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:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt24
-rw-r--r--source/blender/alembic/ABC_alembic.h15
-rw-r--r--source/blender/alembic/CMakeLists.txt2
-rw-r--r--source/blender/alembic/intern/abc_camera.cc5
-rw-r--r--source/blender/alembic/intern/abc_camera.h3
-rw-r--r--source/blender/alembic/intern/abc_curves.cc52
-rw-r--r--source/blender/alembic/intern/abc_curves.h20
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc139
-rw-r--r--source/blender/alembic/intern/abc_exporter.h20
-rw-r--r--source/blender/alembic/intern/abc_hair.cc62
-rw-r--r--source/blender/alembic/intern/abc_hair.h8
-rw-r--r--source/blender/alembic/intern/abc_mball.cc21
-rw-r--r--source/blender/alembic/intern/abc_mball.h3
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc370
-rw-r--r--source/blender/alembic/intern/abc_mesh.h41
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc23
-rw-r--r--source/blender/alembic/intern/abc_nurbs.h3
-rw-r--r--source/blender/alembic/intern/abc_object.cc15
-rw-r--r--source/blender/alembic/intern/abc_object.h14
-rw-r--r--source/blender/alembic/intern/abc_points.cc54
-rw-r--r--source/blender/alembic/intern/abc_points.h11
-rw-r--r--source/blender/alembic/intern/abc_transform.cc14
-rw-r--r--source/blender/alembic/intern/abc_transform.h1
-rw-r--r--source/blender/alembic/intern/abc_util.cc49
-rw-r--r--source/blender/alembic/intern/abc_util.h4
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc115
-rw-r--r--source/blender/avi/intern/avi.c57
-rw-r--r--source/blender/blenfont/BLF_api.h44
-rw-r--r--source/blender/blenfont/intern/blf.c260
-rw-r--r--source/blender/blenfont/intern/blf_dir.c26
-rw-r--r--source/blender/blenfont/intern/blf_font.c416
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c273
-rw-r--r--source/blender/blenfont/intern/blf_internal.h8
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h54
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h332
-rw-r--r--source/blender/blenkernel/BKE_action.h7
-rw-r--r--source/blender/blenkernel/BKE_anim.h45
-rw-r--r--source/blender/blenkernel/BKE_animsys.h49
-rw-r--r--source/blender/blenkernel/BKE_appdir.h2
-rw-r--r--source/blender/blenkernel/BKE_armature.h188
-rw-r--r--source/blender/blenkernel/BKE_blender_user_menu.h49
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h12
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h7
-rw-r--r--source/blender/blenkernel/BKE_bmfont.h61
-rw-r--r--source/blender/blenkernel/BKE_brush.h18
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h19
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h5
-rw-r--r--source/blender/blenkernel/BKE_camera.h32
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h32
-rw-r--r--source/blender/blenkernel/BKE_cloth.h59
-rw-r--r--source/blender/blenkernel/BKE_collection.h200
-rw-r--r--source/blender/blenkernel/BKE_collision.h40
-rw-r--r--source/blender/blenkernel/BKE_constraint.h19
-rw-r--r--source/blender/blenkernel/BKE_context.h52
-rw-r--r--source/blender/blenkernel/BKE_crazyspace.h9
-rw-r--r--source/blender/blenkernel/BKE_curve.h25
-rw-r--r--source/blender/blenkernel/BKE_customdata.h58
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h12
-rw-r--r--source/blender/blenkernel/BKE_deform.h2
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h181
-rw-r--r--source/blender/blenkernel/BKE_displist.h33
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h29
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h14
-rw-r--r--source/blender/blenkernel/BKE_editmesh_cache.h36
-rw-r--r--source/blender/blenkernel/BKE_editmesh_tangent.h40
-rw-r--r--source/blender/blenkernel/BKE_effect.h41
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h20
-rw-r--r--source/blender/blenkernel/BKE_fluidsim.h3
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_global.h12
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h119
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h275
-rw-r--r--source/blender/blenkernel/BKE_group.h60
-rw-r--r--source/blender/blenkernel/BKE_icons.h51
-rw-r--r--source/blender/blenkernel/BKE_idprop.h11
-rw-r--r--source/blender/blenkernel/BKE_image.h16
-rw-r--r--source/blender/blenkernel/BKE_key.h14
-rw-r--r--source/blender/blenkernel/BKE_keyconfig.h58
-rw-r--r--source/blender/blenkernel/BKE_lamp.h2
-rw-r--r--source/blender/blenkernel/BKE_lattice.h51
-rw-r--r--source/blender/blenkernel/BKE_layer.h427
-rw-r--r--source/blender/blenkernel/BKE_library.h54
-rw-r--r--source/blender/blenkernel/BKE_library_override.h91
-rw-r--r--source/blender/blenkernel/BKE_library_query.h3
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_lightprobe.h (renamed from source/blender/blenkernel/BKE_bmfont_types.h)42
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h3
-rw-r--r--source/blender/blenkernel/BKE_main.h41
-rw-r--r--source/blender/blenkernel/BKE_mask.h7
-rw-r--r--source/blender/blenkernel/BKE_material.h21
-rw-r--r--source/blender/blenkernel/BKE_mball.h40
-rw-r--r--source/blender/blenkernel/BKE_mball_tessellate.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh.h165
-rw-r--r--source/blender/blenkernel/BKE_mesh_iterators.h67
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h28
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h122
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h68
-rw-r--r--source/blender/blenkernel/BKE_modifier.h168
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h9
-rw-r--r--source/blender/blenkernel/BKE_multires.h90
-rw-r--r--source/blender/blenkernel/BKE_navmesh_conversion.h67
-rw-r--r--source/blender/blenkernel/BKE_nla.h12
-rw-r--r--source/blender/blenkernel/BKE_node.h66
-rw-r--r--source/blender/blenkernel/BKE_object.h173
-rw-r--r--source/blender/blenkernel/BKE_object_facemap.h53
-rw-r--r--source/blender/blenkernel/BKE_ocean.h6
-rw-r--r--source/blender/blenkernel/BKE_outliner_treehash.h6
-rw-r--r--source/blender/blenkernel/BKE_paint.h50
-rw-r--r--source/blender/blenkernel/BKE_particle.h98
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h15
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h25
-rw-r--r--source/blender/blenkernel/BKE_property.h53
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h19
-rw-r--r--source/blender/blenkernel/BKE_sca.h91
-rw-r--r--source/blender/blenkernel/BKE_scene.h102
-rw-r--r--source/blender/blenkernel/BKE_screen.h101
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h18
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h180
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h81
-rw-r--r--source/blender/blenkernel/BKE_sketch.h149
-rw-r--r--source/blender/blenkernel/BKE_smoke.h7
-rw-r--r--source/blender/blenkernel/BKE_softbody.h6
-rw-r--r--source/blender/blenkernel/BKE_sound.h8
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h155
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h237
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h249
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h127
-rw-r--r--source/blender/blenkernel/BKE_subdiv_foreach.h181
-rw-r--r--source/blender/blenkernel/BKE_subdiv_mesh.h56
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h1
-rw-r--r--source/blender/blenkernel/BKE_text.h4
-rw-r--r--source/blender/blenkernel/BKE_texture.h26
-rw-r--r--source/blender/blenkernel/BKE_tracking.h4
-rw-r--r--source/blender/blenkernel/BKE_unit.h14
-rw-r--r--source/blender/blenkernel/BKE_workspace.h110
-rw-r--r--source/blender/blenkernel/BKE_world.h4
-rw-r--r--source/blender/blenkernel/BKE_writeframeserver.h58
-rw-r--r--source/blender/blenkernel/CMakeLists.txt108
-rw-r--r--source/blender/blenkernel/depsgraph_private.h169
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c8
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c151
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c191
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c2925
-rw-r--r--source/blender/blenkernel/intern/action.c155
-rw-r--r--source/blender/blenkernel/intern/anim.c319
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c671
-rw-r--r--source/blender/blenkernel/intern/appdir.c34
-rw-r--r--source/blender/blenkernel/intern/armature.c947
-rw-r--r--source/blender/blenkernel/intern/armature_update.c235
-rw-r--r--source/blender/blenkernel/intern/blender.c36
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c19
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c10
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c121
-rw-r--r--source/blender/blenkernel/intern/blendfile.c123
-rw-r--r--source/blender/blenkernel/intern/bmfont.c293
-rw-r--r--source/blender/blenkernel/intern/boids.c3
-rw-r--r--source/blender/blenkernel/intern/bpath.c17
-rw-r--r--source/blender/blenkernel/intern/brush.c400
-rw-r--r--source/blender/blenkernel/intern/bullet.c97
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c474
-rw-r--r--source/blender/blenkernel/intern/cachefile.c37
-rw-r--r--source/blender/blenkernel/intern/camera.c122
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c2382
-rw-r--r--source/blender/blenkernel/intern/cloth.c760
-rw-r--r--source/blender/blenkernel/intern/collection.c1200
-rw-r--r--source/blender/blenkernel/intern/collision.c1614
-rw-r--r--source/blender/blenkernel/intern/colorband.c4
-rw-r--r--source/blender/blenkernel/intern/colortools.c115
-rw-r--r--source/blender/blenkernel/intern/constraint.c941
-rw-r--r--source/blender/blenkernel/intern/context.c201
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c68
-rw-r--r--source/blender/blenkernel/intern/curve.c195
-rw-r--r--source/blender/blenkernel/intern/customdata.c221
-rw-r--r--source/blender/blenkernel/intern/customdata_file.c10
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c407
-rw-r--r--source/blender/blenkernel/intern/deform.c48
-rw-r--r--source/blender/blenkernel/intern/displist.c296
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c559
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c2320
-rw-r--r--source/blender/blenkernel/intern/editmesh.c86
-rw-r--r--source/blender/blenkernel/intern/editmesh_cache.c120
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c433
-rw-r--r--source/blender/blenkernel/intern/effect.c327
-rw-r--r--source/blender/blenkernel/intern/fcurve.c244
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c37
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c21
-rw-r--r--source/blender/blenkernel/intern/font.c437
-rw-r--r--source/blender/blenkernel/intern/freestyle.c14
-rw-r--r--source/blender/blenkernel/intern/gpencil.c1347
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c826
-rw-r--r--source/blender/blenkernel/intern/group.c379
-rw-r--r--source/blender/blenkernel/intern/icons.c259
-rw-r--r--source/blender/blenkernel/intern/icons_rasterize.c146
-rw-r--r--source/blender/blenkernel/intern/idcode.c81
-rw-r--r--source/blender/blenkernel/intern/idprop.c46
-rw-r--r--source/blender/blenkernel/intern/image.c326
-rw-r--r--source/blender/blenkernel/intern/ipo.c34
-rw-r--r--source/blender/blenkernel/intern/key.c252
-rw-r--r--source/blender/blenkernel/intern/keyconfig.c137
-rw-r--r--source/blender/blenkernel/intern/lamp.c102
-rw-r--r--source/blender/blenkernel/intern/lattice.c161
-rw-r--r--source/blender/blenkernel/intern/layer.c1533
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c127
-rw-r--r--source/blender/blenkernel/intern/library.c731
-rw-r--r--source/blender/blenkernel/intern/library_idmap.c1
-rw-r--r--source/blender/blenkernel/intern/library_override.c789
-rw-r--r--source/blender/blenkernel/intern/library_query.c303
-rw-r--r--source/blender/blenkernel/intern/library_remap.c205
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c101
-rw-r--r--source/blender/blenkernel/intern/linestyle.c15
-rw-r--r--source/blender/blenkernel/intern/main.c445
-rw-r--r--source/blender/blenkernel/intern/mask.c59
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c17
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c14
-rw-r--r--source/blender/blenkernel/intern/material.c1241
-rw-r--r--source/blender/blenkernel/intern/mball.c230
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c42
-rw-r--r--source/blender/blenkernel/intern/mesh.c517
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c547
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c273
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c211
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c685
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c197
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c380
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c716
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c236
-rw-r--r--source/blender/blenkernel/intern/modifier.c173
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c249
-rw-r--r--source/blender/blenkernel/intern/movieclip.c48
-rw-r--r--source/blender/blenkernel/intern/multires.c543
-rw-r--r--source/blender/blenkernel/intern/multires_inline.h68
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c1206
-rw-r--r--source/blender/blenkernel/intern/multires_subdiv.c67
-rw-r--r--source/blender/blenkernel/intern/navmesh_conversion.c502
-rw-r--r--source/blender/blenkernel/intern/nla.c79
-rw-r--r--source/blender/blenkernel/intern/node.c292
-rw-r--r--source/blender/blenkernel/intern/object.c1542
-rw-r--r--source/blender/blenkernel/intern/object_deform.c17
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c503
-rw-r--r--source/blender/blenkernel/intern/object_facemap.c257
-rw-r--r--source/blender/blenkernel/intern/object_update.c280
-rw-r--r--source/blender/blenkernel/intern/ocean.c93
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c69
-rw-r--r--source/blender/blenkernel/intern/packedFile.c28
-rw-r--r--source/blender/blenkernel/intern/paint.c488
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c140
-rw-r--r--source/blender/blenkernel/intern/particle.c1235
-rw-r--r--source/blender/blenkernel/intern/particle_child.c50
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c490
-rw-r--r--source/blender/blenkernel/intern/particle_system.c300
-rw-r--r--source/blender/blenkernel/intern/pbvh.c176
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c22
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h5
-rw-r--r--source/blender/blenkernel/intern/pointcache.c273
-rw-r--r--source/blender/blenkernel/intern/property.c267
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c590
-rw-r--r--source/blender/blenkernel/intern/sca.c1178
-rw-r--r--source/blender/blenkernel/intern/scene.c1678
-rw-r--r--source/blender/blenkernel/intern/screen.c515
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c70
-rw-r--r--source/blender/blenkernel/intern/sequencer.c74
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c245
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c1055
-rw-r--r--source/blender/blenkernel/intern/sketch.c555
-rw-r--r--source/blender/blenkernel/intern/smoke.c472
-rw-r--r--source/blender/blenkernel/intern/softbody.c250
-rw-r--r--source/blender/blenkernel/intern/sound.c168
-rw-r--r--source/blender/blenkernel/intern/studiolight.c1411
-rw-r--r--source/blender/blenkernel/intern/subdiv.c149
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c1188
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg_mask.c197
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter.c77
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter.h67
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c410
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement.c (renamed from source/blender/render/intern/include/volume_precache.h)29
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement_multires.c358
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c394
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c2038
-rw-r--r--source/blender/blenkernel/intern/subdiv_inline.h80
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c1149
-rw-r--r--source/blender/blenkernel/intern/subdiv_stats.c92
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2302
-rw-r--r--source/blender/blenkernel/intern/text.c3
-rw-r--r--source/blender/blenkernel/intern/texture.c443
-rw-r--r--source/blender/blenkernel/intern/tracking.c7
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c14
-rw-r--r--source/blender/blenkernel/intern/undo_system.c11
-rw-r--r--source/blender/blenkernel/intern/unit.c434
-rw-r--r--source/blender/blenkernel/intern/workspace.c446
-rw-r--r--source/blender/blenkernel/intern/world.c50
-rw-r--r--source/blender/blenkernel/intern/writeavi.c17
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c39
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c419
-rw-r--r--source/blender/blenkernel/nla_private.h18
-rw-r--r--source/blender/blenlib/BLI_bitmap.h6
-rw-r--r--source/blender/blenlib/BLI_callbacks.h7
-rw-r--r--source/blender/blenlib/BLI_expr_pylike_eval.h66
-rw-r--r--source/blender/blenlib/BLI_graph.h185
-rw-r--r--source/blender/blenlib/BLI_heap.h1
-rw-r--r--source/blender/blenlib/BLI_heap_simple.h44
-rw-r--r--source/blender/blenlib/BLI_iterator.h62
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h23
-rw-r--r--source/blender/blenlib/BLI_link_utils.h21
-rw-r--r--source/blender/blenlib/BLI_listbase.h1
-rw-r--r--source/blender/blenlib/BLI_math_color.h2
-rw-r--r--source/blender/blenlib/BLI_math_geom.h41
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h255
-rw-r--r--source/blender/blenlib/BLI_math_solvers.h14
-rw-r--r--source/blender/blenlib/BLI_math_statistics.h6
-rw-r--r--source/blender/blenlib/BLI_math_vector.h20
-rw-r--r--source/blender/blenlib/BLI_memiter.h73
-rw-r--r--source/blender/blenlib/BLI_path_util.h2
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d.h4
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d_beautify.h4
-rw-r--r--source/blender/blenlib/BLI_rand.h11
-rw-r--r--source/blender/blenlib/BLI_string.h3
-rw-r--r--source/blender/blenlib/BLI_timer.h58
-rw-r--r--source/blender/blenlib/BLI_utildefines.h12
-rw-r--r--source/blender/blenlib/BLI_vfontdata.h3
-rw-r--r--source/blender/blenlib/CMakeLists.txt11
-rw-r--r--source/blender/blenlib/intern/BLI_array.c5
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c51
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c39
-rw-r--r--source/blender/blenlib/intern/BLI_heap_simple.c247
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c551
-rw-r--r--source/blender/blenlib/intern/BLI_memiter.c357
-rw-r--r--source/blender/blenlib/intern/BLI_timer.c184
-rw-r--r--source/blender/blenlib/intern/array_store_utils.c4
-rw-r--r--source/blender/blenlib/intern/astar.c28
-rw-r--r--source/blender/blenlib/intern/edgehash.c43
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c1003
-rw-r--r--source/blender/blenlib/intern/freetypefont.c84
-rw-r--r--source/blender/blenlib/intern/graph.c1016
-rw-r--r--source/blender/blenlib/intern/listbase.c23
-rw-r--r--source/blender/blenlib/intern/math_color.c191
-rw-r--r--source/blender/blenlib/intern/math_geom.c551
-rw-r--r--source/blender/blenlib/intern/math_matrix.c447
-rw-r--r--source/blender/blenlib/intern/math_rotation.c17
-rw-r--r--source/blender/blenlib/intern/math_solvers.c95
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c50
-rw-r--r--source/blender/blenlib/intern/noise.c33
-rw-r--r--source/blender/blenlib/intern/path_util.c52
-rw-r--r--source/blender/blenlib/intern/rand.c31
-rw-r--r--source/blender/blenlib/intern/scanfill.c32
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c14
-rw-r--r--source/blender/blenlib/intern/string.c63
-rw-r--r--source/blender/blenlib/intern/task.c2
-rw-r--r--source/blender/blenloader/BLO_readfile.h34
-rw-r--r--source/blender/blenloader/BLO_writefile.h2
-rw-r--r--source/blender/blenloader/CMakeLists.txt8
-rw-r--r--source/blender/blenloader/intern/blend_validate.c2
-rw-r--r--source/blender/blenloader/intern/readblenentry.c6
-rw-r--r--source/blender/blenloader/intern/readfile.c3455
-rw-r--r--source/blender/blenloader/intern/readfile.h7
-rw-r--r--source/blender/blenloader/intern/runtime.c141
-rw-r--r--source/blender/blenloader/intern/undofile.c1
-rw-r--r--source/blender/blenloader/intern/versioning_250.c569
-rw-r--r--source/blender/blenloader/intern/versioning_260.c235
-rw-r--r--source/blender/blenloader/intern/versioning_270.c237
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2484
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c411
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c1032
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c458
-rw-r--r--source/blender/blenloader/intern/writefile.c1228
-rw-r--r--source/blender/blentranslation/BLT_translation.h8
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c7
-rw-r--r--source/blender/bmesh/CMakeLists.txt1
-rw-r--r--source/blender/bmesh/bmesh.h2
-rw-r--r--source/blender/bmesh/bmesh_class.h29
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c534
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h52
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c218
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c202
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h13
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h19
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h4
-rw-r--r--source/blender/bmesh/operators/bmo_bevel.c8
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c24
-rw-r--r--source/blender/bmesh/operators/bmo_similar.c657
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c386
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h3
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c21
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c56
-rw-r--r--source/blender/collada/AnimationClipExporter.cpp55
-rw-r--r--source/blender/collada/AnimationClipExporter.h50
-rw-r--r--source/blender/collada/AnimationExporter.cpp2029
-rw-r--r--source/blender/collada/AnimationExporter.h195
-rw-r--r--source/blender/collada/AnimationImporter.cpp77
-rw-r--r--source/blender/collada/AnimationImporter.h30
-rw-r--r--source/blender/collada/ArmatureExporter.cpp61
-rw-r--r--source/blender/collada/ArmatureExporter.h31
-rw-r--r--source/blender/collada/ArmatureImporter.cpp21
-rw-r--r--source/blender/collada/ArmatureImporter.h4
-rw-r--r--source/blender/collada/BCAnimationCurve.cpp678
-rw-r--r--source/blender/collada/BCAnimationCurve.h156
-rw-r--r--source/blender/collada/BCAnimationSampler.cpp645
-rw-r--r--source/blender/collada/BCAnimationSampler.h205
-rw-r--r--source/blender/collada/BCSampleData.cpp186
-rw-r--r--source/blender/collada/BCSampleData.h102
-rw-r--r--source/blender/collada/BlenderContext.cpp65
-rw-r--r--source/blender/collada/BlenderContext.h56
-rw-r--r--source/blender/collada/CMakeLists.txt13
-rw-r--r--source/blender/collada/ControllerExporter.cpp67
-rw-r--r--source/blender/collada/ControllerExporter.h16
-rw-r--r--source/blender/collada/DocumentExporter.cpp52
-rw-r--r--source/blender/collada/DocumentExporter.h12
-rw-r--r--source/blender/collada/DocumentImporter.cpp347
-rw-r--r--source/blender/collada/DocumentImporter.h9
-rw-r--r--source/blender/collada/EffectExporter.cpp333
-rw-r--r--source/blender/collada/EffectExporter.h21
-rw-r--r--source/blender/collada/ErrorHandler.cpp46
-rw-r--r--source/blender/collada/ExportSettings.h22
-rw-r--r--source/blender/collada/GeometryExporter.cpp332
-rw-r--r--source/blender/collada/GeometryExporter.h51
-rw-r--r--source/blender/collada/ImageExporter.cpp244
-rw-r--r--source/blender/collada/ImageExporter.h14
-rw-r--r--source/blender/collada/InstanceWriter.cpp59
-rw-r--r--source/blender/collada/InstanceWriter.h3
-rw-r--r--source/blender/collada/LightExporter.cpp35
-rw-r--r--source/blender/collada/MaterialExporter.cpp46
-rw-r--r--source/blender/collada/MaterialExporter.h1
-rw-r--r--source/blender/collada/Materials.cpp329
-rw-r--r--source/blender/collada/Materials.h84
-rw-r--r--source/blender/collada/MeshImporter.cpp121
-rw-r--r--source/blender/collada/MeshImporter.h22
-rw-r--r--source/blender/collada/SceneExporter.cpp272
-rw-r--r--source/blender/collada/SceneExporter.h23
-rw-r--r--source/blender/collada/SkinInfo.cpp14
-rw-r--r--source/blender/collada/SkinInfo.h2
-rw-r--r--source/blender/collada/TransformReader.cpp4
-rw-r--r--source/blender/collada/TransformWriter.cpp28
-rw-r--r--source/blender/collada/TransformWriter.h14
-rw-r--r--source/blender/collada/collada.cpp45
-rw-r--r--source/blender/collada/collada.h7
-rw-r--r--source/blender/collada/collada_internal.cpp44
-rw-r--r--source/blender/collada/collada_internal.h15
-rw-r--r--source/blender/collada/collada_utils.cpp698
-rw-r--r--source/blender/collada/collada_utils.h138
-rw-r--r--source/blender/compositor/CMakeLists.txt1
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cpp11
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp12
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h1
-rwxr-xr-xsource/blender/datatoc/datatoc_icon_split.py17
-rw-r--r--source/blender/depsgraph/CMakeLists.txt19
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h185
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h84
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h19
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_physics.h85
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h185
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc155
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc45
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc1089
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h134
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc198
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc (renamed from source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc)86
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc1436
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h86
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h33
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc30
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc523
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc (renamed from source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc)60
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc17
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc85
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc30
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc284
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h80
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc334
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc52
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc104
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h40
-rw-r--r--source/blender/depsgraph/intern/depsgraph_physics.cc270
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc191
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_filter.cc257
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc113
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc372
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc861
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc81
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h102
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc197
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc1151
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h109
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc293
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc9
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h11
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc77
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h44
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_id.cc121
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_id.h36
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc20
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.h27
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_time.cc7
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_time.h2
-rw-r--r--source/blender/depsgraph/util/deg_util_function.h4
-rw-r--r--source/blender/draw/CMakeLists.txt362
-rw-r--r--source/blender/draw/DRW_engine.h159
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c220
-rw-r--r--source/blender/draw/engines/basic/basic_engine.h32
-rw-r--r--source/blender/draw/engines/eevee/eevee_bloom.c336
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c208
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c289
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c578
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c482
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.h31
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c1215
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h59
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c1239
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c1486
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c238
-rw-r--r--source/blender/draw/engines/eevee/eevee_lut.h16926
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c1811
-rw-r--r--source/blender/draw/engines/eevee/eevee_mist.c139
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c215
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c315
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h1054
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c621
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c337
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c320
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c372
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c360
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c621
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl282
-rw-r--r--source/blender/draw/engines/eevee/shaders/background_vert.glsl27
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl862
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl46
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl107
-rw-r--r--source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl59
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl66
-rw-r--r--source/blender/draw/engines/eevee/shaders/concentric_samples_lib.glsl267
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl47
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_world_frag.glsl62
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl218
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl241
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl109
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl30
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl37
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl77
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl95
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl31
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl65
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl476
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl99
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl111
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl22
-rw-r--r--source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl177
-rw-r--r--source/blender/draw/engines/eevee/shaders/lamps_lib.glsl450
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl18
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl43
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl197
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl98
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl87
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl34
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl19
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl49
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl20
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl304
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl14
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl15
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl40
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl24
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_vert.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl523
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl79
-rw-r--r--source/blender/draw/engines/eevee/shaders/ltc_lib.glsl321
-rw-r--r--source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl37
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl86
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_vert.glsl39
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl237
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl196
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl242
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl33
-rw-r--r--source/blender/draw/engines/eevee/shaders/ssr_lib.glsl72
-rw-r--r--source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl18
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl63
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl70
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl63
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl155
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl21
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl75
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl27
-rw-r--r--source/blender/draw/engines/external/external_engine.c234
-rw-r--r--source/blender/draw/engines/external/external_engine.h31
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c311
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c727
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c1631
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c924
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h441
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c356
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c1129
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl87
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl86
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl37
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl68
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl46
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl69
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl49
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl63
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl98
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl97
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl32
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl69
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl43
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl12
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl155
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl17
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl48
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl15
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl147
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl14
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl9
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl51
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl82
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl36
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl15
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl49
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl208
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl36
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl45
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl3
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl83
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl84
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_checkerboard_depth_frag.glsl38
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl123
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl43
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl21
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl111
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl19
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl37
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl20
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl78
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl79
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl70
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl85
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl118
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl21
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl248
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl33
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl191
-rw-r--r--source/blender/draw/engines/workbench/solid_mode.c115
-rw-r--r--source/blender/draw/engines/workbench/transparent_mode.c97
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c176
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c1003
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_aa.c109
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_fxaa.c62
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_taa.c302
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c (renamed from source/blender/render/intern/include/voxeldata.h)44
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.h33
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c661
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c177
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h327
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c208
-rw-r--r--source/blender/draw/engines/workbench/workbench_studiolight.c304
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c227
-rw-r--r--source/blender/draw/intern/DRW_render.h602
-rw-r--r--source/blender/draw/intern/draw_anim_viz.c359
-rw-r--r--source/blender/draw/intern/draw_armature.c1915
-rw-r--r--source/blender/draw/intern/draw_cache.c3717
-rw-r--r--source/blender/draw/intern/draw_cache.h216
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h221
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c1132
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c465
-rw-r--r--source/blender/draw/intern/draw_cache_impl_lattice.c579
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c5912
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c257
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c1689
-rw-r--r--source/blender/draw/intern/draw_common.c1009
-rw-r--r--source/blender/draw/intern/draw_common.h203
-rw-r--r--source/blender/draw/intern/draw_debug.c229
-rw-r--r--source/blender/draw/intern/draw_debug.h41
-rw-r--r--source/blender/draw/intern/draw_hair.c214
-rw-r--r--source/blender/draw/intern/draw_hair_private.h92
-rw-r--r--source/blender/draw/intern/draw_instance_data.c436
-rw-r--r--source/blender/draw/intern/draw_instance_data.h59
-rw-r--r--source/blender/draw/intern/draw_manager.c2716
-rw-r--r--source/blender/draw/intern/draw_manager.h423
-rw-r--r--source/blender/draw/intern/draw_manager_data.c1185
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c1332
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c364
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.h43
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c397
-rw-r--r--source/blender/draw/intern/draw_manager_text.c184
-rw-r--r--source/blender/draw/intern/draw_manager_text.h52
-rw-r--r--source/blender/draw/intern/draw_manager_texture.c152
-rw-r--r--source/blender/draw/intern/draw_view.c272
-rw-r--r--source/blender/draw/intern/draw_view.h35
-rw-r--r--source/blender/draw/modes/draw_mode_engines.h46
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c196
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c264
-rw-r--r--source/blender/draw/modes/edit_lattice_mode.c277
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c804
-rw-r--r--source/blender/draw/modes/edit_mesh_mode_intern.h38
-rw-r--r--source/blender/draw/modes/edit_mesh_mode_text.c357
-rw-r--r--source/blender/draw/modes/edit_metaball_mode.c234
-rw-r--r--source/blender/draw/modes/edit_text_mode.c360
-rw-r--r--source/blender/draw/modes/object_mode.c2992
-rw-r--r--source/blender/draw/modes/overlay_mode.c400
-rw-r--r--source/blender/draw/modes/paint_texture_mode.c402
-rw-r--r--source/blender/draw/modes/paint_vertex_mode.c207
-rw-r--r--source/blender/draw/modes/paint_weight_mode.c248
-rw-r--r--source/blender/draw/modes/particle_mode.c262
-rw-r--r--source/blender/draw/modes/pose_mode.c343
-rw-r--r--source/blender/draw/modes/sculpt_mode.c288
-rw-r--r--source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl38
-rw-r--r--source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl91
-rw-r--r--source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl47
-rw-r--r--source/blender/draw/modes/shaders/armature_axes_vert.glsl30
-rw-r--r--source/blender/draw/modes/shaders/armature_dof_vert.glsl30
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl15
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl156
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl18
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl55
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl101
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl47
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl11
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl36
-rw-r--r--source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl102
-rw-r--r--source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl81
-rw-r--r--source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl82
-rw-r--r--source/blender/draw/modes/shaders/armature_stick_frag.glsl13
-rw-r--r--source/blender/draw/modes/shaders/armature_stick_vert.glsl88
-rw-r--r--source/blender/draw/modes/shaders/common_fullscreen_vert.glsl10
-rw-r--r--source/blender/draw/modes/shaders/common_fxaa_lib.glsl677
-rw-r--r--source/blender/draw/modes/shaders/common_globals_lib.glsl80
-rw-r--r--source/blender/draw/modes/shaders/common_hair_lib.glsl199
-rw-r--r--source/blender/draw/modes/shaders/common_hair_refine_vert.glsl55
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl14
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl96
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl15
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl31
-rw-r--r--source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl39
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl53
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl19
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl31
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl7
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl28
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl152
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl119
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl211
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl7
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl49
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl102
-rw-r--r--source/blender/draw/modes/shaders/edit_normals_geom.glsl15
-rw-r--r--source/blender/draw/modes/shaders/edit_normals_vert.glsl30
-rw-r--r--source/blender/draw/modes/shaders/object_empty_axes_vert.glsl29
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_frag.glsl33
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_vert.glsl32
-rw-r--r--source/blender/draw/modes/shaders/object_grid_frag.glsl246
-rw-r--r--source/blender/draw/modes/shaders/object_grid_vert.glsl63
-rw-r--r--source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl34
-rw-r--r--source/blender/draw/modes/shaders/object_mball_handles_vert.glsl34
-rw-r--r--source/blender/draw/modes/shaders/object_outline_detect_frag.glsl88
-rw-r--r--source/blender/draw/modes/shaders/object_outline_expand_frag.glsl37
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl10
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl40
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl16
-rw-r--r--source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl27
-rw-r--r--source/blender/draw/modes/shaders/object_particle_dot_frag.glsl52
-rw-r--r--source/blender/draw/modes/shaders/object_particle_dot_vert.glsl35
-rw-r--r--source/blender/draw/modes/shaders/object_particle_prim_vert.glsl56
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl10
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl7
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl57
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl127
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl177
-rw-r--r--source/blender/draw/modes/shaders/paint_texture_frag.glsl11
-rw-r--r--source/blender/draw/modes/shaders/paint_texture_vert.glsl15
-rw-r--r--source/blender/draw/modes/shaders/paint_vert_frag.glsl26
-rw-r--r--source/blender/draw/modes/shaders/paint_vertex_frag.glsl18
-rw-r--r--source/blender/draw/modes/shaders/paint_vertex_vert.glsl21
-rw-r--r--source/blender/draw/modes/shaders/paint_weight_frag.glsl97
-rw-r--r--source/blender/draw/modes/shaders/paint_weight_vert.glsl15
-rw-r--r--source/blender/draw/modes/shaders/paint_wire_frag.glsl25
-rw-r--r--source/blender/draw/modes/shaders/paint_wire_vert.glsl14
-rw-r--r--source/blender/draw/modes/shaders/particle_strand_frag.glsl23
-rw-r--r--source/blender/draw/modes/shaders/particle_strand_vert.glsl73
-rw-r--r--source/blender/draw/modes/shaders/sculpt_mask_vert.glsl19
-rw-r--r--source/blender/draw/modes/shaders/volume_velocity_vert.glsl115
-rw-r--r--source/blender/editors/CMakeLists.txt8
-rw-r--r--source/blender/editors/animation/CMakeLists.txt1
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c191
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c172
-rw-r--r--source/blender/editors/animation/anim_deps.c36
-rw-r--r--source/blender/editors/animation/anim_draw.c163
-rw-r--r--source/blender/editors/animation/anim_filter.c158
-rw-r--r--source/blender/editors/animation/anim_intern.h1
-rw-r--r--source/blender/editors/animation/anim_markers.c304
-rw-r--r--source/blender/editors/animation/anim_ops.c146
-rw-r--r--source/blender/editors/animation/drivers.c148
-rw-r--r--source/blender/editors/animation/keyframes_draw.c960
-rw-r--r--source/blender/editors/animation/keyframes_edit.c10
-rw-r--r--source/blender/editors/animation/keyframes_general.c20
-rw-r--r--source/blender/editors/animation/keyframing.c228
-rw-r--r--source/blender/editors/animation/keyingsets.c18
-rw-r--r--source/blender/editors/armature/BIF_generate.h49
-rw-r--r--source/blender/editors/armature/BIF_retarget.h171
-rw-r--r--source/blender/editors/armature/CMakeLists.txt9
-rw-r--r--source/blender/editors/armature/armature_add.c727
-rw-r--r--source/blender/editors/armature/armature_edit.c975
-rw-r--r--source/blender/editors/armature/armature_intern.h34
-rw-r--r--source/blender/editors/armature/armature_naming.c191
-rw-r--r--source/blender/editors/armature/armature_ops.c223
-rw-r--r--source/blender/editors/armature/armature_relations.c201
-rw-r--r--source/blender/editors/armature/armature_select.c749
-rw-r--r--source/blender/editors/armature/armature_skinning.c78
-rw-r--r--source/blender/editors/armature/armature_utils.c75
-rw-r--r--source/blender/editors/armature/editarmature_generate.c305
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c2644
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c2663
-rw-r--r--source/blender/editors/armature/editarmature_undo.c84
-rw-r--r--source/blender/editors/armature/meshlaplacian.c55
-rw-r--r--source/blender/editors/armature/meshlaplacian.h9
-rw-r--r--source/blender/editors/armature/pose_edit.c407
-rw-r--r--source/blender/editors/armature/pose_group.c25
-rw-r--r--source/blender/editors/armature/pose_lib.c47
-rw-r--r--source/blender/editors/armature/pose_select.c524
-rw-r--r--source/blender/editors/armature/pose_slide.c301
-rw-r--r--source/blender/editors/armature/pose_transform.c285
-rw-r--r--source/blender/editors/armature/pose_utils.c160
-rw-r--r--source/blender/editors/armature/reeb.c3435
-rw-r--r--source/blender/editors/armature/reeb.h207
-rw-r--r--source/blender/editors/curve/CMakeLists.txt2
-rw-r--r--source/blender/editors/curve/curve_intern.h7
-rw-r--r--source/blender/editors/curve/curve_ops.c129
-rw-r--r--source/blender/editors/curve/editcurve.c1638
-rw-r--r--source/blender/editors/curve/editcurve_add.c49
-rw-r--r--source/blender/editors/curve/editcurve_paint.c126
-rw-r--r--source/blender/editors/curve/editcurve_select.c802
-rw-r--r--source/blender/editors/curve/editcurve_undo.c83
-rw-r--r--source/blender/editors/curve/editfont.c32
-rw-r--r--source/blender/editors/curve/editfont_undo.c5
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt451
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt63
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c141
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c75
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c813
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c121
-rw-r--r--source/blender/editors/gizmo_library/gizmo_geometry.h54
-rw-r--r--source/blender/editors/gizmo_library/gizmo_group_types/value2d_gizmo_group.c176
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_intern.h111
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_presets.c150
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_utils.c247
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c225
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c491
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/blank3d_gizmo.c89
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c332
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c1103
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c695
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c623
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c466
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/primitive3d_gizmo.c191
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/value2d_gizmo.c198
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt9
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c1134
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c2327
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c1737
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c1569
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c251
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c678
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c870
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c218
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c2124
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1859
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c1285
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h313
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c122
-rw-r--r--source/blender/editors/gpencil/gpencil_old.c211
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c447
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c1933
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c781
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c681
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c1492
-rw-r--r--source/blender/editors/include/BIF_gl.h53
-rw-r--r--source/blender/editors/include/BIF_glutil.h176
-rw-r--r--source/blender/editors/include/ED_anim_api.h32
-rw-r--r--source/blender/editors/include/ED_armature.h79
-rw-r--r--source/blender/editors/include/ED_buttons.h10
-rw-r--r--source/blender/editors/include/ED_curve.h9
-rw-r--r--source/blender/editors/include/ED_datafiles.h66
-rw-r--r--source/blender/editors/include/ED_fileselect.h11
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h254
-rw-r--r--source/blender/editors/include/ED_gizmo_utils.h46
-rw-r--r--source/blender/editors/include/ED_gpencil.h203
-rw-r--r--source/blender/editors/include/ED_image.h6
-rw-r--r--source/blender/editors/include/ED_info.h4
-rw-r--r--source/blender/editors/include/ED_keyframes_draw.h126
-rw-r--r--source/blender/editors/include/ED_keyframing.h12
-rw-r--r--source/blender/editors/include/ED_markers.h3
-rw-r--r--source/blender/editors/include/ED_mask.h2
-rw-r--r--source/blender/editors/include/ED_mball.h7
-rw-r--r--source/blender/editors/include/ED_mesh.h72
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/include/ED_numinput.h2
-rw-r--r--source/blender/editors/include/ED_object.h128
-rw-r--r--source/blender/editors/include/ED_outliner.h7
-rw-r--r--source/blender/editors/include/ED_particle.h19
-rw-r--r--source/blender/editors/include/ED_render.h12
-rw-r--r--source/blender/editors/include/ED_scene.h41
-rw-r--r--source/blender/editors/include/ED_screen.h234
-rw-r--r--source/blender/editors/include/ED_screen_types.h26
-rw-r--r--source/blender/editors/include/ED_sculpt.h5
-rw-r--r--source/blender/editors/include/ED_select_utils.h63
-rw-r--r--source/blender/editors/include/ED_space_api.h4
-rw-r--r--source/blender/editors/include/ED_transform.h58
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h19
-rw-r--r--source/blender/editors/include/ED_undo.h7
-rw-r--r--source/blender/editors/include/ED_util.h5
-rw-r--r--source/blender/editors/include/ED_uvedit.h36
-rw-r--r--source/blender/editors/include/ED_view3d.h187
-rw-r--r--source/blender/editors/include/UI_icons.h1274
-rw-r--r--source/blender/editors/include/UI_interface.h266
-rw-r--r--source/blender/editors/include/UI_interface_icons.h13
-rw-r--r--source/blender/editors/include/UI_resources.h76
-rw-r--r--source/blender/editors/include/UI_view2d.h34
-rw-r--r--source/blender/editors/interface/CMakeLists.txt6
-rw-r--r--source/blender/editors/interface/interface.c963
-rw-r--r--source/blender/editors/interface/interface_align.c70
-rw-r--r--source/blender/editors/interface/interface_anim.c79
-rw-r--r--source/blender/editors/interface/interface_context_menu.c277
-rw-r--r--source/blender/editors/interface/interface_draw.c1938
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c28
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c20
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c8
-rw-r--r--source/blender/editors/interface/interface_handlers.c1291
-rw-r--r--source/blender/editors/interface/interface_icons.c1205
-rw-r--r--source/blender/editors/interface/interface_icons_event.c296
-rw-r--r--source/blender/editors/interface/interface_intern.h174
-rw-r--r--source/blender/editors/interface/interface_layout.c1397
-rw-r--r--source/blender/editors/interface/interface_ops.c470
-rw-r--r--source/blender/editors/interface/interface_panel.c879
-rw-r--r--source/blender/editors/interface/interface_query.c42
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.c4
-rw-r--r--source/blender/editors/interface/interface_region_hud.c363
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.c17
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c21
-rw-r--r--source/blender/editors/interface/interface_region_popover.c396
-rw-r--r--source/blender/editors/interface/interface_region_popup.c267
-rw-r--r--source/blender/editors/interface/interface_region_search.c49
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c604
-rw-r--r--source/blender/editors/interface/interface_regions.c3
-rw-r--r--source/blender/editors/interface/interface_style.c60
-rw-r--r--source/blender/editors/interface/interface_templates.c1630
-rw-r--r--source/blender/editors/interface/interface_utils.c163
-rw-r--r--source/blender/editors/interface/interface_widgets.c2361
-rw-r--r--source/blender/editors/interface/resources.c1961
-rw-r--r--source/blender/editors/interface/view2d.c439
-rw-r--r--source/blender/editors/interface/view2d_ops.c171
-rw-r--r--source/blender/editors/io/CMakeLists.txt1
-rw-r--r--source/blender/editors/io/io_alembic.c22
-rw-r--r--source/blender/editors/io/io_cache.c4
-rw-r--r--source/blender/editors/io/io_collada.c275
-rw-r--r--source/blender/editors/lattice/CMakeLists.txt2
-rw-r--r--source/blender/editors/lattice/editlattice_select.c330
-rw-r--r--source/blender/editors/lattice/editlattice_tools.c263
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c80
-rw-r--r--source/blender/editors/lattice/lattice_ops.c23
-rw-r--r--source/blender/editors/mask/CMakeLists.txt1
-rw-r--r--source/blender/editors/mask/mask_add.c6
-rw-r--r--source/blender/editors/mask/mask_draw.c481
-rw-r--r--source/blender/editors/mask/mask_edit.c101
-rw-r--r--source/blender/editors/mask/mask_editaction.c2
-rw-r--r--source/blender/editors/mask/mask_intern.h2
-rw-r--r--source/blender/editors/mask/mask_ops.c26
-rw-r--r--source/blender/editors/mask/mask_relationships.c7
-rw-r--r--source/blender/editors/mask/mask_select.c21
-rw-r--r--source/blender/editors/mask/mask_shapekey.c11
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt20
-rw-r--r--source/blender/editors/mesh/editface.c82
-rw-r--r--source/blender/editors/mesh/editmesh_add.c159
-rw-r--r--source/blender/editors/mesh/editmesh_add_gizmo.c405
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c268
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c586
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c451
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_screw.c138
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c95
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c1079
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c155
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c466
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c276
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c38
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c467
-rw-r--r--source/blender/editors/mesh/editmesh_path.c202
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c499
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_edgering.c354
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c218
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c142
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c273
-rw-r--r--source/blender/editors/mesh/editmesh_select.c2153
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c1376
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c5037
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c154
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c56
-rw-r--r--source/blender/editors/mesh/mesh_data.c173
-rw-r--r--source/blender/editors/mesh/mesh_intern.h32
-rw-r--r--source/blender/editors/mesh/mesh_mirror.c44
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c732
-rw-r--r--source/blender/editors/mesh/mesh_ops.c225
-rw-r--r--source/blender/editors/mesh/meshtools.c252
-rw-r--r--source/blender/editors/metaball/CMakeLists.txt2
-rw-r--r--source/blender/editors/metaball/editmball_undo.c80
-rw-r--r--source/blender/editors/metaball/mball_edit.c576
-rw-r--r--source/blender/editors/metaball/mball_ops.c28
-rw-r--r--source/blender/editors/object/CMakeLists.txt14
-rw-r--r--source/blender/editors/object/object_add.c969
-rw-r--r--source/blender/editors/object/object_bake.c400
-rw-r--r--source/blender/editors/object/object_bake_api.c76
-rw-r--r--source/blender/editors/object/object_collection.c600
-rw-r--r--source/blender/editors/object/object_constraint.c173
-rw-r--r--source/blender/editors/object/object_data_transfer.c48
-rw-r--r--source/blender/editors/object/object_edit.c1510
-rw-r--r--source/blender/editors/object/object_facemap_ops.c501
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c647
-rw-r--r--source/blender/editors/object/object_group.c588
-rw-r--r--source/blender/editors/object/object_hook.c47
-rw-r--r--source/blender/editors/object/object_intern.h76
-rw-r--r--source/blender/editors/object/object_lod.c114
-rw-r--r--source/blender/editors/object/object_modes.c194
-rw-r--r--source/blender/editors/object/object_modifier.c403
-rw-r--r--source/blender/editors/object/object_ops.c267
-rw-r--r--source/blender/editors/object/object_random.c61
-rw-r--r--source/blender/editors/object/object_relations.c963
-rw-r--r--source/blender/editors/object/object_select.c809
-rw-r--r--source/blender/editors/object/object_shader_fx.c470
-rw-r--r--source/blender/editors/object/object_shapekey.c25
-rw-r--r--source/blender/editors/object/object_transform.c574
-rw-r--r--source/blender/editors/object/object_vgroup.c164
-rw-r--r--source/blender/editors/object/object_warp.c8
-rw-r--r--source/blender/editors/physics/CMakeLists.txt1
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c20
-rw-r--r--source/blender/editors/physics/particle_boids.c20
-rw-r--r--source/blender/editors/physics/particle_edit.c1374
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c22
-rw-r--r--source/blender/editors/physics/particle_object.c205
-rw-r--r--source/blender/editors/physics/physics_fluid.c35
-rw-r--r--source/blender/editors/physics/physics_intern.h10
-rw-r--r--source/blender/editors/physics/physics_ops.c75
-rw-r--r--source/blender/editors/physics/physics_pointcache.c81
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c38
-rw-r--r--source/blender/editors/physics/rigidbody_object.c31
-rw-r--r--source/blender/editors/physics/rigidbody_world.c21
-rw-r--r--source/blender/editors/render/CMakeLists.txt2
-rw-r--r--source/blender/editors/render/render_intern.h12
-rw-r--r--source/blender/editors/render/render_internal.c799
-rw-r--r--source/blender/editors/render/render_opengl.c239
-rw-r--r--source/blender/editors/render/render_ops.c10
-rw-r--r--source/blender/editors/render/render_preview.c556
-rw-r--r--source/blender/editors/render/render_shading.c614
-rw-r--r--source/blender/editors/render/render_update.c371
-rw-r--r--source/blender/editors/render/render_view.c15
-rw-r--r--source/blender/editors/scene/CMakeLists.txt44
-rw-r--r--source/blender/editors/scene/scene_edit.c275
-rw-r--r--source/blender/editors/screen/CMakeLists.txt7
-rw-r--r--source/blender/editors/screen/area.c2201
-rw-r--r--source/blender/editors/screen/area_utils.c89
-rw-r--r--source/blender/editors/screen/glutil.c771
-rw-r--r--source/blender/editors/screen/screen_context.c487
-rw-r--r--source/blender/editors/screen/screen_draw.c456
-rw-r--r--source/blender/editors/screen/screen_edit.c1431
-rw-r--r--source/blender/editors/screen/screen_geometry.c462
-rw-r--r--source/blender/editors/screen/screen_intern.h47
-rw-r--r--source/blender/editors/screen/screen_ops.c1237
-rw-r--r--source/blender/editors/screen/screen_user_menu.c278
-rw-r--r--source/blender/editors/screen/screendump.c4
-rw-r--r--source/blender/editors/screen/workspace_edit.c601
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c199
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c481
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c19
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c128
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c823
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h62
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c596
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c141
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c95
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c278
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c47
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c63
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c84
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c46
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c257
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c82
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c44
-rw-r--r--source/blender/editors/sound/CMakeLists.txt2
-rw-r--r--source/blender/editors/sound/sound_ops.c15
-rw-r--r--source/blender/editors/space_action/action_buttons.c3
-rw-r--r--source/blender/editors/space_action/action_data.c8
-rw-r--r--source/blender/editors/space_action/action_draw.c284
-rw-r--r--source/blender/editors/space_action/action_edit.c42
-rw-r--r--source/blender/editors/space_action/action_intern.h9
-rw-r--r--source/blender/editors/space_action/action_ops.c166
-rw-r--r--source/blender/editors/space_action/action_select.c171
-rw-r--r--source/blender/editors/space_action/space_action.c309
-rw-r--r--source/blender/editors/space_api/spacetypes.c50
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c462
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h18
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c30
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c243
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c359
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c12
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c272
-rw-r--r--source/blender/editors/space_clip/clip_draw.c911
-rw-r--r--source/blender/editors/space_clip/clip_editor.c15
-rw-r--r--source/blender/editors/space_clip/clip_graph_draw.c166
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c38
-rw-r--r--source/blender/editors/space_clip/clip_intern.h11
-rw-r--r--source/blender/editors/space_clip/clip_ops.c9
-rw-r--r--source/blender/editors/space_clip/clip_toolbar.c97
-rw-r--r--source/blender/editors/space_clip/clip_utils.c97
-rw-r--r--source/blender/editors/space_clip/space_clip.c440
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c17
-rw-r--r--source/blender/editors/space_clip/tracking_ops_detect.c8
-rw-r--r--source/blender/editors/space_clip/tracking_ops_orient.c68
-rw-r--r--source/blender/editors/space_clip/tracking_ops_plane.c7
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c13
-rw-r--r--source/blender/editors/space_clip/tracking_ops_stabilize.c11
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c3
-rw-r--r--source/blender/editors/space_clip/tracking_select.c30
-rw-r--r--source/blender/editors/space_console/console_draw.c22
-rw-r--r--source/blender/editors/space_console/space_console.c115
-rw-r--r--source/blender/editors/space_file/file_draw.c144
-rw-r--r--source/blender/editors/space_file/file_intern.h4
-rw-r--r--source/blender/editors/space_file/file_ops.c44
-rw-r--r--source/blender/editors/space_file/file_panels.c7
-rw-r--r--source/blender/editors/space_file/file_utils.c1
-rw-r--r--source/blender/editors/space_file/filelist.c3
-rw-r--r--source/blender/editors/space_file/filesel.c5
-rw-r--r--source/blender/editors/space_file/fsmenu.c2
-rw-r--r--source/blender/editors/space_file/space_file.c207
-rw-r--r--source/blender/editors/space_graph/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c349
-rw-r--r--source/blender/editors/space_graph/graph_draw.c685
-rw-r--r--source/blender/editors/space_graph/graph_edit.c31
-rw-r--r--source/blender/editors/space_graph/graph_intern.h4
-rw-r--r--source/blender/editors/space_graph/graph_ops.c227
-rw-r--r--source/blender/editors/space_graph/graph_select.c73
-rw-r--r--source/blender/editors/space_graph/graph_utils.c45
-rw-r--r--source/blender/editors/space_graph/space_graph.c228
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_image/image_buttons.c92
-rw-r--r--source/blender/editors/space_image/image_draw.c583
-rw-r--r--source/blender/editors/space_image/image_edit.c40
-rw-r--r--source/blender/editors/space_image/image_intern.h5
-rw-r--r--source/blender/editors/space_image/image_ops.c292
-rw-r--r--source/blender/editors/space_image/space_image.c251
-rw-r--r--source/blender/editors/space_info/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_info/info_draw.c3
-rw-r--r--source/blender/editors/space_info/info_intern.h2
-rw-r--r--source/blender/editors/space_info/info_ops.c32
-rw-r--r--source/blender/editors/space_info/info_report.c27
-rw-r--r--source/blender/editors/space_info/info_stats.c281
-rw-r--r--source/blender/editors/space_info/space_info.c89
-rw-r--r--source/blender/editors/space_info/textview.c53
-rw-r--r--source/blender/editors/space_logic/logic_buttons.c165
-rw-r--r--source/blender/editors/space_logic/logic_ops.c753
-rw-r--r--source/blender/editors/space_logic/logic_window.c2600
-rw-r--r--source/blender/editors/space_logic/space_logic.c373
-rw-r--r--source/blender/editors/space_nla/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c7
-rw-r--r--source/blender/editors/space_nla/nla_channels.c51
-rw-r--r--source/blender/editors/space_nla/nla_draw.c416
-rw-r--r--source/blender/editors/space_nla/nla_edit.c115
-rw-r--r--source/blender/editors/space_nla/nla_intern.h4
-rw-r--r--source/blender/editors/space_nla/nla_ops.c175
-rw-r--r--source/blender/editors/space_nla/nla_select.c84
-rw-r--r--source/blender/editors/space_nla/space_nla.c142
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_node/drawnode.c841
-rw-r--r--source/blender/editors/space_node/node_add.c14
-rw-r--r--source/blender/editors/space_node/node_buttons.c6
-rw-r--r--source/blender/editors/space_node/node_draw.c531
-rw-r--r--source/blender/editors/space_node/node_edit.c132
-rw-r--r--source/blender/editors/space_node/node_gizmo.c629
-rw-r--r--source/blender/editors/space_node/node_group.c7
-rw-r--r--source/blender/editors/space_node/node_intern.h22
-rw-r--r--source/blender/editors/space_node/node_ops.c153
-rw-r--r--source/blender/editors/space_node/node_relationships.c4
-rw-r--r--source/blender/editors/space_node/node_select.c29
-rw-r--r--source/blender/editors/space_node/node_templates.c37
-rw-r--r--source/blender/editors/space_node/space_node.c125
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c840
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c1013
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c2157
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c873
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h189
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c113
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c752
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c489
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c1077
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c246
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c222
-rw-r--r--source/blender/editors/space_script/script_edit.c20
-rw-r--r--source/blender/editors/space_script/script_intern.h1
-rw-r--r--source/blender/editors/space_script/script_ops.c1
-rw-r--r--source/blender/editors/space_script/space_script.c11
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c10
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c778
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c60
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h7
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c232
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c29
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c3
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c100
-rw-r--r--source/blender/editors/space_statusbar/CMakeLists.txt (renamed from source/blender/editors/space_logic/CMakeLists.txt)19
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c187
-rw-r--r--source/blender/editors/space_text/space_text.c174
-rw-r--r--source/blender/editors/space_text/text_draw.c261
-rw-r--r--source/blender/editors/space_text/text_header.c2
-rw-r--r--source/blender/editors/space_text/text_ops.c8
-rw-r--r--source/blender/editors/space_text/text_undo.c1
-rw-r--r--source/blender/editors/space_time/space_time.c834
-rw-r--r--source/blender/editors/space_time/time_ops.c226
-rw-r--r--source/blender/editors/space_topbar/CMakeLists.txt (renamed from source/blender/editors/space_time/CMakeLists.txt)9
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c294
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c52
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt28
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c402
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c2793
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c1405
-rw-r--r--source/blender/editors/space_view3d/drawobject.c8435
-rw-r--r--source/blender/editors/space_view3d/drawsimdebug.c180
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c853
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c752
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c97
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c4315
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c1075
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c1036
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c114
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c229
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_camera.c473
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_empty.c210
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_forcefield.c125
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_lamp.c307
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate.c325
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c535
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect.c114
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c429
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c1090
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c295
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h155
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c50
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c362
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c41
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c360
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c1659
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c500
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c209
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c267
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c717
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c102
-rw-r--r--source/blender/editors/transform/CMakeLists.txt9
-rw-r--r--source/blender/editors/transform/transform.c2831
-rw-r--r--source/blender/editors/transform/transform.h239
-rw-r--r--source/blender/editors/transform/transform_constraints.c210
-rw-r--r--source/blender/editors/transform/transform_conversions.c3882
-rw-r--r--source/blender/editors/transform/transform_generics.c1241
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c394
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c2206
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c472
-rw-r--r--source/blender/editors/transform/transform_input.c63
-rw-r--r--source/blender/editors/transform/transform_manipulator.c1982
-rw-r--r--source/blender/editors/transform/transform_ops.c401
-rw-r--r--source/blender/editors/transform/transform_orientations.c154
-rw-r--r--source/blender/editors/transform/transform_snap.c513
-rw-r--r--source/blender/editors/transform/transform_snap_object.c2696
-rw-r--r--source/blender/editors/undo/ed_undo.c85
-rw-r--r--source/blender/editors/undo/memfile_undo.c5
-rw-r--r--source/blender/editors/util/CMakeLists.txt7
-rw-r--r--source/blender/editors/util/ed_transverts.c10
-rw-r--r--source/blender/editors/util/ed_util.c111
-rw-r--r--source/blender/editors/util/gizmo_utils.c76
-rw-r--r--source/blender/editors/util/numinput.c98
-rw-r--r--source/blender/editors/util/select_utils.c125
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c24
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c1103
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h19
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2824
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c1235
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c865
-rw-r--r--source/blender/freestyle/CMakeLists.txt5
-rw-r--r--source/blender/freestyle/FRS_freestyle.h7
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp8
-rw-r--r--source/blender/freestyle/intern/application/Controller.h2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp370
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h20
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp195
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h2
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp49
-rw-r--r--source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp9
-rw-r--r--source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h15
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeViewLayer.cpp (renamed from source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.cpp)8
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeViewLayer.h (renamed from source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h)24
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneHash.cpp4
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneHash.h4
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneVisitor.h4
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.h3
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt72
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h53
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c216
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h (renamed from source/blender/render/intern/include/envmap.h)43
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c207
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c349
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c557
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c168
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c357
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c215
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c230
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c289
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c147
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c187
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c127
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c154
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c131
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c175
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c191
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c176
-rw-r--r--source/blender/gpu/CMakeLists.txt198
-rw-r--r--source/blender/gpu/GPU_attr_binding.h42
-rw-r--r--source/blender/gpu/GPU_basic_shader.h142
-rw-r--r--source/blender/gpu/GPU_batch.h209
-rw-r--r--source/blender/gpu/GPU_batch_presets.h56
-rw-r--r--source/blender/gpu/GPU_batch_utils.h44
-rw-r--r--source/blender/gpu/GPU_buffers.h203
-rw-r--r--source/blender/gpu/GPU_common.h (renamed from source/blender/editors/space_logic/logic_intern.h)49
-rw-r--r--source/blender/gpu/GPU_compositing.h106
-rw-r--r--source/blender/gpu/GPU_context.h (renamed from source/blender/render/intern/include/occlusion.h)41
-rw-r--r--source/blender/gpu/GPU_debug.h18
-rw-r--r--source/blender/gpu/GPU_draw.h90
-rw-r--r--source/blender/gpu/GPU_element.h103
-rw-r--r--source/blender/gpu/GPU_extensions.h19
-rw-r--r--source/blender/gpu/GPU_framebuffer.h154
-rw-r--r--source/blender/gpu/GPU_glew.h7
-rw-r--r--source/blender/gpu/GPU_immediate.h148
-rw-r--r--source/blender/gpu/GPU_immediate_util.h79
-rw-r--r--source/blender/gpu/GPU_legacy_stubs.h457
-rw-r--r--source/blender/gpu/GPU_material.h291
-rw-r--r--source/blender/gpu/GPU_matrix.h190
-rw-r--r--source/blender/gpu/GPU_primitive.h65
-rw-r--r--source/blender/gpu/GPU_select.h3
-rw-r--r--source/blender/gpu/GPU_shader.h319
-rw-r--r--source/blender/gpu/GPU_shader_interface.h105
-rw-r--r--source/blender/gpu/GPU_state.h67
-rw-r--r--source/blender/gpu/GPU_texture.h175
-rw-r--r--source/blender/gpu/GPU_uniformbuffer.h57
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h144
-rw-r--r--source/blender/gpu/GPU_vertex_format.h107
-rw-r--r--source/blender/gpu/GPU_viewport.h130
-rw-r--r--source/blender/gpu/intern/gpu_attr_binding.c85
-rw-r--r--source/blender/gpu/intern/gpu_attr_binding_private.h45
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c718
-rw-r--r--source/blender/gpu/intern/gpu_batch.c691
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c267
-rw-r--r--source/blender/gpu/intern/gpu_batch_private.h (renamed from source/blender/blenloader/BLO_runtime.h)33
-rw-r--r--source/blender/gpu/intern/gpu_batch_utils.c244
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c2064
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c1719
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h160
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c1460
-rw-r--r--source/blender/gpu/intern/gpu_context.cpp329
-rw-r--r--source/blender/gpu/intern/gpu_context_private.h71
-rw-r--r--source/blender/gpu/intern/gpu_debug.c700
-rw-r--r--source/blender/gpu/intern/gpu_draw.c2063
-rw-r--r--source/blender/gpu/intern/gpu_element.c314
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c242
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c995
-rw-r--r--source/blender/gpu/intern/gpu_immediate.c924
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c528
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c21
-rw-r--r--source/blender/gpu/intern/gpu_material.c3042
-rw-r--r--source/blender/gpu/intern/gpu_matrix.c649
-rw-r--r--source/blender/gpu/intern/gpu_primitive.c84
-rw-r--r--source/blender/gpu/intern/gpu_primitive_private.h (renamed from source/blender/editors/space_time/time_intern.h)23
-rw-r--r--source/blender/gpu/intern/gpu_private.h7
-rw-r--r--source/blender/gpu/intern/gpu_select.c33
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c14
-rw-r--r--source/blender/gpu/intern/gpu_select_private.h14
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.c25
-rw-r--r--source/blender/gpu/intern/gpu_shader.c1088
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c369
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.h46
-rw-r--r--source/blender/gpu/intern/gpu_state.c179
-rw-r--r--source/blender/gpu/intern/gpu_texture.c1488
-rw-r--r--source/blender/gpu/intern/gpu_uniformbuffer.c345
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.c272
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.c438
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format_private.h39
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c644
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl42
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl29
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl24
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl42
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl49
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl48
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl35
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl54
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl56
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl21
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl59
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl107
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl21
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl24
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl20
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl40
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl214
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl64
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl26
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl26
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl21
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl22
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl21
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl24
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_frag.glsl288
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_geom.glsl100
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_vert.glsl71
-rw-r--r--source/blender/gpu/shaders/gpu_shader_checker_frag.glsl20
-rw-r--r--source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl20
-rw-r--r--source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl54
-rw-r--r--source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl60
-rw-r--r--source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl68
-rw-r--r--source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl44
-rw-r--r--source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl20
-rw-r--r--source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl67
-rw-r--r--source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl52
-rw-r--r--source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fire_frag.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl208
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl167
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl66
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl58
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl71
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_lib.glsl39
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl94
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl18
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl166
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl20
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl196
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl32
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_frag.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl34
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_linear_frag.glsl30
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl127
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl50
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl25
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl57
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl63
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl32
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl29
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl23
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl23
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_vert.glsl13
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl87
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl83
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl3110
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl24
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl36
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl31
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl30
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl18
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl48
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl74
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_geom.glsl37
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl36
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl22
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_vert.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl21
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl111
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex_world.glsl80
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl21
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl7
-rw-r--r--source/blender/ikplugin/BIK_api.h5
-rw-r--r--source/blender/ikplugin/intern/ikplugin_api.c12
-rw-r--r--source/blender/ikplugin/intern/ikplugin_api.h7
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.c38
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.h9
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp73
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.h4
-rw-r--r--source/blender/imbuf/IMB_imbuf.h1
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h3
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c9
-rw-r--r--source/blender/imbuf/intern/divers.c56
-rw-r--r--source/blender/imbuf/intern/indexer.c2
-rw-r--r--source/blender/imbuf/intern/readimage.c1
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c2
-rw-r--r--source/blender/imbuf/intern/thumbs.c4
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c2
-rw-r--r--source/blender/makesdna/DNA_ID.h178
-rw-r--r--source/blender/makesdna/DNA_action_types.h94
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h583
-rw-r--r--source/blender/makesdna/DNA_anim_types.h53
-rw-r--r--source/blender/makesdna/DNA_armature_types.h16
-rw-r--r--source/blender/makesdna/DNA_brush_types.h158
-rw-r--r--source/blender/makesdna/DNA_camera_types.h57
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h29
-rw-r--r--source/blender/makesdna/DNA_collection_types.h94
-rw-r--r--source/blender/makesdna/DNA_color_types.h10
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h72
-rw-r--r--source/blender/makesdna/DNA_controller_types.h95
-rw-r--r--source/blender/makesdna/DNA_curve_types.h27
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_defs.h6
-rw-r--r--source/blender/makesdna/DNA_dynamicpaint_types.h9
-rw-r--r--source/blender/makesdna/DNA_effect_types.h4
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h6
-rw-r--r--source/blender/makesdna/DNA_freestyle_types.h4
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h483
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h374
-rw-r--r--source/blender/makesdna/DNA_gpu_types.h2
-rw-r--r--source/blender/makesdna/DNA_group_types.h65
-rw-r--r--source/blender/makesdna/DNA_image_types.h39
-rw-r--r--source/blender/makesdna/DNA_key_types.h11
-rw-r--r--source/blender/makesdna/DNA_lamp_types.h123
-rw-r--r--source/blender/makesdna/DNA_lattice_types.h1
-rw-r--r--source/blender/makesdna/DNA_layer_types.h163
-rw-r--r--source/blender/makesdna/DNA_lightprobe_types.h184
-rw-r--r--source/blender/makesdna/DNA_material_types.h446
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h68
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h86
-rw-r--r--source/blender/makesdna/DNA_meta_types.h6
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h176
-rw-r--r--source/blender/makesdna/DNA_node_types.h54
-rw-r--r--source/blender/makesdna/DNA_object_enums.h11
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h82
-rw-r--r--source/blender/makesdna/DNA_object_types.h300
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h26
-rw-r--r--source/blender/makesdna/DNA_particle_types.h56
-rw-r--r--source/blender/makesdna/DNA_property_types.h65
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h43
-rw-r--r--source/blender/makesdna/DNA_scene_types.h963
-rw-r--r--source/blender/makesdna/DNA_screen_types.h145
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h334
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h4
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h244
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h24
-rw-r--r--source/blender/makesdna/DNA_space_types.h292
-rw-r--r--source/blender/makesdna/DNA_texture_types.h136
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h231
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h4
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h349
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h67
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h214
-rw-r--r--source/blender/makesdna/DNA_world_types.h111
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c91
-rw-r--r--source/blender/makesdna/intern/makesdna.c35
-rw-r--r--source/blender/makesrna/RNA_access.h295
-rw-r--r--source/blender/makesrna/RNA_define.h14
-rw-r--r--source/blender/makesrna/RNA_enum_types.h32
-rw-r--r--source/blender/makesrna/RNA_types.h38
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt28
-rw-r--r--source/blender/makesrna/intern/makesrna.c83
-rw-r--r--source/blender/makesrna/intern/rna_ID.c290
-rw-r--r--source/blender/makesrna/intern/rna_access.c1286
-rw-r--r--source/blender/makesrna/intern/rna_action.c61
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c2220
-rw-r--r--source/blender/makesrna/intern/rna_actuator_api.c76
-rw-r--r--source/blender/makesrna/intern/rna_animation.c90
-rw-r--r--source/blender/makesrna/intern/rna_armature.c213
-rw-r--r--source/blender/makesrna/intern/rna_armature_api.c53
-rw-r--r--source/blender/makesrna/intern/rna_boid.c14
-rw-r--r--source/blender/makesrna/intern/rna_brush.c652
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c9
-rw-r--r--source/blender/makesrna/intern/rna_camera.c234
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c284
-rw-r--r--source/blender/makesrna/intern/rna_collection.c381
-rw-r--r--source/blender/makesrna/intern/rna_color.c63
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c608
-rw-r--r--source/blender/makesrna/intern/rna_context.c136
-rw-r--r--source/blender/makesrna/intern/rna_controller.c327
-rw-r--r--source/blender/makesrna/intern/rna_controller_api.c85
-rw-r--r--source/blender/makesrna/intern/rna_curve.c81
-rw-r--r--source/blender/makesrna/intern/rna_curve_api.c10
-rw-r--r--source/blender/makesrna/intern/rna_define.c54
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c543
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c30
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c88
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c5
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c1171
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c1652
-rw-r--r--source/blender/makesrna/intern/rna_group.c144
-rw-r--r--source/blender/makesrna/intern/rna_image.c237
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c29
-rw-r--r--source/blender/makesrna/intern/rna_internal.h107
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h71
-rw-r--r--source/blender/makesrna/intern/rna_key.c9
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c771
-rw-r--r--source/blender/makesrna/intern/rna_lattice.c7
-rw-r--r--source/blender/makesrna/intern/rna_lattice_api.c10
-rw-r--r--source/blender/makesrna/intern/rna_layer.c455
-rw-r--r--source/blender/makesrna/intern/rna_lightprobe.c231
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c21
-rw-r--r--source/blender/makesrna/intern/rna_main.c323
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c415
-rw-r--r--source/blender/makesrna/intern/rna_mask.c20
-rw-r--r--source/blender/makesrna/intern/rna_material.c2191
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c1501
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c36
-rw-r--r--source/blender/makesrna/intern/rna_mesh_utils.h11
-rw-r--r--source/blender/makesrna/intern/rna_meta.c14
-rw-r--r--source/blender/makesrna/intern/rna_meta_api.c9
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c336
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c17
-rw-r--r--source/blender/makesrna/intern/rna_nla.c35
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c236
-rw-r--r--source/blender/makesrna/intern/rna_object.c1870
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c360
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c290
-rw-r--r--source/blender/makesrna/intern/rna_palette.c4
-rw-r--r--source/blender/makesrna/intern/rna_particle.c373
-rw-r--r--source/blender/makesrna/intern/rna_pose.c189
-rw-r--r--source/blender/makesrna/intern/rna_pose_api.c71
-rw-r--r--source/blender/makesrna/intern/rna_property.c202
-rw-r--r--source/blender/makesrna/intern/rna_render.c69
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c93
-rw-r--r--source/blender/makesrna/intern/rna_rna.c1175
-rw-r--r--source/blender/makesrna/intern/rna_scene.c3401
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c36
-rw-r--r--source/blender/makesrna/intern/rna_screen.c258
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c450
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c939
-rw-r--r--source/blender/makesrna/intern/rna_sensor_api.c78
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c42
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c707
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c52
-rw-r--r--source/blender/makesrna/intern/rna_sound.c1
-rw-r--r--source/blender/makesrna/intern/rna_space.c2513
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c26
-rw-r--r--source/blender/makesrna/intern/rna_speaker.c1
-rw-r--r--source/blender/makesrna/intern/rna_texture.c664
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c51
-rw-r--r--source/blender/makesrna/intern/rna_timeline.c2
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c14
-rw-r--r--source/blender/makesrna/intern/rna_ui.c212
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c186
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c966
-rw-r--r--source/blender/makesrna/intern/rna_vfont.c5
-rw-r--r--source/blender/makesrna/intern/rna_wm.c347
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c164
-rw-r--r--source/blender/makesrna/intern/rna_wm_gizmo.c1408
-rw-r--r--source/blender/makesrna/intern/rna_wm_gizmo_api.c290
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c384
-rw-r--r--source/blender/makesrna/intern/rna_workspace_api.c176
-rw-r--r--source/blender/makesrna/intern/rna_world.c325
-rw-r--r--source/blender/modifiers/CMakeLists.txt10
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c99
-rw-r--r--source/blender/modifiers/intern/MOD_array.c242
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c331
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c131
-rw-r--r--source/blender/modifiers/intern/MOD_build.c89
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c81
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c102
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c211
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c106
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c79
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c71
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c54
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c101
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c76
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c46
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c385
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c84
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.c106
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim_util.h9
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c86
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c96
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c65
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c62
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c89
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c43
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c140
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c136
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c234
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c172
-rw-r--r--source/blender/modifiers/intern/MOD_none.c12
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c238
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c219
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c102
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c182
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c93
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c110
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c49
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c101
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c83
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c130
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c62
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c63
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c46
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c141
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c208
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c81
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c105
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c47
-rw-r--r--source/blender/modifiers/intern/MOD_util.c165
-rw-r--r--source/blender/modifiers/intern/MOD_util.h34
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c217
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c71
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c110
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c135
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c669
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c30
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.h16
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c110
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c114
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c175
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c39
-rw-r--r--source/blender/nodes/CMakeLists.txt8
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/NOD_shader.h10
-rw-r--r--source/blender/nodes/NOD_socket.h2
-rw-r--r--source/blender/nodes/NOD_static_types.h10
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c18
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_splitViewer.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.c1
-rw-r--r--source/blender/nodes/intern/node_common.c3
-rw-r--r--source/blender/nodes/intern/node_exec.c2
-rw-r--r--source/blender/nodes/intern/node_socket.c2
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c346
-rw-r--r--source/blender/nodes/shader/node_shader_util.c79
-rw-r--r--source/blender/nodes/shader/node_shader_util.h10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_add_shader.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_background.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bevel.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_blackbody.c15
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c99
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c21
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.c24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.c14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_displacement.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_eevee_specular.c88
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_emission.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.c34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geom.c163
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hair_info.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_holdout.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ies_light.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_lamp.c91
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_layer_weight.c45
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_falloff.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_material.c374
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_shader.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c168
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.c12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output.c97
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_lamp.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_linestyle.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_world.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_particle_info.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_script.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c60
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_squeeze.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tangent.c24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.c22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c44
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c98
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_texture.c166
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.c40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectMath.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectTransform.c86
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_displacement.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_absorption.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.c85
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_scatter.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wavelength.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wireframe.c13
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c44
-rw-r--r--source/blender/nodes/texture/node_texture_util.c1
-rw-r--r--source/blender/nodes/texture/node_texture_util.h3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_image.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_texture.c2
-rw-r--r--source/blender/physics/BPH_mass_spring.h5
-rw-r--r--source/blender/physics/CMakeLists.txt1
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp223
-rw-r--r--source/blender/physics/intern/hair_volume.cpp57
-rw-r--r--source/blender/physics/intern/implicit.h12
-rw-r--r--source/blender/physics/intern/implicit_blender.c189
-rw-r--r--source/blender/python/BPY_extern.h3
-rw-r--r--source/blender/python/CMakeLists.txt1
-rw-r--r--source/blender/python/bmesh/CMakeLists.txt1
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c23
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops.c25
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c46
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c25
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c21
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c92
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.h4
-rw-r--r--source/blender/python/generic/bgl.c1267
-rw-r--r--source/blender/python/generic/blf_py_api.c39
-rw-r--r--source/blender/python/generic/bpy_internal_import.c12
-rw-r--r--source/blender/python/generic/bpy_internal_import.h5
-rw-r--r--source/blender/python/generic/idprop_py_api.c28
-rw-r--r--source/blender/python/generic/py_capi_utils.c78
-rw-r--r--source/blender/python/generic/py_capi_utils.h9
-rw-r--r--source/blender/python/gpu/CMakeLists.txt64
-rw-r--r--source/blender/python/gpu/gpu_py_api.c85
-rw-r--r--source/blender/python/gpu/gpu_py_api.h (renamed from source/blender/render/intern/include/texture_ocean.h)19
-rw-r--r--source/blender/python/gpu/gpu_py_batch.c384
-rw-r--r--source/blender/python/gpu/gpu_py_batch.h48
-rw-r--r--source/blender/python/gpu/gpu_py_element.c242
-rw-r--r--source/blender/python/gpu/gpu_py_element.h39
-rw-r--r--source/blender/python/gpu/gpu_py_matrix.c575
-rw-r--r--source/blender/python/gpu/gpu_py_matrix.h30
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c371
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.h42
-rw-r--r--source/blender/python/gpu/gpu_py_primitive.c81
-rw-r--r--source/blender/python/gpu/gpu_py_primitive.h30
-rw-r--r--source/blender/python/gpu/gpu_py_select.c95
-rw-r--r--source/blender/python/gpu/gpu_py_select.h30
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c834
-rw-r--r--source/blender/python/gpu/gpu_py_shader.h41
-rw-r--r--source/blender/python/gpu/gpu_py_types.c80
-rw-r--r--source/blender/python/gpu/gpu_py_types.h37
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_buffer.c352
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_buffer.h42
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_format.c263
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_format.h41
-rw-r--r--source/blender/python/intern/CMakeLists.txt25
-rw-r--r--source/blender/python/intern/bpy.c8
-rw-r--r--source/blender/python/intern/bpy_app.c40
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c21
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c47
-rw-r--r--source/blender/python/intern/bpy_app_icons.c187
-rw-r--r--source/blender/python/intern/bpy_app_icons.h30
-rw-r--r--source/blender/python/intern/bpy_app_timers.c199
-rw-r--r--source/blender/python/intern/bpy_app_timers.h30
-rw-r--r--source/blender/python/intern/bpy_driver.c50
-rw-r--r--source/blender/python/intern/bpy_driver.h7
-rw-r--r--source/blender/python/intern/bpy_gizmo_wrap.c228
-rw-r--r--source/blender/python/intern/bpy_gizmo_wrap.h35
-rw-r--r--source/blender/python/intern/bpy_interface.c11
-rw-r--r--source/blender/python/intern/bpy_intern_string.c48
-rw-r--r--source/blender/python/intern/bpy_intern_string.h23
-rw-r--r--source/blender/python/intern/bpy_library_load.c19
-rw-r--r--source/blender/python/intern/bpy_library_write.c1
-rw-r--r--source/blender/python/intern/bpy_msgbus.c399
-rw-r--r--source/blender/python/intern/bpy_msgbus.h30
-rw-r--r--source/blender/python/intern/bpy_props.c5
-rw-r--r--source/blender/python/intern/bpy_props.h2
-rw-r--r--source/blender/python/intern/bpy_rna.c202
-rw-r--r--source/blender/python/intern/bpy_rna.h4
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c10
-rw-r--r--source/blender/python/intern/bpy_rna_callback.c195
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.c564
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.h (renamed from source/blender/python/intern/gpu.h)21
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c3
-rw-r--r--source/blender/python/intern/bpy_utils_units.c1
-rw-r--r--source/blender/python/intern/gpu.c342
-rw-r--r--source/blender/python/intern/gpu_offscreen.c408
-rw-r--r--source/blender/python/mathutils/mathutils.c5
-rw-r--r--source/blender/python/mathutils/mathutils.h2
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c187
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c135
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c164
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c39
-rw-r--r--source/blender/python/mathutils/mathutils_noise.c565
-rw-r--r--source/blender/python/simple_enum_gen.py2
-rw-r--r--source/blender/render/CMakeLists.txt62
-rw-r--r--source/blender/render/extern/include/RE_bake.h6
-rw-r--r--source/blender/render/extern/include/RE_engine.h34
-rw-r--r--source/blender/render/extern/include/RE_multires_bake.h8
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h83
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h23
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h188
-rw-r--r--source/blender/render/intern/include/initrender.h7
-rw-r--r--source/blender/render/intern/include/pixelblending.h65
-rw-r--r--source/blender/render/intern/include/pixelshading.h61
-rw-r--r--source/blender/render/intern/include/pointdensity.h50
-rw-r--r--source/blender/render/intern/include/raycounter.h74
-rw-r--r--source/blender/render/intern/include/rayintersection.h135
-rw-r--r--source/blender/render/intern/include/rayobject.h121
-rw-r--r--source/blender/render/intern/include/render_result.h25
-rw-r--r--source/blender/render/intern/include/render_types.h535
-rw-r--r--source/blender/render/intern/include/rendercore.h105
-rw-r--r--source/blender/render/intern/include/renderdatabase.h173
-rw-r--r--source/blender/render/intern/include/renderpipeline.h4
-rw-r--r--source/blender/render/intern/include/shadbuf.h111
-rw-r--r--source/blender/render/intern/include/shading.h105
-rw-r--r--source/blender/render/intern/include/sss.h66
-rw-r--r--source/blender/render/intern/include/strand.h98
-rw-r--r--source/blender/render/intern/include/sunsky.h81
-rw-r--r--source/blender/render/intern/include/texture.h17
-rw-r--r--source/blender/render/intern/include/volumetric.h51
-rw-r--r--source/blender/render/intern/include/zbuf.h101
-rw-r--r--source/blender/render/intern/raytrace/bvh.h407
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp533
-rw-r--r--source/blender/render/intern/raytrace/rayobject_empty.cpp80
-rw-r--r--source/blender/render/intern/raytrace/rayobject_hint.h72
-rw-r--r--source/blender/render/intern/raytrace/rayobject_instance.cpp210
-rw-r--r--source/blender/render/intern/raytrace/rayobject_internal.h157
-rw-r--r--source/blender/render/intern/raytrace/rayobject_octree.cpp1098
-rw-r--r--source/blender/render/intern/raytrace/rayobject_qbvh.cpp160
-rw-r--r--source/blender/render/intern/raytrace/rayobject_raycounter.cpp91
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp531
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.h125
-rw-r--r--source/blender/render/intern/raytrace/rayobject_svbvh.cpp192
-rw-r--r--source/blender/render/intern/raytrace/rayobject_vbvh.cpp206
-rw-r--r--source/blender/render/intern/raytrace/reorganize.h513
-rw-r--r--source/blender/render/intern/raytrace/svbvh.h317
-rw-r--r--source/blender/render/intern/raytrace/vbvh.h238
-rw-r--r--source/blender/render/intern/source/bake.c1342
-rw-r--r--source/blender/render/intern/source/bake_api.c171
-rw-r--r--source/blender/render/intern/source/convertblender.c6014
-rw-r--r--source/blender/render/intern/source/envmap.c822
-rw-r--r--source/blender/render/intern/source/external_engine.c279
-rw-r--r--source/blender/render/intern/source/imagetexture.c97
-rw-r--r--source/blender/render/intern/source/initrender.c363
-rw-r--r--source/blender/render/intern/source/multires_bake.c162
-rw-r--r--source/blender/render/intern/source/occlusion.c1532
-rw-r--r--source/blender/render/intern/source/pipeline.c1765
-rw-r--r--source/blender/render/intern/source/pixelblending.c400
-rw-r--r--source/blender/render/intern/source/pixelshading.c650
-rw-r--r--source/blender/render/intern/source/pointdensity.c270
-rw-r--r--source/blender/render/intern/source/rayshade.c2502
-rw-r--r--source/blender/render/intern/source/render_result.c131
-rw-r--r--source/blender/render/intern/source/render_texture.c2512
-rw-r--r--source/blender/render/intern/source/rendercore.c2030
-rw-r--r--source/blender/render/intern/source/renderdatabase.c1602
-rw-r--r--source/blender/render/intern/source/shadbuf.c2647
-rw-r--r--source/blender/render/intern/source/shadeinput.c1489
-rw-r--r--source/blender/render/intern/source/shadeoutput.c2183
-rw-r--r--source/blender/render/intern/source/sss.c1073
-rw-r--r--source/blender/render/intern/source/strand.c1068
-rw-r--r--source/blender/render/intern/source/sunsky.c506
-rw-r--r--source/blender/render/intern/source/texture_ocean.c160
-rw-r--r--source/blender/render/intern/source/volume_precache.c854
-rw-r--r--source/blender/render/intern/source/volumetric.c836
-rw-r--r--source/blender/render/intern/source/voxeldata.c571
-rw-r--r--source/blender/render/intern/source/zbuf.c3498
-rw-r--r--source/blender/shader_fx/CMakeLists.txt66
-rw-r--r--source/blender/shader_fx/FX_shader_types.h49
-rw-r--r--source/blender/shader_fx/intern/FX_shader_blur.c66
-rw-r--r--source/blender/shader_fx/intern/FX_shader_colorize.c69
-rw-r--r--source/blender/shader_fx/intern/FX_shader_flip.c69
-rw-r--r--source/blender/shader_fx/intern/FX_shader_glow.c78
-rw-r--r--source/blender/shader_fx/intern/FX_shader_light.c104
-rw-r--r--source/blender/shader_fx/intern/FX_shader_pixel.c65
-rw-r--r--source/blender/shader_fx/intern/FX_shader_rim.c72
-rw-r--r--source/blender/shader_fx/intern/FX_shader_shadow.c113
-rw-r--r--source/blender/shader_fx/intern/FX_shader_swirl.c103
-rw-r--r--source/blender/shader_fx/intern/FX_shader_util.c57
-rw-r--r--source/blender/shader_fx/intern/FX_shader_util.h (renamed from source/blender/blenkernel/BKE_bullet.h)17
-rw-r--r--source/blender/shader_fx/intern/FX_shader_wave.c71
-rw-r--r--source/blender/windowmanager/CMakeLists.txt32
-rw-r--r--source/blender/windowmanager/WM_api.h164
-rw-r--r--source/blender/windowmanager/WM_keymap.h26
-rw-r--r--source/blender/windowmanager/WM_message.h30
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h121
-rw-r--r--source/blender/windowmanager/WM_types.h49
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h354
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h441
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo.c800
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c1004
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c205
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h144
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c1242
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c364
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c212
-rw-r--r--source/blender/windowmanager/gizmo/wm_gizmo_fn.h90
-rw-r--r--source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h97
-rw-r--r--source/blender/windowmanager/intern/wm.c74
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c18
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c106
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c1147
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c1192
-rw-r--r--source/blender/windowmanager/intern/wm_files.c525
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c126
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c288
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c89
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c254
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c152
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c98
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c11
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c67
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c96
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c805
-rw-r--r--source/blender/windowmanager/intern/wm_panel_type.c88
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c102
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c329
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c348
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c904
-rw-r--r--source/blender/windowmanager/intern/wm_tooltip.c57
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c622
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus.c258
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h55
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c338
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c141
-rw-r--r--source/blender/windowmanager/message_bus/wm_message_bus.h290
-rw-r--r--source/blender/windowmanager/wm.h14
-rw-r--r--source/blender/windowmanager/wm_draw.h30
-rw-r--r--source/blender/windowmanager/wm_event_system.h17
-rw-r--r--source/blender/windowmanager/wm_event_types.h12
-rw-r--r--source/blender/windowmanager/wm_files.h3
-rw-r--r--source/blender/windowmanager/wm_subwindow.h51
-rw-r--r--source/blender/windowmanager/wm_window.h18
2122 files changed, 334091 insertions, 222343 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 690e1bcf318..a4d8e21c349 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -26,7 +26,6 @@
set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_ID.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_action_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_actuator_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_anim_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
@@ -34,9 +33,9 @@ set(SRC_DNA_INC
${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_collection_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_constraint_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_controller_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curve_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_customdata_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defs.h
@@ -46,53 +45,55 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fileglobal_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_freestyle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_genfile.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpu_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_group_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_ipo_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_key_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lamp_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lattice_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_layer_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lightprobe_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_linestyle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_listBase.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mask_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_material_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mesh_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_meshdata_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mesh_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_meta_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_modifier_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_movieclip_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_nla_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_node_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_enums.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_fluidsim_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_force_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_enums.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_outliner_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_packedFile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_property_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_rigidbody_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_screen_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sdna_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sensor_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sequence_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_shader_fx_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_smoke_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sound_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_space_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_speaker_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_text_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_texture_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_tracking_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_userdef_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_vec_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_vfont_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view2d_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view3d_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_windowmanager_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_workspace_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_world_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_movieclip_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_tracking_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mask_types.h
)
add_subdirectory(datatoc)
@@ -101,6 +102,7 @@ add_subdirectory(windowmanager)
add_subdirectory(blenkernel)
add_subdirectory(blenlib)
add_subdirectory(bmesh)
+add_subdirectory(draw)
add_subdirectory(render)
add_subdirectory(blenfont)
add_subdirectory(blentranslation)
@@ -112,6 +114,8 @@ add_subdirectory(gpu)
add_subdirectory(imbuf)
add_subdirectory(nodes)
add_subdirectory(modifiers)
+add_subdirectory(gpencil_modifiers)
+add_subdirectory(shader_fx)
add_subdirectory(makesdna)
add_subdirectory(makesrna)
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index 70250310213..08136fc2f49 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -29,8 +29,8 @@ extern "C" {
struct bContext;
struct CacheReader;
-struct DerivedMesh;
struct ListBase;
+struct Mesh;
struct Object;
struct Scene;
@@ -114,12 +114,13 @@ void ABC_get_transform(struct CacheReader *reader,
float time,
float scale);
-struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader,
- struct Object *ob,
- struct DerivedMesh *dm,
- const float time,
- const char **err_str,
- int flags);
+/* Either modifies current_mesh in-place or constructs a new mesh. */
+struct Mesh *ABC_read_mesh(struct CacheReader *reader,
+ struct Object *ob,
+ struct Mesh *current_mesh,
+ const float time,
+ const char **err_str,
+ int flags);
void CacheReader_incref(struct CacheReader *reader);
void CacheReader_free(struct CacheReader *reader);
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt
index fb08887c076..d3b5e189292 100644
--- a/source/blender/alembic/CMakeLists.txt
+++ b/source/blender/alembic/CMakeLists.txt
@@ -29,11 +29,11 @@ set(INC
../blenlib
../blenloader
../bmesh
+ ../depsgraph
../editors/include
../makesdna
../makesrna
../windowmanager
- ../depsgraph
../../../intern/guardedalloc
../../../intern/utfconv
)
diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc
index 16416205983..457bbd2b3af 100644
--- a/source/blender/alembic/intern/abc_camera.cc
+++ b/source/blender/alembic/intern/abc_camera.cc
@@ -49,12 +49,11 @@ using Alembic::AbcGeom::kWrapExisting;
/* ************************************************************************** */
-AbcCameraWriter::AbcCameraWriter(Scene *scene,
- Object *ob,
+AbcCameraWriter::AbcCameraWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
OCamera camera(parent->alembicXform(), m_name, m_time_sampling);
m_camera_schema = camera.getSchema();
diff --git a/source/blender/alembic/intern/abc_camera.h b/source/blender/alembic/intern/abc_camera.h
index 16c5cccd5ea..dd5dc28d598 100644
--- a/source/blender/alembic/intern/abc_camera.h
+++ b/source/blender/alembic/intern/abc_camera.h
@@ -35,8 +35,7 @@ class AbcCameraWriter : public AbcObjectWriter {
Alembic::AbcGeom::OFloatProperty m_eye_separation;
public:
- AbcCameraWriter(Scene *scene,
- Object *ob,
+ AbcCameraWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
index b0e2538e8bc..f9880eda451 100644
--- a/source/blender/alembic/intern/abc_curves.cc
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -37,8 +37,8 @@ extern "C" {
#include "BLI_listbase.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "ED_curve.h"
@@ -71,12 +71,11 @@ using Alembic::AbcGeom::OV2fGeomParam;
/* ************************************************************************** */
-AbcCurveWriter::AbcCurveWriter(Scene *scene,
- Object *ob,
+AbcCurveWriter::AbcCurveWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
m_schema = curves.getSchema();
@@ -257,9 +256,21 @@ void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele
/* ************************************************************************** */
-void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel)
+void AbcCurveReader::read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel)
{
- ICurvesSchema::Sample smp = schema.getValue(sample_sel);
+ ICurvesSchema::Sample smp;
+ try {
+ smp = schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return;
+ }
+
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
const P3fArraySamplePtr positions = smp.getPositions();
const FloatArraySamplePtr weights = smp.getPositionWeights();
@@ -399,18 +410,31 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSele
}
}
-/* NOTE: Alembic only stores data about control points, but the DerivedMesh
+/* NOTE: Alembic only stores data about control points, but the Mesh
* 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
+ * object directly and create a new Mesh from that. Also we might need to
* create new or delete existing NURBS in the curve.
*/
-DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/,
- const ISampleSelector &sample_sel,
- int /*read_flag*/,
- const char ** /*err_str*/)
+Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int /*read_flag*/,
+ const char **err_str)
{
- const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel);
+ ICurvesSchema::Sample sample;
+
+ try {
+ sample = m_curves_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ *err_str = "Error reading curve sample; more detail on the console";
+ printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_curves_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
const P3fArraySamplePtr &positions = sample.getPositions();
const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
@@ -449,5 +473,5 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/,
}
}
- return CDDM_from_curve(m_object);
+ return BKE_mesh_new_nomain_from_curve(m_object);
}
diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h
index a9231f947b2..eb80553620d 100644
--- a/source/blender/alembic/intern/abc_curves.h
+++ b/source/blender/alembic/intern/abc_curves.h
@@ -36,8 +36,7 @@ class AbcCurveWriter : public AbcObjectWriter {
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
public:
- AbcCurveWriter(Scene *scene,
- Object *ob,
+ AbcCurveWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
@@ -59,16 +58,17 @@ public:
const char **err_str) const;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
+
+ void read_curve_sample(Curve *cu,
+ const Alembic::AbcGeom::ICurvesSchema &schema,
+ const Alembic::Abc::ISampleSelector &sample_selector);
+
};
/* ************************************************************************** */
-void read_curve_sample(Curve *cu,
- const Alembic::AbcGeom::ICurvesSchema &schema,
- const Alembic::Abc::ISampleSelector &sample_selector);
-
#endif /* __ABC_CURVES_H__ */
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index 9ffed421302..d470488937a 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -60,6 +60,8 @@ extern "C" {
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
}
using Alembic::Abc::TimeSamplingPtr;
@@ -69,6 +71,8 @@ using Alembic::Abc::OBox3dProperty;
ExportSettings::ExportSettings()
: scene(NULL)
+ , view_layer(NULL)
+ , depsgraph(NULL)
, logger()
, selected_only(false)
, visible_layers_only(false)
@@ -111,7 +115,7 @@ static bool object_is_smoke_sim(Object *ob)
return false;
}
-static bool object_type_is_exportable(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
+static bool object_type_is_exportable(Scene *scene, Object *ob)
{
switch (ob->type) {
case OB_MESH:
@@ -126,7 +130,7 @@ static bool object_type_is_exportable(Main *bmain, EvaluationContext *eval_ctx,
case OB_CAMERA:
return true;
case OB_MBALL:
- return AbcMBallWriter::isBasisBall(bmain, eval_ctx, scene, ob);
+ return AbcMBallWriter::isBasisBall(scene, ob);
default:
return false;
}
@@ -136,45 +140,44 @@ static bool object_type_is_exportable(Main *bmain, EvaluationContext *eval_ctx,
/**
* Returns whether this object should be exported into the Alembic file.
*
- * \param settings: export settings, used for options like 'selected only'.
- * \param ob: the object in question.
+ * \param settings export settings, used for options like 'selected only'.
+ * \param ob the object's base in question.
* \param is_duplicated: Normally false; true when the object is instanced
* into the scene by a dupli-object (e.g. part of a dupligroup).
* This ignores selection and layer visibility,
* and assumes that the dupli-object itself (e.g. the group-instantiating empty) is exported.
*/
-static bool export_object(const ExportSettings * const settings, Object *ob,
+static bool export_object(const ExportSettings * const settings, const Base * const ob_base,
bool is_duplicated)
{
if (!is_duplicated) {
/* These two tests only make sense when the object isn't being instanced
* into the scene. When it is, its exportability is determined by
* its dupli-object and the DupliObject::no_draw property. */
- if (settings->selected_only && !parent_selected(ob)) {
+ if (settings->selected_only && !object_selected(ob_base)) {
return false;
}
-
- if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
+ // FIXME Sybren: handle these cleanly (maybe just remove code), now using active scene layer instead.
+ if (settings->visible_layers_only && (ob_base->flag & BASE_VISIBLE) == 0) {
return false;
}
}
- if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
- return false;
- }
+ // if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
+ // return false;
+ // }
return true;
}
/* ************************************************************************** */
-AbcExporter::AbcExporter(Main *bmain, Scene *scene, const char *filename, ExportSettings &settings)
+AbcExporter::AbcExporter(Main *bmain, const char *filename, ExportSettings &settings)
: m_bmain(bmain)
, m_settings(settings)
, m_filename(filename)
, m_trans_sampling_index(0)
, m_shape_sampling_index(0)
- , m_scene(scene)
, m_writer(NULL)
{}
@@ -198,7 +201,7 @@ void AbcExporter::getShutterSamples(unsigned int nr_of_samples,
bool time_relative,
std::vector<double> &samples)
{
- Scene *scene = m_scene; /* for use in the FPS macro */
+ Scene *scene = m_settings.scene; /* for use in the FPS macro */
samples.clear();
unsigned int frame_offset = time_relative ? m_settings.frame_start : 0;
@@ -228,7 +231,7 @@ Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
Alembic::Abc::TimeSamplingType ts(
static_cast<uint32_t>(samples.size()),
- 1.0 / m_scene->r.frs_sec);
+ 1.0 / m_settings.scene->r.frs_sec); /* TODO(Sybren): shouldn't we use the FPS macro here? */
return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples));
}
@@ -249,20 +252,20 @@ void AbcExporter::getFrameSet(unsigned int nr_of_samples,
}
}
-void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
+void AbcExporter::operator()(float &progress, bool &was_canceled)
{
std::string scene_name;
- if (bmain->name[0] != '\0') {
+ if (m_bmain->name[0] != '\0') {
char scene_file_name[FILE_MAX];
- BLI_strncpy(scene_file_name, bmain->name, FILE_MAX);
+ BLI_strncpy(scene_file_name, m_bmain->name, FILE_MAX);
scene_name = scene_file_name;
}
else {
scene_name = "untitled";
}
- Scene *scene = m_scene;
+ Scene *scene = m_settings.scene;
const double fps = FPS;
char buf[16];
snprintf(buf, 15, "%f", fps);
@@ -294,8 +297,8 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index);
- createTransformWritersHierarchy(bmain->eval_ctx);
- createShapeWriters(bmain->eval_ctx);
+ createTransformWritersHierarchy();
+ createShapeWriters();
/* Make a list of frames to export. */
@@ -328,7 +331,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
const double frame = *begin;
/* 'frame' is offset by start frame, so need to cancel the offset. */
- setCurrentFrame(bmain, frame);
+ setCurrentFrame(m_bmain, frame);
if (shape_frames.count(frame) != 0) {
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
@@ -357,42 +360,44 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
}
}
-void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
+void AbcExporter::createTransformWritersHierarchy()
{
- Base *base = static_cast<Base *>(m_scene->base.first);
-
- while (base) {
+ for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; base = base->next) {
Object *ob = base->object;
- switch (ob->type) {
- case OB_LAMP:
- case OB_LATTICE:
- case OB_SPEAKER:
- /* We do not export transforms for objects of these classes. */
- break;
- default:
- exploreTransform(eval_ctx, ob, ob->parent);
+ if (export_object(&m_settings, base, false)) {
+ switch (ob->type) {
+ case OB_LAMP:
+ case OB_LATTICE:
+ case OB_SPEAKER:
+ /* We do not export transforms for objects of these classes. */
+ break;
+ default:
+ exploreTransform(base, ob->parent, NULL);
+ }
}
-
- base = base->next;
}
}
-void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
+void AbcExporter::exploreTransform(Base *ob_base, Object *parent, Object *dupliObParent)
{
/* If an object isn't exported itself, its duplilist shouldn't be
* exported either. */
- if (!export_object(&m_settings, ob, dupliObParent != NULL)) {
+ if (!export_object(&m_settings, ob_base, dupliObParent != NULL)) {
return;
}
- if (object_type_is_exportable(m_bmain, eval_ctx, m_scene, ob)) {
+ Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, ob_base->object);
+ if (object_type_is_exportable(m_settings.scene, ob)) {
createTransformWriter(ob, parent, dupliObParent);
}
- ListBase *lb = object_duplilist(m_bmain, eval_ctx, m_scene, ob);
+ ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob);
if (lb) {
+ Base fake_base = *ob_base; // copy flags (like selection state) from the real object.
+ fake_base.next = fake_base.prev = NULL;
+
DupliObject *link = static_cast<DupliObject *>(lb->first);
Object *dupli_ob = NULL;
Object *dupli_parent = NULL;
@@ -403,11 +408,12 @@ void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Obje
continue;
}
- if (link->type == OB_DUPLIGROUP) {
+ if (link->type == OB_DUPLICOLLECTION) {
dupli_ob = link->ob;
dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
- exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
+ fake_base.object = dupli_ob;
+ exploreTransform(&fake_base, dupli_parent, ob);
}
}
@@ -484,31 +490,30 @@ AbcTransformWriter *AbcExporter::createTransformWriter(Object *ob, Object *paren
return my_writer;
}
-void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
+void AbcExporter::createShapeWriters()
{
- Base *base = static_cast<Base *>(m_scene->base.first);
-
- while (base) {
- Object *ob = base->object;
- exploreObject(eval_ctx, ob, NULL);
-
- base = base->next;
+ for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; base = base->next) {
+ exploreObject(base, NULL);
}
}
-void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
+void AbcExporter::exploreObject(Base *ob_base, Object *dupliObParent)
{
/* If an object isn't exported itself, its duplilist shouldn't be
* exported either. */
- if (!export_object(&m_settings, ob, dupliObParent != NULL)) {
+ if (!export_object(&m_settings, ob_base, dupliObParent != NULL)) {
return;
}
+ Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, ob_base->object);
createShapeWriter(ob, dupliObParent);
- ListBase *lb = object_duplilist(m_bmain, eval_ctx, m_scene, ob);
+ ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob);
if (lb) {
+ Base fake_base = *ob_base; // copy flags (like selection state) from the real object.
+ fake_base.next = fake_base.prev = NULL;
+
DupliObject *link = static_cast<DupliObject *>(lb->first);
for (; link; link = link->next) {
@@ -516,9 +521,9 @@ void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object
if (m_settings.renderable_only && link->no_draw) {
continue;
}
-
- if (link->type == OB_DUPLIGROUP) {
- exploreObject(eval_ctx, link->ob, ob);
+ if (link->type == OB_DUPLICOLLECTION) {
+ fake_base.object = link->ob;
+ exploreObject(&fake_base, ob);
}
}
@@ -541,17 +546,17 @@ void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *x
if (m_settings.export_hair && 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));
+ m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
else if (m_settings.export_particles && psys->part->type == PART_EMITTER) {
- m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
}
}
void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
{
- if (!object_type_is_exportable(m_bmain, m_bmain->eval_ctx, m_scene, ob)) {
+ if (!object_type_is_exportable(m_settings.scene, ob)) {
return;
}
@@ -582,7 +587,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
return;
}
- m_shapes.push_back(new AbcMeshWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ m_shapes.push_back(new AbcMeshWriter(ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_SURF:
@@ -593,7 +598,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
return;
}
- m_shapes.push_back(new AbcNurbsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ m_shapes.push_back(new AbcNurbsWriter(ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_CURVE:
@@ -604,7 +609,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
return;
}
- m_shapes.push_back(new AbcCurveWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ m_shapes.push_back(new AbcCurveWriter(ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_CAMERA:
@@ -612,7 +617,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
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));
+ m_shapes.push_back(new AbcCameraWriter(ob, xform, m_shape_sampling_index, m_settings));
}
break;
@@ -625,7 +630,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
}
m_shapes.push_back(new AbcMBallWriter(
- m_bmain, m_scene, ob, xform,
+ m_bmain, ob, xform,
m_shape_sampling_index, m_settings));
break;
}
@@ -645,7 +650,7 @@ AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
void AbcExporter::setCurrentFrame(Main *bmain, double t)
{
- m_scene->r.cfra = static_cast<int>(t);
- m_scene->r.subframe = static_cast<float>(t) - m_scene->r.cfra;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
+ m_settings.scene->r.cfra = static_cast<int>(t);
+ m_settings.scene->r.subframe = static_cast<float>(t) - m_settings.scene->r.cfra;
+ BKE_scene_graph_update_for_newframe(m_settings.depsgraph, bmain);
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index ae30b4589ee..74af85bfef9 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -34,15 +34,19 @@ class AbcObjectWriter;
class AbcTransformWriter;
class ArchiveWriter;
-struct EvaluationContext;
+struct Depsgraph;
struct Main;
struct Object;
struct Scene;
+struct ViewLayer;
+struct Base;
struct ExportSettings {
ExportSettings();
Scene *scene;
+ ViewLayer *view_layer; // Scene layer to export; all its objects will be exported, unless selected_only=true
+ Depsgraph *depsgraph;
SimpleLogger logger;
bool selected_only;
@@ -88,8 +92,6 @@ class AbcExporter {
unsigned int m_trans_sampling_index, m_shape_sampling_index;
- Scene *m_scene;
-
ArchiveWriter *m_writer;
/* mapping from name to transform writer */
@@ -99,10 +101,10 @@ class AbcExporter {
std::vector<AbcObjectWriter *> m_shapes;
public:
- AbcExporter(Main *bmain, Scene *scene, const char *filename, ExportSettings &settings);
+ AbcExporter(Main *bmain, const char *filename, ExportSettings &settings);
~AbcExporter();
- void operator()(Main *bmain, float &progress, bool &was_canceled);
+ void operator()(float &progress, bool &was_canceled);
protected:
void getShutterSamples(unsigned int nr_of_samples,
@@ -113,11 +115,11 @@ protected:
private:
Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
- void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
+ void createTransformWritersHierarchy();
AbcTransformWriter *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 exploreTransform(Base *ob_base, Object *parent, Object *dupliObParent);
+ void exploreObject(Base *ob_base, Object *dupliObParent);
+ void createShapeWriters();
void createShapeWriter(Object *ob, Object *dupliObParent);
void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform);
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index ed70d36dbee..efe8ea6e79e 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -30,12 +30,15 @@
extern "C" {
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_particle.h"
}
@@ -49,13 +52,12 @@ using Alembic::AbcGeom::OV2fGeomParam;
/* ************************************************************************** */
-AbcHairWriter::AbcHairWriter(Scene *scene,
- Object *ob,
+AbcHairWriter::AbcHairWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
ParticleSystem *psys)
- : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
, m_uv_warning_shown(false)
{
m_psys = psys;
@@ -69,15 +71,8 @@ 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_render(m_scene, m_object, CD_MASK_MESH);
- DM_ensure_tessface(dm);
+ Mesh *mesh = mesh_get_eval_final(m_settings.depsgraph, m_settings.scene, m_object, CD_MASK_MESH);
+ BKE_mesh_tessface_ensure(mesh);
std::vector<Imath::V3f> verts;
std::vector<int32_t> hvertices;
@@ -87,15 +82,13 @@ void AbcHairWriter::do_write()
if (m_psys->pathcache) {
ParticleSettings *part = m_psys->part;
- write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
+ write_hair_sample(mesh, 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);
+ write_hair_child_sample(mesh, 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);
@@ -118,7 +111,7 @@ void AbcHairWriter::do_write()
m_schema.set(m_sample);
}
-void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
+void AbcHairWriter::write_hair_sample(Mesh *mesh,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
@@ -129,9 +122,9 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
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);
+ MTFace *mtface = mesh->mtface;
+ MFace *mface = mesh->mface;
+ MVert *mverts = mesh->mvert;
if ((!mtface || !mface) && !m_uv_warning_shown) {
std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n",
@@ -151,11 +144,13 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
/* underlying info for faces-only emission */
path = cache[p];
+ /* Write UV and normal vectors */
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));
+ if (num < mesh->totface) {
+ /* TODO(Sybren): check whether the NULL check here and if(mface) are actually required */
+ MFace *face = mface == NULL ? NULL : &mface[num];
MTFace *tface = mtface + num;
if (mface) {
@@ -164,14 +159,14 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
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);
+ psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL);
copy_yup_from_zup(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));
+ std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, mesh->totface);
}
}
else if (part->from == PART_FROM_VERT && mtface) {
@@ -179,8 +174,8 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
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));
+ for (int n = 0; n < mesh->totface; ++n) {
+ MFace *face = &mface[n];
MTFace *tface = mtface + n;
unsigned int vtx[4];
vtx[0] = face->v1;
@@ -216,7 +211,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
int steps = path->segments + 1;
hvertices.push_back(steps);
- for (k = 0; k < steps; ++k) {
+ for (k = 0; k < steps; ++k, ++path) {
float vert[3];
copy_v3_v3(vert, path->co);
mul_m4_v3(inv_mat, vert);
@@ -224,12 +219,11 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
/* 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,
+void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
@@ -240,8 +234,8 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
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));
- MVert *mverts = dm->getVertArray(dm);
+ MTFace *mtface = mesh->mtface;
+ MVert *mverts = mesh->mvert;
ParticleCacheKey **cache = m_psys->childcache;
ParticleCacheKey *path;
@@ -264,7 +258,7 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
continue;
}
- MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
+ MFace *face = &mesh->mface[num];
MTFace *tface = mtface + num;
float r_uv[2], tmpnor[3], mapfw[4], vec[3];
@@ -272,7 +266,7 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
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);
+ psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL);
/* Convert Z-up to Y-up. */
norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_hair.h
index 61f5fe361f8..e2dffd4edaf 100644
--- a/source/blender/alembic/intern/abc_hair.h
+++ b/source/blender/alembic/intern/abc_hair.h
@@ -25,7 +25,6 @@
#include "abc_object.h"
-struct DerivedMesh;
struct ParticleSettings;
struct ParticleSystem;
@@ -40,8 +39,7 @@ class AbcHairWriter : public AbcObjectWriter {
bool m_uv_warning_shown;
public:
- AbcHairWriter(Scene *scene,
- Object *ob,
+ AbcHairWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
@@ -50,14 +48,14 @@ public:
private:
virtual void do_write();
- void write_hair_sample(DerivedMesh *dm,
+ void write_hair_sample(struct Mesh *mesh,
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,
+ void write_hair_child_sample(struct Mesh *mesh,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
diff --git a/source/blender/alembic/intern/abc_mball.cc b/source/blender/alembic/intern/abc_mball.cc
index 05700e6024e..c7b2d0c88a5 100644
--- a/source/blender/alembic/intern/abc_mball.cc
+++ b/source/blender/alembic/intern/abc_mball.cc
@@ -30,9 +30,8 @@ extern "C" {
#include "DNA_object_types.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
-#include "BKE_main.h"
+#include "BKE_library.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
@@ -43,23 +42,21 @@ extern "C" {
AbcMBallWriter::AbcMBallWriter(
Main *bmain,
- Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
, m_bmain(bmain)
{
m_is_animated = isAnimated();
m_mesh_ob = BKE_object_copy(bmain, ob);
- m_mesh_ob->curve_cache = (CurveCache *)MEM_callocN(
+ m_mesh_ob->runtime.curve_cache = (CurveCache *)MEM_callocN(
sizeof(CurveCache),
"CurveCache for AbcMBallWriter");
- m_mesh_writer = new AbcMeshWriter(scene, m_mesh_ob, parent,
- time_sampling, settings);
+ m_mesh_writer = new AbcMeshWriter(m_mesh_ob, parent, time_sampling, settings);
m_mesh_writer->setIsAnimated(m_is_animated);
}
@@ -97,13 +94,11 @@ void AbcMBallWriter::do_write()
id_us_min(&tmpmesh->id);
ListBase disp = {NULL, NULL};
- /* TODO(sergey): This is gonna to work for until EvaluationContext
+ /* TODO(sergey): This is gonna to work for until Depsgraph
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
- EvaluationContext eval_ctx;
- DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
- BKE_displist_make_mball_forRender(m_bmain, &eval_ctx, m_scene, m_object, &disp);
+ BKE_displist_make_mball_forRender(m_settings.depsgraph, m_settings.scene, m_object, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
@@ -115,8 +110,8 @@ void AbcMBallWriter::do_write()
m_mesh_ob->data = NULL;
}
-bool AbcMBallWriter::isBasisBall(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
+bool AbcMBallWriter::isBasisBall(Scene *scene, Object *ob)
{
- Object *basis_ob = BKE_mball_basis_find(bmain, eval_ctx, scene, ob);
+ Object *basis_ob = BKE_mball_basis_find(scene, ob);
return ob == basis_ob;
}
diff --git a/source/blender/alembic/intern/abc_mball.h b/source/blender/alembic/intern/abc_mball.h
index 46567ff3386..07cb1908e95 100644
--- a/source/blender/alembic/intern/abc_mball.h
+++ b/source/blender/alembic/intern/abc_mball.h
@@ -43,7 +43,6 @@ class AbcMBallWriter : public AbcObjectWriter {
public:
AbcMBallWriter(
Main *bmain,
- Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
@@ -51,7 +50,7 @@ public:
~AbcMBallWriter();
- static bool isBasisBall(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob);
+ static bool isBasisBall(Scene *scene, Object *ob);
private:
virtual void do_write();
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index a2903f7c3d1..50698ef728e 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -30,6 +30,7 @@
extern "C" {
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_fluidsim_types.h"
#include "DNA_object_types.h"
@@ -37,11 +38,11 @@ extern "C" {
#include "BLI_math_geom.h"
#include "BLI_string.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_depsgraph.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -52,6 +53,8 @@ extern "C" {
#include "bmesh.h"
#include "bmesh_tools.h"
+
+#include "DEG_depsgraph_query.h"
}
using Alembic::Abc::FloatArraySample;
@@ -104,27 +107,27 @@ 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)
+static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points)
{
points.clear();
- points.resize(dm->getNumVerts(dm));
+ points.resize(mesh->totvert);
- MVert *verts = dm->getVertArray(dm);
+ MVert *verts = mesh->mvert;
- for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totvert; i < e; ++i) {
copy_yup_from_zup(points[i].getValue(), verts[i].co);
}
}
-static void get_topology(DerivedMesh *dm,
+static void get_topology(struct Mesh *mesh,
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);
+ const int num_poly = mesh->totpoly;
+ const int num_loops = mesh->totloop;
+ MLoop *mloop = mesh->mloop;
+ MPoly *mpoly = mesh->mpoly;
poly_verts.clear();
loop_counts.clear();
@@ -146,7 +149,7 @@ static void get_topology(DerivedMesh *dm,
}
}
-static void get_creases(DerivedMesh *dm,
+static void get_creases(struct Mesh *mesh,
std::vector<int32_t> &indices,
std::vector<int32_t> &lengths,
std::vector<float> &sharpnesses)
@@ -157,9 +160,9 @@ static void get_creases(DerivedMesh *dm,
lengths.clear();
sharpnesses.clear();
- MEdge *edge = dm->getEdgeArray(dm);
+ MEdge *edge = mesh->medge;
- for (int i = 0, e = dm->getNumEdges(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totedge; i < e; ++i) {
const float sharpness = static_cast<float>(edge[i].crease) * factor;
if (sharpness != 0.0f) {
@@ -172,41 +175,40 @@ static void get_creases(DerivedMesh *dm,
lengths.resize(sharpnesses.size(), 2);
}
-static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
+static void get_vertex_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals)
{
normals.clear();
- normals.resize(dm->getNumVerts(dm));
+ normals.resize(mesh->totvert);
- MVert *verts = dm->getVertArray(dm);
+ MVert *verts = mesh->mvert;
float no[3];
- for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totvert; i < e; ++i) {
normal_short_to_float_v3(no, verts[i].no);
copy_yup_from_zup(normals[i].getValue(), no);
}
}
-static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
+static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals)
{
- MPoly *mpoly = dm->getPolyArray(dm);
- MPoly *mp = mpoly;
+ MPoly *mp = mesh->mpoly;
- MLoop *mloop = dm->getLoopArray(dm);
+ MLoop *mloop = mesh->mloop;
MLoop *ml = mloop;
- MVert *verts = dm->getVertArray(dm);
+ MVert *verts = mesh->mvert;
- const float (*lnors)[3] = static_cast<float(*)[3]>(dm->getLoopDataArray(dm, CD_NORMAL));
+ const float (*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL));
normals.clear();
- normals.resize(dm->getNumLoops(dm));
+ normals.resize(mesh->totloop);
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) {
+ for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) {
ml = mloop + mp->loopstart + (mp->totloop - 1);
for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
@@ -218,7 +220,7 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
else {
float no[3];
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
+ for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) {
ml = mloop + mp->loopstart + (mp->totloop - 1);
/* Flat shaded, use common normal for all verts. */
@@ -287,12 +289,11 @@ static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob)
/* ************************************************************************** */
-AbcMeshWriter::AbcMeshWriter(Scene *scene,
- Object *ob,
+AbcMeshWriter::AbcMeshWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
m_is_animated = isAnimated();
m_subsurf_mod = NULL;
@@ -304,11 +305,11 @@ AbcMeshWriter::AbcMeshWriter(Scene *scene,
}
if (!m_settings.apply_subdiv) {
- m_subsurf_mod = get_subsurf_modifier(m_scene, m_object);
+ m_subsurf_mod = get_subsurf_modifier(m_settings.scene, m_object);
m_is_subd = (m_subsurf_mod != NULL);
}
- m_is_liquid = (get_liquid_sim_modifier(m_scene, m_object) != NULL);
+ m_is_liquid = (get_liquid_sim_modifier(m_settings.scene, m_object) != NULL);
while (parent->alembicXform().getChildHeader(m_name)) {
m_name.append("_");
@@ -369,36 +370,37 @@ void AbcMeshWriter::do_write()
if (!m_first_frame && !m_is_animated)
return;
- DerivedMesh *dm = getFinalMesh();
+ bool needsfree;
+ struct Mesh *mesh = getFinalMesh(needsfree);
try {
if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) {
- writeSubD(dm);
+ writeSubD(mesh);
}
else {
- writeMesh(dm);
+ writeMesh(mesh);
}
- freeMesh(dm);
+ if (needsfree) BKE_id_free(NULL, mesh);
}
catch (...) {
- freeMesh(dm);
+ if (needsfree) BKE_id_free(NULL, mesh);
throw;
}
}
-void AbcMeshWriter::writeMesh(DerivedMesh *dm)
+void AbcMeshWriter::writeMesh(struct Mesh *mesh)
{
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);
+ get_vertices(mesh, points);
+ get_topology(mesh, poly_verts, loop_counts, smooth_normal);
if (m_first_frame && m_settings.export_face_sets) {
- writeFaceSets(dm, m_mesh_schema);
+ writeFaceSets(mesh, m_mesh_schema);
}
m_mesh_sample = OPolyMeshSchema::Sample(V3fArraySample(points),
@@ -407,7 +409,7 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
UVSample sample;
if (m_first_frame && m_settings.export_uvs) {
- const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
+ const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata);
if (!sample.indices.empty() && !sample.uvs.empty()) {
OV2fGeomParam::Sample uv_sample;
@@ -419,15 +421,15 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
m_mesh_sample.setUVs(uv_sample);
}
- write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
+ write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV);
}
if (m_settings.export_normals) {
if (smooth_normal) {
- get_loop_normals(dm, normals);
+ get_loop_normals(mesh, normals);
}
else {
- get_vertex_normals(dm, normals);
+ get_vertex_normals(mesh, normals);
}
ON3fGeomParam::Sample normals_sample;
@@ -441,7 +443,7 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
if (m_is_liquid) {
std::vector<Imath::V3f> velocities;
- getVelocities(dm, velocities);
+ getVelocities(mesh, velocities);
m_mesh_sample.setVelocities(V3fArraySample(velocities));
}
@@ -450,10 +452,10 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
m_mesh_schema.set(m_mesh_sample);
- writeArbGeoParams(dm);
+ writeArbGeoParams(mesh);
}
-void AbcMeshWriter::writeSubD(DerivedMesh *dm)
+void AbcMeshWriter::writeSubD(struct Mesh *mesh)
{
std::vector<float> crease_sharpness;
std::vector<Imath::V3f> points;
@@ -462,12 +464,12 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
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);
+ get_vertices(mesh, points);
+ get_topology(mesh, poly_verts, loop_counts, smooth_normal);
+ get_creases(mesh, crease_indices, crease_lengths, crease_sharpness);
if (m_first_frame && m_settings.export_face_sets) {
- writeFaceSets(dm, m_subdiv_schema);
+ writeFaceSets(mesh, m_subdiv_schema);
}
m_subdiv_sample = OSubDSchema::Sample(V3fArraySample(points),
@@ -476,7 +478,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
UVSample sample;
if (m_first_frame && m_settings.export_uvs) {
- const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
+ const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata);
if (!sample.indices.empty() && !sample.uvs.empty()) {
OV2fGeomParam::Sample uv_sample;
@@ -488,7 +490,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
m_subdiv_sample.setUVs(uv_sample);
}
- write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
+ write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV);
}
if (!crease_indices.empty()) {
@@ -500,14 +502,14 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
m_subdiv_sample.setSelfBounds(bounds());
m_subdiv_schema.set(m_subdiv_sample);
- writeArbGeoParams(dm);
+ writeArbGeoParams(mesh);
}
template <typename Schema>
-void AbcMeshWriter::writeFaceSets(DerivedMesh *dm, Schema &schema)
+void AbcMeshWriter::writeFaceSets(struct Mesh *me, Schema &schema)
{
std::map< std::string, std::vector<int32_t> > geo_groups;
- getGeoGroups(dm, geo_groups);
+ getGeoGroups(me, geo_groups);
std::map< std::string, std::vector<int32_t> >::iterator it;
for (it = geo_groups.begin(); it != geo_groups.end(); ++it) {
@@ -518,14 +520,17 @@ void AbcMeshWriter::writeFaceSets(DerivedMesh *dm, Schema &schema)
}
}
-DerivedMesh *AbcMeshWriter::getFinalMesh()
+Mesh *AbcMeshWriter::getFinalMesh(bool &r_needsfree)
{
/* 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);
+ Scene *scene = DEG_get_evaluated_scene(m_settings.depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object);
+ struct Mesh *mesh = mesh_get_eval_final(m_settings.depsgraph, scene, ob_eval, CD_MASK_MESH);
+ r_needsfree = false;
if (m_subsurf_mod) {
m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
@@ -536,34 +541,30 @@ DerivedMesh *AbcMeshWriter::getFinalMesh()
const int quad_method = m_settings.quad_method;
const int ngon_method = m_settings.ngon_method;
- BMesh *bm = DM_to_bmesh(dm, true);
+ struct BMeshCreateParams bmcp = {false};
+ struct BMeshFromMeshParams bmfmp = {true, false, false, 0};
+ BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp);
BM_mesh_triangulate(bm, quad_method, ngon_method, tag_only, NULL, NULL, NULL);
- DerivedMesh *result = CDDM_from_bmesh(bm, false);
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
BM_mesh_free(bm);
- freeMesh(dm);
-
- dm = result;
+ mesh = result;
+ r_needsfree = true;
}
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);
+ m_custom_data_config.mpoly = mesh->mpoly;
+ m_custom_data_config.mloop = mesh->mloop;
+ m_custom_data_config.totpoly = mesh->totpoly;
+ m_custom_data_config.totloop = mesh->totloop;
+ m_custom_data_config.totvert = mesh->totvert;
- return dm;
-}
-
-void AbcMeshWriter::freeMesh(DerivedMesh *dm)
-{
- dm->release(dm);
+ return mesh;
}
-void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
+void AbcMeshWriter::writeArbGeoParams(struct Mesh *me)
{
if (m_is_liquid) {
/* We don't need anything more for liquid meshes. */
@@ -572,22 +573,22 @@ void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
if (m_first_frame && m_settings.export_vcols) {
if (m_subdiv_schema.valid()) {
- write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
+ write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL);
}
else {
- write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
+ write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL);
}
}
}
-void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels)
+void AbcMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels)
{
- const int totverts = dm->getNumVerts(dm);
+ const int totverts = mesh->totvert;
vels.clear();
vels.resize(totverts);
- ModifierData *md = get_liquid_sim_modifier(m_scene, m_object);
+ ModifierData *md = get_liquid_sim_modifier(m_settings.scene, m_object);
FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md);
FluidsimSettings *fss = fmd->fss;
@@ -605,11 +606,11 @@ void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels
}
void AbcMeshWriter::getGeoGroups(
- DerivedMesh *dm,
+ struct Mesh *mesh,
std::map<std::string, std::vector<int32_t> > &geo_groups)
{
- const int num_poly = dm->getNumPolys(dm);
- MPoly *polygons = dm->getPolyArray(dm);
+ const int num_poly = mesh->totpoly;
+ MPoly *polygons = mesh->mpoly;
for (int i = 0; i < num_poly; ++i) {
MPoly &current_poly = polygons[i];
@@ -638,7 +639,7 @@ void AbcMeshWriter::getGeoGroups(
std::vector<int32_t> faceArray;
- for (int i = 0, e = dm->getNumTessFaces(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totface; i < e; ++i) {
faceArray.push_back(i);
}
@@ -873,11 +874,11 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
}
}
-static bool check_smooth_poly_flag(DerivedMesh *dm)
+static bool check_smooth_poly_flag(Mesh *mesh)
{
- MPoly *mpolys = dm->getPolyArray(dm);
+ MPoly *mpolys = mesh->mpoly;
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totpoly; i < e; ++i) {
MPoly &poly = mpolys[i];
if ((poly.flag & ME_SMOOTH) != 0) {
@@ -888,11 +889,11 @@ static bool check_smooth_poly_flag(DerivedMesh *dm)
return false;
}
-static void set_smooth_poly_flag(DerivedMesh *dm)
+static void set_smooth_poly_flag(Mesh *mesh)
{
- MPoly *mpolys = dm->getPolyArray(dm);
+ MPoly *mpolys = mesh->mpoly;
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totpoly; i < e; ++i) {
MPoly &poly = mpolys[i];
poly.flag |= ME_SMOOTH;
}
@@ -900,7 +901,7 @@ static void set_smooth_poly_flag(DerivedMesh *dm)
static void *add_customdata_cb(void *user_data, const char *name, int data_type)
{
- DerivedMesh *dm = static_cast<DerivedMesh *>(user_data);
+ Mesh *mesh = static_cast<Mesh *>(user_data);
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
void *cd_ptr;
CustomData *loopdata;
@@ -911,7 +912,7 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type)
return NULL;
}
- loopdata = dm->getLoopDataLayout(dm);
+ loopdata = &mesh->ldata;
cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
if (cd_ptr != NULL) {
/* layer already exists, so just return it. */
@@ -920,15 +921,9 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type)
/* create a new layer, taking care to construct the hopefully-soon-to-be-removed
* CD_MTEXPOLY layer too, with the same name. */
- numloops = dm->getNumLoops(dm);
+ numloops = mesh->totloop;
cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT,
NULL, numloops, name);
- if (cd_data_type == CD_MLOOPUV) {
- CustomData_add_layer_named(dm->getPolyDataLayout(dm),
- CD_MTEXPOLY, CD_DEFAULT,
- NULL, numloops, name);
- }
-
return cd_ptr;
}
@@ -992,17 +987,19 @@ static void read_mesh_sample(const std::string & iobject_full_name,
}
}
-CDStreamConfig get_config(DerivedMesh *dm)
+CDStreamConfig get_config(Mesh *mesh)
{
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);
+ BLI_assert(mesh->mvert);
+
+ config.user_data = mesh;
+ config.mvert = mesh->mvert;
+ config.mloop = mesh->mloop;
+ config.mpoly = mesh->mpoly;
+ config.totloop = mesh->totloop;
+ config.totpoly = mesh->totpoly;
+ config.loopdata = &mesh->ldata;
config.add_customdata_cb = add_customdata_cb;
return config;
@@ -1033,14 +1030,8 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
- DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
-
- if (ndm != dm) {
- dm->release(dm);
- }
-
- DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
+ Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
@@ -1070,33 +1061,45 @@ bool AbcMeshReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHe
return true;
}
-DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm,
- const ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str)
+Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str)
{
- const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
+ IPolyMeshSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ *err_str = "Error reading mesh sample; more detail on the console";
+ printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
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;
+ Mesh *new_mesh = NULL;
/* Only read point data when streaming meshes, unless we need to create new ones. */
ImportSettings settings;
settings.read_flag |= read_flag;
- bool topology_changed = positions->size() != dm->getNumVerts(dm) ||
- face_counts->size() != dm->getNumPolys(dm) ||
- face_indices->size() != dm->getNumLoops(dm);
+ bool topology_changed = positions->size() != existing_mesh->totvert ||
+ face_counts->size() != existing_mesh->totpoly ||
+ face_indices->size() != existing_mesh->totloop;
if (topology_changed) {
- new_dm = CDDM_from_template(dm,
- positions->size(),
- 0,
- 0,
- face_indices->size(),
- face_counts->size());
+ new_mesh = BKE_mesh_new_nomain_from_template(existing_mesh,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
}
@@ -1104,8 +1107,8 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm,
/* If the face count changed (e.g. by triangulation), only read points.
* This prevents crash from T49813.
* TODO(kevin): perhaps find a better way to do this? */
- if (face_counts->size() != dm->getNumPolys(dm) ||
- face_indices->size() != dm->getNumLoops(dm))
+ if (face_counts->size() != existing_mesh->totpoly ||
+ face_indices->size() != existing_mesh->totloop)
{
settings.read_flag = MOD_MESHSEQ_READ_VERT;
@@ -1116,40 +1119,39 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm,
}
}
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
config.time = sample_sel.getRequestedTime();
bool do_normals = false;
read_mesh_sample(m_iobject.getFullName(),
&settings, m_schema, sample_sel, config, do_normals);
- if (new_dm) {
+ if (new_mesh) {
/* Check if we had ME_SMOOTH flag set to restore it. */
- if (!do_normals && check_smooth_poly_flag(dm)) {
- set_smooth_poly_flag(new_dm);
+ if (!do_normals && check_smooth_poly_flag(existing_mesh)) {
+ set_smooth_poly_flag(new_mesh);
}
- CDDM_calc_normals(new_dm);
- CDDM_calc_edges(new_dm);
+ BKE_mesh_calc_normals(new_mesh);
+ BKE_mesh_calc_edges(new_mesh, false, false);
/* Here we assume that the number of materials doesn't change, i.e. that
* the material slots that were created when the object was loaded from
* Alembic are still valid now. */
- size_t num_polys = new_dm->getNumPolys(new_dm);
+ size_t num_polys = new_mesh->totpoly;
if (num_polys > 0) {
- MPoly *dmpolies = new_dm->getPolyArray(new_dm);
std::map<std::string, int> mat_map;
- assign_facesets_to_mpoly(sample_sel, 0, dmpolies, num_polys, mat_map);
+ assign_facesets_to_mpoly(sample_sel, 0, new_mesh->mpoly, num_polys, mat_map);
}
- return new_dm;
+ return new_mesh;
}
if (do_normals) {
- CDDM_calc_normals(dm);
+ BKE_mesh_calc_normals(existing_mesh);
}
- return dm;
+ return existing_mesh;
}
void AbcMeshReader::assign_facesets_to_mpoly(
@@ -1311,16 +1313,22 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
- DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+ Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true);
- if (ndm != dm) {
- dm->release(dm);
+ ISubDSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return;
}
- DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
-
- const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
Int32ArraySamplePtr indices = sample.getCreaseIndices();
Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
@@ -1350,29 +1358,41 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
}
}
-DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm,
- const ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str)
+Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str)
{
- const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
+ ISubDSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ *err_str = "Error reading mesh sample; more detail on the console";
+ printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
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;
+ Mesh *new_mesh = 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());
+ if (existing_mesh->totvert != positions->size()) {
+ new_mesh = BKE_mesh_new_nomain_from_template(existing_mesh,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
}
@@ -1380,8 +1400,8 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm,
/* If the face count changed (e.g. by triangulation), only read points.
* This prevents crash from T49813.
* TODO(kevin): perhaps find a better way to do this? */
- if (face_counts->size() != dm->getNumPolys(dm) ||
- face_indices->size() != dm->getNumLoops(dm))
+ if (face_counts->size() != existing_mesh->totpoly ||
+ face_indices->size() != existing_mesh->totpoly)
{
settings.read_flag = MOD_MESHSEQ_READ_VERT;
@@ -1393,22 +1413,22 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm,
}
/* Only read point data when streaming meshes, unless we need to create new ones. */
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
config.time = sample_sel.getRequestedTime();
read_subd_sample(m_iobject.getFullName(),
&settings, m_schema, sample_sel, config);
- if (new_dm) {
+ if (new_mesh) {
/* Check if we had ME_SMOOTH flag set to restore it. */
- if (check_smooth_poly_flag(dm)) {
- set_smooth_poly_flag(new_dm);
+ if (check_smooth_poly_flag(existing_mesh)) {
+ set_smooth_poly_flag(new_mesh);
}
- CDDM_calc_normals(new_dm);
- CDDM_calc_edges(new_dm);
+ BKE_mesh_calc_normals(new_mesh);
+ BKE_mesh_calc_edges(new_mesh, false, false);
- return new_dm;
+ return new_mesh;
}
- return dm;
+ return existing_mesh;
}
diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h
index 70d92f894d2..fd6de1001ae 100644
--- a/source/blender/alembic/intern/abc_mesh.h
+++ b/source/blender/alembic/intern/abc_mesh.h
@@ -26,7 +26,6 @@
#include "abc_customdata.h"
#include "abc_object.h"
-struct DerivedMesh;
struct Mesh;
struct ModifierData;
@@ -50,8 +49,7 @@ class AbcMeshWriter : public AbcObjectWriter {
bool m_is_subd;
public:
- AbcMeshWriter(Scene *scene,
- Object *ob,
+ AbcMeshWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
@@ -64,29 +62,28 @@ private:
bool isAnimated() const;
- void writeMesh(DerivedMesh *dm);
- void writeSubD(DerivedMesh *dm);
+ void writeMesh(struct Mesh *mesh);
+ void writeSubD(struct Mesh *mesh);
- void getMeshInfo(DerivedMesh *dm, std::vector<float> &points,
+ void getMeshInfo(struct Mesh *mesh, 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);
+ struct Mesh *getFinalMesh(bool &r_needsfree);
- void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices);
+ void getMaterialIndices(struct Mesh *mesh, std::vector<int32_t> &indices);
- void writeArbGeoParams(DerivedMesh *dm);
- void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups);
+ void writeArbGeoParams(struct Mesh *mesh);
+ void getGeoGroups(struct Mesh *mesh, std::map<std::string, std::vector<int32_t> > &geoGroups);
/* fluid surfaces support */
- void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
+ void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels);
template <typename Schema>
- void writeFaceSets(DerivedMesh *dm, Schema &schema);
+ void writeFaceSets(struct Mesh *mesh, Schema &schema);
};
/* ************************************************************************** */
@@ -105,10 +102,10 @@ public:
const char **err_str) const;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
private:
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
@@ -135,10 +132,10 @@ public:
const Object *const ob,
const char **err_str) const;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
};
/* ************************************************************************** */
@@ -147,6 +144,6 @@ void read_mverts(MVert *mverts,
const Alembic::AbcGeom::P3fArraySamplePtr &positions,
const Alembic::AbcGeom::N3fArraySamplePtr &normals);
-CDStreamConfig get_config(DerivedMesh *dm);
+CDStreamConfig get_config(struct Mesh *mesh);
#endif /* __ABC_MESH_H__ */
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
index 6273507486a..fcb2f5c5ec5 100644
--- a/source/blender/alembic/intern/abc_nurbs.cc
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -60,12 +60,11 @@ using Alembic::AbcGeom::ONuPatchSchema;
/* ************************************************************************** */
-AbcNurbsWriter::AbcNurbsWriter(Scene *scene,
- Object *ob,
+AbcNurbsWriter::AbcNurbsWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
m_is_animated = isAnimated();
@@ -131,8 +130,8 @@ void AbcNurbsWriter::do_write()
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;
+ if (m_object->runtime.curve_cache->deformed_nurbs.first != NULL) {
+ nulb = &m_object->runtime.curve_cache->deformed_nurbs;
}
else {
nulb = BKE_curve_nurbs_get(curve);
@@ -254,7 +253,19 @@ void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele
nu->resolv = cu->resolv;
const INuPatchSchema &schema = it->first;
- const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
+ INuPatchSchema::Sample smp;
+ try {
+ smp = schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ printf("Alembic: error reading nurbs sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return;
+ }
+
nu->orderu = smp.getUOrder() - 1;
nu->orderv = smp.getVOrder() - 1;
diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_nurbs.h
index abe460a8988..827aa4b365f 100644
--- a/source/blender/alembic/intern/abc_nurbs.h
+++ b/source/blender/alembic/intern/abc_nurbs.h
@@ -32,8 +32,7 @@ class AbcNurbsWriter : public AbcObjectWriter {
bool m_is_animated;
public:
- AbcNurbsWriter(Scene *scene,
- Object *ob,
+ AbcNurbsWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index ddedcf6dcbc..7e0b1ccfbd4 100644
--- a/source/blender/alembic/intern/abc_object.cc
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -32,7 +32,6 @@ extern "C" {
#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"
@@ -59,14 +58,12 @@ using Alembic::AbcGeom::OStringProperty;
/* ************************************************************************** */
-AbcObjectWriter::AbcObjectWriter(Scene *scene,
- Object *ob,
+AbcObjectWriter::AbcObjectWriter(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)
{
@@ -247,12 +244,12 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time)
return s0.getMatrix();
}
-DerivedMesh *AbcObjectReader::read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
- int UNUSED(read_flag),
- const char **UNUSED(err_str))
+struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
+ int UNUSED(read_flag),
+ const char **UNUSED(err_str))
{
- return dm;
+ return existing_mesh;
}
void AbcObjectReader::setupObjectTransform(const float time)
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
index 852ef451f23..8794cb61708 100644
--- a/source/blender/alembic/intern/abc_object.h
+++ b/source/blender/alembic/intern/abc_object.h
@@ -44,7 +44,6 @@ protected:
Object *m_object;
ExportSettings &m_settings;
- Scene *m_scene;
uint32_t m_time_sampling;
Imath::Box3d m_bounds;
@@ -56,8 +55,7 @@ protected:
std::string m_name;
public:
- AbcObjectWriter(Scene *scene,
- Object *ob,
+ AbcObjectWriter(Object *ob,
uint32_t time_sampling,
ExportSettings &settings,
AbcObjectWriter *parent = NULL);
@@ -122,7 +120,7 @@ static bool has_animations(Schema &schema, ImportSettings *settings)
/* ************************************************************************** */
-struct DerivedMesh;
+struct Mesh;
using Alembic::AbcCoreAbstract::chrono_t;
@@ -178,10 +176,10 @@ public:
virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0;
- virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ virtual struct Mesh *read_mesh(struct Mesh *mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
/** Reads the object matrix and sets up an object transform if animated. */
void setupObjectTransform(const float time);
diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc
index 738adb4cd3a..c748139a0e6 100644
--- a/source/blender/alembic/intern/abc_points.cc
+++ b/source/blender/alembic/intern/abc_points.cc
@@ -40,6 +40,8 @@ extern "C" {
#include "BKE_scene.h"
#include "BLI_math.h"
+
+#include "DEG_depsgraph_query.h"
}
using Alembic::AbcGeom::kVertexScope;
@@ -58,13 +60,12 @@ using Alembic::AbcGeom::OPointsSchema;
/* ************************************************************************** */
-AbcPointsWriter::AbcPointsWriter(Scene *scene,
- Object *ob,
+AbcPointsWriter::AbcPointsWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
ParticleSystem *psys)
- : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
m_psys = psys;
@@ -86,7 +87,8 @@ void AbcPointsWriter::do_write()
ParticleKey state;
ParticleSimulationData sim;
- sim.scene = m_scene;
+ sim.depsgraph = m_settings.depsgraph;
+ sim.scene = m_settings.scene;
sim.ob = m_object;
sim.psys = m_psys;
@@ -100,7 +102,7 @@ void AbcPointsWriter::do_write()
continue;
}
- state.time = BKE_scene_frame_get(m_scene);
+ state.time = DEG_get_ctime(m_settings.depsgraph);
if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
continue;
@@ -171,15 +173,9 @@ bool AbcPointsReader::accepts_object_type(const Alembic::AbcCoreAbstract::Object
void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+ Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, NULL);
- DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, 0, NULL);
-
- if (ndm != dm) {
- dm->release(dm);
- }
-
- DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
@@ -216,23 +212,35 @@ void read_points_sample(const IPointsSchema &schema,
read_mverts(config.mvert, positions, vnormals);
}
-DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm,
- const ISampleSelector &sample_sel,
- int /*read_flag*/,
- const char ** /*err_str*/)
+struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int /*read_flag*/,
+ const char **err_str)
{
- const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);
+ IPointsSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ *err_str = "Error reading points sample; more detail on the console";
+ printf("Alembic: error reading points sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
const P3fArraySamplePtr &positions = sample.getPositions();
- DerivedMesh *new_dm = NULL;
+ Mesh *new_mesh = NULL;
- if (dm->getNumVerts(dm) != positions->size()) {
- new_dm = CDDM_new(positions->size(), 0, 0, 0, 0);
+ if (existing_mesh->totvert != positions->size()) {
+ new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0, 0);
}
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
read_points_sample(m_schema, sample_sel, config);
- return new_dm ? new_dm : dm;
+ return new_mesh ? new_mesh : existing_mesh;
}
diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h
index 369a802d763..e986f9448f4 100644
--- a/source/blender/alembic/intern/abc_points.h
+++ b/source/blender/alembic/intern/abc_points.h
@@ -38,8 +38,7 @@ class AbcPointsWriter : public AbcObjectWriter {
ParticleSystem *m_psys;
public:
- AbcPointsWriter(Scene *scene,
- Object *ob,
+ AbcPointsWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
@@ -64,10 +63,10 @@ public:
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
};
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
index 5392387663f..81ebfef3e11 100644
--- a/source/blender/alembic/intern/abc_transform.cc
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -32,6 +32,8 @@ extern "C" {
#include "BLI_math.h"
#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
}
using Alembic::AbcGeom::OObject;
@@ -62,7 +64,7 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
AbcTransformWriter *parent,
unsigned int time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
, m_proxy_from(NULL)
{
m_is_animated = hasAnimation(m_object);
@@ -80,29 +82,31 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
void AbcTransformWriter::do_write()
{
+ Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object);
+
if (m_first_frame) {
m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling());
}
- m_visibility.set(!(m_object->restrictflag & OB_RESTRICT_VIEW));
+ m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEW));
if (!m_first_frame && !m_is_animated) {
return;
}
float yup_mat[4][4];
- create_transform_matrix(m_object, yup_mat,
+ create_transform_matrix(ob_eval, yup_mat,
m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD,
m_proxy_from);
/* Only apply rotation to root camera, parenting will propagate it. */
- if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) {
+ if (ob_eval->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(ob_eval))) {
float rot_mat[4][4];
axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2);
mul_m4_m4m4(yup_mat, yup_mat, rot_mat);
}
- if (!m_object->parent || !m_inherits_xform) {
+ if (!ob_eval->parent || !m_inherits_xform) {
/* Only apply scaling to root objects, parenting will propagate it. */
float scale_mat[4][4];
scale_m4_fl(scale_mat, m_settings.global_scale);
diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h
index 753a4247e9f..12bf9d38007 100644
--- a/source/blender/alembic/intern/abc_transform.h
+++ b/source/blender/alembic/intern/abc_transform.h
@@ -37,7 +37,6 @@ class AbcTransformWriter : public AbcObjectWriter {
Alembic::Abc::M44d m_matrix;
bool m_is_animated;
- bool m_visible;
bool m_inherits_xform;
public:
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
index 24a508e8292..53860ab149d 100644
--- a/source/blender/alembic/intern/abc_util.cc
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -35,6 +35,7 @@
extern "C" {
#include "DNA_object_types.h"
+#include "DNA_layer_types.h"
#include "BLI_math.h"
@@ -60,6 +61,15 @@ std::string get_id_name(const ID * const id)
return name;
}
+/**
+ * @brief get_object_dag_path_name returns the name under which the object
+ * will be exported in the Alembic file. It is of the form
+ * "[../grandparent/]parent/object" if dupli_parent is NULL, or
+ * "dupli_parent/[../grandparent/]parent/object" otherwise.
+ * @param ob
+ * @param dupli_parent
+ * @return
+ */
std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent)
{
std::string name = get_id_name(ob);
@@ -78,31 +88,9 @@ std::string get_object_dag_path_name(const Object * const ob, Object *dupli_pare
return name;
}
-bool object_selected(Object *ob)
-{
- return ob->flag & SELECT;
-}
-
-bool parent_selected(Object *ob)
+bool object_selected(const Base * const ob_base)
{
- 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;
+ return ob_base->flag & SELECT;
}
Imath::M44d convert_matrix(float mat[4][4])
@@ -152,7 +140,10 @@ void create_swapped_rotation_matrix(
rz = -euler[1];
break;
default:
+ ry = 0.0f;
+ rz = 0.0f;
BLI_assert(false);
+ break;
}
unit_m3(rot_x_mat);
@@ -190,11 +181,11 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod
unit_m3(dst_rot);
unit_m4(dst_scale_mat);
- /* We assume there is no sheer component and no homogeneous scaling component. */
- BLI_assert(fabs(src_mat[0][3]) < 2 * FLT_EPSILON);
- BLI_assert(fabs(src_mat[1][3]) < 2 * FLT_EPSILON);
- BLI_assert(fabs(src_mat[2][3]) < 2 * FLT_EPSILON);
- BLI_assert(fabs(src_mat[3][3] - 1.0f) < 2 * FLT_EPSILON);
+ /* TODO(Sybren): This code assumes there is no sheer component and no
+ * homogeneous scaling component, which is not always true when writing
+ * non-hierarchical (e.g. flat) objects (e.g. when parent has non-uniform
+ * scale and the child rotates). This is currently not taken into account
+ * when axis-swapping. */
/* Extract translation, rotation, and scale form matrix. */
mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat);
diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h
index 06eb3f140ca..fae73ec9d11 100644
--- a/source/blender/alembic/intern/abc_util.h
+++ b/source/blender/alembic/intern/abc_util.h
@@ -48,13 +48,13 @@ struct ImportSettings;
struct ID;
struct Object;
+struct Base;
std::string get_id_name(const ID * const id);
std::string get_id_name(const Object * const ob);
std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent);
-bool object_selected(Object *ob);
-bool parent_selected(Object *ob);
+bool object_selected(const Base * const ob_base);
Imath::M44d convert_matrix(float mat[4][4]);
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index b7c1f98bfb0..e1d4eb3490b 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -48,12 +48,14 @@ extern "C" {
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
-#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.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
@@ -227,7 +229,7 @@ static void find_iobject(const IObject &object, IObject &ret,
}
struct ExportJobData {
- Scene *scene;
+ ViewLayer *view_layer;
Main *bmain;
char filename[1024];
@@ -257,20 +259,25 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
G.is_break = false;
+ DEG_graph_build_from_view_layer(data->settings.depsgraph,
+ data->bmain,
+ data->settings.scene,
+ data->view_layer);
+ BKE_scene_graph_update_tagged(data->settings.depsgraph, data->bmain);
+
try {
- Scene *scene = data->scene;
- AbcExporter exporter(data->bmain, scene, data->filename, data->settings);
+ AbcExporter exporter(data->bmain, data->filename, data->settings);
+ Scene *scene = data->settings.scene; /* for the CFRA macro */
const int orig_frame = CFRA;
data->was_canceled = false;
- exporter(data->bmain, *data->progress, data->was_canceled);
+ exporter(*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);
+ BKE_scene_graph_update_for_newframe(data->settings.depsgraph, data->bmain);
}
data->export_ok = !data->was_canceled;
@@ -308,7 +315,8 @@ bool ABC_export(
bool as_background_job)
{
ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData"));
- job->scene = scene;
+
+ job->view_layer = CTX_data_view_layer(C);
job->bmain = CTX_data_main(C);
job->export_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
@@ -329,14 +337,26 @@ bool ABC_export(
* do bigger refactor and maybe there is a better way which does not involve
* hardcore refactoring. */
new (&job->settings) ExportSettings();
- job->settings.scene = job->scene;
+ job->settings.scene = scene;
+ job->settings.depsgraph = DEG_graph_new(scene, job->view_layer, DAG_EVAL_RENDER);
+
+ /* Sybren: for now we only export the active scene layer.
+ * Later in the 2.8 development process this may be replaced by using
+ * a specific collection for Alembic I/O, which can then be toggled
+ * between "real" objects and cached Alembic files. */
+ job->settings.view_layer = job->view_layer;
+
job->settings.frame_start = params->frame_start;
job->settings.frame_end = params->frame_end;
job->settings.frame_samples_xform = params->frame_samples_xform;
job->settings.frame_samples_shape = params->frame_samples_shape;
job->settings.shutter_open = params->shutter_open;
job->settings.shutter_close = params->shutter_close;
+
+ /* Sybren: For now this is ignored, until we can get selection
+ * detection working through Base pointers (instead of ob->flags). */
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;
@@ -345,8 +365,13 @@ bool ABC_export(
job->settings.export_particles = params->export_particles;
job->settings.apply_subdiv = params->apply_subdiv;
job->settings.flatten_hierarchy = params->flatten_hierarchy;
+
+ /* Sybren: visible_layer & renderable only is ignored for now,
+ * to be replaced with collections later in the 2.8 dev process
+ * (also see note above). */
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;
@@ -363,7 +388,7 @@ bool ABC_export(
if (as_background_job) {
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
- job->scene,
+ job->settings.scene,
"Alembic Export",
WM_JOB_PROGRESS,
WM_JOB_TYPE_ALEMBIC);
@@ -606,6 +631,7 @@ enum {
struct ImportJobData {
Main *bmain;
Scene *scene;
+ ViewLayer *view_layer;
char filename[1024];
ImportSettings settings;
@@ -621,37 +647,6 @@ struct ImportJobData {
bool import_ok;
};
-ABC_INLINE bool is_mesh_and_strands(const IObject &object)
-{
- 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;
- }
- else if (IPoints::matches(md)) {
- has_curve = true;
- }
- }
-
- return has_mesh && has_curve;
-}
-
static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
{
SCOPE_TIMER("Alembic import, objects reading and creation");
@@ -807,20 +802,29 @@ static void import_endjob(void *user_data)
else {
/* Add object to scene. */
Base *base;
+ LayerCollection *lc;
+ ViewLayer *view_layer = data->view_layer;
+
+ BKE_view_layer_base_deselect_all(view_layer);
- BKE_scene_base_deselect_all(data->scene);
+ lc = BKE_layer_collection_get_active(view_layer);
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
Object *ob = (*iter)->object();
- ob->lay = data->scene->lay;
- base = BKE_scene_base_add(data->scene, ob);
- BKE_scene_base_select(data->scene, base);
+ BKE_collection_object_add(data->bmain, lc->collection, ob);
+
+ base = BKE_view_layer_base_find(view_layer, ob);
+ /* TODO: is setting active needed? */
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
- DAG_id_tag_update_ex(data->bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&lc->collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_id_tag_update_ex(data->bmain, &ob->id,
+ OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME | DEG_TAG_BASE_FLAGS_UPDATE);
}
- DAG_relations_tag_update(data->bmain);
+ DEG_id_tag_update(&data->scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+ DEG_relations_tag_update(data->bmain);
}
for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
@@ -863,6 +867,7 @@ bool ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence
ImportJobData *job = new ImportJobData();
job->bmain = CTX_data_main(C);
job->scene = CTX_data_scene(C);
+ job->view_layer = CTX_data_view_layer(C);
job->import_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
@@ -924,12 +929,12 @@ void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float
/* ************************************************************************** */
-DerivedMesh *ABC_read_mesh(CacheReader *reader,
- Object *ob,
- DerivedMesh *dm,
- const float time,
- const char **err_str,
- int read_flag)
+Mesh *ABC_read_mesh(CacheReader *reader,
+ Object *ob,
+ Mesh *existing_mesh,
+ const float time,
+ const char **err_str,
+ int read_flag)
{
AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
IObject iobject = abc_reader->iobject();
@@ -948,7 +953,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
/* kFloorIndex is used to be compatible with non-interpolating
* properties; they use the floor. */
ISampleSelector sample_sel(time, ISampleSelector::kFloorIndex);
- return abc_reader->read_derivedmesh(dm, sample_sel, read_flag, err_str);
+ return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str);
}
/* ************************************************************************** */
diff --git a/source/blender/avi/intern/avi.c b/source/blender/avi/intern/avi.c
index 6e798a6244e..94f409d2753 100644
--- a/source/blender/avi/intern/avi.c
+++ b/source/blender/avi/intern/avi.c
@@ -200,35 +200,6 @@ AviError AVI_print_error(AviError in_error)
return in_error;
}
-#if 0
-void AVI_set_debug(int mode)
-{
- AVI_DEBUG = mode;
-}
-
-bool AVI_is_avi(char *name)
-{
- FILE *fp;
- int ret;
-
- fp = BLI_fopen(name, "rb");
- if (fp == NULL)
- return 0;
-
- if (GET_FCC(fp) != FCC("RIFF") ||
- !GET_FCC(fp) ||
- GET_FCC(fp) != FCC("AVI "))
- {
- ret = 0;
- }
- else {
- ret = 1;
- }
-
- fclose(fp);
- return ret;
-}
-#endif
bool AVI_is_avi(const char *name)
{
@@ -850,14 +821,6 @@ AviError AVI_open_compress(char *name, AviMovie *movie, int streams, ...)
movie->streams[i].sh.bottom = 0;
if (movie->streams[i].sh.Type == FCC("vids")) {
-#if 0
- if (movie->streams[i].format == AVI_FORMAT_MJPEG) {
- movie->streams[i].sf = MEM_mallocN(sizeof(AviBitmapInfoHeader) +
- sizeof(AviMJPEGUnknown), "moviestreamformatL");
- movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader) + sizeof(AviMJPEGUnknown);
- }
- else {
-#endif
movie->streams[i].sf = MEM_mallocN(sizeof(AviBitmapInfoHeader), "moviestreamformatS");
movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader);
@@ -874,26 +837,6 @@ AviError AVI_open_compress(char *name, AviMovie *movie, int streams, ...)
((AviBitmapInfoHeader *) movie->streams[i].sf)->YPelsPerMeter = 0;
((AviBitmapInfoHeader *) movie->streams[i].sf)->ClrUsed = 0;
((AviBitmapInfoHeader *) movie->streams[i].sf)->ClrImportant = 0;
-
-#if 0
- if (movie->streams[i].format == AVI_FORMAT_MJPEG) {
- AviMJPEGUnknown *tmp;
-
- tmp = (AviMJPEGUnknown *)((char *) movie->streams[i].sf + sizeof(AviBitmapInfoHeader));
-
- tmp->a = 44;
- tmp->b = 24;
- tmp->c = 0;
- tmp->d = 2;
- tmp->e = 8;
- tmp->f = 2;
- tmp->g = 1;
- }
- }
- else if (movie->streams[i].sh.Type == FCC("auds")) {
- /* pass */
- }
-#endif
}
}
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 0a4212ff233..8a3728574f3 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -35,6 +35,9 @@
#include "BLI_compiler_attrs.h"
#include "BLI_sys_types.h"
+/* enable this only if needed (unused circa 2016) */
+#define BLF_BLUR_ENABLE 0
+
struct rctf;
struct ColorManagedDisplay;
struct ResultBLF;
@@ -43,6 +46,8 @@ int BLF_init(void);
void BLF_exit(void);
void BLF_default_dpi(int dpi);
void BLF_default_set(int fontid);
+int BLF_default(void); /* get default font ID so we can pass it to other functions */
+void BLF_batch_reset(void); /* call when changing opengl context. */
void BLF_cache_clear(void);
@@ -62,6 +67,17 @@ void BLF_aspect(int fontid, float x, float y, float z);
void BLF_position(int fontid, float x, float y, float z);
void BLF_size(int fontid, int size, int dpi);
+/* goal: small but useful color API */
+void BLF_color4ubv(int fontid, const unsigned char rgba[4]);
+void BLF_color3ubv(int fontid, const unsigned char rgb[3]);
+void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha);
+void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b);
+void BLF_color4f(int fontid, float r, float g, float b, float a);
+void BLF_color4fv(int fontid, const float rgba[4]);
+void BLF_color3f(int fontid, float r, float g, float b);
+void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha);
+/* also available: UI_FontThemeColor(fontid, colorid) */
+
/* Set a 4x4 matrix to be multiplied before draw the text.
* Remember that you need call BLF_enable(BLF_MATRIX)
* to enable this.
@@ -76,10 +92,19 @@ void BLF_size(int fontid, int size, int dpi);
*/
void BLF_matrix(int fontid, const float m[16]);
+/* Batch drawcalls together as long as
+ * the modelview matrix and the font remain unchanged. */
+void BLF_batch_draw_begin(void);
+void BLF_batch_draw_flush(void);
+void BLF_batch_draw_end(void);
+
/* Draw the string using the default font, size and dpi. */
void BLF_draw_default(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL();
void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL();
+/* Set size and DPI, and return default font ID. */
+int BLF_set_default(void);
+
/* Draw the string using the current font. */
void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_NONNULL(2);
void BLF_draw(int fontid, const char *str, size_t len) ATTR_NONNULL(2);
@@ -123,29 +148,16 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt
*/
float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT;
-/* and this two function return the width and height
- * of the string, using the default font and both value
- * are multiplied by the aspect of the font.
- */
-void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height) ATTR_NONNULL();
-float BLF_width_default(const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BLF_height_default(const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-
-/* Set rotation for default font. */
-void BLF_rotation_default(float angle);
-
-/* Enable/disable options to the default font. */
-void BLF_enable_default(int option);
-void BLF_disable_default(int option);
-
/* By default, rotation and clipping are disable and
* have to be enable/disable using BLF_enable/disable.
*/
void BLF_rotation(int fontid, float angle);
void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax);
-void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax);
void BLF_wordwrap(int fontid, int wrap_width);
+
+#if BLF_BLUR_ENABLE
void BLF_blur(int fontid, int size);
+#endif
void BLF_enable(int fontid, int option);
void BLF_disable(int fontid, int option);
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 75aabf1f713..70a7b862830 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -50,13 +50,14 @@
#include "BLI_math.h"
#include "BLI_threads.h"
-#include "BIF_gl.h"
#include "BLF_api.h"
#include "IMB_colormanagement.h"
#ifndef BLF_STANDALONE
-#include "GPU_basic_shader.h"
+#include "GPU_shader.h"
+#include "GPU_matrix.h"
+#include "GPU_immediate.h"
#endif
#include "blf_internal_types.h"
@@ -130,6 +131,11 @@ void BLF_exit(void)
blf_font_exit();
}
+void BLF_batch_reset(void)
+{
+ blf_batch_draw_vao_clear();
+}
+
void BLF_cache_clear(void)
{
FontBLF *font;
@@ -137,8 +143,10 @@ void BLF_cache_clear(void)
for (i = 0; i < BLF_MAX_FONT; i++) {
font = global_font[i];
- if (font)
+ if (font) {
blf_glyph_cache_clear(font);
+ blf_kerning_cache_clear(font);
+ }
}
}
@@ -175,6 +183,12 @@ void BLF_default_set(int fontid)
}
}
+int BLF_default(void)
+{
+ ASSERT_DEFAULT_SET;
+ return global_font_default;
+}
+
int BLF_load(const char *name)
{
FontBLF *font;
@@ -358,24 +372,6 @@ void BLF_disable(int fontid, int option)
}
}
-void BLF_enable_default(int option)
-{
- FontBLF *font = blf_get(global_font_default);
-
- if (font) {
- font->flags |= option;
- }
-}
-
-void BLF_disable_default(int option)
-{
- FontBLF *font = blf_get(global_font_default);
-
- if (font) {
- font->flags &= ~option;
- }
-}
-
void BLF_aspect(int fontid, float x, float y, float z)
{
FontBLF *font = blf_get(fontid);
@@ -454,6 +450,7 @@ void BLF_size(int fontid, int size, int dpi)
}
}
+#if BLF_BLUR_ENABLE
void BLF_blur(int fontid, int size)
{
FontBLF *font = blf_get(fontid);
@@ -462,6 +459,97 @@ void BLF_blur(int fontid, int size)
font->blur = size;
}
}
+#endif
+
+void BLF_color4ubv(int fontid, const unsigned char rgba[4])
+{
+ FontBLF *font = blf_get(fontid);
+
+ if (font) {
+ font->color[0] = rgba[0];
+ font->color[1] = rgba[1];
+ font->color[2] = rgba[2];
+ font->color[3] = rgba[3];
+ }
+}
+
+void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha)
+{
+ FontBLF *font = blf_get(fontid);
+
+ if (font) {
+ font->color[0] = rgb[0];
+ font->color[1] = rgb[1];
+ font->color[2] = rgb[2];
+ font->color[3] = alpha;
+ }
+}
+
+void BLF_color3ubv(int fontid, const unsigned char rgb[3])
+{
+ BLF_color3ubv_alpha(fontid, rgb, 255);
+}
+
+void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b)
+{
+ FontBLF *font = blf_get(fontid);
+
+ if (font) {
+ font->color[0] = r;
+ font->color[1] = g;
+ font->color[2] = b;
+ font->color[3] = 255;
+ }
+}
+
+void BLF_color4fv(int fontid, const float rgba[4])
+{
+ FontBLF *font = blf_get(fontid);
+
+ if (font) {
+ rgba_float_to_uchar(font->color, rgba);
+ }
+}
+
+void BLF_color4f(int fontid, float r, float g, float b, float a)
+{
+ float rgba[4] = { r, g, b, a };
+ BLF_color4fv(fontid, rgba);
+}
+
+void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha)
+{
+ float rgba[4];
+ copy_v3_v3(rgba, rgb);
+ rgba[3] = alpha;
+ BLF_color4fv(fontid, rgba);
+}
+
+void BLF_color3f(int fontid, float r, float g, float b)
+{
+ float rgba[4] = { r, g, b, 1.0f };
+ BLF_color4fv(fontid, rgba);
+}
+
+void BLF_batch_draw_begin(void)
+{
+ BLI_assert(g_batch.enabled == false);
+ g_batch.enabled = true;
+}
+
+void BLF_batch_draw_flush(void)
+{
+ if (g_batch.enabled) {
+ blf_batch_draw();
+ }
+}
+
+void BLF_batch_draw_end(void)
+{
+ BLI_assert(g_batch.enabled == true);
+ blf_batch_draw(); /* Draw remaining glyphs */
+ g_batch.enabled = false;
+}
void BLF_draw_default(float x, float y, float z, const char *str, size_t len)
{
@@ -482,72 +570,46 @@ void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t l
BLF_draw_ascii(global_font_default, str, len); /* XXX, use real length */
}
-void BLF_rotation_default(float angle)
+int BLF_set_default(void)
{
- FontBLF *font = blf_get(global_font_default);
+ ASSERT_DEFAULT_SET;
- if (font) {
- font->angle = angle;
- }
+ BLF_size(global_font_default, global_font_points, global_font_dpi);
+
+ return global_font_default;
}
-static void blf_draw_gl__start(FontBLF *font, GLint *mode)
+static void blf_draw_gl__start(FontBLF *font)
{
/*
* The pixmap alignment hack is handle
* in BLF_position (old ui_rasterpos_safe).
*/
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-#ifndef BLF_STANDALONE
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
-#endif
-
- /* Save the current matrix mode. */
- glGetIntegerv(GL_MATRIX_MODE, mode);
+ /* always bind the texture for the first glyph */
+ font->tex_bind_state = 0;
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glLoadIdentity();
+ if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0)
+ return; /* glyphs will be translated individually and batched. */
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
+ GPU_matrix_push();
if (font->flags & BLF_MATRIX)
- glMultMatrixf(font->m);
+ GPU_matrix_mul(font->m);
- glTranslate3fv(font->pos);
+ GPU_matrix_translate_3fv(font->pos);
if (font->flags & BLF_ASPECT)
- glScalef(font->aspect[0], font->aspect[1], font->aspect[2]);
-
- if (font->flags & BLF_ROTATION) /* radians -> degrees */
- glRotatef(font->angle * (float)(180.0 / M_PI), 0.0f, 0.0f, 1.0f);
+ GPU_matrix_scale_3fv(font->aspect);
- if (font->shadow || font->blur)
- glGetFloatv(GL_CURRENT_COLOR, font->orig_col);
-
- /* always bind the texture for the first glyph */
- font->tex_bind_state = -1;
+ if (font->flags & BLF_ROTATION)
+ GPU_matrix_rotate_2d(RAD2DEG(font->angle));
}
-static void blf_draw_gl__end(GLint mode)
+static void blf_draw_gl__end(FontBLF *font)
{
- glMatrixMode(GL_TEXTURE);
- glPopMatrix();
-
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- if (mode != GL_MODELVIEW)
- glMatrixMode(mode);
-
-#ifndef BLF_STANDALONE
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-#endif
- glDisable(GL_BLEND);
+ if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) != 0)
+ GPU_matrix_pop();
}
void BLF_draw_ex(
@@ -555,23 +617,26 @@ void BLF_draw_ex(
struct ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
- GLint mode;
BLF_RESULT_CHECK_INIT(r_info);
if (font && font->glyph_cache) {
- blf_draw_gl__start(font, &mode);
+ blf_draw_gl__start(font);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw__wrap(font, str, len, r_info);
}
else {
blf_font_draw(font, str, len, r_info);
}
- blf_draw_gl__end(mode);
+ blf_draw_gl__end(font);
}
}
void BLF_draw(int fontid, const char *str, size_t len)
{
+ if (len == 0 || str[0] == '\0') {
+ return;
+ }
+
BLF_draw_ex(fontid, str, len, NULL);
}
@@ -580,12 +645,11 @@ void BLF_draw_ascii_ex(
struct ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
- GLint mode;
BLF_RESULT_CHECK_INIT(r_info);
if (font && font->glyph_cache) {
- blf_draw_gl__start(font, &mode);
+ blf_draw_gl__start(font);
if (font->flags & BLF_WORD_WRAP) {
/* use non-ascii draw function for word-wrap */
blf_font_draw__wrap(font, str, len, r_info);
@@ -593,24 +657,31 @@ void BLF_draw_ascii_ex(
else {
blf_font_draw_ascii(font, str, len, r_info);
}
- blf_draw_gl__end(mode);
+ blf_draw_gl__end(font);
}
}
void BLF_draw_ascii(int fontid, const char *str, size_t len)
{
+ if (len == 0 || str[0] == '\0') {
+ return;
+ }
+
BLF_draw_ascii_ex(fontid, str, len, NULL);
}
int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
{
+ if (len == 0 || str[0] == '\0') {
+ return 0;
+ }
+
FontBLF *font = blf_get(fontid);
- GLint mode;
int columns = 0;
if (font && font->glyph_cache) {
- blf_draw_gl__start(font, &mode);
+ blf_draw_gl__start(font);
columns = blf_font_draw_mono(font, str, len, cwidth);
- blf_draw_gl__end(mode);
+ blf_draw_gl__end(font);
}
return columns;
@@ -690,14 +761,6 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt
}
}
-void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height)
-{
- ASSERT_DEFAULT_SET;
-
- BLF_size(global_font_default, global_font_points, global_font_dpi);
- BLF_width_and_height(global_font_default, str, len, r_width, r_height);
-}
-
float BLF_width_ex(
int fontid, const char *str, size_t len,
struct ResultBLF *r_info)
@@ -728,14 +791,6 @@ float BLF_fixed_width(int fontid)
return 0.0f;
}
-float BLF_width_default(const char *str, size_t len)
-{
- ASSERT_DEFAULT_SET;
-
- BLF_size(global_font_default, global_font_points, global_font_dpi);
- return BLF_width(global_font_default, str, len);
-}
-
float BLF_height_ex(
int fontid, const char *str, size_t len,
struct ResultBLF *r_info)
@@ -799,15 +854,6 @@ float BLF_ascender(int fontid)
return 0.0f;
}
-float BLF_height_default(const char *str, size_t len)
-{
- ASSERT_DEFAULT_SET;
-
- BLF_size(global_font_default, global_font_points, global_font_dpi);
-
- return BLF_height(global_font_default, str, len);
-}
-
void BLF_rotation(int fontid, float angle)
{
FontBLF *font = blf_get(fontid);
@@ -829,18 +875,6 @@ void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax)
}
}
-void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax)
-{
- FontBLF *font = blf_get(global_font_default);
-
- if (font) {
- font->clip_rec.xmin = xmin;
- font->clip_rec.ymin = ymin;
- font->clip_rec.xmax = xmax;
- font->clip_rec.ymax = ymax;
- }
-}
-
void BLF_wordwrap(int fontid, int wrap_width)
{
FontBLF *font = blf_get(fontid);
@@ -856,7 +890,7 @@ void BLF_shadow(int fontid, int level, const float rgba[4])
if (font) {
font->shadow = level;
- copy_v4_v4(font->shadow_col, rgba);
+ rgba_float_to_uchar(font->shadow_color, rgba);
}
}
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index ff5c1151a82..f37ed3cb54f 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -154,32 +154,6 @@ char *blf_dir_search(const char *file)
return s;
}
-#if 0 /* UNUSED */
-int blf_dir_split(const char *str, char *file, int *size)
-{
- int i, len;
- char *s;
-
- /* Window, Linux or Mac, this is always / */
- s = strrchr(str, '/');
- if (s) {
- len = s - str;
- for (i = 0; i < len; i++)
- file[i] = str[i];
-
- file[i] = '.';
- file[i + 1] = 't';
- file[i + 2] = 't';
- file[i + 3] = 'f';
- file[i + 4] = '\0';
- s++;
- *size = atoi(s);
- return 1;
- }
- return 0;
-}
-#endif
-
/* Some font have additional file with metrics information,
* in general, the extension of the file is: .afm or .pfm
*/
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index fe9769dd2d1..eaf45d91034 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -58,6 +58,12 @@
#include "BIF_gl.h"
#include "BLF_api.h"
+#include "UI_interface.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_batch.h"
+
#include "blf_internal_types.h"
#include "blf_internal.h"
@@ -67,12 +73,155 @@
# define FT_New_Face FT_New_Face__win32_compat
#endif
+/* Batching buffer for drawing. */
+BatchBLF g_batch;
+
/* freetype2 handle ONLY for this file!. */
static FT_Library ft_lib;
static SpinLock ft_lib_mutex;
+/* -------------------------------------------------------------------- */
+/** \name Glyph Batching
+ * \{ */
+/**
+ * Drawcalls are precious! make them count!
+ * Since most of the Text elems are not covered by other UI elements, we can
+ * group some strings together and render them in one drawcall. This behaviour
+ * is on demand only, between BLF_batch_start() and BLF_batch_end().
+ **/
+static void blf_batch_draw_init(void)
+{
+ GPUVertFormat format = {0};
+ g_batch.pos_loc = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ g_batch.tex_loc = GPU_vertformat_attr_add(&format, "tex", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ g_batch.col_loc = GPU_vertformat_attr_add(&format, "col", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ g_batch.verts = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STREAM);
+ GPU_vertbuf_data_alloc(g_batch.verts, BLF_BATCH_DRAW_LEN_MAX);
+
+ GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
+ GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.tex_loc, &g_batch.tex_step);
+ GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
+ g_batch.glyph_len = 0;
+
+ g_batch.batch = GPU_batch_create_ex(GPU_PRIM_POINTS, g_batch.verts, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+static void blf_batch_draw_exit(void)
+{
+ GPU_BATCH_DISCARD_SAFE(g_batch.batch);
+}
+
+void blf_batch_draw_vao_clear(void)
+{
+ if (g_batch.batch) {
+ GPU_batch_vao_cache_clear(g_batch.batch);
+ }
+}
+
+void blf_batch_draw_begin(FontBLF *font)
+{
+ if (g_batch.batch == NULL) {
+ blf_batch_draw_init();
+ }
+
+ const bool font_changed = (g_batch.font != font);
+ const bool simple_shader = ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0);
+ const bool shader_changed = (simple_shader != g_batch.simple_shader);
+
+ g_batch.active = g_batch.enabled && simple_shader;
+
+ if (simple_shader) {
+ /* Offset is applied to each glyph. */
+ g_batch.ofs[0] = floorf(font->pos[0]);
+ g_batch.ofs[1] = floorf(font->pos[1]);
+ }
+ else {
+ /* Offset is baked in modelview mat. */
+ zero_v2(g_batch.ofs);
+ }
+
+ if (g_batch.active) {
+ float gpumat[4][4];
+ GPU_matrix_model_view_get(gpumat);
+
+ bool mat_changed = (memcmp(gpumat, g_batch.mat, sizeof(g_batch.mat)) != 0);
+
+ if (mat_changed) {
+ /* Modelviewmat is no longer the same.
+ * Flush cache but with the previous mat. */
+ GPU_matrix_push();
+ GPU_matrix_set(g_batch.mat);
+ }
+
+ /* flush cache if config is not the same. */
+ if (mat_changed || font_changed || shader_changed) {
+ blf_batch_draw();
+ g_batch.simple_shader = simple_shader;
+ g_batch.font = font;
+ }
+ else {
+ /* Nothing changed continue batching. */
+ return;
+ }
+
+ if (mat_changed) {
+ GPU_matrix_pop();
+ /* Save for next memcmp. */
+ memcpy(g_batch.mat, gpumat, sizeof(g_batch.mat));
+ }
+ }
+ else {
+ /* flush cache */
+ blf_batch_draw();
+ g_batch.font = font;
+ g_batch.simple_shader = simple_shader;
+ }
+}
+
+void blf_batch_draw(void)
+{
+ if (g_batch.glyph_len == 0)
+ return;
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ /* We need to flush widget base first to ensure correct ordering. */
+ UI_widgetbase_draw_cache_flush();
+
+ GPU_texture_bind(g_batch.tex_bind_state, 0);
+ GPU_vertbuf_vertex_count_set(g_batch.verts, g_batch.glyph_len);
+ GPU_vertbuf_use(g_batch.verts); /* send data */
+
+ GPUBuiltinShader shader = (g_batch.simple_shader) ? GPU_SHADER_TEXT_SIMPLE : GPU_SHADER_TEXT;
+ GPU_batch_program_set_builtin(g_batch.batch, shader);
+ GPU_batch_uniform_1i(g_batch.batch, "glyph", 0);
+ GPU_batch_draw(g_batch.batch);
+
+ GPU_blend(false);
+
+ /* restart to 1st vertex data pointers */
+ GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
+ GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.tex_loc, &g_batch.tex_step);
+ GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
+ g_batch.glyph_len = 0;
+}
+
+static void blf_batch_draw_end(void)
+{
+ if (!g_batch.active) {
+ blf_batch_draw();
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
int blf_font_init(void)
{
+ memset(&g_batch, 0, sizeof(g_batch));
BLI_spin_init(&ft_lib_mutex);
return FT_Init_FreeType(&ft_lib);
}
@@ -81,6 +230,7 @@ void blf_font_exit(void)
{
FT_Done_FreeType(ft_lib);
BLI_spin_end(&ft_lib_mutex);
+ blf_batch_draw_exit();
}
void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
@@ -88,6 +238,14 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
GlyphCacheBLF *gc;
FT_Error err;
+ gc = blf_glyph_cache_find(font, size, dpi);
+ if (gc) {
+ font->glyph_cache = gc;
+ /* Optimization: do not call FT_Set_Char_Size if size did not change. */
+ if (font->size == size && font->dpi == dpi)
+ return;
+ }
+
err = FT_Set_Char_Size(font->face, 0, (FT_F26Dot6)(size * 64), dpi, dpi);
if (err) {
/* FIXME: here we can go through the fixed size and choice a close one */
@@ -98,10 +256,7 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
font->size = size;
font->dpi = dpi;
- gc = blf_glyph_cache_find(font, size, dpi);
- if (gc)
- font->glyph_cache = gc;
- else {
+ if (!gc) {
gc = blf_glyph_cache_new(font);
if (gc)
font->glyph_cache = gc;
@@ -129,6 +284,20 @@ static void blf_font_ensure_ascii_table(FontBLF *font)
}
}
+static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode)
+{
+ KerningCacheBLF *kc = font->kerning_cache;
+
+ font->kerning_mode = kern_mode;
+
+ if (!kc || kc->mode != kern_mode) {
+ font->kerning_cache = kc = blf_kerning_cache_find(font);
+ if (!kc) {
+ font->kerning_cache = kc = blf_kerning_cache_new(font);
+ }
+ }
+}
+
/* Fast path for runs of ASCII characters. Given that common UTF-8
* input will consist of an overwhelming majority of ASCII
* characters.
@@ -156,6 +325,26 @@ static void blf_font_ensure_ascii_table(FontBLF *font)
(((_font)->flags & BLF_KERNING_DEFAULT) ? \
ft_kerning_default : (FT_UInt)FT_KERNING_UNFITTED) \
+/* Note,
+ * blf_font_ensure_ascii_kerning(font, kern_mode); must be called before this macro */
+
+#define BLF_KERNING_STEP_FAST(_font, _kern_mode, _g_prev, _g, _c_prev, _c, _pen_x) \
+{ \
+ if (_g_prev) { \
+ FT_Vector _delta; \
+ if (_c_prev < 0x80 && _c < 0x80) { \
+ _pen_x += (_font)->kerning_cache->table[_c][_c_prev]; \
+ } \
+ else if (FT_Get_Kerning((_font)->face, \
+ (_g_prev)->idx, \
+ (_g)->idx, \
+ _kern_mode, \
+ &(_delta)) == 0) \
+ { \
+ _pen_x += (int)_delta.x >> 6; \
+ } \
+ } \
+} (void)0
#define BLF_KERNING_STEP(_font, _kern_mode, _g_prev, _g, _delta, _pen_x) \
{ \
@@ -176,16 +365,23 @@ static void blf_font_draw_ex(
FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c;
+ unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
- FT_Vector delta;
int pen_x = 0;
size_t i = 0;
GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
+ if (len == 0) {
+ /* early output, don't do any IMM OpenGL. */
+ return;
+ }
+
BLF_KERNING_VARS(font, has_kerning, kern_mode);
blf_font_ensure_ascii_table(font);
+ blf_font_ensure_ascii_kerning(font, kern_mode);
+
+ blf_batch_draw_begin(font);
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
@@ -195,15 +391,18 @@ static void blf_font_draw_ex(
if (UNLIKELY(g == NULL))
continue;
if (has_kerning)
- BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
+ BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
/* do not return this loop if clipped, we want every character tested */
blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
pen_x += g->advance_i;
g_prev = g;
+ c_prev = c;
}
+ blf_batch_draw_end();
+
if (r_info) {
r_info->lines = 1;
r_info->width = pen_x;
@@ -219,30 +418,35 @@ static void blf_font_draw_ascii_ex(
FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info,
int pen_y)
{
- unsigned char c;
+ unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
- FT_Vector delta;
int pen_x = 0;
GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
blf_font_ensure_ascii_table(font);
+ blf_font_ensure_ascii_kerning(font, kern_mode);
+
+ blf_batch_draw_begin(font);
while ((c = *(str++)) && len--) {
BLI_assert(c < 128);
if ((g = glyph_ascii_table[c]) == NULL)
continue;
if (has_kerning)
- BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
+ BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
/* do not return this loop if clipped, we want every character tested */
blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
pen_x += g->advance_i;
g_prev = g;
+ c_prev = c;
}
+ blf_batch_draw_end();
+
if (r_info) {
r_info->lines = 1;
r_info->width = pen_x;
@@ -265,6 +469,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
blf_font_ensure_ascii_table(font);
+ blf_batch_draw_begin(font);
+
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
@@ -284,6 +490,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
pen_x += cwidth * col;
}
+ blf_batch_draw_end();
+
return columns;
}
@@ -292,9 +500,8 @@ static void blf_font_draw_buffer_ex(
FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c;
+ unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
- FT_Vector delta;
int pen_x = (int)font->pos[0];
int pen_y_basis = (int)font->pos[1] + pen_y;
size_t i = 0;
@@ -310,6 +517,7 @@ static void blf_font_draw_buffer_ex(
BLF_KERNING_VARS(font, has_kerning, kern_mode);
blf_font_ensure_ascii_table(font);
+ blf_font_ensure_ascii_kerning(font, kern_mode);
/* another buffer specific call for color conversion */
@@ -321,7 +529,7 @@ static void blf_font_draw_buffer_ex(
if (UNLIKELY(g == NULL))
continue;
if (has_kerning)
- BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
+ BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
chx = pen_x + ((int)g->pos_x);
chy = pen_y_basis + g->height;
@@ -423,6 +631,7 @@ static void blf_font_draw_buffer_ex(
pen_x += g->advance_i;
g_prev = g;
+ c_prev = c;
}
if (r_info) {
@@ -436,41 +645,55 @@ void blf_font_draw_buffer(
blf_font_draw_buffer_ex(font, str, len, r_info, 0);
}
+static bool blf_font_width_to_strlen_glyph_process(
+ FontBLF *font, const bool has_kerning, const FT_UInt kern_mode,
+ const uint c_prev, const uint c, GlyphBLF *g_prev, GlyphBLF *g,
+ int *pen_x, const int width_i)
+{
+ if (UNLIKELY(c == BLI_UTF8_ERR)) {
+ return true; /* break the calling loop. */
+ }
+ if (UNLIKELY(g == NULL)) {
+ return false; /* continue the calling loop. */
+ }
+ if (has_kerning) {
+ BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, *pen_x);
+ }
+
+ *pen_x += g->advance_i;
+
+ return (*pen_x >= width_i);
+}
+
size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, float width, float *r_width)
{
- unsigned int c;
- GlyphBLF *g, *g_prev = NULL;
- FT_Vector delta;
- int pen_x = 0;
- size_t i = 0, i_prev;
+ unsigned int c, c_prev;
+ GlyphBLF *g, *g_prev;
+ int pen_x, width_new;
+ size_t i, i_prev;
GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
- const int width_i = (int)width + 1;
- int width_new;
+ const int width_i = (int)width;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
blf_font_ensure_ascii_table(font);
+ if (has_kerning) {
+ blf_font_ensure_ascii_kerning(font, kern_mode);
+ }
- while ((void)(i_prev = i),
- (void)(width_new = pen_x),
- ((i < len) && str[i]))
+ for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0;
+ (i < len) && str[i];
+ i_prev = i, width_new = pen_x, c_prev = c, g_prev = g)
{
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
- if (UNLIKELY(c == BLI_UTF8_ERR))
- break;
- if (UNLIKELY(g == NULL))
- continue;
- if (has_kerning)
- BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
-
- pen_x += g->advance_i;
-
- if (width_i < pen_x) {
+ if (blf_font_width_to_strlen_glyph_process(
+ font, has_kerning, kern_mode,
+ c_prev, c, g_prev, g,
+ &pen_x, width_i))
+ {
break;
}
-
- g_prev = g;
}
if (r_width) {
@@ -482,97 +705,64 @@ size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, floa
size_t blf_font_width_to_rstrlen(FontBLF *font, const char *str, size_t len, float width, float *r_width)
{
- unsigned int c;
- GlyphBLF *g, *g_prev = NULL;
- FT_Vector delta;
- int pen_x = 0;
- size_t i = 0, i_prev;
+ unsigned int c, c_prev;
+ GlyphBLF *g, *g_prev;
+ int pen_x, width_new;
+ size_t i, i_prev, i_tmp;
+ char *s, *s_prev;
GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
- const int width_i = (int)width + 1;
- int width_new;
-
- bool is_malloc;
- int (*width_accum)[2];
- int width_accum_ofs = 0;
+ const int width_i = (int)width;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
- /* skip allocs in simple cases */
- len = BLI_strnlen(str, len);
- if (width_i <= 1 || len == 0) {
- if (r_width) {
- *r_width = 0.0f;
- }
- return len;
- }
-
- if (len < 2048) {
- width_accum = BLI_array_alloca(width_accum, len);
- is_malloc = false;
- }
- else {
- width_accum = MEM_mallocN(sizeof(*width_accum) * len, __func__);
- is_malloc = true;
- }
-
blf_font_ensure_ascii_table(font);
-
- while ((i < len) && str[i]) {
- BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
-
- if (UNLIKELY(c == BLI_UTF8_ERR))
- break;
- if (UNLIKELY(g == NULL))
- continue;
- if (has_kerning)
- BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
-
- pen_x += g->advance_i;
-
- width_accum[width_accum_ofs][0] = (int)i;
- width_accum[width_accum_ofs][1] = pen_x;
- width_accum_ofs++;
-
- g_prev = g;
+ if (has_kerning) {
+ blf_font_ensure_ascii_kerning(font, kern_mode);
}
- if (pen_x > width_i && width_accum_ofs != 0) {
- const int min_x = pen_x - width_i;
+ i = BLI_strnlen(str, len);
+ s = BLI_str_find_prev_char_utf8(str, &str[i]);
+ i = (size_t)((s != NULL) ? s - str : 0);
+ s_prev = BLI_str_find_prev_char_utf8(str, s);
+ i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0);
+
+ i_tmp = i;
+ BLF_UTF8_NEXT_FAST(font, g, str, i_tmp, c, glyph_ascii_table);
+ for (width_new = pen_x = 0;
+ (s != NULL);
+ i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x)
+ {
+ s_prev = BLI_str_find_prev_char_utf8(str, s);
+ i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0);
- /* search backwards */
- width_new = pen_x;
- while (width_accum_ofs-- > 0) {
- if (min_x > width_accum[width_accum_ofs][1]) {
- break;
- }
+ if (s_prev != NULL) {
+ i_tmp = i_prev;
+ BLF_UTF8_NEXT_FAST(font, g_prev, str, i_tmp, c_prev, glyph_ascii_table);
+ BLI_assert(i_tmp == i);
}
- width_accum_ofs++;
- width_new = pen_x - width_accum[width_accum_ofs][1];
- i_prev = (size_t)width_accum[width_accum_ofs][0];
- }
- else {
- width_new = pen_x;
- i_prev = 0;
- }
- if (is_malloc) {
- MEM_freeN(width_accum);
+ if (blf_font_width_to_strlen_glyph_process(
+ font, has_kerning, kern_mode,
+ c_prev, c, g_prev, g,
+ &pen_x, width_i))
+ {
+ break;
+ }
}
if (r_width) {
*r_width = (float)width_new;
}
- return i_prev;
+ return i;
}
static void blf_font_boundbox_ex(
FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info,
int pen_y)
{
- unsigned int c;
+ unsigned int c, c_prev = BLI_UTF8_ERR;
GlyphBLF *g, *g_prev = NULL;
- FT_Vector delta;
int pen_x = 0;
size_t i = 0;
GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table;
@@ -587,6 +777,7 @@ static void blf_font_boundbox_ex(
box->ymax = -32000.0f;
blf_font_ensure_ascii_table(font);
+ blf_font_ensure_ascii_kerning(font, kern_mode);
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
@@ -596,7 +787,7 @@ static void blf_font_boundbox_ex(
if (UNLIKELY(g == NULL))
continue;
if (has_kerning)
- BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
+ BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
gbox.xmin = (float)pen_x;
gbox.xmax = (float)pen_x + g->advance;
@@ -611,6 +802,7 @@ static void blf_font_boundbox_ex(
pen_x += g->advance_i;
g_prev = g;
+ c_prev = c;
}
if (box->xmin > box->xmax) {
@@ -891,6 +1083,8 @@ void blf_font_free(FontBLF *font)
blf_glyph_cache_free(gc);
}
+ blf_kerning_cache_clear(font);
+
FT_Done_Face(font->face);
if (font->filename)
MEM_freeN(font->filename);
@@ -901,8 +1095,6 @@ void blf_font_free(FontBLF *font)
static void blf_font_fill(FontBLF *font)
{
- unsigned int i;
-
font->aspect[0] = 1.0f;
font->aspect[1] = 1.0f;
font->aspect[2] = 1.0f;
@@ -910,9 +1102,15 @@ static void blf_font_fill(FontBLF *font)
font->pos[1] = 0.0f;
font->angle = 0.0f;
- for (i = 0; i < 16; i++)
+ for (int i = 0; i < 16; i++)
font->m[i] = 0;
+ /* annoying bright color so we can see where to add BLF_color calls */
+ font->color[0] = 255;
+ font->color[1] = 255;
+ font->color[2] = 0;
+ font->color[3] = 255;
+
font->clip_rec.xmin = 0.0f;
font->clip_rec.xmax = 0.0f;
font->clip_rec.ymin = 0.0f;
@@ -921,8 +1119,12 @@ static void blf_font_fill(FontBLF *font)
font->dpi = 0;
font->size = 0;
BLI_listbase_clear(&font->cache);
+ BLI_listbase_clear(&font->kerning_caches);
font->glyph_cache = NULL;
+ font->kerning_cache = NULL;
+#if BLF_BLUR_ENABLE
font->blur = 0;
+#endif
font->tex_size_max = -1;
font->buf_info.fbuf = NULL;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index c19c8528232..2679deea254 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -56,13 +56,69 @@
#include "BLF_api.h"
#ifndef BLF_STANDALONE
-# include "GPU_basic_shader.h"
+# include "GPU_immediate.h"
+# include "GPU_extensions.h"
#endif
#include "blf_internal_types.h"
#include "blf_internal.h"
#include "BLI_strict_flags.h"
+#include "BLI_math_vector.h"
+
+KerningCacheBLF *blf_kerning_cache_find(FontBLF *font)
+{
+ KerningCacheBLF *p;
+
+ p = (KerningCacheBLF *)font->kerning_caches.first;
+ while (p) {
+ if (p->mode == font->kerning_mode)
+ return p;
+ p = p->next;
+ }
+ return NULL;
+}
+
+/* Create a new glyph cache for the current kerning mode. */
+KerningCacheBLF *blf_kerning_cache_new(FontBLF *font)
+{
+ KerningCacheBLF *kc;
+
+ kc = (KerningCacheBLF *)MEM_callocN(sizeof(KerningCacheBLF), "blf_kerning_cache_new");
+ kc->next = NULL;
+ kc->prev = NULL;
+ kc->mode = font->kerning_mode;
+
+ unsigned int i, j;
+ for (i = 0; i < 0x80; i++) {
+ for (j = 0; j < 0x80; j++) {
+ GlyphBLF *g = blf_glyph_search(font->glyph_cache, i);
+ if (!g) {
+ FT_UInt glyph_index = FT_Get_Char_Index(font->face, i);
+ g = blf_glyph_add(font, glyph_index, i);
+ }
+ /* Cannot fail since it has been added just before. */
+ GlyphBLF *g_prev = blf_glyph_search(font->glyph_cache, j);
+
+ FT_Vector delta = {.x = 0, .y = 0};
+ if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, kc->mode, &delta) == 0) {
+ kc->table[i][j] = (int)delta.x >> 6;
+ }
+ else {
+ kc->table[i][j] = 0;
+ }
+ }
+ }
+
+ BLI_addhead(&font->kerning_caches, kc);
+ return kc;
+}
+
+void blf_kerning_cache_clear(FontBLF *font)
+{
+ font->kerning_cache = NULL;
+ BLI_freelistN(&font->kerning_caches);
+}
GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi)
{
@@ -91,12 +147,12 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table));
memset(gc->bucket, 0, sizeof(gc->bucket));
- gc->textures = (GLuint *)MEM_mallocN(sizeof(GLuint) * 256, __func__);
+ gc->textures = (GPUTexture **)MEM_callocN(sizeof(GPUTexture *) * 256, __func__);
gc->textures_len = 256;
gc->texture_current = BLF_TEXTURE_UNSET;
- gc->offset_x = 0;
- gc->offset_y = 0;
- gc->pad = 3;
+ gc->offset_x = 3; /* enough padding for blur */
+ gc->offset_y = 3; /* enough padding for blur */
+ gc->pad = 6;
gc->glyphs_len_max = (int)font->face->num_glyphs;
gc->glyphs_len_free = (int)font->face->num_glyphs;
@@ -141,16 +197,17 @@ void blf_glyph_cache_clear(FontBLF *font)
void blf_glyph_cache_free(GlyphCacheBLF *gc)
{
GlyphBLF *g;
- int i;
+ unsigned int i;
for (i = 0; i < 257; i++) {
while ((g = BLI_pophead(&gc->bucket[i]))) {
blf_glyph_free(g);
}
}
-
- if (gc->texture_current != BLF_TEXTURE_UNSET) {
- glDeleteTextures((int)gc->texture_current + 1, gc->textures);
+ for (i = 0; i < gc->textures_len; i++) {
+ if (gc->textures[i]) {
+ GPU_texture_free(gc->textures[i]);
+ }
}
MEM_freeN(gc->textures);
MEM_freeN(gc);
@@ -159,13 +216,14 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc)
static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
{
int i;
+ char error[256];
/* move the index. */
gc->texture_current++;
if (UNLIKELY(gc->texture_current >= gc->textures_len)) {
gc->textures_len *= 2;
- gc->textures = MEM_reallocN((void *)gc->textures, sizeof(GLuint) * gc->textures_len);
+ gc->textures = MEM_recallocN((void *)gc->textures, sizeof(GPUTexture *) * gc->textures_len);
}
gc->p2_width = (int)blf_next_p2((unsigned int)((gc->glyphs_len_free * gc->glyph_width_max) + (gc->pad * 2)));
@@ -174,30 +232,20 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
}
i = (int)((gc->p2_width - (gc->pad * 2)) / gc->glyph_width_max);
- gc->p2_height = (int)blf_next_p2((unsigned int)(((gc->glyphs_len_max / i) + 1) * gc->glyph_height_max));
+ gc->p2_height = (int)blf_next_p2((unsigned int)(((gc->glyphs_len_max / i) + 1) * gc->glyph_height_max + (gc->pad * 2)));
if (gc->p2_height > font->tex_size_max) {
gc->p2_height = font->tex_size_max;
}
- glGenTextures(1, &gc->textures[gc->texture_current]);
- glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = gc->textures[gc->texture_current]));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
-#ifndef BLF_STANDALONE
- /* needed since basic shader doesn't support alpha-only textures,
- * while we could add support this is only used in a few places
- * (an alternative could be to have a simple shader for BLF). */
- if (GLEW_ARB_texture_swizzle && GPU_basic_shader_use_glsl_get()) {
- GLint swizzle_mask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA};
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask);
- }
-#endif
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
+ unsigned char *pixels = MEM_callocN((size_t)gc->p2_width * (size_t)gc->p2_height, "BLF texture init");
+ GPUTexture *tex = GPU_texture_create_nD(gc->p2_width, gc->p2_height, 0, 2, pixels, GPU_R8, GPU_DATA_UNSIGNED_BYTE, 0, false, error);
+ MEM_freeN(pixels);
+ gc->textures[gc->texture_current] = tex;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_wrap_mode(tex, false);
+ GPU_texture_filters(tex, GPU_NEAREST, GPU_LINEAR);
+ GPU_texture_unbind(tex);
}
GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
@@ -310,8 +358,8 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
}
}
- g->bitmap = (unsigned char *)MEM_mallocN((size_t)(g->width * g->height), "glyph bitmap");
- memcpy((void *)g->bitmap, (void *)bitmap.buffer, (size_t)(g->width * g->height));
+ g->bitmap = (unsigned char *)MEM_mallocN((size_t)g->width * (size_t)g->height, "glyph bitmap");
+ memcpy((void *)g->bitmap, (void *)bitmap.buffer, (size_t)g->width * (size_t)g->height);
}
g->advance = ((float)slot->advance.x) / 64.0f;
@@ -339,87 +387,62 @@ void blf_glyph_free(GlyphBLF *g)
/* don't need free the texture, the GlyphCache already
* have a list of all the texture and free it.
*/
- if (g->bitmap) {
+ if (g->bitmap)
MEM_freeN(g->bitmap);
- }
MEM_freeN(g);
}
-static void blf_texture_draw(float uv[2][2], float dx, float y1, float dx1, float y2)
+static void blf_texture_draw(const unsigned char color[4], const float uv[2][2], float x1, float y1, float x2, float y2)
{
- glBegin(GL_QUADS);
- glTexCoord2f(uv[0][0], uv[0][1]);
- glVertex2f(dx, y1);
-
- glTexCoord2f(uv[0][0], uv[1][1]);
- glVertex2f(dx, y2);
-
- glTexCoord2f(uv[1][0], uv[1][1]);
- glVertex2f(dx1, y2);
-
- glTexCoord2f(uv[1][0], uv[0][1]);
- glVertex2f(dx1, y1);
- glEnd();
+ /* Only one vertex per glyph, geometry shader expand it into a quad. */
+ /* TODO Get rid of Geom Shader because it's not optimal AT ALL for the GPU */
+ copy_v4_fl4(GPU_vertbuf_raw_step(&g_batch.pos_step), x1 + g_batch.ofs[0], y1 + g_batch.ofs[1],
+ x2 + g_batch.ofs[0], y2 + g_batch.ofs[1]);
+ copy_v4_v4(GPU_vertbuf_raw_step(&g_batch.tex_step), (float *)uv);
+ copy_v4_v4_uchar(GPU_vertbuf_raw_step(&g_batch.col_step), color);
+ g_batch.glyph_len++;
+ /* Flush cache if it's full. */
+ if (g_batch.glyph_len == BLF_BATCH_DRAW_LEN_MAX) {
+ blf_batch_draw();
+ }
}
-static void blf_texture5_draw(const float shadow_col[4], float uv[2][2], float x1, float y1, float x2, float y2)
+static void blf_texture5_draw(const unsigned char color_in[4], int tex_w, int tex_h, const float uv[2][2],
+ float x1, float y1, float x2, float y2)
{
- const float soft[25] = {1 / 60.0f, 1 / 60.0f, 2 / 60.0f, 1 / 60.0f, 1 / 60.0f,
- 1 / 60.0f, 3 / 60.0f, 5 / 60.0f, 3 / 60.0f, 1 / 60.0f,
- 2 / 60.0f, 5 / 60.0f, 8 / 60.0f, 5 / 60.0f, 2 / 60.0f,
- 1 / 60.0f, 3 / 60.0f, 5 / 60.0f, 3 / 60.0f, 1 / 60.0f,
- 1 / 60.0f, 1 / 60.0f, 2 / 60.0f, 1 / 60.0f, 1 / 60.0f};
-
- const float *fp = soft;
- float color[4];
- float dx, dy;
-
- color[0] = shadow_col[0];
- color[1] = shadow_col[1];
- color[2] = shadow_col[2];
-
- for (dx = -2; dx < 3; dx++) {
- for (dy = -2; dy < 3; dy++, fp++) {
- color[3] = *(fp) * shadow_col[3];
- glColor4fv(color);
- blf_texture_draw(uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy);
- }
- }
-
- glColor4fv(color);
+ float ofs[2] = { 2 / (float)tex_w, 2 / (float)tex_h };
+ float uv_flag[2][2];
+ copy_v4_v4((float *)uv_flag, (float *)uv);
+ /* flag the x and y component signs for 5x5 bluring */
+ uv_flag[0][0] = -(uv_flag[0][0] - ofs[0]);
+ uv_flag[0][1] = -(uv_flag[0][1] - ofs[1]);
+ uv_flag[1][0] = -(uv_flag[1][0] + ofs[0]);
+ uv_flag[1][1] = -(uv_flag[1][1] + ofs[1]);
+
+ blf_texture_draw(color_in, uv_flag, x1 - 2, y1 + 2, x2 + 2, y2 - 2);
}
-static void blf_texture3_draw(const float shadow_col[4], float uv[2][2], float x1, float y1, float x2, float y2)
+static void blf_texture3_draw(const unsigned char color_in[4], int tex_w, int tex_h, const float uv[2][2],
+ float x1, float y1, float x2, float y2)
{
- const float soft[9] = {1 / 16.0f, 2 / 16.0f, 1 / 16.0f,
- 2 / 16.0f, 4 / 16.0f, 2 / 16.0f,
- 1 / 16.0f, 2 / 16.0f, 1 / 16.0f};
-
- const float *fp = soft;
- float color[4];
- float dx, dy;
-
- color[0] = shadow_col[0];
- color[1] = shadow_col[1];
- color[2] = shadow_col[2];
-
- for (dx = -1; dx < 2; dx++) {
- for (dy = -1; dy < 2; dy++, fp++) {
- color[3] = *(fp) * shadow_col[3];
- glColor4fv(color);
- blf_texture_draw(uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy);
- }
- }
-
- glColor4fv(color);
+ float ofs[2] = { 1 / (float)tex_w, 1 / (float)tex_h };
+ float uv_flag[2][2];
+ copy_v4_v4((float *)uv_flag, (float *)uv);
+ /* flag the x component sign for 3x3 bluring */
+ uv_flag[0][0] = -(uv_flag[0][0] - ofs[0]);
+ uv_flag[0][1] = (uv_flag[0][1] - ofs[1]);
+ uv_flag[1][0] = -(uv_flag[1][0] + ofs[0]);
+ uv_flag[1][1] = (uv_flag[1][1] + ofs[1]);
+
+ blf_texture_draw(color_in, uv_flag, x1 - 1, y1 + 1, x2 + 1, y2 - 1);
}
static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
{
rect->xmin = floorf(x + g->pos_x);
rect->xmax = rect->xmin + (float)g->width;
- rect->ymin = y + g->pos_y;
- rect->ymax = y + g->pos_y - (float)g->height;
+ rect->ymin = floorf(y + g->pos_y);
+ rect->ymax = rect->ymin - (float)g->height;
}
void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
@@ -433,12 +456,12 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
GlyphCacheBLF *gc = font->glyph_cache;
if (font->tex_size_max == -1)
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->tex_size_max);
+ font->tex_size_max = GPU_max_texture_size();
if (gc->texture_current == BLF_TEXTURE_UNSET) {
blf_glyph_cache_texture(font, gc);
gc->offset_x = gc->pad;
- gc->offset_y = 0;
+ gc->offset_y = 3; /* enough padding for blur */
}
if (gc->offset_x > (gc->p2_width - gc->glyph_width_max)) {
@@ -446,7 +469,7 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
gc->offset_y += gc->glyph_height_max;
if (gc->offset_y > (gc->p2_height - gc->glyph_height_max)) {
- gc->offset_y = 0;
+ gc->offset_y = 3; /* enough padding for blur */
blf_glyph_cache_texture(font, gc);
}
}
@@ -467,15 +490,7 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
BLI_assert(g->height > 0);
}
-
- glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
- glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- glBindTexture(GL_TEXTURE_2D, g->tex);
- glTexSubImage2D(GL_TEXTURE_2D, 0, g->offset_x, g->offset_y, g->width, g->height, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap);
- glPopClientAttrib();
+ GPU_texture_update_sub(g->tex, GPU_DATA_UNSIGNED_BYTE, g->bitmap, g->offset_x, g->offset_y, 0, g->width, g->height, 0);
g->uv[0][0] = ((float)g->offset_x) / ((float)gc->p2_width);
g->uv[0][1] = ((float)g->offset_y) / ((float)gc->p2_height);
@@ -502,42 +517,46 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y)
}
if (font->tex_bind_state != g->tex) {
- glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = g->tex));
+ blf_batch_draw();
+ font->tex_bind_state = g->tex;
+ GPU_texture_bind(font->tex_bind_state, 0);
}
+ g_batch.tex_bind_state = g->tex;
+
if (font->flags & BLF_SHADOW) {
rctf rect_ofs;
blf_glyph_calc_rect(&rect_ofs, g,
x + (float)font->shadow_x,
y + (float)font->shadow_y);
- switch (font->shadow) {
- case 3:
- blf_texture3_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
- break;
- case 5:
- blf_texture5_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
- break;
- default:
- glColor4fv(font->shadow_col);
- blf_texture_draw(g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
- break;
+ if (font->shadow == 0) {
+ blf_texture_draw(font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
+ }
+ else if (font->shadow <= 4) {
+ blf_texture3_draw(font->shadow_color, font->glyph_cache->p2_width, font->glyph_cache->p2_height, g->uv,
+ rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
+ }
+ else {
+ blf_texture5_draw(font->shadow_color, font->glyph_cache->p2_width, font->glyph_cache->p2_height, g->uv,
+ rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
}
-
- glColor4fv(font->orig_col);
}
+#if BLF_BLUR_ENABLE
switch (font->blur) {
case 3:
- blf_texture3_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ blf_texture3_draw(font->color, font->glyph_cache->p2_width, font->glyph_cache->p2_height, g->uv,
+ rect.xmin, rect.ymin, rect.xmax, rect.ymax);
break;
case 5:
- blf_texture5_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ blf_texture5_draw(font->color, font->glyph_cache->p2_width, font->glyph_cache->p2_height, g->uv,
+ rect.xmin, rect.ymin, rect.xmax, rect.ymax);
break;
default:
- blf_texture_draw(g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
- break;
+ blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
}
-
- return;
+#else
+ blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+#endif
}
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 708466e8ebd..624f3ae884c 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -37,6 +37,10 @@ struct GlyphBLF;
struct GlyphCacheBLF;
struct rctf;
+void blf_batch_draw_vao_clear(void);
+void blf_batch_draw_begin(struct FontBLF *font);
+void blf_batch_draw(void);
+
unsigned int blf_next_p2(unsigned int x);
unsigned int blf_hash(unsigned int val);
@@ -74,6 +78,10 @@ int blf_font_count_missing_chars(struct FontBLF *font, const char *str, const si
void blf_font_free(struct FontBLF *font);
+struct KerningCacheBLF *blf_kerning_cache_find(struct FontBLF *font);
+struct KerningCacheBLF *blf_kerning_cache_new(struct FontBLF *font);
+void blf_kerning_cache_clear(struct FontBLF *font);
+
struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, unsigned int size, unsigned int dpi);
struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font);
void blf_glyph_cache_clear(struct FontBLF *font);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 5723f08d44b..265835f4c75 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -31,6 +31,37 @@
#ifndef __BLF_INTERNAL_TYPES_H__
#define __BLF_INTERNAL_TYPES_H__
+#include "GPU_vertex_buffer.h"
+#include "GPU_texture.h"
+
+#define BLF_BATCH_DRAW_LEN_MAX 2048 /* in glyph */
+
+typedef struct BatchBLF {
+ struct FontBLF *font; /* can only batch glyph from the same font */
+ struct GPUBatch *batch;
+ struct GPUVertBuf *verts;
+ struct GPUVertBufRaw pos_step, tex_step, col_step;
+ unsigned int pos_loc, tex_loc, col_loc;
+ unsigned int glyph_len;
+ float ofs[2]; /* copy of font->pos */
+ float mat[4][4]; /* previous call modelmatrix. */
+ bool enabled, active, simple_shader;
+ GPUTexture *tex_bind_state;
+} BatchBLF;
+
+extern BatchBLF g_batch;
+
+typedef struct KerningCacheBLF {
+ struct KerningCacheBLF *next, *prev;
+
+ /* kerning mode. */
+ FT_UInt mode;
+
+ /* only cache a ascii glyph pairs. Only store the x
+ * offset we are interested in, instead of the full FT_Vector. */
+ int table[0x80][0x80];
+} KerningCacheBLF;
+
typedef struct GlyphCacheBLF {
struct GlyphCacheBLF *next;
struct GlyphCacheBLF *prev;
@@ -48,7 +79,7 @@ typedef struct GlyphCacheBLF {
struct GlyphBLF *glyph_ascii_table[256];
/* texture array, to draw the glyphs. */
- unsigned int *textures;
+ GPUTexture **textures;
/* size of the array. */
unsigned int textures_len;
@@ -103,7 +134,7 @@ typedef struct GlyphBLF {
int advance_i;
/* texture id where this glyph is store. */
- unsigned int tex;
+ GPUTexture *tex;
/* position inside the texture where this glyph is store. */
int offset_x;
@@ -175,8 +206,10 @@ typedef struct FontBLF {
/* angle in radians. */
float angle;
+#if 0 /* BLF_BLUR_ENABLE */
/* blur: 3 or 5 large kernel */
int blur;
+#endif
/* shadow level. */
int shadow;
@@ -186,10 +219,10 @@ typedef struct FontBLF {
int shadow_y;
/* shadow color. */
- float shadow_col[4];
+ unsigned char shadow_color[4];
- /* store color here when drawing shadow or blur. */
- float orig_col[4];
+ /* main text color. */
+ unsigned char color[4];
/* Multiplied this matrix with the current one before
* draw the text! see blf_draw__start.
@@ -212,7 +245,7 @@ typedef struct FontBLF {
int tex_size_max;
/* cache current OpenGL texture to save calls into the API */
- unsigned int tex_bind_state;
+ GPUTexture *tex_bind_state;
/* font options. */
int flags;
@@ -223,6 +256,12 @@ typedef struct FontBLF {
/* current glyph cache, size and dpi. */
GlyphCacheBLF *glyph_cache;
+ /* list of kerning cache for this font. */
+ ListBase kerning_caches;
+
+ /* current kerning cache for this font and kerning mode. */
+ KerningCacheBLF *kerning_cache;
+
/* freetype2 lib handle. */
FT_Library ft_lib;
@@ -232,6 +271,9 @@ typedef struct FontBLF {
/* freetype2 face. */
FT_Face face;
+ /* freetype kerning */
+ FT_UInt kerning_mode;
+
/* data for buffer usage (drawing into a texture buffer) */
FontBufInfoBLF buf_info;
} FontBLF;
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 89f3431fec8..baec7e77328 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -85,18 +85,13 @@ struct CCGKey;
struct MVert;
struct MEdge;
struct MFace;
-struct MTFace;
struct Object;
struct Scene;
struct Mesh;
struct MLoopNorSpaceArray;
struct BMEditMesh;
-struct KeyBlock;
struct ModifierData;
-struct MCol;
-struct ColorBand;
-struct GPUVertexAttribs;
-struct GPUDrawObject;
+struct Depsgraph;
struct PBVH;
/* number of sub-elements each mesh element has (for interpolation) */
@@ -122,40 +117,9 @@ typedef struct DMFlagMat {
typedef enum DerivedMeshType {
DM_TYPE_CDDM,
- DM_TYPE_EDITBMESH,
DM_TYPE_CCGDM
} DerivedMeshType;
-typedef enum DMDrawOption {
- /* the element is hidden or otherwise non-drawable */
- DM_DRAW_OPTION_SKIP = 0,
- /* normal drawing */
- DM_DRAW_OPTION_NORMAL = 1,
- /* draw, but don't set the color from mcol */
- DM_DRAW_OPTION_NO_MCOL = 2,
- /* used in drawMappedFaces, use GL stipple for the face */
- DM_DRAW_OPTION_STIPPLE = 3,
-} DMDrawOption;
-
-/* Drawing callback types */
-typedef int (*DMSetMaterial)(int mat_nr, void *attribs);
-typedef int (*DMCompareDrawOptions)(void *userData, int cur_index, int next_index);
-typedef void (*DMSetDrawInterpOptions)(void *userData, int index, float t);
-typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index);
-typedef DMDrawOption (*DMSetDrawOptionsMappedTex)(void *userData, int origindex, int mat_nr);
-typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTexPoly *mtexpoly, const bool has_vcol, int matnr);
-
-typedef enum DMDrawFlag {
- DM_DRAW_USE_COLORS = (1 << 0),
- DM_DRAW_ALWAYS_SMOOTH = (1 << 1),
- DM_DRAW_USE_ACTIVE_UV = (1 << 2),
- DM_DRAW_USE_TEXPAINT_UV = (1 << 3),
- DM_DRAW_SKIP_HIDDEN = (1 << 4),
- DM_DRAW_SKIP_SELECT = (1 << 5),
- DM_DRAW_SELECT_USE_EDITMODE = (1 << 6),
- DM_DRAW_NEED_NORMALS = (1 << 7)
-} DMDrawFlag;
-
typedef enum DMForeachFlag {
DM_FOREACH_NOP = 0,
DM_FOREACH_USE_NORMAL = (1 << 0), /* foreachMappedVert, foreachMappedLoop, foreachMappedFaceCenter */
@@ -164,14 +128,9 @@ typedef enum DMForeachFlag {
typedef enum DMDirtyFlag {
/* dm has valid tessellated faces, but tessellated CDDATA need to be updated. */
DM_DIRTY_TESS_CDLAYERS = 1 << 0,
- /* One of the MCOL layers have been updated, force updating of GPUDrawObject's colors buffer.
- * This is necessary with modern, VBO draw code, as e.g. in vpaint mode me->mcol may be updated
- * without actually rebuilding dm (hence by default keeping same GPUDrawObject, and same colors
- * buffer, which prevents update during a stroke!). */
- DM_DIRTY_MCOL_UPDATE_DRAW = 1 << 1,
/* check this with modifier dependsOnNormals callback to see if normals need recalculation */
- DM_DIRTY_NORMALS = 1 << 2,
+ DM_DIRTY_NORMALS = 1 << 1,
} DMDirtyFlag;
typedef struct DerivedMesh DerivedMesh;
@@ -182,9 +141,7 @@ struct DerivedMesh {
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
BVHCache *bvhCache;
- struct GPUDrawObject *drawObject;
DerivedMeshType type;
- float auto_bump_scale;
DMDirtyFlag dirty;
int totmat; /* total materials. Will be valid only before object drawing. */
struct Material **mat; /* material array. Will be valid only before object drawing */
@@ -384,117 +341,6 @@ struct DerivedMesh {
*/
struct PBVH *(*getPBVH)(struct Object *ob, DerivedMesh *dm);
- /* Drawing Operations */
-
- /** Draw all vertices as bgl points (no options) */
- void (*drawVerts)(DerivedMesh *dm);
-
- /** Draw edges in the UV mesh (if exists) */
- void (*drawUVEdges)(DerivedMesh *dm);
-
- /** Draw all edges as lines (no options)
- *
- * Also called for *final* editmode DerivedMeshes
- */
- void (*drawEdges)(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges);
-
- /** Draw all loose edges (edges w/ no adjoining faces) */
- void (*drawLooseEdges)(DerivedMesh *dm);
-
- /** Draw all faces
- * o Set face normal or vertex normal based on inherited face flag
- * o Use inherited face material index to call setMaterial
- * o Only if setMaterial returns true
- *
- * Also called for *final* editmode DerivedMeshes
- */
- void (*drawFacesSolid)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
- bool fast, DMSetMaterial setMaterial);
-
- /** Draw all faces using MTFace
- * - Drawing options too complicated to enumerate, look at code.
- */
- void (*drawFacesTex)(DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag);
-
- /** Draw all faces with GLSL materials
- * o setMaterial is called for every different material nr
- * o Only if setMaterial returns true
- */
- void (*drawFacesGLSL)(DerivedMesh *dm, DMSetMaterial setMaterial);
-
- /** Draw mapped faces (no color, or texture)
- * - Only if !setDrawOptions or
- * setDrawOptions(userData, mapped-face-index, r_drawSmooth)
- * returns true
- *
- * If drawSmooth is set to true then vertex normals should be set and
- * glShadeModel called with GL_SMOOTH. Otherwise the face normal should
- * be set and glShadeModel called with GL_FLAT.
- *
- * The setDrawOptions is allowed to not set drawSmooth (for example, when
- * lighting is disabled), in which case the implementation should draw as
- * smooth shaded.
- */
- void (*drawMappedFaces)(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- DMCompareDrawOptions compareDrawOptions,
- void *userData,
- DMDrawFlag flag);
-
- /** Draw mapped faces using MTFace
- * - Drawing options too complicated to enumerate, look at code.
- */
- void (*drawMappedFacesTex)(DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag);
-
- /** Draw mapped faces with GLSL materials
- * - setMaterial is called for every different material nr
- * - setDrawOptions is called for every face
- * - Only if setMaterial and setDrawOptions return true
- */
- void (*drawMappedFacesGLSL)(DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData);
-
- /** Draw mapped edges as lines
- * - Only if !setDrawOptions or setDrawOptions(userData, mapped-edge)
- * returns true
- */
- void (*drawMappedEdges)(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- void *userData);
-
- /** Draw mapped edges as lines with interpolation values
- * - Only if !setDrawOptions or
- * setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t)
- * returns true
- *
- * NOTE: This routine is optional!
- */
- void (*drawMappedEdgesInterp)(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetDrawInterpOptions setDrawInterpOptions,
- void *userData);
-
- /** Draw all faces with materials
- * - setMaterial is called for every different material nr
- * - setFace is called to verify if a face must be hidden
- */
- void (*drawMappedFacesMat)(DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData);
-
- struct GPUDrawObject *(*gpuObjectNew)(DerivedMesh *dm);
- void (*copy_gpu_data)(DerivedMesh *dm, int type, void *varray_p,
- const int *mat_orig_to_new, const void *user_data);
-
/** Release reference to the DerivedMesh. This function decides internally
* if the DerivedMesh will be freed, or cached for later use. */
void (*release)(DerivedMesh *dm);
@@ -526,17 +372,6 @@ int DM_release(DerivedMesh *dm);
*/
void DM_to_mesh(DerivedMesh *dm, struct Mesh *me, struct Object *ob, CustomDataMask mask, bool take_ownership);
-struct BMEditMesh *DM_to_editbmesh(
- struct DerivedMesh *dm,
- struct BMEditMesh *existing, const bool do_tessellate);
-
-/* conversion to bmesh only */
-void DM_to_bmesh_ex(struct DerivedMesh *dm, struct BMesh *bm, const bool calc_face_normal);
-struct BMesh *DM_to_bmesh(struct DerivedMesh *dm, const bool calc_face_normal);
-
-
-/** Utility function to convert a DerivedMesh to a shape key block */
-void DM_to_meshkey(DerivedMesh *dm, struct Mesh *me, struct KeyBlock *kb);
void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask);
@@ -546,19 +381,19 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask);
* freed, see BKE_customdata.h for the different options
*/
void DM_add_vert_layer(
- struct DerivedMesh *dm, int type, int alloctype,
+ struct DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
void DM_add_edge_layer(
- struct DerivedMesh *dm, int type, int alloctype,
+ struct DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
void DM_add_tessface_layer(
- struct DerivedMesh *dm, int type, int alloctype,
+ struct DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
void DM_add_loop_layer(
- DerivedMesh *dm, int type, int alloctype,
+ DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
void DM_add_poly_layer(
- struct DerivedMesh *dm, int type, int alloctype,
+ struct DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
/* custom data access functions
@@ -624,16 +459,8 @@ void DM_free_poly_data(struct DerivedMesh *dm, int index, int count);
void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
void DM_ensure_normals(DerivedMesh *dm);
-void DM_ensure_tessface(DerivedMesh *dm);
void DM_ensure_looptri_data(DerivedMesh *dm);
-void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num);
-
-void DM_update_tessface_data(DerivedMesh *dm);
-void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate);
-
-void DM_update_materials(DerivedMesh *dm, struct Object *ob);
-struct MLoopUV *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr);
void DM_interp_vert_data(
struct DerivedMesh *source, struct DerivedMesh *dest,
@@ -654,8 +481,6 @@ void DM_interp_tessface_data(
float *weights, FaceVertWeight *vert_weights,
int count, int dest_index);
-void DM_swap_tessface_data(struct DerivedMesh *dm, int index, const int *corner_indices);
-
void DM_interp_loop_data(
struct DerivedMesh *source, struct DerivedMesh *dest,
int *src_indices,
@@ -666,146 +491,51 @@ void DM_interp_poly_data(
int *src_indices,
float *weights, int count, int dest_index);
-/* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */
-void vDM_ColorBand_store(const struct ColorBand *coba, const char alert_color[4]);
-
-/* UNUSED */
-#if 0
-/** Simple function to get me->totvert amount of vertices/normals,
- * correctly deformed and subsurfered. Needed especially when vertexgroups are involved.
- * In use now by vertex/weight paint and particles */
-DMCoNo *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob);
-#endif
-void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos);
-/* */
-DerivedMesh *mesh_get_derived_final(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask);
-DerivedMesh *mesh_get_derived_deform(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask);
+void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
DerivedMesh *mesh_create_derived_for_modifier(
- struct Scene *scene, struct Object *ob,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
struct ModifierData *md, int build_shapekey_layers);
DerivedMesh *mesh_create_derived_render(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask);
-
-DerivedMesh *getEditDerivedBMesh(
- struct BMEditMesh *em, struct Object *ob, CustomDataMask data_mask,
- float (*vertexCos)[3]);
-
-DerivedMesh *mesh_create_derived_index_render(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask, int index);
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
/* same as above but wont use render settings */
DerivedMesh *mesh_create_derived(struct Mesh *me, float (*vertCos)[3]);
-DerivedMesh *mesh_create_derived_view(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask);
DerivedMesh *mesh_create_derived_no_deform(
- struct Scene *scene, struct Object *ob,
- float (*vertCos)[3],
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, float (*vertCos)[3],
CustomDataMask dataMask);
DerivedMesh *mesh_create_derived_no_deform_render(
- struct Scene *scene, struct Object *ob,
- float (*vertCos)[3],
- CustomDataMask dataMask);
-/* for gameengine */
-DerivedMesh *mesh_create_derived_no_virtual(
- struct Scene *scene, struct Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask);
-DerivedMesh *mesh_create_derived_physics(
- struct Scene *scene, struct Object *ob, float (*vertCos)[3],
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, float (*vertCos)[3],
CustomDataMask dataMask);
-DerivedMesh *editbmesh_get_derived_base(
- struct Object *ob, struct BMEditMesh *em, CustomDataMask data_mask);
-DerivedMesh *editbmesh_get_derived_cage(
- struct Scene *scene, struct Object *,
+struct Mesh *editbmesh_get_eval_cage(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *,
struct BMEditMesh *em, CustomDataMask dataMask);
-DerivedMesh *editbmesh_get_derived_cage_and_final(
- struct Scene *scene, struct Object *,
+struct Mesh *editbmesh_get_eval_cage_and_final(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *,
struct BMEditMesh *em, CustomDataMask dataMask,
- DerivedMesh **r_final);
-
-DerivedMesh *object_get_derived_final(struct Object *ob, const bool for_render);
+ struct Mesh **r_final);
float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *r_numVerts))[3];
-bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
+bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, bool has_prev_mesh);
void makeDerivedMesh(
- struct Scene *scene, struct Object *ob, struct BMEditMesh *em,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct BMEditMesh *em,
CustomDataMask dataMask, const bool build_shapekey_layers);
-void weight_to_rgb(float r_rgb[3], const float weight);
-/** Update the weight MCOL preview layer.
- * If weights are NULL, use object's active vgroup(s).
- * Else, weights must be an array of weight float values.
- * If indices is NULL, it must be of numVerts length.
- * Else, it must be of num length, as indices, which contains vertices' idx to apply weights to.
- * (other vertices are assumed zero weight).
- */
-void DM_update_weight_mcol(
- struct Object *ob, struct DerivedMesh *dm, int const draw_flag,
- float *weights, int num, const int *indices);
-
-/** convert layers requested by a GLSL material to actually available layers in
- * the DerivedMesh, with both a pointer for arrays and an offset for editmesh */
-typedef struct DMVertexAttribs {
- struct {
- struct MLoopUV *array;
- int em_offset, gl_index, gl_texco, gl_info_index;
- } tface[MAX_MTFACE];
-
- struct {
- struct MLoopCol *array;
- int em_offset, gl_index, gl_info_index;
- } mcol[MAX_MCOL];
-
- struct {
- float (*array)[4];
- int em_offset, gl_index, gl_info_index;
- } tang[MAX_MTFACE];
-
- struct {
- float (*array)[3];
- int em_offset, gl_index, gl_texco, gl_info_index;
- } orco;
-
- int tottface, totmcol, tottang, totorco;
-} DMVertexAttribs;
-
-void DM_vertex_attributes_from_gpu(
- DerivedMesh *dm,
- struct GPUVertexAttribs *gattribs, DMVertexAttribs *attribs);
-
-void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop);
-void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs);
-
-void DM_calc_tangents_names_from_gpu(
- const struct GPUVertexAttribs *gattribs,
- char (*tangent_names)[MAX_NAME], int *tangent_names_count);
void DM_add_named_tangent_layer_for_uv(
CustomData *uv_data, CustomData *tan_data, int numLoopData,
const char *layer_name);
-#define DM_TANGENT_MASK_ORCO (1 << 9)
-void DM_calc_loop_tangents_step_0(
- const CustomData *loopData, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count,
- bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
- char *ract_uv_name, char *rren_uv_name, short *rtangent_mask);
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME],
int tangent_names_count);
-void DM_calc_auto_bump_scale(DerivedMesh *dm);
-/** Set object's bounding box based on DerivedMesh min/max data */
-void DM_set_object_boundbox(struct Object *ob, DerivedMesh *dm);
+void DM_calc_auto_bump_scale(DerivedMesh *dm);
void DM_init_origspace(DerivedMesh *dm);
@@ -818,20 +548,4 @@ void DM_debug_print_cdlayers(CustomData *cdata);
bool DM_is_valid(DerivedMesh *dm);
#endif
-BLI_INLINE int DM_origindex_mface_mpoly(
- const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) ATTR_NONNULL(1);
-
-BLI_INLINE int DM_origindex_mface_mpoly(
- const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i)
-{
- const int j = index_mf_to_mpoly[i];
- return (j != ORIGINDEX_NONE) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : ORIGINDEX_NONE;
-}
-
-struct MVert *DM_get_vert_array(struct DerivedMesh *dm, bool *r_allocated);
-struct MEdge *DM_get_edge_array(struct DerivedMesh *dm, bool *r_allocated);
-struct MLoop *DM_get_loop_array(struct DerivedMesh *dm, bool *r_allocated);
-struct MPoly *DM_get_poly_array(struct DerivedMesh *dm, bool *r_allocated);
-struct MFace *DM_get_tessface_array(struct DerivedMesh *dm, bool *r_allocated);
-
#endif /* __BKE_DERIVEDMESH_H__ */
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index f1858fc18ed..7f4feb6c2d5 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -137,6 +137,8 @@ void action_groups_clear_tempflags(struct bAction *act);
void BKE_pose_channel_free(struct bPoseChannel *pchan);
void BKE_pose_channel_free_ex(struct bPoseChannel *pchan, bool do_id_user);
+void BKE_pose_channel_free_bbone_cache(struct bPoseChannel *pchan);
+
void BKE_pose_channels_free(struct bPose *pose);
void BKE_pose_channels_free_ex(struct bPose *pose, bool do_id_user);
@@ -163,9 +165,6 @@ struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, con
bool BKE_pose_channels_is_valid(const struct bPose *pose);
#endif
-/* Copy the data from the action-pose (src) into the pose */
-void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
-
/* sets constraint flags */
void BKE_pose_update_constraint_flags(struct bPose *pose);
@@ -204,6 +203,7 @@ void BKE_pose_remove_group_index(struct bPose *pose, const int index);
void what_does_obaction(struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe);
/* for proxy */
+void BKE_pose_copyesult_pchan_result(struct bPoseChannel *pchanto, const struct bPoseChannel *pchanfrom);
bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void BKE_pose_rest(struct bPose *pose);
@@ -211,6 +211,7 @@ void BKE_pose_rest(struct bPose *pose);
/* Tag pose for recalc. Also tag all related data to be recalc. */
void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose);
+
#ifdef __cplusplus
};
#endif
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h
index 05717e3c8af..0d8a50c5325 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_anim.h
@@ -35,10 +35,11 @@
struct bAnimVizSettings;
struct bMotionPath;
struct bPoseChannel;
-struct EvaluationContext;
+struct Depsgraph;
struct ListBase;
struct Main;
struct Object;
+struct ParticleSystem;
struct Path;
struct ReportList;
struct Scene;
@@ -48,13 +49,20 @@ struct Scene;
void animviz_settings_init(struct bAnimVizSettings *avs);
+struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
+
void animviz_free_motionpath_cache(struct bMotionPath *mpath);
void animviz_free_motionpath(struct bMotionPath *mpath);
struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan);
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
-void animviz_calc_motionpaths(struct Main *bmain, struct Scene *scene, ListBase *targets);
+void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
+ struct Main *bmain,
+ struct Scene *scene,
+ ListBase *targets,
+ bool restore,
+ bool current_frame_only);
/* ---------------------------------------------------- */
/* Curve Paths */
@@ -66,25 +74,28 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl
/* ---------------------------------------------------- */
/* Dupli-Geometry */
-struct ListBase *object_duplilist_ex(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob, bool update);
-struct ListBase *object_duplilist(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob);
+struct ListBase *object_duplilist(struct Depsgraph *depsgraph, struct Scene *sce, struct Object *ob);
void free_object_duplilist(struct ListBase *lb);
int count_duplilist(struct Object *ob);
-typedef struct DupliExtraData {
- float obmat[4][4];
- unsigned int lay;
-} DupliExtraData;
+typedef struct DupliObject {
+ struct DupliObject *next, *prev;
+ struct Object *ob;
+ float mat[4][4];
+ float orco[3], uv[2];
+
+ short type; /* from Object.transflag */
+ char no_draw;
+
+ /* Persistent identifier for a dupli object, for inter-frame matching of
+ * objects with motion blur, or inter-update matching for syncing. */
+ int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */
-typedef struct DupliApplyData {
- int num_objects;
- DupliExtraData *extra;
-} DupliApplyData;
+ /* Particle this dupli was generated from. */
+ struct ParticleSystem *particle_system;
-DupliApplyData *duplilist_apply(struct Object *ob, struct Scene *scene, struct ListBase *duplilist);
-void duplilist_restore(struct ListBase *duplilist, DupliApplyData *apply_data);
-void duplilist_free_apply_data(DupliApplyData *apply_data);
+ /* Random ID for shading */
+ unsigned int random_id;
+} DupliObject;
#endif
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 40b4bf8e7f5..43618109e91 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -31,22 +31,23 @@
* \author Joshua Leung
*/
-struct ID;
-struct ListBase;
-struct Main;
struct AnimData;
+struct ChannelDriver;
+struct Depsgraph;
struct FCurve;
-struct KeyingSet;
+struct ID;
struct KS_Path;
+struct KeyingSet;
+struct ListBase;
+struct Main;
struct PathResolvedRNA;
-struct bContext;
-
struct PointerRNA;
struct PropertyRNA;
struct ReportList;
+struct Scene;
struct bAction;
struct bActionGroup;
-struct AnimMapper;
+struct bContext;
/* ************************************* */
/* AnimData API */
@@ -68,10 +69,10 @@ bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct b
void BKE_animdata_free(struct ID *id, const bool do_id_user);
/* Copy AnimData */
-struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const bool do_action);
+struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
/* Copy AnimData */
-bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const bool do_action);
+bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const int flag);
/* Copy AnimData Actions */
void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id, const bool set_newid);
@@ -120,7 +121,7 @@ void BKE_keyingsets_free(struct ListBase *list);
/* Path Fixing API */
/* Get a "fixed" version of the given path (oldPath) */
-char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *prefix, const char *oldName,
+char *BKE_animsys_fix_rna_path_rename(struct ID *owner_id, char *old_path, const char *prefix, const char *oldName,
const char *newName, int oldSubscript, int newSubscript, bool verify_paths);
/* Fix all the paths for the given ID + Action */
@@ -133,10 +134,11 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id, struct AnimData *adt, st
bool verify_paths);
/* Fix all the paths for the entire database... */
-void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName);
+void BKE_animdata_fix_paths_rename_all(struct ID *ref_id, const char *prefix, const char *oldName, const char *newName);
-/* Fix the path after removing elements that are not ID (e.g., node) */
-void BKE_animdata_fix_paths_remove(struct ID *id, const char *path);
+/* Fix the path after removing elements that are not ID (e.g., node).
+ * Returen truth if any animation data was affected. */
+bool BKE_animdata_fix_paths_remove(struct ID *id, const char *path);
/* -------------------------------------- */
@@ -151,7 +153,7 @@ char *BKE_animdata_driver_path_hack(struct bContext *C, struct PointerRNA *ptr,
char *base_path);
/* ************************************* */
-/* Batch AnimData API */
+/* GPUBatch AnimData API */
/* Define for callback looper used in BKE_animdata_main_cb */
typedef void (*ID_AnimData_Edit_Callback)(struct ID *id, struct AnimData *adt, void *user_data);
@@ -176,14 +178,13 @@ void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void
/* In general, these ones should be called to do all animation evaluation */
/* Evaluation loop for evaluating animation data */
-void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct AnimData *adt, float ctime, short recalc);
+void BKE_animsys_evaluate_animdata(struct Depsgraph *depsgraph, struct Scene *scene, struct ID *id, struct AnimData *adt, float ctime, short recalc);
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
-void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime);
+void BKE_animsys_evaluate_all_animation(struct Main *main, struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
/* TODO(sergey): This is mainly a temp public function. */
-struct FCurve;
-bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu, float curval);
+bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct FCurve *fcu, float curval);
/* ------------ Specialized API --------------- */
/* There are a few special tools which require these following functions. They are NOT to be used
@@ -194,19 +195,21 @@ bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap
*/
/* Evaluate Action (F-Curve Bag) */
-void animsys_evaluate_action(struct PointerRNA *ptr, struct bAction *act, struct AnimMapper *remap, float ctime);
+void animsys_evaluate_action(struct Depsgraph *depsgraph, struct PointerRNA *ptr, struct bAction *act, float ctime);
/* Evaluate Action Group */
-void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act, struct bActionGroup *agrp, struct AnimMapper *remap, float ctime);
+void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act, struct bActionGroup *agrp, float ctime);
/* ************************************* */
/* ------------ Evaluation API --------------- */
-struct EvaluationContext;
+struct Depsgraph;
+
+void BKE_animsys_eval_animdata(struct Depsgraph *depsgraph, struct ID *id);
+void BKE_animsys_eval_driver(struct Depsgraph *depsgraph, struct ID *id, int driver_index, struct ChannelDriver *driver_orig);
-void BKE_animsys_eval_animdata(struct EvaluationContext *eval_ctx, struct ID *id);
-void BKE_animsys_eval_driver(struct EvaluationContext *eval_ctx, struct ID *id, struct FCurve *fcurve);
+void BKE_animsys_update_driver_array(struct ID *id);
/* ************************************* */
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index ac8f861fa56..6162c7b6bf6 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -23,6 +23,7 @@
/** \file BKE_appdir.h
* \ingroup bli
*/
+struct ListBase;
/* note on naming: typical _get() suffix is omitted here,
* since its the main purpose of the API. */
@@ -35,6 +36,7 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
bool BKE_appdir_app_template_any(void);
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len);
+void BKE_appdir_app_templates(struct ListBase *templates);
/* Initialize path to program executable */
void BKE_appdir_program_path_init(const char *argv0);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index dea5afa1ac2..0e356c1557f 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -33,7 +33,9 @@
* \author nzc
*/
+struct bPose;
struct Bone;
+struct Depsgraph;
struct GHash;
struct Main;
struct bArmature;
@@ -97,17 +99,19 @@ float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3
void BKE_armature_where_is(struct bArmature *arm);
void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion);
void BKE_pose_clear_pointers(struct bPose *pose);
-void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm);
-void BKE_pose_rebuild_ex(struct Object *ob, struct bArmature *arm, const bool sort_bones);
-void BKE_pose_where_is(struct Scene *scene, struct Object *ob);
-void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra);
+void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose);
+void BKE_pchan_rebuild_bbone_handles(struct bPose *pose, struct bPoseChannel *pchan);
+void BKE_pose_rebuild(struct Main *bmain, struct Object *ob, struct bArmature *arm, const bool do_id_user);
+void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra);
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
/* get_objectspace_bone_matrix has to be removed still */
void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], int root, int posed);
void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3]);
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float mat[3][3]);
-void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll);
+void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll);
+void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll);
/* Common Conversions Between Co-ordinate Spaces */
void BKE_armature_mat_world_to_pose(struct Object *ob, float inmat[4][4], float outmat[4][4]);
@@ -117,7 +121,7 @@ void BKE_armature_loc_pose_to_bone(struct bPoseChannel *pchan, const float inloc
void BKE_armature_mat_bone_to_pose(struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]);
void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], float pose_mat[4][4], float arm_mat[4][4]);
-void BKE_armature_mat_pose_to_bone_ex(struct Object *ob, struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]);
+void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, struct Object *ob, struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]);
void BKE_pchan_mat3_to_rot(struct bPoseChannel *pchan, float mat[3][3], bool use_compat);
void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, float mat[4][4], bool use_comat);
@@ -138,8 +142,38 @@ typedef struct Mat4 {
float mat[4][4];
} Mat4;
-void equalize_bbone_bezier(float *data, int desired);
-void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
+typedef struct BBoneSplineParameters {
+ int segments;
+ float length;
+
+ /* Non-uniform scale correction. */
+ bool do_scale;
+ float scale[3];
+
+ /* Handle control bone data. */
+ bool use_prev, prev_bbone;
+ bool use_next, next_bbone;
+
+ float prev_h[3], next_h[3];
+ float prev_mat[4][4], next_mat[4][4];
+
+ /* Control values. */
+ float ease1, ease2;
+ float roll1, roll2;
+ float scaleIn, scaleOut;
+ float curveInX, curveInY, curveOutX, curveOutY;
+} BBoneSplineParameters;
+
+void BKE_pchan_get_bbone_handles(struct bPoseChannel *pchan, struct bPoseChannel **r_prev, struct bPoseChannel **r_next);
+void BKE_pchan_get_bbone_spline_parameters(struct bPoseChannel *pchan, const bool rest, struct BBoneSplineParameters *r_param);
+
+void b_bone_spline_setup(struct bPoseChannel *pchan, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
+
+void BKE_compute_b_bone_handles(const BBoneSplineParameters *param, float h1[3], float *r_roll1, float h2[3], float *r_roll2, bool ease, bool offsets);
+int BKE_compute_b_bone_spline(struct BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]);
+
+void BKE_pchan_cache_bbone_segments(struct bPoseChannel *pchan);
+void BKE_pchan_copy_bbone_segments_cache(struct bPoseChannel *pchan, struct bPoseChannel *pchan_from);
/* like EBONE_VISIBLE */
#define PBONE_VISIBLE(arm, bone) ( \
@@ -151,11 +185,27 @@ void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array
#define PBONE_SELECTABLE(arm, bone) \
(PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE))
+
+/* context.selected_pose_bones */
+#define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan) \
+ for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \
+ if (PBONE_VISIBLE(((bArmature *)(_ob)->data), (_pchan)->bone) && ((_pchan)->bone->flag & BONE_SELECTED)) {
+#define FOREACH_PCHAN_SELECTED_IN_OBJECT_END \
+ } \
+ } ((void)0)
+/* context.visible_pose_bones */
+#define FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN(_ob, _pchan) \
+ for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \
+ if (PBONE_VISIBLE(((bArmature *)(_ob)->data), (_pchan)->bone)) {
+#define FOREACH_PCHAN_VISIBLE_IN_OBJECT_END \
+ } \
+ } ((void)0)
+
+
/* Evaluation helpers */
struct bKinematicConstraint;
struct bPose;
struct bSplineIKConstraint;
-struct EvaluationContext;
struct bPoseChannel *BKE_armature_ik_solver_find_root(
struct bPoseChannel *pchan,
@@ -165,46 +215,86 @@ struct bPoseChannel *BKE_armature_splineik_solver_find_root(
struct bSplineIKConstraint *data);
void BKE_pose_splineik_init_tree(struct Scene *scene, struct Object *ob, float ctime);
-void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
-
-void BKE_pose_eval_init(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-
-void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-
-void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- int pchan_index);
-
-void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- int pchan_index);
-
-void BKE_pose_bone_done(struct EvaluationContext *eval_ctx,
- struct Object *ob,
- int pchan_index);
-
-void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- int rootchan_index);
-
-void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- int rootchan_index);
-
-void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-
-void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx,
- struct Object *ob);
+void BKE_splineik_execute_tree(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
+
+void BKE_pose_eval_init(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
+
+void BKE_pose_eval_init_ik(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
+
+void BKE_pose_eval_bone(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int pchan_index);
+
+void BKE_pose_constraints_evaluate(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int pchan_index);
+
+void BKE_pose_bone_done(
+ struct Depsgraph *depsgraph,
+ struct Object *ob,
+ int pchan_index);
+
+void BKE_pose_eval_bbone_segments(
+ struct Depsgraph *depsgraph,
+ struct Object *ob,
+ int pchan_index);
+
+void BKE_pose_iktree_evaluate(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int rootchan_index);
+
+void BKE_pose_splineik_evaluate(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int rootchan_index);
+
+void BKE_pose_eval_done(
+ struct Depsgraph *depsgraph,
+ struct Object *object);
+
+void BKE_pose_eval_cleanup(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
+
+void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph,
+ struct Object *object);
+void BKE_pose_eval_proxy_done(struct Depsgraph *depsgraph,
+ struct Object *object);
+void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph,
+ struct Object *object);
+
+void BKE_pose_eval_proxy_copy_bone(
+ struct Depsgraph *depsgraph,
+ struct Object *object,
+ int pchan_index);
+
+/* BBOne deformation cache.
+ *
+ * The idea here is to pre-calculate deformation queternions, matricies and such
+ * used by armature_deform_verts().
+ */
+struct ObjectBBoneDeform;
+struct ObjectBBoneDeform * BKE_armature_cached_bbone_deformation_get(
+ struct Object *object);
+void BKE_armature_cached_bbone_deformation_free_data(struct Object *object);
+void BKE_armature_cached_bbone_deformation_free(struct Object *object);
+void BKE_armature_cached_bbone_deformation_update(struct Object *object);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_blender_user_menu.h b/source/blender/blenkernel/BKE_blender_user_menu.h
new file mode 100644
index 00000000000..ff314314646
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blender_user_menu.h
@@ -0,0 +1,49 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_BLENDER_USER_MENU_H__
+#define __BKE_BLENDER_USER_MENU_H__
+
+/** \file BKE_blender_user_menu.h
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ListBase;
+struct bUserMenu;
+struct bUserMenuItem;
+
+struct bUserMenu *BKE_blender_user_menu_find(
+ struct ListBase *lb, char space_type, const char *context);
+struct bUserMenu *BKE_blender_user_menu_ensure(
+ struct ListBase *lb, char space_type, const char *context);
+
+struct bUserMenuItem *BKE_blender_user_menu_item_add(struct ListBase *lb, int type);
+void BKE_blender_user_menu_item_free(struct bUserMenuItem *umi);
+void BKE_blender_user_menu_item_free_list(struct ListBase *lb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_BLENDER_USER_MENU_H__ */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 16115203294..3415a57a740 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,17 +27,17 @@
/* these lines are grep'd, watch out for our not-so-awesome regex
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
-#define BLENDER_VERSION 279
-#define BLENDER_SUBVERSION 6
-/* Several breakages with 270, e.g. constraint deg vs rad */
-#define BLENDER_MINVERSION 270
-#define BLENDER_MINSUBVERSION 6
+#define BLENDER_VERSION 280
+#define BLENDER_SUBVERSION 35
+/* Several breakages with 280, e.g. collections vs layers */
+#define BLENDER_MINVERSION 280
+#define BLENDER_MINSUBVERSION 0
/* used by packaging tools */
/* can be left blank, otherwise a,b,c... etc with no quotes */
#define BLENDER_VERSION_CHAR
/* alpha/beta/rc/release, docs use this */
-#define BLENDER_VERSION_CYCLE alpha
+#define BLENDER_VERSION_CYCLE beta
extern char versionstr[]; /* from blender.c */
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 74fdde93d9a..e272fcaa3ec 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -65,6 +65,13 @@ struct UserDef *BKE_blendfile_userdef_read_from_memory(
bool BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports);
bool BKE_blendfile_userdef_write_app_template(const char *filepath, struct ReportList *reports);
+struct WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(
+ const char *filepath,
+ const void *filebuf, int filelength,
+ struct ReportList *reports);
+bool BKE_blendfile_workspace_config_write(struct Main *bmain, const char *filepath, struct ReportList *reports);
+void BKE_blendfile_workspace_config_data_free(struct WorkspaceConfigFileData *workspace_config);
+
/* partial blend file writing */
void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
diff --git a/source/blender/blenkernel/BKE_bmfont.h b/source/blender/blenkernel/BKE_bmfont.h
deleted file mode 100644
index 3be84c83892..00000000000
--- a/source/blender/blenkernel/BKE_bmfont.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_BMFONT_H__
-#define __BKE_BMFONT_H__
-
-/** \file BKE_bmfont.h
- * \ingroup bke
- * \since March 2001
- * \author nzc
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct bmGlyph;
-struct ImBuf;
-struct bmFont;
-
-void printfGlyph(struct bmGlyph *glyph);
-void calcAlpha(struct ImBuf *ibuf);
-void readBitmapFontVersion0(struct ImBuf *ibuf,
- unsigned char *rect,
- int step);
-void detectBitmapFont(struct ImBuf *ibuf);
-int locateGlyph(struct bmFont *bmfont, unsigned short unicode);
-void matrixGlyph(struct ImBuf *ibuf, unsigned short unicode,
- float *centerx, float *centery,
- float *sizex, float *sizey,
- float *transx, float *transy,
- float *movex, float *movey, float *advance);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 9fc399c428f..91743bfa567 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -28,12 +28,17 @@
*/
enum eCurveMappingPreset;
+struct bContext;
struct Brush;
+struct Paint;
struct ImBuf;
struct ImagePool;
struct Main;
struct Scene;
+struct ToolSettings;
struct UnifiedPaintSettings;
+struct Material;
+
// enum eCurveMappingPreset;
#include "DNA_object_enums.h"
@@ -45,14 +50,17 @@ void BKE_brush_system_exit(void);
/* datablock functions */
void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode);
+struct Brush *BKE_brush_add_gpencil(struct Main *bmain, struct ToolSettings *ts, const char *name);
+void BKE_brush_init_gpencil_settings(struct Brush *brush);
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode);
void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag);
struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local);
-void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
+void BKE_brush_gpencil_presets(struct bContext *C);
+void BKE_brush_update_material(struct Main *bmain, struct Material *ma, struct Brush *exclude_brush);
/* image icon function */
struct ImBuf *get_brush_icon(struct Brush *brush);
@@ -117,6 +125,14 @@ void BKE_brush_scale_size(
float new_unprojected_radius,
float old_unprojected_radius);
+/* Accessors */
+#define BKE_brush_tool_get(brush, p) \
+ (CHECK_TYPE_ANY(brush, struct Brush *, const struct Brush *), \
+ *(const char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset))
+#define BKE_brush_tool_set(brush, p, tool) { \
+ CHECK_TYPE_ANY(brush, struct Brush *); \
+ *(char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset) = tool; } ((void)0)
+
/* debugging only */
void BKE_brush_debug_print_state(struct Brush *br);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index c6057442fec..018f535a4cb 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -40,6 +40,7 @@
struct DerivedMesh;
struct BMEditMesh;
+struct Mesh;
struct MVert;
struct MFace;
@@ -101,7 +102,7 @@ typedef struct BVHTreeFromMesh {
*/
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
- float epsilon, int tree_type, int axis);
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache);
BVHTree *bvhtree_from_editmesh_verts_ex(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
const BLI_bitmap *mask, int verts_num_active,
@@ -114,7 +115,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
- float epsilon, int tree_type, int axis);
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache);
BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
const BLI_bitmap *edges_mask, int edges_num_active,
@@ -150,8 +151,8 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
const BLI_bitmap *mask, int looptri_num_active,
float epsilon, int tree_type, int axis);
-BVHTree *bvhtree_from_mesh_get(
- struct BVHTreeFromMesh *data, struct DerivedMesh *mesh,
+BVHTree *BKE_bvhtree_from_mesh_get(
+ struct BVHTreeFromMesh *data, struct Mesh *mesh,
const int type, const int tree_type);
/**
@@ -182,14 +183,18 @@ enum {
BVHTREE_FROM_FACES = 2,
BVHTREE_FROM_LOOPTRI = 3,
- BVHTREE_FROM_EM_LOOPTRI = 4,
+ BVHTREE_FROM_LOOSEVERTS = 4,
+ BVHTREE_FROM_LOOSEEDGES = 5,
+
+ BVHTREE_FROM_EM_VERTS = 6,
+ BVHTREE_FROM_EM_EDGES = 7,
+ BVHTREE_FROM_EM_LOOPTRI = 8,
};
-BVHTree *bvhcache_find(BVHCache *cache, int type);
+bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree);
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type);
-void bvhcache_init(BVHCache **cache_p);
void bvhcache_free(BVHCache **cache_p);
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index e9712681090..43768b67f8f 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -35,6 +35,7 @@ extern "C" {
#endif
struct CacheFile;
+struct Depsgraph;
struct Main;
struct Scene;
@@ -57,7 +58,7 @@ 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, const float ctime, const float fps);
+void BKE_cachefile_update_frame(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, const float ctime, const float fps);
bool BKE_cachefile_filepath_get(
const struct Main *bmain, const struct CacheFile *cache_file, float frame,
@@ -65,7 +66,7 @@ bool BKE_cachefile_filepath_get(
float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
-void BKE_cachefile_clean(struct Scene *scene, struct CacheFile *cache_file);
+void BKE_cachefile_clean(struct Main *bmain, struct CacheFile *cache_file);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 8eb8ef22b49..d8e2139be83 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -39,11 +39,13 @@ extern "C" {
#include "DNA_vec_types.h"
struct Camera;
+struct Depsgraph;
struct Main;
struct Object;
struct RegionView3D;
struct RenderData;
struct Scene;
+struct ViewLayer;
struct rctf;
struct View3D;
struct GPUFXSettings;
@@ -60,7 +62,6 @@ void BKE_camera_free(struct Camera *ca);
/* Camera Usage */
float BKE_camera_object_dof_distance(struct Object *ob);
-void BKE_camera_object_mode(struct RenderData *rd, struct Object *ob);
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey);
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y);
@@ -91,11 +92,6 @@ typedef struct CameraParams {
float clipsta;
float clipend;
- /* fields */
- int use_fields;
- int field_second;
- int field_odd;
-
/* computed viewplane */
float ycor;
float viewdx;
@@ -112,7 +108,7 @@ typedef struct CameraParams {
void BKE_camera_params_init(CameraParams *params);
void BKE_camera_params_from_object(CameraParams *params, const struct Object *camera);
-void BKE_camera_params_from_view3d(CameraParams *params, const struct View3D *v3d, const struct RegionView3D *rv3d);
+void BKE_camera_params_from_view3d(CameraParams *params, struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d);
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy);
void BKE_camera_params_compute_matrix(CameraParams *params);
@@ -128,12 +124,13 @@ void BKE_camera_view_frame(
float r_vec[4][3]);
bool BKE_camera_view_frame_fit_to_scene(
- struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct Object *camera_ob,
+ struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *camera_ob,
float r_co[3], float *r_scale);
bool BKE_camera_view_frame_fit_to_coords(
- const struct Scene *scene,
+ const struct Depsgraph *depsgraph,
const float (*cos)[3], int num_cos,
- const struct Object *camera_ob,
+ struct Object *camera_ob,
float r_co[3], float *r_scale);
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings);
@@ -141,11 +138,16 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set
/* Camera multi-view API */
struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname);
-void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]);
-void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]);
-float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname);
-void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname);
-bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, struct Object *camera);
+void BKE_camera_multiview_view_matrix(struct RenderData *rd, const struct Object *camera, const bool is_left, float r_viewmat[4][4]);
+void BKE_camera_multiview_model_matrix(struct RenderData *rd, const struct Object *camera, const char *viewname, float r_modelmat[4][4]);
+float BKE_camera_multiview_shift_x(struct RenderData *rd, const struct Object *camera, const char *viewname);
+void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, const struct Object *camera, const char *viewname);
+bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, const struct Object *camera);
+
+/* Camera background image API */
+struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam);
+void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic);
+void BKE_camera_background_image_clear(struct Camera *cam);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 761b679983d..f2c0b96aa80 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -36,6 +36,7 @@
#define __BKE_CDDERIVEDMESH_H__
#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
struct DerivedMesh;
struct BMEditMesh;
@@ -53,20 +54,15 @@ struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces,
* data to not overwrite the original */
struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh);
+/* creates a CDDerivedMesh from the given Mesh with custom allocation type. */
+struct DerivedMesh *CDDM_from_mesh_ex(struct Mesh *mesh, eCDAllocType alloctype, CustomDataMask mask);
+
+
struct DerivedMesh *CDDM_from_bmesh(struct BMesh *bm, const bool use_mdisps);
/* creates a CDDerivedMesh from the given BMEditMesh */
DerivedMesh *CDDM_from_editbmesh(struct BMEditMesh *em, const bool use_mdisps, const bool use_tessface);
-/* merge verts */
-/* Enum for merge_mode of CDDM_merge_verts.
- * Refer to cdderivedmesh.c for details. */
-enum {
- CDDM_MERGE_VERTS_DUMP_IF_MAPPED,
- CDDM_MERGE_VERTS_DUMP_IF_EQUAL,
-};
-DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode);
-
/* creates a CDDerivedMesh from the given curve object */
struct DerivedMesh *CDDM_from_curve(struct Object *ob);
@@ -78,8 +74,6 @@ DerivedMesh *CDDM_from_curve_displist(struct Object *ob, struct ListBase *dispba
* custom element data.
*/
struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
-struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm);
-struct DerivedMesh *CDDM_copy_with_tessface(struct DerivedMesh *dm);
/* creates a CDDerivedMesh with the same layer stack configuration as the
* given DerivedMesh and containing the requested numbers of elements.
@@ -95,11 +89,6 @@ struct DerivedMesh *CDDM_from_template(
int numVerts, int numEdges, int numFaces,
int numLoops, int numPolys);
-/* converts mfaces to mpolys. note things may break if there are not valid
- * medges surrounding each mface.
- */
-void CDDM_tessfaces_to_faces(struct DerivedMesh *dm);
-
/* applies vertex coordinates or normals to a CDDerivedMesh. if the MVert
* layer is a referenced layer, it will be duplicate to not overwrite the
* original
@@ -112,22 +101,11 @@ void CDDM_apply_vert_normals(struct DerivedMesh *cddm, short (*vertNormals)[3]);
void CDDM_calc_normals_mapping_ex(struct DerivedMesh *dm, const bool only_face_normals);
void CDDM_calc_normals_mapping(struct DerivedMesh *dm);
void CDDM_calc_normals(struct DerivedMesh *dm);
-void CDDM_calc_normals_tessface(struct DerivedMesh *dm);
void CDDM_calc_loop_normals(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle);
void CDDM_calc_loop_normals_spacearr(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle,
struct MLoopNorSpaceArray *r_lnors_spacearr);
-/* calculates edges for a CDDerivedMesh (from face data)
- * this completely replaces the current edge data in the DerivedMesh
- * builds edges from the tessellated face data.
- */
-void CDDM_calc_edges_tessface(struct DerivedMesh *dm);
-
-/* same as CDDM_calc_edges_tessface only makes edges from ngon faces instead of tessellation
- * faces*/
-void CDDM_calc_edges(struct DerivedMesh *dm);
-
/* reconstitute face triangulation */
void CDDM_recalc_tessellation(struct DerivedMesh *dm);
void CDDM_recalc_tessellation_ex(struct DerivedMesh *dm, const bool do_face_nor_cpy);
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 6b76ec33c06..87094e77953 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -37,10 +37,11 @@
struct Object;
struct Scene;
+struct Mesh;
struct MFace;
-struct DerivedMesh;
struct ClothModifierData;
struct CollisionModifierData;
+struct Depsgraph;
#define DO_INLINE MALWAYS_INLINE
@@ -116,6 +117,7 @@ typedef struct ClothVertex {
float goal; /* goal, from SB */
float impulse[3]; /* used in collision.c */
float xrest[3]; /* rest position of the vertex */
+ float dcvel[3]; /* delta velocities to be applied by collision response */
unsigned int impulse_count; /* same as above */
float avg_spring_len; /* average length of connected springs */
float struct_stiff;
@@ -132,11 +134,17 @@ ClothVertex;
typedef struct ClothSpring {
int ij; /* Pij from the paper, one end of the spring. */
int kl; /* Pkl from the paper, one end of the spring. */
- int mn;
- float restlen; /* The original length of the spring. */
- int type; /* types defined in BKE_cloth.h ("springType") */
- int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */
- float stiffness; /* stiffness factor from the vertex groups */
+ int mn; /* For hair springs: third vertex index; For bending springs: edge index; */
+ int *pa; /* Array of vert indices for poly a (for bending springs). */
+ int *pb; /* Array of vert indices for poly b (for bending springs). */
+ int la; /* Length of *pa. */
+ int lb; /* Length of *pb. */
+ float restlen; /* The original length of the spring. */
+ float restang; /* The original angle of the bending springs. */
+ int type; /* Types defined in BKE_cloth.h ("springType"). */
+ int flags; /* Defined in BKE_cloth.h, e.g. deactivated due to tearing. */
+ float lin_stiffness; /* Linear stiffness factor from the vertex groups. */
+ float ang_stiffness; /* Angular stiffness factor from the vertex groups. */
float editrestlen;
/* angular bending spring target and derivatives */
@@ -162,15 +170,21 @@ ClothSpring;
/* These are the bits used in SimSettings.flags. */
typedef enum {
CLOTH_SIMSETTINGS_FLAG_COLLOBJ = ( 1 << 2 ),// object is only collision object, no cloth simulation is done
- CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled
+ CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), /* DEPRECATED, for versioning only. */
CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ),// true if tearing is enabled
- CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* is advanced scaling active? */
+ CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* DEPRECATED, for versioning only. */
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_RESIST_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;
+/* ClothSimSettings.bending_model. */
+typedef enum {
+ CLOTH_BENDING_LINEAR = 0,
+ CLOTH_BENDING_ANGULAR = 1,
+} CLOTH_BENDING_MODEL;
+
/* COLLISION FLAGS */
typedef enum {
CLOTH_COLLSETTINGS_FLAG_ENABLED = ( 1 << 1 ), /* enables cloth - object collisions */
@@ -179,12 +193,12 @@ typedef enum {
/* Spring types as defined in the paper.*/
typedef enum {
- CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1),
- CLOTH_SPRING_TYPE_SHEAR = (1 << 2),
- CLOTH_SPRING_TYPE_BENDING = (1 << 3),
- CLOTH_SPRING_TYPE_GOAL = (1 << 4),
- CLOTH_SPRING_TYPE_SEWING = (1 << 5),
- CLOTH_SPRING_TYPE_BENDING_ANG = (1 << 6),
+ CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1),
+ CLOTH_SPRING_TYPE_SHEAR = (1 << 2),
+ CLOTH_SPRING_TYPE_BENDING = (1 << 3),
+ CLOTH_SPRING_TYPE_GOAL = (1 << 4),
+ CLOTH_SPRING_TYPE_SEWING = (1 << 5),
+ CLOTH_SPRING_TYPE_BENDING_HAIR = (1 << 6),
} CLOTH_SPRING_TYPES;
/* SPRING FLAGS */
@@ -209,10 +223,9 @@ typedef struct ColliderContacts {
} ColliderContacts;
// needed for implicit.c
-int cloth_bvh_objcollision (struct Object *ob, struct ClothModifierData *clmd, float step, float dt );
-int cloth_points_objcollision(struct Object *ob, struct ClothModifierData *clmd, float step, float dt);
+int cloth_bvh_collision(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt);
-void cloth_find_point_contacts(struct Object *ob, struct ClothModifierData *clmd, float step, float dt,
+void cloth_find_point_contacts(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt,
ColliderContacts **r_collider_contacts, int *r_totcolliders);
void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders);
@@ -226,16 +239,18 @@ void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders);
void cloth_free_modifier_extern (struct ClothModifierData *clmd );
void cloth_free_modifier (struct ClothModifierData *clmd );
void cloth_init (struct ClothModifierData *clmd );
-void clothModifier_do (struct ClothModifierData *clmd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3]);
+void clothModifier_do(
+ struct ClothModifierData *clmd, struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct Mesh *me, float (*vertexCos)[3]);
int cloth_uses_vgroup(struct ClothModifierData *clmd);
// needed for collision.c
-void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
-void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
+void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving, bool self);
// needed for button_object.c
-void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr );
+void cloth_clear_cache(
+ struct Object *ob, struct ClothModifierData *clmd, float framenr );
void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]);
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
new file mode 100644
index 00000000000..d78133499ce
--- /dev/null
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -0,0 +1,200 @@
+/*
+ * ***** 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): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_COLLECTION_H__
+#define __BKE_COLLECTION_H__
+
+/** \file blender/blenkernel/BKE_collection.h
+ * \ingroup bke
+ */
+
+#include "BLI_compiler_compat.h"
+#include "BLI_ghash.h"
+#include "BLI_iterator.h"
+#include "DNA_listBase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Structs */
+
+struct Base;
+struct BLI_Iterator;
+struct Collection;
+struct Depsgraph;
+struct ID;
+struct Main;
+struct Object;
+struct Scene;
+struct ViewLayer;
+
+typedef struct CollectionParent {
+ struct CollectionParent *next, *prev;
+ struct Collection *collection;
+} CollectionParent;
+
+/* Collections */
+
+struct Collection *BKE_collection_add(struct Main *bmain, struct Collection *parent, const char *name);
+void BKE_collection_free(struct Collection *collection);
+bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy);
+
+struct Collection *BKE_collection_copy(struct Main *bmain, struct Collection *parent, struct Collection *collection);
+struct Collection *BKE_collection_copy_master(struct Main *bmain, struct Collection *collection, const int flag);
+void BKE_collection_copy_data(struct Main *bmain, struct Collection *collection_dst, const struct Collection *collection_src, const int flag);
+void BKE_collection_copy_full(struct Main *bmain, struct Collection *collection);
+void BKE_collection_make_local(struct Main *bmain, struct Collection *collection, const bool lib_local);
+
+/* Master Collection for Scene */
+
+struct Collection *BKE_collection_master(const struct Scene *scene);
+struct Collection *BKE_collection_master_add(void);
+
+/* Collection Objects */
+
+bool BKE_collection_has_object(struct Collection *collection, struct Object *ob);
+bool BKE_collection_has_object_recursive(struct Collection *collection, struct Object *ob);
+struct Collection *BKE_collection_object_find(struct Main *bmain, struct Collection *collection, struct Object *ob);
+bool BKE_collection_is_empty(struct Collection *collection);
+
+bool BKE_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *ob);
+void BKE_collection_object_add_from(struct Main *bmain, struct Scene *scene, struct Object *ob_src, struct Object *ob_dst);
+bool BKE_collection_object_remove(struct Main *bmain, struct Collection *collection, struct Object *object, const bool free_us);
+void BKE_collection_object_move(struct Main *bmain, struct Scene *scene, struct Collection *collection_dst, struct Collection *collection_src, struct Object *ob);
+
+bool BKE_scene_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, const bool free_us);
+void BKE_collections_object_remove_nulls(struct Main *bmain);
+void BKE_collections_child_remove_nulls(struct Main *bmain, struct Collection *old_collection);
+
+/* Dependencies. */
+
+bool BKE_collection_is_in_scene(struct Collection *collection);
+void BKE_collections_after_lib_link(struct Main *bmain);
+bool BKE_collection_object_cyclic_check(struct Main *bmain, struct Object *object, struct Collection *collection);
+
+/* Object list cache. */
+
+struct ListBase BKE_collection_object_cache_get(struct Collection *collection);
+void BKE_collection_object_cache_free(struct Collection *collection);
+
+struct Base *BKE_collection_or_layer_objects(const struct ViewLayer *view_layer, struct Collection *collection);
+
+/* Editing. */
+
+struct Collection *BKE_collection_from_index(struct Scene *scene, const int index);
+void BKE_collection_new_name_get(struct Collection *collection_parent, char *rname);
+const char *BKE_collection_ui_name_get(struct Collection *collection);
+bool BKE_collection_objects_select(struct ViewLayer *view_layer, struct Collection *collection, bool deselect);
+
+/* Collection children */
+
+bool BKE_collection_child_add(struct Main *bmain,
+ struct Collection *parent,
+ struct Collection *child);
+
+bool BKE_collection_child_remove(struct Main *bmain,
+ struct Collection *parent,
+ struct Collection *child);
+
+bool BKE_collection_move(struct Main *bmain,
+ struct Collection *to_parent,
+ struct Collection *from_parent,
+ struct Collection *relative,
+ bool relative_after,
+ struct Collection *collection);
+
+bool BKE_collection_find_cycle(struct Collection *new_ancestor,
+ struct Collection *collection);
+
+
+/* Iteration callbacks. */
+
+typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data);
+typedef void (*BKE_scene_collections_Cb)(struct Collection *ob, void *data);
+
+void BKE_scene_collections_callback(struct Scene *scene, BKE_scene_collections_Cb callback, void *data);
+void BKE_scene_objects_callback(struct Scene *scene, BKE_scene_objects_Cb callback, void *data);
+
+/* Iteratorion over objects in collection. */
+
+#define FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(_collection, _object, _mode) \
+ { \
+ int _base_flag = (_mode == DAG_EVAL_VIEWPORT) ? \
+ BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER; \
+ int _base_id = 0; \
+ for (Base *_base = (Base*)BKE_collection_object_cache_get(_collection).first; \
+ _base; \
+ _base = _base->next, _base_id++) \
+ { \
+ if (_base->flag & _base_flag) { \
+ Object *_object = _base->object; \
+
+#define FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END \
+ } \
+ } \
+ }
+
+#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object) \
+ for (Base *_base = (Base*)BKE_collection_object_cache_get(_collection).first; \
+ _base; \
+ _base = _base->next) \
+ { \
+ Object *_object = _base->object; \
+ BLI_assert(_object != NULL);
+
+#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END \
+ } ((void)0)
+
+/* Iteration over collections in scene. */
+
+void BKE_scene_collections_iterator_begin(struct BLI_Iterator *iter, void *data_in);
+void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter);
+void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter);
+
+void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in);
+void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter);
+void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
+
+#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance) \
+ ITER_BEGIN(BKE_scene_collections_iterator_begin, \
+ BKE_scene_collections_iterator_next, \
+ BKE_scene_collections_iterator_end, \
+ scene, Collection *, _instance)
+
+#define FOREACH_SCENE_COLLECTION_END \
+ ITER_END
+
+#define FOREACH_SCENE_OBJECT_BEGIN(scene, _instance) \
+ ITER_BEGIN(BKE_scene_objects_iterator_begin, \
+ BKE_scene_objects_iterator_next, \
+ BKE_scene_objects_iterator_end, \
+ scene, Object *, _instance)
+
+#define FOREACH_SCENE_OBJECT_END \
+ ITER_END
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_COLLECTION_H__ */
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index 98dc7d69c0d..9bd1f5385da 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -44,11 +44,12 @@
#include "BLI_kdopbvh.h"
struct CollisionModifierData;
-struct Group;
+struct Collection;
struct MFace;
struct MVert;
struct Object;
struct Scene;
+struct Depsgraph;
struct MVertTri;
////////////////////////////////////////
@@ -62,6 +63,7 @@ typedef enum {
COLLISION_USE_COLLFACE = (1 << 2),
COLLISION_IS_EDGES = (1 << 3),
#endif
+ COLLISION_INACTIVE = (1 << 4),
} COLLISION_FLAGS;
@@ -72,7 +74,7 @@ typedef enum {
typedef struct CollPair {
unsigned int face1; // cloth face
unsigned int face2; // object face
- double distance; // magnitude of vector
+ float distance;
float normal[3];
float vector[3]; // unnormalized collision vector: p2-p1
float pa[3], pb[3]; // collision point p1 on face1, p2 on face2
@@ -143,14 +145,29 @@ void collision_move_object(struct CollisionModifierData *collmd, float step, flo
void collision_get_collider_velocity(float vel_old[3], float vel_new[3], struct CollisionModifierData *collmd, struct CollPair *collpair);
-/////////////////////////////////////////////////
-// used in effect.c
-/////////////////////////////////////////////////
-/* explicit control over layer mask and dupli recursion */
-struct Object **get_collisionobjects_ext(struct Scene *scene, struct Object *self, struct Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli);
+/* Collision relations for dependency graph build. */
+
+typedef struct CollisionRelation {
+ struct CollisionRelation *next, *prev;
+ struct Object *ob;
+} CollisionRelation;
+
+struct ListBase *BKE_collision_relations_create(
+ struct Depsgraph *depsgraph,
+ struct Collection *collection,
+ unsigned int modifier_type);
+void BKE_collision_relations_free(struct ListBase *relations);
+
+/* Collision object lists for physics simulation evaluation. */
-struct Object **get_collisionobjects(struct Scene *scene, struct Object *self, struct Group *group, unsigned int *numcollobj, unsigned int modifier_type);
+struct Object **BKE_collision_objects_create(
+ struct Depsgraph *depsgraph,
+ struct Object *self,
+ struct Collection *collection,
+ unsigned int *numcollobj,
+ unsigned int modifier_type);
+void BKE_collision_objects_free(struct Object **objects);
typedef struct ColliderCache {
struct ColliderCache *next, *prev;
@@ -158,8 +175,11 @@ typedef struct ColliderCache {
struct CollisionModifierData *collmd;
} ColliderCache;
-struct ListBase *get_collider_cache(struct Scene *scene, struct Object *self, struct Group *group);
-void free_collider_cache(struct ListBase **colliders);
+struct ListBase *BKE_collider_cache_create(
+ struct Depsgraph *scene,
+ struct Object *self,
+ struct Collection *collection);
+void BKE_collider_cache_free(struct ListBase **colliders);
/////////////////////////////////////////////////
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 293ac30f0f9..bfcdcb68c4a 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -40,6 +40,7 @@ struct ListBase;
struct Object;
struct Scene;
struct bPoseChannel;
+struct Depsgraph;
/* ---------------------------------------------------------------------------- */
#ifdef __cplusplus
@@ -48,6 +49,7 @@ extern "C" {
/* special struct for use in constraint evaluation */
typedef struct bConstraintOb {
+ struct Depsgraph *depsgraph;/* to get evaluated armature. */
struct Scene *scene; /* for system time, part of deglobalization, code nicer later with local time (ton) */
struct Object *ob; /* if pchan, then armature that it comes from, otherwise constraint owner */
struct bPoseChannel *pchan; /* pose channel that owns the constraints being evaluated */
@@ -104,7 +106,7 @@ typedef struct bConstraintTypeInfo {
/* evaluation */
/* set the ct->matrix for the given constraint target (at the given ctime) */
- void (*get_target_matrix)(struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime);
+ void (*get_target_matrix)(struct Depsgraph *depsgraph, struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime);
/* evaluate the constraint for the given time */
void (*evaluate_constraint)(struct bConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
} bConstraintTypeInfo;
@@ -119,6 +121,8 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
/* Constraint function prototypes */
void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
+struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src, const int flag, const bool do_extern);
+
void BKE_constraints_free(struct ListBase *list);
void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user);
void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern);
@@ -127,11 +131,15 @@ void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void
void BKE_constraint_free_data(struct bConstraint *con);
void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user);
+bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *ct);
+
/* Constraint API function prototypes */
struct bConstraint *BKE_constraints_active_get(struct ListBase *list);
void BKE_constraints_active_set(ListBase *list, struct bConstraint *con);
struct bConstraint *BKE_constraints_find_name(struct ListBase *list, const char *name);
+struct bConstraint *BKE_constraint_find_from_target(struct Object *ob, struct bConstraintTarget *tgt, struct bPoseChannel **r_pchan);
+
struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type);
struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob, struct bPoseChannel *pchan, const char *name, short type);
@@ -143,15 +151,16 @@ void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *s
bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan);
/* Constraint Evaluation function prototypes */
-struct bConstraintOb *BKE_constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype);
+struct bConstraintOb *BKE_constraints_make_evalob(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, void *subdata, short datatype);
void BKE_constraints_clear_evalob(struct bConstraintOb *cob);
void BKE_constraint_mat_convertspace(
struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale);
-void BKE_constraint_target_matrix_get(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime);
-void BKE_constraint_targets_for_solving_get(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime);
-void BKE_constraints_solve(struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
+void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, struct Scene *scene, struct bConstraint *con,
+ int n, short ownertype, void *ownerdata, float mat[4][4], float ctime);
+void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime);
+void BKE_constraints_solve(struct Depsgraph *depsgraph, struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 4db365b7307..798150aee3c 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -40,15 +40,21 @@ extern "C" {
struct ARegion;
struct bScreen;
struct CacheFile;
+struct Collection;
+struct Depsgraph;
+struct LayerCollection;
struct ListBase;
struct Main;
struct Object;
+struct Base;
struct PointerRNA;
struct ReportList;
struct Scene;
+struct ViewLayer;
struct ScrArea;
struct SpaceLink;
struct View3D;
+struct ViewRender;
struct RegionView3D;
struct StructRNA;
struct ToolSettings;
@@ -59,16 +65,17 @@ struct bPoseChannel;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
-struct bGPDpalette;
-struct bGPDpalettecolor;
-struct bGPDbrush;
+struct Brush;
struct wmWindow;
struct wmWindowManager;
+struct RenderEngineType;
struct SpaceText;
struct SpaceImage;
struct SpaceClip;
struct ID;
+#include "DNA_object_enums.h"
+
/* Structs */
struct bContext;
@@ -96,7 +103,7 @@ typedef struct bContextStore {
/* for the context's rna mode enum
* keep aligned with data_mode_strings in context.c */
-enum {
+enum eContextObjectMode {
CTX_MODE_EDIT_MESH = 0,
CTX_MODE_EDIT_CURVE,
CTX_MODE_EDIT_SURFACE,
@@ -110,8 +117,13 @@ enum {
CTX_MODE_PAINT_VERTEX,
CTX_MODE_PAINT_TEXTURE,
CTX_MODE_PARTICLE,
- CTX_MODE_OBJECT
+ CTX_MODE_OBJECT,
+ CTX_MODE_GPENCIL_PAINT,
+ CTX_MODE_GPENCIL_EDIT,
+ CTX_MODE_GPENCIL_SCULPT,
+ CTX_MODE_GPENCIL_WEIGHT,
};
+#define CTX_MODE_NUM (CTX_MODE_GPENCIL_WEIGHT + 1)
/* Context */
@@ -140,12 +152,15 @@ void CTX_py_dict_set(bContext *C, void *value);
struct wmWindowManager *CTX_wm_manager(const bContext *C);
struct wmWindow *CTX_wm_window(const bContext *C);
+struct WorkSpace *CTX_wm_workspace(const bContext *C);
struct bScreen *CTX_wm_screen(const bContext *C);
struct ScrArea *CTX_wm_area(const bContext *C);
struct SpaceLink *CTX_wm_space_data(const bContext *C);
struct ARegion *CTX_wm_region(const bContext *C);
void *CTX_wm_region_data(const bContext *C);
struct ARegion *CTX_wm_menu(const bContext *C);
+struct wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C);
+struct wmMsgBus *CTX_wm_message_bus(const bContext *C);
struct ReportList *CTX_wm_reports(const bContext *C);
struct View3D *CTX_wm_view3d(const bContext *C);
@@ -158,14 +173,13 @@ struct SpaceFile *CTX_wm_space_file(const bContext *C);
struct SpaceSeq *CTX_wm_space_seq(const bContext *C);
struct SpaceOops *CTX_wm_space_outliner(const bContext *C);
struct SpaceNla *CTX_wm_space_nla(const bContext *C);
-struct SpaceTime *CTX_wm_space_time(const bContext *C);
struct SpaceNode *CTX_wm_space_node(const bContext *C);
-struct SpaceLogic *CTX_wm_space_logic(const bContext *C);
struct SpaceIpo *CTX_wm_space_graph(const bContext *C);
struct SpaceAction *CTX_wm_space_action(const bContext *C);
struct SpaceInfo *CTX_wm_space_info(const bContext *C);
struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C);
struct SpaceClip *CTX_wm_space_clip(const bContext *C);
+struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C);
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
@@ -173,6 +187,7 @@ void CTX_wm_screen_set(bContext *C, struct bScreen *screen); /* to be removed */
void CTX_wm_area_set(bContext *C, struct ScrArea *sa);
void CTX_wm_region_set(bContext *C, struct ARegion *region);
void CTX_wm_menu_set(bContext *C, struct ARegion *menu);
+void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup);
const char *CTX_wm_operator_poll_msg_get(struct bContext *C);
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg);
@@ -209,11 +224,6 @@ short CTX_data_type_get(struct bContextDataResult *result);
bool CTX_data_equals(const char *member, const char *str);
bool CTX_data_dir(const char *member);
-#if 0
-void CTX_data_pointer_set(bContextDataResult *result, void *data);
-void CTX_data_list_add(bContextDataResult *result, void *data);
-#endif
-
#define CTX_DATA_BEGIN(C, Type, instance, member) \
{ \
ListBase ctx_data_list; \
@@ -243,9 +253,16 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas
struct Main *CTX_data_main(const bContext *C);
struct Scene *CTX_data_scene(const bContext *C);
+struct LayerCollection *CTX_data_layer_collection(const bContext *C);
+struct Collection *CTX_data_collection(const bContext *C);
+struct ViewLayer *CTX_data_view_layer(const bContext *C);
+struct RenderEngineType *CTX_data_engine_type(const bContext *C);
struct ToolSettings *CTX_data_tool_settings(const bContext *C);
const char *CTX_data_mode_string(const bContext *C);
+int CTX_data_mode_enum_ex(
+ const struct Object *obedit, const struct Object *ob,
+ const eObjectMode object_mode);
int CTX_data_mode_enum(const bContext *C);
void CTX_data_main_set(bContext *C, struct Main *bmain);
@@ -288,18 +305,23 @@ int CTX_data_editable_bones(const bContext *C, ListBase *list);
struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C);
int CTX_data_selected_pose_bones(const bContext *C, ListBase *list);
+int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list);
int CTX_data_visible_pose_bones(const bContext *C, ListBase *list);
struct bGPdata *CTX_data_gpencil_data(const bContext *C);
struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C);
struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C);
-struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C);
-struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C);
-struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C);
+struct Brush *CTX_data_active_gpencil_brush(const bContext *C);
int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
+struct Depsgraph *CTX_data_depsgraph(const bContext *C);
+
+/* Will Return NULL if depsgraph is not allocated yet.
+ * Only used by handful of operators which are run on file load.
+ */
+struct Depsgraph *CTX_data_depsgraph_on_load(const bContext *C);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h
index ee6c5c57678..e9745ed50fa 100644
--- a/source/blender/blenkernel/BKE_crazyspace.h
+++ b/source/blender/blenkernel/BKE_crazyspace.h
@@ -38,23 +38,24 @@ struct Scene;
struct Object;
struct BMEditMesh;
struct Mesh;
+struct Depsgraph;
/* crazyspace.c */
float (*BKE_crazyspace_get_mapped_editverts(
- struct Scene *scene, struct Object *obedit))[3];
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *obedit))[3];
void BKE_crazyspace_set_quats_editmesh(
struct BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4],
const bool use_select);
void BKE_crazyspace_set_quats_mesh(
struct Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]);
int BKE_crazyspace_get_first_deform_matrices_editbmesh(
- struct Scene *, struct Object *, struct BMEditMesh *em,
+ struct Depsgraph *depsgraph, struct Scene *, struct Object *, struct BMEditMesh *em,
float (**deformmats)[3][3], float (**deformcos)[3]);
int BKE_sculpt_get_first_deform_matrices(
- struct Scene *scene, struct Object *ob,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
float (**deformmats)[3][3], float (**deformcos)[3]);
void BKE_crazyspace_build_sculpt(
- struct Scene *scene, struct Object *ob,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
float (**deformmats)[3][3], float (**deformcos)[3]);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 5b7e5f9eebb..be46a2dd01a 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -36,6 +36,7 @@
struct BezTriple;
struct Curve;
struct EditNurb;
+struct Depsgraph;
struct GHash;
struct ListBase;
struct Main;
@@ -88,7 +89,7 @@ void BKE_curve_curve_dimension_update(struct Curve *cu);
void BKE_curve_boundbox_calc(struct Curve *cu, float r_loc[3], float r_size[3]);
struct BoundBox *BKE_curve_boundbox_get(struct Object *ob);
void BKE_curve_texspace_calc(struct Curve *cu);
-void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], float r_size[3]);
+struct BoundBox *BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], float r_size[3]);
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
@@ -122,13 +123,14 @@ void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex);
void BKE_curve_editNurb_free(struct Curve *cu);
struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
-float *BKE_curve_make_orco(struct Scene *scene, struct Object *ob, int *r_numVerts);
+float *BKE_curve_make_orco(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, int *r_numVerts);
float *BKE_curve_surf_make_orco(struct Object *ob);
void BKE_curve_bevelList_free(struct ListBase *bev);
void BKE_curve_bevelList_make(struct Object *ob, struct ListBase *nurbs, bool for_render);
-void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBase *disp,
- const bool for_render, const bool use_render_resolution);
+void BKE_curve_bevel_make(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *disp,
+ const bool for_render, const bool use_render_resolution);
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
@@ -220,10 +222,17 @@ void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles);
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
-
-void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx,
- struct Curve *curve);
+void BKE_curve_eval_geometry(
+ struct Depsgraph *depsgraph,
+ struct Curve *curve);
+
+/* Draw Cache */
+enum {
+ BKE_CURVE_BATCH_DIRTY_ALL = 0,
+ BKE_CURVE_BATCH_DIRTY_SELECT,
+};
+void BKE_curve_batch_cache_dirty_tag(struct Curve *cu, int mode);
+void BKE_curve_batch_cache_free(struct Curve *cu);
/* curve_decimate.c */
unsigned int BKE_curve_decimate_bezt_array(
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index e75997cd394..23bc7ddd6fd 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -67,12 +67,14 @@ extern const CustomDataMask CD_MASK_EVERYTHING;
* CD_NUMTYPES elements, that indicate if a layer can be copied. */
/* add/copy/merge allocation types */
-#define CD_ASSIGN 0 /* use the data pointer */
-#define CD_CALLOC 1 /* allocate blank memory */
-#define CD_DEFAULT 2 /* allocate and set to default */
-#define CD_REFERENCE 3 /* use data pointers, set layer flag NOFREE */
-#define CD_DUPLICATE 4 /* do a full copy of all layers, only allowed if source
- * has same number of elements */
+typedef enum eCDAllocType {
+ CD_ASSIGN = 0, /* use the data pointer */
+ CD_CALLOC = 1, /* allocate blank memory */
+ CD_DEFAULT = 2, /* allocate and set to default */
+ CD_REFERENCE = 3, /* use data pointers, set layer flag NOFREE */
+ CD_DUPLICATE = 4, /* do a full copy of all layers, only allowed if source
+ * has same number of elements */
+} eCDAllocType;
#define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type))
@@ -120,16 +122,18 @@ void CustomData_data_add(int type, void *data1, const void *data2);
/* initializes a CustomData object with the same layer setup as source.
* mask is a bitfield where (mask & (1 << (layer type))) indicates
* if a layer should be copied or not. alloctype must be one of the above. */
-void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem);
+void CustomData_copy(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem);
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
/* same as the above, except that this will preserve existing layers, and only
* add the layers that were not there yet */
-bool CustomData_merge(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem);
+bool CustomData_merge(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem);
/* Reallocate custom data to a new element count.
* Only affects on data layers which are owned by the CustomData itself,
@@ -144,7 +148,7 @@ void CustomData_realloc(struct CustomData *data, int totelem);
* consistent with the new layout.*/
bool CustomData_bmesh_merge(
const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, struct BMesh *bm, const char htype);
+ CustomDataMask mask, eCDAllocType alloctype, struct BMesh *bm, const char htype);
/** NULL's all members and resets the typemap. */
void CustomData_reset(struct CustomData *data);
@@ -164,11 +168,13 @@ void CustomData_free_temporary(struct CustomData *data, int totelem);
* backed by an external data array. the different allocation types are
* defined above. returns the data of the layer.
*/
-void *CustomData_add_layer(struct CustomData *data, int type, int alloctype,
- void *layer, int totelem);
+void *CustomData_add_layer(
+ struct CustomData *data, int type, eCDAllocType alloctype,
+ void *layer, int totelem);
/*same as above but accepts a name */
-void *CustomData_add_layer_named(struct CustomData *data, int type, int alloctype,
- void *layer, int totelem, const char *name);
+void *CustomData_add_layer_named(
+ struct CustomData *data, int type, eCDAllocType alloctype,
+ void *layer, int totelem, const char *name);
/* frees the active or first data layer with the give type.
* returns 1 on success, 0 if no layer with the given type is found
@@ -218,13 +224,20 @@ void CustomData_copy_data(const struct CustomData *source,
struct CustomData *dest, int source_index,
int dest_index, int count);
void CustomData_copy_data_named(const struct CustomData *source,
- struct CustomData *dest, int source_index,
- int dest_index, int count);
+ struct CustomData *dest, int source_index,
+ int dest_index, int count);
void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count);
void CustomData_bmesh_copy_data(const struct CustomData *source,
struct CustomData *dest, void *src_block,
void **dest_block);
+/* Copies data of a single layer of a given type. */
+void CustomData_copy_layer_type_data(const struct CustomData *source,
+ struct CustomData *destination,
+ int type,
+ int source_index, int destination_index,
+ int count);
+
/* frees data in a CustomData object
* return 1 on success, 0 on failure
*/
@@ -376,15 +389,14 @@ void CustomData_validate_layer_name(const struct CustomData *data, int type, con
bool CustomData_verify_versions(struct CustomData *data, int index);
/*BMesh specific customdata stuff*/
-void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata,
- struct CustomData *ldata, int totloop, int totpoly);
-void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total);
-void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
-void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
+void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int totloop);
+void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int total);
+void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *ldata);
+void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, struct CustomData *ldata);
void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, const char htype);
#ifndef NDEBUG
-bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback);
+bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback);
#endif
/* External file storage */
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index 2ee9d8d2408..7d0bb67c54d 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -38,6 +38,7 @@ extern "C" {
#include "BKE_customdata.h"
+struct Depsgraph;
struct Object;
struct Scene;
struct SpaceTransform;
@@ -129,11 +130,12 @@ enum {
};
void BKE_object_data_transfer_layout(
- struct Scene *scene, struct Object *ob_src, struct Object *ob_dst, const int data_types, const bool use_delete,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_src,
+ struct Object *ob_dst, const int data_types, const bool use_delete,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX]);
bool BKE_object_data_transfer_mesh(
- struct Scene *scene,
+ struct Depsgraph *depsgraph, struct Scene *scene,
struct Object *ob_src, struct Object *ob_dst, const int data_types, const bool use_create,
const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
struct SpaceTransform *space_transform, const bool auto_transform,
@@ -141,9 +143,9 @@ bool BKE_object_data_transfer_mesh(
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
struct ReportList *reports);
-bool BKE_object_data_transfer_dm(
- struct Scene *scene,
- struct Object *ob_src, struct Object *ob_dst, struct DerivedMesh *dm_dst,
+bool BKE_object_data_transfer_ex(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob_src, struct Object *ob_dst, struct Mesh *me_dst,
const int data_types, bool use_create,
const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
struct SpaceTransform *space_transform, const bool auto_transform,
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index a20c5a4240c..a29f4197299 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -116,4 +116,6 @@ void BKE_defvert_extract_vgroup_to_polyweights(
struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MLoop *loops, const int num_loops,
struct MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup);
+void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight);
+
#endif /* __BKE_DEFORM_H__ */
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
deleted file mode 100644
index 4af4f696b07..00000000000
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * ***** 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) 2004 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_DEPSGRAPH_H__
-#define __BKE_DEPSGRAPH_H__
-
-/** \file BKE_depsgraph.h
- * \ingroup bke
- */
-
-/* Dependency Graph
- *
- * The dependency graph tracks relations between datablocks, and is used to
- * determine which datablocks need to be update based on dependencies and
- * visibility.
- *
- * It does not itself execute changes in objects, but rather sorts the objects
- * in the appropriate order and sets flags indicating they should be updated.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct ID;
-struct Main;
-struct Object;
-struct Scene;
-
-/* Dependency graph evaluation context
- *
- * This structure stores all the local dependency graph data,
- * which is needed for it's evaluation,
- */
-typedef struct EvaluationContext {
- int mode; /* evaluation mode */
- float ctime; /* evaluation time */
-} EvaluationContext;
-
-typedef enum eEvaluationMode {
- DAG_EVAL_VIEWPORT = 0, /* evaluate for OpenGL viewport */
- DAG_EVAL_PREVIEW = 1, /* evaluate for render with preview settings */
- DAG_EVAL_RENDER = 2, /* evaluate for render purposes */
-} eEvaluationMode;
-
-/* DagNode->eval_flags */
-enum {
- /* Regardless to curve->path animation flag path is to be evaluated anyway,
- * to meet dependencies with such a things as curve modifier and other guys
- * who're using curve deform, where_on_path and so.
- */
- DAG_EVAL_NEED_CURVE_PATH = 1,
- /* Scene evaluation would need to have object's data on CPU,
- * meaning no GPU shortcuts is allowed.
- */
- DAG_EVAL_NEED_CPU = 2,
-};
-
-/* Global initialization/deinitialization */
-void DAG_init(void);
-void DAG_exit(void);
-
-/* Build and Update
- *
- * DAG_scene_relations_update will rebuild the dependency graph for a given
- * scene if needed, and sort objects in the scene.
- *
- * DAG_relations_tag_update will clear all dependency graphs and mark them to
- * be rebuilt later. The graph is not rebuilt immediately to avoid slowdowns
- * when this function is call multiple times from different operators.
- *
- * DAG_scene_relations_rebuild forces an immediaterebuild of the dependency
- * graph, this is only needed in rare cases
- */
-
-void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
-void DAG_scene_relations_validate(struct Main *bmain, struct Scene *sce);
-void DAG_relations_tag_update(struct Main *bmain);
-void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
-void DAG_scene_free(struct Scene *sce);
-
-/* Update Tagging
- *
- * DAG_scene_update_flags will mark all objects that depend on time (animation,
- * physics, ..) to be recalculated, used when changing the current frame.
- *
- * DAG_on_visible_update will mark all objects that are visible for the first
- * time to be updated, for example on file load or changing layer visibility.
- *
- * DAG_id_tag_update will mark a given datablock to be updated. The flag indicates
- * a specific subset to be update (only object transform and data for now).
- *
- * DAG_id_type_tag marks a particular datablock type as having changing. This does
- * not cause any updates but is used by external render engines to detect if for
- * example a datablock was removed. */
-
-void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const bool do_time, const bool do_invisible_flush);
-void DAG_on_visible_update(struct Main *bmain, const bool do_time);
-
-void DAG_id_tag_update(struct ID *id, short flag);
-void DAG_id_tag_update_ex(struct Main *bmain, struct ID *id, short flag);
-void DAG_id_type_tag(struct Main *bmain, short idtype);
-int DAG_id_type_tagged(struct Main *bmain, short idtype);
-
-/* Flushing Tags
- *
- * DAG_scene_flush_update flushes object recalculation flags immediately to other
- * dependencies. Do not use outside of depsgraph.c, this will be removed.
- *
- * DAG_ids_flush_tagged will flush datablock update flags flags to dependencies,
- * use this right before updating to mark all the needed datablocks for update.
- *
- * DAG_ids_check_recalc and DAG_ids_clear_recalc are used for external render
- * engines to detect changes. */
-
-void DAG_scene_flush_update(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
-void DAG_ids_flush_tagged(struct Main *bmain);
-void DAG_ids_check_recalc(struct Main *bmain, struct Scene *scene, bool time);
-void DAG_ids_clear_recalc(struct Main *bmain);
-
-/* Armature: sorts the bones according to dependencies between them */
-
-void DAG_pose_sort(struct Object *ob);
-
-/* Editors: callbacks to notify editors of datablock changes */
-
-void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id),
- void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated),
- void (*scene_pre_func)(struct Main *bmain, struct Scene *scene, bool time));
-
-void DAG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time);
-
-/* ** Threaded update ** */
-
-/* Initialize the DAG for threaded update. */
-void DAG_threaded_update_begin(struct Scene *scene,
- void (*func)(void *node, void *user_data),
- void *user_data);
-
-void DAG_threaded_update_handle_node_updated(void *node_v,
- void (*func)(void *node, void *user_data),
- void *user_data);
-
-/* Debugging: print dependency graph for scene or armature object to console */
-
-void DAG_print_dependencies(struct Main *bmain, struct Scene *scene, struct Object *ob);
-
-/* ************************ DAG querying ********************* */
-
-struct Object *DAG_get_node_object(void *node_v);
-const char *DAG_get_node_name(struct Scene *scene, void *node_v);
-short DAG_get_eval_flags_for_object(struct Scene *scene, void *object);
-bool DAG_is_acyclic(struct Scene *scene);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index a9cfa7b14ed..e6b08a8a063 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -57,8 +57,8 @@ enum {
/* prototypes */
-struct DerivedMesh;
-struct EvaluationContext;
+struct Depsgraph;
+struct Mesh;
struct ListBase;
struct Main;
struct Object;
@@ -87,23 +87,26 @@ void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface, int *to
void BKE_displist_free(struct ListBase *lb);
bool BKE_displist_has_faces(struct ListBase *lb);
-void BKE_displist_make_surf(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, struct DerivedMesh **r_dm_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution);
-void BKE_displist_make_curveTypes(struct Scene *scene, struct Object *ob, const bool for_orco);
-void BKE_displist_make_curveTypes_forRender(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, struct DerivedMesh **r_dm_final,
- const bool for_orco, const bool use_render_resolution);
-void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
-void BKE_displist_make_mball(struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
-void BKE_displist_make_mball_forRender(struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
+void BKE_displist_make_surf(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase,
+ struct Mesh **r_final, const bool for_render, const bool for_orco, const bool use_render_resolution);
+void BKE_displist_make_curveTypes(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ const bool for_render, const bool for_orco);
+void BKE_displist_make_curveTypes_forRender(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase,
+ struct Mesh **r_final, const bool for_orco, const bool use_render_resolution);
+void BKE_displist_make_curveTypes_forOrco(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
+void BKE_displist_make_mball(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+void BKE_displist_make_mball_forRender(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
void BKE_displist_fill(struct ListBase *dispbase, struct ListBase *to, const float normal_proj[3], const bool flipnormal);
-float BKE_displist_calc_taper(struct Scene *scene, struct Object *taperobj, int cur, int tot);
-
-/* add Orco layer to the displist object which has got derived mesh and return orco */
-float *BKE_displist_make_orco(struct Scene *scene, struct Object *ob, struct DerivedMesh *dm_final,
- const bool for_render, const bool use_render_resolution);
+float BKE_displist_calc_taper(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *taperobj, int cur, int tot);
void BKE_displist_minmax(struct ListBase *dispbase, float min[3], float max[3]);
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index c265672da88..d6a9cbb5e17 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -27,11 +27,14 @@
* \ingroup bke
*/
-struct EvaluationContext;
+struct Depsgraph;
+struct DynamicPaintCanvasSettings;
+struct DynamicPaintModifierData;
struct Main;
struct Scene;
+struct ViewLayer;
-/* Actual surface point */
+/* Actual surface point */
typedef struct PaintSurfaceData {
void *format_data; /* special data for each surface "format" */
void *type_data; /* data used by specific surface type */
@@ -42,7 +45,7 @@ typedef struct PaintSurfaceData {
} PaintSurfaceData;
-/* Paint type surface point */
+/* Paint type surface point */
typedef struct PaintPoint {
/* Wet paint is handled at effect layer only
@@ -53,7 +56,7 @@ typedef struct PaintPoint {
float color[4];
} PaintPoint;
-/* height field waves */
+/* height field waves */
typedef struct PaintWavePoint {
float height;
@@ -62,17 +65,20 @@ typedef struct PaintWavePoint {
short state;
} PaintWavePoint;
-struct DerivedMesh *dynamicPaint_Modifier_do(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct DynamicPaintModifierData *pmd, struct Scene *scene,
- struct Object *ob, struct DerivedMesh *dm);
+struct Mesh *dynamicPaint_Modifier_do(
+ struct DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct Mesh *me);
void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd);
-void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tsmd);
+void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd,
+ struct DynamicPaintModifierData *tsmd,
+ int flag);
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene);
struct DynamicPaintSurface *dynamicPaint_createNewSurface(struct DynamicPaintCanvasSettings *canvas, struct Scene *scene);
void dynamicPaint_clearSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
bool dynamicPaint_resetSurface(const struct Scene *scene, struct DynamicPaintSurface *surface);
-void dynamicPaint_freeSurface(struct DynamicPaintSurface *surface);
+void dynamicPaint_freeSurface(const struct DynamicPaintModifierData *pmd,
+ struct DynamicPaintSurface *surface);
void dynamicPaint_freeCanvas(struct DynamicPaintModifierData *pmd);
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd);
void dynamicPaint_freeSurfaceData(struct DynamicPaintSurface *surface);
@@ -88,9 +94,8 @@ struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings
/* image sequence baking */
int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface, float *progress, short *do_update);
int dynamicPaint_calculateFrame(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx, struct DynamicPaintSurface *surface, struct Scene *scene,
- struct Object *cObject, int frame);
+ struct DynamicPaintSurface *surface, struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *cObject, int frame);
void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, char *filename, short output_layer);
/* PaintPoint state */
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 2cae86d4c3b..de4efaf37b0 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -40,6 +40,8 @@ struct Mesh;
struct Scene;
struct DerivedMesh;
struct MeshStatVis;
+struct Depsgraph;
+struct EditMeshData;
/**
* This structure is used for mesh edit-mode.
@@ -62,8 +64,9 @@ typedef struct BMEditMesh {
struct BMLoop *(*looptris)[3];
int tottri;
+ struct Mesh *mesh_eval_final, *mesh_eval_cage;
+
/*derivedmesh stuff*/
- struct DerivedMesh *derivedFinal, *derivedCage;
CustomDataMask lastDataMask;
unsigned char (*derivedVertColor)[4];
int derivedVertColorLen;
@@ -88,17 +91,18 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
void BKE_editmesh_free_derivedmesh(BMEditMesh *em);
void BKE_editmesh_free(BMEditMesh *em);
-void BKE_editmesh_update_linked_customdata(BMEditMesh *em);
void BKE_editmesh_color_free(BMEditMesh *em);
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3];
+void BKE_editmesh_lnorspace_update(BMEditMesh *em);
/* editderivedmesh.c */
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
-void BKE_editmesh_statvis_calc(BMEditMesh *em, struct DerivedMesh *dm,
- const struct MeshStatVis *statvis);
+void BKE_editmesh_statvis_calc(
+ BMEditMesh *em, struct EditMeshData *emd, const struct MeshStatVis *statvis);
-float (*BKE_editmesh_vertexCos_get(struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3];
+float (*BKE_editmesh_vertexCos_get(
+ struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3];
#endif /* __BKE_EDITMESH_H__ */
diff --git a/source/blender/blenkernel/BKE_editmesh_cache.h b/source/blender/blenkernel/BKE_editmesh_cache.h
new file mode 100644
index 00000000000..aaaa79a0857
--- /dev/null
+++ b/source/blender/blenkernel/BKE_editmesh_cache.h
@@ -0,0 +1,36 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_EDITMESH_CACHE_H__
+#define __BKE_EDITMESH_CACHE_H__
+
+/** \file BKE_editmesh_cache.h
+ * \ingroup bke
+ */
+
+struct BMEditMesh;
+struct EditMeshData;
+
+void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, struct EditMeshData *emd);
+void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMeshData *emd);
+
+void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd);
+
+#endif /* __BKE_EDITMESH_CACHE_H__ */
diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h
new file mode 100644
index 00000000000..9553fbc1a5c
--- /dev/null
+++ b/source/blender/blenkernel/BKE_editmesh_tangent.h
@@ -0,0 +1,40 @@
+/*
+ * ***** 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): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_EDITMESH_TANGENT_H__
+#define __BKE_EDITMESH_TANGENT_H__
+
+/** \file BKE_editmesh_tangent.h
+ * \ingroup bke
+ */
+
+void BKE_editmesh_loop_tangent_calc(
+ BMEditMesh *em, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ CustomData *dm_loopdata_out,
+ const uint dm_loopdata_out_len,
+ short *tangent_mask_curr_p);
+
+#endif /* __BKE_EDITMESH_TANGENT_H__ */
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index bb5048a00f0..3d4154c572b 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -40,12 +40,14 @@
struct Object;
struct Scene;
struct ListBase;
-struct Group;
+struct Collection;
struct ParticleSimulationData;
struct ParticleData;
struct ParticleKey;
+struct Depsgraph;
+struct ViewLayer;
-struct EffectorWeights *BKE_add_effector_weights(struct Group *group);
+struct EffectorWeights *BKE_add_effector_weights(struct Collection *collection);
struct PartDeflect *object_add_collision_fields(int type);
/* Input to effector code */
@@ -93,6 +95,7 @@ typedef struct EffectorData {
typedef struct EffectorCache {
struct EffectorCache *next, *prev;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
struct Object *ob;
struct ParticleSystem *psys;
@@ -109,11 +112,35 @@ typedef struct EffectorCache {
int flag;
} EffectorCache;
-void free_partdeflect(struct PartDeflect *pd);
-struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool for_simulation);
-void pdEndEffectors(struct ListBase **effectors);
-void pdPrecalculateEffectors(struct ListBase *effectors);
-void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse);
+typedef struct EffectorRelation {
+ struct EffectorRelation *next, *prev;
+
+ struct Object *ob;
+ struct ParticleSystem *psys;
+ struct PartDeflect *pd;
+} EffectorRelation;
+
+void free_partdeflect(struct PartDeflect *pd);
+
+struct ListBase *BKE_effector_relations_create(
+ struct Depsgraph *depsgraph,
+ struct ViewLayer *view_layer,
+ struct Collection *collection);
+void BKE_effector_relations_free(struct ListBase *lb);
+
+struct ListBase *BKE_effectors_create(
+ struct Depsgraph *depsgraph,
+ struct Object *ob_src,
+ struct ParticleSystem *psys_src,
+ struct EffectorWeights *weights);
+void BKE_effectors_apply(
+ struct ListBase *effectors,
+ struct ListBase *colliders,
+ struct EffectorWeights *weights,
+ struct EffectedPoint *point,
+ float *force,
+ float *impulse);
+void BKE_effectors_free(struct ListBase *lb);
void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point);
void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point);
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index f8ba646fd57..f6490930530 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -108,7 +108,11 @@ 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 PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
+bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
+void BKE_driver_invalidate_expression(struct ChannelDriver *driver, bool expr_changed, bool varname_changed);
+
+float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver,
+ struct ChannelDriver *driver_orig, const float evaltime);
/* ************** F-Curve Modifiers *************** */
@@ -269,6 +273,17 @@ bool BKE_fcurve_is_protected(struct FCurve *fcu);
/* The curve is an infinite cycle via Cycles modifier */
bool BKE_fcurve_is_cyclic(struct FCurve *fcu);
+/* Type of infinite cycle for a curve. */
+typedef enum eFCU_Cycle_Type {
+ FCU_CYCLE_NONE = 0,
+ /* The cycle repeats identically to the base range. */
+ FCU_CYCLE_PERFECT,
+ /* The cycle accumulates the change between start and end keys. */
+ FCU_CYCLE_OFFSET
+} eFCU_Cycle_Type;
+
+eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu);
+
/* -------- Curve Sanity -------- */
void calchandles_fcurve(struct FCurve *fcu);
@@ -282,7 +297,8 @@ 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);
+float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu,
+ struct ChannelDriver *driver_orig, float evaltime);
/* evaluate fcurve and store value */
float calculate_fcurve(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime);
diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h
index af5b146906a..4883f2392b0 100644
--- a/source/blender/blenkernel/BKE_fluidsim.h
+++ b/source/blender/blenkernel/BKE_fluidsim.h
@@ -36,10 +36,11 @@ struct Object;
struct Scene;
struct FluidsimSettings;
struct MVert;
+struct Depsgraph;
/* old interface */
-void initElbeemMesh(struct Scene *scene, struct Object *ob,
+void initElbeemMesh(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
int *numVertices, float **vertices,
int *numTriangles, int **triangles,
int useGlobalCoords, int modifierIndex);
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index ab527e9b393..32bd1c1be7d 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -49,8 +49,8 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings;
/* FreestyleConfig */
void BKE_freestyle_config_init(FreestyleConfig *config);
-void BKE_freestyle_config_free(FreestyleConfig *config);
-void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag);
+void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user);
+void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag);
/* FreestyleConfig.modules */
FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 6ed32fc43ac..9a6560238ea 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -102,7 +102,6 @@ typedef struct Global {
/* G.f */
#define G_RENDER_OGL (1 << 0)
#define G_SWAP_EXCHANGE (1 << 1)
-/* also uses G_FILE_AUTOPLAY */
/* #define G_RENDER_SHADOW (1 << 3) */ /* temp flag, removed */
#define G_BACKBUFSEL (1 << 4)
#define G_PICKSEL (1 << 5)
@@ -154,16 +153,6 @@ enum {
#define G_AUTOPACK (1 << 0)
#define G_FILE_COMPRESS (1 << 1)
-#define G_FILE_AUTOPLAY (1 << 2)
-
-#ifdef DNA_DEPRECATED_ALLOW
-#define G_FILE_ENABLE_ALL_FRAMES (1 << 3) /* deprecated */
-#define G_FILE_SHOW_DEBUG_PROPS (1 << 4) /* deprecated */
-#define G_FILE_SHOW_FRAMERATE (1 << 5) /* deprecated */
-/* #define G_FILE_SHOW_PROFILE (1 << 6) */ /* deprecated */
-/* #define G_FILE_LOCK (1 << 7) */ /* deprecated */
-/* #define G_FILE_SIGN (1 << 8) */ /* deprecated */
-#endif /* DNA_DEPRECATED_ALLOW */
#define G_FILE_USERPREFS (1 << 9)
#define G_FILE_NO_UI (1 << 10)
@@ -217,6 +206,7 @@ enum {
#define G_TRANSFORM_EDIT 2
#define G_TRANSFORM_SEQ 4
#define G_TRANSFORM_FCURVES 8
+#define G_TRANSFORM_WM 16
/* Memory is allocated where? blender.c */
extern Global G;
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 92e16f02e25..34c61083872 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -26,30 +26,49 @@
#ifndef __BKE_GPENCIL_H__
#define __BKE_GPENCIL_H__
-/** \file BKE_gpencil.h
- * \ingroup bke
- * \author Joshua Leung
- */
-
+ /** \file BKE_gpencil.h
+ * \ingroup bke
+ * \author Joshua Leung
+ */
+
+struct CurveMapping;
+struct Depsgraph;
+struct GpencilModifierData;
struct ToolSettings;
struct ListBase;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
+struct bGPDspoint;
struct bGPDstroke;
+struct Material;
struct bGPDpalette;
struct bGPDpalettecolor;
struct Main;
+struct BoundBox;
+struct Brush;
+struct Object;
+struct bDeformGroup;
+struct SimplifyGpencilModifierData;
+struct ArrayGpencilModifierData;
+struct LatticeGpencilModifierData;
+
+struct MDeformVert;
+struct MDeformWeight;
/* ------------ Grease-Pencil API ------------------ */
+void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
+void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
void BKE_gpencil_free_layers(struct ListBase *list);
-void BKE_gpencil_free_brushes(struct ListBase *list);
-void BKE_gpencil_free_palettes(struct ListBase *list);
-void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
+bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf);
+void BKE_gpencil_free(struct bGPdata *gpd, bool free_all);
+
+void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
+void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
@@ -60,21 +79,37 @@ struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[])
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
-void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag);
+void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
+struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src);
+
+void BKE_gpencil_copy_data(struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag);
+struct bGPdata *BKE_gpencil_copy(struct Main *bmain, const struct bGPdata *gpd);
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy);
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
-struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
-struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
+/* materials */
+void BKE_gpencil_material_index_remove(struct bGPdata *gpd, int index);
+void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len);
+int BKE_gpencil_get_material_index(struct Object *ob, struct Material *ma);
+
+/* statistics functions */
+void BKE_gpencil_stats_update(struct bGPdata *gpd);
+
+/* Utilities for creating and populating GP strokes */
+/* - Number of values defining each point in the built-in data
+ * buffers for primitives (e.g. 2D Monkey)
+ */
+#define GP_PRIM_DATABUF_SIZE 5
-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);
+void BKE_gpencil_stroke_add_points(
+ struct bGPDstroke *gps,
+ const float *array, const int totpoints,
+ const float mat[4][4]);
+struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
@@ -103,20 +138,44 @@ struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
-struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
-void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
-void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush);
-
-struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
-void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
-void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
-void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd);
-
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette);
-void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
-void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
-void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
-void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
+struct Material *BKE_gpencil_get_material_from_brush(struct Brush *brush);
+struct Material *BKE_gpencil_material_ensure(struct Main *bmain, struct Object *ob);
+
+/* object boundbox */
+bool BKE_gpencil_data_minmax(
+ struct Object *ob, const struct bGPdata *gpd,
+ float r_min[3], float r_max[3]);
+bool BKE_gpencil_stroke_minmax(
+ const struct bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3]);
+bool BKE_gpencil_stroke_select_check(
+ const struct bGPDstroke *gps);
+
+struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob);
+void BKE_gpencil_centroid_3d(struct bGPdata *gpd, float r_centroid[3]);
+
+/* vertex groups */
+void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps);
+void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
+
+/* GPencil geometry evaluation */
+void BKE_gpencil_eval_geometry(struct Depsgraph *depsgraph, struct bGPdata *gpd);
+
+/* stroke geometry utilities */
+void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
+void BKE_gpencil_simplify_stroke(struct bGPDstroke *gps, float factor);
+void BKE_gpencil_simplify_fixed(struct bGPDstroke *gps);
+void BKE_gpencil_subdivide(struct bGPDstroke *gps, int level, int flag);
+
+void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]);
+
+bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf);
+bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence);
+
+void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
+float BKE_gpencil_multiframe_falloff_calc(struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
#endif /* __BKE_GPENCIL_H__ */
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
new file mode 100644
index 00000000000..e31f61c909a
--- /dev/null
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -0,0 +1,275 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_GPENCIL_MODIFIER_H__
+#define __BKE_GPENCIL_MODIFIER_H__
+
+/** \file BKE_gpencil_modifier.h
+ * \ingroup bke
+ */
+
+#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */
+#include "BLI_compiler_attrs.h"
+#include "BKE_customdata.h"
+
+struct ID;
+struct Depsgraph;
+struct DerivedMesh;
+struct bContext; /* NOTE: bakeModifier() - called from UI - needs to create new datablocks, hence the need for this */
+struct Mesh;
+struct Object;
+struct Scene;
+struct ViewLayer;
+struct ListBase;
+struct bArmature;
+struct Main;
+struct GpencilModifierData;
+struct BMEditMesh;
+struct DepsNodeHandle;
+struct bGPDlayer;
+struct bGPDframe;
+struct bGPDstroke;
+struct ModifierUpdateDepsgraphContext;
+
+#define GPENCIL_MODIFIER_ACTIVE(_md, _is_render) (((_md->mode & eGpencilModifierMode_Realtime) && (_is_render == false)) || \
+ ((_md->mode & eGpencilModifierMode_Render) && (_is_render == true)))
+#define GPENCIL_MODIFIER_EDIT(_md, _is_edit) (((_md->mode & eGpencilModifierMode_Editmode) == 0) && (_is_edit))
+
+typedef enum {
+ /* Should not be used, only for None modifier type */
+ eGpencilModifierTypeType_None,
+
+ /* grease pencil modifiers */
+ eGpencilModifierTypeType_Gpencil,
+} GpencilModifierTypeType;
+
+typedef enum {
+ eGpencilModifierTypeFlag_SupportsMapping = (1 << 0),
+ eGpencilModifierTypeFlag_SupportsEditmode = (1 << 1),
+
+ /* For modifiers that support editmode this determines if the
+ * modifier should be enabled by default in editmode. This should
+ * only be used by modifiers that are relatively speedy and
+ * also generally used in editmode, otherwise let the user enable
+ * it by hand.
+ */
+ eGpencilModifierTypeFlag_EnableInEditmode = (1 << 2),
+
+ /* For modifiers that require original data and so cannot
+ * be placed after any non-deformative modifier.
+ */
+ eGpencilModifierTypeFlag_RequiresOriginalData = (1 << 3),
+
+ /* max one per type */
+ eGpencilModifierTypeFlag_Single = (1 << 4),
+
+ /* can't be added manually by user */
+ eGpencilModifierTypeFlag_NoUserAdd = (1 << 5),
+ /* can't be applied */
+ eGpencilModifierTypeFlag_NoApply = (1 << 6),
+} GpencilModifierTypeFlag;
+
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void(*GreasePencilObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void(*GreasePencilIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
+typedef void(*GreasePencilTexWalkFunc)(void *userData, struct Object *ob, struct GpencilModifierData *md, const char *propname);
+
+typedef struct GpencilModifierTypeInfo {
+ /* The user visible name for this modifier */
+ char name[32];
+
+ /* The DNA struct name for the modifier data type, used to
+ * write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the modifier data type, used by allocation. */
+ int struct_size;
+
+ GpencilModifierTypeType type;
+ GpencilModifierTypeFlag flags;
+
+
+ /********************* Non-optional functions *********************/
+
+ /* Copy instance data for this modifier type. Should copy all user
+ * level settings to the target modifier.
+ */
+ void (*copyData)(const struct GpencilModifierData *md, struct GpencilModifierData *target);
+
+ /* Callback for GP "stroke" modifiers that operate on the
+ * shape and parameters of the provided strokes (e.g. Thickness, Noise, etc.)
+ *
+ * The gpl parameter contains the GP layer that the strokes come from.
+ * While access is provided to this data, you should not directly access
+ * the gpl->frames data from the modifier. Instead, use the gpf parameter
+ * instead.
+ *
+ * The gps parameter contains the GP stroke to operate on. This is usually a copy
+ * of the original (unmodified and saved to files) stroke data.
+ */
+ void (*deformStroke)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Object *ob, struct bGPDlayer *gpl, struct bGPDstroke *gps);
+
+ /* Callback for GP "geometry" modifiers that create extra geometry
+ * in the frame (e.g. Array)
+ *
+ * The gpf parameter contains the GP frame/strokes to operate on. This is
+ * usually a copy of the original (unmodified and saved to files) stroke data.
+ * Modifiers should only add any generated strokes to this frame (and not one accessed
+ * via the gpl parameter).
+ *
+ * The modifier_index parameter indicates where the modifier is
+ * in the modifier stack in relation to other modifiers.
+ */
+ void (*generateStrokes)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Object *ob, struct bGPDlayer *gpl, struct bGPDframe *gpf);
+
+ /* Bake-down GP modifier's effects into the GP datablock.
+ *
+ * This gets called when the user clicks the "Apply" button in the UI.
+ * As such, this callback needs to go through all layers/frames in the
+ * datablock, mutating the geometry and/or creating new datablocks/objects
+ */
+ void (*bakeModifier)(struct Main *bmain, struct Depsgraph *depsgraph,
+ struct GpencilModifierData *md, struct Object *ob);
+
+
+ /********************* Optional functions *********************/
+
+ /* Callback for GP "time" modifiers that offset keyframe time
+ * Returns the frame number to be used after apply the modifier. This is
+ * usually an offset of the animation for duplicated datablocks.
+ *
+ * This function is optional.
+ */
+ int (*remapTime)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *ob, struct bGPDlayer *gpl, int cfra);
+
+ /* Initialize new instance data for this modifier type, this function
+ * should set modifier variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct GpencilModifierData *md);
+
+ /* Free internal modifier data variables, this function should
+ * not free the md variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct GpencilModifierData *md);
+
+ /* Return a boolean value indicating if this modifier is able to be
+ * calculated based on the modifier data. This is *not* regarding the
+ * md->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ bool (*isDisabled)(struct GpencilModifierData *md, int userRenderParams);
+
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ void (*updateDepsgraph)(struct GpencilModifierData *md,
+ const struct ModifierUpdateDepsgraphContext *ctx);
+
+ /* Should return true if the modifier needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ bool (*dependsOnTime)(struct GpencilModifierData *md);
+
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the modifier data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the modifier data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilIDWalkFunc walk, void *userData);
+
+ /* Should call the given walk function for each texture that the
+ * modifier data stores. This is used for finding all textures in
+ * the context for the UI.
+ *
+ * This function is optional. If it is not present, it will be
+ * assumed the modifier has no textures.
+ */
+ void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilTexWalkFunc walk, void *userData);
+
+ /* get the number of times the strokes are duplicated in this modifier.
+ * This is used to calculate the size of the GPU VBOs
+ */
+ int (*getDuplicationFactor)(struct GpencilModifierData *md);
+} GpencilModifierTypeInfo;
+
+/* Initialize modifier's global data (type info and some common global storages). */
+void BKE_gpencil_modifier_init(void);
+
+const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
+void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
+void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
+bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
+bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md);
+struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob, GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name);
+void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst);
+void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md, struct GpencilModifierData *target);
+void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md, struct GpencilModifierData *target, const int flag);
+void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob, GreasePencilIDWalkFunc walk, void *userData);
+void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData);
+
+bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
+bool BKE_gpencil_has_time_modifiers(struct Object *ob);
+
+void BKE_gpencil_stroke_modifiers(
+ struct Depsgraph *depsgraph, struct Object *ob,
+ struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps, bool is_render);
+void BKE_gpencil_geometry_modifiers(
+ struct Depsgraph *depsgraph, struct Object *ob,
+ struct bGPDlayer *gpl, struct bGPDframe *gpf, bool is_render);
+int BKE_gpencil_time_modifier(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ struct bGPDlayer *gpl, int cfra, bool is_render);
+
+void BKE_gpencil_lattice_init(struct Object *ob);
+void BKE_gpencil_lattice_clear(struct Object *ob);
+
+#endif /* __BKE_GPENCIL_MODIFIER_H__ */
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
deleted file mode 100644
index 9824814990f..00000000000
--- a/source/blender/blenkernel/BKE_group.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_GROUP_H__
-#define __BKE_GROUP_H__
-
-/** \file BKE_group.h
- * \ingroup bke
- * \since March 2001
- * \author nzc
- */
-
-struct Base;
-struct EvaluationContext;
-struct Group;
-struct Main;
-struct Object;
-struct Scene;
-
-void BKE_group_free(struct Group *group);
-struct Group *BKE_group_add(struct Main *bmain, const char *name);
-void BKE_group_copy_data(struct Main *bmain, struct Group *group_dst, const struct Group *group_src, const int flag);
-struct Group *BKE_group_copy(struct Main *bmain, const struct Group *group);
-void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local);
-bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
-bool BKE_group_object_unlink(
- struct Main *bmain, struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
-struct Group *BKE_group_object_find(struct Main *bmain, struct Group *group, struct Object *ob);
-bool BKE_group_object_exists(struct Group *group, struct Object *ob);
-bool BKE_group_object_cyclic_check(struct Main *bmain, struct Object *object, struct Group *group);
-bool BKE_group_is_animated(struct Group *group, struct Object *parent);
-
-void BKE_group_handle_recalc_and_update(
- struct Main *bmain, struct EvaluationContext *eval_ctx,
- struct Scene *scene, struct Object *parent, struct Group *group);
-
-#endif /* __BKE_GROUP_H__ */
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 686dba21283..7a5262e0a14 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -36,18 +36,53 @@
typedef void (*DrawInfoFreeFP)(void *drawinfo);
+enum {
+ /** ID preview: obj is #ID. */
+ ICON_DATA_ID = 0,
+ /** Preview: obj is #PreviewImage */
+ ICON_DATA_PREVIEW,
+ /** 2D triangles: obj is #Icon_Geom */
+ ICON_DATA_GEOM,
+ /** Studiolight */
+ ICON_DATA_STUDIOLIGHT,
+ /** GPencil Layer color preview (annotations): obj is #bGPDlayer */
+ ICON_DATA_GPLAYER,
+};
+
struct Icon {
void *drawinfo;
+ /**
+ * Data defined by #obj_type
+ * \note for #ICON_DATA_GEOM the memory is owned by the icon,
+ * could be made into a flag if we want that to be optional.
+ */
void *obj;
+ char obj_type;
+ /** Internal use only. */
+ char flag;
/** #ID_Type or 0 when not used for ID preview. */
short id_type;
DrawInfoFreeFP drawinfo_free;
};
+/** Used for #ICON_DATA_GEOM, assigned to #Icon.obj. */
+struct Icon_Geom {
+ int icon_id;
+ int coords_len;
+ int coords_range[2];
+ const unsigned char (*coords)[2];
+ const unsigned char (*colors)[4];
+ /* when not NULL, the memory of coords and colors is a sub-region of this pointer. */
+ const void *mem;
+};
+
typedef struct Icon Icon;
+struct ImBuf;
struct PreviewImage;
struct ID;
+struct StudioLight;
+struct bGPDlayer;
enum eIconSizes;
@@ -56,6 +91,9 @@ void BKE_icons_init(int first_dyn_id);
/* return icon id for library object or create new icon if not found */
int BKE_icon_id_ensure(struct ID *id);
+/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */
+int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
+
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
/* retrieve icon for id */
@@ -68,7 +106,8 @@ void BKE_icon_set(const int icon_id, struct Icon *icon);
/* remove icon and free data if library object becomes invalid */
void BKE_icon_id_delete(struct ID *id);
-void BKE_icon_delete(const int icon_id);
+bool BKE_icon_delete(const int icon_id);
+bool BKE_icon_delete_unmanaged(const int icon_id);
/* report changes - icon needs to be recalculated */
void BKE_icon_changed(const int icon_id);
@@ -120,6 +159,16 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read(
void BKE_previewimg_cached_release(const char *name);
void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv);
+int BKE_icon_geom_ensure(struct Icon_Geom *geom);
+struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len);
+struct Icon_Geom *BKE_icon_geom_from_file(const char *filename);
+
+struct ImBuf *BKE_icon_geom_rasterize(
+ const struct Icon_Geom *geom,
+ const unsigned int size_x, const unsigned int size_y);
+
+int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type);
+
#define ICON_RENDER_DEFAULT_HEIGHT 32
#endif /* __BKE_ICONS_H__ */
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 48a00462dd1..6df31db7b83 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -32,6 +32,10 @@
#include "BLI_compiler_attrs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct IDProperty;
struct ID;
@@ -91,6 +95,7 @@ void IDP_ReplaceGroupInGroup(struct IDProperty *dest, const struct IDProperty *s
void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
void IDP_ReplaceInGroup_ex(struct IDProperty *group, struct IDProperty *prop, struct IDProperty *prop_exist);
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite) ATTR_NONNULL();
+void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag) ATTR_NONNULL();
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
bool IDP_InsertToGroup(struct IDProperty *group, struct IDProperty *previous,
struct IDProperty *pnew) ATTR_NONNULL(1 /* group */, 3 /* pnew */);
@@ -118,6 +123,8 @@ void IDP_ClearProperty(IDProperty *prop);
void IDP_RelinkProperty(struct IDProperty *prop);
+void IDP_Reset(IDProperty *prop, const IDProperty *reference);
+
#define IDP_Int(prop) ((prop)->data.val)
#define IDP_Array(prop) ((prop)->data.pointer)
/* C11 const correctness for casts */
@@ -154,4 +161,8 @@ void IDP_repr_fn(
void *user_data);
void IDP_print(const struct IDProperty *prop);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BKE_IDPROP_H__ */
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index bd9aeb1ab11..4bcb8e0c15d 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -114,8 +114,6 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const struc
struct anim *openanim(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]);
struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]);
-void BKE_image_de_interlace(struct Image *ima, int odd);
-
void BKE_image_make_local(struct Main *bmain, struct Image *ima, const bool lib_local);
void BKE_image_tag_time(struct Image *ima);
@@ -213,9 +211,9 @@ struct Image *BKE_image_verify_viewer(struct Main *bmain, int type, const char *
void BKE_image_verify_viewer_views(const struct RenderData *rd, struct Image *ima, struct ImageUser *iuser);
/* called on frame change or before render */
-void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
-void BKE_image_user_check_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
-int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, int fieldnr, bool *r_is_in_range);
+void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra);
+void BKE_image_user_check_frame_calc(struct ImageUser *iuser, int cfra);
+int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range);
void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path);
void BKE_image_update_frame(const struct Main *bmain, int cfra);
@@ -271,7 +269,7 @@ bool BKE_image_scale(struct Image *image, int width, int height);
bool BKE_image_has_alpha(struct Image *image);
/* check if texture has gpu texture code */
-bool BKE_image_has_bindcode(struct Image *ima);
+bool BKE_image_has_opengl_texture(struct Image *ima);
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *width, int *height);
void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float size[2]);
@@ -296,6 +294,12 @@ void BKE_image_file_format_set(struct Image *image, int ftype, const struct ImbF
bool BKE_image_has_loaded_ibuf(struct Image *image);
struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name);
struct ImBuf *BKE_image_get_first_ibuf(struct Image *image);
+
+struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name);
+bool BKE_image_remove_renderslot(struct Image *ima, struct ImageUser *iuser, int slot);
+struct RenderSlot *BKE_image_get_renderslot(struct Image *ima, int slot);
+bool BKE_image_clear_renderslot(struct Image *ima, struct ImageUser *iuser, int slot);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 2f953e57d71..73a6f5047b2 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -80,29 +80,19 @@ struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]);
void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src);
char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb);
-// needed for the GE
-typedef struct WeightsArrayCache {
- int num_defgroup_weights;
- float **defgroup_weights;
-} WeightsArrayCache;
-
-float **BKE_keyblock_get_per_block_weights(struct Object *ob, struct Key *key, struct WeightsArrayCache *cache);
-void BKE_keyblock_free_per_block_weights(struct Key *key, float **per_keyblock_weights, struct WeightsArrayCache *cache);
-void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb,
- float **per_keyblock_weights, const int mode);
-
/* conversion functions */
/* Note: 'update_from' versions do not (re)allocate mem in kb, while 'convert_from' do. */
void BKE_keyblock_update_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_to_lattice(struct KeyBlock *kb, struct Lattice *lt);
+int BKE_keyblock_curve_element_count(struct ListBase *nurb);
void BKE_keyblock_update_from_curve(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb);
void BKE_keyblock_convert_from_curve(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb);
void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct ListBase *nurb);
void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb);
-void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct KeyBlock *kb);
+void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct Key *key, struct KeyBlock *kb);
void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me);
void BKE_keyblock_mesh_calc_normals(
struct KeyBlock *kb, struct Mesh *mesh, float (*r_vertnors)[3], float (*r_polynors)[3], float (*r_loopnors)[3]);
diff --git a/source/blender/blenkernel/BKE_keyconfig.h b/source/blender/blenkernel/BKE_keyconfig.h
new file mode 100644
index 00000000000..94d00b19d42
--- /dev/null
+++ b/source/blender/blenkernel/BKE_keyconfig.h
@@ -0,0 +1,58 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_KEYCONFIG_H__
+#define __BKE_KEYCONFIG_H__
+
+/** \file BKE_keyconfig.h
+ * \ingroup bke
+ */
+
+/** Based on #BKE_addon_pref_type_init and friends */
+
+struct UserDef;
+struct wmKeyConfigPref;
+
+/** Actual data is stored in #wmKeyConfigPref. */
+#if defined(__RNA_TYPES_H__)
+typedef struct wmKeyConfigPrefType_Runtime {
+ char idname[64];
+
+ /* RNA integration */
+ ExtensionRNA ext;
+} wmKeyConfigPrefType_Runtime;
+
+#else
+typedef struct wmKeyConfigPrefType_Runtime wmKeyConfigPrefType_Runtime;
+#endif
+
+/* KeyConfig preferenes (UserDef). */
+struct wmKeyConfigPref *BKE_keyconfig_pref_ensure(struct UserDef *userdef, const char *kc_idname);
+
+/* KeyConfig preferenes (RNA). */
+struct wmKeyConfigPrefType_Runtime *BKE_keyconfig_pref_type_find(const char *idname, bool quiet);
+void BKE_keyconfig_pref_type_add(struct wmKeyConfigPrefType_Runtime *kpt_rt);
+void BKE_keyconfig_pref_type_remove(const struct wmKeyConfigPrefType_Runtime *kpt_rt);
+
+void BKE_keyconfig_pref_set_select_mouse(struct UserDef *userdef, int value, bool override);
+
+void BKE_keyconfig_pref_type_init(void);
+void BKE_keyconfig_pref_type_free(void);
+
+#endif /* __BKE_KEYCONFIG_H__ */
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index 3673e657b33..aa655c66477 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -50,8 +50,6 @@ struct Lamp *BKE_lamp_localize(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local);
void BKE_lamp_free(struct Lamp *la);
-void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index f7d006785d2..b2911129525 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -38,11 +38,13 @@
struct Lattice;
struct Main;
+struct Mesh;
struct Object;
struct Scene;
-struct DerivedMesh;
struct BPoint;
struct MDeformVert;
+struct Depsgraph;
+struct bGPDstroke;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
void BKE_lattice_init(struct Lattice *lt);
@@ -53,7 +55,6 @@ void BKE_lattice_free(struct Lattice *lt);
void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
-struct LatticeDeformData;
struct LatticeDeformData *init_latt_deform(struct Object *oblatt, struct Object *ob) ATTR_WARN_UNUSED_RESULT;
void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight);
void end_latt_deform(struct LatticeDeformData *lattice_deform_data);
@@ -61,23 +62,27 @@ void end_latt_deform(struct LatticeDeformData *lattice_deform_data);
bool object_deform_mball(struct Object *ob, struct ListBase *dispbase);
void outside_lattice(struct Lattice *lt);
-void curve_deform_verts(struct Scene *scene, struct Object *cuOb, struct Object *target,
- struct DerivedMesh *dm, float (*vertexCos)[3],
- int numVerts, const char *vgroup, short defaxis);
-void curve_deform_vector(struct Scene *scene, struct Object *cuOb, struct Object *target,
- float orco[3], float vec[3], float mat[3][3], int no_rot_axis);
-
-void lattice_deform_verts(struct Object *laOb, struct Object *target,
- struct DerivedMesh *dm, float (*vertexCos)[3],
- int numVerts, const char *vgroup, float influence);
-void armature_deform_verts(struct Object *armOb, struct Object *target,
- struct DerivedMesh *dm, float (*vertexCos)[3],
- float (*defMats)[3][3], int numVerts, int deformflag,
- float (*prevCos)[3], const char *defgrp_name);
+void curve_deform_verts(
+ struct Object *cuOb, struct Object *target, float (*vertexCos)[3],
+ int numVerts, struct MDeformVert *dvert, const int defgrp_index, short defaxis);
+void curve_deform_vector(
+ struct Object *cuOb, struct Object *target,
+ float orco[3], float vec[3], float mat[3][3], int no_rot_axis);
+
+void lattice_deform_verts(
+ struct Object *laOb, struct Object *target,
+ struct Mesh *mesh, float (*vertexCos)[3],
+ int numVerts, const char *vgroup, float influence);
+void armature_deform_verts(
+ struct Object *armOb, struct Object *target,
+ const struct Mesh *mesh, float (*vertexCos)[3],
+ float (*defMats)[3][3], int numVerts, int deformflag,
+ float (*prevCos)[3], const char *defgrp_name,
+ struct bGPDstroke *gps);
float (*BKE_lattice_vertexcos_get(struct Object *ob, int *r_numVerts))[3];
void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3]);
-void BKE_lattice_modifiers_calc(struct Scene *scene, struct Object *ob);
+void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
struct MDeformVert *BKE_lattice_deform_verts_get(struct Object *lattice);
struct BPoint *BKE_lattice_active_point_get(struct Lattice *lt);
@@ -90,6 +95,8 @@ void BKE_lattice_center_bounds(struct Lattice *lt, float cent[3]);
void BKE_lattice_translate(struct Lattice *lt, float offset[3], bool do_keys);
void BKE_lattice_transform(struct Lattice *lt, float mat[4][4], bool do_keys);
+bool BKE_lattice_is_any_selected(const struct Lattice *lt);
+
int BKE_lattice_index_from_uvw(struct Lattice *lt, const int u, const int v, const int w);
void BKE_lattice_index_to_uvw(struct Lattice *lt, const int index, int *r_u, int *r_v, int *r_w);
int BKE_lattice_index_flip(struct Lattice *lt, const int index,
@@ -99,9 +106,17 @@ void BKE_lattice_bitmap_from_flag(struct Lattice *lt, unsigned int *bitmap, cons
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
+struct Depsgraph;
-void BKE_lattice_eval_geometry(struct EvaluationContext *eval_ctx,
+void BKE_lattice_eval_geometry(struct Depsgraph *depsgraph,
struct Lattice *latt);
+/* Draw Cache */
+enum {
+ BKE_LATTICE_BATCH_DIRTY_ALL = 0,
+ BKE_LATTICE_BATCH_DIRTY_SELECT,
+};
+void BKE_lattice_batch_cache_dirty_tag(struct Lattice *lt, int mode);
+void BKE_lattice_batch_cache_free(struct Lattice *lt);
+
#endif /* __BKE_LATTICE_H__ */
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
new file mode 100644
index 00000000000..e98fa189379
--- /dev/null
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -0,0 +1,427 @@
+/*
+ * ***** 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): Blender Foundation, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_LAYER_H__
+#define __BKE_LAYER_H__
+
+/** \file blender/blenkernel/BKE_layer.h
+ * \ingroup bke
+ */
+
+#include "BKE_collection.h"
+
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TODO_LAYER_OVERRIDE /* CollectionOverride */
+#define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */
+#define TODO_LAYER /* generic todo */
+
+#define ROOT_PROP "root"
+
+struct Base;
+struct Collection;
+struct Depsgraph;
+struct ID;
+struct IDProperty;
+struct LayerCollection;
+struct ListBase;
+struct Main;
+struct Object;
+struct RenderEngine;
+struct Scene;
+struct View3D;
+struct ViewLayer;
+struct WorkSpace;
+
+struct ViewLayer *BKE_view_layer_default_view(const struct Scene *scene);
+struct ViewLayer *BKE_view_layer_default_render(const struct Scene *scene);
+struct ViewLayer *BKE_view_layer_find(const struct Scene *scene, const char *layer_name);
+struct ViewLayer *BKE_view_layer_add(struct Scene *scene, const char *name);
+
+/* DEPRECATED */
+struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene);
+
+void BKE_view_layer_free(struct ViewLayer *view_layer);
+void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user);
+
+void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag);
+
+struct Object *BKE_view_layer_camera_find(struct ViewLayer *view_layer);
+struct ViewLayer *BKE_view_layer_find_from_collection(const struct Scene *scene, struct LayerCollection *lc);
+struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob);
+void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer);
+
+void BKE_view_layer_base_select(struct Base *selbase);
+void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, struct Base *selbase);
+
+void BKE_view_layer_copy_data(
+ struct Scene *scene_dst, const struct Scene *scene_src,
+ struct ViewLayer *view_layer_dst, const struct ViewLayer *view_layer_src,
+ const int flag);
+
+void BKE_view_layer_rename(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, const char *name);
+
+struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer);
+bool BKE_layer_collection_activate(struct ViewLayer *view_layer, struct LayerCollection *lc);
+struct LayerCollection *BKE_layer_collection_activate_parent(struct ViewLayer *view_layer, struct LayerCollection *lc);
+
+int BKE_layer_collection_count(struct ViewLayer *view_layer);
+
+struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer, const int index);
+int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct LayerCollection *lc);
+
+void BKE_main_collection_sync(const struct Main *bmain);
+void BKE_scene_collection_sync(const struct Scene *scene);
+void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer);
+
+void BKE_main_collection_sync_remap(const struct Main *bmain);
+
+struct LayerCollection *BKE_layer_collection_first_from_scene_collection(
+ struct ViewLayer *view_layer, const struct Collection *collection);
+bool BKE_view_layer_has_collection(
+ struct ViewLayer *view_layer, const struct Collection *collection);
+bool BKE_scene_has_object(
+ struct Scene *scene, struct Object *ob);
+
+/* selection and hiding */
+
+bool BKE_layer_collection_objects_select(
+ struct ViewLayer *view_layer, struct LayerCollection *lc, bool deselect);
+bool BKE_layer_collection_has_selected_objects(
+ struct ViewLayer *view_layer, struct LayerCollection *lc);
+
+void BKE_base_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, bool extend);
+void BKE_layer_collection_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct LayerCollection *lc, bool extend);
+
+/* override */
+
+void BKE_override_view_layer_datablock_add(
+ struct ViewLayer *view_layer, int id_type, const char *data_path, const struct ID *owner_id);
+void BKE_override_view_layer_int_add(
+ struct ViewLayer *view_layer, int id_type, const char *data_path, const int value);
+
+void BKE_override_layer_collection_boolean_add(
+ struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value);
+
+/* evaluation */
+
+void BKE_layer_eval_view_layer(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
+
+void BKE_layer_eval_view_layer_indexed(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ int view_layer_index);
+
+/* iterators */
+
+typedef struct ObjectsVisibleIteratorData {
+ struct ViewLayer *view_layer;
+ struct View3D *v3d;
+} ObjectsVisibleIteratorData;
+
+void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_visible_objects_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter);
+
+struct ObjectsInModeIteratorData {
+ int object_mode;
+ struct ViewLayer *view_layer;
+ struct View3D *v3d;
+ struct Base *base_active;
+};
+
+void BKE_view_layer_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_renderable_objects_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_renderable_objects_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_visible_bases_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
+
+#define FOREACH_SELECTED_OBJECT_BEGIN(_view_layer, _v3d, _instance) \
+{ \
+ struct ObjectsVisibleIteratorData data_ = { \
+ .view_layer = _view_layer, \
+ .v3d = _v3d, \
+ }; \
+ ITER_BEGIN(BKE_view_layer_selected_objects_iterator_begin, \
+ BKE_view_layer_selected_objects_iterator_next, \
+ BKE_view_layer_selected_objects_iterator_end, \
+ &data_, Object *, _instance)
+
+#define FOREACH_SELECTED_OBJECT_END \
+ ITER_END; \
+} ((void)0)
+
+#define FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(_view_layer, _v3d, _instance) \
+{ \
+ struct ObjectsVisibleIteratorData data_ = { \
+ .view_layer = _view_layer, \
+ .v3d = _v3d, \
+ }; \
+ ITER_BEGIN(BKE_view_layer_selected_editable_objects_iterator_begin, \
+ BKE_view_layer_selected_editable_objects_iterator_next, \
+ BKE_view_layer_selected_editable_objects_iterator_end, \
+ &data_, Object *, _instance)
+
+#define FOREACH_SELECTED_EDITABLE_OBJECT_END \
+ ITER_END; \
+} ((void)0)
+
+#define FOREACH_VISIBLE_OBJECT_BEGIN(_view_layer, _v3d, _instance) \
+{ \
+ struct ObjectsVisibleIteratorData data_ = { \
+ .view_layer = _view_layer, \
+ .v3d = _v3d, \
+ }; \
+ ITER_BEGIN(BKE_view_layer_visible_objects_iterator_begin, \
+ BKE_view_layer_visible_objects_iterator_next, \
+ BKE_view_layer_visible_objects_iterator_end, \
+ &data_, Object *, _instance)
+
+#define FOREACH_VISIBLE_OBJECT_END \
+ ITER_END; \
+} ((void)0)
+
+#define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_mode, _instance) \
+{ \
+ struct ObjectsInModeIteratorData data_ = { \
+ .object_mode = _object_mode, \
+ .view_layer = _view_layer, \
+ .v3d = _v3d, \
+ .base_active = _view_layer->basact, \
+ }; \
+ ITER_BEGIN(BKE_view_layer_bases_in_mode_iterator_begin, \
+ BKE_view_layer_bases_in_mode_iterator_next, \
+ BKE_view_layer_bases_in_mode_iterator_end, \
+ &data_, Base *, _instance)
+
+#define FOREACH_BASE_IN_MODE_END \
+ ITER_END; \
+} ((void)0)
+
+#define FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _v3d, _instance) \
+ FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, OB_MODE_EDIT, _instance)
+
+#define FOREACH_BASE_IN_EDIT_MODE_END \
+ FOREACH_BASE_IN_MODE_END
+
+#define FOREACH_OBJECT_IN_MODE_BEGIN(_view_layer, _v3d, _object_mode, _instance) \
+ FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_mode, _base) { \
+ Object *_instance = _base->object;
+
+#define FOREACH_OBJECT_IN_MODE_END \
+ } FOREACH_BASE_IN_MODE_END
+
+#define FOREACH_OBJECT_IN_EDIT_MODE_BEGIN(_view_layer, _instance) \
+ FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _base) { \
+ Object *_instance = _base->object;
+
+#define FOREACH_OBJECT_IN_EDIT_MODE_END \
+ } FOREACH_BASE_IN_EDIT_MODE_END
+
+#define FOREACH_SELECTED_BASE_BEGIN(view_layer, _instance) \
+ ITER_BEGIN(BKE_view_layer_selected_bases_iterator_begin, \
+ BKE_view_layer_selected_bases_iterator_next, \
+ BKE_view_layer_selected_bases_iterator_end, \
+ view_layer, Base *, _instance)
+
+#define FOREACH_SELECTED_BASE_END \
+ ITER_END
+
+#define FOREACH_VISIBLE_BASE_BEGIN(_view_layer, _v3d, _instance) \
+{ \
+ struct ObjectsVisibleIteratorData data_ = { \
+ .view_layer = _view_layer, \
+ .v3d = _v3d, \
+ }; \
+ ITER_BEGIN(BKE_view_layer_visible_bases_iterator_begin, \
+ BKE_view_layer_visible_bases_iterator_next, \
+ BKE_view_layer_visible_bases_iterator_end, \
+ &data_, Base *, _instance)
+
+#define FOREACH_VISIBLE_BASE_END \
+ ITER_END; \
+} ((void)0)
+
+
+#define FOREACH_OBJECT_BEGIN(view_layer, _instance) \
+{ \
+ Object *_instance; \
+ Base *_base; \
+ for (_base = (view_layer)->object_bases.first; _base; _base = _base->next) { \
+ _instance = _base->object;
+
+#define FOREACH_OBJECT_END \
+ } \
+} ((void)0)
+
+#define FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, _instance) \
+{ \
+ IteratorBeginCb func_begin; \
+ IteratorCb func_next, func_end; \
+ void *data_in; \
+ \
+ if (flag == SELECT) { \
+ func_begin = &BKE_view_layer_selected_objects_iterator_begin; \
+ func_next = &BKE_view_layer_selected_objects_iterator_next; \
+ func_end = &BKE_view_layer_selected_objects_iterator_end; \
+ data_in = (view_layer); \
+ } \
+ else { \
+ func_begin = BKE_scene_objects_iterator_begin; \
+ func_next = BKE_scene_objects_iterator_next; \
+ func_end = BKE_scene_objects_iterator_end; \
+ data_in = (scene); \
+ } \
+ ITER_BEGIN(func_begin, func_next, func_end, data_in, Object *, _instance)
+
+
+#define FOREACH_OBJECT_FLAG_END \
+ ITER_END; \
+} ((void)0)
+
+struct ObjectsRenderableIteratorData {
+ struct Scene *scene;
+ struct Base base_temp;
+ struct Scene scene_temp;
+
+ struct {
+ struct ViewLayer *view_layer;
+ struct Base *base;
+ struct Scene *set;
+ } iter;
+};
+
+#define FOREACH_OBJECT_RENDERABLE_BEGIN(scene_, _instance) \
+{ \
+ struct ObjectsRenderableIteratorData data_ = { \
+ .scene = (scene_), \
+ }; \
+ ITER_BEGIN(BKE_view_layer_renderable_objects_iterator_begin, \
+ BKE_view_layer_renderable_objects_iterator_next, \
+ BKE_view_layer_renderable_objects_iterator_end, \
+ &data_, Object *, _instance)
+
+
+#define FOREACH_OBJECT_RENDERABLE_END \
+ ITER_END; \
+} ((void)0)
+
+
+/* layer_utils.c */
+
+struct ObjectsInModeParams {
+ int object_mode;
+ uint no_dup_data : 1;
+
+ bool (*filter_fn)(struct Object *ob, void *user_data);
+ void *filter_userdata;
+};
+
+Base **BKE_view_layer_array_from_bases_in_mode_params(
+ struct ViewLayer *view_layer, struct View3D *v3d, uint *r_len,
+ const struct ObjectsInModeParams *params);
+
+struct Object **BKE_view_layer_array_from_objects_in_mode_params(
+ struct ViewLayer *view_layer, struct View3D *v3d, uint *len,
+ const struct ObjectsInModeParams *params);
+
+#define BKE_view_layer_array_from_objects_in_mode(view_layer, v3d, r_len, ...) \
+ BKE_view_layer_array_from_objects_in_mode_params( \
+ view_layer, v3d, r_len, \
+ &(const struct ObjectsInModeParams)__VA_ARGS__)
+
+#define BKE_view_layer_array_from_bases_in_mode(view_layer, v3d, r_len, ...) \
+ BKE_view_layer_array_from_bases_in_mode_params( \
+ view_layer, v3d, r_len, \
+ &(const struct ObjectsInModeParams)__VA_ARGS__)
+
+bool BKE_view_layer_filter_edit_mesh_has_uvs(struct Object *ob, void *user_data);
+bool BKE_view_layer_filter_edit_mesh_has_edges(struct Object *ob, void *user_data);
+
+/* Utility macros that wrap common args (add more as needed). */
+
+#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, v3d, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, v3d, r_len, { \
+ .object_mode = OB_MODE_EDIT});
+
+#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len) \
+ BKE_view_layer_array_from_bases_in_mode( \
+ view_layer, v3d, r_len, { \
+ .object_mode = OB_MODE_EDIT});
+
+#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, v3d, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true});
+
+#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len) \
+ BKE_view_layer_array_from_bases_in_mode( \
+ view_layer, v3d, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true});
+
+#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, v3d, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true, \
+ .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs});
+
+#define BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, v3d, r_len, mode) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, v3d, r_len, { \
+ .object_mode = mode, \
+ .no_dup_data = true});
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_LAYER_H__ */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index c2b971a91cd..038e9377ba4 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -52,9 +52,13 @@ struct PropertyRNA;
size_t BKE_libblock_get_alloc_info(short type, const char **name);
void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
-void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT;
void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
+void *BKE_id_new(struct Main *bmain, const short type, const char *name);
+void *BKE_id_new_nomain(const short type, const char *name);
+
+
/**
* New ID creation/copying options.
*/
@@ -75,9 +79,14 @@ enum {
LIB_ID_COPY_NO_PROXY_CLEAR = 1 << 16, /* Object only, needed by make_local code. */
LIB_ID_COPY_NO_PREVIEW = 1 << 17, /* Do not copy preview data, when supported. */
LIB_ID_COPY_CACHES = 1 << 18, /* Copy runtime data caches. */
- /* XXX TODO Do we want to keep that? would rather try to get rid of it... */
- LIB_ID_COPY_ACTIONS = 1 << 19, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */
- LIB_ID_COPY_KEEP_LIB = 1 << 20, /* Keep the library pointer when copying datablock outside of bmain. */
+ LIB_ID_COPY_NO_ANIMDATA = 1 << 19, /* Don't copy id->adt, used by ID datablock localization routines. */
+ LIB_ID_COPY_CD_REFERENCE = 1 << 20, /* Mesh: Reference CD data layers instead of doing real copy. */
+
+ /* XXX Hackish/not-so-nice specific behaviors needed for some corner cases.
+ * Ideally we should not have those, but we need them for now... */
+ LIB_ID_COPY_ACTIONS = 1 << 24, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */
+ LIB_ID_COPY_KEEP_LIB = 1 << 25, /* Keep the library pointer when copying datablock outside of bmain. */
+ LIB_ID_COPY_SHAPEKEY = 1 << 26, /* EXCEPTION! Deep-copy shapekeys used by copied obdata ID. */
};
void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag);
@@ -147,6 +156,7 @@ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const boo
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test);
bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag, const bool test);
+void BKE_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
void BKE_id_expand_local(struct Main *bmain, struct ID *id);
void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id);
@@ -155,28 +165,7 @@ bool new_id(struct ListBase *lb, struct ID *id, const char *name) ATTR_NONNULL(1
void id_clear_lib_data(struct Main *bmain, struct ID *id);
void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_mainlist);
-struct ListBase *which_libbase(struct Main *mainlib, short type);
-
-#define MAX_LIBARRAY 35
-int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
-
-/* Main API */
-struct Main *BKE_main_new(void);
-void BKE_main_free(struct Main *mainvar);
-
-void BKE_main_lock(struct Main *bmain);
-void BKE_main_unlock(struct Main *bmain);
-
-void BKE_main_relations_create(struct Main *bmain);
-void BKE_main_relations_free(struct Main *bmain);
-
-struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
-struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
-void BKE_main_thumbnail_create(struct Main *bmain);
-
-const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL();
-const char *BKE_main_blendfile_path_from_global(void);
-
+/* Affect whole Main database. */
void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value);
void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value);
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value);
@@ -188,8 +177,12 @@ void BKE_main_id_clear_newpoins(struct Main *bmain);
void BKE_main_lib_objects_recalc_all(struct Main *bmain);
-/* (MAX_ID_NAME - 2) + 3 */
-void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
+#define MAX_ID_FULL_NAME (64 + 64 + 3 + 1) /* 64 is MAX_ID_NAME - 2 */
+#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at begining. */
+void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id);
+void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const struct ID *id);
+
+char *BKE_id_to_unique_string_key(const struct ID *id);
void BKE_library_free(struct Library *lib);
@@ -200,7 +193,10 @@ void BKE_library_make_local(
void BKE_id_tag_set_atomic(struct ID *id, int tag);
void BKE_id_tag_clear_atomic(struct ID *id, int tag);
-bool BKE_id_is_in_gobal_main(struct ID *id);
+bool BKE_id_is_in_global_main(struct ID *id);
+
+void BKE_id_ordered_list(struct ListBase *ordered_lb, const struct ListBase *lb);
+void BKE_id_reorder(const struct ListBase *lb, struct ID *id, struct ID *relative, bool after);
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h
new file mode 100644
index 00000000000..b6642bfa726
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library_override.h
@@ -0,0 +1,91 @@
+/*
+ * ***** 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 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_LIBRARY_OVERRIDE_H__
+#define __BKE_LIBRARY_OVERRIDE_H__
+
+/** \file BKE_library_override.h
+ * \ingroup bke
+ * \since December 2016
+ * \author mont29
+ */
+
+struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
+struct Main;
+
+void BKE_override_static_enable(const bool do_enable);
+bool BKE_override_static_is_enabled(void);
+
+struct IDOverrideStatic *BKE_override_static_init(struct ID *local_id, struct ID *reference_id);
+void BKE_override_static_copy(struct ID *dst_id, const struct ID *src_id);
+void BKE_override_static_clear(struct IDOverrideStatic *override);
+void BKE_override_static_free(struct IDOverrideStatic **override);
+
+struct ID *BKE_override_static_create_from_id(struct Main *bmain, struct ID *reference_id);
+bool BKE_override_static_create_from_tag(struct Main *bmain);
+
+struct IDOverrideStaticProperty *BKE_override_static_property_find(struct IDOverrideStatic *override, const char *rna_path);
+struct IDOverrideStaticProperty *BKE_override_static_property_get(struct IDOverrideStatic *override, const char *rna_path, bool *r_created);
+void BKE_override_static_property_delete(struct IDOverrideStatic *override, struct IDOverrideStaticProperty *override_property);
+
+struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find(
+ struct IDOverrideStaticProperty *override_property,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict);
+struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get(
+ struct IDOverrideStaticProperty *override_property, const short operation,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex,
+ const bool strict, bool *r_strict, bool *r_created);
+void BKE_override_static_property_operation_delete(
+ struct IDOverrideStaticProperty *override_property, struct IDOverrideStaticPropertyOperation *override_property_operation);
+
+bool BKE_override_static_status_check_local(struct Main *bmain, struct ID *local);
+bool BKE_override_static_status_check_reference(struct Main *bmain, struct ID *local);
+
+bool BKE_override_static_operations_create(struct Main *bmain, struct ID *local, const bool force_auto);
+void BKE_main_override_static_operations_create(struct Main *bmain, const bool force_auto);
+
+void BKE_override_static_update(struct Main *bmain, struct ID *local);
+void BKE_main_override_static_update(struct Main *bmain);
+
+
+/* Storage (.blend file writing) part. */
+
+/* For now, we just use a temp main list. */
+typedef struct Main OverrideStaticStorage;
+
+OverrideStaticStorage *BKE_override_static_operations_store_initialize(void);
+struct ID *BKE_override_static_operations_store_start(
+ struct Main *bmain, OverrideStaticStorage *override_storage, struct ID *local);
+void BKE_override_static_operations_store_end(OverrideStaticStorage *override_storage, struct ID *local);
+void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage);
+
+
+
+#endif /* __BKE_LIBRARY_OVERRIDE_H__ */
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index 65fe9abaa65..dcba5df9a72 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -56,6 +56,9 @@ enum {
* How to handle that kind of cases totally depends on what caller code is doing... */
IDWALK_CB_LOOPBACK = (1 << 4),
+ /** That ID is used as static override's reference by its owner. */
+ IDWALK_CB_STATIC_OVERRIDE_REFERENCE = (1 << 5),
+
/**
* Adjusts #ID.us reference-count.
* \note keep in sync with 'newlibadr_us' use in readfile.c
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
index fd37fd762f4..3425ca011b7 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -51,6 +51,8 @@ enum {
* This is needed e.g. in reload scenario, since we have to ensure remapping of Armature data of local proxy
* is also performed. Usual nightmare... */
ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4,
+ /* Do not remap static override pointers. */
+ ID_REMAP_SKIP_STATIC_OVERRIDE = 1 << 5,
};
/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */
diff --git a/source/blender/blenkernel/BKE_bmfont_types.h b/source/blender/blenkernel/BKE_lightprobe.h
index 31513e4b8f1..a769b6653d7 100644
--- a/source/blender/blenkernel/BKE_bmfont_types.h
+++ b/source/blender/blenkernel/BKE_lightprobe.h
@@ -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.
*
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * The Original Code is Copyright (C) Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
@@ -24,35 +24,23 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __BKE_BMFONT_TYPES_H__
-#define __BKE_BMFONT_TYPES_H__
-/** \file BKE_bmfont_types.h
+#ifndef __BKE_LIGHTPROBE_H__
+#define __BKE_LIGHTPROBE_H__
+
+/** \file BKE_lightprobe.h
* \ingroup bke
- * \since March 2001
- * \author nzc
- */
-#define is_power_of_two(N) ((N ^ (N - 1)) == (2 * N - 1))
-/*
- * Moved to IMB_imbuf_types.h where it will live close to the ImBuf type.
- * It is used as a userflag bit mask.
+ * \brief General operations for probes.
*/
-// #define IB_BITMAPFONT 1
-typedef struct bmGlyph {
- unsigned short unicode;
- short locx, locy;
- signed char ofsx, ofsy;
- unsigned char sizex, sizey;
- unsigned char advance, reserved;
-} bmGlyph;
+struct Main;
+struct LightProbe;
-typedef struct bmFont {
- char magic[4];
- short version;
- short glyphcount;
- short xsize, ysize;
- bmGlyph glyphs[1];
-} bmFont;
+void BKE_lightprobe_init(struct LightProbe *probe);
+void *BKE_lightprobe_add(struct Main *bmain, const char *name);
+void BKE_lightprobe_copy_data(struct Main *bmain, struct LightProbe *probe_dst, const struct LightProbe *probe_src, const int flag);
+struct LightProbe *BKE_lightprobe_copy(struct Main *bmain, const struct LightProbe *probe);
+void BKE_lightprobe_make_local(struct Main *bmain, struct LightProbe *probe, const bool lib_local);
+void BKE_lightprobe_free(struct LightProbe *probe);
-#endif
+#endif /* __BKE_LIGHTPROBE_H__ */
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index 3ba4fbe0338..376a324d25c 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -48,6 +48,7 @@ struct Main;
struct Object;
struct ColorBand;
struct bContext;
+struct ViewLayer;
void BKE_linestyle_init(struct FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
@@ -59,7 +60,7 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineSt
void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local);
-FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene);
+FreestyleLineStyle *BKE_linestyle_active_from_view_layer(struct ViewLayer *view_layer);
LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index e224155726f..e5a816b92ce 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -42,17 +42,20 @@
*/
#include "DNA_listBase.h"
-#include "BKE_library.h"
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
#ifdef __cplusplus
extern "C" {
#endif
-struct EvaluationContext;
+struct BlendThumbnail;
+struct BLI_mempool;
+struct Depsgraph;
+struct GHash;
+struct ImBuf;
struct Library;
struct MainLock;
-struct GHash;
-struct BLI_mempool;
/* Blender thumbnail, as written on file (width, height, and data as char RGBA). */
/* We pack pixel data after that struct. */
@@ -110,8 +113,9 @@ typedef struct Main {
ListBase vfont;
ListBase text;
ListBase speaker;
+ ListBase lightprobe;
ListBase sound;
- ListBase group;
+ ListBase collection;
ListBase armature;
ListBase action;
ListBase nodetree;
@@ -125,11 +129,7 @@ typedef struct Main {
ListBase mask;
ListBase linestyle;
ListBase cachefiles;
-
- char id_tag_update[MAX_LIBARRAY];
-
- /* Evaluation context used by viewport */
- struct EvaluationContext *eval_ctx;
+ ListBase workspaces;
/* Must be generated, used and freed by same code - never assume this is valid data unless you know
* when, who and how it was created.
@@ -139,6 +139,27 @@ typedef struct Main {
struct MainLock *lock;
} Main;
+struct Main *BKE_main_new(void);
+void BKE_main_free(struct Main *mainvar);
+
+void BKE_main_lock(struct Main *bmain);
+void BKE_main_unlock(struct Main *bmain);
+
+void BKE_main_relations_create(struct Main *bmain);
+void BKE_main_relations_free(struct Main *bmain);
+
+struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
+struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
+void BKE_main_thumbnail_create(struct Main *bmain);
+
+const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL();
+const char *BKE_main_blendfile_path_from_global(void);
+
+struct ListBase *which_libbase(struct Main *mainlib, short type);
+
+#define MAX_LIBARRAY 37
+int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
+
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
((main)->versionfile > (ver) || (main->versionfile == (ver) && (main)->subversionfile >= (subver)))
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 5598f0dc473..976ee5b2691 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -32,7 +32,7 @@
* \ingroup bke
*/
-struct EvaluationContext;
+struct Depsgraph;
struct ImageUser;
struct Image;
struct ListBase;
@@ -145,7 +145,6 @@ void BKE_mask_update_display(struct Mask *mask, float ctime);
void BKE_mask_evaluate_all_masks(struct Main *bmain, float ctime, const bool do_newframe);
void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe);
void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe);
-void BKE_mask_update_scene(struct Main *bmain, struct Scene *scene);
void BKE_mask_parent_init(struct MaskParent *parent);
void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline, struct MaskSplinePoint *point, const float u);
void BKE_mask_calc_tangent_polyline(struct MaskSpline *spline, struct MaskSplinePoint *point, float t[2]);
@@ -237,8 +236,8 @@ float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline, struct Mas
void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, const float ctime);
void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime);
-void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, struct Mask *mask);
-void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, struct Mask *mask);
+void BKE_mask_eval_animation(struct Depsgraph *depsgraph, struct Mask *mask);
+void BKE_mask_eval_update(struct Depsgraph *depsgraph, struct Mask *mask);
/* mask_rasterize.c */
struct MaskRasterHandle;
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index e2f5fb23465..1ca8928c61d 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -54,11 +54,13 @@ void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
+struct Material *BKE_material_add_gpencil(struct Main *bmain, const char *name);
void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag);
struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma);
struct Material *BKE_material_localize(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
+void BKE_material_init_gpencil_settings(struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
@@ -87,6 +89,8 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
+struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
+
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
@@ -97,26 +101,19 @@ struct Material *BKE_material_pop_id(struct Main *bmain, struct ID *id, int inde
void BKE_material_clear_id(struct Main *bmain, struct ID *id, bool update_data);
/* rendering */
-void init_render_material(struct Main *bmain, struct Material *, int, float *);
-void init_render_materials(struct Main *, int r_mode, float *amd, bool do_default_material);
-void end_render_material(struct Material *);
-void end_render_materials(struct Main *);
-
-bool material_in_material(struct Material *parmat, struct Material *mat);
-
void ramp_blend(int type, float r_col[3], const float fac, const float col[3]);
-/* driver update hacks */
-void material_drivers_update(struct Scene *scene, struct Material *mat, float ctime);
-
/* copy/paste */
void clear_matcopybuf(void);
void free_matcopybuf(void);
void copy_matcopybuf(struct Main *bmain, struct Material *ma);
void paste_matcopybuf(struct Main *bmain, struct Material *ma);
-/* handle backward compatibility for tface/materials called from doversion */
-int do_version_tface(struct Main *main);
+/* Evaluation. */
+
+struct Depsgraph;
+
+void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 87bc7b2dfc5..a7706915bc5 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -32,7 +32,8 @@
* \since March 2001
* \author nzc
*/
-struct EvaluationContext;
+struct BoundBox;
+struct Depsgraph;
struct Main;
struct MetaBall;
struct Object;
@@ -47,36 +48,49 @@ struct MetaBall *BKE_mball_copy(struct Main *bmain, const struct MetaBall *mb);
void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local);
+bool BKE_mball_is_any_selected(const struct MetaBall *mb);
+bool BKE_mball_is_any_selected_multi(struct Object **objects, int objects_len);
+bool BKE_mball_is_any_unselected(const struct MetaBall *mb);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
bool BKE_mball_is_basis(struct Object *ob);
-struct Object *BKE_mball_basis_find(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
+struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
void BKE_mball_texspace_calc(struct Object *ob);
+struct BoundBox *BKE_mball_boundbox_get(struct Object *ob);
float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase);
-void BKE_mball_properties_copy(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *active_object);
+void BKE_mball_properties_copy(struct Scene *scene, struct Object *active_object);
-bool BKE_mball_minmax(struct MetaBall *mb, float min[3], float max[3]);
-bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3],
- float obmat[4][4], const short flag);
-bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]);
-bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]);
+bool BKE_mball_minmax_ex(
+ const struct MetaBall *mb, float min[3], float max[3],
+ const float obmat[4][4], const short flag);
+bool BKE_mball_minmax(const struct MetaBall *mb, float min[3], float max[3]);
+bool BKE_mball_center_median(const struct MetaBall *mb, float r_cent[3]);
+bool BKE_mball_center_bounds(const struct MetaBall *mb, float r_cent[3]);
void BKE_mball_transform(struct MetaBall *mb, float mat[4][4], const bool do_props);
void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type);
+int BKE_mball_select_count(const struct MetaBall *mb);
+int BKE_mball_select_count_multi(struct Object **objects, int objects_len);
void BKE_mball_select_all(struct MetaBall *mb);
+void BKE_mball_select_all_multi(struct Object **objects, int objects_len);
void BKE_mball_deselect_all(struct MetaBall *mb);
+void BKE_mball_deselect_all_multi(struct Object **objects, int objects_len);
void BKE_mball_select_swap(struct MetaBall *mb);
+void BKE_mball_select_swap_multi(struct Object **objects, int objects_len);
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
+struct Depsgraph;
-void BKE_mball_eval_geometry(struct EvaluationContext *eval_ctx,
- struct MetaBall *mball);
+/* Draw Cache */
+
+enum {
+ BKE_MBALL_BATCH_DIRTY_ALL = 0,
+};
+void BKE_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode);
+void BKE_mball_batch_cache_free(struct MetaBall *mb);
#endif
diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h b/source/blender/blenkernel/BKE_mball_tessellate.h
index 254d5e9248a..363bfe09c75 100644
--- a/source/blender/blenkernel/BKE_mball_tessellate.h
+++ b/source/blender/blenkernel/BKE_mball_tessellate.h
@@ -23,13 +23,13 @@
/** \file BKE_mball_tessellate.h
* \ingroup bke
*/
-struct EvaluationContext;
+struct Depsgraph;
struct Main;
struct Object;
struct Scene;
void BKE_mball_polygonize(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene,
+ struct Depsgraph *depsgraph, struct Scene *scene,
struct Object *ob, struct ListBase *dispbase);
void BKE_mball_cubeTable_free(void);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 6d2a431f667..aba42820519 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -31,31 +31,43 @@
* \ingroup bke
*/
+/* defines BLI_INLINE */
+#include "BLI_compiler_compat.h"
+
+/* defines CustomDataMask */
+#include "BKE_customdata.h"
+
struct ID;
struct BMeshCreateParams;
+struct BMeshFromMeshParams;
+struct BMeshToMeshParams;
struct BoundBox;
+struct Depsgraph;
struct EdgeHash;
struct ListBase;
struct LinkNode;
struct BLI_Stack;
struct MemArena;
struct BMesh;
+struct KeyBlock;
struct MLoopTri;
struct Main;
struct Mesh;
+struct ModifierData;
struct MPoly;
struct MLoop;
struct MFace;
struct MEdge;
struct MVert;
+struct MVertTri;
struct MDeformVert;
struct MDisps;
struct Object;
struct CustomData;
-struct DerivedMesh;
struct Scene;
struct MLoopUV;
struct ReportList;
+struct BMEditMesh;
#ifdef __cplusplus
extern "C" {
@@ -70,10 +82,20 @@ extern "C" {
/* *** mesh.c *** */
+struct BMesh *BKE_mesh_to_bmesh_ex(
+ const struct Mesh *me,
+ const struct BMeshCreateParams *create_params,
+ const struct BMeshFromMeshParams *convert_params);
struct BMesh *BKE_mesh_to_bmesh(
struct Mesh *me, struct Object *ob,
const bool add_key_index, const struct BMeshCreateParams *params);
+struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, const struct BMeshToMeshParams *params);
+struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, int64_t cd_mask_extra);
+
+struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ struct BMEditMesh *em, CustomDataMask data_mask, float (*vertexCos)[3]);
+
int poly_find_loop_from_vert(
const struct MPoly *poly,
const struct MLoop *loopstart, unsigned vert);
@@ -83,6 +105,7 @@ int poly_get_adj_loops_from_vert(
unsigned int r_adj[2]);
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
+void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh, const struct MLoopTri *looptri, int r_edges[3]);
void BKE_mesh_free(struct Mesh *me);
void BKE_mesh_init(struct Mesh *me);
@@ -92,6 +115,24 @@ struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
+struct Mesh *BKE_mesh_new_nomain(
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len);
+struct Mesh *BKE_mesh_new_nomain_from_template(
+ const struct Mesh *me_src,
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len);
+
+/* Performs copy for use during evaluation, optional referencing original arrays to reduce memory. */
+struct Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference);
+
+/* These functions construct a new Mesh, contrary to BKE_mesh_from_nurbs which modifies ob itself. */
+struct Mesh *BKE_mesh_new_nomain_from_curve(struct Object *ob);
+struct Mesh *BKE_mesh_new_nomain_from_curve_displist(struct Object *ob, struct ListBase *dispbase);
+
+bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me);
+bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
+
void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local);
void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]);
void BKE_mesh_texspace_calc(struct Mesh *me);
@@ -100,6 +141,22 @@ void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totv
int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr);
struct Mesh *BKE_mesh_from_object(struct Object *ob);
void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me);
+void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
+int BKE_mesh_nurbs_to_mdata(
+ struct Object *ob, struct MVert **r_allvert, int *r_totvert,
+ struct MEdge **r_alledge, int *r_totedge, struct MLoop **r_allloop, struct MPoly **r_allpoly,
+ int *r_totloop, int *r_totpoly);
+int BKE_mesh_nurbs_displist_to_mdata(
+ struct Object *ob, const struct ListBase *dispbase,
+ struct MVert **r_allvert, int *r_totvert,
+ struct MEdge **r_alledge, int *r_totedge,
+ struct MLoop **r_allloop, struct MPoly **r_allpoly,
+ struct MLoopUV **r_alluv, int *r_totloop, int *r_totpoly);
+void BKE_mesh_from_nurbs_displist(
+ struct Main *bmain, struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary);
+void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob);
+void BKE_mesh_to_curve_nurblist(const struct Mesh *me, struct ListBase *nurblist, const int edge_users_test);
+void BKE_mesh_to_curve(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_mesh_material_index_remove(struct Mesh *me, short index);
void BKE_mesh_material_index_clear(struct Mesh *me);
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
@@ -108,17 +165,32 @@ void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth);
const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob);
-void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_rot[3], float r_size[3]);
+struct BoundBox *BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_rot[3], float r_size[3]);
+void BKE_mesh_texspace_get_reference(struct Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size);
void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob);
-bool BKE_mesh_uv_cdlayer_rename_index(struct Mesh *me, const int poly_index, const int loop_index, const int face_index,
- const char *new_name, const bool do_tessface);
+bool BKE_mesh_uv_cdlayer_rename_index(
+ struct Mesh *me, const int loop_index, const int face_index,
+ const char *new_name, const bool do_tessface);
bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface);
float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3];
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
+struct Mesh *BKE_mesh_new_from_object(
+ struct Depsgraph *depsgraph, struct Main *bmain, struct Scene *sce, struct Object *ob,
+ const bool apply_modifiers, const bool calc_undeformed);
+struct Mesh *BKE_mesh_create_derived_for_modifier(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ struct ModifierData *md, int build_shapekey_layers);
+
+/* Copies a nomain-Mesh into an existing Mesh. */
+void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob,
+ CustomDataMask mask, bool take_ownership);
+void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb);
+
+
/* vertex level transformations & checks (no derived mesh) */
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]);
@@ -140,31 +212,13 @@ int BKE_mesh_mselect_find(struct Mesh *me, int index, int type);
int BKE_mesh_mselect_active_get(struct Mesh *me, int type);
void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type);
-/* *** mesh_convert.c *** */
-
-void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
-int BKE_mesh_nurbs_to_mdata(
- struct Object *ob, struct MVert **r_allvert, int *r_totvert,
- struct MEdge **r_alledge, int *r_totedge, struct MLoop **r_allloop, struct MPoly **r_allpoly,
- int *r_totloop, int *r_totpoly);
-int BKE_mesh_nurbs_displist_to_mdata(
- struct Object *ob, const struct ListBase *dispbase,
- struct MVert **r_allvert, int *r_totvert,
- struct MEdge **r_alledge, int *r_totedge,
- struct MLoop **r_allloop, struct MPoly **r_allpoly,
- struct MLoopUV **r_alluv, int *r_totloop, int *r_totpoly);
-void BKE_mesh_from_nurbs_displist(
- struct Main *bmain, struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name);
-void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob);
-void BKE_mesh_to_curve_nurblist(struct DerivedMesh *dm, struct ListBase *nurblist, const int edge_users_test);
-void BKE_mesh_to_curve(struct Main *bmain, struct Scene *scene, struct Object *ob);
+void BKE_mesh_apply_vert_coords(struct Mesh *mesh, float (*vertCoords)[3]);
+void BKE_mesh_apply_vert_normals(struct Mesh *mesh, short (*vertNormals)[3]);
-struct Mesh *BKE_mesh_new_from_object(
- struct Main *bmain, struct Scene *sce, struct Object *ob,
- int apply_modifiers, int settings, int calc_tessface, int calc_undeformed);
/* *** mesh_evaluate.c *** */
+void BKE_mesh_calc_normals_mapping_simple(struct Mesh *me);
void BKE_mesh_calc_normals_mapping(
struct MVert *mverts, int numVerts,
const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float (*r_polyNors)[3],
@@ -181,6 +235,8 @@ void BKE_mesh_calc_normals_poly(
int numLoops, int numPolys, float (*r_polyNors)[3],
const bool only_face_normals);
void BKE_mesh_calc_normals(struct Mesh *me);
+void BKE_mesh_ensure_normals(struct Mesh *me);
+void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
void BKE_mesh_calc_normals_tessface(
struct MVert *mverts, int numVerts,
const struct MFace *mfaces, int numFaces,
@@ -190,13 +246,6 @@ void BKE_mesh_calc_normals_looptri(
const struct MLoop *mloop,
const struct MLoopTri *looptri, int looptri_num,
float (*r_tri_nors)[3]);
-void BKE_mesh_loop_tangents_ex(
- const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
- float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
- const int numLoops, const struct MPoly *mpolys, const int numPolys,
- struct ReportList *reports);
-void BKE_mesh_loop_tangents(
- struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
void BKE_mesh_loop_manifold_fan_around_vert_next(
const struct MLoop *mloops, const struct MPoly *mpolys,
const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index,
@@ -224,6 +273,8 @@ typedef struct MLoopNorSpace {
* - BMLoop pointers. */
struct LinkNode *loops;
char flags;
+
+ void *user_data; /* To be used for extended processing related to loop normal spaces (aka smooth fans). */
} MLoopNorSpace;
/**
* MLoopNorSpace.flags
@@ -239,6 +290,7 @@ typedef struct MLoopNorSpaceArray {
MLoopNorSpace **lspacearr; /* MLoop aligned array */
struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */
char data_type; /* Whether we store loop indices, or pointers to BMLoop. */
+ int num_spaces; /* Number of clnors spaces defined in this array. */
struct MemArena *mem;
} MLoopNorSpaceArray;
/**
@@ -332,7 +384,7 @@ void BKE_mesh_loops_to_mface_corners(
const int numTex, const int numCol,
const bool hasPCol, const bool hasOrigSpace, const bool hasLNor);
void BKE_mesh_loops_to_tessdata(
- struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MFace *mface,
+ struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
void BKE_mesh_tangent_loops_to_tessdata(
struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
@@ -365,6 +417,19 @@ void BKE_mesh_polygon_flip_ex(
void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly);
+/* merge verts */
+/* Enum for merge_mode of CDDM_merge_verts.
+ * Refer to mesh.c for details. */
+enum {
+ MESH_MERGE_VERTS_DUMP_IF_MAPPED,
+ MESH_MERGE_VERTS_DUMP_IF_EQUAL,
+};
+struct Mesh *BKE_mesh_merge_verts(
+ struct Mesh *mesh,
+ const int *vtargetmap, const int tot_vtargetmap,
+ const int merge_mode);
+
+
/* flush flags */
void BKE_mesh_flush_hidden_from_verts_ex(
const struct MVert *mvert,
@@ -407,7 +472,7 @@ void BKE_mesh_calc_relative_deform(
/* *** mesh_validate.c *** */
bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask);
-void BKE_mesh_cd_validate(struct Mesh *me);
+bool BKE_mesh_is_valid(struct Mesh *me);
bool BKE_mesh_validate_material_indices(struct Mesh *me);
bool BKE_mesh_validate_arrays(
@@ -433,15 +498,41 @@ void BKE_mesh_strip_loose_polysloops(struct Mesh *me);
void BKE_mesh_strip_loose_edges(struct Mesh *me);
void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old);
+void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select);
+void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
-
-void BKE_mesh_eval_geometry(struct EvaluationContext *eval_ctx,
+void BKE_mesh_eval_geometry(struct Depsgraph *depsgraph,
struct Mesh *mesh);
+/* Draw Cache */
+enum {
+ BKE_MESH_BATCH_DIRTY_ALL = 0,
+ BKE_MESH_BATCH_DIRTY_MAYBE_ALL,
+ BKE_MESH_BATCH_DIRTY_SELECT,
+ BKE_MESH_BATCH_DIRTY_SHADING,
+ BKE_MESH_BATCH_DIRTY_SCULPT_COORDS,
+ BKE_MESH_BATCH_DIRTY_UVEDIT_ALL,
+ BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT,
+};
+void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, int mode);
+void BKE_mesh_batch_cache_free(struct Mesh *me);
+
+
+/* Inlines */
+
+/* Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,
+ * but I don't want to force every user of BKE_mesh.h to also include that file.
+ * ~~ Sybren */
+BLI_INLINE int BKE_mesh_origindex_mface_mpoly(
+ const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i)
+{
+ const int j = index_mf_to_mpoly[i];
+ return (j != -1) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : -1;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h
new file mode 100644
index 00000000000..70c10806350
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_iterators.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: all of this file.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_ITERATORS_H__
+#define __BKE_MESH_ITERATORS_H__
+
+/** \file BKE_mesh_iterators.h
+ * \ingroup bke
+ */
+
+struct Mesh;
+struct MVert;
+struct MEdge;
+struct MPoly;
+struct MLoop;
+struct MLoopUV;
+struct MLoopTri;
+
+typedef enum MeshForeachFlag {
+ MESH_FOREACH_NOP = 0,
+ MESH_FOREACH_USE_NORMAL = (1 << 0), /* foreachMappedVert, foreachMappedLoop, foreachMappedFaceCenter */
+} MeshForeachFlag;
+
+
+void BKE_mesh_foreach_mapped_vert(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
+ void *userData,
+ MeshForeachFlag flag);
+void BKE_mesh_foreach_mapped_edge(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
+ void *userData);
+void BKE_mesh_foreach_mapped_loop(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag);
+void BKE_mesh_foreach_mapped_face_center(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float cent[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag);
+
+void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
+
+#endif /* __BKE_MESH_ITERATORS_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 5c77ab8a94e..7aea856ff34 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -26,7 +26,7 @@
*/
struct CustomData;
-struct DerivedMesh;
+struct Mesh;
struct MVert;
struct MemArena;
@@ -140,39 +140,37 @@ enum {
MREMAP_MODE_TOPOLOGY = MREMAP_MODE_VERT | MREMAP_MODE_EDGE | MREMAP_MODE_LOOP | MREMAP_MODE_POLY,
};
-float BKE_mesh_remap_calc_difference_from_dm(
+float BKE_mesh_remap_calc_difference_from_mesh(
const struct SpaceTransform *space_transform,
- const struct MVert *verts_dst, const int numverts_dst, struct DerivedMesh *dm_src);
+ const struct MVert *verts_dst, const int numverts_dst, struct Mesh *me_src);
-void BKE_mesh_remap_find_best_match_from_dm(
- const struct MVert *verts_dst, const int numverts_dst, struct DerivedMesh *dm_src,
+void BKE_mesh_remap_find_best_match_from_mesh(
+ const struct MVert *verts_dst, const int numverts_dst, struct Mesh *me_src,
struct SpaceTransform *r_space_transform);
-/* TODO add mesh2mesh versions (we'll need mesh versions of bvhtree funcs too, though!). */
-
-void BKE_mesh_remap_calc_verts_from_dm(
+void BKE_mesh_remap_calc_verts_from_mesh(
const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius,
const struct MVert *verts_dst, const int numverts_dst, const bool dirty_nors_dst,
- struct DerivedMesh *dm_src, MeshPairRemap *r_map);
+ struct Mesh *me_src, MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_edges_from_dm(
+void BKE_mesh_remap_calc_edges_from_mesh(
const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius,
const struct MVert *verts_dst, const int numverts_dst, const struct MEdge *edges_dst, const int numedges_dst,
- const bool dirty_nors_dst, struct DerivedMesh *dm_src, MeshPairRemap *r_map);
+ const bool dirty_nors_dst, struct Mesh *me_src, MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_loops_from_dm(
+void BKE_mesh_remap_calc_loops_from_mesh(
const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius,
struct MVert *verts_dst, const int numverts_dst, struct MEdge *edges_dst, const int numedges_dst,
struct MLoop *loops_dst, const int numloops_dst, struct MPoly *polys_dst, const int numpolys_dst,
struct CustomData *ldata_dst, struct CustomData *pdata_dst,
const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
- struct DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
+ struct Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, struct MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_polys_from_dm(
+void BKE_mesh_remap_calc_polys_from_mesh(
const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius,
struct MVert *verts_dst, const int numverts_dst, struct MLoop *loops_dst, const int numloops_dst,
struct MPoly *polys_dst, const int numpolys_dst, struct CustomData *pdata_dst, const bool dirty_nors_dst,
- struct DerivedMesh *dm_src, struct MeshPairRemap *r_map);
+ struct Mesh *me_src, struct MeshPairRemap *r_map);
#endif /* __BKE_MESH_REMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
new file mode 100644
index 00000000000..5d35f798ad7
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -0,0 +1,122 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_RUNTIME_H__
+#define __BKE_MESH_RUNTIME_H__
+
+/** \file BKE_mesh_runtime.h
+ * \ingroup bke
+ *
+ * This file contains access functions for the Mesh.runtime struct.
+ */
+
+#include "BKE_customdata.h" /* for CustomDataMask */
+
+struct ColorBand;
+struct CustomData;
+struct Depsgraph;
+struct KeyBlock;
+struct Mesh;
+struct MLoop;
+struct MLoopTri;
+struct MVertTri;
+struct Object;
+struct Scene;
+
+/* Undefine to hide DerivedMesh-based function declarations */
+#undef USE_DERIVEDMESH
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh;
+#endif
+
+void BKE_mesh_runtime_reset(struct Mesh *mesh);
+int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
+void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
+const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh);
+bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh);
+bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh);
+void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh);
+void BKE_mesh_runtime_clear_cache(struct Mesh *mesh);
+
+void BKE_mesh_runtime_verttri_from_looptri(
+ struct MVertTri *r_verttri,
+ const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num);
+
+/* NOTE: the functions below are defined in DerivedMesh.c, and are intended to be moved
+ * to a more suitable location when that file is removed.
+ * They should also be renamed to use conventions from BKE, not old DerivedMesh.c.
+ * For now keep the names similar to avoid confusion. */
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_get_derived_final(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+#endif
+struct Mesh *mesh_get_eval_final(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, CustomDataMask dataMask);
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_get_derived_deform(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+#endif
+struct Mesh *mesh_get_eval_deform(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+
+struct Mesh *mesh_create_eval_final_render(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_create_derived_index_render(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask, int index);
+#endif
+struct Mesh *mesh_create_eval_final_index_render(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask, int index);
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_create_derived_view(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+#endif
+struct Mesh *mesh_create_eval_final_view(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+
+void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed, struct Mesh *me, struct KeyBlock *kb);
+
+
+#ifndef NDEBUG
+char *BKE_mesh_runtime_debug_info(struct Mesh *me_eval);
+void BKE_mesh_runtime_debug_print(struct Mesh *me_eval);
+void BKE_mesh_runtime_debug_print_cdlayers(struct CustomData *data);
+bool BKE_mesh_runtime_is_valid(struct Mesh *me_eval);
+#endif /* NDEBUG */
+
+#endif /* __BKE_MESH_RUNTIME_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
new file mode 100644
index 00000000000..62d8f3ada84
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -0,0 +1,68 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_TANGENT_H__
+#define __BKE_MESH_TANGENT_H__
+
+/** \file BKE_mesh_tangent.h
+ * \ingroup bke
+ */
+
+void BKE_mesh_calc_loop_tangent_single_ex(
+ const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
+ float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
+ const int numLoops, const struct MPoly *mpolys, const int numPolys,
+ struct ReportList *reports);
+void BKE_mesh_calc_loop_tangent_single(
+ struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
+
+void BKE_mesh_calc_loop_tangent_ex(
+ const struct MVert *mvert,
+ const struct MPoly *mpoly, const uint mpoly_len,
+ const struct MLoop *mloop,
+ const struct MLoopTri *looptri, const uint looptri_len,
+
+ struct CustomData *loopdata,
+ bool calc_active_tangent,
+ const char (*tangent_names)[64], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ struct CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p);
+
+void BKE_mesh_calc_loop_tangents(
+ struct Mesh *me_eval, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len);
+
+/* Helpers */
+void BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ struct CustomData *uv_data, struct CustomData *tan_data, int numLoopData,
+ const char *layer_name);
+
+#define DM_TANGENT_MASK_ORCO (1 << 9)
+void BKE_mesh_calc_loop_tangent_step_0(
+ const struct CustomData *loopData, bool calc_active_tangent,
+ const char (*tangent_names)[64], int tangent_names_count,
+ bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+ char *ract_uv_name, char *rren_uv_name, short *rtangent_mask);
+
+#endif /* __BKE_MESH_TANGENT_H__ */
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 2d39ac4d102..6f3150880fa 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -33,11 +33,12 @@
#include "BKE_customdata.h"
struct ID;
+struct Depsgraph;
struct DerivedMesh;
-struct DagForest;
-struct DagNode;
+struct Mesh;
struct Object;
struct Scene;
+struct ViewLayer;
struct ListBase;
struct bArmature;
struct Main;
@@ -118,27 +119,23 @@ typedef enum ModifierApplyFlag {
MOD_APPLY_IGNORE_SIMPLIFY = 1 << 3, /* Ignore scene simplification flag and use subdivisions
* level set in multires modifier.
*/
- MOD_APPLY_ALLOW_GPU = 1 << 4, /* Allow modifier to be applied and stored in the GPU.
- * Used by the viewport in order to be able to have SS
- * happening on GPU.
- * Render pipeline (including viewport render) should
- * have DM on the CPU.
- */
} ModifierApplyFlag;
-
typedef struct ModifierUpdateDepsgraphContext {
struct Scene *scene;
struct Object *object;
-
- /* Old depsgraph node handle. */
- struct DagForest *forest;
- struct DagNode *obNode;
-
- /* new depsgraph node handle. */
struct DepsNodeHandle *node;
} ModifierUpdateDepsgraphContext;
+/* Contains the information for deformXXX and applyXXX functions below that
+ * doesn't change between consecutive modifiers. */
+typedef struct ModifierEvalContext {
+ struct Depsgraph *depsgraph;
+ struct Object *object;
+ ModifierApplyFlag flag;
+} ModifierEvalContext;
+
+
typedef struct ModifierTypeInfo {
/* The user visible name for this modifier */
char name[32];
@@ -159,73 +156,61 @@ typedef struct ModifierTypeInfo {
/* Copy instance data for this modifier type. Should copy all user
* level settings to the target modifier.
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
- void (*copyData)(const struct ModifierData *md, struct ModifierData *target);
+ void (*copyData)(const struct ModifierData *md, struct ModifierData *target, const int flag);
+
+
+ /********************* Deform modifier functions *********************/ /* DEPRECATED */
+
+ void (*deformVerts_DM_removed)(void);
+ void (*deformMatrices_DM_removed)(void);
+ void (*deformVertsEM_DM_removed)(void);
+ void (*deformMatricesEM_DM_removed)(void);
+
+ /********************* Non-deform modifier functions *********************/ /* DEPRECATED */
+
+ void (*applyModifier_DM_removed)(void);
/********************* Deform modifier functions *********************/
/* Only for deform types, should apply the deformation
* to the given vertex array. If the deformer requires information from
- * the object it can obtain it from the derivedData argument if non-NULL,
+ * the object it can obtain it from the mesh argument if non-NULL,
* and otherwise the ob argument.
*/
- void (*deformVerts)(struct ModifierData *md, struct Object *ob,
- struct DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag flag);
+ void (*deformVerts)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
/* Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode) */
- void (*deformMatrices)(struct ModifierData *md, struct Object *ob,
- struct DerivedMesh *derivedData,
- float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
+ void (*deformMatrices)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
/* Like deformVerts but called during editmode (for supporting modifiers)
*/
- void (*deformVertsEM)(struct ModifierData *md, struct Object *ob,
- struct BMEditMesh *editData, struct DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts);
+ void (*deformVertsEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
/* Set deform matrix per vertex for crazyspace correction */
- void (*deformMatricesEM)(struct ModifierData *md, struct Object *ob,
- struct BMEditMesh *editData, struct DerivedMesh *derivedData,
- float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
+ void (*deformMatricesEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
/********************* Non-deform modifier functions *********************/
- /* For non-deform types: apply the modifier and return a derived
- * data object (type is dependent on object type).
+ /* For non-deform types: apply the modifier and return a mesh object.
*
- * The derivedData argument should always be non-NULL; the modifier
- * should read the object data from the derived object instead of the
+ * The mesh argument should always be non-NULL; the modifier
+ * should read the object data from the mesh object instead of the
* actual object data.
*
- * The useRenderParams argument indicates if the modifier is being
- * applied in the service of the renderer which may alter quality
- * settings.
- *
- * The isFinalCalc parameter indicates if the modifier is being
- * calculated for a final result or for something temporary
- * (like orcos). This is a hack at the moment, it is meant so subsurf
- * can know if it is safe to reuse its internal cache.
- *
- * The modifier may reuse the derivedData argument (i.e. return it in
+ * The modifier may reuse the mesh argument (i.e. return it in
* modified form), but must not release it.
*/
- struct DerivedMesh *(*applyModifier)(struct ModifierData *md, struct Object *ob,
- struct DerivedMesh *derivedData,
- ModifierApplyFlag flag);
-
- /* Like applyModifier but called during editmode (for supporting
- * modifiers).
- *
- * The derived object that is returned must support the operations that
- * are expected from editmode objects. The same qualifications regarding
- * derivedData apply as for applyModifier.
- */
- struct DerivedMesh *(*applyModifierEM)(struct ModifierData *md, struct Object *ob,
- struct BMEditMesh *editData,
- struct DerivedMesh *derivedData,
- ModifierApplyFlag flag);
+ struct Mesh *(*applyModifier)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh);
/********************* Optional functions *********************/
@@ -270,21 +255,12 @@ typedef struct ModifierTypeInfo {
*
* This function is optional (assumes never disabled if not present).
*/
- bool (*isDisabled)(struct ModifierData *md, int userRenderParams);
-
- /* Add the appropriate relations to the DEP graph depending on the
- * modifier data.
- *
- * This function is optional.
- */
- void (*updateDepgraph)(struct ModifierData *md,
- const ModifierUpdateDepsgraphContext *ctx);
+ bool (*isDisabled)(const struct Scene *scene, struct ModifierData *md, bool userRenderParams);
/* Add the appropriate relations to the dependency graph.
*
* This function is optional.
*/
- /* TODO(sergey): Remove once we finally switched to the new depsgraph. */
void (*updateDepsgraph)(struct ModifierData *md,
const ModifierUpdateDepsgraphContext *ctx);
@@ -297,7 +273,7 @@ typedef struct ModifierTypeInfo {
/* True when a deform modifier uses normals, the requiredDataMask
- * cant be used here because that refers to a normal layer where as
+ * cant be used here because that refers to a normal layer whereas
* in this case we need to know if the deform modifier uses normals.
*
* this is needed because applying 2 deform modifiers will give the
@@ -351,7 +327,7 @@ void modifier_free(struct ModifierData *md);
bool modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
-void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target);
+void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target, const int flag);
void modifier_copyData(struct ModifierData *md, struct ModifierData *target);
void modifier_copyData_ex(struct ModifierData *md, struct ModifierData *target, const int flag);
bool modifier_dependsOnTime(struct ModifierData *md);
@@ -361,7 +337,7 @@ bool modifier_couldBeCage(struct Scene *scene, struct ModifierData *md)
bool modifier_isCorrectableDeformed(struct ModifierData *md);
bool modifier_isSameTopology(ModifierData *md);
bool modifier_isNonGeometrical(ModifierData *md);
-bool modifier_isEnabled(struct Scene *scene, struct ModifierData *md, int required_mode);
+bool modifier_isEnabled(const struct Scene *scene, struct ModifierData *md, int required_mode);
void modifier_setError(struct ModifierData *md, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
bool modifier_isPreview(struct ModifierData *md);
@@ -387,6 +363,7 @@ bool modifiers_isClothEnabled(struct Object *ob);
bool modifiers_isParticleEnabled(struct Object *ob);
struct Object *modifiers_isDeformedByArmature(struct Object *ob);
+struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob);
struct Object *modifiers_isDeformedByLattice(struct Object *ob);
struct Object *modifiers_isDeformedByCurve(struct Object *ob);
bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
@@ -433,28 +410,41 @@ void modifier_path_init(char *path, int path_maxlen, const char *name);
const char *modifier_path_relbase(struct Main *bmain, struct Object *ob);
const char *modifier_path_relbase_from_global(struct Object *ob);
-/* wrappers for modifier callbacks */
+/* wrappers for modifier callbacks that ensure valid normals */
-struct DerivedMesh *modwrap_applyModifier(
- ModifierData *md, struct Object *ob,
- struct DerivedMesh *dm,
- ModifierApplyFlag flag);
-
-struct DerivedMesh *modwrap_applyModifierEM(
- ModifierData *md, struct Object *ob,
- struct BMEditMesh *em,
- struct DerivedMesh *dm,
- ModifierApplyFlag flag);
+struct Mesh *modwrap_applyModifier(
+ ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *me);
void modwrap_deformVerts(
- ModifierData *md, struct Object *ob,
- struct DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag flag);
+ ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *me,
+ float (*vertexCos)[3], int numVerts);
void modwrap_deformVertsEM(
- ModifierData *md, struct Object *ob,
- struct BMEditMesh *em, struct DerivedMesh *dm,
+ ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *em, struct Mesh *me,
float (*vertexCos)[3], int numVerts);
+#define applyModifier_DM_wrapper(NEW_FUNC_NAME, OLD_FUNC_NAME) \
+ static Mesh *NEW_FUNC_NAME(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) \
+ { \
+ DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING); \
+ DerivedMesh *ndm = OLD_FUNC_NAME(md, ctx, dm); \
+ if (ndm != dm) dm->release(dm); \
+ DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true); \
+ return mesh; \
+ }
+
+/* wrappers for modifier callbacks that accept Mesh and select the proper implementation
+ * depending on if the modifier has been ported to Mesh or is still using DerivedMesh
+ */
+
+struct DerivedMesh *modifier_applyModifier_DM_deprecated(
+ struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct DerivedMesh *dm);
+
+struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(
+ struct Object *ob_eval, bool *r_free_mesh);
+
#endif
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index b79f37fd040..5071724d772 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -32,7 +32,7 @@
* \author Sergey Sharybin
*/
-struct EvaluationContext;
+struct Depsgraph;
struct ImBuf;
struct Main;
struct MovieClip;
@@ -84,10 +84,11 @@ struct ImBuf *BKE_movieclip_anim_ibuf_for_frame(struct MovieClip *clip, struct M
bool BKE_movieclip_has_cached_frame(struct MovieClip *clip, struct MovieClipUser *user);
bool BKE_movieclip_put_frame_if_possible(struct MovieClip *clip, struct MovieClipUser *user, struct ImBuf *ibuf);
-/* Evaluaiton. */
-void BKE_movieclip_eval_update(struct EvaluationContext *eval_ctx, struct MovieClip *clip);
+/* Evaluation. */
+void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, struct MovieClip *clip);
+void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, struct MovieClip *clip);
-/* cacheing flags */
+/* caching flags */
#define MOVIECLIP_CACHE_SKIP (1 << 0)
/* postprocessing flags */
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index d8199c96d6b..190ee9e7270 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -32,7 +32,11 @@
* \ingroup bke
*/
+#include "BLI_compiler_compat.h"
+
enum MultiresModifiedFlags;
+
+struct Depsgraph;
struct DerivedMesh;
struct MDisps;
struct Mesh;
@@ -41,6 +45,7 @@ struct Multires;
struct MultiresModifierData;
struct Object;
struct Scene;
+struct SubdivCCG;
struct MLoop;
struct MVert;
@@ -60,7 +65,7 @@ void multires_force_render_update(struct Object *ob);
void multires_force_external_reload(struct Object *ob);
/* internal, only called in subsurf_ccg.c */
-void multires_modifier_update_mdisps(struct DerivedMesh *dm);
+void multires_modifier_update_mdisps(struct DerivedMesh *dm, struct Scene *scene);
void multires_modifier_update_hidden(struct DerivedMesh *dm);
void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, struct Object *ob);
@@ -74,43 +79,33 @@ typedef enum {
struct DerivedMesh *multires_make_derived_from_derived(struct DerivedMesh *dm,
struct MultiresModifierData *mmd,
+ struct Scene *scene,
struct Object *ob,
MultiresFlags flags);
struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene,
struct ModifierData *lastmd);
struct MultiresModifierData *get_multires_modifier(struct Scene *scene, struct Object *ob, bool use_first);
-struct DerivedMesh *get_multires_dm(struct Scene *scene, struct MultiresModifierData *mmd,
- struct Object *ob);
-void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction);
-void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob);
-void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int updateblock, int simple);
+int multires_get_level(const struct Scene *scene, const struct Object *ob, const struct MultiresModifierData *mmd,
+ bool render, bool ignore_simplify);
+struct Mesh *BKE_multires_create_mesh(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct MultiresModifierData *mmd, struct Object *ob);
+void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *object, int direction);
+void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *ob);
+void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *ob, int updateblock, int simple);
void multiresModifier_sync_levels_ex(
- struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst);
-int multiresModifier_reshape(struct Scene *scene, struct MultiresModifierData *mmd,
- struct Object *dst, struct Object *src);
-int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierData *mmd,
- struct Object *ob, struct DerivedMesh *srcdm);
-int multiresModifier_reshapeFromDeformMod(struct Scene *scene, struct MultiresModifierData *mmd,
- struct Object *ob, struct ModifierData *md);
+ struct Scene *scene, struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst);
void multires_stitch_grids(struct Object *);
-/*switch mdisp data in dm between tangent and object space*/
-enum {
- MULTIRES_SPACE_TANGENT,
- MULTIRES_SPACE_OBJECT,
- MULTIRES_SPACE_ABSOLUTE
-};
-void multires_set_space(struct DerivedMesh *dm, struct Object *ob, int from, int to);
-
/* Related to the old multires */
void multires_free(struct Multires *mr);
void multires_load_old(struct Object *ob, struct Mesh *me);
void multires_load_old_250(struct Mesh *);
-void multiresModifier_scale_disp(struct Scene *scene, struct Object *ob);
-void multiresModifier_prepare_join(struct Scene *scene, struct Object *ob, struct Object *to_ob);
+void multiresModifier_scale_disp(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+void multiresModifier_prepare_join(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Object *to_ob);
int multires_mdisp_corners(struct MDisps *s);
@@ -121,4 +116,53 @@ void multires_topology_changed(struct Mesh *me);
void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v);
int mdisp_rot_face_to_crn(struct MVert *mvert, struct MPoly *mpoly, struct MLoop *mloops, const struct MLoopTri *lt, const int face_side, const float u, const float v, float *x, float *y);
+/* Reshaping, define in multires_reshape.c */
+
+bool multiresModifier_reshapeFromObject(
+ struct Depsgraph *depsgraph,
+ struct MultiresModifierData *mmd,
+ struct Object *dst,
+ struct Object *src);
+bool multiresModifier_reshapeFromDeformModifier(
+ struct Depsgraph *depsgraph,
+ struct MultiresModifierData *mmd,
+ struct Object *ob,
+ struct ModifierData *md);
+bool multiresModifier_reshapeFromCCG(
+ const int tot_level,
+ struct Mesh *coarse_mesh,
+ struct SubdivCCG *subdiv_ccg);
+
+/* Subdivision integration, defined in multires_subdiv.c */
+
+struct SubdivSettings;
+struct SubdivToMeshSettings;
+
+void BKE_multires_subdiv_settings_init(
+ struct SubdivSettings *settings,
+ const struct MultiresModifierData *mmd);
+
+/* TODO(sergey): Replace this set of boolean flags with bitmask. */
+void BKE_multires_subdiv_mesh_settings_init(
+ struct SubdivToMeshSettings *mesh_settings,
+ const struct Scene *scene,
+ const struct Object *object,
+ const struct MultiresModifierData *mmd,
+ const bool use_render_params,
+ const bool ignore_simplify);
+
+/* General helpers. */
+
+/* For a given partial derivatives of a ptex face get tangent matrix for
+ * displacement.
+ * Corner needs to be known to properly "rotate" partial derivatives.
+ */
+BLI_INLINE void BKE_multires_construct_tangent_matrix(
+ float tangent_matrix[3][3],
+ const float dPdu[3],
+ const float dPdv[3],
+ const int corner);
+
#endif /* __BKE_MULTIRES_H__ */
+
+#include "intern/multires_inline.h"
diff --git a/source/blender/blenkernel/BKE_navmesh_conversion.h b/source/blender/blenkernel/BKE_navmesh_conversion.h
deleted file mode 100644
index 3be363f4d7b..00000000000
--- a/source/blender/blenkernel/BKE_navmesh_conversion.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_NAVMESH_CONVERSION_H__
-#define __BKE_NAVMESH_CONVERSION_H__
-
-/** \file BKE_navmesh_conversion.h
- * \ingroup bke
- */
-
-struct DerivedMesh;
-
-/* navmesh_conversion.c */
-int buildNavMeshDataByDerivedMesh(struct DerivedMesh *dm, int *vertsPerPoly,
- int *nverts, float **verts,
- int *ndtris, unsigned short **dtris,
- int *npolys, unsigned short **dmeshes,
- unsigned short **polys, int **dtrisToPolysMap,
- int **dtrisToTrisMap, int **trisToFacesMap);
-
-int buildRawVertIndicesData(struct DerivedMesh *dm, int *nverts, float **verts,
- int *ntris, unsigned short **tris, int **trisToFacesMap,
- int **recastData);
-
-int buildNavMeshData(const int nverts, const float *verts,
- const int ntris, const unsigned short *tris,
- const int *recastData, const int *trisToFacesMap,
- int *ndtris, unsigned short **dtris,
- int *npolys, unsigned short **dmeshes, unsigned short **polys,
- int *vertsPerPoly, int **dtrisToPolysMap, int **dtrisToTrisMap);
-
-int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys,
- unsigned short *polys, const unsigned short *dmeshes,
- const float *verts, const unsigned short *dtris,
- const int *dtrisToPolysMap);
-
-int polyNumVerts(const unsigned short *p, const int vertsPerPoly);
-int polyIsConvex(const unsigned short *p, const int vertsPerPoly, const float *verts);
-int polyFindVertex(const unsigned short *p, const int vertsPerPoly, unsigned short vertexIdx);
-float distPointToSegmentSq(const float *point, const float *a, const float *b);
-
-
-#endif /* NAVMESH_CONVERSION_H */
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index 37929bae042..a42819e52a2 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -47,13 +47,13 @@ struct PropertyRNA;
/* ----------------------------- */
/* Data Management */
-void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip);
-void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt);
-void BKE_nla_tracks_free(ListBase *tracks);
+void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user);
+void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user);
+void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user);
-struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain, struct NlaStrip *strip, const bool use_same_action);
-struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain, struct NlaTrack *nlt, const bool use_same_actions);
-void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src);
+struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain, struct NlaStrip *strip, const bool use_same_action, const int flag);
+struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain, struct NlaTrack *nlt, const bool use_same_actions, const int flag);
+void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src, const int flag);
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt, struct NlaTrack *prev);
struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 3d78b95001d..5f0635037c2 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -74,6 +74,7 @@ struct PointerRNA;
struct RenderData;
struct Scene;
struct Tex;
+struct ViewRender;
struct SpaceNode;
struct ARegion;
struct ColorManagedViewSettings;
@@ -151,7 +152,7 @@ typedef struct bNodeType {
float width, minwidth, maxwidth;
float height, minheight, maxheight;
- short nclass, flag, compatibility;
+ short nclass, flag;
/* templates for static sockets */
bNodeSocketTemplate *inputs, *outputs;
@@ -250,10 +251,6 @@ typedef struct bNodeType {
#define NODE_CLASS_SHADER 40
#define NODE_CLASS_LAYOUT 100
-/* nodetype->compatibility */
-#define NODE_OLD_SHADING 1
-#define NODE_NEW_SHADING 2
-
/* node resize directions */
#define NODE_RESIZE_TOP 1
#define NODE_RESIZE_BOTTOM 2
@@ -343,7 +340,7 @@ void ntreeUserIncrefID(struct bNodeTree *ntree);
void ntreeUserDecrefID(struct bNodeTree *ntree);
-struct bNodeTree *ntreeFromID(struct ID *id);
+struct bNodeTree *ntreeFromID(const struct ID *id);
void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist, const bool lib_local);
struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type);
@@ -453,7 +450,11 @@ struct bNode *nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntre
void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node);
+/* Frees the node itself, without affect to anything else. */
void nodeFreeNode(struct bNodeTree *ntree, struct bNode *node);
+/* Will additionally cleanup things like f-curves which uses this node. */
+void nodeDeleteNode(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
+
struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree, struct bNode *node_src, const int flag);
struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node);
@@ -469,6 +470,10 @@ bool nodeAttachNodeCheck(struct bNode *node, struct bNode *parent);
void nodeAttachNode(struct bNode *node, struct bNode *parent);
void nodeDetachNode(struct bNode *node);
+void nodePositionRelative(struct bNode *from_node, struct bNode *to_node,
+ struct bNodeSocket *from_sock, struct bNodeSocket *to_sock);
+void nodePositionPropagate(struct bNode *node);
+
struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name);
int nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **nodep, int *sockindex);
struct bNode *nodeFindRootParent(bNode *node);
@@ -496,7 +501,6 @@ struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
void nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
-void nodeSynchronizeID(struct bNode *node, bool copy_to_id);
int nodeSocketIsHidden(struct bNodeSocket *sock);
void ntreeTagUsedSockets(struct bNodeTree *ntree);
@@ -600,7 +604,6 @@ void node_type_update(struct bNodeType *ntype,
void node_type_exec(struct bNodeType *ntype, NodeInitExecFunction initexecfunc, NodeFreeExecFunction freeexecfunc, NodeExecFunction execfunc);
void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc);
void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *));
-void node_type_compatibility(struct bNodeType *ntype, short compatibility);
/** \} */
@@ -690,27 +693,33 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
} ((void)0)
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Node Tree
+ */
+
+void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, const int layer_index);
+
/* -------------------------------------------------------------------- */
/** \name Shader Nodes
* \{ */
-struct ShadeInput;
-struct ShadeResult;
/* note: types are needed to restore callbacks, don't change values */
/* range 1 - 100 is reserved for common nodes */
/* using toolbox, we add node groups by assuming the values below don't exceed NODE_GROUP_MENU for now */
-#define SH_NODE_OUTPUT 1
+//#define SH_NODE_OUTPUT 1
-#define SH_NODE_MATERIAL 100
+//#define SH_NODE_MATERIAL 100
#define SH_NODE_RGB 101
#define SH_NODE_VALUE 102
#define SH_NODE_MIX_RGB 103
#define SH_NODE_VALTORGB 104
#define SH_NODE_RGBTOBW 105
-#define SH_NODE_TEXTURE 106
+#define SH_NODE_SHADERTORGB 106
+//#define SH_NODE_TEXTURE 106
#define SH_NODE_NORMAL 107
-#define SH_NODE_GEOMETRY 108
+//#define SH_NODE_GEOMETRY 108
#define SH_NODE_MAPPING 109
#define SH_NODE_CURVE_VEC 110
#define SH_NODE_CURVE_RGB 111
@@ -718,7 +727,7 @@ struct ShadeResult;
#define SH_NODE_MATH 115
#define SH_NODE_VECT_MATH 116
#define SH_NODE_SQUEEZE 117
-#define SH_NODE_MATERIAL_EXT 118
+//#define SH_NODE_MATERIAL_EXT 118
#define SH_NODE_INVERT 119
#define SH_NODE_SEPRGB 120
#define SH_NODE_COMBRGB 121
@@ -727,7 +736,7 @@ struct ShadeResult;
#define SH_NODE_OUTPUT_MATERIAL 124
#define SH_NODE_OUTPUT_WORLD 125
-#define SH_NODE_OUTPUT_LAMP 126
+#define SH_NODE_OUTPUT_LIGHT 126
#define SH_NODE_FRESNEL 127
#define SH_NODE_MIX_SHADER 128
#define SH_NODE_ATTRIBUTE 129
@@ -790,6 +799,7 @@ struct ShadeResult;
#define SH_NODE_TEX_POINTDENSITY 192
#define SH_NODE_BSDF_PRINCIPLED 193
#define SH_NODE_TEX_IES 194
+#define SH_NODE_EEVEE_SPECULAR 195
#define SH_NODE_BEVEL 197
#define SH_NODE_DISPLACEMENT 198
#define SH_NODE_VECTOR_DISPLACEMENT 199
@@ -806,14 +816,11 @@ struct ShadeResult;
struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree);
void ntreeShaderEndExecTree(struct bNodeTreeExec *exec);
-bool ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr);
-void ntreeShaderGetTexcoMode(struct bNodeTree *ntree, int osa, short *texco, int *mode);
-
-/* switch material render loop */
-extern void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *);
-void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, struct ShadeResult *));
+bool ntreeShaderExecTree(struct bNodeTree *ntree, int thread);
+struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target);
-void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat, short compatibility);
+void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat,
+ bool *has_surface_output, bool *has_volume_output);
/** \} */
@@ -985,7 +992,7 @@ void ntreeCompositTagRender(struct Scene *sce);
int ntreeCompositTagAnimated(struct bNodeTree *ntree);
void ntreeCompositTagGenerators(struct bNodeTree *ntree);
void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
-void ntreeCompositRegisterPass(struct bNodeTree *ntree, struct Scene *scene, struct SceneRenderLayer *srl, const char *name, int type);
+void ntreeCompositRegisterPass(struct bNodeTree *ntree, struct Scene *scene, struct ViewLayer *view_layer, const char *name, int type);
void ntreeCompositClearTags(struct bNodeTree *ntree);
struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree, struct bNode *node,
@@ -1049,10 +1056,19 @@ struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree);
void ntreeTexEndExecTree(struct bNodeTreeExec *exec);
int ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target,
float coord[3], float dxt[3], float dyt[3], int osatex, const short thread,
- struct Tex *tex, short which_output, int cfra, int preview, struct ShadeInput *shi, struct MTex *mtex);
+ struct Tex *tex, short which_output, int cfra, int preview, struct MTex *mtex);
/** \} */
void init_nodesystem(void);
void free_nodesystem(void);
+/* -------------------------------------------------------------------- */
+/* evaluation support, */
+
+struct Depsgraph;
+
+void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
+ struct bNodeTree *ntree_dst,
+ const struct bNodeTree *ntree_src);
+
#endif /* __BKE_NODE_H__ */
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 677d6b3fba2..35de1501494 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -36,52 +36,74 @@ extern "C" {
#include "BLI_compiler_attrs.h"
struct Base;
-struct EvaluationContext;
+struct Depsgraph;
+struct GpencilModifierData;
struct Scene;
+struct ShaderFxData;
+struct ViewLayer;
+struct ID;
struct Object;
struct BoundBox;
struct View3D;
struct SoftBody;
-struct BulletSoftBody;
struct MovieClip;
struct Main;
+struct Mesh;
struct RigidBodyWorld;
struct HookModifierData;
struct ModifierData;
+struct HookGpencilModifierData;
+struct RegionView3D;
+
+#include "DNA_object_enums.h"
void BKE_object_workob_clear(struct Object *workob);
-void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob);
+void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Object *workob);
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
-struct SoftBody *copy_softbody(const struct SoftBody *sb, const int flag);
-struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb, const int flag);
+void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag);
struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag);
void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src, const int flag);
-void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_particlesystems(struct Object *ob);
void BKE_object_free_softbody(struct Object *ob);
-void BKE_object_free_bulletsoftbody(struct Object *ob);
void BKE_object_free_curve_cache(struct Object *ob);
-void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob);
void BKE_object_free(struct Object *ob);
void BKE_object_free_derived_caches(struct Object *ob);
+void BKE_object_free_derived_mesh_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
+void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd);
+bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModifierData *md);
+
+bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
-void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
+void BKE_object_link_modifiers(struct Scene *scene, struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_modifiers(struct Object *ob, const int flag);
+void BKE_object_free_shaderfx(struct Object *ob, const int flag);
-void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
+void BKE_object_make_proxy(struct Main *bmain, struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest);
bool BKE_object_is_in_editmode(const struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(const struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(const struct Object *ob);
+bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode);
+bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode);
+
+bool BKE_object_data_is_in_editmode(const struct ID *id);
+
+typedef enum eObjectVisibilityCheck {
+ OB_VISIBILITY_CHECK_FOR_VIEWPORT,
+ OB_VISIBILITY_CHECK_FOR_RENDER,
+ OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE,
+} eObjectVisibilityCheck;
+
+bool BKE_object_is_visible(const struct Object *ob, const eObjectVisibilityCheck mode);
void BKE_object_init(struct Object *ob);
struct Object *BKE_object_add_only_object(
@@ -89,22 +111,21 @@ struct Object *BKE_object_add_only_object(
int type, const char *name)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
struct Object *BKE_object_add(
- struct Main *bmain, struct Scene *scene,
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer,
int type, const char *name)
- ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL;
+ ATTR_NONNULL(1, 2, 3) ATTR_RETURNS_NONNULL;
+struct Object *BKE_object_add_from(
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer,
+ int type, const char *name, struct Object *ob_src)
+ ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL;
+struct Object *BKE_object_add_for_data(
+ struct Main *bmain, struct ViewLayer *view_layer,
+ int type, const char *name, struct ID *data, bool do_id_user) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(
struct Main *bmain,
int type, const char *name)
ATTR_NONNULL(1);
-void BKE_object_lod_add(struct Object *ob);
-void BKE_object_lod_sort(struct Object *ob);
-bool BKE_object_lod_remove(struct Object *ob, int level);
-void BKE_object_lod_update(struct Object *ob, const float camera_position[3]);
-bool BKE_object_lod_is_usable(struct Object *ob, struct Scene *scene);
-struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene);
-struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
-
void BKE_object_copy_data(struct Main *bmain, struct Object *ob_dst, const struct Object *ob_src, const int flag);
struct Object *BKE_object_copy(struct Main *bmain, const struct Object *ob);
void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local);
@@ -120,20 +141,36 @@ void BKE_object_mat3_to_rot(struct Object *ob, float mat[3][3], bool use_compat)
void BKE_object_to_mat3(struct Object *ob, float mat[3][3]);
void BKE_object_to_mat4(struct Object *ob, float mat[4][4]);
void BKE_object_apply_mat4(struct Object *ob, float mat[4][4], const bool use_compat, const bool use_parent);
+void BKE_object_apply_mat4_ex(struct Object *ob, float mat[4][4], struct Object *parent, float parentinv[4][4], const bool use_compat);
void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]);
bool BKE_object_pose_context_check(const struct Object *ob);
struct Object *BKE_object_pose_armature_get(struct Object *ob);
+struct Object *BKE_object_pose_armature_get_visible(struct Object *ob, struct ViewLayer *view_layer, struct View3D *v3d);
+
+struct Object **BKE_object_pose_array_get_ex(struct ViewLayer *view_layer, struct View3D *v3d, unsigned int *r_objects_len, bool unique);
+struct Object **BKE_object_pose_array_get_unique(struct ViewLayer *view_layer, struct View3D *v3d, unsigned int *r_objects_len);
+struct Object **BKE_object_pose_array_get(struct ViewLayer *view_layer, struct View3D *v3d, unsigned int *r_objects_len);
-void BKE_object_get_parent_matrix(struct Scene *scene, struct Object *ob, struct Object *par, float parentmat[4][4]);
-void BKE_object_where_is_calc(struct Scene *scene, struct Object *ob);
+struct Base **BKE_object_pose_base_array_get_ex(struct ViewLayer *view_layer, struct View3D *v3d, unsigned int *r_bases_len, bool unique);
+struct Base **BKE_object_pose_base_array_get_unique(struct ViewLayer *view_layer, struct View3D *v3d, unsigned int *r_bases_len);
+struct Base **BKE_object_pose_base_array_get(struct ViewLayer *view_layer, struct View3D *v3d, unsigned int *r_bases_len);
+
+void BKE_object_get_parent_matrix(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ struct Object *par, float parentmat[4][4]);
+void BKE_object_where_is_calc(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_object_where_is_calc_ex(
- struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]);
-void BKE_object_where_is_calc_time(struct Scene *scene, struct Object *ob, float ctime);
+ struct Depsgraph *depsgraph, struct Scene *scene, struct RigidBodyWorld *rbw,
+ struct Object *ob, float r_originmat[3][3]);
+void BKE_object_where_is_calc_time(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime);
void BKE_object_where_is_calc_time_ex(
- struct Scene *scene, struct Object *ob, float ctime,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime,
struct RigidBodyWorld *rbw, float r_originmat[3][3]);
-void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float obmat[4][4]);
+void BKE_object_where_is_calc_mat4(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float obmat[4][4]);
/* possibly belong in own moduke? */
struct BoundBox *BKE_boundbox_alloc_unit(void);
@@ -147,20 +184,18 @@ void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
void BKE_object_dimensions_set(struct Object *ob, const float value[3]);
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
+void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval);
void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
bool BKE_object_minmax_dupli(
- struct Main *bmain, struct Scene *scene,
- struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ float r_min[3], float r_max[3], const bool use_hidden);
/* sometimes min-max isn't enough, we need to loop over each point */
void BKE_object_foreach_display_point(
struct Object *ob, float obmat[4][4],
void (*func_cb)(const float[3], void *), void *user_data);
void BKE_scene_foreach_display_point(
- struct Main *bmain,
- struct Scene *scene,
- struct View3D *v3d,
- const short flag,
+ struct Depsgraph *depsgraph,
void (*func_cb)(const float[3], void *), void *user_data);
bool BKE_object_parent_loop_check(const struct Object *parent, const struct Object *ob);
@@ -188,54 +223,62 @@ void BKE_object_tfm_protected_restore(
/* Dependency graph evaluation callbacks. */
void BKE_object_eval_local_transform(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Object *ob);
void BKE_object_eval_parent(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void BKE_object_eval_constraints(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
-void BKE_object_eval_done(struct EvaluationContext *eval_ctx, struct Object *ob);
+void BKE_object_eval_transform_final(
+ struct Depsgraph *depsgraph, struct Object *ob);
bool BKE_object_eval_proxy_copy(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Object *object);
void BKE_object_eval_uber_transform(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Object *ob);
void BKE_object_eval_uber_data(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
-void BKE_object_eval_cloth(
- struct EvaluationContext *eval_ctx,
+void BKE_object_eval_boundbox(struct Depsgraph *depsgraph, struct Object *object);
+
+void BKE_object_eval_ptcache_reset(
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *object);
-
void BKE_object_eval_transform_all(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *object);
-void BKE_object_handle_data_update(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-void BKE_object_handle_update(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx,
+void BKE_object_eval_update_shading(
+ struct Depsgraph *depsgraph,
+ struct Object *object);
+void BKE_object_data_select_update(
+ struct Depsgraph *depsgraph,
+ struct ID *object_data);
+
+void BKE_object_eval_flush_base_flags(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene, const int view_layer_index,
+ struct Object *object, int base_index,
+ const bool is_from_set);
+
+void BKE_object_handle_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+void BKE_object_handle_update(struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *ob);
void BKE_object_handle_update_ex(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene, struct Object *ob,
struct RigidBodyWorld *rbw,
const bool do_proxy_update);
@@ -243,6 +286,11 @@ void BKE_object_sculpt_modifiers_changed(struct Object *ob);
int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
+struct Mesh *BKE_object_get_evaluated_mesh(const struct Depsgraph *depsgraph, struct Object *ob);
+struct Mesh *BKE_object_get_final_mesh(struct Object *object);
+struct Mesh *BKE_object_get_pre_modified_mesh(struct Object *object);
+struct Mesh *BKE_object_get_original_mesh(struct Object *object);
+
int BKE_object_insert_ptcache(struct Object *ob);
void BKE_object_delete_ptcache(struct Object *ob, int index);
struct KeyBlock *BKE_object_shapekey_insert(struct Main *bmain, struct Object *ob, const char *name, const bool from_mix);
@@ -263,6 +311,10 @@ void BKE_object_data_relink(struct Object *ob);
struct MovieClip *BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default);
+void BKE_object_runtime_reset(struct Object *object);
+
+void BKE_object_batch_cache_dirty_tag(struct Object *ob);
+
/* this function returns a superset of the scenes selection based on relationships */
typedef enum eObRelationTypes {
@@ -282,20 +334,19 @@ typedef enum eObjectSet {
} eObjectSet;
struct LinkNode *BKE_object_relational_superset(
- struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter);
+ struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter);
struct LinkNode *BKE_object_groups(struct Main *bmain, struct Object *ob);
-void BKE_object_groups_clear(
- struct Main *bmain, struct Scene *scene, struct Base *base, struct Object *object);
+void BKE_object_groups_clear(struct Main *bmain, struct Object *object);
struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md);
bool BKE_object_modifier_update_subframe(
- struct Main *bmain, struct EvaluationContext *eval_ctx,
- struct Scene *scene, struct Object *ob, bool update_mesh,
- int parent_recursion, float frame,
- int type);
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ bool update_mesh, int parent_recursion, float frame, int type);
+
+bool BKE_image_empty_visible_in_view3d(const struct Object *ob, const struct RegionView3D *rv3d);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_object_facemap.h b/source/blender/blenkernel/BKE_object_facemap.h
new file mode 100644
index 00000000000..2607e5aa2dd
--- /dev/null
+++ b/source/blender/blenkernel/BKE_object_facemap.h
@@ -0,0 +1,53 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Antony Riakiotakis
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_OBJECT_FACEMAP_H__
+#define __BKE_OBJECT_FACEMAP_H__
+
+/** \file BKE_object_facemap.h
+ * \ingroup bke
+ * \brief Functions for dealing with object face-maps.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bFaceMap;
+struct ListBase;
+struct Object;
+
+struct bFaceMap *BKE_object_facemap_add(struct Object *ob);
+struct bFaceMap *BKE_object_facemap_add_name(struct Object *ob, const char *name);
+void BKE_object_facemap_remove(struct Object *ob, struct bFaceMap *fmap);
+void BKE_object_facemap_clear(struct Object *ob);
+
+int BKE_object_facemap_name_index(struct Object *ob, const char *name);
+void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap);
+struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name);
+void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_OBJECT_FACEMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 3ea104e656a..e18a063ff52 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -31,6 +31,8 @@
extern "C" {
#endif
+struct OceanModifierData;
+
typedef struct OceanResult {
float disp[3];
float normal[3];
@@ -72,6 +74,8 @@ typedef struct OceanCache {
struct Ocean *BKE_ocean_add(void);
void BKE_ocean_free_data(struct Ocean *oc);
void BKE_ocean_free(struct Ocean *oc);
+bool BKE_ocean_ensure(struct OceanModifierData *omd);
+void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData const *omd);
void BKE_ocean_init(
struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
@@ -99,6 +103,8 @@ void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, in
void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j);
void BKE_ocean_free_cache(struct OceanCache *och);
+void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_outliner_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h
index 454edb40c4e..8a14f8fb041 100644
--- a/source/blender/blenkernel/BKE_outliner_treehash.h
+++ b/source/blender/blenkernel/BKE_outliner_treehash.h
@@ -36,8 +36,12 @@ void *BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore)
/* full rebuild for already allocated hashtable */
void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore);
-/* full rebuild for already allocated hashtable */
+/* clear element usage flags */
+void BKE_outliner_treehash_clear_used(void *treehash);
+
+/* Add/remove hashtable elements */
void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem);
+void BKE_outliner_treehash_remove_element(void *treehash, struct TreeStoreElem *elem);
/* find first unused element with specific type, nr and id */
struct TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index eedf5f7985e..00425de50e0 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -33,13 +33,16 @@
*/
struct bContext;
+struct bToolRef;
struct BMesh;
struct BMFace;
struct Brush;
struct CurveMapping;
+struct EnumPropertyItem;
struct MeshElemMap;
struct GridPaintMask;
struct Main;
+struct Mesh;
struct MLoop;
struct MLoopTri;
struct MFace;
@@ -52,11 +55,15 @@ struct PaletteColor;
struct PBVH;
struct ReportList;
struct Scene;
+struct ViewLayer;
struct Sculpt;
struct StrokeCache;
+struct SubdivCCG;
struct Tex;
struct ImagePool;
struct UnifiedPaintSettings;
+struct Depsgraph;
+struct ToolSettings;
enum eOverlayFlags;
@@ -77,11 +84,14 @@ typedef enum ePaintMode {
/** Image space (2D painting). */
PAINT_MODE_TEXTURE_2D = 4,
PAINT_MODE_SCULPT_UV = 5,
+ PAINT_MODE_GPENCIL = 6,
/** Keep last. */
- PAINT_MODE_INVALID = 6
+ PAINT_MODE_INVALID = 7,
} ePaintMode;
+#define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PAINT_MODE_SCULPT_UV)
+
/* overlay invalidation */
typedef enum eOverlayControlFlags {
PAINT_OVERLAY_INVALID_TEXTURE_PRIMARY = 1,
@@ -97,14 +107,15 @@ typedef enum eOverlayControlFlags {
PAINT_OVERLAY_OVERRIDE_PRIMARY | \
PAINT_OVERLAY_OVERRIDE_CURSOR)
-void BKE_paint_invalidate_overlay_tex(struct Scene *scene, const struct Tex *tex);
-void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct CurveMapping *curve);
+void BKE_paint_invalidate_overlay_tex(struct Scene *scene, struct ViewLayer *view_layer, const struct Tex *tex);
+void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct ViewLayer *view_layer, struct CurveMapping *curve);
void BKE_paint_invalidate_overlay_all(void);
eOverlayControlFlags BKE_paint_get_overlay_flags(void);
void BKE_paint_reset_overlay_invalid(eOverlayControlFlags flag);
void BKE_paint_set_overlay_override(enum eOverlayFlags flag);
/* palettes */
+void BKE_palette_init(struct Palette *palette);
void BKE_palette_free(struct Palette *palette);
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
void BKE_palette_copy_data(
@@ -124,17 +135,24 @@ void BKE_paint_curve_copy_data(
struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc);
void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local);
+bool BKE_paint_ensure(const struct ToolSettings *ts, struct Paint **r_paint);
void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag);
+void BKE_paint_runtime_init(const struct ToolSettings *ts, struct Paint *paint);
+
void BKE_paint_cavity_curve_preset(struct Paint *p, int preset);
-eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode);
+eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode);
struct Paint *BKE_paint_get_active_from_paintmode(struct Scene *sce, ePaintMode mode);
-struct Paint *BKE_paint_get_active(struct Scene *sce);
+const struct EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode);
+const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode);
+uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode);
+struct Paint *BKE_paint_get_active(struct Scene *sce, struct ViewLayer *view_layer);
struct Paint *BKE_paint_get_active_from_context(const struct bContext *C);
ePaintMode BKE_paintmode_get_active_from_context(const struct bContext *C);
+ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref);
struct Brush *BKE_paint_brush(struct Paint *paint);
void BKE_paint_brush_set(struct Paint *paint, struct Brush *br);
struct Palette *BKE_paint_palette(struct Paint *paint);
@@ -168,6 +186,15 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct B
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
+
+/* Tool slot API. */
+void BKE_paint_toolslots_init_from_main(struct Main *bmain);
+void BKE_paint_toolslots_len_ensure(struct Paint *paint, int len);
+void BKE_paint_toolslots_brush_update_ex(struct Paint *paint, struct Brush *brush);
+void BKE_paint_toolslots_brush_update(struct Paint *paint);
+void BKE_paint_toolslots_brush_validate(struct Main *bmain, struct Paint *paint);
+struct Brush *BKE_paint_toolslots_brush_get(struct Paint *paint, int slot_index);
+
/* Used for both vertex color and weight paint */
struct SculptVertexPaintGeomMap {
int *vert_map_mem;
@@ -189,7 +216,8 @@ typedef struct SculptSession {
float *vmask;
/* Mesh connectivity */
- const struct MeshElemMap *pmap;
+ struct MeshElemMap *pmap;
+ int *pmap_mem;
/* BMesh for dynamic topology sculpting */
struct BMesh *bm;
@@ -199,6 +227,9 @@ typedef struct SculptSession {
/* Undo/redo log for dynamic topology sculpting */
struct BMLog *bm_log;
+ /* Limit surface/grids. */
+ struct SubdivCCG *subdiv_ccg;
+
/* PBVH acceleration structure */
struct PBVH *pbvh;
bool show_diffuse_color;
@@ -254,13 +285,16 @@ void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
-void BKE_sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob,
- bool need_pmap, bool need_mask);
+void BKE_sculpt_update_mesh_elements(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Sculpt *sd, struct Object *ob,
+ bool need_pmap, bool need_mask);
struct MultiresModifierData *BKE_sculpt_multires_active(struct Scene *scene, struct Object *ob);
int BKE_sculpt_mask_layers_ensure(struct Object *ob,
struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
+struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct Object *ob);
+
enum {
SCULPT_MASK_LAYER_CALC_VERT = (1 << 0),
SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1)
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 54c927aaa99..aa00024b27b 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -49,7 +49,7 @@ struct ParticleSettings;
struct Main;
struct Object;
struct Scene;
-struct DerivedMesh;
+struct Depsgraph;
struct ModifierData;
struct MTFace;
struct MCol;
@@ -62,6 +62,8 @@ struct RNG;
struct BVHTreeRay;
struct BVHTreeRayHit;
struct EdgeHash;
+struct Depsgraph;
+struct ViewLayer;
#define PARTICLE_COLLISION_MAX_COLLISIONS 10
@@ -77,6 +79,7 @@ struct EdgeHash;
/* common stuff that many particle functions need */
typedef struct ParticleSimulationData {
+ struct Depsgraph *depsgraph;
struct Scene *scene;
struct Object *ob;
struct ParticleSystem *psys;
@@ -86,6 +89,8 @@ typedef struct ParticleSimulationData {
* maximum value per time step is important. Only sph_integrate makes use of
* this at the moment. Other solvers could, too. */
float courant_num;
+ /* Only valid during dynamics_step(). */
+ struct RNG *rng;
} ParticleSimulationData;
typedef struct SPHData {
@@ -133,7 +138,7 @@ typedef struct ParticleCacheKey {
typedef struct ParticleThreadContext {
/* shared */
struct ParticleSimulationData sim;
- struct DerivedMesh *dm;
+ struct Mesh *mesh;
struct Material *ma;
/* distribution */
@@ -144,7 +149,7 @@ typedef struct ParticleThreadContext {
float *jit, *jitoff, *weight;
float maxweight;
- int *index, *skip, jitlevel;
+ int *index, jitlevel;
int cfrom, distr;
@@ -286,8 +291,8 @@ BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float ve
int count_particles(struct ParticleSystem *psys);
int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
-int psys_get_child_number(struct Scene *scene, struct ParticleSystem *psys);
-int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys);
+int psys_get_child_number(struct Scene *scene, struct ParticleSystem *psys, const bool use_render_params);
+int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys, const bool use_render_params);
struct ParticleSystem *psys_get_current(struct Object *ob);
/* for rna */
@@ -298,10 +303,12 @@ void psys_set_current_num(Object *ob, int index);
struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
-bool psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys);
+struct ParticleSystem *psys_orig_get(struct ParticleSystem *psys);
+bool psys_in_edit_mode(struct Depsgraph *depsgraph, const struct ParticleSystem *psys);
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
bool psys_check_edited(struct ParticleSystem *psys);
+void psys_find_group_weights(struct ParticleSettings *part);
void psys_check_group_weights(struct ParticleSettings *part);
int psys_uses_gravity(struct ParticleSimulationData *sim);
void BKE_particlesettings_fluid_default_settings(struct ParticleSettings *part);
@@ -311,8 +318,9 @@ void BKE_particlesettings_free(struct ParticleSettings *part);
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit);
void psys_free(struct Object *ob, struct ParticleSystem *psys);
-void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset);
-void psys_render_restore(struct Object *ob, struct ParticleSystem *psys);
+/* Copy. */
+void psys_copy_particles(struct ParticleSystem *psys_dst, struct ParticleSystem *psys_src);
+
bool psys_render_simplify_params(struct ParticleSystem *psys, struct ChildParticle *cpa, float *params);
void psys_interpolate_uvs(const struct MTFace *tface, int quad, const float w[4], float uvco[2]);
@@ -323,7 +331,7 @@ void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int tim
CustomDataMask psys_emitter_customdata_mask(struct ParticleSystem *psys);
void psys_particle_on_emitter(struct ParticleSystemModifierData *psmd, int distr, int index, int index_dmcache,
float fuv[4], float foffset, float vec[3], float nor[3],
- float utan[3], float vtan[3], float orco[3], float ornor[3]);
+ float utan[3], float vtan[3], float orco[3]);
struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct ParticleSystem *psys);
struct ModifierData *object_add_particle_system(
@@ -341,9 +349,9 @@ void psys_reset(struct ParticleSystem *psys, int mode);
void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params);
void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, const bool use_render_params);
-void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params);
+void psys_cache_edit_paths(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params);
void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, const bool editupdate, const bool use_render_params);
-int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
+int do_guides(struct Depsgraph *depsgraph, struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors);
float psys_get_timestep(struct ParticleSimulationData *sim);
float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime);
@@ -356,7 +364,7 @@ void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_twist_curve_init(struct ParticleSettings *part);
void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, struct ListBase *modifiers,
- struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
+ struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], float hairmat[4][4],
struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys, const float parent_orco[3]);
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
@@ -376,7 +384,7 @@ void psys_tasks_create(struct ParticleThreadContext *ctx, int startpart, int end
void psys_tasks_free(struct ParticleTask *tasks, int numtasks);
void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
-void psys_apply_hair_lattice(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
+void psys_apply_hair_lattice(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
/* particle_system.c */
struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
@@ -391,7 +399,7 @@ void psys_check_boid_data(struct ParticleSystem *psys);
void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra);
-void particle_system_update(struct Main *bmain, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
+void particle_system_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
/* Callback format for performing operations on ID-pointers for particle systems */
typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cb_flag);
@@ -409,65 +417,38 @@ void psys_free_particles(struct ParticleSystem *psys);
void psys_free_children(struct ParticleSystem *psys);
void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, bool velocity);
-void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float vec[3]);
-void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
-void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
-void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
+void psys_vec_rot_to_face(struct Mesh *mesh, struct ParticleData *pa, float vec[3]);
+void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]);
+void psys_mat_hair_to_global(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]);
+void psys_mat_hair_to_orco(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]);
float psys_get_dietime_from_cache(struct PointCache *cache, int index);
void psys_free_pdd(struct ParticleSystem *psys);
-float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup);
+float *psys_cache_vgroup(struct Mesh *mesh, struct ParticleSystem *psys, int vgroup);
void psys_get_texture(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleTexture *ptex, int event, float cfra);
void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFace *tface,
float (*orcodata)[3], float w[4], float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3]);
-float psys_particle_value_from_verts(struct DerivedMesh *dm, short from, struct ParticleData *pa, float *values);
+ float orco[3]);
+float psys_particle_value_from_verts(struct Mesh *mesh, short from, struct ParticleData *pa, float *values);
void psys_get_from_key(struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time);
/* BLI_bvhtree_ray_cast callback */
void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit);
-void psys_particle_on_dm(struct DerivedMesh *dm_final, int from, int index, int index_dmcache,
+void psys_particle_on_dm(struct Mesh *mesh_final, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3]);
+ float orco[3]);
/* particle_system.c */
void distribute_particles(struct ParticleSimulationData *sim, int from);
void initialize_particle(struct ParticleSimulationData *sim, struct ParticleData *pa);
-void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, struct ParticleSystem *psys);
-int psys_particle_dm_face_lookup(struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, int findex, const float fw[4], struct LinkNode **poly_nodes);
+void psys_calc_dmcache(struct Object *ob, struct Mesh *mesh_final, struct Mesh *mesh_original, struct ParticleSystem *psys);
+int psys_particle_dm_face_lookup(struct Mesh *mesh_final, struct Mesh *mesh_original, int findex, const float fw[4], struct LinkNode **poly_nodes);
void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, float dtime, float cfra);
-float psys_get_current_display_percentage(struct ParticleSystem *psys);
-
-typedef struct ParticleRenderElem {
- int curchild, totchild, reduce;
- float lambda, t, scalemin, scalemax;
-} ParticleRenderElem;
-
-typedef struct ParticleRenderData {
- ChildParticle *child;
- ParticleCacheKey **pathcache;
- ParticleCacheKey **childcache;
- ListBase pathcachebufs, childcachebufs;
- int totchild, totcached, totchildcache;
- struct DerivedMesh *dm;
- int totdmvert, totdmedge, totdmface;
-
- float mat[4][4];
- float viewmat[4][4], winmat[4][4];
- int winx, winy;
-
- int do_simplify;
- int timeoffset;
- ParticleRenderElem *elems;
-
- /* ORIGINDEX */
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
-} ParticleRenderData;
+float psys_get_current_display_percentage(struct ParticleSystem *psys, const bool use_render_params);
/* psys_reset */
#define PSYS_RESET_ALL 1
@@ -481,10 +462,17 @@ typedef struct ParticleRenderData {
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
+struct Depsgraph;
-void BKE_particle_system_eval_init(struct EvaluationContext *eval_ctx,
+void BKE_particle_system_eval_init(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
#endif
+
+/* Draw Cache */
+enum {
+ BKE_PARTICLE_BATCH_DIRTY_ALL = 0,
+};
+void BKE_particle_batch_cache_dirty_tag(struct ParticleSystem *psys, int mode);
+void BKE_particle_batch_cache_free(struct ParticleSystem *psys);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 1fede116193..47fedb565fc 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -30,6 +30,7 @@
#include "BLI_ghash.h"
#include "BLI_utildefines.h"
+struct GPUBatch;
struct CCGElem;
struct CCGKey;
struct CCGDerivedMesh;
@@ -127,10 +128,9 @@ bool BKE_pbvh_node_find_nearest_to_ray(
/* Drawing */
-void BKE_pbvh_node_draw(PBVHNode *node, void *data);
-void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
- int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast);
-void BKE_pbvh_draw_BB(PBVH *bvh);
+void BKE_pbvh_draw_cb(
+ PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, bool only_mask,
+ void (*draw_fn)(void *user_data, struct GPUBatch *batch), void *user_data);
/* PBVH Access */
typedef enum {
@@ -155,6 +155,8 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
/* multires level, only valid for type == PBVH_GRIDS */
void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key);
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh, int *num_grids);
+
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
@@ -219,7 +221,7 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node);
void BKE_pbvh_bmesh_after_stroke(PBVH *bvh);
-/* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */
+/* Update Normals/Bounding Box/Redraw and clear flags */
void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
@@ -238,7 +240,7 @@ void BKE_pbvh_node_layer_disp_free(PBVHNode *node);
/* vertex deformer */
float (*BKE_pbvh_get_vertCos(struct PBVH *pbvh))[3];
-void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]);
+void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3], const int totvert);
bool BKE_pbvh_isDeformed(struct PBVH *pbvh);
/* Vertex Iterator */
@@ -367,6 +369,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
//void BKE_pbvh_node_BB_reset(PBVHNode *node);
//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
+bool pbvh_has_mask(PBVH *bvh);
void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color);
void pbvh_show_mask_set(PBVH *bvh, bool show_mask);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index e905a5efae4..f13f84e4eb2 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -90,6 +90,7 @@ struct ParticleKey;
struct ParticleSystem;
struct PointCache;
struct Scene;
+struct ViewLayer;
struct SmokeModifierData;
struct SoftBody;
struct RigidBodyWorld;
@@ -186,6 +187,8 @@ typedef struct PTCacheID {
typedef struct PTCacheBaker {
struct Main *bmain;
struct Scene *scene;
+ struct ViewLayer *view_layer;
+ struct Depsgraph *depsgraph;
int bake;
int render;
int anim_init;
@@ -243,13 +246,25 @@ typedef struct PTCacheUndo {
size_t undo_size;
} PTCacheUndo;
+enum {
+ /* Modifier stack got evaluated during particle edit mode, need to copy
+ * new evaluated particles to the edit struct.
+ */
+ PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL = (1 << 0),
+};
+
typedef struct PTCacheEdit {
+ int flags;
+
PTCacheEditPoint *points;
struct PTCacheID pid;
/* particles stuff */
struct ParticleSystem *psys;
+ struct ParticleSystem *psys_eval;
+ struct ParticleSystemModifierData *psmd;
+ struct ParticleSystemModifierData *psmd_eval;
struct KDTree *emitter_field;
float *emitter_cosnos; /* localspace face centers and normals (average of its verts), from the derived mesh */
int *mirror_cache;
@@ -274,8 +289,14 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface);
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
+PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache);
void BKE_ptcache_ids_from_object(
- struct Main *bmain, struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);
+ struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);
+
+/****************** Query funcs ****************************/
+
+/* Check whether object has a point cache. */
+bool BKE_ptcache_object_has(struct Scene *scene, struct Object *ob, int duplis);
/***************** Global funcs ****************************/
void BKE_ptcache_remove(void);
@@ -318,7 +339,7 @@ struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const st
/********************** Baking *********************/
/* Bakes cache with cache_step sized jumps in time, not accurate but very fast. */
-void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene);
+void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer);
/* Bake cache or simulate to current frame with settings defined in the baker. */
void BKE_ptcache_bake(struct PTCacheBaker *baker);
diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h
deleted file mode 100644
index d917a6b55e6..00000000000
--- a/source/blender/blenkernel/BKE_property.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_PROPERTY_H__
-#define __BKE_PROPERTY_H__
-
-/** \file BKE_property.h
- * \ingroup bke
- */
-
-struct bProperty;
-struct ListBase;
-struct Object;
-
-void BKE_bproperty_free(struct bProperty *prop);
-void BKE_bproperty_free_list(struct ListBase *lb);
-struct bProperty *BKE_bproperty_copy(const struct bProperty *prop);
-void BKE_bproperty_copy_list(struct ListBase *lbn, const struct ListBase *lbo);
-void BKE_bproperty_init(struct bProperty *prop);
-struct bProperty *BKE_bproperty_new(int type);
-void BKE_bproperty_unique(struct bProperty *first, struct bProperty *prop, int force);
-struct bProperty *BKE_bproperty_object_get(struct Object *ob, const char *name);
-void BKE_bproperty_object_set(struct Object *ob, struct bProperty *propc);
-// int BKE_bproperty_cmp(struct bProperty *prop, const char *str);
-void BKE_bproperty_set(struct bProperty *prop, const char *str);
-void BKE_bproperty_add(struct bProperty *prop, const char *str);
-/* should really be called '_get_valstr()' or '_as_string()' */
-void BKE_bproperty_set_valstr(struct bProperty *prop, char str[MAX_PROPSTRING]);
-
-#endif
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 470aae40df9..1fa8106d63b 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -37,14 +37,15 @@
struct RigidBodyWorld;
struct RigidBodyOb;
+struct Depsgraph;
struct Scene;
struct Object;
/* -------------- */
/* Memory Management */
-void BKE_rigidbody_free_world(struct RigidBodyWorld *rbw);
-void BKE_rigidbody_free_object(struct Object *ob);
+void BKE_rigidbody_free_world(struct Scene *scene);
+void BKE_rigidbody_free_object(struct Object *ob, struct RigidBodyWorld *rbw);
void BKE_rigidbody_free_constraint(struct Object *ob);
/* ...... */
@@ -79,7 +80,7 @@ void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_center[3]);
/* Utilities */
struct RigidBodyWorld *BKE_rigidbody_get_world(struct Scene *scene);
-void BKE_rigidbody_remove_object(struct Scene *scene, struct Object *ob);
+void BKE_rigidbody_remove_object(struct Main *bmain, struct Scene *scene, struct Object *ob);
void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob);
/* -------------- */
@@ -99,21 +100,19 @@ void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime);
void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
-void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime);
-void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime);
+void BKE_rigidbody_rebuild_world(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
+void BKE_rigidbody_do_simulation(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
/* -------------------- */
/* Depsgraph evaluation */
-struct EvaluationContext;
-
-void BKE_rigidbody_rebuild_sim(struct EvaluationContext *eval_ctx,
+void BKE_rigidbody_rebuild_sim(struct Depsgraph *depsgraph,
struct Scene *scene);
-void BKE_rigidbody_eval_simulation(struct EvaluationContext *eval_ctx,
+void BKE_rigidbody_eval_simulation(struct Depsgraph *depsgraph,
struct Scene *scene);
-void BKE_rigidbody_object_sync_transforms(struct EvaluationContext *eval_ctx,
+void BKE_rigidbody_object_sync_transforms(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
deleted file mode 100644
index 653fc1afa64..00000000000
--- a/source/blender/blenkernel/BKE_sca.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_SCA_H__
-#define __BKE_SCA_H__
-
-/** \file BKE_sca.h
- * \ingroup bke
- */
-
-struct Main;
-struct Object;
-struct bSensor;
-struct bController;
-struct bActuator;
-
-void link_logicbricks(void **poin, void ***ppoin, short *tot, short size);
-void unlink_logicbricks(void **poin, void ***ppoin, short *tot);
-
-void unlink_controller(struct bController *cont);
-void unlink_controllers(struct ListBase *lb);
-void free_controller(struct bController *cont);
-void free_controllers(struct ListBase *lb);
-
-void unlink_actuator(struct bActuator *act);
-void unlink_actuators(struct ListBase *lb);
-void free_actuator(struct bActuator *act);
-void free_actuators(struct ListBase *lb);
-
-void free_sensor(struct bSensor *sens);
-void free_sensors(struct ListBase *lb);
-struct bSensor *copy_sensor(struct bSensor *sens, const int flag);
-void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
-void init_sensor(struct bSensor *sens);
-struct bSensor *new_sensor(int type);
-struct bController *copy_controller(struct bController *cont, const int flag);
-void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
-void init_controller(struct bController *cont);
-struct bController *new_controller(int type);
-struct bActuator *copy_actuator(struct bActuator *act, const int flag);
-void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
-void init_actuator(struct bActuator *act);
-struct bActuator *new_actuator(int type);
-void clear_sca_new_poins_ob(struct Object *ob);
-void clear_sca_new_poins(void);
-void set_sca_new_poins_ob(struct Object *ob);
-void set_sca_new_poins(void);
-
-void BKE_sca_logic_links_remap(struct Main *bmain, struct Object *ob_old, struct Object *ob_new);
-void BKE_sca_logic_copy(struct Object *ob_new, const struct Object *ob, const int flag);
-
-void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up);
-void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up);
-void sca_move_actuator(struct bActuator *act_to_move, struct Object *ob, int move_up);
-
-/* Callback format for performing operations on ID-pointers for sensors/controllers/actuators. */
-typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cb_flag);
-typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cb_flag);
-typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cb_flag);
-
-void BKE_sca_sensors_id_loop(struct ListBase *senslist, SCASensorIDFunc func, void *userdata);
-void BKE_sca_controllers_id_loop(struct ListBase *contlist, SCAControllerIDFunc func, void *userdata);
-void BKE_sca_actuators_id_loop(struct ListBase *atclist, SCAActuatorIDFunc func, void *userdata);
-
-
-const char *sca_state_name_get(Object *ob, short bit);
-
-#endif
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index e85867fcbe7..6344d29a2a0 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -38,43 +38,55 @@ extern "C" {
#endif
struct AviCodecData;
-struct Base;
-struct EvaluationContext;
+struct Collection;
+struct Depsgraph;
struct Main;
struct Object;
struct RenderData;
-struct SceneRenderLayer;
struct Scene;
+struct ViewLayer;
struct UnitSettings;
-struct Main;
-
-#define SCE_COPY_NEW 0
-#define SCE_COPY_EMPTY 1
-#define SCE_COPY_LINK_OB 2
-#define SCE_COPY_LINK_DATA 3
-#define SCE_COPY_FULL 4
+struct ViewRender;
+struct WorkSpace;
+struct TransformOrientation;
+
+typedef enum eSceneCopyMethod {
+ SCE_COPY_NEW = 0,
+ SCE_COPY_EMPTY = 1,
+ SCE_COPY_LINK_OB = 2,
+ SCE_COPY_LINK_DATA = 3,
+ SCE_COPY_FULL = 4,
+} eSceneCopyMethod;
/* Use as the contents of a 'for' loop: for (SETLOOPER(...)) { ... */
#define SETLOOPER(_sce_basis, _sce_iter, _base) \
- _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, NULL); \
+ _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, BKE_view_layer_context_active_PLACEHOLDER(_sce_basis), NULL); \
_base; \
- _base = _setlooper_base_step(&_sce_iter, _base)
+ _base = _setlooper_base_step(&_sce_iter, NULL, _base)
-struct Base *_setlooper_base_step(struct Scene **sce_iter, struct Base *base);
+#define SETLOOPER_VIEW_LAYER(_sce_basis, _view_layer, _sce_iter, _base) \
+ _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, _view_layer, NULL); \
+ _base; \
+ _base = _setlooper_base_step(&_sce_iter, NULL, _base)
+
+#define SETLOOPER_SET_ONLY(_sce_basis, _sce_iter, _base) \
+ _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, NULL, NULL); \
+ _base; \
+ _base = _setlooper_base_step(&_sce_iter, NULL, _base)
+
+struct Base *_setlooper_base_step(struct Scene **sce_iter, struct ViewLayer *view_layer, struct Base *base);
void free_avicodecdata(struct AviCodecData *acd);
+void BKE_scene_free_ex(struct Scene *sce, const bool do_id_user);
void BKE_scene_free(struct Scene *sce);
void BKE_scene_init(struct Scene *sce);
struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
-/* base functions */
-struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name);
-struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob);
-struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob);
-void BKE_scene_base_unlink(struct Scene *sce, struct Base *base);
-void BKE_scene_base_deselect_all(struct Scene *sce);
-void BKE_scene_base_select(struct Scene *sce, struct Base *selbase);
+void BKE_scene_remove_rigidbody_object(struct Main *bmain, struct Scene *scene, struct Object *ob);
+
+bool BKE_scene_object_find(struct Scene *scene, struct Object *ob);
+struct Object *BKE_scene_object_find_by_name(struct Scene *scene, const char *name);
/* Scene base iteration function.
* Define struct here, so no need to bother with alloc/free it.
@@ -87,11 +99,14 @@ typedef struct SceneBaseIter {
int phase;
} SceneBaseIter;
-int BKE_scene_base_iter_next(struct Main *bmain, struct EvaluationContext *eval_ctx, struct SceneBaseIter *iter,
- struct Scene **scene, int val, struct Base **base, struct Object **ob);
+int BKE_scene_base_iter_next(
+ struct Depsgraph *depsgraph, struct SceneBaseIter *iter,
+ struct Scene **scene, int val, struct Base **base, struct Object **ob);
-void BKE_scene_base_flag_to_objects(struct Scene *scene);
+void BKE_scene_base_flag_to_objects(struct ViewLayer *view_layer);
void BKE_scene_base_flag_from_objects(struct Scene *scene);
+void BKE_scene_object_base_flag_sync_from_base(struct Base *base);
+void BKE_scene_object_base_flag_sync_from_object(struct Base *base);
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
@@ -105,7 +120,8 @@ void BKE_scene_groups_relink(struct Scene *sce);
void BKE_scene_make_local(struct Main *bmain, struct Scene *sce, const bool lib_local);
-struct Object *BKE_scene_camera_find(struct Scene *sc);
+struct Scene *BKE_scene_find_from_collection(const struct Main *bmain, const struct Collection *collection);
+
#ifdef DURIAN_CAMERA_SWITCH
struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH
#endif
@@ -124,12 +140,15 @@ float BKE_scene_frame_get_from_ctime(const struct Scene *scene, const float fram
void BKE_scene_frame_set(struct Scene *scene, double cfra);
/* ** Scene evaluation ** */
-void BKE_scene_update_tagged(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce);
-void BKE_scene_update_for_newframe(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay);
-void BKE_scene_update_for_newframe_ex(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay, bool do_invisible_flush);
-struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name);
-bool BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl);
+void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph,
+ struct Main *bmain);
+
+void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph,
+ struct Main *bmain);
+
+void BKE_scene_view_layer_graph_evaluated_ensure(
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer);
struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
@@ -137,16 +156,13 @@ bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *s
/* render profile */
int get_render_subsurf_level(const struct RenderData *r, int level, bool for_render);
int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render);
-int get_render_shadow_samples(const struct RenderData *r, int samples);
-float get_render_aosss_error(const struct RenderData *r, float error);
-bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
-bool BKE_scene_use_world_space_shading(struct Scene *scene);
bool BKE_scene_use_spherical_stereo(struct Scene *scene);
-bool BKE_scene_uses_blender_internal(const struct Scene *scene);
-bool BKE_scene_uses_blender_game(const struct Scene *scene);
+bool BKE_scene_uses_blender_eevee(const struct Scene *scene);
+bool BKE_scene_uses_blender_workbench(const struct Scene *scene);
+bool BKE_scene_uses_cycles(const struct Scene *scene);
void BKE_scene_disable_color_management(struct Scene *scene);
bool BKE_scene_check_color_management_enabled(const struct Scene *scene);
@@ -157,6 +173,8 @@ int BKE_render_num_threads(const struct RenderData *r);
int BKE_render_preview_pixel_size(const struct RenderData *r);
+/**********************************/
+
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
/* multiview */
@@ -176,6 +194,20 @@ void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char
void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height);
int BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
+/* depsgraph */
+void BKE_scene_allocate_depsgraph_hash(struct Scene *scene);
+void BKE_scene_ensure_depsgraph_hash(struct Scene *scene);
+void BKE_scene_free_depsgraph_hash(struct Scene *scene);
+
+struct Depsgraph *BKE_scene_get_depsgraph(struct Scene *scene, struct ViewLayer *view_layer, bool allocate);
+
+void BKE_scene_transform_orientation_remove(
+ struct Scene *scene, struct TransformOrientation *orientation);
+struct TransformOrientation *BKE_scene_transform_orientation_find(
+ const struct Scene *scene, const int index);
+int BKE_scene_transform_orientation_get_index(
+ const struct Scene *scene, const struct TransformOrientation *orientation);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index b33b9e455f1..75d2ed0d0bc 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -41,18 +41,25 @@ struct Menu;
struct Panel;
struct Scene;
struct ScrArea;
+struct ScrVert;
struct SpaceType;
+struct TransformOrientation;
struct View3D;
+struct View3DShading;
struct bContext;
struct bContextDataResult;
struct bScreen;
struct uiLayout;
struct uiList;
struct wmKeyConfig;
+struct wmGizmoMap;
struct wmNotifier;
struct wmWindow;
struct wmWindowManager;
+struct WorkSpace;
struct GPUFXSettings;
+struct wmMsgBus;
+struct ScrAreaMap;
#include "BLI_compiler_attrs.h"
@@ -71,8 +78,9 @@ typedef struct SpaceType {
int spaceid; /* unique space identifier */
int iconid; /* icon lookup for menus */
- /* initial allocation, after this WM will call init() too */
- struct SpaceLink *(*new)(const struct bContext *C);
+ /* Initial allocation, after this WM will call init() too. Some editors need
+ * area and scene data (e.g. frame range) to set their initial scrolling. */
+ struct SpaceLink *(*new)(const struct ScrArea *sa, const struct Scene *scene);
/* not free spacelink itself */
void (*free)(struct SpaceLink *sl);
@@ -81,7 +89,8 @@ typedef struct SpaceType {
/* exit is called when the area is hidden or removed */
void (*exit)(struct wmWindowManager *wm, struct ScrArea *sa);
/* Listeners can react to bContext changes */
- void (*listener)(struct bScreen *sc, struct ScrArea *sa, struct wmNotifier *wmn);
+ void (*listener)(struct wmWindow *win, struct ScrArea *sa,
+ struct wmNotifier *wmn, struct Scene *scene);
/* refresh context, called after filereads, ED_area_tag_refresh() */
void (*refresh)(const struct bContext *C, struct ScrArea *sa);
@@ -96,18 +105,22 @@ typedef struct SpaceType {
/* on startup, define dropboxes for spacetype+regions */
void (*dropboxes)(void);
+ /* initialize gizmo-map-types and gizmo-group-types with the region */
+ void (*gizmos)(void);
+
/* return context data */
int (*context)(const struct bContext *C, const char *member, struct bContextDataResult *result);
/* Used when we want to replace an ID by another (or NULL). */
void (*id_remap)(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id);
+ int (*space_subtype_get)(struct ScrArea *sa);
+ void (*space_subtype_set)(struct ScrArea *sa, int value);
+ void (*space_subtype_item_extend)(struct bContext *C, EnumPropertyItem **item, int *totitem);
+
/* region type definitions */
ListBase regiontypes;
- /* tool shelf definitions */
- ListBase toolshelf;
-
/* read and write... */
/* default keymaps to add */
@@ -120,8 +133,7 @@ typedef struct SpaceType {
typedef struct ARegionType {
struct ARegionType *next, *prev;
- /* unique identifier within this space, defines RGN_TYPE_xxxx */
- int regionid;
+ int regionid; /* unique identifier within this space, defines RGN_TYPE_xxxx */
/* add handlers, stuff you only do once or on area/region type/size changes */
void (*init)(struct wmWindowManager *wm, struct ARegion *ar);
@@ -129,10 +141,21 @@ typedef struct ARegionType {
void (*exit)(struct wmWindowManager *wm, struct ARegion *ar);
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *C, struct ARegion *ar);
+ /* optional, compute button layout before drawing for dynamic size */
+ void (*layout)(const struct bContext *C, struct ARegion *ar);
+ /* snap the size of the region (can be NULL for no snapping). */
+ int (*snap_size)(const struct ARegion *ar, int size, int axis);
/* contextual changes should be handled here */
- void (*listener)(struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, struct wmNotifier *wmn);
+ void (*listener)(struct wmWindow *win, struct ScrArea *sa, struct ARegion *ar,
+ struct wmNotifier *wmn, const struct Scene *scene);
+ /* Optional callback to generate subscriptions. */
+ void (*message_subscribe)(
+ const struct bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus);
- void (*free)(struct ARegion *ar);
+ void (*free)(struct ARegion *);
/* split region, copy data optionally */
void *(*duplicate)(void *poin);
@@ -179,8 +202,12 @@ typedef struct PanelType {
char translation_context[BKE_ST_MAXNAME];
char context[BKE_ST_MAXNAME]; /* for buttons window */
char category[BKE_ST_MAXNAME]; /* for category tabs */
- int space_type;
- int region_type;
+ char owner_id[BKE_ST_MAXNAME]; /* for work-spaces to selectively show. */
+ char parent_id[BKE_ST_MAXNAME]; /* parent idname for subpanels */
+ short space_type;
+ short region_type;
+ /* For popovers, 0 for default. */
+ int ui_units_x;
int flag;
@@ -188,9 +215,15 @@ typedef struct PanelType {
bool (*poll)(const struct bContext *C, struct PanelType *pt);
/* draw header (optional) */
void (*draw_header)(const struct bContext *C, struct Panel *pa);
+ /* draw header preset (optional) */
+ void (*draw_header_preset)(const struct bContext *C, struct Panel *pa);
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *C, struct Panel *pa);
+ /* sub panels */
+ struct PanelType *parent;
+ ListBase children;
+
/* RNA integration */
ExtensionRNA ext;
} PanelType;
@@ -205,7 +238,7 @@ typedef void (*uiListDrawItemFunc)(
/* Draw the filtering part of an uiList */
typedef void (*uiListDrawFilterFunc)(
- struct uiList *ui_list, struct bContext *C, struct uiLayout *layout);
+ struct uiList *ui_list, struct bContext *C, struct uiLayout *layout, bool reverse);
/* Filter items of an uiList */
typedef void (*uiListFilterItemsFunc)(
@@ -231,7 +264,9 @@ typedef struct HeaderType {
char idname[BKE_ST_MAXNAME]; /* unique name */
int space_type;
+ int region_type;
+ bool (*poll)(const struct bContext *C, struct HeaderType *ht);
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *C, struct Header *header);
@@ -253,6 +288,7 @@ typedef struct MenuType {
char idname[BKE_ST_MAXNAME]; /* unique name */
char label[BKE_ST_MAXNAME]; /* for button text */
char translation_context[BKE_ST_MAXNAME];
+ char owner_id[BKE_ST_MAXNAME]; /* optional, see: #wmOwnerID */
const char *description;
/* verify if the menu should draw or not */
@@ -283,6 +319,10 @@ void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);
+struct ARegion *BKE_spacedata_find_region_type(
+ const struct SpaceLink *slink, const struct ScrArea *sa,
+ int region_type) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
void BKE_spacedata_callback_id_remap_set(
void (*func)(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id));
void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id);
@@ -290,35 +330,42 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar);
+void BKE_area_region_panels_free(struct ListBase *panels);
void BKE_screen_area_free(struct ScrArea *sa);
+/* Gizmo-maps of a region need to be freed with the region. Uses callback to avoid low-level call. */
+void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *));
+void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *));
-struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
+struct ARegion *BKE_area_find_region_type(const struct ScrArea *sa, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y);
struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
+struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap, const int spacetype, int x, int y);
struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y);
-unsigned int BKE_screen_view3d_layer_active_ex(
- const struct View3D *v3d, const struct Scene *scene, bool use_localvd) ATTR_NONNULL(2);
-unsigned int BKE_screen_view3d_layer_active(
- const struct View3D *v3d, const struct Scene *scene) ATTR_NONNULL(2);
-
-unsigned int BKE_screen_view3d_layer_all(const struct bScreen *sc) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void BKE_screen_gizmo_tag_refresh(struct bScreen *sc);
void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene);
-void BKE_screen_view3d_scene_sync(struct bScreen *sc);
-void BKE_screen_view3d_main_sync(ListBase *screen_lb, struct Scene *scene);
-void BKE_screen_view3d_twmode_remove(struct View3D *v3d, const int i);
-void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, struct Scene *scene, const int i);
-void BKE_screen_gpu_fx_validate(struct GPUFXSettings *fx_settings);
+void BKE_screen_view3d_scene_sync(struct bScreen *sc, struct Scene *scene);
+bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* zoom factor conversion */
float BKE_screen_view3d_zoom_to_fac(float camzoom);
float BKE_screen_view3d_zoom_from_fac(float zoomfac);
+void BKE_screen_view3d_shading_init(struct View3DShading *shading);
+
/* screen */
void BKE_screen_free(struct bScreen *sc);
-unsigned int BKE_screen_visible_layers(struct bScreen *screen, struct Scene *scene);
+void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL();
+
+struct ScrEdge *BKE_screen_find_edge(struct bScreen *sc, struct ScrVert *v1, struct ScrVert *v2);
+void BKE_screen_sort_scrvert(struct ScrVert **v1, struct ScrVert **v2);
+void BKE_screen_remove_double_scrverts(struct bScreen *sc);
+void BKE_screen_remove_double_scredges(struct bScreen *sc);
+void BKE_screen_remove_unused_scredges(struct bScreen *sc);
+void BKE_screen_remove_unused_scrverts(struct bScreen *sc);
-#endif /* __BKE_SCREEN_H__ */
+#endif
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 705143480d2..ebe732d2336 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -31,7 +31,7 @@
*/
struct bContext;
-struct EvaluationContext;
+struct Depsgraph;
struct StripColorBalance;
struct Editing;
struct GSet;
@@ -40,6 +40,7 @@ struct GPUFX;
struct ImBuf;
struct Main;
struct Mask;
+struct RenderEngineType;
struct Scene;
struct Sequence;
struct SequenceModifierData;
@@ -92,12 +93,13 @@ void BKE_sequence_iterator_end(SeqIterator *iter);
} ((void)0)
typedef struct SeqRenderData {
- struct EvaluationContext *eval_ctx;
struct Main *bmain;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
int rectx;
int recty;
int preview_render_size;
+ int for_render;
int motion_blur_samples;
float motion_blur_shutter;
bool skip_cache;
@@ -112,8 +114,9 @@ typedef struct SeqRenderData {
} SeqRenderData;
void BKE_sequencer_new_render_data(
- struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *scene,
+ struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene,
int rectx, int recty, int preview_render_size,
+ int for_render,
SeqRenderData *r_context);
int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b);
@@ -249,7 +252,7 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change);
bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra);
-void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue);
+void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue);
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
@@ -434,11 +437,12 @@ enum {
};
typedef struct ImBuf *(*SequencerDrawView)(
- struct Main *bmain, struct Scene *scene,
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ int drawtype,
struct Object *camera, int width, int height,
- unsigned int flag, unsigned int draw_flags, int drawtype, int alpha_mode,
+ unsigned int flag, unsigned int draw_flags, int alpha_mode,
int samples, const char *viewname,
- struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
+ struct GPUOffScreen *ofs, char err_out[256]);
extern SequencerDrawView sequencer_view3d_cb;
/* copy/paste */
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
new file mode 100644
index 00000000000..3306d8256e8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -0,0 +1,180 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_SHADER_FX_H__
+#define __BKE_SHADER_FX_H__
+
+/** \file BKE_shader_fx.h
+ * \ingroup bke
+ */
+
+#include "DNA_shader_fx_types.h" /* needed for all enum typdefs */
+#include "BLI_compiler_attrs.h"
+#include "BKE_customdata.h"
+
+struct ID;
+struct Depsgraph;
+struct DerivedMesh;
+struct Mesh;
+struct Object;
+struct Scene;
+struct ViewLayer;
+struct ListBase;
+struct bArmature;
+struct Main;
+struct ShaderFxData;
+struct DepsNodeHandle;
+struct bGPDlayer;
+struct bGPDframe;
+struct bGPDstroke;
+struct ModifierUpdateDepsgraphContext;
+
+#define SHADER_FX_ACTIVE(_fx, _is_render) (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
+ ((_fx->mode & eShaderFxMode_Render) && (_is_render == true)))
+#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
+
+typedef enum {
+ /* Should not be used, only for None type */
+ eShaderFxType_NoneType,
+
+ /* grease pencil effects */
+ eShaderFxType_GpencilType,
+} ShaderFxTypeType;
+
+typedef enum {
+ eShaderFxTypeFlag_SupportsEditmode = (1 << 0),
+
+ /* For effects that support editmode this determines if the
+ * effect should be enabled by default in editmode.
+ */
+ eShaderFxTypeFlag_EnableInEditmode = (1 << 2),
+
+ /* max one per type */
+ eShaderFxTypeFlag_Single = (1 << 4),
+
+ /* can't be added manually by user */
+ eShaderFxTypeFlag_NoUserAdd = (1 << 5),
+} ShaderFxTypeFlag;
+
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void(*ShaderFxObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void(*ShaderFxIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
+typedef void(*ShaderFxTexWalkFunc)(void *userData, struct Object *ob, struct ShaderFxData *fx, const char *propname);
+
+typedef struct ShaderFxTypeInfo {
+ /* The user visible name for this effect */
+ char name[32];
+
+ /* The DNA struct name for the effect data type, used to
+ * write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the effect data type, used by allocation. */
+ int struct_size;
+
+ ShaderFxTypeType type;
+ ShaderFxTypeFlag flags;
+
+ /* Copy instance data for this effect type. Should copy all user
+ * level settings to the target effect.
+ */
+ void(*copyData)(const struct ShaderFxData *fx, struct ShaderFxData *target);
+
+ /* Initialize new instance data for this effect type, this function
+ * should set effect variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct ShaderFxData *fx);
+
+ /* Free internal effect data variables, this function should
+ * not free the fx variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct ShaderFxData *fx);
+
+ /* Return a boolean value indicating if this effect is able to be
+ * calculated based on the effect data. This is *not* regarding the
+ * fx->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ bool (*isDisabled)(struct ShaderFxData *fx, int userRenderParams);
+
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ void (*updateDepsgraph)(struct ShaderFxData *fx,
+ const struct ModifierUpdateDepsgraphContext *ctx);
+
+ /* Should return true if the effect needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ bool (*dependsOnTime)(struct ShaderFxData *fx);
+
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the effect data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct ShaderFxData *fx, struct Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the effect data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct ShaderFxData *fx, struct Object *ob,
+ ShaderFxIDWalkFunc walk, void *userData);
+} ShaderFxTypeInfo;
+
+/* Initialize global data (type info and some common global storages). */
+void BKE_shaderfx_init(void);
+
+const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_new(int type);
+void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
+void BKE_shaderfx_free(struct ShaderFxData *fx);
+bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
+bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx);
+struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name);
+void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
+void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target);
+void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx, struct ShaderFxData *target, const int flag);
+void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+
+bool BKE_shaderfx_has_gpencil(struct Object *ob);
+
+#endif /* __BKE_SHADER_FX_H__ */
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 2dd42a9da1f..3ce5aa323c5 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -33,6 +33,7 @@
/* Shrinkwrap stuff */
#include "BKE_bvhutils.h"
+#include "BLI_bitmap.h"
/*
* Shrinkwrap is composed by a set of functions and options that define the type of shrink.
@@ -47,37 +48,65 @@
*/
struct Object;
-struct DerivedMesh;
+struct Mesh;
struct MVert;
struct MDeformVert;
+struct ModifierEvalContext;
struct ShrinkwrapModifierData;
-struct MDeformVert;
struct BVHTree;
struct SpaceTransform;
+/* Information about boundary edges in the mesh. */
+typedef struct ShrinkwrapBoundaryVertData {
+ /* Average direction of edges that meet here. */
+ float direction[3];
+
+ /* Closest vector to direction that is orthogonal to vertex normal. */
+ float normal_plane[3];
+} ShrinkwrapBoundaryVertData;
+
+typedef struct ShrinkwrapBoundaryData {
+ /* True if the edge belongs to exactly one face. */
+ const BLI_bitmap *edge_is_boundary;
+ /* True if the looptri has any boundary edges. */
+ const BLI_bitmap *looptri_has_boundary;
+
+ /* Mapping from vertex index to boundary vertex index, or -1.
+ * Used for compact storage of data about boundary vertices. */
+ const int *vert_boundary_id;
+ unsigned int num_boundary_verts;
+
+ /* Direction data about boundary vertices. */
+ const ShrinkwrapBoundaryVertData *boundary_verts;
+} ShrinkwrapBoundaryData;
-typedef struct ShrinkwrapCalcData {
- ShrinkwrapModifierData *smd; //shrinkwrap modifier data
+void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh);
+void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh);
- struct Object *ob; //object we are applying shrinkwrap to
+/* Information about a mesh and BVH tree. */
+typedef struct ShrinkwrapTreeData {
+ Mesh *mesh;
- struct MVert *vert; //Array of verts being projected (to fetch normals or other data)
- float (*vertexCos)[3]; //vertexs being shrinkwraped
- int numVerts;
+ BVHTree *bvh;
+ BVHTreeFromMesh treeData;
- struct MDeformVert *dvert; //Pointer to mdeform array
- int vgroup; //Vertex group num
- bool invert_vgroup; /* invert vertex group influence */
+ float (*clnors)[3];
+ ShrinkwrapBoundaryData *boundary;
+} ShrinkwrapTreeData;
- struct DerivedMesh *target; //mesh we are shrinking to
- struct SpaceTransform local2target; //transform to move between local and target space
+/* Checks if the modifier needs target normals with these settings. */
+bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode);
- float keepDist; //Distance to keep above target surface (units are in local space)
+/* Initializes the mesh data structure from the given mesh and settings. */
+bool BKE_shrinkwrap_init_tree(struct ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals);
-} ShrinkwrapCalcData;
+/* Frees the tree data if necessary. */
+void BKE_shrinkwrap_free_tree(struct ShrinkwrapTreeData *data);
-void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts, bool for_render);
+/* Implementation of the Shrinkwrap modifier */
+void shrinkwrapModifier_deform(
+ struct ShrinkwrapModifierData *smd, struct Scene *scene, struct Object *ob, struct Mesh *mesh,
+ struct MDeformVert *dvert, const int defgrp_index, float (*vertexCos)[3], int numVerts);
/*
* This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is:
@@ -91,8 +120,22 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object
*/
bool BKE_shrinkwrap_project_normal(
char options, const float vert[3], const float dir[3], const float ray_radius,
- const struct SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit,
- BVHTree_RayCastCallback callback, void *userdata);
+ const struct SpaceTransform *transf, struct ShrinkwrapTreeData *tree, BVHTreeRayHit *hit);
+
+/* Maps the point to the nearest surface, either by simple nearest, or by target normal projection. */
+void BKE_shrinkwrap_find_nearest_surface(
+ struct ShrinkwrapTreeData *tree, struct BVHTreeNearest *nearest, float co[3], int type);
+
+/* Computes a smooth normal of the target (if applicable) at the hit location. */
+void BKE_shrinkwrap_compute_smooth_normal(
+ const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
+ int looptri_idx, const float hit_co[3], const float hit_no[3], float r_no[3]);
+
+/* Apply the shrink to surface modes to the given original coordinates and nearest point. */
+void BKE_shrinkwrap_snap_point_to_surface(
+ const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
+ int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist,
+ const float point_co[3], float r_point_co[3]);
/*
* NULL initializers to local data
diff --git a/source/blender/blenkernel/BKE_sketch.h b/source/blender/blenkernel/BKE_sketch.h
deleted file mode 100644
index 9b9c125fbe6..00000000000
--- a/source/blender/blenkernel/BKE_sketch.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * ***** 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): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_SKETCH_H__
-#define __BKE_SKETCH_H__
-
-/** \file BKE_sketch.h
- * \ingroup bke
- */
-
-typedef enum SK_PType {
- PT_CONTINUOUS,
- PT_EXACT,
-} SK_PType;
-
-typedef enum SK_PMode {
- PT_SNAP,
- PT_PROJECT,
-} SK_PMode;
-
-typedef struct SK_Point {
- float p[3];
- short p2d[2];
- float no[3];
- float size;
- SK_PType type;
- SK_PMode mode;
-} SK_Point;
-
-typedef struct SK_Stroke {
- struct SK_Stroke *next, *prev;
-
- SK_Point *points;
- int nb_points;
- int buf_size;
- int selected;
-} SK_Stroke;
-
-#define SK_OVERDRAW_LIMIT 5
-
-typedef struct SK_Overdraw {
- SK_Stroke *target;
- int start, end;
- int count;
-} SK_Overdraw;
-
-#define SK_Stroke_BUFFER_INIT_SIZE 20
-
-typedef struct SK_DrawData {
- int mval[2];
- int previous_mval[2];
- SK_PType type;
-} SK_DrawData;
-
-typedef struct SK_Intersection {
- struct SK_Intersection *next, *prev;
- SK_Stroke *stroke;
- int before;
- int after;
- int gesture_index;
- float p[3];
- float lambda; /* used for sorting intersection points */
-} SK_Intersection;
-
-typedef struct SK_Sketch {
- ListBase strokes;
- SK_Stroke *active_stroke;
- SK_Stroke *gesture;
- SK_Point next_point;
- SK_Overdraw over;
-} SK_Sketch;
-
-
-typedef struct SK_Gesture {
- SK_Stroke *stk;
- SK_Stroke *segments;
-
- ListBase intersections;
- ListBase self_intersections;
-
- int nb_self_intersections;
- int nb_intersections;
- int nb_segments;
-} SK_Gesture;
-
-
-/************************************************/
-
-void freeSketch(SK_Sketch *sketch);
-SK_Sketch *createSketch(void);
-
-void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk);
-
-void sk_freeStroke(SK_Stroke *stk);
-SK_Stroke *sk_createStroke(void);
-
-SK_Point *sk_lastStrokePoint(SK_Stroke *stk);
-
-void sk_allocStrokeBuffer(SK_Stroke *stk);
-void sk_shrinkStrokeBuffer(SK_Stroke *stk);
-void sk_growStrokeBuffer(SK_Stroke *stk);
-void sk_growStrokeBufferN(SK_Stroke *stk, int n);
-
-void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n);
-void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n);
-void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt);
-void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end);
-
-void sk_trimStroke(SK_Stroke *stk, int start, int end);
-void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]);
-void sk_polygonizeStroke(SK_Stroke *stk, int start, int end);
-void sk_flattenStroke(SK_Stroke *stk, int start, int end);
-void sk_reverseStroke(SK_Stroke *stk);
-
-void sk_filterLastContinuousStroke(SK_Stroke *stk);
-void sk_filterStroke(SK_Stroke *stk, int start, int end);
-
-void sk_initPoint(SK_Point *pt, SK_DrawData *dd, const float no[3]);
-void sk_copyPoint(SK_Point *dst, SK_Point *src);
-
-int sk_stroke_filtermval(SK_DrawData *dd);
-void sk_endContinuousStroke(SK_Stroke *stk);
-
-void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk);
-
-void sk_initDrawData(SK_DrawData *dd, const int mval[2]);
-
-void sk_deleteSelectedStrokes(SK_Sketch *sketch);
-void sk_selectAllSketch(SK_Sketch *sketch, int mode);
-
-#endif
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h
index a54d50cb154..deee85c02d4 100644
--- a/source/blender/blenkernel/BKE_smoke.h
+++ b/source/blender/blenkernel/BKE_smoke.h
@@ -35,7 +35,10 @@
typedef float (*bresenham_callback)(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+struct Mesh *smokeModifier_do(
+ struct SmokeModifierData *smd, struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob, struct Mesh *me);
void smoke_reallocate_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
void smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
@@ -43,7 +46,7 @@ void smokeModifier_free(struct SmokeModifierData *smd);
void smokeModifier_reset(struct SmokeModifierData *smd);
void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
void smokeModifier_createType(struct SmokeModifierData *smd);
-void smokeModifier_copy(const SmokeModifierData *smd, struct SmokeModifierData *tsmd);
+void smokeModifier_copy(const SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag);
float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
int smoke_get_data_flags(struct SmokeDomainSettings *sds);
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
index 5e8ea89c0f4..b173c995727 100644
--- a/source/blender/blenkernel/BKE_softbody.h
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -31,6 +31,7 @@
* \ingroup bke
*/
+struct Depsgraph;
struct Object;
struct Scene;
struct SoftBody;
@@ -53,13 +54,14 @@ typedef struct BodyPoint {
extern struct SoftBody *sbNew(struct Scene *scene);
/* frees internal data and softbody itself */
-extern void sbFree(struct SoftBody *sb);
+extern void sbFree(struct Object *ob);
/* frees simulation data to reset simulation */
extern void sbFreeSimulation(struct SoftBody *sb);
/* do one simul step, reading and writing vertex locs from given array */
-extern void sbObjectStep(struct Scene *scene, struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts);
+extern void sbObjectStep(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ float framnr, float (*vertexCos)[3], int numVerts);
/* makes totally fresh start situation, resets time */
extern void sbObjectToSoftbody(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 6f8274fabc8..98fb4f47339 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -35,8 +35,8 @@
#define SOUND_WAVE_SAMPLES_PER_SECOND 250
-#ifdef WITH_SYSTEM_AUDASPACE
-# include AUD_DEVICE_H
+#if defined(WITH_AUDASPACE)
+# include <AUD_Device.h>
#endif
struct bSound;
@@ -84,7 +84,7 @@ void BKE_sound_copy_data(struct Main *bmain, struct bSound *sound_dst, const str
void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local);
-#if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE)
+#if defined(WITH_AUDASPACE)
AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
#endif
@@ -149,6 +149,4 @@ float BKE_sound_get_length(struct bSound *sound);
char **BKE_sound_get_device_names(void);
-bool BKE_sound_is_jack_supported(void);
-
#endif /* __BKE_SOUND_H__ */
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
new file mode 100644
index 00000000000..25931e2bbf5
--- /dev/null
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -0,0 +1,155 @@
+/*
+ * ***** 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-2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_STUDIOLIGHT_H__
+#define __BKE_STUDIOLIGHT_H__
+
+/** \file BKE_studiolight.h
+ * \ingroup bke
+ *
+ * Studio lighting for the 3dview
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_sys_types.h"
+
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+
+#include "IMB_imbuf_types.h"
+
+/*
+ * These defines are the indexes in the StudioLight.diffuse_light
+ * X_POS means the light that is traveling towards the positive X
+ * So Light direction.
+ */
+#define STUDIOLIGHT_X_POS 0
+#define STUDIOLIGHT_X_NEG 1
+#define STUDIOLIGHT_Y_POS 2
+#define STUDIOLIGHT_Y_NEG 3
+#define STUDIOLIGHT_Z_POS 4
+#define STUDIOLIGHT_Z_NEG 5
+
+#define STUDIOLIGHT_ICON_ID_TYPE_RADIANCE (1 << 0)
+#define STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE (1 << 1)
+#define STUDIOLIGHT_ICON_ID_TYPE_MATCAP (1 << 2)
+#define STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED (1 << 3)
+
+#define STUDIOLIGHT_MAX_LIGHT 4
+
+#define STUDIOLIGHT_ICON_SIZE 96
+
+/* Only 1 - 5 is supported */
+#define STUDIOLIGHT_SH_BANDS 2
+
+#define STUDIOLIGHT_SH_COEFS_LEN (STUDIOLIGHT_SH_BANDS * STUDIOLIGHT_SH_BANDS)
+
+#if STUDIOLIGHT_SH_BANDS > 3
+/* Bypass L3 */
+#define STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN (STUDIOLIGHT_SH_COEFS_LEN - 7)
+#else
+#define STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN STUDIOLIGHT_SH_COEFS_LEN
+#endif
+
+struct GPUTexture;
+struct StudioLight;
+
+/* StudioLight.flag */
+enum StudioLightFlag {
+ STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED = (1 << 0),
+/* STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED = (1 << 1), */
+ STUDIOLIGHT_INTERNAL = (1 << 2),
+ STUDIOLIGHT_EXTERNAL_FILE = (1 << 3),
+ STUDIOLIGHT_TYPE_STUDIO = (1 << 4),
+ STUDIOLIGHT_TYPE_WORLD = (1 << 5),
+ STUDIOLIGHT_TYPE_MATCAP = (1 << 6),
+ STUDIOLIGHT_EXTERNAL_IMAGE_LOADED = (1 << 7),
+ STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED = (1 << 8),
+ STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE = (1 << 9),
+ STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE = (1 << 10),
+ STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11),
+ STUDIOLIGHT_USER_DEFINED = (1 << 12),
+ STUDIOLIGHT_UI_EXPANDED = (1 << 13),
+};
+
+#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE)
+#define STUDIOLIGHT_FLAG_ORIENTATIONS (STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_TYPE_WORLD | STUDIOLIGHT_TYPE_MATCAP)
+#define STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE (STUDIOLIGHT_TYPE_WORLD)
+#define STUDIOLIGHT_ORIENTATIONS_SOLID (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_TYPE_STUDIO)
+
+typedef void StudioLightFreeFunction(struct StudioLight *, void *data);
+
+typedef struct StudioLight {
+ struct StudioLight *next, *prev;
+
+ int index;
+ int flag;
+ char name[FILE_MAXFILE];
+ char path[FILE_MAX];
+ char *path_irr_cache;
+ char *path_sh_cache;
+ int icon_id_irradiance;
+ int icon_id_radiance;
+ int icon_id_matcap;
+ int icon_id_matcap_flipped;
+ float spherical_harmonics_coefs[STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN][3];
+ float light_direction[3];
+ ImBuf *equirect_radiance_buffer;
+ ImBuf *equirect_irradiance_buffer;
+ ImBuf *radiance_cubemap_buffers[6];
+ struct GPUTexture *equirect_radiance_gputexture;
+ struct GPUTexture *equirect_irradiance_gputexture;
+ SolidLight light[STUDIOLIGHT_MAX_LIGHT];
+ float light_ambient[3];
+
+ /*
+ * Free function to clean up the running icons previews (wmJob) the usage is in
+ * interface_icons. Please be aware that this was build to handle only one free function
+ * that cleans up all icons. just to keep the code simple.
+ */
+ StudioLightFreeFunction *free_function;
+ void *free_function_data;
+} StudioLight;
+
+void BKE_studiolight_init(void);
+void BKE_studiolight_free(void);
+struct StudioLight *BKE_studiolight_find(const char *name, int flag);
+struct StudioLight *BKE_studiolight_findindex(int index, int flag);
+struct StudioLight *BKE_studiolight_find_first(int flag);
+void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type);
+struct ListBase *BKE_studiolight_listbase(void);
+void BKE_studiolight_ensure_flag(StudioLight *sl, int flag);
+void BKE_studiolight_refresh(void);
+StudioLight *BKE_studiolight_load(const char *path, int orientation);
+StudioLight *BKE_studiolight_create(const char *path, const SolidLight light[4], const float light_ambient[3]);
+StudioLight *BKE_studiolight_studio_edit_get(void);
+void BKE_studiolight_remove(StudioLight *sl);
+void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data);
+void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id);
+
+#endif /* __BKE_STUDIOLIGHT_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
new file mode 100644
index 00000000000..0a09d3528b4
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -0,0 +1,237 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv.h
+ * \ingroup bke
+ * \since July 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_H__
+#define __BKE_SUBDIV_H__
+
+#include "BLI_compiler_compat.h"
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct MultiresModifierData;
+struct Object;
+struct OpenSubdiv_Converter;
+struct OpenSubdiv_Evaluator;
+struct OpenSubdiv_TopologyRefiner;
+struct Subdiv;
+struct SubdivToMeshSettings;
+
+typedef enum eSubdivVtxBoundaryInterpolation {
+ /* Do not interpolate boundaries. */
+ SUBDIV_VTX_BOUNDARY_NONE,
+ /* Sharpen edges. */
+ SUBDIV_VTX_BOUNDARY_EDGE_ONLY,
+ /* sharpen edges and corners, */
+ SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER,
+} eSubdivVtxBoundaryInterpolation;
+
+typedef enum eSubdivFVarLinearInterpolation {
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL,
+} eSubdivFVarLinearInterpolation;
+
+typedef struct SubdivSettings {
+ bool is_simple;
+ bool is_adaptive;
+ int level;
+ eSubdivVtxBoundaryInterpolation vtx_boundary_interpolation;
+ eSubdivFVarLinearInterpolation fvar_linear_interpolation;
+} SubdivSettings;
+
+/* NOTE: Order of enumerators MUST match order of values in SubdivStats. */
+typedef enum eSubdivStatsValue {
+ SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME = 0,
+ SUBDIV_STATS_SUBDIV_TO_MESH,
+ SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY,
+ SUBDIV_STATS_EVALUATOR_CREATE,
+ SUBDIV_STATS_EVALUATOR_REFINE,
+ SUBDIV_STATS_SUBDIV_TO_CCG,
+ SUBDIV_STATS_SUBDIV_TO_CCG_ELEMENTS,
+
+ NUM_SUBDIV_STATS_VALUES,
+} eSubdivStatsValue;
+
+typedef struct SubdivStats {
+ union {
+ struct {
+ /* Time spend on creating topology refiner, which includes time
+ * spend on conversion from Blender data to OpenSubdiv data, and
+ * time spend on topology orientation on OpenSubdiv C-API side.
+ */
+ double topology_refiner_creation_time;
+ /* Total time spent in BKE_subdiv_to_mesh(). */
+ double subdiv_to_mesh_time;
+ /* Geometry (MVert and co) creation time during SUBDIV_TYO_MESH. */
+ double subdiv_to_mesh_geometry_time;
+ /* Time spent on evaluator creation from topology refiner. */
+ double evaluator_creation_time;
+ /* Time spent on evaluator->refine(). */
+ double evaluator_refine_time;
+ /* Total time spent on whole CCG creation. */
+ double subdiv_to_ccg_time;
+ /* Time spent on CCG elements evaluation/initialization. */
+ double subdiv_to_ccg_elements_time;
+ };
+ double values_[NUM_SUBDIV_STATS_VALUES];
+ };
+
+ /* Per-value timestamp on when corresponding BKE_subdiv_stats_begin() was
+ * called.
+ */
+ double begin_timestamp_[NUM_SUBDIV_STATS_VALUES];
+} SubdivStats;
+
+/* Functor which evaluates dispalcement at a given (u, v) of given ptex face. */
+typedef struct SubdivDisplacement {
+ /* Return displacement which is to be added to the original coordinate.
+ *
+ * NOTE: This function is supposed to return "continuous" displacement for
+ * each pf PTex faces created for special (non-quad) polygon. This means,
+ * if displacement is stored on per-corner manner (like MDisps for multires)
+ * this is up the displacement implementation to average boundaries of the
+ * displacement grids if needed.
+ *
+ * Averaging of displacement for vertices created for over coarse vertices
+ * and edges is done by subdiv code.
+ */
+ void (*eval_displacement)(struct SubdivDisplacement *displacement,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3]);
+
+ /* Free the data, not the evaluator itself. */
+ void (*free)(struct SubdivDisplacement *displacement);
+
+ void *user_data;
+} SubdivDisplacement;
+
+/* This structure contains everything needed to construct subdivided surface.
+ * It does not specify storage, memory layout or anything else.
+ * It is possible to create different storages (like, grid based CPU side
+ * buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same
+ * Subdiv structure.
+ */
+typedef struct Subdiv {
+ /* Settings this subdivision surface is created for.
+ *
+ * It is read-only after assignment in BKE_subdiv_new_from_FOO().
+ */
+ SubdivSettings settings;
+ /* Topology refiner includes all the glue logic to feed Blender side
+ * topology to OpenSubdiv. It can be shared by both evaluator and GL mesh
+ * drawer.
+ */
+ struct OpenSubdiv_TopologyRefiner *topology_refiner;
+ /* CPU side evaluator. */
+ struct OpenSubdiv_Evaluator *evaluator;
+ /* Optional displacement evaluator. */
+ struct SubdivDisplacement *displacement_evaluator;
+ /* Statistics for debugging. */
+ SubdivStats stats;
+
+ /* Cached values, are not supposed to be accessed directly. */
+ struct {
+ /* Indexed by base face index, element indicates total number of ptex
+ *faces created for preceding base faces.
+ */
+ int *face_ptex_offset;
+ } cache_;
+} Subdiv;
+
+/* ================================ HELPERS ================================= */
+
+/* NOTE: uv_smooth is eSubsurfUVSmooth. */
+eSubdivFVarLinearInterpolation
+BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth);
+
+/* =============================== STATISTICS =============================== */
+
+void BKE_subdiv_stats_init(SubdivStats *stats);
+
+void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value);
+void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value);
+
+void BKE_subdiv_stats_print(const SubdivStats *stats);
+
+/* ============================== CONSTRUCTION ============================== */
+
+Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
+ struct OpenSubdiv_Converter *converter);
+
+Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
+ struct Mesh *mesh);
+
+void BKE_subdiv_free(Subdiv *subdiv);
+
+/* ============================ DISPLACEMENT API ============================ */
+
+void BKE_subdiv_displacement_attach_from_multires(
+ Subdiv *subdiv,
+ const struct Mesh *mesh,
+ const struct MultiresModifierData *mmd);
+
+void BKE_subdiv_displacement_detach(Subdiv *subdiv);
+
+/* ============================ TOPOLOGY HELPERS ============================ */
+
+int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
+
+/* ============================= VARIOUS HELPERS ============================ */
+
+/* For a given (ptex_u, ptex_v) within a ptex face get corresponding
+ * (grid_u, grid_v) within a grid.
+ */
+BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(
+ const float ptex_u, const float ptex_v,
+ float *r_grid_u, float *r_grid_v);
+
+/* For a given subdivision level (which is NOT refinement level) get size of
+ * CCG grid (number of grid points on a side).
+ */
+BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level);
+
+/* Simplified version of mdisp_rot_face_to_crn, only handles quad and
+ * works in normalized coordinates.
+ *
+ * NOTE: Output coordinates are in ptex coordinates.
+ */
+BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(
+ const float u, const float v,
+ float *r_u, float *r_v);
+
+#endif /* __BKE_SUBDIV_H__ */
+
+#include "intern/subdiv_inline.h"
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
new file mode 100644
index 00000000000..b2aaf6fc4cc
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -0,0 +1,249 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv_ccg.h
+ * \ingroup bke
+ * \since July 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_CCG_H__
+#define __BKE_SUBDIV_CCG_H__
+
+#include "BKE_customdata.h"
+#include "BLI_bitmap.h"
+#include "BLI_sys_types.h"
+
+struct CCGElem;
+struct CCGFace;
+struct CCGKey;
+struct DMFlagMat;
+struct Mesh;
+struct Subdiv;
+
+/* =============================================================================
+ * Masks.
+ */
+
+/* Functor which evaluates mask value at a given (u, v) of given ptex face. */
+typedef struct SubdivCCGMask {
+ float (*eval_mask)(struct SubdivCCGMask *mask,
+ const int ptex_face_index,
+ const float u, const float v);
+
+ /* Free the data, not the evaluator itself. */
+ void (*free)(struct SubdivCCGMask *mask);
+
+ void *user_data;
+} SubdivCCGMask;
+
+/* Return true if mesh has mask and evaluator can be used. */
+bool BKE_subdiv_ccg_mask_init_from_paint(
+ SubdivCCGMask *mask_evaluator,
+ const struct Mesh *mesh);
+
+/* =============================================================================
+ * SubdivCCG.
+ */
+
+typedef struct SubdivToCCGSettings {
+ /* Resolution at which regular ptex (created for quad polygon) are being
+ * evaluated. This defines how many vertices final mesh will have: every
+ * regular ptex has resolution^2 vertices. Special (irregular, or ptex
+ * created for a corner of non-quad polygon) will have resolution of
+ * `resolution - 1`.
+ */
+ int resolution;
+ /* Denotes which extra layers to be added to CCG elements. */
+ bool need_normal;
+ bool need_mask;
+} SubdivToCCGSettings;
+
+/* This is actually a coarse face, which consists of multiple CCG grids. */
+typedef struct SubdivCCGFace {
+ /* Total number of grids in this face.
+ *
+ * This 1:1 corresponds to a number of corners (or loops) from a coarse
+ * face.
+ */
+ int num_grids;
+ /* Index of first grid from this face in SubdivCCG->grids array. */
+ int start_grid_index;
+} SubdivCCGFace;
+
+/* Definition of an edge which is adjacent to at least one of the faces. */
+typedef struct SubdivCCGAdjacentEdge {
+ int num_adjacent_faces;
+ /* Indexed by adjacent face index. */
+ SubdivCCGFace **faces;
+ /* Indexed by adjacent face index, then by point index on the edge.
+ * points to a grid element.
+ */
+ struct CCGElem ***boundary_elements;
+} SubdivCCGAdjacentEdge;
+
+/* Definition of a vertex which is adjacent to at least one of the faces. */
+typedef struct SubdivCCGAdjacentVertex {
+ int num_adjacent_faces;
+ /* Indexed by adjacent face index. */
+ SubdivCCGFace **faces;
+ /* Indexed by adjacent face index, points to a grid element.
+ */
+ struct CCGElem **corner_elements;
+} SubdivCCGAdjacentVertex;
+
+/* Representation of subdivision surface which uses CCG grids. */
+typedef struct SubdivCCG {
+ /* This is a subdivision surface this CCG was created for.
+ *
+ * TODO(sergey): Make sure the whole descriptor is valid, including all the
+ * displacement attached to the surface.
+ */
+ struct Subdiv *subdiv;
+ /* A level at which geometry was subdivided. This is what defines grid
+ * resolution. It is NOT the topology refinement level.
+ */
+ int level;
+ /* Resolution of grid. All grids have matching resolution, and resolution
+ * is same as ptex created for non-quad polygons.
+ */
+ int grid_size;
+ /* Grids represent limit surface, with displacement applied. Grids are
+ * corresponding to face-corners of coarse mesh, each grid has
+ * grid_size^2 elements.
+ */
+ /* Indexed by a grid index, points to a grid data which is stored in
+ * grids_storage.
+ */
+ struct CCGElem **grids;
+ /* Flat array of all grids' data. */
+ unsigned char *grids_storage;
+ int num_grids;
+ /* Loose edges, each array element contains grid_size elements
+ * corresponding to vertices created by subdividing coarse edges.
+ */
+ struct CCGElem **edges;
+ int num_edges;
+ /* Loose vertices. Every element corresponds to a loose vertex from a coarse
+ * mesh, every coarse loose vertex corresponds to a single sundivided
+ * element.
+ */
+ struct CCGElem *vertices;
+ int num_vertices;
+ /* Denotes which layers present in the elements.
+ *
+ * Grids always has coordinates, followed by extra layers which are set to
+ * truth here.
+ */
+ bool has_normal;
+ bool has_mask;
+ /* Offsets of corresponding data layers in the elements. */
+ int normal_offset;
+ int mask_offset;
+
+ /* Faces from which grids are emitted. */
+ int num_faces;
+ SubdivCCGFace *faces;
+ /* Indexed by grid index, points to corresponding face from `faces`. */
+ SubdivCCGFace **grid_faces;
+
+ /* Edges which are adjacent to faces.
+ * Used for faster grid stitching, in the cost of extra memory.
+ */
+ int num_adjacent_edges;
+ SubdivCCGAdjacentEdge *adjacent_edges;
+
+ /* Vertices which are adjacent to faces
+ * Used for faster grid stitching, in the cost of extra memory.
+ */
+ int num_adjacent_vertices;
+ SubdivCCGAdjacentVertex *adjacent_vertices;
+
+ struct DMFlagMat *grid_flag_mats;
+ BLI_bitmap **grid_hidden;
+
+ /* TODO(sergey): Consider adding some accessors to a "decoded" geometry,
+ * to make integration with draw manager and such easy.
+ */
+
+ /* TODO(sergey): Consider adding CD layers here, so we can draw final mesh
+ * from grids, and have UVs and such work.
+ */
+
+ /* Integration with sculpting. */
+ /* TODO(sergey): Is this really best way to go? Kind of annoying to have
+ * such use-related flags in a more or less generic structure.
+ */
+ struct {
+ /* Corresponds to MULTIRES_COORDS_MODIFIED. */
+ bool coords;
+ /* Corresponds to MULTIRES_HIDDEN_MODIFIED. */
+ bool hidden;
+ } dirty;
+} SubdivCCG;
+
+/* Create real hi-res CCG from subdivision.
+ *
+ * NOTE: Subdiv is expected to be refined and ready for evaluation.
+ * NOTE: CCG becomes an owner of subdiv.
+ *
+ * TODO(sergey): Allow some user-counter or more explicit control over who owns
+ * the Subdiv. The goal should be to allow viewport GL Mesh and CCG to share
+ * same Subsurf without conflicts.
+ */
+struct SubdivCCG *BKE_subdiv_to_ccg(
+ struct Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ SubdivCCGMask *mask_evaluator);
+
+/* Destroy CCG representation of subdivision surface. */
+void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg);
+
+/* Helper function, creates Mesh structure which is properly setup to use
+ * grids.
+ */
+struct Mesh *BKE_subdiv_to_ccg_mesh(
+ struct Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ const struct Mesh *coarse_mesh);
+
+/* Create a key for accessing grid elements at a given level. */
+void BKE_subdiv_ccg_key(
+ struct CCGKey *key, const SubdivCCG *subdiv_ccg, int level);
+void BKE_subdiv_ccg_key_top_level(
+ struct CCGKey *key, const SubdivCCG *subdiv_ccg);
+
+/* Recalculate all normals based on grid element coordinates. */
+void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg);
+
+/* Average grid coordinates and normals along the grid boundatries. */
+void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg);
+
+/* Similar to above, but only updates given faces. */
+void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG *subdiv_ccg,
+ struct CCGFace **effected_faces,
+ int num_effected_faces);
+
+#endif /* __BKE_SUBDIV_CCG_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
new file mode 100644
index 00000000000..0ea5c978e62
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -0,0 +1,127 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv_eval.h
+ * \ingroup bke
+ * \since September 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_EVAL_H__
+#define __BKE_SUBDIV_EVAL_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+
+/* Returns true if evaluator is ready for use. */
+bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
+bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv,
+ const struct Mesh *mesh);
+
+/* Single point queries. */
+
+void BKE_subdiv_eval_limit_point(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3]);
+void BKE_subdiv_eval_limit_point_and_derivatives(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], float r_dPdu[3], float r_dPdv[3]);
+void BKE_subdiv_eval_limit_point_and_normal(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], float r_N[3]);
+void BKE_subdiv_eval_limit_point_and_short_normal(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], short r_N[3]);
+
+void BKE_subdiv_eval_face_varying(
+ struct Subdiv *subdiv,
+ const int face_varying_channel,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_varying[2]);
+
+/* NOTE: Expects derivatives to be correct.
+ *
+ * TODO(sergey): This is currently used together with
+ * BKE_subdiv_eval_final_point() which cas easily evaluate derivatives.
+ * Would be nice to have dispalcement evaluation function which does not require
+ * knowing derivatives ahead of a time.
+ */
+void BKE_subdiv_eval_displacement(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3]);
+
+void BKE_subdiv_eval_final_point(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3]);
+
+/* Patch queries at given resolution.
+ *
+ * Will evaluate patch at uniformly distributed (u, v) coordinates on a grid
+ * of given resolution, producing resolution^2 evaluation points. The order
+ * goes as u in rows, v in columns.
+ */
+
+void BKE_subdiv_eval_limit_patch_resolution_point(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *buffer, const int offset, const int stride);
+void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *du_buffer, const int du_offset, const int du_stride,
+ void *dv_buffer, const int dv_offset, const int dv_stride);
+void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride);
+void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride);
+
+#endif /* __BKE_SUBDIV_EVAL_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h
new file mode 100644
index 00000000000..d4ef0ee3601
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_foreach.h
@@ -0,0 +1,181 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv_foreach.h
+ * \ingroup bke
+ * \since September 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_FOREACH_H__
+#define __BKE_SUBDIV_FOREACH_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+struct SubdivForeachContext;
+struct SubdivToMeshSettings;
+
+typedef bool (*SubdivForeachTopologyInformationCb)(
+ const struct SubdivForeachContext *context,
+ const int num_vertices,
+ const int num_edges,
+ const int num_loops,
+ const int num_polygons);
+
+typedef void (*SubdivForeachVertexFromCornerCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_vertex_index,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index);
+
+typedef void (*SubdivForeachVertexFromEdgeCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_edge_index,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index);
+
+typedef void (*SubdivForeachVertexInnerCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index);
+
+typedef void (*SubdivForeachEdgeCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int coarse_edge_index,
+ const int subdiv_edge_index,
+ const int subdiv_v1, const int subdiv_v2);
+
+typedef void (*SubdivForeachLoopCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_loop_index,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_loop_index,
+ const int subdiv_vertex_index, const int subdiv_edge_index);
+
+typedef void (*SubdivForeachPolygonCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int coarse_poly_index,
+ const int subdiv_poly_index,
+ const int start_loop_index, const int num_loops);
+
+typedef void (*SubdivForeachLooseCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int coarse_vertex_index,
+ const int subdiv_vertex_index);
+
+typedef void (*SubdivForeachVertexOfLooseEdgeCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int coarse_edge_index,
+ const float u,
+ const int subdiv_vertex_index);
+
+typedef struct SubdivForeachContext {
+ /* Is called when topology information becomes available.
+ * Is only called once.
+ *
+ * NOTE: If this callback returns false, the foreach loop is aborted.
+ */
+ SubdivForeachTopologyInformationCb topology_info;
+ /* These callbacks are called from every ptex which shares "emitting"
+ * vertex or edge.
+ */
+ SubdivForeachVertexFromCornerCb vertex_every_corner;
+ SubdivForeachVertexFromEdgeCb vertex_every_edge;
+ /* Those callbacks are run once per subdivision vertex, ptex is undefined
+ * as in it will be whatever first ptex face happened to be tarversed in
+ * the multi-threaded environment ahd which shares "emitting" vertex or
+ * edge.
+ */
+ SubdivForeachVertexFromCornerCb vertex_corner;
+ SubdivForeachVertexFromEdgeCb vertex_edge;
+ /* Called exactly once, always corresponds to a single ptex face. */
+ SubdivForeachVertexInnerCb vertex_inner;
+ /* Called once for each loose vertex. One loose coarse vertexcorresponds
+ * to a single subdivision vertex.
+ */
+ SubdivForeachLooseCb vertex_loose;
+ /* Called once per vertex created for loose edge. */
+ SubdivForeachVertexOfLooseEdgeCb vertex_of_loose_edge;
+ /* NOTE: If subdivided edge does not come from coarse edge, ORIGINDEX_NONE
+ * will be passed as coarse_edge_index.
+ */
+ SubdivForeachEdgeCb edge;
+ /* NOTE: If subdivided loop does not come from coarse loop, ORIGINDEX_NONE
+ * will be passed as coarse_loop_index.
+ */
+ SubdivForeachLoopCb loop;
+ SubdivForeachPolygonCb poly;
+
+ /* User-defined pointer, to allow callbacks know something about context the
+ * traversal is happening for,
+ */
+ void *user_data;
+
+ /* Initial value of TLS data. */
+ void *user_data_tls;
+ /* Size of TLS data. */
+ size_t user_data_tls_size;
+ /* Function to free TLS storage. */
+ void (*user_data_tls_free)(void *tls);
+} SubdivForeachContext;
+
+/* Invokes callbacks in the order and with values which corresponds to creation
+ * of final subdivided mesh.
+ *
+ * Returns truth if the whole topology was traversed, without any early exits.
+ *
+ * TODO(sergey): Need to either get rid of subdiv or of coarse_mesh.
+ * The main point here is th be abel to get base level topology, which can be
+ * done with either of those. Having both of them is kind of redundant.
+ */
+bool BKE_subdiv_foreach_subdiv_geometry(
+ struct Subdiv *subdiv,
+ const struct SubdivForeachContext *context,
+ const struct SubdivToMeshSettings *mesh_settings,
+ const struct Mesh *coarse_mesh);
+
+#endif /* __BKE_SUBDIV_FOREACH_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_mesh.h b/source/blender/blenkernel/BKE_subdiv_mesh.h
new file mode 100644
index 00000000000..f719527eed8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_mesh.h
@@ -0,0 +1,56 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv_mesh.h
+ * \ingroup bke
+ * \since September 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_MESH_H__
+#define __BKE_SUBDIV_MESH_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+
+typedef struct SubdivToMeshSettings {
+ /* Resolution at which regular ptex (created for quad polygon) are being
+ * evaluated. This defines how many vertices final mesh will have: every
+ * regular ptex has resolution^2 vertices. Special (irregular, or ptex
+ * created for a corner of non-quad polygon) will have resolution of
+ * `resolution - 1`.
+ */
+ int resolution;
+} SubdivToMeshSettings;
+
+/* Create real hi-res mesh from subdivision, all geometry is "real". */
+struct Mesh *BKE_subdiv_to_mesh(
+ struct Subdiv *subdiv,
+ const SubdivToMeshSettings *settings,
+ const struct Mesh *coarse_mesh);
+
+#endif /* __BKE_SUBDIV)MESH_H__ */
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 96320415b16..6cb09ff8822 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -67,6 +67,7 @@ typedef enum {
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
+ struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags);
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index b53af3cec53..e7a8fb1c4a9 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -112,10 +112,6 @@ bool txt_cursor_is_line_end(struct Text *text);
int txt_calc_tab_left(struct TextLine *line, int ch);
int txt_calc_tab_right(struct TextLine *line, int ch);
-#if 0
-void txt_print_undo (struct Text *text);
-#endif
-
/* utility functions, could be moved somewhere more generic but are python/text related */
int text_check_bracket(const char ch);
bool text_check_delim(const char ch);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 7ffa22ac49b..228e17cd2ef 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -40,7 +40,6 @@ extern "C" {
struct bNode;
struct Brush;
struct ColorBand;
-struct EnvMap;
struct FreestyleLineStyle;
struct ImagePool;
struct Lamp;
@@ -53,7 +52,6 @@ struct PointDensity;
struct Tex;
struct TexMapping;
struct TexResult;
-struct VoxelData;
struct World;
/* in ColorBand struct */
@@ -76,27 +74,17 @@ struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot);
// void autotexname(struct Tex *tex);
struct Tex *give_current_object_texture(struct Object *ob);
-struct Tex *give_current_material_texture(struct Material *ma);
-struct Tex *give_current_lamp_texture(struct Lamp *la);
struct Tex *give_current_linestyle_texture(struct FreestyleLineStyle *linestyle);
-struct Tex *give_current_world_texture(struct World *world);
struct Tex *give_current_brush_texture(struct Brush *br);
struct Tex *give_current_particle_texture(struct ParticleSettings *part);
-struct bNode *give_current_material_texture_node(struct Material *ma);
-
bool give_active_mtex(struct ID *id, struct MTex ***mtex_ar, short *act);
void set_active_mtex(struct ID *id, short act);
void set_current_brush_texture(struct Brush *br, struct Tex *tex);
-void set_current_world_texture(struct World *wo, struct Tex *tex);
-void set_current_material_texture(struct Material *ma, struct Tex *tex);
-void set_current_lamp_texture(struct Lamp *la, struct Tex *tex);
void set_current_linestyle_texture(struct FreestyleLineStyle *linestyle, struct Tex *tex);
void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex);
-bool has_current_material_texture(struct Material *ma);
-
struct TexMapping *BKE_texture_mapping_add(int type);
void BKE_texture_mapping_default(struct TexMapping *texmap, int type);
void BKE_texture_mapping_init(struct TexMapping *texmap);
@@ -104,26 +92,12 @@ void BKE_texture_mapping_init(struct TexMapping *texmap);
struct ColorMapping *BKE_texture_colormapping_add(void);
void BKE_texture_colormapping_default(struct ColorMapping *colormap);
-void BKE_texture_envmap_free_data(struct EnvMap *env);
-void BKE_texture_envmap_free(struct EnvMap *env);
-struct EnvMap *BKE_texture_envmap_add(void);
-struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env, const int flag);
-
void BKE_texture_pointdensity_init_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free(struct PointDensity *pd);
struct PointDensity *BKE_texture_pointdensity_add(void);
struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag);
-void BKE_texture_voxeldata_free_data(struct VoxelData *vd);
-void BKE_texture_voxeldata_free(struct VoxelData *vd);
-struct VoxelData *BKE_texture_voxeldata_add(void);
-struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd);
-
-void BKE_texture_ocean_free(struct OceanTex *ot);
-struct OceanTex *BKE_texture_ocean_add(void);
-struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot, const int flag);
-
bool BKE_texture_dependsOnTime(const struct Tex *texture);
bool BKE_texture_is_image_user(const struct Tex *tex);
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 13302caa09d..0c3b118d947 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -32,6 +32,7 @@
* \author Sergey Sharybin
*/
+struct Depsgraph;
struct bGPDlayer;
struct ImBuf;
struct ListBase;
@@ -61,7 +62,8 @@ struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *trac
struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(struct MovieTracking *tracking);
/* matrices for constraints and drawing */
-void BKE_tracking_get_camera_object_matrix(struct Scene *scene, struct Object *ob, float mat[4][4]);
+void BKE_tracking_get_camera_object_matrix(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float mat[4][4]);
void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking, struct MovieTrackingObject *object,
int framenr, int winx, int winy, float mat[4][4]);
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index 82a4659eec7..59475d3098a 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -31,14 +31,23 @@
extern "C" {
#endif
+struct UnitSettings;
+
/* in all cases the value is assumed to be scaled by the user preference */
/* humanly readable representation of a value in units (used for button drawing) */
-size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
+size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
+size_t bUnit_AsString2(char *str, int len_max, double value, int prec, int type, const struct UnitSettings *settings, bool pad);
/* replace units with values, used before python button evaluation */
bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type);
+/* return true if the string contains any valid unit for the given type */
+bool bUnit_ContainsUnit(const char *str, int system, int type);
+
+/* if user does not specify a unit, multiply with this value */
+double bUnit_PreferredUnitScalar(const struct UnitSettings *settings, int type);
+
/* make string keyboard-friendly: 10µm --> 10um */
void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type);
@@ -56,9 +65,12 @@ bool bUnit_IsValid(int system, int type);
void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len);
int bUnit_GetBaseUnit(const void *usys_pt);
+int bUnit_GetBaseUnitOfType(int system, int type);
const char *bUnit_GetName(const void *usys_pt, int index);
const char *bUnit_GetNameDisplay(const void *usys_pt, int index);
+const char *bUnit_GetIdentifier(const void *usys_pt, int index);
double bUnit_GetScaler(const void *usys_pt, int index);
+bool bUnit_IsSuppressed(const void *usys_pt, int index);
/* aligned with PropertyUnit */
enum {
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
new file mode 100644
index 00000000000..6902fb631e4
--- /dev/null
+++ b/source/blender/blenkernel/BKE_workspace.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_workspace.h
+ * \ingroup bke
+ */
+
+#ifndef __BKE_WORKSPACE_H__
+#define __BKE_WORKSPACE_H__
+
+#include "BLI_compiler_attrs.h"
+
+struct bScreen;
+struct bToolRef;
+struct Main;
+struct Scene;
+struct TransformOrientation;
+struct ViewLayer;
+
+/* -------------------------------------------------------------------- */
+/* Create, delete, init */
+
+struct WorkSpace *BKE_workspace_add(struct Main *bmain, const char *name);
+void BKE_workspace_free(struct WorkSpace *workspace);
+void BKE_workspace_remove(struct Main *bmain, struct WorkSpace *workspace);
+
+struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Main *bmain);
+void BKE_workspace_instance_hook_free(const struct Main *bmain, struct WorkSpaceInstanceHook *hook);
+
+struct WorkSpaceLayout *BKE_workspace_layout_add(
+ struct Main *bmain,
+ struct WorkSpace *workspace,
+ struct bScreen *screen,
+ const char *name) ATTR_NONNULL();
+void BKE_workspace_layout_remove(
+ struct Main *bmain,
+ struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL();
+
+void BKE_workspace_relations_free(
+ ListBase *relation_list);
+
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+struct WorkSpaceLayout *BKE_workspace_layout_find(
+ const struct WorkSpace *workspace, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+struct WorkSpaceLayout *BKE_workspace_layout_find_global(
+ const struct Main *bmain, const struct bScreen *screen,
+ struct WorkSpace **r_workspace) ATTR_NONNULL(1, 2);
+
+struct WorkSpaceLayout *BKE_workspace_layout_iter_circular(
+ const struct WorkSpace *workspace, struct WorkSpaceLayout *start,
+ bool (*callback)(const struct WorkSpaceLayout *layout, void *arg),
+ void *arg, const bool iter_backward);
+
+void BKE_workspace_tool_remove(
+ struct WorkSpace *workspace, struct bToolRef *tref) ATTR_NONNULL(1, 2);
+
+/* -------------------------------------------------------------------- */
+/* Getters/Setters */
+
+#define GETTER_ATTRS ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
+#define SETTER_ATTRS ATTR_NONNULL(1)
+
+struct WorkSpace *BKE_workspace_active_get(struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace) SETTER_ATTRS;
+struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook, struct WorkSpaceLayout *layout) SETTER_ATTRS;
+struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_screen_set(
+ struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct bScreen *screen) SETTER_ATTRS;
+
+struct ListBase *BKE_workspace_layouts_get(struct WorkSpace *workspace) GETTER_ATTRS;
+
+const char *BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
+void BKE_workspace_layout_name_set(
+ struct WorkSpace *workspace, struct WorkSpaceLayout *layout, const char *new_name) ATTR_NONNULL();
+struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
+void BKE_workspace_layout_screen_set(struct WorkSpaceLayout *layout, struct bScreen *screen) SETTER_ATTRS;
+
+struct WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+ const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS;
+void BKE_workspace_hook_layout_for_workspace_set(
+ struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL();
+
+bool BKE_workspace_owner_id_check(
+ const struct WorkSpace *workspace, const char *owner_id) ATTR_NONNULL();
+
+#undef GETTER_ATTRS
+#undef SETTER_ATTRS
+
+#endif /* __BKE_WORKSPACE_H__ */
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index b28bac08727..eb0548c682e 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -33,6 +33,7 @@
* \author nzc
*/
+struct Depsgraph;
struct Main;
struct World;
@@ -43,5 +44,6 @@ void BKE_world_copy_data(struct Main *bmain, struct World *wrld_dst, const struc
struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld);
struct World *BKE_world_localize(struct World *wrld);
void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local);
+void BKE_world_eval(struct Depsgraph *depsgraph, struct World *world);
-#endif /* __BKE_WORLD_H__ */
+#endif
diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h
deleted file mode 100644
index c38b1b196c3..00000000000
--- a/source/blender/blenkernel/BKE_writeframeserver.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_WRITEFRAMESERVER_H__
-#define __BKE_WRITEFRAMESERVER_H__
-
-/** \file BKE_writeframeserver.h
- * \ingroup bke
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct RenderData;
-struct ReportList;
-struct Scene;
-
-int BKE_frameserver_start(
- void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
- struct ReportList *reports, bool preview, const char *suffix);
-void BKE_frameserver_end(void *context_v);
-int BKE_frameserver_append(
- void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, const char *suffix, struct ReportList *reports);
-int BKE_frameserver_loop(void *context_v, struct RenderData *rd, struct ReportList *reports);
-void *BKE_frameserver_context_create(void);
-void BKE_frameserver_context_free(void *context_v);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 45f2ac083dd..00b64379647 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../blenloader
../blentranslation
../depsgraph
+ ../draw
../gpu
../ikplugin
../imbuf
@@ -37,6 +38,8 @@ set(INC
../makesrna
../bmesh
../modifiers
+ ../gpencil_modifiers
+ ../shader_fx
../nodes
../physics
../render/extern/include
@@ -50,6 +53,7 @@ set(INC
../../../intern/atomic
../../../intern/clog
../../../intern/libmv
+ ../../../intern/opensubdiv
../../../extern/curve_fit_nd
)
@@ -76,17 +80,17 @@ set(SRC
intern/blender.c
intern/blender_copybuffer.c
intern/blender_undo.c
+ intern/blender_user_menu.c
intern/blendfile.c
- intern/bmfont.c
intern/boids.c
intern/bpath.c
intern/brush.c
- intern/bullet.c
intern/bvhutils.c
intern/cachefile.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
+ intern/collection.c
intern/collision.c
intern/colorband.c
intern/colortools.c
@@ -99,13 +103,14 @@ set(SRC
intern/customdata_file.c
intern/data_transfer.c
intern/deform.c
- intern/depsgraph.c
intern/displist.c
intern/dynamicpaint.c
intern/editderivedmesh.c
intern/editlattice.c
intern/editmesh.c
intern/editmesh_bvh.c
+ intern/editmesh_cache.c
+ intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
intern/fluidsim.c
@@ -113,8 +118,9 @@ set(SRC
intern/font.c
intern/freestyle.c
intern/gpencil.c
- intern/group.c
+ intern/gpencil_modifier.c
intern/icons.c
+ intern/icons_rasterize.c
intern/idcode.c
intern/idprop.c
intern/idprop_utils.c
@@ -122,13 +128,16 @@ set(SRC
intern/image_gen.c
intern/ipo.c
intern/key.c
+ intern/keyconfig.c
intern/lamp.c
intern/lattice.c
intern/library.c
intern/library_idmap.c
+ intern/library_override.c
intern/library_query.c
intern/library_remap.c
intern/linestyle.c
+ intern/main.c
intern/mask.c
intern/mask_evaluate.c
intern/mask_rasterize.c
@@ -138,16 +147,22 @@ set(SRC
intern/mesh.c
intern/mesh_convert.c
intern/mesh_evaluate.c
+ intern/mesh_iterators.c
intern/mesh_mapping.c
+ intern/mesh_merge.c
intern/mesh_remap.c
+ intern/mesh_runtime.c
+ intern/mesh_tangent.c
intern/mesh_validate.c
intern/modifier.c
- intern/modifiers_bmesh.c
intern/movieclip.c
intern/multires.c
+ intern/multires_reshape.c
+ intern/multires_subdiv.c
intern/nla.c
intern/node.c
intern/object.c
+ intern/object_facemap.c
intern/object_deform.c
intern/object_dupli.c
intern/object_update.c
@@ -155,6 +170,7 @@ set(SRC
intern/outliner_treehash.c
intern/packedFile.c
intern/paint.c
+ intern/paint_toolslots.c
intern/particle.c
intern/particle_child.c
intern/particle_distribute.c
@@ -162,22 +178,35 @@ set(SRC
intern/pbvh.c
intern/pbvh_bmesh.c
intern/pointcache.c
- intern/property.c
+ intern/layer.c
+ intern/layer_utils.c
+ intern/lightprobe.c
intern/report.c
intern/rigidbody.c
- intern/sca.c
intern/scene.c
intern/screen.c
intern/seqcache.c
intern/seqeffects.c
intern/seqmodifier.c
intern/sequencer.c
+ intern/shader_fx.c
intern/shrinkwrap.c
- intern/sketch.c
intern/smoke.c
intern/softbody.c
intern/sound.c
intern/speaker.c
+ intern/studiolight.c
+ intern/subdiv.c
+ intern/subdiv_ccg.c
+ intern/subdiv_ccg_mask.c
+ intern/subdiv_converter.c
+ intern/subdiv_converter_mesh.c
+ intern/subdiv_displacement.c
+ intern/subdiv_displacement_multires.c
+ intern/subdiv_eval.c
+ intern/subdiv_foreach.c
+ intern/subdiv_mesh.c
+ intern/subdiv_stats.c
intern/subsurf_ccg.c
intern/suggestions.c
intern/text.c
@@ -192,9 +221,9 @@ set(SRC
intern/tracking_util.c
intern/undo_system.c
intern/unit.c
+ intern/workspace.c
intern/world.c
intern/writeavi.c
- intern/writeframeserver.c
BKE_DerivedMesh.h
BKE_action.h
@@ -207,20 +236,19 @@ set(SRC
BKE_blender.h
BKE_blender_copybuffer.h
BKE_blender_undo.h
+ BKE_blender_user_menu.h
BKE_blender_version.h
BKE_blendfile.h
- BKE_bmfont.h
- BKE_bmfont_types.h
BKE_boids.h
BKE_bpath.h
BKE_brush.h
- BKE_bullet.h
BKE_bvhutils.h
BKE_cachefile.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h
BKE_cloth.h
+ BKE_collection.h
BKE_collision.h
BKE_colorband.h
BKE_colortools.h
@@ -232,12 +260,13 @@ set(SRC
BKE_customdata_file.h
BKE_data_transfer.h
BKE_deform.h
- BKE_depsgraph.h
BKE_displist.h
BKE_dynamicpaint.h
BKE_editlattice.h
BKE_editmesh.h
BKE_editmesh_bvh.h
+ BKE_editmesh_cache.h
+ BKE_editmesh_tangent.h
BKE_effect.h
BKE_fcurve.h
BKE_fluidsim.h
@@ -245,17 +274,19 @@ set(SRC
BKE_freestyle.h
BKE_global.h
BKE_gpencil.h
- BKE_group.h
+ BKE_gpencil_modifier.h
BKE_icons.h
BKE_idcode.h
BKE_idprop.h
BKE_image.h
BKE_ipo.h
BKE_key.h
+ BKE_keyconfig.h
BKE_lamp.h
BKE_lattice.h
BKE_library.h
BKE_library_idmap.h
+ BKE_library_override.h
BKE_library_query.h
BKE_library_remap.h
BKE_linestyle.h
@@ -265,14 +296,18 @@ set(SRC
BKE_mball.h
BKE_mball_tessellate.h
BKE_mesh.h
+ BKE_mesh_iterators.h
BKE_mesh_mapping.h
BKE_mesh_remap.h
+ BKE_mesh_runtime.h
+ BKE_mesh_tangent.h
BKE_modifier.h
BKE_movieclip.h
BKE_multires.h
BKE_nla.h
BKE_node.h
BKE_object.h
+ BKE_object_facemap.h
BKE_object_deform.h
BKE_ocean.h
BKE_outliner_treehash.h
@@ -281,19 +316,25 @@ set(SRC
BKE_particle.h
BKE_pbvh.h
BKE_pointcache.h
- BKE_property.h
+ BKE_layer.h
+ BKE_lightprobe.h
BKE_report.h
BKE_rigidbody.h
- BKE_sca.h
BKE_scene.h
BKE_screen.h
BKE_sequencer.h
+ BKE_shader_fx.h
BKE_shrinkwrap.h
- BKE_sketch.h
BKE_smoke.h
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
+ BKE_studiolight.h
+ BKE_subdiv.h
+ BKE_subdiv_ccg.h
+ BKE_subdiv_eval.h
+ BKE_subdiv_foreach.h
+ BKE_subdiv_mesh.h
BKE_subsurf.h
BKE_suggestions.h
BKE_text.h
@@ -301,19 +342,21 @@ set(SRC
BKE_tracking.h
BKE_undo_system.h
BKE_unit.h
+ BKE_workspace.h
BKE_world.h
BKE_writeavi.h
- BKE_writeframeserver.h
- depsgraph_private.h
nla_private.h
- tracking_private.h
particle_private.h
+ tracking_private.h
intern/CCGSubSurf.h
intern/CCGSubSurf_inline.h
intern/CCGSubSurf_intern.h
- intern/pbvh_intern.h
intern/data_transfer_intern.h
+ intern/multires_inline.h
+ intern/pbvh_intern.h
+ intern/subdiv_converter.h
+ intern/subdiv_inline.h
)
if(WITH_BINRELOC)
@@ -332,7 +375,7 @@ if(WIN32)
endif()
if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+ add_definitions(-DWITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
@@ -420,6 +463,10 @@ if(WITH_PYTHON)
)
add_definitions(-DWITH_PYTHON)
+ if(WITH_PYTHON_SAFETY)
+ add_definitions(-DWITH_PYTHON_SAFETY)
+ endif()
+
if(WITH_PYTHON_SECURITY)
add_definitions(-DWITH_PYTHON_SECURITY)
endif()
@@ -472,18 +519,6 @@ if(WITH_LZMA)
add_definitions(-DWITH_LZMA)
endif()
-if(WITH_GAMEENGINE)
- list(APPEND INC_SYS
- ../../../extern/recastnavigation
- )
- list(APPEND SRC
- intern/navmesh_conversion.c
- BKE_navmesh_conversion.h
- )
-
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
if(WITH_LIBMV)
add_definitions(-DWITH_LIBMV)
endif()
@@ -513,7 +548,6 @@ endif()
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
list(APPEND INC_SYS
- ../../../intern/opensubdiv
${OPENSUBDIV_INCLUDE_DIRS}
)
endif()
@@ -536,8 +570,4 @@ endif()
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
-endif()
-
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h
deleted file mode 100644
index 69ca75836d9..00000000000
--- a/source/blender/blenkernel/depsgraph_private.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * ***** 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) 2004 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/depsgraph_private.h
- * \ingroup bke
- */
-
-#ifndef __DEPSGRAPH_PRIVATE_H__
-#define __DEPSGRAPH_PRIVATE_H__
-
-#include "BKE_depsgraph.h"
-#include "DNA_constraint_types.h"
-#include "BKE_constraint.h"
-
-struct Scene;
-struct Group;
-struct EffectorWeights;
-struct ModifierData;
-
-/* **** DAG relation types *** */
-
-/* scene link to object */
-#define DAG_RL_SCENE (1 << 0)
-/* object link to data */
-#define DAG_RL_DATA (1 << 1)
-
-/* object changes object (parent, track, constraints) */
-#define DAG_RL_OB_OB (1 << 2)
-/* object changes obdata (hooks, constraints) */
-#define DAG_RL_OB_DATA (1 << 3)
-/* data changes object (vertex parent) */
-#define DAG_RL_DATA_OB (1 << 4)
-/* data changes data (deformers) */
-#define DAG_RL_DATA_DATA (1 << 5)
-
-#define DAG_NO_RELATION (1 << 6)
-
-#define DAG_RL_ALL_BUT_DATA (DAG_RL_SCENE | DAG_RL_OB_OB | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_DATA_DATA)
-#define DAG_RL_ALL (DAG_RL_ALL_BUT_DATA | DAG_RL_DATA)
-
-
-#define DAGQUEUEALLOC 50
-
-enum {
- DAG_WHITE = 0,
- DAG_GRAY = 1,
- DAG_BLACK = 2
-};
-
-typedef struct DagAdjList {
- struct DagNode *node;
- short type;
- int count; /* number of identical arcs */
- unsigned int lay; // for flushing redraw/rebuild events
- const char *name;
- struct DagAdjList *next;
-} DagAdjList;
-
-
-typedef struct DagNode {
- int color;
- short type;
- float x, y, k;
- void *ob;
- void *first_ancestor;
- int ancestor_count;
- unsigned int lay; /* accumulated layers of its relations + itself */
- unsigned int scelay; /* layers due to being in scene */
- uint64_t customdata_mask; /* customdata mask */
- int lasttime; /* if lasttime != DagForest->time, this node was not evaluated yet for flushing */
- int BFS_dist; /* BFS distance */
- int DFS_dist; /* DFS distance */
- int DFS_dvtm; /* DFS discovery time */
- int DFS_fntm; /* DFS Finishing time */
- struct DagAdjList *child;
- struct DagAdjList *parent;
- struct DagNode *next;
-
- /* Threaded evaluation routines */
- uint32_t num_pending_parents; /* number of parents which are not updated yet
- * this node has got.
- * Used by threaded update for faster detect whether node could be
- * updated aready.
- */
- bool scheduled;
-
- /* Runtime flags mainly used to determine which extra data is to be evaluated
- * during object_handle_update(). Such an extra data is what depends on the
- * DAG topology, meaning this flags indicates the data evaluation of which
- * depends on the node dependencies.
- */
- short eval_flags;
-} DagNode;
-
-typedef struct DagNodeQueueElem {
- struct DagNode *node;
- struct DagNodeQueueElem *next;
-} DagNodeQueueElem;
-
-typedef struct DagNodeQueue {
- DagNodeQueueElem *first;
- DagNodeQueueElem *last;
- int count;
- int maxlevel;
- struct DagNodeQueue *freenodes;
-} DagNodeQueue;
-
-/* forest as we may have more than one DAG unconnected */
-typedef struct DagForest {
- ListBase DagNode;
- struct GHash *nodeHash;
- int numNodes;
- bool is_acyclic;
- int time; /* for flushing/tagging, compare with node->lasttime */
- bool ugly_hack_sorry; /* prevent type check */
- bool need_update;
-} DagForest;
-
-// queue operations
-DagNodeQueue *queue_create(int slots);
-void queue_raz(DagNodeQueue *queue);
-void push_queue(DagNodeQueue *queue, DagNode *node);
-void push_stack(DagNodeQueue *queue, DagNode *node);
-DagNode *pop_queue(DagNodeQueue *queue);
-DagNode *get_top_node_queue(DagNodeQueue *queue);
-void queue_delete(DagNodeQueue *queue);
-
-// Dag management
-DagForest *dag_init(void);
-DagForest *build_dag(struct Main *bmain, struct Scene *sce, short mask);
-void free_forest(struct DagForest *Dag);
-DagNode *dag_find_node(DagForest *forest, void *fob);
-DagNode *dag_add_node(DagForest *forest, void *fob);
-DagNode *dag_get_node(DagForest *forest, void *fob);
-DagNode *dag_get_sub_node(DagForest *forest, void *fob);
-void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name);
-
-typedef bool (*DagCollobjFilterFunction)(struct Object *obj, struct ModifierData *md);
-
-void dag_add_collision_relations(DagForest *dag, struct Scene *scene, Object *ob, DagNode *node, struct Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name);
-void dag_add_forcefield_relations(DagForest *dag, struct Scene *scene, Object *ob, DagNode *node, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name);
-
-void graph_print_queue(DagNodeQueue *nqueue);
-void graph_print_queue_dist(DagNodeQueue *nqueue);
-void graph_print_adj_list(DagForest *dag);
-
-#endif /* __DEPSGRAPH_PRIVATE_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 40dea6ca663..6ec1b1b36b9 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -40,9 +40,11 @@
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
# include "opensubdiv_converter_capi.h"
+# include "opensubdiv_evaluator_capi.h"
+# include "opensubdiv_topology_refiner_capi.h"
#endif
-#include "GL/glew.h"
+#include "GPU_glew.h"
/***/
@@ -329,7 +331,7 @@ void ccgSubSurf_free(CCGSubSurf *ss)
CCGAllocatorHDL allocator = ss->allocator;
#ifdef WITH_OPENSUBDIV
if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
+ openSubdiv_deleteEvaluator(ss->osd_evaluator);
}
if (ss->osd_mesh != NULL) {
ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
@@ -341,7 +343,7 @@ void ccgSubSurf_free(CCGSubSurf *ss)
MEM_freeN(ss->osd_coarse_coords);
}
if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner);
+ openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
}
#endif
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index 50959d21425..e1cb82d7868 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -236,7 +236,7 @@ struct CCGSubSurf {
* Refiner is created from the modifier stack and used later from the main
* thread to construct GL mesh to avoid threaded access to GL.
*/
- struct OpenSubdiv_TopologyRefinerDescr *osd_topology_refiner; /* Only used at synchronization stage. */
+ struct OpenSubdiv_TopologyRefiner *osd_topology_refiner; /* Only used at synchronization stage. */
/* Denotes whether osd_mesh is invalid now due to topology changes and needs
* to be reconstructed.
*
@@ -249,7 +249,7 @@ struct CCGSubSurf {
/* ** CPU backend. ** */
/* Limit evaluator, used to evaluate CCG. */
- struct OpenSubdiv_EvaluatorDescr *osd_evaluator;
+ struct OpenSubdiv_Evaluator *osd_evaluator;
/* Next PTex face index, used while CCG synchronization
* to fill in PTex index of CCGFace.
*/
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 65c6518cee4..004a50205ba 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -42,8 +42,11 @@
#include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h"
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_gl_mesh_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "GPU_extensions.h"
#define OSD_LOG if (false) printf
@@ -131,7 +134,6 @@ static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
OpenSubdiv_Converter converter;
bool result;
if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) {
@@ -140,15 +142,10 @@ static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
/* TODO(sergey): De-duplicate with topology counter at the bottom of
* the file.
*/
- if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- result = openSubdiv_topologyRefnerCompareConverter(topology_refiner,
- &converter);
+ result = openSubdiv_topologyRefinerCompareWithConverter(
+ ss->osd_topology_refiner,
+ &converter);
ccgSubSurf_converter_free(&converter);
return result;
}
@@ -159,22 +156,13 @@ static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm)
return true;
}
if (ss->osd_topology_refiner != NULL) {
- int levels = openSubdiv_topologyRefinerGetSubdivLevel(
+ const int levels = ss->osd_topology_refiner->getSubdivisionLevel(
ss->osd_topology_refiner);
BLI_assert(ss->osd_mesh_invalid == true);
if (levels != ss->subdivLevels) {
return true;
}
}
- if (ss->osd_mesh != NULL && ss->osd_mesh_invalid == false) {
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner =
- openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- int levels = openSubdiv_topologyRefinerGetSubdivLevel(topology_refiner);
- BLI_assert(ss->osd_topology_refiner == NULL);
- if (levels != ss->subdivLevels) {
- return true;
- }
- }
if (ss->skip_grids == false) {
return compare_ccg_derivedmesh_topology(ss, dm) == false;
}
@@ -194,13 +182,13 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
/* Reset GPU part. */
ss->osd_mesh_invalid = true;
if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner);
+ openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
ss->osd_topology_refiner = NULL;
}
- /* Reste CPU side. */
+ /* Reset CPU side. */
if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
+ openSubdiv_deleteEvaluator(ss->osd_evaluator);
ss->osd_evaluator = NULL;
}
}
@@ -209,10 +197,10 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
{
BLI_assert(ss->meshIFC.numLayers == 3);
- openSubdiv_osdGLMeshUpdateVertexBuffer(ss->osd_mesh,
- (float *) ss->osd_coarse_coords,
- 0,
- ss->osd_num_coarse_coords);
+ ss->osd_mesh->setCoarsePositions(ss->osd_mesh,
+ (float *) ss->osd_coarse_coords,
+ 0,
+ ss->osd_num_coarse_coords);
}
bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
@@ -232,6 +220,9 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
CHECK_COMPUTE_TYPE(CUDA)
CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK)
CHECK_COMPUTE_TYPE(GLSL_COMPUTE)
+ default:
+ compute_type = OPENSUBDIV_EVALUATOR_CPU;
+ break;
#undef CHECK_COMPUTE_TYPE
}
@@ -256,9 +247,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(
ss->osd_topology_refiner,
- compute_type,
- ss->subdivLevels);
- ss->osd_topology_refiner = NULL;
+ compute_type);
if (UNLIKELY(ss->osd_mesh == NULL)) {
/* Most likely compute device is not available. */
@@ -266,13 +255,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
}
ccgSubSurf__updateGLMeshCoords(ss);
- openSubdiv_osdGLMeshRefine(ss->osd_mesh);
- openSubdiv_osdGLMeshSynchronize(ss->osd_mesh);
+ ss->osd_mesh->refine(ss->osd_mesh);
+ ss->osd_mesh->synchronize(ss->osd_mesh);
ss->osd_coarse_coords_invalid = false;
glBindVertexArray(ss->osd_vao);
- glBindBuffer(GL_ARRAY_BUFFER,
- openSubdiv_getOsdGLMeshVertexBuffer(ss->osd_mesh));
+ ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
@@ -286,12 +274,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
}
else if (ss->osd_coarse_coords_invalid) {
ccgSubSurf__updateGLMeshCoords(ss);
- openSubdiv_osdGLMeshRefine(ss->osd_mesh);
- openSubdiv_osdGLMeshSynchronize(ss->osd_mesh);
+ ss->osd_mesh->refine(ss->osd_mesh);
+ ss->osd_mesh->synchronize(ss->osd_mesh);
ss->osd_coarse_coords_invalid = false;
}
- openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index);
+ ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index);
return true;
}
@@ -302,12 +290,12 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
if (LIKELY(ss->osd_mesh != NULL)) {
glBindVertexArray(ss->osd_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
- openSubdiv_getOsdGLMeshPatchIndexBuffer(ss->osd_mesh));
+ ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh));
- openSubdiv_osdGLMeshBindVertexBuffer(ss->osd_mesh);
+ ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
glBindVertexArray(ss->osd_vao);
- openSubdiv_osdGLMeshDisplay(ss->osd_mesh, fill_quads,
- start_partition, num_partitions);
+ ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads,
+ start_partition, num_partitions);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -316,33 +304,21 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else if (ss->osd_mesh != NULL) {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
- else {
- return 0;
+ return ss->osd_topology_refiner->getNumFaces(
+ ss->osd_topology_refiner);
}
- return openSubdiv_topologyRefinerGetNumFaces(topology_refiner);
+ return 0;
}
/* Get number of vertices in base faces in a particular GL mesh. */
int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else if (ss->osd_mesh != NULL) {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
- else {
- return 0;
+ return ss->osd_topology_refiner->getNumFaceVertices(
+ ss->osd_topology_refiner, face);
}
- return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face);
+ return 0;
}
void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids)
@@ -450,17 +426,21 @@ void ccgSubSurf_evaluatorFVarUV(CCGSubSurf *ss,
static bool opensubdiv_createEvaluator(CCGSubSurf *ss)
{
OpenSubdiv_Converter converter;
- OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+ OpenSubdiv_TopologyRefiner *topology_refiner;
if (ss->fMap->numEntries == 0) {
/* OpenSubdiv doesn't support meshes without faces. */
return false;
}
ccgSubSurf_converter_setup_from_ccg(ss, &converter);
- topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter);
+ OpenSubdiv_TopologyRefinerSettings settings;
+ settings.level = ss->subdivLevels;
+ settings.is_adaptive = false;
+ topology_refiner =
+ openSubdiv_createTopologyRefinerFromConverter(
+ &converter, &settings);
ccgSubSurf_converter_free(&converter);
ss->osd_evaluator =
- openSubdiv_createEvaluatorDescr(topology_refiner,
- ss->subdivLevels);
+ openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner);
if (ss->osd_evaluator == NULL) {
BLI_assert(!"OpenSubdiv initialization failed, should not happen.");
return false;
@@ -516,10 +496,11 @@ static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss)
}
}
- openSubdiv_setEvaluatorCoarsePositions(ss->osd_evaluator,
- (float *)positions,
- 0,
- num_basis_verts);
+ ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator,
+ (float *)positions,
+ 0,
+ num_basis_verts);
+ ss->osd_evaluator->refine(ss->osd_evaluator);
MEM_freeN(positions);
}
@@ -540,7 +521,7 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
for (S = 0; S < face->numVerts; S++) {
int x, y, k;
CCGEdge *edge = NULL;
- bool inverse_edge;
+ bool inverse_edge = false;
for (x = 0; x < gridSize; x++) {
for (y = 0; y < gridSize; y++) {
@@ -554,11 +535,12 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index,
- face_u, face_v,
- P,
- do_normals ? dPdu : NULL,
- do_normals ? dPdv : NULL);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator, osd_face_index,
+ face_u, face_v,
+ P,
+ do_normals ? dPdu : NULL,
+ do_normals ? dPdv : NULL);
OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n",
osd_face_index, S, grid_u, grid_v, face_u, face_v, P[0], P[1], P[2]);
@@ -632,7 +614,11 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
* let's just re-evaluate for simplicity.
*/
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator,
+ osd_face_index,
+ u, v,
+ P, dPdu, dPdv);
VertDataCopy(co, P, ss);
if (do_normals) {
cross_v3_v3v3(no, dPdu, dPdv);
@@ -696,7 +682,11 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
float P[3], dPdu[3], dPdv[3];
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator,
+ osd_face_index + S,
+ u, v,
+ P, dPdu, dPdv);
OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n",
osd_face_index + S, S, u, v, P[0], P[1], P[2]);
@@ -739,7 +729,7 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
/* Evaluate edges. */
for (S = 0; S < face->numVerts; S++) {
CCGEdge *edge = FACE_getEdges(face)[S];
- int x, S0, S1;
+ int x, S0 = 0, S1 = 0;
bool flip;
for (x = 0; x < face->numVerts; ++x) {
@@ -834,7 +824,12 @@ void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
OpenSubdiv_Converter converter;
ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
/* TODO(sergey): Remove possibly previously allocated refiner. */
- ss->osd_topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter);
+ OpenSubdiv_TopologyRefinerSettings settings;
+ settings.level = ss->subdivLevels;
+ settings.is_adaptive = false;
+ ss->osd_topology_refiner =
+ openSubdiv_createTopologyRefinerFromConverter(
+ &converter, &settings);
ccgSubSurf_converter_free(&converter);
}
}
@@ -995,7 +990,7 @@ void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
void BKE_subsurf_osd_init(void)
{
- openSubdiv_init(GPU_legacy_support());
+ openSubdiv_init();
BLI_spin_init(&delete_spin);
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
index d6b15148ed1..0301582b303 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
@@ -84,6 +84,13 @@ static OpenSubdiv_SchemeType conv_dm_get_type(
return OSD_SCHEME_CATMARK;
}
+static OpenSubdiv_VtxBoundaryInterpolation
+conv_dm_get_vtx_boundary_interpolation(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+}
+
static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation(
const OpenSubdiv_Converter *converter)
{
@@ -94,6 +101,12 @@ static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation(
return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
}
+static bool conv_dm_specifies_full_topology(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return true;
+}
+
static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter)
{
ConvDMStorage *storage = converter->user_data;
@@ -306,6 +319,20 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
#endif
}
+static bool conv_dm_is_infinite_sharp_vertex(
+ const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return false;
+}
+
+static float conv_dm_get_vertex_sharpness(
+ const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return 0.0f;
+}
+
static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
{
ConvDMStorage *storage = converter->user_data;
@@ -389,12 +416,6 @@ static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter)
return storage->num_uvs;
}
-static void conv_dm_get_uvs(const OpenSubdiv_Converter *converter, float *uvs)
-{
- ConvDMStorage *storage = converter->user_data;
- memcpy(uvs, storage->uvs, sizeof(float) * 2 * storage->num_uvs);
-}
-
static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
int face,
int corner)
@@ -432,35 +453,39 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
{
ConvDMStorage *user_data;
- converter->get_scheme_type = conv_dm_get_type;
+ converter->getSchemeType = conv_dm_get_type;
- converter->get_fvar_linear_interpolation =
+ converter->getVtxBoundaryInterpolation =
+ conv_dm_get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation =
conv_dm_get_fvar_linear_interpolation;
-
- converter->get_num_faces = conv_dm_get_num_faces;
- converter->get_num_edges = conv_dm_get_num_edges;
- converter->get_num_verts = conv_dm_get_num_verts;
-
- converter->get_num_face_verts = conv_dm_get_num_face_verts;
- converter->get_face_verts = conv_dm_get_face_verts;
- converter->get_face_edges = conv_dm_get_face_edges;
-
- converter->get_edge_verts = conv_dm_get_edge_verts;
- converter->get_num_edge_faces = conv_dm_get_num_edge_faces;
- converter->get_edge_faces = conv_dm_get_edge_faces;
- converter->get_edge_sharpness = conv_dm_get_edge_sharpness;
-
- converter->get_num_vert_edges = conv_dm_get_num_vert_edges;
- converter->get_vert_edges = conv_dm_get_vert_edges;
- converter->get_num_vert_faces = conv_dm_get_num_vert_faces;
- converter->get_vert_faces = conv_dm_get_vert_faces;
-
- converter->get_num_uv_layers = conv_dm_get_num_uv_layers;
- converter->precalc_uv_layer = conv_dm_precalc_uv_layer;
- converter->finish_uv_layer = conv_dm_finish_uv_layer;
- converter->get_num_uvs = conv_dm_get_num_uvs;
- converter->get_uvs = conv_dm_get_uvs;
- converter->get_face_corner_uv_index = conv_dm_get_face_corner_uv_index;
+ converter->specifiesFullTopology = conv_dm_specifies_full_topology;
+
+ converter->getNumFaces = conv_dm_get_num_faces;
+ converter->getNumEdges = conv_dm_get_num_edges;
+ converter->getNumVertices = conv_dm_get_num_verts;
+
+ converter->getNumFaceVertices = conv_dm_get_num_face_verts;
+ converter->getFaceVertices = conv_dm_get_face_verts;
+ converter->getFaceEdges = conv_dm_get_face_edges;
+
+ converter->getEdgeVertices = conv_dm_get_edge_verts;
+ converter->getNumEdgeFaces = conv_dm_get_num_edge_faces;
+ converter->getEdgeFaces = conv_dm_get_edge_faces;
+ converter->getEdgeSharpness = conv_dm_get_edge_sharpness;
+
+ converter->getNumVertexEdges = conv_dm_get_num_vert_edges;
+ converter->getVertexEdges = conv_dm_get_vert_edges;
+ converter->getNumVertexFaces = conv_dm_get_num_vert_faces;
+ converter->getVertexFaces = conv_dm_get_vert_faces;
+ converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex;
+ converter->getVertexSharpness = conv_dm_get_vertex_sharpness;
+
+ converter->getNumUVLayers = conv_dm_get_num_uv_layers;
+ converter->precalcUVLayer = conv_dm_precalc_uv_layer;
+ converter->finishUVLayer = conv_dm_finish_uv_layer;
+ converter->getNumUVCoordinates = conv_dm_get_num_uvs;
+ converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index;
user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
user_data->ss = ss;
@@ -476,7 +501,7 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
user_data->uvs = NULL;
user_data->face_uvs = NULL;
- converter->free_user_data = conv_dm_free_user_data;
+ converter->freeUserData = conv_dm_free_user_data;
converter->user_data = user_data;
#ifdef USE_MESH_ELEMENT_MAPPING
@@ -530,6 +555,13 @@ static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(
}
}
+static OpenSubdiv_VtxBoundaryInterpolation
+conv_ccg_get_vtx_boundary_interpolation(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+}
+
static OpenSubdiv_FVarLinearInterpolation
conv_ccg_get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter)
{
@@ -540,6 +572,12 @@ conv_ccg_get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter)
return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
}
+static bool conv_ccg_specifies_full_topology(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return true;
+}
+
static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter)
{
CCGSubSurf *ss = converter->user_data;
@@ -683,6 +721,20 @@ static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
}
}
+static bool conv_ccg_is_infinite_sharp_vertex(
+ const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return false;
+}
+
+static float conv_ccg_get_vertex_sharpness(
+ const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return 0.0f;
+}
+
static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
{
return 0;
@@ -702,11 +754,6 @@ static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter))
return 0;
}
-static void conv_ccg_get_uvs(const OpenSubdiv_Converter * UNUSED(converter),
- float *UNUSED(uvs))
-{
-}
-
static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter),
int UNUSED(face),
int UNUSED(corner_))
@@ -717,45 +764,49 @@ static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(
void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
OpenSubdiv_Converter *converter)
{
- converter->get_scheme_type = conv_ccg_get_bilinear_type;
+ converter->getSchemeType = conv_ccg_get_bilinear_type;
- converter->get_fvar_linear_interpolation =
+ converter->getVtxBoundaryInterpolation =
+ conv_ccg_get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation =
conv_ccg_get_fvar_linear_interpolation;
-
- converter->get_num_faces = conv_ccg_get_num_faces;
- converter->get_num_edges = conv_ccg_get_num_edges;
- converter->get_num_verts = conv_ccg_get_num_verts;
-
- converter->get_num_face_verts = conv_ccg_get_num_face_verts;
- converter->get_face_verts = conv_ccg_get_face_verts;
- converter->get_face_edges = conv_ccg_get_face_edges;
-
- converter->get_edge_verts = conv_ccg_get_edge_verts;
- converter->get_num_edge_faces = conv_ccg_get_num_edge_faces;
- converter->get_edge_faces = conv_ccg_get_edge_faces;
- converter->get_edge_sharpness = conv_ccg_get_edge_sharpness;
-
- converter->get_num_vert_edges = conv_ccg_get_num_vert_edges;
- converter->get_vert_edges = conv_ccg_get_vert_edges;
- converter->get_num_vert_faces = conv_ccg_get_num_vert_faces;
- converter->get_vert_faces = conv_ccg_get_vert_faces;
-
- converter->get_num_uv_layers = conv_ccg_get_num_uv_layers;
- converter->precalc_uv_layer = conv_ccg_precalc_uv_layer;
- converter->finish_uv_layer = conv_ccg_finish_uv_layer;
- converter->get_num_uvs = conv_ccg_get_num_uvs;
- converter->get_uvs = conv_ccg_get_uvs;
- converter->get_face_corner_uv_index = conv_ccg_get_face_corner_uv_index;
-
- converter->free_user_data = NULL;
+ converter->specifiesFullTopology = conv_ccg_specifies_full_topology;
+
+ converter->getNumFaces = conv_ccg_get_num_faces;
+ converter->getNumEdges = conv_ccg_get_num_edges;
+ converter->getNumVertices = conv_ccg_get_num_verts;
+
+ converter->getNumFaceVertices = conv_ccg_get_num_face_verts;
+ converter->getFaceVertices = conv_ccg_get_face_verts;
+ converter->getFaceEdges = conv_ccg_get_face_edges;
+
+ converter->getEdgeVertices = conv_ccg_get_edge_verts;
+ converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces;
+ converter->getEdgeFaces = conv_ccg_get_edge_faces;
+ converter->getEdgeSharpness = conv_ccg_get_edge_sharpness;
+
+ converter->getNumVertexEdges = conv_ccg_get_num_vert_edges;
+ converter->getVertexEdges = conv_ccg_get_vert_edges;
+ converter->getNumVertexFaces = conv_ccg_get_num_vert_faces;
+ converter->getVertexFaces = conv_ccg_get_vert_faces;
+ converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex;
+ converter->getVertexSharpness = conv_ccg_get_vertex_sharpness;
+
+ converter->getNumUVLayers = conv_ccg_get_num_uv_layers;
+ converter->precalcUVLayer = conv_ccg_precalc_uv_layer;
+ converter->finishUVLayer = conv_ccg_finish_uv_layer;
+ converter->getNumUVCoordinates = conv_ccg_get_num_uvs;
+ converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index;
+
+ converter->freeUserData = NULL;
converter->user_data = ss;
}
void ccgSubSurf_converter_free(
struct OpenSubdiv_Converter *converter)
{
- if (converter->free_user_data) {
- converter->free_user_data(converter);
+ if (converter->freeUserData) {
+ converter->freeUserData(converter);
}
}
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index e099ceaea53..992771d368d 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -55,32 +55,29 @@
#include "BKE_colorband.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_tangent.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_multires.h"
#include "BKE_bvhutils.h"
#include "BKE_deform.h"
-#include "BKE_global.h" /* For debug flag, DM_update_tessface_data() func. */
-
-#ifdef WITH_GAMEENGINE
-#include "BKE_navmesh_conversion.h"
-static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
-#endif
#include "BLI_sys_types.h" /* for intptr_t support */
-#include "GPU_buffers.h"
-#include "GPU_glew.h"
-#include "GPU_shader.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#include "BKE_shrinkwrap.h"
#ifdef WITH_OPENSUBDIV
-# include "BKE_depsgraph.h"
# include "DNA_userdef_types.h"
#endif
@@ -89,17 +86,20 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#ifdef USE_MODIFIER_VALIDATE
# define ASSERT_IS_VALID_DM(dm) (BLI_assert((dm == NULL) || (DM_is_valid(dm) == true)))
+# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
#else
# define ASSERT_IS_VALID_DM(dm)
+# define ASSERT_IS_VALID_MESH(mesh)
#endif
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
-static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
+static void mesh_init_origspace(Mesh *mesh);
+
/* -------------------------------------------------------------------- */
@@ -327,7 +327,7 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getPolyDataArray = DM_get_poly_data_layer;
dm->getLoopDataArray = DM_get_loop_data_layer;
- bvhcache_init(&dm->bvhCache);
+ dm->bvhCache = NULL;
}
/**
@@ -349,7 +349,6 @@ void DM_init(
DM_init_funcs(dm);
dm->needsFree = 1;
- dm->auto_bump_scale = -1.0f;
dm->dirty = 0;
/* don't use CustomData_reset(...); because we dont want to touch customdata */
@@ -406,7 +405,6 @@ int DM_release(DerivedMesh *dm)
{
if (dm->needsFree) {
bvhcache_free(&dm->bvhCache);
- GPU_drawobject_free(dm);
CustomData_free(&dm->vertData, dm->numVertData);
CustomData_free(&dm->edgeData, dm->numEdgeData);
CustomData_free(&dm->faceData, dm->numTessFaceData);
@@ -466,39 +464,6 @@ void DM_ensure_normals(DerivedMesh *dm)
BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
}
-static void DM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, float split_angle)
-{
- dm->calcLoopNormals(dm, use_split_normals, split_angle);
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
-}
-
-/* note: until all modifiers can take MPoly's as input,
- * use this at the start of modifiers */
-void DM_ensure_tessface(DerivedMesh *dm)
-{
- const int numTessFaces = dm->getNumTessFaces(dm);
- const int numPolys = dm->getNumPolys(dm);
-
- if ((numTessFaces == 0) && (numPolys != 0)) {
- dm->recalcTessellation(dm);
-
- if (dm->getNumTessFaces(dm) != 0) {
- /* printf("info %s: polys -> ngons calculated\n", __func__); */
- }
- else {
- printf("warning %s: could not create tessfaces from %d polygons, dm->type=%u\n",
- __func__, numPolys, dm->type);
- }
- }
-
- else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
- BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX) || numTessFaces == 0);
- DM_update_tessface_data(dm);
- }
-
- dm->dirty &= ~DM_DIRTY_TESS_CDLAYERS;
-}
-
/**
* Ensure the array is large enough
*
@@ -533,195 +498,13 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
}
}
-void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num)
-{
- int i;
- for (i = 0; i < looptri_num; i++) {
- verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
- verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
- verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;
- }
-}
-
-/* Update tessface CD data from loop/poly ones. Needed when not retessellating after modstack evaluation. */
-/* NOTE: Assumes dm has valid tessellated data! */
-void DM_update_tessface_data(DerivedMesh *dm)
-{
- MFace *mf, *mface = dm->getTessFaceArray(dm);
- MPoly *mp = dm->getPolyArray(dm);
- MLoop *ml = dm->getLoopArray(dm);
-
- CustomData *fdata = dm->getTessFaceDataLayout(dm);
- CustomData *pdata = dm->getPolyDataLayout(dm);
- CustomData *ldata = dm->getLoopDataLayout(dm);
-
- const int totface = dm->getNumTessFaces(dm);
- int mf_idx;
-
- int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
- unsigned int (*loopindex)[4];
-
- /* Should never occur, but better abort than segfault! */
- if (!polyindex)
- return;
-
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
-
- if (CustomData_has_layer(fdata, CD_MTFACE) ||
- CustomData_has_layer(fdata, CD_MCOL) ||
- CustomData_has_layer(fdata, CD_PREVIEW_MCOL) ||
- CustomData_has_layer(fdata, CD_ORIGSPACE) ||
- CustomData_has_layer(fdata, CD_TESSLOOPNORMAL) ||
- CustomData_has_layer(fdata, CD_TANGENT))
- {
- loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__);
-
- for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
- const int mf_len = mf->v4 ? 4 : 3;
- unsigned int *ml_idx = loopindex[mf_idx];
- int i, not_done;
-
- /* Find out loop indices. */
- /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
- for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
- const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
- if (tf_v != -1) {
- ml_idx[tf_v] = i;
- not_done--;
- }
- }
- }
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
- * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
- * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
- */
- BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, mface, polyindex, loopindex, totface);
-
- MEM_freeN(loopindex);
- }
-
- if (G.debug & G_DEBUG)
- printf("%s: Updated tessellated customdata of dm %p\n", __func__, dm);
-
- dm->dirty &= ~DM_DIRTY_TESS_CDLAYERS;
-}
-
-void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
-{
- MFace *mf, *mface = dm->getTessFaceArray(dm);
- MPoly *mp = dm->getPolyArray(dm);
- MLoop *ml = dm->getLoopArray(dm);
-
- CustomData *fdata = dm->getTessFaceDataLayout(dm);
- CustomData *pdata = dm->getPolyDataLayout(dm);
- CustomData *ldata = dm->getLoopDataLayout(dm);
-
- const int totface = dm->getNumTessFaces(dm);
- int mf_idx;
-
- int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
- unsigned int (*loopindex)[4] = NULL;
-
- /* Should never occur, but better abort than segfault! */
- if (!polyindex)
- return;
-
- if (generate) {
- for (int j = 0; j < ldata->totlayer; j++) {
- if (ldata->layers[j].type == CD_TANGENT) {
- CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[j].name);
- CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
-
- if (!loopindex) {
- loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__);
- for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
- const int mf_len = mf->v4 ? 4 : 3;
- unsigned int *ml_idx = loopindex[mf_idx];
-
- /* Find out loop indices. */
- /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
- for (int i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
- const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
- if (tf_v != -1) {
- ml_idx[tf_v] = i;
- not_done--;
- }
- }
- }
- }
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
- * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
- * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
- */
- BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface, ldata->layers[j].name);
- }
- }
- if (loopindex)
- MEM_freeN(loopindex);
- BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
- }
-
- if (G.debug & G_DEBUG)
- printf("%s: Updated tessellated tangents of dm %p\n", __func__, dm);
-}
-
-
-void DM_update_materials(DerivedMesh *dm, Object *ob)
-{
- int i, totmat = ob->totcol + 1; /* materials start from 1, default material is 0 */
-
- if (dm->totmat != totmat) {
- dm->totmat = totmat;
- /* invalidate old materials */
- if (dm->mat)
- MEM_freeN(dm->mat);
-
- dm->mat = MEM_malloc_arrayN(totmat, sizeof(*dm->mat), "DerivedMesh.mat");
- }
-
- /* we leave last material as empty - rationale here is being able to index
- * the materials by using the mf->mat_nr directly and leaving the last
- * material as NULL in case no materials exist on mesh, so indexing will not fail */
- for (i = 0; i < totmat - 1; i++) {
- dm->mat[i] = give_current_material(ob, i + 1);
- }
- dm->mat[i] = NULL;
-}
-
-MLoopUV *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr)
-{
- MLoopUV *uv_base;
-
- BLI_assert(mat_nr < dm->totmat);
-
- if (dm->mat[mat_nr] && dm->mat[mat_nr]->texpaintslot &&
- dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname)
- {
- uv_base = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV,
- dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname);
- /* This can fail if we have changed the name in the UV layer list and have assigned the old name in the material
- * texture slot.*/
- if (!uv_base)
- uv_base = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
- }
- else {
- uv_base = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
- }
-
- return uv_base;
-}
-
void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool take_ownership)
{
/* dm might depend on me, so we need to do everything with a local copy */
Mesh tmp = *me;
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
int did_shapekeys = 0;
- int alloctype = CD_DUPLICATE;
+ eCDAllocType alloctype = CD_DUPLICATE;
if (take_ownership && dm->type == DM_TYPE_CDDM && dm->needsFree) {
bool has_any_referenced_layers =
@@ -754,6 +537,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
CustomData_copy(&dm->loopData, &tmp.ldata, mask, alloctype, totloop);
CustomData_copy(&dm->polyData, &tmp.pdata, mask, alloctype, totpoly);
tmp.cd_flag = dm->cd_flag;
+ tmp.runtime.deformed_only = dm->deformedOnly;
if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
KeyBlock *kb;
@@ -831,8 +615,9 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
* stack */
if (tmp.totvert != me->totvert && !did_shapekeys && me->key) {
printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name);
- if (tmp.key)
+ if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
id_us_min(&tmp.key->id);
+ }
tmp.key = NULL;
}
@@ -859,26 +644,18 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
}
}
-void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb)
+/** Utility function to convert an (evaluated) Mesh to a shape key block. */
+/* Just a shallow wrapper around BKE_keyblock_convert_from_mesh,
+ * that ensures both evaluated mesh and original one has same number of vertices. */
+void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
{
- int a, totvert = dm->getNumVerts(dm);
- float *fp;
- MVert *mvert;
+ const int totvert = me_deformed->totvert;
if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
return;
}
- if (kb->data) MEM_freeN(kb->data);
- kb->data = MEM_malloc_arrayN(me->key->elemsize, me->totvert, "kb->data");
- kb->totelem = totvert;
-
- fp = kb->data;
- mvert = dm->getVertDataArray(dm, CD_MVERT);
-
- for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
- copy_v3_v3(fp, mvert->co);
- }
+ BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
}
/**
@@ -900,27 +677,41 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask)
#endif
}
-void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+static void mesh_set_only_copy(Mesh *mesh, CustomDataMask mask)
+{
+ CustomData_set_only_copy(&mesh->vdata, mask);
+ CustomData_set_only_copy(&mesh->edata, mask);
+ CustomData_set_only_copy(&mesh->fdata, mask);
+ /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
+ * weight paint mode when there are modifiers applied, needs further investigation,
+ * see replies to r50969, Campbell */
+#if 0
+ CustomData_set_only_copy(&mesh->ldata, mask);
+ CustomData_set_only_copy(&mesh->pdata, mask);
+#endif
+}
+
+void DM_add_vert_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData);
}
-void DM_add_edge_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_edge_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
}
-void DM_add_tessface_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_tessface_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numTessFaceData);
}
-void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
}
-void DM_add_poly_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_poly_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
}
@@ -1109,11 +900,6 @@ void DM_interp_tessface_data(
weights, (float *)vert_weights, count, dest_index);
}
-void DM_swap_tessface_data(DerivedMesh *dm, int index, const int *corner_indices)
-{
- CustomData_swap_corners(&dm->faceData, index, corner_indices);
-}
-
void DM_interp_loop_data(
DerivedMesh *source, DerivedMesh *dest,
int *src_indices,
@@ -1146,56 +932,6 @@ DerivedMesh *mesh_create_derived(Mesh *me, float (*vertCos)[3])
return dm;
}
-DerivedMesh *mesh_create_derived_for_modifier(
- Scene *scene, Object *ob,
- ModifierData *md, int build_shapekey_layers)
-{
- Mesh *me = ob->data;
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- DerivedMesh *dm;
- KeyBlock *kb;
-
- md->scene = scene;
-
- if (!(md->mode & eModifierMode_Realtime)) {
- return NULL;
- }
-
- if (mti->isDisabled && mti->isDisabled(md, 0)) {
- return NULL;
- }
-
- if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) {
- BKE_keyblock_convert_to_mesh(kb, me);
- }
-
- if (mti->type == eModifierTypeType_OnlyDeform) {
- int numVerts;
- float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts);
-
- modwrap_deformVerts(md, ob, NULL, deformedVerts, numVerts, 0);
- dm = mesh_create_derived(me, deformedVerts);
-
- if (build_shapekey_layers)
- add_shapekey_layers(dm, me, ob);
-
- MEM_freeN(deformedVerts);
- }
- else {
- DerivedMesh *tdm = mesh_create_derived(me, NULL);
-
- if (build_shapekey_layers)
- add_shapekey_layers(tdm, me, ob);
-
- dm = modwrap_applyModifier(md, ob, tdm, 0);
- ASSERT_IS_VALID_DM(dm);
-
- if (tdm != dm) tdm->release(tdm);
- }
-
- return dm;
-}
-
static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
{
BMIter iter;
@@ -1216,7 +952,7 @@ static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
}
/* orco custom data layer */
-static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free))[3]
+static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free))[3]
{
*free = 0;
@@ -1247,386 +983,77 @@ static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *fr
return NULL;
}
-static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em, int layer)
+static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
{
- DerivedMesh *dm;
+ Mesh *mesh;
float (*orco)[3];
int free;
if (em) {
- dm = CDDM_from_editbmesh(em, false, false);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0);
}
else {
- dm = CDDM_from_mesh(me);
+ mesh = BKE_mesh_copy_for_eval(me, true);
}
- orco = get_orco_coords_dm(ob, em, layer, &free);
+ orco = get_orco_coords(ob, em, layer, &free);
if (orco) {
- CDDM_apply_vert_coords(dm, orco);
+ BKE_mesh_apply_vert_coords(mesh, orco);
if (free) MEM_freeN(orco);
}
- return dm;
+ return mesh;
}
-static void add_orco_dm(
- Object *ob, BMEditMesh *em, DerivedMesh *dm,
- DerivedMesh *orcodm, int layer)
+static void add_orco_mesh(
+ Object *ob, BMEditMesh *em, Mesh *mesh,
+ Mesh *me_orco, int layer)
{
float (*orco)[3], (*layerorco)[3];
int totvert, free;
- totvert = dm->getNumVerts(dm);
+ totvert = mesh->totvert;
- if (orcodm) {
- orco = MEM_calloc_arrayN(totvert, sizeof(float[3]), "dm orco");
+ if (me_orco) {
free = 1;
- if (orcodm->getNumVerts(orcodm) == totvert)
- orcodm->getVertCos(orcodm, orco);
- else
- dm->getVertCos(dm, orco);
- }
- else
- orco = get_orco_coords_dm(ob, em, layer, &free);
-
- if (orco) {
- if (layer == CD_ORCO)
- BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0);
-
- if (!(layerorco = DM_get_vert_data_layer(dm, layer))) {
- DM_add_vert_layer(dm, layer, CD_CALLOC, NULL);
- layerorco = DM_get_vert_data_layer(dm, layer);
- }
-
- memcpy(layerorco, orco, sizeof(float) * 3 * totvert);
- if (free) MEM_freeN(orco);
- }
-}
-
-/* weight paint colors */
-
-/* Something of a hack, at the moment deal with weightpaint
- * by tucking into colors during modifier eval, only in
- * wpaint mode. Works ok but need to make sure recalc
- * happens on enter/exit wpaint.
- */
-
-void weight_to_rgb(float r_rgb[3], const float weight)
-{
- const float blend = ((weight / 2.0f) + 0.5f);
-
- if (weight <= 0.25f) { /* blue->cyan */
- r_rgb[0] = 0.0f;
- r_rgb[1] = blend * weight * 4.0f;
- r_rgb[2] = blend;
- }
- else if (weight <= 0.50f) { /* cyan->green */
- r_rgb[0] = 0.0f;
- r_rgb[1] = blend;
- r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
- }
- else if (weight <= 0.75f) { /* green->yellow */
- r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
- r_rgb[1] = blend;
- r_rgb[2] = 0.0f;
- }
- else if (weight <= 1.0f) { /* yellow->red */
- r_rgb[0] = blend;
- r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
- r_rgb[2] = 0.0f;
- }
- else {
- /* exceptional value, unclamped or nan,
- * avoid uninitialized memory use */
- r_rgb[0] = 1.0f;
- r_rgb[1] = 0.0f;
- r_rgb[2] = 1.0f;
- }
-}
-
-/* draw_flag's for calc_weightpaint_vert_color */
-enum {
- /* only one of these should be set, keep first (for easy bit-shifting) */
- CALC_WP_GROUP_USER_ACTIVE = (1 << 1),
- CALC_WP_GROUP_USER_ALL = (1 << 2),
-
- CALC_WP_MULTIPAINT = (1 << 3),
- CALC_WP_AUTO_NORMALIZE = (1 << 4),
- CALC_WP_MIRROR_X = (1 << 5),
-};
-
-typedef struct DMWeightColorInfo {
- const ColorBand *coba;
- const char *alert_color;
-} DMWeightColorInfo;
-
-
-static int dm_drawflag_calc(const ToolSettings *ts, const Mesh *me)
-{
- return ((ts->multipaint ? CALC_WP_MULTIPAINT : 0) |
- /* CALC_WP_GROUP_USER_ACTIVE or CALC_WP_GROUP_USER_ALL */
- (1 << ts->weightuser) |
- (ts->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0) |
- ((me->editflag & ME_EDIT_MIRROR_X) ? CALC_WP_MIRROR_X : 0));
-}
-
-static void weightpaint_color(unsigned char r_col[4], DMWeightColorInfo *dm_wcinfo, const float input)
-{
- float colf[4];
-
- if (dm_wcinfo && dm_wcinfo->coba) {
- BKE_colorband_evaluate(dm_wcinfo->coba, input, colf);
- }
- else {
- weight_to_rgb(colf, input);
- }
-
- /* don't use rgb_float_to_uchar() here because
- * the resulting float doesn't need 0-1 clamp check */
- r_col[0] = (unsigned char)(colf[0] * 255.0f);
- r_col[1] = (unsigned char)(colf[1] * 255.0f);
- r_col[2] = (unsigned char)(colf[2] * 255.0f);
- r_col[3] = 255;
-}
-
-
-static void calc_weightpaint_vert_color(
- unsigned char r_col[4],
- const MDeformVert *dv,
- DMWeightColorInfo *dm_wcinfo,
- const int defbase_tot, const int defbase_act,
- const bool *defbase_sel, const int defbase_sel_tot,
- const int draw_flag)
-{
- float input = 0.0f;
-
- bool show_alert_color = false;
-
- if ((defbase_sel_tot > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
- /* Multi-Paint feature */
- input = BKE_defvert_multipaint_collective_weight(
- dv, defbase_tot, defbase_sel, defbase_sel_tot, (draw_flag & CALC_WP_AUTO_NORMALIZE) != 0);
-
- /* make it black if the selected groups have no weight on a vertex */
- if (input == 0.0f) {
- show_alert_color = true;
- }
- }
- else {
- /* default, non tricky behavior */
- input = defvert_find_weight(dv, defbase_act);
-
- if (draw_flag & CALC_WP_GROUP_USER_ACTIVE) {
- if (input == 0.0f) {
- show_alert_color = true;
- }
- }
- else if (draw_flag & CALC_WP_GROUP_USER_ALL) {
- if (input == 0.0f) {
- show_alert_color = defvert_is_weight_zero(dv, defbase_tot);
- }
- }
- }
-
- if (show_alert_color == false) {
- CLAMP(input, 0.0f, 1.0f);
- weightpaint_color(r_col, dm_wcinfo, input);
- }
- else {
- copy_v3_v3_char((char *)r_col, dm_wcinfo->alert_color);
- r_col[3] = 255;
- }
-}
-
-static DMWeightColorInfo G_dm_wcinfo;
-
-void vDM_ColorBand_store(const ColorBand *coba, const char alert_color[4])
-{
- G_dm_wcinfo.coba = coba;
- G_dm_wcinfo.alert_color = alert_color;
-}
-
-/**
- * return an array of vertex weight colors, caller must free.
- *
- * \note that we could save some memory and allocate RGB only but then we'd need to
- * re-arrange the colors when copying to the face since MCol has odd ordering,
- * so leave this as is - campbell
- */
-static void calc_weightpaint_vert_array(
- Object *ob, DerivedMesh *dm, int const draw_flag, DMWeightColorInfo *dm_wcinfo,
- unsigned char (*r_wtcol_v)[4])
-{
- BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL;
- const int numVerts = dm->getNumVerts(dm);
-
- if ((ob->actdef != 0) &&
- (CustomData_has_layer(em ? &em->bm->vdata : &dm->vertData, CD_MDEFORMVERT)))
- {
- unsigned char (*wc)[4] = r_wtcol_v;
- unsigned int i;
-
- /* variables for multipaint */
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
- const int defbase_act = ob->actdef - 1;
-
- int defbase_sel_tot = 0;
- bool *defbase_sel = NULL;
-
- if (draw_flag & CALC_WP_MULTIPAINT) {
- defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_sel_tot);
-
- if (defbase_sel_tot > 1 && (draw_flag & CALC_WP_MIRROR_X)) {
- BKE_object_defgroup_mirror_selection(ob, defbase_tot, defbase_sel, defbase_sel, &defbase_sel_tot);
- }
- }
-
- /* editmesh won't have deform verts unless modifiers require it,
- * avoid having to create an array of deform-verts only for drawing
- * by reading from the bmesh directly. */
- if (em) {
- BMIter iter;
- BMVert *eve;
- const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
- BLI_assert(cd_dvert_offset != -1);
-
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- calc_weightpaint_vert_color(
- (unsigned char *)wc, dv, dm_wcinfo,
- defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
- wc++;
- }
- }
- else {
- const MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
- for (i = numVerts; i != 0; i--, wc++, dv++) {
- calc_weightpaint_vert_color(
- (unsigned char *)wc, dv, dm_wcinfo,
- defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
- }
- }
-
- if (defbase_sel) {
- MEM_freeN(defbase_sel);
- }
- }
- else {
- unsigned char col[4];
- if ((ob->actdef == 0) && !BLI_listbase_is_empty(&ob->defbase)) {
- /* color-code for missing data (full brightness isn't easy on the eye). */
- ARRAY_SET_ITEMS(col, 0xa0, 0, 0xa0, 0xff);
- }
- else if (draw_flag & (CALC_WP_GROUP_USER_ACTIVE | CALC_WP_GROUP_USER_ALL)) {
- copy_v3_v3_char((char *)col, dm_wcinfo->alert_color);
- col[3] = 255;
+ if (me_orco->totvert == totvert) {
+ orco = BKE_mesh_vertexCos_get(me_orco, NULL);
}
else {
- weightpaint_color(col, dm_wcinfo, 0.0f);
- }
- copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
- }
-}
-
-/** return an array of vertex weight colors from given weights, caller must free.
- *
- * \note that we could save some memory and allocate RGB only but then we'd need to
- * re-arrange the colors when copying to the face since MCol has odd ordering,
- * so leave this as is - campbell
- */
-static void calc_colors_from_weights_array(
- const int num, const float *weights,
- unsigned char (*r_wtcol_v)[4])
-{
- unsigned char (*wc)[4] = r_wtcol_v;
- int i;
-
- for (i = 0; i < num; i++, wc++, weights++) {
- weightpaint_color((unsigned char *)wc, NULL, *weights);
- }
-}
-
-void DM_update_weight_mcol(
- Object *ob, DerivedMesh *dm, int const draw_flag,
- float *weights, int num, const int *indices)
-{
- BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL;
- unsigned char (*wtcol_v)[4];
- int numVerts = dm->getNumVerts(dm);
- int i;
-
- if (em) {
- BKE_editmesh_color_ensure(em, BM_VERT);
- wtcol_v = em->derivedVertColor;
- }
- else {
- wtcol_v = MEM_malloc_arrayN(numVerts, sizeof(*wtcol_v), __func__);
- }
-
- /* Weights are given by caller. */
- if (weights) {
- float *w = weights;
- /* If indices is not NULL, it means we do not have weights for all vertices,
- * so we must create them (and set them to zero)... */
- if (indices) {
- w = MEM_calloc_arrayN(numVerts, sizeof(float), "Temp weight array DM_update_weight_mcol");
- i = num;
- while (i--)
- w[indices[i]] = weights[i];
+ orco = BKE_mesh_vertexCos_get(mesh, NULL);
}
-
- /* Convert float weights to colors. */
- calc_colors_from_weights_array(numVerts, w, wtcol_v);
-
- if (indices)
- MEM_freeN(w);
}
else {
- /* No weights given, take them from active vgroup(s). */
- calc_weightpaint_vert_array(ob, dm, draw_flag, &G_dm_wcinfo, wtcol_v);
+ /* TODO(sybren): totvert should potentially change here, as ob->data
+ * or em may have a different number of vertices than dm. */
+ orco = get_orco_coords(ob, em, layer, &free);
}
- if (dm->type == DM_TYPE_EDITBMESH) {
- /* editmesh draw function checks specifically for this */
- }
- else {
- const int dm_totpoly = dm->getNumPolys(dm);
- const int dm_totloop = dm->getNumLoops(dm);
- unsigned char(*wtcol_l)[4] = CustomData_get_layer(dm->getLoopDataLayout(dm), CD_PREVIEW_MLOOPCOL);
- MLoop *mloop = dm->getLoopArray(dm), *ml;
- MPoly *mp = dm->getPolyArray(dm);
- int l_index;
- int j;
-
- /* now add to loops, so the data can be passed through the modifier stack
- * If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
- if (!wtcol_l) {
- wtcol_l = MEM_malloc_arrayN(dm_totloop, sizeof(*wtcol_l), __func__);
- CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, dm_totloop);
+ if (orco) {
+ if (layer == CD_ORCO) {
+ BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0);
}
- l_index = 0;
- for (i = 0; i < dm_totpoly; i++, mp++) {
- ml = mloop + mp->loopstart;
+ if (!(layerorco = CustomData_get_layer(&mesh->vdata, layer))) {
+ CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, NULL, mesh->totvert);
+ BKE_mesh_update_customdata_pointers(mesh, false);
- for (j = 0; j < mp->totloop; j++, ml++, l_index++) {
- copy_v4_v4_uchar(&wtcol_l[l_index][0],
- &wtcol_v[ml->v][0]);
- }
+ layerorco = CustomData_get_layer(&mesh->vdata, layer);
}
- MEM_freeN(wtcol_v);
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ memcpy(layerorco, orco, sizeof(float) * 3 * totvert);
+ if (free) MEM_freeN(orco);
}
}
-static void DM_update_statvis_color(const Scene *scene, Object *ob, DerivedMesh *dm)
+static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
-
- BKE_editmesh_statvis_calc(em, dm, &scene->toolsettings->statvis);
+ Mesh *me = ob->data;
+ BKE_mesh_runtime_ensure_edit_data(me);
+ BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
}
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid)
@@ -1685,20 +1112,20 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape
}
}
-static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
+static void add_shapekey_layers(Mesh *me_dst, Mesh *me_src, Object *UNUSED(ob))
{
KeyBlock *kb;
- Key *key = me->key;
+ Key *key = me_src->key;
int i;
- if (!me->key)
+ if (!me_src->key)
return;
/* ensure we can use mesh vertex count for derived mesh custom data */
- if (me->totvert != dm->getNumVerts(dm)) {
+ if (me_src->totvert != me_dst->totvert) {
fprintf(stderr,
- "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n",
- __func__, me->id.name + 2, me->totvert, dm->getNumVerts(dm));
+ "%s: vertex size mismatch (mesh/eval) '%s' (%d != %d)\n",
+ __func__, me_src->id.name + 2, me_src->totvert, me_dst->totvert);
return;
}
@@ -1706,131 +1133,79 @@ static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
int ci;
float *array;
- if (me->totvert != kb->totelem) {
+ if (me_src->totvert != kb->totelem) {
fprintf(stderr,
"%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n",
- __func__, me->id.name + 2, me->totvert, kb->name, kb->totelem);
- array = MEM_calloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__);
+ __func__, me_src->id.name + 2, me_src->totvert, kb->name, kb->totelem);
+ array = MEM_calloc_arrayN((size_t)me_src->totvert, sizeof(float[3]), __func__);
}
else {
- array = MEM_malloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__);
- memcpy(array, kb->data, (size_t)me->totvert * 3 * sizeof(float));
+ array = MEM_malloc_arrayN((size_t)me_src->totvert, sizeof(float[3]), __func__);
+ memcpy(array, kb->data, (size_t)me_src->totvert * sizeof(float[3]));
}
- CustomData_add_layer_named(&dm->vertData, CD_SHAPEKEY, CD_ASSIGN, array, dm->numVertData, kb->name);
- ci = CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, i);
+ CustomData_add_layer_named(&me_dst->vdata, CD_SHAPEKEY, CD_ASSIGN, array, me_dst->totvert, kb->name);
+ ci = CustomData_get_layer_index_n(&me_dst->vdata, CD_SHAPEKEY, i);
- dm->vertData.layers[ci].uid = kb->uid;
+ me_dst->vdata.layers[ci].uid = kb->uid;
}
}
-/**
- * Called after calculating all modifiers.
- *
- * \note tessfaces should already be calculated.
- */
-static void dm_ensure_display_normals(DerivedMesh *dm)
-{
- /* Note: dm *may* have a poly CD_NORMAL layer (generated by a modifier needing poly normals e.g.).
- * We do not use it here, though. And it should be tagged as temp!
- */
- /* BLI_assert((CustomData_has_layer(&dm->polyData, CD_NORMAL) == false)); */
-
- if ((dm->type == DM_TYPE_CDDM) &&
- ((dm->dirty & DM_DIRTY_NORMALS) || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false))
- {
- /* if normals are dirty we want to calculate vertex normals too */
- CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
- }
-}
-
-/**
- * new value for useDeform -1 (hack for the gameengine):
- *
- * - apply only the modifier stack of the object, skipping the virtual modifiers,
- * - don't apply the key
- * - apply deform modifiers and input vertexco
- */
static void mesh_calc_modifiers(
- Scene *scene, Object *ob, float (*inputVertexCos)[3],
- const bool useRenderParams, int useDeform,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (*inputVertexCos)[3],
+ int useDeform,
const bool need_mapping, CustomDataMask dataMask,
const int index, const bool useCache, const bool build_shapekey_layers,
- const bool allow_gpu,
/* return args */
- DerivedMesh **r_deform, DerivedMesh **r_final)
+ Mesh **r_deform, Mesh **r_final)
{
- Mesh *me = ob->data;
ModifierData *firstmd, *md, *previewmd = NULL;
CDMaskLink *datamasks, *curr;
/* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
CustomDataMask mask, nextmask, previewmask = 0, append_mask = CD_MASK_ORIGINDEX;
float (*deformedVerts)[3] = NULL;
- DerivedMesh *dm = NULL, *orcodm, *clothorcodm, *finaldm;
- int numVerts = me->totvert;
+ int numVerts = ((Mesh *)ob->data)->totvert;
+ const bool useRenderParams = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = useRenderParams ? eModifierMode_Render : eModifierMode_Realtime;
bool isPrevDeform = false;
- const bool skipVirtualArmature = (useDeform < 0);
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
const bool has_multires = (mmd && mmd->sculptlvl != 0);
bool multires_applied = false;
const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !useRenderParams;
const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !useRenderParams;
- const int draw_flag = dm_drawflag_calc(scene->toolsettings, me);
/* Generic preview only in object mode! */
const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT);
-#if 0 /* XXX Will re-enable this when we have global mod stack options. */
- const bool do_final_wmcol = (scene->toolsettings->weights_preview == WP_WPREVIEW_FINAL) && do_wmcol;
-#endif
- const bool do_final_wmcol = false;
- const bool do_init_wmcol = ((dataMask & CD_MASK_PREVIEW_MLOOPCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT) && !do_final_wmcol);
- /* XXX Same as above... For now, only weights preview in WPaint mode. */
- const bool do_mod_wmcol = do_init_wmcol;
-
- const bool do_loop_normals = (me->flag & ME_AUTOSMOOTH) != 0;
- const float loop_normals_split_angle = me->smoothresh;
+ const bool do_loop_normals = (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) != 0;
VirtualModifierData virtualModifierData;
ModifierApplyFlag app_flags = useRenderParams ? MOD_APPLY_RENDER : 0;
ModifierApplyFlag deform_app_flags = app_flags;
+ BLI_assert((((Mesh *)ob->data)->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
if (useCache)
app_flags |= MOD_APPLY_USECACHE;
- if (allow_gpu)
- app_flags |= MOD_APPLY_ALLOW_GPU;
if (useDeform)
deform_app_flags |= MOD_APPLY_USECACHE;
- if (!skipVirtualArmature) {
- firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- }
- else {
- /* game engine exception */
- firstmd = ob->modifiers.first;
- if (firstmd && firstmd->type == eModifierType_Armature)
- firstmd = firstmd->next;
- }
+ /* TODO(sybren): do we really need three context objects? Or do we modify
+ * them on the fly to change the flags where needed? */
+ const ModifierEvalContext mectx_deform = {depsgraph, ob, deform_app_flags};
+ const ModifierEvalContext mectx_apply = {depsgraph, ob, app_flags};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO};
- md = firstmd;
+ md = firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
modifiers_clearErrors(ob);
- if (do_mod_wmcol || do_mod_mcol) {
+ if (do_mod_mcol) {
/* Find the last active modifier generating a preview, or NULL if none. */
/* XXX Currently, DPaint modifier just ignores this.
* Needs a stupid hack...
* The whole "modifier preview" thing has to be (re?)designed, anyway! */
previewmd = modifiers_getLastPreview(scene, md, required_mode);
-
- /* even if the modifier doesn't need the data, to make a preview it may */
- if (previewmd) {
- if (do_mod_wmcol) {
- previewmask = CD_MASK_MDEFORMVERT;
- }
- }
}
datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, previewmask);
@@ -1849,8 +1224,6 @@ static void mesh_calc_modifiers(
for (; md; md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode)) {
continue;
}
@@ -1861,9 +1234,9 @@ static void mesh_calc_modifiers(
if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) {
if (!deformedVerts)
- deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts);
- modwrap_deformVerts(md, ob, NULL, deformedVerts, numVerts, deform_app_flags);
+ modwrap_deformVerts(md, &mectx_deform, NULL, deformedVerts, numVerts);
}
else {
break;
@@ -1879,13 +1252,16 @@ static void mesh_calc_modifiers(
* coordinates (vpaint, etc.)
*/
if (r_deform) {
- *r_deform = CDDM_from_mesh(me);
+ *r_deform = BKE_mesh_copy_for_eval(ob->data, true);
- if (build_shapekey_layers)
- add_shapekey_layers(dm, me, ob);
+ /* XXX: Is build_shapekey_layers ever even true? This should have crashed long ago... */
+ BLI_assert(!build_shapekey_layers);
+ if (build_shapekey_layers) {
+ add_shapekey_layers(*r_deform, ob->data, ob);
+ }
if (deformedVerts) {
- CDDM_apply_vert_coords(*r_deform, deformedVerts);
+ BKE_mesh_apply_vert_coords(*r_deform, deformedVerts);
}
}
}
@@ -1894,22 +1270,20 @@ static void mesh_calc_modifiers(
if (inputVertexCos)
deformedVerts = inputVertexCos;
else
- deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts);
}
/* Now apply all remaining modifiers. If useDeform is off then skip
* OnlyDeform ones.
*/
- dm = NULL;
- orcodm = NULL;
- clothorcodm = NULL;
+ Mesh *me = NULL;
+ Mesh *me_orco = NULL;
+ Mesh *me_orco_cloth = NULL;
for (; md; md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode)) {
continue;
}
@@ -1918,7 +1292,7 @@ static void mesh_calc_modifiers(
continue;
}
- if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+ if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && me) {
modifier_setError(md, "Modifier requires original data, bad stack position");
continue;
}
@@ -1969,29 +1343,27 @@ static void mesh_calc_modifiers(
else
mask = 0;
- if (dm && (mask & CD_MASK_ORCO))
- add_orco_dm(ob, NULL, dm, orcodm, CD_ORCO);
+ if (me && (mask & CD_MASK_ORCO)) {
+ add_orco_mesh(ob, NULL, me, me_orco, CD_ORCO);
+ }
/* How to apply modifier depends on (a) what we already have as
- * a result of previous modifiers (could be a DerivedMesh or just
+ * a result of previous modifiers (could be a Mesh or just
* deformed vertices) and (b) what type the modifier is.
*/
if (mti->type == eModifierTypeType_OnlyDeform) {
/* No existing verts to deform, need to build them. */
if (!deformedVerts) {
- if (dm) {
- /* Deforming a derived mesh, read the vertex locations
+ if (me) {
+ /* Deforming a mesh, read the vertex locations
* out of the mesh and deform them. Once done with this
* run of deformers verts will be written back.
*/
- numVerts = dm->getNumVerts(dm);
- deformedVerts =
- MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv");
- dm->getVertCos(dm, deformedVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
}
else {
- deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts);
}
}
@@ -1999,46 +1371,38 @@ static void mesh_calc_modifiers(
* to avoid giving bogus normals to the next modifier see: [#23673] */
if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
/* XXX, this covers bug #23673, but we may need normal calc for other types */
- if (dm && dm->type == DM_TYPE_CDDM) {
- CDDM_apply_vert_coords(dm, deformedVerts);
+ if (me) {
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
}
- modwrap_deformVerts(md, ob, dm, deformedVerts, numVerts, deform_app_flags);
+ modwrap_deformVerts(md, &mectx_deform, me, deformedVerts, numVerts);
}
else {
- DerivedMesh *ndm;
-
/* determine which data layers are needed by following modifiers */
if (curr->next)
nextmask = curr->next->mask;
else
nextmask = dataMask;
- /* apply vertex coordinates or build a DerivedMesh as necessary */
- if (dm) {
+ /* apply vertex coordinates or build a Mesh as necessary */
+ if (me) {
if (deformedVerts) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
-
- CDDM_apply_vert_coords(dm, deformedVerts);
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
}
else {
- dm = CDDM_from_mesh(me);
- ASSERT_IS_VALID_DM(dm);
+ me = BKE_mesh_copy_for_eval(ob->data, true);
+ ASSERT_IS_VALID_MESH(me);
- if (build_shapekey_layers)
- add_shapekey_layers(dm, me, ob);
+ if (build_shapekey_layers) {
+ add_shapekey_layers(me, ob->data, ob);
+ }
if (deformedVerts) {
- CDDM_apply_vert_coords(dm, deformedVerts);
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
- if (do_init_wmcol)
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
-
/* Constructive modifiers need to have an origindex
* otherwise they wont have anywhere to copy the data from.
*
@@ -2048,91 +1412,101 @@ static void mesh_calc_modifiers(
*/
if (need_mapping || (nextmask & CD_MASK_ORIGINDEX)) {
/* calc */
- DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+ CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totvert);
+ CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totedge);
+ CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totpoly);
/* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */
- range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
- range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
- range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
+ range_vn_i(CustomData_get_layer(&me->vdata, CD_ORIGINDEX), me->totvert, 0);
+ range_vn_i(CustomData_get_layer(&me->edata, CD_ORIGINDEX), me->totedge, 0);
+ range_vn_i(CustomData_get_layer(&me->pdata, CD_ORIGINDEX), me->totpoly, 0);
}
}
- /* set the DerivedMesh to only copy needed data */
+ /* set the Mesh to only copy needed data */
mask = curr->mask;
/* needMapping check here fixes bug [#28112], otherwise it's
* possible that it won't be copied */
mask |= append_mask;
- DM_set_only_copy(dm, mask | (need_mapping ? CD_MASK_ORIGINDEX : 0));
+ mesh_set_only_copy(me, mask | (need_mapping ? CD_MASK_ORIGINDEX : 0));
/* add cloth rest shape key if needed */
if (mask & CD_MASK_CLOTH_ORCO)
- add_orco_dm(ob, NULL, dm, clothorcodm, CD_CLOTH_ORCO);
+ add_orco_mesh(ob, NULL, me, me_orco, CD_CLOTH_ORCO);
/* add an origspace layer if needed */
if ((curr->mask) & CD_MASK_ORIGSPACE_MLOOP) {
- if (!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) {
- DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL);
- DM_init_origspace(dm);
+ if (!CustomData_has_layer(&me->ldata, CD_ORIGSPACE_MLOOP)) {
+ CustomData_add_layer(&me->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, me->totloop);
+ mesh_init_origspace(me);
}
}
- ndm = modwrap_applyModifier(md, ob, dm, app_flags);
- ASSERT_IS_VALID_DM(ndm);
-
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (dm && dm != ndm) dm->release(dm);
+ Mesh *me_next = modwrap_applyModifier(md, &mectx_apply, me);
+ ASSERT_IS_VALID_MESH(me_next);
- dm = ndm;
+ if (me_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (me && me != me_next) {
+ BLI_assert(me != ob->data);
+ BKE_id_free(NULL, me);
+ }
+ me = me_next;
if (deformedVerts) {
- if (deformedVerts != inputVertexCos)
+ if (deformedVerts != inputVertexCos) {
MEM_freeN(deformedVerts);
-
+ }
deformedVerts = NULL;
}
}
- /* create an orco derivedmesh in parallel */
+ /* create an orco mesh in parallel */
if (nextmask & CD_MASK_ORCO) {
- if (!orcodm)
- orcodm = create_orco_dm(ob, me, NULL, CD_ORCO);
+ if (!me_orco) {
+ me_orco = create_orco_mesh(ob, ob->data, NULL, CD_ORCO);
+ }
nextmask &= ~CD_MASK_ORCO;
- DM_set_only_copy(orcodm, nextmask | CD_MASK_ORIGINDEX |
+ mesh_set_only_copy(me_orco, nextmask | CD_MASK_ORIGINDEX |
(mti->requiredDataMask ?
mti->requiredDataMask(ob, md) : 0));
- ndm = modwrap_applyModifier(md, ob, orcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO);
- ASSERT_IS_VALID_DM(ndm);
+ me_next = modwrap_applyModifier(md, &mectx_orco, me_orco);
+ ASSERT_IS_VALID_MESH(me_next);
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (orcodm && orcodm != ndm) orcodm->release(orcodm);
- orcodm = ndm;
+ if (me_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (me_orco && me_orco != me_next) {
+ BLI_assert(me_orco != ob->data);
+ BKE_id_free(NULL, me_orco);
+ }
+
+ me_orco = me_next;
}
}
- /* create cloth orco derivedmesh in parallel */
+ /* create cloth orco mesh in parallel */
if (nextmask & CD_MASK_CLOTH_ORCO) {
- if (!clothorcodm)
- clothorcodm = create_orco_dm(ob, me, NULL, CD_CLOTH_ORCO);
+ if (!me_orco_cloth) {
+ me_orco_cloth = create_orco_mesh(ob, ob->data, NULL, CD_CLOTH_ORCO);
+ }
nextmask &= ~CD_MASK_CLOTH_ORCO;
- DM_set_only_copy(clothorcodm, nextmask | CD_MASK_ORIGINDEX);
+ mesh_set_only_copy(me_orco_cloth, nextmask | CD_MASK_ORIGINDEX);
- ndm = modwrap_applyModifier(md, ob, clothorcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO);
- ASSERT_IS_VALID_DM(ndm);
+ me_next = modwrap_applyModifier(md, &mectx_orco, me_orco_cloth);
+ ASSERT_IS_VALID_DM(me_next);
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (clothorcodm && clothorcodm != ndm) {
- clothorcodm->release(clothorcodm);
+ if (me_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (me_orco_cloth && me_orco_cloth != me_next) {
+ BLI_assert(me_orco != ob->data);
+ BKE_id_free(NULL, me_orco_cloth);
}
- clothorcodm = ndm;
+
+ me_orco_cloth = me_next;
}
}
@@ -2140,13 +1514,8 @@ static void mesh_calc_modifiers(
/* XXX Temp and hackish solution! */
if (md->type == eModifierType_DynamicPaint)
append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
- /* In case of active preview modifier, make sure preview mask remains for following modifiers. */
- else if ((md == previewmd) && (do_mod_wmcol)) {
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
- append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
- }
- dm->deformedOnly = false;
+ me->runtime.deformed_only = false;
}
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
@@ -2163,65 +1532,47 @@ static void mesh_calc_modifiers(
for (md = firstmd; md; md = md->next)
modifier_freeTemporaryData(md);
- /* Yay, we are done. If we have a DerivedMesh and deformed vertices
- * need to apply these back onto the DerivedMesh. If we have no
- * DerivedMesh then we need to build one.
+ /* Yay, we are done. If we have a Mesh and deformed vertices
+ * need to apply these back onto the Mesh. If we have no
+ * Mesh then we need to build one.
*/
- if (dm && deformedVerts) {
- finaldm = CDDM_copy(dm);
-
- dm->release(dm);
-
- CDDM_apply_vert_coords(finaldm, deformedVerts);
-
-#if 0 /* For later nice mod preview! */
- /* In case we need modified weights in CD_PREVIEW_MCOL, we have to re-compute it. */
- if (do_final_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
-#endif
- }
- else if (dm) {
- finaldm = dm;
+ if (me) {
+ *r_final = me;
-#if 0 /* For later nice mod preview! */
- /* In case we need modified weights in CD_PREVIEW_MCOL, we have to re-compute it. */
- if (do_final_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
-#endif
+ if (deformedVerts) {
+ BKE_mesh_apply_vert_coords(*r_final, deformedVerts);
+ }
}
else {
- finaldm = CDDM_from_mesh(me);
+ *r_final = BKE_mesh_copy_for_eval(ob->data, true);
if (build_shapekey_layers) {
- add_shapekey_layers(finaldm, me, ob);
+ add_shapekey_layers(*r_final, ob->data, ob);
}
if (deformedVerts) {
- CDDM_apply_vert_coords(finaldm, deformedVerts);
+ BKE_mesh_apply_vert_coords(*r_final, deformedVerts);
}
-
- /* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
}
/* add an orco layer if needed */
if (dataMask & CD_MASK_ORCO) {
- add_orco_dm(ob, NULL, finaldm, orcodm, CD_ORCO);
+ add_orco_mesh(ob, NULL, *r_final, me_orco, CD_ORCO);
if (r_deform && *r_deform)
- add_orco_dm(ob, NULL, *r_deform, NULL, CD_ORCO);
+ add_orco_mesh(ob, NULL, *r_deform, NULL, CD_ORCO);
}
if (do_loop_normals) {
/* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */
- DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle);
+ BKE_mesh_calc_normals_split(*r_final);
+ BKE_mesh_tessface_clear(*r_final);
}
if (sculpt_dyntopo == false) {
/* watch this! after 2.75a we move to from tessface to looptri (by default) */
if (dataMask & CD_MASK_MFACE) {
- DM_ensure_tessface(finaldm);
+ BKE_mesh_tessface_ensure(*r_final);
}
/* without this, drawing ngon tri's faces will show ugly tessellated face
@@ -2234,36 +1585,22 @@ static void mesh_calc_modifiers(
* If using loop normals, poly nors have already been computed.
*/
if (!do_loop_normals) {
- dm_ensure_display_normals(finaldm);
+ BKE_mesh_ensure_normals_for_display(*r_final);
}
}
/* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them,
* as they are used by display code when available (i.e. even if autosmooth is disabled). */
- if (!do_loop_normals && CustomData_has_layer(&finaldm->loopData, CD_NORMAL)) {
- CustomData_free_layers(&finaldm->loopData, CD_NORMAL, finaldm->numLoopData);
+ if (!do_loop_normals && CustomData_has_layer(&(*r_final)->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_final)->ldata, CD_NORMAL, (*r_final)->totloop);
}
-#ifdef WITH_GAMEENGINE
- /* NavMesh - this is a hack but saves having a NavMesh modifier */
- if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) {
- DerivedMesh *tdm;
- tdm = navmesh_dm_createNavMeshForVisualization(finaldm);
- if (finaldm != tdm) {
- finaldm->release(finaldm);
- finaldm = tdm;
- }
-
- DM_ensure_tessface(finaldm);
+ if (me_orco) {
+ BKE_id_free(NULL, me_orco);
+ }
+ if (me_orco_cloth) {
+ BKE_id_free(NULL, me_orco_cloth);
}
-#endif /* WITH_GAMEENGINE */
-
- *r_final = finaldm;
-
- if (orcodm)
- orcodm->release(orcodm);
- if (clothorcodm)
- clothorcodm->release(clothorcodm);
if (deformedVerts && deformedVerts != inputVertexCos)
MEM_freeN(deformedVerts);
@@ -2271,6 +1608,30 @@ static void mesh_calc_modifiers(
BLI_linklist_free((LinkNode *)datamasks, NULL);
}
+static void mesh_calc_modifiers_dm(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (*inputVertexCos)[3],
+ int useDeform,
+ const bool need_mapping, CustomDataMask dataMask,
+ const int index, const bool useCache, const bool build_shapekey_layers,
+ /* return args */
+ DerivedMesh **r_deformdm, DerivedMesh **r_finaldm)
+{
+ Mesh *deform_mesh = NULL, *final_mesh = NULL;
+
+ mesh_calc_modifiers(
+ depsgraph, scene, ob, inputVertexCos, useDeform,
+ need_mapping, dataMask, index, useCache, build_shapekey_layers,
+ (r_deformdm ? &deform_mesh : NULL), &final_mesh);
+
+ if (deform_mesh) {
+ *r_deformdm = CDDM_from_mesh_ex(deform_mesh, CD_DUPLICATE, CD_MASK_MESH);
+ BKE_id_free(NULL, deform_mesh);
+ }
+
+ *r_finaldm = CDDM_from_mesh_ex(final_mesh, CD_DUPLICATE, CD_MASK_MESH);
+ BKE_id_free(NULL, final_mesh);
+}
+
float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
{
BMIter iter;
@@ -2289,7 +1650,7 @@ float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
return cos;
}
-bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
+bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev_mesh)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
@@ -2298,7 +1659,7 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *
return false;
}
- if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+ if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) {
modifier_setError(md, "Modifier requires original data, bad stack position");
return false;
}
@@ -2307,68 +1668,56 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *
}
static void editbmesh_calc_modifiers(
- Scene *scene, Object *ob, BMEditMesh *em,
- CustomDataMask dataMask,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ BMEditMesh *em, CustomDataMask dataMask,
/* return args */
- DerivedMesh **r_cage, DerivedMesh **r_final)
+ Mesh **r_cage, Mesh **r_final)
{
- ModifierData *md, *previewmd = NULL;
+ ModifierData *md;
float (*deformedVerts)[3] = NULL;
- CustomDataMask mask = 0, previewmask = 0, append_mask = 0;
- DerivedMesh *dm = NULL, *orcodm = NULL;
+ CustomDataMask mask = 0, append_mask = 0;
int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
CDMaskLink *datamasks, *curr;
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- int draw_flag = dm_drawflag_calc(scene->toolsettings, ob->data);
-
- // const bool do_mod_mcol = true; // (ob->mode == OB_MODE_OBJECT);
-#if 0 /* XXX Will re-enable this when we have global mod stack options. */
- const bool do_final_wmcol = (scene->toolsettings->weights_preview == WP_WPREVIEW_FINAL) && do_wmcol;
-#endif
- const bool do_final_wmcol = false;
- const bool do_init_wmcol = ((((Mesh *)ob->data)->drawflag & ME_DRAWEIGHT) && !do_final_wmcol);
-
- const bool do_init_statvis = ((((Mesh *)ob->data)->drawflag & ME_DRAW_STATVIS) && !do_init_wmcol);
- const bool do_mod_wmcol = do_init_wmcol;
+ const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */
VirtualModifierData virtualModifierData;
+ /* TODO(sybren): do we really need multiple objects, or shall we change the flags where needed? */
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO};
+ const ModifierEvalContext mectx_cache = {depsgraph, ob, MOD_APPLY_USECACHE};
+
const bool do_loop_normals = (((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH) != 0;
- const float loop_normals_split_angle = ((Mesh *)(ob->data))->smoothresh;
modifiers_clearErrors(ob);
if (r_cage && cageIndex == -1) {
- *r_cage = getEditDerivedBMesh(em, ob, dataMask, NULL);
+ *r_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, dataMask, NULL);
}
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* copied from mesh_calc_modifiers */
- if (do_mod_wmcol) {
- previewmd = modifiers_getLastPreview(scene, md, required_mode);
- /* even if the modifier doesn't need the data, to make a preview it may */
- if (previewmd) {
- previewmask = CD_MASK_MDEFORMVERT;
- }
- }
-
- datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, previewmask);
+ datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, NULL, 0);
curr = datamasks;
+
+ Mesh *me = NULL;
+ Mesh *me_orco = NULL;
+
for (i = 0; md; i++, md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
- if (!editbmesh_modifier_is_enabled(scene, md, dm)) {
+ if (!editbmesh_modifier_is_enabled(scene, md, me != NULL)) {
continue;
}
/* add an orco layer if needed by this modifier */
- if (dm && mti->requiredDataMask) {
+ if (me && mti->requiredDataMask) {
mask = mti->requiredDataMask(ob, md);
- if (mask & CD_MASK_ORCO)
- add_orco_dm(ob, em, dm, orcodm, CD_ORCO);
+ if (mask & CD_MASK_ORCO) {
+ add_orco_mesh(ob, em, me, me_orco, CD_ORCO);
+ }
}
/* How to apply modifier depends on (a) what we already have as
@@ -2379,15 +1728,12 @@ static void editbmesh_calc_modifiers(
if (mti->type == eModifierTypeType_OnlyDeform) {
/* No existing verts to deform, need to build them. */
if (!deformedVerts) {
- if (dm) {
+ if (me) {
/* Deforming a derived mesh, read the vertex locations
* out of the mesh and deform them. Once done with this
* run of deformers verts will be written back.
*/
- numVerts = dm->getNumVerts(dm);
- deformedVerts =
- MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv");
- dm->getVertCos(dm, deformedVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
}
else {
deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
@@ -2395,64 +1741,58 @@ static void editbmesh_calc_modifiers(
}
if (mti->deformVertsEM)
- modwrap_deformVertsEM(md, ob, em, dm, deformedVerts, numVerts);
+ modwrap_deformVertsEM(md, &mectx, em, me, deformedVerts, numVerts);
else
- modwrap_deformVerts(md, ob, dm, deformedVerts, numVerts, 0);
+ modwrap_deformVerts(md, &mectx, me, deformedVerts, numVerts);
}
else {
- DerivedMesh *ndm;
+ Mesh *me_next;
/* apply vertex coordinates or build a DerivedMesh as necessary */
- if (dm) {
+ if (me) {
if (deformedVerts) {
- DerivedMesh *tdm = CDDM_copy(dm);
- if (!(r_cage && dm == *r_cage)) {
- dm->release(dm);
- }
- dm = tdm;
+ Mesh *me_temp = BKE_mesh_copy_for_eval(me, false);
- CDDM_apply_vert_coords(dm, deformedVerts);
+ if (!(r_cage && me == *r_cage)) {
+ BKE_id_free(NULL, me);
+ }
+ me = me_temp;
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
- else if (r_cage && dm == *r_cage) {
- /* dm may be changed by this modifier, so we need to copy it */
- dm = CDDM_copy(dm);
+ else if (r_cage && me == *r_cage) {
+ /* 'me' may be changed by this modifier, so we need to copy it. */
+ me = BKE_mesh_copy_for_eval(me, false);
}
}
else {
- dm = CDDM_from_editbmesh(em, false, false);
- ASSERT_IS_VALID_DM(dm);
+ me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0);
+ ASSERT_IS_VALID_MESH(me);
if (deformedVerts) {
- CDDM_apply_vert_coords(dm, deformedVerts);
- }
-
- if (do_init_wmcol) {
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
}
/* create an orco derivedmesh in parallel */
mask = curr->mask;
if (mask & CD_MASK_ORCO) {
- if (!orcodm)
- orcodm = create_orco_dm(ob, ob->data, em, CD_ORCO);
+ if (!me_orco) {
+ me_orco = create_orco_mesh(ob, ob->data, em, CD_ORCO);
+ }
mask &= ~CD_MASK_ORCO;
- DM_set_only_copy(orcodm, mask | CD_MASK_ORIGINDEX);
+ mesh_set_only_copy(me_orco, mask | CD_MASK_ORIGINDEX);
- if (mti->applyModifierEM) {
- ndm = modwrap_applyModifierEM(md, ob, em, orcodm, MOD_APPLY_ORCO);
- }
- else {
- ndm = modwrap_applyModifier(md, ob, orcodm, MOD_APPLY_ORCO);
- }
- ASSERT_IS_VALID_DM(ndm);
+ me_next = modwrap_applyModifier(md, &mectx_orco, me_orco);
+ ASSERT_IS_VALID_MESH(me_next);
- if (ndm) {
+ if (me_next) {
/* if the modifier returned a new dm, release the old one */
- if (orcodm && orcodm != ndm) orcodm->release(orcodm);
- orcodm = ndm;
+ if (me_orco && me_orco != me_next) {
+ BKE_id_free(NULL, me_orco);
+ }
+ me_orco = me_next;
}
}
@@ -2460,53 +1800,48 @@ static void editbmesh_calc_modifiers(
mask |= append_mask;
mask = curr->mask; /* CD_MASK_ORCO may have been cleared above */
- DM_set_only_copy(dm, mask | CD_MASK_ORIGINDEX);
+ mesh_set_only_copy(me, mask | CD_MASK_ORIGINDEX);
if (mask & CD_MASK_ORIGSPACE_MLOOP) {
- if (!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) {
- DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL);
- DM_init_origspace(dm);
+ if (!CustomData_has_layer(&me->ldata, CD_ORIGSPACE_MLOOP)) {
+ CustomData_add_layer(&me->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, me->totloop);
+ mesh_init_origspace(me);
}
}
- if (mti->applyModifierEM)
- ndm = modwrap_applyModifierEM(md, ob, em, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU);
- else
- ndm = modwrap_applyModifier(md, ob, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU);
- ASSERT_IS_VALID_DM(ndm);
+ me_next = modwrap_applyModifier(md, &mectx_cache, me);
+ ASSERT_IS_VALID_MESH(me_next);
- if (ndm) {
- if (dm && dm != ndm)
- dm->release(dm);
-
- dm = ndm;
+ if (me_next) {
+ if (me && me != me_next) {
+ BKE_id_free(NULL, me);
+ }
+ me = me_next;
if (deformedVerts) {
MEM_freeN(deformedVerts);
deformedVerts = NULL;
}
}
-
- dm->deformedOnly = false;
- }
-
- /* In case of active preview modifier, make sure preview mask remains for following modifiers. */
- if ((md == previewmd) && (do_mod_wmcol)) {
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
- append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
+ me->runtime.deformed_only = false;
}
if (r_cage && i == cageIndex) {
- if (dm && deformedVerts) {
- *r_cage = CDDM_copy(dm);
- CDDM_apply_vert_coords(*r_cage, deformedVerts);
+ if (me && deformedVerts) {
+ *r_cage = BKE_mesh_copy_for_eval(me, false);
+ BKE_mesh_apply_vert_coords(*r_cage, deformedVerts);
}
- else if (dm) {
- *r_cage = dm;
+ else if (me) {
+ *r_cage = me;
}
else {
- *r_cage = getEditDerivedBMesh(
- em, ob, mask,
+ Mesh *me_orig = ob->data;
+ if (me_orig->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ BKE_mesh_runtime_ensure_edit_data(me_orig);
+ me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformedVerts);
+ }
+ *r_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ em, mask,
deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
}
}
@@ -2518,45 +1853,44 @@ static void editbmesh_calc_modifiers(
* to apply these back onto the DerivedMesh. If we have no DerivedMesh
* then we need to build one.
*/
- if (dm && deformedVerts) {
- *r_final = CDDM_copy(dm);
+ if (me && deformedVerts) {
+ *r_final = BKE_mesh_copy_for_eval(me, false);
- if (!(r_cage && dm == *r_cage)) {
- dm->release(dm);
+ if (!(r_cage && me == *r_cage)) {
+ BKE_id_free(NULL, me);
}
-
- CDDM_apply_vert_coords(*r_final, deformedVerts);
+ BKE_mesh_apply_vert_coords(*r_final, deformedVerts);
}
- else if (dm) {
- *r_final = dm;
+ else if (me) {
+ *r_final = me;
}
else if (!deformedVerts && r_cage && *r_cage) {
/* cage should already have up to date normals */
*r_final = *r_cage;
/* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_wmcol)
- DM_update_weight_mcol(ob, *r_final, draw_flag, NULL, 0, NULL);
- if (do_init_statvis)
- DM_update_statvis_color(scene, ob, *r_final);
+ if (do_init_statvis) {
+ editmesh_update_statvis_color(scene, ob);
+ }
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
- *r_final = getEditDerivedBMesh(em, ob, dataMask, deformedVerts);
+ *r_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, dataMask, deformedVerts);
deformedVerts = NULL;
/* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_wmcol)
- DM_update_weight_mcol(ob, *r_final, draw_flag, NULL, 0, NULL);
- if (do_init_statvis)
- DM_update_statvis_color(scene, ob, *r_final);
+ if (do_init_statvis) {
+ editmesh_update_statvis_color(scene, ob);
+ }
}
if (do_loop_normals) {
/* Compute loop normals */
- DM_calc_loop_normals(*r_final, do_loop_normals, loop_normals_split_angle);
+ BKE_mesh_calc_normals_split(*r_final);
+ BKE_mesh_tessface_clear(*r_final);
if (r_cage && *r_cage && (*r_cage != *r_final)) {
- DM_calc_loop_normals(*r_cage, do_loop_normals, loop_normals_split_angle);
+ BKE_mesh_calc_normals_split(*r_cage);
+ BKE_mesh_tessface_clear(*r_cage);
}
}
@@ -2565,13 +1899,13 @@ static void editbmesh_calc_modifiers(
* check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential
* but quiets annoying error messages since tessfaces wont be created. */
if (dataMask & CD_MASK_MFACE) {
- if ((*r_final)->type != DM_TYPE_EDITBMESH) {
- DM_ensure_tessface(*r_final);
+ if ((*r_final)->edit_btmesh == NULL) {
+ BKE_mesh_tessface_ensure(*r_final);
}
if (r_cage && *r_cage) {
- if ((*r_cage)->type != DM_TYPE_EDITBMESH) {
+ if ((*r_cage)->edit_btmesh == NULL) {
if (*r_cage != *r_final) {
- DM_ensure_tessface(*r_cage);
+ BKE_mesh_tessface_ensure(*r_cage);
}
}
}
@@ -2580,63 +1914,92 @@ static void editbmesh_calc_modifiers(
/* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */
if (!do_loop_normals) {
- dm_ensure_display_normals(*r_final);
+ BKE_mesh_ensure_normals_for_display(*r_final);
/* Some modifiers, like datatransfer, may generate those data, we do not want to keep them,
* as they are used by display code when available (i.e. even if autosmooth is disabled). */
- if (CustomData_has_layer(&(*r_final)->loopData, CD_NORMAL)) {
- CustomData_free_layers(&(*r_final)->loopData, CD_NORMAL, (*r_final)->numLoopData);
+ if (CustomData_has_layer(&(*r_final)->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_final)->ldata, CD_NORMAL, (*r_final)->totloop);
}
- if (r_cage && CustomData_has_layer(&(*r_cage)->loopData, CD_NORMAL)) {
- CustomData_free_layers(&(*r_cage)->loopData, CD_NORMAL, (*r_cage)->numLoopData);
+ if (r_cage && CustomData_has_layer(&(*r_cage)->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_cage)->ldata, CD_NORMAL, (*r_cage)->totloop);
}
}
/* add an orco layer if needed */
if (dataMask & CD_MASK_ORCO)
- add_orco_dm(ob, em, *r_final, orcodm, CD_ORCO);
+ add_orco_mesh(ob, em, *r_final, me_orco, CD_ORCO);
- if (orcodm)
- orcodm->release(orcodm);
+ if (me_orco) {
+ BKE_id_free(NULL, me_orco);
+ }
- if (deformedVerts)
+ if (deformedVerts) {
MEM_freeN(deformedVerts);
+ }
}
-#ifdef WITH_OPENSUBDIV
-/* The idea is to skip CPU-side ORCO calculation when
- * we'll be using GPU backend of OpenSubdiv. This is so
- * playback performance is kept as high as possible.
- */
-static bool calc_modifiers_skip_orco(Scene *scene,
- Object *ob,
- bool use_render_params)
+static void mesh_finalize_eval(Object *object)
{
- ModifierData *last_md = ob->modifiers.last;
- const int required_mode = use_render_params ? eModifierMode_Render : eModifierMode_Realtime;
- if (last_md != NULL &&
- last_md->type == eModifierType_Subsurf &&
- modifier_isEnabled(scene, last_md, required_mode))
- {
- if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
- return false;
- }
- else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) {
- return false;
- }
- else if ((DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CPU) != 0) {
- return false;
- }
- SubsurfModifierData *smd = (SubsurfModifierData *)last_md;
- /* TODO(sergey): Deduplicate this with checks from subsurf_ccg.c. */
- return smd->use_opensubdiv != 0;
+ Mesh *mesh = (Mesh *)object->data;
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ /* Special Tweaks for cases when evaluated mesh came from
+ * BKE_mesh_new_nomain_from_template().
+ */
+ BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name));
+ if (mesh_eval->mat != NULL) {
+ MEM_freeN(mesh_eval->mat);
+ }
+ /* Set flag which makes it easier to see what's going on in a debugger. */
+ mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
+ mesh_eval->mat = MEM_dupallocN(mesh->mat);
+ mesh_eval->totcol = mesh->totcol;
+ /* Make evaluated mesh to share same edit mesh pointer as original
+ * and copied meshes.
+ */
+ mesh_eval->edit_btmesh = mesh->edit_btmesh;
+ /* Copy autosmooth settings from original mesh.
+ * This is not done by BKE_mesh_new_nomain_from_template(), so need to take
+ * extra care here.
+ */
+ mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH);
+ mesh_eval->smoothresh = mesh->smoothresh;
+ /* Replace evaluated object's data with fully evaluated mesh. */
+ /* TODO(sergey): There was statement done by Sybren and Mai that this
+ * caused modifiers to be applied twice. which is weirtd and shouldn't
+ * really happen. But since there is no reference to the report, can not
+ * do much about this.
+ */
+
+ /* Object is sometimes not evaluated!
+ * TODO(sergey): BAD TEMPORARY HACK FOR UNTIL WE ARE SMARTER */
+ if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ object->data = mesh_eval;
+ }
+ else {
+ /* evaluated will be available via: 'object->runtime.mesh_eval' */
}
- return false;
}
-#endif
+
+static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob)
+{
+ uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id);
+
+ if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) {
+ BKE_shrinkwrap_compute_boundary_data(ob->runtime.mesh_eval);
+ }
+}
+
+static void mesh_runtime_check_normals_valid(const Mesh *mesh)
+{
+ UNUSED_VARS_NDEBUG(mesh);
+ BLI_assert(!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL));
+ BLI_assert(!(mesh->runtime.cd_dirty_loop & CD_MASK_NORMAL));
+ BLI_assert(!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL));
+}
static void mesh_build_data(
- Scene *scene, Object *ob, CustomDataMask dataMask,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask,
const bool build_shapekey_layers, const bool need_mapping)
{
BLI_assert(ob->type == OB_MESH);
@@ -2644,70 +2007,77 @@ static void mesh_build_data(
BKE_object_free_derived_caches(ob);
BKE_object_sculpt_modifiers_changed(ob);
-#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(scene, ob, false)) {
- dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
- }
+ mesh_calc_modifiers(
+ depsgraph, scene, ob, NULL, 1, need_mapping, dataMask, -1, true, build_shapekey_layers,
+ &ob->runtime.mesh_deform_eval, &ob->runtime.mesh_eval);
+
+#ifdef USE_DERIVEDMESH
+ /* TODO(campbell): remove these copies, they are expected in various places over the code. */
+ ob->derivedDeform = CDDM_from_mesh_ex(ob->runtime.mesh_deform_eval, CD_REFERENCE, CD_MASK_MESH);
+ ob->derivedFinal = CDDM_from_mesh_ex(ob->runtime.mesh_eval, CD_REFERENCE, CD_MASK_MESH);
#endif
- mesh_calc_modifiers(
- scene, ob, NULL, false, 1, need_mapping, dataMask, -1, true, build_shapekey_layers,
- true,
- &ob->derivedDeform, &ob->derivedFinal);
+ BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
+ BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
- DM_set_object_boundbox(ob, ob->derivedFinal);
+ mesh_finalize_eval(ob);
+#ifdef USE_DERIVEDMESH
ob->derivedFinal->needsFree = 0;
ob->derivedDeform->needsFree = 0;
+#endif
ob->lastDataMask = dataMask;
ob->lastNeedMapping = need_mapping;
if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too,
* but this avoids waiting on first stroke) */
-
- BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, false, false);
+ /* XXX Disabled for now.
+ * This can create horrible nasty bugs by generating re-entrant call of mesh_get_eval_final! */
+// BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
- BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS));
+ mesh_runtime_check_normals_valid(ob->runtime.mesh_eval);
+ mesh_build_extra_data(depsgraph, ob);
}
-static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
+static void editbmesh_build_data(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
{
BKE_object_free_derived_caches(obedit);
BKE_object_sculpt_modifiers_changed(obedit);
BKE_editmesh_free_derivedmesh(em);
-#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(scene, obedit, false)) {
- dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
- }
-#endif
+ Mesh *me_cage;
+ Mesh *me_final;
editbmesh_calc_modifiers(
- scene, obedit, em, dataMask,
- &em->derivedCage, &em->derivedFinal);
+ depsgraph, scene, obedit, em, dataMask,
+ &me_cage, &me_final);
- DM_set_object_boundbox(obedit, em->derivedFinal);
+ em->mesh_eval_final = me_final;
+ em->mesh_eval_cage = me_cage;
+
+ BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
em->lastDataMask = dataMask;
- em->derivedFinal->needsFree = 0;
- em->derivedCage->needsFree = 0;
- BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS));
+ mesh_runtime_check_normals_valid(em->mesh_eval_final);
}
-static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *r_need_mapping)
+static CustomDataMask object_get_datamask(const Depsgraph *depsgraph, Object *ob, bool *r_need_mapping)
{
- Object *actob = scene->basact ? scene->basact->object : NULL;
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : NULL;
CustomDataMask mask = ob->customdata_mask;
if (r_need_mapping) {
*r_need_mapping = false;
}
- if (ob == actob) {
+ if (DEG_get_original_object(ob) == actob) {
bool editing = BKE_paint_select_face_test(ob);
/* weight paint and face select need original indices because of selection buffer drawing */
@@ -2726,7 +2096,7 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *
}
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- mask |= CD_MASK_PREVIEW_MLOOPCOL;
+ mask |= CD_MASK_MDEFORMVERT;
}
if (ob->mode & OB_MODE_EDIT)
@@ -2737,151 +2107,208 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *
}
void makeDerivedMesh(
- Scene *scene, Object *ob, BMEditMesh *em,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em,
CustomDataMask dataMask, const bool build_shapekey_layers)
{
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (em) {
- editbmesh_build_data(scene, ob, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, ob, em, dataMask);
}
else {
- mesh_build_data(scene, ob, dataMask, build_shapekey_layers, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, build_shapekey_layers, need_mapping);
}
}
/***/
-DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated DM, use: 'mesh_get_eval_final'. */
+DerivedMesh *mesh_get_derived_final(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (!ob->derivedFinal ||
((dataMask & ob->lastDataMask) != dataMask) ||
(need_mapping != ob->lastNeedMapping))
{
- mesh_build_data(scene, ob, dataMask, false, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
}
if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
return ob->derivedFinal;
}
+#endif
+Mesh *mesh_get_eval_final(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
+{
+ /* if there's no evaluated mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ bool need_mapping;
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
+
+ if (!ob->runtime.mesh_eval ||
+ ((dataMask & ob->lastDataMask) != dataMask) ||
+ (need_mapping != ob->lastNeedMapping))
+ {
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
+ }
+
+ if (ob->runtime.mesh_eval) { BLI_assert(!(ob->runtime.mesh_eval->runtime.cd_dirty_vert & CD_MASK_NORMAL)); }
+ return ob->runtime.mesh_eval;
+}
-DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated DM, use: 'mesh_get_eval_deform' instead. */
+DerivedMesh *mesh_get_derived_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (!ob->derivedDeform ||
((dataMask & ob->lastDataMask) != dataMask) ||
(need_mapping != ob->lastNeedMapping))
{
- mesh_build_data(scene, ob, dataMask, false, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
}
return ob->derivedDeform;
}
+#endif
+Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
+{
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ bool need_mapping;
+
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
+
+ if (!ob->runtime.mesh_deform_eval ||
+ ((dataMask & ob->lastDataMask) != dataMask) ||
+ (need_mapping != ob->lastNeedMapping))
+ {
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
+ }
-DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask dataMask)
+ return ob->runtime.mesh_deform_eval;
+}
+
+
+#ifdef USE_DERIVEDMESH
+/* Deprecated, use `mesh_create_eval_final_render` instead. */
+DerivedMesh *mesh_create_derived_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, NULL, true, 1, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false,
NULL, &final);
return final;
}
-
-DerivedMesh *mesh_create_derived_index_render(Scene *scene, Object *ob, CustomDataMask dataMask, int index)
+#endif
+Mesh *mesh_create_eval_final_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
- DerivedMesh *final;
+ Mesh *final;
mesh_calc_modifiers(
- scene, ob, NULL, true, 1, false, dataMask, index, false, false, false,
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false,
NULL, &final);
return final;
}
-DerivedMesh *mesh_create_derived_view(
- Scene *scene, Object *ob,
- CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated, use `mesh_create_eval_final_index_render` instead. */
+DerivedMesh *mesh_create_derived_index_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask, int index)
{
DerivedMesh *final;
- /* XXX hack
- * psys modifier updates particle state when called during dupli-list generation,
- * which can lead to wrong transforms. This disables particle system modifier execution.
- */
- ob->transflag |= OB_NO_PSYS_UPDATE;
-
- mesh_calc_modifiers(
- scene, ob, NULL, false, 1, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, index, false, false,
NULL, &final);
- ob->transflag &= ~OB_NO_PSYS_UPDATE;
-
return final;
}
-
-DerivedMesh *mesh_create_derived_no_deform(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
+#endif
+Mesh *mesh_create_eval_final_index_render(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask, int index)
{
- DerivedMesh *final;
+ Mesh *final;
mesh_calc_modifiers(
- scene, ob, vertCos, false, 0, false, dataMask, -1, false, false, false,
+ depsgraph, scene, ob, NULL, 1, false, dataMask, index, false, false,
NULL, &final);
return final;
}
-DerivedMesh *mesh_create_derived_no_virtual(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated, use `mesh_create_eval_final_view` instead. */
+DerivedMesh *mesh_create_derived_view(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, CustomDataMask dataMask)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, vertCos, false, -1, false, dataMask, -1, false, false, false,
+ /* XXX hack
+ * psys modifier updates particle state when called during dupli-list generation,
+ * which can lead to wrong transforms. This disables particle system modifier execution.
+ */
+ ob->transflag |= OB_NO_PSYS_UPDATE;
+
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false,
NULL, &final);
+ ob->transflag &= ~OB_NO_PSYS_UPDATE;
+
return final;
}
+#endif
-DerivedMesh *mesh_create_derived_physics(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
+Mesh *mesh_create_eval_final_view(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, CustomDataMask dataMask)
{
- DerivedMesh *final;
+ Mesh *final;
+
+ /* XXX hack
+ * psys modifier updates particle state when called during dupli-list generation,
+ * which can lead to wrong transforms. This disables particle system modifier execution.
+ */
+ ob->transflag |= OB_NO_PSYS_UPDATE;
mesh_calc_modifiers(
- scene, ob, vertCos, false, -1, true, dataMask, -1, false, false, false,
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false,
NULL, &final);
+ ob->transflag &= ~OB_NO_PSYS_UPDATE;
+
return final;
}
-DerivedMesh *mesh_create_derived_no_deform_render(
- Scene *scene, Object *ob,
- float (*vertCos)[3],
- CustomDataMask dataMask)
+DerivedMesh *mesh_create_derived_no_deform(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ float (*vertCos)[3], CustomDataMask dataMask)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, vertCos, true, 0, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, vertCos, 0, false, dataMask, -1, false, false,
NULL, &final);
return final;
@@ -2889,74 +2316,48 @@ DerivedMesh *mesh_create_derived_no_deform_render(
/***/
-DerivedMesh *editbmesh_get_derived_cage_and_final(
- Scene *scene, Object *obedit, BMEditMesh *em,
+Mesh *editbmesh_get_eval_cage_and_final(
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em,
CustomDataMask dataMask,
/* return args */
- DerivedMesh **r_final)
+ Mesh **r_final)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit, NULL);
+ dataMask |= object_get_datamask(depsgraph, obedit, NULL);
- if (!em->derivedCage ||
+ if (!em->mesh_eval_cage ||
(em->lastDataMask & dataMask) != dataMask)
{
- editbmesh_build_data(scene, obedit, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, obedit, em, dataMask);
}
- *r_final = em->derivedFinal;
- if (em->derivedFinal) { BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
- return em->derivedCage;
+ *r_final = em->mesh_eval_final;
+ if (em->mesh_eval_final) { BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS)); }
+ return em->mesh_eval_cage;
}
-DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
+Mesh *editbmesh_get_eval_cage(
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em,
+ CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit, NULL);
+ dataMask |= object_get_datamask(depsgraph, obedit, NULL);
- if (!em->derivedCage ||
+ if (!em->mesh_eval_cage ||
(em->lastDataMask & dataMask) != dataMask)
{
- editbmesh_build_data(scene, obedit, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, obedit, em, dataMask);
}
- return em->derivedCage;
-}
-
-DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDataMask data_mask)
-{
- return getEditDerivedBMesh(em, obedit, data_mask, NULL);
+ return em->mesh_eval_cage;
}
/***/
-/* get derived mesh from an object, using editbmesh if available. */
-DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
-{
- if (for_render) {
- /* TODO(sergey): use proper derived render here in the future. */
- return ob->derivedFinal;
- }
-
- /* only return the editmesh if its from this object because
- * we don't a mesh from another object's modifier stack: T43122 */
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
- if (em && (em->ob == ob)) {
- DerivedMesh *dm = em->derivedFinal;
- return dm;
- }
- }
-
- return ob->derivedFinal;
-}
-
-
/* UNUSED */
#if 0
@@ -3038,287 +2439,22 @@ static void make_vertexcos__mapFunc(
}
}
-void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos)
+void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int totcos)
{
- if (dm->foreachMappedVert) {
+ if (me_eval->runtime.deformed_only == false) {
MappedUserData userData;
memset(r_cos, 0, sizeof(*r_cos) * totcos);
userData.vertexcos = r_cos;
userData.vertex_visit = BLI_BITMAP_NEW(totcos, "vertexcos flags");
- dm->foreachMappedVert(dm, make_vertexcos__mapFunc, &userData, DM_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(me_eval, make_vertexcos__mapFunc, &userData, MESH_FOREACH_NOP);
MEM_freeN(userData.vertex_visit);
}
else {
- int i;
- for (i = 0; i < totcos; i++) {
- dm->getVertCo(dm, i, r_cos[i]);
- }
- }
-}
-
-/* ******************* GLSL ******************** */
-
-/** \name Tangent Space Calculation
- * \{ */
-
-/* Necessary complexity to handle looptri's as quads for correct tangents */
-#define USE_LOOPTRI_DETECT_QUADS
-
-typedef struct {
- float (*precomputedFaceNormals)[3];
- float (*precomputedLoopNormals)[3];
- const MLoopTri *looptri;
- MLoopUV *mloopuv; /* texture coordinates */
- MPoly *mpoly; /* indices */
- MLoop *mloop; /* indices */
- MVert *mvert; /* vertices & normals */
- float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
-#endif
-
-} SGLSLMeshToTangent;
-
-/* interface */
-#include "mikktspace.h"
-
-static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
-#else
- return pMesh->numTessFaces;
-#endif
-}
-
-static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- if (pMesh->face_as_quad_map) {
- const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- return 4;
- }
- }
- return 3;
-#else
- UNUSED_VARS(pContext, face_num);
- return 3;
-#endif
-}
-
-static void dm_ts_GetPosition(
- const SMikkTSpaceContext *pContext, float r_co[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
- const float *co;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
- copy_v3_v3(r_co, co);
-}
-
-static void dm_ts_GetTextureCoordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- if (pMesh->mloopuv != NULL) {
- const float *uv = pMesh->mloopuv[loop_index].uv;
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
-}
-
-static void dm_ts_GetNormal(
- const SMikkTSpaceContext *pContext, float r_no[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
- }
- else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
- }
- else {
-#ifdef USE_LOOPTRI_DETECT_QUADS
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- normal_quad_v3(
- r_no,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
- }
- else
-#endif
- {
- normal_tri_v3(
- r_no,
- pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
- }
- }
- }
- else {
- const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
- normal_short_to_float_v3(r_no, no);
- }
-}
-
-static void dm_ts_SetTSpace(
- const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
- float *pRes;
-
-finally:
- pRes = pMesh->tangent[loop_index];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
-}
-
-void DM_calc_tangents_names_from_gpu(
- const GPUVertexAttribs *gattribs,
- char (*tangent_names)[MAX_NAME], int *r_tangent_names_count)
-{
- int count = 0;
- for (int b = 0; b < gattribs->totlayer; b++) {
- if (gattribs->layer[b].type == CD_TANGENT) {
- strcpy(tangent_names[count++], gattribs->layer[b].name);
+ MVert *mv = me_eval->mvert;
+ for (int i = 0; i < totcos; i++, mv++) {
+ copy_v3_v3(r_cos[i], mv->co);
}
}
- *r_tangent_names_count = count;
-}
-
-static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- struct SGLSLMeshToTangent *mesh2tangent = taskdata;
- /* new computation method */
- {
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
-
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = dm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = dm_ts_GetPosition;
- sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = dm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
-
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
}
void DM_add_named_tangent_layer_for_uv(
@@ -3334,805 +2470,107 @@ void DM_add_named_tangent_layer_for_uv(
}
}
-/**
- * Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
- * Also, we calculate tangent_mask that works as a descriptor of tangents state.
- * If tangent_mask has changed, then recalculate tangents.
- */
-void DM_calc_loop_tangents_step_0(
- const CustomData *loopData, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count,
- bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
- char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
-{
- /* Active uv in viewport */
- int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
- *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
- ract_uv_name[0] = 0;
- if (*ract_uv_n != -1) {
- strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
- }
-
- /* Active tangent in render */
- *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
- rren_uv_name[0] = 0;
- if (*rren_uv_n != -1) {
- strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
- }
-
- /* If active tangent not in tangent_names we take it into account */
- *rcalc_act = false;
- *rcalc_ren = false;
- for (int i = 0; i < tangent_names_count; i++) {
- if (tangent_names[i][0] == 0) {
- calc_active_tangent = true;
- }
- }
- if (calc_active_tangent) {
- *rcalc_act = true;
- *rcalc_ren = true;
- for (int i = 0; i < tangent_names_count; i++) {
- if (STREQ(ract_uv_name, tangent_names[i]))
- *rcalc_act = false;
- if (STREQ(rren_uv_name, tangent_names[i]))
- *rcalc_ren = false;
- }
- }
- *rtangent_mask = 0;
-
- const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
- for (int n = 0; n < uv_layer_num; n++) {
- const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
- bool add = false;
- for (int i = 0; i < tangent_names_count; i++) {
- if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
- add = true;
- break;
- }
- }
- if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
- (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
- {
- add = true;
- }
- if (add)
- *rtangent_mask |= 1 << n;
- }
-
- if (uv_layer_num == 0)
- *rtangent_mask |= DM_TANGENT_MASK_ORCO;
-}
-
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count)
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len)
{
- int act_uv_n = -1;
- int ren_uv_n = -1;
- bool calc_act = false;
- bool calc_ren = false;
- char act_uv_name[MAX_NAME];
- char ren_uv_name[MAX_NAME];
- short tangent_mask = 0;
- DM_calc_loop_tangents_step_0(
- &dm->loopData, calc_active_tangent, tangent_names, tangent_names_count,
- &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
- if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
- /* Check we have all the needed layers */
- MPoly *mpoly = dm->getPolyArray(dm);
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- int totface = dm->getNumLoopTri(dm);
- /* Allocate needed tangent layers */
- for (int i = 0; i < tangent_names_count; i++)
- if (tangent_names[i][0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
- if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1)
- CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, "");
- if (calc_act && act_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
- if (calc_ren && ren_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name);
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (totface != dm->getNumPolys(dm)) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_malloc_arrayN(totface, sizeof(int), __func__);
- int k, j;
- for (k = 0, j = 0; j < totface; k++, j++) {
- face_as_quad_map[k] = j;
- /* step over all quads */
- if (mpoly[looptri[j].poly].totloop == 4) {
- j++; /* skips the nest looptri */
- }
- }
- num_face_as_quad_map = k;
- }
- else {
- num_face_as_quad_map = totface;
- }
-#endif
-
- /* Calculation */
- {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
-
- dm->tangent_mask = 0;
- /* Calculate tangent layers */
- SGLSLMeshToTangent data_array[MAX_MTFACE];
- const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
- for (int n = 0; n < tangent_layer_num; n++) {
- int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
- BLI_assert(n < MAX_MTFACE);
- SGLSLMeshToTangent *mesh2tangent = &data_array[n];
- mesh2tangent->numTessFaces = totface;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent->face_as_quad_map = face_as_quad_map;
- mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
-#endif
- mesh2tangent->mvert = dm->getVertArray(dm);
- mesh2tangent->mpoly = dm->getPolyArray(dm);
- mesh2tangent->mloop = dm->getLoopArray(dm);
- mesh2tangent->looptri = dm->getLoopTriArray(dm);
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL);
- mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- mesh2tangent->orco = NULL;
- mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
-
- /* Fill the resulting tangent_mask */
- if (!mesh2tangent->mloopuv) {
- mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!mesh2tangent->orco)
- continue;
-
- dm->tangent_mask |= DM_TANGENT_MASK_ORCO;
- }
- else {
- int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
- int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- dm->tangent_mask |= 1 << (uv_ind - uv_start);
- }
-
- mesh2tangent->tangent = dm->loopData.layers[index].data;
- BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
- }
-
- BLI_assert(dm->tangent_mask == tangent_mask);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- }
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (face_as_quad_map) {
- MEM_freeN(face_as_quad_map);
- }
-#undef USE_LOOPTRI_DETECT_QUADS
-
-#endif
-
- /* Update active layer index */
- int act_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
- if (act_uv_index != -1) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[act_uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-
- /* Update render layer index */
- int ren_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
- if (ren_uv_index != -1) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[ren_uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
- }
-}
-
-/** \} */
-
-
-void DM_calc_auto_bump_scale(DerivedMesh *dm)
-{
- /* int totvert = dm->getNumVerts(dm); */ /* UNUSED */
- int totface = dm->getNumTessFaces(dm);
-
- MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getTessFaceArray(dm);
- MTFace *mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
-
- if (mtface) {
- double dsum = 0.0;
- int nr_accumulated = 0;
- int f;
-
- for (f = 0; f < totface; f++) {
- {
- float *verts[4], *tex_coords[4];
- const int nr_verts = mface[f].v4 != 0 ? 4 : 3;
- bool is_degenerate;
- int i;
-
- verts[0] = mvert[mface[f].v1].co; verts[1] = mvert[mface[f].v2].co; verts[2] = mvert[mface[f].v3].co;
- tex_coords[0] = mtface[f].uv[0]; tex_coords[1] = mtface[f].uv[1]; tex_coords[2] = mtface[f].uv[2];
- if (nr_verts == 4) {
- verts[3] = mvert[mface[f].v4].co;
- tex_coords[3] = mtface[f].uv[3];
- }
-
- /* discard degenerate faces */
- is_degenerate = 0;
- if (equals_v3v3(verts[0], verts[1]) ||
- equals_v3v3(verts[0], verts[2]) ||
- equals_v3v3(verts[1], verts[2]) ||
- equals_v2v2(tex_coords[0], tex_coords[1]) ||
- equals_v2v2(tex_coords[0], tex_coords[2]) ||
- equals_v2v2(tex_coords[1], tex_coords[2]))
- {
- is_degenerate = 1;
- }
-
- /* verify last vertex as well if this is a quad */
- if (is_degenerate == 0 && nr_verts == 4) {
- if (equals_v3v3(verts[3], verts[0]) ||
- equals_v3v3(verts[3], verts[1]) ||
- equals_v3v3(verts[3], verts[2]) ||
- equals_v2v2(tex_coords[3], tex_coords[0]) ||
- equals_v2v2(tex_coords[3], tex_coords[1]) ||
- equals_v2v2(tex_coords[3], tex_coords[2]))
- {
- is_degenerate = 1;
- }
-
- /* verify the winding is consistent */
- if (is_degenerate == 0) {
- float prev_edge[2];
- bool is_signed = 0;
- sub_v2_v2v2(prev_edge, tex_coords[0], tex_coords[3]);
-
- i = 0;
- while (is_degenerate == 0 && i < 4) {
- float cur_edge[2], signed_area;
- sub_v2_v2v2(cur_edge, tex_coords[(i + 1) & 0x3], tex_coords[i]);
- signed_area = cross_v2v2(prev_edge, cur_edge);
-
- if (i == 0) {
- is_signed = (signed_area < 0.0f) ? 1 : 0;
- }
- else if ((is_signed != 0) != (signed_area < 0.0f)) {
- is_degenerate = 1;
- }
-
- if (is_degenerate == 0) {
- copy_v2_v2(prev_edge, cur_edge);
- i++;
- }
- }
- }
- }
-
- /* proceed if not a degenerate face */
- if (is_degenerate == 0) {
- int nr_tris_to_pile = 0;
- /* quads split at shortest diagonal */
- int offs = 0; /* initial triangulation is 0,1,2 and 0, 2, 3 */
- if (nr_verts == 4) {
- float pos_len_diag0, pos_len_diag1;
-
- pos_len_diag0 = len_squared_v3v3(verts[2], verts[0]);
- pos_len_diag1 = len_squared_v3v3(verts[3], verts[1]);
-
- if (pos_len_diag1 < pos_len_diag0) {
- offs = 1; // alter split
- }
- else if (pos_len_diag0 == pos_len_diag1) { /* do UV check instead */
- float tex_len_diag0, tex_len_diag1;
-
- tex_len_diag0 = len_squared_v2v2(tex_coords[2], tex_coords[0]);
- tex_len_diag1 = len_squared_v2v2(tex_coords[3], tex_coords[1]);
-
- if (tex_len_diag1 < tex_len_diag0) {
- offs = 1; /* alter split */
- }
- }
- }
- nr_tris_to_pile = nr_verts - 2;
- if (nr_tris_to_pile == 1 || nr_tris_to_pile == 2) {
- const int indices[6] = {offs + 0, offs + 1, offs + 2, offs + 0, offs + 2, (offs + 3) & 0x3 };
- int t;
- for (t = 0; t < nr_tris_to_pile; t++) {
- float f2x_area_uv;
- const float *p0 = verts[indices[t * 3 + 0]];
- const float *p1 = verts[indices[t * 3 + 1]];
- const float *p2 = verts[indices[t * 3 + 2]];
-
- float edge_t0[2], edge_t1[2];
- sub_v2_v2v2(edge_t0, tex_coords[indices[t * 3 + 1]], tex_coords[indices[t * 3 + 0]]);
- sub_v2_v2v2(edge_t1, tex_coords[indices[t * 3 + 2]], tex_coords[indices[t * 3 + 0]]);
-
- f2x_area_uv = fabsf(cross_v2v2(edge_t0, edge_t1));
- if (f2x_area_uv > FLT_EPSILON) {
- float norm[3], v0[3], v1[3], f2x_surf_area, fsurf_ratio;
- sub_v3_v3v3(v0, p1, p0);
- sub_v3_v3v3(v1, p2, p0);
- cross_v3_v3v3(norm, v0, v1);
-
- f2x_surf_area = len_v3(norm);
- fsurf_ratio = f2x_surf_area / f2x_area_uv; /* tri area divided by texture area */
-
- nr_accumulated++;
- dsum += (double)(fsurf_ratio);
- }
- }
- }
- }
- }
- }
-
- /* finalize */
- {
- const float avg_area_ratio = (nr_accumulated > 0) ? ((float)(dsum / nr_accumulated)) : 1.0f;
- const float use_as_render_bump_scale = sqrtf(avg_area_ratio); // use width of average surface ratio as your bump scale
- dm->auto_bump_scale = use_as_render_bump_scale;
- }
- }
- else {
- dm->auto_bump_scale = 1.0f;
- }
+ BKE_mesh_calc_loop_tangent_ex(
+ dm->getVertArray(dm),
+ dm->getPolyArray(dm), dm->getNumPolys(dm),
+ dm->getLoopArray(dm),
+ dm->getLoopTriArray(dm), dm->getNumLoopTri(dm),
+ &dm->loopData,
+ calc_active_tangent,
+ tangent_names, tangent_names_len,
+ CustomData_get_layer(&dm->polyData, CD_NORMAL),
+ dm->getLoopDataArray(dm, CD_NORMAL),
+ dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */
+ /* result */
+ &dm->loopData, dm->getNumLoops(dm),
+ &dm->tangent_mask);
}
-void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, DMVertexAttribs *attribs)
+void DM_init_origspace(DerivedMesh *dm)
{
- CustomData *vdata, *ldata;
- int a, b, layer;
- const bool is_editmesh = (dm->type == DM_TYPE_EDITBMESH);
-
- /* From the layers requested by the GLSL shader, figure out which ones are
- * actually available for this derivedmesh, and retrieve the pointers */
-
- memset(attribs, 0, sizeof(DMVertexAttribs));
-
- vdata = &dm->vertData;
- ldata = dm->getLoopDataLayout(dm);
-
- /* calc auto bump scale if necessary */
- if (dm->auto_bump_scale <= 0.0f)
- DM_calc_auto_bump_scale(dm);
-
- char tangent_names[MAX_MTFACE][MAX_NAME];
- int tangent_names_count;
- /* Add a tangent layer/layers. */
- DM_calc_tangents_names_from_gpu(gattribs, tangent_names, &tangent_names_count);
-
- if (tangent_names_count)
- dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
-
- for (b = 0; b < gattribs->totlayer; b++) {
- int type = gattribs->layer[b].type;
- layer = -1;
- if (type == CD_AUTO_FROM_NAME) {
- /* We need to deduct what exact layer is used.
- *
- * We do it based on the specified name.
- */
- if (gattribs->layer[b].name[0]) {
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- type = CD_MTFACE;
- if (layer == -1) {
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- type = CD_MCOL;
- }
- if (layer == -1) {
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- type = CD_TANGENT;
- }
- if (layer == -1) {
- continue;
- }
- }
- else {
- /* Fall back to the UV layer, which matches old behavior. */
- type = CD_MTFACE;
- }
- }
- if (type == CD_MTFACE) {
- /* uv coordinates */
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
- }
-
- a = attribs->tottface++;
-
- if (layer != -1) {
- attribs->tface[a].array = is_editmesh ? NULL : ldata->layers[layer].data;
- attribs->tface[a].em_offset = ldata->layers[layer].offset;
- }
- else {
- attribs->tface[a].array = NULL;
- attribs->tface[a].em_offset = -1;
- }
-
- attribs->tface[a].gl_index = gattribs->layer[b].glindex;
- attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
- }
- else if (type == CD_MCOL) {
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
- }
-
- a = attribs->totmcol++;
-
- if (layer != -1) {
- attribs->mcol[a].array = is_editmesh ? NULL : ldata->layers[layer].data;
- /* odd, store the offset for a different layer type here, but editmode draw code expects it */
- attribs->mcol[a].em_offset = ldata->layers[layer].offset;
- }
- else {
- attribs->mcol[a].array = NULL;
- attribs->mcol[a].em_offset = -1;
- }
-
- attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
- attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- else if (type == CD_TANGENT) {
- /* note, even with 'is_editmesh' this uses the derived-meshes loop data */
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
- }
+ const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- a = attribs->tottang++;
+ OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP);
+ const int numpoly = dm->getNumPolys(dm);
+ // const int numloop = dm->getNumLoops(dm);
+ MVert *mv = dm->getVertArray(dm);
+ MLoop *ml = dm->getLoopArray(dm);
+ MPoly *mp = dm->getPolyArray(dm);
+ int i, j, k;
- if (layer != -1) {
- attribs->tang[a].array = dm->loopData.layers[layer].data;
- attribs->tang[a].em_offset = dm->loopData.layers[layer].offset;
- }
- else {
- attribs->tang[a].array = NULL;
- attribs->tang[a].em_offset = -1;
- }
+ float (*vcos_2d)[2] = NULL;
+ BLI_array_staticdeclare(vcos_2d, 64);
- attribs->tang[a].gl_index = gattribs->layer[b].glindex;
- attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- else if (type == CD_ORCO) {
- /* original coordinates */
- if (layer == -1) {
- layer = CustomData_get_layer_index(vdata, CD_ORCO);
- }
- attribs->totorco = 1;
+ for (i = 0; i < numpoly; i++, mp++) {
+ OrigSpaceLoop *lof = lof_array + mp->loopstart;
- if (layer != -1) {
- attribs->orco.array = vdata->layers[layer].data;
- attribs->orco.em_offset = vdata->layers[layer].offset;
- }
- else {
- attribs->orco.array = NULL;
- attribs->orco.em_offset = -1;
+ if (mp->totloop == 3 || mp->totloop == 4) {
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ copy_v2_v2(lof->uv, default_osf[j]);
}
-
- attribs->orco.gl_index = gattribs->layer[b].glindex;
- attribs->orco.gl_texco = gattribs->layer[b].gltexco;
- attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- }
-}
-
-/**
- * Set vertex shader attribute inputs for a particular tessface vert
- *
- * \param a: tessface index
- * \param index: vertex index
- * \param vert: corner index (0, 1, 2, 3)
- * \param loop: absolute loop corner index
- */
-void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop)
-{
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- int b;
-
- UNUSED_VARS(a, vert);
-
- /* orco texture coordinates */
- if (attribs->totorco) {
- /*const*/ float (*array)[3] = attribs->orco.array;
- const float *orco = (array) ? array[index] : zero;
-
- if (attribs->orco.gl_texco)
- glTexCoord3fv(orco);
- else
- glVertexAttrib3fv(attribs->orco.gl_index, orco);
- }
-
- /* uv texture coordinates */
- for (b = 0; b < attribs->tottface; b++) {
- const float *uv;
-
- if (attribs->tface[b].array) {
- const MLoopUV *mloopuv = &attribs->tface[b].array[loop];
- uv = mloopuv->uv;
- }
- else {
- uv = zero;
- }
-
- if (attribs->tface[b].gl_texco)
- glTexCoord2fv(uv);
- else
- glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
- }
-
- /* vertex colors */
- for (b = 0; b < attribs->totmcol; b++) {
- GLfloat col[4];
-
- if (attribs->mcol[b].array) {
- const MLoopCol *cp = &attribs->mcol[b].array[loop];
- rgba_uchar_to_float(col, &cp->r);
}
else {
- zero_v4(col);
- }
-
- glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
- }
-
- /* tangent for normal mapping */
- for (b = 0; b < attribs->tottang; b++) {
- if (attribs->tang[b].array) {
- /*const*/ float (*array)[4] = attribs->tang[b].array;
- const float *tang = (array) ? array[loop] : zero;
- glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
- }
- }
-}
-
-void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs)
-{
- int i;
- if (attribs->totorco) {
- if (attribs->orco.gl_info_index != -1) {
- glUniform1i(attribs->orco.gl_info_index, 0);
- }
- }
- for (i = 0; i < attribs->tottface; i++) {
- if (attribs->tface[i].gl_info_index != -1) {
- glUniform1i(attribs->tface[i].gl_info_index, 0);
- }
- }
- for (i = 0; i < attribs->totmcol; i++) {
- if (attribs->mcol[i].gl_info_index != -1) {
- glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
- }
- }
-
- for (i = 0; i < attribs->tottang; i++) {
- if (attribs->tang[i].gl_info_index != -1) {
- glUniform1i(attribs->tang[i].gl_info_index, 0);
- }
- }
-}
-
-/* Set object's bounding box based on DerivedMesh min/max data */
-void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
-{
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- dm->getMinMax(dm, min, max);
-
- if (!ob->bb)
- ob->bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
-
- BKE_boundbox_init_from_minmax(ob->bb, min, max);
-
- ob->bb->flag &= ~BOUNDBOX_DIRTY;
-}
-
-/* --- NAVMESH (begin) --- */
-#ifdef WITH_GAMEENGINE
-
-/* BMESH_TODO, navmesh is not working right currently
- * All tools set this as MPoly data, but derived mesh currently draws from MFace (tessface)
- *
- * Proposed solution, rather then copy CD_RECAST into the MFace array,
- * use ORIGINDEX to get the original poly index and then get the CD_RECAST
- * data from the original me->mpoly layer. - campbell
- */
-
-
-BLI_INLINE int navmesh_bit(int a, int b)
-{
- return (a & (1 << b)) >> b;
-}
-
-BLI_INLINE void navmesh_intToCol(int i, float col[3])
-{
- int r = navmesh_bit(i, 0) + navmesh_bit(i, 3) * 2 + 1;
- int g = navmesh_bit(i, 1) + navmesh_bit(i, 4) * 2 + 1;
- int b = navmesh_bit(i, 2) + navmesh_bit(i, 5) * 2 + 1;
- col[0] = 1 - r * 63.0f / 255.0f;
- col[1] = 1 - g * 63.0f / 255.0f;
- col[2] = 1 - b * 63.0f / 255.0f;
-}
-
-static void navmesh_drawColored(DerivedMesh *dm)
-{
- int a, glmode;
- MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT);
- MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
- int *polygonIdx = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
- float col[3];
+ MLoop *l = &ml[mp->loopstart];
+ float p_nor[3], co[3];
+ float mat[3][3];
- if (!polygonIdx)
- return;
+ float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
+ float translate[2], scale[2];
-#if 0
- //UI_ThemeColor(TH_WIRE);
- glLineWidth(2.0);
- dm->drawEdges(dm, 0, 1);
-#endif
+ BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
+ axis_dominant_v3_to_m3(mat, p_nor);
- /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */
- {
- DEBUG_VBO("Using legacy code. drawNavMeshColored\n");
- glBegin(glmode = GL_QUADS);
- for (a = 0; a < dm->numTessFaceData; a++, mface++) {
- int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES;
- int pi = polygonIdx[a];
- if (pi <= 0) {
- zero_v3(col);
- }
- else {
- navmesh_intToCol(pi, col);
- }
+ BLI_array_clear(vcos_2d);
+ BLI_array_reserve(vcos_2d, mp->totloop);
+ for (j = 0; j < mp->totloop; j++, l++) {
+ mul_v3_m3v3(co, mat, mv[l->v].co);
+ copy_v2_v2(vcos_2d[j], co);
- if (new_glmode != glmode) {
- glEnd();
- glBegin(glmode = new_glmode);
- }
- glColor3fv(col);
- glVertex3fv(mvert[mface->v1].co);
- glVertex3fv(mvert[mface->v2].co);
- glVertex3fv(mvert[mface->v3].co);
- if (mface->v4) {
- glVertex3fv(mvert[mface->v4].co);
+ for (k = 0; k < 2; k++) {
+ if (co[k] > max[k])
+ max[k] = co[k];
+ else if (co[k] < min[k])
+ min[k] = co[k];
+ }
}
- }
- glEnd();
- }
-}
-
-static void navmesh_DM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex UNUSED(setDrawOptions),
- DMCompareDrawOptions UNUSED(compareDrawOptions),
- void *UNUSED(userData), DMDrawFlag UNUSED(flag))
-{
- navmesh_drawColored(dm);
-}
-static void navmesh_DM_drawFacesSolid(
- DerivedMesh *dm,
- float (*partial_redraw_planes)[4],
- bool UNUSED(fast), DMSetMaterial UNUSED(setMaterial))
-{
- UNUSED_VARS(partial_redraw_planes);
+ /* Brings min to (0, 0). */
+ negate_v2_v2(translate, min);
- //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial);
- navmesh_drawColored(dm);
-}
+ /* Scale will bring max to (1, 1). */
+ sub_v2_v2v2(scale, max, min);
+ if (scale[0] == 0.0f)
+ scale[0] = 1e-9f;
+ if (scale[1] == 0.0f)
+ scale[1] = 1e-9f;
+ invert_v2(scale);
-static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
-{
- DerivedMesh *result;
- int maxFaces = dm->getNumPolys(dm);
- int *recastData;
- int vertsPerPoly = 0, nverts = 0, ndtris = 0, npolys = 0;
- float *verts = NULL;
- unsigned short *dtris = NULL, *dmeshes = NULL, *polys = NULL;
- int *dtrisToPolysMap = NULL, *dtrisToTrisMap = NULL, *trisToFacesMap = NULL;
- int res;
-
- result = CDDM_copy(dm);
- if (!CustomData_has_layer(&result->polyData, CD_RECAST)) {
- int *sourceRecastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
- if (sourceRecastData) {
- CustomData_add_layer_named(&result->polyData, CD_RECAST, CD_DUPLICATE,
- sourceRecastData, maxFaces, "recastData");
- }
- }
- recastData = (int *)CustomData_get_layer(&result->polyData, CD_RECAST);
-
- /* note: This is not good design! - really should not be doing this */
- result->drawFacesTex = navmesh_DM_drawFacesTex;
- result->drawFacesSolid = navmesh_DM_drawFacesSolid;
-
-
- /* process mesh */
- res = buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nverts, &verts, &ndtris, &dtris,
- &npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap,
- &trisToFacesMap);
- if (res) {
- size_t polyIdx;
-
- /* invalidate concave polygon */
- for (polyIdx = 0; polyIdx < (size_t)npolys; polyIdx++) {
- unsigned short *poly = &polys[polyIdx * 2 * vertsPerPoly];
- if (!polyIsConvex(poly, vertsPerPoly, verts)) {
- /* set negative polygon idx to all faces */
- unsigned short *dmesh = &dmeshes[4 * polyIdx];
- unsigned short tbase = dmesh[2];
- unsigned short tnum = dmesh[3];
- unsigned short ti;
-
- for (ti = 0; ti < tnum; ti++) {
- unsigned short triidx = dtrisToTrisMap[tbase + ti];
- unsigned short faceidx = trisToFacesMap[triidx];
- if (recastData[faceidx] > 0) {
- recastData[faceidx] = -recastData[faceidx];
- }
- }
+ /* Finally, transform all vcos_2d into ((0, 0), (1, 1)) square and assign them as origspace. */
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ add_v2_v2v2(lof->uv, vcos_2d[j], translate);
+ mul_v2_v2(lof->uv, scale);
}
}
}
- else {
- printf("Navmesh: Unable to generate valid Navmesh");
- }
- /* clean up */
- if (verts != NULL)
- MEM_freeN(verts);
- if (dtris != NULL)
- MEM_freeN(dtris);
- if (dmeshes != NULL)
- MEM_freeN(dmeshes);
- if (polys != NULL)
- MEM_freeN(polys);
- if (dtrisToPolysMap != NULL)
- MEM_freeN(dtrisToPolysMap);
- if (dtrisToTrisMap != NULL)
- MEM_freeN(dtrisToTrisMap);
- if (trisToFacesMap != NULL)
- MEM_freeN(trisToFacesMap);
-
- return result;
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ BLI_array_free(vcos_2d);
}
-#endif /* WITH_GAMEENGINE */
-
-/* --- NAVMESH (end) --- */
-
-
-void DM_init_origspace(DerivedMesh *dm)
+static void mesh_init_origspace(Mesh *mesh)
{
const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP);
- const int numpoly = dm->getNumPolys(dm);
- // const int numloop = dm->getNumLoops(dm);
- MVert *mv = dm->getVertArray(dm);
- MLoop *ml = dm->getLoopArray(dm);
- MPoly *mp = dm->getPolyArray(dm);
+ OrigSpaceLoop *lof_array = CustomData_get_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP);
+ const int numpoly = mesh->totpoly;
+ // const int numloop = mesh->totloop;
+ MVert *mv = mesh->mvert;
+ MLoop *ml = mesh->mloop;
+ MPoly *mp = mesh->mpoly;
int i, j, k;
float (*vcos_2d)[2] = NULL;
@@ -4190,12 +2628,11 @@ void DM_init_origspace(DerivedMesh *dm)
}
}
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ BKE_mesh_tessface_clear(mesh);
BLI_array_free(vcos_2d);
}
-
/* derivedmesh info printing function,
* to help track down differences DM output */
@@ -4235,7 +2672,6 @@ char *DM_debug_info(DerivedMesh *dm)
BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm);
switch (dm->type) {
case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
- case DM_TYPE_EDITBMESH: tstr = "DM_TYPE_EDITMESH"; break;
case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
default: tstr = "UNKNOWN"; break;
}
@@ -4334,84 +2770,3 @@ bool DM_is_valid(DerivedMesh *dm)
}
#endif /* NDEBUG */
-
-/* -------------------------------------------------------------------- */
-
-MVert *DM_get_vert_array(DerivedMesh *dm, bool *allocated)
-{
- CustomData *vert_data = dm->getVertDataLayout(dm);
- MVert *mvert = CustomData_get_layer(vert_data, CD_MVERT);
- *allocated = false;
-
- if (mvert == NULL) {
- mvert = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(MVert), "dmvh vert data array");
- dm->copyVertArray(dm, mvert);
- *allocated = true;
- }
-
- return mvert;
-}
-
-MEdge *DM_get_edge_array(DerivedMesh *dm, bool *allocated)
-{
- CustomData *edge_data = dm->getEdgeDataLayout(dm);
- MEdge *medge = CustomData_get_layer(edge_data, CD_MEDGE);
- *allocated = false;
-
- if (medge == NULL) {
- medge = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(MEdge), "dm medge data array");
- dm->copyEdgeArray(dm, medge);
- *allocated = true;
- }
-
- return medge;
-}
-
-MLoop *DM_get_loop_array(DerivedMesh *dm, bool *r_allocated)
-{
- CustomData *loop_data = dm->getLoopDataLayout(dm);
- MLoop *mloop = CustomData_get_layer(loop_data, CD_MLOOP);
- *r_allocated = false;
-
- if (mloop == NULL) {
- mloop = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(MLoop), "dm loop data array");
- dm->copyLoopArray(dm, mloop);
- *r_allocated = true;
- }
-
- return mloop;
-}
-
-MPoly *DM_get_poly_array(DerivedMesh *dm, bool *r_allocated)
-{
- CustomData *poly_data = dm->getPolyDataLayout(dm);
- MPoly *mpoly = CustomData_get_layer(poly_data, CD_MPOLY);
- *r_allocated = false;
-
- if (mpoly == NULL) {
- mpoly = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(MPoly), "dm poly data array");
- dm->copyPolyArray(dm, mpoly);
- *r_allocated = true;
- }
-
- return mpoly;
-}
-
-MFace *DM_get_tessface_array(DerivedMesh *dm, bool *r_allocated)
-{
- CustomData *tessface_data = dm->getTessFaceDataLayout(dm);
- MFace *mface = CustomData_get_layer(tessface_data, CD_MFACE);
- *r_allocated = false;
-
- if (mface == NULL) {
- int numTessFaces = dm->getNumTessFaces(dm);
-
- if (numTessFaces > 0) {
- mface = MEM_malloc_arrayN(numTessFaces, sizeof(MFace), "bvh mface data array");
- dm->copyTessFaceArray(dm, mface);
- *r_allocated = true;
- }
- }
-
- return mface;
-}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 7612e9a3fdb..79230ad9e94 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -55,7 +55,6 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -65,6 +64,8 @@
#include "BKE_main.h"
#include "BKE_object.h"
+#include "DEG_depsgraph_build.h"
+
#include "BIK_api.h"
#include "RNA_access.h"
@@ -425,7 +426,7 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
return NULL;
/* See if this channel exists */
- chan = BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
+ chan = BKE_pose_channel_find_name(pose, name);
if (chan) {
return chan;
}
@@ -453,7 +454,9 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */
BLI_addtail(&pose->chanbase, chan);
- BKE_pose_channels_hash_free(pose);
+ if (pose->chanhash) {
+ BLI_ghash_insert(pose->chanhash, chan->name, chan);
+ }
return chan;
}
@@ -581,12 +584,19 @@ void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const
if (copy_constraints) {
BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb
pchan->constraints = listb;
- pchan->mpath = NULL; /* motion paths should not get copied yet... */
+
+ /* XXX: This is needed for motionpath drawing to work. Dunno why it was setting to null before... */
+ pchan->mpath = animviz_copy_motionpath(pchan->mpath);
}
if (pchan->prop) {
pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag);
}
+
+ pchan->draw_data = NULL; /* Drawing cache, no need to copy. */
+
+ /* Runtime data, no need to copy. */
+ memset(&pchan->runtime, 0, sizeof(pchan->runtime));
}
/* for now, duplicate Bone Groups too when doing this */
@@ -780,6 +790,24 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
IDP_FreeProperty(pchan->prop);
MEM_freeN(pchan->prop);
}
+
+ /* Cached data, for new draw manager rendering code. */
+ MEM_SAFE_FREE(pchan->draw_data);
+
+ /* Cached B-Bone shape data. */
+ BKE_pose_channel_free_bbone_cache(pchan);
+}
+
+/** Deallocates runtime cache of a pose channel's B-Bone shape. */
+void BKE_pose_channel_free_bbone_cache(bPoseChannel *pchan)
+{
+ bPoseChannelRuntime *runtime = &pchan->runtime;
+
+ runtime->bbone_segments = 0;
+ MEM_SAFE_FREE(runtime->bbone_rest_mats);
+ MEM_SAFE_FREE(runtime->bbone_pose_mats);
+ MEM_SAFE_FREE(runtime->bbone_deform_mats);
+ MEM_SAFE_FREE(runtime->bbone_dual_quats);
}
void BKE_pose_channel_free(bPoseChannel *pchan)
@@ -849,39 +877,6 @@ void BKE_pose_free(bPose *pose)
BKE_pose_free_ex(pose, true);
}
-static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan)
-{
- bConstraint *pcon, *con;
-
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- copy_v3_v3(pchan->eul, chan->eul);
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- copy_qt_qt(pchan->quat, chan->quat);
- pchan->rotmode = chan->rotmode;
- copy_m4_m4(pchan->chan_mat, (float(*)[4])chan->chan_mat);
- copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
- pchan->flag = chan->flag;
-
- pchan->roll1 = chan->roll1;
- pchan->roll2 = chan->roll2;
- pchan->curveInX = chan->curveInX;
- pchan->curveInY = chan->curveInY;
- pchan->curveOutX = chan->curveOutX;
- pchan->curveOutY = chan->curveOutY;
- pchan->ease1 = chan->ease1;
- pchan->ease2 = chan->ease2;
- pchan->scaleIn = chan->scaleIn;
- pchan->scaleOut = chan->scaleOut;
-
- con = chan->constraints.first;
- for (pcon = pchan->constraints.first; pcon && con; pcon = pcon->next, con = con->next) {
- pcon->enforce = con->enforce;
- pcon->headtail = con->headtail;
- }
-}
-
/**
* Copy the internal members of each pose channel including constraints
* and ID-Props, used when duplicating bones in editmode.
@@ -910,7 +905,6 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->iklinweight = pchan_from->iklinweight;
/* bbone settings (typically not animated) */
- pchan->bboneflag = pchan_from->bboneflag;
pchan->bbone_next = pchan_from->bbone_next;
pchan->bbone_prev = pchan_from->bbone_prev;
@@ -1323,25 +1317,6 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
/* ************** Pose Management Tools ****************** */
-/* Copy the data from the action-pose (src) into the pose */
-/* both args are assumed to be valid */
-/* exported to game engine */
-/* Note! this assumes both poses are aligned, this isn't always true when dealing with user poses */
-void extract_pose_from_pose(bPose *pose, const bPose *src)
-{
- const bPoseChannel *schan;
- bPoseChannel *pchan = pose->chanbase.first;
-
- if (pose == src) {
- printf("extract_pose_from_pose source and target are the same\n");
- return;
- }
-
- for (schan = src->chanbase.first; (schan && pchan); schan = schan->next, pchan = pchan->next) {
- copy_pose_channel_data(pchan, schan);
- }
-}
-
/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */
void BKE_pose_rest(bPose *pose)
{
@@ -1370,6 +1345,36 @@ void BKE_pose_rest(bPose *pose)
}
}
+void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom)
+{
+ copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
+ copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
+
+ /* used for local constraints */
+ copy_v3_v3(pchanto->loc, pchanfrom->loc);
+ copy_qt_qt(pchanto->quat, pchanfrom->quat);
+ copy_v3_v3(pchanto->eul, pchanfrom->eul);
+ copy_v3_v3(pchanto->size, pchanfrom->size);
+
+ copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
+ copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
+
+ pchanto->roll1 = pchanfrom->roll1;
+ pchanto->roll2 = pchanfrom->roll2;
+ pchanto->curveInX = pchanfrom->curveInX;
+ pchanto->curveInY = pchanfrom->curveInY;
+ pchanto->curveOutX = pchanfrom->curveOutX;
+ pchanto->curveOutY = pchanfrom->curveOutY;
+ pchanto->ease1 = pchanfrom->ease1;
+ pchanto->ease2 = pchanfrom->ease2;
+ pchanto->scaleIn = pchanfrom->scaleIn;
+ pchanto->scaleOut = pchanfrom->scaleOut;
+
+ pchanto->rotmode = pchanfrom->rotmode;
+ pchanto->flag = pchanfrom->flag;
+ pchanto->protectflag = pchanfrom->protectflag;
+}
+
/* both poses should be in sync */
bool BKE_pose_copy_result(bPose *to, bPose *from)
{
@@ -1388,34 +1393,8 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) {
pchanto = BKE_pose_channel_find_name(to, pchanfrom->name);
- if (pchanto) {
- copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
- copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
-
- /* used for local constraints */
- copy_v3_v3(pchanto->loc, pchanfrom->loc);
- copy_qt_qt(pchanto->quat, pchanfrom->quat);
- copy_v3_v3(pchanto->eul, pchanfrom->eul);
- copy_v3_v3(pchanto->size, pchanfrom->size);
-
- copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
- copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
-
- pchanto->roll1 = pchanfrom->roll1;
- pchanto->roll2 = pchanfrom->roll2;
- pchanto->curveInX = pchanfrom->curveInX;
- pchanto->curveInY = pchanfrom->curveInY;
- pchanto->curveOutX = pchanfrom->curveOutX;
- pchanto->curveOutY = pchanfrom->curveOutY;
- pchanto->ease1 = pchanfrom->ease1;
- pchanto->ease2 = pchanfrom->ease2;
- pchanto->scaleIn = pchanfrom->scaleIn;
- pchanto->scaleOut = pchanfrom->scaleOut;
-
- pchanto->rotmode = pchanfrom->rotmode;
- pchanto->flag = pchanfrom->flag;
- pchanto->protectflag = pchanfrom->protectflag;
- pchanto->bboneflag = pchanfrom->bboneflag;
+ if (pchanto != NULL) {
+ BKE_pose_copyesult_pchan_result(pchanto, pchanfrom);
}
}
return true;
@@ -1428,7 +1407,7 @@ void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
/* Depsgraph components depends on actual pose state,
* if pose was changed depsgraph is to be updated as well.
*/
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
/* For the calculation of the effects of an Action at the given frame on an object
@@ -1486,7 +1465,7 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c
RNA_id_pointer_create(&workob->id, &id_ptr);
/* execute action for this group only */
- animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe);
+ animsys_evaluate_action_group(&id_ptr, act, agrp, cframe);
}
else {
AnimData adt = {NULL};
@@ -1498,6 +1477,6 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c
adt.action = act;
/* execute effects of Action on to workob (or it's PoseChannels) */
- BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(NULL, NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
}
}
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index d5f269b82a8..c3b6041243d 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -35,6 +35,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_dlrbTree.h"
#include "BLT_translation.h"
@@ -43,18 +44,29 @@
#include "DNA_key_types.h"
#include "DNA_scene_types.h"
+#include "BKE_anim.h"
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
-#include "BKE_anim.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#include "DEG_depsgraph_build.h"
+
+#include "GPU_batch.h"
+
// XXX bad level call...
+extern short compare_ak_cfraPtr(void *node, void *data);
+extern void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct DLRBT_Tree *keys, int saction_flag);
+extern void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, int saction_flag);
/* --------------------- */
/* forward declarations */
@@ -87,6 +99,8 @@ void animviz_settings_init(bAnimVizSettings *avs)
avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
avs->path_step = 1;
+
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
}
/* ------------------- */
@@ -102,6 +116,10 @@ void animviz_free_motionpath_cache(bMotionPath *mpath)
if (mpath->points)
MEM_freeN(mpath->points);
+ GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
+
/* reset the relevant parameters */
mpath->points = NULL;
mpath->length = 0;
@@ -125,6 +143,27 @@ void animviz_free_motionpath(bMotionPath *mpath)
/* ------------------- */
+/* Make a copy of motionpath data, so that viewing with copy on write works */
+bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
+{
+ bMotionPath *mpath_dst;
+
+ if (mpath_src == NULL)
+ return NULL;
+
+ mpath_dst = MEM_dupallocN(mpath_src);
+ mpath_dst->points = MEM_dupallocN(mpath_src->points);
+
+ /* should get recreated on draw... */
+ mpath_dst->points_vbo = NULL;
+ mpath_dst->batch_line = NULL;
+ mpath_dst->batch_points = NULL;
+
+ return mpath_dst;
+}
+
+/* ------------------- */
+
/**
* Setup motion paths for the given data.
* \note Only used when explicitly calculating paths on bones which may/may not be consider already
@@ -207,7 +246,7 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
mpath->color[1] = 0.0;
mpath->color[2] = 0.0;
- mpath->line_thickness = 1;
+ mpath->line_thickness = 2;
mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
/* allocate a cache */
@@ -228,8 +267,16 @@ typedef struct MPathTarget {
bMotionPath *mpath; /* motion path in question */
+ DLRBT_Tree keys; /* temp, to know where the keyframes are */
+
+ /* Original (Source Objects) */
Object *ob; /* source object */
bPoseChannel *pchan; /* source posechannel (if applicable) */
+
+ /* "Evaluated" Copies (these come from the background COW copie
+ * that provide all the coordinates we want to save off)
+ */
+ Object *ob_eval; /* evaluated object */
} MPathTarget;
/* ........ */
@@ -273,127 +320,95 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
/* ........ */
-/* Note on evaluation optimizations:
- * Optimization's currently used here play tricks with the depsgraph in order to try and
- * evaluate as few objects as strictly necessary to get nicer performance under standard
- * production conditions. For those people who really need the accurate version,
- * disable the ifdef (i.e. 1 -> 0) and comment out the call to motionpaths_calc_optimise_depsgraph()
- */
-
-/* tweak the object ordering to trick depsgraph into making MotionPath calculations run faster */
-static void motionpaths_calc_optimise_depsgraph(Main *bmain, Scene *scene, ListBase *targets)
-{
- Base *base, *baseNext;
- MPathTarget *mpt;
-
- /* make sure our temp-tag isn't already in use */
- for (base = scene->base.first; base; base = base->next)
- base->object->flag &= ~BA_TEMP_TAG;
-
- /* for each target, dump its object to the start of the list if it wasn't moved already */
- for (mpt = targets->first; mpt; mpt = mpt->next) {
- for (base = scene->base.first; base; base = baseNext) {
- baseNext = base->next;
-
- if ((base->object == mpt->ob) && !(mpt->ob->flag & BA_TEMP_TAG)) {
- BLI_remlink(&scene->base, base);
- BLI_addhead(&scene->base, base);
-
- mpt->ob->flag |= BA_TEMP_TAG;
-
- /* we really don't need to continue anymore once this happens, but this line might really 'break' */
- break;
- }
- }
- }
-
- /* "brew me a list that's sorted a bit faster now depsy" */
- DAG_scene_relations_rebuild(bmain, scene);
-}
-
/* update scene for current frame */
-static void motionpaths_calc_update_scene(Main *bmain, Scene *scene)
+static void motionpaths_calc_update_scene(Main *bmain,
+ struct Depsgraph *depsgraph)
{
-#if 1 // 'production' optimizations always on
- /* rigid body simulation needs complete update to work correctly for now */
- /* RB_TODO investigate if we could avoid updating everything */
- if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
- }
- else { /* otherwise we can optimize by restricting updates */
- Base *base, *last = NULL;
-
- /* only stuff that moves or needs display still */
- DAG_scene_update_flags(bmain, scene, scene->lay, true, false);
-
- /* find the last object with the tag
- * - all those afterwards are assumed to not be relevant for our calculations
- */
- /* optimize further by moving out... */
- for (base = scene->base.first; base; base = base->next) {
- if (base->object->flag & BA_TEMP_TAG)
- last = base;
- }
-
- /* perform updates for tagged objects */
- /* XXX: this will break if rigs depend on scene or other data that
- * is animated but not attached to/updatable from objects */
- for (base = scene->base.first; base; base = base->next) {
- /* update this object */
- BKE_object_handle_update(bmain, bmain->eval_ctx, scene, base->object);
-
- /* if this is the last one we need to update, let's stop to save some time */
- if (base == last)
- break;
- }
- }
-#else // original, 'always correct' version
- /* do all updates
- * - if this is too slow, resort to using a more efficient way
- * that doesn't force complete update, but for now, this is the
- * most accurate way!
+ /* Do all updates
+ * - if this is too slow, resort to using a more efficient way
+ * that doesn't force complete update, but for now, this is the
+ * most accurate way!
+ *
+ * TODO(segey): Bring back partial updates, which became impossible
+ * with the new depsgraph due to unsorted nature of bases.
+ *
+ * TODO(sergey): Use evaluation context dedicated to motion paths.
*/
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); /* XXX this is the best way we can get anything moving */
-#endif
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
/* ........ */
/* perform baking for the targets on the current frame */
-static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
+static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
{
MPathTarget *mpt;
/* for each target, check if it can be baked on the current frame */
for (mpt = targets->first; mpt; mpt = mpt->next) {
bMotionPath *mpath = mpt->mpath;
- bMotionPathVert *mpv;
/* current frame must be within the range the cache works for
* - is inclusive of the first frame, but not the last otherwise we get buffer overruns
*/
- if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame))
+ if ((cframe < mpath->start_frame) || (cframe >= mpath->end_frame)) {
continue;
+ }
/* get the relevant cache vert to write to */
- mpv = mpath->points + (CFRA - mpath->start_frame);
+ bMotionPathVert *mpv = mpath->points + (cframe - mpath->start_frame);
- /* pose-channel or object path baking? */
+ Object *ob_eval = mpt->ob_eval;
+
+ /* Lookup evaluated pose channel, here because the depsgraph
+ * evaluation can change them so they are not cached in mpt. */
+ bPoseChannel *pchan_eval = NULL;
if (mpt->pchan) {
+ pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, mpt->pchan->name);
+ }
+
+ /* pose-channel or object path baking? */
+ if (pchan_eval) {
/* heads or tails */
if (mpath->flag & MOTIONPATH_FLAG_BHEAD) {
- copy_v3_v3(mpv->co, mpt->pchan->pose_head);
+ copy_v3_v3(mpv->co, pchan_eval->pose_head);
}
else {
- copy_v3_v3(mpv->co, mpt->pchan->pose_tail);
+ copy_v3_v3(mpv->co, pchan_eval->pose_tail);
}
/* result must be in worldspace */
- mul_m4_v3(mpt->ob->obmat, mpv->co);
+ mul_m4_v3(ob_eval->obmat, mpv->co);
}
else {
/* worldspace object location */
- copy_v3_v3(mpv->co, mpt->ob->obmat[3]);
+ copy_v3_v3(mpv->co, ob_eval->obmat[3]);
+ }
+
+ float mframe = (float)(cframe);
+
+ /* Tag if it's a keyframe */
+ if (BLI_dlrbTree_search_exact(&mpt->keys, compare_ak_cfraPtr, &mframe)) {
+ mpv->flag |= MOTIONPATH_VERT_KEY;
+ }
+
+ /* Incremental update on evaluated object if possible, for fast updating
+ * while dragging in transform. */
+ bMotionPath *mpath_eval = NULL;
+ if (mpt->pchan) {
+ mpath_eval = (pchan_eval) ? pchan_eval->mpath : NULL;
+ }
+ else {
+ mpath_eval = ob_eval->mpath;
+ }
+
+ if (mpath_eval && mpath_eval->length == mpath->length) {
+ bMotionPathVert *mpv_eval = mpath_eval->points + (cframe - mpath_eval->start_frame);
+ *mpv_eval = *mpv;
+
+ GPU_VERTBUF_DISCARD_SAFE(mpath_eval->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_points);
}
}
}
@@ -404,50 +419,110 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
* - recalc: whether we need to
*/
/* TODO: include reports pointer? */
-void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets)
+void animviz_calc_motionpaths(Depsgraph *depsgraph,
+ Main *bmain,
+ Scene *scene,
+ ListBase *targets,
+ bool restore,
+ bool current_frame_only)
{
- MPathTarget *mpt;
- int sfra, efra;
- int cfra;
-
/* sanity check */
if (ELEM(NULL, targets, targets->first))
return;
- /* set frame values */
- cfra = CFRA;
- sfra = efra = cfra;
-
- /* TODO: this method could be improved...
+ /* Compute frame range to bake within.
+ * TODO: this method could be improved...
* 1) max range for standard baking
* 2) minimum range for recalc baking (i.e. between keyframes, but how?) */
- for (mpt = targets->first; mpt; mpt = mpt->next) {
+ int sfra = INT_MAX;
+ int efra = INT_MIN;
+
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
/* try to increase area to do (only as much as needed) */
sfra = MIN2(sfra, mpt->mpath->start_frame);
efra = MAX2(efra, mpt->mpath->end_frame);
}
- if (efra <= sfra) return;
- /* optimize the depsgraph for faster updates */
- /* TODO: whether this is used should depend on some setting for the level of optimizations used */
- motionpaths_calc_optimise_depsgraph(bmain, scene, targets);
+ if (efra <= sfra) {
+ return;
+ }
+
+ /* Limit frame range if we are updating just the current frame. */
+ /* set frame values */
+ int cfra = CFRA;
+ if (current_frame_only) {
+ if (cfra < sfra || cfra > efra) {
+ return;
+ }
+ sfra = efra = cfra;
+ }
+
+ /* get copies of objects/bones to get the calculated results from
+ * (for copy-on-write evaluation), so that we actually get some results
+ */
+ // TODO: Create a copy of background depsgraph that only contain these entities, and only evaluates them..
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob);
+
+ AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id);
+
+ /* build list of all keyframes in active action for object or pchan */
+ BLI_dlrbTree_init(&mpt->keys);
+
+ if (adt) {
+ bAnimVizSettings *avs;
+
+ /* get pointer to animviz settings for each target */
+ if (mpt->pchan)
+ avs = &mpt->ob->pose->avs;
+ else
+ avs = &mpt->ob->avs;
+
+ /* it is assumed that keyframes for bones are all grouped in a single group
+ * unless an option is set to always use the whole action
+ */
+ if ((mpt->pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) {
+ bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
+
+ if (agrp) {
+ agroup_to_keylist(adt, agrp, &mpt->keys, 0);
+ }
+ }
+ else {
+ action_to_keylist(adt, adt->action, &mpt->keys, 0);
+ }
+ }
+ }
/* calculate path over requested range */
+ printf("Calculating MotionPaths between frames %d - %d (%d frames)\n", sfra, efra, efra - sfra + 1);
for (CFRA = sfra; CFRA <= efra; CFRA++) {
- /* update relevant data for new frame */
- motionpaths_calc_update_scene(bmain, scene);
+ if (current_frame_only) {
+ /* For current frame, only update tagged. */
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+ }
+ else {
+ /* Update relevant data for new frame. */
+ motionpaths_calc_update_scene(bmain, depsgraph);
+ }
/* perform baking for targets */
- motionpaths_calc_bake_targets(scene, targets);
+ motionpaths_calc_bake_targets(targets, CFRA);
}
/* reset original environment */
+ /* NOTE: We don't always need to reevaluate the main scene, as the depsgraph
+ * may be a temporary one that works on a subset of the data. We always have
+ * to resoture the current frame though. */
CFRA = cfra;
- motionpaths_calc_update_scene(bmain, scene);
+ if (!current_frame_only && restore) {
+ motionpaths_calc_update_scene(bmain, depsgraph);
+ }
/* clear recalc flags from targets */
- for (mpt = targets->first; mpt; mpt = mpt->next) {
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
bAnimVizSettings *avs;
+ bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
if (mpt->pchan)
@@ -457,6 +532,14 @@ void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets)
/* clear the flag requesting recalculation of targets */
avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
+
+ /* Clean temp data */
+ BLI_dlrbTree_free(&mpt->keys);
+
+ /* Free previous batches to force update. */
+ GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
}
}
@@ -494,18 +577,18 @@ void calc_curvepath(Object *ob, ListBase *nurbs)
return;
}
- if (ob->curve_cache->path) free_path(ob->curve_cache->path);
- ob->curve_cache->path = NULL;
+ if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path);
+ ob->runtime.curve_cache->path = NULL;
/* weak! can only use first curve */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (bl == NULL || !bl->nr) {
return;
}
nu = nurbs->first;
- ob->curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
+ ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
/* if POLY: last vertice != first vertice */
cycl = (bl->poly != -1);
@@ -622,15 +705,15 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua
if (ob == NULL || ob->type != OB_CURVE) return 0;
cu = ob->data;
- if (ob->curve_cache == NULL || ob->curve_cache->path == NULL || ob->curve_cache->path->data == NULL) {
+ if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL || ob->runtime.curve_cache->path->data == NULL) {
printf("no path!\n");
return 0;
}
- path = ob->curve_cache->path;
+ path = ob->runtime.curve_cache->path;
pp = path->data;
/* test for cyclic */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (!bl) return 0;
if (!bl->nr) return 0;
if (bl->poly > -1) cycl = 1;
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 500ece2a735..8e8000f3ea0 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -57,27 +57,27 @@
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
-#include "BKE_nla.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
-#include "BKE_library.h"
+#include "BKE_nla.h"
#include "BKE_report.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "nla_private.h"
#include "atomic_ops.h"
-#include "DEG_depsgraph.h"
-
/* ***************************************** */
/* AnimData API */
@@ -97,6 +97,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_MA: case ID_TE: case ID_NT:
case ID_LA: case ID_CA: case ID_WO:
case ID_LS:
+ case ID_LP:
case ID_SPK:
case ID_SCE:
case ID_MC:
@@ -245,11 +246,14 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
}
/* free nla data */
- BKE_nla_tracks_free(&adt->nla_tracks);
+ BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
/* free drivers - stored as a list of F-Curves */
free_fcurves(&adt->drivers);
+ /* free driver array cache */
+ MEM_SAFE_FREE(adt->driver_array);
+
/* free overrides */
/* TODO... */
@@ -262,11 +266,18 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
/* Copying -------------------------------------------- */
-/* Make a copy of the given AnimData - to be used when copying datablocks */
-AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
+/**
+ * Make a copy of the given AnimData - to be used when copying datablocks.
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
+ * \return The copied animdata.
+ */
+AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
{
AnimData *dadt;
+ const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
+ const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+
/* sanity check before duplicating struct */
if (adt == NULL)
return NULL;
@@ -278,16 +289,17 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, 0, false);
BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, 0, false);
}
- else {
+ else if (do_id_user) {
id_us_plus((ID *)dadt->action);
id_us_plus((ID *)dadt->tmpact);
}
/* duplicate NLA data */
- BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks);
+ BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
/* duplicate drivers (F-Curves) */
copy_fcurves(&dadt->drivers, &adt->drivers);
+ dadt->driver_array = NULL;
/* don't copy overrides */
BLI_listbase_clear(&dadt->overrides);
@@ -296,19 +308,23 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
return dadt;
}
-bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const bool do_action)
+/**
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
+ * \return true is succesfully copied.
+ */
+bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
{
AnimData *adt;
if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
return false;
- BKE_animdata_free(id_to, true);
+ BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
adt = BKE_animdata_from_id(id_from);
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_animdata_copy(bmain, adt, do_action);
+ iat->adt = BKE_animdata_copy(bmain, adt, flag);
}
return true;
@@ -368,7 +384,7 @@ void BKE_animdata_merge_copy(
if (src->nla_tracks.first) {
ListBase tracks = {NULL, NULL};
- BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks);
+ BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
BLI_movelisttolist(&dst->nla_tracks, &tracks);
}
@@ -604,36 +620,8 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p
Object *ob = CTX_data_active_object(C);
if (ob && id) {
- /* only id-types which can be remapped to go through objects should be considered */
- switch (GS(id->name)) {
- case ID_TE: /* textures */
- {
- Material *ma = give_current_material(ob, ob->actcol);
- Tex *tex = give_current_material_texture(ma);
-
- /* assumes: texture will only be shown if it is active material's active texture it's ok */
- if ((ID *)tex == id) {
- char name_esc_ma[(sizeof(ma->id.name) - 2) * 2];
- char name_esc_tex[(sizeof(tex->id.name) - 2) * 2];
-
- BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma));
- BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex));
-
- /* create new path */
- // TODO: use RNA path functions to construct step by step instead?
- // FIXME: maybe this isn't even needed anymore...
- path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s",
- name_esc_ma, name_esc_tex, basepath);
-
- /* free old one */
- if (basepath != base_path)
- MEM_freeN(basepath);
- }
- break;
- }
- default:
- break;
- }
+ /* TODO: after material textures were removed, this function serves
+ * no purpose anymore, but could be used again so was not removed. */
/* fix RNA pointer, as we've now changed the ID root by changing the paths */
if (basepath != path) {
@@ -954,10 +942,11 @@ void BKE_animdata_fix_paths_rename(ID *owner_id, AnimData *adt, ID *ref_id, cons
/* Remove FCurves with Prefix -------------------------------------- */
/* Check RNA-Paths for a list of F-Curves */
-static void fcurves_path_remove_fix(const char *prefix, ListBase *curves)
+static bool fcurves_path_remove_fix(const char *prefix, ListBase *curves)
{
FCurve *fcu, *fcn;
- if (!prefix) return;
+ bool any_removed = false;
+ if (!prefix) return any_removed;
/* we need to check every curve... */
for (fcu = curves->first; fcu; fcu = fcn) {
@@ -967,58 +956,62 @@ static void fcurves_path_remove_fix(const char *prefix, ListBase *curves)
if (STRPREFIX(fcu->rna_path, prefix)) {
BLI_remlink(curves, fcu);
free_fcurve(fcu);
+ any_removed = true;
}
}
}
+ return any_removed;
}
/* Check RNA-Paths for a list of F-Curves */
-static void nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
+static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
{
NlaStrip *strip;
+ bool any_removed = false;
/* recursively check strips, fixing only actions... */
for (strip = strips->first; strip; strip = strip->next) {
/* fix strip's action */
- if (strip->act)
- fcurves_path_remove_fix(prefix, &strip->act->curves);
+ if (strip->act) {
+ any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves);
+ }
/* check sub-strips (if metas) */
- nlastrips_path_remove_fix(prefix, &strip->strips);
+ any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
}
+ return any_removed;
}
-void BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
+bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
{
/* Only some ID-blocks have this info for now, so we cast the
* types that do to be of type IdAdtTemplate
*/
- NlaTrack *nlt;
-
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- AnimData *adt = iat->adt;
-
- /* check if there's any AnimData to start with */
- if (adt) {
- /* free fcurves */
- if (adt->action)
- fcurves_path_remove_fix(prefix, &adt->action->curves);
-
- if (adt->tmpact)
- fcurves_path_remove_fix(prefix, &adt->tmpact->curves);
-
- /* free drivers - stored as a list of F-Curves */
- fcurves_path_remove_fix(prefix, &adt->drivers);
-
- /* NLA Data - Animation Data for Strips */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next)
- nlastrips_path_remove_fix(prefix, &nlt->strips);
+ if (!id_can_have_animdata(id)) {
+ return false;
+ }
+ bool any_removed = false;
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ AnimData *adt = iat->adt;
+ /* check if there's any AnimData to start with */
+ if (adt) {
+ /* free fcurves */
+ if (adt->action != NULL) {
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves);
+ }
+ if (adt->tmpact != NULL) {
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves);
+ }
+ /* free drivers - stored as a list of F-Curves */
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers);
+ /* NLA Data - Animation Data for Strips */
+ for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips);
}
}
+ return any_removed;
}
-
/* Apply Op to All FCurves in Database --------------------------- */
/* "User-Data" wrapper used by BKE_fcurves_main_cb() */
@@ -1173,6 +1166,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
/* grease pencil */
ANIMDATA_IDS_CB(bmain->gpencil.first);
+ /* palettes */
+ ANIMDATA_IDS_CB(bmain->palettes.first);
+
/* cache files */
ANIMDATA_IDS_CB(bmain->cachefiles.first);
}
@@ -1477,42 +1473,14 @@ void BKE_keyingsets_free(ListBase *list)
/* ***************************************** */
/* Evaluation Data-Setting Backend */
-/* Retrieve string to act as RNA-path, adjusted using mapping-table if provided
- * It returns whether the string needs to be freed (i.e. if it was a temp remapped one)
- * // FIXME: maybe it would be faster if we didn't have to alloc/free strings like this all the time, but for now it's safer
- *
- * - remap: remapping table to use
- * - path: original path string (as stored in F-Curve data)
- * - dst: destination string to write data to
- */
-static bool animsys_remap_path(AnimMapper *UNUSED(remap), char *path, char **dst)
-{
- /* is there a valid remapping table to use? */
-#if 0
- if (remap) {
- /* find a matching entry... to use to remap */
- /* ...TODO... */
- }
-#endif
-
- /* nothing suitable found, so just set dst to look at path (i.e. no alloc/free needed) */
- *dst = path;
- return false;
-}
-
static bool animsys_store_rna_setting(
- PointerRNA *ptr, AnimMapper *remap,
+ PointerRNA *ptr,
/* 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);
+ const char *path = rna_path;
/* write value to setting */
if (path) {
@@ -1546,11 +1514,6 @@ static bool animsys_store_rna_setting(
}
}
- /* free temp path-info */
- if (free_path) {
- MEM_freeN((void *)path);
- }
-
return success;
}
@@ -1558,6 +1521,72 @@ static bool animsys_store_rna_setting(
/* less than 1.0 evaluates to false, use epsilon to avoid float error */
#define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON)))
+static bool animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value)
+{
+ PropertyRNA *prop = anim_rna->prop;
+ PointerRNA *ptr = &anim_rna->ptr;
+ int array_index = anim_rna->prop_index;
+ float orig_value;
+
+ /* caller must ensure this is animatable */
+ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ {
+ if (array_index != -1) {
+ const int orig_value_coerce = RNA_property_boolean_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const int orig_value_coerce = RNA_property_boolean_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_INT:
+ {
+ if (array_index != -1) {
+ const int orig_value_coerce = RNA_property_int_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const int orig_value_coerce = RNA_property_int_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_FLOAT:
+ {
+ if (array_index != -1) {
+ const float orig_value_coerce = RNA_property_float_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const float orig_value_coerce = RNA_property_float_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_ENUM:
+ {
+ const int orig_value_coerce = RNA_property_enum_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ break;
+ }
+ default:
+ /* nothing can be done here... so it is unsuccessful? */
+ return false;
+ }
+
+ if (r_value != NULL) {
+ *r_value = orig_value;
+ }
+
+ /* successful */
+ return true;
+}
+
/* Write the given value to a setting using RNA, and return success */
static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value)
{
@@ -1568,27 +1597,24 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
/* 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;
+ /* Check whether value is new. Otherwise we skip all the updates. */
+ float old_value;
+ if (!animsys_read_rna_setting(anim_rna, &old_value)) {
+ return false;
+ }
+ if (old_value == value) {
+ return true;
+ }
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;
- }
+ RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_boolean_get(ptr, prop) != value_coerce) {
- RNA_property_boolean_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_boolean_set(ptr, prop, value_coerce);
}
break;
}
@@ -1597,16 +1623,10 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
int value_coerce = (int)value;
RNA_property_int_clamp(ptr, prop, &value_coerce);
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;
- }
+ RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_int_get(ptr, prop) != value_coerce) {
- RNA_property_int_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_int_set(ptr, prop, value_coerce);
}
break;
}
@@ -1615,26 +1635,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
float value_coerce = value;
RNA_property_float_clamp(ptr, prop, &value_coerce);
if (array_index != -1) {
- if (RNA_property_float_get_index(ptr, prop, array_index) != value_coerce) {
- RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
- written = true;
- }
+ RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_float_get(ptr, prop) != value_coerce) {
- RNA_property_float_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_float_set(ptr, prop, value_coerce);
}
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;
- }
+ RNA_property_enum_set(ptr, prop, value_coerce);
break;
}
default:
@@ -1642,54 +1653,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
return false;
}
- /* 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->recalc & ID_RECALC_SKIP_ANIM_TAG)) {
- /* NOTE: This is a bit annoying to use atomic API here, but this
- * code is at it's EOL and removed already in 2.8 branch.
- */
- atomic_fetch_and_or_int32(&id->recalc, ID_RECALC);
- DAG_id_type_tag(G.main, GS(id->name));
- }
- }
-
/* 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)
+bool BKE_animsys_execute_fcurve(PointerRNA *ptr, FCurve *fcu, float curval)
{
PathResolvedRNA anim_rna;
bool ok = false;
- if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
ok = animsys_write_rna_setting(&anim_rna, curval);
}
@@ -1697,24 +1671,53 @@ bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu,
return ok;
}
+static void animsys_write_orig_anim_rna(
+ PointerRNA *ptr,
+ const char *rna_path,
+ int array_index,
+ float value)
+{
+ /* Pointer is expected to be an ID pointer, if it's not -- we are doomed.
+ *
+ * NOTE: It is possible to have animation data on NLA strip, see T57360.
+ * TODO(sergey): Find solution for those cases.
+ */
+ if (ptr->id.data == NULL) {
+ return;
+ }
+ PointerRNA orig_ptr = *ptr;
+ orig_ptr.id.data = ((ID *)orig_ptr.id.data)->orig_id;
+ orig_ptr.data = orig_ptr.id.data;
+ PathResolvedRNA orig_anim_rna;
+ /* TODO(sergey): Is there a faster way to get anim_rna of original ID? */
+ if (animsys_store_rna_setting(&orig_ptr, rna_path, array_index, &orig_anim_rna)) {
+ animsys_write_rna_setting(&orig_anim_rna, value);
+ }
+}
+
/* Evaluate all the F-Curves in the given list
* This performs a set of standard checks. If extra checks are required, separate code should be used
*/
-static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper *remap, float ctime)
-{
- FCurve *fcu;
-
- /* calculate then execute each curve */
- for (fcu = list->first; fcu; fcu = fcu->next) {
- /* check if this F-Curve doesn't belong to a muted group */
- 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) {
- 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);
- }
+static void animsys_evaluate_fcurves(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *list, float ctime)
+{
+ const bool is_active_depsgraph = DEG_is_active(depsgraph);
+ /* Calculate then execute each curve. */
+ for (FCurve *fcu = list->first; fcu; fcu = fcu->next) {
+ /* Check if this F-Curve doesn't belong to a muted group. */
+ if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
+ continue;
+ }
+ /* Check if this curve should be skipped. */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) {
+ continue;
+ }
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ if (is_active_depsgraph) {
+ animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval);
}
}
}
@@ -1745,7 +1748,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
* new to only be done when drivers only changed */
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (animsys_store_rna_setting(ptr, 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);
}
@@ -1798,13 +1801,12 @@ static void action_idcode_patch_check(ID *id, bAction *act)
/* ----------------------------------------- */
/* Evaluate Action Group */
-void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, AnimMapper *remap, float ctime)
+void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, float ctime)
{
FCurve *fcu;
/* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
if (ELEM(NULL, act, agrp)) return;
- if ((remap) && (remap->target != act)) remap = NULL;
action_idcode_patch_check(ptr->id.data, act);
@@ -1817,7 +1819,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
animsys_write_rna_setting(&anim_rna, curval);
}
@@ -1826,16 +1828,21 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
}
/* Evaluate Action (F-Curve Bag) */
-void animsys_evaluate_action(PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime)
+static void animsys_evaluate_action_ex(
+ Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime)
{
/* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
if (act == NULL) return;
- if ((remap) && (remap->target != act)) remap = NULL;
action_idcode_patch_check(ptr->id.data, act);
/* calculate then execute each curve */
- animsys_evaluate_fcurves(ptr, &act->curves, remap, ctime);
+ animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, ctime);
+}
+
+void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime)
+{
+ animsys_evaluate_action_ex(depsgraph, ptr, act, ctime);
}
/* ***************************************** */
@@ -1864,7 +1871,7 @@ static float nlastrip_get_influence(NlaStrip *strip, float cframe)
}
/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
-static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
+static void nlastrip_evaluate_controls(Depsgraph *depsgraph, NlaStrip *strip, float ctime)
{
/* now strip's evaluate F-Curves for these settings (if applicable) */
if (strip->fcurves.first) {
@@ -1874,7 +1881,7 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
/* execute these settings as per normal */
- animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime);
+ animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, ctime);
}
/* analytically generate values for influence and time (if applicable)
@@ -1896,7 +1903,7 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
}
/* gets the strip active at the current time for a list of strips for evaluation purposes */
-NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime)
+NlaEvalStrip *nlastrips_ctime_get_strip(Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime)
{
NlaStrip *strip, *estrip = NULL;
NlaEvalStrip *nes;
@@ -1973,7 +1980,7 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short
* - negative influence is not supported yet... how would that be defined?
*/
/* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */
- nlastrip_evaluate_controls(estrip, ctime);
+ nlastrip_evaluate_controls(depsgraph, estrip, ctime);
if (estrip->influence <= 0.0f)
return NULL;
@@ -1992,8 +1999,8 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short
return NULL;
/* evaluate controls for the relevant extents of the bordering strips... */
- nlastrip_evaluate_controls(estrip->prev, estrip->start);
- nlastrip_evaluate_controls(estrip->next, estrip->end);
+ nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start);
+ nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end);
break;
}
@@ -2016,7 +2023,7 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short
/* find an NlaEvalChannel that matches the given criteria
* - ptr and prop are the RNA data to find a match for
*/
-static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *ptr, PropertyRNA *prop, int array_index)
+static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, const PathResolvedRNA *prna)
{
NlaEvalChannel *nec;
@@ -2031,7 +2038,7 @@ static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *pt
* other data stored in PointerRNA cannot allow us to definitively
* identify the data
*/
- if ((nec->ptr.data == ptr->data) && (nec->prop == prop) && (nec->index == array_index))
+ if ((nec->rna.ptr.data == prna->ptr.data) && (nec->rna.prop == prna->prop) && ELEM(nec->rna.prop_index, -1, prna->prop_index))
return nec;
}
@@ -2040,11 +2047,11 @@ static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *pt
}
/* initialise default value for NlaEvalChannel, so that it doesn't blend things wrong */
-static void nlaevalchan_value_init(NlaEvalChannel *nec)
+static float nlaevalchan_init_value(PathResolvedRNA *rna)
{
- PointerRNA *ptr = &nec->ptr;
- PropertyRNA *prop = nec->prop;
- int index = nec->index;
+ PointerRNA *ptr = &rna->ptr;
+ PropertyRNA *prop = rna->prop;
+ int index = rna->prop_index;
/* NOTE: while this doesn't work for all RNA properties as default values aren't in fact
* set properly for most of them, at least the common ones (which also happen to get used
@@ -2053,61 +2060,43 @@ static void nlaevalchan_value_init(NlaEvalChannel *nec)
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (RNA_property_array_check(prop))
- nec->value = (float)RNA_property_boolean_get_default_index(ptr, prop, index);
+ return (float)RNA_property_boolean_get_default_index(ptr, prop, index);
else
- nec->value = (float)RNA_property_boolean_get_default(ptr, prop);
- break;
+ return (float)RNA_property_boolean_get_default(ptr, prop);
case PROP_INT:
if (RNA_property_array_check(prop))
- nec->value = (float)RNA_property_int_get_default_index(ptr, prop, index);
+ return (float)RNA_property_int_get_default_index(ptr, prop, index);
else
- nec->value = (float)RNA_property_int_get_default(ptr, prop);
- break;
+ return (float)RNA_property_int_get_default(ptr, prop);
case PROP_FLOAT:
if (RNA_property_array_check(prop))
- nec->value = RNA_property_float_get_default_index(ptr, prop, index);
+ return RNA_property_float_get_default_index(ptr, prop, index);
else
- nec->value = RNA_property_float_get_default(ptr, prop);
- break;
+ return RNA_property_float_get_default(ptr, prop);
case PROP_ENUM:
- nec->value = (float)RNA_property_enum_get_default(ptr, prop);
- break;
+ return (float)RNA_property_enum_get_default(ptr, prop);
default:
- break;
+ return 0.0f;
}
}
/* verify that an appropriate NlaEvalChannel for this F-Curve exists */
-static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, bool *newChan)
+static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, FCurve *fcu, bool *newChan)
{
NlaEvalChannel *nec;
- NlaStrip *strip = nes->strip;
- PropertyRNA *prop;
- PointerRNA new_ptr;
- char *path = NULL;
- /* short free_path = 0; */
+ PathResolvedRNA rna;
/* sanity checks */
if (channels == NULL)
return NULL;
/* get RNA pointer+property info from F-Curve for more convenient handling */
- /* get path, remapped as appropriate to work in its new environment */
- /* free_path = */ /* UNUSED */ animsys_remap_path(strip->remap, fcu->rna_path, &path);
-
- /* a valid property must be available, and it must be animatable */
- if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop) == false) {
- if (G.debug & G_DEBUG) printf("NLA Strip Eval: Cannot resolve path\n");
- return NULL;
- }
- /* only ok if animatable */
- else if (RNA_property_animateable(&new_ptr, prop) == 0) {
- if (G.debug & G_DEBUG) printf("NLA Strip Eval: Property not animatable\n");
+ if (!animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &rna)) {
return NULL;
}
/* try to find a match */
- nec = nlaevalchan_find_match(channels, &new_ptr, prop, fcu->array_index);
+ nec = nlaevalchan_find_match(channels, &rna);
/* allocate a new struct for this if none found */
if (nec == NULL) {
@@ -2115,12 +2104,13 @@ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, N
BLI_addtail(channels, nec);
/* store property links for writing to the property later */
- nec->ptr = new_ptr;
- nec->prop = prop;
- nec->index = fcu->array_index;
+ nec->rna = rna;
+
+ /* store parameters for use with write_orig_anim_rna */
+ nec->rna_path = fcu->rna_path;
/* initialise value using default value of property [#35856] */
- nlaevalchan_value_init(nec);
+ nec->value = nlaevalchan_init_value(&rna);
*newChan = true;
}
else
@@ -2199,7 +2189,7 @@ static void nlaevalchan_buffers_accumulate(ListBase *channels, ListBase *tmp_buf
necn = nec->next;
/* try to find an existing matching channel for this setting in the accumulation buffer */
- necd = nlaevalchan_find_match(channels, &nec->ptr, nec->prop, nec->index);
+ necd = nlaevalchan_find_match(channels, &nec->rna);
/* if there was a matching channel already in the buffer, accumulate to it,
* otherwise, add the current channel to the buffer for efficiency
@@ -2326,7 +2316,7 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, ListBase *channels, Li
/* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
* stored in this channel if it has been used already
*/
- nec = nlaevalchan_verify(ptr, channels, nes, fcu, &newChan);
+ nec = nlaevalchan_verify(ptr, channels, fcu, &newChan);
if (nec)
nlaevalchan_accumulate(nec, nes, value, newChan);
}
@@ -2339,7 +2329,8 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, ListBase *channels, Li
}
/* evaluate transition strip */
-static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+static void nlastrip_evaluate_transition(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_channels = {NULL, NULL};
ListBase tmp_modifiers = {NULL, NULL};
@@ -2379,12 +2370,12 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, Li
/* first strip */
tmp_nes.strip_mode = NES_TIME_TRANSITION_START;
tmp_nes.strip = s1;
- nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
/* second strip */
tmp_nes.strip_mode = NES_TIME_TRANSITION_END;
tmp_nes.strip = s2;
- nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
/* accumulate temp-buffer and full-buffer, using the 'real' strip */
@@ -2395,7 +2386,8 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, Li
}
/* evaluate meta-strip */
-static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+static void nlastrip_evaluate_meta(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_modifiers = {NULL, NULL};
NlaStrip *strip = nes->strip;
@@ -2415,13 +2407,13 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase
/* find the child-strip to evaluate */
evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start;
- tmp_nes = nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime);
+ tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime);
/* directly evaluate child strip into accumulation buffer...
* - there's no need to use a temporary buffer (as it causes issues [T40082])
*/
if (tmp_nes) {
- nlastrip_evaluate(ptr, channels, &tmp_modifiers, tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes);
/* free temp eval-strip */
MEM_freeN(tmp_nes);
@@ -2432,7 +2424,7 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase
}
/* evaluates the given evaluation strip */
-void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+void nlastrip_evaluate(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
NlaStrip *strip = nes->strip;
@@ -2450,10 +2442,10 @@ void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers,
nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes);
break;
case NLASTRIP_TYPE_TRANSITION: /* transition */
- nlastrip_evaluate_transition(ptr, channels, modifiers, nes);
+ nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes);
break;
case NLASTRIP_TYPE_META: /* meta */
- nlastrip_evaluate_meta(ptr, channels, modifiers, nes);
+ nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes);
break;
default: /* do nothing */
@@ -2465,7 +2457,7 @@ void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers,
}
/* write the accumulated settings to */
-void nladata_flush_channels(ListBase *channels)
+void nladata_flush_channels(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels)
{
NlaEvalChannel *nec;
@@ -2473,39 +2465,13 @@ void nladata_flush_channels(ListBase *channels)
if (channels == NULL)
return;
+ const bool is_active_depsgraph = DEG_is_active(depsgraph);
+
/* for each channel with accumulated values, write its value on the property it affects */
for (nec = channels->first; nec; nec = nec->next) {
- PointerRNA *ptr = &nec->ptr;
- PropertyRNA *prop = nec->prop;
- int array_index = nec->index;
- float value = nec->value;
-
- /* write values - see animsys_write_rna_setting() to sync the code */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- if (RNA_property_array_check(prop))
- RNA_property_boolean_set_index(ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value));
- else
- RNA_property_boolean_set(ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value));
- break;
- case PROP_INT:
- if (RNA_property_array_check(prop))
- RNA_property_int_set_index(ptr, prop, array_index, (int)value);
- else
- RNA_property_int_set(ptr, prop, (int)value);
- break;
- case PROP_FLOAT:
- if (RNA_property_array_check(prop))
- RNA_property_float_set_index(ptr, prop, array_index, value);
- else
- RNA_property_float_set(ptr, prop, value);
- break;
- case PROP_ENUM:
- RNA_property_enum_set(ptr, prop, (int)value);
- break;
- default:
- /* can't do anything with other types of property.... */
- break;
+ animsys_write_rna_setting(&nec->rna, nec->value);
+ if (is_active_depsgraph) {
+ animsys_write_orig_anim_rna(ptr, nec->rna_path, nec->rna.prop_index, nec->value);
}
}
}
@@ -2519,7 +2485,7 @@ void nladata_flush_channels(ListBase *channels)
*
* \param[out] echannels Evaluation channels with calculated values
*/
-static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime)
+static void animsys_evaluate_nla(Depsgraph *depsgraph, ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime)
{
NlaTrack *nlt;
short track_index = 0;
@@ -2557,7 +2523,7 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
has_strips = true;
/* otherwise, get strip to evaluate for this channel */
- nes = nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime);
+ nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime);
if (nes) nes->track = nlt;
}
@@ -2582,7 +2548,6 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
else {
/* set settings of dummy NLA strip from AnimData settings */
dummy_strip.act = adt->action;
- dummy_strip.remap = adt->remap;
/* action range is calculated taking F-Modifiers into account (which making new strips doesn't do due to the troublesome nature of that) */
calc_action_range(dummy_strip.act, &dummy_strip.actstart, &dummy_strip.actend, 1);
@@ -2598,14 +2563,14 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
}
/* add this to our list of evaluation strips */
- nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime);
+ nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime);
}
else {
/* special case - evaluate as if there isn't any NLA data */
/* TODO: this is really just a stop-gap measure... */
if (G.debug & G_DEBUG) printf("NLA Eval: Stopgap for active action on NLA Stack - no strips case\n");
- animsys_evaluate_action(ptr, adt->action, adt->remap, ctime);
+ animsys_evaluate_action(depsgraph, ptr, adt->action, ctime);
BLI_freelistN(&estrips);
return;
}
@@ -2618,28 +2583,17 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
/* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
for (nes = estrips.first; nes; nes = nes->next)
- nlastrip_evaluate(ptr, echannels, NULL, nes);
+ nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes);
/* 3. free temporary evaluation data that's not used elsewhere */
BLI_freelistN(&estrips);
-
- /* Tag ID as updated so render engines will recognize changes in data
- * which is animated but doesn't have actions.
- */
- if (ptr->id.data != NULL) {
- ID *id = ptr->id.data;
- if (!(id->recalc & ID_RECALC_SKIP_ANIM_TAG)) {
- id->recalc |= ID_RECALC;
- DAG_id_type_tag(G.main, GS(id->name));
- }
- }
}
/* NLA Evaluation function (mostly for use through do_animdata)
* - All channels that will be affected are not cleared anymore. Instead, we just evaluate into
* some temp channels, where values can be accumulated in one go.
*/
-static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime)
+static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimData *adt, float ctime)
{
ListBase echannels = {NULL, NULL};
@@ -2647,10 +2601,10 @@ static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime)
* and also when the user jumps between different times instead of moving sequentially... */
/* evaluate the NLA stack, obtaining a set of values to flush */
- animsys_evaluate_nla(&echannels, ptr, adt, ctime);
+ animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime);
/* flush effects of accumulating channels in NLA to the actual data they affect */
- nladata_flush_channels(&echannels);
+ nladata_flush_channels(depsgraph, ptr, &echannels);
/* free temp data */
BLI_freelistN(&echannels);
@@ -2659,19 +2613,6 @@ static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime)
/* ***************************************** */
/* Overrides System - Public API */
-/* Clear all overrides */
-
-/* Add or get existing Override for given setting */
-#if 0
-AnimOverride *BKE_animsys_validate_override(PointerRNA *UNUSED(ptr), char *UNUSED(path), int UNUSED(array_index))
-{
- /* FIXME: need to define how to get overrides */
- return NULL;
-}
-#endif
-
-/* -------------------- */
-
/* Evaluate Overrides */
static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
{
@@ -2680,7 +2621,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
/* for each override, simply execute... */
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)) {
+ if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
animsys_write_rna_setting(&anim_rna, aor->value);
}
}
@@ -2726,7 +2667,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* and that the flags for which parts of the anim-data settings need to be recalculated
* have been set already by the depsgraph. Now, we use the recalc
*/
-void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
+void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
{
PointerRNA id_ptr;
@@ -2748,11 +2689,11 @@ void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ct
/* evaluate NLA-stack
* - active action is evaluated as part of the NLA stack as the last item
*/
- animsys_calculate_nla(&id_ptr, adt, ctime);
+ animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime);
}
/* evaluate Active Action only */
else if (adt->action)
- animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime);
+ animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, ctime);
/* reset tag */
adt->recalc &= ~ADT_RECALC_ANIM;
@@ -2796,7 +2737,7 @@ void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ct
* 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
* standard 'root') block are overridden by a larger 'user'
*/
-void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
+void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene *scene, float ctime)
{
ID *id;
@@ -2812,7 +2753,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
for (id = first; id; id = id->next) { \
if (ID_REAL_USERS(id) > 0) { \
AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
} \
} (void)0
@@ -2829,9 +2770,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
NtId_Type *ntp = (NtId_Type *)id; \
if (ntp->nodetree) { \
AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- BKE_animsys_evaluate_animdata(scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
} \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
} \
} (void)0
@@ -2898,6 +2839,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* grease pencil */
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
+ /* palettes */
+ EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM);
+
/* cache files */
EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
@@ -2923,27 +2867,60 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* ************** */
/* Evaluation API */
-void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id)
+void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id)
{
+ float ctime = DEG_get_ctime(depsgraph);
AnimData *adt = BKE_animdata_from_id(id);
Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
* which should get handled as part of the dependency graph instead...
*/
- DEG_debug_print_eval_time(__func__, id->name, id, eval_ctx->ctime);
- BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
+ DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime);
+ short recalc = ADT_RECALC_ANIM;
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, recalc);
+}
+
+void BKE_animsys_update_driver_array(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver.
+ * Ideally the depsgraph could pass a pointer to the COW driver directly,
+ * but this is difficult in the current design. */
+ if (adt && adt->drivers.first) {
+ BLI_assert(!adt->driver_array);
+
+ int num_drivers = BLI_listbase_count(&adt->drivers);
+ adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array");
+
+ int driver_index = 0;
+ for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ adt->driver_array[driver_index++] = fcu;
+ }
+ }
}
-void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
+void BKE_animsys_eval_driver(Depsgraph *depsgraph,
ID *id,
- FCurve *fcu)
+ int driver_index,
+ ChannelDriver *driver_orig)
{
/* TODO(sergey): De-duplicate with BKE animsys. */
- ChannelDriver *driver = fcu->driver;
PointerRNA id_ptr;
bool ok = false;
+ /* Lookup driver, accelerated with driver array map. */
+ const AnimData *adt = BKE_animdata_from_id(id);
+ FCurve *fcu;
+
+ if (adt->driver_array) {
+ fcu = adt->driver_array[driver_index];
+ }
+ else {
+ fcu = BLI_findlink(&adt->drivers, driver_index);
+ }
+
DEG_debug_print_eval_subdata_index(
- __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
+ depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
RNA_id_pointer_create(id, &id_ptr);
@@ -2951,27 +2928,31 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
/* check if driver itself is tagged for recalculation */
/* XXX driver recalc flag is not set yet by depsgraph! */
- if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) {
+ if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID) /*&& (driver_orig->flag & DRIVER_FLAG_RECALC)*/) {
/* 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 */
//printf("\told val = %f\n", 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);
+ if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float ctime = DEG_get_ctime(depsgraph);
+ const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime);
ok = animsys_write_rna_setting(&anim_rna, curval);
+ if (ok && DEG_is_active(depsgraph)) {
+ animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval);
+ }
}
//printf("\tnew val = %f\n", fcu->curval);
/* clear recalc flag */
- driver->flag &= ~DRIVER_FLAG_RECALC;
+ driver_orig->flag &= ~DRIVER_FLAG_RECALC;
/* set error-flag if evaluation failed */
if (ok == 0) {
printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index);
- driver->flag |= DRIVER_FLAG_INVALID;
+ driver_orig->flag |= DRIVER_FLAG_INVALID;
}
}
}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 8d6c34222d7..2848c245553 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -28,9 +28,11 @@
#include <stdio.h>
#include "BLI_utildefines.h"
-#include "BLI_string.h"
#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_listbase.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
#include "BKE_blender_version.h"
#include "BKE_appdir.h" /* own include */
@@ -738,6 +740,32 @@ bool BKE_appdir_app_template_id_search(const char *app_template, char *path, siz
return false;
}
+void BKE_appdir_app_templates(ListBase *templates)
+{
+ BLI_listbase_clear(templates);
+
+ for (int i = 0; i < 2; i++) {
+ char subdir[FILE_MAX];
+ if (!BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], app_template_directory_search[i],
+ subdir, sizeof(subdir)))
+ {
+ continue;
+ }
+
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(subdir, &dir);
+ for (int f = 0; f < totfile; f++) {
+ if (!FILENAME_IS_CURRPAR(dir[f].relname) && S_ISDIR(dir[f].type)) {
+ char *template = BLI_strdup(dir[f].relname);
+ BLI_addtail(templates, BLI_genericNodeN(template));
+ }
+ }
+
+ BLI_filelist_free(dir, totfile);
+ }
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
@@ -813,7 +841,9 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
BLI_dir_create_recursive(tmp_name);
}
#else
- mkdtemp(tmp_name);
+ if (mkdtemp(tmp_name) == NULL) {
+ BLI_dir_create_recursive(tmp_name);
+ }
#endif
}
if (BLI_is_dir(tmp_name)) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 4ad9e9c8205..9abd20679d8 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -27,7 +27,6 @@
* \ingroup bke
*/
-
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
@@ -47,6 +46,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
#include "DNA_lattice_types.h"
#include "DNA_listBase.h"
@@ -60,8 +60,6 @@
#include "BKE_anim.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_idprop.h"
@@ -73,8 +71,11 @@
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph_build.h"
+
#include "BIK_api.h"
-#include "BKE_sketch.h"
+
+#include "atomic_ops.h"
/* **************** Generic Functions, data level *************** */
@@ -136,12 +137,6 @@ void BKE_armature_free(bArmature *arm)
MEM_freeN(arm->edbo);
arm->edbo = NULL;
}
-
- /* free sketch */
- if (arm->sketch) {
- freeSketch(arm->sketch);
- arm->sketch = NULL;
- }
}
void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local)
@@ -205,7 +200,6 @@ void BKE_armature_copy_data(Main *UNUSED(bmain), bArmature *arm_dst, const bArma
arm_dst->edbo = NULL;
arm_dst->act_edbone = NULL;
- arm_dst->sketch = NULL;
}
bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm)
@@ -401,7 +395,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a
/* ************* B-Bone support ******************* */
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
-void equalize_bbone_bezier(float *data, int desired)
+static void equalize_bbone_bezier(float *data, int desired)
{
float *fp, totdist, ddist, dist, fac1, fac2;
float pdist[MAX_BBONE_SUBDIV + 1];
@@ -441,182 +435,284 @@ void equalize_bbone_bezier(float *data, int desired)
copy_qt_qt(fp, temp[MAX_BBONE_SUBDIV]);
}
-/* returns pointer to static array, filled with desired amount of bone->segments elements */
-/* this calculation is done within unit bone space */
-void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV])
+/* Get "next" and "prev" bones - these are used for handle calculations. */
+void BKE_pchan_get_bbone_handles(bPoseChannel *pchan, bPoseChannel **r_prev, bPoseChannel **r_next)
+{
+ if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO) {
+ /* Use connected parent. */
+ if (pchan->bone->flag & BONE_CONNECTED) {
+ *r_prev = pchan->parent;
+ }
+ else {
+ *r_prev = NULL;
+ }
+ }
+ else {
+ /* Use the provided bone as prev - leave blank to eliminate this effect altogether. */
+ *r_prev = pchan->bbone_prev;
+ }
+
+ if (pchan->bone->bbone_next_type == BBONE_HANDLE_AUTO) {
+ /* Use connected child. */
+ *r_next = pchan->child;
+ }
+ else {
+ /* Use the provided bone as next - leave blank to eliminate this effect altogether. */
+ *r_next = pchan->bbone_next;
+ }
+}
+
+/* Compute B-Bone spline parameters for the given channel. */
+void BKE_pchan_get_bbone_spline_parameters(struct bPoseChannel *pchan, const bool rest, struct BBoneSplineParameters *param)
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2;
- float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
- float data[MAX_BBONE_SUBDIV + 1][4], *fp;
- int a;
- bool do_scale = false;
+ float imat[4][4], posemat[4][4];
+ float delta[3];
+
+ memset(param, 0, sizeof(*param));
- length = bone->length;
+ param->segments = bone->segments;
+ param->length = bone->length;
if (!rest) {
- /* check if we need to take non-uniform bone scaling into account */
+ float scale[3];
+
+ /* Check if we need to take non-uniform bone scaling into account. */
mat4_to_size(scale, pchan->pose_mat);
if (fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) {
- size_to_mat4(scalemat, scale);
- invert_m4_m4(iscalemat, scalemat);
-
- length *= scale[1];
- do_scale = 1;
+ param->do_scale = true;
+ copy_v3_v3(param->scale, scale);
}
}
- /* get "next" and "prev" bones - these are used for handle calculations */
- if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) {
- /* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */
- prev = pchan->bbone_prev;
- next = pchan->bbone_next;
- }
- else {
- /* evaluate next and prev bones */
- if (bone->flag & BONE_CONNECTED)
- prev = pchan->parent;
- else
- prev = NULL;
-
- next = pchan->child;
- }
+ BKE_pchan_get_bbone_handles(pchan, &prev, &next);
- /* find the handle points, since this is inside bone space, the
+ /* Find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
* last point = (0, length, 0) */
if (rest) {
invert_m4_m4(imat, pchan->bone->arm_mat);
}
- else if (do_scale) {
+ else if (param->do_scale) {
copy_m4_m4(posemat, pchan->pose_mat);
normalize_m4(posemat);
invert_m4_m4(imat, posemat);
}
- else
+ else {
invert_m4_m4(imat, pchan->pose_mat);
+ }
if (prev) {
- float difmat[4][4], result[3][3], imat3[3][3];
+ float h1[3];
+ bool done = false;
- /* transform previous point inside this bone space */
- if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
- (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL))
- {
- /* Use delta movement (from restpose), and apply this relative to the current bone's head */
+ param->use_prev = true;
+
+ /* Transform previous point inside this bone space. */
+ if (bone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's head. */
if (rest) {
- /* in restpose, arm_head == pose_head */
- h1[0] = h1[1] = h1[2] = 0.0f;
+ /* In restpose, arm_head == pose_head */
+ zero_v3(param->prev_h);
+ done = true;
}
else {
- float delta[3];
sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
sub_v3_v3v3(h1, pchan->pose_head, delta);
}
}
- else {
- /* Use bone head as absolute position */
- if (rest)
- copy_v3_v3(h1, prev->bone->arm_head);
- else
- copy_v3_v3(h1, prev->pose_head);
+ else if (bone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
+ /* Use bone direction by offsetting so that its tail meets current bone's head */
+ if (rest) {
+ sub_v3_v3v3(delta, prev->bone->arm_tail, prev->bone->arm_head);
+ sub_v3_v3v3(h1, bone->arm_head, delta);
+ }
+ else {
+ sub_v3_v3v3(delta, prev->pose_tail, prev->pose_head);
+ sub_v3_v3v3(h1, pchan->pose_head, delta);
+ }
}
- mul_m4_v3(imat, h1);
+ else {
+ /* Apply special handling for smoothly joining B-Bone chains */
+ param->prev_bbone = (prev->bone->segments > 1);
- if (prev->bone->segments > 1) {
- /* if previous bone is B-bone too, use average handle direction */
- h1[1] -= length;
- roll1 = 0.0f;
+ /* Use bone head as absolute position. */
+ copy_v3_v3(h1, rest ? prev->bone->arm_head : prev->pose_head);
}
- normalize_v3(h1);
- negate_v3(h1);
-
- if (prev->bone->segments == 1) {
- /* find the previous roll to interpolate */
- if (rest)
- mul_m4_m4m4(difmat, imat, prev->bone->arm_mat);
- else
- mul_m4_m4m4(difmat, imat, prev->pose_mat);
- copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */
-
- vec_roll_to_mat3(h1, 0.0f, mat3); /* the result of vec_roll without roll */
-
- invert_m3_m3(imat3, mat3);
- mul_m3_m3m3(mat3, result, imat3); /* the matrix transforming vec_roll to desired roll */
+ if (!done) {
+ mul_v3_m4v3(param->prev_h, imat, h1);
+ }
- roll1 = atan2f(mat3[2][0], mat3[2][2]);
+ if (!param->prev_bbone) {
+ /* Find the previous roll to interpolate. */
+ mul_m4_m4m4(param->prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat);
}
}
- else {
- h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
- roll1 = 0.0f;
- }
+
if (next) {
- float difmat[4][4], result[3][3], imat3[3][3];
+ float h2[3];
+ bool done = false;
- /* transform next point inside this bone space */
- if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
- (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL))
- {
- /* Use delta movement (from restpose), and apply this relative to the current bone's tail */
+ param->use_next = true;
+
+ /* Transform next point inside this bone space. */
+ if (bone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's tail. */
if (rest) {
- /* in restpose, arm_tail == pose_tail */
- h2[0] = h2[1] = h2[2] = 0.0f;
+ /* In restpose, arm_head == pose_head */
+ copy_v3_fl3(param->next_h, 0.0f, param->length, 0.0);
+ done = true;
}
else {
- float delta[3];
- sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
+ sub_v3_v3v3(delta, next->pose_head, next->bone->arm_head);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else if (bone->bbone_next_type == BBONE_HANDLE_TANGENT) {
+ /* Use bone direction by offsetting so that its head meets current bone's tail */
+ if (rest) {
+ sub_v3_v3v3(delta, next->bone->arm_tail, next->bone->arm_head);
+ add_v3_v3v3(h2, bone->arm_tail, delta);
+ }
+ else {
+ sub_v3_v3v3(delta, next->pose_tail, next->pose_head);
add_v3_v3v3(h2, pchan->pose_tail, delta);
}
}
else {
- /* Use bone tail as absolute position */
- if (rest)
- copy_v3_v3(h2, next->bone->arm_tail);
- else
- copy_v3_v3(h2, next->pose_tail);
+ /* Apply special handling for smoothly joining B-Bone chains */
+ param->next_bbone = (next->bone->segments > 1);
+
+ /* Use bone tail as absolute position. */
+ copy_v3_v3(h2, rest ? next->bone->arm_tail : next->pose_tail);
}
- mul_m4_v3(imat, h2);
- /* if next bone is B-bone too, use average handle direction */
- if (next->bone->segments > 1) {
- /* pass */
+ if (!done) {
+ mul_v3_m4v3(param->next_h, imat, h2);
}
- else {
- h2[1] -= length;
+
+ /* Find the next roll to interpolate as well. */
+ mul_m4_m4m4(param->next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat);
+ }
+
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ {
+ param->ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f);
+ param->ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f);
+
+ param->roll1 = bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
+ param->roll2 = bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
+
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (prev) {
+ if (prev->bone) {
+ param->roll1 += prev->bone->roll2;
+ }
+
+ if (!rest) {
+ param->roll1 += prev->roll2;
+ }
+ }
}
- normalize_v3(h2);
- /* find the next roll to interpolate as well */
- if (rest)
- mul_m4_m4m4(difmat, imat, next->bone->arm_mat);
- else
- mul_m4_m4m4(difmat, imat, next->pose_mat);
- copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */
+ param->scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ param->scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+
+ /* Extra curve x / y */
+ param->curveInX = bone->curveInX + (!rest ? pchan->curveInX : 0.0f);
+ param->curveInY = bone->curveInY + (!rest ? pchan->curveInY : 0.0f);
+
+ param->curveOutX = bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f);
+ param->curveOutY = bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f);
+ }
+}
+
+/* Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space. */
+void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV])
+{
+ BBoneSplineParameters param;
+
+ BKE_pchan_get_bbone_spline_parameters(pchan, rest, &param);
+
+ pchan->bone->segments = BKE_compute_b_bone_spline(&param, result_array);
+}
+
+/* Computes the bezier handle vectors and rolls coming from custom handles. */
+void BKE_compute_b_bone_handles(const BBoneSplineParameters *param, float h1[3], float *r_roll1, float h2[3], float *r_roll2, bool ease, bool offsets)
+{
+ float mat3[3][3];
+ float length = param->length;
- vec_roll_to_mat3(h2, 0.0f, mat3); /* the result of vec_roll without roll */
+ if (param->do_scale) {
+ length *= param->scale[1];
+ }
- invert_m3_m3(imat3, mat3);
- mul_m3_m3m3(mat3, imat3, result); /* the matrix transforming vec_roll to desired roll */
+ *r_roll1 = *r_roll2 = 0.0f;
- roll2 = atan2f(mat3[2][0], mat3[2][2]);
+ if (param->use_prev) {
+ copy_v3_v3(h1, param->prev_h);
+ if (param->prev_bbone) {
+ /* If previous bone is B-bone too, use average handle direction. */
+ h1[1] -= length;
+ }
+
+ normalize_v3(h1);
+ negate_v3(h1);
+
+ if (!param->prev_bbone) {
+ /* Find the previous roll to interpolate. */
+ copy_m3_m4(mat3, param->prev_mat);
+ mat3_vec_to_roll(mat3, h1, r_roll1);
+ }
+ }
+ else {
+ h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
+ }
+
+ if (param->use_next) {
+ copy_v3_v3(h2, param->next_h);
+
+ /* If next bone is B-bone too, use average handle direction. */
+ if (param->next_bbone) {
+ /* pass */
+ }
+ else {
+ h2[1] -= length;
+ }
+
+ normalize_v3(h2);
+
+ /* Find the next roll to interpolate as well. */
+ copy_m3_m4(mat3, param->next_mat);
+ mat3_vec_to_roll(mat3, h2, r_roll2);
}
else {
h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
- roll2 = 0.0;
}
- {
+ if (ease) {
const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
- const float combined_ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f);
- const float combined_ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f);
- const float hlength1 = combined_ease1 * circle_factor;
- const float hlength2 = combined_ease2 * circle_factor;
+ const float hlength1 = param->ease1 * circle_factor;
+ const float hlength2 = param->ease2 * circle_factor;
/* and only now negate h2 */
mul_v3_fl(h1, hlength1);
@@ -637,68 +733,78 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
* - The "pchan" level offsets are the ones that animators actually
* end up animating
*/
- {
- /* add extra rolls */
- roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
- roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
-
- if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
- if (prev) {
- if (prev->bone)
- roll1 += prev->bone->roll2;
+ if (offsets) {
+ /* Add extra rolls. */
+ *r_roll1 += param->roll1;
+ *r_roll2 += param->roll2;
- if (!rest)
- roll1 += prev->roll2;
- }
- }
-
- /* extra curve x / y */
+ /* Extra curve x / y */
/* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
* when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
* in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
*/
- const float xscale_correction = (do_scale) ? scale[0] : 1.0f;
- const float yscale_correction = (do_scale) ? scale[2] : 1.0f;
+ const float xscale_correction = (param->do_scale) ? param->scale[0] : 1.0f;
+ const float yscale_correction = (param->do_scale) ? param->scale[2] : 1.0f;
+
+ h1[0] += param->curveInX * xscale_correction;
+ h1[2] += param->curveInY * yscale_correction;
+
+ h2[0] += param->curveOutX * xscale_correction;
+ h2[2] += param->curveOutY * yscale_correction;
+ }
+}
+
+/* Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space. */
+int BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV])
+{
+ float scalemat[4][4], iscalemat[4][4];
+ float mat3[3][3];
+ float h1[3], roll1, h2[3], roll2;
+ float data[MAX_BBONE_SUBDIV + 1][4], *fp;
+ float length = param->length;
+ int a;
- h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction;
- h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction;
+ if (param->do_scale) {
+ size_to_mat4(scalemat, param->scale);
+ invert_m4_m4(iscalemat, scalemat);
- h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction;
- h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction;
+ length *= param->scale[1];
}
- /* make curve */
- if (bone->segments > MAX_BBONE_SUBDIV)
- bone->segments = MAX_BBONE_SUBDIV;
+ BKE_compute_b_bone_handles(param, h1, &roll1, h2, &roll2, true, true);
+
+ /* Make curve. */
+ CLAMP_MAX(param->segments, MAX_BBONE_SUBDIV);
BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */
+ equalize_bbone_bezier(data[0], param->segments); /* note: does stride 4! */
- /* make transformation matrices for the segments for drawing */
- for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
+ /* Make transformation matrices for the segments for drawing. */
+ for (a = 0, fp = data[0]; a < param->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
- if (do_scale) {
- /* correct for scaling when this matrix is used in scaled space */
+ if (param->do_scale) {
+ /* Correct for scaling when this matrix is used in scaled space. */
mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
/* BBone scale... */
{
- const int num_segments = bone->segments;
+ const int num_segments = param->segments;
- const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ const float scaleIn = param->scaleIn;
const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
- const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+ const float scaleOut = param->scaleOut;
const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
const float scalefac = scaleFactorIn * scaleFactorOut;
@@ -714,8 +820,9 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
/*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/
mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
}
-
}
+
+ return param->segments;
}
/* ************ Armature Deform ******************* */
@@ -726,26 +833,53 @@ typedef struct bPoseChanDeform {
DualQuat *b_bone_dual_quats;
} bPoseChanDeform;
-static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info, const bool use_quaternion)
+/* Definition of cached object bbone deformations. */
+typedef struct ObjectBBoneDeform {
+ DualQuat *dualquats;
+ bPoseChanDeform *pdef_info_array;
+ int num_pchan;
+} ObjectBBoneDeform;
+
+static void allocate_bbone_cache(bPoseChannel *pchan, int segments)
{
+ bPoseChannelRuntime *runtime = &pchan->runtime;
+
+ if (runtime->bbone_segments != segments) {
+ if (runtime->bbone_segments != 0) {
+ BKE_pose_channel_free_bbone_cache(pchan);
+ }
+
+ runtime->bbone_segments = segments;
+ runtime->bbone_rest_mats = MEM_malloc_arrayN(sizeof(Mat4), (uint)segments, "bPoseChannelRuntime::bbone_rest_mats");
+ runtime->bbone_pose_mats = MEM_malloc_arrayN(sizeof(Mat4), (uint)segments, "bPoseChannelRuntime::bbone_pose_mats");
+ runtime->bbone_deform_mats = MEM_malloc_arrayN(sizeof(Mat4), 1 + (uint)segments, "bPoseChannelRuntime::bbone_deform_mats");
+ runtime->bbone_dual_quats = MEM_malloc_arrayN(sizeof(DualQuat), (uint)segments, "bPoseChannelRuntime::bbone_dual_quats");
+ }
+}
+
+/** Compute and cache the B-Bone shape in the channel runtime struct. */
+void BKE_pchan_cache_bbone_segments(bPoseChannel *pchan)
+{
+ bPoseChannelRuntime *runtime = &pchan->runtime;
Bone *bone = pchan->bone;
- Mat4 b_bone[MAX_BBONE_SUBDIV], b_bone_rest[MAX_BBONE_SUBDIV];
- Mat4 *b_bone_mats;
- DualQuat *b_bone_dual_quats = NULL;
- int a;
+ int segments = bone->segments;
- b_bone_spline_setup(pchan, 0, b_bone);
- b_bone_spline_setup(pchan, 1, b_bone_rest);
+ BLI_assert(segments > 1);
- /* allocate b_bone matrices and dual quats */
- b_bone_mats = MEM_mallocN((1 + bone->segments) * sizeof(Mat4), "BBone defmats");
- pdef_info->b_bone_mats = b_bone_mats;
+ /* Allocate the cache if needed. */
+ allocate_bbone_cache(pchan, segments);
- if (use_quaternion) {
- b_bone_dual_quats = MEM_mallocN((bone->segments) * sizeof(DualQuat), "BBone dqs");
- pdef_info->b_bone_dual_quats = b_bone_dual_quats;
- }
+ /* Compute the shape. */
+ Mat4 *b_bone = runtime->bbone_pose_mats;
+ Mat4 *b_bone_rest = runtime->bbone_rest_mats;
+ Mat4 *b_bone_mats = runtime->bbone_deform_mats;
+ DualQuat *b_bone_dual_quats = runtime->bbone_dual_quats;
+ int a;
+
+ b_bone_spline_setup(pchan, false, b_bone);
+ b_bone_spline_setup(pchan, true, b_bone_rest);
+ /* Compute deform matrices. */
/* first matrix is the inverse arm_mat, to bring points in local bone space
* for finding out which segment it belongs to */
invert_m4_m4(b_bone_mats[0].mat, bone->arm_mat);
@@ -762,15 +896,34 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info
invert_m4_m4(tmat, b_bone_rest[a].mat);
mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat);
- if (use_quaternion)
- mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat);
+ mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat);
+ }
+}
+
+/** Copy cached B-Bone segments from one channel to another */
+void BKE_pchan_copy_bbone_segments_cache(bPoseChannel *pchan, bPoseChannel *pchan_from)
+{
+ bPoseChannelRuntime *runtime = &pchan->runtime;
+ bPoseChannelRuntime *runtime_from = &pchan_from->runtime;
+ int segments = runtime_from->bbone_segments;
+
+ if (segments <= 1) {
+ BKE_pose_channel_free_bbone_cache(pchan);
+ }
+ else {
+ allocate_bbone_cache(pchan, segments);
+
+ memcpy(runtime->bbone_rest_mats, runtime_from->bbone_rest_mats, sizeof(Mat4) * segments);
+ memcpy(runtime->bbone_pose_mats, runtime_from->bbone_pose_mats, sizeof(Mat4) * segments);
+ memcpy(runtime->bbone_deform_mats, runtime_from->bbone_deform_mats, sizeof(Mat4) * (1 + segments));
+ memcpy(runtime->bbone_dual_quats, runtime_from->bbone_dual_quats, sizeof(DualQuat) * segments);
}
}
-static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float co[3], DualQuat *dq, float defmat[3][3])
+static void b_bone_deform(const bPoseChanDeform *pdef_info, Bone *bone, float co[3], DualQuat *dq, float defmat[3][3])
{
- Mat4 *b_bone = pdef_info->b_bone_mats;
- float (*mat)[4] = b_bone[0].mat;
+ const Mat4 *b_bone = pdef_info->b_bone_mats;
+ const float (*mat)[4] = b_bone[0].mat;
float segment, y;
int a;
@@ -862,7 +1015,7 @@ static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonem
add_m3_m3m3(mat, mat, wmat);
}
-static float dist_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, float vec[3], DualQuat *dq,
+static float dist_bone_deform(bPoseChannel *pchan, const bPoseChanDeform *pdef_info, float vec[3], DualQuat *dq,
float mat[3][3], const float co[3])
{
Bone *bone = pchan->bone;
@@ -882,7 +1035,7 @@ static float dist_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, f
contrib = fac;
if (contrib > 0.0f) {
if (vec) {
- if (bone->segments > 1)
+ if (bone->segments > 1 && pdef_info->b_bone_mats != NULL)
/* applies on cop and bbonemat */
b_bone_deform(pdef_info, bone, cop, NULL, (mat) ? bbonemat : NULL);
else
@@ -896,7 +1049,7 @@ static float dist_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, f
pchan_deform_mat_add(pchan, fac, bbonemat, mat);
}
else {
- if (bone->segments > 1) {
+ if (bone->segments > 1 && pdef_info->b_bone_mats != NULL) {
b_bone_deform(pdef_info, bone, cop, &bbonedq, NULL);
add_weighted_dq_dq(dq, &bbonedq, fac);
}
@@ -909,7 +1062,8 @@ static float dist_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, f
return contrib;
}
-static void pchan_bone_deform(bPoseChannel *pchan, bPoseChanDeform *pdef_info, float weight, float vec[3], DualQuat *dq,
+static void pchan_bone_deform(bPoseChannel *pchan, const bPoseChanDeform *pdef_info,
+ float weight, float vec[3], DualQuat *dq,
float mat[3][3], const float co[3], float *contrib)
{
float cop[3], bbonemat[3][3];
@@ -962,7 +1116,10 @@ static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index)
const bool use_quaternion = data->use_quaternion;
if (pchan->bone->segments > 1) {
- pchan_b_bone_defmats(pchan, pdef_info, use_quaternion);
+ BLI_assert(pchan->runtime.bbone_segments == pchan->bone->segments);
+
+ pdef_info->b_bone_mats = pchan->runtime.bbone_deform_mats;
+ pdef_info->b_bone_dual_quats = pchan->runtime.bbone_dual_quats;
}
if (use_quaternion) {
@@ -972,18 +1129,17 @@ static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index)
}
}
-void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
- float (*defMats)[3][3], int numVerts, int deformflag,
- float (*prevCos)[3], const char *defgrp_name)
+void armature_deform_verts(
+ Object *armOb, Object *target, const Mesh *mesh, float (*vertexCos)[3],
+ float (*defMats)[3][3], int numVerts, int deformflag,
+ float (*prevCos)[3], const char *defgrp_name, bGPDstroke *gps)
{
- bPoseChanDeform *pdef_info_array;
- bPoseChanDeform *pdef_info = NULL;
+ const bPoseChanDeform *pdef_info = NULL;
bArmature *arm = armOb->data;
bPoseChannel *pchan, **defnrToPC = NULL;
int *defnrToPCIndex = NULL;
MDeformVert *dverts = NULL;
bDeformGroup *dg;
- DualQuat *dualquats = NULL;
float obinv[4][4], premat[4][4], postmat[4][4];
const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0;
const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0;
@@ -992,7 +1148,6 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
int i, target_totvert = 0; /* safety for vertexgroup overflow */
bool use_dverts = false;
int armature_def_nr;
- int totchan;
/* in editmode, or not an armature */
if (arm->edbo || (armOb->pose == NULL)) {
@@ -1000,7 +1155,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
}
if ((armOb->pose->flag & POSE_RECALC) != 0) {
- printf("ERROR! Trying to evaluate influence of armature '%s' which needs Pose recalc!", armOb->id.name);
+ printf("ERROR! Trying to evaluate influence of armature '%s' which needs Pose recalc!\n", armOb->id.name);
BLI_assert(0);
}
@@ -1009,26 +1164,25 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
mul_m4_m4m4(postmat, obinv, armOb->obmat);
invert_m4_m4(premat, postmat);
- /* bone defmats are already in the channels, chan_mat */
-
- /* initialize B_bone matrices and dual quaternions */
- totchan = BLI_listbase_count(&armOb->pose->chanbase);
-
- if (use_quaternion) {
- dualquats = MEM_callocN(sizeof(DualQuat) * totchan, "dualquats");
+ /* Use pre-calculated bbone deformation.
+ *
+ * TODO(sergey): Make this code robust somehow when there are dependency
+ * cycles involved. */
+ ObjectBBoneDeform * bbone_deform =
+ BKE_armature_cached_bbone_deformation_get(armOb);
+ if (bbone_deform == NULL || bbone_deform->pdef_info_array == NULL) {
+ fprintf(stderr,
+ "Armature does not have bbone cache %s, "
+ "usually happens due to a dependency cycle.\n",
+ armOb->id.name + 2);
+ return;
}
-
- pdef_info_array = MEM_callocN(sizeof(bPoseChanDeform) * totchan, "bPoseChanDeform");
-
- ArmatureBBoneDefmatsData data = {
- .pdef_info_array = pdef_info_array, .dualquats = dualquats, .use_quaternion = use_quaternion
- };
- BLI_task_parallel_listbase(&armOb->pose->chanbase, &data, armature_bbone_defmats_cb, totchan > 512);
+ const bPoseChanDeform *pdef_info_array = bbone_deform->pdef_info_array;
/* get the def_nr for the overall armature vertex group if present */
armature_def_nr = defgroup_name_index(target, defgrp_name);
- if (ELEM(target->type, OB_MESH, OB_LATTICE)) {
+ if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
defbase_tot = BLI_listbase_count(&target->defbase);
if (target->type == OB_MESH) {
@@ -1037,20 +1191,25 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
if (dverts)
target_totvert = me->totvert;
}
- else {
+ else if (target->type == OB_LATTICE) {
Lattice *lt = target->data;
dverts = lt->dvert;
if (dverts)
target_totvert = lt->pntsu * lt->pntsv * lt->pntsw;
}
+ else if (target->type == OB_GPENCIL) {
+ dverts = gps->dvert;
+ if (dverts)
+ target_totvert = gps->totpoints;
+ }
}
/* get a vertex-deform-index to posechannel array */
if (deformflag & ARM_DEF_VGROUP) {
- if (ELEM(target->type, OB_MESH, OB_LATTICE)) {
- /* if we have a DerivedMesh, only use dverts if it has them */
- if (dm) {
- use_dverts = (dm->getVertDataArray(dm, CD_MDEFORMVERT) != NULL);
+ if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ /* if we have a Mesh, only use dverts if it has them */
+ if (mesh) {
+ use_dverts = (mesh->dvert != NULL);
}
else if (dverts) {
use_dverts = true;
@@ -1112,8 +1271,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
}
if (use_dverts || armature_def_nr != -1) {
- if (dm)
- dvert = dm->getVertData(dm, i, CD_MDEFORMVERT);
+ if (mesh) {
+ BLI_assert(i < mesh->totvert);
+ dvert = mesh->dvert + i;
+ }
else if (dverts && i < target_totvert)
dvert = dverts + i;
else
@@ -1149,7 +1310,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
MDeformWeight *dw = dvert->dw;
int deformed = 0;
unsigned int j;
-
+ float acum_weight = 0;
for (j = dvert->totweight; j != 0; j--, dw++) {
const int index = dw->def_nr;
if (index >= 0 && index < defbase_tot && (pchan = defnrToPC[index])) {
@@ -1163,7 +1324,21 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail,
bone->rad_head, bone->rad_tail, bone->dist);
}
+
+ /* check limit of weight */
+ if (target->type == OB_GPENCIL) {
+ if (acum_weight + weight >= 1.0f) {
+ weight = 1.0f - acum_weight;
+ }
+ acum_weight += weight;
+ }
+
pchan_bone_deform(pchan, pdef_info, weight, vec, dq, smat, co, &contrib);
+
+ /* if acumulated weight limit exceed, exit loop */
+ if ((target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) {
+ break;
+ }
}
}
/* if there are vertexgroups but not groups with bones
@@ -1202,7 +1377,9 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
smat = summat;
}
else {
- mul_v3_fl(vec, armature_weight / contrib);
+ if (target->type != OB_GPENCIL) {
+ mul_v3_fl(vec, armature_weight / contrib);
+ }
add_v3_v3v3(co, vec, co);
}
@@ -1232,23 +1409,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
}
}
- if (dualquats)
- MEM_freeN(dualquats);
if (defnrToPC)
MEM_freeN(defnrToPC);
if (defnrToPCIndex)
MEM_freeN(defnrToPCIndex);
-
- /* free B_bone matrices */
- pdef_info = pdef_info_array;
- for (pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next, pdef_info++) {
- if (pdef_info->b_bone_mats)
- MEM_freeN(pdef_info->b_bone_mats);
- if (pdef_info->b_bone_dual_quats)
- MEM_freeN(pdef_info->b_bone_dual_quats);
- }
-
- MEM_freeN(pdef_info_array);
}
/* ************ END Armature Deform ******************* */
@@ -1463,16 +1627,16 @@ void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], fl
copy_v3_v3(outloc, nLocMat[3]);
}
-void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
+void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
{
bPoseChannel work_pchan = *pchan;
/* recalculate pose matrix with only parent transformations,
* bone loc/sca/rot is ignored, scene and frame are not used. */
- BKE_pose_where_is_bone(NULL, ob, &work_pchan, 0.0f, false);
+ BKE_pose_where_is_bone(depsgraph, NULL, ob, &work_pchan, 0.0f, false);
/* find the matrix, need to remove the bone transforms first so this is
- * calculated as a matrix to set rather then a difference ontop of whats
+ * calculated as a matrix to set rather then a difference ontop of what's
* already there. */
unit_m4(outmat);
BKE_pchan_apply_mat4(&work_pchan, outmat, false);
@@ -1594,21 +1758,28 @@ void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float
/* Computes vector and roll based on a rotation.
* "mat" must contain only a rotation, and no scaling. */
-void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll)
+void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
{
if (r_vec) {
copy_v3_v3(r_vec, mat[1]);
}
if (r_roll) {
- float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
+ mat3_vec_to_roll(mat, mat[1], r_roll);
+ }
+}
- vec_roll_to_mat3(mat[1], 0.0f, vecmat);
- invert_m3_m3(vecmatinv, vecmat);
- mul_m3_m3m3(rollmat, vecmatinv, mat);
+/* Computes roll around the vector that best approximates the matrix.
+ * If vec is the Y vector from purely rotational mat, result should be exact. */
+void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
+{
+ float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
- *r_roll = atan2f(rollmat[2][0], rollmat[2][2]);
- }
+ vec_roll_to_mat3(vec, 0.0f, vecmat);
+ invert_m3_m3(vecmatinv, vecmat);
+ mul_m3_m3m3(rollmat, vecmatinv, mat);
+
+ *r_roll = atan2f(rollmat[2][0], rollmat[2][2]);
}
/* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */
@@ -1835,6 +2006,8 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
pchanw.parent = pchan->parent;
pchanw.child = pchan->child;
pchanw.custom_tx = pchan->custom_tx;
+ pchanw.bbone_prev = pchan->bbone_prev;
+ pchanw.bbone_next = pchan->bbone_next;
pchanw.mpath = pchan->mpath;
pchan->mpath = NULL;
@@ -1950,9 +2123,36 @@ void BKE_pose_clear_pointers(bPose *pose)
}
}
-/* only after leave editmode, duplicating, validating older files, library syncing */
-/* NOTE: pose->flag is set for it */
-void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
+void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose)
+{
+ GHash *bone_hash = BKE_armature_bone_from_name_map(armature);
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
+ }
+ BLI_ghash_free(bone_hash, NULL, NULL);
+}
+
+/** Find the matching pose channel using the bone name, if not NULL. */
+static bPoseChannel *pose_channel_find_bone(bPose *pose, Bone *bone)
+{
+ return (bone != NULL) ? BKE_pose_channel_find_name(pose, bone->name) : NULL;
+}
+
+/** Update the links for the B-Bone handles from Bone data. */
+void BKE_pchan_rebuild_bbone_handles(bPose *pose, bPoseChannel *pchan)
+{
+ pchan->bbone_prev = pose_channel_find_bone(pose, pchan->bone->bbone_prev);
+ pchan->bbone_next = pose_channel_find_bone(pose, pchan->bone->bbone_next);
+}
+
+/**
+ * Only after leave editmode, duplicating, validating older files, library syncing.
+ *
+ * \note pose->flag is set for it.
+ *
+ * \param bmain May be NULL, only used to tag depsgraph as being dirty...
+ */
+void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
Bone *bone;
bPose *pose;
@@ -1981,40 +2181,39 @@ void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
for (pchan = pose->chanbase.first; pchan; pchan = next) {
next = pchan->next;
if (pchan->bone == NULL) {
- BKE_pose_channel_free(pchan);
+ BKE_pose_channel_free_ex(pchan, do_id_user);
BKE_pose_channels_hash_free(pose);
BLI_freelinkN(&pose->chanbase, pchan);
}
}
+
+ BKE_pose_channels_hash_make(pose);
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* Find the custom B-Bone handles. */
+ BKE_pchan_rebuild_bbone_handles(pose, pchan);
+ }
+
/* printf("rebuild pose %s, %d bones\n", ob->id.name, counter); */
/* synchronize protected layers with proxy */
- if (ob->proxy) {
+ /* HACK! To preserve 2.7x behavior that you always can pose even locked bones,
+ * do not do any restoration if this is a COW temp copy! */
+ /* Switched back to just NO_MAIN tag, for some reasons (c) using COW tag was working this morning, but not anymore... */
+ if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
BKE_object_copy_proxy_drivers(ob, ob->proxy);
pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
}
- BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */
+ BKE_pose_update_constraint_flags(pose); /* for IK detection for example */
-#ifdef WITH_LEGACY_DEPSGRAPH
- /* the sorting */
- /* Sorting for new dependnecy graph is done on the scene graph level. */
- if (counter > 1 && sort_bones) {
- DAG_pose_sort(ob);
- }
-#else
- UNUSED_VARS(sort_bones);
-#endif
+ pose->flag &= ~POSE_RECALC;
+ pose->flag |= POSE_WAS_REBUILT;
- ob->pose->flag &= ~POSE_RECALC;
- ob->pose->flag |= POSE_WAS_REBUILT;
-
- BKE_pose_channels_hash_make(ob->pose);
-}
-
-void BKE_pose_rebuild(Object *ob, bArmature *arm)
-{
- BKE_pose_rebuild_ex(ob, arm, true);
+ /* Rebuilding poses forces us to also rebuild the dependency graph, since there is one node per pose/bone... */
+ if (bmain != NULL) {
+ DEG_relations_tag_update(bmain);
+ }
}
/* ********************** THE POSE SOLVER ******************* */
@@ -2071,132 +2270,6 @@ void BKE_pchan_calc_mat(bPoseChannel *pchan)
BKE_pchan_to_mat4(pchan, pchan->chan_mat);
}
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
-
-/* NLA strip modifiers */
-static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseChannel *pchan)
-{
- bActionModifier *amod;
- bActionStrip *strip, *strip2;
- float scene_cfra = BKE_scene_frame_get(scene);
- int do_modif;
-
- for (strip = armob->nlastrips.first; strip; strip = strip->next) {
- do_modif = false;
-
- if (scene_cfra >= strip->start && scene_cfra <= strip->end)
- do_modif = true;
-
- if ((scene_cfra > strip->end) && (strip->flag & ACTSTRIP_HOLDLASTFRAME)) {
- do_modif = true;
-
- /* if there are any other strips active, ignore modifiers for this strip -
- * 'hold' option should only hold action modifiers if there are
- * no other active strips */
- for (strip2 = strip->next; strip2; strip2 = strip2->next) {
- if (strip2 == strip) continue;
-
- if (scene_cfra >= strip2->start && scene_cfra <= strip2->end) {
- if (!(strip2->flag & ACTSTRIP_MUTE))
- do_modif = false;
- }
- }
-
- /* if there are any later, activated, strips with 'hold' set, they take precedence,
- * so ignore modifiers for this strip */
- for (strip2 = strip->next; strip2; strip2 = strip2->next) {
- if (scene_cfra < strip2->start) continue;
- if ((strip2->flag & ACTSTRIP_HOLDLASTFRAME) && !(strip2->flag & ACTSTRIP_MUTE)) {
- do_modif = false;
- }
- }
- }
-
- if (do_modif) {
- /* temporal solution to prevent 2 strips accumulating */
- if (scene_cfra == strip->end && strip->next && strip->next->start == scene_cfra)
- continue;
-
- for (amod = strip->modifiers.first; amod; amod = amod->next) {
- switch (amod->type) {
- case ACTSTRIP_MOD_DEFORM:
- {
- /* validate first */
- if (amod->ob && amod->ob->type == OB_CURVE && amod->channel[0]) {
-
- if (STREQ(pchan->name, amod->channel)) {
- float mat4[4][4], mat3[3][3];
-
- curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
- copy_m4_m4(mat4, pchan->pose_mat);
- mul_m4_m3m4(pchan->pose_mat, mat3, mat4);
-
- }
- }
- }
- break;
- case ACTSTRIP_MOD_NOISE:
- {
- if (STREQ(pchan->name, amod->channel)) {
- float nor[3], loc[3], ofs;
- float eul[3], size[3], eulo[3], sizeo[3];
-
- /* calculate turbulance */
- ofs = amod->turbul / 200.0f;
-
- /* make a copy of starting conditions */
- copy_v3_v3(loc, pchan->pose_mat[3]);
- mat4_to_eul(eul, pchan->pose_mat);
- mat4_to_size(size, pchan->pose_mat);
- copy_v3_v3(eulo, eul);
- copy_v3_v3(sizeo, size);
-
- /* apply noise to each set of channels */
- if (amod->channels & 4) {
- /* for scaling */
- nor[0] = BLI_gNoise(amod->noisesize, size[0] + ofs, size[1], size[2], 0, 0) - ofs;
- nor[1] = BLI_gNoise(amod->noisesize, size[0], size[1] + ofs, size[2], 0, 0) - ofs;
- nor[2] = BLI_gNoise(amod->noisesize, size[0], size[1], size[2] + ofs, 0, 0) - ofs;
- add_v3_v3(size, nor);
-
- if (sizeo[0] != 0)
- mul_v3_fl(pchan->pose_mat[0], size[0] / sizeo[0]);
- if (sizeo[1] != 0)
- mul_v3_fl(pchan->pose_mat[1], size[1] / sizeo[1]);
- if (sizeo[2] != 0)
- mul_v3_fl(pchan->pose_mat[2], size[2] / sizeo[2]);
- }
- if (amod->channels & 2) {
- /* for rotation */
- nor[0] = BLI_gNoise(amod->noisesize, eul[0] + ofs, eul[1], eul[2], 0, 0) - ofs;
- nor[1] = BLI_gNoise(amod->noisesize, eul[0], eul[1] + ofs, eul[2], 0, 0) - ofs;
- nor[2] = BLI_gNoise(amod->noisesize, eul[0], eul[1], eul[2] + ofs, 0, 0) - ofs;
-
- compatible_eul(nor, eulo);
- add_v3_v3(eul, nor);
- compatible_eul(eul, eulo);
-
- loc_eul_size_to_mat4(pchan->pose_mat, loc, eul, size);
- }
- if (amod->channels & 1) {
- /* for location */
- nor[0] = BLI_gNoise(amod->noisesize, loc[0] + ofs, loc[1], loc[2], 0, 0) - ofs;
- nor[1] = BLI_gNoise(amod->noisesize, loc[0], loc[1] + ofs, loc[2], 0, 0) - ofs;
- nor[2] = BLI_gNoise(amod->noisesize, loc[0], loc[1], loc[2] + ofs, 0, 0) - ofs;
-
- add_v3_v3v3(pchan->pose_mat[3], loc, nor);
- }
- }
- }
- break;
- }
- }
- }
- }
-}
-
-#endif
-
/* calculate tail of posechannel */
void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
{
@@ -2211,7 +2284,9 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
/* pchan is validated, as having bone and parent pointer
* 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers.
*/
-void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime, bool do_extra)
+void BKE_pose_where_is_bone(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, bPoseChannel *pchan, float ctime, bool do_extra)
{
/* This gives a chan_mat with actions (ipos) results. */
if (do_extra)
@@ -2231,11 +2306,6 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float
}
if (do_extra) {
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- /* do NLA strip modifiers - i.e. curve follow */
- do_strip_modifiers(scene, ob, bone, pchan);
-#endif
-
/* Do constraints */
if (pchan->constraints.first) {
bConstraintOb *cob;
@@ -2247,10 +2317,10 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float
/* prepare PoseChannel for Constraint solving
* - makes a copy of matrix, and creates temporary struct to use
*/
- cob = BKE_constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
/* Solve PoseChannel's Constraints */
- BKE_constraints_solve(&pchan->constraints, cob, ctime); /* ctime doesnt alter objects */
+ BKE_constraints_solve(depsgraph, &pchan->constraints, cob, ctime); /* ctime doesn't alter objects */
/* cleanup after Constraint Solving
* - applies matrix back to pchan, and frees temporary struct used
@@ -2272,7 +2342,7 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float
/* This only reads anim data from channels, and writes to channels */
/* This is the only function adding poses */
-void BKE_pose_where_is(Scene *scene, Object *ob)
+void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bArmature *arm;
Bone *bone;
@@ -2286,8 +2356,10 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
if (ELEM(NULL, arm, scene))
return;
- if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC))
- BKE_pose_rebuild(ob, arm);
+ if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) {
+ /* WARNING! passing NULL bmain here means we won't tag depsgraph's as dirty - hopefully this is OK. */
+ BKE_pose_rebuild(NULL, ob, arm, true);
+ }
ctime = BKE_scene_frame_get(scene); /* not accurate... */
@@ -2311,7 +2383,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
}
/* 2a. construct the IK tree (standard IK) */
- BIK_initialize_tree(scene, ob, ctime);
+ BIK_initialize_tree(depsgraph, scene, ob, ctime);
/* 2b. construct the Spline IK trees
* - this is not integrated as an IK plugin, since it should be able
@@ -2323,15 +2395,15 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* 4a. if we find an IK root, we handle it separated */
if (pchan->flag & POSE_IKTREE) {
- BIK_execute_tree(scene, ob, pchan, ctime);
+ BIK_execute_tree(depsgraph, scene, ob, pchan, ctime);
}
/* 4b. if we find a Spline IK root, we handle it separated too */
else if (pchan->flag & POSE_IKSPLINE) {
- BKE_splineik_execute_tree(scene, ob, pchan, ctime);
+ BKE_splineik_execute_tree(depsgraph, scene, ob, pchan, ctime);
}
/* 5. otherwise just call the normal solver */
else if (!(pchan->flag & POSE_DONE)) {
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
/* 6. release the IK tree */
@@ -2471,3 +2543,78 @@ bPoseChannel *BKE_armature_splineik_solver_find_root(
}
return rootchan;
}
+
+/* ****************************** BBone cache ****************************** */
+
+ObjectBBoneDeform * BKE_armature_cached_bbone_deformation_get(Object *object)
+{
+ return object->runtime.cached_bbone_deformation;
+}
+
+void BKE_armature_cached_bbone_deformation_free_data(Object *object)
+{
+ ObjectBBoneDeform *bbone_deform =
+ BKE_armature_cached_bbone_deformation_get(object);
+ if (bbone_deform == NULL) {
+ return;
+ }
+ /* Free arrays. */
+ MEM_SAFE_FREE(bbone_deform->pdef_info_array);
+ MEM_SAFE_FREE(bbone_deform->dualquats);
+ /* Tag that we've got no data, so we are safe for sequential calls to
+ * data free. */
+ bbone_deform->num_pchan = 0;
+}
+
+void BKE_armature_cached_bbone_deformation_free(Object *object)
+{
+ ObjectBBoneDeform *bbone_deform =
+ BKE_armature_cached_bbone_deformation_get(object);
+ if (bbone_deform == NULL) {
+ return;
+ }
+ BKE_armature_cached_bbone_deformation_free_data(object);
+ MEM_freeN(bbone_deform);
+ object->runtime.cached_bbone_deformation = NULL;
+}
+
+void BKE_armature_cached_bbone_deformation_update(Object *object)
+{
+ BLI_assert(object->type == OB_ARMATURE);
+ BLI_assert(object->pose != NULL);
+ bPose *pose = object->pose;
+ const int totchan = BLI_listbase_count(&pose->chanbase);
+ const bool use_quaternion = true;
+ /* Make sure cache exists. */
+ ObjectBBoneDeform *bbone_deform =
+ BKE_armature_cached_bbone_deformation_get(object);
+ if (bbone_deform == NULL) {
+ bbone_deform = MEM_callocN(sizeof(*bbone_deform), "bbone deform cache");
+ object->runtime.cached_bbone_deformation = bbone_deform;
+ }
+ /* Make sure arrays are allocateds at the proper size. */
+ BKE_armature_cached_bbone_deformation_free_data(object);
+ DualQuat *dualquats = NULL;
+ if (use_quaternion) {
+ dualquats = MEM_calloc_arrayN(
+ sizeof(DualQuat), totchan, "dualquats");
+ }
+ bPoseChanDeform *pdef_info_array = MEM_calloc_arrayN(
+ sizeof(bPoseChanDeform), totchan, "bPoseChanDeform");
+ /* Calculate deofrmation matricies. */
+ ArmatureBBoneDefmatsData data = {
+ .pdef_info_array = pdef_info_array,
+ .dualquats = dualquats,
+ .use_quaternion = use_quaternion
+ };
+ BLI_task_parallel_listbase(&pose->chanbase,
+ &data,
+ armature_bbone_defmats_cb,
+ totchan > 1024);
+ /* Store pointers. */
+ bbone_deform->dualquats = dualquats;
+ atomic_cas_ptr((void **)&bbone_deform->pdef_info_array,
+ bbone_deform->pdef_info_array,
+ pdef_info_array);
+ bbone_deform->num_pchan = totchan;
+}
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 241a842d73f..f5519966ac2 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -26,6 +26,10 @@
* Defines and code for core node types
*/
+/** \file blender/blenkernel/intern/armature_update.c
+ * \ingroup bke
+ */
+
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
@@ -41,9 +45,9 @@
#include "BKE_anim.h"
#include "BKE_armature.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_fcurve.h"
+#include "BKE_object.h"
#include "BKE_scene.h"
#include "BIK_api.h"
@@ -113,9 +117,11 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
* currently for paths to work it needs to go through the bevlist/displist system (ton)
*/
+ /* TODO: Make sure this doesn't crash. */
+#if 0
/* only happens on reload file, but violates depsgraph still... fix! */
if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
- BKE_displist_make_curveTypes(scene, ikData->tar, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, ikData->tar, 0);
/* path building may fail in EditMode after removing verts [#33268]*/
if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
@@ -123,6 +129,9 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
return;
}
}
+#else
+ (void) scene;
+#endif
}
/* find the root bone and the chain of bones from the root to the tip
@@ -197,7 +206,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
/* get the current length of the curve */
/* NOTE: this is assumed to be correct even after the curve was resized */
- splineLen = ikData->tar->curve_cache->path->totdist;
+ splineLen = ikData->tar->runtime.curve_cache->path->totdist;
/* calculate the scale factor to multiply all the path values by so that the
* bone chain retains its current length, such that
@@ -261,15 +270,16 @@ static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
/* ----------- */
/* Evaluate spline IK for a given bone */
-static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
- int index, float ctime)
+static void splineik_evaluate_bone(
+ struct Depsgraph *depsgraph, tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
+ int index, float ctime)
{
bSplineIKConstraint *ikData = tree->ikData;
float poseHead[3], poseTail[3], poseMat[4][4];
float splineVec[3], scaleFac, radius = 1.0f;
/* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
copy_v3_v3(poseHead, pchan->pose_head);
copy_v3_v3(poseTail, pchan->pose_tail);
@@ -511,7 +521,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
}
/* Evaluate the chain starting from the nominated bone */
-static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+static void splineik_execute_tree(struct Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
tSplineIK_Tree *tree;
@@ -525,7 +535,7 @@ static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_
*/
for (i = tree->chainlen - 1; i >= 0; i--) {
bPoseChannel *pchan = tree->chain[i];
- splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
+ splineik_evaluate_bone(depsgraph, tree, scene, ob, pchan, i, ctime);
}
/* free the tree info specific to SplineIK trees now */
@@ -544,57 +554,73 @@ void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime)
splineik_init_tree(scene, ob, ctime);
}
-void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+void BKE_splineik_execute_tree(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, bPoseChannel *pchan_root, float ctime)
{
- splineik_execute_tree(scene, ob, pchan_root, ctime);
+ splineik_execute_tree(depsgraph, scene, ob, pchan_root, ctime);
}
/* *************** Depsgraph evaluation callbacks ************ */
+static void pose_pchan_index_create(bPose *pose)
+{
+ const int num_channels = BLI_listbase_count(&pose->chanbase);
+ pose->chan_array = MEM_malloc_arrayN(
+ num_channels, sizeof(bPoseChannel *), "pose->chan_array");
+ int pchan_index = 0;
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ pose->chan_array[pchan_index++] = pchan;
+ }
+}
+
BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index)
{
bPose *pose = ob->pose;
BLI_assert(pose != NULL);
+ BLI_assert(pose->chan_array != NULL);
BLI_assert(pchan_index >= 0);
BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *));
return pose->chan_array[pchan_index];
}
-void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_init(struct Depsgraph *depsgraph,
Scene *UNUSED(scene),
- Object *ob)
+ Object *object)
{
- bPose *pose = ob->pose;
+ bPose *pose = object->pose;
BLI_assert(pose != NULL);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- BLI_assert(ob->type == OB_ARMATURE);
+ BLI_assert(object->type == OB_ARMATURE);
/* We demand having proper pose. */
- BLI_assert(ob->pose != NULL);
- BLI_assert((ob->pose->flag & POSE_RECALC) == 0);
+ BLI_assert(object->pose != NULL);
+ BLI_assert((object->pose->flag & POSE_RECALC) == 0);
/* imat is needed for solvers. */
- invert_m4_m4(ob->imat, ob->obmat);
-
- const int num_channels = BLI_listbase_count(&pose->chanbase);
- pose->chan_array = MEM_malloc_arrayN(
- num_channels, sizeof(bPoseChannel *), "pose->chan_array");
+ invert_m4_m4(object->imat, object->obmat);
/* clear flags */
- int pchan_index = 0;
for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
- pose->chan_array[pchan_index++] = pchan;
+
+ /* Free B-Bone shape data cache if it's not a B-Bone. */
+ if (pchan->bone == NULL || pchan->bone->segments <= 1) {
+ BKE_pose_channel_free_bbone_cache(pchan);
+ }
}
+
+ pose_pchan_index_create(pose);
+ BKE_armature_cached_bbone_deformation_free_data(object);
}
-void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
@@ -602,7 +628,7 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
return;
}
/* construct the IK tree (standard IK) */
- BIK_initialize_tree(scene, ob, ctime);
+ BIK_initialize_tree(depsgraph, scene, ob, ctime);
/* construct the Spline IK trees
* - this is not integrated as an IK plugin, since it should be able
* to function in conjunction with standard IK
@@ -610,14 +636,14 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
BKE_pose_splineik_init_tree(scene, ob, ctime);
}
-void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_bone(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
+ depsgraph, __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
BLI_assert(ob->type == OB_ARMATURE);
bArmature *arm = (bArmature *)ob->data;
if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
@@ -640,21 +666,21 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
if ((pchan->flag & POSE_DONE) == 0) {
/* TODO(sergey): Use time source node for time. */
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
}
}
}
-void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
+ depsgraph, __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
@@ -665,42 +691,69 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
else {
if ((pchan->flag & POSE_DONE) == 0) {
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
}
-void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_bone_done(struct Depsgraph *depsgraph,
struct Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
float imat[4][4];
- DEG_debug_print_eval(__func__, pchan->name, pchan);
+ DEG_debug_print_eval(depsgraph, __func__, pchan->name, pchan);
if (pchan->bone) {
invert_m4_m4(imat, pchan->bone->arm_mat);
mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
}
+ bArmature *arm = (bArmature *)ob->data;
+ if (DEG_is_active(depsgraph) && arm->edbo == NULL) {
+ bPoseChannel *pchan_orig = pchan->orig_pchan;
+ copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat);
+ copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat);
+ copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]);
+ copy_m4_m4(pchan_orig->constinv, pchan->constinv);
+ BKE_pose_where_is_bone_tail(pchan_orig);
+ if (pchan->bone == NULL || pchan->bone->segments <= 1) {
+ BKE_pose_channel_free_bbone_cache(pchan_orig);
+ }
+ }
+}
+
+void BKE_pose_eval_bbone_segments(struct Depsgraph *depsgraph,
+ struct Object *ob,
+ int pchan_index)
+{
+ bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
+ DEG_debug_print_eval(depsgraph, __func__, pchan->name, pchan);
+ if (pchan->bone != NULL && pchan->bone->segments > 1) {
+ BKE_pchan_cache_bbone_segments(pchan);
+ bArmature *arm = (bArmature *)ob->data;
+ if (DEG_is_active(depsgraph) && arm->edbo == NULL) {
+ BKE_pchan_copy_bbone_segments_cache(pchan->orig_pchan, pchan);
+ }
+ }
}
-void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int rootchan_index)
{
bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
+ depsgraph, __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
}
- BIK_execute_tree(scene, ob, rootchan, ctime);
+ BIK_execute_tree(depsgraph, scene, ob, rootchan, ctime);
}
-void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int rootchan_index)
@@ -708,47 +761,101 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
{
bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
+ depsgraph, __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
}
- BKE_splineik_execute_tree(scene, ob, rootchan, ctime);
+ BKE_splineik_execute_tree(depsgraph, scene, ob, rootchan, ctime);
}
-void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
- Scene *scene,
- Object *ob)
+/* Common part for both original and proxy armatrues. */
+static void pose_eval_done_common(struct Depsgraph *depsgraph, Object *object)
{
- bPose *pose = ob->pose;
+ bPose *pose = object->pose;
+ UNUSED_VARS_NDEBUG(pose);
+ BLI_assert(pose != NULL);
+ BKE_armature_cached_bbone_deformation_update(object);
+ BKE_object_eval_boundbox(depsgraph, object);
+}
+static void pose_eval_cleanup_common(Object *object)
+{
+ bPose *pose = object->pose;
BLI_assert(pose != NULL);
+ BLI_assert(pose->chan_array != NULL || BLI_listbase_is_empty(&pose->chanbase));
+ MEM_SAFE_FREE(pose->chan_array);
+}
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- DEG_debug_print_eval(__func__, ob->id.name, ob);
- BLI_assert(ob->type == OB_ARMATURE);
+void BKE_pose_eval_done(struct Depsgraph *depsgraph, Object *object)
+{
+ bPose *pose = object->pose;
+ BLI_assert(pose != NULL);
+ UNUSED_VARS_NDEBUG(pose);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ BLI_assert(object->type == OB_ARMATURE);
+ pose_eval_done_common(depsgraph, object);
+}
- /* release the IK tree */
- BIK_release_tree(scene, ob, ctime);
+void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *object)
+{
+ bPose *pose = object->pose;
+ BLI_assert(pose != NULL);
+ UNUSED_VARS_NDEBUG(pose);
+ const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ BLI_assert(object->type == OB_ARMATURE);
+ /* Release the IK tree. */
+ BIK_release_tree(scene, object, ctime);
+ pose_eval_cleanup_common(object);
+}
- ob->recalc &= ~OB_RECALC_ALL;
+void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, Object *object)
+{
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
- BLI_assert(pose->chan_array != NULL);
- MEM_freeN(pose->chan_array);
- pose->chan_array = NULL;
+ pose_pchan_index_create(object->pose);
+ BKE_armature_cached_bbone_deformation_free_data(object);
}
-void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+void BKE_pose_eval_proxy_done(struct Depsgraph *depsgraph, Object *object)
{
- BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
- if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
- printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
- ob->id.name + 2, ob->proxy_from->id.name + 2);
- }
- /* Rest of operations are NO-OP in depsgraph, so can clear
- * flag now.
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ pose_eval_done_common(depsgraph, object);
+}
+
+void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, Object *object)
+{
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ pose_eval_cleanup_common(object);
+}
+
+void BKE_pose_eval_proxy_copy_bone(
+ struct Depsgraph *depsgraph,
+ Object *object,
+ int pchan_index)
+{
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
+ /* TODO(sergey): Use indexec lookup, once it's guaranteed to be kept
+ * around for the time while proxies are evaluating.
*/
- ob->recalc &= ~OB_RECALC_ALL;
+#if 0
+ bPoseChannel *pchan_from = pose_pchan_get_indexed(
+ object->proxy_from, pchan_index);
+#else
+ bPoseChannel *pchan_from = BKE_pose_channel_find_name(
+ object->proxy_from->pose, pchan->name);
+#endif
+ BLI_assert(pchan != NULL);
+ BLI_assert(pchan_from != NULL);
+ BKE_pose_copyesult_pchan_result(pchan, pchan_from);
+ BKE_pchan_copy_bbone_segments_cache(pchan, pchan_from);
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index ba20dbaddb0..f1b1aa548d2 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -48,20 +48,25 @@
#include "BKE_addon.h"
#include "BKE_blender.h" /* own include */
#include "BKE_blender_version.h" /* own include */
+#include "BKE_blender_user_menu.h"
#include "BKE_blendfile.h"
#include "BKE_brush.h"
#include "BKE_cachefile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "BKE_studiolight.h"
+
+#include "DEG_depsgraph.h"
#include "RE_pipeline.h"
#include "RE_render_ext.h"
@@ -80,6 +85,8 @@ char versionstr[48] = "";
void BKE_blender_free(void)
{
/* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
+
+ BKE_studiolight_free(); /* needs to run before main free as wm is still referenced for icons preview jobs */
BKE_main_free(G_MAIN);
G_MAIN = NULL;
@@ -92,7 +99,7 @@ void BKE_blender_free(void)
IMB_exit();
BKE_cachefiles_exit();
BKE_images_exit();
- DAG_exit();
+ DEG_free_node_types();
BKE_brush_system_exit();
RE_texture_rng_exit();
@@ -201,6 +208,26 @@ static void userdef_free_keymaps(UserDef *userdef)
BLI_listbase_clear(&userdef->user_keymaps);
}
+static void userdef_free_keyconfig_prefs(UserDef *userdef)
+{
+ for (wmKeyConfigPref *kpt = userdef->user_keyconfig_prefs.first, *kpt_next; kpt; kpt = kpt_next) {
+ kpt_next = kpt->next;
+ IDP_FreeProperty(kpt->prop);
+ MEM_freeN(kpt->prop);
+ MEM_freeN(kpt);
+ }
+ BLI_listbase_clear(&userdef->user_keyconfig_prefs);
+}
+
+static void userdef_free_user_menus(UserDef *userdef)
+{
+ for (bUserMenu *um = userdef->user_menus.first, *um_next; um; um = um_next) {
+ um_next = um->next;
+ BKE_blender_user_menu_item_free_list(&um->items);
+ MEM_freeN(um);
+ }
+}
+
static void userdef_free_addons(UserDef *userdef)
{
for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
@@ -221,6 +248,8 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
#endif
userdef_free_keymaps(userdef);
+ userdef_free_keyconfig_prefs(userdef);
+ userdef_free_user_menus(userdef);
userdef_free_addons(userdef);
if (clear_fonts) {
@@ -236,6 +265,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
BLI_freelistN(&userdef->uifonts);
BLI_freelistN(&userdef->themes);
+
#undef U
}
@@ -283,11 +313,13 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
DATA_SWAP(font_path_ui_mono);
DATA_SWAP(keyconfigstr);
+ DATA_SWAP(gizmo_flag);
DATA_SWAP(app_flag);
/* We could add others. */
FLAG_SWAP(uiflag, int, USER_QUIT_PROMPT);
+#undef SWAP_TYPELESS
#undef DATA_SWAP
#undef LIST_SWAP
#undef FLAG_SWAP
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index e57524af546..7b149761952 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -44,12 +44,15 @@
#include "BKE_blender_copybuffer.h" /* own include */
#include "BKE_blendfile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -95,7 +98,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor
/* Here appending/linking starts. */
Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname);
BLO_library_link_copypaste(mainl, bh);
- BLO_library_link_end(mainl, &bh, 0, NULL, NULL);
+ BLO_library_link_end(mainl, &bh, 0, NULL, NULL, NULL);
/* Mark all library linked objects to be updated. */
BKE_main_lib_objects_recalc_all(bmain_dst);
IMB_colormanagement_check_file_config(bmain_dst);
@@ -117,7 +120,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Main *mainl = NULL;
Library *lib;
BlendHandle *bh;
@@ -129,7 +132,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
return false;
}
- BKE_scene_base_deselect_all(scene);
+ BKE_view_layer_base_deselect_all(view_layer);
/* tag everything, all untagged data can be made local
* its also generally useful to know what is new
@@ -142,7 +145,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
BLO_library_link_copypaste(mainl, bh);
- BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer);
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
@@ -157,7 +160,11 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
/* recreate dependency graph to include new objects */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
+
+ /* Tag update the scene to flush base collection settings, since the new object is added to a
+ * new (active) collection, not its original collection, thus need recalculation. */
+ DEG_id_tag_update(&scene->id, 0);
BLO_blendhandle_close(bh);
/* remove library... */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 441687c1c01..fac3685f7b1 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -46,18 +46,20 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_appdir.h"
#include "BKE_blender_undo.h" /* own include */
#include "BKE_blendfile.h"
-#include "BKE_appdir.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BLO_undofile.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
+#include "DEG_depsgraph.h"
+
/* -------------------------------------------------------------------- */
/** \name Global Undo
@@ -92,8 +94,8 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C)
G.fileflags = fileflags;
if (success) {
- /* important not to update time here, else non keyed tranforms are lost */
- DAG_on_visible_update(bmain, false);
+ /* important not to update time here, else non keyed transforms are lost */
+ DEG_on_visible_update(bmain, false);
}
return success;
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
new file mode 100644
index 00000000000..2c18de70e6d
--- /dev/null
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -0,0 +1,121 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/blender_user_menu.c
+ * \ingroup bke
+ *
+ * User defined menu API.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BKE_blender_user_menu.h"
+#include "BKE_idprop.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Type
+ * \{ */
+
+bUserMenu *BKE_blender_user_menu_find(
+ ListBase *lb, char space_type, const char *context)
+{
+ for (bUserMenu *um = lb->first; um; um = um->next) {
+ if ((space_type == um->space_type) &&
+ (STREQ(context, um->context)))
+ {
+ return um;
+ }
+ }
+ return NULL;
+}
+
+bUserMenu *BKE_blender_user_menu_ensure(
+ ListBase *lb, char space_type, const char *context)
+{
+ bUserMenu *um = BKE_blender_user_menu_find(lb, space_type, context);
+ if (um == NULL) {
+ um = MEM_callocN(sizeof(bUserMenu), __func__);
+ um->space_type = space_type;
+ STRNCPY(um->context, context);
+ BLI_addhead(lb, um);
+ }
+ return um;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Item
+ * \{ */
+
+bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type)
+{
+ uint size;
+
+ if (type == USER_MENU_TYPE_SEP) {
+ size = sizeof(bUserMenuItem);
+ }
+ else if (type == USER_MENU_TYPE_OPERATOR) {
+ size = sizeof(bUserMenuItem_Op);
+ }
+ else if (type == USER_MENU_TYPE_MENU) {
+ size = sizeof(bUserMenuItem_Menu);
+ }
+ else if (type == USER_MENU_TYPE_PROP) {
+ size = sizeof(bUserMenuItem_Prop);
+ }
+ else {
+ size = sizeof(bUserMenuItem);
+ BLI_assert(0);
+ }
+
+ bUserMenuItem *umi = MEM_callocN(size, __func__);
+ umi->type = type;
+ BLI_addtail(lb, umi);
+ return umi;
+}
+
+void BKE_blender_user_menu_item_free(bUserMenuItem *umi)
+{
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ if (umi_op->prop) {
+ IDP_FreeProperty(umi_op->prop);
+ MEM_freeN(umi_op->prop);
+ }
+ }
+ MEM_freeN(umi);
+}
+
+void BKE_blender_user_menu_item_free_list(ListBase *lb)
+{
+ for (bUserMenuItem *umi = lb->first, *umi_next; umi; umi = umi_next) {
+ umi_next = umi->next;
+ BKE_blender_user_menu_item_free(umi);
+ }
+ BLI_listbase_clear(lb);
+}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index c6cb8a412fe..cc42fe71579 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -32,6 +32,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -48,11 +49,13 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_ipo.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -93,7 +96,7 @@ static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
{
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
- if (win->screen->scene == scene) {
+ if (win->scene == scene) {
return true;
}
}
@@ -165,17 +168,22 @@ static void setup_app_data(
* (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
* see: T43424
*/
+ wmWindow *win;
bScreen *curscreen = NULL;
+ ViewLayer *cur_view_layer;
bool track_undo_scene;
/* comes from readfile.c */
SWAP(ListBase, bmain->wm, bfd->main->wm);
+ SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
SWAP(ListBase, bmain->screen, bfd->main->screen);
- /* we re-use current screen */
+ /* we re-use current window and screen */
+ win = CTX_wm_window(C);
curscreen = CTX_wm_screen(C);
- /* but use new Scene pointer */
+ /* but use Scene pointer from new file */
curscene = bfd->curscene;
+ cur_view_layer = bfd->cur_view_layer;
track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
@@ -186,34 +194,41 @@ static void setup_app_data(
if (curscene == NULL) {
curscene = BKE_scene_add(bfd->main, "Empty");
}
+ if (cur_view_layer == NULL) {
+ /* fallback to scene layer */
+ cur_view_layer = BKE_view_layer_default_view(curscene);
+ }
if (track_undo_scene) {
/* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
* replace it with 'curscene' if its needed */
}
- else {
- /* and we enforce curscene to be in current screen */
- if (curscreen) {
- /* can run in bgmode */
- curscreen->scene = curscene;
- }
+ /* and we enforce curscene to be in current screen */
+ else if (win) { /* can run in bgmode */
+ win->scene = curscene;
}
/* BKE_blender_globals_clear will free G_MAIN, here we can still restore pointers */
- blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
- /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */
- if (curscreen) {
- curscene = curscreen->scene;
+ blo_lib_link_restore(bfd->main, CTX_wm_manager(C), curscene, cur_view_layer);
+ if (win) {
+ curscene = win->scene;
}
if (track_undo_scene) {
wmWindowManager *wm = bfd->main->wm.first;
if (wm_scene_is_visible(wm, bfd->curscene) == false) {
curscene = bfd->curscene;
- curscreen->scene = curscene;
- BKE_screen_view3d_scene_sync(curscreen);
+ win->scene = curscene;
+ BKE_screen_view3d_scene_sync(curscreen, curscene);
}
}
+
+ /* We need to tag this here because events may be handled immediately after.
+ * only the current screen is important because we wont have to handle
+ * events from multiple screens at once.*/
+ if (curscreen) {
+ BKE_screen_gizmo_tag_refresh(curscreen);
+ }
}
/* free G_MAIN Main database */
@@ -228,6 +243,7 @@ static void setup_app_data(
CTX_data_main_set(C, bmain);
if (bfd->user) {
+
/* only here free userdef themes... */
BKE_blender_userdef_data_set_and_free(bfd->user);
bfd->user = NULL;
@@ -263,12 +279,14 @@ static void setup_app_data(
/* this can happen when active scene was lib-linked, and doesn't exist anymore */
if (CTX_data_scene(C) == NULL) {
+ wmWindow *win = CTX_wm_window(C);
+
/* in case we don't even have a local scene, add one */
if (!bmain->scene.first)
BKE_scene_add(bmain, "Empty");
CTX_data_scene_set(C, bmain->scene.first);
- CTX_wm_screen(C)->scene = CTX_data_scene(C);
+ win->scene = CTX_data_scene(C);
curscene = CTX_data_scene(C);
}
@@ -317,20 +335,27 @@ static void setup_app_data(
wmWindowManager *wm = bmain->wm.first;
if (wm) {
- wmWindow *win;
-
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen && win->screen->scene) /* zealous check... */
- if (win->screen->scene != curscene)
- BKE_scene_set_background(bmain, win->screen->scene);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene && win->scene != curscene) {
+ BKE_scene_set_background(bmain, win->scene);
+ }
}
}
}
+
+ /* Setting scene might require having a dependency graph, with copy on write
+ * we need to make sure we ensure scene has correct color management before
+ * constructing dependency graph.
+ */
+ if (mode != LOAD_UNDO) {
+ IMB_colormanagement_check_file_config(bmain);
+ }
+
BKE_scene_set_background(bmain, curscene);
if (mode != LOAD_UNDO) {
+ /* TODO(sergey): Can this be also move above? */
RE_FreeAllPersistentData();
- IMB_colormanagement_check_file_config(bmain);
}
MEM_freeN(bfd);
@@ -395,7 +420,7 @@ bool BKE_blendfile_read_from_memory(
bfd = BLO_read_from_memory(filebuf, filelength, params->skip_flags, reports);
if (bfd) {
if (update_defaults)
- BLO_update_defaults_startup_blend(bfd->main);
+ BLO_update_defaults_startup_blend(bfd->main, NULL);
setup_app_data(C, bfd, "<memory2>", params->is_startup, reports);
}
else {
@@ -447,7 +472,7 @@ void BKE_blendfile_read_make_empty(bContext *C)
while (a--) {
id = lbarray[a]->first;
if (id != NULL) {
- if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM)) {
+ if (ELEM(GS(id->name), ID_SCE, ID_SCR, ID_WM, ID_WS)) {
continue;
}
while ((id = lbarray[a]->first)) {
@@ -543,6 +568,54 @@ bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *
return ok;
}
+WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, const void *filebuf, int filelength, ReportList *reports)
+{
+ BlendFileData *bfd;
+ WorkspaceConfigFileData *workspace_config = NULL;
+
+ if (filepath) {
+ bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_USERDEF, reports);
+ }
+ else {
+ bfd = BLO_read_from_memory(filebuf, filelength, BLO_READ_SKIP_USERDEF, reports);
+ }
+
+ if (bfd) {
+ workspace_config = MEM_mallocN(sizeof(*workspace_config), __func__);
+ workspace_config->main = bfd->main;
+ workspace_config->workspaces = bfd->main->workspaces;
+
+ MEM_freeN(bfd);
+ }
+
+ return workspace_config;
+}
+
+bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports)
+{
+ int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_HISTORY);
+ bool retval = false;
+
+ BKE_blendfile_write_partial_begin(bmain);
+
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_blendfile_write_partial_tag_ID(&workspace->id, true);
+ }
+
+ if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) {
+ retval = true;
+ }
+
+ BKE_blendfile_write_partial_end(bmain);
+
+ return retval;
+}
+
+void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config)
+{
+ BKE_main_free(workspace_config->main);
+ MEM_freeN(workspace_config);
+}
/** \} */
diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c
deleted file mode 100644
index b33b07e3a4f..00000000000
--- a/source/blender/blenkernel/intern/bmfont.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): 04-10-2000 frank.
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-/** \file blender/blenkernel/intern/bmfont.c
- * \ingroup bke
- */
-
-
-/**
- * Two external functions:
- *
- * void detectBitmapFont(ImBuf *ibuf)
- * detects if an image buffer contains a bitmap font. It makes the
- * specific bitmap data which is stored in the bitmap invisible to blender.
- *
- * void matrixGlyph(ImBuf *ibuf, unsigned short unicode, *float x 7)
- * returns all the information about the character (unicode) in the floats
- *
- * Room for improvement:
- * add kerning data in the bitmap
- * all calculations in matrixGlyph() are static and could be done during
- * initialization
- */
-
-#include <stdio.h>
-
-#include "MEM_guardedalloc.h"
-#include "IMB_imbuf_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_bmfont.h"
-#include "BKE_bmfont_types.h"
-#include "BKE_global.h"
-
-void printfGlyph(bmGlyph *glyph)
-{
- printf("unicode: %d '%c'\n", glyph->unicode, glyph->unicode);
- printf(" locx: %4d locy: %4d\n", glyph->locx, glyph->locy);
- printf(" sizex: %3d sizey: %3d\n", glyph->sizex, glyph->sizey);
- printf(" ofsx: %3d ofsy: %3d\n", glyph->ofsx, glyph->ofsy);
- printf(" advan: %3d reser: %3d\n", glyph->advance, glyph->reserved);
-}
-
-void calcAlpha(ImBuf *ibuf)
-{
- int i;
- char *rect;
-
- if (ibuf) {
- rect = (char *) ibuf->rect;
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
- rect[3] = MAX3(rect[0], rect[1], rect[2]);
- rect += 4;
- }
- }
-}
-
-void readBitmapFontVersion0(ImBuf *ibuf, unsigned char *rect, int step)
-{
- int glyphcount, bytes, i, index, linelength, ysize;
- unsigned char *buffer;
- bmFont *bmfont;
-
- linelength = ibuf->x * step;
-
- glyphcount = (rect[6 * step] << 8) | rect[7 * step];
- bytes = ((glyphcount - 1) * sizeof(bmGlyph)) + sizeof(bmFont);
-
- ysize = (bytes + (ibuf->x - 1)) / ibuf->x;
-
- if (ysize < ibuf->y) {
- /* we're first going to copy all data into a linear buffer.
- * step can be 4 or 1 bytes, and the data is not sequential because
- * the bitmap was flipped vertically. */
-
- buffer = MEM_mallocN(bytes, "readBitmapFontVersion0:buffer");
-
- index = 0;
- for (i = 0; i < bytes; i++) {
- buffer[i] = rect[index];
- index += step;
- if (index >= linelength) {
- /* we've read one line, no skip to the line *before* that */
- rect -= linelength;
- index -= linelength;
- }
- }
-
- /* we're now going to endian convert the data */
-
- bmfont = MEM_mallocN(bytes, "readBitmapFontVersion0:bmfont");
- index = 0;
-
- /* first read the header */
- bmfont->magic[0] = buffer[index++];
- bmfont->magic[1] = buffer[index++];
- bmfont->magic[2] = buffer[index++];
- bmfont->magic[3] = buffer[index++];
- bmfont->version = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->glyphcount = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->xsize = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->ysize = (buffer[index] << 8) | buffer[index + 1]; index += 2;
-
- for (i = 0; i < bmfont->glyphcount; i++) {
- bmfont->glyphs[i].unicode = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->glyphs[i].locx = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->glyphs[i].locy = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->glyphs[i].ofsx = buffer[index++];
- bmfont->glyphs[i].ofsy = buffer[index++];
- bmfont->glyphs[i].sizex = buffer[index++];
- bmfont->glyphs[i].sizey = buffer[index++];
- bmfont->glyphs[i].advance = buffer[index++];
- bmfont->glyphs[i].reserved = buffer[index++];
- if (G.debug & G_DEBUG) {
- printfGlyph(&bmfont->glyphs[i]);
- }
- }
-
- MEM_freeN(buffer);
-
- if (G.debug & G_DEBUG) {
- printf("Oldy = %d Newy = %d\n", ibuf->y, ibuf->y - ysize);
- printf("glyphcount = %d\n", glyphcount);
- printf("bytes = %d\n", bytes);
- }
-
- /* we've read the data from the image. Now we're going
- * to crop the image vertically so only the bitmap data
- * remains visible */
-
- ibuf->y -= ysize;
- ibuf->userdata = bmfont;
- ibuf->userflags |= IB_BITMAPFONT;
-
- if (ibuf->planes < 32) {
- /* we're going to fake alpha here: */
- calcAlpha(ibuf);
- }
- }
- else {
- printf("readBitmapFontVersion0: corrupted bitmapfont\n");
- }
-}
-
-void detectBitmapFont(ImBuf *ibuf)
-{
- unsigned char *rect;
- unsigned short version;
- int i;
-
- if (ibuf != NULL && ibuf->rect != NULL) {
- /* bitmap must have an x size that is a power of two */
- if (is_power_of_two(ibuf->x)) {
- rect = (unsigned char *) (ibuf->rect + (ibuf->x * (ibuf->y - 1)));
- /* printf ("starts with: %s %c %c %c %c\n", rect, rect[0], rect[1], rect[2], rect[3]); */
- if (rect[0] == 'B' && rect[1] == 'F' && rect[2] == 'N' && rect[3] == 'T') {
- /* printf("found 8bit font !\n");
- * round y size down
- * do the 8 bit font stuff. (not yet) */
- }
- else {
- /* we try all 4 possible combinations */
- for (i = 0; i < 4; i++) {
- if (rect[0] == 'B' && rect[4] == 'F' && rect[8] == 'N' && rect[12] == 'T') {
- /* printf("found 24bit font !\n");
- * We're going to parse the file: */
-
- version = (rect[16] << 8) | rect[20];
-
- if (version == 0) {
- readBitmapFontVersion0(ibuf, rect, 4);
- }
- else {
- printf("detectBitmapFont :Unsupported version %d\n", (int)version);
- }
-
- /* on success ibuf->userdata points to the bitmapfont */
- if (ibuf->userdata) {
- break;
- }
- }
- rect++;
- }
- }
- }
- }
-}
-
-int locateGlyph(bmFont *bmfont, unsigned short unicode)
-{
- int min, max, current = 0;
-
- if (bmfont) {
- min = 0;
- max = bmfont->glyphcount;
- while (1) {
- /* look halfway for glyph */
- current = (min + max) >> 1;
-
- if (bmfont->glyphs[current].unicode == unicode) {
- break;
- }
- else if (bmfont->glyphs[current].unicode < unicode) {
- /* have to move up */
- min = current;
- }
- else {
- /* have to move down */
- max = current;
- }
-
- if (max - min <= 1) {
- /* unable to locate glyph */
- current = 0;
- break;
- }
- }
- }
-
- return(current);
-}
-
-void matrixGlyph(
- ImBuf *ibuf, unsigned short unicode,
- float *centerx, float *centery,
- float *sizex, float *sizey,
- float *transx, float *transy,
- float *movex, float *movey,
- float *advance)
-{
- int index;
- bmFont *bmfont;
-
- *centerx = *centery = 0.0;
- *sizex = *sizey = 1.0;
- *transx = *transy = 0.0;
- *movex = *movey = 0.0;
- *advance = 1.0;
-
- if (ibuf) {
- bmfont = ibuf->userdata;
- if (bmfont && (ibuf->userflags & IB_BITMAPFONT)) {
- index = locateGlyph(bmfont, unicode);
- if (index) {
-
- *sizex = (bmfont->glyphs[index].sizex) / (float) (bmfont->glyphs[0].sizex);
- *sizey = (bmfont->glyphs[index].sizey) / (float) (bmfont->glyphs[0].sizey);
-
- *transx = bmfont->glyphs[index].locx / (float) ibuf->x;
- *transy = (ibuf->y - bmfont->glyphs[index].locy) / (float) ibuf->y;
-
- *centerx = bmfont->glyphs[0].locx / (float) ibuf->x;
- *centery = (ibuf->y - bmfont->glyphs[0].locy) / (float) ibuf->y;
-
- /* 2.0 units is the default size of an object */
-
- *movey = 1.0f - *sizey + 2.0f * (bmfont->glyphs[index].ofsy - bmfont->glyphs[0].ofsy) / (float) bmfont->glyphs[0].sizey;
- *movex = *sizex - 1.0f + 2.0f * (bmfont->glyphs[index].ofsx - bmfont->glyphs[0].ofsx) / (float) bmfont->glyphs[0].sizex;
-
- *advance = 2.0f * bmfont->glyphs[index].advance / (float) bmfont->glyphs[0].advance;
-
- // printfGlyph(&bmfont->glyphs[index]);
- // printf("%c %d %0.5f %0.5f %0.5f %0.5f %0.5f\n", unicode, index, *sizex, *sizey, *transx, *transy, *advance);
- }
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 810056f8fc7..ea62748806c 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -132,6 +132,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
if (eff == NULL && gabr->ob) {
memset(&temp_eff, 0, sizeof(EffectorCache));
temp_eff.ob = gabr->ob;
+ temp_eff.depsgraph = bbd->sim->depsgraph;
temp_eff.scene = bbd->sim->scene;
eff = &temp_eff;
get_effector_data(eff, &efd, &epoint, 0);
@@ -1264,7 +1265,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
/* account for effectors */
pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
- pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
+ BKE_effectors_apply(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
float length = normalize_v3(force);
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index f80a13343d5..0ada712a855 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -478,13 +478,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
} \
} (void)0
- /* do via modifiers instead */
-#if 0
- if (ob->fluidsimSettings) {
- rewrite_path_fixed(ob->fluidsimSettings->surfdataPath, visit_cb, absbase, bpath_user_data);
- }
-#endif
-
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Fluidsim) {
FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
@@ -513,7 +506,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
}
if (ob->soft) {
- BPATH_TRAVERSE_POINTCACHE(ob->soft->ptcaches);
+ BPATH_TRAVERSE_POINTCACHE(ob->soft->shared->ptcaches);
}
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
@@ -588,14 +581,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
}
break;
}
- case ID_TE:
- {
- Tex *tex = (Tex *)id;
- if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format)) {
- rewrite_path_fixed(tex->vd->source_path, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
case ID_SCE:
{
Scene *scene = (Scene *)id;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 5b76d75f261..f8fd3c56eb1 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -29,6 +29,7 @@
#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -36,6 +37,7 @@
#include "BKE_brush.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -129,6 +131,7 @@ static void brush_defaults(Brush *brush)
brush->stencil_dimension[0] = 256;
brush->stencil_dimension[1] = 256;
+
}
/* Datablock add/copy/free/make_local */
@@ -164,6 +167,388 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
return brush;
}
+/* add grease pencil settings */
+void BKE_brush_init_gpencil_settings(Brush *brush)
+{
+ if (brush->gpencil_settings == NULL) {
+ brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings");
+ }
+
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->flag = 0;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+
+ /* curves */
+ brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+/* add a new gp-brush */
+Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name)
+{
+ Brush *brush;
+ Paint *paint = &ts->gp_paint->paint;
+ brush = BKE_brush_add(bmain, name, OB_MODE_GPENCIL_PAINT);
+
+ BKE_paint_brush_set(paint, brush);
+ id_us_min(&brush->id);
+
+ brush->size = 3;
+
+ /* grease pencil basic settings */
+ BKE_brush_init_gpencil_settings(brush);
+
+ /* return brush */
+ return brush;
+}
+
+/* grease pencil cumapping->preset */
+typedef enum eGPCurveMappingPreset {
+ GPCURVE_PRESET_PENCIL = 0,
+ GPCURVE_PRESET_INK = 1,
+ GPCURVE_PRESET_INKNOISE = 2,
+} eGPCurveMappingPreset;
+
+static void brush_gpencil_curvemap_reset(CurveMap *cuma, int preset)
+{
+ if (cuma->curve)
+ MEM_freeN(cuma->curve);
+
+ cuma->totpoint = 3;
+ cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
+
+ switch (preset) {
+ case GPCURVE_PRESET_PENCIL:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.75115f;
+ cuma->curve[1].y = 0.25f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INK:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63448f;
+ cuma->curve[1].y = 0.375f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INKNOISE:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63134f;
+ cuma->curve[1].y = 0.3625f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ }
+
+ if (cuma->table) {
+ MEM_freeN(cuma->table);
+ cuma->table = NULL;
+ }
+}
+
+/* create a set of grease pencil presets */
+void BKE_brush_gpencil_presets(bContext *C)
+{
+#define SMOOTH_STROKE_RADIUS 40
+#define SMOOTH_STROKE_FACTOR 0.9f
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = &ts->gp_paint->paint;
+ Main *bmain = CTX_data_main(C);
+
+ Brush *brush, *deft;
+ CurveMapping *custom_curve;
+
+ /* Pencil brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pen brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
+ deft = brush; /* save default brush */
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Ink brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.6f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INK);
+
+ /* Ink Noise brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.7f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 2;
+ brush->gpencil_settings->thick_smoothfac = 0.5f;
+ brush->gpencil_settings->thick_smoothlvl = 2;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INKNOISE);
+
+ /* Block Basic brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
+ brush->size = 150.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.7f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Marker brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
+ brush->size = 80.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.374f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = M_PI_4; /* 45 degrees */
+ brush->gpencil_settings->draw_angle_factor = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Fill brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
+ brush->size = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->fill_leak = 3;
+ brush->gpencil_settings->fill_threshold = 0.1f;
+ brush->gpencil_settings->fill_simplylvl = 1;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
+ brush->gpencil_tool = GPAINT_TOOL_FILL;
+
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ /* Soft Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
+ brush->size = 30.0f;
+ brush->gpencil_settings->draw_strength = 0.5f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+ brush->gpencil_settings->era_strength_f = 100.0f;
+ brush->gpencil_settings->era_thickness_f = 10.0f;
+
+ /* Hard Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
+ brush->size = 30.0f;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+ brush->gpencil_settings->era_strength_f = 100.0f;
+ brush->gpencil_settings->era_thickness_f = 50.0f;
+
+ /* Point Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
+
+ /* Stroke Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
+
+ /* set default brush */
+ BKE_paint_brush_set(paint, deft);
+
+}
+
+void BKE_brush_update_material(Main *bmain, Material *ma, Brush *exclude_brush)
+{
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if ((exclude_brush != NULL) && (brush == exclude_brush)) {
+ continue;
+ }
+
+ if (brush->gpencil_settings != NULL) {
+ BrushGpencilSettings *gpencil_settings = brush->gpencil_settings;
+ if (((gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) == 0) &&
+ (gpencil_settings->material != ma))
+ {
+ gpencil_settings->material = ma;
+ }
+ }
+ }
+}
+
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
{
Brush *brush;
@@ -197,6 +582,12 @@ void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *bru
}
brush_dst->curve = curvemapping_copy(brush_src->curve);
+ if (brush_src->gpencil_settings != NULL) {
+ brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings);
+ brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(brush_src->gpencil_settings->curve_sensitivity);
+ brush_dst->gpencil_settings->curve_strength = curvemapping_copy(brush_src->gpencil_settings->curve_strength);
+ brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(brush_src->gpencil_settings->curve_jitter);
+ }
/* enable fake user by default */
id_fake_user_set(&brush_dst->id);
@@ -215,11 +606,18 @@ void BKE_brush_free(Brush *brush)
if (brush->icon_imbuf) {
IMB_freeImBuf(brush->icon_imbuf);
}
-
curvemapping_free(brush->curve);
+ if (brush->gpencil_settings != NULL) {
+ curvemapping_free(brush->gpencil_settings->curve_sensitivity);
+ curvemapping_free(brush->gpencil_settings->curve_strength);
+ curvemapping_free(brush->gpencil_settings->curve_jitter);
+ MEM_SAFE_FREE(brush->gpencil_settings);
+ }
+
MEM_SAFE_FREE(brush->gradient);
+
BKE_previewimg_free(&(brush->preview));
}
diff --git a/source/blender/blenkernel/intern/bullet.c b/source/blender/blenkernel/intern/bullet.c
deleted file mode 100644
index 9630ee389fa..00000000000
--- a/source/blender/blenkernel/intern/bullet.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/bullet.c
- * \ingroup bke
- */
-
-
-#include "MEM_guardedalloc.h"
-
-/* types */
-#include "DNA_object_force_types.h" /* here is the softbody struct */
-
-#include "BKE_bullet.h"
-
-
-/* ************ Object level, exported functions *************** */
-
-/* allocates and initializes general main data */
-BulletSoftBody *bsbNew(void)
-{
- BulletSoftBody *bsb;
-
- bsb = MEM_callocN(sizeof(BulletSoftBody), "bulletsoftbody");
-
- bsb->flag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT;
- bsb->linStiff = 0.5f;
- bsb->angStiff = 1.0f;
- bsb->volume = 1.0f;
-
-
- bsb->viterations = 0;
- bsb->piterations = 2;
- bsb->diterations = 0;
- bsb->citerations = 4;
-
- bsb->kSRHR_CL = 0.1f;
- bsb->kSKHR_CL = 1.f;
- bsb->kSSHR_CL = 0.5f;
- bsb->kSR_SPLT_CL = 0.5f;
-
- bsb->kSK_SPLT_CL = 0.5f;
- bsb->kSS_SPLT_CL = 0.5f;
- bsb->kVCF = 1;
- bsb->kDP = 0;
-
- bsb->kDG = 0;
- bsb->kLF = 0;
- bsb->kPR = 0;
- bsb->kVC = 0;
-
- bsb->kDF = 0.2f;
- bsb->kMT = 0.05;
- bsb->kCHR = 1.0f;
- bsb->kKHR = 0.1f;
-
- bsb->kSHR = 1.0f;
- bsb->kAHR = 0.7f;
-
- bsb->collisionflags = 0;
- //bsb->collisionflags = OB_BSB_COL_CL_RS + OB_BSB_COL_CL_SS;
- bsb->numclusteriterations = 64;
- bsb->welding = 0.f;
-
- return bsb;
-}
-
-/* frees all */
-void bsbFree(BulletSoftBody *bsb)
-{
- /* no internal data yet */
- MEM_freeN(bsb);
-}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 151d697d891..5c27b1b6207 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -34,6 +34,7 @@
#include <math.h>
#include <assert.h>
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -41,8 +42,10 @@
#include "BLI_math.h"
#include "BLI_threads.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_bvhutils.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "MEM_guardedalloc.h"
@@ -423,7 +426,8 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
const MVert *vert, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BLI_assert(vert != NULL);
+ BVHTree *tree = NULL;
+
if (verts_mask) {
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
}
@@ -431,17 +435,19 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
verts_num_active = verts_num;
}
- BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ if (verts_num_active) {
+ tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (int i = 0; i < verts_num; i++) {
- if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
- continue;
+ if (tree) {
+ for (int i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
+ }
+ BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
- BLI_bvhtree_insert(tree, i, vert[i].co, 1);
+ BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
}
- BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
}
return tree;
@@ -463,7 +469,6 @@ static void bvhtree_from_mesh_verts_setup_data(
data->vert = vert;
data->vert_allocated = vert_allocated;
- //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */
}
/* Builds a bvh tree where nodes are the vertices of the given em */
@@ -489,12 +494,39 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache)
{
- return bvhtree_from_editmesh_verts_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
+ if (bvh_cache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data->cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data->cached = bvhcache_find(
+ *bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
+ if (data->cached == false) {
+ data->tree = bvhtree_from_editmesh_verts_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ bvh_cache, data->tree, BVHTREE_FROM_EM_VERTS);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ data->tree = bvhtree_from_editmesh_verts_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+ }
+
+ return data->tree;
}
/**
@@ -567,29 +599,31 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(
const BLI_bitmap *edges_mask, int edges_num_active,
float epsilon, int tree_type, int axis)
{
+ BVHTree *tree = NULL;
+
if (edges_mask) {
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
}
else {
edges_num_active = edge_num;
}
- BLI_assert(vert != NULL);
- BLI_assert(edge != NULL);
- /* Create a bvh-tree of the given target */
- BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (int i = 0; i < edge_num; i++) {
- if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
- continue;
- }
- float co[2][3];
- copy_v3_v3(co[0], vert[edge[i].v1].co);
- copy_v3_v3(co[1], vert[edge[i].v2].co);
+ if (edges_num_active) {
+ /* Create a bvh-tree of the given target */
+ tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ for (int i = 0; i < edge_num; i++) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], vert[edge[i].v1].co);
+ copy_v3_v3(co[1], vert[edge[i].v2].co);
- BLI_bvhtree_insert(tree, i, co[0], 2);
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_bvhtree_balance(tree);
}
- BLI_bvhtree_balance(tree);
}
return tree;
@@ -641,12 +675,39 @@ BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache)
{
- return bvhtree_from_editmesh_edges_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
+ if (bvh_cache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data->cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data->cached = bvhcache_find(
+ *bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
+ if (data->cached == false) {
+ data->tree = bvhtree_from_editmesh_edges_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ bvh_cache, data->tree, BVHTREE_FROM_EM_EDGES);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ data->tree = bvhtree_from_editmesh_edges_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+ }
+
+ return data->tree;
}
/**
@@ -833,22 +894,21 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
const BLI_bitmap *looptri_mask, int looptri_num_active)
{
BVHTree *tree = NULL;
- int i;
- if (looptri_num) {
- if (looptri_mask) {
- BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
- }
- else {
- looptri_num_active = looptri_num;
- }
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
+ }
+ else {
+ looptri_num_active = looptri_num;
+ }
+ if (looptri_num_active) {
/* Create a bvh-tree of the given target */
/* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
if (tree) {
if (vert && looptri) {
- for (i = 0; i < looptri_num; i++) {
+ for (int i = 0; i < looptri_num; i++) {
float co[3][3];
if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) {
continue;
@@ -902,23 +962,23 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
/* BMESH specific check that we have tessfaces,
* we _could_ tessellate here but rather not - campbell */
- BVHTree *tree;
+ BVHTree *tree = NULL;
if (bvhCache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
+ bool in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
- if (tree == NULL) {
+ if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
- if (tree == NULL) {
+ in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
+ if (in_cache == false) {
tree = bvhtree_from_editmesh_looptri_create_tree(
epsilon, tree_type, axis,
em, em->tottri, looptri_mask, looptri_num_active);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
- }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
+
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -976,189 +1036,233 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
return tree;
}
+static BLI_bitmap *loose_verts_map_get(
+ const MEdge *medge, int edges_num,
+ const MVert *UNUSED(mvert), int verts_num,
+ int *r_loose_vert_num)
+{
+ BLI_bitmap *loose_verts_mask = BLI_BITMAP_NEW(verts_num, __func__);
+ BLI_BITMAP_SET_ALL(loose_verts_mask, true, verts_num);
+
+ const MEdge *e = medge;
+ int num_linked_verts = 0;
+ for (;edges_num--; e++) {
+ if (BLI_BITMAP_TEST(loose_verts_mask, e->v1)) {
+ BLI_BITMAP_DISABLE(loose_verts_mask, e->v1);
+ num_linked_verts++;
+ }
+ if (BLI_BITMAP_TEST(loose_verts_mask, e->v2)) {
+ BLI_BITMAP_DISABLE(loose_verts_mask, e->v2);
+ num_linked_verts++;
+ }
+ }
+
+ *r_loose_vert_num = verts_num - num_linked_verts;
+
+ return loose_verts_mask;
+}
+
+static BLI_bitmap *loose_edges_map_get(
+ const MEdge *medge, const int edges_len,
+ int *r_loose_edge_len)
+{
+ BLI_bitmap *loose_edges_mask = BLI_BITMAP_NEW(edges_len, __func__);
+
+ int loose_edges_len = 0;
+ const MEdge *e = medge;
+ for (int i = 0; i < edges_len; i++, e++) {
+ if (e->flag & ME_LOOSEEDGE) {
+ BLI_BITMAP_ENABLE(loose_edges_mask, i);
+ loose_edges_len++;
+ }
+ else {
+ BLI_BITMAP_DISABLE(loose_edges_mask, i);
+ }
+ }
+
+ *r_loose_edge_len = loose_edges_len;
+
+ return loose_edges_mask;
+}
+
/**
* Builds or queries a bvhcache for the cache bvhtree of the request type.
*/
-BVHTree *bvhtree_from_mesh_get(
- struct BVHTreeFromMesh *data, struct DerivedMesh *dm,
+BVHTree *BKE_bvhtree_from_mesh_get(
+ struct BVHTreeFromMesh *data, struct Mesh *mesh,
const int type, const int tree_type)
{
- BVHTree *tree = NULL;
-
- BVHTree_NearestPointCallback nearest_callback = NULL;
- BVHTree_RayCastCallback raycast_callback = NULL;
-
- MVert *mvert = NULL;
- MEdge *medge = NULL;
- MFace *mface = NULL;
- MLoop *mloop = NULL;
- const MLoopTri *looptri = NULL;
- bool vert_allocated = false;
- bool edge_allocated = false;
- bool face_allocated = false;
- bool loop_allocated = false;
- bool looptri_allocated = false;
+ struct BVHTreeFromMesh data_cp = {0};
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(dm->bvhCache, type);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
BLI_rw_mutex_unlock(&cache_rwlock);
+ if (data_cp.cached && data_cp.tree == NULL) {
+ memset(data, 0, sizeof(*data));
+ return data_cp.tree;
+ }
+
switch (type) {
case BVHTREE_FROM_VERTS:
- raycast_callback = mesh_verts_spherecast;
+ case BVHTREE_FROM_LOOSEVERTS:
+ data_cp.raycast_callback = mesh_verts_spherecast;
- mvert = DM_get_vert_array(dm, &vert_allocated);
+ data_cp.vert = mesh->mvert;
- if (tree == NULL) {
- /* Not in cache */
+ if (data_cp.cached == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
- if (tree == NULL) {
- tree = bvhtree_from_mesh_verts_create_tree(
- 0.0, tree_type, 6, mvert, dm->getNumVerts(dm), NULL, -1);
-
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS);
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, type, &data_cp.tree);
+
+ if (data_cp.cached == false) {
+ BLI_bitmap *loose_verts_mask = NULL;
+ int loose_vert_len = -1;
+ int verts_len = mesh->totvert;
+
+ if (type == BVHTREE_FROM_LOOSEVERTS) {
+ loose_verts_mask = loose_verts_map_get(
+ mesh->medge, mesh->totedge, data_cp.vert,
+ verts_len, &loose_vert_len);
+ }
+
+ data_cp.tree = bvhtree_from_mesh_verts_create_tree(
+ 0.0, tree_type, 6, data_cp.vert, verts_len,
+ loose_verts_mask, loose_vert_len);
+
+ if (loose_verts_mask != NULL) {
+ MEM_freeN(loose_verts_mask);
}
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
case BVHTREE_FROM_EDGES:
- nearest_callback = mesh_edges_nearest_point;
- raycast_callback = mesh_edges_spherecast;
+ case BVHTREE_FROM_LOOSEEDGES:
+ data_cp.nearest_callback = mesh_edges_nearest_point;
+ data_cp.raycast_callback = mesh_edges_spherecast;
- mvert = DM_get_vert_array(dm, &vert_allocated);
- medge = DM_get_edge_array(dm, &edge_allocated);
+ data_cp.vert = mesh->mvert;
+ data_cp.edge = mesh->medge;
- if (tree == NULL) {
- /* Not in cache */
+ if (data_cp.cached == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
- if (tree == NULL) {
- tree = bvhtree_from_mesh_edges_create_tree(
- mvert, medge, dm->getNumEdges(dm),
- NULL, -1, 0.0, tree_type, 6);
-
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
+ if (data_cp.cached == false) {
+ BLI_bitmap *loose_edges_mask = NULL;
+ int loose_edges_len = -1;
+ int edges_len = mesh->totedge;
+
+ if (type == BVHTREE_FROM_LOOSEEDGES) {
+ loose_edges_mask = loose_edges_map_get(
+ data_cp.edge, edges_len, &loose_edges_len);
}
+
+ data_cp.tree = bvhtree_from_mesh_edges_create_tree(
+ data_cp.vert, data_cp.edge, edges_len,
+ loose_edges_mask, loose_edges_len, 0.0, tree_type, 6);
+
+ if (loose_edges_mask != NULL) {
+ MEM_freeN(loose_edges_mask);
+ }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
case BVHTREE_FROM_FACES:
- nearest_callback = mesh_faces_nearest_point;
- raycast_callback = mesh_faces_spherecast;
+ data_cp.nearest_callback = mesh_faces_nearest_point;
+ data_cp.raycast_callback = mesh_faces_spherecast;
- mvert = DM_get_vert_array(dm, &vert_allocated);
- mface = DM_get_tessface_array(dm, &face_allocated);
+ data_cp.vert = mesh->mvert;
+ data_cp.face = mesh->mface;
- if (tree == NULL) {
- /* Not in cache */
+ if (data_cp.cached == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
- if (tree == NULL) {
- int numFaces = dm->getNumTessFaces(dm);
- BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
-
- tree = bvhtree_from_mesh_faces_create_tree(
- 0.0, tree_type, 6, mvert, mface, numFaces, NULL, -1);
-
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_FACES);
- }
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, BVHTREE_FROM_FACES, &data_cp.tree);
+ if (data_cp.cached == false) {
+ int num_faces = mesh->totface;
+ BLI_assert(!(num_faces == 0 && mesh->totpoly != 0));
+
+ data_cp.tree = bvhtree_from_mesh_faces_create_tree(
+ 0.0, tree_type, 6, data_cp.vert,
+ data_cp.face, num_faces, NULL, -1);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_FACES);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
case BVHTREE_FROM_LOOPTRI:
- nearest_callback = mesh_looptri_nearest_point;
- raycast_callback = mesh_looptri_spherecast;
+ data_cp.nearest_callback = mesh_looptri_nearest_point;
+ data_cp.raycast_callback = mesh_looptri_spherecast;
- mvert = DM_get_vert_array(dm, &vert_allocated);
- mloop = DM_get_loop_array(dm, &loop_allocated);
- looptri = dm->getLoopTriArray(dm);
+ data_cp.vert = mesh->mvert;
+ data_cp.loop = mesh->mloop;
- if (tree == NULL) {
- /* Not in cache */
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
- if (tree == NULL) {
- int looptri_num = dm->getNumLoopTri(dm);
+ /* TODO: store looptris somewhere? */
+ data_cp.looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, BVHTREE_FROM_LOOPTRI, &data_cp.tree);
+ if (data_cp.cached == false) {
+ int looptri_num = BKE_mesh_runtime_looptri_len(mesh);
/* this assert checks we have looptris,
* if not caller should use DM_ensure_looptri() */
- BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0));
+ BLI_assert(!(looptri_num == 0 && mesh->totpoly != 0));
- tree = bvhtree_from_mesh_looptri_create_tree(
+ data_cp.tree = bvhtree_from_mesh_looptri_create_tree(
0.0, tree_type, 6,
- mvert, mloop, looptri, looptri_num, NULL, -1);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_LOOPTRI);
- }
+ data_cp.vert, data_cp.loop,
+ data_cp.looptri, looptri_num, NULL, -1);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_LOOPTRI);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
+ case BVHTREE_FROM_EM_VERTS:
+ case BVHTREE_FROM_EM_EDGES:
+ case BVHTREE_FROM_EM_LOOPTRI:
+ BLI_assert(false);
+ break;
}
- if (tree != NULL) {
+ if (data_cp.tree != NULL) {
#ifdef DEBUG
- if (BLI_bvhtree_get_tree_type(tree) != tree_type) {
- printf("tree_type %d obtained instead of %d\n", BLI_bvhtree_get_tree_type(tree), tree_type);
+ if (BLI_bvhtree_get_tree_type(data_cp.tree) != tree_type) {
+ printf("tree_type %d obtained instead of %d\n",
+ BLI_bvhtree_get_tree_type(data_cp.tree), tree_type);
}
#endif
- data->tree = tree;
-
- data->nearest_callback = nearest_callback;
- data->raycast_callback = raycast_callback;
-
- data->vert = mvert;
- data->edge = medge;
- data->face = mface;
- data->loop = mloop;
- data->looptri = looptri;
- data->vert_allocated = vert_allocated;
- data->edge_allocated = edge_allocated;
- data->face_allocated = face_allocated;
- data->loop_allocated = loop_allocated;
- data->looptri_allocated = looptri_allocated;
-
- data->cached = true;
+ data_cp.cached = true;
+ memcpy(data, &data_cp, sizeof(*data));
}
else {
- if (vert_allocated) {
- MEM_freeN(mvert);
- }
- if (edge_allocated) {
- MEM_freeN(medge);
- }
- if (face_allocated) {
- MEM_freeN(mface);
- }
- if (loop_allocated) {
- MEM_freeN(mloop);
- }
- if (looptri_allocated) {
- MEM_freeN((void *)looptri);
- }
-
+ free_bvhtree_from_mesh(&data_cp);
memset(data, 0, sizeof(*data));
}
- return tree;
+ return data_cp.tree;
}
/** \} */
@@ -1216,16 +1320,17 @@ typedef struct BVHCacheItem {
/**
* Queries a bvhcache for the cache bvhtree of the request type
*/
-BVHTree *bvhcache_find(BVHCache *cache, int type)
+bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree)
{
while (cache) {
const BVHCacheItem *item = cache->link;
if (item->type == type) {
- return item->tree;
+ *r_tree = item->tree;
+ return true;
}
cache = cache->next;
}
- return NULL;
+ return false;
}
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
@@ -1251,11 +1356,9 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
{
BVHCacheItem *item = NULL;
- assert(tree != NULL);
- assert(bvhcache_find(*cache_p, type) == NULL);
+ assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
- assert(item != NULL);
item->type = type;
item->tree = tree;
@@ -1264,13 +1367,8 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
}
/**
- * inits and frees a bvhcache
+ * frees a bvhcache
*/
-void bvhcache_init(BVHCache **cache_p)
-{
- *cache_p = NULL;
-}
-
static void bvhcacheitem_free(void *_item)
{
BVHCacheItem *item = (BVHCacheItem *)_item;
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 5f7759c7b55..c7d7a3a98eb 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -89,13 +89,22 @@ void BKE_cachefile_free(CacheFile *cache_file)
{
BKE_animdata_free((ID *)cache_file, false);
+ if (cache_file->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
+ if (cache_file->handle) {
#ifdef WITH_ALEMBIC
- ABC_free_handle(cache_file->handle);
+ ABC_free_handle(cache_file->handle);
#endif
-
+ cache_file->handle = NULL;
+ }
if (cache_file->handle_mutex) {
BLI_mutex_free(cache_file->handle_mutex);
+ cache_file->handle_mutex = NULL;
}
+
BLI_freelistN(&cache_file->object_paths);
}
@@ -110,8 +119,14 @@ void BKE_cachefile_free(CacheFile *cache_file)
void BKE_cachefile_copy_data(
Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag))
{
+ if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
cache_file_dst->handle = NULL;
- BLI_listbase_clear(&cache_file_dst->object_paths);
+ cache_file_dst->handle_mutex = NULL;
+ BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths);
}
CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file)
@@ -153,20 +168,24 @@ void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
BLI_mutex_lock(cache_file->handle_mutex);
if (cache_file->handle == NULL) {
+ /* Assigning to a CoW copy is a bad idea; assign to the original instead. */
+ BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
BKE_cachefile_reload(bmain, cache_file);
}
BLI_mutex_unlock(cache_file->handle_mutex);
}
-void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
+void BKE_cachefile_update_frame(
+ Main *bmain, struct Depsgraph *depsgraph, 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);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
if (!cache_file->is_sequence) {
continue;
@@ -175,7 +194,7 @@ void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, co
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
- BKE_cachefile_clean(scene, cache_file);
+ BKE_cachefile_clean(bmain, cache_file);
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
cache_file->handle = ABC_create_handle(filename, NULL);
@@ -215,11 +234,9 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f
}
/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
-void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
+void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file)
{
- for (Base *base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
-
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
if (md) {
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index bda26c95815..54ce0d3a903 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -40,6 +40,7 @@
#include "DNA_ID.h"
#include "BLI_math.h"
+#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -47,6 +48,7 @@
#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_object.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
@@ -54,7 +56,9 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "GPU_compositing.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
/****************************** Camera Datablock *****************************/
@@ -62,17 +66,18 @@ void BKE_camera_init(Camera *cam)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cam, id));
- cam->lens = 35.0f;
+ cam->lens = 50.0f;
cam->sensor_x = DEFAULT_SENSOR_WIDTH;
cam->sensor_y = DEFAULT_SENSOR_HEIGHT;
cam->clipsta = 0.1f;
- cam->clipend = 100.0f;
+ cam->clipend = 1000.0f;
cam->drawsize = 0.5f;
cam->ortho_scale = 6.0;
cam->flag |= CAM_SHOWPASSEPARTOUT;
cam->passepartalpha = 0.5f;
- GPU_fx_compositor_init_dof_settings(&cam->gpu_dof);
+ cam->gpu_dof.fstop = 128.0f;
+ cam->gpu_dof.ratio = 1.0f;
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
@@ -100,9 +105,9 @@ void *BKE_camera_add(Main *bmain, const char *name)
*
* \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *UNUSED(cam_dst), const Camera *UNUSED(cam_src), const int UNUSED(flag))
+void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *cam_dst, const Camera *cam_src, const int UNUSED(flag))
{
- /* Nothing to do! */
+ BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
}
Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
@@ -120,22 +125,13 @@ void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local)
/** Free (or release) any data used by this camera (does not free the camera itself). */
void BKE_camera_free(Camera *ca)
{
+ BLI_freelistN(&ca->bg_images);
+
BKE_animdata_free((ID *)ca, false);
}
/******************************** Camera Usage *******************************/
-void BKE_camera_object_mode(RenderData *rd, Object *cam_ob)
-{
- rd->mode &= ~(R_ORTHO | R_PANORAMA);
-
- if (cam_ob && cam_ob->type == OB_CAMERA) {
- Camera *cam = cam_ob->data;
- if (cam->type == CAM_ORTHO) rd->mode |= R_ORTHO;
- if (cam->type == CAM_PANO) rd->mode |= R_PANORAMA;
- }
-}
-
/* get the camera's dof value, takes the dof object into account */
float BKE_camera_object_dof_distance(Object *ob)
{
@@ -143,15 +139,10 @@ float BKE_camera_object_dof_distance(Object *ob)
if (ob->type != OB_CAMERA)
return 0.0f;
if (cam->dof_ob) {
-#if 0
- /* too simple, better to return the distance on the view axis only */
- return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]);
-#else
float view_dir[3], dof_dir[3];
normalize_v3_v3(view_dir, ob->obmat[2]);
sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof_ob->obmat[3]);
return fabsf(dot_v3v3(view_dir, dof_dir));
-#endif
}
return cam->YF_dofdist;
}
@@ -237,7 +228,7 @@ void BKE_camera_params_from_object(CameraParams *params, const Object *ob)
}
}
-void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d)
+void BKE_camera_params_from_view3d(CameraParams *params, Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d)
{
/* common */
params->lens = v3d->lens;
@@ -246,7 +237,8 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons
if (rv3d->persp == RV3D_CAMOB) {
/* camera view */
- BKE_camera_params_from_object(params, v3d->camera);
+ const Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ BKE_camera_params_from_object(params, ob_camera_eval);
params->zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
@@ -281,10 +273,7 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
float pixsize, viewfac, sensor_size, dx, dy;
int sensor_fit;
- /* fields rendering */
params->ycor = yasp / xasp;
- if (params->use_fields)
- params->ycor *= 2.0f;
if (params->is_ortho) {
/* orthographic camera */
@@ -326,18 +315,6 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
viewplane.xmax += dx;
viewplane.ymax += dy;
- /* fields offset */
- if (params->field_second) {
- if (params->field_odd) {
- viewplane.ymin -= 0.5f * params->ycor;
- viewplane.ymax -= 0.5f * params->ycor;
- }
- else {
- viewplane.ymin += 0.5f * params->ycor;
- viewplane.ymax += 0.5f * params->ycor;
- }
- }
-
/* the window matrix is used for clipping, and not changed during OSA steps */
/* using an offset of +0.5 here would give clip errors on edges */
viewplane.xmin *= pixsize;
@@ -641,7 +618,7 @@ static bool camera_frame_fit_calc_from_data(
/* don't move the camera, just yield the fit location */
/* r_scale only valid/useful for ortho cameras */
bool BKE_camera_view_frame_fit_to_scene(
- Main *bmain, Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3], float *r_scale)
+ Depsgraph *depsgraph, Scene *scene, Object *camera_ob, float r_co[3], float *r_scale)
{
CameraParams params;
CameraViewFrameData data_cb;
@@ -652,22 +629,24 @@ bool BKE_camera_view_frame_fit_to_scene(
camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
/* run callback on all visible points */
- BKE_scene_foreach_display_point(bmain, scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb);
+ BKE_scene_foreach_display_point(depsgraph, camera_to_frame_view_cb, &data_cb);
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
bool BKE_camera_view_frame_fit_to_coords(
- const Scene *scene, const float (*cos)[3], int num_cos, const Object *camera_ob,
+ const Depsgraph *depsgraph, const float (*cos)[3], int num_cos, Object *camera_ob,
float r_co[3], float *r_scale)
{
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
CameraParams params;
CameraViewFrameData data_cb;
/* just in case */
*r_scale = 1.0f;
- camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
+ camera_frame_fit_data_init(scene_eval, camera_ob_eval, &params, &data_cb);
/* run callback on all given coordinates */
while (num_cos--) {
@@ -679,12 +658,12 @@ bool BKE_camera_view_frame_fit_to_coords(
/******************* multiview matrix functions ***********************/
-static void camera_model_matrix(Object *camera, float r_modelmat[4][4])
+static void camera_model_matrix(const Object *camera, float r_modelmat[4][4])
{
copy_m4_m4(r_modelmat, camera->obmat);
}
-static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
+static void camera_stereo3d_model_matrix(const Object *camera, const bool is_left, float r_modelmat[4][4])
{
Camera *data = (Camera *)camera->data;
float interocular_distance, convergence_distance;
@@ -782,7 +761,7 @@ static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, flo
}
/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
-void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4])
+void BKE_camera_multiview_view_matrix(RenderData *rd, const Object *camera, const bool is_left, float r_viewmat[4][4])
{
BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
invert_m4(r_viewmat);
@@ -797,7 +776,7 @@ static bool camera_is_left(const char *viewname)
return true;
}
-void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
+void BKE_camera_multiview_model_matrix(RenderData *rd, const Object *camera, const char *viewname, float r_modelmat[4][4])
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
@@ -814,7 +793,7 @@ void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const cha
normalize_m4(r_modelmat);
}
-bool BKE_camera_multiview_spherical_stereo(RenderData *rd, Object *camera)
+bool BKE_camera_multiview_spherical_stereo(RenderData *rd, const Object *camera)
{
Camera *cam;
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
@@ -861,9 +840,9 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha
}
if (name[0] != '\0') {
- Base *base = BKE_scene_base_find_by_name(scene, name);
- if (base) {
- return base->object;
+ Object *ob = BKE_scene_object_find_by_name(scene, name);
+ if (ob != NULL) {
+ return ob;
}
}
@@ -887,7 +866,7 @@ Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *vi
}
}
-static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
+static float camera_stereo3d_shift_x(const Object *camera, const char *viewname)
{
Camera *data = camera->data;
float shift = data->shiftx;
@@ -925,7 +904,7 @@ static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
return shift;
}
-float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname)
+float BKE_camera_multiview_shift_x(RenderData *rd, const Object *camera, const char *viewname)
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
Camera *data = camera->data;
@@ -943,7 +922,7 @@ float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *v
}
}
-void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname)
+void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, const Object *camera, const char *viewname)
{
if (camera->type == OB_CAMERA) {
params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
@@ -960,3 +939,38 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set
r_fx_settings->dof->focus_distance = BKE_camera_object_dof_distance(camera);
}
}
+
+CameraBGImage *BKE_camera_background_image_new(Camera *cam)
+{
+ CameraBGImage *bgpic = MEM_callocN(sizeof(CameraBGImage), "Background Image");
+
+ bgpic->scale = 1.0f;
+ bgpic->alpha = 0.5f;
+ bgpic->iuser.ok = 1;
+ bgpic->iuser.flag |= IMA_ANIM_ALWAYS;
+ bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED;
+
+ BLI_addtail(&cam->bg_images, bgpic);
+
+ return bgpic;
+}
+
+void BKE_camera_background_image_remove(Camera *cam, CameraBGImage *bgpic)
+{
+ BLI_remlink(&cam->bg_images, bgpic);
+
+ MEM_freeN(bgpic);
+}
+
+void BKE_camera_background_image_clear(Camera *cam)
+{
+ CameraBGImage *bgpic = cam->bg_images.first;
+
+ while (bgpic) {
+ CameraBGImage *next_bgpic = bgpic->next;
+
+ BKE_camera_background_image_remove(cam, bgpic);
+
+ bgpic = next_bgpic;
+ }
+}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index ed2b8cddc14..1c3b75b1771 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -46,6 +46,7 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_editmesh.h"
#include "BKE_curve.h"
@@ -57,12 +58,6 @@
#include "MEM_guardedalloc.h"
-#include "GPU_buffers.h"
-#include "GPU_draw.h"
-#include "GPU_glew.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
#include <string.h>
#include <limits.h>
#include <math.h>
@@ -104,7 +99,7 @@ static int cdDM_getNumTessFaces(DerivedMesh *dm)
* to help debug tessfaces issues since BMESH merge. */
#if 0
if (dm->numTessFaceData == 0 && dm->numPolyData != 0) {
- printf("%s: has no faces!, call DM_ensure_tessface() if you need them\n");
+ printf("%s: has no faces!\n");
}
#endif
return dm->numTessFaceData;
@@ -295,7 +290,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
* this derivedmesh is just original mesh. it's the multires subsurf dm
* that this is actually for, to support a pbvh on a modified mesh */
if (!cddm->pbvh && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
bool deformed;
@@ -330,7 +325,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
totvert = deformdm->getNumVerts(deformdm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos, totvert);
MEM_freeN(vertCos);
}
}
@@ -338,1450 +333,6 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
return cddm->pbvh;
}
-/* update vertex normals so that drawing smooth faces works during sculpt
- * TODO: proper fix is to support the pbvh in all drawing modes */
-static void cdDM_update_normals_from_pbvh(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- float (*face_nors)[3];
-
- /* Some callbacks do not use optimal PBVH draw, so needs all the
- * possible data (like normals) to be copied from PBVH back to DM.
- *
- * This is safe to do if PBVH and DM are representing the same mesh,
- * which could be wrong when modifiers are enabled for sculpt.
- * So here we only doing update when there's no modifiers applied
- * during sculpt.
- *
- * It's safe to do nothing if there are modifiers, because in this
- * case modifier stack is re-constructed from scratch on every
- * update.
- */
- if (!cddm->pbvh_draw) {
- return;
- }
-
- face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- BKE_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors);
-}
-
-static void cdDM_drawVerts(DerivedMesh *dm)
-{
- GPU_vertex_setup(dm);
- if (dm->drawObject->tot_loop_verts)
- glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loop_verts);
- else
- glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loose_point);
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawUVEdges(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- int totpoly = dm->getNumPolys(dm);
- int prevstart = 0;
- bool prevdraw = true;
- int curpos = 0;
- int i;
-
- GPU_uvedge_setup(dm);
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
- if (prevdraw != draw) {
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- prevstart = curpos;
- }
-
- curpos += 2 * mpoly->totloop;
- prevdraw = draw;
- }
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUDrawObject *gdo;
- if (cddm->pbvh && cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH)
- {
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, true, false);
-
- return;
- }
-
- GPU_edge_setup(dm);
- gdo = dm->drawObject;
- if (gdo->edges && gdo->points) {
- if (drawAllEdges && drawLooseEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->totedge * 2);
- }
- else if (drawAllEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
- }
- else {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, dm->drawObject->tot_loose_edge_drawn * 2);
- }
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawLooseEdges(DerivedMesh *dm)
-{
- int start;
- int count;
-
- GPU_edge_setup(dm);
-
- start = (dm->drawObject->loose_edge_offset * 2);
- count = (dm->drawObject->totedge - dm->drawObject->loose_edge_offset) * 2;
-
- if (count) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
- }
-
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawFacesSolid(
- DerivedMesh *dm,
- float (*partial_redraw_planes)[4],
- bool UNUSED(fast), DMSetMaterial setMaterial)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- int a;
-
- if (cddm->pbvh) {
- if (cddm->pbvh_draw && BKE_pbvh_has_faces(cddm->pbvh)) {
- float (*face_nors)[3] = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors,
- setMaterial, false, false);
- return;
- }
- }
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- for (a = 0; a < dm->drawObject->totmaterial; a++) {
- if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
- GPU_buffer_draw_elements(
- dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- }
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawFacesTex_common(
- DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- const MLoopCol *mloopcol = NULL;
- int i;
- int colType, start_element, tot_drawn;
- const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
- const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- int totpoly;
- int next_actualFace;
- int mat_index;
- int tot_element;
-
- /* double lookup */
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: not entirely correct, but currently dynamic topology will
- * destroy UVs anyway, so textured display wouldn't work anyway
- *
- * this will do more like solid view with lights set up for
- * textured view, but object itself will be displayed gray
- * (the same as it'll display without UV maps in textured view)
- */
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- GPU_set_tpage(NULL, false, false);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- }
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- if (flag & DM_DRAW_USE_TEXPAINT_UV)
- GPU_texpaint_uv_setup(dm);
- else
- GPU_uv_setup(dm);
- if (mloopcol) {
- GPU_color_setup(dm, colType);
- }
-
- /* lastFlag = 0; */ /* UNUSED */
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- next_actualFace = bufmat->polys[0];
- totpoly = bufmat->totpolys;
-
- tot_element = 0;
- tot_drawn = 0;
- start_element = 0;
-
- for (i = 0; i < totpoly; i++) {
- int actualFace = bufmat->polys[i];
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
- int flush = 0;
- int tot_tri_verts;
-
- if (i != totpoly - 1)
- next_actualFace = bufmat->polys[i + 1];
-
- if (use_hide && (mpoly[actualFace].flag & ME_HIDE)) {
- draw_option = DM_DRAW_OPTION_SKIP;
- }
- else if (drawParams) {
- MTexPoly *tp = use_tface && mtexpoly ? &mtexpoly[actualFace] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mpoly[actualFace].mat_nr);
- }
- else {
- if (index_mp_to_orig) {
- const int orig = index_mp_to_orig[actualFace];
- if (orig == ORIGINDEX_NONE) {
- /* XXX, this is not really correct
- * it will draw the previous faces context for this one when we don't know its settings.
- * but better then skipping it altogether. - campbell */
- draw_option = DM_DRAW_OPTION_NORMAL;
- }
- else if (drawParamsMapped) {
- draw_option = drawParamsMapped(userData, orig, mpoly[actualFace].mat_nr);
- }
- }
- else if (drawParamsMapped) {
- draw_option = drawParamsMapped(userData, actualFace, mpoly[actualFace].mat_nr);
- }
- }
-
- /* flush buffer if current triangle isn't drawable or it's last triangle */
- flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- /* also compare draw options and flush buffer if they're different
- * need for face selection highlight in edit mode */
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3;
- tot_element += tot_tri_verts;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP)
- tot_drawn += tot_tri_verts;
-
- if (tot_drawn) {
- if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
- GPU_color_switch(1);
- else
- GPU_color_switch(0);
-
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
- start_element = tot_element;
- }
- else {
- tot_drawn += tot_tri_verts;
- }
- }
- }
-
- GPU_buffers_unbind();
-
-}
-
-static void cdDM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
-}
-
-static void cdDM_drawMappedFaces(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- const MLoopCol *mloopcol = NULL;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
- int colType;
- int i, j;
- int start_element = 0, tot_element, tot_drawn;
- int totpoly;
- int tot_tri_elem;
- int mat_index;
- GPUBuffer *findex_buffer = NULL;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- if (cddm->pbvh) {
- if (G.debug_value == 14)
- BKE_pbvh_draw_BB(cddm->pbvh);
- }
-
- /* fist, setup common buffers */
- GPU_vertex_setup(dm);
- GPU_triangle_setup(dm);
-
- totpoly = dm->getNumPolys(dm);
-
- /* if we do selection, fill the selection buffer color */
- if (G.f & G_BACKBUFSEL) {
- if (!(flag & DM_DRAW_SKIP_SELECT)) {
- Mesh *me = NULL;
- BMesh *bm = NULL;
- unsigned int *fi_map;
-
- if (flag & DM_DRAW_SELECT_USE_EDITMODE)
- bm = userData;
- else
- me = userData;
-
- findex_buffer = GPU_buffer_alloc(dm->drawObject->tot_loop_verts * sizeof(int));
- fi_map = GPU_buffer_lock(findex_buffer, GPU_BINDING_ARRAY);
-
- if (fi_map) {
- for (i = 0; i < totpoly; i++, mpoly++) {
- int selcol = 0xFFFFFFFF;
- const int orig = (index_mp_to_orig) ? index_mp_to_orig[i] : i;
- bool is_hidden;
-
- if (orig != ORIGINDEX_NONE) {
- if (use_hide) {
- if (flag & DM_DRAW_SELECT_USE_EDITMODE) {
- BMFace *efa = BM_face_at_index(bm, orig);
- is_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0;
- }
- else {
- is_hidden = (me->mpoly[orig].flag & ME_HIDE) != 0;
- }
-
- if (!is_hidden) {
- GPU_select_index_get(orig + 1, &selcol);
- }
- }
- else {
- GPU_select_index_get(orig + 1, &selcol);
- }
- }
-
- for (j = 0; j < mpoly->totloop; j++)
- fi_map[start_element++] = selcol;
- }
-
- start_element = 0;
- mpoly = cddm->mpoly;
-
- GPU_buffer_unlock(findex_buffer, GPU_BINDING_ARRAY);
- GPU_buffer_bind_as_color(findex_buffer);
- }
- }
- }
- else {
- GPU_normal_setup(dm);
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- }
-
- if (use_colors && mloopcol) {
- GPU_color_setup(dm, colType);
- }
- }
- }
-
- tot_tri_elem = dm->drawObject->tot_triangle_point;
-
- if (tot_tri_elem == 0) {
- /* avoid buffer problems in following code */
- }
- else if (setDrawOptions == NULL) {
- /* just draw the entire face array */
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tot_tri_elem);
- }
- else {
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
- int next_actualFace = bufmat->polys[0];
- totpoly = use_hide ? bufmat->totvisiblepolys : bufmat->totpolys;
-
- tot_element = 0;
- start_element = 0;
- tot_drawn = 0;
-
- if (setMaterial)
- draw_option = setMaterial(bufmat->mat_nr + 1, NULL);
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- DMDrawOption last_draw_option = DM_DRAW_OPTION_NORMAL;
-
- for (i = 0; i < totpoly; i++) {
- int actualFace = next_actualFace;
- int flush = 0;
- int tot_tri_verts;
-
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (i != totpoly - 1)
- next_actualFace = bufmat->polys[i + 1];
-
- if (setDrawOptions) {
- const int orig = (index_mp_to_orig) ? index_mp_to_orig[actualFace] : actualFace;
-
- if (orig != ORIGINDEX_NONE) {
- draw_option = setDrawOptions(userData, orig);
- }
- }
-
- /* Goal is to draw as long of a contiguous triangle
- * array as possible, so draw when we hit either an
- * invisible triangle or at the end of the array */
-
- /* flush buffer if current triangle isn't drawable or it's last triangle... */
- flush = (draw_option != last_draw_option) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3;
- tot_element += tot_tri_verts;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- tot_drawn += tot_tri_verts;
-
- if (last_draw_option != draw_option) {
- if (draw_option == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- }
- }
-
- if (tot_drawn) {
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
-
- last_draw_option = draw_option;
- start_element = tot_element;
- }
- else {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- tot_drawn += tot_tri_verts;
- }
- else {
- start_element = tot_element;
- }
- }
- }
- }
- }
- }
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
- GPU_buffers_unbind();
-
- if (findex_buffer)
- GPU_buffer_free(findex_buffer);
-
-}
-
-static void cdDM_drawMappedFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
-}
-
-static void cddm_draw_attrib_vertex(
- DMVertexAttribs *attribs, const MVert *mvert, int a, int index, int loop, int vert,
- const float *lnor, const bool smoothnormal)
-{
- DM_draw_attrib_vertex(attribs, a, index, vert, loop);
-
- /* vertex normal */
- if (lnor) {
- glNormal3fv(lnor);
- }
- else if (smoothnormal) {
- glNormal3sv(mvert[index].no);
- }
-
- /* vertex coordinate */
- glVertex3fv(mvert[index].co);
-}
-
-typedef struct {
- DMVertexAttribs attribs;
- int numdata;
-
- GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
-} GPUMaterialConv;
-
-static void cdDM_drawMappedFacesGLSL(
- DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUVertexAttribs gattribs;
- const MVert *mvert = cddm->mvert;
- const MPoly *mpoly = cddm->mpoly;
- const MLoop *mloop = cddm->mloop;
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- const int totpoly = dm->getNumPolys(dm);
- const short dm_totmat = dm->totmat;
- int a, b, matnr, new_matnr;
- bool do_draw;
- int orig;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: same as for solid draw, not entirely correct, but works fine for now,
- * will skip using textures (dyntopo currently destroys UV anyway) and
- * works fine for matcap
- */
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- setMaterial(1, &gattribs);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- matnr = -1;
- do_draw = false;
-
- if (setDrawOptions != NULL) {
- DMVertexAttribs attribs;
- DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n");
- memset(&attribs, 0, sizeof(attribs));
-
- glBegin(GL_TRIANGLES);
-
- for (a = 0; a < tottri; a++, lt++) {
- const MPoly *mp = &mpoly[lt->poly];
- const unsigned int vtri[3] = {mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v};
- const unsigned int *ltri = lt->tri;
- const float *ln1 = NULL, *ln2 = NULL, *ln3 = NULL;
- const bool smoothnormal = lnors || (mp->flag & ME_SMOOTH);
- new_matnr = mp->mat_nr;
-
- if (new_matnr != matnr) {
- glEnd();
-
- matnr = new_matnr;
- do_draw = setMaterial(matnr + 1, &gattribs);
- if (do_draw) {
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- if (!do_draw) {
- continue;
- }
- else /* if (setDrawOptions) */ {
- orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly;
-
- if (orig == ORIGINDEX_NONE) {
- /* since the material is set by setMaterial(), faces with no
- * origin can be assumed to be generated by a modifier */
-
- /* continue */
- }
- else if (setDrawOptions(userData, orig) == DM_DRAW_OPTION_SKIP)
- continue;
- }
-
- if (!smoothnormal) {
- if (nors) {
- glNormal3fv(nors[lt->poly]);
- }
- else {
- /* TODO ideally a normal layer should always be available */
- float nor[3];
- normal_tri_v3(nor, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- glNormal3fv(nor);
- }
- }
- else if (lnors) {
- ln1 = lnors[ltri[0]];
- ln2 = lnors[ltri[1]];
- ln3 = lnors[ltri[2]];
- }
-
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[0], ltri[0], 0, ln1, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[1], ltri[1], 1, ln2, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal);
- }
- glEnd();
- }
- else {
- GPUMaterialConv *matconv;
- int offset;
- int *mat_orig_to_new;
- int tot_active_mat;
- GPUBuffer *buffer = NULL;
- unsigned char *varray;
- size_t max_element_size = 0;
- int tot_loops = 0;
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
-
- tot_active_mat = dm->drawObject->totmaterial;
-
- matconv = MEM_calloc_arrayN(tot_active_mat, sizeof(*matconv),
- "cdDM_drawMappedFacesGLSL.matconv");
- mat_orig_to_new = MEM_malloc_arrayN(dm->totmat, sizeof(*mat_orig_to_new),
- "cdDM_drawMappedFacesGLSL.mat_orig_to_new");
-
- /* part one, check what attributes are needed per material */
- for (a = 0; a < tot_active_mat; a++) {
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- /* map from original material index to new
- * GPUBufferMaterial index */
- mat_orig_to_new[new_matnr] = a;
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- int numdata = 0;
- DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs);
-
- if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
- matconv[a].datatypes[numdata].size = 3;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- for (b = 0; b < matconv[a].attribs.tottface; b++) {
- if (matconv[a].attribs.tface[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 2;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.totmcol; b++) {
- if (matconv[a].attribs.mcol[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.tottang; b++) {
- if (matconv[a].attribs.tang[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- if (numdata != 0) {
- matconv[a].numdata = numdata;
- max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size);
- }
- }
- }
-
- /* part two, generate and fill the arrays with the data */
- if (max_element_size > 0) {
- buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
-
- varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
- if (varray == NULL) {
- GPU_buffers_unbind();
- GPU_buffer_free(buffer);
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- fprintf(stderr, "Out of memory, can't draw object\n");
- return;
- }
-
- for (a = 0; a < totpoly; a++, mpoly++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly->mat_nr, dm_totmat);
- int j;
- int i = mat_orig_to_new[mat_nr];
- offset = tot_loops * max_element_size;
-
- if (matconv[i].numdata != 0) {
- if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) {
- for (j = 0; j < mpoly->totloop; j++)
- copy_v3_v3((float *)&varray[offset + j * max_element_size],
- (float *)matconv[i].attribs.orco.array[mloop[mpoly->loopstart + j].v]);
- offset += sizeof(float) * 3;
- }
- for (b = 0; b < matconv[i].attribs.tottface; b++) {
- if (matconv[i].attribs.tface[b].array) {
- const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v2_v2((float *)&varray[offset + j * max_element_size], mloopuv[mpoly->loopstart + j].uv);
- offset += sizeof(float) * 2;
- }
- }
- for (b = 0; b < matconv[i].attribs.totmcol; b++) {
- if (matconv[i].attribs.mcol[b].array) {
- const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4_uchar(&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r);
- offset += sizeof(unsigned char) * 4;
- }
- }
- for (b = 0; b < matconv[i].attribs.tottang; b++) {
- if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
- offset += sizeof(float) * 4;
- }
- }
- }
-
- tot_loops += mpoly->totloop;
- }
- GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY);
- }
-
- for (a = 0; a < tot_active_mat; a++) {
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size);
- }
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_unbind();
- }
- }
- }
-
- GPU_buffers_unbind();
- if (buffer)
- GPU_buffer_free(buffer);
-
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- }
-}
-
-static void cdDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-static void cdDM_drawMappedFacesMat(
- DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUVertexAttribs gattribs;
- DMVertexAttribs attribs;
- MVert *mvert = cddm->mvert;
- const MPoly *mpoly = cddm->mpoly;
- const MLoop *mloop = cddm->mloop;
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int a, matnr, new_matnr;
- int orig;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: same as for solid draw, not entirely correct, but works fine for now,
- * will skip using textures (dyntopo currently destroys UV anyway) and
- * works fine for matcap
- */
-
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- setMaterial(userData, 1, &gattribs);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- matnr = -1;
-
- memset(&attribs, 0, sizeof(attribs));
-
- glBegin(GL_TRIANGLES);
-
- for (a = 0; a < tottri; a++, lt++) {
- const MPoly *mp = &mpoly[lt->poly];
- const unsigned int vtri[3] = {mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v};
- const unsigned int *ltri = lt->tri;
- const bool smoothnormal = lnors || (mp->flag & ME_SMOOTH);
- const float *ln1 = NULL, *ln2 = NULL, *ln3 = NULL;
-
- /* material */
- new_matnr = mp->mat_nr + 1;
-
- if (new_matnr != matnr) {
- glEnd();
-
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
-
- glBegin(GL_TRIANGLES);
- }
-
- /* skipping faces */
- if (setFace) {
- orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly;
-
- if (orig != ORIGINDEX_NONE && !setFace(userData, orig))
- continue;
- }
-
- /* smooth normal */
- if (!smoothnormal) {
- if (nors) {
- glNormal3fv(nors[lt->poly]);
- }
- else {
- /* TODO ideally a normal layer should always be available */
- float nor[3];
- normal_tri_v3(nor, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- glNormal3fv(nor);
- }
- }
- else if (lnors) {
- ln1 = lnors[ltri[0]];
- ln2 = lnors[ltri[1]];
- ln3 = lnors[ltri[2]];
- }
-
- /* vertices */
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[0], ltri[0], 0, ln1, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[1], ltri[1], 1, ln2, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal);
- }
- glEnd();
-}
-
-static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- MVert *vert = cddm->mvert;
- MEdge *edge = cddm->medge;
- int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
-
- glBegin(GL_LINES);
- for (i = 0; i < dm->numEdgeData; i++, edge++) {
- if (index) {
- orig = *index++;
- if (setDrawOptions && orig == ORIGINDEX_NONE) continue;
- }
- else
- orig = i;
-
- if (!setDrawOptions || (setDrawOptions(userData, orig) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(vert[edge->v1].co);
- glVertex3fv(vert[edge->v2].co);
- }
- }
- glEnd();
-}
-
-typedef struct FaceCount {
- unsigned int i_visible;
- unsigned int i_hidden;
- unsigned int i_tri_visible;
- unsigned int i_tri_hidden;
-} FaceCount;
-
-static void cdDM_buffer_copy_triangles(
- DerivedMesh *dm, unsigned int *varray,
- const int *mat_orig_to_new)
-{
- GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials;
- int i, j, start;
-
- const int gpu_totmat = dm->drawObject->totmaterial;
- const short dm_totmat = dm->totmat;
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int totpoly = dm->getNumPolys(dm);
-
- FaceCount *fc = MEM_malloc_arrayN(gpu_totmat, sizeof(*fc), "gpumaterial.facecount");
-
- for (i = 0; i < gpu_totmat; i++) {
- fc[i].i_visible = 0;
- fc[i].i_tri_visible = 0;
- fc[i].i_hidden = gpumaterials[i].totpolys - 1;
- fc[i].i_tri_hidden = gpumaterials[i].totelements - 1;
- }
-
- for (i = 0; i < totpoly; i++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat);
- int tottri = ME_POLY_TRI_TOT(&mpoly[i]);
- int mati = mat_orig_to_new[mat_nr];
- gpumat = gpumaterials + mati;
-
- if (mpoly[i].flag & ME_HIDE) {
- for (j = 0; j < tottri; j++, lt++) {
- start = gpumat->start + fc[mati].i_tri_hidden;
- /* v1 v2 v3 */
- varray[start--] = lt->tri[2];
- varray[start--] = lt->tri[1];
- varray[start--] = lt->tri[0];
- fc[mati].i_tri_hidden -= 3;
- }
- gpumat->polys[fc[mati].i_hidden--] = i;
- }
- else {
- for (j = 0; j < tottri; j++, lt++) {
- start = gpumat->start + fc[mati].i_tri_visible;
- /* v1 v2 v3 */
- varray[start++] = lt->tri[0];
- varray[start++] = lt->tri[1];
- varray[start++] = lt->tri[2];
- fc[mati].i_tri_visible += 3;
- }
- gpumat->polys[fc[mati].i_visible++] = i;
- }
- }
-
- /* set the visible polygons */
- for (i = 0; i < gpu_totmat; i++) {
- gpumaterials[i].totvisiblepolys = fc[i].i_visible;
- }
-
- MEM_freeN(fc);
-}
-
-static void cdDM_buffer_copy_vertex(
- DerivedMesh *dm, float *varray)
-{
- const MVert *mvert;
- const MPoly *mpoly;
- const MLoop *mloop;
-
- int i, j, start, totpoly;
-
- mvert = dm->getVertArray(dm);
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v3_v3(&varray[start], mvert[mloop[mpoly->loopstart + j].v].co);
- start += 3;
- }
- }
-
- /* copy loose points */
- j = dm->drawObject->tot_loop_verts * 3;
- for (i = 0; i < dm->drawObject->totvert; i++) {
- if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_loop_verts) {
- copy_v3_v3(&varray[j], mvert[i].co);
- j += 3;
- }
- }
-}
-
-static void cdDM_buffer_copy_normal(
- DerivedMesh *dm, short *varray)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- int i, j, totpoly;
- int start;
-
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-
- const MVert *mvert;
- const MPoly *mpoly;
- const MLoop *mloop;
-
- mvert = dm->getVertArray(dm);
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- /* we are in sculpt mode, disable loop normals (since they won't get updated) */
- if (cddm->pbvh)
- lnors = NULL;
-
- start = 0;
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool smoothnormal = (mpoly->flag & ME_SMOOTH) != 0;
-
- if (lnors) {
- /* Copy loop normals */
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- normal_float_to_short_v3(&varray[start], lnors[mpoly->loopstart + j]);
- }
- }
- else if (smoothnormal) {
- /* Copy vertex normal */
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- copy_v3_v3_short(&varray[start], mvert[mloop[mpoly->loopstart + j].v].no);
- }
- }
- else {
- /* Copy cached OR calculated face normal */
- short f_no_s[3];
-
- if (nors) {
- normal_float_to_short_v3(f_no_s, nors[i]);
- }
- else {
- float f_no[3];
- BKE_mesh_calc_poly_normal(mpoly, &mloop[mpoly->loopstart], mvert, f_no);
- normal_float_to_short_v3(f_no_s, f_no);
- }
-
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- copy_v3_v3_short(&varray[start], f_no_s);
- }
- }
- }
-}
-
-static void cdDM_buffer_copy_uv(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
-
- const MPoly *mpoly;
- const MLoopUV *mloopuv;
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- mpoly = dm->getPolyArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- start += 2;
- }
- }
-}
-
-static void cdDM_buffer_copy_uv_texpaint(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
-
- const MPoly *mpoly;
-
- int totmaterial = dm->totmat;
- const MLoopUV **uv_base;
- const MLoopUV *uv_stencil_base;
- int stencil;
-
- totpoly = dm->getNumPolys(dm);
-
- /* should have been checked for before, reassert */
- BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV));
- uv_base = MEM_malloc_arrayN(totmaterial, sizeof(*uv_base), "texslots");
-
- for (i = 0; i < totmaterial; i++) {
- uv_base[i] = DM_paint_uvlayer_active_get(dm, i);
- }
-
- stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV);
- uv_stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil);
-
- mpoly = dm->getPolyArray(dm);
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- int mat_i = mpoly->mat_nr;
-
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], uv_base[mat_i][mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], uv_stencil_base[mpoly->loopstart + j].uv);
- start += 4;
- }
- }
-
- MEM_freeN((void *)uv_base);
-}
-
-/* treat varray_ as an array of MCol, four MCol's per face */
-static void cdDM_buffer_copy_mcol(
- DerivedMesh *dm, unsigned char *varray,
- const void *user_data)
-{
- int i, j, totpoly;
- int start;
-
- const MLoopCol *mloopcol = user_data;
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v4_v4_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r);
- start += 4;
- }
- }
-}
-
-static void cdDM_buffer_copy_edge(
- DerivedMesh *dm, unsigned int *varray)
-{
- MEdge *medge, *medge_base;
- int i, totedge, iloose, inorm, iloosehidden, inormhidden;
- int tot_loose_hidden = 0, tot_loose = 0;
- int tot_hidden = 0, tot = 0;
-
- medge_base = medge = dm->getEdgeArray(dm);
- totedge = dm->getNumEdges(dm);
-
- for (i = 0; i < totedge; i++, medge++) {
- if (medge->flag & ME_EDGEDRAW) {
- if (medge->flag & ME_LOOSEEDGE) tot_loose++;
- else tot++;
- }
- else {
- if (medge->flag & ME_LOOSEEDGE) tot_loose_hidden++;
- else tot_hidden++;
- }
- }
-
- inorm = 0;
- inormhidden = tot;
- iloose = tot + tot_hidden;
- iloosehidden = iloose + tot_loose;
-
- medge = medge_base;
- for (i = 0; i < totedge; i++, medge++) {
- if (medge->flag & ME_EDGEDRAW) {
- if (medge->flag & ME_LOOSEEDGE) {
- varray[iloose * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[iloose * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- iloose++;
- }
- else {
- varray[inorm * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[inorm * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- inorm++;
- }
- }
- else {
- if (medge->flag & ME_LOOSEEDGE) {
- varray[iloosehidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[iloosehidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- iloosehidden++;
- }
- else {
- varray[inormhidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[inormhidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- inormhidden++;
- }
- }
- }
-
- dm->drawObject->tot_loose_edge_drawn = tot_loose;
- dm->drawObject->loose_edge_offset = tot + tot_hidden;
- dm->drawObject->tot_edge_drawn = tot;
-}
-
-static void cdDM_buffer_copy_uvedge(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
- const MLoopUV *mloopuv;
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- totpoly = dm->getNumPolys(dm);
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv);
- start += 4;
- }
- }
-}
-
-static void cdDM_copy_gpu_data(
- DerivedMesh *dm, int type, void *varray_p,
- const int *mat_orig_to_new, const void *user_data)
-{
- /* 'varray_p' cast is redundant but include for self-documentation */
- switch (type) {
- case GPU_BUFFER_VERTEX:
- cdDM_buffer_copy_vertex(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_NORMAL:
- cdDM_buffer_copy_normal(dm, (short *)varray_p);
- break;
- case GPU_BUFFER_COLOR:
- cdDM_buffer_copy_mcol(dm, (unsigned char *)varray_p, user_data);
- break;
- case GPU_BUFFER_UV:
- cdDM_buffer_copy_uv(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_UV_TEXPAINT:
- cdDM_buffer_copy_uv_texpaint(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_EDGE:
- cdDM_buffer_copy_edge(dm, (unsigned int *)varray_p);
- break;
- case GPU_BUFFER_UVEDGE:
- cdDM_buffer_copy_uvedge(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_TRIANGLES:
- cdDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new);
- break;
- default:
- break;
- }
-}
-
-/* add a new point to the list of points related to a particular
- * vertex */
-#ifdef USE_GPU_POINT_LINK
-
-static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
-{
- GPUVertPointLink *lnk;
-
- lnk = &gdo->vert_points[vert_index];
-
- /* if first link is in use, add a new link at the end */
- if (lnk->point_index != -1) {
- /* get last link */
- for (; lnk->next; lnk = lnk->next) ;
-
- /* add a new link from the pool */
- lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
- gdo->vert_points_usage++;
- }
-
- lnk->point_index = point_index;
-}
-
-#else
-
-static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
-{
- GPUVertPointLink *lnk;
- lnk = &gdo->vert_points[vert_index];
- if (lnk->point_index == -1) {
- lnk->point_index = point_index;
- }
-}
-
-#endif /* USE_GPU_POINT_LINK */
-
-/* for each vertex, build a list of points related to it; these lists
- * are stored in an array sized to the number of vertices */
-static void cdDM_drawobject_init_vert_points(
- GPUDrawObject *gdo,
- const MPoly *mpoly, const MLoop *mloop,
- int tot_poly)
-{
- int i;
- int tot_loops = 0;
-
- /* allocate the array and space for links */
- gdo->vert_points = MEM_malloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink),
- "GPUDrawObject.vert_points");
-#ifdef USE_GPU_POINT_LINK
- gdo->vert_points_mem = MEM_calloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink),
- "GPUDrawObject.vert_points_mem");
- gdo->vert_points_usage = 0;
-#endif
-
- /* -1 indicates the link is not yet used */
- for (i = 0; i < gdo->totvert; i++) {
-#ifdef USE_GPU_POINT_LINK
- gdo->vert_points[i].link = NULL;
-#endif
- gdo->vert_points[i].point_index = -1;
- }
-
- for (i = 0; i < tot_poly; i++) {
- int j;
- const MPoly *mp = &mpoly[i];
-
- /* assign unique indices to vertices of the mesh */
- for (j = 0; j < mp->totloop; j++) {
- cdDM_drawobject_add_vert_point(gdo, mloop[mp->loopstart + j].v, tot_loops + j);
- }
- tot_loops += mp->totloop;
- }
-
- /* map any unused vertices to loose points */
- for (i = 0; i < gdo->totvert; i++) {
- if (gdo->vert_points[i].point_index == -1) {
- gdo->vert_points[i].point_index = gdo->tot_loop_verts + gdo->tot_loose_point;
- gdo->tot_loose_point++;
- }
- }
-}
-
-/* see GPUDrawObject's structure definition for a description of the
- * data being initialized here */
-static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm)
-{
- GPUDrawObject *gdo;
- const MPoly *mpoly;
- const MLoop *mloop;
- const short dm_totmat = dm->totmat;
- GPUBufferMaterial *mat_info;
- int i, totloops, totpolys;
-
- /* object contains at least one material (default included) so zero means uninitialized dm */
- BLI_assert(dm_totmat != 0);
-
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
-
- totpolys = dm->getNumPolys(dm);
- totloops = dm->getNumLoops(dm);
-
- /* get the number of points used by each material, treating
- * each quad as two triangles */
- mat_info = MEM_calloc_arrayN(dm_totmat, sizeof(*mat_info), "GPU_drawobject_new.mat_orig_to_new");
-
- for (i = 0; i < totpolys; i++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat);
- mat_info[mat_nr].totpolys++;
- mat_info[mat_nr].totelements += 3 * ME_POLY_TRI_TOT(&mpoly[i]);
- mat_info[mat_nr].totloops += mpoly[i].totloop;
- }
- /* create the GPUDrawObject */
- gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
- gdo->totvert = dm->getNumVerts(dm);
- gdo->totedge = dm->getNumEdges(dm);
-
- GPU_buffer_material_finalize(gdo, mat_info, dm_totmat);
-
- gdo->tot_loop_verts = totloops;
-
- /* store total number of points used for triangles */
- gdo->tot_triangle_point = poly_to_tri_count(totpolys, totloops) * 3;
-
- cdDM_drawobject_init_vert_points(gdo, mpoly, mloop, totpolys);
-
- return gdo;
-}
-
static void cdDM_foreachMappedVert(
DerivedMesh *dm,
void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
@@ -1913,7 +464,7 @@ void CDDM_recalc_tessellation_ex(DerivedMesh *dm, const bool do_face_nor_cpy)
/* Tessellation recreated faceData, and the active layer indices need to get re-propagated
* from loops and polys to faces */
- CustomData_bmesh_update_active_layers(&dm->faceData, &dm->polyData, &dm->loopData);
+ CustomData_bmesh_update_active_layers(&dm->faceData, &dm->loopData);
}
void CDDM_recalc_tessellation(DerivedMesh *dm)
@@ -2005,24 +556,6 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getPBVH = cdDM_getPBVH;
dm->getPolyMap = cdDM_getPolyMap;
- dm->drawVerts = cdDM_drawVerts;
-
- dm->drawUVEdges = cdDM_drawUVEdges;
- dm->drawEdges = cdDM_drawEdges;
- dm->drawLooseEdges = cdDM_drawLooseEdges;
- dm->drawMappedEdges = cdDM_drawMappedEdges;
-
- dm->drawFacesSolid = cdDM_drawFacesSolid;
- dm->drawFacesTex = cdDM_drawFacesTex;
- dm->drawFacesGLSL = cdDM_drawFacesGLSL;
- dm->drawMappedFaces = cdDM_drawMappedFaces;
- dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
- dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL;
- dm->drawMappedFacesMat = cdDM_drawMappedFacesMat;
-
- dm->gpuObjectNew = cdDM_GPUobject_new;
- dm->copy_gpu_data = cdDM_copy_gpu_data;
-
dm->foreachMappedVert = cdDM_foreachMappedVert;
dm->foreachMappedEdge = cdDM_foreachMappedEdge;
dm->foreachMappedLoop = cdDM_foreachMappedLoop;
@@ -2062,20 +595,31 @@ DerivedMesh *CDDM_new(int numVerts, int numEdges, int numTessFaces, int numLoops
DerivedMesh *CDDM_from_mesh(Mesh *mesh)
{
+ return CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_MESH);
+}
+
+DerivedMesh *CDDM_from_mesh_ex(Mesh *mesh, eCDAllocType alloctype, CustomDataMask mask)
+{
CDDerivedMesh *cddm = cdDM_create(__func__);
DerivedMesh *dm = &cddm->dm;
- CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS);
- int alloctype;
+
+ mask &= ~CD_MASK_MDISPS;
/* this does a referenced copy, with an exception for fluidsim */
DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, 0 /* mesh->totface */,
mesh->totloop, mesh->totpoly);
+ /* This should actually be dm->deformedOnly = mesh->runtime.deformed_only,
+ * but only if the original mesh had its deformed_only flag correctly set
+ * (which isn't generally the case). */
dm->deformedOnly = 1;
dm->cd_flag = mesh->cd_flag;
- alloctype = CD_REFERENCE;
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ dm->dirty |= DM_DIRTY_NORMALS;
+ }
+ /* TODO DM_DIRTY_TESS_CDLAYERS ? Maybe not though, since we probably want to switch to looptris ? */
CustomData_merge(&mesh->vdata, &dm->vertData, mask, alloctype,
mesh->totvert);
@@ -2111,8 +655,8 @@ DerivedMesh *CDDM_from_curve(Object *ob)
{
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
return CDDM_from_curve_displist(ob, &disp);
@@ -2153,7 +697,6 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase)
if (alluv) {
const char *uvname = "Orco";
- CustomData_add_layer_named(&cddm->dm.polyData, CD_MTEXPOLY, CD_DEFAULT, NULL, totpoly, uvname);
CustomData_add_layer_named(&cddm->dm.loopData, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
}
@@ -2168,22 +711,18 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase)
static void loops_to_customdata_corners(
BMesh *bm, CustomData *facedata,
int cdindex, const BMLoop *l3[3],
- int numCol, int numTex)
+ int numCol, int numUV)
{
const BMLoop *l;
- BMFace *f = l3[0]->f;
+// BMFace *f = l3[0]->f;
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
int i, j, hasPCol = CustomData_has_layer(&bm->ldata, CD_PREVIEW_MLOOPCOL);
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
- texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
-
- ME_MTEXFACE_CPY(texface, texpoly);
for (j = 0; j < 3; j++) {
l = l3[j];
@@ -2213,6 +752,8 @@ static void loops_to_customdata_corners(
}
}
+/* TODO(campbell): remove, use BKE_mesh_from_bmesh_for_eval_nomain instead. */
+
/* used for both editbmesh and bmesh */
static DerivedMesh *cddm_from_bmesh_ex(
struct BMesh *bm, const bool use_mdisps,
@@ -2237,7 +778,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
MLoop *mloop = cddm->mloop;
MPoly *mpoly = cddm->mpoly;
int numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
- int numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ int numUV = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
int *index, add_orig;
CustomDataMask mask;
unsigned int i, j;
@@ -2267,7 +808,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
/* add tessellation mface layers */
if (use_tessface) {
- CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em_tottri);
+ CustomData_from_bmeshpoly(&dm->faceData, &dm->loopData, em_tottri);
}
index = dm->getVertDataArray(dm, CD_ORIGINDEX);
@@ -2339,7 +880,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
/* map mfaces to polygons in the same cddm intentionally */
*index++ = BM_elem_index_get(efa);
- loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex);
+ loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numUV);
test_index_face(mf, &dm->faceData, i, 3);
}
}
@@ -2397,16 +938,13 @@ DerivedMesh *CDDM_from_editbmesh(BMEditMesh *em, const bool use_mdisps, const bo
use_tessface, em->tottri, (const BMLoop *(*)[3])em->looptris);
}
-static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
- const bool need_tessface_data,
- const bool faces_from_tessfaces)
+DerivedMesh *CDDM_copy(DerivedMesh *source)
{
- const bool copy_tessface_data = (faces_from_tessfaces || need_tessface_data);
CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
DerivedMesh *dm = &cddm->dm;
int numVerts = source->numVertData;
int numEdges = source->numEdgeData;
- int numTessFaces = copy_tessface_data ? source->numTessFaceData : 0;
+ int numTessFaces = 0;
int numLoops = source->numLoopData;
int numPolys = source->numPolyData;
@@ -2416,9 +954,6 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
source->getVertDataArray(source, CD_ORIGINDEX);
source->getEdgeDataArray(source, CD_ORIGINDEX);
source->getPolyDataArray(source, CD_ORIGINDEX);
- if (copy_tessface_data) {
- source->getTessFaceDataArray(source, CD_ORIGINDEX);
- }
/* this initializes dm, and copies all non mvert/medge/mface layers */
DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces,
@@ -2430,15 +965,10 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
/* Tessellation data is never copied, so tag it here.
* Only tag dirty layers if we really ignored tessellation faces.
*/
- if (!copy_tessface_data) {
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
- }
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
- if (copy_tessface_data) {
- CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces);
- }
/* now add mvert/medge/mface layers */
cddm->mvert = source->dupVertArray(source);
@@ -2447,17 +977,7 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
- if (faces_from_tessfaces || copy_tessface_data) {
- cddm->mface = source->dupTessFaceArray(source);
- CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces);
- }
-
- if (!faces_from_tessfaces) {
- DM_DupPolys(source, dm);
- }
- else {
- CDDM_tessfaces_to_faces(dm);
- }
+ DM_DupPolys(source, dm);
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
@@ -2465,21 +985,6 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
return dm;
}
-DerivedMesh *CDDM_copy(DerivedMesh *source)
-{
- return cddm_copy_ex(source, false, false);
-}
-
-DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source)
-{
- return cddm_copy_ex(source, false, true);
-}
-
-DerivedMesh *CDDM_copy_with_tessface(DerivedMesh *source)
-{
- return cddm_copy_ex(source, true, false);
-}
-
/* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
* relationship between mesh data this needs to be set by the caller. */
DerivedMesh *CDDM_from_template_ex(
@@ -2748,813 +1253,6 @@ void CDDM_calc_loop_normals_spacearr(
#endif
}
-
-void CDDM_calc_normals_tessface(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- float (*face_nors)[3];
-
- if (dm->numVertData == 0) return;
-
- /* we don't want to overwrite any referenced layers */
- cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
-
- /* fill in if it exists */
- face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
- if (!face_nors) {
- face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, dm->numTessFaceData);
- }
-
- BKE_mesh_calc_normals_tessface(cddm->mvert, dm->numVertData,
- cddm->mface, dm->numTessFaceData, face_nors);
-
- cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
-}
-
-#if 1
-
-/**
- * Poly compare with vtargetmap
- * Function used by #CDDM_merge_verts.
- * The function compares poly_source after applying vtargetmap, with poly_target.
- * The two polys are identical if they share the same vertices in the same order, or in reverse order,
- * but starting position loopstart may be different.
- * The function is called with direct_reverse=1 for same order (i.e. same normal),
- * and may be called again with direct_reverse=-1 for reverse order.
- * \return 1 if polys are identical, 0 if polys are different.
- */
-static int cddm_poly_compare(
- MLoop *mloop_array,
- MPoly *mpoly_source, MPoly *mpoly_target,
- const int *vtargetmap, const int direct_reverse)
-{
- int vert_source, first_vert_source, vert_target;
- int i_loop_source;
- int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted;
- bool compare_completed = false;
- bool same_loops = false;
-
- MLoop *mloop_source, *mloop_target;
-
- BLI_assert(direct_reverse == 1 || direct_reverse == -1);
-
- i_loop_source = 0;
- mloop_source = mloop_array + mpoly_source->loopstart;
- vert_source = mloop_source->v;
-
- if (vtargetmap[vert_source] != -1) {
- vert_source = vtargetmap[vert_source];
- }
- else {
- /* All source loop vertices should be mapped */
- BLI_assert(false);
- }
-
- /* Find same vertex within mpoly_target's loops */
- mloop_target = mloop_array + mpoly_target->loopstart;
- for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) {
- if (mloop_target->v == vert_source) {
- break;
- }
- }
-
- /* If same vertex not found, then polys cannot be equal */
- if (i_loop_target >= mpoly_target->totloop) {
- return false;
- }
-
- /* Now mloop_source and m_loop_target have one identical vertex */
- /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */
- /* Go around the loop and check that all vertices match in same order */
- /* Skipping source loops when consecutive source vertices are mapped to same target vertex */
-
- i_loop_target_start = i_loop_target;
- i_loop_target_offset = 0;
- first_vert_source = vert_source;
-
- compare_completed = false;
- same_loops = false;
-
- while (!compare_completed) {
-
- vert_target = mloop_target->v;
-
- /* First advance i_loop_source, until it points to different vertex, after mapping applied */
- do {
- i_loop_source++;
-
- if (i_loop_source == mpoly_source->totloop) {
- /* End of loops for source, must match end of loop for target. */
- if (i_loop_target_offset == mpoly_target->totloop - 1) {
- compare_completed = true;
- same_loops = true;
- break; /* Polys are identical */
- }
- else {
- compare_completed = true;
- same_loops = false;
- break; /* Polys are different */
- }
- }
-
- mloop_source++;
- vert_source = mloop_source->v;
-
- if (vtargetmap[vert_source] != -1) {
- vert_source = vtargetmap[vert_source];
- }
- else {
- /* All source loop vertices should be mapped */
- BLI_assert(false);
- }
-
- } while (vert_source == vert_target);
-
- if (compare_completed) {
- break;
- }
-
- /* Now advance i_loop_target as well */
- i_loop_target_offset++;
-
- if (i_loop_target_offset == mpoly_target->totloop) {
- /* End of loops for target only, that means no match */
- /* except if all remaining source vertices are mapped to first target */
- for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) {
- vert_source = vtargetmap[mloop_source->v];
- if (vert_source != first_vert_source) {
- compare_completed = true;
- same_loops = false;
- break;
- }
- }
- if (!compare_completed) {
- same_loops = true;
- }
- break;
- }
-
- /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */
- i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop;
- if (i_loop_target_adjusted < 0) {
- i_loop_target_adjusted += mpoly_target->totloop;
- }
- mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted;
- vert_target = mloop_target->v;
-
- if (vert_target != vert_source) {
- same_loops = false; /* Polys are different */
- break;
- }
- }
- return same_loops;
-}
-
-/* Utility stuff for using GHash with polys */
-
-typedef struct PolyKey {
- int poly_index; /* index of the MPoly within the derived mesh */
- int totloops; /* number of loops in the poly */
- unsigned int hash_sum; /* Sum of all vertices indices */
- unsigned int hash_xor; /* Xor of all vertices indices */
-} PolyKey;
-
-
-static unsigned int poly_gset_hash_fn(const void *key)
-{
- const PolyKey *pk = key;
- return pk->hash_sum;
-}
-
-static bool poly_gset_compare_fn(const void *k1, const void *k2)
-{
- const PolyKey *pk1 = k1;
- const PolyKey *pk2 = k2;
- if ((pk1->hash_sum == pk2->hash_sum) &&
- (pk1->hash_xor == pk2->hash_xor) &&
- (pk1->totloops == pk2->totloops))
- {
- /* Equality - note that this does not mean equality of polys */
- return false;
- }
- else {
- return true;
- }
-}
-
-/**
- * Merge Verts
- *
- * This frees dm, and returns a new one.
- *
- * \param vtargetmap The table that maps vertices to target vertices. a value of -1
- * indicates a vertex is a target, and is to be kept.
- * This array is aligned with 'dm->numVertData'
- * \warning \a vtergatmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported
- * and will likely generate corrupted geometry.
- *
- * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size)
- *
- * \param merge_mode enum with two modes.
- * - #CDDM_MERGE_VERTS_DUMP_IF_MAPPED
- * When called by the Mirror Modifier,
- * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
- * of faces sharing the same set of vertices)
- * - #CDDM_MERGE_VERTS_DUMP_IF_EQUAL
- * When called by the Array Modifier,
- * In this mode, faces where all vertices are merged are double-checked,
- * to see whether all target vertices actually make up a poly already.
- * Indeed it could be that all of a poly's vertices are merged,
- * but merged to vertices that do not make up a single poly,
- * in which case the original poly should not be dumped.
- * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are
- * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror.
- *
- * \note #CDDM_recalc_tessellation has to run on the returned DM if you want to access tessfaces.
- */
-DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
-{
-// #define USE_LOOPS
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- CDDerivedMesh *cddm2 = NULL;
-
- const int totvert = dm->numVertData;
- const int totedge = dm->numEdgeData;
- const int totloop = dm->numLoopData;
- const int totpoly = dm->numPolyData;
-
- const int totvert_final = totvert - tot_vtargetmap;
-
- MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__);
- int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__);
- int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__);
- STACK_DECLARE(mvert);
- STACK_DECLARE(oldv);
-
- /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
- * generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
- * cases can be forged that would end requiring more... */
- MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__);
- int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__);
- int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__);
- STACK_DECLARE(medge);
- STACK_DECLARE(olde);
-
- MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__);
- int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__);
-#ifdef USE_LOOPS
- int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__);
-#endif
- STACK_DECLARE(mloop);
- STACK_DECLARE(oldl);
-
- MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__);
- int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__);
- STACK_DECLARE(mpoly);
- STACK_DECLARE(oldp);
-
- EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
-
- int i, j, c;
-
- PolyKey *poly_keys;
- GSet *poly_gset = NULL;
-
- STACK_INIT(oldv, totvert_final);
- STACK_INIT(olde, totedge);
- STACK_INIT(oldl, totloop);
- STACK_INIT(oldp, totpoly);
-
- STACK_INIT(mvert, totvert_final);
- STACK_INIT(medge, totedge);
- STACK_INIT(mloop, totloop);
- STACK_INIT(mpoly, totpoly);
-
- /* fill newv with destination vertex indices */
- mv = cddm->mvert;
- c = 0;
- for (i = 0; i < totvert; i++, mv++) {
- if (vtargetmap[i] == -1) {
- STACK_PUSH(oldv, i);
- STACK_PUSH(mvert, *mv);
- newv[i] = c++;
- }
- else {
- /* dummy value */
- newv[i] = 0;
- }
- }
-
- /* now link target vertices to destination indices */
- for (i = 0; i < totvert; i++) {
- if (vtargetmap[i] != -1) {
- newv[i] = newv[vtargetmap[i]];
- }
- }
-
- /* Don't remap vertices in cddm->mloop, because we need to know the original
- * indices in order to skip faces with all vertices merged.
- * The "update loop indices..." section further down remaps vertices in mloop.
- */
-
- /* now go through and fix edges and faces */
- med = cddm->medge;
- c = 0;
- for (i = 0; i < totedge; i++, med++) {
- const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
- if (LIKELY(v1 != v2)) {
- void **val_p;
-
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- newe[i] = POINTER_AS_INT(*val_p);
- }
- else {
- STACK_PUSH(olde, i);
- STACK_PUSH(medge, *med);
- newe[i] = c;
- *val_p = POINTER_FROM_INT(c);
- c++;
- }
- }
- else {
- newe[i] = -1;
- }
- }
-
- if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
- /* In this mode, we need to determine, whenever a poly' vertices are all mapped */
- /* if the targets already make up a poly, in which case the new poly is dropped */
- /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
- PolyKey *mpgh;
- poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__);
- poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
- /* Duplicates allowed because our compare function is not pure equality */
- BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
-
- mp = cddm->mpoly;
- mpgh = poly_keys;
- for (i = 0; i < totpoly; i++, mp++, mpgh++) {
- mpgh->poly_index = i;
- mpgh->totloops = mp->totloop;
- ml = cddm->mloop + mp->loopstart;
- mpgh->hash_sum = mpgh->hash_xor = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- mpgh->hash_sum += ml->v;
- mpgh->hash_xor ^= ml->v;
- }
- BLI_gset_insert(poly_gset, mpgh);
- }
-
- if (cddm->pmap) {
- MEM_freeN(cddm->pmap);
- MEM_freeN(cddm->pmap_mem);
- }
- /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */
- /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */
- BKE_mesh_vert_poly_map_create(&cddm->pmap, &cddm->pmap_mem,
- cddm->mpoly, cddm->mloop,
- totvert, totpoly, totloop);
- } /* done preparing for fast poly compare */
-
-
- mp = cddm->mpoly;
- mv = cddm->mvert;
- for (i = 0; i < totpoly; i++, mp++) {
- MPoly *mp_new;
-
- ml = cddm->mloop + mp->loopstart;
-
- /* check faces with all vertices merged */
- bool all_vertices_merged = true;
-
- for (j = 0; j < mp->totloop; j++, ml++) {
- if (vtargetmap[ml->v] == -1) {
- all_vertices_merged = false;
- /* This will be used to check for poly using several time the same vert. */
- mv[ml->v].flag &= ~ME_VERT_TMP_TAG;
- }
- else {
- /* This will be used to check for poly using several time the same vert. */
- mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG;
- }
- }
-
- if (UNLIKELY(all_vertices_merged)) {
- if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_MAPPED) {
- /* In this mode, all vertices merged is enough to dump face */
- continue;
- }
- else if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
- /* Additional condition for face dump: target vertices must make up an identical face */
- /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
- /* (2) second step is thorough but more costly poly compare */
- int i_poly, v_target;
- bool found = false;
- PolyKey pkey;
-
- /* Use poly_gset for fast (although not 100% certain) identification of same poly */
- /* First, make up a poly_summary structure */
- ml = cddm->mloop + mp->loopstart;
- pkey.hash_sum = pkey.hash_xor = 0;
- pkey.totloops = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
- pkey.hash_sum += v_target;
- pkey.hash_xor ^= v_target;
- pkey.totloops++;
- }
- if (BLI_gset_haskey(poly_gset, &pkey)) {
-
- /* There might be a poly that matches this one.
- * We could just leave it there and say there is, and do a "continue".
- * ... but we are checking whether there is an exact poly match.
- * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
- */
-
- /* Consider current loop again */
- ml = cddm->mloop + mp->loopstart;
- /* Consider the target of the loop's first vert */
- v_target = vtargetmap[ml->v];
- /* Now see if v_target belongs to a poly that shares all vertices with source poly,
- * in same order, or reverse order */
-
- for (i_poly = 0; i_poly < cddm->pmap[v_target].count; i_poly++) {
- MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly);
-
- if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) ||
- cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1))
- {
- found = true;
- break;
- }
- }
- if (found) {
- /* Current poly's vertices are mapped to a poly that is strictly identical */
- /* Current poly is dumped */
- continue;
- }
- }
- }
- }
-
-
- /* Here either the poly's vertices were not all merged
- * or they were all merged, but targets do not make up an identical poly,
- * the poly is retained.
- */
- ml = cddm->mloop + mp->loopstart;
-
- c = 0;
- MLoop *last_valid_ml = NULL;
- MLoop *first_valid_ml = NULL;
- bool need_edge_from_last_valid_ml = false;
- bool need_edge_to_first_valid_ml = false;
- int created_edges = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v;
-#ifndef NDEBUG
- {
- MLoop *next_ml = cddm->mloop + mp->loopstart + ((j + 1) % mp->totloop);
- uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v;
- med = cddm->medge + ml->e;
- uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
- BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1));
- }
-#endif
- /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */
- if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) {
- mv[mlv].flag |= ME_VERT_TMP_TAG;
-
- if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) {
- /* We need to create a new edge between last valid loop and this one! */
- void **val_p;
-
- uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
- uint v2 = mlv;
- BLI_assert(v1 != v2);
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- last_valid_ml->e = POINTER_AS_INT(*val_p);
- }
- else {
- const int new_eidx = STACK_SIZE(medge);
- STACK_PUSH(olde, olde[last_valid_ml->e]);
- STACK_PUSH(medge, cddm->medge[last_valid_ml->e]);
- medge[new_eidx].v1 = last_valid_ml->v;
- medge[new_eidx].v2 = ml->v;
- /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
- *val_p = POINTER_FROM_INT(new_eidx);
- created_edges++;
-
- last_valid_ml->e = new_eidx;
- }
- need_edge_from_last_valid_ml = false;
- }
-
-#ifdef USE_LOOPS
- newl[j + mp->loopstart] = STACK_SIZE(mloop);
-#endif
- STACK_PUSH(oldl, j + mp->loopstart);
- last_valid_ml = STACK_PUSH_RET_PTR(mloop);
- *last_valid_ml = *ml;
- if (first_valid_ml == NULL) {
- first_valid_ml = last_valid_ml;
- }
- c++;
-
- /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges
- * in that part of code make remapping later totally unreliable. */
- BLI_assert(newe[ml->e] != -1);
- last_valid_ml->e = newe[ml->e];
- }
- else {
- if (last_valid_ml != NULL) {
- need_edge_from_last_valid_ml = true;
- }
- else {
- need_edge_to_first_valid_ml = true;
- }
- }
- }
- if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) &&
- (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml)))
- {
- /* We need to create a new edge between last valid loop and first valid one! */
- void **val_p;
-
- uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
- uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v;
- BLI_assert(v1 != v2);
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- last_valid_ml->e = POINTER_AS_INT(*val_p);
- }
- else {
- const int new_eidx = STACK_SIZE(medge);
- STACK_PUSH(olde, olde[last_valid_ml->e]);
- STACK_PUSH(medge, cddm->medge[last_valid_ml->e]);
- medge[new_eidx].v1 = last_valid_ml->v;
- medge[new_eidx].v2 = first_valid_ml->v;
- /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
- *val_p = POINTER_FROM_INT(new_eidx);
- created_edges++;
-
- last_valid_ml->e = new_eidx;
- }
- need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false;
- }
-
- if (UNLIKELY(c == 0)) {
- BLI_assert(created_edges == 0);
- continue;
- }
- else if (UNLIKELY(c < 3)) {
- STACK_DISCARD(oldl, c);
- STACK_DISCARD(mloop, c);
- if (created_edges > 0) {
- for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) {
- BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL);
- }
- STACK_DISCARD(olde, created_edges);
- STACK_DISCARD(medge, created_edges);
- }
- continue;
- }
-
- mp_new = STACK_PUSH_RET_PTR(mpoly);
- *mp_new = *mp;
- mp_new->totloop = c;
- BLI_assert(mp_new->totloop >= 3);
- mp_new->loopstart = STACK_SIZE(mloop) - c;
-
- STACK_PUSH(oldp, i);
- } /* end of the loop that tests polys */
-
-
- if (poly_gset) {
- // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset));
-
- BLI_gset_free(poly_gset, NULL);
- MEM_freeN(poly_keys);
- }
-
- /*create new cddm*/
- cddm2 = (CDDerivedMesh *)CDDM_from_template(
- (DerivedMesh *)cddm, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly));
-
- /*update edge indices and copy customdata*/
- med = medge;
- for (i = 0; i < cddm2->dm.numEdgeData; i++, med++) {
- BLI_assert(newv[med->v1] != -1);
- med->v1 = newv[med->v1];
- BLI_assert(newv[med->v2] != -1);
- med->v2 = newv[med->v2];
-
- /* Can happen in case vtargetmap contains some double chains, we do not support that. */
- BLI_assert(med->v1 != med->v2);
-
- CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
- }
-
- /*update loop indices and copy customdata*/
- ml = mloop;
- for (i = 0; i < cddm2->dm.numLoopData; i++, ml++) {
- /* Edge remapping has already be done in main loop handling part above. */
- BLI_assert(newv[ml->v] != -1);
- ml->v = newv[ml->v];
-
- CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
- }
-
- /*copy vertex customdata*/
- mv = mvert;
- for (i = 0; i < cddm2->dm.numVertData; i++, mv++) {
- CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1);
- }
-
- /*copy poly customdata*/
- mp = mpoly;
- for (i = 0; i < cddm2->dm.numPolyData; i++, mp++) {
- CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1);
- }
-
- /*copy over data. CustomData_add_layer can do this, need to look it up.*/
- memcpy(cddm2->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
- memcpy(cddm2->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
- memcpy(cddm2->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
- memcpy(cddm2->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
-
- MEM_freeN(mvert);
- MEM_freeN(medge);
- MEM_freeN(mloop);
- MEM_freeN(mpoly);
-
- MEM_freeN(newv);
- MEM_freeN(newe);
-#ifdef USE_LOOPS
- MEM_freeN(newl);
-#endif
-
- MEM_freeN(oldv);
- MEM_freeN(olde);
- MEM_freeN(oldl);
- MEM_freeN(oldp);
-
- BLI_edgehash_free(ehash, NULL);
-
- /*free old derivedmesh*/
- dm->needsFree = 1;
- dm->release(dm);
-
- return (DerivedMesh *)cddm2;
-}
-#endif
-
-void CDDM_calc_edges_tessface(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- CustomData edgeData;
- EdgeSetIterator *ehi;
- MFace *mf = cddm->mface;
- MEdge *med;
- EdgeSet *eh;
- int i, *index, numEdges, numFaces = dm->numTessFaceData;
-
- eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces));
-
- for (i = 0; i < numFaces; i++, mf++) {
- BLI_edgeset_add(eh, mf->v1, mf->v2);
- BLI_edgeset_add(eh, mf->v2, mf->v3);
-
- if (mf->v4) {
- BLI_edgeset_add(eh, mf->v3, mf->v4);
- BLI_edgeset_add(eh, mf->v4, mf->v1);
- }
- else {
- BLI_edgeset_add(eh, mf->v3, mf->v1);
- }
- }
-
- numEdges = BLI_edgeset_len(eh);
-
- /* write new edges into a temporary CustomData */
- CustomData_reset(&edgeData);
- CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
- CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
-
- med = CustomData_get_layer(&edgeData, CD_MEDGE);
- index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
-
- for (ehi = BLI_edgesetIterator_new(eh), i = 0;
- BLI_edgesetIterator_isDone(ehi) == false;
- BLI_edgesetIterator_step(ehi), i++, med++, index++)
- {
- BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2);
-
- med->flag = ME_EDGEDRAW | ME_EDGERENDER;
- *index = ORIGINDEX_NONE;
- }
- BLI_edgesetIterator_free(ehi);
-
- /* free old CustomData and assign new one */
- CustomData_free(&dm->edgeData, dm->numEdgeData);
- dm->edgeData = edgeData;
- dm->numEdgeData = numEdges;
-
- cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
-
- BLI_edgeset_free(eh);
-}
-
-/* warning, this uses existing edges but CDDM_calc_edges_tessface() doesn't */
-void CDDM_calc_edges(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- CustomData edgeData;
- EdgeHashIterator *ehi;
- MPoly *mp = cddm->mpoly;
- MLoop *ml;
- MEdge *med, *origmed;
- EdgeHash *eh;
- unsigned int eh_reserve;
- int v1, v2;
- const int *eindex;
- int i, j, *index;
- const int numFaces = dm->numPolyData;
- const int numLoops = dm->numLoopData;
- int numEdges = dm->numEdgeData;
-
- eindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
- med = cddm->medge;
-
- eh_reserve = max_ii(med ? numEdges : 0, BLI_EDGEHASH_SIZE_GUESS_FROM_LOOPS(numLoops));
- eh = BLI_edgehash_new_ex(__func__, eh_reserve);
- if (med) {
- for (i = 0; i < numEdges; i++, med++) {
- BLI_edgehash_insert(eh, med->v1, med->v2, POINTER_FROM_INT(i + 1));
- }
- }
-
- for (i = 0; i < numFaces; i++, mp++) {
- ml = cddm->mloop + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++) {
- v1 = ml->v;
- v2 = ME_POLY_LOOP_NEXT(cddm->mloop, mp, j)->v;
- BLI_edgehash_reinsert(eh, v1, v2, NULL);
- }
- }
-
- numEdges = BLI_edgehash_len(eh);
-
- /* write new edges into a temporary CustomData */
- CustomData_reset(&edgeData);
- CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
- CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
-
- origmed = cddm->medge;
- med = CustomData_get_layer(&edgeData, CD_MEDGE);
- index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
-
- for (ehi = BLI_edgehashIterator_new(eh), i = 0;
- BLI_edgehashIterator_isDone(ehi) == false;
- BLI_edgehashIterator_step(ehi), ++i, ++med, ++index)
- {
- BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
- j = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
-
- if (j == 0 || !eindex) {
- med->flag = ME_EDGEDRAW | ME_EDGERENDER;
- *index = ORIGINDEX_NONE;
- }
- else {
- med->flag = ME_EDGEDRAW | ME_EDGERENDER | origmed[j - 1].flag;
- *index = eindex[j - 1];
- }
-
- BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(i));
- }
- BLI_edgehashIterator_free(ehi);
-
- /* free old CustomData and assign new one */
- CustomData_free(&dm->edgeData, dm->numEdgeData);
- dm->edgeData = edgeData;
- dm->numEdgeData = numEdges;
-
- cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
-
- mp = cddm->mpoly;
- for (i = 0; i < numFaces; i++, mp++) {
- ml = cddm->mloop + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++) {
- v1 = ml->v;
- v2 = ME_POLY_LOOP_NEXT(cddm->mloop, mp, j)->v;
- ml->e = POINTER_AS_INT(BLI_edgehash_lookup(eh, v1, v2));
- }
- }
-
- BLI_edgehash_free(eh, NULL);
-}
-
void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts)
{
BLI_assert(numVerts >= 0);
@@ -3654,20 +1352,6 @@ MPoly *CDDM_get_polys(DerivedMesh *dm)
return ((CDDerivedMesh *)dm)->mpoly;
}
-void CDDM_tessfaces_to_faces(DerivedMesh *dm)
-{
- /* converts mfaces to mpolys/mloops */
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
-
- BKE_mesh_convert_mfaces_to_mpolys_ex(
- NULL, &cddm->dm.faceData, &cddm->dm.loopData, &cddm->dm.polyData,
- cddm->dm.numEdgeData, cddm->dm.numTessFaceData,
- cddm->dm.numLoopData, cddm->dm.numPolyData,
- cddm->medge, cddm->mface,
- &cddm->dm.numLoopData, &cddm->dm.numPolyData,
- &cddm->mloop, &cddm->mpoly);
-}
-
void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert)
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 88d4766048f..e10cfc38164 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -33,6 +33,7 @@
#include "DNA_cloth_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -40,10 +41,14 @@
#include "BLI_edgehash.h"
#include "BLI_linklist.h"
-#include "BKE_cdderivedmesh.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "BKE_bvhutils.h"
#include "BKE_cloth.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
@@ -55,13 +60,19 @@
/* Prototypes for internal functions.
*/
static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*vertexCos)[3]);
-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_from_mesh ( ClothModifierData *clmd, Mesh *mesh );
+static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, 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 );
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh );
+static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh );
+static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh );
+static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh );
+
+typedef struct BendSpringRef {
+ int index;
+ int polys;
+ ClothSpring *spring;
+} BendSpringRef;
/******************************************************************************
*
@@ -80,13 +91,18 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->gravity[0] = 0.0;
clmd->sim_parms->gravity[1] = 0.0;
clmd->sim_parms->gravity[2] = -9.81;
- clmd->sim_parms->structural = 15.0;
- clmd->sim_parms->max_struct = 15.0;
- clmd->sim_parms->shear = 15.0;
+ clmd->sim_parms->tension = 15.0;
+ clmd->sim_parms->max_tension = 15.0;
+ clmd->sim_parms->compression = 15.0;
+ clmd->sim_parms->max_compression = 15.0;
+ clmd->sim_parms->shear = 5.0;
+ clmd->sim_parms->max_shear = 5.0;
clmd->sim_parms->bending = 0.5;
clmd->sim_parms->max_bend = 0.5;
+ clmd->sim_parms->tension_damp = 5.0;
+ clmd->sim_parms->compression_damp = 5.0;
+ clmd->sim_parms->shear_damp = 5.0;
clmd->sim_parms->bending_damping = 0.5;
- clmd->sim_parms->Cdis = 5.0;
clmd->sim_parms->Cvi = 1.0;
clmd->sim_parms->mass = 0.3f;
clmd->sim_parms->stepsPerFrame = 5;
@@ -101,7 +117,6 @@ void cloth_init(ClothModifierData *clmd )
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 */
clmd->coll_parms->self_friction = 5.0;
clmd->coll_parms->friction = 5.0;
@@ -109,8 +124,7 @@ void cloth_init(ClothModifierData *clmd )
clmd->coll_parms->epsilon = 0.015f;
clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED;
clmd->coll_parms->collision_list = NULL;
- clmd->coll_parms->self_loop_count = 1.0;
- clmd->coll_parms->selfepsilon = 0.75;
+ clmd->coll_parms->selfepsilon = 0.015;
clmd->coll_parms->vgroup_selfcol = 0;
/* These defaults are copied from softbody.c's
@@ -129,6 +143,8 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->voxel_cell_size = 0.1f;
+ clmd->sim_parms->bending_model = CLOTH_BENDING_ANGULAR;
+
if (!clmd->sim_parms->effector_weights)
clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL);
@@ -136,44 +152,6 @@ void cloth_init(ClothModifierData *clmd )
clmd->point_cache->step = 1;
}
-static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon)
-{
- unsigned int i;
- BVHTree *bvhtree;
- Cloth *cloth;
- ClothVertex *verts;
-
- if (!clmd)
- return NULL;
-
- cloth = clmd->clothObject;
-
- if (!cloth)
- return NULL;
-
- verts = cloth->verts;
-
- /* in the moment, return zero if no faces there */
- if (!cloth->mvert_num)
- return NULL;
-
- /* create quadtree with k=26 */
- bvhtree = BLI_bvhtree_new(cloth->mvert_num, epsilon, 4, 6);
-
- /* fill tree */
- for (i = 0; i < cloth->mvert_num; i++, verts++) {
- const float *co;
- co = verts->xold;
-
- BLI_bvhtree_insert(bvhtree, i, co, 1);
- }
-
- /* balance tree */
- BLI_bvhtree_balance(bvhtree);
-
- return bvhtree;
-}
-
static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon)
{
unsigned int i;
@@ -217,14 +195,21 @@ static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon
return bvhtree;
}
-void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
+void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self)
{
unsigned int i = 0;
Cloth *cloth = clmd->clothObject;
- BVHTree *bvhtree = cloth->bvhtree;
+ BVHTree *bvhtree;
ClothVertex *verts = cloth->verts;
const MVertTri *vt;
+ if (self) {
+ bvhtree = cloth->bvhselftree;
+ }
+ else {
+ bvhtree = cloth->bvhtree;
+ }
+
if (!bvhtree)
return;
@@ -236,12 +221,12 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
float co[3][3], co_moving[3][3];
bool ret;
- copy_v3_v3(co[0], verts[vt->tri[0]].txold);
- copy_v3_v3(co[1], verts[vt->tri[1]].txold);
- copy_v3_v3(co[2], verts[vt->tri[2]].txold);
-
/* copy new locations into array */
if (moving) {
+ copy_v3_v3(co[0], verts[vt->tri[0]].txold);
+ copy_v3_v3(co[1], verts[vt->tri[1]].txold);
+ copy_v3_v3(co[2], verts[vt->tri[2]].txold);
+
/* update moving positions */
copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
@@ -250,48 +235,11 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
}
else {
- ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
- }
+ copy_v3_v3(co[0], verts[vt->tri[0]].tx);
+ copy_v3_v3(co[1], verts[vt->tri[1]].tx);
+ copy_v3_v3(co[2], verts[vt->tri[2]].tx);
- /* check if tree is already full */
- if (ret == false) {
- break;
- }
- }
-
- BLI_bvhtree_update_tree(bvhtree);
- }
-}
-
-void bvhselftree_update_from_cloth(ClothModifierData *clmd, bool moving)
-{
- unsigned int i = 0;
- Cloth *cloth = clmd->clothObject;
- BVHTree *bvhtree = cloth->bvhselftree;
- ClothVertex *verts = cloth->verts;
- const MVertTri *vt;
-
- if (!bvhtree)
- return;
-
- vt = cloth->tri;
-
- /* update vertex position in bvh tree */
- if (verts && vt) {
- for (i = 0; i < cloth->mvert_num; i++, verts++) {
- const float *co, *co_moving;
- bool ret;
-
- co = verts->txold;
-
- /* copy new locations into array */
- if (moving) {
- /* update moving positions */
- co_moving = verts->tx;
- ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1);
- }
- else {
- ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1);
+ ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
}
/* check if tree is already full */
@@ -317,7 +265,7 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);
}
-static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
+static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
{
PointCache *cache;
@@ -340,12 +288,13 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
BKE_cloth_solver_set_positions(clmd);
clmd->clothObject->last_frame= MINFRAME-1;
+ clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame;
}
return 1;
}
-static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
+static int do_step_cloth(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
{
ClothVertex *verts = NULL;
Cloth *cloth;
@@ -357,7 +306,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/* simulate 1 frame forward */
cloth = clmd->clothObject;
verts = cloth->verts;
- mvert = result->getVertArray(result);
+ mvert = result->mvert;
/* force any pinned verts to their constrained location. */
for (i = 0; i < clmd->clothObject->mvert_num; i++, verts++) {
@@ -370,7 +319,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
mul_m4_v3(ob->obmat, verts->xconst);
}
- effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, clmd->sim_parms->effector_weights);
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH )
cloth_update_verts ( ob, clmd, result );
@@ -378,19 +327,22 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/* Support for dynamic vertex groups, changing from frame to frame */
cloth_apply_vgroup ( clmd, result );
- if ( clmd->sim_parms->flags & (CLOTH_SIMSETTINGS_FLAG_SEW | CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) )
+ if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) ||
+ (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min > 0.0f))
+ {
cloth_update_spring_lengths ( clmd, result );
+ }
cloth_update_springs( clmd );
// TIMEIT_START(cloth_step)
/* call the solver. */
- ret = BPH_cloth_solve(ob, framenr, clmd, effectors);
+ ret = BPH_cloth_solve(depsgraph, ob, framenr, clmd, effectors);
// TIMEIT_END(cloth_step)
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
// printf ( "%f\n", ( float ) tval() );
@@ -400,7 +352,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/************************************************
* clothModifier_do - main simulation function
************************************************/
-void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3])
+void clothModifier_do(ClothModifierData *clmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh, float (*vertexCos)[3])
{
PointCache *cache;
PTCacheID pid;
@@ -408,15 +360,14 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
int framenr, startframe, endframe;
int cache_result;
- clmd->scene= scene; /* nice to pass on later :) */
- framenr= (int)scene->r.cfra;
+ framenr = DEG_get_ctime(depsgraph);
cache= clmd->point_cache;
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->time_scale;
- if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->mvert_num)) {
+ if (clmd->sim_parms->reset || (clmd->clothObject && mesh->totvert != clmd->clothObject->mvert_num)) {
clmd->sim_parms->reset = 0;
cache->flag |= PTCACHE_OUTDATED;
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
@@ -425,9 +376,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
cache->flag &= ~PTCACHE_REDO_NEEDED;
}
- // unused in the moment, calculated separately in implicit.c
- clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
-
/* simulation is only active during a specific period */
if (framenr < startframe) {
BKE_ptcache_invalidate(cache);
@@ -438,12 +386,12 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
}
/* initialize simulation data if it didn't exist already */
- if (!do_init_cloth(ob, clmd, dm, framenr))
+ if (!do_init_cloth(ob, clmd, mesh, framenr))
return;
if (framenr == startframe) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- do_init_cloth(ob, clmd, dm, framenr);
+ do_init_cloth(ob, clmd, mesh, framenr);
BKE_ptcache_validate(cache, framenr);
cache->flag &= ~PTCACHE_REDO_NEEDED;
clmd->clothObject->last_frame= framenr;
@@ -479,9 +427,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
return;
}
- if (!can_simulate)
- return;
-
/* if on second frame, write cache for first frame */
if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
BKE_ptcache_write(&pid, startframe);
@@ -491,7 +436,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
/* do simulation */
BKE_ptcache_validate(cache, framenr);
- if (!do_step_cloth(ob, clmd, dm, framenr)) {
+ if (!do_step_cloth(depsgraph, ob, clmd, mesh, framenr)) {
BKE_ptcache_invalidate(cache);
}
else
@@ -528,6 +473,9 @@ void cloth_free_modifier(ClothModifierData *clmd )
while (search) {
ClothSpring *spring = search->link;
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
+
MEM_freeN ( spring );
search = search->next;
}
@@ -594,6 +542,9 @@ void cloth_free_modifier_extern(ClothModifierData *clmd )
while (search) {
ClothSpring *spring = search->link;
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
+
MEM_freeN ( spring );
search = search->next;
}
@@ -659,15 +610,11 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte
int cloth_uses_vgroup(ClothModifierData *clmd)
{
- return (((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) ||
- (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) ||
- (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW) ||
- (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF)) &&
- ((clmd->sim_parms->vgroup_mass>0) ||
- (clmd->sim_parms->vgroup_struct>0)||
- (clmd->sim_parms->vgroup_bend>0) ||
- (clmd->sim_parms->vgroup_shrink>0) ||
- (clmd->coll_parms->vgroup_selfcol>0)));
+ return (((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) && (clmd->coll_parms->vgroup_selfcol > 0)) ||
+ (clmd->sim_parms->vgroup_struct > 0) ||
+ (clmd->sim_parms->vgroup_bend > 0) ||
+ (clmd->sim_parms->vgroup_shrink > 0) ||
+ (clmd->sim_parms->vgroup_mass > 0));
}
/**
@@ -675,7 +622,7 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
*
**/
/* can be optimized to do all groups in one loop */
-static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh )
{
int i = 0;
int j = 0;
@@ -685,11 +632,11 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
/* float goalfac = 0; */ /* UNUSED */
ClothVertex *verts = NULL;
- if (!clmd || !dm) return;
+ if (!clmd || !mesh) return;
clothObj = clmd->clothObject;
- mvert_num = dm->getNumVerts(dm);
+ mvert_num = mesh->totvert;
verts = clothObj->verts;
@@ -697,7 +644,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
for (i = 0; i < mvert_num; i++, verts++) {
/* Reset Goal values to standard */
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )
+ if (clmd->sim_parms->vgroup_mass > 0)
verts->goal= clmd->sim_parms->defgoal;
else
verts->goal= 0.0f;
@@ -709,10 +656,10 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
- dvert = dm->getVertData ( dm, i, CD_MDEFORMVERT );
+ dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
if ( dvert ) {
for ( j = 0; j < dvert->totweight; j++ ) {
- if (( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass-1)) && (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )) {
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass - 1)) {
verts->goal = dvert->dw [j].weight;
/* goalfac= 1.0f; */ /* UNUSED */
@@ -725,15 +672,16 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
verts->flags |= CLOTH_VERT_FLAG_PINNED;
}
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) {
- if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct-1)) {
- verts->struct_stiff = dvert->dw [j].weight;
- verts->shear_stiff = dvert->dw [j].weight;
- }
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct - 1)) {
+ verts->struct_stiff = dvert->dw[j].weight;
+ }
- if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend-1)) {
- verts->bend_stiff = dvert->dw [j].weight;
- }
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shear - 1)) {
+ verts->shear_stiff = dvert->dw[j].weight;
+ }
+
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend - 1)) {
+ verts->bend_stiff = dvert->dw[j].weight;
}
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) {
@@ -743,12 +691,10 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
}
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) {
- if (clmd->sim_parms->vgroup_shrink > 0) {
- if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
- /* used for linear interpolation between min and max shrink factor based on weight */
- verts->shrink_factor = dvert->dw[j].weight;
- }
+ if (clmd->sim_parms->vgroup_shrink > 0) {
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
+ /* Used for linear interpolation between min and max shrink factor based on weight. */
+ verts->shrink_factor = dvert->dw[j].weight;
}
}
}
@@ -759,31 +705,25 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, int i1, int i2)
{
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) {
- /* linear interpolation between min and max shrink factor based on weight */
- float base = 1.0f - clmd->sim_parms->shrink_min;
- float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
+ /* Linear interpolation between min and max shrink factor based on weight. */
+ float base = 1.0f - clmd->sim_parms->shrink_min;
+ float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
- float k1 = base + delta * verts[i1].shrink_factor;
- float k2 = base + delta * verts[i2].shrink_factor;
+ float k1 = base + delta * verts[i1].shrink_factor;
+ float k2 = base + delta * verts[i2].shrink_factor;
- /* Use geometrical mean to average two factors since it behaves better
- for diagonals when a rectangle transforms into a trapezoid. */
- return sqrtf(k1 * k2);
- }
- else
- return 1.0f;
+ /* Use geometrical mean to average two factors since it behaves better
+ for diagonals when a rectangle transforms into a trapezoid. */
+ return sqrtf(k1 * k2);
}
-static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first)
+static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float UNUSED(framenr), int first)
{
int i = 0;
MVert *mvert = NULL;
ClothVertex *verts = NULL;
float (*shapekey_rest)[3] = NULL;
float tnull[3] = {0, 0, 0};
- Cloth *cloth = NULL;
- float maxdist = 0;
// If we have a clothObject, free it.
if ( clmd->clothObject != NULL ) {
@@ -796,8 +736,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" );
if ( clmd->clothObject ) {
clmd->clothObject->old_solver_type = 255;
- // clmd->clothObject->old_collision_type = 255;
- cloth = clmd->clothObject;
clmd->clothObject->edgeset = NULL;
}
else if (!clmd->clothObject) {
@@ -805,25 +743,25 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
return 0;
}
- // mesh input objects need DerivedMesh
- if ( !dm )
+ // mesh input objects need Mesh
+ if ( !mesh )
return 0;
- cloth_from_mesh ( clmd, dm );
+ cloth_from_mesh ( clmd, mesh );
// create springs
clmd->clothObject->springs = NULL;
clmd->clothObject->numsprings = -1;
if ( clmd->sim_parms->shapekey_rest && !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) )
- shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO );
+ shapekey_rest = CustomData_get_layer(&mesh->vdata, CD_CLOTH_ORCO);
- mvert = dm->getVertArray (dm);
+ mvert = mesh->mvert;
verts = clmd->clothObject->verts;
// set initial values
- for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) {
+ for ( i = 0; i < mesh->totvert; i++, verts++ ) {
if (first) {
copy_v3_v3(verts->x, mvert[i].co);
@@ -841,7 +779,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
verts->mass = clmd->sim_parms->mass;
verts->impulse_count = 0;
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )
+ if (clmd->sim_parms->vgroup_mass > 0)
verts->goal= clmd->sim_parms->defgoal;
else
verts->goal= 0.0f;
@@ -861,9 +799,9 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
// apply / set vertex groups
// has to be happen before springs are build!
- cloth_apply_vgroup (clmd, dm);
+ cloth_apply_vgroup (clmd, mesh);
- if ( !cloth_build_springs ( clmd, dm ) ) {
+ if ( !cloth_build_springs ( clmd, mesh ) ) {
cloth_free_modifier ( clmd );
modifier_setError(&(clmd->modifier), "Cannot build springs");
printf("cloth_free_modifier cloth_build_springs\n");
@@ -876,23 +814,18 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
if (!first)
BKE_cloth_solver_set_positions(clmd);
- clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
-
- for (i = 0; i < dm->getNumVerts(dm); i++) {
- maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f));
- }
-
- clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist );
+ clmd->clothObject->bvhtree = bvhtree_build_from_cloth (clmd, clmd->coll_parms->epsilon);
+ clmd->clothObject->bvhselftree = bvhtree_build_from_cloth(clmd, clmd->coll_parms->selfepsilon);
return 1;
}
-static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh )
{
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- const unsigned int mvert_num = dm->getNumVerts(dm);
- const unsigned int looptri_num = dm->getNumLoopTri(dm);
+ const MLoop *mloop = mesh->mloop;
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const unsigned int mvert_num = mesh->totvert;
+ const unsigned int looptri_num = mesh->runtime.looptris.len;
/* Allocate our vertices. */
clmd->clothObject->mvert_num = mvert_num;
@@ -913,7 +846,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
printf("cloth_free_modifier clmd->clothObject->looptri\n");
return;
}
- DM_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
+ BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
/* Free the springs since they can't be correct if the vertices
* changed.
@@ -924,7 +857,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
}
/***************************************************************************************
- * SPRING NETWORK BUILDING IMPLEMENTATION BEGIN
+ * SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION BEGIN
***************************************************************************************/
BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
@@ -951,13 +884,16 @@ static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num)
}
}
-static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist)
+static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist, BendSpringRef *spring_ref)
{
if ( cloth->springs != NULL ) {
LinkNode *search = cloth->springs;
while (search) {
ClothSpring *spring = search->link;
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
+
MEM_freeN ( spring );
search = search->next;
}
@@ -968,12 +904,49 @@ static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist)
cloth_free_edgelist(edgelist, cloth->mvert_num);
+ MEM_SAFE_FREE(spring_ref);
+
if (cloth->edgeset) {
BLI_edgeset_free(cloth->edgeset);
cloth->edgeset = NULL;
}
}
+BLI_INLINE void cloth_bend_poly_dir(ClothVertex *verts, int i, int j, int *inds, int len, float r_dir[3])
+{
+ float cent[3] = {0};
+ float fact = 1.0f / len;
+
+ for (int x = 0; x < len; x++) {
+ madd_v3_v3fl(cent, verts[inds[x]].xrest, fact);
+ }
+
+ normal_tri_v3(r_dir, verts[i].xrest, verts[j].xrest, cent);
+}
+
+static float cloth_spring_angle(ClothVertex *verts, int i, int j, int *i_a, int *i_b, int len_a, int len_b)
+{
+ float dir_a[3], dir_b[3];
+ float tmp[3], vec_e[3];
+ float sin, cos;
+
+ /* Poly vectors. */
+ cloth_bend_poly_dir(verts, j, i, i_a, len_a, dir_a);
+ cloth_bend_poly_dir(verts, i, j, i_b, len_b, dir_b);
+
+ /* Edge vector. */
+ sub_v3_v3v3(vec_e, verts[i].xrest, verts[j].xrest);
+ normalize_v3(vec_e);
+
+ /* Compute angle. */
+ cos = dot_v3v3(dir_a, dir_b);
+
+ cross_v3_v3v3(tmp, dir_a, dir_b);
+ sin = dot_v3v3(tmp, vec_e);
+
+ return atan2f(sin, cos);
+}
+
static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
@@ -998,7 +971,7 @@ static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
ClothHairData *hair_ij, *hair_kl;
bool is_root = spring->kl != prev_mn;
- if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) {
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) {
continue;
}
@@ -1017,24 +990,6 @@ static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x);
normalize_v3(dir_new);
-#if 0
- if (clmd->debug_data && (spring->ij == 0 || spring->ij == 1)) {
- float a[3], b[3];
-
- copy_v3_v3(a, cloth->verts[spring->kl].x);
-// BKE_sim_debug_data_add_dot(clmd->debug_data, cloth_vert ? cloth_vert->x : key->co, 1, 1, 0, "frames", 8246, p, k);
-
- mul_v3_v3fl(b, hair_frame[0], clmd->sim_parms->avg_spring_len);
- BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 1, 0, 0, "frames", 8247, spring->kl, spring->mn);
-
- mul_v3_v3fl(b, hair_frame[1], clmd->sim_parms->avg_spring_len);
- BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 1, 0, "frames", 8248, spring->kl, spring->mn);
-
- mul_v3_v3fl(b, hair_frame[2], clmd->sim_parms->avg_spring_len);
- BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 0, 1, "frames", 8249, spring->kl, spring->mn);
- }
-#endif
-
/* get local targets for kl/mn vertices by putting rest targets into the current frame,
* then multiply with the rest length to get the actual goals
*/
@@ -1073,7 +1028,7 @@ static void cloth_hair_update_bending_rest_targets(ClothModifierData *clmd)
ClothHairData *hair_ij, *hair_kl;
bool is_root = spring->kl != prev_mn;
- if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) {
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) {
continue;
}
@@ -1113,18 +1068,24 @@ static void cloth_update_springs( ClothModifierData *clmd )
while (search) {
ClothSpring *spring = search->link;
- spring->stiffness = 0.0f;
+ spring->lin_stiffness = 0.0f;
+
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ if (spring->type & CLOTH_SPRING_TYPE_BENDING) {
+ spring->ang_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ }
+ }
- if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
- spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
+ if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
+ spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
}
- else if (spring->type == CLOTH_SPRING_TYPE_SHEAR) {
- spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
+ else if (spring->type & CLOTH_SPRING_TYPE_SHEAR) {
+ spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
}
else if (spring->type == CLOTH_SPRING_TYPE_BENDING) {
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
}
- else if (spring->type == CLOTH_SPRING_TYPE_BENDING_ANG) {
+ else if (spring->type == CLOTH_SPRING_TYPE_BENDING_HAIR) {
ClothVertex *v1 = &cloth->verts[spring->ij];
ClothVertex *v2 = &cloth->verts[spring->kl];
if (clmd->hairdata) {
@@ -1132,7 +1093,7 @@ static void cloth_update_springs( ClothModifierData *clmd )
v1->bend_stiff = clmd->hairdata[spring->ij].bending_stiffness;
v2->bend_stiff = clmd->hairdata[spring->kl].bending_stiffness;
}
- spring->stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f;
+ spring->lin_stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f;
}
else if (spring->type == CLOTH_SPRING_TYPE_GOAL) {
/* Warning: Appending NEW goal springs does not work because implicit solver would need reset! */
@@ -1155,27 +1116,27 @@ static void cloth_update_springs( ClothModifierData *clmd )
}
/* Update rest verts, for dynamically deformable cloth */
-static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh )
{
unsigned int i = 0;
- MVert *mvert = dm->getVertArray (dm);
+ MVert *mvert = mesh->mvert;
ClothVertex *verts = clmd->clothObject->verts;
/* vertex count is already ensured to match */
- for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) {
+ for ( i = 0; i < mesh->totvert; 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 )
+/* Update spring rest length, for dynamically deformable cloth */
+static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh )
{
Cloth *cloth = clmd->clothObject;
LinkNode *search = cloth->springs;
unsigned int struct_springs = 0;
unsigned int i = 0;
- unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+ unsigned int mvert_num = (unsigned int)mesh->totvert;
float shrink_factor;
clmd->sim_parms->avg_spring_len = 0.0f;
@@ -1187,16 +1148,23 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *d
while (search) {
ClothSpring *spring = search->link;
- if ( spring->type != CLOTH_SPRING_TYPE_SEWING ) {
- if ( spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING) )
+ if (spring->type != CLOTH_SPRING_TYPE_SEWING) {
+ if (spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING)) {
shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- else
+ }
+ else {
shrink_factor = 1.0f;
+ }
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
+
+ if (spring->type & CLOTH_SPRING_TYPE_BENDING) {
+ spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
+ spring->pa, spring->pb, spring->la, spring->lb);
+ }
}
- if ( spring->type == CLOTH_SPRING_TYPE_STRUCTURAL ) {
+ if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
clmd->sim_parms->avg_spring_len += spring->restlen;
cloth->verts[spring->ij].avg_spring_len += spring->restlen;
cloth->verts[spring->kl].avg_spring_len += spring->restlen;
@@ -1206,12 +1174,14 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *d
search = search->next;
}
- if (struct_springs > 0)
+ if (struct_springs > 0) {
clmd->sim_parms->avg_spring_len /= struct_springs;
+ }
for (i = 0; i < mvert_num; i++) {
- if (cloth->verts[i].spring_count > 0)
+ if (cloth->verts[i].spring_count > 0) {
cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
+ }
}
}
@@ -1250,23 +1220,115 @@ void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3]
mul_m3_m3m3(mat, rot, mat);
}
-static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
+/* Add a shear and a bend spring between two verts within a poly. */
+static bool cloth_add_shear_bend_spring(ClothModifierData *clmd, LinkNodePair *edgelist,
+ const MLoop *mloop, const MPoly *mpoly, int i, int j, int k)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothSpring *spring;
+ const MLoop *tmp_loop;
+ float shrink_factor;
+ int x, y;
+
+ /* Combined shear/bend properties. */
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (!spring) {
+ return false;
+ }
+
+ spring_verts_ordered_set(spring,
+ mloop[mpoly[i].loopstart + j].v,
+ mloop[mpoly[i].loopstart + k].v);
+
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
+ spring->type |= CLOTH_SPRING_TYPE_SHEAR;
+ spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
+
+ if (edgelist) {
+ BLI_linklist_append(&edgelist[spring->ij], spring);
+ BLI_linklist_append(&edgelist[spring->kl], spring);
+ }
+
+ /* Bending specific properties. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ spring->type |= CLOTH_SPRING_TYPE_BENDING;
+
+ spring->la = k - j + 1;
+ spring->lb = mpoly[i].totloop - k + j + 1;
+
+ spring->pa = MEM_mallocN(sizeof(*spring->pa) * spring->la, "spring poly");
+ if (!spring->pa) {
+ return false;
+ }
+
+ spring->pb = MEM_mallocN(sizeof(*spring->pb) * spring->lb, "spring poly");
+ if (!spring->pb) {
+ return false;
+ }
+
+ tmp_loop = mloop + mpoly[i].loopstart;
+
+ for (x = 0; x < spring->la; x++) {
+ spring->pa[x] = tmp_loop[j + x].v;
+ }
+
+ for (x = 0; x <= j; x++) {
+ spring->pb[x] = tmp_loop[x].v;
+ }
+
+ for (y = k; y < mpoly[i].totloop; x++, y++) {
+ spring->pb[x] = tmp_loop[y].v;
+ }
+
+ spring->mn = -1;
+
+ spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
+ spring->pa, spring->pb, spring->la, spring->lb);
+
+ spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f;
+ }
+
+ BLI_linklist_prepend(&cloth->springs, spring);
+
+ return true;
+}
+
+BLI_INLINE bool cloth_bend_set_poly_vert_array(int **poly, int len, const MLoop *mloop)
+{
+ int *p = MEM_mallocN(sizeof(int) * len, "spring poly");
+
+ if (!p) {
+ return false;
+ }
+
+ for (int i = 0; i < len; i++, mloop++) {
+ p[i] = mloop->v;
+ }
+
+ *poly = p;
+
+ return true;
+}
+
+static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh )
{
Cloth *cloth = clmd->clothObject;
ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0;
- unsigned int i = 0;
- unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
- unsigned int numedges = (unsigned int)dm->getNumEdges (dm);
- unsigned int numpolys = (unsigned int)dm->getNumPolys(dm);
+ unsigned int mvert_num = (unsigned int)mesh->totvert;
+ unsigned int numedges = (unsigned int)mesh->totedge;
+ unsigned int numpolys = (unsigned int)mesh->totpoly;
float shrink_factor;
- const MEdge *medge = dm->getEdgeArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
+ const MEdge *medge = mesh->medge;
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
int index2 = 0; // our second vertex index
- LinkNodePair *edgelist;
+ LinkNodePair *edgelist = NULL;
EdgeSet *edgeset = NULL;
LinkNode *search = NULL, *search2 = NULL;
+ BendSpringRef *spring_ref = NULL;
// error handling
if ( numedges==0 )
@@ -1280,13 +1342,23 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
cloth->springs = NULL;
cloth->edgeset = NULL;
- edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" );
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ spring_ref = MEM_callocN(sizeof(*spring_ref) * numedges, "temp bend spring reference");
- if (!edgelist)
- return 0;
+ if (!spring_ref) {
+ return 0;
+ }
+ }
+ else {
+ edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" );
+
+ if (!edgelist) {
+ return 0;
+ }
+ }
- // structural springs
- for ( i = 0; i < numedges; i++ ) {
+ /* Structural springs. */
+ for (int i = 0; i < numedges; i++) {
spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
if ( spring ) {
@@ -1294,13 +1366,13 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) {
// handle sewing (loose edges will be pulled together)
spring->restlen = 0.0f;
- spring->stiffness = 1.0f;
+ spring->lin_stiffness = 1.0f;
spring->type = CLOTH_SPRING_TYPE_SEWING;
}
else {
shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
+ spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;
clmd->sim_parms->avg_spring_len += spring->restlen;
@@ -1315,9 +1387,13 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
struct_springs++;
BLI_linklist_prepend ( &cloth->springs, spring );
+
+ if (spring_ref) {
+ spring_ref[i].spring = spring;
+ }
}
else {
- cloth_free_errorsprings(cloth, edgelist);
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
return 0;
}
}
@@ -1325,86 +1401,147 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
if (struct_springs_real > 0)
clmd->sim_parms->avg_spring_len /= struct_springs_real;
- for (i = 0; i < mvert_num; i++) {
+ for (int i = 0; i < mvert_num; i++) {
if (cloth->verts[i].spring_count > 0)
cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
}
- // shear springs
- for (i = 0; i < numpolys; i++) {
- /* triangle faces already have shear springs due to structural geometry */
- if (mpoly[i].totloop == 4) {
- int j;
+ edgeset = BLI_edgeset_new_ex(__func__, numedges);
+ cloth->edgeset = edgeset;
- for (j = 0; j != 2; j++) {
- spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+ if (numpolys) {
+ for (int i = 0; i < numpolys; i++) {
+ /* Shear springs. */
+ /* Triangle faces already have shear springs due to structural geometry. */
+ if (mpoly[i].totloop > 3) {
+ for (int j = 1; j < mpoly[i].totloop - 1; j++) {
+ if (j > 1) {
+ if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, 0, j)) {
+ shear_springs++;
+
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ bend_springs++;
+ }
+ }
+ else {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+ }
+
+ for (int k = j + 2; k < mpoly[i].totloop; k++) {
+ if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, j, k)) {
+ shear_springs++;
- if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
- return 0;
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ bend_springs++;
+ }
+ }
+ else {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+ }
}
+ }
- spring_verts_ordered_set(
- spring,
- mloop[mpoly[i].loopstart + (j + 0)].v,
- mloop[mpoly[i].loopstart + (j + 2)].v);
+ /* Angular bending springs along struct springs. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ const MLoop *ml = mloop + mpoly[i].loopstart;
- shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->type = CLOTH_SPRING_TYPE_SHEAR;
- spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
+ for (int j = 0; j < mpoly[i].totloop; j++, ml++) {
+ BendSpringRef *curr_ref = &spring_ref[ml->e];
+ curr_ref->polys++;
- BLI_linklist_append(&edgelist[spring->ij], spring);
- BLI_linklist_append(&edgelist[spring->kl], spring);
+ /* First poly found for this edge, store poly index. */
+ if (curr_ref->polys == 1) {
+ curr_ref->index = i;
+ }
+ /* Second poly found for this edge, add bending data. */
+ else if (curr_ref->polys == 2) {
+ spring = curr_ref->spring;
+
+ spring->type |= CLOTH_SPRING_TYPE_BENDING;
- shear_springs++;
+ spring->la = mpoly[curr_ref->index].totloop;
+ spring->lb = mpoly[i].totloop;
- BLI_linklist_prepend(&cloth->springs, spring);
+ if (!cloth_bend_set_poly_vert_array(&spring->pa, spring->la, &mloop[mpoly[curr_ref->index].loopstart]) ||
+ !cloth_bend_set_poly_vert_array(&spring->pb, spring->lb, &mloop[mpoly[i].loopstart]))
+ {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+
+ spring->mn = ml->e;
+
+ spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
+ spring->pa, spring->pb, spring->la, spring->lb);
+
+ spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f;
+
+ bend_springs++;
+ }
+ /* Third poly found for this edge, remove bending data. */
+ else if (curr_ref->polys == 3) {
+ spring = curr_ref->spring;
+
+ spring->type &= ~CLOTH_SPRING_TYPE_BENDING;
+ MEM_freeN(spring->pa);
+ MEM_freeN(spring->pb);
+ spring->pa = NULL;
+ spring->pb = NULL;
+
+ bend_springs--;
+ }
+ }
}
}
- }
- edgeset = BLI_edgeset_new_ex(__func__, numedges);
- cloth->edgeset = edgeset;
+ /* Linear bending springs. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_LINEAR) {
+ search2 = cloth->springs;
- if (numpolys) {
- // bending springs
- search2 = cloth->springs;
- for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) {
- if ( !search2 )
- break;
+ for (int i = struct_springs; i < struct_springs+shear_springs; i++) {
+ if (!search2) {
+ break;
+ }
- tspring2 = search2->link;
- search = edgelist[tspring2->kl].list;
- while ( search ) {
- tspring = search->link;
- index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) );
+ tspring2 = search2->link;
+ search = edgelist[tspring2->kl].list;
+
+ while (search) {
+ tspring = search->link;
+ index2 = ((tspring->ij == tspring2->kl) ? (tspring->kl) : (tspring->ij));
+
+ /* Check for existing spring. */
+ /* Check also if startpoint is equal to endpoint. */
+ if ((index2 != tspring2->ij) &&
+ !BLI_edgeset_haskey(edgeset, tspring2->ij, index2))
+ {
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (!spring) {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
- // check for existing spring
- // check also if startpoint is equal to endpoint
- if ((index2 != tspring2->ij) &&
- !BLI_edgeset_haskey(edgeset, tspring2->ij, index2))
- {
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+ spring_verts_ordered_set(spring, tspring2->ij, index2);
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
+ spring->type = CLOTH_SPRING_TYPE_BENDING;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
+ bend_springs++;
- if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
- return 0;
+ BLI_linklist_prepend(&cloth->springs, spring);
}
- spring_verts_ordered_set(spring, tspring2->ij, index2);
- shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->type = CLOTH_SPRING_TYPE_BENDING;
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
- BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
- bend_springs++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
+ search = search->next;
}
- search = search->next;
+
+ search2 = search2->next;
}
- search2 = search2->next;
}
}
else if (struct_springs > 2) {
@@ -1419,7 +1556,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
return 0;
}
@@ -1427,8 +1564,8 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring->kl = tspring->ij;
spring->mn = tspring->kl;
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
- spring->type = CLOTH_SPRING_TYPE_BENDING_ANG;
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ spring->type = CLOTH_SPRING_TYPE_BENDING_HAIR;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
bend_springs++;
BLI_linklist_prepend ( &cloth->springs, spring );
@@ -1456,7 +1593,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
return 0;
}
@@ -1464,7 +1601,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring->kl = tspring->kl;
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
spring->type = CLOTH_SPRING_TYPE_BENDING;
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
bend_springs++;
BLI_linklist_prepend ( &cloth->springs, spring );
@@ -1481,17 +1618,18 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
/* note: the edges may already exist so run reinsert */
/* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */
- for (i = 0; i < numedges; i++) { /* struct springs */
+ for (int i = 0; i < numedges; i++) { /* struct springs */
BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2);
}
- for (i = 0; i < numpolys; i++) { /* edge springs */
+ for (int i = 0; i < numpolys; i++) { /* edge springs */
if (mpoly[i].totloop == 4) {
BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 0].v, mloop[mpoly[i].loopstart + 2].v);
BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 1].v, mloop[mpoly[i].loopstart + 3].v);
}
}
+ MEM_SAFE_FREE(spring_ref);
cloth->numsprings = struct_springs + shear_springs + bend_springs;
@@ -1506,5 +1644,5 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
} /* cloth_build_springs */
/***************************************************************************************
- * SPRING NETWORK BUILDING IMPLEMENTATION END
+ * SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION END
***************************************************************************************/
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
new file mode 100644
index 00000000000..7b7898392d4
--- /dev/null
+++ b/source/blender/blenkernel/intern/collection.c
@@ -0,0 +1,1200 @@
+/*
+ * ***** 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): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/collection.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_iterator.h"
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_threads.h"
+#include "BLT_translation.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_collection.h"
+#include "BKE_icons.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+
+#include "DNA_ID.h"
+#include "DNA_collection_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
+
+/******************************** Prototypes ********************************/
+
+static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us);
+static bool collection_child_remove(Collection *parent, Collection *collection);
+static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us);
+static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us);
+
+static CollectionChild *collection_find_child(Collection *parent, Collection *collection);
+static CollectionParent *collection_find_parent(Collection *child, Collection *collection);
+
+static bool collection_find_child_recursive(Collection *parent, Collection *collection);
+
+/***************************** Add Collection *******************************/
+
+/* Add new collection, without view layer syncing. */
+static Collection *collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
+{
+ /* Determine new collection name. */
+ char name[MAX_NAME];
+
+ if (name_custom) {
+ STRNCPY(name, name_custom);
+ }
+ else {
+ BKE_collection_new_name_get(collection_parent, name);
+ }
+
+ /* Create new collection. */
+ Collection *collection = BKE_libblock_alloc(bmain, ID_GR, name, 0);
+
+ /* We increase collection user count when linking to Collections. */
+ id_us_min(&collection->id);
+
+ /* Optionally add to parent collection. */
+ if (collection_parent) {
+ collection_child_add(collection_parent, collection, 0, true);
+ }
+
+ return collection;
+}
+
+/**
+ * Add a collection to a collection ListBase and synchronize all render layers
+ * The ListBase is NULL when the collection is to be added to the master collection
+ */
+Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
+{
+ Collection *collection = collection_add(bmain, collection_parent, name_custom);
+ BKE_main_collection_sync(bmain);
+ return collection;
+}
+
+/*********************** Free and Delete Collection ****************************/
+
+/** Free (or release) any data used by this collection (does not free the collection itself). */
+void BKE_collection_free(Collection *collection)
+{
+ /* No animdata here. */
+ BKE_previewimg_free(&collection->preview);
+
+ BLI_freelistN(&collection->gobject);
+ BLI_freelistN(&collection->children);
+ BLI_freelistN(&collection->parents);
+
+ BKE_collection_object_cache_free(collection);
+}
+
+/**
+ * Remove a collection, optionally removing its child objects or moving
+ * them to parent collections.
+ */
+bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
+{
+ /* Master collection is not real datablock, can't be removed. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BLI_assert(!"Scene master collection can't be deleted");
+ return false;
+ }
+
+ if (hierarchy) {
+ /* Remove child objects. */
+ CollectionObject *cob = collection->gobject.first;
+ while (cob != NULL) {
+ collection_object_remove(bmain, collection, cob->ob, true);
+ cob = collection->gobject.first;
+ }
+
+ /* Delete all child collections recursively. */
+ CollectionChild *child = collection->children.first;
+ while (child != NULL) {
+ BKE_collection_delete(bmain, child->collection, hierarchy);
+ child = collection->children.first;
+ }
+ }
+ else {
+ /* Link child collections into parent collection. */
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+ collection_child_add(parent, child->collection, 0, true);
+ }
+ }
+
+ CollectionObject *cob = collection->gobject.first;
+ while (cob != NULL) {
+ /* Link child object into parent collections. */
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+ collection_object_add(bmain, parent, cob->ob, 0, true);
+ }
+
+ /* Remove child object. */
+ collection_object_remove(bmain, collection, cob->ob, true);
+ cob = collection->gobject.first;
+ }
+ }
+
+ BKE_libblock_delete(bmain, collection);
+
+ BKE_main_collection_sync(bmain);
+
+ return true;
+}
+
+/***************************** Collection Copy *******************************/
+
+/**
+ * Only copy internal data of Collection ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_collection_copy_data(
+ Main *bmain, Collection *collection_dst, const Collection *collection_src, const int flag)
+{
+ /* Do not copy collection's preview (same behavior as for objects). */
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
+ BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
+ }
+ else {
+ collection_dst->preview = NULL;
+ }
+
+ collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_listbase_clear(&collection_dst->object_cache);
+
+ BLI_listbase_clear(&collection_dst->gobject);
+ BLI_listbase_clear(&collection_dst->children);
+ BLI_listbase_clear(&collection_dst->parents);
+
+ for (CollectionChild *child = collection_src->children.first; child; child = child->next) {
+ collection_child_add(collection_dst, child->collection, flag, false);
+ }
+ for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) {
+ collection_object_add(bmain, collection_dst, cob->ob, flag, false);
+ }
+}
+
+/**
+ * Makes a shallow copy of a Collection
+ *
+ * Add a new collection in the same level as the old one, copy any nested collections
+ * but link the objects to the new collection (as oppose to copy them).
+ */
+Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection)
+{
+ /* It's not allowed to copy the master collection. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BLI_assert("!Master collection can't be copied");
+ return NULL;
+ }
+
+ Collection *collection_new;
+ BKE_id_copy_ex(bmain, &collection->id, (ID **)&collection_new, 0, false);
+ id_us_min(&collection_new->id); /* Copying add one user by default, need to get rid of that one. */
+
+ /* Optionally add to parent. */
+ if (parent) {
+ if (collection_child_add(parent, collection_new, 0, true)) {
+ /* Put collection right after existing one. */
+ CollectionChild *child = collection_find_child(parent, collection);
+ CollectionChild *child_new = collection_find_child(parent, collection_new);
+
+ if (child && child_new) {
+ BLI_remlink(&parent->children, child_new);
+ BLI_insertlinkafter(&parent->children, child, child_new);
+ }
+ }
+ }
+
+ BKE_main_collection_sync(bmain);
+
+ return collection_new;
+}
+
+Collection *BKE_collection_copy_master(Main *bmain, Collection *collection, const int flag)
+{
+ BLI_assert(collection->flag & COLLECTION_IS_MASTER);
+
+ Collection *collection_dst = MEM_dupallocN(collection);
+ BKE_collection_copy_data(bmain, collection_dst, collection, flag);
+ return collection_dst;
+}
+
+void BKE_collection_copy_full(Main *UNUSED(bmain), Collection *UNUSED(collection))
+{
+ // TODO: implement full scene copy
+}
+
+void BKE_collection_make_local(Main *bmain, Collection *collection, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &collection->id, true, lib_local);
+}
+
+/********************************* Naming *******************************/
+
+/**
+ * The automatic/fallback name of a new collection.
+ */
+void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
+{
+ char *name;
+
+ if (!collection_parent) {
+ name = BLI_sprintfN("Collection");
+ }
+ else if (collection_parent->flag & COLLECTION_IS_MASTER) {
+ name = BLI_sprintfN("Collection %d", BLI_listbase_count(&collection_parent->children) + 1);
+ }
+ else {
+ const int number = BLI_listbase_count(&collection_parent->children) + 1;
+ const int digits = integer_digits_i(number);
+ const int max_len =
+ sizeof(collection_parent->id.name) - 1 /* NULL terminator */ - (1 + digits) /* " %d" */ - 2 /* ID */;
+ name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number);
+ }
+
+ BLI_strncpy(rname, name, MAX_NAME);
+ MEM_freeN(name);
+}
+
+/**
+ * The name to show in the interface.
+ */
+const char *BKE_collection_ui_name_get(struct Collection *collection)
+{
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return IFACE_("Scene Collection");
+ }
+ else {
+ return collection->id.name + 2;
+ }
+}
+
+/* **************** Object List Cache *******************/
+
+static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict)
+{
+ int child_restrict = collection->flag | parent_restrict;
+
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object));
+
+ if (base == NULL) {
+ base = MEM_callocN(sizeof(Base), "Object Base");
+ base->object = cob->ob;
+ BLI_addtail(lb, base);
+ }
+
+ int object_restrict = base->object->restrictflag;
+
+ if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
+ ((object_restrict & OB_RESTRICT_VIEW) == 0))
+ {
+ base->flag |= BASE_ENABLED_VIEWPORT;
+ }
+
+ if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) &&
+ ((object_restrict & OB_RESTRICT_RENDER) == 0))
+ {
+ base->flag |= BASE_ENABLED_RENDER;
+ }
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ collection_object_cache_fill(lb, child->collection, child_restrict);
+ }
+}
+
+ListBase BKE_collection_object_cache_get(Collection *collection)
+{
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
+ static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
+
+ BLI_mutex_lock(&cache_lock);
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
+ collection_object_cache_fill(&collection->object_cache, collection, 0);
+ collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
+ }
+ BLI_mutex_unlock(&cache_lock);
+ }
+
+ return collection->object_cache;
+}
+
+static void collection_object_cache_free(Collection *collection)
+{
+ /* Clear own cache an for all parents, since those are affected by changes as well. */
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_freelistN(&collection->object_cache);
+
+ for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
+ collection_object_cache_free(parent->collection);
+ }
+}
+
+void BKE_collection_object_cache_free(Collection *collection)
+{
+ collection_object_cache_free(collection);
+}
+
+Base *BKE_collection_or_layer_objects(const ViewLayer *view_layer, Collection *collection)
+{
+ if (collection) {
+ return BKE_collection_object_cache_get(collection).first;
+ }
+ else {
+ return FIRSTBASE(view_layer);
+ }
+}
+
+/*********************** Scene Master Collection ***************/
+
+Collection *BKE_collection_master_add()
+{
+ /* Not an actual datablock, but owned by scene. */
+ Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection");
+ STRNCPY(master_collection->id.name, "GRMaster Collection");
+ master_collection->flag |= COLLECTION_IS_MASTER;
+ return master_collection;
+}
+
+Collection *BKE_collection_master(const Scene *scene)
+{
+ return scene->master_collection;
+}
+
+/*********************** Cyclic Checks ************************/
+
+static bool collection_object_cyclic_check_internal(Object *object, Collection *collection)
+{
+ if (object->dup_group) {
+ Collection *dup_collection = object->dup_group;
+ if ((dup_collection->id.tag & LIB_TAG_DOIT) == 0) {
+ /* Cycle already exists in collections, let's prevent further crappyness */
+ return true;
+ }
+ /* flag the object to identify cyclic dependencies in further dupli collections */
+ dup_collection->id.tag &= ~LIB_TAG_DOIT;
+
+ if (dup_collection == collection) {
+ return true;
+ }
+ else {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(dup_collection, collection_object)
+ {
+ if (collection_object_cyclic_check_internal(collection_object, dup_collection)) {
+ return true;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ /* un-flag the object, it's allowed to have the same collection multiple times in parallel */
+ dup_collection->id.tag |= LIB_TAG_DOIT;
+ }
+
+ return false;
+}
+
+bool BKE_collection_object_cyclic_check(Main *bmain, Object *object, Collection *collection)
+{
+ /* first flag all collections */
+ BKE_main_id_tag_listbase(&bmain->collection, LIB_TAG_DOIT, true);
+
+ return collection_object_cyclic_check_internal(object, collection);
+}
+
+/******************* Collection Object Membership *******************/
+
+bool BKE_collection_has_object(Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ return (BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)));
+}
+
+bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ const ListBase objects = BKE_collection_object_cache_get(collection);
+ return (BLI_findptr(&objects, ob, offsetof(Base, object)));
+}
+
+Collection *BKE_collection_object_find(Main *bmain, Collection *collection, Object *ob)
+{
+ if (collection)
+ collection = collection->id.next;
+ else
+ collection = bmain->collection.first;
+
+ while (collection) {
+ if (BKE_collection_has_object(collection, ob))
+ return collection;
+ collection = collection->id.next;
+ }
+ return NULL;
+}
+
+bool BKE_collection_is_empty(Collection *collection)
+{
+ return BLI_listbase_is_empty(&collection->gobject) && BLI_listbase_is_empty(&collection->children);
+}
+
+/********************** Collection Objects *********************/
+
+static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us)
+{
+ if (ob->dup_group) {
+ /* Cyclic dependency check. */
+ if (collection_find_child_recursive(ob->dup_group, collection)) {
+ return false;
+ }
+ }
+
+ CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
+ if (cob) {
+ return false;
+ }
+
+ cob = MEM_callocN(sizeof(CollectionObject), __func__);
+ cob->ob = ob;
+ BLI_addtail(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
+
+ if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&ob->id);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
+ return true;
+}
+
+static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
+{
+ CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
+ if (cob == NULL) {
+ return false;
+ }
+
+ BLI_freelinkN(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
+
+ if (free_us) {
+ BKE_libblock_free_us(bmain, ob);
+ }
+ else {
+ id_us_min(&ob->id);
+ }
+
+ DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+
+ return true;
+}
+
+/**
+ * Add object to collection
+ */
+bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ if (!collection_object_add(bmain, collection, ob, 0, true)) {
+ return false;
+ }
+
+ if (BKE_collection_is_in_scene(collection)) {
+ BKE_main_collection_sync(bmain);
+ }
+
+ return true;
+}
+
+/**
+ * Add object to all scene collections that reference objects is in
+ * (used to copy objects)
+ */
+void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
+{
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
+ {
+ if (BKE_collection_has_object(collection, ob_src)) {
+ collection_object_add(bmain, collection, ob_dst, 0, true);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ BKE_main_collection_sync(bmain);
+}
+
+/**
+ * Remove object from collection.
+ */
+bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ if (!collection_object_remove(bmain, collection, ob, free_us)) {
+ return false;
+ }
+
+ if (BKE_collection_is_in_scene(collection)) {
+ BKE_main_collection_sync(bmain);
+ }
+
+ return true;
+}
+
+/**
+ * Remove object from all collections of scene
+ * \param scene_collection_skip: Don't remove base from this collection.
+ */
+static bool scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us,
+ Collection *collection_skip)
+{
+ bool removed = false;
+
+ BKE_scene_remove_rigidbody_object(bmain, scene, ob);
+
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
+ {
+ if (collection != collection_skip) {
+ removed |= collection_object_remove(bmain, collection, ob, free_us);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ BKE_main_collection_sync(bmain);
+
+ return removed;
+}
+
+/**
+ * Remove object from all collections of scene
+ */
+bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
+{
+ return scene_collections_object_remove(bmain, scene, ob, free_us, NULL);
+}
+
+/*
+ * Remove all NULL objects from collections.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ */
+static void collection_object_remove_nulls(Collection *collection)
+{
+ bool changed = false;
+
+ for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
+ cob_next = cob->next;
+
+ if (cob->ob == NULL) {
+ BLI_freelinkN(&collection->gobject, cob);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ BKE_collection_object_cache_free(collection);
+ }
+}
+
+void BKE_collections_object_remove_nulls(Main *bmain)
+{
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ collection_object_remove_nulls(scene->master_collection);
+ }
+
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ collection_object_remove_nulls(collection);
+ }
+}
+
+static void collection_null_children_remove(Collection *collection)
+{
+ for (CollectionChild *child = collection->children.first, *child_next = NULL; child; child = child_next) {
+ child_next = child->next;
+
+ if (child->collection == NULL) {
+ BLI_freelinkN(&collection->children, child);
+ }
+ }
+}
+
+static void collection_missing_parents_remove(Collection *collection)
+{
+ for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL; parent = parent_next) {
+ parent_next = parent->next;
+
+ if (!collection_find_child(parent->collection, collection)) {
+ BLI_freelinkN(&collection->parents, parent);
+ }
+ }
+}
+
+/**
+ * Remove all NULL children from parent collections of changed \a collection.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ *
+ * \note caller must ensure BKE_main_collection_sync_remap() is called afterwards!
+ *
+ * \param collection may be \a NULL, in which case whole \a bmain database of collections is checked.
+ */
+void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
+{
+ if (collection == NULL) {
+ /* We need to do the checks in two steps when more than one collection may be involved,
+ * otherwise we can miss some cases...
+ * Also, master collections are not in bmain, so we also need to loop over scenes.
+ */
+ for (collection = bmain->collection.first; collection != NULL; collection = collection->id.next) {
+ collection_null_children_remove(collection);
+ }
+ for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) {
+ collection_null_children_remove(BKE_collection_master(scene));
+ }
+
+ for (collection = bmain->collection.first; collection != NULL; collection = collection->id.next) {
+ collection_missing_parents_remove(collection);
+ }
+ for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) {
+ collection_missing_parents_remove(BKE_collection_master(scene));
+ }
+ }
+ else {
+ for (CollectionParent *parent = collection->parents.first, *parent_next; parent; parent = parent_next) {
+ parent_next = parent->next;
+
+ collection_null_children_remove(parent->collection);
+
+ if (!collection_find_child(parent->collection, collection)) {
+ BLI_freelinkN(&collection->parents, parent);
+ }
+ }
+ }
+}
+
+/**
+ * Move object from a collection into another
+ *
+ * If source collection is NULL move it from all the existing collections.
+ */
+void BKE_collection_object_move(
+ Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
+{
+ /* In both cases we first add the object, then remove it from the other collections.
+ * Otherwise we lose the original base and whether it was active and selected. */
+ if (collection_src != NULL) {
+ if (BKE_collection_object_add(bmain, collection_dst, ob)) {
+ BKE_collection_object_remove(bmain, collection_src, ob, false);
+ }
+ }
+ else {
+ /* Adding will fail if object is already in collection.
+ * However we still need to remove it from the other collections. */
+ BKE_collection_object_add(bmain, collection_dst, ob);
+ scene_collections_object_remove(bmain, scene, ob, false, collection_dst);
+ }
+}
+
+/***************** Collection Scene Membership ****************/
+
+bool BKE_collection_is_in_scene(Collection *collection)
+{
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return true;
+ }
+
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ if (BKE_collection_is_in_scene(cparent->collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BKE_collections_after_lib_link(Main *bmain)
+{
+ /* Update view layer collections to match any changes in linked
+ * collections after file load. */
+ BKE_main_collection_sync(bmain);
+}
+
+/********************** Collection Children *******************/
+
+bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection)
+{
+ if (collection == new_ancestor) {
+ return true;
+ }
+
+ for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) {
+ if (BKE_collection_find_cycle(parent->collection, collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static CollectionChild *collection_find_child(Collection *parent, Collection *collection)
+{
+ return BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection));
+}
+
+static bool collection_find_child_recursive(Collection *parent, Collection *collection)
+{
+ for (CollectionChild *child = parent->children.first; child; child = child->next) {
+ if (child->collection == collection) {
+ return true;
+ }
+
+ if (collection_find_child_recursive(child->collection, collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static CollectionParent *collection_find_parent(Collection *child, Collection *collection)
+{
+ return BLI_findptr(&child->parents, collection, offsetof(CollectionParent, collection));
+}
+
+static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us)
+{
+ CollectionChild *child = collection_find_child(parent, collection);
+ if (child) {
+ return false;
+ }
+ if (BKE_collection_find_cycle(parent, collection)) {
+ return false;
+ }
+
+ child = MEM_callocN(sizeof(CollectionChild), "CollectionChild");
+ child->collection = collection;
+ BLI_addtail(&parent->children, child);
+
+ /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent");
+ cparent->collection = parent;
+ BLI_addtail(&collection->parents, cparent);
+ }
+
+ if (add_us) {
+ id_us_plus(&collection->id);
+ }
+
+ BKE_collection_object_cache_free(parent);
+
+ return true;
+}
+
+static bool collection_child_remove(Collection *parent, Collection *collection)
+{
+ CollectionChild *child = collection_find_child(parent, collection);
+ if (child == NULL) {
+ return false;
+ }
+
+ CollectionParent *cparent = collection_find_parent(collection, parent);
+ BLI_freelinkN(&collection->parents, cparent);
+ BLI_freelinkN(&parent->children, child);
+
+ id_us_min(&collection->id);
+
+ BKE_collection_object_cache_free(parent);
+
+ return true;
+}
+
+bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
+{
+ if (!collection_child_add(parent, child, 0, true)) {
+ return false;
+ }
+
+ BKE_main_collection_sync(bmain);
+ return true;
+}
+
+bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
+{
+ if (!collection_child_remove(parent, child)) {
+ return false;
+ }
+
+ BKE_main_collection_sync(bmain);
+ return true;
+}
+
+/********************** Collection index *********************/
+
+static Collection *collection_from_index_recursive(Collection *collection, const int index, int *index_current)
+{
+ if (index == (*index_current)) {
+ return collection;
+ }
+
+ (*index_current)++;
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ Collection *nested = collection_from_index_recursive(child->collection, index, index_current);
+ if (nested != NULL) {
+ return nested;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Return Scene Collection for a given index.
+ *
+ * The index is calculated from top to bottom counting the children before the siblings.
+ */
+Collection *BKE_collection_from_index(Scene *scene, const int index)
+{
+ int index_current = 0;
+ Collection *master_collection = BKE_collection_master(scene);
+ return collection_from_index_recursive(master_collection, index, &index_current);
+}
+
+static bool collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
+{
+ bool changed = false;
+
+ if (collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base) {
+ if (deselect) {
+ if (base->flag & BASE_SELECTED) {
+ base->flag &= ~BASE_SELECTED;
+ changed = true;
+ }
+ }
+ else {
+ if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
+ base->flag |= BASE_SELECTED;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ if (collection_objects_select(view_layer, collection, deselect)) {
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+/**
+ * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
+ * Return true if any object was selected.
+ */
+bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
+{
+ LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer, collection);
+
+ if (layer_collection != NULL) {
+ return BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
+ }
+ else {
+ return collection_objects_select(view_layer, collection, deselect);
+ }
+}
+
+/***************** Collection move (outliner drag & drop) *********************/
+
+bool BKE_collection_move(Main *bmain,
+ Collection *to_parent,
+ Collection *from_parent,
+ Collection *relative,
+ bool relative_after,
+ Collection *collection)
+{
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return false;
+ }
+ if (BKE_collection_find_cycle(to_parent, collection)) {
+ return false;
+ }
+
+ /* Move to new parent collection */
+ if (from_parent) {
+ collection_child_remove(from_parent, collection);
+ }
+
+ collection_child_add(to_parent, collection, 0, true);
+
+ /* Move to specified location under parent. */
+ if (relative) {
+ CollectionChild *child = collection_find_child(to_parent, collection);
+ CollectionChild *relative_child = collection_find_child(to_parent, relative);
+
+ if (relative_child) {
+ BLI_remlink(&to_parent->children, child);
+
+ if (relative_after) {
+ BLI_insertlinkafter(&to_parent->children, relative_child, child);
+ }
+ else {
+ BLI_insertlinkbefore(&to_parent->children, relative_child, child);
+ }
+
+ BKE_collection_object_cache_free(to_parent);
+ }
+ }
+
+ BKE_main_collection_sync(bmain);
+
+ return true;
+}
+
+/**************************** Iterators ******************************/
+
+/* scene collection iteractor */
+
+typedef struct CollectionsIteratorData {
+ Scene *scene;
+ void **array;
+ int tot, cur;
+} CollectionsIteratorData;
+
+static void scene_collection_callback(Collection *collection, BKE_scene_collections_Cb callback, void *data)
+{
+ callback(collection, data);
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ scene_collection_callback(child->collection, callback, data);
+ }
+}
+
+static void scene_collections_count(Collection *UNUSED(collection), void *data)
+{
+ int *tot = data;
+ (*tot)++;
+}
+
+static void scene_collections_build_array(Collection *collection, void *data)
+{
+ Collection ***array = data;
+ **array = collection;
+ (*array)++;
+}
+
+static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot)
+{
+ Collection *collection;
+ Collection **array;
+
+ *collections_array = NULL;
+ *tot = 0;
+
+ if (scene == NULL) {
+ return;
+ }
+
+ collection = BKE_collection_master(scene);
+ BLI_assert(collection != NULL);
+ scene_collection_callback(collection, scene_collections_count, tot);
+
+ if (*tot == 0)
+ return;
+
+ *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
+ scene_collection_callback(collection, scene_collections_build_array, &array);
+}
+
+/**
+ * Only use this in non-performance critical situations
+ * (it iterates over all scene collections twice)
+ */
+void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ Scene *scene = data_in;
+ CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__);
+
+ data->scene = scene;
+ iter->data = data;
+ iter->valid = true;
+
+ scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
+ BLI_assert(data->tot != 0);
+
+ data->cur = 0;
+ iter->current = data->array[data->cur];
+}
+
+void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter)
+{
+ CollectionsIteratorData *data = iter->data;
+
+ if (++data->cur < data->tot) {
+ iter->current = data->array[data->cur];
+ }
+ else {
+ iter->valid = false;
+ }
+}
+
+void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter)
+{
+ CollectionsIteratorData *data = iter->data;
+
+ if (data) {
+ if (data->array) {
+ MEM_freeN(data->array);
+ }
+ MEM_freeN(data);
+ }
+ iter->valid = false;
+}
+
+
+/* scene objects iteractor */
+
+typedef struct SceneObjectsIteratorData {
+ GSet *visited;
+ CollectionObject *cob_next;
+ BLI_Iterator scene_collection_iter;
+} SceneObjectsIteratorData;
+
+void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ Scene *scene = data_in;
+ SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__);
+ iter->data = data;
+
+ /* lookup list ot make sure each object is object called once */
+ data->visited = BLI_gset_ptr_new(__func__);
+
+ /* we wrap the scenecollection iterator here to go over the scene collections */
+ BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene);
+
+ Collection *collection = data->scene_collection_iter.current;
+ data->cob_next = collection->gobject.first;
+
+ BKE_scene_objects_iterator_next(iter);
+}
+
+/**
+ * Ensures we only get each object once, even when included in several collections.
+ */
+static CollectionObject *object_base_unique(GSet *gs, CollectionObject *cob)
+{
+ for (; cob != NULL; cob = cob->next) {
+ Object *ob = cob->ob;
+ void **ob_key_p;
+ if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) {
+ *ob_key_p = ob;
+ return cob;
+ }
+ }
+ return NULL;
+}
+
+void BKE_scene_objects_iterator_next(BLI_Iterator *iter)
+{
+ SceneObjectsIteratorData *data = iter->data;
+ CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) : NULL;
+
+ if (cob) {
+ data->cob_next = cob->next;
+ iter->current = cob->ob;
+ }
+ else {
+ /* if this is the last object of this ListBase look at the next Collection */
+ Collection *collection;
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ do {
+ collection = data->scene_collection_iter.current;
+ /* get the first unique object of this collection */
+ CollectionObject *new_cob = object_base_unique(data->visited, collection->gobject.first);
+ if (new_cob) {
+ data->cob_next = new_cob->next;
+ iter->current = new_cob->ob;
+ return;
+ }
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ } while (data->scene_collection_iter.valid);
+
+ if (!data->scene_collection_iter.valid) {
+ iter->valid = false;
+ }
+ }
+}
+
+void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
+{
+ SceneObjectsIteratorData *data = iter->data;
+ if (data) {
+ BKE_scene_collections_iterator_end(&data->scene_collection_iter);
+ BLI_gset_free(data->visited, NULL);
+ MEM_freeN(data);
+ }
+}
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 84490ba3ee2..d868a06d134 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -33,8 +33,8 @@
#include "MEM_guardedalloc.h"
#include "DNA_cloth_types.h"
+#include "DNA_collection_types.h"
#include "DNA_effect_types.h"
-#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
#include "DNA_scene_types.h"
@@ -43,24 +43,45 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_edgehash.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_effect.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_scene.h"
-#ifdef WITH_BULLET
-#include "Bullet-C-Api.h"
-#endif
#include "BLI_kdopbvh.h"
#include "BKE_collision.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
+
#ifdef WITH_ELTOPO
#include "eltopo-capi.h"
#endif
+typedef struct ColDetectData {
+ ClothModifierData *clmd;
+ CollisionModifierData *collmd;
+ BVHTreeOverlap *overlap;
+ CollPair *collisions;
+ bool culling;
+ bool use_normal;
+ bool collided;
+} ColDetectData;
+
+typedef struct SelfColDetectData {
+ ClothModifierData *clmd;
+ BVHTreeOverlap *overlap;
+ CollPair *collisions;
+ bool collided;
+} SelfColDetectData;
+
/***********************************
Collision modifier code start
***********************************/
@@ -68,7 +89,7 @@ Collision modifier code start
/* step is limited from 0 (frame start position) to 1 (frame end position) */
void collision_move_object(CollisionModifierData *collmd, float step, float prevstep)
{
- float tv[3] = {0, 0, 0};
+ float oldx[3];
unsigned int i = 0;
/* the collider doesn't move this frame */
@@ -81,15 +102,14 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
}
for (i = 0; i < collmd->mvert_num; i++) {
- sub_v3_v3v3(tv, collmd->xnew[i].co, collmd->x[i].co);
- VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep);
- VECADDS(collmd->current_xnew[i].co, collmd->x[i].co, tv, step);
- sub_v3_v3v3(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co);
+ interp_v3_v3v3(oldx, collmd->x[i].co, collmd->xnew[i].co, prevstep);
+ interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, step);
+ sub_v3_v3v3(collmd->current_v[i].co, collmd->current_x[i].co, oldx);
}
bvhtree_update_from_mvert(
- collmd->bvhtree, collmd->current_x, collmd->current_xnew,
- collmd->tri, collmd->tri_num, true);
+ collmd->bvhtree, collmd->current_x, NULL,
+ collmd->tri, collmd->tri_num, false);
}
BVHTree *bvhtree_build_from_mvert(
@@ -172,6 +192,233 @@ void bvhtree_update_from_mvert(
Collision modifier code end
***********************************/
+BLI_INLINE int next_ind(int i)
+{
+ return (++i < 3) ? i : 0;
+}
+
+static float compute_collision_point(float a1[3], float a2[3], float a3[3], float b1[3], float b2[3], float b3[3],
+ bool culling, bool use_normal, float r_a[3], float r_b[3], float r_vec[3])
+{
+ float a[3][3];
+ float b[3][3];
+ float dist = FLT_MAX;
+ float tmp_co1[3], tmp_co2[3];
+ float isect_a[3], isect_b[3];
+ int isect_count = 0;
+ float tmp, tmp_vec[3];
+ float normal[3], cent[3];
+ bool backside = false;
+
+ copy_v3_v3(a[0], a1);
+ copy_v3_v3(a[1], a2);
+ copy_v3_v3(a[2], a3);
+
+ copy_v3_v3(b[0], b1);
+ copy_v3_v3(b[1], b2);
+ copy_v3_v3(b[2], b3);
+
+ /* Find intersections. */
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(a[i], a[next_ind(i)], b[0], b[1], b[2], &tmp, NULL)) {
+ interp_v3_v3v3(isect_a, a[i], a[next_ind(i)], tmp);
+ isect_count++;
+ }
+ }
+
+ if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
+ isect_count++;
+ }
+ }
+ }
+ else if (isect_count == 1) {
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
+ interp_v3_v3v3(isect_b, b[i], b[next_ind(i)], tmp);
+ break;
+ }
+ }
+ }
+
+ /* Determine collision side. */
+ if (culling) {
+ normal_tri_v3(normal, b[0], b[1], b[2]);
+ mid_v3_v3v3v3(cent, b[0], b[1], b[2]);
+
+ if (isect_count == 2) {
+ backside = true;
+ }
+ else if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ sub_v3_v3v3(tmp_vec, a[i], cent);
+ if (dot_v3v3(tmp_vec, normal) < 0.0f) {
+ backside = true;
+ break;
+ }
+ }
+ }
+ }
+ else if (use_normal) {
+ normal_tri_v3(normal, b[0], b[1], b[2]);
+ }
+
+ if (isect_count == 1) {
+ /* Edge intersection. */
+ copy_v3_v3(r_a, isect_a);
+ copy_v3_v3(r_b, isect_b);
+
+ if (use_normal) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+ }
+
+ return 0.0f;
+ }
+
+ if (backside) {
+ float maxdist = 0.0f;
+ bool found = false;
+
+ /* Point projections. */
+ for (int i = 0; i < 3; i++) {
+ if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) {
+ if (tmp > maxdist) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ madd_v3_v3v3fl(r_b, a[i], normal, tmp);
+ found = true;
+ }
+ }
+ }
+
+ negate_v3(normal);
+
+ for (int i = 0; i < 3; i++) {
+ if (isect_ray_tri_v3(b[i], normal, a[0], a[1], a[2], &tmp, NULL)) {
+ if (tmp > maxdist) {
+ maxdist = tmp;
+ madd_v3_v3v3fl(r_a, b[i], normal, tmp);
+ copy_v3_v3(r_b, b[i]);
+ found = true;
+ }
+ }
+ }
+
+ negate_v3(normal);
+
+ /* Edge projections. */
+ for (int i = 0; i < 3; i++) {
+ float dir[3];
+
+ sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]);
+ cross_v3_v3v3(dir, tmp_vec, normal);
+
+ for (int j = 0; j < 3; j++) {
+ if (isect_line_plane_v3(tmp_co1, a[j], a[next_ind(j)], b[i], dir) &&
+ point_in_slice_seg(tmp_co1, a[j], a[next_ind(j)]) &&
+ point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)]))
+ {
+ closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]);
+ sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2);
+ tmp = len_v3(tmp_vec);
+
+ if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ found = true;
+ }
+ }
+ }
+ }
+
+ /* If no point is found, will fallback onto regular proximity test below. */
+ if (found) {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+
+ if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+
+ return 0.0f;
+ }
+ }
+
+ /* Closest point. */
+ for (int i = 0; i < 3; i++) {
+ closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]);
+ tmp = len_squared_v3v3(tmp_co1, a[i]);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ copy_v3_v3(r_b, tmp_co1);
+ }
+ }
+
+ for (int i = 0; i < 3; i++) {
+ closest_on_tri_to_point_v3(tmp_co1, b[i], a[0], a[1], a[2]);
+ tmp = len_squared_v3v3(tmp_co1, b[i]);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, b[i]);
+ }
+ }
+
+ /* Closest edge. */
+ if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ isect_seg_seg_v3(a[i], a[next_ind(i)], b[j], b[next_ind(j)], tmp_co1, tmp_co2);
+ tmp = len_squared_v3v3(tmp_co1, tmp_co2);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ }
+ }
+ }
+ }
+
+ if (isect_count == 0) {
+ sub_v3_v3v3(r_vec, r_a, r_b);
+ dist = sqrtf(dist);
+ }
+ else {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+ dist = 0.0f;
+ }
+
+ if (culling && use_normal) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+ else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) {
+ return FLT_MAX;
+ }
+
+ return dist;
+}
+
// w3 is not perfect
static void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 )
{
@@ -226,141 +473,131 @@ DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float
VECADDMUL(to, v3, w3);
}
-static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end )
+static int cloth_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, Object *collob,
+ CollPair *collpair, uint collision_count, const float dt)
{
int result = 0;
Cloth *cloth1;
float w1, w2, w3, u1, u2, u3;
float v1[3], v2[3], relativeVelocity[3];
float magrelVel;
- float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
cloth1 = clmd->clothObject;
- for ( ; collpair != collision_end; collpair++ ) {
+ for (int i = 0; i < collision_count; i++, collpair++) {
float i1[3], i2[3], i3[3];
zero_v3(i1);
zero_v3(i2);
zero_v3(i3);
- /* only handle static collisions here */
- if ( collpair->flag & COLLISION_IN_FUTURE )
+ /* Only handle static collisions here. */
+ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
continue;
+ }
- /* compute barycentric coordinates for both collision points */
- collision_compute_barycentric ( collpair->pa,
- cloth1->verts[collpair->ap1].txold,
- cloth1->verts[collpair->ap2].txold,
- cloth1->verts[collpair->ap3].txold,
- &w1, &w2, &w3 );
+ /* Compute barycentric coordinates for both collision points. */
+ collision_compute_barycentric(collpair->pa,
+ cloth1->verts[collpair->ap1].tx,
+ cloth1->verts[collpair->ap2].tx,
+ cloth1->verts[collpair->ap3].tx,
+ &w1, &w2, &w3);
- /* was: txold */
- collision_compute_barycentric ( collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
- &u1, &u2, &u3 );
+ collision_compute_barycentric(collpair->pb,
+ collmd->current_x[collpair->bp1].co,
+ collmd->current_x[collpair->bp2].co,
+ collmd->current_x[collpair->bp3].co,
+ &u1, &u2, &u3);
/* Calculate relative "velocity". */
- collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 );
+ collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
- collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
+ collision_interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3);
sub_v3_v3v3(relativeVelocity, v2, v1);
/* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
- /* printf("magrelVel: %f\n", magrelVel); */
-
- /* Calculate masses of points.
- * TODO */
-
- /* If v_n_mag < 0 the edges are approaching each other. */
- if ( magrelVel > ALMOST_ZERO ) {
+ /* If magrelVel < 0 the edges are approaching each other. */
+ if (magrelVel > 0.0f) {
/* Calculate Impulse magnitude to stop all motion in normal direction. */
float magtangent = 0, repulse = 0, d = 0;
double impulse = 0.0;
float vrel_t_pre[3];
- float temp[3], spf;
+ float temp[3];
+ float time_multiplier;
- /* calculate tangential velocity */
- copy_v3_v3 ( temp, collpair->normal );
+ /* Calculate tangential velocity. */
+ copy_v3_v3(temp, collpair->normal);
mul_v3_fl(temp, magrelVel);
sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
/* Decrease in magnitude of relative tangential velocity due to coulomb friction
- * in original formula "magrelVel" should be the "change of relative velocity in normal direction" */
- magtangent = min_ff(clmd->coll_parms->friction * 0.01f * magrelVel, len_v3(vrel_t_pre));
+ * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
+ magtangent = min_ff(collob->pd->pdef_cfrict * 0.01f * magrelVel, len_v3(vrel_t_pre));
/* Apply friction impulse. */
if ( magtangent > ALMOST_ZERO ) {
normalize_v3(vrel_t_pre);
- impulse = magtangent / ( 1.0f + w1*w1 + w2*w2 + w3*w3 ); /* 2.0 * */
- VECADDMUL ( i1, vrel_t_pre, w1 * impulse );
- VECADDMUL ( i2, vrel_t_pre, w2 * impulse );
- VECADDMUL ( i3, vrel_t_pre, w3 * impulse );
+ impulse = magtangent / 1.5;
+
+ VECADDMUL(i1, vrel_t_pre, w1 * impulse);
+ VECADDMUL(i2, vrel_t_pre, w2 * impulse);
+ VECADDMUL(i3, vrel_t_pre, w3 * impulse);
}
- /* Apply velocity stopping impulse
- * I_c = m * v_N / 2.0
- * no 2.0 * magrelVel normally, but looks nicer DG */
- impulse = magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3 );
+ /* Apply velocity stopping impulse. */
+ impulse = magrelVel / 1.5f;
- VECADDMUL ( i1, collpair->normal, w1 * impulse );
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
cloth1->verts[collpair->ap1].impulse_count++;
- VECADDMUL ( i2, collpair->normal, w2 * impulse );
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
cloth1->verts[collpair->ap2].impulse_count++;
- VECADDMUL ( i3, collpair->normal, w3 * impulse );
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
cloth1->verts[collpair->ap3].impulse_count++;
- /* Apply repulse impulse if distance too short
- * I_r = -min(dt*kd, m(0, 1d/dt - v_n))
- * DG: this formula ineeds to be changed for this code since we apply impulses/repulses like this:
- * v += impulse; x_new = x + v;
- * We don't use dt!!
- * DG TODO: Fix usage of dt here! */
- spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
+ time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance;
- if ( ( magrelVel < 0.1f*d*spf ) && ( d > ALMOST_ZERO ) ) {
- repulse = MIN2 ( d*1.0f/spf, 0.1f*d*spf - magrelVel );
- /* stay on the safe side and clamp repulse */
- if ( impulse > ALMOST_ZERO )
- repulse = min_ff( repulse, 5.0*impulse );
+ if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
+ repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
+
+ /* Stay on the safe side and clamp repulse. */
+ if (impulse > ALMOST_ZERO) {
+ repulse = min_ff(repulse, 5.0f * impulse);
+ }
+
repulse = max_ff(impulse, repulse);
- impulse = repulse / ( 1.0f + w1*w1 + w2*w2 + w3*w3 ); /* original 2.0 / 0.25 */
- VECADDMUL ( i1, collpair->normal, impulse );
- VECADDMUL ( i2, collpair->normal, impulse );
- VECADDMUL ( i3, collpair->normal, impulse );
+ impulse = repulse / 1.5f;
+
+ VECADDMUL(i1, collpair->normal, impulse);
+ VECADDMUL(i2, collpair->normal, impulse);
+ VECADDMUL(i3, collpair->normal, impulse);
}
result = 1;
}
else {
- /* Apply repulse impulse if distance too short
- * I_r = -min(dt*kd, max(0, 1d/dt - v_n))
- * DG: this formula ineeds to be changed for this code since we apply impulses/repulses like this:
- * v += impulse; x_new = x + v;
- * We don't use dt!! */
- float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
-
- float d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - (float)collpair->distance;
- if ( d > ALMOST_ZERO) {
- /* stay on the safe side and clamp repulse */
- float repulse = d*1.0f/spf;
+ float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+ float d;
+
+ d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance;
- float impulse = repulse / ( 3.0f * ( 1.0f + w1*w1 + w2*w2 + w3*w3 )); /* original 2.0 / 0.25 */
+ if (d > ALMOST_ZERO) {
+ /* Stay on the safe side and clamp repulse. */
+ float repulse = d / time_multiplier;
+ float impulse = repulse / 4.5f;
- VECADDMUL ( i1, collpair->normal, impulse );
- VECADDMUL ( i2, collpair->normal, impulse );
- VECADDMUL ( i3, collpair->normal, impulse );
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
cloth1->verts[collpair->ap1].impulse_count++;
cloth1->verts[collpair->ap2].impulse_count++;
@@ -371,20 +608,190 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
}
if (result) {
- int i = 0;
+ float clamp = clmd->coll_parms->clamp * dt;
- for (i = 0; i < 3; i++) {
- if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[i]) < ABS(i1[i]))
- cloth1->verts[collpair->ap1].impulse[i] = i1[i];
+ if ((clamp > 0.0f) &&
+ ((len_v3(i1) > clamp) ||
+ (len_v3(i2) > clamp) ||
+ (len_v3(i3) > clamp)))
+ {
+ return 0;
+ }
- if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[i]) < ABS(i2[i]))
- cloth1->verts[collpair->ap2].impulse[i] = i2[i];
+ for (int j = 0; j < 3; j++) {
+ if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
+ cloth1->verts[collpair->ap1].impulse[j] = i1[j];
- if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[i]) < ABS(i3[i]))
- cloth1->verts[collpair->ap3].impulse[i] = i3[i];
+ if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
+ cloth1->verts[collpair->ap2].impulse[j] = i2[j];
+
+ if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
+ cloth1->verts[collpair->ap3].impulse[j] = i3[j];
}
}
}
+
+ return result;
+}
+
+static int cloth_selfcollision_response_static(ClothModifierData *clmd, CollPair *collpair,
+ uint collision_count, const float dt)
+{
+ int result = 0;
+ Cloth *cloth1;
+ float w1, w2, w3, u1, u2, u3;
+ float v1[3], v2[3], relativeVelocity[3];
+ float magrelVel;
+
+ cloth1 = clmd->clothObject;
+
+ for (int i = 0; i < collision_count; i++, collpair++) {
+ float i1[3], i2[3], i3[3];
+
+ zero_v3(i1);
+ zero_v3(i2);
+ zero_v3(i3);
+
+ /* Only handle static collisions here. */
+ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
+ continue;
+ }
+
+ /* Compute barycentric coordinates for both collision points. */
+ collision_compute_barycentric(collpair->pa,
+ cloth1->verts[collpair->ap1].tx,
+ cloth1->verts[collpair->ap2].tx,
+ cloth1->verts[collpair->ap3].tx,
+ &w1, &w2, &w3);
+
+ collision_compute_barycentric(collpair->pb,
+ cloth1->verts[collpair->bp1].tx,
+ cloth1->verts[collpair->bp2].tx,
+ cloth1->verts[collpair->bp3].tx,
+ &u1, &u2, &u3);
+
+ /* Calculate relative "velocity". */
+ collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
+
+ collision_interpolateOnTriangle(v2, cloth1->verts[collpair->bp1].tv, cloth1->verts[collpair->bp2].tv, cloth1->verts[collpair->bp3].tv, u1, u2, u3);
+
+ sub_v3_v3v3(relativeVelocity, v2, v1);
+
+ /* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
+ magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
+
+ /* TODO: Impulses should be weighed by mass as this is self col,
+ * this has to be done after mass distribution is implemented. */
+
+ /* If magrelVel < 0 the edges are approaching each other. */
+ if (magrelVel > 0.0f) {
+ /* Calculate Impulse magnitude to stop all motion in normal direction. */
+ float magtangent = 0, repulse = 0, d = 0;
+ double impulse = 0.0;
+ float vrel_t_pre[3];
+ float temp[3], time_multiplier;
+
+ /* Calculate tangential velocity. */
+ copy_v3_v3(temp, collpair->normal);
+ mul_v3_fl(temp, magrelVel);
+ sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
+
+ /* Decrease in magnitude of relative tangential velocity due to coulomb friction
+ * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
+ magtangent = min_ff(clmd->coll_parms->self_friction * 0.01f * magrelVel, len_v3(vrel_t_pre));
+
+ /* Apply friction impulse. */
+ if (magtangent > ALMOST_ZERO) {
+ normalize_v3(vrel_t_pre);
+
+ impulse = magtangent / 1.5;
+
+ VECADDMUL(i1, vrel_t_pre, w1 * impulse);
+ VECADDMUL(i2, vrel_t_pre, w2 * impulse);
+ VECADDMUL(i3, vrel_t_pre, w3 * impulse);
+ }
+
+ /* Apply velocity stopping impulse. */
+ impulse = magrelVel / 3.0f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ cloth1->verts[collpair->ap1].impulse_count++;
+
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ cloth1->verts[collpair->ap2].impulse_count++;
+
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ cloth1->verts[collpair->ap3].impulse_count++;
+
+ time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+
+ d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
+
+ if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
+ repulse = MIN2 (d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
+
+ if (impulse > ALMOST_ZERO) {
+ repulse = min_ff(repulse, 5.0*impulse);
+ }
+
+ repulse = max_ff(impulse, repulse);
+
+ impulse = repulse / 1.5f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ }
+
+ result = 1;
+ }
+ else {
+ float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+ float d;
+
+ d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
+
+ if ( d > ALMOST_ZERO) {
+ /* Stay on the safe side and clamp repulse. */
+ float repulse = d*1.0f/time_multiplier;
+ float impulse = repulse / 9.0f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+
+ cloth1->verts[collpair->ap1].impulse_count++;
+ cloth1->verts[collpair->ap2].impulse_count++;
+ cloth1->verts[collpair->ap3].impulse_count++;
+
+ result = 1;
+ }
+ }
+
+ if (result) {
+ float clamp = clmd->coll_parms->self_clamp * dt;
+
+ if ((clamp > 0.0f) &&
+ ((len_v3(i1) > clamp) ||
+ (len_v3(i2) > clamp) ||
+ (len_v3(i3) > clamp)))
+ {
+ return 0;
+ }
+
+ for (int j = 0; j < 3; j++) {
+ if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
+ cloth1->verts[collpair->ap1].impulse[j] = i1[j];
+
+ if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
+ cloth1->verts[collpair->ap2].impulse[j] = i2[j];
+
+ if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
+ cloth1->verts[collpair->ap3].impulse[j] = i3[j];
+ }
+ }
+ }
+
return result;
}
@@ -392,224 +799,257 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
# pragma GCC diagnostic pop
#endif
-//Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned
-static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2,
- BVHTreeOverlap *overlap, CollPair *collpair, float UNUSED(dt))
+static void cloth_collision(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- ClothModifierData *clmd = (ClothModifierData *)md1;
- CollisionModifierData *collmd = (CollisionModifierData *) md2;
- /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
+ ColDetectData *data = (ColDetectData *)userdata;
+
+ ClothModifierData *clmd = data->clmd;
+ CollisionModifierData *collmd = data->collmd;
+ CollPair *collpair = data->collisions;
const MVertTri *tri_a, *tri_b;
-#ifdef WITH_BULLET
ClothVertex *verts1 = clmd->clothObject->verts;
-#endif
- double distance = 0;
+ float distance = 0.0f;
float epsilon1 = clmd->coll_parms->epsilon;
- float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+ float pa[3], pb[3], vect[3];
- tri_a = &clmd->clothObject->tri[overlap->indexA];
- tri_b = &collmd->tri[overlap->indexB];
+ tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
+ tri_b = &collmd->tri[data->overlap[index].indexB];
- /* fill face_a */
- collpair->ap1 = tri_a->tri[0];
- collpair->ap2 = tri_a->tri[1];
- collpair->ap3 = tri_a->tri[2];
+ /* Compute distance and normal. */
+ distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx,
+ collmd->current_x[tri_b->tri[0]].co, collmd->current_x[tri_b->tri[1]].co, collmd->current_x[tri_b->tri[2]].co,
+ data->culling, data->use_normal, pa, pb, vect);
- /* fill face_b */
- collpair->bp1 = tri_b->tri[0];
- collpair->bp2 = tri_b->tri[1];
- collpair->bp3 = tri_b->tri[2];
+ if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
+ collpair[index].ap1 = tri_a->tri[0];
+ collpair[index].ap2 = tri_a->tri[1];
+ collpair[index].ap3 = tri_a->tri[2];
- {
+ collpair[index].bp1 = tri_b->tri[0];
+ collpair[index].bp2 = tri_b->tri[1];
+ collpair[index].bp3 = tri_b->tri[2];
-#ifdef WITH_BULLET
- // calc distance + normal
- distance = plNearestPoints (
- verts1[collpair->ap1].txold, verts1[collpair->ap2].txold, verts1[collpair->ap3].txold, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, collpair->pa, collpair->pb, collpair->vector );
-#else
- // just be sure that we don't add anything
- distance = 2.0 * (double)( epsilon1 + epsilon2 + ALMOST_ZERO );
-#endif
+ copy_v3_v3(collpair[index].pa, pa);
+ copy_v3_v3(collpair[index].pb, pb);
+ copy_v3_v3(collpair[index].vector, vect);
- // distance -1 means no collision result
- if (distance != -1.0 && (distance <= (double)(epsilon1 + epsilon2 + ALMOST_ZERO))) {
- normalize_v3_v3(collpair->normal, collpair->vector);
+ normalize_v3_v3(collpair[index].normal, collpair[index].vector);
- collpair->distance = distance;
- collpair->flag = 0;
- collpair++;
- }/*
- else {
- float w1, w2, w3, u1, u2, u3;
- float v1[3], v2[3], relativeVelocity[3];
+ collpair[index].distance = distance;
+ collpair[index].flag = 0;
+
+ data->collided = true;
+ }
+ else {
+ collpair[index].flag = COLLISION_INACTIVE;
+ }
+}
+
+static void cloth_selfcollision(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SelfColDetectData *data = (SelfColDetectData *)userdata;
+
+ ClothModifierData *clmd = data->clmd;
+ CollPair *collpair = data->collisions;
+ const MVertTri *tri_a, *tri_b;
+ ClothVertex *verts1 = clmd->clothObject->verts;
+ float distance = 0.0f;
+ float epsilon = clmd->coll_parms->selfepsilon;
+ float pa[3], pb[3], vect[3];
+
+ tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
+ tri_b = &clmd->clothObject->tri[data->overlap[index].indexB];
+
+ for (uint i = 0; i < 3; i++) {
+ for (uint j = 0; j < 3; j++) {
+ if (tri_a->tri[i] == tri_b->tri[j]) {
+ collpair[index].flag = COLLISION_INACTIVE;
+ return;
+ }
+ }
+ }
- // calc relative velocity
+ if (((verts1[tri_a->tri[0]].flags & verts1[tri_a->tri[1]].flags & verts1[tri_a->tri[2]].flags) |
+ (verts1[tri_b->tri[0]].flags & verts1[tri_b->tri[1]].flags & verts1[tri_b->tri[2]].flags)) & CLOTH_VERT_FLAG_NOSELFCOLL)
+ {
+ collpair[index].flag = COLLISION_INACTIVE;
+ return;
+ }
- // compute barycentric coordinates for both collision points
- collision_compute_barycentric ( collpair->pa,
- verts1[collpair->ap1].txold,
- verts1[collpair->ap2].txold,
- verts1[collpair->ap3].txold,
- &w1, &w2, &w3 );
+ /* Compute distance and normal. */
+ distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx,
+ verts1[tri_b->tri[0]].tx, verts1[tri_b->tri[1]].tx, verts1[tri_b->tri[2]].tx,
+ false, false, pa, pb, vect);
- // was: txold
- collision_compute_barycentric ( collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
- &u1, &u2, &u3 );
+ if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
+ collpair[index].ap1 = tri_a->tri[0];
+ collpair[index].ap2 = tri_a->tri[1];
+ collpair[index].ap3 = tri_a->tri[2];
- // Calculate relative "velocity".
- collision_interpolateOnTriangle ( v1, verts1[collpair->ap1].tv, verts1[collpair->ap2].tv, verts1[collpair->ap3].tv, w1, w2, w3 );
+ collpair[index].bp1 = tri_b->tri[0];
+ collpair[index].bp2 = tri_b->tri[1];
+ collpair[index].bp3 = tri_b->tri[2];
- collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
+ copy_v3_v3(collpair[index].pa, pa);
+ copy_v3_v3(collpair[index].pb, pb);
+ copy_v3_v3(collpair[index].vector, vect);
- sub_v3_v3v3(relativeVelocity, v2, v1);
+ normalize_v3_v3(collpair[index].normal, collpair[index].vector);
- if (sqrt(dot_v3v3(relativeVelocity, relativeVelocity)) >= distance)
- {
- // check for collision in the future
- collpair->flag |= COLLISION_IN_FUTURE;
- collpair++;
- }
- }*/
+ collpair[index].distance = distance;
+ collpair[index].flag = 0;
+
+ data->collided = true;
+ }
+ else {
+ collpair[index].flag = COLLISION_INACTIVE;
}
- return collpair;
}
-static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned int *maxobj, Object *ob, Object *self, int level, unsigned int modifier_type)
+static void add_collision_object(ListBase *relations, Object *ob, int level, unsigned int modifier_type)
{
CollisionModifierData *cmd= NULL;
- if (ob == self)
- return;
-
/* only get objects with collision modifier */
if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) || (modifier_type != eModifierType_Collision))
cmd= (CollisionModifierData *)modifiers_findByType(ob, modifier_type);
if (cmd) {
- /* extend array */
- if (*numobj >= *maxobj) {
- *maxobj *= 2;
- *objs= MEM_reallocN(*objs, sizeof(Object *)*(*maxobj));
- }
-
- (*objs)[*numobj] = ob;
- (*numobj)++;
+ CollisionRelation *relation = MEM_callocN(sizeof(CollisionRelation), "CollisionRelation");
+ relation->ob = ob;
+ BLI_addtail(relations, relation);
}
/* objects in dupli groups, one level only for now */
+ /* TODO: this doesn't really work, we are not taking into account the
+ * dupli transforms and can get objects in the list multiple times. */
if (ob->dup_group && level == 0) {
- GroupObject *go;
- Group *group= ob->dup_group;
+ Collection *collection= ob->dup_group;
/* add objects */
- for (go= group->gobject.first; go; go= go->next)
- add_collision_object(objs, numobj, maxobj, go->ob, self, level+1, modifier_type);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
+ {
+ add_collision_object(relations, object, level+1, modifier_type);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
-// return all collision objects in scene
-// collision object will exclude self
-Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
+/* Create list of collision relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of colliders during evaluation. */
+ListBase *BKE_collision_relations_create(Depsgraph *depsgraph, Collection *collection, unsigned int modifier_type)
{
- Base *base;
- Object **objs;
- GroupObject *go;
- unsigned int numobj= 0, maxobj= 100;
- int level = dupli ? 0 : 1;
-
- objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray");
-
- /* gather all collision objects */
- if (group) {
- /* use specified group */
- for (go= group->gobject.first; go; go= go->next)
- add_collision_object(&objs, &numobj, &maxobj, go->ob, self, level, modifier_type);
- }
- else {
- Scene *sce_iter;
- /* add objects in same layer in scene */
- for (SETLOOPER(scene, sce_iter, base)) {
- if ( base->lay & layer )
- add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ Base *base = BKE_collection_or_layer_objects(view_layer, collection);
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
+ ListBase *relations = MEM_callocN(sizeof(ListBase), "CollisionRelation list");
+
+ for (; base; base = base->next) {
+ if (base->flag & base_flag) {
+ add_collision_object(relations, base->object, 0, modifier_type);
}
}
- *numcollobj= numobj;
-
- return objs;
+ return relations;
}
-Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type)
+void BKE_collision_relations_free(ListBase *relations)
{
- /* Need to check for active layers, too.
- Otherwise this check fails if the objects are not on the same layer - DG */
- return get_collisionobjects_ext(scene, self, group, self->lay | scene->lay, numcollobj, modifier_type, true);
+ if (relations) {
+ BLI_freelistN(relations);
+ MEM_freeN(relations);
+ }
}
-static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level)
+/* Create effective list of colliders from relations built beforehand.
+ * Self will be excluded. */
+Object **BKE_collision_objects_create(Depsgraph *depsgraph, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type)
{
- CollisionModifierData *cmd= NULL;
- ColliderCache *col;
+ ListBase *relations = DEG_get_collision_relations(depsgraph, collection, modifier_type);
- if (ob == self)
- return;
+ if (!relations) {
+ *numcollobj = 0;
+ return NULL;
+ }
- if (ob->pd && ob->pd->deflect)
- cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ int maxnum = BLI_listbase_count(relations);
+ int num = 0;
+ Object **objects = MEM_callocN(sizeof(Object*) * maxnum, __func__);
- if (cmd && cmd->bvhtree) {
- if (*objs == NULL)
- *objs = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+ for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
- col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
- col->ob = ob;
- col->collmd = cmd;
- /* make sure collider is properly set up */
- collision_move_object(cmd, 1.0, 0.0);
- BLI_addtail(*objs, col);
+ if (ob != self) {
+ objects[num] = ob;
+ num++;
+ }
}
- /* objects in dupli groups, one level only for now */
- if (ob->dup_group && level == 0) {
- GroupObject *go;
- Group *group= ob->dup_group;
+ if (num == 0) {
+ MEM_freeN(objects);
+ objects = NULL;
+ }
- /* add objects */
- for (go= group->gobject.first; go; go= go->next)
- add_collider_cache_object(objs, go->ob, self, level+1);
+ *numcollobj = num;
+ return objects;
+}
+
+void BKE_collision_objects_free(Object **objects)
+{
+ if (objects) {
+ MEM_freeN(objects);
}
}
-ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
+/* Create effective list of colliders from relations built beforehand.
+ * Self will be excluded. */
+ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collection *collection)
{
- GroupObject *go;
- ListBase *objs= NULL;
+ ListBase *relations = DEG_get_collision_relations(depsgraph, collection, eModifierType_Collision);
+ ListBase *cache = NULL;
- /* add object in same layer in scene */
- if (group) {
- for (go= group->gobject.first; go; go= go->next)
- add_collider_cache_object(&objs, go->ob, self, 0);
+ if (!relations) {
+ return NULL;
}
- else {
- Scene *sce_iter;
- Base *base;
- /* add objects in same layer in scene */
- for (SETLOOPER(scene, sce_iter, base)) {
- if (!self || (base->lay & self->lay))
- add_collider_cache_object(&objs, base->object, self, 0);
+ for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
+
+ if (ob == self) {
+ continue;
+ }
+
+ CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ if (cmd && cmd->bvhtree) {
+ if (cache == NULL) {
+ cache = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+ }
+ ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
+ col->ob = ob;
+ col->collmd = cmd;
+ /* make sure collider is properly set up */
+ collision_move_object(cmd, 1.0, 0.0);
+ BLI_addtail(cache, col);
}
}
- return objs;
+ return cache;
}
-void free_collider_cache(ListBase **colliders)
+void BKE_collider_cache_free(ListBase **colliders)
{
if (*colliders) {
BLI_freelistN(*colliders);
@@ -618,25 +1058,49 @@ void free_collider_cache(ListBase **colliders)
}
}
+static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData * clmd, CollisionModifierData *collmd,
+ CollPair **collisions, int numresult,
+ BVHTreeOverlap *overlap, bool culling, bool use_normal)
+{
+ *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array");
+
+ ColDetectData data = {.clmd = clmd,
+ .collmd = collmd,
+ .overlap = overlap,
+ .collisions = *collisions,
+ .culling = culling,
+ .use_normal = use_normal,
+ .collided = false};
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = true;
+ BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings);
+
+ return data.collided;
+}
-static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd,
- CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap, double dt)
+static bool cloth_bvh_selfcollisions_nearcheck(ClothModifierData * clmd, CollPair *collisions,
+ int numresult, BVHTreeOverlap *overlap)
{
- int i;
+ SelfColDetectData data = {.clmd = clmd,
+ .overlap = overlap,
+ .collisions = collisions,
+ .collided = false};
- *collisions = (CollPair *) MEM_mallocN(sizeof(CollPair) * numresult * 4, "collision array" ); // * 4 since cloth_collision_static can return more than 1 collision
- *collisions_index = *collisions;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = true;
+ BLI_task_parallel_range(0, numresult, &data, cloth_selfcollision, &settings);
- for ( i = 0; i < numresult; i++ ) {
- *collisions_index = cloth_collision((ModifierData *)clmd, (ModifierData *)collmd,
- overlap+i, *collisions_index, dt);
- }
+ return data.collided;
}
-static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index)
+static int cloth_bvh_objcollisions_resolve(ClothModifierData * clmd, Object **collobjs, CollPair **collisions,
+ uint *collision_counts, const uint numcollobj, const float dt)
{
Cloth *cloth = clmd->clothObject;
- int i=0, j = 0, /*numfaces = 0, */ mvert_num = 0;
+ int i = 0, j = 0, mvert_num = 0;
ClothVertex *verts = NULL;
int ret = 0;
int result = 0;
@@ -644,26 +1108,68 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
mvert_num = clmd->clothObject->mvert_num;
verts = cloth->verts;
- // process all collisions (calculate impulses, TODO: also repulses if distance too short)
result = 1;
- for ( j = 0; j < 2; j++ ) { /* 5 is just a value that ensures convergence */
+
+ for (j = 0; j < 2; j++) {
result = 0;
- if ( collmd->bvhtree ) {
- result += cloth_collision_response_static ( clmd, collmd, collisions, collisions_index );
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob= collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- // apply impulses in parallel
- if (result) {
- for (i = 0; i < mvert_num; i++) {
- // calculate "velocities" (just xnew = xold + v; no dt in v)
- if (verts[i].impulse_count) {
- // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
- VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
- zero_v3(verts[i].impulse);
- verts[i].impulse_count = 0;
+ if ( collmd->bvhtree ) {
+ result += cloth_collision_response_static(clmd, collmd, collob, collisions[i], collision_counts[i], dt);
+ }
+ }
- ret++;
- }
+ /* Apply impulses in parallel. */
+ if (result) {
+ for (i = 0; i < mvert_num; i++) {
+ // calculate "velocities" (just xnew = xold + v; no dt in v)
+ if (verts[i].impulse_count) {
+ VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
+ VECADD ( verts[i].dcvel, verts[i].dcvel, verts[i].impulse);
+ zero_v3(verts[i].impulse);
+ verts[i].impulse_count = 0;
+
+ ret++;
+ }
+ }
+ }
+ else {
+ break;
+ }
+ }
+ return ret;
+}
+
+static int cloth_bvh_selfcollisions_resolve(ClothModifierData * clmd, CollPair *collisions, int collision_count, const float dt)
+{
+ Cloth *cloth = clmd->clothObject;
+ int i = 0, j = 0, mvert_num = 0;
+ ClothVertex *verts = NULL;
+ int ret = 0;
+ int result = 0;
+
+ mvert_num = clmd->clothObject->mvert_num;
+ verts = cloth->verts;
+
+ for (j = 0; j < 2; j++) {
+ result = 0;
+
+ result += cloth_selfcollision_response_static(clmd, collisions, collision_count, dt);
+
+ /* Apply impulses in parallel. */
+ if (result) {
+ for (i = 0; i < mvert_num; i++) {
+ if (verts[i].impulse_count) {
+ // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
+ VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
+ VECADD ( verts[i].dcvel, verts[i].dcvel, verts[i].impulse);
+ zero_v3(verts[i].impulse);
+ verts[i].impulse_count = 0;
+
+ ret++;
}
}
}
@@ -675,219 +1181,149 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
return ret;
}
-// cloth - object collisions
-int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt )
+int cloth_bvh_collision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
{
- Cloth *cloth= clmd->clothObject;
- BVHTree *cloth_bvh= cloth->bvhtree;
- unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ mvert_num = 0, k, l, j;
- int rounds = 0; // result counts applied collisions; ic is for debug output;
+ Cloth *cloth = clmd->clothObject;
+ BVHTree *cloth_bvh = cloth->bvhtree;
+ uint i = 0, mvert_num = 0;
+ int rounds = 0;
ClothVertex *verts = NULL;
int ret = 0, ret2 = 0;
Object **collobjs = NULL;
unsigned int numcollobj = 0;
+ uint *coll_counts_obj = NULL;
+ BVHTreeOverlap **overlap_obj = NULL;
+ uint coll_count_self = 0;
+ BVHTreeOverlap *overlap_self = NULL;
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || cloth_bvh==NULL)
return 0;
verts = cloth->verts;
- /* numfaces = cloth->numfaces; */ /* UNUSED */
mvert_num = cloth->mvert_num;
- ////////////////////////////////////////////////////////////
- // static collisions
- ////////////////////////////////////////////////////////////
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
+ bvhtree_update_from_cloth(clmd, false, false);
- // update cloth bvh
- bvhtree_update_from_cloth ( clmd, 1 ); // 0 means STATIC, 1 means MOVING (see later in this function)
- bvhselftree_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function)
+ collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ if (collobjs) {
+ coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts");
+ overlap_obj = MEM_callocN(sizeof(*overlap_obj) * numcollobj, "BVHOverlap");
- if (!collobjs)
- return 0;
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- /* move object to position (step) in time */
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
+ if (!collmd->bvhtree) {
+ continue;
+ }
- if (!collmd->bvhtree)
- continue;
+ /* Move object to position (step) in time. */
+ collision_move_object(collmd, step + dt, step);
- /* move object to position (step) in time */
- collision_move_object ( collmd, step + dt, step );
+ overlap_obj[i] = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL);
+ }
+ }
}
- do {
- CollPair **collisions, **collisions_index;
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
+ bvhtree_update_from_cloth(clmd, false, true);
+
+ overlap_self = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &coll_count_self, NULL, NULL);
+ }
+ do {
ret2 = 0;
- collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
- collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
+ /* Object collisions. */
+ if ((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) && collobjs) {
+ CollPair **collisions;
+ bool collided = false;
- // check all collision objects
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- BVHTreeOverlap *overlap = NULL;
- unsigned int result = 0;
+ collisions = MEM_callocN(sizeof(CollPair *) * numcollobj, "CollPair");
- if (!collmd->bvhtree)
- continue;
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- /* search for overlapping collision pairs */
- overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
+ if (!collmd->bvhtree) {
+ continue;
+ }
- // go to next object if no overlap is there
- if ( result && overlap ) {
- /* check if collisions really happen (costly near check) */
- cloth_bvh_objcollisions_nearcheck ( clmd, collmd, &collisions[i],
- &collisions_index[i], result, overlap, dt/(float)clmd->coll_parms->loop_count);
+ if (coll_counts_obj[i] && overlap_obj[i]) {
+ collided = cloth_bvh_objcollisions_nearcheck(clmd, collmd, &collisions[i], coll_counts_obj[i], overlap_obj[i],
+ (collob->pd->flag & PFIELD_CLOTH_USE_CULLING),
+ (collob->pd->flag & PFIELD_CLOTH_USE_NORMAL)) || collided;
+ }
+ }
- // resolve nearby collisions
- ret += cloth_bvh_objcollisions_resolve ( clmd, collmd, collisions[i], collisions_index[i]);
+ if (collided) {
+ ret += cloth_bvh_objcollisions_resolve(clmd, collobjs, collisions, coll_counts_obj, numcollobj, dt);
ret2 += ret;
}
- if ( overlap )
- MEM_freeN ( overlap );
- }
- rounds++;
+ for (i = 0; i < numcollobj; i++) {
+ MEM_SAFE_FREE(collisions[i]);
+ }
- for (i = 0; i < numcollobj; i++) {
- if ( collisions[i] ) MEM_freeN ( collisions[i] );
+ MEM_freeN(collisions);
}
- MEM_freeN(collisions);
- MEM_freeN(collisions_index);
+ /* Self collisions. */
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
+ CollPair *collisions = NULL;
- ////////////////////////////////////////////////////////////
- // update positions
- // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
- ////////////////////////////////////////////////////////////
+ verts = cloth->verts;
+ mvert_num = cloth->mvert_num;
- /* verts come from clmd */
- for (i = 0; i < mvert_num; i++) {
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
- if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
- continue;
+ if (cloth->bvhselftree) {
+ if (coll_count_self && overlap_self) {
+ collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * coll_count_self, "collision array");
+
+ if (cloth_bvh_selfcollisions_nearcheck(clmd, collisions, coll_count_self, overlap_self)) {
+ ret += cloth_bvh_selfcollisions_resolve(clmd, collisions, coll_count_self, dt);
+ ret2 += ret;
+ }
}
+
}
- VECADD ( verts[i].tx, verts[i].txold, verts[i].tv );
+ MEM_SAFE_FREE(collisions);
}
- ////////////////////////////////////////////////////////////
-
-
- ////////////////////////////////////////////////////////////
- // Test on *simple* selfcollisions
- ////////////////////////////////////////////////////////////
- if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) {
- for (l = 0; l < (unsigned int)clmd->coll_parms->self_loop_count; l++) {
- /* TODO: add coll quality rounds again */
- BVHTreeOverlap *overlap = NULL;
- unsigned int result = 0;
-
- // collisions = 1;
- verts = cloth->verts; // needed for openMP
-
- /* numfaces = cloth->numfaces; */ /* UNUSED */
- mvert_num = cloth->mvert_num;
-
- verts = cloth->verts;
-
- if ( cloth->bvhselftree ) {
- // search for overlapping collision pairs
- overlap = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &result, NULL, NULL);
-
- /* Could be parallelized (using BLI_task)... */
- for ( k = 0; k < result; k++ ) {
- float temp[3];
- float length = 0;
- float mindistance;
-
- i = overlap[k].indexA;
- j = overlap[k].indexB;
-
- mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len );
-
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
- if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) &&
- ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) )
- {
- continue;
- }
- }
-
- if ((cloth->verts[i].flags & CLOTH_VERT_FLAG_NOSELFCOLL) ||
- (cloth->verts[j].flags & CLOTH_VERT_FLAG_NOSELFCOLL))
- {
- continue;
- }
-
- sub_v3_v3v3(temp, verts[i].tx, verts[j].tx);
-
- if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue;
-
- if (BLI_edgeset_haskey(cloth->edgeset, i, j)) {
- continue;
- }
-
- length = normalize_v3(temp );
-
- if ( length < mindistance ) {
- float correction = mindistance - length;
-
- if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
- mul_v3_fl(temp, -correction);
- VECADD ( verts[j].tx, verts[j].tx, temp );
- }
- else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) {
- mul_v3_fl(temp, correction);
- VECADD ( verts[i].tx, verts[i].tx, temp );
- }
- else {
- mul_v3_fl(temp, correction * -0.5f);
- VECADD ( verts[j].tx, verts[j].tx, temp );
-
- sub_v3_v3v3(verts[i].tx, verts[i].tx, temp);
- }
- ret = 1;
- ret2 += ret;
- }
- else {
- // check for approximated time collisions
- }
- }
-
- if ( overlap )
- MEM_freeN ( overlap );
- }
- }
- ////////////////////////////////////////////////////////////
-
- ////////////////////////////////////////////////////////////
- // SELFCOLLISIONS: update velocities
- ////////////////////////////////////////////////////////////
- if (ret2) {
- for (i = 0; i < cloth->mvert_num; i++) {
- if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) {
- sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
+ /* Apply all collision resolution. */
+ if (ret2) {
+ for (i = 0; i < mvert_num; i++) {
+ if (clmd->sim_parms->vgroup_mass > 0) {
+ if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
+ continue;
}
}
+
+ VECADD(verts[i].tx, verts[i].txold, verts[i].tv);
}
- ////////////////////////////////////////////////////////////
}
+
+ rounds++;
}
- while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
+ while (ret2 && (clmd->coll_parms->loop_count > rounds));
- if (collobjs)
- MEM_freeN(collobjs);
+ if (overlap_obj) {
+ for (i = 0; i < numcollobj; i++) {
+ MEM_SAFE_FREE(overlap_obj[i]);
+ }
+
+ MEM_freeN(overlap_obj);
+ }
- return 1|MIN2 ( ret, 1 );
+ MEM_SAFE_FREE(coll_counts_obj);
+
+ MEM_SAFE_FREE(overlap_self);
+
+ BKE_collision_objects_free(collobjs);
+
+ return MIN2(ret, 1);
}
BLI_INLINE void max_v3_v3v3(float r[3], const float a[3], const float b[3])
@@ -913,106 +1349,6 @@ void collision_get_collider_velocity(float vel_old[3], float vel_new[3], Collisi
copy_v3_v3(vel_old, vel_new);
}
-static bool cloth_points_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd,
- CollPair *collpair, CollPair *collision_end, float dt)
-{
- bool result = false;
- float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - pd->pdef_sbdamp);
- float inv_dt = 1.0f / dt;
- Cloth *cloth1 = clmd->clothObject;
-
- // float w1, w2;
- float u1, u2, u3;
- float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
-
- for ( ; collpair != collision_end; collpair++ ) {
- float margin_distance = (float)(collpair->distance - (double)epsilon2);
- float impulse[3];
- float mag_v_rel;
-
- if (margin_distance > 0.0f)
- continue;
-
- zero_v3(impulse);
-
- /* only handle static collisions here */
- if ( collpair->flag & COLLISION_IN_FUTURE )
- continue;
-
- /* compute barycentric coordinates for both collision points */
- // w1 = 1.0f - collpair->time;
- // w2 = collpair->time;
-
- /* was: txold */
- collision_compute_barycentric ( collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
- &u1, &u2, &u3 );
-
- /* Calculate relative velocity */
- copy_v3_v3(v1, cloth1->verts[collpair->ap1].tv);
-
- collision_interpolateOnTriangle ( v2_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
- /* XXX assume constant velocity of the collider for now */
- copy_v3_v3(v2_old, v2_new);
-
- sub_v3_v3v3(v_rel_old, v1, v2_old);
- sub_v3_v3v3(v_rel_new, v1, v2_new);
-
- /* normal component of the relative velocity */
- mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
-
- /**** DEBUG ****/
- BKE_sim_debug_data_add_dot(collpair->pa, 0.9, 0.2, 0.2, "collision", 833, collpair->face1, collpair->face2);
- BKE_sim_debug_data_add_dot(collpair->pb, 0.2, 0.9, 0.2, "collision", 834, collpair->face1, collpair->face2);
- BKE_sim_debug_data_add_line(collpair->pa, collpair->pb, 0.8, 0.8, 0.8, "collision", 835, collpair->face1, collpair->face2);
- /********/
-
- if (mag_v_rel < -ALMOST_ZERO) {
- float v_nor_old, v_nor_new;
- float v_tan_old[3], v_tan_new[3];
- float bounce, repulse;
-
- /* Collision response based on
- * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
- * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
- */
-
- v_nor_old = mag_v_rel;
- v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
-
- madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
- madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
-
- repulse = -margin_distance * inv_dt + dot_v3v3(v1, collpair->normal);
-
- if (margin_distance < -epsilon2) {
- bounce = -v_nor_new + v_nor_old * restitution;
- mul_v3_v3fl(impulse, collpair->normal, max_ff(repulse, bounce));
- }
- else {
- bounce = 0.0f;
- mul_v3_v3fl(impulse, collpair->normal, repulse);
- }
- cloth1->verts[collpair->ap1].impulse_count++;
-
- result = true;
- }
-
- if (result) {
- int i = 0;
-
- for (i = 0; i < 3; i++) {
- if (cloth1->verts[collpair->ap1].impulse_count > 0 && fabsf(cloth1->verts[collpair->ap1].impulse[i]) < fabsf(impulse[i]))
- cloth1->verts[collpair->ap1].impulse[i] = impulse[i];
- }
- }
- }
- return result;
-}
-
BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3],
float r_nor[3], float *r_lambda, float r_w[3])
{
@@ -1024,60 +1360,16 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float
cross_v3_v3v3(r_nor, edge1, edge2);
normalize_v3(r_nor);
+ sub_v3_v3v3(v0p2, p2, v0);
nor_v0p2 = dot_v3v3(v0p2, r_nor);
madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
sub_v3_v3v3(p1p2, p2, p1);
- sub_v3_v3v3(v0p2, p2, v0);
nor_p1p2 = dot_v3v3(p1p2, r_nor);
*r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f);
return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f;
-
-#if 0 /* XXX this method uses the intersection point, but is broken and doesn't work well in general */
- float p[3], vec1[3], line[3], edge1[3], edge2[3], q[3];
- float a, f, u, v;
-
- sub_v3_v3v3(edge1, v1, v0);
- sub_v3_v3v3(edge2, v2, v0);
- sub_v3_v3v3(line, p2, p1);
-
- cross_v3_v3v3(p, line, edge2);
- a = dot_v3v3(edge1, p);
- if (a == 0.0f) return 0;
- f = 1.0f / a;
-
- sub_v3_v3v3(vec1, p1, v0);
-
- u = f * dot_v3v3(vec1, p);
- if ((u < 0.0f) || (u > 1.0f))
- return false;
-
- cross_v3_v3v3(q, vec1, edge1);
-
- v = f * dot_v3v3(line, q);
- if ((v < 0.0f) || ((u + v) > 1.0f))
- return false;
-
- *r_lambda = f * dot_v3v3(edge2, q);
- /* don't care about 0..1 lambda range here */
-#if 0
- if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) {
- return 0;
- }
-#endif
-
- r_w[0] = 1.0f - u - v;
- r_w[1] = u;
- r_w[2] = v;
- r_w[3] = 0.0f;
-
- cross_v3_v3v3(r_nor, edge1, edge2);
- normalize_v3(r_nor);
-
- return true;
-#endif
}
static CollPair *cloth_point_collpair(
@@ -1166,162 +1458,7 @@ static void cloth_points_objcollisions_nearcheck(
}
}
-static int cloth_points_objcollisions_resolve(
- ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd,
- CollPair *collisions, CollPair *collisions_index, float dt)
-{
- Cloth *cloth = clmd->clothObject;
- int i = 0, mvert_num = clmd->clothObject->mvert_num;
- ClothVertex *verts = cloth->verts;
- int ret = 0;
-
- // process all collisions
- if ( collmd->bvhtree ) {
- bool result = cloth_points_collision_response_static(clmd, collmd, pd, collisions, collisions_index, dt);
-
- // apply impulses in parallel
- if (result) {
- for (i = 0; i < mvert_num; i++) {
- // calculate "velocities" (just xnew = xold + v; no dt in v)
- if (verts[i].impulse_count) {
- // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
- VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
- zero_v3(verts[i].impulse);
- verts[i].impulse_count = 0;
-
- ret++;
- }
- }
- }
- }
-
- return ret;
-}
-
-// cloth - object collisions
-int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt)
-{
- Cloth *cloth= clmd->clothObject;
- BVHTree *cloth_bvh;
- int rounds = 0; // result counts applied collisions; ic is for debug output;
- float round_dt = dt / (float)clmd->coll_parms->loop_count;
- unsigned int i = 0, mvert_num = 0;
- ClothVertex *verts = NULL;
- int ret = 0, ret2 = 0;
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- verts = cloth->verts;
- mvert_num = cloth->mvert_num;
-
- ////////////////////////////////////////////////////////////
- // static collisions
- ////////////////////////////////////////////////////////////
-
- // create temporary cloth points bvh
- cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
- /* fill tree */
- for (i = 0; i < mvert_num; i++) {
- float co[2][3];
-
- copy_v3_v3(co[0], verts[i].x);
- copy_v3_v3(co[1], verts[i].tx);
-
- BLI_bvhtree_insert(cloth_bvh, i, co[0], 2);
- }
- /* balance tree */
- BLI_bvhtree_balance(cloth_bvh);
-
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
- if (!collobjs)
- return 0;
-
- /* move object to position (step) in time */
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- if (!collmd->bvhtree)
- continue;
-
- /* move object to position (step) in time */
- collision_move_object ( collmd, step + dt, step );
- }
-
- do {
- CollPair **collisions, **collisions_index;
-
- ret2 = 0;
-
- collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
- collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
-
- // check all collision objects
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- BVHTreeOverlap *overlap = NULL;
- unsigned int result = 0;
- float epsilon;
-
- if (!collmd->bvhtree)
- continue;
-
- /* search for overlapping collision pairs */
- overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
-
- // go to next object if no overlap is there
- if (result && overlap) {
- /* check if collisions really happen (costly near check) */
- cloth_points_objcollisions_nearcheck(clmd, collmd, &collisions[i], &collisions_index[i],
- result, overlap, epsilon, round_dt);
-
- // resolve nearby collisions
- ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], round_dt);
- ret2 += ret;
- }
-
- if (overlap)
- MEM_freeN ( overlap );
- }
- rounds++;
-
- for (i = 0; i < numcollobj; i++) {
- if (collisions[i])
- MEM_freeN(collisions[i]);
- }
-
- MEM_freeN(collisions);
- MEM_freeN(collisions_index);
-
- ////////////////////////////////////////////////////////////
- // update positions
- // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
- ////////////////////////////////////////////////////////////
-
- // verts come from clmd
- for (i = 0; i < mvert_num; i++) {
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
- if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
- continue;
- }
- }
-
- VECADD ( verts[i].tx, verts[i].txold, verts[i].tv );
- }
- ////////////////////////////////////////////////////////////
- }
- while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
-
- if (collobjs)
- MEM_freeN(collobjs);
-
- BLI_bvhtree_free(cloth_bvh);
-
- return 1|MIN2 ( ret, 1 );
-}
-
-void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, float dt,
+void cloth_find_point_contacts(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt,
ColliderContacts **r_collider_contacts, int *r_totcolliders)
{
Cloth *cloth= clmd->clothObject;
@@ -1342,7 +1479,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
////////////////////////////////////////////////////////////
/* Check we do have collision objects to test against, before doing anything else. */
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
if (!collobjs) {
*r_collider_contacts = NULL;
*r_totcolliders = 0;
@@ -1350,7 +1487,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
}
// create temporary cloth points bvh
- cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
+ cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6);
/* fill tree */
for (i = 0; i < mvert_num; i++) {
float co[6];
@@ -1414,8 +1551,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
MEM_freeN(overlap);
}
- if (collobjs)
- MEM_freeN(collobjs);
+ BKE_collision_objects_free(collobjs);
BLI_bvhtree_free(cloth_bvh);
@@ -1426,7 +1562,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
// verts come from clmd
for (i = 0; i < mvert_num; i++) {
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
+ if (clmd->sim_parms->vgroup_mass > 0) {
if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
continue;
}
diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c
index f72d4df725a..7fc1124a422 100644
--- a/source/blender/blenkernel/intern/colorband.c
+++ b/source/blender/blenkernel/intern/colorband.c
@@ -78,7 +78,9 @@ void BKE_colorband_init(ColorBand *coba, bool rangetype)
}
coba->tot = 2;
+ coba->cur = 0;
coba->color_mode = COLBAND_BLEND_RGB;
+ coba->ipotype = COLBAND_INTERP_LINEAR;
}
static void colorband_init_from_table_rgba_simple(
@@ -208,7 +210,7 @@ static void colorband_init_from_table_rgba_resample(
}
while ((carr_len > 1 && !BLI_heap_is_empty(heap)) &&
- ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x)))
+ ((carr_len >= MAXCOLORBAND) || (BLI_heap_top_value(heap) <= eps_2x)))
{
c = BLI_heap_pop_min(heap);
struct ColorResampleElem *c_next = c->next, *c_prev = c->prev;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index ff4795afe87..108e188fe92 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -282,6 +282,7 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
case CURVE_PRESET_MID9: cuma->totpoint = 9; break;
case CURVE_PRESET_ROUND: cuma->totpoint = 4; break;
case CURVE_PRESET_ROOT: cuma->totpoint = 4; break;
+ case CURVE_PRESET_GAUSS: cuma->totpoint = 7; break;
}
cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
@@ -352,6 +353,24 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
cuma->curve[3].x = 1;
cuma->curve[3].y = 0;
break;
+ case CURVE_PRESET_GAUSS:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 0.025f;
+ cuma->curve[1].x = 0.16f;
+ cuma->curve[1].y = 0.135f;
+ cuma->curve[2].x = 0.298f;
+ cuma->curve[2].y = 0.36f;
+
+ cuma->curve[3].x = 0.50f;
+ cuma->curve[3].y = 1.0f;
+
+ cuma->curve[4].x = 0.70f;
+ cuma->curve[4].y = 0.36f;
+ cuma->curve[5].x = 0.84f;
+ cuma->curve[5].y = 0.135f;
+ cuma->curve[6].x = 1.0f;
+ cuma->curve[6].y = 0.025f;
+ break;
}
/* mirror curve in x direction to have positive slope
@@ -919,6 +938,22 @@ void curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const
vecout[2] = curvemap_evaluateF(&cumap->cm[2], curvemap_evaluateF(&cumap->cm[3], vecin[2]));
}
+static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap, float vecout[3], const float vecin[3],
+ const int channel_offset[3])
+{
+ const float v0in = vecin[channel_offset[0]];
+ const float v1in = vecin[channel_offset[1]];
+ const float v2in = vecin[channel_offset[2]];
+
+ const float v0 = curvemap_evaluateF(&cumap->cm[channel_offset[0]], v0in);
+ const float v2 = curvemap_evaluateF(&cumap->cm[channel_offset[2]], v2in);
+ const float v1 = v2 + ((v0 - v2) * (v1in - v2in) / (v0in - v2in));
+
+ vecout[channel_offset[0]] = v0;
+ vecout[channel_offset[1]] = v1;
+ vecout[channel_offset[2]] = v2;
+}
+
/** same as #curvemapping_evaluate_premulRGBF
* but black/bwmul are passed as args for the compositor
* where they can change per pixel.
@@ -928,20 +963,73 @@ void curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const
* \param black Use instead of cumap->black
* \param bwmul Use instead of cumap->bwmul
*/
-void curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap, float vecout[3], const float vecin[3],
- const float black[3], const float bwmul[3])
+void curvemapping_evaluate_premulRGBF_ex(
+ const CurveMapping *cumap, float vecout[3], const float vecin[3],
+ const float black[3], const float bwmul[3])
{
- vecout[0] = curvemap_evaluateF(&cumap->cm[0], (vecin[0] - black[0]) * bwmul[0]);
- vecout[1] = curvemap_evaluateF(&cumap->cm[1], (vecin[1] - black[1]) * bwmul[1]);
- vecout[2] = curvemap_evaluateF(&cumap->cm[2], (vecin[2] - black[2]) * bwmul[2]);
+ const float r = (vecin[0] - black[0]) * bwmul[0];
+ const float g = (vecin[1] - black[1]) * bwmul[1];
+ const float b = (vecin[2] - black[2]) * bwmul[2];
+
+ switch (cumap->tone) {
+ default:
+ case CURVE_TONE_STANDARD:
+ {
+ vecout[0] = curvemap_evaluateF(&cumap->cm[0], r);
+ vecout[1] = curvemap_evaluateF(&cumap->cm[1], g);
+ vecout[2] = curvemap_evaluateF(&cumap->cm[2], b);
+ break;
+ }
+ case CURVE_TONE_FILMLIKE:
+ {
+ if (r >= g) {
+ if (g > b) {
+ /* Case 1: r >= g > b */
+ const int shuffeled_channels[] = {0, 1, 2};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > r) {
+ /* Case 2: b > r >= g */
+ const int shuffeled_channels[] = {2, 0, 1};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > g) {
+ /* Case 3: r >= b > g */
+ const int shuffeled_channels[] = {0, 2, 1};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else {
+ /* Case 4: r >= g == b */
+ copy_v2_fl2(vecout, curvemap_evaluateF(&cumap->cm[0], r), curvemap_evaluateF(&cumap->cm[1], g));
+ vecout[2] = vecout[1];
+ }
+ }
+ else {
+ if (r >= b) {
+ /* Case 5: g > r >= b */
+ const int shuffeled_channels[] = {1, 0, 2};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > g) {
+ /* Case 6: b > g > r */
+ const int shuffeled_channels[] = {2, 1, 0};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else {
+ /* Case 7: g >= b > r */
+ const int shuffeled_channels[] = {1, 2, 0};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ }
+ break;
+ }
+ }
}
/* RGB with black/white points and premult. tables are checked */
void curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
{
- vecout[0] = curvemap_evaluateF(&cumap->cm[0], (vecin[0] - cumap->black[0]) * cumap->bwmul[0]);
- vecout[1] = curvemap_evaluateF(&cumap->cm[1], (vecin[1] - cumap->black[1]) * cumap->bwmul[1]);
- vecout[2] = curvemap_evaluateF(&cumap->cm[2], (vecin[2] - cumap->black[2]) * cumap->bwmul[2]);
+ curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul);
}
/* same as above, byte version */
@@ -1401,17 +1489,6 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
scopes_update_cb,
&settings);
- /* test for nicer distribution even - non standard, leave it out for a while */
-#if 0
- for (a = 0; a < 256; a++) {
- bin_lum[a] = sqrt (bin_lum[a]);
- bin_r[a] = sqrt(bin_r[a]);
- bin_g[a] = sqrt(bin_g[a]);
- bin_b[a] = sqrt(bin_b[a]);
- bin_a[a] = sqrt(bin_a[a]);
- }
-#endif
-
/* convert hist data to float (proportional to max count) */
nl = na = nr = nb = ng = 0;
for (a = 0; a < 256; a++) {
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 66147c44352..8c31b830ff7 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -52,6 +52,7 @@
#include "DNA_object_types.h"
#include "DNA_action_types.h"
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_lattice_types.h"
@@ -68,22 +69,24 @@
#include "BKE_camera.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_displist.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h" /* for geometry targets */
-#include "BKE_cdderivedmesh.h" /* for geometry targets */
-#include "BKE_object.h"
+#include "BKE_displist.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
-#include "BKE_library.h"
#include "BKE_idprop.h"
-#include "BKE_shrinkwrap.h"
-#include "BKE_editmesh.h"
+#include "BKE_library.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_movieclip.h"
+#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_shrinkwrap.h"
#include "BKE_tracking.h"
-#include "BKE_movieclip.h"
#include "BIK_api.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#ifdef WITH_PYTHON
# include "BPY_extern.h"
#endif
@@ -98,17 +101,16 @@
/* Constraint Target Macros */
#define VALID_CONS_TARGET(ct) ((ct) && (ct->tar))
-/* Workaround for cyclic depenndnecy with curves.
- * In such case curve_cache might not be ready yet,
- */
-#define CYCLIC_DEPENDENCY_WORKAROUND
-
/* ************************ Constraints - General Utilities *************************** */
/* These functions here don't act on any specific constraints, and are therefore should/will
* not require any of the special function-pointers afforded by the relevant constraint
* type-info structs.
*/
+static void damptrack_do_transform(float matrix[4][4], const float tarvec[3], int track_axis);
+
+static bConstraint *constraint_find_original(Object *ob, bPoseChannel *pchan, bConstraint *con, Object **r_orig_ob);
+
/* -------------- Naming -------------- */
/* Find the first available, non-duplicate name for a given constraint */
@@ -121,7 +123,7 @@ void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
/* package an object/bone for use in constraint evaluation */
/* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */
-bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype)
+bConstraintOb *BKE_constraints_make_evalob(Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
{
bConstraintOb *cob;
@@ -130,6 +132,7 @@ bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subda
/* for system time, part of deglobalization, code nicer later with local time (ton) */
cob->scene = scene;
+ cob->depsgraph = depsgraph;
/* based on type of available data */
switch (datatype) {
@@ -392,99 +395,104 @@ void BKE_constraint_mat_convertspace(
/* function that sets the given matrix based on given vertex group in mesh */
static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[4][4])
{
- DerivedMesh *dm = NULL;
+ /* when not in EditMode, use the 'final' evaluated mesh, depsgraph
+ * ensures we build with CD_MDEFORMVERT layer
+ */
+ Mesh *me_eval = ob->runtime.mesh_eval;
BMEditMesh *em = BKE_editmesh_from_object(ob);
- float vec[3] = {0.0f, 0.0f, 0.0f};
- float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3];
+ float plane[3];
float imat[3][3], tmat[3][3];
const int defgroup = defgroup_name_index(ob, substring);
- short freeDM = 0;
/* initialize target matrix using target matrix */
copy_m4_m4(mat, ob->obmat);
/* get index of vertex group */
- if (defgroup == -1) return;
-
- /* get DerivedMesh */
- if (em) {
- /* target is in editmode, so get a special derived mesh */
- dm = CDDM_from_editbmesh(em, false, false);
- freeDM = 1;
- }
- else {
- /* when not in EditMode, use the 'final' derived mesh, depsgraph
- * ensures we build with CD_MDEFORMVERT layer
- */
- dm = (DerivedMesh *)ob->derivedFinal;
+ if (defgroup == -1) {
+ return;
}
- /* only continue if there's a valid DerivedMesh */
- if (dm) {
- MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
- int numVerts = dm->getNumVerts(dm);
- int i;
- float co[3], nor[3];
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ float normal[3] = {0.0f, 0.0f, 0.0f};
+ float weightsum = 0.0f;
+ if (me_eval) {
+ MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT);
+ int numVerts = me_eval->totvert;
/* check that dvert is a valid pointers (just in case) */
if (dvert) {
MDeformVert *dv = dvert;
- float weightsum = 0.0f;
+ MVert *mv = me_eval->mvert;
/* get the average of all verts with that are in the vertex-group */
- for (i = 0; i < numVerts; i++, dv++) {
+ for (int i = 0; i < numVerts; i++, dv++, mv++) {
MDeformWeight *dw = defvert_find_index(dv, defgroup);
if (dw && dw->weight > 0.0f) {
- dm->getVertCo(dm, i, co);
- dm->getVertNo(dm, i, nor);
- madd_v3_v3fl(vec, co, dw->weight);
+ float nor[3];
+ normal_short_to_float_v3(nor, mv->no);
+ madd_v3_v3fl(vec, mv->co, dw->weight);
madd_v3_v3fl(normal, nor, dw->weight);
weightsum += dw->weight;
}
}
+ }
+ }
+ else if (em) {
+ if (CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
+ BMVert *v;
+ BMIter iter;
- /* calculate averages of normal and coordinates */
- if (weightsum > 0) {
- mul_v3_fl(vec, 1.0f / weightsum);
- mul_v3_fl(normal, 1.0f / weightsum);
- }
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, v->head.data, CD_MDEFORMVERT);
+ MDeformWeight *dw = defvert_find_index(dv, defgroup);
+ if (dw && dw->weight > 0.0f) {
+ madd_v3_v3fl(vec, v->co, dw->weight);
+ madd_v3_v3fl(normal, v->no, dw->weight);
+ weightsum += dw->weight;
+ }
+ }
+ }
+ }
+ else {
+ /* No valid edit or evaluated mesh, just abort. */
+ return;
+ }
- /* derive the rotation from the average normal:
- * - code taken from transform_manipulator.c,
- * calc_manipulator_stats, V3D_MANIP_NORMAL case
- */
- /* we need the transpose of the inverse for a normal... */
- copy_m3_m4(imat, ob->obmat);
+ /* calculate averages of normal and coordinates */
+ if (weightsum > 0) {
+ mul_v3_fl(vec, 1.0f / weightsum);
+ mul_v3_fl(normal, 1.0f / weightsum);
+ }
- invert_m3_m3(tmat, imat);
- transpose_m3(tmat);
- mul_m3_v3(tmat, normal);
+ /* derive the rotation from the average normal:
+ * - code taken from transform_gizmo.c,
+ * calc_gizmo_stats, V3D_MANIP_NORMAL case
+ */
+ /* we need the transpose of the inverse for a normal... */
+ copy_m3_m4(imat, ob->obmat);
- normalize_v3(normal);
- copy_v3_v3(plane, tmat[1]);
+ invert_m3_m3(tmat, imat);
+ transpose_m3(tmat);
+ mul_m3_v3(tmat, normal);
- cross_v3_v3v3(mat[0], normal, plane);
- if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) {
- copy_v3_v3(plane, tmat[0]);
- cross_v3_v3v3(mat[0], normal, plane);
- }
+ normalize_v3(normal);
+ copy_v3_v3(plane, tmat[1]);
- copy_v3_v3(mat[2], normal);
- cross_v3_v3v3(mat[1], mat[2], mat[0]);
-
- normalize_m4(mat);
+ cross_v3_v3v3(mat[0], normal, plane);
+ if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) {
+ copy_v3_v3(plane, tmat[0]);
+ cross_v3_v3v3(mat[0], normal, plane);
+ }
+ copy_v3_v3(mat[2], normal);
+ cross_v3_v3v3(mat[1], mat[2], mat[0]);
- /* apply the average coordinate as the new location */
- mul_v3_m4v3(mat[3], ob->obmat, vec);
- }
- }
+ normalize_m4(mat);
- /* free temporary DerivedMesh created (in EditMode case) */
- if (dm && freeDM)
- dm->release(dm);
+ /* apply the average coordinate as the new location */
+ mul_v3_m4v3(mat[3], ob->obmat, vec);
}
/* function that sets the given matrix based on given vertex group in lattice */
@@ -492,7 +500,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
{
Lattice *lt = (Lattice *)ob->data;
- DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL;
const float *co = dl ? dl->verts : NULL;
BPoint *bp = lt->def;
@@ -575,19 +583,19 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
* PoseChannel by the Armature Object's Matrix to get a worldspace
* matrix.
*/
- if (headtail < 0.000001f) {
+ bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE);
+ bool full_bbone = (flag & CONSTRAINT_BBONE_SHAPE_FULL) != 0;
+
+ if (headtail < 0.000001f && !(is_bbone && full_bbone)) {
/* skip length interpolation if set to head */
mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
}
- else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) {
+ else if (is_bbone && pchan->bone->segments == pchan->runtime.bbone_segments) {
/* use point along bbone */
- Mat4 bbone[MAX_BBONE_SUBDIV];
+ Mat4 *bbone = pchan->runtime.bbone_pose_mats;
float tempmat[4][4];
float loc[3], fac;
- /* get bbone segments */
- b_bone_spline_setup(pchan, 0, bbone);
-
/* figure out which segment(s) the headtail value falls in */
fac = (float)pchan->bone->segments * headtail;
@@ -625,8 +633,18 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
mul_v3_m4v3(loc, pchan->pose_mat, pt);
}
+ /* apply full transformation of the segment if requested */
+ if (full_bbone) {
+ int index = floorf(fac);
+ CLAMP(index, 0, pchan->bone->segments - 1);
+
+ mul_m4_m4m4(tempmat, pchan->pose_mat, bbone[index].mat);
+ }
+ else {
+ copy_m4_m4(tempmat, pchan->pose_mat);
+ }
+
/* use interpolated distance for subtarget */
- copy_m4_m4(tempmat, pchan->pose_mat);
copy_v3_v3(tempmat[3], loc);
mul_m4_m4m4(mat, ob->obmat, tempmat);
@@ -689,7 +707,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
/* This function should be used for the get_target_matrix member of all
* constraints that are not picky about what happens to their target matrix.
*/
-static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
+static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct))
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
@@ -697,6 +715,16 @@ static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bCo
unit_m4(ct->matrix);
}
+/* This is a variant that extracts full transformation from B-Bone segments.
+ */
+static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
+{
+ if (VALID_CONS_TARGET(ct))
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag | CONSTRAINT_BBONE_SHAPE_FULL, con->headtail);
+ else if (ct)
+ unit_m4(ct->matrix);
+}
+
/* This following macro should be used for all standard single-target *_get_tars functions
* to save typing and reduce maintenance woes.
* (Hopefully all compilers will be happy with the lines with just a space on them. Those are
@@ -1158,7 +1186,7 @@ static void kinematic_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bKinematicConstraint *data = con->data;
@@ -1245,7 +1273,9 @@ static void followpath_flush_tars(bConstraint *con, ListBase *list, bool no_copy
}
}
-static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con, bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
bFollowPathConstraint *data = con->data;
@@ -1260,13 +1290,7 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
* currently for paths to work it needs to go through the bevlist/displist system (ton)
*/
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
-#endif
-
- if (ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) {
+ if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path && ct->tar->runtime.curve_cache->path->data) {
float quat[4];
if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
/* animated position along curve depending on time */
@@ -1303,21 +1327,7 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
unit_m4(totmat);
if (data->followflag & FOLLOWPATH_FOLLOW) {
-#if 0
- float x1, q[4];
- vec_to_quat(quat, dir, (short)data->trackflag, (short)data->upflag);
-
- normalize_v3(dir);
- q[0] = cosf(0.5 * vec[3]);
- x1 = sinf(0.5 * vec[3]);
- q[1] = -x1 * dir[0];
- q[2] = -x1 * dir[1];
- q[3] = -x1 * dir[2];
- mul_qt_qtqt(quat, q, quat);
-#else
quat_apply_track(quat, data->trackflag, data->upflag);
-#endif
-
quat_to_mat4(totmat, quat);
}
@@ -1760,7 +1770,7 @@ static void sizelike_new_data(void *cdata)
{
bSizeLikeConstraint *data = (bSizeLikeConstraint *)cdata;
- data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z;
+ data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z | SIZELIKE_MULTIPLY;
}
static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -1808,29 +1818,28 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta
mat4_to_size(size, ct->matrix);
mat4_to_size(obsize, cob->matrix);
- if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
- if (data->flag & SIZELIKE_OFFSET) {
- size[0] += (obsize[0] - 1.0f);
- mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
+ if (data->flag & SIZELIKE_OFFSET) {
+ /* Scale is a multiplicative quantity, so adding it makes no sense.
+ * However, the additive mode has to stay for backward compatibility. */
+ if (data->flag & SIZELIKE_MULTIPLY) {
+ /* size[i] *= obsize[i] */
+ mul_v3_v3(size, obsize);
+ }
+ else {
+ /* 2.7 compatibility mode: size[i] += (obsize[i] - 1.0f) */
+ add_v3_v3(size, obsize);
+ add_v3_fl(size, -1.0f);
}
- else
- mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
+ }
+
+ if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
+ mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
}
if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) {
- if (data->flag & SIZELIKE_OFFSET) {
- size[1] += (obsize[1] - 1.0f);
- mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
- }
- else
- mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
+ mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
}
if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) {
- if (data->flag & SIZELIKE_OFFSET) {
- size[2] += (obsize[2] - 1.0f);
- mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
- }
- else
- mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
+ mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
}
}
}
@@ -1907,7 +1916,7 @@ static bConstraintTypeInfo CTI_TRANSLIKE = {
NULL, /* new data */
translike_get_tars, /* get constraint targets */
translike_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
+ default_get_tarmat_full_bbone, /* get target matrix */
translike_evaluate /* evaluate */
};
@@ -2028,21 +2037,19 @@ static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userd
}
/* Whether this approach is maintained remains to be seen (aligorith) */
-static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con, bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
#ifdef WITH_PYTHON
bPythonConstraint *data = con->data;
#endif
if (VALID_CONS_TARGET(ct)) {
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- /* special exception for curves - depsgraph issues */
- if (ct->tar->type == OB_CURVE) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
+ if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) {
+ unit_m4(ct->matrix);
+ return;
}
-#endif
/* firstly calculate the matrix the normal way, then let the py-function override
* this matrix if it needs to do so
@@ -2070,15 +2077,6 @@ static void pycon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targe
/* only evaluate in python if we're allowed to do so */
if ((G.f & G_SCRIPT_AUTOEXEC) == 0) return;
-/* currently removed, until I this can be re-implemented for multiple targets */
-#if 0
- /* Firstly, run the 'driver' function which has direct access to the objects involved
- * Technically, this is potentially dangerous as users may abuse this and cause dependency-problems,
- * but it also allows certain 'clever' rigging hacks to work.
- */
- BPY_pyconstraint_driver(data, cob, targets);
-#endif
-
/* Now, run the actual 'constraint' function, which should only access the matrices */
BPY_pyconstraint_exec(data, cob, targets);
#endif /* WITH_PYTHON */
@@ -2099,6 +2097,199 @@ static bConstraintTypeInfo CTI_PYTHON = {
pycon_evaluate /* evaluate */
};
+/* ----------- Armature Constraint -------------- */
+
+static void armdef_free(bConstraint *con)
+{
+ bArmatureConstraint *data = con->data;
+
+ /* Target list. */
+ BLI_freelistN(&data->targets);
+}
+
+static void armdef_copy(bConstraint *con, bConstraint *srccon)
+{
+ bArmatureConstraint *pcon = (bArmatureConstraint *)con->data;
+ bArmatureConstraint *opcon = (bArmatureConstraint *)srccon->data;
+
+ BLI_duplicatelist(&pcon->targets, &opcon->targets);
+}
+
+static int armdef_get_tars(bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bArmatureConstraint *data = con->data;
+
+ *list = data->targets;
+
+ return BLI_listbase_count(&data->targets);
+ }
+
+ return 0;
+}
+
+static void armdef_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+ bArmatureConstraint *data = con->data;
+ bConstraintTarget *ct;
+
+ /* Target list. */
+ for (ct = data->targets.first; ct; ct = ct->next) {
+ func(con, (ID **)&ct->tar, false, userdata);
+ }
+}
+
+/* Compute the world space pose matrix of the target bone. */
+static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
+{
+ if (ct != NULL) {
+ if (ct->tar && ct->tar->type == OB_ARMATURE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
+
+ if (pchan != NULL) {
+ mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat);
+ return;
+ }
+ }
+
+ unit_m4(ct->matrix);
+ }
+}
+
+/* Compute and accumulate transformation for a single target bone. */
+static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, const float wco[3], bool force_envelope, float *r_totweight, float r_sum_mat[4][4], DualQuat *r_sum_dq)
+{
+ float mat[4][4], iobmat[4][4], basemat[4][4], co[3];
+ Bone *bone = pchan->bone;
+ float weight = ct->weight;
+
+ /* Our object's location in target pose space. */
+ invert_m4_m4(iobmat, ct->tar->obmat);
+ mul_v3_m4v3(co, iobmat, wco);
+
+ /* Multiply by the envelope weight when appropriate. */
+ if (force_envelope || (bone->flag & BONE_MULT_VG_ENV)) {
+ weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail,
+ bone->rad_head, bone->rad_tail, bone->dist);
+ }
+
+ /* Find the correct bone transform matrix in world space. */
+ if (bone->segments > 1 && bone->segments == pchan->runtime.bbone_segments) {
+ Mat4 *b_bone_mats = pchan->runtime.bbone_deform_mats;
+ float (*iamat)[4] = b_bone_mats[0].mat;
+
+ /* The target is a B-Bone:
+ * FIRST: find the segment (see b_bone_deform in armature.c)
+ * Need to transform co back to bonespace, only need y. */
+ float y = iamat[0][1] * co[0] + iamat[1][1] * co[1] + iamat[2][1] * co[2] + iamat[3][1];
+
+ float segment = bone->length / ((float)bone->segments);
+ int a = (int)(y / segment);
+
+ CLAMP(a, 0, bone->segments - 1);
+
+ /* Convert the selected matrix into object space. */
+ mul_m4_series(mat, ct->tar->obmat, b_bone_mats[a + 1].mat, iobmat);
+ }
+ else {
+ /* Simple bone. This requires DEG_OPCODE_BONE_DONE dependency due to chan_mat. */
+ mul_m4_series(mat, ct->tar->obmat, pchan->chan_mat, iobmat);
+ }
+
+ /* Accumulate the transformation. */
+ *r_totweight += weight;
+
+ if (r_sum_dq != NULL) {
+ DualQuat tmpdq;
+
+ mul_m4_series(basemat, ct->tar->obmat, bone->arm_mat, iobmat);
+
+ mat4_to_dquat(&tmpdq, basemat, mat);
+ add_weighted_dq_dq(r_sum_dq, &tmpdq, weight);
+ }
+ else {
+ mul_m4_fl(mat, weight);
+ add_m4_m4m4(r_sum_mat, r_sum_mat, mat);
+ }
+}
+
+static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bArmatureConstraint *data = con->data;
+
+ float sum_mat[4][4], input_co[3];
+ DualQuat sum_dq;
+ float weight = 0.0f;
+
+ /* Prepare for blending. */
+ zero_m4(sum_mat);
+ memset(&sum_dq, 0, sizeof(sum_dq));
+
+ DualQuat *pdq = (data->flag & CONSTRAINT_ARMATURE_QUATERNION) ? &sum_dq : NULL;
+ bool use_envelopes = (data->flag & CONSTRAINT_ARMATURE_ENVELOPE) != 0;
+
+ if (cob->pchan && cob->pchan->bone && !(data->flag & CONSTRAINT_ARMATURE_CUR_LOCATION)) {
+ /* For constraints on bones, use the rest position to bind b-bone segments
+ * and envelopes, to allow safely changing the bone location as if parented. */
+ copy_v3_v3(input_co, cob->pchan->bone->arm_head);
+ mul_m4_v3(cob->ob->obmat, input_co);
+ }
+ else {
+ copy_v3_v3(input_co, cob->matrix[3]);
+ }
+
+ /* Process all targets. */
+ for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) {
+ if (ct->weight <= 0.0f) {
+ continue;
+ }
+
+ /* Lookup the bone and abort if failed. */
+ if (!VALID_CONS_TARGET(ct) || ct->tar->type != OB_ARMATURE) {
+ return;
+ }
+
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
+
+ if (pchan == NULL || pchan->bone == NULL) {
+ return;
+ }
+
+ armdef_accumulate_bone(ct, pchan, input_co, use_envelopes, &weight, sum_mat, pdq);
+ }
+
+ /* Compute the final transform. */
+ if (weight > 0.0f) {
+ if (pdq != NULL) {
+ normalize_dq(pdq, weight);
+ dquat_to_mat4(sum_mat, pdq);
+ }
+ else {
+ mul_m4_fl(sum_mat, 1.0f / weight);
+ }
+
+ /* Apply the transform to the result matrix. */
+ mul_m4_m4m4(cob->matrix, sum_mat, cob->matrix);
+ }
+}
+
+static bConstraintTypeInfo CTI_ARMATURE = {
+ CONSTRAINT_TYPE_ARMATURE, /* type */
+ sizeof(bArmatureConstraint), /* size */
+ "Armature", /* name */
+ "bArmatureConstraint", /* struct name */
+ armdef_free, /* free data */
+ armdef_id_looper, /* id looper */
+ armdef_copy, /* copy data */
+ NULL, /* new data */
+ armdef_get_tars, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ armdef_get_tarmat, /* get target matrix */
+ armdef_evaluate /* evaluate */
+};
+
/* -------- Action Constraint ----------- */
static void actcon_new_data(void *cdata)
@@ -2146,7 +2337,7 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bActionConstraint *data = con->data;
@@ -2778,9 +2969,24 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
dist /= size[1];
/* data->orglength==0 occurs on first run, and after 'R' button is clicked */
- if (data->orglength == 0)
+ if (data->orglength == 0) {
data->orglength = dist;
+ /* Write the computed length back to the master copy if in COW evaluation. */
+ if (DEG_is_active(cob->depsgraph)) {
+ Object *orig_ob = NULL;
+ bConstraint *orig_con = constraint_find_original(cob->ob, cob->pchan, con, &orig_ob);
+
+ if (orig_con != NULL) {
+ bStretchToConstraint *orig_data = orig_con->data;
+
+ orig_data->orglength = data->orglength;
+
+ DEG_id_tag_update(&orig_ob->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_TRANSFORM);
+ }
+ }
+ }
+
scale[1] = dist / data->orglength;
bulge = powf(data->orglength / dist, data->bulge);
@@ -3041,66 +3247,6 @@ static bConstraintTypeInfo CTI_MINMAX = {
minmax_evaluate /* evaluate */
};
-/* ------- RigidBody Joint ---------- */
-
-static void rbj_new_data(void *cdata)
-{
- bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)cdata;
-
- /* removed code which set target of this constraint */
- data->type = 1;
-}
-
-static void rbj_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
-{
- bRigidBodyJointConstraint *data = con->data;
-
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
- func(con, (ID **)&data->child, false, userdata);
-}
-
-static int rbj_get_tars(bConstraint *con, ListBase *list)
-{
- if (con && list) {
- bRigidBodyJointConstraint *data = con->data;
- bConstraintTarget *ct;
-
- /* standard target-getting macro for single-target constraints without subtargets */
- SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
-
- return 1;
- }
-
- return 0;
-}
-
-static void rbj_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
-{
- if (con && list) {
- bRigidBodyJointConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
-
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
- }
-}
-
-static bConstraintTypeInfo CTI_RIGIDBODYJOINT = {
- CONSTRAINT_TYPE_RIGIDBODYJOINT, /* type */
- sizeof(bRigidBodyJointConstraint), /* size */
- "Rigid Body Joint", /* name */
- "bRigidBodyJointConstraint", /* struct name */
- NULL, /* free data */
- rbj_id_looper, /* id looper */
- NULL, /* copy data */
- rbj_new_data, /* new data */
- rbj_get_tars, /* get constraint targets */
- rbj_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- NULL /* evaluate - this is not solved here... is just an interface for game-engine */
-};
-
/* -------- Clamp To ---------- */
static void clampto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -3137,16 +3283,10 @@ static void clampto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void clampto_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void clampto_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (VALID_CONS_TARGET(ct)) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
- }
-#endif
-
/* technically, this isn't really needed for evaluation, but we don't know what else
* might end up calling this...
*/
@@ -3174,7 +3314,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
BKE_object_minmax(ct->tar, curveMin, curveMax, true);
/* get targetmatrix */
- if (data->tar->curve_cache && data->tar->curve_cache->path && data->tar->curve_cache->path->data) {
+ if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path && data->tar->runtime.curve_cache->path->data) {
float vec[4], dir[3], totmat[4][4];
float curvetime;
short clamp_axis;
@@ -3480,53 +3620,64 @@ static void shrinkwrap_flush_tars(bConstraint *con, ListBase *list, bool no_copy
}
-static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data;
if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) {
+
bool fail = false;
float co[3] = {0.0f, 0.0f, 0.0f};
+ bool track_normal = false;
+ float track_no[3] = {0.0f, 0.0f, 0.0f};
SpaceTransform transform;
- /* TODO(sergey): use proper for_render flag here when known. */
- DerivedMesh *target = object_get_derived_final(ct->tar, false);
+ Mesh *target_eval = ct->tar->runtime.mesh_eval;
- BVHTreeFromMesh treeData = {NULL};
+ copy_m4_m4(ct->matrix, cob->matrix);
- unit_m4(ct->matrix);
+ bool do_track_normal = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0;
+ ShrinkwrapTreeData tree;
- if (target != NULL) {
+ if (BKE_shrinkwrap_init_tree(&tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) {
BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat);
switch (scon->shrinkType) {
case MOD_SHRINKWRAP_NEAREST_SURFACE:
case MOD_SHRINKWRAP_NEAREST_VERTEX:
+ case MOD_SHRINKWRAP_TARGET_PROJECT:
{
BVHTreeNearest nearest;
- float dist;
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
- if (scon->shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX)
- bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_VERTS, 2);
- else
- bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_space_transform_apply(&transform, co);
+
+ BKE_shrinkwrap_find_nearest_surface(&tree, &nearest, co, scon->shrinkType);
- if (treeData.tree == NULL) {
+ if (nearest.index < 0) {
fail = true;
break;
}
- BLI_space_transform_apply(&transform, co);
+ if (scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) {
+ if (do_track_normal) {
+ track_normal = true;
+ BKE_shrinkwrap_compute_smooth_normal(&tree, NULL, nearest.index, nearest.co, nearest.no, track_no);
+ BLI_space_transform_invert_normal(&transform, track_no);
+ }
- BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData);
+ BKE_shrinkwrap_snap_point_to_surface(&tree, NULL, scon->shrinkMode, nearest.index, nearest.co, nearest.no, scon->dist, co, co);
+ }
+ else {
+ const float dist = len_v3v3(co, nearest.co);
- dist = len_v3v3(co, nearest.co);
- if (dist != 0.0f) {
- interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */
+ if (dist != 0.0f) {
+ interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */
+ }
}
+
BLI_space_transform_invert(&transform, co);
break;
}
@@ -3564,24 +3715,37 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
break;
}
- bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 4);
- if (treeData.tree == NULL) {
- fail = true;
- break;
+ char cull_mode = scon->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK;
+
+ BKE_shrinkwrap_project_normal(cull_mode, co, no, 0.0f, &transform, &tree, &hit);
+
+ if (scon->flag & CON_SHRINKWRAP_PROJECT_OPPOSITE) {
+ float inv_no[3];
+ negate_v3_v3(inv_no, no);
+
+ if ((scon->flag & CON_SHRINKWRAP_PROJECT_INVERT_CULL) && (cull_mode != 0)) {
+ cull_mode ^= CON_SHRINKWRAP_PROJECT_CULL_MASK;
+ }
+
+ BKE_shrinkwrap_project_normal(cull_mode, co, inv_no, 0.0f, &transform, &tree, &hit);
}
- if (BKE_shrinkwrap_project_normal(0, co, no, scon->dist, &transform, treeData.tree,
- &hit, treeData.raycast_callback, &treeData) == false)
- {
+ if (hit.index < 0) {
fail = true;
break;
}
- copy_v3_v3(co, hit.co);
+
+ if (do_track_normal) {
+ track_normal = true;
+ BKE_shrinkwrap_compute_smooth_normal(&tree, &transform, hit.index, hit.co, hit.no, track_no);
+ }
+
+ BKE_shrinkwrap_snap_point_to_surface(&tree, &transform, scon->shrinkMode, hit.index, hit.co, hit.no, scon->dist, co, co);
break;
}
}
- free_bvhtree_from_mesh(&treeData);
+ BKE_shrinkwrap_free_tree(&tree);
if (fail == true) {
/* Don't move the point */
@@ -3591,6 +3755,11 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
/* co is in local object coordinates, change it to global and update target position */
mul_m4_v3(cob->matrix, co);
copy_v3_v3(ct->matrix[3], co);
+
+ if (track_normal) {
+ mul_mat3_m4_v3(cob->matrix, track_no);
+ damptrack_do_transform(ct->matrix, track_no, scon->trackAxis);
+ }
}
}
}
@@ -3601,7 +3770,7 @@ static void shrinkwrap_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, Li
/* only evaluate if there is a target */
if (VALID_CONS_TARGET(ct)) {
- copy_v3_v3(cob->matrix[3], ct->matrix[3]);
+ copy_m4_m4(cob->matrix, ct->matrix);
}
}
@@ -3675,7 +3844,22 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- float obvec[3], tarvec[3], obloc[3];
+ float tarvec[3];
+
+ /* find the (unit) direction vector going from the owner to the target */
+ sub_v3_v3v3(tarvec, ct->matrix[3], cob->matrix[3]);
+
+ damptrack_do_transform(cob->matrix, tarvec, data->trackflag);
+ }
+}
+
+static void damptrack_do_transform(float matrix[4][4], const float tarvec_in[3], int track_axis)
+{
+ /* find the (unit) direction vector going from the owner to the target */
+ float tarvec[3];
+
+ if (normalize_v3_v3(tarvec, tarvec_in) != 0.0f) {
+ float obvec[3], obloc[3];
float raxis[3], rangle;
float rmat[3][3], tmat[4][4];
@@ -3684,24 +3868,15 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
* - the normalization step at the end should take care of any unwanted scaling
* left over in the 3x3 matrix we used
*/
- copy_v3_v3(obvec, track_dir_vecs[data->trackflag]);
- mul_mat3_m4_v3(cob->matrix, obvec);
+ copy_v3_v3(obvec, track_dir_vecs[track_axis]);
+ mul_mat3_m4_v3(matrix, obvec);
if (normalize_v3(obvec) == 0.0f) {
/* exceptional case - just use the track vector as appropriate */
- copy_v3_v3(obvec, track_dir_vecs[data->trackflag]);
+ copy_v3_v3(obvec, track_dir_vecs[track_axis]);
}
- /* find the (unit) direction vector going from the owner to the target */
- copy_v3_v3(obloc, cob->matrix[3]);
- sub_v3_v3v3(tarvec, ct->matrix[3], obloc);
-
- if (normalize_v3(tarvec) == 0.0f) {
- /* the target is sitting on the owner, so just make them use the same direction vectors */
- /* FIXME: or would it be better to use the pure direction vector? */
- copy_v3_v3(tarvec, obvec);
- //copy_v3_v3(tarvec, track_dir_vecs[data->trackflag]);
- }
+ copy_v3_v3(obloc, matrix[3]);
/* determine the axis-angle rotation, which represents the smallest possible rotation
* between the two rotation vectors (i.e. the 'damping' referred to in the name)
@@ -3734,8 +3909,8 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
}
rangle = M_PI;
- copy_v3_v3(tmpvec, track_dir_vecs[(data->trackflag + 1) % 6]);
- mul_mat3_m4_v3(cob->matrix, tmpvec);
+ copy_v3_v3(tmpvec, track_dir_vecs[(track_axis + 1) % 6]);
+ mul_mat3_m4_v3(matrix, tmpvec);
cross_v3_v3v3(raxis, obvec, tmpvec);
if (normalize_v3(raxis) == 0.0f) {
@@ -3753,10 +3928,10 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
* we may have destroyed that in the process of multiplying the matrix
*/
unit_m4(tmat);
- mul_m4_m3m4(tmat, rmat, cob->matrix); // m1, m3, m2
+ mul_m4_m3m4(tmat, rmat, matrix); // m1, m3, m2
- copy_m4_m4(cob->matrix, tmat);
- copy_v3_v3(cob->matrix[3], obloc);
+ copy_m4_m4(matrix, tmat);
+ copy_v3_v3(matrix[3], obloc);
}
}
@@ -3839,16 +4014,10 @@ static void splineik_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void splineik_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void splineik_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (VALID_CONS_TARGET(ct)) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
- }
-#endif
-
/* technically, this isn't really needed for evaluation, but we don't know what else
* might end up calling this...
*/
@@ -4016,20 +4185,25 @@ static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bFollowTrackConstraint *data = con->data;
MovieClip *clip = data->clip;
MovieTracking *tracking;
MovieTrackingTrack *track;
MovieTrackingObject *tracking_object;
- Object *camob = data->camera ? data->camera : scene->camera;
- float ctime = BKE_scene_frame_get(scene);
+
+ Object *camob_eval = DEG_get_evaluated_object(
+ depsgraph,
+ data->camera ? data->camera : scene->camera);
+
+ float ctime = DEG_get_ctime(depsgraph);
float framenr;
if (data->flag & FOLLOWTRACK_ACTIVECLIP)
clip = scene->clip;
- if (!clip || !data->track[0] || !camob)
+ if (!clip || !data->track[0] || !camob_eval)
return;
tracking = &clip->tracking;
@@ -4058,7 +4232,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
float imat[4][4];
- copy_m4_m4(mat, camob->obmat);
+ copy_m4_m4(mat, camob_eval->obmat);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat);
invert_m4(imat);
@@ -4067,7 +4241,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
}
else {
- BKE_tracking_get_camera_object_matrix(cob->scene, camob, mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, cob->scene, camob_eval, mat);
mul_m4_m4m4(cob->matrix, obmat, mat);
translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
@@ -4079,7 +4253,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
float len, d;
- BKE_object_where_is_calc_mat4(scene, camob, mat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, camob_eval, mat);
/* camera axis */
vec[0] = 0.0f;
@@ -4147,7 +4321,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
}
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, camob);
+ BKE_camera_params_from_object(&params, camob_eval);
if (params.is_ortho) {
vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx);
@@ -4159,9 +4333,9 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
else
vec[0] *= aspect;
- mul_v3_m4v3(disp, camob->obmat, vec);
+ mul_v3_m4v3(disp, camob_eval->obmat, vec);
- copy_m4_m4(rmat, camob->obmat);
+ copy_m4_m4(rmat, camob_eval->obmat);
zero_v3(rmat[3]);
mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
@@ -4179,10 +4353,10 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
else
vec[0] *= aspect;
- mul_v3_m4v3(disp, camob->obmat, vec);
+ mul_v3_m4v3(disp, camob_eval->obmat, vec);
/* apply camera rotation so Z-axis would be co-linear */
- copy_m4_m4(rmat, camob->obmat);
+ copy_m4_m4(rmat, camob_eval->obmat);
zero_v3(rmat[3]);
mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
@@ -4191,9 +4365,8 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if (data->depth_ob) {
Object *depth_ob = data->depth_ob;
- /* TODO(sergey): use proper for_render flag here when known. */
- DerivedMesh *target = object_get_derived_final(depth_ob, false);
- if (target) {
+ Mesh *target_eval = depth_ob->runtime.mesh_eval;
+ if (target_eval) {
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeRayHit hit;
float ray_start[3], ray_end[3], ray_nor[3], imat[4][4];
@@ -4201,25 +4374,25 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
invert_m4_m4(imat, depth_ob->obmat);
- mul_v3_m4v3(ray_start, imat, camob->obmat[3]);
+ mul_v3_m4v3(ray_start, imat, camob_eval->obmat[3]);
mul_v3_m4v3(ray_end, imat, cob->matrix[3]);
sub_v3_v3v3(ray_nor, ray_end, ray_start);
normalize_v3(ray_nor);
- bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 4);
+ BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4);
hit.dist = BVH_RAYCAST_DIST_MAX;
hit.index = -1;
- result = BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
+ result = BLI_bvhtree_ray_cast(
+ treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
if (result != -1) {
mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co);
}
free_bvhtree_from_mesh(&treeData);
- target->release(target);
}
}
}
@@ -4260,6 +4433,7 @@ static void camerasolver_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bCameraSolverConstraint *data = con->data;
MovieClip *clip = data->clip;
@@ -4271,7 +4445,7 @@ static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
float mat[4][4], obmat[4][4];
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object = BKE_tracking_object_get_camera(tracking);
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = DEG_get_ctime(depsgraph);
float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
@@ -4318,6 +4492,7 @@ static void objectsolver_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bObjectSolverConstraint *data = con->data;
MovieClip *clip = data->clip;
@@ -4337,10 +4512,10 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if (object) {
float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4];
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = DEG_get_ctime(depsgraph);
float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
- BKE_object_where_is_calc_mat4(scene, camob, cammat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, camob, cammat);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
@@ -4392,7 +4567,7 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
return;
}
- const float frame = BKE_scene_frame_get(scene);
+ const float frame = DEG_get_ctime(cob->depsgraph);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
BKE_cachefile_ensure_handle(G.main, cache_file);
@@ -4490,7 +4665,7 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[14] = &CTI_DISTLIMIT; /* Limit Distance Constraint */
constraintsTypeInfo[15] = &CTI_STRETCHTO; /* StretchTo Constaint */
constraintsTypeInfo[16] = &CTI_MINMAX; /* Floor Constraint */
- constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */
+ /* constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; */ /* RigidBody Constraint - Deprecated */
constraintsTypeInfo[18] = &CTI_CLAMPTO; /* ClampTo Constraint */
constraintsTypeInfo[19] = &CTI_TRANSFORM; /* Transformation Constraint */
constraintsTypeInfo[20] = &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */
@@ -4503,6 +4678,7 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
+ constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */
}
/* This function should be used for getting the appropriate type-info when only
@@ -4642,7 +4818,7 @@ static bConstraint *add_new_constraint_internal(const char *name, short type)
/* Set up a generic constraint datablock */
con->type = type;
- con->flag |= CONSTRAINT_EXPAND;
+ con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL;
con->enforce = 1.0f;
/* Determine a basic name, and info */
@@ -4718,6 +4894,11 @@ static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const ch
return con;
}
+bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *UNUSED(ct))
+{
+ return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE);
+}
+
/* ......... */
/* Add new constraint for the given bone */
@@ -4769,6 +4950,43 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool i
id_us_plus(*idpoin);
}
+/** Copies a single constraint's data (\a dst must already be a shallow copy of \a src). */
+static void constraint_copy_data_ex(bConstraint *dst, bConstraint *src, const int flag, const bool do_extern)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src);
+
+ /* make a new copy of the constraint's data */
+ dst->data = MEM_dupallocN(dst->data);
+
+ /* only do specific constraints if required */
+ if (cti) {
+ /* perform custom copying operations if needed */
+ if (cti->copy_data)
+ cti->copy_data(dst, src);
+
+ /* Fix usercounts for all referenced data that need it. */
+ if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
+ }
+
+ /* for proxies we don't want to make extern */
+ if (do_extern) {
+ /* go over used ID-links for this constraint to ensure that they are valid for proxies */
+ if (cti->id_looper)
+ cti->id_looper(dst, con_extern_cb, NULL);
+ }
+ }
+}
+
+/** Allocate and duplicate a single constraint, ouside of any object/pose context. */
+bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern)
+{
+ bConstraint *dst = MEM_dupallocN(src);
+ constraint_copy_data_ex(dst, src, flag, do_extern);
+ dst->next = dst->prev = NULL;
+ return dst;
+}
+
/* duplicate all of the constraints in a constraint stack */
void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
@@ -4778,29 +4996,7 @@ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag,
BLI_duplicatelist(dst, src);
for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- /* make a new copy of the constraint's data */
- con->data = MEM_dupallocN(con->data);
-
- /* only do specific constraints if required */
- if (cti) {
- /* perform custom copying operations if needed */
- if (cti->copy_data)
- cti->copy_data(con, srccon);
-
- /* Fix usercounts for all referenced data that need it. */
- if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- cti->id_looper(con, con_fix_copied_refs_cb, NULL);
- }
-
- /* for proxies we don't want to make extern */
- if (do_extern) {
- /* go over used ID-links for this constraint to ensure that they are valid for proxies */
- if (cti->id_looper)
- cti->id_looper(con, con_extern_cb, NULL);
- }
- }
+ constraint_copy_data_ex(con, srccon, flag, do_extern);
}
}
@@ -4848,6 +5044,102 @@ void BKE_constraints_active_set(ListBase *list, bConstraint *con)
}
}
+static bConstraint *constraint_list_find_from_target(ListBase *constraints, bConstraintTarget *tgt)
+{
+ for (bConstraint *con = constraints->first; con; con = con->next) {
+ ListBase *targets = NULL;
+
+ if (con->type == CONSTRAINT_TYPE_PYTHON) {
+ targets = &((bPythonConstraint *)con->data)->targets;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ARMATURE) {
+ targets = &((bArmatureConstraint *)con->data)->targets;
+ }
+
+ if (targets && BLI_findindex(targets, tgt) != -1) {
+ return con;
+ }
+ }
+
+ return NULL;
+}
+
+/* Finds the constraint that owns the given target within the object. */
+bConstraint *BKE_constraint_find_from_target(Object *ob, bConstraintTarget *tgt, bPoseChannel **r_pchan)
+{
+ if (r_pchan != NULL) {
+ *r_pchan = NULL;
+ }
+
+ bConstraint *result = constraint_list_find_from_target(&ob->constraints, tgt);
+
+ if (result != NULL) {
+ return result;
+ }
+
+ if (ob->pose != NULL) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ result = constraint_list_find_from_target(&pchan->constraints, tgt);
+
+ if (result != NULL) {
+ if (r_pchan != NULL) {
+ *r_pchan = pchan;
+ }
+
+ return result;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Finds the original copy of the constraint based on a COW copy. */
+static bConstraint *constraint_find_original(Object *ob, bPoseChannel *pchan, bConstraint *con, Object **r_orig_ob)
+{
+ Object *orig_ob = (Object *)DEG_get_original_id(&ob->id);
+
+ if (ELEM(orig_ob, NULL, ob)) {
+ return NULL;
+ }
+
+ /* Find which constraint list to use. */
+ ListBase *constraints, *orig_constraints;
+
+ if (pchan != NULL) {
+ bPoseChannel *orig_pchan = pchan->orig_pchan;
+
+ if (orig_pchan == NULL) {
+ return NULL;
+ }
+
+ constraints = &pchan->constraints;
+ orig_constraints = &orig_pchan->constraints;
+ }
+ else {
+ constraints = &ob->constraints;
+ orig_constraints = &orig_ob->constraints;
+ }
+
+ /* Lookup the original constraint by index. */
+ int index = BLI_findindex(constraints, con);
+
+ if (index >= 0) {
+ bConstraint *orig_con = BLI_findlink(orig_constraints, index);
+
+ /* Verify it has correct type and name. */
+ if (orig_con && orig_con->type == con->type && STREQ(orig_con->name, con->name)) {
+ if (r_orig_ob != NULL) {
+ *r_orig_ob = orig_ob;
+ }
+
+ return orig_con;
+ }
+ }
+
+ return NULL;
+}
+
/* -------- Constraints and Proxies ------- */
/* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */
@@ -4897,7 +5189,7 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
* None of the actual calculations of the matrices should be done here! Also, this function is
* not to be used by any new constraints, particularly any that have multiple targets.
*/
-void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
+void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
@@ -4909,6 +5201,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
cob = MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb");
cob->type = ownertype;
cob->scene = scene;
+ cob->depsgraph = depsgraph;
switch (ownertype) {
case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */
{
@@ -4944,11 +5237,11 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
cti->get_constraint_targets(con, &targets);
/* only calculate the target matrix on the first target */
- ct = (bConstraintTarget *)BLI_findlink(&targets, index);
+ ct = BLI_findlink(&targets, index);
if (ct) {
if (cti->get_target_matrix)
- cti->get_target_matrix(con, cob, ct, ctime);
+ cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
copy_m4_m4(mat, ct->matrix);
}
@@ -4964,7 +5257,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
}
/* Get the list of targets required for solving a constraint */
-void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
+void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
@@ -4982,7 +5275,7 @@ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob
*/
if (cti->get_target_matrix) {
for (ct = targets->first; ct; ct = ct->next)
- cti->get_target_matrix(con, cob, ct, ctime);
+ cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
}
else {
for (ct = targets->first; ct; ct = ct->next)
@@ -4999,7 +5292,7 @@ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob
* BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and
* after running this function, to sort out cob
*/
-void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
+void BKE_constraints_solve(struct Depsgraph *depsgraph, ListBase *conlist, bConstraintOb *cob, float ctime)
{
bConstraint *con;
float oldmat[4][4];
@@ -5034,7 +5327,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
/* prepare targets for constraint solving */
- BKE_constraint_targets_for_solving_get(con, cob, &targets, ctime);
+ BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
/* Solve the constraint and put result in cob->matrix */
cti->evaluate_constraint(con, cob, &targets);
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index c9468c7d95c..b3a26087dd0 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -38,6 +39,9 @@
#include "DNA_object_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -47,9 +51,14 @@
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
+#include "BKE_workspace.h"
+
+#include "RE_engine.h"
#include "RNA_access.h"
@@ -66,10 +75,12 @@ struct bContext {
struct {
struct wmWindowManager *manager;
struct wmWindow *window;
+ struct WorkSpace *workspace;
struct bScreen *screen;
struct ScrArea *area;
struct ARegion *region;
struct ARegion *menu;
+ struct wmGizmoGroup *gizmo_group;
struct bContextStore *store;
const char *operator_poll_msg; /* reason for poll failing */
} wm;
@@ -83,13 +94,6 @@ struct bContext {
int py_init; /* true if python is initialized */
void *py_context;
} data;
-
- /* data evaluation */
-#if 0
- struct {
- int render;
- } eval;
-#endif
};
/* context */
@@ -627,6 +631,11 @@ wmWindow *CTX_wm_window(const bContext *C)
return ctx_wm_python_context_get(C, "window", &RNA_Window, C->wm.window);
}
+WorkSpace *CTX_wm_workspace(const bContext *C)
+{
+ return ctx_wm_python_context_get(C, "workspace", &RNA_WorkSpace, C->wm.workspace);
+}
+
bScreen *CTX_wm_screen(const bContext *C)
{
return ctx_wm_python_context_get(C, "screen", &RNA_Screen, C->wm.screen);
@@ -659,6 +668,16 @@ struct ARegion *CTX_wm_menu(const bContext *C)
return C->wm.menu;
}
+struct wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C)
+{
+ return C->wm.gizmo_group;
+}
+
+struct wmMsgBus *CTX_wm_message_bus(const bContext *C)
+{
+ return C->wm.manager ? C->wm.manager->message_bus : NULL;
+}
+
struct ReportList *CTX_wm_reports(const bContext *C)
{
if (C->wm.manager)
@@ -750,14 +769,6 @@ struct SpaceNla *CTX_wm_space_nla(const bContext *C)
return NULL;
}
-struct SpaceTime *CTX_wm_space_time(const bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TIME)
- return sa->spacedata.first;
- return NULL;
-}
-
struct SpaceNode *CTX_wm_space_node(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
@@ -766,14 +777,6 @@ struct SpaceNode *CTX_wm_space_node(const bContext *C)
return NULL;
}
-struct SpaceLogic *CTX_wm_space_logic(const bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_LOGIC)
- return sa->spacedata.first;
- return NULL;
-}
-
struct SpaceIpo *CTX_wm_space_graph(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
@@ -814,6 +817,14 @@ struct SpaceClip *CTX_wm_space_clip(const bContext *C)
return NULL;
}
+struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_TOPBAR)
+ return sa->spacedata.first;
+ return NULL;
+}
+
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager = wm;
@@ -826,9 +837,11 @@ void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
void CTX_wm_window_set(bContext *C, wmWindow *win)
{
C->wm.window = win;
- C->wm.screen = (win) ? win->screen : NULL;
- if (C->wm.screen)
- C->data.scene = C->wm.screen->scene;
+ if (win) {
+ C->data.scene = win->scene;
+ }
+ C->wm.workspace = (win) ? BKE_workspace_active_get(win->workspace_hook) : NULL;
+ C->wm.screen = (win) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL;
C->wm.area = NULL;
C->wm.region = NULL;
}
@@ -836,8 +849,6 @@ void CTX_wm_window_set(bContext *C, wmWindow *win)
void CTX_wm_screen_set(bContext *C, bScreen *screen)
{
C->wm.screen = screen;
- if (C->wm.screen)
- C->data.scene = C->wm.screen->scene;
C->wm.area = NULL;
C->wm.region = NULL;
}
@@ -858,6 +869,11 @@ void CTX_wm_menu_set(bContext *C, ARegion *menu)
C->wm.menu = menu;
}
+void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup)
+{
+ C->wm.gizmo_group = gzgroup;
+}
+
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
{
C->wm.operator_poll_msg = msg;
@@ -896,10 +912,74 @@ Scene *CTX_data_scene(const bContext *C)
return C->data.scene;
}
-int CTX_data_mode_enum(const bContext *C)
+ViewLayer *CTX_data_view_layer(const bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer;
+
+ if (ctx_data_pointer_verify(C, "view_layer", (void *)&view_layer)) {
+ return view_layer;
+ }
+
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ if (win) {
+ view_layer = BKE_view_layer_find(scene, win->view_layer_name);
+ if (view_layer) {
+ return view_layer;
+ }
+ }
+
+ return BKE_view_layer_default_view(scene);
+}
+RenderEngineType *CTX_data_engine_type(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ return RE_engines_find(scene->r.engine);
+}
+
+/**
+ * This is tricky. Sometimes the user overrides the render_layer
+ * but not the scene_collection. In this case what to do?
+ *
+ * If the scene_collection is linked to the ViewLayer we use it.
+ * Otherwise we fallback to the active one of the ViewLayer.
+ */
+LayerCollection *CTX_data_layer_collection(const bContext *C)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *layer_collection;
+
+ if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) {
+ if (BKE_view_layer_has_collection(view_layer, layer_collection->collection)) {
+ return layer_collection;
+ }
+ }
+
+ /* fallback */
+ return BKE_layer_collection_get_active(view_layer);
+}
+
+Collection *CTX_data_collection(const bContext *C)
+{
+ Collection *collection;
+ if (ctx_data_pointer_verify(C, "collection", (void *)&collection)) {
+ return collection;
+ }
+
+ LayerCollection *layer_collection = CTX_data_layer_collection(C);
+ if (layer_collection) {
+ return layer_collection->collection;
+ }
+
+ /* fallback */
+ Scene *scene = CTX_data_scene(C);
+ return BKE_collection_master(scene);
+}
+
+int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectMode object_mode)
+{
+ // Object *obedit = CTX_data_edit_object(C);
if (obedit) {
switch (obedit->type) {
case OB_MESH:
@@ -919,21 +999,30 @@ int CTX_data_mode_enum(const bContext *C)
}
}
else {
- Object *ob = CTX_data_active_object(C);
-
+ // Object *ob = CTX_data_active_object(C);
if (ob) {
- if (ob->mode & OB_MODE_POSE) return CTX_MODE_POSE;
- else if (ob->mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT;
- else if (ob->mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT;
- else if (ob->mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
- else if (ob->mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
- else if (ob->mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ if (object_mode & OB_MODE_POSE) return CTX_MODE_POSE;
+ else if (object_mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT;
+ else if (object_mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT;
+ else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
+ else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
+ else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ else if (object_mode & OB_MODE_GPENCIL_PAINT) return CTX_MODE_GPENCIL_PAINT;
+ else if (object_mode & OB_MODE_GPENCIL_EDIT) return CTX_MODE_GPENCIL_EDIT;
+ else if (object_mode & OB_MODE_GPENCIL_SCULPT) return CTX_MODE_GPENCIL_SCULPT;
+ else if (object_mode & OB_MODE_GPENCIL_WEIGHT) return CTX_MODE_GPENCIL_WEIGHT;
}
}
return CTX_MODE_OBJECT;
}
+int CTX_data_mode_enum(const bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Object *obact = obedit ? NULL : CTX_data_active_object(C);
+ return CTX_data_mode_enum_ex(obedit, obact, obact ? obact->mode : OB_MODE_OBJECT);
+}
/* would prefer if we can use the enum version below over this one - Campbell */
/* must be aligned with above enum */
@@ -952,8 +1041,13 @@ static const char *data_mode_strings[] = {
"imagepaint",
"particlemode",
"objectmode",
+ "greasepencil_paint",
+ "greasepencil_edit",
+ "greasepencil_sculpt",
+ "greasepencil_weight",
NULL
};
+BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode")
const char *CTX_data_mode_string(const bContext *C)
{
return data_mode_strings[CTX_data_mode_enum(C)];
@@ -1104,6 +1198,11 @@ int CTX_data_selected_pose_bones(const bContext *C, ListBase *list)
return ctx_data_collection_get(C, "selected_pose_bones", list);
}
+int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list)
+{
+ return ctx_data_collection_get(C, "selected_pose_bones_from_active_object", list);
+}
+
int CTX_data_visible_pose_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "visible_pose_bones", list);
@@ -1119,17 +1218,7 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
return ctx_data_pointer_get(C, "active_gpencil_layer");
}
-bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C)
-{
- return ctx_data_pointer_get(C, "active_gpencil_palette");
-}
-
-bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C)
-{
- return ctx_data_pointer_get(C, "active_gpencil_palettecolor");
-}
-
-bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C)
+Brush *CTX_data_active_gpencil_brush(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_brush");
}
@@ -1153,3 +1242,17 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
}
+
+Depsgraph *CTX_data_depsgraph(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return BKE_scene_get_depsgraph(scene, view_layer, true);
+}
+
+Depsgraph *CTX_data_depsgraph_on_load(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return BKE_scene_get_depsgraph(scene, view_layer, false);
+}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 56df8e51eba..354cc4926f1 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -48,6 +48,7 @@
#include "BKE_multires.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
+#include "BKE_library.h"
BLI_INLINE void tan_calc_quat_v3(
float r_quat[4],
@@ -99,27 +100,26 @@ static int modifiers_disable_subsurf_temporary(Object *ob)
}
/* disable subsurf temporal, get mapped cos, and enable it */
-float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3]
+float (*BKE_crazyspace_get_mapped_editverts(
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit))[3]
{
Mesh *me = obedit->data;
- DerivedMesh *dm;
+ Mesh *me_eval;
float (*vertexcos)[3];
int nverts = me->edit_btmesh->bm->totvert;
/* disable subsurf temporal, get mapped cos, and enable it */
if (modifiers_disable_subsurf_temporary(obedit)) {
/* need to make new derivemesh */
- makeDerivedMesh(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, false);
+ makeDerivedMesh(depsgraph, scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, false);
}
/* now get the cage */
vertexcos = MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map");
- dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
+ me_eval = editbmesh_get_eval_cage(depsgraph, scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
- mesh_get_mapped_verts_coords(dm, vertexcos, nverts);
-
- dm->release(dm);
+ mesh_get_mapped_verts_coords(me_eval, vertexcos, nverts);
/* set back the flag, no new cage needs to be built, transform does it */
modifiers_disable_subsurf_temporary(obedit);
@@ -250,19 +250,21 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, float (*origcos)[3], float (*mapped
/** returns an array of deform matrices for crazyspace correction, and the
* number of modifiers left */
-int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, BMEditMesh *em,
- float (**deformmats)[3][3], float (**deformcos)[3])
+int BKE_crazyspace_get_first_deform_matrices_editbmesh(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em,
+ float (**deformmats)[3][3], float (**deformcos)[3])
{
ModifierData *md;
- DerivedMesh *dm;
+ Mesh *me;
int i, a, numleft = 0, numVerts = 0;
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
VirtualModifierData virtualModifierData;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
modifiers_clearErrors(ob);
- dm = NULL;
+ me = NULL;
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* compute the deformation matrices and coordinates for the first
@@ -271,7 +273,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
for (i = 0; md && i <= cageIndex; i++, md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!editbmesh_modifier_is_enabled(scene, md, dm))
+ if (!editbmesh_modifier_is_enabled(scene, md, me != NULL))
continue;
if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
@@ -282,27 +284,26 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
data_mask = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
- dm = getEditDerivedBMesh(em, ob, data_mask, NULL);
+ me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, data_mask, NULL);
deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
for (a = 0; a < numVerts; a++)
unit_m3(defmats[a]);
}
-
- mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats,
- numVerts);
+ mti->deformMatricesEM(md, &mectx, em, me, deformedVerts, defmats, numVerts);
}
else
break;
}
for (; md && i <= cageIndex; md = md->next, i++)
- if (editbmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md))
+ if (editbmesh_modifier_is_enabled(scene, md, me != NULL) && modifier_isCorrectableDeformed(md))
numleft++;
- if (dm)
- dm->release(dm);
+ if (me) {
+ BKE_id_free(NULL, me);
+ }
*deformmats = defmats;
*deformcos = deformedVerts;
@@ -310,16 +311,19 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
return numleft;
}
-int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+int BKE_sculpt_get_first_deform_matrices(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
{
ModifierData *md;
- DerivedMesh *dm;
+ Mesh *me_eval;
int a, numVerts = 0;
float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
int numleft = 0;
VirtualModifierData virtualModifierData;
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
if (has_multires) {
*deformmats = NULL;
@@ -327,7 +331,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
return numleft;
}
- dm = NULL;
+ me_eval = NULL;
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
for (; md; md = md->next) {
@@ -337,8 +341,8 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
if (mti->type == eModifierTypeType_OnlyDeform) {
if (!defmats) {
- Mesh *me = (Mesh *)ob->data;
- dm = mesh_create_derived(me, NULL);
+ Mesh *me = ob->data;
+ me_eval = BKE_mesh_copy_for_eval(me, true);
deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats");
@@ -346,7 +350,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
unit_m3(defmats[a]);
}
- if (mti->deformMatrices) mti->deformMatrices(md, ob, dm, deformedVerts, defmats, numVerts);
+ if (mti->deformMatrices) {
+ mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts);
+ }
else break;
}
}
@@ -360,8 +366,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
numleft++;
}
- if (dm)
- dm->release(dm);
+ if (me_eval) {
+ BKE_id_free(NULL, me_eval);
+ }
*deformmats = defmats;
*deformcos = deformedVerts;
@@ -369,9 +376,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
return numleft;
}
-void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
{
- int totleft = BKE_sculpt_get_first_deform_matrices(scene, ob, deformmats, deformcos);
+ int totleft = BKE_sculpt_get_first_deform_matrices(depsgraph, scene, ob, deformmats, deformcos);
if (totleft) {
/* there are deformation modifier which doesn't support deformation matrices
@@ -383,6 +390,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
int i, deformed = 0;
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
Mesh *me = (Mesh *)ob->data;
for (; md; md = md->next) {
@@ -396,7 +404,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
if (mti->deformMatrices && !deformed)
continue;
- mti->deformVerts(md, ob, NULL, deformedVerts, me->totvert, 0);
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, me->totvert);
deformed = 1;
}
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index b395df49061..a4f348578f7 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -53,7 +53,6 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -129,6 +128,8 @@ void BKE_curve_free(Curve *cu)
{
BKE_animdata_free((ID *)cu, false);
+ BKE_curve_batch_cache_free(cu);
+
BKE_nurbList_free(&cu->nurb);
BKE_curve_editfont_free(cu);
@@ -209,8 +210,9 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
cu_dst->tb = MEM_dupallocN(cu_src->tb);
cu_dst->bb = MEM_dupallocN(cu_src->bb);
+ cu_dst->batch_cache = NULL;
- if (cu_src->key) {
+ if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag, false);
}
@@ -221,7 +223,7 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
Curve *BKE_curve_copy(Main *bmain, const Curve *cu)
{
Curve *cu_copy;
- BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, 0, false);
+ BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, LIB_ID_COPY_SHAPEKEY, false);
return cu_copy;
}
@@ -323,16 +325,22 @@ void BKE_curve_boundbox_calc(Curve *cu, float r_loc[3], float r_size[3])
BoundBox *BKE_curve_boundbox_get(Object *ob)
{
- Curve *cu = ob->data;
+ /* This is Object-level data access, DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
+ if (ob->bb == NULL || ob->bb->flag & BOUNDBOX_DIRTY) {
+ Curve *cu = ob->data;
+ float min[3], max[3];
- if (ob->bb)
- return ob->bb;
+ INIT_MINMAX(min, max);
+ BKE_curve_minmax(cu, true, min, max);
- if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_curve_texspace_calc(cu);
+ if (ob->bb == NULL) {
+ ob->bb = MEM_mallocN(sizeof(*ob->bb), __func__);
+ }
+ BKE_boundbox_init_from_minmax(ob->bb, min, max);
+ ob->bb->flag &= ~BOUNDBOX_DIRTY;
}
- return cu->bb;
+ return ob->bb;
}
void BKE_curve_texspace_calc(Curve *cu)
@@ -355,7 +363,7 @@ void BKE_curve_texspace_calc(Curve *cu)
}
}
-void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3])
+BoundBox *BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3])
{
if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
BKE_curve_texspace_calc(cu);
@@ -364,6 +372,8 @@ void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_s
if (r_loc) copy_v3_v3(r_loc, cu->loc);
if (r_rot) copy_v3_v3(r_rot, cu->rot);
if (r_size) copy_v3_v3(r_size, cu->size);
+
+ return cu->bb;
}
bool BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3])
@@ -1725,7 +1735,7 @@ float *BKE_curve_surf_make_orco(Object *ob)
/* NOTE: This routine is tied to the order of vertex
* built by displist and as passed to the renderer.
*/
-float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
+float *BKE_curve_make_orco(Depsgraph *depsgraph, Scene *scene, Object *ob, int *r_numVerts)
{
Curve *cu = ob->data;
DispList *dl;
@@ -1733,7 +1743,7 @@ float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
float *fp, *coord_array;
ListBase disp = {NULL, NULL};
- BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
+ BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
numVerts = 0;
for (dl = disp.first; dl; dl = dl->next) {
@@ -1824,8 +1834,9 @@ float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
/* ***************** BEVEL ****************** */
-void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
- const bool for_render, const bool use_render_resolution)
+void BKE_curve_bevel_make(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *disp,
+ const bool for_render, const bool use_render_resolution)
{
DispList *dl, *dlnew;
Curve *bevcu, *cu;
@@ -1849,14 +1860,14 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
facy = cu->bevobj->size[1];
if (for_render) {
- BKE_displist_make_curveTypes_forRender(scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
+ BKE_displist_make_curveTypes_forRender(depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
dl = bevdisp.first;
}
- else if (cu->bevobj->curve_cache) {
- dl = cu->bevobj->curve_cache->disp.first;
+ else if (cu->bevobj->runtime.curve_cache) {
+ dl = cu->bevobj->runtime.curve_cache->disp.first;
}
else {
- BLI_assert(cu->bevobj->curve_cache != NULL);
+ BLI_assert(cu->bevobj->runtime.curve_cache != NULL);
dl = NULL;
}
@@ -2769,14 +2780,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
- bev = &ob->curve_cache->bev;
+ bev = &ob->runtime.curve_cache->bev;
/* do we need to calculate the radius for each point? */
/* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */
/* STEP 1: MAKE POLYS */
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
nu = nurbs->first;
if (cu->editnurb && ob->type != OB_FONT) {
is_editmode = 1;
@@ -3407,44 +3418,16 @@ static void calchandleNurb_intern(
}
if (leftviolate || rightviolate) { /* align left handle */
BLI_assert(is_fcurve);
-#if 0
- if (is_fcurve)
-#endif
- {
- /* simple 2d calculation */
- float h1_x = p2_h1[0] - p2[0];
- float h2_x = p2[0] - p2_h2[0];
-
- if (leftviolate) {
- p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x;
- }
- else {
- p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x;
- }
+ /* simple 2d calculation */
+ float h1_x = p2_h1[0] - p2[0];
+ float h2_x = p2[0] - p2_h2[0];
+
+ if (leftviolate) {
+ p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x;
}
-#if 0
else {
- float h1[3], h2[3];
- float dot;
-
- sub_v3_v3v3(h1, p2_h1, p2);
- sub_v3_v3v3(h2, p2, p2_h2);
-
- len_a = normalize_v3(h1);
- len_b = normalize_v3(h2);
-
- dot = dot_v3v3(h1, h2);
-
- if (leftviolate) {
- mul_v3_fl(h1, dot * len_b);
- sub_v3_v3v3(p2_h2, p2, h1);
- }
- else {
- mul_v3_fl(h2, dot * len_a);
- add_v3_v3v3(p2_h1, p2, h2);
- }
+ p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x;
}
-#endif
}
}
}
@@ -4654,18 +4637,18 @@ float (*BKE_curve_nurbs_keyVertexCos_get(ListBase *lb, float *key))[3]
BezTriple *bezt = nu->bezt;
for (i = 0; i < nu->pntsu; i++, bezt++) {
- copy_v3_v3(co, key); co += 3; key += 3;
- copy_v3_v3(co, key); co += 3; key += 3;
- copy_v3_v3(co, key); co += 3; key += 3;
- key += 3; /* skip tilt */
+ copy_v3_v3(co, &key[0]); co += 3;
+ copy_v3_v3(co, &key[3]); co += 3;
+ copy_v3_v3(co, &key[6]); co += 3;
+ key += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
BPoint *bp = nu->bp;
for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
- copy_v3_v3(co, key); co += 3; key += 3;
- key++; /* skip tilt */
+ copy_v3_v3(co, key); co += 3;
+ key += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -4683,18 +4666,18 @@ void BKE_curve_nurbs_keyVertexTilts_apply(ListBase *lb, float *key)
BezTriple *bezt = nu->bezt;
for (i = 0; i < nu->pntsu; i++, bezt++) {
- key += 3 * 3;
- bezt->alfa = *key;
- key += 3;
+ bezt->alfa = key[9];
+ bezt->radius = key[10];
+ key += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
BPoint *bp = nu->bp;
for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
- key += 3;
- bp->alfa = *key;
- key++;
+ bp->alfa = key[3];
+ bp->radius = key[4];
+ key += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -4864,11 +4847,6 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles)
nu->orderv = 1;
nu->type = type;
-#if 0 /* UNUSED */
- if (nu->flagu & CU_NURB_CYCLIC) c = nu->orderu - 1;
- else c = 0;
-#endif
-
if (type == CU_NURBS) {
nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
nu->flagu |= CU_NURB_BEZIER;
@@ -5010,12 +4988,6 @@ bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
vert = &nu->bp[cu->actvert];
}
}
- /* get functions should never set! */
-#if 0
- else {
- cu->actnu = cu->actvert = CU_ACT_NONE;
- }
-#endif
}
*r_nu = nu;
@@ -5164,8 +5136,29 @@ void BKE_curve_transform_ex(
KeyBlock *kb;
for (kb = cu->key->block.first; kb; kb = kb->next) {
float *fp = kb->data;
- for (i = kb->totelem; i--; fp += 3) {
- mul_m4_v3(mat, fp);
+ int n = kb->totelem;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
+ mul_m4_v3(mat, &fp[0]);
+ mul_m4_v3(mat, &fp[3]);
+ mul_m4_v3(mat, &fp[6]);
+ if (do_props) {
+ fp[10] *= unit_scale; /* radius */
+ }
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
+ mul_m4_v3(mat, fp);
+ if (do_props) {
+ fp[4] *= unit_scale; /* radius */
+ }
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
}
}
}
@@ -5209,8 +5202,23 @@ void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys)
KeyBlock *kb;
for (kb = cu->key->block.first; kb; kb = kb->next) {
float *fp = kb->data;
- for (i = kb->totelem; i--; fp += 3) {
- add_v3_v3(fp, offset);
+ int n = kb->totelem;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
+ add_v3_v3(&fp[0], offset);
+ add_v3_v3(&fp[3], offset);
+ add_v3_v3(&fp[6], offset);
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
+ add_v3_v3(fp, offset);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
}
}
}
@@ -5288,7 +5296,7 @@ bool BKE_curve_material_index_validate(Curve *cu)
}
if (!is_valid) {
- DAG_id_tag_update(&cu->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&cu->id, OB_RECALC_DATA);
return true;
}
else {
@@ -5355,11 +5363,28 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t
/* **** Depsgraph evaluation **** */
-void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_curve_eval_geometry(Depsgraph *depsgraph,
Curve *curve)
{
- DEG_debug_print_eval(__func__, curve->id.name, curve);
+ DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve);
if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
BKE_curve_texspace_calc(curve);
}
}
+
+/* Draw Engine */
+void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = NULL;
+void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
+
+void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode)
+{
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_dirty_tag_cb(cu, mode);
+ }
+}
+void BKE_curve_batch_cache_free(Curve *cu)
+{
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_free_cb(cu);
+ }
+}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 8fa117dfce1..e841832f51c 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -53,6 +53,7 @@
#include "BKE_customdata.h"
#include "BKE_customdata_file.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
@@ -390,37 +391,19 @@ static void layerSwap_tface(void *data, const int *corner_indices)
{
MTFace *tf = data;
float uv[4][2];
- static const short pin_flags[4] = { TF_PIN1, TF_PIN2, TF_PIN3, TF_PIN4 };
- static const char sel_flags[4] = { TF_SEL1, TF_SEL2, TF_SEL3, TF_SEL4 };
- short unwrap = tf->unwrap & ~(TF_PIN1 | TF_PIN2 | TF_PIN3 | TF_PIN4);
- char flag = tf->flag & ~(TF_SEL1 | TF_SEL2 | TF_SEL3 | TF_SEL4);
int j;
for (j = 0; j < 4; ++j) {
const int source_index = corner_indices[j];
-
copy_v2_v2(uv[j], tf->uv[source_index]);
-
- /* swap pinning flags around */
- if (tf->unwrap & pin_flags[source_index]) {
- unwrap |= pin_flags[j];
- }
-
- /* swap selection flags around */
- if (tf->flag & sel_flags[source_index]) {
- flag |= sel_flags[j];
- }
}
memcpy(tf->uv, uv, sizeof(tf->uv));
- tf->unwrap = unwrap;
- tf->flag = flag;
}
static void layerDefault_tface(void *data, int count)
{
- static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, NULL,
- 0, 0, TF_DYNAMIC | TF_CONVERTED, 0, 0};
+ static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
MTFace *tf = (MTFace *)data;
int i;
@@ -489,11 +472,7 @@ static void layerInterp_origspace_face(
}
}
- /* delay writing to the destination incase dest is in sources */
-
-#if 0 /* no need, this ONLY contains UV's */
- *osf = *(OrigSpaceFace *)(*sources);
-#endif
+ /* delay writing to the destination in case dest is in sources */
memcpy(osf->uv, uv, sizeof(osf->uv));
}
@@ -1190,6 +1169,15 @@ static void layerSwap_flnor(void *data, const int *corner_indices)
memcpy(flnors, nors, sizeof(nors));
}
+static void layerDefault_fmap(void *data, int count)
+{
+ int *fmap_num = (int *)data;
+ int i;
+ for (i = 0; i < count; i++) {
+ *fmap_num = -1;
+ }
+}
+
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -1215,8 +1203,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 3 floats per normal vector */
{sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal},
- /* 9: CD_POLYINDEX */ /* DEPRECATED */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 9: CD_FACEMAP */
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
/* 10: CD_PROP_FLT */
{sizeof(MFloatProperty), "MFloatProperty", 1, N_("Float"), layerCopy_propFloat, NULL, NULL, NULL},
/* 11: CD_PROP_INT */
@@ -1228,10 +1216,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
/* 14: CD_ORCO */
{sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 15: CD_MTEXPOLY */
+ /* 15: CD_MTEXPOLY */ /* DEPRECATED */
/* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */
- {sizeof(MTexPoly), "MTexPoly", 1, N_("UVMap") /* "Face Texture" */, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface},
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 16: CD_MLOOPUV */
{sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), NULL, NULL, layerInterp_mloopuv, NULL, NULL,
layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv,
@@ -1310,7 +1297,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace",
- /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags",
+ /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFaceMap",
/* 10-14 */ "CDMFloatProperty", "CDMIntProperty", "CDMStringProperty", "CDOrigSpace", "CDOrco",
/* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
/* 20-24 */ "CDPreviewMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDMRecast",
@@ -1325,41 +1312,41 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
const CustomDataMask CD_MASK_BAREMESH =
- CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT;
+ CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE |
CD_MASK_MDEFORMVERT |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP |
- CD_MASK_MTEXPOLY | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
+ CD_MASK_RECAST | CD_MASK_PAINT_MASK |
CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MDEFORMVERT | CD_MASK_MLOOPUV |
- CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX |
+ CD_MASK_MLOOPCOL | CD_MASK_SHAPE_KEYINDEX |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
CD_MASK_MDISPS | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MDEFORMVERT |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT |
CD_MASK_PREVIEW_MCOL | CD_MASK_SHAPEKEY | CD_MASK_RECAST |
CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_BMESH =
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS |
CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
/**
* cover values copied by #BKE_mesh_loops_to_tessdata
*/
const CustomDataMask CD_MASK_FACECORNERS =
- CD_MASK_MTFACE | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
+ CD_MASK_MTFACE | CD_MASK_MLOOPUV |
CD_MASK_MCOL | CD_MASK_MLOOPCOL |
CD_MASK_PREVIEW_MCOL | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP |
@@ -1368,7 +1355,7 @@ const CustomDataMask CD_MASK_FACECORNERS =
const CustomDataMask CD_MASK_EVERYTHING =
CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT |
- CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
+ CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_TANGENT | CD_MASK_MDISPS | CD_MASK_PREVIEW_MCOL | CD_MASK_CLOTH_ORCO | CD_MASK_RECAST |
/* BMESH ONLY START */
CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_SHAPE_KEYINDEX | CD_MASK_SHAPEKEY | CD_MASK_BWEIGHT | CD_MASK_CREASE |
@@ -1376,7 +1363,7 @@ const CustomDataMask CD_MASK_EVERYTHING =
/* BMESH ONLY END */
CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN |
CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
static const LayerTypeInfo *layerType_getInfo(int type)
{
@@ -1407,8 +1394,9 @@ void customData_mask_layers__print(CustomDataMask mask)
/********************* CustomData functions *********************/
static void customData_update_offsets(CustomData *data);
-static CustomDataLayer *customData_add_layer__internal(CustomData *data, int type, int alloctype, void *layerdata,
- int totelem, const char *name);
+static CustomDataLayer *customData_add_layer__internal(
+ CustomData *data, int type, eCDAllocType alloctype, void *layerdata,
+ int totelem, const char *name);
void CustomData_update_typemap(CustomData *data)
{
@@ -1437,8 +1425,9 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
-bool CustomData_merge(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem)
+bool CustomData_merge(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem)
{
/*const LayerTypeInfo *typeInfo;*/
CustomDataLayer *layer, *newlayer;
@@ -1520,8 +1509,9 @@ void CustomData_realloc(CustomData *data, int totelem)
}
}
-void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem)
+void CustomData_copy(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem)
{
CustomData_reset(dest);
@@ -1820,8 +1810,9 @@ static int customData_resize(CustomData *data, int amount)
return 1;
}
-static CustomDataLayer *customData_add_layer__internal(CustomData *data, int type, int alloctype, void *layerdata,
- int totelem, const char *name)
+static CustomDataLayer *customData_add_layer__internal(
+ CustomData *data, int type, eCDAllocType alloctype, void *layerdata,
+ int totelem, const char *name)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
int flag = 0, index = data->totlayer;
@@ -1883,7 +1874,14 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
data->layers[index].flag = flag;
data->layers[index].data = newlayerdata;
- if (name || (name = DATA_(typeInfo->defaultname))) {
+ /* Set default name if none exists. Note we only call DATA_() once
+ * we know there is a default name, to avoid overhead of locale lookups
+ * in the depsgraph. */
+ if (!name && typeInfo->defaultname) {
+ name = DATA_(typeInfo->defaultname);
+ }
+
+ if (name) {
BLI_strncpy(data->layers[index].name, name, sizeof(data->layers[index].name));
CustomData_set_layer_unique_name(data, index);
}
@@ -1908,8 +1906,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
return &data->layers[index];
}
-void *CustomData_add_layer(CustomData *data, int type, int alloctype,
- void *layerdata, int totelem)
+void *CustomData_add_layer(
+ CustomData *data, int type, eCDAllocType alloctype,
+ void *layerdata, int totelem)
{
CustomDataLayer *layer;
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -1925,8 +1924,9 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
}
/*same as above but accepts a name*/
-void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
- void *layerdata, int totelem, const char *name)
+void *CustomData_add_layer_named(
+ CustomData *data, int type, eCDAllocType alloctype,
+ void *layerdata, int totelem, const char *name)
{
CustomDataLayer *layer;
@@ -2243,6 +2243,27 @@ void CustomData_copy_data(const CustomData *source, CustomData *dest,
}
}
+void CustomData_copy_layer_type_data(const CustomData *source,
+ CustomData *destination,
+ int type,
+ int source_index, int destination_index,
+ int count)
+{
+ const int source_layer_index = CustomData_get_layer_index(source, type);
+ if (source_layer_index == -1) {
+ return;
+ }
+ const int destinaiton_layer_index =
+ CustomData_get_layer_index(destination, type);
+ if (destinaiton_layer_index == -1) {
+ return;
+ }
+ CustomData_copy_data_layer(source, destination,
+ source_layer_index, destinaiton_layer_index,
+ source_index, destination_index,
+ count);
+}
+
void CustomData_free_elem(CustomData *data, int index, int count)
{
int i;
@@ -2501,13 +2522,10 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou
/* BMesh functions */
/* needed to convert to/from different face reps */
-void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata,
- int totloop, int totpoly)
+void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
{
- int i;
- for (i = 0; i < fdata->totlayer; i++) {
+ for (int i = 0; i < fdata->totlayer; i++) {
if (fdata->layers[i].type == CD_MTFACE) {
- CustomData_add_layer_named(pdata, CD_MTEXPOLY, CD_CALLOC, NULL, totpoly, fdata->layers[i].name);
CustomData_add_layer_named(ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MCOL) {
@@ -2522,19 +2540,18 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *l
}
}
-void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total)
+void CustomData_from_bmeshpoly(
+ CustomData *fdata, CustomData *ldata, int total)
{
int i;
/* avoid accumulating extra layers */
- BLI_assert(!CustomData_from_bmeshpoly_test(fdata, pdata, ldata, false));
+ BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false));
- for (i = 0; i < pdata->totlayer; i++) {
- if (pdata->layers[i].type == CD_MTEXPOLY) {
- CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, pdata->layers[i].name);
- }
- }
for (i = 0; i < ldata->totlayer; i++) {
+ if (ldata->layers[i].type == CD_MLOOPUV) {
+ CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
if (ldata->layers[i].type == CD_MLOOPCOL) {
CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
}
@@ -2552,7 +2569,7 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData
}
}
- CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
+ CustomData_bmesh_update_active_layers(fdata, ldata);
}
#ifndef NDEBUG
@@ -2562,13 +2579,13 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData
* \param fallback: Use when there are no layers to handle,
* since callers may expect success or failure.
*/
-bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback)
+bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback)
{
int a_num = 0, b_num = 0;
#define LAYER_CMP(l_a, t_a, l_b, t_b) \
((a_num += CustomData_number_of_layers(l_a, t_a)) == (b_num += CustomData_number_of_layers(l_b, t_b)))
- if (!LAYER_CMP(pdata, CD_MTEXPOLY, fdata, CD_MTFACE))
+ if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE))
return false;
if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL))
return false;
@@ -2590,25 +2607,21 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom
#endif
-void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
- if (CustomData_has_layer(pdata, CD_MTEXPOLY)) {
- act = CustomData_get_active_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
+ if (CustomData_has_layer(ldata, CD_MLOOPUV)) {
+ act = CustomData_get_active_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_active(fdata, CD_MTFACE, act);
- act = CustomData_get_render_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_render_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_render(fdata, CD_MTFACE, act);
- act = CustomData_get_clone_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_clone_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_clone(fdata, CD_MTFACE, act);
- act = CustomData_get_stencil_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_stencil_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_stencil(fdata, CD_MTFACE, act);
}
@@ -2632,25 +2645,21 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata,
* used by do_versions in readfile.c when creating pdata and ldata for pre-bmesh
* meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files
*/
-void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
if (CustomData_has_layer(fdata, CD_MTFACE)) {
act = CustomData_get_active_layer(fdata, CD_MTFACE);
- CustomData_set_layer_active(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
act = CustomData_get_render_layer(fdata, CD_MTFACE);
- CustomData_set_layer_render(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
act = CustomData_get_clone_layer(fdata, CD_MTFACE);
- CustomData_set_layer_clone(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
act = CustomData_get_stencil_layer(fdata, CD_MTFACE);
- CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
}
@@ -2695,7 +2704,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
bool CustomData_bmesh_merge(
const CustomData *source, CustomData *dest,
- CustomDataMask mask, int alloctype, BMesh *bm, const char htype)
+ CustomDataMask mask, eCDAllocType alloctype, BMesh *bm, const char htype)
{
BMHeader *h;
BMIter iter;
@@ -3438,11 +3447,17 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
data_arg.type = nlayer->type;
data_arg.index = index;
- if (!typeInfo->defaultname)
+ if (!typeInfo->defaultname) {
return;
+ }
+
+ /* Set default name if none specified. Note we only call DATA_() when
+ * needed to avoid overhead of locale lookups in the depsgraph. */
+ if (nlayer->name[0] == '\0') {
+ STRNCPY(nlayer->name, DATA_(typeInfo->defaultname));
+ }
- BLI_uniquename_cb(customdata_unique_check, &data_arg, DATA_(typeInfo->defaultname), '.', nlayer->name,
- sizeof(nlayer->name));
+ BLI_uniquename_cb(customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
}
void CustomData_validate_layer_name(const CustomData *data, int type, const char *name, char *outname)
@@ -3741,19 +3756,6 @@ void CustomData_external_remove(CustomData *data, ID *id, int type, int totelem)
CustomData_external_read(data, id, CD_TYPE_AS_MASK(layer->type), totelem);
layer->flag &= ~CD_FLAG_EXTERNAL;
-
-#if 0
- remove_file = 1;
- for (i = 0; i < data->totlayer; i++)
- if (data->layers[i].flag & CD_FLAG_EXTERNAL)
- remove_file = 0;
-
- if (remove_file) {
- customdata_external_filename(filename, id, external);
- cdf_remove(filename);
- CustomData_external_free(data);
- }
-#endif
}
}
@@ -3769,21 +3771,6 @@ bool CustomData_external_test(CustomData *data, int type)
return (layer->flag & CD_FLAG_EXTERNAL) != 0;
}
-#if 0
-void CustomData_external_remove_object(CustomData *data, ID *id)
-{
- CustomDataExternal *external = data->external;
- char filename[FILE_MAX];
-
- if (!external)
- return;
-
- customdata_external_filename(filename, id, external);
- cdf_remove(filename);
- CustomData_external_free(data);
-}
-#endif
-
/* ********** Mesh-to-mesh data transfer ********** */
static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag)
{
diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c
index 3fee2ef6021..3350d8e7b2f 100644
--- a/source/blender/blenkernel/intern/customdata_file.c
+++ b/source/blender/blenkernel/intern/customdata_file.c
@@ -110,16 +110,6 @@ static int cdf_endian(void)
return CDF_ENDIAN_BIG;
}
-#if 0
-static int cdf_data_type_size(int datatype)
-{
- if (datatype == CDF_DATA_FLOAT)
- return sizeof(float);
-
- return 0;
-}
-#endif
-
CDataFile *cdf_create(int type)
{
CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 7407fc2051f..73c5f6cecdf 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -42,14 +42,13 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_mesh_remap.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
@@ -79,7 +78,7 @@ CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types
cddata_mask |= CD_MASK_MDEFORMVERT; /* Exception for vgroups :/ */
}
else if (cddata_type == CD_FAKE_UV) {
- cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV;
+ cddata_mask |= CD_MASK_MLOOPUV;
}
else if (cddata_type == CD_FAKE_LNOR) {
cddata_mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
@@ -256,77 +255,76 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
/* Generic pre/post processing, only used by custom loop normals currently. */
static void data_transfer_dtdata_type_preprocess(
- Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
- const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src)
+ Mesh *me_src, Mesh *me_dst,
+ const int dtdata_type, const bool dirty_nors_dst)
{
if (dtdata_type == DT_TYPE_LNOR) {
/* Compute custom normals into regular loop normals, which will be used for the transfer. */
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
const float split_angle_dst = me_dst->smoothresh;
- dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
+ BKE_mesh_calc_normals_split(me_src);
- if (dm_dst) {
- dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst);
- }
- else {
- float (*poly_nors_dst)[3];
- float (*loop_nors_dst)[3];
- short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
-
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- if (dirty_nors_dst || !poly_nors_dst) {
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_calc_normals_poly(verts_dst, NULL, num_verts_dst, loops_dst, polys_dst,
- num_loops_dst, num_polys_dst, poly_nors_dst, true);
- }
- /* Cache loop nors into a temp CDLayer. */
- loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- if (dirty_nors_dst || loop_nors_dst) {
- if (!loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
- loops_dst, loop_nors_dst, num_loops_dst,
- polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
- use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
- }
+ float (*poly_nors_dst)[3];
+ float (*loop_nors_dst)[3];
+ short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
+ /* Cache poly nors into a temp CDLayer. */
+ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ const bool do_poly_nors_dst = (poly_nors_dst == NULL);
+ if (do_poly_nors_dst) {
+ poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
+ CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_poly_nors_dst) {
+ BKE_mesh_calc_normals_poly(
+ verts_dst, NULL, num_verts_dst, loops_dst, polys_dst,
+ num_loops_dst, num_polys_dst, poly_nors_dst, true);
+ }
+ /* Cache loop nors into a temp CDLayer. */
+ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
+ const bool do_loop_nors_dst = (loop_nors_dst == NULL);
+ if (do_loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_loop_nors_dst) {
+ BKE_mesh_normals_loop_split(
+ verts_dst, num_verts_dst, edges_dst, num_edges_dst,
+ loops_dst, loop_nors_dst, num_loops_dst,
+ polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
+ use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
}
}
}
static void data_transfer_dtdata_type_postprocess(
- Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst,
+ Object *UNUSED(ob_src), Object *UNUSED(ob_dst), Mesh *UNUSED(me_src), Mesh *me_dst,
const int dtdata_type, const bool changed)
{
if (dtdata_type == DT_TYPE_LNOR) {
/* Bake edited destination loop normals into custom normals again. */
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL);
float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL);
@@ -530,7 +528,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
continue;
}
data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (fro; ;odifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst);
}
@@ -574,7 +572,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
data_dst_to_delete[idx_dst] = false;
}
if (r_map) {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -632,7 +630,7 @@ static bool data_transfer_layersmapping_cdlayers(
data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
else if (use_dupref_dst && r_map) {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst);
}
@@ -659,7 +657,7 @@ static bool data_transfer_layersmapping_cdlayers(
if (tolayers >= 0) { /* Real-layer index */
idx_dst = tolayers;
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -675,7 +673,7 @@ static bool data_transfer_layersmapping_cdlayers(
data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
else {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -696,7 +694,7 @@ static bool data_transfer_layersmapping_cdlayers(
CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
}
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -713,7 +711,7 @@ static bool data_transfer_layersmapping_cdlayers(
CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
}
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -762,7 +760,7 @@ static bool data_transfer_layersmapping_cdlayers(
}
static bool data_transfer_layersmapping_generate(
- ListBase *r_map, Object *ob_src, Object *ob_dst, DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
+ ListBase *r_map, Object *ob_src, Object *ob_dst, Mesh *me_src, Mesh *me_dst,
const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights,
const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers,
SpaceTransform *space_transform)
@@ -774,12 +772,12 @@ static bool data_transfer_layersmapping_generate(
if (elem_type == ME_VERT) {
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getVertDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata;
+ cd_src = &me_src->vdata;
+ cd_dst = &me_dst->vdata;
if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- cd_src, cd_dst, dm_dst != NULL,
+ cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -794,24 +792,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MVert, bweight);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
+ if (use_delete) {
me_dst->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- }
+ me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getVertArray(dm_src),
- dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert,
- dm_src->getNumVerts(dm_src),
- dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert,
+ me_src->mvert, me_dst->mvert,
+ me_src->totvert, me_dst->totvert,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -820,12 +811,12 @@ static bool data_transfer_layersmapping_generate(
else if (cddata_type == CD_FAKE_MDEFORMVERT) {
bool ret;
- cd_src = dm_src->getVertDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata;
+ cd_src = &me_src->vdata;
+ cd_dst = &me_dst->vdata;
ret = data_transfer_layersmapping_vgroups(r_map, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- ob_src, ob_dst, cd_src, cd_dst, dm_dst != NULL,
+ ob_src, ob_dst, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers);
/* Mesh stores its dvert in a specific pointer too. :( */
@@ -839,12 +830,12 @@ static bool data_transfer_layersmapping_generate(
}
else if (elem_type == ME_EDGE) {
if (!(cddata_type & CD_FAKE)) { /* Unused for edges, currently... */
- cd_src = dm_src->getEdgeDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getEdgeDataLayout(dm_dst) : &me_dst->edata;
+ cd_src = &me_src->edata;
+ cd_dst = &me_dst->edata;
if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- cd_src, cd_dst, dm_dst != NULL,
+ cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -859,24 +850,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MEdge, crease);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
+ if (use_delete && !me_dst) {
me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
+ me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -888,24 +872,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MEdge, bweight);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
+ if (use_delete && !me_dst) {
me_dst->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- }
+ me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -919,10 +896,8 @@ static bool data_transfer_layersmapping_generate(
data_transfer_layersmapping_add_item(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag, NULL, interp_data);
return true;
}
@@ -942,12 +917,12 @@ static bool data_transfer_layersmapping_generate(
}
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getLoopDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ cd_src = &me_src->ldata;
+ cd_dst = &me_dst->ldata;
if (!data_transfer_layersmapping_cdlayers(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
+ num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -962,16 +937,16 @@ static bool data_transfer_layersmapping_generate(
}
else if (elem_type == ME_POLY) {
if (cddata_type == CD_FAKE_UV) {
- cddata_type = CD_MTEXPOLY;
+ cddata_type = CD_MLOOPUV;
}
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getPolyDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
+ cd_src = &me_src->pdata;
+ cd_dst = &me_dst->pdata;
if (!data_transfer_layersmapping_cdlayers(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
+ num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -988,10 +963,8 @@ static bool data_transfer_layersmapping_generate(
data_transfer_layersmapping_add_item(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getPolyArray(dm_src),
- dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly,
- dm_src->getNumPolys(dm_src),
- dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly,
+ me_src->mpoly, me_dst->mpoly,
+ me_src->totpoly, me_dst->totpoly,
elem_size, data_size, data_offset, data_flag, NULL, interp_data);
return true;
}
@@ -1010,25 +983,26 @@ static bool data_transfer_layersmapping_generate(
* to get (as much as possible) exact copy of source data layout.
*/
void BKE_object_data_transfer_layout(
- Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete,
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX])
{
- DerivedMesh *dm_src;
+ Mesh *me_src;
Mesh *me_dst;
int i;
const bool use_create = true; /* We always create needed layers here. */
- CustomDataMask dm_src_mask = CD_MASK_BAREMESH;
+ CustomDataMask me_src_mask = CD_MASK_BAREMESH;
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
me_dst = ob_dst->data;
- /* Get source DM.*/
- dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
- dm_src = mesh_get_derived_final(scene, ob_src, dm_src_mask);
- if (!dm_src) {
+ /* Get source evaluated mesh.*/
+ me_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
+ me_src = mesh_get_eval_final(depsgraph, scene, ob_src, me_src_mask);
+ if (!me_src) {
return;
}
@@ -1057,37 +1031,37 @@ void BKE_object_data_transfer_layout(
const int num_elem_dst = me_dst->totvert;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
const int num_elem_dst = me_dst->totedge;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
const int num_elem_dst = me_dst->totloop;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_POLY(dtdata_type)) {
const int num_elem_dst = me_dst->totpoly;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
}
}
-bool BKE_object_data_transfer_dm(
- Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create,
- const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
- SpaceTransform *space_transform, const bool auto_transform,
+bool BKE_object_data_transfer_ex(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, Mesh *me_dst,
+ const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode,
+ const int map_loop_mode, const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform,
const float max_distance, const float ray_radius, const float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
@@ -1101,9 +1075,8 @@ bool BKE_object_data_transfer_dm(
SpaceTransform auto_space_transform;
- DerivedMesh *dm_src;
- Mesh *me_dst, *me_src;
- bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */
+ Mesh *me_src;
+ bool dirty_nors_dst = true; /* Assumed always true if not using an evaluated mesh as destination. */
int i;
MDeformVert *mdef = NULL;
@@ -1117,53 +1090,40 @@ bool BKE_object_data_transfer_dm(
const bool use_delete = false; /* We never delete data layers from destination here. */
- CustomDataMask dm_src_mask = CD_MASK_BAREMESH;
+ CustomDataMask me_src_mask = CD_MASK_BAREMESH;
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
- me_dst = ob_dst->data;
- me_src = ob_src->data;
- if (dm_dst) {
- dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0;
- use_create = false; /* Never create needed custom layers on DM (modifier case). */
+ if (me_dst) {
+ dirty_nors_dst = (me_dst->runtime.cd_dirty_vert & CD_NORMAL) != 0;
+ /* Never create needed custom layers on passed destination mesh
+ * (assumed to *not* be ob_dst->data, aka modifier case). */
+ use_create = false;
+ }
+ else {
+ me_dst = ob_dst->data;
}
if (vgroup_name) {
- if (dm_dst) {
- mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT);
- }
- else {
- mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
- }
+ mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
if (mdef) {
vg_idx = defgroup_name_index(ob_dst, vgroup_name);
}
}
- /* Get source DM.*/
- dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
- /* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm,
- * can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers...
- * Issue is, this means we cannot be sure to have requested cd layers in source.
- *
- * Also, we need to make a local copy of dm_src, otherwise we may end with concurrent creation
- * of data in it (multi-threaded evaluation of the modifier stack, see T46672).
- */
- dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask);
- if (!dm_src) {
+ /* Get source evaluated mesh.*/
+ me_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
+ me_src = mesh_get_eval_final(depsgraph, scene, ob_src, me_src_mask);
+ if (!me_src) {
return changed;
}
- dm_src = CDDM_copy(dm_src);
if (auto_transform) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
-
if (space_transform == NULL) {
space_transform = &auto_space_transform;
}
- BKE_mesh_remap_find_best_match_from_dm(verts_dst, num_verts_dst, dm_src, space_transform);
+ BKE_mesh_remap_find_best_match_from_mesh(me_dst->mvert, me_dst->totvert, me_src, space_transform);
}
/* Check all possible data types.
@@ -1177,9 +1137,7 @@ bool BKE_object_data_transfer_dm(
continue;
}
- data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst,
- dtdata_type, dirty_nors_dst,
- (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh);
+ data_transfer_dtdata_type_preprocess(me_src, me_dst, dtdata_type, dirty_nors_dst);
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
@@ -1193,11 +1151,11 @@ bool BKE_object_data_transfer_dm(
}
if (DT_DATATYPE_IS_VERT(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
if (!geom_map_init[VDATA]) {
- const int num_verts_src = dm_src->getNumVerts(dm_src);
+ const int num_verts_src = me_src->totvert;
if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1205,13 +1163,13 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_vert_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_vert_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
continue;
}
- if ((map_vert_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ if ((map_vert_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any faces, "
"None of the 'Face' mappings can be used in this case");
@@ -1223,9 +1181,9 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_verts_from_dm(
+ BKE_mesh_remap_calc_verts_from_mesh(
map_vert_mode, space_transform, max_distance, ray_radius,
- verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]);
+ verts_dst, num_verts_dst, dirty_nors_dst, me_src, &geom_map[VDATA]);
geom_map_init[VDATA] = true;
}
@@ -1235,7 +1193,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_VERT,
cddata_type, mix_mode, mix_factor, weights[VDATA],
num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1251,13 +1209,13 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
if (!geom_map_init[EDATA]) {
- const int num_edges_src = dm_src->getNumEdges(dm_src);
+ const int num_edges_src = me_src->totedge;
if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1265,7 +1223,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_edge_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ if ((map_edge_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any faces, "
"None of the 'Face' mappings can be used in this case");
@@ -1277,10 +1235,10 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_edges_from_dm(
+ BKE_mesh_remap_calc_edges_from_mesh(
map_edge_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst,
- dm_src, &geom_map[EDATA]);
+ me_src, &geom_map[EDATA]);
geom_map_init[EDATA] = true;
}
@@ -1292,7 +1250,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_EDGE,
cddata_type, mix_mode, mix_factor, weights[EDATA],
num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1308,21 +1266,21 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
if (!geom_map_init[LDATA]) {
- const int num_loops_src = dm_src->getNumLoops(dm_src);
+ const int num_loops_src = me_src->totloop;
if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1330,7 +1288,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_loop_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_loop_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
@@ -1342,13 +1300,13 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_loops_from_dm(
+ BKE_mesh_remap_calc_loops_from_mesh(
map_loop_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst,
loops_dst, num_loops_dst, polys_dst, num_polys_dst,
ldata_dst, pdata_dst,
(me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst,
- dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh,
+ me_src,
island_callback, islands_handling_precision, &geom_map[LDATA]);
geom_map_init[LDATA] = true;
}
@@ -1361,7 +1319,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_LOOP,
cddata_type, mix_mode, mix_factor, weights[LDATA],
num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1377,16 +1335,16 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_POLY(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
if (!geom_map_init[PDATA]) {
- const int num_polys_src = dm_src->getNumPolys(dm_src);
+ const int num_polys_src = me_src->totpoly;
if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1394,7 +1352,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_poly_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_poly_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
@@ -1406,11 +1364,11 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_polys_from_dm(
+ BKE_mesh_remap_calc_polys_from_mesh(
map_poly_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, loops_dst, num_loops_dst,
polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst,
- dm_src, &geom_map[PDATA]);
+ me_src, &geom_map[PDATA]);
geom_map_init[PDATA] = true;
}
@@ -1422,7 +1380,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_POLY,
cddata_type, mix_mode, mix_factor, weights[PDATA],
num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1438,14 +1396,13 @@ bool BKE_object_data_transfer_dm(
}
}
- data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed);
+ data_transfer_dtdata_type_postprocess(ob_src, ob_dst, me_src, me_dst, dtdata_type, changed);
}
for (i = 0; i < DATAMAX; i++) {
BKE_mesh_remap_free(&geom_map[i]);
MEM_SAFE_FREE(weights[i]);
}
- dm_src->release(dm_src);
return changed;
@@ -1457,16 +1414,16 @@ bool BKE_object_data_transfer_dm(
}
bool BKE_object_data_transfer_mesh(
- Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_create,
- const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
- SpaceTransform *space_transform, const bool auto_transform,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, const int data_types,
+ const bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode,
+ const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform,
const float max_distance, const float ray_radius, const float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
ReportList *reports)
{
- return BKE_object_data_transfer_dm(
- scene, ob_src, ob_dst, NULL, data_types, use_create,
+ return BKE_object_data_transfer_ex(
+ depsgraph, scene, ob_src, ob_dst, NULL, data_types, use_create,
map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode,
space_transform, auto_transform,
max_distance, ray_radius, islands_handling_precision,
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index f33f17019b3..e61b8f71ffa 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -54,7 +54,9 @@
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h" /* own include */
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "data_transfer_intern.h"
@@ -73,6 +75,8 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
BLI_addtail(&ob->defbase, defgroup);
defgroup_unique_name(defgroup, ob);
+ BKE_object_batch_cache_dirty_tag(ob);
+
return defgroup;
}
@@ -475,12 +479,12 @@ void defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip
bDeformGroup *defgroup_find_name(Object *ob, const char *name)
{
- return BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name));
+ return (name && name[0] != '\0') ? BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name)) : NULL;
}
int defgroup_name_index(Object *ob, const char *name)
{
- return (name) ? BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) : -1;
+ return (name && name[0] != '\0') ? BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) : -1;
}
/**
@@ -1290,3 +1294,43 @@ bool data_transfer_layersmapping_vgroups(
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Various utils & helpers.
+ * \{ */
+
+void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight)
+{
+ const float blend = ((weight / 2.0f) + 0.5f);
+
+ if (weight <= 0.25f) { /* blue->cyan */
+ r_rgb[0] = 0.0f;
+ r_rgb[1] = blend * weight * 4.0f;
+ r_rgb[2] = blend;
+ }
+ else if (weight <= 0.50f) { /* cyan->green */
+ r_rgb[0] = 0.0f;
+ r_rgb[1] = blend;
+ r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
+ }
+ else if (weight <= 0.75f) { /* green->yellow */
+ r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
+ r_rgb[1] = blend;
+ r_rgb[2] = 0.0f;
+ }
+ else if (weight <= 1.0f) { /* yellow->red */
+ r_rgb[0] = blend;
+ r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
+ r_rgb[2] = 0.0f;
+ }
+ else {
+ /* exceptional value, unclamped or nan,
+ * avoid uninitialized memory use */
+ r_rgb[0] = 1.0f;
+ r_rgb[1] = 0.0f;
+ r_rgb[2] = 1.0f;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index dea1a3718dd..182c3204ccb 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -48,13 +49,14 @@
#include "BLI_utildefines.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_object.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mball_tessellate.h"
+#include "BKE_mesh.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_anim.h"
@@ -64,6 +66,9 @@
#include "BLI_sys_types.h" // for intptr_t support
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
static void boundbox_displist_object(Object *ob);
void BKE_displist_elem_free(DispList *dl)
@@ -680,17 +685,17 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis
* - first point left, last point right
* - based on subdivided points in original curve, not on points in taper curve (still)
*/
-static float displist_calc_taper(Scene *scene, Object *taperobj, float fac)
+static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, float fac)
{
DispList *dl;
if (taperobj == NULL || taperobj->type != OB_CURVE)
return 1.0;
- dl = taperobj->curve_cache ? taperobj->curve_cache->disp.first : NULL;
+ dl = taperobj->runtime.curve_cache ? taperobj->runtime.curve_cache->disp.first : NULL;
if (dl == NULL) {
- BKE_displist_make_curveTypes(scene, taperobj, 0);
- dl = taperobj->curve_cache->disp.first;
+ BKE_displist_make_curveTypes(depsgraph, scene, taperobj, false, false);
+ dl = taperobj->runtime.curve_cache->disp.first;
}
if (dl) {
float minx, dx, *fp;
@@ -720,39 +725,39 @@ static float displist_calc_taper(Scene *scene, Object *taperobj, float fac)
return 1.0;
}
-float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot)
+float BKE_displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, int cur, int tot)
{
float fac = ((float)cur) / (float)(tot - 1);
- return displist_calc_taper(scene, taperobj, fac);
+ return displist_calc_taper(depsgraph, scene, taperobj, fac);
}
-void BKE_displist_make_mball(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
+void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (!ob || ob->type != OB_MBALL)
return;
- if (ob == BKE_mball_basis_find(bmain, eval_ctx, scene, ob)) {
- if (ob->curve_cache) {
- BKE_displist_free(&(ob->curve_cache->disp));
+ if (ob == BKE_mball_basis_find(scene, ob)) {
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&(ob->runtime.curve_cache->disp));
}
else {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
}
- BKE_mball_polygonize(bmain, eval_ctx, scene, ob, &ob->curve_cache->disp);
+ BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
BKE_mball_texspace_calc(ob);
- object_deform_mball(ob, &ob->curve_cache->disp);
+ object_deform_mball(ob, &ob->runtime.curve_cache->disp);
/* NOP for MBALLs anyway... */
boundbox_displist_object(ob);
}
}
-void BKE_displist_make_mball_forRender(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
+void BKE_displist_make_mball_forRender(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
- BKE_mball_polygonize(bmain, eval_ctx, scene, ob, dispbase);
+ BKE_mball_polygonize(depsgraph, scene, ob, dispbase);
BKE_mball_texspace_calc(ob);
object_deform_mball(ob, dispbase);
@@ -800,14 +805,15 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob,
return pretessellatePoint;
}
-static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_modifiers_pre(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
+ const bool for_render, const bool use_render_resolution)
{
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
Curve *cu = ob->data;
- int numVerts = 0;
+ int numElems = 0, numVerts = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
ModifierApplyFlag app_flag = 0;
float (*deformedVerts)[3] = NULL;
@@ -825,21 +831,25 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
required_mode |= eModifierMode_Editmode;
if (!editmode) {
- keyVerts = BKE_key_evaluate_object(ob, &numVerts);
+ keyVerts = BKE_key_evaluate_object(ob, &numElems);
if (keyVerts) {
+ BLI_assert(BKE_keyblock_curve_element_count(nurb) == numElems);
+
/* split coords from key data, the latter also includes
* tilts, which is passed through in the modifier stack.
* this is also the reason curves do not use a virtual
* shape key modifier yet. */
deformedVerts = BKE_curve_nurbs_keyVertexCos_get(nurb, keyVerts);
- BLI_assert(BKE_nurbList_verts_count(nurb) == numVerts);
+ numVerts = BKE_nurbList_verts_count(nurb);
}
}
@@ -847,8 +857,6 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode))
continue;
if (mti->type != eModifierTypeType_OnlyDeform)
@@ -858,7 +866,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts);
}
- mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, app_flag);
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
if (md == pretessellatePoint)
break;
@@ -910,9 +918,10 @@ static void displist_apply_allverts(ListBase *dispbase, float (*allverts)[3])
}
}
-static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
- ListBase *dispbase, DerivedMesh **r_dm_final,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_modifiers_post(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
+ ListBase *dispbase, Mesh **r_final,
+ const bool for_render, const bool use_render_resolution)
{
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
@@ -920,7 +929,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
Curve *cu = ob->data;
int required_mode = 0, totvert = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- DerivedMesh *dm = NULL, *ndm;
+ Mesh *modified = NULL, *mesh_applied;
float (*vertCos)[3] = NULL;
int useCache = !for_render;
ModifierApplyFlag app_flag = 0;
@@ -932,6 +941,11 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx_deform = {depsgraph, ob,
+ editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ const ModifierEvalContext mectx_apply = {depsgraph, ob,
+ useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
@@ -941,43 +955,34 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
md = pretessellatePoint->next;
}
- if (r_dm_final && *r_dm_final) {
- (*r_dm_final)->release(*r_dm_final);
+ if (r_final && *r_final) {
+ BKE_id_free(NULL, r_final);
}
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- ModifierApplyFlag appf = app_flag;
-
- md->scene = scene;
if (!modifier_isEnabled(scene, md, required_mode))
continue;
if (mti->type == eModifierTypeType_OnlyDeform ||
- (mti->type == eModifierTypeType_DeformOrConstruct && !dm))
+ (mti->type == eModifierTypeType_DeformOrConstruct && !modified))
{
- if (editmode)
- appf |= MOD_APPLY_USECACHE;
- if (dm) {
+ if (modified) {
if (!vertCos) {
- totvert = dm->getNumVerts(dm);
- vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "dfmv");
- dm->getVertCos(dm, vertCos);
+ vertCos = BKE_mesh_vertexCos_get(modified, &totvert);
}
-
- mti->deformVerts(md, ob, dm, vertCos, totvert, appf);
+ mti->deformVerts(md, &mectx_deform, modified, vertCos, totvert);
}
else {
if (!vertCos) {
vertCos = displist_get_allverts(dispbase, &totvert);
}
-
- mti->deformVerts(md, ob, NULL, vertCos, totvert, appf);
+ mti->deformVerts(md, &mectx_deform, NULL, vertCos, totvert);
}
}
else {
- if (!r_dm_final) {
+ if (!r_final) {
/* makeDisplistCurveTypes could be used for beveling, where derived mesh
* is totally unnecessary, so we could stop modifiers applying
* when we found constructive modifier but derived mesh is unwanted result
@@ -985,13 +990,17 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
break;
}
- if (dm) {
+ if (modified) {
if (vertCos) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
-
- CDDM_apply_vert_coords(dm, vertCos);
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
}
}
else {
@@ -1003,7 +1012,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
curve_to_filledpoly(cu, nurb, dispbase);
}
- dm = CDDM_from_curve_displist(ob, dispbase);
+ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
}
if (vertCos) {
@@ -1012,29 +1021,31 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
vertCos = NULL;
}
- if (useCache)
- appf |= MOD_APPLY_USECACHE;
+ mesh_applied = mti->applyModifier(md, &mectx_apply, modified);
- ndm = modwrap_applyModifier(md, ob, dm, appf);
-
- if (ndm) {
+ if (mesh_applied) {
/* Modifier returned a new derived mesh */
- if (dm && dm != ndm) /* Modifier */
- dm->release(dm);
- dm = ndm;
+ if (modified && modified != mesh_applied) /* Modifier */
+ BKE_id_free(NULL, modified);
+ modified = mesh_applied;
}
}
}
if (vertCos) {
- if (dm) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
+ if (modified) {
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
+ BKE_mesh_calc_normals_mapping_simple(modified);
- CDDM_apply_vert_coords(dm, vertCos);
- CDDM_calc_normals_mapping(dm);
MEM_freeN(vertCos);
}
else {
@@ -1044,23 +1055,27 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
}
}
- if (r_dm_final) {
- if (dm) {
+ if (r_final) {
+ if (modified) {
/* see: mesh_calc_modifiers */
- if (dm->getNumTessFaces(dm) == 0) {
- dm->recalcTessellation(dm);
+ if (modified->totface == 0) {
+ BKE_mesh_tessface_calc(modified);
}
/* Even if tessellation is not needed, some modifiers might have modified CD layers
* (like mloopcol or mloopuv), hence we have to update those. */
- else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
- DM_update_tessface_data(dm);
+ else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) {
+ BKE_mesh_tessface_calc(modified);
}
- if (dm->type == DM_TYPE_CDDM) {
- CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
- }
+ /* XXX2.8(Sybren): make sure the face normals are recalculated as well */
+ BKE_mesh_ensure_normals(modified);
+
+ (*r_final) = modified;
+ }
+ else {
+ (*r_final) = NULL;
}
- (*r_dm_final) = dm;
+
}
}
@@ -1092,13 +1107,15 @@ static void displist_surf_indices(DispList *dl)
}
}
-static DerivedMesh *create_orco_dm(Scene *scene, Object *ob)
+/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
+static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
DerivedMesh *dm;
ListBase disp = {NULL, NULL};
/* OrcoDM should be created from underformed disp lists */
- BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
+ BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
dm = CDDM_from_curve_displist(ob, &disp);
BKE_displist_free(&disp);
@@ -1135,9 +1152,13 @@ static void add_orco_dm(Object *ob, DerivedMesh *dm, DerivedMesh *orcodm)
else
DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco);
}
+#endif
-static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
- const bool for_render, const bool use_render_resolution)
+/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
+static void curve_calc_orcodm(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
+ const bool for_render, const bool use_render_resolution)
{
/* this function represents logic of mesh's orcodm calculation
* for displist-based objects
@@ -1158,6 +1179,8 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
@@ -1174,7 +1197,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
* This means we can create ORCO DM in advance and assume it's
* never NULL.
*/
- orcodm = create_orco_dm(scene, ob);
+ orcodm = create_orco_dm(depsgraph, scene, ob);
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
@@ -1186,7 +1209,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
if (mti->type != eModifierTypeType_Constructive)
continue;
- ndm = modwrap_applyModifier(md, ob, orcodm, app_flag);
+ ndm = modwrap_applyModifier(md, &mectx, orcodm);
if (ndm) {
/* if the modifier returned a new dm, release the old one */
@@ -1202,10 +1225,12 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
orcodm->release(orcodm);
}
+#endif
-void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution)
+void BKE_displist_make_surf(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ Mesh **r_final,
+ const bool for_render, const bool for_orco, const bool use_render_resolution)
{
ListBase nubase = {NULL, NULL};
Nurb *nu;
@@ -1222,7 +1247,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
}
if (!for_orco)
- curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution);
+ curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
for (nu = nubase.first; nu; nu = nu->next) {
if ((for_render || nu->hide == 0) && BKE_nurb_check_valid_uv(nu)) {
@@ -1288,8 +1313,8 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
}
if (!for_orco) {
- BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final,
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
+ curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final,
for_render, use_render_resolution);
}
@@ -1515,9 +1540,10 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu,
}
}
-static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution)
+static void do_makeDispListCurveTypes(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ Mesh **r_final,
+ const bool for_render, const bool for_orco, const bool use_render_resolution)
{
Curve *cu = ob->data;
@@ -1525,21 +1551,21 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
if (ob->type == OB_SURF) {
- BKE_displist_make_surf(scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution);
+ BKE_displist_make_surf(depsgraph, scene, ob, dispbase, r_final, for_render, for_orco, use_render_resolution);
}
else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
ListBase dlbev;
ListBase nubase = {NULL, NULL};
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
/* We only re-evaluate path if evaluation is not happening for orco.
* If the calculation happens for orco, we should never free data which
* was needed before and only not needed for orco calculation.
*/
if (!for_orco) {
- if (ob->curve_cache->path) free_path(ob->curve_cache->path);
- ob->curve_cache->path = NULL;
+ if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path);
+ ob->runtime.curve_cache->path = NULL;
}
if (ob->type == OB_FONT) {
@@ -1550,12 +1576,12 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
if (!for_orco)
- curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution);
+ curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
- BKE_curve_bevelList_make(ob, &nubase, for_render != false);
+ BKE_curve_bevelList_make(ob, &nubase, use_render_resolution);
/* If curve has no bevel will return nothing */
- BKE_curve_bevel_make(scene, ob, &dlbev, for_render, use_render_resolution);
+ BKE_curve_bevel_make(depsgraph, scene, ob, &dlbev, for_render, use_render_resolution);
/* no bevel or extrude, and no width correction? */
if (!dlbev.first && cu->width == 1.0f) {
@@ -1563,7 +1589,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
else {
float widfac = cu->width - 1.0f;
- BevList *bl = ob->curve_cache->bev.first;
+ BevList *bl = ob->runtime.curve_cache->bev.first;
Nurb *nu = nubase.first;
for (; bl && nu; bl = bl->next, nu = nu->next) {
@@ -1690,7 +1716,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
taper_fac -= (1.0f - lastblend) / len;
}
- fac = displist_calc_taper(scene, cu->taperobj, taper_fac);
+ fac = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_fac);
}
if (bevp->split_tag) {
@@ -1743,18 +1769,18 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (!for_orco) {
if ((cu->flag & CU_PATH) ||
- DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CURVE_PATH)
+ DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH)
{
calc_curvepath(ob, &nubase);
}
}
if (!for_orco) {
- BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution);
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
+ curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution);
}
- if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) {
+ if (cu->flag & CU_DEFORM_FILL && !ob->runtime.mesh_eval) {
curve_to_filledpoly(cu, &nubase, dispbase);
}
@@ -1762,7 +1788,8 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
}
-void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
+void BKE_displist_make_curveTypes(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, const bool for_render, const bool for_orco)
{
ListBase *dispbase;
@@ -1774,58 +1801,37 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
BKE_object_free_derived_caches(ob);
- if (!ob->curve_cache) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
+ if (!ob->runtime.curve_cache) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
}
- dispbase = &(ob->curve_cache->disp);
+ dispbase = &(ob->runtime.curve_cache->disp);
- do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0);
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, &ob->runtime.mesh_eval, for_render, for_orco, false);
boundbox_displist_object(ob);
}
-void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final, const bool for_orco,
- const bool use_render_resolution)
+void BKE_displist_make_curveTypes_forRender(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ Mesh **r_final, const bool for_orco,
+ const bool use_render_resolution)
{
- if (ob->curve_cache == NULL) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
+ if (ob->runtime.curve_cache == NULL) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
- do_makeDispListCurveTypes(scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution);
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, r_final, true, for_orco, use_render_resolution);
}
-void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase)
+void BKE_displist_make_curveTypes_forOrco(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
- if (ob->curve_cache == NULL) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
- }
-
- do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1, 1);
-}
-
-/* add Orco layer to the displist object which has got derived mesh and return orco */
-float *BKE_displist_make_orco(Scene *scene, Object *ob, DerivedMesh *dm_final,
- const bool for_render,
- const bool use_render_resolution)
-{
- float *orco;
-
- if (dm_final == NULL)
- dm_final = ob->derivedFinal;
-
- if (!dm_final->getVertDataArray(dm_final, CD_ORCO)) {
- curve_calc_orcodm(scene, ob, dm_final, for_render, use_render_resolution);
- }
-
- orco = dm_final->getVertDataArray(dm_final, CD_ORCO);
-
- if (orco) {
- orco = MEM_dupallocN(orco);
+ if (ob->runtime.curve_cache == NULL) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
- return orco;
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, NULL, 1, 1, 1);
}
void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3])
@@ -1863,14 +1869,14 @@ static void boundbox_displist_object(Object *ob)
if (ob->bb == NULL)
ob->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- if (ob->derivedFinal) {
- DM_set_object_boundbox(ob, ob->derivedFinal);
+ if (ob->runtime.mesh_eval) {
+ BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
}
else {
float min[3], max[3];
INIT_MINMAX(min, max);
- BKE_displist_minmax(&ob->curve_cache->disp, min, max);
+ BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
BKE_boundbox_init_from_minmax(ob->bb, min, max);
ob->bb->flag &= ~BOUNDBOX_DIRTY;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index e129251157e..5453982b070 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -41,9 +41,9 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_dynamicpaint_types.h"
-#include "DNA_group_types.h" /*GroupObject*/
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -55,27 +55,32 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h" /* bvh tree */
+#include "BKE_collection.h"
+#include "BKE_collision.h"
#include "BKE_colorband.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_dynamicpaint.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
-/* for image output */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+/* for image output */
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -246,7 +251,7 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
return 0; /* not supported atm */
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- return (surface->canvas->dm) ? surface->canvas->dm->getNumVerts(surface->canvas->dm) : 0;
+ return (surface->canvas->mesh) ? surface->canvas->mesh->totvert : 0;
}
return 0;
@@ -487,42 +492,17 @@ static void scene_setSubframe(Scene *scene, float subframe)
scene->r.subframe = subframe;
}
-static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene)
+static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgraph)
{
- Base *base = NULL;
- GroupObject *go = NULL;
- Object *brushObj = NULL;
- ModifierData *md = NULL;
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
int flags = 0;
- if (surface->brush_group)
- go = surface->brush_group->gobject.first;
- else
- base = scene->base.first;
-
- while (base || go) {
- brushObj = NULL;
-
- /* select object */
- if (surface->brush_group) {
- if (go->ob)
- brushObj = go->ob;
- }
- else {
- brushObj = base->object;
- }
-
- if (surface->brush_group)
- go = go->next;
- else
- base = base->next;
-
- if (!brushObj) {
- continue;
- }
+ for (int i = 0; i < numobjects; i++) {
+ Object *brushObj = objects[i];
- md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
@@ -535,12 +515,9 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
}
}
- return flags;
-}
+ BKE_collision_objects_free(objects);
-static int brush_usesMaterial(const DynamicPaintBrushSettings *brush, const Scene *scene)
-{
- return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!BKE_scene_use_new_shading_nodes(scene)));
+ return flags;
}
/* check whether two bounds intersect */
@@ -837,9 +814,10 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
{
if (pmd->brush) {
- if (pmd->brush->dm)
- pmd->brush->dm->release(pmd->brush->dm);
- pmd->brush->dm = NULL;
+ if (pmd->brush->mesh) {
+ BKE_id_free(NULL, pmd->brush->mesh);
+ }
+ pmd->brush->mesh = NULL;
if (pmd->brush->paint_ramp)
MEM_freeN(pmd->brush->paint_ramp);
@@ -937,10 +915,13 @@ void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
surface->data = NULL;
}
-void dynamicPaint_freeSurface(DynamicPaintSurface *surface)
+void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd,
+ DynamicPaintSurface *surface)
{
/* point cache */
- BKE_ptcache_free_list(&(surface->ptcaches));
+ if ((pmd->modifier.flag & eModifierFlag_SharedCaches) == 0) {
+ BKE_ptcache_free_list(&(surface->ptcaches));
+ }
surface->pointcache = NULL;
if (surface->effector_weights)
@@ -962,14 +943,15 @@ void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
while (surface) {
next_surface = surface->next;
- dynamicPaint_freeSurface(surface);
+ dynamicPaint_freeSurface(pmd, surface);
surface = next_surface;
}
- /* free dm copy */
- if (pmd->canvas->dm)
- pmd->canvas->dm->release(pmd->canvas->dm);
- pmd->canvas->dm = NULL;
+ /* free mesh copy */
+ if (pmd->canvas->mesh) {
+ BKE_id_free(NULL, pmd->canvas->mesh);
+ }
+ pmd->canvas->mesh = NULL;
MEM_freeN(pmd->canvas);
pmd->canvas = NULL;
@@ -1081,7 +1063,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
if (!canvas)
return false;
canvas->pmd = pmd;
- canvas->dm = NULL;
+ canvas->mesh = NULL;
/* Create one surface */
if (!dynamicPaint_createNewSurface(canvas, scene))
@@ -1103,7 +1085,6 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
brush->collision = MOD_DPAINT_COL_VOLUME;
- brush->mat = NULL;
brush->r = 0.15f;
brush->g = 0.4f;
brush->b = 0.8f;
@@ -1122,7 +1103,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->smudge_strength = 0.3f;
brush->max_velocity = 1.0f;
- brush->dm = NULL;
+ brush->mesh = NULL;
/* Paint proximity falloff colorramp. */
{
@@ -1161,7 +1142,9 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
return true;
}
-void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tpmd)
+void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd,
+ struct DynamicPaintModifierData *tpmd,
+ int flag)
{
/* Init modifier */
tpmd->type = pmd->type;
@@ -1176,11 +1159,19 @@ void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, stru
tpmd->canvas->pmd = tpmd;
/* free default surface */
if (tpmd->canvas->surfaces.first)
- dynamicPaint_freeSurface(tpmd->canvas->surfaces.first);
+ dynamicPaint_freeSurface(tpmd, tpmd->canvas->surfaces.first);
/* copy existing surfaces */
for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, NULL);
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* TODO(sergey): Consider passing some tips to the surface
+ * creation to avoid this allocate-and-free cache behavior. */
+ BKE_ptcache_free_list(&t_surface->ptcaches);
+ tpmd->modifier.flag |= eModifierFlag_SharedCaches;
+ t_surface->ptcaches = surface->ptcaches;
+ t_surface->pointcache = surface->pointcache;
+ }
/* surface settings */
t_surface->brush_group = surface->brush_group;
@@ -1243,7 +1234,6 @@ void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, stru
t_brush->flags = brush->flags;
t_brush->collision = brush->collision;
- t_brush->mat = brush->mat;
t_brush->r = brush->r;
t_brush->g = brush->g;
t_brush->b = brush->b;
@@ -1311,7 +1301,7 @@ static bool surface_usesAdjData(DynamicPaintSurface *surface)
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
- DerivedMesh *dm = surface->canvas->dm;
+ Mesh *mesh = surface->canvas->mesh;
PaintAdjData *ad;
int *temp_data;
int neigh_points = 0;
@@ -1321,7 +1311,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* For vertex format, neighbors are connected by edges */
- neigh_points = 2 * dm->getNumEdges(dm);
+ neigh_points = 2 * mesh->totedge;
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
neigh_points = sData->total_points * 8;
@@ -1357,11 +1347,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
int n_pos;
/* For vertex format, count every vertex that is connected by an edge */
- int numOfEdges = dm->getNumEdges(dm);
- int numOfPolys = dm->getNumPolys(dm);
- struct MEdge *edge = dm->getEdgeArray(dm);
- struct MPoly *mpoly = dm->getPolyArray(dm);
- struct MLoop *mloop = dm->getLoopArray(dm);
+ int numOfEdges = mesh->totedge;
+ int numOfPolys = mesh->totpoly;
+ struct MEdge *edge = mesh->medge;
+ struct MPoly *mpoly = mesh->mpoly;
+ struct MLoop *mloop = mesh->mloop;
/* count number of edges per vertex */
for (i = 0; i < numOfEdges; i++) {
@@ -1545,7 +1535,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
{
PaintSurfaceData *sData = surface->data;
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- DerivedMesh *dm = surface->canvas->dm;
+ Mesh *mesh = surface->canvas->mesh;
int i;
const bool scene_color_manage = BKE_scene_check_color_management_enabled(scene);
@@ -1566,9 +1556,9 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
Tex *tex = surface->init_texture;
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
+ const MLoop *mloop = mesh->mloop;
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const int tottri = BKE_mesh_runtime_looptri_len(mesh);
const MLoopUV *mloopuv = NULL;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
@@ -1577,8 +1567,8 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
return;
/* get uv map */
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->init_layername, uvname);
- mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname);
+ mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
if (!mloopuv)
return;
@@ -1621,9 +1611,9 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
/* for vertex surface, just copy colors from mcol */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- const MLoop *mloop = dm->getLoopArray(dm);
- const int totloop = dm->getNumLoops(dm);
- const MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
+ const MLoop *mloop = mesh->mloop;
+ const int totloop = mesh->totloop;
+ const MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername);
if (!col)
return;
@@ -1632,8 +1622,8 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername);
if (!col)
return;
@@ -1755,7 +1745,7 @@ static void dynamic_paint_apply_surface_displace_cb(
}
/* apply displacing vertex surface to the derived mesh */
-static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result)
+static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result)
{
PaintSurfaceData *sData = surface->data;
@@ -1764,7 +1754,7 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri
/* displace paint */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- MVert *mvert = result->getVertArray(result);
+ MVert *mvert = result->mvert;
DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
ParallelRangeSettings settings;
@@ -1882,10 +1872,10 @@ static void dynamic_paint_apply_surface_wave_cb(
/*
* Apply canvas data to the object derived mesh
*/
-static DerivedMesh *dynamicPaint_Modifier_apply(
- DynamicPaintModifierData *pmd, Object *ob, DerivedMesh *dm)
+static Mesh *dynamicPaint_Modifier_apply(
+ DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
{
- DerivedMesh *result = CDDM_copy(dm);
+ Mesh *result = BKE_mesh_copy_for_eval(mesh, false);
if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
@@ -1905,10 +1895,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* vertex color paint */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- MLoop *mloop = CDDM_get_loops(result);
- const int totloop = result->numLoopData;
- MPoly *mpoly = CDDM_get_polys(result);
- const int totpoly = result->numPolyData;
+ MLoop *mloop = result->mloop;
+ const int totloop = result->totloop;
+ MPoly *mpoly = result->mpoly;
+ const int totpoly = result->totpoly;
/* paint is stored on dry and wet layers, so mix final color first */
float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
@@ -1926,28 +1916,28 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
}
/* paint layer */
- MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
+ MLoopCol *mloopcol = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
mloopcol = CustomData_add_layer_named(
- &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
}
/* wet layer */
- MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
+ MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
mloopcol_wet = CustomData_add_layer_named(
- &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
}
/* Save preview results to weight layer to be able to share same drawing methods */
MLoopCol *mloopcol_preview = NULL;
if (surface->flags & MOD_DPAINT_PREVIEW) {
- mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
+ mloopcol_preview = CustomData_get_layer(&result->ldata, CD_PREVIEW_MLOOPCOL);
if (!mloopcol_preview) {
mloopcol_preview = CustomData_add_layer(
- &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
+ &result->ldata, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
}
}
@@ -1972,12 +1962,12 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
MEM_freeN(fcolor);
/* Mark tessellated CD layers as dirty. */
- result->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ //result->dirty |= DM_DIRTY_TESS_CDLAYERS;
}
/* vertex group paint */
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
int defgrp_index = defgroup_name_index(ob, surface->output_name);
- MDeformVert *dvert = result->getVertDataArray(result, CD_MDEFORMVERT);
+ MDeformVert *dvert = CustomData_get_layer(&result->vdata, CD_MDEFORMVERT);
float *weight = (float *)sData->type_data;
/* viewport preview */
@@ -1985,12 +1975,13 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* Save preview results to weight layer to be
* able to share same drawing methods.
* Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */
- DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
+ //TODO port this function
+ //DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
}
/* apply weights into a vertex group, if doesn't exists add a new layer */
if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
- dvert = CustomData_add_layer(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
+ dvert = CustomData_add_layer(&result->vdata, CD_MDEFORMVERT, CD_CALLOC,
NULL, sData->total_points);
}
if (defgrp_index != -1 && dvert) {
@@ -2014,7 +2005,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
}
/* wave simulation */
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- MVert *mvert = result->getVertArray(result);
+ MVert *mvert = result->mvert;
DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
ParallelRangeSettings settings;
@@ -2038,14 +2029,15 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
}
if (update_normals) {
- result->dirty |= DM_DIRTY_NORMALS;
+ //result->dirty |= DM_DIRTY_NORMALS;
}
}
- /* make a copy of dm to use as brush data */
+ /* make a copy of mesh to use as brush data */
if (pmd->brush) {
- if (pmd->brush->dm)
- pmd->brush->dm->release(pmd->brush->dm);
- pmd->brush->dm = CDDM_copy(result);
+ if (pmd->brush->mesh) {
+ BKE_id_free(NULL, pmd->brush->mesh);
+ }
+ pmd->brush->mesh = BKE_mesh_copy_for_eval(result, false);
}
return result;
@@ -2060,27 +2052,28 @@ void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
}
}
-static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMesh *dm)
+static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh)
{
- if (canvas->dm) {
- canvas->dm->release(canvas->dm);
+ if (canvas->mesh) {
+ BKE_id_free(NULL, canvas->mesh);
}
- canvas->dm = CDDM_copy(dm);
+ canvas->mesh = BKE_mesh_copy_for_eval(mesh, false);
}
/*
* Updates derived mesh copy and processes dynamic paint step / caches.
*/
static void dynamicPaint_frameUpdate(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+ DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, Mesh *mesh)
{
if (pmd->canvas) {
DynamicPaintCanvasSettings *canvas = pmd->canvas;
DynamicPaintSurface *surface = canvas->surfaces.first;
/* update derived mesh copy */
- canvas_copyDerivedMesh(canvas, dm);
+ canvas_copyMesh(canvas, mesh);
/* in case image sequence baking, stop here */
if (canvas->flags & MOD_DPAINT_BAKING)
@@ -2136,14 +2129,14 @@ static void dynamicPaint_frameUpdate(
else if (can_simulate) {
/* calculate surface frame */
canvas->flags |= MOD_DPAINT_BAKING;
- dynamicPaint_calculateFrame(bmain, eval_ctx, surface, scene, ob, current_frame);
+ dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
canvas->flags &= ~MOD_DPAINT_BAKING;
- /* restore canvas derivedmesh if required */
+ /* restore canvas mesh if required */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next)
{
- canvas_copyDerivedMesh(canvas, dm);
+ canvas_copyMesh(canvas, mesh);
}
BKE_ptcache_validate(cache, surface->current_frame);
@@ -2155,26 +2148,27 @@ static void dynamicPaint_frameUpdate(
}
/* Modifier call. Processes dynamic paint modifier step. */
-DerivedMesh *dynamicPaint_Modifier_do(Main *bmain,
- EvaluationContext *eval_ctx, DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+Mesh *dynamicPaint_Modifier_do(
+ DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, Mesh *mesh)
{
if (pmd->canvas) {
- DerivedMesh *ret;
+ Mesh *ret;
/* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(bmain, eval_ctx, pmd, scene, ob, dm);
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
/* Return output mesh */
- ret = dynamicPaint_Modifier_apply(pmd, ob, dm);
+ ret = dynamicPaint_Modifier_apply(pmd, ob, mesh);
return ret;
}
else {
/* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(bmain, eval_ctx, pmd, scene, ob, dm);
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
/* Return output mesh */
- return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ return dynamicPaint_Modifier_apply(pmd, ob, mesh);
}
}
@@ -2776,7 +2770,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
PaintSurfaceData *sData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
- DerivedMesh *dm = canvas->dm;
+ Mesh *mesh = canvas->mesh;
PaintUVPoint *tempPoints = NULL;
Vec3f *tempWeights = NULL;
@@ -2790,19 +2784,19 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
*progress = 0.0f;
*do_update = true;
- if (!dm)
+ if (!mesh)
return setError(canvas, N_("Canvas mesh not updated"));
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ)
return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
- mloop = dm->getLoopArray(dm);
- mlooptri = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
+ mloop = mesh->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const int tottri = BKE_mesh_runtime_looptri_len(mesh);
/* get uv map */
- if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->uvlayer_name, uvname);
- mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->uvlayer_name, uvname);
+ mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
}
/* Check for validity */
@@ -2928,7 +2922,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
BKE_mesh_vert_looptri_map_create(
&vert_to_looptri_map, &vert_to_looptri_map_mem,
- dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+ mesh->mvert, mesh->totvert, mlooptri, tottri, mloop, mesh->totloop);
int total_border = 0;
@@ -3341,91 +3335,6 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
}
-/***************************** Material / Texture Sampling ******************************/
-
-/* stores a copy of required materials to allow doing adjustments
- * without interfering the render/preview */
-typedef struct BrushMaterials {
- Material *mat;
- Material **ob_mats;
- int tot;
-} BrushMaterials;
-
-/* Initialize materials for brush object:
- * Calculates inverse matrices for linked objects, updates
- * volume caches etc. */
-static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats)
-{
- /* Calculate inverse transformation matrix
- * for this object */
- invert_m4_m4(brushOb->imat, brushOb->obmat);
- copy_m4_m4(brushOb->imat_ren, brushOb->imat);
-
- /* Now process every material linked to this brush object */
- if ((ui_mat == NULL) && brushOb->mat && brushOb->totcol) {
- int i, tot = (*give_totcolp(brushOb));
-
- /* allocate material pointer array */
- if (tot) {
- bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials");
- for (i = 0; i < tot; i++) {
- bMats->ob_mats[i] = RE_sample_material_init(give_current_material(brushOb, (i + 1)), scene);
- }
- }
- bMats->tot = tot;
- }
- else {
- bMats->mat = RE_sample_material_init(ui_mat, scene);
- }
-}
-
-/* free all data allocated by dynamicPaint_updateBrushMaterials() */
-static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
-{
- /* Now process every material linked to this brush object */
- if (bMats->ob_mats) {
- int i;
- for (i = 0; i < bMats->tot; i++) {
- RE_sample_material_free(bMats->ob_mats[i]);
- }
- MEM_freeN(bMats->ob_mats);
- }
- else if (bMats->mat) {
- RE_sample_material_free(bMats->mat);
- }
-}
-
-/*
- * Get material diffuse color and alpha (including linked textures) in given coordinates
- */
-static void dynamicPaint_doMaterialTex(
- const BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
- const float volume_co[3], const float surface_co[3],
- int triIndex, DerivedMesh *orcoDm)
-{
- Material *mat = bMats->mat;
-
- const MLoopTri *mlooptri = orcoDm->getLoopTriArray(orcoDm);
- const MPoly *mpoly = orcoDm->getPolyArray(orcoDm);
-
- /* If no material defined, use the one assigned to the mesh face */
- if (mat == NULL) {
- if (bMats->ob_mats) {
- int mat_nr = mpoly[mlooptri[triIndex].poly].mat_nr;
- if (mat_nr >= (*give_totcolp(brushOb)))
- return;
- mat = bMats->ob_mats[mat_nr];
- if (mat == NULL)
- return; /* No material assigned */
- }
- else {
- return;
- }
- }
- RE_sample_material_color(mat, color, alpha, volume_co, surface_co, triIndex, orcoDm, brushOb);
-}
-
-
/***************************** Ray / Nearest Point Utils ******************************/
@@ -3746,11 +3655,11 @@ static void dynamic_paint_brush_velocity_compute_cb(
}
static void dynamicPaint_brushMeshCalculateVelocity(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
{
float prev_obmat[4][4];
- DerivedMesh *dm_p, *dm_c;
+ Mesh *mesh_p, *mesh_c;
MVert *mvert_p, *mvert_c;
int numOfVerts_p, numOfVerts_c;
@@ -3764,26 +3673,26 @@ static void dynamicPaint_brushMeshCalculateVelocity(
prev_fra = cur_fra - 1;
}
- /* previous frame dm */
+ /* previous frame mesh */
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- dm_p = CDDM_copy(brush->dm);
- numOfVerts_p = dm_p->getNumVerts(dm_p);
- mvert_p = dm_p->getVertArray(dm_p);
+ depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ mesh_p = BKE_mesh_copy_for_eval(brush->mesh, false);
+ numOfVerts_p = mesh_p->totvert;
+ mvert_p = mesh_p->mvert;
copy_m4_m4(prev_obmat, ob->obmat);
- /* current frame dm */
+ /* current frame mesh */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- dm_c = brush->dm;
- numOfVerts_c = dm_c->getNumVerts(dm_c);
- mvert_c = dm_p->getVertArray(dm_c);
+ depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ mesh_c = brush->mesh;
+ numOfVerts_c = mesh_c->totvert;
+ mvert_c = mesh_c->mvert;
(*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
if (!(*brushVel))
@@ -3807,12 +3716,12 @@ static void dynamicPaint_brushMeshCalculateVelocity(
dynamic_paint_brush_velocity_compute_cb,
&settings);
- dm_p->release(dm_p);
+ BKE_id_free(NULL, mesh_p);
}
/* calculate velocity for object center point */
static void dynamicPaint_brushObjectCalculateVelocity(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
{
float prev_obmat[4][4];
float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
@@ -3827,18 +3736,18 @@ static void dynamicPaint_brushObjectCalculateVelocity(
prev_fra = cur_fra - 1;
}
- /* previous frame dm */
+ /* previous frame mesh */
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
copy_m4_m4(prev_obmat, ob->obmat);
- /* current frame dm */
+ /* current frame mesh */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
/* calculate speed */
mul_m4_v3(prev_obmat, prev_loc);
@@ -3852,12 +3761,11 @@ typedef struct DynamicPaintPaintData {
const DynamicPaintSurface *surface;
const DynamicPaintBrushSettings *brush;
Object *brushOb;
- const BrushMaterials *bMats;
const Scene *scene;
const float timescale;
const int c_index;
- DerivedMesh *dm;
+ Mesh *mesh;
const MVert *mvert;
const MLoop *mloop;
const MLoopTri *mlooptri;
@@ -3889,14 +3797,10 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
VolumeGrid *grid = bData->grid;
const DynamicPaintBrushSettings *brush = data->brush;
- Object *brushOb = data->brushOb;
- const BrushMaterials *bMats = data->bMats;
- const Scene *scene = data->scene;
const float timescale = data->timescale;
const int c_index = data->c_index;
- DerivedMesh *dm = data->dm;
const MVert *mvert = data->mvert;
const MLoop *mloop = data->mloop;
const MLoopTri *mlooptri = data->mlooptri;
@@ -4156,13 +4060,6 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
sampleColor[1] = brush->g;
sampleColor[2] = brush->b;
- /* Get material+textures color on hit point if required */
- if (brush_usesMaterial(brush, scene)) {
- dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index] + ss].v,
- hitCoord, hitTri, dm);
- }
-
/* Sample proximity colorband if required */
if ((hit_found == HIT_PROXIMITY) &&
(brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP))
@@ -4210,27 +4107,24 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
}
}
-static int dynamicPaint_paintMesh(Main *bmain,
- EvaluationContext *eval_ctx,
- DynamicPaintSurface *surface,
+static int dynamicPaint_paintMesh(Depsgraph *depsgraph, DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
- BrushMaterials *bMats,
Scene *scene,
float timescale)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
Vec3f *brushVelocity = NULL;
MVert *mvert = NULL;
const MLoopTri *mlooptri = NULL;
const MLoop *mloop = NULL;
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushMeshCalculateVelocity(bmain, eval_ctx, scene, brushOb, brush, &brushVelocity, timescale);
+ dynamicPaint_brushMeshCalculateVelocity(depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
- if (!brush->dm)
+ if (!brush->mesh)
return 0;
{
@@ -4242,11 +4136,11 @@ static int dynamicPaint_paintMesh(Main *bmain,
Bounds3D mesh_bb = {{0}};
VolumeGrid *grid = bData->grid;
- dm = CDDM_copy(brush->dm);
- mvert = dm->getVertArray(dm);
- mlooptri = dm->getLoopTriArray(dm);
- mloop = dm->getLoopArray(dm);
- numOfVerts = dm->getNumVerts(dm);
+ mesh = BKE_mesh_copy_for_eval(brush->mesh, false);
+ mvert = mesh->mvert;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ mloop = mesh->mloop;
+ numOfVerts = mesh->totvert;
/* Transform collider vertices to global space
* (Faster than transforming per surface point
@@ -4277,7 +4171,7 @@ static int dynamicPaint_paintMesh(Main *bmain,
/* check bounding box collision */
if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
/* Build a bvh tree from transformed vertices */
- if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) {
+ if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRI, 4)) {
int c_index;
int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
@@ -4293,9 +4187,9 @@ static int dynamicPaint_paintMesh(Main *bmain,
/* loop through cell points and process brush */
DynamicPaintPaintData data = {
.surface = surface,
- .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .brush = brush, .brushOb = brushOb,
.scene = scene, .timescale = timescale, .c_index = c_index,
- .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
+ .mesh = mesh, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
.brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
.treeData = &treeData
};
@@ -4311,7 +4205,7 @@ static int dynamicPaint_paintMesh(Main *bmain,
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
- dm->release(dm);
+ BKE_id_free(NULL, mesh);
}
@@ -4618,13 +4512,9 @@ static void dynamic_paint_paint_single_point_cb_ex(
const PaintBakeData *bData = sData->bData;
const DynamicPaintBrushSettings *brush = data->brush;
- Object *brushOb = data->brushOb;
- const BrushMaterials *bMats = data->bMats;
- const Scene *scene = data->scene;
const float timescale = data->timescale;
- const MVert *mvert = data->mvert;
const float brush_radius = data->brush_radius;
const Vec3f *brushVelocity = data->brushVelocity;
@@ -4653,17 +4543,6 @@ static void dynamic_paint_paint_single_point_cb_ex(
float depth = 0.0f;
float velocity_val = 0.0f;
- /* material */
- if (brush_usesMaterial(brush, scene)) {
- float alpha_factor = 1.0f;
- float hit_coord[3];
- /* use dummy coord of first vertex */
- mul_v3_m4v3(hit_coord, brushOb->obmat, mvert[0].co);
-
- dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
- }
-
/* color ramp */
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband))
@@ -4701,11 +4580,9 @@ static void dynamic_paint_paint_single_point_cb_ex(
paintColor[2] = colorband[2];
}
else {
- if (!brush_usesMaterial(brush, scene)) {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
}
}
else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
@@ -4718,24 +4595,24 @@ static void dynamic_paint_paint_single_point_cb_ex(
}
static int dynamicPaint_paintSinglePoint(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
- Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+ Depsgraph *depsgraph, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
+ Object *brushOb, Scene *scene, float timescale)
{
PaintSurfaceData *sData = surface->data;
float brush_radius = brush->paint_distance * surface->radius_scale;
Vec3f brushVel;
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushObjectCalculateVelocity(bmain, eval_ctx, scene, brushOb, &brushVel, timescale);
+ dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
- const MVert *mvert = brush->dm->getVertArray(brush->dm);
+ const MVert *mvert = brush->mesh->mvert;
/*
* Loop through every surface point
*/
DynamicPaintPaintData data = {
.surface = surface,
- .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .brush = brush, .brushOb = brushOb,
.scene = scene, .timescale = timescale,
.mvert = mvert,
.brush_radius = brush_radius, .brushVelocity = &brushVel,
@@ -5019,7 +4896,7 @@ static void dynamic_paint_prepare_effect_cb(
EffectedPoint epoint;
pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
epoint.vel_to_sec = 1.0f;
- pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
}
/* if global gravity is enabled, add it too */
@@ -5048,7 +4925,7 @@ static void dynamic_paint_prepare_effect_cb(
}
static int dynamicPaint_prepareEffectStep(
- DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
+ struct Depsgraph *depsgraph, DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
{
double average_force = 0.0f;
float shrink_speed = 0.0f, spread_speed = 0.0f;
@@ -5059,7 +4936,7 @@ static int dynamicPaint_prepareEffectStep(
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, surface->effector_weights);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
@@ -5083,7 +4960,7 @@ static int dynamicPaint_prepareEffectStep(
}
average_force /= sData->total_points;
}
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
/* Get number of required steps using average point distance
@@ -5747,10 +5624,10 @@ static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *o
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- DerivedMesh *dm = surface->canvas->dm;
- MVert *mvert = dm->getVertArray(dm);
+ Mesh *mesh = surface->canvas->mesh;
+ MVert *mvert = mesh->mvert;
- int numOfVerts = dm->getNumVerts(dm);
+ int numOfVerts = mesh->totvert;
int i;
if (!bData->prev_verts)
@@ -5891,19 +5768,19 @@ static void dynamic_paint_generate_bake_data_cb(
}
}
-static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
+static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Depsgraph *depsgraph, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- DerivedMesh *dm = surface->canvas->dm;
+ Mesh *mesh = surface->canvas->mesh;
int index;
bool new_bdata = false;
const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
- (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY));
+ (surface_getBrushFlags(surface, depsgraph) & BRUSH_USES_VELOCITY));
const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
- int canvasNumOfVerts = dm->getNumVerts(dm);
- MVert *mvert = dm->getVertArray(dm);
+ int canvasNumOfVerts = mesh->totvert;
+ MVert *mvert = mesh->mvert;
Vec3f *canvas_verts;
if (bData) {
@@ -6017,12 +5894,13 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
* Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface.
*/
static int dynamicPaint_doStep(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
int ret = 1;
if (sData->total_points < 1)
@@ -6043,50 +5921,23 @@ static int dynamicPaint_doStep(
* Loop through surface's target paint objects and do painting
*/
{
- Base *base = NULL;
- GroupObject *go = NULL;
- Object *brushObj = NULL;
- ModifierData *md = NULL;
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
/* backup current scene frame */
int scene_frame = scene->r.cfra;
float scene_subframe = scene->r.subframe;
- /* either from group or from all objects */
- if (surface->brush_group)
- go = surface->brush_group->gobject.first;
- else
- base = scene->base.first;
-
- while (base || go) {
- brushObj = NULL;
- /* select object */
- if (surface->brush_group) {
- if (go->ob)
- brushObj = go->ob;
- }
- else
- brushObj = base->object;
-
- /* next item */
- if (surface->brush_group)
- go = go->next;
- else
- base = base->next;
-
- if (!brushObj) {
- /* skip item */
- continue;
- }
+ for (int i = 0; i < numobjects; i++) {
+ Object *brushObj = objects[i];
/* check if target has an active dp modifier */
- md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
/* make sure we're dealing with a brush */
if (pmd2->brush) {
DynamicPaintBrushSettings *brush = pmd2->brush;
- BrushMaterials bMats = {NULL};
/* calculate brush speed vectors if required */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
@@ -6101,44 +5952,35 @@ static int dynamicPaint_doStep(
/* update object data on this subframe */
if (subframe) {
scene_setSubframe(scene, subframe);
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
- /* Prepare materials if required */
- if (brush_usesMaterial(brush, scene))
- dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats);
+
/* Apply brush on the surface depending on it's collision type */
- /* Particle brush: */
- if (brush->collision == MOD_DPAINT_COL_PSYS) {
- if (brush->psys && brush->psys->part &&
- ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
- psys_check_enabled(brushObj, brush->psys, G.is_rendering))
- {
- /* Paint a particle system */
- BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt,
- BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
- dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
- }
+ if (brush->psys && brush->psys->part &&
+ ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ psys_check_enabled(brushObj, brush->psys, for_render))
+ {
+ /* Paint a particle system */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &brush->psys->part->id, brush->psys->part->adt,
+ BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
+ dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
}
/* Object center distance: */
- else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
- dynamicPaint_paintSinglePoint(
- bmain, eval_ctx, surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale);
+ if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
+ dynamicPaint_paintSinglePoint(depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
}
/* Mesh volume/proximity: */
else if (brushObj != ob) {
- dynamicPaint_paintMesh(bmain, eval_ctx, surface, brush, brushObj, &bMats, scene, timescale);
+ dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
}
- /* free temp material data */
- if (brush_usesMaterial(brush, scene))
- dynamicPaint_freeBrushMaterials(&bMats);
/* reset object to it's original state */
if (subframe) {
scene->r.cfra = scene_frame;
scene->r.subframe = scene_subframe;
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
@@ -6152,6 +5994,8 @@ static int dynamicPaint_doStep(
}
}
}
+
+ BKE_collision_objects_free(objects);
}
/* surfaces operations that use adjacency data */
@@ -6173,7 +6017,7 @@ static int dynamicPaint_doStep(
return setError(canvas, N_("Not enough free memory"));
/* Prepare effects and get number of required steps */
- steps = dynamicPaint_prepareEffectStep(surface, scene, ob, &force, timescale);
+ steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
for (s = 0; s < steps; s++) {
dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
}
@@ -6198,16 +6042,17 @@ static int dynamicPaint_doStep(
* Calculate a single frame and included subframes for surface
*/
int dynamicPaint_calculateFrame(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame)
+ DynamicPaintSurface *surface, struct Depsgraph *depsgraph,
+ Scene *scene, Object *cObject, int frame)
{
float timescale = 1.0f;
/* apply previous displace on derivedmesh if incremental surface */
if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL)
- dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
+ dynamicPaint_applySurfaceDisplace(surface, surface->canvas->mesh);
/* update bake data */
- dynamicPaint_generateBakeData(surface, scene, cObject);
+ dynamicPaint_generateBakeData(surface, depsgraph, cObject);
/* don't do substeps for first frame */
if (surface->substeps && (frame != surface->start_frame)) {
@@ -6216,10 +6061,10 @@ int dynamicPaint_calculateFrame(
for (st = 1; st <= surface->substeps; st++) {
float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(bmain, eval_ctx, scene, cObject, surface, timescale, subframe))
+ if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe))
return 0;
}
}
- return dynamicPaint_doStep(bmain, eval_ctx, scene, cObject, surface, timescale, 0.0f);
+ return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
}
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index db9ce6c9b7d..e6873e66c91 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -49,2290 +49,20 @@
#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_editmesh_tangent.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "MEM_guardedalloc.h"
-#include "GPU_glew.h"
-#include "GPU_buffers.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
-static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4]);
-
-typedef struct EditDerivedBMesh {
- DerivedMesh dm;
-
- BMEditMesh *em;
-
- /** when set, \a vertexNos, polyNos are lazy initialized */
- const float (*vertexCos)[3];
-
- /** lazy initialize (when \a vertexCos is set) */
- float const (*vertexNos)[3];
- float const (*polyNos)[3];
- /** also lazy init but dont depend on \a vertexCos */
- const float (*polyCos)[3];
-} EditDerivedBMesh;
-
-/* -------------------------------------------------------------------- */
-/* Lazy initialize datastructures */
-
-static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm);
-
-static void emDM_ensureVertNormals(EditDerivedBMesh *bmdm)
-{
- if (bmdm->vertexCos && (bmdm->vertexNos == NULL)) {
-
- BMesh *bm = bmdm->em->bm;
- const float (*vertexCos)[3], (*polyNos)[3];
- float (*vertexNos)[3];
-
- /* calculate vertex normals from poly normals */
- emDM_ensurePolyNormals(bmdm);
-
- BM_mesh_elem_index_ensure(bm, BM_FACE);
-
- polyNos = bmdm->polyNos;
- vertexCos = bmdm->vertexCos;
- vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__);
-
- BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos);
-
- bmdm->vertexNos = (const float (*)[3])vertexNos;
- }
-}
-
-static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm)
-{
- if (bmdm->vertexCos && (bmdm->polyNos == NULL)) {
- BMesh *bm = bmdm->em->bm;
- const float (*vertexCos)[3];
- float (*polyNos)[3];
-
- BMFace *efa;
- BMIter fiter;
- int i;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__);
-
- vertexCos = bmdm->vertexCos;
-
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_elem_index_set(efa, i); /* set_inline */
- BM_face_calc_normal_vcos(bm, efa, polyNos[i], vertexCos);
- }
- bm->elem_index_dirty &= ~BM_FACE;
-
- bmdm->polyNos = (const float (*)[3])polyNos;
- }
-}
-
-static void emDM_ensurePolyCenters(EditDerivedBMesh *bmdm)
-{
- if (bmdm->polyCos == NULL) {
- BMesh *bm = bmdm->em->bm;
- float (*polyCos)[3];
-
- BMFace *efa;
- BMIter fiter;
- int i;
-
- polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__);
-
- if (bmdm->vertexCos) {
- const float (*vertexCos)[3];
- vertexCos = bmdm->vertexCos;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_face_calc_center_mean_vcos(bm, efa, polyCos[i], vertexCos);
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_face_calc_center_mean(efa, polyCos[i]);
- }
- }
-
- bmdm->polyCos = (const float (*)[3])polyCos;
- }
-}
-
-static void emDM_calcNormals(DerivedMesh *dm)
-{
- /* Nothing to do: normals are already calculated and stored on the
- * BMVerts and BMFaces */
- dm->dirty &= ~DM_DIRTY_NORMALS;
-}
-
-static void emDM_calcLoopNormalsSpaceArray(
- DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr);
-
-static void emDM_calcLoopNormals(DerivedMesh *dm, const bool use_split_normals, const float split_angle)
-{
- emDM_calcLoopNormalsSpaceArray(dm, use_split_normals, split_angle, NULL);
-}
-
-/* #define DEBUG_CLNORS */
-
-static void emDM_calcLoopNormalsSpaceArray(
- DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- const float (*vertexCos)[3], (*vertexNos)[3], (*polyNos)[3];
- float (*loopNos)[3];
- short (*clnors_data)[2];
- int cd_loop_clnors_offset;
-
- /* calculate loop normals from poly and vertex normals */
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- dm->dirty &= ~DM_DIRTY_NORMALS;
-
- vertexCos = bmdm->vertexCos;
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- loopNos = dm->getLoopDataArray(dm, CD_NORMAL);
- if (!loopNos) {
- DM_add_loop_layer(dm, CD_NORMAL, CD_CALLOC, NULL);
- loopNos = dm->getLoopDataArray(dm, CD_NORMAL);
- }
-
- /* We can have both, give priority to dm's data, and fallback to bm's ones. */
- clnors_data = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL);
- cd_loop_clnors_offset = clnors_data ? -1 : CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
-
- BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, use_split_normals, split_angle, loopNos,
- r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
-#ifdef DEBUG_CLNORS
- if (r_lnors_spacearr) {
- int i;
- for (i = 0; i < numLoops; i++) {
- if (r_lnors_spacearr->lspacearr[i]->ref_alpha != 0.0f) {
- LinkNode *loops = r_lnors_spacearr->lspacearr[i]->loops;
- printf("Loop %d uses lnor space %p:\n", i, r_lnors_spacearr->lspacearr[i]);
- print_v3("\tfinal lnor:", loopNos[i]);
- print_v3("\tauto lnor:", r_lnors_spacearr->lspacearr[i]->vec_lnor);
- print_v3("\tref_vec:", r_lnors_spacearr->lspacearr[i]->vec_ref);
- printf("\talpha: %f\n\tbeta: %f\n\tloops: %p\n", r_lnors_spacearr->lspacearr[i]->ref_alpha,
- r_lnors_spacearr->lspacearr[i]->ref_beta, r_lnors_spacearr->lspacearr[i]->loops);
- printf("\t\t(shared with loops");
- while (loops) {
- printf(" %d", POINTER_AS_INT(loops->link));
- loops = loops->next;
- }
- printf(")\n");
- }
- else {
- printf("Loop %d has no lnor space\n", i);
- }
- }
- }
-#endif
-}
-
-
-/** \name Tangent Space Calculation
- * \{ */
-
-/* Necessary complexity to handle looptri's as quads for correct tangents */
-#define USE_LOOPTRI_DETECT_QUADS
-
-typedef struct {
- const float (*precomputedFaceNormals)[3];
- const float (*precomputedLoopNormals)[3];
- const BMLoop *(*looptris)[3];
- int cd_loop_uv_offset; /* texture coordinates */
- const float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
-#endif
-
-} SGLSLEditMeshToTangent;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-/* seems weak but only used on quads */
-static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
-{
- const BMLoop *l = BM_FACE_FIRST_LOOP(f);
- while (vert_index--) {
- l = l->next;
- }
- return l;
-}
-#endif
-
-/* interface */
-#include "mikktspace.h"
-
-static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
-#else
- return pMesh->numTessFaces;
-#endif
-}
-
-static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- if (pMesh->face_as_quad_map) {
- const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- return 4;
- }
- }
- return 3;
-#else
- UNUSED_VARS(pContext, face_num);
- return 3;
-#endif
-}
-
-static void emdm_ts_GetPosition(
- const SMikkTSpaceContext *pContext, float r_co[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
- const float *co;
-
-finally:
- co = l->v->co;
- copy_v3_v3(r_co, co);
-}
-
-static void emdm_ts_GetTextureCoordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
-finally:
- if (pMesh->cd_loop_uv_offset != -1) {
- const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
-}
-
-static void emdm_ts_GetNormal(
- const SMikkTSpaceContext *pContext, float r_no[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
-finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
- }
- else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
- }
- else {
- copy_v3_v3(r_no, l->f->no);
- }
- }
- else {
- copy_v3_v3(r_no, l->v->no);
- }
-}
-
-static void emdm_ts_SetTSpace(
- const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
- float *pRes;
-
-finally:
- pRes = pMesh->tangent[BM_elem_index_get(l)];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
-}
-
-static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
- /* new computation method */
- {
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = emdm_ts_GetPosition;
- sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = emdm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
-}
-
-/**
- * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
- *
- * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
- * This is done because #CD_TANGENT is cache data used only for drawing.
- */
-
-static void emDM_calc_loop_tangents(
- DerivedMesh *dm, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = bmdm->em->bm;
-
- int act_uv_n = -1;
- int ren_uv_n = -1;
- bool calc_act = false;
- bool calc_ren = false;
- char act_uv_name[MAX_NAME];
- char ren_uv_name[MAX_NAME];
- short tangent_mask = 0;
-
- DM_calc_loop_tangents_step_0(
- &bm->ldata, calc_active_tangent, tangent_names, tangent_names_count,
- &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
-
- if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
- for (int i = 0; i < tangent_names_count; i++)
- if (tangent_names[i][0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]);
- if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1)
- CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, "");
- if (calc_act && act_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name);
- if (calc_ren && ren_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name);
- int totface = em->tottri;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (bmdm->em->tottri != bm->totface) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
- int i, j;
- for (i = 0, j = 0; j < totface; i++, j++) {
- face_as_quad_map[i] = j;
- /* step over all quads */
- if (em->looptris[j][0]->f->len == 4) {
- j++; /* skips the nest looptri */
- }
- }
- num_face_as_quad_map = i;
- }
- else {
- num_face_as_quad_map = totface;
- }
-#endif
- /* Calculation */
- {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
-
- dm->tangent_mask = 0;
- /* Calculate tangent layers */
- SGLSLEditMeshToTangent data_array[MAX_MTFACE];
- int index = 0;
- int n = 0;
- CustomData_update_typemap(&dm->loopData);
- const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
- for (n = 0; n < tangent_layer_num; n++) {
- index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
- BLI_assert(n < MAX_MTFACE);
- SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
- mesh2tangent->numTessFaces = em->tottri;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent->face_as_quad_map = face_as_quad_map;
- mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
-#endif
- mesh2tangent->precomputedFaceNormals = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL);
- mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
-
- /* needed for indexing loop-tangents */
- int htype_index = BM_LOOP;
- if (mesh2tangent->cd_loop_uv_offset == -1) {
- mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!mesh2tangent->orco)
- continue;
- /* needed for orco lookups */
- htype_index |= BM_VERT;
- dm->tangent_mask |= DM_TANGENT_MASK_ORCO;
- }
- else {
- /* Fill the resulting tangent_mask */
- int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
- int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- dm->tangent_mask |= 1 << (uv_ind - uv_start);
- }
-
- if (mesh2tangent->precomputedFaceNormals) {
- /* needed for face normal lookups */
- htype_index |= BM_FACE;
- }
- BM_mesh_elem_index_ensure(bm, htype_index);
-
- mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
- mesh2tangent->tangent = dm->loopData.layers[index].data;
-
- BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
- }
-
- BLI_assert(dm->tangent_mask == tangent_mask);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- }
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (face_as_quad_map) {
- MEM_freeN(face_as_quad_map);
- }
-#undef USE_LOOPTRI_DETECT_QUADS
-#endif
- }
-
- /* Update active layer index */
- int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
- if (act_uv_index >= 0) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-
- /* Update render layer index */
- int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
- if (ren_uv_index >= 0) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-}
-
-/** \} */
-
-
-static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
-{
- /* do nothing */
-}
-
-static void emDM_recalcLoopTri(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMLoop *(*looptris)[3] = bmdm->em->looptris;
- MLoopTri *mlooptri;
- const int tottri = bmdm->em->tottri;
- int i;
-
- DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array_wip;
-
- BLI_assert(tottri == 0 || mlooptri != NULL);
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- BLI_assert(tottri == dm->looptris.num);
-
- BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP);
-
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- MLoopTri *lt = &mlooptri[i];
-
- ARRAY_SET_ITEMS(
- lt->tri,
- BM_elem_index_get(ltri[0]),
- BM_elem_index_get(ltri[1]),
- BM_elem_index_get(ltri[2]));
- lt->poly = BM_elem_index_get(ltri[0]->f);
- }
-
- BLI_assert(dm->looptris.array == NULL);
- atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip);
- dm->looptris.array_wip = NULL;
-}
-
-static void emDM_foreachMappedVert(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
- void *userData,
- DMForeachFlag flag)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *eve;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
-
- if (flag & DM_FOREACH_USE_NORMAL) {
- emDM_ensureVertNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- }
- else {
- vertexNos = NULL;
- }
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- const float *no = (flag & DM_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL;
- func(userData, i, vertexCos[i], no, NULL);
- }
- }
- else {
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- const float *no = (flag & DM_FOREACH_USE_NORMAL) ? eve->no : NULL;
- func(userData, i, eve->co, no, NULL);
- }
- }
-}
-static void emDM_foreachMappedEdge(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *eed;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- func(userData, i,
- bmdm->vertexCos[BM_elem_index_get(eed->v1)],
- bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
- }
- }
- else {
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- func(userData, i, eed->v1->co, eed->v2->co);
- }
- }
-}
-
-static void emDM_drawMappedEdges(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *eed;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
- }
- }
- glEnd();
- }
- else {
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(eed->v1->co);
- glVertex3fv(eed->v2->co);
- }
- }
- glEnd();
- }
-}
-static void emDM_drawEdges(
- DerivedMesh *dm,
- bool UNUSED(drawLooseEdges),
- bool UNUSED(drawAllEdges))
-{
- emDM_drawMappedEdges(dm, NULL, NULL);
-}
-
-static void emDM_drawMappedEdgesInterp(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetDrawInterpOptions setDrawInterpOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *eed;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]);
- setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
- }
- }
- glEnd();
- }
- else {
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(eed->v1->co);
- setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(eed->v2->co);
- }
- }
- glEnd();
- }
-}
-
-static void emDM_drawUVEdges(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMFace *efa;
- BMIter iter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- if (UNLIKELY(cd_loop_uv_offset == -1)) {
- return;
- }
-
- glBegin(GL_LINES);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- const float *uv, *uv_prev;
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
- continue;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter->prev, cd_loop_uv_offset))->uv;
- do {
- uv = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- glVertex2fv(uv);
- glVertex2fv(uv_prev);
- uv_prev = uv;
- } while ((l_iter = l_iter->next) != l_first);
- }
- glEnd();
-}
-
-static void emDM_foreachMappedLoop(
- DerivedMesh *dm,
- void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
- void *userData,
- DMForeachFlag flag)
-{
- /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
- * return loop data from bmesh itself. */
- const float (*lnors)[3] = (flag & DM_FOREACH_USE_NORMAL) ? DM_get_loop_data_layer(dm, CD_NORMAL) : NULL;
-
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMFace *efa;
- BMIter iter;
-
- const float (*vertexCos)[3] = bmdm->vertexCos;
- int f_idx;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) {
- BMLoop *l_iter, *l_first;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const BMVert *eve = l_iter->v;
- const int v_idx = BM_elem_index_get(eve);
- const float *no = lnors ? *lnors++ : NULL;
- func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no);
- } while ((l_iter = l_iter->next) != l_first);
- }
-}
-
-static void emDM_foreachMappedFaceCenter(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float co[3], const float no[3]),
- void *userData,
- DMForeachFlag flag)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- const float (*polyNos)[3];
- const float (*polyCos)[3];
- BMFace *efa;
- BMIter iter;
- int i;
-
- emDM_ensurePolyCenters(bmdm);
- polyCos = bmdm->polyCos; /* always set */
-
- if (flag & DM_FOREACH_USE_NORMAL) {
- emDM_ensurePolyNormals(bmdm);
- polyNos = bmdm->polyNos; /* maybe NULL */
- }
- else {
- polyNos = NULL;
- }
-
- if (polyNos) {
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
- const float *no = polyNos[i];
- func(userData, i, polyCos[i], no);
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
- const float *no = (flag & DM_FOREACH_USE_NORMAL) ? efa->no : NULL;
- func(userData, i, polyCos[i], no);
- }
- }
-}
-
-static void emDM_drawMappedFaces(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- /* currently unused -- each original face is handled separately */
- DMCompareDrawOptions UNUSED(compareDrawOptions),
- void *userData,
- DMDrawFlag flag)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- BMFace *efa;
- struct BMLoop *(*looptris)[3] = bmdm->em->looptris;
- const int tottri = bmdm->em->tottri;
- DMDrawOption draw_option;
- int i;
- const int skip_normals = !(flag & DM_DRAW_NEED_NORMALS);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */;
- unsigned char(*color_vert_array)[4] = em->derivedVertColor;
- unsigned char(*color_face_array)[4] = em->derivedFaceColor;
- bool has_vcol_preview = (color_vert_array != NULL) && !skip_normals;
- bool has_fcol_preview = (color_face_array != NULL) && !skip_normals;
- bool has_vcol_any = has_vcol_preview;
-
- /* GL_ZERO is used to detect if drawing has started or not */
- GLenum poly_prev = GL_ZERO;
- GLenum shade_prev = GL_ZERO;
- DMDrawOption draw_option_prev = DM_DRAW_OPTION_SKIP;
-
- /* call again below is ok */
- if (has_vcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
- if (has_fcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- }
- if (has_vcol_preview || has_fcol_preview) {
- flag |= DM_DRAW_ALWAYS_SMOOTH;
- /* weak, this logic should really be moved higher up */
- setMaterial = NULL;
- }
-
- if (bmdm->vertexCos) {
- short prev_mat_nr = -1;
-
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
-
- if (skip_normals) {
- vertexNos = NULL;
- polyNos = NULL;
- }
- else {
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
- }
-
- BM_mesh_elem_index_ensure(bm, lnors ? BM_VERT | BM_FACE | BM_LOOP : BM_VERT | BM_FACE);
-
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
- drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH));
-
- draw_option = (!setDrawOptions ?
- DM_DRAW_OPTION_NORMAL :
- setDrawOptions(userData, BM_elem_index_get(efa)));
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
-
- if (draw_option_prev != draw_option) {
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- draw_option_prev = draw_option;
- }
-
-
- if (efa->mat_nr != prev_mat_nr) {
- if (setMaterial) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- setMaterial(efa->mat_nr + 1, NULL);
- }
- prev_mat_nr = efa->mat_nr;
- }
-
- if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
-
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
- else if (has_fcol_preview) glColor3ubv((const GLubyte *)&(color_face_array[BM_elem_index_get(efa)]));
- if (skip_normals) {
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- const GLenum shade_type = drawSmooth ? GL_SMOOTH : GL_FLAT;
- if (shade_type != shade_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glShadeModel((shade_prev = shade_type)); /* same as below but switch shading */
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
-
- if (!drawSmooth) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- }
- }
- }
- }
- else {
- short prev_mat_nr = -1;
-
- BM_mesh_elem_index_ensure(bm, lnors ? BM_FACE | BM_LOOP : BM_FACE);
-
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
- drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH));
-
- draw_option = (setDrawOptions ?
- setDrawOptions(userData, BM_elem_index_get(efa)) :
- DM_DRAW_OPTION_NORMAL);
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
-
- if (draw_option_prev != draw_option) {
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- draw_option_prev = draw_option;
- }
-
- if (efa->mat_nr != prev_mat_nr) {
- if (setMaterial) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- setMaterial(efa->mat_nr + 1, NULL);
- }
- prev_mat_nr = efa->mat_nr;
- }
-
- if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
-
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
- else if (has_fcol_preview) glColor3ubv((const GLubyte *)&(color_face_array[BM_elem_index_get(efa)]));
-
- if (skip_normals) {
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- const GLenum shade_type = drawSmooth ? GL_SMOOTH : GL_FLAT;
- if (shade_type != shade_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glShadeModel((shade_prev = shade_type)); /* same as below but switch shading */
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
-
- if (!drawSmooth) {
- glNormal3fv(efa->no);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(ltri[0]->v->no);
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(ltri[1]->v->no);
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(ltri[2]->v->no);
- glVertex3fv(ltri[2]->v->co);
- }
- }
- }
- }
- }
-
- /* if non zero we know a face was rendered */
- if (poly_prev != GL_ZERO) glEnd();
-
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
-
- if (shade_prev == GL_FLAT) {
- glShadeModel(GL_SMOOTH);
- }
-}
-
-static void bmdm_get_tri_uv(BMLoop *ltri[3], MLoopUV *luv[3], const int cd_loop_uv_offset)
-{
- luv[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_uv_offset);
- luv[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_uv_offset);
- luv[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_uv_offset);
-}
-
-static void bmdm_get_tri_col(BMLoop *ltri[3], MLoopCol *lcol[3], const int cd_loop_color_offset)
-{
- lcol[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_color_offset);
- lcol[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_color_offset);
- lcol[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_color_offset);
-}
-
-static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4])
-{
- lcol[0] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[0]->v)];
- lcol[1] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[1]->v)];
- lcol[2] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[2]->v)];
-}
-
-static void emDM_drawFacesTex_common(
- DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- BMFace *efa;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- MLoopUV *luv[3], dummyluv = {{0}};
- MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
- unsigned char(*color_vert_array)[4] = em->derivedVertColor;
- bool has_uv = (cd_loop_uv_offset != -1);
- bool has_vcol_preview = (color_vert_array != NULL);
- bool has_vcol = (cd_loop_color_offset != -1) && (has_vcol_preview == false);
- bool has_vcol_any = (has_vcol_preview || has_vcol);
- int i;
-
- (void) compareDrawOptions;
-
- luv[0] = luv[1] = luv[2] = &dummyluv;
-
- // dummylcol.r = dummylcol.g = dummylcol.b = dummylcol.a = 255; /* UNUSED */
-
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- BM_mesh_elem_index_ensure(bm, BM_FACE);
-
- /* call again below is ok */
- if (has_vcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- if (bmdm->vertexCos) {
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT);
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL;
- /*unsigned char *cp = NULL;*/ /*UNUSED*/
- int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH);
- DMDrawOption draw_option;
-
- efa = ltri[0]->f;
-
- if (drawParams) {
- draw_option = drawParams(tp, has_vcol, efa->mat_nr);
- }
- else if (drawParamsMapped)
- draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr);
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
-
- if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset);
- if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset);
- else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
-
- glBegin(GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
-
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- glEnd();
- }
- }
- }
- else {
- BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT);
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL;
- /*unsigned char *cp = NULL;*/ /*UNUSED*/
- int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH);
- DMDrawOption draw_option;
-
- efa = ltri[0]->f;
-
- if (drawParams)
- draw_option = drawParams(tp, has_vcol, efa->mat_nr);
- else if (drawParamsMapped)
- draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr);
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
-
- if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset);
- if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset);
- else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
-
- glBegin(GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(efa->no);
-
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(ltri[0]->v->no);
- glVertex3fv(ltri[0]->v->co);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(ltri[1]->v->no);
- glVertex3fv(ltri[1]->v->co);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(ltri[2]->v->no);
- glVertex3fv(ltri[2]->v->co);
- }
- glEnd();
- }
- }
- }
-}
-
-static void emDM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag UNUSED(flag))
-{
- emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
-}
-
-static void emDM_drawMappedFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag UNUSED(flag))
-{
- emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
-}
-
-/**
- * \note
- *
- * For UV's:
- * const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, attribs->tface[i].em_offset);
- *
- * This is intentionally different to calling:
- * CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, i);
- *
- * ... because the material may use layer names to select different UV's
- * see: [#34378]
- */
-static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop)
-{
- BMVert *eve = loop->v;
- int i;
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- if (attribs->totorco) {
- int index = BM_elem_index_get(eve);
- const float *orco = (attribs->orco.array) ? attribs->orco.array[index] : zero;
-
- if (attribs->orco.gl_texco)
- glTexCoord3fv(orco);
- else
- glVertexAttrib3fv(attribs->orco.gl_index, orco);
- }
- for (i = 0; i < attribs->tottface; i++) {
- const float *uv;
-
- if (attribs->tface[i].em_offset != -1) {
- const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, attribs->tface[i].em_offset);
- uv = luv->uv;
- }
- else {
- uv = zero;
- }
-
- if (attribs->tface[i].gl_texco)
- glTexCoord2fv(uv);
- else
- glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
- }
- for (i = 0; i < attribs->totmcol; i++) {
- float col[4];
- if (attribs->mcol[i].em_offset != -1) {
- const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset);
- rgba_uchar_to_float(col, &cp->r);
- }
- else {
- col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f;
- }
- glVertexAttrib4fv(attribs->mcol[i].gl_index, col);
- }
-
- for (i = 0; i < attribs->tottang; i++) {
- const float *tang;
- if (attribs->tang[i].em_offset != -1) {
- tang = attribs->tang[i].array[BM_elem_index_get(loop)];
- }
- else {
- tang = zero;
- }
- glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
- }
-}
-
-static void emDM_drawMappedFacesGLSL(
- DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-
- BMFace *efa;
- DMVertexAttribs attribs;
- GPUVertexAttribs gattribs;
-
- int i, matnr, new_matnr, fi;
- bool do_draw;
-
- do_draw = false;
- matnr = -1;
-
- memset(&attribs, 0, sizeof(attribs));
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
-
- if (setDrawOptions && (setDrawOptions(userData, BM_elem_index_get(efa)) == DM_DRAW_OPTION_SKIP))
- continue;
-
- /* material */
- new_matnr = efa->mat_nr + 1;
- if (new_matnr != matnr) {
- if (matnr != -1)
- glEnd();
-
- do_draw = setMaterial(matnr = new_matnr, &gattribs);
- if (do_draw) {
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
- if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
- }
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- if (do_draw) {
-
- /* draw face */
- drawSmooth = lnors || BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
-
- if (!drawSmooth) {
- if (vertexCos) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
- }
- }
- else {
- glNormal3fv(efa->no);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- else {
- if (vertexCos) {
- for (fi = 0; fi < 3; fi++) {
- const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(vertexNos[j]);
- glVertex3fv(vertexCos[j]);
- }
- }
- else {
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(ltri[fi]->v->no);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- }
- }
-
- if (matnr != -1) {
- glEnd();
- }
-}
-
-static void emDM_drawFacesGLSL(
- DerivedMesh *dm,
- int (*setMaterial)(int matnr, void *attribs))
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-static void emDM_drawMappedFacesMat(
- DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- BMFace *efa;
- DMVertexAttribs attribs = {{{NULL}}};
- GPUVertexAttribs gattribs;
- int i, matnr, new_matnr, fi;
-
- matnr = -1;
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
-
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
-
- /* face hiding */
- if (setFace && !setFace(userData, BM_elem_index_get(efa)))
- continue;
-
- /* material */
- new_matnr = efa->mat_nr + 1;
- if (new_matnr != matnr) {
- if (matnr != -1)
- glEnd();
-
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- /* draw face */
- drawSmooth = lnors || BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
-
- if (!drawSmooth) {
- if (vertexCos) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
- }
- }
- else {
- glNormal3fv(efa->no);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- else {
- if (vertexCos) {
- for (fi = 0; fi < 3; fi++) {
- const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(vertexNos[j]);
- glVertex3fv(vertexCos[j]);
- }
- }
- else {
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(ltri[fi]->v->no);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- }
-
- if (matnr != -1) {
- glEnd();
- }
-}
-
-static void emDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *eve;
- BMIter iter;
- int i;
-
- if (bm->totvert) {
- if (bmdm->vertexCos) {
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- minmax_v3v3_v3(r_min, r_max, bmdm->vertexCos[i]);
- }
- }
- else {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- minmax_v3v3_v3(r_min, r_max, eve->co);
- }
- }
- }
- else {
- zero_v3(r_min);
- zero_v3(r_max);
- }
-}
-static int emDM_getNumVerts(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->bm->totvert;
-}
-
-static int emDM_getNumEdges(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->bm->totedge;
-}
-
-static int emDM_getNumTessFaces(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->tottri;
-}
-
-static int emDM_getNumLoops(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->bm->totloop;
-}
-
-static int emDM_getNumPolys(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->bm->totface;
-}
-
-static void bmvert_to_mvert(BMesh *bm, BMVert *ev, MVert *r_vert)
-{
- const float *f;
-
- copy_v3_v3(r_vert->co, ev->co);
-
- normal_float_to_short_v3(r_vert->no, ev->no);
-
- r_vert->flag = BM_vert_flag_to_mflag(ev);
-
- if ((f = CustomData_bmesh_get(&bm->vdata, ev->head.data, CD_BWEIGHT))) {
- r_vert->bweight = (unsigned char)((*f) * 255.0f);
- }
-}
-
-static void emDM_getVert(DerivedMesh *dm, int index, MVert *r_vert)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *ev;
-
- if (UNLIKELY(index < 0 || index >= bm->totvert)) {
- BLI_assert(!"error in emDM_getVert");
- return;
- }
-
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- ev = bm->vtable[index]; /* should be BM_vert_at_index() */
- // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */
-
- bmvert_to_mvert(bm, ev, r_vert);
- if (bmdm->vertexCos)
- copy_v3_v3(r_vert->co, bmdm->vertexCos[index]);
-}
-
-static void emDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
-
- if (UNLIKELY(index < 0 || index >= bm->totvert)) {
- BLI_assert(!"error in emDM_getVertCo");
- return;
- }
-
- if (bmdm->vertexCos) {
- copy_v3_v3(r_co, bmdm->vertexCos[index]);
- }
- else {
- BMVert *ev;
-
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- ev = bm->vtable[index]; /* should be BM_vert_at_index() */
- // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */
- copy_v3_v3(r_co, ev->co);
- }
-}
-
-static void emDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
-
- if (UNLIKELY(index < 0 || index >= bm->totvert)) {
- BLI_assert(!"error in emDM_getVertNo");
- return;
- }
-
-
- if (bmdm->vertexCos) {
- emDM_ensureVertNormals(bmdm);
- copy_v3_v3(r_no, bmdm->vertexNos[index]);
- }
- else {
- BMVert *ev;
-
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- ev = bm->vtable[index]; /* should be BM_vert_at_index() */
- // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */
- copy_v3_v3(r_no, ev->no);
- }
-}
-
-static void emDM_getPolyNo(DerivedMesh *dm, int index, float r_no[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
-
- if (UNLIKELY(index < 0 || index >= bm->totface)) {
- BLI_assert(!"error in emDM_getPolyNo");
- return;
- }
-
- if (bmdm->vertexCos) {
- emDM_ensurePolyNormals(bmdm);
- copy_v3_v3(r_no, bmdm->polyNos[index]);
- }
- else {
- BMFace *efa;
-
- BLI_assert((bm->elem_table_dirty & BM_FACE) == 0);
- efa = bm->ftable[index]; /* should be BM_vert_at_index() */
- // efa = BM_face_at_index(bm, index); /* warning, does list loop, _not_ ideal */
- copy_v3_v3(r_no, efa->no);
- }
-}
-
-static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *r_edge)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *e;
- const float *f;
-
- if (UNLIKELY(index < 0 || index >= bm->totedge)) {
- BLI_assert(!"error in emDM_getEdge");
- return;
- }
-
- BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0);
- e = bm->etable[index]; /* should be BM_edge_at_index() */
- // e = BM_edge_at_index(bm, index); /* warning, does list loop, _not_ ideal */
-
- r_edge->flag = BM_edge_flag_to_mflag(e);
-
- r_edge->v1 = BM_elem_index_get(e->v1);
- r_edge->v2 = BM_elem_index_get(e->v2);
-
- if ((f = CustomData_bmesh_get(&bm->edata, e->head.data, CD_BWEIGHT))) {
- r_edge->bweight = (unsigned char)((*f) * 255.0f);
- }
- if ((f = CustomData_bmesh_get(&bm->edata, e->head.data, CD_CREASE))) {
- r_edge->crease = (unsigned char)((*f) * 255.0f);
- }
-}
-
-static void emDM_getTessFace(DerivedMesh *dm, int index, MFace *r_face)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMFace *ef;
- BMLoop **ltri;
-
- if (UNLIKELY(index < 0 || index >= bmdm->em->tottri)) {
- BLI_assert(!"error in emDM_getTessFace");
- return;
- }
-
- ltri = bmdm->em->looptris[index];
-
- ef = ltri[0]->f;
-
- r_face->mat_nr = (unsigned char) ef->mat_nr;
- r_face->flag = BM_face_flag_to_mflag(ef);
-
- r_face->v1 = BM_elem_index_get(ltri[0]->v);
- r_face->v2 = BM_elem_index_get(ltri[1]->v);
- r_face->v3 = BM_elem_index_get(ltri[2]->v);
- r_face->v4 = 0;
-
- test_index_face(r_face, NULL, 0, 3);
-}
-
-static void emDM_copyVertArray(DerivedMesh *dm, MVert *r_vert)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *eve;
- BMIter iter;
- const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
-
- if (bmdm->vertexCos) {
- int i;
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(r_vert->co, bmdm->vertexCos[i]);
- normal_float_to_short_v3(r_vert->no, eve->no);
- r_vert->flag = BM_vert_flag_to_mflag(eve);
-
- r_vert->bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset) : 0;
-
- r_vert++;
- }
- }
- else {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- copy_v3_v3(r_vert->co, eve->co);
- normal_float_to_short_v3(r_vert->no, eve->no);
- r_vert->flag = BM_vert_flag_to_mflag(eve);
-
- r_vert->bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset) : 0;
-
- r_vert++;
- }
- }
-}
-
-static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *r_edge)
-{
- BMesh *bm = ((EditDerivedBMesh *)dm)->em->bm;
- BMEdge *eed;
- BMIter iter;
-
- const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
- const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- r_edge->v1 = BM_elem_index_get(eed->v1);
- r_edge->v2 = BM_elem_index_get(eed->v2);
-
- r_edge->flag = BM_edge_flag_to_mflag(eed);
-
- r_edge->crease = (cd_edge_crease_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset) : 0;
- r_edge->bweight = (cd_edge_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset) : 0;
-
- r_edge++;
- }
-}
-
-static void emDM_copyTessFaceArray(DerivedMesh *dm, MFace *r_face)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- struct BMLoop *(*looptris)[3] = bmdm->em->looptris;
- BMFace *ef;
- int i;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- for (i = 0; i < bmdm->em->tottri; i++, r_face++) {
- BMLoop **ltri = looptris[i];
- ef = ltri[0]->f;
-
- r_face->mat_nr = (unsigned char) ef->mat_nr;
-
- r_face->flag = BM_face_flag_to_mflag(ef);
- r_face->edcode = 0;
-
- r_face->v1 = BM_elem_index_get(ltri[0]->v);
- r_face->v2 = BM_elem_index_get(ltri[1]->v);
- r_face->v3 = BM_elem_index_get(ltri[2]->v);
- r_face->v4 = 0;
-
- test_index_face(r_face, NULL, 0, 3);
- }
-}
-
-static void emDM_copyLoopArray(DerivedMesh *dm, MLoop *r_loop)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMIter iter;
- BMFace *efa;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- r_loop->v = BM_elem_index_get(l_iter->v);
- r_loop->e = BM_elem_index_get(l_iter->e);
- r_loop++;
- } while ((l_iter = l_iter->next) != l_first);
- }
-}
-
-static void emDM_copyPolyArray(DerivedMesh *dm, MPoly *r_poly)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMIter iter;
- BMFace *efa;
- int i;
-
- i = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- r_poly->flag = BM_face_flag_to_mflag(efa);
- r_poly->loopstart = i;
- r_poly->totloop = efa->len;
- r_poly->mat_nr = efa->mat_nr;
-
- r_poly++;
- i += efa->len;
- }
-}
-
-static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- void *datalayer;
-
- datalayer = DM_get_tessface_data_layer(dm, type);
- if (datalayer)
- return datalayer;
-
- /* layers are store per face for editmesh, we convert to a temporary
- * data layer array in the derivedmesh when these are requested */
- if (type == CD_MTFACE || type == CD_MCOL) {
- const char *bmdata;
- char *data;
- bool has_type_source = false;
-
- if (type == CD_MTFACE) {
- has_type_source = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY);
- }
- else {
- has_type_source = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL);
- }
-
- if (has_type_source) {
- /* offset = bm->pdata.layers[index].offset; */ /* UNUSED */
- BMLoop *(*looptris)[3] = bmdm->em->looptris;
- const int size = CustomData_sizeof(type);
- int i, j;
-
- DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
- const int index = CustomData_get_layer_index(&dm->faceData, type);
- dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
-
- data = datalayer = DM_get_tessface_data_layer(dm, type);
-
- if (type == CD_MTFACE) {
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
-
- for (i = 0; i < bmdm->em->tottri; i++, data += size) {
- BMFace *efa = looptris[i][0]->f;
-
- // bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY);
- bmdata = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- ME_MTEXFACE_CPY(((MTFace *)data), ((const MTexPoly *)bmdata));
- for (j = 0; j < 3; j++) {
- // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPUV);
- bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_uv_offset);
- copy_v2_v2(((MTFace *)data)->uv[j], ((const MLoopUV *)bmdata)->uv);
- }
- }
- }
- else {
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- for (i = 0; i < bmdm->em->tottri; i++, data += size) {
- for (j = 0; j < 3; j++) {
- // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPCOL);
- bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_color_offset);
- MESH_MLOOPCOL_TO_MCOL(((const MLoopCol *)bmdata), (((MCol *)data) + j));
- }
- }
- }
- }
- }
-
- /* Special handling for CD_TESSLOOPNORMAL, we generate it on demand as well. */
- if (type == CD_TESSLOOPNORMAL) {
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-
- if (lnors) {
- BMLoop *(*looptris)[3] = bmdm->em->looptris;
- short (*tlnors)[4][3], (*tlnor)[4][3];
- int index, i, j;
-
- DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
- index = CustomData_get_layer_index(&dm->faceData, type);
- dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
-
- tlnor = tlnors = DM_get_tessface_data_layer(dm, type);
-
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
-
- for (i = 0; i < bmdm->em->tottri; i++, tlnor++, looptris++) {
- for (j = 0; j < 3; j++) {
- normal_float_to_short_v3((*tlnor)[j], lnors[BM_elem_index_get((*looptris)[j])]);
- }
- }
- }
- }
-
- return datalayer;
-}
-
-static void emDM_getVertCos(DerivedMesh *dm, float (*r_cos)[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *eve;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(r_cos[i], bmdm->vertexCos[i]);
- }
- }
- else {
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(r_cos[i], eve->co);
- }
- }
-}
-
-static void emDM_release(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- if (DM_release(dm)) {
- if (bmdm->vertexCos) {
- MEM_freeN((void *)bmdm->vertexCos);
- if (bmdm->vertexNos) {
- MEM_freeN((void *)bmdm->vertexNos);
- }
- if (bmdm->polyNos) {
- MEM_freeN((void *)bmdm->polyNos);
- }
- }
-
- if (bmdm->polyCos) {
- MEM_freeN((void *)bmdm->polyCos);
- }
-
- MEM_freeN(bmdm);
- }
-}
-
-static CustomData *bmDm_getVertDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->em->bm->vdata;
-}
-
-static CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->em->bm->edata;
-}
-
-static CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->dm.faceData;
-}
-
-static CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->em->bm->ldata;
-}
-
-static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->em->bm->pdata;
-}
-
-/**
- * \note This may be called per-draw,
- * avoid allocating large arrays where possible and keep this a thin wrapper for #BMesh.
- */
-DerivedMesh *getEditDerivedBMesh(
- BMEditMesh *em, struct Object *UNUSED(ob),
- CustomDataMask data_mask,
- float (*vertexCos)[3])
-{
- EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__);
- BMesh *bm = em->bm;
-
- bmdm->em = em;
-
- DM_init((DerivedMesh *)bmdm, DM_TYPE_EDITBMESH, bm->totvert,
- bm->totedge, em->tottri, bm->totloop, bm->totface);
-
- /* could also get from the objects mesh directly */
- bmdm->dm.cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
-
- bmdm->dm.getVertCos = emDM_getVertCos;
- bmdm->dm.getMinMax = emDM_getMinMax;
-
- bmdm->dm.getVertDataLayout = bmDm_getVertDataLayout;
- bmdm->dm.getEdgeDataLayout = bmDm_getEdgeDataLayout;
- bmdm->dm.getTessFaceDataLayout = bmDm_getTessFaceDataLayout;
- bmdm->dm.getLoopDataLayout = bmDm_getLoopDataLayout;
- bmdm->dm.getPolyDataLayout = bmDm_getPolyDataLayout;
-
- bmdm->dm.getNumVerts = emDM_getNumVerts;
- bmdm->dm.getNumEdges = emDM_getNumEdges;
- bmdm->dm.getNumTessFaces = emDM_getNumTessFaces;
- bmdm->dm.getNumLoops = emDM_getNumLoops;
- bmdm->dm.getNumPolys = emDM_getNumPolys;
-
- bmdm->dm.getVert = emDM_getVert;
- bmdm->dm.getVertCo = emDM_getVertCo;
- bmdm->dm.getVertNo = emDM_getVertNo;
- bmdm->dm.getPolyNo = emDM_getPolyNo;
- bmdm->dm.getEdge = emDM_getEdge;
- bmdm->dm.getTessFace = emDM_getTessFace;
- bmdm->dm.copyVertArray = emDM_copyVertArray;
- bmdm->dm.copyEdgeArray = emDM_copyEdgeArray;
- bmdm->dm.copyTessFaceArray = emDM_copyTessFaceArray;
- bmdm->dm.copyLoopArray = emDM_copyLoopArray;
- bmdm->dm.copyPolyArray = emDM_copyPolyArray;
-
- bmdm->dm.getTessFaceDataArray = emDM_getTessFaceDataArray;
-
- bmdm->dm.calcNormals = emDM_calcNormals;
- bmdm->dm.calcLoopNormals = emDM_calcLoopNormals;
- bmdm->dm.calcLoopNormalsSpaceArray = emDM_calcLoopNormalsSpaceArray;
- bmdm->dm.calcLoopTangents = emDM_calc_loop_tangents;
- bmdm->dm.recalcTessellation = emDM_recalcTessellation;
- bmdm->dm.recalcLoopTri = emDM_recalcLoopTri;
-
- bmdm->dm.foreachMappedVert = emDM_foreachMappedVert;
- bmdm->dm.foreachMappedLoop = emDM_foreachMappedLoop;
- bmdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
- bmdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
-
- bmdm->dm.drawEdges = emDM_drawEdges;
- bmdm->dm.drawMappedEdges = emDM_drawMappedEdges;
- bmdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp;
- bmdm->dm.drawMappedFaces = emDM_drawMappedFaces;
- bmdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex;
- bmdm->dm.drawMappedFacesGLSL = emDM_drawMappedFacesGLSL;
- bmdm->dm.drawMappedFacesMat = emDM_drawMappedFacesMat;
- bmdm->dm.drawFacesTex = emDM_drawFacesTex;
- bmdm->dm.drawFacesGLSL = emDM_drawFacesGLSL;
- bmdm->dm.drawUVEdges = emDM_drawUVEdges;
-
- bmdm->dm.release = emDM_release;
-
- bmdm->vertexCos = (const float (*)[3])vertexCos;
- bmdm->dm.deformedOnly = (vertexCos != NULL);
-
- const int cd_dvert_offset = (data_mask & CD_MASK_MDEFORMVERT) ?
- CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) : -1;
-
- if (cd_dvert_offset != -1) {
- BMIter iter;
- BMVert *eve;
- int i;
-
- DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT,
- BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
- }
- }
-
- const int cd_skin_offset = (data_mask & CD_MASK_MVERT_SKIN) ?
- CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN) : -1;
-
- if (cd_skin_offset != -1) {
- BMIter iter;
- BMVert *eve;
- int i;
-
- DM_add_vert_layer(&bmdm->dm, CD_MVERT_SKIN, CD_CALLOC, NULL);
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- DM_set_vert_data(&bmdm->dm, i, CD_MVERT_SKIN,
- BM_ELEM_CD_GET_VOID_P(eve, cd_skin_offset));
- }
- }
-
- return (DerivedMesh *)bmdm;
-}
-
-
-
/* -------------------------------------------------------------------- */
/* StatVis Functions */
@@ -2375,7 +105,7 @@ static void statvis_calc_overhang(
/* fallback max */
{
float fcol[3];
- weight_to_rgb(fcol, 1.0f);
+ BKE_defvert_weight_to_rgb(fcol, 1.0f);
rgb_float_to_uchar(col_fallback_max, fcol);
}
@@ -2389,7 +119,7 @@ static void statvis_calc_overhang(
fac = (fac - min) * minmax_irange;
fac = 1.0f - fac;
CLAMP(fac, 0.0f, 1.0f);
- weight_to_rgb(fcol, fac);
+ BKE_defvert_weight_to_rgb(fcol, fac);
rgb_float_to_uchar(r_face_colors[index], fcol);
}
else {
@@ -2524,7 +254,7 @@ static void statvis_calc_thickness(
fac = (fac - min) * minmax_irange;
fac = 1.0f - fac;
CLAMP(fac, 0.0f, 1.0f);
- weight_to_rgb(fcol, fac);
+ BKE_defvert_weight_to_rgb(fcol, fac);
rgb_float_to_uchar(r_face_colors[i], fcol);
}
else {
@@ -2563,7 +293,7 @@ static void statvis_calc_intersect(
overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len);
/* same for all faces */
- weight_to_rgb(fcol, 1.0f);
+ BKE_defvert_weight_to_rgb(fcol, 1.0f);
rgb_float_to_uchar(col, fcol);
if (overlap) {
@@ -2650,7 +380,7 @@ static void statvis_calc_distort(
float fcol[3];
fac = (fac - min) * minmax_irange;
CLAMP(fac, 0.0f, 1.0f);
- weight_to_rgb(fcol, fac);
+ BKE_defvert_weight_to_rgb(fcol, fac);
rgb_float_to_uchar(r_face_colors[index], fcol);
}
else {
@@ -2700,7 +430,7 @@ static void statvis_calc_sharp(
float fcol[3];
fac = (fac - min) * minmax_irange;
CLAMP(fac, 0.0f, 1.0f);
- weight_to_rgb(fcol, fac);
+ BKE_defvert_weight_to_rgb(fcol, fac);
rgb_float_to_uchar(r_vert_colors[i], fcol);
}
else {
@@ -2710,18 +440,15 @@ static void statvis_calc_sharp(
}
void BKE_editmesh_statvis_calc(
- BMEditMesh *em, DerivedMesh *dm,
+ BMEditMesh *em, EditMeshData *emd,
const MeshStatVis *statvis)
{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BLI_assert(dm == NULL || dm->type == DM_TYPE_EDITBMESH);
-
switch (statvis->type) {
case SCE_STATVIS_OVERHANG:
{
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_overhang(
- em, bmdm ? bmdm->polyNos : NULL,
+ em, emd ? emd->polyNos : NULL,
statvis->overhang_min / (float)M_PI,
statvis->overhang_max / (float)M_PI,
statvis->overhang_axis,
@@ -2733,7 +460,7 @@ void BKE_editmesh_statvis_calc(
const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_thickness(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, emd ? emd->vertexCos : NULL,
statvis->thickness_min * scale,
statvis->thickness_max * scale,
statvis->thickness_samples,
@@ -2744,7 +471,7 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_intersect(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, emd ? emd->vertexCos : NULL,
em->derivedFaceColor);
break;
}
@@ -2752,11 +479,12 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_FACE);
- if (bmdm)
- emDM_ensurePolyNormals(bmdm);
+ if (emd) {
+ BKE_editmesh_cache_ensure_poly_normals(em, emd);
+ }
statvis_calc_distort(
- em, bmdm ? bmdm->vertexCos : NULL, bmdm ? bmdm->polyNos : NULL,
+ em, emd ? emd->vertexCos : NULL, emd ? emd->polyNos : NULL,
statvis->distort_min,
statvis->distort_max,
em->derivedFaceColor);
@@ -2766,7 +494,7 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_VERT);
statvis_calc_sharp(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, emd ? emd->vertexCos : NULL,
statvis->sharp_min,
statvis->sharp_max,
/* in this case they are vertex colors */
@@ -2799,14 +527,14 @@ static void cage_mapped_verts_callback(
}
}
-float (*BKE_editmesh_vertexCos_get(BMEditMesh *em, Scene *scene, int *r_numVerts))[3]
+float (*BKE_editmesh_vertexCos_get(struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_numVerts))[3]
{
- DerivedMesh *cage, *final;
+ Mesh *cage, *final;
BLI_bitmap *visit_bitmap;
struct CageUserData data;
float (*cos_cage)[3];
- cage = editbmesh_get_derived_cage_and_final(scene, em->ob, em, CD_MASK_BAREMESH, &final);
+ cage = editbmesh_get_eval_cage_and_final(depsgraph, scene, em->ob, em, CD_MASK_BAREMESH, &final);
cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
/* when initializing cage verts, we only want the first cage coordinate for each vertex,
@@ -2817,7 +545,7 @@ float (*BKE_editmesh_vertexCos_get(BMEditMesh *em, Scene *scene, int *r_numVerts
data.cos_cage = cos_cage;
data.visit_bitmap = visit_bitmap;
- cage->foreachMappedVert(cage, cage_mapped_verts_callback, &data, DM_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
MEM_freeN(visit_bitmap);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index fea3c24d322..11f3594da04 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -39,6 +39,7 @@
#include "BKE_editmesh.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
@@ -58,7 +59,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
*em_copy = *em;
- em_copy->derivedCage = em_copy->derivedFinal = NULL;
+ em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
em_copy->derivedVertColor = NULL;
em_copy->derivedVertColorLen = 0;
@@ -89,11 +90,13 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
/* sanity check */
+#if 0 /* disable in mutlti-object edit. */
#ifndef NDEBUG
if (((Mesh *)ob->data)->edit_btmesh) {
BLI_assert(((Mesh *)ob->data)->edit_btmesh->ob == ob);
}
#endif
+#endif
return ((Mesh *)ob->data)->edit_btmesh;
}
@@ -112,18 +115,6 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
BMLoop *(*looptris)[3];
-#if 0
- /* note, we could be clever and re-use this array but would need to ensure
- * its realloced at some point, for now just free it */
- if (em->looptris) MEM_freeN(em->looptris);
-
- /* Use em->tottri when set, this means no reallocs while transforming,
- * (unless scanfill fails), otherwise... */
- /* allocate the length of totfaces, avoid many small reallocs,
- * if all faces are tri's it will be correct, quads == 2x allocs */
- BLI_array_reserve(looptris, (em->tottri && em->tottri < bm->totface * 3) ? em->tottri : bm->totface);
-#else
-
/* this means no reallocs for quad dominant models, for */
if ((em->looptris != NULL) &&
/* (*em->tottri >= looptris_tot)) */
@@ -137,8 +128,6 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
}
-#endif
-
em->looptris = looptris;
/* after allocating the em->looptris, we're ready to tessellate */
@@ -152,51 +141,25 @@ void BKE_editmesh_tessface_calc(BMEditMesh *em)
/* commented because editbmesh_build_data() ensures we get tessfaces */
#if 0
- if (em->derivedFinal && em->derivedFinal == em->derivedCage) {
- if (em->derivedFinal->recalcTessellation)
- em->derivedFinal->recalcTessellation(em->derivedFinal);
+ if (em->mesh_eval_final && em->mesh_eval_final == em->mesh_eval_cage) {
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
}
- else if (em->derivedFinal) {
- if (em->derivedCage->recalcTessellation)
- em->derivedCage->recalcTessellation(em->derivedCage);
- if (em->derivedFinal->recalcTessellation)
- em->derivedFinal->recalcTessellation(em->derivedFinal);
+ else if (em->mesh_eval_final) {
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_cage);
}
#endif
}
-void BKE_editmesh_update_linked_customdata(BMEditMesh *em)
-{
- BMesh *bm = em->bm;
- int act;
-
- if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) {
- act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act);
- }
-}
-
void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
{
- if (em->derivedCage) {
- em->derivedCage->needsFree = 1;
- em->derivedCage->release(em->derivedCage);
+ if (em->mesh_eval_cage) {
+ BKE_id_free(NULL, em->mesh_eval_cage);
}
- if (em->derivedFinal && em->derivedFinal != em->derivedCage) {
- em->derivedFinal->needsFree = 1;
- em->derivedFinal->release(em->derivedFinal);
+ if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
+ BKE_id_free(NULL, em->mesh_eval_final);
}
-
- em->derivedCage = em->derivedFinal = NULL;
+ em->mesh_eval_cage = em->mesh_eval_final = NULL;
}
/*does not free the BMEditMesh struct itself*/
@@ -264,3 +227,24 @@ float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
return orco;
}
+
+void BKE_editmesh_lnorspace_update(BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+
+ /* We need to create clnors data if none exist yet, otherwise there is no way to edit them.
+ * Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading
+ * in case we were using autosmooth so far...
+ * Note: there is a problem here, which is that if someone starts a normal editing operation on previously
+ * autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges
+ * (and hence autosmooth is 'lost').
+ * Not sure how critical this is, and how to fix that issue? */
+ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ Mesh *me = em->ob->data;
+ if (me->flag & ME_AUTOSMOOTH) {
+ BM_edges_sharp_from_angle_set(bm, me->smoothresh);
+ }
+ }
+
+ BM_lnorspace_update(bm);
+}
diff --git a/source/blender/blenkernel/intern/editmesh_cache.c b/source/blender/blenkernel/intern/editmesh_cache.c
new file mode 100644
index 00000000000..f0af0ede9b1
--- /dev/null
+++ b/source/blender/blenkernel/intern/editmesh_cache.c
@@ -0,0 +1,120 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/editmesh_cache.c
+ * \ingroup bke
+ *
+ * Manage edit mesh cache: #EditMeshData
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h" /* own include */
+
+void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd)
+{
+ if (!(emd->vertexCos && (emd->polyNos == NULL))) {
+ return;
+ }
+
+ BMesh *bm = em->bm;
+ const float (*vertexCos)[3];
+ float (*polyNos)[3];
+
+ BMFace *efa;
+ BMIter fiter;
+ int i;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__);
+
+ vertexCos = emd->vertexCos;
+
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_elem_index_set(efa, i); /* set_inline */
+ BM_face_calc_normal_vcos(bm, efa, polyNos[i], vertexCos);
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+
+ emd->polyNos = (const float (*)[3])polyNos;
+}
+
+void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh *em, EditMeshData *emd)
+{
+ if (!(emd->vertexCos && (emd->vertexNos == NULL))) {
+ return;
+ }
+
+ BMesh *bm = em->bm;
+ const float (*vertexCos)[3], (*polyNos)[3];
+ float (*vertexNos)[3];
+
+ /* calculate vertex normals from poly normals */
+ BKE_editmesh_cache_ensure_poly_normals(em, emd);
+
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ polyNos = emd->polyNos;
+ vertexCos = emd->vertexCos;
+ vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__);
+
+ BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos);
+
+ emd->vertexNos = (const float (*)[3])vertexNos;
+}
+
+void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd)
+{
+ if (emd->polyCos != NULL) {
+ return;
+ }
+ BMesh *bm = em->bm;
+ float (*polyCos)[3];
+
+ BMFace *efa;
+ BMIter fiter;
+ int i;
+
+ polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__);
+
+ if (emd->vertexCos) {
+ const float (*vertexCos)[3];
+ vertexCos = emd->vertexCos;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_face_calc_center_mean_vcos(bm, efa, polyCos[i], vertexCos);
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_face_calc_center_mean(efa, polyCos[i]);
+ }
+ }
+
+ emd->polyCos = (const float (*)[3])polyCos;
+}
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
new file mode 100644
index 00000000000..4231ad54ea8
--- /dev/null
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -0,0 +1,433 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/editmesh_tangent.c
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_defs.h"
+#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h" /* for utility functions */
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_tangent.h"
+
+#include "MEM_guardedalloc.h"
+
+/* interface */
+#include "mikktspace.h"
+
+/** \name Tangent Space Calculation
+ * \{ */
+
+/* Necessary complexity to handle looptri's as quads for correct tangents */
+#define USE_LOOPTRI_DETECT_QUADS
+
+typedef struct {
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const BMLoop *(*looptris)[3];
+ int cd_loop_uv_offset; /* texture coordinates */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+
+} SGLSLEditMeshToTangent;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+/* seems weak but only used on quads */
+static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
+{
+ const BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ while (vert_index--) {
+ l = l->next;
+ }
+ return l;
+}
+#endif
+
+static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ return pMesh->num_face_as_quad_map;
+#else
+ return pMesh->numTessFaces;
+#endif
+}
+
+static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ return 4;
+ }
+ }
+ return 3;
+#else
+ UNUSED_VARS(pContext, face_num);
+ return 3;
+#endif
+}
+
+static void emdm_ts_GetPosition(
+ const SMikkTSpaceContext *pContext, float r_co[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+ const float *co;
+
+finally:
+ co = l->v->co;
+ copy_v3_v3(r_co, co);
+}
+
+static void emdm_ts_GetTextureCoordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+finally:
+ if (pMesh->cd_loop_uv_offset != -1) {
+ const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
+ copy_v2_v2(r_uv, uv);
+ }
+ else {
+ const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
+ map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ }
+}
+
+static void emdm_ts_GetNormal(
+ const SMikkTSpaceContext *pContext, float r_no[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+finally:
+ if (pMesh->precomputedLoopNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
+ }
+ else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
+ if (pMesh->precomputedFaceNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
+ }
+ else {
+ copy_v3_v3(r_no, l->f->no);
+ }
+ }
+ else {
+ copy_v3_v3(r_no, l->v->no);
+ }
+}
+
+static void emdm_ts_SetTSpace(
+ const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+ float *pRes;
+
+finally:
+ pRes = pMesh->tangent[BM_elem_index_get(l)];
+ copy_v3_v3(pRes, fvTangent);
+ pRes[3] = fSign;
+}
+
+static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = emdm_ts_GetPosition;
+ sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = emdm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+}
+
+/**
+ * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
+ *
+ * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
+ * This is done because #CD_TANGENT is cache data used only for drawing.
+ */
+void BKE_editmesh_loop_tangent_calc(
+ BMEditMesh *em, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p)
+{
+ BMesh *bm = em->bm;
+
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ short tangent_mask = 0;
+ short tangent_mask_curr = *tangent_mask_curr_p;
+
+ BKE_mesh_calc_loop_tangent_step_0(
+ &bm->ldata, calc_active_tangent, tangent_names, tangent_names_len,
+ &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+
+ if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
+ for (int i = 0; i < tangent_names_len; i++) {
+ if (tangent_names[i][0]) {
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ &bm->ldata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
+ }
+ }
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
+ if (calc_act && act_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
+ int totface = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (em->tottri != bm->totface) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+ int i, j;
+ for (i = 0, j = 0; j < totface; i++, j++) {
+ face_as_quad_map[i] = j;
+ /* step over all quads */
+ if (em->looptris[j][0]->f->len == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = i;
+ }
+ else {
+ num_face_as_quad_map = totface;
+ }
+#endif
+ /* Calculation */
+ if (em->tottri != 0) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ tangent_mask_curr = 0;
+ /* Calculate tangent layers */
+ SGLSLEditMeshToTangent data_array[MAX_MTFACE];
+ int index = 0;
+ int n = 0;
+ CustomData_update_typemap(loopdata_out);
+ const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+ for (n = 0; n < tangent_layer_num; n++) {
+ index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+#endif
+ mesh2tangent->precomputedFaceNormals = poly_normals;
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = loop_normals;
+ mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
+
+ /* needed for indexing loop-tangents */
+ int htype_index = BM_LOOP;
+ if (mesh2tangent->cd_loop_uv_offset == -1) {
+ mesh2tangent->orco = vert_orco;
+ if (!mesh2tangent->orco)
+ continue;
+ /* needed for orco lookups */
+ htype_index |= BM_VERT;
+ tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ /* Fill the resulting tangent_mask */
+ int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name);
+ int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ tangent_mask_curr |= 1 << (uv_ind - uv_start);
+ }
+ if (mesh2tangent->precomputedFaceNormals) {
+ /* needed for face normal lookups */
+ htype_index |= BM_FACE;
+ }
+ BM_mesh_elem_index_ensure(bm, htype_index);
+
+ mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
+ mesh2tangent->tangent = loopdata_out->layers[index].data;
+
+ BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+
+ BLI_assert(tangent_mask_curr == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
+ else {
+ tangent_mask_curr = tangent_mask;
+ }
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+#undef USE_LOOPTRI_DETECT_QUADS
+#endif
+ }
+
+ *tangent_mask_curr_p = tangent_mask_curr;
+
+ int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
+ CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+
+ /* Update render layer index */
+ int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 82bf65993a8..f54082de153 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -37,9 +37,10 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
@@ -57,13 +58,14 @@
#include "PIL_time.h"
#include "BKE_anim.h" /* needed for where_on_path */
+#include "BKE_bvhutils.h"
+#include "BKE_collection.h"
#include "BKE_collision.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -71,6 +73,9 @@
#include "BKE_scene.h"
#include "BKE_smoke.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
@@ -82,7 +87,7 @@
#include <string.h>
#endif // WITH_MOD_FLUID
-EffectorWeights *BKE_add_effector_weights(Group *group)
+EffectorWeights *BKE_add_effector_weights(Collection *collection)
{
EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights");
int i;
@@ -93,7 +98,7 @@ EffectorWeights *BKE_add_effector_weights(Group *group)
weights->global_gravity = 1.0f;
- weights->group = group;
+ weights->group = collection;
return weights;
}
@@ -107,6 +112,7 @@ PartDeflect *object_add_collision_fields(int type)
pd->pdef_sbdamp = 0.1f;
pd->pdef_sbift = 0.2f;
pd->pdef_sboft = 0.02f;
+ pd->pdef_cfrict = 5.0f;
pd->seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
pd->f_strength = 1.0f;
pd->f_damp = 1.0f;
@@ -127,14 +133,13 @@ PartDeflect *object_add_collision_fields(int type)
pd->f_flow = 1.0f;
break;
}
- pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION;
+ pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION | PFIELD_CLOTH_USE_CULLING;
return pd;
}
-/* ***************** PARTICLES ***************** */
+/************************ PARTICLES ***************************/
-/* -------------------------- Effectors ------------------ */
void free_partdeflect(PartDeflect *pd)
{
if (!pd) {
@@ -146,183 +151,195 @@ void free_partdeflect(PartDeflect *pd)
MEM_freeN(pd);
}
-static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
-{
- EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
- eff->scene = scene;
- eff->ob = ob;
- eff->psys = psys;
- eff->pd = pd;
- eff->frame = -1;
- return eff;
-}
-static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src, bool for_simulation)
-{
- EffectorCache *eff = NULL;
+/******************** EFFECTOR RELATIONS ***********************/
- if (ob == ob_src) {
- return;
+static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *eff)
+{
+ float ctime = DEG_get_ctime(depsgraph);
+ uint cfra = (uint)(ctime >= 0 ? ctime : -ctime);
+ if (!eff->pd->rng) {
+ eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
+ }
+ else {
+ BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
}
- if (for_simulation) {
- if (weights->weight[ob->pd->forcefield] == 0.0f) {
- return;
- }
+ if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) {
+ Curve *cu = eff->ob->data;
+ if (cu->flag & CU_PATH) {
+ if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path == NULL || eff->ob->runtime.curve_cache->path->data == NULL)
+ BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, false, false);
- if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal) {
- return;
+ if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) {
+ where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
+ mul_m4_v3(eff->ob->obmat, eff->guide_loc);
+ mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
+ }
}
}
+ else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
+ eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface);
+ if (eff->ob->type == OB_CURVE)
+ eff->flag |= PE_USE_NORMAL_DATA;
+ }
+ else if (eff->psys)
+ psys_update_particle_tree(eff->psys, ctime);
- if (*effectors == NULL)
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
+ /* Store object velocity */
+ if (eff->ob) {
+ float old_vel[3];
- eff = new_effector_cache(scene, ob, NULL, ob->pd);
+ BKE_object_where_is_calc_time(depsgraph, eff->scene, eff->ob, cfra - 1.0f);
+ copy_v3_v3(old_vel, eff->ob->obmat[3]);
+ BKE_object_where_is_calc_time(depsgraph, eff->scene, eff->ob, cfra);
+ sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel);
+ }
+}
- /* make sure imat is up to date */
- invert_m4_m4(ob->imat, ob->obmat);
+static void add_effector_relation(ListBase *relations, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+{
+ EffectorRelation *relation = MEM_callocN(sizeof(EffectorRelation), "EffectorRelation");
+ relation->ob = ob;
+ relation->psys = psys;
+ relation->pd = pd;
- BLI_addtail(*effectors, eff);
+ BLI_addtail(relations, relation);
}
-static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src, bool for_simulation)
-{
- ParticleSettings *part = psys->part;
- if (!psys_check_enabled(ob, psys, G.is_rendering)) {
- return;
- }
- if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
- return;
- }
- if (part->pd && part->pd->forcefield && (!for_simulation || weights->weight[part->pd->forcefield] != 0.0f)) {
- if (*effectors == NULL) {
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
- }
- BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd));
+static void add_effector_evaluation(ListBase **effectors, Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+{
+ if (*effectors == NULL) {
+ *effectors = MEM_callocN(sizeof(ListBase), "effector effectors");
}
- if (part->pd2 && part->pd2->forcefield && (!for_simulation || weights->weight[part->pd2->forcefield] != 0.0f)) {
- if (*effectors == NULL) {
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
- }
- BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd2));
- }
+ EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
+ eff->depsgraph = depsgraph;
+ eff->scene = scene;
+ eff->ob = ob;
+ eff->psys = psys;
+ eff->pd = pd;
+ eff->frame = -1;
+ BLI_addtail(*effectors, eff);
+
+ precalculate_effector(depsgraph, eff);
}
-/* returns ListBase handle with objects taking part in the effecting */
-ListBase *pdInitEffectors(
- Scene *scene, Object *ob_src, ParticleSystem *psys_src,
- EffectorWeights *weights, bool for_simulation)
+/* Create list of effector relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of effectors during evaluation. */
+ListBase *BKE_effector_relations_create(
+ Depsgraph *depsgraph,
+ ViewLayer *view_layer,
+ Collection *collection)
{
- const uint layer = ob_src->lay;
- ListBase *effectors = NULL;
+ Base *base = BKE_collection_or_layer_objects(view_layer, collection);
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
- if (weights->group) {
- for (GroupObject *go = weights->group->gobject.first; go; go = go->next) {
- if ((go->ob->lay & layer)) {
- if (go->ob->pd && go->ob->pd->forcefield) {
- add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src, for_simulation);
- }
+ ListBase *relations = MEM_callocN(sizeof(ListBase), "effector relations");
- if (go->ob->particlesystem.first) {
- for (ParticleSystem *psys = go->ob->particlesystem.first; psys; psys = psys->next) {
- add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src, for_simulation);
- }
- }
- }
+ for (; base; base = base->next) {
+ if (!(base->flag & base_flag)) {
+ continue;
}
- }
- else {
- for (Base *base = scene->base.first; base; base = base->next) {
- if ((base->lay & layer)) {
- if (base->object->pd && base->object->pd->forcefield) {
- add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation);
+
+ Object *ob = base->object;
+
+ if (ob->pd && ob->pd->forcefield) {
+ add_effector_relation(relations, ob, NULL, ob->pd);
+ }
+
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ if (psys_check_enabled(ob, psys, for_render)) {
+ if (part->pd && part->pd->forcefield) {
+ add_effector_relation(relations, ob, psys, part->pd);
}
- if (base->object->particlesystem.first) {
- for (ParticleSystem *psys = base->object->particlesystem.first; psys; psys = psys->next) {
- add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation);
- }
+ if (part->pd2 && part->pd2->forcefield) {
+ add_effector_relation(relations, ob, psys, part->pd2);
}
}
}
}
- if (for_simulation) {
- pdPrecalculateEffectors(effectors);
- }
-
- return effectors;
+ return relations;
}
-void pdEndEffectors(ListBase **effectors)
+void BKE_effector_relations_free(ListBase *lb)
{
- if (*effectors) {
- for (EffectorCache *eff = (*effectors)->first; eff; eff = eff->next) {
- if (eff->guide_data) {
- MEM_freeN(eff->guide_data);
- }
- }
-
- BLI_freelistN(*effectors);
- MEM_freeN(*effectors);
- *effectors = NULL;
+ if (lb) {
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
}
}
-static void precalculate_effector(EffectorCache *eff)
+/* Create effective list of effectors from relations built beforehand. */
+ListBase *BKE_effectors_create(
+ Depsgraph *depsgraph,
+ Object *ob_src,
+ ParticleSystem *psys_src,
+ EffectorWeights *weights)
{
- uint cfra = (uint)(eff->scene->r.cfra >= 0 ? eff->scene->r.cfra : -eff->scene->r.cfra);
- if (!eff->pd->rng) {
- eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
- }
- else {
- BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group);
+ ListBase *effectors = NULL;
+
+ if (!relations) {
+ return NULL;
}
- if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) {
- Curve *cu = eff->ob->data;
- if (cu->flag & CU_PATH) {
- if ((eff->ob->curve_cache == NULL) ||
- (eff->ob->curve_cache->path == NULL) ||
- (eff->ob->curve_cache->path->data == NULL))
- {
- BKE_displist_make_curveTypes(eff->scene, eff->ob, 0);
+ for (EffectorRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
+
+ if (relation->psys) {
+ /* Get evaluated particle system. */
+ ParticleSystem *psys = BLI_findstring(&ob->particlesystem,
+ relation->psys->name, offsetof(ParticleSystem, name));
+ ParticleSettings *part = psys->part;
+
+ if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
+ continue;
}
- if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) {
- where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
- mul_m4_v3(eff->ob->obmat, eff->guide_loc);
- mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
+ PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2;
+ if (weights->weight[pd->forcefield] == 0.0f) {
+ continue;
}
+
+ add_effector_evaluation(&effectors, depsgraph, scene, ob, psys, pd);
}
- }
- else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
- eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface);
- if (eff->ob->type == OB_CURVE) {
- eff->flag |= PE_USE_NORMAL_DATA;
+ else {
+ /* Object effector. */
+ if (ob == ob_src) {
+ continue;
+ }
+ else if (weights->weight[ob->pd->forcefield] == 0.0f) {
+ continue;
+ }
+ else if (ob->pd->shape == PFIELD_SHAPE_POINTS && ob->runtime.mesh_eval == NULL) {
+ continue;
+ }
+
+ add_effector_evaluation(&effectors, depsgraph, scene, ob, NULL, ob->pd);
}
}
- else if (eff->psys) {
- psys_update_particle_tree(eff->psys, eff->scene->r.cfra);
- }
- /* Store object velocity */
- if (eff->ob) {
- float old_vel[3];
-
- BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra - 1.0f);
- copy_v3_v3(old_vel, eff->ob->obmat[3]);
- BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra);
- sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel);
- }
+ return effectors;
}
-void pdPrecalculateEffectors(ListBase *effectors)
+void BKE_effectors_free(ListBase *lb)
{
- if (effectors) {
- for (EffectorCache *eff = effectors->first; eff; eff = eff->next) {
- precalculate_effector(eff);
+ if (lb) {
+ for (EffectorCache *eff = lb->first; eff; eff = eff->next) {
+ if (eff->guide_data) {
+ MEM_freeN(eff->guide_data);
+ }
}
+
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
}
}
@@ -413,7 +430,7 @@ static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, Effect
return visibility;
}
if (!colls) {
- colls = get_collider_cache(eff->scene, eff->ob, NULL);
+ colls = BKE_collider_cache_create(eff->depsgraph, eff->ob, NULL);
}
if (!colls) {
return visibility;
@@ -453,7 +470,7 @@ static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, Effect
}
if (!colliders)
- free_collider_cache(&colls);
+ BKE_collider_cache_free(&colls);
return visibility;
}
@@ -534,7 +551,7 @@ float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *UNU
if (falloff == 0.0f)
break;
- r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point)));
+ r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point2)));
falloff *= falloff_func_rad(eff->pd, r_fac);
break;
@@ -577,7 +594,7 @@ int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], floa
}
int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity)
{
- float cfra = eff->scene->r.cfra;
+ float cfra = DEG_get_ctime(eff->depsgraph);
int ret = 0;
/* In case surface object is in Edit mode when loading the .blend, surface modifier is never executed
@@ -596,12 +613,10 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
efd->size = 0.0f;
}
else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
-
- if (eff->ob->derivedFinal) {
- DerivedMesh *dm = eff->ob->derivedFinal;
-
- dm->getVertCo(dm, *efd->index, efd->loc);
- dm->getVertNo(dm, *efd->index, efd->nor);
+ Mesh *me_eval = eff->ob->runtime.mesh_eval;
+ if (me_eval != NULL) {
+ copy_v3_v3(efd->loc, me_eval->mvert[*efd->index].co);
+ normal_short_to_float_v3(efd->nor, me_eval->mvert[*efd->index].no);
mul_m4_v3(eff->ob->obmat, efd->loc);
mul_mat3_m4_v3(eff->ob->obmat, efd->nor);
@@ -624,6 +639,7 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
}
else {
ParticleSimulationData sim = {NULL};
+ sim.depsgraph = eff->depsgraph;
sim.scene = eff->scene;
sim.ob = eff->ob;
sim.psys = eff->psys;
@@ -658,13 +674,13 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
/* use z-axis as normal*/
normalize_v3_v3(efd->nor, ob->obmat[2]);
- if (eff->pd && eff->pd->shape == PFIELD_SHAPE_PLANE) {
+ if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) {
float temp[3], translate[3];
sub_v3_v3v3(temp, point->loc, ob->obmat[3]);
project_v3_v3v3(translate, temp, efd->nor);
/* for vortex the shape chooses between old / new force */
- if (eff->pd->forcefield == PFIELD_VORTEX) {
+ if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) {
add_v3_v3v3(efd->loc, ob->obmat[3], translate);
}
else { /* normally efd->loc is closest point on effector xy-plane */
@@ -710,7 +726,8 @@ static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoin
efd->index = p;
if (eff->pd->shape == PFIELD_SHAPE_POINTS) {
- *tot = eff->ob->derivedFinal ? eff->ob->derivedFinal->numVertData : 1;
+ Mesh *me_eval = eff->ob->runtime.mesh_eval;
+ *tot = me_eval != NULL ? me_eval->totvert : 1;
if (*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) {
*p = point->index % *tot;
@@ -893,7 +910,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
}
break;
case PFIELD_MAGNET:
- if (eff->pd->shape == PFIELD_SHAPE_POINT)
+ if (ELEM(eff->pd->shape, PFIELD_SHAPE_POINT, PFIELD_SHAPE_LINE))
/* magnetic field of a moving charge */
cross_v3_v3v3(temp, efd->nor, efd->vec_to_point);
else
@@ -988,7 +1005,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
}
}
-/* -------- pdDoEffectors() --------
+/* -------- BKE_effectors_apply() --------
* generic force/speed system, now used for particles and softbodies
* scene = scene where it runs in, for time and stuff
* lb = listbase with objects that take part in effecting
@@ -1001,7 +1018,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
* flags = only used for softbody wind now
* guide = old speed of particle
*/
-void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
+void BKE_effectors_apply(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
{
/*
* Modifies the force on a particle according to its
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 877f1c13da9..2f0c70a4e12 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -49,6 +49,8 @@
#include "BLI_threads.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#include "BLI_expr_pylike_eval.h"
+#include "BLI_alloca.h"
#include "BLT_translation.h"
@@ -65,6 +67,8 @@
#include "RNA_access.h"
+#include "atomic_ops.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -882,25 +886,44 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample
* that the handles are correctly
*/
-/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */
-bool BKE_fcurve_is_cyclic(FCurve *fcu)
+/* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */
+eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
{
FModifier *fcm = fcu->modifiers.first;
- if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES)
- return false;
+ if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES) {
+ return FCU_CYCLE_NONE;
+ }
- if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED))
- return false;
+ if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) {
+ return FCU_CYCLE_NONE;
+ }
- if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE))
- return false;
+ if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE)) {
+ return FCU_CYCLE_NONE;
+ }
FMod_Cycles *data = (FMod_Cycles *)fcm->data;
- return data && data->after_cycles == 0 && data->before_cycles == 0 &&
- ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) &&
- ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET);
+ if (data && data->after_cycles == 0 && data->before_cycles == 0) {
+ if (data->before_mode == FCM_EXTRAPOLATE_CYCLIC && data->after_mode == FCM_EXTRAPOLATE_CYCLIC) {
+ return FCU_CYCLE_PERFECT;
+ }
+
+ if (ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) &&
+ ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET))
+ {
+ return FCU_CYCLE_OFFSET;
+ }
+ }
+
+ return FCU_CYCLE_NONE;
+}
+
+/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */
+bool BKE_fcurve_is_cyclic(FCurve *fcu)
+{
+ return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
}
/* Shifts 'in' by the difference in coordinates between 'to' and 'from', using 'out' as the output buffer.
@@ -1288,31 +1311,6 @@ bool driver_get_variable_property(
return true;
}
-#if 0
-/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
-static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dtar)
-{
- ID *id;
- /* sanity check */
- if (ELEM(NULL, driver, dtar))
- return NULL;
-
- id = dtar_id_ensure_proxy_from(dtar->id);
-
- /* check if the ID here is a valid object */
- if (id && GS(id->name)) {
- Object *ob = (Object *)id;
-
- /* get pose, and subsequently, posechannel */
- return BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
- }
- else {
- /* cannot find a posechannel this way */
- return NULL;
- }
-}
-#endif
-
static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
{
short valid_targets = 0;
@@ -1694,11 +1692,8 @@ void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
/* remove and free the driver variable */
driver_free_variable(&driver->variables, dvar);
-#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
- if (driver->type == DRIVER_TYPE_PYTHON)
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
-#endif
+ BKE_driver_invalidate_expression(driver, false, true);
}
/* Copy driver variables from src_vars list to dst_vars list */
@@ -1835,11 +1830,8 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
/* set the default type to 'single prop' */
driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
-#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
- if (driver->type == DRIVER_TYPE_PYTHON)
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
-#endif
+ BKE_driver_invalidate_expression(driver, false, true);
/* return the target */
return dvar;
@@ -1868,6 +1860,8 @@ void fcurve_free_driver(FCurve *fcu)
BPY_DECREF(driver->expr_comp);
#endif
+ BLI_expr_pylike_free(driver->expr_simple);
+
/* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
MEM_freeN(driver);
fcu->driver = NULL;
@@ -1885,6 +1879,7 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
/* copy all data */
ndriver = MEM_dupallocN(driver);
ndriver->expr_comp = NULL;
+ ndriver->expr_simple = NULL;
/* copy variables */
BLI_listbase_clear(&ndriver->variables); /* to get rid of refs to non-copied data (that's still used on original) */
@@ -1894,6 +1889,124 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
return ndriver;
}
+/* Driver Expression Evaluation --------------- */
+
+static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver)
+{
+ /* Prepare parameter names. */
+ int names_len = BLI_listbase_count(&driver->variables);
+ const char **names = BLI_array_alloca(names, names_len + 1);
+ int i = 0;
+
+ names[i++] = "frame";
+
+ for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ names[i++] = dvar->name;
+ }
+
+ return BLI_expr_pylike_parse(driver->expression, names, names_len + 1);
+}
+
+static bool driver_evaluate_simple_expr(ChannelDriver *driver, ExprPyLike_Parsed *expr, float *result, float time)
+{
+ /* Prepare parameter values. */
+ int vars_len = BLI_listbase_count(&driver->variables);
+ double *vars = BLI_array_alloca(vars, vars_len + 1);
+ int i = 0;
+
+ vars[i++] = time;
+
+ for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ vars[i++] = driver_get_variable_value(driver, dvar);
+ }
+
+ /* Evaluate expression. */
+ double result_val;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, vars, vars_len + 1, &result_val);
+ const char *message;
+
+ switch (status) {
+ case EXPR_PYLIKE_SUCCESS:
+ if (isfinite(result_val)) {
+ *result = (float)result_val;
+ }
+ return true;
+
+ case EXPR_PYLIKE_DIV_BY_ZERO:
+ case EXPR_PYLIKE_MATH_ERROR:
+ message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
+ fprintf(stderr, "\n%s in Driver: '%s'\n", message, driver->expression);
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ return true;
+
+ default:
+ /* arriving here means a bug, not user error */
+ printf("Error: simple driver expression evaluation failed: '%s'\n", driver->expression);
+ return false;
+ }
+}
+
+/* Compile and cache the driver expression if necessary, with thread safety. */
+static bool driver_compile_simple_expr(ChannelDriver *driver)
+{
+ if (driver->expr_simple != NULL) {
+ return true;
+ }
+
+ if (driver->type != DRIVER_TYPE_PYTHON) {
+ return false;
+ }
+
+ /* It's safe to parse in multiple threads; at worst it'll
+ * waste some effort, but in return avoids mutex contention. */
+ ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
+
+ /* Store the result if the field is still NULL, or discard
+ * it if another thread got here first. */
+ if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
+ BLI_expr_pylike_free(expr);
+ }
+
+ return true;
+}
+
+/* Try using the simple expression evaluator to compute the result of the driver.
+ * On success, stores the result and returns true; on failure result is set to 0. */
+static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, ChannelDriver *driver_orig, float *result, float time)
+{
+ *result = 0.0f;
+
+ return driver_compile_simple_expr(driver_orig) &&
+ BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
+ driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
+}
+
+/* Check if the expression in the driver conforms to the simple subset. */
+bool BKE_driver_has_simple_expression(ChannelDriver *driver)
+{
+ return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
+}
+
+/* Reset cached compiled expression data */
+void BKE_driver_invalidate_expression(ChannelDriver *driver, bool expr_changed, bool varname_changed)
+{
+ if (expr_changed || varname_changed) {
+ BLI_expr_pylike_free(driver->expr_simple);
+ driver->expr_simple = NULL;
+ }
+
+#ifdef WITH_PYTHON
+ if (expr_changed) {
+ driver->flag |= DRIVER_FLAG_RECOMPILE;
+ }
+
+ if (varname_changed) {
+ driver->flag |= DRIVER_FLAG_RENAMEVAR;
+ }
+#endif
+}
+
/* Driver Evaluation -------------------------- */
/* Evaluate a Driver Variable to get a value that contributes to the final */
@@ -1922,13 +2035,14 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
* - "evaltime" is the frame at which F-Curve is being evaluated
* - has to return a float value
+ * - driver_orig is where we cache Python expressions, in case of COW
*/
-float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
+float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime)
{
DriverVar *dvar;
/* check if driver can be evaluated */
- if (driver->flag & DRIVER_FLAG_INVALID)
+ if (driver_orig->flag & DRIVER_FLAG_INVALID)
return 0.0f;
switch (driver->type) {
@@ -1996,26 +2110,26 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl
}
case DRIVER_TYPE_PYTHON: /* expression */
{
-#ifdef WITH_PYTHON
/* check for empty or invalid expression */
- if ( (driver->expression[0] == '\0') ||
- (driver->flag & DRIVER_FLAG_INVALID) )
+ if ( (driver_orig->expression[0] == '\0') ||
+ (driver_orig->flag & DRIVER_FLAG_INVALID) )
{
driver->curval = 0.0f;
}
- else {
+ else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) {
+#ifdef WITH_PYTHON
/* this evaluates the expression using Python, and returns its result:
* - on errors it reports, then returns 0.0f
*/
BLI_mutex_lock(&python_driver_lock);
- driver->curval = BPY_driver_exec(anim_rna, driver, evaltime);
+ driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
BLI_mutex_unlock(&python_driver_lock);
- }
#else /* WITH_PYTHON*/
- UNUSED_VARS(anim_rna, evaltime);
+ UNUSED_VARS(anim_rna, evaltime);
#endif /* WITH_PYTHON*/
+ }
break;
}
default:
@@ -2187,24 +2301,6 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
}
}
-#if 0
-static void berekenx(float *f, float *o, int b)
-{
- float t, c0, c1, c2, c3;
- int a;
-
- c0 = f[0];
- c1 = 3.0f * (f[3] - f[0]);
- c2 = 3.0f * (f[0] - 2.0f * f[3] + f[6]);
- c3 = f[9] - f[0] + 3.0f * (f[3] - f[6]);
-
- for (a = 0; a < b; a++) {
- t = o[a];
- o[a] = c0 + t * c1 + t * t * c2 + t * t * t * c3;
- }
-}
-#endif
-
/* -------------------------- */
@@ -2705,7 +2801,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime)
return evaluate_fcurve_ex(fcu, evaltime, 0.0);
}
-float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
+float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, ChannelDriver *driver_orig, float evaltime)
{
BLI_assert(fcu->driver != NULL);
float cvalue = 0.0f;
@@ -2715,7 +2811,7 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evalt
*/
if (fcu->driver) {
/* evaltime now serves as input for the curve */
- evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime);
+ evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, evaltime);
/* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
if (fcu->totvert == 0) {
@@ -2762,7 +2858,7 @@ float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
/* calculate and set curval (evaluates driver too if necessary) */
float curval;
if (fcu->driver) {
- curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime);
+ curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, evaltime);
}
else {
curval = evaluate_fcurve(fcu, evaltime);
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index 0487302d9b6..bf1532bab42 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -30,46 +30,31 @@
*/
-// headers for fluidsim bobj meshes
-#include <stdlib.h>
-#include <zlib.h>
-#include <string.h>
-#include <stdio.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_object_fluidsim_types.h"
-#include "DNA_object_force_types.h" // for pointcache
#include "DNA_object_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_scene_types.h"
#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_fluidsim.h"
-#include "BKE_modifier.h"
-#include "BKE_mesh.h"
+#include "BKE_library.h"
+#include "BKE_mesh_runtime.h"
/* ************************* fluidsim bobj file handling **************************** */
-
//-------------------------------------------------------------------------------
// file handling
//-------------------------------------------------------------------------------
-void initElbeemMesh(struct Scene *scene, struct Object *ob,
+void initElbeemMesh(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
int *numVertices, float **vertices,
int *numTriangles, int **triangles,
int useGlobalCoords, int modifierIndex)
{
- DerivedMesh *dm;
+ Mesh *mesh;
const MVert *mvert;
const MLoop *mloop;
const MLoopTri *looptri, *lt;
@@ -77,13 +62,13 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
float *verts;
int *tris;
- dm = mesh_create_derived_index_render(scene, ob, CD_MASK_BAREMESH, modifierIndex);
+ mesh = mesh_create_eval_final_index_render(depsgraph, scene, ob, CD_MASK_BAREMESH, modifierIndex);
- mvert = dm->getVertArray(dm);
- mloop = dm->getLoopArray(dm);
- looptri = dm->getLoopTriArray(dm);
- mvert_num = dm->getNumVerts(dm);
- looptri_num = dm->getNumLoopTri(dm);
+ mvert = mesh->mvert;
+ mloop = mesh->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ mvert_num = mesh->totvert;
+ looptri_num = mesh->runtime.looptris.len;
*numVertices = mvert_num;
verts = MEM_mallocN(mvert_num * sizeof(float[3]), "elbeemmesh_vertices");
@@ -102,5 +87,5 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
}
*triangles = tris;
- dm->release(dm);
+ BKE_id_free(NULL, mesh);
}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index f5915e1ddb9..8fce320800e 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -835,27 +835,6 @@ static FModifierTypeInfo FMI_NOISE = {
NULL /* evaluate with storage */
};
-/* Filter F-Curve Modifier --------------------------- */
-
-#if 0 // XXX not yet implemented
-static FModifierTypeInfo FMI_FILTER = {
- FMODIFIER_TYPE_FILTER, /* type */
- sizeof(FMod_Filter), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- N_("Filter"), /* name */
- "FMod_Filter", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- NULL, /* new data */
- NULL /*fcm_filter_verify*/, /* verify */
- NULL, /* evaluate time */
- fcm_filter_evaluate, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL /* evaluate with storage */
-};
-#endif // XXX not yet implemented
-
/* Python F-Curve Modifier --------------------------- */
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index e51b10a97a4..1b6061d5b04 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -364,7 +364,8 @@ static VChar *find_vfont_char(VFontData *vfd, unsigned int character)
}
static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
- float yofs, float rot, int charidx, short mat_nr)
+ float yofs, float rot, int charidx, short mat_nr,
+ const float font_size)
{
Nurb *nu2;
BPoint *bp;
@@ -417,18 +418,19 @@ static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
bp = nu2->bp;
}
- mul_v2_fl(bp[0].vec, cu->fsize);
- mul_v2_fl(bp[1].vec, cu->fsize);
- mul_v2_fl(bp[2].vec, cu->fsize);
- mul_v2_fl(bp[3].vec, cu->fsize);
+ mul_v2_fl(bp[0].vec, font_size);
+ mul_v2_fl(bp[1].vec, font_size);
+ mul_v2_fl(bp[2].vec, font_size);
+ mul_v2_fl(bp[3].vec, font_size);
}
static void buildchar(Curve *cu, ListBase *nubase, unsigned int character, CharInfo *info,
- float ofsx, float ofsy, float rot, int charidx)
+ float ofsx, float ofsy, float rot, int charidx,
+ const float fsize)
{
BezTriple *bezt1, *bezt2;
Nurb *nu1 = NULL, *nu2 = NULL;
- float *fp, fsize, shear, x, si, co;
+ float *fp, shear, x, si, co;
VFontData *vfd = NULL;
VChar *che = NULL;
int i;
@@ -448,7 +450,6 @@ static void buildchar(Curve *cu, ListBase *nubase, unsigned int character, CharI
#endif
/* make a copy at distance ofsx, ofsy with shear */
- fsize = cu->fsize;
shear = cu->shear;
si = sinf(rot);
co = cosf(rot);
@@ -635,7 +636,46 @@ struct TempLineInfo {
int wspace_nr; /* number of whitespaces of line */
};
-bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
+typedef struct VFontToCurveIter {
+ int iteraction;
+ float scale_to_fit;
+ struct {
+ float min;
+ float max;
+ } bisect;
+ bool ok;
+ int status;
+} VFontToCurveIter;
+
+enum {
+ VFONT_TO_CURVE_INIT = 0,
+ VFONT_TO_CURVE_BISECT,
+ VFONT_TO_CURVE_SCALE_ONCE,
+ VFONT_TO_CURVE_DONE,
+};
+
+#define FONT_TO_CURVE_SCALE_ITERATIONS 20
+#define FONT_TO_CURVE_SCALE_THRESHOLD 0.0001f
+
+/**
+ * Font metric values explained:
+ *
+ * Baseline: Line where the text "rests", used as the origin vertical position for the glyphs.
+ * Em height: Space most glyphs should fit within.
+ * Ascent: the recommended distance above the baseline to fit most characters.
+ * Descent: the recommended distance below the baseline to fit most characters.
+ *
+ * We obtain ascent and descent from the font itself (FT_Face->ascender / face->height).
+ * And in some cases it is even the same value as FT_Face->bbox.yMax/yMin (font top and bottom respectively).
+ *
+ * The em_height here is relative to FT_Face->bbox.
+*/
+#define ASCENT(vfd) ((vfd)->ascender * (vfd)->em_height)
+#define DESCENT(vfd) ((vfd)->em_height - ASCENT(vfd))
+
+static bool vfont_to_curve(Object *ob, Curve *cu, int mode,
+ VFontToCurveIter *iter_data,
+ ListBase *r_nubase,
const wchar_t **r_text, int *r_text_len, bool *r_text_free,
struct CharTrans **r_chartransdata)
{
@@ -648,20 +688,27 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
bool use_textbox;
VChar *che;
struct CharTrans *chartransdata = NULL, *ct;
- /* Text at the beginning of the last used text-box (use for y-axis alignment). */
- int i_textbox = 0;
struct TempLineInfo *lineinfo;
float *f, xof, yof, xtrax, linedist;
- float twidth, maxlen = 0;
+ float twidth = 0, maxlen = 0;
int i, slen, j;
int curbox;
int selstart, selend;
int cnr = 0, lnr = 0, wsnr = 0;
- const wchar_t *mem;
+ const wchar_t *mem = NULL;
wchar_t ascii;
bool ok = false;
- const float xof_scale = cu->xof / cu->fsize;
- const float yof_scale = cu->yof / cu->fsize;
+ const float font_size = cu->fsize * iter_data->scale_to_fit;
+ const float xof_scale = cu->xof / font_size;
+ const float yof_scale = cu->yof / font_size;
+ int last_line = -1;
+ /* Length of the text disregarding \n breaks. */
+ float current_line_length = 0.0f;
+ float longest_line_length = 0.0f;
+
+ /* Text at the beginning of the last used text-box (use for y-axis alignment).
+ * We overallocate by one to simplify logic of getting last char. */
+ int *i_textbox_array = MEM_callocN(sizeof(*i_textbox_array) * (cu->totbox + 1), "TextBox initial char index");
#define MARGIN_X_MIN (xof_scale + tb_scale.x)
#define MARGIN_Y_MIN (yof_scale + tb_scale.y)
@@ -738,7 +785,7 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
linedist = cu->linedist;
curbox = 0;
- textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+ textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
use_textbox = (tb_scale.w != 0.0f);
@@ -750,7 +797,7 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
oldvfont = NULL;
for (i = 0; i < slen; i++) {
- custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK);
+ custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK | CU_CHINFO_OVERFLOW);
}
for (i = 0; i <= slen; i++) {
@@ -819,6 +866,7 @@ makebreak:
{
// fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]);
for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
+ bool dobreak = false;
if (mem[j] == ' ' || mem[j] == '-') {
ct -= (i - (j - 1));
cnr -= (i - (j - 1));
@@ -828,9 +876,9 @@ makebreak:
xof = ct->xof;
ct[1].dobreak = 1;
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
- goto makebreak;
+ dobreak = true;
}
- if (chartransdata[j].dobreak) {
+ else if (chartransdata[j].dobreak) {
// fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]);
ct->dobreak = 1;
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
@@ -838,6 +886,13 @@ makebreak:
cnr -= 1;
i--;
xof = ct->xof;
+ dobreak = true;
+ }
+ if (dobreak) {
+ if (tb_scale.h == 0.0f) {
+ /* Note: If underlined text is truncated away, the extra space is also truncated. */
+ custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW;
+ }
goto makebreak;
}
}
@@ -859,16 +914,30 @@ makebreak:
CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
if ((tb_scale.h != 0.0f) &&
- (cu->totbox > (curbox + 1)) &&
((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale))
{
- i_textbox = i + 1;
- maxlen = 0;
- curbox++;
+ if (cu->totbox > (curbox + 1)) {
+ maxlen = 0;
+ curbox++;
+ i_textbox_array[curbox] = i + 1;
- textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+ textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
- yof = MARGIN_Y_MIN;
+ yof = MARGIN_Y_MIN;
+ }
+ else if (last_line == -1) {
+ last_line = lnr + 1;
+ info->flag |= CU_CHINFO_OVERFLOW;
+ }
+ }
+
+ current_line_length += xof;
+ if (ct->dobreak) {
+ current_line_length += twidth;
+ }
+ else {
+ longest_line_length = MAX2(current_line_length, longest_line_length);
+ current_line_length = 0.0f;
}
/* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
@@ -907,9 +976,9 @@ makebreak:
if (selboxes && (i >= selstart) && (i <= selend)) {
sb = &selboxes[i - selstart];
- sb->y = yof * cu->fsize - linedist * cu->fsize * 0.1f;
- sb->h = linedist * cu->fsize;
- sb->w = xof * cu->fsize;
+ sb->y = yof * font_size - linedist * font_size * 0.1f;
+ sb->h = linedist * font_size;
+ sb->w = xof * font_size;
}
if (ascii == 32) {
@@ -926,11 +995,13 @@ makebreak:
xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f)) ) + xtrax;
if (sb) {
- sb->w = (xof * cu->fsize) - sb->w;
+ sb->w = (xof * font_size) - sb->w;
}
}
ct++;
}
+ current_line_length += xof + twidth;
+ longest_line_length = MAX2(current_line_length, longest_line_length);
cu->lines = 1;
for (i = 0; i <= slen; i++) {
@@ -1019,50 +1090,73 @@ makebreak:
/* top-baseline is default, in this case, do nothing */
if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
if (tb_scale.h != 0.0f) {
- /* top and top-baseline are the same when text-boxes are used */
- if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) {
- /* all previous textboxes are 'full', only align the last used text-box */
- float yoff;
+ /* We need to loop all the text-boxes even the "full" ones.
+ * This way they all get the same vertical padding. */
+ for (int tb_index = 0; tb_index < cu->totbox; tb_index++) {
+ struct CharTrans *ct_first, *ct_last;
+ const int i_textbox = i_textbox_array[tb_index];
+ const int i_textbox_next = i_textbox_array[tb_index + 1];
+ const bool is_last_filled_textbox = ELEM(i_textbox_next, 0, slen + 1);
int lines;
- struct CharTrans *ct_last, *ct_textbox;
- ct_last = chartransdata + slen - 1;
- ct_textbox = chartransdata + i_textbox;
+ ct_first = chartransdata + i_textbox;
+ ct_last = chartransdata + (is_last_filled_textbox ? slen: i_textbox_next - 1);
+ lines = ct_last->linenr - ct_first->linenr + 1;
- lines = ct_last->linenr - ct_textbox->linenr + 1;
- if (mem[slen - 1] == '\n') {
- lines++;
- }
+ textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / font_size);
+ /* The initial Y origin of the textbox is hardcoded to 1.0f * text scale. */
+ const float textbox_y_origin = 1.0f;
+ float yoff = 0.0f;
- if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
- yoff = (lines * linedist) - tb_scale.h;
- }
- else if (cu->align_y == CU_ALIGN_Y_CENTER) {
- yoff = 0.5f * ((lines * linedist) - tb_scale.h);
+ switch (cu->align_y) {
+ case CU_ALIGN_Y_TOP_BASELINE:
+ break;
+ case CU_ALIGN_Y_TOP:
+ yoff = textbox_y_origin - ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_CENTER:
+ yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - ASCENT(vfd)) -
+ (tb_scale.h * 0.5f) + textbox_y_origin);
+ break;
+ case CU_ALIGN_Y_BOTTOM_BASELINE:
+ yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h;
+ break;
+ case CU_ALIGN_Y_BOTTOM:
+ yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h + DESCENT(vfd);
+ break;
}
- ct = ct_textbox;
- for (i = i_textbox - 1; i < slen; i++) {
+ for (ct = ct_first; ct <= ct_last; ct++) {
ct->yof += yoff;
- ct++;
+ }
+
+ if (is_last_filled_textbox) {
+ break;
}
}
}
else {
- /* non text-box case handled separately */
- ct = chartransdata;
- float yoff;
+ /* Non text-box case handled separately. */
+ float yoff = 0.0f;
- if (cu->align_y == CU_ALIGN_Y_TOP) {
- yoff = -linedist;
- }
- else if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
- yoff = (lnr - 1.0f) * linedist;
- }
- else if (cu->align_y == CU_ALIGN_Y_CENTER) {
- yoff = (lnr - 2.0f) * linedist * 0.5f;
+ switch (cu->align_y) {
+ case CU_ALIGN_Y_TOP_BASELINE:
+ break;
+ case CU_ALIGN_Y_TOP:
+ yoff = -ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_CENTER:
+ yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_BOTTOM_BASELINE:
+ yoff = (lnr - 1) * linedist;
+ break;
+ case CU_ALIGN_Y_BOTTOM:
+ yoff = (lnr - 1) * linedist + DESCENT(vfd);
+ break;
}
+ ct = chartransdata;
for (i = 0; i <= slen; i++) {
ct->yof += yoff;
ct++;
@@ -1071,12 +1165,13 @@ makebreak:
}
MEM_freeN(lineinfo);
+ MEM_freeN(i_textbox_array);
/* TEXT ON CURVE */
/* Note: Only OB_CURVE objects could have a path */
if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) {
- BLI_assert(cu->textoncurve->curve_cache != NULL);
- if (cu->textoncurve->curve_cache->path) {
+ BLI_assert(cu->textoncurve->runtime.curve_cache != NULL);
+ if (cu->textoncurve->runtime.curve_cache != NULL && cu->textoncurve->runtime.curve_cache->path != NULL) {
float distfac, imat[4][4], imat3[3][3], cmat[3][3];
float minx, maxx, miny, maxy;
float timeofs, sizefac;
@@ -1091,7 +1186,7 @@ makebreak:
copy_m3_m4(cmat, cu->textoncurve->obmat);
mul_m3_m3m3(cmat, cmat, imat3);
- sizefac = normalize_v3(cmat[0]) / cu->fsize;
+ sizefac = normalize_v3(cmat[0]) / font_size;
minx = miny = 1.0e20f;
maxx = maxy = -1.0e20f;
@@ -1106,7 +1201,7 @@ makebreak:
/* we put the x-coordinaat exact at the curve, the y is rotated */
/* length correction */
- distfac = sizefac * cu->textoncurve->curve_cache->path->totdist / (maxx - minx);
+ distfac = sizefac * cu->textoncurve->runtime.curve_cache->path->totdist / (maxx - minx);
timeofs = 0.0f;
if (distfac > 1.0f) {
@@ -1184,19 +1279,21 @@ makebreak:
ct = chartransdata;
for (i = 0; i <= selend; i++, ct++) {
if (i >= selstart) {
- selboxes[i - selstart].x = ct->xof * cu->fsize;
- selboxes[i - selstart].y = ct->yof * cu->fsize;
+ selboxes[i - selstart].x = ct->xof * font_size;
+ selboxes[i - selstart].y = ct->yof * font_size;
}
}
}
- if (mode == FO_CURSUP || mode == FO_CURSDOWN || mode == FO_PAGEUP || mode == FO_PAGEDOWN) {
+ if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN) &&
+ iter_data->status == VFONT_TO_CURVE_INIT)
+ {
ct = &chartransdata[ef->pos];
- if ((mode == FO_CURSUP || mode == FO_PAGEUP) && ct->linenr == 0) {
+ if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) {
/* pass */
}
- else if ((mode == FO_CURSDOWN || mode == FO_PAGEDOWN) && ct->linenr == lnr) {
+ else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) {
/* pass */
}
else {
@@ -1235,27 +1332,25 @@ makebreak:
f = ef->textcurs[0];
- f[0] = cu->fsize * (-0.1f * co + ct->xof);
- f[1] = cu->fsize * ( 0.1f * si + ct->yof);
+ f[0] = font_size * (-0.1f * co + ct->xof);
+ f[1] = font_size * ( 0.1f * si + ct->yof);
- f[2] = cu->fsize * ( 0.1f * co + ct->xof);
- f[3] = cu->fsize * (-0.1f * si + ct->yof);
+ f[2] = font_size * ( 0.1f * co + ct->xof);
+ f[3] = font_size * (-0.1f * si + ct->yof);
- f[4] = cu->fsize * ( 0.1f * co + 0.8f * si + ct->xof);
- f[5] = cu->fsize * (-0.1f * si + 0.8f * co + ct->yof);
+ f[4] = font_size * ( 0.1f * co + 0.8f * si + ct->xof);
+ f[5] = font_size * (-0.1f * si + 0.8f * co + ct->yof);
- f[6] = cu->fsize * (-0.1f * co + 0.8f * si + ct->xof);
- f[7] = cu->fsize * ( 0.1f * si + 0.8f * co + ct->yof);
+ f[6] = font_size * (-0.1f * co + 0.8f * si + ct->xof);
+ f[7] = font_size * ( 0.1f * si + 0.8f * co + ct->yof);
}
if (mode == FO_SELCHANGE) {
MEM_freeN(chartransdata);
chartransdata = NULL;
- goto finally;
}
-
- if (mode == FO_EDIT) {
+ else if (mode == FO_EDIT) {
/* make nurbdata */
BKE_nurbList_free(r_nubase);
@@ -1264,6 +1359,13 @@ makebreak:
unsigned int cha = (unsigned int) mem[i];
info = &(custrinfo[i]);
+ if ((cu->overflow == CU_OVERFLOW_TRUNCATE) &&
+ (ob && ob->mode != OB_MODE_EDIT) &&
+ (info->flag & CU_CHINFO_OVERFLOW))
+ {
+ break;
+ }
+
if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
cha = towupper(cha);
}
@@ -1274,7 +1376,7 @@ makebreak:
}
/* We do not want to see any character for \n or \r */
if (cha != '\n')
- buildchar(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i);
+ buildchar(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i, font_size);
if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {
float ulwidth, uloverlap = 0.0f;
@@ -1301,17 +1403,134 @@ makebreak:
build_underline(cu, r_nubase,
&rect, cu->ulpos - 0.05f,
- ct->rot, i, info->mat_nr);
+ ct->rot, i, info->mat_nr,
+ font_size);
}
ct++;
}
}
- ok = true;
+ if (iter_data->status == VFONT_TO_CURVE_SCALE_ONCE) {
+ /* That means we were in a final run, just exit. */
+ BLI_assert(cu->overflow == CU_OVERFLOW_SCALE);
+ iter_data->status = VFONT_TO_CURVE_DONE;
+ }
+ else if (cu->overflow == CU_OVERFLOW_NONE) {
+ /* Do nothing. */
+ }
+ else if ((tb_scale.h == 0.0f) && (tb_scale.w == 0.0f)) {
+ /* Do nothing. */
+ }
+ else if (cu->overflow == CU_OVERFLOW_SCALE) {
+ if ((cu->totbox == 1) && ((tb_scale.w == 0.0f) || (tb_scale.h == 0.0f))) {
+ /* These are special cases, simpler to deal with. */
+ if (tb_scale.w == 0.0f) {
+ /* This is a potential vertical overflow.
+ * Since there is no width limit, all the new lines are from line breaks. */
+ if ((last_line != -1) && (lnr > last_line)) {
+ const float total_text_height = lnr * linedist;
+ iter_data->scale_to_fit = tb_scale.h / total_text_height;
+ iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
+ }
+ }
+ else if (tb_scale.h == 0.0f) {
+ /* This is a horizontal overflow. */
+ if (lnr > 1) {
+ /* We make sure longest line before it broke can fit here. */
+ float scale_to_fit = tb_scale.w / (longest_line_length);
+ scale_to_fit -= FLT_EPSILON;
+
+ iter_data->scale_to_fit = scale_to_fit;
+ iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
+ }
+ }
+ }
+ else {
+ /* This is the really complicated case, the best we can do is to iterate over
+ * this function a few times until we get an acceptable result.
+ *
+ * Keep in mind that there is no single number that will make all fit to the end.
+ * In a way, our ultimate goal is to get the highest scale that still leads to the
+ * number of extra lines to zero.
+ */
+ if (iter_data->status == VFONT_TO_CURVE_INIT) {
+ bool valid = true;
+
+ for (int tb_index = 0; tb_index <= curbox; tb_index++) {
+ TextBox *tb = &cu->tb[tb_index];
+ if ((tb->w == 0.0f) || (tb->h == 0.0f)) {
+ valid = false;
+ break;
+ }
+ }
-finally:
+ if (valid && (last_line != -1) && (lnr > last_line)) {
+ const float total_text_height = lnr * linedist;
+ float scale_to_fit = tb_scale.h / total_text_height;
+
+ iter_data->bisect.max = 1.0f;
+ iter_data->bisect.min = scale_to_fit;
+ iter_data->status = VFONT_TO_CURVE_BISECT;
+ }
+ }
+ else {
+ BLI_assert(iter_data->status == VFONT_TO_CURVE_BISECT);
+ /* Try to get the highest scale that gives us the exactly
+ * number of lines we need. */
+ bool valid = false;
+
+ if ((last_line != -1) && (lnr > last_line)) {
+ /* It is overflowing, scale it down. */
+ iter_data->bisect.max = iter_data->scale_to_fit;
+ }
+ else {
+ /* It fits inside the textbox, scale it up. */
+ iter_data->bisect.min = iter_data->scale_to_fit;
+ valid = true;
+ }
+
+ /* Bisecting to try to find the best fit. */
+ iter_data->scale_to_fit = (iter_data->bisect.max + iter_data->bisect.min) * 0.5f;
+
+ /* We iterated enough or got a good enough result. */
+ if ((!iter_data->iteraction--) ||
+ ((iter_data->bisect.max - iter_data->bisect.min) < (cu->fsize * FONT_TO_CURVE_SCALE_THRESHOLD)))
+ {
+ if (valid) {
+ iter_data->status = VFONT_TO_CURVE_DONE;
+ }
+ else {
+ iter_data->scale_to_fit = iter_data->bisect.min;
+ iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
+ }
+ }
+ }
+ }
+ }
+
+ /* Scale to fit only works for single text box layouts. */
+ if (ELEM(iter_data->status,
+ VFONT_TO_CURVE_SCALE_ONCE,
+ VFONT_TO_CURVE_BISECT))
{
+ /* Always cleanup before going to the scale-to-fit repetition. */
+ if (r_nubase != NULL) {
+ BKE_nurbList_free(r_nubase);
+ }
+
+ if (chartransdata != NULL) {
+ MEM_freeN(chartransdata);
+ }
+
+ if (ef == NULL) {
+ MEM_freeN((void *)mem);
+ }
+ return true;
+ }
+ else {
+ ok = true;
+finally:
if (r_text) {
*r_text = mem;
*r_text_len = slen;
@@ -1322,23 +1541,58 @@ finally:
MEM_freeN((void *)mem);
}
}
- }
- if (chartransdata) {
- if (ok && r_chartransdata) {
- *r_chartransdata = chartransdata;
- }
- else {
- MEM_freeN(chartransdata);
+ if (chartransdata) {
+ if (ok && r_chartransdata) {
+ *r_chartransdata = chartransdata;
+ }
+ else {
+ MEM_freeN(chartransdata);
+ }
}
- }
+ /* Store the effective scale, to use for the textbox lines. */
+ cu->fsize_realtime = font_size;
+ }
return ok;
#undef MARGIN_X_MIN
#undef MARGIN_Y_MIN
}
+#undef DESCENT
+#undef ASCENT
+
+bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
+ const wchar_t **r_text, int *r_text_len, bool *r_text_free,
+ struct CharTrans **r_chartransdata)
+{
+ VFontToCurveIter data = {
+ .iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS,
+ .scale_to_fit = 1.0f,
+ .ok = true,
+ .status = VFONT_TO_CURVE_INIT,
+ };
+
+ do {
+ data.ok &= vfont_to_curve(ob,
+ cu,
+ mode,
+ &data,
+ r_nubase,
+ r_text,
+ r_text_len,
+ r_text_free,
+ r_chartransdata);
+ } while (data.ok && ELEM(data.status,
+ VFONT_TO_CURVE_SCALE_ONCE,
+ VFONT_TO_CURVE_BISECT));
+
+ return data.ok;
+}
+
+#undef FONT_TO_CURVE_SCALE_ITERATIONS
+#undef FONT_TO_CURVE_SCALE_THRESHOLD
bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
{
@@ -1348,6 +1602,7 @@ bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
NULL, NULL, NULL, NULL);
}
+/** Warning: expects to have access to evaluated data (i.e. passed object should be evaluated one...). */
bool BKE_vfont_to_curve(Object *ob, int mode)
{
Curve *cu = ob->data;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 686fe3bda93..57a2d2d4134 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -31,8 +31,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_freestyle_types.h"
-#include "DNA_group_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -61,17 +61,21 @@ void BKE_freestyle_config_init(FreestyleConfig *config)
BLI_listbase_clear(&config->linesets);
}
-void BKE_freestyle_config_free(FreestyleConfig *config)
+void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user)
{
FreestyleLineSet *lineset;
for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
if (lineset->group) {
- id_us_min(&lineset->group->id);
+ if (do_id_user) {
+ id_us_min(&lineset->group->id);
+ }
lineset->group = NULL;
}
if (lineset->linestyle) {
- id_us_min(&lineset->linestyle->id);
+ if (do_id_user) {
+ id_us_min(&lineset->linestyle->id);
+ }
lineset->linestyle = NULL;
}
}
@@ -79,7 +83,7 @@ void BKE_freestyle_config_free(FreestyleConfig *config)
BLI_freelistN(&config->modules);
}
-void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag)
+void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag)
{
FreestyleLineSet *lineset, *new_lineset;
FreestyleModuleConfig *module, *new_module;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index a0d759118ec..e694c12e543 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -39,26 +39,84 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
#include "BLI_string_utils.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
#include "BLT_translation.h"
+#include "DNA_anim_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_userdef_types.h"
#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "BKE_context.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
+#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_colortools.h"
+#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_material.h"
+#include "DEG_depsgraph.h"
/* ************************************************** */
-/* GENERAL STUFF */
+/* Draw Engine */
-/* --------- Memory Management ------------ */
+void(*BKE_gpencil_batch_cache_dirty_tag_cb)(bGPdata *gpd) = NULL;
+void(*BKE_gpencil_batch_cache_free_cb)(bGPdata *gpd) = NULL;
+
+void BKE_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
+{
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+ BKE_gpencil_batch_cache_dirty_tag_cb(gpd);
+ }
+}
+
+void BKE_gpencil_batch_cache_free(bGPdata *gpd)
+{
+ if (gpd) {
+ BKE_gpencil_batch_cache_free_cb(gpd);
+ }
+}
+
+/* ************************************************** */
+/* Memory Management */
+
+/* clean vertex groups weights */
+void BKE_gpencil_free_point_weights(MDeformVert *dvert)
+{
+ if (dvert == NULL) {
+ return;
+ }
+ MEM_SAFE_FREE(dvert->dw);
+}
+
+void BKE_gpencil_free_stroke_weights(bGPDstroke *gps)
+{
+ if (gps == NULL) {
+ return;
+ }
+
+ if (gps->dvert == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+}
/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(bGPDstroke *gps)
@@ -66,10 +124,14 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps)
if (gps == NULL) {
return;
}
-
/* free stroke memory arrays, then stroke itself */
- if (gps->points)
+ if (gps->points) {
MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
if (gps->triangles)
MEM_freeN(gps->triangles);
@@ -92,6 +154,24 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf)
return changed;
}
+/* Free strokes and colors belonging to a gp-frame */
+bool BKE_gpencil_free_frame_runtime_data(bGPDframe *derived_gpf)
+{
+ bGPDstroke *gps_next;
+ if (!derived_gpf) {
+ return false;
+ }
+
+ /* free strokes */
+ for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ BKE_gpencil_free_stroke(gps);
+ }
+ BLI_listbase_clear(&derived_gpf->strokes);
+
+ return true;
+}
+
/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
@@ -111,67 +191,7 @@ void BKE_gpencil_free_frames(bGPDlayer *gpl)
gpl->actframe = NULL;
}
-/* Free all of a gp-colors */
-static void free_gpencil_colors(bGPDpalette *palette)
-{
- /* error checking */
- if (palette == NULL) {
- return;
- }
-
- /* free colors */
- BLI_freelistN(&palette->colors);
-}
-
-/* Free all of the gp-palettes and colors */
-void BKE_gpencil_free_palettes(ListBase *list)
-{
- 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 BKE_gpencil_free_layers(ListBase *list)
@@ -192,20 +212,26 @@ void BKE_gpencil_free_layers(ListBase *list)
}
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
-void BKE_gpencil_free(bGPdata *gpd, bool free_palettes)
+void BKE_gpencil_free(bGPdata *gpd, bool free_all)
{
+ /* clear animation data */
BKE_animdata_free(&gpd->id, false);
/* free layers */
BKE_gpencil_free_layers(&gpd->layers);
- /* free palettes */
- if (free_palettes) {
- BKE_gpencil_free_palettes(&gpd->palettes);
+ /* materials */
+ MEM_SAFE_FREE(gpd->mat);
+
+ /* free all data */
+ if (free_all) {
+ /* clear cache */
+ BKE_gpencil_batch_cache_free(gpd);
}
}
-/* -------- Container Creation ---------- */
+/* ************************************************** */
+/* Container Creation */
/* add a new gp-frame to the given layer */
bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
@@ -317,7 +343,8 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
/* add a new gp-layer and make it the active layer */
bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
{
- bGPDlayer *gpl;
+ bGPDlayer *gpl = NULL;
+ bGPDlayer *gpl_active = NULL;
/* check that list is ok */
if (gpd == NULL)
@@ -326,31 +353,45 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
/* allocate memory for frame and add to end of list */
gpl = MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
- /* add to datablock */
- BLI_addtail(&gpd->layers, gpl);
-
- /* set basic settings */
- copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
- /* Since GPv2 thickness must be 0 */
- gpl->thickness = 0;
+ gpl_active = BKE_gpencil_layer_getactive(gpd);
- gpl->opacity = 1.0f;
-
- /* onion-skinning settings */
- if (gpd->flag & GP_DATA_SHOW_ONIONSKINS)
- gpl->flag |= GP_LAYER_ONIONSKIN;
+ /* add to datablock */
+ if (gpl_active == NULL) {
+ BLI_addtail(&gpd->layers, gpl);
+ }
+ else {
+ /* if active layer, add after that layer */
+ BLI_insertlinkafter(&gpd->layers, gpl_active, gpl);
+ }
- gpl->flag |= (GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL);
+ /* annotation vs GP Object behaviour is slightly different */
+ if (gpd->flag & GP_DATA_ANNOTATIONS) {
+ /* set default color of new strokes for this layer */
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
+ gpl->opacity = 1.0f;
- ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
- ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ /* set default thickness of new strokes for this layer */
+ gpl->thickness = 3;
- /* high quality fill by default */
- gpl->flag |= GP_LAYER_HQ_FILL;
+ /* Onion colors */
+ ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f);
+ ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f);
+ }
+ else {
+ /* thickness parameter represents "thickness change", not absolute thickness */
+ gpl->thickness = 0;
+ gpl->opacity = 1.0f;
+ /* onion-skinning settings */
+ gpl->onion_flag |= GP_LAYER_ONIONSKIN;
+ }
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
- BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+ BLI_uniquename(&gpd->layers, gpl,
+ (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),
+ '.',
+ offsetof(bGPDlayer, info),
+ sizeof(gpl->info));
/* make this one the active one */
if (setactive)
@@ -360,292 +401,148 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
return gpl;
}
-/* add a new gp-palette and make it the active */
-bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive)
-{
- bGPDpalette *palette;
-
- /* check that list is ok */
- if (gpd == NULL) {
- return NULL;
- }
-
- /* allocate memory and add to end of list */
- palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette");
-
- /* add to datablock */
- BLI_addtail(&gpd->palettes, palette);
-
- /* set basic settings */
- /* auto-name */
- BLI_strncpy(palette->info, name, sizeof(palette->info));
- BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
- sizeof(palette->info));
-
- /* make this one the active one */
- /* NOTE: Always make this active if there's nothing else yet (T50123) */
- if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) {
- BKE_gpencil_palette_setactive(gpd, palette);
- }
-
- /* return palette */
- return palette;
-}
-
-/* create a set of default drawing brushes with predefined presets */
-void BKE_gpencil_brush_init_presets(ToolSettings *ts)
+/* add a new gp-datablock */
+bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
- bGPDbrush *brush;
- /* Basic brush */
- brush = BKE_gpencil_brush_addnew(ts, "Basic", true);
- brush->thickness = 3.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
-
- brush->draw_smoothfac = 0.0f;
- brush->draw_smoothlvl = 1;
- brush->sublevel = 0;
- brush->draw_random_sub = 0.0f;
-
- /* Pencil brush */
- brush = BKE_gpencil_brush_addnew(ts, "Pencil", false);
- brush->thickness = 7.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 0.7f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
-
- brush->draw_smoothfac = 1.0f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
-
- /* Ink brush */
- brush = BKE_gpencil_brush_addnew(ts, "Ink", false);
- brush->thickness = 7.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.6f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ bGPdata *gpd;
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ /* allocate memory for a new block */
+ gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
- brush->draw_smoothfac = 1.1f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+ /* initial settings */
+ gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
- /* 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;
+ /* general flags */
+ gpd->flag |= GP_DATA_VIEWALIGN;
+ gpd->flag |= GP_DATA_STROKE_FORCE_RECALC;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ /* GP object specific settings */
+ ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
- brush->draw_random_press = 1.0f;
+ gpd->xray_mode = GP_XRAY_3DSPACE;
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ /* grid settings */
+ ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color
+ ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale
+ gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ /* onion-skinning settings (datablock level) */
+ gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
+ gpd->onion_flag |= GP_ONION_FADE;
+ gpd->onion_mode = GP_ONION_MODE_RELATIVE;
+ gpd->onion_factor = 0.5f;
+ ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
+ ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ gpd->gstep = 1;
+ gpd->gstep_next = 1;
- brush->draw_smoothfac = 1.1f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+ return gpd;
+}
- /* Marker brush */
- brush = BKE_gpencil_brush_addnew(ts, "Marker", false);
- brush->thickness = 10.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 2.0f;
- brush->flag &= ~GP_BRUSH_USE_PRESSURE;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+/* ************************************************** */
+/* Primitive Creation */
+/* Utilities for easier bulk-creation of geometry */
- brush->draw_random_press = 0.0f;
+/**
+ * Populate stroke with point data from data buffers
+ *
+ * \param array Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values
+ * \param mat 4x4 transform matrix to transform points into the right coordinate space
+ */
+void BKE_gpencil_stroke_add_points(bGPDstroke *gps, const float *array, const int totpoints, const float mat[4][4])
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ const int x = GP_PRIM_DATABUF_SIZE * i;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ pt->x = array[x];
+ pt->y = array[x + 1];
+ pt->z = array[x + 2];
+ mul_m4_v3(mat, &pt->x);
- brush->draw_angle = M_PI_4; /* 45 degrees */
- brush->draw_angle_factor = 1.0f;
+ pt->pressure = array[x + 3];
+ pt->strength = array[x + 4];
+ }
+}
- brush->draw_smoothfac = 1.0f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+/* Create a new stroke, with pre-allocated data buffers */
+bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness)
+{
+ /* allocate memory for a new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- /* Crayon brush */
- brush = BKE_gpencil_brush_addnew(ts, "Crayon", false);
- brush->thickness = 10.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 3.0f;
- brush->flag &= ~GP_BRUSH_USE_PRESSURE;
+ gps->thickness = thickness * 25;
+ gps->inittime = 0;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 0.140f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ /* enable recalculation flag by default */
+ gps->flag = GP_STROKE_RECALC_CACHES | GP_STROKE_3DSPACE;
- brush->draw_random_press = 0.0f;
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ /* initialize triangle memory to dummy data */
+ gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ gps->mat_nr = mat_idx;
- brush->draw_smoothfac = 0.0f;
- brush->draw_smoothlvl = 1;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.5f;
+ /* add to frame */
+ BLI_addtail(&gpf->strokes, gps);
+ return gps;
}
-/* add a new gp-brush and make it the active */
-bGPDbrush *BKE_gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive)
-{
- bGPDbrush *brush;
- /* check that list is ok */
- if (ts == NULL) {
- return NULL;
- }
-
- /* allocate memory and add to end of list */
- brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush");
-
- /* add to datablock */
- BLI_addtail(&ts->gp_brushes, brush);
-
- /* set basic settings */
- brush->thickness = 3;
- brush->draw_smoothlvl = 1;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->draw_strength = 1.0f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- /* curves */
- brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
-
- /* auto-name */
- BLI_strncpy(brush->info, name, sizeof(brush->info));
- BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
+/* ************************************************** */
+/* Data Duplication */
- /* make this one the active one */
- if (setactive) {
- BKE_gpencil_brush_setactive(ts, brush);
+/* make a copy of a given gpencil weights */
+void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
+{
+ if (gps_src == NULL) {
+ return;
}
+ BLI_assert(gps_src->totpoints == gps_dst->totpoints);
- /* return brush */
- return brush;
+ BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
}
-/* add a new gp-palettecolor and make it the active */
-bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive)
+/* make a copy of a given gpencil stroke */
+bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src)
{
- bGPDpalettecolor *palcolor;
+ bGPDstroke *gps_dst = NULL;
- /* check that list is ok */
- if (palette == NULL) {
- return NULL;
- }
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->prev = gps_dst->next = NULL;
- /* allocate memory and add to end of list */
- palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor");
+ gps_dst->points = MEM_dupallocN(gps_src->points);
- /* 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);
+ if (gps_src->dvert != NULL) {
+ gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
+ }
+ else {
+ gps_dst->dvert = NULL;
}
- /* return palette color */
- return palcolor;
-}
-
-/* add a new gp-datablock */
-bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
-{
- bGPdata *gpd;
-
- /* allocate memory for a new block */
- gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
-
- /* initial settings */
- gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
-
- /* for now, stick to view is also enabled by default
- * since this is more useful...
+ /* Don't clear triangles, so that modifier evaluation can just use
+ * this without extra work first. Most places that need to force
+ * this data to get recalculated will destroy the data anyway though.
*/
- gpd->flag |= GP_DATA_VIEWALIGN;
+ gps_dst->triangles = MEM_dupallocN(gps_dst->triangles);
+ /* gps_dst->flag |= GP_STROKE_RECALC_CACHES; */
- return gpd;
+ /* return new stroke */
+ return gps_dst;
}
-/* -------- Data Duplication ---------- */
-
/* make a copy of a given gpencil frame */
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
{
- bGPDstroke *gps_dst;
+ bGPDstroke *gps_dst = NULL;
bGPDframe *gpf_dst;
/* error checking */
@@ -660,11 +557,8 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
/* copy strokes */
BLI_listbase_clear(&gpf_dst->strokes);
for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke, then adjust pointer to points too */
- gps_dst = MEM_dupallocN(gps_src);
- gps_dst->points = MEM_dupallocN(gps_src->points);
- gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
- gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
@@ -672,55 +566,24 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
return gpf_dst;
}
-/* make a copy of a given gpencil brush */
-bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src)
-{
- 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)
+/* make a copy of strokes between gpencil frames */
+void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst)
{
- bGPDpalette *palette_dst;
- const bGPDpalettecolor *palcolor_src;
- bGPDpalettecolor *palcolord_dst;
-
+ bGPDstroke *gps_dst = NULL;
/* error checking */
- if (palette_src == NULL) {
- return NULL;
+ if ((gpf_src == NULL) || (gpf_dst == NULL)) {
+ return;
}
- /* make a copy of source palette */
- palette_dst = MEM_dupallocN(palette_src);
- palette_dst->prev = palette_dst->next = NULL;
-
- /* copy colors */
- BLI_listbase_clear(&palette_dst->colors);
- for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) {
- /* make a copy of source */
- palcolord_dst = MEM_dupallocN(palcolor_src);
- BLI_addtail(&palette_dst->colors, palcolord_dst);
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
}
-
- /* return new palette */
- return palette_dst;
}
+
/* make a copy of a given gpencil layer */
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
{
@@ -755,14 +618,19 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/**
* Only copy internal data of GreasePencil ID from source to already allocated/initialized destination.
- * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ * You probably never want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
*
* WARNING! This function will not handle ID user count!
*
* \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
+void BKE_gpencil_copy_data(bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
{
+ /* duplicate material array */
+ if (gpd_src->mat) {
+ gpd_dst->mat = MEM_dupallocN(gpd_src->mat);
+ }
+
/* copy layers */
BLI_listbase_clear(&gpd_dst->layers);
for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
@@ -771,45 +639,45 @@ void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata
BLI_addtail(&gpd_dst->layers, gpl_dst);
}
- /* copy palettes */
- BLI_listbase_clear(&gpd_dst->palettes);
- for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
- bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */
- BLI_addtail(&gpd_dst->palettes, palette_dst);
- }
+}
+
+/* Standard API to make a copy of GP datablock, separate from copying its data */
+bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
+{
+ bGPdata *gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd->id, (ID **)&gpd_copy, 0, false);
+ return gpd_copy;
}
/* make a copy of a given gpencil datablock */
+// XXX: Should this be deprecated?
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
+ bGPdata *gpd_dst;
+
/* Yuck and super-uber-hyper yuck!!!
* Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
* so for now keep old code for that one. */
- if (internal_copy) {
- const bGPDlayer *gpl_src;
- bGPDlayer *gpl_dst;
- bGPdata *gpd_dst;
+ /* error checking */
+ if (gpd_src == NULL) {
+ return NULL;
+ }
+
+ if (internal_copy) {
/* make a straight copy for undo buffers used during stroke drawing */
gpd_dst = MEM_dupallocN(gpd_src);
-
- /* copy layers */
- BLI_listbase_clear(&gpd_dst->layers);
- for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
- /* make a copy of source layer and its data */
- gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- }
-
- /* return new */
- return gpd_dst;
}
else {
BLI_assert(bmain != NULL);
- bGPdata *gpd_copy;
- BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false);
- return gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_dst, 0, false);
}
+
+ /* Copy internal data (layers, etc.) */
+ BKE_gpencil_copy_data(gpd_dst, gpd_src, 0);
+
+ /* return new */
+ return gpd_dst;
}
void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
@@ -817,7 +685,8 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local);
}
-/* -------- GP-Stroke API --------- */
+/* ************************************************** */
+/* GP Stroke API */
/* ensure selection status of stroke is in sync with its points */
void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
@@ -842,7 +711,8 @@ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
}
}
-/* -------- GP-Frame API ---------- */
+/* ************************************************** */
+/* GP Frame API */
/* delete the last stroke of the given frame */
void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
@@ -855,18 +725,25 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
return;
/* free the stroke and its data */
- MEM_freeN(gps->points);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
/* if frame has no strokes after this, delete it */
if (BLI_listbase_is_empty(&gpf->strokes)) {
BKE_gpencil_layer_delframe(gpl, gpf);
- BKE_gpencil_layer_getframe(gpl, cfra, 0);
+ BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
}
}
-/* -------- GP-Layer API ---------- */
+/* ************************************************** */
+/* GP Layer API */
/* Check if the given layer is able to be edited or not */
bool gpencil_layer_is_editable(const bGPDlayer *gpl)
@@ -1048,8 +925,6 @@ bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
*/
if (gpl->actframe == gpf)
gpl->actframe = gpf->prev;
- else
- gpl->actframe = NULL;
/* free the frame and its data */
changed = BKE_gpencil_free_strokes(gpf);
@@ -1087,11 +962,18 @@ void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
return;
/* loop over layers deactivating all */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next)
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
gpl->flag &= ~GP_LAYER_ACTIVE;
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
+ }
/* set as active one */
active->flag |= GP_LAYER_ACTIVE;
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ active->flag &= ~GP_LAYER_LOCKED;
+ }
}
/* delete the active gp-layer */
@@ -1103,255 +985,578 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
/* free layer */
BKE_gpencil_free_frames(gpl);
+
+ /* free icon providing preview of icon color */
+ BKE_icon_delete(gpl->runtime.icon_id);
+
BLI_freelinkN(&gpd->layers, gpl);
}
-/* ************************************************** */
-/* get the active gp-brush for editing */
-bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts)
+Material *BKE_gpencil_get_material_from_brush(Brush *brush)
{
- bGPDbrush *brush;
+ Material *ma = NULL;
- /* error checking */
- if (ELEM(NULL, ts, ts->gp_brushes.first)) {
- return NULL;
+ if ((brush != NULL) && (brush->gpencil_settings != NULL) &&
+ (brush->gpencil_settings->material != NULL))
+ {
+ ma = brush->gpencil_settings->material;
}
- /* loop over brushes until found (assume only one active) */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- if (brush->flag & GP_BRUSH_ACTIVE) {
- return brush;
+ return ma;
+}
+
+/* Get active color, and add all default settings if we don't find anything */
+Material *BKE_gpencil_material_ensure(Main *bmain, Object *ob)
+{
+ Material *ma = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, bmain, ob))
+ return NULL;
+
+ ma = give_current_material(ob, ob->actcol);
+ if (ma == NULL) {
+ if (ob->totcol == 0) {
+ BKE_object_material_slot_add(bmain, ob);
}
+ ma = BKE_material_add_gpencil(bmain, DATA_("Material"));
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+ else if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
}
- /* no active brush found */
- return NULL;
+ return ma;
}
-/* set the active gp-brush */
-void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active)
+/* ************************************************** */
+/* GP Object - Boundbox Support */
+
+/**
+ * Get min/max coordinate bounds for single stroke
+ * \return Returns whether we found any selected points
+ */
+bool BKE_gpencil_stroke_minmax(
+ const bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3])
{
- bGPDbrush *brush;
+ const bGPDspoint *pt;
+ int i;
+ bool changed = false;
- /* error checking */
- if (ELEM(NULL, ts, ts->gp_brushes.first, active)) {
- return;
- }
+ if (ELEM(NULL, gps, r_min, r_max))
+ return false;
- /* loop over brushes deactivating all */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- brush->flag &= ~GP_BRUSH_ACTIVE;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {
+ minmax_v3v3_v3(r_min, r_max, &pt->x);
+ changed = true;
+ }
}
-
- /* set as active one */
- active->flag |= GP_BRUSH_ACTIVE;
+ return changed;
}
-/* delete the active gp-brush */
-void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush)
+/* get min/max bounds of all strokes in GP datablock */
+bool BKE_gpencil_data_minmax(Object *ob, const bGPdata *gpd, float r_min[3], float r_max[3])
{
- /* error checking */
- if (ELEM(NULL, ts, brush)) {
- return;
- }
+ float bmat[3][3];
+ bool changed = false;
- /* free curves */
- if (brush->cur_sensitivity) {
- curvemapping_free(brush->cur_sensitivity);
+ INIT_MINMAX(r_min, r_max);
+
+ if (gpd == NULL)
+ return changed;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = gpl->actframe;
+
+ if (gpf != NULL) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ changed = BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
+ }
+ }
}
- if (brush->cur_strength) {
- curvemapping_free(brush->cur_strength);
+
+ if ((changed) && (ob)) {
+ copy_m3_m4(bmat, ob->obmat);
+ mul_m3_v3(bmat, r_min);
+ add_v3_v3(r_min, ob->obmat[3]);
+ mul_m3_v3(bmat, r_max);
+ add_v3_v3(r_max, ob->obmat[3]);
}
- if (brush->cur_jitter) {
- curvemapping_free(brush->cur_jitter);
+
+ return changed;
+}
+
+bool BKE_gpencil_stroke_select_check(
+ const bGPDstroke *gps)
+{
+ const bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ return true;
+ }
}
+ return false;
+}
- /* free */
- BLI_freelinkN(&ts->gp_brushes, brush);
+/* compute center of bounding box */
+void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
+{
+ float min[3], max[3], tot[3];
+
+ BKE_gpencil_data_minmax(NULL, gpd, min, max);
+
+ add_v3_v3v3(tot, min, max);
+ mul_v3_v3fl(r_centroid, tot, 0.5f);
}
-/* ************************************************** */
-/* get the active gp-palette for editing */
-bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd)
+
+/* create bounding box values */
+static void boundbox_gpencil(Object *ob)
{
- bGPDpalette *palette;
+ BoundBox *bb;
+ bGPdata *gpd;
+ float min[3], max[3];
- /* error checking */
- if (ELEM(NULL, gpd, gpd->palettes.first)) {
- return NULL;
+ if (ob->bb == NULL) {
+ ob->bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
}
- /* 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;
- }
+ bb = ob->bb;
+ gpd = ob->data;
- /* no active palette found */
- return NULL;
+ BKE_gpencil_data_minmax(NULL, gpd, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
+
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
-/* set the active gp-palette */
-void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active)
+/* get bounding box */
+BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
- bGPDpalette *palette;
+ bGPdata *gpd;
- /* error checking */
- if (ELEM(NULL, gpd, gpd->palettes.first, active)) {
- return;
- }
+ if (ELEM(NULL, ob, ob->data))
+ return NULL;
- /* loop over palettes deactivating all */
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- palette->flag &= ~PL_PALETTE_ACTIVE;
+ gpd = ob->data;
+ if ((ob->bb) && ((ob->bb->flag & BOUNDBOX_DIRTY) == 0) &&
+ ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0))
+ {
+ return ob->bb;
}
- /* set as active one */
- active->flag |= PL_PALETTE_ACTIVE;
- /* force color recalc */
- BKE_gpencil_palette_change_strokes(gpd);
+ boundbox_gpencil(ob);
+
+ return ob->bb;
}
-/* delete the active gp-palette */
-void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette)
+/* ************************************************** */
+/* Apply Transforms */
+
+void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
{
- /* error checking */
- if (ELEM(NULL, gpd, palette)) {
+ if (gpd == NULL)
return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* FIXME: For now, we just skip parented layers.
+ * Otherwise, we have to update each frame to find
+ * the current parent position/effects.
+ */
+ if (gpl->parent) {
+ continue;
+ }
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) {
+ mul_m4_v3(mat, &pt->x);
+ }
+
+ /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ }
+ }
}
- /* 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;
+/* ************************************************** */
+/* GP Object - Vertex Groups */
- 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;
+/* remove a vertex group */
+void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
+{
+ bGPdata *gpd = ob->data;
+ MDeformVert *dvert = NULL;
+ const int def_nr = BLI_findindex(&ob->defbase, defgroup);
+
+ /* Remove points data */
+ if (gpd) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->dvert != NULL) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ MDeformWeight *dw = defvert_find_index(dvert, def_nr);
+ if (dw != NULL) {
+ defvert_remove_group(dvert, dw);
+ }
+ }
+ }
+ }
}
}
}
+
+ /* Remove the group */
+ BLI_freelinkN(&ob->defbase, defgroup);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
}
-/* get the active gp-palettecolor for editing */
-bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette)
+void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
{
- bGPDpalettecolor *palcolor;
+ if (gps->dvert == NULL) {
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
+ }
+}
- /* error checking */
- if (ELEM(NULL, palette, palette->colors.first)) {
- return NULL;
+/* ************************************************** */
+
+/**
+ * Apply smooth to stroke point
+ * \param gps Stroke to smooth
+ * \param i Point index
+ * \param inf Amount of smoothing to apply
+ */
+bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf)
+{
+ bGPDspoint *pt = &gps->points[i];
+ // float pressure = 0.0f;
+ float sco[3] = { 0.0f };
+
+ /* Do nothing if not enough points to smooth out */
+ if (gps->totpoints <= 2) {
+ return false;
}
- /* 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;
+ /* Only affect endpoints by a fraction of the normal strength,
+ * to prevent the stroke from shrinking too much
+ */
+ if ((i == 0) || (i == gps->totpoints - 1)) {
+ inf *= 0.1f;
+ }
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
+ {
+ // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
+ const int steps = 2;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
+
+ /* add the point itself */
+ madd_v3_v3fl(sco, &pt->x, average_fac);
+
+ /* n-steps before/after current point */
+ // XXX: review how the endpoints are treated by this algorithm
+ // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = i - step;
+ int after = i + step;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
+
+ /* add both these points to the average-sum (s += p[i]/n) */
+ madd_v3_v3fl(sco, &pt1->x, average_fac);
+ madd_v3_v3fl(sco, &pt2->x, average_fac);
+
}
}
- /* no active color found */
- return NULL;
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
+
+ return true;
}
-/* get the gp-palettecolor looking for name */
-bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name)
+
+/**
+ * Apply smooth for strength to stroke point */
+bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence)
{
- /* error checking */
- if (ELEM(NULL, palette, name)) {
- return NULL;
+ bGPDspoint *ptb = &gps->points[point_index];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
}
- return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info));
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the strength
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
+ }
+ const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal;
+
+ return true;
}
-/* Change color name in all strokes */
-void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname)
+/**
+ * Apply smooth for thickness to stroke point (use pressure) */
+bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
- if (ELEM(NULL, gpd, oldname, newname))
- return;
+ /* Do nothing if not enough points */
+ if ((gps->totpoints <= 2) || (point_index < 1)) {
+ return false;
+ }
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (STREQ(gps->colorname, oldname)) {
- BLI_strncpy(gps->colorname, newname, sizeof(gps->colorname));
- }
- }
- }
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
}
+ float optimal = interpf(ptc->pressure, pta->pressure, fac);
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->pressure = interpf(optimal, ptb->pressure, influence);
+ return true;
}
-/* Delete all strokes of the color */
-void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
+/**
+* Apply smooth for UV rotation to stroke point (use pressure) */
+bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps, *gpsn;
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
- if (ELEM(NULL, gpd, name))
- return;
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = 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);
- }
+ /* Compute theoretical optimal value */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
+ }
+ float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac);
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence);
+ CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2);
+
+ return true;
+}
+
+/**
+ * Get range of selected frames in layer.
+ * Always the active frame is considered as selected, so if no more selected the range
+ * will be equal to the current active frame.
+ * \param gpl Layer
+ * \param r_initframe Number of first selected frame
+ * \param r_endframe Number of last selected frame
+ */
+void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe)
+{
+ *r_initframe = gpl->actframe->framenum;
+ *r_endframe = gpl->actframe->framenum;
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ if (gpf->framenum < *r_initframe) {
+ *r_initframe = gpf->framenum;
+ }
+ if (gpf->framenum > *r_endframe) {
+ *r_endframe = gpf->framenum;
}
}
}
+}
+/**
+ * Get Falloff factor base on frame range
+ * \param gpf Frame
+ * \param actnum Number of active frame in layer
+ * \param f_init Number of first selected frame
+ * \param f_end Number of last selected frame
+ * \param cur_falloff Curve with falloff factors
+ */
+float BKE_gpencil_multiframe_falloff_calc(bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
+{
+ float fnum = 0.5f; /* default mid curve */
+ float value;
+
+ /* check curve is available */
+ if (cur_falloff == NULL) {
+ return 1.0f;
+ }
+
+ /* frames to the right of the active frame */
+ if (gpf->framenum < actnum) {
+ fnum = (float)(gpf->framenum - f_init) / (actnum - f_init);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum);
+ }
+ /* frames to the left of the active frame */
+ else if (gpf->framenum > actnum) {
+ fnum = (float)(gpf->framenum - actnum) / (f_end - actnum);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f);
+ }
+ else {
+ value = 1.0f;
+ }
+
+ return value;
}
-/* set the active gp-palettecolor */
-void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active)
+/* remove strokes using a material */
+void BKE_gpencil_material_index_remove(bGPdata *gpd, int index)
{
- bGPDpalettecolor *palcolor;
+ bGPDstroke *gps, *gpsn;
- /* error checking */
- if (ELEM(NULL, palette, palette->colors.first, active)) {
- return;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->mat_nr == index) {
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles) MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
+ else {
+ /* reassign strokes */
+ if (gps->mat_nr > index) {
+ gps->mat_nr--;
+ }
+ }
+ }
+ }
+ }
+}
+
+void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len)
+{
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* reassign strokes */
+ MAT_NR_REMAP(gps->mat_nr);
+ }
+ }
}
- /* loop over colors deactivating all */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~PC_COLOR_ACTIVE;
+#undef MAT_NR_REMAP
+
+}
+
+/* statistics functions */
+void BKE_gpencil_stats_update(bGPdata *gpd)
+{
+ gpd->totlayer = 0;
+ gpd->totframe = 0;
+ gpd->totstroke = 0;
+ gpd->totpoint = 0;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpd->totlayer++;
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ gpd->totframe++;
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ gpd->totstroke++;
+ gpd->totpoint += gps->totpoints;
+ }
+ }
}
- /* set as active one */
- active->flag |= PC_COLOR_ACTIVE;
}
-/* delete the active gp-palettecolor */
-void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor)
+/* get material index */
+int BKE_gpencil_get_material_index(Object *ob, Material *ma)
{
- /* error checking */
- if (ELEM(NULL, palette, palcolor)) {
- return;
+ short *totcol = give_totcolp(ob);
+ Material *read_ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ read_ma = give_current_material(ob, i + 1);
+ if (ma == read_ma) {
+ return i + 1;
+ }
}
- /* free */
- BLI_freelinkN(&palette->colors, palcolor);
+ return 0;
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
new file mode 100644
index 00000000000..68691cd3d05
--- /dev/null
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -0,0 +1,826 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+ /** \file blender/blenkernel/intern/gpencil_modifier.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_lattice.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+
+static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL };
+
+/* *************************************************** */
+/* Geometry Utilities */
+
+/* calculate stroke normal using some points */
+void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
+{
+ if (gps->totpoints < 3) {
+ zero_v3(r_normal);
+ return;
+ }
+
+ bGPDspoint *points = gps->points;
+ int totpoints = gps->totpoints;
+
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float vec1[3];
+ float vec2[3];
+
+ /* initial vector (p0 -> p1) */
+ sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(vec2, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(r_normal, vec1, vec2);
+
+ /* Normalize vector */
+ normalize_v3(r_normal);
+}
+
+/* Get points of stroke always flat to view not affected by camera view or view position */
+static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d)
+{
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
+
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
+
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
+
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
+
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
+
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+ vec2f *point = &points2d[i];
+ point->x = dot_v3v3(loc, locx);
+ point->y = dot_v3v3(loc, locy);
+ }
+
+}
+
+/* Stroke Simplify ------------------------------------- */
+
+/* Reduce a series of points to a simplified version, but
+ * maintains the general shape of the series
+ *
+ * Ramer - Douglas - Peucker algorithm
+ * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ */
+static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon)
+{
+ vec2f *old_points2d = points2d;
+ int totpoints = gps->totpoints;
+ char *marked = NULL;
+ char work;
+
+ int start = 1;
+ int end = gps->totpoints - 2;
+
+ marked = MEM_callocN(totpoints, "GP marked array");
+ marked[start] = 1;
+ marked[end] = 1;
+
+ work = 1;
+ int totmarked = 0;
+ /* while still reducing */
+ while (work) {
+ int ls, le;
+ work = 0;
+
+ ls = start;
+ le = start + 1;
+
+ /* while not over interval */
+ while (ls < end) {
+ int max_i = 0;
+ float v1[2];
+ /* divided to get more control */
+ float max_dist = epsilon / 10.0f;
+
+ /* find the next marked point */
+ while (marked[le] == 0) {
+ le++;
+ }
+
+ /* perpendicular vector to ls-le */
+ v1[1] = old_points2d[le].x - old_points2d[ls].x;
+ v1[0] = old_points2d[ls].y - old_points2d[le].y;
+
+ for (int i = ls + 1; i < le; i++) {
+ float mul;
+ float dist;
+ float v2[2];
+
+ v2[0] = old_points2d[i].x - old_points2d[ls].x;
+ v2[1] = old_points2d[i].y - old_points2d[ls].y;
+
+ if (v2[0] == 0 && v2[1] == 0) {
+ continue;
+ }
+
+ mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
+
+ dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
+
+ if (dist > max_dist) {
+ max_dist = dist;
+ max_i = i;
+ }
+ }
+
+ if (max_i != 0) {
+ work = 1;
+ marked[max_i] = 1;
+ totmarked++;
+ }
+
+ ls = le;
+ le = ls + 1;
+ }
+ }
+
+ /* adding points marked */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = NULL;
+ MDeformVert *dvert_src = NULL;
+
+ if (gps->dvert != NULL) {
+ old_dvert = MEM_dupallocN(gps->dvert);
+ }
+ /* resize gps */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+ if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ if (dvert_src->dw) {
+ memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
+ }
+ }
+ j++;
+ }
+ else {
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+ MEM_SAFE_FREE(marked);
+}
+
+/* Simplify stroke using Ramer-Douglas-Peucker algorithm */
+void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor)
+{
+ /* first create temp data and convert points to 2D */
+ vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points");
+
+ gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d);
+
+ gpencil_rdp_stroke(gps, points2d, factor);
+
+ MEM_SAFE_FREE(points2d);
+}
+
+/* Simplify alternate vertex of stroke except extrems */
+void BKE_gpencil_simplify_fixed(bGPDstroke *gps)
+{
+ if (gps->totpoints < 5) {
+ return;
+ }
+
+ /* save points */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = NULL;
+ MDeformVert *dvert_src = NULL;
+
+ if (gps->dvert != NULL) {
+ old_dvert = MEM_dupallocN(gps->dvert);
+ }
+
+ /* resize gps */
+ int newtot = (gps->totpoints - 2) / 2;
+ if (((gps->totpoints - 2) % 2) > 0) {
+ newtot++;
+ }
+ newtot += 2;
+
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
+ }
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+
+ if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ if (dvert_src->dw) {
+ memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
+ }
+ }
+ j++;
+ }
+ else {
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+}
+
+/* *************************************************** */
+/* Modifier Utilities */
+
+/* Lattice Modifier ---------------------------------- */
+/* Usually, evaluation of the lattice modifier is self-contained.
+ * However, since GP's modifiers operate on a per-stroke basis,
+ * we need to these two extra functions that called before/after
+ * each loop over all the geometry being evaluated.
+ */
+
+ /* init lattice deform data */
+void BKE_gpencil_lattice_init(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Object *latob = NULL;
+
+ latob = mmd->object;
+ if ((!latob) || (latob->type != OB_LATTICE)) {
+ return;
+ }
+ if (mmd->cache_data) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ }
+
+ /* init deform data */
+ mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob);
+ }
+ }
+}
+
+/* clear lattice deform data */
+void BKE_gpencil_lattice_clear(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ mmd->cache_data = NULL;
+ }
+ }
+ }
+}
+
+/* *************************************************** */
+/* Modifier Methods - Evaluation Loops, etc. */
+
+/* check if exist geometry modifiers */
+bool BKE_gpencil_has_geometry_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti && mti->generateStrokes) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* check if exist time modifiers */
+bool BKE_gpencil_has_time_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti && mti->remapTime) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* apply stroke modifiers */
+void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, bool is_render)
+{
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
+ continue;
+ }
+
+ if (mti && mti->deformStroke) {
+ mti->deformStroke(md, depsgraph, ob, gpl, gps);
+
+ /* some modifiers could require a recalc of fill triangulation data */
+ if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) {
+ if (ELEM(md->type,
+ eGpencilModifierType_Armature,
+ eGpencilModifierType_Hook,
+ eGpencilModifierType_Lattice,
+ eGpencilModifierType_Offset))
+ {
+
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* apply stroke geometry modifiers */
+void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render)
+{
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
+ continue;
+ }
+
+ if (mti->generateStrokes) {
+ mti->generateStrokes(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+ }
+}
+
+/* apply time modifiers */
+int BKE_gpencil_time_modifier(Depsgraph *depsgraph, Scene *scene, Object *ob,
+ bGPDlayer *gpl, int cfra, bool is_render)
+{
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+ int nfra = cfra;
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
+ continue;
+ }
+
+ if (mti->remapTime) {
+ nfra = mti->remapTime(md, depsgraph, scene, ob, gpl, cfra);
+ /* if the frame number changed, don't evaluate more and return */
+ if (nfra != cfra) {
+ return nfra;
+ }
+ }
+ }
+ }
+
+ /* if no time modifier, return original frame number */
+ return nfra;
+}
+/* *************************************************** */
+
+void BKE_gpencil_eval_geometry(Depsgraph *depsgraph,
+ bGPdata *gpd)
+{
+ DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
+ int ctime = (int)DEG_get_ctime(depsgraph);
+
+ /* update active frame */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
+ }
+
+ /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()?
+ * This would be better than inventing our own logic for this stuff...
+ */
+
+ /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node)
+ * later when there's more happening here. For now, let's just keep this in here to avoid
+ * needing to have one more node slowing down evaluation...
+ */
+ if (DEG_is_active(depsgraph)) {
+ bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
+
+ /* sync "actframe" changes back to main-db too,
+ * so that editing tools work with copy-on-write
+ * when the current frame changes
+ */
+ for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
+ }
+ }
+}
+
+void BKE_gpencil_modifier_init(void)
+{
+ /* Initialize modifier types */
+ gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */
+}
+
+GpencilModifierData *BKE_gpencil_modifier_new(int type)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
+
+ /* note, this name must be made unique later */
+ BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
+
+ md->type = type;
+ md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded;
+ md->flag = eGpencilModifierFlag_StaticOverride_Local;
+
+ if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode)
+ md->mode |= eGpencilModifierMode_Editmode;
+
+ if (mti->initData) mti->initData(md);
+
+ return md;
+}
+
+static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (mti->freeData) mti->freeData(md);
+ if (md->error) MEM_freeN(md->error);
+
+ MEM_freeN(md);
+}
+
+void BKE_gpencil_modifier_free(GpencilModifierData *md)
+{
+ BKE_gpencil_modifier_free_ex(md, 0);
+}
+
+/* check unique name */
+bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
+{
+ if (modifiers && gmd) {
+ const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
+ return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name));
+ }
+ return false;
+}
+
+bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ return mti->dependsOnTime && mti->dependsOnTime(md);
+}
+
+const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
+{
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
+ return modifier_gpencil_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
+
+ /* md_dst may have already be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (mti->freeData) {
+ mti->freeData(md_dst);
+ }
+
+ const size_t data_size = sizeof(GpencilModifierData);
+ const char *md_src_data = ((const char *)md_src) + data_size;
+ char *md_dst_data = ((char *)md_dst) + data_size;
+ BLI_assert(data_size <= (size_t)mti->struct_size);
+ memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size);
+}
+
+static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ target->mode = md->mode;
+ target->flag = md->flag;
+
+ if (mti->copyData) {
+ mti->copyData(md, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_ex(md, target, 0);
+}
+
+GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next)
+ if (md->type == type)
+ break;
+
+ return md;
+}
+
+void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, ob, walk, userData);
+ }
+ else if (mti->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk;
+ mti->foreachObjectLink(md, ob, fp, userData);
+ }
+ }
+}
+
+void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachTexLink)
+ mti->foreachTexLink(md, ob, walk, userData);
+ }
+}
+
+GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
+{
+ return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
+}
+
+void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag)
+{
+ bGPDspoint *temp_points;
+ MDeformVert *temp_dverts = NULL;
+ MDeformVert *dvert = NULL;
+ MDeformVert *dvert_final = NULL;
+ MDeformVert *dvert_next = NULL;
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ for (int s = 0; s < level; s++) {
+ totnewpoints = gps->totpoints - 1;
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrays */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ temp_dverts = MEM_dupallocN(gps->dvert);
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* move points from last to first to new place */
+ i2 = gps->totpoints - 1;
+ for (int i = oldtotpoints - 1; i > 0; i--) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_final = &gps->dvert[i2];
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ }
+ i2 -= 2;
+ }
+ /* interpolate mid points */
+ i2 = 1;
+ for (int i = 0; i < oldtotpoints - 1; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ /* add a half way point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_next = &temp_dverts[i + 1];
+ dvert_final = &gps->dvert[i2];
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = MEM_dupallocN(dvert->dw);
+
+ /* interpolate weight values */
+ for (int d = 0; d < dvert->totweight; d++) {
+ MDeformWeight *dw_a = &dvert->dw[d];
+ if (dvert_next->totweight > d) {
+ MDeformWeight *dw_b = &dvert_next->dw[d];
+ MDeformWeight *dw_final = &dvert_final->dw[d];
+ dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
+ }
+ }
+ }
+
+ i2 += 2;
+ }
+
+ MEM_SAFE_FREE(temp_points);
+ MEM_SAFE_FREE(temp_dverts);
+
+ /* move points to smooth stroke (not simple flag )*/
+ if ((flag & GP_SUBDIV_SIMPLE) == 0) {
+ /* duplicate points in a temp area with the new subdivide data */
+ temp_points = MEM_dupallocN(gps->points);
+
+ /* extreme points are not changed */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i + 1];
+
+ /* move point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ }
+
+ }
+}
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
deleted file mode 100644
index 62f608f8565..00000000000
--- a/source/blender/blenkernel/intern/group.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/group.c
- * \ingroup bke
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_group_types.h"
-#include "DNA_material_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_particle_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-
-
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-#include "BKE_group.h"
-#include "BKE_icons.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_scene.h" /* BKE_scene_base_find */
-
-static void free_group_object(GroupObject *go)
-{
- MEM_freeN(go);
-}
-
-/** Free (or release) any data used by this group (does not free the group itself). */
-void BKE_group_free(Group *group)
-{
- /* don't free group itself */
- GroupObject *go;
-
- /* No animdata here. */
-
- while ((go = BLI_pophead(&group->gobject))) {
- free_group_object(go);
- }
-
- BKE_previewimg_free(&group->preview);
-}
-
-Group *BKE_group_add(Main *bmain, const char *name)
-{
- Group *group;
-
- group = BKE_libblock_alloc(bmain, ID_GR, name, 0);
- id_us_min(&group->id);
- id_us_ensure_real(&group->id);
- group->layer = (1 << 20) - 1;
-
- group->preview = NULL;
-
- return group;
-}
-
-/**
- * Only copy internal data of Group ID from source to already allocated/initialized destination.
- * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
- *
- * WARNING! This function will not handle ID user count!
- *
- * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
- */
-void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag)
-{
- BLI_duplicatelist(&group_dst->gobject, &group_src->gobject);
-
- /* Do not copy group's preview (same behavior as for objects). */
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
- BKE_previewimg_id_copy(&group_dst->id, &group_src->id);
- }
- else {
- group_dst->preview = NULL;
- }
-}
-
-Group *BKE_group_copy(Main *bmain, const Group *group)
-{
- Group *group_copy;
- BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false);
- return group_copy;
-}
-
-void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local)
-{
- BKE_id_make_local_generic(bmain, &group->id, true, lib_local);
-}
-
-/* external */
-static bool group_object_add_internal(Group *group, Object *ob)
-{
- GroupObject *go;
-
- if (group == NULL || ob == NULL) {
- return false;
- }
-
- /* check if the object has been added already */
- if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) {
- return false;
- }
-
- go = MEM_callocN(sizeof(GroupObject), "groupobject");
- BLI_addtail(&group->gobject, go);
-
- go->ob = ob;
- id_us_ensure_real(&go->ob->id);
-
- return true;
-}
-
-bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base)
-{
- if (group_object_add_internal(group, object)) {
- if ((object->flag & OB_FROMGROUP) == 0) {
-
- if (scene && base == NULL)
- base = BKE_scene_base_find(scene, object);
-
- object->flag |= OB_FROMGROUP;
-
- if (base)
- base->flag |= OB_FROMGROUP;
- }
- return true;
- }
- else {
- return false;
- }
-}
-
-/* also used for (ob == NULL) */
-static int group_object_unlink_internal(Group *group, Object *ob)
-{
- GroupObject *go, *gon;
- int removed = 0;
- if (group == NULL) return 0;
-
- go = group->gobject.first;
- while (go) {
- gon = go->next;
- if (go->ob == ob) {
- BLI_remlink(&group->gobject, go);
- free_group_object(go);
- removed = 1;
- /* should break here since an object being in a group twice cant happen? */
- }
- go = gon;
- }
- return removed;
-}
-
-static bool group_object_cyclic_check_internal(Object *object, Group *group)
-{
- if (object->dup_group) {
- Group *dup_group = object->dup_group;
- if ((dup_group->id.tag & LIB_TAG_DOIT) == 0) {
- /* Cycle already exists in groups, let's prevent further crappyness */
- return true;
- }
- /* flag the object to identify cyclic dependencies in further dupli groups */
- dup_group->id.tag &= ~LIB_TAG_DOIT;
-
- if (dup_group == group)
- return true;
- else {
- GroupObject *gob;
- for (gob = dup_group->gobject.first; gob; gob = gob->next) {
- if (group_object_cyclic_check_internal(gob->ob, group)) {
- return true;
- }
- }
- }
-
- /* un-flag the object, it's allowed to have the same group multiple times in parallel */
- dup_group->id.tag |= LIB_TAG_DOIT;
- }
-
- return false;
-}
-
-bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group)
-{
- /* first flag all groups */
- BKE_main_id_tag_listbase(&bmain->group, LIB_TAG_DOIT, true);
-
- return group_object_cyclic_check_internal(object, group);
-}
-
-bool BKE_group_object_unlink(Main *bmain, Group *group, Object *object, Scene *scene, Base *base)
-{
- if (group_object_unlink_internal(group, object)) {
- /* object can be NULL */
- if (object && BKE_group_object_find(bmain, NULL, object) == NULL) {
- if (scene && base == NULL)
- base = BKE_scene_base_find(scene, object);
-
- object->flag &= ~OB_FROMGROUP;
-
- if (base)
- base->flag &= ~OB_FROMGROUP;
- }
- return true;
- }
- else {
- return false;
- }
-}
-
-bool BKE_group_object_exists(Group *group, Object *ob)
-{
- if (group == NULL || ob == NULL) {
- return false;
- }
- else {
- return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
- }
-}
-
-Group *BKE_group_object_find(Main *bmain, Group *group, Object *ob)
-{
- if (group)
- group = group->id.next;
- else
- group = bmain->group.first;
-
- while (group) {
- if (BKE_group_object_exists(group, ob))
- return group;
- group = group->id.next;
- }
- return NULL;
-}
-
-bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
-{
- GroupObject *go;
-
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- if (parent->nlastrips.first)
- return 1;
-#endif
-
- for (go = group->gobject.first; go; go = go->next)
- if (go->ob && go->ob->proxy)
- return true;
-
- return false;
-}
-
-#if 0 // add back when timeoffset & animsys work again
-/* only replaces object strips or action when parent nla instructs it */
-/* keep checking nla.c though, in case internal structure of strip changes */
-static void group_replaces_nla(Object *parent, Object *target, char mode)
-{
- static ListBase nlastrips = {NULL, NULL};
- static bAction *action = NULL;
- static bool done = false;
- bActionStrip *strip, *nstrip;
-
- if (mode == 's') {
-
- for (strip = parent->nlastrips.first; strip; strip = strip->next) {
- if (strip->object == target) {
- if (done == 0) {
- /* clear nla & action from object */
- nlastrips = target->nlastrips;
- BLI_listbase_clear(&target->nlastrips);
- action = target->action;
- target->action = NULL;
- target->nlaflag |= OB_NLA_OVERRIDE;
- done = true;
- }
- nstrip = MEM_dupallocN(strip);
- BLI_addtail(&target->nlastrips, nstrip);
- }
- }
- }
- else if (mode == 'e') {
- if (done) {
- BLI_freelistN(&target->nlastrips);
- target->nlastrips = nlastrips;
- target->action = action;
-
- BLI_listbase_clear(&nlastrips); /* not needed, but yah... :) */
- action = NULL;
- done = false;
- }
- }
-}
-#endif
-
-/* puts all group members in local timing system, after this call
- * you can draw everything, leaves tags in objects to signal it needs further updating */
-
-/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
-void BKE_group_handle_recalc_and_update(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group)
-{
- GroupObject *go;
-
-#if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time,
- * not just on frame change.
- * This isn't working because the animation data is only re-evaluated on frame change so commenting for now
- * but when its enabled at some point it will need to be changed so as not to update so much - campbell */
-
- /* if animated group... */
- if (parent->nlastrips.first) {
- int cfrao;
-
- /* switch to local time */
- cfrao = scene->r.cfra;
-
- /* we need a DAG per group... */
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob && go->recalc) {
- go->ob->recalc = go->recalc;
-
- group_replaces_nla(parent, go->ob, 's');
- BKE_object_handle_update(eval_ctx, scene, go->ob);
- group_replaces_nla(parent, go->ob, 'e');
-
- /* leave recalc tags in case group members are in normal scene */
- go->ob->recalc = go->recalc;
- }
- }
-
- /* restore */
- scene->r.cfra = cfrao;
- }
- else
-#endif
- {
- /* only do existing tags, as set by regular depsgraph */
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob) {
- if (go->ob->recalc) {
- BKE_object_handle_update(bmain, eval_ctx, scene, go->ob);
- }
- }
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index e49f24c8120..2a348751365 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -37,23 +37,27 @@
#include "MEM_guardedalloc.h"
-#include "DNA_group_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "DNA_brush_types.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_linklist_lockfree.h"
#include "BLI_string.h"
+#include "BLI_fileops.h"
#include "BLI_threads.h"
#include "BKE_icons.h"
#include "BKE_global.h" /* only for G.background test */
+#include "BKE_studiolight.h"
#include "BLI_sys_types.h" // for intptr_t support
@@ -63,6 +67,14 @@
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
+/**
+ * Only allow non-managed icons to be removed (by Python for eg).
+ * Previews & ID's have their own functions to remove icons.
+ */
+enum {
+ ICON_FLAG_MANAGED = (1 << 0),
+};
+
/* GLOBALS */
static GHash *gIcons = NULL;
@@ -85,6 +97,19 @@ static void icon_free(void *val)
Icon *icon = val;
if (icon) {
+ if (icon->obj_type == ICON_DATA_GEOM) {
+ struct Icon_Geom *obj = icon->obj;
+ if (obj->mem) {
+ /* coords & colors are part of this memory. */
+ MEM_freeN((void *)obj->mem);
+ }
+ else {
+ MEM_freeN((void *)obj->coords);
+ MEM_freeN((void *)obj->colors);
+ }
+ MEM_freeN(icon->obj);
+ }
+
if (icon->drawinfo_free) {
icon->drawinfo_free(icon->drawinfo);
}
@@ -95,6 +120,31 @@ static void icon_free(void *val)
}
}
+static void icon_free_data(int icon_id, Icon *icon)
+{
+ if (icon->obj_type == ICON_DATA_ID) {
+ ((ID *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_PREVIEW) {
+ ((PreviewImage *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_GPLAYER) {
+ ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_GEOM) {
+ ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
+ StudioLight *sl = icon->obj;
+ if (sl != NULL) {
+ BKE_studiolight_unset_icon_id(sl, icon_id);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+}
+
/* create an id for a new icon and make sure that ids from deleted icons get reused
* after the integer number range is used up */
static int get_next_free_id(void)
@@ -282,8 +332,9 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id)
ID_PRV_CASE(ID_IM, Image);
ID_PRV_CASE(ID_BR, Brush);
ID_PRV_CASE(ID_OB, Object);
- ID_PRV_CASE(ID_GR, Group);
+ ID_PRV_CASE(ID_GR, Collection);
ID_PRV_CASE(ID_SCE, Scene);
+ ID_PRV_CASE(ID_SCR, bScreen);
#undef ID_PRV_CASE
default:
break;
@@ -476,6 +527,7 @@ void BKE_icon_changed(const int icon_id)
if (icon) {
/* We *only* expect ID-tied icons here, not non-ID icon/preview! */
BLI_assert(icon->id_type != 0);
+ BLI_assert(icon->obj_type == ICON_DATA_ID);
/* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here ,
* we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */
@@ -492,22 +544,31 @@ void BKE_icon_changed(const int icon_id)
}
}
-static int icon_id_ensure_create_icon(struct ID *id)
+static Icon *icon_create(int icon_id, int obj_type, void *obj)
{
- BLI_assert(BLI_thread_is_main());
+ Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__);
- Icon *new_icon = NULL;
-
- new_icon = MEM_mallocN(sizeof(Icon), __func__);
-
- new_icon->obj = id;
- new_icon->id_type = GS(id->name);
+ new_icon->obj_type = obj_type;
+ new_icon->obj = obj;
+ new_icon->id_type = 0;
+ new_icon->flag = 0;
/* next two lines make sure image gets created */
new_icon->drawinfo = NULL;
new_icon->drawinfo_free = NULL;
- BLI_ghash_insert(gIcons, POINTER_FROM_INT(id->icon_id), new_icon);
+ BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon);
+
+ return new_icon;
+}
+
+static int icon_id_ensure_create_icon(struct ID *id)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ Icon *icon = icon_create(id->icon_id, ICON_DATA_ID, id);
+ icon->id_type = GS(id->name);
+ icon->flag = ICON_FLAG_MANAGED;
return id->icon_id;
}
@@ -541,13 +602,49 @@ int BKE_icon_id_ensure(struct ID *id)
return icon_id_ensure_create_icon(id);
}
+
+static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ /* NOTE: The color previews for GP Layers don't really need
+ * to be "rendered" to image per se (as it will just be a plain
+ * colored rectangle), we need to define icon data here so that
+ * we can store a pointer to the layer data in icon->obj.
+ */
+ Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl);
+ icon->flag = ICON_FLAG_MANAGED;
+
+ return gpl->runtime.icon_id;
+}
+
+int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
+{
+ /* Never handle icons in non-main thread! */
+ BLI_assert(BLI_thread_is_main());
+
+ if (!gpl || G.background) {
+ return 0;
+ }
+
+ if (gpl->runtime.icon_id)
+ return gpl->runtime.icon_id;
+
+ gpl->runtime.icon_id = get_next_free_id();
+
+ if (!gpl->runtime.icon_id) {
+ printf("%s: Internal error - not enough IDs\n", __func__);
+ return 0;
+ }
+
+ return icon_gplayer_color_ensure_create_icon(gpl);
+}
+
/**
* Return icon id of given preview, or create new icon if not found.
*/
int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
- Icon *new_icon = NULL;
-
if (!preview || G.background)
return 0;
@@ -578,16 +675,8 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return icon_id_ensure_create_icon(id);
}
- new_icon = MEM_mallocN(sizeof(Icon), __func__);
-
- new_icon->obj = preview;
- new_icon->id_type = 0; /* Special, tags as non-ID icon/preview. */
-
- /* next two lines make sure image gets created */
- new_icon->drawinfo = NULL;
- new_icon->drawinfo_free = NULL;
-
- BLI_ghash_insert(gIcons, POINTER_FROM_INT(preview->icon_id), new_icon);
+ Icon *icon = icon_create(preview->icon_id, ICON_DATA_PREVIEW, preview);
+ icon->flag = ICON_FLAG_MANAGED;
return preview->icon_id;
}
@@ -649,21 +738,127 @@ void BKE_icon_id_delete(struct ID *id)
/**
* Remove icon and free data.
*/
-void BKE_icon_delete(const int icon_id)
+bool BKE_icon_delete(const int icon_id)
{
- Icon *icon;
+ if (icon_id == 0) {
+ /* no icon defined for library object */
+ return false;
+ }
- if (!icon_id) return; /* no icon defined for library object */
+ Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+ if (icon) {
+ icon_free_data(icon_id, icon);
+ icon_free(icon);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
- icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+bool BKE_icon_delete_unmanaged(const int icon_id)
+{
+ if (icon_id == 0) {
+ /* no icon defined for library object */
+ return false;
+ }
+ Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
if (icon) {
- if (icon->id_type != 0) {
- ((ID *)(icon->obj))->icon_id = 0;
+ if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
+ BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon);
+ return false;
}
else {
- ((PreviewImage *)(icon->obj))->icon_id = 0;
+ icon_free_data(icon_id, icon);
+ icon_free(icon);
+ return true;
}
- icon_free(icon);
}
+ else {
+ return false;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Icon
+ * \{ */
+
+int BKE_icon_geom_ensure(struct Icon_Geom *geom)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ if (geom->icon_id) {
+ return geom->icon_id;
+ }
+
+ geom->icon_id = get_next_free_id();
+
+ icon_create(geom->icon_id, ICON_DATA_GEOM, geom);
+ /* Not managed for now, we may want this to be configurable per icon). */
+
+ return geom->icon_id;
+}
+
+struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len)
+{
+ BLI_assert(BLI_thread_is_main());
+ if (data_len <= 8) {
+ goto fail;
+ }
+ /* Skip the header. */
+ data_len -= 8;
+ const int div = 3 * 2 * 3;
+ const int coords_len = data_len / div;
+ if (coords_len * div != data_len) {
+ goto fail;
+ }
+
+ const uchar header[4] = {'V', 'C', 'O', 0};
+ const uchar *p = data;
+ if (memcmp(p, header, ARRAY_SIZE(header)) != 0) {
+ goto fail;
+ }
+ p += 4;
+
+ struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__);
+ geom->coords_range[0] = (int)*p++;
+ geom->coords_range[1] = (int)*p++;
+ /* x, y ignored for now */
+ p += 2;
+
+ geom->coords_len = coords_len;
+ geom->coords = (const void *)p;
+ geom->colors = (const void *)(p + (data_len / 3));
+ geom->icon_id = 0;
+ geom->mem = data;
+ return geom;
+
+fail:
+ MEM_freeN((void *)data);
+ return NULL;
+}
+
+struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
+{
+ BLI_assert(BLI_thread_is_main());
+ size_t data_len;
+ uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len);
+ if (data == NULL) {
+ return NULL;
+ }
+ return BKE_icon_geom_from_memory(data, data_len);
+}
+
+/** \} */
+
+/** \name Studio Light Icon
+ * \{ */
+int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
+{
+ int icon_id = get_next_free_id();
+ Icon *icon = icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl);
+ icon->id_type = id_type;
+ return icon_id;
}
+/** \} */
diff --git a/source/blender/blenkernel/intern/icons_rasterize.c b/source/blender/blenkernel/intern/icons_rasterize.c
new file mode 100644
index 00000000000..24576c24953
--- /dev/null
+++ b/source/blender/blenkernel/intern/icons_rasterize.c
@@ -0,0 +1,146 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenkernel/intern/icons_rasterize.c
+ * \ingroup bke
+ */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_math_geom.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_icons.h"
+
+#include "BLI_strict_flags.h"
+
+struct UserRasterInfo {
+ int pt[3][2];
+ const uint *color;
+ /* only for smooth shading */
+ struct {
+ float pt_fl[3][2];
+ uint color_u[3][4];
+ } smooth;
+ int rect_size[2];
+ uint *rect;
+};
+
+static void tri_fill_flat(int x, int x_end, int y, void *user_data)
+{
+ struct UserRasterInfo *data = user_data;
+ uint *p = &data->rect[(y * data->rect_size[1]) + x];
+ uint col = data->color[0];
+ while (x++ != x_end) {
+ *p++ = col;
+ }
+}
+
+static void tri_fill_smooth(int x, int x_end, int y, void *user_data)
+{
+ struct UserRasterInfo *data = user_data;
+ uint *p = &data->rect[(y * data->rect_size[1]) + x];
+ float pt_step_fl[2] = {(float)x, (float)y};
+ while (x++ != x_end) {
+ float w[3];
+ barycentric_weights_v2_clamped(UNPACK3(data->smooth.pt_fl), pt_step_fl, w);
+
+ uint col_u[4] = {0, 0, 0, 0};
+ for (uint corner = 0; corner < 3; corner++) {
+ for (uint chan = 0; chan < 4; chan++) {
+ col_u[chan] += data->smooth.color_u[corner][chan] * (uint)(w[corner] * 255.0f);
+ }
+ }
+ union {
+ uint as_u32;
+ uchar as_bytes[4];
+ } col;
+ col.as_bytes[0] = (uchar)(col_u[0] / 255);
+ col.as_bytes[1] = (uchar)(col_u[1] / 255);
+ col.as_bytes[2] = (uchar)(col_u[2] / 255);
+ col.as_bytes[3] = (uchar)(col_u[3] / 255);
+ *p++ = col.as_u32;
+
+ pt_step_fl[0] += 1.0f;
+ }
+}
+
+ImBuf *BKE_icon_geom_rasterize(
+ const struct Icon_Geom *geom,
+ const unsigned int size_x, const unsigned int size_y)
+{
+ const int coords_len = geom->coords_len;
+
+ const uchar (*pos)[2] = geom->coords;
+ const uint *col = (void *)geom->colors;
+
+ /* TODO(campbell): Currently rasterizes to fixed size, then scales.
+ * Should rasterize to double size for eg instead. */
+ const int rect_size[2] = {max_ii(256, (int)size_x * 2), max_ii(256, (int)size_y * 2)};
+
+ ImBuf *ibuf = IMB_allocImBuf((uint)rect_size[0], (uint)rect_size[1], 32, IB_rect);
+
+ struct UserRasterInfo data;
+
+ data.rect_size[0] = rect_size[0];
+ data.rect_size[1] = rect_size[1];
+
+ data.rect = ibuf->rect;
+
+ float scale[2];
+ const bool use_scale = (rect_size[0] != 256) || (rect_size[1] != 256);
+
+ if (use_scale) {
+ scale[0] = ((float)rect_size[0] / 256.0f);
+ scale[1] = ((float)rect_size[1] / 256.0f);
+ }
+
+ for (int t = 0; t < coords_len; t += 1, pos += 3, col += 3) {
+ if (use_scale) {
+ ARRAY_SET_ITEMS(data.pt[0], (int)(pos[0][0] * scale[0]), (int)(pos[0][1] * scale[1]));
+ ARRAY_SET_ITEMS(data.pt[1], (int)(pos[1][0] * scale[0]), (int)(pos[1][1] * scale[1]));
+ ARRAY_SET_ITEMS(data.pt[2], (int)(pos[2][0] * scale[0]), (int)(pos[2][1] * scale[1]));
+ }
+ else {
+ ARRAY_SET_ITEMS(data.pt[0], UNPACK2(pos[0]));
+ ARRAY_SET_ITEMS(data.pt[1], UNPACK2(pos[1]));
+ ARRAY_SET_ITEMS(data.pt[2], UNPACK2(pos[2]));
+ }
+ data.color = col;
+ if ((col[0] == col[1]) && (col[0] == col[2])) {
+ BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_flat, &data);
+ }
+ else {
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[0], UNPACK2_EX((float), data.pt[0], ));
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[1], UNPACK2_EX((float), data.pt[1], ));
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[2], UNPACK2_EX((float), data.pt[2], ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[0], UNPACK4_EX((uint), ((uchar *)(col + 0)), ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[1], UNPACK4_EX((uint), ((uchar *)(col + 1)), ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[2], UNPACK4_EX((uint), ((uchar *)(col + 2)), ));
+ BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_smooth, &data);
+ }
+ }
+ IMB_scaleImBuf(ibuf, size_x, size_y);
+ return ibuf;
+}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index d995dce1259..d97c00f8229 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -39,7 +39,7 @@
#include "BLT_translation.h"
-#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_idcode.h"
typedef struct {
@@ -56,44 +56,46 @@ typedef struct {
/* WARNING! Keep it in sync with i18n contexts in BLT_translation.h */
static IDType idtypes[] = {
/** ID's directly below must all be in #Main, and be kept in sync with #MAX_LIBARRAY (membership, not order) */
- { ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE },
- { 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 },
- { ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
- { ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
- { ID_LA, "Lamp", "lamps", BLT_I18NCONTEXT_ID_LAMP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_LI, "Library", "libraries", BLT_I18NCONTEXT_ID_LIBRARY, 0 },
- { ID_LS, "FreestyleLineStyle", "linestyles", BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_LT, "Lattice", "lattices", BLT_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_MA, "Material", "materials", BLT_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE },
- { ID_MB, "Metaball", "metaballs", BLT_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE },
- { ID_MC, "MovieClip", "movieclips", BLT_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_ME, "Mesh", "meshes", BLT_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE },
- { ID_MSK, "Mask", "masks", BLT_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE },
- { ID_NT, "NodeTree", "node_groups", BLT_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_OB, "Object", "objects", BLT_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE },
- { ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE },
- { ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, 0 },
- { ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
- { ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE },
- { ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE },
- { ID_TE, "Texture", "textures", BLT_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_TXT, "Text", "texts", BLT_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE },
- { ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
- { ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
- { ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+ {ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE},
+ {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_GR, "Collection", "collections", BLT_I18NCONTEXT_ID_COLLECTION, 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_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE}, /* deprecated */
+ {ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
+ {ID_LA, "Light", "lights", BLT_I18NCONTEXT_ID_LAMP, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LI, "Library", "libraries", BLT_I18NCONTEXT_ID_LIBRARY, 0 },
+ {ID_LS, "FreestyleLineStyle", "linestyles", BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LT, "Lattice", "lattices", BLT_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MA, "Material", "materials", BLT_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MB, "Metaball", "metaballs", BLT_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MC, "MovieClip", "movieclips", BLT_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_ME, "Mesh", "meshes", BLT_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MSK, "Mask", "masks", BLT_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_NT, "NodeTree", "node_groups", BLT_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_OB, "Object", "objects", BLT_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LP, "LightProbe", "light_probes", BLT_I18NCONTEXT_ID_LIGHTPROBE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
+ {ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_TE, "Texture", "textures", BLT_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_TXT, "Text", "texts", BLT_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+ {ID_WS, "WorkSpace", "workspaces", BLT_I18NCONTEXT_ID_WORKSPACE, IDTYPE_FLAGS_ISLINKABLE},
/** Keep last, not an ID exactly, only include for completeness */
- { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
+ {ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
};
/* -1 for ID_ID */
@@ -203,6 +205,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(PA);
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
+ CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
@@ -210,6 +213,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(TXT);
CASE_IDFILTER(VF);
CASE_IDFILTER(WO);
+ CASE_IDFILTER(WS);
default:
return 0;
}
@@ -247,6 +251,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
CASE_IDFILTER(PA);
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
+ CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
@@ -294,6 +299,7 @@ int BKE_idcode_to_index(const short idcode)
CASE_IDINDEX(PA);
CASE_IDINDEX(PAL);
CASE_IDINDEX(PC);
+ CASE_IDINDEX(LP);
CASE_IDINDEX(SCE);
CASE_IDINDEX(SCR);
CASE_IDINDEX(SPK);
@@ -303,6 +309,7 @@ int BKE_idcode_to_index(const short idcode)
CASE_IDINDEX(VF);
CASE_IDINDEX(WM);
CASE_IDINDEX(WO);
+ CASE_IDINDEX(WS);
}
BLI_assert(0);
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 7a526d31567..8cc40d4e74c 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -476,6 +476,7 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
BLI_assert(prop->type == IDP_GROUP);
newp = idp_generic_copy(prop, flag);
newp->len = prop->len;
+ newp->subtype = prop->subtype;
for (link = prop->data.group.first; link; link = link->next) {
BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
@@ -601,8 +602,9 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
/**
* If a property is missing in \a dest, add it.
+ * Do it recursively.
*/
-void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
+void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag)
{
IDProperty *prop;
@@ -611,14 +613,30 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw
if (do_overwrite) {
for (prop = src->data.group.first; prop; prop = prop->next) {
- IDProperty *copy = IDP_CopyProperty(prop);
+ if (prop->type == IDP_GROUP) {
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+
+ if (prop_exist != NULL) {
+ IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
+ continue;
+ }
+ }
+
+ IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
IDP_ReplaceInGroup(dest, copy);
}
}
else {
for (prop = src->data.group.first; prop; prop = prop->next) {
- if (IDP_GetPropertyFromGroup(dest, prop->name) == NULL) {
- IDProperty *copy = IDP_CopyProperty(prop);
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+ if (prop_exist != NULL) {
+ if (prop->type == IDP_GROUP) {
+ IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
+ continue;
+ }
+ }
+ else {
+ IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
dest->len++;
BLI_addtail(&dest->data.group, copy);
}
@@ -627,6 +645,15 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw
}
/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
+void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
+{
+ IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
+}
+
+/**
* This function has a sanity check to make sure ID properties with the same name don't
* get added to the group.
*
@@ -1067,4 +1094,15 @@ void IDP_ClearProperty(IDProperty *prop)
prop->len = prop->totallen = 0;
}
+void IDP_Reset(IDProperty *prop, const IDProperty *reference)
+{
+ if (prop == NULL) {
+ return;
+ }
+ IDP_ClearProperty(prop);
+ if (reference != NULL) {
+ IDP_MergeGroup(prop, reference, true);
+ }
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 1d209dec935..f1a921650f0 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -68,7 +68,6 @@
#include "BLI_timecode.h" /* for stamp timecode format */
#include "BLI_utildefines.h"
-#include "BKE_bmfont.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -82,6 +81,7 @@
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_sequencer.h" /* seq_foreground_frame_get() */
+#include "BKE_workspace.h"
#include "BLF_api.h"
@@ -185,76 +185,6 @@ void BKE_images_exit(void)
BLI_spin_end(&image_spin);
}
-/* ******** IMAGE PROCESSING ************* */
-
-static void de_interlace_ng(struct ImBuf *ibuf) /* neogeo fields */
-{
- struct ImBuf *tbuf1, *tbuf2;
-
- if (ibuf == NULL) return;
- if (ibuf->flags & IB_fields) return;
- ibuf->flags |= IB_fields;
-
- if (ibuf->rect) {
- /* make copies */
- tbuf1 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, (int)IB_rect);
- tbuf2 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, (int)IB_rect);
-
- ibuf->x *= 2;
-
- IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
- IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
-
- ibuf->x /= 2;
- IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
- IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
-
- IMB_freeImBuf(tbuf1);
- IMB_freeImBuf(tbuf2);
- }
- ibuf->y /= 2;
-}
-
-static void de_interlace_st(struct ImBuf *ibuf) /* standard fields */
-{
- struct ImBuf *tbuf1, *tbuf2;
-
- if (ibuf == NULL) return;
- if (ibuf->flags & IB_fields) return;
- ibuf->flags |= IB_fields;
-
- if (ibuf->rect) {
- /* make copies */
- tbuf1 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, IB_rect);
- tbuf2 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, IB_rect);
-
- ibuf->x *= 2;
-
- IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
- IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
-
- ibuf->x /= 2;
- IMB_rectcpy(ibuf, tbuf2, 0, 0, 0, 0, tbuf2->x, tbuf2->y);
- IMB_rectcpy(ibuf, tbuf1, 0, tbuf2->y, 0, 0, tbuf1->x, tbuf1->y);
-
- IMB_freeImBuf(tbuf1);
- IMB_freeImBuf(tbuf2);
- }
- ibuf->y /= 2;
-}
-
-void BKE_image_de_interlace(Image *ima, int odd)
-{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ibuf) {
- if (odd)
- de_interlace_st(ibuf);
- else
- de_interlace_ng(ibuf);
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
-}
-
/* ***************** ALLOC & FREE, DATA MANAGING *************** */
static void image_free_cached_frames(Image *image)
@@ -341,19 +271,18 @@ void BKE_image_free_buffers(Image *ima)
/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free(Image *ima)
{
- int a;
-
/* Also frees animdata. */
BKE_image_free_buffers(ima);
image_free_packedfiles(ima);
- for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) {
- if (ima->renders[a]) {
- RE_FreeRenderResult(ima->renders[a]);
- ima->renders[a] = NULL;
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) {
+ if (slot->render) {
+ RE_FreeRenderResult(slot->render);
+ slot->render = NULL;
}
}
+ BLI_freelistN(&ima->renderslots);
BKE_image_free_views(ima);
MEM_SAFE_FREE(ima->stereo3d_format);
@@ -369,7 +298,6 @@ static void image_init(Image *ima, short source, short type)
ima->ok = IMA_OK;
- ima->xrep = ima->yrep = 1;
ima->aspx = ima->aspy = 1.0;
ima->gen_x = 1024; ima->gen_y = 1024;
ima->gen_type = IMA_GENTYPE_GRID;
@@ -380,6 +308,12 @@ static void image_init(Image *ima, short source, short type)
if (source == IMA_SRC_VIEWER)
ima->flag |= IMA_VIEW_AS_RENDER;
+ if (type == IMA_TYPE_R_RESULT) {
+ for (int i = 0; i < 8; i++) {
+ BKE_image_add_renderslot(ima, NULL);
+ }
+ }
+
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
}
@@ -466,18 +400,17 @@ void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_s
/* Cleanup stuff that cannot be copied. */
ima_dst->cache = NULL;
ima_dst->rr = NULL;
- for (int i = 0; i < IMA_MAX_RENDER_SLOT; i++) {
- ima_dst->renders[i] = NULL;
+
+ BLI_duplicatelist(&ima_dst->renderslots, &ima_src->renderslots);
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima_dst->renderslots) {
+ slot->render = NULL;
}
BLI_listbase_clear(&ima_dst->anims);
- ima_dst->totbind = 0;
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima_dst->bindcode[i] = 0;
ima_dst->gputexture[i] = NULL;
}
- ima_dst->repbind = NULL;
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id);
@@ -540,16 +473,14 @@ bool BKE_image_scale(Image *image, int width, int height)
return (ibuf != NULL);
}
-bool BKE_image_has_bindcode(Image *ima)
+bool BKE_image_has_opengl_texture(Image *ima)
{
- bool has_bindcode = false;
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->bindcode[i]) {
- has_bindcode = true;
- break;
+ if (ima->gputexture[i]) {
+ return true;
}
}
- return has_bindcode;
+ return false;
}
static void image_init_color_management(Image *ima)
@@ -932,21 +863,6 @@ void BKE_image_tag_time(Image *ima)
ima->lastused = PIL_check_seconds_timer_i();
}
-#if 0
-static void tag_all_images_time(Main *bmain)
-{
- Image *ima;
- int ctime = PIL_check_seconds_timer_i();
-
- ima = bmain->image.first;
- while (ima) {
- if (ima->bindcode || ima->repbind || ima->ibufs.first) {
- ima->lastused = ctime;
- }
- }
-}
-#endif
-
static uintptr_t image_mem_size(Image *image)
{
uintptr_t size = 0;
@@ -1208,7 +1124,6 @@ bool BKE_imtype_is_movie(const char imtype)
case R_IMF_IMTYPE_H264:
case R_IMF_IMTYPE_THEORA:
case R_IMF_IMTYPE_XVID:
- case R_IMF_IMTYPE_FRAMESERVER:
return true;
}
return false;
@@ -1349,7 +1264,6 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else if (STREQ(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
#endif
else if (STREQ(imtype_arg, "FFMPEG")) return R_IMF_IMTYPE_FFMPEG;
- else if (STREQ(imtype_arg, "FRAMESERVER")) return R_IMF_IMTYPE_FRAMESERVER;
#ifdef WITH_CINEON
else if (STREQ(imtype_arg, "CINEON")) return R_IMF_IMTYPE_CINEON;
else if (STREQ(imtype_arg, "DPX")) return R_IMF_IMTYPE_DPX;
@@ -2654,19 +2568,19 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
}
}
+ for (Camera *cam = mainp->camera.first; cam; cam = cam->id.next) {
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ callback(bgpic->ima, &bgpic->iuser, customdata);
+ }
+ }
+
/* image window, compo node users */
for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
- BGpic *bgpic;
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- callback(bgpic->ima, &bgpic->iuser, customdata);
- }
- }
- else if (sa->spacetype == SPACE_IMAGE) {
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
callback(sima->image, &sima->iuser, customdata);
}
@@ -2756,11 +2670,6 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
ima->name[0] = '\0';
}
-#if 0
- /* force reload on first use, but not for multilayer, that makes nodes and buttons in ui drawing fail */
- if (ima->type != IMA_TYPE_MULTILAYER)
- BKE_image_free_buffers(ima);
-#else
/* image buffers for non-sequence multilayer will share buffers with RenderResult,
* however sequence multilayer will own buffers. Such logic makes switching from
* single multilayer file to sequence completely unstable
@@ -2769,7 +2678,6 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
* sequences behave stable
*/
BKE_image_free_buffers(ima);
-#endif
ima->ok = 1;
if (iuser)
@@ -3019,7 +2927,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
if (ima->render_slot == ima->last_render_slot)
rr = RE_AcquireResultRead(RE_GetSceneRender(scene));
else
- rr = ima->renders[ima->render_slot];
+ rr = BKE_image_get_renderslot(ima, ima->render_slot)->render;
/* set proper views */
image_init_multilayer_multiview(ima, rr);
@@ -3053,27 +2961,39 @@ bool BKE_image_is_openexr(struct Image *ima)
void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
{
- /* called right before rendering, ima->renders contains render
+ /* called right before rendering, ima->renderslots contains render
* result pointers for everything but the current render */
Render *re = RE_GetSceneRender(scene);
- int slot = ima->render_slot, last = ima->last_render_slot;
- if (slot != last) {
- ima->renders[last] = NULL;
- RE_SwapResult(re, &ima->renders[last]);
+ /* Ensure we always have a valid render slot. */
+ if (!ima->renderslots.first) {
+ BKE_image_add_renderslot(ima, NULL);
+ ima->render_slot = 0;
+ ima->last_render_slot = 0;
+ }
+ else if (ima->render_slot >= BLI_listbase_count(&ima->renderslots)) {
+ ima->render_slot = 0;
+ ima->last_render_slot = 0;
+ }
+
+ RenderSlot *last_slot = BKE_image_get_renderslot(ima, ima->last_render_slot);
+ RenderSlot *cur_slot = BKE_image_get_renderslot(ima, ima->render_slot);
- if (ima->renders[slot]) {
+ if (last_slot && ima->render_slot != ima->last_render_slot) {
+ last_slot->render = NULL;
+ RE_SwapResult(re, &last_slot->render);
+
+ if (cur_slot->render) {
if (free_current_slot) {
- RE_FreeRenderResult(ima->renders[slot]);
- ima->renders[slot] = NULL;
+ BKE_image_clear_renderslot(ima, NULL, ima->render_slot);
}
else {
- RE_SwapResult(re, &ima->renders[slot]);
+ RE_SwapResult(re, &cur_slot->render);
}
}
}
- ima->last_render_slot = slot;
+ ima->last_render_slot = ima->render_slot;
}
/**************************** multiview load openexr *********************************/
@@ -3132,7 +3052,7 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
#endif /* WITH_OPENEXR */
/* common stuff to do with images after loading */
-static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
+static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf))
{
/* Preview is NULL when it has never been used as an icon before.
* Never handle previews/icons outside of main thread. */
@@ -3140,11 +3060,6 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
}
- /* fields */
- if (ima->flag & IMA_FIELDS) {
- if (ima->flag & IMA_STD_FIELD) de_interlace_st(ibuf);
- else de_interlace_ng(ibuf);
- }
/* timer */
BKE_image_tag_time(ima);
@@ -3495,7 +3410,7 @@ static ImBuf *load_image_single(
flag |= imbuf_alpha_flags_for_image(ima);
/* get the correct filepath */
- BKE_image_user_frame_calc(iuser, cfra, 0);
+ BKE_image_user_frame_calc(iuser, cfra);
if (iuser)
iuser_t = *iuser;
@@ -3528,9 +3443,6 @@ static ImBuf *load_image_single(
image_initialize_after_load(ima, ibuf);
*r_assign = true;
- /* check if the image is a font image... */
- detectBitmapFont(ibuf);
-
/* make packed file for autopack */
if ((has_packed == false) && (G.fileflags & G_AUTOPACK)) {
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
@@ -3691,11 +3603,12 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO))
actview = iuser->multiview_eye;
+ RenderSlot *slot;
if (from_render) {
RE_AcquireResultImage(re, &rres, actview);
}
- else if (ima->renders[ima->render_slot]) {
- rres = *(ima->renders[ima->render_slot]);
+ else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
+ rres = *(slot->render);
rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL;
}
else
@@ -4249,9 +4162,9 @@ void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
}
}
-int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool *r_is_in_range)
+int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, bool *r_is_in_range)
{
- const int len = (iuser->fie_ima * iuser->frames) / 2;
+ const int len = iuser->frames;
if (r_is_in_range) {
*r_is_in_range = false;
@@ -4287,12 +4200,8 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool
}
}
- /* convert current frame to current field */
- cfra = 2 * (cfra);
- if (fieldnr) cfra++;
-
/* transform to images space */
- framenr = (cfra + iuser->fie_ima - 2) / iuser->fie_ima;
+ framenr = cfra;
if (framenr > iuser->frames) framenr = iuser->frames;
if (iuser->cycl) {
@@ -4308,11 +4217,11 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool
}
}
-void BKE_image_user_frame_calc(ImageUser *iuser, int cfra, int fieldnr)
+void BKE_image_user_frame_calc(ImageUser *iuser, int cfra)
{
if (iuser) {
bool is_in_range;
- const int framenr = BKE_image_user_frame_get(iuser, cfra, fieldnr, &is_in_range);
+ const int framenr = BKE_image_user_frame_get(iuser, cfra, &is_in_range);
if (is_in_range) {
iuser->flag |= IMA_USER_FRAME_IN_RANGE;
@@ -4331,10 +4240,10 @@ void BKE_image_user_frame_calc(ImageUser *iuser, int cfra, int fieldnr)
}
}
-void BKE_image_user_check_frame_calc(ImageUser *iuser, int cfra, int fieldnr)
+void BKE_image_user_check_frame_calc(ImageUser *iuser, int cfra)
{
if ((iuser->flag & IMA_ANIM_ALWAYS) || (iuser->flag & IMA_NEED_FRAME_RECALC)) {
- BKE_image_user_frame_calc(iuser, cfra, fieldnr);
+ BKE_image_user_frame_calc(iuser, cfra);
iuser->flag &= ~IMA_NEED_FRAME_RECALC;
}
@@ -4345,7 +4254,7 @@ static void image_update_frame(struct Image *UNUSED(ima), struct ImageUser *iuse
{
int cfra = *(int *)customdata;
- BKE_image_user_check_frame_calc(iuser, cfra, 0);
+ BKE_image_user_check_frame_calc(iuser, cfra);
}
void BKE_image_update_frame(const Main *bmain, int cfra)
@@ -4553,15 +4462,6 @@ bool BKE_image_is_dirty(Image *image)
void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options)
{
-#if 0
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- if (ibuf) {
- ibuf->ftype = ftype;
- ibuf->foptions = options;
- }
- BKE_image_release_ibuf(image, ibuf, NULL);
-#endif
-
BLI_spin_lock(&image_spin);
if (image->cache != NULL) {
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
@@ -4725,3 +4625,97 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
}
}
}
+
+/**************************** Render Slots ***************************/
+
+RenderSlot *BKE_image_add_renderslot(Image *ima, const char *name)
+{
+ RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image new Render Slot");
+ if (name && name[0]) {
+ BLI_strncpy(slot->name, name, sizeof(slot->name));
+ }
+ else {
+ int n = BLI_listbase_count(&ima->renderslots) + 1;
+ BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", n);
+ }
+ BLI_addtail(&ima->renderslots, slot);
+ return slot;
+}
+
+bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int index)
+{
+ int num_slots = BLI_listbase_count(&ima->renderslots);
+ if (index >= num_slots || num_slots == 1) {
+ return false;
+ }
+
+ RenderSlot *remove_slot = BLI_findlink(&ima->renderslots, index);
+ RenderSlot *current_slot = BLI_findlink(&ima->renderslots, ima->render_slot);
+ RenderSlot *current_last_slot = BLI_findlink(&ima->renderslots, ima->last_render_slot);
+
+ RenderSlot *next_slot;
+ if (current_slot == remove_slot) {
+ next_slot = BLI_findlink(&ima->renderslots, (index == num_slots - 1) ? index - 1 : index + 1);
+ }
+ else {
+ next_slot = current_slot;
+ }
+
+ /* If the slot to be removed is the slot with the last render, make another slot the last render slot. */
+ if (remove_slot == current_last_slot) {
+ /* Choose the currently selected slot unless that one is being removed, in that case take the next one. */
+ RenderSlot *next_last_slot;
+ if (current_slot == remove_slot)
+ next_last_slot = next_slot;
+ else
+ next_last_slot = current_slot;
+
+ if (!iuser) return false;
+ Render *re = RE_GetSceneRender(iuser->scene);
+ if (!re) return false;
+ RE_SwapResult(re, &current_last_slot->render);
+ RE_SwapResult(re, &next_last_slot->render);
+ current_last_slot = next_last_slot;
+ }
+
+ current_slot = next_slot;
+
+ BLI_remlink(&ima->renderslots, remove_slot);
+
+ ima->render_slot = BLI_findindex(&ima->renderslots, current_slot);
+ ima->last_render_slot = BLI_findindex(&ima->renderslots, current_last_slot);
+
+ if (remove_slot->render) {
+ RE_FreeRenderResult(remove_slot->render);
+ }
+ MEM_freeN(remove_slot);
+
+ return true;
+}
+
+bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int index)
+{
+ if (index == ima->last_render_slot) {
+ if (!iuser) return false;
+ if (G.is_rendering) return false;
+ Render *re = RE_GetSceneRender(iuser->scene);
+ if (!re) return false;
+ RE_ClearResult(re);
+ return true;
+ }
+ else {
+ RenderSlot *slot = BLI_findlink(&ima->renderslots, index);
+ if (!slot) return false;
+ if (slot->render) {
+ RE_FreeRenderResult(slot->render);
+ slot->render = NULL;
+ }
+ return true;
+ }
+}
+
+RenderSlot *BKE_image_get_renderslot(Image *ima, int index)
+{
+ /* Can be NULL for images without render slots. */
+ return BLI_findlink(&ima->renderslots, index);
+}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index effbff37c33..aae208dd967 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -46,7 +46,6 @@
/* since we have versioning code here */
#define DNA_DEPRECATED_ALLOW
-#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
@@ -146,17 +145,6 @@ static AdrBit2Path ob_layer_bits[] = {
{(1 << 19), "layers", 19}
};
-/* Material mode */
-static AdrBit2Path ma_mode_bits[] = {
-// {MA_TRACEBLE, "traceable", 0},
-// {MA_SHADOW, "shadow", 0},
-// {MA_SHLESS, "shadeless", 0},
-// ...
- {MA_RAYTRANSP, "transparency", 0},
- {MA_RAYMIRROR, "raytrace_mirror.enabled", 0},
-// {MA_HALO, "type", MA_TYPE_HALO}
-};
-
/* ----------------- */
/* quick macro for returning the appropriate array for adrcode_bitmaps_to_paths() */
@@ -173,9 +161,6 @@ static AdrBit2Path *adrcode_bitmaps_to_paths(int blocktype, int adrcode, int *to
if ((blocktype == ID_OB) && (adrcode == OB_LAY)) {
RET_ABP(ob_layer_bits);
}
- else if ((blocktype == ID_MA) && (adrcode == MA_MODE)) {
- RET_ABP(ma_mode_bits);
- }
// XXX TODO: add other types...
/* Normal curve */
@@ -1767,23 +1752,6 @@ void do_versions_ipos_to_animato(Main *bmain)
ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL);
/* No need to id_us_min ipo ID here, ipo_to_animdata already does it. */
ob->ipo = NULL;
-
- {
- /* If we have any empty action actuators, assume they were
- * converted IPO Actuators using the object IPO */
- bActuator *act;
- bActionActuator *aa;
-
- for (act = ob->actuators.first; act; act = act->next) {
- /* Any actuators set to ACT_IPO at this point are actually Action Actuators that
- * need this converted IPO to finish converting the actuator. */
- if (act->type == ACT_IPO) {
- aa = (bActionActuator *)act->data;
- aa->act = ob->adt->action;
- act->type = ACT_ACTION;
- }
- }
- }
}
}
@@ -2029,7 +1997,7 @@ void do_versions_ipos_to_animato(Main *bmain)
for (id = bmain->lamp.first; id; id = id->next) {
Lamp *la = (Lamp *)id;
- if (G.debug & G_DEBUG) printf("\tconverting lamp %s\n", id->name + 2);
+ if (G.debug & G_DEBUG) printf("\tconverting light %s\n", id->name + 2);
/* we're only interested in the IPO */
if (la->ipo) {
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 4689575655e..a01d78f5c36 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -76,6 +76,12 @@
#define IPO_BEZTRIPLE 100
#define IPO_BPOINT 101
+/* Internal use only. */
+typedef struct WeightsArrayCache {
+ int num_defgroup_weights;
+ float **defgroup_weights;
+} WeightsArrayCache;
+
/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free(Key *key)
@@ -119,31 +125,31 @@ Key *BKE_key_add(Main *bmain, ID *id) /* common function */
case ID_ME:
el = key->elemstr;
- el[0] = 3;
+ el[0] = KEYELEM_FLOAT_LEN_COORD;
el[1] = IPO_FLOAT;
el[2] = 0;
- key->elemsize = 12;
+ key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
break;
case ID_LT:
el = key->elemstr;
- el[0] = 3;
+ el[0] = KEYELEM_FLOAT_LEN_COORD;
el[1] = IPO_FLOAT;
el[2] = 0;
- key->elemsize = 12;
+ key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
break;
case ID_CU:
el = key->elemstr;
- el[0] = 4;
+ el[0] = KEYELEM_ELEM_SIZE_CURVE;
el[1] = IPO_BPOINT;
el[2] = 0;
- key->elemsize = 16;
+ key->elemsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
break;
@@ -540,31 +546,33 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **
/* currently only the first value of 'ofs' may be set. */
-static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs)
+static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs, int *step)
{
if (key->from == NULL) {
return false;
}
+ *step = 1;
+
switch (GS(key->from->name)) {
case ID_ME:
- *ofs = sizeof(float) * 3;
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
*poinsize = *ofs;
break;
case ID_LT:
- *ofs = sizeof(float) * 3;
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
*poinsize = *ofs;
break;
case ID_CU:
if (mode == KEY_MODE_BPOINT) {
- *ofs = sizeof(float) * 4;
- *poinsize = *ofs;
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]);
+ *step = KEYELEM_ELEM_LEN_BPOINT;
}
else {
- ofs[0] = sizeof(float) * 12;
- *poinsize = (*ofs) / 3;
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]);
+ *step = KEYELEM_ELEM_LEN_BEZTRIPLE;
}
-
+ *poinsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
break;
default:
BLI_assert(!"invalid 'key->from' ID type");
@@ -577,14 +585,14 @@ static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int
static void cp_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode)
{
float ktot = 0.0, kd = 0.0;
- int elemsize, poinsize = 0, a, *ofsp, ofs[32], flagflo = 0;
+ int elemsize, poinsize = 0, a, step, *ofsp, ofs[32], flagflo = 0;
char *k1, *kref, *freek1, *freekref;
char *cp, elemstr[8];
/* currently always 0, in future key_pointer_size may assign */
ofs[1] = 0;
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0]))
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
return;
if (end > tot) end = tot;
@@ -628,10 +636,9 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
}
/* just do it here, not above! */
- elemsize = key->elemsize;
- if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+ elemsize = key->elemsize * step;
- for (a = start; a < end; a++) {
+ for (a = start; a < end; a += step) {
cp = key->elemstr;
if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr;
@@ -642,20 +649,20 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
switch (cp[1]) {
case IPO_FLOAT:
if (weights) {
- memcpy(poin, kref, sizeof(float) * 3);
+ memcpy(poin, kref, sizeof(float[KEYELEM_FLOAT_LEN_COORD]));
if (*weights != 0.0f)
- rel_flerp(cp[0], (float *)poin, (float *)kref, (float *)k1, *weights);
+ rel_flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)kref, (float *)k1, *weights);
weights++;
}
else {
- memcpy(poin, k1, sizeof(float) * 3);
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_COORD]));
}
break;
case IPO_BPOINT:
- memcpy(poin, k1, sizeof(float) * 4);
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]));
break;
case IPO_BEZTRIPLE:
- memcpy(poin, k1, sizeof(float) * 12);
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]));
break;
default:
/* should never happen */
@@ -682,10 +689,6 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
k1 += elemsize;
kref += elemsize;
}
-
- if (mode == KEY_MODE_BEZTRIPLE) {
- a += 2;
- }
}
if (freek1) MEM_freeN(freek1);
@@ -699,7 +702,7 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
if (nu->bp) {
- step = nu->pntsu * nu->pntsv;
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
a1 = max_ii(a, start);
a2 = min_ii(a + step, end);
@@ -707,7 +710,7 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BPOINT);
}
else if (nu->bezt) {
- step = 3 * nu->pntsu;
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
/* exception because keys prefer to work with complete blocks */
a1 = max_ii(a, start);
@@ -721,18 +724,19 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
}
}
-void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
- float **per_keyblock_weights, const int mode)
+static void key_evaluate_relative(
+ const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
+ float **per_keyblock_weights, const int mode)
{
KeyBlock *kb;
- int *ofsp, ofs[3], elemsize, b;
+ int *ofsp, ofs[3], elemsize, b, step;
char *cp, *poin, *reffrom, *from, elemstr[8];
int poinsize, keyblock_index;
/* currently always 0, in future key_pointer_size may assign */
ofs[1] = 0;
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0]))
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
return;
if (end > tot) end = tot;
@@ -743,8 +747,7 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
elemstr[2] = 0;
/* just here, not above! */
- elemsize = key->elemsize;
- if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+ elemsize = key->elemsize * step;
/* step 1 init */
cp_key(start, end, tot, basispoin, key, actkb, key->refkey, NULL, mode);
@@ -773,7 +776,7 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
reffrom += key->elemsize * start; // key elemsize yes!
from += key->elemsize * start;
- for (b = start; b < end; b++) {
+ for (b = start; b < end; b += step) {
weight = weights ? (*weights * icuval) : icuval;
@@ -786,13 +789,13 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
switch (cp[1]) {
case IPO_FLOAT:
- rel_flerp(3, (float *)poin, (float *)reffrom, (float *)from, weight);
+ rel_flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)reffrom, (float *)from, weight);
break;
case IPO_BPOINT:
- rel_flerp(4, (float *)poin, (float *)reffrom, (float *)from, weight);
+ rel_flerp(KEYELEM_FLOAT_LEN_BPOINT, (float *)poin, (float *)reffrom, (float *)from, weight);
break;
case IPO_BEZTRIPLE:
- rel_flerp(12, (float *)poin, (float *)reffrom, (float *)from, weight);
+ rel_flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE, (float *)poin, (float *)reffrom, (float *)from, weight);
break;
default:
/* should never happen */
@@ -811,7 +814,6 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
reffrom += elemsize;
from += elemsize;
- if (mode == KEY_MODE_BEZTRIPLE) b += 2;
if (weights) weights++;
}
@@ -827,7 +829,7 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
{
float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0;
float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0;
- int a, ofs[32], *ofsp;
+ int a, step, ofs[32], *ofsp;
int flagdo = 15, flagflo = 0, elemsize, poinsize = 0;
char *k1, *k2, *k3, *k4, *freek1, *freek2, *freek3, *freek4;
char *cp, elemstr[8];
@@ -835,7 +837,7 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
/* currently always 0, in future key_pointer_size may assign */
ofs[1] = 0;
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0]))
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
return;
if (end > tot) end = tot;
@@ -953,11 +955,9 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
elemstr[2] = 0;
/* only here, not above! */
- elemsize = key->elemsize;
- if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
-
- for (a = start; a < end; a++) {
+ elemsize = key->elemsize * step;
+ for (a = start; a < end; a += step) {
cp = key->elemstr;
if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr;
@@ -967,13 +967,13 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
switch (cp[1]) {
case IPO_FLOAT:
- flerp(3, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
+ flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
break;
case IPO_BPOINT:
- flerp(4, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
+ flerp(KEYELEM_FLOAT_LEN_BPOINT, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
break;
case IPO_BEZTRIPLE:
- flerp(12, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t);
+ flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t);
break;
default:
/* should never happen */
@@ -1038,8 +1038,6 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
k4 += elemsize;
}
}
-
- if (mode == KEY_MODE_BEZTRIPLE) a += 2;
}
if (freek1) MEM_freeN(freek1);
@@ -1120,7 +1118,7 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac
return NULL;
}
-float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache)
+static float **keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache)
{
KeyBlock *keyblock;
float **per_keyblock_weights;
@@ -1140,7 +1138,7 @@ float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCac
return per_keyblock_weights;
}
-void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache)
+static void keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache)
{
int a;
@@ -1175,9 +1173,9 @@ static void do_mesh_key(Object *ob, Key *key, char *out, const int tot)
if (key->type == KEY_RELATIVE) {
WeightsArrayCache cache = {0, NULL};
float **per_keyblock_weights;
- per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, &cache);
- BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
- BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache);
+ per_keyblock_weights = keyblock_get_per_block_weights(ob, key, &cache);
+ key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
+ keyblock_free_per_block_weights(key, per_keyblock_weights, &cache);
}
else {
const float ctime_scaled = key->ctime / 100.0f;
@@ -1200,11 +1198,11 @@ static void do_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock **k, float
for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
if (nu->bp) {
- step = nu->pntsu * nu->pntsv;
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BPOINT);
}
else if (nu->bezt) {
- step = 3 * nu->pntsu;
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BEZTRIPLE);
}
else {
@@ -1220,12 +1218,12 @@ static void do_rel_cu_key(Curve *cu, Key *key, KeyBlock *actkb, char *out, const
for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
if (nu->bp) {
- step = nu->pntsu * nu->pntsv;
- BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT);
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
+ key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT);
}
else if (nu->bezt) {
- step = 3 * nu->pntsu;
- BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE);
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
+ key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE);
}
else {
step = 0;
@@ -1266,9 +1264,9 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
if (key->type == KEY_RELATIVE) {
float **per_keyblock_weights;
- per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, NULL);
- BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
- BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, NULL);
+ per_keyblock_weights = keyblock_get_per_block_weights(ob, key, NULL);
+ key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
+ keyblock_free_per_block_weights(key, per_keyblock_weights, NULL);
}
else {
const float ctime_scaled = key->ctime / 100.0f;
@@ -1304,28 +1302,19 @@ float *BKE_key_evaluate_object_ex(
Mesh *me = ob->data;
tot = me->totvert;
- size = tot * 3 * sizeof(float);
+ size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
tot = lt->pntsu * lt->pntsv * lt->pntsw;
- size = tot * 3 * sizeof(float);
+ size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- Nurb *nu;
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- tot += 3 * nu->pntsu;
- size += nu->pntsu * 12 * sizeof(float);
- }
- else if (nu->bp) {
- tot += nu->pntsu * nu->pntsv;
- size += nu->pntsu * nu->pntsv * 12 * sizeof(float);
- }
- }
+ tot = BKE_keyblock_curve_element_count(&cu->nurb);
+ size = tot * sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
}
/* if nothing to interpolate, cancel */
@@ -1457,7 +1446,7 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
kb = MEM_callocN(sizeof(KeyBlock), "Keyblock");
BLI_addtail(&key->block, kb);
- kb->type = KEY_CARDINAL;
+ kb->type = KEY_LINEAR;
tot = BLI_listbase_count(&key->block);
if (name) {
@@ -1661,6 +1650,24 @@ void BKE_keyblock_convert_to_lattice(KeyBlock *kb, Lattice *lt)
}
/************************* Curve ************************/
+
+int BKE_keyblock_curve_element_count(ListBase *nurb)
+{
+ Nurb *nu;
+ int tot = 0;
+
+ nu = nurb->first;
+ while (nu) {
+ if (nu->bezt)
+ tot += KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
+ else if (nu->bp)
+ tot += KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
+
+ nu = nu->next;
+ }
+ return tot;
+}
+
void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *nurb)
{
Nurb *nu;
@@ -1670,7 +1677,7 @@ void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *n
int a, tot;
/* count */
- BLI_assert(BKE_nurbList_verts_count(nurb) == kb->totelem);
+ BLI_assert(BKE_keyblock_curve_element_count(nurb) == kb->totelem);
tot = kb->totelem;
if (tot == 0) return;
@@ -1679,21 +1686,20 @@ void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *n
for (nu = nurb->first; nu; nu = nu->next) {
if (nu->bezt) {
for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3) {
- copy_v3_v3(fp, bezt->vec[i]);
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(&fp[i * 3], bezt->vec[i]);
}
- fp[0] = bezt->alfa;
- fp += 3; /* alphas */
+ fp[9] = bezt->alfa;
+ fp[10] = bezt->radius;
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
-
- ;
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, fp += 4, bp++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++) {
copy_v3_v3(fp, bp->vec);
fp[3] = bp->alfa;
+ fp[4] = bp->radius;
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -1704,7 +1710,7 @@ void BKE_keyblock_convert_from_curve(Curve *cu, KeyBlock *kb, ListBase *nurb)
int tot;
/* count */
- tot = BKE_nurbList_verts_count(nurb);
+ tot = BKE_keyblock_curve_element_count(nurb);
if (tot == 0) return;
MEM_SAFE_FREE(kb->data);
@@ -1723,26 +1729,27 @@ void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nu
const float *fp;
int a, tot;
- tot = BKE_nurbList_verts_count(nurb);
+ tot = BKE_keyblock_curve_element_count(nurb);
tot = min_ii(kb->totelem, tot);
fp = kb->data;
for (nu = nurb->first; nu && tot > 0; nu = nu->next) {
if (nu->bezt) {
- for (a = nu->pntsu, bezt = nu->bezt; a && tot > 0; a--, tot -= 3, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3) {
- copy_v3_v3(bezt->vec[i], fp);
+ for (a = nu->pntsu, bezt = nu->bezt; a && (tot -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; a--, bezt++) {
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(bezt->vec[i], &fp[i * 3]);
}
- bezt->alfa = fp[0];
- fp += 3; /* alphas */
+ bezt->alfa = fp[9];
+ bezt->radius = fp[10];
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && tot; a--, tot--, fp += 4, bp++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && (tot -= KEYELEM_ELEM_LEN_BPOINT) >= 0; a--, bp++) {
copy_v3_v3(bp->vec, fp);
bp->alfa = fp[3];
+ bp->radius = fp[4];
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -1767,16 +1774,16 @@ void BKE_keyblock_update_from_mesh(Mesh *me, KeyBlock *kb)
}
}
-void BKE_keyblock_convert_from_mesh(Mesh *me, KeyBlock *kb)
+void BKE_keyblock_convert_from_mesh(Mesh *me, Key *key, KeyBlock *kb)
{
- int tot = me->totvert;
+ const int len = me->totvert;
if (me->totvert == 0) return;
MEM_SAFE_FREE(kb->data);
- kb->data = MEM_mallocN(me->key->elemsize * tot, __func__);
- kb->totelem = tot;
+ kb->data = MEM_malloc_arrayN((size_t)len, (size_t)key->elemsize, __func__);
+ kb->totelem = len;
BKE_keyblock_update_from_mesh(me, kb);
}
@@ -1871,7 +1878,7 @@ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- BLI_assert(BKE_nurbList_verts_count(&cu->nurb) == kb->totelem);
+ BLI_assert(BKE_keyblock_curve_element_count(&cu->nurb) == kb->totelem);
}
else if (ob->type == OB_MESH) {
Mesh *me = ob->data;
@@ -1900,17 +1907,16 @@ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->bezt) {
for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3, co++) {
- copy_v3_v3(fp, *co);
+ for (int i = 0; i < 3; i++, co++) {
+ copy_v3_v3(&fp[i * 3], *co);
}
- fp += 3; /* skip alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, co++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) {
copy_v3_v3(fp, *co);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -1937,7 +1943,7 @@ void BKE_keyblock_convert_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = (Curve *)ob->data;
elemsize = cu->key->elemsize;
- tot = BKE_nurbList_verts_count(&cu->nurb);
+ tot = BKE_keyblock_curve_element_count(&cu->nurb);
}
if (tot == 0) return;
@@ -1987,17 +1993,16 @@ float (*BKE_keyblock_convert_to_vertcos(Object *ob, KeyBlock *kb))[3]
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->bezt) {
for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3, co++) {
- copy_v3_v3(*co, fp);
+ for (int i = 0; i < 3; i++, co++) {
+ copy_v3_v3(*co, &fp[i * 3]);
}
- fp += 3; /* skip alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, co++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) {
copy_v3_v3(*co, fp);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -2026,17 +2031,16 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->bezt) {
for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3, ofs++) {
- add_v3_v3(fp, *ofs);
+ for (int i = 0; i < 3; i++, ofs++) {
+ add_v3_v3(&fp[i * 3], *ofs);
}
- fp += 3; /* skip alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, ofs++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, ofs++) {
add_v3_v3(fp, *ofs);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
diff --git a/source/blender/blenkernel/intern/keyconfig.c b/source/blender/blenkernel/intern/keyconfig.c
new file mode 100644
index 00000000000..f2db375f3ec
--- /dev/null
+++ b/source/blender/blenkernel/intern/keyconfig.c
@@ -0,0 +1,137 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/keyconfig.c
+ * \ingroup bke
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "RNA_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_keyconfig.h" /* own include */
+#include "BKE_idprop.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* -------------------------------------------------------------------- */
+/** \name Key-Config Preference (UserDef) API
+ *
+ * \see #BKE_addon_pref_type_init for logic this is bases on.
+ * \{ */
+
+wmKeyConfigPref *BKE_keyconfig_pref_ensure(UserDef *userdef, const char *kc_idname)
+{
+ wmKeyConfigPref *kpt = BLI_findstring(
+ &userdef->user_keyconfig_prefs, kc_idname, offsetof(wmKeyConfigPref, idname));
+ if (kpt == NULL) {
+ kpt = MEM_callocN(sizeof(*kpt), __func__);
+ STRNCPY(kpt->idname, kc_idname);
+ BLI_addtail(&userdef->user_keyconfig_prefs, kpt);
+ }
+ if (kpt->prop == NULL) {
+ IDPropertyTemplate val = {0};
+ kpt->prop = IDP_New(IDP_GROUP, &val, kc_idname); /* name is unimportant */
+ }
+ return kpt;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Key-Config Preference (RNA Type) API
+ *
+ * \see #BKE_addon_pref_type_init for logic this is bases on.
+ * \{ */
+
+static GHash *global_keyconfigpreftype_hash = NULL;
+
+
+wmKeyConfigPrefType_Runtime *BKE_keyconfig_pref_type_find(const char *idname, bool quiet)
+{
+ if (idname[0]) {
+ wmKeyConfigPrefType_Runtime *kpt_rt;
+
+ kpt_rt = BLI_ghash_lookup(global_keyconfigpreftype_hash, idname);
+ if (kpt_rt) {
+ return kpt_rt;
+ }
+
+ if (!quiet) {
+ printf("search for unknown keyconfig-pref '%s'\n", idname);
+ }
+ }
+ else {
+ if (!quiet) {
+ printf("search for empty keyconfig-pref\n");
+ }
+ }
+
+ return NULL;
+}
+
+void BKE_keyconfig_pref_type_add(wmKeyConfigPrefType_Runtime *kpt_rt)
+{
+ BLI_ghash_insert(global_keyconfigpreftype_hash, kpt_rt->idname, kpt_rt);
+}
+
+void BKE_keyconfig_pref_type_remove(const wmKeyConfigPrefType_Runtime *kpt_rt)
+{
+ BLI_ghash_remove(global_keyconfigpreftype_hash, kpt_rt->idname, NULL, MEM_freeN);
+}
+
+void BKE_keyconfig_pref_type_init(void)
+{
+ BLI_assert(global_keyconfigpreftype_hash == NULL);
+ global_keyconfigpreftype_hash = BLI_ghash_str_new(__func__);
+}
+
+void BKE_keyconfig_pref_type_free(void)
+{
+ BLI_ghash_free(global_keyconfigpreftype_hash, NULL, MEM_freeN);
+ global_keyconfigpreftype_hash = NULL;
+}
+
+/* Set select mouse, for versioning code. */
+void BKE_keyconfig_pref_set_select_mouse(UserDef *userdef, int value, bool override)
+{
+ wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(userdef, WM_KEYCONFIG_STR_DEFAULT);
+ IDProperty *idprop = IDP_GetPropertyFromGroup(kpt->prop, "select_mouse");
+ if (!idprop) {
+ IDPropertyTemplate tmp = { .i = value };
+ IDP_AddToGroup(kpt->prop, IDP_New(IDP_INT, &tmp, "select_mouse"));
+ }
+ else if (override) {
+ IDP_Int(idprop) = value;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 84a8e11bdc8..681ff3b619f 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -59,47 +59,37 @@ void BKE_lamp_init(Lamp *la)
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(la, id));
la->r = la->g = la->b = la->k = 1.0f;
- la->haint = la->energy = 1.0f;
+ la->energy = 10.0f;
la->dist = 25.0f;
la->spotsize = DEG2RADF(45.0f);
la->spotblend = 0.15f;
la->att2 = 1.0f;
- la->mode = LA_SHAD_BUF;
+ la->mode = LA_SHADOW;
la->bufsize = 512;
la->clipsta = 0.5f;
la->clipend = 40.0f;
+ la->bleedexp = 2.5f;
la->samp = 3;
la->bias = 1.0f;
la->soft = 3.0f;
- la->compressthresh = 0.05f;
- la->ray_samp = la->ray_sampy = la->ray_sampz = 1;
- la->area_size = la->area_sizey = la->area_sizez = 0.1f;
+ la->area_size = la->area_sizey = la->area_sizez = 0.25f;
la->buffers = 1;
- la->buftype = LA_SHADBUF_HALFWAY;
- la->ray_samp_method = LA_SAMP_HALTON;
- la->adapt_thresh = 0.001f;
la->preview = NULL;
la->falloff_type = LA_FALLOFF_INVSQUARE;
la->coeff_const = 1.0f;
la->coeff_lin = 0.0f;
la->coeff_quad = 0.0f;
la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
- la->sun_effect_type = 0;
- la->horizon_brightness = 1.0;
- la->spread = 1.0;
- la->sun_brightness = 1.0;
- la->sun_size = 1.0;
- la->backscattered_light = 1.0f;
- la->atm_turbidity = 2.0f;
- la->atm_inscattering_factor = 1.0f;
- la->atm_extinction_factor = 1.0f;
- la->atm_distance_factor = 1.0f;
- la->sun_intensity = 1.0f;
- la->skyblendtype = MA_RAMP_ADD;
- la->skyblendfac = 1.0f;
- la->sky_colorspace = BLI_XYZ_CIE;
- la->sky_exposure = 1.0f;
- la->shadow_frustum_size = 10.0f;
+ la->cascade_max_dist = 200.0f;
+ la->cascade_count = 4;
+ la->cascade_exponent = 0.8f;
+ la->cascade_fade = 0.1f;
+ la->contact_dist = 0.2f;
+ la->contact_bias = 0.03f;
+ la->contact_spread = 0.2f;
+ la->contact_thickness = 0.2f;
+ la->spec_fac = 1.0f;
+ la->att_dist = 40.0f;
curvemapping_initialize(la->curfalloff);
}
@@ -125,13 +115,6 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
*/
void BKE_lamp_copy_data(Main *bmain, Lamp *la_dst, const Lamp *la_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (la_dst->mtex[a]) {
- la_dst->mtex[a] = MEM_mallocN(sizeof(*la_dst->mtex[a]), __func__);
- *la_dst->mtex[a] = *la_src->mtex[a];
- }
- }
-
la_dst->curfalloff = curvemapping_copy(la_src->curfalloff);
if (la_src->nodetree) {
@@ -167,17 +150,7 @@ Lamp *BKE_lamp_localize(Lamp *la)
*
* NOTE: Only possible once nested node trees are fully converted to that too. */
- Lamp *lan;
- int a;
-
- lan = BKE_libblock_copy_nolib(&la->id, false);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (lan->mtex[a]) {
- lan->mtex[a] = MEM_mallocN(sizeof(MTex), __func__);
- memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
- }
- }
+ Lamp *lan = BKE_libblock_copy_nolib(&la->id, false);
lan->curfalloff = curvemapping_copy(la->curfalloff);
@@ -186,6 +159,8 @@ Lamp *BKE_lamp_localize(Lamp *la)
lan->preview = NULL;
+ lan->id.tag |= LIB_TAG_LOCALIZED;
+
return lan;
}
@@ -196,12 +171,6 @@ void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local)
void BKE_lamp_free(Lamp *la)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(la->mtex[a]);
- }
-
BKE_animdata_free((ID *)la, false);
curvemapping_free(la->curfalloff);
@@ -217,40 +186,3 @@ void BKE_lamp_free(Lamp *la)
BKE_icon_id_delete(&la->id);
la->id.icon_id = 0;
}
-
-/* Calculate all drivers for lamps, see material_drivers_update for why this is a bad hack */
-
-static void lamp_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime)
-{
- bNode *node;
-
- /* nodetree itself */
- if (ntree->adt && ntree->adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS);
-
- /* nodes */
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->id && node->type == NODE_GROUP)
- lamp_node_drivers_update(scene, (bNodeTree *)node->id, ctime);
-}
-
-void lamp_drivers_update(Scene *scene, Lamp *la, float ctime)
-{
- /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited already
- * (see BKE_scene_update_tagged()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else
- * in the meantime... [#32017] */
- if (la->id.tag & LIB_TAG_DOIT)
- return;
-
- la->id.tag |= LIB_TAG_DOIT;
-
- /* lamp itself */
- if (la->adt && la->adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, &la->id, la->adt, ctime, ADT_RECALC_DRIVERS);
-
- /* nodes */
- if (la->nodetree)
- lamp_node_drivers_update(scene, la->nodetree, ctime);
-
- la->id.tag &= ~LIB_TAG_DOIT;
-}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 1e99712f47a..0fa675639ea 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -53,7 +53,6 @@
#include "BKE_anim.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -66,10 +65,7 @@
#include "BKE_deform.h"
-/* Workaround for cyclic dependency with curves.
- * In such case curve_cache might not be ready yet,
- */
-#define CYCLIC_DEPENDENCY_WORKAROUND
+#include "DEG_depsgraph_query.h"
int BKE_lattice_index_from_uvw(Lattice *lt,
const int u, const int v, const int w)
@@ -215,9 +211,9 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
/* works best if we force to linear type (endpoints match) */
lt->typeu = lt->typev = lt->typew = KEY_LINEAR;
- /* prevent using deformed locations */
- if (ltOb->curve_cache != NULL) {
- BKE_displist_free(&ltOb->curve_cache->disp);
+ if (ltOb->runtime.curve_cache) {
+ /* prevent using deformed locations */
+ BKE_displist_free(&ltOb->runtime.curve_cache->disp);
}
copy_m4_m4(mat, ltOb->obmat);
@@ -290,7 +286,7 @@ void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src,
{
lt_dst->def = MEM_dupallocN(lt_src->def);
- if (lt_src->key) {
+ if (lt_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &lt_src->key->id, (ID **)&lt_dst->key, flag, false);
}
@@ -306,7 +302,7 @@ void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src,
Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt)
{
Lattice *lt_copy;
- BKE_id_copy_ex(bmain, &lt->id, (ID **)&lt_copy, 0, false);
+ BKE_id_copy_ex(bmain, &lt->id, (ID **)&lt_copy, LIB_ID_COPY_SHAPEKEY, false);
return lt_copy;
}
@@ -315,6 +311,8 @@ void BKE_lattice_free(Lattice *lt)
{
BKE_animdata_free(&lt->id, false);
+ BKE_lattice_batch_cache_free(lt);
+
MEM_SAFE_FREE(lt->def);
if (lt->dvert) {
BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
@@ -351,7 +349,7 @@ LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob)
/* we make an array with all differences */
Lattice *lt = oblatt->data;
BPoint *bp;
- DispList *dl = oblatt->curve_cache ? BKE_displist_find(&oblatt->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = oblatt->runtime.curve_cache ? BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : NULL;
const float *co = dl ? dl->verts : NULL;
float *fp, imat[4][4];
float fu, fv, fw;
@@ -422,10 +420,11 @@ void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float
int defgrp_index = -1;
float co_prev[3], weight_blend = 0.0f;
MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
+ float *__restrict latticedata = lattice_deform_data->latticedata;
if (lt->editlatt) lt = lt->editlatt->latt;
- if (lattice_deform_data->latticedata == NULL) return;
+ if (latticedata == NULL) return;
if (lt->vgroup[0] && dvert) {
defgrp_index = defgroup_name_index(ob, lt->vgroup);
@@ -506,7 +505,7 @@ void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float
idx_u = idx_v;
}
- madd_v3_v3fl(co, &lattice_deform_data->latticedata[idx_u * 3], u);
+ madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
if (defgrp_index != -1)
weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index));
@@ -559,7 +558,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
int cycl = 0;
/* test for cyclic */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (!bl->nr) return false;
if (bl->poly > -1) cycl = 1;
@@ -574,7 +573,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
if (cycl == 0) {
- Path *path = ob->curve_cache->path;
+ Path *path = ob->runtime.curve_cache->path;
float dvec[3];
if (ctime < 0.0f) {
@@ -603,7 +602,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
/* co: local coord, result local too */
/* returns quaternion for rotation, using cd->no_rot_axis */
/* axis is using another define!!! */
-static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
+static bool calc_curve_deform(Object *par, float co[3],
const short axis, CurveDeform *cd, float r_quat[4])
{
Curve *cu = par->data;
@@ -611,14 +610,12 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
short index;
const bool is_neg_axis = (axis > 2);
- /* to be sure, mostly after file load, also cyclic dependencies */
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (par->curve_cache == NULL) {
- BKE_displist_make_curveTypes(scene, par, false);
+ if (par->runtime.curve_cache == NULL) {
+ /* Happens with a cyclic dependencies. */
+ return false;
}
-#endif
- if (par->curve_cache->path == NULL) {
+ if (par->runtime.curve_cache->path == NULL) {
return false; /* happens on append, cyclic dependencies and empty curves */
}
@@ -628,7 +625,7 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
if (cu->flag & CU_STRETCH)
fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
else
- fac = -(co[index] - cd->dmax[index]) / (par->curve_cache->path->totdist);
+ fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist);
}
else {
index = axis;
@@ -636,8 +633,8 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
}
else {
- if (LIKELY(par->curve_cache->path->totdist > FLT_EPSILON)) {
- fac = +(co[index] - cd->dmin[index]) / (par->curve_cache->path->totdist);
+ if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
+ fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist);
}
else {
fac = 0.0f;
@@ -707,14 +704,12 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
}
void curve_deform_verts(
- Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
- int numVerts, const char *vgroup, short defaxis)
+ Object *cuOb, Object *target, float (*vertexCos)[3],
+ int numVerts, MDeformVert *dvert, const int defgrp_index, short defaxis)
{
Curve *cu;
int a;
CurveDeform cd;
- MDeformVert *dvert = NULL;
- int defgrp_index = -1;
const bool is_neg_axis = (defaxis > 2);
if (cuOb->type != OB_CURVE)
@@ -735,26 +730,6 @@ void curve_deform_verts(
cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
}
- /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice).
- * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
- */
- if (vgroup && vgroup[0] && ELEM(target->type, OB_MESH, OB_LATTICE)) {
- defgrp_index = defgroup_name_index(target, vgroup);
-
- if (defgrp_index != -1) {
- /* if there's derived data without deformverts, don't use vgroups */
- if (dm) {
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
- }
- else if (target->type == OB_LATTICE) {
- dvert = ((Lattice *)target->data)->dvert;
- }
- else {
- dvert = ((Mesh *)target->data)->dvert;
- }
- }
- }
-
if (dvert) {
MDeformVert *dvert_iter;
float vec[3];
@@ -766,7 +741,7 @@ void curve_deform_verts(
if (weight > 0.0f) {
mul_m4_v3(cd.curvespace, vertexCos[a]);
copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
@@ -789,7 +764,7 @@ void curve_deform_verts(
if (weight > 0.0f) {
/* already in 'cd.curvespace', prev for loop */
copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
@@ -800,7 +775,7 @@ void curve_deform_verts(
if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
for (a = 0; a < numVerts; a++) {
mul_m4_v3(cd.curvespace, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
}
@@ -815,7 +790,7 @@ void curve_deform_verts(
for (a = 0; a < numVerts; a++) {
/* already in 'cd.curvespace', prev for loop */
- calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
}
@@ -825,7 +800,7 @@ void curve_deform_verts(
/* input vec and orco = local coord in armature space */
/* orco is original not-animated or deformed reference point */
/* result written in vec and mat */
-void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
+void curve_deform_vector(Object *cuOb, Object *target,
float orco[3], float vec[3], float mat[3][3], int no_rot_axis)
{
CurveDeform cd;
@@ -844,7 +819,7 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
mul_m4_v3(cd.curvespace, vec);
- if (calc_curve_deform(scene, cuOb, vec, target->trackflag, &cd, quat)) {
+ if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) {
float qmat[3][3];
quat_to_mat3(qmat, quat);
@@ -857,7 +832,7 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
}
-void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
+void lattice_deform_verts(Object *laOb, Object *target, Mesh *mesh,
float (*vertexCos)[3], int numVerts, const char *vgroup, float fac)
{
LatticeDeformData *lattice_deform_data;
@@ -878,8 +853,8 @@ void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
if (defgrp_index != -1) {
/* if there's derived data without deformverts, don't use vgroups */
- if (dm) {
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ if (mesh) {
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
}
else if (target->type == OB_LATTICE) {
dvert = ((Lattice *)target->data)->dvert;
@@ -1027,47 +1002,54 @@ void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3])
}
}
-void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
+void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
Lattice *lt = ob->data;
+ /* Get vertex coordinates from the original copy; otherwise we get already-modified coordinates. */
+ Object *ob_orig = DEG_get_original_object(ob);
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
float (*vertexCos)[3] = NULL;
int numVerts, editmode = (lt->editlatt != NULL);
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
}
else {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
}
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue;
if (!(md->mode & eModifierMode_Realtime)) continue;
if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
- if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue;
if (mti->type != eModifierTypeType_OnlyDeform) continue;
- if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts);
- mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0);
+ if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
+ mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts);
}
- /* always displist to make this work like derivedmesh */
- if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts);
+ if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ if (vertexCos) {
+ BKE_lattice_vertexcos_apply(ob, vertexCos);
+ MEM_freeN(vertexCos);
+ }
+ }
+ else {
+ /* Displist won't do anything; this is just for posterity's sake until we remove it. */
+ if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
- {
DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
dl->type = DL_VERTS;
dl->parts = 1;
dl->nr = numVerts;
dl->verts = (float *) vertexCos;
- BLI_addtail(&ob->curve_cache->disp, dl);
+ BLI_addtail(&ob->runtime.curve_cache->disp, dl);
}
}
@@ -1141,7 +1123,7 @@ BoundBox *BKE_lattice_boundbox_get(Object *ob)
void BKE_lattice_minmax_dl(Object *ob, Lattice *lt, float min[3], float max[3])
{
- DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL;
if (!dl) {
BKE_lattice_minmax(lt, min, max);
@@ -1226,9 +1208,42 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
}
}
+bool BKE_lattice_is_any_selected(const Lattice *lt)
+{
+ /* Intentionally don't handle 'lt->editlatt' (caller must do this). */
+ const BPoint *bp = lt->def;
+ int a = lt->pntsu * lt->pntsv * lt->pntsw;
+ while (a--) {
+ if (bp->hide == 0) {
+ if (bp->f1 & SELECT) {
+ return true;
+ }
+ }
+ bp++;
+ }
+ return false;
+}
+
/* **** Depsgraph evaluation **** */
-void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_lattice_eval_geometry(struct Depsgraph *UNUSED(depsgraph),
Lattice *UNUSED(latt))
{
}
+
+/* Draw Engine */
+void (*BKE_lattice_batch_cache_dirty_tag_cb)(Lattice *lt, int mode) = NULL;
+void (*BKE_lattice_batch_cache_free_cb)(Lattice *lt) = NULL;
+
+void BKE_lattice_batch_cache_dirty_tag(Lattice *lt, int mode)
+{
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_dirty_tag_cb(lt, mode);
+ }
+}
+void BKE_lattice_batch_cache_free(Lattice *lt)
+{
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_free_cb(lt);
+ }
+}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
new file mode 100644
index 00000000000..f525893a854
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer.c
@@ -0,0 +1,1533 @@
+/*
+ * ***** 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): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/layer.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_array.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_threads.h"
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+#include "BKE_collection.h"
+#include "BKE_freestyle.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+
+#include "DNA_ID.h"
+#include "DNA_space_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DRW_engine.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* prototype */
+static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
+
+
+/*********************** Layer Collections and bases *************************/
+
+static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection)
+{
+ LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
+ lc->collection = collection;
+ BLI_addtail(lb_parent, lc);
+
+ return lc;
+}
+
+static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc == view_layer->active_collection) {
+ view_layer->active_collection = NULL;
+ }
+
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ layer_collection_free(view_layer, nlc);
+ }
+
+ BLI_freelistN(&lc->layer_collections);
+}
+
+static Base *object_base_new(Object *ob)
+{
+ Base *base = MEM_callocN(sizeof(Base), "Object Base");
+ base->object = ob;
+ return base;
+}
+
+/********************************* View Layer ********************************/
+
+
+/* RenderLayer */
+
+/* Returns the default view layer to view in workspaces if there is
+ * none linked to the workspace yet. */
+ViewLayer *BKE_view_layer_default_view(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (!(view_layer->flag & VIEW_LAYER_RENDER)) {
+ return view_layer;
+ }
+ }
+
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+/* Returns the default view layer to render if we need to render just one. */
+ViewLayer *BKE_view_layer_default_render(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (view_layer->flag & VIEW_LAYER_RENDER) {
+ return view_layer;
+ }
+ }
+
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+/* Returns view layer with matching name, or NULL if not found. */
+ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (STREQ(view_layer->name, layer_name)) {
+ return view_layer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * This is a placeholder to know which areas of the code need to be addressed
+ * for the Workspace changes. Never use this, you should typically get the
+ * active layer from the context or window.
+ */
+ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
+{
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+static ViewLayer *view_layer_add(const char *name)
+{
+ if (!name) {
+ name = DATA_("View Layer");
+ }
+
+ ViewLayer *view_layer = MEM_callocN(sizeof(ViewLayer), "View Layer");
+ view_layer->flag = VIEW_LAYER_RENDER | VIEW_LAYER_FREESTYLE;
+
+ BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name));
+
+ /* Pure rendering pipeline settings. */
+ view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */
+ view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
+ view_layer->pass_alpha_threshold = 0.5f;
+ BKE_freestyle_config_init(&view_layer->freestyle_config);
+
+ return view_layer;
+}
+
+/**
+ * Add a new view layer
+ * by default, a view layer has the master collection
+ */
+ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
+{
+ ViewLayer *view_layer = view_layer_add(name);
+
+ BLI_addtail(&scene->view_layers, view_layer);
+
+ /* unique name */
+ BLI_uniquename(
+ &scene->view_layers, view_layer, DATA_("ViewLayer"), '.',
+ offsetof(ViewLayer, name), sizeof(view_layer->name));
+
+ BKE_layer_collection_sync(scene, view_layer);
+
+ return view_layer;
+}
+
+void BKE_view_layer_free(ViewLayer *view_layer)
+{
+ BKE_view_layer_free_ex(view_layer, true);
+}
+
+/**
+ * Free (or release) any data used by this ViewLayer.
+ */
+void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
+{
+ view_layer->basact = NULL;
+
+ BLI_freelistN(&view_layer->object_bases);
+
+ if (view_layer->object_bases_hash) {
+ BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
+ }
+
+ for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
+ layer_collection_free(view_layer, lc);
+ }
+ BLI_freelistN(&view_layer->layer_collections);
+
+ for (ViewLayerEngineData *sled = view_layer->drawdata.first; sled; sled = sled->next) {
+ if (sled->storage) {
+ if (sled->free) {
+ sled->free(sled->storage);
+ }
+ MEM_freeN(sled->storage);
+ }
+ }
+ BLI_freelistN(&view_layer->drawdata);
+
+ MEM_SAFE_FREE(view_layer->stats);
+
+ BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user);
+
+ if (view_layer->id_properties) {
+ IDP_FreeProperty(view_layer->id_properties);
+ MEM_freeN(view_layer->id_properties);
+ }
+
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ MEM_freeN(view_layer);
+}
+
+/**
+ * Tag all the selected objects of a renderlayer
+ */
+void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTED) != 0) {
+ base->object->flag |= tag;
+ }
+ else {
+ base->object->flag &= ~tag;
+ }
+ }
+}
+
+static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc)
+{
+ for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) {
+ if (lcn == lc) {
+ return true;
+ }
+ if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Fallback for when a Scene has no camera to use
+ *
+ * \param view_layer: in general you want to use the same ViewLayer that is used
+ * for depsgraph. If rendering you pass the scene active layer, when viewing in the viewport
+ * you want to get ViewLayer from context.
+ */
+Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->type == OB_CAMERA) {
+ return base->object;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Find the ViewLayer a LayerCollection belongs to
+ */
+ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
+ return view_layer;
+ }
+ }
+
+ return NULL;
+}
+
+/* Base */
+
+static void view_layer_bases_hash_create(ViewLayer *view_layer)
+{
+ static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER;
+
+ if (view_layer->object_bases_hash == NULL) {
+ BLI_mutex_lock(&hash_lock);
+
+ if (view_layer->object_bases_hash == NULL) {
+ view_layer->object_bases_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object) {
+ BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
+ }
+ }
+ }
+
+ BLI_mutex_unlock(&hash_lock);
+ }
+}
+
+Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
+{
+ if (!view_layer->object_bases_hash) {
+ view_layer_bases_hash_create(view_layer);
+ }
+
+ return BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+}
+
+void BKE_view_layer_base_deselect_all(ViewLayer *view_layer)
+{
+ Base *base;
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag &= ~BASE_SELECTED;
+ }
+}
+
+void BKE_view_layer_base_select(Base *selbase)
+{
+ if ((selbase->flag & BASE_SELECTABLE) != 0) {
+ selbase->flag |= BASE_SELECTED;
+ }
+}
+
+void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Base *selbase)
+{
+ view_layer->basact = selbase;
+ BKE_view_layer_base_select(selbase);
+}
+
+/**************************** Copy View Layer and Layer Collections ***********************/
+
+static void layer_collections_copy_data(
+ ViewLayer *view_layer_dst, const ViewLayer *view_layer_src,
+ ListBase *layer_collections_dst, const ListBase *layer_collections_src)
+{
+ BLI_duplicatelist(layer_collections_dst, layer_collections_src);
+
+ LayerCollection *layer_collection_dst = layer_collections_dst->first;
+ const LayerCollection *layer_collection_src = layer_collections_src->first;
+
+ while (layer_collection_dst != NULL) {
+ layer_collections_copy_data(
+ view_layer_dst,
+ view_layer_src,
+ &layer_collection_dst->layer_collections,
+ &layer_collection_src->layer_collections);
+
+ if (layer_collection_src == view_layer_src->active_collection) {
+ view_layer_dst->active_collection = layer_collection_dst;
+ }
+
+ layer_collection_dst = layer_collection_dst->next;
+ layer_collection_src = layer_collection_src->next;
+ }
+}
+
+/**
+ * Only copy internal data of ViewLayer from source to already allocated/initialized destination.
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_view_layer_copy_data(
+ Scene *scene_dst, const Scene *UNUSED(scene_src),
+ ViewLayer *view_layer_dst, const ViewLayer *view_layer_src,
+ const int flag)
+{
+ if (view_layer_dst->id_properties != NULL) {
+ view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag);
+ }
+ BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag);
+
+ view_layer_dst->stats = NULL;
+
+ /* Clear temporary data. */
+ BLI_listbase_clear(&view_layer_dst->drawdata);
+ view_layer_dst->object_bases_array = NULL;
+ view_layer_dst->object_bases_hash = NULL;
+
+ /* Copy layer collections and object bases. */
+ /* Inline 'BLI_duplicatelist' and update the active base. */
+ BLI_listbase_clear(&view_layer_dst->object_bases);
+ for (Base *base_src = view_layer_src->object_bases.first; base_src; base_src = base_src->next) {
+ Base *base_dst = MEM_dupallocN(base_src);
+ BLI_addtail(&view_layer_dst->object_bases, base_dst);
+ if (view_layer_src->basact == base_src) {
+ view_layer_dst->basact = base_dst;
+ }
+ }
+
+ view_layer_dst->active_collection = NULL;
+ layer_collections_copy_data(
+ view_layer_dst,
+ view_layer_src,
+ &view_layer_dst->layer_collections,
+ &view_layer_src->layer_collections);
+
+ LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first;
+ lc_scene_dst->collection = scene_dst->master_collection;
+}
+
+void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname)
+{
+ char oldname[sizeof(view_layer->name)];
+
+ BLI_strncpy(oldname, view_layer->name, sizeof(view_layer->name));
+
+ BLI_strncpy_utf8(view_layer->name, newname, sizeof(view_layer->name));
+ BLI_uniquename(&scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name));
+
+ if (scene->nodetree) {
+ bNode *node;
+ int index = BLI_findindex(&scene->view_layers, view_layer);
+
+ for (node = scene->nodetree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) {
+ if (node->custom1 == index)
+ BLI_strncpy(node->name, view_layer->name, NODE_MAXSTR);
+ }
+ }
+ }
+
+ /* Fix all the animation data and windows which may link to this. */
+ BKE_animdata_fix_paths_rename_all(NULL, "view_layers", oldname, view_layer->name);
+
+ /* WM can be missing on startup. */
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene == scene && STREQ(win->view_layer_name, oldname)) {
+ STRNCPY(win->view_layer_name, view_layer->name);
+ }
+ }
+ }
+
+ /* Dependency graph uses view layer name based lookups. */
+ DEG_id_tag_update(&scene->id, 0);
+}
+
+/* LayerCollection */
+
+/**
+ * Recursively get the collection for a given index
+ */
+static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ if (*i == number) {
+ return lc;
+ }
+
+ (*i)++;
+ }
+
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i);
+ if (lc_nested) {
+ return lc_nested;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Get the collection for a given index
+ */
+LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index)
+{
+ int i = 0;
+ return collection_from_index(&view_layer->layer_collections, index, &i);
+}
+
+/**
+ * Get the active collection
+ */
+LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer)
+{
+ return view_layer->active_collection;
+}
+
+/*
+ * Activate collection
+ */
+bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ return false;
+ }
+
+ view_layer->active_collection = lc;
+ return true;
+}
+
+/**
+ * Activate first parent collection
+ */
+LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc)
+{
+ CollectionParent *parent = lc->collection->parents.first;
+
+ if (parent) {
+ lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection);
+ }
+ else {
+ lc = NULL;
+ }
+
+ if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ /* Don't activate excluded collections. */
+ return BKE_layer_collection_activate_parent(view_layer, lc);
+ }
+
+ if (!lc) {
+ lc = view_layer->layer_collections.first;
+ }
+
+ view_layer->active_collection = lc;
+ return lc;
+}
+
+/**
+ * Recursively get the count of collections
+ */
+static int collection_count(ListBase *lb)
+{
+ int i = 0;
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ i += collection_count(&lc->layer_collections) + 1;
+ }
+ return i;
+}
+
+/**
+ * Get the total number of collections
+ * (including all the nested collections)
+ */
+int BKE_layer_collection_count(ViewLayer *view_layer)
+{
+ return collection_count(&view_layer->layer_collections);
+}
+
+/**
+ * Recursively get the index for a given collection
+ */
+static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i)
+{
+ for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ if (lcol == lc) {
+ return *i;
+ }
+
+ (*i)++;
+ }
+
+ for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ int i_nested = index_from_collection(&lcol->layer_collections, lc, i);
+ if (i_nested != -1) {
+ return i_nested;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Return -1 if not found
+ */
+int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection *lc)
+{
+ int i = 0;
+ return index_from_collection(&view_layer->layer_collections, lc, &i);
+}
+
+/*********************************** Syncing *********************************
+ *
+ * The layer collection tree mirrors the scene collection tree. Whenever that
+ * changes we need to synchronize them so that there is a corresponding layer
+ * collection for each collection. Note that the scene collection tree can
+ * contain link or override collections, and so this is also called on .blend
+ * file load to ensure any new or removed collections are synced.
+ *
+ * The view layer also contains a list of bases for each object that exists
+ * in at least one layer collection. That list is also synchronized here, and
+ * stores state like selection. */
+
+static short layer_collection_sync(
+ ViewLayer *view_layer, const ListBase *lb_scene,
+ ListBase *lb_layer, ListBase *new_object_bases,
+ short parent_exclude, short parent_restrict)
+{
+ /* TODO: support recovery after removal of intermediate collections, reordering, ..
+ * For local edits we can make editing operating do the appropriate thing, but for
+ * linking we can only sync after the fact. */
+
+ /* Remove layer collections that no longer have a corresponding scene collection. */
+ for (LayerCollection *lc = lb_layer->first; lc;) {
+ /* Note ID remap can set lc->collection to NULL when deleting collections. */
+ LayerCollection *lc_next = lc->next;
+ Collection *collection = (lc->collection) ?
+ BLI_findptr(lb_scene, lc->collection, offsetof(CollectionChild, collection)) : NULL;
+
+ if (!collection) {
+ if (lc == view_layer->active_collection) {
+ view_layer->active_collection = NULL;
+ }
+
+ /* Free recursively. */
+ layer_collection_free(view_layer, lc);
+ BLI_freelinkN(lb_layer, lc);
+ }
+
+ lc = lc_next;
+ }
+
+ /* Add layer collections for any new scene collections, and ensure order is the same. */
+ ListBase new_lb_layer = {NULL, NULL};
+ short runtime_flag = 0;
+
+ for (const CollectionChild *child = lb_scene->first; child; child = child->next) {
+ Collection *collection = child->collection;
+ LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection));
+
+ if (lc) {
+ BLI_remlink(lb_layer, lc);
+ BLI_addtail(&new_lb_layer, lc);
+ }
+ else {
+ lc = layer_collection_add(&new_lb_layer, collection);
+ lc->flag = parent_exclude;
+ }
+
+ /* Collection restrict is inherited. */
+ short child_restrict = parent_restrict;
+ if (!(collection->flag & COLLECTION_IS_MASTER)) {
+ child_restrict |= collection->flag;
+ }
+
+ /* Sync child collections. */
+ short child_runtime_flag = layer_collection_sync(
+ view_layer, &collection->children,
+ &lc->layer_collections, new_object_bases,
+ lc->flag, child_restrict);
+
+ /* Layer collection exclude is not inherited. */
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ lc->runtime_flag = 0;
+ continue;
+ }
+ else {
+ lc->runtime_flag = child_runtime_flag;
+ }
+
+ /* Sync objects, except if collection was excluded. */
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ if (cob->ob == NULL) {
+ continue;
+ }
+
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, cob->ob);
+
+ if (base) {
+ /* Move from old base list to new base list. Base might have already
+ * been moved to the new base list and the first/last test ensure that
+ * case also works. */
+ if (!ELEM(base, new_object_bases->first, new_object_bases->last)) {
+ BLI_remlink(&view_layer->object_bases, base);
+ BLI_addtail(new_object_bases, base);
+ }
+ }
+ else {
+ /* Create new base. */
+ base = object_base_new(cob->ob);
+ BLI_addtail(new_object_bases, base);
+ BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
+ }
+
+ int object_restrict = base->object->restrictflag;
+
+ if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
+ ((object_restrict & OB_RESTRICT_VIEW) == 0))
+ {
+ base->flag |= BASE_VISIBLE | BASE_ENABLED | BASE_ENABLED_VIEWPORT;
+
+ if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) &&
+ ((object_restrict & OB_RESTRICT_SELECT) == 0))
+ {
+ base->flag |= BASE_SELECTABLE;
+ }
+ }
+
+ if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) &&
+ ((object_restrict & OB_RESTRICT_RENDER) == 0))
+
+ {
+ base->flag |= BASE_ENABLED_RENDER;
+ }
+
+ /* Update runtime flags used for display and tools. */
+ if (base->flag & BASE_VISIBLE) {
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_ENABLED_OBJECTS;
+ }
+
+ if (base->flag & BASE_HIDDEN) {
+ view_layer->runtime_flag |= VIEW_LAYER_HAS_HIDE;
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_HIDDEN_OBJECTS;
+ }
+ else if (base->flag & BASE_VISIBLE) {
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_VISIBLE_OBJECTS;
+ }
+
+ /* Holdout and indirect only */
+ if (lc->flag & LAYER_COLLECTION_HOLDOUT) {
+ base->flag |= BASE_HOLDOUT;
+ }
+ if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
+ base->flag |= BASE_INDIRECT_ONLY;
+ }
+
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
+ }
+
+ runtime_flag |= lc->runtime_flag;
+ }
+
+ /* Replace layer collection list with new one. */
+ *lb_layer = new_lb_layer;
+ BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer));
+
+ return runtime_flag;
+}
+
+/**
+ * Update view layer collection tree from collections used in the scene.
+ * This is used when collections are removed or added, both while editing
+ * and on file loaded in case linked data changed or went missing.
+ */
+void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
+{
+ if (!scene->master_collection) {
+ /* Happens for old files that don't have versioning applied yet. */
+ return;
+ }
+
+ /* Free cache. */
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ /* Create object to base hash if it does not exist yet. */
+ if (!view_layer->object_bases_hash) {
+ view_layer_bases_hash_create(view_layer);
+ }
+
+ /* Clear visible and selectable flags to be reset. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag &= ~(BASE_VISIBLE |
+ BASE_ENABLED |
+ BASE_SELECTABLE |
+ BASE_ENABLED_VIEWPORT |
+ BASE_ENABLED_RENDER |
+ BASE_HOLDOUT |
+ BASE_INDIRECT_ONLY);
+ }
+
+ view_layer->runtime_flag = 0;
+
+ /* Generate new layer connections and object bases when collections changed. */
+ CollectionChild child = {NULL, NULL, scene->master_collection};
+ const ListBase collections = {&child, &child};
+ ListBase new_object_bases = {NULL, NULL};
+
+ const short parent_exclude = 0, parent_restrict = 0;
+ layer_collection_sync(
+ view_layer, &collections,
+ &view_layer->layer_collections, &new_object_bases,
+ parent_exclude, parent_restrict);
+
+ /* Any remaning object bases are to be removed. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (view_layer->basact == base) {
+ view_layer->basact = NULL;
+ }
+
+ if (base->object) {
+ BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL);
+ }
+ }
+
+ BLI_freelistN(&view_layer->object_bases);
+ view_layer->object_bases = new_object_bases;
+
+ /* Always set a valid active collection. */
+ LayerCollection *active = view_layer->active_collection;
+
+ if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) {
+ BKE_layer_collection_activate_parent(view_layer, active);
+ }
+ else if (active == NULL) {
+ view_layer->active_collection = view_layer->layer_collections.first;
+ }
+}
+
+void BKE_scene_collection_sync(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ BKE_layer_collection_sync(scene, view_layer);
+ }
+}
+
+void BKE_main_collection_sync(const Main *bmain)
+{
+ /* TODO: if a single collection changed, figure out which
+ * scenes it belongs to and only update those. */
+
+ /* TODO: optimize for file load so only linked collections get checked? */
+
+ for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ BKE_scene_collection_sync(scene);
+ }
+}
+
+void BKE_main_collection_sync_remap(const Main *bmain)
+{
+ /* On remapping of object or collection pointers free caches. */
+ /* TODO: try to make this faster */
+
+ for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ if (view_layer->object_bases_hash) {
+ BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
+ view_layer->object_bases_hash = NULL;
+ }
+ }
+ }
+
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ BKE_collection_object_cache_free(collection);
+ DEG_id_tag_update_ex((Main *)bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
+ BKE_main_collection_sync(bmain);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Select all the objects of this layer collection
+ *
+ * It also select the objects that are in nested collections.
+ * \note Recursive
+ */
+bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect)
+{
+ if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ bool changed = false;
+
+ if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base) {
+ if (deselect) {
+ if (base->flag & BASE_SELECTED) {
+ base->flag &= ~BASE_SELECTED;
+ changed = true;
+ }
+ }
+ else {
+ if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
+ base->flag |= BASE_SELECTED;
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect);
+ }
+
+ return changed;
+}
+
+bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base && (base->flag & BASE_SELECTED)) {
+ return true;
+ }
+ }
+ }
+
+ for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ if (BKE_layer_collection_has_selected_objects(view_layer, iter)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* Update after toggling visibility of an object base. */
+void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool extend)
+{
+ if (!extend) {
+ /* Make only one base visible. */
+ for (Base *other = view_layer->object_bases.first; other; other = other->next) {
+ other->flag |= BASE_HIDDEN;
+ }
+
+ base->flag &= ~BASE_HIDDEN;
+ }
+ else {
+ /* Toggle visibility of one base. */
+ base->flag ^= BASE_HIDDEN;
+ }
+
+ BKE_layer_collection_sync(scene, view_layer);
+}
+
+void BKE_layer_collection_set_visible(Scene *scene, ViewLayer *view_layer, LayerCollection *lc, bool extend)
+{
+ if (!extend) {
+ /* Make only objects from one collection visible. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag |= BASE_HIDDEN;
+ }
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(lc->collection, ob)
+ {
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+
+ if (base) {
+ base->flag &= ~BASE_HIDDEN;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ BKE_layer_collection_activate(view_layer, lc);
+ }
+ else {
+ /* Toggle visibility of objects from collection. */
+ bool hide = (lc->runtime_flag & LAYER_COLLECTION_HAS_VISIBLE_OBJECTS) != 0;
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(lc->collection, ob)
+ {
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+
+ if (base) {
+ if (hide) {
+ base->flag |= BASE_HIDDEN;
+ }
+ else {
+ base->flag &= ~BASE_HIDDEN;
+ }
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ BKE_layer_collection_sync(scene, view_layer);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const Collection *collection)
+{
+ if (lc->collection == collection) {
+ return lc;
+ }
+
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection);
+ if (found) {
+ return found;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Return the first matching LayerCollection in the ViewLayer for the Collection.
+ */
+LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const Collection *collection)
+{
+ for (LayerCollection *layer_collection = view_layer->layer_collections.first;
+ layer_collection != NULL;
+ layer_collection = layer_collection->next)
+ {
+ LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, collection);
+
+ if (found != NULL) {
+ return found;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * See if view layer has the scene collection linked directly, or indirectly (nested)
+ */
+bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *collection)
+{
+ return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL;
+}
+
+/**
+ * See if the object is in any of the scene layers of the scene
+ */
+bool BKE_scene_has_object(Scene *scene, Object *ob)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Override */
+
+/**
+ * Add a new datablock override
+ */
+void BKE_override_view_layer_datablock_add(
+ ViewLayer *view_layer, int id_type, const char *data_path, const ID *owner_id)
+{
+ UNUSED_VARS(view_layer, id_type, data_path, owner_id);
+ TODO_LAYER_OVERRIDE;
+}
+
+/**
+ * Add a new int override
+ */
+void BKE_override_view_layer_int_add(
+ ViewLayer *view_layer, int id_type, const char *data_path, const int value)
+{
+ UNUSED_VARS(view_layer, id_type, data_path, value);
+ TODO_LAYER_OVERRIDE;
+}
+
+/**
+ * Add a new boolean override
+ */
+void BKE_override_layer_collection_boolean_add(
+ struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value)
+{
+ UNUSED_VARS(layer_collection, id_type, data_path, value);
+ TODO_LAYER_OVERRIDE;
+}
+
+/** \} */
+
+/* Iterators */
+
+/* -------------------------------------------------------------------- */
+/** \name Private Iterator Helpers
+ * \{ */
+
+typedef struct LayerObjectBaseIteratorData {
+ View3D *v3d;
+ Base *base;
+} LayerObjectBaseIteratorData;
+
+static bool object_bases_iterator_is_valid_ex(View3D *v3d, Base *base, const int flag)
+{
+ if (v3d != NULL) {
+ BLI_assert(v3d->spacetype == SPACE_VIEW3D);
+ if ((v3d->object_type_exclude_viewport & (1 << base->object->type)) != 0) {
+ return false;
+ }
+
+ if (v3d->localvd && ((base->local_view_bits & v3d->local_view_uuid) == 0)) {
+ return false;
+ }
+ }
+
+ if ((base->flag & flag) == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool object_bases_iterator_is_valid(View3D *v3d, Base *base)
+{
+ return object_bases_iterator_is_valid_ex(v3d, base, ~(0));
+}
+
+static void object_bases_iterator_begin(BLI_Iterator *iter, void *data_in_v, const int flag)
+{
+ ObjectsVisibleIteratorData *data_in = data_in_v;
+ ViewLayer *view_layer = data_in->view_layer;
+ View3D *v3d = data_in->v3d;
+ Base *base = view_layer->object_bases.first;
+
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->data = NULL;
+ iter->valid = false;
+ return;
+ }
+
+ LayerObjectBaseIteratorData *data = MEM_callocN(sizeof(LayerObjectBaseIteratorData), __func__);
+ iter->data = data;
+
+ data->v3d = v3d;
+ data->base = base;
+
+ if (object_bases_iterator_is_valid_ex(v3d, base, flag) == false) {
+ object_bases_iterator_next(iter, flag);
+ }
+ else {
+ iter->current = base;
+ }
+}
+
+static void object_bases_iterator_next(BLI_Iterator *iter, const int flag)
+{
+ LayerObjectBaseIteratorData *data = iter->data;
+ Base *base = data->base->next;
+
+ while (base) {
+ if (object_bases_iterator_is_valid_ex(data->v3d, base, flag)) {
+ iter->current = base;
+ data->base = base;
+ return;
+ }
+ base = base->next;
+ }
+
+ iter->valid = false;
+}
+
+static void object_bases_iterator_end(BLI_Iterator *iter)
+{
+ MEM_SAFE_FREE(iter->data);
+}
+
+static void objects_iterator_begin(BLI_Iterator *iter, void *data_in, const int flag)
+{
+ object_bases_iterator_begin(iter, data_in, flag);
+
+ if (iter->valid) {
+ iter->current = ((Base *)iter->current)->object;
+ }
+}
+
+static void objects_iterator_next(BLI_Iterator *iter, const int flag)
+{
+ object_bases_iterator_next(iter, flag);
+
+ if (iter->valid) {
+ iter->current = ((Base *)iter->current)->object;
+ }
+}
+
+static void objects_iterator_end(BLI_Iterator *iter)
+{
+ object_bases_iterator_end(iter);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_objects_iterator
+ * See: #FOREACH_SELECTED_OBJECT_BEGIN
+ * \{ */
+
+void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter)
+{
+ objects_iterator_next(iter, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter)
+{
+ objects_iterator_end(iter);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_visible_objects_iterator
+ * \{ */
+
+void BKE_view_layer_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_VISIBLE);
+}
+
+void BKE_view_layer_visible_objects_iterator_next(BLI_Iterator *iter)
+{
+ objects_iterator_next(iter, BASE_VISIBLE);
+}
+
+void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter)
+{
+ objects_iterator_end(iter);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_editable_objects_iterator
+ * \{ */
+
+void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_SELECTED);
+ if (iter->valid) {
+ if (BKE_object_is_libdata((Object *)iter->current) == false) {
+ // First object is valid (selectable and not libdata) -> all good.
+ return;
+ }
+ else {
+ // Object is selectable but not editable -> search for another one.
+ BKE_view_layer_selected_editable_objects_iterator_next(iter);
+ }
+ }
+}
+
+void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter)
+{
+ // Search while there are objects and the one we have is not editable (editable = not libdata).
+ do {
+ objects_iterator_next(iter, BASE_SELECTED);
+ } while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false);
+}
+
+void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter)
+{
+ objects_iterator_end(iter);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_bases_iterator
+ * \{ */
+
+void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter)
+{
+ object_bases_iterator_next(iter, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter)
+{
+ object_bases_iterator_end(iter);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_visible_bases_iterator
+ * \{ */
+
+void BKE_view_layer_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ object_bases_iterator_begin(iter, data_in, BASE_VISIBLE);
+}
+
+void BKE_view_layer_visible_bases_iterator_next(BLI_Iterator *iter)
+{
+ object_bases_iterator_next(iter, BASE_VISIBLE);
+}
+
+void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter)
+{
+ object_bases_iterator_end(iter);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_renderable_objects_iterator
+ * \{ */
+
+void BKE_view_layer_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ struct ObjectsRenderableIteratorData *data = data_in;
+
+ /* Tag objects to prevent going over the same object twice. */
+ for (Scene *scene = data->scene; scene; scene = scene->set) {
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.flag |= LIB_TAG_DOIT;
+ }
+ }
+ }
+
+ ViewLayer *view_layer = data->scene->view_layers.first;
+ data->iter.view_layer = view_layer;
+
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+
+ data->iter.set = NULL;
+
+ iter->data = data_in;
+ BKE_view_layer_renderable_objects_iterator_next(iter);
+}
+
+void BKE_view_layer_renderable_objects_iterator_next(BLI_Iterator *iter)
+{
+ /* Set it early in case we need to exit and we are running from within a loop. */
+ iter->skip = true;
+
+ struct ObjectsRenderableIteratorData *data = iter->data;
+ Base *base = data->iter.base->next;
+
+ /* There is still a base in the current scene layer. */
+ if (base != NULL) {
+ Object *ob = base->object;
+
+ /* We need to set the iter.base even if the rest fail otherwise
+ * we keep checking the exactly same base over and over again. */
+ data->iter.base = base;
+
+ if (ob->id.flag & LIB_TAG_DOIT) {
+ ob->id.flag &= ~LIB_TAG_DOIT;
+
+ if ((base->flag & BASE_VISIBLE) != 0) {
+ iter->skip = false;
+ iter->current = ob;
+ }
+ }
+ return;
+ }
+
+ /* Time to go to the next scene layer. */
+ if (data->iter.set == NULL) {
+ while ((data->iter.view_layer = data->iter.view_layer->next)) {
+ ViewLayer *view_layer = data->iter.view_layer;
+ if (view_layer->flag & VIEW_LAYER_RENDER) {
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+ return;
+ }
+ }
+
+ /* Setup the "set" for the next iteration. */
+ data->scene_temp.set = data->scene;
+ data->iter.set = &data->scene_temp;
+ return;
+ }
+
+ /* Look for an object in the next set. */
+ while ((data->iter.set = data->iter.set->set)) {
+ ViewLayer *view_layer = BKE_view_layer_default_render(data->iter.set);
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+ return;
+ }
+
+ iter->valid = false;
+}
+
+void BKE_view_layer_renderable_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* Do nothing - iter->data was static allocated, we can't free it. */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_bases_in_mode_iterator
+ * \{ */
+
+void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ struct ObjectsInModeIteratorData *data = data_in;
+ Base *base = data->base_active;
+
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->valid = false;
+ return;
+ }
+ iter->data = data_in;
+ iter->current = base;
+
+ if (object_bases_iterator_is_valid(data->v3d, base) == false) {
+ BKE_view_layer_bases_in_mode_iterator_next(iter);
+ }
+}
+
+void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter)
+{
+ struct ObjectsInModeIteratorData *data = iter->data;
+ Base *base = iter->current;
+
+ if (base == data->base_active) {
+ /* first step */
+ base = data->view_layer->object_bases.first;
+ if (base == data->base_active) {
+ base = base->next;
+ }
+ }
+ else {
+ base = base->next;
+ }
+
+ while (base) {
+ if ((base->object->type == data->base_active->object->type) &&
+ (base != data->base_active) &&
+ (base->object->mode & data->object_mode) &&
+ object_bases_iterator_is_valid(data->v3d, base))
+ {
+ iter->current = base;
+ return;
+ }
+ base = base->next;
+ }
+ iter->valid = false;
+}
+
+void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* Evaluation */
+
+void BKE_layer_eval_view_layer(
+ struct Depsgraph *depsgraph,
+ struct Scene *UNUSED(scene),
+ ViewLayer *view_layer)
+{
+ DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer);
+
+ /* Visibility based on depsgraph mode. */
+ const eEvaluationMode mode = DEG_get_mode(depsgraph);
+ const int base_visible_flag = (mode == DAG_EVAL_VIEWPORT)
+ ? BASE_ENABLED_VIEWPORT
+ : BASE_ENABLED_RENDER;
+ /* Create array of bases, for fast index-based lookup. */
+ const int num_object_bases = BLI_listbase_count(&view_layer->object_bases);
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+ view_layer->object_bases_array = MEM_malloc_arrayN(
+ num_object_bases, sizeof(Base *), "view_layer->object_bases_array");
+ int base_index = 0;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ /* Compute visibility for depsgraph evaluation mode. */
+ if (base->flag & base_visible_flag) {
+ base->flag |= BASE_ENABLED | BASE_VISIBLE;
+ if (mode == DAG_EVAL_VIEWPORT && (base->flag & BASE_HIDDEN)) {
+ base->flag &= ~BASE_VISIBLE;
+ }
+ }
+ else {
+ base->flag &= ~(BASE_ENABLED | BASE_VISIBLE | BASE_SELECTABLE);
+ }
+ /* If base is not selectabled, clear select. */
+ if ((base->flag & BASE_SELECTABLE) == 0) {
+ base->flag &= ~BASE_SELECTED;
+ }
+ view_layer->object_bases_array[base_index++] = base;
+ }
+ /* Flush back base flag to the original view layer for editing. */
+ if (view_layer == DEG_get_evaluated_view_layer(depsgraph)) {
+ ViewLayer *view_layer_orig = DEG_get_input_view_layer(depsgraph);
+ Base *base_orig = view_layer_orig->object_bases.first;
+ const Base *base_eval = view_layer->object_bases.first;
+ while (base_orig != NULL) {
+ if (base_orig->flag & base_visible_flag) {
+ base_orig->flag = base_eval->flag;
+ base_eval = base_eval->next;
+ }
+ base_orig = base_orig->next;
+ }
+ }
+}
+
+void BKE_layer_eval_view_layer_indexed(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ int view_layer_index)
+{
+ BLI_assert(view_layer_index >= 0);
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
+ BLI_assert(view_layer != NULL);
+ BKE_layer_eval_view_layer(depsgraph, scene, view_layer);
+}
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
new file mode 100644
index 00000000000..2d446af9ac8
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -0,0 +1,127 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/layer_utils.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_array.h"
+#include "BLI_listbase.h"
+
+#include "BKE_collection.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+Base **BKE_view_layer_array_from_bases_in_mode_params(
+ ViewLayer *view_layer, View3D *v3d, uint *r_len,
+ const struct ObjectsInModeParams *params)
+{
+ if (params->no_dup_data) {
+ FOREACH_BASE_IN_MODE_BEGIN(view_layer, v3d, params->object_mode, base_iter) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ } FOREACH_BASE_IN_MODE_END;
+ }
+
+ Base **base_array = NULL;
+ BLI_array_declare(base_array);
+
+ FOREACH_BASE_IN_MODE_BEGIN(view_layer, v3d, params->object_mode, base_iter) {
+ if (params->filter_fn) {
+ if (!params->filter_fn(base_iter->object, params->filter_userdata)) {
+ continue;
+ }
+ }
+ if (params->no_dup_data) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ if (id->tag & LIB_TAG_DOIT) {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ BLI_array_append(base_array, base_iter);
+ } FOREACH_BASE_IN_MODE_END;
+
+ base_array = MEM_reallocN(base_array, sizeof(*base_array) * BLI_array_len(base_array));
+ /* We always need a valid allocation (prevent crash on free). */
+ if (base_array == NULL) {
+ base_array = MEM_mallocN(0, __func__);
+ }
+ *r_len = BLI_array_len(base_array);
+ return base_array;
+}
+
+Object **BKE_view_layer_array_from_objects_in_mode_params(
+ ViewLayer *view_layer, View3D *v3d, uint *r_len,
+ const struct ObjectsInModeParams *params)
+{
+ Base **base_array = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, v3d, r_len, params);
+ if (base_array != NULL) {
+ for (uint i = 0; i < *r_len; i++) {
+ ((Object **)base_array)[i] = base_array[i]->object;
+ }
+ }
+ return (Object **)base_array;
+}
+
+bool BKE_view_layer_filter_edit_mesh_has_uvs(Object *ob, void *UNUSED(user_data))
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em != NULL) {
+ if (CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV) != -1) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool BKE_view_layer_filter_edit_mesh_has_edges(Object *ob, void *UNUSED(user_data))
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em != NULL) {
+ if (em->bm->totedge != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index a6cee54d81f..aa6cbcc343e 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -47,7 +47,7 @@
#include "DNA_brush_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
@@ -62,6 +62,7 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -70,6 +71,7 @@
#include "DNA_vfont_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_world_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -78,8 +80,8 @@
#include "BLI_memarena.h"
#include "BLI_mempool.h"
#include "BLI_string_utils.h"
-
#include "BLI_threads.h"
+
#include "BLT_translation.h"
#include "BKE_action.h"
@@ -89,12 +91,11 @@
#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_font.h"
#include "BKE_global.h"
-#include "BKE_group.h"
#include "BKE_gpencil.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
@@ -103,6 +104,7 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -117,6 +119,7 @@
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
+#include "BKE_lightprobe.h"
#include "BKE_sound.h"
#include "BKE_speaker.h"
#include "BKE_scene.h"
@@ -418,6 +421,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_LP:
+ if (!test) BKE_lightprobe_make_local(bmain, (LightProbe *)id, lib_local);
+ return true;
case ID_WO:
if (!test) BKE_world_make_local(bmain, (World *)id, lib_local);
return true;
@@ -431,7 +437,7 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local);
return true;
case ID_GR:
- if (!test) BKE_group_make_local(bmain, (Group *)id, lib_local);
+ if (!test) BKE_collection_make_local(bmain, (Collection *)id, lib_local);
return true;
case ID_AR:
if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local);
@@ -469,7 +475,11 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
case ID_CF:
if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
return true;
+ case ID_WS:
case ID_SCR:
+ /* A bit special: can be appended but not linked. Return false
+ * since supporting make-local doesn't make much sense. */
+ return false;
case ID_LI:
case ID_KE:
case ID_WM:
@@ -589,6 +599,9 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
case ID_SPK:
BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag);
break;
+ case ID_LP:
+ BKE_lightprobe_copy_data(bmain, (LightProbe *)*r_newid, (LightProbe *)id, flag);
+ break;
case ID_CA:
BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag);
break;
@@ -602,7 +615,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag);
break;
case ID_GR:
- BKE_group_copy_data(bmain, (Group *)*r_newid, (Group *)id, flag);
+ BKE_collection_copy_data(bmain, (Collection *)*r_newid, (Collection *)id, flag);
break;
case ID_AR:
BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag);
@@ -620,7 +633,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
BKE_particlesettings_copy_data(bmain, (ParticleSettings *)*r_newid, (ParticleSettings *)id, flag);
break;
case ID_GD:
- BKE_gpencil_copy_data(bmain, (bGPdata *)*r_newid, (bGPdata *)id, flag);
+ BKE_gpencil_copy_data((bGPdata *)*r_newid, (bGPdata *)id, flag);
break;
case ID_MC:
BKE_movieclip_copy_data(bmain, (MovieClip *)*r_newid, (MovieClip *)id, flag);
@@ -649,6 +662,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
case ID_LI:
case ID_SCR:
case ID_WM:
+ case ID_WS:
case ID_IP:
BLI_assert(0); /* Should have been rejected at start of function! */
break;
@@ -677,7 +691,76 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
*/
bool id_copy(Main *bmain, const ID *id, ID **newid, bool test)
{
- return BKE_id_copy_ex(bmain, id, newid, 0, test);
+ return BKE_id_copy_ex(bmain, id, newid, LIB_ID_COPY_SHAPEKEY, test);
+}
+
+/** Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note Most internal ID data itself is not swapped (only IDProperties are). */
+void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
+{
+ BLI_assert(GS(id_a->name) == GS(id_b->name));
+
+ const ID id_a_back = *id_a;
+ const ID id_b_back = *id_b;
+
+#define CASE_SWAP(_gs, _type) \
+ case _gs: \
+ SWAP(_type, *(_type *)id_a, *(_type *)id_b); \
+ break
+
+ switch ((ID_Type)GS(id_a->name)) {
+ CASE_SWAP(ID_SCE, Scene);
+ CASE_SWAP(ID_LI, Library);
+ CASE_SWAP(ID_OB, Object);
+ CASE_SWAP(ID_ME, Mesh);
+ CASE_SWAP(ID_CU, Curve);
+ CASE_SWAP(ID_MB, MetaBall);
+ CASE_SWAP(ID_MA, Material);
+ CASE_SWAP(ID_TE, Tex);
+ CASE_SWAP(ID_IM, Image);
+ CASE_SWAP(ID_LT, Lattice);
+ CASE_SWAP(ID_LA, Lamp);
+ CASE_SWAP(ID_LP, LightProbe);
+ CASE_SWAP(ID_CA, Camera);
+ CASE_SWAP(ID_KE, Key);
+ CASE_SWAP(ID_WO, World);
+ CASE_SWAP(ID_SCR, bScreen);
+ CASE_SWAP(ID_VF, VFont);
+ CASE_SWAP(ID_TXT, Text);
+ CASE_SWAP(ID_SPK, Speaker);
+ CASE_SWAP(ID_SO, bSound);
+ CASE_SWAP(ID_GR, Collection);
+ CASE_SWAP(ID_AR, bArmature);
+ CASE_SWAP(ID_AC, bAction);
+ CASE_SWAP(ID_NT, bNodeTree);
+ CASE_SWAP(ID_BR, Brush);
+ CASE_SWAP(ID_PA, ParticleSettings);
+ CASE_SWAP(ID_WM, wmWindowManager);
+ CASE_SWAP(ID_WS, WorkSpace);
+ CASE_SWAP(ID_GD, bGPdata);
+ CASE_SWAP(ID_MC, MovieClip);
+ CASE_SWAP(ID_MSK, Mask);
+ CASE_SWAP(ID_LS, FreestyleLineStyle);
+ CASE_SWAP(ID_PAL, Palette);
+ CASE_SWAP(ID_PC, PaintCurve);
+ CASE_SWAP(ID_CF, CacheFile);
+ case ID_IP:
+ break; /* Deprecated. */
+ }
+
+#undef CASE_SWAP
+
+ /* Restore original ID's internal data. */
+ *id_a = id_a_back;
+ *id_b = id_b_back;
+
+ /* Exception: IDProperties. */
+ id_a->properties = id_b_back.properties;
+ id_b->properties = id_a_back.properties;
+
+ /* Swap will have broken internal references to itself, restore them. */
+ BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false);
+ BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false);
}
/** Does *not* set ID->newid pointer. */
@@ -693,15 +776,23 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (id_copy(bmain, id, &newid, false) && newid) {
/* copy animation actions too */
BKE_animdata_copy_id_action(bmain, id, false);
- /* us is 1 by convention, but RNA_property_pointer_set
- * will also increment it, so set it to zero */
- newid->us = 0;
+ /* us is 1 by convention with new IDs, but RNA_property_pointer_set
+ * will also increment it, decrement it here. */
+ id_us_min(newid);
/* assign copy */
RNA_id_pointer_create(newid, &idptr);
RNA_property_pointer_set(ptr, prop, idptr);
RNA_property_update(C, ptr, prop);
+ /* tag grease pencil datablock and disable onion */
+ if (GS(id->name) == ID_GD) {
+ DEG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(newid, OB_RECALC_OB | OB_RECALC_DATA);
+ bGPdata *gpd = (bGPdata *)newid;
+ gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
+ }
+
return true;
}
}
@@ -807,81 +898,6 @@ void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
id->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
-ListBase *which_libbase(Main *mainlib, short type)
-{
- switch ((ID_Type)type) {
- case ID_SCE:
- return &(mainlib->scene);
- case ID_LI:
- return &(mainlib->library);
- case ID_OB:
- return &(mainlib->object);
- case ID_ME:
- return &(mainlib->mesh);
- case ID_CU:
- return &(mainlib->curve);
- case ID_MB:
- return &(mainlib->mball);
- case ID_MA:
- return &(mainlib->mat);
- case ID_TE:
- return &(mainlib->tex);
- case ID_IM:
- return &(mainlib->image);
- case ID_LT:
- return &(mainlib->latt);
- case ID_LA:
- return &(mainlib->lamp);
- case ID_CA:
- return &(mainlib->camera);
- case ID_IP:
- return &(mainlib->ipo);
- case ID_KE:
- return &(mainlib->key);
- case ID_WO:
- return &(mainlib->world);
- case ID_SCR:
- return &(mainlib->screen);
- case ID_VF:
- return &(mainlib->vfont);
- case ID_TXT:
- return &(mainlib->text);
- case ID_SPK:
- return &(mainlib->speaker);
- case ID_SO:
- return &(mainlib->sound);
- case ID_GR:
- return &(mainlib->group);
- case ID_AR:
- return &(mainlib->armature);
- case ID_AC:
- return &(mainlib->action);
- case ID_NT:
- return &(mainlib->nodetree);
- case ID_BR:
- return &(mainlib->brush);
- case ID_PA:
- return &(mainlib->particle);
- case ID_WM:
- return &(mainlib->wm);
- case ID_GD:
- return &(mainlib->gpencil);
- case ID_MC:
- return &(mainlib->movieclip);
- case ID_MSK:
- return &(mainlib->mask);
- case ID_LS:
- return &(mainlib->linestyle);
- case ID_PAL:
- return &(mainlib->palettes);
- case ID_PC:
- return &(mainlib->paintcurves);
- case ID_CF:
- return &(mainlib->cachefiles);
- }
- return NULL;
-}
-
/**
* Clear or set given tags for all ids in listbase (runtime tags).
*/
@@ -963,72 +979,11 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
/* flag for full recalc */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ID_IS_LINKED(ob)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
}
- DAG_id_type_tag(bmain, ID_OB);
-}
-
-/**
- * puts into array *lb pointers to all the ListBase structs in main,
- * and returns the number of them as the function result. This is useful for
- * generic traversal of all the blocks in a Main (by traversing all the
- * lists in turn), without worrying about block types.
- *
- * \note MAX_LIBARRAY define should match this code */
-int set_listbasepointers(Main *main, ListBase **lb)
-{
- /* 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[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[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[INDEX_ID_NULL] = NULL;
-
- return (MAX_LIBARRAY - 1);
+ DEG_id_type_tag(bmain, ID_OB);
}
/* *********** ALLOC AND FREE *****************
@@ -1075,8 +1030,9 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
CASE_RETURN(ID_VF, VFont);
CASE_RETURN(ID_TXT, Text);
CASE_RETURN(ID_SPK, Speaker);
+ CASE_RETURN(ID_LP, LightProbe);
CASE_RETURN(ID_SO, bSound);
- CASE_RETURN(ID_GR, Group);
+ CASE_RETURN(ID_GR, Collection);
CASE_RETURN(ID_AR, bArmature);
CASE_RETURN(ID_AC, bAction);
CASE_RETURN(ID_NT, bNodeTree);
@@ -1090,6 +1046,7 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
CASE_RETURN(ID_PAL, Palette);
CASE_RETURN(ID_PC, PaintCurve);
CASE_RETURN(ID_CF, CacheFile);
+ CASE_RETURN(ID_WS, WorkSpace);
}
return 0;
#undef CASE_RETURN
@@ -1147,7 +1104,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
/* TODO to be removed from here! */
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
}
}
else {
@@ -1206,6 +1163,9 @@ void BKE_libblock_init_empty(ID *id)
case ID_SPK:
BKE_speaker_init((Speaker *)id);
break;
+ case ID_LP:
+ BKE_lightprobe_init((LightProbe *)id);
+ break;
case ID_CA:
BKE_camera_init((Camera *)id);
break;
@@ -1270,21 +1230,47 @@ void BKE_libblock_init_empty(ID *id)
/* Should not be needed - animation from lib pre-2.5 is broken anyway. */
BLI_assert(0);
break;
+ case ID_PAL:
+ BKE_palette_init((Palette *)id);
+ break;
default:
BLI_assert(0); /* Should never reach this point... */
}
}
-/* by spec, animdata is first item after ID */
-/* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */
-static void id_copy_animdata(Main *bmain, ID *id, const bool do_action)
+/** Generic helper to create a new empty datablock of given type in given \a bmain database.
+ *
+ * \param name can be NULL, in which case we get default name for this ID type. */
+void *BKE_id_new(Main *bmain, const short type, const char *name)
{
- AnimData *adt = BKE_animdata_from_id(id);
+ BLI_assert(bmain != NULL);
+
+ if (name == NULL) {
+ name = DATA_(BKE_idcode_to_name(type));
+ }
+
+ ID *id = BKE_libblock_alloc(bmain, type, name, 0);
+ BKE_libblock_init_empty(id);
+
+ return id;
+}
- if (adt) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action); /* could be set to false, need to investigate */
+/** Generic helper to create a new temporary empty datablock of given type, *outside* of any Main database.
+ *
+ * \param name can be NULL, in which case we get default name for this ID type. */
+void *BKE_id_new_nomain(const short type, const char *name)
+{
+ if (name == NULL) {
+ name = DATA_(BKE_idcode_to_name(type));
}
+
+ ID *id = BKE_libblock_alloc(NULL, type, name,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG);
+ BKE_libblock_init_empty(id);
+
+ return id;
}
void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
@@ -1299,6 +1285,8 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+ /* Never implicitly copy shapekeys when generating temp data outside of Main database. */
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_COPY_SHAPEKEY) == 0);
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
/* r_newid already contains pointer to allocated memory. */
@@ -1326,12 +1314,30 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
}
- /* the duplicate should get a copy of the animdata */
- BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
- id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ /* XXX Again... We need a way to control what we copy in a much more refined way.
+ * We cannot always copy this, some internal copying will die on it! */
+ /* For now, upper level code will have to do that itself when required. */
+#if 0
+ if (id->override != NULL) {
+ BKE_override_copy(new_id, id);
+ }
+#endif
+
+ if (id_can_have_animdata(new_id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)new_id;
+
+ /* the duplicate should get a copy of the animdata */
+ if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
+ BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ iat->adt = BKE_animdata_copy(bmain, iat->adt, flag);
+ }
+ else {
+ iat->adt = NULL;
+ }
+ }
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- DAG_id_type_tag(bmain, GS(new_id->name));
+ DEG_id_type_tag(bmain, GS(new_id->name));
}
*r_newid = new_id;
@@ -1362,256 +1368,6 @@ void BKE_library_free(Library *lib)
freePackedFile(lib->packedfile);
}
-Main *BKE_main_new(void)
-{
- Main *bmain = MEM_callocN(sizeof(Main), "new main");
- bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT);
- bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
- BLI_spin_init((SpinLock *)bmain->lock);
- return bmain;
-}
-
-void BKE_main_free(Main *mainvar)
-{
- /* also call when reading a file, erase all, etc */
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
-
- MEM_SAFE_FREE(mainvar->blen_thumb);
-
- a = set_listbasepointers(mainvar, lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id;
-
- while ( (id = lb->first) ) {
-#if 1
- BKE_libblock_free_ex(mainvar, id, false, false);
-#else
- /* errors freeing ID's can be hard to track down,
- * enable this so valgrind will give the line number in its error log */
- switch (a) {
- case 0: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 1: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 2: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 3: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 4: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 5: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 6: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 7: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 8: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 9: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 10: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 11: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 12: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 13: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 14: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 15: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 16: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 17: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 18: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 19: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 20: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 21: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 22: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 23: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 24: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 25: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 26: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 27: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 28: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 29: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 30: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 31: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 32: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 33: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 34: BKE_libblock_free_ex(mainvar, id, false, false); break;
- default:
- BLI_assert(0);
- break;
- }
-#endif
- }
- }
-
- if (mainvar->relations) {
- BKE_main_relations_free(mainvar);
- }
-
- BLI_spin_end((SpinLock *)mainvar->lock);
- MEM_freeN(mainvar->lock);
- DEG_evaluation_context_free(mainvar->eval_ctx);
- MEM_freeN(mainvar);
-}
-
-void BKE_main_lock(struct Main *bmain)
-{
- BLI_spin_lock((SpinLock *) bmain->lock);
-}
-
-void BKE_main_unlock(struct Main *bmain)
-{
- BLI_spin_unlock((SpinLock *) bmain->lock);
-}
-
-
-static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag)
-{
- MainIDRelations *rel = user_data;
-
- if (*id_pointer) {
- MainIDRelationsEntry *entry, **entry_p;
-
- entry = BLI_mempool_alloc(rel->entry_pool);
- if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
- entry->next = *entry_p;
- }
- else {
- entry->next = NULL;
- }
- entry->id_pointer = id_pointer;
- entry->usage_flag = cb_flag;
- *entry_p = entry;
-
- entry = BLI_mempool_alloc(rel->entry_pool);
- if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
- entry->next = *entry_p;
- }
- else {
- entry->next = NULL;
- }
- entry->id_pointer = (ID **)id_self;
- entry->usage_flag = cb_flag;
- *entry_p = entry;
- }
-
- return IDWALK_RET_NOP;
-}
-
-/** Generate the mappings between used IDs and their users, and vice-versa. */
-void BKE_main_relations_create(Main *bmain)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- ID *id;
- int a;
-
- if (bmain->relations != NULL) {
- BKE_main_relations_free(bmain);
- }
-
- bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
- bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
-
- for (a = set_listbasepointers(bmain, lbarray); a--; ) {
- for (id = lbarray[a]->first; id; id = id->next) {
- BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY);
- }
- }
-}
-
-void BKE_main_relations_free(Main *bmain)
-{
- if (bmain->relations) {
- if (bmain->relations->id_used_to_user) {
- BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
- }
- if (bmain->relations->id_user_to_used) {
- BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
- }
- BLI_mempool_destroy(bmain->relations->entry_pool);
- MEM_freeN(bmain->relations);
- bmain->relations = NULL;
- }
-}
-
-/**
- * Generates a raw .blend file thumbnail data from given image.
- *
- * \param bmain If not NULL, also store generated data in this Main.
- * \param img ImBuf image to generate thumbnail data from.
- * \return The generated .blend file raw thumbnail data.
- */
-BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
-{
- BlendThumbnail *data = NULL;
-
- if (bmain) {
- MEM_SAFE_FREE(bmain->blen_thumb);
- }
-
- if (img) {
- const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y);
- data = MEM_mallocN(sz, __func__);
-
- IMB_rect_from_float(img); /* Just in case... */
- data->width = img->x;
- data->height = img->y;
- memcpy(data->rect, img->rect, sz - sizeof(*data));
- }
-
- if (bmain) {
- bmain->blen_thumb = data;
- }
- return data;
-}
-
-/**
- * Generates an image from raw .blend file thumbnail \a data.
- *
- * \param bmain Use this bmain->blen_thumb data if given \a data is NULL.
- * \param data Raw .blend file thumbnail data.
- * \return An ImBuf from given data, or NULL if invalid.
- */
-ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
-{
- ImBuf *img = NULL;
-
- if (!data && bmain) {
- data = bmain->blen_thumb;
- }
-
- if (data) {
- /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail
- * here (we do not want to pass the first two ints!). */
- img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata);
- memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data));
- }
-
- return img;
-}
-
-/**
- * Generates an empty (black) thumbnail for given Main.
- */
-void BKE_main_thumbnail_create(struct Main *bmain)
-{
- MEM_SAFE_FREE(bmain->blen_thumb);
-
- bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__);
- bmain->blen_thumb->width = BLEN_THUMB_SIZE;
- bmain->blen_thumb->height = BLEN_THUMB_SIZE;
-}
-
-/**
- * Return filepath of given \a main.
- */
-const char *BKE_main_blendfile_path(const Main *bmain)
-{
- return bmain->name;
-}
-
-/**
- * Return filepath of global main (G_MAIN).
- *
- * \warning Usage is not recommended, you should always try to get a valid Main pointer from context...
- */
-const char *BKE_main_blendfile_path_from_global(void)
-{
- return BKE_main_blendfile_path(G_MAIN);
-}
-
/* ***************** ID ************************ */
ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name)
{
@@ -2320,7 +2076,7 @@ void BKE_library_make_local(
* Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL && ob->pose->flag & POSE_RECALC) {
- BKE_pose_rebuild(ob, ob->data);
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
}
}
@@ -2368,16 +2124,58 @@ void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
}
/**
- * Returns in name the name of the block, with a 3-character prefix prepended
- * indicating whether it comes from a library, has a fake user, or no users.
+ * Generate full name of the data-block (without ID code, but with library is any)
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name An allocated string of minimal length MAX_ID_FULL_NAME, will be filled with generated string.
+ */
+void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id)
+{
+ strcpy(name, id->name + 2);
+
+ if (id->lib != NULL) {
+ const size_t idname_len = strlen(id->name + 2);
+ const size_t libname_len = strlen(id->lib->id.name + 2);
+
+ name[idname_len] = ' ';
+ name[idname_len + 1] = '[';
+ strcpy(name + idname_len + 2, id->lib->id.name + 2);
+ name[idname_len + 2 + libname_len] = ']';
+ name[idname_len + 2 + libname_len + 1] = '\0';
+ }
+}
+
+/**
+ * Generate full name of the data-block (without ID code, but with library is any), with a 3-character prefix prepended
+ * indicating whether it comes from a library, is overriding, has a fake or no user, etc.
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name An allocated string of minimal length MAX_ID_FULL_NAME_UI, will be filled with generated string.
*/
-void BKE_id_ui_prefix(char name[MAX_ID_NAME + 1], const ID *id)
+void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const ID *id)
{
- name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ' ';
+ name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_STATIC_OVERRIDE(id) ? 'O' : ' ';
name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
name[2] = ' ';
- strcpy(name + 3, id->name + 2);
+ BKE_id_full_name_get(name + 3, id);
+}
+
+/**
+ * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any.
+ *
+ * \return A unique allocated string key for any ID in the whole Main database.
+ */
+char *BKE_id_to_unique_string_key(const struct ID *id)
+{
+ char name[MAX_ID_FULL_NAME + 2];
+ name[0] = id->name[0];
+ name[1] = id->name[1];
+ BKE_id_full_name_get(name + 2, id);
+
+ return BLI_strdup(name);
}
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
@@ -2417,8 +2215,103 @@ void BKE_id_tag_clear_atomic(ID *id, int tag)
/** Check that given ID pointer actually is in G_MAIN.
* Main intended use is for debug asserts in places we cannot easily get rid of G_Main... */
-bool BKE_id_is_in_gobal_main(ID *id)
+bool BKE_id_is_in_global_main(ID *id)
{
/* We do not want to fail when id is NULL here, even though this is a bit strange behavior... */
return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1);
}
+
+/************************* Datablock order in UI **************************/
+
+static int *id_order_get(ID *id)
+{
+ /* Only for workspace tabs currently. */
+ switch (GS(id->name)) {
+ case ID_WS:
+ return &((WorkSpace *)id)->order;
+ default:
+ return NULL;
+ }
+}
+
+static int id_order_compare(const void *a, const void *b)
+{
+ ID *id_a = ((LinkData *)a)->data;
+ ID *id_b = ((LinkData *)b)->data;
+
+ int *order_a = id_order_get(id_a);
+ int *order_b = id_order_get(id_b);
+
+ if (order_a && order_b) {
+ if (*order_a < *order_b) {
+ return -1;
+ }
+ else if (*order_a > *order_b) {
+ return 1;
+ }
+ }
+
+ return strcmp(id_a->name, id_b->name);
+}
+
+/**
+ * Returns ordered list of datablocks for display in the UI.
+ * Result is list of LinkData of IDs that must be freed.
+ */
+void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
+{
+ BLI_listbase_clear(ordered_lb);
+
+ for (ID *id = lb->first; id; id = id->next) {
+ BLI_addtail(ordered_lb, BLI_genericNodeN(id));
+ }
+
+ BLI_listbase_sort(ordered_lb, id_order_compare);
+
+ int num = 0;
+ for (LinkData *link = ordered_lb->first; link; link = link->next) {
+ int *order = id_order_get(link->data);
+ if (order) {
+ *order = num++;
+ }
+ }
+}
+
+/**
+ * Reorder ID in the list, before or after the "relative" ID.
+ */
+void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
+{
+ int *id_order = id_order_get(id);
+ int relative_order;
+
+ if (relative) {
+ relative_order = *id_order_get(relative);
+ }
+ else {
+ relative_order = (after) ? BLI_listbase_count(lb) : 0;
+ }
+
+ if (after) {
+ /* Insert after. */
+ for (ID *other = lb->first; other; other = other->next) {
+ int *order = id_order_get(other);
+ if (*order > relative_order) {
+ (*order)++;
+ }
+ }
+
+ *id_order = relative_order + 1;
+ }
+ else {
+ /* Insert before. */
+ for (ID *other = lb->first; other; other = other->next) {
+ int *order = id_order_get(other);
+ if (*order < relative_order) {
+ (*order)--;
+ }
+ }
+
+ *id_order = relative_order - 1;
+ }
+}
diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c
index daf097b9f0b..1cc13b39a97 100644
--- a/source/blender/blenkernel/intern/library_idmap.c
+++ b/source/blender/blenkernel/intern/library_idmap.c
@@ -32,6 +32,7 @@
#include "BKE_idcode.h"
#include "BKE_library.h"
#include "BKE_library_idmap.h" /* own include */
+#include "BKE_main.h"
/** \file blender/blenkernel/intern/library_idmap.c
* \ingroup bke
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
new file mode 100644
index 00000000000..714730b2f52
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -0,0 +1,789 @@
+/*
+ * ***** 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 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/library_override.c
+ * \ingroup bke
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_library_override.h"
+#include "BKE_library_remap.h"
+#include "BKE_main.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "PIL_time.h"
+#include "PIL_time_utildefines.h"
+
+#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
+
+static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src);
+static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src);
+
+static void bke_override_property_clear(IDOverrideStaticProperty *op);
+static void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop);
+
+/* Temp, for until static override is ready and tested enough to go 'public', we hide it by default in UI and such. */
+static bool _override_static_enabled = false;
+
+void BKE_override_static_enable(const bool do_enable)
+{
+ _override_static_enabled = do_enable;
+}
+
+bool BKE_override_static_is_enabled()
+{
+ return _override_static_enabled;
+}
+
+/** Initialize empty overriding of \a reference_id by \a local_id. */
+IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id)
+{
+ /* If reference_id is NULL, we are creating an override template for purely local data.
+ * Else, reference *must* be linked data. */
+ BLI_assert(reference_id == NULL || reference_id->lib != NULL);
+ BLI_assert(local_id->override_static == NULL);
+
+ ID *ancestor_id;
+ for (ancestor_id = reference_id;
+ ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL;
+ ancestor_id = ancestor_id->override_static->reference);
+
+ if (ancestor_id != NULL && ancestor_id->override_static != NULL) {
+ /* Original ID has a template, use it! */
+ BKE_override_static_copy(local_id, ancestor_id);
+ if (local_id->override_static->reference != reference_id) {
+ id_us_min(local_id->override_static->reference);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ }
+ return local_id->override_static;
+ }
+
+ /* Else, generate new empty override. */
+ local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ /* TODO do we want to add tag or flag to referee to mark it as such? */
+ return local_id->override_static;
+}
+
+/** Deep copy of a whole override from \a src_id to \a dst_id. */
+void BKE_override_static_copy(ID *dst_id, const ID *src_id)
+{
+ BLI_assert(src_id->override_static != NULL);
+
+ if (dst_id->override_static != NULL) {
+ if (src_id->override_static == NULL) {
+ BKE_override_static_free(&dst_id->override_static);
+ return;
+ }
+ else {
+ BKE_override_static_clear(dst_id->override_static);
+ }
+ }
+ else if (src_id->override_static == NULL) {
+ return;
+ }
+ else {
+ BKE_override_static_init(dst_id, NULL);
+ }
+
+ /* Source is already overriding data, we copy it but reuse its reference for dest ID.
+ * otherwise, source is only an override template, it then becomes reference of dest ID. */
+ dst_id->override_static->reference = src_id->override_static->reference ? src_id->override_static->reference : (ID *)src_id;
+ id_us_plus(dst_id->override_static->reference);
+
+ BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties);
+ for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, *op_src = src_id->override_static->properties.first;
+ op_dst;
+ op_dst = op_dst->next, op_src = op_src->next)
+ {
+ bke_override_property_copy(op_dst, op_src);
+ }
+
+ dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+}
+
+/** Clear any overriding data from given \a override. */
+void BKE_override_static_clear(IDOverrideStatic *override)
+{
+ BLI_assert(override != NULL);
+
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ bke_override_property_clear(op);
+ }
+ BLI_freelistN(&override->properties);
+
+ id_us_min(override->reference);
+ /* override->storage should never be refcounted... */
+}
+
+/** Free given \a override. */
+void BKE_override_static_free(struct IDOverrideStatic **override)
+{
+ BLI_assert(*override != NULL);
+
+ BKE_override_static_clear(*override);
+ MEM_freeN(*override);
+ *override = NULL;
+}
+
+static ID *override_static_create_from(Main *bmain, ID *reference_id)
+{
+ ID *local_id;
+
+ if (!id_copy(bmain, reference_id, (ID **)&local_id, false)) {
+ return NULL;
+ }
+ id_us_min(local_id);
+
+ BKE_override_static_init(local_id, reference_id);
+ local_id->override_static->flag |= STATICOVERRIDE_AUTO;
+
+ return local_id;
+}
+
+
+/** Create an overridden local copy of linked reference. */
+ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id)
+{
+ BLI_assert(reference_id != NULL);
+ BLI_assert(reference_id->lib != NULL);
+
+ ID *local_id = override_static_create_from(bmain, reference_id);
+
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */
+ BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+
+ return local_id;
+}
+
+/** Create overridden local copies of all tagged data-blocks in given Main.
+ *
+ * \note Set id->newid of overridden libs with newly created overrides, caller is responsible to clean those pointers
+ * before/after usage as needed.
+ *
+ * \return \a true on success, \a false otherwise.
+ */
+bool BKE_override_static_create_from_tag(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ bool ret = true;
+
+ const int num_types = a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
+ if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) {
+ ret = false;
+ }
+ }
+ }
+ }
+
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */
+ a = num_types;
+ while (a--) {
+ for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && reference_id->newid != NULL) {
+ ID *local_id = reference_id->newid;
+ BKE_libblock_remap(bmain, reference_id, local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Find override property from given RNA path, if it exists.
+ */
+IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, const char *rna_path)
+{
+ /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
+ return BLI_findstring_ptr(&override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path));
+}
+
+/**
+ * Find override property from given RNA path, or create it if it does not exist.
+ */
+IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, const char *rna_path, bool *r_created)
+{
+ /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path);
+
+ if (op == NULL) {
+ op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__);
+ op->rna_path = BLI_strdup(rna_path);
+ BLI_addtail(&override->properties, op);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return op;
+}
+
+void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src)
+{
+ op_dst->rna_path = BLI_strdup(op_src->rna_path);
+ BLI_duplicatelist(&op_dst->operations, &op_src->operations);
+
+ for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, *opop_src = op_src->operations.first;
+ opop_dst;
+ opop_dst = opop_dst->next, opop_src = opop_src->next)
+ {
+ bke_override_property_operation_copy(opop_dst, opop_src);
+ }
+}
+
+void bke_override_property_clear(IDOverrideStaticProperty *op)
+{
+ BLI_assert(op->rna_path != NULL);
+
+ MEM_freeN(op->rna_path);
+
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ bke_override_property_operation_clear(opop);
+ }
+ BLI_freelistN(&op->operations);
+}
+
+/**
+ * Remove and free given \a override_property from given ID \a override.
+ */
+void BKE_override_static_property_delete(IDOverrideStatic *override, IDOverrideStaticProperty *override_property)
+{
+ bke_override_property_clear(override_property);
+ BLI_freelinkN(&override->properties, override_property);
+}
+
+/**
+ * Find override property operation from given sub-item(s), if it exists.
+ */
+IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find(
+ IDOverrideStaticProperty *override_property,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict)
+{
+ IDOverrideStaticPropertyOperation *opop;
+ const int subitem_defindex = -1;
+
+ if (r_strict) {
+ *r_strict = true;
+ }
+
+ if (subitem_locname != NULL) {
+ opop = BLI_findstring_ptr(&override_property->operations, subitem_locname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_name));
+
+ if (opop == NULL) {
+ return NULL;
+ }
+
+ if (subitem_refname == NULL || opop->subitem_reference_name == NULL) {
+ return subitem_refname == opop->subitem_reference_name ? opop : NULL;
+ }
+ return (subitem_refname != NULL && opop->subitem_reference_name != NULL &&
+ STREQ(subitem_refname, opop->subitem_reference_name)) ? opop : NULL;
+ }
+
+ if (subitem_refname != NULL) {
+ opop = BLI_findstring_ptr(&override_property->operations, subitem_refname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name));
+
+ if (opop == NULL) {
+ return NULL;
+ }
+
+ if (subitem_locname == NULL || opop->subitem_local_name == NULL) {
+ return subitem_locname == opop->subitem_local_name ? opop : NULL;
+ }
+ return (subitem_locname != NULL && opop->subitem_local_name != NULL &&
+ STREQ(subitem_locname, opop->subitem_local_name)) ? opop : NULL;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_locindex, sizeof(subitem_locindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
+ {
+ return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_refindex, sizeof(subitem_refindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index))))
+ {
+ return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL;
+ }
+
+ /* index == -1 means all indices, that is valid fallback in case we requested specific index. */
+ if (!strict && (subitem_locindex != subitem_defindex) &&
+ (opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_defindex, sizeof(subitem_defindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
+ {
+ if (r_strict) {
+ *r_strict = false;
+ }
+ return opop;
+ }
+
+ return NULL;
+}
+
+/**
+ * Find override property operation from given sub-item(s), or create it if it does not exist.
+ */
+IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get(
+ IDOverrideStaticProperty *override_property, const short operation,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex,
+ const bool strict, bool *r_strict, bool *r_created)
+{
+ IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(override_property,
+ subitem_refname, subitem_locname,
+ subitem_refindex, subitem_locindex,
+ strict, r_strict);
+
+ if (opop == NULL) {
+ opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__);
+ opop->operation = operation;
+ if (subitem_locname) {
+ opop->subitem_local_name = BLI_strdup(subitem_locname);
+ }
+ if (subitem_refname) {
+ opop->subitem_reference_name = BLI_strdup(subitem_refname);
+ }
+ opop->subitem_local_index = subitem_locindex;
+ opop->subitem_reference_index = subitem_refindex;
+
+ BLI_addtail(&override_property->operations, opop);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return opop;
+}
+
+void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src)
+{
+ if (opop_src->subitem_reference_name) {
+ opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name);
+ }
+ if (opop_src->subitem_local_name) {
+ opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name);
+ }
+}
+
+void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop)
+{
+ if (opop->subitem_reference_name) {
+ MEM_freeN(opop->subitem_reference_name);
+ }
+ if (opop->subitem_local_name) {
+ MEM_freeN(opop->subitem_local_name);
+ }
+}
+
+/**
+ * Remove and free given \a override_property_operation from given ID \a override_property.
+ */
+void BKE_override_static_property_operation_delete(
+ IDOverrideStaticProperty *override_property, IDOverrideStaticPropertyOperation *override_property_operation)
+{
+ bke_override_property_operation_clear(override_property_operation);
+ BLI_freelinkN(&override_property->operations, override_property_operation);
+}
+
+/**
+ * Check that status of local data-block is still valid against current reference one.
+ *
+ * It means that all overridable, but not overridden, properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some property has been changed in local and a new IDOverrideProperty
+ * (of IDOverridePropertyOperation) has to be added.
+ *
+ * \return true if status is OK, false otherwise. */
+bool BKE_override_static_status_check_local(Main *bmain, ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, local status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ /* Note that reference is assumed always valid, caller has to ensure that itself. */
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
+ {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Check that status of reference data-block is still valid against current local one.
+ *
+ * It means that all non-overridden properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some reference has changed and local needs to be updated against it.
+ *
+ * \return true if status is OK, false otherwise. */
+bool BKE_override_static_status_check_reference(Main *bmain, ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, reference is virtual, so its status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
+ if (!BKE_override_static_status_check_reference(bmain, reference)) {
+ /* If reference is also override of another data-block, and its status is not OK,
+ * then this override is not OK either.
+ * Note that this should only happen when reloading libraries... */
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+ }
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
+ {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Compares local and reference data-blocks and create new override operations as needed,
+ * or reset to reference values if overriding is not allowed.
+ *
+ * \note Defining override operations is only mandatory before saving a .blend file on disk (not for undo!).
+ * Knowing that info at runtime is only useful for UI/UX feedback.
+ *
+ * \note This is by far the biggest operation (the more time-consuming) of the three so far, since it has to go over
+ * all properties in depth (all overridable ones at least). Generating diff values and applying overrides
+ * are much cheaper.
+ *
+ * \return true if new overriding op was created, or some local data was reset. */
+bool BKE_override_static_operations_create(Main *bmain, ID *local, const bool force_auto)
+{
+ BLI_assert(local->override_static != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+ bool ret = false;
+
+ if (!is_template && (force_auto || local->override_static->flag & STATICOVERRIDE_AUTO)) {
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+
+ eRNAOverrideMatchResult report_flags = 0;
+ RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags);
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
+ ret = true;
+ }
+#ifndef NDEBUG
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
+ printf("We did restore some properties of %s from its reference.\n", local->name);
+ }
+ if (ret) {
+ printf("We did generate static override rules for %s\n", local->name);
+ }
+ else {
+ printf("No new static override rules for %s\n", local->name);
+ }
+#endif
+ }
+ return ret;
+}
+
+/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
+void BKE_main_override_static_operations_create(Main *bmain, const bool force_auto)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (force_auto ||
+ (ID_IS_STATIC_OVERRIDE_AUTO(id) && (id->tag & LIB_TAG_OVERRIDESTATIC_AUTOREFRESH)))
+ {
+ BKE_override_static_operations_create(bmain, id, force_auto);
+ id->tag &= ~LIB_TAG_OVERRIDESTATIC_AUTOREFRESH;
+ }
+ }
+ }
+}
+
+/** Update given override from its reference (re-applying overridden properties). */
+void BKE_override_static_update(Main *bmain, ID *local)
+{
+ if (local->override_static == NULL || local->override_static->reference == NULL) {
+ return;
+ }
+
+ /* Recursively do 'ancestors' overrides first, if any. */
+ if (local->override_static->reference->override_static && (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
+ BKE_override_static_update(bmain, local->override_static->reference);
+ }
+
+ /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based
+ * on reference than on current override.
+ * So we work on temp copy of reference, and 'swap' its content with local. */
+
+ /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)!
+ * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do,
+ * as innefficient as it is. :/
+ * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep
+ * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data
+ * also remain correct). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first if extra useless usual user handling is actually
+ * a (performances) issue here. */
+
+ ID *tmp_id;
+ id_copy(bmain, local->override_static->reference, &tmp_id, false);
+
+ if (tmp_id == NULL) {
+ return;
+ }
+
+ PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
+ RNA_id_pointer_create(local, &rnaptr_src);
+ RNA_id_pointer_create(tmp_id, &rnaptr_dst);
+ if (local->override_static->storage) {
+ rnaptr_storage = &rnaptr_storage_stack;
+ RNA_id_pointer_create(local->override_static->storage, rnaptr_storage);
+ }
+
+ RNA_struct_override_apply(bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
+
+ /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id,
+ * we'll actually free old, outdated data from local. */
+ BKE_id_swap(bmain, local, tmp_id);
+
+ /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */
+ /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */
+ BKE_libblock_free_ex(bmain, tmp_id, true, false);
+
+ if (local->override_static->storage) {
+ /* We know this datablock is not used anywhere besides local->override->storage. */
+ /* XXX For until we get fully shadow copies, we still need to ensure storage releases
+ * its usage of any ID pointers it may have. */
+ BKE_libblock_free_ex(bmain, local->override_static->storage, true, false);
+ local->override_static->storage = NULL;
+ }
+
+ local->tag |= LIB_TAG_OVERRIDESTATIC_REFOK;
+
+ /* Full rebuild of Depsgraph! */
+ DEG_on_visible_update(bmain, true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
+}
+
+/** Update all overrides from given \a bmain. */
+void BKE_main_override_static_update(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (id->override_static != NULL && id->lib == NULL) {
+ BKE_override_static_update(bmain, id);
+ }
+ }
+ }
+}
+
+/***********************************************************************************************************************
+ * Storage (how to wtore overriding data into .blend files).
+ *
+ * Basically:
+ * I) Only 'differential' storage needs special handling here. All others (replacing values or
+ * inserting/removing items from a collection) can be handled with simply storing current content of local data-block.
+ * II) We store the differential value into a second 'ghost' data-block, which is an empty ID of same type as local one,
+ * where we only define values that need differential data.
+ *
+ * This avoids us having to modify 'real' data-block at write time (and restoring it afterwards), which is inneficient,
+ * and potentially dangerous (in case of concurrent access...), while not using much extra memory in typical cases.
+ * It also ensures stored data-block always contains exact same data as "desired" ones (kind of "baked" data-blocks).
+ */
+
+/** Initialize an override storage. */
+OverrideStaticStorage *BKE_override_static_operations_store_initialize(void)
+{
+ return BKE_main_new();
+}
+
+/**
+ * Generate suitable 'write' data (this only affects differential override operations).
+ *
+ * Note that \a local ID is no more modified by this call, all extra data are stored in its temp \a storage_id copy. */
+ID *BKE_override_static_operations_store_start(Main *bmain, OverrideStaticStorage *override_storage, ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+ BLI_assert(override_storage != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+
+ if (is_template) {
+ /* This is actually purely local data with an override template, nothing to do here! */
+ return NULL;
+ }
+
+ /* Forcefully ensure we know about all needed override operations. */
+ BKE_override_static_operations_create(bmain, local, false);
+
+ ID *storage_id;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(BKE_override_operations_store_start);
+#endif
+
+ /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable
+ * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first is extra useless usual user handling is actually
+ * a (performances) issue here, before doing it. */
+ id_copy((Main *)override_storage, local, &storage_id, false);
+
+ if (storage_id != NULL) {
+ PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage;
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+ RNA_id_pointer_create(local, &rnaptr_final);
+ RNA_id_pointer_create(storage_id, &rnaptr_storage);
+
+ if (!RNA_struct_override_store(
+ bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static))
+ {
+ BKE_libblock_free_ex(override_storage, storage_id, true, false);
+ storage_id = NULL;
+ }
+ }
+
+ local->override_static->storage = storage_id;
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(BKE_override_operations_store_start);
+#endif
+ return storage_id;
+}
+
+/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */
+void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until
+ * whole file is written anyway (otherwise we'd get mem pointers overlap...). */
+ local->override_static->storage = NULL;
+}
+
+void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage)
+{
+ /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs
+ * without increasing usercount of used data-blocks... */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(override_storage, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ while ((id = lb->first)) {
+ BKE_libblock_free_ex(override_storage, id, true, false);
+ }
+ }
+
+ BKE_main_free(override_storage);
+}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index f5367f6f8b3..f0f23eaa87d 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -31,14 +31,12 @@
#include "MEM_guardedalloc.h"
-#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@@ -52,15 +50,17 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_force_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_sensor_types.h"
#include "DNA_sequence_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
#include "DNA_text_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
@@ -69,8 +69,10 @@
#include "BLI_linklist_stack.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -79,9 +81,9 @@
#include "BKE_node.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
-#include "BKE_sca.h"
#include "BKE_sequencer.h"
#include "BKE_tracking.h"
+#include "BKE_workspace.h"
#define FOREACH_FINALIZE _finalize
@@ -194,27 +196,8 @@ static void library_foreach_modifiersForeachIDLink(
FOREACH_FINALIZE_VOID;
}
-static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
- bool is_reference, void *user_data)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_particlesystemsObjectLooper(
- ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_sensorsObjectLooper(
- bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cb_flag)
+static void library_foreach_gpencil_modifiersForeachIDLink(
+ void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
@@ -222,17 +205,18 @@ static void library_foreach_sensorsObjectLooper(
FOREACH_FINALIZE_VOID;
}
-static void library_foreach_controllersObjectLooper(
- bController *UNUSED(controller), ID **id_pointer, void *user_data, int cb_flag)
+static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
+ bool is_reference, void *user_data)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
+ const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
-static void library_foreach_actuatorsObjectLooper(
- bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cb_flag)
+static void library_foreach_particlesystemsObjectLooper(
+ ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
@@ -296,6 +280,9 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
{
FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
+ for (int i = 0; i < paint->tool_slots_len; i++) {
+ FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
+ }
FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
FOREACH_FINALIZE_VOID;
@@ -312,6 +299,16 @@ static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ FOREACH_CALLBACK_INVOKE(data, lc->collection, IDWALK_CB_NOP);
+ library_foreach_layer_collection(data, &lc->layer_collections);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_ID_as_subdata_link(
ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
{
@@ -384,6 +381,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
continue;
}
+ if (id->override_static != NULL) {
+ CALLBACK_INVOKE_ID(id->override_static->reference, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ CALLBACK_INVOKE_ID(id->override_static->storage, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ }
+
library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
AnimData *adt = BKE_animdata_from_id(id);
@@ -402,8 +404,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
{
Scene *scene = (Scene *) id;
ToolSettings *toolsett = scene->toolsettings;
- SceneRenderLayer *srl;
- Base *base;
CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
@@ -413,35 +413,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, callback, user_data, flag, &data);
}
- /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later,
- * since basact is just a pointer to one of those items. */
- CALLBACK_INVOKE(scene->obedit, IDWALK_CB_NOP);
-
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
-
- if (srl->mat_override) {
- CALLBACK_INVOKE(srl->mat_override, IDWALK_CB_USER);
- }
- if (srl->light_override) {
- CALLBACK_INVOKE(srl->light_override, IDWALK_CB_USER);
- }
- for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
- }
- }
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
- }
- if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
- }
- }
- }
-
if (scene->ed) {
Sequence *seq;
SEQP_BEGIN(scene->ed, seq)
@@ -458,10 +429,37 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
} SEQ_END;
}
- CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
- for (base = scene->base.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_CB_USER);
+ for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) {
+ CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
+ }
+ for (CollectionChild *child = scene->master_collection->children.first; child; child = child->next) {
+ CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
+ }
+
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ CALLBACK_INVOKE(base->object, IDWALK_CB_NOP);
+ }
+
+ library_foreach_layer_collection(&data, &view_layer->layer_collections);
+
+ for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
+ if (fmc->script) {
+ CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
+ }
+ }
+
+ for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ if (fls->group) {
+ CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
+ }
+
+ if (fls->linestyle) {
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
+ }
+ }
}
for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
@@ -469,8 +467,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
if (toolsett) {
- CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_CB_NOP);
-
CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP);
CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP);
@@ -493,14 +489,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
if (toolsett->uvsculpt) {
library_foreach_paint(&data, &toolsett->uvsculpt->paint);
}
+ if (toolsett->gp_paint) {
+ library_foreach_paint(&data, &toolsett->gp_paint->paint);
+ }
}
if (scene->rigidbody_world) {
BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
}
- CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP);
-
break;
}
@@ -585,6 +582,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
+ BKE_gpencil_modifiers_foreachIDLink(object, library_foreach_gpencil_modifiersForeachIDLink, &data);
BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data);
for (psys = object->particlesystem.first; psys; psys = psys->next) {
@@ -598,10 +596,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
}
}
-
- BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
- BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data);
- BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data);
break;
}
@@ -623,31 +617,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
for (i = 0; i < mesh->totcol; i++) {
CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
}
-
- /* XXX Really not happy with this - probably texface should rather use some kind of
- * 'texture slots' and just set indices in each poly/face item - would also save some memory.
- * Maybe a nice TODO for blender2.8? */
- if (mesh->mtface || mesh->mtpoly) {
- for (i = 0; i < mesh->pdata.totlayer; i++) {
- if (mesh->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data;
-
- for (int j = 0; j < mesh->totpoly; j++, txface++) {
- CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE);
- }
- }
- }
-
- for (i = 0; i < mesh->fdata.totlayer; i++) {
- if (mesh->fdata.layers[i].type == CD_MTFACE) {
- MTFace *tface = (MTFace *)mesh->fdata.layers[i].data;
-
- for (int j = 0; j < mesh->totface; j++, tface++) {
- CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE);
- }
- }
- }
- }
break;
}
@@ -680,19 +649,17 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_MA:
{
Material *material = (Material *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (material->mtex[i]) {
- library_foreach_mtex(&data, material->mtex[i]);
- }
- }
if (material->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(material->group, IDWALK_CB_USER);
if (material->texpaintslot != NULL) {
CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
}
+ if (material->gp_style != NULL) {
+ CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
+ CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
+ }
break;
}
@@ -704,16 +671,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data);
}
CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
- if (texture->env) {
- CALLBACK_INVOKE(texture->env->object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(texture->env->ima, IDWALK_CB_USER);
- }
- if (texture->pd)
- CALLBACK_INVOKE(texture->pd->object, IDWALK_CB_NOP);
- if (texture->vd)
- CALLBACK_INVOKE(texture->vd->object, IDWALK_CB_NOP);
- if (texture->ot)
- CALLBACK_INVOKE(texture->ot->object, IDWALK_CB_NOP);
break;
}
@@ -727,11 +684,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_LA:
{
Lamp *lamp = (Lamp *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (lamp->mtex[i]) {
- library_foreach_mtex(&data, lamp->mtex[i]);
- }
- }
if (lamp->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data);
@@ -743,6 +695,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
{
Camera *camera = (Camera *) id;
CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP);
+ for (CameraBGImage *bgpic = camera->bg_images.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+ CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER);
+ }
+ else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+ CALLBACK_INVOKE(bgpic->clip, IDWALK_CB_USER);
+ }
+ }
+
break;
}
@@ -753,21 +714,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
break;
}
- case ID_SCR:
- {
- bScreen *screen = (bScreen *) id;
- CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE);
- break;
- }
-
case ID_WO:
{
World *world = (World *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (world->mtex[i]) {
- library_foreach_mtex(&data, world->mtex[i]);
- }
- }
if (world->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data);
@@ -782,12 +731,22 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
break;
}
+ case ID_LP:
+ {
+ LightProbe *probe = (LightProbe *) id;
+ CALLBACK_INVOKE(probe->image, IDWALK_CB_USER);
+ CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP);
+ break;
+ }
+
case ID_GR:
{
- Group *group = (Group *) id;
- GroupObject *gob;
- for (gob = group->gobject.first; gob; gob = gob->next) {
- CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE);
+ Collection *collection = (Collection *) id;
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
+ }
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
}
break;
}
@@ -827,6 +786,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
+ if (brush->gpencil_settings) {
+ CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
+ }
library_foreach_mtex(&data, &brush->mtex);
library_foreach_mtex(&data, &brush->mask_mtex);
break;
@@ -876,6 +838,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
}
}
+
+ for (ParticleDupliWeight *dw = psett->dupliweights.first; dw; dw = dw->next) {
+ CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP);
+ }
break;
}
@@ -970,22 +936,60 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
break;
}
+
+ case ID_WM:
+ {
+ wmWindowManager *wm = (wmWindowManager *)id;
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
+
+ CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE);
+
+ CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP);
+ /* allow callback to set a different workspace */
+ BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
+ }
+ break;
+ }
+
+ case ID_WS:
+ {
+ WorkSpace *workspace = (WorkSpace *)id;
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer.
+ * However we can't access layout->screen here since we are outside the workspace project. */
+ CALLBACK_INVOKE(screen, IDWALK_CB_USER);
+ /* allow callback to set a different screen */
+ BKE_workspace_layout_screen_set(layout, screen);
+ }
+ break;
+ }
case ID_GD:
{
bGPdata *gpencil = (bGPdata *) id;
+ /* materials */
+ for (i = 0; i < gpencil->totcol; i++) {
+ CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
+ }
- for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) {
- CALLBACK_INVOKE(gp_layer->parent, IDWALK_CB_NOP);
+ for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; gplayer = gplayer->next) {
+ CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
}
+
break;
}
/* Nothing needed for those... */
+ case ID_SCR:
case ID_IM:
case ID_VF:
case ID_TXT:
case ID_SO:
- case ID_WM:
case ID_PAL:
case ID_PC:
case ID_CF:
@@ -1062,14 +1066,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT,
ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT));
case ID_OB:
- /* Could be the following, but simpler to just always say 'yes' here. */
-#if 0
- return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */
- ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC
- /* + constraints, modifiers and game logic ID types... */);
-#else
+ /* Could be more specific, but simpler to just always say 'yes' here. */
return true;
-#endif
case ID_ME:
return ELEM(id_type_used, ID_ME, ID_KE, ID_MA, ID_IM);
case ID_CU:
@@ -1095,16 +1093,12 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_SPK:
return ELEM(id_type_used, ID_SO);
case ID_GR:
- return ELEM(id_type_used, ID_OB);
+ return ELEM(id_type_used, ID_OB, ID_GR);
case ID_NT:
- /* Could be the following, but node.id has no type restriction... */
-#if 0
- return ELEM(id_type_used, ID_GD /* + node.id types... */);
-#else
+ /* Could be more specific, but node.id has no type restriction... */
return true;
-#endif
case ID_BR:
- return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE);
+ return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA);
case ID_PA:
return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
case ID_MC:
@@ -1113,13 +1107,18 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
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));
+ case ID_LP:
+ return ELEM(id_type_used, ID_IM);
+ case ID_GD:
+ return ELEM(id_type_used, ID_MA);
+ case ID_WS:
+ return ELEM(id_type_used, ID_SCR, ID_SCE);
case ID_IM:
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:
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 604e7754352..e5d313e5018 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -39,7 +39,7 @@
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cachefile_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
@@ -53,6 +53,7 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -60,6 +61,7 @@
#include "DNA_text_types.h"
#include "DNA_vfont_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "BLI_blenlib.h"
@@ -71,11 +73,10 @@
#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_font.h"
-#include "BKE_group.h"
#include "BKE_gpencil.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@@ -83,7 +84,9 @@
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -99,15 +102,19 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
-#include "BKE_sca.h"
+#include "BKE_lightprobe.h"
#include "BKE_speaker.h"
#include "BKE_sound.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
#include "BKE_text.h"
#include "BKE_texture.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -173,6 +180,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
if (*id_p && (*id_p == old_id)) {
+ const bool is_reference = (cb_flag & IDWALK_CB_STATIC_OVERRIDE_REFERENCE) != 0;
const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
@@ -183,11 +191,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_STATIC_OVERRIDE) != 0;
const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
#ifdef DEBUG_PRINT
- printf("In %s: Remapping %s (%p) to %s (%p) (is_indirect: %d, skip_indirect: %d)\n",
- id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, is_indirect, skip_indirect);
+ printf("In %s (lib %p): Remapping %s (%p) to %s (%p) "
+ "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
+ id->name, id->lib, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id,
+ is_indirect, skip_indirect, is_reference, skip_reference);
#endif
if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
@@ -199,7 +210,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
* (skipped_indirect too). */
if ((is_never_null && skip_never_null) ||
(is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) ||
- (skip_indirect && is_indirect))
+ (skip_indirect && is_indirect) ||
+ (is_reference && skip_reference))
{
if (is_indirect) {
id_remap_data->skipped_indirect++;
@@ -212,7 +224,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
}
}
- else if (is_never_null || is_obj_editmode) {
+ else if (is_never_null || is_obj_editmode || is_reference) {
id_remap_data->skipped_direct++;
}
else {
@@ -229,7 +241,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
else {
if (!is_never_null) {
*id_p = new_id;
- DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update_ex(id_remap_data->bmain, id_self,
+ DEG_TAG_COPY_ON_WRITE | DEG_TAG_TRANSFORM | DEG_TAG_GEOMETRY);
}
if (cb_flag & IDWALK_CB_USER) {
id_us_min(old_id);
@@ -251,58 +264,9 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
return IDWALK_RET_NOP;
}
-/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */
-static void libblock_remap_data_preprocess_scene_base_unlink(
- IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect)
-{
- if (skip_indirect && is_indirect) {
- r_id_remap_data->skipped_indirect++;
- r_id_remap_data->skipped_refcounted++;
- }
- else {
- id_us_min((ID *)base->object);
- BKE_scene_base_unlink(sce, base);
- MEM_freeN(base);
- if (!is_indirect) {
- r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
- }
- }
-}
-
static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
{
switch (GS(r_id_remap_data->id->name)) {
- case ID_SCE:
- {
- Scene *sce = (Scene *)r_id_remap_data->id;
-
- if (!r_id_remap_data->new_id) {
- const bool is_indirect = (sce->id.lib != NULL);
- const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
-
- /* In case we are unlinking... */
- if (!r_id_remap_data->old_id) {
- /* ... everything from scene. */
- Base *base, *base_next;
- for (base = sce->base.first; base; base = base_next) {
- base_next = base->next;
- libblock_remap_data_preprocess_scene_base_unlink(
- r_id_remap_data, sce, base, skip_indirect, is_indirect);
- }
- }
- else if (GS(r_id_remap_data->old_id->name) == ID_OB) {
- /* ... a specific object from scene. */
- Object *old_ob = (Object *)r_id_remap_data->old_id;
- Base *base = BKE_scene_base_find(sce, old_ob);
-
- if (base) {
- libblock_remap_data_preprocess_scene_base_unlink(
- r_id_remap_data, sce, base, skip_indirect, is_indirect);
- }
- }
- }
- break;
- }
case ID_OB:
{
ID *old_id = r_id_remap_data->old_id;
@@ -328,58 +292,49 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
}
}
+/* Can be called with both old_ob and new_ob being NULL, this means we have to check whole Main database then. */
static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob)
{
- if (old_ob->flag & OB_FROMGROUP) {
- /* Note that for Scene's BaseObject->flag, either we:
- * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
- * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is.
- * So in any case, no need to update them here. */
- if (BKE_group_object_find(bmain, NULL, old_ob) == NULL) {
- old_ob->flag &= ~OB_FROMGROUP;
- }
- if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */
- for (Group *group = bmain->group.first; group; group = group->id.next) {
- BKE_group_object_unlink(bmain, group, NULL, NULL, NULL);
+ if (new_ob == NULL) {
+ /* In case we unlinked old_ob (new_ob is NULL), the object has already
+ * been removed from the scenes and their collections. We still have
+ * to remove the NULL children from collections not used in any scene. */
+ BKE_collections_object_remove_nulls(bmain);
+ }
+
+ BKE_main_collection_sync_remap(bmain);
+
+ if (old_ob == NULL) {
+ for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) {
+ if (ob->type == OB_MBALL && BKE_mball_is_basis(ob)) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
- else {
- new_ob->flag |= OB_FROMGROUP;
- }
}
- if (old_ob->type == OB_MBALL) {
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ else {
+ for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) {
if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ break; /* There is only one basis... */
}
}
}
}
-static void libblock_remap_data_postprocess_group_scene_unlink(Main *bmain, Scene *sce, ID *old_id)
+/* Can be called with both old_collection and new_collection being NULL,
+ * this means we have to check whole Main database then. */
+static void libblock_remap_data_postprocess_collection_update(
+ Main *bmain, Collection *UNUSED(old_collection), Collection *new_collection)
{
- /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
- * in one scene...). */
- for (Base *base = sce->base.first; base; base = base->next) {
- if (base->flag & OB_FROMGROUP) {
- Object *ob = base->object;
-
- if (ob->flag & OB_FROMGROUP) {
- Group *grp = BKE_group_object_find(bmain, NULL, ob);
-
- /* Unlinked group (old_id) is still in bmain... */
- if (grp && (&grp->id == old_id || grp->id.us == 0)) {
- grp = BKE_group_object_find(bmain, grp, ob);
- }
- if (!grp) {
- ob->flag &= ~OB_FROMGROUP;
- }
- }
- if (!(ob->flag & OB_FROMGROUP)) {
- base->flag &= ~OB_FROMGROUP;
- }
- }
+ if (new_collection == NULL) {
+ /* XXX Complex cases can lead to NULL pointers in other collections than old_collection,
+ * and BKE_main_collection_sync_remap() does not tolerate any of those, so for now always check whole
+ * existing collections for NULL pointers.
+ * I'd consider optimizing that whole collection remapping process a TODO for later. */
+ BKE_collections_child_remove_nulls(bmain, NULL /*old_collection*/);
}
+
+ BKE_main_collection_sync_remap(bmain);
}
static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *ob, ID *new_id)
@@ -480,10 +435,6 @@ ATTR_NONNULL(1) static void libblock_remap_data(
}
}
- if (old_id && GS(old_id->name) == ID_OB) {
- BKE_sca_logic_links_remap(bmain, (Object *)old_id, (Object *)new_id);
- }
-
/* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
* though, we can always add an option (flag) to control this later if needed. */
if (old_id && (old_id->flag & LIB_FAKEUSER)) {
@@ -567,11 +518,7 @@ void BKE_libblock_remap_locked(
libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
break;
case ID_GR:
- if (!new_id) { /* Only affects us in case group was unlinked. */
- for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
- }
- }
+ libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id);
break;
case ID_ME:
case ID_CU:
@@ -594,8 +541,8 @@ void BKE_libblock_remap_locked(
libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
BKE_main_lock(bmain);
- /* Full rebuild of DAG! */
- DAG_relations_tag_update(bmain);
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
}
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
@@ -668,32 +615,22 @@ void BKE_libblock_relink_ex(
switch (GS(id->name)) {
case ID_SCE:
{
- Scene *sce = (Scene *)id;
-
if (old_id) {
switch (GS(old_id->name)) {
case ID_OB:
- {
libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
break;
- }
case ID_GR:
- if (!new_id) { /* Only affects us in case group was unlinked. */
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
- }
+ libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id);
break;
default:
break;
}
}
else {
- /* No choice but to check whole objects/groups. */
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- libblock_remap_data_postprocess_object_update(bmain, ob, NULL);
- }
- for (Group *grp = bmain->group.first; grp; grp = grp->id.next) {
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
- }
+ /* No choice but to check whole objects/collections. */
+ libblock_remap_data_postprocess_collection_update(bmain, NULL, NULL);
+ libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
}
break;
}
@@ -747,6 +684,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
MEM_freeN(id->properties);
}
+ if (id->override_static) {
+ BKE_override_static_free(&id->override_static);
+ }
+
/* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */
}
@@ -755,7 +696,7 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
const short type = GS(id->name);
switch (type) {
case ID_SCE:
- BKE_scene_free((Scene *)id);
+ BKE_scene_free_ex((Scene *)id, false);
break;
case ID_LI:
BKE_library_free((Library *)id);
@@ -811,11 +752,14 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
case ID_SPK:
BKE_speaker_free((Speaker *)id);
break;
+ case ID_LP:
+ BKE_lightprobe_free((LightProbe *)id);
+ break;
case ID_SO:
BKE_sound_free((bSound *)id);
break;
case ID_GR:
- BKE_group_free((Group *)id);
+ BKE_collection_free((Collection *)id);
break;
case ID_AR:
BKE_armature_free((bArmature *)id);
@@ -857,6 +801,9 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
case ID_CF:
BKE_cachefile_free((CacheFile *)id);
break;
+ case ID_WS:
+ BKE_workspace_free((WorkSpace *)id);
+ break;
}
}
@@ -867,7 +814,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
if (use_flag_from_idtag) {
if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
- flag |= LIB_ID_FREE_NO_MAIN;
+ flag |= LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER | LIB_ID_FREE_NO_DEG_TAG;
}
else {
flag &= ~LIB_ID_FREE_NO_MAIN;
@@ -895,7 +842,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
const short type = GS(id->name);
if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
}
#ifdef WITH_PYTHON
@@ -958,7 +905,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b
short type = GS(id->name);
ListBase *lb = which_libbase(bmain, type);
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
#ifdef WITH_PYTHON
#ifdef WITH_PYTHON_SAFETY
@@ -1007,8 +954,8 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
id_us_min(id);
- /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
- * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
+ /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding collections when deleting an object.
+ * Since only 'user_one' usage of objects is collections, and only 'real user' usage of objects is scenes,
* removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
* fully unlinked.
* But only for local objects, not linked ones!
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
new file mode 100644
index 00000000000..4cb2b450afe
--- /dev/null
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -0,0 +1,101 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/lightprobe.c
+ * \ingroup bke
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_animsys.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_lightprobe.h"
+#include "BKE_main.h"
+
+void BKE_lightprobe_init(LightProbe *probe)
+{
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(probe, id));
+
+ probe->grid_resolution_x = probe->grid_resolution_y = probe->grid_resolution_z = 4;
+ probe->distinf = 2.5f;
+ probe->distpar = 2.5f;
+ probe->falloff = 0.2f;
+ probe->clipsta = 0.8f;
+ probe->clipend = 40.0f;
+ probe->vis_bias = 1.0f;
+ probe->vis_blur = 0.2f;
+ probe->intensity = 1.0f;
+
+ probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA;
+}
+
+void *BKE_lightprobe_add(Main *bmain, const char *name)
+{
+ LightProbe *probe;
+
+ probe = BKE_libblock_alloc(bmain, ID_LP, name, 0);
+
+ BKE_lightprobe_init(probe);
+
+ return probe;
+}
+
+/**
+ * Only copy internal data of LightProbe ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_lightprobe_copy_data(
+ Main *UNUSED(bmain), LightProbe *UNUSED(probe_dst), const LightProbe *UNUSED(probe_src), const int UNUSED(flag))
+{
+ /* Nothing to do here. */
+}
+
+LightProbe *BKE_lightprobe_copy(Main *bmain, const LightProbe *probe)
+{
+ LightProbe *probe_copy;
+ BKE_id_copy_ex(bmain, &probe->id, (ID **)&probe_copy, 0, false);
+ return probe_copy;
+}
+
+void BKE_lightprobe_make_local(Main *bmain, LightProbe *probe, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &probe->id, true, lib_local);
+}
+
+void BKE_lightprobe_free(LightProbe *probe)
+{
+ BKE_animdata_free((ID *)probe, false);
+}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index e00884c8a9d..5757ae7480b 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -212,20 +212,11 @@ void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle,
BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local);
}
-FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene)
+FreestyleLineStyle *BKE_linestyle_active_from_view_layer(ViewLayer *view_layer)
{
- SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- if (!actsrl) {
- return NULL;
- }
-
- FreestyleConfig *config = &actsrl->freestyleConfig;
+ FreestyleConfig *config = &view_layer->freestyle_config;
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
-
- if (lineset) {
- return lineset->linestyle;
- }
- return NULL;
+ return (lineset) ? lineset->linestyle : NULL;
}
static LineStyleModifier *new_modifier(const char *name, int type, size_t size)
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
new file mode 100644
index 00000000000..c063af48186
--- /dev/null
+++ b/source/blender/blenkernel/intern/main.c
@@ -0,0 +1,445 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/main.c
+ * \ingroup bke
+ *
+ * Contains management of Main database itself.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_mempool.h"
+#include "BLI_threads.h"
+
+#include "DNA_ID.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_main.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+Main *BKE_main_new(void)
+{
+ Main *bmain = MEM_callocN(sizeof(Main), "new main");
+ bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
+ BLI_spin_init((SpinLock *)bmain->lock);
+ return bmain;
+}
+
+void BKE_main_free(Main *mainvar)
+{
+ /* also call when reading a file, erase all, etc */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+
+ MEM_SAFE_FREE(mainvar->blen_thumb);
+
+ a = set_listbasepointers(mainvar, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id;
+
+ while ( (id = lb->first) ) {
+#if 1
+ BKE_libblock_free_ex(mainvar, id, false, false);
+#else
+ /* errors freeing ID's can be hard to track down,
+ * enable this so valgrind will give the line number in its error log */
+ switch (a) {
+ case 0: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 1: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 2: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 3: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 4: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 5: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 6: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 7: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 8: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 9: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 10: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 11: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 12: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 13: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 14: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 15: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 16: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 17: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 18: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 19: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 20: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 21: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 22: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 23: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 24: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 25: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 26: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 27: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 28: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 29: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 30: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 31: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 32: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 33: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 34: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+#endif
+ }
+ }
+
+ if (mainvar->relations) {
+ BKE_main_relations_free(mainvar);
+ }
+
+ BLI_spin_end((SpinLock *)mainvar->lock);
+ MEM_freeN(mainvar->lock);
+ MEM_freeN(mainvar);
+}
+
+void BKE_main_lock(struct Main *bmain)
+{
+ BLI_spin_lock((SpinLock *) bmain->lock);
+}
+
+void BKE_main_unlock(struct Main *bmain)
+{
+ BLI_spin_unlock((SpinLock *) bmain->lock);
+}
+
+
+static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag)
+{
+ MainIDRelations *rel = user_data;
+
+ if (*id_pointer) {
+ MainIDRelationsEntry *entry, **entry_p;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = id_pointer;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = (ID **)id_self;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/** Generate the mappings between used IDs and their users, and vice-versa. */
+void BKE_main_relations_create(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ if (bmain->relations != NULL) {
+ BKE_main_relations_free(bmain);
+ }
+
+ bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
+ bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
+
+ for (a = set_listbasepointers(bmain, lbarray); a--; ) {
+ for (id = lbarray[a]->first; id; id = id->next) {
+ BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY);
+ }
+ }
+}
+
+void BKE_main_relations_free(Main *bmain)
+{
+ if (bmain->relations) {
+ if (bmain->relations->id_used_to_user) {
+ BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
+ }
+ if (bmain->relations->id_user_to_used) {
+ BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
+ }
+ BLI_mempool_destroy(bmain->relations->entry_pool);
+ MEM_freeN(bmain->relations);
+ bmain->relations = NULL;
+ }
+}
+
+/**
+ * Generates a raw .blend file thumbnail data from given image.
+ *
+ * \param bmain If not NULL, also store generated data in this Main.
+ * \param img ImBuf image to generate thumbnail data from.
+ * \return The generated .blend file raw thumbnail data.
+ */
+BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
+{
+ BlendThumbnail *data = NULL;
+
+ if (bmain) {
+ MEM_SAFE_FREE(bmain->blen_thumb);
+ }
+
+ if (img) {
+ const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y);
+ data = MEM_mallocN(sz, __func__);
+
+ IMB_rect_from_float(img); /* Just in case... */
+ data->width = img->x;
+ data->height = img->y;
+ memcpy(data->rect, img->rect, sz - sizeof(*data));
+ }
+
+ if (bmain) {
+ bmain->blen_thumb = data;
+ }
+ return data;
+}
+
+/**
+ * Generates an image from raw .blend file thumbnail \a data.
+ *
+ * \param bmain Use this bmain->blen_thumb data if given \a data is NULL.
+ * \param data Raw .blend file thumbnail data.
+ * \return An ImBuf from given data, or NULL if invalid.
+ */
+ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
+{
+ ImBuf *img = NULL;
+
+ if (!data && bmain) {
+ data = bmain->blen_thumb;
+ }
+
+ if (data) {
+ /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail
+ * here (we do not want to pass the first two ints!). */
+ img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata);
+ memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data));
+ }
+
+ return img;
+}
+
+/**
+ * Generates an empty (black) thumbnail for given Main.
+ */
+void BKE_main_thumbnail_create(struct Main *bmain)
+{
+ MEM_SAFE_FREE(bmain->blen_thumb);
+
+ bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__);
+ bmain->blen_thumb->width = BLEN_THUMB_SIZE;
+ bmain->blen_thumb->height = BLEN_THUMB_SIZE;
+}
+
+/**
+ * Return filepath of given \a main.
+ */
+const char *BKE_main_blendfile_path(const Main *bmain)
+{
+ return bmain->name;
+}
+
+/**
+ * Return filepath of global main (G_MAIN).
+ *
+ * \warning Usage is not recommended, you should always try to get a valid Main pointer from context...
+ */
+const char *BKE_main_blendfile_path_from_global(void)
+{
+ return BKE_main_blendfile_path(G_MAIN);
+}
+
+/**
+ * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type.
+ */
+ListBase *which_libbase(Main *bmain, short type)
+{
+ switch ((ID_Type)type) {
+ case ID_SCE:
+ return &(bmain->scene);
+ case ID_LI:
+ return &(bmain->library);
+ case ID_OB:
+ return &(bmain->object);
+ case ID_ME:
+ return &(bmain->mesh);
+ case ID_CU:
+ return &(bmain->curve);
+ case ID_MB:
+ return &(bmain->mball);
+ case ID_MA:
+ return &(bmain->mat);
+ case ID_TE:
+ return &(bmain->tex);
+ case ID_IM:
+ return &(bmain->image);
+ case ID_LT:
+ return &(bmain->latt);
+ case ID_LA:
+ return &(bmain->lamp);
+ case ID_CA:
+ return &(bmain->camera);
+ case ID_IP:
+ return &(bmain->ipo);
+ case ID_KE:
+ return &(bmain->key);
+ case ID_WO:
+ return &(bmain->world);
+ case ID_SCR:
+ return &(bmain->screen);
+ case ID_VF:
+ return &(bmain->vfont);
+ case ID_TXT:
+ return &(bmain->text);
+ case ID_SPK:
+ return &(bmain->speaker);
+ case ID_LP:
+ return &(bmain->lightprobe);
+ case ID_SO:
+ return &(bmain->sound);
+ case ID_GR:
+ return &(bmain->collection);
+ case ID_AR:
+ return &(bmain->armature);
+ case ID_AC:
+ return &(bmain->action);
+ case ID_NT:
+ return &(bmain->nodetree);
+ case ID_BR:
+ return &(bmain->brush);
+ case ID_PA:
+ return &(bmain->particle);
+ case ID_WM:
+ return &(bmain->wm);
+ case ID_GD:
+ return &(bmain->gpencil);
+ case ID_MC:
+ return &(bmain->movieclip);
+ case ID_MSK:
+ return &(bmain->mask);
+ case ID_LS:
+ return &(bmain->linestyle);
+ case ID_PAL:
+ return &(bmain->palettes);
+ case ID_PC:
+ return &(bmain->paintcurves);
+ case ID_CF:
+ return &(bmain->cachefiles);
+ case ID_WS:
+ return &(bmain->workspaces);
+ }
+ return NULL;
+}
+
+/**
+ * puts into array *lb pointers to all the ListBase structs in main,
+ * and returns the number of them as the function result. This is useful for
+ * generic traversal of all the blocks in a Main (by traversing all the
+ * lists in turn), without worrying about block types.
+ *
+ * \note MAX_LIBARRAY define should match this code */
+int set_listbasepointers(Main *bmain, ListBase **lb)
+{
+ /* 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[INDEX_ID_LI] = &(bmain->library); /* Libraries may be accessed from pretty much any other ID... */
+ lb[INDEX_ID_IP] = &(bmain->ipo);
+ lb[INDEX_ID_AC] = &(bmain->action); /* moved here to avoid problems when freeing with animato (aligorith) */
+ lb[INDEX_ID_KE] = &(bmain->key);
+ lb[INDEX_ID_PAL] = &(bmain->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */
+ lb[INDEX_ID_GD] = &(bmain->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
+ lb[INDEX_ID_NT] = &(bmain->nodetree);
+ lb[INDEX_ID_IM] = &(bmain->image);
+ lb[INDEX_ID_TE] = &(bmain->tex);
+ lb[INDEX_ID_MA] = &(bmain->mat);
+ lb[INDEX_ID_VF] = &(bmain->vfont);
+
+ /* Important!: When adding a new object type,
+ * the specific data should be inserted here
+ */
+
+ lb[INDEX_ID_AR] = &(bmain->armature);
+
+ lb[INDEX_ID_CF] = &(bmain->cachefiles);
+ lb[INDEX_ID_ME] = &(bmain->mesh);
+ lb[INDEX_ID_CU] = &(bmain->curve);
+ lb[INDEX_ID_MB] = &(bmain->mball);
+
+ lb[INDEX_ID_LT] = &(bmain->latt);
+ lb[INDEX_ID_LA] = &(bmain->lamp);
+ lb[INDEX_ID_CA] = &(bmain->camera);
+
+ lb[INDEX_ID_TXT] = &(bmain->text);
+ lb[INDEX_ID_SO] = &(bmain->sound);
+ lb[INDEX_ID_GR] = &(bmain->collection);
+ lb[INDEX_ID_PAL] = &(bmain->palettes);
+ lb[INDEX_ID_PC] = &(bmain->paintcurves);
+ lb[INDEX_ID_BR] = &(bmain->brush);
+ lb[INDEX_ID_PA] = &(bmain->particle);
+ lb[INDEX_ID_SPK] = &(bmain->speaker);
+ lb[INDEX_ID_LP] = &(bmain->lightprobe);
+
+ lb[INDEX_ID_WO] = &(bmain->world);
+ lb[INDEX_ID_MC] = &(bmain->movieclip);
+ lb[INDEX_ID_SCR] = &(bmain->screen);
+ lb[INDEX_ID_OB] = &(bmain->object);
+ lb[INDEX_ID_LS] = &(bmain->linestyle); /* referenced by scenes */
+ lb[INDEX_ID_SCE] = &(bmain->scene);
+ lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */
+ lb[INDEX_ID_WM] = &(bmain->wm);
+ lb[INDEX_ID_MSK] = &(bmain->mask);
+
+ lb[INDEX_ID_NULL] = NULL;
+
+ return (MAX_LIBARRAY - 1);
+}
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index b5742dbdbb7..97058467fd9 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -51,7 +51,7 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
+
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mask.h"
@@ -61,6 +61,8 @@
#include "BKE_movieclip.h"
#include "BKE_image.h"
+#include "DEG_depsgraph_build.h"
+
static struct {
ListBase splines;
struct GHash *id_hash;
@@ -817,7 +819,7 @@ Mask *BKE_mask_new(Main *bmain, const char *name)
mask->sfra = 1;
mask->efra = 100;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
return mask;
}
@@ -1417,34 +1419,6 @@ void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe)
* for now re-evaluate all. eventually this might work differently */
void BKE_mask_update_display(Mask *mask, float ctime)
{
-#if 0
- MaskLayer *masklay;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- if (spline->points_deform) {
- int i = 0;
-
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point;
-
- if (spline->points_deform) {
- point = &spline->points_deform[i];
- BKE_mask_point_free(point);
- }
- }
- if (spline->points_deform) {
- MEM_freeN(spline->points_deform);
- }
-
- spline->points_deform = NULL;
- }
- }
- }
-#endif
-
BKE_mask_evaluate(mask, ctime, false);
}
@@ -1457,18 +1431,6 @@ void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const bool do_newfram
}
}
-void BKE_mask_update_scene(Main *bmain, Scene *scene)
-{
- Mask *mask;
-
- for (mask = bmain->mask.first; mask; mask = mask->id.next) {
- if (mask->id.recalc & ID_RECALC_ALL) {
- bool do_new_frame = (mask->id.recalc & ID_RECALC_DATA) != 0;
- BKE_mask_evaluate_all_masks(bmain, CFRA, do_new_frame);
- }
- }
-}
-
void BKE_mask_parent_init(MaskParent *parent)
{
parent->id_type = ID_MC;
@@ -1667,19 +1629,6 @@ MaskLayerShape *BKE_mask_layer_shape_verify_frame(MaskLayer *masklay, const int
BKE_mask_layer_shape_sort(masklay);
}
-#if 0
- {
- MaskLayerShape *masklay_shape;
- int i = 0;
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- printf("mask %d, %d\n", i++, masklay_shape->frame);
- }
- }
-#endif
-
return masklay_shape;
}
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index e2a9691e577..55939f8eadf 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -40,12 +40,13 @@
#include "BLI_math.h"
#include "DNA_mask_types.h"
+#include "DNA_object_types.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height)
{
@@ -897,24 +898,26 @@ void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime)
}
}
-void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask)
+void BKE_mask_eval_animation(struct Depsgraph *depsgraph, Mask *mask)
{
- DEG_debug_print_eval(__func__, mask->id.name, mask);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
for (MaskLayer *mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
{
- BKE_mask_layer_evaluate_animation(mask_layer, eval_ctx->ctime);
+ BKE_mask_layer_evaluate_animation(mask_layer, ctime);
}
}
-void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask)
+void BKE_mask_eval_update(struct Depsgraph *depsgraph, Mask *mask)
{
- DEG_debug_print_eval(__func__, mask->id.name, mask);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
for (MaskLayer *mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
{
- BKE_mask_layer_evaluate_deform(mask_layer, eval_ctx->ctime);
+ BKE_mask_layer_evaluate_deform(mask_layer, ctime);
}
}
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 2f2b82a00eb..ecdd30edc36 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -749,12 +749,6 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas
for (j = 0; j < tot_diff_feather_points; j++) {
copy_v2_v2(co_feather, diff_feather_points[j]);
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
-
- /* no need for these attrs */
-#if 0
- sf_vert->tmp.u = sf_vert_tot;
- sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
-#endif
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
}
@@ -1217,7 +1211,6 @@ static float maskrasterize_layer_z_depth_tri(const float pt[2],
}
#endif
-#if 1
static float maskrasterize_layer_z_depth_quad(const float pt[2],
const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
@@ -1226,7 +1219,6 @@ static float maskrasterize_layer_z_depth_quad(const float pt[2],
//return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]) + (v4[2] * w[3]);
return w[2] + w[3]; /* we can make this assumption for small speedup */
}
-#endif
static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], const float dist_orig, const float xy[2])
{
@@ -1247,10 +1239,8 @@ static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], cons
}
#else
/* we know all tris are close for now */
- if (1) {
- if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
- return 0.0f;
- }
+ if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
+ return 0.0f;
}
#endif
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 3414d08b8e7..6741ebf39d2 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -37,12 +37,13 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_customdata_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_ID.h"
#include "DNA_meta_types.h"
#include "DNA_node_types.h"
@@ -56,9 +57,10 @@
#include "BLI_array_utils.h"
#include "BKE_animsys.h"
+#include "BKE_brush.h"
#include "BKE_displist.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
+#include "BKE_gpencil.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
@@ -73,6 +75,9 @@
#include "BKE_editmesh.h"
#include "BKE_font.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "GPU_material.h"
/* used in UI and render */
@@ -87,16 +92,10 @@ void init_def_material(void)
/** Free (or release) any data used by this material (does not free the material itself). */
void BKE_material_free(Material *ma)
{
- int a;
-
BKE_animdata_free((ID *)ma, false);
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(ma->mtex[a]);
- }
-
- MEM_SAFE_FREE(ma->ramp_col);
- MEM_SAFE_FREE(ma->ramp_spec);
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
/* is no lib link block, but material extension */
if (ma->nodetree) {
@@ -107,105 +106,51 @@ void BKE_material_free(Material *ma)
MEM_SAFE_FREE(ma->texpaintslot);
- GPU_material_free(&ma->gpumaterial);
+ MEM_SAFE_FREE(ma->gp_style);
BKE_icon_id_delete((ID *)ma);
BKE_previewimg_free(&ma->preview);
}
+void BKE_material_init_gpencil_settings(Material *ma)
+{
+ if ((ma) && (ma->gp_style == NULL)) {
+ ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings");
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* set basic settings */
+ gp_style->stroke_rgba[3] = 1.0f;
+ gp_style->pattern_gridsize = 0.1f;
+ gp_style->gradient_radius = 0.5f;
+ ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
+ ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
+ gp_style->texture_opacity = 1.0f;
+ gp_style->texture_pixsize = 100.0f;
+
+ gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
+}
+
void BKE_material_init(Material *ma)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
- ma->r = ma->g = ma->b = ma->ref = 0.8;
+ ma->r = ma->g = ma->b = 0.8;
ma->specr = ma->specg = ma->specb = 1.0;
- ma->mirr = ma->mirg = ma->mirb = 1.0;
- ma->spectra = 1.0;
- ma->amb = 1.0;
- ma->alpha = 1.0;
- ma->spec = ma->hasize = 0.5;
- ma->har = 50;
- ma->starc = ma->ringc = 4;
- ma->linec = 12;
- ma->flarec = 1;
- ma->flaresize = ma->subsize = 1.0;
- ma->flareboost = 1;
- ma->seed2 = 6;
- ma->friction = 0.5;
- ma->refrac = 4.0;
- ma->roughness = 0.5;
- ma->param[0] = 0.5;
- ma->param[1] = 0.1;
- ma->param[2] = 0.5;
- ma->param[3] = 0.1;
- ma->rms = 0.1;
- ma->darkness = 1.0;
-
- ma->strand_sta = ma->strand_end = 1.0f;
-
- ma->ang = 1.0;
- ma->ray_depth = 2;
- ma->ray_depth_tra = 2;
- ma->fresnel_mir = 0.0;
- ma->fresnel_tra = 0.0;
- ma->fresnel_tra_i = 1.25;
- ma->fresnel_mir_i = 1.25;
- ma->tx_limit = 0.0;
- ma->tx_falloff = 1.0;
- ma->shad_alpha = 1.0f;
- ma->vcol_alpha = 0;
-
- ma->gloss_mir = ma->gloss_tra = 1.0;
- ma->samp_gloss_mir = ma->samp_gloss_tra = 18;
- ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005;
- ma->dist_mir = 0.0;
- ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
-
- ma->rampfac_col = 1.0;
- ma->rampfac_spec = 1.0;
+ // ma->alpha = 1.0; /* DEPRECATED */
+ ma->spec = 0.5;
+
+ ma->roughness = 0.25f;
+
ma->pr_lamp = 3; /* two lamps, is bits */
ma->pr_type = MA_SPHERE;
- ma->sss_radius[0] = 1.0f;
- ma->sss_radius[1] = 1.0f;
- ma->sss_radius[2] = 1.0f;
- ma->sss_col[0] = 1.0f;
- ma->sss_col[1] = 1.0f;
- ma->sss_col[2] = 1.0f;
- ma->sss_error = 0.05f;
- ma->sss_scale = 0.1f;
- ma->sss_ior = 1.3f;
- ma->sss_colfac = 1.0f;
- ma->sss_texfac = 0.0f;
- ma->sss_front = 1.0f;
- ma->sss_back = 1.0f;
-
- ma->vol.density = 1.0f;
- ma->vol.emission = 0.0f;
- ma->vol.scattering = 1.0f;
- ma->vol.reflection = 1.0f;
- ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f;
- ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f;
- ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f;
- ma->vol.density_scale = 1.0f;
- ma->vol.depth_cutoff = 0.01f;
- ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
- ma->vol.stepsize = 0.2f;
- ma->vol.shade_type = MA_VOL_SHADE_SHADED;
- ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
- ma->vol.precache_resolution = 50;
- ma->vol.ms_spread = 0.2f;
- ma->vol.ms_diff = 1.f;
- ma->vol.ms_intensity = 1.f;
-
- ma->game.flag = GEMAT_BACKCULL;
- ma->game.alpha_blend = 0;
- ma->game.face_orientation = 0;
-
- ma->mode = MA_TRACEBLE | MA_SHADBUF | MA_SHADOW | MA_RAYBIAS | MA_TANGENT_STR | MA_ZTRANSP;
- ma->mode2 = MA_CASTSHADOW;
- ma->shade_flag = MA_APPROX_OCCLUSION;
ma->preview = NULL;
+
+ ma->alpha_threshold = 0.5f;
+
}
Material *BKE_material_add(Main *bmain, const char *name)
@@ -219,6 +164,21 @@ Material *BKE_material_add(Main *bmain, const char *name)
return ma;
}
+Material *BKE_material_add_gpencil(Main *bmain, const char *name)
+{
+ Material *ma;
+
+ ma = BKE_material_add(bmain, name);
+
+ /* grease pencil settings */
+ if (ma != NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ BKE_brush_update_material(bmain, ma, NULL);
+ }
+ return ma;
+}
+
+
/**
* Only copy internal data of Material ID from source to already allocated/initialized destination.
* You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@@ -229,20 +189,6 @@ Material *BKE_material_add(Main *bmain, const char *name)
*/
void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma_src->mtex[a]) {
- ma_dst->mtex[a] = MEM_mallocN(sizeof(*ma_dst->mtex[a]), __func__);
- *ma_dst->mtex[a] = *ma_src->mtex[a];
- }
- }
-
- if (ma_src->ramp_col) {
- ma_dst->ramp_col = MEM_dupallocN(ma_src->ramp_col);
- }
- if (ma_src->ramp_spec) {
- ma_dst->ramp_spec = MEM_dupallocN(ma_src->ramp_spec);
- }
-
if (ma_src->nodetree) {
/* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
* (see BKE_libblock_copy_ex()). */
@@ -260,7 +206,13 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr
ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot);
}
+ if (ma_src->gp_style != NULL) {
+ ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style);
+ }
+
BLI_listbase_clear(&ma_dst->gpumaterial);
+
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
}
Material *BKE_material_copy(Main *bmain, const Material *ma)
@@ -283,30 +235,25 @@ Material *BKE_material_localize(Material *ma)
*
* NOTE: Only possible once nested node trees are fully converted to that too. */
- Material *man;
- int a;
-
- man = BKE_libblock_copy_nolib(&ma->id, false);
-
- /* no increment for texture ID users, in previewrender.c it prevents decrement */
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- man->mtex[a] = MEM_mallocN(sizeof(MTex), "copymaterial");
- memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex));
- }
- }
-
- if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col);
- if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec);
+ Material *man = BKE_libblock_copy_nolib(&ma->id, false);
man->texpaintslot = NULL;
man->preview = NULL;
- if (ma->nodetree)
+ if (ma->nodetree != NULL) {
man->nodetree = ntreeLocalize(ma->nodetree);
+ }
+
+ if (ma->gp_style != NULL) {
+ man->gp_style = MEM_dupallocN(ma->gp_style);
+ }
BLI_listbase_clear(&man->gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
+
+ man->id.tag |= LIB_TAG_LOCALIZED;
+
return man;
}
@@ -320,6 +267,7 @@ Material ***give_matarar(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
+ bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@@ -333,6 +281,10 @@ Material ***give_matarar(Object *ob)
mb = ob->data;
return &(mb->mat);
}
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->mat);
+ }
return NULL;
}
@@ -341,6 +293,7 @@ short *give_totcolp(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
+ bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@@ -354,6 +307,10 @@ short *give_totcolp(Object *ob)
mb = ob->data;
return &(mb->totcol);
}
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->totcol);
+ }
return NULL;
}
@@ -370,6 +327,8 @@ Material ***give_matarar_id(ID *id)
return &(((Curve *)id)->mat);
case ID_MB:
return &(((MetaBall *)id)->mat);
+ case ID_GD:
+ return &(((bGPdata *)id)->mat);
default:
break;
}
@@ -388,6 +347,8 @@ short *give_totcolp_id(ID *id)
return &(((Curve *)id)->totcol);
case ID_MB:
return &(((MetaBall *)id)->totcol);
+ case ID_GD:
+ return &(((bGPdata *)id)->totcol);
default:
break;
}
@@ -409,6 +370,9 @@ static void material_data_index_remove_id(ID *id, short index)
case ID_MB:
/* meta-elems don't have materials atm */
break;
+ case ID_GD:
+ BKE_gpencil_material_index_remove((bGPdata *)id, index);
+ break;
default:
break;
}
@@ -461,7 +425,8 @@ void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user)
}
*totcolp = totcol;
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
@@ -478,7 +443,9 @@ void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
id_us_plus((ID *)ma);
test_all_objects_materials(bmain, id);
- DAG_relations_tag_update(bmain);
+
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -512,7 +479,8 @@ Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data
material_data_index_remove_id(id, index);
}
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -539,7 +507,8 @@ void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
material_data_index_clear_id(id);
}
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -584,6 +553,21 @@ Material *give_current_material(Object *ob, short act)
return ma;
}
+MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
+{
+ Material *ma = give_current_material(ob, act);
+ if (ma != NULL) {
+ if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ }
+
+ return ma->gp_style;
+ }
+ else {
+ return NULL;
+ }
+}
+
Material *give_node_material(Material *ma)
{
if (ma && ma->use_nodes && ma->nodetree) {
@@ -634,7 +618,8 @@ void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, boo
if (ob->totcol && ob->actcol == 0) ob->actcol = 1;
if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_GEOMETRY);
+ DEG_relations_tag_update(bmain);
}
void test_object_materials(Main *bmain, Object *ob, ID *id)
@@ -676,14 +661,6 @@ void assign_material_id(Main *bmain, ID *id, Material *ma, short act)
if (act > MAXMAT) return;
if (act < 1) act = 1;
- /* this is needed for Python overrides,
- * we just have to take care that the UI can't do this */
-#if 0
- /* prevent crashing when using accidentally */
- BLI_assert(id->lib == NULL);
- if (id->lib) return;
-#endif
-
/* test arraylens */
totcolp = give_totcolp_id(id);
@@ -823,6 +800,9 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap)
else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_curve_material_remap(ob->data, remap, ob->totcol);
}
+ else if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_material_remap(ob->data, remap, ob->totcol);
+ }
else {
/* add support for this object data! */
BLI_assert(matar == NULL);
@@ -939,278 +919,8 @@ bool BKE_object_material_slot_add(Main *bmain, Object *ob)
return true;
}
-static void do_init_render_material(Main *bmain, Material *ma, int r_mode, float *amb)
-{
- MTex *mtex;
- int a, needuv = 0, needtang = 0;
-
- if (ma->flarec == 0) ma->flarec = 1;
-
- /* add all texcoflags from mtex, texco and mapto were cleared in advance */
- for (a = 0; a < MAX_MTEX; a++) {
-
- /* separate tex switching */
- if (ma->septex & (1 << a)) continue;
-
- mtex = ma->mtex[a];
- if (mtex && mtex->tex && (mtex->tex->type | (mtex->tex->use_nodes && mtex->tex->nodetree) )) {
-
- ma->texco |= mtex->texco;
- ma->mapto |= mtex->mapto;
-
- /* always get derivatives for these textures */
- if (ELEM(mtex->tex->type, TEX_IMAGE, TEX_ENVMAP)) ma->texco |= TEXCO_OSA;
- else if (mtex->texflag & (MTEX_COMPAT_BUMP | MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) ma->texco |= TEXCO_OSA;
-
- if (ma->texco & (TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM | TEXCO_STRAND | TEXCO_STRESS)) needuv = 1;
- else if (ma->texco & (TEXCO_GLOB | TEXCO_UV | TEXCO_OBJECT | TEXCO_SPEED)) needuv = 1;
- else if (ma->texco & (TEXCO_LAVECTOR | TEXCO_VIEW)) needuv = 1;
-
- if ((ma->mapto & MAP_NORM) && (mtex->normapspace == MTEX_NSPACE_TANGENT))
- needtang = 1;
- }
- }
-
- if (needtang) ma->mode |= MA_NORMAP_TANG;
- else ma->mode &= ~MA_NORMAP_TANG;
-
- if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) {
- needuv = 1;
- if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */
- }
- if (needuv) ma->texco |= NEED_UV;
-
- /* since the raytracer doesnt recalc O structs for each ray, we have to preset them all */
- if (r_mode & R_RAYTRACE) {
- if ((ma->mode & (MA_RAYMIRROR | MA_SHADOW_TRA)) || ((ma->mode & MA_TRANSP) && (ma->mode & MA_RAYTRANSP))) {
- ma->texco |= NEED_UV | TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM;
- if (r_mode & R_OSA) ma->texco |= TEXCO_OSA;
- }
- }
-
- if (amb) {
- ma->ambr = ma->amb * amb[0];
- ma->ambg = ma->amb * amb[1];
- ma->ambb = ma->amb * amb[2];
- }
-
- /* local group override */
- if ((ma->shade_flag & MA_GROUP_LOCAL) && ma->id.lib && ma->group && ma->group->id.lib) {
- Group *group;
-
- for (group = bmain->group.first; group; group = group->id.next) {
- if (!ID_IS_LINKED(group) && STREQ(group->id.name, ma->group->id.name)) {
- ma->group = group;
- }
- }
- }
-}
-
-static void init_render_nodetree(Main *bmain, bNodeTree *ntree, Material *basemat, int r_mode, float *amb)
-{
- bNode *node;
-
- /* parses the geom+tex nodes */
- ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- Material *ma = (Material *)node->id;
- if (ma != basemat) {
- do_init_render_material(bmain, ma, r_mode, amb);
- basemat->texco |= ma->texco;
- }
-
- basemat->mode_l |= ma->mode & ~(MA_MODE_PIPELINE | MA_SHLESS);
- basemat->mode2_l |= ma->mode2 & ~MA_MODE2_PIPELINE;
- /* basemat only considered shadeless if all node materials are too */
- if (!(ma->mode & MA_SHLESS))
- basemat->mode_l &= ~MA_SHLESS;
-
- if (ma->strand_surfnor > 0.0f)
- basemat->mode_l |= MA_STR_SURFDIFF;
- }
- else if (node->type == NODE_GROUP)
- init_render_nodetree(bmain, (bNodeTree *)node->id, basemat, r_mode, amb);
- }
- else if (node->typeinfo->type == SH_NODE_NORMAL_MAP) {
- basemat->mode2_l |= MA_TANGENT_CONCRETE;
- NodeShaderNormalMap *nm = node->storage;
- bool taken_into_account = false;
- for (int i = 0; i < basemat->nmap_tangent_names_count; i++) {
- if (STREQ(basemat->nmap_tangent_names[i], nm->uv_map)) {
- taken_into_account = true;
- break;
- }
- }
- if (!taken_into_account) {
- BLI_assert(basemat->nmap_tangent_names_count < MAX_MTFACE + 1);
- strcpy(basemat->nmap_tangent_names[basemat->nmap_tangent_names_count++], nm->uv_map);
- }
- }
- }
-}
-
-void init_render_material(Main *bmain, Material *mat, int r_mode, float *amb)
-{
-
- do_init_render_material(bmain, mat, r_mode, amb);
-
- if (mat->nodetree && mat->use_nodes) {
- /* mode_l will take the pipeline options from the main material, and the or-ed
- * result of non-pipeline options from the nodes. shadeless is an exception,
- * mode_l will have it set when all node materials are shadeless. */
- mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS;
- mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE;
- mat->nmap_tangent_names_count = 0;
- init_render_nodetree(bmain, mat->nodetree, mat, r_mode, amb);
-
- if (!mat->nodetree->execdata)
- mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree);
- }
- else {
- mat->mode_l = mat->mode;
- mat->mode2_l = mat->mode2;
-
- if (mat->strand_surfnor > 0.0f)
- mat->mode_l |= MA_STR_SURFDIFF;
- }
-}
-
-void init_render_materials(Main *bmain, int r_mode, float *amb, bool do_default_material)
-{
- Material *ma;
-
- /* clear these flags before going over materials, to make sure they
- * are cleared only once, otherwise node materials contained in other
- * node materials can go wrong */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->id.us) {
- ma->texco = 0;
- ma->mapto = 0;
- }
- }
-
- /* two steps, first initialize, then or the flags for layers */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- /* is_used flag comes back in convertblender.c */
- ma->flag &= ~MA_IS_USED;
- if (ma->id.us)
- init_render_material(bmain, ma, r_mode, amb);
- }
-
- if (do_default_material) {
- init_render_material(bmain, &defmaterial, r_mode, amb);
- }
-}
-
-/* only needed for nodes now */
-void end_render_material(Material *mat)
-{
- if (mat && mat->nodetree && mat->use_nodes) {
- if (mat->nodetree->execdata)
- ntreeShaderEndExecTree(mat->nodetree->execdata);
- }
-}
-
-void end_render_materials(Main *bmain)
-{
- Material *ma;
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->id.us)
- end_render_material(ma);
-}
-
-static bool material_in_nodetree(bNodeTree *ntree, Material *mat)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- if (node->id == (ID *)mat) {
- return true;
- }
- }
- else if (node->type == NODE_GROUP) {
- if (material_in_nodetree((bNodeTree *)node->id, mat)) {
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-bool material_in_material(Material *parmat, Material *mat)
-{
- if (parmat == mat)
- return true;
- else if (parmat->nodetree && parmat->use_nodes)
- return material_in_nodetree(parmat->nodetree, mat);
- else
- return false;
-}
-
-
/* ****************** */
-/* Update drivers for materials in a nodetree */
-static void material_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime)
-{
- bNode *node;
-
- /* nodetree itself */
- if (ntree->adt && ntree->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- material_drivers_update(scene, (Material *)node->id, ctime);
- }
- else if (node->type == NODE_GROUP) {
- material_node_drivers_update(scene, (bNodeTree *)node->id, ctime);
- }
- }
- }
-}
-
-/* Calculate all drivers for materials
- * FIXME: this is really a terrible method which may result in some things being calculated
- * multiple times. However, without proper despgraph support for these things, we are forced
- * into this sort of thing...
- */
-void material_drivers_update(Scene *scene, Material *ma, float ctime)
-{
- //if (G.f & G_DEBUG)
- // printf("material_drivers_update(%s, %s)\n", scene->id.name, ma->id.name);
-
- /* Prevent infinite recursion by checking (and tagging the material) as having been visited already
- * (see BKE_scene_update_tagged()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else
- * in the meantime... [#32017]
- */
- if (ma->id.tag & LIB_TAG_DOIT)
- return;
-
- ma->id.tag |= LIB_TAG_DOIT;
-
- /* material itself */
- if (ma->adt && ma->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &ma->id, ma->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- if (ma->nodetree) {
- material_node_drivers_update(scene, ma->nodetree, ctime);
- }
-
- ma->id.tag &= ~LIB_TAG_DOIT;
-}
-
bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
{
Material *mao, ***matarar;
@@ -1290,23 +1000,16 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
}
/* check indices from mesh */
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
material_data_index_remove_id((ID *)ob->data, actcol - 1);
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
}
}
return true;
}
-static bool get_mtex_slot_valid_texpaint(struct MTex *mtex)
-{
- return (mtex && (mtex->texco == TEXCO_UV) &&
- mtex->tex && (mtex->tex->type == TEX_IMAGE) &&
- mtex->tex->ima);
-}
-
static bNode *nodetree_uv_node_recursive(bNode *node)
{
bNode *inode;
@@ -1327,14 +1030,58 @@ static bNode *nodetree_uv_node_recursive(bNode *node)
return NULL;
}
-void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
+static int count_texture_nodes_recursive(bNodeTree *nodetree)
+{
+ int tex_nodes = 0;
+
+ for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ tex_nodes++;
+ }
+ else if (node->type == NODE_GROUP) {
+ /* recurse into the node group and see if it contains any textures */
+ tex_nodes += count_texture_nodes_recursive((bNodeTree *)node->id);
+ }
+ }
+
+ return tex_nodes;
+}
+
+static void fill_texpaint_slots_recursive(bNodeTree *nodetree, bNode *active_node, Material *ma, int *index)
{
- MTex **mtex;
- short count = 0;
- short index = 0, i;
+ for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ if (active_node == node) {
+ ma->paint_active_slot = *index;
+ }
+ ma->texpaintslot[*index].ima = (Image *)node->id;
- bool use_nodes = BKE_scene_use_new_shading_nodes(scene);
- bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene);
+ /* for new renderer, we need to traverse the treeback in search of a UV node */
+ bNode *uvnode = nodetree_uv_node_recursive(node);
+
+ if (uvnode) {
+ NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
+ ma->texpaintslot[*index].uvname = storage->uv_map;
+ /* set a value to index so UI knows that we have a valid pointer for the mesh */
+ ma->texpaintslot[*index].valid = true;
+ }
+ else {
+ /* just invalidate the index here so UV map does not get displayed on the UI */
+ ma->texpaintslot[*index].valid = false;
+ }
+ (*index)++;
+ }
+ else if (node->type == NODE_GROUP) {
+ /* recurse into the node group and see if it contains any textures */
+ fill_texpaint_slots_recursive((bNodeTree *)node->id, active_node, ma, index);
+ }
+ }
+}
+
+void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
+{
+ int count = 0;
+ int index = 0;
if (!ma)
return;
@@ -1351,88 +1098,25 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
return;
}
- if (use_nodes || ma->use_nodes) {
- bNode *node, *active_node;
-
- if (!(ma->nodetree)) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
-
- for (node = ma->nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id)
- count++;
- }
-
- if (count == 0) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
- ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
-
- active_node = nodeGetActiveTexture(ma->nodetree);
-
- for (node = ma->nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
- if (active_node == node)
- ma->paint_active_slot = index;
- ma->texpaintslot[index].ima = (Image *)node->id;
-
- /* for new renderer, we need to traverse the treeback in search of a UV node */
- if (use_nodes) {
- bNode *uvnode = nodetree_uv_node_recursive(node);
-
- if (uvnode) {
- NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
- ma->texpaintslot[index].uvname = storage->uv_map;
- /* set a value to index so UI knows that we have a valid pointer for the mesh */
- ma->texpaintslot[index].index = 0;
- }
- else {
- /* just invalidate the index here so UV map does not get displayed on the UI */
- ma->texpaintslot[index].index = -1;
- }
- }
- else {
- ma->texpaintslot[index].index = -1;
- }
- index++;
- }
- }
+ if (!(ma->nodetree)) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
}
- else if (is_bi) {
- for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
- if (get_mtex_slot_valid_texpaint(*mtex)) {
- count++;
- }
- }
-
- if (count == 0) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
-
- ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
- for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
- if (get_mtex_slot_valid_texpaint(*mtex)) {
- ma->texpaintslot[index].ima = (*mtex)->tex->ima;
- ma->texpaintslot[index].uvname = (*mtex)->uvname;
- ma->texpaintslot[index].index = i;
+ count = count_texture_nodes_recursive(ma->nodetree);
- index++;
- }
- }
- }
- else {
+ if (count == 0) {
ma->paint_active_slot = 0;
ma->paint_clone_slot = 0;
return;
}
+ ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+
+ bNode *active_node = nodeGetActiveTexture(ma->nodetree);
+
+ fill_texpaint_slots_recursive(ma->nodetree, active_node, ma, &index);
ma->tot_slots = count;
@@ -1688,21 +1372,6 @@ void clear_matcopybuf(void)
void free_matcopybuf(void)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (matcopybuf.mtex[a]) {
- MEM_freeN(matcopybuf.mtex[a]);
- matcopybuf.mtex[a] = NULL;
- }
- }
-
- if (matcopybuf.ramp_col) MEM_freeN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) MEM_freeN(matcopybuf.ramp_spec);
-
- matcopybuf.ramp_col = NULL;
- matcopybuf.ramp_spec = NULL;
-
if (matcopybuf.nodetree) {
ntreeFreeTree(matcopybuf.nodetree);
MEM_freeN(matcopybuf.nodetree);
@@ -1714,574 +1383,42 @@ void free_matcopybuf(void)
void copy_matcopybuf(Main *bmain, Material *ma)
{
- int a;
- MTex *mtex;
-
if (matcopied)
free_matcopybuf();
memcpy(&matcopybuf, ma, sizeof(Material));
- if (matcopybuf.ramp_col) matcopybuf.ramp_col = MEM_dupallocN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) matcopybuf.ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = matcopybuf.mtex[a];
- if (mtex) {
- matcopybuf.mtex[a] = MEM_dupallocN(mtex);
- }
- }
matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false);
matcopybuf.preview = NULL;
BLI_listbase_clear(&matcopybuf.gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
matcopied = 1;
}
void paste_matcopybuf(Main *bmain, Material *ma)
{
- int a;
- MTex *mtex;
ID id;
if (matcopied == 0)
return;
- /* free current mat */
- if (ma->ramp_col) MEM_freeN(ma->ramp_col);
- if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
- }
+
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
if (ma->nodetree) {
ntreeFreeTree(ma->nodetree);
MEM_freeN(ma->nodetree);
}
- GPU_material_free(&ma->gpumaterial);
-
id = (ma->id);
memcpy(ma, &matcopybuf, sizeof(Material));
(ma->id) = id;
- if (matcopybuf.ramp_col) ma->ramp_col = MEM_dupallocN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) ma->ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec);
-
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (mtex) {
- ma->mtex[a] = MEM_dupallocN(mtex);
- if (mtex->tex) {
- /* first check this is in main (we may have loaded another file) [#35500] */
- if (BLI_findindex(&bmain->tex, mtex->tex) != -1) {
- id_us_plus((ID *)mtex->tex);
- }
- else {
- ma->mtex[a]->tex = NULL;
- }
- }
- }
- }
-
ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false);
}
-
-/*********************** texface to material convert functions **********************/
-/* encode all the TF information into a single int */
-static int encode_tfaceflag(MTFace *tf, int convertall)
-{
- /* calculate the flag */
- int flag = tf->mode;
-
- /* options that change the material offline render */
- if (!convertall) {
- flag &= ~TF_OBCOL;
- }
-
- /* clean flags that are not being converted */
- flag &= ~TF_TEX;
- flag &= ~TF_SHAREDVERT;
- flag &= ~TF_SHAREDCOL;
- flag &= ~TF_CONVERTED;
-
- /* light tface flag is ignored in GLSL mode */
- flag &= ~TF_LIGHT;
-
- /* 15 is how big the flag can be - hardcoded here and in decode_tfaceflag() */
- flag |= tf->transp << 15;
-
- /* increase 1 so flag 0 is different than no flag yet */
- return flag + 1;
-}
-
-/* set the material options based in the tface flag */
-static void decode_tfaceflag(Material *ma, int flag, int convertall)
-{
- int alphablend;
- GameSettings *game = &ma->game;
-
- /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
- flag -= 1;
-
- alphablend = flag >> 15; /* encoded in the encode_tfaceflag function */
- (*game).flag = 0;
-
- /* General Material Options */
- if ((flag & TF_DYNAMIC) == 0) (*game).flag |= GEMAT_NOPHYSICS;
-
- /* Material Offline Rendering Properties */
- if (convertall) {
- if (flag & TF_OBCOL) ma->shade_flag |= MA_OBCOLOR;
- }
-
- /* Special Face Properties */
- if ((flag & TF_TWOSIDE) == 0) (*game).flag |= GEMAT_BACKCULL;
- if (flag & TF_INVISIBLE) (*game).flag |= GEMAT_INVISIBLE;
- if (flag & TF_BMFONT) (*game).flag |= GEMAT_TEXT;
-
- /* Face Orientation */
- if (flag & TF_BILLBOARD) (*game).face_orientation |= GEMAT_HALO;
- else if (flag & TF_BILLBOARD2) (*game).face_orientation |= GEMAT_BILLBOARD;
- else if (flag & TF_SHADOW) (*game).face_orientation |= GEMAT_SHADOW;
-
- /* Alpha Blend */
- if (flag & TF_ALPHASORT && ELEM(alphablend, TF_ALPHA, TF_ADD)) (*game).alpha_blend = GEMAT_ALPHA_SORT;
- else if (alphablend & TF_ALPHA) (*game).alpha_blend = GEMAT_ALPHA;
- else if (alphablend & TF_ADD) (*game).alpha_blend = GEMAT_ADD;
- else if (alphablend & TF_CLIP) (*game).alpha_blend = GEMAT_CLIP;
-}
-
-/* boolean check to see if the mesh needs a material */
-static int check_tfaceneedmaterial(int flag)
-{
- /* check if the flags we have are not deprecated != than default material options
- * also if only flags are visible and collision see if all objects using this mesh have this option in physics */
-
- /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
- flag -= 1;
-
- /* deprecated flags */
- flag &= ~TF_OBCOL;
- flag &= ~TF_SHAREDVERT;
- flag &= ~TF_SHAREDCOL;
-
- /* light tface flag is ignored in GLSL mode */
- flag &= ~TF_LIGHT;
-
- /* automatic detected if tex image has alpha */
- flag &= ~(TF_ALPHA << 15);
- /* automatic detected if using texture */
- flag &= ~TF_TEX;
-
- /* settings for the default NoMaterial */
- if (flag == TF_DYNAMIC)
- return 0;
-
- else
- return 1;
-}
-
-/* return number of digits of an integer */
-/* XXX to be optmized or replaced by an equivalent blender internal function */
-static int integer_getdigits(int number)
-{
- int i = 0;
- if (number == 0) return 1;
-
- while (number != 0) {
- number = (int)(number / 10);
- i++;
- }
- return i;
-}
-
-static void calculate_tface_materialname(char *matname, char *newname, int flag)
-{
- /* if flag has only light and collision and material matches those values
- * you can do strcpy(name, mat_name);
- * otherwise do: */
- int digits = integer_getdigits(flag);
- /* clamp the old name, remove the MA prefix and add the .TF.flag suffix
- * e.g. matname = "MALoooooooooooooongName"; newname = "Loooooooooooooon.TF.2" */
- BLI_snprintf(newname, MAX_ID_NAME, "%.*s.TF.%0*d", MAX_ID_NAME - (digits + 5), matname, digits, flag);
-}
-
-/* returns -1 if no match */
-static short mesh_getmaterialnumber(Mesh *me, Material *ma)
-{
- short a;
-
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a] == ma) {
- return a;
- }
- }
-
- return -1;
-}
-
-/* append material */
-static short mesh_addmaterial(Main *bmain, Mesh *me, Material *ma)
-{
- BKE_material_append_id(bmain, &me->id, NULL);
- me->mat[me->totcol - 1] = ma;
-
- id_us_plus(&ma->id);
-
- return me->totcol - 1;
-}
-
-static void set_facetexture_flags(Material *ma, Image *image)
-{
- if (image) {
- ma->mode |= MA_FACETEXTURE;
- /* we could check if the texture has alpha, but then more meshes sharing the same
- * material may need it. Let's make it simple. */
- if (BKE_image_has_alpha(image))
- ma->mode |= MA_FACETEXTURE_ALPHA;
- }
-}
-
-/* returns material number */
-static short convert_tfacenomaterial(Main *bmain, Mesh *me, MTFace *tf, int flag)
-{
- Material *ma;
- char idname[MAX_ID_NAME];
- short mat_nr = -1;
-
- /* new material, the name uses the flag*/
- BLI_snprintf(idname, sizeof(idname), "MAMaterial.TF.%0*d", integer_getdigits(flag), flag);
-
- if ((ma = BLI_findstring(&bmain->mat, idname + 2, offsetof(ID, name) + 2))) {
- mat_nr = mesh_getmaterialnumber(me, ma);
- /* assign the material to the mesh */
- if (mat_nr == -1) mat_nr = mesh_addmaterial(bmain, me, ma);
-
- /* if needed set "Face Textures [Alpha]" Material options */
- set_facetexture_flags(ma, tf->tpage);
- }
- /* create a new material */
- else {
- ma = BKE_material_add(bmain, idname + 2);
-
- if (ma) {
- printf("TexFace Convert: Material \"%s\" created.\n", idname + 2);
- mat_nr = mesh_addmaterial(bmain, me, ma);
-
- /* if needed set "Face Textures [Alpha]" Material options */
- set_facetexture_flags(ma, tf->tpage);
-
- decode_tfaceflag(ma, flag, 1);
- /* the final decoding will happen after, outside the main loop
- * for now store the flag into the material and change light/tex/collision
- * store the flag as a negative number */
- ma->game.flag = -flag;
- id_us_min((ID *)ma);
- }
- else {
- printf("Error: Unable to create Material \"%s\" for Mesh \"%s\".", idname + 2, me->id.name + 2);
- }
- }
-
- /* set as converted, no need to go bad to this face */
- tf->mode |= TF_CONVERTED;
- return mat_nr;
-}
-
-/* Function to fully convert materials */
-static void convert_tfacematerial(Main *bmain, Material *ma)
-{
- Mesh *me;
- Material *mat_new;
- MFace *mf;
- MTFace *tf;
- int flag, index;
- int a;
- short mat_nr;
- CustomDataLayer *cdl;
- char idname[MAX_ID_NAME];
-
- for (me = bmain->mesh.first; me; me = me->id.next) {
- /* check if this mesh uses this material */
- for (a = 0; a < me->totcol; a++)
- if (me->mat[a] == ma) break;
-
- /* no material found */
- if (a == me->totcol) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- /* loop over all the faces and stop at the ones that use the material*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (me->mat[mf->mat_nr] != ma) continue;
-
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- flag = encode_tfaceflag(tf, 1);
-
- /* the name of the new material */
- calculate_tface_materialname(ma->id.name, (char *)&idname, flag);
-
- if ((mat_new = BLI_findstring(&bmain->mat, idname + 2, offsetof(ID, name) + 2))) {
- /* material already existent, see if the mesh has it */
- mat_nr = mesh_getmaterialnumber(me, mat_new);
- /* material is not in the mesh, add it */
- if (mat_nr == -1) mat_nr = mesh_addmaterial(bmain, me, mat_new);
- }
- /* create a new material */
- else {
- mat_new = BKE_material_copy(bmain, ma);
- if (mat_new) {
- /* rename the material*/
- BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name));
- id_us_min((ID *)mat_new);
-
- mat_nr = mesh_addmaterial(bmain, me, mat_new);
- decode_tfaceflag(mat_new, flag, 1);
- }
- else {
- printf("Error: Unable to create Material \"%s\" for Mesh \"%s.", idname + 2, me->id.name + 2);
- mat_nr = mf->mat_nr;
- continue;
- }
- }
-
- /* if the material has a texture but no texture channel
- * set "Face Textures [Alpha]" Material options
- * actually we need to run it always, because of old behavior
- * of using face texture if any texture channel was present (multitex) */
- //if ((!mat_new->mtex[0]) && (!mat_new->mtex[0]->tex))
- set_facetexture_flags(mat_new, tf->tpage);
-
- /* set the material number to the face*/
- mf->mat_nr = mat_nr;
- }
- /* remove material from mesh */
- for (a = 0; a < me->totcol; ) {
- if (me->mat[a] == ma) {
- BKE_material_pop_id(bmain, &me->id, a, true);
- }
- else {
- a++;
- }
- }
- }
-}
-
-
-#define MAT_BGE_DISPUTED -99999
-
-int do_version_tface(Main *main)
+void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)
{
- Mesh *me;
- Material *ma;
- MFace *mf;
- MTFace *tf;
- CustomDataLayer *cdl;
- int a;
- int flag;
- int index;
-
- /* Operator in help menu has been removed for 2.7x */
- int fileload = 1;
-
- /* sometimes mesh has no materials but will need a new one. In those
- * cases we need to ignore the mf->mat_nr and only look at the face
- * mode because it can be zero as uninitialized or the 1st created material
- */
- int nomaterialslots;
-
- /* alert to user to check the console */
- int nowarning = 1;
-
- /* mark all the materials to conversion with a flag
- * if there is tface create a complete flag for that storing in flag
- * if there is tface and flag > 0: creates a new flag based on this face
- * if flags are different set flag to -1
- */
-
- /* 1st part: marking mesh materials to update */
- for (me = main->mesh.first; me; me = me->id.next) {
- if (ID_IS_LINKED(me)) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- nomaterialslots = (me->totcol == 0 ? 1 : 0);
-
- /* loop over all the faces*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
-
- /* conversion should happen only once */
- if (fileload)
- tf->mode &= ~TF_CONVERTED;
- else {
- if ((tf->mode & TF_CONVERTED)) continue;
- else tf->mode |= TF_CONVERTED;
- }
-
- /* no material slots */
- if (nomaterialslots) {
- flag = encode_tfaceflag(tf, 1);
-
- /* create/find a new material and assign to the face */
- if (check_tfaceneedmaterial(flag)) {
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag);
- }
- /* else mark them as no-material to be reverted to 0 later */
- else {
- mf->mat_nr = -1;
- }
- }
- else if (mf->mat_nr < me->totcol) {
- ma = me->mat[mf->mat_nr];
-
- /* no material create one if necessary */
- if (!ma) {
- /* find a new material and assign to the face */
- flag = encode_tfaceflag(tf, 1);
-
- /* create/find a new material and assign to the face */
- if (check_tfaceneedmaterial(flag))
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag);
-
- continue;
- }
-
- /* we can't read from this if it comes from a library,
- * at doversion time: direct_link might not have happened on it,
- * so ma->mtex is not pointing to valid memory yet.
- * later we could, but it's better not */
- else if (ID_IS_LINKED(ma))
- continue;
-
- /* material already marked as disputed */
- else if (ma->game.flag == MAT_BGE_DISPUTED)
- continue;
-
- /* found a material */
- else {
- flag = encode_tfaceflag(tf, ((fileload) ? 0 : 1));
-
- /* first time changing this material */
- if (ma->game.flag == 0)
- ma->game.flag = -flag;
-
- /* mark material as disputed */
- else if (ma->game.flag != -flag) {
- ma->game.flag = MAT_BGE_DISPUTED;
- continue;
- }
-
- /* material ok so far */
- else {
- ma->game.flag = -flag;
-
- /* some people uses multitexture with TexFace by creating a texture
- * channel which not necessarily the tf->tpage image. But the game engine
- * was enabling it. Now it's required to set "Face Texture [Alpha] in the
- * material settings. */
- if (!fileload)
- set_facetexture_flags(ma, tf->tpage);
- }
- }
- }
- else {
- continue;
- }
- }
-
- /* if we didn't have material slot and now we do, we need to
- * make sure the materials are correct */
- if (nomaterialslots) {
- if (me->totcol > 0) {
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (mf->mat_nr == -1) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, encode_tfaceflag(tf, 1));
- }
- }
- }
- else {
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- mf->mat_nr = 0;
- }
- }
- }
-
- }
-
- /* 2nd part - conversion */
- /* skip library files */
-
- /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */
- for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) {
- if (ID_IS_LINKED(ma)) continue;
-
- /* disputed material */
- if (ma->game.flag == MAT_BGE_DISPUTED) {
- ma->game.flag = 0;
- if (fileload) {
- printf("Warning: material \"%s\" skipped.\n", ma->id.name + 2);
- nowarning = 0;
- }
- else {
- convert_tfacematerial(main, ma);
- }
- continue;
- }
-
- /* no conflicts in this material - 90% of cases
- * convert from tface system to material */
- else if (ma->game.flag < 0) {
- decode_tfaceflag(ma, -(ma->game.flag), 1);
-
- /* material is good make sure all faces using
- * this material are set to converted */
- if (fileload) {
- for (me = main->mesh.first; me; me = me->id.next) {
- /* check if this mesh uses this material */
- for (a = 0; a < me->totcol; a++)
- if (me->mat[a] == ma) break;
-
- /* no material found */
- if (a == me->totcol) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- /* loop over all the faces and stop at the ones that use the material*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (me->mat[mf->mat_nr] == ma) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- tf->mode |= TF_CONVERTED;
- }
- }
- }
- }
- }
- /* material is not used by faces with texface
- * set the default flag - do it only once */
- else {
- if (fileload) {
- ma->game.flag = GEMAT_BACKCULL;
- }
- }
- }
-
- return nowarning;
+ DEG_debug_print_eval(depsgraph, __func__, material->id.name, material);
+ GPU_material_free(&material->gpumaterial);
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 9e926e5ef53..63adcfc3cae 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -57,7 +57,6 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -74,6 +73,8 @@ void BKE_mball_free(MetaBall *mb)
{
BKE_animdata_free((ID *)mb, false);
+ BKE_mball_batch_cache_free(mb);
+
MEM_SAFE_FREE(mb->mat);
BLI_freelistN(&mb->elems);
@@ -119,6 +120,7 @@ void BKE_mball_copy_data(Main *UNUSED(bmain), MetaBall *mb_dst, const MetaBall *
mb_dst->editelems = NULL;
mb_dst->lastelem = NULL;
+ mb_dst->batch_cache = NULL;
}
MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb)
@@ -203,7 +205,7 @@ void BKE_mball_texspace_calc(Object *ob)
(min)[0] = (min)[1] = (min)[2] = 1.0e30f;
(max)[0] = (max)[1] = (max)[2] = -1.0e30f;
- dl = ob->curve_cache->disp.first;
+ dl = ob->runtime.curve_cache->disp.first;
while (dl) {
tot = dl->nr;
if (tot) do_it = true;
@@ -220,20 +222,29 @@ void BKE_mball_texspace_calc(Object *ob)
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
-#if 0
- loc[0] = (min[0] + max[0]) / 2.0f;
- loc[1] = (min[1] + max[1]) / 2.0f;
- loc[2] = (min[2] + max[2]) / 2.0f;
-
- size[0] = (max[0] - min[0]) / 2.0f;
- size[1] = (max[1] - min[1]) / 2.0f;
- size[2] = (max[2] - min[2]) / 2.0f;
-#endif
+
BKE_boundbox_init_from_minmax(bb, min, max);
bb->flag &= ~BOUNDBOX_DIRTY;
}
+/** Return or compute bbox for given metaball object. */
+BoundBox *BKE_mball_boundbox_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MBALL);
+
+ if (ob->bb != NULL && (ob->bb->flag & BOUNDBOX_DIRTY) == 0) {
+ return ob->bb;
+ }
+
+ /* This should always only be called with evaluated objects, but currently RNA is a problem here... */
+ if (ob->runtime.curve_cache != NULL) {
+ BKE_mball_texspace_calc(ob);
+ }
+
+ return ob->bb;
+}
+
float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
{
BoundBox *bb;
@@ -299,6 +310,11 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
int basis1nr, basis2nr;
char basis1name[MAX_ID_NAME], basis2name[MAX_ID_NAME];
+ if (ob1->id.name[2] != ob2->id.name[2]) {
+ /* Quick return in case first char of both ID's names is not the same... */
+ return false;
+ }
+
BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.');
BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.');
@@ -310,13 +326,46 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
}
}
+bool BKE_mball_is_any_selected(const MetaBall *mb)
+{
+ for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool BKE_mball_is_any_selected_multi(Object **objects, int objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ if (BKE_mball_is_any_selected(mb)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_mball_is_any_unselected(const MetaBall *mb)
+{
+ for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ if ((ml->flag & SELECT) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* \brief copy some properties from object to other metaball object with same base name
*
* When some properties (wiresize, threshold, update flags) of metaball are changed, then this properties
* are copied to all metaballs in same "group" (metaballs with same base name: MBall,
* MBall.001, MBall.002, etc). The most important is to copy properties to the base metaball,
* because this metaball influence polygonisation of metaballs. */
-void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *active_object)
+void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
Scene *sce_iter = scene;
Base *base;
@@ -328,8 +377,11 @@ void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *
BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &ob)) {
+ /* Pass depsgraph as NULL, which means we will not expand into
+ * duplis unlike when we generate the mball. Expanding duplis
+ * would not be compatible when editing multiple view layers. */
+ BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) {
if (ob->type == OB_MBALL) {
if (ob != active_object) {
BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
@@ -359,28 +411,27 @@ void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *
*
* warning!, is_basis_mball() can fail on returned object, see long note above.
*/
-Object *BKE_mball_basis_find(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *basis)
+Object *BKE_mball_basis_find(Scene *scene, Object *basis)
{
- Scene *sce_iter = scene;
- Base *base;
- Object *ob, *bob = basis;
+ Object *bob = basis;
int basisnr, obnr;
char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
- SceneBaseIter iter;
BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &ob)) {
- if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) {
- if (ob != bob) {
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
- if (STREQ(obname, basisname)) {
- if (obnr < basisnr) {
- basis = ob;
- basisnr = obnr;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if ((ob->type == OB_MBALL) && !(base->flag & BASE_FROMDUPLI)) {
+ if (ob != bob) {
+ BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
+
+ /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
+ if (STREQ(obname, basisname)) {
+ if (obnr < basisnr) {
+ basis = ob;
+ basisnr = obnr;
+ }
}
}
}
@@ -390,17 +441,17 @@ Object *BKE_mball_basis_find(Main *bmain, EvaluationContext *eval_ctx, Scene *sc
return basis;
}
-bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3],
- float obmat[4][4], const short flag)
+bool BKE_mball_minmax_ex(
+ const MetaBall *mb, float min[3], float max[3],
+ const float obmat[4][4], const short flag)
{
const float scale = obmat ? mat4_to_scale(obmat) : 1.0f;
- MetaElem *ml;
bool changed = false;
float centroid[3], vec[3];
INIT_MINMAX(min, max);
- for (ml = mb->elems.first; ml; ml = ml->next) {
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
if ((ml->flag & flag) == flag) {
const float scale_mb = (ml->rad * 0.5f) * scale;
int i;
@@ -427,27 +478,24 @@ bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3],
/* basic vertex data functions */
-bool BKE_mball_minmax(MetaBall *mb, float min[3], float max[3])
+bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
{
- MetaElem *ml;
-
INIT_MINMAX(min, max);
- for (ml = mb->elems.first; ml; ml = ml->next) {
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
minmax_v3v3_v3(min, max, &ml->x);
}
return (BLI_listbase_is_empty(&mb->elems) == false);
}
-bool BKE_mball_center_median(MetaBall *mb, float r_cent[3])
+bool BKE_mball_center_median(const MetaBall *mb, float r_cent[3])
{
- MetaElem *ml;
int total = 0;
zero_v3(r_cent);
- for (ml = mb->elems.first; ml; ml = ml->next) {
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
add_v3_v3(r_cent, &ml->x);
total++;
}
@@ -459,7 +507,7 @@ bool BKE_mball_center_median(MetaBall *mb, float r_cent[3])
return (total != 0);
}
-bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3])
+bool BKE_mball_center_bounds(const MetaBall *mb, float r_cent[3])
{
float min[3], max[3];
@@ -473,26 +521,25 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3])
void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props)
{
- MetaElem *me;
float quat[4];
const float scale = mat4_to_scale(mat);
const float scale_sqrt = sqrtf(scale);
mat4_to_quat(quat, mat);
- for (me = mb->elems.first; me; me = me->next) {
- mul_m4_v3(mat, &me->x);
- mul_qt_qtqt(me->quat, quat, me->quat);
+ for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ mul_m4_v3(mat, &ml->x);
+ mul_qt_qtqt(ml->quat, quat, ml->quat);
if (do_props) {
- me->rad *= scale;
+ ml->rad *= scale;
/* hrmf, probably elems shouldn't be
* treating scale differently - campbell */
- if (!MB_TYPE_SIZE_SQUARED(me->type)) {
- mul_v3_fl(&me->expx, scale);
+ if (!MB_TYPE_SIZE_SQUARED(ml->type)) {
+ mul_v3_fl(&ml->expx, scale);
}
else {
- mul_v3_fl(&me->expx, scale_sqrt);
+ mul_v3_fl(&ml->expx, scale_sqrt);
}
}
}
@@ -500,44 +547,99 @@ void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props)
void BKE_mball_translate(MetaBall *mb, const float offset[3])
{
- MetaElem *ml;
-
- for (ml = mb->elems.first; ml; ml = ml->next) {
+ for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
add_v3_v3(&ml->x, offset);
}
}
/* *** select funcs *** */
-void BKE_mball_select_all(struct MetaBall *mb)
+int BKE_mball_select_count(const MetaBall *mb)
{
- MetaElem *ml;
+ int sel = 0;
+ for (const MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ sel++;
+ }
+ }
+ return sel;
+}
- for (ml = mb->editelems->first; ml; ml = ml->next) {
+int BKE_mball_select_count_multi(Object **objects, int objects_len)
+{
+ int sel = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ const Object *obedit = objects[ob_index];
+ const MetaBall *mb = (MetaBall *)obedit->data;
+ sel += BKE_mball_select_count(mb);
+ }
+ return sel;
+}
+
+void BKE_mball_select_all(MetaBall *mb)
+{
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
ml->flag |= SELECT;
}
}
-void BKE_mball_deselect_all(MetaBall *mb)
+void BKE_mball_select_all_multi(Object **objects, int objects_len)
{
- MetaElem *ml;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = obedit->data;
+ BKE_mball_select_all(mb);
+ }
+}
- for (ml = mb->editelems->first; ml; ml = ml->next) {
+void BKE_mball_deselect_all(MetaBall *mb)
+{
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
ml->flag &= ~SELECT;
}
}
-void BKE_mball_select_swap(struct MetaBall *mb)
+void BKE_mball_deselect_all_multi(Object **objects, int objects_len)
{
- MetaElem *ml;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = obedit->data;
+
+ BKE_mball_deselect_all(mb);
+ }
+}
- for (ml = mb->editelems->first; ml; ml = ml->next) {
+void BKE_mball_select_swap(MetaBall *mb)
+{
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
ml->flag ^= SELECT;
}
}
+void BKE_mball_select_swap_multi(Object **objects, int objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ BKE_mball_select_swap(mb);
+ }
+}
+
/* **** Depsgraph evaluation **** */
-void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
- MetaBall *UNUSED(mball))
+/* Draw Engine */
+
+void (*BKE_mball_batch_cache_dirty_tag_cb)(MetaBall *mb, int mode) = NULL;
+void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = NULL;
+
+void BKE_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
{
+ if (mb->batch_cache) {
+ BKE_mball_batch_cache_dirty_tag_cb(mb, mode);
+ }
+}
+void BKE_mball_batch_cache_free(MetaBall *mb)
+{
+ if (mb->batch_cache) {
+ BKE_mball_batch_cache_free_cb(mb);
+ }
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 840062df3a3..5525c41c9dd 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -48,12 +48,14 @@
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_main.h"
#include "BKE_mball_tessellate.h" /* own include */
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "BLI_strict_flags.h"
/* experimental (faster) normal calculation */
@@ -837,27 +839,6 @@ static void vnormal(PROCESS *process, const float point[3], float r_no[3])
r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f;
r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f;
r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f;
-
-#if 0
- f = normalize_v3(r_no);
-
- if (0) {
- float tvec[3];
-
- delta *= 2.0f;
-
- f = process->function(process, point[0], point[1], point[2]);
-
- tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f;
- tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f;
- tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f;
-
- if (normalize_v3(tvec) != 0.0f) {
- add_v3_v3(r_no, tvec);
- normalize_v3(r_no);
- }
- }
-#endif
}
#endif /* USE_ACCUM_NORMAL */
@@ -1056,7 +1037,7 @@ static void polygonize(PROCESS *process)
* Iterates over ALL objects in the scene and all of its sets, including
* making all duplis(not only metas). Copies metas to mainb array.
* Computes bounding boxes for building BVH. */
-static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob)
+static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Object *ob)
{
Scene *sce_iter = scene;
Base *base;
@@ -1075,13 +1056,13 @@ static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process
BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
/* make main array */
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &bob)) {
+ BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 1, &base, &bob)) {
if (bob->type == OB_MBALL) {
zero_size = 0;
ml = NULL;
- if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) {
+ if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
mb = ob->data;
if (mb->editelems) ml = mb->editelems->first;
@@ -1233,12 +1214,13 @@ static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process
}
}
-void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
+void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
MetaBall *mb;
DispList *dl;
unsigned int a;
PROCESS process = {0};
+ bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
mb = ob->data;
@@ -1249,10 +1231,10 @@ void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene
else if (process.thresh < 0.1f) process.converge_res = 4;
else process.converge_res = 2;
- if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return;
+ if (is_render && (mb->flag == MB_UPDATE_NEVER)) return;
if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return;
- if (eval_ctx->mode == DAG_EVAL_RENDER) {
+ if (is_render) {
process.size = mb->rendersize;
}
else {
@@ -1267,7 +1249,7 @@ void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene
process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena");
/* initialize all mainb (MetaElems) */
- init_meta(bmain, eval_ctx, &process, scene, ob);
+ init_meta(depsgraph, &process, scene, ob);
if (process.totelem > 0) {
build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 5758e00a28d..1400fbd514e 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -32,8 +32,10 @@
#include "DNA_object_types.h"
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"
@@ -41,15 +43,15 @@
#include "BLI_string.h"
#include "BKE_animsys.h"
+#include "BKE_idcode.h"
#include "BKE_main.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_editmesh.h"
@@ -109,7 +111,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
for (i = 0; i < c1->totlayer; i++) {
if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i1++;
}
@@ -117,7 +119,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
for (i = 0; i < c2->totlayer; i++) {
if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i2++;
}
@@ -131,14 +133,14 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
i1 = 0; i2 = 0;
for (i = 0; i < tot; i++) {
while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i1++;
l1++;
}
while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i2++;
l2++;
@@ -306,7 +308,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
* Callers could also check but safer to do here - campbell */
}
else {
- const int tottex_original = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
@@ -317,16 +319,16 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
{
BKE_mesh_tessface_clear(me);
- CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface);
+ CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface);
/* TODO - add some --debug-mesh option */
if (G.debug & G_DEBUG) {
/* note: this warning may be un-called for if we are initializing the mesh for the
* first time from bmesh, rather then giving a warning about this we could be smarter
* and check if there was any data to begin with, for now just print the warning with
- * some info to help troubleshoot whats going on - campbell */
+ * some info to help troubleshoot what's going on - campbell */
printf("%s: warning! Tessellation uvs or vcol data got out of sync, "
- "had to reset!\n CD_MTFACE: %d != CD_MTEXPOLY: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
+ "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
__func__, tottex_tessface, tottex_original, totcol_tessface, totcol_original);
}
}
@@ -372,6 +374,49 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
}
}
+bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me)
+{
+ BMesh *bm = me->edit_btmesh ? me->edit_btmesh->bm : NULL;
+ bool changed = false;
+ if (bm) {
+ if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
+ BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP);
+ changed = true;
+ }
+ }
+ else {
+ if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ CustomData_add_layer(
+ &me->pdata,
+ CD_FACEMAP,
+ CD_DEFAULT,
+ NULL,
+ me->totpoly);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
+{
+ BMesh *bm = me->edit_btmesh ? me->edit_btmesh->bm : NULL;
+ bool changed = false;
+ if (bm) {
+ if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
+ BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP);
+ changed = true;
+ }
+ }
+ else {
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ CustomData_free_layers(&me->pdata, CD_FACEMAP, me->totpoly);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
/* this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
* mloopcol and mcol) have the same relative active/render/clone/mask indices.
*
@@ -380,14 +425,11 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
* versions of the mesh. - campbell*/
static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd)
{
- if (me->edit_btmesh)
- BKE_editmesh_update_linked_customdata(me->edit_btmesh);
-
if (do_ensure_tess_cd) {
mesh_ensure_tessellation_customdata(me);
}
- CustomData_bmesh_update_active_layers(&me->fdata, &me->pdata, &me->ldata);
+ CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata);
}
void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
@@ -406,7 +448,6 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
- me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY);
me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
@@ -426,6 +467,8 @@ void BKE_mesh_free(Mesh *me)
{
BKE_animdata_free(&me->id, false);
+ BKE_mesh_runtime_clear_cache(me);
+
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
@@ -460,12 +503,7 @@ void BKE_mesh_init(Mesh *me)
me->size[0] = me->size[1] = me->size[2] = 1.0;
me->smoothresh = DEG2RADF(30);
me->texflag = ME_AUTOSPACE;
-
- /* disable because its slow on many GPU's, see [#37518] */
-#if 0
- me->flag = ME_TWOSIDED;
-#endif
- me->drawflag = ME_DRAWEDGES | ME_DRAWFACES | ME_DRAWCREASES;
+ me->drawflag = 0;
CustomData_reset(&me->vdata);
CustomData_reset(&me->edata);
@@ -496,15 +534,22 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag)
{
const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */
+ CustomDataMask mask = CD_MASK_MESH;
+
+ if (me_src->id.tag & LIB_TAG_NO_MAIN) {
+ /* For copies in depsgraph, keep data like origindex and orco. */
+ mask |= CD_MASK_DERIVEDMESH;
+ }
me_dst->mat = MEM_dupallocN(me_src->mat);
- CustomData_copy(&me_src->vdata, &me_dst->vdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totvert);
- CustomData_copy(&me_src->edata, &me_dst->edata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totedge);
- CustomData_copy(&me_src->ldata, &me_dst->ldata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totloop);
- CustomData_copy(&me_src->pdata, &me_dst->pdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totpoly);
+ const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, mask, alloc_type, me_dst->totvert);
+ CustomData_copy(&me_src->edata, &me_dst->edata, mask, alloc_type, me_dst->totedge);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, mask, alloc_type, me_dst->totloop);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, mask, alloc_type, me_dst->totpoly);
if (do_tessface) {
- CustomData_copy(&me_src->fdata, &me_dst->fdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totface);
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, mask, alloc_type, me_dst->totface);
}
else {
mesh_tessface_clear_intern(me_dst, false);
@@ -514,37 +559,223 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int
me_dst->edit_btmesh = NULL;
+ /* Call BKE_mesh_runtime_reset? */
+ me_dst->runtime.batch_cache = NULL;
+ me_dst->runtime.looptris.array = NULL;
+ me_dst->runtime.bvh_cache = NULL;
+ me_dst->runtime.shrinkwrap_data = NULL;
+
+ if (me_src->id.tag & LIB_TAG_NO_MAIN) {
+ me_dst->runtime.deformed_only = me_src->runtime.deformed_only;
+ }
+ else {
+ /* This is a direct copy of a main mesh, so for now it has the same topology. */
+ me_dst->runtime.deformed_only = 1;
+ }
+ me_dst->runtime.is_original = false;
+
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
me_dst->bb = MEM_dupallocN(me_dst->bb);
/* TODO Do we want to add flag to prevent this? */
- if (me_src->key) {
+ if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag, false);
}
}
+/* Custom data layer functions; those assume that totXXX are set correctly. */
+static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface)
+{
+ if (!CustomData_get_layer(&mesh->vdata, CD_MVERT))
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_MEDGE))
+ CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP))
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+ if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY))
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE))
+ CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface);
+}
+static void mesh_ensure_cdlayers_origindex(Mesh *mesh, bool do_tessface)
+{
+ if (!CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly);
+
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->fdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
+}
+
+Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
+{
+ Mesh *mesh = BKE_libblock_alloc(
+ NULL, ID_ME,
+ BKE_idcode_to_name(ID_ME),
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG);
+ BKE_libblock_init_empty(&mesh->id);
+
+ /* don't use CustomData_reset(...); because we dont want to touch customdata */
+ copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1);
+
+ mesh->totvert = verts_len;
+ mesh->totedge = edges_len;
+ mesh->totface = tessface_len;
+ mesh->totloop = loops_len;
+ mesh->totpoly = polys_len;
+
+ mesh_ensure_cdlayers_primary(mesh, true);
+ mesh_ensure_cdlayers_origindex(mesh, true);
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ return mesh;
+}
+
+static Mesh *mesh_new_nomain_from_template_ex(
+ const Mesh *me_src,
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len,
+ CustomDataMask mask)
+{
+ /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
+ const bool do_tessface = (tessface_len ||
+ ((me_src->totface != 0) && (me_src->totpoly == 0)));
+
+ Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
+
+ me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->mselect = MEM_dupallocN(me_dst->mselect);
+
+ me_dst->totvert = verts_len;
+ me_dst->totedge = edges_len;
+ me_dst->totface = tessface_len;
+ me_dst->totloop = loops_len;
+ me_dst->totpoly = polys_len;
+
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, mask, CD_CALLOC, verts_len);
+ CustomData_copy(&me_src->edata, &me_dst->edata, mask, CD_CALLOC, edges_len);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, mask, CD_CALLOC, loops_len);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, mask, CD_CALLOC, polys_len);
+ if (do_tessface) {
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, mask, CD_CALLOC, tessface_len);
+ }
+ else {
+ mesh_tessface_clear_intern(me_dst, false);
+ }
+
+ /* The destination mesh should at least have valid primary CD layers,
+ * even in cases where the source mesh does not. */
+ mesh_ensure_cdlayers_primary(me_dst, do_tessface);
+ mesh_ensure_cdlayers_origindex(me_dst, false);
+ BKE_mesh_update_customdata_pointers(me_dst, false);
+
+ return me_dst;
+}
+
+Mesh *BKE_mesh_new_nomain_from_template(
+ const Mesh *me_src,
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len)
+{
+ return mesh_new_nomain_from_template_ex(
+ me_src,
+ verts_len, edges_len, tessface_len,
+ loops_len, polys_len,
+ CD_MASK_EVERYTHING);
+}
+
+Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference)
+{
+ int flags = (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW);
+
+ if (reference) {
+ flags |= LIB_ID_COPY_CD_REFERENCE;
+ }
+
+ Mesh *result;
+ BKE_id_copy_ex(NULL, &source->id, (ID **)&result, flags, false);
+ return result;
+}
+
Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me)
{
Mesh *me_copy;
- BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, 0, false);
+ BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, LIB_ID_COPY_SHAPEKEY, false);
return me_copy;
}
+BMesh *BKE_mesh_to_bmesh_ex(
+ const Mesh *me,
+ const struct BMeshCreateParams *create_params,
+ const struct BMeshFromMeshParams *convert_params)
+{
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+
+ bm = BM_mesh_create(&allocsize, create_params);
+ BM_mesh_bm_from_me(bm, me, convert_params);
+
+ return bm;
+}
+
BMesh *BKE_mesh_to_bmesh(
Mesh *me, Object *ob,
const bool add_key_index, const struct BMeshCreateParams *params)
{
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+ return BKE_mesh_to_bmesh_ex(
+ me, params,
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = false,
+ .add_key_index = add_key_index,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ });
+}
- bm = BM_mesh_create(&allocsize, params);
+Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params)
+{
+ BLI_assert(params->calc_object_remap == false);
+ Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
+ BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ return mesh;
+}
- BM_mesh_bm_from_me(
- bm, me, (&(struct BMeshFromMeshParams){
- .add_key_index = add_key_index, .use_shapekey = true, .active_shapekey = ob->shapenr,
- }));
+Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const int64_t cd_mask_extra)
+{
+ Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
+ BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
+ return mesh;
+}
- return bm;
+/**
+ * TODO(campbell): support mesh with only an edit-mesh which is lazy initialized.
+ */
+Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ BMEditMesh *em, CustomDataMask data_mask, float (*vertexCos)[3])
+{
+ Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask);
+ /* Use editmesh directly where possible. */
+ me->runtime.is_original = true;
+ if (vertexCos) {
+ /* We will own this array in the future. */
+ BKE_mesh_apply_vert_coords(me, vertexCos);
+ MEM_freeN(vertexCos);
+ me->runtime.is_original = false;
+ }
+ return me;
}
void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
@@ -553,121 +784,82 @@ void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
}
bool BKE_mesh_uv_cdlayer_rename_index(
- Mesh *me, const int poly_index, const int loop_index, const int face_index,
+ Mesh *me, const int loop_index, const int face_index,
const char *new_name, const bool do_tessface)
{
- CustomData *pdata, *ldata, *fdata;
- CustomDataLayer *cdlp, *cdlu, *cdlf;
- const int step = do_tessface ? 3 : 2;
- int i;
+ CustomData *ldata, *fdata;
+ CustomDataLayer *cdlu, *cdlf;
if (me->edit_btmesh) {
- pdata = &me->edit_btmesh->bm->pdata;
ldata = &me->edit_btmesh->bm->ldata;
fdata = NULL; /* No tessellated data in BMesh! */
}
else {
- pdata = &me->pdata;
ldata = &me->ldata;
fdata = &me->fdata;
}
- cdlp = &pdata->layers[poly_index];
+
cdlu = &ldata->layers[loop_index];
- cdlf = fdata && do_tessface ? &fdata->layers[face_index] : NULL;
+ cdlf = (face_index != -1) && fdata && do_tessface ? &fdata->layers[face_index] : NULL;
- if (cdlp->name != new_name) {
+ if (cdlu->name != new_name) {
/* Mesh validate passes a name from the CD layer as the new name,
* Avoid memcpy from self to self in this case.
*/
- BLI_strncpy(cdlp->name, new_name, sizeof(cdlp->name));
- CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers);
+ BLI_strncpy(cdlu->name, new_name, sizeof(cdlu->name));
+ CustomData_set_layer_unique_name(ldata, loop_index);
}
- /* Loop until we do have exactly the same name for all layers! */
- for (i = 1; !STREQ(cdlp->name, cdlu->name) || (cdlf && !STREQ(cdlp->name, cdlf->name)); i++) {
- switch (i % step) {
- case 0:
- BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name));
- CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers);
- break;
- case 1:
- BLI_strncpy(cdlu->name, cdlp->name, sizeof(cdlu->name));
- CustomData_set_layer_unique_name(ldata, cdlu - ldata->layers);
- break;
- case 2:
- if (cdlf) {
- BLI_strncpy(cdlf->name, cdlp->name, sizeof(cdlf->name));
- CustomData_set_layer_unique_name(fdata, cdlf - fdata->layers);
- }
- break;
- }
+ if (cdlf == NULL) {
+ return false;
}
+ BLI_strncpy(cdlf->name, cdlu->name, sizeof(cdlf->name));
+ CustomData_set_layer_unique_name(fdata, face_index);
+
return true;
}
bool BKE_mesh_uv_cdlayer_rename(Mesh *me, const char *old_name, const char *new_name, bool do_tessface)
{
- CustomData *pdata, *ldata, *fdata;
+ CustomData *ldata, *fdata;
if (me->edit_btmesh) {
- pdata = &me->edit_btmesh->bm->pdata;
ldata = &me->edit_btmesh->bm->ldata;
/* No tessellated data in BMesh! */
fdata = NULL;
do_tessface = false;
}
else {
- pdata = &me->pdata;
ldata = &me->ldata;
fdata = &me->fdata;
do_tessface = (do_tessface && fdata->totlayer);
}
{
- const int pidx_start = CustomData_get_layer_index(pdata, CD_MTEXPOLY);
const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV);
const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1;
- int pidx = CustomData_get_named_layer(pdata, CD_MTEXPOLY, old_name);
int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name);
int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1;
/* None of those cases should happen, in theory!
* Note this assume we have the same number of mtexpoly, mloopuv and mtface layers!
*/
- if (pidx == -1) {
- if (lidx == -1) {
- if (fidx == -1) {
- /* No layer found with this name! */
- return false;
- }
- else {
- lidx = fidx;
- }
- }
- pidx = lidx;
- }
- else {
- if (lidx == -1) {
- lidx = pidx;
+ if (lidx == -1) {
+ if (fidx == -1) {
+ /* No layer found with this name! */
+ return false;
}
- if (fidx == -1 && do_tessface) {
- fidx = pidx;
+ else {
+ lidx = fidx;
}
}
-#if 0
- /* For now, we do not consider mismatch in indices (i.e. same name leading to (relative) different indices). */
- else if (pidx != lidx) {
- lidx = pidx;
- }
-#endif
/* Go back to absolute indices! */
- pidx += pidx_start;
lidx += lidx_start;
if (fidx != -1)
fidx += fidx_start;
- return BKE_mesh_uv_cdlayer_rename_index(me, pidx, lidx, fidx, new_name, do_tessface);
+ return BKE_mesh_uv_cdlayer_rename_index(me, lidx, fidx, new_name, do_tessface);
}
}
@@ -722,19 +914,25 @@ void BKE_mesh_texspace_calc(Mesh *me)
BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
- Mesh *me = ob->data;
+ /* This is Object-level data access, DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
+ if (ob->bb == NULL || ob->bb->flag & BOUNDBOX_DIRTY) {
+ Mesh *me = ob->data;
+ float min[3], max[3];
- if (ob->bb)
- return ob->bb;
+ INIT_MINMAX(min, max);
+ BKE_mesh_minmax(me, min, max);
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
+ if (ob->bb == NULL) {
+ ob->bb = MEM_mallocN(sizeof(*ob->bb), __func__);
+ }
+ BKE_boundbox_init_from_minmax(ob->bb, min, max);
+ ob->bb->flag &= ~BOUNDBOX_DIRTY;
}
- return me->bb;
+ return ob->bb;
}
-void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_size[3])
+BoundBox *BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_size[3])
{
if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
BKE_mesh_texspace_calc(me);
@@ -743,6 +941,20 @@ void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_siz
if (r_loc) copy_v3_v3(r_loc, me->loc);
if (r_rot) copy_v3_v3(r_rot, me->rot);
if (r_size) copy_v3_v3(r_size, me->size);
+
+ return me->bb;
+}
+
+void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size)
+{
+ if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(me);
+ }
+
+ if (r_texflag != NULL) *r_texflag = &me->texflag;
+ if (r_loc != NULL) *r_loc = me->loc;
+ if (r_rot != NULL) *r_rot = me->rot;
+ if (r_size != NULL) *r_size = me->size;
}
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
@@ -904,7 +1116,6 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
test_object_modifiers(ob);
}
-
void BKE_mesh_material_index_remove(Mesh *me, short index)
{
MPoly *mp;
@@ -999,15 +1210,15 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
/**
* Return a newly MEM_malloc'd array of all the mesh vertex locations
- * \note \a r_numVerts may be NULL
+ * \note \a r_verts_len may be NULL
*/
-float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3]
+float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_verts_len))[3]
{
- int i, numVerts = me->totvert;
- float (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "vertexcos1");
+ int i, verts_len = me->totvert;
+ float (*cos)[3] = MEM_malloc_arrayN(verts_len, sizeof(*cos), "vertexcos1");
- if (r_numVerts) *r_numVerts = numVerts;
- for (i = 0; i < numVerts; i++)
+ if (r_verts_len) *r_verts_len = verts_len;
+ for (i = 0; i < verts_len; i++)
copy_v3_v3(cos[i], me->mvert[i].co);
return cos;
@@ -1046,10 +1257,6 @@ int poly_get_adj_loops_from_vert(
vert);
if (corner != -1) {
-#if 0 /* unused - this loop */
- const MLoop *ml = &mloop[poly->loopstart + corner];
-#endif
-
/* vertex was found */
r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v;
r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
@@ -1072,6 +1279,21 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v)
return -1;
}
+/**
+ * Sets each output array element to the edge index if it is a real edge, or -1.
+ */
+void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3])
+{
+ for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
+ const MLoop *l1 = &mesh->mloop[looptri->tri[i]], *l2 = &mesh->mloop[looptri->tri[i_next]];
+ const MEdge *e = &mesh->medge[l1->e];
+
+ bool is_real = (l1->v == e->v1 && l2->v == e->v2) || (l1->v == e->v2 && l2->v == e->v1);
+
+ r_edges[i] = is_real ? l1->e : -1;
+ }
+}
+
/* basic vertex data functions */
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
{
@@ -1139,13 +1361,13 @@ void BKE_mesh_ensure_navmesh(Mesh *me)
{
if (!CustomData_has_layer(&me->pdata, CD_RECAST)) {
int i;
- int numFaces = me->totpoly;
+ int polys_len = me->totpoly;
int *recastData;
- recastData = (int *)MEM_malloc_arrayN(numFaces, sizeof(int), __func__);
- for (i = 0; i < numFaces; i++) {
+ recastData = (int *)MEM_malloc_arrayN(polys_len, sizeof(int), __func__);
+ for (i = 0; i < polys_len; i++) {
recastData[i] = i + 1;
}
- CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, numFaces, "recastData");
+ CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, polys_len, "recastData");
}
}
@@ -1337,6 +1559,37 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
+
+void BKE_mesh_apply_vert_coords(Mesh *mesh, float (*vertCoords)[3])
+{
+ MVert *vert;
+ int i;
+
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ mesh->mvert = vert;
+
+ for (i = 0; i < mesh->totvert; ++i, ++vert)
+ copy_v3_v3(vert->co, vertCoords[i]);
+
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+}
+
+void BKE_mesh_apply_vert_normals(Mesh *mesh, short (*vertNormals)[3])
+{
+ MVert *vert;
+ int i;
+
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ mesh->mvert = vert;
+
+ for (i = 0; i < mesh->totvert; ++i, ++vert)
+ copy_v3_v3_short(vert->no, vertNormals[i]);
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+}
+
/**
* Compute 'split' (aka loop, or per face corner's) normals.
*
@@ -1388,6 +1641,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
if (free_polynors) {
MEM_freeN(polynors);
}
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_split(Mesh *mesh)
@@ -1421,25 +1676,25 @@ static int split_faces_prepare_new_verts(
* dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */
BLI_assert(lnors_spacearr != NULL);
- const int num_loops = mesh->totloop;
- int num_verts = mesh->totvert;
+ const int loops_len = mesh->totloop;
+ int verts_len = mesh->totvert;
MVert *mvert = mesh->mvert;
MLoop *mloop = mesh->mloop;
- BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
- BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
+ BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
MLoop *ml = mloop;
MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX);
- for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
+ for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) {
if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
const int vert_idx = ml->v;
const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
/* If vert is already used by another smooth fan, we need a new vert for this one. */
- const int new_vert_idx = vert_used ? num_verts++ : vert_idx;
+ const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
BLI_assert(*lnor_space);
@@ -1484,7 +1739,7 @@ static int split_faces_prepare_new_verts(
MEM_freeN(done_loops);
MEM_freeN(verts_used);
- return num_verts - mesh->totvert;
+ return verts_len - mesh->totvert;
}
/* Detect needed new edges, and update accordingly loops' edge indices.
@@ -1552,12 +1807,12 @@ static int split_faces_prepare_new_edges(
static void split_faces_split_new_verts(
Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts)
{
- const int num_verts = mesh->totvert - num_new_verts;
+ const int verts_len = mesh->totvert - num_new_verts;
MVert *mvert = mesh->mvert;
/* Remember new_verts is a single linklist, so its items are in reversed order... */
MVert *new_mv = &mvert[mesh->totvert - 1];
- for (int i = mesh->totvert - 1; i >= num_verts ; i--, new_mv--, new_verts = new_verts->next) {
+ for (int i = mesh->totvert - 1; i >= verts_len ; i--, new_mv--, new_verts = new_verts->next) {
BLI_assert(new_verts->new_index == i);
BLI_assert(new_verts->new_index != new_verts->orig_index);
CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
@@ -1652,15 +1907,17 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
#endif
}
-
/* **** Depsgraph evaluation **** */
void BKE_mesh_eval_geometry(
- EvaluationContext *UNUSED(eval_ctx),
+ Depsgraph *depsgraph,
Mesh *mesh)
{
- DEG_debug_print_eval(__func__, mesh->id.name, mesh);
+ DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
BKE_mesh_texspace_calc(mesh);
+ /* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is
+ * (e.g. after modifiers, etc.) */
+ mesh->texflag &= ~ME_AUTOSPACE;
}
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index bfee7f3924c..eed02dae824 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -22,9 +22,11 @@
* \ingroup bke
*/
+
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
+#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
@@ -39,24 +41,33 @@
#include "BKE_main.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_key.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
#include "BKE_displist.h"
#include "BKE_library.h"
#include "BKE_material.h"
-#include "BKE_modifier.h"
#include "BKE_mball.h"
-#include "BKE_depsgraph.h"
+/* these 2 are only used by conversion functions */
#include "BKE_curve.h"
/* -- */
#include "BKE_object.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
/* Define for cases when you want extra validation of mesh
* after certain modifications.
*/
// #undef VALIDATE_MESH
+#ifdef VALIDATE_MESH
+# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
+#else
+# define ASSERT_IS_VALID_MESH(mesh)
+#endif
+
void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
{
DispList *dl;
@@ -206,8 +217,8 @@ int BKE_mesh_nurbs_to_mdata(
{
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
return BKE_mesh_nurbs_displist_to_mdata(
@@ -480,13 +491,65 @@ int BKE_mesh_nurbs_displist_to_mdata(
return 0;
}
+Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
+{
+ Curve *cu = ob->data;
+ Mesh *mesh;
+ MVert *allvert;
+ MEdge *alledge;
+ MLoop *allloop;
+ MPoly *allpoly;
+ MLoopUV *alluv = NULL;
+ int totvert, totedge, totloop, totpoly;
+ bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
+
+ if (BKE_mesh_nurbs_displist_to_mdata(
+ ob, dispbase, &allvert, &totvert, &alledge,
+ &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL,
+ &totloop, &totpoly) != 0)
+ {
+ /* Error initializing mdata. This often happens when curve is empty */
+ return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ }
+
+ mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
+ memcpy(mesh->medge, alledge, totedge * sizeof(MEdge));
+ memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop));
+ memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
+
+ if (alluv) {
+ const char *uvname = "Orco";
+ CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
+ }
+
+ MEM_freeN(allvert);
+ MEM_freeN(alledge);
+ MEM_freeN(allloop);
+ MEM_freeN(allpoly);
+
+ return mesh;
+}
+
+Mesh *BKE_mesh_new_nomain_from_curve(Object *ob)
+{
+ ListBase disp = {NULL, NULL};
+
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
+ }
+
+ return BKE_mesh_new_nomain_from_curve_displist(ob, &disp);
+}
/* this may fail replacing ob->data, be sure to check ob->type */
void BKE_mesh_from_nurbs_displist(
- Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name)
+ Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary)
{
Object *ob1;
- DerivedMesh *dm = ob->derivedFinal;
+ Mesh *me_eval = ob->runtime.mesh_eval;
Mesh *me;
Curve *cu;
MVert *allvert = NULL;
@@ -498,7 +561,7 @@ void BKE_mesh_from_nurbs_displist(
cu = ob->data;
- if (dm == NULL) {
+ if (me_eval == NULL) {
if (BKE_mesh_nurbs_displist_to_mdata(
ob, dispbase, &allvert, &totvert,
&alledge, &totedge, &allloop,
@@ -523,7 +586,6 @@ void BKE_mesh_from_nurbs_displist(
if (alluv) {
const char *uvname = "Orco";
- me->mtpoly = CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname);
me->mloopuv = CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
}
@@ -531,7 +593,8 @@ void BKE_mesh_from_nurbs_displist(
}
else {
me = BKE_mesh_add(bmain, obdata_name);
- DM_to_mesh(dm, me, ob, CD_MASK_MESH, false);
+ ob->runtime.mesh_eval = NULL;
+ BKE_mesh_nomain_to_mesh(me_eval, me, ob, CD_MASK_MESH, false);
}
me->totcol = cu->totcol;
@@ -570,7 +633,16 @@ void BKE_mesh_from_nurbs_displist(
ob1 = ob1->id.next;
}
- BKE_libblock_free_us(bmain, cu);
+ if (temporary) {
+ /* For temporary objects in BKE_mesh_new_from_object don't remap
+ * the entire scene with associated depsgraph updates, which are
+ * problematic for renderers exporting data. */
+ id_us_min(&cu->id);
+ BKE_libblock_free(bmain, cu);
+ }
+ else {
+ BKE_libblock_free_us(bmain, cu);
+ }
}
void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
@@ -579,11 +651,11 @@ void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
- BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name);
+ BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false);
}
typedef struct EdgeLink {
@@ -610,15 +682,15 @@ static void appendPolyLineVert(ListBase *lb, unsigned int index)
BLI_addtail(lb, vl);
}
-void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int edge_users_test)
+void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int edge_users_test)
{
- MVert *mvert = dm->getVertArray(dm);
- MEdge *med, *medge = dm->getEdgeArray(dm);
- MPoly *mp, *mpoly = dm->getPolyArray(dm);
- MLoop *mloop = dm->getLoopArray(dm);
+ MVert *mvert = me->mvert;
+ MEdge *med, *medge = me->medge;
+ MPoly *mp, *mpoly = me->mpoly;
+ MLoop *mloop = me->mloop;
- int dm_totedge = dm->getNumEdges(dm);
- int dm_totpoly = dm->getNumPolys(dm);
+ int medge_len = me->totedge;
+ int mpoly_len = me->totpoly;
int totedges = 0;
int i;
@@ -628,8 +700,8 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
ListBase edges = {NULL, NULL};
/* get boundary edges */
- edge_users = MEM_calloc_arrayN(dm_totedge, sizeof(int), __func__);
- for (i = 0, mp = mpoly; i < dm_totpoly; i++, mp++) {
+ edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__);
+ for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
MLoop *ml = &mloop[mp->loopstart];
int j;
for (j = 0; j < mp->totloop; j++, ml++) {
@@ -639,7 +711,7 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
/* create edges from all faces (so as to find edges not in any faces) */
med = medge;
- for (i = 0; i < dm_totedge; i++, med++) {
+ for (i = 0; i < medge_len; i++, med++) {
if (edge_users[i] == edge_users_test) {
EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink");
edl->edge = med;
@@ -743,15 +815,14 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
}
}
-void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob)
+void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
/* make new mesh data from the original copy */
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_MESH);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_MESH);
ListBase nurblist = {NULL, NULL};
- bool needsFree = false;
- BKE_mesh_to_curve_nurblist(dm, &nurblist, 0);
- BKE_mesh_to_curve_nurblist(dm, &nurblist, 1);
+ BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0);
+ BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 1);
if (nurblist.first) {
Curve *cu = BKE_curve_add(bmain, ob->id.name + 2, OB_CURVE);
@@ -763,33 +834,19 @@ void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob)
ob->data = cu;
ob->type = OB_CURVE;
- /* curve objects can't contain DM in usual cases, we could free memory */
- needsFree = true;
- }
-
- dm->needsFree = needsFree;
- dm->release(dm);
-
- if (needsFree) {
- ob->derivedFinal = NULL;
-
- /* curve object could have got bounding box only in special cases */
- if (ob->bb) {
- MEM_freeN(ob->bb);
- ob->bb = NULL;
- }
+ BKE_object_free_derived_caches(ob);
}
}
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
- Main *bmain, Scene *sce, Object *ob,
- int apply_modifiers, int settings, int calc_tessface, int calc_undeformed)
+ Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob,
+ const bool apply_modifiers, const bool calc_undeformed)
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
int i;
- const bool render = (settings == eModifierMode_Render);
+ const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const bool cage = !apply_modifiers;
bool do_mat_id_data_us = true;
@@ -800,15 +857,14 @@ Mesh *BKE_mesh_new_from_object(
case OB_SURF:
{
ListBase dispbase = {NULL, NULL};
- DerivedMesh *derivedFinal = NULL;
+ Mesh *me_eval_final = NULL;
int uv_from_orco;
/* copies object and modifiers (but not the data) */
Object *tmpobj;
/* TODO: make it temp copy outside bmain! */
- BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES, false);
+ BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES | LIB_ID_CREATE_NO_DEG_TAG, false);
tmpcu = (Curve *)tmpobj->data;
- id_us_min(&tmpcu->id);
/* Copy cached display list, it might be needed by the stack evaluation.
* Ideally stack should be able to use render-time display list, but doing
@@ -816,11 +872,11 @@ Mesh *BKE_mesh_new_from_object(
*
* TODO(sergey): Look into more proper solution.
*/
- if (ob->curve_cache != NULL) {
- if (tmpobj->curve_cache == NULL) {
- tmpobj->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
+ if (ob->runtime.curve_cache != NULL) {
+ if (tmpobj->runtime.curve_cache == NULL) {
+ tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
}
- BKE_displist_copy(&tmpobj->curve_cache->disp, &ob->curve_cache->disp);
+ BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &ob->runtime.curve_cache->disp);
}
/* if getting the original caged mesh, delete object modifiers */
@@ -828,7 +884,8 @@ Mesh *BKE_mesh_new_from_object(
BKE_object_free_modifiers(tmpobj, 0);
/* copies the data */
- copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data);
+ BKE_id_copy_ex(bmain, ob->data, (ID **)&copycu, LIB_ID_CREATE_NO_DEG_TAG, false);
+ tmpobj->data = copycu;
/* make sure texture space is calculated for a copy of curve,
* it will be used for the final result.
@@ -842,16 +899,16 @@ Mesh *BKE_mesh_new_from_object(
copycu->editnurb = tmpcu->editnurb;
/* get updated display list, and convert to a mesh */
- BKE_displist_make_curveTypes_forRender(sce, tmpobj, &dispbase, &derivedFinal, false, render);
+ BKE_displist_make_curveTypes_forRender(depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, render);
copycu->editfont = NULL;
copycu->editnurb = NULL;
- tmpobj->derivedFinal = derivedFinal;
+ tmpobj->runtime.mesh_eval = me_eval_final;
/* convert object type to mesh */
uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
- BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2);
+ BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true);
tmpmesh = tmpobj->data;
@@ -861,11 +918,11 @@ Mesh *BKE_mesh_new_from_object(
* if it didn't the curve did not have any segments or otherwise
* would have generated an empty mesh */
if (tmpobj->type != OB_MESH) {
- BKE_libblock_free_us(bmain, tmpobj);
+ BKE_libblock_free(bmain, tmpobj);
return NULL;
}
- BKE_libblock_free_us(bmain, tmpobj);
+ BKE_libblock_free(bmain, tmpobj);
/* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist()
* already transfers the ownership of materials from the temp copy of the Curve ID to the new
@@ -878,7 +935,7 @@ Mesh *BKE_mesh_new_from_object(
case OB_MBALL:
{
/* metaballs don't have modifiers, so just convert to mesh */
- Object *basis_ob = BKE_mball_basis_find(bmain, bmain->eval_ctx, sce, ob);
+ Object *basis_ob = BKE_mball_basis_find(sce, ob);
/* todo, re-generatre for render-res */
/* metaball_polygonize(scene, ob) */
@@ -891,20 +948,14 @@ Mesh *BKE_mesh_new_from_object(
if (render) {
ListBase disp = {NULL, NULL};
- /* TODO(sergey): This is gonna to work for until EvaluationContext
- * only contains for_render flag. As soon as CoW is
- * implemented, this is to be rethought.
- */
- EvaluationContext eval_ctx;
- DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
- BKE_displist_make_mball_forRender(bmain, &eval_ctx, sce, ob, &disp);
+ BKE_displist_make_mball_forRender(depsgraph, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
}
else {
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
BKE_mesh_from_metaball(&disp, tmpmesh);
}
@@ -926,7 +977,7 @@ Mesh *BKE_mesh_new_from_object(
/* if not getting the original caged mesh, get final derived mesh */
else {
/* Make a dummy mesh, saves copying */
- DerivedMesh *dm;
+ Mesh *me_eval;
/* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */
CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter,
* for example, needs CD_MASK_MDEFORMVERT */
@@ -934,14 +985,15 @@ Mesh *BKE_mesh_new_from_object(
if (calc_undeformed)
mask |= CD_MASK_ORCO;
- /* Write the display mesh into the dummy mesh */
- if (render)
- dm = mesh_create_derived_render(sce, ob, mask);
- else
- dm = mesh_create_derived_view(sce, ob, mask);
+ if (render) {
+ me_eval = mesh_create_eval_final_render(depsgraph, sce, ob, mask);
+ }
+ else {
+ me_eval = mesh_create_eval_final_view(depsgraph, sce, ob, mask);
+ }
tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
- DM_to_mesh(dm, tmpmesh, ob, mask, true);
+ BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, ob, mask, true);
/* Copy autosmooth settings from original mesh. */
Mesh *me = (Mesh *)ob->data;
@@ -1019,10 +1071,345 @@ Mesh *BKE_mesh_new_from_object(
break;
} /* end copy materials */
- if (calc_tessface) {
- /* cycles and exporters rely on this still */
- BKE_mesh_tessface_ensure(tmpmesh);
+ return tmpmesh;
+}
+
+
+static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
+{
+ KeyBlock *kb;
+ Key *key = mesh_src->key;
+ int i;
+
+ if (!mesh_src->key)
+ return;
+
+ /* ensure we can use mesh vertex count for derived mesh custom data */
+ if (mesh_src->totvert != mesh_dest->totvert) {
+ fprintf(stderr,
+ "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n",
+ __func__, mesh_src->id.name + 2, mesh_src->totvert, mesh_dest->totvert);
+ return;
}
- return tmpmesh;
+ for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) {
+ int ci;
+ float *array;
+
+ if (mesh_src->totvert != kb->totelem) {
+ fprintf(stderr,
+ "%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n",
+ __func__, mesh_src->id.name + 2, mesh_src->totvert, kb->name, kb->totelem);
+ array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
+ }
+ else {
+ array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
+ memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float));
+ }
+
+ CustomData_add_layer_named(&mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name);
+ ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i);
+
+ mesh_dest->vdata.layers[ci].uid = kb->uid;
+ }
+}
+
+
+Mesh *BKE_mesh_create_derived_for_modifier(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ ModifierData *md, int build_shapekey_layers)
+{
+ Mesh *me = ob->data;
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ Mesh *result;
+ KeyBlock *kb;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
+
+ if (!(md->mode & eModifierMode_Realtime)) {
+ return NULL;
+ }
+
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
+ return NULL;
+ }
+
+ if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) {
+ BKE_keyblock_convert_to_mesh(kb, me);
+ }
+
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ int numVerts;
+ float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts);
+
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
+ BKE_id_copy_ex(
+ NULL, &me->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_mesh_apply_vert_coords(result, deformedVerts);
+
+ if (build_shapekey_layers)
+ add_shapekey_layers(result, me);
+
+ MEM_freeN(deformedVerts);
+ }
+ else {
+ Mesh *mesh_temp;
+ BKE_id_copy_ex(
+ NULL, &me->id, (ID **)&mesh_temp,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+
+ if (build_shapekey_layers)
+ add_shapekey_layers(mesh_temp, me);
+
+ result = mti->applyModifier(md, &mectx, mesh_temp);
+ ASSERT_IS_VALID_MESH(result);
+
+ if (mesh_temp != result) {
+ BKE_id_free(NULL, mesh_temp);
+ }
+ }
+
+ return result;
+}
+
+/* This is a Mesh-based copy of the same function in DerivedMesh.c */
+static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid)
+{
+ KeyBlock *kb;
+ int i, j, tot;
+
+ if (!mesh_dst->key)
+ return;
+
+ tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY);
+ for (i = 0; i < tot; i++) {
+ CustomDataLayer *layer = &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
+ float (*cos)[3], (*kbcos)[3];
+
+ for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ if (kb->uid == layer->uid)
+ break;
+ }
+
+ if (!kb) {
+ kb = BKE_keyblock_add(mesh_dst->key, layer->name);
+ kb->uid = layer->uid;
+ }
+
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
+ kb->totelem = mesh_src->totvert;
+
+ kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
+ if (kb->uid == actshape_uid) {
+ MVert *mvert = mesh_src->mvert;
+
+ for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) {
+ copy_v3_v3(*kbcos, mvert->co);
+ }
+ }
+ else {
+ for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
+ copy_v3_v3(*kbcos, *cos);
+ }
+ }
+ }
+
+ for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ if (kb->totelem != mesh_src->totvert) {
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ kb->totelem = mesh_src->totvert;
+ kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
+ fprintf(stderr, "%s: lost a shapekey layer: '%s'! (bmesh internal error)\n", __func__, kb->name);
+ }
+ }
+}
+
+
+/* This is a Mesh-based copy of DM_to_mesh() */
+void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership)
+{
+ /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
+ /* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */
+ Mesh tmp = *mesh_dst;
+ int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
+ int did_shapekeys = 0;
+ eCDAllocType alloctype = CD_DUPLICATE;
+
+ if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
+ bool has_any_referenced_layers =
+ CustomData_has_referenced(&mesh_src->vdata) ||
+ CustomData_has_referenced(&mesh_src->edata) ||
+ CustomData_has_referenced(&mesh_src->ldata) ||
+ CustomData_has_referenced(&mesh_src->fdata) ||
+ CustomData_has_referenced(&mesh_src->pdata);
+ if (!has_any_referenced_layers) {
+ alloctype = CD_ASSIGN;
+ }
+ }
+ CustomData_reset(&tmp.vdata);
+ CustomData_reset(&tmp.edata);
+ CustomData_reset(&tmp.fdata);
+ CustomData_reset(&tmp.ldata);
+ CustomData_reset(&tmp.pdata);
+
+ BKE_mesh_ensure_normals(mesh_src);
+
+ totvert = tmp.totvert = mesh_src->totvert;
+ totedge = tmp.totedge = mesh_src->totedge;
+ totloop = tmp.totloop = mesh_src->totloop;
+ totpoly = tmp.totpoly = mesh_src->totpoly;
+ tmp.totface = 0;
+
+ CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask, alloctype, totvert);
+ CustomData_copy(&mesh_src->edata, &tmp.edata, mask, alloctype, totedge);
+ CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask, alloctype, totloop);
+ CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask, alloctype, totpoly);
+ tmp.cd_flag = mesh_src->cd_flag;
+ tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
+
+ if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
+ KeyBlock *kb;
+ int uid;
+
+ if (ob) {
+ kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1);
+ if (kb) {
+ uid = kb->uid;
+ }
+ else {
+ printf("%s: error - could not find active shapekey %d!\n",
+ __func__, ob->shapenr - 1);
+
+ uid = INT_MAX;
+ }
+ }
+ else {
+ /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
+ uid = INT_MAX;
+ }
+
+ shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
+ did_shapekeys = 1;
+ }
+
+ /* copy texture space */
+ if (ob) {
+ BKE_mesh_texspace_copy_from_object(&tmp, ob);
+ }
+
+ /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
+ * we set them here in case they are missing */
+ /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and always directly pass mesh_src->mxxx,
+ * instead of using a ternary operator. */
+ if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) {
+ CustomData_add_layer(
+ &tmp.vdata, CD_MVERT, CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->mvert : MEM_dupallocN(mesh_src->mvert),
+ totvert);
+ }
+ if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) {
+ CustomData_add_layer(
+ &tmp.edata, CD_MEDGE, CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->medge : MEM_dupallocN(mesh_src->medge),
+ totedge);
+ }
+ if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
+ /* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the
+ * BKE_mesh_update_customdata_pointers() call below. */
+ tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop);
+ tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly);
+
+ CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
+ CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
+ }
+
+ /* object had got displacement layer, should copy this layer to save sculpted data */
+ /* NOTE: maybe some other layers should be copied? nazgul */
+ if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) {
+ if (totloop == mesh_dst->totloop) {
+ MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
+ CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
+ }
+ }
+
+ /* yes, must be before _and_ after tessellate */
+ BKE_mesh_update_customdata_pointers(&tmp, false);
+
+ /* since 2.65 caller must do! */
+ // BKE_mesh_tessface_calc(&tmp);
+
+ CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
+ CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
+ CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
+ CustomData_free(&mesh_dst->ldata, mesh_dst->totloop);
+ CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly);
+
+ /* ok, this should now use new CD shapekey data,
+ * which should be fed through the modifier
+ * stack */
+ if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) {
+ printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name);
+ if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
+ id_us_min(&tmp.key->id);
+ }
+ tmp.key = NULL;
+ }
+
+ /* Clear selection history */
+ MEM_SAFE_FREE(tmp.mselect);
+ tmp.totselect = 0;
+ BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb));
+ if (mesh_dst->bb) {
+ MEM_freeN(mesh_dst->bb);
+ tmp.bb = NULL;
+ }
+
+ /* skip the listbase */
+ MEMCPY_STRUCT_OFS(mesh_dst, &tmp, id.prev);
+
+ if (take_ownership) {
+ if (alloctype == CD_ASSIGN) {
+ CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask);
+ CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask);
+ CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask);
+ CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask);
+ }
+ BKE_id_free(NULL, mesh_src);
+ }
+}
+
+/* This is a Mesh-based copy of DM_to_meshkey() */
+void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
+{
+ int a, totvert = mesh_src->totvert;
+ float *fp;
+ MVert *mvert;
+
+ if (totvert == 0 || mesh_dst->totvert == 0 || mesh_dst->totvert != totvert) {
+ return;
+ }
+
+ if (kb->data) MEM_freeN(kb->data);
+ kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->totvert, "kb->data");
+ kb->totelem = totvert;
+
+ fp = kb->data;
+ mvert = mesh_src->mvert;
+
+ for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
+ copy_v3_v3(fp, mvert->co);
+ }
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index e3b1f20e583..fd117734aaf 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -88,6 +88,20 @@ static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
}
}
+/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(),
+ * and remove the function of the same name below, as that one doesn't seem to be
+ * called anywhere. */
+void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh)
+{
+ const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
+
+ BKE_mesh_calc_normals_mapping_ex(
+ mesh->mvert, mesh->totvert,
+ mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL,
+ mesh->mface, mesh->totface, NULL, NULL,
+ only_face_normals);
+}
+
/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-NULL
* and vertex normals are stored in actual mverts.
*/
@@ -332,6 +346,44 @@ void BKE_mesh_calc_normals_poly(
MEM_freeN(lnors_weighted);
}
+void BKE_mesh_ensure_normals(Mesh *mesh)
+{
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ BKE_mesh_calc_normals(mesh);
+ }
+ BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
+}
+
+/**
+ * Called after calculating all modifiers.
+ */
+void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
+{
+ /* Note: mesh *may* have a poly CD_NORMAL layer (generated by a modifier needing poly normals e.g.).
+ * We do not use it here, though. And it should be tagged as temp!
+ */
+ /* BLI_assert((CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false)); */
+
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL || !CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+ float (*poly_nors)[3] = NULL;
+ poly_nors = MEM_malloc_arrayN((size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
+
+ /* if normals are dirty we want to calculate vertex normals too */
+ bool only_face_normals = !(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL);
+
+ /* calculate face normals */
+ BKE_mesh_calc_normals_poly(
+ mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly,
+ mesh->totloop, mesh->totpoly, poly_nors,
+ only_face_normals);
+
+ CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ }
+}
+
+/* Note that this does not update the CD_NORMAL layer, but does update the normals in the CD_MVERT layer. */
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
@@ -344,6 +396,7 @@ void BKE_mesh_calc_normals(Mesh *mesh)
#ifdef DEBUG_TIME
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_tessface(
@@ -456,6 +509,8 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo
mem = lnors_spacearr->mem;
lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
+
+ lnors_spacearr->num_spaces = 0;
}
BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
lnors_spacearr->data_type = data_type;
@@ -463,21 +518,24 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
{
- BLI_memarena_clear(lnors_spacearr->mem);
+ lnors_spacearr->num_spaces = 0;
lnors_spacearr->lspacearr = NULL;
lnors_spacearr->loops_pool = NULL;
+ BLI_memarena_clear(lnors_spacearr->mem);
}
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
{
- BLI_memarena_free(lnors_spacearr->mem);
+ lnors_spacearr->num_spaces = 0;
lnors_spacearr->lspacearr = NULL;
lnors_spacearr->loops_pool = NULL;
+ BLI_memarena_free(lnors_spacearr->mem);
lnors_spacearr->mem = NULL;
}
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
{
+ lnors_spacearr->num_spaces++;
return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
}
@@ -1835,155 +1893,6 @@ void BKE_mesh_normals_loop_to_vertex(
/* -------------------------------------------------------------------- */
-/** \name Mesh Tangent Calculations
- * \{ */
-
-/* Tangent space utils. */
-
-/* User data. */
-typedef struct {
- const MPoly *mpolys; /* faces */
- const MLoop *mloops; /* faces's vertices */
- const MVert *mverts; /* vertices */
- const MLoopUV *luvs; /* texture coordinates */
- float (*lnors)[3]; /* loops' normals */
- float (*tangents)[4]; /* output tangents */
- int num_polys; /* number of polygons */
-} BKEMeshToTangent;
-
-/* Mikktspace's API */
-static int get_num_faces(const SMikkTSpaceContext *pContext)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- return p_mesh->num_polys;
-}
-
-static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- return p_mesh->mpolys[face_idx].totloop;
-}
-
-static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
- copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
-}
-
-static void get_texture_coordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
- const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
-}
-
-static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
-}
-
-static void set_tspace(
- const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
- const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
- copy_v3_v3(p_res, fv_tangent);
- p_res[3] = face_sign;
-}
-
-/**
- * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
- * split normals can be used to recreate the full tangent space.
- * Note: * The mesh should be made of only tris and quads!
- */
-void BKE_mesh_loop_tangents_ex(
- const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
- float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
- const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
- ReportList *reports)
-{
- BKEMeshToTangent mesh_to_tangent = {NULL};
- SMikkTSpaceContext s_context = {NULL};
- SMikkTSpaceInterface s_interface = {NULL};
-
- const MPoly *mp;
- int mp_index;
-
- /* First check we do have a tris/quads only mesh. */
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- if (mp->totloop > 4) {
- BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
- return;
- }
- }
-
- /* Compute Mikktspace's tangent normals. */
- mesh_to_tangent.mpolys = mpolys;
- mesh_to_tangent.mloops = mloops;
- mesh_to_tangent.mverts = mverts;
- mesh_to_tangent.luvs = loopuvs;
- mesh_to_tangent.lnors = loopnors;
- mesh_to_tangent.tangents = r_looptangent;
- mesh_to_tangent.num_polys = numPolys;
-
- s_context.m_pUserData = &mesh_to_tangent;
- s_context.m_pInterface = &s_interface;
- s_interface.m_getNumFaces = get_num_faces;
- s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
- s_interface.m_getPosition = get_position;
- s_interface.m_getTexCoord = get_texture_coordinate;
- s_interface.m_getNormal = get_normal;
- s_interface.m_setTSpaceBasic = set_tspace;
-
- /* 0 if failed */
- if (genTangSpaceDefault(&s_context) == false) {
- BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
- }
-}
-
-/**
- * Wrapper around BKE_mesh_loop_tangents_ex, which takes care of most boiling code.
- * \note
- * - There must be a valid loop's CD_NORMALS available.
- * - The mesh should be made of only tris and quads!
- */
-void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
-{
- MLoopUV *loopuvs;
- float (*loopnors)[3];
-
- /* Check we have valid texture coordinates first! */
- if (uvmap) {
- loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
- }
- else {
- loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
- }
- if (!loopuvs) {
- BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
- return;
- }
-
- loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- if (!loopnors) {
- BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
- return;
- }
-
- BKE_mesh_loop_tangents_ex(
- mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
- loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
/** \name Polygon Calculations
* \{ */
@@ -2256,30 +2165,6 @@ static float mesh_calc_poly_area_centroid(
return total_area;
}
-#if 0 /* slow version of the function below */
-void BKE_mesh_calc_poly_angles(
- MPoly *mpoly, MLoop *loopstart,
- MVert *mvarray, float angles[])
-{
- MLoop *ml;
- MLoop *mloop = &loopstart[-mpoly->loopstart];
-
- int j;
- for (j = 0, ml = loopstart; j < mpoly->totloop; j++, ml++) {
- MLoop *ml_prev = ME_POLY_LOOP_PREV(mloop, mpoly, j);
- MLoop *ml_next = ME_POLY_LOOP_NEXT(mloop, mpoly, j);
-
- float e1[3], e2[3];
-
- sub_v3_v3v3(e1, mvarray[ml_next->v].co, mvarray[ml->v].co);
- sub_v3_v3v3(e2, mvarray[ml_prev->v].co, mvarray[ml->v].co);
-
- angles[j] = (float)M_PI - angle_v3v3(e1, e2);
- }
-}
-
-#else /* equivalent the function above but avoid multiple subtractions + normalize */
-
void BKE_mesh_calc_poly_angles(
const MPoly *mpoly, const MLoop *loopstart,
const MVert *mvarray, float angles[])
@@ -2304,7 +2189,6 @@ void BKE_mesh_calc_poly_angles(
i_next++;
}
}
-#endif
void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop *mloop)
{
@@ -2556,12 +2440,12 @@ void BKE_mesh_calc_volume(
*/
void BKE_mesh_loops_to_mface_corners(
CustomData *fdata, CustomData *ldata,
- CustomData *pdata, unsigned int lindex[4], int findex,
- const int polyindex,
+ CustomData *UNUSED(pdata), unsigned int lindex[4], int findex,
+ const int UNUSED(polyindex),
const int mf_len, /* 3 or 4 */
/* cache values to avoid lookups every time */
- const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */
+ const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
@@ -2569,17 +2453,13 @@ void BKE_mesh_loops_to_mface_corners(
)
{
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
int i, j;
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
- texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
-
- ME_MTEXFACE_CPY(texface, texpoly);
for (j = 0; j < mf_len; j++) {
mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
@@ -2632,14 +2512,14 @@ void BKE_mesh_loops_to_mface_corners(
* \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used.
*/
void BKE_mesh_loops_to_tessdata(
- CustomData *fdata, CustomData *ldata, CustomData *pdata, MFace *mface,
+ CustomData *fdata, CustomData *ldata, MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
{
/* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
* Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
* this. Better imho to live with it for now. :/ --mont29
*/
- const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
@@ -2649,17 +2529,14 @@ void BKE_mesh_loops_to_tessdata(
const int *pidx;
unsigned int (*lidx)[4];
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
- MTexPoly *texpoly = CustomData_get_layer_n(pdata, CD_MTEXPOLY, i);
MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
for (findex = 0, pidx = polyindices, lidx = loopindices;
findex < num_faces;
pidx++, lidx++, findex++, texface++)
{
- ME_MTEXFACE_CPY(texface, &texpoly[*pidx]);
-
for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
}
@@ -2982,7 +2859,7 @@ int BKE_mesh_recalc_tessellation(
/* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
* they are directly tessellated from */
CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
if (do_face_nor_copy) {
/* If polys have a normals layer, copying that to faces can help
@@ -3003,7 +2880,7 @@ int BKE_mesh_recalc_tessellation(
* So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
* ...
*/
- BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, NULL, mface_to_poly_map, lindices, totface);
+ BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
/* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
* ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
@@ -3173,11 +3050,10 @@ void BKE_mesh_recalc_looptri(
}
static void bm_corners_to_loops_ex(
- ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
+ ID *id, CustomData *fdata, CustomData *ldata,
MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
{
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
@@ -3188,9 +3064,6 @@ static void bm_corners_to_loops_ex(
for (i = 0; i < numTex; i++) {
texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
- texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, findex, i);
-
- ME_MTEXFACE_CPY(texpoly, texface);
mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++;
@@ -3300,7 +3173,7 @@ void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
mesh->medge, mesh->mface,
&mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly);
- CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->pdata, &mesh->ldata);
+ CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
BKE_mesh_update_customdata_pointers(mesh, true);
}
@@ -3344,7 +3217,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(
CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
- CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly);
+ CustomData_to_bmeshpoly(fdata, ldata, totloop);
if (id) {
/* ensure external data is transferred */
@@ -3394,7 +3267,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(
# undef ML
- bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol);
+ bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
if (polyindex) {
*polyindex = i;
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
new file mode 100644
index 00000000000..73dcd912f48
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -0,0 +1,211 @@
+/*
+ * ***** 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): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_iterators.c
+ * \ingroup bke
+ *
+ * Functions for iterating mesh features.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+/* Copied from cdDM_foreachMappedVert */
+void BKE_mesh_foreach_mapped_vert(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ const MVert *mv = mesh->mvert;
+ const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv->co, NULL, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ func(userData, i, mv->co, NULL, no);
+ }
+ }
+}
+
+/* Copied from cdDM_foreachMappedEdge */
+void BKE_mesh_foreach_mapped_edge(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
+ void *userData)
+{
+ const MVert *mv = mesh->mvert;
+ const MEdge *med = mesh->medge;
+ const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv[med->v1].co, mv[med->v2].co);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ }
+ }
+}
+
+/* Copied from cdDM_foreachMappedLoop */
+void BKE_mesh_foreach_mapped_loop(
+ Mesh *mesh,
+ void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
+ * return loop data from bmesh itself. */
+ const float (*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? CustomData_get_layer(&mesh->ldata, CD_NORMAL) : NULL;
+
+ const MVert *mv = mesh->mvert;
+ const MLoop *ml = mesh->mloop;
+ const MPoly *mp = mesh->mpoly;
+ const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ int p_idx, i;
+
+ if (v_index || f_index) {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = v_index ? v_index[ml->v] : ml->v;
+ const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
+ continue;
+ }
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
+ else {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = ml->v;
+ const int f_idx = p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
+}
+
+/* Copied from cdDM_foreachMappedFaceCenter */
+void BKE_mesh_foreach_mapped_face_center(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float cent[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ const MVert *mvert = mesh->mvert;
+ const MPoly *mp = mesh->mpoly;
+ const MLoop *ml;
+ float _no_buf[3];
+ float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
+ const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, orig, cent, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, i, cent, no);
+ }
+ }
+}
+
+
+/* Helpers based on above foreach loopers> */
+
+typedef struct MappedVCosData {
+ float (*vertexcos)[3];
+ BLI_bitmap *vertex_visit;
+} MappedVCosData;
+
+static void get_vertexcos__mapFunc(
+ void *user_data, int index, const float co[3],
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
+
+ if (BLI_BITMAP_TEST(mapped_vcos_data->vertex_visit, index) == 0) {
+ /* We need coord from prototype vertex, not from copies,
+ * we assume they stored in the beginning of vertex array stored in evaluated mesh
+ * (mirror modifier for eg does this). */
+ copy_v3_v3(mapped_vcos_data->vertexcos[index], co);
+ BLI_BITMAP_ENABLE(mapped_vcos_data->vertex_visit, index);
+ }
+}
+
+void BKE_mesh_foreach_mapped_vert_coords_get(Mesh *me_eval, float (*r_cos)[3], const int totcos)
+{
+ MappedVCosData user_data;
+ memset(r_cos, 0, sizeof(*r_cos) * totcos);
+ user_data.vertexcos = r_cos;
+ user_data.vertex_visit = BLI_BITMAP_NEW(totcos, __func__);
+ BKE_mesh_foreach_mapped_vert(me_eval, get_vertexcos__mapFunc, &user_data, MESH_FOREACH_NOP);
+ MEM_freeN(user_data.vertex_visit);
+}
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
new file mode 100644
index 00000000000..5324c397ebf
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -0,0 +1,685 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_merge.c
+ * \ingroup bke
+ */
+#include <string.h> // for memcpy
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_utildefines_stack.h"
+#include "BLI_edgehash.h"
+#include "BLI_ghash.h"
+
+#include "BKE_customdata.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+
+/**
+ * Poly compare with vtargetmap
+ * Function used by #BKE_mesh_merge_verts.
+ * The function compares poly_source after applying vtargetmap, with poly_target.
+ * The two polys are identical if they share the same vertices in the same order, or in reverse order,
+ * but starting position loopstart may be different.
+ * The function is called with direct_reverse=1 for same order (i.e. same normal),
+ * and may be called again with direct_reverse=-1 for reverse order.
+ * \return 1 if polys are identical, 0 if polys are different.
+ */
+static int cddm_poly_compare(
+ MLoop *mloop_array,
+ MPoly *mpoly_source, MPoly *mpoly_target,
+ const int *vtargetmap, const int direct_reverse)
+{
+ int vert_source, first_vert_source, vert_target;
+ int i_loop_source;
+ int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted;
+ bool compare_completed = false;
+ bool same_loops = false;
+
+ MLoop *mloop_source, *mloop_target;
+
+ BLI_assert(direct_reverse == 1 || direct_reverse == -1);
+
+ i_loop_source = 0;
+ mloop_source = mloop_array + mpoly_source->loopstart;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ /* Find same vertex within mpoly_target's loops */
+ mloop_target = mloop_array + mpoly_target->loopstart;
+ for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) {
+ if (mloop_target->v == vert_source) {
+ break;
+ }
+ }
+
+ /* If same vertex not found, then polys cannot be equal */
+ if (i_loop_target >= mpoly_target->totloop) {
+ return false;
+ }
+
+ /* Now mloop_source and m_loop_target have one identical vertex */
+ /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */
+ /* Go around the loop and check that all vertices match in same order */
+ /* Skipping source loops when consecutive source vertices are mapped to same target vertex */
+
+ i_loop_target_start = i_loop_target;
+ i_loop_target_offset = 0;
+ first_vert_source = vert_source;
+
+ compare_completed = false;
+ same_loops = false;
+
+ while (!compare_completed) {
+
+ vert_target = mloop_target->v;
+
+ /* First advance i_loop_source, until it points to different vertex, after mapping applied */
+ do {
+ i_loop_source++;
+
+ if (i_loop_source == mpoly_source->totloop) {
+ /* End of loops for source, must match end of loop for target. */
+ if (i_loop_target_offset == mpoly_target->totloop - 1) {
+ compare_completed = true;
+ same_loops = true;
+ break; /* Polys are identical */
+ }
+ else {
+ compare_completed = true;
+ same_loops = false;
+ break; /* Polys are different */
+ }
+ }
+
+ mloop_source++;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ } while (vert_source == vert_target);
+
+ if (compare_completed) {
+ break;
+ }
+
+ /* Now advance i_loop_target as well */
+ i_loop_target_offset++;
+
+ if (i_loop_target_offset == mpoly_target->totloop) {
+ /* End of loops for target only, that means no match */
+ /* except if all remaining source vertices are mapped to first target */
+ for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) {
+ vert_source = vtargetmap[mloop_source->v];
+ if (vert_source != first_vert_source) {
+ compare_completed = true;
+ same_loops = false;
+ break;
+ }
+ }
+ if (!compare_completed) {
+ same_loops = true;
+ }
+ break;
+ }
+
+ /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */
+ i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop;
+ if (i_loop_target_adjusted < 0) {
+ i_loop_target_adjusted += mpoly_target->totloop;
+ }
+ mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted;
+ vert_target = mloop_target->v;
+
+ if (vert_target != vert_source) {
+ same_loops = false; /* Polys are different */
+ break;
+ }
+ }
+ return same_loops;
+}
+
+
+/* Utility stuff for using GHash with polys, used by vertex merging. */
+
+typedef struct PolyKey {
+ int poly_index; /* index of the MPoly within the derived mesh */
+ int totloops; /* number of loops in the poly */
+ unsigned int hash_sum; /* Sum of all vertices indices */
+ unsigned int hash_xor; /* Xor of all vertices indices */
+} PolyKey;
+
+
+static unsigned int poly_gset_hash_fn(const void *key)
+{
+ const PolyKey *pk = key;
+ return pk->hash_sum;
+}
+
+static bool poly_gset_compare_fn(const void *k1, const void *k2)
+{
+ const PolyKey *pk1 = k1;
+ const PolyKey *pk2 = k2;
+ if ((pk1->hash_sum == pk2->hash_sum) &&
+ (pk1->hash_xor == pk2->hash_xor) &&
+ (pk1->totloops == pk2->totloops))
+ {
+ /* Equality - note that this does not mean equality of polys */
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+/**
+ * Merge Verts
+ *
+ * This frees the given mesh and returns a new mesh.
+ *
+ * \param vtargetmap The table that maps vertices to target vertices. a value of -1
+ * indicates a vertex is a target, and is to be kept.
+ * This array is aligned with 'mesh->totvert'
+ * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported
+ * and will likely generate corrupted geometry.
+ *
+ * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size)
+ *
+ * \param merge_mode enum with two modes.
+ * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
+ * When called by the Mirror Modifier,
+ * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
+ * of faces sharing the same set of vertices)
+ * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
+ * When called by the Array Modifier,
+ * In this mode, faces where all vertices are merged are double-checked,
+ * to see whether all target vertices actually make up a poly already.
+ * Indeed it could be that all of a poly's vertices are merged,
+ * but merged to vertices that do not make up a single poly,
+ * in which case the original poly should not be dumped.
+ * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are
+ * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror.
+ *
+ * \note #BKE_mesh_recalc_tessellation has to run on the returned DM if you want to access tessfaces.
+ */
+Mesh *BKE_mesh_merge_verts(Mesh *mesh, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
+{
+ /* This was commented out back in 2013, see commit f45d8827bafe6b9eaf9de42f4054e9d84a21955d. */
+// #define USE_LOOPS
+
+ Mesh *result = NULL;
+
+ const int totvert = mesh->totvert;
+ const int totedge = mesh->totedge;
+ const int totloop = mesh->totloop;
+ const int totpoly = mesh->totpoly;
+
+ const int totvert_final = totvert - tot_vtargetmap;
+
+ MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__);
+ int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__);
+ int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__);
+ STACK_DECLARE(mvert);
+ STACK_DECLARE(oldv);
+
+ /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
+ * generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
+ * cases can be forged that would end requiring more... */
+ MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__);
+ int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__);
+ int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__);
+ STACK_DECLARE(medge);
+ STACK_DECLARE(olde);
+
+ MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__);
+ int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__);
+#ifdef USE_LOOPS
+ int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__);
+#endif
+ STACK_DECLARE(mloop);
+ STACK_DECLARE(oldl);
+
+ MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__);
+ int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__);
+ STACK_DECLARE(mpoly);
+ STACK_DECLARE(oldp);
+
+ EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
+
+ int i, j, c;
+
+ PolyKey *poly_keys;
+ GSet *poly_gset = NULL;
+ MeshElemMap *poly_map = NULL;
+ int *poly_map_mem = NULL;
+
+ STACK_INIT(oldv, totvert_final);
+ STACK_INIT(olde, totedge);
+ STACK_INIT(oldl, totloop);
+ STACK_INIT(oldp, totpoly);
+
+ STACK_INIT(mvert, totvert_final);
+ STACK_INIT(medge, totedge);
+ STACK_INIT(mloop, totloop);
+ STACK_INIT(mpoly, totpoly);
+
+ /* fill newv with destination vertex indices */
+ mv = mesh->mvert;
+ c = 0;
+ for (i = 0; i < totvert; i++, mv++) {
+ if (vtargetmap[i] == -1) {
+ STACK_PUSH(oldv, i);
+ STACK_PUSH(mvert, *mv);
+ newv[i] = c++;
+ }
+ else {
+ /* dummy value */
+ newv[i] = 0;
+ }
+ }
+
+ /* now link target vertices to destination indices */
+ for (i = 0; i < totvert; i++) {
+ if (vtargetmap[i] != -1) {
+ newv[i] = newv[vtargetmap[i]];
+ }
+ }
+
+ /* Don't remap vertices in cddm->mloop, because we need to know the original
+ * indices in order to skip faces with all vertices merged.
+ * The "update loop indices..." section further down remaps vertices in mloop.
+ */
+
+ /* now go through and fix edges and faces */
+ med = mesh->medge;
+ c = 0;
+ for (i = 0; i < totedge; i++, med++) {
+ const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ if (LIKELY(v1 != v2)) {
+ void **val_p;
+
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ newe[i] = POINTER_AS_INT(*val_p);
+ }
+ else {
+ STACK_PUSH(olde, i);
+ STACK_PUSH(medge, *med);
+ newe[i] = c;
+ *val_p = POINTER_FROM_INT(c);
+ c++;
+ }
+ }
+ else {
+ newe[i] = -1;
+ }
+ }
+
+ if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* In this mode, we need to determine, whenever a poly' vertices are all mapped */
+ /* if the targets already make up a poly, in which case the new poly is dropped */
+ /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
+ PolyKey *mpgh;
+ poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__);
+ poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
+ /* Duplicates allowed because our compare function is not pure equality */
+ BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
+
+ mp = mesh->mpoly;
+ mpgh = poly_keys;
+ for (i = 0; i < totpoly; i++, mp++, mpgh++) {
+ mpgh->poly_index = i;
+ mpgh->totloops = mp->totloop;
+ ml = mesh->mloop + mp->loopstart;
+ mpgh->hash_sum = mpgh->hash_xor = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ mpgh->hash_sum += ml->v;
+ mpgh->hash_xor ^= ml->v;
+ }
+ BLI_gset_insert(poly_gset, mpgh);
+ }
+
+ /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */
+ /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */
+ BKE_mesh_vert_poly_map_create(
+ &poly_map, &poly_map_mem,
+ mesh->mpoly, mesh->mloop,
+ totvert, totpoly, totloop);
+ } /* done preparing for fast poly compare */
+
+
+ mp = mesh->mpoly;
+ mv = mesh->mvert;
+ for (i = 0; i < totpoly; i++, mp++) {
+ MPoly *mp_new;
+
+ ml = mesh->mloop + mp->loopstart;
+
+ /* check faces with all vertices merged */
+ bool all_vertices_merged = true;
+
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ if (vtargetmap[ml->v] == -1) {
+ all_vertices_merged = false;
+ /* This will be used to check for poly using several time the same vert. */
+ mv[ml->v].flag &= ~ME_VERT_TMP_TAG;
+ }
+ else {
+ /* This will be used to check for poly using several time the same vert. */
+ mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG;
+ }
+ }
+
+ if (UNLIKELY(all_vertices_merged)) {
+ if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_MAPPED) {
+ /* In this mode, all vertices merged is enough to dump face */
+ continue;
+ }
+ else if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* Additional condition for face dump: target vertices must make up an identical face */
+ /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
+ /* (2) second step is thorough but more costly poly compare */
+ int i_poly, v_target;
+ bool found = false;
+ PolyKey pkey;
+
+ /* Use poly_gset for fast (although not 100% certain) identification of same poly */
+ /* First, make up a poly_summary structure */
+ ml = mesh->mloop + mp->loopstart;
+ pkey.hash_sum = pkey.hash_xor = 0;
+ pkey.totloops = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
+ pkey.hash_sum += v_target;
+ pkey.hash_xor ^= v_target;
+ pkey.totloops++;
+ }
+ if (BLI_gset_haskey(poly_gset, &pkey)) {
+
+ /* There might be a poly that matches this one.
+ * We could just leave it there and say there is, and do a "continue".
+ * ... but we are checking whether there is an exact poly match.
+ * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
+ */
+
+ /* Consider current loop again */
+ ml = mesh->mloop + mp->loopstart;
+ /* Consider the target of the loop's first vert */
+ v_target = vtargetmap[ml->v];
+ /* Now see if v_target belongs to a poly that shares all vertices with source poly,
+ * in same order, or reverse order */
+
+ for (i_poly = 0; i_poly < poly_map[v_target].count; i_poly++) {
+ MPoly *target_poly = mesh->mpoly + *(poly_map[v_target].indices + i_poly);
+
+ if (cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, +1) ||
+ cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, -1))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ /* Current poly's vertices are mapped to a poly that is strictly identical */
+ /* Current poly is dumped */
+ continue;
+ }
+ }
+ }
+ }
+
+
+ /* Here either the poly's vertices were not all merged
+ * or they were all merged, but targets do not make up an identical poly,
+ * the poly is retained.
+ */
+ ml = mesh->mloop + mp->loopstart;
+
+ c = 0;
+ MLoop *last_valid_ml = NULL;
+ MLoop *first_valid_ml = NULL;
+ bool need_edge_from_last_valid_ml = false;
+ bool need_edge_to_first_valid_ml = false;
+ int created_edges = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v;
+#ifndef NDEBUG
+ {
+ MLoop *next_ml = mesh->mloop + mp->loopstart + ((j + 1) % mp->totloop);
+ uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v;
+ med = mesh->medge + ml->e;
+ uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1));
+ }
+#endif
+ /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */
+ if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) {
+ mv[mlv].flag |= ME_VERT_TMP_TAG;
+
+ if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) {
+ /* We need to create a new edge between last valid loop and this one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
+ uint v2 = mlv;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = POINTER_AS_INT(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = POINTER_FROM_INT(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_from_last_valid_ml = false;
+ }
+
+#ifdef USE_LOOPS
+ newl[j + mp->loopstart] = STACK_SIZE(mloop);
+#endif
+ STACK_PUSH(oldl, j + mp->loopstart);
+ last_valid_ml = STACK_PUSH_RET_PTR(mloop);
+ *last_valid_ml = *ml;
+ if (first_valid_ml == NULL) {
+ first_valid_ml = last_valid_ml;
+ }
+ c++;
+
+ /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges
+ * in that part of code make remapping later totally unreliable. */
+ BLI_assert(newe[ml->e] != -1);
+ last_valid_ml->e = newe[ml->e];
+ }
+ else {
+ if (last_valid_ml != NULL) {
+ need_edge_from_last_valid_ml = true;
+ }
+ else {
+ need_edge_to_first_valid_ml = true;
+ }
+ }
+ }
+ if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) &&
+ (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml)))
+ {
+ /* We need to create a new edge between last valid loop and first valid one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
+ uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = POINTER_AS_INT(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = first_valid_ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = POINTER_FROM_INT(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false;
+ }
+
+ if (UNLIKELY(c == 0)) {
+ BLI_assert(created_edges == 0);
+ continue;
+ }
+ else if (UNLIKELY(c < 3)) {
+ STACK_DISCARD(oldl, c);
+ STACK_DISCARD(mloop, c);
+ if (created_edges > 0) {
+ for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) {
+ BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL);
+ }
+ STACK_DISCARD(olde, created_edges);
+ STACK_DISCARD(medge, created_edges);
+ }
+ continue;
+ }
+
+ mp_new = STACK_PUSH_RET_PTR(mpoly);
+ *mp_new = *mp;
+ mp_new->totloop = c;
+ BLI_assert(mp_new->totloop >= 3);
+ mp_new->loopstart = STACK_SIZE(mloop) - c;
+
+ STACK_PUSH(oldp, i);
+ } /* end of the loop that tests polys */
+
+
+ if (poly_gset) {
+ // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset));
+
+ BLI_gset_free(poly_gset, NULL);
+ MEM_freeN(poly_keys);
+ }
+
+ /*create new cddm*/
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly));
+
+ /*update edge indices and copy customdata*/
+ med = medge;
+ for (i = 0; i < result->totedge; i++, med++) {
+ BLI_assert(newv[med->v1] != -1);
+ med->v1 = newv[med->v1];
+ BLI_assert(newv[med->v2] != -1);
+ med->v2 = newv[med->v2];
+
+ /* Can happen in case vtargetmap contains some double chains, we do not support that. */
+ BLI_assert(med->v1 != med->v2);
+
+ CustomData_copy_data(&mesh->edata, &result->edata, olde[i], i, 1);
+ }
+
+ /*update loop indices and copy customdata*/
+ ml = mloop;
+ for (i = 0; i < result->totloop; i++, ml++) {
+ /* Edge remapping has already be done in main loop handling part above. */
+ BLI_assert(newv[ml->v] != -1);
+ ml->v = newv[ml->v];
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, oldl[i], i, 1);
+ }
+
+ /*copy vertex customdata*/
+ mv = mvert;
+ for (i = 0; i < result->totvert; i++, mv++) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, oldv[i], i, 1);
+ }
+
+ /*copy poly customdata*/
+ mp = mpoly;
+ for (i = 0; i < result->totpoly; i++, mp++) {
+ CustomData_copy_data(&mesh->pdata, &result->pdata, oldp[i], i, 1);
+ }
+
+ /*copy over data. CustomData_add_layer can do this, need to look it up.*/
+ memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
+ memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
+ memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
+ memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
+
+ MEM_freeN(mvert);
+ MEM_freeN(medge);
+ MEM_freeN(mloop);
+ MEM_freeN(mpoly);
+
+ MEM_freeN(newv);
+ MEM_freeN(newe);
+#ifdef USE_LOOPS
+ MEM_freeN(newl);
+#endif
+
+ MEM_freeN(oldv);
+ MEM_freeN(olde);
+ MEM_freeN(oldl);
+ MEM_freeN(oldp);
+
+ BLI_edgehash_free(ehash, NULL);
+
+ if (poly_map != NULL)
+ MEM_freeN(poly_map);
+ if (poly_map_mem != NULL)
+ MEM_freeN(poly_map_mem);
+
+ BKE_id_free(NULL, mesh);
+
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 62c81bf8cba..bdf5b3fddcc 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -41,10 +42,10 @@
#include "BKE_bvhutils.h"
#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h" /* own include */
+#include "BKE_mesh_runtime.h"
#include "BLI_strict_flags.h"
@@ -121,8 +122,8 @@ static bool mesh_remap_bvhtree_query_raycast(
* In other words, beyond a certain (relatively small) distance, all differences have more or less the same weight
* in final result, which allows to reduce influence of a few high differences, in favor of a global good matching.
*/
-float BKE_mesh_remap_calc_difference_from_dm(
- const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, DerivedMesh *dm_src)
+float BKE_mesh_remap_calc_difference_from_mesh(
+ const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, Mesh *me_src)
{
BVHTreeFromMesh treedata = {NULL};
BVHTreeNearest nearest = {0};
@@ -131,7 +132,7 @@ float BKE_mesh_remap_calc_difference_from_dm(
float result = 0.0f;
int i;
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -250,8 +251,8 @@ static void mesh_calc_eigen_matrix(
/**
* Set r_space_transform so that best bbox of dst matches best bbox of src.
*/
-void BKE_mesh_remap_find_best_match_from_dm(
- const MVert *verts_dst, const int numverts_dst, DerivedMesh *dm_src, SpaceTransform *r_space_transform)
+void BKE_mesh_remap_find_best_match_from_mesh(
+ const MVert *verts_dst, const int numverts_dst, Mesh *me_src, SpaceTransform *r_space_transform)
{
/* Note that those are done so that we successively get actual mirror matrix (by multiplication of columns)... */
const float mirrors[][3] = {
@@ -269,15 +270,14 @@ void BKE_mesh_remap_find_best_match_from_dm(
float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4];
float best_match = FLT_MAX, match;
- const int numverts_src = dm_src->getNumVerts(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)numverts_src, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ const int numverts_src = me_src->totvert;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
mesh_calc_eigen_matrix(NULL, (const float (*)[3])vcos_src, numverts_src, mat_src);
mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst);
BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
- match = BKE_mesh_remap_calc_difference_from_dm(r_space_transform, verts_dst, numverts_dst, dm_src);
+ match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src);
best_match = match;
copy_m4_m4(best_mat_dst, mat_dst);
@@ -288,7 +288,7 @@ void BKE_mesh_remap_find_best_match_from_dm(
mul_v3_fl(mat_dst[2], (*mirr)[2]);
BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
- match = BKE_mesh_remap_calc_difference_from_dm(r_space_transform, verts_dst, numverts_dst, dm_src);
+ match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src);
if (match < best_match) {
best_match = match;
copy_m4_m4(best_mat_dst, mat_dst);
@@ -430,9 +430,9 @@ typedef struct IslandResult {
/* Will be enough in 99% of cases. */
#define MREMAP_DEFAULT_BUFSIZE 32
-void BKE_mesh_remap_calc_verts_from_dm(
+void BKE_mesh_remap_calc_verts_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
- const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src,
+ const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), Mesh *me_src,
MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -444,7 +444,7 @@ void BKE_mesh_remap_calc_verts_from_dm(
BKE_mesh_remap_init(r_map, numverts_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numverts_dst == dm_src->getNumVerts(dm_src));
+ BLI_assert(numverts_dst == me_src->totvert);
for (i = 0; i < numverts_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -457,7 +457,7 @@ void BKE_mesh_remap_calc_verts_from_dm(
float tmp_co[3], tmp_no[3];
if (mode == MREMAP_MODE_VERT_NEAREST) {
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -478,11 +478,10 @@ void BKE_mesh_remap_calc_verts_from_dm(
}
}
else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) {
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ MEdge *edges_src = me_src->medge;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -530,18 +529,16 @@ void BKE_mesh_remap_calc_verts_from_dm(
else if (ELEM(mode, MREMAP_MODE_VERT_POLY_NEAREST, MREMAP_MODE_VERT_POLYINTERP_NEAREST,
MREMAP_MODE_VERT_POLYINTERP_VNORPROJ))
{
- MPoly *polys_src = dm_src->getPolyArray(dm_src);
- MLoop *loops_src = dm_src->getLoopArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ MPoly *polys_src = me_src->mpoly;
+ MLoop *loops_src = me_src->mloop;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
float (*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__);
float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
-
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
@@ -625,10 +622,10 @@ void BKE_mesh_remap_calc_verts_from_dm(
}
}
-void BKE_mesh_remap_calc_edges_from_dm(
+void BKE_mesh_remap_calc_edges_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
const MVert *verts_dst, const int numverts_dst, const MEdge *edges_dst, const int numedges_dst,
- const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src, MeshPairRemap *r_map)
+ const bool UNUSED(dirty_nors_dst), Mesh *me_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
@@ -639,7 +636,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
BKE_mesh_remap_init(r_map, numedges_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numedges_dst == dm_src->getNumEdges(dm_src));
+ BLI_assert(numedges_dst == me_src->totedge);
for (i = 0; i < numedges_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -652,10 +649,10 @@ void BKE_mesh_remap_calc_edges_from_dm(
float tmp_co[3], tmp_no[3];
if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
- const int num_verts_src = dm_src->getNumVerts(dm_src);
- const int num_edges_src = dm_src->getNumEdges(dm_src);
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ const int num_verts_src = me_src->totvert;
+ const int num_edges_src = me_src->totedge;
+ MEdge *edges_src = me_src->medge;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
MeshElemMap *vert_to_edge_src_map;
int *vert_to_edge_src_map_mem;
@@ -673,9 +670,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
&vert_to_edge_src_map, &vert_to_edge_src_map_mem,
edges_src, num_verts_src, num_edges_src);
- dm_src->getVertCos(dm_src, vcos_src);
-
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numedges_dst; i++) {
@@ -775,7 +770,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
MEM_freeN(vert_to_edge_src_map_mem);
}
else if (mode == MREMAP_MODE_EDGE_NEAREST) {
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
nearest.index = -1;
for (i = 0; i < numedges_dst; i++) {
@@ -796,13 +791,12 @@ void BKE_mesh_remap_calc_edges_from_dm(
}
}
else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) {
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- MPoly *polys_src = dm_src->getPolyArray(dm_src);
- MLoop *loops_src = dm_src->getLoopArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ MEdge *edges_src = me_src->medge;
+ MPoly *polys_src = me_src->mpoly;
+ MLoop *loops_src = me_src->mloop;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
- dm_src->getVertCos(dm_src, vcos_src);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
for (i = 0; i < numedges_dst; i++) {
interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
@@ -821,9 +815,9 @@ void BKE_mesh_remap_calc_edges_from_dm(
int best_eidx_src = -1;
for (; nloops--; ml_src++) {
- MEdge *me_src = &edges_src[ml_src->e];
- float *co1_src = vcos_src[me_src->v1];
- float *co2_src = vcos_src[me_src->v2];
+ MEdge *med_src = &edges_src[ml_src->e];
+ float *co1_src = vcos_src[med_src->v1];
+ float *co2_src = vcos_src[med_src->v2];
float co_src[3];
float dist_sq;
@@ -848,14 +842,14 @@ void BKE_mesh_remap_calc_edges_from_dm(
}
else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) {
const int num_rays_min = 5, num_rays_max = 100;
- const int numedges_src = dm_src->getNumEdges(dm_src);
+ const int numedges_src = me_src->totedge;
/* Subtleness - this one we can allocate only max number of cast rays per edges! */
int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max), __func__);
/* Here it's simpler to just allocate for all edges :/ */
float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
for (i = 0; i < numedges_dst; i++) {
/* For each dst edge, we sample some rays from it (interpolated from its vertices)
@@ -1108,13 +1102,13 @@ static float mesh_remap_calc_loops_astar_f_cost(
#define ASTAR_STEPS_MAX 64
-void BKE_mesh_remap_calc_loops_from_dm(
+void BKE_mesh_remap_calc_loops_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst,
MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst,
CustomData *ldata_dst, CustomData *pdata_dst,
const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
- DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
+ Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -1129,7 +1123,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (mode == MREMAP_MODE_TOPOLOGY) {
/* In topology mapping, we assume meshes are identical, islands included! */
- BLI_assert(numloops_dst == dm_src->getNumLoops(dm_src));
+ BLI_assert(numloops_dst == me_src->totloop);
for (i = 0; i < numloops_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -1172,19 +1166,15 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Unlike above, those are one-to-one mappings, simpler! */
int *loop_to_poly_map_src = NULL;
- bool verts_allocated_src;
- MVert *verts_src = DM_get_vert_array(dm_src, &verts_allocated_src);
- const int num_verts_src = dm_src->getNumVerts(dm_src);
+ MVert *verts_src = me_src->mvert;
+ const int num_verts_src = me_src->totvert;
float (*vcos_src)[3] = NULL;
- bool edges_allocated_src;
- MEdge *edges_src = DM_get_edge_array(dm_src, &edges_allocated_src);
- const int num_edges_src = dm_src->getNumEdges(dm_src);
- bool loops_allocated_src;
- MLoop *loops_src = DM_get_loop_array(dm_src, &loops_allocated_src);
- const int num_loops_src = dm_src->getNumLoops(dm_src);
- bool polys_allocated_src;
- MPoly *polys_src = DM_get_poly_array(dm_src, &polys_allocated_src);
- const int num_polys_src = dm_src->getNumPolys(dm_src);
+ MEdge *edges_src = me_src->medge;
+ const int num_edges_src = me_src->totedge;
+ MLoop *loops_src = me_src->mloop;
+ const int num_loops_src = me_src->totloop;
+ MPoly *polys_src = me_src->mpoly;
+ const int num_polys_src = me_src->totpoly;
const MLoopTri *looptri_src = NULL;
int num_looptri_src = 0;
@@ -1201,8 +1191,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE;
if (!use_from_vert) {
- vcos_src = MEM_mallocN(sizeof(*vcos_src) * (size_t)num_verts_src, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ vcos_src = BKE_mesh_vertexCos_get(me_src, NULL);
vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__);
indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__);
@@ -1218,11 +1207,12 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (need_pnors_dst) {
/* Cache poly nors into a temp CDLayer. */
poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ const bool do_poly_nors_dst = (poly_nors_dst == NULL);
if (!poly_nors_dst) {
poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- if (dirty_nors_dst) {
+ if (dirty_nors_dst || do_poly_nors_dst) {
BKE_mesh_calc_normals_poly(
verts_dst, NULL, numverts_dst, loops_dst, polys_dst,
numloops_dst, numpolys_dst, poly_nors_dst, true);
@@ -1233,11 +1223,12 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Cache poly nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- if (dirty_nors_dst || !loop_nors_dst) {
- if (!loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
+ const bool do_loop_nors_dst = (loop_nors_dst == NULL);
+ if (!loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(
verts_dst, numverts_dst, edges_dst, numedges_dst,
loops_dst, loop_nors_dst, numloops_dst,
@@ -1247,13 +1238,17 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
if (need_pnors_src || need_lnors_src) {
/* Simpler for now, calcNormals never stores pnors :( */
- dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
+ if (!CustomData_has_layer(&me_src->pdata, CD_NORMAL)) {
+ CustomData_add_layer(&me_src->pdata, CD_NORMAL, CD_CALLOC, NULL, me_src->totpoly);
+ CustomData_set_layer_flag(&me_src->pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ BKE_mesh_calc_normals_split(me_src);
if (need_pnors_src) {
- poly_nors_src = dm_src->getPolyDataArray(dm_src, CD_NORMAL);
+ poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL);
}
if (need_lnors_src) {
- loop_nors_src = dm_src->getLoopDataArray(dm_src, CD_NORMAL);
+ loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
}
}
}
@@ -1352,38 +1347,25 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
}
- /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
bvhtree_from_mesh_verts_ex(
- &treedata[tindex], verts_src, num_verts_src, verts_allocated_src,
+ &treedata[tindex], verts_src, num_verts_src, false,
verts_active, num_verts_active, 0.0, 2, 6);
- if (verts_allocated_src) {
- verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */
- }
}
MEM_freeN(verts_active);
}
else {
BLI_assert(num_trees == 1);
- bvhtree_from_mesh_get(&treedata[0], dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2);
}
}
else { /* We use polygons. */
if (use_islands) {
/* bvhtree here uses looptri faces... */
- const unsigned int dirty_tess_flag = dm_src->dirty & DM_DIRTY_TESS_CDLAYERS;
BLI_bitmap *looptri_active;
- /* We do not care about tessellated data here, only geometry itself is important. */
- if (dirty_tess_flag) {
- dm_src->dirty &= ~dirty_tess_flag;
- }
- if (dirty_tess_flag) {
- dm_src->dirty |= dirty_tess_flag;
- }
-
- looptri_src = dm_src->getLoopTriArray(dm_src);
- num_looptri_src = dm_src->getNumLoopTri(dm_src);
+ looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
+ num_looptri_src = me_src->runtime.looptris.len;
looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
for (tindex = 0; tindex < num_trees; tindex++) {
@@ -1396,26 +1378,19 @@ void BKE_mesh_remap_calc_loops_from_dm(
num_looptri_active++;
}
}
- /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */
bvhtree_from_mesh_looptri_ex(
&treedata[tindex],
- verts_src, verts_allocated_src,
- loops_src, loops_allocated_src,
+ verts_src, false,
+ loops_src, false,
looptri_src, num_looptri_src, false,
looptri_active, num_looptri_active, 0.0, 2, 6);
- if (verts_allocated_src) {
- verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */
- }
- if (loops_allocated_src) {
- loops_allocated_src = false; /* Only 'give' our loops once, to first tree! */
- }
}
MEM_freeN(looptri_active);
}
else {
BLI_assert(num_trees == 1);
- bvhtree_from_mesh_get(&treedata[0], dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2);
}
}
@@ -1918,21 +1893,9 @@ void BKE_mesh_remap_calc_loops_from_dm(
BLI_astar_solution_free(&as_solution);
}
- if (verts_allocated_src) {
- MEM_freeN(verts_src);
- }
if (vcos_src) {
MEM_freeN(vcos_src);
}
- if (edges_allocated_src) {
- MEM_freeN(edges_src);
- }
- if (loops_allocated_src) {
- MEM_freeN(loops_src);
- }
- if (polys_allocated_src) {
- MEM_freeN(polys_src);
- }
if (vert_to_loop_map_src) {
MEM_freeN(vert_to_loop_map_src);
}
@@ -1975,11 +1938,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
-void BKE_mesh_remap_calc_polys_from_dm(
+void BKE_mesh_remap_calc_polys_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
MVert *verts_dst, const int numverts_dst, MLoop *loops_dst, const int numloops_dst,
MPoly *polys_dst, const int numpolys_dst, CustomData *pdata_dst, const bool dirty_nors_dst,
- DerivedMesh *dm_src, MeshPairRemap *r_map)
+ Mesh *me_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
@@ -2006,7 +1969,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BKE_mesh_remap_init(r_map, numpolys_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numpolys_dst == dm_src->getNumPolys(dm_src));
+ BLI_assert(numpolys_dst == me_src->totpoly);
for (i = 0; i < numpolys_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -2017,7 +1980,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BVHTreeRayHit rayhit = {0};
float hit_dist;
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
if (mode == MREMAP_MODE_POLY_NEAREST) {
nearest.index = -1;
@@ -2082,7 +2045,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
*/
RNG *rng = BLI_rng_new(0);
- const size_t numpolys_src = (size_t)dm_src->getNumPolys(dm_src);
+ const size_t numpolys_src = (size_t)me_src->totpoly;
/* Here it's simpler to just allocate for all polys :/ */
int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__);
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
new file mode 100644
index 00000000000..0931318f17a
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -0,0 +1,380 @@
+/*
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_runtime.c
+ * \ingroup bke
+ */
+
+#include "atomic_ops.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_geom.h"
+#include "BLI_threads.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_shrinkwrap.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Runtime Struct Utils
+ * \{ */
+
+static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/**
+ * Default values defined at read time.
+ */
+void BKE_mesh_runtime_reset(Mesh *mesh)
+{
+ memset(&mesh->runtime, 0, sizeof(mesh->runtime));
+}
+
+void BKE_mesh_runtime_clear_cache(Mesh *mesh)
+{
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_mesh_batch_cache_free(mesh);
+ BKE_mesh_runtime_clear_edit_data(mesh);
+}
+
+/* This is a ported copy of DM_ensure_looptri_data(dm) */
+/**
+ * Ensure the array is large enough
+ *
+ * /note This function must always be thread-protected by caller. It should only be used by internal code.
+ */
+static void mesh_ensure_looptri_data(Mesh *mesh)
+{
+ const unsigned int totpoly = mesh->totpoly;
+ const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
+
+ BLI_assert(mesh->runtime.looptris.array_wip == NULL);
+
+ SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+
+ if ((looptris_len > mesh->runtime.looptris.len_alloc) ||
+ (looptris_len < mesh->runtime.looptris.len_alloc * 2) ||
+ (totpoly == 0))
+ {
+ MEM_SAFE_FREE(mesh->runtime.looptris.array_wip);
+ mesh->runtime.looptris.len_alloc = 0;
+ mesh->runtime.looptris.len = 0;
+ }
+
+ if (totpoly) {
+ if (mesh->runtime.looptris.array_wip == NULL) {
+ mesh->runtime.looptris.array_wip = MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__);
+ mesh->runtime.looptris.len_alloc = looptris_len;
+ }
+
+ mesh->runtime.looptris.len = looptris_len;
+ }
+}
+
+/* This is a ported copy of CDDM_recalc_looptri(dm). */
+void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
+{
+ mesh_ensure_looptri_data(mesh);
+ BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != NULL);
+
+ BKE_mesh_recalc_looptri(
+ mesh->mloop, mesh->mpoly,
+ mesh->mvert,
+ mesh->totloop, mesh->totpoly,
+ mesh->runtime.looptris.array_wip);
+
+ BLI_assert(mesh->runtime.looptris.array == NULL);
+ atomic_cas_ptr((void **)&mesh->runtime.looptris.array, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+ mesh->runtime.looptris.array_wip = NULL;
+}
+
+/* This is a ported copy of dm_getNumLoopTri(dm). */
+int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
+{
+ const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
+ BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
+ return looptri_len;
+}
+
+/* This is a ported copy of dm_getLoopTriArray(dm). */
+const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh)
+{
+ MLoopTri *looptri;
+
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
+ looptri = mesh->runtime.looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+
+ if (looptri != NULL) {
+ BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
+ }
+ else {
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
+ /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
+ * recomputed those looptris. */
+ if (mesh->runtime.looptris.array == NULL) {
+ BKE_mesh_runtime_looptri_recalc(mesh);
+ }
+ looptri = mesh->runtime.looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+ }
+ return looptri;
+}
+
+/* This is a copy of DM_verttri_from_looptri(). */
+void BKE_mesh_runtime_verttri_from_looptri(
+ MVertTri *r_verttri, const MLoop *mloop,
+ const MLoopTri *looptri, int looptri_num)
+{
+ int i;
+ for (i = 0; i < looptri_num; i++) {
+ r_verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
+ r_verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
+ r_verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;
+ }
+}
+
+
+bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh)
+{
+ if (mesh->runtime.edit_data != NULL) {
+ return false;
+ }
+
+ mesh->runtime.edit_data = MEM_callocN(sizeof(EditMeshData), "EditMeshData");
+ return true;
+}
+
+bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
+{
+ if (mesh->runtime.edit_data == NULL) {
+ return false;
+ }
+
+ if (mesh->runtime.edit_data->polyCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->polyCos);
+ if (mesh->runtime.edit_data->polyNos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->polyNos);
+ if (mesh->runtime.edit_data->vertexCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexCos);
+ if (mesh->runtime.edit_data->vertexNos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexNos);
+
+ MEM_SAFE_FREE(mesh->runtime.edit_data);
+ return true;
+}
+
+void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
+{
+ bvhcache_free(&mesh->runtime.bvh_cache);
+ MEM_SAFE_FREE(mesh->runtime.looptris.array);
+ /* TODO(sergey): Does this really belong here? */
+ if (mesh->runtime.subdiv_ccg != NULL) {
+ BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
+ mesh->runtime.subdiv_ccg = NULL;
+ }
+ BKE_shrinkwrap_discard_boundary_data(mesh);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Batch Cache Callbacks
+ * \{ */
+
+/* Draw Engine */
+void (*BKE_mesh_batch_cache_dirty_tag_cb)(Mesh *me, int mode) = NULL;
+void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL;
+
+void BKE_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
+{
+ if (me->runtime.batch_cache) {
+ BKE_mesh_batch_cache_dirty_tag_cb(me, mode);
+ }
+}
+void BKE_mesh_batch_cache_free(Mesh *me)
+{
+ if (me->runtime.batch_cache) {
+ BKE_mesh_batch_cache_free_cb(me);
+ }
+}
+
+/** \} */
+
+/** \name Mesh runtime debug helpers.
+ * \{ */
+/* evaluated mesh info printing function,
+ * to help track down differences output */
+
+#ifndef NDEBUG
+#include "BLI_dynstr.h"
+
+static void mesh_runtime_debug_info_layers(
+ DynStr *dynstr, CustomData *cd)
+{
+ int type;
+
+ for (type = 0; type < CD_NUMTYPES; type++) {
+ if (CustomData_has_layer(cd, type)) {
+ /* note: doesn't account for multiple layers */
+ const char *name = CustomData_layertype_name(type);
+ const int size = CustomData_sizeof(type);
+ const void *pt = CustomData_get_layer(cd, type);
+ const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(type, &structname, &structnum);
+ BLI_dynstr_appendf(
+ dynstr,
+ " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name, structname, type, (const void *)pt, size, pt_size);
+ }
+ }
+}
+
+char *BKE_mesh_runtime_debug_info(Mesh *me_eval)
+{
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+
+ BLI_dynstr_appendf(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval);
+#if 0
+ const char *tstr;
+ switch (me_eval->type) {
+ case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
+ case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
+ default: tstr = "UNKNOWN"; break;
+ }
+ BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
+#endif
+ BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert);
+ BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge);
+ BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface);
+ BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly);
+ BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only);
+
+ BLI_dynstr_appendf(dynstr, " 'vertexLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'edgeLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->edata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'loopLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'polyLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'tessFaceLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
+}
+
+void BKE_mesh_runtime_debug_print(Mesh *me_eval)
+{
+ char *str = BKE_mesh_runtime_debug_info(me_eval);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
+}
+
+/* XXX Should go in customdata file? */
+void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
+{
+ int i;
+ const CustomDataLayer *layer;
+
+ printf("{\n");
+
+ for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
+
+ const char *name = CustomData_layertype_name(layer->type);
+ const int size = CustomData_sizeof(layer->type);
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(layer->type, &structname, &structnum);
+ printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name, structname, layer->type, (const void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size));
+ }
+
+ printf("}\n");
+}
+
+bool BKE_mesh_runtime_is_valid(Mesh *me_eval)
+{
+ const bool do_verbose = true;
+ const bool do_fixes = false;
+
+ bool is_valid = true;
+ bool changed = true;
+
+ if (do_verbose) {
+ printf("MESH: %s\n", me_eval->id.name + 2);
+ }
+
+ is_valid &= BKE_mesh_validate_all_customdata(
+ &me_eval->vdata, &me_eval->edata, &me_eval->ldata, &me_eval->pdata,
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose, do_fixes,
+ &changed);
+
+ is_valid &= BKE_mesh_validate_arrays(
+ me_eval,
+ me_eval->mvert, me_eval->totvert,
+ me_eval->medge, me_eval->totedge,
+ me_eval->mface, me_eval->totface,
+ me_eval->mloop, me_eval->totloop,
+ me_eval->mpoly, me_eval->totpoly,
+ me_eval->dvert,
+ do_verbose, do_fixes,
+ &changed);
+
+ BLI_assert(changed == false);
+
+ return is_valid;
+}
+
+#endif /* NDEBUG */
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
new file mode 100644
index 00000000000..b8d260e6922
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -0,0 +1,716 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_tangent.c
+ * \ingroup bke
+ *
+ * Functions to evaluate mesh tangents.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_stack.h"
+#include "BLI_task.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_report.h"
+
+#include "BLI_strict_flags.h"
+
+#include "atomic_ops.h"
+#include "mikktspace.h"
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Mesh Tangent Calculations (Single Layer)
+ * \{ */
+
+/* Tangent space utils. */
+
+/* User data. */
+typedef struct {
+ const MPoly *mpolys; /* faces */
+ const MLoop *mloops; /* faces's vertices */
+ const MVert *mverts; /* vertices */
+ const MLoopUV *luvs; /* texture coordinates */
+ float (*lnors)[3]; /* loops' normals */
+ float (*tangents)[4]; /* output tangents */
+ int num_polys; /* number of polygons */
+} BKEMeshToTangent;
+
+/* Mikktspace's API */
+static int get_num_faces(const SMikkTSpaceContext *pContext)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->num_polys;
+}
+
+static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->mpolys[face_idx].totloop;
+}
+
+static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
+ copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
+}
+
+static void get_texture_coordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
+ const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
+}
+
+static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
+}
+
+static void set_tspace(
+ const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
+ const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
+ copy_v3_v3(p_res, fv_tangent);
+ p_res[3] = face_sign;
+}
+
+/**
+ * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
+ * split normals can be used to recreate the full tangent space.
+ * Note: * The mesh should be made of only tris and quads!
+ */
+void BKE_mesh_calc_loop_tangent_single_ex(
+ const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
+ float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
+ const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
+ ReportList *reports)
+{
+ BKEMeshToTangent mesh_to_tangent = {NULL};
+ SMikkTSpaceContext s_context = {NULL};
+ SMikkTSpaceInterface s_interface = {NULL};
+
+ const MPoly *mp;
+ int mp_index;
+
+ /* First check we do have a tris/quads only mesh. */
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ if (mp->totloop > 4) {
+ BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
+ return;
+ }
+ }
+
+ /* Compute Mikktspace's tangent normals. */
+ mesh_to_tangent.mpolys = mpolys;
+ mesh_to_tangent.mloops = mloops;
+ mesh_to_tangent.mverts = mverts;
+ mesh_to_tangent.luvs = loopuvs;
+ mesh_to_tangent.lnors = loopnors;
+ mesh_to_tangent.tangents = r_looptangent;
+ mesh_to_tangent.num_polys = numPolys;
+
+ s_context.m_pUserData = &mesh_to_tangent;
+ s_context.m_pInterface = &s_interface;
+ s_interface.m_getNumFaces = get_num_faces;
+ s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
+ s_interface.m_getPosition = get_position;
+ s_interface.m_getTexCoord = get_texture_coordinate;
+ s_interface.m_getNormal = get_normal;
+ s_interface.m_setTSpaceBasic = set_tspace;
+
+ /* 0 if failed */
+ if (genTangSpaceDefault(&s_context) == false) {
+ BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
+ }
+}
+
+/**
+ * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
+ * \note
+ * - There must be a valid loop's CD_NORMALS available.
+ * - The mesh should be made of only tris and quads!
+ */
+void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
+{
+ MLoopUV *loopuvs;
+ float (*loopnors)[3];
+
+ /* Check we have valid texture coordinates first! */
+ if (uvmap) {
+ loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
+ }
+ else {
+ loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
+ }
+ if (!loopuvs) {
+ BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
+ return;
+ }
+
+ loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ if (!loopnors) {
+ BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
+ return;
+ }
+
+ BKE_mesh_calc_loop_tangent_single_ex(
+ mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
+ loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Mesh Tangent Calculations (All Layers)
+ * \{ */
+
+
+/* Necessary complexity to handle looptri's as quads for correct tangents */
+#define USE_LOOPTRI_DETECT_QUADS
+
+typedef struct {
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const MLoopTri *looptri;
+ MLoopUV *mloopuv; /* texture coordinates */
+ const MPoly *mpoly; /* indices */
+ const MLoop *mloop; /* indices */
+ const MVert *mvert; /* vertices & normals */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+
+} SGLSLMeshToTangent;
+
+/* interface */
+static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ return pMesh->num_face_as_quad_map;
+#else
+ return pMesh->numTessFaces;
+#endif
+}
+
+static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ return 4;
+ }
+ }
+ return 3;
+#else
+ UNUSED_VARS(pContext, face_num);
+ return 3;
+#endif
+}
+
+static void dm_ts_GetPosition(
+ const SMikkTSpaceContext *pContext, float r_co[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+ const float *co;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
+ copy_v3_v3(r_co, co);
+}
+
+static void dm_ts_GetTextureCoordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ if (pMesh->mloopuv != NULL) {
+ const float *uv = pMesh->mloopuv[loop_index].uv;
+ copy_v2_v2(r_uv, uv);
+ }
+ else {
+ const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
+ map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ }
+}
+
+static void dm_ts_GetNormal(
+ const SMikkTSpaceContext *pContext, float r_no[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ if (pMesh->precomputedLoopNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
+ }
+ else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
+ if (pMesh->precomputedFaceNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
+ }
+ else {
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ normal_quad_v3(
+ r_no,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
+ }
+ else
+#endif
+ {
+ normal_tri_v3(
+ r_no,
+ pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
+ }
+ }
+ }
+ else {
+ const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
+ normal_short_to_float_v3(r_no, no);
+ }
+}
+
+static void dm_ts_SetTSpace(
+ const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+ float *pRes;
+
+finally:
+ pRes = pMesh->tangent[loop_index];
+ copy_v3_v3(pRes, fvTangent);
+ pRes[3] = fSign;
+}
+
+static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct SGLSLMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = dm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = dm_ts_GetPosition;
+ sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = dm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
+
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+}
+
+void BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ CustomData *uv_data, CustomData *tan_data, int numLoopData,
+ const char *layer_name)
+{
+ if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
+ CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
+ {
+ CustomData_add_layer_named(
+ tan_data, CD_TANGENT, CD_CALLOC, NULL,
+ numLoopData, layer_name);
+ }
+}
+
+/**
+ * Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
+ * Also, we calculate tangent_mask that works as a descriptor of tangents state.
+ * If tangent_mask has changed, then recalculate tangents.
+ */
+void BKE_mesh_calc_loop_tangent_step_0(
+ const CustomData *loopData, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_count,
+ bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+ char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
+{
+ /* Active uv in viewport */
+ int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
+ *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
+ ract_uv_name[0] = 0;
+ if (*ract_uv_n != -1) {
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
+ }
+
+ /* Active tangent in render */
+ *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
+ rren_uv_name[0] = 0;
+ if (*rren_uv_n != -1) {
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
+ }
+
+ /* If active tangent not in tangent_names we take it into account */
+ *rcalc_act = false;
+ *rcalc_ren = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] == 0) {
+ calc_active_tangent = true;
+ }
+ }
+ if (calc_active_tangent) {
+ *rcalc_act = true;
+ *rcalc_ren = true;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (STREQ(ract_uv_name, tangent_names[i]))
+ *rcalc_act = false;
+ if (STREQ(rren_uv_name, tangent_names[i]))
+ *rcalc_ren = false;
+ }
+ }
+ *rtangent_mask = 0;
+
+ const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
+ for (int n = 0; n < uv_layer_num; n++) {
+ const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
+ bool add = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
+ add = true;
+ break;
+ }
+ }
+ if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
+ (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name))))
+ {
+ add = true;
+ }
+ if (add)
+ *rtangent_mask |= (short)(1 << n);
+ }
+
+ if (uv_layer_num == 0)
+ *rtangent_mask |= DM_TANGENT_MASK_ORCO;
+}
+
+/**
+ * See: #BKE_editmesh_loop_tangent_calc (matching logic).
+ */
+void BKE_mesh_calc_loop_tangent_ex(
+ const MVert *mvert,
+ const MPoly *mpoly, const uint mpoly_len,
+ const MLoop *mloop,
+ const MLoopTri *looptri,
+ const uint looptri_len,
+
+ CustomData *loopdata,
+ bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p)
+{
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ short tangent_mask = 0;
+ short tangent_mask_curr = *tangent_mask_curr_p;
+
+ BKE_mesh_calc_loop_tangent_step_0(
+ loopdata, calc_active_tangent, tangent_names, tangent_names_len,
+ &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+ if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
+ /* Check we have all the needed layers */
+ /* Allocate needed tangent layers */
+ for (int i = 0; i < tangent_names_len; i++)
+ if (tangent_names[i][0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
+ if (calc_act && act_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (looptri_len != mpoly_len) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__);
+ int k, j;
+ for (k = 0, j = 0; j < (int)looptri_len; k++, j++) {
+ face_as_quad_map[k] = j;
+ /* step over all quads */
+ if (mpoly[looptri[j].poly].totloop == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = k;
+ }
+ else {
+ num_face_as_quad_map = (int)looptri_len;
+ }
+#endif
+
+ /* Calculation */
+ if (looptri_len != 0) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ tangent_mask_curr = 0;
+ /* Calculate tangent layers */
+ SGLSLMeshToTangent data_array[MAX_MTFACE];
+ const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+ for (int n = 0; n < tangent_layer_num; n++) {
+ int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = (int)looptri_len;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+#endif
+ mesh2tangent->mvert = mvert;
+ mesh2tangent->mpoly = mpoly;
+ mesh2tangent->mloop = mloop;
+ mesh2tangent->looptri = looptri;
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = loop_normals;
+ mesh2tangent->precomputedFaceNormals = poly_normals;
+
+ mesh2tangent->orco = NULL;
+ mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
+
+ /* Fill the resulting tangent_mask */
+ if (!mesh2tangent->mloopuv) {
+ mesh2tangent->orco = vert_orco;
+ if (!mesh2tangent->orco)
+ continue;
+
+ tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ int uv_ind = CustomData_get_named_layer_index(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
+ int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ tangent_mask_curr |= (short)(1 << (uv_ind - uv_start));
+ }
+
+ mesh2tangent->tangent = loopdata_out->layers[index].data;
+ BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+
+ BLI_assert(tangent_mask_curr == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
+ else {
+ tangent_mask_curr = tangent_mask;
+ }
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+#undef USE_LOOPTRI_DETECT_QUADS
+
+#endif
+
+ *tangent_mask_curr_p = tangent_mask_curr;
+
+ /* Update active layer index */
+ int act_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name);
+ CustomData_set_layer_active_index(loopdata, CD_TANGENT, tan_index);
+ }/* else tangent has been built from orco */
+
+ /* Update render layer index */
+ int ren_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(loopdata, CD_TANGENT, tan_index);
+ }/* else tangent has been built from orco */
+ }
+}
+
+void BKE_mesh_calc_loop_tangents(
+ Mesh *me_eval, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len)
+{
+ /* TODO(campbell): store in Mesh.runtime to avoid recalculation. */
+ short tangent_mask = 0;
+ BKE_mesh_calc_loop_tangent_ex(
+ me_eval->mvert,
+ me_eval->mpoly, (uint)me_eval->totpoly,
+ me_eval->mloop,
+ me_eval->runtime.looptris.array, (uint)me_eval->runtime.looptris.len,
+ &me_eval->ldata,
+ calc_active_tangent,
+ tangent_names, tangent_names_len,
+ CustomData_get_layer(&me_eval->pdata, CD_NORMAL),
+ CustomData_get_layer(&me_eval->ldata, CD_NORMAL),
+ CustomData_get_layer(&me_eval->vdata, CD_ORCO), /* may be NULL */
+ /* result */
+ &me_eval->ldata, (uint)me_eval->totloop,
+ &tangent_mask);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 82b3edb5b49..af4d1265cfd 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -43,10 +43,10 @@
#include "BLI_math_vector.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
+#include "DEG_depsgraph.h"
+
#include "MEM_guardedalloc.h"
/* loop v/e are unsigned, so using max uint_32 value as invalid marker... */
@@ -618,62 +618,6 @@ bool BKE_mesh_validate_arrays(
}
/* Test same polys. */
-#if 0
- {
- bool p1_sub = true, p2_sub = true;
-
- /* NOTE: This performs a sub-set test. */
- /* XXX This (and the sort of verts list) is better than systematic
- * search of all verts of one list into the other if lists have
- * a fair amount of elements.
- * Not sure however it's worth it in this case?
- * But as we also need sorted vert list to check verts multi-used
- * (in first pass of checks)... */
- /* XXX If we consider only "equal" polys (i.e. using exactly same set of verts)
- * as invalid, better to replace this by a simple memory cmp... */
- while ((p1_nv && p2_nv) && (p1_sub || p2_sub)) {
- if (*p1_v < *p2_v) {
- if (p1_sub)
- p1_sub = false;
- p1_nv--;
- p1_v++;
- }
- else if (*p2_v < *p1_v) {
- if (p2_sub)
- p2_sub = false;
- p2_nv--;
- p2_v++;
- }
- else {
- /* Equality, both next verts. */
- p1_nv--;
- p2_nv--;
- p1_v++;
- p2_v++;
- }
- }
- if (p1_nv && p1_sub)
- p1_sub = false;
- else if (p2_nv && p2_sub)
- p2_sub = false;
-
- if (p1_sub && p2_sub) {
- PRINT("\tPolys %u and %u use same vertices, considering poly %u as invalid.\n",
- prev_sp->index, sp->index, sp->index);
- sp->invalid = true;
- }
- /* XXX In fact, these might be valid? :/ */
- else if (p1_sub) {
- PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", sp->index, prev_sp->index);
- sp->invalid = true;
- }
- else if (p2_sub) {
- PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", prev_sp->index, sp->index);
- prev_sp->invalid = true;
- prev_sp = sp; /* sp is new reference poly. */
- }
- }
-#else
if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
if (do_verbose) {
PRINT_ERR("\tPolys %u and %u use same vertices (%d",
@@ -687,7 +631,6 @@ bool BKE_mesh_validate_arrays(
}
sp->invalid = true;
}
-#endif
else {
prev_sp = sp;
}
@@ -939,7 +882,7 @@ bool BKE_mesh_validate_all_customdata(
{
bool is_valid = true;
bool is_change_v, is_change_e, is_change_l, is_change_p;
- int tot_texpoly, tot_uvloop, tot_vcolloop;
+ int tot_uvloop, tot_vcolloop;
CustomDataMask mask = check_meshmask ? CD_MASK_MESH : 0;
is_valid &= mesh_validate_customdata(vdata, mask, do_verbose, do_fixes, &is_change_v);
@@ -947,17 +890,8 @@ bool BKE_mesh_validate_all_customdata(
is_valid &= mesh_validate_customdata(ldata, mask, do_verbose, do_fixes, &is_change_l);
is_valid &= mesh_validate_customdata(pdata, mask, do_verbose, do_fixes, &is_change_p);
- tot_texpoly = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV);
tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
- if (tot_texpoly != tot_uvloop) {
- PRINT_ERR("\tCustomDataLayer mismatch, tot_texpoly(%d), tot_uvloop(%d)\n",
- tot_texpoly, tot_uvloop);
- }
- if (tot_texpoly > MAX_MTFACE) {
- PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, tot_texpoly - MAX_MTFACE);
- }
if (tot_uvloop > MAX_MTFACE) {
PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
MAX_MTFACE, tot_uvloop - MAX_MTFACE);
@@ -968,18 +902,10 @@ bool BKE_mesh_validate_all_customdata(
}
/* check indices of clone/stencil */
- if (do_fixes && CustomData_get_clone_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) {
- CustomData_set_layer_clone(pdata, CD_MTEXPOLY, 0);
- is_change_p = true;
- }
if (do_fixes && CustomData_get_clone_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
CustomData_set_layer_clone(ldata, CD_MLOOPUV, 0);
is_change_l = true;
}
- if (do_fixes && CustomData_get_stencil_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) {
- CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, 0);
- is_change_p = true;
- }
if (do_fixes && CustomData_get_stencil_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
CustomData_set_layer_stencil(ldata, CD_MLOOPUV, 0);
is_change_l = true;
@@ -991,7 +917,7 @@ bool BKE_mesh_validate_all_customdata(
}
/**
- * \see #DM_is_valid to call on derived meshes
+ * Validates and corrects a Mesh.
*
* \returns true if a change is made.
*/
@@ -1022,7 +948,7 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
&changed);
if (changed) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
return true;
}
else {
@@ -1031,61 +957,39 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
}
/**
- * Duplicate of BM_mesh_cd_validate() for Mesh data.
+ * Checks if a Mesh is valid without any modification. This is always verbose.
+ *
+ * \see #DM_is_valid to call on derived meshes
+ *
+ * \returns is_valid.
*/
-void BKE_mesh_cd_validate(Mesh *me)
+bool BKE_mesh_is_valid(Mesh *me)
{
- int totlayer_mtex = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
- int totlayer_uv = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
- int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
- int mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
- int uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
- int i;
+ const bool do_verbose = true;
+ const bool do_fixes = false;
- /* XXX For now, do not delete those, just warn they are not really usable. */
- if (UNLIKELY(totlayer_mtex > MAX_MTFACE)) {
- printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, totlayer_mtex - MAX_MTFACE);
- }
- if (UNLIKELY(totlayer_uv > MAX_MTFACE)) {
- printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, totlayer_uv - MAX_MTFACE);
- }
- if (UNLIKELY(totlayer_mcol > MAX_MCOL)) {
- printf("WARNING! More VCol layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MCOL, totlayer_mcol - MAX_MCOL);
- }
+ bool is_valid = true;
+ bool changed = true;
- if (LIKELY(totlayer_mtex == totlayer_uv)) {
- /* pass */
- }
- else if (totlayer_mtex < totlayer_uv) {
- do {
- const char *from_name = me->ldata.layers[uv_index + totlayer_mtex].name;
- CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, from_name);
- CustomData_set_layer_unique_name(&me->pdata, totlayer_mtex);
- } while (totlayer_uv != ++totlayer_mtex);
- mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
- }
- else if (totlayer_uv < totlayer_mtex) {
- do {
- const char *from_name = me->pdata.layers[mtex_index + totlayer_uv].name;
- CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, from_name);
- CustomData_set_layer_unique_name(&me->ldata, totlayer_uv);
- } while (totlayer_mtex != ++totlayer_uv);
- uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
- }
+ is_valid &= BKE_mesh_validate_all_customdata(
+ &me->vdata, &me->edata, &me->ldata, &me->pdata,
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose, do_fixes, &changed);
- BLI_assert(totlayer_mtex == totlayer_uv);
+ is_valid &= BKE_mesh_validate_arrays(
+ me,
+ me->mvert, me->totvert,
+ me->medge, me->totedge,
+ me->mface, me->totface,
+ me->mloop, me->totloop,
+ me->mpoly, me->totpoly,
+ me->dvert,
+ do_verbose, do_fixes,
+ &changed);
- /* Check uv/tex names match as well!!! */
- for (i = 0; i < totlayer_mtex; i++, mtex_index++, uv_index++) {
- const char *name_src = me->pdata.layers[mtex_index].name;
- const char *name_dst = me->ldata.layers[uv_index].name;
- if (!STREQ(name_src, name_dst)) {
- BKE_mesh_uv_cdlayer_rename_index(me, mtex_index, uv_index, -1, name_src, false);
- }
- }
+ BLI_assert(changed == false);
+
+ return is_valid;
}
/**
@@ -1108,7 +1012,7 @@ bool BKE_mesh_validate_material_indices(Mesh *me)
}
if (!is_valid) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
return true;
}
else {
@@ -1540,4 +1444,78 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
BLI_edgehash_free(eh, NULL);
}
+
+void BKE_mesh_calc_edges_loose(Mesh *mesh)
+{
+ MEdge *med = mesh->medge;
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ med->flag |= ME_LOOSEEDGE;
+ }
+ MLoop *ml = mesh->mloop;
+ for (int i = 0; i < mesh->totloop; i++, ml++) {
+ mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE;
+ }
+}
+
+/**
+ * Calculate/create edges from tessface data
+ *
+ * \param mesh The mesh to add edges into
+ */
+
+void BKE_mesh_calc_edges_tessface(Mesh *mesh)
+{
+ CustomData edgeData;
+ EdgeSetIterator *ehi;
+ MFace *mf = mesh->mface;
+ MEdge *med;
+ EdgeSet *eh;
+ int i, *index, numEdges, numFaces = mesh->totface;
+
+ eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces));
+
+ for (i = 0; i < numFaces; i++, mf++) {
+ BLI_edgeset_add(eh, mf->v1, mf->v2);
+ BLI_edgeset_add(eh, mf->v2, mf->v3);
+
+ if (mf->v4) {
+ BLI_edgeset_add(eh, mf->v3, mf->v4);
+ BLI_edgeset_add(eh, mf->v4, mf->v1);
+ }
+ else {
+ BLI_edgeset_add(eh, mf->v3, mf->v1);
+ }
+ }
+
+ numEdges = BLI_edgeset_len(eh);
+
+ /* write new edges into a temporary CustomData */
+ CustomData_reset(&edgeData);
+ CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+
+ med = CustomData_get_layer(&edgeData, CD_MEDGE);
+ index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
+
+ for (ehi = BLI_edgesetIterator_new(eh), i = 0;
+ BLI_edgesetIterator_isDone(ehi) == false;
+ BLI_edgesetIterator_step(ehi), i++, med++, index++)
+ {
+ BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2);
+
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ *index = ORIGINDEX_NONE;
+ }
+ BLI_edgesetIterator_free(ehi);
+
+ /* free old CustomData and assign new one */
+ CustomData_free(&mesh->edata, mesh->totedge);
+ mesh->edata = edgeData;
+ mesh->totedge = numEdges;
+
+ mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
+
+ BLI_edgeset_free(eh);
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 723b4a5aa97..d67a3080819 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -46,6 +46,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
@@ -58,17 +59,25 @@
#include "BLT_translation.h"
#include "BKE_appdir.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
+#include "BKE_idcode.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_DerivedMesh.h"
/* may move these, only for modifier_path_relbase */
#include "BKE_main.h"
/* end */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_modifiertypes.h"
static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL};
@@ -127,6 +136,7 @@ ModifierData *modifier_new(int type)
md->type = type;
md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;
+ md->flag = eModifierFlag_StaticOverride_Local;
if (mti->flags & eModifierTypeFlag_EnableInEditmode)
md->mode |= eModifierMode_Editmode;
@@ -283,7 +293,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
/* callback's can use this
* to avoid copying every member.
*/
-void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst)
+void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst, const int UNUSED(flag))
{
const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
@@ -313,9 +323,10 @@ void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
target->mode = md->mode;
+ target->flag = md->flag;
if (mti->copyData) {
- mti->copyData(md, target);
+ mti->copyData(md, target, flag);
}
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
@@ -338,9 +349,7 @@ bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
- return ((!mti->isDisabled || !mti->isDisabled(md, 0)) &&
+ return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
(mti->flags & eModifierTypeFlag_SupportsEditmode) &&
modifier_supportsMapping(md));
}
@@ -349,11 +358,9 @@ bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
return ((md->mode & eModifierMode_Realtime) &&
(md->mode & eModifierMode_Editmode) &&
- (!mti->isDisabled || !mti->isDisabled(md, 0)) &&
+ (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
modifier_supportsMapping(md));
}
@@ -410,9 +417,7 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
bool supports_mapping;
- md->scene = scene;
-
- if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue;
if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
if (md->mode & eModifierMode_DisableTemporary) continue;
@@ -468,14 +473,12 @@ bool modifiers_isParticleEnabled(Object *ob)
*
* \param scene Current scene, may be NULL, in which case isDisabled callback of the modifier is never called.
*/
-bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode)
+bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if ((md->mode & required_mode) != required_mode) return false;
- if (scene != NULL && mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false;
+ if (scene != NULL && mti->isDisabled && mti->isDisabled(scene, md, required_mode == eModifierMode_Render)) return false;
if (md->mode & eModifierMode_DisableTemporary) return false;
if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false;
@@ -619,6 +622,27 @@ Object *modifiers_isDeformedByArmature(Object *ob)
return NULL;
}
+Object *modifiers_isDeformedByMeshDeform(Object *ob)
+{
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ MeshDeformModifierData *mdmd = NULL;
+
+ /* return the first selected armature, this lets us use multiple armatures */
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_MeshDeform) {
+ mdmd = (MeshDeformModifierData *) md;
+ if (mdmd->object && (mdmd->object->flag & SELECT))
+ return mdmd->object;
+ }
+ }
+
+ if (mdmd) /* if were still here then return the last armature */
+ return mdmd->object;
+
+ return NULL;
+}
+
/* Takes an object and returns its first selected lattice, else just its lattice
* This should work for multiple lattices per object
*/
@@ -686,7 +710,7 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm)
bool modifier_isCorrectableDeformed(ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return (mti->deformMatricesEM != NULL);
+ return mti->deformMatricesEM != NULL;
}
bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
@@ -695,9 +719,9 @@ bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
int required_mode = eModifierMode_Realtime;
- if (ob->mode == OB_MODE_EDIT)
+ if (ob->mode == OB_MODE_EDIT) {
required_mode |= eModifierMode_Editmode;
-
+ }
for (; md; md = md->next) {
if (!modifier_isEnabled(scene, md, required_mode)) {
/* pass */
@@ -802,61 +826,106 @@ void modifier_path_init(char *path, int path_maxlen, const char *name)
/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
-struct DerivedMesh *modwrap_applyModifier(
- ModifierData *md, Object *ob,
- struct DerivedMesh *dm,
- ModifierApplyFlag flag)
+struct Mesh *modwrap_applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *me)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
+ BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- DM_ensure_normals(dm);
+ BKE_mesh_calc_normals(me);
}
- return mti->applyModifier(md, ob, dm, flag);
+ return mti->applyModifier(md, ctx, me);
}
-struct DerivedMesh *modwrap_applyModifierEM(
- ModifierData *md, Object *ob,
- struct BMEditMesh *em,
- DerivedMesh *dm,
- ModifierApplyFlag flag)
+void modwrap_deformVerts(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *me, float (*vertexCos)[3], int numVerts)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
+ BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
- if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- DM_ensure_normals(dm);
+ if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(me);
}
- return mti->applyModifierEM(md, ob, em, dm, flag);
+ mti->deformVerts(md, ctx, me, vertexCos, numVerts);
}
-void modwrap_deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag flag)
+void modwrap_deformVertsEM(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *em, Mesh *me,
+ float (*vertexCos)[3], int numVerts)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
+ BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
- if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- DM_ensure_normals(dm);
+ if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(me);
}
- mti->deformVerts(md, ob, dm, vertexCos, numVerts, flag);
+ mti->deformVertsEM(md, ctx, em, me, vertexCos, numVerts);
}
-void modwrap_deformVertsEM(
- ModifierData *md, Object *ob,
- struct BMEditMesh *em, DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts)
+/* end modifier callback wrappers */
+
+
+/* wrappers for modifier callbacks that accept Mesh and select the proper implementation
+ * depending on if the modifier has been ported to Mesh or is still using DerivedMesh
+ */
+
+/* deprecated variants of above that accept DerivedMesh */
+
+struct DerivedMesh *modifier_applyModifier_DM_deprecated(
+ struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct DerivedMesh *dm)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
- if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- DM_ensure_normals(dm);
+ /* TODO(sybren): deduplicate all the copies of this code in this file. */
+ Mesh *mesh = NULL;
+ if (dm != NULL) {
+ mesh = BKE_id_new_nomain(ID_ME, NULL);
+ DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
}
- mti->deformVertsEM(md, ob, em, dm, vertexCos, numVerts);
+
+ struct Mesh *new_mesh = mti->applyModifier(md, ctx, mesh);
+
+ /* Make a DM that doesn't reference new_mesh so we can free the latter. */
+ DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING);
+
+ if (new_mesh != mesh) {
+ BKE_id_free(NULL, new_mesh);
+ }
+ if (mesh != NULL) {
+ BKE_id_free(NULL, mesh);
+ }
+
+ return ndm;
+
+}
+
+/**
+ * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
+ * e.g. second operand for boolean modifier.
+ * Note that modifiers in stack always get fully evaluated COW ID pointers, never original ones. Makes things simpler.
+ */
+Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, bool *r_free_mesh)
+{
+ Mesh *me = NULL;
+
+ if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
+ /* Note: currently we have no equivalent to derived cagemesh or even final dm in BMEditMesh...
+ * This is TODO in core depsgraph/modifier stack code still. */
+ BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ if (em != NULL) { /* em might not exist yet in some cases, just after loading a .blend file, see T57878. */
+ me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0);
+ *r_free_mesh = true;
+ }
+ }
+ if (me == NULL) {
+ me = ob_eval->runtime.mesh_eval;
+ *r_free_mesh = false;
+ }
+
+ return me;
}
-/* end modifier callback wrappers */
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
deleted file mode 100644
index 4de876f1060..00000000000
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * ***** 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) 2005 by the Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Joseph Eagar
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-/** \file blender/blenkernel/intern/modifiers_bmesh.c
- * \ingroup bke
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_alloca.h"
-
-#include "BKE_DerivedMesh.h"
-#include "BKE_editmesh.h"
-
-/* Static function for alloc */
-static BMFace *bm_face_create_from_mpoly(
- MPoly *mp, MLoop *ml,
- BMesh *bm, BMVert **vtable, BMEdge **etable)
-{
- BMVert **verts = BLI_array_alloca(verts, mp->totloop);
- BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
- int j;
-
- for (j = 0; j < mp->totloop; j++, ml++) {
- verts[j] = vtable[ml->v];
- edges[j] = etable[ml->e];
- }
-
- return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
-}
-
-/**
- * The main function for copying DerivedMesh data into BMesh.
- *
- * \note The mesh may already have geometry. see 'is_init'
- */
-void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
-{
- MVert *mv, *mvert;
- MEdge *me, *medge;
- MPoly *mpoly, *mp;
- MLoop *mloop;
- BMVert *v, **vtable;
- BMEdge *e, **etable;
- float (*face_normals)[3];
- BMFace *f;
- int i, j, totvert, totedge /* , totface */ /* UNUSED */ ;
- bool is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0);
- char has_orig_htype = 0;
-
- int cd_vert_bweight_offset;
- int cd_edge_bweight_offset;
- int cd_edge_crease_offset;
-
- if (is_init == false) {
- /* check if we have an origflag */
- has_orig_htype |= CustomData_has_layer(&bm->vdata, CD_ORIGINDEX) ? BM_VERT : 0;
- has_orig_htype |= CustomData_has_layer(&bm->edata, CD_ORIGINDEX) ? BM_EDGE : 0;
- has_orig_htype |= CustomData_has_layer(&bm->pdata, CD_ORIGINDEX) ? BM_FACE : 0;
- }
-
- /*merge custom data layout*/
- CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT);
- CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE);
- CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP);
- CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE);
-
- if (is_init) {
- BM_mesh_cd_flag_apply(bm, dm->cd_flag);
- }
-
- cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
- cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
-
- totvert = dm->getNumVerts(dm);
- totedge = dm->getNumEdges(dm);
- /* totface = dm->getNumPolys(dm); */ /* UNUSED */
-
- vtable = MEM_mallocN(sizeof(*vtable) * totvert, __func__);
- etable = MEM_mallocN(sizeof(*etable) * totedge, __func__);
-
- /*do verts*/
- bool vert_allocated;
- mv = mvert = DM_get_vert_array(dm, &vert_allocated);
- for (i = 0; i < totvert; i++, mv++) {
- v = BM_vert_create(bm, mv->co, NULL, BM_CREATE_SKIP_CD);
- normal_short_to_float_v3(v->no, mv->no);
- v->head.hflag = BM_vert_flag_from_mflag(mv->flag);
- BM_elem_index_set(v, i); /* set_inline */
-
- CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data, true);
- vtable[i] = v;
-
- /* add bevel weight */
- if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mv->bweight / 255.0f);
-
- if (UNLIKELY(has_orig_htype & BM_VERT)) {
- int *orig_index = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_ORIGINDEX);
- *orig_index = ORIGINDEX_NONE;
- }
- }
- if (vert_allocated) MEM_freeN(mvert);
- if (is_init) bm->elem_index_dirty &= ~BM_VERT;
-
- /*do edges*/
- bool edge_allocated;
- me = medge = DM_get_edge_array(dm, &edge_allocated);
- for (i = 0; i < totedge; i++, me++) {
- //BLI_assert(BM_edge_exists(vtable[me->v1], vtable[me->v2]) == NULL);
- e = BM_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, BM_CREATE_SKIP_CD);
-
- e->head.hflag = BM_edge_flag_from_mflag(me->flag);
- BM_elem_index_set(e, i); /* set_inline */
-
- CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data, true);
- etable[i] = e;
-
- if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)me->bweight / 255.0f);
- if (cd_edge_crease_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)me->crease / 255.0f);
-
- if (UNLIKELY(has_orig_htype & BM_EDGE)) {
- int *orig_index = CustomData_bmesh_get(&bm->edata, e->head.data, CD_ORIGINDEX);
- *orig_index = ORIGINDEX_NONE;
- }
- }
- if (edge_allocated) MEM_freeN(medge);
- if (is_init) bm->elem_index_dirty &= ~BM_EDGE;
-
- /* do faces */
- /* note: i_alt is aligned with bmesh faces which may not always align with mpolys */
- bool poly_allocated, loop_allocated;
- mpoly = mp = DM_get_poly_array(dm, &poly_allocated);
- mloop = DM_get_loop_array(dm, &loop_allocated);
- face_normals = (dm->dirty & DM_DIRTY_NORMALS) ? NULL : CustomData_get_layer(&dm->polyData, CD_NORMAL);
- for (i = 0; i < dm->numPolyData; i++, mp++) {
- BMLoop *l_iter;
- BMLoop *l_first;
-
- f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart,
- bm, vtable, etable);
-
- if (UNLIKELY(f == NULL)) {
- continue;
- }
-
- f->head.hflag = BM_face_flag_from_mflag(mp->flag);
- BM_elem_index_set(f, bm->totface - 1); /* set_inline */
- f->mat_nr = mp->mat_nr;
-
- j = mp->loopstart;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- /* Save index of correspsonding MLoop */
- CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, j, &l_iter->head.data, true);
- BM_elem_index_set(l_iter, j++); /* set_inline */
- } while ((l_iter = l_iter->next) != l_first);
-
- CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, i, &f->head.data, true);
-
- if (calc_face_normal) {
- if (face_normals) {
- copy_v3_v3(f->no, face_normals[i]);
- }
- else {
- BM_face_normal_update(f);
- }
- }
-
- if (UNLIKELY(has_orig_htype & BM_FACE)) {
- int *orig_index = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_ORIGINDEX);
- *orig_index = ORIGINDEX_NONE;
- }
- }
- if (poly_allocated) MEM_freeN(mpoly);
- if (loop_allocated) MEM_freeN(mloop);
- if (is_init) bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
-
- MEM_freeN(vtable);
- MEM_freeN(etable);
-}
-
-/* converts a cddm to a BMEditMesh. if existing is non-NULL, the
- * new geometry will be put in there.*/
-BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do_tessellate)
-{
- BMEditMesh *em = existing;
- BMesh *bm;
-
- if (em) {
- bm = em->bm;
- }
- else {
- bm = BM_mesh_create(
- &bm_mesh_allocsize_default,
- &((struct BMeshCreateParams){.use_toolflags = false,}));
- }
-
- DM_to_bmesh_ex(dm, bm, do_tessellate);
-
- if (!em) {
- em = BKE_editmesh_create(bm, do_tessellate);
- }
- else {
- if (do_tessellate) {
- BKE_editmesh_tessface_calc(em);
- }
- }
-
- return em;
-}
-
-BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal)
-{
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm);
-
- bm = BM_mesh_create(
- &allocsize,
- &((struct BMeshCreateParams){.use_toolflags = false,}));
-
- DM_to_bmesh_ex(dm, bm, calc_face_normal);
-
- return bm;
-}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index a11b0c62aa8..0117b36a16e 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1162,6 +1162,7 @@ void BKE_movieclip_get_size(MovieClip *clip, MovieClipUser *user, int *width, in
* cache lookups and even unwanted non-proxied files loading when doing mask parenting,
* so let's disable this for now and assume image sequence consists of images with
* equal sizes (sergey)
+ * TODO(sergey): Support reading sequences of different resolution.
*/
if (user->framenr == clip->lastframe) {
#endif
@@ -1609,8 +1610,51 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip,
return result;
}
-void BKE_movieclip_eval_update(struct EvaluationContext *UNUSED(eval_ctx), MovieClip *clip)
+static void movieclip_selection_synchronize(MovieClip *clip_dst, const MovieClip *clip_src)
{
- DEG_debug_print_eval(__func__, clip->id.name, clip);
+ BLI_assert(clip_dst != clip_src);
+ MovieTracking *tracking_dst = &clip_dst->tracking, tracking_src = clip_src->tracking;
+ /* Syncs the active object, track and plane track. */
+ tracking_dst->objectnr = tracking_src.objectnr;
+ const int active_track_index = BLI_findindex(&tracking_src.tracks, tracking_src.act_track);
+ const int active_plane_track_index = BLI_findindex(&tracking_src.plane_tracks, tracking_src.act_plane_track);
+ tracking_dst->act_track = BLI_findlink(&tracking_dst->tracks, active_track_index);
+ tracking_dst->act_plane_track = BLI_findlink(&tracking_dst->plane_tracks, active_plane_track_index);
+
+ /* Syncs the tracking selection flag. */
+ MovieTrackingObject *tracking_object_dst, *tracking_object_src;
+ tracking_object_src = tracking_src.objects.first;
+
+ for (tracking_object_dst = tracking_dst->objects.first;
+ tracking_object_dst != NULL;
+ tracking_object_dst = tracking_object_dst->next,
+ tracking_object_src = tracking_object_src->next)
+ {
+ ListBase *tracksbase_dst, *tracksbase_src;
+ tracksbase_dst = BKE_tracking_object_get_tracks(tracking_dst, tracking_object_dst);
+ tracksbase_src = BKE_tracking_object_get_tracks(&tracking_src, tracking_object_src);
+
+ MovieTrackingTrack *track_dst, *track_src;
+ track_src = tracksbase_src->first;
+ for (track_dst = tracksbase_dst->first;
+ track_dst != NULL;
+ track_dst = track_dst->next, track_src = track_src->next)
+ {
+ track_dst->flag = track_src->flag;
+ track_dst->pat_flag = track_src->pat_flag;
+ track_dst->search_flag = track_src->search_flag;
+ }
+ }
+}
+
+void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, MovieClip *clip)
+{
+ DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
BKE_tracking_dopesheet_tag_update(&clip->tracking);
}
+
+void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip *clip)
+{
+ DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
+ movieclip_selection_synchronize(clip, (MovieClip *)clip->id.orig_id);
+}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 279c6eb0c82..a21e919bca7 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -49,12 +49,15 @@
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
#include "BKE_editmesh.h"
@@ -62,6 +65,8 @@
#include "CCGSubSurf.h"
+#include "DEG_depsgraph_query.h"
+
#include <math.h>
#include <string.h>
@@ -277,19 +282,26 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level)
return mdisps;
}
-DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
+Mesh *BKE_multires_create_mesh(
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ MultiresModifierData *mmd,
+ Object *ob)
{
- ModifierData *md = (ModifierData *)mmd;
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
- DerivedMesh *dm;
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene, ob_eval, CD_MASK_BAREMESH);
+ ModifierEvalContext modifier_ctx = {
+ .depsgraph = depsgraph,
+ .object = ob_eval,
+ .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY};
- dm = mti->applyModifier(md, ob, tdm, MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY);
- if (dm == tdm) {
- dm = CDDM_copy(tdm);
- }
+ const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type);
+ Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh);
- return dm;
+ if (result == deformed_mesh) {
+ result = BKE_mesh_copy_for_eval(deformed_mesh, true);
+ }
+ return result;
}
MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd)
@@ -336,17 +348,17 @@ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_f
return mmd;
}
-static int multires_get_level(Object *ob, MultiresModifierData *mmd,
- bool render, bool ignore_simplify)
+int multires_get_level(const Scene *scene, const Object *ob, const MultiresModifierData *mmd,
+ bool render, bool ignore_simplify)
{
if (render)
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl, true) : mmd->renderlvl;
+ return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->renderlvl, true) : mmd->renderlvl;
else if (ob->mode == OB_MODE_SCULPT)
return mmd->sculptlvl;
else if (ignore_simplify)
return mmd->lvl;
else
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl, false) : mmd->lvl;
+ return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl;
}
void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
@@ -366,21 +378,49 @@ static void multires_dm_mark_as_modified(DerivedMesh *dm, MultiresModifiedFlags
ccgdm->multires.modified_flags |= flags;
}
+static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg,
+ MultiresModifiedFlags flags)
+{
+ if (flags & MULTIRES_COORDS_MODIFIED) {
+ subdiv_ccg->dirty.coords = true;
+ }
+ if (flags & MULTIRES_HIDDEN_MODIFIED) {
+ subdiv_ccg->dirty.hidden = true;
+ }
+}
+
void multires_mark_as_modified(Object *ob, MultiresModifiedFlags flags)
{
- if (ob && ob->derivedFinal)
- multires_dm_mark_as_modified(ob->derivedFinal, flags);
+ if (ob == NULL) {
+ return;
+ }
+ Mesh *mesh = ob->data;
+ SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg;
+ if (subdiv_ccg == NULL) {
+ return;
+ }
+ multires_ccg_mark_as_modified(subdiv_ccg, flags);
}
void multires_force_update(Object *ob)
{
- if (ob) {
- BKE_object_free_derived_caches(ob);
-
- if (ob->sculpt && ob->sculpt->pbvh) {
- BKE_pbvh_free(ob->sculpt->pbvh);
- ob->sculpt->pbvh = NULL;
+ if (ob == NULL) {
+ return;
+ }
+ SculptSession *sculpt_session = ob->sculpt;
+ if (sculpt_session != NULL && sculpt_session->pbvh != NULL) {
+ PBVH *pbvh = sculpt_session->pbvh;
+ if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
+ Mesh *mesh = ob->data;
+ multiresModifier_reshapeFromCCG(
+ sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
+ }
+ else {
+ /* NOTE: Disabled for until OpenSubdiv is enabled by default. */
+ // BLI_assert(!"multires_force_update is used on non-grids PBVH");
}
+ BKE_pbvh_free(pbvh);
+ ob->sculpt->pbvh = NULL;
}
}
@@ -398,68 +438,6 @@ void multires_force_render_update(Object *ob)
multires_force_update(ob);
}
-int multiresModifier_reshapeFromDM(Scene *scene, MultiresModifierData *mmd,
- Object *ob, DerivedMesh *srcdm)
-{
- DerivedMesh *mrdm = get_multires_dm(scene, mmd, ob);
-
- if (mrdm && srcdm && mrdm->getNumVerts(mrdm) == srcdm->getNumVerts(srcdm)) {
- multires_mvert_to_ss(mrdm, srcdm->getVertArray(srcdm));
-
- multires_dm_mark_as_modified(mrdm, MULTIRES_COORDS_MODIFIED);
- multires_force_update(ob);
-
- mrdm->release(mrdm);
-
- return 1;
- }
-
- if (mrdm) mrdm->release(mrdm);
-
- return 0;
-}
-
-/* Returns 1 on success, 0 if the src's totvert doesn't match */
-int multiresModifier_reshape(Scene *scene, MultiresModifierData *mmd, Object *dst, Object *src)
-{
- DerivedMesh *srcdm = mesh_get_derived_final(scene, src, CD_MASK_BAREMESH);
- return multiresModifier_reshapeFromDM(scene, mmd, dst, srcdm);
-}
-
-int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mmd,
- Object *ob, ModifierData *md)
-{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- DerivedMesh *dm, *ndm;
- int numVerts, result;
- float (*deformedVerts)[3];
-
- if (multires_get_level(ob, mmd, false, true) == 0)
- return 0;
-
- /* Create DerivedMesh for deformation modifier */
- dm = get_multires_dm(scene, mmd, ob);
- numVerts = dm->getNumVerts(dm);
- deformedVerts = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "multiresReshape_deformVerts");
-
- dm->getVertCos(dm, deformedVerts);
- mti->deformVerts(md, ob, dm, deformedVerts, numVerts, 0);
-
- ndm = CDDM_copy(dm);
- CDDM_apply_vert_coords(ndm, deformedVerts);
-
- MEM_freeN(deformedVerts);
- dm->release(dm);
-
- /* Reshaping */
- result = multiresModifier_reshapeFromDM(scene, mmd, ob, ndm);
-
- /* Cleanup */
- ndm->release(ndm);
-
- return result;
-}
-
/* reset the multires levels to match the number of mdisps */
static int get_levels_from_disps(Object *ob)
{
@@ -680,10 +658,10 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
}
/* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */
-void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int direction)
+void multiresModifier_del_levels(MultiresModifierData *mmd, Scene *scene, Object *ob, int direction)
{
Mesh *me = BKE_mesh_from_object(ob);
- int lvl = multires_get_level(ob, mmd, false, true);
+ int lvl = multires_get_level(scene, ob, mmd, false, true);
int levels = mmd->totlvl - lvl;
MDisps *mdisps;
@@ -700,7 +678,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire
multires_set_tot_level(ob, mmd, lvl);
}
-static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask)
+static DerivedMesh *multires_dm_create_local(Scene *scene, Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask)
{
MultiresModifierData mmd = {{NULL}};
MultiresFlags flags = MULTIRES_USE_LOCAL_MMD;
@@ -714,29 +692,44 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv
if (alloc_paint_mask)
flags |= MULTIRES_ALLOC_PAINT_MASK;
- return multires_make_derived_from_derived(dm, &mmd, ob, flags);
+ return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags);
}
-static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal, int plain_uv, int alloc_paint_mask)
+static DerivedMesh *subsurf_dm_create_local(
+ Scene *scene, Object *ob, DerivedMesh *dm,
+ int lvl,
+ bool is_simple, bool is_optimal, bool is_plain_uv, bool alloc_paint_mask,
+ bool for_render)
{
SubsurfModifierData smd = {{NULL}};
SubsurfFlags flags = 0;
smd.levels = smd.renderLevels = lvl;
- if (!plain_uv)
- smd.flags |= eSubsurfModifierFlag_SubsurfUv;
- if (simple)
+ smd.quality = 3;
+ if (!is_plain_uv) {
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ }
+ else {
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE;
+ }
+ if (is_simple) {
smd.subdivType = ME_SIMPLE_SUBSURF;
- if (optimal)
+ }
+ if (is_optimal) {
smd.flags |= eSubsurfModifierFlag_ControlEdges;
+ }
- if (ob->mode & OB_MODE_EDIT)
+ if (ob->mode & OB_MODE_EDIT) {
flags |= SUBSURF_IN_EDIT_MODE;
-
- if (alloc_paint_mask)
+ }
+ if (alloc_paint_mask) {
flags |= SUBSURF_ALLOC_PAINT_MASK;
+ }
+ if (for_render) {
+ flags |= SUBSURF_USE_RENDER_PARAMS;
+ }
- return subsurf_make_derived_from_derived(dm, &smd, NULL, flags);
+ return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags);
}
@@ -750,7 +743,7 @@ static float v3_dist_from_plane(float v[3], float center[3], float no[3])
return dot_v3v3(s, no);
}
-void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
+void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object *ob)
{
DerivedMesh *cddm, *dispdm, *origdm;
Mesh *me;
@@ -772,7 +765,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
/* generate highest level with displacements */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- dispdm = multires_dm_create_local(ob, cddm, totlvl, totlvl, 0, 0);
+ dispdm = multires_dm_create_local(scene, ob, cddm, totlvl, totlvl, 0, 0);
cddm->release(cddm);
/* copy the new locations of the base verts into the mesh */
@@ -868,7 +861,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
/* subdivide the mesh to highest level without displacements */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
+ origdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, 0, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, 0, false);
cddm->release(cddm);
/* calc disps */
@@ -878,7 +871,9 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
dispdm->release(dispdm);
}
-static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl, int updateblock, int simple)
+static void multires_subdivide(
+ MultiresModifierData *mmd, Scene *scene, Object *ob,
+ int totlvl, int updateblock, int simple)
{
Mesh *me = ob->data;
MDisps *mdisps;
@@ -907,11 +902,11 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
/* create subsurf DM from original mesh at high level */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
ss = ((CCGDerivedMesh *)highdm)->ss;
/* create multires DM from original mesh at low level */
- lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask);
+ lowdm = multires_dm_create_local(scene, ob, cddm, lvl, lvl, simple, has_mask);
BLI_assert(lowdm != cddm);
cddm->release(cddm);
@@ -961,9 +956,9 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
multires_set_tot_level(ob, mmd, totlvl);
}
-void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple)
+void multiresModifier_subdivide(MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple)
{
- multires_subdivide(mmd, ob, mmd->totlvl + 1, updateblock, simple);
+ multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple);
}
static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *grid, float t[3])
@@ -1196,7 +1191,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm
}
}
-void multires_modifier_update_mdisps(struct DerivedMesh *dm)
+void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
Object *ob;
@@ -1228,11 +1223,11 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm)
else cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
ss = ((CCGDerivedMesh *)highdm)->ss;
/* create multires DM from original mesh and displacements */
- lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple, has_mask);
+ lowdm = multires_dm_create_local(scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask);
cddm->release(cddm);
/* gather grid data */
@@ -1290,7 +1285,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm)
else cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ subdm = subsurf_dm_create_local(scene, ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
cddm->release(cddm);
multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl);
@@ -1332,147 +1327,36 @@ void multires_modifier_update_hidden(DerivedMesh *dm)
}
}
-void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
+void multires_stitch_grids(Object *ob)
{
- DerivedMesh *ccgdm = NULL, *subsurf = NULL;
- CCGElem **gridData, **subGridData = NULL;
- CCGKey key;
- MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- MDisps *mdisps;
- MultiresModifierData *mmd = get_multires_modifier(NULL, ob, 1);
- int *gridOffset, totlvl;
- int i, k, numGrids, gridSize, dGridSize, dSkip;
-
- if (!mmd)
+ if (ob == NULL) {
return;
-
- mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
-
- if (!mdisps) {
- goto cleanup;
- }
-
- totlvl = mmd->totlvl;
- ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple, false);
-
- subsurf = subsurf_dm_create_local(ob, dm, totlvl,
- mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
-
- numGrids = subsurf->getNumGrids(subsurf);
- gridSize = subsurf->getGridSize(subsurf);
- gridData = subsurf->getGridData(subsurf);
- subsurf->getGridKey(subsurf, &key);
-
- subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
-
- for (i = 0; i < numGrids; i++) {
- subGridData[i] = MEM_calloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData");
- memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize);
- }
-
- /* numGrids = ccgdm->dm->getNumGrids((DerivedMesh *)ccgdm); */ /*UNUSED*/
- gridSize = ccgdm->getGridSize((DerivedMesh *)ccgdm);
- gridData = ccgdm->getGridData((DerivedMesh *)ccgdm);
- gridOffset = ccgdm->getGridOffset((DerivedMesh *)ccgdm);
-
- dGridSize = multires_side_tot[totlvl];
- dSkip = (dGridSize - 1) / (gridSize - 1);
-
- k = 0; /*current loop/mdisp index within the mloop array*/
-
- /* TODO: Use BLI_task parallel range for that one too? */
- for (i = 0; i < dm->numPolyData; ++i) {
- const int numVerts = mpoly[i].totloop;
- int S, x, y, gIndex = gridOffset[i];
-
- for (S = 0; S < numVerts; ++S, ++gIndex, ++k) {
- MDisps *mdisp = &mdisps[mpoly[i].loopstart + S];
- /* CCGElem *grid = gridData[gIndex]; */ /* UNUSED */
- CCGElem *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = NULL;
-
- /* when adding new faces in edit mode, need to allocate disps */
- if (!mdisp->disps) {
- mdisp->totdisp = gridSize * gridSize;
- mdisp->level = totlvl;
- mdisp->disps = MEM_calloc_arrayN(mdisp->totdisp, 3 * sizeof(float), "disp in multires_set_space");
- }
-
- dispgrid = mdisp->disps;
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
- float *co = CCG_grid_elem_co(&key, subgrid, x, y);
- float mat[3][3], dco[3];
-
- /* construct tangent space matrix */
- grid_tangent_matrix(mat, &key, x, y, subgrid);
-
- /* convert to absolute coordinates in space */
- if (from == MULTIRES_SPACE_TANGENT) {
- mul_v3_m3v3(dco, mat, data);
- add_v3_v3(dco, co);
- }
- else if (from == MULTIRES_SPACE_OBJECT) {
- add_v3_v3v3(dco, co, data);
- }
- else if (from == MULTIRES_SPACE_ABSOLUTE) {
- copy_v3_v3(dco, data);
- }
-
- /*now, convert to desired displacement type*/
- if (to == MULTIRES_SPACE_TANGENT) {
- invert_m3(mat);
-
- sub_v3_v3(dco, co);
- mul_v3_m3v3(data, mat, dco);
- }
- else if (to == MULTIRES_SPACE_OBJECT) {
- sub_v3_v3(dco, co);
- mul_v3_m3v3(data, mat, dco);
- }
- else if (to == MULTIRES_SPACE_ABSOLUTE) {
- copy_v3_v3(data, dco);
- }
- }
- }
- }
}
-
-cleanup:
- if (subsurf) {
- subsurf->needsFree = 1;
- subsurf->release(subsurf);
+ SculptSession *sculpt_session = ob->sculpt;
+ if (sculpt_session == NULL) {
+ return;
}
-
- if (ccgdm) {
- ccgdm->needsFree = 1;
- ccgdm->release(ccgdm);
+ PBVH *pbvh = sculpt_session->pbvh;
+ SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg;
+ if (pbvh == NULL || subdiv_ccg == NULL) {
+ return;
}
-}
-
-void multires_stitch_grids(Object *ob)
-{
- /* utility for smooth brush */
- if (ob && ob->derivedFinal) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)ob->derivedFinal;
- CCGFace **faces;
- int totface;
-
- if (ccgdm->pbvh) {
- BKE_pbvh_get_grid_updates(ccgdm->pbvh, false, (void ***)&faces, &totface);
-
- if (totface) {
- ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface);
- MEM_freeN(faces);
- }
- }
+ BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS);
+ /* NOTE: Currently CCG does not keep track of faces, making it impossible
+ * to use BKE_pbvh_get_grid_updates().
+ */
+ CCGFace **faces;
+ int num_faces;
+ BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces);
+ if (num_faces) {
+ BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
+ MEM_freeN(faces);
}
}
DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
MultiresModifierData *mmd,
+ Scene *scene,
Object *ob,
MultiresFlags flags)
{
@@ -1483,16 +1367,17 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
CCGKey key;
const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0;
const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0;
- int lvl = multires_get_level(ob, mmd, render, ignore_simplify);
+ int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify);
int i, gridSize, numGrids;
if (lvl == 0)
return dm;
- result = subsurf_dm_create_local(ob, dm, lvl,
+ result = subsurf_dm_create_local(scene, ob, dm, lvl,
mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges,
- mmd->flags & eMultiresModifierFlag_PlainUv,
- flags & MULTIRES_ALLOC_PAINT_MASK);
+ mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+ flags & MULTIRES_ALLOC_PAINT_MASK,
+ render);
if (!(flags & MULTIRES_USE_LOCAL_MMD)) {
ccgdm = (CCGDerivedMesh *)result;
@@ -2168,7 +2053,7 @@ void multires_load_old(Object *ob, Mesh *me)
BLI_insertlinkbefore(&ob->modifiers, md, mmd);
for (i = 0; i < me->mr->level_count - 1; ++i)
- multiresModifier_subdivide(mmd, ob, 1, 0);
+ multiresModifier_subdivide(mmd, NULL, ob, 1, 0);
mmd->lvl = mmd->totlvl;
orig = CDDM_from_mesh(me);
@@ -2177,7 +2062,7 @@ void multires_load_old(Object *ob, Mesh *me)
* reference subsurfed dm with this option, before calling multiresModifier_disp_run(),
* which implicitly expects both subsurfs from its first dm and oldGridData parameters to
* be of the same "format"! */
- dm = multires_make_derived_from_derived(orig, mmd, ob, 0);
+ dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0);
multires_load_old_dm(dm, me, mmd->totlvl + 1);
@@ -2192,14 +2077,14 @@ void multires_load_old(Object *ob, Mesh *me)
/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
* such that 'ob_dst' has the same total number of levels as 'ob_src'. */
-void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
+void multiresModifier_sync_levels_ex(Scene *scene, Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
{
if (mmd_src->totlvl == mmd_dst->totlvl) {
return;
}
if (mmd_src->totlvl > mmd_dst->totlvl) {
- multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
+ multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
}
else {
multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
@@ -2221,134 +2106,50 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
}
if (mmd_src && mmd_dst) {
- multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst);
+ multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst);
}
}
-static void multires_apply_smat_cb(
- void *__restrict userdata,
- const int pidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void multires_apply_uniform_scale(Object *object, const float scale)
{
- MultiresThreadedData *tdata = userdata;
-
- CCGElem **gridData = tdata->gridData;
- CCGElem **subGridData = tdata->subGridData;
- CCGKey *dm_key = tdata->key;
- CCGKey *subdm_key = tdata->sub_key;
- MPoly *mpoly = tdata->mpoly;
- MDisps *mdisps = tdata->mdisps;
- int *gridOffset = tdata->gridOffset;
- int gridSize = tdata->gridSize;
- int dGridSize = tdata->dGridSize;
- int dSkip = tdata->dSkip;
- float (*smat)[3] = tdata->smat;
-
- const int numVerts = mpoly[pidx].totloop;
- MDisps *mdisp = &mdisps[mpoly[pidx].loopstart];
- int S, x, y, gIndex = gridOffset[pidx];
-
- for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) {
- CCGElem *grid = gridData[gIndex];
- CCGElem *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = mdisp->disps;
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *co = CCG_grid_elem_co(dm_key, grid, x, y);
- float *sco = CCG_grid_elem_co(subdm_key, subgrid, x, y);
- float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
- float mat[3][3], disp[3];
-
- /* construct tangent space matrix */
- grid_tangent_matrix(mat, dm_key, x, y, grid);
-
- /* scale subgrid coord and calculate displacement */
- mul_m3_v3(smat, sco);
- sub_v3_v3v3(disp, sco, co);
-
- /* convert difference to tangent space */
- invert_m3(mat);
- mul_v3_m3v3(data, mat, disp);
- }
+ Mesh *mesh = (Mesh *)object->data;
+ MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ for (int i = 0; i < mesh->totloop; ++i) {
+ MDisps *grid = &mdisps[i];
+ for (int j = 0; j < grid->totdisp; ++j) {
+ mul_v3_fl(grid->disps[j], scale);
}
}
}
-static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
+static void multires_apply_smat(
+ struct Depsgraph *UNUSED(depsgraph),
+ Scene *scene,
+ Object *object,
+ float smat[3][3])
{
- DerivedMesh *dm = NULL, *cddm = NULL, *subdm = NULL;
- CCGElem **gridData, **subGridData;
- CCGKey dm_key, subdm_key;
- Mesh *me = (Mesh *)ob->data;
- MPoly *mpoly = me->mpoly;
- /* MLoop *mloop = me->mloop; */ /* UNUSED */
- MDisps *mdisps;
- int *gridOffset;
- int i, /*numGrids, */ gridSize, dGridSize, dSkip, totvert;
- float (*vertCos)[3] = NULL;
- MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1);
- MultiresModifierData high_mmd;
-
- CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
-
- if (!mdisps || !mmd || !mmd->totlvl) return;
-
- /* we need derived mesh created from highest resolution */
- high_mmd = *mmd;
- high_mmd.lvl = high_mmd.totlvl;
-
- /* unscaled multires with applied displacement */
- subdm = get_multires_dm(scene, &high_mmd, ob);
-
- /* prepare scaled CDDM to create ccgDN */
- cddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
-
- totvert = cddm->getNumVerts(cddm);
- vertCos = MEM_malloc_arrayN(totvert, sizeof(*vertCos), "multiresScale vertCos");
- cddm->getVertCos(cddm, vertCos);
- for (i = 0; i < totvert; i++)
- mul_m3_v3(smat, vertCos[i]);
- CDDM_apply_vert_coords(cddm, vertCos);
- MEM_freeN(vertCos);
-
- /* scaled ccgDM for tangent space of object with applied scale */
- dm = subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
- cddm->release(cddm);
-
- gridSize = dm->getGridSize(dm);
- gridData = dm->getGridData(dm);
- gridOffset = dm->getGridOffset(dm);
- dm->getGridKey(dm, &dm_key);
- subGridData = subdm->getGridData(subdm);
- subdm->getGridKey(subdm, &subdm_key);
-
- dGridSize = multires_side_tot[high_mmd.totlvl];
- dSkip = (dGridSize - 1) / (gridSize - 1);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
-
- MultiresThreadedData data = {
- .gridData = gridData,
- .subGridData = subGridData,
- .key = &dm_key,
- .sub_key = &subdm_key,
- .mpoly = mpoly,
- .mdisps = mdisps,
- .gridOffset = gridOffset,
- .gridSize = gridSize,
- .dGridSize = dGridSize,
- .dSkip = dSkip,
- .smat = smat
- };
-
- BLI_task_parallel_range(0, me->totpoly, &data, multires_apply_smat_cb, &settings);
-
- dm->release(dm);
- subdm->release(subdm);
+ const MultiresModifierData *mmd = get_multires_modifier(scene, object, true);
+ if (mmd == NULL || mmd->totlvl == 0) {
+ return;
+ }
+ /* Make sure layer present. */
+ Mesh *mesh = (Mesh *)object->data;
+ CustomData_external_read(
+ &mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop);
+ if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) {
+ return;
+ }
+ if (is_uniform_scaled_m3(smat)) {
+ const float scale = mat3_to_scale(smat);
+ multires_apply_uniform_scale(object, scale);
+ }
+ else {
+ /* TODO(sergey): This branch of code actually requires more work to
+ * preserve all the details.
+ */
+ const float scale = mat3_to_scale(smat);
+ multires_apply_uniform_scale(object, scale);
+ }
}
int multires_mdisp_corners(MDisps *s)
@@ -2364,17 +2165,17 @@ int multires_mdisp_corners(MDisps *s)
return 0;
}
-void multiresModifier_scale_disp(Scene *scene, Object *ob)
+void multiresModifier_scale_disp(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
float smat[3][3];
/* object's scale matrix */
BKE_object_scale_to_mat3(ob, smat);
- multires_apply_smat(scene, ob, smat);
+ multires_apply_smat(depsgraph, scene, ob, smat);
}
-void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
+void multiresModifier_prepare_join(struct Depsgraph *depsgraph, Scene *scene, Object *ob, Object *to_ob)
{
float smat[3][3], tmat[3][3], mat[3][3];
multires_sync_levels(scene, to_ob, ob);
@@ -2385,7 +2186,7 @@ void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
BKE_object_scale_to_mat3(ob, smat);
mul_m3_m3m3(mat, smat, tmat);
- multires_apply_smat(scene, ob, mat);
+ multires_apply_smat(depsgraph, scene, ob, mat);
}
/* update multires data after topology changing */
diff --git a/source/blender/blenkernel/intern/multires_inline.h b/source/blender/blenkernel/intern/multires_inline.h
new file mode 100644
index 00000000000..99b4695fe46
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_inline.h
@@ -0,0 +1,68 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/multires_inline.h
+ * \ingroup bke
+ */
+
+#ifndef __MULTIRES_INLINE_H__
+#define __MULTIRES_INLINE_H__
+
+#include "BKE_multires.h"
+#include "BLI_math_vector.h"
+
+BLI_INLINE void BKE_multires_construct_tangent_matrix(
+ float tangent_matrix[3][3],
+ const float dPdu[3],
+ const float dPdv[3],
+ const int corner)
+{
+ if (corner == 0) {
+ copy_v3_v3(tangent_matrix[0], dPdv);
+ copy_v3_v3(tangent_matrix[1], dPdu);
+ mul_v3_fl(tangent_matrix[0], -1.0f);
+ mul_v3_fl(tangent_matrix[1], -1.0f);
+ }
+ else if (corner == 1) {
+ copy_v3_v3(tangent_matrix[0], dPdu);
+ copy_v3_v3(tangent_matrix[1], dPdv);
+ mul_v3_fl(tangent_matrix[1], -1.0f);
+ }
+ else if (corner == 2) {
+ copy_v3_v3(tangent_matrix[0], dPdv);
+ copy_v3_v3(tangent_matrix[1], dPdu);
+ }
+ else if (corner == 3) {
+ copy_v3_v3(tangent_matrix[0], dPdu);
+ copy_v3_v3(tangent_matrix[1], dPdv);
+ mul_v3_fl(tangent_matrix[0], -1.0f);
+ }
+ cross_v3_v3v3(tangent_matrix[2], dPdu, dPdv);
+ normalize_v3(tangent_matrix[0]);
+ normalize_v3(tangent_matrix[1]);
+ normalize_v3(tangent_matrix[2]);
+}
+
+#endif /* __MULTIRES_INLINE_H__ */
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
new file mode 100644
index 00000000000..72be2617798
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -0,0 +1,1206 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/multires_reshape.c
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_task.h"
+
+#include "BKE_ccg.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
+
+#include "DEG_depsgraph_query.h"
+
+static void multires_reshape_init_mmd(
+ MultiresModifierData *reshape_mmd,
+ const MultiresModifierData *mmd)
+{
+ *reshape_mmd = *mmd;
+}
+
+static void multires_reshape_init_mmd_top_level(
+ MultiresModifierData *reshape_mmd,
+ const MultiresModifierData *mmd)
+{
+ *reshape_mmd = *mmd;
+ reshape_mmd->lvl = reshape_mmd->totlvl;
+}
+
+/* =============================================================================
+ * General reshape implementation, reused by all particular cases.
+ */
+
+typedef struct MultiresReshapeContext {
+ Subdiv *subdiv;
+ const Mesh *coarse_mesh;
+ MDisps *mdisps;
+ GridPaintMask *grid_paint_mask;
+ int top_grid_size;
+ int top_level;
+} MultiresReshapeContext;
+
+static void multires_reshape_allocate_displacement_grid(
+ MDisps *displacement_grid, const int level)
+{
+ const int grid_size = BKE_subdiv_grid_size_from_level(level);
+ const int grid_area = grid_size * grid_size;
+ float (*disps)[3] = MEM_calloc_arrayN(
+ grid_area, 3 * sizeof(float), "multires disps");
+ displacement_grid->disps = disps;
+ displacement_grid->totdisp = grid_area;
+ displacement_grid->level = level;
+}
+
+static void multires_reshape_ensure_displacement_grid(
+ MDisps *displacement_grid, const int level)
+{
+ if (displacement_grid->disps != NULL) {
+ return;
+ }
+ multires_reshape_allocate_displacement_grid(
+ displacement_grid, level);
+}
+
+static void multires_reshape_ensure_displacement_grids(
+ Mesh *mesh,
+ const int grid_level)
+{
+ const int num_grids = mesh->totloop;
+ MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ multires_reshape_ensure_displacement_grid(
+ &mdisps[grid_index], grid_level);
+ }
+}
+
+static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level)
+{
+ GridPaintMask *grid_paint_masks =
+ CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ if (grid_paint_masks == NULL) {
+ return;
+ }
+ const int num_grids = mesh->totloop;
+ const int grid_size = BKE_subdiv_grid_size_from_level(grid_level);
+ const int grid_area = grid_size * grid_size;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
+ if (grid_paint_mask->level == grid_level) {
+ continue;
+ }
+ grid_paint_mask->level = grid_level;
+ if (grid_paint_mask->data) {
+ MEM_freeN(grid_paint_mask->data);
+ }
+ grid_paint_mask->data = MEM_calloc_arrayN(
+ grid_area, sizeof(float), "gpm.data");
+ }
+}
+
+static void multires_reshape_ensure_grids(Mesh *mesh, const int grid_level)
+{
+ multires_reshape_ensure_displacement_grids(mesh, grid_level);
+ multires_reshape_ensure_mask_grids(mesh, grid_level);
+}
+
+static void multires_reshape_vertex_copy_to_next(
+ MultiresReshapeContext *ctx,
+ const MPoly *coarse_poly,
+ const int current_corner,
+ const MDisps *current_displacement_grid,
+ const GridPaintMask *current_mask_grid,
+ const int current_grid_x, const int current_grid_y)
+{
+ const int grid_size = ctx->top_grid_size;
+ const int next_current_corner = (current_corner + 1) % coarse_poly->totloop;
+ const int next_grid_x = 0;
+ const int next_grid_y = current_grid_x;
+ const int current_index = current_grid_y * grid_size + current_grid_x;
+ const int next_index = next_grid_y * grid_size + next_grid_x;
+ /* Copy displacement. */
+ MDisps *next_displacement_grid = &ctx->mdisps[
+ coarse_poly->loopstart + next_current_corner];
+ float *next_displacement = next_displacement_grid->disps[next_index];
+ copy_v3_v3(next_displacement,
+ current_displacement_grid->disps[current_index]);
+ SWAP(float, next_displacement[0], next_displacement[1]);
+ next_displacement[0] = -next_displacement[0];
+ /* Copy mask, if exists. */
+ if (current_mask_grid != NULL) {
+ GridPaintMask *next_mask_grid = &ctx->grid_paint_mask[
+ coarse_poly->loopstart + next_current_corner];
+ next_mask_grid->data[next_index] =
+ current_mask_grid->data[current_index];
+ }
+}
+
+static void multires_reshape_vertex_copy_to_prev(
+ MultiresReshapeContext *ctx,
+ const MPoly *coarse_poly,
+ const int current_corner,
+ const MDisps *current_displacement_grid,
+ const GridPaintMask *current_mask_grid,
+ const int current_grid_x, const int current_grid_y)
+{
+ const int grid_size = ctx->top_grid_size;
+ const int prev_current_corner =
+ (current_corner - 1 + coarse_poly->totloop) % coarse_poly->totloop;
+ const int prev_grid_x = current_grid_y;
+ const int prev_grid_y = 0;
+ const int current_index = current_grid_y * grid_size + current_grid_x;
+ const int prev_index = prev_grid_y * grid_size + prev_grid_x;
+ /* Copy displacement. */
+ MDisps *prev_displacement_grid = &ctx->mdisps[
+ coarse_poly->loopstart + prev_current_corner];
+ float *prev_displacement = prev_displacement_grid->disps[prev_index];
+ copy_v3_v3(prev_displacement,
+ current_displacement_grid->disps[current_index]);
+ SWAP(float, prev_displacement[0], prev_displacement[1]);
+ prev_displacement[1] = -prev_displacement[1];
+ /* Copy mask, if exists. */
+ if (current_mask_grid != NULL) {
+ GridPaintMask *prev_mask_grid = &ctx->grid_paint_mask[
+ coarse_poly->loopstart + prev_current_corner];
+ prev_mask_grid->data[prev_index] =
+ current_mask_grid->data[current_index];
+ }
+}
+
+static void copy_boundary_displacement(
+ MultiresReshapeContext *ctx,
+ const MPoly *coarse_poly,
+ const int corner,
+ const int grid_x, const int grid_y,
+ const MDisps *displacement_grid,
+ const GridPaintMask *mask_grid)
+{
+ if (grid_x == 0 && grid_y == 0) {
+ for (int i = 0; i < coarse_poly->totloop; i++) {
+ const int current_face_corner =
+ (corner + i) % coarse_poly->totloop;
+ const int grid_index = coarse_poly->loopstart + current_face_corner;
+ MDisps *current_displacement_grid = &ctx->mdisps[grid_index];
+ GridPaintMask *current_mask_grid =
+ mask_grid != NULL ? &ctx->grid_paint_mask[grid_index]
+ : NULL;
+ multires_reshape_vertex_copy_to_next(
+ ctx,
+ coarse_poly,
+ current_face_corner,
+ current_displacement_grid,
+ current_mask_grid,
+ 0, 0);
+ }
+ }
+ else if (grid_x == 0) {
+ multires_reshape_vertex_copy_to_prev(
+ ctx,
+ coarse_poly,
+ corner,
+ displacement_grid,
+ mask_grid,
+ grid_x, grid_y);
+ }
+ else if (grid_y == 0) {
+ multires_reshape_vertex_copy_to_next(
+ ctx,
+ coarse_poly,
+ corner,
+ displacement_grid,
+ mask_grid,
+ grid_x, grid_y);
+ }
+}
+
+static void multires_reshape_vertex_from_final_data(
+ MultiresReshapeContext *ctx,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const float final_P[3], const float final_mask)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ const int grid_size = ctx->top_grid_size;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ const int loop_index = coarse_poly->loopstart + coarse_corner;
+ /* Evaluate limit surface. */
+ float P[3], dPdu[3], dPdv[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, P, dPdu, dPdv);
+ /* Get coordinate and corner configuration. */
+ float grid_u, grid_v;
+ MDisps *displacement_grid;
+ GridPaintMask *grid_paint_mask = NULL;
+ int face_corner = coarse_corner;
+ int grid_corner = 0;
+ int grid_index;
+ if (coarse_poly->totloop == 4) {
+ float corner_u, corner_v;
+ face_corner = BKE_subdiv_rotate_quad_to_corner(
+ u, v, &corner_u, &corner_v);
+ grid_corner = face_corner;
+ grid_index = loop_index + face_corner;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(
+ corner_u, corner_v, &grid_u, &grid_v);
+ }
+ else {
+ grid_index = loop_index;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, &grid_u, &grid_v);
+ }
+ displacement_grid = &ctx->mdisps[grid_index];
+ if (ctx->grid_paint_mask != NULL) {
+ grid_paint_mask = &ctx->grid_paint_mask[grid_index];
+ BLI_assert(grid_paint_mask->level == displacement_grid->level);
+ }
+ /* Convert object coordinate to a tangent space of displacement grid. */
+ float D[3];
+ sub_v3_v3v3(D, final_P, P);
+ float tangent_matrix[3][3];
+ BKE_multires_construct_tangent_matrix(
+ tangent_matrix, dPdu, dPdv, grid_corner);
+ float inv_tangent_matrix[3][3];
+ invert_m3_m3(inv_tangent_matrix, tangent_matrix);
+ float tangent_D[3];
+ mul_v3_m3v3(tangent_D, inv_tangent_matrix, D);
+ /* Write tangent displacement. */
+ const int grid_x = (grid_u * (grid_size - 1) + 0.5f);
+ const int grid_y = (grid_v * (grid_size - 1) + 0.5f);
+ const int index = grid_y * grid_size + grid_x;
+ copy_v3_v3(displacement_grid->disps[index], tangent_D);
+ /* Write mask grid. */
+ if (grid_paint_mask != NULL) {
+ grid_paint_mask->data[index] = final_mask;
+ }
+ /* Copy boundary to the next/previous grids */
+ copy_boundary_displacement(
+ ctx, coarse_poly, face_corner, grid_x, grid_y,
+ displacement_grid, grid_paint_mask);
+}
+
+/* =============================================================================
+ * Helpers to propagate displacement to higher levels.
+ */
+
+typedef struct MultiresPropagateData {
+ /* Number of displacement grids. */
+ int num_grids;
+ /* Resolution level up to which displacement is known. */
+ int reshape_level;
+ /* Resolution up to which propagation is happening, affecting all the
+ * levels in [reshape_level + 1, top_level].
+ */
+ int top_level;
+ /* Grid sizes at the corresponding levels. */
+ int reshape_grid_size;
+ int top_grid_size;
+ /* Keys to access CCG at different levels. */
+ CCGKey reshape_level_key;
+ CCGKey top_level_key;
+ /* Original grid data, before any updates for reshape.
+ * Contains data at the reshape_level resolution level.
+ */
+ CCGElem **orig_grids_data;
+ /* Custom data layers from a coarse mesh. */
+ MDisps *mdisps;
+ GridPaintMask *grid_paint_mask;
+} MultiresPropagateData;
+
+static CCGElem **allocate_grids(CCGKey *key, int num_grids)
+{
+ CCGElem **grids = MEM_calloc_arrayN(
+ num_grids, sizeof(CCGElem *), "reshape grids*");
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ grids[grid_index] = MEM_calloc_arrayN(
+ key->elem_size,
+ key->grid_area,
+ "reshape orig_grids_data elems");
+ }
+ return grids;
+}
+
+static void free_grids(CCGElem **grids, int num_grids)
+{
+ if (grids == NULL) {
+ return;
+ }
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ MEM_freeN(grids[grid_index]);
+ }
+ MEM_freeN(grids);
+}
+
+/* Initialize element sizes and offsets. */
+static void multires_reshape_init_key_layers(
+ CCGKey *key,
+ const MultiresPropagateData *data)
+{
+ key->elem_size = 3 * sizeof(float);
+ if (data->grid_paint_mask != NULL) {
+ key->mask_offset = 3 * sizeof(float);
+ key->elem_size += sizeof(float);
+ key->has_mask = true;
+ }
+ else {
+ key->mask_offset = -1;
+ key->has_mask = false;
+ }
+ /* We never have normals in original grids. */
+ key->normal_offset = -1;
+ key->has_normals = false;
+}
+
+/* Initialize key used to access reshape grids at given level. */
+static void multires_reshape_init_level_key(
+ CCGKey *key,
+ const MultiresPropagateData *data,
+ const int level)
+{
+ key->level = level;
+ /* Init layers. */
+ multires_reshape_init_key_layers(key, data);
+ /* By default, only 3 floats for coordinate, */
+ key->grid_size = BKE_subdiv_grid_size_from_level(key->level);
+ key->grid_area = key->grid_size * key->grid_size;
+ key->grid_bytes = key->elem_size * key->grid_area;
+}
+
+static void multires_reshape_store_original_grids(
+ MultiresPropagateData *data)
+{
+ const int num_grids = data->num_grids;
+ /* Original data to be backed up. */
+ const MDisps *mdisps = data->mdisps;
+ const GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ /* Allocate grids for backup. */
+ CCGKey *orig_key = &data->reshape_level_key;
+ CCGElem **orig_grids_data = allocate_grids(orig_key, num_grids);
+ /* Fill in grids. */
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *orig_grid = orig_grids_data[grid_index];
+ for (int y = 0; y < orig_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < orig_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * top_grid_size + top_x;
+ memcpy(CCG_grid_elem_co(orig_key, orig_grid, x, y),
+ mdisps[grid_index].disps[top_index],
+ sizeof(float) * 3);
+ if (orig_key->has_mask) {
+ *CCG_grid_elem_mask(orig_key, orig_grid, x, y) =
+ grid_paint_mask[grid_index].data[top_index];
+ }
+ }
+ }
+ }
+ /* Store in the context. */
+ data->orig_grids_data = orig_grids_data;
+}
+
+static void multires_reshape_propagate_prepare(
+ MultiresPropagateData *data,
+ Mesh *coarse_mesh,
+ const int reshape_level,
+ const int top_level)
+{
+ BLI_assert(reshape_level <= top_level);
+ memset(data, 0, sizeof(*data));
+ data->num_grids = coarse_mesh->totloop;
+ data->reshape_level = reshape_level;
+ data->top_level = top_level;
+ if (reshape_level == top_level) {
+ /* Nothing to do, reshape will happen on the whole grid content. */
+ return;
+ }
+ data->mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ data->grid_paint_mask =
+ CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
+ data->top_grid_size = BKE_subdiv_grid_size_from_level(top_level);
+ data->reshape_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
+ /* Initialize keys to access CCG at different levels. */
+ multires_reshape_init_level_key(
+ &data->reshape_level_key, data, data->reshape_level);
+ multires_reshape_init_level_key(
+ &data->top_level_key, data, data->top_level);
+ /* Make a copy of grids before reshaping, so we can calculate deltas
+ * later on.
+ */
+ multires_reshape_store_original_grids(data);
+}
+
+static void multires_reshape_propagate_prepare_from_mmd(
+ MultiresPropagateData *data,
+ struct Depsgraph *depsgraph,
+ Object *object,
+ const MultiresModifierData *mmd,
+ const int top_level,
+ const bool use_render_params)
+{
+ /* TODO(sergey): Find mode reliable way of getting current level. */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Mesh *mesh = object->data;
+ const int level = multires_get_level(
+ scene_eval, object, mmd, use_render_params, true);
+ multires_reshape_propagate_prepare(data, mesh, level, top_level);
+}
+
+/* Calculate delta of changed reshape level data layers. Delta goes to a
+ * grids at top level (meaning, the result grids are only partially filled
+ * in).
+ */
+static void multires_reshape_calculate_delta(
+ MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
+{
+ const int num_grids = data->num_grids;
+ /* At this point those custom data layers has updated data for the
+ * level we are propagating from.
+ */
+ const MDisps *mdisps = data->mdisps;
+ const GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ CCGKey *reshape_key = &data->reshape_level_key;
+ CCGKey *delta_level_key = &data->top_level_key;
+ /* Calculate delta. */
+ const int top_grid_size = data->top_grid_size;
+ const int reshape_grid_size = data->reshape_grid_size;
+ const int delta_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (reshape_grid_size - 1);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ /*const*/ CCGElem *orig_grid = data->orig_grids_data[grid_index];
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ for (int y = 0; y < reshape_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < reshape_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * delta_grid_size + top_x;
+ sub_v3_v3v3(
+ CCG_grid_elem_co(
+ delta_level_key, delta_grid, top_x, top_y),
+ mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(reshape_key, orig_grid, x, y));
+ if (delta_level_key->has_mask) {
+ const float old_mask_value = *CCG_grid_elem_mask(
+ reshape_key, orig_grid, x, y);
+ const float new_mask_value =
+ grid_paint_mask[grid_index].data[top_index];
+ *CCG_grid_elem_mask(
+ delta_level_key, delta_grid, top_x, top_y) =
+ new_mask_value - old_mask_value;
+ }
+ }
+ }
+ }
+}
+
+/* Makes it so delta is propagated onto all the higher levels, but is also
+ * that this delta is smoothed in a way that it does not cause artifacts on
+ * boundaries.
+ */
+
+typedef struct MultiresPropagateCornerData {
+ float coord_delta[3];
+ float mask_delta;
+} MultiresPropagateCornerData;
+
+BLI_INLINE void multires_reshape_propagate_init_patch_corners(
+ MultiresPropagateData *data,
+ CCGElem *delta_grid,
+ const int patch_x, const int patch_y,
+ MultiresPropagateCornerData r_corners[4])
+{
+ CCGKey *delta_level_key = &data->top_level_key;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ const int x = patch_x * skip;
+ const int y = patch_y * skip;
+ /* Store coordinate deltas. */
+ copy_v3_v3(r_corners[0].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid, x, y));
+ copy_v3_v3(r_corners[1].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid, x + skip, y));
+ copy_v3_v3(r_corners[2].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid, x, y + skip));
+ copy_v3_v3(r_corners[3].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid,
+ x + skip, y + skip));
+ if (delta_level_key->has_mask) {
+ r_corners[0].mask_delta =
+ *CCG_grid_elem_mask(delta_level_key, delta_grid, x, y);
+ r_corners[1].mask_delta =
+ *CCG_grid_elem_mask(delta_level_key, delta_grid,
+ x + skip, y);
+ r_corners[2].mask_delta =
+ *CCG_grid_elem_mask(delta_level_key, delta_grid,
+ x, y + skip);
+ r_corners[3].mask_delta =
+ *CCG_grid_elem_mask(delta_level_key, delta_grid,
+ x + skip, y + skip);
+ }
+}
+
+BLI_INLINE void multires_reshape_propagate_interpolate_coord(
+ float delta[3],
+ const MultiresPropagateCornerData corners[4],
+ const float weights[4])
+{
+ interp_v3_v3v3v3v3(
+ delta,
+ corners[0].coord_delta, corners[1].coord_delta,
+ corners[2].coord_delta, corners[3].coord_delta,
+ weights);
+}
+
+BLI_INLINE float multires_reshape_propagate_interpolate_mask(
+ const MultiresPropagateCornerData corners[4],
+ const float weights[4])
+{
+ return corners[0].mask_delta * weights[0] +
+ corners[1].mask_delta * weights[1] +
+ corners[2].mask_delta * weights[2] +
+ corners[3].mask_delta * weights[3];
+}
+
+BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid_patch(
+ MultiresPropagateData *data,
+ CCGElem *delta_grid,
+ const int patch_x, const int patch_y)
+{
+ CCGKey *delta_level_key = &data->top_level_key;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ const float skip_inv = 1.0f / (float)skip;
+ MultiresPropagateCornerData corners[4];
+ multires_reshape_propagate_init_patch_corners(
+ data, delta_grid, patch_x, patch_y, corners);
+ const int start_x = patch_x * skip;
+ const int start_y = patch_y * skip;
+ for (int y = 0; y <= skip; y++) {
+ const float v = (float)y * skip_inv;
+ const int final_y = start_y + y;
+ for (int x = 0; x <= skip; x++) {
+ const float u = (float)x * skip_inv;
+ const int final_x = start_x + x;
+ const float linear_weights[4] = {(1.0f - u) * (1.0f - v),
+ u * (1.0f - v),
+ (1.0f - u) * v,
+ u * v};
+ multires_reshape_propagate_interpolate_coord(
+ CCG_grid_elem_co(delta_level_key, delta_grid,
+ final_x, final_y),
+ corners,
+ linear_weights);
+ if (delta_level_key->has_mask) {
+ float *mask = CCG_grid_elem_mask(delta_level_key, delta_grid,
+ final_x, final_y);
+ *mask = multires_reshape_propagate_interpolate_mask(
+ corners, linear_weights);
+ }
+ }
+ }
+}
+
+BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid(
+ MultiresPropagateData *data,
+ CCGElem *delta_grid)
+{
+ const int orig_grid_size = data->reshape_grid_size;
+ for (int patch_y = 0; patch_y < orig_grid_size - 1; patch_y++) {
+ for (int patch_x = 0; patch_x < orig_grid_size - 1; patch_x++) {
+ multires_reshape_propagate_and_smooth_delta_grid_patch(
+ data, delta_grid, patch_x, patch_y);
+ }
+ }
+}
+
+/* Entry point to propagate+smooth. */
+static void multires_reshape_propagate_and_smooth_delta(
+ MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
+{
+ const int num_grids = data->num_grids;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ multires_reshape_propagate_and_smooth_delta_grid(data, delta_grid);
+ }
+}
+
+/* Apply smoothed deltas on the actual data layers. */
+static void multires_reshape_propagate_apply_delta(
+ MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
+{
+ const int num_grids = data->num_grids;
+ /* At this point those custom data layers has updated data for the
+ * level we are propagating from.
+ */
+ MDisps *mdisps = data->mdisps;
+ GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ CCGKey *orig_key = &data->reshape_level_key;
+ CCGKey *delta_level_key = &data->top_level_key;
+ CCGElem **orig_grids_data = data->orig_grids_data;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ /* Restore grid values at the reshape level. Those values are to be changed
+ * to the accommodate for the smooth delta.
+ */
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *orig_grid = orig_grids_data[grid_index];
+ for (int y = 0; y < orig_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < orig_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * top_grid_size + top_x;
+ copy_v3_v3(mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(orig_key, orig_grid, x, y));
+ if (grid_paint_mask != NULL) {
+ grid_paint_mask[grid_index].data[top_index] =
+ *CCG_grid_elem_mask(orig_key, orig_grid, x, y);
+ }
+ }
+ }
+ }
+ /* Add smoothed delta to all the levels. */
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ for (int y = 0; y < top_grid_size; y++) {
+ for (int x = 0; x < top_grid_size; x++) {
+ const int top_index = y * top_grid_size + x;
+ add_v3_v3(mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(delta_level_key, delta_grid, x, y));
+ if (delta_level_key->has_mask) {
+ grid_paint_mask[grid_index].data[top_index] +=
+ *CCG_grid_elem_mask(
+ delta_level_key, delta_grid, x, y);
+ }
+ }
+ }
+ }
+}
+
+static void multires_reshape_propagate(MultiresPropagateData *data)
+{
+ if (data->reshape_level == data->top_level) {
+ return;
+ }
+ const int num_grids = data->num_grids;
+ /* Calculate delta made at the reshape level. */
+ CCGKey *delta_level_key = &data->top_level_key;
+ CCGElem **delta_grids_data = allocate_grids(delta_level_key, num_grids);
+ multires_reshape_calculate_delta(data, delta_grids_data);
+ /* Propagate deltas to the higher levels. */
+ multires_reshape_propagate_and_smooth_delta(data, delta_grids_data);
+ /* Finally, apply smoothed deltas. */
+ multires_reshape_propagate_apply_delta(data, delta_grids_data);
+ /* Cleanup. */
+ free_grids(delta_grids_data, num_grids);
+}
+
+static void multires_reshape_propagate_free(MultiresPropagateData *data)
+{
+ free_grids(data->orig_grids_data, data->num_grids);
+}
+
+/* =============================================================================
+ * Reshape from deformed vertex coordinates.
+ */
+
+typedef struct MultiresReshapeFromDeformedVertsContext {
+ MultiresReshapeContext reshape_ctx;
+ const float (*deformed_verts)[3];
+ int num_deformed_verts;
+} MultiresReshapeFromDeformedVertsContext;
+
+static bool multires_reshape_topology_info(
+ const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int UNUSED(num_edges),
+ const int UNUSED(num_loops),
+ const int UNUSED(num_polygons))
+{
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ if (num_vertices != ctx->num_deformed_verts) {
+ return false;
+ }
+ return true;
+}
+
+static void multires_reshape_vertex(
+ MultiresReshapeFromDeformedVertsContext *ctx,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ const float *final_P = ctx->deformed_verts[subdiv_vertex_index];
+ multires_reshape_vertex_from_final_data(
+ &ctx->reshape_ctx,
+ ptex_face_index, u, v,
+ coarse_poly_index,
+ coarse_corner,
+ final_P, 0.0f);
+}
+
+static void multires_reshape_vertex_inner(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx,
+ ptex_face_index, u, v,
+ coarse_poly_index,
+ coarse_corner,
+ subdiv_vertex_index);
+}
+
+static void multires_reshape_vertex_every_corner(
+ const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_vertex_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx,
+ ptex_face_index, u, v,
+ coarse_poly_index,
+ coarse_corner,
+ subdiv_vertex_index);
+}
+
+static void multires_reshape_vertex_every_edge(
+ const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_edge_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx,
+ ptex_face_index, u, v,
+ coarse_poly_index,
+ coarse_corner,
+ subdiv_vertex_index);
+}
+
+static Subdiv *multires_create_subdiv_for_reshape(
+ struct Depsgraph *depsgraph,
+ /*const*/ Object *object,
+ const MultiresModifierData *mmd)
+{
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
+ Mesh *deformed_mesh = mesh_get_eval_deform(
+ depsgraph, scene_eval, object_eval, CD_MASK_BAREMESH);
+ SubdivSettings subdiv_settings;
+ BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
+ Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh);
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) {
+ BKE_subdiv_free(subdiv);
+ return NULL;
+ }
+ return subdiv;
+}
+
+static bool multires_reshape_from_vertcos(
+ struct Depsgraph *depsgraph,
+ Object *object,
+ const MultiresModifierData *mmd,
+ const float (*deformed_verts)[3],
+ const int num_deformed_verts,
+ const bool use_render_params)
+{
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Mesh *coarse_mesh = object->data;
+ MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ /* Pick maximum between multires level and dispalcement level.
+ * This is because mesh can be used by objects with multires at different
+ * levels.
+ *
+ * TODO(sergey): At this point it should be possible to always use
+ * mdisps->level.
+ */
+ const int top_level = max_ii(mmd->totlvl, mdisps->level);
+ /* Make sure displacement grids are ready. */
+ multires_reshape_ensure_grids(coarse_mesh, top_level);
+ /* Construct context. */
+ MultiresReshapeFromDeformedVertsContext reshape_deformed_verts_ctx = {
+ .reshape_ctx = {
+ .coarse_mesh = coarse_mesh,
+ .mdisps = mdisps,
+ .grid_paint_mask = NULL,
+ .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
+ .top_level = top_level,
+ },
+ .deformed_verts = deformed_verts,
+ .num_deformed_verts = num_deformed_verts,
+ };
+ SubdivForeachContext foreach_context = {
+ .topology_info = multires_reshape_topology_info,
+ .vertex_inner = multires_reshape_vertex_inner,
+ .vertex_every_edge = multires_reshape_vertex_every_edge,
+ .vertex_every_corner = multires_reshape_vertex_every_corner,
+ .user_data = &reshape_deformed_verts_ctx,
+ };
+ /* Initialize subdivision surface. */
+ Subdiv *subdiv = multires_create_subdiv_for_reshape(depsgraph, object, mmd);
+ if (subdiv == NULL) {
+ return false;
+ }
+ reshape_deformed_verts_ctx.reshape_ctx.subdiv = subdiv;
+ /* Initialize mesh rasterization settings. */
+ SubdivToMeshSettings mesh_settings;
+ BKE_multires_subdiv_mesh_settings_init(
+ &mesh_settings, scene_eval, object, mmd, use_render_params, true);
+ /* Initialize propagation to higher levels. */
+ MultiresPropagateData propagate_data;
+ multires_reshape_propagate_prepare_from_mmd(
+ &propagate_data, depsgraph, object, mmd, top_level, use_render_params);
+ /* Run all the callbacks. */
+ BKE_subdiv_foreach_subdiv_geometry(
+ subdiv,
+ &foreach_context,
+ &mesh_settings,
+ coarse_mesh);
+ BKE_subdiv_free(subdiv);
+ /* Update higher levels if needed. */
+ multires_reshape_propagate(&propagate_data);
+ multires_reshape_propagate_free(&propagate_data);
+ return true;
+}
+
+/* =============================================================================
+ * Reshape from object.
+ */
+
+/* Returns truth on success, false otherwise.
+ *
+ * This function might fail in cases like source and destination not having
+ * matched amount of vertices.
+ */
+bool multiresModifier_reshapeFromObject(
+ struct Depsgraph *depsgraph,
+ MultiresModifierData *mmd,
+ Object *dst,
+ Object *src)
+{
+ /* Would be cool to support this eventually, but it is very tricky to match
+ * vertices order even for meshes, when mixing meshes and other objects it's
+ * even more tricky.
+ */
+ if (src->type != OB_MESH) {
+ return false;
+ }
+ MultiresModifierData reshape_mmd;
+ multires_reshape_init_mmd(&reshape_mmd, mmd);
+ /* Get evaluated vertices locations to reshape to. */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *src_eval = DEG_get_evaluated_object(depsgraph, src);
+ Mesh *src_mesh_eval = mesh_get_eval_final(
+ depsgraph, scene_eval, src_eval, CD_MASK_BAREMESH);
+ int num_deformed_verts;
+ float (*deformed_verts)[3] = BKE_mesh_vertexCos_get(
+ src_mesh_eval, &num_deformed_verts);
+ bool result = multires_reshape_from_vertcos(
+ depsgraph,
+ dst,
+ &reshape_mmd,
+ deformed_verts,
+ num_deformed_verts,
+ false);
+ MEM_freeN(deformed_verts);
+ return result;
+}
+
+/* =============================================================================
+ * Reshape from modifier.
+ */
+
+bool multiresModifier_reshapeFromDeformModifier(
+ struct Depsgraph *depsgraph,
+ MultiresModifierData *mmd,
+ Object *object,
+ ModifierData *md)
+{
+ MultiresModifierData highest_mmd;
+ /* It is possible that the current subdivision level of multires is lower
+ * that it's maximum possible one (i.e., viewport is set to a lower level
+ * for the performance purposes). But even then, we want all the multires
+ * levels to be reshaped. Most accurate way to do so is to ignore all
+ * simplifications and calculate deformation modifier for the highest
+ * possible multires level.
+ * Alternative would be propagate displacement from current level to a
+ * higher ones, but that is likely to cause artifacts.
+ */
+ multires_reshape_init_mmd_top_level(&highest_mmd, mmd);
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ /* Perform sanity checks and early output. */
+ if (multires_get_level(
+ scene_eval, object, &highest_mmd, false, true) == 0)
+ {
+ return false;
+ }
+ /* Create mesh for the multires, ignoring any further modifiers (leading
+ * deformation modifiers will be applied though).
+ */
+ Mesh *multires_mesh = BKE_multires_create_mesh(
+ depsgraph, scene_eval, &highest_mmd, object);
+ int num_deformed_verts;
+ float (*deformed_verts)[3] = BKE_mesh_vertexCos_get(
+ multires_mesh, &num_deformed_verts);
+ /* Apply deformation modifier on the multires, */
+ const ModifierEvalContext modifier_ctx = {
+ .depsgraph = depsgraph,
+ .object = object,
+ .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY};
+ modwrap_deformVerts(
+ md, &modifier_ctx, multires_mesh, deformed_verts,
+ multires_mesh->totvert);
+ BKE_id_free(NULL, multires_mesh);
+ /* Reshaping */
+ bool result = multires_reshape_from_vertcos(
+ depsgraph,
+ object,
+ &highest_mmd,
+ deformed_verts,
+ num_deformed_verts,
+ false);
+ /* Cleanup */
+ MEM_freeN(deformed_verts);
+ return result;
+}
+
+/* =============================================================================
+ * Reshape from grids.
+ */
+
+typedef struct ReshapeFromCCGTaskData {
+ MultiresReshapeContext reshape_ctx;
+ int *face_ptex_offset;
+ const CCGKey *key;
+ /*const*/ CCGElem **grids;
+} ReshapeFromCCGTaskData;
+
+static void reshape_from_ccg_regular_face(ReshapeFromCCGTaskData *data,
+ const MPoly *coarse_poly)
+{
+ const CCGKey *key = data->key;
+ /*const*/ CCGElem **grids = data->grids;
+ const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int key_grid_size = key->grid_size;
+ const int key_grid_size_1 = key_grid_size - 1;
+ const int resolution = 2 * key_grid_size - 1;
+ const float resolution_1_inv = 1.0f / (float)(resolution - 1);
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_face_index = data->face_ptex_offset[coarse_poly_index];
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * resolution_1_inv;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * resolution_1_inv;
+ float corner_u, corner_v;
+ float grid_u, grid_v;
+ const int face_corner = BKE_subdiv_rotate_quad_to_corner(
+ u, v, &corner_u, &corner_v);
+ BKE_subdiv_ptex_face_uv_to_grid_uv(
+ corner_u, corner_v, &grid_u, &grid_v);
+ /*const*/ CCGElem *grid =
+ grids[coarse_poly->loopstart + face_corner];
+ /*const*/ CCGElem *grid_element = CCG_grid_elem(
+ key,
+ grid,
+ key_grid_size_1 * grid_u,
+ key_grid_size_1 * grid_v);
+ const float *final_P = CCG_elem_co(key, grid_element);
+ float final_mask = 0.0f;
+ if (key->has_mask) {
+ final_mask = *CCG_elem_mask(key, grid_element);
+ }
+ multires_reshape_vertex_from_final_data(
+ &data->reshape_ctx,
+ ptex_face_index,
+ u, v,
+ coarse_poly_index,
+ 0,
+ final_P, final_mask);
+ }
+ }
+}
+
+static void reshape_from_ccg_special_face(ReshapeFromCCGTaskData *data,
+ const MPoly *coarse_poly)
+{
+ const CCGKey *key = data->key;
+ /*const*/ CCGElem **grids = data->grids;
+ const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int key_grid_size = key->grid_size;
+ const int key_grid_size_1 = key_grid_size - 1;
+ const int resolution = key_grid_size;
+ const float resolution_1_inv = 1.0f / (float)(resolution - 1);
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_face_index = data->face_ptex_offset[coarse_poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * resolution_1_inv;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * resolution_1_inv;
+ float grid_u, grid_v;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, &grid_u, &grid_v);
+ /*const*/ CCGElem *grid =
+ grids[coarse_poly->loopstart + corner];
+ /*const*/ CCGElem *grid_element = CCG_grid_elem(
+ key,
+ grid,
+ key_grid_size_1 * grid_u,
+ key_grid_size_1 * grid_v);
+ const float *final_P = CCG_elem_co(key, grid_element);
+ float final_mask = 0.0f;
+ if (key->has_mask) {
+ final_mask = *CCG_elem_mask(key, grid_element);
+ }
+ multires_reshape_vertex_from_final_data(
+ &data->reshape_ctx,
+ ptex_face_index + corner,
+ u, v,
+ coarse_poly_index,
+ corner,
+ final_P, final_mask);
+ }
+ }
+ }
+}
+
+static void reshape_from_ccg_task(
+ void *__restrict userdata,
+ const int coarse_poly_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ ReshapeFromCCGTaskData *data = userdata;
+ const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ if (coarse_poly->totloop == 4) {
+ reshape_from_ccg_regular_face(data, coarse_poly);
+ }
+ else {
+ reshape_from_ccg_special_face(data, coarse_poly);
+ }
+}
+
+bool multiresModifier_reshapeFromCCG(
+ const int tot_level,
+ Mesh *coarse_mesh,
+ SubdivCCG *subdiv_ccg)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Sanity checks. */
+ if (coarse_mesh->totloop != subdiv_ccg->num_grids) {
+ /* Grids are supposed to eb created for each face-cornder (aka loop). */
+ return false;
+ }
+ MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ GridPaintMask *grid_paint_mask =
+ CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ /* Pick maximum between multires level and dispalcement level.
+ * This is because mesh can be used by objects with multires at different
+ * levels.
+ *
+ * TODO(sergey): At this point it should be possible to always use
+ * mdisps->level.
+ */
+ const int top_level = max_ii(tot_level, mdisps->level);
+ /* Make sure displacement grids are ready. */
+ multires_reshape_ensure_grids(coarse_mesh, top_level);
+ /* Construct context. */
+ ReshapeFromCCGTaskData data = {
+ .reshape_ctx = {
+ .subdiv = subdiv,
+ .coarse_mesh = coarse_mesh,
+ .mdisps = mdisps,
+ .grid_paint_mask = grid_paint_mask,
+ .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
+ .top_level = top_level},
+ .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv),
+ .key = &key,
+ .grids = subdiv_ccg->grids};
+ /* Initialize propagation to higher levels. */
+ MultiresPropagateData propagate_data;
+ multires_reshape_propagate_prepare(
+ &propagate_data, coarse_mesh, key.level, top_level);
+ /* Threaded grids iteration. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(0, coarse_mesh->totpoly,
+ &data,
+ reshape_from_ccg_task,
+ &parallel_range_settings);
+ /* Update higher levels if needed. */
+ multires_reshape_propagate(&propagate_data);
+ multires_reshape_propagate_free(&propagate_data);
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/multires_subdiv.c b/source/blender/blenkernel/intern/multires_subdiv.c
new file mode 100644
index 00000000000..e0b316d49de
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_subdiv.c
@@ -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) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/multires_subdiv.c
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_mesh.h"
+
+void BKE_multires_subdiv_settings_init(
+ SubdivSettings *settings,
+ const MultiresModifierData *mmd)
+{
+ settings->is_simple = (mmd->simple != 0);
+ settings->is_adaptive = !settings->is_simple;
+ settings->level = mmd->quality;
+ settings->vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY;
+ settings->fvar_linear_interpolation =
+ BKE_subdiv_fvar_interpolation_from_uv_smooth(mmd->uv_smooth);
+}
+
+void BKE_multires_subdiv_mesh_settings_init(
+ SubdivToMeshSettings *mesh_settings,
+ const Scene *scene,
+ const Object *object,
+ const MultiresModifierData *mmd,
+ const bool use_render_params,
+ const bool ignore_simplify)
+{
+ const int level = multires_get_level(
+ scene, object, mmd, use_render_params, ignore_simplify);
+ mesh_settings->resolution = (1 << level) + 1;
+}
diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c
deleted file mode 100644
index 35bcca52f63..00000000000
--- a/source/blender/blenkernel/intern/navmesh_conversion.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/navmesh_conversion.c
- * \ingroup bke
- */
-
-#include <math.h>
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_math.h"
-#include "BLI_sort.h"
-
-#include "BKE_navmesh_conversion.h"
-#include "BKE_cdderivedmesh.h"
-
-#include "recast-capi.h"
-
-BLI_INLINE float area2(const float *a, const float *b, const float *c)
-{
- return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
-}
-
-BLI_INLINE int left(const float *a, const float *b, const float *c)
-{
- return area2(a, b, c) < 0;
-}
-
-int polyNumVerts(const unsigned short *p, const int vertsPerPoly)
-{
- int i, nv = 0;
- for (i = 0; i < vertsPerPoly; i++) {
- if (p[i] == 0xffff)
- break;
- nv++;
- }
- return nv;
-}
-
-int polyIsConvex(const unsigned short *p, const int vertsPerPoly, const float *verts)
-{
- int j, nv = polyNumVerts(p, vertsPerPoly);
- if (nv < 3)
- return 0;
- for (j = 0; j < nv; j++) {
- const float *v = &verts[3 * p[j]];
- const float *v_next = &verts[3 * p[(j + 1) % nv]];
- const float *v_prev = &verts[3 * p[(nv + j - 1) % nv]];
- if (!left(v_prev, v, v_next))
- return 0;
-
- }
- return 1;
-}
-
-/* XXX, could replace with #dist_to_line_segment_v3(), or add a squared version */
-float distPointToSegmentSq(const float point[3], const float a[3], const float b[3])
-{
- float abx[3], dx[3];
- float d, t;
-
- sub_v3_v3v3(abx, b, a);
- sub_v3_v3v3(dx, point, a);
-
- d = abx[0] * abx[0] + abx[2] * abx[2];
- t = abx[0] * dx[0] + abx[2] * dx[2];
-
- if (d > 0.0f)
- t /= d;
- if (t < 0.0f)
- t = 0.0f;
- else if (t > 1.0f)
- t = 1.0f;
- dx[0] = a[0] + t * abx[0] - point[0];
- dx[2] = a[2] + t * abx[2] - point[2];
-
- return dx[0] * dx[0] + dx[2] * dx[2];
-}
-
-int buildRawVertIndicesData(DerivedMesh *dm, int *nverts_r, float **verts_r,
- int *ntris_r, unsigned short **tris_r, int **trisToFacesMap_r,
- int **recastData)
-{
- int vi, fi, triIdx;
- int nverts, ntris;
- int *trisToFacesMap;
- float *verts;
- unsigned short *tris, *tri;
- int nfaces;
- MFace *faces;
-
- nverts = dm->getNumVerts(dm);
- if (nverts >= 0xffff) {
- printf("Converting navmesh: Error! Too many vertices. Max number of vertices %d\n", 0xffff);
- return 0;
- }
- if (nverts == 0) {
- printf("Converting navmesh: Error! There are no vertices!\n");
- return 0;
- }
-
- verts = MEM_mallocN(sizeof(float[3]) * nverts, "buildRawVertIndicesData verts");
- dm->getVertCos(dm, (float(*)[3])verts);
-
- /* flip coordinates */
- for (vi = 0; vi < nverts; vi++) {
- SWAP(float, verts[3 * vi + 1], verts[3 * vi + 2]);
- }
-
- /* calculate number of tris */
- dm->recalcTessellation(dm);
- nfaces = dm->getNumTessFaces(dm);
- if (nfaces == 0) {
- printf("Converting navmesh: Error! There are %i vertices, but no faces!\n", nverts);
- return 0;
- }
-
- faces = dm->getTessFaceArray(dm);
- ntris = nfaces;
- for (fi = 0; fi < nfaces; fi++) {
- MFace *face = &faces[fi];
- if (face->v4)
- ntris++;
- }
-
- /* copy and transform to triangles (reorder on the run) */
- trisToFacesMap = MEM_callocN(sizeof(int) * ntris, "buildRawVertIndicesData trisToFacesMap");
- tris = MEM_callocN(sizeof(unsigned short) * 3 * ntris, "buildRawVertIndicesData tris");
- tri = tris;
- triIdx = 0;
- for (fi = 0; fi < nfaces; fi++) {
- MFace *face = &faces[fi];
- tri[3 * triIdx + 0] = (unsigned short) face->v1;
- tri[3 * triIdx + 1] = (unsigned short) face->v3;
- tri[3 * triIdx + 2] = (unsigned short) face->v2;
- trisToFacesMap[triIdx++] = fi;
- if (face->v4) {
- tri[3 * triIdx + 0] = (unsigned short) face->v1;
- tri[3 * triIdx + 1] = (unsigned short) face->v4;
- tri[3 * triIdx + 2] = (unsigned short) face->v3;
- trisToFacesMap[triIdx++] = fi;
- }
- }
-
- /* carefully, recast data is just reference to data in derived mesh */
- *recastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
-
- *nverts_r = nverts;
- *verts_r = verts;
- *ntris_r = ntris;
- *tris_r = tris;
- *trisToFacesMap_r = trisToFacesMap;
-
- return 1;
-}
-
-int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys,
- unsigned short *polys, const unsigned short *dmeshes,
- const float *verts, const unsigned short *dtris,
- const int *dtrisToPolysMap)
-{
- int polyidx;
- int capacity = vertsPerPoly;
- unsigned short *newPoly = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPoly");
- memset(newPoly, 0xff, sizeof(unsigned short) * capacity);
-
- for (polyidx = 0; polyidx < npolys; polyidx++) {
- size_t i;
- int j, k;
- int nv = 0;
- /* search border */
- int tri, btri = -1;
- int edge, bedge = -1;
- int dtrisNum = dmeshes[polyidx * 4 + 3];
- int dtrisBase = dmeshes[polyidx * 4 + 2];
- unsigned char *traversedTris = MEM_callocN(sizeof(unsigned char) * dtrisNum, "buildPolygonsByDetailedMeshes traversedTris");
- unsigned short *adjustedPoly;
- int adjustedNv;
- int allBorderTraversed;
-
- for (j = 0; j < dtrisNum && btri == -1; j++) {
- int curpolytri = dtrisBase + j;
- for (k = 0; k < 3; k++) {
- unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- btri = curpolytri;
- bedge = k;
- break;
- }
- }
- }
- if (btri == -1 || bedge == -1) {
- /* can't find triangle with border edge */
- MEM_freeN(traversedTris);
- MEM_freeN(newPoly);
-
- return 0;
- }
-
- newPoly[nv++] = dtris[btri * 3 * 2 + bedge];
- tri = btri;
- edge = (bedge + 1) % 3;
- traversedTris[tri - dtrisBase] = 1;
- while (tri != btri || edge != bedge) {
- int neighbortri = dtris[tri * 3 * 2 + 3 + edge];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- if (nv == capacity) {
- unsigned short *newPolyBig;
- capacity += vertsPerPoly;
- newPolyBig = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPolyBig");
- memset(newPolyBig, 0xff, sizeof(unsigned short) * capacity);
- memcpy(newPolyBig, newPoly, sizeof(unsigned short) * nv);
- MEM_freeN(newPoly);
- newPoly = newPolyBig;
- }
- newPoly[nv++] = dtris[tri * 3 * 2 + edge];
- /* move to next edge */
- edge = (edge + 1) % 3;
- }
- else {
- /* move to next tri */
- int twinedge = -1;
- for (k = 0; k < 3; k++) {
- if (dtris[neighbortri * 3 * 2 + 3 + k] == tri) {
- twinedge = k;
- break;
- }
- }
- if (twinedge == -1) {
- printf("Converting navmesh: Error! Can't find neighbor edge - invalid adjacency info\n");
- MEM_freeN(traversedTris);
- goto returnLabel;
- }
- tri = neighbortri;
- edge = (twinedge + 1) % 3;
- traversedTris[tri - dtrisBase] = 1;
- }
- }
-
- adjustedPoly = MEM_callocN(sizeof(unsigned short) * nv, "buildPolygonsByDetailedMeshes adjustedPoly");
- adjustedNv = 0;
- for (i = 0; i < nv; i++) {
- unsigned short prev = newPoly[(nv + i - 1) % nv];
- unsigned short cur = newPoly[i];
- unsigned short next = newPoly[(i + 1) % nv];
- float distSq = distPointToSegmentSq(&verts[3 * cur], &verts[3 * prev], &verts[3 * next]);
- static const float tolerance = 0.001f;
- if (distSq > tolerance)
- adjustedPoly[adjustedNv++] = cur;
- }
- memcpy(newPoly, adjustedPoly, adjustedNv * sizeof(unsigned short));
- MEM_freeN(adjustedPoly);
- nv = adjustedNv;
-
- allBorderTraversed = 1;
- for (i = 0; i < dtrisNum; i++) {
- if (traversedTris[i] == 0) {
- /* check whether it has border edges */
- int curpolytri = dtrisBase + i;
- for (k = 0; k < 3; k++) {
- unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- allBorderTraversed = 0;
- break;
- }
- }
- }
- }
-
- if (nv <= vertsPerPoly && allBorderTraversed) {
- for (i = 0; i < nv; i++) {
- polys[polyidx * vertsPerPoly * 2 + i] = newPoly[i];
- }
- }
-
- MEM_freeN(traversedTris);
- }
-
-returnLabel:
- MEM_freeN(newPoly);
-
- return 1;
-}
-
-struct SortContext {
- const int *recastData;
- const int *trisToFacesMap;
-};
-
-static int compareByData(const void *a, const void *b, void *ctx)
-{
- return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)a]] -
- ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)b]]);
-}
-
-int buildNavMeshData(const int nverts, const float *verts,
- const int ntris, const unsigned short *tris,
- const int *recastData, const int *trisToFacesMap,
- int *ndtris_r, unsigned short **dtris_r,
- int *npolys_r, unsigned short **dmeshes_r, unsigned short **polys_r,
- int *vertsPerPoly_r, int **dtrisToPolysMap_r, int **dtrisToTrisMap_r)
-
-{
- int *trisMapping;
- int i;
- struct SortContext context;
- int validTriStart, prevPolyIdx, curPolyIdx, newPolyIdx, prevpolyidx;
- unsigned short *dmesh;
-
- int ndtris, npolys, vertsPerPoly;
- unsigned short *dtris, *dmeshes, *polys;
- int *dtrisToPolysMap, *dtrisToTrisMap;
-
- if (!recastData) {
- printf("Converting navmesh: Error! Can't find recast custom data\n");
- return 0;
- }
-
- trisMapping = MEM_callocN(sizeof(int) * ntris, "buildNavMeshData trisMapping");
-
- /* sort the triangles by polygon idx */
- for (i = 0; i < ntris; i++)
- trisMapping[i] = i;
- context.recastData = recastData;
- context.trisToFacesMap = trisToFacesMap;
- BLI_qsort_r(trisMapping, ntris, sizeof(int), compareByData, &context);
-
- /* search first valid triangle - triangle of convex polygon */
- validTriStart = -1;
- for (i = 0; i < ntris; i++) {
- if (recastData[trisToFacesMap[trisMapping[i]]] > 0) {
- validTriStart = i;
- break;
- }
- }
-
- if (validTriStart < 0) {
- printf("Converting navmesh: Error! No valid polygons in mesh\n");
- MEM_freeN(trisMapping);
- return 0;
- }
-
- ndtris = ntris - validTriStart;
- /* fill dtris to faces mapping */
- dtrisToTrisMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToTrisMap");
- memcpy(dtrisToTrisMap, &trisMapping[validTriStart], ndtris * sizeof(int));
- MEM_freeN(trisMapping);
-
- /* create detailed mesh triangles - copy only valid triangles
- * and reserve memory for adjacency info */
- dtris = MEM_callocN(sizeof(unsigned short) * 3 * 2 * ndtris, "buildNavMeshData dtris");
- memset(dtris, 0xff, sizeof(unsigned short) * 3 * 2 * ndtris);
- for (i = 0; i < ndtris; i++) {
- memcpy(dtris + 3 * 2 * i, tris + 3 * dtrisToTrisMap[i], sizeof(unsigned short) * 3);
- }
-
- /* create new recast data corresponded to dtris and renumber for continuous indices */
- prevPolyIdx = -1;
- newPolyIdx = 0;
- dtrisToPolysMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToPolysMap");
- for (i = 0; i < ndtris; i++) {
- curPolyIdx = recastData[trisToFacesMap[dtrisToTrisMap[i]]];
- if (curPolyIdx != prevPolyIdx) {
- newPolyIdx++;
- prevPolyIdx = curPolyIdx;
- }
- dtrisToPolysMap[i] = newPolyIdx;
- }
-
-
- /* build adjacency info for detailed mesh triangles */
- if (!recast_buildMeshAdjacency(dtris, ndtris, nverts, 3)) {
- printf("Converting navmesh: Error! Unable to build mesh adjacency information\n");
- MEM_freeN(trisMapping);
- MEM_freeN(dtrisToPolysMap);
- return 0;
- }
-
- /* create detailed mesh description for each navigation polygon */
- npolys = dtrisToPolysMap[ndtris - 1];
- dmeshes = MEM_callocN(sizeof(unsigned short) * npolys * 4, "buildNavMeshData dmeshes");
- memset(dmeshes, 0, npolys * 4 * sizeof(unsigned short));
- dmesh = NULL;
- prevpolyidx = 0;
- for (i = 0; i < ndtris; i++) {
- int curpolyidx = dtrisToPolysMap[i];
- if (curpolyidx != prevpolyidx) {
- if (curpolyidx != prevpolyidx + 1) {
- printf("Converting navmesh: Error! Wrong order of detailed mesh faces\n");
- goto fail;
- }
- dmesh = dmesh == NULL ? dmeshes : dmesh + 4;
- dmesh[2] = (unsigned short)i; /* tbase */
- dmesh[3] = 0; /* tnum */
- prevpolyidx = curpolyidx;
- }
- dmesh[3]++;
- }
-
- /* create navigation polygons */
- vertsPerPoly = 6;
- polys = MEM_callocN(sizeof(unsigned short) * npolys * vertsPerPoly * 2, "buildNavMeshData polys");
- memset(polys, 0xff, sizeof(unsigned short) * vertsPerPoly * 2 * npolys);
-
- if (!buildPolygonsByDetailedMeshes(vertsPerPoly, npolys, polys, dmeshes, verts, dtris, dtrisToPolysMap)) {
- printf("Converting navmesh: Error! Unable to build polygons from detailed mesh\n");
- goto fail;
- }
-
- *ndtris_r = ndtris;
- *npolys_r = npolys;
- *vertsPerPoly_r = vertsPerPoly;
- *dtris_r = dtris;
- *dmeshes_r = dmeshes;
- *polys_r = polys;
- *dtrisToPolysMap_r = dtrisToPolysMap;
- *dtrisToTrisMap_r = dtrisToTrisMap;
-
- return 1;
-
-fail:
- MEM_freeN(dmeshes);
- MEM_freeN(dtrisToPolysMap);
- MEM_freeN(dtrisToTrisMap);
- return 0;
-}
-
-
-int buildNavMeshDataByDerivedMesh(DerivedMesh *dm, int *vertsPerPoly,
- int *nverts, float **verts,
- int *ndtris, unsigned short **dtris,
- int *npolys, unsigned short **dmeshes,
- unsigned short **polys, int **dtrisToPolysMap,
- int **dtrisToTrisMap, int **trisToFacesMap)
-{
- int res;
- int ntris = 0, *recastData = NULL;
- unsigned short *tris = NULL;
-
- res = buildRawVertIndicesData(dm, nverts, verts, &ntris, &tris, trisToFacesMap, &recastData);
- if (!res) {
- printf("Converting navmesh: Error! Can't get raw vertices and indices from mesh\n");
- goto exit;
- }
-
- res = buildNavMeshData(*nverts, *verts, ntris, tris, recastData, *trisToFacesMap,
- ndtris, dtris, npolys, dmeshes, polys, vertsPerPoly,
- dtrisToPolysMap, dtrisToTrisMap);
- if (!res) {
- printf("Converting navmesh: Error! Can't build navmesh data from mesh\n");
- goto exit;
- }
-
-exit:
- if (tris)
- MEM_freeN(tris);
-
- return res;
-}
-
-int polyFindVertex(const unsigned short *p, const int vertsPerPoly, unsigned short vertexIdx)
-{
- int i, res = -1;
- for (i = 0; i < vertsPerPoly; i++) {
- if (p[i] == 0xffff)
- break;
- if (p[i] == vertexIdx) {
- res = i;
- break;
- }
- }
- return res;
-}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 2f0af028abd..76671e0775d 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -60,7 +60,7 @@
#include "BKE_nla.h"
#ifdef WITH_AUDASPACE
-# include AUD_SPECIAL_H
+# include <AUD_Special.h>
#endif
#include "RNA_access.h"
@@ -76,7 +76,7 @@
/* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
* and the strip itself.
*/
-void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip)
+void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
{
NlaStrip *cs, *csn;
@@ -87,12 +87,13 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip)
/* free child-strips */
for (cs = strip->strips.first; cs; cs = csn) {
csn = cs->next;
- BKE_nlastrip_free(&strip->strips, cs);
+ BKE_nlastrip_free(&strip->strips, cs, do_id_user);
}
/* remove reference to action */
- if (strip->act)
+ if (strip->act != NULL && do_id_user) {
id_us_min(&strip->act->id);
+ }
/* free remapping info */
//if (strip->remap)
@@ -114,7 +115,7 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip)
/* Remove the given NLA track from the set of NLA tracks, free the track's data,
* and the track itself.
*/
-void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt)
+void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
{
NlaStrip *strip, *stripn;
@@ -125,7 +126,7 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt)
/* free strips */
for (strip = nlt->strips.first; strip; strip = stripn) {
stripn = strip->next;
- BKE_nlastrip_free(&nlt->strips, strip);
+ BKE_nlastrip_free(&nlt->strips, strip, do_id_user);
}
/* free NLA track itself now */
@@ -138,7 +139,7 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt)
/* Free the elements of type NLA Tracks provided in the given list, but do not free
* the list itself since that is not free-standing
*/
-void BKE_nla_tracks_free(ListBase *tracks)
+void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
{
NlaTrack *nlt, *nltn;
@@ -149,7 +150,7 @@ void BKE_nla_tracks_free(ListBase *tracks)
/* free tracks one by one */
for (nlt = tracks->first; nlt; nlt = nltn) {
nltn = nlt->next;
- BKE_nlatrack_free(tracks, nlt);
+ BKE_nlatrack_free(tracks, nlt, do_id_user);
}
/* clear the list's pointers to be safe */
@@ -162,12 +163,15 @@ void BKE_nla_tracks_free(ListBase *tracks)
* Copy NLA strip
*
* \param use_same_action When true, the existing action is used (instead of being duplicated)
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
*/
-NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_action)
+NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_action, const int flag)
{
NlaStrip *strip_d;
NlaStrip *cs, *cs_d;
+ const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+
/* sanity check */
if (strip == NULL)
return NULL;
@@ -179,12 +183,14 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac
/* handle action */
if (strip_d->act) {
if (use_same_action) {
- /* increase user-count of action */
- id_us_plus(&strip_d->act->id);
+ if (do_id_user) {
+ /* increase user-count of action */
+ id_us_plus(&strip_d->act->id);
+ }
}
else {
/* use a copy of the action instead (user count shouldn't have changed yet) */
- strip_d->act = BKE_action_copy(bmain, strip_d->act);
+ BKE_id_copy_ex(bmain, &strip_d->act->id, (ID **)&strip_d->act, flag, false);
}
}
@@ -196,7 +202,7 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac
BLI_listbase_clear(&strip_d->strips);
for (cs = strip->strips.first; cs; cs = cs->next) {
- cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action);
+ cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action, flag);
BLI_addtail(&strip_d->strips, cs_d);
}
@@ -204,8 +210,11 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac
return strip_d;
}
-/* Copy NLA Track */
-NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_actions)
+/**
+ * Copy a single NLA Track.
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
+ */
+NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_actions, const int flag)
{
NlaStrip *strip, *strip_d;
NlaTrack *nlt_d;
@@ -222,7 +231,7 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_acti
BLI_listbase_clear(&nlt_d->strips);
for (strip = nlt->strips.first; strip; strip = strip->next) {
- strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions);
+ strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions, flag);
BLI_addtail(&nlt_d->strips, strip_d);
}
@@ -230,8 +239,11 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_acti
return nlt_d;
}
-/* Copy all NLA data */
-void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src)
+/**
+ * Copy all NLA data.
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
+ */
+void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int flag)
{
NlaTrack *nlt, *nlt_d;
@@ -246,7 +258,7 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src)
for (nlt = src->first; nlt; nlt = nlt->next) {
/* make a copy, and add the copy to the destination list */
// XXX: we need to fix this sometime
- nlt_d = BKE_nlatrack_copy(bmain, nlt, true);
+ nlt_d = BKE_nlatrack_copy(bmain, nlt, true, flag);
BLI_addtail(dst, nlt_d);
}
}
@@ -752,7 +764,7 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
}
/* free the meta-strip now */
- BKE_nlastrip_free(strips, strip);
+ BKE_nlastrip_free(strips, strip, true);
}
/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
@@ -2013,30 +2025,3 @@ void BKE_nla_tweakmode_exit(AnimData *adt)
adt->actstrip = NULL;
adt->flag &= ~ADT_NLA_EDIT_ON;
}
-
-/* Baking Tools ------------------------------------------- */
-
-static void UNUSED_FUNCTION(BKE_nla_bake) (Scene *scene, ID *UNUSED(id), AnimData *adt, int UNUSED(flag))
-{
-
- /* verify that data is valid
- * 1) Scene and AnimData must be provided
- * 2) there must be tracks to merge...
- */
- if (ELEM(NULL, scene, adt, adt->nla_tracks.first))
- return;
-
- /* if animdata currently has an action, 'push down' this onto the stack first */
- if (adt->action)
- BKE_nla_action_pushdown(adt);
-
- /* get range of motion to bake, and the channels involved... */
-
- /* temporarily mute the action, and start keying to it */
-
- /* start keying... */
-
- /* unmute the action */
-}
-
-/* *************************************************** */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 2946fb29863..04cc58f373f 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -75,6 +75,9 @@
#include "NOD_shader.h"
#include "NOD_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#define NODE_DEFAULT_MAX_WIDTH 700
/* Fallback types for undefined tree, nodes, sockets */
@@ -1211,6 +1214,56 @@ void nodeDetachNode(struct bNode *node)
}
}
+void nodePositionRelative(bNode *from_node, bNode *to_node, bNodeSocket *from_sock, bNodeSocket *to_sock)
+{
+ float offset_x;
+ int tot_sock_idx;
+
+ /* Socket to plug into. */
+ if (SOCK_IN == to_sock->in_out) {
+ offset_x = - (from_node->typeinfo->width + 50);
+ tot_sock_idx = BLI_listbase_count(&to_node->outputs);
+ tot_sock_idx += BLI_findindex(&to_node->inputs, to_sock);
+ }
+ else {
+ offset_x = to_node->typeinfo->width + 50;
+ tot_sock_idx = BLI_findindex(&to_node->outputs, to_sock);
+ }
+
+ BLI_assert(tot_sock_idx != -1);
+
+ float offset_y = U.widget_unit * tot_sock_idx;
+
+ /* Output socket. */
+ if (from_sock) {
+ if (SOCK_IN == from_sock->in_out) {
+ tot_sock_idx = BLI_listbase_count(&from_node->outputs);
+ tot_sock_idx += BLI_findindex(&from_node->inputs, from_sock);
+ }
+ else {
+ tot_sock_idx = BLI_findindex(&from_node->outputs, from_sock);
+ }
+ }
+
+ BLI_assert(tot_sock_idx != -1);
+
+ offset_y -= U.widget_unit * tot_sock_idx;
+
+ from_node->locx = to_node->locx + offset_x;
+ from_node->locy = to_node->locy - offset_y;
+}
+
+void nodePositionPropagate(bNode *node)
+{
+ for (bNodeSocket *nsock = node->inputs.first; nsock; nsock = nsock->next) {
+ if (nsock->link != NULL) {
+ bNodeLink *link = nsock->link;
+ nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock);
+ nodePositionPropagate(link->fromnode);
+ }
+ }
+}
+
void ntreeInitDefault(bNodeTree *ntree)
{
ntree_set_typeinfo(ntree, NULL);
@@ -1592,54 +1645,6 @@ void BKE_node_preview_set_pixel(bNodePreview *preview, const float col[4], int x
}
}
-#if 0
-static void nodeClearPreview(bNode *node)
-{
- if (node->preview && node->preview->rect)
- memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect));
-}
-
-/* use it to enforce clear */
-void ntreeClearPreview(bNodeTree *ntree)
-{
- bNode *node;
-
- if (ntree == NULL)
- return;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->typeinfo->flag & NODE_PREVIEW)
- nodeClearPreview(node);
- if (node->type == NODE_GROUP)
- ntreeClearPreview((bNodeTree *)node->id);
- }
-}
-
-/* hack warning! this function is only used for shader previews, and
- * since it gets called multiple times per pixel for Ztransp we only
- * add the color once. Preview gets cleared before it starts render though */
-void nodeAddToPreview(bNode *node, const float col[4], int x, int y, int do_manage)
-{
- bNodePreview *preview = node->preview;
- if (preview) {
- if (x >= 0 && y >= 0) {
- if (x < preview->xsize && y < preview->ysize) {
- unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
-
- if (do_manage) {
- linearrgb_to_srgb_uchar4(tar, col);
- }
- else {
- rgba_float_to_uchar(tar, col);
- }
- }
- //else printf("prv out bound x y %d %d\n", x, y);
- }
- //else printf("prv out bound x y %d %d\n", x, y);
- }
-}
-#endif
-
/* ************** Free stuff ********** */
/* goes over entire tree */
@@ -1684,14 +1689,16 @@ static void node_unlink_attached(bNodeTree *ntree, bNode *parent)
}
/** \note caller needs to manage node->id user */
-static void node_free_node_ex(bNodeTree *ntree, bNode *node, bool remove_animdata, bool use_api_free_cb)
+static void node_free_node_ex(
+ Main *bmain, bNodeTree *ntree, bNode *node,
+ bool remove_animdata, bool use_api_free_cb)
{
bNodeSocket *sock, *nextsock;
/* don't remove node animdata if the tree is localized,
* Action is shared with the original tree (T38221)
*/
- remove_animdata &= ntree && !(ntree->flag & NTREE_IS_LOCALIZED);
+ remove_animdata &= ntree && !(ntree->id.tag & LIB_TAG_LOCALIZED);
/* extra free callback */
if (use_api_free_cb && node->typeinfo->freefunc_api) {
@@ -1718,7 +1725,11 @@ static void node_free_node_ex(bNodeTree *ntree, bNode *node, bool remove_animdat
BLI_strescape(propname_esc, node->name, sizeof(propname_esc));
BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc);
- BKE_animdata_fix_paths_remove((ID *)ntree, prefix);
+ if (BKE_animdata_fix_paths_remove((ID *)ntree, prefix)) {
+ if (bmain != NULL) {
+ DEG_relations_tag_update(bmain);
+ }
+ }
}
if (ntree->typeinfo->free_node_cache)
@@ -1761,7 +1772,12 @@ static void node_free_node_ex(bNodeTree *ntree, bNode *node, bool remove_animdat
void nodeFreeNode(bNodeTree *ntree, bNode *node)
{
- node_free_node_ex(ntree, node, true, true);
+ node_free_node_ex(NULL, ntree, node, false, true);
+}
+
+void nodeDeleteNode(Main *bmain, bNodeTree *ntree, bNode *node)
+{
+ node_free_node_ex(bmain, ntree, node, true, true);
}
static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock)
@@ -1784,7 +1800,7 @@ static void free_localized_node_groups(bNodeTree *ntree)
* since it is a localized copy itself (no risk of accessing free'd
* data in main, see [#37939]).
*/
- if (!(ntree->flag & NTREE_IS_LOCALIZED))
+ if (!(ntree->id.tag & LIB_TAG_LOCALIZED))
return;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1831,7 +1847,7 @@ void ntreeFreeTree(bNodeTree *ntree)
for (node = ntree->nodes.first; node; node = next) {
next = node->next;
- node_free_node_ex(ntree, node, false, false);
+ node_free_node_ex(NULL, ntree, node, false, false);
}
/* free interface sockets */
@@ -1939,15 +1955,15 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
-bNodeTree *ntreeFromID(ID *id)
+bNodeTree *ntreeFromID(const ID *id)
{
switch (GS(id->name)) {
- case ID_MA: return ((Material *)id)->nodetree;
- case ID_LA: return ((Lamp *)id)->nodetree;
- case ID_WO: return ((World *)id)->nodetree;
- case ID_TE: return ((Tex *)id)->nodetree;
- case ID_SCE: return ((Scene *)id)->nodetree;
- case ID_LS: return ((FreestyleLineStyle *)id)->nodetree;
+ case ID_MA: return ((const Material *)id)->nodetree;
+ case ID_LA: return ((const Lamp *)id)->nodetree;
+ case ID_WO: return ((const World *)id)->nodetree;
+ case ID_TE: return ((const Tex *)id)->nodetree;
+ case ID_SCE: return ((const Scene *)id)->nodetree;
+ case ID_LS: return ((const FreestyleLineStyle *)id)->nodetree;
default: return NULL;
}
}
@@ -1995,9 +2011,6 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
if (ntree) {
bNodeTree *ltree;
bNode *node;
- AnimData *adt;
-
- bAction *action_backup = NULL, *tmpact_backup = NULL;
BLI_spin_lock(&spin);
if (!ntree->duplilock) {
@@ -2007,24 +2020,16 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
BLI_mutex_lock(ntree->duplilock);
- /* Workaround for copying an action on each render!
- * set action to NULL so animdata actions don't get copied */
- adt = BKE_animdata_from_id(&ntree->id);
-
- if (adt) {
- action_backup = adt->action;
- tmpact_backup = adt->tmpact;
-
- adt->action = NULL;
- adt->tmpact = NULL;
- }
-
/* Make full copy outside of Main database.
* Note: previews are not copied here.
*/
- BKE_id_copy_ex(NULL, (ID *)ntree, (ID **)&ltree,
- LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_COPY_NO_PREVIEW, false);
- ltree->flag |= NTREE_IS_LOCALIZED;
+ BKE_id_copy_ex(
+ NULL, &ntree->id, (ID **)&ltree,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_COPY_NO_PREVIEW |
+ LIB_ID_COPY_NO_ANIMDATA),
+ false);
for (node = ltree->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP && node->id) {
@@ -2032,31 +2037,19 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
}
}
- if (adt) {
- AnimData *ladt = BKE_animdata_from_id(&ltree->id);
-
- adt->action = ladt->action = action_backup;
- adt->tmpact = ladt->tmpact = tmpact_backup;
-
- if (action_backup)
- id_us_plus(&action_backup->id);
- if (tmpact_backup)
- id_us_plus(&tmpact_backup->id);
-
- }
- /* end animdata uglyness */
-
/* ensures only a single output node is enabled */
ntreeSetOutput(ntree);
for (node = ntree->nodes.first; node; node = node->next) {
/* store new_node pointer to original */
- node->new_node->new_node = node;
+ node->new_node->original = node;
}
if (ntree->typeinfo->localize)
ntree->typeinfo->localize(ltree, ntree);
+ ltree->id.tag |= LIB_TAG_LOCALIZED;
+
BLI_mutex_unlock(ntree->duplilock);
return ltree;
@@ -2596,7 +2589,7 @@ void BKE_node_clipboard_clear(void)
for (node = node_clipboard.nodes.first; node; node = node_next) {
node_next = node->next;
- node_free_node_ex(NULL, node, false, false);
+ node_free_node_ex(NULL, NULL, node, false, false);
}
BLI_listbase_clear(&node_clipboard.nodes);
@@ -3127,77 +3120,6 @@ void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
}
-/* nodes that use ID data get synced with local data */
-void nodeSynchronizeID(bNode *node, bool copy_to_id)
-{
- if (node->id == NULL) return;
-
- if (ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) {
- bNodeSocket *sock;
- Material *ma = (Material *)node->id;
- int a;
- short check_flags = SOCK_UNAVAIL;
-
- if (!copy_to_id)
- check_flags |= SOCK_HIDDEN;
-
- /* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */
- for (a = 0, sock = node->inputs.first; sock; sock = sock->next, a++) {
- if (!(sock->flag & check_flags)) {
- if (copy_to_id) {
- switch (a) {
- case MAT_IN_COLOR:
- copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_SPEC:
- copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_REFL:
- ma->ref = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_MIR:
- copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_AMB:
- ma->amb = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_EMIT:
- ma->emit = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_SPECTRA:
- ma->spectra = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_RAY_MIRROR:
- ma->ray_mirror = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_ALPHA:
- ma->alpha = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_TRANSLUCENCY:
- ma->translucency = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- }
- }
- else {
- switch (a) {
- case MAT_IN_COLOR:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->r); break;
- case MAT_IN_SPEC:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->specr); break;
- case MAT_IN_REFL:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ref; break;
- case MAT_IN_MIR:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->mirr); break;
- case MAT_IN_AMB:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->amb; break;
- case MAT_IN_EMIT:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->emit; break;
- case MAT_IN_SPECTRA:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->spectra; break;
- case MAT_IN_RAY_MIRROR:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ray_mirror; break;
- case MAT_IN_ALPHA:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->alpha; break;
- case MAT_IN_TRANSLUCENCY:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->translucency; break;
- }
- }
- }
- }
- }
-}
-
-
/* ************* node type access ********** */
void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
@@ -3424,11 +3346,6 @@ void node_type_internal_links(bNodeType *ntype, void (*update_internal_links)(bN
ntype->update_internal_links = update_internal_links;
}
-void node_type_compatibility(struct bNodeType *ntype, short compatibility)
-{
- ntype->compatibility = compatibility;
-}
-
/* callbacks for undefined types */
static bool node_undefined_poll(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(nodetree))
@@ -3563,10 +3480,7 @@ static void registerShaderNodes(void)
{
register_node_type_sh_group();
- register_node_type_sh_output();
- register_node_type_sh_material();
register_node_type_sh_camera();
- register_node_type_sh_lamp();
register_node_type_sh_gamma();
register_node_type_sh_brightcontrast();
register_node_type_sh_value();
@@ -3577,9 +3491,8 @@ static void registerShaderNodes(void)
register_node_type_sh_mix_rgb();
register_node_type_sh_valtorgb();
register_node_type_sh_rgbtobw();
- register_node_type_sh_texture();
+ register_node_type_sh_shadertorgb();
register_node_type_sh_normal();
- register_node_type_sh_geom();
register_node_type_sh_mapping();
register_node_type_sh_curve_vec();
register_node_type_sh_curve_rgb();
@@ -3587,7 +3500,6 @@ static void registerShaderNodes(void)
register_node_type_sh_vect_math();
register_node_type_sh_vect_transform();
register_node_type_sh_squeeze();
- register_node_type_sh_material_ext();
register_node_type_sh_invert();
register_node_type_sh_seprgb();
register_node_type_sh_combrgb();
@@ -3633,6 +3545,7 @@ static void registerShaderNodes(void)
register_node_type_sh_add_shader();
register_node_type_sh_uvmap();
register_node_type_sh_uvalongstroke();
+ register_node_type_sh_eevee_specular();
register_node_type_sh_output_lamp();
register_node_type_sh_output_material();
@@ -3826,3 +3739,28 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
return true;
}
+
+/* -------------------------------------------------------------------- */
+/* NodeTree kernel functions */
+
+void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index)
+{
+ BLI_assert(layer_index != -1);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
+ if (node->custom1 == layer_index) {
+ node->custom1 = 0;
+ }
+ else if (node->custom1 > layer_index) {
+ node->custom1--;
+ }
+ }
+ }
+}
+
+void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
+ bNodeTree *ntree_dst,
+ const bNodeTree *ntree_src)
+{
+ DEG_debug_print_eval(depsgraph, __func__, ntree_src->id.name, ntree_dst);
+}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 82c86747af8..67edcff49a6 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -39,9 +39,10 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_group_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
@@ -53,12 +54,13 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
#include "DNA_object_types.h"
-#include "DNA_property_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "BLI_blenlib.h"
@@ -76,21 +78,21 @@
#include "BKE_idprop.h"
#include "BKE_armature.h"
#include "BKE_action.h"
-#include "BKE_bullet.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_animsys.h"
#include "BKE_anim.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
-#include "BKE_group.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_icons.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
+#include "BKE_layer.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -103,20 +105,28 @@
#include "BKE_multires.h"
#include "BKE_node.h"
#include "BKE_object.h"
+#include "BKE_object_facemap.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "BKE_property.h"
+#include "BKE_lightprobe.h"
#include "BKE_rigidbody.h"
-#include "BKE_sca.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
+#include "BKE_shader_fx.h"
#include "BKE_speaker.h"
#include "BKE_softbody.h"
#include "BKE_subsurf.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_material.h"
#include "BKE_camera.h"
#include "BKE_image.h"
+#include "BKE_gpencil.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DRW_engine.h"
#ifdef WITH_MOD_FLUID
#include "LBM_fluidsim.h"
@@ -129,8 +139,6 @@
#include "CCGSubSurf.h"
#include "atomic_ops.h"
-#include "GPU_material.h"
-
/* Vertex parent modifies original BMesh which is not safe for threading.
* Ideally such a modification should be handled as a separate DAG update
* callback for mesh datablock, but for until it is actually supported use
@@ -152,16 +160,6 @@ void BKE_object_workob_clear(Object *workob)
workob->rotmode = ROT_MODE_EUL;
}
-void BKE_object_update_base_layer(struct Scene *scene, Object *ob)
-{
- Base *base = scene->base.first;
-
- while (base) {
- if (base->object == ob) base->lay = ob->lay;
- base = base->next;
- }
-}
-
void BKE_object_free_particlesystems(Object *ob)
{
ParticleSystem *psys;
@@ -173,42 +171,35 @@ void BKE_object_free_particlesystems(Object *ob)
void BKE_object_free_softbody(Object *ob)
{
- if (ob->soft) {
- sbFree(ob->soft);
- ob->soft = NULL;
- }
-}
-
-void BKE_object_free_bulletsoftbody(Object *ob)
-{
- if (ob->bsoft) {
- bsbFree(ob->bsoft);
- ob->bsoft = NULL;
- }
+ sbFree(ob);
}
void BKE_object_free_curve_cache(Object *ob)
{
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
- if (ob->curve_cache->path) {
- free_path(ob->curve_cache->path);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ if (ob->runtime.curve_cache->path) {
+ free_path(ob->runtime.curve_cache->path);
}
- BKE_nurbList_free(&ob->curve_cache->deformed_nurbs);
- MEM_freeN(ob->curve_cache);
- ob->curve_cache = NULL;
+ BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs);
+ MEM_freeN(ob->runtime.curve_cache);
+ ob->runtime.curve_cache = NULL;
}
}
void BKE_object_free_modifiers(Object *ob, const int flag)
{
ModifierData *md;
+ GpencilModifierData *gp_md;
while ((md = BLI_pophead(&ob->modifiers))) {
modifier_free_ex(md, flag);
}
+ while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
+ BKE_gpencil_modifier_free_ex(gp_md, flag);
+ }
/* particle modifiers were freed, so free the particlesystems as well */
BKE_object_free_particlesystems(ob);
@@ -219,6 +210,15 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
BKE_object_free_derived_caches(ob);
}
+void BKE_object_free_shaderfx(Object *ob, const int flag)
+{
+ ShaderFxData *fx;
+
+ while ((fx = BLI_pophead(&ob->shader_fx))) {
+ BKE_shaderfx_free_ex(fx, flag);
+ }
+}
+
void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
{
/* reset functionality */
@@ -241,6 +241,29 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
}
}
+void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd)
+{
+ if (hmd->object == NULL) {
+ return;
+ }
+ /* reset functionality */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
+
+ if (hmd->subtarget[0] && pchan) {
+ float imat[4][4], mat[4][4];
+
+ /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
+ mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
+
+ invert_m4_m4(imat, mat);
+ mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
+ }
+ else {
+ invert_m4_m4(hmd->object->imat, hmd->object->obmat);
+ mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
+ }
+}
+
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti;
@@ -265,7 +288,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return true;
}
-void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
+void BKE_object_link_modifiers(Scene *scene, struct Object *ob_dst, const struct Object *ob_src)
{
ModifierData *md;
BKE_object_free_modifiers(ob_dst, 0);
@@ -291,7 +314,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
switch (md->type) {
case eModifierType_Softbody:
- BKE_object_copy_softbody(ob_dst, ob_src);
+ BKE_object_copy_softbody(ob_dst, ob_src, 0);
break;
case eModifierType_Skin:
/* ensure skin-node customdata exists */
@@ -304,7 +327,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
if (md->type == eModifierType_Multires) {
/* Has to be done after mod creation, but *before* we actually copy its settings! */
- multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ multiresModifier_sync_levels_ex(scene, ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
}
modifier_copyData(md, nmd);
@@ -317,6 +340,93 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
/* TODO: smoke?, cloth? */
}
+/* Copy CCG related data. Used to sync copy of mesh with reshaped original
+ * mesh.
+ */
+static void copy_ccg_data(Mesh *mesh_destination,
+ Mesh *mesh_source,
+ int layer_type)
+{
+ BLI_assert(mesh_destination->totloop == mesh_source->totloop);
+ CustomData *data_destination = &mesh_destination->ldata;
+ CustomData *data_source = &mesh_source->ldata;
+ const int num_elements = mesh_source->totloop;
+ if (!CustomData_has_layer(data_source, layer_type)) {
+ return;
+ }
+ const int layer_index = CustomData_get_layer_index(
+ data_destination, layer_type);
+ CustomData_free_layer(
+ data_destination, layer_type, num_elements, layer_index);
+ BLI_assert(!CustomData_has_layer(data_destination, layer_type));
+ CustomData_add_layer(
+ data_destination, layer_type, CD_CALLOC, NULL, num_elements);
+ BLI_assert(CustomData_has_layer(data_destination, layer_type));
+ CustomData_copy_layer_type_data(data_source, data_destination,
+ layer_type, 0, 0, num_elements);
+}
+
+static void object_update_from_subsurf_ccg(Object *object)
+{
+ /* Currently CCG is only created for Mesh objects. */
+ if (object->type != OB_MESH) {
+ return;
+ }
+ /* Object was never evaluated, so can not have CCG subdivision surface. */
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ if (mesh_eval == NULL) {
+ return;
+ }
+ SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
+ if (subdiv_ccg == NULL) {
+ return;
+ }
+ /* Check whether there is anything to be reshaped. */
+ if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) {
+ return;
+ }
+ const int tot_level = mesh_eval->runtime.subdiv_ccg_tot_level;
+ Object *object_orig = DEG_get_original_object(object);
+ Mesh *mesh_orig = (Mesh *)object_orig->data;
+ multiresModifier_reshapeFromCCG(tot_level, mesh_orig, subdiv_ccg);
+ /* NOTE: we need to reshape into an original mesh from main database,
+ * allowing:
+ *
+ * - Update copies of that mesh at any moment.
+ * - Save the file without doing extra reshape.
+ * - All the users of the mesh have updated displacement.
+ *
+ * However, the tricky part here is that we only know about sculpted
+ * state of a mesh on an object level, and object is being updated after
+ * mesh datablock is updated. This forces us to:
+ *
+ * - Update mesh datablock from object evaluation, which is technically
+ * forbidden, but there is no other place for this yet.
+ * - Reshape to the original mesh from main database, and then copy updated
+ * layer to copy of that mesh (since copy of the mesh has decoupled
+ * custom data layers).
+ *
+ * All this is defeating all the designs we need to follow to allow safe
+ * threaded evaluation, but this is as good as we can make it within the
+ * current sculpt//evaluated mesh design. This is also how we've survived
+ * with old DerivedMesh based solutions. So, while this is all wrong and
+ * needs reconsideration, doesn't seem to be a big stopper for real
+ * production artists.
+ */
+ /* TODO(sergey): Solve this somehow, to be fully stable for threaded
+ * evaluation environment.
+ */
+ /* NOTE: runtime.mesh_orig is what was before assigning mesh_eval,
+ * it is orig as in what was in object_eval->data before evaluating
+ * modifier stack.
+ *
+ * mesh_cow is a copy-on-written version od object_orig->data.
+ */
+ Mesh *mesh_cow = object->runtime.mesh_orig;
+ copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS);
+ copy_ccg_data(mesh_cow, mesh_orig, CD_GRID_PAINT_MASK);
+}
+
/* free data derived from mesh, called when mesh changes or is freed */
void BKE_object_free_derived_caches(Object *ob)
{
@@ -346,6 +456,39 @@ void BKE_object_free_derived_caches(Object *ob)
ob->bb = NULL;
}
+ object_update_from_subsurf_ccg(ob);
+ BKE_object_free_derived_mesh_caches(ob);
+ BKE_armature_cached_bbone_deformation_free(ob);
+
+ if (ob->runtime.mesh_eval != NULL) {
+ Mesh *mesh_eval = ob->runtime.mesh_eval;
+ /* Restore initial pointer. */
+ if (ob->data == mesh_eval) {
+ ob->data = ob->runtime.mesh_orig;
+ }
+ /* Evaluated mesh points to edit mesh, but does not own it. */
+ mesh_eval->edit_btmesh = NULL;
+ BKE_mesh_free(mesh_eval);
+ BKE_libblock_free_data(&mesh_eval->id, false);
+ MEM_freeN(mesh_eval);
+ ob->runtime.mesh_eval = NULL;
+ }
+ if (ob->runtime.mesh_deform_eval != NULL) {
+ Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval;
+ BKE_mesh_free(mesh_deform_eval);
+ BKE_libblock_free_data(&mesh_deform_eval->id, false);
+ MEM_freeN(mesh_deform_eval);
+ ob->runtime.mesh_deform_eval = NULL;
+ }
+
+ BKE_object_free_curve_cache(ob);
+
+ /* clear grease pencil data */
+ DRW_gpencil_freecache(ob);
+}
+
+void BKE_object_free_derived_mesh_caches(struct Object *ob)
+{
if (ob->derivedFinal) {
ob->derivedFinal->needsFree = 1;
ob->derivedFinal->release(ob->derivedFinal);
@@ -356,8 +499,6 @@ void BKE_object_free_derived_caches(Object *ob)
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform = NULL;
}
-
- BKE_object_free_curve_cache(ob);
}
void BKE_object_free_caches(Object *object)
@@ -381,14 +522,12 @@ void BKE_object_free_caches(Object *object)
for (md = object->modifiers.first; md != NULL; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
- if (psmd->dm_final != NULL) {
- psmd->dm_final->needsFree = 1;
- psmd->dm_final->release(psmd->dm_final);
- psmd->dm_final = NULL;
- if (psmd->dm_deformed != NULL) {
- psmd->dm_deformed->needsFree = 1;
- psmd->dm_deformed->release(psmd->dm_deformed);
- psmd->dm_deformed = NULL;
+ if (psmd->mesh_final) {
+ BKE_id_free(NULL, psmd->mesh_final);
+ psmd->mesh_final = NULL;
+ if (psmd->mesh_original) {
+ BKE_id_free(NULL, psmd->mesh_original);
+ psmd->mesh_original = NULL;
}
psmd->flag |= eParticleSystemFlag_file_loaded;
update_flag |= OB_RECALC_DATA;
@@ -396,12 +535,21 @@ void BKE_object_free_caches(Object *object)
}
}
+ /* NOTE: If object is coming from a duplicator, it might be a temporary
+ * object created by dependency graph, which shares pointers with original
+ * object. In this case we can not free anything.
+ */
+ if ((object->base_flag & BASE_FROMDUPLI) == 0) {
+ BKE_object_free_derived_caches(object);
+ update_flag |= OB_RECALC_DATA;
+ }
+
/* Tag object for update, so once memory critical operation is over and
* scene update routines are back to it's business the object will be
* guaranteed to be in a known state.
*/
if (update_flag != 0) {
- DAG_id_tag_update(&object->id, update_flag);
+ DEG_id_tag_update(&object->id, update_flag);
}
}
@@ -410,8 +558,11 @@ void BKE_object_free(Object *ob)
{
BKE_animdata_free((ID *)ob, false);
+ DRW_drawdata_free((ID *)ob);
+
/* BKE_<id>_free shall never touch to ID->us. Never ever. */
BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
MEM_SAFE_FREE(ob->mat);
MEM_SAFE_FREE(ob->matbits);
@@ -419,6 +570,7 @@ void BKE_object_free(Object *ob)
MEM_SAFE_FREE(ob->bb);
BLI_freelistN(&ob->defbase);
+ BLI_freelistN(&ob->fmaps);
if (ob->pose) {
BKE_pose_free_ex(ob->pose, false);
ob->pose = NULL;
@@ -427,27 +579,14 @@ void BKE_object_free(Object *ob)
animviz_free_motionpath(ob->mpath);
ob->mpath = NULL;
}
- BKE_bproperty_free_list(&ob->prop);
-
- free_sensors(&ob->sensors);
- free_controllers(&ob->controllers);
- free_actuators(&ob->actuators);
BKE_constraints_free_ex(&ob->constraints, false);
free_partdeflect(ob->pd);
- BKE_rigidbody_free_object(ob);
+ BKE_rigidbody_free_object(ob, NULL);
BKE_rigidbody_free_constraint(ob);
- if (ob->soft) {
- sbFree(ob->soft);
- ob->soft = NULL;
- }
- if (ob->bsoft) {
- bsbFree(ob->bsoft);
- ob->bsoft = NULL;
- }
- GPU_lamp_free(ob);
+ sbFree(ob);
BKE_sculptsession_free(ob);
@@ -456,12 +595,12 @@ void BKE_object_free(Object *ob)
BLI_freelistN(&ob->lodlevels);
/* Free runtime curves data. */
- if (ob->curve_cache) {
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
- if (ob->curve_cache->path)
- free_path(ob->curve_cache->path);
- MEM_freeN(ob->curve_cache);
- ob->curve_cache = NULL;
+ if (ob->runtime.curve_cache) {
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ if (ob->runtime.curve_cache->path)
+ free_path(ob->runtime.curve_cache->path);
+ MEM_freeN(ob->runtime.curve_cache);
+ ob->runtime.curve_cache = NULL;
}
BKE_previewimg_free(&ob->preview);
@@ -470,63 +609,135 @@ void BKE_object_free(Object *ob)
/* actual check for internal data, not context or flags */
bool BKE_object_is_in_editmode(const Object *ob)
{
- if (ob->data == NULL)
+ if (ob->data == NULL) {
return false;
+ }
+
+ switch (ob->type) {
+ case OB_MESH:
+ return ((Mesh *)ob->data)->edit_btmesh != NULL;
+ case OB_ARMATURE:
+ return ((bArmature *)ob->data)->edbo != NULL;
+ case OB_FONT:
+ return ((Curve *)ob->data)->editfont != NULL;
+ case OB_MBALL:
+ return ((MetaBall *)ob->data)->editelems != NULL;
+ case OB_LATTICE:
+ return ((Lattice *)ob->data)->editlatt != NULL;
+ case OB_SURF:
+ case OB_CURVE:
+ return ((Curve *)ob->data)->editnurb != NULL;
+ default:
+ return false;
+ }
+}
+
+bool BKE_object_is_in_editmode_vgroup(const Object *ob)
+{
+ return (OB_TYPE_SUPPORT_VGROUP(ob->type) &&
+ BKE_object_is_in_editmode(ob));
+}
+bool BKE_object_data_is_in_editmode(const ID *id)
+{
+ const short type = GS(id->name);
+ BLI_assert(OB_DATA_SUPPORT_EDITMODE(type));
+ switch (type) {
+ case ID_ME:
+ return ((const Mesh *)id)->edit_btmesh != NULL;
+ case ID_CU:
+ return (
+ (((const Curve *)id)->editnurb != NULL) ||
+ (((const Curve *)id)->editfont != NULL)
+ );
+ case ID_MB:
+ return ((const MetaBall *)id)->editelems != NULL;
+ case ID_LT:
+ return ((const Lattice *)id)->editlatt != NULL;
+ case ID_AR:
+ return ((const bArmature *)id)->edbo != NULL;
+ default:
+ BLI_assert(0);
+ return false;
+ }
+}
+
+bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
+{
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->edit_btmesh)
- return true;
+ return ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
+ (me->edit_btmesh == NULL) &&
+ (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX));
}
- else if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
- if (arm->edbo)
+ return false;
+}
+
+bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode)
+{
+ if (object_mode & OB_MODE_EDIT) {
+ if (BKE_object_is_in_editmode(ob)) {
return true;
+ }
}
- else if (ob->type == OB_FONT) {
- Curve *cu = ob->data;
-
- if (cu->editfont)
+ else if (object_mode & OB_MODE_VERTEX_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
return true;
+ }
}
- else if (ob->type == OB_MBALL) {
- MetaBall *mb = ob->data;
-
- if (mb->editelems)
+ else if (object_mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
return true;
+ }
}
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
-
- if (lt->editlatt)
+ else if (object_mode & OB_MODE_SCULPT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
return true;
+ }
}
- else if (ob->type == OB_SURF || ob->type == OB_CURVE) {
- Curve *cu = ob->data;
-
- if (cu->editnurb)
+ else if (object_mode & OB_MODE_POSE) {
+ if (ob->pose != NULL) {
return true;
+ }
}
return false;
}
-bool BKE_object_is_in_editmode_vgroup(const Object *ob)
+bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
{
- return (OB_TYPE_SUPPORT_VGROUP(ob->type) &&
- BKE_object_is_in_editmode(ob));
+ return ((ob->mode == object_mode) ||
+ (ob->mode & object_mode) != 0);
}
-bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
+/**
+ * Return if the object is visible, as evaluated by depsgraph
+ */
+bool BKE_object_is_visible(const Object *ob, const eObjectVisibilityCheck mode)
{
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- return ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
- (me->edit_btmesh == NULL) &&
- (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX));
+ if ((ob->base_flag & BASE_VISIBLE) == 0) {
+ return false;
}
- return false;
+ if (mode == OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) {
+ return true;
+ }
+
+ if (((ob->transflag & OB_DUPLI) == 0) &&
+ (ob->particlesystem.first == NULL))
+ {
+ return true;
+ }
+
+ switch (mode) {
+ case OB_VISIBILITY_CHECK_FOR_VIEWPORT:
+ return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT) != 0);
+ case OB_VISIBILITY_CHECK_FOR_RENDER:
+ return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0);
+ default:
+ BLI_assert(!"Object visible test mode not supported.");
+ return false;
+ }
}
bool BKE_object_exists_check(Main *bmain, const Object *obtest)
@@ -554,11 +765,12 @@ static const char *get_obdata_defname(int type)
case OB_FONT: return DATA_("Text");
case OB_MBALL: return DATA_("Mball");
case OB_CAMERA: return DATA_("Camera");
- case OB_LAMP: return DATA_("Lamp");
+ case OB_LAMP: return DATA_("Light");
case OB_LATTICE: return DATA_("Lattice");
case OB_ARMATURE: return DATA_("Armature");
case OB_SPEAKER: return DATA_("Speaker");
case OB_EMPTY: return DATA_("Empty");
+ case OB_GPENCIL: return DATA_("GPencil");
default:
printf("get_obdata_defname: Internal error, bad type: %d\n", type);
return DATA_("Empty");
@@ -582,6 +794,8 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
case OB_LATTICE: return BKE_lattice_add(bmain, name);
case OB_ARMATURE: return BKE_armature_add(bmain, name);
case OB_SPEAKER: return BKE_speaker_add(bmain, name);
+ case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name);
+ case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name);
case OB_EMPTY: return NULL;
default:
printf("%s: Internal error, bad type: %d\n", __func__, type);
@@ -619,6 +833,11 @@ void BKE_object_init(Object *ob)
ob->dt = OB_TEXTURE;
ob->empty_drawtype = OB_PLAINAXES;
ob->empty_drawsize = 1.0;
+ ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT;
+ ob->empty_image_visibility_flag = (
+ OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE |
+ OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC |
+ OB_EMPTY_IMAGE_VISIBLE_BACKSIDE);
if (ob->type == OB_EMPTY) {
copy_v2_fl(ob->ima_ofs, -0.5f);
}
@@ -636,26 +855,10 @@ void BKE_object_init(Object *ob)
ob->dupsta = 1; ob->dupend = 100;
ob->dupfacesca = 1.0;
- /* Game engine defaults*/
- ob->mass = ob->inertia = 1.0f;
- ob->formfactor = 0.4f;
- ob->damping = 0.04f;
- ob->rdamping = 0.1f;
- ob->anisotropicFriction[0] = 1.0f;
- ob->anisotropicFriction[1] = 1.0f;
- ob->anisotropicFriction[2] = 1.0f;
- ob->gameflag = OB_PROP | OB_COLLISION;
- ob->margin = 0.04f;
- ob->init_state = 1;
- ob->state = 1;
- ob->obstacleRad = 1.0f;
- ob->step_height = 0.15f;
- ob->jump_speed = 10.0f;
- ob->fall_speed = 55.0f;
- ob->max_jumps = 1;
ob->col_group = 0x01;
ob->col_mask = 0xffff;
ob->preview = NULL;
+ ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
/* NT fluid sim defaults */
ob->fluidsimSettings = NULL;
@@ -664,6 +867,8 @@ void BKE_object_init(Object *ob)
/* Animation Visualization defaults */
animviz_settings_init(&ob->avs);
+
+ ob->display.flag = OB_SHOW_SHADOW;
}
/* more general add: creates minimum required data, but without vertices etc. */
@@ -676,6 +881,9 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
+ /* We increase object user count when linking to Collections. */
+ id_us_min(&ob->id);
+
/* default object vars */
ob->type = type;
@@ -684,168 +892,112 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
return ob;
}
-/* general add: to scene, with layer from area and default name */
-/* creates minimum required data, but without vertices etc. */
-Object *BKE_object_add(
- Main *bmain, Scene *scene,
- int type, const char *name)
+
+static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
Object *ob;
- Base *base;
ob = BKE_object_add_only_object(bmain, type, name);
-
ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
+ BKE_view_layer_base_deselect_all(view_layer);
- ob->lay = scene->lay;
-
- base = BKE_scene_base_add(scene, ob);
- BKE_scene_base_deselect_all(scene);
- BKE_scene_base_select(scene, base);
- DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
return ob;
}
-
-#ifdef WITH_GAMEENGINE
-
-void BKE_object_lod_add(Object *ob)
-{
- LodLevel *lod = MEM_callocN(sizeof(LodLevel), "LoD Level");
- LodLevel *last = ob->lodlevels.last;
-
- /* If the lod list is empty, initialize it with the base lod level */
- if (!last) {
- LodLevel *base = MEM_callocN(sizeof(LodLevel), "Base LoD Level");
- BLI_addtail(&ob->lodlevels, base);
- base->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
- base->source = ob;
- base->obhysteresis = 10;
- last = ob->currentlod = base;
- }
-
- lod->distance = last->distance + 25.0f;
- lod->obhysteresis = 10;
- lod->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
-
- BLI_addtail(&ob->lodlevels, lod);
-}
-
-static int lod_cmp(const void *a, const void *b)
-{
- const LodLevel *loda = a;
- const LodLevel *lodb = b;
-
- if (loda->distance < lodb->distance) return -1;
- return loda->distance > lodb->distance;
-}
-
-void BKE_object_lod_sort(Object *ob)
-{
- BLI_listbase_sort(&ob->lodlevels, lod_cmp);
-}
-
-bool BKE_object_lod_remove(Object *ob, int level)
+/**
+ * General add: to scene, with layer from area and default name
+ *
+ * Object is added to the active Collection.
+ * If there is no linked collection to the active ViewLayer we create a new one.
+ */
+/* creates minimum required data, but without vertices etc. */
+Object *BKE_object_add(
+ Main *bmain, Scene *UNUSED(scene), ViewLayer *view_layer,
+ int type, const char *name)
{
- LodLevel *rem;
-
- if (level < 1 || level > BLI_listbase_count(&ob->lodlevels) - 1)
- return false;
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
- rem = BLI_findlink(&ob->lodlevels, level);
+ ob = object_add_common(bmain, view_layer, type, name);
- if (rem == ob->currentlod) {
- ob->currentlod = rem->prev;
- }
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
- BLI_remlink(&ob->lodlevels, rem);
- MEM_freeN(rem);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
- /* If there are no user defined lods, remove the base lod as well */
- if (BLI_listbase_is_single(&ob->lodlevels)) {
- LodLevel *base = ob->lodlevels.first;
- BLI_remlink(&ob->lodlevels, base);
- MEM_freeN(base);
- ob->currentlod = NULL;
- }
-
- return true;
+ return ob;
}
-static LodLevel *lod_level_select(Object *ob, const float camera_position[3])
+/**
+ * Add a new object, using another one as a reference
+ *
+ * \param ob_src object to use to determine the collections of the new object.
+ */
+Object *BKE_object_add_from(
+ Main *bmain, Scene *scene, ViewLayer *view_layer,
+ int type, const char *name, Object *ob_src)
{
- LodLevel *current = ob->currentlod;
- float dist_sq;
-
- if (!current) return NULL;
-
- dist_sq = len_squared_v3v3(ob->obmat[3], camera_position);
-
- if (dist_sq < SQUARE(current->distance)) {
- /* check for higher LoD */
- while (current->prev && dist_sq < SQUARE(current->distance)) {
- current = current->prev;
- }
- }
- else {
- /* check for lower LoD */
- while (current->next && dist_sq > SQUARE(current->next->distance)) {
- current = current->next;
- }
- }
-
- return current;
-}
+ Object *ob;
+ Base *base;
-bool BKE_object_lod_is_usable(Object *ob, Scene *scene)
-{
- bool active = (scene) ? ob == OBACT : false;
- return (ob->mode == OB_MODE_OBJECT || !active);
-}
+ ob = object_add_common(bmain, view_layer, type, name);
+ BKE_collection_object_add_from(bmain, scene, ob_src, ob);
-void BKE_object_lod_update(Object *ob, const float camera_position[3])
-{
- LodLevel *cur_level = ob->currentlod;
- LodLevel *new_level = lod_level_select(ob, camera_position);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
- if (new_level != cur_level) {
- ob->currentlod = new_level;
- }
+ return ob;
}
-static Object *lod_ob_get(Object *ob, Scene *scene, int flag)
+/**
+ * Add a new object, but assign the given datablock as the ob->data
+ * for the newly created object.
+ *
+ * \param data The datablock to assign as ob->data for the new object.
+ * This is assumed to be of the correct type.
+ * \param do_id_user If true, id_us_plus() will be called on data when
+ * assigning it to the object.
+ */
+Object *BKE_object_add_for_data(
+ Main *bmain, ViewLayer *view_layer,
+ int type, const char *name, ID *data, bool do_id_user)
{
- LodLevel *current = ob->currentlod;
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
- if (!current || !BKE_object_lod_is_usable(ob, scene))
- return ob;
+ /* same as object_add_common, except we don't create new ob->data */
+ ob = BKE_object_add_only_object(bmain, type, name);
+ ob->data = data;
+ if (do_id_user) id_us_plus(data);
- while (current->prev && (!(current->flags & flag) || !current->source || current->source->type != OB_MESH)) {
- current = current->prev;
- }
+ BKE_view_layer_base_deselect_all(view_layer);
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- return current->source;
-}
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
-struct Object *BKE_object_lod_meshob_get(Object *ob, Scene *scene)
-{
- return lod_ob_get(ob, scene, OB_LOD_USE_MESH);
-}
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
-struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
-{
- return lod_ob_get(ob, scene, OB_LOD_USE_MAT);
+ return ob;
}
-#endif /* WITH_GAMEENGINE */
-
-SoftBody *copy_softbody(const SoftBody *sb, const int flag)
+void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
{
+ SoftBody *sb = ob_src->soft;
SoftBody *sbn;
+ bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN;
- if (sb == NULL) return(NULL);
+ ob_dst->softflag = ob_src->softflag;
+ if (sb == NULL) {
+ ob_dst->soft = NULL;
+ return;
+ }
sbn = MEM_dupallocN(sb);
@@ -878,64 +1030,27 @@ SoftBody *copy_softbody(const SoftBody *sb, const int flag)
sbn->scratch = NULL;
- sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, flag);
+ if (tagged_no_main == 0) {
+ sbn->shared = MEM_dupallocN(sb->shared);
+ sbn->shared->pointcache = BKE_ptcache_copy_list(&sbn->shared->ptcaches, &sb->shared->ptcaches, flag);
+ }
if (sb->effector_weights)
sbn->effector_weights = MEM_dupallocN(sb->effector_weights);
- return sbn;
-}
-
-BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb, const int UNUSED(flag))
-{
- BulletSoftBody *bsbn;
-
- if (bsb == NULL)
- return NULL;
- bsbn = MEM_dupallocN(bsb);
- /* no pointer in this structure yet */
- return bsbn;
+ ob_dst->soft = sbn;
}
ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag)
{
- ParticleSystem *psysn;
- ParticleData *pa;
- int p;
-
- psysn = MEM_dupallocN(psys);
- psysn->particles = MEM_dupallocN(psys->particles);
- psysn->child = MEM_dupallocN(psys->child);
+ ParticleSystem *psysn = MEM_dupallocN(psys);
- if (psys->part->type == PART_HAIR) {
- for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++)
- pa->hair = MEM_dupallocN(pa->hair);
- }
-
- if (psysn->particles && (psysn->particles->keys || psysn->particles->boid)) {
- ParticleKey *key = psysn->particles->keys;
- BoidParticle *boid = psysn->particles->boid;
-
- if (key)
- key = MEM_dupallocN(key);
-
- if (boid)
- boid = MEM_dupallocN(boid);
-
- for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++) {
- if (boid)
- pa->boid = boid++;
- if (key) {
- pa->keys = key;
- key += pa->totkey;
- }
- }
- }
+ psys_copy_particles(psysn, psys);
if (psys->clmd) {
psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
- psys->hair_in_dm = psys->hair_out_dm = NULL;
+ psys->hair_in_mesh = psys->hair_out_mesh = NULL;
}
BLI_duplicatelist(&psysn->targets, &psys->targets);
@@ -947,13 +1062,19 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
psysn->effectors = NULL;
psysn->tree = NULL;
psysn->bvhtree = NULL;
+ psysn->batch_cache = NULL;
BLI_listbase_clear(&psysn->pathcachebufs);
BLI_listbase_clear(&psysn->childcachebufs);
- psysn->renderdata = NULL;
- /* XXX Never copy caches here? */
- psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES);
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0);
+ psysn->flag |= PSYS_SHARED_CACHES;
+ BLI_assert(psysn->pointcache != NULL);
+ }
+ else {
+ psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag);
+ }
/* XXX - from reading existing code this seems correct but intended usage of
* pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
@@ -1013,14 +1134,6 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const
}
}
-void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src)
-{
- if (ob_src->soft) {
- ob_dst->softflag = ob_src->softflag;
- ob_dst->soft = copy_softbody(ob_src->soft, 0);
- }
-}
-
static void copy_object_pose(Object *obn, const Object *ob, const int flag)
{
bPoseChannel *chan;
@@ -1087,12 +1200,103 @@ Object *BKE_object_pose_armature_get(Object *ob)
ob = modifiers_isDeformedByArmature(ob);
+ /* Only use selected check when non-active. */
if (BKE_object_pose_context_check(ob))
return ob;
return NULL;
}
+Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer, View3D *v3d)
+{
+ Object *ob_armature = BKE_object_pose_armature_get(ob);
+ if (ob_armature) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob_armature);
+ if (base) {
+ if (BASE_VISIBLE(v3d, base)) {
+ return ob_armature;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Access pose array with special check to get pose object when in weight paint mode.
+ */
+Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer, View3D *v3d, uint *r_objects_len, bool unique)
+{
+ Object *ob_active = OBACT(view_layer);
+ Object *ob_pose = BKE_object_pose_armature_get(ob_active);
+ Object **objects = NULL;
+ if (ob_pose == ob_active) {
+ objects = BKE_view_layer_array_from_objects_in_mode(
+ view_layer, v3d, r_objects_len, {
+ .object_mode = OB_MODE_POSE,
+ .no_dup_data = unique});
+ }
+ else if (ob_pose != NULL) {
+ *r_objects_len = 1;
+ objects = MEM_mallocN(sizeof(*objects), __func__);
+ objects[0] = ob_pose;
+ }
+ else {
+ *r_objects_len = 0;
+ objects = MEM_mallocN(0, __func__);
+ }
+ return objects;
+}
+Object **BKE_object_pose_array_get_unique(ViewLayer *view_layer, View3D *v3d, uint *r_objects_len)
+{
+ return BKE_object_pose_array_get_ex(view_layer, v3d, r_objects_len, true);
+}
+Object **BKE_object_pose_array_get(ViewLayer *view_layer, View3D *v3d, uint *r_objects_len)
+{
+ return BKE_object_pose_array_get_ex(view_layer, v3d, r_objects_len, false);
+}
+
+Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer, View3D *v3d, uint *r_bases_len, bool unique)
+{
+ Base *base_active = BASACT(view_layer);
+ Object *ob_pose = base_active ? BKE_object_pose_armature_get(base_active->object) : NULL;
+ Base *base_pose = NULL;
+ Base **bases = NULL;
+
+ if (base_active) {
+ if (ob_pose == base_active->object) {
+ base_pose = base_active;
+ }
+ else {
+ base_pose = BKE_view_layer_base_find(view_layer, ob_pose);
+ }
+ }
+
+ if (base_active && (base_pose == base_active)) {
+ bases = BKE_view_layer_array_from_bases_in_mode(
+ view_layer, v3d, r_bases_len, {
+ .object_mode = OB_MODE_POSE,
+ .no_dup_data = unique});
+ }
+ else if (base_pose != NULL) {
+ *r_bases_len = 1;
+ bases = MEM_mallocN(sizeof(*bases), __func__);
+ bases[0] = base_pose;
+ }
+ else {
+ *r_bases_len = 0;
+ bases = MEM_mallocN(0, __func__);
+ }
+ return bases;
+}
+Base **BKE_object_pose_base_array_get_unique(ViewLayer *view_layer, View3D *v3d, uint *r_bases_len)
+{
+ return BKE_object_pose_base_array_get_ex(view_layer, v3d, r_bases_len, true);
+}
+Base **BKE_object_pose_base_array_get(ViewLayer *view_layer, View3D *v3d, uint *r_bases_len)
+{
+ return BKE_object_pose_base_array_get_ex(view_layer, v3d, r_bases_len, false);
+}
+
void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
{
copy_v3_v3(ob_tar->loc, ob_src->loc);
@@ -1112,9 +1316,14 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
*
* \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_src, const int flag)
+void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag)
{
ModifierData *md;
+ GpencilModifierData *gmd;
+ ShaderFxData *fx;
+
+ /* Do not copy runtime data. */
+ BKE_object_runtime_reset(ob_dst);
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
@@ -1134,7 +1343,6 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser);
if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb);
- ob_dst->flag &= ~OB_FROMGROUP;
BLI_listbase_clear(&ob_dst->modifiers);
@@ -1145,21 +1353,37 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
BLI_addtail(&ob_dst->modifiers, nmd);
}
- BLI_listbase_clear(&ob_dst->prop);
- BKE_bproperty_copy_list(&ob_dst->prop, &ob_src->prop);
+ BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
+
+ for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
+ GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
+ BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
+ BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
+ BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
+ }
+
+ BLI_listbase_clear(&ob_dst->shader_fx);
- BKE_sca_logic_copy(ob_dst, ob_src, flag_subdata);
+ for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
+ ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
+ BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
+ BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
+ BLI_addtail(&ob_dst->shader_fx, nfx);
+ }
if (ob_src->pose) {
copy_object_pose(ob_dst, ob_src, flag_subdata);
/* backwards compat... non-armatures can get poses in older files? */
- if (ob_src->type == OB_ARMATURE)
- BKE_pose_rebuild(ob_dst, ob_dst->data);
+ if (ob_src->type == OB_ARMATURE) {
+ const bool do_pose_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+ BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user);
+ }
}
defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase);
+ BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps);
BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
- ob_dst->mode = OB_MODE_OBJECT;
+ ob_dst->mode = ob_dst->type != OB_GPENCIL ? OB_MODE_OBJECT : ob_dst->mode;
ob_dst->sculpt = NULL;
if (ob_src->pd) {
@@ -1168,8 +1392,7 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng);
}
}
- ob_dst->soft = copy_softbody(ob_src->soft, flag_subdata);
- ob_dst->bsoft = copy_bulletsoftbody(ob_src->bsoft, flag_subdata);
+ BKE_object_copy_softbody(ob_dst, ob_src, flag_subdata);
ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata);
ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata);
@@ -1178,16 +1401,14 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
ob_dst->derivedDeform = NULL;
ob_dst->derivedFinal = NULL;
- BLI_listbase_clear(&ob_dst->gpulamp);
+ BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
- ob_dst->mpath = NULL;
+ ob_dst->avs = ob_src->avs;
+ ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
copy_object_lod(ob_dst, ob_src, flag_subdata);
- /* Do not copy runtime curve data. */
- ob_dst->curve_cache = NULL;
-
/* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id);
@@ -1202,6 +1423,10 @@ Object *BKE_object_copy(Main *bmain, const Object *ob)
{
Object *ob_copy;
BKE_id_copy_ex(bmain, &ob->id, (ID **)&ob_copy, 0, false);
+
+ /* We increase object user count when linking to Collections. */
+ id_us_min(&ob_copy->id);
+
return ob_copy;
}
@@ -1325,9 +1550,9 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* proxy rule: lib_object->proxy_from == the one we borrow from, set temporally while object_update */
/* local_object->proxy == pointer to library object, saved in files and read */
-/* local_object->proxy_group == pointer to group dupli-object, saved in files and read */
+/* local_object->proxy_group == pointer to collection dupli-object, saved in files and read */
-void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
+void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
{
/* paranoia checks */
if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) {
@@ -1336,24 +1561,24 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
}
ob->proxy = target;
- ob->proxy_group = gob;
+ ob->proxy_group = cob;
id_lib_extern(&target->id);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- DAG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* copy transform
- * - gob means this proxy comes from a group, just apply the matrix
+ * - cob means this proxy comes from a collection, just apply the matrix
* so the object wont move from its dupli-transform.
*
- * - no gob means this is being made from a linked object,
+ * - no cob means this is being made from a linked object,
* this is closer to making a copy of the object - in-place. */
- if (gob) {
+ if (cob) {
ob->rotmode = target->rotmode;
- mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat);
- if (gob->dup_group) { /* should always be true */
+ mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat);
+ if (cob->dup_group) { /* should always be true */
float tvec[3];
- mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs);
+ mul_v3_mat3_m4v3(tvec, ob->obmat, cob->dup_group->dupli_ofs);
sub_v3_v3(ob->obmat[3], tvec);
}
BKE_object_apply_mat4(ob, ob->obmat, false, true);
@@ -1402,7 +1627,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
if (target->type == OB_ARMATURE) {
copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
BKE_pose_rest(ob->pose); /* clear all transforms in channels */
- BKE_pose_rebuild(ob, ob->data); /* set all internal links */
+ BKE_pose_rebuild(bmain, ob, ob->data, true); /* set all internal links */
armature_set_id_extern(ob);
}
@@ -1438,6 +1663,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
ob->empty_drawsize *= size;
break;
}
+ case OB_GPENCIL:
+ {
+ ob->empty_drawsize *= size;
+ break;
+ }
case OB_FONT:
{
Curve *cu = ob->data;
@@ -1662,7 +1892,7 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
if (ob->parent) {
float par_imat[4][4];
- BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat);
+ BKE_object_get_parent_matrix(NULL, NULL, ob, ob->parent, par_imat);
invert_m4(par_imat);
mul_m4_m4m4(mat, par_imat, ob->obmat);
}
@@ -1675,23 +1905,31 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
int enable_cu_speed = 1;
/**
- * \param scene: Used when curve cache needs to be calculated, or for dupli-frame time.
+ * \param depsgraph: Used for dupli-frame time.
* \return success if \a mat is set.
*/
-static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
+static bool ob_parcurve(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, Object *par, float mat[4][4])
{
Curve *cu = par->data;
float vec[4], dir[3], quat[4], radius, ctime;
+ /* TODO: Make sure this doesn't crash. */
+#if 0
/* only happens on reload file, but violates depsgraph still... fix! */
if (par->curve_cache == NULL) {
if (scene == NULL) {
return false;
}
- BKE_displist_make_curveTypes(scene, par, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, par, 0);
+ }
+#else
+ /* See: T56619 */
+ if (par->runtime.curve_cache == NULL) {
+ return false;
}
+#endif
- if (par->curve_cache->path == NULL) {
+ if (par->runtime.curve_cache->path == NULL) {
return false;
}
@@ -1714,11 +1952,11 @@ static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
}
else {
/* For dupli-frames only */
- if (scene == NULL) {
+ if (depsgraph == NULL) {
return false;
}
- ctime = BKE_scene_frame_get(scene);
+ ctime = DEG_get_ctime(depsgraph);
if (cu->pathlen) {
ctime /= cu->pathlen;
}
@@ -1732,21 +1970,7 @@ static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
if (cu->flag & CU_FOLLOW) {
-#if 0
- float si, q[4];
- vec_to_quat(quat, dir, ob->trackflag, ob->upflag);
-
- /* the tilt */
- normalize_v3(dir);
- q[0] = cosf(0.5 * vec[3]);
- si = sinf(0.5 * vec[3]);
- q[1] = -si * dir[0];
- q[2] = -si * dir[1];
- q[3] = -si * dir[2];
- mul_qt_qtqt(quat, q, quat);
-#else
quat_apply_track(quat, ob->trackflag, ob->upflag);
-#endif
normalize_qt(quat);
quat_to_mat4(mat, quat);
}
@@ -1806,84 +2030,43 @@ static void give_parvert(Object *par, int nr, float vec[3])
if (par->type == OB_MESH) {
Mesh *me = par->data;
BMEditMesh *em = me->edit_btmesh;
- DerivedMesh *dm;
-
- dm = (em) ? em->derivedFinal : par->derivedFinal;
+ Mesh *me_eval = (em) ? em->mesh_eval_final : par->runtime.mesh_eval;
- if (dm) {
+ if (me_eval) {
int count = 0;
- int numVerts = dm->getNumVerts(dm);
+ const int numVerts = me_eval->totvert;
if (nr < numVerts) {
- bool use_special_ss_case = false;
-
- if (dm->type == DM_TYPE_CCGDM) {
- ModifierData *md;
- VirtualModifierData virtualModifierData;
- use_special_ss_case = true;
- for (md = modifiers_getVirtualModifierList(par, &virtualModifierData);
- md != NULL;
- md = md->next)
- {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- /* TODO(sergey): Check for disabled modifiers. */
- if (mti->type != eModifierTypeType_OnlyDeform && md->next != NULL) {
- use_special_ss_case = false;
- break;
- }
- }
- }
-
- if (!use_special_ss_case) {
- /* avoid dm->getVertDataArray() since it allocates arrays in the dm (not thread safe) */
- if (em && dm->type == DM_TYPE_EDITBMESH) {
- if (em->bm->elem_table_dirty & BM_VERT) {
+ if (em && me_eval->runtime.is_original) {
+ if (em->bm->elem_table_dirty & BM_VERT) {
#ifdef VPARENT_THREADING_HACK
- BLI_mutex_lock(&vparent_lock);
- if (em->bm->elem_table_dirty & BM_VERT) {
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
- }
- BLI_mutex_unlock(&vparent_lock);
-#else
- BLI_assert(!"Not safe for threading");
+ BLI_mutex_lock(&vparent_lock);
+ if (em->bm->elem_table_dirty & BM_VERT) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
-#endif
}
+ BLI_mutex_unlock(&vparent_lock);
+#else
+ BLI_assert(!"Not safe for threading");
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+#endif
}
}
- if (use_special_ss_case) {
- /* Special case if the last modifier is SS and no constructive modifier are in front of it. */
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ccgdm->ss, POINTER_FROM_INT(nr));
- /* In case we deleted some verts, nr may refer to inexistent one now, see T42557. */
- if (ccg_vert) {
- float *co = ccgSubSurf_getVertData(ccgdm->ss, ccg_vert);
- add_v3_v3(vec, co);
- count++;
- }
- }
- else if (CustomData_has_layer(&dm->vertData, CD_ORIGINDEX) &&
- !(em && dm->type == DM_TYPE_EDITBMESH))
+ if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) &&
+ !(em && me_eval->runtime.is_original))
{
- int i;
-
+ const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
/* Get the average of all verts with (original index == nr). */
- for (i = 0; i < numVerts; i++) {
- const int *index = dm->getVertData(dm, i, CD_ORIGINDEX);
- if (*index == nr) {
- float co[3];
- dm->getVertCo(dm, i, co);
- add_v3_v3(vec, co);
+ for (int i = 0; i < numVerts; i++) {
+ if (index[i] == nr) {
+ add_v3_v3(vec, me_eval->mvert[i].co);
count++;
}
}
}
else {
if (nr < numVerts) {
- float co[3];
- dm->getVertCo(dm, nr, co);
- add_v3_v3(vec, co);
+ add_v3_v3(vec, me_eval->mvert[nr].co);
count++;
}
}
@@ -1897,12 +2080,14 @@ static void give_parvert(Object *par, int nr, float vec[3])
}
else {
/* use first index if its out of range */
- dm->getVertCo(dm, 0, vec);
+ if (me_eval->totvert) {
+ copy_v3_v3(vec, me_eval->mvert[0].co);
+ }
}
}
else {
fprintf(stderr,
- "%s: DerivedMesh is needed to solve parenting, "
+ "%s: Evaluated mesh is needed to solve parenting, "
"object position can be wrong now\n", __func__);
}
}
@@ -1910,10 +2095,10 @@ static void give_parvert(Object *par, int nr, float vec[3])
ListBase *nurb;
/* Unless there's some weird depsgraph failure the cache should exist. */
- BLI_assert(par->curve_cache != NULL);
+ BLI_assert(par->runtime.curve_cache != NULL);
- if (par->curve_cache->deformed_nurbs.first != NULL) {
- nurb = &par->curve_cache->deformed_nurbs;
+ if (par->runtime.curve_cache->deformed_nurbs.first != NULL) {
+ nurb = &par->runtime.curve_cache->deformed_nurbs;
}
else {
Curve *cu = par->data;
@@ -1924,7 +2109,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
}
else if (par->type == OB_LATTICE) {
Lattice *latt = par->data;
- DispList *dl = par->curve_cache ? BKE_displist_find(&par->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = par->runtime.curve_cache ? BKE_displist_find(&par->runtime.curve_cache->disp, DL_VERTS) : NULL;
float (*co)[3] = dl ? (float (*)[3])dl->verts : NULL;
int tot;
@@ -1969,7 +2154,7 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4])
}
-void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
+void BKE_object_get_parent_matrix(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, float parentmat[4][4])
{
float tmat[4][4];
float vec[3];
@@ -1980,7 +2165,7 @@ void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float p
ok = 0;
if (par->type == OB_CURVE) {
if ((((Curve *)par->data)->flag & CU_PATH) &&
- (ob_parcurve(scene, ob, par, tmat)))
+ (ob_parcurve(depsgraph, scene, ob, par, tmat)))
{
ok = 1;
}
@@ -2016,7 +2201,8 @@ void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float p
/**
* \param r_originmat Optional matrix that stores the space the object is in (without its own matrix applied)
*/
-static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4],
+static void solve_parenting(Depsgraph *depsgraph,
+ Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4],
float r_originmat[3][3], const bool set_origin)
{
float totmat[4][4];
@@ -2027,7 +2213,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4
if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat);
- BKE_object_get_parent_matrix(scene, ob, par, totmat);
+ BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -2070,20 +2256,21 @@ static bool where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat
}
/* note, scene is the active scene while actual_scene is the scene the object resides in */
-void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
- RigidBodyWorld *rbw, float r_originmat[3][3])
+void BKE_object_where_is_calc_time_ex(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime,
+ RigidBodyWorld *rbw, float r_originmat[3][3])
{
if (ob == NULL) return;
/* execute drivers only, as animation has already been done */
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS);
if (ob->parent) {
Object *par = ob->parent;
float slowmat[4][4];
/* calculate parent matrix */
- solve_parenting(scene, ob, par, ob->obmat, slowmat, r_originmat, true);
+ solve_parenting(depsgraph, scene, ob, par, ob->obmat, slowmat, r_originmat, true);
/* "slow parent" is definitely not threadsafe, and may also give bad results jumping around
* An old-fashioned hack which probably doesn't really cut it anymore
@@ -2105,8 +2292,8 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
/* solve constraints */
if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) {
bConstraintOb *cob;
- cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
- BKE_constraints_solve(&ob->constraints, cob, ctime);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
BKE_constraints_clear_evalob(cob);
}
@@ -2115,16 +2302,16 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
else ob->transflag &= ~OB_NEG_SCALE;
}
-void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime)
+void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime)
{
- BKE_object_where_is_calc_time_ex(scene, ob, ctime, NULL, NULL);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, ctime, NULL, NULL);
}
/* get object transformation matrix without recalculating dependencies and
* constraints -- assume dependencies are already solved by depsgraph.
* no changes to object and it's parent would be done.
* used for bundles orientation in 3d space relative to parented blender camera */
-void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
+void BKE_object_where_is_calc_mat4(Depsgraph *depsgraph, Scene *scene, Object *ob, float obmat[4][4])
{
if (ob->parent) {
@@ -2132,7 +2319,7 @@ void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
Object *par = ob->parent;
- solve_parenting(scene, ob, par, obmat, slowmat, NULL, false);
+ solve_parenting(depsgraph, scene, ob, par, obmat, slowmat, NULL, false);
if (ob->partype & PARSLOW)
where_is_object_parslow(ob, obmat, slowmat);
@@ -2142,52 +2329,69 @@ void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
}
}
-void BKE_object_where_is_calc_ex(Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
+void BKE_object_where_is_calc_ex(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
{
- BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), rbw, r_originmat);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), rbw, r_originmat);
}
-void BKE_object_where_is_calc(Scene *scene, Object *ob)
+void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), NULL, NULL);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), NULL, NULL);
}
-/* for calculation of the inverse parent transform, only used for editor */
-void BKE_object_workob_calc_parent(Scene *scene, Object *ob, Object *workob)
+/**
+ * For calculation of the inverse parent transform, only used for editor.
+ *
+ * It assumes the object parent is already in the depsgraph.
+ * Otherwise, after changing ob->parent you need to call:
+ * - #DEG_relations_tag_update(bmain);
+ * - #BKE_scene_graph_update_tagged(depsgraph, bmain);
+ */
+void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob)
{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
BKE_object_workob_clear(workob);
unit_m4(workob->obmat);
unit_m4(workob->parentinv);
unit_m4(workob->constinv);
- workob->parent = ob->parent;
- workob->trackflag = ob->trackflag;
- workob->upflag = ob->upflag;
+ /* Since this is used while calculating parenting, at this moment ob_eval->parent is still NULL. */
+ workob->parent = DEG_get_evaluated_object(depsgraph, ob->parent);
- workob->partype = ob->partype;
- workob->par1 = ob->par1;
- workob->par2 = ob->par2;
- workob->par3 = ob->par3;
+ workob->trackflag = ob_eval->trackflag;
+ workob->upflag = ob_eval->upflag;
- workob->constraints.first = ob->constraints.first;
- workob->constraints.last = ob->constraints.last;
+ workob->partype = ob_eval->partype;
+ workob->par1 = ob_eval->par1;
+ workob->par2 = ob_eval->par2;
+ workob->par3 = ob_eval->par3;
- BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
+ workob->constraints = ob_eval->constraints;
- BKE_object_where_is_calc(scene, workob);
+ BLI_strncpy(workob->parsubstr, ob_eval->parsubstr, sizeof(workob->parsubstr));
+
+ BKE_object_where_is_calc(depsgraph, scene, workob);
}
-/* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
-void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent)
+/**
+ * Applies the global transformation \a mat to the \a ob using a relative parent space if supplied.
+ *
+ * \param mat the global transformation mat that the object should be set object to.
+ * \param parent the parent space in which this object will be set relative to (should probably always be parent_eval).
+ * \param use_compat true to ensure that rotations are set using the min difference between the old and new orientation.
+ */
+void BKE_object_apply_mat4_ex(Object *ob, float mat[4][4], Object *parent, float parentinv[4][4], const bool use_compat)
{
+ /* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
+
float rot[3][3];
- if (use_parent && ob->parent) {
+ if (parent != NULL) {
float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
- BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
+ BKE_object_get_parent_matrix(NULL, NULL, ob, parent, parent_mat);
- mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv);
+ mul_m4_m4m4(diff_mat, parent_mat, parentinv);
invert_m4_m4(imat, diff_mat);
mul_m4_m4m4(rmat, imat, mat); /* get the parent relative matrix */
@@ -2209,10 +2413,16 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c
/* BKE_object_mat3_to_rot handles delta rotations */
}
+/* XXX: should be removed after COW operators port to use BKE_object_apply_mat4_ex directly */
+void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent)
+{
+ BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat);
+}
+
BoundBox *BKE_boundbox_alloc_unit(void)
{
BoundBox *bb;
- const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {-1.0f, -1.0f, -1.0f};
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
BKE_boundbox_init_from_minmax(bb, min, max);
@@ -2260,20 +2470,29 @@ BoundBox *BKE_object_boundbox_get(Object *ob)
{
BoundBox *bb = NULL;
- if (ob->type == OB_MESH) {
- bb = BKE_mesh_boundbox_get(ob);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
- bb = BKE_curve_boundbox_get(ob);
- }
- else if (ob->type == OB_MBALL) {
- bb = ob->bb;
- }
- else if (ob->type == OB_LATTICE) {
- bb = BKE_lattice_boundbox_get(ob);
- }
- else if (ob->type == OB_ARMATURE) {
- bb = BKE_armature_boundbox_get(ob);
+ switch (ob->type) {
+ case OB_MESH:
+ bb = BKE_mesh_boundbox_get(ob);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ bb = BKE_curve_boundbox_get(ob);
+ break;
+ case OB_MBALL:
+ bb = BKE_mball_boundbox_get(ob);
+ break;
+ case OB_LATTICE:
+ bb = BKE_lattice_boundbox_get(ob);
+ break;
+ case OB_ARMATURE:
+ bb = BKE_armature_boundbox_get(ob);
+ break;
+ case OB_GPENCIL:
+ bb = BKE_gpencil_boundbox_get(ob);
+ break;
+ default:
+ break;
}
return bb;
}
@@ -2288,6 +2507,23 @@ void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
}
}
+void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
+{
+ float min[3], max[3];
+
+ INIT_MINMAX(min, max);
+
+ BKE_mesh_minmax(me_eval, min, max);
+
+ if (ob->bb == NULL) {
+ ob->bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
+ }
+
+ BKE_boundbox_init_from_minmax(ob->bb, min, max);
+
+ ob->bb->flag &= ~BOUNDBOX_DIRTY;
+}
+
void BKE_object_dimensions_get(Object *ob, float vec[3])
{
BoundBox *bb = NULL;
@@ -2393,7 +2629,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us
float size[3];
copy_v3_v3(size, ob->size);
- if (ob->type == OB_EMPTY) {
+ if ((ob->type == OB_EMPTY) || (ob->type == OB_GPENCIL)) {
mul_v3_fl(size, ob->empty_drawsize);
}
@@ -2417,9 +2653,9 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
if (!ob->iuser) {
ob->iuser = MEM_callocN(sizeof(ImageUser), "image user");
ob->iuser->ok = 1;
+ ob->iuser->flag |= IMA_ANIM_ALWAYS;
ob->iuser->frames = 100;
ob->iuser->sfra = 1;
- ob->iuser->fie_ima = 2;
}
}
else {
@@ -2430,9 +2666,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
}
}
-bool BKE_object_minmax_dupli(
- Main *bmain, Scene *scene,
- Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
+bool BKE_object_minmax_dupli(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
{
bool ok = false;
if ((ob->transflag & OB_DUPLI) == 0) {
@@ -2441,7 +2675,7 @@ bool BKE_object_minmax_dupli(
else {
ListBase *lb;
DupliObject *dob;
- lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob);
+ lb = object_duplilist(depsgraph, scene, ob);
for (dob = lb->first; dob; dob = dob->next) {
if ((use_hidden == false) && (dob->no_draw != 0)) {
/* pass */
@@ -2473,21 +2707,19 @@ void BKE_object_foreach_display_point(
{
float co[3];
- if (ob->derivedFinal) {
- DerivedMesh *dm = ob->derivedFinal;
- MVert *mv = dm->getVertArray(dm);
- int totvert = dm->getNumVerts(dm);
- int i;
-
- for (i = 0; i < totvert; i++, mv++) {
+ if (ob->runtime.mesh_eval) {
+ const Mesh *me = ob->runtime.mesh_eval;
+ const MVert *mv = me->mvert;
+ const int totvert = me->totvert;
+ for (int i = 0; i < totvert; i++, mv++) {
mul_v3_m4v3(co, obmat, mv->co);
func_cb(co, user_data);
}
}
- else if (ob->curve_cache && ob->curve_cache->disp.first) {
+ else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
DispList *dl;
- for (dl = ob->curve_cache->disp.first; dl; dl = dl->next) {
+ for (dl = ob->runtime.curve_cache->disp.first; dl; dl = dl->next) {
const float *v3 = dl->verts;
int totvert = dl->nr;
int i;
@@ -2501,33 +2733,20 @@ void BKE_object_foreach_display_point(
}
void BKE_scene_foreach_display_point(
- Main *bmain, Scene *scene, View3D *v3d, const short flag,
+ Depsgraph *depsgraph,
void (*func_cb)(const float[3], void *), void *user_data)
{
- Base *base;
- Object *ob;
-
- for (base = FIRSTBASE; base; base = base->next) {
- if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag & flag) == flag) {
- ob = base->object;
-
- if ((ob->transflag & OB_DUPLI) == 0) {
- BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
- }
- else {
- ListBase *lb;
- DupliObject *dob;
-
- lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob);
- for (dob = lb->first; dob; dob = dob->next) {
- if (dob->no_draw == 0) {
- BKE_object_foreach_display_point(dob->ob, dob->mat, func_cb, user_data);
- }
- }
- free_object_duplilist(lb); /* does restore */
- }
+ DEG_OBJECT_ITER_BEGIN(
+ depsgraph, ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+ {
+ if ((ob->base_flag & BASE_SELECTED) != 0) {
+ BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
}
}
+ DEG_OBJECT_ITER_END;
}
/* copied from DNA_object_types.h */
@@ -2541,7 +2760,7 @@ typedef struct ObTfmBack {
float obmat[4][4]; /* final worldspace matrix with constraints & animsys applied */
float parentinv[4][4]; /* inverse result of parent, so that object doesn't 'stick' to parent */
float constinv[4][4]; /* inverse result of constraints. doesn't include effect of parent or object local transform */
- float imat[4][4]; /* inverse matrix of 'obmat' for during render, old game engine, temporally: ipokeys of transform */
+ float imat[4][4]; /* inverse matrix of 'obmat' for during render, temporally: ipokeys of transform */
} ObTfmBack;
void *BKE_object_tfm_backup(Object *ob)
@@ -2598,25 +2817,24 @@ bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
return BKE_object_parent_loop_check(par->parent, ob);
}
-static void object_handle_update_proxy(Main *bmain,
- EvaluationContext *eval_ctx,
+static void object_handle_update_proxy(Depsgraph *depsgraph,
Scene *scene,
Object *object,
const bool do_proxy_update)
{
- /* The case when this is a group proxy, object_update is called in group.c */
+ /* The case when this is a collection proxy, object_update is called in collection.c */
if (object->proxy == NULL) {
return;
}
/* set pointer in library proxy target, for copying, but restore it */
object->proxy->proxy_from = object;
- // printf("set proxy pointer for later group stuff %s\n", ob->id.name);
+ // printf("set proxy pointer for later collection stuff %s\n", ob->id.name);
/* the no-group proxy case, we call update */
if (object->proxy_group == NULL) {
if (do_proxy_update) {
// printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
- BKE_object_handle_update(bmain, eval_ctx, scene, object->proxy);
+ BKE_object_handle_update(depsgraph, scene, object->proxy);
}
}
}
@@ -2629,14 +2847,18 @@ static void object_handle_update_proxy(Main *bmain,
/* the main object update call, for object matrix, constraints, keys and displist (modifiers) */
/* requires flags to be set! */
/* Ideally we shouldn't have to pass the rigid body world, but need bigger restructuring to avoid id */
-void BKE_object_handle_update_ex(Main *bmain,
- EvaluationContext *eval_ctx,
+void BKE_object_handle_update_ex(Depsgraph *depsgraph,
Scene *scene, Object *ob,
RigidBodyWorld *rbw,
const bool do_proxy_update)
{
- if ((ob->recalc & OB_RECALC_ALL) == 0) {
- object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update);
+ const ID *object_data = ob->data;
+ const bool recalc_object = (ob->id.recalc & ID_RECALC) != 0;
+ const bool recalc_data =
+ (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0)
+ : 0;
+ if (!recalc_object && ! recalc_data) {
+ object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
return;
}
/* Speed optimization for animation lookups. */
@@ -2646,46 +2868,48 @@ void BKE_object_handle_update_ex(Main *bmain,
BKE_pose_update_constraint_flags(ob->pose);
}
}
- if (ob->recalc & OB_RECALC_DATA) {
+ if (recalc_data) {
if (ob->type == OB_ARMATURE) {
/* this happens for reading old files and to match library armatures
* with poses we do it ahead of BKE_object_where_is_calc to ensure animation
* is evaluated on the rebuilt pose, otherwise we get incorrect poses
* on file load */
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC))
- BKE_pose_rebuild(ob, ob->data);
+ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+ /* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */
+ BKE_pose_rebuild(NULL, ob, ob->data, true);
+ }
}
}
/* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers,
* which is only in BKE_object_where_is_calc now */
/* XXX: should this case be OB_RECALC_OB instead? */
- if (ob->recalc & OB_RECALC_ALL) {
+ if (recalc_object || recalc_data) {
if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
printf("recalcob %s\n", ob->id.name + 2);
}
/* Handle proxy copy for target. */
- if (!BKE_object_eval_proxy_copy(eval_ctx, ob)) {
- BKE_object_where_is_calc_ex(scene, rbw, ob, NULL);
+ if (!BKE_object_eval_proxy_copy(depsgraph, ob)) {
+ BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, NULL);
}
}
- if (ob->recalc & OB_RECALC_DATA) {
- BKE_object_handle_data_update(bmain, eval_ctx, scene, ob);
+ if (recalc_data) {
+ BKE_object_handle_data_update(depsgraph, scene, ob);
}
- ob->recalc &= ~OB_RECALC_ALL;
+ ob->id.recalc &= ID_RECALC_ALL;
- object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update);
+ object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
}
/* WARNING: "scene" here may not be the scene object actually resides in.
* When dealing with background-sets, "scene" is actually the active scene.
* e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
- * rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the corrent rigid body world
+ * rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the current rigid body world
*/
-void BKE_object_handle_update(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
+void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_object_handle_update_ex(bmain, eval_ctx, scene, ob, NULL, true);
+ BKE_object_handle_update_ex(depsgraph, scene, ob, NULL, true);
}
void BKE_object_sculpt_modifiers_changed(Object *ob)
@@ -2730,14 +2954,7 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
switch (GS(((ID *)ob->data)->name)) {
case ID_ME:
{
- Mesh *me = ob->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
- if (r_texflag) *r_texflag = &me->texflag;
- if (r_loc) *r_loc = me->loc;
- if (r_size) *r_size = me->size;
- if (r_rot) *r_rot = me->rot;
+ BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size);
break;
}
case ID_CU:
@@ -2767,6 +2984,68 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
return 1;
}
+/** Get evaluated mesh for given (main, original) object and depsgraph. */
+Mesh *BKE_object_get_evaluated_mesh(const Depsgraph *depsgraph, Object *ob)
+{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ return ob_eval->runtime.mesh_eval;
+}
+
+/* Get object's mesh with all modifiers applied. */
+Mesh *BKE_object_get_final_mesh(Object *object)
+{
+ if (object->runtime.mesh_eval != NULL) {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ BLI_assert(object->runtime.mesh_eval == object->data);
+ BLI_assert((object->runtime.mesh_eval->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) != 0);
+ return object->runtime.mesh_eval;
+ }
+ /* Wasn't evaluated yet. */
+ return object->data;
+}
+
+/* Get mesh which is not affected by modifiers:
+ * - For original objects it will be same as object->data, and it is a mesh
+ * which is in the corresponding bmain.
+ * - For copied-on-write objects it will give pointer to a copied-on-write
+ * mesh which corresponds to original object's mesh.
+ */
+Mesh *BKE_object_get_pre_modified_mesh(Object *object)
+{
+ if (object->runtime.mesh_orig != NULL) {
+ BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ BLI_assert(object->id.orig_id != NULL);
+ BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data);
+ Mesh *result = object->runtime.mesh_orig;
+ BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
+ return result;
+ }
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ return object->data;
+}
+
+/* Get a mesh which corresponds to very very original mesh from bmain.
+ * - For original objects it will be object->data.
+ * - For evaluated objects it will be same mesh as corresponding original
+ * object uses as data.
+ */
+Mesh *BKE_object_get_original_mesh(Object *object)
+{
+ Mesh *result = NULL;
+ if (object->id.orig_id == NULL) {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ result = object->data;
+ }
+ else {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ result = ((Object *)object->id.orig_id)->data;
+ }
+ BLI_assert(result != NULL);
+ BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) == 0);
+ return result;
+}
+
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = a, *bd = b;
@@ -2841,7 +3120,7 @@ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const
if (newkey || from_mix == false) {
/* create from mesh */
kb = BKE_keyblock_add_ctime(key, name, false);
- BKE_keyblock_convert_from_mesh(me, kb);
+ BKE_keyblock_convert_from_mesh(me, key, kb);
}
else {
/* copy from current values */
@@ -3269,6 +3548,10 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
return clip;
}
+void BKE_object_runtime_reset(Object *object)
+{
+ memset(&object->runtime, 0, sizeof(object->runtime));
+}
/*
* Find an associated Armature object
@@ -3304,33 +3587,33 @@ static void obrel_list_add(LinkNode **links, Object *ob)
}
/*
- * Iterates over all objects of the given scene.
+ * Iterates over all objects of the given scene layer.
* Depending on the eObjectSet flag:
* collect either OB_SET_ALL, OB_SET_VISIBLE or OB_SET_SELECTED objects.
* If OB_SET_VISIBLE or OB_SET_SELECTED are collected,
* then also add related objects according to the given includeFilters.
*/
-LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter)
+LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter)
{
LinkNode *links = NULL;
Base *base;
/* Remove markers from all objects */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
/* iterate over all selected and visible objects */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
if (objectSet == OB_SET_ALL) {
/* as we get all anyways just add it */
Object *ob = base->object;
obrel_list_add(&links, ob);
}
else {
- if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(((View3D *)NULL), scene, base)) ||
- (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, base)))
+ if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(((View3D *)NULL), base)) ||
+ (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(((View3D *)NULL), base)))
{
Object *ob = base->object;
@@ -3359,8 +3642,8 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS
/* child relationship */
if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) {
Base *local_base;
- for (local_base = scene->base.first; local_base; local_base = local_base->next) {
- if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) {
+ for (local_base = view_layer->object_bases.first; local_base; local_base = local_base->next) {
+ if (BASE_EDITABLE_BGMODE(((View3D *)NULL), local_base)) {
Object *child = local_base->object;
if (obrel_list_test(child)) {
@@ -3395,27 +3678,21 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS
*/
struct LinkNode *BKE_object_groups(Main *bmain, Object *ob)
{
- LinkNode *group_linknode = NULL;
- Group *group = NULL;
- while ((group = BKE_group_object_find(bmain, group, ob))) {
- BLI_linklist_prepend(&group_linknode, group);
+ LinkNode *collection_linknode = NULL;
+ Collection *collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob))) {
+ BLI_linklist_prepend(&collection_linknode, collection);
}
- return group_linknode;
+ return collection_linknode;
}
-void BKE_object_groups_clear(Main *bmain, Scene *scene, Base *base, Object *object)
+void BKE_object_groups_clear(Main *bmain, Object *ob)
{
- Group *group = NULL;
-
- BLI_assert((base == NULL) || (base->object == object));
-
- if (scene && base == NULL) {
- base = BKE_scene_base_find(scene, object);
- }
-
- while ((group = BKE_group_object_find(bmain, group, base->object))) {
- BKE_group_object_unlink(bmain, group, object, scene, base);
+ Collection *collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob))) {
+ BKE_collection_object_remove(bmain, collection, ob, false);
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -3439,12 +3716,12 @@ KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot)
Mesh *me = ob->data;
unsigned int i;
- DerivedMesh *dm = ob->derivedDeform ? ob->derivedDeform : ob->derivedFinal;
+ Mesh *me_eval = ob->runtime.mesh_deform_eval ? ob->runtime.mesh_deform_eval : ob->runtime.mesh_deform_eval;
const int *index;
- if (dm && (index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))) {
- MVert *mvert = dm->getVertArray(dm);
- unsigned int totvert = dm->getNumVerts(dm);
+ if (me_eval && (index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX))) {
+ MVert *mvert = me_eval->mvert;
+ uint totvert = me_eval->totvert;
/* tree over-allocs in case where some verts have ORIGINDEX_NONE */
tot = 0;
@@ -3594,12 +3871,80 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
return false;
}
+bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
+{
+ if (BKE_gpencil_modifier_dependsOnTime(md)) {
+ return true;
+ }
+
+ /* Check whether modifier is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name);
+
+ /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
+ if (adt->action) {
+ for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
+ return true;
+ }
+ }
+ }
+
+ /* This here allows modifier properties to get driven and still update properly */
+ for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
+{
+ if (BKE_shaderfx_dependsOnTime(fx)) {
+ return true;
+ }
+
+ /* Check whether effect is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name);
+
+ /* action - check for F-Curves with paths containing string[' */
+ if (adt->action) {
+ for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows properties to get driven and still update properly */
+ for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* set "ignore cache" flag for all caches on this object */
-static void object_cacheIgnoreClear(Main *bmain, Object *ob, int state)
+static void object_cacheIgnoreClear(Object *ob, int state)
{
ListBase pidlist;
PTCacheID *pid;
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0);
+ BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->cache) {
@@ -3617,10 +3962,8 @@ static void object_cacheIgnoreClear(Main *bmain, Object *ob, int state)
* Avoid calling this in new code unless there is a very good reason for it!
*/
bool BKE_object_modifier_update_subframe(
- Main *bmain, EvaluationContext *eval_ctx,
- Scene *scene, Object *ob, bool update_mesh,
- int parent_recursion, float frame,
- int type)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, bool update_mesh,
+ int parent_recursion, float frame, int type)
{
ModifierData *md = modifiers_findByType(ob, (ModifierType)type);
bConstraint *con;
@@ -3643,8 +3986,8 @@ bool BKE_object_modifier_update_subframe(
if (parent_recursion) {
int recursion = parent_recursion - 1;
bool no_update = false;
- if (ob->parent) no_update |= BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ob->parent, 0, recursion, frame, type);
- if (ob->track) no_update |= BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ob->track, 0, recursion, frame, type);
+ if (ob->parent) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->parent, 0, recursion, frame, type);
+ if (ob->track) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->track, 0, recursion, frame, type);
/* skip subframe if object is parented
* to vertex of a dynamic paint canvas */
@@ -3661,7 +4004,7 @@ bool BKE_object_modifier_update_subframe(
cti->get_constraint_targets(con, &targets);
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar)
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ct->tar, 0, recursion, frame, type);
+ BKE_object_modifier_update_subframe(depsgraph, scene, ct->tar, 0, recursion, frame, type);
}
/* free temp targets */
if (cti->flush_constraint_targets)
@@ -3671,29 +4014,48 @@ bool BKE_object_modifier_update_subframe(
}
/* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
+ /* TODO(sergey): What about animation? */
+ ob->id.recalc |= ID_RECALC_ALL;
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
if (update_mesh) {
/* ignore cache clear during subframe updates
- * to not mess up cache validity */
- object_cacheIgnoreClear(bmain, ob, 1);
- BKE_object_handle_update(bmain, eval_ctx, scene, ob);
- object_cacheIgnoreClear(bmain, ob, 0);
+ * to not mess up cache validity */
+ object_cacheIgnoreClear(ob, 1);
+ BKE_object_handle_update(depsgraph, scene, ob);
+ object_cacheIgnoreClear(ob, 0);
}
else
- BKE_object_where_is_calc_time(scene, ob, frame);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, frame);
/* for curve following objects, parented curve has to be updated too */
if (ob->type == OB_CURVE) {
Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
}
/* and armatures... */
if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
- BKE_pose_where_is(scene, ob);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
+ BKE_pose_where_is(depsgraph, scene, ob);
}
return false;
}
+
+bool BKE_image_empty_visible_in_view3d(const Object *ob, const RegionView3D *rv3d)
+{
+ int visibility_flag = ob->empty_image_visibility_flag;
+
+ if ((visibility_flag & OB_EMPTY_IMAGE_VISIBLE_BACKSIDE) == 0) {
+ if (dot_v3v3((float *)&ob->obmat[2], (float *)&rv3d->viewinv[2]) < 0.0f) {
+ return false;
+ }
+ }
+
+ if (rv3d->is_persp) {
+ return visibility_flag & OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE;
+ }
+ else {
+ return visibility_flag & OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC;
+ }
+}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 47f86c28dfc..70569bfd51b 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -51,7 +51,9 @@
#include "BKE_editmesh.h"
#include "BKE_object_deform.h" /* own include */
#include "BKE_object.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil.h"
/** \name Misc helpers
* \{ */
@@ -401,10 +403,17 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
*/
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
- if (BKE_object_is_in_editmode_vgroup(ob))
- object_defgroup_remove_edit_mode(ob, defgroup);
- else
- object_defgroup_remove_object_mode(ob, defgroup);
+ if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_vgroup_remove(ob, defgroup);
+ }
+ else {
+ if (BKE_object_is_in_editmode_vgroup(ob))
+ object_defgroup_remove_edit_mode(ob, defgroup);
+ else
+ object_defgroup_remove_object_mode(ob, defgroup);
+
+ BKE_object_batch_cache_dirty_tag(ob);
+ }
}
/**
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 1406a7dd66b..882ec07f56a 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -42,26 +42,30 @@
#include "BLI_rand.h"
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
#include "BKE_animsys.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_depsgraph.h"
+#include "BKE_collection.h"
#include "BKE_font.h"
-#include "BKE_group.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_editmesh.h"
#include "BKE_anim.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "BLI_strict_flags.h"
#include "BLI_hash.h"
@@ -69,16 +73,14 @@
/* Dupli-Geometry */
typedef struct DupliContext {
- EvaluationContext *eval_ctx;
- bool do_update;
- bool animated;
- Group *group; /* XXX child objects are selected from this group if set, could be nicer */
+ Depsgraph *depsgraph;
+ Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */
+ Object *obedit; /* Only to check if the object is in edit-mode. */
- Main *bmain;
Scene *scene;
+ ViewLayer *view_layer;
Object *object;
float space_mat[4][4];
- unsigned int lay;
int persistent_id[MAX_DUPLI_RECUR];
int level;
@@ -98,23 +100,20 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx);
/* create initial context for root object */
static void init_context(
- DupliContext *r_ctx, Main *bmain, EvaluationContext *eval_ctx,
- Scene *scene, Object *ob, float space_mat[4][4], bool update)
+ DupliContext *r_ctx, Depsgraph *depsgraph,
+ Scene *scene, Object *ob, float space_mat[4][4])
{
- r_ctx->eval_ctx = eval_ctx;
- r_ctx->bmain = bmain;
+ r_ctx->depsgraph = depsgraph;
r_ctx->scene = scene;
- /* don't allow BKE_object_handle_update for viewport during render, can crash */
- r_ctx->do_update = update && !(G.is_rendering && eval_ctx->mode != DAG_EVAL_RENDER);
- r_ctx->animated = false;
- r_ctx->group = NULL;
+ r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ r_ctx->collection = NULL;
r_ctx->object = ob;
+ r_ctx->obedit = OBEDIT_FROM_OBACT(ob);
if (space_mat)
copy_m4_m4(r_ctx->space_mat, space_mat);
else
unit_m4(r_ctx->space_mat);
- r_ctx->lay = ob->lay;
r_ctx->level = 0;
r_ctx->gen = get_dupli_generator(r_ctx);
@@ -123,15 +122,13 @@ static void init_context(
}
/* create sub-context for recursive duplis */
-static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated)
+static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
{
*r_ctx = *ctx;
- r_ctx->animated |= animated; /* object animation makes all children animated */
-
/* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
- if (ctx->gen->type == OB_DUPLIGROUP)
- r_ctx->group = ctx->object->dup_group;
+ if (ctx->gen->type == OB_DUPLICOLLECTION)
+ r_ctx->collection = ctx->object->dup_group;
r_ctx->object = ob;
if (mat)
@@ -146,8 +143,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj
* mat is transform of the object relative to current context (including object obmat)
*/
static DupliObject *make_dupli(const DupliContext *ctx,
- Object *ob, float mat[4][4], int index,
- bool animated, bool hide)
+ Object *ob, float mat[4][4], int index)
{
DupliObject *dob;
int i;
@@ -164,7 +160,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->ob = ob;
mul_m4_m4m4(dob->mat, (float (*)[4])ctx->space_mat, mat);
dob->type = ctx->gen->type;
- dob->animated = animated || ctx->animated; /* object itself or some parent is animated */
/* set persistent id, which is an array with a persistent index for each level
* (particle number, vertex number, ..). by comparing this we can find the same
@@ -177,8 +172,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
for (; i < MAX_DUPLI_RECUR; i++)
dob->persistent_id[i] = INT_MAX;
- if (hide)
- dob->no_draw = true;
/* metaballs never draw in duplis, they are instead merged into one by the basis
* mball outside of the group. this does mean that if that mball is not in the
* scene, they will not show up at all, limitation that should be solved once. */
@@ -208,12 +201,12 @@ static DupliObject *make_dupli(const DupliContext *ctx,
/* recursive dupli objects
* space_mat is the local dupli space (excluding dupli object obmat!)
*/
-static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated)
+static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index)
{
- /* simple preventing of too deep nested groups with MAX_DUPLI_RECUR */
+ /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
if (ctx->level < MAX_DUPLI_RECUR) {
DupliContext rctx;
- copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated);
+ copy_dupli_context(&rctx, ctx, ob, space_mat, index);
if (rctx.gen) {
rctx.gen->make_duplis(&rctx);
}
@@ -235,45 +228,40 @@ static bool is_child(const Object *ob, const Object *parent)
return false;
}
-/* create duplis from every child in scene or group */
+/* create duplis from every child in scene or collection */
static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb)
{
Object *parent = ctx->object;
- Object *obedit = ctx->scene->obedit;
-
- if (ctx->group) {
- unsigned int lay = ctx->group->layer;
- int groupid = 0;
- GroupObject *go;
- for (go = ctx->group->gobject.first; go; go = go->next, groupid++) {
- Object *ob = go->ob;
- if ((ob->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ if (ctx->collection) {
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(ctx->collection, ob, mode)
+ {
+ if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, _base_id);
/* mballs have a different dupli handling */
- if (ob->type != OB_MBALL)
+ if (ob->type != OB_MBALL) {
ob->flag |= OB_DONE; /* doesn't render */
-
+ }
make_child_duplis_cb(&pctx, userdata, ob);
}
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
else {
- unsigned int lay = ctx->scene->lay;
int baseid = 0;
- Base *base;
- for (base = ctx->scene->base.first; base; base = base->next, baseid++) {
+ ViewLayer *view_layer = ctx->view_layer;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) {
Object *ob = base->object;
-
- if ((base->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid);
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL)
- ob->flag |= OB_DONE; /* doesnt render */
+ ob->flag |= OB_DONE; /* doesn't render */
make_child_duplis_cb(&pctx, userdata, ob);
}
@@ -284,77 +272,49 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
/*---- Implementations ----*/
-/* OB_DUPLIGROUP */
-static void make_duplis_group(const DupliContext *ctx)
+/* OB_DUPLICOLLECTION */
+static void make_duplis_collection(const DupliContext *ctx)
{
- bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
Object *ob = ctx->object;
- Group *group;
- GroupObject *go;
- float group_mat[4][4];
- int id;
- bool animated, hide;
+ Collection *collection;
+ float collection_mat[4][4];
if (ob->dup_group == NULL) return;
- group = ob->dup_group;
+ collection = ob->dup_group;
- /* combine group offset and obmat */
- unit_m4(group_mat);
- sub_v3_v3(group_mat[3], group->dupli_ofs);
- mul_m4_m4m4(group_mat, ob->obmat, group_mat);
+ /* combine collection offset and obmat */
+ unit_m4(collection_mat);
+ sub_v3_v3(collection_mat[3], collection->dupli_ofs);
+ mul_m4_m4m4(collection_mat, ob->obmat, collection_mat);
/* don't access 'ob->obmat' from now on. */
- /* handles animated groups */
-
- /* we need to check update for objects that are not in scene... */
- if (ctx->do_update) {
- /* note: update is optional because we don't always need object
- * transformations to be correct. Also fixes bug [#29616]. */
- BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, ctx->scene, ob, group);
- }
-
- animated = BKE_group_is_animated(group, ob);
-
- for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
- /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
- if (go->ob != ob) {
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(collection, cob, mode)
+ {
+ if (cob != ob) {
float mat[4][4];
- /* Special case for instancing dupli-groups, see: T40051
- * this object may be instanced via dupli-verts/faces, in this case we don't want to render
- * (blender convention), but _do_ show in the viewport.
- *
- * Regular objects work fine but not if we're instancing dupli-groups,
- * because the rules for rendering aren't applied to objects they instance.
- * We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
- */
- if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
- continue;
- }
-
- /* group dupli offset, should apply after everything else */
- mul_m4_m4m4(mat, group_mat, go->ob->obmat);
-
- /* check the group instance and object layers match, also that the object visible flags are ok. */
- hide = (go->ob->lay & group->layer) == 0 ||
- (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
+ /* collection dupli offset, should apply after everything else */
+ mul_m4_m4m4(mat, collection_mat, cob->obmat);
- make_dupli(ctx, go->ob, mat, id, animated, hide);
+ make_dupli(ctx, cob, mat, _base_id);
/* recursion */
- make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
+ make_recursive_duplis(ctx, cob, collection_mat, _base_id);
}
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
-static const DupliGenerator gen_dupli_group = {
- OB_DUPLIGROUP, /* type */
- make_duplis_group /* make_duplis */
+static const DupliGenerator gen_dupli_collection = {
+ OB_DUPLICOLLECTION, /* type */
+ make_duplis_collection /* make_duplis */
};
/* OB_DUPLIFRAMES */
static void make_duplis_frames(const DupliContext *ctx)
{
+ Depsgraph *depsgraph = ctx->depsgraph;
Scene *scene = ctx->scene;
Object *ob = ctx->object;
extern int enable_cu_speed; /* object.c */
@@ -362,8 +322,8 @@ static void make_duplis_frames(const DupliContext *ctx)
int cfrao = scene->r.cfra;
int dupend = ob->dupend;
- /* dupliframes not supported inside groups */
- if (ctx->group)
+ /* dupliframes not supported inside collections */
+ if (ctx->collection)
return;
/* if we don't have any data/settings which will lead to object movement,
* don't waste time trying, as it will all look the same...
@@ -381,10 +341,6 @@ static void make_duplis_frames(const DupliContext *ctx)
/* duplicate over the required range */
if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0;
- /* special flag to avoid setting recalc flags to notify the depsgraph of
- * updates, as this is not a permanent change to the object */
- ob->id.recalc |= ID_RECALC_SKIP_ANIM_TAG;
-
for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) {
int ok = 1;
@@ -402,10 +358,11 @@ static void make_duplis_frames(const DupliContext *ctx)
* and/or other objects which may affect this object's transforms are not updated either.
* However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine!
*/
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
- BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra);
+ /* ob-eval will do drivers, so we don't need to do them */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
- make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false);
+ make_dupli(ctx, ob, ob->obmat, scene->r.cfra);
}
}
@@ -416,8 +373,9 @@ static void make_duplis_frames(const DupliContext *ctx)
*/
scene->r.cfra = cfrao;
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
- BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra);
+ /* ob-eval will do drivers, so we don't need to do them */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
/* but, to make sure unkeyed object transforms are still sane,
* let's copy object's original data back over
@@ -432,7 +390,7 @@ static const DupliGenerator gen_dupli_frames = {
/* OB_DUPLIVERTS */
typedef struct VertexDupliData {
- DerivedMesh *dm;
+ Mesh *me_eval;
BMEditMesh *edit_btmesh;
int totvert;
float (*orco)[3];
@@ -490,56 +448,34 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false);
+ dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
if (vdd->orco)
copy_v3_v3(dob->orco, vdd->orco[index]);
/* recursion */
- make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index, false);
+ make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
}
static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child)
{
VertexDupliData *vdd = userdata;
- DerivedMesh *dm = vdd->dm;
+ Mesh *me_eval = vdd->me_eval;
vdd->inst_ob = child;
invert_m4_m4(child->imat, child->obmat);
/* relative transform from parent to child space */
mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat);
- if (vdd->edit_btmesh) {
- dm->foreachMappedVert(dm, vertex_dupli__mapFunc, vdd,
- vdd->use_rotation ? DM_FOREACH_USE_NORMAL : 0);
- }
- else {
- int a, totvert = vdd->totvert;
- float vec[3], no[3];
-
- if (vdd->use_rotation) {
- for (a = 0; a < totvert; a++) {
- dm->getVertCo(dm, a, vec);
- dm->getVertNo(dm, a, no);
-
- vertex_dupli__mapFunc(vdd, a, vec, no, NULL);
- }
- }
- else {
- for (a = 0; a < totvert; a++) {
- dm->getVertCo(dm, a, vec);
-
- vertex_dupli__mapFunc(vdd, a, vec, NULL, NULL);
- }
- }
- }
+ BKE_mesh_foreach_mapped_vert(me_eval, vertex_dupli__mapFunc, vdd,
+ vdd->use_rotation ? MESH_FOREACH_USE_NORMAL : 0);
}
static void make_duplis_verts(const DupliContext *ctx)
{
Scene *scene = ctx->scene;
Object *parent = ctx->object;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
VertexDupliData vdd;
vdd.ctx = ctx;
@@ -547,32 +483,31 @@ static void make_duplis_verts(const DupliContext *ctx)
/* gather mesh info */
{
- Mesh *me = parent->data;
- BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH);
+ vdd.edit_btmesh = BKE_editmesh_from_object(parent);
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
- vdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
- }
- else if (em) {
- vdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
+ /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */
+ if (vdd.edit_btmesh != NULL) {
+ /* XXX TODO replace with equivalent of editbmesh_get_eval_cage when available. */
+ vdd.me_eval = mesh_get_eval_deform(ctx->depsgraph, scene, parent, dm_mask);
}
else {
- vdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ vdd.me_eval = mesh_get_eval_final(ctx->depsgraph, scene, parent, dm_mask);
}
- vdd.edit_btmesh = me->edit_btmesh;
- if (use_texcoords)
- vdd.orco = vdd.dm->getVertDataArray(vdd.dm, CD_ORCO);
- else
+ if (use_texcoords) {
+ vdd.orco = CustomData_get_layer(&vdd.me_eval->vdata, CD_ORCO);
+ }
+ else {
vdd.orco = NULL;
+ }
- vdd.totvert = vdd.dm->getNumVerts(vdd.dm);
+ vdd.totvert = vdd.me_eval->totvert;
}
make_child_duplis(ctx, &vdd, make_child_duplis_verts);
- vdd.dm->release(vdd.dm);
+ vdd.me_eval = NULL;
}
static const DupliGenerator gen_dupli_verts = {
@@ -626,8 +561,8 @@ static void make_duplis_font(const DupliContext *ctx)
const wchar_t *text = NULL;
bool text_free = false;
- /* font dupliverts not supported inside groups */
- if (ctx->group)
+ /* font dupliverts not supported inside collections */
+ if (ctx->collection)
return;
copy_m4_m4(pmat, par->obmat);
@@ -655,7 +590,9 @@ static void make_duplis_font(const DupliContext *ctx)
/* advance matching BLI_strncpy_wchar_from_utf8 */
for (a = 0; a < text_len; a++, ct++) {
- ob = find_family_object(ctx->bmain, cu->family, family_len, (unsigned int)text[a], family_gh);
+ /* XXX That G.main is *really* ugly, but not sure what to do here...
+ * Definitively don't think it would be safe to put back Main *bmain pointer in DupliContext as done in 2.7x? */
+ ob = find_family_object(G.main, cu->family, family_len, (unsigned int)text[a], family_gh);
if (ob) {
vec[0] = fsize * (ct->xof - xof);
vec[1] = fsize * (ct->yof - yof);
@@ -675,7 +612,7 @@ static void make_duplis_font(const DupliContext *ctx)
copy_v3_v3(obmat[3], vec);
- make_dupli(ctx, ob, obmat, a, false, false);
+ make_dupli(ctx, ob, obmat, a);
}
}
@@ -695,7 +632,7 @@ static const DupliGenerator gen_dupli_verts_font = {
/* OB_DUPLIFACES */
typedef struct FaceDupliData {
- DerivedMesh *dm;
+ Mesh *me_eval;
int totface;
MPoly *mpoly;
MLoop *mloop;
@@ -743,7 +680,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
float (*orco)[3] = fdd->orco;
MLoopUV *mloopuv = fdd->mloopuv;
int a, totface = fdd->totface;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
float child_imat[4][4];
DupliObject *dob;
@@ -781,7 +718,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(ctx, inst_ob, obmat, a, false, false);
+ dob = make_dupli(ctx, inst_ob, obmat, a);
if (use_texcoords) {
float w = 1.0f / (float)mp->totloop;
@@ -801,7 +738,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
}
/* recursion */
- make_recursive_duplis(ctx, inst_ob, space_mat, a, false);
+ make_recursive_duplis(ctx, inst_ob, space_mat, a);
}
}
@@ -809,7 +746,7 @@ static void make_duplis_faces(const DupliContext *ctx)
{
Scene *scene = ctx->scene;
Object *parent = ctx->object;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
FaceDupliData fdd;
fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
@@ -819,36 +756,34 @@ static void make_duplis_faces(const DupliContext *ctx)
BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH);
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
- fdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
- }
- else if (em) {
- fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
+ /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */
+ if (em != NULL) {
+ /* XXX TODO replace with equivalent of editbmesh_get_eval_cage when available. */
+ fdd.me_eval = mesh_get_eval_deform(ctx->depsgraph, scene, parent, dm_mask);
}
else {
- fdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ fdd.me_eval = mesh_get_eval_final(ctx->depsgraph, scene, parent, dm_mask);
}
if (use_texcoords) {
- CustomData *ml_data = fdd.dm->getLoopDataLayout(fdd.dm);
- const int uv_idx = CustomData_get_render_layer(ml_data, CD_MLOOPUV);
- fdd.orco = fdd.dm->getVertDataArray(fdd.dm, CD_ORCO);
- fdd.mloopuv = CustomData_get_layer_n(ml_data, CD_MLOOPUV, uv_idx);
+ fdd.orco = CustomData_get_layer(&fdd.me_eval->vdata, CD_ORCO);
+ const int uv_idx = CustomData_get_render_layer(&fdd.me_eval->ldata, CD_MLOOPUV);
+ fdd.mloopuv = CustomData_get_layer_n(&fdd.me_eval->ldata, CD_MLOOPUV, uv_idx);
}
else {
fdd.orco = NULL;
fdd.mloopuv = NULL;
}
- fdd.totface = fdd.dm->getNumPolys(fdd.dm);
- fdd.mpoly = fdd.dm->getPolyArray(fdd.dm);
- fdd.mloop = fdd.dm->getLoopArray(fdd.dm);
- fdd.mvert = fdd.dm->getVertArray(fdd.dm);
+ fdd.totface = fdd.me_eval->totpoly;
+ fdd.mpoly = fdd.me_eval->mpoly;
+ fdd.mloop = fdd.me_eval->mloop;
+ fdd.mvert = fdd.me_eval->mvert;
}
make_child_duplis(ctx, &fdd, make_child_duplis_faces);
- fdd.dm->release(fdd.dm);
+ fdd.me_eval = NULL;
}
static const DupliGenerator gen_dupli_faces = {
@@ -861,10 +796,10 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
{
Scene *scene = ctx->scene;
Object *par = ctx->object;
- bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ bool for_render = mode == DAG_EVAL_RENDER;
+ bool use_texcoords = for_render;
- GroupObject *go;
Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
DupliObject *dob;
ParticleDupliWeight *dw;
@@ -877,8 +812,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0;
float (*obmat)[4];
int a, b, hair = 0;
- int totpart, totchild, totgroup = 0 /*, pa_num */;
- const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene);
+ int totpart, totchild;
int no_draw_flag = PARS_UNEXIST;
@@ -889,21 +823,20 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part == NULL)
return;
- if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER)))
+ if (!psys_check_enabled(par, psys, for_render))
return;
if (!for_render)
no_draw_flag |= PARS_NO_DISP;
- ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */
+ ctime = DEG_get_ctime(ctx->depsgraph); /* NOTE: in old animsys, used parent object's timeoffset... */
totpart = psys->totpart;
totchild = psys->totchild;
- BLI_srandom((unsigned int)(31415926 + psys->seed));
-
- if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
+ if ((for_render || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
ParticleSimulationData sim = {NULL};
+ sim.depsgraph = ctx->depsgraph;
sim.scene = scene;
sim.ob = par;
sim.psys = psys;
@@ -917,10 +850,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
return;
}
else { /*PART_DRAW_GR */
- if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject))
+ if (part->dup_group == NULL)
+ return;
+
+ const ListBase dup_collection_objects = BKE_collection_object_cache_get(part->dup_group);
+ if (BLI_listbase_is_empty(&dup_collection_objects))
return;
- if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) {
+ if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) {
return;
}
}
@@ -937,46 +874,67 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
totpart = psys->totcached;
}
- psys_check_group_weights(part);
+ RNG *rng = BLI_rng_new_srandom(31415926u + (unsigned int)psys->seed);
psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
/* gather list of objects or single object */
- if (part->ren_as == PART_DRAW_GR) {
- if (ctx->do_update) {
- BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, scene, par, part->dup_group);
- }
+ int totcollection = 0;
+ if (part->ren_as == PART_DRAW_GR) {
if (part->draw & PART_DRAW_COUNT_GR) {
- for (dw = part->dupliweights.first; dw; dw = dw->next)
- totgroup += dw->count;
+ psys_find_group_weights(part);
+
+ for (dw = part->dupliweights.first; dw; dw = dw->next) {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ if (dw->ob == object) {
+ totcollection += dw->count;
+ break;
+ }
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
}
else {
- for (go = part->dup_group->gobject.first; go; go = go->next)
- totgroup++;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ (void) object;
+ totcollection++;
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
/* we also copy the actual objects to restore afterwards, since
* BKE_object_where_is_calc_time will change the object which breaks transform */
- oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list");
- obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list");
-
- if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
- dw = part->dupliweights.first;
+ oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
+ obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list");
- for (a = 0; a < totgroup; dw = dw->next) {
- for (b = 0; b < dw->count; b++, a++) {
- oblist[a] = dw->ob;
- obcopylist[a] = *dw->ob;
+ if (part->draw & PART_DRAW_COUNT_GR) {
+ a = 0;
+ for (dw = part->dupliweights.first; dw; dw = dw->next) {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ if (dw->ob == object) {
+ for (b = 0; b < dw->count; b++, a++) {
+ oblist[a] = dw->ob;
+ obcopylist[a] = *dw->ob;
+ }
+ break;
+ }
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
}
else {
- go = part->dup_group->gobject.first;
- for (a = 0; a < totgroup; a++, go = go->next) {
- oblist[a] = go->ob;
- obcopylist[a] = *go->ob;
+ a = 0;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ oblist[a] = object;
+ obcopylist[a] = *object;
+ a++;
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
}
else {
@@ -1018,14 +976,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->ren_as == PART_DRAW_GR) {
/* prevent divide by zero below [#28336] */
- if (totgroup == 0)
+ if (totcollection == 0)
continue;
- /* for groups, pick the object based on settings */
+ /* for collections, pick the object based on settings */
if (part->draw & PART_DRAW_RAND_GR)
- b = BLI_rand() % totgroup;
+ b = BLI_rng_get_int(rng) % totcollection;
else
- b = a % totgroup;
+ b = a % totcollection;
ob = oblist[b];
obmat = oblist[b]->obmat;
@@ -1065,27 +1023,37 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
- for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) {
-
+ b = 0;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
copy_m4_m4(tmat, oblist[b]->obmat);
+
/* apply particle scale */
mul_mat3_m4_fl(tmat, size * scale);
mul_v3_fl(tmat[3], size * scale);
- /* group dupli offset, should apply after everything else */
- if (!is_zero_v3(part->dup_group->dupli_ofs))
+
+ /* collection dupli offset, should apply after everything else */
+ if (!is_zero_v3(part->dup_group->dupli_ofs)) {
sub_v3_v3(tmat[3], part->dup_group->dupli_ofs);
+ }
+
/* individual particle transform */
mul_m4_m4m4(mat, pamat, tmat);
- dob = make_dupli(ctx, go->ob, mat, a, false, false);
+ dob = make_dupli(ctx, object, mat, a);
dob->particle_system = psys;
- if (use_texcoords)
+
+ if (use_texcoords) {
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
+ }
+
+ b++;
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
else {
/* to give ipos in object correct offset */
- BKE_object_where_is_calc_time(scene, ob, ctime - pa_time);
+ BKE_object_where_is_calc_time(ctx->depsgraph, scene, ob, ctime - pa_time);
copy_v3_v3(vec, obmat[3]);
obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;
@@ -1126,24 +1094,22 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->draw & PART_DRAW_GLOBAL_OB)
add_v3_v3v3(mat[3], mat[3], vec);
- dob = make_dupli(ctx, ob, mat, a, false, false);
+ dob = make_dupli(ctx, ob, mat, a);
dob->particle_system = psys;
if (use_texcoords)
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
- /* XXX blender internal needs this to be set to dupligroup to render
- * groups correctly, but we don't want this hack for cycles */
- if (dupli_type_hack && ctx->group)
- dob->type = OB_DUPLIGROUP;
}
}
/* restore objects since they were changed in BKE_object_where_is_calc_time */
if (part->ren_as == PART_DRAW_GR) {
- for (a = 0; a < totgroup; a++)
+ for (a = 0; a < totcollection; a++)
*(oblist[a]) = obcopylist[a];
}
else
*ob = obcopy;
+
+ BLI_rng_free(rng);
}
/* clean up */
@@ -1167,7 +1133,7 @@ static void make_duplis_particles(const DupliContext *ctx)
for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
/* particles create one more level for persistent psys index */
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid);
make_duplis_particle_system(&pctx, psys);
}
}
@@ -1189,7 +1155,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
return NULL;
/* Should the dupli's be generated for this object? - Respect restrict flags */
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
+ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
return NULL;
if (transflag & OB_DUPLIPARTS) {
@@ -1210,8 +1176,8 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
else if (transflag & OB_DUPLIFRAMES) {
return &gen_dupli_frames;
}
- else if (transflag & OB_DUPLIGROUP) {
- return &gen_dupli_group;
+ else if (transflag & OB_DUPLICOLLECTION) {
+ return &gen_dupli_collection;
}
return NULL;
@@ -1221,11 +1187,11 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/* ---- ListBase dupli container implementation ---- */
/* Returns a list of DupliObject */
-ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update)
+ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
DupliContext ctx;
- init_context(&ctx, bmain, eval_ctx, scene, ob, NULL, update);
+ init_context(&ctx, depsgraph, sce, ob, NULL);
if (ctx.gen) {
ctx.duplilist = duplilist;
ctx.gen->make_duplis(&ctx);
@@ -1234,13 +1200,6 @@ ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *s
return duplilist;
}
-/* note: previously updating was always done, this is why it defaults to be on
- * but there are likely places it can be called without updating */
-ListBase *object_duplilist(Main *bmain, EvaluationContext *eval_ctx, Scene *sce, Object *ob)
-{
- return object_duplilist_ex(bmain, eval_ctx, sce, ob, true);
-}
-
void free_object_duplilist(ListBase *lb)
{
BLI_freelistN(lb);
@@ -1276,59 +1235,3 @@ int count_duplilist(Object *ob)
}
return 1;
}
-
-DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
-{
- DupliApplyData *apply_data = NULL;
- int num_objects = BLI_listbase_count(duplilist);
-
- if (num_objects > 0) {
- DupliObject *dob;
- int i;
- apply_data = MEM_mallocN(sizeof(DupliApplyData), "DupliObject apply data");
- apply_data->num_objects = num_objects;
- apply_data->extra = MEM_mallocN(sizeof(DupliExtraData) * (size_t) num_objects,
- "DupliObject apply extra data");
-
- for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
- /* make sure derivedmesh is calculated once, before drawing */
- if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
- mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
- dob->ob->transflag |= OB_DUPLICALCDERIVED;
- }
- }
-
- for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
- /* copy obmat from duplis */
- copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);
- copy_m4_m4(dob->ob->obmat, dob->mat);
-
- /* copy layers from the main duplicator object */
- apply_data->extra[i].lay = dob->ob->lay;
- dob->ob->lay = ob->lay;
- }
- }
- return apply_data;
-}
-
-void duplilist_restore(ListBase *duplilist, DupliApplyData *apply_data)
-{
- DupliObject *dob;
- int i;
- /* Restore object matrices.
- * NOTE: this has to happen in reverse order, since nested
- * dupli objects can repeatedly override the obmat.
- */
- for (dob = duplilist->last, i = apply_data->num_objects - 1; dob; dob = dob->prev, --i) {
- copy_m4_m4(dob->ob->obmat, apply_data->extra[i].obmat);
- dob->ob->transflag &= ~OB_DUPLICALCDERIVED;
-
- dob->ob->lay = apply_data->extra[i].lay;
- }
-}
-
-void duplilist_free_apply_data(DupliApplyData *apply_data)
-{
- MEM_freeN(apply_data->extra);
- MEM_freeN(apply_data);
-}
diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c
new file mode 100644
index 00000000000..ef254864d2e
--- /dev/null
+++ b/source/blender/blenkernel/intern/object_facemap.c
@@ -0,0 +1,257 @@
+
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/object_facemap.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_object.h"
+#include "BKE_object_facemap.h" /* own include */
+#include "BKE_object_deform.h"
+
+#include "BLT_translation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+static bool fmap_unique_check(void *arg, const char *name)
+{
+ struct {Object *ob; void *fm; } *data = arg;
+
+ bFaceMap *fmap;
+
+ for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) {
+ if (data->fm != fmap) {
+ if (!strcmp(fmap->name, name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bFaceMap *fmap_duplicate(bFaceMap *infmap)
+{
+ bFaceMap *outfmap;
+
+ if (!infmap)
+ return NULL;
+
+ outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap");
+
+ /* For now, just copy everything over. */
+ memcpy(outfmap, infmap, sizeof(bFaceMap));
+
+ outfmap->next = outfmap->prev = NULL;
+
+ return outfmap;
+}
+
+void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase)
+{
+ bFaceMap *fmap, *fmapn;
+
+ BLI_listbase_clear(outbase);
+
+ for (fmap = inbase->first; fmap; fmap = fmap->next) {
+ fmapn = fmap_duplicate(fmap);
+ BLI_addtail(outbase, fmapn);
+ }
+}
+
+void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap)
+{
+ struct {Object *ob; void *fmap; } data;
+ data.ob = ob;
+ data.fmap = fmap;
+
+ BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name));
+}
+
+bFaceMap *BKE_object_facemap_add_name(Object *ob, const char *name)
+{
+ bFaceMap *fmap;
+
+ if (!ob || ob->type != OB_MESH)
+ return NULL;
+
+ fmap = MEM_callocN(sizeof(bFaceMap), __func__);
+
+ BLI_strncpy(fmap->name, name, sizeof(fmap->name));
+
+ BLI_addtail(&ob->fmaps, fmap);
+
+ ob->actfmap = BLI_listbase_count(&ob->fmaps);
+
+ BKE_object_facemap_unique_name(ob, fmap);
+
+ return fmap;
+}
+
+bFaceMap *BKE_object_facemap_add(Object *ob)
+{
+ return BKE_object_facemap_add_name(ob, DATA_("FaceMap"));
+}
+
+
+static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge)
+{
+ const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
+
+ if (cd_fmap_offset != -1) {
+ BMFace *efa;
+ BMIter iter;
+ int *map;
+
+ if (purge) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map) {
+ if (*map == fmap_nr)
+ *map = -1;
+ else if (*map > fmap_nr)
+ *map -= 1;
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map && *map == fmap_nr && (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
+ *map = -1;
+ }
+ }
+ }
+ }
+
+ if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
+ ob->actfmap--;
+
+ BLI_remlink(&ob->fmaps, fmap);
+ MEM_freeN(fmap);
+ }
+ }
+}
+
+static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge)
+{
+ const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
+ int i;
+
+ if (map) {
+ for (i = 0; i < me->totpoly; i++) {
+ if (map[i] == fmap_nr)
+ map[i] = -1;
+ else if (purge && map[i] > fmap_nr)
+ map[i]--;
+ }
+ }
+ }
+
+ if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
+ ob->actfmap--;
+
+ BLI_remlink(&ob->fmaps, fmap);
+ MEM_freeN(fmap);
+ }
+}
+
+static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge)
+{
+ if (is_edit_mode)
+ object_fmap_remove_edit_mode(ob, fmap, false, purge);
+ else
+ object_fmap_remove_object_mode(ob, fmap, purge);
+}
+
+void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap)
+{
+ fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true);
+}
+
+void BKE_object_facemap_clear(Object *ob)
+{
+ bFaceMap *fmap = (bFaceMap *)ob->fmaps.first;
+
+ if (fmap) {
+ const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
+
+ while (fmap) {
+ bFaceMap *next_fmap = fmap->next;
+ fmap_remove_exec(ob, fmap, edit_mode, false);
+ fmap = next_fmap;
+ }
+ }
+ /* remove all face-maps */
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0);
+ }
+ ob->actfmap = 0;
+}
+
+int BKE_object_facemap_name_index(Object *ob, const char *name)
+{
+ return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1;
+}
+
+bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
+{
+ return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
+}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index bb738033f02..2ac4c739e09 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -28,22 +28,22 @@
*/
#include "DNA_anim_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
-#include "BLI_threads.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
-#include "BKE_depsgraph.h"
+#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
@@ -53,21 +53,26 @@
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "BKE_gpencil.h"
+
+#include "MEM_guardedalloc.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
-static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER;
-void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
- Object *ob)
+void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* calculate local matrix */
BKE_object_to_mat4(ob, ob->obmat);
@@ -75,7 +80,7 @@ void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
/* Evaluate parent */
/* NOTE: based on solve_parenting(), but with the cruft stripped out */
-void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
+void BKE_object_eval_parent(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
@@ -85,14 +90,14 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
float tmat[4][4];
float locmat[4][4];
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* get local matrix (but don't calculate it, as that was done already!) */
// XXX: redundant?
copy_m4_m4(locmat, ob->obmat);
/* get parent effect matrix */
- BKE_object_get_parent_matrix(scene, ob, par, totmat);
+ BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -107,14 +112,14 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
}
}
-void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
+void BKE_object_eval_constraints(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
bConstraintOb *cob;
float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* evaluate constraints stack */
/* TODO: split this into:
@@ -125,23 +130,30 @@ void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
* Not sure why, this is from Joshua - sergey
*
*/
- cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
- BKE_constraints_solve(&ob->constraints, cob, ctime);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
BKE_constraints_clear_evalob(cob);
}
-void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* Set negative scale flag in object. */
if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
else ob->transflag &= ~OB_NEG_SCALE;
+
+ if (DEG_is_active(depsgraph)) {
+ Object *ob_orig = DEG_get_original_object(ob);
+ copy_m4_m4(ob_orig->obmat, ob->obmat);
+ copy_m4_m4(ob_orig->constinv, ob->constinv);
+ ob_orig->transflag = ob->transflag;
+ ob_orig->flag = ob->flag;
+ }
}
void BKE_object_handle_data_update(
- Main *bmain,
- EvaluationContext *eval_ctx,
+ Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
@@ -150,40 +162,47 @@ void BKE_object_handle_data_update(
Key *key;
float ctime = BKE_scene_frame_get(scene);
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL)
- printf("recalcdata %s\n", ob->id.name + 2);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* TODO(sergey): Only used by legacy depsgraph. */
if (adt) {
/* evaluate drivers - datalevel */
- /* XXX: for mesh types, should we push this to derivedmesh instead? */
- BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
+ /* XXX: for mesh types, should we push this to evaluated mesh instead? */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
}
/* TODO(sergey): Only used by legacy depsgraph. */
key = BKE_key_from_object(ob);
if (key && key->block.first) {
if (!(ob->shapeflag & OB_SHAPE_LOCK))
- BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
}
/* includes all keys and modifiers */
switch (ob->type) {
case OB_MESH:
{
- BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL;
+#if 0
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
+#else
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_btmesh : NULL;
+ if (em && em->ob != ob) {
+ em = NULL;
+ }
+#endif
+
uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
#ifdef WITH_FREESTYLE
/* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
- if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
+ if (DEG_get_mode(depsgraph) != DAG_EVAL_VIEWPORT) {
data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
}
#endif
if (em) {
- makeDerivedMesh(scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */
+ makeDerivedMesh(depsgraph, scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */
}
else {
- makeDerivedMesh(scene, ob, NULL, data_mask, false);
+ makeDerivedMesh(depsgraph, scene, ob, NULL, data_mask, false);
}
break;
}
@@ -195,75 +214,48 @@ void BKE_object_handle_data_update(
}
}
else {
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob);
}
break;
case OB_MBALL:
- BKE_displist_make_mball(bmain, eval_ctx, scene, ob);
+ BKE_displist_make_mball(depsgraph, scene, ob);
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
- BKE_displist_make_curveTypes(scene, ob, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, ob, false, false);
break;
case OB_LATTICE:
- BKE_lattice_modifiers_calc(scene, ob);
+ BKE_lattice_modifiers_calc(depsgraph, scene, ob);
break;
case OB_EMPTY:
if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
if (BKE_image_is_animated(ob->data))
- BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
+ BKE_image_user_check_frame_calc(ob->iuser, (int)ctime);
break;
}
- /* related materials */
- /* XXX: without depsgraph tagging, this will always need to be run, which will be slow!
- * However, not doing anything (or trying to hack around this lack) is not an option
- * anymore, especially due to Cycles [#31834]
- */
- if (ob->totcol) {
- int a;
- if (ob->totcol != 0) {
- BLI_mutex_lock(&material_lock);
- for (a = 1; a <= ob->totcol; a++) {
- Material *ma = give_current_material(ob, a);
- if (ma) {
- /* recursively update drivers for this material */
- material_drivers_update(scene, ma, ctime);
- }
- }
- BLI_mutex_unlock(&material_lock);
- }
- }
- else if (ob->type == OB_LAMP)
- lamp_drivers_update(scene, ob->data, ctime);
-
/* particles */
- if (ob != scene->obedit && ob->particlesystem.first) {
+ if (!(ob->mode & OB_MODE_EDIT) && ob->particlesystem.first) {
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
ParticleSystem *tpsys, *psys;
- DerivedMesh *dm;
ob->transflag &= ~OB_DUPLIPARTS;
psys = ob->particlesystem.first;
while (psys) {
- /* ensure this update always happens even if psys is disabled */
- if (psys->recalc & PSYS_RECALC_TYPE) {
- psys_changed_type(ob, psys);
- }
-
- if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) {
+ if (psys_check_enabled(ob, psys, use_render_params)) {
/* check use of dupli objects here */
- if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
+ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || use_render_params) &&
((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
(psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
{
ob->transflag |= OB_DUPLIPARTS;
}
- particle_system_update(bmain, scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER));
+ particle_system_update(depsgraph, scene, ob, psys, use_render_params);
psys = psys->next;
}
else if (psys->flag & PSYS_DELETE) {
@@ -275,28 +267,31 @@ void BKE_object_handle_data_update(
else
psys = psys->next;
}
+ }
+ BKE_object_eval_boundbox(depsgraph, ob);
+}
- if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
- /* this is to make sure we get render level duplis in groups:
- * the derivedmesh must be created before init_render_mesh,
- * since object_duplilist does dupliparticles before that */
- CustomDataMask data_mask = CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL;
- dm = mesh_create_derived_render(scene, ob, data_mask);
- dm->release(dm);
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
+void BKE_object_eval_boundbox(Depsgraph *depsgraph, Object *object)
+{
+ if (!DEG_is_active(depsgraph)) {
+ return;
+ }
+ Object *ob_orig = DEG_get_original_object(object);
+ BoundBox *bb = BKE_object_boundbox_get(object);
+ if (bb != NULL) {
+ if (ob_orig->bb == NULL) {
+ ob_orig->bb = MEM_mallocN(sizeof(*ob_orig->bb), __func__);
}
+ *ob_orig->bb = *bb;
}
-
- /* quick cache removed */
}
-bool BKE_object_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx),
+bool BKE_object_eval_proxy_copy(Depsgraph *depsgraph,
Object *object)
{
/* Handle proxy copy for target, */
if (ID_IS_LINKED(object) && object->proxy_from) {
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
if (object->proxy_from->proxy_group) {
/* Transform proxy into group space. */
Object *obg = object->proxy_from->proxy_group;
@@ -316,46 +311,137 @@ bool BKE_object_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx),
return false;
}
-void BKE_object_eval_uber_transform(EvaluationContext *eval_ctx, Object *object)
+void BKE_object_eval_uber_transform(Depsgraph *depsgraph, Object *object)
+{
+ BKE_object_eval_proxy_copy(depsgraph, object);
+}
+
+void BKE_object_batch_cache_dirty_tag(Object *ob)
{
- BKE_object_eval_proxy_copy(eval_ctx, object);
- object->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME);
- if (object->data == NULL) {
- object->recalc &= ~OB_RECALC_DATA;
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ break;
+ case OB_LATTICE:
+ BKE_lattice_batch_cache_dirty_tag(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
+ break;
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ BKE_curve_batch_cache_dirty_tag(ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
+ break;
+ case OB_MBALL:
+ BKE_mball_batch_cache_dirty_tag(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
+ break;
+ case OB_GPENCIL:
+ BKE_gpencil_batch_cache_dirty_tag(ob->data);
+ break;
}
}
-void BKE_object_eval_uber_data(Main *bmain, EvaluationContext *eval_ctx,
+void BKE_object_eval_uber_data(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type != OB_ARMATURE);
- BKE_object_handle_data_update(bmain, eval_ctx, scene, ob);
-
- ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
+ BKE_object_handle_data_update(depsgraph, scene, ob);
+ BKE_object_batch_cache_dirty_tag(ob);
}
-void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx),
- Scene *scene,
- Object *object)
+void BKE_object_eval_ptcache_reset(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *object)
{
- DEG_debug_print_eval(__func__, object->id.name, object);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
}
-void BKE_object_eval_transform_all(EvaluationContext *eval_ctx,
+void BKE_object_eval_transform_all(Depsgraph *depsgraph,
Scene *scene,
Object *object)
{
/* This mimics full transform update chain from new depsgraph. */
- BKE_object_eval_local_transform(eval_ctx, object);
+ BKE_object_eval_local_transform(depsgraph, object);
if (object->parent != NULL) {
- BKE_object_eval_parent(eval_ctx, scene, object);
+ BKE_object_eval_parent(depsgraph, scene, object);
}
if (!BLI_listbase_is_empty(&object->constraints)) {
- BKE_object_eval_constraints(eval_ctx, scene, object);
+ BKE_object_eval_constraints(depsgraph, scene, object);
+ }
+ BKE_object_eval_uber_transform(depsgraph, object);
+ BKE_object_eval_transform_final(depsgraph, object);
+}
+
+void BKE_object_eval_update_shading(Depsgraph *depsgraph, Object *object)
+{
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ if (object->type == OB_MESH) {
+ BKE_mesh_batch_cache_dirty_tag(object->data, BKE_MESH_BATCH_DIRTY_SHADING);
+ }
+}
+
+void BKE_object_data_select_update(Depsgraph *depsgraph, ID *object_data)
+{
+ DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
+ switch (GS(object_data->name)) {
+ case ID_ME:
+ BKE_mesh_batch_cache_dirty_tag(
+ (Mesh *)object_data,
+ BKE_MESH_BATCH_DIRTY_SELECT);
+ break;
+ case ID_CU:
+ BKE_curve_batch_cache_dirty_tag(
+ (Curve *)object_data,
+ BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ case ID_LT:
+ BKE_lattice_batch_cache_dirty_tag(
+ (struct Lattice *)object_data,
+ BKE_LATTICE_BATCH_DIRTY_SELECT);
+ break;
+ default:
+ break;
+ }
+}
+
+void BKE_object_eval_flush_base_flags(Depsgraph *depsgraph,
+ Scene *scene, const int view_layer_index,
+ Object *object, int base_index,
+ const bool is_from_set)
+{
+ /* TODO(sergey): Avoid list lookup. */
+ BLI_assert(view_layer_index >= 0);
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
+ BLI_assert(view_layer != NULL);
+ BLI_assert(view_layer->object_bases_array != NULL);
+ BLI_assert(base_index >= 0);
+ BLI_assert(base_index < MEM_allocN_len(view_layer->object_bases_array) / sizeof(Base *));
+ Base *base = view_layer->object_bases_array[base_index];
+ BLI_assert(base->object == object);
+
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+
+ /* Copy flags and settings from base. */
+ object->base_flag = base->flag;
+ if (is_from_set) {
+ object->base_flag |= BASE_FROM_SET;
+ object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLE);
+ }
+ object->base_local_view_bits = base->local_view_bits;
+
+ /* Copy to original object datablock if needed. */
+ if (DEG_is_active(depsgraph)) {
+ Object *object_orig = DEG_get_original_object(object);
+ object_orig->base_flag = object->base_flag;
+ }
+
+ if (object->mode == OB_MODE_PARTICLE_EDIT) {
+ for (ParticleSystem *psys = object->particlesystem.first;
+ psys != NULL;
+ psys = psys->next)
+ {
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ }
}
- BKE_object_eval_uber_transform(eval_ctx, object);
- BKE_object_eval_done(eval_ctx, object);
}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 7f3f916964a..adbe1a7f889 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
@@ -241,14 +242,6 @@ static void init_complex(fftw_complex cmpl, float real, float image)
cmpl[1] = image;
}
-#if 0 /* unused */
-static void add_complex_f(fftw_complex res, fftw_complex cmpl, float f)
-{
- res[0] = cmpl[0] + f;
- res[1] = cmpl[1];
-}
-#endif
-
static void add_comlex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2)
{
res[0] = cmpl1[0] + cmpl2[0];
@@ -774,15 +767,6 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount
if (o->_do_normals) {
BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH);
BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH);
-
-#if 0
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
- o->_N_y[i * o->_N + j] = 1.0f / scale;
- }
- }
- (MEM01)
-#endif
o->_N_y = 1.0f / scale;
}
@@ -835,6 +819,35 @@ struct Ocean *BKE_ocean_add(void)
return oc;
}
+bool BKE_ocean_ensure(struct OceanModifierData *omd)
+{
+ if (omd->ocean) {
+ return false;
+ }
+
+ omd->ocean = BKE_ocean_add();
+ BKE_ocean_init_from_modifier(omd->ocean, omd);
+ return true;
+}
+
+void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData const *omd)
+{
+ short do_heightfield, do_chop, do_normals, do_jacobian;
+
+ do_heightfield = true;
+ do_chop = (omd->chop_amount > 0);
+ do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
+ do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
+
+ BKE_ocean_free_data(ocean);
+ BKE_ocean_init(ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
+ omd->spatial_size, omd->spatial_size,
+ omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
+ omd->depth, omd->time,
+ do_heightfield, do_chop, do_normals, do_jacobian,
+ omd->seed);
+}
+
void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals,
short do_jacobian, int seed)
@@ -1227,30 +1240,12 @@ void BKE_ocean_simulate_cache(struct OceanCache *och, int frame)
cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_DISPLACE);
och->ibufs_disp[f] = IMB_loadiffname(string, 0, NULL);
-#if 0
- if (och->ibufs_disp[f] == NULL)
- printf("error loading %s\n", string);
- else
- printf("loaded cache %s\n", string);
-#endif
cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_FOAM);
och->ibufs_foam[f] = IMB_loadiffname(string, 0, NULL);
-#if 0
- if (och->ibufs_foam[f] == NULL)
- printf("error loading %s\n", string);
- else
- printf("loaded cache %s\n", string);
-#endif
cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_NORMAL);
och->ibufs_norm[f] = IMB_loadiffname(string, 0, NULL);
-#if 0
- if (och->ibufs_norm[f] == NULL)
- printf("error loading %s\n", string);
- else
- printf("loaded cache %s\n", string);
-#endif
}
@@ -1325,13 +1320,6 @@ void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v
* break up the foam where height (Y) is low (wave valley), and X and Z displacement is greatest
*/
-#if 0
- vec[0] = ocr.disp[0];
- vec[1] = ocr.disp[2];
- hor_stretch = len_v2(vec);
- CLAMP(hor_stretch, 0.0, 1.0);
-#endif
-
neg_disp = ocr.disp[1] < 0.0f ? 1.0f + ocr.disp[1] : 1.0f;
neg_disp = neg_disp < 0.0f ? 0.0f : neg_disp;
@@ -1339,15 +1327,6 @@ void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v
neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2] : 1.0f;
neg_eplus = neg_eplus < 0.0f ? 0.0f : neg_eplus;
-#if 0
- if (ocr.disp[1] < 0.0 || r > och->foam_fade)
- pr *= och->foam_fade;
-
-
- pr = pr * (1.0 - hor_stretch) * ocr.disp[1];
- pr = pr * neg_disp * neg_eplus;
-#endif
-
if (pr < 1.0f)
pr *= pr;
@@ -1511,4 +1490,16 @@ void BKE_ocean_bake(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och),
/* unused */
(void)update_cb;
}
+
+void BKE_ocean_init_from_modifier(struct Ocean *UNUSED(ocean), struct OceanModifierData const *UNUSED(omd))
+{
+}
+
#endif /* WITH_OCEANSIM */
+
+void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd)
+{
+ BKE_ocean_free_cache(omd->oceancache);
+ omd->oceancache = NULL;
+ omd->cached = false;
+}
diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index 9db9b2ddf54..fb62645ef43 100644
--- a/source/blender/blenkernel/intern/outliner_treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -27,6 +27,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -40,6 +41,7 @@
typedef struct TseGroup {
TreeStoreElem **elems;
+ int lastused;
int size;
int allocated;
} TseGroup;
@@ -53,10 +55,11 @@ static TseGroup *tse_group_create(void)
tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems");
tse_group->size = 0;
tse_group->allocated = 1;
+ tse_group->lastused = 0;
return tse_group;
}
-static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
+static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem)
{
if (UNLIKELY(tse_group->size == tse_group->allocated)) {
tse_group->allocated *= 2;
@@ -66,6 +69,26 @@ static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
tse_group->size++;
}
+static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem)
+{
+ int min_allocated = MAX2(1, tse_group->allocated / 2);
+ BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0);
+
+ tse_group->size--;
+ BLI_assert(tse_group->size >= 0);
+ for (int i = 0; i < tse_group->size; i++) {
+ if (tse_group->elems[i] == elem) {
+ memcpy(tse_group->elems[i], tse_group->elems[i + 1], (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *));
+ break;
+ }
+ }
+
+ if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) {
+ tse_group->allocated = min_allocated;
+ tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
+ }
+}
+
static void tse_group_free(TseGroup *tse_group)
{
MEM_freeN(tse_group->elems);
@@ -122,6 +145,16 @@ static void free_treehash_group(void *key)
tse_group_free(key);
}
+void BKE_outliner_treehash_clear_used(void *treehash)
+{
+ GHashIterator gh_iter;
+
+ GHASH_ITER(gh_iter, treehash) {
+ TseGroup *group = BLI_ghashIterator_getValue(&gh_iter);
+ group->lastused = 0;
+ }
+}
+
void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
{
BLI_assert(treehash);
@@ -140,7 +173,22 @@ void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
*val_p = tse_group_create();
}
group = *val_p;
- tse_group_add(group, elem);
+ group->lastused = 0;
+ tse_group_add_element(group, elem);
+}
+
+void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem)
+{
+ TseGroup *group = BLI_ghash_lookup(treehash, elem);
+
+ BLI_assert(group != NULL);
+ if (group->size <= 1) {
+ /* one element -> remove group completely */
+ BLI_ghash_remove(treehash, elem, NULL, free_treehash_group);
+ }
+ else {
+ tse_group_remove_element(group, elem);
+ }
}
static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
@@ -163,10 +211,19 @@ TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, s
group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
if (group) {
- int i;
- for (i = 0; i < group->size; i++) {
- if (!group->elems[i]->used) {
- return group->elems[i];
+ /* Find unused element, with optimization to start from previously
+ * found element assuming we do repeated lookups. */
+ int size = group->size;
+ int offset = group->lastused;
+
+ for (int i = 0; i < size; i++, offset++) {
+ if (offset >= size) {
+ offset = 0;
+ }
+
+ if (!group->elems[offset]->used) {
+ group->lastused = offset;
+ return group->elems[offset];
}
}
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 0637fc4f00c..0446b697c68 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -54,6 +54,7 @@
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
@@ -264,33 +265,6 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
BKE_report(reports, RPT_INFO, "No new files have been packed");
}
-
-#if 0
-
-// attempt to create a function that generates an unique filename
-// this will work when all functions in fileops.c understand relative filenames...
-
-static char *find_new_name(char *name)
-{
- char tempname[FILE_MAX];
- char *newname;
- size_t len;
-
- if (fop_exists(name)) {
- for (number = 1; number <= 999; number++) {
- BLI_snprintf(tempname, sizeof(tempname), "%s.%03d", name, number);
- if (!fop_exists(tempname)) {
- break;
- }
- }
- }
- len = strlen(tempname) + 1;
- newname = MEM_mallocN(len, "find_new_name");
- memcpy(newname, tempname, len * sizeof(char));
- return newname;
-}
-#endif
-
int writePackedFile(
ReportList *reports, const char *ref_file_name, const char *filename, PackedFile *pf, const bool guimode)
{
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index dd5d801d2ac..8b44bbfa15f 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -41,30 +41,46 @@
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "DNA_space_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_bitmap.h"
+#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
#include "BKE_brush.h"
+#include "BKE_ccg.h"
#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_main.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_enum_types.h"
+
#include "bmesh.h"
const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100};
@@ -74,9 +90,9 @@ const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255};
static eOverlayControlFlags overlay_flags = 0;
-void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
+void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, view_layer);
Brush *br = p->brush;
if (!br)
@@ -88,9 +104,9 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
overlay_flags |= PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY;
}
-void BKE_paint_invalidate_cursor_overlay(Scene *scene, CurveMapping *curve)
+void BKE_paint_invalidate_cursor_overlay(Scene *scene, ViewLayer *view_layer, CurveMapping *curve)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, view_layer);
Brush *br = p->brush;
if (br && br->curve == curve)
@@ -146,6 +162,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return &ts->imapaint.paint;
case PAINT_MODE_SCULPT_UV:
return &ts->uvsculpt->paint;
+ case PAINT_MODE_GPENCIL:
+ return &ts->gp_paint->paint;
case PAINT_MODE_INVALID:
return NULL;
default:
@@ -156,13 +174,50 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return NULL;
}
-Paint *BKE_paint_get_active(Scene *sce)
+const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode)
{
- if (sce) {
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ return rna_enum_brush_sculpt_tool_items;
+ case PAINT_MODE_VERTEX:
+ return rna_enum_brush_vertex_tool_items;
+ case PAINT_MODE_WEIGHT:
+ return rna_enum_brush_weight_tool_items;
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
+ return rna_enum_brush_image_tool_items;
+ case PAINT_MODE_SCULPT_UV:
+ return NULL;
+ case PAINT_MODE_GPENCIL:
+ return rna_enum_brush_gpencil_types_items;
+ case PAINT_MODE_INVALID:
+ break;
+ }
+ return NULL;
+}
+
+const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode)
+{
+ switch (mode) {
+ case PAINT_MODE_SCULPT: return "sculpt_tool";
+ case PAINT_MODE_VERTEX: return "vertex_tool";
+ case PAINT_MODE_WEIGHT: return "weight_tool";
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D: return "image_tool";
+ case PAINT_MODE_GPENCIL: return "gpencil_tool";
+ default:
+ /* invalid paint mode */
+ return NULL;
+ }
+}
+
+Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
+{
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
- if (sce->basact && sce->basact->object) {
- switch (sce->basact->object->mode) {
+ if (view_layer->basact && view_layer->basact->object) {
+ switch (view_layer->basact->object->mode) {
case OB_MODE_SCULPT:
return &ts->sculpt->paint;
case OB_MODE_VERTEX_PAINT:
@@ -171,10 +226,14 @@ Paint *BKE_paint_get_active(Scene *sce)
return &ts->wpaint->paint;
case OB_MODE_TEXTURE_PAINT:
return &ts->imapaint.paint;
+ case OB_MODE_GPENCIL_PAINT:
+ return &ts->gp_paint->paint;
case OB_MODE_EDIT:
if (ts->use_uv_sculpt)
return &ts->uvsculpt->paint;
return &ts->imapaint.paint;
+ default:
+ break;
}
}
@@ -188,14 +247,15 @@ Paint *BKE_paint_get_active(Scene *sce)
Paint *BKE_paint_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (view_layer->basact && view_layer->basact->object)
+ obact = view_layer->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -209,7 +269,7 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
}
}
else {
- return BKE_paint_get_active(sce);
+ return BKE_paint_get_active(sce, view_layer);
}
}
@@ -219,14 +279,15 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
ePaintMode BKE_paintmode_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (view_layer->basact && view_layer->basact->object)
+ obact = view_layer->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -266,6 +327,32 @@ ePaintMode BKE_paintmode_get_active_from_context(const bContext *C)
return PAINT_MODE_INVALID;
}
+ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref)
+{
+ if (tref->space_type == SPACE_VIEW3D) {
+ switch (tref->mode) {
+ case CTX_MODE_SCULPT:
+ return PAINT_MODE_SCULPT;
+ case CTX_MODE_PAINT_VERTEX:
+ return PAINT_MODE_VERTEX;
+ case CTX_MODE_PAINT_WEIGHT:
+ return PAINT_MODE_WEIGHT;
+ case CTX_MODE_GPENCIL_PAINT:
+ return PAINT_MODE_GPENCIL;
+ case CTX_MODE_PAINT_TEXTURE:
+ return PAINT_MODE_TEXTURE_3D;
+ }
+ }
+ else if (tref->space_type == SPACE_IMAGE) {
+ switch (tref->mode) {
+ case SI_MODE_PAINT:
+ return PAINT_MODE_TEXTURE_2D;
+ }
+ }
+
+ return PAINT_MODE_INVALID;
+}
+
Brush *BKE_paint_brush(Paint *p)
{
return p ? p->brush : NULL;
@@ -277,7 +364,62 @@ void BKE_paint_brush_set(Paint *p, Brush *br)
id_us_min((ID *)p->brush);
id_us_plus((ID *)br);
p->brush = br;
+
+ BKE_paint_toolslots_brush_update(p);
+ }
+}
+
+void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint)
+{
+ if (paint == &ts->imapaint.paint) {
+ paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool);
+ paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT;
+ }
+ else if (paint == &ts->sculpt->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, sculpt_tool);
+ paint->runtime.ob_mode = OB_MODE_SCULPT;
+ }
+ else if (paint == &ts->vpaint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool);
+ paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT;
+ }
+ else if (paint == &ts->wpaint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool);
+ paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
+ }
+ else if (paint == &ts->gp_paint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, gpencil_tool);
+ paint->runtime.ob_mode = OB_MODE_GPENCIL_PAINT;
+ }
+ else if (paint == &ts->uvsculpt->paint) {
+ /* We don't use these yet. */
+ paint->runtime.tool_offset = 0;
+ paint->runtime.ob_mode = 0;
+ }
+ else {
+ BLI_assert(0);
+ }
+}
+
+uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode)
+{
+ switch (mode) {
+ case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
+ return offsetof(Brush, imagepaint_tool);
+ case PAINT_MODE_SCULPT:
+ return offsetof(Brush, sculpt_tool);
+ case PAINT_MODE_VERTEX:
+ return offsetof(Brush, vertexpaint_tool);
+ case PAINT_MODE_WEIGHT:
+ return offsetof(Brush, weightpaint_tool);
+ case PAINT_MODE_GPENCIL:
+ return offsetof(Brush, gpencil_tool);
+ case PAINT_MODE_SCULPT_UV:
+ case PAINT_MODE_INVALID:
+ break; /* We don't use these yet. */
}
+ return 0;
}
/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */
@@ -332,8 +474,8 @@ void BKE_paint_palette_set(Paint *p, Palette *palette)
{
if (p) {
id_us_min((ID *)p->palette);
- id_us_plus((ID *)palette);
p->palette = palette;
+ id_us_plus((ID *)p->palette);
}
}
@@ -341,8 +483,8 @@ void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
{
if (br) {
id_us_min((ID *)br->paint_curve);
- id_us_plus((ID *)pc);
br->paint_curve = pc;
+ id_us_plus((ID *)br->paint_curve);
}
}
@@ -375,13 +517,7 @@ void BKE_palette_clear(Palette *palette)
Palette *BKE_palette_add(Main *bmain, const char *name)
{
- Palette *palette;
-
- palette = BKE_libblock_alloc(bmain, ID_PAL, name, 0);
-
- /* enable fake user by default */
- id_fake_user_set(&palette->id);
-
+ Palette *palette = BKE_id_new(bmain, ID_PAL, name);
return palette;
}
@@ -410,6 +546,12 @@ void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local)
BKE_id_make_local_generic(bmain, &palette->id, true, lib_local);
}
+void BKE_palette_init(Palette *palette)
+{
+ /* Enable fake user by default. */
+ id_fake_user_set(&palette->id);
+}
+
/** Free (or release) any data used by this palette (does not free the palette itself). */
void BKE_palette_free(Palette *palette)
{
@@ -418,19 +560,17 @@ void BKE_palette_free(Palette *palette)
PaletteColor *BKE_palette_color_add(Palette *palette)
{
- PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color");
+ PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color");
BLI_addtail(&palette->colors, color);
return color;
}
-
bool BKE_palette_is_empty(const struct Palette *palette)
{
return BLI_listbase_is_empty(&palette->colors);
}
-
-/* are we in vertex paint or weight pain face select mode? */
+/* are we in vertex paint or weight paint face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
return ( (ob != NULL) &&
@@ -477,7 +617,7 @@ void BKE_paint_cavity_curve_preset(Paint *p, int preset)
curvemapping_changed(p->cavity_curve, false);
}
-eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode)
+eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
{
switch (mode) {
case PAINT_MODE_SCULPT:
@@ -486,9 +626,8 @@ eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode)
return OB_MODE_VERTEX_PAINT;
case PAINT_MODE_WEIGHT:
return OB_MODE_WEIGHT_PAINT;
- case PAINT_MODE_TEXTURE_3D:
- return OB_MODE_TEXTURE_PAINT;
case PAINT_MODE_TEXTURE_2D:
+ case PAINT_MODE_TEXTURE_3D:
return OB_MODE_TEXTURE_PAINT;
case PAINT_MODE_SCULPT_UV:
return OB_MODE_EDIT;
@@ -498,23 +637,84 @@ eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode)
}
}
+/**
+ * Call when entering each respective paint mode.
+ */
+bool BKE_paint_ensure(const ToolSettings *ts, struct Paint **r_paint)
+{
+ Paint *paint = NULL;
+ if (*r_paint) {
+ /* Note: 'ts->imapaint' is ignored, it's not allocated. */
+ BLI_assert(
+ ELEM(*r_paint,
+ &ts->gp_paint->paint,
+ &ts->sculpt->paint,
+ &ts->vpaint->paint,
+ &ts->wpaint->paint,
+ &ts->uvsculpt->paint));
+
+#ifdef DEBUG
+ struct Paint paint_test = **r_paint;
+ BKE_paint_runtime_init(ts, *r_paint);
+ /* Swap so debug doesn't hide errors when release fails. */
+ SWAP(Paint, **r_paint, paint_test);
+ BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode);
+ BLI_assert(paint_test.runtime.tool_offset == (*r_paint)->runtime.tool_offset);
+#endif
+ return true;
+ }
+
+ if (((VPaint **)r_paint == &ts->vpaint) ||
+ ((VPaint **)r_paint == &ts->wpaint))
+ {
+ VPaint *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
+ else if ((Sculpt **)r_paint == &ts->sculpt) {
+ Sculpt *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+
+ /* Turn on X plane mirror symmetry by default */
+ paint->symmetry_flags |= PAINT_SYMM_X;
+
+ /* Make sure at least dyntopo subdivision is enabled */
+ data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
+ }
+ else if ((GpPaint **)r_paint == &ts->gp_paint) {
+ GpPaint *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
+ else if ((UvSculpt **)r_paint == &ts->uvsculpt) {
+ UvSculpt *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
+
+ paint->flags |= PAINT_SHOW_BRUSH;
+
+ *r_paint = paint;
+
+ BKE_paint_runtime_init(ts, paint);
+
+ return false;
+}
+
void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3])
{
UnifiedPaintSettings *ups = &sce->toolsettings->unified_paint_settings;
- Brush *brush;
Paint *paint = BKE_paint_get_active_from_paintmode(sce, mode);
/* If there's no brush, create one */
- brush = BKE_paint_brush(paint);
- if (brush == NULL) {
- eObjectMode ob_mode = BKE_paint_object_mode_from_paint_mode(mode);
- brush = BKE_brush_first_search(bmain, ob_mode);
-
- if (!brush) {
- brush = BKE_brush_add(bmain, "Brush", ob_mode);
- id_us_min(&brush->id); /* fake user only */
+ if (PAINT_MODE_HAS_BRUSH(mode)) {
+ Brush *brush = BKE_paint_brush(paint);
+ if (brush == NULL) {
+ eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode);
+ brush = BKE_brush_first_search(bmain, ob_mode);
+ if (!brush) {
+ brush = BKE_brush_add(bmain, "Brush", ob_mode);
+ id_us_min(&brush->id); /* fake user only */
+ }
+ BKE_paint_brush_set(paint, brush);
}
- BKE_paint_brush_set(paint, brush);
}
memcpy(paint->paint_cursor_col, col, 3);
@@ -529,6 +729,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3])
void BKE_paint_free(Paint *paint)
{
curvemapping_free(paint->cavity_curve);
+ MEM_SAFE_FREE(paint->tool_slots);
}
/* called when copying scene settings, so even if 'src' and 'tar' are the same
@@ -539,10 +740,16 @@ void BKE_paint_copy(Paint *src, Paint *tar, const int flag)
{
tar->brush = src->brush;
tar->cavity_curve = curvemapping_copy(src->cavity_curve);
+ tar->tool_slots = MEM_dupallocN(src->tool_slots);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus((ID *)tar->brush);
id_us_plus((ID *)tar->palette);
+ if (src->tool_slots != NULL) {
+ for (int i = 0; i < tar->tool_slots_len; i++) {
+ id_us_plus((ID *)tar->tool_slots[i].brush);
+ }
+ }
}
}
@@ -713,8 +920,8 @@ void BKE_sculptsession_bm_to_me(Object *ob, bool reorder)
if (ob && ob->sculpt) {
sculptsession_bm_to_me_update_data_only(ob, reorder);
- /* ensure the objects DerivedMesh mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* ensure the objects evaluated mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
@@ -724,7 +931,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object)
if (object->sculpt->bm) {
/* Ensure no points to old arrays are stored in DM
*
- * Apparently, we could not use DAG_id_tag_update
+ * Apparently, we could not use DEG_id_tag_update
* here because this will lead to the while object
* surface to disappear, so we'll release DM in place.
*/
@@ -749,7 +956,6 @@ void BKE_sculptsession_free(Object *ob)
{
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
- DerivedMesh *dm = ob->derivedFinal;
if (ss->bm) {
BKE_sculptsession_bm_to_me(ob, true);
@@ -758,12 +964,11 @@ void BKE_sculptsession_free(Object *ob)
if (ss->pbvh)
BKE_pbvh_free(ss->pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
if (ss->bm_log)
BM_log_free(ss->bm_log);
- if (dm && dm->getPBVH)
- dm->getPBVH(NULL, dm); /* signal to clear */
-
if (ss->texcache)
MEM_freeN(ss->texcache);
@@ -853,14 +1058,25 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
}
/**
- * \param need_mask So the DerivedMesh thats returned has mask data
+ * \param need_mask So that the evaluated mesh that is returned has mask data.
*/
-void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
- bool need_pmap, bool need_mask)
+void BKE_sculpt_update_mesh_elements(
+ Depsgraph *depsgraph, Scene *scene, Sculpt *sd, Object *ob,
+ bool need_pmap, bool need_mask)
{
- DerivedMesh *dm;
+ /* TODO(sergey): Make sure ob points to an original object. This is what it
+ * is supposed to be pointing to. The issue is, currently draw code takes
+ * care of PBVH creation, even though this is something up to dependency
+ * graph.
+ * Probably, we need to being back logic which was checking for sculpt mode
+ * and (re)create PBVH if needed in that case, similar to how DerivedMesh
+ * was handling this.
+ */
+ ob = DEG_get_original_object(ob);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
@@ -895,13 +1111,13 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, CD_MASK_BAREMESH);
/* VWPaint require mesh info for loop lookup, so require sculpt mode here */
if (mmd && ob->mode & OB_MODE_SCULPT) {
ss->multires = mmd;
- ss->totvert = dm->getNumVerts(dm);
- ss->totpoly = dm->getNumPolys(dm);
+ ss->totvert = me_eval->totvert;
+ ss->totpoly = me_eval->totpoly;
ss->mvert = NULL;
ss->mpoly = NULL;
ss->mloop = NULL;
@@ -916,22 +1132,34 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
}
- ss->pbvh = dm->getPBVH(ob, dm);
- ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL;
+ ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
+
+ PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
+ BLI_assert(pbvh == ss->pbvh);
+ UNUSED_VARS_NDEBUG(pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
+ if (need_pmap && ob->type == OB_MESH) {
+ BKE_mesh_vert_poly_map_create(
+ &ss->pmap, &ss->pmap_mem,
+ me->mpoly, me->mloop,
+ me->totvert, me->totpoly, me->totloop);
+ }
pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color);
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
if (ss->modifiers_active) {
if (!ss->orig_cos) {
+ Object *object_orig = DEG_get_original_object(ob);
int a;
BKE_sculptsession_free_deformMats(ss);
ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL);
- BKE_crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos);
- BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+ BKE_crazyspace_build_sculpt(depsgraph, scene, object_orig, &ss->deform_imats, &ss->deform_cos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos, me->totvert);
for (a = 0; a < me->totvert; ++a) {
invert_m3(ss->deform_imats[a]);
@@ -955,7 +1183,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
if (vertCos) {
if (!pbvh_deformed) {
/* apply shape keys coordinates to PBVH */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, me->totvert);
}
if (ss->deform_cos == NULL) {
ss->deform_cos = vertCos;
@@ -966,6 +1194,9 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
}
}
+
+ /* 2.8x - avoid full mesh update! */
+ BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS);
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
@@ -1041,18 +1272,9 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
{
- Sculpt *sd = scene->toolsettings->sculpt;
- if (sd == NULL) {
- sd = scene->toolsettings->sculpt = MEM_callocN(sizeof(Sculpt), __func__);
-
- /* Turn on X plane mirror symmetry by default */
- sd->paint.symmetry_flags |= PAINT_SYMM_X;
- sd->paint.flags |= PAINT_SHOW_BRUSH;
-
- /* Make sure at least dyntopo subdivision is enabled */
- sd->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
- }
+ BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->sculpt);
+ Sculpt *sd = scene->toolsettings->sculpt;
if (!sd->detail_size) {
sd->detail_size = 12;
}
@@ -1074,3 +1296,123 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
sd->paint.tile_offset[2] = 1.0f;
}
}
+
+static bool check_sculpt_object_deformed(Object *object, const bool for_construction)
+{
+ bool deformed = false;
+
+ /* Active modifiers means extra deformation, which can't be handled correct
+ * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
+ * stuff and show final evaluated mesh so user would see actual object shape.
+ */
+ deformed |= object->sculpt->modifiers_active;
+
+ if (for_construction) {
+ deformed |= object->sculpt->kb != NULL;
+ }
+ else {
+ /* As in case with modifiers, we can't synchronize deformation made against
+ * PBVH and non-locked keyblock, so also use PBVH only for brushes and
+ * final DM to give final result to user.
+ */
+ deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
+ }
+
+ return deformed;
+}
+
+static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
+{
+ PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm,
+ ob->sculpt->bm_smooth_shading,
+ ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset,
+ ob->sculpt->cd_face_node_offset);
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ return pbvh;
+}
+
+static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
+{
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
+ PBVH *pbvh = BKE_pbvh_new();
+
+ MLoopTri *looptri = MEM_malloc_arrayN(
+ looptris_num, sizeof(*looptri), __func__);
+
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly,
+ me->mvert,
+ me->totloop, me->totpoly,
+ looptri);
+
+ BKE_pbvh_build_mesh(
+ pbvh,
+ me->mpoly, me->mloop,
+ me->mvert, me->totvert, &me->vdata,
+ looptri, looptris_num);
+
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+
+ const bool is_deformed = check_sculpt_object_deformed(ob, true);
+ if (is_deformed && me_eval_deform != NULL) {
+ int totvert;
+ float (*v_cos)[3] = BKE_mesh_vertexCos_get(me_eval_deform, &totvert);
+ BKE_pbvh_apply_vertCos(pbvh, v_cos, totvert);
+ MEM_freeN(v_cos);
+ }
+
+ return pbvh;
+}
+
+static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_build_grids(
+ pbvh,
+ subdiv_ccg->grids, subdiv_ccg->num_grids,
+ &key,
+ (void **)subdiv_ccg->grid_faces,
+ subdiv_ccg->grid_flag_mats,
+ subdiv_ccg->grid_hidden);
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ return pbvh;
+}
+
+PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
+{
+ if (ob == NULL || ob->sculpt == NULL) {
+ return NULL;
+ }
+ PBVH *pbvh = ob->sculpt->pbvh;
+ if (pbvh != NULL) {
+ /* Nothing to do, PBVH is already up to date. */
+ return pbvh;
+ }
+
+ if (ob->sculpt->bm != NULL) {
+ /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
+ pbvh = build_pbvh_for_dynamic_topology(ob);
+ }
+ else {
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *mesh_eval = object_eval->data;
+ if (mesh_eval->runtime.subdiv_ccg != NULL) {
+ pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg);
+ }
+ else if (ob->type == OB_MESH) {
+ Mesh *me_eval_deform = mesh_get_eval_deform(
+ depsgraph, DEG_get_evaluated_scene(depsgraph), ob, CD_MASK_BAREMESH);
+ pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
+ }
+ }
+
+ ob->sculpt->pbvh = pbvh;
+ return pbvh;
+}
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
new file mode 100644
index 00000000000..92e42a0a468
--- /dev/null
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -0,0 +1,140 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/paint_toolslots.c
+ * \ingroup bke
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_brush_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_brush.h"
+#include "BKE_paint.h"
+
+void BKE_paint_toolslots_len_ensure(Paint *paint, int len)
+{
+ /* Tool slots are 'uchar'. */
+ BLI_assert(len <= UCHAR_MAX);
+ if (paint->tool_slots_len < len) {
+ paint->tool_slots = MEM_recallocN(paint->tool_slots, sizeof(*paint->tool_slots) * len);
+ paint->tool_slots_len = len;
+ }
+}
+
+static void paint_toolslots_init(Main *bmain, Paint *paint)
+{
+ if (paint == NULL) {
+ return;
+ }
+ const eObjectMode ob_mode = paint->runtime.ob_mode;
+ BLI_assert(paint->runtime.tool_offset && ob_mode);
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode & ob_mode) {
+ const int slot_index = BKE_brush_tool_get(brush, paint);
+ BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
+ if (paint->tool_slots[slot_index].brush == NULL) {
+ paint->tool_slots[slot_index].brush = brush;
+ id_us_plus(&brush->id);
+ }
+ }
+ }
+}
+
+void BKE_paint_toolslots_init_from_main(struct Main *bmain)
+{
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ paint_toolslots_init(bmain, &ts->imapaint.paint);
+ paint_toolslots_init(bmain, &ts->sculpt->paint);
+ paint_toolslots_init(bmain, &ts->vpaint->paint);
+ paint_toolslots_init(bmain, &ts->wpaint->paint);
+ paint_toolslots_init(bmain, &ts->gp_paint->paint);
+ }
+}
+
+
+void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush)
+{
+ const uint tool_offset = paint->runtime.tool_offset;
+ UNUSED_VARS_NDEBUG(tool_offset);
+ BLI_assert(tool_offset != 0);
+ const int slot_index = BKE_brush_tool_get(brush, paint);
+ BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
+ PaintToolSlot *tslot = &paint->tool_slots[slot_index];
+ id_us_plus(&brush->id);
+ id_us_min(&tslot->brush->id);
+ tslot->brush = brush;
+}
+
+void BKE_paint_toolslots_brush_update(Paint *paint)
+{
+ if (paint->brush == NULL) {
+ return;
+ }
+ BKE_paint_toolslots_brush_update_ex(paint, paint->brush);
+}
+
+/**
+ * Run this to ensure brush types are set for each slot on entering modes
+ * (for new scenes for example).
+ */
+void BKE_paint_toolslots_brush_validate(Main *bmain, Paint *paint)
+{
+ /* Clear slots with invalid slots or mode (unlikely but possible). */
+ const uint tool_offset = paint->runtime.tool_offset;
+ UNUSED_VARS_NDEBUG(tool_offset);
+ const eObjectMode ob_mode = paint->runtime.ob_mode;
+ BLI_assert(tool_offset && ob_mode);
+ for (int i = 0; i < paint->tool_slots_len; i++) {
+ PaintToolSlot *tslot = &paint->tool_slots[i];
+ if (tslot->brush) {
+ if ((i != BKE_brush_tool_get(tslot->brush, paint)) ||
+ (tslot->brush->ob_mode & ob_mode) == 0)
+ {
+ id_us_min(&tslot->brush->id);
+ tslot->brush = NULL;
+ }
+ }
+ }
+
+ /* Unlikely but possible the active brush is not currently using a slot. */
+ BKE_paint_toolslots_brush_update(paint);
+
+ /* Fill slots from brushes. */
+ paint_toolslots_init(bmain, paint);
+}
+
+Brush *BKE_paint_toolslots_brush_get(Paint *paint, int slot_index)
+{
+ if (slot_index < paint->tool_slots_len) {
+ PaintToolSlot *tslot = &paint->tool_slots[slot_index];
+ return tslot->brush;
+ }
+ return NULL;
+}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 40c0e1f8184..6ceae2fdc2d 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -36,8 +36,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@@ -51,6 +51,7 @@
#include "BLI_noise.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_kdopbvh.h"
#include "BLI_kdtree.h"
#include "BLI_rand.h"
#include "BLI_task.h"
@@ -64,10 +65,10 @@
#include "BKE_boids.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_effect.h"
#include "BKE_global.h"
-#include "BKE_group.h"
#include "BKE_main.h"
#include "BKE_lattice.h"
@@ -78,14 +79,17 @@
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
-#include "BKE_depsgraph.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_cdderivedmesh.h" /* for weight_to_rgb() */
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_deform.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "RE_render_ext.h"
#include "particle_private.h"
@@ -96,19 +100,19 @@ float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
void psys_init_rng(void)
{
- int i;
- BLI_srandom(5831); /* arbitrary */
- for (i = 0; i < PSYS_FRAND_COUNT; ++i) {
- PSYS_FRAND_BASE[i] = BLI_frand();
- PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rand();
- PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rand();
+ RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */
+ for (int i = 0; i < PSYS_FRAND_COUNT; ++i) {
+ PSYS_FRAND_BASE[i] = BLI_rng_get_float(rng);
+ PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rng_get_int(rng);
+ PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rng_get_int(rng);
}
+ BLI_rng_free(rng);
}
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
-static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
- int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
+static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
+ int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
@@ -228,31 +232,15 @@ void psys_set_current_num(Object *ob, int index)
}
}
-#if 0 /* UNUSED */
-Object *psys_find_object(Scene *scene, ParticleSystem *psys)
-{
- Base *base;
- ParticleSystem *tpsys;
-
- for (base = scene->base.first; base; base = base->next) {
- for (tpsys = base->object->particlesystem.first; psys; psys = psys->next) {
- if (tpsys == psys)
- return base->object;
- }
- }
-
- return NULL;
-}
-#endif
-
struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData *sim)
{
struct LatticeDeformData *lattice_deform_data = NULL;
- if (psys_in_edit_mode(sim->scene, sim->psys) == 0) {
+ if (psys_in_edit_mode(sim->depsgraph, sim->psys) == 0) {
Object *lattice = NULL;
ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys);
- int mode = G.is_rendering ? eModifierMode_Render : eModifierMode_Realtime;
+ bool for_render = DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER;
+ int mode = for_render ? eModifierMode_Render : eModifierMode_Realtime;
for (; md; md = md->next) {
if (md->type == eModifierType_Lattice) {
@@ -285,10 +273,40 @@ void psys_enable_all(Object *ob)
for (; psys; psys = psys->next)
psys->flag &= ~PSYS_DISABLED;
}
-bool psys_in_edit_mode(Scene *scene, ParticleSystem *psys)
+
+ParticleSystem *psys_orig_get(ParticleSystem *psys)
+{
+ if (psys->orig_psys == NULL) {
+ return psys;
+ }
+ return psys->orig_psys;
+}
+
+static PTCacheEdit *psys_orig_edit_get(ParticleSystem *psys)
+{
+ if (psys->orig_psys == NULL) {
+ return psys->edit;
+ }
+ return psys->orig_psys->edit;
+}
+
+bool psys_in_edit_mode(Depsgraph *depsgraph, const ParticleSystem *psys)
{
- return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata);
+ const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ if (view_layer->basact == NULL) {
+ /* TODO(sergey): Needs double-check with multi-object edit. */
+ return false;
+ }
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const Object *object = view_layer->basact->object;
+ if (object->mode != OB_MODE_PARTICLE_EDIT) {
+ return false;
+ }
+ const ParticleSystem *psys_orig = psys_orig_get((ParticleSystem *)psys);
+ return (psys_orig->edit || psys->pointcache->edit) &&
+ (use_render_params == false);
}
+
bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSystemModifierData *psmd;
@@ -297,7 +315,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_
return 0;
psmd = psys_get_modifier(ob, psys);
- if (psys->renderdata || use_render_params) {
+ if (use_render_params) {
if (!(psmd->modifier.mode & eModifierMode_Render))
return 0;
}
@@ -315,68 +333,84 @@ bool psys_check_edited(ParticleSystem *psys)
return (psys->pointcache->edit && psys->pointcache->edit->edited);
}
+void psys_find_group_weights(ParticleSettings *part)
+{
+ /* Find object pointers based on index. If the collection is linked from
+ * another library linking may not have the object pointers available on
+ * file load, so we have to retrieve them later. See T49273. */
+ const ListBase dup_group_objects = BKE_collection_object_cache_get(part->dup_group);
+
+ for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
+ if (dw->ob == NULL) {
+ Base *base = BLI_findlink(&dup_group_objects, dw->index);
+ if (base != NULL) {
+ dw->ob = base->object;
+ }
+ }
+ }
+}
+
void psys_check_group_weights(ParticleSettings *part)
{
ParticleDupliWeight *dw, *tdw;
- GroupObject *go;
- int current = 0;
- if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) {
- /* First try to find NULL objects from their index,
- * and remove all weights that don't have an object in the group. */
- dw = part->dupliweights.first;
- while (dw) {
- if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) {
- go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
- if (go) {
- dw->ob = go->ob;
- }
- else {
- tdw = dw->next;
- BLI_freelinkN(&part->dupliweights, dw);
- dw = tdw;
- }
- }
- else {
- dw = dw->next;
- }
- }
+ if (part->ren_as != PART_DRAW_GR || !part->dup_group) {
+ BLI_freelistN(&part->dupliweights);
+ return;
+ }
- /* then add objects in the group to new list */
- go = part->dup_group->gobject.first;
- while (go) {
- dw = part->dupliweights.first;
- while (dw && dw->ob != go->ob)
- dw = dw->next;
-
- if (!dw) {
- dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
- dw->ob = go->ob;
- dw->count = 1;
- BLI_addtail(&part->dupliweights, dw);
- }
+ /* Find object pointers. */
+ psys_find_group_weights(part);
- go = go->next;
+ /* Remove NULL objects, that were removed from the collection. */
+ dw = part->dupliweights.first;
+ while (dw) {
+ if (dw->ob == NULL || !BKE_collection_has_object_recursive(part->dup_group, dw->ob)) {
+ tdw = dw->next;
+ BLI_freelinkN(&part->dupliweights, dw);
+ dw = tdw;
}
+ else {
+ dw = dw->next;
+ }
+ }
+ /* Add new objects in the collection. */
+ int index = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
+ {
dw = part->dupliweights.first;
- for (; dw; dw = dw->next) {
- if (dw->flag & PART_DUPLIW_CURRENT) {
- current = 1;
- break;
- }
+ while (dw && dw->ob != object) {
+ dw = dw->next;
}
- if (!current) {
- dw = part->dupliweights.first;
- if (dw)
- dw->flag |= PART_DUPLIW_CURRENT;
+ if (!dw) {
+ dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
+ dw->ob = object;
+ dw->count = 1;
+ BLI_addtail(&part->dupliweights, dw);
}
+
+ dw->index = index++;
}
- else {
- BLI_freelistN(&part->dupliweights);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ /* Ensure there is an element marked as current. */
+ int current = 0;
+ for (dw = part->dupliweights.first; dw; dw = dw->next) {
+ if (dw->flag & PART_DUPLIW_CURRENT) {
+ current = 1;
+ break;
+ }
+ }
+
+ if (!current) {
+ dw = part->dupliweights.first;
+ if (dw)
+ dw->flag |= PART_DUPLIW_CURRENT;
}
}
+
int psys_uses_gravity(ParticleSimulationData *sim)
{
return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part && sim->psys->part->effector_weights->global_gravity != 0.0f;
@@ -419,7 +453,7 @@ void BKE_particlesettings_free(ParticleSettings *part)
fluid_free_settings(part->fluid);
}
-void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
+void free_hair(Object *object, ParticleSystem *psys, int dynamics)
{
PARTICLE_P;
@@ -434,26 +468,23 @@ void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
if (psys->clmd) {
if (dynamics) {
- BKE_ptcache_free_list(&psys->ptcaches);
- psys->pointcache = NULL;
-
modifier_free((ModifierData *)psys->clmd);
-
- psys->clmd = NULL;
- psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
+ PTCacheID pid;
+ BKE_ptcache_id_from_particles(&pid, object, psys);
+ BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
}
else {
cloth_free_modifier(psys->clmd);
}
}
- if (psys->hair_in_dm)
- psys->hair_in_dm->release(psys->hair_in_dm);
- psys->hair_in_dm = NULL;
+ if (psys->hair_in_mesh)
+ BKE_id_free(NULL, psys->hair_in_mesh);
+ psys->hair_in_mesh = NULL;
- if (psys->hair_out_dm)
- psys->hair_out_dm->release(psys->hair_out_dm);
- psys->hair_out_dm = NULL;
+ if (psys->hair_out_mesh)
+ BKE_id_free(NULL, psys->hair_out_mesh);
+ psys->hair_out_mesh = NULL;
}
void free_keyed_keys(ParticleSystem *psys)
{
@@ -562,7 +593,21 @@ void psys_free(Object *ob, ParticleSystem *psys)
psys_free_path_cache(psys, NULL);
- free_hair(ob, psys, 1);
+ /* NOTE: We pass dynamics=0 to free_hair() to prevent it from doing an
+ * unneeded clear of the cache. But for historical reason that code path
+ * was only clearing cloth part of modifier data.
+ *
+ * Part of the story there is that particle evaluation is trying to not
+ * re-allocate thew ModifierData itself, and limits all allocations to
+ * the cloth part of it.
+ *
+ * Why evaluation is relying on hair_free() and in some specific code
+ * paths there is beyond me.
+ */
+ free_hair(ob, psys, 0);
+ if (psys->clmd != NULL) {
+ modifier_free((ModifierData *)psys->clmd);
+ }
psys_free_particles(psys);
@@ -590,7 +635,9 @@ void psys_free(Object *ob, ParticleSystem *psys)
psys->part = NULL;
- BKE_ptcache_free_list(&psys->ptcaches);
+ if ((psys->flag & PSYS_SHARED_CACHES) == 0) {
+ BKE_ptcache_free_list(&psys->ptcaches);
+ }
psys->pointcache = NULL;
BLI_freelistN(&psys->targets);
@@ -601,213 +648,62 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (psys->fluid_springs)
MEM_freeN(psys->fluid_springs);
- pdEndEffectors(&psys->effectors);
+ BKE_effectors_free(psys->effectors);
if (psys->pdd) {
psys_free_pdd(psys);
MEM_freeN(psys->pdd);
}
- MEM_freeN(psys);
- }
-}
-
-/************************************************/
-/* Rendering */
-/************************************************/
-/* these functions move away particle data and bring it back after
- * rendering, to make different render settings possible without
- * removing the previous data. this should be solved properly once */
-
-void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset)
-{
- ParticleRenderData *data;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
-
- if (psys->renderdata)
- return;
-
- data = MEM_callocN(sizeof(ParticleRenderData), "ParticleRenderData");
-
- data->child = psys->child;
- data->totchild = psys->totchild;
- data->pathcache = psys->pathcache;
- data->pathcachebufs.first = psys->pathcachebufs.first;
- data->pathcachebufs.last = psys->pathcachebufs.last;
- data->totcached = psys->totcached;
- data->childcache = psys->childcache;
- data->childcachebufs.first = psys->childcachebufs.first;
- data->childcachebufs.last = psys->childcachebufs.last;
- data->totchildcache = psys->totchildcache;
-
- if (psmd->dm_final) {
- data->dm = CDDM_copy_with_tessface(psmd->dm_final);
- }
- data->totdmvert = psmd->totdmvert;
- data->totdmedge = psmd->totdmedge;
- data->totdmface = psmd->totdmface;
-
- psys->child = NULL;
- psys->pathcache = NULL;
- psys->childcache = NULL;
- psys->totchild = psys->totcached = psys->totchildcache = 0;
- BLI_listbase_clear(&psys->pathcachebufs);
- BLI_listbase_clear(&psys->childcachebufs);
-
- copy_m4_m4(data->winmat, winmat);
- mul_m4_m4m4(data->viewmat, viewmat, ob->obmat);
- mul_m4_m4m4(data->mat, winmat, data->viewmat);
- data->winx = winx;
- data->winy = winy;
+ BKE_particle_batch_cache_free(psys);
- data->timeoffset = timeoffset;
-
- psys->renderdata = data;
-
- /* Hair can and has to be recalculated if everything isn't displayed. */
- if (psys->part->disp != 100 && ELEM(psys->part->type, PART_HAIR, PART_FLUID)) {
- psys->recalc |= PSYS_RECALC_RESET;
+ MEM_freeN(psys);
}
}
-void psys_render_restore(Object *ob, ParticleSystem *psys)
+void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src)
{
- ParticleRenderData *data;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- float render_disp = psys_get_current_display_percentage(psys);
- float disp;
-
- data = psys->renderdata;
- if (!data)
- return;
-
- if (data->elems)
- MEM_freeN(data->elems);
-
- if (psmd->dm_final) {
- psmd->dm_final->needsFree = 1;
- psmd->dm_final->release(psmd->dm_final);
- }
- if (psmd->dm_deformed) {
- psmd->dm_deformed->needsFree = 1;
- psmd->dm_deformed->release(psmd->dm_deformed);
- psmd->dm_deformed = NULL;
- }
-
- psys_free_path_cache(psys, NULL);
-
- if (psys->child) {
- MEM_freeN(psys->child);
- psys->child = 0;
- psys->totchild = 0;
- }
-
- psys->child = data->child;
- psys->totchild = data->totchild;
- psys->pathcache = data->pathcache;
- psys->pathcachebufs.first = data->pathcachebufs.first;
- psys->pathcachebufs.last = data->pathcachebufs.last;
- psys->totcached = data->totcached;
- psys->childcache = data->childcache;
- psys->childcachebufs.first = data->childcachebufs.first;
- psys->childcachebufs.last = data->childcachebufs.last;
- psys->totchildcache = data->totchildcache;
-
- psmd->dm_final = data->dm;
- psmd->totdmvert = data->totdmvert;
- psmd->totdmedge = data->totdmedge;
- psmd->totdmface = data->totdmface;
- psmd->flag &= ~eParticleSystemFlag_psys_updated;
-
- if (psmd->dm_final) {
- if (!psmd->dm_final->deformedOnly) {
- if (ob->derivedDeform) {
- psmd->dm_deformed = CDDM_copy(ob->derivedDeform);
- }
- else {
- psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data);
- }
- DM_ensure_tessface(psmd->dm_deformed);
+ /* Free existing particles. */
+ if (psys_dst->particles != psys_src->particles) {
+ psys_free_particles(psys_dst);
+ }
+ if (psys_dst->child != psys_src->child) {
+ psys_free_children(psys_dst);
+ }
+ /* Restore counters. */
+ psys_dst->totpart = psys_src->totpart;
+ psys_dst->totchild = psys_src->totchild;
+ /* Copy particles and children. */
+ psys_dst->particles = MEM_dupallocN(psys_src->particles);
+ psys_dst->child = MEM_dupallocN(psys_src->child);
+ if (psys_dst->part->type == PART_HAIR) {
+ ParticleData *pa;
+ int p;
+ for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
+ pa->hair = MEM_dupallocN(pa->hair);
}
- psys_calc_dmcache(ob, psmd->dm_final, psmd->dm_deformed, psys);
}
-
- MEM_freeN(data);
- psys->renderdata = NULL;
-
- /* restore particle display percentage */
- disp = psys_get_current_display_percentage(psys);
-
- if (disp != render_disp) {
- /* Hair can and has to be recalculated if everything isn't displayed. */
- if (ELEM(psys->part->type, PART_HAIR, PART_FLUID)) {
- psys->recalc |= PSYS_RECALC_RESET;
+ if (psys_dst->particles && (psys_dst->particles->keys || psys_dst->particles->boid)) {
+ ParticleKey *key = psys_dst->particles->keys;
+ BoidParticle *boid = psys_dst->particles->boid;
+ ParticleData *pa;
+ int p;
+ if (key != NULL) {
+ key = MEM_dupallocN(key);
}
- else {
- PARTICLE_P;
-
- LOOP_PARTICLES {
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
- }
+ if (boid != NULL) {
+ boid = MEM_dupallocN(boid);
}
- }
-}
-
-bool psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float *params)
-{
- ParticleRenderData *data;
- ParticleRenderElem *elem;
- float x, w, scale, alpha, lambda, t, scalemin, scalemax;
- int b;
-
- if (!(psys->renderdata && (psys->part->simplify_flag & PART_SIMPLIFY_ENABLE)))
- return false;
-
- data = psys->renderdata;
- if (!data->do_simplify)
- return false;
- b = (data->index_mf_to_mpoly) ? DM_origindex_mface_mpoly(data->index_mf_to_mpoly, data->index_mp_to_orig, cpa->num) : cpa->num;
- if (b == ORIGINDEX_NONE) {
- return false;
- }
-
- elem = &data->elems[b];
-
- lambda = elem->lambda;
- t = elem->t;
- scalemin = elem->scalemin;
- scalemax = elem->scalemax;
-
- if (!elem->reduce) {
- scale = scalemin;
- alpha = 1.0f;
- }
- else {
- x = (elem->curchild + 0.5f) / elem->totchild;
- if (x < lambda - t) {
- scale = scalemax;
- alpha = 1.0f;
- }
- else if (x >= lambda + t) {
- scale = scalemin;
- alpha = 0.0f;
- }
- else {
- w = (lambda + t - x) / (2.0f * t);
- scale = scalemin + (scalemax - scalemin) * w;
- alpha = w;
+ for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
+ if (boid != NULL) {
+ pa->boid = boid++;
+ }
+ if (key != NULL) {
+ pa->keys = key;
+ key += pa->totkey;
+ }
}
}
-
- params[0] = scale;
- params[1] = alpha;
-
- elem->curchild++;
-
- return 1;
}
/************************************************/
@@ -859,7 +755,7 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic
typedef struct ParticleInterpolationData {
HairKey *hkey[2];
- DerivedMesh *dm;
+ Mesh *mesh;
MVert *mvert[2];
int keyed;
@@ -993,8 +889,8 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic
pind->birthtime = key->time;
pind->dietime = (key + pa->totkey - 1)->time;
- if (pind->dm) {
- pind->mvert[0] = CDDM_get_vert(pind->dm, pa->hair_index);
+ if (pind->mesh) {
+ pind->mvert[0] = &pind->mesh->mvert[pa->hair_index];
pind->mvert[1] = pind->mvert[0] + 1;
}
}
@@ -1103,7 +999,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
edit_to_particle(keys + 1, pind->ekey[0]);
edit_to_particle(keys + 2, pind->ekey[1]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
pind->mvert[0] = pind->mvert[1] - 1;
mvert_to_particle(keys + 1, pind->mvert[0], pind->hkey[0]);
mvert_to_particle(keys + 2, pind->mvert[1], pind->hkey[1]);
@@ -1128,7 +1024,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
else
edit_to_particle(keys, pind->ekey[0]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
if (pind->hkey[0] != pa->hair)
mvert_to_particle(keys, pind->mvert[0] - 1, pind->hkey[0] - 1);
else
@@ -1147,7 +1043,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
else
edit_to_particle(keys + 3, pind->ekey[1]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
if (pind->hkey[1] != pa->hair + pa->totkey - 1)
mvert_to_particle(keys + 3, pind->mvert[1] + 1, pind->hkey[1] + 1);
else
@@ -1216,7 +1112,7 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
/* interpolate a location on a face based on face coordinates */
void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*orcodata)[3],
float w[4], float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
float *v1 = 0, *v2 = 0, *v3 = 0, *v4 = 0;
float e1[3], e2[3], s1, s2, t1, t2;
@@ -1314,21 +1210,13 @@ void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*or
o4 = orcodata[mface->v4];
interp_v3_v3v3v3v3(orco, o1, o2, o3, o4, w);
-
- if (ornor)
- normal_quad_v3(ornor, o1, o2, o3, o4);
}
else {
interp_v3_v3v3v3(orco, o1, o2, o3, w);
-
- if (ornor)
- normal_tri_v3(ornor, o1, o2, o3);
}
}
else {
copy_v3_v3(orco, vec);
- if (ornor && nor)
- copy_v3_v3(ornor, nor);
}
}
}
@@ -1381,7 +1269,7 @@ void psys_interpolate_mcol(const MCol *mcol, int quad, const float w[4], MCol *m
}
}
-static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, const float fw[4], const float *values)
+static float psys_interpolate_value_from_verts(Mesh *mesh, short from, int index, const float fw[4], const float *values)
{
if (values == 0 || index == -1)
return 0.0;
@@ -1392,7 +1280,7 @@ static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int
case PART_FROM_FACE:
case PART_FROM_VOLUME:
{
- MFace *mf = dm->getTessFaceData(dm, index, CD_MFACE);
+ MFace *mf = &mesh->mface[index];
return interpolate_particle_value(values[mf->v1], values[mf->v2], values[mf->v3], values[mf->v4], fw, mf->v4);
}
@@ -1442,7 +1330,7 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
* \return the DM tessface index.
*/
int psys_particle_dm_face_lookup(
- DerivedMesh *dm_final, DerivedMesh *dm_deformed,
+ Mesh *mesh_final, Mesh *mesh_original,
int findex_orig, const float fw[4], struct LinkNode **poly_nodes)
{
MFace *mtessface_final;
@@ -1454,36 +1342,36 @@ int psys_particle_dm_face_lookup(
const int *index_mf_to_mpoly = NULL;
const int *index_mp_to_orig = NULL;
- const int totface_final = dm_final->getNumTessFaces(dm_final);
- const int totface_deformed = dm_deformed ? dm_deformed->getNumTessFaces(dm_deformed) : totface_final;
+ const int totface_final = mesh_final->totface;
+ const int totface_deformed = mesh_original ? mesh_original->totface : totface_final;
if (ELEM(0, totface_final, totface_deformed)) {
return DMCACHE_NOTFOUND;
}
- index_mf_to_mpoly = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
- index_mp_to_orig = dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
+ index_mf_to_mpoly = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
+ index_mp_to_orig = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
BLI_assert(index_mf_to_mpoly);
- if (dm_deformed) {
- index_mf_to_mpoly_deformed = dm_deformed->getTessFaceDataArray(dm_deformed, CD_ORIGINDEX);
+ if (mesh_original) {
+ index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX);
}
else {
- BLI_assert(dm_final->deformedOnly);
+ BLI_assert(mesh_final->runtime.deformed_only);
index_mf_to_mpoly_deformed = index_mf_to_mpoly;
}
BLI_assert(index_mf_to_mpoly_deformed);
pindex_orig = index_mf_to_mpoly_deformed[findex_orig];
- if (dm_deformed == NULL) {
- dm_deformed = dm_final;
+ if (mesh_original == NULL) {
+ mesh_original = mesh_final;
}
index_mf_to_mpoly_deformed = NULL;
- mtessface_final = dm_final->getTessFaceArray(dm_final);
- osface_final = dm_final->getTessFaceDataArray(dm_final, CD_ORIGSPACE);
+ mtessface_final = mesh_final->mface;
+ osface_final = CustomData_get_layer(&mesh_final->fdata, CD_ORIGSPACE);
if (osface_final == NULL) {
/* Assume we don't need osface_final data, and we get a direct 1-1 mapping... */
@@ -1496,7 +1384,7 @@ int psys_particle_dm_face_lookup(
return DMCACHE_NOTFOUND;
}
}
- else if (findex_orig >= dm_deformed->getNumTessFaces(dm_deformed)) {
+ else if (findex_orig >= mesh_original->totface) {
return DMCACHE_NOTFOUND; /* index not in the original mesh */
}
@@ -1525,7 +1413,7 @@ int psys_particle_dm_face_lookup(
else { /* if we have no node, try every face */
for (int findex_dst = 0; findex_dst < totface_final; findex_dst++) {
/* If current tessface from 'final' DM and orig tessface (given by index) map to the same orig poly... */
- if (DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
+ if (BKE_mesh_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
faceuv = osface_final[findex_dst].uv;
/* check that this intersects - Its possible this misses :/ -
@@ -1545,22 +1433,22 @@ int psys_particle_dm_face_lookup(
return DMCACHE_NOTFOUND;
}
-static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4])
+static int psys_map_index_on_dm(Mesh *mesh, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4])
{
if (index < 0)
return 0;
- if (dm->deformedOnly || index_dmcache == DMCACHE_ISCHILD) {
+ if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) {
/* for meshes that are either only deformed or for child particles, the
* index and fw do not require any mapping, so we can directly use it */
if (from == PART_FROM_VERT) {
- if (index >= dm->getNumVerts(dm))
+ if (index >= mesh->totvert)
return 0;
*mapindex = index;
}
else { /* FROM_FACE/FROM_VOLUME */
- if (index >= dm->getNumTessFaces(dm))
+ if (index >= mesh->totface)
return 0;
*mapindex = index;
@@ -1572,7 +1460,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
* to their new location, which means a different index, and for faces
* also a new face interpolation weights */
if (from == PART_FROM_VERT) {
- if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > dm->getNumVerts(dm))
+ if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > mesh->totvert)
return 0;
*mapindex = index_dmcache;
@@ -1585,15 +1473,15 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
i = index_dmcache;
- if (i == DMCACHE_NOTFOUND || i >= dm->getNumTessFaces(dm))
+ if (i == DMCACHE_NOTFOUND || i >= mesh->totface)
return 0;
*mapindex = i;
/* modify the original weights to become
* weights for the derived mesh face */
- osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
- mface = dm->getTessFaceData(dm, i, CD_MFACE);
+ osface = CustomData_get_layer(&mesh->fdata, CD_ORIGSPACE);
+ mface = &mesh->mface[i];
if (osface == NULL)
mapfw[0] = mapfw[1] = mapfw[2] = mapfw[3] = 0.0f;
@@ -1606,32 +1494,31 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
}
/* interprets particle data to get a point on a mesh in object space */
-void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_dmcache,
+void psys_particle_on_dm(Mesh *mesh_final, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
float tmpnor[3], mapfw[4];
float (*orcodata)[3];
int mapindex;
- if (!psys_map_index_on_dm(dm_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
+ if (!psys_map_index_on_dm(mesh_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
if (vec) { vec[0] = vec[1] = vec[2] = 0.0; }
if (nor) { nor[0] = nor[1] = 0.0; nor[2] = 1.0; }
if (orco) { orco[0] = orco[1] = orco[2] = 0.0; }
- if (ornor) { ornor[0] = ornor[1] = 0.0; ornor[2] = 1.0; }
if (utan) { utan[0] = utan[1] = utan[2] = 0.0; }
if (vtan) { vtan[0] = vtan[1] = vtan[2] = 0.0; }
return;
}
- orcodata = dm_final->getVertDataArray(dm_final, CD_ORCO);
+ orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO);
if (from == PART_FROM_VERT) {
- dm_final->getVertCo(dm_final, mapindex, vec);
+ copy_v3_v3(vec, mesh_final->mvert[mapindex].co);
if (nor) {
- dm_final->getVertNo(dm_final, mapindex, nor);
+ normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no);
normalize_v3(nor);
}
@@ -1644,11 +1531,6 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
}
}
- if (ornor) {
- dm_final->getVertNo(dm_final, mapindex, ornor);
- normalize_v3(ornor);
- }
-
if (utan && vtan) {
utan[0] = utan[1] = utan[2] = 0.0f;
vtan[0] = vtan[1] = vtan[2] = 0.0f;
@@ -1659,15 +1541,15 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
MTFace *mtface;
MVert *mvert;
- mface = dm_final->getTessFaceData(dm_final, mapindex, CD_MFACE);
- mvert = dm_final->getVertDataArray(dm_final, CD_MVERT);
- mtface = CustomData_get_layer(&dm_final->faceData, CD_MTFACE);
+ mface = &mesh_final->mface[mapindex];
+ mvert = mesh_final->mvert;
+ mtface = mesh_final->mtface;
if (mtface)
mtface += mapindex;
if (from == PART_FROM_VOLUME) {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco, ornor);
+ psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
if (nor)
copy_v3_v3(nor, tmpnor);
@@ -1676,19 +1558,19 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
add_v3_v3(vec, tmpnor);
}
else
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco, ornor);
+ psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
}
}
-float psys_particle_value_from_verts(DerivedMesh *dm, short from, ParticleData *pa, float *values)
+float psys_particle_value_from_verts(Mesh *mesh, short from, ParticleData *pa, float *values)
{
float mapfw[4];
int mapindex;
- if (!psys_map_index_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
+ if (!psys_map_index_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
return 0.0f;
- return psys_interpolate_value_from_verts(dm, from, mapindex, mapfw, values);
+ return psys_interpolate_value_from_verts(mesh, from, mapindex, mapfw, values);
}
ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
@@ -1712,7 +1594,7 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
/* ready for future use */
static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index),
float *UNUSED(fuv), float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
/* TODO */
float zerovec[3] = {0.0f, 0.0f, 0.0f};
@@ -1731,9 +1613,6 @@ static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index),
if (orco) {
copy_v3_v3(orco, zerovec);
}
- if (ornor) {
- copy_v3_v3(ornor, zerovec);
- }
}
/************************************************/
/* Particles on emitter */
@@ -1776,9 +1655,9 @@ CustomDataMask psys_emitter_customdata_mask(ParticleSystem *psys)
void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int index, int index_dmcache,
float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
- if (psmd && psmd->dm_final) {
+ if (psmd && psmd->mesh_final) {
if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) {
if (vec)
copy_v3_v3(vec, fuv);
@@ -1788,10 +1667,10 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
return;
}
/* we cant use the num_dmcache */
- psys_particle_on_dm(psmd->dm_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco, ornor);
+ psys_particle_on_dm(psmd->mesh_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco);
}
else
- psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco, ornor);
+ psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco);
}
/************************************************/
@@ -1813,7 +1692,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
return;
LOOP_PARTICLES {
- psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0, 0);
+ psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0);
mul_m4_v3(sim->ob->obmat, state.co);
mul_mat3_m4_v3(sim->ob->obmat, state.vel);
@@ -1839,7 +1718,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
}
}
-int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
+int do_guides(Depsgraph *depsgraph, ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
{
CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve : NULL;
CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve : NULL;
@@ -1902,7 +1781,7 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i
/* curve taper */
if (cu->taperobj)
- mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
+ mul_v3_fl(vec_to_point, BKE_displist_calc_taper(depsgraph, eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
else { /* curve size*/
if (cu->flag & CU_PATH_RADIUS) {
@@ -1970,7 +1849,7 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK
copy_qt_qt(eff_key.rot, (ca - 1)->rot);
pd_point_from_particle(sim, sim->psys->particles + i, &eff_key, &epoint);
- pdDoEffectors(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
+ BKE_effectors_apply(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
mul_v3_fl(force, effector * powf((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps);
@@ -2004,7 +1883,7 @@ static void offset_child(ChildParticle *cpa, ParticleKey *par, float *par_rot, P
add_v3_v3(child->co, par->co);
}
-float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
+float *psys_cache_vgroup(Mesh *mesh, ParticleSystem *psys, int vgroup)
{
float *vg = 0;
@@ -2013,9 +1892,9 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
}
else if (psys->vgroup[vgroup]) {
- MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ MDeformVert *dvert = mesh->dvert;
if (dvert) {
- int totvert = dm->getNumVerts(dm), i;
+ int totvert = mesh->totvert, i;
vg = MEM_callocN(sizeof(float) * totvert, "vg_cache");
if (psys->vg_neg & (1 << vgroup)) {
for (i = 0; i < totvert; i++)
@@ -2041,7 +1920,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
int from = PART_FROM_FACE;
totparent = (int)(totchild * part->parents * 0.3f);
- if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
+ if (use_render_params && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* hard limit, workaround for it being ignored above */
@@ -2052,10 +1931,10 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
tree = BLI_kdtree_new(totparent);
for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) {
- psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
/* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
- get_cpa_texture(sim->psmd->dm_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+ get_cpa_texture(sim->psmd->mesh_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
if (ptex.exist >= psys_frand(psys, p + 24)) {
BLI_kdtree_insert(tree, p, orco);
@@ -2065,7 +1944,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
BLI_kdtree_balance(tree);
for (; p < totchild; p++, cpa++) {
- psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
cpa->parent = BLI_kdtree_find_nearest(tree, orco, NULL);
}
@@ -2085,10 +1964,10 @@ static bool psys_thread_context_init_path(
psys_thread_context_init(ctx, sim);
/*---start figuring out what is actually wanted---*/
- if (psys_in_edit_mode(scene, psys)) {
+ if (psys_in_edit_mode(sim->depsgraph, psys)) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
- if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if ((use_render_params == 0) && (psys_orig_edit_get(psys) == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
segments = 1 << pset->draw_step;
@@ -2097,14 +1976,14 @@ static bool psys_thread_context_init_path(
if (totchild && part->childtype == PART_CHILD_FACES) {
totparent = (int)(totchild * part->parents * 0.3f);
- if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
+ if (use_render_params && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* part->parents could still be 0 so we can't test with totparent */
between = 1;
}
- if (psys->renderdata || use_render_params)
+ if (use_render_params)
segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
@@ -2130,15 +2009,15 @@ static bool psys_thread_context_init_path(
psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim);
/* cache all relevant vertex groups if they exist */
- ctx->vg_length = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_LENGTH);
- ctx->vg_clump = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_CLUMP);
- ctx->vg_kink = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_KINK);
- ctx->vg_rough1 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH1);
- ctx->vg_rough2 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH2);
- ctx->vg_roughe = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGHE);
- ctx->vg_twist = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_TWIST);
+ ctx->vg_length = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_LENGTH);
+ ctx->vg_clump = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_CLUMP);
+ ctx->vg_kink = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_KINK);
+ ctx->vg_rough1 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH1);
+ ctx->vg_rough2 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH2);
+ ctx->vg_roughe = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGHE);
+ ctx->vg_twist = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_TWIST);
if (psys->part->flag & PART_CHILD_EFFECT)
- ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
+ ctx->vg_effector = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_EFFECTOR);
/* prepare curvemapping tables */
if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) {
@@ -2182,11 +2061,12 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
ParticleSystem *psys = ctx->sim.psys;
ParticleSettings *part = psys->part;
ParticleCacheKey **cache = psys->childcache;
- ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.scene, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache;
+ PTCacheEdit *edit = psys_orig_edit_get(psys);
+ ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.depsgraph, psys) && edit ? edit->pathcache : psys->pathcache;
ParticleCacheKey *child, *key[4];
ParticleTexture ptex;
float *cpa_fuv = 0, *par_rot = 0, rot[4];
- float orco[3], ornor[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
+ float orco[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
float eff_length, eff_vec[3], weight[4];
int k, cpa_num;
short cpa_from;
@@ -2208,7 +2088,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
needupdate = 0;
w = 0;
while (w < 4 && cpa->pa[w] >= 0) {
- if (psys->edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
+ if (edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
needupdate = 1;
break;
}
@@ -2282,20 +2162,20 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
- psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, ornor, 0, 0, orco, 0);
+ psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
mul_m4_v3(ob->obmat, co);
for (w = 0; w < 4; w++)
sub_v3_v3v3(off1[w], co, key[w]->co);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
}
else {
ParticleData *pa = psys->particles + cpa->parent;
float co[3];
if (ctx->editupdate) {
- if (!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
+ if (!(edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
return;
memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
@@ -2320,13 +2200,13 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
: pa->num_dmcache;
/* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
- if (cpa_num > ctx->sim.psmd->dm_final->getNumTessFaces(ctx->sim.psmd->dm_final))
+ if (cpa_num > ctx->sim.psmd->mesh_final->totface)
cpa_num = 0;
cpa_fuv = pa->fuv;
- psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, ornor, 0, 0, orco, 0);
+ psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
}
child_keys->segments = ctx->segments;
@@ -2432,9 +2312,9 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
BLI_listbase_clear(&modifiers);
psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset,
- par_co, NULL, NULL, NULL, par_orco, NULL);
+ par_co, NULL, NULL, NULL, par_orco);
- psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par, par_orco);
+ psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, hairmat, child_keys, par, par_orco);
}
else
zero_v3(par_orco);
@@ -2576,7 +2456,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
ParticleSettings *part = psys->part;
ParticleCacheKey *ca, **cache;
- DerivedMesh *hair_dm = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_dm : NULL;
+ Mesh *hair_mesh = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_mesh : NULL;
ParticleKey result;
@@ -2592,7 +2472,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)((use_render_params) ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
@@ -2603,8 +2483,8 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache) == 0)
return;
- if (psys_in_edit_mode(sim->scene, psys))
- if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if (psys_in_edit_mode(sim->depsgraph, psys))
+ if ((psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
return;
keyed = psys->flag & PSYS_KEYED;
@@ -2621,15 +2501,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) {
if ((psys->part->flag & PART_CHILD_EFFECT) == 0)
- vg_effector = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_EFFECTOR);
+ vg_effector = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_EFFECTOR);
if (!psys->totchild)
- vg_length = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_LENGTH);
+ vg_length = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_LENGTH);
}
/* ensure we have tessfaces to be used for mapping */
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(psmd->dm_final);
+ BKE_mesh_tessface_ensure(psmd->mesh_final);
}
/*---first main loop: create all actual particles' paths---*/
@@ -2638,14 +2518,14 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
if (vg_length)
- pa_length *= psys_particle_value_from_verts(psmd->dm_final, part->from, pa, vg_length);
+ pa_length *= psys_particle_value_from_verts(psmd->mesh_final, part->from, pa, vg_length);
}
pind.keyed = keyed;
pind.cache = baked ? psys->pointcache : NULL;
pind.epoint = NULL;
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
- pind.dm = hair_dm;
+ pind.mesh = hair_mesh;
memset(cache[p], 0, sizeof(*cache[p]) * (segments + 1));
@@ -2655,7 +2535,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
/* hairmat is needed for for non-hair particle too so we get proper rotations */
- psys_mat_hair_to_global(sim->ob, psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, psmd->mesh_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -2687,7 +2567,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
/* dynamic hair is in object space */
/* keyed and baked are already in global space */
- if (hair_dm)
+ if (hair_mesh)
mul_m4_v3(sim->ob->obmat, ca->co);
else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR))
mul_m4_v3(hairmat, ca->co);
@@ -2710,7 +2590,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->part->flag & PART_CHILD_EFFECT) == 0) {
float effector = 1.0f;
if (vg_effector)
- effector *= psys_particle_value_from_verts(psmd->dm_final, psys->part->from, pa, vg_effector);
+ effector *= psys_particle_value_from_verts(psmd->mesh_final, psys->part->from, pa, vg_effector);
sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
length = len_v3(vec);
@@ -2723,7 +2603,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) {
for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
/* ca is safe to cast, since only co and vel are used */
- do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
+ do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
}
/* lattices have to be calculated separately to avoid mixups between effector calculations */
@@ -2771,219 +2651,255 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if (vg_length)
MEM_freeN(vg_length);
}
-void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
-{
- ParticleCacheKey *ca, **cache = edit->pathcache;
- ParticleEditSettings *pset = &scene->toolsettings->particle;
-
- PTCacheEditPoint *point = NULL;
- PTCacheEditKey *ekey = NULL;
-
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleData *pa = psys ? psys->particles : NULL;
-
- ParticleInterpolationData pind;
- ParticleKey result;
- float birthtime = 0.0f, dietime = 0.0f;
- float t, time = 0.0f, keytime = 0.0f /*, frs_sec */;
- float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
- int k, i;
- int segments = 1 << pset->draw_step;
- int totpart = edit->totpoint, recalc_set = 0;
+typedef struct CacheEditrPathsIterData {
+ Object *object;
+ PTCacheEdit *edit;
+ ParticleSystemModifierData *psmd;
+ ParticleData *pa;
+ int segments;
+ bool use_weight;
float sel_col[3];
float nosel_col[3];
+} CacheEditrPathsIterData;
- segments = MAX2(segments, 4);
-
- if (!cache || edit->totpoint != edit->totcached) {
- /* clear out old and create new empty path cache */
- psys_free_path_cache(edit->psys, edit);
- cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
-
- /* set flag for update (child particles check this too) */
- for (i = 0, point = edit->points; i < totpart; i++, point++)
- point->flag |= PEP_EDIT_RECALC;
- recalc_set = 1;
+static void psys_cache_edit_paths_iter(
+ void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ CacheEditrPathsIterData *iter_data = (CacheEditrPathsIterData *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if (edit->totcached && !(point->flag & PEP_EDIT_RECALC)) {
+ return;
+ }
+ if (point->totkey == 0) {
+ return;
}
+ Object *ob = iter_data->object;
+ ParticleSystem *psys = edit->psys;
+ ParticleCacheKey **cache = edit->pathcache;
+ ParticleSystemModifierData *psmd = iter_data->psmd;
+ ParticleData *pa = iter_data->pa ? iter_data->pa + iter : NULL;
+ PTCacheEditKey *ekey = point->keys;
+ const int segments = iter_data->segments;
+ const bool use_weight = iter_data->use_weight;
- /* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */
+ float birthtime = 0.0f, dietime = 0.0f;
+ float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
- const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
+ ParticleInterpolationData pind;
+ pind.keyed = 0;
+ pind.cache = NULL;
+ pind.epoint = point;
+ pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
+ pind.mesh = NULL;
+ /* should init_particle_interpolation set this ? */
if (use_weight) {
- ; /* use weight painting colors now... */
- }
- else {
- sel_col[0] = (float)edit->sel_col[0] / 255.0f;
- sel_col[1] = (float)edit->sel_col[1] / 255.0f;
- sel_col[2] = (float)edit->sel_col[2] / 255.0f;
- nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
- nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
- nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
+ pind.hkey[0] = NULL;
+ /* pa != NULL since the weight brush is only available for hair */
+ pind.hkey[0] = pa->hair;
+ pind.hkey[1] = pa->hair + 1;
}
- /*---first main loop: create all actual particles' paths---*/
- for (i = 0, point = edit->points; i < totpart; i++, pa += pa ? 1 : 0, point++) {
- if (edit->totcached && !(point->flag & PEP_EDIT_RECALC))
- continue;
+ memset(cache[iter], 0, sizeof(*cache[iter]) * (segments + 1));
- if (point->totkey == 0)
- continue;
+ cache[iter]->segments = segments;
- ekey = point->keys;
+ /*--get the first data points--*/
+ init_particle_interpolation(ob, psys, pa, &pind);
- pind.keyed = 0;
- pind.cache = NULL;
- pind.epoint = point;
- pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
- pind.dm = NULL;
+ if (psys) {
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat);
+ copy_v3_v3(rotmat[0], hairmat[2]);
+ copy_v3_v3(rotmat[1], hairmat[1]);
+ copy_v3_v3(rotmat[2], hairmat[0]);
+ }
+ birthtime = pind.birthtime;
+ dietime = pind.dietime;
- /* should init_particle_interpolation set this ? */
- if (use_weight) {
- pind.hkey[0] = NULL;
- /* pa != NULL since the weight brush is only available for hair */
- pind.hkey[0] = pa->hair;
- pind.hkey[1] = pa->hair + 1;
- }
+ if (birthtime >= dietime) {
+ cache[iter]->segments = -1;
+ return;
+ }
+ /*--interpolate actual path from data points--*/
+ ParticleCacheKey *ca;
+ int k;
+ float t, time = 0.0f, keytime = 0.0f;
+ for (k = 0, ca = cache[iter]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
+ t = birthtime + time * (dietime - birthtime);
+ ParticleKey result;
+ result.time = -t;
+ do_particle_interpolation(psys, iter, pa, t, &pind, &result);
+ copy_v3_v3(ca->co, result.co);
+
+ /* non-hair points are already in global space */
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ mul_m4_v3(hairmat, ca->co);
- memset(cache[i], 0, sizeof(*cache[i]) * (segments + 1));
+ if (k) {
+ cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
- cache[i]->segments = segments;
+ if (k == segments)
+ copy_qt_qt(ca->rot, (ca - 1)->rot);
- /*--get the first data points--*/
- init_particle_interpolation(ob, psys, pa, &pind);
+ /* set velocity */
+ sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
- if (psys) {
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
- copy_v3_v3(rotmat[0], hairmat[2]);
- copy_v3_v3(rotmat[1], hairmat[1]);
- copy_v3_v3(rotmat[2], hairmat[0]);
+ if (k == 1)
+ copy_v3_v3((ca - 1)->vel, ca->vel);
+ }
}
-
- birthtime = pind.birthtime;
- dietime = pind.dietime;
-
- if (birthtime >= dietime) {
- cache[i]->segments = -1;
- continue;
+ else {
+ ca->vel[0] = ca->vel[1] = 0.0f;
+ ca->vel[2] = 1.0f;
}
- /*--interpolate actual path from data points--*/
- for (k = 0, ca = cache[i]; k <= segments; k++, ca++) {
- time = (float)k / (float)segments;
- t = birthtime + time * (dietime - birthtime);
- result.time = -t;
- do_particle_interpolation(psys, i, pa, t, &pind, &result);
- copy_v3_v3(ca->co, result.co);
-
- /* non-hair points are already in global space */
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- mul_m4_v3(hairmat, ca->co);
-
- if (k) {
- cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
-
- if (k == segments)
- copy_qt_qt(ca->rot, (ca - 1)->rot);
-
- /* set velocity */
- sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
-
- if (k == 1)
- copy_v3_v3((ca - 1)->vel, ca->vel);
- }
+ /* selection coloring in edit mode */
+ if (use_weight) {
+ if (k == 0) {
+ BKE_defvert_weight_to_rgb(ca->col, pind.hkey[1]->weight);
}
else {
- ca->vel[0] = ca->vel[1] = 0.0f;
- ca->vel[2] = 1.0f;
- }
-
- /* selection coloring in edit mode */
- if (use_weight) {
- if (k == 0) {
- weight_to_rgb(ca->col, pind.hkey[1]->weight);
+ /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
+ float real_t;
+ if (result.time < 0.0f) {
+ real_t = -result.time;
}
else {
- /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
- float real_t;
- if (result.time < 0.0f) {
- real_t = -result.time;
- }
- else {
- real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
- }
+ real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
+ }
- while (pind.hkey[1]->time < real_t) {
- pind.hkey[1]++;
- }
- pind.hkey[0] = pind.hkey[1] - 1;
- /* end copy */
+ while (pind.hkey[1]->time < real_t) {
+ pind.hkey[1]++;
+ }
+ pind.hkey[0] = pind.hkey[1] - 1;
+ /* end copy */
- float w1[3], w2[3];
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ float w1[3], w2[3];
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- weight_to_rgb(w1, pind.hkey[0]->weight);
- weight_to_rgb(w2, pind.hkey[1]->weight);
+ BKE_defvert_weight_to_rgb(w1, pind.hkey[0]->weight);
+ BKE_defvert_weight_to_rgb(w2, pind.hkey[1]->weight);
- interp_v3_v3v3(ca->col, w1, w2, keytime);
+ interp_v3_v3v3(ca->col, w1, w2, keytime);
+ }
+ }
+ else {
+ if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
+ if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
+ copy_v3_v3(ca->col, iter_data->sel_col);
+ }
+ else {
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ interp_v3_v3v3(ca->col, iter_data->sel_col, iter_data->nosel_col, keytime);
}
}
else {
- if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
- if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- copy_v3_v3(ca->col, sel_col);
- }
- else {
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, sel_col, nosel_col, keytime);
- }
+ if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime);
}
else {
- if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, nosel_col, sel_col, keytime);
- }
- else {
- copy_v3_v3(ca->col, nosel_col);
- }
+ copy_v3_v3(ca->col, iter_data->nosel_col);
}
}
-
- ca->time = t;
}
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- /* First rotation is based on emitting face orientation.
- * This is way better than having flipping rotations resulting
- * from using a global axis as a rotation pole (vec_to_quat()).
- * It's not an ideal solution though since it disregards the
- * initial tangent, but taking that in to account will allow
- * the possibility of flipping again. -jahka
- */
- mat3_to_quat_is_ok(cache[i]->rot, rotmat);
+
+ ca->time = t;
+ }
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ /* First rotation is based on emitting face orientation.
+ * This is way better than having flipping rotations resulting
+ * from using a global axis as a rotation pole (vec_to_quat()).
+ * It's not an ideal solution though since it disregards the
+ * initial tangent, but taking that in to account will allow
+ * the possibility of flipping again. -jahka
+ */
+ mat3_to_quat_is_ok(cache[iter]->rot, rotmat);
+ }
+}
+
+void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
+{
+ ParticleCacheKey **cache = edit->pathcache;
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+
+ ParticleSystem *psys = edit->psys;
+
+ ParticleData *pa = psys ? psys->particles : NULL;
+
+ int segments = 1 << pset->draw_step;
+ int totpart = edit->totpoint, recalc_set = 0;
+
+ segments = MAX2(segments, 4);
+
+ if (!cache || edit->totpoint != edit->totcached) {
+ /* Clear out old and create new empty path cache. */
+ psys_free_path_cache(edit->psys, edit);
+ cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
+ /* Set flag for update (child particles check this too). */
+ int i;
+ PTCacheEditPoint *point;
+ for (i = 0, point = edit->points; i < totpart; i++, point++) {
+ point->flag |= PEP_EDIT_RECALC;
}
+ recalc_set = 1;
}
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
+
+ CacheEditrPathsIterData iter_data;
+ iter_data.object = ob;
+ iter_data.edit = edit;
+ iter_data.psmd = edit->psmd_eval;
+ iter_data.pa = pa;
+ iter_data.segments = segments;
+ iter_data.use_weight = use_weight;
+
+ if (use_weight) {
+ ; /* use weight painting colors now... */
+ }
+ else {
+ iter_data.sel_col[0] = (float)edit->sel_col[0] / 255.0f;
+ iter_data.sel_col[1] = (float)edit->sel_col[1] / 255.0f;
+ iter_data.sel_col[2] = (float)edit->sel_col[2] / 255.0f;
+ iter_data.nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
+ iter_data.nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
+ iter_data.nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
+ }
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings);
+
edit->totcached = totpart;
if (psys) {
ParticleSimulationData sim = {0};
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
- sim.psmd = psys_get_modifier(ob, psys);
+ sim.psmd = edit->psmd_eval;
psys_cache_child_paths(&sim, cfra, true, use_render_params);
}
/* clear recalc flag if set here */
if (recalc_set) {
- for (i = 0, point = edit->points; i < totpart; i++, point++)
+ PTCacheEditPoint *point;
+ int i;
+ for (i = 0, point = edit->points; i < totpart; i++, point++) {
point->flag &= ~PEP_EDIT_RECALC;
+ }
}
}
/************************************************/
@@ -3007,22 +2923,6 @@ void psys_get_from_key(ParticleKey *key, float loc[3], float vel[3], float rot[4
if (rot) copy_qt_qt(rot, key->rot);
if (time) *time = key->time;
}
-/*-------changing particle keys from space to another-------*/
-#if 0
-static void key_from_object(Object *ob, ParticleKey *key)
-{
- float q[4];
-
- add_v3_v3(key->vel, key->co);
-
- mul_m4_v3(ob->obmat, key->co);
- mul_m4_v3(ob->obmat, key->vel);
- mat4_to_quat(q, ob->obmat);
-
- sub_v3_v3v3(key->vel, key->vel, key->co);
- mul_qt_qtqt(key->rot, q, key->rot);
-}
-#endif
static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[4][4])
{
@@ -3065,7 +2965,7 @@ static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat
cross_v3_v3v3(mat[0], mat[1], mat[2]);
}
-static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float mat[4][4], int orco)
+static void psys_face_mat(Object *ob, Mesh *mesh, ParticleData *pa, float mat[4][4], int orco)
{
float v[3][3];
MFace *mface;
@@ -3073,72 +2973,72 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m
float (*orcodata)[3];
int i = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num : pa->num_dmcache;
- if (i == -1 || i >= dm->getNumTessFaces(dm)) { unit_m4(mat); return; }
+ if (i == -1 || i >= mesh->totface) { unit_m4(mat); return; }
- mface = dm->getTessFaceData(dm, i, CD_MFACE);
- osface = dm->getTessFaceData(dm, i, CD_ORIGSPACE);
+ mface = &mesh->mface[i];
+ osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE);
- if (orco && (orcodata = dm->getVertDataArray(dm, CD_ORCO))) {
+ if (orco && (orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO))) {
copy_v3_v3(v[0], orcodata[mface->v1]);
copy_v3_v3(v[1], orcodata[mface->v2]);
copy_v3_v3(v[2], orcodata[mface->v3]);
/* ugly hack to use non-transformed orcos, since only those
* give symmetric results for mirroring in particle mode */
- if (DM_get_vert_data_layer(dm, CD_ORIGINDEX))
+ if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
BKE_mesh_orco_verts_transform(ob->data, v, 3, 1);
}
else {
- dm->getVertCo(dm, mface->v1, v[0]);
- dm->getVertCo(dm, mface->v2, v[1]);
- dm->getVertCo(dm, mface->v3, v[2]);
+ copy_v3_v3(v[0], mesh->mvert[mface->v1].co);
+ copy_v3_v3(v[1], mesh->mvert[mface->v2].co);
+ copy_v3_v3(v[2], mesh->mvert[mface->v3].co);
}
triatomat(v[0], v[1], v[2], (osface) ? osface->uv : NULL, mat);
}
-void psys_mat_hair_to_object(Object *UNUSED(ob), DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_object(Object *UNUSED(ob), Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float vec[3];
/* can happen when called from a different object's modifier */
- if (!dm) {
+ if (!mesh) {
unit_m4(hairmat);
return;
}
- psys_face_mat(0, dm, pa, hairmat, 0);
- psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0);
+ psys_face_mat(0, mesh, pa, hairmat, 0);
+ psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0);
copy_v3_v3(hairmat[3], vec);
}
-void psys_mat_hair_to_orco(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_orco(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float vec[3], orco[3];
- psys_face_mat(ob, dm, pa, hairmat, 1);
- psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco, 0);
+ psys_face_mat(ob, mesh, pa, hairmat, 1);
+ psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco);
/* see psys_face_mat for why this function is called */
- if (DM_get_vert_data_layer(dm, CD_ORIGINDEX))
+ if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
copy_v3_v3(hairmat[3], orco);
}
-void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float vec[3])
+void psys_vec_rot_to_face(Mesh *mesh, ParticleData *pa, float vec[3])
{
float mat[4][4];
- psys_face_mat(0, dm, pa, mat, 0);
+ psys_face_mat(0, mesh, pa, mat, 0);
transpose_m4(mat); /* cheap inverse for rotation matrix */
mul_mat3_m4_v3(mat, vec);
}
-void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_global(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float facemat[4][4];
- psys_mat_hair_to_object(ob, dm, from, pa, facemat);
+ psys_mat_hair_to_object(ob, mesh, from, pa, facemat);
mul_m4_m4m4(hairmat, ob->obmat, facemat);
}
@@ -3186,8 +3086,8 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
psys->flag = PSYS_CURRENT;
psys->cfra = BKE_scene_frame_get_from_ctime(scene, CFRA + 1);
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
return md;
}
@@ -3232,8 +3132,11 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
else
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
static void default_particle_settings(ParticleSettings *part)
@@ -3296,7 +3199,7 @@ static void default_particle_settings(ParticleSettings *part)
part->clength = 1.0f;
part->clength_thres = 0.0f;
- part->draw = PART_DRAW_EMITTER;
+ part->draw = 0;
part->draw_line[0] = 0.5;
part->path_start = 0.0f;
part->path_end = 1.0f;
@@ -3308,16 +3211,18 @@ static void default_particle_settings(ParticleSettings *part)
part->color_vec_max = 1.f;
part->draw_col = PART_DRAW_COL_MAT;
- part->simplify_refsize = 1920;
- part->simplify_rate = 1.0f;
- part->simplify_transition = 0.1f;
- part->simplify_viewport = 0.8;
-
if (!part->effector_weights)
part->effector_weights = BKE_add_effector_weights(NULL);
part->omat = 1;
part->use_modifier_stack = false;
+ part->draw_size = 0.1f;
+
+ part->shape_flag = PART_SHAPE_CLOSE_TIP;
+ part->shape = 0.0f;
+ part->rad_root = 1.0f;
+ part->rad_tip = 0.0f;
+ part->rad_scale = 0.01f;
}
@@ -3341,6 +3246,8 @@ void BKE_particlesettings_clump_curve_init(ParticleSettings *part)
cumap->cm[0].curve[1].x = 1.0f;
cumap->cm[0].curve[1].y = 1.0f;
+ curvemapping_initialize(cumap);
+
part->clumpcurve = cumap;
}
@@ -3353,6 +3260,8 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part)
cumap->cm[0].curve[1].x = 1.0f;
cumap->cm[0].curve[1].y = 1.0f;
+ curvemapping_initialize(cumap);
+
part->roughcurve = cumap;
}
@@ -3365,6 +3274,8 @@ void BKE_particlesettings_twist_curve_init(ParticleSettings *part)
cumap->cm[0].curve[1].x = 1.0f;
cumap->cm[0].curve[1].y = 1.0f;
+ curvemapping_initialize(cumap);
+
part->twistcurve = cumap;
}
@@ -3421,25 +3332,25 @@ void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const
/* Textures */
/************************************************/
-static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const float fuv[4],
+static int get_particle_uv(Mesh *mesh, ParticleData *pa, int index, const float fuv[4],
char *name, float *texco, bool from_vert)
{
MFace *mf;
MTFace *tf;
int i;
- tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, name);
+ tf = CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name);
if (tf == NULL)
- tf = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ tf = mesh->mtface;
if (tf == NULL)
return 0;
if (pa) {
i = ELEM(pa->num_dmcache, DMCACHE_NOTFOUND, DMCACHE_ISCHILD) ? pa->num : pa->num_dmcache;
- if ((!from_vert && i >= dm->getNumTessFaces(dm)) ||
- (from_vert && i >= dm->getNumVerts(dm)))
+ if ((!from_vert && i >= mesh->totface) ||
+ (from_vert && i >= mesh->totvert))
{
i = -1;
}
@@ -3455,12 +3366,12 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
}
else {
if (from_vert) {
- mf = dm->getTessFaceDataArray(dm, CD_MFACE);
+ mf = mesh->mface;
/* This finds the first face to contain the emitting vertex,
* this is not ideal, but is mostly fine as UV seams generally
* map to equal-colored parts of a texture */
- for (int j = 0; j < dm->getNumTessFaces(dm); j++, mf++) {
+ for (int j = 0; j < mesh->totface; j++, mf++) {
if (ELEM(i, mf->v1, mf->v2, mf->v3, mf->v4)) {
i = j;
break;
@@ -3468,7 +3379,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
}
}
else {
- mf = dm->getTessFaceData(dm, i, CD_MFACE);
+ mf = &mesh->mface[i];
}
psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
@@ -3503,7 +3414,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
CLAMP(pvalue, -1.0f, 1.0f); \
} (void)0
-static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra)
+static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra)
{
MTex *mtex, **mtexp = part->mtex;
int m;
@@ -3537,7 +3448,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (fw && get_particle_uv(dm, NULL, face_index, fw, mtex->uvname,
+ if (fw && get_particle_uv(mesh, NULL, face_index, fw, mtex->uvname,
texvec, (part->from == PART_FROM_VERT)))
{
break;
@@ -3615,7 +3526,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname,
+ if (get_particle_uv(sim->psmd->mesh_final, pa, 0, pa->fuv, mtex->uvname,
texvec, (part->from == PART_FROM_VERT)))
{
break;
@@ -3623,7 +3534,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
/* no break, failed to get uv's, so let's try orco's */
ATTR_FALLTHROUGH;
case TEXCO_ORCO:
- psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec, 0);
+ psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec);
if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
BKE_mesh_texspace_calc(me);
@@ -3745,28 +3656,28 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
ParticleSystem *psys = ctx->sim.psys;
int i = cpa - psys->child;
- get_cpa_texture(ctx->dm, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+ get_cpa_texture(ctx->mesh, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
if (ptex->exist < psys_frand(psys, i + 24))
return;
if (ctx->vg_length)
- ptex->length *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_length);
+ ptex->length *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_length);
if (ctx->vg_clump)
- ptex->clump *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
+ ptex->clump *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
if (ctx->vg_kink)
- ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
+ ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
if (ctx->vg_rough1)
- ptex->rough1 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
+ ptex->rough1 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
if (ctx->vg_rough2)
- ptex->rough2 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2);
+ ptex->rough2 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2);
if (ctx->vg_roughe)
- ptex->roughe *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
+ ptex->roughe *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
if (ctx->vg_effector)
- ptex->effector *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
+ ptex->effector *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
if (ctx->vg_twist)
- ptex->twist *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
+ ptex->twist *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
}
/* get's hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, const bool vel)
@@ -3819,22 +3730,22 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
/* pind.dm disabled in editmode means we don't get effectors taken into
* account when subdividing for instance */
- pind.dm = psys_in_edit_mode(sim->scene, psys) ? NULL : psys->hair_out_dm;
+ pind.mesh = psys_in_edit_mode(sim->depsgraph, psys) ? NULL : psys->hair_out_mesh; /* XXX Sybren EEK */
init_particle_interpolation(sim->ob, psys, pa, &pind);
do_particle_interpolation(psys, p, pa, t, &pind, state);
- if (pind.dm) {
+ if (pind.mesh) {
mul_m4_v3(sim->ob->obmat, state->co);
mul_mat3_m4_v3(sim->ob->obmat, state->vel);
}
else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) {
if ((pa->flag & PARS_REKEY) == 0) {
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, part->from, pa, hairmat);
mul_m4_v3(hairmat, state->co);
mul_mat3_m4_v3(hairmat, state->vel);
if (sim->psys->effectors && (part->flag & PART_CHILD_GUIDE) == 0) {
- do_guides(sim->psys->part, sim->psys->effectors, state, p, state->time);
+ do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, state, p, state->time);
/* TODO: proper velocity handling */
}
@@ -3885,7 +3796,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
- psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
/* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
//copy_v3_v3(cpa_1st, co);
@@ -3894,9 +3805,9 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
pa = psys->particles + cpa->parent;
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco);
if (part->type == PART_HAIR)
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
else
unit_m4(hairmat);
@@ -3914,10 +3825,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
cpa_num = pa->num;
cpa_fuv = pa->fuv;
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco);
if (part->type == PART_HAIR) {
- psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0);
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
}
else {
copy_v3_v3(orco, cpa->fuv);
@@ -3925,18 +3836,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
}
}
- /* correct child ipo timing */
-#if 0 // XXX old animation system
- if ((part->flag & PART_ABS_TIME) == 0 && part->ipo) {
- calc_ipo(part->ipo, 100.0f * t);
- execute_ipo((ID *)part, part->ipo);
- }
-#endif // XXX old animation system
-
/* get different child parameters from textures & vgroups */
memset(&ctx, 0, sizeof(ParticleThreadContext));
ctx.sim = *sim;
- ctx.dm = psmd->dm_final;
+ ctx.mesh = psmd->mesh_final;
ctx.ma = ma;
/* TODO: assign vertex groups */
get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
@@ -4020,7 +3923,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
float timestep = psys_get_timestep(sim);
/* negative time means "use current time" */
- cfra = state->time > 0 ? state->time : BKE_scene_frame_get(sim->scene);
+ cfra = state->time > 0 ? state->time : DEG_get_ctime(sim->depsgraph);
if (p >= totpart) {
if (!psys->totchild)
@@ -4190,18 +4093,18 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
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);
+ if ((part->childtype == PART_CHILD_FACES) && (psmd->mesh_final != NULL)) {
+ CustomData *mtf_data = &psmd->mesh_final->fdata;
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 && !is_grid) {
- mface = psmd->dm_final->getTessFaceData(psmd->dm_final, cpa->num, CD_MFACE);
+ mface = CustomData_get(&psmd->mesh_final->fdata, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
}
- psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco);
return;
}
else {
@@ -4209,8 +4112,8 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
}
}
- if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL) && !is_grid) {
- CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ if ((part->from == PART_FROM_FACE) && (psmd->mesh_final != NULL) && !is_grid) {
+ CustomData *mtf_data = &psmd->mesh_final->fdata;
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
@@ -4219,20 +4122,20 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
if (num == DMCACHE_NOTFOUND)
num = pa->num;
- if (num >= psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
+ if (num >= psmd->mesh_final->totface) {
/* happens when simplify is enabled
* gives invalid coords but would crash otherwise */
num = DMCACHE_NOTFOUND;
}
if (mtface && !ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
+ mface = CustomData_get(&psmd->mesh_final->fdata, num, CD_MFACE);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
}
}
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco);
}
void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[4][4], float *scale)
@@ -4250,9 +4153,9 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
pa = psys->particles + cpa->pa[0];
if (pa)
- psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0, 0);
+ psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0);
else
- psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0, 0);
+ psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0);
if (psys->part->rotmode == PART_ROT_VEL) {
transpose_m3_m4(nmat, ob->imat);
@@ -4384,9 +4287,10 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
madd_v3_v3fl(center, yvec, bb->offset[1]);
}
-void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
+void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
{
ParticleSimulationData sim = {0};
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -4401,7 +4305,7 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
float hairmat[4][4], imat[4][4];
for (p = 0; p < psys->totpart; p++, pa++) {
- psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
hkey = pa->hair;
@@ -4419,3 +4323,22 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag |= PSYS_EDITED;
}
}
+
+
+
+/* Draw Engine */
+void (*BKE_particle_batch_cache_dirty_tag_cb)(ParticleSystem *psys, int mode) = NULL;
+void (*BKE_particle_batch_cache_free_cb)(ParticleSystem *psys) = NULL;
+
+void BKE_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode)
+{
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_dirty_tag_cb(psys, mode);
+ }
+}
+void BKE_particle_batch_cache_free(ParticleSystem *psys)
+{
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_free_cb(psys);
+ }
+}
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 79c3f247232..0cba5f5a2fc 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -39,40 +39,6 @@
#include "particle_private.h"
-struct Material;
-
-static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3])
-{
- float cross[3], nstrand[3], vnor[3], blend;
-
- if (!((ma->mode & MA_STR_SURFDIFF) || (ma->strand_surfnor > 0.0f)))
- return;
-
- if (ma->mode & MA_STR_SURFDIFF) {
- cross_v3_v3v3(cross, surfnor, nor);
- cross_v3_v3v3(nstrand, nor, cross);
-
- blend = dot_v3v3(nstrand, surfnor);
- CLAMP(blend, 0.0f, 1.0f);
-
- interp_v3_v3v3(vnor, nstrand, surfnor, blend);
- normalize_v3(vnor);
- }
- else {
- copy_v3_v3(vnor, nor);
- }
-
- if (ma->strand_surfnor > 0.0f) {
- if (ma->strand_surfnor > surfdist) {
- blend = (ma->strand_surfnor - surfdist) / ma->strand_surfnor;
- interp_v3_v3v3(vnor, vnor, surfnor, blend);
- normalize_v3(vnor);
- }
- }
-
- copy_v3_v3(nor, vnor);
-}
-
/* ------------------------------------------------------------------------- */
typedef struct ParticlePathIterator {
@@ -320,7 +286,7 @@ static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *k
}
void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *modifiers,
- ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
+ ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], float hairmat[4][4],
ParticleCacheKey *keys, ParticleCacheKey *parent_keys, const float parent_orco[3])
{
struct ParticleSettings *part = ctx->sim.psys->part;
@@ -333,11 +299,8 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
int totkeys, k;
float max_length;
-#if 0 /* TODO for the future: use true particle modifiers that work on the whole curve */
- for (mod = modifiers->first; mod; mod = mod->next) {
- mod->apply(keys, totkeys, parent_keys);
- }
-#else
+ /* TODO for the future: use true particle modifiers that work on the whole curve */
+
(void)modifiers;
(void)mod;
@@ -389,9 +352,6 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
if (k >= 2) {
sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co);
mul_v3_fl((key-1)->vel, 0.5);
-
- if (ma && draw_col_ma)
- get_strand_normal(ma, ornor, cur_length, (key-1)->vel);
}
if (use_length_check && k > 0) {
@@ -413,11 +373,9 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
if (ma && draw_col_ma) {
copy_v3_v3(key->col, &ma->r);
- get_strand_normal(ma, ornor, cur_length, key->vel);
}
}
}
-#endif
}
/* ------------------------------------------------------------------------- */
@@ -820,7 +778,7 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
if (part->flag & PART_CHILD_EFFECT)
/* state is safe to cast, since only co and vel are used */
- guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
+ guided = do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
if (guided == 0) {
float orco_offset[3];
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 8a3b1312590..bbb8a96dd4d 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -50,14 +50,13 @@
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
-static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot);
+#include "DEG_depsgraph_query.h"
static void alloc_child_particles(ParticleSystem *psys, int tot)
{
@@ -80,12 +79,13 @@ static void alloc_child_particles(ParticleSystem *psys, int tot)
}
}
-static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, DerivedMesh *deformdm, ParticleSystem *psys)
+static void distribute_simple_children(Scene *scene, Object *ob, Mesh *final_mesh, Mesh *deform_mesh, ParticleSystem *psys, const bool use_render_params)
{
ChildParticle *cpa = NULL;
int i, p;
- int child_nbr= psys_get_child_number(scene, psys);
- int totpart= psys_get_tot_child(scene, psys);
+ int child_nbr= psys_get_child_number(scene, psys, use_render_params);
+ int totpart= psys_get_tot_child(scene, psys, use_render_params);
+ RNG *rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
alloc_child_particles(psys, totpart);
@@ -97,9 +97,9 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi
/* create even spherical distribution inside unit sphere */
while (length>=1.0f) {
- cpa->fuv[0]=2.0f*BLI_frand()-1.0f;
- cpa->fuv[1]=2.0f*BLI_frand()-1.0f;
- cpa->fuv[2]=2.0f*BLI_frand()-1.0f;
+ cpa->fuv[0]=2.0f*BLI_rng_get_float(rng)-1.0f;
+ cpa->fuv[1]=2.0f*BLI_rng_get_float(rng)-1.0f;
+ cpa->fuv[2]=2.0f*BLI_rng_get_float(rng)-1.0f;
length=len_v3(cpa->fuv);
}
@@ -107,14 +107,16 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi
}
}
/* dmcache must be updated for parent particles if children from faces is used */
- psys_calc_dmcache(ob, finaldm, deformdm, psys);
+ psys_calc_dmcache(ob, final_mesh, deform_mesh, psys);
+
+ BLI_rng_free(rng);
}
-static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
+static void distribute_grid(Mesh *mesh, ParticleSystem *psys)
{
ParticleData *pa=NULL;
float min[3], max[3], delta[3], d;
- MVert *mv, *mvert = dm->getVertDataArray(dm,0);
- int totvert=dm->getNumVerts(dm), from=psys->part->from;
+ MVert *mv, *mvert = mesh->mvert;
+ int totvert=mesh->totvert, from=psys->part->from;
int i, j, k, p, res=psys->part->grid_res, size[3], axis;
/* find bounding box of dm */
@@ -196,8 +198,8 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
int a, a1, a2, a0mul, a1mul, a2mul, totface;
int amax= from==PART_FROM_FACE ? 3 : 1;
- totface=dm->getNumTessFaces(dm);
- mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);
+ totface = mesh->totface;
+ mface = mface_array = mesh->mface;
for (a=0; a<amax; a++) {
if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
@@ -314,19 +316,16 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
static void hammersley_create(float *out, int n, int seed, float amount)
{
RNG *rng;
- double p, t, offs[2];
- int k, kk;
+
+ double offs[2], t;
rng = BLI_rng_new(31415926 + n + seed);
offs[0] = BLI_rng_get_double(rng) + (double)amount;
offs[1] = BLI_rng_get_double(rng) + (double)amount;
BLI_rng_free(rng);
- for (k = 0; k < n; k++) {
- t = 0;
- for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1)
- if (kk & 1) /* kk mod 2 = 1 */
- t += p;
+ for (int k = 0; k < n; k++) {
+ BLI_hammersley_1D(k, &t);
out[2*k + 0] = fmod((double)k/(double)n + offs[0], 1.0);
out[2*k + 1] = fmod(t + offs[1], 1.0);
@@ -434,7 +433,7 @@ static int distribute_binary_search(float *sum, int n, float value)
/* the max number if calls to rng_* funcs within psys_thread_distribute_particle
* be sure to keep up to date if this changes */
-#define PSYS_RND_DIST_SKIP 2
+#define PSYS_RND_DIST_SKIP 3
/* note: this function must be thread safe, for from == PART_FROM_CHILD */
#define ONLY_WORKING_WITH_PA_VERTS 0
@@ -443,7 +442,7 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
ParticleThreadContext *ctx= thread->ctx;
MFace *mface;
- mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE);
+ mface = ctx->mesh->mface;
int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
@@ -452,12 +451,12 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
zero_v4(pa->fuv);
- if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->dm->getNumVerts(ctx->dm)) {
+ if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->mesh->totvert) {
/* This finds the first face to contain the emitting vertex,
* this is not ideal, but is mostly fine as UV seams generally
* map to equal-colored parts of a texture */
- for (int i = 0; i < ctx->dm->getNumTessFaces(ctx->dm); i++, mface++) {
+ for (int i = 0; i < ctx->mesh->totface; i++, mface++) {
if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) {
unsigned int *vert = &mface->v1;
@@ -478,8 +477,8 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
KDTreeNearest ptn[3];
int w, maxw;
- psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
+ psys_particle_on_dm(ctx->mesh,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
+ BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1);
maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
for (w=0; w<maxw; w++) {
@@ -488,13 +487,15 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
}
#endif
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float randu, randv;
int distr= ctx->distr;
int i;
@@ -503,7 +504,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
MFace *mface;
pa->num = i = ctx->index[p];
- mface = dm->getTessFaceData(dm,i,CD_MFACE);
+ mface = &mesh->mface[i];
switch (distr) {
case PART_DISTR_JIT:
@@ -530,13 +531,15 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
}
pa->foffset= 0.0f;
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float *v1, *v2, *v3, *v4, nor[3], co[3];
float cur_d, min_d, randu, randv;
int distr= ctx->distr;
@@ -544,10 +547,10 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
MFace *mface;
- MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
+ MVert *mvert = mesh->mvert;
pa->num = i = ctx->index[p];
- mface = dm->getTessFaceData(dm,i,CD_MFACE);
+ mface = &mesh->mface[i];
switch (distr) {
case PART_DISTR_JIT:
@@ -575,9 +578,9 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
pa->foffset= 0.0f;
/* experimental */
- tot=dm->getNumTessFaces(dm);
+ tot = mesh->totface;
- psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
+ psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0);
normalize_v3(nor);
negate_v3(nor);
@@ -585,7 +588,7 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
min_d=FLT_MAX;
intersect=0;
- for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
+ for (i=0, mface=mesh->mface; i<tot; i++,mface++) {
if (i==pa->num) continue;
v1=mvert[mface->v1].co;
@@ -619,19 +622,22 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
break;
case PART_DISTR_RAND:
- pa->foffset *= BLI_frand();
+ pa->foffset *= BLI_rng_get_float(thread->rng);
+ rng_skip_tot--;
break;
}
}
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot >= 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p) {
ParticleThreadContext *ctx= thread->ctx;
Object *ob= ctx->sim.ob;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float orco1[3], co1[3], nor1[3];
float randu, randv;
int cfrom= ctx->cfrom;
@@ -647,7 +653,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
return;
}
- mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
+ mf = &mesh->mface[ctx->index[p]];
randu= BLI_rng_get_float(thread->rng);
randv= BLI_rng_get_float(thread->rng);
@@ -664,8 +670,8 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
int parent[10];
float pweight[10];
- psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
+ psys_particle_on_dm(mesh,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1);
+ BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1);
maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
maxd=ptn[maxw-1].dist;
@@ -743,16 +749,10 @@ static void exec_distribute_child(TaskPool * __restrict UNUSED(pool), void *task
/* RNG skipping at the beginning */
cpa = psys->child;
for (p = 0; p < task->begin; ++p, ++cpa) {
- if (task->ctx->skip) /* simplification skip */
- BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
-
BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
}
for (; p < task->end; ++p, ++cpa) {
- if (task->ctx->skip) /* simplification skip */
- BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
-
distribute_children_exec(task, cpa, p);
}
}
@@ -779,11 +779,15 @@ static int distribute_compare_orig_index(const void *p1, const void *p2, void *u
return 1;
}
-static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
+static void distribute_invalid(ParticleSimulationData *sim, int from)
{
+ Scene *scene = sim->scene;
+ ParticleSystem *psys = sim->psys;
+ const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
+
if (from == PART_FROM_CHILD) {
ChildParticle *cpa;
- int p, totchild = psys_get_tot_child(scene, psys);
+ int p, totchild = psys_get_tot_child(scene, psys, use_render_params);
if (psys->child && totchild) {
for (p=0,cpa=psys->child; p<totchild; p++,cpa++) {
@@ -805,19 +809,18 @@ static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
}
}
-/* Creates a distribution of coordinates on a DerivedMesh */
-/* This is to denote functionality that does not yet work with mesh - only derived mesh */
+/* Creates a distribution of coordinates on a Mesh */
static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, ParticleSimulationData *sim, int from)
{
Scene *scene = sim->scene;
- DerivedMesh *finaldm = sim->psmd->dm_final;
+ Mesh *final_mesh = sim->psmd->mesh_final;
Object *ob = sim->ob;
ParticleSystem *psys= sim->psys;
ParticleData *pa=0, *tpars= 0;
ParticleSettings *part;
ParticleSeam *seams= 0;
KDTree *tree=0;
- DerivedMesh *dm= NULL;
+ Mesh *mesh = NULL;
float *jit= NULL;
int i, p=0;
int cfrom=0;
@@ -825,6 +828,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
int jitlevel= 1, distr;
float *element_weight=NULL,*jitter_offset=NULL, *vweight=NULL;
float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3];
+ RNG *rng = NULL;
if (ELEM(NULL, ob, psys, psys->part))
return 0;
@@ -834,7 +838,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
if (totpart==0)
return 0;
- if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) {
+ if (!final_mesh->runtime.deformed_only && !CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) {
printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
// XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
return 0;
@@ -847,32 +851,37 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
psys_thread_context_init(ctx, sim);
+ const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
+
/* First handle special cases */
if (from == PART_FROM_CHILD) {
/* Simple children */
if (part->childtype != PART_CHILD_FACES) {
- BLI_srandom(31415926 + psys->seed + psys->child_seed);
- distribute_simple_children(scene, ob, finaldm, sim->psmd->dm_deformed, psys);
+ distribute_simple_children(scene, ob, final_mesh, sim->psmd->mesh_original, psys, use_render_params);
return 0;
}
}
else {
/* Grid distribution */
if (part->distr==PART_DISTR_GRID && from != PART_FROM_VERT) {
- BLI_srandom(31415926 + psys->seed);
-
if (psys->part->use_modifier_stack) {
- dm = finaldm;
+ mesh = final_mesh;
}
else {
- dm = CDDM_from_mesh((Mesh*)ob->data);
+ BKE_id_copy_ex(
+ NULL, ob->data, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
}
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
- distribute_grid(dm,psys);
+ distribute_grid(mesh,psys);
- if (dm != finaldm) {
- dm->release(dm);
+ if (mesh != final_mesh) {
+ BKE_id_free(NULL, mesh);
}
return 0;
@@ -881,54 +890,61 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* Create trees and original coordinates if needed */
if (from == PART_FROM_CHILD) {
- distr=PART_DISTR_RAND;
- BLI_srandom(31415926 + psys->seed + psys->child_seed);
- dm= finaldm;
+ distr = PART_DISTR_RAND;
+ rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
+ mesh= final_mesh;
/* BMESH ONLY */
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
children=1;
tree=BLI_kdtree_new(totpart);
for (p=0,pa=psys->particles; p<totpart; p++,pa++) {
- psys_particle_on_dm(dm,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco,NULL);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco, 1, 1);
+ psys_particle_on_dm(mesh,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco);
+ BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
BLI_kdtree_insert(tree, p, orco);
}
BLI_kdtree_balance(tree);
- totpart = psys_get_tot_child(scene, psys);
+ totpart = psys_get_tot_child(scene, psys, use_render_params);
cfrom = from = PART_FROM_FACE;
}
else {
distr = part->distr;
- BLI_srandom(31415926 + psys->seed);
+
+ rng = BLI_rng_new_srandom(31415926 + psys->seed);
if (psys->part->use_modifier_stack)
- dm = finaldm;
+ mesh = final_mesh;
else
- dm= CDDM_from_mesh((Mesh*)ob->data);
+ BKE_id_copy_ex(
+ NULL, ob->data, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
/* we need orco for consistent distributions */
- if (!CustomData_has_layer(&dm->vertData, CD_ORCO))
- DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob));
+ if (!CustomData_has_layer(&mesh->vdata, CD_ORCO))
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
if (from == PART_FROM_VERT) {
- MVert *mv= dm->getVertDataArray(dm, CD_MVERT);
- float (*orcodata)[3] = dm->getVertDataArray(dm, CD_ORCO);
- int totvert = dm->getNumVerts(dm);
+ MVert *mv = mesh->mvert;
+ float (*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
+ int totvert = mesh->totvert;
tree=BLI_kdtree_new(totvert);
for (p=0; p<totvert; p++) {
if (orcodata) {
copy_v3_v3(co,orcodata[p]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co, 1, 1);
}
else
copy_v3_v3(co,mv[p].co);
@@ -940,17 +956,18 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
/* Get total number of emission elements and allocate needed arrays */
- totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm);
+ totelem = (from == PART_FROM_VERT) ? mesh->totvert : mesh->totface;
if (totelem == 0) {
- distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0);
+ distribute_invalid(sim, children ? PART_FROM_CHILD : 0);
if (G.debug & G_DEBUG)
fprintf(stderr,"Particle distribution error: Nothing to emit from!\n");
- if (dm != finaldm) dm->release(dm);
+ if (mesh != final_mesh) BKE_id_free(NULL, mesh);
BLI_kdtree_free(tree);
+ BLI_rng_free(rng);
return 0;
}
@@ -960,37 +977,37 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
jitter_offset = MEM_callocN(sizeof(float) * totelem, "particle_distribution_jitoff");
/* Calculate weights from face areas */
- if ((part->flag&PART_EDISTR || children) && from != PART_FROM_VERT) {
+ if ((part->flag & PART_EDISTR || children) && from != PART_FROM_VERT) {
MVert *v1, *v2, *v3, *v4;
float totarea=0.f, co1[3], co2[3], co3[3], co4[3];
float (*orcodata)[3];
- orcodata= dm->getVertDataArray(dm, CD_ORCO);
+ orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
for (i=0; i<totelem; i++) {
- MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+ MFace *mf = &mesh->mface[i];
if (orcodata) {
copy_v3_v3(co1, orcodata[mf->v1]);
copy_v3_v3(co2, orcodata[mf->v2]);
copy_v3_v3(co3, orcodata[mf->v3]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co1, 1, 1);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co2, 1, 1);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co3, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co1, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co2, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co3, 1, 1);
if (mf->v4) {
copy_v3_v3(co4, orcodata[mf->v4]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co4, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co4, 1, 1);
}
}
else {
- v1= (MVert*)dm->getVertData(dm,mf->v1,CD_MVERT);
- v2= (MVert*)dm->getVertData(dm,mf->v2,CD_MVERT);
- v3= (MVert*)dm->getVertData(dm,mf->v3,CD_MVERT);
+ v1 = &mesh->mvert[mf->v1];
+ v2 = &mesh->mvert[mf->v2];
+ v3 = &mesh->mvert[mf->v3];
copy_v3_v3(co1, v1->co);
copy_v3_v3(co2, v2->co);
copy_v3_v3(co3, v3->co);
if (mf->v4) {
- v4= (MVert*)dm->getVertData(dm,mf->v4,CD_MVERT);
+ v4 = &mesh->mvert[mf->v4];
copy_v3_v3(co4, v4->co);
}
}
@@ -1017,7 +1034,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
/* Calculate weights from vgroup */
- vweight = psys_cache_vgroup(dm,psys,PSYS_VG_DENSITY);
+ vweight = psys_cache_vgroup(mesh,psys,PSYS_VG_DENSITY);
if (vweight) {
if (from==PART_FROM_VERT) {
@@ -1026,7 +1043,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
else { /* PART_FROM_FACE / PART_FROM_VOLUME */
for (i=0;i<totelem; i++) {
- MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+ MFace *mf = &mesh->mface[i];
tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
if (mf->v4) {
@@ -1087,11 +1104,11 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
totmapped = i_mapped;
/* Finally assign elements to particles */
- if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) {
+ if (part->flag & PART_TRAND) {
for (p = 0; p < totpart; p++) {
/* In theory element_sum[totmapped - 1] should be 1.0,
* but due to float errors this is not necessarily always true, so scale pos accordingly. */
- const float pos = BLI_frand() * element_sum[totmapped - 1];
+ const float pos = BLI_rng_get_float(rng) * element_sum[totmapped - 1];
const int eidx = distribute_binary_search(element_sum, totmapped, pos);
particle_element[p] = element_map[eidx];
BLI_assert(pos <= element_sum[eidx]);
@@ -1129,12 +1146,12 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
int *orig_index = NULL;
if (from == PART_FROM_VERT) {
- if (dm->numVertData)
- orig_index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ if (mesh->totvert)
+ orig_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
}
else {
- if (dm->numTessFaceData)
- orig_index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ if (mesh->totface)
+ orig_index = CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX);
}
if (orig_index) {
@@ -1177,14 +1194,15 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
ctx->maxweight= maxweight;
ctx->cfrom= cfrom;
ctx->distr= distr;
- ctx->dm= dm;
+ ctx->mesh= mesh;
ctx->tpars= tpars;
if (children) {
- totpart= psys_render_simplify_distribution(ctx, totpart);
alloc_child_particles(psys, totpart);
}
+ BLI_rng_free(rng);
+
return 1;
}
@@ -1202,7 +1220,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
TaskPool *task_pool;
ParticleThreadContext ctx;
ParticleTask *tasks;
- DerivedMesh *finaldm = sim->psmd->dm_final;
+ Mesh *final_mesh = sim->psmd->mesh_final;
int i, totpart, numtasks;
/* create a task pool for distribution tasks */
@@ -1227,10 +1245,10 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
BLI_task_pool_free(task_pool);
- psys_calc_dmcache(sim->ob, finaldm, sim->psmd->dm_deformed, sim->psys);
+ psys_calc_dmcache(sim->ob, final_mesh, sim->psmd->mesh_original, sim->psys);
- if (ctx.dm != finaldm)
- ctx.dm->release(ctx.dm);
+ if (ctx.mesh != final_mesh)
+ BKE_id_free(NULL, ctx.mesh);
psys_tasks_free(tasks, numtasks);
@@ -1240,7 +1258,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
/* ready for future use, to emit particles without geometry */
static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from))
{
- distribute_invalid(sim->scene, sim->psys, 0);
+ distribute_invalid(sim, 0);
fprintf(stderr,"Shape emission not yet possible!\n");
}
@@ -1251,7 +1269,7 @@ void distribute_particles(ParticleSimulationData *sim, int from)
int distr_error=0;
if (psmd) {
- if (psmd->dm_final)
+ if (psmd->mesh_final)
distribute_particles_on_dm(sim, from);
else
distr_error=1;
@@ -1260,250 +1278,8 @@ void distribute_particles(ParticleSimulationData *sim, int from)
distribute_particles_on_shape(sim, from);
if (distr_error) {
- distribute_invalid(sim->scene, sim->psys, from);
+ distribute_invalid(sim, from);
fprintf(stderr,"Particle distribution error!\n");
}
}
-
-/* ======== Simplify ======== */
-
-static float psys_render_viewport_falloff(double rate, float dist, float width)
-{
- return pow(rate, dist / width);
-}
-
-static float psys_render_projected_area(ParticleSystem *psys, const float center[3], float area, double vprate, float *viewport)
-{
- ParticleRenderData *data = psys->renderdata;
- float co[4], view[3], ortho1[3], ortho2[3], w, dx, dy, radius;
-
- /* transform to view space */
- copy_v3_v3(co, center);
- co[3] = 1.0f;
- mul_m4_v4(data->viewmat, co);
-
- /* compute two vectors orthogonal to view vector */
- normalize_v3_v3(view, co);
- ortho_basis_v3v3_v3(ortho1, ortho2, view);
-
- /* compute on screen minification */
- w = co[2] * data->winmat[2][3] + data->winmat[3][3];
- dx = data->winx * ortho2[0] * data->winmat[0][0];
- dy = data->winy * ortho2[1] * data->winmat[1][1];
- w = sqrtf(dx * dx + dy * dy) / w;
-
- /* w squared because we are working with area */
- area = area * w * w;
-
- /* viewport of the screen test */
-
- /* project point on screen */
- mul_m4_v4(data->winmat, co);
- if (co[3] != 0.0f) {
- co[0] = 0.5f * data->winx * (1.0f + co[0] / co[3]);
- co[1] = 0.5f * data->winy * (1.0f + co[1] / co[3]);
- }
-
- /* screen space radius */
- radius = sqrtf(area / (float)M_PI);
-
- /* make smaller using fallof once over screen edge */
- *viewport = 1.0f;
-
- if (co[0] + radius < 0.0f)
- *viewport *= psys_render_viewport_falloff(vprate, -(co[0] + radius), data->winx);
- else if (co[0] - radius > data->winx)
- *viewport *= psys_render_viewport_falloff(vprate, (co[0] - radius) - data->winx, data->winx);
-
- if (co[1] + radius < 0.0f)
- *viewport *= psys_render_viewport_falloff(vprate, -(co[1] + radius), data->winy);
- else if (co[1] - radius > data->winy)
- *viewport *= psys_render_viewport_falloff(vprate, (co[1] - radius) - data->winy, data->winy);
-
- return area;
-}
-
-/* BMESH_TODO, for orig face data, we need to use MPoly */
-static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
-{
- DerivedMesh *dm = ctx->dm;
- Mesh *me = (Mesh *)(ctx->sim.ob->data);
- MFace *mf, *mface;
- MVert *mvert;
- ParticleRenderData *data;
- ParticleRenderElem *elems, *elem;
- ParticleSettings *part = ctx->sim.psys->part;
- float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp;
- float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport;
- double vprate;
- int *facetotvert;
- int a, b, totorigface, totface, newtot, skipped;
-
- /* double lookup */
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
-
- if (part->ren_as != PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
- return tot;
- if (!ctx->sim.psys->renderdata)
- return tot;
-
- data = ctx->sim.psys->renderdata;
- if (data->timeoffset)
- return 0;
- if (!(part->simplify_flag & PART_SIMPLIFY_ENABLE))
- return tot;
-
- mvert = dm->getVertArray(dm);
- mface = dm->getTessFaceArray(dm);
- totface = dm->getNumTessFaces(dm);
- totorigface = me->totpoly;
-
- if (totface == 0 || totorigface == 0)
- return tot;
-
- index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
-
- facearea = MEM_callocN(sizeof(float) * totorigface, "SimplifyFaceArea");
- facecenter = MEM_callocN(sizeof(float[3]) * totorigface, "SimplifyFaceCenter");
- facetotvert = MEM_callocN(sizeof(int) * totorigface, "SimplifyFaceArea");
- elems = MEM_callocN(sizeof(ParticleRenderElem) * totorigface, "SimplifyFaceElem");
-
- if (data->elems)
- MEM_freeN(data->elems);
-
- data->do_simplify = true;
- data->elems = elems;
- data->index_mf_to_mpoly = index_mf_to_mpoly;
- data->index_mp_to_orig = index_mp_to_orig;
-
- /* compute number of children per original face */
- for (a = 0; a < tot; a++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
- if (b != ORIGINDEX_NONE) {
- elems[b].totchild++;
- }
- }
-
- /* compute areas and centers of original faces */
- for (mf = mface, a = 0; a < totface; a++, mf++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
-
- if (b != ORIGINDEX_NONE) {
- copy_v3_v3(co1, mvert[mf->v1].co);
- copy_v3_v3(co2, mvert[mf->v2].co);
- copy_v3_v3(co3, mvert[mf->v3].co);
-
- add_v3_v3(facecenter[b], co1);
- add_v3_v3(facecenter[b], co2);
- add_v3_v3(facecenter[b], co3);
-
- if (mf->v4) {
- copy_v3_v3(co4, mvert[mf->v4].co);
- add_v3_v3(facecenter[b], co4);
- facearea[b] += area_quad_v3(co1, co2, co3, co4);
- facetotvert[b] += 4;
- }
- else {
- facearea[b] += area_tri_v3(co1, co2, co3);
- facetotvert[b] += 3;
- }
- }
- }
-
- for (a = 0; a < totorigface; a++)
- if (facetotvert[a] > 0)
- mul_v3_fl(facecenter[a], 1.0f / facetotvert[a]);
-
- /* for conversion from BU area / pixel area to reference screen size */
- BKE_mesh_texspace_get(me, 0, 0, size);
- fac = ((size[0] + size[1] + size[2]) / 3.0f) / part->simplify_refsize;
- fac = fac * fac;
-
- powrate = log(0.5f) / log(part->simplify_rate * 0.5f);
- if (part->simplify_flag & PART_SIMPLIFY_VIEWPORT)
- vprate = pow(1.0f - part->simplify_viewport, 5.0);
- else
- vprate = 1.0;
-
- /* set simplification parameters per original face */
- for (a = 0, elem = elems; a < totorigface; a++, elem++) {
- area = psys_render_projected_area(ctx->sim.psys, facecenter[a], facearea[a], vprate, &viewport);
- arearatio = fac * area / facearea[a];
-
- if ((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) {
- /* lambda is percentage of elements to keep */
- lambda = (arearatio < 1.0f) ? powf(arearatio, powrate) : 1.0f;
- lambda *= viewport;
-
- lambda = MAX2(lambda, 1.0f / elem->totchild);
-
- /* compute transition region */
- t = part->simplify_transition;
- elem->t = (lambda - t < 0.0f) ? lambda : (lambda + t > 1.0f) ? 1.0f - lambda : t;
- elem->reduce = 1;
-
- /* scale at end and beginning of the transition region */
- elem->scalemax = (lambda + t < 1.0f) ? 1.0f / lambda : 1.0f / (1.0f - elem->t * elem->t / t);
- elem->scalemin = (lambda + t < 1.0f) ? 0.0f : elem->scalemax * (1.0f - elem->t / t);
-
- elem->scalemin = sqrtf(elem->scalemin);
- elem->scalemax = sqrtf(elem->scalemax);
-
- /* clamp scaling */
- scaleclamp = (float)min_ii(elem->totchild, 10);
- elem->scalemin = MIN2(scaleclamp, elem->scalemin);
- elem->scalemax = MIN2(scaleclamp, elem->scalemax);
-
- /* extend lambda to include transition */
- lambda = lambda + elem->t;
- if (lambda > 1.0f)
- lambda = 1.0f;
- }
- else {
- lambda = arearatio;
-
- elem->scalemax = 1.0f; //sqrt(lambda);
- elem->scalemin = 1.0f; //sqrt(lambda);
- elem->reduce = 0;
- }
-
- elem->lambda = lambda;
- elem->scalemin = sqrtf(elem->scalemin);
- elem->scalemax = sqrtf(elem->scalemax);
- elem->curchild = 0;
- }
-
- MEM_freeN(facearea);
- MEM_freeN(facecenter);
- MEM_freeN(facetotvert);
-
- /* move indices and set random number skipping */
- ctx->skip = MEM_callocN(sizeof(int) * tot, "SimplificationSkip");
-
- skipped = 0;
- for (a = 0, newtot = 0; a < tot; a++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
-
- if (b != ORIGINDEX_NONE) {
- if (elems[b].curchild++ < ceil(elems[b].lambda * elems[b].totchild)) {
- ctx->index[newtot] = ctx->index[a];
- ctx->skip[newtot] = skipped;
- skipped = 0;
- newtot++;
- }
- else skipped++;
- }
- else skipped++;
- }
-
- for (a = 0, elem = elems; a < totorigface; a++, elem++)
- elem->curchild = 0;
-
- return newtot;
-}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index cc6e28b2a82..bcaebc9bf15 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -70,15 +70,16 @@
#include "BKE_animsys.h"
#include "BKE_boids.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_collision.h"
#include "BKE_colortools.h"
#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_particle.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_collection.h"
#include "BKE_object.h"
#include "BKE_material.h"
#include "BKE_cloth.h"
@@ -88,12 +89,14 @@
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "BKE_bvhutils.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "PIL_time.h"
#include "RE_shader_ext.h"
-#include "DEG_depsgraph.h"
/* fluid sim particle import */
#ifdef WITH_MOD_FLUID
@@ -121,11 +124,11 @@ static int particles_are_dynamic(ParticleSystem *psys)
return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID);
}
-float psys_get_current_display_percentage(ParticleSystem *psys)
+float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_render_params)
{
ParticleSettings *part=psys->part;
- if ((psys->renderdata && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
+ if ((use_render_params && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
(part->child_nbr && part->childtype) || /* display percentage applies to children */
(psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */
{
@@ -287,31 +290,31 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
}
}
-int psys_get_child_number(Scene *scene, ParticleSystem *psys)
+int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
int nbr;
if (!psys->part->childtype)
return 0;
- if (psys->renderdata)
+ if (use_render_params)
nbr= psys->part->ren_child_nbr;
else
nbr= psys->part->child_nbr;
- return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL);
+ return get_render_child_particle_number(&scene->r, nbr, use_render_params);
}
-int psys_get_tot_child(Scene *scene, ParticleSystem *psys)
+int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
- return psys->totpart*psys_get_child_number(scene, psys);
+ return psys->totpart*psys_get_child_number(scene, psys, use_render_params);
}
/************************************************/
/* Distribution */
/************************************************/
-void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deformed, ParticleSystem *psys)
+void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, ParticleSystem *psys)
{
/* use for building derived mesh mapping info:
*
@@ -324,13 +327,13 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
PARTICLE_P;
/* CACHE LOCATIONS */
- if (!dm_final->deformedOnly) {
- /* Will use later to speed up subsurf/derivedmesh */
+ if (!mesh_final->runtime.deformed_only) {
+ /* Will use later to speed up subsurf/evaluated mesh. */
LinkNode *node, *nodedmelem, **nodearray;
int totdmelem, totelem, i, *origindex, *origindex_poly = NULL;
if (psys->part->from == PART_FROM_VERT) {
- totdmelem= dm_final->getNumVerts(dm_final);
+ totdmelem = mesh_final->totvert;
if (use_modifier_stack) {
totelem= totdmelem;
@@ -338,11 +341,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
}
else {
totelem= me->totvert;
- origindex= dm_final->getVertDataArray(dm_final, CD_ORIGINDEX);
+ origindex = CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX);
}
}
else { /* FROM_FACE/FROM_VOLUME */
- totdmelem= dm_final->getNumTessFaces(dm_final);
+ totdmelem= mesh_final->totface;
if (use_modifier_stack) {
totelem= totdmelem;
@@ -350,11 +353,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
origindex_poly= NULL;
}
else {
- totelem = dm_deformed->getNumTessFaces(dm_deformed);
- origindex = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
+ totelem = mesh_original->totface;
+ origindex = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
/* for face lookups we need the poly origindex too */
- origindex_poly= dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
+ origindex_poly = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
if (origindex_poly == NULL) {
origindex= NULL;
}
@@ -414,7 +417,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
pa->num_dmcache = DMCACHE_NOTFOUND;
}
else { /* FROM_FACE/FROM_VOLUME */
- pa->num_dmcache = psys_particle_dm_face_lookup(dm_final, dm_deformed, pa->num, pa->fuv, nodearray);
+ pa->num_dmcache = psys_particle_dm_face_lookup(mesh_final, mesh_original, pa->num, pa->fuv, nodearray);
}
}
}
@@ -438,7 +441,7 @@ void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData
{
memset(ctx, 0, sizeof(ParticleThreadContext));
ctx->sim = *sim;
- ctx->dm = ctx->sim.psmd->dm_final;
+ ctx->mesh = ctx->sim.psmd->mesh_final;
ctx->ma = give_current_material(sim->ob, sim->psys->part->omat);
}
@@ -513,7 +516,6 @@ void psys_thread_context_free(ParticleThreadContext *ctx)
if (ctx->jitoff) MEM_freeN(ctx->jitoff);
if (ctx->weight) MEM_freeN(ctx->weight);
if (ctx->index) MEM_freeN(ctx->index);
- if (ctx->skip) MEM_freeN(ctx->skip);
if (ctx->seams) MEM_freeN(ctx->seams);
//if (ctx->vertpart) MEM_freeN(ctx->vertpart);
BLI_kdtree_free(ctx->tree);
@@ -704,9 +706,9 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic
/* get birth location from object */
if (use_tangents)
- psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0,0);
+ psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0);
else
- psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0);
+ psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0);
/* get possible textural influence */
psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra);
@@ -990,14 +992,14 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic
}
/* recursively evaluate emitter parent anim at cfra */
-static void evaluate_emitter_anim(Scene *scene, Object *ob, float cfra)
+static void evaluate_emitter_anim(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra)
{
if (ob->parent)
- evaluate_emitter_anim(scene, ob->parent, cfra);
+ evaluate_emitter_anim(depsgraph, scene, ob->parent, cfra);
/* we have to force RECALC_ANIM here since where_is_objec_time only does drivers */
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM);
- BKE_object_where_is_calc_time(scene, ob, cfra);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
}
/* sets particle to the emitter surface with initial velocity & rotation */
@@ -1011,7 +1013,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
/* get precise emitter matrix if particle is born */
if (part->type != PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
- evaluate_emitter_anim(sim->scene, sim->ob, pa->time);
+ evaluate_emitter_anim(sim->depsgraph, sim->scene, sim->ob, pa->time);
psys->flag |= PSYS_OB_ANIM_RESTORE;
}
@@ -1145,7 +1147,8 @@ static void set_keyed_keys(ParticleSimulationData *sim)
int totpart = psys->totpart, k, totkeys = psys->totkeyed;
int keyed_flag = 0;
- ksim.scene= sim->scene;
+ ksim.depsgraph = sim->depsgraph;
+ ksim.scene = sim->scene;
/* no proper targets so let's clear and bail out */
if (psys->totkeyed==0) {
@@ -1305,9 +1308,10 @@ void psys_update_particle_tree(ParticleSystem *psys, float cfra)
static void psys_update_effectors(ParticleSimulationData *sim)
{
- pdEndEffectors(&sim->psys->effectors);
- sim->psys->effectors = pdInitEffectors(sim->scene, sim->ob, sim->psys,
- sim->psys->part->effector_weights, true);
+ BKE_effectors_free(sim->psys->effectors);
+ sim->psys->effectors = BKE_effectors_create(sim->depsgraph,
+ sim->ob, sim->psys,
+ sim->psys->part->effector_weights);
precalc_guides(sim, sim->psys->effectors);
}
@@ -2059,11 +2063,12 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo
ParticleSettings *part = sim->psys->part;
ParticleData *pa = efdata->pa;
EffectedPoint epoint;
+ RNG *rng = sim->rng;
/* add effectors */
pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint);
if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)
- pdDoEffectors(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
+ BKE_effectors_apply(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
mul_v3_fl(force, efdata->ptex.field);
mul_v3_fl(impulse, efdata->ptex.field);
@@ -2074,9 +2079,9 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo
/* brownian force */
if (part->brownfac != 0.0f) {
- force[0] += (BLI_frand()-0.5f) * part->brownfac;
- force[1] += (BLI_frand()-0.5f) * part->brownfac;
- force[2] += (BLI_frand()-0.5f) * part->brownfac;
+ force[0] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
+ force[1] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
+ force[2] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
}
if (part->flag & PART_ROT_DYN && epoint.ave)
@@ -2127,7 +2132,7 @@ static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, floa
tkey.time=pa->state.time;
if (part->type != PART_HAIR) {
- if (do_guides(sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
+ if (do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
copy_v3_v3(pa->state.co,tkey.co);
/* guides don't produce valid velocity */
sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co);
@@ -2647,16 +2652,17 @@ static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRay
return hit->index >= 0;
}
-static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation)
+static int collision_response(ParticleSimulationData *sim, ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation)
{
ParticleCollisionElement *pce = &col->pce;
PartDeflect *pd = col->hit->pd;
+ RNG *rng = sim->rng;
float co[3]; /* point of collision */
float x = hit->dist/col->original_ray_length; /* location factor of collision between this iteration */
float f = col->f + x * (1.0f - col->f); /* time factor of collision between timestep */
float dt1 = (f - col->f) * col->total_time; /* time since previous collision (in seconds) */
float dt2 = (1.0f - f) * col->total_time; /* time left after collision (in seconds) */
- int through = (BLI_frand() < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */
+ int through = (BLI_rng_get_float(rng) < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */
/* calculate exact collision location */
interp_v3_v3v3(co, col->co1, col->co2, x);
@@ -2681,8 +2687,8 @@ static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeR
float v0_tan[3];/* tangential component of v0 */
float vc_tan[3];/* tangential component of collision surface velocity */
float v0_dot, vc_dot;
- float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_frand() - 0.5f);
- float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_frand() - 0.5f);
+ float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_rng_get_float(rng) - 0.5f);
+ float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_rng_get_float(rng) - 0.5f);
float distance, nor[3], dot;
CLAMP(damp,0.0f, 1.0f);
@@ -2892,7 +2898,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
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)
+ else if (collision_response(sim, pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0)
return;
}
else
@@ -2908,10 +2914,9 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
- Base *base;
int distr=0, alloc=0, skip=0;
- if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
+ if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys, use_render_params)) || psys->recalc&PSYS_RECALC_RESET)
alloc=1;
if (alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
@@ -2921,7 +2926,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
if (alloc)
realloc_particles(sim, sim->psys->totpart);
- if (psys_get_tot_child(sim->scene, psys)) {
+ if (psys_get_tot_child(sim->scene, psys, use_render_params)) {
/* don't generate children while computing the hair keys */
if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
distribute_particles(sim, PART_FROM_CHILD);
@@ -2938,12 +2943,13 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
skip = 1; /* only hair, keyed and baked stuff can have paths */
else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
skip = 1; /* particle visualization must be set as path */
- else if (!psys->renderdata) {
+ else if (DEG_get_mode(sim->depsgraph) != DAG_EVAL_RENDER) {
if (part->draw_as != PART_DRAW_REND)
skip = 1; /* draw visualization */
else if (psys->pointcache->flag & PTCACHE_BAKING)
skip = 1; /* no need to cache paths while baking dynamics */
- else if (psys_in_edit_mode(sim->scene, psys)) {
+
+ else if (psys_in_edit_mode(sim->depsgraph, psys)) {
if ((pset->flag & PE_DRAW_PART)==0)
skip = 1;
else if (part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0)
@@ -2953,15 +2959,19 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
/* particle instance modifier with "path" option need cached paths even if particle system doesn't */
- for (base = sim->scene->base.first; base; base= base->next) {
- ModifierData *md = modifiers_findByType(base->object, eModifierType_ParticleInstance);
- if (md) {
- ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
- if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) {
- skip = 0;
- break;
+ if (skip) {
+ FOREACH_SCENE_OBJECT_BEGIN(sim->scene, ob)
+ {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleInstance);
+ if (md) {
+ ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
+ if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) {
+ skip = 0;
+ break;
+ }
}
}
+ FOREACH_SCENE_OBJECT_END;
}
if (!skip) {
@@ -3021,11 +3031,11 @@ static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight)
return dvert;
}
-static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int totedge, DerivedMesh **r_dm, ClothHairData **r_hairdata)
+static void hair_create_input_mesh(ParticleSimulationData *sim, int totpoint, int totedge, Mesh **r_mesh, ClothHairData **r_hairdata)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
- DerivedMesh *dm;
+ Mesh *mesh;
ClothHairData *hairdata;
MVert *mvert;
MEdge *medge;
@@ -3037,14 +3047,15 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
float max_length;
float hair_radius;
- dm = *r_dm;
- if (!dm) {
- *r_dm = dm = CDDM_new(totpoint, totedge, 0, 0, 0);
- DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
+ mesh = *r_mesh;
+ if (!mesh) {
+ *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0);
+ CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert);
+ BKE_mesh_update_customdata_pointers(mesh, false);
}
- mvert = CDDM_get_verts(dm);
- medge = CDDM_get_edges(dm);
- dvert = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
+ mvert = mesh->mvert;
+ medge = mesh->medge;
+ dvert = mesh->dvert;
hairdata = *r_hairdata;
if (!hairdata) {
@@ -3079,7 +3090,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
pa->hair_index = hair_index;
use_hair = psys_hair_use_simulation(pa, max_length);
- psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
normalize_m4(root_mat);
@@ -3159,8 +3170,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
if (!psys->clmd) {
psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth);
psys->clmd->sim_parms->goalspring = 0.0f;
- psys->clmd->sim_parms->vel_damping = 1.0f;
- psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_GOAL|CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
+ psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS;
psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
}
@@ -3176,26 +3186,26 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
}
realloc_roots = false; /* whether hair root info array has to be reallocated */
- if (psys->hair_in_dm) {
- DerivedMesh *dm = psys->hair_in_dm;
- if (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm)) {
- dm->release(dm);
- psys->hair_in_dm = NULL;
+ if (psys->hair_in_mesh) {
+ Mesh *mesh = psys->hair_in_mesh;
+ if (totpoint != mesh->totvert || totedge != mesh->totedge) {
+ BKE_id_free(NULL, mesh);
+ psys->hair_in_mesh = NULL;
realloc_roots = true;
}
}
- if (!psys->hair_in_dm || !psys->clmd->hairdata || realloc_roots) {
+ if (!psys->hair_in_mesh || !psys->clmd->hairdata || realloc_roots) {
if (psys->clmd->hairdata) {
MEM_freeN(psys->clmd->hairdata);
psys->clmd->hairdata = NULL;
}
}
- hair_create_input_dm(sim, totpoint, totedge, &psys->hair_in_dm, &psys->clmd->hairdata);
+ hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh, &psys->clmd->hairdata);
- if (psys->hair_out_dm)
- psys->hair_out_dm->release(psys->hair_out_dm);
+ if (psys->hair_out_mesh)
+ BKE_id_free(NULL, psys->hair_out_mesh);
psys->clmd->point_cache = psys->pointcache;
/* for hair sim we replace the internal cloth effector weights temporarily
@@ -3204,13 +3214,16 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
clmd_effweights = psys->clmd->sim_parms->effector_weights;
psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
- deformedVerts = MEM_mallocN(sizeof(*deformedVerts) * psys->hair_in_dm->getNumVerts(psys->hair_in_dm), "do_hair_dynamics vertexCos");
- psys->hair_out_dm = CDDM_copy(psys->hair_in_dm);
- psys->hair_out_dm->getVertCos(psys->hair_out_dm, deformedVerts);
-
- clothModifier_do(psys->clmd, sim->scene, sim->ob, psys->hair_in_dm, deformedVerts);
-
- CDDM_apply_vert_coords(psys->hair_out_dm, deformedVerts);
+ BKE_id_copy_ex(
+ NULL, &psys->hair_in_mesh->id, (ID **)&psys->hair_out_mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ deformedVerts = BKE_mesh_vertexCos_get(psys->hair_out_mesh, NULL);
+ clothModifier_do(psys->clmd, sim->depsgraph, sim->scene, sim->ob, psys->hair_in_mesh, deformedVerts);
+ BKE_mesh_apply_vert_coords(psys->hair_out_mesh, deformedVerts);
MEM_freeN(deformedVerts);
@@ -3222,7 +3235,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys);
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
pa->size = part->size;
@@ -3237,7 +3250,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re
if (psys->recalc & PSYS_RECALC_RESET) {
/* need this for changing subsurf levels */
- psys_calc_dmcache(sim->ob, sim->psmd->dm_final, sim->psmd->dm_deformed, psys);
+ psys_calc_dmcache(sim->ob, sim->psmd->mesh_final, sim->psmd->mesh_original, psys);
if (psys->clmd)
cloth_free_modifier(psys->clmd);
@@ -3284,7 +3297,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra))
if (pa->totkey) {
sub_v3_v3(key->co, root->co);
- psys_vec_rot_to_face(sim->psmd->dm_final, pa, key->co);
+ psys_vec_rot_to_face(sim->psmd->mesh_final, pa, key->co);
}
key->time = pa->state.time;
@@ -3494,7 +3507,6 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part=psys->part;
- RNG *rng;
BoidBrainData bbd;
ParticleTexture ptex;
PARTICLE_P;
@@ -3521,14 +3533,13 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
return;
}
- BLI_srandom(31415926 + (int)cfra + psys->seed);
/* for now do both, boids us 'rng' */
- rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
+ sim->rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
psys_update_effectors(sim);
if (part->type != PART_HAIR)
- sim->colliders = get_collider_cache(sim->scene, sim->ob, part->collision_group);
+ sim->colliders = BKE_collider_cache_create(sim->depsgraph, sim->ob, part->collision_group);
/* initialize physics type specific stuff */
switch (part->phystype) {
@@ -3540,7 +3551,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
bbd.cfra = cfra;
bbd.dfra = dfra;
bbd.timestep = timestep;
- bbd.rng = rng;
+ bbd.rng = sim->rng;
psys_update_particle_tree(psys, cfra);
@@ -3735,16 +3746,18 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
pa->state.time=cfra;
}
- free_collider_cache(&sim->colliders);
- BLI_rng_free(rng);
+ BKE_collider_cache_free(&sim->colliders);
+ BLI_rng_free(sim->rng);
+ sim->rng = NULL;
}
-static void update_children(ParticleSimulationData *sim)
+
+static void update_children(ParticleSimulationData *sim, const bool use_render_params)
{
if ((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE)==0)
/* don't generate children while growing hair - waste of time */
psys_free_children(sim->psys);
else if (sim->psys->part->childtype) {
- if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys))
+ if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys, use_render_params))
distribute_particles(sim, PART_FROM_CHILD);
else {
/* Children are up to date, nothing to do. */
@@ -3754,7 +3767,7 @@ static void update_children(ParticleSimulationData *sim)
psys_free_children(sim->psys);
}
/* updates cached particles' alive & other flags etc..*/
-static void cached_step(ParticleSimulationData *sim, float cfra)
+static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -3764,7 +3777,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
psys_update_effectors(sim);
- disp= psys_get_current_display_percentage(psys);
+ disp= psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
@@ -3800,7 +3813,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
}
static void particles_fluid_step(
- Main *bmain, ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params)
+ ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
if (psys->particles) {
@@ -3831,7 +3844,7 @@ static void particles_fluid_step(
// ok, start loading
BLI_join_dirfile(filename, sizeof(filename), fss->surfdataPath, OB_FLUIDSIM_SURF_PARTICLES_FNAME);
- BLI_path_abs(filename, modifier_path_relbase(bmain, sim->ob));
+ BLI_path_abs(filename, modifier_path_relbase_from_global(sim->ob));
BLI_path_frame(filename, curFrame, 0); // fixed #frame-no
@@ -3905,7 +3918,7 @@ static void particles_fluid_step(
} // fluid sim particles done
}
#else
- UNUSED_VARS(bmain, use_render_params);
+ UNUSED_VARS(use_render_params);
#endif // WITH_MOD_FLUID
}
@@ -3987,8 +4000,8 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
int cache_result = BKE_ptcache_read(pid, cache_cfra, true);
if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
- cached_step(sim, cfra);
- update_children(sim);
+ cached_step(sim, cfra, use_render_params);
+ update_children(sim, use_render_params);
psys_update_path_cache(sim, cfra, use_render_params);
BKE_ptcache_validate(cache, (int)cache_cfra);
@@ -4005,7 +4018,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
}
else if (cache_result == PTCACHE_READ_OLD) {
psys->cfra = (float)cache->simframe;
- cached_step(sim, psys->cfra);
+ cached_step(sim, psys->cfra, use_render_params);
}
/* if on second frame, write cache for first frame */
@@ -4017,7 +4030,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
/* 3. do dynamics */
/* set particles to be not calculated TODO: can't work with pointcache */
- disp= psys_get_current_display_percentage(psys);
+ disp= psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
if (psys_frand(psys, p) > disp)
@@ -4055,9 +4068,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
sim->courant_num = 0.0f;
dynamics_step(sim, cfra+dframe+t_frac - 1.f);
psys->cfra = cfra+dframe+t_frac - 1.f;
-#if 0
- 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)
update_timestep(psys, sim);
/* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */
@@ -4073,7 +4084,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
BKE_ptcache_write(pid, (int)cache_cfra);
}
- update_children(sim);
+ update_children(sim, use_render_params);
/* cleanup */
if (psys->lattice_deform_data) {
@@ -4199,11 +4210,13 @@ static int hair_needs_recalc(ParticleSystem *psys)
/* main particle update call, checks that things are ok on the large scale and
* then advances in to actual particle calculations depending on particle type */
-void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
+void particle_system_update(struct Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSimulationData sim= {0};
ParticleSettings *part = psys->part;
+ ParticleSystem *psys_orig = psys_orig_get(psys);
float cfra;
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
/* drawdata is outdated after ANY change */
if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
@@ -4211,12 +4224,13 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
if (!psys_check_enabled(ob, psys, use_render_params))
return;
- cfra= BKE_scene_frame_get(scene);
+ cfra = DEG_get_ctime(depsgraph);
- sim.scene= scene;
- sim.ob= ob;
- sim.psys= psys;
- sim.psmd= psys_get_modifier(ob, psys);
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psmd;
/* system was already updated from modifier stack */
if (sim.psmd->flag & eParticleSystemFlag_psys_updated) {
@@ -4226,22 +4240,19 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
return;
}
- if (!sim.psmd->dm_final)
+ if (!sim.psmd->mesh_final)
return;
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(sim.psmd->dm_final);
+ BKE_mesh_tessface_ensure(sim.psmd->mesh_final);
}
/* execute drivers only, as animation has already been done */
- BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS);
/* to verify if we need to restore object afterwards */
psys->flag &= ~PSYS_OB_ANIM_RESTORE;
- if (psys->recalc & PSYS_RECALC_TYPE)
- psys_changed_type(sim.ob, sim.psys);
-
if (psys->recalc & PSYS_RECALC_RESET)
psys->totunexist = 0;
@@ -4264,10 +4275,10 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
free_hair(ob, psys, 0);
- if (psys->edit && psys->free_edit) {
- psys->free_edit(psys->edit);
- psys->edit = NULL;
- psys->free_edit = NULL;
+ if (psys_orig->edit && psys_orig->free_edit) {
+ psys_orig->free_edit(psys_orig->edit);
+ psys_orig->edit = NULL;
+ psys_orig->free_edit = NULL;
}
/* first step is negative so particles get killed and reset */
@@ -4276,7 +4287,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
for (i=0; i<=part->hair_step; i++) {
hcfra=100.0f*(float)i/(float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW)==0)
- BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM);
system_step(&sim, hcfra, use_render_params);
psys->cfra = hcfra;
psys->recalc = 0;
@@ -4295,7 +4306,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
}
case PART_FLUID:
{
- particles_fluid_step(bmain, &sim, (int)cfra, use_render_params);
+ particles_fluid_step(&sim, (int)cfra, use_render_params);
break;
}
default:
@@ -4305,7 +4316,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
case PART_PHYS_KEYED:
{
PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys);
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
bool free_unexisting = false;
/* Particles without dynamics haven't been reset yet because they don't use pointcache */
@@ -4359,16 +4370,33 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
/* make sure emitter is left at correct time (particle emission can change this) */
if (psys->flag & PSYS_OB_ANIM_RESTORE) {
- evaluate_emitter_anim(scene, ob, cfra);
+ evaluate_emitter_anim(depsgraph, scene, ob, cfra);
psys->flag &= ~PSYS_OB_ANIM_RESTORE;
}
+ if (psys_orig->edit) {
+ psys_orig->edit->flags |= PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL;
+ }
+
+ if (DEG_is_active(depsgraph)) {
+ if (psys_orig != psys) {
+ if (psys_orig->edit != NULL &&
+ psys_orig->edit->psys == psys_orig)
+ {
+ psys_orig->edit->psys_eval = psys;
+ psys_orig->edit->psmd_eval = psmd;
+ }
+ psys_orig->flag = (psys->flag & ~PSYS_SHARED_CACHES);
+ }
+ }
+
psys->cfra = cfra;
psys->recalc = 0;
/* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */
- if (psys->renderdata==0)
- invert_m4_m4(psys->imat, ob->obmat);
+ invert_m4_m4(psys->imat, ob->obmat);
+
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
/* ID looper */
@@ -4399,10 +4427,16 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
/* **** Depsgraph evaluation **** */
-void BKE_particle_system_eval_init(EvaluationContext *UNUSED(eval_ctx),
+void BKE_particle_system_eval_init(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+ for (ParticleSystem *psys = ob->particlesystem.first;
+ psys != NULL;
+ psys = psys->next)
+ {
+ psys->recalc |= (psys->part->id.recalc & DEG_TAG_PSYS_ALL);
+ }
BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 746e8b63a18..413f0407c86 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -41,6 +41,7 @@
#include "BKE_paint.h"
#include "GPU_buffers.h"
+#include "GPU_immediate.h"
#include "bmesh.h"
@@ -636,7 +637,6 @@ void BKE_pbvh_free(PBVH *bvh)
BLI_gset_free(node->bm_other_verts, NULL);
}
}
- GPU_pbvh_multires_buffers_free(&bvh->grid_common_gpu_buffer);
if (bvh->deformed) {
if (bvh->verts) {
@@ -1101,7 +1101,6 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
static int pbvh_get_buffers_update_flags(PBVH *bvh)
{
int update_flags = 0;
- update_flags |= bvh->show_diffuse_color ? GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR : 0;
update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0;
return update_flags;
}
@@ -1117,19 +1116,21 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
switch (bvh->type) {
case PBVH_GRIDS:
node->draw_buffers =
- GPU_pbvh_grid_buffers_build(node->prim_indices,
- node->totprim,
- bvh->grid_hidden,
- bvh->gridkey.grid_size,
- &bvh->gridkey, &bvh->grid_common_gpu_buffer);
+ GPU_pbvh_grid_buffers_build(
+ node->prim_indices,
+ node->totprim,
+ bvh->grid_hidden,
+ bvh->gridkey.grid_size,
+ &bvh->gridkey);
break;
case PBVH_FACES:
node->draw_buffers =
- GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
- bvh->mpoly, bvh->mloop, bvh->looptri,
- bvh->verts,
- node->prim_indices,
- node->totprim);
+ GPU_pbvh_mesh_buffers_build(
+ node->face_vert_indices,
+ bvh->mpoly, bvh->mloop, bvh->looptri,
+ bvh->verts,
+ node->prim_indices,
+ node->totprim);
break;
case PBVH_BMESH:
node->draw_buffers =
@@ -1180,19 +1181,6 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
}
}
-void BKE_pbvh_draw_BB(PBVH *bvh)
-{
- GPU_pbvh_BB_draw_init();
-
- for (int a = 0; a < bvh->totnode; a++) {
- PBVHNode *node = &bvh->nodes[a];
-
- GPU_pbvh_BB_draw(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
- }
-
- GPU_pbvh_BB_draw_end();
-}
-
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
{
int update = 0;
@@ -1353,6 +1341,12 @@ void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
*key = bvh->gridkey;
}
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh, int *num_grids)
+{
+ BLI_assert(bvh->type == PBVH_GRIDS);
+ *num_grids = bvh->totgrid;
+ return bvh->grids;
+}
BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
{
@@ -1996,42 +1990,6 @@ bool BKE_pbvh_node_find_nearest_to_ray(
return hit;
}
-typedef struct {
- DMSetMaterial setMaterial;
- bool wireframe;
- bool fast;
-} PBVHNodeDrawData;
-
-void BKE_pbvh_node_draw(PBVHNode *node, void *data_v)
-{
- PBVHNodeDrawData *data = data_v;
-
-#if 0
- /* XXX: Just some quick code to show leaf nodes in different colors */
- float col[3];
- float spec[3] = {0.0f, 0.0f, 0.0f};
-
- if (0) { //is_partial) {
- col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6;
- }
- else {
- srand((long long)node);
- for (int i = 0; i < 3; ++i)
- col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7;
- }
-
- GPU_basic_shader_colors(col, spec, 0, 1.0f);
- glColor3f(1, 0, 0);
-#endif
-
- if (!(node->flag & PBVH_FullyHidden)) {
- GPU_pbvh_buffers_draw(node->draw_buffers,
- data->setMaterial,
- data->wireframe,
- data->fast);
- }
-}
-
typedef enum {
ISECT_INSIDE,
ISECT_OUTSIDE,
@@ -2091,37 +2049,44 @@ bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
-static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node)
-{
- if (!node->draw_buffers)
- return;
-
- if (GPU_pbvh_buffers_diffuse_changed(node->draw_buffers, node->bm_faces, bvh->show_diffuse_color))
- node->flag |= PBVH_UpdateDrawBuffers;
-}
+struct PBVHNodeDrawCallbackData {
+ void (*draw_fn)(void *user_data, GPUBatch *batch);
+ void *user_data;
+ bool fast;
+ bool only_mask; /* Only draw nodes that have mask data. */
+};
-static void pbvh_node_check_mask_changed(PBVH *bvh, PBVHNode *node)
+static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
{
- if (!node->draw_buffers) {
- return;
- }
- if (GPU_pbvh_buffers_mask_changed(node->draw_buffers, bvh->show_mask)) {
- node->flag |= PBVH_UpdateDrawBuffers;
+ struct PBVHNodeDrawCallbackData *data = data_v;
+
+ if (!(node->flag & PBVH_FullyHidden)) {
+ GPUBatch *triangles = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast);
+ bool show_mask = GPU_pbvh_buffers_has_mask(node->draw_buffers);
+ if (!data->only_mask || show_mask) {
+ if (triangles != NULL) {
+ data->draw_fn(data->user_data, triangles);
+ }
+ }
}
}
-void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
- DMSetMaterial setMaterial, bool wireframe, bool fast)
-{
- PBVHNodeDrawData draw_data = {setMaterial, wireframe, fast};
+/**
+ * Version of #BKE_pbvh_draw that runs a callback.
+ */
+void BKE_pbvh_draw_cb(
+ PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, bool only_mask,
+ void (*draw_fn)(void *user_data, GPUBatch *batch), void *user_data)
+{
+ struct PBVHNodeDrawCallbackData draw_data = {
+ .only_mask = only_mask,
+ .fast = fast,
+ .draw_fn = draw_fn,
+ .user_data = user_data,
+ };
PBVHNode **nodes;
int totnode;
- for (int a = 0; a < bvh->totnode; a++) {
- pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]);
- pbvh_node_check_mask_changed(bvh, &bvh->nodes[a]);
- }
-
BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers),
&nodes, &totnode);
@@ -2131,15 +2096,19 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
if (nodes) MEM_freeN(nodes);
if (planes) {
- BKE_pbvh_search_callback(bvh, BKE_pbvh_node_planes_contain_AABB,
- planes, BKE_pbvh_node_draw, &draw_data);
+ BKE_pbvh_search_callback(
+ bvh, BKE_pbvh_node_planes_contain_AABB,
+ planes, pbvh_node_draw_cb, &draw_data);
}
else {
- BKE_pbvh_search_callback(bvh, NULL, NULL, BKE_pbvh_node_draw, &draw_data);
+ BKE_pbvh_search_callback(
+ bvh, NULL,
+ NULL, pbvh_node_draw_cb, &draw_data);
}
-
+#if 0
if (G.debug_value == 14)
- BKE_pbvh_draw_BB(bvh);
+ pbvh_draw_BB(bvh);
+#endif
}
void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
@@ -2195,8 +2164,13 @@ float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3]
return vertCos;
}
-void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
+void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3], const int totvert)
{
+ if (totvert != pbvh->totvert) {
+ BLI_assert(!"PBVH: Given deforming vcos number does not natch PBVH vertex number!");
+ return;
+ }
+
if (!pbvh->deformed) {
if (pbvh->verts) {
/* if pbvh is not already deformed, verts/faces points to the */
@@ -2351,24 +2325,24 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK);
}
-void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color)
+bool pbvh_has_mask(PBVH *bvh)
{
- bool has_mask = false;
-
switch (bvh->type) {
case PBVH_GRIDS:
- has_mask = (bvh->gridkey.has_mask != 0);
- break;
+ return (bvh->gridkey.has_mask != 0);
case PBVH_FACES:
- has_mask = (bvh->vdata && CustomData_get_layer(bvh->vdata,
- CD_PAINT_MASK));
- break;
+ return (bvh->vdata && CustomData_get_layer(bvh->vdata,
+ CD_PAINT_MASK));
case PBVH_BMESH:
- has_mask = (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
- break;
+ return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
}
- bvh->show_diffuse_color = !has_mask || show_diffuse_color;
+ return false;
+}
+
+void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color)
+{
+ bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color;
}
void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index e32a5d0681e..3369b05ea60 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -27,7 +27,7 @@
#include "BLI_utildefines.h"
#include "BLI_buffer.h"
#include "BLI_ghash.h"
-#include "BLI_heap.h"
+#include "BLI_heap_simple.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
@@ -721,7 +721,7 @@ static void pbvh_bmesh_node_drop_orig(PBVHNode *node)
struct EdgeQueue;
typedef struct EdgeQueue {
- Heap *heap;
+ HeapSimple *heap;
const float *center;
float center_proj[3]; /* for when we use projected coords. */
float radius_squared;
@@ -840,7 +840,7 @@ static void edge_queue_insert(
BMVert **pair = BLI_mempool_alloc(eq_ctx->pool);
pair[0] = e->v1;
pair[1] = e->v2;
- BLI_heap_insert(eq_ctx->q->heap, priority, pair);
+ BLI_heapsimple_insert(eq_ctx->q->heap, priority, pair);
#ifdef USE_EDGEQUEUE_TAG
BLI_assert(EDGE_QUEUE_TEST(e) == false);
EDGE_QUEUE_ENABLE(e);
@@ -1008,7 +1008,7 @@ static void long_edge_queue_create(
PBVH *bvh, const float center[3], const float view_normal[3],
float radius, const bool use_frontface, const bool use_projected)
{
- eq_ctx->q->heap = BLI_heap_new();
+ eq_ctx->q->heap = BLI_heapsimple_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len;
@@ -1070,7 +1070,7 @@ static void short_edge_queue_create(
PBVH *bvh, const float center[3], const float view_normal[3],
float radius, const bool use_frontface, const bool use_projected)
{
- eq_ctx->q->heap = BLI_heap_new();
+ eq_ctx->q->heap = BLI_heapsimple_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
@@ -1237,8 +1237,8 @@ static bool pbvh_bmesh_subdivide_long_edges(
{
bool any_subdivided = false;
- while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
- BMVert **pair = BLI_heap_pop_min(eq_ctx->q->heap);
+ while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
+ BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
BMVert *v1 = pair[0], *v2 = pair[1];
BMEdge *e;
@@ -1454,8 +1454,8 @@ static bool pbvh_bmesh_collapse_short_edges(
/* deleted verts point to vertices they were merged into, or NULL when removed. */
GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
- while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
- BMVert **pair = BLI_heap_pop_min(eq_ctx->q->heap);
+ while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
+ BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
BMVert *v1 = pair[0], *v2 = pair[1];
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
@@ -1961,7 +1961,7 @@ bool BKE_pbvh_bmesh_update_topology(
short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_collapse_short_edges(
&eq_ctx, bvh, &deleted_faces);
- BLI_heap_free(q.heap, NULL);
+ BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
@@ -1976,7 +1976,7 @@ bool BKE_pbvh_bmesh_update_topology(
long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_subdivide_long_edges(
&eq_ctx, bvh, &edge_loops);
- BLI_heap_free(q.heap, NULL);
+ BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 4aef97bda47..ea8bd1933cd 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -144,11 +144,6 @@ struct PBVH {
const DMFlagMat *grid_flag_mats;
int totgrid;
BLI_bitmap **grid_hidden;
- /* index_buf of GPU_PBVH_Buffers can be the same for all 'fully drawn' nodes (same size).
- * Previously was stored in a static var in gpu_buffer.c, but this breaks in case we handle several different
- * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer
- * in an opaque pointer per pbvh. See T47637. */
- struct GridCommonGPUBuffer *grid_common_gpu_buffer;
/* Only used during BVH build and update,
* don't need to remain valid after */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index f611e7a94cd..affe95ffe78 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
+#include "DNA_collection_types.h"
#include "DNA_dynamicpaint_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -59,8 +60,10 @@
#include "BKE_appdir.h"
#include "BKE_anim.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -72,6 +75,8 @@
#include "BIK_api.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_BULLET
# include "RBI_api.h"
#endif
@@ -1291,8 +1296,8 @@ static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUS
if (rbo->type == RBO_TYPE_ACTIVE) {
#ifdef WITH_BULLET
- RB_body_get_position(rbo->physics_object, rbo->pos);
- RB_body_get_orientation(rbo->physics_object, rbo->orn);
+ RB_body_get_position(rbo->shared->physics_object, rbo->pos);
+ RB_body_get_orientation(rbo->shared->physics_object, rbo->orn);
#endif
PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos);
PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn);
@@ -1385,9 +1390,9 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
pid->ob= ob;
pid->calldata= sb;
pid->type= PTCACHE_TYPE_SOFTBODY;
- pid->cache= sb->pointcache;
- pid->cache_ptr= &sb->pointcache;
- pid->ptcaches= &sb->ptcaches;
+ pid->cache= sb->shared->pointcache;
+ pid->cache_ptr= &sb->shared->pointcache;
+ pid->ptcaches= &sb->shared->ptcaches;
pid->totpoint= pid->totwrite= ptcache_softbody_totpoint;
pid->error = ptcache_softbody_error;
@@ -1615,9 +1620,9 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->ob= ob;
pid->calldata= rbw;
pid->type= PTCACHE_TYPE_RIGIDBODY;
- pid->cache= rbw->pointcache;
- pid->cache_ptr= &rbw->pointcache;
- pid->ptcaches= &rbw->ptcaches;
+ pid->cache= rbw->shared->pointcache;
+ pid->cache_ptr= &rbw->shared->pointcache;
+ pid->ptcaches= &rbw->shared->ptcaches;
pid->totpoint= pid->totwrite= ptcache_rigidbody_totpoint;
pid->error = ptcache_rigidbody_error;
@@ -1648,92 +1653,195 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-void BKE_ptcache_ids_from_object(Main *bmain, ListBase *lb, Object *ob, Scene *scene, int duplis)
+PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
{
- PTCacheID *pid;
- ParticleSystem *psys;
- ModifierData *md;
+ PTCacheID result = {0};
- lb->first= lb->last= NULL;
+ ListBase pidlist;
+ BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
- if (ob->soft) {
- pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
- BKE_ptcache_id_from_softbody(pid, ob, ob->soft);
- BLI_addtail(lb, pid);
+ for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->cache == cache) {
+ result = *pid;
+ break;
+ }
}
- for (psys=ob->particlesystem.first; psys; psys=psys->next) {
- if (psys->part==NULL)
- continue;
+ BLI_freelistN(&pidlist);
- /* check to make sure point cache is actually used by the particles */
- if (ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED))
- continue;
+ return result;
+}
- /* hair needs to be included in id-list for cache edit mode to work */
- /* if (psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DYNAMICS)==0) */
- /* continue; */
+/* Callback which is used by point cache foreach() family of functions.
+ *
+ * Receives ID of the point cache.
+ *
+ * NOTE: This ID is owned by foreach() routines and can not be used outside of
+ * the foreach loop. This means that if one wants to store them those are to be
+ * malloced and copied over.
+ *
+ * If the function returns false, then foreach() loop aborts.
+ */
+typedef bool (*ForeachPtcacheCb)(PTCacheID *pid, void *userdata);
- if (psys->part->type == PART_FLUID)
+static bool foreach_object_particle_ptcache(Object *object,
+ ForeachPtcacheCb callback,
+ void *callback_user_data)
+{
+ PTCacheID pid;
+ for (ParticleSystem *psys = object->particlesystem.first;
+ psys != NULL;
+ psys = psys->next)
+ {
+ if (psys->part==NULL) {
continue;
-
- pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
- BKE_ptcache_id_from_particles(pid, ob, psys);
- BLI_addtail(lb, pid);
+ }
+ /* Check to make sure point cache is actually used by the particles. */
+ if (ELEM(psys->part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) {
+ continue;
+ }
+ /* Hair needs to be included in id-list for cache edit mode to work. */
+#if 0
+ if ((psys->part->type == PART_HAIR) &&
+ (psys->flag & PSYS_HAIR_DYNAMICS) == 0)
+ {
+ continue;
+ }
+#endif
+ if (psys->part->type == PART_FLUID) {
+ continue;
+ }
+ BKE_ptcache_id_from_particles(&pid, object, psys);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
}
+ return true;
+}
- for (md=ob->modifiers.first; md; md=md->next) {
+static bool foreach_object_modifier_ptcache(Object *object,
+ ForeachPtcacheCb callback,
+ void *callback_user_data)
+{
+ PTCacheID pid;
+ for (ModifierData *md = object->modifiers.first; md != NULL; md = md->next) {
if (md->type == eModifierType_Cloth) {
- pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
- BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md);
- BLI_addtail(lb, pid);
+ BKE_ptcache_id_from_cloth(&pid, object, (ClothModifierData*)md);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
}
else if (md->type == eModifierType_Smoke) {
SmokeModifierData *smd = (SmokeModifierData *)md;
if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
- pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
- BKE_ptcache_id_from_smoke(pid, ob, (SmokeModifierData*)md);
- BLI_addtail(lb, pid);
+ BKE_ptcache_id_from_smoke(&pid, object, (SmokeModifierData*)md);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
}
}
else if (md->type == eModifierType_DynamicPaint) {
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
if (pmd->canvas) {
DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
-
for (; surface; surface=surface->next) {
- pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID");
- BKE_ptcache_id_from_dynamicpaint(pid, ob, surface);
- BLI_addtail(lb, pid);
+ BKE_ptcache_id_from_dynamicpaint(&pid, object, surface);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
}
}
}
}
+ return true;
+}
- if (scene && ob->rigidbody_object && scene->rigidbody_world) {
- pid = MEM_callocN(sizeof(PTCacheID), "PTCacheID");
- BKE_ptcache_id_from_rigidbody(pid, ob, scene->rigidbody_world);
- BLI_addtail(lb, pid);
- }
-
- if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) {
- ListBase *lb_dupli_ob;
- /* don't update the dupli groups, we only want their pid's */
- if ((lb_dupli_ob = object_duplilist_ex(bmain, bmain->eval_ctx, scene, ob, false))) {
- DupliObject *dob;
- for (dob= lb_dupli_ob->first; dob; dob= dob->next) {
- if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */
- ListBase lb_dupli_pid;
- BKE_ptcache_ids_from_object(bmain, &lb_dupli_pid, dob->ob, scene, duplis);
- BLI_movelisttolist(lb, &lb_dupli_pid);
- if (lb_dupli_pid.first)
- printf("Adding Dupli\n");
- }
+/* Return false if any of callbacks returned false. */
+static bool foreach_object_ptcache(Scene *scene,
+ Object *object,
+ int duplis,
+ ForeachPtcacheCb callback,
+ void *callback_user_data)
+{
+ PTCacheID pid;
+ /* Soft body. */
+ if (object->soft != NULL) {
+ BKE_ptcache_id_from_softbody(&pid, object, object->soft);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ /* Particle systems. */
+ if (!foreach_object_particle_ptcache(object, callback, callback_user_data)) {
+ return false;
+ }
+ /* Modifiers. */
+ if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) {
+ return false;
+ }
+ /* Rigid body. */
+ if (scene != NULL &&
+ object->rigidbody_object != NULL &&
+ scene->rigidbody_world != NULL)
+ {
+ BKE_ptcache_id_from_rigidbody(&pid, object, scene->rigidbody_world);
+ if (!callback(&pid, callback_user_data)) {
+ return false;
+ }
+ }
+ /* Consider all object in dupli groups to be part of the same object,
+ * for baking with linking dupligroups. Once we have better overrides
+ * this can be revisited so users select the local objects directly. */
+ if (scene != NULL && (duplis-- > 0) && (object->dup_group != NULL)) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(object->dup_group,
+ current_object)
+ {
+ if (current_object == object) {
+ continue;
}
-
- free_object_duplilist(lb_dupli_ob); /* does restore */
+ foreach_object_ptcache(scene,
+ current_object,
+ duplis,
+ callback,
+ callback_user_data);
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
+ return true;
+}
+
+typedef struct PTCacheIDsFromObjectData {
+ ListBase *list_base;
+} PTCacheIDsFromObjectData;
+
+static bool ptcache_ids_from_object_cb(PTCacheID *pid, void *userdata)
+{
+ PTCacheIDsFromObjectData *data = userdata;
+ PTCacheID *own_pid = MEM_mallocN(sizeof(PTCacheID), "PTCacheID");
+ *own_pid = *pid;
+ BLI_addtail(data->list_base, own_pid);
+ return true;
+}
+
+void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
+{
+ PTCacheIDsFromObjectData data;
+ lb->first = lb->last = NULL;
+ data.list_base = lb;
+ foreach_object_ptcache(
+ scene, ob, duplis, ptcache_ids_from_object_cb, &data);
+}
+
+static bool ptcache_object_has_cb(PTCacheID *UNUSED(pid),
+ void *UNUSED(userdata))
+{
+ return false;
+}
+
+bool BKE_ptcache_object_has(struct Scene *scene, struct Object *ob, int duplis)
+{
+ return !foreach_object_ptcache(
+ scene, ob, duplis, ptcache_object_has_cb, NULL);
}
/* File handling */
@@ -3151,19 +3259,6 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra
if (startframe && endframe) {
*startframe= cache->startframe;
*endframe= cache->endframe;
-
- /* TODO: time handling with object offsets and simulated vs. cached
- * particles isn't particularly easy, so for now what you see is what
- * you get. In the future point cache could handle the whole particle
- * system timing. */
-#if 0
- if ((ob->partype & PARSLOW)==0) {
- offset= ob->sf;
-
- *startframe += (int)(offset+0.5f);
- *endframe += (int)(offset+0.5f);
- }
-#endif
}
/* verify cached_frames array is up to date */
@@ -3269,12 +3364,6 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
sbFreeSimulation(pid->calldata);
else if (pid->type == PTCACHE_TYPE_PARTICLES)
psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH);
-#if 0
- else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
- smokeModifier_reset(pid->calldata);
- else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES)
- smokeModifier_reset_turbulence(pid->calldata);
-#endif
else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT)
dynamicPaint_clearSurface(scene, (DynamicPaintSurface*)pid->calldata);
}
@@ -3356,6 +3445,7 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
if (ob->type == OB_ARMATURE)
BIK_clear_cache(ob->pose);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
return reset;
}
@@ -3510,13 +3600,14 @@ PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcach
* every user action changing stuff, and then it runs a complete bake??? (ton) */
/* Baking */
-void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene)
+void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
PTCacheBaker baker;
memset(&baker, 0, sizeof(baker));
baker.bmain = bmain;
baker.scene = scene;
+ baker.view_layer = view_layer;
baker.bake = 0;
baker.render = 0;
baker.anim_init = 0;
@@ -3542,6 +3633,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
{
Main *bmain = baker->bmain;
Scene *scene = baker->scene;
+ ViewLayer *view_layer = baker->view_layer;
+ struct Depsgraph *depsgraph = baker->depsgraph;
Scene *sce_iter; /* SETLOOPER macro only */
Base *base;
ListBase pidlist;
@@ -3571,7 +3664,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
/* get all pids from the object and search for smoke low res */
ListBase pidlist2;
PTCacheID *pid2;
- BKE_ptcache_ids_from_object(bmain, &pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
+ BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
for (pid2=pidlist2.first; pid2; pid2=pid2->next) {
if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) {
@@ -3604,9 +3697,9 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
else {
- for (SETLOOPER(scene, sce_iter, base)) {
+ for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
/* cache/bake everything in the scene */
- BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR);
+ BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
for (pid=pidlist.first; pid; pid=pid->next) {
cache = pid->cache;
@@ -3660,7 +3753,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
stime = ptime = PIL_check_seconds_timer();
for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) {
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
if (baker->update_progress) {
float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe));
@@ -3715,8 +3808,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
else {
- for (SETLOOPER(scene, sce_iter, base)) {
- BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR);
+ for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
+ BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
for (pid=pidlist.first; pid; pid=pid->next) {
/* skip hair particles */
@@ -3746,7 +3839,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
CFRA = cfrao;
if (bake) { /* already on cfra unless baking */
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
/* TODO: call redraw all windows somehow */
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
deleted file mode 100644
index cb297744ab8..00000000000
--- a/source/blender/blenkernel/intern/property.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): ton roosendaal
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/property.c
- * \ingroup bke
- *
- * This module deals with bProperty only,
- * they are used on blender objects in the game engine
- * (where they get converted into C++ classes - CValue and subclasses)
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_property_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-
-#include "BKE_property.h"
-
-void BKE_bproperty_free(bProperty *prop)
-{
-
- if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
- MEM_freeN(prop);
-
-}
-
-void BKE_bproperty_free_list(ListBase *lb)
-{
- bProperty *prop;
-
- while ((prop = BLI_pophead(lb))) {
- BKE_bproperty_free(prop);
- }
-}
-
-bProperty *BKE_bproperty_copy(const bProperty *prop)
-{
- bProperty *propn;
-
- propn = MEM_dupallocN(prop);
- if (prop->poin && prop->poin != &prop->data) {
- propn->poin = MEM_dupallocN(prop->poin);
- }
- else {
- propn->poin = &propn->data;
- }
-
- return propn;
-}
-
-void BKE_bproperty_copy_list(ListBase *lbn, const ListBase *lbo)
-{
- bProperty *prop, *propn;
- BKE_bproperty_free_list(lbn); /* in case we are copying to an object with props */
- prop = lbo->first;
- while (prop) {
- propn = BKE_bproperty_copy(prop);
- BLI_addtail(lbn, propn);
- prop = prop->next;
- }
-
-
-}
-
-void BKE_bproperty_init(bProperty *prop)
-{
- /* also use when property changes type */
-
- if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
- prop->poin = NULL;
-
- prop->data = 0;
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- case GPROP_FLOAT:
- case GPROP_TIME:
- prop->poin = &prop->data;
- break;
- case GPROP_STRING:
- prop->poin = MEM_callocN(MAX_PROPSTRING, "property string");
- break;
- }
-}
-
-
-bProperty *BKE_bproperty_new(int type)
-{
- bProperty *prop;
-
- prop = MEM_callocN(sizeof(bProperty), "property");
- prop->type = type;
-
- BKE_bproperty_init(prop);
-
- strcpy(prop->name, "prop");
-
- return prop;
-}
-
-
-bProperty *BKE_bproperty_object_get(Object *ob, const char *name)
-{
- return BLI_findstring(&ob->prop, name, offsetof(bProperty, name));
-}
-
-void BKE_bproperty_object_set(Object *ob, bProperty *propc)
-{
- bProperty *prop;
- prop = BKE_bproperty_object_get(ob, propc->name);
- if (prop) {
- BLI_remlink(&ob->prop, prop);
- BKE_bproperty_free(prop);
- }
- BLI_addtail(&ob->prop, BKE_bproperty_copy(propc));
-}
-
-/* negative: prop is smaller
- * positive: prop is larger
- */
-#if 0 /* UNUSED */
-int BKE_bproperty_cmp(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
- float fvalue, ftest;
-
- switch (prop->type) {
- case GPROP_BOOL:
- if (BLI_strcasecmp(str, "true") == 0) {
- if (prop->data == 1) return 0;
- else return 1;
- }
- else if (BLI_strcasecmp(str, "false") == 0) {
- if (prop->data == 0) return 0;
- else return 1;
- }
- /* no break, do GPROP_int too! */
-
- case GPROP_INT:
- return prop->data - atoi(str);
-
- case GPROP_FLOAT:
- case GPROP_TIME:
- /* WARNING: untested for GPROP_TIME
- * function isn't used currently */
- fvalue = *((float *)&prop->data);
- ftest = (float)atof(str);
- if (fvalue > ftest) return 1;
- else if (fvalue < ftest) return -1;
- return 0;
-
- case GPROP_STRING:
- return strcmp(prop->poin, str);
- }
-
- return 0;
-}
-#endif
-
-void BKE_bproperty_set(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
-
- switch (prop->type) {
- case GPROP_BOOL:
- if (BLI_strcasecmp(str, "true") == 0) prop->data = 1;
- else if (BLI_strcasecmp(str, "false") == 0) prop->data = 0;
- else prop->data = (atoi(str) != 0);
- break;
- case GPROP_INT:
- prop->data = atoi(str);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- *((float *)&prop->data) = (float)atof(str);
- break;
- case GPROP_STRING:
- strcpy(prop->poin, str); /* TODO - check size? */
- break;
- }
-
-}
-
-void BKE_bproperty_add(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- prop->data += atoi(str);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- *((float *)&prop->data) += (float)atof(str);
- break;
- case GPROP_STRING:
- /* strcpy(prop->poin, str); */
- break;
- }
-}
-
-/* reads value of property, sets it in chars in str */
-void BKE_bproperty_set_valstr(bProperty *prop, char str[MAX_PROPSTRING])
-{
-// extern int Gdfra; /* sector.c */
-
- if (str == NULL) return;
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- sprintf(str, "%d", prop->data);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- sprintf(str, "%f", *((float *)&prop->data));
- break;
- case GPROP_STRING:
- BLI_strncpy(str, prop->poin, MAX_PROPSTRING);
- break;
- }
-}
-
-#if 0 /* UNUSED */
-void cp_property(bProperty *prop1, bProperty *prop2)
-{
- char str[128];
-
- BKE_bproperty_set_valstr(prop2, str);
-
- BKE_bproperty_set(prop1, str);
-}
-#endif
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 7fb313c838f..9ba3593f6b8 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -47,34 +47,39 @@
#endif
#include "DNA_ID.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_depsgraph.h"
+#include "BKE_collection.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
/* ************************************** */
/* Memory Management */
/* Freeing Methods --------------------- */
-#ifndef WITH_BULLET
+#ifdef WITH_BULLET
+static void rigidbody_update_ob_array(RigidBodyWorld *rbw);
+#else
static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {}
static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {}
static void RB_dworld_delete(void *UNUSED(world)) {}
@@ -85,44 +90,51 @@ static void RB_constraint_delete(void *UNUSED(con)) {}
#endif
/* Free rigidbody world */
-void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
+void BKE_rigidbody_free_world(Scene *scene)
{
+ bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ scene->rigidbody_world = NULL;
+
/* sanity check */
if (!rbw)
return;
- if (rbw->physics_world) {
+ if (is_orig && rbw->shared->physics_world) {
/* free physics references, we assume that all physics objects in will have been added to the world */
- GroupObject *go;
if (rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- if (go->ob && go->ob->rigidbody_constraint) {
- RigidBodyCon *rbc = go->ob->rigidbody_constraint;
-
- if (rbc->physics_constraint)
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object)
+ {
+ if (object->rigidbody_constraint) {
+ RigidBodyCon *rbc = object->rigidbody_constraint;
+ if (rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ }
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
- if (rbw->group) {
- for (go = rbw->group->gobject.first; go; go = go->next) {
- if (go->ob && go->ob->rigidbody_object) {
- RigidBodyOb *rbo = go->ob->rigidbody_object;
- if (rbo->physics_object)
- RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
- }
+ if (rbw->group) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ BKE_rigidbody_free_object(object, rbw);
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* free dynamics world */
- RB_dworld_delete(rbw->physics_world);
+ RB_dworld_delete(rbw->shared->physics_world);
}
if (rbw->objects)
free(rbw->objects);
- /* free cache */
- BKE_ptcache_free_list(&(rbw->ptcaches));
- rbw->pointcache = NULL;
+ if (is_orig) {
+ /* free cache */
+ BKE_ptcache_free_list(&(rbw->shared->ptcaches));
+ rbw->shared->pointcache = NULL;
+
+ MEM_freeN(rbw->shared);
+ }
/* free effector weights */
if (rbw->effector_weights)
@@ -133,8 +145,9 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
}
/* Free RigidBody settings and sim instances */
-void BKE_rigidbody_free_object(Object *ob)
+void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
{
+ bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL;
/* sanity check */
@@ -142,14 +155,26 @@ void BKE_rigidbody_free_object(Object *ob)
return;
/* free physics references */
- if (rbo->physics_object) {
- RB_body_delete(rbo->physics_object);
- rbo->physics_object = NULL;
- }
+ if (is_orig) {
+ if (rbo->shared->physics_object) {
+ BLI_assert(rbw);
+ if (rbw) {
+ /* We can only remove the body from the world if the world is known.
+ * The world is generally only unknown if it's an evaluated copy of
+ * an object that's being freed, in which case this code isn't run anyway. */
+ RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
+ }
- if (rbo->physics_shape) {
- RB_shape_delete(rbo->physics_shape);
- rbo->physics_shape = NULL;
+ RB_body_delete(rbo->shared->physics_object);
+ rbo->shared->physics_object = NULL;
+ }
+
+ if (rbo->shared->physics_shape) {
+ RB_shape_delete(rbo->shared->physics_shape);
+ rbo->shared->physics_shape = NULL;
+ }
+
+ MEM_freeN(rbo->shared);
}
/* free data itself */
@@ -186,7 +211,7 @@ void BKE_rigidbody_free_constraint(Object *ob)
* be added to relevant groups later...
*/
-RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag))
+RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag)
{
RigidBodyOb *rboN = NULL;
@@ -194,12 +219,13 @@ RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag))
/* just duplicate the whole struct first (to catch all the settings) */
rboN = MEM_dupallocN(ob->rigidbody_object);
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
+ rboN->shared = MEM_callocN(sizeof(*rboN->shared), "RigidBodyOb_Shared");
+ }
+
/* tag object as needing to be verified */
rboN->flag |= RBO_FLAG_NEEDS_VALIDATE;
-
- /* clear out all the fields which need to be revalidated later */
- rboN->physics_object = NULL;
- rboN->physics_shape = NULL;
}
/* return new copy of settings */
@@ -228,32 +254,39 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(f
/* ************************************** */
/* Setup Utilities - Validate Sim Instances */
-/* get the appropriate DerivedMesh based on rigid body mesh source */
-static DerivedMesh *rigidbody_get_mesh(Object *ob)
+/* get the appropriate evaluated mesh based on rigid body mesh source */
+static Mesh *rigidbody_get_mesh(Object *ob)
{
- if (ob->rigidbody_object->mesh_source == RBO_MESH_DEFORM) {
- return ob->derivedDeform;
- }
- else if (ob->rigidbody_object->mesh_source == RBO_MESH_FINAL) {
- return ob->derivedFinal;
- }
- else {
- return CDDM_from_mesh(ob->data);
- }
+ switch (ob->rigidbody_object->mesh_source) {
+ case RBO_MESH_DEFORM:
+ return ob->runtime.mesh_deform_eval;
+ case RBO_MESH_FINAL:
+ return ob->runtime.mesh_eval;
+ case RBO_MESH_BASE:
+ /* This mesh may be used for computing looptris, which should be done
+ * on the original; otherwise every time the CoW is recreated it will
+ * have to be recomputed. */
+ BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE);
+ return ob->runtime.mesh_orig;
+ }
+
+ /* Just return something sensible so that at least Blender won't crash. */
+ BLI_assert(!"Unknown mesh source");
+ return ob->runtime.mesh_eval;
}
/* create collision shape of mesh - convex hull */
static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed)
{
rbCollisionShape *shape = NULL;
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
MVert *mvert = NULL;
int totvert = 0;
if (ob->type == OB_MESH && ob->data) {
- dm = rigidbody_get_mesh(ob);
- mvert = (dm) ? dm->getVertArray(dm) : NULL;
- totvert = (dm) ? dm->getNumVerts(dm) : 0;
+ mesh = rigidbody_get_mesh(ob);
+ mvert = (mesh) ? mesh->mvert : NULL;
+ totvert = (mesh) ? mesh->totvert : 0;
}
else {
printf("ERROR: cannot make Convex Hull collision shape for non-Mesh object\n");
@@ -266,9 +299,6 @@ static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, fl
printf("ERROR: no vertices to define Convex Hull collision shape with\n");
}
- if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
- dm->release(dm);
-
return shape;
}
@@ -280,24 +310,24 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
rbCollisionShape *shape = NULL;
if (ob->type == OB_MESH) {
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
MVert *mvert;
const MLoopTri *looptri;
int totvert;
int tottri;
const MLoop *mloop;
- dm = rigidbody_get_mesh(ob);
+ mesh = rigidbody_get_mesh(ob);
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return NULL;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- looptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
/* sanity checking - potential case when no data will be present */
if ((totvert == 0) || (tottri == 0)) {
@@ -347,11 +377,6 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
shape = RB_shape_new_gimpact_mesh(mdata);
}
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
else {
printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n");
@@ -381,7 +406,7 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
return;
/* don't create a new shape if we already have one and don't want to rebuild it */
- if (rbo->physics_shape && !rebuild)
+ if (rbo->shared->physics_shape && !rebuild)
return;
/* if automatically determining dimensions, use the Object's boundbox
@@ -445,15 +470,16 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
break;
}
/* use box shape if we can't fall back to old shape */
- if (new_shape == NULL && rbo->physics_shape == NULL) {
+ if (new_shape == NULL && rbo->shared->physics_shape == NULL) {
new_shape = RB_shape_new_box(size[0], size[1], size[2]);
}
/* assign new collision shape if creation was successful */
if (new_shape) {
- if (rbo->physics_shape)
- RB_shape_delete(rbo->physics_shape);
- rbo->physics_shape = new_shape;
- RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo));
+ if (rbo->shared->physics_shape) {
+ RB_shape_delete(rbo->shared->physics_shape);
+ }
+ rbo->shared->physics_shape = new_shape;
+ RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo));
}
}
@@ -514,30 +540,25 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
case RB_SHAPE_TRIMESH:
{
if (ob->type == OB_MESH) {
- DerivedMesh *dm = rigidbody_get_mesh(ob);
+ Mesh *mesh = rigidbody_get_mesh(ob);
MVert *mvert;
const MLoopTri *lt = NULL;
int totvert, tottri = 0;
const MLoop *mloop = NULL;
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- lt = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ lt = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
if (totvert > 0 && tottri > 0) {
BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL);
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
else {
/* rough estimate from boundbox as fallback */
@@ -546,12 +567,6 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
}
break;
}
-
-#if 0 // XXX: not defined yet
- case RB_SHAPE_COMPOUND:
- volume = 0.0f;
- break;
-#endif
}
/* return the volume calculated */
@@ -597,39 +612,28 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
case RB_SHAPE_TRIMESH:
{
if (ob->type == OB_MESH) {
- DerivedMesh *dm = rigidbody_get_mesh(ob);
+ Mesh *mesh = rigidbody_get_mesh(ob);
MVert *mvert;
const MLoopTri *looptri;
int totvert, tottri;
const MLoop *mloop;
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- looptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
if (totvert > 0 && tottri > 0) {
BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center);
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
break;
}
-
-#if 0 // XXX: not defined yet
- case RB_SHAPE_COMPOUND:
- volume = 0.0f;
- break;
-#endif
}
}
@@ -654,48 +658,48 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* make sure collision shape exists */
/* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */
- if (rbo->physics_shape == NULL || rebuild)
+ if (rbo->shared->physics_shape == NULL || rebuild)
rigidbody_validate_sim_shape(ob, true);
- if (rbo->physics_object && rebuild == false) {
- RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
+ if (rbo->shared->physics_object) {
+ RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
}
- if (!rbo->physics_object || rebuild) {
+ if (!rbo->shared->physics_object || rebuild) {
/* remove rigid body if it already exists before creating a new one */
- if (rbo->physics_object) {
- RB_body_delete(rbo->physics_object);
+ if (rbo->shared->physics_object) {
+ RB_body_delete(rbo->shared->physics_object);
}
mat4_to_loc_quat(loc, rot, ob->obmat);
- rbo->physics_object = RB_body_new(rbo->physics_shape, loc, rot);
+ rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot);
- RB_body_set_friction(rbo->physics_object, rbo->friction);
- RB_body_set_restitution(rbo->physics_object, rbo->restitution);
+ RB_body_set_friction(rbo->shared->physics_object, rbo->friction);
+ RB_body_set_restitution(rbo->shared->physics_object, rbo->restitution);
- RB_body_set_damping(rbo->physics_object, rbo->lin_damping, rbo->ang_damping);
- RB_body_set_sleep_thresh(rbo->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
- RB_body_set_activation_state(rbo->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION);
+ RB_body_set_damping(rbo->shared->physics_object, rbo->lin_damping, rbo->ang_damping);
+ RB_body_set_sleep_thresh(rbo->shared->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
+ RB_body_set_activation_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION);
if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED)
- RB_body_deactivate(rbo->physics_object);
+ RB_body_deactivate(rbo->shared->physics_object);
- RB_body_set_linear_factor(rbo->physics_object,
+ RB_body_set_linear_factor(rbo->shared->physics_object,
(ob->protectflag & OB_LOCK_LOCX) == 0,
(ob->protectflag & OB_LOCK_LOCY) == 0,
(ob->protectflag & OB_LOCK_LOCZ) == 0);
- RB_body_set_angular_factor(rbo->physics_object,
+ RB_body_set_angular_factor(rbo->shared->physics_object,
(ob->protectflag & OB_LOCK_ROTX) == 0,
(ob->protectflag & OB_LOCK_ROTY) == 0,
(ob->protectflag & OB_LOCK_ROTZ) == 0);
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
- RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
+ RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
}
- if (rbw && rbw->physics_world)
- RB_dworld_add_body(rbw->physics_world, rbo->physics_object, rbo->col_groups);
+ if (rbw && rbw->shared->physics_world)
+ RB_dworld_add_body(rbw->shared->physics_world, rbo->shared->physics_object, rbo->col_groups);
}
/* --------------------- */
@@ -729,7 +733,8 @@ static void rigidbody_constraint_init_spring(
set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
}
-static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float))
+static void rigidbody_constraint_set_limits(
+ RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float))
{
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
@@ -787,7 +792,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
if (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) {
if (rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
RB_constraint_delete(rbc->physics_constraint);
rbc->physics_constraint = NULL;
}
@@ -795,11 +800,11 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
}
if (rbc->physics_constraint && rebuild == false) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
}
if (rbc->physics_constraint == NULL || rebuild) {
- rbRigidBody *rb1 = rbc->ob1->rigidbody_object->physics_object;
- rbRigidBody *rb2 = rbc->ob2->rigidbody_object->physics_object;
+ rbRigidBody *rb1 = rbc->ob1->rigidbody_object->shared->physics_object;
+ rbRigidBody *rb2 = rbc->ob2->rigidbody_object->shared->physics_object;
/* remove constraint if it already exists before creating a new one */
if (rbc->physics_constraint) {
@@ -903,8 +908,8 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
RB_constraint_set_solver_iterations(rbc->physics_constraint, -1);
}
- if (rbw && rbw->physics_world && rbc->physics_constraint) {
- RB_dworld_add_constraint(rbw->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS);
+ if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
+ RB_dworld_add_constraint(rbw->shared->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS);
}
}
@@ -919,14 +924,14 @@ void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool re
return;
/* create new sim world */
- if (rebuild || rbw->physics_world == NULL) {
- if (rbw->physics_world)
- RB_dworld_delete(rbw->physics_world);
- rbw->physics_world = RB_dworld_new(scene->physics_settings.gravity);
+ if (rebuild || rbw->shared->physics_world == NULL) {
+ if (rbw->shared->physics_world)
+ RB_dworld_delete(rbw->shared->physics_world);
+ rbw->shared->physics_world = RB_dworld_new(scene->physics_settings.gravity);
}
- RB_dworld_set_solver_iterations(rbw->physics_world, rbw->num_solver_iterations);
- RB_dworld_set_split_impulse(rbw->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE);
+ RB_dworld_set_solver_iterations(rbw->shared->physics_world, rbw->num_solver_iterations);
+ RB_dworld_set_split_impulse(rbw->shared->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE);
}
/* ************************************** */
@@ -947,6 +952,7 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
/* create a new sim world */
rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld");
+ rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared");
/* set default settings */
rbw->effector_weights = BKE_add_effector_weights(NULL);
@@ -958,8 +964,8 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
rbw->steps_per_second = 60; /* Bullet default (60 Hz) */
rbw->num_solver_iterations = 10; /* 10 is bullet default */
- rbw->pointcache = BKE_ptcache_add(&(rbw->ptcaches));
- rbw->pointcache->step = 1;
+ rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches));
+ rbw->shared->pointcache->step = 1;
/* return this sim world */
return rbw;
@@ -977,12 +983,16 @@ RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag)
id_us_plus((ID *)rbw_copy->constraints);
}
- /* XXX Never copy caches here? */
- rbw_copy->pointcache = BKE_ptcache_copy_list(&rbw_copy->ptcaches, &rbw->ptcaches, flag & ~LIB_ID_COPY_CACHES);
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
+ rbw_copy->shared = MEM_callocN(sizeof(*rbw_copy->shared), "RigidBodyWorld_Shared");
+ BKE_ptcache_copy_list(&rbw_copy->shared->ptcaches, &rbw->shared->ptcaches, LIB_ID_COPY_CACHES);
+ rbw_copy->shared->pointcache = rbw_copy->shared->ptcaches.first;
+ }
rbw_copy->objects = NULL;
- rbw_copy->physics_world = NULL;
rbw_copy->numbodies = 0;
+ rigidbody_update_ob_array(rbw_copy);
return rbw_copy;
}
@@ -1024,6 +1034,7 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
/* create new settings data, and link it up */
rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb");
+ rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyOb_Shared");
/* set default settings */
rbo->type = type;
@@ -1038,8 +1049,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */
rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */
- rbo->lin_damping = 0.04f; /* 0.04 is game engine default */
- rbo->ang_damping = 0.1f; /* 0.1 is game engine default */
+ rbo->lin_damping = 0.04f;
+ rbo->ang_damping = 0.1f;
rbo->col_groups = 1;
@@ -1148,18 +1159,13 @@ RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
return scene->rigidbody_world;
}
-void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
+void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
- RigidBodyOb *rbo = ob->rigidbody_object;
RigidBodyCon *rbc;
- GroupObject *go;
int i;
if (rbw) {
- /* remove from rigidbody world, free object won't do this */
- if (rbw->physics_world && rbo->physics_object)
- RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
/* remove object from array */
if (rbw && rbw->objects) {
@@ -1173,8 +1179,8 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
/* remove object from rigid body constraints */
if (rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *obt = go->ob;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, obt)
+ {
if (obt && obt->rigidbody_constraint) {
rbc = obt->rigidbody_constraint;
if (ELEM(ob, rbc->ob1, rbc->ob2)) {
@@ -1182,11 +1188,13 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
}
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
+ BKE_collection_object_remove(bmain, rbw->group, ob, false);
}
/* remove object's settings */
- BKE_rigidbody_free_object(ob);
+ BKE_rigidbody_free_object(ob, rbw);
/* flag cache as outdated */
BKE_rigidbody_cache_reset(rbw);
@@ -1198,8 +1206,8 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
RigidBodyCon *rbc = ob->rigidbody_constraint;
/* remove from rigidbody world, free object won't do this */
- if (rbw && rbw->physics_world && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
}
/* remove object's settings */
BKE_rigidbody_free_constraint(ob);
@@ -1215,20 +1223,32 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
/* Update object array and rigid body count so they're in sync with the rigid body group */
static void rigidbody_update_ob_array(RigidBodyWorld *rbw)
{
- GroupObject *go;
- int i, n;
+ if (rbw->group == NULL) {
+ rbw->numbodies = 0;
+ rbw->objects = realloc(rbw->objects, 0);
+ return;
+ }
- n = BLI_listbase_count(&rbw->group->gobject);
+ int n = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ (void)object;
+ n++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
if (rbw->numbodies != n) {
rbw->numbodies = n;
rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies);
}
- for (go = rbw->group->gobject.first, i = 0; go; go = go->next, i++) {
- Object *ob = go->ob;
- rbw->objects[i] = ob;
+ int i = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ rbw->objects[i] = object;
+ i++;
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
@@ -1245,51 +1265,51 @@ static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
}
/* update gravity, since this RNA setting is not part of RigidBody settings */
- RB_dworld_set_gravity(rbw->physics_world, adj_gravity);
+ RB_dworld_set_gravity(rbw->shared->physics_world, adj_gravity);
/* update object array in case there are changes */
rigidbody_update_ob_array(rbw);
}
-static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
+static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
{
float loc[3];
float rot[4];
float scale[3];
/* only update if rigid body exists */
- if (rbo->physics_object == NULL)
+ if (rbo->shared->physics_object == NULL)
return;
if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
- DerivedMesh *dm = ob->derivedDeform;
- if (dm) {
- MVert *mvert = dm->getVertArray(dm);
- int totvert = dm->getNumVerts(dm);
+ Mesh *mesh = ob->runtime.mesh_deform_eval;
+ if (mesh) {
+ MVert *mvert = mesh->mvert;
+ int totvert = mesh->totvert;
BoundBox *bb = BKE_object_boundbox_get(ob);
- RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
+ RB_shape_trimesh_update(rbo->shared->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
}
}
mat4_decompose(loc, rot, scale, ob->obmat);
/* update scale for all objects */
- RB_body_set_scale(rbo->physics_object, scale);
+ RB_body_set_scale(rbo->shared->physics_object, scale);
/* compensate for embedded convex hull collision margin */
if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH)
- RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2]));
+ RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2]));
/* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */
if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) {
- RB_body_set_kinematic_state(rbo->physics_object, true);
- RB_body_set_mass(rbo->physics_object, 0.0f);
+ RB_body_set_kinematic_state(rbo->shared->physics_object, true);
+ RB_body_set_mass(rbo->shared->physics_object, 0.0f);
}
/* update rigid body location and rotation for kinematic bodies */
if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
- RB_body_activate(rbo->physics_object);
- RB_body_set_loc_rot(rbo->physics_object, loc, rot);
+ RB_body_activate(rbo->shared->physics_object);
+ RB_body_set_loc_rot(rbo->shared->physics_object, loc, rot);
}
/* update influence of effectors - but don't do it on an effector */
/* only dynamic bodies need effector update */
@@ -1299,34 +1319,34 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
ListBase *effectors;
/* get effectors present in the group specified by effector_weights */
- effectors = pdInitEffectors(scene, ob, NULL, effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights);
if (effectors) {
float eff_force[3] = {0.0f, 0.0f, 0.0f};
float eff_loc[3], eff_vel[3];
/* create dummy 'point' which represents last known position of object as result of sim */
// XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals?
- RB_body_get_position(rbo->physics_object, eff_loc);
- RB_body_get_linear_velocity(rbo->physics_object, eff_vel);
+ RB_body_get_position(rbo->shared->physics_object, eff_loc);
+ RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
/* calculate net force of effectors, and apply to sim object
* - we use 'central force' since apply force requires a "relative position" which we don't have...
*/
- pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
+ BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
if (G.f & G_DEBUG)
printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
/* activate object in case it is deactivated */
if (!is_zero_v3(eff_force))
- RB_body_activate(rbo->physics_object);
- RB_body_apply_central_force(rbo->physics_object, eff_force);
+ RB_body_activate(rbo->shared->physics_object);
+ RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
}
else if (G.f & G_DEBUG)
printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
/* cleanup */
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
/* NOTE: passive objects don't need to be updated since they don't move */
@@ -1340,10 +1360,8 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
*
* \param rebuild Rebuild entire simulation
*/
-static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
+static void rigidbody_update_simulation(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
- GroupObject *go;
-
/* update world */
if (rebuild)
BKE_rigidbody_validate_sim_world(scene, rbw, true);
@@ -1356,28 +1374,26 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
* Memory management needs redesign here, this is just a dirty workaround.
*/
if (rebuild && rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
- if (ob) {
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- if (rbc && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
- RB_constraint_delete(rbc->physics_constraint);
- rbc->physics_constraint = NULL;
- }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob)
+ {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* update objects */
- for (go = rbw->group->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
-
- if (ob && ob->type == OB_MESH) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob)
+ {
+ if (ob->type == OB_MESH) {
/* validate that we've got valid object set up here... */
RigidBodyOb *rbo = ob->rigidbody_object;
/* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
if (rbo == NULL) {
/* Since this object is included in the sim group but doesn't have
@@ -1394,6 +1410,9 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
/* refresh object... */
if (rebuild) {
/* World has been rebuilt so rebuild object */
+ /* TODO(Sybren): rigidbody_validate_sim_object() can call rigidbody_validate_sim_shape(),
+ * but neither resets the RBO_FLAG_NEEDS_RESHAPE flag nor calls RB_body_set_collision_shape().
+ * This results in the collision shape being created twice, which is unnecessary. */
rigidbody_validate_sim_object(rbw, ob, true);
}
else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) {
@@ -1405,76 +1424,75 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
rigidbody_validate_sim_shape(ob, true);
/* now tell RB sim about it */
// XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies
- RB_body_set_collision_shape(rbo->physics_object, rbo->physics_shape);
+ RB_body_set_collision_shape(rbo->shared->physics_object, rbo->shared->physics_shape);
}
rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
}
/* update simulation object... */
- rigidbody_update_sim_ob(scene, rbw, ob, rbo);
+ rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo);
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
/* update constraints */
if (rbw->constraints == NULL) /* no constraints, move on */
return;
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
- if (ob) {
- /* validate that we've got valid object set up here... */
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc(scene, ob);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob)
+ {
+ /* validate that we've got valid object set up here... */
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
+ BKE_object_where_is_calc(depsgraph, scene, ob);
- if (rbc == NULL) {
- /* Since this object is included in the group but doesn't have
- * constraint settings (perhaps it was added manually), add!
- */
- ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
- rigidbody_validate_sim_constraint(rbw, ob, true);
+ if (rbc == NULL) {
+ /* Since this object is included in the group but doesn't have
+ * constraint settings (perhaps it was added manually), add!
+ */
+ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
+ rigidbody_validate_sim_constraint(rbw, ob, true);
- rbc = ob->rigidbody_constraint;
+ rbc = ob->rigidbody_constraint;
+ }
+ else {
+ /* perform simulation data updates as tagged */
+ if (rebuild) {
+ /* World has been rebuilt so rebuild constraint */
+ rigidbody_validate_sim_constraint(rbw, ob, true);
}
- else {
- /* perform simulation data updates as tagged */
- if (rebuild) {
- /* World has been rebuilt so rebuild constraint */
- rigidbody_validate_sim_constraint(rbw, ob, true);
- }
- else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
- rigidbody_validate_sim_constraint(rbw, ob, false);
- }
- rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
+ else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
+ rigidbody_validate_sim_constraint(rbw, ob, false);
}
+ rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
-static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw)
+static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, RigidBodyWorld *rbw)
{
- GroupObject *go;
-
- for (go = rbw->group->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
-
- if (ob) {
- RigidBodyOb *rbo = ob->rigidbody_object;
- /* reset kinematic state for transformed objects */
- if (rbo && (ob->flag & SELECT) && (G.moving & G_TRANSFORM_OBJ)) {
- RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
- /* deactivate passive objects so they don't interfere with deactivation of active objects */
- if (rbo->type == RBO_TYPE_PASSIVE)
- RB_body_deactivate(rbo->physics_object);
- }
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob)
+ {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Reset kinematic state for transformed objects. */
+ if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) {
+ RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
+ /* Deactivate passive objects so they don't interfere with deactivation of active objects. */
+ if (rbo->type == RBO_TYPE_PASSIVE)
+ RB_body_deactivate(rbo->shared->physics_object);
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
{
- return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->pointcache->startframe);
+ return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe);
}
/* Sync rigid body and object transformations */
@@ -1564,11 +1582,11 @@ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], flo
copy_qt_qt(ob->quat, quat);
}
- if (rbo->physics_object) {
+ if (rbo->shared->physics_object) {
/* allow passive objects to return to original transform */
if (rbo->type == RBO_TYPE_PASSIVE)
- RB_body_set_kinematic_state(rbo->physics_object, true);
- RB_body_set_loc_rot(rbo->physics_object, rbo->pos, rbo->orn);
+ RB_body_set_kinematic_state(rbo->shared->physics_object, true);
+ RB_body_set_loc_rot(rbo->shared->physics_object, rbo->pos, rbo->orn);
}
// RB_TODO update rigid body physics object's loc/rot for dynamic objects here as well (needs to be done outside bullet's update loop)
}
@@ -1576,7 +1594,7 @@ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], flo
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
{
if (rbw) {
- rbw->pointcache->flag |= PTCACHE_OUTDATED;
+ rbw->shared->pointcache->flag |= PTCACHE_OUTDATED;
}
}
@@ -1584,7 +1602,7 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* Rebuild rigid body world */
/* NOTE: this needs to be called before frame update to work correctly */
-void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
+void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
PointCache *cache;
@@ -1593,17 +1611,25 @@ void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
- cache = rbw->pointcache;
+ cache = rbw->shared->pointcache;
/* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */
- if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&rbw->group->gobject)) {
+ int n = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ (void)object;
+ n++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ if (rbw->shared->physics_world == NULL || rbw->numbodies != n) {
cache->flag |= PTCACHE_OUTDATED;
}
if (ctime == startframe + 1 && rbw->ltime == startframe) {
if (cache->flag & PTCACHE_OUTDATED) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- rigidbody_update_simulation(scene, rbw, true);
+ rigidbody_update_simulation(depsgraph, scene, rbw, true);
BKE_ptcache_validate(cache, (int)ctime);
cache->last_exact = 0;
cache->flag &= ~PTCACHE_REDO_NEEDED;
@@ -1612,7 +1638,7 @@ void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
}
/* Run RigidBody simulation for the specified physics world */
-void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
+void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime)
{
float timestep;
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -1622,7 +1648,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
- cache = rbw->pointcache;
+ cache = rbw->shared->pointcache;
if (ctime <= startframe) {
rbw->ltime = startframe;
@@ -1634,7 +1660,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
}
/* don't try to run the simulation if we don't have a world yet but allow reading baked cache */
- if (rbw->physics_world == NULL && !(cache->flag & PTCACHE_BAKED))
+ if (rbw->shared->physics_world == NULL && !(cache->flag & PTCACHE_BAKED))
return;
else if (rbw->objects == NULL)
rigidbody_update_ob_array(rbw);
@@ -1649,22 +1675,28 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
return;
}
+ if (!DEG_is_active(depsgraph)) {
+ /* When the depsgraph is inactive we should neither write to the cache
+ * nor run the simulation. */
+ return;
+ }
+
/* advance simulation, we can only step one frame forward */
- if (can_simulate) {
+ if (compare_ff_relative(ctime, rbw->ltime + 1, FLT_EPSILON, 64)) {
/* write cache for first frame when on second frame */
if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
BKE_ptcache_write(&pid, startframe);
}
/* update and validate simulation */
- rigidbody_update_simulation(scene, rbw, false);
+ rigidbody_update_simulation(depsgraph, scene, rbw, false);
/* calculate how much time elapsed since last step in seconds */
timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale;
/* step simulation by the requested timestep, steps per second are adjusted to take time scale into account */
- RB_dworld_step_simulation(rbw->physics_world, timestep, INT_MAX, 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f));
+ RB_dworld_step_simulation(rbw->shared->physics_world, timestep, INT_MAX, 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f));
- rigidbody_update_simulation_post_step(rbw);
+ rigidbody_update_simulation_post_step(depsgraph, rbw);
/* write cache for current frame */
BKE_ptcache_validate(cache, (int)ctime);
@@ -1695,14 +1727,14 @@ void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFun
struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; }
struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) { return NULL; }
struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { return NULL; }
-void BKE_rigidbody_remove_object(Scene *scene, Object *ob) {}
+void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) {}
void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) {}
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) {}
void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) {}
bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) { return false; }
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) {}
-void BKE_rigidbody_rebuild_world(Scene *scene, float ctime) {}
-void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
+void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) {}
+void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) {}
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic pop
@@ -1710,38 +1742,42 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
#endif /* WITH_BULLET */
+
+
/* -------------------- */
/* Depsgraph evaluation */
-void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_rebuild_sim(Depsgraph *depsgraph,
Scene *scene)
{
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
/* rebuild sim data (i.e. after resetting to start of timeline) */
if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_rigidbody_rebuild_world(scene, ctime);
+ BKE_rigidbody_rebuild_world(depsgraph, scene, ctime);
}
}
-void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_eval_simulation(Depsgraph *depsgraph,
Scene *scene)
{
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
+
/* evaluate rigidbody sim */
- if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_rigidbody_do_simulation(scene, ctime);
+ if (!BKE_scene_check_rigidbody_active(scene)) {
+ return;
}
+ BKE_rigidbody_do_simulation(depsgraph, scene, ctime);
}
-void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_object_sync_transforms(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, ob->id.name, ob, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, ob->id.name, ob, ctime);
/* read values pushed into RBO from sim/cache... */
BKE_rigidbody_sync_transforms(rbw, ob, ctime);
}
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
deleted file mode 100644
index 56e64387096..00000000000
--- a/source/blender/blenkernel/intern/sca.c
+++ /dev/null
@@ -1,1178 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- * these all are linked to objects (listbase)
- * all data is 'direct data', not Blender lib data.
- */
-
-/** \file blender/blenkernel/intern/sca.c
- * \ingroup bke
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#include <float.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_controller_types.h"
-#include "DNA_sensor_types.h"
-#include "DNA_actuator_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
-#include "BLI_math.h"
-
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_library.h"
-#include "BKE_library_query.h"
-#include "BKE_sca.h"
-
-/* ******************* SENSORS ************************ */
-
-void free_sensor(bSensor *sens)
-{
- if (sens->links) MEM_freeN(sens->links);
- if (sens->data) MEM_freeN(sens->data);
- MEM_freeN(sens);
-
-}
-
-void free_sensors(ListBase *lb)
-{
- bSensor *sens;
-
- while ((sens = BLI_pophead(lb))) {
- free_sensor(sens);
- }
-}
-
-bSensor *copy_sensor(bSensor *sens, const int UNUSED(flag))
-{
- bSensor *sensn;
-
- sensn= MEM_dupallocN(sens);
- sensn->flag |= SENS_NEW;
- if (sens->data) {
- sensn->data= MEM_dupallocN(sens->data);
- }
-
- if (sens->links) sensn->links= MEM_dupallocN(sens->links);
-
- return sensn;
-}
-
-void copy_sensors(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bSensor *sens, *sensn;
-
- lbn->first= lbn->last= NULL;
- sens= lbo->first;
- while (sens) {
- sensn= copy_sensor(sens, flag);
- BLI_addtail(lbn, sensn);
- sens= sens->next;
- }
-}
-
-void init_sensor(bSensor *sens)
-{
- /* also use when sensor changes type */
- bNearSensor *ns;
- bMouseSensor *ms;
- bJoystickSensor *js;
- bRaySensor *rs;
-
- if (sens->data) MEM_freeN(sens->data);
- sens->data= NULL;
- sens->pulse = 0;
-
- switch (sens->type) {
- case SENS_ALWAYS:
- sens->pulse = 0;
- break;
- case SENS_NEAR:
- ns=sens->data= MEM_callocN(sizeof(bNearSensor), "nearsens");
- ns->dist= 1.0;
- ns->resetdist= 2.0;
- break;
- case SENS_KEYBOARD:
- sens->data= MEM_callocN(sizeof(bKeyboardSensor), "keysens");
- break;
- case SENS_PROPERTY:
- sens->data= MEM_callocN(sizeof(bPropertySensor), "propsens");
- break;
- case SENS_ARMATURE:
- sens->data= MEM_callocN(sizeof(bArmatureSensor), "armsens");
- break;
- case SENS_ACTUATOR:
- sens->data= MEM_callocN(sizeof(bActuatorSensor), "actsens");
- break;
- case SENS_DELAY:
- sens->data= MEM_callocN(sizeof(bDelaySensor), "delaysens");
- break;
- case SENS_MOUSE:
- ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens");
- ms->type= 1; // LEFTMOUSE workaround because Mouse Sensor types enum starts in 1
- break;
- case SENS_COLLISION:
- sens->data= MEM_callocN(sizeof(bCollisionSensor), "colsens");
- break;
- case SENS_RADAR:
- sens->data= MEM_callocN(sizeof(bRadarSensor), "radarsens");
- break;
- case SENS_RANDOM:
- sens->data= MEM_callocN(sizeof(bRandomSensor), "randomsens");
- break;
- case SENS_RAY:
- sens->data= MEM_callocN(sizeof(bRaySensor), "raysens");
- rs = sens->data;
- rs->range = 0.01f;
- break;
- case SENS_MESSAGE:
- sens->data= MEM_callocN(sizeof(bMessageSensor), "messagesens");
- break;
- case SENS_JOYSTICK:
- sens->data= MEM_callocN(sizeof(bJoystickSensor), "joysticksens");
- js= sens->data;
- js->hatf = SENS_JOY_HAT_UP;
- js->axis = 1;
- js->hat = 1;
- break;
- default:
- ; /* this is very severe... I cannot make any memory for this */
- /* logic brick... */
- }
-}
-
-bSensor *new_sensor(int type)
-{
- bSensor *sens;
-
- sens= MEM_callocN(sizeof(bSensor), "Sensor");
- sens->type= type;
- sens->flag= SENS_SHOW;
-
- init_sensor(sens);
-
- strcpy(sens->name, "sensor");
-// XXX make_unique_prop_names(sens->name);
-
- return sens;
-}
-
-/* ******************* CONTROLLERS ************************ */
-
-void unlink_controller(bController *cont)
-{
- bSensor *sens;
- Object *ob;
-
- /* check for controller pointers in sensors */
- ob= G.main->object.first;
- while (ob) {
- sens= ob->sensors.first;
- while (sens) {
- unlink_logicbricks((void **)&cont, (void ***)&(sens->links), &sens->totlinks);
- sens= sens->next;
- }
- ob= ob->id.next;
- }
-}
-
-void unlink_controllers(ListBase *lb)
-{
- bController *cont;
-
- for (cont= lb->first; cont; cont= cont->next)
- unlink_controller(cont);
-}
-
-void free_controller(bController *cont)
-{
- if (cont->links) MEM_freeN(cont->links);
-
- /* the controller itself */
- if (cont->data) MEM_freeN(cont->data);
- MEM_freeN(cont);
-
-}
-
-void free_controllers(ListBase *lb)
-{
- bController *cont;
-
- while ((cont = BLI_pophead(lb))) {
- if (cont->slinks)
- MEM_freeN(cont->slinks);
- free_controller(cont);
- }
-}
-
-bController *copy_controller(bController *cont, const int UNUSED(flag))
-{
- bController *contn;
-
- cont->mynew=contn= MEM_dupallocN(cont);
- contn->flag |= CONT_NEW;
- if (cont->data) {
- contn->data= MEM_dupallocN(cont->data);
- }
-
- if (cont->links) contn->links= MEM_dupallocN(cont->links);
- contn->slinks= NULL;
- contn->totslinks= 0;
-
- return contn;
-}
-
-void copy_controllers(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bController *cont, *contn;
-
- lbn->first= lbn->last= NULL;
- cont= lbo->first;
- while (cont) {
- contn= copy_controller(cont, flag);
- BLI_addtail(lbn, contn);
- cont= cont->next;
- }
-}
-
-void init_controller(bController *cont)
-{
- /* also use when controller changes type, leave actuators... */
-
- if (cont->data) MEM_freeN(cont->data);
- cont->data= NULL;
-
- switch (cont->type) {
- case CONT_EXPRESSION:
- cont->data= MEM_callocN(sizeof(bExpressionCont), "expcont");
- break;
- case CONT_PYTHON:
- cont->data= MEM_callocN(sizeof(bPythonCont), "pycont");
- break;
- }
-}
-
-bController *new_controller(int type)
-{
- bController *cont;
-
- cont= MEM_callocN(sizeof(bController), "Controller");
- cont->type= type;
- cont->flag= CONT_SHOW;
-
- init_controller(cont);
-
- strcpy(cont->name, "cont");
-// XXX make_unique_prop_names(cont->name);
-
- return cont;
-}
-
-/* ******************* ACTUATORS ************************ */
-
-void unlink_actuator(bActuator *act)
-{
- bController *cont;
- Object *ob;
-
- /* check for actuator pointers in controllers */
- ob= G.main->object.first;
- while (ob) {
- cont= ob->controllers.first;
- while (cont) {
- unlink_logicbricks((void **)&act, (void ***)&(cont->links), &cont->totlinks);
- cont= cont->next;
- }
- ob= ob->id.next;
- }
-}
-
-void unlink_actuators(ListBase *lb)
-{
- bActuator *act;
-
- for (act= lb->first; act; act= act->next)
- unlink_actuator(act);
-}
-
-void free_actuator(bActuator *act)
-{
- if (act->data) {
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- {
- bActionActuator *aa = (bActionActuator *)act->data;
- if (aa->act)
- id_us_min((ID *)aa->act);
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = (bSoundActuator *) act->data;
- if (sa->sound)
- id_us_min((ID *)sa->sound);
- break;
- }
- }
-
- MEM_freeN(act->data);
- }
- MEM_freeN(act);
-}
-
-void free_actuators(ListBase *lb)
-{
- bActuator *act;
-
- while ((act = BLI_pophead(lb))) {
- free_actuator(act);
- }
-}
-
-bActuator *copy_actuator(bActuator *act, const int flag)
-{
- bActuator *actn;
-
- act->mynew=actn= MEM_dupallocN(act);
- actn->flag |= ACT_NEW;
- if (act->data) {
- actn->data= MEM_dupallocN(act->data);
- }
-
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- {
- bActionActuator *aa = (bActionActuator *)act->data;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)aa->act);
- }
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = (bSoundActuator *)act->data;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)sa->sound);
- }
- break;
- }
- }
- return actn;
-}
-
-void copy_actuators(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bActuator *act, *actn;
-
- lbn->first= lbn->last= NULL;
- act= lbo->first;
- while (act) {
- actn= copy_actuator(act, flag);
- BLI_addtail(lbn, actn);
- act= act->next;
- }
-}
-
-void init_actuator(bActuator *act)
-{
- /* also use when actuator changes type */
- bCameraActuator *ca;
- bObjectActuator *oa;
- bRandomActuator *ra;
- bSoundActuator *sa;
- bSteeringActuator *sta;
- bArmatureActuator *arma;
- bMouseActuator *ma;
- bEditObjectActuator *eoa;
-
- if (act->data) MEM_freeN(act->data);
- act->data= NULL;
-
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- act->data= MEM_callocN(sizeof(bActionActuator), "actionact");
- break;
- case ACT_SOUND:
- sa = act->data= MEM_callocN(sizeof(bSoundActuator), "soundact");
- sa->volume = 1.0f;
- sa->sound3D.rolloff_factor = 1.0f;
- sa->sound3D.reference_distance = 1.0f;
- sa->sound3D.max_gain = 1.0f;
- sa->sound3D.cone_inner_angle = DEG2RADF(360.0f);
- sa->sound3D.cone_outer_angle = DEG2RADF(360.0f);
- sa->sound3D.max_distance = FLT_MAX;
- break;
- case ACT_OBJECT:
- act->data= MEM_callocN(sizeof(bObjectActuator), "objectact");
- oa= act->data;
- oa->flag= 15;
- break;
- case ACT_PROPERTY:
- act->data= MEM_callocN(sizeof(bPropertyActuator), "propact");
- break;
- case ACT_CAMERA:
- act->data= MEM_callocN(sizeof(bCameraActuator), "camact");
- ca = act->data;
- ca->axis = OB_POSX;
- ca->damping = 1.0/32.0;
- break;
- case ACT_EDIT_OBJECT:
- act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact");
- eoa = act->data;
- eoa->upflag= ACT_TRACK_UP_Z;
- eoa->trackflag= ACT_TRACK_TRAXIS_Y;
- break;
- case ACT_CONSTRAINT:
- act->data= MEM_callocN(sizeof(bConstraintActuator), "cons act");
- break;
- case ACT_SCENE:
- act->data= MEM_callocN(sizeof(bSceneActuator), "scene act");
- break;
- case ACT_GROUP:
- act->data= MEM_callocN(sizeof(bGroupActuator), "group act");
- break;
- case ACT_RANDOM:
- act->data= MEM_callocN(sizeof(bRandomActuator), "random act");
- ra=act->data;
- ra->float_arg_1 = 0.1f;
- break;
- case ACT_MESSAGE:
- act->data= MEM_callocN(sizeof(bMessageActuator), "message act");
- break;
- case ACT_GAME:
- act->data= MEM_callocN(sizeof(bGameActuator), "game act");
- break;
- case ACT_VISIBILITY:
- act->data= MEM_callocN(sizeof(bVisibilityActuator), "visibility act");
- break;
- case ACT_2DFILTER:
- act->data = MEM_callocN(sizeof( bTwoDFilterActuator ), "2d filter act");
- break;
- case ACT_PARENT:
- act->data = MEM_callocN(sizeof( bParentActuator ), "parent act");
- break;
- case ACT_STATE:
- act->data = MEM_callocN(sizeof( bStateActuator ), "state act");
- break;
- case ACT_ARMATURE:
- act->data = MEM_callocN(sizeof( bArmatureActuator ), "armature act");
- arma = act->data;
- arma->influence = 1.f;
- break;
- case ACT_STEERING:
- act->data = MEM_callocN(sizeof( bSteeringActuator), "steering act");
- sta = act->data;
- sta->acceleration = 3.f;
- sta->turnspeed = 120.f;
- sta->dist = 1.f;
- sta->velocity= 3.f;
- sta->flag = ACT_STEERING_AUTOMATICFACING | ACT_STEERING_LOCKZVEL;
- sta->facingaxis = 1;
- break;
- case ACT_MOUSE:
- ma = act->data = MEM_callocN(sizeof( bMouseActuator ), "mouse act");
- ma->flag = ACT_MOUSE_VISIBLE|ACT_MOUSE_USE_AXIS_X|ACT_MOUSE_USE_AXIS_Y|ACT_MOUSE_RESET_X|ACT_MOUSE_RESET_Y|ACT_MOUSE_LOCAL_Y;
- ma->sensitivity[0] = ma->sensitivity[1] = 2.f;
- ma->object_axis[0] = ACT_MOUSE_OBJECT_AXIS_Z;
- ma->object_axis[1] = ACT_MOUSE_OBJECT_AXIS_X;
- ma->limit_y[0] = DEG2RADF(-90.0f);
- ma->limit_y[1] = DEG2RADF(90.0f);
- break;
- default:
- ; /* this is very severe... I cannot make any memory for this */
- /* logic brick... */
- }
-}
-
-bActuator *new_actuator(int type)
-{
- bActuator *act;
-
- act= MEM_callocN(sizeof(bActuator), "Actuator");
- act->type= type;
- act->flag= ACT_SHOW;
-
- init_actuator(act);
-
- strcpy(act->name, "act");
-// XXX make_unique_prop_names(act->name);
-
- return act;
-}
-
-/* ******************** GENERAL ******************* */
-void clear_sca_new_poins_ob(Object *ob)
-{
- bSensor *sens;
- bController *cont;
- bActuator *act;
-
- sens= ob->sensors.first;
- while (sens) {
- sens->flag &= ~SENS_NEW;
- sens= sens->next;
- }
- cont= ob->controllers.first;
- while (cont) {
- cont->mynew= NULL;
- cont->flag &= ~CONT_NEW;
- cont= cont->next;
- }
- act= ob->actuators.first;
- while (act) {
- act->mynew= NULL;
- act->flag &= ~ACT_NEW;
- act= act->next;
- }
-}
-
-void clear_sca_new_poins(void)
-{
- Object *ob;
-
- ob= G.main->object.first;
- while (ob) {
- clear_sca_new_poins_ob(ob);
- ob= ob->id.next;
- }
-}
-
-void set_sca_new_poins_ob(Object *ob)
-{
- bSensor *sens;
- bController *cont;
- bActuator *act;
- int a;
-
- sens= ob->sensors.first;
- while (sens) {
- if (sens->flag & SENS_NEW) {
- for (a=0; a<sens->totlinks; a++) {
- if (sens->links[a] && sens->links[a]->mynew)
- sens->links[a] = sens->links[a]->mynew;
- }
- }
- sens= sens->next;
- }
-
- cont= ob->controllers.first;
- while (cont) {
- if (cont->flag & CONT_NEW) {
- for (a=0; a<cont->totlinks; a++) {
- if ( cont->links[a] && cont->links[a]->mynew)
- cont->links[a] = cont->links[a]->mynew;
- }
- }
- cont= cont->next;
- }
-
-
- act= ob->actuators.first;
- while (act) {
- if (act->flag & ACT_NEW) {
- if (act->type==ACT_EDIT_OBJECT) {
- bEditObjectActuator *eoa= act->data;
- ID_NEW_REMAP(eoa->ob);
- }
- else if (act->type==ACT_SCENE) {
- bSceneActuator *sca= act->data;
- ID_NEW_REMAP(sca->camera);
- }
- else if (act->type==ACT_CAMERA) {
- bCameraActuator *ca= act->data;
- ID_NEW_REMAP(ca->ob);
- }
- else if (act->type==ACT_OBJECT) {
- bObjectActuator *oa= act->data;
- ID_NEW_REMAP(oa->reference);
- }
- else if (act->type==ACT_MESSAGE) {
- bMessageActuator *ma= act->data;
- ID_NEW_REMAP(ma->toObject);
- }
- else if (act->type==ACT_PARENT) {
- bParentActuator *para = act->data;
- ID_NEW_REMAP(para->ob);
- }
- else if (act->type==ACT_ARMATURE) {
- bArmatureActuator *aa = act->data;
- ID_NEW_REMAP(aa->target);
- ID_NEW_REMAP(aa->subtarget);
- }
- else if (act->type==ACT_PROPERTY) {
- bPropertyActuator *pa= act->data;
- ID_NEW_REMAP(pa->ob);
- }
- else if (act->type==ACT_STEERING) {
- bSteeringActuator *sta = act->data;
- ID_NEW_REMAP(sta->navmesh);
- ID_NEW_REMAP(sta->target);
- }
- }
- act= act->next;
- }
-}
-
-
-void set_sca_new_poins(void)
-{
- Object *ob;
-
- ob= G.main->object.first;
- while (ob) {
- set_sca_new_poins_ob(ob);
- ob= ob->id.next;
- }
-}
-
-/**
- * Try to remap logic links to new object... Very, *very* weak.
- */
-/* XXX Logick bricks... I don't have words to say what I think about this behavior.
- * They have silent hidden ugly inter-objects dependencies (a sensor can link into any other
- * object's controllers, and same between controllers and actuators, without *any* explicit reference
- * to data-block involved).
- * This is bad, bad, bad!!!
- * ...and forces us to add yet another very ugly hack to get remapping with logic bricks working. */
-void BKE_sca_logic_links_remap(Main *bmain, Object *ob_old, Object *ob_new)
-{
- if (ob_new == NULL || (ob_old->controllers.first == NULL && ob_old->actuators.first == NULL)) {
- /* Nothing to do here... */
- return;
- }
-
- GHash *controllers_map = ob_old->controllers.first ?
- BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->controllers)) : NULL;
- GHash *actuators_map = ob_old->actuators.first ?
- BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->actuators)) : NULL;
-
- /* We try to remap old controllers/actuators to new ones - in a very basic way. */
- for (bController *cont_old = ob_old->controllers.first, *cont_new = ob_new->controllers.first;
- cont_old;
- cont_old = cont_old->next)
- {
- bController *cont_new2 = cont_new;
-
- if (cont_old->mynew != NULL) {
- cont_new2 = cont_old->mynew;
- if (!(cont_new2 == cont_new || BLI_findindex(&ob_new->controllers, cont_new2) >= 0)) {
- cont_new2 = NULL;
- }
- }
- else if (cont_new && cont_old->type != cont_new->type) {
- cont_new2 = NULL;
- }
-
- BLI_ghash_insert(controllers_map, cont_old, cont_new2);
-
- if (cont_new) {
- cont_new = cont_new->next;
- }
- }
-
- for (bActuator *act_old = ob_old->actuators.first, *act_new = ob_new->actuators.first;
- act_old;
- act_old = act_old->next)
- {
- bActuator *act_new2 = act_new;
-
- if (act_old->mynew != NULL) {
- act_new2 = act_old->mynew;
- if (!(act_new2 == act_new || BLI_findindex(&ob_new->actuators, act_new2) >= 0)) {
- act_new2 = NULL;
- }
- }
- else if (act_new && act_old->type != act_new->type) {
- act_new2 = NULL;
- }
-
- BLI_ghash_insert(actuators_map, act_old, act_new2);
-
- if (act_new) {
- act_new = act_new->next;
- }
- }
-
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- if (controllers_map != NULL) {
- for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) {
- for (int a = 0; a < sens->totlinks; a++) {
- if (sens->links[a]) {
- bController *old_link = sens->links[a];
- bController **new_link_p = (bController **)BLI_ghash_lookup_p(controllers_map, old_link);
-
- if (new_link_p == NULL) {
- /* old_link is *not* in map's keys (i.e. not to any ob_old->controllers),
- * which means we ignore it totally here. */
- }
- else if (*new_link_p == NULL) {
- unlink_logicbricks((void **)&old_link, (void ***)&(sens->links), &sens->totlinks);
- a--;
- }
- else {
- sens->links[a] = *new_link_p;
- }
- }
- }
- }
- }
-
- if (actuators_map != NULL) {
- for (bController *cont = ob->controllers.first; cont; cont = cont->next) {
- for (int a = 0; a < cont->totlinks; a++) {
- if (cont->links[a]) {
- bActuator *old_link = cont->links[a];
- bActuator **new_link_p = (bActuator **)BLI_ghash_lookup_p(actuators_map, old_link);
-
- if (new_link_p == NULL) {
- /* old_link is *not* in map's keys (i.e. not to any ob_old->actuators),
- * which means we ignore it totally here. */
- }
- else if (*new_link_p == NULL) {
- unlink_logicbricks((void **)&old_link, (void ***)&(cont->links), &cont->totlinks);
- a--;
- }
- else {
- cont->links[a] = *new_link_p;
- }
- }
- }
- }
- }
- }
-
- if (controllers_map) {
- BLI_ghash_free(controllers_map, NULL, NULL);
- }
- if (actuators_map) {
- BLI_ghash_free(actuators_map, NULL, NULL);
- }
-}
-
-/**
- * Handle the copying of logic data into a new object, including internal logic links update.
- * External links (links between logic bricks of different objects) must be handled separately.
- */
-void BKE_sca_logic_copy(Object *ob_new, const Object *ob, const int flag)
-{
- copy_sensors(&ob_new->sensors, &ob->sensors, flag);
- copy_controllers(&ob_new->controllers, &ob->controllers, flag);
- copy_actuators(&ob_new->actuators, &ob->actuators, flag);
-
- for (bSensor *sens = ob_new->sensors.first; sens; sens = sens->next) {
- if (sens->flag & SENS_NEW) {
- for (int a = 0; a < sens->totlinks; a++) {
- if (sens->links[a] && sens->links[a]->mynew) {
- sens->links[a] = sens->links[a]->mynew;
- }
- }
- }
- }
-
- for (bController *cont = ob_new->controllers.first; cont; cont = cont->next) {
- if (cont->flag & CONT_NEW) {
- for (int a = 0; a < cont->totlinks; a++) {
- if (cont->links[a] && cont->links[a]->mynew) {
- cont->links[a] = cont->links[a]->mynew;
- }
- }
- }
- }
-}
-
-/* ******************** INTERFACE ******************* */
-void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up)
-{
- bSensor *sens, *tmp;
-
- int val;
- val = move_up ? 1 : 2;
-
- /* make sure this sensor belongs to this object */
- sens= ob->sensors.first;
- while (sens) {
- if (sens == sens_to_move) break;
- sens= sens->next;
- }
- if (!sens) return;
-
- /* move up */
- if (val == 1 && sens->prev) {
- for (tmp=sens->prev; tmp; tmp=tmp->prev) {
- if (tmp->flag & SENS_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->sensors, sens);
- BLI_insertlinkbefore(&ob->sensors, tmp, sens);
- }
- }
- /* move down */
- else if (val == 2 && sens->next) {
- for (tmp=sens->next; tmp; tmp=tmp->next) {
- if (tmp->flag & SENS_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->sensors, sens);
- BLI_insertlinkafter(&ob->sensors, tmp, sens);
- }
- }
-}
-
-void sca_move_controller(bController *cont_to_move, Object *ob, int move_up)
-{
- bController *cont, *tmp;
-
- int val;
- val = move_up ? 1 : 2;
-
- /* make sure this controller belongs to this object */
- cont= ob->controllers.first;
- while (cont) {
- if (cont == cont_to_move) break;
- cont= cont->next;
- }
- if (!cont) return;
-
- /* move up */
- if (val == 1 && cont->prev) {
- /* locate the controller that has the same state mask but is earlier in the list */
- tmp = cont->prev;
- while (tmp) {
- if (tmp->state_mask & cont->state_mask)
- break;
- tmp = tmp->prev;
- }
- if (tmp) {
- BLI_remlink(&ob->controllers, cont);
- BLI_insertlinkbefore(&ob->controllers, tmp, cont);
- }
- }
-
- /* move down */
- else if (val == 2 && cont->next) {
- tmp = cont->next;
- while (tmp) {
- if (tmp->state_mask & cont->state_mask)
- break;
- tmp = tmp->next;
- }
- BLI_remlink(&ob->controllers, cont);
- BLI_insertlinkafter(&ob->controllers, tmp, cont);
- }
-}
-
-void sca_move_actuator(bActuator *act_to_move, Object *ob, int move_up)
-{
- bActuator *act, *tmp;
- int val;
-
- val = move_up ? 1 : 2;
-
- /* make sure this actuator belongs to this object */
- act= ob->actuators.first;
- while (act) {
- if (act == act_to_move) break;
- act= act->next;
- }
- if (!act) return;
-
- /* move up */
- if (val == 1 && act->prev) {
- /* locate the first visible actuators before this one */
- for (tmp = act->prev; tmp; tmp=tmp->prev) {
- if (tmp->flag & ACT_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->actuators, act);
- BLI_insertlinkbefore(&ob->actuators, tmp, act);
- }
- }
- /* move down */
- else if (val == 2 && act->next) {
- /* locate the first visible actuators after this one */
- for (tmp=act->next; tmp; tmp=tmp->next) {
- if (tmp->flag & ACT_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->actuators, act);
- BLI_insertlinkafter(&ob->actuators, tmp, act);
- }
- }
-}
-
-void link_logicbricks(void **poin, void ***ppoin, short *tot, short size)
-{
- void **old_links= NULL;
-
- int ibrick;
-
- /* check if the bricks are already linked */
- for (ibrick=0; ibrick < *tot; ibrick++) {
- if ((*ppoin)[ibrick] == *poin)
- return;
- }
-
- if (*ppoin) {
- old_links= *ppoin;
-
- (*tot) ++;
- *ppoin = MEM_callocN((*tot)*size, "new link");
-
- for (ibrick=0; ibrick < *(tot) - 1; ibrick++) {
- (*ppoin)[ibrick] = old_links[ibrick];
- }
- (*ppoin)[ibrick] = *poin;
-
- if (old_links) MEM_freeN(old_links);
- }
- else {
- (*tot) = 1;
- *ppoin = MEM_callocN((*tot)*size, "new link");
- (*ppoin)[0] = *poin;
- }
-}
-
-void unlink_logicbricks(void **poin, void ***ppoin, short *tot)
-{
- int ibrick, removed;
-
- removed= 0;
- for (ibrick=0; ibrick < *tot; ibrick++) {
- if (removed) (*ppoin)[ibrick - removed] = (*ppoin)[ibrick];
- else if ((*ppoin)[ibrick] == *poin) removed = 1;
- }
-
- if (removed) {
- (*tot) --;
-
- if (*tot == 0) {
- MEM_freeN(*ppoin);
- (*ppoin)= NULL;
- }
- return;
- }
-}
-
-void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *userdata)
-{
- bSensor *sensor;
-
- for (sensor = senslist->first; sensor; sensor = sensor->next) {
- func(sensor, (ID **)&sensor->ob, userdata, IDWALK_CB_NOP);
-
- switch (sensor->type) {
- case SENS_TOUCH: /* DEPRECATED */
- {
- bTouchSensor *ts = sensor->data;
- func(sensor, (ID **)&ts->ma, userdata, IDWALK_CB_NOP);
- break;
- }
- case SENS_MESSAGE:
- {
- bMessageSensor *ms = sensor->data;
- func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_CB_NOP);
- break;
- }
- case SENS_ALWAYS:
- case SENS_NEAR:
- case SENS_KEYBOARD:
- case SENS_PROPERTY:
- case SENS_MOUSE:
- case SENS_COLLISION:
- case SENS_RADAR:
- case SENS_RANDOM:
- case SENS_RAY:
- case SENS_JOYSTICK:
- case SENS_ACTUATOR:
- case SENS_DELAY:
- case SENS_ARMATURE:
- default:
- break;
- }
- }
-}
-
-void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, void *userdata)
-{
- bController *controller;
-
- for (controller = contlist->first; controller; controller = controller->next) {
- switch (controller->type) {
- case CONT_PYTHON:
- {
- bPythonCont *pc = controller->data;
- func(controller, (ID **)&pc->text, userdata, IDWALK_CB_NOP);
- break;
- }
- case CONT_LOGIC_AND:
- case CONT_LOGIC_OR:
- case CONT_EXPRESSION:
- case CONT_LOGIC_NAND:
- case CONT_LOGIC_NOR:
- case CONT_LOGIC_XOR:
- case CONT_LOGIC_XNOR:
- default:
- break;
- }
- }
-}
-
-void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *userdata)
-{
- bActuator *actuator;
-
- for (actuator = actlist->first; actuator; actuator = actuator->next) {
- func(actuator, (ID **)&actuator->ob, userdata, IDWALK_CB_NOP);
-
- switch (actuator->type) {
- case ACT_ADD_OBJECT: /* DEPRECATED */
- {
- bAddObjectActuator *aoa = actuator->data;
- func(actuator, (ID **)&aoa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_ACTION:
- {
- bActionActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->act, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->sound, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_EDIT_OBJECT:
- {
- bEditObjectActuator *eoa = actuator->data;
- func(actuator, (ID **)&eoa->ob, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&eoa->me, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_SCENE:
- {
- bSceneActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->scene, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&sa->camera, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_PROPERTY:
- {
- bPropertyActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_OBJECT:
- {
- bObjectActuator *oa = actuator->data;
- func(actuator, (ID **)&oa->reference, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_CAMERA:
- {
- bCameraActuator *ca = actuator->data;
- func(actuator, (ID **)&ca->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_MESSAGE:
- {
- bMessageActuator *ma = actuator->data;
- func(actuator, (ID **)&ma->toObject, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_2DFILTER:
- {
- bTwoDFilterActuator *tdfa = actuator->data;
- func(actuator, (ID **)&tdfa->text, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_PARENT:
- {
- bParentActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_ARMATURE:
- {
- bArmatureActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->target, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_STEERING:
- {
- bSteeringActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->target, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_CB_NOP);
- break;
- }
- /* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */
- case ACT_LAMP:
- case ACT_MATERIAL:
- case ACT_END_OBJECT: /* DEPRECATED */
- case ACT_CONSTRAINT:
- case ACT_GROUP:
- case ACT_RANDOM:
- case ACT_GAME:
- case ACT_VISIBILITY:
- case ACT_SHAPEACTION:
- case ACT_STATE:
- case ACT_MOUSE:
- default:
- break;
- }
- }
-}
-
-const char *sca_state_name_get(Object *ob, short bit)
-{
- bController *cont;
- unsigned int mask;
-
- mask = (1<<bit);
- cont = ob->controllers.first;
- while (cont) {
- if (cont->state_mask & mask) {
- return cont->name;
- }
- cont = cont->next;
- }
- return NULL;
-}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3947ca157c0..090c016ed00 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -37,7 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
@@ -49,6 +49,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_gpencil_types.h"
#include "BLI_math.h"
@@ -67,17 +68,17 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_colortools.h"
-#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_group.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -92,12 +93,18 @@
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_unit.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
#include "RE_engine.h"
+#include "engines/eevee/eevee_lightcache.h"
+
#include "PIL_time.h"
#include "IMB_colormanagement.h"
@@ -105,8 +112,8 @@
#include "bmesh.h"
-const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER";
-const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME";
+const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
+const char *RE_engine_id_BLENDER_WORKBENCH = "BLENDER_WORKBENCH";
const char *RE_engine_id_CYCLES = "CYCLES";
void free_avicodecdata(AviCodecData *acd)
@@ -166,6 +173,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
}
+ if (ts->gp_paint) {
+ ts->gp_paint = MEM_dupallocN(ts->gp_paint);
+ BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag);
+ }
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
ts->imapaint.paintcursor = NULL;
@@ -173,15 +184,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->particle.scene = NULL;
ts->particle.object = NULL;
- /* duplicate Grease Pencil Drawing Brushes */
- BLI_listbase_clear(&ts->gp_brushes);
- for (bGPDbrush *brush = toolsettings->gp_brushes.first; brush; brush = brush->next) {
- bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
- BLI_addtail(&ts->gp_brushes, newbrush);
- }
-
/* duplicate Grease Pencil interpolation curve */
ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
+ /* duplicate Grease Pencil multiframe fallof */
+ ts->gp_sculpt.cur_falloff = curvemapping_copy(ts->gp_sculpt.cur_falloff);
return ts;
}
@@ -206,16 +212,20 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_paint_free(&toolsettings->uvsculpt->paint);
MEM_freeN(toolsettings->uvsculpt);
}
+ if (toolsettings->gp_paint) {
+ BKE_paint_free(&toolsettings->gp_paint->paint);
+ MEM_freeN(toolsettings->gp_paint);
+ }
BKE_paint_free(&toolsettings->imapaint.paint);
- /* free Grease Pencil Drawing Brushes */
- BKE_gpencil_free_brushes(&toolsettings->gp_brushes);
- BLI_freelistN(&toolsettings->gp_brushes);
-
/* free Grease Pencil interpolation curve */
if (toolsettings->gp_interpolate.custom_ipo) {
curvemapping_free(toolsettings->gp_interpolate.custom_ipo);
}
+ /* free Grease Pencil multiframe falloff curve */
+ if (toolsettings->gp_sculpt.cur_falloff) {
+ curvemapping_free(toolsettings->gp_sculpt.cur_falloff);
+ }
MEM_freeN(toolsettings);
}
@@ -234,25 +244,25 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
sce_dst->ed = NULL;
- sce_dst->theDag = NULL;
- sce_dst->depsgraph = NULL;
- sce_dst->obedit = NULL;
- sce_dst->stats = NULL;
+ sce_dst->depsgraph_hash = NULL;
sce_dst->fps_info = NULL;
- BLI_duplicatelist(&(sce_dst->base), &(sce_src->base));
- for (Base *base_dst = sce_dst->base.first, *base_src = sce_src->base.first;
- base_dst;
- base_dst = base_dst->next, base_src = base_src->next)
+ /* Master Collection */
+ if (sce_src->master_collection) {
+ sce_dst->master_collection = BKE_collection_copy_master(bmain, sce_src->master_collection, flag);
+ }
+
+ /* View Layers */
+ BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers);
+ for (ViewLayer *view_layer_src = sce_src->view_layers.first, *view_layer_dst = sce_dst->view_layers.first;
+ view_layer_src;
+ view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next)
{
- if (base_src == sce_src->basact) {
- sce_dst->basact = base_dst;
- }
+ BKE_view_layer_copy_data(sce_dst, sce_src, view_layer_dst, view_layer_src, flag_subdata);
}
BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers));
BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces));
- BLI_duplicatelist(&(sce_dst->r.layers), &(sce_src->r.layers));
BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views));
BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets));
@@ -267,17 +277,6 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata);
}
- /* copy Freestyle settings */
- for (SceneRenderLayer *srl_dst = sce_dst->r.layers.first, *srl_src = sce_src->r.layers.first;
- srl_src;
- srl_dst = srl_dst->next, srl_src = srl_src->next)
- {
- if (srl_dst->prop != NULL) {
- srl_dst->prop = IDP_CopyProperty_ex(srl_dst->prop, flag_subdata);
- }
- BKE_freestyle_config_copy(&srl_dst->freestyleConfig, &srl_src->freestyleConfig, flag_subdata);
- }
-
/* copy color management settings */
BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings);
BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings);
@@ -322,6 +321,9 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
else {
sce_dst->preview = NULL;
}
+
+ sce_dst->eevee.light_cache = NULL;
+ /* TODO Copy the cache. */
}
Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
@@ -331,20 +333,16 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* TODO this should/could most likely be replaced by call to more generic code at some point...
* But for now, let's keep it well isolated here. */
if (type == SCE_COPY_EMPTY) {
- ListBase rl, rv;
+ ListBase rv;
sce_copy = BKE_scene_add(bmain, sce->id.name + 2);
- rl = sce_copy->r.layers;
rv = sce_copy->r.views;
curvemapping_free_data(&sce_copy->r.mblur_shutter_curve);
sce_copy->r = sce->r;
- sce_copy->r.layers = rl;
- sce_copy->r.actlay = 0;
sce_copy->r.views = rv;
sce_copy->unit = sce->unit;
sce_copy->physics_settings = sce->physics_settings;
- sce_copy->gm = sce->gm;
sce_copy->audio = sce->audio;
if (sce->id.properties)
@@ -366,6 +364,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
+ /* viewport display settings */
+ sce_copy->display = sce->display;
+
/* tool settings */
sce_copy->toolsettings = BKE_toolsettings_copy(sce->toolsettings, 0);
@@ -399,8 +400,8 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (type == SCE_COPY_FULL) {
/* Copy Freestyle LineStyle datablocks. */
- for (SceneRenderLayer *srl_dst = sce_copy->r.layers.first; srl_dst; srl_dst = srl_dst->next) {
- for (FreestyleLineSet *lineset = srl_dst->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (ViewLayer *view_layer_dst = sce_copy->view_layers.first; view_layer_dst; view_layer_dst = view_layer_dst->next) {
+ for (FreestyleLineSet *lineset = view_layer_dst->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
id_us_min(&lineset->linestyle->id);
/* XXX Not copying anim/actions here? */
@@ -415,6 +416,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS, false);
}
+ /* Collections */
+ BKE_collection_copy_full(bmain, sce_copy->master_collection);
+
/* Full copy of GreasePencil. */
/* XXX Not copying anim/actions here? */
if (sce_copy->gpd) {
@@ -430,7 +434,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
/* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations
- * are done outside of blenkernel with ED_objects_single_users! */
+ * are done outside of blenkernel with ED_object_single_users! */
/* camera */
/* XXX This is most certainly useless? Object have not yet been duplicated... */
@@ -456,15 +460,11 @@ void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local)
}
/** Free (or release) any data used by this scene (does not free the scene itself). */
-void BKE_scene_free(Scene *sce)
+void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
{
- SceneRenderLayer *srl;
-
BKE_animdata_free((ID *)sce, false);
- sce->basact = NULL;
- BLI_freelistN(&sce->base);
- BKE_sequencer_editing_free(sce, false);
+ BKE_sequencer_editing_free(sce, do_id_user);
BKE_keyingsets_free(&sce->keyingsets);
@@ -476,8 +476,7 @@ void BKE_scene_free(Scene *sce)
}
if (sce->rigidbody_world) {
- BKE_rigidbody_free_world(sce->rigidbody_world);
- sce->rigidbody_world = NULL;
+ BKE_rigidbody_free_world(sce);
}
if (sce->r.avicodecdata) {
@@ -491,27 +490,15 @@ void BKE_scene_free(Scene *sce)
sce->r.ffcodecdata.properties = NULL;
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- if (srl->prop != NULL) {
- IDP_FreeProperty(srl->prop);
- MEM_freeN(srl->prop);
- }
- BKE_freestyle_config_free(&srl->freestyleConfig);
- }
-
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
- BLI_freelistN(&sce->r.layers);
BLI_freelistN(&sce->r.views);
BKE_toolsettings_free(sce->toolsettings);
sce->toolsettings = NULL;
- DAG_scene_free(sce);
- if (sce->depsgraph)
- DEG_graph_free(sce->depsgraph);
+ BKE_scene_free_depsgraph_hash(sce);
- MEM_SAFE_FREE(sce->stats);
MEM_SAFE_FREE(sce->fps_info);
BKE_sound_destroy_scene(sce);
@@ -520,6 +507,37 @@ void BKE_scene_free(Scene *sce)
BKE_previewimg_free(&sce->preview);
curvemapping_free_data(&sce->r.mblur_shutter_curve);
+
+ for (ViewLayer *view_layer = sce->view_layers.first, *view_layer_next; view_layer; view_layer = view_layer_next) {
+ view_layer_next = view_layer->next;
+
+ BLI_remlink(&sce->view_layers, view_layer);
+ BKE_view_layer_free_ex(view_layer, do_id_user);
+ }
+
+ /* Master Collection */
+ // TODO: what to do with do_id_user? it's also true when just
+ // closing the file which seems wrong? should decrement users
+ // for objects directly in the master collection? then other
+ // collections in the scene need to do it too?
+ if (sce->master_collection) {
+ BKE_collection_free(sce->master_collection);
+ MEM_freeN(sce->master_collection);
+ sce->master_collection = NULL;
+ }
+
+ if (sce->eevee.light_cache) {
+ EEVEE_lightcache_free(sce->eevee.light_cache);
+ sce->eevee.light_cache = NULL;
+ }
+
+ /* These are freed on doversion. */
+ BLI_assert(sce->layer_properties == NULL);
+}
+
+void BKE_scene_free(Scene *sce)
+{
+ BKE_scene_free_ex(sce, true);
}
void BKE_scene_init(Scene *sce)
@@ -532,9 +550,9 @@ void BKE_scene_init(Scene *sce)
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(sce, id));
- sce->lay = sce->layact = 1;
+ unit_qt(sce->cursor.rotation);
- sce->r.mode = R_GAMMA | R_OSA | R_SHADOW | R_SSS | R_ENVMAP | R_RAYTRACE;
+ sce->r.mode = R_OSA;
sce->r.cfra = 1;
sce->r.sfra = 1;
sce->r.efra = 250;
@@ -545,9 +563,7 @@ void BKE_scene_init(Scene *sce)
sce->r.yasp = 1;
sce->r.tilex = 256;
sce->r.tiley = 256;
- sce->r.mblur_samples = 1;
- sce->r.filtertype = R_FILTER_MITCH;
- sce->r.size = 50;
+ sce->r.size = 100;
sce->r.im_format.planes = R_IMF_PLANES_RGBA;
sce->r.im_format.imtype = R_IMF_IMTYPE_PNG;
@@ -555,15 +571,13 @@ void BKE_scene_init(Scene *sce)
sce->r.im_format.quality = 90;
sce->r.im_format.compress = 15;
- sce->r.displaymode = R_OUTPUT_AREA;
+ sce->r.displaymode = R_OUTPUT_WINDOW;
sce->r.framapto = 100;
sce->r.images = 100;
sce->r.framelen = 1.0;
sce->r.blurfac = 0.5;
sce->r.frs_sec = 24;
sce->r.frs_sec_base = 1;
- sce->r.edgeint = 10;
- sce->r.ocres = 128;
/* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used,
* images would look in the same way as in current blender
@@ -572,18 +586,11 @@ void BKE_scene_init(Scene *sce)
*/
sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
- sce->r.gauss = 1.0;
+ sce->r.dither_intensity = 1.0f;
- /* deprecated but keep for upwards compat */
- sce->r.postgamma = 1.0;
- sce->r.posthue = 0.0;
- sce->r.postsat = 1.0;
-
- sce->r.bake_mode = 1; /* prevent to include render stuff here */
+ sce->r.bake_mode = 0;
sce->r.bake_filter = 16;
- sce->r.bake_osa = 5;
sce->r.bake_flag = R_BAKE_CLEAR;
- sce->r.bake_normal_space = R_BAKE_SPACE_TANGENT;
sce->r.bake_samples = 256;
sce->r.bake_biasdist = 0.001;
@@ -611,7 +618,6 @@ void BKE_scene_init(Scene *sce)
sce->r.fg_stamp[3] = 1.0f;
sce->r.bg_stamp[0] = sce->r.bg_stamp[1] = sce->r.bg_stamp[2] = 0.0f;
sce->r.bg_stamp[3] = 0.25f;
- sce->r.raytrace_options = R_RAYTRACE_USE_INSTANCES;
sce->r.seq_prev_type = OB_SOLID;
sce->r.seq_rend_type = OB_SOLID;
@@ -621,8 +627,6 @@ void BKE_scene_init(Scene *sce)
sce->r.simplify_subsurf = 6;
sce->r.simplify_particles = 1.0f;
- sce->r.simplify_shadowsamples = 16;
- sce->r.simplify_aosss = 1.0f;
sce->r.border.xmin = 0.0f;
sce->r.border.ymin = 0.0f;
@@ -643,33 +647,25 @@ void BKE_scene_init(Scene *sce)
CURVEMAP_SLOPE_POS_NEG);
sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
+
+ sce->toolsettings->object_flag |= SCE_OBJECT_MODE_LOCK;
sce->toolsettings->doublimit = 0.001;
sce->toolsettings->vgroup_weight = 1.0f;
sce->toolsettings->uvcalc_margin = 0.001f;
+ sce->toolsettings->uvcalc_flag = UVCALC_TRANSFORM_CORRECT;
sce->toolsettings->unwrapper = 1;
sce->toolsettings->select_thresh = 0.01f;
+ sce->toolsettings->gizmo_flag = SCE_GIZMO_SHOW_TRANSLATE | SCE_GIZMO_SHOW_ROTATE | SCE_GIZMO_SHOW_SCALE;
sce->toolsettings->selectmode = SCE_SELECT_VERTEX;
sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX;
- sce->toolsettings->normalsize = 0.1;
sce->toolsettings->autokey_mode = U.autokey_mode;
- sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
- sce->toolsettings->skgen_resolution = 100;
- sce->toolsettings->skgen_threshold_internal = 0.01f;
- sce->toolsettings->skgen_threshold_external = 0.01f;
- sce->toolsettings->skgen_angle_limit = 45.0f;
- sce->toolsettings->skgen_length_ratio = 1.3f;
- sce->toolsettings->skgen_length_limit = 1.5f;
- sce->toolsettings->skgen_correlation_limit = 0.98f;
- sce->toolsettings->skgen_symmetry_limit = 0.1f;
- sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
- sce->toolsettings->skgen_postpro_passes = 1;
- sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL | SKGEN_FILTER_EXTERNAL | SKGEN_FILTER_SMART | SKGEN_HARMONIC | SKGEN_SUB_CORRELATION | SKGEN_STICK_TO_EMBEDDING;
- sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
- sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
+ sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN;
+ sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT;
+ sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
+ sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT;
sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
@@ -694,12 +690,25 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->imapaint.normal_angle = 80;
sce->toolsettings->imapaint.seam_bleed = 2;
+ /* grease pencil multiframe falloff curve */
+ sce->toolsettings->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff;
+ curvemapping_initialize(gp_falloff_curve);
+ curvemap_reset(gp_falloff_curve->cm,
+ &gp_falloff_curve->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+
sce->physics_settings.gravity[0] = 0.0f;
sce->physics_settings.gravity[1] = 0.0f;
sce->physics_settings.gravity[2] = -9.81f;
sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY;
+ sce->unit.system = USER_UNIT_METRIC;
sce->unit.scale_length = 1.0f;
+ sce->unit.length_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH);
+ sce->unit.mass_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
+ sce->unit.time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
pset = &sce->toolsettings->particle;
pset->flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY;
@@ -724,12 +733,13 @@ void BKE_scene_init(Scene *sce)
sce->r.ffcodecdata.audio_bitrate = 192;
sce->r.ffcodecdata.audio_channels = 2;
- BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_RENDER, sizeof(sce->r.engine));
+ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
sce->audio.distance_model = 2.0f;
sce->audio.doppler_factor = 1.0f;
sce->audio.speed_of_sound = 343.3f;
sce->audio.volume = 1.0f;
+ sce->audio.flag = AUDIO_SYNC;
BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic));
@@ -737,7 +747,6 @@ void BKE_scene_init(Scene *sce)
sce->r.osa = 8;
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
- BKE_scene_add_render_layer(sce, NULL);
/* multiview - stereo */
BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
@@ -748,59 +757,6 @@ void BKE_scene_init(Scene *sce)
srv = sce->r.views.last;
BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
- /* game data */
- sce->gm.stereoflag = STEREO_NOSTEREO;
- sce->gm.stereomode = STEREO_ANAGLYPH;
- sce->gm.eyeseparation = 0.10;
-
- sce->gm.dome.angle = 180;
- sce->gm.dome.mode = DOME_FISHEYE;
- sce->gm.dome.res = 4;
- sce->gm.dome.resbuf = 1.0f;
- sce->gm.dome.tilt = 0;
-
- sce->gm.xplay = 640;
- sce->gm.yplay = 480;
- sce->gm.freqplay = 60;
- sce->gm.depth = 32;
-
- sce->gm.gravity = 9.8f;
- sce->gm.physicsEngine = WOPHY_BULLET;
- sce->gm.mode = 32; //XXX ugly harcoding, still not sure we should drop mode. 32 == 1 << 5 == use_occlusion_culling
- sce->gm.occlusionRes = 128;
- sce->gm.ticrate = 60;
- sce->gm.maxlogicstep = 5;
- sce->gm.physubstep = 1;
- sce->gm.maxphystep = 5;
- sce->gm.lineardeactthreshold = 0.8f;
- sce->gm.angulardeactthreshold = 1.0f;
- sce->gm.deactivationtime = 0.0f;
-
- sce->gm.flag = GAME_DISPLAY_LISTS;
- sce->gm.matmode = GAME_MAT_MULTITEX;
-
- sce->gm.obstacleSimulation = OBSTSIMULATION_NONE;
- sce->gm.levelHeight = 2.f;
-
- sce->gm.recastData.cellsize = 0.3f;
- sce->gm.recastData.cellheight = 0.2f;
- sce->gm.recastData.agentmaxslope = M_PI_4;
- sce->gm.recastData.agentmaxclimb = 0.9f;
- sce->gm.recastData.agentheight = 2.0f;
- sce->gm.recastData.agentradius = 0.6f;
- sce->gm.recastData.edgemaxlen = 12.0f;
- sce->gm.recastData.edgemaxerror = 1.3f;
- sce->gm.recastData.regionminsize = 8.f;
- sce->gm.recastData.regionmergesize = 20.f;
- sce->gm.recastData.vertsperpoly = 6;
- sce->gm.recastData.detailsampledist = 6.0f;
- sce->gm.recastData.detailsamplemaxerror = 1.0f;
-
- sce->gm.lodflag = SCE_LOD_USE_HYST;
- sce->gm.scehysteresis = 10;
-
- sce->gm.exitkey = 218; // Blender key code for ESC
-
BKE_sound_create_scene(sce);
/* color management */
@@ -821,48 +777,67 @@ void BKE_scene_init(Scene *sce)
/* GP Sculpt brushes */
{
- GP_BrushEdit_Settings *gset = &sce->toolsettings->gp_sculpt;
- GP_EditBrush_Data *gp_brush;
+ GP_Sculpt_Settings *gset = &sce->toolsettings->gp_sculpt;
+ GP_Sculpt_Data *gp_brush;
+ float curcolor_add[3], curcolor_sub[3];
+ ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
+ ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
- gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_SMOOTH_PRESSURE | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_THICKNESS];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_STRENGTH];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_GRAB];
gp_brush->size = 50;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_PUSH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_TWIST];
gp_brush->size = 50;
- gp_brush->strength = 0.3f; // XXX?
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->strength = 0.3f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_PINCH];
gp_brush->size = 50;
- gp_brush->strength = 0.5f; // XXX?
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
+ gp_brush = &gset->brush[GP_SCULPT_TYPE_RANDOMIZE];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
/* GP Stroke Placement */
@@ -870,6 +845,90 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+
+ /* Annotations */
+ sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ sce->toolsettings->annotate_thickness = 3;
+
+ sce->orientation_index_custom = -1;
+
+ /* Master Collection */
+ sce->master_collection = BKE_collection_master_add();
+
+ BKE_view_layer_add(sce, "View Layer");
+
+ /* SceneDisplay */
+ copy_v3_v3(sce->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3});
+ sce->display.shadow_shift = 0.1;
+
+ sce->display.matcap_ssao_distance = 0.2f;
+ sce->display.matcap_ssao_attenuation = 1.0f;
+ sce->display.matcap_ssao_samples = 16;
+
+ /* OpenGL Render. */
+ BKE_screen_view3d_shading_init(&sce->display.shading);
+
+ /* SceneEEVEE */
+ sce->eevee.gi_diffuse_bounces = 3;
+ sce->eevee.gi_cubemap_resolution = 512;
+ sce->eevee.gi_visibility_resolution = 32;
+ sce->eevee.gi_cubemap_draw_size = 0.3f;
+ sce->eevee.gi_irradiance_draw_size = 0.1f;
+ sce->eevee.gi_irradiance_smoothing = 0.1f;
+ sce->eevee.gi_filter_quality = 1.0f;
+
+ sce->eevee.taa_samples = 16;
+ sce->eevee.taa_render_samples = 64;
+
+ sce->eevee.sss_samples = 7;
+ sce->eevee.sss_jitter_threshold = 0.3f;
+
+ sce->eevee.ssr_quality = 0.25f;
+ sce->eevee.ssr_max_roughness = 0.5f;
+ sce->eevee.ssr_thickness = 0.2f;
+ sce->eevee.ssr_border_fade = 0.075f;
+ sce->eevee.ssr_firefly_fac = 10.0f;
+
+ sce->eevee.volumetric_start = 0.1f;
+ sce->eevee.volumetric_end = 100.0f;
+ sce->eevee.volumetric_tile_size = 8;
+ sce->eevee.volumetric_samples = 64;
+ sce->eevee.volumetric_sample_distribution = 0.8f;
+ sce->eevee.volumetric_light_clamp = 0.0f;
+ sce->eevee.volumetric_shadow_samples = 16;
+
+ sce->eevee.gtao_distance = 0.2f;
+ sce->eevee.gtao_factor = 1.0f;
+ sce->eevee.gtao_quality = 0.25f;
+
+ sce->eevee.bokeh_max_size = 100.0f;
+ sce->eevee.bokeh_threshold = 1.0f;
+
+ copy_v3_fl(sce->eevee.bloom_color, 1.0f);
+ sce->eevee.bloom_threshold = 0.8f;
+ sce->eevee.bloom_knee = 0.5f;
+ sce->eevee.bloom_intensity = 0.8f;
+ sce->eevee.bloom_radius = 6.5f;
+ sce->eevee.bloom_clamp = 1.0f;
+
+ sce->eevee.motion_blur_samples = 8;
+ sce->eevee.motion_blur_shutter = 1.0f;
+
+ sce->eevee.shadow_method = SHADOW_ESM;
+ sce->eevee.shadow_cube_size = 512;
+ sce->eevee.shadow_cascade_size = 1024;
+
+ sce->eevee.light_cache = NULL;
+ sce->eevee.light_threshold = 0.01f;
+
+ sce->eevee.overscan = 3.0f;
+
+ sce->eevee.flag =
+ SCE_EEVEE_VOLUMETRIC_LIGHTS |
+ SCE_EEVEE_GTAO_BENT_NORMALS |
+ SCE_EEVEE_GTAO_BOUNCE |
+ SCE_EEVEE_TAA_REPROJECTION |
+ SCE_EEVEE_SSR_HALF_RESOLUTION;
}
Scene *BKE_scene_add(Main *bmain, const char *name)
@@ -885,75 +944,54 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
-Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
+/**
+ * Check if there is any instance of the object in the scene
+ */
+bool BKE_scene_object_find(Scene *scene, Object *ob)
{
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- if (STREQ(base->object->id.name + 2, name)) {
- break;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object))) {
+ return true;
}
}
-
- return base;
+ return false;
}
-Base *BKE_scene_base_find(Scene *scene, Object *ob)
+Object *BKE_scene_object_find_by_name(Scene *scene, const char *name)
{
- return BLI_findptr(&scene->base, ob, offsetof(Base, object));
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (STREQ(base->object->id.name + 2, name)) {
+ return base->object;
+ }
+ }
+ }
+ return NULL;
}
/**
* Sets the active scene, mainly used when running in background mode (``--scene`` command line argument).
* This is also called to set the scene directly, bypassing windowing code.
- * Otherwise #ED_screen_set_scene is used when changing scenes by the user.
+ * Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
*/
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
- Scene *sce;
- Base *base;
Object *ob;
- Group *group;
- GroupObject *go;
- int flag;
/* check for cyclic sets, for reading old files but also for definite security (py?) */
BKE_scene_validate_setscene(bmain, scene);
- /* can happen when switching modes in other scenes */
- if (scene->obedit && !(scene->obedit->mode & OB_MODE_EDIT))
- scene->obedit = NULL;
-
/* deselect objects (for dataselect) */
for (ob = bmain->object.first; ob; ob = ob->id.next)
- ob->flag &= ~(SELECT | OB_FROMGROUP);
-
- /* group flags again */
- for (group = bmain->group.first; group; group = group->id.next) {
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob) {
- go->ob->flag |= OB_FROMGROUP;
- }
- }
- }
-
- /* sort baselist for scene and sets */
- for (sce = scene; sce; sce = sce->set)
- DAG_scene_relations_rebuild(bmain, sce);
+ ob->flag &= ~SELECT;
/* copy layers and flags from bases to objects */
- for (base = scene->base.first; base; base = base->next) {
- ob = base->object;
- ob->lay = base->lay;
-
- /* group patch... */
- base->flag &= ~(OB_FROMGROUP);
- flag = ob->flag & (OB_FROMGROUP);
- base->flag |= flag;
-
- /* not too nice... for recovering objects with lost data */
- //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE;
- ob->flag = base->flag;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ ob = base->object;
+ /* collection patch... */
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
}
/* no full animation update, this to enable render code to work (render code calls own animation updates) */
}
@@ -973,8 +1011,8 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
}
/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
-int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBaseIter *iter,
- Scene **scene, int val, Base **base, Object **ob)
+int BKE_scene_base_iter_next(Depsgraph *depsgraph, SceneBaseIter *iter,
+ Scene **scene, int val, Base **base, Object **ob)
{
bool run_again = true;
@@ -992,17 +1030,21 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
/* the first base */
if (iter->phase == F_START) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer = (depsgraph) ?
+ DEG_get_evaluated_view_layer(depsgraph) :
+ BKE_view_layer_context_active_PLACEHOLDER(*scene);
+ *base = view_layer->object_bases.first;
if (*base) {
*ob = (*base)->object;
iter->phase = F_SCENE;
}
else {
- /* exception: empty scene */
+ /* exception: empty scene layer */
while ((*scene)->set) {
(*scene) = (*scene)->set;
- if ((*scene)->base.first) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
+ if (view_layer_set->object_bases.first) {
+ *base = view_layer_set->object_bases.first;
*ob = (*base)->object;
iter->phase = F_SCENE;
break;
@@ -1021,8 +1063,9 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
/* (*scene) is finished, now do the set */
while ((*scene)->set) {
(*scene) = (*scene)->set;
- if ((*scene)->base.first) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
+ if (view_layer_set->object_bases.first) {
+ *base = view_layer_set->object_bases.first;
*ob = (*base)->object;
break;
}
@@ -1037,12 +1080,12 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
else {
if (iter->phase != F_DUPLI) {
- if ( (*base)->object->transflag & OB_DUPLI) {
- /* groups cannot be duplicated for mballs yet,
+ if (depsgraph && (*base)->object->transflag & OB_DUPLI) {
+ /* collections cannot be duplicated for mballs yet,
* this enters eternal loop because of
- * makeDispListMBall getting called inside of group_duplilist */
+ * makeDispListMBall getting called inside of collection_duplilist */
if ((*base)->object->dup_group == NULL) {
- iter->duplilist = object_duplilist_ex(bmain, eval_ctx, (*scene), (*base)->object, false);
+ iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object);
iter->dupob = iter->duplilist->first;
@@ -1056,7 +1099,7 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
/* handle dupli's */
if (iter->dupob) {
- (*base)->flag |= OB_FROMDUPLI;
+ (*base)->flag_legacy |= OB_FROMDUPLI;
*ob = iter->dupob->ob;
iter->phase = F_DUPLI;
@@ -1075,7 +1118,7 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
else if (iter->phase == F_DUPLI) {
iter->phase = F_SCENE;
- (*base)->flag &= ~OB_FROMDUPLI;
+ (*base)->flag_legacy &= ~OB_FROMDUPLI;
if (iter->dupli_refob) {
/* Restore last object's real matrix. */
@@ -1091,22 +1134,18 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
}
-#if 0
- if (ob && *ob) {
- printf("Scene: '%s', '%s'\n", (*scene)->id.name + 2, (*ob)->id.name + 2);
- }
-#endif
-
return iter->phase;
}
-Object *BKE_scene_camera_find(Scene *sc)
+Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection)
{
- Base *base;
-
- for (base = sc->base.first; base; base = base->next)
- if (base->object->type == OB_CAMERA)
- return base->object;
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) {
+ if (BKE_view_layer_has_collection(layer, collection)) {
+ return scene;
+ }
+ }
+ }
return NULL;
}
@@ -1160,6 +1199,7 @@ int BKE_scene_camera_switch_update(Scene *scene)
Object *camera = BKE_scene_camera_switch_find(scene);
if (camera) {
scene->camera = camera;
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
return 1;
}
#else
@@ -1218,49 +1258,14 @@ int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, in
return (delta_prev < delta_next) ? second_prev : second_next;
}
-
-Base *BKE_scene_base_add(Scene *sce, Object *ob)
-{
- Base *b = MEM_callocN(sizeof(*b), __func__);
- BLI_addhead(&sce->base, b);
-
- b->object = ob;
- b->flag = ob->flag;
- b->lay = ob->lay;
-
- return b;
-}
-
-void BKE_scene_base_unlink(Scene *sce, Base *base)
+void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob)
{
/* remove rigid body constraint from world before removing object */
- if (base->object->rigidbody_constraint)
- BKE_rigidbody_remove_constraint(sce, base->object);
+ if (ob->rigidbody_constraint)
+ BKE_rigidbody_remove_constraint(scene, ob);
/* remove rigid body object from world before removing object */
- if (base->object->rigidbody_object)
- BKE_rigidbody_remove_object(sce, base->object);
-
- BLI_remlink(&sce->base, base);
- if (sce->basact == base)
- sce->basact = NULL;
-}
-
-void BKE_scene_base_deselect_all(Scene *sce)
-{
- Base *b;
-
- for (b = sce->base.first; b; b = b->next) {
- b->flag &= ~SELECT;
- b->object->flag = b->flag;
- }
-}
-
-void BKE_scene_base_select(Scene *sce, Base *selbase)
-{
- selbase->flag |= SELECT;
- selbase->object->flag = selbase->flag;
-
- sce->basact = selbase;
+ if (ob->rigidbody_object)
+ BKE_rigidbody_remove_object(bmain, scene, ob);
}
/* checks for cycle, returns 1 if it's all OK */
@@ -1312,109 +1317,6 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra)
scene->r.cfra = (int)intpart;
}
-#ifdef WITH_LEGACY_DEPSGRAPH
-/* drivers support/hacks
- * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render
- * - these are always run since the depsgraph can't handle non-object data
- * - these happen after objects are all done so that we can read in their final transform values,
- * though this means that objects can't refer to scene info for guidance...
- */
-static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene)
-{
- SceneRenderLayer *srl;
- float ctime = BKE_scene_frame_get(scene);
-
- /* scene itself */
- if (scene->adt && scene->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* world */
- /* TODO: what about world textures? but then those have nodes too... */
- if (scene->world) {
- ID *wid = (ID *)scene->world;
- AnimData *adt = BKE_animdata_from_id(wid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- if (scene->nodetree) {
- ID *nid = (ID *)scene->nodetree;
- AnimData *adt = BKE_animdata_from_id(nid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* world nodes */
- if (scene->world && scene->world->nodetree) {
- ID *nid = (ID *)scene->world->nodetree;
- AnimData *adt = BKE_animdata_from_id(nid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* freestyle */
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
- FreestyleConfig *config = &srl->freestyleConfig;
- FreestyleLineSet *lineset;
-
- for (lineset = config->linesets.first; lineset; lineset = lineset->next) {
- if (lineset->linestyle) {
- ID *lid = &lineset->linestyle->id;
- AnimData *adt = BKE_animdata_from_id(lid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS);
- }
- }
- }
-}
-
-/* deps hack - do extra recalcs at end */
-static void scene_depsgraph_hack(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
-{
- Base *base;
-
- scene->customdata_mask = scene_parent->customdata_mask;
-
- /* sets first, we allow per definition current scene to have
- * dependencies on sets, but not the other way around. */
- if (scene->set)
- scene_depsgraph_hack(bmain, eval_ctx, scene->set, scene_parent);
-
- for (base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
-
- if (ob->depsflag) {
- int recalc = 0;
- // printf("depshack %s\n", ob->id.name + 2);
-
- if (ob->depsflag & OB_DEPS_EXTRA_OB_RECALC)
- recalc |= OB_RECALC_OB;
- if (ob->depsflag & OB_DEPS_EXTRA_DATA_RECALC)
- recalc |= OB_RECALC_DATA;
-
- ob->recalc |= recalc;
- BKE_object_handle_update(bmain, eval_ctx, scene_parent, ob);
-
- if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) {
- GroupObject *go;
-
- for (go = ob->dup_group->gobject.first; go; go = go->next) {
- if (go->ob)
- go->ob->recalc |= recalc;
- }
- BKE_group_handle_recalc_and_update(bmain, eval_ctx, scene_parent, ob, ob->dup_group);
- }
- }
- }
-}
-#endif /* WITH_LEGACY_DEPSGRAPH */
-
/* That's like really a bummer, because currently animation data for armatures
* might want to use pose, and pose might be missing on the object.
* This happens when changing visible layers, which leads to situations when
@@ -1427,392 +1329,41 @@ static void scene_depsgraph_hack(Main *bmain, EvaluationContext *eval_ctx, Scene
#define POSE_ANIMATION_WORKAROUND
#ifdef POSE_ANIMATION_WORKAROUND
-static void scene_armature_depsgraph_workaround(Main *bmain)
+static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph)
{
Object *ob;
- if (BLI_listbase_is_empty(&bmain->armature) || !DAG_id_type_tagged(bmain, ID_OB)) {
+ if (BLI_listbase_is_empty(&bmain->armature) || !DEG_id_type_updated(depsgraph, ID_OB)) {
return;
}
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->type == OB_ARMATURE && ob->adt && ob->adt->recalc & ADT_RECALC_ANIM) {
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild(ob, ob->data);
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
}
}
}
}
#endif
-#ifdef WITH_LEGACY_DEPSGRAPH
-static void scene_rebuild_rbw_recursive(Scene *scene, float ctime)
-{
- if (scene->set)
- scene_rebuild_rbw_recursive(scene->set, ctime);
-
- if (BKE_scene_check_rigidbody_active(scene))
- BKE_rigidbody_rebuild_world(scene, ctime);
-}
-
-static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
-{
- if (scene->set)
- scene_do_rb_simulation_recursive(scene->set, ctime);
-
- if (BKE_scene_check_rigidbody_active(scene))
- BKE_rigidbody_do_simulation(scene, ctime);
-}
-#endif
-
-/* Used to visualize CPU threads activity during threaded object update,
- * would pollute STDERR with whole bunch of timing information which then
- * could be parsed and nicely visualized.
- */
-#ifdef WITH_LEGACY_DEPSGRAPH
-# undef DETAILED_ANALYSIS_OUTPUT
-#else
-/* ALWAYS KEEY DISABLED! */
-# undef DETAILED_ANALYSIS_OUTPUT
-#endif
-
-/* Mballs evaluation uses BKE_scene_base_iter_next which calls
- * duplilist for all objects in the scene. This leads to conflict
- * accessing and writing same data from multiple threads.
- *
- * Ideally Mballs shouldn't do such an iteration and use DAG
- * queries instead. For the time being we've got new DAG
- * let's keep it simple and update mballs in a single thread.
- */
-#define MBALL_SINGLETHREAD_HACK
-
-#ifdef WITH_LEGACY_DEPSGRAPH
-typedef struct StatisicsEntry {
- struct StatisicsEntry *next, *prev;
- Object *object;
- double start_time;
- double duration;
-} StatisicsEntry;
-
-typedef struct ThreadedObjectUpdateState {
- /* TODO(sergey): We might want this to be per-thread object. */
- EvaluationContext *eval_ctx;
- Main *bmain;
- Scene *scene;
- Scene *scene_parent;
- double base_time;
-
-#ifdef MBALL_SINGLETHREAD_HACK
- bool has_mballs;
-#endif
-
- int num_threads;
-
- /* Execution statistics */
- bool has_updated_objects;
- ListBase *statistics;
-} ThreadedObjectUpdateState;
-
-static void scene_update_object_add_task(void *node, void *user_data);
-
-static void scene_update_all_bases(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
-{
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- Object *object = base->object;
-
- BKE_object_handle_update_ex(bmain, eval_ctx, scene_parent, object, scene->rigidbody_world, true);
-
- if (object->dup_group && (object->transflag & OB_DUPLIGROUP))
- BKE_group_handle_recalc_and_update(bmain, eval_ctx, scene_parent, object, object->dup_group);
-
- /* always update layer, so that animating layers works (joshua july 2010) */
- /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes
- * (on scene-set, the base-lay is copied to ob-lay (ton nov 2012) */
- // base->lay = ob->lay;
- }
-}
-
-static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata, int threadid)
-{
-/* Disable print for now in favor of summary statistics at the end of update. */
-#define PRINT if (false) printf
-
- ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool);
- void *node = taskdata;
- Object *object = DAG_get_node_object(node);
- EvaluationContext *eval_ctx = state->eval_ctx;
- Main *bmain = state->bmain;
- Scene *scene = state->scene;
- Scene *scene_parent = state->scene_parent;
-
-#ifdef MBALL_SINGLETHREAD_HACK
- if (object && object->type == OB_MBALL) {
- state->has_mballs = true;
- }
- else
-#endif
- if (object) {
- double start_time = 0.0;
- bool add_to_stats = false;
-
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- if (object->recalc & OB_RECALC_ALL) {
- printf("Thread %d: update object %s\n", threadid, object->id.name);
- }
-
- start_time = PIL_check_seconds_timer();
-
- if (object->recalc & OB_RECALC_ALL) {
- state->has_updated_objects = true;
- add_to_stats = true;
- }
- }
-
- /* We only update object itself here, dupli-group will be updated
- * separately from main thread because of we've got no idea about
- * dependencies inside the group.
- */
- BKE_object_handle_update_ex(bmain, eval_ctx, scene_parent, object, scene->rigidbody_world, false);
-
- /* Calculate statistics. */
- if (add_to_stats) {
- StatisicsEntry *entry;
-
- entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics");
- entry->object = object;
- entry->start_time = start_time;
- entry->duration = PIL_check_seconds_timer() - start_time;
-
- BLI_addtail(&state->statistics[threadid], entry);
- }
- }
- else {
- PRINT("Threda %d: update node %s\n", threadid,
- DAG_get_node_name(scene, node));
- }
-
- /* Update will decrease child's valency and schedule child with zero valency. */
- DAG_threaded_update_handle_node_updated(node, scene_update_object_add_task, pool);
-
-#undef PRINT
-}
-
-static void scene_update_object_add_task(void *node, void *user_data)
-{
- TaskPool *task_pool = user_data;
-
- BLI_task_pool_push(task_pool, scene_update_object_func, node, false, TASK_PRIORITY_LOW);
-}
-
-static void print_threads_statistics(ThreadedObjectUpdateState *state)
-{
- double finish_time;
-
- if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
- return;
- }
-
-#ifdef DETAILED_ANALYSIS_OUTPUT
- if (state->has_updated_objects) {
- tot_thread = BLI_system_thread_count();
-
- fprintf(stderr, "objects update base time %f\n", state->base_time);
-
- for (i = 0; i < tot_thread; i++) {
- StatisicsEntry *entry;
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- fprintf(stderr, "thread %d object %s start_time %f duration %f\n",
- i, entry->object->id.name + 2,
- entry->start_time, entry->duration);
- }
- BLI_freelistN(&state->statistics[i]);
- }
- }
-#else
- finish_time = PIL_check_seconds_timer();
- int total_objects = 0;
-
- for (int i = 0; i < state->num_threads; i++) {
- int thread_total_objects = 0;
- double thread_total_time = 0.0;
- StatisicsEntry *entry;
-
- if (state->has_updated_objects) {
- /* Don't pollute output if no objects were updated. */
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- thread_total_objects++;
- thread_total_time += entry->duration;
- }
-
- printf("Thread %d: total %d objects in %f sec.\n",
- i,
- thread_total_objects,
- thread_total_time);
-
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration);
- }
-
- total_objects += thread_total_objects;
- }
-
- BLI_freelistN(&state->statistics[i]);
- }
- if (state->has_updated_objects) {
- printf("Scene updated %d objects in %f sec\n",
- total_objects,
- finish_time - state->base_time);
- }
-#endif
-}
-
-static bool scene_need_update_objects(Main *bmain)
-{
- return
- /* Object datablocks themselves (for OB_RECALC_OB) */
- DAG_id_type_tagged(bmain, ID_OB) ||
-
- /* Objects data datablocks (for OB_RECALC_DATA) */
- DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */
- DAG_id_type_tagged(bmain, ID_CU) || /* Curve */
- DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */
- DAG_id_type_tagged(bmain, ID_LA) || /* Lamp */
- DAG_id_type_tagged(bmain, ID_LT) || /* Lattice */
- DAG_id_type_tagged(bmain, ID_CA) || /* Camera */
- DAG_id_type_tagged(bmain, ID_KE) || /* KE */
- DAG_id_type_tagged(bmain, ID_SPK) || /* Speaker */
- DAG_id_type_tagged(bmain, ID_AR); /* Armature */
-}
-
-static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
-{
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
- ThreadedObjectUpdateState state;
- bool need_singlethread_pass;
- bool need_free_scheduler;
-
- /* Early check for whether we need to invoke all the task-based
- * things (spawn new ppol, traverse dependency graph and so on).
- *
- * Basically if there's no ID datablocks tagged for update which
- * corresponds to object->recalc flags (which are checked in
- * BKE_object_handle_update() then we do nothing here.
- */
- if (!scene_need_update_objects(bmain)) {
- return;
- }
-
- state.eval_ctx = eval_ctx;
- state.bmain = bmain;
- state.scene = scene;
- state.scene_parent = scene_parent;
-
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- task_scheduler = BLI_task_scheduler_create(1);
- need_free_scheduler = true;
- }
- else {
- task_scheduler = BLI_task_scheduler_get();
- need_free_scheduler = false;
- }
-
- /* Those are only needed when blender is run with --debug argument. */
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
- state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics),
- "scene update objects stats");
- state.has_updated_objects = false;
- state.base_time = PIL_check_seconds_timer();
- state.num_threads = tot_thread;
- }
-
-#ifdef MBALL_SINGLETHREAD_HACK
- state.has_mballs = false;
-#endif
-
- task_pool = BLI_task_pool_create(task_scheduler, &state);
-
- DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- print_threads_statistics(&state);
- MEM_freeN(state.statistics);
- }
-
- /* We do single thread pass to update all the objects which are in cyclic dependency.
- * Such objects can not be handled by a generic DAG traverse and it's really tricky
- * to detect whether cycle could be solved or not.
- *
- * In this situation we simply update all remaining objects in a single thread and
- * it'll happen in the same exact order as it was in single-threaded DAG.
- *
- * We couldn't use threaded update for objects which are in cycle because they might
- * access data of each other which is being re-evaluated.
- *
- * Also, as was explained above, for now we also update all the mballs in single thread.
- *
- * - sergey -
- */
- need_singlethread_pass = DAG_is_acyclic(scene) == false;
-#ifdef MBALL_SINGLETHREAD_HACK
- need_singlethread_pass |= state.has_mballs;
-#endif
-
- if (need_singlethread_pass) {
- scene_update_all_bases(bmain, eval_ctx, scene, scene_parent);
- }
-
- if (need_free_scheduler) {
- BLI_task_scheduler_free(task_scheduler);
- }
-}
-
-static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
-{
- scene->customdata_mask = scene_parent->customdata_mask;
-
- /* sets first, we allow per definition current scene to have
- * dependencies on sets, but not the other way around. */
- if (scene->set)
- scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent);
-
- /* scene objects */
- scene_update_objects(eval_ctx, bmain, scene, scene_parent);
-
- /* scene drivers... */
- scene_update_drivers(bmain, scene);
-
- /* update masking curves */
- BKE_mask_update_scene(bmain, scene);
-
-}
-#endif /* WITH_LEGACY_DEPSGRAPH */
-
static bool check_rendered_viewport_visible(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
wmWindow *window;
for (window = wm->windows.first; window != NULL; window = window->next) {
- bScreen *screen = window->screen;
- ScrArea *area;
- for (area = screen->areabase.first; area != NULL; area = area->next) {
+ const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ Scene *scene = window->scene;
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+
+ if (type->draw_engine || !type->render) {
+ continue;
+ }
+
+ for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) {
View3D *v3d = area->spacedata.first;
if (area->spacetype != SPACE_VIEW3D) {
continue;
}
- if (v3d->drawtype == OB_RENDER) {
+ if (v3d->shading.type == OB_RENDER) {
return true;
}
}
@@ -1820,7 +1371,10 @@ static bool check_rendered_viewport_visible(Main *bmain)
return false;
}
-static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
+/* TODO(campbell): shouldn't we be able to use 'DEG_get_view_layer' here?
+ * Currently this is NULL on load, so don't. */
+static void prepare_mesh_for_viewport_render(
+ Main *bmain, const ViewLayer *view_layer)
{
/* This is needed to prepare mesh to be used by the render
* engine from the viewport rendering. We do loading here
@@ -1831,7 +1385,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
* call loading of the edit data for the mesh objects.
*/
- Object *obedit = scene->obedit;
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (obedit) {
Mesh *mesh = obedit->data;
if ((obedit->type == OB_MESH) &&
@@ -1845,318 +1399,106 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
(&(struct BMeshToMeshParams){
.calc_object_remap = true,
}));
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
}
}
}
-void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
+/* TODO(sergey): This actually should become view_layer_graph or so.
+ * Same applies to update_for_newframe.
+ */
+void BKE_scene_graph_update_tagged(Depsgraph *depsgraph,
+ Main *bmain)
{
- Scene *sce_iter;
-#ifdef WITH_LEGACY_DEPSGRAPH
- bool use_new_eval = !DEG_depsgraph_use_legacy();
-#endif
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- /* keep this first */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
-
- /* (re-)build dependency graph if needed */
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
- DAG_scene_relations_update(bmain, sce_iter);
- /* Uncomment this to check if dependency graph was properly tagged for update. */
-#if 0
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (use_new_eval)
-#endif
- {
- DAG_scene_relations_validate(bmain, sce_iter);
- }
-#endif
+ bool run_callbacks = DEG_id_type_any_updated(depsgraph);
+ if (run_callbacks) {
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE);
}
- /* flush editing data if needed */
- prepare_mesh_for_viewport_render(bmain, scene);
-
- /* flush recalc flags to dependencies */
- DAG_ids_flush_tagged(bmain);
-
- /* removed calls to quick_cache, see pointcache.c */
-
- /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
- * when trying to find materials with drivers that need evaluating [#32017]
+ /* TODO(sergey): Some functions here are changing global state,
+ * for example, clearing update tags from bmain.
*/
- BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
-
- /* update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed
- *
- * in the future this should handle updates for all datablocks, not
- * only objects and scenes. - brecht */
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
- }
- else
-#endif
- {
- DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
- }
-
- /* update sound system animation (TODO, move to depsgraph) */
- BKE_sound_update_scene(bmain, scene);
-
- /* extra call here to recalc scene animation (for sequencer) */
- {
- AnimData *adt = BKE_animdata_from_id(&scene->id);
- float ctime = BKE_scene_frame_get(scene);
-
- if (adt && (adt->recalc & ADT_RECALC_ANIM))
- BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0);
- }
-
- /* Extra call here to recalc material animation.
- *
- * Need to do this so changing material settings from the graph/dopesheet
- * will update stuff in the viewport.
+ /* (Re-)build dependency graph if needed. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Uncomment this to check if graph was properly tagged for update. */
+ // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
+ /* Flush editing data if needed. */
+ prepare_mesh_for_viewport_render(bmain, view_layer);
+ /* Flush recalc flags to dependencies. */
+ DEG_graph_flush_update(bmain, depsgraph);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
*/
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
- Material *material;
- float ctime = BKE_scene_frame_get(scene);
-
- for (material = bmain->mat.first;
- material;
- material = material->id.next)
- {
- AnimData *adt = BKE_animdata_from_id(&material->id);
- if (adt && (adt->recalc & ADT_RECALC_ANIM))
- BKE_animsys_evaluate_animdata(scene, &material->id, adt, ctime, 0);
- }
- }
-
- /* Also do the same for node trees. */
- if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
- float ctime = BKE_scene_frame_get(scene);
+ DEG_evaluate_on_refresh(depsgraph);
+ /* Update sound system animation (TODO, move to depsgraph). */
+ BKE_sound_update_scene(bmain, scene);
- FOREACH_NODETREE_BEGIN(bmain, ntree, id)
- {
- AnimData *adt = BKE_animdata_from_id(&ntree->id);
- if (adt && (adt->recalc & ADT_RECALC_ANIM))
- BKE_animsys_evaluate_animdata(scene, &ntree->id, adt, ctime, 0);
- }
- FOREACH_NODETREE_END;
+ /* Notify python about depsgraph update */
+ if (run_callbacks) {
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_POST);
}
-#endif
-
- /* notify editors and python about recalc */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
-
/* Inform editors about possible changes. */
- DAG_ids_check_recalc(bmain, scene, false);
-
- /* clear recalc flags */
- DAG_ids_clear_recalc(bmain);
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
+ /* Clear recalc flags. */
+ DEG_ids_clear_recalc(bmain, depsgraph);
}
/* applies changes right away, does all sets too */
-void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay)
-{
- BKE_scene_update_for_newframe_ex(eval_ctx, bmain, sce, lay, false);
-}
-
-void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay, bool do_invisible_flush)
+void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph,
+ Main *bmain)
{
- float ctime = BKE_scene_frame_get(sce);
- Scene *sce_iter;
-#ifdef DETAILED_ANALYSIS_OUTPUT
- double start_time = PIL_check_seconds_timer();
-#endif
-#ifdef WITH_LEGACY_DEPSGRAPH
- bool use_new_eval = !DEG_depsgraph_use_legacy();
-#else
- /* TODO(sergey): Pass to evaluation routines instead of storing layer in the dependency graph? */
- (void) do_invisible_flush;
-#endif
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- DAG_editors_update_pre(bmain, sce, true);
-
- /* keep this first */
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
-
- /* update animated image textures for particles, modifiers, gpu, etc,
- * call this at the start so modifiers with textures don't lag 1 frame */
- BKE_image_update_frame(bmain, sce->r.cfra);
-
-#ifdef WITH_LEGACY_DEPSGRAPH
- /* rebuild rigid body worlds before doing the actual frame update
- * this needs to be done on start frame but animation playback usually starts one frame later
- * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
+ /* TODO(sergey): Some functions here are changing global state,
+ * for example, clearing update tags from bmain.
*/
- if (!use_new_eval) {
- scene_rebuild_rbw_recursive(sce, ctime);
- }
-#endif
-
- BKE_sound_set_cfra(sce->r.cfra);
-
- /* clear animation overrides */
- /* XXX TODO... */
-
- for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
- DAG_scene_relations_update(bmain, sce_iter);
-
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- /* flush recalc flags to dependencies, if we were only changing a frame
- * this would not be necessary, but if a user or a script has modified
- * some datablock before BKE_scene_update_tagged was called, we need the flush */
- DAG_ids_flush_tagged(bmain);
-
- /* Following 2 functions are recursive
- * so don't call within 'scene_update_tagged_recursive' */
- DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
- BKE_mask_evaluate_all_masks(bmain, ctime, true);
- }
-#endif
-
- /* 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
-
- /* All 'standard' (i.e. without any dependencies) animation is handled here,
- * with an 'local' to 'macro' order of evaluation. This should ensure that
- * settings stored nestled within a hierarchy (i.e. settings in a Texture block
- * can be overridden by settings from Scene, which owns the Texture through a hierarchy
- * such as Scene->World->MTex/Texture) can still get correctly overridden.
+ const float ctime = BKE_scene_frame_get(scene);
+ /* Keep this first. */
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
+ /* Update animated image textures for particles, modifiers, gpu, etc,
+ * call this at the start so modifiers with textures don't lag 1 frame.
*/
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
- /*...done with recursive funcs */
- }
-#endif
-
- /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
- * when trying to find materials with drivers that need evaluating [#32017]
+ BKE_image_update_frame(bmain, scene->r.cfra);
+ BKE_sound_set_cfra(scene->r.cfra);
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Update animated cache files for modifiers.
+ *
+ * TODO(sergey): Make this a depsgraph node?
*/
- BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
-
- /* run rigidbody sim */
- /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- scene_do_rb_simulation_recursive(sce, ctime);
- }
-#endif
-
- /* BKE_object_handle_update() on all objects, groups and sets */
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (use_new_eval) {
- DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
- }
- else {
- scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
- }
-#else
- DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
-#endif
-
- /* update sound system animation (TODO, move to depsgraph) */
- BKE_sound_update_scene(bmain, sce);
-
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- scene_depsgraph_hack(bmain, eval_ctx, sce, sce);
- }
+ BKE_cachefile_update_frame(bmain, depsgraph, scene, ctime,
+ (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base));
+#ifdef POSE_ANIMATION_WORKAROUND
+ scene_armature_depsgraph_workaround(bmain, depsgraph);
#endif
-
- /* notify editors and python about recalc */
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST);
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST);
-
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ */
+ DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
+ /* Update sound system animation (TODO, move to depsgraph). */
+ BKE_sound_update_scene(bmain, scene);
+ /* Notify editors and python about recalc. */
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
/* Inform editors about possible changes. */
- DAG_ids_check_recalc(bmain, sce, true);
-
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
/* clear recalc flags */
- DAG_ids_clear_recalc(bmain);
-
-#ifdef DETAILED_ANALYSIS_OUTPUT
- fprintf(stderr, "frame update start_time %f duration %f\n", start_time, PIL_check_seconds_timer() - start_time);
-#endif
+ DEG_ids_clear_recalc(bmain, depsgraph);
}
-/* return default layer, also used to patch old files */
-SceneRenderLayer *BKE_scene_add_render_layer(Scene *sce, const char *name)
+/** Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
+ *
+ * \warning Sets matching depsgraph as active, so should only be called from the active editing context
+ * (usually, from operators).
+ */
+void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
- SceneRenderLayer *srl;
-
- if (!name)
- name = DATA_("RenderLayer");
-
- srl = MEM_callocN(sizeof(SceneRenderLayer), "new render layer");
- BLI_strncpy(srl->name, name, sizeof(srl->name));
- BLI_uniquename(&sce->r.layers, srl, DATA_("RenderLayer"), '.', offsetof(SceneRenderLayer, name), sizeof(srl->name));
- BLI_addtail(&sce->r.layers, srl);
-
- /* note, this is also in render, pipeline.c, to make layer when scenedata doesnt have it */
- srl->lay = (1 << 20) - 1;
- srl->layflag = 0x7FFF; /* solid ztra halo edge strand */
- srl->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
- srl->pass_alpha_threshold = 0.5f;
- BKE_freestyle_config_init(&srl->freestyleConfig);
-
- return srl;
-}
-
-bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *srl)
-{
- const int act = BLI_findindex(&scene->r.layers, srl);
- Scene *sce;
-
- if (act == -1) {
- return false;
- }
- else if ( (scene->r.layers.first == scene->r.layers.last) &&
- (scene->r.layers.first == srl))
- {
- /* ensure 1 layer is kept */
- return false;
- }
-
- BKE_freestyle_config_free(&srl->freestyleConfig);
-
- if (srl->prop) {
- IDP_FreeProperty(srl->prop);
- MEM_freeN(srl->prop);
- }
-
- BLI_remlink(&scene->r.layers, srl);
- MEM_freeN(srl);
-
- scene->r.actlay = 0;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->nodetree) {
- bNode *node;
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
- if (node->custom1 == act)
- node->custom1 = 0;
- else if (node->custom1 > act)
- node->custom1--;
- }
- }
- }
- }
-
- return true;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ DEG_make_active(depsgraph);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
}
/* return default view */
@@ -2223,37 +1565,34 @@ int get_render_child_particle_number(const RenderData *r, int num, bool for_rend
}
}
-int get_render_shadow_samples(const RenderData *r, int samples)
-{
- if ((r->mode & R_SIMPLIFY) && samples > 0)
- return min_ii(r->simplify_shadowsamples, samples);
- else
- return samples;
-}
-
-float get_render_aosss_error(const RenderData *r, float error)
-{
- if (r->mode & R_SIMPLIFY)
- return ((1.0f - r->simplify_aosss) * 10.0f + 1.0f) * error;
- else
- return error;
-}
-
-/* helper function for the SETLOOPER macro */
-Base *_setlooper_base_step(Scene **sce_iter, Base *base)
+/**
+ * Helper function for the SETLOOPER and SETLOOPER_VIEW_LAYER macros
+ *
+ * It iterates over the bases of the active layer and then the bases
+ * of the active layer of the background (set) scenes recursively.
+ */
+Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base)
{
if (base && base->next) {
- /* common case, step to the next */
+ /* Common case, step to the next. */
return base->next;
}
- else if (base == NULL && (*sce_iter)->base.first) {
- /* first time looping, return the scenes first base */
- return (Base *)(*sce_iter)->base.first;
+ else if ((base == NULL) && (view_layer != NULL)) {
+ /* First time looping, return the scenes first base. */
+ /* For the first loop we should get the layer from workspace when available. */
+ if (view_layer->object_bases.first) {
+ return (Base *)view_layer->object_bases.first;
+ }
+ /* No base on this scene layer. */
+ goto next_set;
}
else {
- /* reached the end, get the next base in the set */
+next_set:
+ /* Reached the end, get the next base in the set. */
while ((*sce_iter = (*sce_iter)->set)) {
- base = (Base *)(*sce_iter)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*sce_iter));
+ base = (Base *)view_layer_set->object_bases.first;
+
if (base) {
return base;
}
@@ -2263,58 +1602,68 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base)
return NULL;
}
-bool BKE_scene_use_new_shading_nodes(const Scene *scene)
-{
- const RenderEngineType *type = RE_engines_find(scene->r.engine);
- return (type && type->flag & RE_USE_SHADING_NODES);
-}
-
bool BKE_scene_use_shading_nodes_custom(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
}
-bool BKE_scene_use_world_space_shading(Scene *scene)
-{
- const RenderEngineType *type = RE_engines_find(scene->r.engine);
- return ((scene->r.mode & R_USE_WS_SHADING) ||
- (type && (type->flag & RE_USE_SHADING_NODES)));
-}
-
bool BKE_scene_use_spherical_stereo(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->flag & RE_USE_SPHERICAL_STEREO);
}
-bool BKE_scene_uses_blender_internal(const Scene *scene)
+bool BKE_scene_uses_blender_eevee(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER);
+ return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
}
-bool BKE_scene_uses_blender_game(const Scene *scene)
+bool BKE_scene_uses_blender_workbench(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME);
+ return STREQ(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH);
}
-void BKE_scene_base_flag_to_objects(struct Scene *scene)
+bool BKE_scene_uses_cycles(const Scene *scene)
{
- Base *base = scene->base.first;
+ return STREQ(scene->r.engine, RE_engine_id_CYCLES);
+}
+
+void BKE_scene_base_flag_to_objects(ViewLayer *view_layer)
+{
+ Base *base = view_layer->object_bases.first;
while (base) {
- base->object->flag = base->flag;
+ BKE_scene_object_base_flag_sync_from_base(base);
base = base->next;
}
}
-void BKE_scene_base_flag_from_objects(struct Scene *scene)
+void BKE_scene_object_base_flag_sync_from_base(Base *base)
{
- Base *base = scene->base.first;
+ Object *ob = base->object;
- while (base) {
- base->flag = base->object->flag;
- base = base->next;
+ ob->flag = base->flag;
+
+ if ((base->flag & BASE_SELECTED) != 0) {
+ ob->flag |= SELECT;
+ }
+ else {
+ ob->flag &= ~SELECT;
+ }
+}
+
+void BKE_scene_object_base_flag_sync_from_object(Base *base)
+{
+ Object *ob = base->object;
+ base->flag = ob->flag;
+
+ if ((ob->flag & SELECT) != 0) {
+ base->flag |= BASE_SELECTED;
+ BLI_assert((base->flag & BASE_SELECTABLE) != 0);
+ }
+ else {
+ base->flag &= ~BASE_SELECTED;
}
}
@@ -2683,3 +2032,146 @@ int BKE_scene_multiview_num_videos_get(const RenderData *rd)
return BKE_scene_multiview_num_views_get(rd);
}
}
+
+/* Manipulation of depsgraph storage. */
+
+/* This is a key which identifies depsgraph. */
+typedef struct DepsgraphKey {
+ ViewLayer *view_layer;
+ /* TODO(sergey): Need to include window somehow (same layer might be in a
+ * different states in different windows).
+ */
+} DepsgraphKey;
+
+static unsigned int depsgraph_key_hash(const void *key_v)
+{
+ const DepsgraphKey *key = key_v;
+ unsigned int hash = BLI_ghashutil_ptrhash(key->view_layer);
+ /* TODO(sergey): Include hash from other fields in the key. */
+ return hash;
+}
+
+static bool depsgraph_key_compare(const void *key_a_v, const void *key_b_v)
+{
+ const DepsgraphKey *key_a = key_a_v;
+ const DepsgraphKey *key_b = key_b_v;
+ /* TODO(sergey): Compare rest of */
+ return !(key_a->view_layer == key_b->view_layer);
+}
+
+static void depsgraph_key_free(void *key_v)
+{
+ DepsgraphKey *key = key_v;
+ MEM_freeN(key);
+}
+
+static void depsgraph_key_value_free(void *value)
+{
+ Depsgraph *depsgraph = value;
+ DEG_graph_free(depsgraph);
+}
+
+void BKE_scene_allocate_depsgraph_hash(Scene *scene)
+{
+ scene->depsgraph_hash = BLI_ghash_new(depsgraph_key_hash,
+ depsgraph_key_compare,
+ "Scene Depsgraph Hash");
+}
+
+void BKE_scene_ensure_depsgraph_hash(Scene *scene)
+{
+ if (scene->depsgraph_hash == NULL) {
+ BKE_scene_allocate_depsgraph_hash(scene);
+ }
+}
+
+void BKE_scene_free_depsgraph_hash(Scene *scene)
+{
+ if (scene->depsgraph_hash == NULL) {
+ return;
+ }
+ BLI_ghash_free(scene->depsgraph_hash,
+ depsgraph_key_free,
+ depsgraph_key_value_free);
+}
+
+/* Query depsgraph for a specific contexts. */
+
+Depsgraph *BKE_scene_get_depsgraph(Scene *scene,
+ ViewLayer *view_layer,
+ bool allocate)
+{
+ BLI_assert(scene != NULL);
+ BLI_assert(view_layer != NULL);
+ /* Make sure hash itself exists. */
+ if (allocate) {
+ BKE_scene_ensure_depsgraph_hash(scene);
+ }
+ if (scene->depsgraph_hash == NULL) {
+ return NULL;
+ }
+ /* Either ensure item is in the hash or simply return NULL if it's not,
+ * depending on whether caller wants us to create depsgraph or not.
+ */
+ DepsgraphKey key;
+ key.view_layer = view_layer;
+ Depsgraph *depsgraph;
+ if (allocate) {
+ DepsgraphKey **key_ptr;
+ Depsgraph **depsgraph_ptr;
+ if (!BLI_ghash_ensure_p_ex(scene->depsgraph_hash,
+ &key,
+ (void ***)&key_ptr,
+ (void ***)&depsgraph_ptr))
+ {
+ *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__);
+ **key_ptr = key;
+ *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT);
+ /* TODO(sergey): Would be cool to avoid string format print,
+ * but is a bit tricky because we can't know in advance whether
+ * we will ever enable debug messages for this depsgraph.
+ */
+ char name[1024];
+ BLI_snprintf(name, sizeof(name), "%s :: %s", scene->id.name, view_layer->name);
+ DEG_debug_name_set(*depsgraph_ptr, name);
+ }
+ depsgraph = *depsgraph_ptr;
+ }
+ else {
+ depsgraph = BLI_ghash_lookup(scene->depsgraph_hash, &key);
+ }
+ return depsgraph;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Scene Orientation
+ * \{ */
+
+void BKE_scene_transform_orientation_remove(
+ Scene *scene, TransformOrientation *orientation)
+{
+ const int orientation_index = BKE_scene_transform_orientation_get_index(scene, orientation);
+ if (scene->orientation_index_custom == orientation_index) {
+ /* could also use orientation_index-- */
+ scene->orientation_type = V3D_MANIP_GLOBAL;
+ scene->orientation_index_custom = -1;
+ }
+ BLI_freelinkN(&scene->transform_spaces, orientation);
+}
+
+TransformOrientation *BKE_scene_transform_orientation_find(
+ const Scene *scene, const int index)
+{
+ return BLI_findlink(&scene->transform_spaces, index);
+}
+
+/**
+ * \return the index that \a orientation has within \a scene's transform-orientation list or -1 if not found.
+ */
+int BKE_scene_transform_orientation_get_index(
+ const Scene *scene, const TransformOrientation *orientation)
+{
+ return BLI_findindex(&scene->transform_spaces, orientation);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 3c615221564..225f74616cf 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -39,19 +39,21 @@
#include "MEM_guardedalloc.h"
-#include "GPU_compositing.h"
-
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
+#include "BLI_math_vector.h"
#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
#include "BLI_rect.h"
+#include "BLI_utildefines.h"
+#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
/* ************ Spacetype/regiontype handling ************** */
@@ -72,6 +74,8 @@ static void spacetype_free(SpaceType *st)
if (pt->ext.free) {
pt->ext.free(pt->ext.data);
}
+
+ BLI_freelistN(&pt->children);
}
for (ht = art->headertypes.first; ht; ht = ht->next) {
@@ -85,8 +89,6 @@ static void spacetype_free(SpaceType *st)
}
BLI_freelistN(&st->regiontypes);
- BLI_freelistN(&st->toolshelf);
-
}
void BKE_spacetypes_free(void)
@@ -184,10 +186,35 @@ void BKE_spacedata_freelist(ListBase *lb)
BLI_freelistN(lb);
}
+static void panel_list_copy(ListBase *newlb, const ListBase *lb)
+{
+ BLI_listbase_clear(newlb);
+ BLI_duplicatelist(newlb, lb);
+
+ /* copy panel pointers */
+ Panel *newpa = newlb->first;
+ Panel *pa = lb->first;
+ for (; newpa; newpa = newpa->next, pa = pa->next) {
+ newpa->activedata = NULL;
+
+ Panel *newpatab = newlb->first;
+ Panel *patab = lb->first;
+ while (newpatab) {
+ if (newpa->paneltab == patab) {
+ newpa->paneltab = newpatab;
+ break;
+ }
+ newpatab = newpatab->next;
+ patab = patab->next;
+ }
+
+ panel_list_copy(&newpa->children, &pa->children);
+ }
+}
+
ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
{
ARegion *newar = MEM_dupallocN(ar);
- Panel *pa, *newpa, *patab;
newar->prev = newar->next = NULL;
BLI_listbase_clear(&newar->handlers);
@@ -195,9 +222,11 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
BLI_listbase_clear(&newar->panels_category);
BLI_listbase_clear(&newar->panels_category_active);
BLI_listbase_clear(&newar->ui_lists);
- newar->swinid = 0;
+ newar->visible = 0;
+ newar->gizmo_map = NULL;
newar->regiontimer = NULL;
newar->headerstr = NULL;
+ newar->draw_buffer = NULL;
/* use optional regiondata callback */
if (ar->regiondata) {
@@ -217,26 +246,11 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
if (ar->v2d.tab_offset)
newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
- BLI_listbase_clear(&newar->panels);
- BLI_duplicatelist(&newar->panels, &ar->panels);
+ panel_list_copy(&newar->panels, &ar->panels);
BLI_listbase_clear(&newar->ui_previews);
BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
- /* copy panel pointers */
- for (newpa = newar->panels.first; newpa; newpa = newpa->next) {
- patab = newar->panels.first;
- pa = ar->panels.first;
- while (patab) {
- if (newpa->paneltab == pa) {
- newpa->paneltab = patab;
- break;
- }
- patab = patab->next;
- pa = pa->next;
- }
- }
-
return newar;
}
@@ -295,6 +309,30 @@ void BKE_spacedata_draw_locks(int set)
}
}
+/**
+ * Version of #BKE_area_find_region_type that also works if \a slink is not the active space of \a sa.
+ */
+ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink, const ScrArea *sa, int region_type)
+{
+ const bool is_slink_active = slink == sa->spacedata.first;
+ const ListBase *regionbase = (is_slink_active) ?
+ &sa->regionbase : &slink->regionbase;
+ ARegion *ar = NULL;
+
+ BLI_assert(BLI_findindex(&sa->spacedata, slink) != -1);
+ for (ar = regionbase->first; ar; ar = ar->next) {
+ if (ar->regiontype == region_type) {
+ break;
+ }
+ }
+
+ /* Should really unit test this instead. */
+ BLI_assert(!is_slink_active || ar == BKE_area_find_region_type(sa, region_type));
+
+ return ar;
+}
+
+
static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL;
void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
@@ -310,6 +348,57 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
}
}
+/**
+ * Avoid bad-level calls to #WM_gizmomap_tag_refresh.
+ */
+static void (*region_refresh_tag_gizmomap_callback)(struct wmGizmoMap *) = NULL;
+
+void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *))
+{
+ region_refresh_tag_gizmomap_callback = callback;
+}
+
+void BKE_screen_gizmo_tag_refresh(struct bScreen *sc)
+{
+ if (region_refresh_tag_gizmomap_callback == NULL) {
+ return;
+ }
+
+ ScrArea *sa;
+ ARegion *ar;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->gizmo_map != NULL) {
+ region_refresh_tag_gizmomap_callback(ar->gizmo_map);
+ }
+ }
+ }
+}
+
+/**
+ * Avoid bad-level calls to #WM_gizmomap_delete.
+ */
+static void (*region_free_gizmomap_callback)(struct wmGizmoMap *) = NULL;
+
+void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *))
+{
+ region_free_gizmomap_callback = callback;
+}
+
+void BKE_area_region_panels_free(ListBase *lb)
+{
+ Panel *pa, *pa_next;
+ for (pa = lb->first; pa; pa = pa_next) {
+ pa_next = pa->next;
+ if (pa->activedata) {
+ MEM_freeN(pa->activedata);
+ }
+ BKE_area_region_panels_free(&pa->children);
+ }
+
+ BLI_freelistN(lb);
+}
+
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
{
@@ -332,16 +421,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
ar->v2d.tab_offset = NULL;
}
- if (!BLI_listbase_is_empty(&ar->panels)) {
- Panel *pa, *pa_next;
- for (pa = ar->panels.first; pa; pa = pa_next) {
- pa_next = pa->next;
- if (pa->activedata) {
- MEM_freeN(pa->activedata);
- }
- MEM_freeN(pa);
- }
- }
+ BKE_area_region_panels_free(&ar->panels);
for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
if (uilst->dyn_data) {
@@ -359,6 +439,11 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
MEM_freeN(uilst->properties);
}
}
+
+ if (ar->gizmo_map != NULL) {
+ region_free_gizmomap_callback(ar->gizmo_map);
+ }
+
BLI_freelistN(&ar->ui_lists);
BLI_freelistN(&ar->ui_previews);
BLI_freelistN(&ar->panels_category);
@@ -374,6 +459,7 @@ void BKE_screen_area_free(ScrArea *sa)
for (ar = sa->regionbase.first; ar; ar = ar->next)
BKE_area_region_free(st, ar);
+ MEM_SAFE_FREE(sa->global);
BLI_freelistN(&sa->regionbase);
BKE_spacedata_freelist(&sa->spacedata);
@@ -381,10 +467,21 @@ void BKE_screen_area_free(ScrArea *sa)
BLI_freelistN(&sa->actionzones);
}
+void BKE_screen_area_map_free(ScrAreaMap *area_map)
+{
+ for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
+ area_next = area->next;
+ BKE_screen_area_free(area);
+ }
+
+ BLI_freelistN(&area_map->vertbase);
+ BLI_freelistN(&area_map->edgebase);
+ BLI_freelistN(&area_map->areabase);
+}
+
/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free(bScreen *sc)
{
- ScrArea *sa, *san;
ARegion *ar;
/* No animdata here. */
@@ -394,51 +491,198 @@ void BKE_screen_free(bScreen *sc)
BLI_freelistN(&sc->regionbase);
- for (sa = sc->areabase.first; sa; sa = san) {
- san = sa->next;
- BKE_screen_area_free(sa);
- }
+ BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(sc));
- BLI_freelistN(&sc->vertbase);
- BLI_freelistN(&sc->edgebase);
- BLI_freelistN(&sc->areabase);
+ BKE_previewimg_free(&sc->preview);
/* Region and timer are freed by the window manager. */
MEM_SAFE_FREE(sc->tool_tip);
}
-/* for depsgraph */
-unsigned int BKE_screen_visible_layers(bScreen *screen, Scene *scene)
+/* ***************** Screen edges & verts ***************** */
+
+ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2)
{
+ ScrEdge *se;
+
+ BKE_screen_sort_scrvert(&v1, &v2);
+ for (se = sc->edgebase.first; se; se = se->next) {
+ if (se->v1 == v1 && se->v2 == v2) {
+ return se;
+ }
+ }
+
+ return NULL;
+}
+
+void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
+{
+ ScrVert *tmp;
+
+ if (*v1 > *v2) {
+ tmp = *v1;
+ *v1 = *v2;
+ *v2 = tmp;
+ }
+}
+
+void BKE_screen_remove_double_scrverts(bScreen *sc)
+{
+ ScrVert *v1, *verg;
+ ScrEdge *se;
ScrArea *sa;
- unsigned int layer = 0;
- if (screen) {
- /* get all used view3d layers */
- for (sa = screen->areabase.first; sa; sa = sa->next)
- if (sa->spacetype == SPACE_VIEW3D)
- layer |= ((View3D *)sa->spacedata.first)->lay;
+ verg = sc->vertbase.first;
+ while (verg) {
+ if (verg->newv == NULL) { /* !!! */
+ v1 = verg->next;
+ while (v1) {
+ if (v1->newv == NULL) { /* !?! */
+ if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
+ /* printf("doublevert\n"); */
+ v1->newv = verg;
+ }
+ }
+ v1 = v1->next;
+ }
+ }
+ verg = verg->next;
+ }
+
+ /* replace pointers in edges and faces */
+ se = sc->edgebase.first;
+ while (se) {
+ if (se->v1->newv) se->v1 = se->v1->newv;
+ if (se->v2->newv) se->v2 = se->v2->newv;
+ /* edges changed: so.... */
+ BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
+ se = se->next;
+ }
+ sa = sc->areabase.first;
+ while (sa) {
+ if (sa->v1->newv) sa->v1 = sa->v1->newv;
+ if (sa->v2->newv) sa->v2 = sa->v2->newv;
+ if (sa->v3->newv) sa->v3 = sa->v3->newv;
+ if (sa->v4->newv) sa->v4 = sa->v4->newv;
+ sa = sa->next;
+ }
+
+ /* remove */
+ verg = sc->vertbase.first;
+ while (verg) {
+ v1 = verg->next;
+ if (verg->newv) {
+ BLI_remlink(&sc->vertbase, verg);
+ MEM_freeN(verg);
+ }
+ verg = v1;
+ }
+
+}
+
+void BKE_screen_remove_double_scredges(bScreen *sc)
+{
+ ScrEdge *verg, *se, *sn;
+
+ /* compare */
+ verg = sc->edgebase.first;
+ while (verg) {
+ se = verg->next;
+ while (se) {
+ sn = se->next;
+ if (verg->v1 == se->v1 && verg->v2 == se->v2) {
+ BLI_remlink(&sc->edgebase, se);
+ MEM_freeN(se);
+ }
+ se = sn;
+ }
+ verg = verg->next;
}
+}
+
+void BKE_screen_remove_unused_scredges(bScreen *sc)
+{
+ ScrEdge *se, *sen;
+ ScrArea *sa;
+ int a = 0;
+
+ /* sets flags when edge is used in area */
+ sa = sc->areabase.first;
+ while (sa) {
+ se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
+ if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
+ if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
+ if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
+ else se->flag = 1;
+ sa = sa->next;
+ a++;
+ }
+ se = sc->edgebase.first;
+ while (se) {
+ sen = se->next;
+ if (se->flag == 0) {
+ BLI_remlink(&sc->edgebase, se);
+ MEM_freeN(se);
+ }
+ else {
+ se->flag = 0;
+ }
+ se = sen;
+ }
+}
+
+void BKE_screen_remove_unused_scrverts(bScreen *sc)
+{
+ ScrVert *sv, *svn;
+ ScrEdge *se;
- if (!layer)
- return scene->lay;
+ /* we assume edges are ok */
- return layer;
+ se = sc->edgebase.first;
+ while (se) {
+ se->v1->flag = 1;
+ se->v2->flag = 1;
+ se = se->next;
+ }
+
+ sv = sc->vertbase.first;
+ while (sv) {
+ svn = sv->next;
+ if (sv->flag == 0) {
+ BLI_remlink(&sc->vertbase, sv);
+ MEM_freeN(sv);
+ }
+ else {
+ sv->flag = 0;
+ }
+ sv = svn;
+ }
}
/* ***************** Utilities ********************** */
-/* Find a region of the specified type from the given area */
-ARegion *BKE_area_find_region_type(ScrArea *sa, int type)
+/**
+ * Find a region of type \a region_type in the currently active space of \a sa.
+ *
+ * \note This does _not_ work if the region to look up is not in the active
+ * space. Use #BKE_spacedata_find_region_type if that may be the case.
+ */
+ARegion *BKE_area_find_region_type(const ScrArea *sa, int region_type)
{
if (sa) {
- ARegion *ar;
-
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == type)
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == region_type)
return ar;
}
}
+
return NULL;
}
@@ -514,71 +758,26 @@ ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short
return big;
}
-ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
+ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap, const int spacetype, int x, int y)
{
- ScrArea *sa, *sa_found = NULL;
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (ScrArea *sa = areamap->areabase.first; sa; sa = sa->next) {
if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
- sa_found = sa;
+ return sa;
}
break;
}
}
- return sa_found;
-}
-
-
-/**
- * Utility function to get the active layer to use when adding new objects.
- */
-unsigned int BKE_screen_view3d_layer_active_ex(const View3D *v3d, const Scene *scene, bool use_localvd)
-{
- unsigned int lay;
- if ((v3d == NULL) || (v3d->scenelock && !v3d->localvd)) {
- lay = scene->layact;
- }
- else {
- lay = v3d->layact;
- }
-
- if (use_localvd) {
- if (v3d && v3d->localvd) {
- lay |= v3d->lay;
- }
- }
-
- return lay;
+ return NULL;
}
-unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const struct Scene *scene)
+ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
{
- return BKE_screen_view3d_layer_active_ex(v3d, scene, true);
-}
-
-/**
- * Accumulate all visible layers on this screen.
- */
-unsigned int BKE_screen_view3d_layer_all(const bScreen *sc)
-{
- const ScrArea *sa;
- unsigned int lay = 0;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
- lay |= v3d->lay;
- }
- }
-
- return lay;
+ return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(sc), spacetype, x, y);
}
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
{
- int bit;
-
if (v3d->scenelock && v3d->localvd == NULL) {
- v3d->lay = scene->lay;
v3d->camera = scene->camera;
if (v3d->camera == NULL) {
@@ -592,19 +791,10 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
}
}
}
-
- if ((v3d->lay & v3d->layact) == 0) {
- for (bit = 0; bit < 32; bit++) {
- if (v3d->lay & (1u << bit)) {
- v3d->layact = (1u << bit);
- break;
- }
- }
- }
}
}
-void BKE_screen_view3d_scene_sync(bScreen *sc)
+void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
{
/* are there cameras in the views that are not in the scene? */
ScrArea *sa;
@@ -613,59 +803,29 @@ void BKE_screen_view3d_scene_sync(bScreen *sc)
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *) sl;
- BKE_screen_view3d_sync(v3d, sc->scene);
+ BKE_screen_view3d_sync(v3d, scene);
}
}
}
}
-void BKE_screen_view3d_main_sync(ListBase *screen_lb, Scene *scene)
-{
- bScreen *sc;
- ScrArea *sa;
- SpaceLink *sl;
-
- /* from scene copy to the other views */
- for (sc = screen_lb->first; sc; sc = sc->id.next) {
- if (sc->scene != scene)
- continue;
-
- for (sa = sc->areabase.first; sa; sa = sa->next)
- for (sl = sa->spacedata.first; sl; sl = sl->next)
- if (sl->spacetype == SPACE_VIEW3D)
- BKE_screen_view3d_sync((View3D *)sl, scene);
- }
-}
-
-void BKE_screen_view3d_twmode_remove(View3D *v3d, const int i)
-{
- const int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
- if (selected_index == i) {
- v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
- }
- else if (selected_index > i) {
- v3d->twmode--;
- }
-}
-
-void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, Scene *scene, const int i)
+void BKE_screen_view3d_shading_init(View3DShading *shading)
{
- bScreen *sc;
+ memset(shading, 0, sizeof(*shading));
- for (sc = screen_lb->first; sc; sc = sc->id.next) {
- if (sc->scene == scene) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- BKE_screen_view3d_twmode_remove(v3d, i);
- }
- }
- }
- }
- }
+ shading->type = OB_SOLID;
+ shading->prev_type = OB_SOLID;
+ shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_BONE;
+ shading->light = V3D_LIGHTING_STUDIO;
+ shading->shadow_intensity = 0.5f;
+ shading->xray_alpha = 0.5f;
+ shading->xray_alpha_wire = 0.5f;
+ shading->cavity_valley_factor = 1.0f;
+ shading->cavity_ridge_factor = 1.0f;
+ shading->curvature_ridge_factor = 1.0f;
+ shading->curvature_valley_factor = 1.0f;
+ copy_v3_fl(shading->single_color, 0.8f);
+ copy_v3_fl(shading->background_color, 0.05f);
}
/* magic zoom calculation, no idea what
@@ -686,25 +846,12 @@ float BKE_screen_view3d_zoom_from_fac(float zoomfac)
return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
}
-void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings)
+bool BKE_screen_is_fullscreen_area(const bScreen *screen)
{
- /* currently we use DOF from the camera _only_,
- * so we never allocate this, only copy from the Camera */
-#if 0
- if ((fx_settings->dof == NULL) &&
- (fx_settings->fx_flag & GPU_FX_FLAG_DOF))
- {
- GPUDOFSettings *fx_dof;
- fx_dof = fx_settings->dof = MEM_callocN(sizeof(GPUDOFSettings), __func__);
- }
-#endif
-
- if ((fx_settings->ssao == NULL) &&
- (fx_settings->fx_flag & GPU_FX_FLAG_SSAO))
- {
- GPUSSAOSettings *fx_ssao;
- fx_ssao = fx_settings->ssao = MEM_callocN(sizeof(GPUSSAOSettings), __func__);
+ return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
+}
- GPU_fx_compositor_init_ssao_settings(fx_ssao);
- }
+bool BKE_screen_is_used(const bScreen *screen)
+{
+ return (screen->winid != 0);
}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index c69f8ff074f..d5e32ac7e39 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -1767,76 +1767,6 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
if (output != output) output = 1;
if (wipe->forward) output = 1 - output;
break;
- /* BOX WIPE IS NOT WORKING YET */
- /* case DO_CROSS_WIPE: */
- /* BOX WIPE IS NOT WORKING YET */
-#if 0
- case DO_BOX_WIPE:
- if (!wipe->forward) {
- facf0 = 1.0f - facf0; /* Go the other direction */
- }
-
- width = (int)(wipe->edgeWidth * ((xo + yo) / 2.0));
- hwidth = (float)width / 2.0;
- if (angle == 0) angle = 0.000001;
- b1 = posy / 2 - (-angle) * posx / 2;
- b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2);
- b2 = y - (-angle) * x;
-
- hyp = abs(angle * x + y + (-posy / 2 - angle * posx / 2)) * wipezone->pythangle;
- hyp2 = abs(angle * x + y + (-(yo - posy / 2) - angle * (xo - posx / 2))) * wipezone->pythangle;
-
- temp1 = xo * (1 - facf0 / 2) - xo * facf0 / 2;
- temp2 = yo * (1 - facf0 / 2) - yo * facf0 / 2;
- pointdist = hypot(temp1, temp2);
-
- if (b2 < b1 && b2 < b3) {
- if (hwidth < pointdist)
- output = in_band(hwidth, hyp, 0, 1);
- }
- else if (b2 > b1 && b2 > b3) {
- if (hwidth < pointdist)
- output = in_band(hwidth, hyp2, 0, 1);
- }
- else {
- if (hyp < hwidth && hyp2 > hwidth)
- output = in_band(hwidth, hyp, 1, 1);
- else if (hyp > hwidth && hyp2 < hwidth)
- output = in_band(hwidth, hyp2, 1, 1);
- else
- output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
- }
-
- if (!wipe->forward) {
- facf0 = 1.0f - facf0; /* Go the other direction */
- }
- angle = -1 / angle;
- b1 = posy / 2 - (-angle) * posx / 2;
- b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2);
- b2 = y - (-angle) * x;
-
- hyp = abs(angle * x + y + (-posy / 2 - angle * posx / 2)) * wipezone->pythangle;
- hyp2 = abs(angle * x + y + (-(yo - posy / 2) - angle * (xo - posx / 2))) * wipezone->pythangle;
-
- if (b2 < b1 && b2 < b3) {
- if (hwidth < pointdist)
- output *= in_band(hwidth, hyp, 0, 1);
- }
- else if (b2 > b1 && b2 > b3) {
- if (hwidth < pointdist)
- output *= in_band(hwidth, hyp2, 0, 1);
- }
- else {
- if (hyp < hwidth && hyp2 > hwidth)
- output *= in_band(hwidth, hyp, 1, 1);
- else if (hyp > hwidth && hyp2 < hwidth)
- output *= in_band(hwidth, hyp2, 1, 1);
- else
- output *= in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
- }
-
- break;
-#endif
case DO_IRIS_WIPE:
if (xo > yo) yo = xo;
else xo = yo;
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 57b3cd41047..c02a47db321 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -63,9 +63,9 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_movieclip.h"
@@ -75,6 +75,9 @@
#include "BKE_library.h"
#include "BKE_idprop.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "RE_pipeline.h"
@@ -89,8 +92,10 @@
#include "BKE_context.h"
#include "BKE_sound.h"
+#include "RE_engine.h"
+
#ifdef WITH_AUDASPACE
-# include AUD_SPECIAL_H
+# include <AUD_Special.h>
#endif
/* mutable state for sequencer */
@@ -587,17 +592,17 @@ void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixe
/*********************** sequencer pipeline functions *************************/
void BKE_sequencer_new_render_data(
- EvaluationContext *eval_ctx,
- Main *bmain, Scene *scene, int rectx, int recty,
- int preview_render_size,
+ Main *bmain, struct Depsgraph *depsgraph, Scene *scene, int rectx, int recty,
+ int preview_render_size, int for_render,
SeqRenderData *r_context)
{
- r_context->eval_ctx = eval_ctx;
r_context->bmain = bmain;
+ r_context->depsgraph = depsgraph;
r_context->scene = scene;
r_context->rectx = rectx;
r_context->recty = recty;
r_context->preview_render_size = preview_render_size;
+ r_context->for_render = for_render;
r_context->motion_blur_samples = 0;
r_context->motion_blur_shutter = 0;
r_context->skip_cache = false;
@@ -1457,6 +1462,7 @@ typedef struct SeqIndexBuildContext {
int view_id;
Main *bmain;
+ Depsgraph *depsgraph;
Scene *scene;
Sequence *seq, *orig_seq;
} SeqIndexBuildContext;
@@ -1589,12 +1595,8 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
}
if (sanim->anim) {
-#if 0
- seq_anim_add_suffix(scene, sanim->anim, i);
-#else
/* we already have the suffix */
IMB_suffix_anim(sanim->anim, suffix);
-#endif
}
else {
if (openfile) {
@@ -1945,7 +1947,9 @@ static int seq_proxy_context_count(Sequence *seq, Scene *scene)
return num_views;
}
-void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, ListBase *queue)
+void BKE_sequencer_proxy_rebuild_context(
+ Main *bmain, Depsgraph *depsgraph, Scene *scene,
+ Sequence *seq, struct GSet *file_list, ListBase *queue)
{
SeqIndexBuildContext *context;
Sequence *nseq;
@@ -1977,6 +1981,7 @@ void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *se
context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
context->bmain = bmain;
+ context->depsgraph = depsgraph;
context->scene = scene;
context->orig_seq = seq;
context->seq = nseq;
@@ -2030,9 +2035,10 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
/* fail safe code */
BKE_sequencer_new_render_data(
- bmain->eval_ctx, bmain, context->scene,
+ bmain, context->depsgraph, context->scene,
(scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f,
(scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 100,
+ false,
&render_context);
render_context.skip_cache = true;
@@ -2752,17 +2758,12 @@ static ImBuf *seq_render_effect_strip_impl(
if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
sh.get_default_fac(seq, cfra, &fac, &facf);
-
- if ((scene->r.mode & R_FIELDS) == 0)
- facf = fac;
+ facf = fac;
}
else {
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
if (fcu) {
fac = facf = evaluate_fcurve(fcu, cfra);
- if (scene->r.mode & R_FIELDS) {
- facf = evaluate_fcurve(fcu, cfra + 0.5f);
- }
}
else {
fac = facf = seq->effect_fader;
@@ -3130,7 +3131,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
/* anim-data */
adt = BKE_animdata_from_id(&mask->id);
- BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(context->depsgraph, context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
@@ -3267,6 +3268,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
// have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */
have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree;
+ /* Get view layer for the strip. */
+ ViewLayer *view_layer = BKE_view_layer_default_render(scene);
+ /* Depsgraph will be NULL when doing rendering. */
+ Depsgraph *depsgraph = NULL;
+
orig_data.scemode = scene->r.scemode;
orig_data.cfra = scene->r.cfra;
orig_data.subframe = scene->r.subframe;
@@ -3322,12 +3328,16 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
/* opengl offscreen render */
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
+ depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
- context->bmain, scene, camera, width, height, IB_rect, draw_flags, context->scene->r.seq_prev_type,
+ depsgraph, scene,
+ context->scene->r.seq_prev_type,
+ camera, width, height, IB_rect,
+ draw_flags,
scene->r.alphamode, context->gpu_samples, viewname,
- context->gpu_fx, context->gpu_offscreen, err_out);
+ context->gpu_offscreen, err_out);
if (ibuf == NULL) {
fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
}
@@ -3348,12 +3358,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
* When rendering from command line renderer is called from main thread, in this
* case it's always safe to render scene here
*/
- if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) {
+ if (!is_thread_main || is_rendering == false || is_background || context->for_render) {
if (re == NULL)
re = RE_NewSceneRender(scene);
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
- RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false);
+ RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, frame, false);
/* restore previous state after it was toggled on & off by RE_BlenderFrame */
G.is_rendering = is_rendering;
@@ -3411,8 +3420,8 @@ finally:
scene->r.cfra = orig_data.cfra;
scene->r.subframe = orig_data.subframe;
- if (is_frame_update) {
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
+ if (is_frame_update && (depsgraph != NULL)) {
+ BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
}
#ifdef DURIAN_CAMERA_SWITCH
@@ -3502,7 +3511,7 @@ static ImBuf *do_render_strip_uncached(
ibuf = seq_render_scene_strip(context, seq, nr, cfra);
/* Scene strips update all animation, so we need to restore original state.*/
- BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra);
+ BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, context->scene, cfra);
copy_to_ibuf_still(context, seq, nr, ibuf);
}
@@ -5239,11 +5248,6 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
if (sound->playback_handle == NULL) {
BKE_libblock_free(bmain, sound);
-#if 0
- if (op)
- BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
-#endif
-
return NULL;
}
@@ -5251,10 +5255,6 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
if (info.specs.channels == AUD_CHANNELS_INVALID) {
BKE_libblock_free(bmain, sound);
-#if 0
- if (op)
- BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
-#endif
return NULL;
}
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
new file mode 100644
index 00000000000..f19b450dece
--- /dev/null
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -0,0 +1,245 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/shader_fx.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_shader_fx_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_shader_fx.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "FX_shader_types.h"
+
+static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = { NULL };
+
+/* *************************************************** */
+/* Methods - Evaluation Loops, etc. */
+
+/* check if exist grease pencil effects */
+bool BKE_shaderfx_has_gpencil(Object *ob)
+{
+ ShaderFxData *fx;
+ for (fx = ob->shader_fx.first; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ if (fxi->type == eShaderFxType_GpencilType) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void BKE_shaderfx_init(void)
+{
+ /* Initialize shaders */
+ shaderfx_type_init(shader_fx_types); /* FX_shader_util.c */
+}
+
+ShaderFxData *BKE_shaderfx_new(int type)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
+
+ /* note, this name must be made unique later */
+ BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name));
+
+ fx->type = type;
+ fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded;
+ fx->flag = eShaderFxFlag_StaticOverride_Local;
+
+ if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode)
+ fx->mode |= eShaderFxMode_Editmode;
+
+ if (fxi->initData) fxi->initData(fx);
+
+ return fx;
+}
+
+static void shaderfx_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(fx, NULL, shaderfx_free_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(fx, NULL, (ShaderFxObjectWalkFunc)shaderfx_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (fxi->freeData) fxi->freeData(fx);
+ if (fx->error) MEM_freeN(fx->error);
+
+ MEM_freeN(fx);
+}
+
+void BKE_shaderfx_free(ShaderFxData *fx)
+{
+ BKE_shaderfx_free_ex(fx, 0);
+}
+
+/* check unique name */
+bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
+{
+ if (shaders && fx) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ return BLI_uniquename(shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name));
+ }
+ return false;
+}
+
+bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ return fxi->dependsOnTime && fxi->dependsOnTime(fx);
+}
+
+const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
+{
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
+ return shader_fx_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type);
+
+ /* fx_dst may have already be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (fxi->freeData) {
+ fxi->freeData(fx_dst);
+ }
+
+ const size_t data_size = sizeof(ShaderFxData);
+ const char *fx_src_data = ((const char *)fx_src) + data_size;
+ char *fx_dst_data = ((char *)fx_dst) + data_size;
+ BLI_assert(data_size <= (size_t)fxi->struct_size);
+ memcpy(fx_dst_data, fx_src_data, (size_t)fxi->struct_size - data_size);
+}
+
+static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ target->mode = fx->mode;
+ target->flag = fx->flag;
+
+ if (fxi->copyData) {
+ fxi->copyData(fx, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(target, NULL, shaderfx_copy_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(target, NULL, (ShaderFxObjectWalkFunc)shaderfx_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_ex(fx, target, 0);
+}
+
+ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+
+ for (; fx; fx = fx->next)
+ if (fx->type == type)
+ break;
+
+ return fx;
+}
+
+void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+
+ for (; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ if (fxi->foreachIDLink) fxi->foreachIDLink(fx, ob, walk, userData);
+ else if (fxi->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ ShaderFxObjectWalkFunc fp = (ShaderFxObjectWalkFunc)walk;
+ fxi->foreachObjectLink(fx, ob, fp, userData);
+ }
+ }
+}
+
+ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name)
+{
+ return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name));
+}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 65d42467f67..87193df3b49 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -45,15 +45,22 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_task.h"
+#include "BLI_math_solvers.h"
#include "BKE_shrinkwrap.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_DerivedMesh.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h" /* for OMP limits. */
#include "BKE_subsurf.h"
+#include "BKE_mesh_runtime.h"
+
+#include "MEM_guardedalloc.h"
#include "BLI_strict_flags.h"
@@ -67,20 +74,262 @@
/* Util macros */
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
+typedef struct ShrinkwrapCalcData {
+ ShrinkwrapModifierData *smd; //shrinkwrap modifier data
+
+ struct Object *ob; //object we are applying shrinkwrap to
+
+ struct MVert *vert; //Array of verts being projected (to fetch normals or other data)
+ float(*vertexCos)[3]; //vertexs being shrinkwraped
+ int numVerts;
+
+ struct MDeformVert *dvert; //Pointer to mdeform array
+ int vgroup; //Vertex group num
+ bool invert_vgroup; /* invert vertex group influence */
+
+ struct Mesh *target; //mesh we are shrinking to
+ struct SpaceTransform local2target; //transform to move between local and target space
+ struct ShrinkwrapTreeData *tree; // mesh BVH tree data
+
+ float keepDist; //Distance to keep above target surface (units are in local space)
+
+} ShrinkwrapCalcData;
+
typedef struct ShrinkwrapCalcCBData {
ShrinkwrapCalcData *calc;
- void *treeData;
- void *auxData;
- BVHTree *targ_tree;
- BVHTree *aux_tree;
- void *targ_callback;
- void *aux_callback;
+ ShrinkwrapTreeData *tree;
+ ShrinkwrapTreeData *aux_tree;
float *proj_axis;
SpaceTransform *local2aux;
} ShrinkwrapCalcCBData;
+
+/* Checks if the modifier needs target normals with these settings. */
+bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
+{
+ return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
+ (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX && shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
+}
+
+/* Initializes the mesh data structure from the given mesh and settings. */
+bool BKE_shrinkwrap_init_tree(ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
+{
+ memset(data, 0, sizeof(*data));
+
+ if (!mesh || mesh->totvert <= 0) {
+ return false;
+ }
+
+ data->mesh = mesh;
+
+ if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
+ data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2);
+
+ return data->bvh != NULL;
+ }
+ else {
+ if (mesh->totpoly <= 0) {
+ return false;
+ }
+
+ data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_LOOPTRI, 4);
+
+ if (data->bvh == NULL) {
+ return false;
+ }
+
+ if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
+ if ((mesh->flag & ME_AUTOSMOOTH) != 0) {
+ data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ }
+ }
+
+ if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ data->boundary = mesh->runtime.shrinkwrap_data;
+ }
+
+ return true;
+ }
+}
+
+/* Frees the tree data if necessary. */
+void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
+{
+ free_bvhtree_from_mesh(&data->treeData);
+}
+
+/* Free boundary data for target project */
+void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh)
+{
+ struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
+
+ if (data != NULL) {
+ MEM_freeN((void *)data->edge_is_boundary);
+ MEM_freeN((void *)data->looptri_has_boundary);
+ MEM_freeN((void *)data->vert_boundary_id);
+ MEM_freeN((void *)data->boundary_verts);
+
+ MEM_freeN(data);
+ }
+
+ mesh->runtime.shrinkwrap_data = NULL;
+}
+
+/* Accumulate edge for average boundary edge direction. */
+static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata, signed char *status, int index, const float edge_dir[3], signed char side)
+{
+ BLI_assert(index >= 0);
+ float *direction = vdata[index].direction;
+
+ /* Invert the direction vector if either:
+ * - This is the second edge and both edges have the vertex as start or end.
+ * - For third and above, if it points in the wrong direction.
+ */
+ if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) {
+ sub_v3_v3(direction, edge_dir);
+ }
+ else {
+ add_v3_v3(direction, edge_dir);
+ }
+
+ status[index] = (status[index] == 0) ? side : -1;
+}
+
+static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(struct Mesh *mesh)
+{
+ const MLoop *mloop = mesh->mloop;
+ const MEdge *medge = mesh->medge;
+ const MVert *mvert = mesh->mvert;
+
+ /* Count faces per edge (up to 2). */
+ char *edge_mode = MEM_calloc_arrayN((size_t)mesh->totedge, sizeof(char), __func__);
+
+ for (int i = 0; i < mesh->totloop; i++) {
+ unsigned int eidx = mloop[i].e;
+
+ if (edge_mode[eidx] < 2) {
+ edge_mode[eidx]++;
+ }
+ }
+
+ /* Build the boundary edge bitmask. */
+ BLI_bitmap *edge_is_boundary = BLI_BITMAP_NEW(mesh->totedge, "ShrinkwrapBoundaryData::edge_is_boundary");
+ unsigned int num_boundary_edges = 0;
+
+ for (int i = 0; i < mesh->totedge; i++) {
+ edge_mode[i] = (edge_mode[i] == 1);
+
+ if (edge_mode[i]) {
+ BLI_BITMAP_ENABLE(edge_is_boundary, i);
+ num_boundary_edges++;
+ }
+ }
+
+ /* If no boundary, return NULL. */
+ if (num_boundary_edges == 0) {
+ MEM_freeN(edge_is_boundary);
+ MEM_freeN(edge_mode);
+ return NULL;
+ }
+
+ /* Allocate the data object. */
+ ShrinkwrapBoundaryData *data = MEM_callocN(sizeof(ShrinkwrapBoundaryData), "ShrinkwrapBoundaryData");
+
+ data->edge_is_boundary = edge_is_boundary;
+
+ /* Build the boundary looptri bitmask. */
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ int totlooptri = BKE_mesh_runtime_looptri_len(mesh);
+
+ BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(totlooptri, "ShrinkwrapBoundaryData::looptri_is_boundary");
+
+ for (int i = 0; i < totlooptri; i++) {
+ int edges[3];
+ BKE_mesh_looptri_get_real_edges(mesh, &mlooptri[i], edges);
+
+ for (int j = 0; j < 3; j++) {
+ if (edges[j] >= 0 && edge_mode[edges[j]]) {
+ BLI_BITMAP_ENABLE(looptri_has_boundary, i);
+ break;
+ }
+ }
+ }
+
+ data->looptri_has_boundary = looptri_has_boundary;
+
+ /* Find boundary vertices and build a mapping table for compact storage of data. */
+ int *vert_boundary_id = MEM_calloc_arrayN((size_t)mesh->totvert, sizeof(int), "ShrinkwrapBoundaryData::vert_boundary_id");
+
+ for (int i = 0; i < mesh->totedge; i++) {
+ if (edge_mode[i]) {
+ const MEdge *edge = &medge[i];
+
+ vert_boundary_id[edge->v1] = 1;
+ vert_boundary_id[edge->v2] = 1;
+ }
+ }
+
+ unsigned int num_boundary_verts = 0;
+
+ for (int i = 0; i < mesh->totvert; i++) {
+ vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? (int)num_boundary_verts++ : -1;
+ }
+
+ data->vert_boundary_id = vert_boundary_id;
+ data->num_boundary_verts = num_boundary_verts;
+
+ /* Compute average directions. */
+ ShrinkwrapBoundaryVertData *boundary_verts = MEM_calloc_arrayN(num_boundary_verts, sizeof(*boundary_verts), "ShrinkwrapBoundaryData::boundary_verts");
+
+ signed char *vert_status = MEM_calloc_arrayN(num_boundary_verts, sizeof(char), __func__);
+
+ for (int i = 0; i < mesh->totedge; i++) {
+ if (edge_mode[i]) {
+ const MEdge *edge = &medge[i];
+
+ float dir[3];
+ sub_v3_v3v3(dir, mvert[edge->v2].co, mvert[edge->v1].co);
+ normalize_v3(dir);
+
+ merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v1], dir, 1);
+ merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v2], dir, 2);
+ }
+ }
+
+ MEM_freeN(vert_status);
+
+ /* Finalize average direction and compute normal. */
+ for (int i = 0; i < mesh->totvert; i++) {
+ int bidx = vert_boundary_id[i];
+
+ if (bidx >= 0) {
+ ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
+ float no[3], tmp[3];
+
+ normalize_v3(vdata->direction);
+
+ normal_short_to_float_v3(no, mesh->mvert[i].no);
+ cross_v3_v3v3(tmp, no, vdata->direction);
+ cross_v3_v3v3(vdata->normal_plane, tmp, no);
+ normalize_v3(vdata->normal_plane);
+ }
+ }
+
+ data->boundary_verts = boundary_verts;
+
+ MEM_freeN(edge_mode);
+ return data;
+}
+
+void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh)
+{
+ BKE_shrinkwrap_discard_boundary_data(mesh);
+
+ mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh);
+}
+
/*
* Shrinkwrap to the nearest vertex
*
@@ -95,7 +344,7 @@ static void shrinkwrap_calc_nearest_vertex_cb_ex(
ShrinkwrapCalcCBData *data = userdata;
ShrinkwrapCalcData *calc = data->calc;
- BVHTreeFromMesh *treeData = data->treeData;
+ BVHTreeFromMesh *treeData = &data->tree->treeData;
BVHTreeNearest *nearest = tls->userdata_chunk;
float *co = calc->vertexCos[i];
@@ -151,24 +400,13 @@ static void shrinkwrap_calc_nearest_vertex_cb_ex(
static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
{
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
- if (calc->target != NULL && calc->target->getNumVerts(calc->target) == 0) {
- return;
- }
-
- TIMEIT_BENCH(bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_VERTS, 2), bvhtree_verts);
- if (treeData.tree == NULL) {
- OUT_OF_MEMORY();
- return;
- }
-
/* Setup nearest */
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
- ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ ShrinkwrapCalcCBData data = {.calc = calc, .tree = calc->tree};
ParallelRangeSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
@@ -177,8 +415,6 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
BLI_task_parallel_range(0, calc->numVerts,
&data, shrinkwrap_calc_nearest_vertex_cb_ex,
&settings);
-
- free_bvhtree_from_mesh(&treeData);
}
@@ -193,8 +429,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
bool BKE_shrinkwrap_project_normal(
char options, const float vert[3], const float dir[3],
const float ray_radius, const SpaceTransform *transf,
- BVHTree *tree, BVHTreeRayHit *hit,
- BVHTree_RayCastCallback callback, void *userdata)
+ ShrinkwrapTreeData *tree, BVHTreeRayHit *hit)
{
/* don't use this because this dist value could be incompatible
* this value used by the callback for comparing prev/new dist values.
@@ -229,7 +464,7 @@ bool BKE_shrinkwrap_project_normal(
hit_tmp.index = -1;
- BLI_bvhtree_ray_cast(tree, co, no, ray_radius, &hit_tmp, callback, userdata);
+ BLI_bvhtree_ray_cast(tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData);
if (hit_tmp.index != -1) {
/* invert the normal first so face culling works on rotated objects */
@@ -237,7 +472,7 @@ bool BKE_shrinkwrap_project_normal(
BLI_space_transform_invert_normal(transf, hit_tmp.no);
}
- if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) {
+ if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) {
/* apply backface */
const float dot = dot_v3v3(dir, hit_tmp.no);
if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
@@ -271,12 +506,8 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
ShrinkwrapCalcCBData *data = userdata;
ShrinkwrapCalcData *calc = data->calc;
- void *treeData = data->treeData;
- void *auxData = data->auxData;
- BVHTree *targ_tree = data->targ_tree;
- BVHTree *aux_tree = data->aux_tree;
- void *targ_callback = data->targ_callback;
- void *aux_callback = data->aux_callback;
+ ShrinkwrapTreeData *tree = data->tree;
+ ShrinkwrapTreeData *aux_tree = data->aux_tree;
float *proj_axis = data->proj_axis;
SpaceTransform *local2aux = data->local2aux;
@@ -296,41 +527,40 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
return;
}
- if (calc->vert) {
- /* calc->vert contains verts from derivedMesh */
- /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
- /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
- if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- normal_short_to_float_v3(tmp_no, calc->vert[i].no);
- }
- else {
- copy_v3_v3(tmp_co, co);
- copy_v3_v3(tmp_no, proj_axis);
- }
+ if (calc->vert != NULL && calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
+ /* calc->vert contains verts from evaluated mesh. */
+ /* These coordinates are deformed by vertexCos only for normal projection (to get correct normals) */
+ /* for other cases calc->verts contains undeformed coordinates and vertexCos should be used */
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ normal_short_to_float_v3(tmp_no, calc->vert[i].no);
}
else {
copy_v3_v3(tmp_co, co);
copy_v3_v3(tmp_no, proj_axis);
}
-
hit->index = -1;
hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+ bool is_aux = false;
+
/* Project over positive direction of axis */
if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, tmp_no, 0.0,
- local2aux, aux_tree, hit,
- aux_callback, auxData);
+ if (BKE_shrinkwrap_project_normal(
+ 0, tmp_co, tmp_no, 0.0,
+ local2aux, aux_tree, hit))
+ {
+ is_aux = true;
+ }
}
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0,
- &calc->local2target, targ_tree, hit,
- targ_callback, treeData);
+ if (BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0,
+ &calc->local2target, tree, hit))
+ {
+ is_aux = false;
+ }
}
/* Project over negative direction of axis */
@@ -338,34 +568,54 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
float inv_no[3];
negate_v3_v3(inv_no, tmp_no);
+ char options = calc->smd->shrinkOpts;
+
+ if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) && (options & MOD_SHRINKWRAP_CULL_TARGET_MASK)) {
+ options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK;
+ }
+
if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, inv_no, 0.0,
- local2aux, aux_tree, hit,
- aux_callback, auxData);
+ if (BKE_shrinkwrap_project_normal(
+ 0, tmp_co, inv_no, 0.0,
+ local2aux, aux_tree, hit))
+ {
+ is_aux = true;
+ }
}
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, inv_no, 0.0,
- &calc->local2target, targ_tree, hit,
- targ_callback, treeData);
+ if (BKE_shrinkwrap_project_normal(
+ options, tmp_co, inv_no, 0.0,
+ &calc->local2target, tree, hit))
+ {
+ is_aux = false;
+ }
}
/* don't set the initial dist (which is more efficient),
* because its calculated in the targets space, we want the dist in our own space */
if (proj_limit_squared != 0.0f) {
- if (len_squared_v3v3(hit->co, co) > proj_limit_squared) {
+ if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) {
hit->index = -1;
}
}
if (hit->index != -1) {
- madd_v3_v3v3fl(hit->co, hit->co, tmp_no, calc->keepDist);
+ if (is_aux) {
+ BKE_shrinkwrap_snap_point_to_surface(
+ aux_tree, local2aux, calc->smd->shrinkMode,
+ hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co);
+ }
+ else {
+ BKE_shrinkwrap_snap_point_to_surface(
+ tree, &calc->local2target, calc->smd->shrinkMode,
+ hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co);
+ }
+
interp_v3_v3v3(co, co, hit->co, weight);
}
}
-static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render)
+static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
{
/* Options about projection direction */
float proj_axis[3] = {0.0f, 0.0f, 0.0f};
@@ -376,11 +626,12 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
* for finding the best hit, to get the real dist,
* measure the len_v3v3() from the input coord to hit.co */
BVHTreeRayHit hit;
- void *treeData = NULL;
/* auxiliary target */
- DerivedMesh *auxMesh = NULL;
- void *auxData = NULL;
+ Mesh *auxMesh = NULL;
+ bool auxMesh_free;
+ ShrinkwrapTreeData *aux_tree = NULL;
+ ShrinkwrapTreeData aux_tree_stack;
SpaceTransform local2aux;
/* If the user doesn't allows to project in any direction of projection axis
@@ -388,10 +639,6 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
return;
- if (calc->target != NULL && calc->target->getNumPolys(calc->target) == 0) {
- return;
- }
-
/* Prepare data to retrieve the direction in which we should project each vertex */
if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
if (calc->vert == NULL) return;
@@ -412,97 +659,382 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
if (calc->smd->auxTarget) {
- auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render);
+ auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->smd->auxTarget, &auxMesh_free);
if (!auxMesh)
return;
BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget);
}
- /* use editmesh to avoid array allocation */
- BMEditMesh *emtarget = NULL, *emaux = NULL;
- union {
- BVHTreeFromEditMesh emtreedata;
- BVHTreeFromMesh dmtreedata;
- } treedata_stack, auxdata_stack;
+ if (BKE_shrinkwrap_init_tree(&aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false)) {
+ aux_tree = &aux_tree_stack;
+ }
- BVHTree *targ_tree;
- void *targ_callback;
- if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) {
- emtarget = BKE_editmesh_from_object(calc->smd->target);
- if ((targ_tree = bvhtree_from_editmesh_looptri(
- &treedata_stack.emtreedata, emtarget, 0.0, 4, 6, &calc->target->bvhCache)))
- {
- targ_callback = treedata_stack.emtreedata.raycast_callback;
- treeData = &treedata_stack.emtreedata;
- }
+ /* After successfully build the trees, start projection vertices. */
+ ShrinkwrapCalcCBData data = {
+ .calc = calc, .tree = calc->tree, .aux_tree = aux_tree,
+ .proj_axis = proj_axis, .local2aux = &local2aux
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
+ settings.userdata_chunk = &hit;
+ settings.userdata_chunk_size = sizeof(hit);
+ BLI_task_parallel_range(0, calc->numVerts,
+ &data,
+ shrinkwrap_calc_normal_projection_cb_ex,
+ &settings);
+
+ /* free data structures */
+ if (aux_tree) {
+ BKE_shrinkwrap_free_tree(aux_tree);
}
- else {
- if ((targ_tree = bvhtree_from_mesh_get(
- &treedata_stack.dmtreedata, calc->target, BVHTREE_FROM_LOOPTRI, 4)))
- {
- targ_callback = treedata_stack.dmtreedata.raycast_callback;
- treeData = &treedata_stack.dmtreedata;
- }
- }
- if (targ_tree) {
- BVHTree *aux_tree = NULL;
- void *aux_callback = NULL;
- if (auxMesh != NULL && auxMesh->getNumPolys(auxMesh) != 0) {
- /* use editmesh to avoid array allocation */
- if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
- emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
- if ((aux_tree = bvhtree_from_editmesh_looptri(
- &auxdata_stack.emtreedata, emaux, 0.0, 4, 6, &auxMesh->bvhCache)))
- {
- aux_callback = auxdata_stack.emtreedata.raycast_callback;
- auxData = &auxdata_stack.emtreedata;
+ if (auxMesh != NULL && auxMesh_free) {
+ BKE_id_free(NULL, auxMesh);
+ }
+}
+
+/*
+ * Shrinkwrap Target Surface Project mode
+ *
+ * It uses Newton's method to find a surface location with its
+ * smooth normal pointing at the original point.
+ *
+ * The equation system on barycentric weights and normal multiplier:
+ *
+ * (w0*V0 + w1*V1 + w2*V2) + l * (w0*N0 + w1*N1 + w2*N2) - CO = 0
+ * w0 + w1 + w2 = 1
+ *
+ * The actual solution vector is [ w0, w1, l ], with w2 eliminated.
+ */
+
+//#define TRACE_TARGET_PROJECT
+
+typedef struct TargetProjectTriData {
+ const float **vtri_co;
+ const float (*vtri_no)[3];
+ const float *point_co;
+
+ float n0_minus_n2[3], n1_minus_n2[3];
+ float c0_minus_c2[3], c1_minus_c2[3];
+
+ /* Current interpolated position and normal. */
+ float co_interp[3], no_interp[3];
+} TargetProjectTriData;
+
+/* Computes the deviation of the equation system from goal. */
+static void target_project_tri_deviation(void *userdata, const float x[3], float r_delta[3])
+{
+ TargetProjectTriData *data = userdata;
+
+ float w[3] = { x[0], x[1], 1.0f - x[0] - x[1] };
+ interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w);
+ interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w);
+
+ madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]);
+ sub_v3_v3(r_delta, data->point_co);
+}
+
+/* Computes the Jacobian matrix of the equation system. */
+static void target_project_tri_jacobian(void *userdata, const float x[3], float r_jacobian[3][3])
+{
+ TargetProjectTriData *data = userdata;
+
+ madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]);
+ madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]);
+
+ copy_v3_v3(r_jacobian[2], data->vtri_no[2]);
+ madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]);
+ madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]);
+}
+
+/* Clamp barycentric weights to the triangle. */
+static void target_project_tri_clamp(float x[3])
+{
+ if (x[0] < 0.0f) {
+ x[0] = 0.0f;
+ }
+ if (x[1] < 0.0f) {
+ x[1] = 0.0f;
+ }
+ if (x[0] + x[1] > 1.0f) {
+ x[0] = x[0] / (x[0] + x[1]);
+ x[1] = 1.0f - x[0];
+ }
+}
+
+/* Correct the Newton's method step to keep the coordinates within the triangle. */
+static bool target_project_tri_correct(void *UNUSED(userdata), const float x[3], float step[3], float x_next[3])
+{
+ /* Insignificant correction threshold */
+ const float epsilon = 1e-6f;
+ const float dir_epsilon = 0.05f;
+ bool fixed = false, locked = false;
+
+ /* Weight 0 and 1 boundary check. */
+ for (int i = 0; i < 2; i++) {
+ if (step[i] > x[i]) {
+ if (step[i] > dir_epsilon * fabsf(step[1 - i])) {
+ /* Abort if the solution is clearly outside the domain. */
+ if (x[i] < epsilon) {
+ return false;
}
+
+ /* Scale a significant step down to arrive at the boundary. */
+ mul_v3_fl(step, x[i] / step[i]);
+ fixed = true;
}
else {
- if ((aux_tree = bvhtree_from_mesh_get(
- &auxdata_stack.dmtreedata, auxMesh, BVHTREE_FROM_LOOPTRI, 4)) != NULL)
- {
- aux_callback = auxdata_stack.dmtreedata.raycast_callback;
- auxData = &auxdata_stack.dmtreedata;
- }
+ /* Reset precision errors to stay at the boundary. */
+ step[i] = x[i];
+ fixed = locked = true;
}
}
- /* After sucessufuly build the trees, start projection vertexs */
- ShrinkwrapCalcCBData data = {
- .calc = calc,
- .treeData = treeData, .targ_tree = targ_tree, .targ_callback = targ_callback,
- .auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback,
- .proj_axis = proj_axis, .local2aux = &local2aux,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
- settings.userdata_chunk = &hit;
- settings.userdata_chunk_size = sizeof(hit);
- BLI_task_parallel_range(0, calc->numVerts,
- &data,
- shrinkwrap_calc_normal_projection_cb_ex,
- &settings);
}
- /* free data structures */
- if (treeData) {
- if (emtarget) {
- free_bvhtree_from_editmesh(treeData);
+ /* Weight 2 boundary check. */
+ float sum = x[0] + x[1];
+ float sstep = step[0] + step[1];
+
+ if (sum - sstep > 1.0f) {
+ if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) {
+ /* Abort if the solution is clearly outside the domain. */
+ if (sum > 1.0f - epsilon) {
+ return false;
+ }
+
+ /* Scale a significant step down to arrive at the boundary. */
+ mul_v3_fl(step, (1.0f - sum) / -sstep);
+ fixed = true;
}
else {
- free_bvhtree_from_mesh(treeData);
+ /* Reset precision errors to stay at the boundary. */
+ if (locked) {
+ step[0] = step[1] = 0.0f;
+ }
+ else {
+ step[0] -= 0.5f * sstep;
+ step[1] = -step[0];
+ fixed = true;
+ }
+ }
+ }
+
+ /* Recompute and clamp the new coordinates after step correction. */
+ if (fixed) {
+ sub_v3_v3v3(x_next, x, step);
+ target_project_tri_clamp(x_next);
+ }
+
+ return true;
+}
+
+static bool target_project_solve_point_tri(
+ const float *vtri_co[3], const float vtri_no[3][3], const float point_co[3],
+ const float hit_co[3], float hit_dist_sq,
+ float r_hit_co[3], float r_hit_no[3])
+{
+ float x[3], tmp[3];
+ float dist = sqrtf(hit_dist_sq);
+ float epsilon = dist * 1.0e-5f;
+
+ CLAMP_MIN(epsilon, 1.0e-5f);
+
+ /* Initial solution vector: barycentric weights plus distance along normal. */
+ interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co);
+
+ interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x);
+ sub_v3_v3v3(tmp, point_co, hit_co);
+
+ x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist;
+
+ /* Solve the equations iteratively. */
+ TargetProjectTriData tri_data = { .vtri_co = vtri_co, .vtri_no = vtri_no, .point_co = point_co };
+
+ sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]);
+ sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]);
+ sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]);
+ sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]);
+
+ target_project_tri_clamp(x);
+
+#ifdef TRACE_TARGET_PROJECT
+ const bool trace = true;
+#else
+ const bool trace = false;
+#endif
+
+ bool ok = BLI_newton3d_solve(target_project_tri_deviation, target_project_tri_jacobian, target_project_tri_correct, &tri_data, epsilon, 20, trace, x, x);
+
+ if (ok) {
+ copy_v3_v3(r_hit_co, tri_data.co_interp);
+ copy_v3_v3(r_hit_no, tri_data.no_interp);
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool update_hit(BVHTreeNearest *nearest, int index, const float co[3], const float hit_co[3], const float hit_no[3])
+{
+ float dist_sq = len_squared_v3v3(hit_co, co);
+
+ if (dist_sq < nearest->dist_sq) {
+#ifdef TRACE_TARGET_PROJECT
+ printf("===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq);
+#endif
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, hit_co);
+ normalize_v3_v3(nearest->no, hit_no);
+ return true;
+ }
+
+ return false;
+}
+
+/* Target projection on a non-manifold boundary edge - treats it like an infinitely thin cylinder. */
+static void target_project_edge(const ShrinkwrapTreeData *tree, int index, const float co[3], BVHTreeNearest *nearest, int eidx)
+{
+ const BVHTreeFromMesh *data = &tree->treeData;
+ const MEdge *edge = &tree->mesh->medge[eidx];
+ const float *vedge_co[2] = { data->vert[edge->v1].co, data->vert[edge->v2].co };
+
+#ifdef TRACE_TARGET_PROJECT
+ printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n", eidx, UNPACK3(vedge_co[0]), UNPACK3(vedge_co[1]));
+#endif
+
+ /* Retrieve boundary vertex IDs */
+ const int *vert_boundary_id = tree->boundary->vert_boundary_id;
+ int bid1 = vert_boundary_id[edge->v1], bid2 = vert_boundary_id[edge->v2];
+
+ if (bid1 < 0 || bid2 < 0) {
+ return;
+ }
+
+ /* Retrieve boundary vertex normals and align them to direction. */
+ const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts;
+ float vedge_dir[2][3], dir[3];
+
+ copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane);
+ copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane);
+
+ sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]);
+
+ if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) {
+ negate_v3(vedge_dir[0]);
+ }
+ if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) {
+ negate_v3(vedge_dir[1]);
+ }
+
+ /* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */
+ float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]);
+ float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]);
+ float d0co = dot_v3v3(vedge_dir[0], co);
+
+ float a = d0v1 - d0v0 + d1v0 - d1v1;
+ float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co);
+ float c = d0co - d0v0;
+ float det = b * b - 4 * a * c;
+
+ if (det >= 0) {
+ const float epsilon = 1e-6f;
+ float sdet = sqrtf(det);
+ float hit_co[3], hit_no[3];
+
+ for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) {
+ float x = (- b + ((float)i - 1) * sdet) / (2 * a);
+
+ if (x >= -epsilon && x <= 1.0f + epsilon) {
+ CLAMP(x, 0, 1);
+
+ float vedge_no[2][3];
+ normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no);
+ normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no);
+
+ interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
+ interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
+
+ update_hit(nearest, index, co, hit_co, hit_no);
+ }
}
}
+}
+
+/* Target normal projection BVH callback - based on mesh_looptri_nearest_point. */
+static void mesh_looptri_target_project(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+{
+ const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata;
+ const BVHTreeFromMesh *data = &tree->treeData;
+ const MLoopTri *lt = &data->looptri[index];
+ const MLoop *loop[3] = { &data->loop[lt->tri[0]], &data->loop[lt->tri[1]], &data->loop[lt->tri[2]] };
+ const MVert *vtri[3] = { &data->vert[loop[0]->v], &data->vert[loop[1]->v], &data->vert[loop[2]->v] };
+ const float *vtri_co[3] = { vtri[0]->co, vtri[1]->co, vtri[2]->co };
+ float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3];
+
+ /* First find the closest point and bail out if it's worse than the current solution. */
+ closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co));
+ dist_sq = len_squared_v3v3(co, raw_hit_co);
+
+#ifdef TRACE_TARGET_PROJECT
+ printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n",
+ index, UNPACK3(vtri_co[0]), UNPACK3(vtri_co[1]), UNPACK3(vtri_co[2]), dist_sq, nearest->dist_sq);
+#endif
+
+ if (dist_sq >= nearest->dist_sq)
+ return;
+
+ /* Decode normals */
+ normal_short_to_float_v3(vtri_no[0], vtri[0]->no);
+ normal_short_to_float_v3(vtri_no[1], vtri[1]->no);
+ normal_short_to_float_v3(vtri_no[2], vtri[2]->no);
+
+ /* Solve the equations for the triangle */
+ if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
+ update_hit(nearest, index, co, hit_co, hit_no);
+ }
+ /* Boundary edges */
+ else if (tree->boundary && BLI_BITMAP_TEST(tree->boundary->looptri_has_boundary, index)) {
+ const BLI_bitmap *is_boundary = tree->boundary->edge_is_boundary;
+ int edges[3];
+
+ BKE_mesh_looptri_get_real_edges(tree->mesh, lt, edges);
- if (auxData) {
- if (emaux) {
- free_bvhtree_from_editmesh(auxData);
+ for (int i = 0; i < 3; i++) {
+ if (edges[i] >= 0 && BLI_BITMAP_TEST(is_boundary, edges[i])) {
+ target_project_edge(tree, index, co, nearest, edges[i]);
+ }
}
- else {
- free_bvhtree_from_mesh(auxData);
+ }
+}
+
+/*
+ * Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
+ */
+void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, BVHTreeNearest *nearest, float co[3], int type)
+{
+ BVHTreeFromMesh *treeData = &tree->treeData;
+
+ if (type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+#ifdef TRACE_TARGET_PROJECT
+ printf("====== TARGET PROJECT START ======\n");
+#endif
+
+ BLI_bvhtree_find_nearest_ex(tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER);
+
+#ifdef TRACE_TARGET_PROJECT
+ printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq);
+#endif
+
+ if (nearest->index < 0) {
+ /* fallback to simple nearest */
+ BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
}
}
+ else {
+ BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
+ }
}
/*
@@ -519,7 +1051,6 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(
ShrinkwrapCalcCBData *data = userdata;
ShrinkwrapCalcData *calc = data->calc;
- BVHTreeFromMesh *treeData = data->treeData;
BVHTreeNearest *nearest = tls->userdata_chunk;
float *co = calc->vertexCos[i];
@@ -548,31 +1079,26 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(
* If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
* so we can initiate the "nearest.dist" with the expected value to that last hit.
* This will lead in pruning of the search tree. */
- if (nearest->index != -1)
- nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ if (nearest->index != -1) {
+ if (calc->smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ /* Heuristic doesn't work because of additional restrictions. */
+ nearest->index = -1;
+ nearest->dist_sq = FLT_MAX;
+ }
+ else {
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ }
+ }
else
nearest->dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+ BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType);
/* Found the nearest vertex */
if (nearest->index != -1) {
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
- /* Make the vertex stay on the front side of the face */
- madd_v3_v3v3fl(tmp_co, nearest->co, nearest->no, calc->keepDist);
- }
- else {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- const float dist = sasqrt(nearest->dist_sq);
- if (dist > FLT_EPSILON) {
- /* linear interpolation */
- interp_v3_v3v3(tmp_co, tmp_co, nearest->co, (dist - calc->keepDist) / dist);
- }
- else {
- copy_v3_v3(tmp_co, nearest->co);
- }
- }
+ BKE_shrinkwrap_snap_point_to_surface(
+ data->tree, NULL, calc->smd->shrinkMode,
+ nearest->index, nearest->co, nearest->no, calc->keepDist, tmp_co, tmp_co);
/* Convert the coordinates back to mesh coordinates */
BLI_space_transform_invert(&calc->local2target, tmp_co);
@@ -580,28 +1106,161 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(
}
}
-static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+/**
+ * Compute a smooth normal of the target (if applicable) at the hit location.
+ *
+ * \param tree: information about the mesh
+ * \param transform: transform from the hit coordinate space to the object space; may be null
+ * \param r_no: output in hit coordinate space; may be shared with inputs
+ */
+void BKE_shrinkwrap_compute_smooth_normal(
+ const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
+ int looptri_idx, const float hit_co[3], const float hit_no[3], float r_no[3])
{
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
- BVHTreeNearest nearest = NULL_BVHTreeNearest;
+ const BVHTreeFromMesh *treeData = &tree->treeData;
+ const MLoopTri *tri = &treeData->looptri[looptri_idx];
+
+ /* Interpolate smooth normals if enabled. */
+ if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) {
+ const MVert *verts[] = {
+ &treeData->vert[treeData->loop[tri->tri[0]].v],
+ &treeData->vert[treeData->loop[tri->tri[1]].v],
+ &treeData->vert[treeData->loop[tri->tri[2]].v],
+ };
+ float w[3], no[3][3], tmp_co[3];
- if (calc->target->getNumPolys(calc->target) == 0) {
- return;
+ /* Custom and auto smooth split normals. */
+ if (tree->clnors) {
+ copy_v3_v3(no[0], tree->clnors[tri->tri[0]]);
+ copy_v3_v3(no[1], tree->clnors[tri->tri[1]]);
+ copy_v3_v3(no[2], tree->clnors[tri->tri[2]]);
+ }
+ /* Ordinary vertex normals. */
+ else {
+ normal_short_to_float_v3(no[0], verts[0]->no);
+ normal_short_to_float_v3(no[1], verts[1]->no);
+ normal_short_to_float_v3(no[2], verts[2]->no);
+ }
+
+ /* Barycentric weights from hit point. */
+ copy_v3_v3(tmp_co, hit_co);
+
+ if (transform) {
+ BLI_space_transform_apply(transform, tmp_co);
+ }
+
+ interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co);
+
+ /* Interpolate using weights. */
+ interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
+
+ if (transform) {
+ BLI_space_transform_invert_normal(transform, r_no);
+ }
+ else {
+ normalize_v3(r_no);
+ }
}
+ /* Use the looptri normal if flat. */
+ else {
+ copy_v3_v3(r_no, hit_no);
+ }
+}
- /* Create a bvh-tree of the given target */
- bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_LOOPTRI, 2);
- if (treeData.tree == NULL) {
- OUT_OF_MEMORY();
- return;
+/* Helper for MOD_SHRINKWRAP_INSIDE, MOD_SHRINKWRAP_OUTSIDE and MOD_SHRINKWRAP_OUTSIDE_SURFACE. */
+static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[3], const float hit_co[3], const float hit_no[3], float goal_dist, float forcesign, bool forcesnap)
+{
+ float dist = len_v3v3(point_co, hit_co);
+
+ /* If exactly on the surface, push out along normal */
+ if (dist < FLT_EPSILON) {
+ madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign);
+ }
+ /* Move to the correct side if needed */
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, point_co, hit_co);
+ float dsign = signf(dot_v3v3(delta, hit_no));
+
+ /* If on the wrong side or too close, move to correct */
+ if (forcesnap || dsign * forcesign < 0 || dist < goal_dist) {
+ interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign * forcesign) / dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, point_co);
+ }
}
+}
+
+/**
+ * Apply the shrink to surface modes to the given original coordinates and nearest point.
+ *
+ * \param tree: mesh data for smooth normals
+ * \param transform: transform from the hit coordinate space to the object space; may be null
+ * \param r_point_co: may be the same memory location as point_co, hit_co, or hit_no.
+ */
+void BKE_shrinkwrap_snap_point_to_surface(
+ const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
+ int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist,
+ const float point_co[3], float r_point_co[3])
+{
+ float dist, tmp[3];
+
+ switch (mode) {
+ /* Offsets along the line between point_co and hit_co. */
+ case MOD_SHRINKWRAP_ON_SURFACE:
+ if (goal_dist > 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) {
+ interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ case MOD_SHRINKWRAP_INSIDE:
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false);
+ break;
+
+ case MOD_SHRINKWRAP_OUTSIDE:
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false);
+ break;
+
+ case MOD_SHRINKWRAP_OUTSIDE_SURFACE:
+ if (goal_dist > 0) {
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ /* Offsets along the normal */
+ case MOD_SHRINKWRAP_ABOVE_SURFACE:
+ if (goal_dist > 0) {
+ BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp);
+ madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ default:
+ printf("Unknown Shrinkwrap surface snap mode: %d\n", mode);
+ copy_v3_v3(r_point_co, hit_co);
+ }
+}
+
+static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+{
+ BVHTreeNearest nearest = NULL_BVHTreeNearest;
/* Setup nearest */
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
/* Find the nearest vertex */
- ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ ShrinkwrapCalcCBData data = {.calc = calc, .tree = calc->tree};
ParallelRangeSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
@@ -611,17 +1270,16 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
&data,
shrinkwrap_calc_nearest_surface_point_cb_ex,
&settings);
-
- free_bvhtree_from_mesh(&treeData);
}
/* Main shrinkwrap function */
-void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts, bool for_render)
+void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, struct Scene *scene, Object *ob, Mesh *mesh,
+ MDeformVert *dvert, const int defgrp_index, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *ss_mesh = NULL;
ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+ bool target_free = false;
/* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */
if (smd->target == ob) smd->target = NULL;
@@ -633,20 +1291,12 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
calc.ob = ob;
calc.numVerts = numVerts;
calc.vertexCos = vertexCos;
+ calc.dvert = dvert;
+ calc.vgroup = defgrp_index;
calc.invert_vgroup = (smd->shrinkOpts & MOD_SHRINKWRAP_INVERT_VGROUP) != 0;
- /* DeformVertex */
- calc.vgroup = defgroup_name_index(calc.ob, calc.smd->vgroup_name);
- if (dm) {
- calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
- }
- else if (calc.ob->type == OB_LATTICE) {
- calc.dvert = BKE_lattice_deform_verts_get(calc.ob);
- }
-
-
if (smd->target) {
- calc.target = object_get_derived_final(smd->target, for_render);
+ calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(smd->target, &target_free);
/* TODO there might be several "bugs" on non-uniform scales matrixs
* because it will no longer be nearest surface, not sphere projection
@@ -657,14 +1307,9 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
calc.keepDist = smd->keepDist;
}
-
-
- calc.vgroup = defgroup_name_index(calc.ob, smd->vgroup_name);
-
- if (dm != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
+ if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
/* Setup arrays to get vertexs positions, normals and deform weights */
- calc.vert = dm->getVertDataArray(dm, CD_MVERT);
- calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ calc.vert = mesh->mvert;
/* Using vertexs positions/normals as if a subsurface was applied */
if (smd->subsurfLevels) {
@@ -672,7 +1317,10 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */
ssmd.levels = smd->subsurfLevels; /* levels */
- ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0);
+ /* TODO to be moved to Mesh once we are done with changes in subsurf code. */
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+
+ ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, scene, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0);
if (ss_mesh) {
calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT);
@@ -684,29 +1332,42 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
}
/* Just to make sure we are not leaving any memory behind */
- assert(ssmd.emCache == NULL);
- assert(ssmd.mCache == NULL);
+ BLI_assert(ssmd.emCache == NULL);
+ BLI_assert(ssmd.mCache == NULL);
+
+ dm->release(dm);
}
}
/* Projecting target defined - lets work! */
- if (calc.target) {
+ ShrinkwrapTreeData tree;
+
+ if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) {
+ calc.tree = &tree;
+
switch (smd->shrinkType) {
case MOD_SHRINKWRAP_NEAREST_SURFACE:
+ case MOD_SHRINKWRAP_TARGET_PROJECT:
TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface);
break;
case MOD_SHRINKWRAP_PROJECT:
- TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc, for_render), deform_project);
+ TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
break;
case MOD_SHRINKWRAP_NEAREST_VERTEX:
TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex);
break;
}
+
+ BKE_shrinkwrap_free_tree(&tree);
}
/* free memory */
if (ss_mesh)
ss_mesh->release(ss_mesh);
+
+ if (target_free && calc.target) {
+ BKE_id_free(NULL, calc.target);
+ }
}
diff --git a/source/blender/blenkernel/intern/sketch.c b/source/blender/blenkernel/intern/sketch.c
deleted file mode 100644
index 0bf7a9f278e..00000000000
--- a/source/blender/blenkernel/intern/sketch.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * ***** 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): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/sketch.c
- * \ingroup bke
- */
-
-
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_sketch.h"
-
-
-#include "DNA_userdef_types.h"
-
-void freeSketch(SK_Sketch *sketch)
-{
- SK_Stroke *stk, *next;
-
- for (stk = sketch->strokes.first; stk; stk = next) {
- next = stk->next;
-
- sk_freeStroke(stk);
- }
-
- MEM_freeN(sketch);
-}
-
-SK_Sketch *createSketch(void)
-{
- SK_Sketch *sketch;
-
- sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch");
-
- sketch->active_stroke = NULL;
- sketch->gesture = NULL;
-
- BLI_listbase_clear(&sketch->strokes);
-
- return sketch;
-}
-
-void sk_initPoint(SK_Point *pt, SK_DrawData *dd, const float no[3])
-{
- if (no) {
- normalize_v3_v3(pt->no, no);
- }
- else {
- pt->no[0] = 0.0f;
- pt->no[1] = 0.0f;
- pt->no[2] = 1.0f;
- }
- pt->p2d[0] = dd->mval[0];
- pt->p2d[1] = dd->mval[1];
-
- pt->size = 0.0f;
- pt->type = PT_CONTINUOUS;
- pt->mode = PT_SNAP;
- /* more init code here */
-}
-
-void sk_copyPoint(SK_Point *dst, SK_Point *src)
-{
- memcpy(dst, src, sizeof(SK_Point));
-}
-
-void sk_allocStrokeBuffer(SK_Stroke *stk)
-{
- stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer");
-}
-
-void sk_freeStroke(SK_Stroke *stk)
-{
- MEM_freeN(stk->points);
- MEM_freeN(stk);
-}
-
-SK_Stroke *sk_createStroke(void)
-{
- SK_Stroke *stk;
-
- stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke");
-
- stk->selected = 0;
- stk->nb_points = 0;
- stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE;
-
- sk_allocStrokeBuffer(stk);
-
- return stk;
-}
-
-void sk_shrinkStrokeBuffer(SK_Stroke *stk)
-{
- if (stk->nb_points < stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- stk->buf_size = stk->nb_points;
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-void sk_growStrokeBuffer(SK_Stroke *stk)
-{
- if (stk->nb_points == stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- stk->buf_size *= 2;
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-void sk_growStrokeBufferN(SK_Stroke *stk, int n)
-{
- if (stk->nb_points + n > stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- while (stk->nb_points + n > stk->buf_size) {
- stk->buf_size *= 2;
- }
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-
-void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
-{
- memcpy(stk->points + n, pt, sizeof(SK_Point));
-}
-
-void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
-{
- int size = stk->nb_points - n;
-
- sk_growStrokeBuffer(stk);
-
- memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point));
-
- memcpy(stk->points + n, pt, sizeof(SK_Point));
-
- stk->nb_points++;
-}
-
-void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt)
-{
- sk_growStrokeBuffer(stk);
-
- memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point));
-
- stk->nb_points++;
-}
-
-void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end)
-{
- int size = end - start;
-
- sk_growStrokeBufferN(stk, len - size);
-
- if (len != size) {
- int tail_size = stk->nb_points - end;
-
- memmove(stk->points + start + len, stk->points + end, tail_size * sizeof(SK_Point));
- }
-
- memcpy(stk->points + start, pts, len * sizeof(SK_Point));
-
- stk->nb_points += len - size;
-}
-
-void sk_trimStroke(SK_Stroke *stk, int start, int end)
-{
- int size = end - start + 1;
-
- if (start > 0) {
- memmove(stk->points, stk->points + start, size * sizeof(SK_Point));
- }
-
- stk->nb_points = size;
-}
-
-void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3])
-{
- SK_Point pt1, pt2;
- SK_Point *prev, *next;
- float delta_p[3];
- int i, total;
-
- total = end - start;
-
- sub_v3_v3v3(delta_p, p_end, p_start);
-
- prev = stk->points + start;
- next = stk->points + end;
-
- copy_v3_v3(pt1.p, p_start);
- copy_v3_v3(pt1.no, prev->no);
- pt1.mode = prev->mode;
- pt1.type = prev->type;
-
- copy_v3_v3(pt2.p, p_end);
- copy_v3_v3(pt2.no, next->no);
- pt2.mode = next->mode;
- pt2.type = next->type;
-
- sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */
- sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */
-
- for (i = 1; i < total; i++) {
- float delta = (float)i / (float)total;
- float *p = stk->points[start + 1 + i].p;
-
- mul_v3_v3fl(p, delta_p, delta);
- add_v3_v3(p, p_start);
- }
-}
-
-void sk_polygonizeStroke(SK_Stroke *stk, int start, int end)
-{
- int offset;
- int i;
-
- /* find first exact points outside of range */
- for (; start > 0; start--) {
- if (stk->points[start].type == PT_EXACT) {
- break;
- }
- }
-
- for (; end < stk->nb_points - 1; end++) {
- if (stk->points[end].type == PT_EXACT) {
- break;
- }
- }
-
- offset = start + 1;
-
- for (i = start + 1; i < end; i++) {
- if (stk->points[i].type == PT_EXACT) {
- if (offset != i) {
- memcpy(stk->points + offset, stk->points + i, sizeof(SK_Point));
- }
-
- offset++;
- }
- }
-
- /* some points were removes, move end of array */
- if (offset < end) {
- int size = stk->nb_points - end;
- memmove(stk->points + offset, stk->points + end, size * sizeof(SK_Point));
- stk->nb_points = offset + size;
- }
-}
-
-void sk_flattenStroke(SK_Stroke *stk, int start, int end)
-{
- float normal[3], distance[3];
- float limit;
- int i, total;
-
- total = end - start + 1;
-
- copy_v3_v3(normal, stk->points[start].no);
-
- sub_v3_v3v3(distance, stk->points[end].p, stk->points[start].p);
- project_v3_v3v3(normal, distance, normal);
- limit = normalize_v3(normal);
-
- for (i = 1; i < total - 1; i++) {
- float d = limit * i / total;
- float offset[3];
- float *p = stk->points[start + i].p;
-
- sub_v3_v3v3(distance, p, stk->points[start].p);
- project_v3_v3v3(distance, distance, normal);
-
- copy_v3_v3(offset, normal);
- mul_v3_fl(offset, d);
-
- sub_v3_v3(p, distance);
- add_v3_v3(p, offset);
- }
-}
-
-void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk)
-{
- if (sketch->active_stroke == stk) {
- sketch->active_stroke = NULL;
- }
-
- BLI_remlink(&sketch->strokes, stk);
- sk_freeStroke(stk);
-}
-
-void sk_reverseStroke(SK_Stroke *stk)
-{
- SK_Point *old_points = stk->points;
- int i = 0;
-
- sk_allocStrokeBuffer(stk);
-
- for (i = 0; i < stk->nb_points; i++) {
- sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i);
- }
-
- MEM_freeN(old_points);
-}
-
-
-/* Ramer-Douglas-Peucker algorithm for line simplification */
-void sk_filterStroke(SK_Stroke *stk, int start, int end)
-{
- SK_Point *old_points = stk->points;
- int nb_points = stk->nb_points;
- char *marked = NULL;
- char work;
- int i;
-
- if (start == -1) {
- start = 0;
- end = stk->nb_points - 1;
- }
-
- sk_allocStrokeBuffer(stk);
- stk->nb_points = 0;
-
- /* adding points before range */
- for (i = 0; i < start; i++) {
- sk_appendStrokePoint(stk, old_points + i);
- }
-
- marked = MEM_callocN(nb_points, "marked array");
- marked[start] = 1;
- marked[end] = 1;
-
- work = 1;
-
- /* while still reducing */
- while (work) {
- int ls, le;
- work = 0;
-
- ls = start;
- le = start + 1;
-
- /* while not over interval */
- while (ls < end) {
- int max_i = 0;
- short v1[2];
- float max_dist = 16; /* more than 4 pixels */
-
- /* find the next marked point */
- while (marked[le] == 0) {
- le++;
- }
-
- /* perpendicular vector to ls-le */
- v1[1] = old_points[le].p2d[0] - old_points[ls].p2d[0];
- v1[0] = old_points[ls].p2d[1] - old_points[le].p2d[1];
-
-
- for (i = ls + 1; i < le; i++) {
- float mul;
- float dist;
- short v2[2];
-
- v2[0] = old_points[i].p2d[0] - old_points[ls].p2d[0];
- v2[1] = old_points[i].p2d[1] - old_points[ls].p2d[1];
-
- if (v2[0] == 0 && v2[1] == 0) {
- continue;
- }
-
- mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
-
- dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
-
- if (dist > max_dist) {
- max_dist = dist;
- max_i = i;
- }
- }
-
- if (max_i != 0) {
- work = 1;
- marked[max_i] = 1;
- }
-
- ls = le;
- le = ls + 1;
- }
- }
-
-
- /* adding points after range */
- for (i = start; i <= end; i++) {
- if (marked[i]) {
- sk_appendStrokePoint(stk, old_points + i);
- }
- }
-
- MEM_freeN(marked);
-
- /* adding points after range */
- for (i = end + 1; i < nb_points; i++) {
- sk_appendStrokePoint(stk, old_points + i);
- }
-
- MEM_freeN(old_points);
-
- sk_shrinkStrokeBuffer(stk);
-}
-
-
-void sk_filterLastContinuousStroke(SK_Stroke *stk)
-{
- int start, end;
-
- end = stk->nb_points - 1;
-
- for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--) {
- /* nothing to do here*/
- }
-
- if (end - start > 1) {
- sk_filterStroke(stk, start, end);
- }
-}
-
-SK_Point *sk_lastStrokePoint(SK_Stroke *stk)
-{
- SK_Point *pt = NULL;
-
- if (stk->nb_points > 0) {
- pt = stk->points + (stk->nb_points - 1);
- }
-
- return pt;
-}
-
-void sk_endContinuousStroke(SK_Stroke *stk)
-{
- stk->points[stk->nb_points - 1].type = PT_EXACT;
-}
-
-void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk)
-{
- if (stk) {
- memcpy(&(sketch->next_point), &(stk->points[stk->nb_points - 1]), sizeof(SK_Point));
- }
-}
-
-int sk_stroke_filtermval(SK_DrawData *dd)
-{
- int retval = 0;
- if (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist) {
- retval = 1;
- }
-
- return retval;
-}
-
-void sk_initDrawData(SK_DrawData *dd, const int mval[2])
-{
- dd->mval[0] = mval[0];
- dd->mval[1] = mval[1];
- dd->previous_mval[0] = -1;
- dd->previous_mval[1] = -1;
- dd->type = PT_EXACT;
-}
-
-
-void sk_deleteSelectedStrokes(SK_Sketch *sketch)
-{
- SK_Stroke *stk, *next;
-
- for (stk = sketch->strokes.first; stk; stk = next) {
- next = stk->next;
-
- if (stk->selected == 1) {
- sk_removeStroke(sketch, stk);
- }
- }
-}
-
-void sk_selectAllSketch(SK_Sketch *sketch, int mode)
-{
- SK_Stroke *stk = NULL;
-
- if (mode == -1) {
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = 0;
- }
- }
- else if (mode == 0) {
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = 1;
- }
- }
- else if (mode == 1) {
- int selected = 1;
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- selected &= stk->selected;
- }
-
- selected ^= 1;
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = selected;
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index ccc991ed24a..26d9f59853c 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -54,6 +54,7 @@
#include "DNA_constraint_types.h"
#include "DNA_customdata_types.h"
#include "DNA_lamp_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -65,17 +66,17 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_collision.h"
#include "BKE_colortools.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -84,6 +85,9 @@
#include "BKE_smoke.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RE_shader_ext.h"
#include "GPU_glew.h"
@@ -103,9 +107,9 @@
static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
+struct Mesh;
struct Object;
struct Scene;
-struct DerivedMesh;
struct SmokeModifierData;
// timestep default value for nice appearance 0.1f
@@ -127,7 +131,7 @@ void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(s
void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity),
int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color),
float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; }
+struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *UNUSED(me)) { return NULL; }
float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; }
#endif /* WITH_SMOKE */
@@ -192,20 +196,20 @@ static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3])
pos[2] *= 1.0f / sds->cell_size[2];
}
-/* set domain transformations and base resolution from object derivedmesh */
-static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *ob, DerivedMesh *dm, bool init_resolution)
+/* set domain transformations and base resolution from object mesh */
+static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds, Object *ob, Mesh *me, bool init_resolution)
{
size_t i;
float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
float size[3];
- MVert *verts = dm->getVertArray(dm);
+ MVert *verts = me->mvert;
float scale = 0.0;
int res;
res = sds->maxres;
// get BB of domain
- for (i = 0; i < dm->getNumVerts(dm); i++)
+ for (i = 0; i < me->totvert; i++)
{
// min BB
min[0] = MIN2(min[0], verts[i].co[0]);
@@ -271,14 +275,14 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *
sds->cell_size[2] /= (float)sds->base_res[2];
}
-static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
+static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me)
{
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
{
SmokeDomainSettings *sds = smd->domain;
int res[3];
- /* set domain dimensions from derivedmesh */
- smoke_set_domain_from_derivedmesh(sds, ob, dm, true);
+ /* set domain dimensions from mesh */
+ smoke_set_domain_from_mesh(sds, ob, me, true);
/* reset domain values */
zero_v3_int(sds->shift);
zero_v3(sds->shift_f);
@@ -302,7 +306,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene,
/* allocate fluid */
smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
/* allocate highres fluid */
if (sds->flags & MOD_SMOKE_HIGHRES) {
@@ -316,7 +320,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene,
}
else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
{
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
return 1;
}
@@ -327,7 +331,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene,
smokeModifier_createType(smd);
}
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
return 1;
}
@@ -358,8 +362,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
MEM_freeN(smd->domain->effector_weights);
smd->domain->effector_weights = NULL;
- BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0] = NULL;
+ if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) {
+ BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
+ smd->domain->point_cache[0] = NULL;
+ }
if (smd->domain->coba) {
MEM_freeN(smd->domain->coba);
@@ -374,7 +380,7 @@ static void smokeModifier_freeFlow(SmokeModifierData *smd)
{
if (smd->flow)
{
- if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm);
+ if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh);
if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
MEM_freeN(smd->flow);
smd->flow = NULL;
@@ -396,9 +402,9 @@ static void smokeModifier_freeCollision(SmokeModifierData *smd)
}
}
- if (smd->coll->dm)
- smd->coll->dm->release(smd->coll->dm);
- smd->coll->dm = NULL;
+ if (smd->coll->mesh)
+ BKE_id_free(NULL, smd->coll->mesh);
+ smd->coll->mesh = NULL;
MEM_freeN(smd->coll);
smd->coll = NULL;
@@ -581,7 +587,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->flow->color[1] = 0.7f;
smd->flow->color[2] = 0.7f;
- smd->flow->dm = NULL;
+ smd->flow->mesh = NULL;
smd->flow->psys = NULL;
}
@@ -596,16 +602,12 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->coll->verts_old = NULL;
smd->coll->numverts = 0;
smd->coll->type = 0; // static obstacle
- smd->coll->dm = NULL;
-
-#ifdef USE_SMOKE_COLLISION_DM
- smd->coll->dm = NULL;
-#endif
+ smd->coll->mesh = NULL;
}
}
}
-void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd)
+void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag)
{
tsmd->type = smd->type;
tsmd->time = smd->time;
@@ -613,80 +615,102 @@ void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifie
smokeModifier_createType(tsmd);
if (tsmd->domain) {
- tsmd->domain->fluid_group = smd->domain->fluid_group;
- tsmd->domain->coll_group = smd->domain->coll_group;
-
- tsmd->domain->adapt_margin = smd->domain->adapt_margin;
- tsmd->domain->adapt_res = smd->domain->adapt_res;
- tsmd->domain->adapt_threshold = smd->domain->adapt_threshold;
-
- tsmd->domain->alpha = smd->domain->alpha;
- tsmd->domain->beta = smd->domain->beta;
- tsmd->domain->amplify = smd->domain->amplify;
- tsmd->domain->maxres = smd->domain->maxres;
- tsmd->domain->flags = smd->domain->flags;
- tsmd->domain->highres_sampling = smd->domain->highres_sampling;
- tsmd->domain->viewsettings = smd->domain->viewsettings;
- tsmd->domain->noise = smd->domain->noise;
- tsmd->domain->diss_speed = smd->domain->diss_speed;
- tsmd->domain->strength = smd->domain->strength;
-
- tsmd->domain->border_collisions = smd->domain->border_collisions;
- tsmd->domain->vorticity = smd->domain->vorticity;
- tsmd->domain->time_scale = smd->domain->time_scale;
-
- tsmd->domain->burning_rate = smd->domain->burning_rate;
- tsmd->domain->flame_smoke = smd->domain->flame_smoke;
- tsmd->domain->flame_vorticity = smd->domain->flame_vorticity;
- tsmd->domain->flame_ignition = smd->domain->flame_ignition;
- tsmd->domain->flame_max_temp = smd->domain->flame_max_temp;
- copy_v3_v3(tsmd->domain->flame_smoke_color, smd->domain->flame_smoke_color);
-
- MEM_freeN(tsmd->domain->effector_weights);
- tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights);
- tsmd->domain->openvdb_comp = smd->domain->openvdb_comp;
- tsmd->domain->data_depth = smd->domain->data_depth;
- tsmd->domain->cache_file_format = smd->domain->cache_file_format;
-
- tsmd->domain->slice_method = smd->domain->slice_method;
- tsmd->domain->axis_slice_method = smd->domain->axis_slice_method;
- tsmd->domain->slice_per_voxel = smd->domain->slice_per_voxel;
- tsmd->domain->slice_depth = smd->domain->slice_depth;
- tsmd->domain->slice_axis = smd->domain->slice_axis;
- tsmd->domain->draw_velocity = smd->domain->draw_velocity;
- tsmd->domain->vector_draw_type = smd->domain->vector_draw_type;
- tsmd->domain->vector_scale = smd->domain->vector_scale;
+ SmokeDomainSettings *tsds = tsmd->domain;
+ SmokeDomainSettings *sds = smd->domain;
- if (smd->domain->coba) {
- tsmd->domain->coba = MEM_dupallocN(smd->domain->coba);
+ BKE_ptcache_free_list(&(tsds->ptcaches[0]));
+
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* Share the cache with the original object's modifier. */
+ tsmd->modifier.flag |= eModifierFlag_SharedCaches;
+ tsds->point_cache[0] = sds->point_cache[0];
+ tsds->ptcaches[0] = sds->ptcaches[0];
+ }
+ else {
+ tsds->point_cache[0] = BKE_ptcache_copy_list(&(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag);
+ }
+
+ tsds->fluid_group = sds->fluid_group;
+ tsds->coll_group = sds->coll_group;
+
+ tsds->adapt_margin = sds->adapt_margin;
+ tsds->adapt_res = sds->adapt_res;
+ tsds->adapt_threshold = sds->adapt_threshold;
+
+ tsds->alpha = sds->alpha;
+ tsds->beta = sds->beta;
+ tsds->amplify = sds->amplify;
+ tsds->maxres = sds->maxres;
+ tsds->flags = sds->flags;
+ tsds->highres_sampling = sds->highres_sampling;
+ tsds->viewsettings = sds->viewsettings;
+ tsds->noise = sds->noise;
+ tsds->diss_speed = sds->diss_speed;
+ tsds->strength = sds->strength;
+
+ tsds->border_collisions = sds->border_collisions;
+ tsds->vorticity = sds->vorticity;
+ tsds->time_scale = sds->time_scale;
+
+ tsds->burning_rate = sds->burning_rate;
+ tsds->flame_smoke = sds->flame_smoke;
+ tsds->flame_vorticity = sds->flame_vorticity;
+ tsds->flame_ignition = sds->flame_ignition;
+ tsds->flame_max_temp = sds->flame_max_temp;
+ copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color);
+
+ MEM_freeN(tsds->effector_weights);
+ tsds->effector_weights = MEM_dupallocN(sds->effector_weights);
+ tsds->openvdb_comp = sds->openvdb_comp;
+ tsds->data_depth = sds->data_depth;
+ tsds->cache_file_format = sds->cache_file_format;
+
+ tsds->display_thickness = sds->display_thickness;
+ tsds->slice_method = sds->slice_method;
+ tsds->axis_slice_method = sds->axis_slice_method;
+ tsds->slice_per_voxel = sds->slice_per_voxel;
+ tsds->slice_depth = sds->slice_depth;
+ tsds->slice_axis = sds->slice_axis;
+ tsds->interp_method = sds->interp_method;
+ tsds->draw_velocity = sds->draw_velocity;
+ tsds->vector_draw_type = sds->vector_draw_type;
+ tsds->vector_scale = sds->vector_scale;
+
+ tsds->use_coba = sds->use_coba;
+ tsds->coba_field = sds->coba_field;
+ if (sds->coba) {
+ tsds->coba = MEM_dupallocN(sds->coba);
}
}
else if (tsmd->flow) {
- tsmd->flow->psys = smd->flow->psys;
- tsmd->flow->noise_texture = smd->flow->noise_texture;
-
- tsmd->flow->vel_multi = smd->flow->vel_multi;
- tsmd->flow->vel_normal = smd->flow->vel_normal;
- tsmd->flow->vel_random = smd->flow->vel_random;
-
- tsmd->flow->density = smd->flow->density;
- copy_v3_v3(tsmd->flow->color, smd->flow->color);
- tsmd->flow->fuel_amount = smd->flow->fuel_amount;
- tsmd->flow->temp = smd->flow->temp;
- tsmd->flow->volume_density = smd->flow->volume_density;
- tsmd->flow->surface_distance = smd->flow->surface_distance;
- tsmd->flow->particle_size = smd->flow->particle_size;
- tsmd->flow->subframes = smd->flow->subframes;
-
- tsmd->flow->texture_size = smd->flow->texture_size;
- tsmd->flow->texture_offset = smd->flow->texture_offset;
- BLI_strncpy(tsmd->flow->uvlayer_name, smd->flow->uvlayer_name, sizeof(tsmd->flow->uvlayer_name));
- tsmd->flow->vgroup_density = smd->flow->vgroup_density;
-
- tsmd->flow->type = smd->flow->type;
- tsmd->flow->source = smd->flow->source;
- tsmd->flow->texture_type = smd->flow->texture_type;
- tsmd->flow->flags = smd->flow->flags;
+ SmokeFlowSettings *tsfs = tsmd->flow;
+ SmokeFlowSettings *sfs = smd->flow;
+
+ tsfs->psys = sfs->psys;
+ tsfs->noise_texture = sfs->noise_texture;
+
+ tsfs->vel_multi = sfs->vel_multi;
+ tsfs->vel_normal = sfs->vel_normal;
+ tsfs->vel_random = sfs->vel_random;
+
+ tsfs->density = sfs->density;
+ copy_v3_v3(tsfs->color, sfs->color);
+ tsfs->fuel_amount = sfs->fuel_amount;
+ tsfs->temp = sfs->temp;
+ tsfs->volume_density = sfs->volume_density;
+ tsfs->surface_distance = sfs->surface_distance;
+ tsfs->particle_size = sfs->particle_size;
+ tsfs->subframes = sfs->subframes;
+
+ tsfs->texture_size = sfs->texture_size;
+ tsfs->texture_offset = sfs->texture_offset;
+ BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
+ tsfs->vgroup_density = sfs->vgroup_density;
+
+ tsfs->type = sfs->type;
+ tsfs->source = sfs->source;
+ tsfs->texture_type = sfs->texture_type;
+ tsfs->flags = sfs->flags;
}
else if (tsmd->coll) {
/* leave it as initialized, collision settings is mostly caches */
@@ -695,17 +719,17 @@ void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifie
#ifdef WITH_SMOKE
-// forward decleration
-static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene);
+// forward declaration
+static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer);
static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-static int get_lamp(Scene *scene, float *light)
+static int get_lamp(ViewLayer *view_layer, float *light)
{
Base *base_tmp = NULL;
int found_lamp = 0;
// try to find a lamp, preferably local
- for (base_tmp = scene->base.first; base_tmp; base_tmp = base_tmp->next) {
+ for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
if (base_tmp->object->type == OB_LAMP) {
Lamp *la = base_tmp->object->data;
@@ -741,7 +765,7 @@ typedef struct ObstaclesFromDMData {
int *num_obstacles;
} ObstaclesFromDMData;
-static void obstacles_from_derivedmesh_task_cb(
+static void obstacles_from_mesh_task_cb(
void *__restrict userdata,
const int z,
const ParallelRangeTLS *__restrict UNUSED(tls))
@@ -798,13 +822,13 @@ static void obstacles_from_derivedmesh_task_cb(
}
}
-static void obstacles_from_derivedmesh(
+static void obstacles_from_mesh(
Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs,
unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt)
{
- if (!scs->dm) return;
+ if (!scs->mesh) return;
{
- DerivedMesh *dm = NULL;
+ Mesh *me = NULL;
MVert *mvert = NULL;
const MLoopTri *looptri;
const MLoop *mloop;
@@ -814,12 +838,12 @@ static void obstacles_from_derivedmesh(
float *vert_vel = NULL;
bool has_velocity = false;
- dm = CDDM_copy(scs->dm);
- CDDM_calc_normals(dm);
- mvert = dm->getVertArray(dm);
- mloop = dm->getLoopArray(dm);
- looptri = dm->getLoopTriArray(dm);
- numverts = dm->getNumVerts(dm);
+ me = BKE_mesh_copy_for_eval(scs->mesh, true);
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ mloop = me->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(me);
+ numverts = me->totvert;
// DG TODO
// if (scs->type > SM_COLL_STATIC)
@@ -866,7 +890,7 @@ static void obstacles_from_derivedmesh(
copy_v3_v3(&scs->verts_old[i * 3], co);
}
- if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) {
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
ObstaclesFromDMData data = {
.sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri,
.tree = &treeData, .obstacle_map = obstacle_map,
@@ -879,19 +903,19 @@ static void obstacles_from_derivedmesh(
settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(sds->res_min[2], sds->res_max[2],
&data,
- obstacles_from_derivedmesh_task_cb,
+ obstacles_from_mesh_task_cb,
&settings);
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
- dm->release(dm);
+ BKE_id_free(NULL, me);
if (vert_vel) MEM_freeN(vert_vel);
}
}
/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
-static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt,
+static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettings *sds, float dt,
int UNUSED(substep), int UNUSED(totalsteps))
{
Object **collobjs = NULL;
@@ -931,7 +955,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
}
- collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
+ collobjs = BKE_collision_objects_create(depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
// update obstacle tags in cells
for (collIndex = 0; collIndex < numcollobj; collIndex++)
@@ -944,12 +968,11 @@ 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, num_obstacles, dt);
+ obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
}
}
- if (collobjs)
- MEM_freeN(collobjs);
+ BKE_collision_objects_free(collobjs);
/* obstacle cells should not contain any velocity from the smoke simulation */
for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
@@ -1264,7 +1287,7 @@ static void emit_from_particles_task_cb(
}
static void emit_from_particles(
- Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Scene *scene, float dt)
+ Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Depsgraph *depsgraph, Scene *scene, float dt)
{
if (sfs && sfs->psys && sfs->psys->part && ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
{
@@ -1283,6 +1306,7 @@ static void emit_from_particles(
int hires_multiplier = 1;
KDTree *tree = NULL;
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = flow_ob;
sim.psys = psys;
@@ -1335,7 +1359,7 @@ static void emit_from_particles(
continue;
}
- state.time = BKE_scene_frame_get(scene); /* use scene time */
+ state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */
if (psys_get_particle_state(&sim, p, &state, 0) == 0)
continue;
@@ -1436,7 +1460,7 @@ static void emit_from_particles(
}
}
-static void sample_derivedmesh(
+static void sample_mesh(
SmokeFlowSettings *sfs,
const MVert *mvert, const MLoop *mloop, const MLoopTri *mlooptri, const MLoopUV *mloopuv,
float *influence_map, float *velocity_map, int index, const int base_res[3], float flow_center[3],
@@ -1593,7 +1617,7 @@ typedef struct EmitFromDMData {
int *min, *max, *res;
} EmitFromDMData;
-static void emit_from_derivedmesh_task_cb(
+static void emit_from_mesh_task_cb(
void *__restrict userdata,
const int z,
const ParallelRangeTLS *__restrict UNUSED(tls))
@@ -1615,7 +1639,7 @@ static void emit_from_derivedmesh_task_cb(
lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
- sample_derivedmesh(
+ sample_mesh(
data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
em->influence, em->velocity, index, data->sds->base_res, data->flow_center,
data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
@@ -1633,7 +1657,7 @@ static void emit_from_derivedmesh_task_cb(
x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
- sample_derivedmesh(
+ sample_mesh(
data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
em->influence_high, NULL, index, data->sds->base_res, data->flow_center,
data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
@@ -1644,14 +1668,13 @@ static void emit_from_derivedmesh_task_cb(
}
}
-static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
+static void emit_from_mesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
{
- if (sfs->dm) {
- DerivedMesh *dm;
+ if (sfs->mesh) {
+ Mesh *me;
int defgrp_index = sfs->vgroup_density - 1;
MDeformVert *dvert = NULL;
MVert *mvert = NULL;
- MVert *mvert_orig = NULL;
const MLoopTri *mlooptri = NULL;
const MLoopUV *mloopuv = NULL;
const MLoop *mloop = NULL;
@@ -1664,19 +1687,24 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
int min[3], max[3], res[3];
int hires_multiplier = 1;
- /* copy derivedmesh for thread safety because we modify it,
+ /* copy mesh for thread safety because we modify it,
* main issue is its VertArray being modified, then replaced and freed
*/
- dm = CDDM_copy(sfs->dm);
+ me = BKE_mesh_copy_for_eval(sfs->mesh, true);
+
+ /* Duplicate vertices to modify. */
+ if (me->mvert) {
+ me->mvert = MEM_dupallocN(me->mvert);
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ }
- CDDM_calc_normals(dm);
- mvert = dm->getVertArray(dm);
- mvert_orig = dm->dupVertArray(dm); /* copy original mvert and restore when done */
- numOfVerts = dm->getNumVerts(dm);
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
- mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, sfs->uvlayer_name);
- mloop = dm->getLoopArray(dm);
- mlooptri = dm->getLoopTriArray(dm);
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ numOfVerts = me->totvert;
+ dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
+ mloop = me->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(me);
if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
@@ -1691,8 +1719,8 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
}
}
- /* Transform dm vertices to
- * domain grid space for fast lookups */
+ /* Transform mesh vertices to
+ * domain grid space for fast lookups */
for (i = 0; i < numOfVerts; i++) {
float n[3];
/* vert pos */
@@ -1737,7 +1765,7 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
res[i] = em->res[i] * hires_multiplier;
}
- if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) {
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
const float hr = 1.0f / ((float)hires_multiplier);
EmitFromDMData data = {
@@ -1754,23 +1782,20 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(min[2], max[2],
&data,
- emit_from_derivedmesh_task_cb,
+ emit_from_mesh_task_cb,
&settings);
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
- /* restore original mverts */
- CustomData_set_layer(&dm->vertData, CD_MVERT, mvert_orig);
- if (mvert) {
- MEM_freeN(mvert);
- }
if (vert_vel) {
MEM_freeN(vert_vel);
}
- dm->needsFree = 1;
- dm->release(dm);
+ if (me->mvert) {
+ MEM_freeN(me->mvert);
+ }
+ BKE_id_free(NULL, me);
}
}
@@ -2107,7 +2132,7 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value
}
static void update_flowsfluids(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
{
Object **flowobjs = NULL;
EmissionMap *emaps = NULL;
@@ -2149,7 +2174,7 @@ static void update_flowsfluids(
sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2];
}
- flowobjs = get_collisionobjects(scene, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
+ flowobjs = BKE_collision_objects_create(depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
/* init emission maps for each flow */
emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
@@ -2171,21 +2196,25 @@ static void update_flowsfluids(
/* just sample flow directly to emission map if no subframes */
if (!subframes) {
if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- emit_from_particles(collob, sds, sfs, em, scene, dt);
+ emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt);
}
else {
- emit_from_derivedmesh(collob, sds, sfs, em, dt);
+ emit_from_mesh(collob, sds, sfs, em, dt);
}
}
/* sample subframes */
else {
- int scene_frame = scene->r.cfra;
+#if 0
+ int scene_frame = (int)DEG_get_ctime(depsgraph);
+#endif
// float scene_subframe = scene->r.subframe; // UNUSED
int subframe;
for (subframe = 0; subframe <= subframes; subframe++) {
EmissionMap em_temp = {NULL};
float sample_size = 1.0f / (float)(subframes+1);
+#if 0
float prev_frame_pos = sample_size * (float)(subframe+1);
+#endif
float sdt = dt * sample_size;
int hires_multiplier = 1;
@@ -2193,6 +2222,8 @@ static void update_flowsfluids(
hires_multiplier = sds->amplify + 1;
}
+ /* TODO: setting the scene frame no longer works with the new depsgraph. */
+#if 0
/* set scene frame to match previous frame + subframe
* or use current frame for last sample */
if (subframe < subframes) {
@@ -2203,10 +2234,11 @@ static void update_flowsfluids(
scene->r.cfra = scene_frame;
scene->r.subframe = 0.0f;
}
+#endif
if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
/* emit_from_particles() updates timestep internally */
- emit_from_particles(collob, sds, sfs, &em_temp, scene, sdt);
+ emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt);
if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
hires_multiplier = 1;
}
@@ -2214,13 +2246,11 @@ static void update_flowsfluids(
else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
/* update flow object frame */
BLI_mutex_lock(&object_update_lock);
- BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, collob,
- true, 5, BKE_scene_frame_get(scene), eModifierType_Smoke);
+ BKE_object_modifier_update_subframe(depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke);
BLI_mutex_unlock(&object_update_lock);
/* apply flow */
- emit_from_derivedmesh(collob, sds, sfs, &em_temp, sdt);
+ emit_from_mesh(collob, sds, sfs, &em_temp, sdt);
}
/* combine emission maps */
@@ -2452,8 +2482,7 @@ static void update_flowsfluids(
}
}
- if (flowobjs)
- MEM_freeN(flowobjs);
+ BKE_collision_objects_free(flowobjs);
if (emaps)
MEM_freeN(emaps);
}
@@ -2512,7 +2541,7 @@ static void update_effectors_task_cb(
mul_m4_v3(sds->obmat, voxelCenter);
pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
- pdDoEffectors(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
+ BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
/* convert retvel to local space */
mag = len_v3(retvel);
@@ -2528,12 +2557,12 @@ static void update_effectors_task_cb(
}
}
-static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
+static void update_effectors(Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
{
ListBase *effectors;
/* make sure smoke flow influence is 0.0f */
sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights);
if (effectors) {
// precalculate wind forces
@@ -2560,12 +2589,12 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
&settings);
}
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
static void step(
- Main *bmain, EvaluationContext *eval_ctx,
- Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps)
+ Depsgraph *depsgraph,
+ Scene *scene, Object *ob, SmokeModifierData *smd, Mesh *domain_me, float fps)
{
SmokeDomainSettings *sds = smd->domain;
/* stability values copied from wturbulence.cpp */
@@ -2581,19 +2610,10 @@ static void step(
float gravity[3] = {0.0f, 0.0f, -1.0f};
float gravity_mag;
-#if 0 /* UNUSED */
- /* get max velocity and lower the dt value if it is too high */
- size_t size = sds->res[0] * sds->res[1] * sds->res[2];
- float *velX = smoke_get_velocity_x(sds->fluid);
- float *velY = smoke_get_velocity_y(sds->fluid);
- float *velZ = smoke_get_velocity_z(sds->fluid);
- size_t i;
-#endif
-
/* update object state */
invert_m4_m4(sds->imat, ob->obmat);
copy_m4_m4(sds->obmat, ob->obmat);
- smoke_set_domain_from_derivedmesh(sds, ob, domain_dm, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
+ smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
/* use global gravity if enabled */
if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
@@ -2612,14 +2632,6 @@ static void step(
// maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
maxVel = (sds->dx * 5.0f);
-#if 0
- for (i = 0; i < size; i++) {
- float vtemp = (velX[i] * velX[i] + velY[i] * velY[i] + velZ[i] * velZ[i]);
- if (vtemp > maxVelMag)
- maxVelMag = vtemp;
- }
-#endif
-
maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale;
totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
@@ -2635,19 +2647,19 @@ static void step(
for (substep = 0; substep < totalSubsteps; substep++)
{
// calc animated obstacle velocities
- update_flowsfluids(bmain, eval_ctx, scene, ob, sds, dtSubdiv);
- update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps);
+ update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
+ update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps);
if (sds->total_cells > 1) {
- update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
+ update_effectors(depsgraph, scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
smoke_step(sds->fluid, gravity, dtSubdiv);
}
}
}
-static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
+static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
{
- DerivedMesh *result;
+ Mesh *result;
MVert *mverts;
MPoly *mpolys;
MLoop *mloops;
@@ -2669,11 +2681,10 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
num_faces = 0;
}
- result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces);
- mverts = CDDM_get_verts(result);
- mpolys = CDDM_get_polys(result);
- mloops = CDDM_get_loops(result);
-
+ result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
+ mverts = result->mvert;
+ mpolys = result->mpoly;
+ mloops = result->mloop;
if (num_verts) {
/* volume bounds */
@@ -2726,48 +2737,49 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
}
}
-
- CDDM_calc_edges(result);
- result->dirty |= DM_DIRTY_NORMALS;
+ BKE_mesh_calc_edges(result, false, false);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
static void smokeModifier_process(
- Main *bmain, EvaluationContext *eval_ctx, SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+ SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
+ const int scene_framenr = (int)DEG_get_ctime(depsgraph);
+
if ((smd->type & MOD_SMOKE_TYPE_FLOW))
{
- if (scene->r.cfra >= smd->time)
- smokeModifier_init(smd, ob, scene, dm);
+ if (scene_framenr >= smd->time)
+ smokeModifier_init(smd, ob, scene_framenr, me);
- if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm);
- smd->flow->dm = CDDM_copy(dm);
+ if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh);
+ smd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
- if (scene->r.cfra > smd->time)
+ if (scene_framenr > smd->time)
{
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
}
- else if (scene->r.cfra < smd->time)
+ else if (scene_framenr < smd->time)
{
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
smokeModifier_reset_ex(smd, false);
}
}
else if (smd->type & MOD_SMOKE_TYPE_COLL)
{
- if (scene->r.cfra >= smd->time)
- smokeModifier_init(smd, ob, scene, dm);
+ if (scene_framenr >= smd->time)
+ smokeModifier_init(smd, ob, scene_framenr, me);
if (smd->coll)
{
- if (smd->coll->dm)
- smd->coll->dm->release(smd->coll->dm);
+ if (smd->coll->mesh)
+ BKE_id_free(NULL, smd->coll->mesh);
- smd->coll->dm = CDDM_copy(dm);
+ smd->coll->mesh = BKE_mesh_copy_for_eval(me, false);
}
- smd->time = scene->r.cfra;
- if (scene->r.cfra < smd->time)
+ smd->time = scene_framenr;
+ if (scene_framenr < smd->time)
{
smokeModifier_reset_ex(smd, false);
}
@@ -2780,9 +2792,7 @@ static void smokeModifier_process(
int startframe, endframe, framenr;
float timescale;
- framenr = scene->r.cfra;
-
- //printf("time: %d\n", scene->r.cfra);
+ framenr = scene_framenr;
cache = sds->point_cache[0];
BKE_ptcache_id_from_smoke(&pid, ob, smd);
@@ -2803,10 +2813,10 @@ static void smokeModifier_process(
CLAMP(framenr, startframe, endframe);
/* If already viewing a pre/after frame, no need to reload */
- if ((smd->time == framenr) && (framenr != scene->r.cfra))
+ if ((smd->time == framenr) && (framenr != scene_framenr))
return;
- if (smokeModifier_init(smd, ob, scene, dm) == 0)
+ if (smokeModifier_init(smd, ob, scene_framenr, me) == 0)
{
printf("bad smokeModifier_init\n");
return;
@@ -2814,7 +2824,7 @@ static void smokeModifier_process(
/* only calculate something when we advanced a single frame */
/* don't simulate if viewing start frame, but scene frame is not real start frame */
- bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene->r.cfra);
+ bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr);
/* try to read from cache */
if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
@@ -2836,7 +2846,7 @@ static void smokeModifier_process(
}
// set new time
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
/* do simulation */
@@ -2854,11 +2864,11 @@ static void smokeModifier_process(
}
- step(bmain, eval_ctx, scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base);
+ step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base);
}
// create shadows before writing cache so they get stored
- smoke_calc_transparency(sds, scene);
+ smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
if (sds->wt && sds->total_cells > 1) {
smoke_turbulence_step(sds->wt, sds->fluid);
@@ -2875,14 +2885,14 @@ static void smokeModifier_process(
}
}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+struct Mesh *smokeModifier_do(
+ SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
/* lock so preview render does not read smoke data while it gets modified */
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- /* Ugly G.main, hopefully won't be needed anymore in 2.8 */
- smokeModifier_process(G.main, G.main->eval_ctx , smd, scene, ob, dm);
+ smokeModifier_process(smd, depsgraph, scene, ob, me);
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
@@ -2895,7 +2905,7 @@ struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Objec
return createDomainGeometry(smd->domain, ob);
}
else {
- return CDDM_copy(dm);
+ return BKE_mesh_copy_for_eval(me, false);
}
}
@@ -2997,7 +3007,7 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f
cb(result, input, res, pixel, tRay, correct);
}
-static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
+static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer)
{
float bv[6] = {0};
float light[3];
@@ -3005,7 +3015,7 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
float *density = smoke_get_density(sds->fluid);
float correct = -7.0f * sds->dx;
- if (!get_lamp(scene, light)) return;
+ if (!get_lamp(view_layer, light)) return;
/* convert light pos to sim cell space */
mul_m4_v3(sds->imat, light);
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 940f7f72d62..4c1555e9451 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -55,13 +55,13 @@
#include "MEM_guardedalloc.h"
/* types */
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_lattice_types.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_mesh_types.h"
+#include "DNA_lattice_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_group_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -69,9 +69,12 @@
#include "BLI_ghash.h"
#include "BLI_threads.h"
+#include "BKE_collection.h"
+#include "BKE_collision.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_softbody.h"
#include "BKE_pointcache.h"
@@ -79,6 +82,9 @@
#include "BKE_mesh.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "PIL_time.h"
/* callbacks for errors and interrupts and some goo */
@@ -132,7 +138,7 @@ typedef struct SB_thread_context {
float timenow;
int ifirst;
int ilast;
- ListBase *do_effector;
+ ListBase *effectors;
int do_deflector;
float fieldfactor;
float windfactor;
@@ -508,39 +514,24 @@ static void ccd_build_deflector_hash_single(GHash *hash, Object *ob)
}
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
+static void ccd_build_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash)
{
- Object *ob;
-
if (!hash) return;
- if (group) {
- /* Explicit collision group */
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- ob = go->ob;
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
- if (ob == vertexowner || ob->type != OB_MESH)
- continue;
+ for (int i = 0; i < numobjects; i++) {
+ Object *ob = objects[i];
+ if (ob->type == OB_MESH) {
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);
- }
- }
- }
+ BKE_collision_objects_free(objects);
}
static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
@@ -554,42 +545,26 @@ static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
}
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
+static void ccd_update_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash)
{
- Object *ob;
-
if ((!hash) || (!vertexowner)) return;
- if (group) {
- /* Explicit collision group */
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- ob = go->ob;
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
- if (ob == vertexowner || ob->type != OB_MESH)
- continue;
+ for (int i = 0; i < numobjects; i++) {
+ Object *ob = objects[i];
+ if (ob->type == OB_MESH) {
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;
- }
- ccd_update_deflector_hash_single(hash, ob);
- }
- }
- }
+ BKE_collision_objects_free(objects);
}
-
/*--- collider caching and dicing ---*/
@@ -975,37 +950,21 @@ static void free_softbody_intern(SoftBody *sb)
/* +++ dependency information functions*/
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer)
+static int query_external_colliders(Depsgraph *depsgraph, Collection *collection)
{
- 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;
- }
- }
- }
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, NULL, collection, &numobjects, eModifierType_Collision);
+ BKE_collision_objects_free(objects);
- return 0;
-}
-
-static int query_external_colliders(Scene *scene, Group *group, Object *me)
-{
- return(are_there_deflectors(scene, group, me->lay));
+ return (numobjects != 0);
}
/* --- dependency information functions*/
/* +++ the aabb "force" section*/
-static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int UNUSED(par_layer), struct Object *vertexowner, float UNUSED(time))
+static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), struct Object *vertexowner, float UNUSED(time))
{
Object *ob;
SoftBody *sb=vertexowner->soft;
@@ -1066,7 +1025,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U
/* +++ the face external section*/
static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float face_v3[3], float *damp,
- float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time)
+ float force[3], struct Object *vertexowner, float time)
{
Object *ob;
GHash *hash;
@@ -1167,7 +1126,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float
static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], float face_v3[3], float *damp,
- float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time)
+ float force[3], struct Object *vertexowner, float time)
{
Object *ob;
GHash *hash;
@@ -1304,7 +1263,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow)
zero_v3(feedback);
if (sb_detect_face_collisionCached(
sb->bpoint[bf->v1].pos, sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos,
- &damp, feedback, ob->lay, ob, timenow))
+ &damp, feedback, ob, timenow))
{
madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune);
madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune);
@@ -1322,7 +1281,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow)
zero_v3(feedback);
if (sb_detect_face_pointCached(
sb->bpoint[bf->v1].pos, sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos,
- &damp, feedback, ob->lay, ob, timenow))
+ &damp, feedback, ob, timenow))
{
madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune);
madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune);
@@ -1351,7 +1310,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow)
/* +++ the spring external section*/
static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], float *damp,
- float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time)
+ float force[3], struct Object *vertexowner, float time)
{
Object *ob;
GHash *hash;
@@ -1470,7 +1429,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
return deflected;
}
-static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *do_effector)
+static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *effectors)
{
SoftBody *sb = ob->soft;
int a;
@@ -1488,7 +1447,7 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
/* +++ springs colliding */
if (ob->softflag & OB_SB_EDGECOLL) {
if ( sb_detect_edge_collisionCached (sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos,
- &damp, feedback, ob->lay, ob, timenow)) {
+ &damp, feedback, ob, timenow)) {
add_v3_v3(bs->ext_force, feedback);
bs->flag |= BSF_INTERSECT;
//bs->cf=damp;
@@ -1504,14 +1463,14 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
float vel[3], sp[3], pr[3], force[3];
float f, windfactor = 0.25f;
/*see if we have wind*/
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float speed[3] = {0.0f, 0.0f, 0.0f};
float pos[3];
mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
pd_point_from_soft(scene, pos, vel, -1, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
mul_v3_fl(speed, windfactor);
add_v3_v3(vel, speed);
@@ -1544,32 +1503,30 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
}
-static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow)
+static void scan_for_ext_spring_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float timenow)
{
SoftBody *sb = ob->soft;
- ListBase *do_effector = NULL;
- do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
- _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector);
- pdEndEffectors(&do_effector);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights);
+ _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, effectors);
+ BKE_effectors_free(effectors);
}
static void *exec_scan_for_ext_spring_forces(void *data)
{
SB_thread_context *pctx = (SB_thread_context*)data;
- _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->do_effector);
+ _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->effectors);
return NULL;
}
-static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void)))
+static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void)))
{
- ListBase *do_effector = NULL;
ListBase threads;
SB_thread_context *sb_threads;
int i, totthread, left, dec;
int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
- do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights);
/* figure the number of threads while preventing pretty pointless threading overhead */
totthread= BKE_scene_num_threads(scene);
@@ -1594,7 +1551,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
}
else
sb_threads[i].ifirst = 0;
- sb_threads[i].do_effector = do_effector;
+ sb_threads[i].effectors = effectors;
sb_threads[i].do_deflector = false;// not used here
sb_threads[i].fieldfactor = 0.0f;// not used here
sb_threads[i].windfactor = 0.0f;// not used here
@@ -1614,7 +1571,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
/* clean up */
MEM_freeN(sb_threads);
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
@@ -1649,7 +1606,7 @@ static int choose_winner(float*w, float* pos, float*a, float*b, float*c, float*c
static int sb_detect_vertex_collisionCached(
float opco[3], float facenormal[3], float *damp,
- float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner,
+ float force[3], struct Object *vertexowner,
float time, float vel[3], float *intrusion)
{
Object *ob= NULL;
@@ -1845,8 +1802,8 @@ static int sb_deflect_face(Object *ob, float *actpos, float *facenormal, float *
float s_actpos[3];
int deflected;
copy_v3_v3(s_actpos, actpos);
- deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force, ob->lay, ob, time, vel, intrusion);
- //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force, ob->lay, ob, time, vel, intrusion);
+ deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force, ob, time, vel, intrusion);
+ //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force, ob, time, vel, intrusion);
return(deflected);
}
@@ -1969,7 +1926,7 @@ static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, floa
/* since this is definitely the most CPU consuming task here .. try to spread it */
/* core function _softbody_calc_forces_slice_in_a_thread */
/* result is int to be able to flag user break */
-static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor)
+static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
{
float iks;
int bb, do_selfcollision, do_springcollision, do_aero;
@@ -2088,14 +2045,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
}
/* particle field & vortex */
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float kd;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale);
@@ -2170,11 +2127,11 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
static void *exec_softbody_calc_forces(void *data)
{
SB_thread_context *pctx = (SB_thread_context*)data;
- _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->do_effector, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
+ _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->effectors, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
return NULL;
}
-static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor)
+static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
{
ListBase threads;
SB_thread_context *sb_threads;
@@ -2206,7 +2163,7 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
}
else
sb_threads[i].ifirst = 0;
- sb_threads[i].do_effector = do_effector;
+ sb_threads[i].effectors = effectors;
sb_threads[i].do_deflector = do_deflector;
sb_threads[i].fieldfactor = fieldfactor;
sb_threads[i].windfactor = windfactor;
@@ -2229,14 +2186,13 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
MEM_freeN(sb_threads);
}
-static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow)
+static void softbody_calc_forcesEx(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow)
{
/* rule we never alter free variables :bp->vec bp->pos in here !
* this will ruin adaptive stepsize AKA heun! (BM)
*/
SoftBody *sb= ob->soft; /* is supposed to be there */
/*BodyPoint *bproot;*/ /* UNUSED */
- ListBase *do_effector = NULL;
/* float gravity; */ /* UNUSED */
/* float iks; */
float fieldfactor = -1.0f, windfactor = 0.25;
@@ -2245,7 +2201,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, sb->collision_group, ob);
+ do_deflector= query_external_colliders(depsgraph, sb->collision_group);
/* 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));
@@ -2254,31 +2210,31 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
/* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
if (do_springcollision || do_aero)
- sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL);
+ sb_sfesf_threads_run(depsgraph, scene, ob, timenow, sb->totspring, NULL);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights);
if (do_deflector) {
float defforce[3];
- do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow);
+ do_deflector = sb_detect_aabb_collisionCached(defforce, ob, timenow);
}
- sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, do_effector, do_deflector, fieldfactor, windfactor);
+ sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, effectors, do_deflector, fieldfactor, windfactor);
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
/* finish matrix and solve */
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
-static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow)
+static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow)
{
/* redirection to the new threaded Version */
if (!(G.debug_value & 0x10)) { // 16
- softbody_calc_forcesEx(scene, ob, forcetime, timenow);
+ softbody_calc_forcesEx(depsgraph, scene, ob, forcetime, timenow);
return;
}
else {
@@ -2297,7 +2253,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
BodyPoint *bp;
/* BodyPoint *bproot; */ /* UNUSED */
BodySpring *bs;
- ListBase *do_effector = NULL;
float iks, ks, kd, gravity[3] = {0.0f, 0.0f, 0.0f};
float fieldfactor = -1.0f, windfactor = 0.25f;
float tune = sb->ballstiff;
@@ -2309,7 +2264,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
}
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, sb->collision_group, ob);
+ do_deflector= query_external_colliders(depsgraph, sb->collision_group);
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));
@@ -2317,13 +2272,13 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */
/* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
- if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow);
+ if (do_springcollision || do_aero) scan_for_ext_spring_forces(depsgraph, scene, ob, timenow);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights);
if (do_deflector) {
float defforce[3];
- do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow);
+ do_deflector = sb_detect_aabb_collisionCached(defforce, ob, timenow);
}
bp = sb->bpoint;
@@ -2422,13 +2377,13 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* particle field & vortex */
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale);
@@ -2520,7 +2475,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
}
@@ -3321,7 +3276,8 @@ SoftBody *sbNew(Scene *scene)
sb->shearstiff = 1.0f;
sb->solverflags |= SBSO_OLDERR;
- sb->pointcache = BKE_ptcache_add(&sb->ptcaches);
+ sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared");
+ sb->shared->pointcache = BKE_ptcache_add(&sb->shared->ptcaches);
if (!sb->effector_weights)
sb->effector_weights = BKE_add_effector_weights(NULL);
@@ -3332,14 +3288,26 @@ SoftBody *sbNew(Scene *scene)
}
/* frees all */
-void sbFree(SoftBody *sb)
+void sbFree(Object *ob)
{
+ SoftBody *sb = ob->soft;
+ if (sb == NULL) {
+ return;
+ }
+
free_softbody_intern(sb);
- BKE_ptcache_free_list(&sb->ptcaches);
- sb->pointcache = NULL;
+
+ if ((ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+ /* Only free shared data on non-CoW copies */
+ BKE_ptcache_free_list(&sb->shared->ptcaches);
+ sb->shared->pointcache = NULL;
+ MEM_freeN(sb->shared);
+ }
if (sb->effector_weights)
MEM_freeN(sb->effector_weights);
MEM_freeN(sb);
+
+ ob->soft = NULL;
}
void sbFreeSimulation(SoftBody *sb)
@@ -3506,7 +3474,7 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int
}
}
-static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
+static void softbody_step(struct Depsgraph *depsgraph, Scene *scene, Object *ob, SoftBody *sb, float dtime)
{
/* the simulator */
float forcetime;
@@ -3520,12 +3488,10 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
*/
if (dtime < 0 || dtime > 10.5f) return;
- ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
+ ccd_update_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
if (sb->scratch->needstobuildcollider) {
- if (query_external_colliders(scene, sb->collision_group, ob)) {
- ccd_build_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
- }
+ ccd_build_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
sb->scratch->needstobuildcollider=0;
}
@@ -3554,12 +3520,12 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
sb->scratch->flag &= ~SBF_DOFUZZY;
/* do predictive euler step */
- softbody_calc_forces(scene, ob, forcetime, timedone/dtime);
+ softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 1, NULL, mid_flags);
/* crop new slope values to do averaged slope step */
- softbody_calc_forces(scene, ob, forcetime, timedone/dtime);
+ softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 2, &err, mid_flags);
softbody_apply_goalsnap(ob);
@@ -3640,7 +3606,7 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
}
/* simulates one step. framenr is in frames */
-void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
+void sbObjectStep(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
{
SoftBody *sb= ob->soft;
PointCache *cache;
@@ -3648,8 +3614,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
float dtime, timescale;
int framedelta, framenr, startframe, endframe;
int cache_result;
-
- cache= sb->pointcache;
+ cache= sb->shared->pointcache;
framenr= (int)cfra;
framedelta= framenr - cache->simframe;
@@ -3717,7 +3682,8 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
}
/* try to read from cache */
- bool can_simulate = (framenr == sb->last_frame+1) && !(cache->flag & PTCACHE_BAKED);
+ bool can_write_cache = DEG_is_active(depsgraph);
+ bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED) && can_write_cache;
cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
@@ -3728,7 +3694,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
BKE_ptcache_validate(cache, framenr);
- if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
+ if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED && can_write_cache)
BKE_ptcache_write(&pid, framenr);
sb->last_frame = framenr;
@@ -3740,7 +3706,9 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
}
else if (/*ob->id.lib || */(cache->flag & PTCACHE_BAKED)) { /* "library linking & pointcaches" has to be solved properly at some point */
/* if baked and nothing in cache, do nothing */
- BKE_ptcache_invalidate(cache);
+ if (can_write_cache) {
+ BKE_ptcache_invalidate(cache);
+ }
return;
}
@@ -3757,7 +3725,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
dtime = framedelta*timescale;
/* do simulation */
- softbody_step(scene, ob, sb, dtime);
+ softbody_step(depsgraph, scene, ob, sb, dtime);
softbody_to_object(ob, vertexCos, numVerts, 0);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index d21055ada6a..5135362bd69 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -48,13 +48,11 @@
#include "DNA_speaker_types.h"
#ifdef WITH_AUDASPACE
-# include AUD_SOUND_H
-# include AUD_SEQUENCE_H
-# include AUD_HANDLE_H
-# include AUD_SPECIAL_H
-# ifdef WITH_SYSTEM_AUDASPACE
-# include "../../../intern/audaspace/intern/AUD_Set.h"
-# endif
+# include <AUD_Sound.h>
+# include <AUD_Sequence.h>
+# include <AUD_Handle.h>
+# include <AUD_Special.h>
+# include "../../../intern/audaspace/intern/AUD_Set.h"
#endif
#include "BKE_global.h"
@@ -228,7 +226,7 @@ void BKE_sound_init_once(void)
atexit(BKE_sound_exit_once);
}
-static AUD_Device *sound_device;
+static AUD_Device *sound_device = NULL;
void *BKE_sound_get_device(void)
{
@@ -237,6 +235,9 @@ void *BKE_sound_get_device(void)
void BKE_sound_init(struct Main *bmain)
{
+ /* Make sure no instance of the sound system is running, otherwise we get leaks. */
+ BKE_sound_exit();
+
AUD_DeviceSpecs specs;
int device, buffersize;
const char *device_name;
@@ -302,7 +303,6 @@ void BKE_sound_exit_once(void)
sound_device = NULL;
AUD_exitOnce();
-#ifdef WITH_SYSTEM_AUDASPACE
if (audio_device_names != NULL) {
int i;
for (i = 0; audio_device_names[i]; i++) {
@@ -311,7 +311,6 @@ void BKE_sound_exit_once(void)
free(audio_device_names);
audio_device_names = NULL;
}
-#endif
}
/* XXX unused currently */
@@ -811,13 +810,76 @@ void BKE_sound_read_waveform(bSound *sound, short *stop)
BLI_spin_unlock(sound->spinlock);
}
-void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
+static void sound_update_base(Scene *scene, Base *base, void *new_set)
{
- Object *ob;
- Base *base;
+ Object *ob = base->object;
NlaTrack *track;
NlaStrip *strip;
Speaker *speaker;
+ float quat[4];
+
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
+ return;
+ }
+
+ ob->id.tag &= ~LIB_TAG_DOIT;
+
+ if ((ob->type != OB_SPEAKER) || !ob->adt) {
+ return;
+ }
+
+ for (track = ob->adt->nla_tracks.first; track; track = track->next) {
+ for (strip = track->strips.first; strip; strip = strip->next) {
+ if (strip->type != NLASTRIP_TYPE_SOUND) {
+ continue;
+ }
+ speaker = (Speaker *)ob->data;
+
+ if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
+ if (speaker->sound) {
+ AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
+ }
+ else {
+ AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
+ strip->speaker_handle = NULL;
+ }
+ }
+ else {
+ if (speaker->sound) {
+ strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
+ speaker->sound->playback_handle,
+ (double)strip->start / FPS, FLT_MAX, 0);
+ AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
+ }
+ }
+
+ if (strip->speaker_handle) {
+ const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
+ AUD_addSet(new_set, strip->speaker_handle);
+ AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
+ AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
+ AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
+ AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
+ AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
+ AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
+ AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
+ AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
+
+ mat4_to_quat(quat, ob->obmat);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
+ AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
+ AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
+ }
+ }
+ }
+}
+
+void BKE_sound_update_scene(Main *bmain, Scene *scene)
+{
+ Base *base;
Scene *sce_it;
void *new_set = AUD_createSet();
@@ -826,59 +888,18 @@ void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
/* cheap test to skip looping over all objects (no speakers is a common case) */
if (!BLI_listbase_is_empty(&bmain->speaker)) {
- for (SETLOOPER(scene, sce_it, base)) {
- ob = base->object;
- if ((ob->type != OB_SPEAKER) || !ob->adt) {
- continue;
- }
- for (track = ob->adt->nla_tracks.first; track; track = track->next) {
- for (strip = track->strips.first; strip; strip = strip->next) {
- if (strip->type != NLASTRIP_TYPE_SOUND) {
- continue;
- }
- speaker = (Speaker *)ob->data;
-
- if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
- if (speaker->sound) {
- AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
- }
- else {
- AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
- strip->speaker_handle = NULL;
- }
- }
- else {
- if (speaker->sound) {
- strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
- speaker->sound->playback_handle,
- (double)strip->start / FPS, FLT_MAX, 0);
- AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
- }
- }
-
- if (strip->speaker_handle) {
- const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
- AUD_addSet(new_set, strip->speaker_handle);
- AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
- AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
- AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
- AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
- AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
- AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
- AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
- AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
-
- mat4_to_quat(quat, ob->obmat);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
- AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
- AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
- }
- }
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
+
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ sound_update_base(scene, base, new_set);
}
}
+
+ for (SETLOOPER_SET_ONLY(scene, sce_it, base)) {
+ sound_update_base(scene, base, new_set);
+ }
+
}
while ((handle = AUD_getSet(scene->speaker_handles))) {
@@ -911,28 +932,12 @@ float BKE_sound_get_length(bSound *sound)
char **BKE_sound_get_device_names(void)
{
if (audio_device_names == NULL) {
-#ifdef WITH_SYSTEM_AUDASPACE
audio_device_names = AUD_getDeviceNames();
-#else
- static const char *names[] = {
- "Null", "SDL", "OpenAL", "JACK", NULL
- };
- audio_device_names = (char **)names;
-#endif
}
return audio_device_names;
}
-bool BKE_sound_is_jack_supported(void)
-{
-#ifdef WITH_SYSTEM_AUDASPACE
- return 1;
-#else
- return (bool)AUD_isJackSupported();
-#endif
-}
-
#else /* WITH_AUDASPACE */
#include "BLI_utildefines.h"
@@ -979,5 +984,6 @@ void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char
void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
-bool BKE_sound_is_jack_supported(void) { return false; }
+char **BKE_sound_get_device_names(void) { static char *names[1] = {NULL}; return names; }
+
#endif /* WITH_AUDASPACE */
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
new file mode 100644
index 00000000000..10d9dcfbfec
--- /dev/null
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -0,0 +1,1411 @@
+/*
+ * ***** 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-2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenkernel/intern/studiolight.c
+ * \ingroup bke
+ */
+
+#include "BKE_studiolight.h"
+
+#include "BKE_appdir.h"
+#include "BKE_icons.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+#include "BLI_path_util.h"
+#include "BLI_rand.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "DNA_listBase.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "GPU_texture.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* Statics */
+static ListBase studiolights;
+static int last_studiolight_id = 0;
+#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 96
+#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT 32
+#define STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * 2)
+
+/*
+ * The method to calculate the irradiance buffers
+ * The irradiance buffer is only shown in the background when in LookDev.
+ *
+ * STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE is very slow, but very accurate
+ * STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS is faster but has artifacts
+ * Cannot have both enabled at the same time!!!
+ */
+// #define STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+#define STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS
+
+/* Temporarily disabled due to the creation of textures with -nan(ind)s */
+#define STUDIOLIGHT_SH_WINDOWING 0.0f /* 0.0 is disabled */
+
+/*
+ * Disable this option so caches are not loaded from disk
+ * Do not checkin with this commented out
+ */
+#define STUDIOLIGHT_LOAD_CACHED_FILES
+
+static const char *STUDIOLIGHT_LIGHTS_FOLDER = "studiolights/studio/";
+static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/";
+static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/";
+
+/* ITER MACRO */
+
+/** Iter on all pixel giving texel center position and pixel pointer.
+ * Arguments
+ * type : type of src.
+ * src : source buffer.
+ * channels : number of channels per pixel.
+ *
+ * Others
+ * x, y : normalized UV coordinate [0..1] of the current pixel center.
+ * texel_size[2] : UV size of a pixel in this texture.
+ * pixel[] : pointer to the current pixel.
+ */
+#define ITER_PIXELS(type, src, channels, width, height) \
+{ \
+ float texel_size[2]; \
+ texel_size[0] = 1.0f / width; \
+ texel_size[1] = 1.0f / height; \
+ type (*pixel_)[channels] = (type (*)[channels])src; \
+ for (float y = 0.5 * texel_size[1]; y < 1.0; y += texel_size[1]) { \
+ for (float x = 0.5 * texel_size[0]; x < 1.0; x += texel_size[0], pixel_++) { \
+ type *pixel = *pixel_;
+
+#define ITER_PIXELS_END \
+ } \
+ } \
+} ((void)0)
+
+/* FUNCTIONS */
+#define IMB_SAFE_FREE(p) do { \
+if (p) { \
+ IMB_freeImBuf(p); \
+ p = NULL; \
+} \
+} while (0)
+
+#define GPU_TEXTURE_SAFE_FREE(p) do { \
+if (p) { \
+ GPU_texture_free(p); \
+ p = NULL; \
+} \
+} while (0)
+
+static void studiolight_free(struct StudioLight *sl)
+{
+#define STUDIOLIGHT_DELETE_ICON(s) { \
+ if (s != 0) { \
+ BKE_icon_delete(s); \
+ s = 0; \
+ } \
+}
+ if (sl->free_function) {
+ sl->free_function(sl, sl->free_function_data);
+ }
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_radiance);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_irradiance);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap_flipped);
+#undef STUDIOLIGHT_DELETE_ICON
+
+ for (int index = 0; index < 6; index++) {
+ IMB_SAFE_FREE(sl->radiance_cubemap_buffers[index]);
+ }
+ GPU_TEXTURE_SAFE_FREE(sl->equirect_radiance_gputexture);
+ GPU_TEXTURE_SAFE_FREE(sl->equirect_irradiance_gputexture);
+ IMB_SAFE_FREE(sl->equirect_radiance_buffer);
+ IMB_SAFE_FREE(sl->equirect_irradiance_buffer);
+ MEM_SAFE_FREE(sl->path_irr_cache);
+ MEM_SAFE_FREE(sl->path_sh_cache);
+ MEM_SAFE_FREE(sl);
+}
+
+static struct StudioLight *studiolight_create(int flag)
+{
+ struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
+ sl->path[0] = 0x00;
+ sl->name[0] = 0x00;
+ sl->path_irr_cache = NULL;
+ sl->path_sh_cache = NULL;
+ sl->free_function = NULL;
+ sl->flag = flag;
+ sl->index = ++last_studiolight_id;
+ if (flag & STUDIOLIGHT_TYPE_STUDIO) {
+ sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE);
+ }
+ else if (flag & STUDIOLIGHT_TYPE_MATCAP) {
+ sl->icon_id_matcap = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP);
+ sl->icon_id_matcap_flipped = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED);
+ }
+ else {
+ sl->icon_id_radiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE);
+ }
+
+ for (int index = 0; index < 6; index++) {
+ sl->radiance_cubemap_buffers[index] = NULL;
+ }
+
+ return sl;
+}
+
+#define STUDIOLIGHT_FILE_VERSION 1
+
+#define READ_VAL(type, parser, id, val, lines) do { \
+ for (LinkNode *line = lines; line; line = line->next) { \
+ char *val_str, *str = line->link; \
+ if ((val_str = strstr(str, id " "))) { \
+ val_str += sizeof(id); /* Skip id + spacer. */ \
+ val = parser(val_str); \
+ } \
+ } \
+} while (0)
+
+#define READ_FVAL(id, val, lines) READ_VAL(float, atof, id, val, lines)
+#define READ_IVAL(id, val, lines) READ_VAL(int, atoi, id, val, lines)
+
+#define READ_VEC3(id, val, lines) do { \
+ READ_FVAL(id ".x", val[0], lines); \
+ READ_FVAL(id ".y", val[1], lines); \
+ READ_FVAL(id ".z", val[2], lines); \
+} while (0)
+
+#define READ_SOLIDLIGHT(sl, i, lines) do { \
+ READ_IVAL("light[" STRINGIFY(i) "].flag", sl[i].flag, lines); \
+ READ_FVAL("light[" STRINGIFY(i) "].smooth", sl[i].smooth, lines); \
+ READ_VEC3("light[" STRINGIFY(i) "].col", sl[i].col, lines); \
+ READ_VEC3("light[" STRINGIFY(i) "].spec", sl[i].spec, lines); \
+ READ_VEC3("light[" STRINGIFY(i) "].vec", sl[i].vec, lines); \
+} while (0)
+
+static void studiolight_load_solid_light(StudioLight *sl)
+{
+ LinkNode *lines = BLI_file_read_as_lines(sl->path);
+ if (lines) {
+ READ_VEC3("light_ambient", sl->light_ambient, lines);
+ READ_SOLIDLIGHT(sl->light, 0, lines);
+ READ_SOLIDLIGHT(sl->light, 1, lines);
+ READ_SOLIDLIGHT(sl->light, 2, lines);
+ READ_SOLIDLIGHT(sl->light, 3, lines);
+ }
+ BLI_file_free_lines(lines);
+}
+
+#undef READ_SOLIDLIGHT
+#undef READ_VEC3
+#undef READ_IVAL
+#undef READ_FVAL
+
+#define WRITE_FVAL(str, id, val) (BLI_dynstr_appendf(str, id " %f\n", val))
+#define WRITE_IVAL(str, id, val) (BLI_dynstr_appendf(str, id " %d\n", val))
+
+#define WRITE_VEC3(str, id, val) do { \
+ WRITE_FVAL(str, id ".x", val[0]); \
+ WRITE_FVAL(str, id ".y", val[1]); \
+ WRITE_FVAL(str, id ".z", val[2]); \
+} while (0)
+
+#define WRITE_SOLIDLIGHT(str, sl, i) do { \
+ WRITE_IVAL(str, "light[" STRINGIFY(i) "].flag", sl[i].flag); \
+ WRITE_FVAL(str, "light[" STRINGIFY(i) "].smooth", sl[i].smooth); \
+ WRITE_VEC3(str, "light[" STRINGIFY(i) "].col", sl[i].col); \
+ WRITE_VEC3(str, "light[" STRINGIFY(i) "].spec", sl[i].spec); \
+ WRITE_VEC3(str, "light[" STRINGIFY(i) "].vec", sl[i].vec); \
+} while (0)
+
+static void studiolight_write_solid_light(StudioLight *sl)
+{
+ FILE *fp = BLI_fopen(sl->path, "wb");
+ if (fp) {
+ DynStr *str = BLI_dynstr_new();
+
+ /* Very dumb ascii format. One value per line separated by a space. */
+ WRITE_IVAL(str, "version", STUDIOLIGHT_FILE_VERSION);
+ WRITE_VEC3(str, "light_ambient", sl->light_ambient);
+ WRITE_SOLIDLIGHT(str, sl->light, 0);
+ WRITE_SOLIDLIGHT(str, sl->light, 1);
+ WRITE_SOLIDLIGHT(str, sl->light, 2);
+ WRITE_SOLIDLIGHT(str, sl->light, 3);
+
+ char *cstr = BLI_dynstr_get_cstring(str);
+
+ fwrite(cstr, BLI_dynstr_get_len(str), 1, fp);
+ fclose(fp);
+
+ MEM_freeN(cstr);
+ BLI_dynstr_free(str);
+ }
+}
+
+#undef WRITE_SOLIDLIGHT
+#undef WRITE_VEC3
+#undef WRITE_IVAL
+#undef WRITE_FVAL
+
+static void direction_to_equirect(float r[2], const float dir[3])
+{
+ r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
+ r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
+}
+
+static void equirect_to_direction(float r[3], float u, float v)
+{
+ float phi = (-(M_PI * 2)) * u + M_PI;
+ float theta = -M_PI * v + M_PI;
+ float sin_theta = sinf(theta);
+ r[0] = sin_theta * cosf(phi);
+ r[1] = sin_theta * sinf(phi);
+ r[2] = cosf(theta);
+}
+
+static void UNUSED_FUNCTION(direction_to_cube_face_uv)(float r_uv[2], int *r_face, const float dir[3])
+{
+ if (fabsf(dir[0]) > fabsf(dir[1]) && fabsf(dir[0]) > fabsf(dir[2])) {
+ bool is_pos = (dir[0] > 0.0f);
+ *r_face = is_pos ? STUDIOLIGHT_X_POS : STUDIOLIGHT_X_NEG;
+ r_uv[0] = dir[2] / fabsf(dir[0]) * (is_pos ? 1 : -1);
+ r_uv[1] = dir[1] / fabsf(dir[0]) * (is_pos ? -1 : -1);
+ }
+ else if (fabsf(dir[1]) > fabsf(dir[0]) && fabsf(dir[1]) > fabsf(dir[2])) {
+ bool is_pos = (dir[1] > 0.0f);
+ *r_face = is_pos ? STUDIOLIGHT_Y_POS : STUDIOLIGHT_Y_NEG;
+ r_uv[0] = dir[0] / fabsf(dir[1]) * (is_pos ? 1 : 1);
+ r_uv[1] = dir[2] / fabsf(dir[1]) * (is_pos ? -1 : 1);
+ }
+ else {
+ bool is_pos = (dir[2] > 0.0f);
+ *r_face = is_pos ? STUDIOLIGHT_Z_NEG : STUDIOLIGHT_Z_POS;
+ r_uv[0] = dir[0] / fabsf(dir[2]) * (is_pos ? -1 : 1);
+ r_uv[1] = dir[1] / fabsf(dir[2]) * (is_pos ? -1 : -1);
+ }
+ r_uv[0] = r_uv[0] * 0.5f + 0.5f;
+ r_uv[1] = r_uv[1] * 0.5f + 0.5f;
+}
+
+static void cube_face_uv_to_direction(float r_dir[3], float x, float y, int face)
+{
+ const float conversion_matrices[6][3][3] = {
+ {{ 0.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}},
+ {{ 0.0f, 0.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}},
+ {{ 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, { 0.0f, 1.0f, 0.0f}},
+ {{ 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 0.0f, -1.0f, 0.0f}},
+ {{ 1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}},
+ {{-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}
+ };
+
+ copy_v3_fl3(r_dir, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f);
+ mul_m3_v3(conversion_matrices[face], r_dir);
+ normalize_v3(r_dir);
+}
+
+static void studiolight_load_equirect_image(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ ImBuf *ibuf = NULL;
+ ibuf = IMB_loadiffname(sl->path, 0, NULL);
+ if (ibuf == NULL) {
+ float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
+ copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
+ ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
+ }
+ IMB_float_from_rect(ibuf);
+ sl->equirect_radiance_buffer = ibuf;
+ }
+ sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
+}
+
+static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ char error[256];
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ ImBuf *ibuf = sl->equirect_radiance_buffer;
+
+ if (sl->flag & STUDIOLIGHT_TYPE_MATCAP) {
+ float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
+
+ float (*offset4)[4] = (float (*)[4])ibuf->rect_float;
+ float (*offset3)[3] = (float (*)[3])gpu_matcap_3components;
+ for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) {
+ copy_v3_v3(*offset3, *offset4);
+ }
+
+ sl->equirect_radiance_gputexture = GPU_texture_create_nD(
+ ibuf->x, ibuf->y, 0, 2, gpu_matcap_3components, GPU_R11F_G11F_B10F, GPU_DATA_FLOAT, 0, false, error);
+
+ MEM_SAFE_FREE(gpu_matcap_3components);
+ }
+ else {
+ sl->equirect_radiance_gputexture = GPU_texture_create_2D(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ GPUTexture *tex = sl->equirect_radiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
+}
+
+static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ char error[256];
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED);
+ ImBuf *ibuf = sl->equirect_irradiance_buffer;
+ sl->equirect_irradiance_gputexture = GPU_texture_create_2D(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ GPUTexture *tex = sl->equirect_irradiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE;
+}
+
+static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
+{
+ float uv[2];
+ direction_to_equirect(uv, direction);
+ nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
+}
+
+static void studiolight_calculate_radiance_buffer(
+ ImBuf *ibuf, float *colbuf,
+ const int index_x, const int index_y, const int index_z,
+ const float xsign, const float ysign, const float zsign)
+{
+ ITER_PIXELS(float, colbuf, 4,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
+ {
+ float direction[3];
+ direction[index_x] = xsign * (x - 0.5f);
+ direction[index_y] = ysign * (y - 0.5f);
+ direction[index_z] = zsign * 0.5f;
+ normalize_v3(direction);
+ studiolight_calculate_radiance(ibuf, pixel, direction);
+ }
+ ITER_PIXELS_END;
+}
+
+static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ ImBuf *ibuf = sl->equirect_radiance_buffer;
+ if (ibuf) {
+ float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__);
+
+ /* front */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, -1, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* back */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 2, 1, 1, 1, -1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* left */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, 1, -1, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* right */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 2, 1, 0, -1, -1, -1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* top */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, -1, -1, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* bottom */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, 0, 1, 2, 1, -1, -1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+#if 0
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], "/tmp/studiolight_radiance_left.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], "/tmp/studiolight_radiance_right.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], "/tmp/studiolight_radiance_front.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], "/tmp/studiolight_radiance_back.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], "/tmp/studiolight_radiance_bottom.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat);
+#endif
+ MEM_freeN(colbuf);
+ }
+ }
+ sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED;
+}
+
+/*
+ * Spherical Harmonics
+ */
+BLI_INLINE float area_element(float x, float y)
+{
+ return atan2(x * y, sqrtf(x * x + y * y + 1));
+}
+
+BLI_INLINE float texel_solid_angle(float x, float y, float halfpix)
+{
+ float v1x = (x - halfpix) * 2.0f - 1.0f;
+ float v1y = (y - halfpix) * 2.0f - 1.0f;
+ float v2x = (x + halfpix) * 2.0f - 1.0f;
+ float v2y = (y + halfpix) * 2.0f - 1.0f;
+
+ return area_element(v1x, v1y) - area_element(v1x, v2y) - area_element(v2x, v1y) + area_element(v2x, v2y);
+}
+
+static void studiolight_calculate_cubemap_vector_weight(float normal[3], float *weight, int face, float x, float y)
+{
+ const float halfpix = 0.5f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
+ cube_face_uv_to_direction(normal, x, y, face);
+ *weight = texel_solid_angle(x, y, halfpix);
+}
+
+static void studiolight_spherical_harmonics_calculate_coefficients(StudioLight *sl, float (*sh)[3])
+{
+ float weight_accum = 0.0f;
+ memset(sh, 0, sizeof(float) * 3 * STUDIOLIGHT_SH_COEFS_LEN);
+
+ for (int face = 0; face < 6; face++) {
+ ITER_PIXELS(float, sl->radiance_cubemap_buffers[face]->rect_float, 4,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
+ {
+ float color[3], cubevec[3], weight;
+ studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, x, y);
+ mul_v3_v3fl(color, pixel, weight);
+ weight_accum += weight;
+
+ int i = 0;
+ /* L0 */
+ madd_v3_v3fl(sh[i++], color, 0.2822095f);
+#if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
+ const float nx = cubevec[0];
+ const float ny = cubevec[1];
+ const float nz = cubevec[2];
+ madd_v3_v3fl(sh[i++], color, -0.488603f * nz);
+ madd_v3_v3fl(sh[i++], color, 0.488603f * ny);
+ madd_v3_v3fl(sh[i++], color, -0.488603f * nx);
+#endif
+#if STUDIOLIGHT_SH_BANDS > 2 /* L2 */
+ const float nx2 = SQUARE(nx);
+ const float ny2 = SQUARE(ny);
+ const float nz2 = SQUARE(nz);
+ madd_v3_v3fl(sh[i++], color, 1.092548f * nx * nz);
+ madd_v3_v3fl(sh[i++], color, -1.092548f * nz * ny);
+ madd_v3_v3fl(sh[i++], color, 0.315392f * (3.0f * ny2 - 1.0f));
+ madd_v3_v3fl(sh[i++], color, 1.092548f * nx * ny);
+ madd_v3_v3fl(sh[i++], color, 0.546274f * (nx2 - nz2));
+#endif
+ /* Bypass L3 Because final irradiance does not need it. */
+#if STUDIOLIGHT_SH_BANDS > 4 /* L4 */
+ const float nx4 = SQUARE(nx2);
+ const float ny4 = SQUARE(ny2);
+ const float nz4 = SQUARE(nz2);
+ madd_v3_v3fl(sh[i++], color, 2.5033429417967046f * nx * nz * (nx2 - nz2));
+ madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
+ madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(sh[i++], color, (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
+ madd_v3_v3fl(sh[i++], color, -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(sh[i++], color, 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(sh[i++], color, -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
+ madd_v3_v3fl(sh[i++], color, 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
+#endif
+ }
+ ITER_PIXELS_END;
+ }
+
+ /* The sum of solid angle should be equal to the solid angle of the sphere (4 PI),
+ * so normalize in order to make our weightAccum exactly match 4 PI. */
+ for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; ++i) {
+ mul_v3_fl(sh[i], M_PI * 4.0f / weight_accum);
+ }
+}
+
+/* Take monochrome SH as input */
+static float studiolight_spherical_harmonics_lambda_get(float *sh, float max_laplacian)
+{
+ /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf */
+ float table_l[STUDIOLIGHT_SH_BANDS];
+ float table_b[STUDIOLIGHT_SH_BANDS];
+
+ float lambda = 0.0f;
+
+ table_l[0] = 0.0f;
+ table_b[0] = 0.0f;
+ int index = 1;
+ for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
+ table_l[level] = (float)(SQUARE(level) * SQUARE(level + 1));
+
+ float b = 0.0f;
+ for (int m = -1; m <= level; m++) {
+ b += SQUARE(sh[index++]);
+ }
+ table_b[level] = b;
+ }
+
+ float squared_lamplacian = 0.0f;
+ for (int level = 1; level < STUDIOLIGHT_SH_BANDS; level++) {
+ squared_lamplacian += table_l[level] * table_b[level];
+ }
+
+ const float target_squared_laplacian = max_laplacian * max_laplacian;
+ if (squared_lamplacian <= target_squared_laplacian) {
+ return lambda;
+ }
+
+ const int no_iterations = 10000000;
+ for (int i = 0; i < no_iterations; ++i) {
+ float f = 0.0f;
+ float fd = 0.0f;
+
+ for (int level = 1; level < STUDIOLIGHT_SH_BANDS; ++level) {
+ f += table_l[level] * table_b[level] / SQUARE(1.0f + lambda * table_l[level]);
+ fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) / CUBE(1.0f + lambda * table_l[level]);
+ }
+
+ f = target_squared_laplacian - f;
+
+ float delta = -f / fd;
+ lambda += delta;
+
+ if (ABS(delta) < 1e-6f) {
+ break;
+ }
+ }
+
+ return lambda;
+}
+
+static void studiolight_spherical_harmonics_apply_windowing(float (*sh)[3], float max_laplacian)
+{
+ if (max_laplacian <= 0.0f)
+ return;
+
+ float sh_r[STUDIOLIGHT_SH_COEFS_LEN];
+ float sh_g[STUDIOLIGHT_SH_COEFS_LEN];
+ float sh_b[STUDIOLIGHT_SH_COEFS_LEN];
+ for (int i = 0; i < STUDIOLIGHT_SH_COEFS_LEN; i++) {
+ sh_r[i] = sh[i][0];
+ sh_g[i] = sh[i][1];
+ sh_b[i] = sh[i][2];
+ }
+ float lambda_r = studiolight_spherical_harmonics_lambda_get(sh_r, max_laplacian);
+ float lambda_g = studiolight_spherical_harmonics_lambda_get(sh_g, max_laplacian);
+ float lambda_b = studiolight_spherical_harmonics_lambda_get(sh_b, max_laplacian);
+
+ /* Apply windowing lambda */
+ int index = 0;
+ for (int level = 0; level < STUDIOLIGHT_SH_BANDS; level++) {
+ float s[3];
+ s[0] = 1.0f / (1.0f + lambda_r * SQUARE(level) * SQUARE(level + 1.0f));
+ s[1] = 1.0f / (1.0f + lambda_g * SQUARE(level) * SQUARE(level + 1.0f));
+ s[2] = 1.0f / (1.0f + lambda_b * SQUARE(level) * SQUARE(level + 1.0f));
+
+ for (int m = -1; m <= level; m++) {
+ mul_v3_v3(sh[index++], s);
+ }
+ }
+}
+
+static float studiolight_spherical_harmonics_geomerics_eval(const float normal[3], float sh0, float sh1, float sh2, float sh3)
+{
+ /* Use Geomerics non-linear SH. */
+ /* http://www.geomerics.com/wp-content/uploads/2015/08/CEDEC_Geomerics_ReconstructingDiffuseLighting1.pdf */
+ float R0 = sh0 * M_1_PI;
+
+ float R1[3] = {-sh3, sh2, -sh1};
+ mul_v3_fl(R1, 0.5f * M_1_PI * 1.5f); /* 1.5f is to improve the contrast a bit. */
+ float lenR1 = len_v3(R1);
+ mul_v3_fl(R1, 1.0f / lenR1);
+ float q = 0.5f * (1.0f + dot_v3v3(R1, normal));
+
+ float p = 1.0f + 2.0f * lenR1 / R0;
+ float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0);
+
+ return R0 * (a + (1.0f - a) * (p + 1.0f) * powf(q, p));
+}
+
+BLI_INLINE void studiolight_spherical_harmonics_eval(StudioLight *sl, float color[3], const float normal[3])
+{
+#if STUDIOLIGHT_SH_BANDS == 2
+ float (*sh)[3] = (float (*)[3])sl->spherical_harmonics_coefs;
+ for (int i = 0; i < 3; ++i) {
+ color[i] = studiolight_spherical_harmonics_geomerics_eval(normal, sh[0][i], sh[1][i], sh[2][i], sh[3][i]);
+ }
+ return;
+#else
+
+ /* L0 */
+ mul_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
+# if STUDIOLIGHT_SH_BANDS > 1 /* L1 */
+ const float nx = normal[0];
+ const float ny = normal[1];
+ const float nz = normal[2];
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * nx);
+# endif
+# if STUDIOLIGHT_SH_BANDS > 2 /* L2 */
+ const float nx2 = SQUARE(nx);
+ const float ny2 = SQUARE(ny);
+ const float nz2 = SQUARE(nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * nx * nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * nz * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * ny2 - 1.0f));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * nx * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (nx2 - nz2));
+# endif
+ /* L3 coefs are 0 */
+# if STUDIOLIGHT_SH_BANDS > 4 /* L4 */
+ const float nx4 = SQUARE(nx2);
+ const float ny4 = SQUARE(ny2);
+ const float nz4 = SQUARE(nz2);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[9], 2.5033429417967046f * nx * nz * (nx2 - nz2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[10], -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[11], 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[12], -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[13], (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[14], -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[15], 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[16], -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[17], 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
+# endif
+#endif
+}
+
+/* This modify the radiance into irradiance. */
+static void studiolight_spherical_harmonics_apply_band_factors(StudioLight *sl, float (*sh)[3])
+{
+ static float sl_sh_band_factors[5] = {
+ 1.0f,
+ 2.0f / 3.0f,
+ 1.0f / 4.0f,
+ 0.0f,
+ -1.0f / 24.0f
+ };
+
+ int index = 0, dst_idx = 0;
+ for (int band = 0; band < STUDIOLIGHT_SH_BANDS; band++) {
+ for (int m = 0; m < SQUARE(band + 1) - SQUARE(band); m++) {
+ /* Skip L3 */
+ if (band != 3) {
+ mul_v3_v3fl(sl->spherical_harmonics_coefs[dst_idx++], sh[index], sl_sh_band_factors[band]);
+ }
+ index++;
+ }
+ }
+}
+
+static void studiolight_calculate_diffuse_light(StudioLight *sl)
+{
+ /* init light to black */
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
+
+ float sh_coefs[STUDIOLIGHT_SH_COEFS_LEN][3];
+ studiolight_spherical_harmonics_calculate_coefficients(sl, sh_coefs);
+ studiolight_spherical_harmonics_apply_windowing(sh_coefs, STUDIOLIGHT_SH_WINDOWING);
+ studiolight_spherical_harmonics_apply_band_factors(sl, sh_coefs);
+
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ FILE *fp = BLI_fopen(sl->path_sh_cache, "wb");
+ if (fp) {
+ fwrite(sl->spherical_harmonics_coefs, sizeof(sl->spherical_harmonics_coefs), 1, fp);
+ fclose(fp);
+ }
+ }
+ }
+ sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
+}
+
+BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(
+ ImBuf *radiance_buffer, const float normal[3], float color[3],
+ int xoffset, int yoffset, int zoffset, float zsign)
+{
+ if (radiance_buffer == NULL) {
+ return;
+ }
+
+ float accum[3] = {0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.00001f;
+ ITER_PIXELS(float, radiance_buffer->rect_float, 4,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE,
+ STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE)
+ {
+ float direction[3];
+ direction[zoffset] = zsign * 0.5f;
+ direction[xoffset] = x - 0.5f;
+ direction[yoffset] = y - 0.5f;
+ normalize_v3(direction);
+ float weight = dot_v3v3(direction, normal) > 0.95f ? 1.0f : 0.0f;
+ // float solid_angle = texel_solid_angle(x, y, texel_size[0] * 0.5f);
+ madd_v3_v3fl(accum, pixel, weight);
+ accum_weight += weight;
+ }
+ ITER_PIXELS_END;
+
+ madd_v3_v3fl(color, accum, 1.0f / accum_weight);
+}
+
+#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+static void studiolight_irradiance_eval(StudioLight *sl, float color[3], const float normal[3])
+{
+ copy_v3_fl(color, 0.0f);
+
+ /* XXX: This is madness, iterating over all cubemap pixels for each destination pixels
+ * even if their weight is 0.0f.
+ * It should use hemisphere, cosine sampling at least. */
+
+ /* back */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, 0, 2, 1, 1);
+ /* front */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, 0, 2, 1, -1);
+
+ /* left */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, 1, 2, 0, 1);
+ /* right */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, 1, 2, 0, -1);
+
+ /* top */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, 0, 1, 2, 1);
+ /* bottom */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, 0, 1, 2, -1);
+
+ mul_v3_fl(color, 1.0 / M_PI);
+}
+#endif
+
+static float brdf_approx(float spec_color, float roughness, float NV)
+{
+ /* Very rough own approx. We don't need it to be correct, just fast.
+ * Just simulate fresnel effect with roughness attenuation. */
+ float fresnel = exp2(-8.35f * NV) * (1.0f - roughness);
+ return spec_color * (1.0f - fresnel) + fresnel;
+}
+
+/* NL need to be unclamped. w in [0..1] range. */
+static float wrapped_lighting(float NL, float w)
+{
+ float w_1 = w + 1.0f;
+ return max_ff((NL + w) / (w_1 * w_1), 0.0f);
+}
+
+static float blinn_specular(
+ const float L[3], const float I[3], const float N[3], float R[3], float NL, float roughness, float wrap)
+{
+ float half_dir[3];
+ float wrapped_NL = dot_v3v3(L, R);
+ add_v3_v3v3(half_dir, L, I);
+ normalize_v3(half_dir);
+ float spec_angle = max_ff(dot_v3v3(half_dir, N), 0.0f);
+
+ float gloss = 1.0f - roughness;
+ /* Reduce gloss for smooth light. (simulate bigger light) */
+ gloss *= 1.0f - wrap;
+ float shininess = exp2(10.0f * gloss + 1.0f);
+
+ /* Pi is already divided in the lamp power.
+ * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */
+ float normalization_factor = shininess * 0.125f + 1.0f;
+ float spec_light = powf(spec_angle, shininess) * max_ff(NL, 0.0f) * normalization_factor;
+
+ /* Simulate Env. light. */
+ float w = wrap * (1.0 - roughness) + roughness;
+ float spec_env = wrapped_lighting(wrapped_NL, w);
+
+ float w2 = wrap * wrap;
+
+ return spec_light * (1.0 - w2) + spec_env * w2;
+}
+
+/* Keep in sync with the glsl shader function get_world_lighting() */
+static void studiolight_lights_eval(StudioLight *sl, float color[3], const float normal[3])
+{
+ float R[3], I[3] = {0.0f, 0.0f, 1.0f}, N[3] = {normal[0], normal[2], -normal[1]};
+ const float roughness = 0.5f;
+ const float diffuse_color = 0.8f;
+ const float specular_color = brdf_approx(0.05f, roughness, N[2]);
+ float diff_light[3], spec_light[3];
+
+ /* Ambient lighting */
+ copy_v3_v3(diff_light, sl->light_ambient);
+ copy_v3_v3(spec_light, sl->light_ambient);
+
+ reflect_v3_v3v3(R, I, N);
+ for (int i = 0; i < 3; ++i) {
+ SolidLight *light = &sl->light[i];
+ if (light->flag) {
+ /* Diffuse lighting */
+ float NL = dot_v3v3(light->vec, N);
+ float diff = wrapped_lighting(NL, light->smooth);
+ madd_v3_v3fl(diff_light, light->col, diff);
+ /* Specular lighting */
+ float spec = blinn_specular(light->vec, I, N, R, NL, roughness, light->smooth);
+ madd_v3_v3fl(spec_light, light->spec, spec);
+ }
+ }
+
+ /* Multiply result by surface colors. */
+ mul_v3_fl(diff_light, diffuse_color * (1.0 - specular_color));
+ mul_v3_fl(spec_light, specular_color);
+
+ add_v3_v3v3(color, diff_light, spec_light);
+}
+
+static bool studiolight_load_irradiance_equirect_image(StudioLight *sl)
+{
+#ifdef STUDIOLIGHT_LOAD_CACHED_FILES
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ ImBuf *ibuf = NULL;
+ ibuf = IMB_loadiffname(sl->path_irr_cache, 0, NULL);
+ if (ibuf) {
+ IMB_float_from_rect(ibuf);
+ sl->equirect_irradiance_buffer = ibuf;
+ sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED;
+ return true;
+ }
+ }
+#else
+ UNUSED_VARS(sl);
+#endif
+ return false;
+}
+
+static bool studiolight_load_spherical_harmonics_coefficients(StudioLight *sl)
+{
+#ifdef STUDIOLIGHT_LOAD_CACHED_FILES
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ FILE *fp = BLI_fopen(sl->path_sh_cache, "rb");
+ if (fp) {
+ if (fread((void *)(sl->spherical_harmonics_coefs), sizeof(sl->spherical_harmonics_coefs), 1, fp)) {
+ sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
+ fclose(fp);
+ return true;
+ }
+ fclose(fp);
+ }
+ }
+#else
+ UNUSED_VARS(sl);
+#endif
+ return false;
+}
+
+static void studiolight_calculate_irradiance_equirect_image(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
+#else
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
+#endif
+
+ float *colbuf = MEM_mallocN(STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH * STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT * sizeof(float[4]), __func__);
+
+ ITER_PIXELS(float, colbuf, 4,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT)
+ {
+ float dir[3];
+ equirect_to_direction(dir, x, y);
+#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ studiolight_irradiance_eval(sl, pixel, dir);
+#else
+ studiolight_spherical_harmonics_eval(sl, pixel, dir);
+#endif
+ pixel[3] = 1.0f;
+ }
+ ITER_PIXELS_END;
+
+ sl->equirect_irradiance_buffer = IMB_allocFromBuffer(
+ NULL, colbuf,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_WIDTH,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECT_HEIGHT);
+ MEM_freeN(colbuf);
+
+#ifdef STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ /*
+ * Only store cached files when using STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ */
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ IMB_saveiff(sl->equirect_irradiance_buffer, sl->path_irr_cache, IB_rectfloat);
+ }
+#endif
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED;
+}
+
+static StudioLight *studiolight_add_file(const char *path, int flag)
+{
+ char filename[FILE_MAXFILE];
+ BLI_split_file_part(path, filename, FILE_MAXFILE);
+
+ if ((((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) && BLI_path_extension_check(filename, ".sl")) ||
+ BLI_path_extension_check_array(filename, imb_ext_image))
+ {
+ StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | flag);
+ BLI_strncpy(sl->name, filename, FILE_MAXFILE);
+ BLI_strncpy(sl->path, path, FILE_MAXFILE);
+
+ if ((flag & STUDIOLIGHT_TYPE_STUDIO) != 0) {
+ studiolight_load_solid_light(sl);
+ }
+ else {
+ sl->path_irr_cache = BLI_string_joinN(path, ".irr");
+ sl->path_sh_cache = BLI_string_joinN(path, ".sh2");
+ }
+ BLI_addtail(&studiolights, sl);
+ return sl;
+ }
+ return NULL;
+}
+
+static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag)
+{
+ struct direntry *dir;
+ const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
+ if (folder) {
+ uint totfile = BLI_filelist_dir_contents(folder, &dir);
+ int i;
+ for (i = 0; i < totfile; i++) {
+ if ((dir[i].type & S_IFREG)) {
+ studiolight_add_file(dir[i].path, flag);
+ }
+ }
+ BLI_filelist_free(dir, totfile);
+ dir = NULL;
+ }
+}
+
+static int studiolight_flag_cmp_order(const StudioLight *sl)
+{
+ /* Internal studiolights before external studio lights */
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ return 1;
+ }
+ return 0;
+}
+
+static int studiolight_cmp(const void *a, const void *b)
+{
+ const StudioLight *sl1 = a;
+ const StudioLight *sl2 = b;
+
+ const int flagorder1 = studiolight_flag_cmp_order(sl1);
+ const int flagorder2 = studiolight_flag_cmp_order(sl2);
+
+ if (flagorder1 < flagorder2) {
+ return -1;
+ }
+ else if (flagorder1 > flagorder2) {
+ return 1;
+ }
+ else {
+ return BLI_strcasecmp(sl1->name, sl2->name);
+ }
+}
+
+/* icons */
+
+/* Takes normalized uvs as parameter (range from 0 to 1).
+ * inner_edge and outer_edge are distances (from the center)
+ * in uv space for the alpha mask falloff. */
+static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
+{
+ /* Coords from center. */
+ float co[2] = {u - 0.5f, v - 0.5f};
+ float dist = len_v2(co);
+ float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge);
+ uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f));
+ return mask << 24;
+}
+
+/* Percentage of the icon that the preview sphere covers. */
+#define STUDIOLIGHT_DIAMETER 0.95f
+/* Rescale coord around (0.5, 0.5) by STUDIOLIGHT_DIAMETER. */
+#define RESCALE_COORD(x) (x / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f)
+
+/* Remaps normalized UV [0..1] to a sphere normal around (0.5, 0.5) */
+static void sphere_normal_from_uv(float normal[3], float u, float v)
+{
+ normal[0] = u * 2.0f - 1.0f;
+ normal[1] = v * 2.0f - 1.0f;
+ float dist = len_v2(normal);
+ normal[2] = sqrtf(1.0f - SQUARE(dist));
+}
+
+static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ ITER_PIXELS(uint, icon_buffer, 1,
+ STUDIOLIGHT_ICON_SIZE,
+ STUDIOLIGHT_ICON_SIZE)
+ {
+ float dy = RESCALE_COORD(y);
+ float dx = RESCALE_COORD(x);
+
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
+ if (alphamask != 0) {
+ float normal[3], direction[3], color[4];
+ float incoming[3] = {0.0f, 0.0f, -1.0f};
+ sphere_normal_from_uv(normal, dx, dy);
+ reflect_v3_v3v3(direction, incoming, normal);
+ /* We want to see horizon not poles. */
+ SWAP(float, direction[1], direction[2]);
+ direction[1] = -direction[1];
+
+ studiolight_calculate_radiance(sl->equirect_radiance_buffer, color, direction);
+
+ *pixel = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ else {
+ *pixel = 0x0;
+ }
+ }
+ ITER_PIXELS_END;
+}
+
+static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ ImBuf *ibuf = sl->equirect_radiance_buffer;
+
+ ITER_PIXELS(uint, icon_buffer, 1,
+ STUDIOLIGHT_ICON_SIZE,
+ STUDIOLIGHT_ICON_SIZE)
+ {
+ float dy = RESCALE_COORD(y);
+ float dx = RESCALE_COORD(x);
+ if (flipped) {
+ dx = 1.0f - dx;
+ }
+
+ float color[4];
+ nearest_interpolation_color(ibuf, NULL, color, dx * ibuf->x - 1.0f, dy * ibuf->y - 1.0f);
+
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
+
+ *pixel = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ ITER_PIXELS_END;
+}
+
+static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
+{
+ ITER_PIXELS(uint, icon_buffer, 1,
+ STUDIOLIGHT_ICON_SIZE,
+ STUDIOLIGHT_ICON_SIZE)
+ {
+ float dy = RESCALE_COORD(y);
+ float dx = RESCALE_COORD(x);
+
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - texel_size[0], 0.5f);
+ if (alphamask != 0) {
+ float normal[3], color[3];
+ sphere_normal_from_uv(normal, dx, dy);
+ /* We want to see horizon not poles. */
+ SWAP(float, normal[1], normal[2]);
+ normal[1] = -normal[1];
+
+ studiolight_lights_eval(sl, color, normal);
+
+ *pixel = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ else {
+ *pixel = 0x0;
+ }
+ }
+ ITER_PIXELS_END;
+}
+
+/* API */
+void BKE_studiolight_init(void)
+{
+ /* Add default studio light */
+ StudioLight * sl = studiolight_create(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED | STUDIOLIGHT_TYPE_STUDIO);
+ BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
+
+ copy_v4_fl4(sl->light_ambient, 0.025000, 0.025000, 0.025000, 1.000000);
+
+ copy_v4_fl4(sl->light[0].vec, -0.580952, 0.228571, 0.781185, 0.0);
+ copy_v4_fl4(sl->light[0].col, 0.900000, 0.900000, 0.900000, 1.000000);
+ copy_v4_fl4(sl->light[0].spec, 0.318547, 0.318547, 0.318547, 1.000000);
+ sl->light[0].flag = 1;
+ sl->light[0].smooth = 0.1;
+
+ copy_v4_fl4(sl->light[1].vec, 0.788218, 0.593482, -0.162765, 0.0);
+ copy_v4_fl4(sl->light[1].col, 0.267115, 0.269928, 0.358840, 1.000000);
+ copy_v4_fl4(sl->light[1].spec, 0.090838, 0.090838, 0.090838, 1.000000);
+ sl->light[1].flag = 1;
+ sl->light[1].smooth = 0.25;
+
+ copy_v4_fl4(sl->light[2].vec, 0.696472, -0.696472, -0.172785, 0.0);
+ copy_v4_fl4(sl->light[2].col, 0.293216, 0.304662, 0.401968, 1.000000);
+ copy_v4_fl4(sl->light[2].spec, 0.069399, 0.020331, 0.020331, 1.000000);
+ sl->light[2].flag = 1;
+ sl->light[2].smooth = 0.5;
+
+ BLI_addtail(&studiolights, sl);
+
+ /* go over the preset folder and add a studiolight for every image with its path */
+ /* Also reserve icon space for it. */
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_LIGHTS_FOLDER, STUDIOLIGHT_TYPE_STUDIO);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_LIGHTS_FOLDER, STUDIOLIGHT_TYPE_STUDIO | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_TYPE_WORLD);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_TYPE_WORLD | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_TYPE_MATCAP);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_TYPE_MATCAP | STUDIOLIGHT_USER_DEFINED);
+
+ /* sort studio lights on filename. */
+ BLI_listbase_sort(&studiolights, studiolight_cmp);
+}
+
+void BKE_studiolight_free(void)
+{
+ struct StudioLight *sl;
+ while ((sl = BLI_pophead(&studiolights))) {
+ studiolight_free(sl);
+ }
+}
+
+struct StudioLight *BKE_studiolight_find_first(int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ }
+ return NULL;
+}
+
+struct StudioLight *BKE_studiolight_find(const char *name, int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ else {
+ /* flags do not match, so use default */
+ return BKE_studiolight_find_first(flag);
+ }
+ }
+ }
+ /* When not found, use the default studio light */
+ return BKE_studiolight_find_first(flag);
+}
+
+struct StudioLight *BKE_studiolight_findindex(int index, int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if (sl->index == index) {
+ return sl;
+ }
+ }
+ /* When not found, use the default studio light */
+ return BKE_studiolight_find_first(flag);
+}
+
+struct ListBase *BKE_studiolight_listbase(void)
+{
+ return &studiolights;
+}
+
+void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type)
+{
+ switch (icon_id_type) {
+ case STUDIOLIGHT_ICON_ID_TYPE_RADIANCE:
+ default:
+ {
+ studiolight_radiance_preview(icon_buffer, sl);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE:
+ {
+ studiolight_irradiance_preview(icon_buffer, sl);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_MATCAP:
+ {
+ studiolight_matcap_preview(icon_buffer, sl, false);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED:
+ {
+ studiolight_matcap_preview(icon_buffer, sl, true);
+ break;
+ }
+ }
+}
+
+/* Ensure state of Studiolights */
+void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
+{
+ if ((sl->flag & flag) == flag) {
+ return;
+ }
+
+ if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) {
+ studiolight_load_equirect_image(sl);
+ }
+ if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) {
+ studiolight_calculate_radiance_cubemap_buffers(sl);
+ }
+ if ((flag & STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED)) {
+ if (!studiolight_load_spherical_harmonics_coefficients(sl)) {
+ studiolight_calculate_diffuse_light(sl);
+ }
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE)) {
+ studiolight_create_equirect_radiance_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE)) {
+ studiolight_create_equirect_irradiance_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECT_IRRADIANCE_IMAGE_CALCULATED)) {
+ if (!studiolight_load_irradiance_equirect_image(sl)) {
+ studiolight_calculate_irradiance_equirect_image(sl);
+ }
+ }
+}
+
+/*
+ * Python API Functions
+ */
+void BKE_studiolight_remove(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ BLI_remlink(&studiolights, sl);
+ studiolight_free(sl);
+ }
+}
+
+StudioLight *BKE_studiolight_load(const char *path, int type)
+{
+ StudioLight *sl = studiolight_add_file(path, type | STUDIOLIGHT_USER_DEFINED);
+ return sl;
+}
+
+StudioLight *BKE_studiolight_create(const char *path, const SolidLight light[4], const float light_ambient[3])
+{
+ StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_USER_DEFINED | STUDIOLIGHT_TYPE_STUDIO);
+
+ char filename[FILE_MAXFILE];
+ BLI_split_file_part(path, filename, FILE_MAXFILE);
+ BLI_snprintf(sl->path, FILE_MAXFILE, "%s%s", path, ".sl");
+ BLI_snprintf(sl->name, FILE_MAXFILE, "%s%s", filename, ".sl");
+
+ memcpy(sl->light, light, sizeof(*light) * 3);
+ memcpy(sl->light_ambient, light_ambient, sizeof(*light_ambient) * 3);
+
+ studiolight_write_solid_light(sl);
+
+ BLI_addtail(&studiolights, sl);
+ return sl;
+}
+
+/* Only useful for workbench while editing the userprefs. */
+StudioLight *BKE_studiolight_studio_edit_get(void)
+{
+ static StudioLight sl = {0};
+ sl.flag = STUDIOLIGHT_TYPE_STUDIO;
+
+ memcpy(sl.light, U.light, sizeof(*sl.light) * 3);
+ memcpy(sl.light_ambient, U.light_ambient, sizeof(sl.light_ambient) * 3);
+
+ return &sl;
+}
+
+void BKE_studiolight_refresh(void)
+{
+ BKE_studiolight_free();
+ BKE_studiolight_init();
+}
+
+void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data)
+{
+ sl->free_function = free_function;
+ sl->free_function_data = data;
+}
+
+void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id)
+{
+ BLI_assert(sl != NULL);
+ if (sl->icon_id_radiance == icon_id) {
+ sl->icon_id_radiance = 0;
+ }
+ if (sl->icon_id_irradiance == icon_id) {
+ sl->icon_id_irradiance = 0;
+ }
+ if (sl->icon_id_matcap == icon_id) {
+ sl->icon_id_matcap = 0;
+ }
+ if (sl->icon_id_matcap_flipped == icon_id) {
+ sl->icon_id_matcap_flipped = 0;
+ }
+}
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
new file mode 100644
index 00000000000..b2736ed8f37
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -0,0 +1,149 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "subdiv_converter.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_converter_capi.h"
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
+
+eSubdivFVarLinearInterpolation
+BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
+{
+ switch (uv_smooth) {
+ case SUBSURF_UV_SMOOTH_NONE:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE;
+ case SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
+ case SUBSURF_UV_SMOOTH_ALL:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE;
+ }
+ BLI_assert(!"Unknown uv smooth flag");
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
+}
+
+Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
+ struct OpenSubdiv_Converter *converter)
+{
+ SubdivStats stats;
+ BKE_subdiv_stats_init(&stats);
+ BKE_subdiv_stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
+ OpenSubdiv_TopologyRefinerSettings topology_refiner_settings;
+ topology_refiner_settings.level = settings->level;
+ topology_refiner_settings.is_adaptive = settings->is_adaptive;
+ struct OpenSubdiv_TopologyRefiner *osd_topology_refiner = NULL;
+ if (converter->getNumVertices(converter) != 0) {
+ osd_topology_refiner =
+ openSubdiv_createTopologyRefinerFromConverter(
+ converter, &topology_refiner_settings);
+
+ }
+ else {
+ /* TODO(sergey): Check whether original geometry had any vertices.
+ * The thing here is: OpenSubdiv can only deal with faces, but our
+ * side of subdiv also deals with loose vertices and edges.
+ */
+ }
+ Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr");
+ subdiv->settings = *settings;
+ subdiv->topology_refiner = osd_topology_refiner;
+ subdiv->evaluator = NULL;
+ subdiv->displacement_evaluator = NULL;
+ BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
+ subdiv->stats = stats;
+ return subdiv;
+}
+
+Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
+ struct Mesh *mesh)
+{
+ if (mesh->totvert == 0) {
+ return NULL;
+ }
+ OpenSubdiv_Converter converter;
+ BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
+ Subdiv *subdiv = BKE_subdiv_new_from_converter(settings, &converter);
+ BKE_subdiv_converter_free(&converter);
+ return subdiv;
+}
+
+void BKE_subdiv_free(Subdiv *subdiv)
+{
+ if (subdiv->evaluator != NULL) {
+ openSubdiv_deleteEvaluator(subdiv->evaluator);
+ }
+ if (subdiv->topology_refiner != NULL) {
+ openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
+ }
+ BKE_subdiv_displacement_detach(subdiv);
+ if (subdiv->cache_.face_ptex_offset != NULL) {
+ MEM_freeN(subdiv->cache_.face_ptex_offset);
+ }
+ MEM_freeN(subdiv);
+}
+
+int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
+{
+ if (subdiv->cache_.face_ptex_offset != NULL) {
+ return subdiv->cache_.face_ptex_offset;
+ }
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ if (topology_refiner == NULL) {
+ return NULL;
+ }
+ const int num_coarse_faces =
+ topology_refiner->getNumFaces(topology_refiner);
+ subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
+ num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
+ int ptex_offset = 0;
+ for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
+ const int num_ptex_faces =
+ topology_refiner->getNumFacePtexFaces(
+ topology_refiner, face_index);
+ subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
+ ptex_offset += num_ptex_faces;
+ }
+ return subdiv->cache_.face_ptex_offset;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
new file mode 100644
index 00000000000..e488b1129fc
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -0,0 +1,1188 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_ccg.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_ccg.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math_bits.h"
+#include "BLI_math_vector.h"
+#include "BLI_task.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_ccg.h"
+#include "BKE_mesh.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+
+#include "opensubdiv_topology_refiner_capi.h"
+
+/* =============================================================================
+ * Generally useful internal helpers.
+ */
+
+/* Number of floats in per-vertex elements. */
+static int num_element_float_get(const SubdivCCG *subdiv_ccg)
+{
+ /* We always have 3 floats for coordinate. */
+ int num_floats = 3;
+ if (subdiv_ccg->has_normal) {
+ num_floats += 3;
+ }
+ if (subdiv_ccg->has_mask) {
+ num_floats += 1;
+ }
+ return num_floats;
+}
+
+/* Per-vertex element size in bytes. */
+static int element_size_bytes_get(const SubdivCCG *subdiv_ccg)
+{
+ return sizeof(float) * num_element_float_get(subdiv_ccg);
+}
+
+/* =============================================================================
+ * Internal helpers for CCG creation.
+ */
+
+static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg,
+ const SubdivToCCGSettings *settings)
+{
+ /* CCG always contains coordinates. Rest of layers are coming after them. */
+ int layer_offset = sizeof(float) * 3;
+ /* Mask. */
+ if (settings->need_mask) {
+ subdiv_ccg->has_mask = true;
+ subdiv_ccg->mask_offset = layer_offset;
+ layer_offset += sizeof(float);
+ }
+ else {
+ subdiv_ccg->has_mask = false;
+ subdiv_ccg->mask_offset = -1;
+ }
+ /* Normals.
+ *
+ * NOTE: Keep them at the end, matching old CCGDM. Doesn't really matter
+ * here, but some other area might in theory depend memory layout.
+ */
+ if (settings->need_normal) {
+ subdiv_ccg->has_normal = true;
+ subdiv_ccg->normal_offset = layer_offset;
+ layer_offset += sizeof(float) * 3;
+ }
+ else {
+ subdiv_ccg->has_normal = false;
+ subdiv_ccg->normal_offset = -1;
+ }
+}
+
+/* TODO(sergey): Make it more accessible function. */
+static int topology_refiner_count_face_corners(
+ OpenSubdiv_TopologyRefiner *topology_refiner)
+{
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ int num_corners = 0;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ num_corners += topology_refiner->getNumFaceVertices(
+ topology_refiner, face_index);
+ }
+ return num_corners;
+}
+
+/* NOTE: Grid size and layer flags are to be filled in before calling this
+ * function.
+ */
+static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ /* Allocate memory for surface grids. */
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ const int num_grids = topology_refiner_count_face_corners(topology_refiner);
+ const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
+ const int grid_area = grid_size * grid_size;
+ subdiv_ccg->num_grids = num_grids;
+ subdiv_ccg->grids =
+ MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids");
+ subdiv_ccg->grids_storage = MEM_calloc_arrayN(
+ num_grids, ((size_t)grid_area) * element_size,
+ "subdiv ccg grids storage");
+ const size_t grid_size_in_bytes = (size_t)grid_area * element_size;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ const size_t grid_offset = grid_size_in_bytes * grid_index;
+ subdiv_ccg->grids[grid_index] =
+ (CCGElem *)&subdiv_ccg->grids_storage[grid_offset];
+ }
+ /* Grid material flags. */
+ subdiv_ccg->grid_flag_mats = MEM_calloc_arrayN(
+ num_grids, sizeof(DMFlagMat), "ccg grid material flags");
+ /* Grid hidden flags. */
+ subdiv_ccg->grid_hidden = MEM_calloc_arrayN(
+ num_grids, sizeof(BLI_bitmap *), "ccg grid material flags");
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ subdiv_ccg->grid_hidden[grid_index] =
+ BLI_BITMAP_NEW(grid_area, "ccg grid hidden");
+ }
+ /* TODO(sergey): Allocate memory for loose elements. */
+ /* Allocate memory for faces. */
+ subdiv_ccg->num_faces = num_faces;
+ if (num_faces) {
+ subdiv_ccg->faces = MEM_calloc_arrayN(
+ num_faces, sizeof(SubdivCCGFace), "Subdiv CCG faces");
+ subdiv_ccg->grid_faces = MEM_calloc_arrayN(
+ num_grids, sizeof(SubdivCCGFace *), "Subdiv CCG grid faces");
+ }
+}
+
+/* =============================================================================
+ * Grids evaluation.
+ */
+
+typedef struct CCGEvalGridsData {
+ SubdivCCG *subdiv_ccg;
+ Subdiv *subdiv;
+ int *face_ptex_offset;
+ SubdivCCGMask *mask_evaluator;
+} CCGEvalGridsData;
+
+static void subdiv_ccg_eval_grid_element(
+ CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u, const float v,
+ unsigned char *element)
+{
+ Subdiv *subdiv = data->subdiv;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ if (subdiv->displacement_evaluator != NULL) {
+ BKE_subdiv_eval_final_point(
+ subdiv, ptex_face_index, u, v, (float *)element);
+ }
+ else if (subdiv_ccg->has_normal) {
+ BKE_subdiv_eval_limit_point_and_normal(
+ subdiv, ptex_face_index, u, v,
+ (float *)element,
+ (float *)(element + subdiv_ccg->normal_offset));
+ }
+ else {
+ BKE_subdiv_eval_limit_point(
+ subdiv, ptex_face_index, u, v, (float *)element);
+ }
+ if (subdiv_ccg->has_mask) {
+ float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
+ if (data->mask_evaluator != NULL) {
+ *mask_value_ptr = data->mask_evaluator->eval_mask(
+ data->mask_evaluator, ptex_face_index, u, v);
+ }
+ else {
+ *mask_value_ptr = 0.0f;
+ }
+ }
+}
+
+BLI_INLINE void rotate_corner_to_quad(
+ const int corner,
+ const float u, const float v,
+ float *r_u, float *r_v)
+{
+ if (corner == 0) {
+ *r_u = 0.5f - v * 0.5f;
+ *r_v = 0.5f - u * 0.5f;
+ }
+ else if (corner == 1) {
+ *r_u = 0.5f + u * 0.5f;
+ *r_v = 0.5f - v * 0.5f;
+ }
+ else if (corner == 2) {
+ *r_u = 0.5f + v * 0.5f;
+ *r_v = 0.5f + u * 0.5f;
+ }
+ else {
+ BLI_assert(corner == 3);
+ *r_u = 0.5f - u * 0.5f;
+ *r_v = 0.5f + v * 0.5f;
+ }
+}
+
+static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data,
+ const int face_index)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ const int ptex_face_index = data->face_ptex_offset[face_index];
+ const int grid_size = subdiv_ccg->grid_size;
+ const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
+ const SubdivCCGFace *face = &faces[face_index];
+ for (int corner = 0; corner < face->num_grids; corner++) {
+ const int grid_index = face->start_grid_index + corner;
+ unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
+ for (int y = 0; y < grid_size; y++) {
+ const float grid_v = (float)y * grid_size_1_inv;
+ for (int x = 0; x < grid_size; x++) {
+ const float grid_u = (float)x * grid_size_1_inv;
+ float u, v;
+ rotate_corner_to_quad(corner, grid_u, grid_v, &u, &v);
+ const size_t grid_element_index = (size_t)y * grid_size + x;
+ const size_t grid_element_offset =
+ grid_element_index * element_size;
+ subdiv_ccg_eval_grid_element(
+ data,
+ ptex_face_index, u, v,
+ &grid[grid_element_offset]);
+ }
+ }
+ /* Assign grid's face. */
+ grid_faces[grid_index] = &faces[face_index];
+ }
+}
+
+static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data,
+ const int face_index)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ const int grid_size = subdiv_ccg->grid_size;
+ const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
+ const SubdivCCGFace *face = &faces[face_index];
+ for (int corner = 0; corner < face->num_grids; corner++) {
+ const int grid_index = face->start_grid_index + corner;
+ unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
+ for (int y = 0; y < grid_size; y++) {
+ const float u = 1.0f - ((float)y * grid_size_1_inv);
+ for (int x = 0; x < grid_size; x++) {
+ const float v = 1.0f - ((float)x * grid_size_1_inv);
+ const int ptex_face_index =
+ data->face_ptex_offset[face_index] + corner;
+ const size_t grid_element_index = (size_t)y * grid_size + x;
+ const size_t grid_element_offset =
+ grid_element_index * element_size;
+ subdiv_ccg_eval_grid_element(
+ data,
+ ptex_face_index, u, v,
+ &grid[grid_element_offset]);
+ }
+ }
+ /* Assign grid's face. */
+ grid_faces[grid_index] = &faces[face_index];
+ }
+}
+
+static void subdiv_ccg_eval_grids_task(
+ void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ CCGEvalGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ SubdivCCGFace *face = &subdiv_ccg->faces[face_index];
+ if (face->num_grids == 4) {
+ subdiv_ccg_eval_regular_grid(data, face_index);
+ }
+ else {
+ subdiv_ccg_eval_special_grid(data, face_index);
+ }
+}
+
+static bool subdiv_ccg_evaluate_grids(
+ SubdivCCG *subdiv_ccg,
+ Subdiv *subdiv,
+ SubdivCCGMask *mask_evaluator)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ /* Initialize data passed to all the tasks. */
+ CCGEvalGridsData data;
+ data.subdiv_ccg = subdiv_ccg;
+ data.subdiv = subdiv;
+ data.face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+ data.mask_evaluator = mask_evaluator;
+ /* Threaded grids evaluation. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(0, num_faces,
+ &data,
+ subdiv_ccg_eval_grids_task,
+ &parallel_range_settings);
+ /* If displacement is used, need to calculate normals after all final
+ * coordinates are known.
+ */
+ if (subdiv->displacement_evaluator != NULL) {
+ BKE_subdiv_ccg_recalc_normals(subdiv_ccg);
+ }
+ return true;
+}
+
+/* Initialize face descriptors, assuming memory for them was already
+ * allocated.
+ */
+static void subdiv_ccg_init_faces(SubdivCCG *subdiv_ccg)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_faces = subdiv_ccg->num_faces;
+ int corner_index = 0;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ const int num_corners = topology_refiner->getNumFaceVertices(
+ topology_refiner, face_index);
+ subdiv_ccg->faces[face_index].num_grids = num_corners;
+ subdiv_ccg->faces[face_index].start_grid_index = corner_index;
+ corner_index += num_corners;
+ }
+}
+
+/* TODO(sergey): Consider making it generic enough to be fit into BLI. */
+typedef struct StaticOrHeapIntStorage {
+ int static_storage[64];
+ int static_storage_size;
+ int *heap_storage;
+ int heap_storage_size;
+} StaticOrHeapIntStorage;
+
+static void static_or_heap_storage_init(StaticOrHeapIntStorage *storage)
+{
+ storage->static_storage_size =
+ sizeof(storage->static_storage) / sizeof(*storage->static_storage);
+ storage->heap_storage = NULL;
+ storage->heap_storage_size = 0;
+}
+
+static int *static_or_heap_storage_get(StaticOrHeapIntStorage *storage,
+ int size)
+{
+ /* Requested size small enough to be fit into stack allocated memory. */
+ if (size <= storage->static_storage_size) {
+ return storage->static_storage;
+ }
+ /* Make sure heap ius big enough. */
+ if (size > storage->heap_storage_size) {
+ MEM_SAFE_FREE(storage->heap_storage);
+ storage->heap_storage = MEM_malloc_arrayN(
+ size, sizeof(int), "int storage");
+ storage->heap_storage_size = size;
+ }
+ return storage->heap_storage;
+}
+
+static void static_or_heap_storage_free(StaticOrHeapIntStorage *storage)
+{
+ MEM_SAFE_FREE(storage->heap_storage);
+}
+
+static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG *subdiv_ccg,
+ const int num_edges)
+{
+ subdiv_ccg->num_adjacent_edges = num_edges;
+ subdiv_ccg->adjacent_edges = MEM_calloc_arrayN(
+ subdiv_ccg->num_adjacent_edges,
+ sizeof(*subdiv_ccg->adjacent_edges),
+ "ccg adjacent edges");
+}
+
+/* Returns storage where boundary elements are to be stored. */
+static CCGElem **subdiv_ccg_adjacent_edge_add_face(
+ SubdivCCG *subdiv_ccg,
+ SubdivCCGAdjacentEdge *adjacent_edge,
+ SubdivCCGFace *face)
+{
+ const int grid_size = subdiv_ccg->grid_size * 2;
+ const int adjacent_face_index = adjacent_edge->num_adjacent_faces;
+ ++adjacent_edge->num_adjacent_faces;
+ /* Store new adjacent face. */
+ adjacent_edge->faces = MEM_reallocN(
+ adjacent_edge->faces,
+ adjacent_edge->num_adjacent_faces * sizeof(*adjacent_edge->faces));
+ adjacent_edge->faces[adjacent_face_index] = face;
+ /* Allocate memory for the boundary elements. */
+ adjacent_edge->boundary_elements = MEM_reallocN(
+ adjacent_edge->boundary_elements,
+ adjacent_edge->num_adjacent_faces *
+ sizeof(*adjacent_edge->boundary_elements));
+ adjacent_edge->boundary_elements[adjacent_face_index] =
+ MEM_malloc_arrayN(
+ grid_size * 2, sizeof(CCGElem *), "ccg adjacent boundary");
+ return adjacent_edge->boundary_elements[adjacent_face_index];
+}
+
+static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_edges = topology_refiner->getNumEdges(topology_refiner);
+ const int grid_size = subdiv_ccg->grid_size;
+ if (num_edges == 0) {
+ /* Early output, nothing to do in this case. */
+ return;
+ }
+ subdiv_ccg_allocate_adjacent_edges(subdiv_ccg, num_edges);
+ /* Initialize storage. */
+ StaticOrHeapIntStorage face_vertices_storage;
+ StaticOrHeapIntStorage face_edges_storage;
+ static_or_heap_storage_init(&face_vertices_storage);
+ static_or_heap_storage_init(&face_edges_storage);
+ /* Key to access elements. */
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Store adjacency for all faces. */
+ const int num_faces = subdiv_ccg->num_faces;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ SubdivCCGFace *face = &faces[face_index];
+ const int num_face_grids = face->num_grids;
+ const int num_face_edges = num_face_grids;
+ int *face_vertices = static_or_heap_storage_get(
+ &face_vertices_storage, num_face_edges);
+ topology_refiner->getFaceVertices(
+ topology_refiner, face_index, face_vertices);
+ /* Note that order of edges is same as order of MLoops, which also
+ * means it's the same as order of grids.
+ */
+ int *face_edges = static_or_heap_storage_get(
+ &face_edges_storage, num_face_edges);
+ topology_refiner->getFaceEdges(
+ topology_refiner, face_index, face_edges);
+ /* Store grids adjacency for this edge. */
+ for (int corner = 0; corner < num_face_edges; corner++) {
+ const int vertex_index = face_vertices[corner];
+ const int edge_index = face_edges[corner];
+ int edge_vertices[2];
+ topology_refiner->getEdgeVertices(
+ topology_refiner, edge_index, edge_vertices);
+ const bool is_edge_flipped = (edge_vertices[0] != vertex_index);
+ /* Grid which is adjacent to the current corner. */
+ const int current_grid_index = face->start_grid_index + corner;
+ CCGElem *current_grid = subdiv_ccg->grids[current_grid_index];
+ /* Grid which is adjacent to the next corner. */
+ const int next_grid_index =
+ face->start_grid_index + (corner + 1) % num_face_grids;
+ CCGElem *next_grid = subdiv_ccg->grids[next_grid_index];
+ /* Add new face to the adjacent edge. */
+ SubdivCCGAdjacentEdge *adjacent_edge =
+ &subdiv_ccg->adjacent_edges[edge_index];
+ CCGElem **boundary_elements = subdiv_ccg_adjacent_edge_add_face(
+ subdiv_ccg, adjacent_edge, face);
+ /* Fill CCG elements along the edge. */
+ int boundary_element_index = 0;
+ if (is_edge_flipped) {
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] =
+ CCG_grid_elem(&key,
+ next_grid,
+ grid_size - i - 1,
+ grid_size - 1);
+ }
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] =
+ CCG_grid_elem(&key,
+ current_grid,
+ grid_size - 1,
+ i);
+ }
+ }
+ else {
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] =
+ CCG_grid_elem(&key,
+ current_grid,
+ grid_size - 1,
+ grid_size - i - 1);
+ }
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] =
+ CCG_grid_elem(&key,
+ next_grid,
+ i,
+ grid_size - 1);
+ }
+ }
+ }
+ }
+ /* Free possibly heap-allocated storage. */
+ static_or_heap_storage_free(&face_vertices_storage);
+ static_or_heap_storage_free(&face_edges_storage);
+}
+
+static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG *subdiv_ccg,
+ const int num_vertices)
+{
+ subdiv_ccg->num_adjacent_vertices = num_vertices;
+ subdiv_ccg->adjacent_vertices = MEM_calloc_arrayN(
+ subdiv_ccg->num_adjacent_vertices,
+ sizeof(*subdiv_ccg->adjacent_vertices),
+ "ccg adjacent vertices");
+}
+
+/* Returns storage where corner elements are to be stored. This is a pointer
+ * to the actual storage.
+ */
+static CCGElem **subdiv_ccg_adjacent_vertex_add_face(
+ SubdivCCGAdjacentVertex *adjacent_vertex,
+ SubdivCCGFace *face)
+{
+ const int adjacent_face_index = adjacent_vertex->num_adjacent_faces;
+ ++adjacent_vertex->num_adjacent_faces;
+ /* Store new adjacent face. */
+ adjacent_vertex->faces = MEM_reallocN(
+ adjacent_vertex->faces,
+ adjacent_vertex->num_adjacent_faces *
+ sizeof(*adjacent_vertex->faces));
+ adjacent_vertex->faces[adjacent_face_index] = face;
+ /* Allocate memory for the boundary elements. */
+ adjacent_vertex->corner_elements = MEM_reallocN(
+ adjacent_vertex->corner_elements,
+ adjacent_vertex->num_adjacent_faces *
+ sizeof(*adjacent_vertex->corner_elements));
+ return &adjacent_vertex->corner_elements[adjacent_face_index];
+}
+
+static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_vertices =
+ topology_refiner->getNumVertices(topology_refiner);
+ const int grid_size = subdiv_ccg->grid_size;
+ if (num_vertices == 0) {
+ /* Early output, nothing to do in this case. */
+ return;
+ }
+ subdiv_ccg_allocate_adjacent_vertices(subdiv_ccg, num_vertices);
+ /* Initialize storage. */
+ StaticOrHeapIntStorage face_vertices_storage;
+ static_or_heap_storage_init(&face_vertices_storage);
+ /* Key to access elements. */
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Store adjacency for all faces. */
+ const int num_faces = subdiv_ccg->num_faces;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ SubdivCCGFace *face = &faces[face_index];
+ const int num_face_grids = face->num_grids;
+ const int num_face_edges = num_face_grids;
+ int *face_vertices = static_or_heap_storage_get(
+ &face_vertices_storage, num_face_edges);
+ topology_refiner->getFaceVertices(
+ topology_refiner, face_index, face_vertices);
+ for (int corner = 0; corner < num_face_edges; corner++) {
+ const int vertex_index = face_vertices[corner];
+ /* Grid which is adjacent to the current corner. */
+ const int grid_index = face->start_grid_index + corner;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ /* Add new face to the adjacent edge. */
+ SubdivCCGAdjacentVertex *adjacent_vertex =
+ &subdiv_ccg->adjacent_vertices[vertex_index];
+ CCGElem **corner_element = subdiv_ccg_adjacent_vertex_add_face(
+ adjacent_vertex, face);
+ *corner_element = CCG_grid_elem(
+ &key, grid, grid_size - 1, grid_size - 1);
+ }
+ }
+ /* Free possibly heap-allocated storage. */
+ static_or_heap_storage_free(&face_vertices_storage);
+}
+
+static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg)
+{
+ subdiv_ccg_init_faces_edge_neighborhood(subdiv_ccg);
+ subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg);
+}
+
+/* =============================================================================
+ * Creation / evaluation.
+ */
+
+SubdivCCG *BKE_subdiv_to_ccg(
+ Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ SubdivCCGMask *mask_evaluator)
+{
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg");
+ subdiv_ccg->subdiv = subdiv;
+ subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1);
+ subdiv_ccg->grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
+ subdiv_ccg_init_layers(subdiv_ccg, settings);
+ subdiv_ccg_alloc_elements(subdiv_ccg, subdiv);
+ subdiv_ccg_init_faces(subdiv_ccg);
+ subdiv_ccg_init_faces_neighborhood(subdiv_ccg);
+ if (!subdiv_ccg_evaluate_grids(subdiv_ccg, subdiv, mask_evaluator)) {
+ BKE_subdiv_ccg_destroy(subdiv_ccg);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ return NULL;
+ }
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ return subdiv_ccg;
+}
+
+Mesh *BKE_subdiv_to_ccg_mesh(
+ Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ const Mesh *coarse_mesh)
+{
+ /* Make sure evaluator is ready. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (coarse_mesh->totpoly) {
+ return false;
+ }
+ }
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ SubdivCCGMask mask_evaluator;
+ bool has_mask = BKE_subdiv_ccg_mask_init_from_paint(
+ &mask_evaluator, coarse_mesh);
+ SubdivCCG *subdiv_ccg = BKE_subdiv_to_ccg(
+ subdiv, settings, has_mask ? &mask_evaluator : NULL);
+ if (has_mask) {
+ mask_evaluator.free(&mask_evaluator);
+ }
+ if (subdiv_ccg == NULL) {
+ return NULL;
+ }
+ Mesh *result = BKE_mesh_new_nomain_from_template(
+ coarse_mesh, 0, 0, 0, 0, 0);
+ result->runtime.subdiv_ccg = subdiv_ccg;
+ return result;
+}
+
+void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
+{
+ const int num_grids = subdiv_ccg->num_grids;
+ MEM_SAFE_FREE(subdiv_ccg->grids);
+ MEM_SAFE_FREE(subdiv_ccg->grids_storage);
+ MEM_SAFE_FREE(subdiv_ccg->edges);
+ MEM_SAFE_FREE(subdiv_ccg->vertices);
+ MEM_SAFE_FREE(subdiv_ccg->grid_flag_mats);
+ if (subdiv_ccg->grid_hidden != NULL) {
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ MEM_freeN(subdiv_ccg->grid_hidden[grid_index]);
+ }
+ MEM_freeN(subdiv_ccg->grid_hidden);
+ }
+ if (subdiv_ccg->subdiv != NULL) {
+ BKE_subdiv_free(subdiv_ccg->subdiv);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->faces);
+ MEM_SAFE_FREE(subdiv_ccg->grid_faces);
+ /* Free map of adjacent edges. */
+ for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) {
+ SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i];
+ for (int face_index = 0;
+ face_index < adjacent_edge->num_adjacent_faces;
+ face_index++)
+ {
+ MEM_SAFE_FREE(adjacent_edge->boundary_elements[face_index]);
+ }
+ MEM_SAFE_FREE(adjacent_edge->faces);
+ MEM_SAFE_FREE(adjacent_edge->boundary_elements);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->adjacent_edges);
+ /* Free map of adjacent vertices. */
+ for (int i = 0; i < subdiv_ccg->num_adjacent_vertices; i++) {
+ SubdivCCGAdjacentVertex *adjacent_vertex =
+ &subdiv_ccg->adjacent_vertices[i];
+ MEM_SAFE_FREE(adjacent_vertex->faces);
+ MEM_SAFE_FREE(adjacent_vertex->corner_elements);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices);
+ MEM_freeN(subdiv_ccg);
+}
+
+void BKE_subdiv_ccg_key(CCGKey *key, const SubdivCCG *subdiv_ccg, int level)
+{
+ key->level = level;
+ key->elem_size = element_size_bytes_get(subdiv_ccg);
+ key->grid_size = BKE_subdiv_grid_size_from_level(level);
+ key->grid_area = key->grid_size * key->grid_size;
+ key->grid_bytes = key->elem_size * key->grid_area;
+
+ key->normal_offset = subdiv_ccg->normal_offset;
+ key->mask_offset = subdiv_ccg->mask_offset;
+
+ key->has_normals = subdiv_ccg->has_normal;
+ key->has_mask = subdiv_ccg->has_mask;
+}
+
+void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg)
+{
+ BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level);
+}
+
+/* =============================================================================
+ * Normals.
+ */
+
+typedef struct RecalcInnerNormalsData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+} RecalcInnerNormalsData;
+
+typedef struct RecalcInnerNormalsTLSData {
+ float (*face_normals)[3];
+} RecalcInnerNormalsTLSData;
+
+/* Evaluate high-res face normals, for faces which corresponds to grid elements
+ *
+ * {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}}
+ *
+ * The result is stored in normals storage from TLS.
+ */
+static void subdiv_ccg_recalc_inner_face_normals(
+ RecalcInnerNormalsData *data,
+ RecalcInnerNormalsTLSData *tls,
+ const int grid_index)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ const int grid_size = subdiv_ccg->grid_size;
+ const int grid_size_1 = grid_size - 1;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ if (tls->face_normals == NULL) {
+ tls->face_normals = MEM_malloc_arrayN(
+ grid_size_1 * grid_size_1,
+ 3 * sizeof(float),
+ "CCG TLS normals");
+ }
+ for (int y = 0; y < grid_size -1; y++) {
+ for (int x = 0; x < grid_size - 1; x++) {
+ CCGElem *grid_elements[4] = {
+ CCG_grid_elem(key, grid, x, y + 1),
+ CCG_grid_elem(key, grid, x + 1, y + 1),
+ CCG_grid_elem(key, grid, x + 1, y),
+ CCG_grid_elem(key, grid, x, y)
+ };
+ float *co[4] = {
+ CCG_elem_co(key, grid_elements[0]),
+ CCG_elem_co(key, grid_elements[1]),
+ CCG_elem_co(key, grid_elements[2]),
+ CCG_elem_co(key, grid_elements[3])
+ };
+ const int face_index = y * grid_size_1 + x;
+ float *face_normal = tls->face_normals[face_index];
+ normal_quad_v3(face_normal, co[0], co[1], co[2], co[3]);
+ }
+ }
+}
+
+/* Average normals at every grid element, using adjacent faces normals. */
+static void subdiv_ccg_average_inner_face_normals(
+ RecalcInnerNormalsData *data,
+ RecalcInnerNormalsTLSData *tls,
+ const int grid_index)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ const int grid_size = subdiv_ccg->grid_size;
+ const int grid_size_1 = grid_size - 1;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ const float (*face_normals)[3] = tls->face_normals;
+ for (int y = 0; y < grid_size; y++) {
+ for (int x = 0; x < grid_size; x++) {
+ float normal_acc[3] = {0.0f, 0.0f, 0.0f};
+ int counter = 0;
+ /* Accumulate normals of all adjacent faces. */
+ if (x < grid_size_1 && y < grid_size_1) {
+ add_v3_v3(normal_acc, face_normals[y * grid_size_1 + x]);
+ counter++;
+ }
+ if (x >= 1) {
+ if (y < grid_size_1) {
+ add_v3_v3(normal_acc,
+ face_normals[y * grid_size_1 + (x - 1)]);
+ counter++;
+ }
+ if (y >= 1) {
+ add_v3_v3(normal_acc,
+ face_normals[(y - 1) * grid_size_1 + (x - 1)]);
+ counter++;
+ }
+ }
+ if (y >= 1 && x < grid_size_1) {
+ add_v3_v3(normal_acc, face_normals[(y - 1) * grid_size_1 + x]);
+ counter++;
+ }
+ /* Normalize and store. */
+ mul_v3_v3fl(CCG_grid_elem_no(key, grid, x, y),
+ normal_acc,
+ 1.0f / (float)counter);
+ }
+ }
+}
+
+static void subdiv_ccg_recalc_inner_normal_task(
+ void *__restrict userdata_v,
+ const int grid_index,
+ const ParallelRangeTLS *__restrict tls_v)
+{
+ RecalcInnerNormalsData *data = userdata_v;
+ RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk;
+ subdiv_ccg_recalc_inner_face_normals(data, tls, grid_index);
+ subdiv_ccg_average_inner_face_normals(data, tls, grid_index);
+}
+
+static void subdiv_ccg_recalc_inner_normal_finalize(
+ void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
+{
+ RecalcInnerNormalsTLSData *tls = tls_v;
+ MEM_SAFE_FREE(tls->face_normals);
+}
+
+/* Recalculate normals which corresponds to non-boundaries elements of grids. */
+static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ RecalcInnerNormalsData data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key
+ };
+ RecalcInnerNormalsTLSData tls_data = {NULL};
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.userdata_chunk = &tls_data;
+ parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
+ parallel_range_settings.func_finalize =
+ subdiv_ccg_recalc_inner_normal_finalize;
+ BLI_task_parallel_range(0, subdiv_ccg->num_grids,
+ &data,
+ subdiv_ccg_recalc_inner_normal_task,
+ &parallel_range_settings);
+}
+
+void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg)
+{
+ if (!subdiv_ccg->has_normal) {
+ /* Grids don't have normals, can do early output. */
+ return;
+ }
+ subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg);
+ BKE_subdiv_ccg_average_grids(subdiv_ccg);
+}
+
+/* =============================================================================
+ * Boundary averaging/stitching.
+ */
+
+typedef struct AverageInnerGridsData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+} AverageInnerGridsData;
+
+static void average_grid_element_value_v3(float a[3], float b[3])
+{
+ add_v3_v3(a, b);
+ mul_v3_fl(a, 0.5f);
+ copy_v3_v3(b, a);
+}
+
+static void average_grid_element(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ CCGElem *grid_element_a,
+ CCGElem *grid_element_b)
+{
+ average_grid_element_value_v3(CCG_elem_co(key, grid_element_a),
+ CCG_elem_co(key, grid_element_b));
+ if (subdiv_ccg->has_normal) {
+ average_grid_element_value_v3(CCG_elem_no(key, grid_element_a),
+ CCG_elem_no(key, grid_element_b));
+ }
+ if (subdiv_ccg->has_mask) {
+ float mask =
+ (*CCG_elem_mask(key, grid_element_a) +
+ *CCG_elem_mask(key, grid_element_b)) * 0.5f;
+ *CCG_elem_mask(key, grid_element_a) = mask;
+ *CCG_elem_mask(key, grid_element_b) = mask;
+ }
+}
+
+static void copy_grid_element(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ CCGElem *destination,
+ CCGElem *source)
+{
+ copy_v3_v3(CCG_elem_co(key, destination), CCG_elem_co(key, source));
+ if (subdiv_ccg->has_normal) {
+ copy_v3_v3(CCG_elem_no(key, destination), CCG_elem_no(key, source));
+ }
+ if (subdiv_ccg->has_mask) {
+ *CCG_elem_mask(key, destination) = *CCG_elem_mask(key, source);
+ }
+}
+
+static void subdiv_ccg_average_inner_face_grids(
+ SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGFace *face)
+{
+ CCGElem **grids = subdiv_ccg->grids;
+ const int num_face_grids = face->num_grids;
+ const int grid_size = subdiv_ccg->grid_size;
+ CCGElem *prev_grid = grids[face->start_grid_index + num_face_grids - 1];
+ for (int corner = 0; corner < num_face_grids; corner++) {
+ CCGElem *grid = grids[face->start_grid_index + corner];
+ for (int i = 0; i < grid_size; i++) {
+ CCGElem *prev_grid_element = CCG_grid_elem(key, prev_grid, i, 0);
+ CCGElem *grid_element = CCG_grid_elem(key, grid, 0, i);
+ average_grid_element(
+ subdiv_ccg, key, prev_grid_element, grid_element);
+ }
+ prev_grid = grid;
+ }
+
+}
+
+static void subdiv_ccg_average_inner_grids_task(
+ void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
+{
+ AverageInnerGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace *face = &faces[face_index];
+ subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
+}
+
+typedef struct AverageGridsBoundariesData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+} AverageGridsBoundariesData;
+
+static void subdiv_ccg_average_grids_boundary(
+ SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGAdjacentEdge *adjacent_edge)
+{
+ const int num_adjacent_faces = adjacent_edge->num_adjacent_faces;
+ const int grid_size2 = subdiv_ccg->grid_size * 2;
+ if (num_adjacent_faces == 1) {
+ /* Nothing to average with. */
+ return;
+ }
+ /* Incrementall average result to elements of a first adjacent face.
+ *
+ * Arguably, this is less precise than accumulating and then diving once,
+ * but on another hand this is more stable when coordinates are big.
+ */
+ for (int face_index = 1; face_index < num_adjacent_faces; face_index++) {
+ /* NOTE: We ignore very first and very last elements, they correspond
+ * to corner vertices, and they can belong to multiple edges.
+ * The fact, that they can belong to multiple edges means we can't
+ * safely average them.
+ * The fact, that they correspond to a corner elements, means they will
+ * be handled at the upcoming pass over corner elements.
+ */
+ for (int i = 1; i < grid_size2 - 1; i++) {
+ CCGElem *grid_element_0 =
+ adjacent_edge->boundary_elements[0][i];
+ CCGElem *grid_element_face_index =
+ adjacent_edge->boundary_elements[face_index][i];
+ average_grid_element(subdiv_ccg,
+ key,
+ grid_element_0,
+ grid_element_face_index);
+ }
+ }
+ /* Copy averaged value to all the other faces. */
+ for (int face_index = 1; face_index < num_adjacent_faces; face_index++) {
+ for (int i = 1; i < grid_size2 -1; i++) {
+ CCGElem *grid_element_0 =
+ adjacent_edge->boundary_elements[0][i];
+ CCGElem *grid_element_face_index =
+ adjacent_edge->boundary_elements[face_index][i];
+ copy_grid_element(subdiv_ccg,
+ key,
+ grid_element_face_index,
+ grid_element_0);
+ }
+ }
+}
+
+static void subdiv_ccg_average_grids_boundaries_task(
+ void *__restrict userdata_v,
+ const int adjacent_edge_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
+{
+ AverageGridsBoundariesData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGAdjacentEdge *adjacent_edge =
+ &subdiv_ccg->adjacent_edges[adjacent_edge_index];
+ subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge);
+}
+
+typedef struct AverageGridsCornerData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+} AverageGridsCornerData;
+
+static void subdiv_ccg_average_grids_corners(
+ SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGAdjacentVertex *adjacent_vertex)
+{
+ const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces;
+ if (num_adjacent_faces == 1) {
+ /* Nothing to average with. */
+ return;
+ }
+ /* Incrementall average result to elements of a first adjacent face.
+ * See comment to the boundary averaging.
+ */
+ for (int face_index = 1; face_index < num_adjacent_faces; face_index++) {
+ CCGElem *grid_element_0 =
+ adjacent_vertex->corner_elements[0];
+ CCGElem *grid_element_face_index =
+ adjacent_vertex->corner_elements[face_index];
+ average_grid_element(subdiv_ccg,
+ key,
+ grid_element_0,
+ grid_element_face_index);
+ }
+ /* Copy averaged value to all the other faces. */
+ for (int face_index = 1; face_index < num_adjacent_faces; face_index++) {
+ CCGElem *grid_element_0 =
+ adjacent_vertex->corner_elements[0];
+ CCGElem *grid_element_face_index =
+ adjacent_vertex->corner_elements[face_index];
+ copy_grid_element(subdiv_ccg,
+ key,
+ grid_element_face_index,
+ grid_element_0);
+ }
+}
+
+static void subdiv_ccg_average_grids_corners_task(
+ void *__restrict userdata_v,
+ const int adjacent_vertex_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
+{
+ AverageGridsCornerData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGAdjacentVertex *adjacent_vertex =
+ &subdiv_ccg->adjacent_vertices[adjacent_vertex_index];
+ subdiv_ccg_average_grids_corners(subdiv_ccg, key, adjacent_vertex);
+}
+
+static void subdiv_ccg_average_all_boundaries_and_corners(
+ SubdivCCG *subdiv_ccg,
+ CCGKey *key)
+{
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ /* Average grids across coarse edges. */
+ AverageGridsBoundariesData boundaries_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = key,
+ };
+ BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_edges,
+ &boundaries_data,
+ subdiv_ccg_average_grids_boundaries_task,
+ &parallel_range_settings);
+ /* Average grids at coarse vertices. */
+ AverageGridsCornerData corner_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = key,
+ };
+ BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_vertices,
+ &corner_data,
+ subdiv_ccg_average_grids_corners_task,
+ &parallel_range_settings);
+}
+
+void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ /* Average inner boundaries of grids (within one face), across faces
+ * from different face-corners.
+ */
+ AverageInnerGridsData inner_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key,
+ };
+ BLI_task_parallel_range(0, subdiv_ccg->num_faces,
+ &inner_data,
+ subdiv_ccg_average_inner_grids_task,
+ &parallel_range_settings);
+ subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
+}
+
+typedef struct StitchFacesInnerGridsData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+ struct CCGFace **effected_ccg_faces;
+} StitchFacesInnerGridsData;
+
+static void subdiv_ccg_stitch_face_inner_grids_task(
+ void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
+{
+ StitchFacesInnerGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ struct CCGFace **effected_ccg_faces = data->effected_ccg_faces;
+ struct CCGFace *effected_ccg_face = effected_ccg_faces[face_index];
+ SubdivCCGFace *face = (SubdivCCGFace *)effected_ccg_face;
+ subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
+}
+
+void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG *subdiv_ccg,
+ struct CCGFace **effected_faces,
+ int num_effected_faces)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ StitchFacesInnerGridsData data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key,
+ .effected_ccg_faces = effected_faces,
+ };
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(0, num_effected_faces,
+ &data,
+ subdiv_ccg_stitch_face_inner_grids_task,
+ &parallel_range_settings);
+ /* TODO(sergey): Only average elements which are adjacent to modified
+ * faces.
+ */
+ subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
+}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg_mask.c b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
new file mode 100644
index 00000000000..0da30fb1bf0
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_ccg_mask.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.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_ccg_mask.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_ccg.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_subdiv.h"
+
+#include "MEM_guardedalloc.h"
+
+typedef struct PolyCornerIndex {
+ int poly_index;
+ int corner;
+} PolyCornerIndex;
+
+typedef struct GridPaintMaskData {
+ // int grid_size;
+ const MPoly *mpoly;
+ const GridPaintMask *grid_paint_mask;
+ /* Indexed by ptex face index, contains polygon/corner which corresponds
+ * to it.
+ *
+ * NOTE: For quad polygon this is an index of first corner only, since
+ * there we only have one ptex.
+ */
+ PolyCornerIndex *ptex_poly_corner;
+} GridPaintMaskData;
+
+static int mask_get_grid_and_coord(
+ SubdivCCGMask *mask_evaluator,
+ const int ptex_face_index, const float u, const float v,
+ const GridPaintMask **r_mask_grid,
+ float *grid_u, float *grid_v)
+{
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int start_grid_index = poly->loopstart + poly_corner->corner;
+ int corner = 0;
+ if (poly->totloop == 4) {
+ float corner_u, corner_v;
+ corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
+ *r_mask_grid =
+ &data->grid_paint_mask[start_grid_index + corner];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
+ }
+ else {
+ *r_mask_grid =
+ &data->grid_paint_mask[start_grid_index];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
+ }
+ return corner;
+}
+
+BLI_INLINE float read_mask_grid(const GridPaintMask *mask_grid,
+ const float grid_u, const float grid_v)
+{
+ if (mask_grid->data == NULL) {
+ return 0;
+ }
+ const int grid_size = BKE_subdiv_grid_size_from_level(mask_grid->level);
+ const int x = (grid_u * (grid_size - 1) + 0.5f);
+ const int y = (grid_v * (grid_size - 1) + 0.5f);
+ return mask_grid->data[y * grid_size + x];
+}
+
+static float eval_mask(SubdivCCGMask *mask_evaluator,
+ const int ptex_face_index,
+ const float u, const float v)
+{
+ const GridPaintMask *mask_grid;
+ float grid_u, grid_v;
+ mask_get_grid_and_coord(mask_evaluator,
+ ptex_face_index, u, v,
+ &mask_grid,
+ &grid_u, &grid_v);
+ return read_mask_grid(mask_grid, grid_u, grid_v);
+}
+
+static void free_mask_data(SubdivCCGMask *mask_evaluator)
+{
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ MEM_freeN(data->ptex_poly_corner);
+ MEM_freeN(data);
+}
+
+/* TODO(sergey): This seems to be generally used information, which almost
+ * worth adding to a subdiv itself, with possible cache of the value.
+ */
+static int count_num_ptex_faces(const Mesh *mesh)
+{
+ int num_ptex_faces = 0;
+ const MPoly *mpoly = mesh->mpoly;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
+ }
+ return num_ptex_faces;
+}
+
+static void displacement_data_init_mapping(SubdivCCGMask *mask_evaluator,
+ const Mesh *mesh)
+{
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ const MPoly *mpoly = mesh->mpoly;
+ const int num_ptex_faces = count_num_ptex_faces(mesh);
+ /* Allocate memory. */
+ data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces,
+ sizeof(*data->ptex_poly_corner),
+ "ptex poly corner");
+ /* Fill in offsets. */
+ int ptex_face_index = 0;
+ PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ if (poly->totloop == 4) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = 0;
+ ptex_face_index++;
+ }
+ else {
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = corner;
+ ptex_face_index++;
+ }
+ }
+ }
+}
+
+static void displacement_init_data(SubdivCCGMask *mask_evaluator,
+ const Mesh *mesh)
+{
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ data->mpoly = mesh->mpoly;
+ data->grid_paint_mask =
+ CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ displacement_data_init_mapping(mask_evaluator, mesh);
+}
+
+static void displacement_init_functions(SubdivCCGMask *mask_evaluator)
+{
+ mask_evaluator->eval_mask = eval_mask;
+ mask_evaluator->free = free_mask_data;
+}
+
+bool BKE_subdiv_ccg_mask_init_from_paint(
+ SubdivCCGMask *mask_evaluator,
+ const struct Mesh *mesh)
+{
+ GridPaintMask *grid_paint_mask =
+ CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ if (grid_paint_mask == NULL) {
+ return false;
+ }
+ /* Allocate all required memory. */
+ mask_evaluator->user_data = MEM_callocN(sizeof(GridPaintMaskData),
+ "mask from grid data");
+ displacement_init_data(mask_evaluator, mesh);
+ displacement_init_functions(mask_evaluator);
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_converter.c b/source/blender/blenkernel/intern/subdiv_converter.c
new file mode 100644
index 00000000000..b3eab1565d7
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_converter.c
@@ -0,0 +1,77 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_converter.c
+ * \ingroup bke
+ */
+
+#include "subdiv_converter.h"
+
+#include "BLI_utildefines.h"
+
+#include "opensubdiv_converter_capi.h"
+
+void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter)
+{
+ if (converter->freeUserData) {
+ converter->freeUserData(converter);
+ }
+}
+
+int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
+ const SubdivSettings *settings)
+{
+ switch (settings->vtx_boundary_interpolation) {
+ case SUBDIV_VTX_BOUNDARY_NONE:
+ return OSD_VTX_BOUNDARY_NONE;
+ case SUBDIV_VTX_BOUNDARY_EDGE_ONLY:
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+ case SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER:
+ return OSD_VTX_BOUNDARY_EDGE_AND_CORNER;
+ }
+ BLI_assert(!"Unknown vtx boundary interpolation");
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+}
+
+/*OpenSubdiv_FVarLinearInterpolation*/ int
+BKE_subdiv_converter_fvar_linear_from_settings(const SubdivSettings *settings)
+{
+ switch (settings->fvar_linear_interpolation) {
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE:
+ return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES:
+ return OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL:
+ return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
+ }
+ BLI_assert(!"Unknown fvar linear interpolation");
+ return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_converter.h b/source/blender/blenkernel/intern/subdiv_converter.h
new file mode 100644
index 00000000000..17172bc29f7
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_converter.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) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __SUBDIV_CONVERTER_H__
+#define __SUBDIV_CONVERTER_H__
+
+/** \file blender/blenkernel/intern/subdiv_converter.h
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+/* NOTE: Was initially used to get proper enumerator types, but this makes
+ * it tricky to compile without OpenSubdiv.
+ */
+/* #include "opensubdiv_converter_capi.h" */
+
+struct Mesh;
+struct OpenSubdiv_Converter;
+struct SubdivSettings;
+
+void BKE_subdiv_converter_init_for_mesh(struct OpenSubdiv_Converter *converter,
+ const struct SubdivSettings *settings,
+ const struct Mesh *mesh);
+
+/* NOTE: Frees converter data, but not converter itself. This means, that if
+ * converter was allocated on heap, it is up to the user to free that memory.
+ */
+void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter);
+
+/* ============================ INTERNAL HELPERS ============================ */
+
+/* TODO(sergey): Find a way to make it OpenSubdiv_VtxBoundaryInterpolation,
+ * without breaking compilation without OpenSubdiv.
+ */
+int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
+ const SubdivSettings *settings);
+
+/* TODO(sergey): Find a way to make it OpenSubdiv_FVarLinearInterpolation,
+ * without breaking compilation without OpenSubdiv.
+ */
+int BKE_subdiv_converter_fvar_linear_from_settings(
+ const SubdivSettings *settings);
+
+#endif /* __SUBDIV_CONVERTER_H__ */
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
new file mode 100644
index 00000000000..5941de682f4
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -0,0 +1,410 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_converter_mesh.c
+ * \ingroup bke
+ */
+
+#include "subdiv_converter.h"
+
+#include <string.h>
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_subdiv.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_converter_capi.h"
+
+typedef struct ConverterStorage {
+ SubdivSettings settings;
+ const Mesh *mesh;
+ /* Indexed by loop index, value denotes index of face-varying vertex
+ * which corresponds to the UV coordinate.
+ */
+ int *loop_uv_indices;
+ int num_uv_coordinates;
+ /* Indexed by coarse mesh elements, gives index of corresponding element
+ * with ignoring all non-manifold entities.
+ *
+ * NOTE: This isn't strictly speaking manifold, this is more like non-loose
+ * geometry index. As in, index of element as if there were no loose edges
+ * or vertices in the mesh.
+ */
+ int *manifold_vertex_index;
+ /* Indexed by vertex index from mesh, corresponds to whether this vertex has
+ * infinite sharpness due to non-manifol topology.
+ */
+ BLI_bitmap *infinite_sharp_vertices_map;
+ /* Reverse mapping to above. */
+ int *manifold_vertex_index_reverse;
+ int *manifold_edge_index_reverse;
+ /* Number of non-loose elements. */
+ int num_manifold_vertices;
+ int num_manifold_edges;
+} ConverterStorage;
+
+static OpenSubdiv_SchemeType get_scheme_type(
+ const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ if (storage->settings.is_simple) {
+ return OSD_SCHEME_BILINEAR;
+ }
+ else {
+ return OSD_SCHEME_CATMARK;
+ }
+}
+
+static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation(
+ const struct OpenSubdiv_Converter *converter) {
+ ConverterStorage *storage = converter->user_data;
+ return BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
+ &storage->settings);
+}
+
+static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(
+ const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return BKE_subdiv_converter_fvar_linear_from_settings(&storage->settings);
+}
+
+static bool specifies_full_topology(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return false;
+}
+
+static int get_num_faces(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->mesh->totpoly;
+}
+
+static int get_num_edges(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_manifold_edges;
+}
+
+static int get_num_vertices(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_manifold_vertices;
+}
+
+static int get_num_face_vertices(const OpenSubdiv_Converter *converter,
+ int manifold_face_index)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->mesh->mpoly[manifold_face_index].totloop;
+}
+
+static void get_face_vertices(const OpenSubdiv_Converter *converter,
+ int manifold_face_index,
+ int *manifold_face_vertices)
+{
+ ConverterStorage *storage = converter->user_data;
+ const MPoly *poly = &storage->mesh->mpoly[manifold_face_index];
+ const MLoop *mloop = storage->mesh->mloop;
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ manifold_face_vertices[corner] = storage->manifold_vertex_index[
+ mloop[poly->loopstart + corner].v];
+ }
+}
+
+static void get_edge_vertices(const OpenSubdiv_Converter *converter,
+ int manifold_edge_index,
+ int *manifold_edge_vertices)
+{
+ ConverterStorage *storage = converter->user_data;
+ const int edge_index =
+ storage->manifold_edge_index_reverse[manifold_edge_index];
+ const MEdge *edge = &storage->mesh->medge[edge_index];
+ manifold_edge_vertices[0] = storage->manifold_vertex_index[edge->v1];
+ manifold_edge_vertices[1] = storage->manifold_vertex_index[edge->v2];
+}
+
+static float get_edge_sharpness(const OpenSubdiv_Converter *converter,
+ int manifold_edge_index)
+{
+ ConverterStorage *storage = converter->user_data;
+ const int edge_index =
+ storage->manifold_edge_index_reverse[manifold_edge_index];
+ const MEdge *medge = storage->mesh->medge;
+ const float edge_crease = (float)medge[edge_index].crease / 255.0f;
+ return edge_crease * edge_crease * 10.0f;
+}
+
+
+static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
+ int manifold_vertex_index)
+{
+ ConverterStorage *storage = converter->user_data;
+ const int vertex_index =
+ storage->manifold_vertex_index_reverse[manifold_vertex_index];
+ return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map,
+ vertex_index);
+}
+
+static float get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return 0.0f;
+}
+
+static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ const Mesh *mesh = storage->mesh;
+ return CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
+}
+
+static void precalc_uv_layer(const OpenSubdiv_Converter *converter,
+ const int layer_index)
+{
+ ConverterStorage *storage = converter->user_data;
+ const Mesh *mesh = storage->mesh;
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
+ const MLoopUV *mloopuv = CustomData_get_layer_n(
+ &mesh->ldata, CD_MLOOPUV, layer_index);
+ const int num_poly = mesh->totpoly;
+ const int num_vert = mesh->totvert;
+ const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+ /* Initialize memory required for the operations. */
+ if (storage->loop_uv_indices == NULL) {
+ storage->loop_uv_indices = MEM_malloc_arrayN(
+ mesh->totloop, sizeof(int), "loop uv vertex index");
+ }
+ UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
+ mpoly, mloop, mloopuv,
+ num_poly, num_vert,
+ limit,
+ false, true);
+ /* NOTE: First UV vertex is supposed to be always marked as separate. */
+ storage->num_uv_coordinates = -1;
+ for (int vertex_index = 0; vertex_index < num_vert; ++vertex_index) {
+ const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map,
+ vertex_index);
+ while (uv_vert != NULL) {
+ if (uv_vert->separate) {
+ storage->num_uv_coordinates++;
+ }
+ const MPoly *mp = &mpoly[uv_vert->poly_index];
+ const int global_loop_index = mp->loopstart +
+ uv_vert->loop_of_poly_index;
+ storage->loop_uv_indices[global_loop_index] =
+ storage->num_uv_coordinates;
+ uv_vert = uv_vert->next;
+ }
+ }
+ /* So far this value was used as a 0-based index, actual number of UV
+ * vertices is 1 more.
+ */
+ storage->num_uv_coordinates += 1;
+ BKE_mesh_uv_vert_map_free(uv_vert_map);
+}
+
+static void finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
+{
+}
+
+static int get_num_uvs(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_uv_coordinates;
+}
+
+static int get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
+ const int face_index,
+ const int corner)
+{
+ ConverterStorage *storage = converter->user_data;
+ const MPoly *mp = &storage->mesh->mpoly[face_index];
+ return storage->loop_uv_indices[mp->loopstart + corner];
+}
+
+static void free_user_data(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *user_data = converter->user_data;
+ MEM_SAFE_FREE(user_data->loop_uv_indices);
+ MEM_freeN(user_data->manifold_vertex_index);
+ MEM_freeN(user_data->infinite_sharp_vertices_map);
+ MEM_freeN(user_data->manifold_vertex_index_reverse);
+ MEM_freeN(user_data->manifold_edge_index_reverse);
+ MEM_freeN(user_data);
+}
+
+static void init_functions(OpenSubdiv_Converter *converter)
+{
+ converter->getSchemeType = get_scheme_type;
+ converter->getVtxBoundaryInterpolation = get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation = get_fvar_linear_interpolation;
+ converter->specifiesFullTopology = specifies_full_topology;
+
+ converter->getNumFaces = get_num_faces;
+ converter->getNumEdges = get_num_edges;
+ converter->getNumVertices = get_num_vertices;
+
+ converter->getNumFaceVertices = get_num_face_vertices;
+ converter->getFaceVertices = get_face_vertices;
+ converter->getFaceEdges = NULL;
+
+ converter->getEdgeVertices = get_edge_vertices;
+ converter->getNumEdgeFaces = NULL;
+ converter->getEdgeFaces = NULL;
+ converter->getEdgeSharpness = get_edge_sharpness;
+
+ converter->getNumVertexEdges = NULL;
+ converter->getVertexEdges = NULL;
+ converter->getNumVertexFaces = NULL;
+ converter->getVertexFaces = NULL;
+ converter->isInfiniteSharpVertex = is_infinite_sharp_vertex;
+ converter->getVertexSharpness = get_vertex_sharpness;
+
+ converter->getNumUVLayers = get_num_uv_layers;
+ converter->precalcUVLayer = precalc_uv_layer;
+ converter->finishUVLayer = finish_uv_layer;
+ converter->getNumUVCoordinates = get_num_uvs;
+ converter->getFaceCornerUVIndex = get_face_corner_uv_index;
+
+ converter->freeUserData = free_user_data;
+}
+
+static void initialize_manifold_index_array(const BLI_bitmap *used_map,
+ const int num_elements,
+ int **indices_r,
+ int **indices_reverse_r,
+ int *num_manifold_elements_r)
+{
+ int *indices = NULL;
+ if (indices_r != NULL) {
+ indices = MEM_malloc_arrayN(
+ num_elements, sizeof(int), "manifold indices");
+ }
+ int *indices_reverse = NULL;
+ if (indices_reverse_r != NULL) {
+ indices_reverse = MEM_malloc_arrayN(
+ num_elements, sizeof(int), "manifold indices reverse");
+ }
+ int offset = 0;
+ for (int i = 0; i < num_elements; i++) {
+ if (BLI_BITMAP_TEST_BOOL(used_map, i)) {
+ if (indices != NULL) {
+ indices[i] = i - offset;
+ }
+ if (indices_reverse != NULL) {
+ indices_reverse[i - offset] = i;
+ }
+ }
+ else {
+ if (indices != NULL) {
+ indices[i] = -1;
+ }
+ offset++;
+ }
+ }
+ if (indices_r != NULL) {
+ *indices_r = indices;
+ }
+ if (indices_reverse_r != NULL) {
+ *indices_reverse_r = indices_reverse;
+ }
+ *num_manifold_elements_r = num_elements - offset;
+}
+
+static void initialize_manifold_indices(ConverterStorage *storage)
+{
+ const Mesh *mesh = storage->mesh;
+ const MEdge *medge = mesh->medge;
+ const MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+ /* Set bits of elements which are not loose. */
+ BLI_bitmap *vert_used_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ BLI_bitmap *edge_used_map = BLI_BITMAP_NEW(mesh->totedge, "edge used map");
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ const MLoop *loop = &mloop[poly->loopstart + corner];
+ BLI_BITMAP_ENABLE(vert_used_map, loop->v);
+ BLI_BITMAP_ENABLE(edge_used_map, loop->e);
+ }
+ }
+ initialize_manifold_index_array(vert_used_map,
+ mesh->totvert,
+ &storage->manifold_vertex_index,
+ &storage->manifold_vertex_index_reverse,
+ &storage->num_manifold_vertices);
+ initialize_manifold_index_array(edge_used_map,
+ mesh->totedge,
+ NULL,
+ &storage->manifold_edge_index_reverse,
+ &storage->num_manifold_edges);
+ /* Initialize infinite sharp mapping. */
+ storage->infinite_sharp_vertices_map =
+ BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ for (int edge_index = 0; edge_index < mesh->totedge; edge_index++) {
+ if (!BLI_BITMAP_TEST_BOOL(edge_used_map, edge_index)) {
+ const MEdge *edge = &medge[edge_index];
+ BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v1);
+ BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v2);
+ }
+ }
+ /* Free working variables. */
+ MEM_freeN(vert_used_map);
+ MEM_freeN(edge_used_map);
+}
+
+static void init_user_data(OpenSubdiv_Converter *converter,
+ const SubdivSettings *settings,
+ const Mesh *mesh)
+{
+ ConverterStorage *user_data =
+ MEM_mallocN(sizeof(ConverterStorage), __func__);
+ user_data->settings = *settings;
+ user_data->mesh = mesh;
+ user_data->loop_uv_indices = NULL;
+ initialize_manifold_indices(user_data);
+ converter->user_data = user_data;
+}
+
+void BKE_subdiv_converter_init_for_mesh(struct OpenSubdiv_Converter *converter,
+ const SubdivSettings *settings,
+ const Mesh *mesh)
+{
+ init_functions(converter);
+ init_user_data(converter, settings, mesh);
+}
diff --git a/source/blender/render/intern/include/volume_precache.h b/source/blender/blenkernel/intern/subdiv_displacement.c
index 9aa280d8276..a6af6f45e59 100644
--- a/source/blender/render/intern/include/volume_precache.h
+++ b/source/blender/blenkernel/intern/subdiv_displacement.c
@@ -15,25 +15,32 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
* All rights reserved.
*
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb.
+ * Contributor(s): Sergey Sharybin.
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/render/intern/include/volume_precache.h
- * \ingroup render
+/** \file blender/blenkernel/intern/subdiv_displacement.c
+ * \ingroup bke
*/
+#include "BKE_subdiv.h"
-void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float bbmin[3], float bbmax[3]);
-int point_inside_volume_objectinstance(Render *re, ObjectInstanceRen *obi, const float co[3]);
+#include "BLI_utildefines.h"
-void volume_precache(Render *re);
-void free_volume_precache(Render *re);
+#include "MEM_guardedalloc.h"
-#define VOL_MS_TIMESTEP 0.1f
+void BKE_subdiv_displacement_detach(Subdiv *subdiv)
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ return;
+ }
+ if (subdiv->displacement_evaluator->free != NULL) {
+ subdiv->displacement_evaluator->free(subdiv->displacement_evaluator);
+ }
+ MEM_freeN(subdiv->displacement_evaluator);
+ subdiv->displacement_evaluator = NULL;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.c b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
new file mode 100644
index 00000000000..5744ac3ca0d
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
@@ -0,0 +1,358 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_displacement_multires.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_multires.h"
+
+#include "MEM_guardedalloc.h"
+
+typedef struct PolyCornerIndex {
+ int poly_index;
+ int corner;
+} PolyCornerIndex;
+
+typedef struct MultiresDisplacementData {
+ int grid_size;
+ const MPoly *mpoly;
+ const MDisps *mdisps;
+ /* Indexed by ptex face index, contains polygon/corner which corresponds
+ * to it.
+ *
+ * NOTE: For quad polygon this is an index of first corner only, since
+ * there we only have one ptex.
+ */
+ PolyCornerIndex *ptex_poly_corner;
+} MultiresDisplacementData;
+
+/* Denotes which grid to use to average value of the displacement read from the
+ * grid which corresponds to the ptex face.
+ */
+typedef enum eAverageWith {
+ AVERAGE_WITH_NONE,
+ AVERAGE_WITH_ALL,
+ AVERAGE_WITH_PREV,
+ AVERAGE_WITH_NEXT,
+} eAverageWith;
+
+static int displacement_get_grid_and_coord(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const float u, const float v,
+ const MDisps **r_displacement_grid,
+ float *grid_u, float *grid_v)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int start_grid_index = poly->loopstart + poly_corner->corner;
+ int corner = 0;
+ if (poly->totloop == 4) {
+ float corner_u, corner_v;
+ corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
+ *r_displacement_grid = &data->mdisps[start_grid_index + corner];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
+ }
+ else {
+ *r_displacement_grid = &data->mdisps[start_grid_index];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
+ }
+ return corner;
+}
+
+static const MDisps *displacement_get_next_grid(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int effective_corner = (poly->totloop == 4) ? corner
+ : poly_corner->corner;
+ const int next_corner = (effective_corner + 1) % poly->totloop;
+ return &data->mdisps[poly->loopstart + next_corner];
+}
+
+static const MDisps *displacement_get_prev_grid(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int effective_corner = (poly->totloop == 4) ? corner
+ : poly_corner->corner;
+ const int prev_corner =
+ (effective_corner - 1 + poly->totloop) % poly->totloop;
+ return &data->mdisps[poly->loopstart + prev_corner];
+}
+
+BLI_INLINE eAverageWith read_displacement_grid(
+ const MDisps *displacement_grid,
+ const int grid_size,
+ const float grid_u, const float grid_v,
+ float r_tangent_D[3])
+{
+ if (displacement_grid->disps == NULL) {
+ zero_v3(r_tangent_D);
+ return AVERAGE_WITH_NONE;
+ }
+ const int x = (grid_u * (grid_size - 1) + 0.5f);
+ const int y = (grid_v * (grid_size - 1) + 0.5f);
+ copy_v3_v3(r_tangent_D, displacement_grid->disps[y * grid_size + x]);
+ if (x == 0 && y == 0) {
+ return AVERAGE_WITH_ALL;
+ }
+ else if (x == 0) {
+ return AVERAGE_WITH_PREV;
+ }
+ else if (y == 0) {
+ return AVERAGE_WITH_NEXT;
+ }
+ return AVERAGE_WITH_NONE;
+}
+
+static void average_with_all(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float UNUSED(grid_u), const float UNUSED(grid_v),
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ for (int current_corner = 0;
+ current_corner < poly->totloop;
+ current_corner++)
+ {
+ if (current_corner == corner) {
+ continue;
+ }
+ const MDisps *displacement_grid =
+ &data->mdisps[poly->loopstart + current_corner];
+ const float *current_tangent_D = displacement_grid->disps[0];
+ r_tangent_D[2] += current_tangent_D[2];
+ }
+ r_tangent_D[2] /= (float)poly->totloop;
+}
+
+static void average_with_next(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float grid_u, const float UNUSED(grid_v),
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ const MDisps *next_displacement_grid = displacement_get_next_grid(
+ displacement, ptex_face_index, corner);
+ float next_tangent_D[3];
+ read_displacement_grid(next_displacement_grid, grid_size,
+ 0.0f, grid_u,
+ next_tangent_D);
+ r_tangent_D[2] += next_tangent_D[2];
+ r_tangent_D[2] *= 0.5f;
+}
+
+static void average_with_prev(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float UNUSED(grid_u), const float grid_v,
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ const MDisps *prev_displacement_grid = displacement_get_prev_grid(
+ displacement, ptex_face_index, corner);
+ float prev_tangent_D[3];
+ read_displacement_grid(prev_displacement_grid, grid_size,
+ grid_v, 0.0f,
+ prev_tangent_D);
+ r_tangent_D[2] += prev_tangent_D[2];
+ r_tangent_D[2] *= 0.5f;
+}
+
+static void average_displacement(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ eAverageWith average_with,
+ const float grid_u, const float grid_v,
+ float r_tangent_D[3])
+{
+ switch (average_with) {
+ case AVERAGE_WITH_ALL:
+ average_with_all(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_PREV:
+ average_with_prev(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_NEXT:
+ average_with_next(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_NONE:
+ break;
+ }
+}
+
+static void eval_displacement(SubdivDisplacement *displacement,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ /* Get displacement in tangent space. */
+ const MDisps *displacement_grid;
+ float grid_u, grid_v;
+ int corner = displacement_get_grid_and_coord(displacement,
+ ptex_face_index, u, v,
+ &displacement_grid,
+ &grid_u, &grid_v);
+ /* Read displacement from the current displacement grid and see if any
+ * averaging is needed.
+ */
+ float tangent_D[3];
+ eAverageWith average_with =
+ read_displacement_grid(displacement_grid, grid_size,
+ grid_u, grid_v,
+ tangent_D);
+ average_displacement(displacement,
+ ptex_face_index, corner,
+ average_with, grid_u, grid_v,
+ tangent_D);
+ /* Convert it to the object space. */
+ float tangent_matrix[3][3];
+ BKE_multires_construct_tangent_matrix(tangent_matrix, dPdu, dPdv, corner);
+ mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
+}
+
+static void free_displacement(SubdivDisplacement *displacement)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ MEM_freeN(data->ptex_poly_corner);
+ MEM_freeN(data);
+}
+
+/* TODO(sergey): This seems to be generally used information, which almost
+ * worth adding to a subdiv itself, with possible cache of the value.
+ */
+static int count_num_ptex_faces(const Mesh *mesh)
+{
+ int num_ptex_faces = 0;
+ const MPoly *mpoly = mesh->mpoly;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
+ }
+ return num_ptex_faces;
+}
+
+static void displacement_data_init_mapping(SubdivDisplacement *displacement,
+ const Mesh *mesh)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const MPoly *mpoly = mesh->mpoly;
+ const int num_ptex_faces = count_num_ptex_faces(mesh);
+ /* Allocate memory. */
+ data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces,
+ sizeof(*data->ptex_poly_corner),
+ "ptex poly corner");
+ /* Fill in offsets. */
+ int ptex_face_index = 0;
+ PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ if (poly->totloop == 4) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = 0;
+ ptex_face_index++;
+ }
+ else {
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = corner;
+ ptex_face_index++;
+ }
+ }
+ }
+}
+
+static void displacement_init_data(SubdivDisplacement *displacement,
+ const Mesh *mesh,
+ const MultiresModifierData *mmd)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl);
+ data->mpoly = mesh->mpoly;
+ data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ displacement_data_init_mapping(displacement, mesh);
+}
+
+static void displacement_init_functions(SubdivDisplacement *displacement)
+{
+ displacement->eval_displacement = eval_displacement;
+ displacement->free = free_displacement;
+}
+
+void BKE_subdiv_displacement_attach_from_multires(
+ Subdiv *subdiv,
+ const Mesh *mesh,
+ const MultiresModifierData *mmd)
+{
+ /* Make sure we don't have previously assigned displacement. */
+ BKE_subdiv_displacement_detach(subdiv);
+ /* Allocate all required memory. */
+ SubdivDisplacement *displacement = MEM_callocN(sizeof(SubdivDisplacement),
+ "multires displacement");
+ displacement->user_data = MEM_callocN(sizeof(MultiresDisplacementData),
+ "multires displacement data");
+ displacement_init_data(displacement, mesh, mmd);
+ displacement_init_functions(displacement);
+ /* Finish. */
+ subdiv->displacement_evaluator = displacement;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
new file mode 100644
index 00000000000..f4a9e1a95fd
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -0,0 +1,394 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_eval.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_eval.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_subdiv.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
+
+bool BKE_subdiv_eval_begin(Subdiv *subdiv)
+{
+ if (subdiv->topology_refiner == NULL) {
+ /* Happens on input mesh with just loose geometry,
+ * or when OpenSubdiv is disabled
+ */
+ return false;
+ }
+ else if (subdiv->evaluator == NULL) {
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
+ subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
+ subdiv->topology_refiner);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
+ if (subdiv->evaluator == NULL) {
+ return false;
+ }
+ }
+ else {
+ /* TODO(sergey): Check for topology change. */
+ }
+ return true;
+}
+
+static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
+{
+ const MVert *mvert = mesh->mvert;
+ const MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+ /* Mark vertices which needs new coordinates. */
+ /* TODO(sergey): This is annoying to calculate this on every update,
+ * maybe it's better to cache this mapping. Or make it possible to have
+ * OpenSubdiv's vertices match mesh ones?
+ */
+ BLI_bitmap *vertex_used_map =
+ BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ const MLoop *loop = &mloop[poly->loopstart + corner];
+ BLI_BITMAP_ENABLE(vertex_used_map, loop->v);
+ }
+ }
+ for (int vertex_index = 0, manifold_veretx_index = 0;
+ vertex_index < mesh->totvert;
+ vertex_index++)
+ {
+ if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
+ continue;
+ }
+ const MVert *vertex = &mvert[vertex_index];
+ subdiv->evaluator->setCoarsePositions(
+ subdiv->evaluator,
+ vertex->co,
+ manifold_veretx_index, 1);
+ manifold_veretx_index++;
+ }
+ MEM_freeN(vertex_used_map);
+}
+
+static void set_face_varying_data_from_uv(Subdiv *subdiv,
+ const MLoopUV *mloopuv,
+ const int layer_index)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ const MLoopUV *mluv = mloopuv;
+ /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
+ * loops of a face, need to watch for that, to prevent wrong UVs assigned.
+ */
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ const int num_face_vertices = topology_refiner->getNumFaceVertices(
+ topology_refiner, face_index);
+ const int *uv_indicies = topology_refiner->getFaceFVarValueIndices(
+ topology_refiner, face_index, layer_index);
+ for (int vertex_index = 0;
+ vertex_index < num_face_vertices;
+ vertex_index++, mluv++)
+ {
+ evaluator->setFaceVaryingData(evaluator,
+ layer_index,
+ mluv->uv,
+ uv_indicies[vertex_index],
+ 1);
+ }
+ }
+}
+
+bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
+{
+ if (!BKE_subdiv_eval_begin(subdiv)) {
+ return false;
+ }
+ if (subdiv->evaluator == NULL) {
+ /* NOTE: This situation is supposed to be handled by begin(). */
+ BLI_assert(!"Is not supposed to happen");
+ return false;
+ }
+ /* Set coordinates of base mesh vertices. */
+ set_coarse_positions(subdiv, mesh);
+ /* Set face-varyign data to UV maps. */
+ const int num_uv_layers =
+ CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
+ const MLoopUV *mloopuv = CustomData_get_layer_n(
+ &mesh->ldata, CD_MLOOPUV, layer_index);
+ set_face_varying_data_from_uv(subdiv, mloopuv, layer_index);
+ }
+ /* Update evaluator to the new coarse geometry. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
+ subdiv->evaluator->refine(subdiv->evaluator);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
+ return true;
+}
+
+/* ========================== Single point queries ========================== */
+
+void BKE_subdiv_eval_limit_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3])
+{
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
+ ptex_face_index,
+ u, v,
+ r_P, NULL, NULL);
+}
+
+void BKE_subdiv_eval_limit_point_and_derivatives(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], float r_dPdu[3], float r_dPdv[3])
+{
+ subdiv->evaluator->evaluateLimit(subdiv->evaluator,
+ ptex_face_index,
+ u, v,
+ r_P, r_dPdu, r_dPdv);
+}
+
+void BKE_subdiv_eval_limit_point_and_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], float r_N[3])
+{
+ float dPdu[3], dPdv[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
+ ptex_face_index,
+ u, v,
+ r_P, dPdu, dPdv);
+ cross_v3_v3v3(r_N, dPdu, dPdv);
+ normalize_v3(r_N);
+}
+
+void BKE_subdiv_eval_limit_point_and_short_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], short r_N[3])
+{
+ float N_float[3];
+ BKE_subdiv_eval_limit_point_and_normal(subdiv,
+ ptex_face_index,
+ u, v,
+ r_P, N_float);
+ normal_float_to_short_v3(r_N, N_float);
+}
+
+void BKE_subdiv_eval_face_varying(
+ Subdiv *subdiv,
+ const int face_varying_channel,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_face_varying[2])
+{
+ subdiv->evaluator->evaluateFaceVarying(subdiv->evaluator,
+ face_varying_channel,
+ ptex_face_index,
+ u, v,
+ r_face_varying);
+}
+
+void BKE_subdiv_eval_displacement(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3])
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ zero_v3(r_D);
+ return;
+ }
+ subdiv->displacement_evaluator->eval_displacement(
+ subdiv->displacement_evaluator,
+ ptex_face_index,
+ u, v,
+ dPdu, dPdv,
+ r_D);
+}
+
+void BKE_subdiv_eval_final_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3])
+{
+ if (subdiv->displacement_evaluator) {
+ float dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
+ BKE_subdiv_eval_displacement(subdiv,
+ ptex_face_index, u, v,
+ dPdu, dPdv,
+ D);
+ add_v3_v3(r_P, D);
+ }
+ else {
+ BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
+ }
+}
+
+/* =================== Patch queries at given resolution =================== */
+
+/* Move buffer forward by a given number of bytes. */
+static void buffer_apply_offset(void **buffer, const int offset)
+{
+ *buffer = ((unsigned char *)*buffer) + offset;
+}
+
+/* Write given number of floats to the beginning of given buffer. */
+static void buffer_write_float_value(void **buffer,
+ const float *values_buffer, int num_values)
+{
+ memcpy(*buffer, values_buffer, sizeof(float) * num_values);
+}
+
+/* Similar to above, just operates with short values. */
+static void buffer_write_short_value(void **buffer,
+ const short *values_buffer, int num_values)
+{
+ memcpy(*buffer, values_buffer, sizeof(short) * num_values);
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *buffer, const int offset, const int stride)
+{
+ buffer_apply_offset(&buffer, offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ BKE_subdiv_eval_limit_point(subdiv,
+ ptex_face_index,
+ u, v,
+ buffer);
+ buffer_apply_offset(&buffer, stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *du_buffer, const int du_offset, const int du_stride,
+ void *dv_buffer, const int dv_offset, const int dv_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&du_buffer, du_offset);
+ buffer_apply_offset(&dv_buffer, dv_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, du_buffer, dv_buffer);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&du_buffer, du_stride);
+ buffer_apply_offset(&dv_buffer, dv_stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&normal_buffer, normal_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ float normal[3];
+ BKE_subdiv_eval_limit_point_and_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, normal);
+ buffer_write_float_value(&normal_buffer, normal, 3);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&normal_buffer, normal_stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&normal_buffer, normal_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ short normal[3];
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, normal);
+ buffer_write_short_value(&normal_buffer, normal, 3);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&normal_buffer, normal_stride);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
new file mode 100644
index 00000000000..511536c31b5
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_foreach.c
@@ -0,0 +1,2038 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_foreach.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_foreach.h"
+
+#include "atomic_ops.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_bitmap.h"
+#include "BLI_math_vector.h"
+#include "BLI_task.h"
+
+#include "BKE_mesh.h"
+#include "BKE_key.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_mesh.h"
+
+#include "MEM_guardedalloc.h"
+
+/* =============================================================================
+ * General helpers.
+ */
+
+/* Number of ptex faces for a given polygon. */
+BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly)
+{
+ return (poly->totloop == 4) ? 1 : poly->totloop;
+}
+
+BLI_INLINE int num_edges_per_ptex_face_get(const int resolution)
+{
+ return 2 * (resolution - 1) * resolution;
+}
+
+BLI_INLINE int num_inner_edges_per_ptex_face_get(const int resolution)
+{
+ if (resolution < 2) {
+ return 0;
+ }
+ return (resolution - 2) * resolution +
+ (resolution - 1) * (resolution - 1);
+}
+
+/* Number of subdivision polygons per ptex face. */
+BLI_INLINE int num_polys_per_ptex_get(const int resolution)
+{
+ return (resolution - 1) * (resolution - 1);
+}
+
+/* Subdivision resolution per given polygon's ptex faces. */
+BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
+{
+ return (poly->totloop == 4) ? (resolution)
+ : ((resolution >> 1) + 1);
+}
+
+/* =============================================================================
+ * Context which is passed to all threaded tasks.
+ */
+
+typedef struct SubdivForeachTaskContext {
+ const Mesh *coarse_mesh;
+ const SubdivToMeshSettings *settings;
+ /* Callbacks. */
+ const SubdivForeachContext *foreach_context;
+ /* Counters of geometry in subdivided mesh, initialized as a part of
+ * offsets calculation.
+ */
+ int num_subdiv_vertices;
+ int num_subdiv_edges;
+ int num_subdiv_loops;
+ int num_subdiv_polygons;
+ /* Offsets of various geometry in the subdivision mesh arrays. */
+ int vertices_corner_offset;
+ int vertices_edge_offset;
+ int vertices_inner_offset;
+ int edge_boundary_offset;
+ int edge_inner_offset;
+ /* Indexed by coarse polygon index, indicates offset in subdivided mesh
+ * vertices, edges and polygons arrays, where first element of the poly
+ * begins.
+ */
+ int *subdiv_vertex_offset;
+ int *subdiv_edge_offset;
+ int *subdiv_polygon_offset;
+ /* Indexed by base face index, element indicates total number of ptex faces
+ * created for preceding base faces.
+ */
+ int *face_ptex_offset;
+ /* Bitmap indicating whether vertex was used already or not.
+ * - During patch evaluation indicates whether coarse vertex was already
+ * evaluated and its position on limit is already known.
+ */
+ BLI_bitmap *coarse_vertices_used_map;
+ /* Bitmap indicating whether edge was used already or not. This includes:
+ * - During context initialization it indicates whether subdivided vertices
+ * for corresponding edge were already calculated or not.
+ * - During patch evaluation it indicates whether vertices along this edge
+ * were already evaluated.
+ */
+ BLI_bitmap *coarse_edges_used_map;
+} SubdivForeachTaskContext;
+
+/* NOTE: Expects edge map to be zeroed. */
+static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx)
+{
+ /* Reset counters. */
+ ctx->num_subdiv_vertices = 0;
+ ctx->num_subdiv_edges = 0;
+ ctx->num_subdiv_loops = 0;
+ ctx->num_subdiv_polygons = 0;
+ /* Static geometry counters. */
+ const int resolution = ctx->settings->resolution;
+ const int no_quad_patch_resolution = ((resolution >> 1) + 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_inner_vertices_per_quad = (resolution - 2) * (resolution - 2);
+ const int num_inner_vertices_per_noquad_patch =
+ (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 2);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ ctx->num_subdiv_vertices = coarse_mesh->totvert;
+ ctx->num_subdiv_edges =
+ coarse_mesh->totedge * (num_subdiv_vertices_per_coarse_edge + 1);
+ /* Calculate extra vertices and edges createdd by non-loose geometry. */
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const bool is_edge_used =
+ BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, loop->e);
+ /* Edges which aren't counted yet. */
+ if (!is_edge_used) {
+ BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e);
+ ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
+ }
+ }
+ /* Inner vertices of polygon. */
+ if (num_ptex_faces_per_poly == 1) {
+ ctx->num_subdiv_vertices += num_inner_vertices_per_quad;
+ ctx->num_subdiv_edges +=
+ num_edges_per_ptex_face_get(resolution - 2) +
+ 4 * num_subdiv_vertices_per_coarse_edge;
+ ctx->num_subdiv_polygons += num_polys_per_ptex_get(resolution);
+ }
+ else {
+ ctx->num_subdiv_vertices +=
+ 1 +
+ num_ptex_faces_per_poly * (no_quad_patch_resolution - 2) +
+ num_ptex_faces_per_poly * num_inner_vertices_per_noquad_patch;
+ ctx->num_subdiv_edges +=
+ num_ptex_faces_per_poly *
+ (num_inner_edges_per_ptex_face_get(
+ no_quad_patch_resolution - 1) +
+ (no_quad_patch_resolution - 2) +
+ num_subdiv_vertices_per_coarse_edge);
+ if (no_quad_patch_resolution >= 3) {
+ ctx->num_subdiv_edges += coarse_poly->totloop;
+ }
+ ctx->num_subdiv_polygons +=
+ num_ptex_faces_per_poly *
+ num_polys_per_ptex_get(no_quad_patch_resolution);
+ }
+ }
+ /* Calculate extra vertices createdd by loose edges. */
+ for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
+ if (!BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, edge_index)) {
+ ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
+ }
+ }
+ ctx->num_subdiv_loops = ctx->num_subdiv_polygons * 4;
+}
+
+static void subdiv_foreach_ctx_init_offsets(SubdivForeachTaskContext *ctx)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int resolution = ctx->settings->resolution;
+ const int resolution_2 = resolution - 2;
+ const int resolution_2_squared = resolution_2 * resolution_2;
+ const int no_quad_patch_resolution = ((resolution >> 1) + 1);
+ const int num_irregular_vertices_per_patch =
+ (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ /* Constant offsets in arrays. */
+ ctx->vertices_corner_offset = 0;
+ ctx->vertices_edge_offset = coarse_mesh->totvert;
+ ctx->vertices_inner_offset =
+ ctx->vertices_edge_offset +
+ coarse_mesh->totedge * num_subdiv_vertices_per_coarse_edge;
+ ctx->edge_boundary_offset = 0;
+ ctx->edge_inner_offset =
+ ctx->edge_boundary_offset +
+ coarse_mesh->totedge * num_subdiv_edges_per_coarse_edge;
+ /* "Indexed" offsets. */
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ int vertex_offset = 0;
+ int edge_offset = 0;
+ int polygon_offset = 0;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ ctx->subdiv_vertex_offset[poly_index] = vertex_offset;
+ ctx->subdiv_edge_offset[poly_index] = edge_offset;
+ ctx->subdiv_polygon_offset[poly_index] = polygon_offset;
+ if (num_ptex_faces_per_poly == 1) {
+ vertex_offset += resolution_2_squared;
+ edge_offset += num_edges_per_ptex_face_get(resolution - 2) +
+ 4 * num_subdiv_vertices_per_coarse_edge;
+ polygon_offset += num_polys_per_ptex_get(resolution);
+ }
+ else {
+ vertex_offset +=
+ 1 +
+ num_ptex_faces_per_poly * num_irregular_vertices_per_patch;
+ edge_offset +=
+ num_ptex_faces_per_poly *
+ (num_inner_edges_per_ptex_face_get(
+ no_quad_patch_resolution - 1) +
+ (no_quad_patch_resolution - 2) +
+ num_subdiv_vertices_per_coarse_edge);
+ if (no_quad_patch_resolution >= 3) {
+ edge_offset += coarse_poly->totloop;
+ }
+ polygon_offset +=
+ num_ptex_faces_per_poly *
+ num_polys_per_ptex_get(no_quad_patch_resolution);
+ }
+ }
+}
+
+static void subdiv_foreach_ctx_init(Subdiv *subdiv,
+ SubdivForeachTaskContext *ctx)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ /* Allocate maps and offsets. */
+ ctx->coarse_vertices_used_map =
+ BLI_BITMAP_NEW(coarse_mesh->totvert, "vertices used map");
+ ctx->coarse_edges_used_map =
+ BLI_BITMAP_NEW(coarse_mesh->totedge, "edges used map");
+ ctx->subdiv_vertex_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_vertex_offset),
+ "vertex_offset");
+ ctx->subdiv_edge_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_edge_offset),
+ "subdiv_edge_offset");
+ ctx->subdiv_polygon_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_polygon_offset),
+ "subdiv_edge_offset");
+ /* Initialize all offsets. */
+ subdiv_foreach_ctx_init_offsets(ctx);
+ /* Calculate number of geometry in the result subdivision mesh. */
+ subdiv_foreach_ctx_count(ctx);
+ /* Re-set maps which were used at this step. */
+ BLI_BITMAP_SET_ALL(ctx->coarse_edges_used_map, false, coarse_mesh->totedge);
+ ctx->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+}
+
+static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
+{
+ MEM_freeN(ctx->coarse_vertices_used_map);
+ MEM_freeN(ctx->coarse_edges_used_map);
+ MEM_freeN(ctx->subdiv_vertex_offset);
+ MEM_freeN(ctx->subdiv_edge_offset);
+ MEM_freeN(ctx->subdiv_polygon_offset);
+}
+
+/* =============================================================================
+ * Vertex traversal process.
+ */
+
+/* Traversal of corner vertices. They are coming from coarse vertices. */
+
+static void subdiv_foreach_corner_vertices_regular_do(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromCornerCb vertex_corner,
+ bool check_usage)
+{
+ const float weights[4][2] = {{0.0f, 0.0f},
+ {1.0f, 0.0f},
+ {1.0f, 1.0f},
+ {0.0f, 1.0f}};
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map,
+ coarse_loop->v))
+ {
+ continue;
+ }
+ const int coarse_vertex_index = coarse_loop->v;
+ const int subdiv_vertex_index =
+ ctx->vertices_corner_offset + coarse_vertex_index;
+ const float u = weights[corner][0];
+ const float v = weights[corner][1];
+ vertex_corner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, v,
+ coarse_vertex_index,
+ coarse_poly_index,
+ 0,
+ subdiv_vertex_index);
+ }
+}
+
+static void subdiv_foreach_corner_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_corner_vertices_regular_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true);
+}
+
+static void subdiv_foreach_corner_vertices_special_do(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromCornerCb vertex_corner,
+ bool check_usage)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map,
+ coarse_loop->v))
+ {
+ continue;
+ }
+ const int coarse_vertex_index = coarse_loop->v;
+ const int subdiv_vertex_index =
+ ctx->vertices_corner_offset + coarse_vertex_index;
+ vertex_corner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ 0.0f, 0.0f,
+ coarse_vertex_index,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
+}
+
+static void subdiv_foreach_corner_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_corner_vertices_special_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true);
+}
+
+static void subdiv_foreach_corner_vertices(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_corner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_corner_vertices_special(ctx, tls, coarse_poly);
+ }
+}
+
+static void subdiv_foreach_every_corner_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_corner_vertices_regular_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_every_corner,
+ false);
+}
+
+static void subdiv_foreach_every_corner_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_corner_vertices_special_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_every_corner,
+ false);
+}
+
+static void subdiv_foreach_every_corner_vertices(SubdivForeachTaskContext *ctx)
+{
+ if (ctx->foreach_context->vertex_every_corner == NULL) {
+ return;
+ }
+ const SubdivForeachContext *foreach_context = ctx->foreach_context;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ void *tls = NULL;
+ if (foreach_context->user_data_tls_size != 0) {
+ tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls");
+ memcpy(tls,
+ foreach_context->user_data_tls,
+ foreach_context->user_data_tls_size);
+ }
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_every_corner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_every_corner_vertices_special(ctx, tls, coarse_poly);
+ }
+ }
+ if (tls != NULL) {
+ MEM_freeN(tls);
+ }
+}
+
+/* Traverse of edge vertices. They are coming from coarse edges. */
+
+static void subdiv_foreach_edge_vertices_regular_do(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromEdgeCb vertex_edge,
+ bool check_usage)
+{
+ const int resolution = ctx->settings->resolution;
+ const int resolution_1 = resolution - 1;
+ const float inv_resolution_1 = 1.0f / (float)resolution_1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const int coarse_edge_index = coarse_loop->e;
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map,
+ coarse_edge_index))
+ {
+ continue;
+ }
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int subdiv_vertex_index =
+ ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ for (int vertex_index = 0;
+ vertex_index < num_subdiv_vertices_per_coarse_edge;
+ vertex_index++, subdiv_vertex_index++)
+ {
+ float fac = (vertex_index + 1) * inv_resolution_1;
+ if (flip) {
+ fac = 1.0f - fac;
+ }
+ if (corner >= 2) {
+ fac = 1.0f - fac;
+ }
+ float u, v;
+ if ((corner & 1) == 0) {
+ u = fac;
+ v = (corner == 2) ? 1.0f : 0.0f;
+ }
+ else {
+ u = (corner == 1) ? 1.0f : 0.0f;
+ v = fac;
+ }
+ vertex_edge(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, v,
+ coarse_edge_index,
+ coarse_poly_index,
+ 0,
+ subdiv_vertex_index);
+ }
+ }
+}
+
+static void subdiv_foreach_edge_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_edge_vertices_regular_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_edge,
+ true);
+}
+
+static void subdiv_foreach_edge_vertices_special_do(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromEdgeCb vertex_edge,
+ bool check_usage)
+{
+ const int resolution = ctx->settings->resolution;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1);
+ const float inv_ptex_resolution_1 =
+ 1.0f / (float)(num_vertices_per_ptex_edge - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_start_index = ctx->face_ptex_offset[poly_index];
+ int ptex_face_index = ptex_face_start_index;
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const int coarse_edge_index = coarse_loop->e;
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map,
+ coarse_edge_index))
+ {
+ continue;
+ }
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int subdiv_vertex_index =
+ ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ int veretx_delta = 1;
+ if (flip) {
+ subdiv_vertex_index += num_subdiv_vertices_per_coarse_edge - 1;
+ veretx_delta = -1;
+ }
+ for (int vertex_index = 1;
+ vertex_index < num_vertices_per_ptex_edge;
+ vertex_index++, subdiv_vertex_index += veretx_delta)
+ {
+ const float u = vertex_index * inv_ptex_resolution_1;
+ vertex_edge(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, 0.0f,
+ coarse_edge_index,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
+ const int next_ptex_face_index =
+ ptex_face_start_index + (corner + 1) % coarse_poly->totloop;
+ for (int vertex_index = 1;
+ vertex_index < num_vertices_per_ptex_edge - 1;
+ vertex_index++, subdiv_vertex_index += veretx_delta)
+ {
+ const float v = 1.0f - vertex_index * inv_ptex_resolution_1;
+ vertex_edge(
+ ctx->foreach_context,
+ tls,
+ next_ptex_face_index,
+ 0.0f, v,
+ coarse_edge_index,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
+ }
+}
+
+static void subdiv_foreach_edge_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_edge_vertices_special_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_edge,
+ true);
+}
+
+static void subdiv_foreach_edge_vertices(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_edge_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_edge_vertices_special(ctx, tls, coarse_poly);
+ }
+}
+
+static void subdiv_foreach_every_edge_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_edge_vertices_regular_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_every_edge,
+ false);
+}
+
+static void subdiv_foreach_every_edge_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_edge_vertices_special_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_every_edge,
+ false);
+}
+
+static void subdiv_foreach_every_edge_vertices(SubdivForeachTaskContext *ctx)
+{
+ if (ctx->foreach_context->vertex_every_edge == NULL) {
+ return;
+ }
+ const SubdivForeachContext *foreach_context = ctx->foreach_context;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ void *tls = NULL;
+ if (foreach_context->user_data_tls_size != 0) {
+ tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls");
+ memcpy(tls,
+ foreach_context->user_data_tls,
+ foreach_context->user_data_tls_size);
+ }
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_every_edge_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_every_edge_vertices_special(ctx, tls, coarse_poly);
+ }
+ }
+ if (tls != NULL) {
+ MEM_freeN(tls);
+ }
+}
+
+/* Traversal of inner vertices, they are coming from ptex patches. */
+
+static void subdiv_foreach_inner_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
+ int subdiv_vertex_index =
+ ctx->vertices_inner_offset + start_vertex_index;
+ for (int y = 1; y < resolution - 1; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 1; x < resolution - 1; x++, subdiv_vertex_index++) {
+ const float u = x * inv_resolution_1;
+ ctx->foreach_context->vertex_inner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, v,
+ coarse_poly_index, 0,
+ subdiv_vertex_index);
+ }
+ }
+}
+
+static void subdiv_foreach_inner_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ const int ptex_face_resolution = ptex_face_resolution_get(
+ coarse_poly, resolution);
+ const float inv_ptex_face_resolution_1 =
+ 1.0f / (float)(ptex_face_resolution - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
+ int subdiv_vertex_index = ctx->vertices_inner_offset + start_vertex_index;
+ ctx->foreach_context->vertex_inner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ 1.0f, 1.0f,
+ coarse_poly_index, 0,
+ subdiv_vertex_index);
+ subdiv_vertex_index++;
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ for (int y = 1; y < ptex_face_resolution - 1; y++) {
+ const float v = y * inv_ptex_face_resolution_1;
+ for (int x = 1;
+ x < ptex_face_resolution; x++,
+ subdiv_vertex_index++)
+ {
+ const float u = x * inv_ptex_face_resolution_1;
+ ctx->foreach_context->vertex_inner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, v,
+ coarse_poly_index, corner,
+ subdiv_vertex_index);
+ }
+ }
+ }
+}
+
+static void subdiv_foreach_inner_vertices(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_inner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_inner_vertices_special(ctx, tls, coarse_poly);
+ }
+}
+
+/* Traverse all vertices which are emitted from given coarse polygon. */
+static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const int poly_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (ctx->foreach_context->vertex_corner != NULL) {
+ subdiv_foreach_corner_vertices(ctx, tls, coarse_poly);
+ }
+ if (ctx->foreach_context->vertex_edge != NULL) {
+ subdiv_foreach_edge_vertices(ctx, tls, coarse_poly);
+ }
+ if (ctx->foreach_context->vertex_inner != NULL) {
+ subdiv_foreach_inner_vertices(ctx, tls, coarse_poly);
+ }
+}
+
+/* =============================================================================
+ * Edge traversal process.
+ */
+
+/* TODO(sergey): Coarse edge are always NONE, consider getting rid of it. */
+static int subdiv_foreach_edges_row(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const int coarse_edge_index,
+ const int start_subdiv_edge_index,
+ const int start_vertex_index,
+ const int num_edges_per_row)
+{
+ int subdiv_edge_index = start_subdiv_edge_index;
+ int vertex_index = start_vertex_index;
+ for (int edge_index = 0;
+ edge_index < num_edges_per_row - 1;
+ edge_index++, subdiv_edge_index++)
+ {
+ const int v1 = vertex_index;
+ const int v2 = vertex_index + 1;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ coarse_edge_index,
+ subdiv_edge_index,
+ v1, v2);
+ vertex_index += 1;
+ }
+ return subdiv_edge_index;
+}
+
+/* TODO(sergey): Coarse edges are always NONE, consider getting rid of them. */
+static int subdiv_foreach_edges_column(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const int coarse_start_edge_index,
+ const int coarse_end_edge_index,
+ const int start_subdiv_edge_index,
+ const int start_vertex_index,
+ const int num_edges_per_row)
+{
+ int subdiv_edge_index = start_subdiv_edge_index;
+ int vertex_index = start_vertex_index;
+ for (int edge_index = 0;
+ edge_index < num_edges_per_row;
+ edge_index++, subdiv_edge_index++)
+ {
+ int coarse_edge_index = ORIGINDEX_NONE;
+ if (edge_index == 0) {
+ coarse_edge_index = coarse_start_edge_index;
+ }
+ else if (edge_index == num_edges_per_row - 1) {
+ coarse_edge_index = coarse_end_edge_index;
+ }
+ const int v1 = vertex_index;
+ const int v2 = vertex_index + num_edges_per_row;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ coarse_edge_index,
+ subdiv_edge_index,
+ v1, v2);
+ vertex_index += 1;
+ }
+ return subdiv_edge_index;
+}
+
+/* Defines edges between inner vertices of patch, and also edges to the
+ * boundary.
+ */
+
+/* Consider a subdivision of base face at level 1:
+ *
+ * y
+ * ^
+ * | (6) ---- (7) ---- (8)
+ * | | | |
+ * | (3) ---- (4) ---- (5)
+ * | | | |
+ * | (0) ---- (1) ---- (2)
+ * o---------------------------> x
+ *
+ * This is illustrate which parts of geometry is created by code below.
+ */
+
+static void subdiv_foreach_edges_all_patches_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int resolution = ctx->settings->resolution;
+ const int start_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ int subdiv_edge_index =
+ ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index];
+ /* Traverse bottom row of edges (0-1, 1-2). */
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_vertex_index,
+ resolution - 2);
+ /* Traverse remaining edges. */
+ for (int row = 0; row < resolution - 3; row++) {
+ const int start_row_vertex_index =
+ start_vertex_index + row * (resolution - 2);
+ /* Traverse vertical columns.
+ *
+ * At first iteration it will be edges (0-3. 1-4, 2-5), then it
+ * will be (3-6, 4-7, 5-8) and so on.
+ */
+ subdiv_edge_index = subdiv_foreach_edges_column(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index,
+ resolution - 2);
+ /* Create horizontal edge row.
+ *
+ * At first iteration it will be edges (3-4, 4-5), then it will be
+ * (6-7, 7-8) and so on.
+ */
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index + resolution - 2,
+ resolution - 2);
+ }
+ /* Connect inner part of patch to boundary. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index;
+ int side_stride = 0;
+ /* Calculate starting veretx of corresponding inner part of ptex. */
+ if (corner == 0) {
+ side_stride = 1;
+ }
+ else if (corner == 1) {
+ side_start_index += resolution - 3;
+ side_stride = resolution - 2;
+ }
+ else if (corner == 2) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ num_subdiv_vertices_per_coarse_edge - 1;
+ side_stride = -1;
+ }
+ else if (corner == 3) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ (num_subdiv_vertices_per_coarse_edge - 1);
+ side_stride = -(resolution - 2);
+ }
+ for (int i = 0; i < resolution - 2; i++, subdiv_edge_index++) {
+ const int v1 = (flip)
+ ? (start_edge_vertex + (resolution - i - 3))
+ : (start_edge_vertex + i);
+ const int v2 = side_start_index + side_stride * i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ }
+ }
+}
+
+static void subdiv_foreach_edges_all_patches_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int resolution = ctx->settings->resolution;
+ const int ptex_face_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_face_inner_resolution = ptex_face_resolution - 2;
+ const int num_inner_vertices_per_ptex =
+ (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int center_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int start_vertex_index = center_vertex_index + 1;
+ int subdiv_edge_index =
+ ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index];
+ /* Traverse inner ptex edges. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int start_ptex_face_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ /* Similar steps to regular patch case. */
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_ptex_face_vertex_index,
+ ptex_face_inner_resolution + 1);
+ for (int row = 0; row < ptex_face_inner_resolution - 1; row++) {
+ const int start_row_vertex_index =
+ start_ptex_face_vertex_index +
+ row * (ptex_face_inner_resolution + 1);
+ subdiv_edge_index = subdiv_foreach_edges_column(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index,
+ ptex_face_inner_resolution + 1);
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index + ptex_face_inner_resolution + 1,
+ ptex_face_inner_resolution + 1);
+ }
+ }
+ /* Create connections between ptex faces. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ int current_patch_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ int next_path_vertex_index =
+ start_vertex_index + next_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - ptex_face_resolution + 1;
+ for (int row = 0;
+ row < ptex_face_inner_resolution;
+ row++, subdiv_edge_index++)
+ {
+ const int v1 = current_patch_vertex_index;
+ const int v2 = next_path_vertex_index;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ }
+ }
+ /* Create edges from center. */
+ if (ptex_face_resolution >= 3) {
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, subdiv_edge_index++)
+ {
+ const int current_patch_end_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int v1 = center_vertex_index;
+ const int v2 = current_patch_end_vertex_index;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ }
+ }
+ /* Connect inner path of patch to boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ {
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index;
+ if (ptex_face_resolution >= 3) {
+ side_start_index =
+ start_vertex_index + num_inner_vertices_per_ptex * corner;
+ }
+ else {
+ side_start_index = center_vertex_index;
+ }
+ for (int i = 0; i < ptex_face_resolution - 1;
+ i++,
+ subdiv_edge_index++)
+ {
+ const int v1 = (flip)
+ ? (start_edge_vertex + (resolution - i - 3))
+ : (start_edge_vertex + i);
+ const int v2 = side_start_index + i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ }
+ }
+ if (ptex_face_resolution >= 3) {
+ const MEdge *coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index =
+ start_vertex_index + num_inner_vertices_per_ptex * corner;
+ for (int i = 0;
+ i < ptex_face_resolution - 2;
+ i++, subdiv_edge_index++)
+ {
+ const int v1 = (flip)
+ ? (start_edge_vertex + (resolution - i - 3))
+ : (start_edge_vertex + i);
+ const int v2 = side_start_index +
+ (ptex_face_inner_resolution + 1) * i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ }
+ }
+ prev_coarse_loop = coarse_loop;
+ }
+}
+
+static void subdiv_foreach_edges_all_patches(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_edges_all_patches_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_edges_all_patches_special(ctx, tls, coarse_poly);
+ }
+}
+
+static void subdiv_foreach_edges(SubdivForeachTaskContext *ctx,
+ void *tls,
+ int poly_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ subdiv_foreach_edges_all_patches(ctx, tls, coarse_poly);
+}
+
+static void subdiv_foreach_boundary_edges(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ int coarse_edge_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const int resolution = ctx->settings->resolution;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ int subdiv_edge_index =
+ ctx->edge_boundary_offset +
+ coarse_edge_index * num_subdiv_edges_per_coarse_edge;
+ int last_vertex_index = ctx->vertices_corner_offset + coarse_edge->v1;
+ for (int i = 0;
+ i < num_subdiv_edges_per_coarse_edge - 1;
+ i++, subdiv_edge_index++)
+ {
+ const int v1 = last_vertex_index;
+ const int v2 =
+ ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge +
+ i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ coarse_edge_index,
+ subdiv_edge_index,
+ v1, v2);
+ last_vertex_index = v2;
+ }
+ const int v1 = last_vertex_index;
+ const int v2 = ctx->vertices_corner_offset + coarse_edge->v2;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ coarse_edge_index,
+ subdiv_edge_index,
+ v1, v2);
+}
+
+/* =============================================================================
+ * Loops traversal.
+ */
+
+static void rotate_indices(const int rot, int *a, int *b, int *c, int *d)
+{
+ int values[4] = {*a, *b, *c, *d};
+ *a = values[(0 - rot + 4) % 4];
+ *b = values[(1 - rot + 4) % 4];
+ *c = values[(2 - rot + 4) % 4];
+ *d = values[(3 - rot + 4) % 4];
+}
+
+static void subdiv_foreach_loops_of_poly(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ int subdiv_loop_start_index,
+ const int ptex_face_index,
+ const int coarse_poly_index,
+ const int coarse_corner_index,
+ const int rotation,
+ /*const*/ int v0, /*const*/ int e0,
+ /*const*/ int v1, /*const*/ int e1,
+ /*const*/ int v2, /*const*/ int e2,
+ /*const*/ int v3, /*const*/ int e3,
+ const float u, const float v,
+ const float du, const float dv)
+{
+ rotate_indices(rotation, &v0, &v1, &v2, &v3);
+ rotate_indices(rotation, &e0, &e1, &e2, &e3);
+ ctx->foreach_context->loop(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index, u, v,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 0,
+ v0, e0);
+ ctx->foreach_context->loop(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index, u + du, v,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 1,
+ v1, e1);
+ ctx->foreach_context->loop(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index, u + du, v + dv,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 2,
+ v2, e2);
+ ctx->foreach_context->loop(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index, u, v + dv,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 3,
+ v3, e3);
+}
+
+static void subdiv_foreach_loops_regular(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_inner_resolution = ptex_resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1);
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[coarse_poly_index];
+ const int start_edge_index =
+ ctx->edge_inner_offset +
+ ctx->subdiv_edge_offset[coarse_poly_index];
+ const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index];
+ const int start_loop_index = 4 * start_poly_index;
+ const float du = inv_ptex_resolution_1;
+ const float dv = inv_ptex_resolution_1;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_loop_index = start_loop_index;
+ /* Loops for inner part of ptex. */
+ for (int y = 1; y < ptex_resolution - 2; y++) {
+ const float v = y * inv_ptex_resolution_1;
+ const int inner_y = y - 1;
+ for (int x = 1; x < ptex_resolution - 2; x++, subdiv_loop_index += 4) {
+ const int inner_x = x - 1;
+ const float u = x * inv_ptex_resolution_1;
+ /* Vertex indices ordered counter-clockwise. */
+ const int v0 = start_vertex_index +
+ (inner_y * ptex_inner_resolution + inner_x);
+ const int v1 = v0 + 1;
+ const int v2 = v0 + ptex_inner_resolution + 1;
+ const int v3 = v0 + ptex_inner_resolution;
+ /* Edge indices ordered counter-clockwise. */
+ const int e0 = start_edge_index +
+ (inner_y * (2 * ptex_inner_resolution - 1) + inner_x);
+ const int e1 = e0 + ptex_inner_resolution;
+ const int e2 = e0 + (2 * ptex_inner_resolution - 1);
+ const int e3 = e0 + ptex_inner_resolution - 1;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index,
+ coarse_poly_index, 0,
+ 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ }
+ }
+ /* Loops for faces connecting inner ptex part with boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index;
+ int side_stride = 0;
+ int v0 = ctx->vertices_corner_offset + coarse_loop->v;
+ int v3, e3;
+ int e2_offset, e2_stride;
+ float u, v, delta_u, delta_v;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
+ }
+ /* Calculate starting veretx of corresponding inner part of ptex. */
+ if (corner == 0) {
+ side_stride = 1;
+ e2_offset = 0;
+ e2_stride = 1;
+ u = 0.0f;
+ v = 0.0f;
+ delta_u = du;
+ delta_v = 0.0f;
+ }
+ else if (corner == 1) {
+ side_start_index += resolution - 3;
+ side_stride = resolution - 2;
+ e2_offset = 2 * num_subdiv_edges_per_coarse_edge - 4;
+ e2_stride = 2 * num_subdiv_edges_per_coarse_edge - 3;
+ u = 1.0f - du;
+ v = 0;
+ delta_u = 0.0f;
+ delta_v = dv;
+ }
+ else if (corner == 2) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ num_subdiv_vertices_per_coarse_edge - 1;
+ side_stride = -1;
+ e2_offset = num_edges_per_ptex_face_get(resolution - 2) - 1;
+ e2_stride = -1;
+ u = 1.0f - du;
+ v = 1.0f - dv;
+ delta_u = -du;
+ delta_v = 0.0f;
+ }
+ else if (corner == 3) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ (num_subdiv_vertices_per_coarse_edge - 1);
+ side_stride = -(resolution - 2);
+ e2_offset = num_edges_per_ptex_face_get(resolution - 2) -
+ (2 * num_subdiv_edges_per_coarse_edge - 3);
+ e2_stride = -(2 * num_subdiv_edges_per_coarse_edge - 3);
+ u = 0.0f;
+ v = 1.0f - dv;
+ delta_u = 0.0f;
+ delta_v = -dv;
+ }
+ for (int i = 0; i < resolution - 2; i++, subdiv_loop_index += 4) {
+ int v1;
+ if (flip) {
+ v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ v1 = start_edge_vertex + i;
+ }
+ const int v2 = side_start_index + side_stride * i;
+ int e0;
+ if (flip) {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - i - 1;
+ }
+ else {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ i;
+ }
+ int e1 = start_edge_index +
+ num_edges_per_ptex_face_get(resolution - 2) +
+ corner * num_subdiv_vertices_per_coarse_edge +
+ i;
+ int e2;
+ if (i == 0) {
+ e2 = start_edge_index +
+ num_edges_per_ptex_face_get(resolution - 2) +
+ ((corner - 1 + coarse_poly->totloop) %
+ coarse_poly->totloop) *
+ num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ }
+ else {
+ e2 = start_edge_index + e2_offset + e2_stride * (i - 1);
+ }
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index,
+ coarse_poly_index, corner,
+ corner,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u + delta_u * i, v + delta_v * i, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ prev_coarse_loop = coarse_loop;
+ }
+}
+
+static void subdiv_foreach_loops_special(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_face_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_face_inner_resolution = ptex_face_resolution - 2;
+ const float inv_ptex_resolution_1 =
+ 1.0f / (float)(ptex_face_resolution - 1);
+ const int num_inner_vertices_per_ptex =
+ (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
+ const int num_inner_edges_per_ptex_face =
+ num_inner_edges_per_ptex_face_get(
+ ptex_face_inner_resolution + 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int center_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[coarse_poly_index];
+ const int start_vertex_index = center_vertex_index + 1;
+ const int start_inner_vertex_index = center_vertex_index + 1;
+ const int start_edge_index = ctx->edge_inner_offset +
+ ctx->subdiv_edge_offset[coarse_poly_index];
+ const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index];
+ const int start_loop_index = 4 * start_poly_index;
+ const float du = inv_ptex_resolution_1;
+ const float dv = inv_ptex_resolution_1;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_loop_index = start_loop_index;
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int corner_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
+ for (int y = 1; y < ptex_face_inner_resolution; y++) {
+ const float v = y * inv_ptex_resolution_1;
+ const int inner_y = y - 1;
+ for (int x = 1;
+ x < ptex_face_inner_resolution + 1;
+ x++, subdiv_loop_index += 4)
+ {
+ const int inner_x = x - 1;
+ const float u = x * inv_ptex_resolution_1;
+ /* Vertex indices ordered counter-clockwise. */
+ const int v0 =
+ corner_vertex_index +
+ (inner_y * (ptex_face_inner_resolution + 1) + inner_x);
+ const int v1 = v0 + 1;
+ const int v2 = v0 + ptex_face_inner_resolution + 2;
+ const int v3 = v0 + ptex_face_inner_resolution + 1;
+ /* Edge indices ordered counter-clockwise. */
+ const int e0 = corner_edge_index +
+ (inner_y * (2 * ptex_face_inner_resolution + 1) + inner_x);
+ const int e1 = e0 + ptex_face_inner_resolution + 1;
+ const int e2 = e0 + (2 * ptex_face_inner_resolution + 1);
+ const int e3 = e0 + ptex_face_inner_resolution;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index + corner,
+ coarse_poly_index, corner,
+ 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ }
+ }
+ }
+ /* Create connections between ptex faces. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
+ const int next_corner_edge_index =
+ start_edge_index + next_corner * num_inner_edges_per_ptex_face;
+ int current_patch_vertex_index =
+ start_inner_vertex_index +
+ corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ int next_path_vertex_index =
+ start_inner_vertex_index +
+ next_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - ptex_face_resolution + 1;
+ int v0 = current_patch_vertex_index;
+ int v1 = next_path_vertex_index;
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ int e0 = start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ corner * (ptex_face_resolution - 2);
+ int e1 = next_corner_edge_index + num_inner_edges_per_ptex_face -
+ ptex_face_resolution + 2;
+ int e3 = corner_edge_index + 2 * ptex_face_resolution - 4;
+ for (int row = 1;
+ row < ptex_face_inner_resolution;
+ row++, subdiv_loop_index += 4)
+ {
+ const int v2 = next_path_vertex_index;
+ const int v3 = current_patch_vertex_index;
+ const int e2 = e0 + 1;
+ const float u = row * du;
+ const float v = 1.0f - dv;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index + next_corner,
+ coarse_poly_index, next_corner,
+ 3,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ v0 = v3;
+ v1 = v2;
+ e0 = e2;
+ e1 += 1;
+ e3 += 2 * ptex_face_resolution - 3;
+ }
+ }
+ /* Create loops from center. */
+ if (ptex_face_resolution >= 3) {
+ const int start_center_edge_index =
+ start_edge_index +
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution) * coarse_poly->totloop;
+ const int start_boundary_edge =
+ start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution - 1;
+ for (int corner = 0, prev_corner = coarse_poly->totloop - 1;
+ corner < coarse_poly->totloop;
+ prev_corner = corner, corner++, subdiv_loop_index += 4)
+ {
+ const int corner_edge_index =
+ start_edge_index +
+ corner * num_inner_edges_per_ptex_face;
+ const int current_patch_end_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int prev_current_patch_end_vertex_index =
+ start_vertex_index + prev_corner *
+ num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int v0 = center_vertex_index;
+ const int v1 = prev_current_patch_end_vertex_index;
+ const int v2 = current_patch_end_vertex_index - 1;
+ const int v3 = current_patch_end_vertex_index;
+ const int e0 = start_center_edge_index + prev_corner;
+ const int e1 = start_boundary_edge +
+ prev_corner * (ptex_face_inner_resolution);
+ const int e2 = corner_edge_index +
+ num_inner_edges_per_ptex_face - 1;
+ const int e3 = start_center_edge_index + corner;
+ const float u = 1.0f - du;
+ const float v = 1.0f - dv;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index,
+ ptex_face_index + corner,
+ coarse_poly_index, corner,
+ 2,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ }
+ }
+ /* Loops for faces connecting inner ptex part with boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int prev_corner = coarse_poly->totloop - 1, corner = 0;
+ corner < coarse_poly->totloop;
+ prev_corner = corner, corner++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const int corner_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
+ /* Create loops for polygons along U axis. */
+ int v0 = ctx->vertices_corner_offset + coarse_loop->v;
+ int v3, e3;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
+ }
+ for (int i = 0;
+ i <= ptex_face_inner_resolution;
+ i++, subdiv_loop_index += 4)
+ {
+ int v1;
+ if (flip) {
+ v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ v1 = start_edge_vertex + i;
+ }
+ int v2;
+ if (ptex_face_inner_resolution >= 1) {
+ v2 = corner_vertex_index + i;
+ }
+ else {
+ v2 = center_vertex_index;
+ }
+ int e0;
+ if (flip) {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - i - 1;
+ }
+ else {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ i;
+ }
+ int e1 = start_edge_index +
+ corner * (2 * ptex_face_inner_resolution + 1);
+ if (ptex_face_resolution >= 3) {
+ e1 += coarse_poly->totloop * (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ i;
+ }
+ int e2 = 0;
+ if (i == 0 && ptex_face_resolution >= 3) {
+ e2 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution + 1;
+ }
+ else if (i == 0 && ptex_face_resolution < 3) {
+ e2 = start_edge_index +
+ prev_corner * (2 * ptex_face_inner_resolution + 1);
+ }
+ else {
+ e2 = corner_edge_index + i - 1;
+ }
+ const float u = du * i;
+ const float v = 0.0f;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index + corner,
+ coarse_poly_index, corner,
+ 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ /* Create loops for polygons along V axis. */
+ const bool flip_prev = (prev_coarse_edge->v2 == coarse_loop->v);
+ v0 = corner_vertex_index;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ }
+ e3 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution + 1;
+ for (int i = 0;
+ i <= ptex_face_inner_resolution - 1;
+ i++, subdiv_loop_index += 4)
+ {
+ int v1;
+ int e0, e1;
+ if (i == ptex_face_inner_resolution - 1) {
+ v1 = start_vertex_index +
+ prev_corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ e1 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ prev_corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution;
+ e0 = start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ prev_corner * ptex_face_inner_resolution;
+ }
+ else {
+ v1 = v0 + ptex_face_inner_resolution + 1;
+ e0 = corner_edge_index + ptex_face_inner_resolution +
+ i * (2 * ptex_face_inner_resolution + 1);
+ e1 = e3 + 1;
+ }
+ int v2 = flip_prev ? v3 - 1 : v3 + 1;
+ int e2;
+ if (flip_prev) {
+ e2 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e *
+ num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 2 - i;
+ }
+ else {
+ e2 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e *
+ num_subdiv_edges_per_coarse_edge + 1 + i;
+ }
+ const float u = 0.0f;
+ const float v = du * (i + 1);
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index + corner,
+ coarse_poly_index, corner,
+ 1,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ prev_coarse_loop = coarse_loop;
+ }
+}
+
+static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx,
+ void *tls,
+ int poly_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_loops_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_loops_special(ctx, tls, coarse_poly);
+ }
+}
+
+/* =============================================================================
+ * Polygons traverse process.
+ */
+
+static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx,
+ void *tls,
+ int poly_index)
+{
+ const int resolution = ctx->settings->resolution;
+ const int start_poly_index = ctx->subdiv_polygon_offset[poly_index];
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ const int ptex_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int num_polys_per_ptex = num_polys_per_ptex_get(ptex_resolution);
+ const int num_loops_per_ptex = 4 * num_polys_per_ptex;
+ const int start_loop_index = 4 * start_poly_index;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_polyon_index = start_poly_index;
+ for (int ptex_of_poly_index = 0;
+ ptex_of_poly_index < num_ptex_faces_per_poly;
+ ptex_of_poly_index++)
+ {
+ for (int subdiv_poly_index = 0;
+ subdiv_poly_index < num_polys_per_ptex;
+ subdiv_poly_index++, subdiv_polyon_index++)
+ {
+ const int loopstart = start_loop_index +
+ (ptex_of_poly_index * num_loops_per_ptex) +
+ (subdiv_poly_index * 4);
+ ctx->foreach_context->poly(
+ ctx->foreach_context,
+ tls,
+ poly_index,
+ subdiv_polyon_index,
+ loopstart, 4);
+ }
+ }
+}
+
+/* =============================================================================
+ * Loose elements traverse process.
+ */
+
+static void subdiv_foreach_loose_vertices_task(
+ void *__restrict userdata,
+ const int coarse_vertex_index,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ if (BLI_BITMAP_TEST_BOOL(ctx->coarse_vertices_used_map,
+ coarse_vertex_index))
+ {
+ /* Vertex is not loose, was handled when handling polygons. */
+ return;
+ }
+ const int subdiv_vertex_index =
+ ctx->vertices_corner_offset + coarse_vertex_index;
+ ctx->foreach_context->vertex_loose(
+ ctx->foreach_context,
+ tls->userdata_chunk,
+ coarse_vertex_index,
+ subdiv_vertex_index);
+}
+
+static void subdiv_foreach_vertices_of_loose_edges_task(
+ void *__restrict userdata,
+ const int coarse_edge_index,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ if (BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, coarse_edge_index)) {
+ /* Vertex is not loose, was handled when handling polygons. */
+ return;
+ }
+ const int resolution = ctx->settings->resolution;
+ const int resolution_1 = resolution - 1;
+ const float inv_resolution_1 = 1.0f / (float)resolution_1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index];
+ /* Subdivion vertices which corresponds to edge's v1 and v2. */
+ const int subdiv_v1_index =
+ ctx->vertices_corner_offset + coarse_edge->v1;
+ const int subdiv_v2_index =
+ ctx->vertices_corner_offset + coarse_edge->v2;
+ /* First subdivided inner vertex of the edge. */
+ const int subdiv_start_vertex =
+ ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ /* Perform interpolation. */
+ for (int i = 0; i < resolution; i++) {
+ const float u = i * inv_resolution_1;
+ int subdiv_vertex_index;
+ if (i == 0) {
+ subdiv_vertex_index = subdiv_v1_index;
+ }
+ else if (i == resolution - 1) {
+ subdiv_vertex_index = subdiv_v2_index;
+ }
+ else {
+ subdiv_vertex_index = subdiv_start_vertex + (i - 1);
+ }
+ ctx->foreach_context->vertex_of_loose_edge(
+ ctx->foreach_context,
+ tls->userdata_chunk,
+ coarse_edge_index,
+ u,
+ subdiv_vertex_index);
+ }
+}
+
+/* =============================================================================
+ * Subdivision process entry points.
+ */
+
+static void subdiv_foreach_task(
+ void *__restrict userdata,
+ const int poly_index,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ /* Traverse hi-poly vertex coordinates and normals. */
+ subdiv_foreach_vertices(ctx, tls->userdata_chunk, poly_index);
+ /* Traverse mesh geometry for the given base poly index. */
+ if (ctx->foreach_context->edge != NULL) {
+ subdiv_foreach_edges(ctx, tls->userdata_chunk, poly_index);
+ }
+ if (ctx->foreach_context->loop != NULL) {
+ subdiv_foreach_loops(ctx, tls->userdata_chunk, poly_index);
+ }
+ if (ctx->foreach_context->poly != NULL) {
+ subdiv_foreach_polys(ctx, tls->userdata_chunk, poly_index);
+ }
+}
+
+static void subdiv_foreach_boundary_edges_task(
+ void *__restrict userdata,
+ const int edge_index,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index);
+}
+
+static void subdiv_foreach_finalize(void *__restrict userdata,
+ void *__restrict userdata_chunk)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ ctx->foreach_context->user_data_tls_free(userdata_chunk);
+}
+
+bool BKE_subdiv_foreach_subdiv_geometry(
+ Subdiv *subdiv,
+ const SubdivForeachContext *context,
+ const SubdivToMeshSettings *mesh_settings,
+ const Mesh *coarse_mesh)
+{
+ SubdivForeachTaskContext ctx = {0};
+ ctx.coarse_mesh = coarse_mesh;
+ ctx.settings = mesh_settings;
+ ctx.foreach_context = context;
+ subdiv_foreach_ctx_init(subdiv, &ctx);
+ if (context->topology_info != NULL) {
+ if (!context->topology_info(context,
+ ctx.num_subdiv_vertices,
+ ctx.num_subdiv_edges,
+ ctx.num_subdiv_loops,
+ ctx.num_subdiv_polygons))
+ {
+ subdiv_foreach_ctx_free(&ctx);
+ return false;
+ }
+ }
+ /* Single threaded passes to average displacement on the corner vertices
+ * and boundary edges.
+ */
+ subdiv_foreach_every_corner_vertices(&ctx);
+ subdiv_foreach_every_edge_vertices(&ctx);
+ /* Threaded traversal of the rest of topology. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.userdata_chunk = context->user_data_tls;
+ parallel_range_settings.userdata_chunk_size = context->user_data_tls_size;
+ if (context->user_data_tls_free != NULL) {
+ parallel_range_settings.func_finalize = subdiv_foreach_finalize;
+ }
+ BLI_task_parallel_range(0, coarse_mesh->totpoly,
+ &ctx,
+ subdiv_foreach_task,
+ &parallel_range_settings);
+ if (context->vertex_loose != NULL) {
+ BLI_task_parallel_range(0, coarse_mesh->totvert,
+ &ctx,
+ subdiv_foreach_loose_vertices_task,
+ &parallel_range_settings);
+ }
+ if (context->vertex_of_loose_edge != NULL) {
+ BLI_task_parallel_range(0, coarse_mesh->totedge,
+ &ctx,
+ subdiv_foreach_vertices_of_loose_edges_task,
+ &parallel_range_settings);
+ }
+ if (context->edge != NULL) {
+ BLI_task_parallel_range(0, coarse_mesh->totedge,
+ &ctx,
+ subdiv_foreach_boundary_edges_task,
+ &parallel_range_settings);
+ }
+ subdiv_foreach_ctx_free(&ctx);
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_inline.h b/source/blender/blenkernel/intern/subdiv_inline.h
new file mode 100644
index 00000000000..7eebde48bdc
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_inline.h
@@ -0,0 +1,80 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_inline.h
+ * \ingroup bke
+ */
+
+#ifndef __SUBDIV_INLINE_H__
+#define __SUBDIV_INLINE_H__
+
+#include "BLI_assert.h"
+#include "BLI_compiler_compat.h"
+
+#include "BKE_subdiv.h"
+
+BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(
+ const float ptex_u, const float ptex_v,
+ float *r_grid_u, float *r_grid_v)
+{
+ *r_grid_u = 1.0f - ptex_v;
+ *r_grid_v = 1.0f - ptex_u;
+}
+
+BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level)
+{
+ return (1 << (level - 1)) + 1;
+}
+
+BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(
+ const float u, const float v,
+ float *r_u, float *r_v)
+{
+ int corner;
+ if (u <= 0.5f && v <= 0.5f) {
+ corner = 0;
+ *r_u = 2.0f * u;
+ *r_v = 2.0f * v;
+ }
+ else if (u > 0.5f && v <= 0.5f) {
+ corner = 1;
+ *r_u = 2.0f * v;
+ *r_v = 2.0f * (1.0f - u);
+ }
+ else if (u > 0.5f && v > 0.5f) {
+ corner = 2;
+ *r_u = 2.0f * (1.0f - u);
+ *r_v = 2.0f * (1.0f - v);
+ }
+ else {
+ BLI_assert(u <= 0.5f && v >= 0.5f);
+ corner = 3;
+ *r_u = 2.0f * (1.0f - v);
+ *r_v = 2.0f * u;
+ }
+ return corner;
+}
+
+#endif /* __SUBDIV_INLINE_H__ */
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
new file mode 100644
index 00000000000..d9fcdf52969
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -0,0 +1,1149 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_mesh.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_mesh.h"
+
+#include "atomic_ops.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_bitmap.h"
+#include "BLI_math_vector.h"
+#include "BLI_task.h"
+
+#include "BKE_mesh.h"
+#include "BKE_key.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+
+#include "MEM_guardedalloc.h"
+
+/* =============================================================================
+ * Subdivision context.
+ */
+
+typedef struct SubdivMeshContext {
+ const Mesh *coarse_mesh;
+ Subdiv *subdiv;
+ Mesh *subdiv_mesh;
+ /* Cached custom data arrays for fastter access. */
+ int *vert_origindex;
+ int *edge_origindex;
+ int *loop_origindex;
+ int *poly_origindex;
+ /* UV layers interpolation. */
+ int num_uv_layers;
+ MLoopUV *uv_layers[MAX_MTFACE];
+} SubdivMeshContext;
+
+static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
+{
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ ctx->num_uv_layers =
+ CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
+ ctx->uv_layers[layer_index] = CustomData_get_layer_n(
+ &subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
+ }
+}
+
+static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
+{
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ /* Pointers to original indices layers. */
+ ctx->vert_origindex = CustomData_get_layer(
+ &subdiv_mesh->vdata, CD_ORIGINDEX);
+ ctx->edge_origindex = CustomData_get_layer(
+ &subdiv_mesh->edata, CD_ORIGINDEX);
+ ctx->loop_origindex = CustomData_get_layer(
+ &subdiv_mesh->ldata, CD_ORIGINDEX);
+ ctx->poly_origindex = CustomData_get_layer(
+ &subdiv_mesh->pdata, CD_ORIGINDEX);
+ /* UV layers interpolation. */
+ subdiv_mesh_ctx_cache_uv_layers(ctx);
+}
+
+/* =============================================================================
+ * Loop custom data copy helpers.
+ */
+
+typedef struct LoopsOfPtex {
+ /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
+ const MLoop *first_loop;
+ /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */
+ const MLoop *last_loop;
+ /* For quad coarse faces only. */
+ const MLoop *second_loop;
+ const MLoop *third_loop;
+} LoopsOfPtex;
+
+static void loops_of_ptex_get(
+ const SubdivMeshContext *ctx,
+ LoopsOfPtex *loops_of_ptex,
+ const MPoly *coarse_poly,
+ const int ptex_of_poly_index)
+{
+ const MLoop *coarse_mloop = ctx->coarse_mesh->mloop;
+ const int first_ptex_loop_index =
+ coarse_poly->loopstart + ptex_of_poly_index;
+ /* Loop which look in the (opposite) V direction of the current
+ * ptex face.
+ *
+ * TODO(sergey): Get rid of using module on every iteration.
+ */
+ const int last_ptex_loop_index =
+ coarse_poly->loopstart +
+ (ptex_of_poly_index + coarse_poly->totloop - 1) %
+ coarse_poly->totloop;
+ loops_of_ptex->first_loop = &coarse_mloop[first_ptex_loop_index];
+ loops_of_ptex->last_loop = &coarse_mloop[last_ptex_loop_index];
+ if (coarse_poly->totloop == 4) {
+ loops_of_ptex->second_loop = loops_of_ptex->first_loop + 1;
+ loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2;
+ }
+ else {
+ loops_of_ptex->second_loop = NULL;
+ loops_of_ptex->third_loop = NULL;
+ }
+}
+
+/* =============================================================================
+ * Vertex custom data interpolation helpers.
+ */
+
+/* TODO(sergey): Somehow de-duplicate with loops storage, without too much
+ * exception cases all over the code.
+ */
+
+typedef struct VerticesForInterpolation {
+ /* This field points to a vertex data which is to be used for interpolation.
+ * The idea is to avoid unnecessary allocations for regular faces, where
+ * we can simply
+ */
+ const CustomData *vertex_data;
+ /* Vertices data calculated for ptex corners. There are always 4 elements
+ * in this custom data, aligned the following way:
+ *
+ * index 0 -> uv (0, 0)
+ * index 1 -> uv (0, 1)
+ * index 2 -> uv (1, 1)
+ * index 3 -> uv (1, 0)
+ *
+ * Is allocated for non-regular faces (triangles and n-gons).
+ */
+ CustomData vertex_data_storage;
+ bool vertex_data_storage_allocated;
+ /* Infices within vertex_data to interpolate for. The indices are aligned
+ * with uv coordinates in a similar way as indices in loop_data_storage.
+ */
+ int vertex_indices[4];
+} VerticesForInterpolation;
+
+static void vertex_interpolation_init(
+ const SubdivMeshContext *ctx,
+ VerticesForInterpolation *vertex_interpolation,
+ const MPoly *coarse_poly)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ if (coarse_poly->totloop == 4) {
+ vertex_interpolation->vertex_data = &coarse_mesh->vdata;
+ vertex_interpolation->vertex_indices[0] =
+ coarse_mloop[coarse_poly->loopstart + 0].v;
+ vertex_interpolation->vertex_indices[1] =
+ coarse_mloop[coarse_poly->loopstart + 1].v;
+ vertex_interpolation->vertex_indices[2] =
+ coarse_mloop[coarse_poly->loopstart + 2].v;
+ vertex_interpolation->vertex_indices[3] =
+ coarse_mloop[coarse_poly->loopstart + 3].v;
+ vertex_interpolation->vertex_data_storage_allocated = false;
+ }
+ else {
+ vertex_interpolation->vertex_data =
+ &vertex_interpolation->vertex_data_storage;
+ /* Allocate storage for loops corresponding to ptex corners. */
+ CustomData_copy(&ctx->coarse_mesh->vdata,
+ &vertex_interpolation->vertex_data_storage,
+ CD_MASK_EVERYTHING,
+ CD_CALLOC,
+ 4);
+ /* Initialize indices. */
+ vertex_interpolation->vertex_indices[0] = 0;
+ vertex_interpolation->vertex_indices[1] = 1;
+ vertex_interpolation->vertex_indices[2] = 2;
+ vertex_interpolation->vertex_indices[3] = 3;
+ vertex_interpolation->vertex_data_storage_allocated = true;
+ /* Interpolate center of poly right away, it stays unchanged for all
+ * ptex faces.
+ */
+ const float weight = 1.0f / (float)coarse_poly->totloop;
+ float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
+ int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
+ for (int i = 0; i < coarse_poly->totloop; ++i) {
+ weights[i] = weight;
+ indices[i] = coarse_mloop[coarse_poly->loopstart + i].v;
+ }
+ CustomData_interp(&coarse_mesh->vdata,
+ &vertex_interpolation->vertex_data_storage,
+ indices,
+ weights, NULL,
+ coarse_poly->totloop,
+ 2);
+ }
+}
+
+static void vertex_interpolation_from_corner(
+ const SubdivMeshContext *ctx,
+ VerticesForInterpolation *vertex_interpolation,
+ const MPoly *coarse_poly,
+ const int corner)
+{
+ if (coarse_poly->totloop == 4) {
+ /* Nothing to do, all indices and data is already assigned. */
+ }
+ else {
+ const CustomData *vertex_data = &ctx->coarse_mesh->vdata;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ LoopsOfPtex loops_of_ptex;
+ loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner);
+ /* Ptex face corner corresponds to a poly loop with same index. */
+ CustomData_copy_data(
+ vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ coarse_mloop[coarse_poly->loopstart + corner].v,
+ 0,
+ 1);
+ /* Interpolate remaining ptex face corners, which hits loops
+ * middle points.
+ *
+ * TODO(sergey): Re-use one of interpolation results from previous
+ * iteration.
+ */
+ const float weights[2] = {0.5f, 0.5f};
+ const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop;
+ const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop;
+ const int first_indices[2] = {
+ coarse_mloop[first_loop_index].v,
+ coarse_mloop[coarse_poly->loopstart +
+ (first_loop_index - coarse_poly->loopstart + 1) %
+ coarse_poly->totloop].v};
+ const int last_indices[2] = {coarse_mloop[first_loop_index].v,
+ coarse_mloop[last_loop_index].v};
+ CustomData_interp(vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ first_indices,
+ weights, NULL,
+ 2,
+ 1);
+ CustomData_interp(vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ last_indices,
+ weights, NULL,
+ 2,
+ 3);
+ }
+}
+
+static void vertex_interpolation_end(
+ VerticesForInterpolation *vertex_interpolation)
+{
+ if (vertex_interpolation->vertex_data_storage_allocated) {
+ CustomData_free(&vertex_interpolation->vertex_data_storage, 4);
+ }
+}
+
+/* =============================================================================
+ * Loop custom data interpolation helpers.
+ */
+
+typedef struct LoopsForInterpolation {
+ /* This field points to a loop data which is to be used for interpolation.
+ * The idea is to avoid unnecessary allocations for regular faces, where
+ * we can simply
+ */
+ const CustomData *loop_data;
+ /* Loops data calculated for ptex corners. There are always 4 elements
+ * in this custom data, aligned the following way:
+ *
+ * index 0 -> uv (0, 0)
+ * index 1 -> uv (0, 1)
+ * index 2 -> uv (1, 1)
+ * index 3 -> uv (1, 0)
+ *
+ * Is allocated for non-regular faces (triangles and n-gons).
+ */
+ CustomData loop_data_storage;
+ bool loop_data_storage_allocated;
+ /* Infices within loop_data to interpolate for. The indices are aligned with
+ * uv coordinates in a similar way as indices in loop_data_storage.
+ */
+ int loop_indices[4];
+} LoopsForInterpolation;
+
+static void loop_interpolation_init(
+ const SubdivMeshContext *ctx,
+ LoopsForInterpolation *loop_interpolation,
+ const MPoly *coarse_poly)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ if (coarse_poly->totloop == 4) {
+ loop_interpolation->loop_data = &coarse_mesh->ldata;
+ loop_interpolation->loop_indices[0] = coarse_poly->loopstart + 0;
+ loop_interpolation->loop_indices[1] = coarse_poly->loopstart + 1;
+ loop_interpolation->loop_indices[2] = coarse_poly->loopstart + 2;
+ loop_interpolation->loop_indices[3] = coarse_poly->loopstart + 3;
+ loop_interpolation->loop_data_storage_allocated = false;
+ }
+ else {
+ loop_interpolation->loop_data = &loop_interpolation->loop_data_storage;
+ /* Allocate storage for loops corresponding to ptex corners. */
+ CustomData_copy(&ctx->coarse_mesh->ldata,
+ &loop_interpolation->loop_data_storage,
+ CD_MASK_EVERYTHING,
+ CD_CALLOC,
+ 4);
+ /* Initialize indices. */
+ loop_interpolation->loop_indices[0] = 0;
+ loop_interpolation->loop_indices[1] = 1;
+ loop_interpolation->loop_indices[2] = 2;
+ loop_interpolation->loop_indices[3] = 3;
+ loop_interpolation->loop_data_storage_allocated = true;
+ /* Interpolate center of poly right away, it stays unchanged for all
+ * ptex faces.
+ */
+ const float weight = 1.0f / (float)coarse_poly->totloop;
+ float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
+ int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
+ for (int i = 0; i < coarse_poly->totloop; ++i) {
+ weights[i] = weight;
+ indices[i] = coarse_poly->loopstart + i;
+ }
+ CustomData_interp(&coarse_mesh->ldata,
+ &loop_interpolation->loop_data_storage,
+ indices,
+ weights, NULL,
+ coarse_poly->totloop,
+ 2);
+ }
+}
+
+static void loop_interpolation_from_corner(
+ const SubdivMeshContext *ctx,
+ LoopsForInterpolation *loop_interpolation,
+ const MPoly *coarse_poly,
+ const int corner)
+{
+ if (coarse_poly->totloop == 4) {
+ /* Nothing to do, all indices and data is already assigned. */
+ }
+ else {
+ const CustomData *loop_data = &ctx->coarse_mesh->ldata;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ LoopsOfPtex loops_of_ptex;
+ loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner);
+ /* Ptex face corner corresponds to a poly loop with same index. */
+ CustomData_free_elem(&loop_interpolation->loop_data_storage, 0, 1);
+ CustomData_copy_data(loop_data,
+ &loop_interpolation->loop_data_storage,
+ coarse_poly->loopstart + corner,
+ 0,
+ 1);
+ /* Interpolate remaining ptex face corners, which hits loops
+ * middle points.
+ *
+ * TODO(sergey): Re-use one of interpolation results from previous
+ * iteration.
+ */
+ const float weights[2] = {0.5f, 0.5f};
+ const int first_indices[2] = {
+ loops_of_ptex.first_loop - coarse_mloop,
+ (loops_of_ptex.first_loop + 1 - coarse_mloop) %
+ coarse_poly->totloop};
+ const int last_indices[2] = {
+ loops_of_ptex.last_loop - coarse_mloop,
+ loops_of_ptex.first_loop - coarse_mloop};
+ CustomData_interp(loop_data,
+ &loop_interpolation->loop_data_storage,
+ first_indices,
+ weights, NULL,
+ 2,
+ 1);
+ CustomData_interp(loop_data,
+ &loop_interpolation->loop_data_storage,
+ last_indices,
+ weights, NULL,
+ 2,
+ 3);
+ }
+}
+
+static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
+{
+ if (loop_interpolation->loop_data_storage_allocated) {
+ CustomData_free(&loop_interpolation->loop_data_storage, 4);
+ }
+}
+
+/* =============================================================================
+ * TLS.
+ */
+
+typedef struct SubdivMeshTLS {
+ bool vertex_interpolation_initialized;
+ VerticesForInterpolation vertex_interpolation;
+ const MPoly *vertex_interpolation_coarse_poly;
+ int vertex_interpolation_coarse_corner;
+
+ bool loop_interpolation_initialized;
+ LoopsForInterpolation loop_interpolation;
+ const MPoly *loop_interpolation_coarse_poly;
+ int loop_interpolation_coarse_corner;
+} SubdivMeshTLS;
+
+static void subdiv_mesh_tls_free(void *tls_v)
+{
+ SubdivMeshTLS *tls = tls_v;
+ if (tls->vertex_interpolation_initialized) {
+ vertex_interpolation_end(&tls->vertex_interpolation);
+ }
+ if (tls->loop_interpolation_initialized) {
+ loop_interpolation_end(&tls->loop_interpolation);
+ }
+}
+
+/* =============================================================================
+ * Evaluation helper functions.
+ */
+
+static void eval_final_point_and_vertex_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], short r_N[3])
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv, ptex_face_index, u, v, r_P, r_N);
+ }
+ else {
+ BKE_subdiv_eval_final_point(
+ subdiv, ptex_face_index, u, v, r_P);
+ }
+}
+
+/* =============================================================================
+ * Displacement helpers
+ */
+
+static void subdiv_accumulate_vertex_displacement(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ MVert *subdiv_vert)
+{
+ float dummy_P[3], dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
+ BKE_subdiv_eval_displacement(subdiv,
+ ptex_face_index, u, v,
+ dPdu, dPdv,
+ D);
+ add_v3_v3(subdiv_vert->co, D);
+ if (subdiv_vert->flag & ME_VERT_TMP_TAG) {
+ mul_v3_fl(subdiv_vert->co, 0.5f);
+ }
+ subdiv_vert->flag |= ME_VERT_TMP_TAG;
+}
+
+/* =============================================================================
+ * Callbacks.
+ */
+
+static bool subdiv_mesh_topology_info(
+ const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int num_edges,
+ const int num_loops,
+ const int num_polygons)
+{
+ SubdivMeshContext *subdiv_context = foreach_context->user_data;
+ subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template(
+ subdiv_context->coarse_mesh,
+ num_vertices,
+ num_edges,
+ 0,
+ num_loops,
+ num_polygons);
+ subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context);
+ return true;
+}
+
+/* =============================================================================
+ * Vertex subdivision process.
+ */
+
+static void subdiv_vertex_data_copy(
+ const SubdivMeshContext *ctx,
+ const MVert *coarse_vertex,
+ MVert *subdiv_vertex)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ const int coarse_vertex_index = coarse_vertex - coarse_mesh->mvert;
+ const int subdiv_vertex_index = subdiv_vertex - subdiv_mesh->mvert;
+ subdiv_vertex->flag &= ~ME_VERT_TMP_TAG;
+ CustomData_copy_data(&coarse_mesh->vdata,
+ &ctx->subdiv_mesh->vdata,
+ coarse_vertex_index,
+ subdiv_vertex_index,
+ 1);
+}
+
+static void subdiv_vertex_data_interpolate(
+ const SubdivMeshContext *ctx,
+ MVert *subdiv_vertex,
+ const VerticesForInterpolation *vertex_interpolation,
+ const float u, const float v)
+{
+ const int subdiv_vertex_index = subdiv_vertex - ctx->subdiv_mesh->mvert;
+ const float weights[4] = {(1.0f - u) * (1.0f - v),
+ u * (1.0f - v),
+ u * v,
+ (1.0f - u) * v};
+ subdiv_vertex->flag &= ~ME_VERT_TMP_TAG;
+ CustomData_interp(vertex_interpolation->vertex_data,
+ &ctx->subdiv_mesh->vdata,
+ vertex_interpolation->vertex_indices,
+ weights, NULL,
+ 4,
+ subdiv_vertex_index);
+ if (ctx->vert_origindex != NULL) {
+ ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
+ }
+}
+
+static void evaluate_vertex_and_apply_displacement_copy(
+ const SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u, const float v,
+ const MVert *coarse_vert,
+ MVert *subdiv_vert)
+{
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data from original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
+ subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ ctx->subdiv,
+ ptex_face_index,
+ u, v,
+ subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
+}
+
+static void evaluate_vertex_and_apply_displacement_interpolate(
+ const SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u, const float v,
+ VerticesForInterpolation *vertex_interpolation,
+ MVert *subdiv_vert)
+{
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data from original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
+ subdiv_vertex_data_interpolate(ctx,
+ subdiv_vert,
+ vertex_interpolation,
+ u, v);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ ctx->subdiv,
+ ptex_face_index,
+ u, v,
+ subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
+}
+
+static void subdiv_mesh_vertex_every_corner_or_edge(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ Subdiv *subdiv = ctx->subdiv;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_accumulate_vertex_displacement(
+ subdiv, ptex_face_index, u, v, subdiv_vert);
+}
+
+static void subdiv_mesh_vertex_every_corner(
+ const SubdivForeachContext *foreach_context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_vertex_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ subdiv_mesh_vertex_every_corner_or_edge(
+ foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
+}
+
+static void subdiv_mesh_vertex_every_edge(
+ const SubdivForeachContext *foreach_context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_edge_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ subdiv_mesh_vertex_every_corner_or_edge(
+ foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
+}
+
+static void subdiv_mesh_vertex_corner(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const MVert *coarse_vert = &coarse_mvert[coarse_vertex_index];
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ evaluate_vertex_and_apply_displacement_copy(
+ ctx, ptex_face_index, u, v, coarse_vert, subdiv_vert);
+}
+
+static void subdiv_mesh_ensure_vertex_interpolation(
+ SubdivMeshContext *ctx,
+ SubdivMeshTLS *tls,
+ const MPoly *coarse_poly,
+ const int coarse_corner)
+{
+ /* Check whether we've moved to another corner or polygon. */
+ if (tls->vertex_interpolation_initialized) {
+ if (tls->vertex_interpolation_coarse_poly != coarse_poly ||
+ tls->vertex_interpolation_coarse_corner != coarse_corner)
+ {
+ vertex_interpolation_end(&tls->vertex_interpolation);
+ tls->vertex_interpolation_initialized = false;
+ }
+ }
+ /* Initialize the interpolation. */
+ if (!tls->vertex_interpolation_initialized) {
+ vertex_interpolation_init(ctx, &tls->vertex_interpolation, coarse_poly);
+ }
+ /* Update it for a new corner if needed. */
+ if (!tls->vertex_interpolation_initialized ||
+ tls->vertex_interpolation_coarse_corner != coarse_corner)
+ {
+ vertex_interpolation_from_corner(
+ ctx, &tls->vertex_interpolation, coarse_poly, coarse_corner);
+ }
+ /* Store settings used for the current state of interpolator. */
+ tls->vertex_interpolation_initialized = true;
+ tls->vertex_interpolation_coarse_poly = coarse_poly;
+ tls->vertex_interpolation_coarse_corner = coarse_corner;
+}
+
+static void subdiv_mesh_vertex_edge(
+ const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_edge_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_mesh_ensure_vertex_interpolation(
+ ctx, tls, coarse_poly, coarse_corner);
+ evaluate_vertex_and_apply_displacement_interpolate(
+ ctx,
+ ptex_face_index, u, v,
+ &tls->vertex_interpolation,
+ subdiv_vert);
+}
+
+static void subdiv_mesh_vertex_inner(
+ const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_mesh_ensure_vertex_interpolation(
+ ctx, tls, coarse_poly, coarse_corner);
+ subdiv_vertex_data_interpolate(
+ ctx, subdiv_vert, &tls->vertex_interpolation, u, v);
+ eval_final_point_and_vertex_normal(
+ subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no);
+}
+
+/* =============================================================================
+ * Edge subdivision process.
+ */
+
+static void subdiv_copy_edge_data(
+ SubdivMeshContext *ctx,
+ MEdge *subdiv_edge,
+ const MEdge *coarse_edge)
+{
+ const int subdiv_edge_index = subdiv_edge - ctx->subdiv_mesh->medge;
+ if (coarse_edge == NULL) {
+ subdiv_edge->crease = 0;
+ subdiv_edge->bweight = 0;
+ subdiv_edge->flag = 0;
+ if (ctx->edge_origindex != NULL) {
+ ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE;
+ }
+ return;
+ }
+ const int coarse_edge_index = coarse_edge - ctx->coarse_mesh->medge;
+ CustomData_copy_data(&ctx->coarse_mesh->edata,
+ &ctx->subdiv_mesh->edata,
+ coarse_edge_index,
+ subdiv_edge_index,
+ 1);
+}
+
+static void subdiv_mesh_edge(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const int subdiv_edge_index,
+ const int subdiv_v1, const int subdiv_v2)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MEdge *subdiv_medge = subdiv_mesh->medge;
+ MEdge *subdiv_edge = &subdiv_medge[subdiv_edge_index];
+ const MEdge *coarse_edge = NULL;
+ if (coarse_edge_index != ORIGINDEX_NONE) {
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ coarse_edge = &coarse_medge[coarse_edge_index];
+ }
+ subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge);
+ subdiv_edge->v1 = subdiv_v1;
+ subdiv_edge->v2 = subdiv_v2;
+}
+
+/* =============================================================================
+ * Loops creation/interpolation.
+ */
+
+static void subdiv_interpolate_loop_data(
+ const SubdivMeshContext *ctx,
+ MLoop *subdiv_loop,
+ const LoopsForInterpolation *loop_interpolation,
+ const float u, const float v)
+{
+ const int subdiv_loop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
+ const float weights[4] = {(1.0f - u) * (1.0f - v),
+ u * (1.0f - v),
+ u * v,
+ (1.0f - u) * v};
+ CustomData_interp(loop_interpolation->loop_data,
+ &ctx->subdiv_mesh->ldata,
+ loop_interpolation->loop_indices,
+ weights, NULL,
+ 4,
+ subdiv_loop_index);
+ /* TODO(sergey): Set ORIGINDEX. */
+}
+
+static void subdiv_eval_uv_layer(SubdivMeshContext *ctx,
+ MLoop *subdiv_loop,
+ const int ptex_face_index,
+ const float u, const float v)
+{
+ if (ctx->num_uv_layers == 0) {
+ return;
+ }
+ Subdiv *subdiv = ctx->subdiv;
+ const int mloop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
+ MLoopUV *subdiv_loopuv = &ctx->uv_layers[layer_index][mloop_index];
+ BKE_subdiv_eval_face_varying(subdiv,
+ layer_index,
+ ptex_face_index,
+ u, v,
+ subdiv_loopuv->uv);
+ }
+}
+
+static void subdiv_mesh_ensure_loop_interpolation(
+ SubdivMeshContext *ctx,
+ SubdivMeshTLS *tls,
+ const MPoly *coarse_poly,
+ const int coarse_corner)
+{
+ /* Check whether we've moved to another corner or polygon. */
+ if (tls->loop_interpolation_initialized) {
+ if (tls->loop_interpolation_coarse_poly != coarse_poly ||
+ tls->loop_interpolation_coarse_corner != coarse_corner)
+ {
+ loop_interpolation_end(&tls->loop_interpolation);
+ tls->loop_interpolation_initialized = false;
+ }
+ }
+ /* Initialize the interpolation. */
+ if (!tls->loop_interpolation_initialized) {
+ loop_interpolation_init(ctx, &tls->loop_interpolation, coarse_poly);
+ }
+ /* Update it for a new corner if needed. */
+ if (!tls->loop_interpolation_initialized ||
+ tls->loop_interpolation_coarse_corner != coarse_corner)
+ {
+ loop_interpolation_from_corner(
+ ctx, &tls->loop_interpolation, coarse_poly, coarse_corner);
+ }
+ /* Store settings used for the current state of interpolator. */
+ tls->loop_interpolation_initialized = true;
+ tls->loop_interpolation_coarse_poly = coarse_poly;
+ tls->loop_interpolation_coarse_corner = coarse_corner;
+}
+
+static void subdiv_mesh_loop(
+ const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_loop_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_loop_index,
+ const int subdiv_vertex_index, const int subdiv_edge_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MLoop *subdiv_mloop = subdiv_mesh->mloop;
+ MLoop *subdiv_loop = &subdiv_mloop[subdiv_loop_index];
+ subdiv_mesh_ensure_loop_interpolation(
+ ctx, tls, coarse_poly, coarse_corner);
+ subdiv_interpolate_loop_data(
+ ctx, subdiv_loop, &tls->loop_interpolation, u, v);
+ subdiv_eval_uv_layer(ctx, subdiv_loop, ptex_face_index, u, v);
+ subdiv_loop->v = subdiv_vertex_index;
+ subdiv_loop->e = subdiv_edge_index;
+}
+
+/* =============================================================================
+ * Polygons subdivision process.
+ */
+
+static void subdiv_copy_poly_data(const SubdivMeshContext *ctx,
+ MPoly *subdiv_poly,
+ const MPoly *coarse_poly)
+{
+ const int coarse_poly_index = coarse_poly - ctx->coarse_mesh->mpoly;
+ const int subdiv_poly_index = subdiv_poly - ctx->subdiv_mesh->mpoly;
+ CustomData_copy_data(&ctx->coarse_mesh->pdata,
+ &ctx->subdiv_mesh->pdata,
+ coarse_poly_index,
+ subdiv_poly_index,
+ 1);
+}
+
+static void subdiv_mesh_poly(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_poly_index,
+ const int subdiv_poly_index,
+ const int start_loop_index, const int num_loops)
+{
+ BLI_assert(coarse_poly_index != ORIGINDEX_NONE);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MPoly *subdiv_mpoly = subdiv_mesh->mpoly;
+ MPoly *subdiv_poly = &subdiv_mpoly[subdiv_poly_index];
+ subdiv_copy_poly_data(ctx, subdiv_poly, coarse_poly);
+ subdiv_poly->loopstart = start_loop_index;
+ subdiv_poly->totloop = num_loops;
+}
+
+/* =============================================================================
+ * Loose elements subdivision process.
+ */
+
+static void subdiv_mesh_vertex_loose(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_vertex_index,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ const MVert *coarse_vertex = &coarse_mvert[coarse_vertex_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_vertex_data_copy(ctx, coarse_vertex, subdiv_vertex);
+}
+
+/* Get neighbor edges of the given one.
+ * - neighbors[0] is an edge adjacent to edge->v1.
+ * - neighbors[1] is an edge adjacent to edge->v1.
+ */
+static void find_edge_neighbors(const SubdivMeshContext *ctx,
+ const MEdge *edge,
+ const MEdge *neighbors[2])
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ neighbors[0] = NULL;
+ neighbors[1] = NULL;
+ for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
+ const MEdge *current_edge = &coarse_medge[edge_index];
+ if (current_edge == edge) {
+ continue;
+ }
+ if (ELEM(edge->v1, current_edge->v1, current_edge->v2)) {
+ neighbors[0] = current_edge;
+ }
+ if (ELEM(edge->v2, current_edge->v1, current_edge->v2)) {
+ neighbors[1] = current_edge;
+ }
+ }
+}
+
+static void points_for_loose_edges_interpolation_get(
+ SubdivMeshContext *ctx,
+ const MEdge *coarse_edge,
+ const MEdge *neighbors[2],
+ float points_r[4][3])
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ /* Middle points corresponds to the edge. */
+ copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co);
+ copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co);
+ /* Start point, duplicate from edge start if no neighbor. */
+ if (neighbors[0] != NULL) {
+ if (neighbors[0]->v1 == coarse_edge->v1) {
+ copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v2].co);
+ }
+ else {
+ copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v1].co);
+ }
+ }
+ else {
+ sub_v3_v3v3(points_r[0], points_r[1], points_r[2]);
+ add_v3_v3(points_r[0], points_r[1]);
+ }
+ /* End point, duplicate from edge end if no neighbor. */
+ if (neighbors[1] != NULL) {
+ if (neighbors[1]->v1 == coarse_edge->v2) {
+ copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v2].co);
+ }
+ else {
+ copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v1].co);
+ }
+ }
+ else {
+ sub_v3_v3v3(points_r[3], points_r[2], points_r[1]);
+ add_v3_v3(points_r[3], points_r[2]);
+ }
+}
+
+static void subdiv_mesh_vertex_of_loose_edge(
+ const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const float u,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ /* Find neighbors of the current loose edge. */
+ const MEdge *neighbors[2];
+ find_edge_neighbors(ctx, coarse_edge, neighbors);
+ /* Get points for b-spline interpolation. */
+ float points[4][3];
+ points_for_loose_edges_interpolation_get(
+ ctx, coarse_edge, neighbors, points);
+ /* Perform interpolation. */
+ float weights[4];
+ key_curve_position_weights(u, weights, KEY_BSPLINE);
+
+ MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
+ interp_v3_v3v3v3v3(subdiv_vertex->co,
+ points[0],
+ points[1],
+ points[2],
+ points[3],
+ weights);
+ /* Reset flags and such. */
+ subdiv_vertex->flag = 0;
+ subdiv_vertex->bweight = 0.0f;
+ /* Reset normal. */
+ subdiv_vertex->no[0] = 0.0f;
+ subdiv_vertex->no[1] = 0.0f;
+ subdiv_vertex->no[2] = 1.0f;
+}
+
+/* =============================================================================
+ * Initialization.
+ */
+
+static void setup_foreach_callbacks(SubdivForeachContext *foreach_context,
+ const Subdiv *subdiv)
+{
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ /* General information. */
+ foreach_context->topology_info = subdiv_mesh_topology_info;
+ /* Every boundary geometry. Used for dispalcement averaging. */
+ if (subdiv->displacement_evaluator != NULL) {
+ foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
+ foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge;
+ }
+ else {
+ foreach_context->vertex_every_corner = NULL;
+ foreach_context->vertex_every_edge = NULL;
+ }
+ foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
+ foreach_context->vertex_edge = subdiv_mesh_vertex_edge;
+ foreach_context->vertex_inner = subdiv_mesh_vertex_inner;
+ foreach_context->edge = subdiv_mesh_edge;
+ foreach_context->loop = subdiv_mesh_loop;
+ foreach_context->poly = subdiv_mesh_poly;
+ foreach_context->vertex_loose = subdiv_mesh_vertex_loose;
+ foreach_context->vertex_of_loose_edge = subdiv_mesh_vertex_of_loose_edge;
+ foreach_context->user_data_tls_free = subdiv_mesh_tls_free;
+}
+
+/* =============================================================================
+ * Public entry point.
+ */
+
+Mesh *BKE_subdiv_to_mesh(
+ Subdiv *subdiv,
+ const SubdivToMeshSettings *settings,
+ const Mesh *coarse_mesh)
+{
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ /* Make sure evaluator is up to date with possible new topology, and that
+ * is is refined for the new positions of coarse vertices.
+ */
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ /* This could happen in two situations:
+ * - OpenSubdiv is disabled.
+ * - Something totally bad happened, and OpenSubdiv rejected our
+ * topology.
+ * In either way, we can't safely continue.
+ */
+ if (coarse_mesh->totpoly) {
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ return NULL;
+ }
+ }
+ /* Initialize subdivion mesh creation context/ */
+ SubdivMeshContext subdiv_context = {0};
+ subdiv_context.coarse_mesh = coarse_mesh;
+ subdiv_context.subdiv = subdiv;
+ /* Multi-threaded traversal/evaluation. */
+ BKE_subdiv_stats_begin(&subdiv->stats,
+ SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ SubdivForeachContext foreach_context;
+ setup_foreach_callbacks(&foreach_context, subdiv);
+ SubdivMeshTLS tls = {0};
+ foreach_context.user_data = &subdiv_context;
+ foreach_context.user_data_tls_size = sizeof(SubdivMeshTLS);
+ foreach_context.user_data_tls = &tls;
+ BKE_subdiv_foreach_subdiv_geometry(subdiv,
+ &foreach_context,
+ settings,
+ coarse_mesh);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ Mesh *result = subdiv_context.subdiv_mesh;
+ // BKE_mesh_validate(result, true, true);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ if (subdiv->displacement_evaluator != NULL) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_stats.c b/source/blender/blenkernel/intern/subdiv_stats.c
new file mode 100644
index 00000000000..a0cd1d909b7
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_stats.c
@@ -0,0 +1,92 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_stats.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include <stdio.h>
+
+#include "PIL_time.h"
+
+void BKE_subdiv_stats_init(SubdivStats *stats)
+{
+ stats->topology_refiner_creation_time = 0.0;
+ stats->subdiv_to_mesh_time = 0.0;
+ stats->subdiv_to_mesh_geometry_time = 0.0;
+ stats->evaluator_creation_time = 0.0;
+ stats->evaluator_refine_time = 0.0;
+ stats->subdiv_to_ccg_time = 0.0;
+ stats->subdiv_to_ccg_elements_time = 0.0;
+}
+
+void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value)
+{
+ stats->begin_timestamp_[value] = PIL_check_seconds_timer();
+}
+
+void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value)
+{
+ stats->values_[value] =
+ PIL_check_seconds_timer() - stats->begin_timestamp_[value];
+}
+
+void BKE_subdiv_stats_print(const SubdivStats *stats)
+{
+#define STATS_PRINT_TIME(stats, value, description) \
+ do { \
+ if ((stats)->value > 0.0) { \
+ printf(" %s: %f (sec)\n", description, (stats)->value); \
+ } \
+ } while (false)
+
+ printf("Subdivision surface statistics:\n");
+
+ STATS_PRINT_TIME(stats,
+ topology_refiner_creation_time,
+ "Topology refiner creation time");
+ STATS_PRINT_TIME(stats,
+ subdiv_to_mesh_time,
+ "Subdivision to mesh time");
+ STATS_PRINT_TIME(stats,
+ subdiv_to_mesh_geometry_time,
+ " Geometry time");
+ STATS_PRINT_TIME(stats,
+ evaluator_creation_time,
+ "Evaluator creation time");
+ STATS_PRINT_TIME(stats,
+ evaluator_refine_time,
+ "Evaluator refine time");
+ STATS_PRINT_TIME(stats,
+ subdiv_to_ccg_time,
+ "Subdivision to CCG time");
+ STATS_PRINT_TIME(stats,
+ subdiv_to_ccg_elements_time,
+ " Elements time");
+
+#undef STATS_PRINT_TIME
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 3c4e1f92344..bba3e97cad7 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -69,6 +69,7 @@
#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
@@ -77,12 +78,6 @@
# include "BLI_array.h"
#endif
-#include "GPU_draw.h"
-#include "GPU_glew.h"
-#include "GPU_buffers.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
#include "CCGSubSurf.h"
#ifdef WITH_OPENSUBDIV
@@ -1050,43 +1045,6 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
int gridSideEdges;
int gridInternalEdges;
- /* code added in bmesh but works correctly without, commenting - campbell */
-#if 0
- int lasti, previ;
- i = lastface;
- lasti = 0;
- while (1) {
- previ = i;
- if (ccgdm->faceMap[i].startEdge >= edgeNum) {
- i -= fabsf(i - lasti) / 2.0f;
- }
- else if (ccgdm->faceMap[i].startEdge < edgeNum) {
- i += fabsf(i - lasti) / 2.0f;
- }
- else {
- break;
- }
-
- if (i < 0) {
- i = 0;
- break;
- }
-
- if (i > lastface) {
- i = lastface;
- break;
-
- }
-
- if (i == lasti)
- break;
-
- lasti = previ;
- }
-
- i = i > 0 ? i - 1 : i;
-#endif
-
i = 0;
while (i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) {
i++;
@@ -1766,47 +1724,7 @@ static void ccgDM_foreachMappedLoop(
}
}
-static void ccgDM_drawVerts(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- CCGVertIterator vi;
- CCGEdgeIterator ei;
- CCGFaceIterator fi;
-
- glBegin(GL_POINTS);
- for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
- CCGVert *v = ccgVertIterator_getCurrent(&vi);
- glVertex3fv(ccgSubSurf_getVertData(ss, v));
- }
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- int x;
-
- for (x = 1; x < edgeSize - 1; x++)
- glVertex3fv(ccgSubSurf_getEdgeData(ss, e, x));
- }
-
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- glVertex3fv(ccgSubSurf_getFaceCenterData(f));
- for (S = 0; S < numVerts; S++)
- for (x = 1; x < gridSize - 1; x++)
- glVertex3fv(ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
- for (S = 0; S < numVerts; S++)
- for (y = 1; y < gridSize - 1; y++)
- for (x = 1; x < gridSize - 1; x++)
- glVertex3fv(ccgSubSurf_getFaceGridData(ss, f, S, x, y));
- }
- glEnd();
-}
-
-static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
+static void UNUSED_FUNCTION(ccgdm_pbvh_update)(CCGDerivedMesh *ccgdm)
{
if (ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) {
CCGFace **faces;
@@ -1821,2179 +1739,6 @@ static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
}
}
-static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
-{
- GPUDrawObject *gdo;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): We currently only support all edges drawing. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
- ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
- }
- return;
- }
-#endif
-
- ccgdm_pbvh_update(ccgdm);
-
-/* old debug feature for edges, unsupported for now */
-#if 0
- int useAging = 0;
-
- if (!(G.f & G_BACKBUFSEL)) {
- CCGSubSurf *ss = ccgdm->ss;
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- /* it needs some way to upload this to VBO now */
- if (useAging) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
- }
-#endif
-
- GPU_edge_setup(dm);
- gdo = dm->drawObject;
- if (gdo->edges && gdo->points) {
- if (drawAllEdges && drawLooseEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, (gdo->totedge - gdo->totinterior) * 2);
- }
- else if (drawAllEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
- }
- else {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, gdo->tot_loose_edge_drawn * 2);
- }
- }
-
- if (gdo->edges && ccgdm->drawInteriorEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->interior_offset * 2, gdo->totinterior * 2);
- }
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawLooseEdges(DerivedMesh *dm)
-{
- int start;
- int count;
-
-#ifdef WITH_OPENSUBDIV
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): Needs implementation. */
- return;
- }
-#endif
-
- GPU_edge_setup(dm);
-
- start = (dm->drawObject->loose_edge_offset * 2);
- count = (dm->drawObject->interior_offset - dm->drawObject->loose_edge_offset) * 2;
-
- if (count) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
- }
-
- GPU_buffers_unbind();
-}
-
-static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3])
-{
- float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
- float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
-
- no[0] = b_dY * a_cZ - b_dZ * a_cY;
- no[1] = b_dZ * a_cX - b_dX * a_cZ;
- no[2] = b_dX * a_cY - b_dY * a_cX;
-
- normalize_v3(no);
-}
-
-
-static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
-{
- float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
- float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
- float no[3];
-
- no[0] = b_dY * a_cZ - b_dZ * a_cY;
- no[1] = b_dZ * a_cX - b_dX * a_cZ;
- no[2] = b_dX * a_cY - b_dY * a_cX;
-
- /* don't normalize, GL_NORMALIZE is enabled */
- glNormal3fv(no);
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_normal(
- DerivedMesh *dm, short *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int shademodel;
- int start = 0;
-
- /* we are in sculpt mode, disable loop normals (since they won't get updated) */
- if (ccgdm->pbvh)
- lnors = NULL;
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- const float (*ln)[3] = NULL;
-
- if (faceFlags) {
- shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT;
- }
- else {
- shademodel = GL_SMOOTH;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += gridFaces * gridFaces * numVerts * 4;
- }
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
-
- if (ln) {
- /* Can't use quad strips here... */
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- normal_float_to_short_v3(&varray[start + 0], ln[0]);
- normal_float_to_short_v3(&varray[start + 4], ln[3]);
- normal_float_to_short_v3(&varray[start + 8], ln[2]);
- normal_float_to_short_v3(&varray[start + 12], ln[1]);
-
- start += 16;
- ln += 4;
- }
- }
- }
- else if (shademodel == GL_SMOOTH) {
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- float *a = CCG_grid_elem_no(&key, faceGridData, x, y );
- float *b = CCG_grid_elem_no(&key, faceGridData, x + 1, y);
- float *c = CCG_grid_elem_no(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_no(&key, faceGridData, x, y + 1);
-
- normal_float_to_short_v3(&varray[start], a);
- normal_float_to_short_v3(&varray[start + 4], b);
- normal_float_to_short_v3(&varray[start + 8], c);
- normal_float_to_short_v3(&varray[start + 12], d);
-
- start += 16;
- }
- }
- }
- else {
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- float f_no[3];
- short f_no_s[3];
-
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y );
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y );
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_NormalFast(a, b, c, d, f_no);
- normal_float_to_short_v3(f_no_s, f_no);
-
- copy_v3_v3_short(&varray[start], f_no_s);
- copy_v3_v3_short(&varray[start + 4], f_no_s);
- copy_v3_v3_short(&varray[start + 8], f_no_s);
- copy_v3_v3_short(&varray[start + 12], f_no_s);
-
- start += 16;
- }
- }
- }
- }
- }
-}
-
-typedef struct FaceCount {
- unsigned int i_visible;
- unsigned int i_hidden;
- unsigned int i_tri_visible;
- unsigned int i_tri_hidden;
-} FaceCount;
-
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_triangles(
- DerivedMesh *dm, unsigned int *varray,
- const int *mat_orig_to_new)
-{
- GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials;
- const int gpu_totmat = dm->drawObject->totmaterial;
- const short dm_totmat = dm->totmat;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- short mat_nr = -1;
- int start;
- int totloops = 0;
- FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount");
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < gpu_totmat; i++) {
- fc[i].i_visible = 0;
- fc[i].i_tri_visible = 0;
- fc[i].i_hidden = gpumaterials[i].totpolys - 1;
- fc[i].i_tri_hidden = gpumaterials[i].totelements - 1;
- }
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- bool is_hidden;
- int mati;
-
- if (faceFlags) {
- mat_nr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat);
- is_hidden = (faceFlags[index].flag & ME_HIDE) != 0;
- }
- else {
- mat_nr = 0;
- is_hidden = false;
- }
- mati = mat_orig_to_new[mat_nr];
- gpumat = dm->drawObject->materials + mati;
-
- if (is_hidden) {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- start = gpumat->start + fc[mati].i_tri_hidden;
-
- varray[start--] = totloops;
- varray[start--] = totloops + 2;
- varray[start--] = totloops + 3;
-
- varray[start--] = totloops;
- varray[start--] = totloops + 1;
- varray[start--] = totloops + 2;
-
- fc[mati].i_tri_hidden -= 6;
-
- totloops += 4;
- }
- }
- }
- gpumat->polys[fc[mati].i_hidden--] = i;
- }
- else {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- start = gpumat->start + fc[mati].i_tri_visible;
-
- varray[start++] = totloops + 3;
- varray[start++] = totloops + 2;
- varray[start++] = totloops;
-
- varray[start++] = totloops + 2;
- varray[start++] = totloops + 1;
- varray[start++] = totloops;
-
- fc[mati].i_tri_visible += 6;
-
- totloops += 4;
- }
- }
- }
- gpumat->polys[fc[mati].i_visible++] = i;
- }
- }
-
- /* set the visible polygons */
- for (i = 0; i < gpu_totmat; i++) {
- gpumaterials[i].totvisiblepolys = fc[i].i_visible;
- }
-
- MEM_freeN(fc);
-}
-
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_vertex(
- DerivedMesh *dm, void *varray_p)
-{
- float *varray = varray_p;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int totedge = ccgSubSurf_getNumEdges(ss);
- int start = 0;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- copy_v3_v3(&varray[start], a);
- copy_v3_v3(&varray[start + 3], b);
- copy_v3_v3(&varray[start + 6], c);
- copy_v3_v3(&varray[start + 9], d);
-
- start += 12;
- }
- }
- }
- }
-
- /* upload loose points */
- for (i = 0; i < totedge; i++) {
- CCGEdge *e = ccgdm->edgeMap[i].edge;
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
-
- if (!ccgSubSurf_getEdgeNumFaces(e)) {
- int j = 0;
- for (j = 0; j < edgeSize; j++) {
- copy_v3_v3(&varray[start], CCG_elem_offset_co(&key, edgeData, j));
- start += 3;
- }
- }
- }
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_color(
- DerivedMesh *dm, unsigned char *varray,
- const void *user_data)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- const unsigned char *mloopcol = user_data;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
- int iface = 0;
-
- CCG_key_top_level(&key, ss);
-
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- copy_v4_v4_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]);
- copy_v4_v4_uchar(&varray[start + 4], &mloopcol[iface * 16 + 12]);
- copy_v4_v4_uchar(&varray[start + 8], &mloopcol[iface * 16 + 8]);
- copy_v4_v4_uchar(&varray[start + 12], &mloopcol[iface * 16 + 4]);
-
- start += 16;
- iface++;
- }
- }
- }
- }
-}
-
-static void ccgDM_buffer_copy_uv(
- DerivedMesh *dm, void *varray_p)
-{
- float *varray = varray_p;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- MLoopUV *mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- copy_v2_v2(&varray[start + 0], mloopuv[0].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[3].uv);
- copy_v2_v2(&varray[start + 4], mloopuv[2].uv);
- copy_v2_v2(&varray[start + 6], mloopuv[1].uv);
-
- mloopuv += 4;
- start += 8;
- }
- }
- }
- }
-}
-
-static void ccgDM_buffer_copy_uv_texpaint(
- DerivedMesh *dm, float *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int dm_totmat = dm->totmat;
- MLoopUV **mloopuv_base;
- MLoopUV *stencil_base;
- int stencil;
-
- CCG_key_top_level(&key, ss);
-
- /* should have been checked for before, reassert */
- BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV));
- mloopuv_base = MEM_mallocN(dm_totmat * sizeof(*mloopuv_base), "texslots");
-
- for (i = 0; i < dm_totmat; i++) {
- mloopuv_base[i] = DM_paint_uvlayer_active_get(dm, i);
- }
-
- stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV);
- stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil);
-
- start = 0;
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int matnr;
-
- if (faceFlags) {
- matnr = faceFlags[index].mat_nr;
- }
- else {
- matnr = 0;
- }
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- /* divide by 4, gives us current loop-index */
- unsigned int i_ml = start / 4;
- copy_v2_v2(&varray[start + 0], mloopuv_base[matnr][i_ml + 0].uv);
- copy_v2_v2(&varray[start + 2], stencil_base[i_ml + 0].uv);
- copy_v2_v2(&varray[start + 4], mloopuv_base[matnr][i_ml + 3].uv);
- copy_v2_v2(&varray[start + 6], stencil_base[i_ml + 3].uv);
- copy_v2_v2(&varray[start + 8], mloopuv_base[matnr][i_ml + 2].uv);
- copy_v2_v2(&varray[start + 10], stencil_base[i_ml + 2].uv);
- copy_v2_v2(&varray[start + 12], mloopuv_base[matnr][i_ml + 1].uv);
- copy_v2_v2(&varray[start + 14], stencil_base[i_ml + 1].uv);
- start += 16;
- }
- }
- }
- }
-
- MEM_freeN(mloopuv_base);
-}
-
-static void ccgDM_buffer_copy_uvedge(
- DerivedMesh *dm, float *varray)
-{
- int i, totpoly;
- int start;
- const MLoopUV *mloopuv;
-#ifndef USE_LOOP_LAYOUT_FAST
- const MPoly *mpoly = dm->getPolyArray(dm);
-#endif
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- totpoly = dm->getNumPolys(dm);
- start = 0;
-
-#ifndef USE_LOOP_LAYOUT_FAST
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv);
- start += 4;
- }
- }
-#else
- for (i = 0; i < totpoly; i++) {
- copy_v2_v2(&varray[start + 0], mloopuv[(i * 4) + 0].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[(i * 4) + 1].uv);
-
- copy_v2_v2(&varray[start + 4], mloopuv[(i * 4) + 1].uv);
- copy_v2_v2(&varray[start + 6], mloopuv[(i * 4) + 2].uv);
-
- copy_v2_v2(&varray[start + 8], mloopuv[(i * 4) + 2].uv);
- copy_v2_v2(&varray[start + 10], mloopuv[(i * 4) + 3].uv);
-
- copy_v2_v2(&varray[start + 12], mloopuv[(i * 4) + 3].uv);
- copy_v2_v2(&varray[start + 14], mloopuv[(i * 4) + 0].uv);
-
- start += 16;
- }
-#endif
-}
-
-static void ccgDM_buffer_copy_edge(
- DerivedMesh *dm, unsigned int *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- /* getEdgeSuze returns num of verts, edges is one less */
- int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss) - 1;
- int totedge = ccgSubSurf_getNumEdges(ss);
- int grid_face_side = ccgSubSurf_getGridSize(ss) - 1;
- int totface = ccgSubSurf_getNumFaces(ss);
- unsigned int index_start;
- unsigned int tot_interior = 0;
- unsigned int grid_tot_face = grid_face_side * grid_face_side;
-
- unsigned int iloose, inorm, iloosehidden, inormhidden;
- unsigned int tot_loose_hidden = 0, tot_loose = 0;
- unsigned int tot_hidden = 0, tot = 0;
- unsigned int iloosevert;
- /* int tot_interior = 0; */
-
- /* first, handle hidden/loose existing edges, then interior edges */
- for (j = 0; j < totedge; j++) {
- CCGEdge *e = ccgdm->edgeMap[j].edge;
-
- if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) {
- if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose_hidden++;
- else tot_hidden++;
- }
- else {
- if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose++;
- else tot++;
- }
- }
-
- inorm = 0;
- inormhidden = tot * edgeSize;
- iloose = (tot + tot_hidden) * edgeSize;
- iloosehidden = (tot + tot_hidden + tot_loose) * edgeSize;
- iloosevert = dm->drawObject->tot_loop_verts;
-
- /* part one, handle all normal edges */
- for (j = 0; j < totedge; j++) {
- CCGFace *f;
- int fhandle = 0;
- int totvert = 0;
- unsigned int S = 0;
- CCGEdge *e = ccgdm->edgeMap[j].edge;
- bool isloose = !ccgSubSurf_getEdgeNumFaces(e);
-
- if (!isloose) {
- CCGVert *v1, *v2;
- CCGVert *ev1 = ccgSubSurf_getEdgeVert0(e);
- CCGVert *ev2 = ccgSubSurf_getEdgeVert1(e);
-
- f = ccgSubSurf_getEdgeFace(e, 0);
- fhandle = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- totvert = ccgSubSurf_getFaceNumVerts(f);
-
- /* find the index of vertices in the face */
- for (i = 0; i < totvert; i++) {
- v1 = ccgSubSurf_getFaceVert(f, i);
- v2 = ccgSubSurf_getFaceVert(f, (i + 1) % totvert);
-
- if ((ev1 == v1 && ev2 == v2) || (ev1 == v2 && ev2 == v1)) {
- S = i;
- break;
- }
- }
- }
-
- if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) {
- if (isloose) {
- for (i = 0; i < edgeSize; i++) {
- varray[iloosehidden * 2] = iloosevert;
- varray[iloosehidden * 2 + 1] = iloosevert + 1;
- iloosehidden++;
- iloosevert++;
- }
- /* we are through with this loose edge and moving to the next, so increase by one */
- iloosevert++;
- }
- else {
- index_start = ccgdm->faceMap[fhandle].startFace;
-
- for (i = 0; i < grid_face_side; i++) {
- varray[inormhidden * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1;
- varray[inormhidden * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2;
- varray[inormhidden * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2;
- varray[inormhidden * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3;
- inormhidden += 2;
- }
- }
- }
- else {
- if (isloose) {
- for (i = 0; i < edgeSize; i++) {
- varray[iloose * 2] = iloosevert;
- varray[iloose * 2 + 1] = iloosevert + 1;
- iloose++;
- iloosevert++;
- }
- /* we are through with this loose edge and moving to the next, so increase by one */
- iloosevert++;
- }
- else {
- index_start = ccgdm->faceMap[fhandle].startFace;
-
- for (i = 0; i < grid_face_side; i++) {
- varray[inorm * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1;
- varray[inorm * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2;
- varray[inorm * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2;
- varray[inorm * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3;
- inorm += 2;
- }
- }
- }
- }
-
- /* part two, handle interior edges */
- inorm = totedge * grid_face_side * 2;
-
- index_start = 0;
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- unsigned int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (x = 1; x < grid_face_side; x++) {
- for (y = 0; y < grid_face_side; y++) {
- unsigned int tmp = (index_start + x * grid_face_side + y) * 4;
- varray[inorm * 2] = tmp;
- varray[inorm * 2 + 1] = tmp + 1;
- inorm++;
- }
- }
- for (x = 0; x < grid_face_side; x++) {
- for (y = 0; y < grid_face_side; y++) {
- unsigned int tmp = (index_start + x * grid_face_side + y) * 4;
- varray[inorm * 2] = tmp + 3;
- varray[inorm * 2 + 1] = tmp;
- inorm++;
- }
- }
-
- tot_interior += grid_face_side * (2 * grid_face_side - 1);
- index_start += grid_tot_face;
- }
- }
-
- dm->drawObject->tot_loose_edge_drawn = tot_loose * edgeSize;
- dm->drawObject->loose_edge_offset = (tot + tot_hidden) * edgeSize;
- dm->drawObject->tot_edge_drawn = tot * edgeSize;
-
- dm->drawObject->interior_offset = totedge * edgeSize;
- dm->drawObject->totinterior = tot_interior;
-}
-
-static void ccgDM_copy_gpu_data(
- DerivedMesh *dm, int type, void *varray_p,
- const int *mat_orig_to_new, const void *user_data)
-{
- /* 'varray_p' cast is redundant but include for self-documentation */
- switch (type) {
- case GPU_BUFFER_VERTEX:
- ccgDM_buffer_copy_vertex(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_NORMAL:
- ccgDM_buffer_copy_normal(dm, (short *)varray_p);
- break;
- case GPU_BUFFER_UV:
- ccgDM_buffer_copy_uv(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_UV_TEXPAINT:
- ccgDM_buffer_copy_uv_texpaint(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_COLOR:
- ccgDM_buffer_copy_color(dm, (unsigned char *)varray_p, user_data);
- break;
- case GPU_BUFFER_UVEDGE:
- ccgDM_buffer_copy_uvedge(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_EDGE:
- ccgDM_buffer_copy_edge(dm, (unsigned int *)varray_p);
- break;
- case GPU_BUFFER_TRIANGLES:
- ccgDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new);
- break;
- default:
- break;
- }
-}
-
-static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- GPUDrawObject *gdo;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
- const short dm_totmat = (faceFlags) ? dm->totmat : 1;
- GPUBufferMaterial *matinfo;
- int i;
- unsigned int tot_internal_edges = 0;
- int edgeVerts = ccgSubSurf_getEdgeSize(ss);
- int edgeSize = edgeVerts - 1;
-
- int totedge = ccgSubSurf_getNumEdges(ss);
- int totface = ccgSubSurf_getNumFaces(ss);
-
- /* object contains at least one material (default included) so zero means uninitialized dm */
- BLI_assert(dm_totmat != 0);
-
- matinfo = MEM_callocN(sizeof(*matinfo) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new");
-
- if (faceFlags) {
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- const short new_matnr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat);
- matinfo[new_matnr].totelements += numVerts * gridFaces * gridFaces * 6;
- matinfo[new_matnr].totloops += numVerts * gridFaces * gridFaces * 4;
- matinfo[new_matnr].totpolys++;
- tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1);
- }
- }
- else {
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- matinfo[0].totelements += numVerts * gridFaces * gridFaces * 6;
- matinfo[0].totloops += numVerts * gridFaces * gridFaces * 4;
- matinfo[0].totpolys++;
- tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1);
- }
- }
-
- /* create the GPUDrawObject */
- gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
- gdo->totvert = 0; /* used to count indices, doesn't really matter for ccgsubsurf */
- gdo->totedge = (totedge * edgeSize + tot_internal_edges);
-
- GPU_buffer_material_finalize(gdo, matinfo, dm_totmat);
-
- /* store total number of points used for triangles */
- gdo->tot_triangle_point = ccgSubSurf_getNumFinalFaces(ss) * 6;
- gdo->tot_loop_verts = ccgSubSurf_getNumFinalFaces(ss) * 4;
-
- /* finally, count loose points */
- for (i = 0; i < totedge; i++) {
- CCGEdge *e = ccgdm->edgeMap[i].edge;
-
- if (!ccgSubSurf_getEdgeNumFaces(e))
- gdo->tot_loose_point += edgeVerts;
- }
-
- return gdo;
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial)
-{
- int a;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
- ccgdm_pbvh_update(ccgdm);
-
- if (ccgdm->pbvh && ccgdm->multires.mmd) {
- if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
- BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
- setMaterial, false, fast);
- }
-
- return;
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- CCGSubSurf *ss = ccgdm->ss;
- const DMFlagMat *faceFlags = ccgdm->faceFlags;
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int i, current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) {
- return;
- }
- if (setMaterial == NULL) {
- ccgSubSurf_drawGLMesh(ss,
- true,
- -1,
- -1);
- return;
- }
- 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;
- int new_matnr;
- bool new_draw_smooth;
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, NULL);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, NULL);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- for (a = 0; a < dm->drawObject->totmaterial; a++) {
- if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start,
- dm->drawObject->materials[a].totelements);
- }
- }
- GPU_buffers_unbind();
-}
-
-typedef struct {
- DMVertexAttribs attribs;
- int numdata;
-
- GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
-} GPUMaterialConv;
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- GPUVertexAttribs gattribs;
- int a, b;
- const DMFlagMat *faceFlags = ccgdm->faceFlags;
- unsigned char *varray;
- size_t max_element_size = 0;
- int tot_loops = 0;
- int totpoly = ccgSubSurf_getNumFaces(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int i, current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) {
- return;
- }
- 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;
- int new_matnr;
- bool new_draw_smooth;
-
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, &gattribs);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, &gattribs);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- if (setDrawOptions != NULL) {
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- DMVertexAttribs attribs = {{{NULL}}};
- int i;
- int matnr = -1;
- int do_draw = 0;
-
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
- DM_draw_attrib_vertex_uniforms(&attribs); \
-} (void)0
-
- totpoly = ccgSubSurf_getNumFaces(ss);
- for (a = 0, i = 0; i < totpoly; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const float (*ln)[3] = NULL;
- int S, x, y, drawSmooth;
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int origIndex = ccgDM_getFaceMapIndex(ss, f);
-
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int new_matnr;
-
- if (faceFlags) {
- drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
- new_matnr = faceFlags[index].mat_nr + 1;
- }
- else {
- drawSmooth = 1;
- new_matnr = 1;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- if (new_matnr != matnr) {
- do_draw = setMaterial(matnr = new_matnr, &gattribs);
- if (do_draw)
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- }
-
- if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) &&
- (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP)))
- {
- a += gridFaces * gridFaces * numVerts;
- continue;
- }
-
- glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- CCGElem *vda, *vdb;
-
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(ln[1]);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glNormal3fv(ln[2]);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glNormal3fv(ln[3]);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glNormal3fv(ln[0]);
- glVertex3fv(aco);
-
- ln += 4;
- a++;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 0);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- if (x != gridFaces - 1)
- a++;
- }
-
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 3);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 2);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- glEnd();
-
- a++;
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(aco, bco, cco, dco);
-
- PASSATTRIB(0, 1, 1);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glVertex3fv(aco);
-
- a++;
- }
- }
- glEnd();
- }
- }
- }
-
- glShadeModel(GL_SMOOTH);
-#undef PASSATTRIB
- }
- else {
- GPUMaterialConv *matconv;
- size_t offset;
- int *mat_orig_to_new;
- int tot_active_mat;
- GPUBuffer *buffer = NULL;
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
-
- tot_active_mat = dm->drawObject->totmaterial;
-
- matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat,
- "cdDM_drawMappedFacesGLSL.matconv");
- mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
- "cdDM_drawMappedFacesGLSL.mat_orig_to_new");
-
- /* part one, check what attributes are needed per material */
- for (a = 0; a < tot_active_mat; a++) {
- int new_matnr;
- int do_draw;
-
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- /* map from original material index to new
- * GPUBufferMaterial index */
- mat_orig_to_new[new_matnr] = a;
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- int numdata = 0;
- DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs);
-
- if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
- matconv[a].datatypes[numdata].size = 3;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- for (b = 0; b < matconv[a].attribs.tottface; b++) {
- if (matconv[a].attribs.tface[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 2;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.totmcol; b++) {
- if (matconv[a].attribs.mcol[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.tottang; b++) {
- if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- if (numdata != 0) {
- matconv[a].numdata = numdata;
- max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size);
- }
- }
- }
-
- /* part two, generate and fill the arrays with the data */
- if (max_element_size > 0) {
- buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
-
- varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
- if (varray == NULL) {
- GPU_buffers_unbind();
- GPU_buffer_free(buffer);
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- fprintf(stderr, "Out of memory, can't draw object\n");
- return;
- }
-
- for (a = 0; a < totpoly; a++) {
- CCGFace *f = ccgdm->faceMap[a].face;
- int orig_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int i;
-
- if (faceFlags) {
- i = mat_orig_to_new[faceFlags[orig_index].mat_nr];
- }
- else {
- i = mat_orig_to_new[0];
- }
-
- if (matconv[i].numdata != 0) {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
-
- offset = tot_loops * max_element_size;
-
- if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) {
- int index;
-
- index = getFaceIndex(ss, f, S, x, y, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x + 1, y, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + 2 * max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + 3 * max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
-
- offset += sizeof(float) * 3;
- }
- for (b = 0; b < matconv[i].attribs.tottface; b++) {
- if (matconv[i].attribs.tface[b].array) {
- const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array + tot_loops;
-
- copy_v2_v2((float *)&varray[offset], mloopuv[0].uv);
- copy_v2_v2((float *)&varray[offset + max_element_size], mloopuv[3].uv);
- copy_v2_v2((float *)&varray[offset + 2 * max_element_size], mloopuv[2].uv);
- copy_v2_v2((float *)&varray[offset + 3 * max_element_size], mloopuv[1].uv);
-
- offset += sizeof(float) * 2;
- }
- }
- for (b = 0; b < matconv[i].attribs.totmcol; b++) {
- if (matconv[i].attribs.mcol[b].array) {
- const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array + tot_loops;
-
- copy_v4_v4_uchar(&varray[offset], &mloopcol[0].r);
- copy_v4_v4_uchar(&varray[offset + max_element_size], &mloopcol[3].r);
- copy_v4_v4_uchar(&varray[offset + 2 * max_element_size], &mloopcol[2].r);
- copy_v4_v4_uchar(&varray[offset + 3 * max_element_size], &mloopcol[1].r);
-
- offset += sizeof(unsigned char) * 4;
- }
- }
- for (b = 0; b < matconv[i].attribs.tottang; b++) {
- if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops;
-
- copy_v4_v4((float *)&varray[offset], looptang[0]);
- copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
- copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
- copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
-
- offset += sizeof(float) * 4;
- }
- }
-
- tot_loops += 4;
- }
- }
- }
- }
- else {
- tot_loops += 4 * numVerts * gridFaces * gridFaces;
- }
- }
- GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY);
- }
-
- for (a = 0; a < tot_active_mat; a++) {
- int new_matnr;
- int do_draw;
-
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size);
- }
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_unbind();
- }
- }
- }
-
- GPU_buffers_unbind();
- if (buffer)
- GPU_buffer_free(buffer);
-
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- }
-}
-
-static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- GPUVertexAttribs gattribs;
- DMVertexAttribs attribs = {{{NULL}}};
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int a, i, numVerts, matnr, totface;
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
- return;
- }
- 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;
- int new_matnr;
- bool new_draw_smooth;
-
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- setMaterial(userData, mat_nr, &gattribs);
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- setMaterial(userData, mat_nr, &gattribs);
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- matnr = -1;
-
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
- DM_draw_attrib_vertex_uniforms(&attribs); \
-} (void)0
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (a = 0, i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const float (*ln)[3] = NULL;
- int S, x, y, drawSmooth;
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int origIndex = ccgDM_getFaceMapIndex(ss, f);
- int new_matnr;
-
- numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- /* get flags */
- if (faceFlags) {
- drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
- new_matnr = faceFlags[index].mat_nr + 1;
- }
- else {
- drawSmooth = 1;
- new_matnr = 1;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- /* material */
- if (new_matnr != matnr) {
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- }
-
- /* face hiding */
- if ((setFace && (origIndex != ORIGINDEX_NONE) && !setFace(userData, origIndex))) {
- a += gridFaces * gridFaces * numVerts;
- continue;
- }
-
- /* draw face*/
- glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- CCGElem *vda, *vdb;
-
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(ln[1]);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glNormal3fv(ln[2]);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glNormal3fv(ln[3]);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glNormal3fv(ln[0]);
- glVertex3fv(aco);
-
- ln += 4;
- a++;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- vda = CCG_grid_elem(&key, faceGridData, x, y);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 0);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- if (x != gridFaces - 1)
- a++;
- }
-
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 3);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 2);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- glEnd();
-
- a++;
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(aco, bco, cco, dco);
-
- PASSATTRIB(0, 1, 1);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glVertex3fv(aco);
-
- a++;
- }
- }
- glEnd();
- }
- }
- }
-
- glShadeModel(GL_SMOOTH);
-#undef PASSATTRIB
-}
-
-static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int colType;
- const MLoopCol *mloopcol = NULL;
- MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- DMDrawOption draw_option;
- int i, totpoly;
- bool flush;
- const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- unsigned int next_actualFace;
- unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
- int mat_index;
- int tot_element, start_element, tot_drawn;
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) {
- return;
- }
- if (drawParams == NULL) {
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
- return;
- }
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- 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;
- draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- }
- else {
- mat_nr = 0;
- draw_smooth = false;
- }
-
- if (drawParams != NULL) {
- MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
- }
- else {
- draw_option = (drawParamsMapped)
- ? drawParamsMapped(userData, i, mat_nr)
- : DM_DRAW_OPTION_NORMAL;
- }
-
- 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, 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;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- num_draw_patches += num_patches;
- }
- if (num_draw_patches != 0) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- start_draw_patch = current_patch;
- num_draw_patches = 0;
- }
- else {
- num_draw_patches += num_patches;
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- if (flag & DM_DRAW_USE_TEXPAINT_UV)
- GPU_texpaint_uv_setup(dm);
- else
- GPU_uv_setup(dm);
- if (mloopcol) {
- GPU_color_setup(dm, colType);
- }
-
- next_actualFace = 0;
-
- /* lastFlag = 0; */ /* UNUSED */
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- next_actualFace = bufmat->polys[0];
- totpoly = bufmat->totpolys;
-
- tot_element = 0;
- tot_drawn = 0;
- start_element = 0;
-
- for (i = 0; i < totpoly; i++) {
- int polyindex = bufmat->polys[i];
- CCGFace *f = ccgdm->faceMap[polyindex].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = ccgDM_getFaceMapIndex(ss, f);
- int orig_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int mat_nr;
- int facequads = numVerts * gridFaces * gridFaces;
- int actualFace = ccgdm->faceMap[polyindex].startFace;
-
- if (i != totpoly - 1) {
- polyindex = bufmat->polys[i + 1];
- next_actualFace = ccgdm->faceMap[polyindex].startFace;
- }
-
- if (faceFlags) {
- mat_nr = faceFlags[orig_index].mat_nr;
- }
- else {
- mat_nr = 0;
- }
-
- if (drawParams) {
- MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[actualFace] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
- }
- else if (index != ORIGINDEX_NONE)
- draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL;
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- /* flush buffer if current triangle isn't drawable or it's last triangle */
- flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- /* also compare draw options and flush buffer if they're different
- * need for face selection highlight in edit mode */
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_element += facequads * 6;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP)
- tot_drawn += facequads * 6;
-
- if (tot_drawn) {
- if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
- GPU_color_switch(1);
- else
- GPU_color_switch(0);
-
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
-
- start_element = tot_element;
- }
- else {
- tot_drawn += facequads * 6;
- }
- }
- }
-
-
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawFacesTex(DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
-}
-
-static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
-}
-
-/* same as cdDM_drawUVEdges */
-static void ccgDM_drawUVEdges(DerivedMesh *dm)
-{
- MPoly *mpoly = dm->getPolyArray(dm);
- int totpoly = dm->getNumPolys(dm);
- int prevstart = 0;
- bool prevdraw = true;
- int curpos = 0;
- int i;
-
- GPU_uvedge_setup(dm);
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
- if (prevdraw != draw) {
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- prevstart = curpos;
- }
-
- curpos += 2 * mpoly->totloop;
- prevdraw = draw;
- }
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawMappedFaces(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- MLoopCol *mloopcol = NULL;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int i, gridSize = ccgSubSurf_getGridSize(ss);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int useColors = flag & DM_DRAW_USE_COLORS;
- int gridFaces = gridSize - 1, totface;
- int prev_mat_nr = -1;
-
- if (ccgdm->pbvh) {
- if (G.debug_value == 14)
- BKE_pbvh_draw_BB(ccgdm->pbvh);
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- int new_matnr;
- bool draw_smooth, do_draw = true;
- if (setDrawOptions == NULL) {
- /* TODO(sergey): This is for cases when vertex colors or weights
- * are visualising. Currently we don't have CD layers for this data
- * and here we only make it so there's no garbage displayed.
- *
- * In the future we'll either need to have CD for this data or pass
- * this data as face-varying or vertex-varying data in OSD mesh.
- */
- glColor3f(0.8f, 0.8f, 0.8f);
- }
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
- return;
- }
- if (faceFlags) {
- draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
- new_matnr = (faceFlags[0].mat_nr + 1);
- }
- else {
- draw_smooth = true;
- new_matnr = 1;
- }
- if (setMaterial) {
- setMaterial(new_matnr, NULL);
- }
- if (setDrawOptions) {
- if (setDrawOptions(userData, 0) == DM_DRAW_OPTION_SKIP) {
- do_draw = false;
- }
- }
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
- glShadeModel(GL_SMOOTH);
- }
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
-
- /* currently unused -- each original face is handled separately */
- (void)compareDrawOptions;
-
- if (useColors) {
- mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL);
- if (!mloopcol)
- mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL);
- }
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
- int origIndex;
- unsigned char *cp = NULL;
- const float (*ln)[3] = NULL;
-
- origIndex = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
-
- if (flag & DM_DRAW_ALWAYS_SMOOTH) drawSmooth = 1;
- else if (faceFlags) drawSmooth = (lnors || (faceFlags[origIndex].flag & ME_SMOOTH));
- else drawSmooth = 1;
-
- if (mloopcol) {
- cp = (unsigned char *)mloopcol;
- mloopcol += gridFaces * gridFaces * numVerts * 4;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- {
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (setMaterial) {
- int mat_nr = faceFlags ? faceFlags[origIndex].mat_nr + 1 : 1;
-
- if (mat_nr != prev_mat_nr) {
- setMaterial(mat_nr, NULL); /* XXX, no faceFlags no material */
- prev_mat_nr = mat_nr;
- }
- }
-
- if (setDrawOptions && (index != ORIGINDEX_NONE))
- draw_option = setDrawOptions(userData, index);
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- if (draw_option == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[4]);
- glNormal3fv(ln[1]);
- glVertex3fv(d);
- if (cp) glColor4ubv(&cp[8]);
- glNormal3fv(ln[2]);
- glVertex3fv(c);
- if (cp) glColor4ubv(&cp[12]);
- glNormal3fv(ln[3]);
- glVertex3fv(b);
- if (cp) glColor4ubv(&cp[0]);
- glNormal3fv(ln[0]);
- glVertex3fv(a);
-
- if (cp) cp += 16;
- ln += 4;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- CCGElem *a, *b;
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- a = CCG_grid_elem(&key, faceGridData, x, y + 0);
- b = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[0]);
- glNormal3fv(CCG_elem_no(&key, a));
- glVertex3fv(CCG_elem_co(&key, a));
- if (cp) glColor4ubv(&cp[4]);
- glNormal3fv(CCG_elem_no(&key, b));
- glVertex3fv(CCG_elem_co(&key, b));
-
- if (x != gridFaces - 1) {
- if (cp) cp += 16;
- }
- }
-
- a = CCG_grid_elem(&key, faceGridData, x, y + 0);
- b = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[12]);
- glNormal3fv(CCG_elem_no(&key, a));
- glVertex3fv(CCG_elem_co(&key, a));
- if (cp) glColor4ubv(&cp[8]);
- glNormal3fv(CCG_elem_no(&key, b));
- glVertex3fv(CCG_elem_co(&key, b));
-
- if (cp) cp += 16;
-
- glEnd();
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(a, b, c, d);
-
- if (cp) glColor4ubv(&cp[4]);
- glVertex3fv(d);
- if (cp) glColor4ubv(&cp[8]);
- glVertex3fv(c);
- if (cp) glColor4ubv(&cp[12]);
- glVertex3fv(b);
- if (cp) glColor4ubv(&cp[0]);
- glVertex3fv(a);
-
- if (cp) cp += 16;
- }
- }
- glEnd();
- }
- }
- if (draw_option == DM_DRAW_OPTION_STIPPLE)
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- }
- }
-}
-
-static void ccgDM_drawMappedEdges(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGEdgeIterator ei;
- CCGKey key;
- int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): Only draw edges from base mesh. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
- if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) {
- ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
- }
- }
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
- int index = ccgDM_getEdgeMapIndex(ss, e);
-
- glBegin(GL_LINE_STRIP);
- if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) {
- if (useAging && !(G.f & G_BACKBUFSEL)) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
-
- for (i = 0; i < edgeSize - 1; i++) {
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i));
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i + 1));
- }
- }
- glEnd();
- }
-}
-
-static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetDrawInterpOptions setDrawInterpOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- CCGEdgeIterator ei;
- int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- BLI_assert(!"Not currently supported");
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
- int index = ccgDM_getEdgeMapIndex(ss, e);
-
- glBegin(GL_LINE_STRIP);
- if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) {
- for (i = 0; i < edgeSize; i++) {
- setDrawInterpOptions(userData, index, (float) i / (edgeSize - 1));
-
- if (useAging && !(G.f & G_BACKBUFSEL)) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
-
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i));
- }
- }
- glEnd();
- }
-}
-
static void ccgDM_foreachMappedFaceCenter(
DerivedMesh *dm,
void (*func)(void *userData, int index, const float co[3], const float no[3]),
@@ -4036,7 +1781,7 @@ static void ccgDM_release(DerivedMesh *dm)
if (ccgdm->multires.mmd) {
if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED)
- multires_modifier_update_mdisps(dm);
+ multires_modifier_update_mdisps(dm, NULL);
if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED)
multires_modifier_update_hidden(dm);
}
@@ -4534,7 +2279,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden);
}
else if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
@@ -4558,7 +2303,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
totvert = deformdm->getNumVerts(deformdm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert);
MEM_freeN(vertCos);
}
}
@@ -4671,23 +2416,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop;
ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
- ccgdm->dm.drawVerts = ccgDM_drawVerts;
- ccgdm->dm.drawEdges = ccgDM_drawEdges;
- ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
- ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
- ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
- ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL;
- ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
- ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
- ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
- ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat;
- ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
-
- ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
- ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
- ccgdm->dm.gpuObjectNew = ccgDM_GPUObjectNew;
- ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data;
-
ccgdm->dm.release = ccgDM_release;
}
@@ -4790,14 +2518,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0);
-#if 0
- /* this is not in trunk, can gives problems because colors initialize
- * as black, just don't do it!, it works fine - campbell */
- if (!CustomData_has_layer(&ccgdm->dm.faceData, CD_MCOL))
- DM_add_tessface_layer(&ccgdm->dm, CD_MCOL, CD_CALLOC, NULL);
- mcol = DM_get_tessface_data_layer(&ccgdm->dm, CD_MCOL);
-#endif
-
loopindex = loopindex2 = 0; /* current loop index */
for (index = 0; index < totface; index++) {
CCGFace *f = ccgdm->faceMap[index].face;
@@ -5139,8 +2859,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
*/
return
(flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
- (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) &&
- (openSubdiv_supportGPUDisplay());
+ (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
#else
(void)flags;
return false;
@@ -5150,12 +2869,13 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
+ struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags)
{
int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
- int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
+ int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
CCGDerivedMesh *result;
bool use_gpu_backend = subsurf_use_gpu_backend(flags);
@@ -5163,7 +2883,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
/* note: editmode calculation can only run once per
* modifier stack evaluation (uses freed cache) [#36299] */
if (flags & SUBSURF_FOR_EDIT_MODE) {
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
/* TODO(sergey): Same as emCache below. */
if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) {
@@ -5184,7 +2904,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
else if (flags & SUBSURF_USE_RENDER_PARAMS) {
/* Do not use cache in render mode. */
CCGSubSurf *ss;
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->renderLevels, true) : smd->renderLevels;
if (levels == 0)
return dm;
@@ -5200,7 +2920,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
}
else {
int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
CCGSubSurf *ss;
/* It is quite possible there is a much better place to do this. It
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 63b9f838632..3b9edaa4c18 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -47,8 +47,6 @@
#include "BLI_fileops.h"
#include "DNA_constraint_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -58,7 +56,6 @@
#include "DNA_node_types.h"
#include "DNA_material_types.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index bd6199d91b4..5031b2de462 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -44,9 +44,7 @@
#include "DNA_key_types.h"
#include "DNA_object_types.h"
-#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
-#include "DNA_world_types.h"
#include "DNA_brush_types.h"
#include "DNA_node_types.h"
#include "DNA_color_types.h"
@@ -213,22 +211,6 @@ void BKE_texture_free(Tex *tex)
}
MEM_SAFE_FREE(tex->coba);
- if (tex->env) {
- BKE_texture_envmap_free(tex->env);
- tex->env = NULL;
- }
- if (tex->pd) {
- BKE_texture_pointdensity_free(tex->pd);
- tex->pd = NULL;
- }
- if (tex->vd) {
- BKE_texture_voxeldata_free(tex->vd);
- tex->vd = NULL;
- }
- if (tex->ot) {
- BKE_texture_ocean_free(tex->ot);
- tex->ot = NULL;
- }
BKE_icon_id_delete((ID *)tex);
BKE_previewimg_free(&tex->preview);
@@ -251,7 +233,6 @@ void BKE_texture_default(Tex *tex)
tex->texfilter = TXF_EWA;
tex->afmax = 8;
tex->xrepeat = tex->yrepeat = 1;
- tex->fie_ima = 2;
tex->sfra = 1;
tex->frames = 0;
tex->offset = 0;
@@ -285,31 +266,6 @@ void BKE_texture_default(Tex *tex)
tex->vn_distm = 0;
tex->vn_coltype = 0;
- if (tex->env) {
- tex->env->stype = ENV_ANIM;
- tex->env->clipsta = 0.1;
- tex->env->clipend = 100;
- tex->env->cuberes = 512;
- tex->env->depth = 0;
- }
-
- if (tex->pd) {
- tex->pd->radius = 0.3f;
- tex->pd->falloff_type = TEX_PD_FALLOFF_STD;
- }
-
- if (tex->vd) {
- tex->vd->resol[0] = tex->vd->resol[1] = tex->vd->resol[2] = 0;
- tex->vd->interp_type = TEX_VD_LINEAR;
- tex->vd->file_format = TEX_VD_SMOKE;
- }
-
- if (tex->ot) {
- tex->ot->output = TEX_OCN_DISPLACEMENT;
- tex->ot->object = NULL;
- }
-
- tex->iuser.fie_ima = 2;
tex->iuser.ok = 1;
tex->iuser.frames = 100;
tex->iuser.sfra = 1;
@@ -319,26 +275,6 @@ void BKE_texture_default(Tex *tex)
void BKE_texture_type_set(Tex *tex, int type)
{
- switch (type) {
-
- case TEX_VOXELDATA:
- if (tex->vd == NULL)
- tex->vd = BKE_texture_voxeldata_add();
- break;
- case TEX_POINTDENSITY:
- if (tex->pd == NULL)
- tex->pd = BKE_texture_pointdensity_add();
- break;
- case TEX_ENVMAP:
- if (tex->env == NULL)
- tex->env = BKE_texture_envmap_add();
- break;
- case TEX_OCEAN:
- if (tex->ot == NULL)
- tex->ot = BKE_texture_ocean_add();
- break;
- }
-
tex->type = type;
}
@@ -476,10 +412,6 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
MEM_freeN(mtex_ar[slot]);
mtex_ar[slot] = NULL;
}
- else if (GS(id->name) == ID_MA) {
- /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
- ((Material *)id)->septex &= ~(1 << slot);
- }
mtex_ar[slot] = BKE_texture_mtex_add();
@@ -498,9 +430,6 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
*/
void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag)
{
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
-
if (!BKE_texture_is_image_user(tex_src)) {
tex_dst->ima = NULL;
}
@@ -508,19 +437,6 @@ void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const
if (tex_dst->coba) {
tex_dst->coba = MEM_dupallocN(tex_dst->coba);
}
- if (tex_dst->env) {
- tex_dst->env = BKE_texture_envmap_copy(tex_dst->env, flag_subdata);
- }
- if (tex_dst->pd) {
- tex_dst->pd = BKE_texture_pointdensity_copy(tex_dst->pd, flag_subdata);
- }
- if (tex_dst->vd) {
- tex_dst->vd = MEM_dupallocN(tex_dst->vd);
- }
- if (tex_dst->ot) {
- tex_dst->ot = BKE_texture_ocean_copy(tex_dst->ot, flag_subdata);
- }
-
if (tex_src->nodetree) {
if (tex_src->nodetree->execdata) {
ntreeTexEndExecTree(tex_src->nodetree->execdata);
@@ -565,19 +481,6 @@ Tex *BKE_texture_localize(Tex *tex)
/* image texture: BKE_texture_free also doesn't decrease */
if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
- if (texn->env) {
- texn->env = BKE_texture_envmap_copy(texn->env, LIB_ID_CREATE_NO_USER_REFCOUNT);
- id_us_min(&texn->env->ima->id);
- }
- if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd, LIB_ID_CREATE_NO_USER_REFCOUNT);
- if (texn->vd) {
- texn->vd = MEM_dupallocN(texn->vd);
- if (texn->vd->dataset)
- texn->vd->dataset = MEM_dupallocN(texn->vd->dataset);
- }
- if (texn->ot) {
- texn->ot = BKE_texture_ocean_copy(tex->ot, LIB_ID_CREATE_NO_USER_REFCOUNT);
- }
texn->preview = NULL;
@@ -585,6 +488,8 @@ Tex *BKE_texture_localize(Tex *tex)
texn->nodetree = ntreeLocalize(tex->nodetree);
}
+ texn->id.tag |= LIB_TAG_LOCALIZED;
+
return texn;
}
@@ -596,64 +501,6 @@ void BKE_texture_make_local(Main *bmain, Tex *tex, const bool lib_local)
BKE_id_make_local_generic(bmain, &tex->id, true, lib_local);
}
-Tex *give_current_object_texture(Object *ob)
-{
- Material *ma, *node_ma;
- Tex *tex = NULL;
-
- if (ob == NULL) return NULL;
- if (ob->totcol == 0 && !(ob->type == OB_LAMP)) return NULL;
-
- if (ob->type == OB_LAMP) {
- tex = give_current_lamp_texture(ob->data);
- }
- else {
- ma = give_current_material(ob, ob->actcol);
-
- if ((node_ma = give_node_material(ma)))
- ma = node_ma;
-
- tex = give_current_material_texture(ma);
- }
-
- return tex;
-}
-
-Tex *give_current_lamp_texture(Lamp *la)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
-
- if (la) {
- mtex = la->mtex[(int)(la->texact)];
- if (mtex) tex = mtex->tex;
- }
-
- return tex;
-}
-
-void set_current_lamp_texture(Lamp *la, Tex *newtex)
-{
- int act = la->texact;
-
- if (la->mtex[act] && la->mtex[act]->tex)
- id_us_min(&la->mtex[act]->tex->id);
-
- if (newtex) {
- if (!la->mtex[act]) {
- la->mtex[act] = BKE_texture_mtex_add();
- la->mtex[act]->texco = TEXCO_GLOB;
- }
-
- la->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (la->mtex[act]) {
- MEM_freeN(la->mtex[act]);
- la->mtex[act] = NULL;
- }
-}
-
Tex *give_current_linestyle_texture(FreestyleLineStyle *linestyle)
{
MTex *mtex = NULL;
@@ -689,55 +536,9 @@ void set_current_linestyle_texture(FreestyleLineStyle *linestyle, Tex *newtex)
}
}
-bNode *give_current_material_texture_node(Material *ma)
-{
- if (ma && ma->use_nodes && ma->nodetree)
- return nodeGetActiveID(ma->nodetree, ID_TE);
-
- return NULL;
-}
-
-Tex *give_current_material_texture(Material *ma)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
- bNode *node;
-
- if (ma && ma->use_nodes && ma->nodetree) {
- /* first check texture, then material, this works together
- * with a hack that clears the active ID flag for textures on
- * making a material node active */
- node = nodeGetActiveID(ma->nodetree, ID_TE);
-
- if (node) {
- tex = (Tex *)node->id;
- ma = NULL;
- }
- }
-
- if (ma) {
- mtex = ma->mtex[(int)(ma->texact)];
- if (mtex) tex = mtex->tex;
- }
-
- return tex;
-}
-
bool give_active_mtex(ID *id, MTex ***mtex_ar, short *act)
{
switch (GS(id->name)) {
- case ID_MA:
- *mtex_ar = ((Material *)id)->mtex;
- if (act) *act = (((Material *)id)->texact);
- break;
- case ID_WO:
- *mtex_ar = ((World *)id)->mtex;
- if (act) *act = (((World *)id)->texact);
- break;
- case ID_LA:
- *mtex_ar = ((Lamp *)id)->mtex;
- if (act) *act = (((Lamp *)id)->texact);
- break;
case ID_LS:
*mtex_ar = ((FreestyleLineStyle *)id)->mtex;
if (act) *act = (((FreestyleLineStyle *)id)->texact);
@@ -761,15 +562,6 @@ void set_active_mtex(ID *id, short act)
else if (act >= MAX_MTEX) act = MAX_MTEX - 1;
switch (GS(id->name)) {
- case ID_MA:
- ((Material *)id)->texact = act;
- break;
- case ID_WO:
- ((World *)id)->texact = act;
- break;
- case ID_LA:
- ((Lamp *)id)->texact = act;
- break;
case ID_LS:
((FreestyleLineStyle *)id)->texact = act;
break;
@@ -781,100 +573,6 @@ void set_active_mtex(ID *id, short act)
}
}
-void set_current_material_texture(Material *ma, Tex *newtex)
-{
- Tex *tex = NULL;
- bNode *node;
-
- if ((ma->use_nodes && ma->nodetree) &&
- (node = nodeGetActiveID(ma->nodetree, ID_TE)))
- {
- tex = (Tex *)node->id;
- id_us_min(&tex->id);
- if (newtex) {
- node->id = &newtex->id;
- id_us_plus(&newtex->id);
- }
- else {
- node->id = NULL;
- }
- }
- else {
- int act = (int)ma->texact;
-
- tex = (ma->mtex[act]) ? ma->mtex[act]->tex : NULL;
- id_us_min(&tex->id);
-
- if (newtex) {
- if (!ma->mtex[act]) {
- ma->mtex[act] = BKE_texture_mtex_add();
- /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
- ma->septex &= ~(1 << act);
- /* For volumes the default UV texture coordinates are not available. */
- if (ma->material_type == MA_TYPE_VOLUME) {
- ma->mtex[act]->texco = TEXCO_ORCO;
- }
- }
-
- ma->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (ma->mtex[act]) {
- MEM_freeN(ma->mtex[act]);
- ma->mtex[act] = NULL;
- }
- }
-}
-
-bool has_current_material_texture(Material *ma)
-{
- bNode *node;
-
- if (ma && ma->use_nodes && ma->nodetree) {
- node = nodeGetActiveID(ma->nodetree, ID_TE);
-
- if (node)
- return true;
- }
-
- return (ma != NULL);
-}
-
-Tex *give_current_world_texture(World *world)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
-
- if (!world) return NULL;
-
- mtex = world->mtex[(int)(world->texact)];
- if (mtex) tex = mtex->tex;
-
- return tex;
-}
-
-void set_current_world_texture(World *wo, Tex *newtex)
-{
- int act = wo->texact;
-
- if (wo->mtex[act] && wo->mtex[act]->tex)
- id_us_min(&wo->mtex[act]->tex->id);
-
- if (newtex) {
- if (!wo->mtex[act]) {
- wo->mtex[act] = BKE_texture_mtex_add();
- wo->mtex[act]->texco = TEXCO_VIEW;
- }
-
- wo->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (wo->mtex[act]) {
- MEM_freeN(wo->mtex[act]);
- wo->mtex[act] = NULL;
- }
-}
-
Tex *give_current_brush_texture(Brush *br)
{
return br->mtex.tex;
@@ -929,65 +627,6 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_texture_envmap_add(void)
-{
- EnvMap *env;
-
- env = MEM_callocN(sizeof(EnvMap), "envmap");
- env->type = ENV_CUBE;
- env->stype = ENV_ANIM;
- env->clipsta = 0.1;
- env->clipend = 100.0;
- env->cuberes = 512;
- env->viewscale = 0.5;
-
- return env;
-}
-
-/* ------------------------------------------------------------------------- */
-
-EnvMap *BKE_texture_envmap_copy(const EnvMap *env, const int flag)
-{
- EnvMap *envn;
- int a;
-
- envn = MEM_dupallocN(env);
- envn->ok = 0;
- for (a = 0; a < 6; a++) {
- envn->cube[a] = NULL;
- }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)envn->ima);
- }
-
- return envn;
-}
-
-/* ------------------------------------------------------------------------- */
-
-void BKE_texture_envmap_free_data(EnvMap *env)
-{
- unsigned int part;
-
- for (part = 0; part < 6; part++) {
- if (env->cube[part])
- IMB_freeImBuf(env->cube[part]);
- env->cube[part] = NULL;
- }
- env->ok = 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-void BKE_texture_envmap_free(EnvMap *env)
-{
-
- BKE_texture_envmap_free_data(env);
- MEM_freeN(env);
-
-}
-
-/* ------------------------------------------------------------------------- */
void BKE_texture_pointdensity_init_data(PointDensity *pd)
{
@@ -1060,77 +699,8 @@ void BKE_texture_pointdensity_free(PointDensity *pd)
BKE_texture_pointdensity_free_data(pd);
MEM_freeN(pd);
}
-
/* ------------------------------------------------------------------------- */
-void BKE_texture_voxeldata_free_data(VoxelData *vd)
-{
- if (vd->dataset) {
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- }
-
-}
-
-void BKE_texture_voxeldata_free(VoxelData *vd)
-{
- BKE_texture_voxeldata_free_data(vd);
- MEM_freeN(vd);
-}
-
-VoxelData *BKE_texture_voxeldata_add(void)
-{
- VoxelData *vd;
-
- vd = MEM_callocN(sizeof(VoxelData), "voxeldata");
- vd->dataset = NULL;
- vd->resol[0] = vd->resol[1] = vd->resol[2] = 1;
- vd->interp_type = TEX_VD_LINEAR;
- vd->file_format = TEX_VD_SMOKE;
- vd->int_multiplier = 1.0;
- vd->extend = TEX_CLIP;
- vd->object = NULL;
- vd->cachedframe = -1;
- vd->ok = 0;
-
- return vd;
-}
-
-VoxelData *BKE_texture_voxeldata_copy(VoxelData *vd)
-{
- VoxelData *vdn;
-
- vdn = MEM_dupallocN(vd);
- vdn->dataset = NULL;
-
- return vdn;
-}
-
-/* ------------------------------------------------------------------------- */
-
-OceanTex *BKE_texture_ocean_add(void)
-{
- OceanTex *ot;
-
- ot = MEM_callocN(sizeof(struct OceanTex), "ocean texture");
- ot->output = TEX_OCN_DISPLACEMENT;
- ot->object = NULL;
-
- return ot;
-}
-
-OceanTex *BKE_texture_ocean_copy(const OceanTex *ot, const int UNUSED(flag))
-{
- OceanTex *otn = MEM_dupallocN(ot);
-
- return otn;
-}
-
-void BKE_texture_ocean_free(struct OceanTex *ot)
-{
- MEM_freeN(ot);
-}
-
/**
* \returns true if this texture can use its #Texture.ima (even if its NULL)
*/
@@ -1141,15 +711,6 @@ bool BKE_texture_is_image_user(const struct Tex *tex)
{
return true;
}
- case TEX_ENVMAP:
- {
- if (tex->env) {
- if (tex->env->stype == ENV_LOAD) {
- return true;
- }
- }
- break;
- }
}
return false;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index a3536cd0d68..f19f27c85a7 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -61,6 +61,7 @@
#include "BKE_movieclip.h"
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_layer.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -398,17 +399,17 @@ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTrackin
/* Get transformation matrix for a given object which is used
* for parenting motion tracker reconstruction to 3D world.
*/
-void BKE_tracking_get_camera_object_matrix(Scene *scene, Object *ob, float mat[4][4])
+void BKE_tracking_get_camera_object_matrix(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float mat[4][4])
{
if (!ob) {
if (scene->camera)
ob = scene->camera;
else
- ob = BKE_scene_camera_find(scene);
+ ob = BKE_view_layer_camera_find(BKE_view_layer_context_active_PLACEHOLDER(scene));
}
if (ob)
- BKE_object_where_is_calc_mat4(scene, ob, mat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, ob, mat);
else
unit_m4(mat);
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 331db5b6ff0..aae9985bc24 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -982,7 +982,7 @@ static void initialize_track_for_stabilization(StabContext *ctx,
static void initialize_all_tracks(StabContext *ctx, float aspect)
{
- size_t i, track_cnt = 0;
+ size_t i, track_len = 0;
MovieClip *clip = ctx->clip;
MovieTracking *tracking = ctx->tracking;
MovieTrackingTrack *track;
@@ -1011,20 +1011,20 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
track);
local_data->is_init_for_stabilization = false;
- ++track_cnt;
+ ++track_len;
}
- if (!track_cnt) {
+ if (!track_len) {
return;
}
- order = MEM_mallocN(track_cnt * sizeof(TrackInitOrder),
+ order = MEM_mallocN(track_len * sizeof(TrackInitOrder),
"stabilization track order");
if (!order) {
return;
}
- track_cnt = establish_track_initialization_order(ctx, order);
- if (track_cnt == 0) {
+ track_len = establish_track_initialization_order(ctx, order);
+ if (track_len == 0) {
goto cleanup;
}
@@ -1032,7 +1032,7 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
average_marker_positions(ctx, reference_frame, average_pos);
setup_pivot(average_pos, pivot);
- for (i = 0; i < track_cnt; ++i) {
+ for (i = 0; i < track_len; ++i) {
track = order[i].data;
if (reference_frame != order[i].reference_frame) {
reference_frame = order[i].reference_frame;
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 0ebfb4065e4..abc53bf031a 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -39,6 +39,8 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_undo_system.h"
@@ -413,12 +415,21 @@ UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
}
+/**
+ * \param C: Can be NULL from some callers if their encoding function doesn't need it
+ */
bool BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
{
UNDO_NESTED_ASSERT(false);
undosys_stack_validate(ustack, false);
bool is_not_empty = ustack->step_active != NULL;
+ /* Might not be final place for this to be called - probably only want to call it from some
+ * undo handlers, not all of them? */
+ if (BKE_override_static_is_enabled()) {
+ BKE_main_override_static_operations_create(G.main, false);
+ }
+
/* Remove all undos after (also when 'ustack->step_active == NULL'). */
while (ustack->steps.last != ustack->step_active) {
UndoStep *us_iter = ustack->steps.last;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 3a903eb31c1..5527cb5d39a 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -35,6 +35,8 @@
#include "BLI_string.h"
#include "BLI_string_utf8.h"
+#include "DNA_scene_types.h"
+
#include "BKE_unit.h" /* own include */
#ifdef WIN32
@@ -90,6 +92,7 @@ typedef struct bUnitDef {
/* if name_short has non-ASCII chars, name_alt should be present */
const char *name_display; /* can be NULL */
+ const char *identifier; /* when NULL, a transformed version of the name will be taken */
double scalar;
double bias; /* not used yet, needed for converting temperature */
@@ -108,20 +111,23 @@ typedef struct bUnitCollection {
int length; /* to quickly find the last item */
} bUnitCollection;
+#define UNIT_COLLECTION_LENGTH(def) (sizeof(def) / sizeof(bUnitDef) - 1)
+#define NULL_UNIT {NULL, NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+
/* Dummy */
-static struct bUnitDef buDummyDef[] = { {"", NULL, "", NULL, NULL, 1.0, 0.0}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}};
+static struct bUnitDef buDummyDef[] = { {"", NULL, "", NULL, NULL, NULL, 1.0, 0.0}, NULL_UNIT};
static struct bUnitCollection buDummyCollection = {buDummyDef, 0, 0, sizeof(buDummyDef)};
/* Lengths */
-static const struct bUnitDef buMetricLenDef[] = {
- {"kilometer", "kilometers", "km", NULL, "Kilometers", UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
- {"hectometer", "hectometers", "hm", NULL, "100 Meters", UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"dekameter", "dekameters", "dam", NULL, "10 Meters", UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"meter", "meters", "m", NULL, "Meters", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"centimeter", "centimeters", "cm", NULL, "Centimeters", UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
- {"millimeter", "millimeters", "mm", NULL, "Millimeters", UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
- {"micrometer", "micrometers", "µm", "um", "Micrometers", UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
+static struct bUnitDef buMetricLenDef[] = {
+ {"kilometer", "kilometers", "km", NULL, "Kilometers", "KILOMETERS", UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
+ {"hectometer", "hectometers", "hm", NULL, "100 Meters", "HECTOMETERS", UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"dekameter", "dekameters", "dam", NULL, "10 Meters", "DEKAMETERS", UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"meter", "meters", "m", NULL, "Meters", "METERS", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", "DECIMETERS", UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"centimeter", "centimeters", "cm", NULL, "Centimeters", "CENTIMETERS", UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
+ {"millimeter", "millimeters", "mm", NULL, "Millimeters", "MILLIMETERS", UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
+ {"micrometer", "micrometers", "µm", "um", "Micrometers", "MICROMETERS", UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
/* These get displayed because of float precision problems in the transform header,
* could work around, but for now probably people wont use these */
@@ -129,163 +135,163 @@ static const struct bUnitDef buMetricLenDef[] = {
{"nanometer", "Nanometers", "nm", NULL, 0.000000001, 0.0, B_UNIT_DEF_NONE},
{"picometer", "Picometers", "pm", NULL, 0.000000000001, 0.0, B_UNIT_DEF_NONE},
#endif
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ NULL_UNIT
};
-static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, sizeof(buMetricLenDef) / sizeof(bUnitDef)};
+static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricLenDef)};
static struct bUnitDef buImperialLenDef[] = {
- {"mile", "miles", "mi", "m", "Miles", UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
- {"furlong", "furlongs", "fur", NULL, "Furlongs", UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
- {"chain", "chains", "ch", NULL, "Chains", UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
- {"yard", "yards", "yd", NULL, "Yards", UN_SC_YD, 0.0, B_UNIT_DEF_SUPPRESS},
- {"foot", "feet", "'", "ft", "Feet", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"inch", "inches", "\"", "in", "Inches", UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
- {"thou", "thou", "thou", "mil", "Thou", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, /* plural for thou has no 's' */
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"mile", "miles", "mi", "m", "Miles", "MILES", UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
+ {"furlong", "furlongs", "fur", NULL, "Furlongs", "FURLONGS", UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"chain", "chains", "ch", NULL, "Chains", "CHAINS", UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"yard", "yards", "yd", NULL, "Yards", "YARDS", UN_SC_YD, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"foot", "feet", "'", "ft", "Feet", "FEET", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"inch", "inches", "\"", "in", "Inches", "INCHES", UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
+ {"thou", "thou", "thou", "mil", "Thou", "THOU", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, /* plural for thou has no 's' */
+ NULL_UNIT
};
-static struct bUnitCollection buImperialLenCollection = {buImperialLenDef, 4, 0, sizeof(buImperialLenDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialLenCollection = {buImperialLenDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialLenDef)};
/* Areas */
static struct bUnitDef buMetricAreaDef[] = {
- {"square kilometer", "square kilometers", "km²", "km2", "Square Kilometers", UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
- {"square hectometer", "square hectometers", "hm²", "hm2", "Square Hectometers", UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, /* hectare */
- {"square dekameter", "square dekameters", "dam²", "dam2", "Square Dekameters", UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, /* are */
- {"square meter", "square meters", "m²", "m2", "Square Meters", UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"square decimeter", "square decimetees", "dm²", "dm2", "Square Decimeters", UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"square centimeter", "square centimeters", "cm²", "cm2", "Square Centimeters", UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
- {"square millimeter", "square millimeters", "mm²", "mm2", "Square Millimeters", UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
- {"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"square kilometer", "square kilometers", "km²", "km2", "Square Kilometers", NULL, UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
+ {"square hectometer", "square hectometers", "hm²", "hm2", "Square Hectometers", NULL, UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS}, /* hectare */
+ {"square dekameter", "square dekameters", "dam²", "dam2", "Square Dekameters", NULL, UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS}, /* are */
+ {"square meter", "square meters", "m²", "m2", "Square Meters", NULL, UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"square decimeter", "square decimetees", "dm²", "dm2", "Square Decimeters", NULL, UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"square centimeter", "square centimeters", "cm²", "cm2", "Square Centimeters", NULL, UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
+ {"square millimeter", "square millimeters", "mm²", "mm2", "Square Millimeters", NULL, UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
+ {"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", NULL, UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT
};
-static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, sizeof(buMetricAreaDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricAreaDef)};
static struct bUnitDef buImperialAreaDef[] = {
- {"square mile", "square miles", "sq mi", "sq m", "Square Miles", UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
- {"square furlong", "square furlongs", "sq fur", NULL, "Square Furlongs", UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
- {"square chain", "square chains", "sq ch", NULL, "Square Chains", UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
- {"square yard", "square yards", "sq yd", NULL, "Square Yards", UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
- {"square foot", "square feet", "sq ft", NULL, "Square Feet", UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"square inch", "square inches", "sq in", NULL, "Square Inches", UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
- {"square thou", "square thous", "sq mil", NULL, "Square Thous", UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"square mile", "square miles", "sq mi", "sq m", "Square Miles", NULL, UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
+ {"square furlong", "square furlongs", "sq fur", NULL, "Square Furlongs", NULL, UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"square chain", "square chains", "sq ch", NULL, "Square Chains", NULL, UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"square yard", "square yards", "sq yd", NULL, "Square Yards", NULL, UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
+ {"square foot", "square feet", "sq ft", NULL, "Square Feet", NULL, UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"square inch", "square inches", "sq in", NULL, "Square Inches", NULL, UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
+ {"square thou", "square thous", "sq mil", NULL, "Square Thous", NULL, UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT
};
-static struct bUnitCollection buImperialAreaCollection = {buImperialAreaDef, 4, 0, sizeof(buImperialAreaDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialAreaCollection = {buImperialAreaDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialAreaDef)};
/* Volumes */
static struct bUnitDef buMetricVolDef[] = {
- {"cubic kilometer", "cubic kilometers", "km³", "km3", "Cubic Kilometers", UN_SC_KM * UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
- {"cubic hectometer", "cubic hectometers", "hm³", "hm3", "Cubic Hectometers", UN_SC_HM * UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic dekameter", "cubic dekameters", "dam³", "dam3", "Cubic Dekameters", UN_SC_DAM * UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic meter", "cubic meters", "m³", "m3", "Cubic Meters", UN_SC_M * UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"cubic decimeter", "cubic decimeters", "dm³", "dm3", "Cubic Decimeters", UN_SC_DM * UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic centimeter", "cubic centimeters", "cm³", "cm3", "Cubic Centimeters", UN_SC_CM * UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
- {"cubic millimeter", "cubic millimeters", "mm³", "mm3", "Cubic Millimeters", UN_SC_MM * UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
- {"cubic micrometer", "cubic micrometers", "µm³", "um3", "Cubic Micrometers", UN_SC_UM * UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"cubic kilometer", "cubic kilometers", "km³", "km3", "Cubic Kilometers", NULL, UN_SC_KM * UN_SC_KM * UN_SC_KM, 0.0, B_UNIT_DEF_NONE},
+ {"cubic hectometer", "cubic hectometers", "hm³", "hm3", "Cubic Hectometers", NULL, UN_SC_HM * UN_SC_HM * UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic dekameter", "cubic dekameters", "dam³", "dam3", "Cubic Dekameters", NULL, UN_SC_DAM * UN_SC_DAM * UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic meter", "cubic meters", "m³", "m3", "Cubic Meters", NULL, UN_SC_M * UN_SC_M * UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"cubic decimeter", "cubic decimeters", "dm³", "dm3", "Cubic Decimeters", NULL, UN_SC_DM * UN_SC_DM * UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic centimeter", "cubic centimeters", "cm³", "cm3", "Cubic Centimeters", NULL, UN_SC_CM * UN_SC_CM * UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
+ {"cubic millimeter", "cubic millimeters", "mm³", "mm3", "Cubic Millimeters", NULL, UN_SC_MM * UN_SC_MM * UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
+ {"cubic micrometer", "cubic micrometers", "µm³", "um3", "Cubic Micrometers", NULL, UN_SC_UM * UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT
};
-static struct bUnitCollection buMetricVolCollection = {buMetricVolDef, 3, 0, sizeof(buMetricVolDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricVolCollection = {buMetricVolDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricVolDef)};
static struct bUnitDef buImperialVolDef[] = {
- {"cubic mile", "cubic miles", "cu mi", "cu m", "Cubic Miles", UN_SC_MI * UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
- {"cubic furlong", "cubic furlongs", "cu fur", NULL, "Cubic Furlongs", UN_SC_FUR * UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic chain", "cubic chains", "cu ch", NULL, "Cubic Chains", UN_SC_CH * UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
- {"cubic yard", "cubic yards", "cu yd", NULL, "Cubic Yards", UN_SC_YD * UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
- {"cubic foot", "cubic feet", "cu ft", NULL, "Cubic Feet", UN_SC_FT * UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"cubic inch", "cubic inches", "cu in", NULL, "Cubic Inches", UN_SC_IN * UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
- {"cubic thou", "cubic thous", "cu mil", NULL, "Cubic Thous", UN_SC_MIL * UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"cubic mile", "cubic miles", "cu mi", "cu m", "Cubic Miles", NULL, UN_SC_MI * UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
+ {"cubic furlong", "cubic furlongs", "cu fur", NULL, "Cubic Furlongs", NULL, UN_SC_FUR * UN_SC_FUR * UN_SC_FUR, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic chain", "cubic chains", "cu ch", NULL, "Cubic Chains", NULL, UN_SC_CH * UN_SC_CH * UN_SC_CH, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"cubic yard", "cubic yards", "cu yd", NULL, "Cubic Yards", NULL, UN_SC_YD * UN_SC_YD * UN_SC_YD, 0.0, B_UNIT_DEF_NONE},
+ {"cubic foot", "cubic feet", "cu ft", NULL, "Cubic Feet", NULL, UN_SC_FT * UN_SC_FT * UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"cubic inch", "cubic inches", "cu in", NULL, "Cubic Inches", NULL, UN_SC_IN * UN_SC_IN * UN_SC_IN, 0.0, B_UNIT_DEF_NONE},
+ {"cubic thou", "cubic thous", "cu mil", NULL, "Cubic Thous", NULL, UN_SC_MIL * UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT
};
-static struct bUnitCollection buImperialVolCollection = {buImperialVolDef, 4, 0, sizeof(buImperialVolDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialVolCollection = {buImperialVolDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialVolDef)};
/* Mass */
static struct bUnitDef buMetricMassDef[] = {
- {"ton", "tonnes", "ton", "t", "1000 Kilograms", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE},
- {"quintal", "quintals", "ql", "q", "100 Kilograms", UN_SC_QL, 0.0, B_UNIT_DEF_SUPPRESS},
- {"kilogram", "kilograms", "kg", NULL, "Kilograms", UN_SC_KG, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"hectogram", "hectograms", "hg", NULL, "Hectograms", UN_SC_HG, 0.0, B_UNIT_DEF_SUPPRESS},
- {"dekagram", "dekagrams", "dag", NULL, "10 Grams", UN_SC_DAG, 0.0, B_UNIT_DEF_SUPPRESS},
- {"gram", "grams", "g", NULL, "Grams", UN_SC_G, 0.0, B_UNIT_DEF_NONE},
- {"milligram", "milligrams", "mg", NULL, "Milligrams", UN_SC_MG, 0.0, B_UNIT_DEF_NONE},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"ton", "tonnes", "ton", "t", "Tonnes", "TONNES", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE},
+ {"quintal", "quintals", "ql", "q", "100 Kilograms", "QUINTALS", UN_SC_QL, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"kilogram", "kilograms", "kg", NULL, "Kilograms", "KILOGRAMS", UN_SC_KG, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"hectogram", "hectograms", "hg", NULL, "Hectograms", "HECTOGRAMS", UN_SC_HG, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"dekagram", "dekagrams", "dag", NULL, "10 Grams", "DEKAGRAMS", UN_SC_DAG, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"gram", "grams", "g", NULL, "Grams", "GRAMS", UN_SC_G, 0.0, B_UNIT_DEF_NONE},
+ {"milligram", "milligrams", "mg", NULL, "Milligrams", "MILLIGRAMS", UN_SC_MG, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT
};
-static struct bUnitCollection buMetricMassCollection = {buMetricMassDef, 2, 0, sizeof(buMetricMassDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricMassCollection = {buMetricMassDef, 2, 0, UNIT_COLLECTION_LENGTH(buMetricMassDef)};
static struct bUnitDef buImperialMassDef[] = {
- {"ton", "tonnes", "ton", "t", "Tonnes", UN_SC_ITON, 0.0, B_UNIT_DEF_NONE},
- {"centum weight", "centum weights", "cwt", NULL, "Centum weights", UN_SC_CWT, 0.0, B_UNIT_DEF_NONE},
- {"stone", "stones", "st", NULL, "Stones", UN_SC_ST, 0.0, B_UNIT_DEF_NONE},
- {"pound", "pounds", "lb", NULL, "Pounds", UN_SC_LB, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"ounce", "ounces", "oz", NULL, "Ounces", UN_SC_OZ, 0.0, B_UNIT_DEF_NONE},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"ton", "tonnes", "ton", "t", "Tonnes", "TONNES", UN_SC_ITON, 0.0, B_UNIT_DEF_NONE},
+ {"centum weight", "centum weights", "cwt", NULL, "Centum weights", "CENTUM_WEIGHTS", UN_SC_CWT, 0.0, B_UNIT_DEF_NONE},
+ {"stone", "stones", "st", NULL, "Stones", "STONES", UN_SC_ST, 0.0, B_UNIT_DEF_NONE},
+ {"pound", "pounds", "lb", NULL, "Pounds", "POUNDS", UN_SC_LB, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"ounce", "ounces", "oz", NULL, "Ounces", "OUNCES", UN_SC_OZ, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT
};
-static struct bUnitCollection buImperialMassCollection = {buImperialMassDef, 3, 0, sizeof(buImperialMassDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialMassCollection = {buImperialMassDef, 3, 0, UNIT_COLLECTION_LENGTH(buImperialMassDef)};
/* Even if user scales the system to a point where km^3 is used, velocity and
* acceleration aren't scaled: that's why we have so few units for them */
/* Velocity */
static struct bUnitDef buMetricVelDef[] = {
- {"meter per second", "meters per second", "m/s", NULL, "Meters per second", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"kilometer per hour", "kilometers per hour", "km/h", NULL, "Kilometers per hour", UN_SC_KM / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"meter per second", "meters per second", "m/s", NULL, "Meters per second", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"kilometer per hour", "kilometers per hour", "km/h", NULL, "Kilometers per hour", NULL, UN_SC_KM / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
+ NULL_UNIT
};
-static struct bUnitCollection buMetricVelCollection = {buMetricVelDef, 0, 0, sizeof(buMetricVelDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricVelCollection = {buMetricVelDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricVelDef)};
static struct bUnitDef buImperialVelDef[] = {
- {"foot per second", "feet per second", "ft/s", "fps", "Feet per second", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"mile per hour", "miles per hour", "mph", NULL, "Miles per hour", UN_SC_MI / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"foot per second", "feet per second", "ft/s", "fps", "Feet per second", NULL, UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"mile per hour", "miles per hour", "mph", NULL, "Miles per hour", NULL, UN_SC_MI / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
+ NULL_UNIT
};
-static struct bUnitCollection buImperialVelCollection = {buImperialVelDef, 0, 0, sizeof(buImperialVelDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialVelCollection = {buImperialVelDef, 0, 0, UNIT_COLLECTION_LENGTH(buImperialVelDef)};
/* Acceleration */
static struct bUnitDef buMetricAclDef[] = {
- {"meter per second squared", "meters per second squared", "m/s²", "m/s2", "Meters per second squared", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"meter per second squared", "meters per second squared", "m/s²", "m/s2", "Meters per second squared", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ NULL_UNIT
};
-static struct bUnitCollection buMetricAclCollection = {buMetricAclDef, 0, 0, sizeof(buMetricAclDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricAclCollection = {buMetricAclDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricAclDef)};
static struct bUnitDef buImperialAclDef[] = {
- {"foot per second squared", "feet per second squared", "ft/s²", "ft/s2", "Feet per second squared", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"foot per second squared", "feet per second squared", "ft/s²", "ft/s2", "Feet per second squared", NULL, UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ NULL_UNIT
};
-static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0, sizeof(buImperialAclDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0, UNIT_COLLECTION_LENGTH(buImperialAclDef)};
/* Time */
static struct bUnitDef buNaturalTimeDef[] = {
/* weeks? - probably not needed for blender */
- {"day", "days", "d", NULL, "Days", 90000.0, 0.0, B_UNIT_DEF_NONE},
- {"hour", "hours", "hr", "h", "Hours", 3600.0, 0.0, B_UNIT_DEF_NONE},
- {"minute", "minutes", "min", "m", "Minutes", 60.0, 0.0, B_UNIT_DEF_NONE},
- {"second", "seconds", "sec", "s", "Seconds", 1.0, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"millisecond", "milliseconds", "ms", NULL, "Milliseconds", 0.001, 0.0, B_UNIT_DEF_NONE},
- {"microsecond", "microseconds", "µs", "us", "Microseconds", 0.000001, 0.0, B_UNIT_DEF_NONE},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"day", "days", "d", NULL, "Days", "DAYS", 90000.0, 0.0, B_UNIT_DEF_NONE},
+ {"hour", "hours", "hr", "h", "Hours", "HOURS", 3600.0, 0.0, B_UNIT_DEF_NONE},
+ {"minute", "minutes", "min", "m", "Minutes", "MINUTES", 60.0, 0.0, B_UNIT_DEF_NONE},
+ {"second", "seconds", "sec", "s", "Seconds", "SECONDS", 1.0, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"millisecond", "milliseconds", "ms", NULL, "Milliseconds", "MILLISECONDS", 0.001, 0.0, B_UNIT_DEF_NONE},
+ {"microsecond", "microseconds", "µs", "us", "Microseconds", "MICROSECONDS", 0.000001, 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT
};
-static struct bUnitCollection buNaturalTimeCollection = {buNaturalTimeDef, 3, 0, sizeof(buNaturalTimeDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buNaturalTimeCollection = {buNaturalTimeDef, 3, 0, UNIT_COLLECTION_LENGTH(buNaturalTimeDef)};
static struct bUnitDef buNaturalRotDef[] = {
- {"degree", "degrees", "°", "d", "Degrees", M_PI / 180.0, 0.0, B_UNIT_DEF_NONE},
+ {"degree", "degrees", "°", "d", "Degrees", "DEGREES", M_PI / 180.0, 0.0, B_UNIT_DEF_NONE},
/* arcminutes/arcseconds are used in Astronomy/Navigation areas... */
- {"arcminute", "arcminutes", "'", NULL, "Arcminutes", (M_PI / 180.0) / 60.0, 0.0, B_UNIT_DEF_SUPPRESS},
- {"arcsecond", "arcseconds", "\"", NULL, "Arcseconds", (M_PI / 180.0) / 3600.0, 0.0, B_UNIT_DEF_SUPPRESS},
- {"radian", "radians", "r", NULL, "Radians", 1.0, 0.0, B_UNIT_DEF_NONE},
-// {"turn", "turns", "t", NULL, "Turns", 1.0 / (M_PI * 2.0), 0.0, B_UNIT_DEF_NONE},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"arcminute", "arcminutes", "'", NULL, "Arcminutes", "ARCMINUTES", (M_PI / 180.0) / 60.0, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"arcsecond", "arcseconds", "\"", NULL, "Arcseconds", "ARCSECONDS", (M_PI / 180.0) / 3600.0, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"radian", "radians", "r", NULL, "Radians", "RADIANS", 1.0, 0.0, B_UNIT_DEF_NONE},
+// {"turn", "turns", "t", NULL, "Turns", NULL, 1.0 / (M_PI * 2.0), 0.0, B_UNIT_DEF_NONE},
+ NULL_UNIT
};
-static struct bUnitCollection buNaturalRotCollection = {buNaturalRotDef, 0, 0, sizeof(buNaturalRotDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buNaturalRotCollection = {buNaturalRotDef, 0, 0, UNIT_COLLECTION_LENGTH(buNaturalRotDef)};
/* Camera Lengths */
static struct bUnitDef buCameraLenDef[] = {
- {"meter", "meters", "m", NULL, "Meters", UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, /* base unit */
- {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"centimeter", "centimeters", "cm", NULL, "Centimeters", UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
- {"millimeter", "millimeters", "mm", NULL, "Millimeters", UN_SC_M, 0.0, B_UNIT_DEF_NONE},
- {"micrometer", "micrometers", "µm", "um", "Micrometers", UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS},
- {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
+ {"meter", "meters", "m", NULL, "Meters", NULL, UN_SC_KM, 0.0, B_UNIT_DEF_NONE}, /* base unit */
+ {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", NULL, UN_SC_HM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"centimeter", "centimeters", "cm", NULL, "Centimeters", NULL, UN_SC_DAM, 0.0, B_UNIT_DEF_SUPPRESS},
+ {"millimeter", "millimeters", "mm", NULL, "Millimeters", NULL, UN_SC_M, 0.0, B_UNIT_DEF_NONE},
+ {"micrometer", "micrometers", "µm", "um", "Micrometers", NULL, UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS},
+ NULL_UNIT
};
-static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, sizeof(buCameraLenDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buCameraLenDef)};
#define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1)
@@ -341,9 +347,12 @@ static const bUnitDef *unit_best_fit(
static void unit_dual_convert(
double value, const bUnitCollection *usys,
bUnitDef const **r_unit_a, bUnitDef const **r_unit_b,
- double *r_value_a, double *r_value_b)
+ double *r_value_a, double *r_value_b,
+ const bUnitDef *main_unit)
{
- const bUnitDef *unit = unit_best_fit(value, usys, NULL, 1);
+ const bUnitDef *unit;
+ if (main_unit) unit = main_unit;
+ else unit = unit_best_fit(value, usys, NULL, 1);
*r_value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
*r_value_b = value - (*r_value_a);
@@ -405,17 +414,6 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con
while (unit->name_short[j] && (i < len_max)) {
str[i++] = unit->name_short[j++];
}
-#if 0
- if (pad) {
- /* this loop only runs if so many zeros were removed that
- * the unit name only used padded chars,
- * In that case add padding for the name. */
-
- while (i <= len + j && (i < len_max)) {
- str[i++] = pad;
- }
- }
-#endif
}
/* terminate no matter what's done with padding above */
@@ -426,43 +424,135 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con
return i;
}
-/* Used for drawing number buttons, try keep fast.
- * Return the length of the generated string.
- */
-size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
+static bool unit_should_be_split(int type)
{
- const bUnitCollection *usys = unit_get_system(system, type);
+ return ELEM(type, B_UNIT_LENGTH, B_UNIT_MASS, B_UNIT_TIME, B_UNIT_CAMERA);
+}
- if (usys == NULL || usys->units[0].name == NULL)
- usys = &buDummyCollection;
+typedef struct {
+ int system;
+ int rotation;
+ /* USER_UNIT_ADAPTIVE means none, otherwise the value is the index in the collection */
+ int length;
+ int mass;
+ int time;
+} PreferredUnits;
- /* split output makes sense only for length, mass and time */
- if (split && (type == B_UNIT_LENGTH || type == B_UNIT_MASS || type == B_UNIT_TIME || type == B_UNIT_CAMERA)) {
- const bUnitDef *unit_a, *unit_b;
- double value_a, value_b;
+static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings)
+{
+ PreferredUnits units = { 0 };
+ units.system = settings->system;
+ units.rotation = settings->system_rotation;
+ units.length = settings->length_unit;
+ units.mass = settings->mass_unit;
+ units.time = settings->time_unit;
+ return units;
+}
+
+static size_t unit_as_string_splitted(
+ char *str, int len_max, double value, int prec,
+ const bUnitCollection *usys, const bUnitDef *main_unit)
+{
+ const bUnitDef *unit_a, *unit_b;
+ double value_a, value_b;
- unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b);
+ unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b, main_unit);
- /* check the 2 is a smaller unit */
- if (unit_b > unit_a) {
- size_t i;
- i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');
+ /* check the 2 is a smaller unit */
+ if (unit_b > unit_a) {
+ size_t i;
+ i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');
- prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar);
- prec = max_ii(prec, 0);
+ prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar);
+ prec = max_ii(prec, 0);
- /* is there enough space for at least 1 char of the next unit? */
- if (i + 2 < len_max) {
- str[i++] = ' ';
+ /* is there enough space for at least 1 char of the next unit? */
+ if (i + 2 < len_max) {
+ str[i++] = ' ';
- /* use low precision since this is a smaller unit */
- i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0');
- }
- return i;
+ /* use low precision since this is a smaller unit */
+ i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0');
}
+ return i;
}
- return unit_as_string(str, len_max, value, prec, usys, NULL, pad ? ' ' : '\0');
+ return -1;
+}
+
+static bool is_valid_unit_collection(const bUnitCollection *usys)
+{
+ return usys != NULL && usys->units[0].name != NULL;
+}
+
+static const bUnitDef *get_preferred_unit_if_used(int type, PreferredUnits units)
+{
+ const bUnitCollection *usys = unit_get_system(units.system, type);
+ if (!is_valid_unit_collection(usys)) return NULL;
+
+ int max_offset = usys->length - 1;
+
+ switch (type) {
+ case B_UNIT_LENGTH:
+ case B_UNIT_AREA:
+ case B_UNIT_VOLUME:
+ if (units.length == USER_UNIT_ADAPTIVE) return NULL;
+ return usys->units + MIN2(units.length, max_offset);
+ case B_UNIT_MASS:
+ if (units.mass == USER_UNIT_ADAPTIVE) return NULL;
+ return usys->units + MIN2(units.mass, max_offset);
+ case B_UNIT_TIME:
+ if (units.time == USER_UNIT_ADAPTIVE) return NULL;
+ return usys->units + MIN2(units.time, max_offset);
+ case B_UNIT_ROTATION:
+ if (units.rotation == 0) return usys->units + 0;
+ else if (units.rotation == USER_UNIT_ROT_RADIANS) return usys->units + 3;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/* Return the length of the generated string. */
+static size_t unit_as_string_main(
+ char *str, int len_max, double value, int prec,
+ int type, bool split, bool pad, PreferredUnits units)
+{
+ const bUnitCollection *usys = unit_get_system(units.system, type);
+ const bUnitDef *main_unit = NULL;
+
+ if (!is_valid_unit_collection(usys)) {
+ usys = &buDummyCollection;
+ }
+ else {
+ main_unit = get_preferred_unit_if_used(type, units);
+ }
+
+ if (split && unit_should_be_split(type)) {
+ int length = unit_as_string_splitted(str, len_max, value, prec, usys, main_unit);
+ /* failed when length is negative, fallback to no split */
+ if (length >= 0) return length;
+ }
+
+ return unit_as_string(str, len_max, value, prec, usys, main_unit, pad ? ' ' : '\0');
+}
+
+size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
+{
+ PreferredUnits units;
+ units.system = system;
+ units.rotation = 0;
+ units.length = USER_UNIT_ADAPTIVE;
+ units.mass = USER_UNIT_ADAPTIVE;
+ units.time = USER_UNIT_ADAPTIVE;
+ return unit_as_string_main(str, len_max, value, prec, type, split, pad, units);
+}
+
+size_t bUnit_AsString2(char *str, int len_max, double value, int prec, int type, const UnitSettings *settings, bool pad)
+{
+ bool do_split = (settings->flag & USER_UNIT_OPT_SPLIT) != 0;
+ PreferredUnits units = preferred_units_from_UnitSettings(settings);
+ return unit_as_string_main(str, len_max, value, prec, type, do_split, pad, units);
}
BLI_INLINE bool isalpha_or_utf8(const int ch)
@@ -631,6 +721,27 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const c
return unit;
}
+bool bUnit_ContainsUnit(const char *str, int system, int type)
+{
+ const bUnitCollection *usys = unit_get_system(system, type);
+ if (!is_valid_unit_collection(usys)) return false;
+
+ for (int i = 0; i < usys->length; i++) {
+ if (unit_find(str, usys->units + i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+double bUnit_PreferredUnitScalar(const struct UnitSettings *settings, int type)
+{
+ PreferredUnits units = preferred_units_from_UnitSettings(settings);
+ const bUnitDef *unit = get_preferred_unit_if_used(type, units);
+ if (unit == NULL) return 1.0;
+ else return unit->scalar;
+}
+
/* make a copy of the string that replaces the units with numbers
* this is used before parsing
* This is only used when evaluating user input and can afford to be a bit slower
@@ -649,16 +760,13 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const c
bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
+ if (!is_valid_unit_collection(usys)) return false;
const bUnitDef *unit = NULL, *default_unit;
double scale_pref_base = scale_pref;
char str_tmp[TEMP_STR_SIZE];
bool changed = false;
- if (usys == NULL || usys->units[0].name == NULL) {
- return changed;
- }
-
/* make lowercase */
BLI_str_tolower_ascii(str, len_max);
@@ -824,6 +932,11 @@ int bUnit_GetBaseUnit(const void *usys_pt)
return ((bUnitCollection *)usys_pt)->base_unit;
}
+int bUnit_GetBaseUnitOfType(int system, int type)
+{
+ return unit_get_system(system, type)->base_unit;
+}
+
const char *bUnit_GetName(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name;
@@ -832,8 +945,21 @@ const char *bUnit_GetNameDisplay(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name_display;
}
+const char *bUnit_GetIdentifier(const void *usys_pt, int index)
+{
+ const bUnitDef *unit = ((const bUnitCollection *)usys_pt)->units + index;
+ if (unit->identifier == NULL) {
+ BLI_assert(false && "identifier for this unit is not specified yet");
+ }
+ return unit->identifier;
+}
double bUnit_GetScaler(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].scalar;
}
+
+bool bUnit_IsSuppressed(const void *usys_pt, int index)
+{
+ return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
+}
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
new file mode 100644
index 00000000000..0b1f9d8bd24
--- /dev/null
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -0,0 +1,446 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/workspace.c
+ * \ingroup bke
+ */
+
+/* allow accessing private members of DNA_workspace_types.h */
+#define DNA_PRIVATE_WORKSPACE_ALLOW
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.h"
+
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_object.h"
+#include "BKE_workspace.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Internal utils */
+
+static void workspace_layout_name_set(
+ WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+{
+ BLI_strncpy(layout->name, new_name, sizeof(layout->name));
+ BLI_uniquename(&workspace->layouts, layout, "Layout", '.', offsetof(WorkSpaceLayout, name), sizeof(layout->name));
+}
+
+/**
+ * This should only be used directly when it is to be expected that there isn't
+ * a layout within \a workspace that wraps \a screen. Usually - especially outside
+ * of BKE_workspace - #BKE_workspace_layout_find should be used!
+ */
+static WorkSpaceLayout *workspace_layout_find_exec(
+ const WorkSpace *workspace, const bScreen *screen)
+{
+ return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen));
+}
+
+static void workspace_relation_add(
+ ListBase *relation_list, void *parent, void *data)
+{
+ WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__);
+ relation->parent = parent;
+ relation->value = data;
+ /* add to head, if we switch back to it soon we find it faster. */
+ BLI_addhead(relation_list, relation);
+}
+static void workspace_relation_remove(
+ ListBase *relation_list, WorkSpaceDataRelation *relation)
+{
+ BLI_remlink(relation_list, relation);
+ MEM_freeN(relation);
+}
+
+static void workspace_relation_ensure_updated(
+ ListBase *relation_list, void *parent, void *data)
+{
+ WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ relation->value = data;
+ /* reinsert at the head of the list, so that more commonly used relations are found faster. */
+ BLI_remlink(relation_list, relation);
+ BLI_addhead(relation_list, relation);
+ }
+ else {
+ /* no matching relation found, add new one */
+ workspace_relation_add(relation_list, parent, data);
+ }
+}
+
+static void *workspace_relation_get_data_matching_parent(
+ const ListBase *relation_list, const void *parent)
+{
+ WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ return relation->value;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/**
+ * Checks if \a screen is already used within any workspace. A screen should never be assigned to multiple
+ * WorkSpaceLayouts, but that should be ensured outside of the BKE_workspace module and without such checks.
+ * Hence, this should only be used as assert check before assigining a screen to a workspace.
+ */
+#ifndef NDEBUG
+static bool workspaces_is_screen_used
+#else
+static bool UNUSED_FUNCTION(workspaces_is_screen_used)
+#endif
+ (const Main *bmain, bScreen *screen)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if (workspace_layout_find_exec(workspace, screen)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* -------------------------------------------------------------------- */
+/* Create, delete, init */
+
+WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
+{
+ WorkSpace *new_workspace = BKE_libblock_alloc(bmain, ID_WS, name, 0);
+ return new_workspace;
+}
+
+/**
+ * The function that actually frees the workspace data (not workspace itself). It shouldn't be called
+ * directly, instead #BKE_workspace_remove should be, which calls this through #BKE_libblock_free then.
+ *
+ * Should something like a bke_internal.h be added, this should go there!
+ */
+void BKE_workspace_free(WorkSpace *workspace)
+{
+ BKE_workspace_relations_free(&workspace->hook_layout_relations);
+
+ BLI_freelistN(&workspace->owner_ids);
+ BLI_freelistN(&workspace->layouts);
+
+ while (!BLI_listbase_is_empty(&workspace->tools)) {
+ BKE_workspace_tool_remove(workspace, workspace->tools.first);
+ }
+
+ if (workspace->status_text) {
+ MEM_freeN(workspace->status_text);
+ workspace->status_text = NULL;
+ }
+}
+
+/**
+ * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
+ * calls #BKE_workspace_free (through #BKE_libblock_free) to free the workspace data, and frees
+ * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
+ *
+ * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
+ */
+void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
+{
+ for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout; layout = layout_next) {
+ layout_next = layout->next;
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
+ BKE_libblock_free(bmain, workspace);
+}
+
+WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain)
+{
+ WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__);
+
+ /* set an active screen-layout for each possible window/workspace combination */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first);
+ }
+
+ return hook;
+}
+void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook)
+{
+ /* workspaces should never be freed before wm (during which we call this function) */
+ BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces));
+
+ /* Free relations for this hook */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
+ relation;
+ relation = relation_next)
+ {
+ relation_next = relation->next;
+ if (relation->parent == hook) {
+ workspace_relation_remove(&workspace->hook_layout_relations, relation);
+ }
+ }
+ }
+
+ MEM_freeN(hook);
+}
+
+/**
+ * Add a new layout to \a workspace for \a screen.
+ */
+WorkSpaceLayout *BKE_workspace_layout_add(
+ Main *bmain,
+ WorkSpace *workspace,
+ bScreen *screen,
+ const char *name)
+{
+ WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__);
+
+ BLI_assert(!workspaces_is_screen_used(bmain, screen));
+#ifndef DEBUG
+ UNUSED_VARS(bmain);
+#endif
+ layout->screen = screen;
+ id_us_plus(&layout->screen->id);
+ workspace_layout_name_set(workspace, layout, name);
+ BLI_addtail(&workspace->layouts, layout);
+
+ return layout;
+}
+
+void BKE_workspace_layout_remove(
+ Main *bmain,
+ WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ id_us_min(&layout->screen->id);
+ BKE_libblock_free(bmain, layout->screen);
+ BLI_freelinkN(&workspace->layouts, layout);
+}
+
+void BKE_workspace_relations_free(
+ ListBase *relation_list)
+{
+ for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) {
+ relation_next = relation->next;
+ workspace_relation_remove(relation_list, relation);
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+WorkSpaceLayout *BKE_workspace_layout_find(
+ const WorkSpace *workspace, const bScreen *screen)
+{
+ WorkSpaceLayout *layout = workspace_layout_find_exec(workspace, screen);
+ if (layout) {
+ return layout;
+ }
+
+ printf("%s: Couldn't find layout in this workspace: '%s' screen: '%s'. "
+ "This should not happen!\n",
+ __func__, workspace->id.name + 2, screen->id.name + 2);
+
+ return NULL;
+}
+
+/**
+ * Find the layout for \a screen without knowing which workspace to look in.
+ * Can also be used to find the workspace that contains \a screen.
+ *
+ * \param r_workspace: Optionally return the workspace that contains the looked up layout (if found).
+ */
+WorkSpaceLayout *BKE_workspace_layout_find_global(
+ const Main *bmain, const bScreen *screen,
+ WorkSpace **r_workspace)
+{
+ WorkSpaceLayout *layout;
+
+ if (r_workspace) {
+ *r_workspace = NULL;
+ }
+
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if ((layout = workspace_layout_find_exec(workspace, screen))) {
+ if (r_workspace) {
+ *r_workspace = workspace;
+ }
+
+ return layout;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Circular workspace layout iterator.
+ *
+ * \param callback: Custom function which gets executed for each layout. Can return false to stop iterating.
+ * \param arg: Custom data passed to each \a callback call.
+ *
+ * \return the layout at which \a callback returned false.
+ */
+WorkSpaceLayout *BKE_workspace_layout_iter_circular(
+ const WorkSpace *workspace, WorkSpaceLayout *start,
+ bool (*callback)(const WorkSpaceLayout *layout, void *arg),
+ void *arg, const bool iter_backward)
+{
+ WorkSpaceLayout *iter_layout;
+
+ if (iter_backward) {
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start);
+ }
+ else {
+ LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start)
+ }
+
+ return NULL;
+}
+
+void BKE_workspace_tool_remove(
+ struct WorkSpace *workspace, struct bToolRef *tref)
+{
+ if (tref->runtime) {
+ MEM_freeN(tref->runtime);
+ }
+ if (tref->properties) {
+ IDP_FreeProperty(tref->properties);
+ MEM_freeN(tref->properties);
+ }
+ BLI_remlink(&workspace->tools, tref);
+ MEM_freeN(tref);
+}
+
+/* -------------------------------------------------------------------- */
+/* Getters/Setters */
+
+WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook)
+{
+ return hook->active;
+}
+void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
+{
+ hook->active = workspace;
+ if (workspace) {
+ WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+ if (layout) {
+ hook->act_layout = layout;
+ }
+ }
+}
+
+WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
+{
+ return hook->act_layout;
+}
+void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout)
+{
+ hook->act_layout = layout;
+}
+
+bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook)
+{
+ return hook->act_layout->screen;
+}
+void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace, bScreen *screen)
+{
+ /* we need to find the WorkspaceLayout that wraps this screen */
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen);
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout);
+}
+
+ListBase *BKE_workspace_layouts_get(WorkSpace *workspace)
+{
+ return &workspace->layouts;
+}
+
+const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout)
+{
+ return layout->name;
+}
+void BKE_workspace_layout_name_set(WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+{
+ workspace_layout_name_set(workspace, layout, new_name);
+}
+
+bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout)
+{
+ return layout->screen;
+}
+void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen)
+{
+ layout->screen = screen;
+}
+
+WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+ const WorkSpaceInstanceHook *hook, const WorkSpace *workspace)
+{
+ return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+}
+void BKE_workspace_hook_layout_for_workspace_set(
+ WorkSpaceInstanceHook *hook, WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ hook->act_layout = layout;
+ workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
+}
+
+bool BKE_workspace_owner_id_check(
+ const WorkSpace *workspace, const char *owner_id)
+{
+ if ((*owner_id == '\0') ||
+ ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0))
+ {
+ return true;
+ }
+ else {
+ /* we could use hash lookup, for now this list is highly under < ~16 items. */
+ return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL;
+ }
+}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index a44d717bbdd..f4c32987117 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_world_types.h"
@@ -43,6 +44,7 @@
#include "BLI_listbase.h"
#include "BKE_animsys.h"
+#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -51,18 +53,18 @@
#include "BKE_node.h"
#include "BKE_world.h"
+#include "DRW_engine.h"
+
+#include "DEG_depsgraph.h"
+
#include "GPU_material.h"
/** Free (or release) any data used by this world (does not free the world itself). */
void BKE_world_free(World *wrld)
{
- int a;
-
BKE_animdata_free((ID *)wrld, false);
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(wrld->mtex[a]);
- }
+ DRW_drawdata_free((ID *)wrld);
/* is no lib link block, but world extension */
if (wrld->nodetree) {
@@ -84,23 +86,9 @@ void BKE_world_init(World *wrld)
wrld->horr = 0.05f;
wrld->horg = 0.05f;
wrld->horb = 0.05f;
- wrld->zenr = 0.01f;
- wrld->zeng = 0.01f;
- wrld->zenb = 0.01f;
- wrld->skytype = 0;
-
- wrld->exp = 0.0f;
- wrld->exposure = wrld->range = 1.0f;
wrld->aodist = 10.0f;
- wrld->aosamp = 5;
wrld->aoenergy = 1.0f;
- wrld->ao_env_energy = 1.0f;
- wrld->ao_indirect_energy = 1.0f;
- wrld->ao_indirect_bounces = 1;
- wrld->aobias = 0.05f;
- wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
- wrld->ao_approx_error = 0.25f;
wrld->preview = NULL;
wrld->miststa = 5.0f;
@@ -128,12 +116,6 @@ World *BKE_world_add(Main *bmain, const char *name)
*/
void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (wrld_src->mtex[a]) {
- wrld_dst->mtex[a] = MEM_dupallocN(wrld_src->mtex[a]);
- }
- }
-
if (wrld_src->nodetree) {
/* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
* (see BKE_libblock_copy_ex()). */
@@ -141,6 +123,7 @@ void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, co
}
BLI_listbase_clear(&wrld_dst->gpumaterial);
+ BLI_listbase_clear((ListBase *)&wrld_dst->drawdata);
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
BKE_previewimg_id_copy(&wrld_dst->id, &wrld_src->id);
@@ -170,23 +153,18 @@ World *BKE_world_localize(World *wrld)
* NOTE: Only possible once nested node trees are fully converted to that too. */
World *wrldn;
- int a;
wrldn = BKE_libblock_copy_nolib(&wrld->id, false);
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) {
- wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), __func__);
- memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
- }
- }
-
if (wrld->nodetree)
wrldn->nodetree = ntreeLocalize(wrld->nodetree);
wrldn->preview = NULL;
BLI_listbase_clear(&wrldn->gpumaterial);
+ BLI_listbase_clear((ListBase *)&wrldn->drawdata);
+
+ wrldn->id.tag |= LIB_TAG_LOCALIZED;
return wrldn;
}
@@ -195,3 +173,9 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
+
+void BKE_world_eval(struct Depsgraph *depsgraph, World *world)
+{
+ DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
+ GPU_material_free(&world->gpumaterial);
+}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 7e989b6588f..a1732b79ea3 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -43,6 +43,7 @@
#include "BLI_utildefines.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -84,10 +85,6 @@ static void context_free_avi(void *context_v);
# include "BKE_writeffmpeg.h"
#endif
-#ifdef WITH_FRAMESERVER
-# include "BKE_writeframeserver.h"
-#endif
-
bMovieHandle *BKE_movie_handle_get(const char imtype)
{
static bMovieHandle mh = {NULL};
@@ -121,16 +118,6 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.context_free = BKE_ffmpeg_context_free;
}
#endif
-#ifdef WITH_FRAMESERVER
- if (imtype == R_IMF_IMTYPE_FRAMESERVER) {
- mh.start_movie = BKE_frameserver_start;
- mh.append_movie = BKE_frameserver_append;
- mh.end_movie = BKE_frameserver_end;
- mh.get_next_frame = BKE_frameserver_loop;
- mh.context_create = BKE_frameserver_context_create;
- mh.context_free = BKE_frameserver_context_free;
- }
-#endif
/* in case all above are disabled */
(void)imtype;
@@ -211,8 +198,6 @@ static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int
avi->interlace = 0;
avi->odd_fields = 0;
-/* avi->interlace = rd->mode & R_FIELDS; */
-/* avi->odd_fields = (rd->mode & R_ODDFIELD) ? 1 : 0; */
printf("Created avi: %s\n", name);
return 1;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 68083b499f3..06f11301acb 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -45,8 +45,8 @@
#include "BLI_blenlib.h"
#ifdef WITH_AUDASPACE
-# include AUD_DEVICE_H
-# include AUD_SPECIAL_H
+# include <AUD_Device.h>
+# include <AUD_Special.h>
#endif
#include "BLI_utildefines.h"
@@ -54,6 +54,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_sound.h"
@@ -326,10 +327,6 @@ static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, A
frame->pts = cfra;
- if (rd->mode & R_FIELDS) {
- frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0);
- }
-
ret = avcodec_encode_video2(c, &packet, frame, &got_output);
if (ret >= 0 && got_output) {
@@ -611,14 +608,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
}
-#if 0
- /* this options are not set in ffmpeg.c and leads to artifacts with MPEG-4
- * see #33586: Encoding to mpeg4 makes first frame(s) blocky
- */
- c->rc_initial_buffer_occupancy = rd->ffcodecdata.rc_buffer_size * 3 / 4;
- c->rc_buffer_aggressivity = 1.0;
-#endif
-
/* Deprecated and not doing anything since July 2015, deleted in recent ffmpeg */
//c->me_method = ME_EPZS;
@@ -674,25 +663,11 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
}
- if ((of->oformat->flags & AVFMT_GLOBALHEADER)
-#if 0
- || STREQ(of->oformat->name, "mp4")
- || STREQ(of->oformat->name, "mov")
- || STREQ(of->oformat->name, "3gp")
-#endif
- )
- {
+ if ((of->oformat->flags & AVFMT_GLOBALHEADER)) {
PRINT("Using global header\n");
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
- /* Determine whether we are encoding interlaced material or not */
- if (rd->mode & R_FIELDS) {
- PRINT("Encoding interlaced video\n");
- c->flags |= CODEC_FLAG_INTERLACED_DCT;
- c->flags |= CODEC_FLAG_INTERLACED_ME;
- }
-
/* xasp & yasp got float lately... */
st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255);
@@ -1306,12 +1281,6 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{
PRINT("Closing ffmpeg...\n");
-#if 0
- if (context->audio_stream) { /* SEE UPPER */
- write_audio_frames(context);
- }
-#endif
-
#ifdef WITH_AUDASPACE
if (is_autosplit == false) {
if (context->audio_mixdown_device) {
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
deleted file mode 100644
index ebd6de6009e..00000000000
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * ***** 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.
- *
- * Copyright (c) 2006 Peter Schlaile
- *
- * Contributor(s):
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/writeframeserver.c
- * \ingroup bke
- *
- * Frameserver
- * Makes Blender accessible from TMPGenc directly using VFAPI (you can
- * use firefox too ;-)
- */
-
-#ifdef WITH_FRAMESERVER
-
-#include <string.h>
-#include <stdio.h>
-
-#if defined(_WIN32)
-#include <winsock2.h>
-#include <windows.h>
-#include <winbase.h>
-#include <direct.h>
-#else
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netdb.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#endif
-
-#include <stdlib.h>
-
-#include "DNA_userdef_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_writeframeserver.h"
-#include "BKE_global.h"
-#include "BKE_report.h"
-
-#include "DNA_scene_types.h"
-#include "MEM_guardedalloc.h"
-
-typedef struct FrameserverContext {
- int sock;
- int connsock;
- int write_ppm;
- int render_width;
- int render_height;
-} FrameserverContext;
-
-
-#if defined(_WIN32)
-static int startup_socket_system(void)
-{
- WSADATA wsa;
- return (WSAStartup(MAKEWORD(2, 0), &wsa) == 0);
-}
-
-static void shutdown_socket_system(void)
-{
- WSACleanup();
-}
-static int select_was_interrupted_by_signal(void)
-{
- return (WSAGetLastError() == WSAEINTR);
-}
-#else
-static int startup_socket_system(void)
-{
- return 1;
-}
-
-static void shutdown_socket_system(void)
-{
-}
-
-static int select_was_interrupted_by_signal(void)
-{
- return (errno == EINTR);
-}
-
-static int closesocket(int fd)
-{
- return close(fd);
-}
-#endif
-
-int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix))
-{
- struct sockaddr_in addr;
- int arg = 1;
- FrameserverContext *context = context_v;
-
- (void)scene; /* unused */
-
- if (!startup_socket_system()) {
- BKE_report(reports, RPT_ERROR, "Cannot startup socket system");
- return 0;
- }
-
- if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot open socket");
- return 0;
- }
-
- setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(U.frameserverport);
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot bind to socket");
- return 0;
- }
-
- if (listen(context->sock, SOMAXCONN) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog");
- return 0;
- }
- context->connsock = -1;
-
- context->render_width = rectx;
- context->render_height = recty;
-
- return 1;
-}
-
-static char index_page[] =
-"HTTP/1.1 200 OK\r\n"
-"Content-Type: text/html\r\n"
-"\r\n"
-"<html><head><title>Blender Frameserver</title></head>\n"
-"<body><pre>\n"
-"<H2>Blender Frameserver</H2>\n"
-"<A HREF=info.txt>Render Info</A><br>\n"
-"<A HREF=close.txt>Stop Rendering</A><br>\n"
-"\n"
-"Images can be found here\n"
-"\n"
-"images/ppm/%d.ppm\n"
-"\n"
-"</pre></body></html>\n";
-
-static char good_bye[] =
-"HTTP/1.1 200 OK\r\n"
-"Content-Type: text/html\r\n"
-"\r\n"
-"<html><head><title>Blender Frameserver</title></head>\n"
-"<body><pre>\n"
-"Render stopped. Goodbye</pre></body></html>";
-
-static int safe_write(const int connsock, char *s, int tosend)
-{
- int total = tosend;
- do {
- int got = send(connsock, s, tosend, 0);
- if (got < 0) {
- return got;
- }
- tosend -= got;
- s += got;
- } while (tosend > 0);
-
- return total;
-}
-
-static int safe_puts(const int connsock, char *s)
-{
- return safe_write(connsock, s, strlen(s));
-}
-
-static int handle_request(FrameserverContext *context, RenderData *rd, char *req)
-{
- char *p;
- char *path;
- int pathlen;
-
- if (memcmp(req, "GET ", 4) != 0) {
- return -1;
- }
-
- p = req + 4;
- path = p;
-
- while (*p != ' ' && *p) p++;
-
- *p = 0;
-
- if (STREQ(path, "/index.html") || STREQ(path, "/")) {
- safe_puts(context->connsock, index_page);
- return -1;
- }
-
- context->write_ppm = 0;
- pathlen = strlen(path);
-
- if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
- context->write_ppm = 1;
- return atoi(path + 12);
- }
- if (STREQ(path, "/info.txt")) {
- char buf[4096];
-
- sprintf(buf,
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html\r\n"
- "\r\n"
- "start %d\n"
- "end %d\n"
- "width %d\n"
- "height %d\n"
- "rate %d\n"
- "ratescale %d\n",
- rd->sfra,
- rd->efra,
- context->render_width,
- context->render_height,
- rd->frs_sec,
- 1
- );
-
- safe_puts(context->connsock, buf);
- return -1;
- }
- if (STREQ(path, "/close.txt")) {
- safe_puts(context->connsock, good_bye);
- G.is_break = true; /* Abort render */
- return -1;
- }
- return -1;
-}
-
-int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports))
-{
- fd_set readfds;
- struct timeval tv;
- struct sockaddr_in addr;
- int len, rval;
- unsigned int socklen;
- char buf[4096];
-
- FrameserverContext *context = context_v;
-
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
-
- tv.tv_sec = 1;
- tv.tv_usec = 0;
-
- FD_ZERO(&readfds);
- FD_SET(context->sock, &readfds);
-
- rval = select(context->sock + 1, &readfds, NULL, NULL, &tv);
- if (rval < 0) {
- return -1;
- }
-
- if (rval == 0) { /* nothing to be done */
- return -1;
- }
-
- socklen = sizeof(addr);
-
- if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) {
- return -1;
- }
-
- FD_ZERO(&readfds);
- FD_SET(context->connsock, &readfds);
-
- for (;;) {
- /* give 10 seconds for telnet testing... */
- tv.tv_sec = 10;
- tv.tv_usec = 0;
-
- rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv);
- if (rval > 0) {
- break;
- }
- else if (rval == 0) {
- return -1;
- }
- else if (rval < 0) {
- if (!select_was_interrupted_by_signal()) {
- return -1;
- }
- }
- }
-
- len = recv(context->connsock, buf, sizeof(buf) - 1, 0);
-
- if (len < 0) {
- return -1;
- }
-
- buf[len] = 0;
-
- return handle_request(context, rd, buf);
-}
-
-static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty)
-{
- unsigned char *rendered_frame;
- unsigned char *row = (unsigned char *) malloc(context->render_width * 3);
- int y;
- char header[1024];
-
- sprintf(header,
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: image/ppm\r\n"
- "Connection: close\r\n"
- "\r\n"
- "P6\n"
- "# Creator: blender frameserver v0.0.1\n"
- "%d %d\n"
- "255\n",
- rectx, recty);
-
- safe_puts(context->connsock, header);
-
- rendered_frame = (unsigned char *)pixels;
-
- for (y = recty - 1; y >= 0; y--) {
- unsigned char *target = row;
- unsigned char *src = rendered_frame + rectx * 4 * y;
- unsigned char *end = src + rectx * 4;
- while (src != end) {
- target[2] = src[2];
- target[1] = src[1];
- target[0] = src[0];
-
- target += 3;
- src += 4;
- }
- safe_write(context->connsock, (char *)row, 3 * rectx);
- }
- free(row);
- closesocket(context->connsock);
- context->connsock = -1;
-}
-
-int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
- int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
-{
- FrameserverContext *context = context_v;
-
- fprintf(stderr, "Serving frame: %d\n", frame);
- if (context->write_ppm) {
- serve_ppm(context, pixels, rectx, recty);
- }
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
-
- return 1;
-}
-
-void BKE_frameserver_end(void *context_v)
-{
- FrameserverContext *context = context_v;
-
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
- closesocket(context->sock);
- shutdown_socket_system();
-}
-
-void *BKE_frameserver_context_create(void)
-{
- FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context");
- return context;
-}
-
-void BKE_frameserver_context_free(void *context_v)
-{
- FrameserverContext *context = context_v;
- if (context) {
- MEM_freeN(context);
- }
-}
-
-#endif /* WITH_FRAMESERVER */
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
index 71937531dac..67728445f3a 100644
--- a/source/blender/blenkernel/nla_private.h
+++ b/source/blender/blenkernel/nla_private.h
@@ -33,6 +33,10 @@
#ifndef __NLA_PRIVATE_H__
#define __NLA_PRIVATE_H__
+struct Depsgraph;
+
+#include "RNA_types.h"
+
/* --------------- NLA Evaluation DataTypes ----------------------- */
/* used for list of strips to accumulate at current time */
@@ -66,9 +70,11 @@ enum eNlaEvalStrip_StripMode {
typedef struct NlaEvalChannel {
struct NlaEvalChannel *next, *prev;
- PointerRNA ptr; /* pointer to struct containing property to use */
- PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */
- int index; /* array index (where applicable) */
+ /* RNA reference to use with pointer and index */
+ PathResolvedRNA rna;
+
+ /* Original parameters used to look up the reference for write_orig_anim_rna */
+ const char *rna_path;
float value; /* value of this channel */
} NlaEvalChannel;
@@ -81,8 +87,8 @@ float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode);
/* --------------- NLA Evaluation (very-private stuff) ----------------------- */
/* these functions are only defined here to avoid problems with the order in which they get defined... */
-NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime);
-void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes);
-void nladata_flush_channels(ListBase *channels);
+NlaEvalStrip *nlastrips_ctime_get_strip(struct Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime);
+void nlastrip_evaluate(struct Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes);
+void nladata_flush_channels(struct Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels);
#endif /* __NLA_PRIVATE_H__ */
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index e8c92d9baff..8e873c76dc9 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -69,6 +69,12 @@ typedef unsigned int BLI_bitmap;
((_bitmap)[(_index) >> _BITMAP_POWER] & \
(1u << ((_index) & _BITMAP_MASK))))
+#define BLI_BITMAP_TEST_AND_SET_ATOMIC(_bitmap, _index) \
+ (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
+ (atomic_fetch_and_or_uint32((uint32_t*)&(_bitmap)[(_index) >> _BITMAP_POWER], \
+ (1u << ((_index) & _BITMAP_MASK))) & \
+ (1u << ((_index) & _BITMAP_MASK))))
+
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
(BLI_BITMAP_TEST(_bitmap, _index) != 0))
diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h
index 3db7d2d87f1..2bbd82f6db8 100644
--- a/source/blender/blenlib/BLI_callbacks.h
+++ b/source/blender/blenlib/BLI_callbacks.h
@@ -53,11 +53,10 @@ typedef enum {
BLI_CB_EVT_UNDO_POST,
BLI_CB_EVT_REDO_PRE,
BLI_CB_EVT_REDO_POST,
- BLI_CB_EVT_SCENE_UPDATE_PRE,
- BLI_CB_EVT_SCENE_UPDATE_POST,
- BLI_CB_EVT_GAME_PRE,
- BLI_CB_EVT_GAME_POST,
+ BLI_CB_EVT_DEPSGRAPH_UPDATE_PRE,
+ BLI_CB_EVT_DEPSGRAPH_UPDATE_POST,
BLI_CB_EVT_VERSION_UPDATE,
+ BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST,
BLI_CB_EVT_TOT
} eCbEvent;
diff --git a/source/blender/blenlib/BLI_expr_pylike_eval.h b/source/blender/blenlib/BLI_expr_pylike_eval.h
new file mode 100644
index 00000000000..578e4776038
--- /dev/null
+++ b/source/blender/blenlib/BLI_expr_pylike_eval.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.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation, Alexander Gavrilov
+ * All rights reserved.
+ *
+ * Contributor(s): Alexander Gavrilov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_EXPR_PYLIKE_EVAL_H__
+#define __BLI_EXPR_PYLIKE_EVAL_H__
+
+/** \file BLI_expr_pylike_eval.h
+ * \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Opaque structure containing pre-parsed data for evaluation. */
+typedef struct ExprPyLike_Parsed ExprPyLike_Parsed;
+
+/** Expression evaluation return code. */
+typedef enum eExprPyLike_EvalStatus {
+ EXPR_PYLIKE_SUCCESS = 0,
+ /* Computation errors; result is still set, but may be NaN */
+ EXPR_PYLIKE_DIV_BY_ZERO,
+ EXPR_PYLIKE_MATH_ERROR,
+ /* Expression dependent errors or bugs; result is 0 */
+ EXPR_PYLIKE_INVALID,
+ EXPR_PYLIKE_FATAL_ERROR,
+} eExprPyLike_EvalStatus;
+
+void BLI_expr_pylike_free(struct ExprPyLike_Parsed *expr);
+bool BLI_expr_pylike_is_valid(struct ExprPyLike_Parsed *expr);
+bool BLI_expr_pylike_is_constant(struct ExprPyLike_Parsed *expr);
+ExprPyLike_Parsed *BLI_expr_pylike_parse(
+ const char *expression,
+ const char **param_names, int param_names_len);
+eExprPyLike_EvalStatus BLI_expr_pylike_eval(
+ struct ExprPyLike_Parsed *expr,
+ const double *param_values, int param_values_len,
+ double *r_result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_EXPR_PYLIKE_EVAL_H__ */
diff --git a/source/blender/blenlib/BLI_graph.h b/source/blender/blenlib/BLI_graph.h
deleted file mode 100644
index 0b316d3c5bb..00000000000
--- a/source/blender/blenlib/BLI_graph.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Joshua Leung
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BLI_GRAPH_H__
-#define __BLI_GRAPH_H__
-
-/** \file BLI_graph.h
- * \ingroup bli
- */
-
-#include "DNA_listBase.h"
-
-struct BGraph;
-struct BNode;
-struct BArc;
-
-struct RadialArc;
-
-typedef void (*FreeArc)(struct BArc *);
-typedef void (*FreeNode)(struct BNode *);
-typedef void (*RadialSymmetry)(struct BNode *root_node, struct RadialArc *ring, int total);
-typedef void (*AxialSymmetry)(struct BNode *root_node, struct BNode *node1, struct BNode *node2, struct BArc *arc1, struct BArc *arc2);
-
-/* IF YOU MODIFY THOSE TYPES, YOU NEED TO UPDATE ALL THOSE THAT "INHERIT" FROM THEM
- *
- * RigGraph, ReebGraph
- *
- * */
-
-typedef struct BGraph {
- ListBase arcs;
- ListBase nodes;
-
- float length;
-
- /* function pointer to deal with custom fonctionnality */
- FreeArc free_arc;
- FreeNode free_node;
- RadialSymmetry radial_symmetry;
- AxialSymmetry axial_symmetry;
-} BGraph;
-
-typedef struct BNode {
- void *next, *prev;
- float p[3];
- int flag;
-
- int degree;
- struct BArc **arcs;
-
- int subgraph_index;
-
- int symmetry_level;
- int symmetry_flag;
- float symmetry_axis[3];
-} BNode;
-
-typedef struct BArc {
- void *next, *prev;
- struct BNode *head, *tail;
- int flag;
-
- float length;
-
- int symmetry_level;
- int symmetry_group;
- int symmetry_flag;
-} BArc;
-
-struct BArcIterator;
-
-void *IT_head(void *iter);
-void *IT_tail(void *iter);
-void *IT_peek(void *iter, int n);
-void *IT_next(void *iter);
-void *IT_nextN(void *iter, int n);
-void *IT_previous(void *iter);
-int IT_stopped(void *iter);
-
-typedef void * (*HeadFct)(void *iter);
-typedef void * (*TailFct)(void *iter);
-typedef void * (*PeekFct)(void *iter, int n);
-typedef void * (*NextFct)(void *iter);
-typedef void * (*NextNFct)(void *iter, int n);
-typedef void * (*PreviousFct)(void *iter);
-typedef int (*StoppedFct)(void *iter);
-
-typedef struct BArcIterator {
- HeadFct head;
- TailFct tail;
- PeekFct peek;
- NextFct next;
- NextNFct nextN;
- PreviousFct previous;
- StoppedFct stopped;
-
- float *p, *no;
- float size;
-
- int length;
- int index;
-} BArcIterator;
-
-/* Helper structure for radial symmetry */
-typedef struct RadialArc {
- struct BArc *arc;
- float n[3]; /* normalized vector joining the nodes of the arc */
-} RadialArc;
-
-BNode *BLI_otherNode(BArc *arc, BNode *node);
-
-void BLI_freeNode(BGraph *graph, BNode *node);
-void BLI_removeNode(BGraph *graph, BNode *node);
-
-void BLI_removeArc(BGraph *graph, BArc *arc);
-
-void BLI_flagNodes(BGraph *graph, int flag);
-void BLI_flagArcs(BGraph *graph, int flag);
-
-bool BLI_hasAdjacencyList(BGraph *rg);
-void BLI_buildAdjacencyList(BGraph *rg);
-void BLI_rebuildAdjacencyListForNode(BGraph *rg, BNode *node);
-void BLI_freeAdjacencyList(BGraph *rg);
-
-int BLI_FlagSubgraphs(BGraph *graph);
-void BLI_ReflagSubgraph(BGraph *graph, int old_subgraph, int new_subgraph);
-
-#define SHAPE_RADIX 10 /* each shape level is encoded this base */
-
-int BLI_subtreeShape(BGraph *graph, BNode *node, BArc *rootArc, int include_root);
-float BLI_subtreeLength(BNode *node);
-void BLI_calcGraphLength(BGraph *graph);
-
-void BLI_replaceNode(BGraph *graph, BNode *node_src, BNode *node_replaced);
-void BLI_replaceNodeInArc(BGraph *graph, BArc *arc, BNode *node_src, BNode *node_replaced);
-void BLI_removeDoubleNodes(BGraph *graph, float limit);
-BNode *BLI_FindNodeByPosition(BGraph *graph, const float p[3], const float limit);
-
-BArc *BLI_findConnectedArc(BGraph *graph, BArc *arc, BNode *v);
-
-bool BLI_isGraphCyclic(BGraph *graph);
-
-/*------------ Symmetry handling ------------*/
-void BLI_markdownSymmetry(BGraph *graph, BNode *root_node, float limit);
-
-void BLI_mirrorAlongAxis(float v[3], float center[3], float axis[3]);
-
-/* BNode symmetry flags */
-#define SYM_TOPOLOGICAL 1
-#define SYM_PHYSICAL 2
-
-/* the following two are exclusive */
-#define SYM_AXIAL 4
-#define SYM_RADIAL 8
-
-/* BArc symmetry flags
- *
- * axial symmetry sides */
-#define SYM_SIDE_POSITIVE 1
-#define SYM_SIDE_NEGATIVE 2
-/* Anything higher is the order in radial symmetry */
-#define SYM_SIDE_RADIAL 3
-
-#endif /*__BLI_GRAPH_H__*/
diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h
index 771b9dabe4d..35c8df3075c 100644
--- a/source/blender/blenlib/BLI_heap.h
+++ b/source/blender/blenlib/BLI_heap.h
@@ -43,6 +43,7 @@ void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1, 2);
bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1);
unsigned int BLI_heap_len(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
HeapNode *BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void *BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1);
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) ATTR_NONNULL(1, 2);
void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr) ATTR_NONNULL(1, 2);
diff --git a/source/blender/blenlib/BLI_heap_simple.h b/source/blender/blenlib/BLI_heap_simple.h
new file mode 100644
index 00000000000..eed33558d84
--- /dev/null
+++ b/source/blender/blenlib/BLI_heap_simple.h
@@ -0,0 +1,44 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_HEAP_SIMPLE_H__
+#define __BLI_HEAP_SIMPLE_H__
+
+/** \file BLI_heap_simple.h
+ * \ingroup bli
+ * \brief A min-heap / priority queue ADT
+ */
+
+struct HeapSimple;
+typedef struct HeapSimple HeapSimple;
+
+typedef void (*HeapSimpleFreeFP)(void *ptr);
+
+HeapSimple *BLI_heapsimple_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
+HeapSimple *BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT;
+void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
+void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
+void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1);
+bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1);
+uint BLI_heapsimple_len(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+float BLI_heapsimple_top_value(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void *BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1);
+
+#endif /* __BLI_HEAP_SIMPLE_H__ */
diff --git a/source/blender/blenlib/BLI_iterator.h b/source/blender/blenlib/BLI_iterator.h
new file mode 100644
index 00000000000..d3d375122a1
--- /dev/null
+++ b/source/blender/blenlib/BLI_iterator.h
@@ -0,0 +1,62 @@
+/*
+ * ***** 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): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_ITERATOR_H__
+#define __BLI_ITERATOR_H__
+
+/** \file BLI_iterator.h
+ * \ingroup bli
+ */
+
+typedef struct BLI_Iterator {
+ void *current; /* current pointer we iterate over */
+ void *data; /* stored data required for this iterator */
+ bool skip;
+ bool valid;
+} BLI_Iterator;
+
+typedef void (*IteratorCb)(BLI_Iterator *iter);
+typedef void (*IteratorBeginCb)(BLI_Iterator *iter, void *data_in);
+
+#define ITER_BEGIN(callback_begin, callback_next, callback_end, _data_in, _type, _instance) \
+{ \
+ _type _instance; \
+ IteratorCb callback_end_func = callback_end; \
+ BLI_Iterator iter_macro; \
+ iter_macro.skip = false; \
+ iter_macro.valid = true; \
+ for (callback_begin(&iter_macro, (_data_in)); \
+ iter_macro.valid; \
+ callback_next(&iter_macro)) \
+ { \
+ if (iter_macro.skip) { \
+ iter_macro.skip = false; \
+ continue; \
+ } \
+ _instance = (_type ) iter_macro.current;
+
+#define ITER_END \
+ } \
+ callback_end_func(&iter_macro); \
+} ((void)0)
+
+#endif /* __BLI_ITERATOR_H__ */
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index c92f40c67bf..e4203a01b17 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -40,6 +40,8 @@ extern "C" {
#endif
struct BVHTree;
+struct DistProjectedAABBPrecalc;
+
typedef struct BVHTree BVHTree;
#define USE_KDOPBVH_WATERTIGHT
@@ -83,6 +85,10 @@ typedef struct BVHTreeRayHit {
} BVHTreeRayHit;
enum {
+ /* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
+ BVH_NEAREST_OPTIMAL_ORDER = (1 << 0),
+};
+enum {
/* calculate IsectRayPrecalc data */
BVH_RAYCAST_WATERTIGHT = (1 << 0),
};
@@ -101,6 +107,13 @@ typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b
/* callback to range search query */
typedef void (*BVHTree_RangeQuery)(void *userdata, int index, const float co[3], float dist_sq);
+/* callback to find nearest projected */
+typedef void (*BVHTree_NearestProjectedCallback)(
+ void *userdata, int index,
+ const struct DistProjectedAABBPrecalc *precalc,
+ const float (*clip_plane)[4], const int clip_plane_len,
+ BVHTreeNearest *nearest);
+
/* callbacks to BLI_bvhtree_walk_dfs */
/* return true to traverse into this nodes children, else skip. */
@@ -135,6 +148,10 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree);
/* find nearest node to the given coordinates
* (if nearest is given it will only search nodes where square distance is smaller than nearest->dist) */
+int BLI_bvhtree_find_nearest_ex(
+ BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
+ BVHTree_NearestPointCallback callback, void *userdata,
+ int flag);
int BLI_bvhtree_find_nearest(
BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
BVHTree_NearestPointCallback callback, void *userdata);
@@ -162,6 +179,12 @@ int BLI_bvhtree_range_query(
BVHTree *tree, const float co[3], float radius,
BVHTree_RangeQuery callback, void *userdata);
+int BLI_bvhtree_find_nearest_projected(
+ BVHTree *tree, float projmat[4][4], float winsize[2], float mval[2],
+ float clip_planes[6][4], int clip_num,
+ BVHTreeNearest *nearest,
+ BVHTree_NearestProjectedCallback callback, void *userdata);
+
void BLI_bvhtree_walk_dfs(
BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb,
diff --git a/source/blender/blenlib/BLI_link_utils.h b/source/blender/blenlib/BLI_link_utils.h
index d469b105f93..7a1a13a6b31 100644
--- a/source/blender/blenlib/BLI_link_utils.h
+++ b/source/blender/blenlib/BLI_link_utils.h
@@ -35,6 +35,27 @@
list = link; \
} (void)0
+/* Use for append (single linked list, storing the last element). */
+#define BLI_LINKS_APPEND(list, link) { \
+ (link)->next = NULL; \
+ if ((list)->first) { \
+ (list)->last->next = link; \
+ } \
+ else { \
+ (list)->first = link; \
+ } \
+ (list)->last = link; \
+} (void)0
+
+/* Use for inserting after a certain element. */
+#define BLI_LINKS_INSERT_AFTER(list, node, link) { \
+ if ((node)->next == NULL) { \
+ (list)->last = link; \
+ } \
+ (link)->next = (node)->next; \
+ (node)->next = link; \
+} (void)0
+
#define BLI_LINKS_FREE(list) { \
while (list) { \
void *next = list->next; \
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index c4ad5acfe4b..34e7a1fa212 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -82,6 +82,7 @@ void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlink
void BLI_listbases_swaplinks(struct ListBase *listbasea, struct ListBase *listbaseb, void *vlinka, void *vlinkb) ATTR_NONNULL(2, 3);
void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
+void BLI_movelisttolist_reverse(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1);
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 72d29164988..3653191232c 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -112,7 +112,7 @@ void BLI_init_srgb_conversion(void);
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4]);
MINLINE void premul_to_straight_v4(float color[4]);
-MINLINE void straight_to_premul_v4_v4(float straight[4], const float premul[4]);
+MINLINE void straight_to_premul_v4_v4(float premul[4], const float straight[4]);
MINLINE void straight_to_premul_v4(float color[4]);
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]);
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index e4cf4839b45..d5287e8d8aa 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -121,11 +121,14 @@ float dist_squared_ray_to_seg_v3(
const float v0[3], const float v1[3],
float r_point[3], float *r_depth);
+void aabb_get_near_far_from_plane(
+ const float plane_no[3], const float bbmin[3], const float bbmax[3],
+ float bb_near[3], float bb_afar[3]);
+
struct DistRayAABB_Precalc {
float ray_origin[3];
float ray_direction[3];
float ray_inv_dir[3];
- bool sign[3];
};
void dist_squared_ray_to_aabb_v3_precalc(
struct DistRayAABB_Precalc *neasrest_precalc,
@@ -140,6 +143,24 @@ float dist_squared_ray_to_aabb_v3_simple(
const float bb_min[3], const float bb_max[3],
float r_point[3], float *r_depth);
+struct DistProjectedAABBPrecalc {
+ float ray_origin[3];
+ float ray_direction[3];
+ float ray_inv_dir[3];
+ float pmat[4][4];
+ float mval[2];
+};
+void dist_squared_to_projected_aabb_precalc(
+ struct DistProjectedAABBPrecalc *precalc,
+ const float projmat[4][4], const float winsize[2], const float mval[2]);
+float dist_squared_to_projected_aabb(
+ struct DistProjectedAABBPrecalc *data,
+ const float bbmin[3], const float bbmax[3],
+ bool r_axis_closest[3]);
+float dist_squared_to_projected_aabb_simple(
+ const float projmat[4][4], const float winsize[2], const float mval[2],
+ const float bbmin[3], const float bbmax[3]);
+
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
@@ -228,6 +249,9 @@ bool isect_ray_plane_v3(
float *r_lambda, const bool clip);
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]);
+bool isect_point_planes_v3_negated(
+ const float (*planes)[4], const int totplane, const float p[3]);
+
bool isect_line_plane_v3(
float r_isect_co[3], const float l1[3], const float l2[3],
const float plane_co[3], const float plane_no[3]) ATTR_WARN_UNUSED_RESULT;
@@ -296,6 +320,11 @@ bool isect_ray_seg_v2(
const float v0[2], const float v1[2],
float *r_lambda, float *r_u);
+bool isect_ray_seg_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float v0[3], const float v1[3],
+ float *r_lambda);
+
/* point in polygon */
bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr, const bool use_holes);
bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const unsigned int nr, const bool use_holes);
@@ -331,6 +360,14 @@ bool isect_ray_aabb_v3_simple(
float *tmin, float *tmax);
/* other */
+#define ISECT_AABB_PLANE_BEHIND_ANY 0
+#define ISECT_AABB_PLANE_CROSS_ANY 1
+#define ISECT_AABB_PLANE_IN_FRONT_ALL 2
+
+int isect_aabb_planes_v3(
+ const float (*planes)[4], const int totplane,
+ const float bbmin[3], const float bbmax[3]);
+
bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius,
const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float ipoint[3]);
@@ -341,6 +378,8 @@ bool clip_segment_v3_plane_n(
const float p1[3], const float p2[3], const float plane_array[][4], const int plane_tot,
float r_p1[3], float r_p2[3]);
+bool point_in_slice_seg(float p[3], float l1[3], float l2[3]);
+
/****************************** Interpolation ********************************/
void interp_weights_tri_v3(float w[3], const float a[3], const float b[3], const float c[3], const float p[3]);
void interp_weights_quad_v3(float w[4], const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 9d418749bd1..d4d498590b5 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -46,81 +46,112 @@ void unit_m2(float R[2][2]);
void unit_m3(float R[3][3]);
void unit_m4(float R[4][4]);
-void copy_m2_m2(float R[2][2], float A[2][2]);
-void copy_m3_m3(float R[3][3], float A[3][3]);
-void copy_m4_m4(float R[4][4], float A[4][4]);
-void copy_m3_m4(float R[3][3], float A[4][4]);
-void copy_m4_m3(float R[4][4], float A[3][3]);
+void copy_m2_m2(float R[2][2], const float A[2][2]);
+void copy_m3_m3(float R[3][3], const float A[3][3]);
+void copy_m4_m4(float R[4][4], const float A[4][4]);
+void copy_m3_m4(float R[3][3], const float A[4][4]);
+void copy_m4_m3(float R[4][4], const float A[3][3]);
/* double->float */
-void copy_m3_m3d(float R[3][3], double A[3][3]);
+void copy_m3_m3d(float R[3][3], const double A[3][3]);
void swap_m3m3(float A[3][3], float B[3][3]);
void swap_m4m4(float A[4][4], float B[4][4]);
/******************************** Arithmetic *********************************/
-void add_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]);
-void add_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]);
+void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
+void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
-void sub_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]);
-void sub_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]);
+void sub_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
+void sub_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
-void mul_m3_m3m3(float R[3][3], float A[3][3], float B[3][3]);
-void mul_m4_m3m4(float R[4][4], float A[3][3], float B[4][4]);
-void mul_m4_m4m3(float R[4][4], float A[4][4], float B[3][3]);
-void mul_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]);
-void mul_m3_m3m4(float R[3][3], float A[4][4], float B[3][3]);
+void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
+void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4]);
+void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3]);
+void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
+void mul_m3_m3m4(float R[3][3], const float A[4][4], const float B[3][3]);
+
+/* special matrix multiplies
+ * uniq: R <-- AB, R is neither A nor B
+ * pre: R <-- AR
+ * post: R <-- RB
+ */
+void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]);
+void mul_m3_m3_pre(float R[3][3], const float A[3][3]);
+void mul_m3_m3_post(float R[3][3], const float B[3][3]);
+void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4]);
+void mul_m4_m4_pre(float R[4][4], const float A[4][4]);
+void mul_m4_m4_post(float R[4][4], const float B[4][4]);
/* mul_m3_series */
-void _va_mul_m3_series_3(float R[3][3], float M1[3][3], float M2[3][3]) ATTR_NONNULL();
-void _va_mul_m3_series_4(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3]) ATTR_NONNULL();
-void _va_mul_m3_series_5(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3]) ATTR_NONNULL();
-void _va_mul_m3_series_6(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
- float M5[3][3]) ATTR_NONNULL();
-void _va_mul_m3_series_7(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
- float M5[3][3], float M6[3][3]) ATTR_NONNULL();
-void _va_mul_m3_series_8(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
- float M5[3][3], float M6[3][3], float M7[3][3]) ATTR_NONNULL();
-void _va_mul_m3_series_9(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
- float M5[3][3], float M6[3][3], float M7[3][3], float M8[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_3(
+ float R[3][3], const float M1[3][3], const float M2[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_4(
+ float R[3][3], const float M1[3][3], const float M2[3][3], const float M3[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_5(
+ float R[3][3], const float M1[3][3], const float M2[3][3], const float M3[3][3],
+ const float M4[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_6(
+ float R[3][3], const float M1[3][3], const float M2[3][3], const float M3[3][3],
+ const float M4[3][3], const float M5[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_7(
+ float R[3][3], const float M1[3][3], const float M2[3][3], const float M3[3][3],
+ const float M4[3][3], const float M5[3][3], const float M6[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_8(
+ float R[3][3], const float M1[3][3], const float M2[3][3], const float M3[3][3],
+ const float M4[3][3], const float M5[3][3], const float M6[3][3], const float M7[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_9(
+ float R[3][3], const float M1[3][3], const float M2[3][3], const float M3[3][3],
+ const float M4[3][3], const float M5[3][3], const float M6[3][3], const float M7[3][3],
+ const float M8[3][3]) ATTR_NONNULL();
/* mul_m4_series */
-void _va_mul_m4_series_3(float R[4][4], float M1[4][4], float M2[4][4]) ATTR_NONNULL();
-void _va_mul_m4_series_4(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4]) ATTR_NONNULL();
-void _va_mul_m4_series_5(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4]) ATTR_NONNULL();
-void _va_mul_m4_series_6(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
- float M5[4][4]) ATTR_NONNULL();
-void _va_mul_m4_series_7(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
- float M5[4][4], float M6[4][4]) ATTR_NONNULL();
-void _va_mul_m4_series_8(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
- float M5[4][4], float M6[4][4], float M7[4][4]) ATTR_NONNULL();
-void _va_mul_m4_series_9(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
- float M5[4][4], float M6[4][4], float M7[4][4], float M8[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_3(
+ float R[4][4], const float M1[4][4], const float M2[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_4(
+ float R[4][4], const float M1[4][4], const float M2[4][4], const float M3[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_5(
+ float R[4][4], const float M1[4][4], const float M2[4][4], const float M3[4][4],
+ const float M4[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_6(
+ float R[4][4], const float M1[4][4], const float M2[4][4], const float M3[4][4],
+ const float M4[4][4], const float M5[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_7(
+ float R[4][4], const float M1[4][4], const float M2[4][4], const float M3[4][4],
+ const float M4[4][4], const float M5[4][4], const float M6[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_8(
+ float R[4][4], const float M1[4][4], const float M2[4][4], const float M3[4][4],
+ const float M4[4][4], const float M5[4][4], const float M6[4][4], const float M7[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_9(
+ float R[4][4], const float M1[4][4], const float M2[4][4], const float M3[4][4],
+ const float M4[4][4], const float M5[4][4], const float M6[4][4], const float M7[4][4],
+ const float M8[4][4]) ATTR_NONNULL();
#define mul_m3_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m3_series_, __VA_ARGS__)
#define mul_m4_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m4_series_, __VA_ARGS__)
-void mul_m4_v3(float M[4][4], float r[3]);
-void mul_v3_m4v3(float r[3], float M[4][4], const float v[3]);
-void mul_v2_m4v3(float r[2], float M[4][4], const float v[3]);
-void mul_v2_m2v2(float r[2], float M[2][2], const float v[2]);
-void mul_m2v2(float M[2][2], float v[2]);
-void mul_mat3_m4_v3(float M[4][4], float r[3]);
-void mul_v3_mat3_m4v3(float r[3], float M[4][4], const float v[3]);
-void mul_m4_v4(float M[4][4], float r[4]);
-void mul_v4_m4v4(float r[4], float M[4][4], const float v[4]);
-void mul_project_m4_v3(float M[4][4], float vec[3]);
-void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]);
-void mul_v2_project_m4_v3(float r[2], float M[4][4], const float vec[3]);
-
-void mul_m3_v2(float m[3][3], float r[2]);
-void mul_v2_m3v2(float r[2], float m[3][3], float v[2]);
-void mul_m3_v3(float M[3][3], float r[3]);
-void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]);
-void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]);
-void mul_transposed_m3_v3(float M[3][3], float r[3]);
-void mul_transposed_mat3_m4_v3(float M[4][4], float r[3]);
-void mul_m3_v3_double(float M[3][3], double r[3]);
+void mul_m4_v3(const float M[4][4], float r[3]);
+void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3]);
+void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]);
+void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]);
+void mul_m2v2(const float M[2][2], float v[2]);
+void mul_mat3_m4_v3(const float M[4][4], float r[3]);
+void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]);
+void mul_m4_v4(const float M[4][4], float r[4]);
+void mul_v4_m4v4(float r[4], const float M[4][4], const float v[4]);
+void mul_v4_m4v3(float r[4], const float M[4][4], const float v[3]); /* v has implicit w = 1.0f */
+void mul_project_m4_v3(const float M[4][4], float vec[3]);
+void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3]);
+void mul_v2_project_m4_v3(float r[2], const float M[4][4], const float vec[3]);
+
+void mul_m3_v2(const float m[3][3], float r[2]);
+void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2]);
+void mul_m3_v3(const float M[3][3], float r[3]);
+void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3]);
+void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3]);
+void mul_transposed_m3_v3(const float M[3][3], float r[3]);
+void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
+void mul_m3_v3_double(const float M[3][3], double r[3]);
void mul_m3_fl(float R[3][3], float f);
void mul_m4_fl(float R[4][4], float f);
@@ -131,103 +162,103 @@ void negate_mat3_m4(float R[4][4]);
void negate_m4(float R[4][4]);
bool invert_m3_ex(float m[3][3], const float epsilon);
-bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon);
+bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon);
bool invert_m3(float R[3][3]);
-bool invert_m3_m3(float R[3][3], float A[3][3]);
+bool invert_m3_m3(float R[3][3], const float A[3][3]);
bool invert_m4(float R[4][4]);
-bool invert_m4_m4(float R[4][4], float A[4][4]);
+bool invert_m4_m4(float R[4][4], const float A[4][4]);
/* double arithmetic (mixed float/double) */
-void mul_m4_v4d(float M[4][4], double r[4]);
-void mul_v4d_m4v4d(double r[4], float M[4][4], double v[4]);
+void mul_m4_v4d(const float M[4][4], double r[4]);
+void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
/* double matrix functions (no mixing types) */
-void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]);
-void mul_m3_v3_db(double M[3][3], double r[3]);
+void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]);
+void mul_m3_v3_db(const double M[3][3], double r[3]);
/****************************** Linear Algebra *******************************/
void transpose_m3(float R[3][3]);
-void transpose_m3_m3(float R[3][3], float A[3][3]);
-void transpose_m3_m4(float R[3][3], float A[4][4]);
+void transpose_m3_m3(float R[3][3], const float A[3][3]);
+void transpose_m3_m4(float R[3][3], const float A[4][4]);
void transpose_m4(float R[4][4]);
-void transpose_m4_m4(float R[4][4], float A[4][4]);
+void transpose_m4_m4(float R[4][4], const float A[4][4]);
-int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit);
+int compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit);
void normalize_m3_ex(float R[3][3], float r_scale[3]) ATTR_NONNULL();
void normalize_m3(float R[3][3]) ATTR_NONNULL();
-void normalize_m3_m3_ex(float R[3][3], float A[3][3], float r_scale[3]) ATTR_NONNULL();
-void normalize_m3_m3(float R[3][3], float A[3][3]) ATTR_NONNULL();
+void normalize_m3_m3_ex(float R[3][3], const float A[3][3], float r_scale[3]) ATTR_NONNULL();
+void normalize_m3_m3(float R[3][3], const float A[3][3]) ATTR_NONNULL();
void normalize_m4_ex(float R[4][4], float r_scale[3]) ATTR_NONNULL();
void normalize_m4(float R[4][4]) ATTR_NONNULL();
-void normalize_m4_m4_ex(float R[4][4], float A[4][4], float r_scale[3]) ATTR_NONNULL();
-void normalize_m4_m4(float R[4][4], float A[4][4]) ATTR_NONNULL();
+void normalize_m4_m4_ex(float R[4][4], const float A[4][4], float r_scale[3]) ATTR_NONNULL();
+void normalize_m4_m4(float R[4][4], const float A[4][4]) ATTR_NONNULL();
void orthogonalize_m3(float R[3][3], int axis);
void orthogonalize_m4(float R[4][4], int axis);
-bool is_orthogonal_m3(float mat[3][3]);
-bool is_orthogonal_m4(float mat[4][4]);
-bool is_orthonormal_m3(float mat[3][3]);
-bool is_orthonormal_m4(float mat[4][4]);
+bool is_orthogonal_m3(const float mat[3][3]);
+bool is_orthogonal_m4(const float mat[4][4]);
+bool is_orthonormal_m3(const float mat[3][3]);
+bool is_orthonormal_m4(const float mat[4][4]);
-bool is_uniform_scaled_m3(float mat[3][3]);
-bool is_uniform_scaled_m4(float m[4][4]);
+bool is_uniform_scaled_m3(const float mat[3][3]);
+bool is_uniform_scaled_m4(const float m[4][4]);
/* Note: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix!
* Nowadays 'adjoint' usually refers to the conjugate transpose,
* which for real-valued matrices is simply the transpose.
*/
-void adjoint_m2_m2(float R[2][2], float A[2][2]);
-void adjoint_m3_m3(float R[3][3], float A[3][3]);
-void adjoint_m4_m4(float R[4][4], float A[4][4]);
+void adjoint_m2_m2(float R[2][2], const float A[2][2]);
+void adjoint_m3_m3(float R[3][3], const float A[3][3]);
+void adjoint_m4_m4(float R[4][4], const float A[4][4]);
float determinant_m2(float a, float b,
float c, float d);
float determinant_m3(float a, float b, float c,
float d, float e, float f,
float g, float h, float i);
-float determinant_m3_array(float m[3][3]);
-float determinant_m4(float A[4][4]);
+float determinant_m3_array(const float m[3][3]);
+float determinant_m4(const float A[4][4]);
#define PSEUDOINVERSE_EPSILON 1e-8f
void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]);
-void pseudoinverse_m4_m4(float Ainv[4][4], float A[4][4], float epsilon);
-void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon);
+void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon);
+void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon);
-bool has_zero_axis_m4(float matrix[4][4]);
+bool has_zero_axis_m4(const float matrix[4][4]);
-void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]);
+void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]);
/****************************** Transformations ******************************/
void scale_m3_fl(float R[3][3], float scale);
void scale_m4_fl(float R[4][4], float scale);
-float mat3_to_scale(float M[3][3]);
-float mat4_to_scale(float M[4][4]);
-float mat4_to_xy_scale(float M[4][4]);
+float mat3_to_scale(const float M[3][3]);
+float mat4_to_scale(const float M[4][4]);
+float mat4_to_xy_scale(const float M[4][4]);
void size_to_mat3(float R[3][3], const float size[3]);
void size_to_mat4(float R[4][4], const float size[3]);
-void mat3_to_size(float r[3], float M[3][3]);
-void mat4_to_size(float r[3], float M[4][4]);
+void mat3_to_size(float r[3], const float M[3][3]);
+void mat4_to_size(float r[3], const float M[4][4]);
void translate_m4(float mat[4][4], float tx, float ty, float tz);
void rotate_m4(float mat[4][4], const char axis, const float angle);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
-void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]);
-void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wmat[4][4]);
-void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4]);
-void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4]);
+void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);
+void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]);
+void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]);
+void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4]);
-void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]);
+void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3], const float eul[3], const float size[3]);
@@ -238,20 +269,20 @@ void loc_quat_size_to_mat4(float R[4][4],
void loc_axisangle_size_to_mat4(float R[4][4],
const float loc[3], const float axis[4], const float angle, const float size[3]);
-void blend_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t);
-void blend_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t);
+void blend_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t);
+void blend_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t);
-void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t);
-void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t);
+void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t);
+void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t);
-bool is_negative_m3(float mat[3][3]);
-bool is_negative_m4(float mat[4][4]);
+bool is_negative_m3(const float mat[3][3]);
+bool is_negative_m4(const float mat[4][4]);
-bool is_zero_m3(float mat[3][3]);
-bool is_zero_m4(float mat[4][4]);
+bool is_zero_m3(const float mat[3][3]);
+bool is_zero_m4(const float mat[4][4]);
-bool equals_m3m3(float mat1[3][3], float mat2[3][3]);
-bool equals_m4m4(float mat1[4][4], float mat2[4][4]);
+bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]);
+bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]);
/* SpaceTransform helper */
typedef struct SpaceTransform {
@@ -260,8 +291,8 @@ typedef struct SpaceTransform {
} SpaceTransform;
-void BLI_space_transform_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]);
-void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]);
+void BLI_space_transform_from_matrices(struct SpaceTransform *data, const float local[4][4], const float target[4][4]);
+void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, const float local[4][4], const float target[4][4]);
void BLI_space_transform_apply(const struct SpaceTransform *data, float co[3]);
void BLI_space_transform_invert(const struct SpaceTransform *data, float co[3]);
void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float no[3]);
@@ -272,8 +303,8 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
/*********************************** Other ***********************************/
-void print_m3(const char *str, float M[3][3]);
-void print_m4(const char *str, float M[4][4]);
+void print_m3(const char *str, const float M[3][3]);
+void print_m4(const char *str, const float M[4][4]);
#define print_m3_id(M) print_m3(STRINGIFY(M), M)
#define print_m4_id(M) print_m4(STRINGIFY(M), M)
diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h
index 3c1cb90937d..845d2100133 100644
--- a/source/blender/blenlib/BLI_math_solvers.h
+++ b/source/blender/blenlib/BLI_math_solvers.h
@@ -53,12 +53,14 @@ void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[], float r_V[3]
bool BLI_tridiagonal_solve(const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
bool BLI_tridiagonal_solve_cyclic(const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
-/**************************** Inline Definitions ******************************/
-#if 0 /* None so far. */
-# if BLI_MATH_DO_INLINE
-# include "intern/math_geom_inline.c"
-# endif
-#endif
+/* Generic 3 variable Newton's method solver. */
+typedef void (*Newton3D_DeltaFunc)(void *userdata, const float x[3], float r_delta[3]);
+typedef void (*Newton3D_JacobianFunc)(void *userdata, const float x[3], float r_jacobian[3][3]);
+typedef bool (*Newton3D_CorrectionFunc)(void *userdata, const float x[3], float step[3], float x_next[3]);
+
+bool BLI_newton3d_solve(
+ Newton3D_DeltaFunc func_delta, Newton3D_JacobianFunc func_jacobian, Newton3D_CorrectionFunc func_correction, void *userdata,
+ float epsilon, int max_iterations, bool trace, const float x_init[3], float result[3]);
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic pop
diff --git a/source/blender/blenlib/BLI_math_statistics.h b/source/blender/blenlib/BLI_math_statistics.h
index 210d41bcf59..40641c05e08 100644
--- a/source/blender/blenlib/BLI_math_statistics.h
+++ b/source/blender/blenlib/BLI_math_statistics.h
@@ -51,12 +51,6 @@ void BLI_covariance_m3_v3n(
const float (*cos_v3)[3], const int nbr_cos_v3, const bool use_sample_correction,
float r_covmat[3][3], float r_center[3]);
-/**************************** Inline Definitions ******************************/
-#if 0 /* None so far. */
-# if BLI_MATH_DO_INLINE
-# include "intern/math_geom_inline.c"
-# endif
-#endif
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic pop
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index c23c0409f81..a663d08b074 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -78,6 +78,9 @@ MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
MINLINE void copy_v4_v4_int(int r[4], const int a[4]);
+/* int <-> float */
+MINLINE void copy_v2fl_v2i(float r[2], const int a[2]);
+MINLINE void round_v2i_v2fl(int r[2], const float a[2]);
/* double -> float */
MINLINE void copy_v2fl_v2db(float r[2], const double a[2]);
MINLINE void copy_v3fl_v3db(float r[3], const double a[3]);
@@ -117,19 +120,21 @@ MINLINE void mul_v2_v2fl(float r[2], const float a[2], float f);
MINLINE void mul_v3_fl(float r[3], float f);
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f);
MINLINE void mul_v2_v2(float r[2], const float a[2]);
+MINLINE void mul_v2_v2v2(float r[2], const float a[2], const float b[2]);
MINLINE void mul_v3_v3(float r[3], const float a[3]);
MINLINE void mul_v3_v3v3(float r[3], const float a[3], const float b[3]);
MINLINE void mul_v4_fl(float r[4], float f);
+MINLINE void mul_v4_v4(float r[4], const float a[4]);
MINLINE void mul_v4_v4fl(float r[3], const float a[3], float f);
MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]);
MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]);
-MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE float dot_m4_v3_row_x(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE float dot_m4_v3_row_y(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE float dot_m4_v3_row_z(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f);
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f);
@@ -333,6 +338,7 @@ void print_vn(const char *str, const float v[], const int n);
MINLINE void normal_float_to_short_v2(short r[2], const float n[2]);
MINLINE void normal_short_to_float_v3(float r[3], const short n[3]);
MINLINE void normal_float_to_short_v3(short r[3], const float n[3]);
+MINLINE void normal_float_to_short_v4(short r[4], const float n[4]);
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]);
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
diff --git a/source/blender/blenlib/BLI_memiter.h b/source/blender/blenlib/BLI_memiter.h
new file mode 100644
index 00000000000..55eb023313d
--- /dev/null
+++ b/source/blender/blenlib/BLI_memiter.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_MEMITER_H__
+#define __BLI_MEMITER_H__
+
+/** \file BLI_memiter.h
+ * \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "BLI_sys_types.h"
+#include "BLI_compiler_attrs.h"
+#include "BLI_compiler_compat.h"
+
+/* 512kb, good default for small elems. */
+#define BLI_MEMITER_DEFAULT_SIZE (1 << 19)
+
+struct BLI_memiter;
+struct BLI_memiter_chunk;
+
+typedef struct BLI_memiter BLI_memiter;
+
+/* warning, ATTR_MALLOC flag on BLI_memiter_alloc causes crash, see: D2756 */
+BLI_memiter *BLI_memiter_create(unsigned int chunk_size) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+void *BLI_memiter_alloc(BLI_memiter *mi, unsigned int size) ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from) ATTR_NONNULL(1, 3);
+void *BLI_memiter_calloc(BLI_memiter *mi, unsigned int size) ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void BLI_memiter_destroy(BLI_memiter *mi) ATTR_NONNULL(1);
+void BLI_memiter_clear(BLI_memiter *mi) ATTR_NONNULL(1);
+unsigned int BLI_memiter_count(const BLI_memiter *mi) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
+/* utils */
+void *BLI_memiter_elem_first(BLI_memiter *mi);
+void *BLI_memiter_elem_first_size(BLI_memiter *mi, unsigned int *r_size);
+
+/* private structure */
+typedef struct BLI_memiter_handle {
+ struct BLI_memiter_elem *elem;
+ uint elem_left;
+} BLI_memiter_handle;
+
+void BLI_memiter_iter_init(BLI_memiter *mi, BLI_memiter_handle *iter) ATTR_NONNULL();
+bool BLI_memiter_iter_done(const BLI_memiter_handle *iter) ATTR_NONNULL();
+void *BLI_memiter_iter_step(BLI_memiter_handle *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BLI_memiter_iter_step_size(BLI_memiter_handle *iter, uint *r_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_MEMITER_H__ */
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index e434e83416b..dcfb2c9cbc9 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -108,6 +108,8 @@ void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_path_is_unc(const char *path);
+void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) ATTR_NONNULL();
+
#if defined(WIN32)
void BLI_cleanup_unc_16(wchar_t *path_16);
void BLI_cleanup_unc(char *path_16, int maxlen);
diff --git a/source/blender/blenlib/BLI_polyfill_2d.h b/source/blender/blenlib/BLI_polyfill_2d.h
index 099f08d4663..0ede111fc42 100644
--- a/source/blender/blenlib/BLI_polyfill_2d.h
+++ b/source/blender/blenlib/BLI_polyfill_2d.h
@@ -21,6 +21,10 @@
#ifndef __BLI_POLYFILL_2D_H__
#define __BLI_POLYFILL_2D_H__
+/** \file BLI_polyfill_2d.h
+ * \ingroup bli
+ */
+
struct MemArena;
void BLI_polyfill_calc_arena(
diff --git a/source/blender/blenlib/BLI_polyfill_2d_beautify.h b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
index 73b52125904..96b730bee68 100644
--- a/source/blender/blenlib/BLI_polyfill_2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
@@ -21,6 +21,10 @@
#ifndef __BLI_POLYFILL_2D_BEAUTIFY_H__
#define __BLI_POLYFILL_2D_BEAUTIFY_H__
+/** \file BLI_polyfill_2d_beautify.h
+ * \ingroup bli
+ */
+
struct Heap;
struct MemArena;
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index 5bb7ab391b9..f7dea562393 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -64,15 +64,8 @@ void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem
/** Note that skipping is as slow as generating n numbers! */
void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1);
-/** Seed for the random number generator, using noise.c hash[] */
-void BLI_srandom(unsigned int seed);
-
-/** Return a pseudo-random number N where 0<=N<(2^31) */
-int BLI_rand(void) ATTR_WARN_UNUSED_RESULT;
-
-/** Return a pseudo-random number N where 0.0f<=N<1.0f */
-float BLI_frand(void) ATTR_WARN_UNUSED_RESULT;
-void BLI_frand_unit_v3(float v[3]);
+/* fill an array with random numbers */
+void BLI_array_frand(float *ar, int count, unsigned int seed);
/** Return a pseudo-random (hash) float from an integer value */
float BLI_hash_frand(unsigned int seed) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index faa8dc03615..2fb8f045841 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -33,6 +33,7 @@
*/
#include <stdarg.h>
+#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
@@ -71,6 +72,7 @@ char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT A
size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL();
size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
+size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();
void BLI_str_format_byte_unit(char dst[15], long long int size, const bool base_10) ATTR_NONNULL();
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -85,6 +87,7 @@ size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT
void BLI_str_tolower_ascii(char *str, const size_t len) ATTR_NONNULL();
void BLI_str_toupper_ascii(char *str, const size_t len) ATTR_NONNULL();
+void BLI_str_rstrip(char *str) ATTR_NONNULL();
int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL();
int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len) ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_timer.h b/source/blender/blenlib/BLI_timer.h
new file mode 100644
index 00000000000..8f18d4fb3f4
--- /dev/null
+++ b/source/blender/blenlib/BLI_timer.h
@@ -0,0 +1,58 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_TIMER_H__
+#define __BLI_TIMER_H__
+
+#include "BLI_sys_types.h"
+
+/** \file BLI_timer.h
+ * \ingroup BLI
+ */
+
+/* ret < 0: the timer will be removed.
+ * ret >= 0: the timer will be called again in ret seconds */
+typedef double (*BLI_timer_func)(uintptr_t uuid, void *user_data);
+typedef void (*BLI_timer_data_free)(uintptr_t uuid, void *user_data);
+
+/* `func(...) < 0`: The timer will be removed.
+ * `func(...) >= 0`: The function will be called again in that many seconds. */
+void BLI_timer_register(
+ uintptr_t uuid,
+ BLI_timer_func func,
+ void *user_data,
+ BLI_timer_data_free user_data_free,
+ double first_interval,
+ bool persistent);
+
+bool BLI_timer_is_registered(uintptr_t uuid);
+
+/* Returns False when the timer does not exist (anymore). */
+bool BLI_timer_unregister(uintptr_t uuid);
+
+/* Execute all registered functions that are due. */
+void BLI_timer_execute(void);
+
+void BLI_timer_free(void);
+
+#endif /* __BLI_TIMER_H__ */
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 98c27bd053b..f81bfc2f853 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -274,11 +274,15 @@ extern "C" {
#define SQUARE(a) ({ \
typeof(a) a_ = (a); \
((a_) * (a_)); })
+#define CUBE(a) ({ \
+ typeof(a) a_ = (a); \
+ ((a_) * (a_) * (a_)); })
#else
#define ABS(a) ((a) < 0 ? (-(a)) : (a))
#define SQUARE(a) ((a) * (a))
+#define CUBE(a) ((a) * (a) * (a))
#endif
@@ -629,6 +633,14 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
# define UNLIKELY(x) (x)
#endif
+/* Expands to an integer constant expression evaluating to a close upper bound
+ * on the number the number of decimal digits in a value expressible in the
+ * integer type given by the argument (if it is a type name) or the the integer
+ * type of the argument (if it is an expression). The meaning of the resulting
+ * expression is unspecified for other arguments.
+ * i.e: DECIMAL_DIGITS_BOUND(uchar) is equal to 3. */
+#define DECIMAL_DIGITS_BOUND(t) (241 * sizeof(t) / 100 + 1)
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenlib/BLI_vfontdata.h
index 1cc1ef17486..892d084f5ee 100644
--- a/source/blender/blenlib/BLI_vfontdata.h
+++ b/source/blender/blenlib/BLI_vfontdata.h
@@ -43,6 +43,9 @@ typedef struct VFontData {
struct GHash *characters;
char name[128];
float scale;
+ /* Calculated from the font. */
+ float em_height;
+ float ascender;
} VFontData;
typedef struct VChar {
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 16dfec77260..921ecc29e18 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -48,12 +48,15 @@ set(SRC
intern/BLI_ghash.c
intern/BLI_ghash_utils.c
intern/BLI_heap.c
+ intern/BLI_heap_simple.c
intern/BLI_kdopbvh.c
intern/BLI_kdtree.c
intern/BLI_linklist.c
intern/BLI_linklist_lockfree.c
intern/BLI_memarena.c
+ intern/BLI_memiter.c
intern/BLI_mempool.c
+ intern/BLI_timer.c
intern/DLRB_tree.c
intern/array_store.c
intern/array_store_utils.c
@@ -68,10 +71,10 @@ set(SRC
intern/easing.c
intern/edgehash.c
intern/endian_switch.c
+ intern/expr_pylike_eval.c
intern/fileops.c
intern/fnmatch.c
intern/freetypefont.c
- intern/graph.c
intern/gsqueue.c
intern/hash_md5.c
intern/hash_mm2a.c
@@ -152,17 +155,19 @@ set(SRC
BLI_edgehash.h
BLI_endian_switch.h
BLI_endian_switch_inline.h
+ BLI_expr_pylike_eval.h
BLI_fileops.h
BLI_fileops_types.h
BLI_fnmatch.h
BLI_ghash.h
- BLI_graph.h
BLI_gsqueue.h
BLI_hash.h
BLI_hash_md5.h
BLI_hash_mm2a.h
BLI_hash_mm3.h
BLI_heap.h
+ BLI_heap_simple.h
+ BLI_iterator.h
BLI_jitter_2d.h
BLI_kdopbvh.h
BLI_kdtree.h
@@ -186,6 +191,7 @@ set(SRC
BLI_math_statistics.h
BLI_math_vector.h
BLI_memarena.h
+ BLI_memiter.h
BLI_memory_utils.h
BLI_mempool.h
BLI_noise.h
@@ -210,6 +216,7 @@ set(SRC
BLI_task.h
BLI_threads.h
BLI_timecode.h
+ BLI_timer.h
BLI_utildefines.h
BLI_utildefines_iter.h
BLI_utildefines_stack.h
diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c
index d16dd36763d..0380656a33a 100644
--- a/source/blender/blenlib/intern/BLI_array.c
+++ b/source/blender/blenlib/intern/BLI_array.c
@@ -90,9 +90,4 @@ void _bli_array_grow_func(
}
*arr_p = arr_tmp;
-
- /* caller must do */
-#if 0
- arr_len += num;
-#endif
}
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index ec75c140159..071a7e2dc0e 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -1108,57 +1108,6 @@ void BLI_ghashIterator_free(GHashIterator *ghi)
MEM_freeN(ghi);
}
-/* inline functions now */
-#if 0
-/**
- * Retrieve the key from an iterator.
- *
- * \param ghi The iterator.
- * \return The key at the current index, or NULL if the
- * iterator is done.
- */
-void *BLI_ghashIterator_getKey(GHashIterator *ghi)
-{
- return ghi->curEntry->key;
-}
-
-/**
- * Retrieve the value from an iterator.
- *
- * \param ghi The iterator.
- * \return The value at the current index, or NULL if the
- * iterator is done.
- */
-void *BLI_ghashIterator_getValue(GHashIterator *ghi)
-{
- return ghi->curEntry->val;
-}
-
-/**
- * Retrieve the value from an iterator.
- *
- * \param ghi The iterator.
- * \return The value at the current index, or NULL if the
- * iterator is done.
- */
-void **BLI_ghashIterator_getValue_p(GHashIterator *ghi)
-{
- return &ghi->curEntry->val;
-}
-
-/**
- * Determine if an iterator is done (has reached the end of
- * the hash table).
- *
- * \param ghi The iterator.
- * \return True if done, False otherwise.
- */
-bool BLI_ghashIterator_done(GHashIterator *ghi)
-{
- return ghi->curEntry == NULL;
-}
-#endif
-
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index 5658c1fd103..c785c1ac012 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -38,9 +38,9 @@
/***/
struct HeapNode {
- void *ptr;
float value;
uint index;
+ void *ptr;
};
struct HeapNode_Chunk {
@@ -87,8 +87,14 @@ struct Heap {
BLI_INLINE void heap_swap(Heap *heap, const uint i, const uint j)
{
-
-#if 0
+#if 1
+ HeapNode **tree = heap->tree;
+ HeapNode *pi = tree[i], *pj = tree[j];
+ pi->index = j;
+ tree[j] = pi;
+ pj->index = i;
+ tree[i] = pj;
+#elif 0
SWAP(uint, heap->tree[i]->index, heap->tree[j]->index);
SWAP(HeapNode *, heap->tree[i], heap->tree[j]);
#else
@@ -105,6 +111,7 @@ BLI_INLINE void heap_swap(Heap *heap, const uint i, const uint j)
static void heap_down(Heap *heap, uint i)
{
/* size won't change in the loop */
+ HeapNode **const tree = heap->tree;
const uint size = heap->size;
while (1) {
@@ -112,14 +119,14 @@ static void heap_down(Heap *heap, uint i)
const uint r = HEAP_RIGHT(i);
uint smallest = i;
- if ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[smallest])) {
+ if (LIKELY(l < size) && HEAP_COMPARE(tree[l], tree[smallest])) {
smallest = l;
}
- if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) {
+ if (LIKELY(r < size) && HEAP_COMPARE(tree[r], tree[smallest])) {
smallest = r;
}
- if (smallest == i) {
+ if (UNLIKELY(smallest == i)) {
break;
}
@@ -130,10 +137,12 @@ static void heap_down(Heap *heap, uint i)
static void heap_up(Heap *heap, uint i)
{
- while (i > 0) {
+ HeapNode **const tree = heap->tree;
+
+ while (LIKELY(i > 0)) {
const uint p = HEAP_PARENT(i);
- if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) {
+ if (HEAP_COMPARE(tree[p], tree[i])) {
break;
}
heap_swap(heap, p, i);
@@ -318,6 +327,17 @@ HeapNode *BLI_heap_top(const Heap *heap)
}
/**
+ * Return the value of top node of the heap.
+ * This is the node with the lowest value.
+ */
+float BLI_heap_top_value(const Heap *heap)
+{
+ BLI_assert(heap->size != 0);
+
+ return heap->tree[0]->value;
+}
+
+/**
* Pop the top node off the heap and return it's pointer.
*/
void *BLI_heap_pop_min(Heap *heap)
@@ -394,6 +414,9 @@ void *BLI_heap_node_ptr(const HeapNode *node)
static bool heap_is_minheap(const Heap *heap, uint root)
{
if (root < heap->size) {
+ if (heap->tree[root]->index != root) {
+ return false;
+ }
const uint l = HEAP_LEFT(root);
if (l < heap->size) {
if (HEAP_COMPARE(heap->tree[l], heap->tree[root]) || !heap_is_minheap(heap, l)) {
diff --git a/source/blender/blenlib/intern/BLI_heap_simple.c b/source/blender/blenlib/intern/BLI_heap_simple.c
new file mode 100644
index 00000000000..777b9c61b28
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_heap_simple.c
@@ -0,0 +1,247 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/BLI_heap_simple.c
+ * \ingroup bli
+ *
+ * A min-heap / priority queue ADT.
+ *
+ * Simplified version of the heap that only supports insertion and removal from top.
+ *
+ * See BLI_heap.c for a more full featured heap implementation.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_heap_simple.h"
+#include "BLI_strict_flags.h"
+
+#define HEAP_PARENT(i) (((i) - 1) >> 1)
+
+/* -------------------------------------------------------------------- */
+/** \name HeapSimple Internal Structs
+ * \{ */
+
+typedef struct HeapSimpleNode {
+ float value;
+ void *ptr;
+} HeapSimpleNode;
+
+struct HeapSimple {
+ uint size;
+ uint bufsize;
+ HeapSimpleNode *tree;
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name HeapSimple Internal Functions
+ * \{ */
+
+static void heapsimple_down(HeapSimple *heap, uint start_i, const HeapSimpleNode *init)
+{
+#if 1
+ /* The compiler isn't smart enough to realize that all computations
+ * using index here can be modified to work with byte offset. */
+ uint8_t * const tree_buf = (uint8_t *)heap->tree;
+
+#define OFFSET(i) (i * (uint)sizeof(HeapSimpleNode))
+#define NODE(offset) (*(HeapSimpleNode*)(tree_buf + (offset)))
+#else
+ HeapSimpleNode *const tree = heap->tree;
+
+#define OFFSET(i) (i)
+#define NODE(i) tree[i]
+#endif
+
+#define HEAP_LEFT_OFFSET(i) (((i) << 1) + OFFSET(1))
+
+ const uint size = OFFSET(heap->size);
+
+ /* Pull the active node values into locals. This allows spilling
+ * the data from registers instead of literally swapping nodes. */
+ float active_val = init->value;
+ void *active_ptr = init->ptr;
+
+ /* Prepare the first iteration and spill value. */
+ uint i = OFFSET(start_i);
+
+ NODE(i).value = active_val;
+
+ for (;;) {
+ const uint l = HEAP_LEFT_OFFSET(i);
+ const uint r = l + OFFSET(1); /* right */
+
+ /* Find the child with the smallest value. */
+ uint smallest = i;
+
+ if (LIKELY(l < size) && NODE(l).value < active_val) {
+ smallest = l;
+ }
+ if (LIKELY(r < size) && NODE(r).value < NODE(smallest).value) {
+ smallest = r;
+ }
+
+ if (UNLIKELY(smallest == i)) {
+ break;
+ }
+
+ /* Move the smallest child into the current node.
+ * Skip padding: for some reason that makes it faster here. */
+ NODE(i).value = NODE(smallest).value;
+ NODE(i).ptr = NODE(smallest).ptr;
+
+ /* Proceed to next iteration and spill value. */
+ i = smallest;
+ NODE(i).value = active_val;
+ }
+
+ /* Spill the pointer into the final position of the node. */
+ NODE(i).ptr = active_ptr;
+
+#undef NODE
+#undef OFFSET
+#undef HEAP_LEFT_OFFSET
+}
+
+static void heapsimple_up(HeapSimple *heap, uint i, float active_val, void *active_ptr)
+{
+ HeapSimpleNode *const tree = heap->tree;
+
+ while (LIKELY(i > 0)) {
+ const uint p = HEAP_PARENT(i);
+
+ if (active_val >= tree[p].value) {
+ break;
+ }
+
+ tree[i] = tree[p];
+ i = p;
+ }
+
+ tree[i].value = active_val;
+ tree[i].ptr = active_ptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public HeapSimple API
+ * \{ */
+
+/**
+ * Creates a new simple heap, which only supports insertion and removal from top.
+ *
+ * \note Use when the size of the heap is known in advance.
+ */
+HeapSimple *BLI_heapsimple_new_ex(uint tot_reserve)
+{
+ HeapSimple *heap = MEM_mallocN(sizeof(HeapSimple), __func__);
+ /* ensure we have at least one so we can keep doubling it */
+ heap->size = 0;
+ heap->bufsize = MAX2(1u, tot_reserve);
+ heap->tree = MEM_mallocN(heap->bufsize * sizeof(HeapSimpleNode), "BLIHeapSimpleTree");
+ return heap;
+}
+
+HeapSimple *BLI_heapsimple_new(void)
+{
+ return BLI_heapsimple_new_ex(1);
+}
+
+void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
+{
+ if (ptrfreefp) {
+ for (uint i = 0; i < heap->size; i++) {
+ ptrfreefp(heap->tree[i].ptr);
+ }
+ }
+
+ MEM_freeN(heap->tree);
+ MEM_freeN(heap);
+}
+
+void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
+{
+ if (ptrfreefp) {
+ for (uint i = 0; i < heap->size; i++) {
+ ptrfreefp(heap->tree[i].ptr);
+ }
+ }
+
+ heap->size = 0;
+}
+
+/**
+ * Insert heap node with a value (often a 'cost') and pointer into the heap,
+ * duplicate values are allowed.
+ */
+void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr)
+{
+ if (UNLIKELY(heap->size >= heap->bufsize)) {
+ heap->bufsize *= 2;
+ heap->tree = MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree));
+ }
+
+ heapsimple_up(heap, heap->size++, value, ptr);
+}
+
+bool BLI_heapsimple_is_empty(const HeapSimple *heap)
+{
+ return (heap->size == 0);
+}
+
+uint BLI_heapsimple_len(const HeapSimple *heap)
+{
+ return heap->size;
+}
+
+/**
+ * Return the lowest value of the heap.
+ */
+float BLI_heapsimple_top_value(const HeapSimple *heap)
+{
+ BLI_assert(heap->size != 0);
+
+ return heap->tree[0].value;
+}
+
+/**
+ * Pop the top node off the heap and return it's pointer.
+ */
+void *BLI_heapsimple_pop_min(HeapSimple *heap)
+{
+ BLI_assert(heap->size != 0);
+
+ void *ptr = heap->tree[0].ptr;
+
+ if (--heap->size) {
+ heapsimple_down(heap, 0, &heap->tree[heap->size]);
+ }
+
+ return ptr;
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 467eed97a74..7959ca4c0f2 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -56,6 +56,7 @@
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
#include "BLI_task.h"
+#include "BLI_heap_simple.h"
#include "BLI_strict_flags.h"
@@ -167,6 +168,18 @@ typedef struct BVHRayCastData {
BVHTreeRayHit hit;
} BVHRayCastData;
+typedef struct BVHNearestProjectedData {
+ const BVHTree *tree;
+ struct DistProjectedAABBPrecalc precalc;
+ bool closest_axis[3];
+ float clip_plane[6][4];
+ int clip_plane_len;
+ BVHTree_NearestProjectedCallback callback;
+ void *userdata;
+ BVHTreeNearest nearest;
+
+} BVHNearestProjectedData;
+
/** \} */
@@ -201,74 +214,6 @@ MINLINE axis_t max_axis(axis_t a, axis_t b)
}
#endif
-#if 0
-
-/*
- * Generic push and pop heap
- */
-#define PUSH_HEAP_BODY(HEAP_TYPE, PRIORITY, heap, heap_size) \
- { \
- HEAP_TYPE element = heap[heap_size - 1]; \
- int child = heap_size - 1; \
- while (child != 0) { \
- int parent = (child - 1) / 2; \
- if (PRIORITY(element, heap[parent])) { \
- heap[child] = heap[parent]; \
- child = parent; \
- } \
- else { \
- break; \
- } \
- } \
- heap[child] = element; \
- } (void)0
-
-#define POP_HEAP_BODY(HEAP_TYPE, PRIORITY, heap, heap_size) \
- { \
- HEAP_TYPE element = heap[heap_size - 1]; \
- int parent = 0; \
- while (parent < (heap_size - 1) / 2) { \
- int child2 = (parent + 1) * 2; \
- if (PRIORITY(heap[child2 - 1], heap[child2])) { \
- child2--; \
- } \
- if (PRIORITY(element, heap[child2])) { \
- break; \
- } \
- heap[parent] = heap[child2]; \
- parent = child2; \
- } \
- heap[parent] = element; \
- } (void)0
-
-static bool ADJUST_MEMORY(void *local_memblock, void **memblock, int new_size, int *max_size, int size_per_item)
-{
- int new_max_size = *max_size * 2;
- void *new_memblock = NULL;
-
- if (new_size <= *max_size) {
- return true;
- }
-
- if (*memblock == local_memblock) {
- new_memblock = malloc(size_per_item * new_max_size);
- memcpy(new_memblock, *memblock, size_per_item * *max_size);
- }
- else {
- new_memblock = realloc(*memblock, size_per_item * new_max_size);
- }
-
- if (new_memblock) {
- *memblock = new_memblock;
- *max_size = new_max_size;
- return true;
- }
- else {
- return false;
- }
-}
-#endif
-
/**
* Introsort
* with permission deriven from the following Java code:
@@ -276,17 +221,7 @@ static bool ADJUST_MEMORY(void *local_memblock, void **memblock, int new_size, i
* and he derived it from the SUN STL
*/
-//static int size_threshold = 16;
-#if 0
-/**
- * Common methods for all algorithms
- */
-static int floor_lg(int a)
-{
- return (int)(floor(log(a) / log(2)));
-}
-#endif
static void node_minmax_init(const BVHTree *tree, BVHNode *node)
{
@@ -344,39 +279,6 @@ static int bvh_partition(BVHNode **a, int lo, int hi, BVHNode *x, int axis)
}
}
-#if 0
-/**
- * Heapsort algorithm
- */
-static void bvh_downheap(BVHNode **a, int i, int n, int lo, int axis)
-{
- BVHNode *d = a[lo + i - 1];
- int child;
- while (i <= n / 2) {
- child = 2 * i;
- if ((child < n) && ((a[lo + child - 1])->bv[axis] < (a[lo + child])->bv[axis])) {
- child++;
- }
- if (!(d->bv[axis] < (a[lo + child - 1])->bv[axis])) break;
- a[lo + i - 1] = a[lo + child - 1];
- i = child;
- }
- a[lo + i - 1] = d;
-}
-
-static void bvh_heapsort(BVHNode **a, int lo, int hi, int axis)
-{
- int n = hi - lo, i;
- for (i = n / 2; i >= 1; i = i - 1) {
- bvh_downheap(a, i, n, lo, axis);
- }
- for (i = n; i > 1; i = i - 1) {
- SWAP(BVHNode *, a[lo], a[lo + i - 1]);
- bvh_downheap(a, 1, i - 1, lo, axis);
- }
-}
-#endif
-
static BVHNode *bvh_medianof3(BVHNode **a, int lo, int mid, int hi, int axis) /* returns Sortable */
{
if ((a[mid])->bv[axis] < (a[lo])->bv[axis]) {
@@ -401,41 +303,6 @@ static BVHNode *bvh_medianof3(BVHNode **a, int lo, int mid, int hi, int axis) /
}
}
-#if 0
-/*
- * Quicksort algorithm modified for Introsort
- */
-static void bvh_introsort_loop(BVHNode **a, int lo, int hi, int depth_limit, int axis)
-{
- int p;
-
- while (hi - lo > size_threshold) {
- if (depth_limit == 0) {
- bvh_heapsort(a, lo, hi, axis);
- return;
- }
- depth_limit = depth_limit - 1;
- p = bvh_partition(a, lo, hi, bvh_medianof3(a, lo, lo + ((hi - lo) / 2) + 1, hi - 1, axis), axis);
- bvh_introsort_loop(a, p, hi, depth_limit, axis);
- hi = p;
- }
-}
-
-static void sort(BVHNode **a0, int begin, int end, int axis)
-{
- if (begin < end) {
- BVHNode **a = a0;
- bvh_introsort_loop(a, begin, end, 2 * floor_lg(end - begin), axis);
- bvh_insertionsort(a, begin, end, axis);
- }
-}
-
-static void sort_along_axis(BVHTree *tree, int start, int end, int axis)
-{
- sort(tree->nodes, start, end, axis);
-}
-#endif
-
/**
* \note after a call to this function you can expect one of:
* - every node to left of a[n] are smaller or equal to it
@@ -501,25 +368,27 @@ static void create_kdop_hull(const BVHTree *tree, BVHNode *node, const float *co
}
/**
- * \note depends on the fact that the BVH's for each face is already build
+ * \note depends on the fact that the BVH's for each face is already built
*/
static void refit_kdop_hull(const BVHTree *tree, BVHNode *node, int start, int end)
{
float newmin, newmax;
- float *bv = node->bv;
+ float *__restrict bv = node->bv;
int j;
axis_t axis_iter;
node_minmax_init(tree, node);
for (j = start; j < end; j++) {
+ float *__restrict node_bv = tree->nodes[j]->bv;
+
/* for all Axes. */
for (axis_iter = tree->start_axis; axis_iter < tree->stop_axis; axis_iter++) {
- newmin = tree->nodes[j]->bv[(2 * axis_iter)];
+ newmin = node_bv[(2 * axis_iter)];
if ((newmin < bv[(2 * axis_iter)]))
bv[(2 * axis_iter)] = newmin;
- newmax = tree->nodes[j]->bv[(2 * axis_iter) + 1];
+ newmax = node_bv[(2 * axis_iter) + 1];
if ((newmax > bv[(2 * axis_iter) + 1]))
bv[(2 * axis_iter) + 1] = newmax;
}
@@ -1398,35 +1267,18 @@ static float calc_nearest_point_squared(const float proj[3], BVHNode *node, floa
/* nearest on AABB hull */
for (i = 0; i != 3; i++, bv += 2) {
- if (bv[0] > proj[i])
- nearest[i] = bv[0];
- else if (bv[1] < proj[i])
- nearest[i] = bv[1];
- else
- nearest[i] = proj[i];
+ float val = proj[i];
+ if (bv[0] > val)
+ val = bv[0];
+ if (bv[1] < val)
+ val = bv[1];
+ nearest[i] = val;
}
-#if 0
- /* nearest on a general hull */
- copy_v3_v3(nearest, data->co);
- for (i = data->tree->start_axis; i != data->tree->stop_axis; i++, bv += 2) {
- float proj = dot_v3v3(nearest, bvhtree_kdop_axes[i]);
- float dl = bv[0] - proj;
- float du = bv[1] - proj;
-
- if (dl > 0) {
- madd_v3_v3fl(nearest, bvhtree_kdop_axes[i], dl);
- }
- else if (du < 0) {
- madd_v3_v3fl(nearest, bvhtree_kdop_axes[i], du);
- }
- }
-#endif
-
return len_squared_v3v3(proj, nearest);
}
-/* TODO: use a priority queue to reduce the number of nodes looked on */
+/* Depth first search method */
static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node)
{
if (node->totnode == 0) {
@@ -1470,104 +1322,53 @@ static void dfs_find_nearest_begin(BVHNearestData *data, BVHNode *node)
dfs_find_nearest_dfs(data, node);
}
-
-#if 0
-
-typedef struct NodeDistance {
- BVHNode *node;
- float dist;
-
-} NodeDistance;
-
-#define DEFAULT_FIND_NEAREST_HEAP_SIZE 1024
-
-#define NodeDistance_priority(a, b) ((a).dist < (b).dist)
-
-static void NodeDistance_push_heap(NodeDistance *heap, int heap_size)
-PUSH_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size)
-
-static void NodeDistance_pop_heap(NodeDistance *heap, int heap_size)
-POP_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size)
-
-/* NN function that uses an heap.. this functions leads to an optimal number of min-distance
- * but for normal tri-faces and BV 6-dop.. a simple dfs with local heuristics (as implemented
- * in source/blender/blenkernel/intern/shrinkwrap.c) works faster.
- *
- * It may make sense to use this function if the callback queries are very slow.. or if its impossible
- * to get a nice heuristic
- *
- * this function uses "malloc/free" instead of the MEM_* because it intends to be thread safe */
-static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
+/* Priority queue method */
+static void heap_find_nearest_inner(BVHNearestData *data, HeapSimple *heap, BVHNode *node)
{
- int i;
- NodeDistance default_heap[DEFAULT_FIND_NEAREST_HEAP_SIZE];
- NodeDistance *heap = default_heap, current;
- int heap_size = 0, max_heap_size = sizeof(default_heap) / sizeof(default_heap[0]);
- float nearest[3];
-
- int callbacks = 0, push_heaps = 0;
-
if (node->totnode == 0) {
- dfs_find_nearest_dfs(data, node);
- return;
+ if (data->callback)
+ data->callback(data->userdata, node->index, data->co, &data->nearest);
+ else {
+ data->nearest.index = node->index;
+ data->nearest.dist_sq = calc_nearest_point_squared(data->proj, node, data->nearest.co);
+ }
}
+ else {
+ float nearest[3];
- current.node = node;
- current.dist = calc_nearest_point(data->proj, node, nearest);
+ for (int i = 0; i != node->totnode; i++) {
+ float dist_sq = calc_nearest_point_squared(data->proj, node->children[i], nearest);
- while (current.dist < data->nearest.dist) {
-// printf("%f : %f\n", current.dist, data->nearest.dist);
- for (i = 0; i < current.node->totnode; i++) {
- BVHNode *child = current.node->children[i];
- if (child->totnode == 0) {
- callbacks++;
- dfs_find_nearest_dfs(data, child);
+ if (dist_sq < data->nearest.dist_sq) {
+ BLI_heapsimple_insert(heap, dist_sq, node->children[i]);
}
- else {
- /* adjust heap size */
- if ((heap_size >= max_heap_size) &&
- ADJUST_MEMORY(default_heap, (void **)&heap,
- heap_size + 1, &max_heap_size, sizeof(heap[0])) == false)
- {
- printf("WARNING: bvh_find_nearest got out of memory\n");
-
- if (heap != default_heap)
- free(heap);
+ }
+ }
+}
- return;
- }
+static void heap_find_nearest_begin(BVHNearestData *data, BVHNode *root)
+{
+ float nearest[3];
+ float dist_sq = calc_nearest_point_squared(data->proj, root, nearest);
- heap[heap_size].node = current.node->children[i];
- heap[heap_size].dist = calc_nearest_point(data->proj, current.node->children[i], nearest);
+ if (dist_sq < data->nearest.dist_sq) {
+ HeapSimple *heap = BLI_heapsimple_new_ex(32);
- if (heap[heap_size].dist >= data->nearest.dist) continue;
- heap_size++;
+ heap_find_nearest_inner(data, heap, root);
- NodeDistance_push_heap(heap, heap_size);
- // PUSH_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size);
- push_heaps++;
- }
+ while (!BLI_heapsimple_is_empty(heap) && BLI_heapsimple_top_value(heap) < data->nearest.dist_sq) {
+ BVHNode *node = BLI_heapsimple_pop_min(heap);
+ heap_find_nearest_inner(data, heap, node);
}
- if (heap_size == 0) break;
-
- current = heap[0];
- NodeDistance_pop_heap(heap, heap_size);
-// POP_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size);
- heap_size--;
+ BLI_heapsimple_free(heap, NULL);
}
-
-// printf("hsize=%d, callbacks=%d, pushs=%d\n", heap_size, callbacks, push_heaps);
-
- if (heap != default_heap)
- free(heap);
}
-#endif
-
-int BLI_bvhtree_find_nearest(
+int BLI_bvhtree_find_nearest_ex(
BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
- BVHTree_NearestPointCallback callback, void *userdata)
+ BVHTree_NearestPointCallback callback, void *userdata,
+ int flag)
{
axis_t axis_iter;
@@ -1594,8 +1395,14 @@ int BLI_bvhtree_find_nearest(
}
/* dfs search */
- if (root)
- dfs_find_nearest_begin(&data, root);
+ if (root) {
+ if (flag & BVH_NEAREST_OPTIMAL_ORDER) {
+ heap_find_nearest_begin(&data, root);
+ }
+ else {
+ dfs_find_nearest_begin(&data, root);
+ }
+ }
/* copy back results */
if (nearest) {
@@ -1605,6 +1412,13 @@ int BLI_bvhtree_find_nearest(
return data.nearest.index;
}
+int BLI_bvhtree_find_nearest(
+ BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
+ BVHTree_NearestPointCallback callback, void *userdata)
+{
+ return BLI_bvhtree_find_nearest_ex(tree, co, nearest, callback, userdata, 0);
+}
+
/** \} */
@@ -1754,35 +1568,6 @@ static void dfs_raycast_all(BVHRayCastData *data, BVHNode *node)
}
}
-#if 0
-static void iterative_raycast(BVHRayCastData *data, BVHNode *node)
-{
- while (node) {
- float dist = fast_ray_nearest_hit(data, node);
- if (dist >= data->hit.dist) {
- node = node->skip[1];
- continue;
- }
-
- if (node->totnode == 0) {
- if (data->callback) {
- data->callback(data->userdata, node->index, &data->ray, &data->hit);
- }
- else {
- data->hit.index = node->index;
- data->hit.dist = dist;
- madd_v3_v3v3fl(data->hit.co, data->ray.origin, data->ray.direction, dist);
- }
-
- node = node->skip[1];
- }
- else {
- node = node->children[0];
- }
- }
-}
-#endif
-
static void bvhtree_ray_cast_data_precalc(BVHRayCastData *data, int flag)
{
int i;
@@ -2020,6 +1805,198 @@ int BLI_bvhtree_range_query(
/* -------------------------------------------------------------------- */
+/** \name BLI_bvhtree_nearest_projected
+* \{ */
+
+static void bvhtree_nearest_projected_dfs_recursive(
+ BVHNearestProjectedData *__restrict data, const BVHNode *node)
+{
+ if (node->totnode == 0) {
+ if (data->callback) {
+ data->callback(
+ data->userdata, node->index, &data->precalc,
+ NULL, 0,
+ &data->nearest);
+ }
+ else {
+ data->nearest.index = node->index;
+ data->nearest.dist_sq = dist_squared_to_projected_aabb(
+ &data->precalc,
+ (float[3]) {node->bv[0], node->bv[2], node->bv[4]},
+ (float[3]) {node->bv[1], node->bv[3], node->bv[5]},
+ data->closest_axis);
+ }
+ }
+ else {
+ /* First pick the closest node to recurse into */
+ if (data->closest_axis[node->main_axis]) {
+ for (int i = 0; i != node->totnode; i++) {
+ const float *bv = node->children[i]->bv;
+
+ if (dist_squared_to_projected_aabb(
+ &data->precalc,
+ (float[3]) {bv[0], bv[2], bv[4]},
+ (float[3]) {bv[1], bv[3], bv[5]},
+ data->closest_axis) <= data->nearest.dist_sq)
+ {
+ bvhtree_nearest_projected_dfs_recursive(data, node->children[i]);
+ }
+ }
+ }
+ else {
+ for (int i = node->totnode; i--;) {
+ const float *bv = node->children[i]->bv;
+
+ if (dist_squared_to_projected_aabb(
+ &data->precalc,
+ (float[3]) {bv[0], bv[2], bv[4]},
+ (float[3]) {bv[1], bv[3], bv[5]},
+ data->closest_axis) <= data->nearest.dist_sq)
+ {
+ bvhtree_nearest_projected_dfs_recursive(data, node->children[i]);
+ }
+ }
+ }
+ }
+}
+
+static void bvhtree_nearest_projected_with_clipplane_test_dfs_recursive(
+ BVHNearestProjectedData *__restrict data, const BVHNode *node)
+{
+ if (node->totnode == 0) {
+ if (data->callback) {
+ data->callback(
+ data->userdata, node->index, &data->precalc,
+ data->clip_plane, data->clip_plane_len,
+ &data->nearest);
+ }
+ else {
+ data->nearest.index = node->index;
+ data->nearest.dist_sq = dist_squared_to_projected_aabb(
+ &data->precalc,
+ (float[3]) {node->bv[0], node->bv[2], node->bv[4]},
+ (float[3]) {node->bv[1], node->bv[3], node->bv[5]},
+ data->closest_axis);
+ }
+ }
+ else {
+ /* First pick the closest node to recurse into */
+ if (data->closest_axis[node->main_axis]) {
+ for (int i = 0; i != node->totnode; i++) {
+ const float *bv = node->children[i]->bv;
+ const float bb_min[3] = {bv[0], bv[2], bv[4]};
+ const float bb_max[3] = {bv[1], bv[3], bv[5]};
+
+ int isect_type = isect_aabb_planes_v3(data->clip_plane, data->clip_plane_len, bb_min, bb_max);
+
+ if ((isect_type != ISECT_AABB_PLANE_BEHIND_ANY) && dist_squared_to_projected_aabb(
+ &data->precalc, bb_min, bb_max,
+ data->closest_axis) <= data->nearest.dist_sq)
+ {
+ if (isect_type == ISECT_AABB_PLANE_CROSS_ANY) {
+ bvhtree_nearest_projected_with_clipplane_test_dfs_recursive(data, node->children[i]);
+ }
+ else {
+ /* ISECT_AABB_PLANE_IN_FRONT_ALL */
+ bvhtree_nearest_projected_dfs_recursive(data, node->children[i]);
+ }
+ }
+ }
+ }
+ else {
+ for (int i = node->totnode; i--;) {
+ const float *bv = node->children[i]->bv;
+ const float bb_min[3] = {bv[0], bv[2], bv[4]};
+ const float bb_max[3] = {bv[1], bv[3], bv[5]};
+
+ int isect_type = isect_aabb_planes_v3(data->clip_plane, data->clip_plane_len, bb_min, bb_max);
+
+ if (isect_type != ISECT_AABB_PLANE_BEHIND_ANY && dist_squared_to_projected_aabb(
+ &data->precalc, bb_min, bb_max,
+ data->closest_axis) <= data->nearest.dist_sq)
+ {
+ if (isect_type == ISECT_AABB_PLANE_CROSS_ANY) {
+ bvhtree_nearest_projected_with_clipplane_test_dfs_recursive(data, node->children[i]);
+ }
+ else {
+ /* ISECT_AABB_PLANE_IN_FRONT_ALL */
+ bvhtree_nearest_projected_dfs_recursive(data, node->children[i]);
+ }
+ }
+ }
+ }
+ }
+}
+
+int BLI_bvhtree_find_nearest_projected(
+ BVHTree *tree, float projmat[4][4], float winsize[2], float mval[2],
+ float clip_plane[6][4], int clip_plane_len,
+ BVHTreeNearest *nearest,
+ BVHTree_NearestProjectedCallback callback, void *userdata)
+{
+ BVHNode *root = tree->nodes[tree->totleaf];
+ if (root != NULL) {
+ BVHNearestProjectedData data;
+ dist_squared_to_projected_aabb_precalc(
+ &data.precalc, projmat, winsize, mval);
+
+ data.callback = callback;
+ data.userdata = userdata;
+
+ if (clip_plane) {
+ data.clip_plane_len = clip_plane_len;
+ for (int i = 0; i < data.clip_plane_len; i++) {
+ copy_v4_v4(data.clip_plane[i], clip_plane[i]);
+ }
+ }
+ else {
+ data.clip_plane_len = 1;
+ planes_from_projmat(
+ projmat,
+ NULL, NULL, NULL, NULL,
+ data.clip_plane[0], NULL);
+ }
+
+ if (nearest) {
+ memcpy(&data.nearest, nearest, sizeof(*nearest));
+ }
+ else {
+ data.nearest.index = -1;
+ data.nearest.dist_sq = FLT_MAX;
+ }
+ {
+ const float bb_min[3] = {root->bv[0], root->bv[2], root->bv[4]};
+ const float bb_max[3] = {root->bv[1], root->bv[3], root->bv[5]};
+
+ int isect_type = isect_aabb_planes_v3(data.clip_plane, data.clip_plane_len, bb_min, bb_max);
+
+ if (isect_type != 0 && dist_squared_to_projected_aabb(
+ &data.precalc, bb_min, bb_max,
+ data.closest_axis) <= data.nearest.dist_sq)
+ {
+ if (isect_type == 1) {
+ bvhtree_nearest_projected_with_clipplane_test_dfs_recursive(&data, root);
+ }
+ else {
+ bvhtree_nearest_projected_dfs_recursive(&data, root);
+ }
+ }
+ }
+
+ if (nearest) {
+ memcpy(nearest, &data.nearest, sizeof(*nearest));
+ }
+
+ return data.nearest.index;
+ }
+ return -1;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
/** \name BLI_bvhtree_walk_dfs
* \{ */
diff --git a/source/blender/blenlib/intern/BLI_memiter.c b/source/blender/blenlib/intern/BLI_memiter.c
new file mode 100644
index 00000000000..9c5f026f836
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_memiter.c
@@ -0,0 +1,357 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/BLI_memiter.c
+ * \ingroup bli
+ *
+ * Simple, fast memory allocator for allocating many small elements of different sizes
+ * in fixed size memory chunks,
+ * although allocations bigger than the chunk size are supported.
+ * They will reduce the efficiency of this data-structure.
+ * Elements are pointer aligned.
+ *
+ * Supports:
+ *
+ * - Allocation of mixed sizes.
+ * - Iterating over allocations in-order.
+ * - Clearing for re-use.
+ *
+ * Unsupported:
+ *
+ * - Freeing individual elements.
+ *
+ * \note We could inline iteration stepping,
+ * but tests show this doesn't give noticeable speedup.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+
+#include "BLI_memiter.h" /* own include */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_strict_flags.h" /* keep last */
+
+typedef uintptr_t data_t;
+typedef intptr_t offset_t;
+
+/* Write the chunk terminator on adding each element.
+ * typically we rely on the 'count' to avoid iterating past the end. */
+// #define USE_TERMINATE_PARANOID
+
+/* Currently totalloc isnt used. */
+ // #define USE_TOTALLOC
+
+/* pad must be power of two */
+#define PADUP(num, pad) (((num) + ((pad) - 1)) & ~((pad) - 1))
+
+typedef struct BLI_memiter_elem {
+ offset_t size;
+ data_t data[0];
+} BLI_memiter_elem;
+
+typedef struct BLI_memiter_chunk {
+ struct BLI_memiter_chunk *next;
+ /**
+ * internal format is:
+ * ``[next_pointer, size:data, size:data, ..., negative_offset]``
+ *
+ * Where negative offset rewinds to the start.
+ */
+ data_t data[0];
+} BLI_memiter_chunk;
+
+typedef struct BLI_memiter {
+ /* A pointer to 'head' is needed so we can iterate in the order allocated. */
+ struct BLI_memiter_chunk *head, *tail;
+ data_t *data_curr;
+ data_t *data_last;
+ /* Used unless a large element is requested.
+ * (which should be very rare!). */
+ uint chunk_size_in_bytes_min;
+ uint count;
+#ifdef USE_TOTALLOC
+ uint totalloc;
+#endif
+} BLI_memiter;
+
+
+BLI_INLINE uint data_offset_from_size(uint size)
+{
+ return (PADUP(size, (uint)sizeof(data_t))) / (uint)sizeof(data_t);
+}
+
+static void memiter_set_rewind_offset(BLI_memiter *mi)
+{
+ BLI_memiter_elem *elem = (BLI_memiter_elem *)mi->data_curr;
+ elem->size = (offset_t)(((data_t *)mi->tail) - mi->data_curr);
+ BLI_assert(elem->size < 0);
+}
+
+static void memiter_init(BLI_memiter *mi)
+{
+ mi->head = NULL;
+ mi->tail = NULL;
+ mi->data_curr = NULL;
+ mi->data_last = NULL;
+ mi->count = 0;
+#ifdef USE_TOTALLOC
+ mi->totalloc = 0;
+#endif
+}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public API's
+ * \{ */
+
+/**
+ * \param chunk_size_min: Should be a power of two and
+ * significantly larger than the average element size used.
+ *
+ * While allocations of any size are supported, they won't be efficient
+ * (effectively becoming a single-linked list).
+ *
+ * Its intended that many elements can be stored per chunk.
+ */
+BLI_memiter *BLI_memiter_create(uint chunk_size_min)
+{
+ BLI_memiter *mi = MEM_mallocN(sizeof(BLI_memiter), "BLI_memiter");
+ memiter_init(mi);
+
+ /* Small values are used for tests to check for correctness,
+ * but otherwise not that useful. */
+ const uint slop_space = (sizeof(BLI_memiter_chunk) + MEM_SIZE_OVERHEAD);
+ if (chunk_size_min >= 1024) {
+ /* As long as the input is a power of 2, this will give efficient sizes. */
+ chunk_size_min -= slop_space;
+ }
+
+ mi->chunk_size_in_bytes_min = chunk_size_min;
+ return mi;
+}
+
+void *BLI_memiter_alloc(BLI_memiter *mi, uint elem_size)
+{
+ const uint data_offset = data_offset_from_size(elem_size);
+ data_t *data_curr_next = mi->data_curr + (1 + data_offset);
+
+ if (UNLIKELY(mi->data_curr == NULL) || (data_curr_next > mi->data_last)) {
+
+#ifndef USE_TERMINATE_PARANOID
+ if (mi->data_curr != NULL) {
+ memiter_set_rewind_offset(mi);
+ }
+#endif
+
+ uint chunk_size_in_bytes = mi->chunk_size_in_bytes_min;
+ if (UNLIKELY(chunk_size_in_bytes < elem_size + (uint)sizeof(data_t[2]))) {
+ chunk_size_in_bytes = elem_size + (uint)sizeof(data_t[2]);
+ }
+ uint chunk_size = data_offset_from_size(chunk_size_in_bytes);
+ BLI_memiter_chunk *chunk = MEM_mallocN(
+ sizeof(BLI_memiter_chunk) +
+ (chunk_size * sizeof(data_t)),
+ "BLI_memiter_chunk");
+
+ if (mi->head == NULL) {
+ BLI_assert(mi->tail == NULL);
+ mi->head = chunk;
+ }
+ else {
+ mi->tail->next = chunk;
+ }
+ mi->tail = chunk;
+ chunk->next = NULL;
+
+ mi->data_curr = chunk->data;
+ mi->data_last = chunk->data + (chunk_size - 1);
+ data_curr_next = mi->data_curr + (1 + data_offset);
+ }
+
+ BLI_assert(data_curr_next <= mi->data_last);
+
+ BLI_memiter_elem *elem = (BLI_memiter_elem *)mi->data_curr;
+ elem->size = (offset_t)elem_size;
+ mi->data_curr = data_curr_next;
+
+#ifdef USE_TERMINATE_PARANOID
+ memiter_set_rewind_offset(mi);
+#endif
+
+ mi->count += 1;
+
+#ifdef USE_TOTALLOC
+ mi->totalloc += elem_size;
+#endif
+
+ return elem->data;
+}
+
+void *BLI_memiter_calloc(BLI_memiter *mi, uint elem_size)
+{
+ void *data = BLI_memiter_alloc(mi, elem_size);
+ memset(data, 0, elem_size);
+ return data;
+}
+
+void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
+{
+ void *data = BLI_memiter_alloc(mi, elem_size);
+ memcpy(data, data_from, elem_size);
+}
+
+static void memiter_free_data(BLI_memiter *mi)
+{
+ BLI_memiter_chunk *chunk = mi->head;
+ while (chunk) {
+ BLI_memiter_chunk *chunk_next = chunk->next;
+ MEM_freeN(chunk);
+ chunk = chunk_next;
+ }
+}
+
+void BLI_memiter_destroy(BLI_memiter *mi)
+{
+ memiter_free_data(mi);
+ MEM_freeN(mi);
+}
+
+void BLI_memiter_clear(BLI_memiter *mi)
+{
+ memiter_free_data(mi);
+ memiter_init(mi);
+}
+
+uint BLI_memiter_count(const BLI_memiter *mi)
+{
+ return mi->count;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Helper API's
+ * \{ */
+
+/* Support direct lookup for first. */
+void *BLI_memiter_elem_first(BLI_memiter *mi)
+{
+ if (mi->head != NULL) {
+ BLI_memiter_chunk *chunk = mi->head;
+ BLI_memiter_elem *elem = (BLI_memiter_elem *)chunk->data;
+ return elem->data;
+ }
+ else {
+ return NULL;
+ }
+}
+
+void *BLI_memiter_elem_first_size(BLI_memiter *mi, uint *r_size)
+{
+ if (mi->head != NULL) {
+ BLI_memiter_chunk *chunk = mi->head;
+ BLI_memiter_elem *elem = (BLI_memiter_elem *)chunk->data;
+ *r_size = (uint)elem->size;
+ return elem->data;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Iterator API's
+ *
+ * \note We could loop over elements until a NULL chunk is found,
+ * however this means every allocation needs to preemptively run
+ * #memiter_set_rewind_offset (see #USE_TERMINATE_PARANOID).
+ * Unless we have a call to finalize allocation (which complicates usage).
+ * So use a counter instead.
+ *
+ * \{ */
+
+void BLI_memiter_iter_init(BLI_memiter *mi, BLI_memiter_handle *iter)
+{
+ iter->elem = mi->head ? (BLI_memiter_elem *)mi->head->data : NULL;
+ iter->elem_left = mi->count;
+}
+
+bool BLI_memiter_iter_done(const BLI_memiter_handle *iter)
+{
+ return iter->elem_left != 0;
+}
+
+BLI_INLINE void memiter_chunk_step(BLI_memiter_handle *iter)
+{
+ BLI_assert(iter->elem->size < 0);
+ BLI_memiter_chunk *chunk = (BLI_memiter_chunk *)(((data_t *)iter->elem) + iter->elem->size);
+ chunk = chunk->next;
+ iter->elem = chunk ? (BLI_memiter_elem *)chunk->data : NULL;
+ BLI_assert(iter->elem == NULL || iter->elem->size >= 0);
+}
+
+void *BLI_memiter_iter_step_size(BLI_memiter_handle *iter, uint *r_size)
+{
+ if (iter->elem_left != 0) {
+ iter->elem_left -= 1;
+ if (UNLIKELY(iter->elem->size < 0)) {
+ memiter_chunk_step(iter);
+ }
+ BLI_assert(iter->elem->size >= 0);
+ uint size = (uint)iter->elem->size;
+ *r_size = size; /* <-- only difference */
+ data_t *data = iter->elem->data;
+ iter->elem = (BLI_memiter_elem *)&data[data_offset_from_size(size)];
+ return (void *)data;
+ }
+ else {
+ return NULL;
+ }
+}
+
+void *BLI_memiter_iter_step(BLI_memiter_handle *iter)
+{
+ if (iter->elem_left != 0) {
+ iter->elem_left -= 1;
+ if (UNLIKELY(iter->elem->size < 0)) {
+ memiter_chunk_step(iter);
+ }
+ BLI_assert(iter->elem->size >= 0);
+ uint size = (uint)iter->elem->size;
+ data_t *data = iter->elem->data;
+ iter->elem = (BLI_memiter_elem *)&data[data_offset_from_size(size)];
+ return (void *)data;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/BLI_timer.c b/source/blender/blenlib/intern/BLI_timer.c
new file mode 100644
index 00000000000..7bb919d47e0
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_timer.c
@@ -0,0 +1,184 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/BLI_timer.c
+ * \ingroup bli
+ */
+
+#include "BLI_timer.h"
+#include "BLI_listbase.h"
+#include "BLI_callbacks.h"
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#define GET_TIME() PIL_check_seconds_timer()
+
+typedef struct TimedFunction {
+ struct TimedFunction *next, *prev;
+ BLI_timer_func func;
+ BLI_timer_data_free user_data_free;
+ void *user_data;
+ double next_time;
+ uintptr_t uuid;
+ bool tag_removal;
+ bool persistent;
+} TimedFunction;
+
+typedef struct TimerContainer {
+ ListBase funcs;
+ bool file_load_cb_registered;
+} TimerContainer;
+
+static TimerContainer GlobalTimer = { 0 };
+
+static void ensure_callback_is_registered(void);
+
+void BLI_timer_register(
+ uintptr_t uuid,
+ BLI_timer_func func,
+ void *user_data,
+ BLI_timer_data_free user_data_free,
+ double first_interval,
+ bool persistent)
+{
+ ensure_callback_is_registered();
+
+ TimedFunction *timed_func = MEM_callocN(sizeof(TimedFunction), __func__);
+ timed_func->func = func;
+ timed_func->user_data_free = user_data_free;
+ timed_func->user_data = user_data;
+ timed_func->next_time = GET_TIME() + first_interval;
+ timed_func->tag_removal = false;
+ timed_func->persistent = persistent;
+ timed_func->uuid = uuid;
+
+ BLI_addtail(&GlobalTimer.funcs, timed_func);
+}
+
+static void clear_user_data(TimedFunction *timed_func)
+{
+ if (timed_func->user_data_free) {
+ timed_func->user_data_free(timed_func->uuid, timed_func->user_data);
+ timed_func->user_data_free = NULL;
+ }
+}
+
+bool BLI_timer_unregister(uintptr_t uuid)
+{
+ LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
+ if (timed_func->uuid == uuid) {
+ if (timed_func->tag_removal) {
+ return false;
+ }
+ else {
+ timed_func->tag_removal = true;
+ clear_user_data(timed_func);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool BLI_timer_is_registered(uintptr_t uuid)
+{
+ LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
+ if (timed_func->uuid == uuid && !timed_func->tag_removal) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void execute_functions_if_necessary(void)
+{
+ double current_time = GET_TIME();
+
+ LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
+ if (timed_func->tag_removal) continue;
+ if (timed_func->next_time > current_time) continue;
+
+ double ret = timed_func->func(timed_func->uuid, timed_func->user_data);
+
+ if (ret < 0) {
+ timed_func->tag_removal = true;
+ }
+ else {
+ timed_func->next_time = current_time + ret;
+ }
+ }
+}
+
+static void remove_tagged_functions(void)
+{
+ for (TimedFunction *timed_func = GlobalTimer.funcs.first; timed_func; ) {
+ TimedFunction *next = timed_func->next;
+ if (timed_func->tag_removal) {
+ clear_user_data(timed_func);
+ BLI_freelinkN(&GlobalTimer.funcs, timed_func);
+ }
+ timed_func = next;
+ }
+}
+
+void BLI_timer_execute()
+{
+ execute_functions_if_necessary();
+ remove_tagged_functions();
+}
+
+void BLI_timer_free()
+{
+ LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
+ timed_func->tag_removal = true;
+ }
+
+ remove_tagged_functions();
+}
+
+struct Main;
+struct ID;
+static void remove_non_persistent_functions(struct Main *UNUSED(_1), struct ID *UNUSED(_2), void *UNUSED(_3))
+{
+ LISTBASE_FOREACH(TimedFunction *, timed_func, &GlobalTimer.funcs) {
+ if (!timed_func->persistent) {
+ timed_func->tag_removal = true;
+ }
+ }
+}
+
+static bCallbackFuncStore load_post_callback = {
+ NULL, NULL, /* next, prev */
+ remove_non_persistent_functions, /* func */
+ NULL, /* arg */
+ 0 /* alloc */
+};
+
+static void ensure_callback_is_registered()
+{
+ if (!GlobalTimer.file_load_cb_registered) {
+ BLI_callback_add(&load_post_callback, BLI_CB_EVT_LOAD_POST);
+ GlobalTimer.file_load_cb_registered = true;
+ }
+}
diff --git a/source/blender/blenlib/intern/array_store_utils.c b/source/blender/blenlib/intern/array_store_utils.c
index 83cd28ddf11..97e4207328b 100644
--- a/source/blender/blenlib/intern/array_store_utils.c
+++ b/source/blender/blenlib/intern/array_store_utils.c
@@ -43,9 +43,6 @@ BArrayStore *BLI_array_store_at_size_ensure(
BArrayStore **bs_p = &bs_stride->stride_table[stride - 1];
if ((*bs_p) == NULL) {
-#if 0
- unsigned int chunk_count = chunk_size;
-#else
/* calculate best chunk-count to fit a power of two */
unsigned int chunk_count = chunk_size;
{
@@ -54,7 +51,6 @@ BArrayStore *BLI_array_store_at_size_ensure(
size = MEM_SIZE_OPTIMAL(size);
chunk_count = size / stride;
}
-#endif
(*bs_p) = BLI_array_store_create(stride, chunk_count);
}
diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c
index 86c1faad096..30ad6c7838c 100644
--- a/source/blender/blenlib/intern/astar.c
+++ b/source/blender/blenlib/intern/astar.c
@@ -52,7 +52,7 @@
#include "BLI_compiler_attrs.h"
#include "BLI_alloca.h"
-#include "BLI_heap.h"
+#include "BLI_heap_simple.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
@@ -206,7 +206,7 @@ bool BLI_astar_graph_solve(
BLI_AStarGraph *as_graph, const int node_index_src, const int node_index_dst, astar_f_cost f_cost_cb,
BLI_AStarSolution *r_solution, const int max_steps)
{
- Heap *todo_nodes;
+ HeapSimple *todo_nodes;
BLI_bitmap *done_nodes = r_solution->done_nodes;
int *prev_nodes = r_solution->prev_nodes;
@@ -225,13 +225,14 @@ bool BLI_astar_graph_solve(
return true;
}
- todo_nodes = BLI_heap_new();
- BLI_heap_insert(todo_nodes,
- f_cost_cb(as_graph, r_solution, NULL, -1, node_index_src, node_index_dst),
- POINTER_FROM_INT(node_index_src));
+ todo_nodes = BLI_heapsimple_new();
+ BLI_heapsimple_insert(
+ todo_nodes,
+ f_cost_cb(as_graph, r_solution, NULL, -1, node_index_src, node_index_dst),
+ POINTER_FROM_INT(node_index_src));
- while (!BLI_heap_is_empty(todo_nodes)) {
- const int node_curr_idx = POINTER_AS_INT(BLI_heap_pop_min(todo_nodes));
+ while (!BLI_heapsimple_is_empty(todo_nodes)) {
+ const int node_curr_idx = POINTER_AS_INT(BLI_heapsimple_pop_min(todo_nodes));
BLI_AStarGNode *node_curr = &as_graph->nodes[node_curr_idx];
LinkData *ld;
@@ -249,7 +250,7 @@ bool BLI_astar_graph_solve(
/* Success! Path found... */
r_solution->steps = g_steps[node_curr_idx] + 1;
- BLI_heap_free(todo_nodes, NULL);
+ BLI_heapsimple_free(todo_nodes, NULL);
return true;
}
@@ -269,14 +270,15 @@ bool BLI_astar_graph_solve(
g_steps[node_next_idx] = g_steps[node_curr_idx] + 1;
/* We might have this node already in heap, but since this 'instance' will be evaluated first,
* no problem. */
- BLI_heap_insert(todo_nodes,
- f_cost_cb(as_graph, r_solution, link, node_curr_idx, node_next_idx, node_index_dst),
- POINTER_FROM_INT(node_next_idx));
+ BLI_heapsimple_insert(
+ todo_nodes,
+ f_cost_cb(as_graph, r_solution, link, node_curr_idx, node_next_idx, node_index_dst),
+ POINTER_FROM_INT(node_next_idx));
}
}
}
}
- BLI_heap_free(todo_nodes, NULL);
+ BLI_heapsimple_free(todo_nodes, NULL);
return false;
}
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index 7074a776aaf..1ba26b06c18 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -659,49 +659,6 @@ void BLI_edgehashIterator_free(EdgeHashIterator *ehi)
MEM_freeN(ehi);
}
-/* inline functions now */
-#if 0
-/**
- * Retrieve the key from an iterator.
- */
-void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, uint *r_v0, uint *r_v1)
-{
- *r_v0 = ehi->curEntry->v0;
- *r_v1 = ehi->curEntry->v1;
-}
-
-/**
- * Retrieve the value from an iterator.
- */
-void *BLI_edgehashIterator_getValue(EdgeHashIterator *ehi)
-{
- return ehi->curEntry->val;
-}
-
-/**
- * Retrieve the pointer to the value from an iterator.
- */
-void **BLI_edgehashIterator_getValue_p(EdgeHashIterator *ehi)
-{
- return &ehi->curEntry->val;
-}
-
-/**
- * Set the value for an iterator.
- */
-void BLI_edgehashIterator_setValue(EdgeHashIterator *ehi, void *val)
-{
- ehi->curEntry->val = val;
-}
-
-/**
- * Determine if an iterator is done.
- */
-bool BLI_edgehashIterator_isDone(EdgeHashIterator *ehi)
-{
- return (ehi->curEntry == NULL);
-}
-#endif
/** \} */
diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c
new file mode 100644
index 00000000000..7bcf32dd880
--- /dev/null
+++ b/source/blender/blenlib/intern/expr_pylike_eval.c
@@ -0,0 +1,1003 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation, Alexander Gavrilov
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alexander Gavrilov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/expr_pylike_eval.c
+ * \ingroup bli
+ * \author Alexander Gavrilov
+ * \since 2018
+ *
+ * Simple evaluator for a subset of Python expressions that can be
+ * computed using purely double precision floating point values.
+ *
+ * Supported subset:
+ *
+ * - Identifiers use only ASCII characters.
+ * - Literals:
+ * floating point and decimal integer.
+ * - Constants:
+ * pi, True, False
+ * - Operators:
+ * +, -, *, /, ==, !=, <, <=, >, >=, and, or, not, ternary if
+ * - Functions:
+ * min, max, radians, degrees,
+ * abs, fabs, floor, ceil, trunc, int,
+ * sin, cos, tan, asin, acos, atan, atan2,
+ * exp, log, sqrt, pow, fmod
+ *
+ * The implementation has no global state and can be used multithreaded.
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <float.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <fenv.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_expr_pylike_eval.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
+#include "BLI_alloca.h"
+
+#ifdef _MSC_VER
+#pragma fenv_access (on)
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Types
+ * \{ */
+
+typedef enum eOpCode {
+ /* Double constant: (-> dval) */
+ OPCODE_CONST,
+ /* 1 argument function call: (a -> func1(a)) */
+ OPCODE_FUNC1,
+ /* 2 argument function call: (a b -> func2(a,b)) */
+ OPCODE_FUNC2,
+ /* Parameter access: (-> params[ival]) */
+ OPCODE_PARAMETER,
+ /* Minimum of multiple inputs: (a b c... -> min); ival = arg count */
+ OPCODE_MIN,
+ /* Maximum of multiple inputs: (a b c... -> max); ival = arg count */
+ OPCODE_MAX,
+ /* Jump (pc += jmp_offset) */
+ OPCODE_JMP,
+ /* Pop and jump if zero: (a -> ); JUMP IF NOT a */
+ OPCODE_JMP_ELSE,
+ /* Jump if nonzero, or pop: (a -> a JUMP) IF a ELSE (a -> ) */
+ OPCODE_JMP_OR,
+ /* Jump if zero, or pop: (a -> a JUMP) IF NOT a ELSE (a -> ) */
+ OPCODE_JMP_AND,
+ /* For comparison chaining: (a b -> 0 JUMP) IF NOT func2(a,b) ELSE (a b -> b) */
+ OPCODE_CMP_CHAIN,
+} eOpCode;
+
+typedef double (*UnaryOpFunc)(double);
+typedef double (*BinaryOpFunc)(double, double);
+
+typedef struct ExprOp {
+ eOpCode opcode;
+
+ int jmp_offset;
+
+ union {
+ int ival;
+ double dval;
+ void *ptr;
+ UnaryOpFunc func1;
+ BinaryOpFunc func2;
+ } arg;
+} ExprOp;
+
+struct ExprPyLike_Parsed {
+ int ops_count;
+ int max_stack;
+
+ ExprOp ops[];
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+/** Free the parsed data; NULL argument is ok. */
+void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
+{
+ if (expr != NULL) {
+ MEM_freeN(expr);
+ }
+}
+
+/** Check if the parsing result is valid for evaluation. */
+bool BLI_expr_pylike_is_valid(ExprPyLike_Parsed *expr)
+{
+ return expr != NULL && expr->ops_count > 0;
+}
+
+/** Check if the parsed expression always evaluates to the same value. */
+bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr)
+{
+ return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stack Machine Evaluation
+ * \{ */
+
+/**
+ * Evaluate the expression with the given parameters.
+ * The order and number of parameters must match the names given to parse.
+ */
+eExprPyLike_EvalStatus BLI_expr_pylike_eval(
+ ExprPyLike_Parsed *expr,
+ const double *param_values, int param_values_len,
+ double *r_result)
+{
+ *r_result = 0.0;
+
+ if (!BLI_expr_pylike_is_valid(expr)) {
+ return EXPR_PYLIKE_INVALID;
+ }
+
+#define FAIL_IF(condition) if (condition) { return EXPR_PYLIKE_FATAL_ERROR; }
+
+ /* Check the stack requirement is at least remotely sane and allocate on the actual stack. */
+ FAIL_IF(expr->max_stack <= 0 || expr->max_stack > 1000);
+
+ double *stack = BLI_array_alloca(stack, expr->max_stack);
+
+ /* Evaluate expression. */
+ ExprOp *ops = expr->ops;
+ int sp = 0, pc;
+
+ feclearexcept(FE_ALL_EXCEPT);
+
+ for (pc = 0; pc >= 0 && pc < expr->ops_count; pc++) {
+ switch (ops[pc].opcode) {
+ /* Arithmetic */
+ case OPCODE_CONST:
+ FAIL_IF(sp >= expr->max_stack);
+ stack[sp++] = ops[pc].arg.dval;
+ break;
+ case OPCODE_PARAMETER:
+ FAIL_IF(sp >= expr->max_stack || ops[pc].arg.ival >= param_values_len);
+ stack[sp++] = param_values[ops[pc].arg.ival];
+ break;
+ case OPCODE_FUNC1:
+ FAIL_IF(sp < 1);
+ stack[sp - 1] = ops[pc].arg.func1(stack[sp - 1]);
+ break;
+ case OPCODE_FUNC2:
+ FAIL_IF(sp < 2);
+ stack[sp - 2] = ops[pc].arg.func2(stack[sp - 2], stack[sp - 1]);
+ sp--;
+ break;
+ case OPCODE_MIN:
+ FAIL_IF(sp < ops[pc].arg.ival);
+ for (int j = 1; j < ops[pc].arg.ival; j++, sp--) {
+ CLAMP_MAX(stack[sp - 2], stack[sp - 1]);
+ }
+ break;
+ case OPCODE_MAX:
+ FAIL_IF(sp < ops[pc].arg.ival);
+ for (int j = 1; j < ops[pc].arg.ival; j++, sp--) {
+ CLAMP_MIN(stack[sp - 2], stack[sp - 1]);
+ }
+ break;
+
+ /* Jumps */
+ case OPCODE_JMP:
+ pc += ops[pc].jmp_offset;
+ break;
+ case OPCODE_JMP_ELSE:
+ FAIL_IF(sp < 1);
+ if (!stack[--sp]) {
+ pc += ops[pc].jmp_offset;
+ }
+ break;
+ case OPCODE_JMP_OR:
+ case OPCODE_JMP_AND:
+ FAIL_IF(sp < 1);
+ if (!stack[sp - 1] == !(ops[pc].opcode == OPCODE_JMP_OR)) {
+ pc += ops[pc].jmp_offset;
+ }
+ else {
+ sp--;
+ }
+ break;
+
+ /* For chaining comparisons, i.e. "a < b < c" as "a < b and b < c" */
+ case OPCODE_CMP_CHAIN:
+ FAIL_IF(sp < 2);
+ /* If comparison fails, return 0 and jump to end. */
+ if (!ops[pc].arg.func2(stack[sp - 2], stack[sp - 1])) {
+ stack[sp - 2] = 0.0;
+ pc += ops[pc].jmp_offset;
+ }
+ /* Otherwise keep b on the stack and proceed. */
+ else {
+ stack[sp - 2] = stack[sp - 1];
+ }
+ sp--;
+ break;
+
+ default:
+ return EXPR_PYLIKE_FATAL_ERROR;
+ }
+ }
+
+ FAIL_IF(sp != 1 || pc != expr->ops_count);
+
+#undef FAIL_IF
+
+ *r_result = stack[0];
+
+ /* Detect floating point evaluation errors. */
+ int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID);
+ if (flags) {
+ return (flags & FE_INVALID) ? EXPR_PYLIKE_MATH_ERROR : EXPR_PYLIKE_DIV_BY_ZERO;
+ }
+
+ return EXPR_PYLIKE_SUCCESS;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Built-In Operations
+ * \{ */
+
+static double op_negate(double arg)
+{
+ return -arg;
+}
+
+static double op_mul(double a, double b)
+{
+ return a * b;
+}
+
+static double op_div(double a, double b)
+{
+ return a / b;
+}
+
+static double op_add(double a, double b)
+{
+ return a + b;
+}
+
+static double op_sub(double a, double b)
+{
+ return a - b;
+}
+
+static double op_radians(double arg)
+{
+ return arg * M_PI / 180.0;
+}
+
+static double op_degrees(double arg)
+{
+ return arg * 180.0 / M_PI;
+}
+
+static double op_not(double a)
+{
+ return a ? 0.0 : 1.0;
+}
+
+static double op_eq(double a, double b)
+{
+ return a == b ? 1.0 : 0.0;
+}
+
+static double op_ne(double a, double b)
+{
+ return a != b ? 1.0 : 0.0;
+}
+
+static double op_lt(double a, double b)
+{
+ return a < b ? 1.0 : 0.0;
+}
+
+static double op_le(double a, double b)
+{
+ return a <= b ? 1.0 : 0.0;
+}
+
+static double op_gt(double a, double b)
+{
+ return a > b ? 1.0 : 0.0;
+}
+
+static double op_ge(double a, double b)
+{
+ return a >= b ? 1.0 : 0.0;
+}
+
+typedef struct BuiltinConstDef {
+ const char *name;
+ double value;
+} BuiltinConstDef;
+
+static BuiltinConstDef builtin_consts[] = {
+ { "pi", M_PI },
+ { "True", 1.0 },
+ { "False", 0.0 },
+ { NULL, 0.0 }
+};
+
+typedef struct BuiltinOpDef {
+ const char *name;
+ eOpCode op;
+ void *funcptr;
+} BuiltinOpDef;
+
+static BuiltinOpDef builtin_ops[] = {
+ { "radians", OPCODE_FUNC1, op_radians },
+ { "degrees", OPCODE_FUNC1, op_degrees },
+ { "abs", OPCODE_FUNC1, abs },
+ { "fabs", OPCODE_FUNC1, abs },
+ { "floor", OPCODE_FUNC1, floor },
+ { "ceil", OPCODE_FUNC1, ceil },
+ { "trunc", OPCODE_FUNC1, trunc },
+ { "int", OPCODE_FUNC1, trunc },
+ { "sin", OPCODE_FUNC1, sin },
+ { "cos", OPCODE_FUNC1, cos },
+ { "tan", OPCODE_FUNC1, tan },
+ { "asin", OPCODE_FUNC1, asin },
+ { "acos", OPCODE_FUNC1, acos },
+ { "atan", OPCODE_FUNC1, atan },
+ { "atan2", OPCODE_FUNC2, atan2 },
+ { "exp", OPCODE_FUNC1, exp },
+ { "log", OPCODE_FUNC1, log },
+ { "sqrt", OPCODE_FUNC1, sqrt },
+ { "pow", OPCODE_FUNC2, pow },
+ { "fmod", OPCODE_FUNC2, fmod },
+ { NULL, OPCODE_CONST, NULL }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Expression Parser State
+ * \{ */
+
+#define MAKE_CHAR2(a, b) (((a) << 8) | (b))
+
+#define CHECK_ERROR(condition) if (!(condition)) { return false; }
+
+/* For simplicity simple token types are represented by their own character;
+ * these are special identifiers for multi-character tokens. */
+#define TOKEN_ID MAKE_CHAR2('I', 'D')
+#define TOKEN_NUMBER MAKE_CHAR2('0', '0')
+#define TOKEN_GE MAKE_CHAR2('>', '=')
+#define TOKEN_LE MAKE_CHAR2('<', '=')
+#define TOKEN_NE MAKE_CHAR2('!', '=')
+#define TOKEN_EQ MAKE_CHAR2('=', '=')
+#define TOKEN_AND MAKE_CHAR2('A', 'N')
+#define TOKEN_OR MAKE_CHAR2('O', 'R')
+#define TOKEN_NOT MAKE_CHAR2('N', 'O')
+#define TOKEN_IF MAKE_CHAR2('I', 'F')
+#define TOKEN_ELSE MAKE_CHAR2('E', 'L')
+
+static const char *token_eq_characters = "!=><";
+static const char *token_characters = "~`!@#$%^&*+-=/\\?:;<>(){}[]|.,\"'";
+
+typedef struct KeywordTokenDef {
+ const char *name;
+ short token;
+} KeywordTokenDef;
+
+static KeywordTokenDef keyword_list[] = {
+ { "and", TOKEN_AND },
+ { "or", TOKEN_OR },
+ { "not", TOKEN_NOT },
+ { "if", TOKEN_IF },
+ { "else", TOKEN_ELSE },
+ { NULL, TOKEN_ID }
+};
+
+typedef struct ExprParseState {
+ int param_names_len;
+ const char **param_names;
+
+ /* Original expression */
+ const char *expr;
+ const char *cur;
+
+ /* Current token */
+ short token;
+ char *tokenbuf;
+ double tokenval;
+
+ /* Opcode buffer */
+ int ops_count, max_ops, last_jmp;
+ ExprOp *ops;
+
+ /* Stack space requirement tracking */
+ int stack_ptr, max_stack;
+} ExprParseState;
+
+/* Reserve space for the specified number of operations in the buffer. */
+static ExprOp *parse_alloc_ops(ExprParseState *state, int count)
+{
+ if (state->ops_count + count > state->max_ops) {
+ state->max_ops = power_of_2_max_i(state->ops_count + count);
+ state->ops = MEM_reallocN(state->ops, state->max_ops * sizeof(ExprOp));
+ }
+
+ ExprOp *op = &state->ops[state->ops_count];
+ state->ops_count += count;
+ return op;
+}
+
+/* Add one operation and track stack usage. */
+static ExprOp *parse_add_op(ExprParseState *state, eOpCode code, int stack_delta)
+{
+ /* track evaluation stack depth */
+ state->stack_ptr += stack_delta;
+ CLAMP_MIN(state->stack_ptr, 0);
+ CLAMP_MIN(state->max_stack, state->stack_ptr);
+
+ /* allocate the new instruction */
+ ExprOp *op = parse_alloc_ops(state, 1);
+ memset(op, 0, sizeof(ExprOp));
+ op->opcode = code;
+ return op;
+}
+
+/* Add one jump operation and return an index for parse_set_jump. */
+static int parse_add_jump(ExprParseState *state, eOpCode code)
+{
+ parse_add_op(state, code, -1);
+ return state->last_jmp = state->ops_count;
+}
+
+/* Set the jump offset in a previously added jump operation. */
+static void parse_set_jump(ExprParseState *state, int jump)
+{
+ state->last_jmp = state->ops_count;
+ state->ops[jump - 1].jmp_offset = state->ops_count - jump;
+}
+
+/* Add a function call operation, applying constant folding when possible. */
+static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *funcptr)
+{
+ ExprOp *prev_ops = &state->ops[state->ops_count];
+ int jmp_gap = state->ops_count - state->last_jmp;
+
+ feclearexcept(FE_ALL_EXCEPT);
+
+ switch (code) {
+ case OPCODE_FUNC1:
+ CHECK_ERROR(args == 1);
+
+ if (jmp_gap >= 1 && prev_ops[-1].opcode == OPCODE_CONST) {
+ UnaryOpFunc func = funcptr;
+
+ double result = func(prev_ops[-1].arg.dval);
+
+ if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
+ prev_ops[-1].arg.dval = result;
+ return true;
+ }
+ }
+ break;
+
+ case OPCODE_FUNC2:
+ CHECK_ERROR(args == 2);
+
+ if (jmp_gap >= 2 && prev_ops[-2].opcode == OPCODE_CONST && prev_ops[-1].opcode == OPCODE_CONST) {
+ BinaryOpFunc func = funcptr;
+
+ double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval);
+
+ if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
+ prev_ops[-2].arg.dval = result;
+ state->ops_count--;
+ state->stack_ptr--;
+ return true;
+ }
+ }
+ break;
+
+ default:
+ BLI_assert(false);
+ return false;
+ }
+
+ parse_add_op(state, code, 1 - args)->arg.ptr = funcptr;
+ return true;
+}
+
+/* Extract the next token from raw characters. */
+static bool parse_next_token(ExprParseState *state)
+{
+ /* Skip whitespace. */
+ while (isspace(*state->cur)) {
+ state->cur++;
+ }
+
+ /* End of string. */
+ if (*state->cur == 0) {
+ state->token = 0;
+ return true;
+ }
+
+ /* Floating point numbers. */
+ if (isdigit(*state->cur) || (state->cur[0] == '.' && isdigit(state->cur[1]))) {
+ char *end, *out = state->tokenbuf;
+ bool is_float = false;
+
+ while (isdigit(*state->cur))
+ *out++ = *state->cur++;
+
+ if (*state->cur == '.') {
+ is_float = true;
+ *out++ = *state->cur++;
+
+ while (isdigit(*state->cur))
+ *out++ = *state->cur++;
+ }
+
+ if (ELEM(*state->cur, 'e', 'E')) {
+ is_float = true;
+ *out++ = *state->cur++;
+
+ if (ELEM(*state->cur, '+', '-'))
+ *out++ = *state->cur++;
+
+ CHECK_ERROR(isdigit(*state->cur));
+
+ while (isdigit(*state->cur))
+ *out++ = *state->cur++;
+ }
+
+ *out = 0;
+
+ /* Forbid C-style octal constants. */
+ if (!is_float && state->tokenbuf[0] == '0') {
+ for (char *p = state->tokenbuf + 1; *p; p++) {
+ if (*p != '0') {
+ return false;
+ }
+ }
+ }
+
+ state->token = TOKEN_NUMBER;
+ state->tokenval = strtod(state->tokenbuf, &end);
+ return (end == out);
+ }
+
+ /* ?= tokens */
+ if (state->cur[1] == '=' && strchr(token_eq_characters, state->cur[0])) {
+ state->token = MAKE_CHAR2(state->cur[0], state->cur[1]);
+ state->cur += 2;
+ return true;
+ }
+
+ /* Special characters (single character tokens) */
+ if (strchr(token_characters, *state->cur)) {
+ state->token = *state->cur++;
+ return true;
+ }
+
+ /* Identifiers */
+ if (isalpha(*state->cur) || ELEM(*state->cur, '_')) {
+ char *out = state->tokenbuf;
+
+ while (isalnum(*state->cur) || ELEM(*state->cur, '_'))
+ *out++ = *state->cur++;
+
+ *out = 0;
+
+ for (int i = 0; keyword_list[i].name; i++) {
+ if (STREQ(state->tokenbuf, keyword_list[i].name)) {
+ state->token = keyword_list[i].token;
+ return true;
+ }
+ }
+
+ state->token = TOKEN_ID;
+ return true;
+ }
+
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recursive Descent Parser
+ * \{ */
+
+static bool parse_expr(ExprParseState *state);
+
+static int parse_function_args(ExprParseState *state)
+{
+ if (!parse_next_token(state) || state->token != '(' || !parse_next_token(state)) {
+ return -1;
+ }
+
+ int arg_count = 0;
+
+ for (;;) {
+ if (!parse_expr(state)) {
+ return -1;
+ }
+
+ arg_count++;
+
+ switch (state->token) {
+ case ',':
+ if (!parse_next_token(state)) {
+ return -1;
+ }
+ break;
+
+ case ')':
+ if (!parse_next_token(state)) {
+ return -1;
+ }
+ return arg_count;
+
+ default:
+ return -1;
+ }
+ }
+}
+
+static bool parse_unary(ExprParseState *state)
+{
+ int i;
+
+ switch (state->token) {
+ case '+':
+ return parse_next_token(state) && parse_unary(state);
+
+ case '-':
+ CHECK_ERROR(parse_next_token(state) && parse_unary(state));
+ parse_add_func(state, OPCODE_FUNC1, 1, op_negate);
+ return true;
+
+ case '(':
+ return parse_next_token(state) &&
+ parse_expr(state) &&
+ state->token == ')' &&
+ parse_next_token(state);
+
+ case TOKEN_NUMBER:
+ parse_add_op(state, OPCODE_CONST, 1)->arg.dval = state->tokenval;
+ return parse_next_token(state);
+
+ case TOKEN_ID:
+ /* Parameters: search in reverse order in case of duplicate names - the last one should win. */
+ for (i = state->param_names_len - 1; i >= 0; i--) {
+ if (STREQ(state->tokenbuf, state->param_names[i])) {
+ parse_add_op(state, OPCODE_PARAMETER, 1)->arg.ival = i;
+ return parse_next_token(state);
+ }
+ }
+
+ /* Ordinary builtin constants. */
+ for (i = 0; builtin_consts[i].name; i++) {
+ if (STREQ(state->tokenbuf, builtin_consts[i].name)) {
+ parse_add_op(state, OPCODE_CONST, 1)->arg.dval = builtin_consts[i].value;
+ return parse_next_token(state);
+ }
+ }
+
+ /* Ordinary builtin functions. */
+ for (i = 0; builtin_ops[i].name; i++) {
+ if (STREQ(state->tokenbuf, builtin_ops[i].name)) {
+ int args = parse_function_args(state);
+
+ return parse_add_func(state, builtin_ops[i].op, args, builtin_ops[i].funcptr);
+ }
+ }
+
+ /* Specially supported functions. */
+ if (STREQ(state->tokenbuf, "min")) {
+ int cnt = parse_function_args(state);
+ CHECK_ERROR(cnt > 0);
+
+ parse_add_op(state, OPCODE_MIN, 1 - cnt)->arg.ival = cnt;
+ return true;
+ }
+
+ if (STREQ(state->tokenbuf, "max")) {
+ int cnt = parse_function_args(state);
+ CHECK_ERROR(cnt > 0);
+
+ parse_add_op(state, OPCODE_MAX, 1 - cnt)->arg.ival = cnt;
+ return true;
+ }
+
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+static bool parse_mul(ExprParseState *state)
+{
+ CHECK_ERROR(parse_unary(state));
+
+ for (;;) {
+ switch (state->token) {
+ case '*':
+ CHECK_ERROR(parse_next_token(state) && parse_unary(state));
+ parse_add_func(state, OPCODE_FUNC2, 2, op_mul);
+ break;
+
+ case '/':
+ CHECK_ERROR(parse_next_token(state) && parse_unary(state));
+ parse_add_func(state, OPCODE_FUNC2, 2, op_div);
+ break;
+
+ default:
+ return true;
+ }
+ }
+}
+
+static bool parse_add(ExprParseState *state)
+{
+ CHECK_ERROR(parse_mul(state));
+
+ for (;;) {
+ switch (state->token) {
+ case '+':
+ CHECK_ERROR(parse_next_token(state) && parse_mul(state));
+ parse_add_func(state, OPCODE_FUNC2, 2, op_add);
+ break;
+
+ case '-':
+ CHECK_ERROR(parse_next_token(state) && parse_mul(state));
+ parse_add_func(state, OPCODE_FUNC2, 2, op_sub);
+ break;
+
+ default:
+ return true;
+ }
+ }
+}
+
+static BinaryOpFunc parse_get_cmp_func(short token)
+{
+ switch (token) {
+ case TOKEN_EQ:
+ return op_eq;
+ case TOKEN_NE:
+ return op_ne;
+ case '>':
+ return op_gt;
+ case TOKEN_GE:
+ return op_ge;
+ case '<':
+ return op_lt;
+ case TOKEN_LE:
+ return op_le;
+ default:
+ return NULL;
+ }
+}
+
+static bool parse_cmp_chain(ExprParseState *state, BinaryOpFunc cur_func)
+{
+ BinaryOpFunc next_func = parse_get_cmp_func(state->token);
+
+ if (next_func) {
+ parse_add_op(state, OPCODE_CMP_CHAIN, -1)->arg.func2 = cur_func;
+ int jump = state->last_jmp = state->ops_count;
+
+ CHECK_ERROR(parse_next_token(state) && parse_add(state));
+ CHECK_ERROR(parse_cmp_chain(state, next_func));
+
+ parse_set_jump(state, jump);
+ }
+ else {
+ parse_add_func(state, OPCODE_FUNC2, 2, cur_func);
+ }
+
+ return true;
+}
+
+static bool parse_cmp(ExprParseState *state)
+{
+ CHECK_ERROR(parse_add(state));
+
+ BinaryOpFunc func = parse_get_cmp_func(state->token);
+
+ if (func) {
+ CHECK_ERROR(parse_next_token(state) && parse_add(state));
+
+ return parse_cmp_chain(state, func);
+ }
+
+ return true;
+}
+
+static bool parse_not(ExprParseState *state)
+{
+ if (state->token == TOKEN_NOT) {
+ CHECK_ERROR(parse_next_token(state) && parse_not(state));
+ parse_add_func(state, OPCODE_FUNC1, 1, op_not);
+ return true;
+ }
+
+ return parse_cmp(state);
+}
+
+static bool parse_and(ExprParseState *state)
+{
+ CHECK_ERROR(parse_not(state));
+
+ if (state->token == TOKEN_AND) {
+ int jump = parse_add_jump(state, OPCODE_JMP_AND);
+
+ CHECK_ERROR(parse_next_token(state) && parse_and(state));
+
+ parse_set_jump(state, jump);
+ }
+
+ return true;
+}
+
+static bool parse_or(ExprParseState *state)
+{
+ CHECK_ERROR(parse_and(state));
+
+ if (state->token == TOKEN_OR) {
+ int jump = parse_add_jump(state, OPCODE_JMP_OR);
+
+ CHECK_ERROR(parse_next_token(state) && parse_or(state));
+
+ parse_set_jump(state, jump);
+ }
+
+ return true;
+}
+
+static bool parse_expr(ExprParseState *state)
+{
+ /* Temporarily set the constant expression evaluation barrier */
+ int prev_last_jmp = state->last_jmp;
+ int start = state->last_jmp = state->ops_count;
+
+ CHECK_ERROR(parse_or(state));
+
+ if (state->token == TOKEN_IF) {
+ /* Ternary IF expression in python requires swapping the
+ * main body with condition, so stash the body opcodes. */
+ int size = state->ops_count - start;
+ int bytes = size * sizeof(ExprOp);
+
+ ExprOp *body = MEM_mallocN(bytes, "driver if body");
+ memcpy(body, state->ops + start, bytes);
+
+ state->last_jmp = state->ops_count = start;
+ state->stack_ptr--;
+
+ /* Parse condition. */
+ if (!parse_next_token(state) || !parse_or(state) ||
+ state->token != TOKEN_ELSE || !parse_next_token(state))
+ {
+ MEM_freeN(body);
+ return false;
+ }
+
+ int jmp_else = parse_add_jump(state, OPCODE_JMP_ELSE);
+
+ /* Add body back. */
+ memcpy(parse_alloc_ops(state, size), body, bytes);
+ MEM_freeN(body);
+
+ state->stack_ptr++;
+
+ int jmp_end = parse_add_jump(state, OPCODE_JMP);
+
+ /* Parse the else block. */
+ parse_set_jump(state, jmp_else);
+
+ CHECK_ERROR(parse_expr(state));
+
+ parse_set_jump(state, jmp_end);
+ }
+ /* If no actual jumps happened, restore previous barrier */
+ else if (state->last_jmp == start) {
+ state->last_jmp = prev_last_jmp;
+ }
+
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Parsing Function
+ * \{ */
+
+/**
+ * Compile the expression and return the result.
+ *
+ * Parse the expression for evaluation later.
+ * Returns non-NULL even on failure; use is_valid to check.
+ */
+ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression, const char **param_names, int param_names_len)
+{
+ /* Prepare the parser state. */
+ ExprParseState state;
+ memset(&state, 0, sizeof(state));
+
+ state.cur = state.expr = expression;
+
+ state.param_names_len = param_names_len;
+ state.param_names = param_names;
+
+ state.tokenbuf = MEM_mallocN(strlen(expression) + 1, __func__);
+
+ state.max_ops = 16;
+ state.ops = MEM_mallocN(state.max_ops * sizeof(ExprOp), __func__);
+
+ /* Parse the expression. */
+ ExprPyLike_Parsed *expr;
+
+ if (parse_next_token(&state) && parse_expr(&state) && state.token == 0) {
+ BLI_assert(state.stack_ptr == 1);
+
+ int bytesize = sizeof(ExprPyLike_Parsed) + state.ops_count * sizeof(ExprOp);
+
+ expr = MEM_mallocN(bytesize, "ExprPyLike_Parsed");
+ expr->ops_count = state.ops_count;
+ expr->max_stack = state.max_stack;
+
+ memcpy(expr->ops, state.ops, state.ops_count * sizeof(ExprOp));
+ }
+ else {
+ /* Always return a non-NULL object so that parse failure can be cached. */
+ expr = MEM_callocN(sizeof(ExprPyLike_Parsed), "ExprPyLike_Parsed(empty)");
+ }
+
+ MEM_freeN(state.tokenbuf);
+ MEM_freeN(state.ops);
+ return expr;
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
index b493b97863c..0bed7d42e9f 100644
--- a/source/blender/blenlib/intern/freetypefont.c
+++ b/source/blender/blenlib/intern/freetypefont.c
@@ -291,14 +291,6 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile *pf)
const char *fontname;
VFontData *vfd;
-#if 0
- FT_CharMap found = 0;
- FT_CharMap charmap;
- FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
- FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
- int n;
-#endif
-
/* load the freetype font */
err = FT_New_Memory_Face(library,
pf->data,
@@ -308,25 +300,6 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile *pf)
if (err) return NULL;
-#if 0
- for (n = 0; n < face->num_charmaps; n++)
- {
- charmap = face->charmaps[n];
- if (charmap->platform_id == my_platform_id &&
- charmap->encoding_id == my_encoding_id)
- {
- found = charmap;
- break;
- }
- }
-
- if (!found) { return NULL; }
-
- /* now, select the charmap for the face object */
- err = FT_Set_Charmap(face, found);
- if (err) { return NULL; }
-#endif
-
/* allocate blender font */
vfd = MEM_callocN(sizeof(*vfd), "FTVFontData");
@@ -359,10 +332,27 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile *pf)
lcode = charcode = FT_Get_First_Char(face, &glyph_index);
}
+ /* Blender default BFont is not "complete". */
+ const bool complete_font = (face->ascender != 0) && (face->descender != 0) &&
+ (face->ascender != face->descender);
+
+ if (complete_font) {
+ /* We can get descender as well, but we simple store descender in relation to the ascender.
+ * Also note that descender is stored as a negative number. */
+ vfd->ascender = (float)face->ascender / (face->ascender - face->descender);
+ }
+ else {
+ vfd->ascender = 0.8f;
+ vfd->em_height = 1.0f;
+ }
/* Adjust font size */
if (face->bbox.yMax != face->bbox.yMin) {
vfd->scale = (float)(1.0 / (double)(face->bbox.yMax - face->bbox.yMin));
+
+ if (complete_font) {
+ vfd->em_height = (float)(face->ascender - face->descender) / (face->bbox.yMax - face->bbox.yMin);
+ }
}
else {
vfd->scale = 1.0f / 1000.0f;
@@ -393,13 +383,6 @@ static int check_freetypefont(PackedFile *pf)
FT_Face face;
FT_GlyphSlot glyph;
FT_UInt glyph_index;
-#if 0
- FT_CharMap charmap;
- FT_CharMap found;
- FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
- FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
- int n;
-#endif
int success = 0;
err = FT_New_Memory_Face(library,
@@ -412,23 +395,6 @@ static int check_freetypefont(PackedFile *pf)
//XXX error("This is not a valid font");
}
else {
-
-#if 0
- for (n = 0; n < face->num_charmaps; n++) {
- charmap = face->charmaps[n];
- if (charmap->platform_id == my_platform_id && charmap->encoding_id == my_encoding_id) {
- found = charmap;
- break;
- }
- }
-
- if (!found) { return 0; }
-
- /* now, select the charmap for the face object */
- err = FT_Set_Charmap(face, found);
- if (err) { return 0; }
-#endif
-
glyph_index = FT_Get_Char_Index(face, 'A');
err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
if (err) {
@@ -533,22 +499,6 @@ VChar *BLI_vfontchar_copy(const VChar *vchar_src, const int UNUSED(flag))
return vchar_dst;
}
-#if 0
-
-/* Freetype2 Outline struct */
-
-typedef struct FT_Outline_ {
- short n_contours; /* number of contours in glyph */
- short n_points; /* number of points in the glyph */
-
- FT_Vector *points; /* the outline's points */
- char *tags; /* the points flags */
- short *contours; /* the contour end points */
-
- int flags; /* outline masks */
-} FT_Outline;
-
-#endif
/*
* from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
diff --git a/source/blender/blenlib/intern/graph.c b/source/blender/blenlib/intern/graph.c
deleted file mode 100644
index e346b8ec003..00000000000
--- a/source/blender/blenlib/intern/graph.c
+++ /dev/null
@@ -1,1016 +0,0 @@
-/*
- * ***** 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): Martin Poirier
- *
- * ***** END GPL LICENSE BLOCK *****
- * graph.c: Common graph interface and methods
- */
-
-/** \file blender/blenlib/intern/graph.c
- * \ingroup bli
- */
-
-#include <float.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
-#include "BLI_graph.h"
-#include "BLI_math.h"
-
-
-static void testRadialSymmetry(BGraph *graph, BNode *root_node, RadialArc *ring, int total, float axis[3], float limit, int group);
-
-static void handleAxialSymmetry(BGraph *graph, BNode *root_node, int depth, float axis[3], float limit);
-static void testAxialSymmetry(BGraph *graph, BNode *root_node, BNode *node1, BNode *node2, BArc *arc1, BArc *arc2, float axis[3], float limit, int group);
-static void flagAxialSymmetry(BNode *root_node, BNode *end_node, BArc *arc, int group);
-
-void BLI_freeNode(BGraph *graph, BNode *node)
-{
- if (node->arcs) {
- MEM_freeN(node->arcs);
- }
-
- if (graph->free_node) {
- graph->free_node(node);
- }
-}
-
-void BLI_removeNode(BGraph *graph, BNode *node)
-{
- BLI_freeNode(graph, node);
- BLI_freelinkN(&graph->nodes, node);
-}
-
-BNode *BLI_otherNode(BArc *arc, BNode *node)
-{
- return (arc->head == node) ? arc->tail : arc->head;
-}
-
-void BLI_removeArc(BGraph *graph, BArc *arc)
-{
- if (graph->free_arc) {
- graph->free_arc(arc);
- }
-
- BLI_freelinkN(&graph->arcs, arc);
-}
-
-void BLI_flagNodes(BGraph *graph, int flag)
-{
- BNode *node;
-
- for (node = graph->nodes.first; node; node = node->next) {
- node->flag = flag;
- }
-}
-
-void BLI_flagArcs(BGraph *graph, int flag)
-{
- BArc *arc;
-
- for (arc = graph->arcs.first; arc; arc = arc->next) {
- arc->flag = flag;
- }
-}
-
-static void addArcToNodeAdjacencyList(BNode *node, BArc *arc)
-{
- node->arcs[node->flag] = arc;
- node->flag++;
-}
-
-void BLI_buildAdjacencyList(BGraph *graph)
-{
- BNode *node;
- BArc *arc;
-
- for (node = graph->nodes.first; node; node = node->next) {
- if (node->arcs != NULL) {
- MEM_freeN(node->arcs);
- }
-
- node->arcs = MEM_callocN((node->degree) * sizeof(BArc *), "adjacency list");
-
- /* temporary use to indicate the first index available in the lists */
- node->flag = 0;
- }
-
- for (arc = graph->arcs.first; arc; arc = arc->next) {
- addArcToNodeAdjacencyList(arc->head, arc);
- addArcToNodeAdjacencyList(arc->tail, arc);
- }
-
- for (node = graph->nodes.first; node; node = node->next) {
- if (node->degree != node->flag) {
- printf("error in node [%p]. Added only %i arcs out of %i\n", (void *)node, node->flag, node->degree);
- }
- }
-}
-
-void BLI_rebuildAdjacencyListForNode(BGraph *graph, BNode *node)
-{
- BArc *arc;
-
- if (node->arcs != NULL) {
- MEM_freeN(node->arcs);
- }
-
- node->arcs = MEM_callocN((node->degree) * sizeof(BArc *), "adjacency list");
-
- /* temporary use to indicate the first index available in the lists */
- node->flag = 0;
-
- for (arc = graph->arcs.first; arc; arc = arc->next) {
- if (arc->head == node) {
- addArcToNodeAdjacencyList(arc->head, arc);
- }
- else if (arc->tail == node) {
- addArcToNodeAdjacencyList(arc->tail, arc);
- }
- }
-
- if (node->degree != node->flag) {
- printf("error in node [%p]. Added only %i arcs out of %i\n", (void *)node, node->flag, node->degree);
- }
-}
-
-void BLI_freeAdjacencyList(BGraph *graph)
-{
- BNode *node;
-
- for (node = graph->nodes.first; node; node = node->next) {
- if (node->arcs != NULL) {
- MEM_freeN(node->arcs);
- node->arcs = NULL;
- }
- }
-}
-
-bool BLI_hasAdjacencyList(BGraph *graph)
-{
- BNode *node;
-
- for (node = graph->nodes.first; node; node = node->next) {
- if (node->arcs == NULL) {
- return false;
- }
- }
-
- return true;
-}
-
-void BLI_replaceNodeInArc(BGraph *graph, BArc *arc, BNode *node_src, BNode *node_replaced)
-{
- if (arc->head == node_replaced) {
- arc->head = node_src;
- node_src->degree++;
- }
-
- if (arc->tail == node_replaced) {
- arc->tail = node_src;
- node_src->degree++;
- }
-
- if (arc->head == arc->tail) {
- node_src->degree -= 2;
-
- graph->free_arc(arc);
- BLI_freelinkN(&graph->arcs, arc);
- }
-
- if (node_replaced->degree == 0) {
- BLI_removeNode(graph, node_replaced);
- }
-}
-
-void BLI_replaceNode(BGraph *graph, BNode *node_src, BNode *node_replaced)
-{
- BArc *arc, *next_arc;
-
- for (arc = graph->arcs.first; arc; arc = next_arc) {
- next_arc = arc->next;
-
- if (arc->head == node_replaced) {
- arc->head = node_src;
- node_replaced->degree--;
- node_src->degree++;
- }
-
- if (arc->tail == node_replaced) {
- arc->tail = node_src;
- node_replaced->degree--;
- node_src->degree++;
- }
-
- if (arc->head == arc->tail) {
- node_src->degree -= 2;
-
- graph->free_arc(arc);
- BLI_freelinkN(&graph->arcs, arc);
- }
- }
-
- if (node_replaced->degree == 0) {
- BLI_removeNode(graph, node_replaced);
- }
-}
-
-void BLI_removeDoubleNodes(BGraph *graph, float limit)
-{
- const float limit_sq = limit * limit;
- BNode *node_src, *node_replaced;
-
- for (node_src = graph->nodes.first; node_src; node_src = node_src->next) {
- for (node_replaced = graph->nodes.first; node_replaced; node_replaced = node_replaced->next) {
- if (node_replaced != node_src && len_squared_v3v3(node_replaced->p, node_src->p) <= limit_sq) {
- BLI_replaceNode(graph, node_src, node_replaced);
- }
- }
- }
-
-}
-
-BNode *BLI_FindNodeByPosition(BGraph *graph, const float p[3], const float limit)
-{
- const float limit_sq = limit * limit;
- BNode *closest_node = NULL, *node;
- float min_distance = 0.0f;
-
- for (node = graph->nodes.first; node; node = node->next) {
- float distance = len_squared_v3v3(p, node->p);
- if (distance <= limit_sq && (closest_node == NULL || distance < min_distance)) {
- closest_node = node;
- min_distance = distance;
- }
- }
-
- return closest_node;
-}
-/************************************* SUBGRAPH DETECTION **********************************************/
-
-static void flagSubgraph(BNode *node, int subgraph)
-{
- if (node->subgraph_index == 0) {
- BArc *arc;
- int i;
-
- node->subgraph_index = subgraph;
-
- for (i = 0; i < node->degree; i++) {
- arc = node->arcs[i];
- flagSubgraph(BLI_otherNode(arc, node), subgraph);
- }
- }
-}
-
-int BLI_FlagSubgraphs(BGraph *graph)
-{
- BNode *node;
- int subgraph = 0;
-
- if (BLI_hasAdjacencyList(graph) == 0) {
- BLI_buildAdjacencyList(graph);
- }
-
- for (node = graph->nodes.first; node; node = node->next) {
- node->subgraph_index = 0;
- }
-
- for (node = graph->nodes.first; node; node = node->next) {
- if (node->subgraph_index == 0) {
- subgraph++;
- flagSubgraph(node, subgraph);
- }
- }
-
- return subgraph;
-}
-
-void BLI_ReflagSubgraph(BGraph *graph, int old_subgraph, int new_subgraph)
-{
- BNode *node;
-
- for (node = graph->nodes.first; node; node = node->next) {
- if (node->flag == old_subgraph) {
- node->flag = new_subgraph;
- }
- }
-}
-
-/*************************************** CYCLE DETECTION ***********************************************/
-
-static bool detectCycle(BNode *node, BArc *src_arc)
-{
- bool value = false;
-
- if (node->flag == 0) {
- int i;
-
- /* mark node as visited */
- node->flag = 1;
-
- for (i = 0; i < node->degree && value == 0; i++) {
- BArc *arc = node->arcs[i];
-
- /* don't go back on the source arc */
- if (arc != src_arc) {
- value = detectCycle(BLI_otherNode(arc, node), arc);
- }
- }
- }
- else {
- value = true;
- }
-
- return value;
-}
-
-bool BLI_isGraphCyclic(BGraph *graph)
-{
- BNode *node;
- bool value = false;
-
- /* NEED TO CHECK IF ADJACENCY LIST EXIST */
-
- /* Mark all nodes as not visited */
- BLI_flagNodes(graph, 0);
-
- /* detectCycles in subgraphs */
- for (node = graph->nodes.first; node && value == false; node = node->next) {
- /* only for nodes in subgraphs that haven't been visited yet */
- if (node->flag == 0) {
- value = value || detectCycle(node, NULL);
- }
- }
-
- return value;
-}
-
-BArc *BLI_findConnectedArc(BGraph *graph, BArc *arc, BNode *v)
-{
- BArc *nextArc;
-
- for (nextArc = graph->arcs.first; nextArc; nextArc = nextArc->next) {
- if (arc != nextArc && (nextArc->head == v || nextArc->tail == v)) {
- break;
- }
- }
-
- return nextArc;
-}
-
-/*********************************** GRAPH AS TREE FUNCTIONS *******************************************/
-
-static int subtreeShape(BNode *node, BArc *rootArc, int include_root)
-{
- int depth = 0;
-
- node->flag = 1;
-
- if (include_root) {
- BNode *newNode = BLI_otherNode(rootArc, node);
- return subtreeShape(newNode, rootArc, 0);
- }
- else {
- /* Base case, no arcs leading away */
- if (node->arcs == NULL || *(node->arcs) == NULL) {
- return 0;
- }
- else {
- int i;
-
- for (i = 0; i < node->degree; i++) {
- BArc *arc = node->arcs[i];
- BNode *newNode = BLI_otherNode(arc, node);
-
- /* stop immediate and cyclic backtracking */
- if (arc != rootArc && newNode->flag == 0) {
- depth += subtreeShape(newNode, arc, 0);
- }
- }
- }
-
- return SHAPE_RADIX * depth + 1;
- }
-}
-
-int BLI_subtreeShape(BGraph *graph, BNode *node, BArc *rootArc, int include_root)
-{
- BLI_flagNodes(graph, 0);
- return subtreeShape(node, rootArc, include_root);
-}
-
-float BLI_subtreeLength(BNode *node)
-{
- float length = 0;
- int i;
-
- node->flag = 0; /* flag node as visited */
-
- for (i = 0; i < node->degree; i++) {
- BArc *arc = node->arcs[i];
- BNode *other_node = BLI_otherNode(arc, node);
-
- if (other_node->flag != 0) {
- float subgraph_length = arc->length + BLI_subtreeLength(other_node);
- length = MAX2(length, subgraph_length);
- }
- }
-
- return length;
-}
-
-void BLI_calcGraphLength(BGraph *graph)
-{
- float length = 0;
- int nb_subgraphs;
- int i;
-
- nb_subgraphs = BLI_FlagSubgraphs(graph);
-
- for (i = 1; i <= nb_subgraphs; i++) {
- BNode *node;
-
- for (node = graph->nodes.first; node; node = node->next) {
- /* start on an external node of the subgraph */
- if (node->subgraph_index == i && node->degree == 1) {
- float subgraph_length = BLI_subtreeLength(node);
- length = MAX2(length, subgraph_length);
- break;
- }
- }
- }
-
- graph->length = length;
-}
-
-/********************************* SYMMETRY DETECTION **************************************************/
-
-static void markdownSymmetryArc(BGraph *graph, BArc *arc, BNode *node, int level, float limit);
-
-void BLI_mirrorAlongAxis(float v[3], float center[3], float axis[3])
-{
- float dv[3], pv[3];
-
- sub_v3_v3v3(dv, v, center);
- project_v3_v3v3(pv, dv, axis);
- mul_v3_fl(pv, -2);
- add_v3_v3(v, pv);
-}
-
-static void testRadialSymmetry(BGraph *graph, BNode *root_node, RadialArc *ring, int total, float axis[3], float limit, int group)
-{
- const float limit_sq = limit * limit;
- int symmetric = 1;
- int i;
-
- /* sort ring by angle */
- for (i = 0; i < total - 1; i++) {
- float minAngle = FLT_MAX;
- int minIndex = -1;
- int j;
-
- for (j = i + 1; j < total; j++) {
- float angle = dot_v3v3(ring[i].n, ring[j].n);
-
- /* map negative values to 1..2 */
- if (angle < 0) {
- angle = 1 - angle;
- }
-
- if (angle < minAngle) {
- minIndex = j;
- minAngle = angle;
- }
- }
-
- /* swap if needed */
- if (minIndex != i + 1) {
- RadialArc tmp;
- tmp = ring[i + 1];
- ring[i + 1] = ring[minIndex];
- ring[minIndex] = tmp;
- }
- }
-
- for (i = 0; i < total && symmetric; i++) {
- BNode *node1, *node2;
- float tangent[3];
- float normal[3];
- float p[3];
- int j = (i + 1) % total; /* next arc in the circular list */
-
- add_v3_v3v3(tangent, ring[i].n, ring[j].n);
- cross_v3_v3v3(normal, tangent, axis);
-
- node1 = BLI_otherNode(ring[i].arc, root_node);
- node2 = BLI_otherNode(ring[j].arc, root_node);
-
- copy_v3_v3(p, node2->p);
- BLI_mirrorAlongAxis(p, root_node->p, normal);
-
- /* check if it's within limit before continuing */
- if (len_squared_v3v3(node1->p, p) > limit_sq) {
- symmetric = 0;
- }
-
- }
-
- if (symmetric) {
- /* mark node as symmetric physically */
- copy_v3_v3(root_node->symmetry_axis, axis);
- root_node->symmetry_flag |= SYM_PHYSICAL;
- root_node->symmetry_flag |= SYM_RADIAL;
-
- /* FLAG SYMMETRY GROUP */
- for (i = 0; i < total; i++) {
- ring[i].arc->symmetry_group = group;
- ring[i].arc->symmetry_flag = SYM_SIDE_RADIAL + i;
- }
-
- if (graph->radial_symmetry) {
- graph->radial_symmetry(root_node, ring, total);
- }
- }
-}
-
-static void handleRadialSymmetry(BGraph *graph, BNode *root_node, int depth, float axis[3], float limit)
-{
- RadialArc *ring = NULL;
- RadialArc *unit;
- int total = 0;
- int group;
- int first;
- int i;
-
- /* mark topological symmetry */
- root_node->symmetry_flag |= SYM_TOPOLOGICAL;
-
- /* total the number of arcs in the symmetry ring */
- for (i = 0; i < root_node->degree; i++) {
- BArc *connectedArc = root_node->arcs[i];
-
- /* depth is store as a negative in flag. symmetry level is positive */
- if (connectedArc->symmetry_level == -depth) {
- total++;
- }
- }
-
- ring = MEM_callocN(sizeof(RadialArc) * total, "radial symmetry ring");
- unit = ring;
-
- /* fill in the ring */
- for (i = 0; i < root_node->degree; i++) {
- BArc *connectedArc = root_node->arcs[i];
-
- /* depth is store as a negative in flag. symmetry level is positive */
- if (connectedArc->symmetry_level == -depth) {
- BNode *otherNode = BLI_otherNode(connectedArc, root_node);
- float vec[3];
-
- unit->arc = connectedArc;
-
- /* project the node to node vector on the symmetry plane */
- sub_v3_v3v3(unit->n, otherNode->p, root_node->p);
- project_v3_v3v3(vec, unit->n, axis);
- sub_v3_v3v3(unit->n, unit->n, vec);
-
- normalize_v3(unit->n);
-
- unit++;
- }
- }
-
- /* sort ring by arc length
- * using a rather bogus insertion sort
- * but rings will never get too big to matter
- * */
- for (i = 0; i < total; i++) {
- int j;
-
- for (j = i - 1; j >= 0; j--) {
- BArc *arc1, *arc2;
-
- arc1 = ring[j].arc;
- arc2 = ring[j + 1].arc;
-
- if (arc1->length > arc2->length) {
- /* swap with smaller */
- RadialArc tmp;
-
- tmp = ring[j + 1];
- ring[j + 1] = ring[j];
- ring[j] = tmp;
- }
- else {
- break;
- }
- }
- }
-
- /* Dispatch to specific symmetry tests */
- first = 0;
- group = 0;
-
- for (i = 1; i < total; i++) {
- int dispatch = 0;
- int last = i - 1;
-
- if (fabsf(ring[first].arc->length - ring[i].arc->length) > limit) {
- dispatch = 1;
- }
-
- /* if not dispatching already and on last arc
- * Dispatch using current arc as last
- */
- if (dispatch == 0 && i == total - 1) {
- last = i;
- dispatch = 1;
- }
-
- if (dispatch) {
- int sub_total = last - first + 1;
-
- group += 1;
-
- if (sub_total == 1) {
- group -= 1; /* not really a group so decrement */
- /* NOTHING TO DO */
- }
- else if (sub_total == 2) {
- BArc *arc1, *arc2;
- BNode *node1, *node2;
-
- arc1 = ring[first].arc;
- arc2 = ring[last].arc;
-
- node1 = BLI_otherNode(arc1, root_node);
- node2 = BLI_otherNode(arc2, root_node);
-
- testAxialSymmetry(graph, root_node, node1, node2, arc1, arc2, axis, limit, group);
- }
- else if (sub_total != total) /* allocate a new sub ring if needed */ {
- RadialArc *sub_ring = MEM_callocN(sizeof(RadialArc) * sub_total, "radial symmetry ring");
- int sub_i;
-
- /* fill in the sub ring */
- for (sub_i = 0; sub_i < sub_total; sub_i++) {
- sub_ring[sub_i] = ring[first + sub_i];
- }
-
- testRadialSymmetry(graph, root_node, sub_ring, sub_total, axis, limit, group);
-
- MEM_freeN(sub_ring);
- }
- else if (sub_total == total) {
- testRadialSymmetry(graph, root_node, ring, total, axis, limit, group);
- }
-
- first = i;
- }
- }
-
-
- MEM_freeN(ring);
-}
-
-static void flagAxialSymmetry(BNode *root_node, BNode *end_node, BArc *arc, int group)
-{
- float vec[3];
-
- arc->symmetry_group = group;
-
- sub_v3_v3v3(vec, end_node->p, root_node->p);
-
- if (dot_v3v3(vec, root_node->symmetry_axis) < 0) {
- arc->symmetry_flag |= SYM_SIDE_NEGATIVE;
- }
- else {
- arc->symmetry_flag |= SYM_SIDE_POSITIVE;
- }
-}
-
-static void testAxialSymmetry(BGraph *graph, BNode *root_node, BNode *node1, BNode *node2, BArc *arc1, BArc *arc2, float axis[3], float limit, int group)
-{
- const float limit_sq = limit * limit;
- float nor[3], vec[3], p[3];
-
- sub_v3_v3v3(p, node1->p, root_node->p);
- cross_v3_v3v3(nor, p, axis);
-
- sub_v3_v3v3(p, root_node->p, node2->p);
- cross_v3_v3v3(vec, p, axis);
- add_v3_v3(vec, nor);
-
- cross_v3_v3v3(nor, vec, axis);
-
- if (fabsf(nor[0]) > fabsf(nor[1]) && fabsf(nor[0]) > fabsf(nor[2]) && nor[0] < 0) {
- negate_v3(nor);
- }
- else if (fabsf(nor[1]) > fabsf(nor[0]) && fabsf(nor[1]) > fabsf(nor[2]) && nor[1] < 0) {
- negate_v3(nor);
- }
- else if (fabsf(nor[2]) > fabsf(nor[1]) && fabsf(nor[2]) > fabsf(nor[0]) && nor[2] < 0) {
- negate_v3(nor);
- }
-
- /* mirror node2 along axis */
- copy_v3_v3(p, node2->p);
- BLI_mirrorAlongAxis(p, root_node->p, nor);
-
- /* check if it's within limit before continuing */
- if (len_squared_v3v3(node1->p, p) <= limit_sq) {
- /* mark node as symmetric physically */
- copy_v3_v3(root_node->symmetry_axis, nor);
- root_node->symmetry_flag |= SYM_PHYSICAL;
- root_node->symmetry_flag |= SYM_AXIAL;
-
- /* flag side on arcs */
- flagAxialSymmetry(root_node, node1, arc1, group);
- flagAxialSymmetry(root_node, node2, arc2, group);
-
- if (graph->axial_symmetry) {
- graph->axial_symmetry(root_node, node1, node2, arc1, arc2);
- }
- }
- else {
- /* NOT SYMMETRIC */
- }
-}
-
-static void handleAxialSymmetry(BGraph *graph, BNode *root_node, int depth, float axis[3], float limit)
-{
- BArc *arc1 = NULL, *arc2 = NULL;
- BNode *node1 = NULL, *node2 = NULL;
- int i;
-
- /* mark topological symmetry */
- root_node->symmetry_flag |= SYM_TOPOLOGICAL;
-
- for (i = 0; i < root_node->degree; i++) {
- BArc *connectedArc = root_node->arcs[i];
-
- /* depth is store as a negative in flag. symmetry level is positive */
- if (connectedArc->symmetry_level == -depth) {
- if (arc1 == NULL) {
- arc1 = connectedArc;
- node1 = BLI_otherNode(arc1, root_node);
- }
- else {
- arc2 = connectedArc;
- node2 = BLI_otherNode(arc2, root_node);
- break; /* Can stop now, the two arcs have been found */
- }
- }
- }
-
- /* shouldn't happen, but just to be sure */
- if (node1 == NULL || node2 == NULL) {
- return;
- }
-
- testAxialSymmetry(graph, root_node, node1, node2, arc1, arc2, axis, limit, 1);
-}
-
-static void markdownSecondarySymmetry(BGraph *graph, BNode *node, int depth, int level, float limit)
-{
- float axis[3] = {0, 0, 0};
- int count = 0;
- int i;
-
- /* count the number of branches in this symmetry group
- * and determinate the axis of symmetry
- */
- for (i = 0; i < node->degree; i++) {
- BArc *connectedArc = node->arcs[i];
-
- /* depth is store as a negative in flag. symmetry level is positive */
- if (connectedArc->symmetry_level == -depth) {
- count++;
- }
- /* If arc is on the axis */
- else if (connectedArc->symmetry_level == level) {
- add_v3_v3(axis, connectedArc->head->p);
- sub_v3_v3v3(axis, axis, connectedArc->tail->p);
- }
- }
-
- normalize_v3(axis);
-
- /* Split between axial and radial symmetry */
- if (count == 2) {
- handleAxialSymmetry(graph, node, depth, axis, limit);
- }
- else {
- handleRadialSymmetry(graph, node, depth, axis, limit);
- }
-
- /* markdown secondary symetries */
- for (i = 0; i < node->degree; i++) {
- BArc *connectedArc = node->arcs[i];
-
- if (connectedArc->symmetry_level == -depth) {
- /* markdown symmetry for branches corresponding to the depth */
- markdownSymmetryArc(graph, connectedArc, node, level + 1, limit);
- }
- }
-}
-
-static void markdownSymmetryArc(BGraph *graph, BArc *arc, BNode *node, int level, float limit)
-{
- int i;
-
- /* if arc is null, we start straight from a node */
- if (arc) {
- arc->symmetry_level = level;
-
- node = BLI_otherNode(arc, node);
- }
-
- for (i = 0; i < node->degree; i++) {
- BArc *connectedArc = node->arcs[i];
-
- if (connectedArc != arc) {
- BNode *connectedNode = BLI_otherNode(connectedArc, node);
-
- /* symmetry level is positive value, negative values is subtree depth */
- connectedArc->symmetry_level = -BLI_subtreeShape(graph, connectedNode, connectedArc, 0);
- }
- }
-
- arc = NULL;
-
- for (i = 0; i < node->degree; i++) {
- int issymmetryAxis = 0;
- BArc *connectedArc = node->arcs[i];
-
- /* only arcs not already marked as symetric */
- if (connectedArc->symmetry_level < 0) {
- int j;
-
- /* true by default */
- issymmetryAxis = 1;
-
- for (j = 0; j < node->degree; j++) {
- BArc *otherArc = node->arcs[j];
-
- /* different arc, same depth */
- if (otherArc != connectedArc && otherArc->symmetry_level == connectedArc->symmetry_level) {
- /* not on the symmetry axis */
- issymmetryAxis = 0;
- break;
- }
- }
- }
-
- /* arc could be on the symmetry axis */
- if (issymmetryAxis == 1) {
- /* no arc as been marked previously, keep this one */
- if (arc == NULL) {
- arc = connectedArc;
- }
- else if (connectedArc->symmetry_level < arc->symmetry_level) {
- /* go with more complex subtree as symmetry arc */
- arc = connectedArc;
- }
- }
- }
-
- /* go down the arc continuing the symmetry axis */
- if (arc) {
- markdownSymmetryArc(graph, arc, node, level, limit);
- }
-
-
- /* secondary symmetry */
- for (i = 0; i < node->degree; i++) {
- BArc *connectedArc = node->arcs[i];
-
- /* only arcs not already marked as symetric and is not the next arc on the symmetry axis */
- if (connectedArc->symmetry_level < 0) {
- /* subtree depth is store as a negative value in the symmetry */
- markdownSecondarySymmetry(graph, node, -connectedArc->symmetry_level, level, limit);
- }
- }
-}
-
-void BLI_markdownSymmetry(BGraph *graph, BNode *root_node, float limit)
-{
- BNode *node;
- BArc *arc;
-
- if (root_node == NULL) {
- return;
- }
-
- if (BLI_isGraphCyclic(graph)) {
- return;
- }
-
- /* mark down all arcs as non-symetric */
- BLI_flagArcs(graph, 0);
-
- /* mark down all nodes as not on the symmetry axis */
- BLI_flagNodes(graph, 0);
-
- node = root_node;
-
- /* sanity check REMOVE ME */
- if (node->degree > 0) {
- arc = node->arcs[0];
-
- if (node->degree == 1) {
- markdownSymmetryArc(graph, arc, node, 1, limit);
- }
- else {
- markdownSymmetryArc(graph, NULL, node, 1, limit);
- }
-
-
-
- /* mark down non-symetric arcs */
- for (arc = graph->arcs.first; arc; arc = arc->next) {
- if (arc->symmetry_level < 0) {
- arc->symmetry_level = 0;
- }
- else {
- /* mark down nodes with the lowest level symmetry axis */
- if (arc->head->symmetry_level == 0 || arc->head->symmetry_level > arc->symmetry_level) {
- arc->head->symmetry_level = arc->symmetry_level;
- }
- if (arc->tail->symmetry_level == 0 || arc->tail->symmetry_level > arc->symmetry_level) {
- arc->tail->symmetry_level = arc->symmetry_level;
- }
- }
- }
- }
-}
-
-void *IT_head(void *arg)
-{
- BArcIterator *iter = (BArcIterator *)arg;
- return iter->head(iter);
-}
-
-void *IT_tail(void *arg)
-{
- BArcIterator *iter = (BArcIterator *)arg;
- return iter->tail(iter);
-}
-
-void *IT_peek(void *arg, int n)
-{
- BArcIterator *iter = (BArcIterator *)arg;
-
- if (iter->index + n < 0) {
- return iter->head(iter);
- }
- else if (iter->index + n >= iter->length) {
- return iter->tail(iter);
- }
- else {
- return iter->peek(iter, n);
- }
-}
-
-void *IT_next(void *arg)
-{
- BArcIterator *iter = (BArcIterator *)arg;
- return iter->next(iter);
-}
-
-void *IT_nextN(void *arg, int n)
-{
- BArcIterator *iter = (BArcIterator *)arg;
- return iter->nextN(iter, n);
-}
-
-void *IT_previous(void *arg)
-{
- BArcIterator *iter = (BArcIterator *)arg;
- return iter->previous(iter);
-}
-
-int IT_stopped(void *arg)
-{
- BArcIterator *iter = (BArcIterator *)arg;
- return iter->stopped(iter);
-}
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 568448327bd..da187fbd19d 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -68,6 +68,26 @@ void BLI_movelisttolist(ListBase *dst, ListBase *src)
}
/**
+ * moves the entire contents of \a src at the begining of \a dst.
+ */
+void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
+{
+ if (src->first == NULL) return;
+
+ if (dst->first == NULL) {
+ dst->first = src->first;
+ dst->last = src->last;
+ }
+ else {
+ ((Link *)src->last)->next = dst->first;
+ ((Link *)dst->first)->prev = src->last;
+ dst->first = src->first;
+ }
+
+ src->first = src->last = NULL;
+}
+
+/**
* Prepends \a vlink (assumed to begin with a Link) onto listbase.
*/
void BLI_addhead(ListBase *listbase, void *vlink)
@@ -578,6 +598,9 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
Link *link = NULL;
const char *id_iter;
+ if (id == NULL)
+ return NULL;
+
for (link = listbase->first; link; link = link->next) {
id_iter = ((const char *)link) + offset;
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index ef9e46fc62d..9399646bedf 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -380,8 +380,10 @@ void xyz_to_rgb(float xc, float yc, float zc, float *r, float *g, float *b, int
}
}
-/* we define a 'cpack' here as a (3 byte color code) number that can be expressed like 0xFFAA66 or so.
- * for that reason it is sensitive for endianness... with this function it works correctly
+/**
+ * We define a 'cpack' here as a (3 byte color code) number that can be expressed like 0xFFAA66 or so.
+ * for that reason it is sensitive for endianness... with this function it works correctly.
+ * \see #imm_cpack
*/
unsigned int hsv_to_cpack(float h, float s, float v)
@@ -675,135 +677,80 @@ void rgb_to_lab(float r, float g, float b, float *ll, float *la, float *lb)
xyz_to_lab(x, y, z, ll, la, lb);
}
-static void xyz_to_lms(float x, float y, float z, float *l, float *m, float *s)
-{
- *l = 0.3897f * x + 0.6890f * y - 0.0787f * z;
- *m = -0.2298f * x + 1.1834f * y + 0.0464f * z;
- *s = z;
-}
-
-static void lms_to_xyz(float l, float m, float s, float *x, float *y, float *z)
-{
- *x = 1.9102f * l - 1.1121f * m + 0.2019f * s;
- *y = 0.3709f * l + 0.6290f * m + 0.0000f * s;
- *z = s;
-}
-
-static void normalize_rgb(float rgb[3])
-{
- const float max = max_fff(rgb[0], rgb[1], rgb[2]);
-
- if (max > 0.0f) {
- mul_v3_fl(rgb, 1.0f / max);
- }
-}
+/* ****************************** blackbody ******************************** */
-/* Color rendering of spectra, adapted from public domain code by John Walker,
- * http://www.fourmilab.ch/
+/* Calculate color in range 800..12000 using an approximation
+ * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
+ * Max absolute error for RGB is (0.00095, 0.00077, 0.00057),
+ * which is enough to get the same 8 bit/channel color.
*/
-static void spectrum_to_xyz(float temperature, float xyz[3])
-{
- int i;
- float lambda, x = 0.0f, y = 0.0f, z = 0.0f, xyz_sum;
-
- /* CIE colour matching functions xBar, yBar, and zBar for wavelengths from
- * 380 through 780 nanometers, every 5 nanometers.
- * For a wavelength lambda in this range:
- *
- * cie_colour_match[(lambda - 380) / 5][0] = xBar
- * cie_colour_match[(lambda - 380) / 5][1] = yBar
- * cie_colour_match[(lambda - 380) / 5][2] = zBar
- */
-
- const float cie_colour_match[81][3] = {
- {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
- {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
- {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
- {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
- {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
- {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
- {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
- {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
- {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
- {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
- {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
- {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
- {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
- {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
- {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
- {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
- {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
- {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
- {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
- {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
- {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
- {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
- {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
- {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
- {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
- {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
- {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}
- };
-
- for (i = 0, lambda = 380.0f; lambda < 780.1f; i++, lambda += 5.0f) {
- /* wavelength in meter */
- const float wlm = lambda * 1e-9f;
- const float Me = (3.74183e-16f * powf(wlm, -5.0f)) / (expf(1.4388e-2f / (wlm * temperature)) - 1.0f);
-
- x += Me * cie_colour_match[i][0];
- y += Me * cie_colour_match[i][1];
- z += Me * cie_colour_match[i][2];
+static const float blackbody_table_r[6][3] = {
+ { 2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f },
+ { 3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f },
+ { 4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f },
+ { 4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f },
+ { 4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f },
+ { 3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f },
+};
+
+static const float blackbody_table_g[6][3] = {
+ { -7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f },
+ { -1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f },
+ { -1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f },
+ { -1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f },
+ { -1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f },
+ { -5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f },
+};
+
+static const float blackbody_table_b[6][4] = {
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ { -2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f },
+ { -2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f },
+ { 6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f },
+};
+
+static void blackbody_temperature_to_rgb(float rgb[3], float t)
+{
+ if (t >= 12000.0f) {
+ rgb[0] = 0.826270103f;
+ rgb[1] = 0.994478524f;
+ rgb[2] = 1.56626022f;
+ }
+ else if (t < 965.0f) {
+ rgb[0] = 4.70366907f;
+ rgb[1] = 0.0f;
+ rgb[2] = 0.0f;
+ }
+ else {
+ int i = (t >= 6365.0f) ? 5 :
+ (t >= 3315.0f) ? 4 :
+ (t >= 1902.0f) ? 3 :
+ (t >= 1449.0f) ? 2 :
+ (t >= 1167.0f) ? 1 : 0;
+
+ const float *r = blackbody_table_r[i];
+ const float *g = blackbody_table_g[i];
+ const float *b = blackbody_table_b[i];
+
+ const float t_inv = 1.0f / t;
+ rgb[0] = r[0] * t_inv + r[1] * t + r[2];
+ rgb[1] = g[0] * t_inv + g[1] * t + g[2];
+ rgb[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
}
-
- xyz_sum = (x + y + z);
-
- xyz[0] = x / xyz_sum;
- xyz[1] = y / xyz_sum;
- xyz[2] = z / xyz_sum;
}
void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max)
{
- int i, j = 0, dj = 1;
- float rgb[3], xyz[3], lms[3], lms_w[3];
- float bb_temp;
-
- if (min < max) {
- SWAP(float, min, max);
- j = width - 1;
- dj = -1;
- }
+ for (int i = 0; i < width; i++) {
+ float temperature = min + (max - min) / (float)width * (float)i;
- for (i = 0; i < width; i++, j += dj) {
- bb_temp = min + (max - min) / (float)width * (float)i;
+ float rgb[3];
+ blackbody_temperature_to_rgb(rgb, temperature);
- /* integrate blackbody radiation spectrum to XYZ */
- spectrum_to_xyz(bb_temp, xyz);
-
- /* normalize highest temperature to white (in LMS system) */
- xyz_to_lms(xyz[0], xyz[1], xyz[2], &lms[0], &lms[1], &lms[2]);
-
- if (i == 0) {
- lms_w[0] = 1.0f / lms[0];
- lms_w[1] = 1.0f / lms[1];
- lms_w[2] = 1.0f / lms[2];
- }
-
- mul_v3_v3(lms, lms_w);
-
- lms_to_xyz(lms[0], lms[1], lms[2], &xyz[0], &xyz[1], &xyz[2]);
-
- /* convert to RGB */
- xyz_to_rgb(xyz[0], xyz[1], xyz[2], &rgb[0], &rgb[1], &rgb[2], BLI_XYZ_CIE);
- constrain_rgb(&rgb[0], &rgb[1], &rgb[2]);
- normalize_rgb(rgb);
-
- copy_v3_v3(&r_table[(j << 2)], rgb);
-
- if (rgb[2] > 0.1f)
- r_table[(j << 2) + 3] = rgb[2];
- else
- r_table[(j << 2) + 3] = 0.0f;
+ copy_v3_v3(&r_table[i * 4], rgb);
+ r_table[i * 4 + 3] = 0.0f;
}
}
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index dca9d4204c3..eae82ff2f4f 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -548,8 +548,6 @@ float dist_signed_squared_to_corner_v3v3v3(
dist_b = dist_signed_squared_to_plane3_v3(s_p_v2, plane_b);
#endif
-
-
if (flip) {
return min_ff(dist_a, dist_b);
}
@@ -570,6 +568,8 @@ float dist_squared_to_ray_v3(
*r_depth = dot_v3v3(dvec, ray_direction);
return len_squared_v3(dvec) - SQUARE(*r_depth);
}
+
+
/**
* Find the closest point in a seg to a ray and return the distance squared.
* \param r_point: Is the point on segment closest to ray (or to ray_origin if the ray and the segment are parallel).
@@ -580,43 +580,68 @@ float dist_squared_ray_to_seg_v3(
const float v0[3], const float v1[3],
float r_point[3], float *r_depth)
{
- float a[3], t[3], n[3], lambda;
- sub_v3_v3v3(a, v1, v0);
- sub_v3_v3v3(t, v0, ray_origin);
- cross_v3_v3v3(n, a, ray_direction);
- const float nlen = len_squared_v3(n);
-
- /* if (nlen == 0.0f) the lines are parallel,
- * has no nearest point, only distance squared.*/
- if (nlen == 0.0f) {
- /* Calculate the distance to the point v0 then */
- copy_v3_v3(r_point, v0);
- *r_depth = dot_v3v3(t, ray_direction);
- }
- else {
- float c[3], cray[3];
- sub_v3_v3v3(c, n, t);
- cross_v3_v3v3(cray, c, ray_direction);
- lambda = dot_v3v3(cray, n) / nlen;
- if (lambda <= 0) {
+ float lambda, depth;
+ if (isect_ray_seg_v3(
+ ray_origin, ray_direction, v0, v1, &lambda))
+ {
+ if (lambda <= 0.0f) {
copy_v3_v3(r_point, v0);
-
- *r_depth = dot_v3v3(t, ray_direction);
}
- else if (lambda >= 1) {
+ else if (lambda >= 1.0f) {
copy_v3_v3(r_point, v1);
-
- sub_v3_v3v3(t, v1, ray_origin);
- *r_depth = dot_v3v3(t, ray_direction);
}
else {
- madd_v3_v3v3fl(r_point, v0, a, lambda);
-
- sub_v3_v3v3(t, r_point, ray_origin);
- *r_depth = dot_v3v3(t, ray_direction);
+ interp_v3_v3v3(r_point, v0, v1, lambda);
}
}
- return len_squared_v3(t) - SQUARE(*r_depth);
+ else {
+ /* has no nearest point, only distance squared. */
+ /* Calculate the distance to the point v0 then */
+ copy_v3_v3(r_point, v0);
+ }
+
+ float dvec[3];
+ sub_v3_v3v3(dvec, r_point, ray_origin);
+ depth = dot_v3v3(dvec, ray_direction);
+
+ if (r_depth) {
+ *r_depth = depth;
+ }
+
+ return len_squared_v3(dvec) - SQUARE(depth);
+}
+
+
+/* Returns the coordinates of the nearest vertex and
+ * the farthest vertex from a plane (or normal). */
+void aabb_get_near_far_from_plane(
+ const float plane_no[3], const float bbmin[3], const float bbmax[3],
+ float bb_near[3], float bb_afar[3])
+{
+ if (plane_no[0] < 0.0f) {
+ bb_near[0] = bbmax[0];
+ bb_afar[0] = bbmin[0];
+ }
+ else {
+ bb_near[0] = bbmin[0];
+ bb_afar[0] = bbmax[0];
+ }
+ if (plane_no[1] < 0.0f) {
+ bb_near[1] = bbmax[1];
+ bb_afar[1] = bbmin[1];
+ }
+ else {
+ bb_near[1] = bbmin[1];
+ bb_afar[1] = bbmax[1];
+ }
+ if (plane_no[2] < 0.0f) {
+ bb_near[2] = bbmax[2];
+ bb_afar[2] = bbmin[2];
+ }
+ else {
+ bb_near[2] = bbmin[2];
+ bb_afar[2] = bbmax[2];
+ }
}
/* -------------------------------------------------------------------- */
@@ -634,7 +659,6 @@ void dist_squared_ray_to_aabb_v3_precalc(
neasrest_precalc->ray_inv_dir[i] =
(neasrest_precalc->ray_direction[i] != 0.0f) ?
(1.0f / neasrest_precalc->ray_direction[i]) : FLT_MAX;
- neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f);
}
}
@@ -648,30 +672,8 @@ float dist_squared_ray_to_aabb_v3(
{
// bool r_axis_closest[3];
float local_bvmin[3], local_bvmax[3];
- if (data->sign[0]) {
- local_bvmin[0] = bb_max[0];
- local_bvmax[0] = bb_min[0];
- }
- else {
- local_bvmin[0] = bb_min[0];
- local_bvmax[0] = bb_max[0];
- }
- if (data->sign[1]) {
- local_bvmin[1] = bb_max[1];
- local_bvmax[1] = bb_min[1];
- }
- else {
- local_bvmin[1] = bb_min[1];
- local_bvmax[1] = bb_max[1];
- }
- if (data->sign[2]) {
- local_bvmin[2] = bb_max[2];
- local_bvmax[2] = bb_min[2];
- }
- else {
- local_bvmin[2] = bb_min[2];
- local_bvmax[2] = bb_max[2];
- }
+ aabb_get_near_far_from_plane(
+ data->ray_direction, bb_min, bb_max, local_bvmin, local_bvmax);
const float tmin[3] = {
(local_bvmin[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
@@ -693,38 +695,38 @@ float dist_squared_ray_to_aabb_v3(
rtmax = tmax[0];
va[0] = vb[0] = local_bvmax[0];
main_axis = 3;
- // r_axis_closest[0] = data->sign[0];
+ // r_axis_closest[0] = neasrest_precalc->ray_direction[0] < 0.0f;
}
else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
rtmax = tmax[1];
va[1] = vb[1] = local_bvmax[1];
main_axis = 2;
- // r_axis_closest[1] = data->sign[1];
+ // r_axis_closest[1] = neasrest_precalc->ray_direction[1] < 0.0f;
}
else {
rtmax = tmax[2];
va[2] = vb[2] = local_bvmax[2];
main_axis = 1;
- // r_axis_closest[2] = data->sign[2];
+ // r_axis_closest[2] = neasrest_precalc->ray_direction[2] < 0.0f;
}
if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
rtmin = tmin[0];
va[0] = vb[0] = local_bvmin[0];
main_axis -= 3;
- // r_axis_closest[0] = !data->sign[0];
+ // r_axis_closest[0] = neasrest_precalc->ray_direction[0] >= 0.0f;
}
else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
rtmin = tmin[1];
va[1] = vb[1] = local_bvmin[1];
main_axis -= 1;
- // r_axis_closest[1] = !data->sign[1];
+ // r_axis_closest[1] = neasrest_precalc->ray_direction[1] >= 0.0f;
}
else {
rtmin = tmin[2];
va[2] = vb[2] = local_bvmin[2];
main_axis -= 2;
- // r_axis_closest[2] = !data->sign[2];
+ // r_axis_closest[2] = neasrest_precalc->ray_direction[2] >= 0.0f;
}
if (main_axis < 0) {
main_axis += 3;
@@ -739,14 +741,14 @@ float dist_squared_ray_to_aabb_v3(
return 0.0f;
}
- if (data->sign[main_axis]) {
- va[main_axis] = local_bvmax[main_axis];
- vb[main_axis] = local_bvmin[main_axis];
- }
- else {
+ if (data->ray_direction[main_axis] >= 0.0f) {
va[main_axis] = local_bvmin[main_axis];
vb[main_axis] = local_bvmax[main_axis];
}
+ else {
+ va[main_axis] = local_bvmax[main_axis];
+ vb[main_axis] = local_bvmin[main_axis];
+ }
return dist_squared_ray_to_seg_v3(
data->ray_origin, data->ray_direction, va, vb,
@@ -765,6 +767,214 @@ float dist_squared_ray_to_aabb_v3_simple(
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name dist_squared_to_projected_aabb and helpers
+* \{ */
+
+/**
+ * \param projmat: Projection Matrix (usually perspective
+ * matrix multiplied by object matrix).
+ */
+void dist_squared_to_projected_aabb_precalc(
+ struct DistProjectedAABBPrecalc *precalc,
+ const float projmat[4][4], const float winsize[2], const float mval[2])
+{
+ float win_half[2], relative_mval[2], px[4], py[4];
+
+ mul_v2_v2fl(win_half, winsize, 0.5f);
+ sub_v2_v2v2(precalc->mval, mval, win_half);
+
+ relative_mval[0] = precalc->mval[0] / win_half[0];
+ relative_mval[1] = precalc->mval[1] / win_half[1];
+
+ copy_m4_m4(precalc->pmat, projmat);
+ for (int i = 0; i < 4; i++) {
+ px[i] = precalc->pmat[i][0] - precalc->pmat[i][3] * relative_mval[0];
+ py[i] = precalc->pmat[i][1] - precalc->pmat[i][3] * relative_mval[1];
+
+ precalc->pmat[i][0] *= win_half[0];
+ precalc->pmat[i][1] *= win_half[1];
+ }
+#if 0
+ float projmat_trans[4][4];
+ transpose_m4_m4(projmat_trans, projmat);
+ if (!isect_plane_plane_plane_v3(
+ projmat_trans[0], projmat_trans[1], projmat_trans[3],
+ precalc->ray_origin))
+ {
+ /* Orthographic projection. */
+ isect_plane_plane_v3(
+ px, py,
+ precalc->ray_origin,
+ precalc->ray_direction);
+ }
+ else {
+ /* Perspective projection. */
+ cross_v3_v3v3(precalc->ray_direction, py, px);
+ //normalize_v3(precalc->ray_direction);
+ }
+#else
+ if (!isect_plane_plane_v3(
+ px, py,
+ precalc->ray_origin,
+ precalc->ray_direction))
+ {
+ /* Matrix with weird coplanar planes. Undetermined origin.*/
+ zero_v3(precalc->ray_origin);
+ precalc->ray_direction[0] = precalc->pmat[0][3];
+ precalc->ray_direction[1] = precalc->pmat[1][3];
+ precalc->ray_direction[2] = precalc->pmat[2][3];
+ }
+#endif
+
+ for (int i = 0; i < 3; i++) {
+ precalc->ray_inv_dir[i] =
+ (precalc->ray_direction[i] != 0.0f) ?
+ (1.0f / precalc->ray_direction[i]) : FLT_MAX;
+ }
+}
+
+/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */
+float dist_squared_to_projected_aabb(
+ struct DistProjectedAABBPrecalc *data,
+ const float bbmin[3], const float bbmax[3],
+ bool r_axis_closest[3])
+{
+ float local_bvmin[3], local_bvmax[3];
+ aabb_get_near_far_from_plane(
+ data->ray_direction, bbmin, bbmax, local_bvmin, local_bvmax);
+
+ const float tmin[3] = {
+ (local_bvmin[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
+ (local_bvmin[1] - data->ray_origin[1]) * data->ray_inv_dir[1],
+ (local_bvmin[2] - data->ray_origin[2]) * data->ray_inv_dir[2],
+ };
+ const float tmax[3] = {
+ (local_bvmax[0] - data->ray_origin[0]) * data->ray_inv_dir[0],
+ (local_bvmax[1] - data->ray_origin[1]) * data->ray_inv_dir[1],
+ (local_bvmax[2] - data->ray_origin[2]) * data->ray_inv_dir[2],
+ };
+ /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */
+ float va[3], vb[3];
+ /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */
+ float rtmin, rtmax;
+ int main_axis;
+
+ if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
+ rtmax = tmax[0];
+ va[0] = vb[0] = local_bvmax[0];
+ main_axis = 3;
+ r_axis_closest[0] = data->ray_direction[0] < 0.0f;
+ }
+ else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
+ rtmax = tmax[1];
+ va[1] = vb[1] = local_bvmax[1];
+ main_axis = 2;
+ r_axis_closest[1] = data->ray_direction[1] < 0.0f;
+ }
+ else {
+ rtmax = tmax[2];
+ va[2] = vb[2] = local_bvmax[2];
+ main_axis = 1;
+ r_axis_closest[2] = data->ray_direction[2] < 0.0f;
+ }
+
+ if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
+ rtmin = tmin[0];
+ va[0] = vb[0] = local_bvmin[0];
+ main_axis -= 3;
+ r_axis_closest[0] = data->ray_direction[0] >= 0.0f;
+ }
+ else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
+ rtmin = tmin[1];
+ va[1] = vb[1] = local_bvmin[1];
+ main_axis -= 1;
+ r_axis_closest[1] = data->ray_direction[1] >= 0.0f;
+ }
+ else {
+ rtmin = tmin[2];
+ va[2] = vb[2] = local_bvmin[2];
+ main_axis -= 2;
+ r_axis_closest[2] = data->ray_direction[2] >= 0.0f;
+ }
+ if (main_axis < 0) {
+ main_axis += 3;
+ }
+
+ /* if rtmin <= rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+ return 0;
+ }
+
+ if (data->ray_direction[main_axis] >= 0.0f) {
+ va[main_axis] = local_bvmin[main_axis];
+ vb[main_axis] = local_bvmax[main_axis];
+ }
+ else {
+ va[main_axis] = local_bvmax[main_axis];
+ vb[main_axis] = local_bvmin[main_axis];
+ }
+ float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]);
+
+ float va2d[2] = {
+ (dot_m4_v3_row_x(data->pmat, va) + data->pmat[3][0]),
+ (dot_m4_v3_row_y(data->pmat, va) + data->pmat[3][1]),
+ };
+ float vb2d[2] = {
+ (va2d[0] + data->pmat[main_axis][0] * scale),
+ (va2d[1] + data->pmat[main_axis][1] * scale),
+ };
+
+ float w_a = mul_project_m4_v3_zfac(data->pmat, va);
+ if (w_a != 1.0f) {
+ /* Perspective Projection. */
+ float w_b = w_a + data->pmat[main_axis][3] * scale;
+ va2d[0] /= w_a;
+ va2d[1] /= w_a;
+ vb2d[0] /= w_b;
+ vb2d[1] /= w_b;
+ }
+
+ float dvec[2], edge[2], lambda, rdist_sq;
+ sub_v2_v2v2(dvec, data->mval, va2d);
+ sub_v2_v2v2(edge, vb2d, va2d);
+ lambda = dot_v2v2(dvec, edge);
+ if (lambda != 0.0f) {
+ lambda /= len_squared_v2(edge);
+ if (lambda <= 0.0f) {
+ rdist_sq = len_squared_v2v2(data->mval, va2d);
+ r_axis_closest[main_axis] = true;
+ }
+ else if (lambda >= 1.0f) {
+ rdist_sq = len_squared_v2v2(data->mval, vb2d);
+ r_axis_closest[main_axis] = false;
+ }
+ else {
+ madd_v2_v2fl(va2d, edge, lambda);
+ rdist_sq = len_squared_v2v2(data->mval, va2d);
+ r_axis_closest[main_axis] = lambda < 0.5f;
+ }
+ }
+ else {
+ rdist_sq = len_squared_v2v2(data->mval, va2d);
+ }
+
+ return rdist_sq;
+}
+
+float dist_squared_to_projected_aabb_simple(
+ const float projmat[4][4], const float winsize[2], const float mval[2],
+ const float bbmin[3], const float bbmax[3])
+{
+ struct DistProjectedAABBPrecalc data;
+ dist_squared_to_projected_aabb_precalc(&data, projmat, winsize, mval);
+
+ bool dummy[3] = {true, true, true};
+ return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
+}
+/** \} */
+
+
/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
* published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc.
*
@@ -1244,90 +1454,6 @@ int isect_line_sphere_v2(const float l1[2], const float l2[2],
}
/* point in polygon (keep float and int versions in sync) */
-#if 0
-bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr,
- const bool use_holes)
-{
- /* we do the angle rule, define that all added angles should be about zero or (2 * PI) */
- float angletot = 0.0;
- float fp1[2], fp2[2];
- unsigned int i;
- const float *p1, *p2;
-
- p1 = verts[nr - 1];
-
- /* first vector */
- fp1[0] = (float)(p1[0] - pt[0]);
- fp1[1] = (float)(p1[1] - pt[1]);
-
- for (i = 0; i < nr; i++) {
- p2 = verts[i];
-
- /* second vector */
- fp2[0] = (float)(p2[0] - pt[0]);
- fp2[1] = (float)(p2[1] - pt[1]);
-
- /* dot and angle and cross */
- angletot += angle_signed_v2v2(fp1, fp2);
-
- /* circulate */
- copy_v2_v2(fp1, fp2);
- p1 = p2;
- }
-
- angletot = fabsf(angletot);
- if (use_holes) {
- const float nested = floorf((angletot / (float)(M_PI * 2.0)) + 0.00001f);
- angletot -= nested * (float)(M_PI * 2.0);
- return (angletot > 4.0f) != ((int)nested % 2);
- }
- else {
- return (angletot > 4.0f);
- }
-}
-bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const unsigned int nr,
- const bool use_holes)
-{
- /* we do the angle rule, define that all added angles should be about zero or (2 * PI) */
- float angletot = 0.0;
- float fp1[2], fp2[2];
- unsigned int i;
- const int *p1, *p2;
-
- p1 = verts[nr - 1];
-
- /* first vector */
- fp1[0] = (float)(p1[0] - pt[0]);
- fp1[1] = (float)(p1[1] - pt[1]);
-
- for (i = 0; i < nr; i++) {
- p2 = verts[i];
-
- /* second vector */
- fp2[0] = (float)(p2[0] - pt[0]);
- fp2[1] = (float)(p2[1] - pt[1]);
-
- /* dot and angle and cross */
- angletot += angle_signed_v2v2(fp1, fp2);
-
- /* circulate */
- copy_v2_v2(fp1, fp2);
- p1 = p2;
- }
-
- angletot = fabsf(angletot);
- if (use_holes) {
- const float nested = floorf((angletot / (float)(M_PI * 2.0)) + 0.00001f);
- angletot -= nested * (float)(M_PI * 2.0);
- return (angletot > 4.0f) != ((int)nested % 2);
- }
- else {
- return (angletot > 4.0f);
- }
-}
-
-#else
-
bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr,
const bool UNUSED(use_holes))
{
@@ -1357,8 +1483,6 @@ bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const unsign
return isect;
}
-#endif
-
/* point in tri */
/* only single direction */
@@ -1833,6 +1957,33 @@ bool isect_ray_seg_v2(
return false;
}
+
+bool isect_ray_seg_v3(
+ const float ray_origin[3], const float ray_direction[3],
+ const float v0[3], const float v1[3],
+ float *r_lambda)
+{
+ float a[3], t[3], n[3];
+ sub_v3_v3v3(a, v1, v0);
+ sub_v3_v3v3(t, v0, ray_origin);
+ cross_v3_v3v3(n, a, ray_direction);
+ const float nlen = len_squared_v3(n);
+
+ if (nlen == 0.0f) {
+ /* the lines are parallel.*/
+ return false;
+ }
+
+ float c[3], cray[3];
+ sub_v3_v3v3(c, n, t);
+ cross_v3_v3v3(cray, c, ray_direction);
+
+ *r_lambda = dot_v3v3(cray, n) / nlen;
+
+ return true;
+}
+
+
/**
* Check if a point is behind all planes.
*/
@@ -1850,6 +2001,23 @@ bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
}
/**
+ * Check if a point is in front all planes.
+ * Same as isect_point_planes_v3 but with planes facing the opposite direction.
+ */
+bool isect_point_planes_v3_negated(
+ const float(*planes)[4], const int totplane, const float p[3])
+{
+ for (int i = 0; i < totplane; i++) {
+ if (plane_point_side_v3(planes[i], p) <= 0.0f) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/**
* Intersect line/plane.
*
* \param r_isect_co The intersection point.
@@ -2107,6 +2275,38 @@ static bool getLowestRoot(const float a, const float b, const float c, const flo
return false;
}
+
+/**
+ * Checks status of an AABB in relation to a list of planes.
+ *
+ * \returns intersection type:
+ * - ISECT_AABB_PLANE_BEHIND_ONE (0): AABB is completely behind at least 1 plane;
+ * - ISECT_AABB_PLANE_CROSS_ANY (1): AABB intersects at least 1 plane;
+ * - ISECT_AABB_PLANE_IN_FRONT_ALL (2): AABB is completely in front of all planes;
+ */
+int isect_aabb_planes_v3(
+ const float (*planes)[4], const int totplane,
+ const float bbmin[3], const float bbmax[3])
+{
+ int ret = ISECT_AABB_PLANE_IN_FRONT_ALL;
+
+ float bb_near[3], bb_far[3];
+ for (int i = 0; i < totplane; i++) {
+ aabb_get_near_far_from_plane(planes[i], bbmin, bbmax, bb_near, bb_far);
+
+ if (plane_point_side_v3(planes[i], bb_far) < 0.0f) {
+ return ISECT_AABB_PLANE_BEHIND_ANY;
+ }
+ else if ((ret != ISECT_AABB_PLANE_CROSS_ANY) &&
+ (plane_point_side_v3(planes[i], bb_near) < 0.0f))
+ {
+ ret = ISECT_AABB_PLANE_CROSS_ANY;
+ }
+ }
+
+ return ret;
+}
+
bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius,
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float ipoint[3])
@@ -2304,18 +2504,6 @@ bool isect_axial_line_segment_tri_v3(
float u, v, f;
int a0 = axis, a1 = (axis + 1) % 3, a2 = (axis + 2) % 3;
-#if 0
- return isect_line_segment_tri_v3(p1, p2, v0, v1, v2, lambda);
-
- /* first a simple bounding box test */
- if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return false;
- if (min_fff(v0[a2], v1[a2], v2[a2]) > p1[a2]) return false;
- if (max_fff(v0[a1], v1[a1], v2[a1]) < p1[a1]) return false;
- if (max_fff(v0[a2], v1[a2], v2[a2]) < p1[a2]) return false;
-
- /* then a full intersection test */
-#endif
-
sub_v3_v3v3(e1, v1, v0);
sub_v3_v3v3(e2, v2, v0);
sub_v3_v3v3(p, v0, p1);
@@ -2632,13 +2820,10 @@ float line_point_factor_v3_ex(
float dot;
sub_v3_v3v3(u, l2, l1);
sub_v3_v3v3(h, p, l1);
-#if 0
- return (dot_v3v3(u, h) / dot_v3v3(u, u));
-#else
+
/* better check for zero */
dot = len_squared_v3(u);
return (dot > epsilon) ? (dot_v3v3(u, h) / dot) : fallback;
-#endif
}
float line_point_factor_v3(
const float p[3], const float l1[3], const float l2[3])
@@ -2654,13 +2839,9 @@ float line_point_factor_v2_ex(
float dot;
sub_v2_v2v2(u, l2, l1);
sub_v2_v2v2(h, p, l1);
-#if 0
- return (dot_v2v2(u, h) / dot_v2v2(u, u));
-#else
/* better check for zero */
dot = len_squared_v2(u);
return (dot > epsilon) ? (dot_v2v2(u, h) / dot) : fallback;
-#endif
}
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
@@ -2755,29 +2936,25 @@ static bool point_in_slice(const float p[3], const float v1[3], const float l1[3
return (h >= 0.0f && h <= 1.0f);
}
-#if 0
-
/* adult sister defining the slice planes by the origin and the normal
* NOTE |normal| may not be 1 but defining the thickness of the slice */
-static int point_in_slice_as(float p[3], float origin[3], float normal[3])
+static bool point_in_slice_as(float p[3], float origin[3], float normal[3])
{
float h, rp[3];
sub_v3_v3v3(rp, p, origin);
h = dot_v3v3(normal, rp) / dot_v3v3(normal, normal);
- if (h < 0.0f || h > 1.0f) return 0;
- return 1;
+ if (h < 0.0f || h > 1.0f) return false;
+ return true;
}
-/*mama (knowing the squared length of the normal) */
-static int point_in_slice_m(float p[3], float origin[3], float normal[3], float lns)
+bool point_in_slice_seg(float p[3], float l1[3], float l2[3])
{
- float h, rp[3];
- sub_v3_v3v3(rp, p, origin);
- h = dot_v3v3(normal, rp) / lns;
- if (h < 0.0f || h > 1.0f) return 0;
- return 1;
+ float normal[3];
+
+ sub_v3_v3v3(normal, l2, l1);
+
+ return point_in_slice_as(p, l1, normal);
}
-#endif
bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3])
{
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index f117c815ee9..462d0737016 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -33,6 +33,8 @@
#include "BLI_strict_flags.h"
+#include "eigen_capi.h"
+
/********************************* Init **************************************/
void zero_m2(float m[2][2])
@@ -74,23 +76,23 @@ void unit_m4(float m[4][4])
m[3][0] = m[3][1] = m[3][2] = 0.0f;
}
-void copy_m2_m2(float m1[2][2], float m2[2][2])
+void copy_m2_m2(float m1[2][2], const float m2[2][2])
{
memcpy(m1, m2, sizeof(float[2][2]));
}
-void copy_m3_m3(float m1[3][3], float m2[3][3])
+void copy_m3_m3(float m1[3][3], const float m2[3][3])
{
/* destination comes first: */
memcpy(m1, m2, sizeof(float[3][3]));
}
-void copy_m4_m4(float m1[4][4], float m2[4][4])
+void copy_m4_m4(float m1[4][4], const float m2[4][4])
{
memcpy(m1, m2, sizeof(float[4][4]));
}
-void copy_m3_m4(float m1[3][3], float m2[4][4])
+void copy_m3_m4(float m1[3][3], const float m2[4][4])
{
m1[0][0] = m2[0][0];
m1[0][1] = m2[0][1];
@@ -105,7 +107,7 @@ void copy_m3_m4(float m1[3][3], float m2[4][4])
m1[2][2] = m2[2][2];
}
-void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */
+void copy_m4_m3(float m1[4][4], const float m2[3][3]) /* no clear */
{
m1[0][0] = m2[0][0];
m1[0][1] = m2[0][1];
@@ -131,7 +133,7 @@ void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */
}
-void copy_m3_m3d(float R[3][3], double A[3][3])
+void copy_m3_m3d(float R[3][3], const double A[3][3])
{
/* Keep it stupid simple for better data flow in CPU. */
R[0][0] = (float)A[0][0];
@@ -177,64 +179,127 @@ void swap_m4m4(float m1[4][4], float m2[4][4])
/******************************** Arithmetic *********************************/
-void mul_m4_m4m4(float m1[4][4], float m3_[4][4], float m2_[4][4])
+void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
{
- float m2[4][4], m3[4][4];
+ if (A == R)
+ mul_m4_m4_post(R, B);
+ else if (B == R)
+ mul_m4_m4_pre(R, A);
+ else
+ mul_m4_m4m4_uniq(R, A, B);
+}
- /* copy so it works when m1 is the same pointer as m2 or m3 */
- copy_m4_m4(m2, m2_);
- copy_m4_m4(m3, m3_);
+void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4])
+{
+ BLI_assert(R != A && R != B);
- /* matrix product: m1[j][k] = m2[j][i].m3[i][k] */
- m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] + m2[0][2] * m3[2][0] + m2[0][3] * m3[3][0];
- m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] + m2[0][2] * m3[2][1] + m2[0][3] * m3[3][1];
- m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] + m2[0][2] * m3[2][2] + m2[0][3] * m3[3][2];
- m1[0][3] = m2[0][0] * m3[0][3] + m2[0][1] * m3[1][3] + m2[0][2] * m3[2][3] + m2[0][3] * m3[3][3];
+ /* matrix product: R[j][k] = A[j][i] . B[i][k] */
+#ifdef __SSE2__
+ __m128 A0 = _mm_loadu_ps(A[0]);
+ __m128 A1 = _mm_loadu_ps(A[1]);
+ __m128 A2 = _mm_loadu_ps(A[2]);
+ __m128 A3 = _mm_loadu_ps(A[3]);
- m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] + m2[1][2] * m3[2][0] + m2[1][3] * m3[3][0];
- m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] + m2[1][2] * m3[2][1] + m2[1][3] * m3[3][1];
- m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] + m2[1][2] * m3[2][2] + m2[1][3] * m3[3][2];
- m1[1][3] = m2[1][0] * m3[0][3] + m2[1][1] * m3[1][3] + m2[1][2] * m3[2][3] + m2[1][3] * m3[3][3];
+ for (int i = 0; i < 4; i++) {
+ __m128 B0 = _mm_set1_ps(B[i][0]);
+ __m128 B1 = _mm_set1_ps(B[i][1]);
+ __m128 B2 = _mm_set1_ps(B[i][2]);
+ __m128 B3 = _mm_set1_ps(B[i][3]);
- m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] + m2[2][2] * m3[2][0] + m2[2][3] * m3[3][0];
- m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] + m2[2][2] * m3[2][1] + m2[2][3] * m3[3][1];
- m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2] + m2[2][3] * m3[3][2];
- m1[2][3] = m2[2][0] * m3[0][3] + m2[2][1] * m3[1][3] + m2[2][2] * m3[2][3] + m2[2][3] * m3[3][3];
+ __m128 sum = _mm_add_ps(
+ _mm_add_ps(_mm_mul_ps(B0, A0), _mm_mul_ps(B1, A1)),
+ _mm_add_ps(_mm_mul_ps(B2, A2), _mm_mul_ps(B3, A3)));
- m1[3][0] = m2[3][0] * m3[0][0] + m2[3][1] * m3[1][0] + m2[3][2] * m3[2][0] + m2[3][3] * m3[3][0];
- m1[3][1] = m2[3][0] * m3[0][1] + m2[3][1] * m3[1][1] + m2[3][2] * m3[2][1] + m2[3][3] * m3[3][1];
- m1[3][2] = m2[3][0] * m3[0][2] + m2[3][1] * m3[1][2] + m2[3][2] * m3[2][2] + m2[3][3] * m3[3][2];
- m1[3][3] = m2[3][0] * m3[0][3] + m2[3][1] * m3[1][3] + m2[3][2] * m3[2][3] + m2[3][3] * m3[3][3];
+ _mm_storeu_ps(R[i], sum);
+ }
+#else
+ R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0];
+ R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1];
+ R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2] + B[0][3] * A[3][2];
+ R[0][3] = B[0][0] * A[0][3] + B[0][1] * A[1][3] + B[0][2] * A[2][3] + B[0][3] * A[3][3];
+
+ R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0] + B[1][3] * A[3][0];
+ R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1] + B[1][3] * A[3][1];
+ R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2] + B[1][3] * A[3][2];
+ R[1][3] = B[1][0] * A[0][3] + B[1][1] * A[1][3] + B[1][2] * A[2][3] + B[1][3] * A[3][3];
+
+ R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0] + B[2][3] * A[3][0];
+ R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1] + B[2][3] * A[3][1];
+ R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2] + B[2][3] * A[3][2];
+ R[2][3] = B[2][0] * A[0][3] + B[2][1] * A[1][3] + B[2][2] * A[2][3] + B[2][3] * A[3][3];
+
+ R[3][0] = B[3][0] * A[0][0] + B[3][1] * A[1][0] + B[3][2] * A[2][0] + B[3][3] * A[3][0];
+ R[3][1] = B[3][0] * A[0][1] + B[3][1] * A[1][1] + B[3][2] * A[2][1] + B[3][3] * A[3][1];
+ R[3][2] = B[3][0] * A[0][2] + B[3][1] * A[1][2] + B[3][2] * A[2][2] + B[3][3] * A[3][2];
+ R[3][3] = B[3][0] * A[0][3] + B[3][1] * A[1][3] + B[3][2] * A[2][3] + B[3][3] * A[3][3];
+#endif
+}
+void mul_m4_m4_pre(float R[4][4], const float A[4][4])
+{
+ BLI_assert(A != R);
+ float B[4][4];
+ copy_m4_m4(B, R);
+ mul_m4_m4m4_uniq(R, A, B);
}
-void mul_m3_m3m3(float m1[3][3], float m3_[3][3], float m2_[3][3])
+void mul_m4_m4_post(float R[4][4], const float B[4][4])
{
- float m2[3][3], m3[3][3];
+ BLI_assert(B != R);
+ float A[4][4];
+ copy_m4_m4(A, R);
+ mul_m4_m4m4_uniq(R, A, B);
+}
- /* copy so it works when m1 is the same pointer as m2 or m3 */
- copy_m3_m3(m2, m2_);
- copy_m3_m3(m3, m3_);
+void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
+{
+ if (A == R)
+ mul_m3_m3_post(R, B);
+ else if (B == R)
+ mul_m3_m3_pre(R, A);
+ else
+ mul_m3_m3m3_uniq(R, A, B);
+}
- /* m1[i][j] = m2[i][k] * m3[k][j], args are flipped! */
- m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] + m2[0][2] * m3[2][0];
- m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] + m2[0][2] * m3[2][1];
- m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] + m2[0][2] * m3[2][2];
+void mul_m3_m3_pre(float R[3][3], const float A[3][3])
+{
+ BLI_assert(A != R);
+ float B[3][3];
+ copy_m3_m3(B, R);
+ mul_m3_m3m3_uniq(R, A, B);
+}
- m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] + m2[1][2] * m3[2][0];
- m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] + m2[1][2] * m3[2][1];
- m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] + m2[1][2] * m3[2][2];
+void mul_m3_m3_post(float R[3][3], const float B[3][3])
+{
+ BLI_assert(B != R);
+ float A[3][3];
+ copy_m3_m3(A, R);
+ mul_m3_m3m3_uniq(R, A, B);
+}
- m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] + m2[2][2] * m3[2][0];
- m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] + m2[2][2] * m3[2][1];
- m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2];
+void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3])
+{
+ BLI_assert(R != A && R != B);
+
+ R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
+ R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
+ R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
+
+ R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
+ R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
+ R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
+
+ R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
+ R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
+ R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
}
-void mul_m4_m4m3(float m1[4][4], float m3_[4][4], float m2_[3][3])
+void mul_m4_m4m3(float m1[4][4], const float m3_[4][4], const float m2_[3][3])
{
float m2[3][3], m3[4][4];
/* copy so it works when m1 is the same pointer as m2 or m3 */
+ /* TODO: avoid copying when matrices are different */
copy_m3_m3(m2, m2_);
copy_m4_m4(m3, m3_);
@@ -250,11 +315,12 @@ void mul_m4_m4m3(float m1[4][4], float m3_[4][4], float m2_[3][3])
}
/* m1 = m2 * m3, ignore the elements on the 4th row/column of m3 */
-void mul_m3_m3m4(float m1[3][3], float m3_[4][4], float m2_[3][3])
+void mul_m3_m3m4(float m1[3][3], const float m3_[4][4], const float m2_[3][3])
{
float m2[3][3], m3[4][4];
/* copy so it works when m1 is the same pointer as m2 or m3 */
+ /* TODO: avoid copying when matrices are different */
copy_m3_m3(m2, m2_);
copy_m4_m4(m3, m3_);
@@ -272,11 +338,12 @@ void mul_m3_m3m4(float m1[3][3], float m3_[4][4], float m2_[3][3])
m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2];
}
-void mul_m4_m3m4(float m1[4][4], float m3_[3][3], float m2_[4][4])
+void mul_m4_m3m4(float m1[4][4], const float m3_[3][3], const float m2_[4][4])
{
float m2[4][4], m3[3][3];
/* copy so it works when m1 is the same pointer as m2 or m3 */
+ /* TODO: avoid copying when matrices are different */
copy_m4_m4(m2, m2_);
copy_m3_m3(m3, m3_);
@@ -296,20 +363,20 @@ void mul_m4_m3m4(float m1[4][4], float m3_[3][3], float m2_[4][4])
* \{ */
void _va_mul_m3_series_3(
float r[3][3],
- float m1[3][3], float m2[3][3])
+ const float m1[3][3], const float m2[3][3])
{
mul_m3_m3m3(r, m1, m2);
}
void _va_mul_m3_series_4(
float r[3][3],
- float m1[3][3], float m2[3][3], float m3[3][3])
+ const float m1[3][3], const float m2[3][3], const float m3[3][3])
{
mul_m3_m3m3(r, m1, m2);
mul_m3_m3m3(r, r, m3);
}
void _va_mul_m3_series_5(
float r[3][3],
- float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3])
+ const float m1[3][3], const float m2[3][3], const float m3[3][3], const float m4[3][3])
{
mul_m3_m3m3(r, m1, m2);
mul_m3_m3m3(r, r, m3);
@@ -317,8 +384,8 @@ void _va_mul_m3_series_5(
}
void _va_mul_m3_series_6(
float r[3][3],
- float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3],
- float m5[3][3])
+ const float m1[3][3], const float m2[3][3], const float m3[3][3], const float m4[3][3],
+ const float m5[3][3])
{
mul_m3_m3m3(r, m1, m2);
mul_m3_m3m3(r, r, m3);
@@ -327,8 +394,8 @@ void _va_mul_m3_series_6(
}
void _va_mul_m3_series_7(
float r[3][3],
- float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3],
- float m5[3][3], float m6[3][3])
+ const float m1[3][3], const float m2[3][3], const float m3[3][3], const float m4[3][3],
+ const float m5[3][3], const float m6[3][3])
{
mul_m3_m3m3(r, m1, m2);
mul_m3_m3m3(r, r, m3);
@@ -338,8 +405,8 @@ void _va_mul_m3_series_7(
}
void _va_mul_m3_series_8(
float r[3][3],
- float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3],
- float m5[3][3], float m6[3][3], float m7[3][3])
+ const float m1[3][3], const float m2[3][3], const float m3[3][3], const float m4[3][3],
+ const float m5[3][3], const float m6[3][3], const float m7[3][3])
{
mul_m3_m3m3(r, m1, m2);
mul_m3_m3m3(r, r, m3);
@@ -350,8 +417,8 @@ void _va_mul_m3_series_8(
}
void _va_mul_m3_series_9(
float r[3][3],
- float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3],
- float m5[3][3], float m6[3][3], float m7[3][3], float m8[3][3])
+ const float m1[3][3], const float m2[3][3], const float m3[3][3], const float m4[3][3],
+ const float m5[3][3], const float m6[3][3], const float m7[3][3], const float m8[3][3])
{
mul_m3_m3m3(r, m1, m2);
mul_m3_m3m3(r, r, m3);
@@ -367,20 +434,20 @@ void _va_mul_m3_series_9(
* \{ */
void _va_mul_m4_series_3(
float r[4][4],
- float m1[4][4], float m2[4][4])
+ const float m1[4][4], const float m2[4][4])
{
mul_m4_m4m4(r, m1, m2);
}
void _va_mul_m4_series_4(
float r[4][4],
- float m1[4][4], float m2[4][4], float m3[4][4])
+ const float m1[4][4], const float m2[4][4], const float m3[4][4])
{
mul_m4_m4m4(r, m1, m2);
mul_m4_m4m4(r, r, m3);
}
void _va_mul_m4_series_5(
float r[4][4],
- float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4])
+ const float m1[4][4], const float m2[4][4], const float m3[4][4], const float m4[4][4])
{
mul_m4_m4m4(r, m1, m2);
mul_m4_m4m4(r, r, m3);
@@ -388,8 +455,8 @@ void _va_mul_m4_series_5(
}
void _va_mul_m4_series_6(
float r[4][4],
- float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4],
- float m5[4][4])
+ const float m1[4][4], const float m2[4][4], const float m3[4][4], const float m4[4][4],
+ const float m5[4][4])
{
mul_m4_m4m4(r, m1, m2);
mul_m4_m4m4(r, r, m3);
@@ -398,8 +465,8 @@ void _va_mul_m4_series_6(
}
void _va_mul_m4_series_7(
float r[4][4],
- float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4],
- float m5[4][4], float m6[4][4])
+ const float m1[4][4], const float m2[4][4], const float m3[4][4], const float m4[4][4],
+ const float m5[4][4], const float m6[4][4])
{
mul_m4_m4m4(r, m1, m2);
mul_m4_m4m4(r, r, m3);
@@ -409,8 +476,8 @@ void _va_mul_m4_series_7(
}
void _va_mul_m4_series_8(
float r[4][4],
- float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4],
- float m5[4][4], float m6[4][4], float m7[4][4])
+ const float m1[4][4], const float m2[4][4], const float m3[4][4], const float m4[4][4],
+ const float m5[4][4], const float m6[4][4], const float m7[4][4])
{
mul_m4_m4m4(r, m1, m2);
mul_m4_m4m4(r, r, m3);
@@ -421,8 +488,8 @@ void _va_mul_m4_series_8(
}
void _va_mul_m4_series_9(
float r[4][4],
- float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4],
- float m5[4][4], float m6[4][4], float m7[4][4], float m8[4][4])
+ const float m1[4][4], const float m2[4][4], const float m3[4][4], const float m4[4][4],
+ const float m5[4][4], const float m6[4][4], const float m7[4][4], const float m8[4][4])
{
mul_m4_m4m4(r, m1, m2);
mul_m4_m4m4(r, r, m3);
@@ -434,7 +501,7 @@ void _va_mul_m4_series_9(
}
/** \} */
-void mul_v2_m3v2(float r[2], float m[3][3], float v[2])
+void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2])
{
float temp[3], warped[3];
@@ -447,12 +514,12 @@ void mul_v2_m3v2(float r[2], float m[3][3], float v[2])
r[1] = warped[1] / warped[2];
}
-void mul_m3_v2(float m[3][3], float r[2])
+void mul_m3_v2(const float m[3][3], float r[2])
{
mul_v2_m3v2(r, m, r);
}
-void mul_m4_v3(float mat[4][4], float vec[3])
+void mul_m4_v3(const float mat[4][4], float vec[3])
{
const float x = vec[0];
const float y = vec[1];
@@ -462,7 +529,7 @@ void mul_m4_v3(float mat[4][4], float vec[3])
vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2];
}
-void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3])
+void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
{
const float x = vec[0];
const float y = vec[1];
@@ -472,7 +539,7 @@ void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3])
r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2];
}
-void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3])
+void mul_v2_m4v3(float r[2], const float mat[4][4], const float vec[3])
{
const float x = vec[0];
@@ -480,7 +547,7 @@ void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3])
r[1] = x * mat[0][1] + vec[1] * mat[1][1] + mat[2][1] * vec[2] + mat[3][1];
}
-void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2])
+void mul_v2_m2v2(float r[2], const float mat[2][2], const float vec[2])
{
const float x = vec[0];
@@ -488,13 +555,13 @@ void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2])
r[1] = mat[0][1] * x + mat[1][1] * vec[1];
}
-void mul_m2v2(float mat[2][2], float vec[2])
+void mul_m2v2(const float mat[2][2], float vec[2])
{
mul_v2_m2v2(vec, mat, vec);
}
/* same as mul_m4_v3() but doesnt apply translation component */
-void mul_mat3_m4_v3(float mat[4][4], float vec[3])
+void mul_mat3_m4_v3(const float mat[4][4], float vec[3])
{
const float x = vec[0];
const float y = vec[1];
@@ -504,7 +571,7 @@ void mul_mat3_m4_v3(float mat[4][4], float vec[3])
vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
}
-void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3])
+void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3])
{
const float x = vec[0];
const float y = vec[1];
@@ -514,7 +581,7 @@ void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3])
r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
}
-void mul_project_m4_v3(float mat[4][4], float vec[3])
+void mul_project_m4_v3(const float mat[4][4], float vec[3])
{
/* absolute value to not flip the frustum upside down behind the camera */
const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
@@ -525,7 +592,7 @@ void mul_project_m4_v3(float mat[4][4], float vec[3])
vec[2] /= w;
}
-void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3])
+void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3])
{
const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
mul_v3_m4v3(r, mat, vec);
@@ -535,7 +602,7 @@ void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3])
r[2] /= w;
}
-void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3])
+void mul_v2_project_m4_v3(float r[2], const float mat[4][4], const float vec[3])
{
const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
mul_v2_m4v3(r, mat, vec);
@@ -544,7 +611,7 @@ void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3])
r[1] /= w;
}
-void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4])
+void mul_v4_m4v4(float r[4], const float mat[4][4], const float v[4])
{
const float x = v[0];
const float y = v[1];
@@ -556,12 +623,12 @@ void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4])
r[3] = x * mat[0][3] + y * mat[1][3] + z * mat[2][3] + mat[3][3] * v[3];
}
-void mul_m4_v4(float mat[4][4], float r[4])
+void mul_m4_v4(const float mat[4][4], float r[4])
{
mul_v4_m4v4(r, mat, r);
}
-void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4])
+void mul_v4d_m4v4d(double r[4], const float mat[4][4], const double v[4])
{
const double x = v[0];
const double y = v[1];
@@ -573,12 +640,21 @@ void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4])
r[3] = x * (double)mat[0][3] + y * (double)mat[1][3] + z * (double)mat[2][3] + (double)mat[3][3] * v[3];
}
-void mul_m4_v4d(float mat[4][4], double r[4])
+void mul_m4_v4d(const float mat[4][4], double r[4])
{
mul_v4d_m4v4d(r, mat, r);
}
-void mul_v3_m3v3(float r[3], float M[3][3], const float a[3])
+void mul_v4_m4v3(float r[4], const float M[4][4], const float v[3])
+{
+ /* v has implicit w = 1.0f */
+ r[0] = v[0] * M[0][0] + v[1] * M[1][0] + M[2][0] * v[2] + M[3][0];
+ r[1] = v[0] * M[0][1] + v[1] * M[1][1] + M[2][1] * v[2] + M[3][1];
+ r[2] = v[0] * M[0][2] + v[1] * M[1][2] + M[2][2] * v[2] + M[3][2];
+ r[3] = v[0] * M[0][3] + v[1] * M[1][3] + M[2][3] * v[2] + M[3][3];
+}
+
+void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
{
BLI_assert(r != a);
@@ -587,7 +663,7 @@ void mul_v3_m3v3(float r[3], float M[3][3], const float a[3])
r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
-void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3])
+void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3])
{
BLI_assert(r != a);
@@ -596,7 +672,7 @@ void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3])
r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
-void mul_v2_m3v3(float r[2], float M[3][3], const float a[3])
+void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
{
BLI_assert(r != a);
@@ -604,17 +680,17 @@ void mul_v2_m3v3(float r[2], float M[3][3], const float a[3])
r[1] = M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2];
}
-void mul_m3_v3(float M[3][3], float r[3])
+void mul_m3_v3(const float M[3][3], float r[3])
{
mul_v3_m3v3(r, M, (const float[3]){UNPACK3(r)});
}
-void mul_m3_v3_db(double M[3][3], double r[3])
+void mul_m3_v3_db(const double M[3][3], double r[3])
{
mul_v3_m3v3_db(r, M, (const double[3]){UNPACK3(r)});
}
-void mul_transposed_m3_v3(float mat[3][3], float vec[3])
+void mul_transposed_m3_v3(const float mat[3][3], float vec[3])
{
const float x = vec[0];
const float y = vec[1];
@@ -624,7 +700,7 @@ void mul_transposed_m3_v3(float mat[3][3], float vec[3])
vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2];
}
-void mul_transposed_mat3_m4_v3(float mat[4][4], float vec[3])
+void mul_transposed_mat3_m4_v3(const float mat[4][4], float vec[3])
{
const float x = vec[0];
const float y = vec[1];
@@ -688,7 +764,7 @@ void negate_m4(float m[4][4])
m[i][j] *= -1.0f;
}
-void mul_m3_v3_double(float mat[3][3], double vec[3])
+void mul_m3_v3_double(const float mat[3][3], double vec[3])
{
const double x = vec[0];
const double y = vec[1];
@@ -698,7 +774,7 @@ void mul_m3_v3_double(float mat[3][3], double vec[3])
vec[2] = x * (double)mat[0][2] + y * (double)mat[1][2] + (double)mat[2][2] * vec[2];
}
-void add_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3])
+void add_m3_m3m3(float m1[3][3], const float m2[3][3], const float m3[3][3])
{
int i, j;
@@ -707,7 +783,7 @@ void add_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3])
m1[i][j] = m2[i][j] + m3[i][j];
}
-void add_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4])
+void add_m4_m4m4(float m1[4][4], const float m2[4][4], const float m3[4][4])
{
int i, j;
@@ -716,7 +792,7 @@ void add_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4])
m1[i][j] = m2[i][j] + m3[i][j];
}
-void sub_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3])
+void sub_m3_m3m3(float m1[3][3], const float m2[3][3], const float m3[3][3])
{
int i, j;
@@ -725,7 +801,7 @@ void sub_m3_m3m3(float m1[3][3], float m2[3][3], float m3[3][3])
m1[i][j] = m2[i][j] - m3[i][j];
}
-void sub_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4])
+void sub_m4_m4m4(float m1[4][4], const float m2[4][4], const float m3[4][4])
{
int i, j;
@@ -734,7 +810,7 @@ void sub_m4_m4m4(float m1[4][4], float m2[4][4], float m3[4][4])
m1[i][j] = m2[i][j] - m3[i][j];
}
-float determinant_m3_array(float m[3][3])
+float determinant_m3_array(const float m[3][3])
{
return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
@@ -750,7 +826,7 @@ bool invert_m3_ex(float m[3][3], const float epsilon)
return success;
}
-bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon)
+bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon)
{
float det;
int a, b;
@@ -786,7 +862,7 @@ bool invert_m3(float m[3][3])
return success;
}
-bool invert_m3_m3(float m1[3][3], float m2[3][3])
+bool invert_m3_m3(float m1[3][3], const float m2[3][3])
{
float det;
int a, b;
@@ -821,73 +897,11 @@ bool invert_m4(float m[4][4])
return success;
}
-/*
- * Computes the inverse of mat and puts it in inverse.
- * Returns true on success (i.e. can always find a pivot) and false on failure.
- * Uses Gaussian Elimination with partial (maximal column) pivoting.
- *
- * Mark Segal - 1992
- */
-
-bool invert_m4_m4(float inverse[4][4], float mat[4][4])
+bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
{
- int i, j, k;
- double temp;
- float tempmat[4][4];
- float max;
- int maxj;
-
- BLI_assert(inverse != mat);
-
- /* Set inverse to identity */
- for (i = 0; i < 4; i++)
- for (j = 0; j < 4; j++)
- inverse[i][j] = 0;
- for (i = 0; i < 4; i++)
- inverse[i][i] = 1;
-
- /* Copy original matrix so we don't mess it up */
- for (i = 0; i < 4; i++)
- for (j = 0; j < 4; j++)
- tempmat[i][j] = mat[i][j];
-
- for (i = 0; i < 4; i++) {
- /* Look for row with max pivot */
- max = fabsf(tempmat[i][i]);
- maxj = i;
- for (j = i + 1; j < 4; j++) {
- if (fabsf(tempmat[j][i]) > max) {
- max = fabsf(tempmat[j][i]);
- maxj = j;
- }
- }
- /* Swap rows if necessary */
- if (maxj != i) {
- for (k = 0; k < 4; k++) {
- SWAP(float, tempmat[i][k], tempmat[maxj][k]);
- SWAP(float, inverse[i][k], inverse[maxj][k]);
- }
- }
-
- if (UNLIKELY(tempmat[i][i] == 0.0f)) {
- return false; /* No non-zero pivot */
- }
- temp = (double)tempmat[i][i];
- for (k = 0; k < 4; k++) {
- tempmat[i][k] = (float)((double)tempmat[i][k] / temp);
- inverse[i][k] = (float)((double)inverse[i][k] / temp);
- }
- for (j = 0; j < 4; j++) {
- if (j != i) {
- temp = tempmat[j][i];
- for (k = 0; k < 4; k++) {
- tempmat[j][k] -= (float)((double)tempmat[i][k] * temp);
- inverse[j][k] -= (float)((double)inverse[i][k] * temp);
- }
- }
- }
- }
- return true;
+ /* Use optimized matrix inverse from Eigen, since performance
+ * impact of this function is significant in complex rigs. */
+ return EIG_invert_m4_m4(inverse, mat);
}
/****************************** Linear Algebra *******************************/
@@ -907,7 +921,7 @@ void transpose_m3(float mat[3][3])
mat[2][1] = t;
}
-void transpose_m3_m3(float rmat[3][3], float mat[3][3])
+void transpose_m3_m3(float rmat[3][3], const float mat[3][3])
{
BLI_assert(rmat != mat);
@@ -923,7 +937,7 @@ void transpose_m3_m3(float rmat[3][3], float mat[3][3])
}
/* seems obscure but in-fact a common operation */
-void transpose_m3_m4(float rmat[3][3], float mat[4][4])
+void transpose_m3_m4(float rmat[3][3], const float mat[4][4])
{
BLI_assert(&rmat[0][0] != &mat[0][0]);
@@ -964,7 +978,7 @@ void transpose_m4(float mat[4][4])
mat[3][2] = t;
}
-void transpose_m4_m4(float rmat[4][4], float mat[4][4])
+void transpose_m4_m4(float rmat[4][4], const float mat[4][4])
{
BLI_assert(rmat != mat);
@@ -986,7 +1000,8 @@ void transpose_m4_m4(float rmat[4][4], float mat[4][4])
rmat[3][3] = mat[3][3];
}
-int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit)
+/* TODO: return bool */
+int compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit)
{
if (compare_v4v4(mat1[0], mat2[0], limit))
if (compare_v4v4(mat1[1], mat2[1], limit))
@@ -996,6 +1011,11 @@ int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit)
return 0;
}
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ */
void orthogonalize_m3(float mat[3][3], int axis)
{
float size[3];
@@ -1080,6 +1100,11 @@ void orthogonalize_m3(float mat[3][3], int axis)
mul_v3_fl(mat[2], size[2]);
}
+/**
+ * Make an orthonormal matrix around the selected axis of the given matrix.
+ *
+ * \param axis: Axis to build the orthonormal basis around.
+ */
void orthogonalize_m4(float mat[4][4], int axis)
{
float size[3];
@@ -1164,7 +1189,7 @@ void orthogonalize_m4(float mat[4][4], int axis)
mul_v3_fl(mat[2], size[2]);
}
-bool is_orthogonal_m3(float m[3][3])
+bool is_orthogonal_m3(const float m[3][3])
{
int i, j;
@@ -1178,7 +1203,7 @@ bool is_orthogonal_m3(float m[3][3])
return true;
}
-bool is_orthogonal_m4(float m[4][4])
+bool is_orthogonal_m4(const float m[4][4])
{
int i, j;
@@ -1193,7 +1218,7 @@ bool is_orthogonal_m4(float m[4][4])
return true;
}
-bool is_orthonormal_m3(float m[3][3])
+bool is_orthonormal_m3(const float m[3][3])
{
if (is_orthogonal_m3(m)) {
int i;
@@ -1208,7 +1233,7 @@ bool is_orthonormal_m3(float m[3][3])
return false;
}
-bool is_orthonormal_m4(float m[4][4])
+bool is_orthonormal_m4(const float m[4][4])
{
if (is_orthogonal_m4(m)) {
int i;
@@ -1223,7 +1248,7 @@ bool is_orthonormal_m4(float m[4][4])
return false;
}
-bool is_uniform_scaled_m3(float m[3][3])
+bool is_uniform_scaled_m3(const float m[3][3])
{
const float eps = 1e-7f;
float t[3][3];
@@ -1251,7 +1276,7 @@ bool is_uniform_scaled_m3(float m[3][3])
return false;
}
-bool is_uniform_scaled_m4(float m[4][4])
+bool is_uniform_scaled_m4(const float m[4][4])
{
float t[3][3];
copy_m3_m4(t, m);
@@ -1273,14 +1298,14 @@ void normalize_m3(float mat[3][3])
}
}
-void normalize_m3_m3_ex(float rmat[3][3], float mat[3][3], float r_scale[3])
+void normalize_m3_m3_ex(float rmat[3][3], const float mat[3][3], float r_scale[3])
{
int i;
for (i = 0; i < 3; i++) {
r_scale[i] = normalize_v3_v3(rmat[i], mat[i]);
}
}
-void normalize_m3_m3(float rmat[3][3], float mat[3][3])
+void normalize_m3_m3(float rmat[3][3], const float mat[3][3])
{
int i;
for (i = 0; i < 3; i++) {
@@ -1309,7 +1334,7 @@ void normalize_m4(float mat[4][4])
}
}
-void normalize_m4_m4_ex(float rmat[4][4], float mat[4][4], float r_scale[3])
+void normalize_m4_m4_ex(float rmat[4][4], const float mat[4][4], float r_scale[3])
{
int i;
for (i = 0; i < 3; i++) {
@@ -1318,7 +1343,7 @@ void normalize_m4_m4_ex(float rmat[4][4], float mat[4][4], float r_scale[3])
}
copy_v4_v4(rmat[3], mat[3]);
}
-void normalize_m4_m4(float rmat[4][4], float mat[4][4])
+void normalize_m4_m4(float rmat[4][4], const float mat[4][4])
{
int i;
for (i = 0; i < 3; i++) {
@@ -1328,7 +1353,7 @@ void normalize_m4_m4(float rmat[4][4], float mat[4][4])
copy_v4_v4(rmat[3], mat[3]);
}
-void adjoint_m2_m2(float m1[2][2], float m[2][2])
+void adjoint_m2_m2(float m1[2][2], const float m[2][2])
{
BLI_assert(m1 != m);
m1[0][0] = m[1][1];
@@ -1337,7 +1362,7 @@ void adjoint_m2_m2(float m1[2][2], float m[2][2])
m1[1][1] = m[0][0];
}
-void adjoint_m3_m3(float m1[3][3], float m[3][3])
+void adjoint_m3_m3(float m1[3][3], const float m[3][3])
{
BLI_assert(m1 != m);
m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1];
@@ -1353,7 +1378,7 @@ void adjoint_m3_m3(float m1[3][3], float m[3][3])
m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0];
}
-void adjoint_m4_m4(float out[4][4], float in[4][4]) /* out = ADJ(in) */
+void adjoint_m4_m4(float out[4][4], const float in[4][4]) /* out = ADJ(in) */
{
float a1, a2, a3, a4, b1, b2, b3, b4;
float c1, c2, c3, c4, d1, d2, d3, d4;
@@ -1419,7 +1444,7 @@ float determinant_m3(float a1, float a2, float a3,
return ans;
}
-float determinant_m4(float m[4][4])
+float determinant_m4(const float m[4][4])
{
float ans;
float a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;
@@ -1487,14 +1512,14 @@ void size_to_mat4(float mat[4][4], const float size[3])
mat[3][3] = 1.0f;
}
-void mat3_to_size(float size[3], float mat[3][3])
+void mat3_to_size(float size[3], const float mat[3][3])
{
size[0] = len_v3(mat[0]);
size[1] = len_v3(mat[1]);
size[2] = len_v3(mat[2]);
}
-void mat4_to_size(float size[3], float mat[4][4])
+void mat4_to_size(float size[3], const float mat[4][4])
{
size[0] = len_v3(mat[0]);
size[1] = len_v3(mat[1]);
@@ -1504,7 +1529,7 @@ void mat4_to_size(float size[3], float mat[4][4])
/* this gets the average scale of a matrix, only use when your scaling
* data that has no idea of scale axis, examples are bone-envelope-radius
* and curve radius */
-float mat3_to_scale(float mat[3][3])
+float mat3_to_scale(const float mat[3][3])
{
/* unit length vector */
float unit_vec[3];
@@ -1513,7 +1538,7 @@ float mat3_to_scale(float mat[3][3])
return len_v3(unit_vec);
}
-float mat4_to_scale(float mat[4][4])
+float mat4_to_scale(const float mat[4][4])
{
/* unit length vector */
float unit_vec[3];
@@ -1523,7 +1548,7 @@ float mat4_to_scale(float mat[4][4])
}
/** Return 2D scale (in XY plane) of given mat4. */
-float mat4_to_xy_scale(float M[4][4])
+float mat4_to_xy_scale(const float M[4][4])
{
/* unit length vector in xy plane */
float unit_vec[3] = {(float)M_SQRT1_2, (float)M_SQRT1_2, 0.0f};
@@ -1531,7 +1556,7 @@ float mat4_to_xy_scale(float M[4][4])
return len_v3(unit_vec);
}
-void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3])
+void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3])
{
/* keep rot as a 3x3 matrix, the caller can convert into a quat or euler */
size[0] = normalize_v3_v3(rot[0], mat3[0]);
@@ -1543,7 +1568,7 @@ void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3])
}
}
-void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wmat[4][4])
+void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
{
float mat3[3][3]; /* wmat -> 3x3 */
@@ -1554,7 +1579,7 @@ void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wm
copy_v3_v3(loc, wmat[3]);
}
-void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4])
+void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4])
{
float mat3[3][3];
float mat3_n[3][3]; /* normalized mat3 */
@@ -1572,7 +1597,7 @@ void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4])
copy_v3_v3(loc, wmat[3]);
}
-void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4])
+void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4])
{
float rot[3][3];
mat4_to_loc_rot_size(loc, rot, size, wmat);
@@ -1589,7 +1614,7 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4]
* See https://en.wikipedia.org/wiki/Polar_decomposition for more.
*/
#ifndef MATH_STANDALONE
-void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3])
+void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3])
{
/* From svd decomposition (M = WSV*), we have:
* U = WV*
@@ -1700,7 +1725,7 @@ void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
mul_m4_m4m4(mat, mat, tmat);
}
-void blend_m3_m3m3(float out[3][3], float dst[3][3], float src[3][3], const float srcweight)
+void blend_m3_m3m3(float out[3][3], const float dst[3][3], const float src[3][3], const float srcweight)
{
float srot[3][3], drot[3][3];
float squat[4], dquat[4], fquat[4];
@@ -1723,7 +1748,7 @@ void blend_m3_m3m3(float out[3][3], float dst[3][3], float src[3][3], const floa
mul_m3_m3m3(out, rmat, smat);
}
-void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const float srcweight)
+void blend_m4_m4m4(float out[4][4], const float dst[4][4], const float src[4][4], const float srcweight)
{
float sloc[3], dloc[3], floc[3];
float srot[3][3], drot[3][3];
@@ -1761,7 +1786,7 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa
* \param B: Input matrix which is totally effective with `t = 1.0`.
* \param t: Interpolation factor.
*/
-void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t)
+void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t)
{
/* 'Rotation' component ('U' part of polar decomposition, the closest orthogonal matrix to M3 rot/scale
* transformation matrix), spherically interpolated. */
@@ -1796,7 +1821,7 @@ void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t)
* \param B: Input matrix which is totally effective with `t = 1.0`.
* \param t: Interpolation factor.
*/
-void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t)
+void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t)
{
float A3[3][3], B3[3][3], R3[3][3];
@@ -1817,27 +1842,27 @@ void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t)
}
#endif /* MATH_STANDALONE */
-bool is_negative_m3(float mat[3][3])
+bool is_negative_m3(const float mat[3][3])
{
float vec[3];
cross_v3_v3v3(vec, mat[0], mat[1]);
return (dot_v3v3(vec, mat[2]) < 0.0f);
}
-bool is_negative_m4(float mat[4][4])
+bool is_negative_m4(const float mat[4][4])
{
float vec[3];
cross_v3_v3v3(vec, mat[0], mat[1]);
return (dot_v3v3(vec, mat[2]) < 0.0f);
}
-bool is_zero_m3(float mat[3][3])
+bool is_zero_m3(const float mat[3][3])
{
return (is_zero_v3(mat[0]) &&
is_zero_v3(mat[1]) &&
is_zero_v3(mat[2]));
}
-bool is_zero_m4(float mat[4][4])
+bool is_zero_m4(const float mat[4][4])
{
return (is_zero_v4(mat[0]) &&
is_zero_v4(mat[1]) &&
@@ -1845,14 +1870,14 @@ bool is_zero_m4(float mat[4][4])
is_zero_v4(mat[3]));
}
-bool equals_m3m3(float mat1[3][3], float mat2[3][3])
+bool equals_m3m3(const float mat1[3][3], const float mat2[3][3])
{
return (equals_v3v3(mat1[0], mat2[0]) &&
equals_v3v3(mat1[1], mat2[1]) &&
equals_v3v3(mat1[2], mat2[2]));
}
-bool equals_m4m4(float mat1[4][4], float mat2[4][4])
+bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
{
return (equals_v4v4(mat1[0], mat2[0]) &&
equals_v4v4(mat1[1], mat2[1]) &&
@@ -1943,7 +1968,7 @@ void loc_axisangle_size_to_mat4(float mat[4][4], const float loc[3], const float
/*********************************** Other ***********************************/
-void print_m3(const char *str, float m[3][3])
+void print_m3(const char *str, const float m[3][3])
{
printf("%s\n", str);
printf("%f %f %f\n", m[0][0], m[1][0], m[2][0]);
@@ -1952,7 +1977,7 @@ void print_m3(const char *str, float m[3][3])
printf("\n");
}
-void print_m4(const char *str, float m[4][4])
+void print_m4(const char *str, const float m[4][4])
{
printf("%s\n", str);
printf("%f %f %f %f\n", m[0][0], m[1][0], m[2][0], m[3][0]);
@@ -2406,7 +2431,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
}
}
-void pseudoinverse_m4_m4(float Ainv[4][4], float A_[4][4], float epsilon)
+void pseudoinverse_m4_m4(float Ainv[4][4], const float A_[4][4], float epsilon)
{
/* compute Moore-Penrose pseudo inverse of matrix, singular values
* below epsilon are ignored for stability (truncated SVD) */
@@ -2427,7 +2452,7 @@ void pseudoinverse_m4_m4(float Ainv[4][4], float A_[4][4], float epsilon)
mul_m4_series(Ainv, U, Wm, V);
}
-void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon)
+void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon)
{
/* try regular inverse when possible, otherwise fall back to slow svd */
if (!invert_m3_m3(Ainv, A)) {
@@ -2439,14 +2464,14 @@ void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon)
}
}
-bool has_zero_axis_m4(float matrix[4][4])
+bool has_zero_axis_m4(const float matrix[4][4])
{
return len_squared_v3(matrix[0]) < FLT_EPSILON ||
len_squared_v3(matrix[1]) < FLT_EPSILON ||
len_squared_v3(matrix[2]) < FLT_EPSILON;
}
-void invert_m4_m4_safe(float Ainv[4][4], float A[4][4])
+void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4])
{
if (!invert_m4_m4(Ainv, A)) {
float Atemp[4][4];
@@ -2494,7 +2519,7 @@ void invert_m4_m4_safe(float Ainv[4][4], float A[4][4])
* this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z)
* where (x', y', z') are the coordinates of P' in target space such that it keeps (X, Y, Z) coordinates in global space.
*/
-void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4])
+void BLI_space_transform_from_matrices(SpaceTransform *data, const float local[4][4], const float target[4][4])
{
float itarget[4][4];
invert_m4_m4(itarget, target);
@@ -2512,7 +2537,7 @@ void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4],
* this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z)
* where (X', Y', Z') are the coordinates of p' in global space such that it keeps (x, y, z) coordinates in target space.
*/
-void BLI_space_transform_global_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4])
+void BLI_space_transform_global_from_matrices(SpaceTransform *data, const float local[4][4], const float target[4][4])
{
float ilocal[4][4];
invert_m4_m4(ilocal, local);
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index f0c830d33c6..19aff2caa5d 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -1872,19 +1872,24 @@ void dquat_to_mat4(float mat[4][4], const DualQuat *dq)
/* normalize */
len = sqrtf(dot_qtqt(q0, q0));
- if (len != 0.0f)
- mul_qt_fl(q0, 1.0f / len);
+ if (len != 0.0f) {
+ len = 1.0f / len;
+ }
+ mul_qt_fl(q0, len);
/* rotation */
quat_to_mat4(mat, q0);
/* translation */
t = dq->trans;
- mat[3][0] = 2.0f * (-t[0] * q0[1] + t[1] * q0[0] - t[2] * q0[3] + t[3] * q0[2]);
- mat[3][1] = 2.0f * (-t[0] * q0[2] + t[1] * q0[3] + t[2] * q0[0] - t[3] * q0[1]);
- mat[3][2] = 2.0f * (-t[0] * q0[3] - t[1] * q0[2] + t[2] * q0[1] + t[3] * q0[0]);
+ mat[3][0] = 2.0f * (-t[0] * q0[1] + t[1] * q0[0] - t[2] * q0[3] + t[3] * q0[2]) * len;
+ mat[3][1] = 2.0f * (-t[0] * q0[2] + t[1] * q0[3] + t[2] * q0[0] - t[3] * q0[1]) * len;
+ mat[3][2] = 2.0f * (-t[0] * q0[3] - t[1] * q0[2] + t[2] * q0[1] + t[3] * q0[0]) * len;
- /* note: this does not handle scaling */
+ /* scaling */
+ if (dq->scale_weight) {
+ mul_m4_m4m4(mat, mat, dq->scale);
+ }
}
void add_weighted_dq_dq(DualQuat *dqsum, const DualQuat *dq, float weight)
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index e3174d8340a..7b9727ead8e 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -179,3 +179,98 @@ bool BLI_tridiagonal_solve_cyclic(const float *a, const float *b, const float *c
return success;
}
+
+/**
+ * \brief Solve a generic f(x) = 0 equation using Newton's method.
+ *
+ * \param func_delta Callback computing the value of f(x).
+ * \param func_jacobian Callback computing the Jacobian matrix of the function at x.
+ * \param func_correction Callback for forcing the search into an arbitrary custom domain. May be NULL.
+ * \param userdata Data for the callbacks.
+ * \param epsilon Desired precision.
+ * \param max_iterations Limit on the iterations.
+ * \param max_corrections Limit on the number of times the correction callback can fire before giving up.
+ * \param trace Enables logging to console.
+ * \param x_init Initial solution vector.
+ * \param result Final result.
+ * \return true if success
+ */
+bool BLI_newton3d_solve(
+ Newton3D_DeltaFunc func_delta, Newton3D_JacobianFunc func_jacobian, Newton3D_CorrectionFunc func_correction, void *userdata,
+ float epsilon, int max_iterations, bool trace, const float x_init[3], float result[3])
+{
+ float fdelta[3], fdeltav, next_fdeltav;
+ float jacobian[3][3], step[3], x[3], x_next[3];
+
+ epsilon *= epsilon;
+
+ copy_v3_v3(x, x_init);
+
+ func_delta(userdata, x, fdelta);
+ fdeltav = len_squared_v3(fdelta);
+
+ if (trace) {
+ printf("START (%g, %g, %g) %g\n", x[0], x[1], x[2], fdeltav);
+ }
+
+ for (int i = 0; i < max_iterations && fdeltav > epsilon; i++) {
+ /* Newton's method step. */
+ func_jacobian(userdata, x, jacobian);
+
+ if (!invert_m3(jacobian)) {
+ return false;
+ }
+
+ mul_v3_m3v3(step, jacobian, fdelta);
+ sub_v3_v3v3(x_next, x, step);
+
+ /* Custom out-of-bounds value correction. */
+ if (func_correction) {
+ if (trace) {
+ printf("%3d * (%g, %g, %g)\n", i, x_next[0], x_next[1], x_next[2]);
+ }
+
+ if (!func_correction(userdata, x, step, x_next)) {
+ return false;
+ }
+ }
+
+ func_delta(userdata, x_next, fdelta);
+ next_fdeltav = len_squared_v3(fdelta);
+
+ if (trace) {
+ printf("%3d ? (%g, %g, %g) %g\n", i, x_next[0], x_next[1], x_next[2], next_fdeltav);
+ }
+
+ /* Line search correction. */
+ while (next_fdeltav > fdeltav) {
+ float g0 = sqrtf(fdeltav), g1 = sqrtf(next_fdeltav);
+ float g01 = -g0 / len_v3(step);
+ float det = 2.0f * (g1 - g0 - g01);
+ float l = (det == 0.0f) ? 0.1f : -g01 / det;
+ CLAMP_MIN(l, 0.1f);
+
+ mul_v3_fl(step, l);
+ sub_v3_v3v3(x_next, x, step);
+
+ func_delta(userdata, x_next, fdelta);
+ next_fdeltav = len_squared_v3(fdelta);
+
+ if (trace) {
+ printf("%3d . (%g, %g, %g) %g\n", i, x_next[0], x_next[1], x_next[2], next_fdeltav);
+ }
+ }
+
+ copy_v3_v3(x, x_next);
+ fdeltav = next_fdeltav;
+ }
+
+ bool success = (fdeltav <= epsilon);
+
+ if (trace) {
+ printf("%s (%g, %g, %g) %g\n", success ? "OK " : "FAIL", x[0], x[1], x[2], fdeltav);
+ }
+
+ copy_v3_v3(result, x);
+ return success;
+}
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 37eab44c6e8..fc3f11fd1be 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -192,6 +192,19 @@ MINLINE void copy_v4_v4_int(int r[4], const int a[4])
r[3] = a[3];
}
+/* int <-> float */
+MINLINE void round_v2i_v2fl(int r[2], const float a[2])
+{
+ r[0] = (int)roundf(a[0]);
+ r[1] = (int)roundf(a[1]);
+}
+
+MINLINE void copy_v2fl_v2i(float r[2], const int a[2])
+{
+ r[0] = (float)a[0];
+ r[1] = (float)a[1];
+}
+
/* double -> float */
MINLINE void copy_v2fl_v2db(float r[2], const double a[2])
{
@@ -446,6 +459,14 @@ MINLINE void mul_v4_fl(float r[4], float f)
r[3] *= f;
}
+MINLINE void mul_v4_v4(float r[4], const float a[4])
+{
+ r[0] *= a[0];
+ r[1] *= a[1];
+ r[2] *= a[2];
+ r[3] *= a[3];
+}
+
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f)
{
r[0] = a[0] * f;
@@ -491,7 +512,7 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2])
* return co_4d[3];
* \endcode
*/
-MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3])
+MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3])
{
return (mat[0][3] * co[0]) +
(mat[1][3] * co[1]) +
@@ -501,15 +522,15 @@ MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3])
/**
* Has the effect of #mul_m3_v3(), on a single axis.
*/
-MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3])
+MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3])
{
return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
}
-MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3])
+MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3])
{
return M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2];
}
-MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3])
+MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3])
{
return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
@@ -518,15 +539,15 @@ MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3])
* Has the effect of #mul_mat3_m4_v3(), on a single axis.
* (no adding translation)
*/
-MINLINE float dot_m4_v3_row_x(float M[4][4], const float a[3])
+MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3])
{
return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2];
}
-MINLINE float dot_m4_v3_row_y(float M[4][4], const float a[3])
+MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3])
{
return M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2];
}
-MINLINE float dot_m4_v3_row_z(float M[4][4], const float a[3])
+MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3])
{
return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2];
}
@@ -594,6 +615,12 @@ MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3])
r[2] = v1[2] * v2[2];
}
+MINLINE void mul_v2_v2v2(float r[2], const float a[2], const float b[2])
+{
+ r[0] = a[0] * b[0];
+ r[1] = a[1] * b[1];
+}
+
MINLINE void negate_v2(float r[2])
{
r[0] = -r[0];
@@ -998,6 +1025,15 @@ MINLINE void normal_float_to_short_v3(short out[3], const float in[3])
out[2] = (short) (in[2] * 32767.0f);
}
+MINLINE void normal_float_to_short_v4(short out[4], const float in[4])
+{
+ out[0] = (short) (in[0] * 32767.0f);
+ out[1] = (short) (in[1] * 32767.0f);
+ out[2] = (short) (in[2] * 32767.0f);
+ out[3] = (short) (in[3] * 32767.0f);
+}
+
+
/********************************* Comparison ********************************/
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index 075ae2f5357..8ee99544ca5 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -1092,26 +1092,6 @@ static float noise3_perlin(float vec[3])
#undef SURVE
}
-#if 0
-static float turbulence_perlin(const float point[3], float lofreq, float hifreq)
-{
- float freq, t, p[3];
-
- p[0] = point[0] + 123.456;
- p[1] = point[1];
- p[2] = point[2];
-
- t = 0;
- for (freq = lofreq; freq < hifreq; freq *= 2.0) {
- t += fabsf(noise3_perlin(p)) / freq;
- p[0] *= 2.0f;
- p[1] *= 2.0f;
- p[2] *= 2.0f;
- }
- return t - 0.3; /* readjust to make mean value = 0.0 */
-}
-#endif
-
/* for use with BLI_gNoise/gTurbulence, returns signed noise */
static float orgPerlinNoise(float x, float y, float z)
{
@@ -1147,19 +1127,6 @@ float BLI_hnoisep(float noisesize, float x, float y, float z)
return noise3_perlin(vec);
}
-#if 0
-static float turbulencep(float noisesize, float x, float y, float z, int nr)
-{
- float vec[3];
-
- vec[0] = x / noisesize;
- vec[1] = y / noisesize;
- vec[2] = z / noisesize;
- nr++;
- return turbulence_perlin(vec, 1.0, (float)(1 << nr));
-}
-#endif
-
/******************/
/* VORONOI/WORLEY */
/******************/
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 84c932db1c7..a7118a583b5 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -928,6 +928,48 @@ bool BLI_path_frame_check_chars(const char *path)
}
/**
+ * Creates a display string from path to be used menus and the user interface.
+ * Like bpy.path.display_name().
+ */
+void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
+{
+ /* Strip leading underscores and spaces. */
+ int strip_offset = 0;
+ while (ELEM(name[strip_offset], '_', ' ')) {
+ strip_offset++;
+ }
+
+ BLI_strncpy(display_name, name + strip_offset, maxlen);
+
+ /* Replace underscores with spaces. */
+ BLI_str_replace_char(display_name, '_', ' ');
+
+ /* Strip extension. */
+ BLI_path_extension_replace(display_name, maxlen, "");
+
+ /* Test if string has any upper case characters. */
+ bool all_lower = true;
+ for (int i = 0; display_name[i]; i++) {
+ if (isupper(display_name[i])) {
+ all_lower = false;
+ break;
+ }
+ }
+
+ if (all_lower) {
+ /* For full lowercase string, use title case. */
+ bool prevspace = true;
+ for (int i = 0; display_name[i]; i++) {
+ if (prevspace) {
+ display_name[i] = toupper(display_name[i]);
+ }
+
+ prevspace = isspace(display_name[i]);
+ }
+ }
+}
+
+/**
* If path begins with "//", strips that and replaces it with basepath directory.
*
* \note Also converts drive-letter prefix to something more sensible
@@ -1301,16 +1343,6 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c
return; /* string is NULL, probably shouldnt happen but return anyway */
}
-
- /* we first push all slashes into unix mode, just to make sure we don't get
- * any mess with slashes later on. -jesterKing */
- /* constant strings can be passed for those parameters - don't change them - elubie */
-#if 0
- BLI_str_replace_char(relabase, '\\', '/');
- BLI_str_replace_char(dir, '\\', '/');
- BLI_str_replace_char(file, '\\', '/');
-#endif
-
/* Resolve relative references */
if (relabase && dir[0] == '/' && dir[1] == '/') {
char *lslash;
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index 23905be4ced..c85b471fb2d 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -265,27 +265,16 @@ void BLI_rng_skip(RNG *rng, int n)
/***/
-/* initialize with some non-zero seed */
-static RNG theBLI_rng = {611330372042337130};
-
-void BLI_srandom(unsigned int seed)
-{
- BLI_rng_srandom(&theBLI_rng, seed);
-}
-
-int BLI_rand(void)
+/* fill an array with random numbers */
+void BLI_array_frand(float *ar, int count, unsigned int seed)
{
- return BLI_rng_get_int(&theBLI_rng);
-}
+ RNG rng;
-float BLI_frand(void)
-{
- return BLI_rng_get_float(&theBLI_rng);
-}
+ BLI_rng_srandom(&rng, seed);
-void BLI_frand_unit_v3(float v[3])
-{
- BLI_rng_get_float_unit_v3(&theBLI_rng, v);
+ for (int i = 0; i < count; i++) {
+ ar[i] = BLI_rng_get_float(&rng);
+ }
}
float BLI_hash_frand(unsigned int seed)
@@ -386,6 +375,8 @@ void BLI_halton_1D(unsigned int prime, double offset, int n, double *r)
{
const double invprime = 1.0 / (double)prime;
+ *r = 0.0;
+
for (int s = 0; s < n; s++) {
*r = halton_ex(invprime, &offset);
}
@@ -395,6 +386,8 @@ void BLI_halton_2D(unsigned int prime[2], double offset[2], int n, double *r)
{
const double invprimes[2] = {1.0 / (double)prime[0], 1.0 / (double)prime[1]};
+ r[0] = r[1] = 0.0;
+
for (int s = 0; s < n; s++) {
for (int i = 0; i < 2; i++) {
r[i] = halton_ex(invprimes[i], &offset[i]);
@@ -406,6 +399,8 @@ void BLI_halton_3D(unsigned int prime[3], double offset[3], int n, double *r)
{
const double invprimes[3] = {1.0 / (double)prime[0], 1.0 / (double)prime[1], 1.0 / (double)prime[2]};
+ r[0] = r[1] = r[2] = 0.0;
+
for (int s = 0; s < n; s++) {
for (int i = 0; i < 3; i++) {
r[i] = halton_ex(invprimes[i], &offset[i]);
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index f1564d132e3..427a3eb1edb 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -811,38 +811,6 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const
}
#endif
-#if 0
- if (flag & BLI_SCANFILL_CALC_QUADTRI_FASTPATH) {
- const int totverts = BLI_listbase_count(&sf_ctx->fillvertbase);
-
- if (totverts == 3) {
- eve = sf_ctx->fillvertbase.first;
-
- addfillface(sf_ctx, eve, eve->next, eve->next->next);
- return 1;
- }
- else if (totverts == 4) {
- float vec1[3], vec2[3];
-
- eve = sf_ctx->fillvertbase.first;
- /* no need to check 'eve->next->next->next' is valid, already counted */
- /* use shortest diagonal for quad */
- sub_v3_v3v3(vec1, eve->co, eve->next->next->co);
- sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co);
-
- if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) {
- addfillface(sf_ctx, eve, eve->next, eve->next->next);
- addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve);
- }
- else {
- addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next);
- addfillface(sf_ctx, eve->next->next->next, eve, eve->next);
- }
- return 2;
- }
- }
-#endif
-
/* first test vertices if they are in edges */
/* including resetting of flags */
for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index 3b6ab99ae86..ef1df479f13 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -95,20 +95,6 @@ void BLI_scanfill_obj_dump(ScanFillContext *sf_ctx)
}
#endif
-#if 0
-void BLI_scanfill_view3d_dump(ScanFillContext *sf_ctx)
-{
- ScanFillEdge *eed;
-
- bl_debug_draw_quad_clear();
- bl_debug_color_set(0x0000ff);
-
- for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
- bl_debug_draw_edge_add(eed->v1->co, eed->v2->co);
- }
-}
-#endif
-
static ListBase *edge_isect_ls_ensure(GHash *isect_hash, ScanFillEdge *eed)
{
ListBase *e_ls;
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index c1696a912ba..25375278901 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
+#include <inttypes.h>
#include "MEM_guardedalloc.h"
@@ -779,6 +780,21 @@ void BLI_str_toupper_ascii(char *str, const size_t len)
}
/**
+ * Strip whitespace from end of the string.
+ */
+void BLI_str_rstrip(char *str)
+{
+ for (int i = (int)strlen(str) - 1; i > 0; i--) {
+ if (isspace(str[i])) {
+ str[i] = '\0';
+ }
+ else {
+ break;
+ }
+ }
+}
+
+/**
* Strip trailing zeros from a float, eg:
* 0.0000 -> 0.0
* 2.0010 -> 2.001
@@ -960,24 +976,13 @@ size_t BLI_str_partition_ex(
return end ? (size_t)(end - str) : strlen(str);
}
-/**
- * Format ints with decimal grouping.
- * 1000 -> 1,000
- *
- * \param dst The resulting string
- * \param num Number to format
- * \return The length of \a dst
- */
-size_t BLI_str_format_int_grouped(char dst[16], int num)
+static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_len)
{
- char src[16];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
- int num_len, commas;
-
- num_len = sprintf(src, "%d", num);
+ int commas;
if (*p_src == '-') {
*p_dst++ = *p_src++;
@@ -996,6 +1001,38 @@ size_t BLI_str_format_int_grouped(char dst[16], int num)
}
/**
+ * Format ints with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst The resulting string
+ * \param num Number to format
+ * \return The length of \a dst
+ */
+size_t BLI_str_format_int_grouped(char dst[16], int num)
+{
+ char src[16];
+ int num_len = sprintf(src, "%d", num);
+
+ return BLI_str_format_int_grouped_ex(src, dst, num_len);
+}
+
+/**
+ * Format uint64_t with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst The resulting string
+ * \param num Number to format
+ * \return The length of \a dst
+ */
+size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num)
+{
+ char src[16];
+ int num_len = sprintf(src, "%"PRIu64"", num);
+
+ return BLI_str_format_int_grouped_ex(src, dst, num_len);
+}
+
+/**
* Format a size in bytes using binary units.
* 1000 -> 1 KB
* Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index b6d704d8d82..b8b54e192b4 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -816,7 +816,7 @@ static void task_pool_push(
return;
}
}
- /* Do push to a global execution ppol, slowest possible method,
+ /* Do push to a global execution pool, slowest possible method,
* causes quite reasonable amount of threading overhead.
*/
task_scheduler_push(pool->scheduler, task, priority);
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 5a1c479f450..df8cc164869 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -39,16 +39,18 @@ extern "C" {
struct BlendThumbnail;
struct bScreen;
struct LinkNode;
+struct ListBase;
struct Main;
struct MemFile;
struct ReportList;
struct Scene;
+struct ViewLayer;
struct UserDef;
struct View3D;
struct bContext;
struct BHead;
struct FileData;
-struct BlendFileReadParams;
+struct wmWindowManager;
typedef struct BlendHandle BlendHandle;
@@ -66,12 +68,19 @@ typedef struct BlendFileData {
int globalf;
char filename[1024]; /* 1024 = FILE_MAX */
- struct bScreen *curscreen;
+ struct bScreen *curscreen; /* TODO think this isn't needed anymore? */
struct Scene *curscene;
+ struct ViewLayer *cur_view_layer; /* layer to activate in workspaces when reading without UI */
eBlenFileType type;
} BlendFileData;
+typedef struct WorkspaceConfigFileData {
+ struct Main *main; /* has to be freed when done reading file data */
+
+ struct ListBase workspaces;
+} WorkspaceConfigFileData;
+
struct BlendFileReadParams {
uint skip_flags : 2; /* eBLOReadSkip */
uint is_startup : 1;
@@ -113,6 +122,7 @@ void BLO_blendhandle_close(BlendHandle *bh);
/***/
#define BLO_GROUP_MAX 32
+#define BLO_EMBEDDED_STARTUP_BLEND "<startup.blend>"
bool BLO_has_bfile_extension(const char *str);
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name);
@@ -132,17 +142,19 @@ struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, con
struct ID *BLO_library_link_named_part_ex(
struct Main *mainl, BlendHandle **bh,
const short idcode, const char *name, const int flag,
- struct Scene *scene, struct View3D *v3d);
-void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d);
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer);
+void BLO_library_link_end(
+ struct Main *mainl, BlendHandle **bh, int flag,
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer);
void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname);
-BlendFileData *blo_read_blendafterruntime(int file, const char *name, int actualsize, struct ReportList *reports);
-
/* internal function but we need to expose it */
-void blo_lib_link_screen_restore(struct Main *newmain, struct bScreen *curscreen, struct Scene *curscene);
+void blo_lib_link_restore(
+ struct Main *newmain, struct wmWindowManager *curwm,
+ struct Scene *curscene, struct ViewLayer *cur_render_layer);
typedef void (*BLOExpandDoitCallback) (void *fdhandle, struct Main *mainvar, void *idv);
@@ -151,12 +163,18 @@ void BLO_expand_main(void *fdhandle, struct Main *mainvar);
/* Update defaults in startup.blend & userprefs.blend, without having to save and embed it */
void BLO_update_defaults_userpref_blend(void);
-void BLO_update_defaults_startup_blend(struct Main *mainvar);
+void BLO_update_defaults_startup_blend(struct Main *mainvar, const char *app_template);
+
+/* Version patch user preferences. */
+void BLO_version_defaults_userpref_blend(struct Main *mainvar, struct UserDef *userdef);
struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath);
struct Main *BLO_main_from_memfile(struct MemFile *memfile, struct Main *bmain, struct Scene **r_scene);
+/* datafiles (generated theme) */
+extern const struct bTheme U_theme_default;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h
index f6d0be6f5f0..d615514f081 100644
--- a/source/blender/blenloader/BLO_writefile.h
+++ b/source/blender/blenloader/BLO_writefile.h
@@ -44,4 +44,6 @@ extern bool BLO_write_file(
extern bool BLO_write_file_mem(
struct Main *mainvar, struct MemFile *compare, struct MemFile *current, int write_flags);
+bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports);
+
#endif
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index dd0a8543b9f..49987cb860c 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -29,11 +29,14 @@ set(INC
../blenkernel
../blenlib
../blentranslation
+ ../depsgraph
+ ../draw
../imbuf
../makesdna
../makesrna
../nodes
../render/extern/include
+ ../windowmanager
../../../intern/guardedalloc
# for writefile.c: dna_type_offsets.h
@@ -46,21 +49,22 @@ set(INC_SYS
)
set(SRC
+ ${CMAKE_SOURCE_DIR}/release/datafiles/userdef/userdef_default_theme.c
intern/blend_validate.c
intern/readblenentry.c
intern/readfile.c
- intern/runtime.c
intern/undofile.c
intern/versioning_250.c
intern/versioning_260.c
intern/versioning_270.c
+ intern/versioning_280.c
intern/versioning_defaults.c
intern/versioning_legacy.c
+ intern/versioning_userdef.c
intern/writefile.c
BLO_blend_defs.h
BLO_readfile.h
- BLO_runtime.h
BLO_undofile.h
BLO_writefile.h
intern/readfile.h
diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c
index 4fb5d0e1286..1bc503719b4 100644
--- a/source/blender/blenloader/intern/blend_validate.c
+++ b/source/blender/blenloader/intern/blend_validate.c
@@ -47,7 +47,7 @@
#include "BKE_report.h"
#include "BLO_readfile.h"
-#include "BLO_runtime.h"
+#include "BLO_writefile.h"
#include "readfile.h"
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 0d8f056e9c4..6bf0e7bf809 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -396,6 +396,9 @@ BlendFileData *BLO_read_from_memfile(
/* makes lookup of existing images in old main */
blo_make_image_pointer_map(fd, oldmain);
+ /* makes lookup of existing light caches in old main */
+ blo_make_scene_pointer_map(fd, oldmain);
+
/* makes lookup of existing video clips in old main */
blo_make_movieclip_pointer_map(fd, oldmain);
@@ -406,6 +409,9 @@ BlendFileData *BLO_read_from_memfile(
bfd = blo_read_file_internal(fd, filename);
+ /* ensures relinked light caches are not freed */
+ blo_end_scene_pointer_map(fd, oldmain);
+
/* ensures relinked images are not freed */
blo_end_image_pointer_map(fd, oldmain);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 57d4978c776..229d0d04423 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -54,25 +54,30 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
+/* Allow using DNA struct members that are marked as private for read/write.
+ * Note: Each header that uses this needs to define its own way of handling
+ * it. There's no generic implementation, direct use does nothing. */
+#define DNA_PRIVATE_READ_WRITE_ALLOW
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
-#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_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_dynamicpaint_types.h"
#include "DNA_effect_types.h"
#include "DNA_fileglobal_types.h"
#include "DNA_genfile.h"
-#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_layer_types.h"
#include "DNA_lamp_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_meta_types.h"
@@ -85,12 +90,11 @@
#include "DNA_object_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
-#include "DNA_property_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
-#include "DNA_sensor_types.h"
#include "DNA_sdna_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
@@ -99,10 +103,13 @@
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
+#include "RNA_access.h"
+
#include "MEM_guardedalloc.h"
#include "BLI_endian_switch.h"
@@ -118,38 +125,47 @@
#include "BKE_brush.h"
#include "BKE_cachefile.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
+#include "BKE_colortools.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_global.h" // for G
-#include "BKE_group.h"
-#include "BKE_library.h" // for which_libbase
-#include "BKE_library_idmap.h"
-#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
-#include "BKE_material.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_library_idmap.h"
+#include "BKE_library_override.h"
+#include "BKE_library_query.h"
#include "BKE_main.h" // for Main
+#include "BKE_material.h"
#include "BKE_mesh.h" // for ME_ defines (patching)
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_node.h" // for tree type defines
#include "BKE_object.h"
#include "BKE_ocean.h"
+#include "BKE_outliner_treehash.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
-#include "BKE_sca.h" // for init_actuator
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
-#include "BKE_outliner_treehash.h"
+#include "BKE_shader_fx.h"
#include "BKE_sound.h"
-#include "BKE_colortools.h"
+#include "BKE_workspace.h"
+
+#include "DRW_engine.h"
+
+#include "DEG_depsgraph.h"
#include "NOD_common.h"
#include "NOD_socket.h"
@@ -249,10 +265,15 @@ typedef struct OldNewMap {
/* local prototypes */
static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
static void direct_link_modifiers(FileData *fd, ListBase *lb);
-static void convert_tface_mt(FileData *fd, Main *main);
static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
+#ifdef USE_COLLECTION_COMPAT_28
+static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc);
+#endif
+static void direct_link_animdata(FileData *fd, AnimData *adt);
+static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt);
+
/* this function ensures that reports are printed,
* in the case of libraray linking errors this is important!
*
@@ -653,7 +674,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
/* Add library datablock itself to 'main' Main, since libraries are **never** linked data.
* Fixes bug where you could end with all ID_LI datablocks having the same name... */
- lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib", 0);
+ lib = BKE_libblock_alloc(mainlist->first, ID_LI, BLI_path_basename(filepath), 0);
lib->id.us = ID_FAKE_USERS(lib); /* Important, consistency with main ID reading code from read_libblock(). */
BLI_strncpy(lib->name, filepath, sizeof(lib->name));
BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath));
@@ -1013,20 +1034,6 @@ static int *read_file_thumbnail(FileData *fd)
return blend_thumb;
}
-static int fd_read_from_file(FileData *filedata, void *buffer, uint size)
-{
- int readsize = read(filedata->filedes, buffer, size);
-
- if (readsize < 0) {
- readsize = EOF;
- }
- else {
- filedata->seek += readsize;
- }
-
- return readsize;
-}
-
static int fd_read_gzip_from_file(FileData *filedata, void *buffer, uint size)
{
int readsize = gzread(filedata->gzfiledes, buffer, size);
@@ -1329,6 +1336,8 @@ void blo_freefiledata(FileData *fd)
oldnewmap_free(fd->imamap);
if (fd->movieclipmap)
oldnewmap_free(fd->movieclipmap);
+ if (fd->scenemap)
+ oldnewmap_free(fd->scenemap);
if (fd->soundmap)
oldnewmap_free(fd->soundmap);
if (fd->packedmap)
@@ -1399,6 +1408,9 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha
if (BLO_has_bfile_extension(r_dir) && BLI_is_file(r_dir)) {
break;
}
+ else if (STREQ(r_dir, BLO_EMBEDDED_STARTUP_BLEND)) {
+ break;
+ }
if (prev_slash) {
*prev_slash = c;
@@ -1516,6 +1528,13 @@ static void *newimaadr(FileData *fd, const void *adr) /* used to resto
return NULL;
}
+static void *newsceadr(FileData *fd, const void *adr) /* used to restore scene data after undo */
+{
+ if (fd->scenemap && adr)
+ return oldnewmap_lookup_and_inc(fd->scenemap, adr, true);
+ return NULL;
+}
+
static void *newmclipadr(FileData *fd, const void *adr) /* used to restore movie clip data after undo */
{
if (fd->movieclipmap && adr)
@@ -1621,6 +1640,37 @@ void blo_clear_proxy_pointers_from_lib(Main *oldmain)
}
}
+void blo_make_scene_pointer_map(FileData *fd, Main *oldmain)
+{
+ Scene *sce = oldmain->scene.first;
+
+ fd->scenemap = oldnewmap_new();
+
+ for (; sce; sce = sce->id.next) {
+ if (sce->eevee.light_cache) {
+ struct LightCache *light_cache = sce->eevee.light_cache;
+ oldnewmap_insert(fd->scenemap, light_cache, light_cache, 0);
+ }
+ }
+}
+
+void blo_end_scene_pointer_map(FileData *fd, Main *oldmain)
+{
+ OldNew *entry = fd->scenemap->entries;
+ Scene *sce = oldmain->scene.first;
+ int i;
+
+ /* used entries were restored, so we put them to zero */
+ for (i = 0; i < fd->scenemap->nentries; i++, entry++) {
+ if (entry->nr > 0)
+ entry->newp = NULL;
+ }
+
+ for (; sce; sce = sce->id.next) {
+ sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache);
+ }
+}
+
void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
{
Image *ima = oldmain->image.first;
@@ -1630,16 +1680,22 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
fd->imamap = oldnewmap_new();
for (; ima; ima = ima->id.next) {
- if (ima->cache)
+ if (ima->cache) {
oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0);
- for (a = 0; a < TEXTARGET_COUNT; a++)
- if (ima->gputexture[a])
+ }
+ for (a = 0; a < TEXTARGET_COUNT; a++) {
+ if (ima->gputexture[a]) {
oldnewmap_insert(fd->imamap, ima->gputexture[a], ima->gputexture[a], 0);
- if (ima->rr)
+ }
+ }
+ if (ima->rr) {
oldnewmap_insert(fd->imamap, ima->rr, ima->rr, 0);
- for (a = 0; a < IMA_MAX_RENDER_SLOT; a++)
- if (ima->renders[a])
- oldnewmap_insert(fd->imamap, ima->renders[a], ima->renders[a], 0);
+ }
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) {
+ if (slot->render) {
+ oldnewmap_insert(fd->imamap, slot->render, slot->render, 0);
+ }
+ }
}
for (; sce; sce = sce->id.next) {
if (sce->nodetree && sce->nodetree->previews) {
@@ -1672,13 +1728,13 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
if (ima->cache == NULL) {
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
for (i = 0; i < TEXTARGET_COUNT; i++) {
- ima->bindcode[i] = 0;
ima->gputexture[i] = NULL;
}
ima->rr = NULL;
}
- for (i = 0; i < IMA_MAX_RENDER_SLOT; i++)
- ima->renders[i] = newimaadr(fd, ima->renders[i]);
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) {
+ slot->render = newimaadr(fd, slot->render);
+ }
for (i = 0; i < TEXTARGET_COUNT; i++)
ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]);
@@ -2237,6 +2293,42 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p
/* ************ READ ID *************** */
+static void lib_link_id(FileData *fd, Main *main)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(main, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (id->override_static) {
+ id->override_static->reference = newlibadr_us(fd, id->lib, id->override_static->reference);
+ id->override_static->storage = newlibadr_us(fd, id->lib, id->override_static->storage);
+ }
+ }
+ }
+}
+
+static void direct_link_id_override_property_operation_cb(FileData *fd, void *data)
+{
+ IDOverrideStaticPropertyOperation *opop = data;
+
+ opop->subitem_reference_name = newdataadr(fd, opop->subitem_reference_name);
+ opop->subitem_local_name = newdataadr(fd, opop->subitem_local_name);
+}
+
+static void direct_link_id_override_property_cb(FileData *fd, void *data)
+{
+ IDOverrideStaticProperty *op = data;
+
+ op->rna_path = newdataadr(fd, op->rna_path);
+ link_list_ex(fd, &op->operations, direct_link_id_override_property_operation_cb);
+}
+
static void direct_link_id(FileData *fd, ID *id)
{
/*link direct data of ID properties*/
@@ -2250,6 +2342,17 @@ static void direct_link_id(FileData *fd, ID *id)
/* That way datablock reading not going through main read_libblock() function are still in a clear tag state.
* (glowering at certain nodetree fake datablock here...). */
id->tag = 0;
+
+ /* Link direct data of overrides. */
+ if (id->override_static) {
+ id->override_static = newdataadr(fd, id->override_static);
+ link_list_ex(fd, &id->override_static->properties, direct_link_id_override_property_cb);
+ }
+
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+ if (drawdata) {
+ BLI_listbase_clear((ListBase *)drawdata);
+ }
}
/* ************ READ CurveMapping *************** */
@@ -2270,6 +2373,7 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
}
/* ************ READ Brush *************** */
+
/* library brush linking after fileread */
static void lib_link_brush(FileData *fd, Main *main)
{
@@ -2285,6 +2389,11 @@ static void lib_link_brush(FileData *fd, Main *main)
brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush);
brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
+ /* link default grease pencil palette */
+ if (brush->gpencil_settings != NULL) {
+ brush->gpencil_settings->material = newlibadr_us(fd, brush->id.lib, brush->gpencil_settings->material);
+ }
+
brush->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -2296,6 +2405,7 @@ static void direct_link_brush(FileData *fd, Brush *brush)
/* fallof curve */
brush->curve = newdataadr(fd, brush->curve);
+
brush->gradient = newdataadr(fd, brush->gradient);
if (brush->curve)
@@ -2303,11 +2413,29 @@ static void direct_link_brush(FileData *fd, Brush *brush)
else
BKE_brush_curve_preset(brush, CURVE_PRESET_SHARP);
+ /* grease pencil */
+ brush->gpencil_settings = newdataadr(fd, brush->gpencil_settings);
+ if (brush->gpencil_settings != NULL) {
+ brush->gpencil_settings->curve_sensitivity = newdataadr(fd, brush->gpencil_settings->curve_sensitivity);
+ brush->gpencil_settings->curve_strength = newdataadr(fd, brush->gpencil_settings->curve_strength);
+ brush->gpencil_settings->curve_jitter = newdataadr(fd, brush->gpencil_settings->curve_jitter);
+
+ if (brush->gpencil_settings->curve_sensitivity)
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_sensitivity);
+
+ if (brush->gpencil_settings->curve_strength)
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_strength);
+
+ if (brush->gpencil_settings->curve_jitter)
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_jitter);
+ }
+
brush->preview = NULL;
brush->icon_imbuf = NULL;
}
/* ************ READ Palette *************** */
+
static void lib_link_palette(FileData *fd, Main *main)
{
/* only link ID pointers */
@@ -2322,6 +2450,7 @@ static void lib_link_palette(FileData *fd, Main *main)
static void direct_link_palette(FileData *fd, Palette *palette)
{
+
/* palette itself has been read */
link_list(fd, &palette->colors);
}
@@ -2555,6 +2684,7 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
/* compiled expression data will need to be regenerated (old pointer may still be set here) */
driver->expr_comp = NULL;
+ driver->expr_simple = NULL;
/* give the driver a fresh chance - the operating environment may be different now
* (addons, etc. may be different) so the driver namespace may be sane now [#32155]
@@ -2769,6 +2899,7 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
/* link drivers */
link_list(fd, &adt->drivers);
direct_link_fcurves(fd, &adt->drivers);
+ adt->driver_array = NULL;
/* link overrides */
// TODO...
@@ -2813,6 +2944,81 @@ static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
direct_link_animdata(fd, cache_file->adt);
}
+/* ************ READ WORKSPACES *************** */
+
+static void lib_link_workspaces(FileData *fd, Main *bmain)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+ ID *id = (ID *)workspace;
+
+ if ((id->tag & LIB_TAG_NEED_LINK) == 0) {
+ continue;
+ }
+ IDP_LibLinkProperty(id->properties, fd);
+ id_us_ensure_real(id);
+
+ for (WorkSpaceLayout *layout = layouts->first, *layout_next; layout; layout = layout_next) {
+ layout->screen = newlibadr_us(fd, id->lib, layout->screen);
+
+ layout_next = layout->next;
+ if (layout->screen) {
+ if (ID_IS_LINKED(id)) {
+ layout->screen->winid = 0;
+ if (layout->screen->temp) {
+ /* delete temp layouts when appending */
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
+ }
+ }
+ }
+
+ id->tag &= ~LIB_TAG_NEED_LINK;
+ }
+}
+
+static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main *main)
+{
+ link_list(fd, BKE_workspace_layouts_get(workspace));
+ link_list(fd, &workspace->hook_layout_relations);
+ link_list(fd, &workspace->owner_ids);
+ link_list(fd, &workspace->tools);
+
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first;
+ relation;
+ relation = relation->next)
+ {
+ relation->parent = newglobadr(fd, relation->parent); /* data from window - need to access through global oldnew-map */
+ relation->value = newdataadr(fd, relation->value);
+ }
+
+ /* Same issue/fix as in direct_link_workspace_link_scene_data: Can't read workspace data
+ * when reading windows, so have to update windows after/when reading workspaces. */
+ for (wmWindowManager *wm = main->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpaceLayout *act_layout = newdataadr(fd, BKE_workspace_active_layout_get(win->workspace_hook));
+ if (act_layout) {
+ BKE_workspace_active_layout_set(win->workspace_hook, act_layout);
+ }
+ }
+ }
+
+ for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ tref->runtime = NULL;
+ tref->properties = newdataadr(fd, tref->properties);
+ IDP_DirectLinkGroup_OrFree(&tref->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+
+ workspace->status_text = NULL;
+}
+
+static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id)
+{
+ WorkSpace *workspace = BKE_workspace_active_get(hook);
+ BKE_workspace_active_set(hook, newlibadr(fd, id->lib, workspace));
+}
+
+
/* ************ READ MOTION PATHS *************** */
/* direct data for cache */
@@ -2824,6 +3030,10 @@ static void direct_link_motionpath(FileData *fd, bMotionPath *mpath)
/* relink points cache */
mpath->points = newdataadr(fd, mpath->points);
+
+ mpath->points_vbo = NULL;
+ mpath->batch_line = NULL;
+ mpath->batch_points = NULL;
}
/* ************ READ NODE TREE *************** */
@@ -3267,6 +3477,11 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
}
/* own ipo, all constraints have it */
con->ipo = newlibadr_us(fd, id->lib, con->ipo); // XXX deprecated - old animation system
+
+ /* If linking from a library, clear 'local' static override flag. */
+ if (id->lib != NULL) {
+ con->flag &= ~CONSTRAINT_STATICOVERRIDE_LOCAL;
+ }
}
/* relink all ID-blocks used by the constraints */
@@ -3295,6 +3510,14 @@ static void direct_link_constraints(FileData *fd, ListBase *lb)
IDP_DirectLinkGroup_OrFree(&data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
break;
}
+ case CONSTRAINT_TYPE_ARMATURE:
+ {
+ bArmatureConstraint *data = con->data;
+
+ link_list(fd, &data->targets);
+
+ break;
+ }
case CONSTRAINT_TYPE_SPLINEIK:
{
bSplineIKConstraint *data = con->data;
@@ -3340,7 +3563,7 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
bool rebuild = false;
if (fd->memfile == NULL) {
- if (ob->proxy || (ob->id.lib == NULL && arm->id.lib)) {
+ if (ob->proxy || ob->id.lib != arm->id.lib) {
rebuild = true;
}
}
@@ -3384,7 +3607,7 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
if (rebuild) {
- DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
BKE_pose_tag_recalc(bmain, pose);
}
}
@@ -3422,6 +3645,9 @@ static void direct_link_bones(FileData *fd, Bone *bone)
bone->prop = newdataadr(fd, bone->prop);
IDP_DirectLinkGroup_OrFree(&bone->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ bone->bbone_next = newdataadr(fd, bone->bbone_next);
+ bone->bbone_prev = newdataadr(fd, bone->bbone_prev);
+
bone->flag &= ~BONE_DRAW_ACTIVE;
link_list(fd, &bone->childbase);
@@ -3436,7 +3662,6 @@ static void direct_link_armature(FileData *fd, bArmature *arm)
link_list(fd, &arm->bonebase);
arm->edbo = NULL;
- arm->sketch = NULL;
arm->adt = newdataadr(fd, arm->adt);
direct_link_animdata(fd, arm->adt);
@@ -3462,6 +3687,11 @@ static void lib_link_camera(FileData *fd, Main *main)
ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob);
+ for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) {
+ bgpic->ima = newlibadr_us(fd, ca->id.lib, bgpic->ima);
+ bgpic->clip = newlibadr_us(fd, ca->id.lib, bgpic->clip);
+ }
+
ca->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -3471,6 +3701,12 @@ static void direct_link_camera(FileData *fd, Camera *ca)
{
ca->adt = newdataadr(fd, ca->adt);
direct_link_animdata(fd, ca->adt);
+
+ link_list(fd, &ca->bg_images);
+
+ for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) {
+ bgpic->iuser.ok = 1;
+ }
}
@@ -3483,14 +3719,6 @@ static void lib_link_lamp(FileData *fd, Main *main)
IDP_LibLinkProperty(la->id.properties, fd);
lib_link_animdata(fd, &la->id, la->adt);
- for (int a = 0; a < MAX_MTEX; a++) {
- MTex *mtex = la->mtex[a];
- if (mtex) {
- mtex->tex = newlibadr_us(fd, la->id.lib, mtex->tex);
- mtex->object = newlibadr(fd, la->id.lib, mtex->object);
- }
- }
-
la->ipo = newlibadr_us(fd, la->id.lib, la->ipo); // XXX deprecated - old animation system
if (la->nodetree) {
@@ -3505,15 +3733,9 @@ static void lib_link_lamp(FileData *fd, Main *main)
static void direct_link_lamp(FileData *fd, Lamp *la)
{
- int a;
-
la->adt = newdataadr(fd, la->adt);
direct_link_animdata(fd, la->adt);
- for (a = 0; a < MAX_MTEX; a++) {
- la->mtex[a] = newdataadr(fd, la->mtex[a]);
- }
-
la->curfalloff = newdataadr(fd, la->curfalloff);
if (la->curfalloff)
direct_link_curvemapping(fd, la->curfalloff);
@@ -3638,6 +3860,7 @@ static void direct_link_mball(FileData *fd, MetaBall *mb)
mb->editelems = NULL;
/* mb->edit_elems.first= mb->edit_elems.last= NULL;*/
mb->lastelem = NULL;
+ mb->batch_cache = NULL;
}
/* ************ READ WORLD ***************** */
@@ -3651,14 +3874,6 @@ static void lib_link_world(FileData *fd, Main *main)
wrld->ipo = newlibadr_us(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system
- for (int a = 0; a < MAX_MTEX; a++) {
- MTex *mtex = wrld->mtex[a];
- if (mtex) {
- mtex->tex = newlibadr_us(fd, wrld->id.lib, mtex->tex);
- mtex->object = newlibadr(fd, wrld->id.lib, mtex->object);
- }
- }
-
if (wrld->nodetree) {
lib_link_ntree(fd, &wrld->id, wrld->nodetree);
wrld->nodetree->id.lib = wrld->id.lib;
@@ -3671,15 +3886,9 @@ static void lib_link_world(FileData *fd, Main *main)
static void direct_link_world(FileData *fd, World *wrld)
{
- int a;
-
wrld->adt = newdataadr(fd, wrld->adt);
direct_link_animdata(fd, wrld->adt);
- for (a = 0; a < MAX_MTEX; a++) {
- wrld->mtex[a] = newdataadr(fd, wrld->mtex[a]);
- }
-
wrld->nodetree = newdataadr(fd, wrld->nodetree);
if (wrld->nodetree) {
direct_link_id(fd, &wrld->nodetree->id);
@@ -3786,23 +3995,22 @@ static void direct_link_image(FileData *fd, Image *ima)
if (!ima->cache) {
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima->bindcode[i] = 0;
ima->gputexture[i] = NULL;
}
ima->rr = NULL;
}
- ima->repbind = NULL;
-
/* undo system, try to restore render buffers */
+ link_list(fd, &(ima->renderslots));
if (fd->imamap) {
- int a;
-
- for (a = 0; a < IMA_MAX_RENDER_SLOT; a++)
- ima->renders[a] = newimaadr(fd, ima->renders[a]);
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) {
+ slot->render = newimaadr(fd, slot->render);
+ }
}
else {
- memset(ima->renders, 0, sizeof(ima->renders));
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) {
+ slot->render = NULL;
+ }
ima->last_render_slot = ima->render_slot;
}
@@ -3906,6 +4114,7 @@ static void direct_link_curve(FileData *fd, Curve *cu)
cu->editnurb = NULL;
cu->editfont = NULL;
+ cu->batch_cache = NULL;
for (nu = cu->nurb.first; nu; nu = nu->next) {
nu->bezt = newdataadr(fd, nu->bezt);
@@ -3932,14 +4141,6 @@ static void lib_link_texture(FileData *fd, Main *main)
tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima);
tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo); // XXX deprecated - old animation system
- if (tex->env)
- tex->env->object = newlibadr(fd, tex->id.lib, tex->env->object);
- if (tex->pd)
- tex->pd->object = newlibadr(fd, tex->id.lib, tex->pd->object);
- if (tex->vd)
- tex->vd->object = newlibadr(fd, tex->id.lib, tex->vd->object);
- if (tex->ot)
- tex->ot->object = newlibadr(fd, tex->id.lib, tex->ot->object);
if (tex->nodetree) {
lib_link_ntree(fd, &tex->id, tex->nodetree);
@@ -3957,34 +4158,6 @@ static void direct_link_texture(FileData *fd, Tex *tex)
direct_link_animdata(fd, tex->adt);
tex->coba = newdataadr(fd, tex->coba);
- tex->env = newdataadr(fd, tex->env);
- if (tex->env) {
- tex->env->ima = NULL;
- memset(tex->env->cube, 0, 6 * sizeof(void *));
- tex->env->ok = 0;
- }
- tex->pd = newdataadr(fd, tex->pd);
- if (tex->pd) {
- tex->pd->point_tree = NULL;
- tex->pd->coba = newdataadr(fd, tex->pd->coba);
- tex->pd->falloff_curve = newdataadr(fd, tex->pd->falloff_curve);
- if (tex->pd->falloff_curve) {
- direct_link_curvemapping(fd, tex->pd->falloff_curve);
- }
- tex->pd->point_data = NULL; /* runtime data */
- }
-
- tex->vd = newdataadr(fd, tex->vd);
- if (tex->vd) {
- tex->vd->dataset = NULL;
- tex->vd->ok = 0;
- }
- else {
- if (tex->type == TEX_VOXELDATA)
- tex->vd = MEM_callocN(sizeof(VoxelData), "direct_link_texture VoxelData");
- }
-
- tex->ot = newdataadr(fd, tex->ot);
tex->nodetree = newdataadr(fd, tex->nodetree);
if (tex->nodetree) {
@@ -4009,21 +4182,23 @@ static void lib_link_material(FileData *fd, Main *main)
lib_link_animdata(fd, &ma->id, ma->adt);
ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system
- ma->group = newlibadr_us(fd, ma->id.lib, ma->group);
-
- for (int a = 0; a < MAX_MTEX; a++) {
- MTex *mtex = ma->mtex[a];
- if (mtex) {
- mtex->tex = newlibadr_us(fd, ma->id.lib, mtex->tex);
- mtex->object = newlibadr(fd, ma->id.lib, mtex->object);
- }
- }
if (ma->nodetree) {
lib_link_ntree(fd, &ma->id, ma->nodetree);
ma->nodetree->id.lib = ma->id.lib;
}
+ /* relink grease pencil settings */
+ if (ma->gp_style != NULL) {
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ if (gp_style->sima != NULL) {
+ gp_style->sima = newlibadr_us(fd, ma->id.lib, gp_style->sima);
+ }
+ if (gp_style->ima != NULL) {
+ gp_style->ima = newlibadr_us(fd, ma->id.lib, gp_style->ima);
+ }
+ }
+
ma->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
@@ -4031,19 +4206,11 @@ static void lib_link_material(FileData *fd, Main *main)
static void direct_link_material(FileData *fd, Material *ma)
{
- int a;
-
ma->adt = newdataadr(fd, ma->adt);
direct_link_animdata(fd, ma->adt);
- for (a = 0; a < MAX_MTEX; a++) {
- ma->mtex[a] = newdataadr(fd, ma->mtex[a]);
- }
ma->texpaintslot = NULL;
- ma->ramp_col = newdataadr(fd, ma->ramp_col);
- ma->ramp_spec = newdataadr(fd, ma->ramp_spec);
-
ma->nodetree = newdataadr(fd, ma->nodetree);
if (ma->nodetree) {
direct_link_id(fd, &ma->nodetree->id);
@@ -4052,6 +4219,8 @@ static void direct_link_material(FileData *fd, Material *ma)
ma->preview = direct_link_preview_image(fd, ma->preview);
BLI_listbase_clear(&ma->gpumaterial);
+
+ ma->gp_style = newdataadr(fd, ma->gp_style);
}
/* ************ READ PARTICLE SETTINGS ***************** */
@@ -4167,40 +4336,8 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
}
if (part->dupliweights.first && part->dup_group) {
- ParticleDupliWeight *dw;
- int index_ok = 0;
- /* check for old files without indices (all indexes 0) */
- if (BLI_listbase_is_single(&part->dupliweights)) {
- /* special case for only one object in the group */
- index_ok = 1;
- }
- else {
- for (dw = part->dupliweights.first; dw; dw = dw->next) {
- if (dw->index > 0) {
- index_ok = 1;
- break;
- }
- }
- }
-
- if (index_ok) {
- /* if we have indexes, let's use them */
- for (dw = part->dupliweights.first; dw; dw = dw->next) {
- /* Do not try to restore pointer here, we have to search for group objects in another
- * separated step.
- * Reason is, the used group may be linked from another library, which has not yet
- * been 'lib_linked'.
- * Since dw->ob is not considered as an object user (it does not make objet directly linked),
- * we may have no valid way to retrieve it yet.
- * See T49273. */
- dw->ob = NULL;
- }
- }
- else {
- /* otherwise try to get objects from own library (won't work on library linked groups) */
- for (dw = part->dupliweights.first; dw; dw = dw->next) {
- dw->ob = newlibadr(fd, part->id.lib, dw->ob);
- }
+ for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
+ dw->ob = newlibadr(fd, part->id.lib, dw->ob);
}
}
else {
@@ -4387,7 +4524,6 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
BLI_listbase_clear(&psys->pathcachebufs);
BLI_listbase_clear(&psys->childcachebufs);
psys->pdd = NULL;
- psys->renderdata = NULL;
if (psys->clmd) {
psys->clmd = newdataadr(fd, psys->clmd);
@@ -4403,7 +4539,7 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->clmd->sim_parms->presets = 0;
}
- psys->hair_in_dm = psys->hair_out_dm = NULL;
+ psys->hair_in_mesh = psys->hair_out_mesh = NULL;
psys->clmd->solver_result = NULL;
}
@@ -4414,55 +4550,15 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
psys->tree = NULL;
psys->bvhtree = NULL;
+
+ psys->orig_psys = NULL;
+ psys->batch_cache = NULL;
}
return;
}
/* ************ READ MESH ***************** */
-static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
-{
- MTFace *tf = mtface;
- int i;
-
- /* Add pseudo-references (not fake users!) to images used by texface. A
- * little bogus; it would be better if each mesh consistently added one ref
- * to each image it used. - z0r */
- for (i = 0; i < totface; i++, tf++) {
- tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage);
- }
-}
-
-static void lib_link_customdata_mtface(FileData *fd, Mesh *me, CustomData *fdata, int totface)
-{
- int i;
- for (i = 0; i < fdata->totlayer; i++) {
- CustomDataLayer *layer = &fdata->layers[i];
-
- if (layer->type == CD_MTFACE)
- lib_link_mtface(fd, me, layer->data, totface);
- }
-
-}
-
-static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata, int totface)
-{
- int i;
-
- for (i = 0; i < pdata->totlayer; i++) {
- CustomDataLayer *layer = &pdata->layers[i];
-
- if (layer->type == CD_MTEXPOLY) {
- MTexPoly *tf = layer->data;
- int j;
-
- for (j = 0; j < totface; j++, tf++) {
- tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage);
- }
- }
- }
-}
-
static void lib_link_mesh(FileData *fd, Main *main)
{
Mesh *me;
@@ -4489,19 +4585,9 @@ static void lib_link_mesh(FileData *fd, Main *main)
me->ipo = newlibadr_us(fd, me->id.lib, me->ipo); // XXX: deprecated: old anim sys
me->key = newlibadr_us(fd, me->id.lib, me->key);
me->texcomesh = newlibadr_us(fd, me->id.lib, me->texcomesh);
-
- lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
- lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly);
- if (me->mr && me->mr->levels.first) {
- lib_link_customdata_mtface(fd, me, &me->mr->fdata,
- ((MultiresLevel *)me->mr->levels.first)->totface);
- }
}
}
- /* convert texface options to material */
- convert_tface_mt(fd, main);
-
for (me = main->mesh.first; me; me = me->id.next) {
if (me->id.tag & LIB_TAG_NEED_LINK) {
/*check if we need to convert mfaces to mpolys*/
@@ -4657,7 +4743,6 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
mesh->dvert = newdataadr(fd, mesh->dvert);
mesh->mloopcol = newdataadr(fd, mesh->mloopcol);
mesh->mloopuv = newdataadr(fd, mesh->mloopuv);
- mesh->mtpoly = newdataadr(fd, mesh->mtpoly);
mesh->mselect = newdataadr(fd, mesh->mselect);
/* animdata */
@@ -4676,18 +4761,13 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
mesh->bb = NULL;
mesh->edit_btmesh = NULL;
+ BKE_mesh_runtime_reset(mesh);
/* happens with old files */
if (mesh->mselect == NULL) {
mesh->totselect = 0;
}
- if (mesh->mloopuv || mesh->mtpoly) {
- /* for now we have to ensure texpoly and mloopuv layers are aligned
- * in the future we may allow non-aligned layers */
- BKE_mesh_cd_validate(mesh);
- }
-
/* Multires data */
mesh->mr = newdataadr(fd, mesh->mr);
if (mesh->mr) {
@@ -4767,6 +4847,7 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
direct_link_dverts(fd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert);
lt->editlatt = NULL;
+ lt->batch_cache = NULL;
lt->adt = newdataadr(fd, lt->adt);
direct_link_animdata(fd, lt->adt);
@@ -4775,8 +4856,8 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
/* ************ READ OBJECT ***************** */
-static void lib_link_modifiers__linkModifiers(
- void *userData, Object *ob, ID **idpoin, int cb_flag)
+static void lib_link_modifiers_common(
+ void *userData, Object *ob, ID **idpoin, int cb_flag)
{
FileData *fd = userData;
@@ -4785,9 +4866,42 @@ static void lib_link_modifiers__linkModifiers(
id_us_plus_no_lib(*idpoin);
}
}
+
static void lib_link_modifiers(FileData *fd, Object *ob)
{
- modifiers_foreachIDLink(ob, lib_link_modifiers__linkModifiers, fd);
+ modifiers_foreachIDLink(ob, lib_link_modifiers_common, fd);
+
+ /* If linking from a library, clear 'local' static override flag. */
+ if (ob->id.lib != NULL) {
+ for (ModifierData *mod = ob->modifiers.first; mod != NULL; mod = mod->next) {
+ mod->flag &= ~eModifierFlag_StaticOverride_Local;
+ }
+ }
+
+}
+
+static void lib_link_gpencil_modifiers(FileData *fd, Object *ob)
+{
+ BKE_gpencil_modifiers_foreachIDLink(ob, lib_link_modifiers_common, fd);
+
+ /* If linking from a library, clear 'local' static override flag. */
+ if (ob->id.lib != NULL) {
+ for (GpencilModifierData *mod = ob->greasepencil_modifiers.first; mod != NULL; mod = mod->next) {
+ mod->flag &= ~eGpencilModifierFlag_StaticOverride_Local;
+ }
+ }
+}
+
+static void lib_link_shaderfxs(FileData *fd, Object *ob)
+{
+ BKE_shaderfx_foreachIDLink(ob, lib_link_modifiers_common, fd);
+
+ /* If linking from a library, clear 'local' static override flag. */
+ if (ob->id.lib != NULL) {
+ for (ShaderFxData *fx = ob->shader_fx.first; fx != NULL; fx = fx->next) {
+ fx->flag &= ~eShaderFxFlag_StaticOverride_Local;
+ }
+ }
}
static void lib_link_object(FileData *fd, Main *main)
@@ -4809,7 +4923,15 @@ static void lib_link_object(FileData *fd, Main *main)
ob->parent = newlibadr(fd, ob->id.lib, ob->parent);
ob->track = newlibadr(fd, ob->id.lib, ob->track);
ob->poselib = newlibadr_us(fd, ob->id.lib, ob->poselib);
- ob->dup_group = newlibadr_us(fd, ob->id.lib, ob->dup_group);
+
+ /* 2.8x drops support for non-empty dupli instances. */
+ if (ob->type == OB_EMPTY) {
+ ob->dup_group = newlibadr_us(fd, ob->id.lib, ob->dup_group);
+ }
+ else {
+ ob->dup_group = NULL;
+ ob->transflag &= ~OB_DUPLICOLLECTION;
+ }
ob->proxy = newlibadr_us(fd, ob->id.lib, ob->proxy);
if (ob->proxy) {
@@ -4872,7 +4994,6 @@ static void lib_link_object(FileData *fd, Main *main)
}
ob->gpd = newlibadr_us(fd, ob->id.lib, ob->gpd);
- ob->duplilist = NULL;
ob->id.tag &= ~LIB_TAG_NEED_LINK;
/* if id.us==0 a new base will be created later on */
@@ -4892,143 +5013,6 @@ static void lib_link_object(FileData *fd, Main *main)
}
}
- for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) {
- for (a = 0; a < sens->totlinks; a++)
- sens->links[a] = newglobadr(fd, sens->links[a]);
-
- if (sens->type == SENS_MESSAGE) {
- bMessageSensor *ms = sens->data;
- ms->fromObject =
- newlibadr(fd, ob->id.lib, ms->fromObject);
- }
- }
-
- for (bController *cont = ob->controllers.first; cont; cont = cont->next) {
- for (a = 0; a < cont->totlinks; a++)
- cont->links[a] = newglobadr(fd, cont->links[a]);
-
- if (cont->type == CONT_PYTHON) {
- bPythonCont *pc = cont->data;
- pc->text = newlibadr(fd, ob->id.lib, pc->text);
- }
- cont->slinks = NULL;
- cont->totslinks = 0;
- }
-
- for (bActuator *act = ob->actuators.first; act; act = act->next) {
- switch (act->type) {
- case ACT_SOUND:
- {
- bSoundActuator *sa = act->data;
- sa->sound = newlibadr_us(fd, ob->id.lib, sa->sound);
- break;
- }
- case ACT_GAME:
- /* bGameActuator *ga= act->data; */
- break;
- case ACT_CAMERA:
- {
- bCameraActuator *ca = act->data;
- ca->ob = newlibadr(fd, ob->id.lib, ca->ob);
- break;
- }
- /* leave this one, it's obsolete but necessary to read for conversion */
- case ACT_ADD_OBJECT:
- {
- bAddObjectActuator *eoa = act->data;
- if (eoa)
- eoa->ob = newlibadr(fd, ob->id.lib, eoa->ob);
- break;
- }
- case ACT_OBJECT:
- {
- bObjectActuator *oa = act->data;
- if (oa == NULL) {
- init_actuator(act);
- }
- else {
- oa->reference = newlibadr(fd, ob->id.lib, oa->reference);
- }
- break;
- }
- case ACT_EDIT_OBJECT:
- {
- bEditObjectActuator *eoa = act->data;
- if (eoa == NULL) {
- init_actuator(act);
- }
- else {
- eoa->ob = newlibadr(fd, ob->id.lib, eoa->ob);
- eoa->me = newlibadr(fd, ob->id.lib, eoa->me);
- }
- break;
- }
- case ACT_SCENE:
- {
- bSceneActuator *sa = act->data;
- sa->camera = newlibadr(fd, ob->id.lib, sa->camera);
- sa->scene = newlibadr(fd, ob->id.lib, sa->scene);
- break;
- }
- case ACT_ACTION:
- {
- bActionActuator *aa = act->data;
- aa->act = newlibadr_us(fd, ob->id.lib, aa->act);
- break;
- }
- case ACT_SHAPEACTION:
- {
- bActionActuator *aa = act->data;
- aa->act = newlibadr_us(fd, ob->id.lib, aa->act);
- break;
- }
- case ACT_PROPERTY:
- {
- bPropertyActuator *pa = act->data;
- pa->ob = newlibadr(fd, ob->id.lib, pa->ob);
- break;
- }
- case ACT_MESSAGE:
- {
- bMessageActuator *ma = act->data;
- ma->toObject = newlibadr(fd, ob->id.lib, ma->toObject);
- break;
- }
- case ACT_2DFILTER:
- {
- bTwoDFilterActuator *_2dfa = act->data;
- _2dfa->text = newlibadr(fd, ob->id.lib, _2dfa->text);
- break;
- }
- case ACT_PARENT:
- {
- bParentActuator *parenta = act->data;
- parenta->ob = newlibadr(fd, ob->id.lib, parenta->ob);
- break;
- }
- case ACT_STATE:
- /* bStateActuator *statea = act->data; */
- break;
- case ACT_ARMATURE:
- {
- bArmatureActuator *arma = act->data;
- arma->target = newlibadr(fd, ob->id.lib, arma->target);
- arma->subtarget = newlibadr(fd, ob->id.lib, arma->subtarget);
- break;
- }
- case ACT_STEERING:
- {
- bSteeringActuator *steeringa = act->data;
- steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target);
- steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh);
- break;
- }
- case ACT_MOUSE:
- /* bMouseActuator *moa = act->data; */
- break;
- }
- }
-
{
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
@@ -5056,6 +5040,8 @@ static void lib_link_object(FileData *fd, Main *main)
lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem);
lib_link_modifiers(fd, ob);
+ lib_link_gpencil_modifiers(fd, ob);
+ lib_link_shaderfxs(fd, ob);
if (ob->rigidbody_constraint) {
ob->rigidbody_constraint->ob1 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob1);
@@ -5116,6 +5102,9 @@ static void direct_link_pose(FileData *fd, bPose *pose)
/* in case this value changes in future, clamp else we get undefined behavior */
CLAMP(pchan->rotmode, ROT_MODE_MIN, ROT_MODE_MAX);
+
+ pchan->draw_data = NULL;
+ memset(&pchan->runtime, 0, sizeof(pchan->runtime));
}
pose->ikdata = NULL;
if (pose->ikparam != NULL) {
@@ -5131,7 +5120,6 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
for (md = lb->first; md; md = md->next) {
md->error = NULL;
- md->scene = NULL;
/* if modifiers disappear, or for upward compatibility */
if (NULL == modifierType_getInfo(md->type))
@@ -5197,6 +5185,13 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->domain->shadow = NULL;
smd->domain->tex = NULL;
smd->domain->tex_shadow = NULL;
+ smd->domain->tex_flame = NULL;
+ smd->domain->tex_flame_coba = NULL;
+ smd->domain->tex_coba = NULL;
+ smd->domain->tex_field = NULL;
+ smd->domain->tex_velocity_x = NULL;
+ smd->domain->tex_velocity_y = NULL;
+ smd->domain->tex_velocity_z = NULL;
smd->domain->tex_wt = NULL;
smd->domain->coba = newdataadr(fd, smd->domain->coba);
@@ -5227,7 +5222,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->coll = NULL;
smd->flow = newdataadr(fd, smd->flow);
smd->flow->smd = smd;
- smd->flow->dm = NULL;
+ smd->flow->mesh = NULL;
smd->flow->verts_old = NULL;
smd->flow->numverts = 0;
smd->flow->psys = newdataadr(fd, smd->flow->psys);
@@ -5240,7 +5235,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
smd->coll->smd = smd;
smd->coll->verts_old = NULL;
smd->coll->numverts = 0;
- smd->coll->dm = NULL;
+ smd->coll->mesh = NULL;
}
else {
smd->type = 0;
@@ -5256,7 +5251,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
if (pmd->canvas) {
pmd->canvas = newdataadr(fd, pmd->canvas);
pmd->canvas->pmd = pmd;
- pmd->canvas->dm = NULL;
+ pmd->canvas->mesh = NULL;
pmd->canvas->flags &= ~MOD_DPAINT_BAKING; /* just in case */
if (pmd->canvas->surfaces.first) {
@@ -5279,7 +5274,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
pmd->brush->psys = newdataadr(fd, pmd->brush->psys);
pmd->brush->paint_ramp = newdataadr(fd, pmd->brush->paint_ramp);
pmd->brush->vel_ramp = newdataadr(fd, pmd->brush->vel_ramp);
- pmd->brush->dm = NULL;
+ pmd->brush->mesh = NULL;
}
}
else if (md->type == eModifierType_Collision) {
@@ -5312,7 +5307,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
else if (md->type == eModifierType_Surface) {
SurfaceModifierData *surmd = (SurfaceModifierData *)md;
- surmd->dm = NULL;
+ surmd->mesh = NULL;
surmd->bvhtree = NULL;
surmd->x = NULL;
surmd->v = NULL;
@@ -5334,8 +5329,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
else if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
- psmd->dm_final = NULL;
- psmd->dm_deformed = NULL;
+ psmd->mesh_final = NULL;
+ psmd->mesh_original = NULL;
psmd->psys = newdataadr(fd, psmd->psys);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
psmd->flag |= eParticleSystemFlag_file_loaded;
@@ -5369,8 +5364,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
else if (md->type == eModifierType_Ocean) {
OceanModifierData *omd = (OceanModifierData *)md;
omd->oceancache = NULL;
- omd->ocean = BKE_ocean_add();
- omd->refresh = MOD_OCEAN_REFRESH_RESET;
+ omd->ocean = NULL;
}
else if (md->type == eModifierType_Warp) {
WarpModifierData *tmd = (WarpModifierData *)md;
@@ -5450,24 +5444,71 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
}
}
+ else if (md->type == eModifierType_Bevel) {
+ BevelModifierData *bmd = (BevelModifierData *)md;
+ bmd->clnordata.faceHash = NULL;
+ }
}
}
-static void direct_link_object(FileData *fd, Object *ob)
+static void direct_link_gpencil_modifiers(FileData *fd, ListBase *lb)
{
- PartEff *paf;
- bProperty *prop;
- bSensor *sens;
- bController *cont;
- bActuator *act;
+ GpencilModifierData *md;
+
+ link_list(fd, lb);
- /* weak weak... this was only meant as draw flag, now is used in give_base_to_objects too */
- ob->flag &= ~OB_FROMGROUP;
+ for (md = lb->first; md; md = md->next) {
+ md->error = NULL;
- /* This is a transient flag; clear in order to avoid unneeded object update pending from
- * time when file was saved.
- */
- ob->recalc = 0;
+ /* if modifiers disappear, or for upward compatibility */
+ if (NULL == BKE_gpencil_modifierType_getInfo(md->type))
+ md->type = eModifierType_None;
+
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md;
+ gpmd->cache_data = NULL;
+ }
+ else if (md->type == eGpencilModifierType_Hook) {
+ HookGpencilModifierData *hmd = (HookGpencilModifierData *)md;
+
+ hmd->curfalloff = newdataadr(fd, hmd->curfalloff);
+ if (hmd->curfalloff) {
+ direct_link_curvemapping(fd, hmd->curfalloff);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Thick) {
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+
+ gpmd->curve_thickness = newdataadr(fd, gpmd->curve_thickness);
+ if (gpmd->curve_thickness) {
+ direct_link_curvemapping(fd, gpmd->curve_thickness);
+ /* initialize the curve. Maybe this could be moved to modififer logic */
+ curvemapping_initialize(gpmd->curve_thickness);
+ }
+ }
+
+ }
+}
+
+static void direct_link_shaderfxs(FileData *fd, ListBase *lb)
+{
+ ShaderFxData *fx;
+
+ link_list(fd, lb);
+
+ for (fx = lb->first; fx; fx = fx->next) {
+ fx->error = NULL;
+
+ /* if shader disappear, or for upward compatibility */
+ if (NULL == BKE_shaderfxType_getInfo(fx->type))
+ fx->type = eShaderFxType_None;
+
+ }
+}
+
+static void direct_link_object(FileData *fd, Object *ob)
+{
+ PartEff *paf;
/* XXX This should not be needed - but seems like it can happen in some cases, so for now play safe... */
ob->proxy_from = NULL;
@@ -5496,6 +5537,7 @@ static void direct_link_object(FileData *fd, Object *ob)
direct_link_motionpath(fd, ob->mpath);
link_list(fd, &ob->defbase);
+ link_list(fd, &ob->fmaps);
// XXX deprecated - old animation system <<<
direct_link_nlastrips(fd, &ob->nlastrips);
link_list(fd, &ob->constraintChannels);
@@ -5507,6 +5549,8 @@ static void direct_link_object(FileData *fd, Object *ob)
/* do it here, below old data gets converted */
direct_link_modifiers(fd, &ob->modifiers);
+ direct_link_gpencil_modifiers(fd, &ob->greasepencil_modifiers);
+ direct_link_shaderfxs(fd, &ob->shader_fx);
link_list(fd, &ob->effect);
paf = ob->effect.first;
@@ -5583,20 +5627,26 @@ static void direct_link_object(FileData *fd, Object *ob)
if (!sb->effector_weights)
sb->effector_weights = BKE_add_effector_weights(NULL);
- direct_link_pointcache_list(fd, &sb->ptcaches, &sb->pointcache, 0);
+ sb->shared = newdataadr(fd, sb->shared);
+ if (sb->shared == NULL) {
+ /* Link deprecated caches if they exist, so we can use them for versioning.
+ * We should only do this when sb->shared == NULL, because those pointers
+ * are always set (for compatibility with older Blenders). We mustn't link
+ * the same pointcache twice. */
+ direct_link_pointcache_list(fd, &sb->ptcaches, &sb->pointcache, false);
+ }
+ else {
+ /* link caches */
+ direct_link_pointcache_list(fd, &sb->shared->ptcaches, &sb->shared->pointcache, false);
+ }
}
- ob->bsoft = newdataadr(fd, ob->bsoft);
ob->fluidsimSettings = newdataadr(fd, ob->fluidsimSettings); /* NT */
ob->rigidbody_object = newdataadr(fd, ob->rigidbody_object);
if (ob->rigidbody_object) {
RigidBodyOb *rbo = ob->rigidbody_object;
-
- /* must nullify the references to physics sim objects, since they no-longer exist
- * (and will need to be recalculated)
- */
- rbo->physics_object = NULL;
- rbo->physics_shape = NULL;
+ /* Allocate runtime-only struct */
+ rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyObShared");
}
ob->rigidbody_constraint = newdataadr(fd, ob->rigidbody_constraint);
if (ob->rigidbody_constraint)
@@ -5605,43 +5655,8 @@ static void direct_link_object(FileData *fd, Object *ob)
link_list(fd, &ob->particlesystem);
direct_link_particlesystems(fd, &ob->particlesystem);
- link_list(fd, &ob->prop);
- for (prop = ob->prop.first; prop; prop = prop->next) {
- prop->poin = newdataadr(fd, prop->poin);
- if (prop->poin == NULL)
- prop->poin = &prop->data;
- }
-
- link_list(fd, &ob->sensors);
- for (sens = ob->sensors.first; sens; sens = sens->next) {
- sens->data = newdataadr(fd, sens->data);
- sens->links = newdataadr(fd, sens->links);
- test_pointer_array(fd, (void **)&sens->links);
- }
-
direct_link_constraints(fd, &ob->constraints);
- link_glob_list(fd, &ob->controllers);
- if (ob->init_state) {
- /* if a known first state is specified, set it so that the game will start ok */
- ob->state = ob->init_state;
- }
- else if (!ob->state) {
- ob->state = 1;
- }
- for (cont = ob->controllers.first; cont; cont = cont->next) {
- cont->data = newdataadr(fd, cont->data);
- cont->links = newdataadr(fd, cont->links);
- test_pointer_array(fd, (void **)&cont->links);
- if (cont->state_mask == 0)
- cont->state_mask = 1;
- }
-
- link_glob_list(fd, &ob->actuators);
- for (act = ob->actuators.first; act; act = act->next) {
- act->data = newdataadr(fd, act->data);
- }
-
link_list(fd, &ob->hooks);
while (ob->hooks.first) {
ObHook *hook = ob->hooks.first;
@@ -5681,12 +5696,9 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->bb = NULL;
ob->derivedDeform = NULL;
ob->derivedFinal = NULL;
- BLI_listbase_clear(&ob->gpulamp);
+ BKE_object_runtime_reset(ob);
link_list(fd, &ob->pc_ids);
- /* Runtime curve data */
- ob->curve_cache = NULL;
-
/* in case this value changes in future, clamp else we get undefined behavior */
CLAMP(ob->rotmode, ROT_MODE_MIN, ROT_MODE_MAX);
@@ -5706,6 +5718,205 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->preview = direct_link_preview_image(fd, ob->preview);
}
+static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *view_settings)
+{
+ view_settings->curve_mapping = newdataadr(fd, view_settings->curve_mapping);
+
+ if (view_settings->curve_mapping)
+ direct_link_curvemapping(fd, view_settings->curve_mapping);
+}
+
+/* ***************** READ VIEW LAYER *************** */
+
+static void direct_link_layer_collections(FileData *fd, ListBase *lb, bool master)
+{
+ link_list(fd, lb);
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+#ifdef USE_COLLECTION_COMPAT_28
+ lc->scene_collection = newdataadr(fd, lc->scene_collection);
+#endif
+
+ /* Master collection is not a real datablock. */
+ if (master) {
+ lc->collection = newdataadr(fd, lc->collection);
+ }
+
+ direct_link_layer_collections(fd, &lc->layer_collections, false);
+ }
+}
+
+static void direct_link_view_layer(FileData *fd, ViewLayer *view_layer)
+{
+ view_layer->stats = NULL;
+ link_list(fd, &view_layer->object_bases);
+ view_layer->basact = newdataadr(fd, view_layer->basact);
+
+ direct_link_layer_collections(fd, &view_layer->layer_collections, true);
+ view_layer->active_collection = newdataadr(fd, view_layer->active_collection);
+
+ view_layer->id_properties = newdataadr(fd, view_layer->id_properties);
+ IDP_DirectLinkGroup_OrFree(&view_layer->id_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ link_list(fd, &(view_layer->freestyle_config.modules));
+ link_list(fd, &(view_layer->freestyle_config.linesets));
+
+ BLI_listbase_clear(&view_layer->drawdata);
+ view_layer->object_bases_array = NULL;
+ view_layer->object_bases_hash = NULL;
+}
+
+static void lib_link_layer_collection(FileData *fd, Library *lib, LayerCollection *layer_collection, bool master)
+{
+ /* Master collection is not a real datablock. */
+ if (!master) {
+ layer_collection->collection = newlibadr(fd, lib, layer_collection->collection);
+ }
+
+ for (LayerCollection *layer_collection_nested = layer_collection->layer_collections.first;
+ layer_collection_nested != NULL;
+ layer_collection_nested = layer_collection_nested->next)
+ {
+ lib_link_layer_collection(fd, lib, layer_collection_nested, false);
+ }
+}
+
+static void lib_link_view_layer(FileData *fd, Library *lib, ViewLayer *view_layer)
+{
+ for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
+ fmc->script = newlibadr(fd, lib, fmc->script);
+ }
+
+ for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ fls->linestyle = newlibadr_us(fd, lib, fls->linestyle);
+ fls->group = newlibadr_us(fd, lib, fls->group);
+ }
+
+ for (Base *base = view_layer->object_bases.first, *base_next = NULL; base; base = base_next) {
+ base_next = base->next;
+
+ /* we only bump the use count for the collection objects */
+ base->object = newlibadr(fd, lib, base->object);
+
+ if (base->object == NULL) {
+ /* Free in case linked object got lost. */
+ BLI_freelinkN(&view_layer->object_bases, base);
+ if (view_layer->basact == base) {
+ view_layer->basact = NULL;
+ }
+ }
+ }
+
+ for (LayerCollection *layer_collection = view_layer->layer_collections.first;
+ layer_collection != NULL;
+ layer_collection = layer_collection->next)
+ {
+ lib_link_layer_collection(fd, lib, layer_collection, true);
+ }
+
+ IDP_LibLinkProperty(view_layer->id_properties, fd);
+}
+
+/* ***************** READ COLLECTION *************** */
+
+#ifdef USE_COLLECTION_COMPAT_28
+static void direct_link_scene_collection(FileData *fd, SceneCollection *sc)
+{
+ link_list(fd, &sc->objects);
+ link_list(fd, &sc->scene_collections);
+
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ direct_link_scene_collection(fd, nsc);
+ }
+}
+
+static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollection *sc)
+{
+ for (LinkData *link = sc->objects.first; link; link = link->next) {
+ link->data = newlibadr_us(fd, lib, link->data);
+ BLI_assert(link->data);
+ }
+
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ lib_link_scene_collection(fd, lib, nsc);
+ }
+}
+#endif
+
+static void direct_link_collection(FileData *fd, Collection *collection)
+{
+ link_list(fd, &collection->gobject);
+ link_list(fd, &collection->children);
+
+ collection->preview = direct_link_preview_image(fd, collection->preview);
+
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_listbase_clear(&collection->object_cache);
+ BLI_listbase_clear(&collection->parents);
+
+#ifdef USE_COLLECTION_COMPAT_28
+ /* This runs before the very first doversion. */
+ collection->collection = newdataadr(fd, collection->collection);
+ if (collection->collection != NULL) {
+ direct_link_scene_collection(fd, collection->collection);
+ }
+
+ collection->view_layer = newdataadr(fd, collection->view_layer);
+ if (collection->view_layer != NULL) {
+ direct_link_view_layer(fd, collection->view_layer);
+ }
+#endif
+}
+
+static void lib_link_collection_data(FileData *fd, Library *lib, Collection *collection)
+{
+ for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
+ cob_next = cob->next;
+ cob->ob = newlibadr_us(fd, lib, cob->ob);
+
+ if (cob->ob == NULL) {
+ BLI_freelinkN(&collection->gobject, cob);
+ }
+ }
+
+ for (CollectionChild *child = collection->children.first, *child_next = NULL; child; child = child_next) {
+ child_next = child->next;
+ child->collection = newlibadr_us(fd, lib, child->collection);
+
+ if (child->collection == NULL ||
+ BKE_collection_find_cycle(collection, child->collection))
+ {
+ BLI_freelinkN(&collection->children, child);
+ }
+ else {
+ CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent");
+ cparent->collection = collection;
+ BLI_addtail(&child->collection->parents, cparent);
+ }
+ }
+}
+
+static void lib_link_collection(FileData *fd, Main *main)
+{
+ for (Collection *collection = main->collection.first; collection; collection = collection->id.next) {
+ if (collection->id.tag & LIB_TAG_NEED_LINK) {
+ collection->id.tag &= ~LIB_TAG_NEED_LINK;
+ IDP_LibLinkProperty(collection->id.properties, fd);
+
+#ifdef USE_COLLECTION_COMPAT_28
+ if (collection->collection) {
+ lib_link_scene_collection(fd, collection->id.lib, collection->collection);
+ }
+
+ if (collection->view_layer) {
+ lib_link_view_layer(fd, collection->id.lib, collection->view_layer);
+ }
+#endif
+
+ lib_link_collection_data(fd, collection->id.lib, collection);
+ }
+ }
+}
+
/* ************ READ SCENE ***************** */
/* patch for missing scene IDs, can't be in do-versions */
@@ -5723,8 +5934,15 @@ static void link_paint(FileData *fd, Scene *sce, Paint *p)
{
if (p) {
p->brush = newlibadr_us(fd, sce->id.lib, p->brush);
+ for (int i = 0; i < p->tool_slots_len; i++) {
+ if (p->tool_slots[i].brush != NULL) {
+ p->tool_slots[i].brush = newlibadr_us(fd, sce->id.lib, p->tool_slots[i].brush);
+ }
+ }
p->palette = newlibadr_us(fd, sce->id.lib, p->palette);
p->paint_cursor = NULL;
+
+ BKE_paint_runtime_init(sce->toolsettings, p);
}
}
@@ -5738,6 +5956,41 @@ static void lib_link_sequence_modifiers(FileData *fd, Scene *scene, ListBase *lb
}
}
+static void direct_link_lightcache_texture(FileData *fd, LightCacheTexture *lctex)
+{
+ lctex->tex = NULL;
+
+ if (lctex->data) {
+ lctex->data = newdataadr(fd, lctex->data);
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int data_size = lctex->components * lctex->tex_size[0] * lctex->tex_size[1] * lctex->tex_size[2];
+
+ if (lctex->data_type == LIGHTCACHETEX_FLOAT) {
+ BLI_endian_switch_float_array((float *)lctex->data, data_size * sizeof(float));
+ }
+ else if (lctex->data_type == LIGHTCACHETEX_UINT) {
+ BLI_endian_switch_uint32_array((uint *)lctex->data, data_size * sizeof(uint));
+ }
+ }
+ }
+}
+
+static void direct_link_lightcache(FileData *fd, LightCache *cache)
+{
+ direct_link_lightcache_texture(fd, &cache->cube_tx);
+ direct_link_lightcache_texture(fd, &cache->grid_tx);
+
+ if (cache->cube_mips) {
+ cache->cube_mips = newdataadr(fd, cache->cube_mips);
+ for (int i = 0; i < cache->mips_len; ++i) {
+ direct_link_lightcache_texture(fd, &cache->cube_mips[i]);
+ }
+ }
+
+ cache->cube_data = newdataadr(fd, cache->cube_data);
+ cache->grid_data = newdataadr(fd, cache->grid_data);
+}
+
/* check for cyclic set-scene,
* libs can cause this case which is normally prevented, see (T#####) */
#define USE_SETSCENE_CHECK
@@ -5794,6 +6047,7 @@ static void lib_link_scene(FileData *fd, Main *main)
link_paint(fd, sce, &sce->toolsettings->wpaint->paint);
link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
link_paint(fd, sce, &sce->toolsettings->uvsculpt->paint);
+ link_paint(fd, sce, &sce->toolsettings->gp_paint->paint);
if (sce->toolsettings->sculpt)
sce->toolsettings->sculpt->gravity_object =
@@ -5811,21 +6065,19 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->toolsettings->imapaint.canvas =
newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.canvas);
- sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
-
sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object);
- for (Base *next, *base = sce->base.first; base; base = next) {
- next = base->next;
+ for (Base *base_legacy_next, *base_legacy = sce->base.first; base_legacy; base_legacy = base_legacy_next) {
+ base_legacy_next = base_legacy->next;
- base->object = newlibadr_us(fd, sce->id.lib, base->object);
+ base_legacy->object = newlibadr_us(fd, sce->id.lib, base_legacy->object);
- if (base->object == NULL) {
+ if (base_legacy->object == NULL) {
blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: object lost from scene: '%s'"),
sce->id.name + 2);
- BLI_remlink(&sce->base, base);
- if (base == sce->basact) sce->basact = NULL;
- MEM_freeN(base);
+ BLI_remlink(&sce->base, base_legacy);
+ if (base_legacy == sce->basact) sce->basact = NULL;
+ MEM_freeN(base_legacy);
}
}
@@ -5879,7 +6131,7 @@ static void lib_link_scene(FileData *fd, Main *main)
BKE_sequencer_update_sound_bounds_all(sce);
- /* rigidbody world relies on it's linked groups */
+ /* rigidbody world relies on it's linked collections */
if (sce->rigidbody_world) {
RigidBodyWorld *rbw = sce->rigidbody_world;
if (rbw->group)
@@ -5898,7 +6150,6 @@ static void lib_link_scene(FileData *fd, Main *main)
for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) {
srl->mat_override = newlibadr_us(fd, sce->id.lib, srl->mat_override);
- srl->light_override = newlibadr_us(fd, sce->id.lib, srl->light_override);
for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
fmc->script = newlibadr(fd, sce->id.lib, fmc->script);
}
@@ -5907,12 +6158,23 @@ static void lib_link_scene(FileData *fd, Main *main)
fls->group = newlibadr_us(fd, sce->id.lib, fls->group);
}
}
- /*Game Settings: Dome Warp Text*/
- sce->gm.dome.warptext = newlibadr(fd, sce->id.lib, sce->gm.dome.warptext);
-
/* Motion Tracking */
sce->clip = newlibadr_us(fd, sce->id.lib, sce->clip);
+#ifdef USE_COLLECTION_COMPAT_28
+ if (sce->collection) {
+ lib_link_scene_collection(fd, sce->id.lib, sce->collection);
+ }
+#endif
+
+ if (sce->master_collection) {
+ lib_link_collection_data(fd, sce->id.lib, sce->master_collection);
+ }
+
+ for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ lib_link_view_layer(fd, sce->id.lib, view_layer);
+ }
+
#ifdef USE_SETSCENE_CHECK
if (sce->set != NULL) {
/* link flag for scenes with set would be reset later,
@@ -5963,7 +6225,7 @@ static void link_recurs_seq(FileData *fd, ListBase *lb)
}
}
-static void direct_link_paint(FileData *fd, Paint *p)
+static void direct_link_paint(FileData *fd, const Scene *scene, Paint *p)
{
if (p->num_input_samples < 1)
p->num_input_samples = 1;
@@ -5973,15 +6235,19 @@ static void direct_link_paint(FileData *fd, Paint *p)
direct_link_curvemapping(fd, p->cavity_curve);
else
BKE_paint_cavity_curve_preset(p, CURVE_PRESET_LINE);
+
+ p->tool_slots = newdataadr(fd, p->tool_slots);
+
+ BKE_paint_runtime_init(scene->toolsettings, p);
}
-static void direct_link_paint_helper(FileData *fd, Paint **paint)
+static void direct_link_paint_helper(FileData *fd, const Scene *scene, Paint **paint)
{
/* TODO. is this needed */
(*paint) = newdataadr(fd, (*paint));
if (*paint) {
- direct_link_paint(fd, *paint);
+ direct_link_paint(fd, scene, *paint);
}
}
@@ -6008,29 +6274,18 @@ static void direct_link_sequence_modifiers(FileData *fd, ListBase *lb)
}
}
-static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *view_settings)
-{
- view_settings->curve_mapping = newdataadr(fd, view_settings->curve_mapping);
-
- if (view_settings->curve_mapping)
- direct_link_curvemapping(fd, view_settings->curve_mapping);
-}
-
static void direct_link_scene(FileData *fd, Scene *sce)
{
Editing *ed;
Sequence *seq;
MetaStack *ms;
RigidBodyWorld *rbw;
+ ViewLayer *view_layer;
SceneRenderLayer *srl;
- sce->theDag = NULL;
- sce->depsgraph = NULL;
- sce->obedit = NULL;
- sce->stats = NULL;
+ sce->depsgraph_hash = NULL;
sce->fps_info = NULL;
sce->customdata_mask_modal = 0;
- sce->lay_updated = 0;
BKE_sound_create_scene(sce);
@@ -6049,12 +6304,13 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings = newdataadr(fd, sce->toolsettings);
if (sce->toolsettings) {
- direct_link_paint_helper(fd, (Paint **)&sce->toolsettings->sculpt);
- direct_link_paint_helper(fd, (Paint **)&sce->toolsettings->vpaint);
- direct_link_paint_helper(fd, (Paint **)&sce->toolsettings->wpaint);
- direct_link_paint_helper(fd, (Paint **)&sce->toolsettings->uvsculpt);
+ direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->sculpt);
+ direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->vpaint);
+ direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->wpaint);
+ direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->uvsculpt);
+ direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_paint);
- direct_link_paint(fd, &sce->toolsettings->imapaint.paint);
+ direct_link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
sce->toolsettings->imapaint.paintcursor = NULL;
sce->toolsettings->particle.paintcursor = NULL;
@@ -6062,28 +6318,16 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->particle.object = NULL;
sce->toolsettings->gp_sculpt.paintcursor = NULL;
- /* relink grease pencil drawing brushes */
- link_list(fd, &sce->toolsettings->gp_brushes);
- for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) {
- brush->cur_sensitivity = newdataadr(fd, brush->cur_sensitivity);
- if (brush->cur_sensitivity) {
- direct_link_curvemapping(fd, brush->cur_sensitivity);
- }
- brush->cur_strength = newdataadr(fd, brush->cur_strength);
- if (brush->cur_strength) {
- direct_link_curvemapping(fd, brush->cur_strength);
- }
- brush->cur_jitter = newdataadr(fd, brush->cur_jitter);
- if (brush->cur_jitter) {
- direct_link_curvemapping(fd, brush->cur_jitter);
- }
- }
-
/* relink grease pencil interpolation curves */
sce->toolsettings->gp_interpolate.custom_ipo = newdataadr(fd, sce->toolsettings->gp_interpolate.custom_ipo);
if (sce->toolsettings->gp_interpolate.custom_ipo) {
direct_link_curvemapping(fd, sce->toolsettings->gp_interpolate.custom_ipo);
}
+ /* relink grease pencil multiframe falloff curve */
+ sce->toolsettings->gp_sculpt.cur_falloff = newdataadr(fd, sce->toolsettings->gp_sculpt.cur_falloff);
+ if (sce->toolsettings->gp_sculpt.cur_falloff) {
+ direct_link_curvemapping(fd, sce->toolsettings->gp_sculpt.cur_falloff);
+ }
}
if (sce->ed) {
@@ -6204,11 +6448,6 @@ static void direct_link_scene(FileData *fd, Scene *sce)
}
}
-#ifdef DURIAN_CAMERA_SWITCH
- /* Runtime */
- sce->r.mode &= ~R_NO_CAMERA_SWITCH;
-#endif
-
sce->r.avicodecdata = newdataadr(fd, sce->r.avicodecdata);
if (sce->r.avicodecdata) {
sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat);
@@ -6228,11 +6467,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
for (srl = sce->r.layers.first; srl; srl = srl->next) {
srl->prop = newdataadr(fd, srl->prop);
IDP_DirectLinkGroup_OrFree(&srl->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- }
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
link_list(fd, &(srl->freestyleConfig.modules));
- }
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
link_list(fd, &(srl->freestyleConfig.linesets));
}
@@ -6247,10 +6482,34 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->rigidbody_world = newdataadr(fd, sce->rigidbody_world);
rbw = sce->rigidbody_world;
if (rbw) {
- /* must nullify the reference to physics sim object, since it no-longer exist
- * (and will need to be recalculated)
- */
- rbw->physics_world = NULL;
+ rbw->shared = newdataadr(fd, rbw->shared);
+
+ if (rbw->shared == NULL) {
+ /* Link deprecated caches if they exist, so we can use them for versioning.
+ * We should only do this when rbw->shared == NULL, because those pointers
+ * are always set (for compatibility with older Blenders). We mustn't link
+ * the same pointcache twice. */
+ direct_link_pointcache_list(fd, &rbw->ptcaches, &rbw->pointcache, false);
+
+ /* make sure simulation starts from the beginning after loading file */
+ if (rbw->pointcache) {
+ rbw->ltime = (float)rbw->pointcache->startframe;
+ }
+ }
+ else {
+ /* must nullify the reference to physics sim object, since it no-longer exist
+ * (and will need to be recalculated)
+ */
+ rbw->shared->physics_world = NULL;
+
+ /* link caches */
+ direct_link_pointcache_list(fd, &rbw->shared->ptcaches, &rbw->shared->pointcache, false);
+
+ /* make sure simulation starts from the beginning after loading file */
+ if (rbw->shared->pointcache) {
+ rbw->ltime = (float)rbw->shared->pointcache->startframe;
+ }
+ }
rbw->objects = NULL;
rbw->numbodies = 0;
@@ -6258,18 +6517,671 @@ static void direct_link_scene(FileData *fd, Scene *sce)
rbw->effector_weights = newdataadr(fd, rbw->effector_weights);
if (!rbw->effector_weights)
rbw->effector_weights = BKE_add_effector_weights(NULL);
-
- /* link cache */
- direct_link_pointcache_list(fd, &rbw->ptcaches, &rbw->pointcache, false);
- /* make sure simulation starts from the beginning after loading file */
- if (rbw->pointcache) {
- rbw->ltime = (float)rbw->pointcache->startframe;
- }
}
sce->preview = direct_link_preview_image(fd, sce->preview);
direct_link_curvemapping(fd, &sce->r.mblur_shutter_curve);
+
+#ifdef USE_COLLECTION_COMPAT_28
+ /* this runs before the very first doversion */
+ if (sce->collection) {
+ sce->collection = newdataadr(fd, sce->collection);
+ direct_link_scene_collection(fd, sce->collection);
+ }
+#endif
+
+ if (sce->master_collection) {
+ sce->master_collection = newdataadr(fd, sce->master_collection);
+ direct_link_collection(fd, sce->master_collection);
+ /* Needed because this is an ID outside of Main. */
+ sce->master_collection->id.py_instance = NULL;
+ }
+
+ /* insert into global old-new map for reading without UI (link_global accesses it again) */
+ link_glob_list(fd, &sce->view_layers);
+ for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ direct_link_view_layer(fd, view_layer);
+ }
+
+ if (fd->memfile) {
+ /* If it's undo try to recover the cache. */
+ if (fd->scenemap) sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache);
+ else sce->eevee.light_cache = NULL;
+ }
+ else {
+ /* else read the cache from file. */
+ if (sce->eevee.light_cache) {
+ sce->eevee.light_cache = newdataadr(fd, sce->eevee.light_cache);
+ direct_link_lightcache(fd, sce->eevee.light_cache);
+ }
+ }
+
+ sce->layer_properties = newdataadr(fd, sce->layer_properties);
+ IDP_DirectLinkGroup_OrFree(&sce->layer_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+}
+
+/* ****************** READ GREASE PENCIL ***************** */
+
+/* relink's grease pencil data's refs */
+static void lib_link_gpencil(FileData *fd, Main *main)
+{
+ /* Relink all datablock linked by GP datablock */
+ for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ if (gpd->id.tag & LIB_TAG_NEED_LINK) {
+ /* Layers */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Layer -> Parent References */
+ gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent);
+ }
+
+ /* Datablock Stuff */
+ IDP_LibLinkProperty(gpd->id.properties, fd);
+ lib_link_animdata(fd, &gpd->id, gpd->adt);
+
+ /* materials */
+ for (int a = 0; a < gpd->totcol; a++) {
+ gpd->mat[a] = newlibadr_us(fd, gpd->id.lib, gpd->mat[a]);
+ }
+
+ gpd->id.tag &= ~LIB_TAG_NEED_LINK;
+ }
+ }
+}
+
+/* relinks grease-pencil data - used for direct_link and old file linkage */
+static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
+{
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+ bGPDpalette *palette;
+
+ /* we must firstly have some grease-pencil data to link! */
+ if (gpd == NULL)
+ return;
+
+ /* relink animdata */
+ gpd->adt = newdataadr(fd, gpd->adt);
+ direct_link_animdata(fd, gpd->adt);
+
+ /* relink palettes (old palettes deprecated, only to convert old files) */
+ link_list(fd, &gpd->palettes);
+ if (gpd->palettes.first != NULL) {
+ for (palette = gpd->palettes.first; palette; palette = palette->next) {
+ link_list(fd, &palette->colors);
+ }
+ }
+
+ /* materials */
+ gpd->mat = newdataadr(fd, gpd->mat);
+ test_pointer_array(fd, (void **)&gpd->mat);
+
+ /* relink layers */
+ link_list(fd, &gpd->layers);
+
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* relink frames */
+ link_list(fd, &gpl->frames);
+
+ gpl->actframe = newdataadr(fd, gpl->actframe);
+
+ gpl->runtime.icon_id = 0;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* relink strokes (and their points) */
+ link_list(fd, &gpf->strokes);
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* relink stroke points array */
+ gps->points = newdataadr(fd, gps->points);
+
+ /* relink weight data */
+ if (gps->dvert) {
+ gps->dvert = newdataadr(fd, gps->dvert);
+ direct_link_dverts(fd, gps->totpoints, gps->dvert);
+ }
+
+ /* the triangulation is not saved, so need to be recalculated */
+ gps->triangles = NULL;
+ gps->tot_triangles = 0;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ }
+ }
+}
+
+/* *********** READ AREA **************** */
+
+static void direct_link_panel_list(FileData *fd, ListBase *lb)
+{
+ link_list(fd, lb);
+
+ for (Panel *pa = lb->first; pa; pa = pa->next) {
+ pa->paneltab = newdataadr(fd, pa->paneltab);
+ pa->runtime_flag = 0;
+ pa->activedata = NULL;
+ pa->type = NULL;
+ direct_link_panel_list(fd, &pa->children);
+ }
+}
+
+static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
+{
+ uiList *ui_list;
+
+ direct_link_panel_list(fd, &ar->panels);
+
+ link_list(fd, &ar->panels_category_active);
+
+ link_list(fd, &ar->ui_lists);
+
+ for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
+ ui_list->type = NULL;
+ ui_list->dyn_data = NULL;
+ ui_list->properties = newdataadr(fd, ui_list->properties);
+ IDP_DirectLinkGroup_OrFree(&ui_list->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+
+ link_list(fd, &ar->ui_previews);
+
+ if (spacetype == SPACE_EMPTY) {
+ /* unkown space type, don't leak regiondata */
+ ar->regiondata = NULL;
+ }
+ else if (ar->flag & RGN_FLAG_TEMP_REGIONDATA) {
+ /* Runtime data, don't use. */
+ ar->regiondata = NULL;
+ }
+ else {
+ ar->regiondata = newdataadr(fd, ar->regiondata);
+ if (ar->regiondata) {
+ if (spacetype == SPACE_VIEW3D) {
+ RegionView3D *rv3d = ar->regiondata;
+
+ rv3d->localvd = newdataadr(fd, rv3d->localvd);
+ rv3d->clipbb = newdataadr(fd, rv3d->clipbb);
+
+ rv3d->depths = NULL;
+ rv3d->gpuoffscreen = NULL;
+ rv3d->render_engine = NULL;
+ rv3d->sms = NULL;
+ rv3d->smooth_timer = NULL;
+ }
+ }
+ }
+
+ ar->v2d.tab_offset = NULL;
+ ar->v2d.tab_num = 0;
+ ar->v2d.tab_cur = 0;
+ ar->v2d.sms = NULL;
+ ar->v2d.alpha_hor = ar->v2d.alpha_vert = 255; /* visible by default */
+ BLI_listbase_clear(&ar->panels_category);
+ BLI_listbase_clear(&ar->handlers);
+ BLI_listbase_clear(&ar->uiblocks);
+ ar->headerstr = NULL;
+ ar->visible = 0;
+ ar->type = NULL;
+ ar->do_draw = 0;
+ ar->gizmo_map = NULL;
+ ar->regiontimer = NULL;
+ ar->draw_buffer = NULL;
+ memset(&ar->drawrct, 0, sizeof(ar->drawrct));
+}
+
+static void direct_link_area(FileData *fd, ScrArea *area)
+{
+ SpaceLink *sl;
+ ARegion *ar;
+
+ link_list(fd, &(area->spacedata));
+ link_list(fd, &(area->regionbase));
+
+ BLI_listbase_clear(&area->handlers);
+ area->type = NULL; /* spacetype callbacks */
+ area->butspacetype = SPACE_EMPTY; /* Should always be unset so that rna_Area_type_get works correctly */
+ area->region_active_win = -1;
+
+ area->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE;
+
+ area->global = newdataadr(fd, area->global);
+
+ /* if we do not have the spacetype registered we cannot
+ * free it, so don't allocate any new memory for such spacetypes. */
+ if (!BKE_spacetype_exists(area->spacetype)) {
+ area->butspacetype = area->spacetype; /* Hint for versioning code to replace deprecated space types. */
+ area->spacetype = SPACE_EMPTY;
+ }
+
+ for (ar = area->regionbase.first; ar; ar = ar->next) {
+ direct_link_region(fd, ar, area->spacetype);
+ }
+
+ /* accident can happen when read/save new file with older version */
+ /* 2.50: we now always add spacedata for info */
+ if (area->spacedata.first == NULL) {
+ SpaceInfo *sinfo = MEM_callocN(sizeof(SpaceInfo), "spaceinfo");
+ area->spacetype = sinfo->spacetype = SPACE_INFO;
+ BLI_addtail(&area->spacedata, sinfo);
+ }
+ /* add local view3d too */
+ else if (area->spacetype == SPACE_VIEW3D) {
+ blo_do_versions_view3d_split_250(area->spacedata.first, &area->regionbase);
+ }
+
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
+ link_list(fd, &(sl->regionbase));
+
+ /* if we do not have the spacetype registered we cannot
+ * free it, so don't allocate any new memory for such spacetypes. */
+ if (!BKE_spacetype_exists(sl->spacetype))
+ sl->spacetype = SPACE_EMPTY;
+
+ for (ar = sl->regionbase.first; ar; ar = ar->next)
+ direct_link_region(fd, ar, sl->spacetype);
+
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+
+ v3d->flag |= V3D_INVALID_BACKBUF;
+
+ if (v3d->gpd) {
+ v3d->gpd = newdataadr(fd, v3d->gpd);
+ direct_link_gpencil(fd, v3d->gpd);
+ }
+ v3d->localvd = newdataadr(fd, v3d->localvd);
+ v3d->properties_storage = NULL;
+
+ /* render can be quite heavy, set to solid on load */
+ if (v3d->shading.type == OB_RENDER) {
+ v3d->shading.type = OB_SOLID;
+ }
+ v3d->shading.prev_type = OB_SOLID;
+
+ if (v3d->fx_settings.dof)
+ v3d->fx_settings.dof = newdataadr(fd, v3d->fx_settings.dof);
+ if (v3d->fx_settings.ssao)
+ v3d->fx_settings.ssao = newdataadr(fd, v3d->fx_settings.ssao);
+
+ blo_do_versions_view3d_split_250(v3d, &sl->regionbase);
+ }
+ else if (sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
+
+ sipo->ads = newdataadr(fd, sipo->ads);
+ BLI_listbase_clear(&sipo->ghostCurves);
+ }
+ else if (sl->spacetype == SPACE_NLA) {
+ SpaceNla *snla = (SpaceNla *)sl;
+
+ snla->ads = newdataadr(fd, snla->ads);
+ }
+ else if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOops *soops = (SpaceOops *)sl;
+
+ /* use newdataadr_no_us and do not free old memory avoiding double
+ * frees and use of freed memory. this could happen because of a
+ * bug fixed in revision 58959 where the treestore memory address
+ * was not unique */
+ TreeStore *ts = newdataadr_no_us(fd, soops->treestore);
+ soops->treestore = NULL;
+ if (ts) {
+ TreeStoreElem *elems = newdataadr_no_us(fd, ts->data);
+
+ soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), ts->usedelem,
+ 512, BLI_MEMPOOL_ALLOW_ITER);
+ if (ts->usedelem && elems) {
+ int i;
+ for (i = 0; i < ts->usedelem; i++) {
+ TreeStoreElem *new_elem = BLI_mempool_alloc(soops->treestore);
+ *new_elem = elems[i];
+ }
+ }
+ /* we only saved what was used */
+ soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw
+ }
+ soops->treehash = NULL;
+ soops->tree.first = soops->tree.last = NULL;
+ }
+ else if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ sima->iuser.scene = NULL;
+ sima->iuser.ok = 1;
+ sima->scopes.waveform_1 = NULL;
+ sima->scopes.waveform_2 = NULL;
+ sima->scopes.waveform_3 = NULL;
+ sima->scopes.vecscope = NULL;
+ sima->scopes.ok = 0;
+
+ /* WARNING: gpencil data is no longer stored directly in sima after 2.5
+ * so sacrifice a few old files for now to avoid crashes with new files!
+ * committed: r28002 */
+#if 0
+ sima->gpd = newdataadr(fd, sima->gpd);
+ if (sima->gpd)
+ direct_link_gpencil(fd, sima->gpd);
+#endif
+ }
+ else if (sl->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)sl;
+
+ if (snode->gpd) {
+ snode->gpd = newdataadr(fd, snode->gpd);
+ direct_link_gpencil(fd, snode->gpd);
+ }
+
+ link_list(fd, &snode->treepath);
+ snode->edittree = NULL;
+ snode->iofsd = NULL;
+ BLI_listbase_clear(&snode->linkdrag);
+ }
+ else if (sl->spacetype == SPACE_TEXT) {
+ SpaceText *st = (SpaceText *)sl;
+
+ st->drawcache = NULL;
+ st->scroll_accum[0] = 0.0f;
+ st->scroll_accum[1] = 0.0f;
+ }
+ else if (sl->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ /* grease pencil data is not a direct data and can't be linked from direct_link*
+ * functions, it should be linked from lib_link* functions instead
+ *
+ * otherwise it'll lead to lost grease data on open because it'll likely be
+ * read from file after all other users of grease pencil and newdataadr would
+ * simple return NULL here (sergey)
+ */
+#if 0
+ if (sseq->gpd) {
+ sseq->gpd = newdataadr(fd, sseq->gpd);
+ direct_link_gpencil(fd, sseq->gpd);
+ }
+#endif
+ sseq->scopes.reference_ibuf = NULL;
+ sseq->scopes.zebra_ibuf = NULL;
+ sseq->scopes.waveform_ibuf = NULL;
+ sseq->scopes.sep_waveform_ibuf = NULL;
+ sseq->scopes.vector_ibuf = NULL;
+ sseq->scopes.histogram_ibuf = NULL;
+ sseq->compositor = NULL;
+ }
+ else if (sl->spacetype == SPACE_BUTS) {
+ SpaceButs *sbuts = (SpaceButs *)sl;
+
+ sbuts->path = NULL;
+ sbuts->texuser = NULL;
+ sbuts->mainbo = sbuts->mainb;
+ sbuts->mainbuser = sbuts->mainb;
+ }
+ else if (sl->spacetype == SPACE_CONSOLE) {
+ SpaceConsole *sconsole = (SpaceConsole *)sl;
+ ConsoleLine *cl, *cl_next;
+
+ link_list(fd, &sconsole->scrollback);
+ link_list(fd, &sconsole->history);
+
+ //for (cl= sconsole->scrollback.first; cl; cl= cl->next)
+ // cl->line= newdataadr(fd, cl->line);
+
+ /* comma expressions, (e.g. expr1, expr2, expr3) evaluate each expression,
+ * from left to right. the right-most expression sets the result of the comma
+ * expression as a whole*/
+ for (cl = sconsole->history.first; cl; cl = cl_next) {
+ cl_next = cl->next;
+ cl->line = newdataadr(fd, cl->line);
+ if (cl->line) {
+ /* the allocted length is not written, so reset here */
+ cl->len_alloc = cl->len + 1;
+ }
+ else {
+ BLI_remlink(&sconsole->history, cl);
+ MEM_freeN(cl);
+ }
+ }
+ }
+ else if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+
+ /* this sort of info is probably irrelevant for reloading...
+ * plus, it isn't saved to files yet!
+ */
+ sfile->folders_prev = sfile->folders_next = NULL;
+ sfile->files = NULL;
+ sfile->layout = NULL;
+ sfile->op = NULL;
+ sfile->previews_timer = NULL;
+ sfile->params = newdataadr(fd, sfile->params);
+ }
+ else if (sl->spacetype == SPACE_CLIP) {
+ SpaceClip *sclip = (SpaceClip *)sl;
+
+ sclip->scopes.track_search = NULL;
+ sclip->scopes.track_preview = NULL;
+ sclip->scopes.ok = 0;
+ }
+ }
+
+ BLI_listbase_clear(&area->actionzones);
+
+ area->v1 = newdataadr(fd, area->v1);
+ area->v2 = newdataadr(fd, area->v2);
+ area->v3 = newdataadr(fd, area->v3);
+ area->v4 = newdataadr(fd, area->v4);
+}
+
+static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area)
+{
+ area->full = newlibadr(fd, parent_id->lib, area->full);
+
+ memset(&area->runtime, 0x0, sizeof(area->runtime));
+
+ for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = (View3D *)sl;
+
+ v3d->camera = newlibadr(fd, parent_id->lib, v3d->camera);
+ v3d->ob_centre = newlibadr(fd, parent_id->lib, v3d->ob_centre);
+
+ if (v3d->localvd) {
+ v3d->localvd->camera = newlibadr(fd, parent_id->lib, v3d->localvd->camera);
+ }
+ break;
+ }
+ case SPACE_IPO:
+ {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
+ bDopeSheet *ads = sipo->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, parent_id->lib, ads->source);
+ ads->filter_grp = newlibadr(fd, parent_id->lib, ads->filter_grp);
+ }
+ break;
+ }
+ case SPACE_BUTS:
+ {
+ SpaceButs *sbuts = (SpaceButs *)sl;
+ sbuts->pinid = newlibadr(fd, parent_id->lib, sbuts->pinid);
+ if (sbuts->pinid == NULL) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
+ }
+ break;
+ }
+ case SPACE_FILE:
+ break;
+ case SPACE_ACTION:
+ {
+ SpaceAction *saction = (SpaceAction *)sl;
+ bDopeSheet *ads = &saction->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, parent_id->lib, ads->source);
+ ads->filter_grp = newlibadr(fd, parent_id->lib, ads->filter_grp);
+ }
+
+ saction->action = newlibadr(fd, parent_id->lib, saction->action);
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ sima->image = newlibadr_real_us(fd, parent_id->lib, sima->image);
+ sima->mask_info.mask = newlibadr_real_us(fd, parent_id->lib, sima->mask_info.mask);
+
+ /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
+ * so fingers crossed this works fine!
+ */
+ sima->gpd = newlibadr_us(fd, parent_id->lib, sima->gpd);
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
+ * so fingers crossed this works fine!
+ */
+ sseq->gpd = newlibadr_us(fd, parent_id->lib, sseq->gpd);
+ break;
+ }
+ case SPACE_NLA:
+ {
+ SpaceNla *snla = (SpaceNla *)sl;
+ bDopeSheet *ads = snla->ads;
+
+ if (ads) {
+ ads->source = newlibadr(fd, parent_id->lib, ads->source);
+ ads->filter_grp = newlibadr(fd, parent_id->lib, ads->filter_grp);
+ }
+ break;
+ }
+ case SPACE_TEXT:
+ {
+ SpaceText *st = (SpaceText *)sl;
+
+ st->text = newlibadr(fd, parent_id->lib, st->text);
+ break;
+ }
+ case SPACE_SCRIPT:
+ {
+ SpaceScript *scpt = (SpaceScript *)sl;
+ /*scpt->script = NULL; - 2.45 set to null, better re-run the script */
+ if (scpt->script) {
+ scpt->script = newlibadr(fd, parent_id->lib, scpt->script);
+ if (scpt->script) {
+ SCRIPT_SET_NULL(scpt->script);
+ }
+ }
+ break;
+ }
+ case SPACE_OUTLINER:
+ {
+ SpaceOops *so = (SpaceOops *)sl;
+ so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ tselem->id = newlibadr(fd, NULL, tselem->id);
+ }
+ if (so->treehash) {
+ /* rebuild hash table, because it depends on ids too */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+ break;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode = (SpaceNode *)sl;
+ bNodeTreePath *path, *path_next;
+ bNodeTree *ntree;
+
+ /* node tree can be stored locally in id too, link this first */
+ snode->id = newlibadr(fd, parent_id->lib, snode->id);
+ snode->from = newlibadr(fd, parent_id->lib, snode->from);
+
+ ntree = snode->id ? ntreeFromID(snode->id) : NULL;
+ snode->nodetree = ntree ? ntree : newlibadr_us(fd, parent_id->lib, snode->nodetree);
+
+ for (path = snode->treepath.first; path; path = path->next) {
+ if (path == snode->treepath.first) {
+ /* first nodetree in path is same as snode->nodetree */
+ path->nodetree = snode->nodetree;
+ }
+ else
+ path->nodetree = newlibadr_us(fd, parent_id->lib, path->nodetree);
+
+ if (!path->nodetree)
+ break;
+ }
+
+ /* remaining path entries are invalid, remove */
+ for (; path; path = path_next) {
+ path_next = path->next;
+
+ BLI_remlink(&snode->treepath, path);
+ MEM_freeN(path);
+ }
+
+ /* edittree is just the last in the path,
+ * set this directly since the path may have been shortened above */
+ if (snode->treepath.last) {
+ path = snode->treepath.last;
+ snode->edittree = path->nodetree;
+ }
+ else {
+ snode->edittree = NULL;
+ }
+ break;
+ }
+ case SPACE_CLIP:
+ {
+ SpaceClip *sclip = (SpaceClip *)sl;
+ sclip->clip = newlibadr_real_us(fd, parent_id->lib, sclip->clip);
+ sclip->mask_info.mask = newlibadr_real_us(fd, parent_id->lib, sclip->mask_info.mask);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * \return false on error.
+ */
+static bool direct_link_area_map(FileData *fd, ScrAreaMap *area_map)
+{
+ link_list(fd, &area_map->vertbase);
+ link_list(fd, &area_map->edgebase);
+ link_list(fd, &area_map->areabase);
+ for (ScrArea *area = area_map->areabase.first; area; area = area->next) {
+ direct_link_area(fd, area);
+ }
+
+ /* edges */
+ for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) {
+ se->v1 = newdataadr(fd, se->v1);
+ se->v2 = newdataadr(fd, se->v2);
+ BKE_screen_sort_scrvert(&se->v1, &se->v2);
+
+ if (se->v1 == NULL) {
+ BLI_remlink(&area_map->edgebase, se);
+
+ return false;
+ }
+ }
+
+ return true;
}
/* ************ READ WM ***************** */
@@ -6282,9 +7194,20 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
link_list(fd, &wm->windows);
for (win = wm->windows.first; win; win = win->next) {
+ win->parent = newdataadr(fd, win->parent);
+
+ WorkSpaceInstanceHook *hook = win->workspace_hook;
+ win->workspace_hook = newdataadr(fd, hook);
+
+ /* we need to restore a pointer to this later when reading workspaces, so store in global oldnew-map */
+ oldnewmap_insert(fd->globmap, hook, win->workspace_hook, 0);
+
+ direct_link_area_map(fd, &win->global_areas);
+
win->ghostwin = NULL;
+ win->gpuctx = NULL;
win->eventstate = NULL;
- win->curswin = NULL;
+ win->cursor_keymap_status = NULL;
win->tweak = NULL;
#ifdef WIN32
win->ime_data = NULL;
@@ -6293,12 +7216,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
BLI_listbase_clear(&win->queue);
BLI_listbase_clear(&win->handlers);
BLI_listbase_clear(&win->modalhandlers);
- BLI_listbase_clear(&win->subwindows);
BLI_listbase_clear(&win->gesture);
- BLI_listbase_clear(&win->drawdata);
- win->drawmethod = -1;
- win->drawfail = 0;
win->active = 0;
win->cursor = 0;
@@ -6306,7 +7225,6 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
win->modalcursor = 0;
win->grabcursor = 0;
win->addmousemove = true;
- win->multisamples = 0;
win->stereo3d_format = newdataadr(fd, win->stereo3d_format);
/* multiview always fallback to anaglyph at file opening
@@ -6328,6 +7246,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
wm->userconf = NULL;
wm->undo_stack = NULL;
+ wm->message_bus = NULL;
+
BLI_listbase_clear(&wm->jobs);
BLI_listbase_clear(&wm->drags);
@@ -6347,7 +7267,16 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
if (wm->id.tag & LIB_TAG_NEED_LINK) {
/* Note: WM IDProperties are never written to file, hence no need to read/link them here. */
for (win = wm->windows.first; win; win = win->next) {
+ if (win->workspace_hook) { /* NULL for old files */
+ lib_link_workspace_instance_hook(fd, win->workspace_hook, &wm->id);
+ }
+ win->scene = newlibadr(fd, wm->id.lib, win->scene);
+ /* deprecated, but needed for versioning (will be NULL'ed then) */
win->screen = newlibadr(fd, NULL, win->screen);
+
+ for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ lib_link_area(fd, &wm->id, area);
+ }
}
wm->id.tag &= ~LIB_TAG_NEED_LINK;
@@ -6355,72 +7284,6 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
}
}
-/* ****************** READ GREASE PENCIL ***************** */
-
-/* relink's grease pencil data's refs */
-static void lib_link_gpencil(FileData *fd, Main *main)
-{
- for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
- if (gpd->id.tag & LIB_TAG_NEED_LINK) {
- IDP_LibLinkProperty(gpd->id.properties, fd);
- lib_link_animdata(fd, &gpd->id, gpd->adt);
-
- gpd->id.tag &= ~LIB_TAG_NEED_LINK;
- }
- }
-}
-
-/* relinks grease-pencil data - used for direct_link and old file linkage */
-static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
-{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
- bGPDpalette *palette;
-
- /* we must firstly have some grease-pencil data to link! */
- if (gpd == NULL)
- return;
-
- /* 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);
-
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- /* relink strokes (and their points) */
- link_list(fd, &gpf->strokes);
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- gps->points = newdataadr(fd, gps->points);
-
- /* the triangulation is not saved, so need to be recalculated */
- gps->triangles = NULL;
- gps->tot_triangles = 0;
- gps->flag |= GP_STROKE_RECALC_CACHES;
- /* the color pointer is not saved, so need to be recalculated using the color name */
- gps->palcolor = NULL;
- gps->flag |= GP_STROKE_RECALC_COLOR;
- }
- }
- }
-}
-
/* ****************** READ SCREEN ***************** */
/* note: file read without screens option G_FILE_NO_UI;
@@ -6430,219 +7293,16 @@ static void lib_link_screen(FileData *fd, Main *main)
for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) {
if (sc->id.tag & LIB_TAG_NEED_LINK) {
IDP_LibLinkProperty(sc->id.properties, fd);
- id_us_ensure_real(&sc->id);
+ /* deprecated, but needed for versioning (will be NULL'ed then) */
sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
- /* this should not happen, but apparently it does somehow. Until we figure out the cause,
- * just assign first available scene */
- if (!sc->scene)
- sc->scene = main->scene.first;
-
sc->animtimer = NULL; /* saved in rare cases */
sc->tool_tip = NULL;
sc->scrubbing = false;
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- sa->full = newlibadr(fd, sc->id.lib, sa->full);
-
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- switch (sl->spacetype) {
- case SPACE_VIEW3D:
- {
- View3D *v3d = (View3D *)sl;
- BGpic *bgpic = NULL;
-
- v3d->camera = newlibadr(fd, sc->id.lib, v3d->camera);
- v3d->ob_centre = newlibadr(fd, sc->id.lib, v3d->ob_centre);
-
- /* should be do_versions but not easy adding into the listbase */
- if (v3d->bgpic) {
- v3d->bgpic = newlibadr(fd, sc->id.lib, v3d->bgpic);
- BLI_addtail(&v3d->bgpicbase, bgpic);
- v3d->bgpic = NULL;
- }
-
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- bgpic->ima = newlibadr_us(fd, sc->id.lib, bgpic->ima);
- bgpic->clip = newlibadr_us(fd, sc->id.lib, bgpic->clip);
- }
- if (v3d->localvd) {
- v3d->localvd->camera = newlibadr(fd, sc->id.lib, v3d->localvd->camera);
- }
- break;
- }
- case SPACE_IPO:
- {
- SpaceIpo *sipo = (SpaceIpo *)sl;
- bDopeSheet *ads = sipo->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
- }
- break;
- }
- case SPACE_BUTS:
- {
- SpaceButs *sbuts = (SpaceButs *)sl;
- sbuts->pinid = newlibadr(fd, sc->id.lib, sbuts->pinid);
- if (sbuts->pinid == NULL) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
- }
- break;
- }
- case SPACE_FILE:
- break;
- case SPACE_ACTION:
- {
- SpaceAction *saction = (SpaceAction *)sl;
- bDopeSheet *ads = &saction->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
- }
-
- saction->action = newlibadr(fd, sc->id.lib, saction->action);
- break;
- }
- case SPACE_IMAGE:
- {
- SpaceImage *sima = (SpaceImage *)sl;
-
- sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image);
- sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask);
-
- /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
- * so fingers crossed this works fine!
- */
- sima->gpd = newlibadr_us(fd, sc->id.lib, sima->gpd);
- break;
- }
- case SPACE_SEQ:
- {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
- * so fingers crossed this works fine!
- */
- sseq->gpd = newlibadr_us(fd, sc->id.lib, sseq->gpd);
- break;
- }
- case SPACE_NLA:
- {
- SpaceNla *snla = (SpaceNla *)sl;
- bDopeSheet *ads = snla->ads;
-
- if (ads) {
- ads->source = newlibadr(fd, sc->id.lib, ads->source);
- ads->filter_grp = newlibadr(fd, sc->id.lib, ads->filter_grp);
- }
- break;
- }
- case SPACE_TEXT:
- {
- SpaceText *st = (SpaceText *)sl;
-
- st->text = newlibadr(fd, sc->id.lib, st->text);
- break;
- }
- case SPACE_SCRIPT:
- {
- SpaceScript *scpt = (SpaceScript *)sl;
- /*scpt->script = NULL; - 2.45 set to null, better re-run the script */
- if (scpt->script) {
- scpt->script = newlibadr(fd, sc->id.lib, scpt->script);
- if (scpt->script) {
- SCRIPT_SET_NULL(scpt->script);
- }
- }
- break;
- }
- case SPACE_OUTLINER:
- {
- SpaceOops *so = (SpaceOops *)sl;
- so->search_tse.id = newlibadr(fd, NULL, so->search_tse.id);
-
- if (so->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
-
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- tselem->id = newlibadr(fd, NULL, tselem->id);
- }
- if (so->treehash) {
- /* rebuild hash table, because it depends on ids too */
- so->storeflag |= SO_TREESTORE_REBUILD;
- }
- }
- break;
- }
- case SPACE_NODE:
- {
- SpaceNode *snode = (SpaceNode *)sl;
- bNodeTreePath *path, *path_next;
- bNodeTree *ntree;
-
- /* node tree can be stored locally in id too, link this first */
- snode->id = newlibadr(fd, sc->id.lib, snode->id);
- snode->from = newlibadr(fd, sc->id.lib, snode->from);
-
- 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) {
- /* first nodetree in path is same as snode->nodetree */
- path->nodetree = snode->nodetree;
- }
- else
- path->nodetree = newlibadr_us(fd, sc->id.lib, path->nodetree);
-
- if (!path->nodetree)
- break;
- }
-
- /* remaining path entries are invalid, remove */
- for (; path; path = path_next) {
- path_next = path->next;
-
- BLI_remlink(&snode->treepath, path);
- MEM_freeN(path);
- }
-
- /* edittree is just the last in the path,
- * set this directly since the path may have been shortened above */
- if (snode->treepath.last) {
- path = snode->treepath.last;
- snode->edittree = path->nodetree;
- }
- else {
- snode->edittree = NULL;
- }
- break;
- }
- case SPACE_CLIP:
- {
- SpaceClip *sclip = (SpaceClip *)sl;
-
- sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip);
- sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask);
- break;
- }
- case SPACE_LOGIC:
- {
- SpaceLogic *slogic = (SpaceLogic *)sl;
-
- slogic->gpd = newlibadr_us(fd, sc->id.lib, slogic->gpd);
- break;
- }
- default:
- break;
- }
- }
+ for (ScrArea *area = sc->areabase.first; area; area = area->next) {
+ lib_link_area(fd, &sc->id, area);
}
sc->id.tag &= ~LIB_TAG_NEED_LINK;
}
@@ -6747,93 +7407,66 @@ static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
-/* called from kernel/blender.c */
-/* used to link a file (without UI) to the current UI */
-/* note that it assumes the old pointers in UI are still valid, so old Main is not freed */
-void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *curscene)
+static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)
{
- wmWindow *win;
- wmWindowManager *wm;
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
- struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+
+ if (v3d->camera == NULL || v3d->scenelock) {
+ v3d->camera = scene->camera;
+ }
- /* first windowmanager */
- for (wm = newmain->wm.first; wm; wm = wm->id.next) {
- for (win = wm->windows.first; win; win = win->next) {
- win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL);
+ if (v3d->localvd) {
+ Base *base = NULL;
- if (win->screen == NULL)
- win->screen = curscreen;
+ v3d->localvd->camera = scene->camera;
- win->screen->winid = win->winid;
+ /* Localview can become invalid during undo/redo steps, so we exit it when no could be found. */
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->local_view_bits & v3d->local_view_uuid) {
+ break;
+ }
+ }
+ if (base == NULL) {
+ MEM_freeN(v3d->localvd);
+ v3d->localvd = NULL;
+ v3d->local_view_uuid = 0;
+
+ for (ARegion *ar = area->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->localvd) {
+ MEM_freeN(rv3d->localvd);
+ rv3d->localvd = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
}
}
+}
+static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, Main *newmain, WorkSpaceLayout *layout)
+{
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
- for (sc = newmain->screen.first; sc; sc = sc->id.next) {
- Scene *oldscene = sc->scene;
-
- sc->scene = restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL);
- if (sc->scene == NULL)
- sc->scene = curscene;
-
- /* keep cursor location through undo */
- copy_v3_v3(sc->scene->cursor, oldscene->cursor);
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
-
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ /* avoid conflicts with 2.8x branch */
+ {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
- BGpic *bgpic;
ARegion *ar;
- if (v3d->scenelock)
- v3d->camera = NULL; /* always get from scene */
- else
- v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
- if (v3d->camera == NULL)
- v3d->camera = sc->scene->camera;
+ v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL);
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- if ((bgpic->ima = restore_pointer_by_name(id_map, (ID *)bgpic->ima, USER_IGNORE))) {
- id_us_plus((ID *)bgpic->ima);
- }
- if ((bgpic->clip = restore_pointer_by_name(id_map, (ID *)bgpic->clip, USER_IGNORE))) {
- id_us_plus((ID *)bgpic->clip);
- }
- }
- if (v3d->localvd) {
- /*Base *base;*/
-
- v3d->localvd->camera = sc->scene->camera;
-
- /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
-#if 0 /* XXX regionlocalview ? */
- for (base = sc->scene->base.first; base; base = base->next) {
- if (base->lay & v3d->lay) {
- break;
- }
- }
- if (base == NULL) {
- v3d->lay = v3d->localvd->lay;
- v3d->layact = v3d->localvd->layact;
- MEM_freeN(v3d->localvd);
- v3d->localvd = NULL;
- }
-#endif
- }
- else if (v3d->scenelock) {
- v3d->lay = sc->scene->lay;
- }
-
- /* not very nice, but could help */
- if ((v3d->layact & v3d->lay) == 0) v3d->layact = v3d->lay;
-
/* free render engines for now */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_WINDOW) {
@@ -7025,89 +7658,55 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
sclip->scopes.ok = 0;
}
- else if (sl->spacetype == SPACE_LOGIC) {
- SpaceLogic *slogic = (SpaceLogic *)sl;
-
- slogic->gpd = restore_pointer_by_name(id_map, (ID *)slogic->gpd, USER_REAL);
- }
}
}
}
-
- /* update IDs stored in all possible clipboards */
- lib_link_clipboard_restore(id_map);
-
- BKE_main_idmap_destroy(id_map);
}
-static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
+/**
+ * Used to link a file (without UI) to the current UI.
+ * Note that it assumes the old pointers in UI are still valid, so old Main is not freed.
+ */
+void blo_lib_link_restore(Main *newmain, wmWindowManager *curwm, Scene *curscene, ViewLayer *cur_view_layer)
{
- Panel *pa;
- uiList *ui_list;
+ struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
- link_list(fd, &ar->panels);
+ for (WorkSpace *workspace = newmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
- for (pa = ar->panels.first; pa; pa = pa->next) {
- pa->paneltab = newdataadr(fd, pa->paneltab);
- pa->runtime_flag = 0;
- pa->activedata = NULL;
- pa->type = NULL;
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ lib_link_workspace_layout_restore(id_map, newmain, layout);
+ }
}
- link_list(fd, &ar->panels_category_active);
-
- link_list(fd, &ar->ui_lists);
+ for (wmWindow *win = curwm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ ID *workspace_id = (ID *)workspace;
+ Scene *oldscene = win->scene;
- for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
- ui_list->type = NULL;
- ui_list->dyn_data = NULL;
- ui_list->properties = newdataadr(fd, ui_list->properties);
- IDP_DirectLinkGroup_OrFree(&ui_list->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- }
+ workspace = restore_pointer_by_name(id_map, workspace_id, USER_REAL);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ win->scene = restore_pointer_by_name(id_map, (ID *)win->scene, USER_REAL);
+ if (win->scene == NULL) {
+ win->scene = curscene;
+ }
+ if (BKE_view_layer_find(win->scene, win->view_layer_name) == NULL) {
+ STRNCPY(win->view_layer_name, cur_view_layer->name);
+ }
+ BKE_workspace_active_set(win->workspace_hook, workspace);
- link_list(fd, &ar->ui_previews);
+ /* keep cursor location through undo */
+ copy_v3_v3(win->scene->cursor.location, oldscene->cursor.location);
+ copy_qt_qt(win->scene->cursor.rotation, oldscene->cursor.rotation);
+ lib_link_window_scene_data_restore(win, win->scene, cur_view_layer);
- if (spacetype == SPACE_EMPTY) {
- /* unkown space type, don't leak regiondata */
- ar->regiondata = NULL;
- }
- else if (ar->flag & RGN_FLAG_TEMP_REGIONDATA) {
- /* Runtime data, don't use. */
- ar->regiondata = NULL;
+ BLI_assert(win->screen == NULL);
}
- else {
- ar->regiondata = newdataadr(fd, ar->regiondata);
- if (ar->regiondata) {
- if (spacetype == SPACE_VIEW3D) {
- RegionView3D *rv3d = ar->regiondata;
- rv3d->localvd = newdataadr(fd, rv3d->localvd);
- rv3d->clipbb = newdataadr(fd, rv3d->clipbb);
-
- rv3d->depths = NULL;
- rv3d->gpuoffscreen = NULL;
- rv3d->render_engine = NULL;
- rv3d->sms = NULL;
- rv3d->smooth_timer = NULL;
- rv3d->compositor = NULL;
- }
- }
- }
+ /* update IDs stored in all possible clipboards */
+ lib_link_clipboard_restore(id_map);
- ar->v2d.tab_offset = NULL;
- ar->v2d.tab_num = 0;
- ar->v2d.tab_cur = 0;
- ar->v2d.sms = NULL;
- BLI_listbase_clear(&ar->panels_category);
- BLI_listbase_clear(&ar->handlers);
- BLI_listbase_clear(&ar->uiblocks);
- ar->headerstr = NULL;
- ar->swinid = 0;
- ar->type = NULL;
- ar->swap = 0;
- ar->do_draw = 0;
- ar->regiontimer = NULL;
- memset(&ar->drawrct, 0, sizeof(ar->drawrct));
+ BKE_main_idmap_destroy(id_map);
}
/* for the saved 2.50 files without regiondata */
@@ -7130,308 +7729,23 @@ void blo_do_versions_view3d_split_250(View3D *v3d, ListBase *regions)
}
/* this was not initialized correct always */
- if (v3d->twtype == 0)
- v3d->twtype = V3D_MANIP_TRANSLATE;
if (v3d->gridsubdiv == 0)
v3d->gridsubdiv = 10;
}
static bool direct_link_screen(FileData *fd, bScreen *sc)
{
- ScrArea *sa;
- ScrVert *sv;
- ScrEdge *se;
bool wrong_id = false;
- link_list(fd, &(sc->vertbase));
- link_list(fd, &(sc->edgebase));
- link_list(fd, &(sc->areabase));
sc->regionbase.first = sc->regionbase.last = NULL;
sc->context = NULL;
+ sc->active_region = NULL;
- sc->mainwin = sc->subwinactive = 0; /* indices */
- sc->swap = 0;
-
- /* edges */
- for (se = sc->edgebase.first; se; se = se->next) {
- se->v1 = newdataadr(fd, se->v1);
- se->v2 = newdataadr(fd, se->v2);
- if ((intptr_t)se->v1 > (intptr_t)se->v2) {
- sv = se->v1;
- se->v1 = se->v2;
- se->v2 = sv;
- }
-
- if (se->v1 == NULL) {
- printf("Error reading Screen %s... removing it.\n", sc->id.name + 2);
- BLI_remlink(&sc->edgebase, se);
- wrong_id = true;
- }
- }
-
- /* areas */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- ARegion *ar;
-
- link_list(fd, &(sa->spacedata));
- link_list(fd, &(sa->regionbase));
-
- BLI_listbase_clear(&sa->handlers);
- sa->type = NULL; /* spacetype callbacks */
- sa->region_active_win = -1;
-
- /* if we do not have the spacetype registered (game player), we cannot
- * free it, so don't allocate any new memory for such spacetypes. */
- if (!BKE_spacetype_exists(sa->spacetype))
- sa->spacetype = SPACE_EMPTY;
-
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- direct_link_region(fd, ar, sa->spacetype);
-
- /* accident can happen when read/save new file with older version */
- /* 2.50: we now always add spacedata for info */
- if (sa->spacedata.first == NULL) {
- SpaceInfo *sinfo = MEM_callocN(sizeof(SpaceInfo), "spaceinfo");
- sa->spacetype = sinfo->spacetype = SPACE_INFO;
- BLI_addtail(&sa->spacedata, sinfo);
- }
- /* add local view3d too */
- else if (sa->spacetype == SPACE_VIEW3D)
- blo_do_versions_view3d_split_250(sa->spacedata.first, &sa->regionbase);
-
- /* incase we set above */
- sa->butspacetype = sa->spacetype;
-
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- link_list(fd, &(sl->regionbase));
-
- /* if we do not have the spacetype registered (game player), we cannot
- * free it, so don't allocate any new memory for such spacetypes. */
- if (!BKE_spacetype_exists(sl->spacetype))
- sl->spacetype = SPACE_EMPTY;
-
- for (ar = sl->regionbase.first; ar; ar = ar->next)
- direct_link_region(fd, ar, sl->spacetype);
-
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- BGpic *bgpic;
-
- v3d->flag |= V3D_INVALID_BACKBUF;
-
- link_list(fd, &v3d->bgpicbase);
-
- /* should be do_versions except this doesnt fit well there */
- if (v3d->bgpic) {
- bgpic = newdataadr(fd, v3d->bgpic);
- BLI_addtail(&v3d->bgpicbase, bgpic);
- v3d->bgpic = NULL;
- }
-
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next)
- bgpic->iuser.ok = 1;
-
- if (v3d->gpd) {
- v3d->gpd = newdataadr(fd, v3d->gpd);
- direct_link_gpencil(fd, v3d->gpd);
- }
- v3d->localvd = newdataadr(fd, v3d->localvd);
- BLI_listbase_clear(&v3d->afterdraw_transp);
- BLI_listbase_clear(&v3d->afterdraw_xray);
- BLI_listbase_clear(&v3d->afterdraw_xraytransp);
- v3d->properties_storage = NULL;
- v3d->defmaterial = NULL;
-
- /* render can be quite heavy, set to solid on load */
- if (v3d->drawtype == OB_RENDER)
- v3d->drawtype = OB_SOLID;
- v3d->prev_drawtype = OB_SOLID;
-
- if (v3d->fx_settings.dof)
- v3d->fx_settings.dof = newdataadr(fd, v3d->fx_settings.dof);
- if (v3d->fx_settings.ssao)
- v3d->fx_settings.ssao = newdataadr(fd, v3d->fx_settings.ssao);
-
- blo_do_versions_view3d_split_250(v3d, &sl->regionbase);
- }
- else if (sl->spacetype == SPACE_IPO) {
- SpaceIpo *sipo = (SpaceIpo *)sl;
-
- sipo->ads = newdataadr(fd, sipo->ads);
- BLI_listbase_clear(&sipo->ghostCurves);
- }
- else if (sl->spacetype == SPACE_NLA) {
- SpaceNla *snla = (SpaceNla *)sl;
-
- snla->ads = newdataadr(fd, snla->ads);
- }
- else if (sl->spacetype == SPACE_OUTLINER) {
- SpaceOops *soops = (SpaceOops *)sl;
-
- /* use newdataadr_no_us and do not free old memory avoiding double
- * frees and use of freed memory. this could happen because of a
- * bug fixed in revision 58959 where the treestore memory address
- * was not unique */
- TreeStore *ts = newdataadr_no_us(fd, soops->treestore);
- soops->treestore = NULL;
- if (ts) {
- TreeStoreElem *elems = newdataadr_no_us(fd, ts->data);
-
- soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), ts->usedelem,
- 512, BLI_MEMPOOL_ALLOW_ITER);
- if (ts->usedelem && elems) {
- int i;
- for (i = 0; i < ts->usedelem; i++) {
- TreeStoreElem *new_elem = BLI_mempool_alloc(soops->treestore);
- *new_elem = elems[i];
- }
- }
- /* we only saved what was used */
- soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw
- }
- soops->treehash = NULL;
- soops->tree.first = soops->tree.last = NULL;
- }
- else if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- sima->iuser.scene = NULL;
- sima->iuser.ok = 1;
- sima->scopes.waveform_1 = NULL;
- sima->scopes.waveform_2 = NULL;
- sima->scopes.waveform_3 = NULL;
- sima->scopes.vecscope = NULL;
- sima->scopes.ok = 0;
-
- /* WARNING: gpencil data is no longer stored directly in sima after 2.5
- * so sacrifice a few old files for now to avoid crashes with new files!
- * committed: r28002 */
-#if 0
- sima->gpd = newdataadr(fd, sima->gpd);
- if (sima->gpd)
- direct_link_gpencil(fd, sima->gpd);
-#endif
- }
- else if (sl->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)sl;
-
- if (snode->gpd) {
- snode->gpd = newdataadr(fd, snode->gpd);
- direct_link_gpencil(fd, snode->gpd);
- }
-
- link_list(fd, &snode->treepath);
- snode->edittree = NULL;
- snode->iofsd = NULL;
- BLI_listbase_clear(&snode->linkdrag);
- }
- else if (sl->spacetype == SPACE_TEXT) {
- SpaceText *st = (SpaceText *)sl;
-
- st->drawcache = NULL;
- st->scroll_accum[0] = 0.0f;
- st->scroll_accum[1] = 0.0f;
- }
- else if (sl->spacetype == SPACE_TIME) {
- SpaceTime *stime = (SpaceTime *)sl;
- BLI_listbase_clear(&stime->caches);
- }
- else if (sl->spacetype == SPACE_LOGIC) {
- SpaceLogic *slogic = (SpaceLogic *)sl;
-
- /* XXX: this is new stuff, which shouldn't be directly linking to gpd... */
- if (slogic->gpd) {
- slogic->gpd = newdataadr(fd, slogic->gpd);
- direct_link_gpencil(fd, slogic->gpd);
- }
- }
- else if (sl->spacetype == SPACE_SEQ) {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- /* grease pencil data is not a direct data and can't be linked from direct_link*
- * functions, it should be linked from lib_link* functions instead
- *
- * otherwise it'll lead to lost grease data on open because it'll likely be
- * read from file after all other users of grease pencil and newdataadr would
- * simple return NULL here (sergey)
- */
-#if 0
- if (sseq->gpd) {
- sseq->gpd = newdataadr(fd, sseq->gpd);
- direct_link_gpencil(fd, sseq->gpd);
- }
-#endif
- sseq->scopes.reference_ibuf = NULL;
- sseq->scopes.zebra_ibuf = NULL;
- sseq->scopes.waveform_ibuf = NULL;
- sseq->scopes.sep_waveform_ibuf = NULL;
- sseq->scopes.vector_ibuf = NULL;
- sseq->scopes.histogram_ibuf = NULL;
- sseq->compositor = NULL;
- }
- else if (sl->spacetype == SPACE_BUTS) {
- SpaceButs *sbuts = (SpaceButs *)sl;
-
- sbuts->path = NULL;
- sbuts->texuser = NULL;
- sbuts->mainbo = sbuts->mainb;
- sbuts->mainbuser = sbuts->mainb;
- }
- else if (sl->spacetype == SPACE_CONSOLE) {
- SpaceConsole *sconsole = (SpaceConsole *)sl;
- ConsoleLine *cl, *cl_next;
-
- link_list(fd, &sconsole->scrollback);
- link_list(fd, &sconsole->history);
-
- //for (cl= sconsole->scrollback.first; cl; cl= cl->next)
- // cl->line= newdataadr(fd, cl->line);
-
- /* comma expressions, (e.g. expr1, expr2, expr3) evaluate each expression,
- * from left to right. the right-most expression sets the result of the comma
- * expression as a whole*/
- for (cl = sconsole->history.first; cl; cl = cl_next) {
- cl_next = cl->next;
- cl->line = newdataadr(fd, cl->line);
- if (cl->line) {
- /* the allocted length is not written, so reset here */
- cl->len_alloc = cl->len + 1;
- }
- else {
- BLI_remlink(&sconsole->history, cl);
- MEM_freeN(cl);
- }
- }
- }
- else if (sl->spacetype == SPACE_FILE) {
- SpaceFile *sfile = (SpaceFile *)sl;
-
- /* this sort of info is probably irrelevant for reloading...
- * plus, it isn't saved to files yet!
- */
- sfile->folders_prev = sfile->folders_next = NULL;
- sfile->files = NULL;
- sfile->layout = NULL;
- sfile->op = NULL;
- sfile->previews_timer = NULL;
- sfile->params = newdataadr(fd, sfile->params);
- }
- else if (sl->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = (SpaceClip *)sl;
-
- sclip->scopes.track_search = NULL;
- sclip->scopes.track_preview = NULL;
- sclip->scopes.ok = 0;
- }
- }
+ sc->preview = direct_link_preview_image(fd, sc->preview);
- BLI_listbase_clear(&sa->actionzones);
-
- sa->v1 = newdataadr(fd, sa->v1);
- sa->v2 = newdataadr(fd, sa->v2);
- sa->v3 = newdataadr(fd, sa->v3);
- sa->v4 = newdataadr(fd, sa->v4);
+ if (!direct_link_area_map(fd, AREAMAP_FROM_SCREEN(sc))) {
+ printf("Error reading Screen %s... removing it.\n", sc->id.name + 2);
+ wrong_id = true;
}
return wrong_id;
@@ -7525,6 +7839,28 @@ static void fix_relpaths_library(const char *basepath, Main *main)
}
}
+/* ************ READ PROBE ***************** */
+
+static void lib_link_lightprobe(FileData *fd, Main *main)
+{
+ for (LightProbe *prb = main->lightprobe.first; prb; prb = prb->id.next) {
+ if (prb->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(prb->id.properties, fd);
+ lib_link_animdata(fd, &prb->id, prb->adt);
+
+ prb->visibility_grp = newlibadr(fd, prb->id.lib, prb->visibility_grp);
+
+ prb->id.tag &= ~LIB_TAG_NEED_LINK;
+ }
+ }
+}
+
+static void direct_link_lightprobe(FileData *fd, LightProbe *prb)
+{
+ prb->adt = newdataadr(fd, prb->adt);
+ direct_link_animdata(fd, prb->adt);
+}
+
/* ************ READ SPEAKER ***************** */
static void lib_link_speaker(FileData *fd, Main *main)
@@ -7599,40 +7935,6 @@ static void lib_link_sound(FileData *fd, Main *main)
}
}
}
-/* ***************** READ GROUP *************** */
-
-static void direct_link_group(FileData *fd, Group *group)
-{
- link_list(fd, &group->gobject);
-
- group->preview = direct_link_preview_image(fd, group->preview);
-}
-
-static void lib_link_group(FileData *fd, Main *bmain)
-{
- for (Group *group = bmain->group.first; group; group = group->id.next) {
- if (group->id.tag & LIB_TAG_NEED_LINK) {
- IDP_LibLinkProperty(group->id.properties, fd);
-
- bool add_us = false;
-
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
- if (go->ob) {
- go->ob->flag |= OB_FROMGROUP;
- /* if group has an object, it increments user... */
- add_us = true;
- }
- }
- if (add_us) {
- id_us_ensure_real(&group->id);
- }
- BKE_group_object_unlink(bmain, group, NULL, NULL, NULL); /* removes NULL entries */
-
- group->id.tag &= ~LIB_TAG_NEED_LINK;
- }
- }
-}
/* ***************** READ MOVIECLIP *************** */
@@ -8142,6 +8444,7 @@ static const char *dataname(short id_code)
case ID_VF: return "Data from VF";
case ID_TXT: return "Data from TXT";
case ID_SPK: return "Data from SPK";
+ case ID_LP: return "Data from LP";
case ID_SO: return "Data from SO";
case ID_NT: return "Data from NT";
case ID_BR: return "Data from BR";
@@ -8154,6 +8457,7 @@ static const char *dataname(short id_code)
case ID_MSK: return "Data from MSK";
case ID_LS: return "Data from LS";
case ID_CF: return "Data from CF";
+ case ID_WS: return "Data from WS";
}
return "Data from Lib Block";
@@ -8276,6 +8580,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
+ id->orig_id = NULL;
id->recalc = 0;
/* this case cannot be direct_linked: it's just the ID part */
@@ -8363,8 +8668,11 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
case ID_SO:
direct_link_sound(fd, (bSound *)id);
break;
+ case ID_LP:
+ direct_link_lightprobe(fd, (LightProbe *)id);
+ break;
case ID_GR:
- direct_link_group(fd, (Group *)id);
+ direct_link_collection(fd, (Collection *)id);
break;
case ID_AR:
direct_link_armature(fd, (bArmature *)id);
@@ -8402,6 +8710,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
case ID_CF:
direct_link_cachefile(fd, (CacheFile *)id);
break;
+ case ID_WS:
+ direct_link_workspace(fd, (WorkSpace *)id, main);
+ break;
}
oldnewmap_free_unused(fd->datamap);
@@ -8447,6 +8758,7 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
bfd->curscreen = fg->curscreen;
bfd->curscene = fg->curscene;
+ bfd->cur_view_layer = fg->cur_view_layer;
MEM_freeN(fg);
@@ -8459,6 +8771,7 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
/* note, this has to be kept for reading older files... */
static void link_global(FileData *fd, BlendFileData *bfd)
{
+ bfd->cur_view_layer = newglobadr(fd, bfd->cur_view_layer);
bfd->curscreen = newlibadr(fd, NULL, bfd->curscreen);
bfd->curscene = newlibadr(fd, NULL, bfd->curscene);
// this happens in files older than 2.35
@@ -8467,27 +8780,6 @@ static void link_global(FileData *fd, BlendFileData *bfd)
}
}
-static void convert_tface_mt(FileData *fd, Main *main)
-{
- Main *gmain;
-
- /* this is a delayed do_version (so it can create new materials) */
- if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 3)) {
- //XXX hack, material.c uses G_MAIN all over the place, instead of main
- /* XXX NOTE: this hack should not beneeded anymore... but will check/remove this in 2.8 code rather */
- // temporarily set G_MAIN to the current main
- gmain = G_MAIN;
- G_MAIN = main;
-
- if (!(do_version_tface(main))) {
- BKE_report(fd->reports, RPT_WARNING, "Texface conversion problem (see error in console)");
- }
-
- //XXX hack, material.c uses G_MAIN allover the place, instead of main
- G_MAIN = gmain;
- }
-}
-
/* initialize userdef with non-UI dependency stuff */
/* other initializers (such as theme color defaults) go to resources.c */
static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
@@ -8515,6 +8807,16 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
user->walk_navigation.jump_height = 0.4f; /* m */
user->walk_navigation.teleport_time = 0.2f; /* s */
}
+
+ /* grease pencil multisamples */
+ if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "short", "gpencil_multisamples")) {
+ user->gpencil_multisamples = 4;
+ }
+
+ /* tablet pressure threshold */
+ if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "float", "pressure_threshold_max")) {
+ user->pressure_threshold_max = 1.0f;
+ }
}
static void do_versions(FileData *fd, Library *lib, Main *main)
@@ -8541,6 +8843,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
blo_do_versions_250(fd, lib, main);
blo_do_versions_260(fd, lib, main);
blo_do_versions_270(fd, lib, main);
+ blo_do_versions_280(fd, lib, main);
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
@@ -8554,12 +8857,15 @@ static void do_versions_after_linking(Main *main)
// main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
do_versions_after_linking_270(main);
+ do_versions_after_linking_280(main);
}
static void lib_link_all(FileData *fd, Main *main)
{
oldnewmap_sort(fd);
+ lib_link_id(fd, main);
+
/* No load UI for undo memfiles */
if (fd->memfile == NULL) {
lib_link_windowmanager(fd, main);
@@ -8582,14 +8888,15 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_text(fd, main);
lib_link_camera(fd, main);
lib_link_speaker(fd, main);
+ lib_link_lightprobe(fd, main);
lib_link_sound(fd, main);
- lib_link_group(fd, main);
+ lib_link_collection(fd, main);
lib_link_armature(fd, main);
lib_link_action(fd, main);
lib_link_vfont(fd, main);
lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
- lib_link_brush(fd, main);
lib_link_palette(fd, main);
+ lib_link_brush(fd, main);
lib_link_paint_curve(fd, main);
lib_link_particlesettings(fd, main);
lib_link_movieclip(fd, main);
@@ -8597,6 +8904,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_linestyle(fd, main);
lib_link_gpencil(fd, main);
lib_link_cachefiles(fd, main);
+ lib_link_workspaces(fd, main);
lib_link_library(fd, main); /* only init users */
}
@@ -8626,14 +8934,10 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
/* read all data into fd->datamap */
bhead = read_data_into_oldnewmap(fd, bhead, "user def");
- if (user->keymaps.first) {
- /* backwards compatibility */
- user->user_keymaps = user->keymaps;
- user->keymaps.first = user->keymaps.last = NULL;
- }
-
link_list(fd, &user->themes);
link_list(fd, &user->user_keymaps);
+ link_list(fd, &user->user_keyconfig_prefs);
+ link_list(fd, &user->user_menus);
link_list(fd, &user->addons);
link_list(fd, &user->autoexec_paths);
@@ -8659,6 +8963,22 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
direct_link_keymapitem(fd, kmi);
}
+ for (wmKeyConfigPref *kpt = user->user_keyconfig_prefs.first; kpt; kpt = kpt->next) {
+ kpt->prop = newdataadr(fd, kpt->prop);
+ IDP_DirectLinkGroup_OrFree(&kpt->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+
+ for (bUserMenu *um = user->user_menus.first; um; um = um->next) {
+ link_list(fd, &um->items);
+ for (bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ umi_op->prop = newdataadr(fd, umi_op->prop);
+ IDP_DirectLinkGroup_OrFree(&umi_op->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+ }
+ }
+
for (addon = user->addons.first; addon; addon = addon->next) {
addon->prop = newdataadr(fd, addon->prop);
IDP_DirectLinkGroup_OrFree(&addon->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
@@ -8669,6 +8989,9 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
link_list(fd, &user->uistyles);
+ /* Don't read the active app template, use the default one. */
+ user->app_template[0] = '\0';
+
/* free fd->datamap again */
oldnewmap_free_unused(fd->datamap);
oldnewmap_clear(fd->datamap);
@@ -8749,7 +9072,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = read_libblock(fd, mainlist.last, bhead, LIB_TAG_READ | LIB_TAG_EXTERN, NULL);
}
break;
- /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
+ /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
case ID_SCRN:
bhead->code = ID_SCR;
/* pass on to default */
@@ -8789,6 +9112,14 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false);
+ /* Now that all our data-blocks are loaded, we can re-generate overrides from their references. */
+ if (fd->memfile == NULL) {
+ /* Do not apply in undo case! */
+ lib_verify_nodetree(bfd->main, true); /* Needed to ensure we have typeinfo in nodes... */
+ BKE_main_override_static_update(bfd->main);
+ BKE_collections_after_lib_link(bfd->main);
+ }
+
lib_verify_nodetree(bfd->main, true);
fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */
@@ -8989,6 +9320,11 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
}
}
else {
+ /* in 2.50+ file identifier for screens is patched, forward compatibility */
+ if (bhead->code == ID_SCRN) {
+ bhead->code = ID_SCR;
+ }
+
id = is_yet_read(fd, mainvar, bhead);
if (id == NULL) {
read_libblock(fd, mainvar, bhead, LIB_TAG_TESTIND, NULL);
@@ -9025,6 +9361,14 @@ static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *ch
}
}
+static void expand_id(FileData *fd, Main *mainvar, ID *id)
+{
+ if (id->override_static) {
+ expand_doit(fd, mainvar, id->override_static->reference);
+ expand_doit(fd, mainvar, id->override_static->storage);
+ }
+}
+
static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *prop)
{
if (!prop)
@@ -9213,15 +9557,27 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
}
}
}
+
+ for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
+ expand_doit(fd, mainvar, dw->ob);
+ }
}
-static void expand_group(FileData *fd, Main *mainvar, Group *group)
+static void expand_collection(FileData *fd, Main *mainvar, Collection *collection)
{
- GroupObject *go;
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ expand_doit(fd, mainvar, cob->ob);
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ expand_doit(fd, mainvar, child->collection);
+ }
- for (go = group->gobject.first; go; go = go->next) {
- expand_doit(fd, mainvar, go->ob);
+#ifdef USE_COLLECTION_COMPAT_28
+ if (collection->collection != NULL) {
+ expand_scene_collection(fd, mainvar, collection->collection);
}
+#endif
}
static void expand_key(FileData *fd, Main *mainvar, Key *key)
@@ -9280,19 +9636,13 @@ static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
expand_doit(fd, mainvar, brush->mask_mtex.tex);
expand_doit(fd, mainvar, brush->clone.image);
expand_doit(fd, mainvar, brush->paint_curve);
+ if (brush->gpencil_settings != NULL) {
+ expand_doit(fd, mainvar, brush->gpencil_settings->material);
+ }
}
static void expand_material(FileData *fd, Main *mainvar, Material *ma)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- expand_doit(fd, mainvar, ma->mtex[a]->tex);
- expand_doit(fd, mainvar, ma->mtex[a]->object);
- }
- }
-
expand_doit(fd, mainvar, ma->ipo); // XXX deprecated - old animation system
if (ma->adt)
@@ -9301,21 +9651,15 @@ static void expand_material(FileData *fd, Main *mainvar, Material *ma)
if (ma->nodetree)
expand_nodetree(fd, mainvar, ma->nodetree);
- if (ma->group)
- expand_doit(fd, mainvar, ma->group);
+ if (ma->gp_style) {
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ expand_doit(fd, mainvar, gp_style->sima);
+ expand_doit(fd, mainvar, gp_style->ima);
+ }
}
static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a]) {
- expand_doit(fd, mainvar, la->mtex[a]->tex);
- expand_doit(fd, mainvar, la->mtex[a]->object);
- }
- }
-
expand_doit(fd, mainvar, la->ipo); // XXX deprecated - old animation system
if (la->adt)
@@ -9337,15 +9681,6 @@ static void expand_lattice(FileData *fd, Main *mainvar, Lattice *lt)
static void expand_world(FileData *fd, Main *mainvar, World *wrld)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) {
- expand_doit(fd, mainvar, wrld->mtex[a]->tex);
- expand_doit(fd, mainvar, wrld->mtex[a]->object);
- }
- }
-
expand_doit(fd, mainvar, wrld->ipo); // XXX deprecated - old animation system
if (wrld->adt)
@@ -9392,9 +9727,7 @@ static void expand_curve(FileData *fd, Main *mainvar, Curve *cu)
static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me)
{
- CustomDataLayer *layer;
- TFace *tf;
- int a, i;
+ int a;
if (me->adt)
expand_animdata(fd, mainvar, me->adt);
@@ -9405,46 +9738,6 @@ static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me)
expand_doit(fd, mainvar, me->key);
expand_doit(fd, mainvar, me->texcomesh);
-
- if (me->tface) {
- tf = me->tface;
- for (i = 0; i < me->totface; i++, tf++) {
- if (tf->tpage)
- expand_doit(fd, mainvar, tf->tpage);
- }
- }
-
- if (me->mface && !me->mpoly) {
- MTFace *mtf;
-
- for (a = 0; a < me->fdata.totlayer; a++) {
- layer = &me->fdata.layers[a];
-
- if (layer->type == CD_MTFACE) {
- mtf = (MTFace *)layer->data;
- for (i = 0; i < me->totface; i++, mtf++) {
- if (mtf->tpage)
- expand_doit(fd, mainvar, mtf->tpage);
- }
- }
- }
- }
- else {
- MTexPoly *mtp;
-
- for (a = 0; a < me->pdata.totlayer; a++) {
- layer = &me->pdata.layers[a];
-
- if (layer->type == CD_MTEXPOLY) {
- mtp = (MTexPoly *)layer->data;
-
- for (i = 0; i < me->totpoly; i++, mtp++) {
- if (mtp->tpage)
- expand_doit(fd, mainvar, mtp->tpage);
- }
- }
- }
- }
}
/* temp struct used to transport needed info to expand_constraint_cb() */
@@ -9524,9 +9817,6 @@ static void expand_object_expandModifiers(
static void expand_object(FileData *fd, Main *mainvar, Object *ob)
{
ParticleSystem *psys;
- bSensor *sens;
- bController *cont;
- bActuator *act;
bActionStrip *strip;
PartEff *paf;
int a;
@@ -9542,6 +9832,24 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
}
+ /* expand_object_expandModifier() */
+ if (ob->greasepencil_modifiers.first) {
+ struct { FileData *fd; Main *mainvar; } data;
+ data.fd = fd;
+ data.mainvar = mainvar;
+
+ BKE_gpencil_modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
+ }
+
+ /* expand_object_expandShaderFx() */
+ if (ob->shader_fx.first) {
+ struct { FileData *fd; Main *mainvar; } data;
+ data.fd = fd;
+ data.mainvar = mainvar;
+
+ BKE_shaderfx_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
+ }
+
expand_pose(fd, mainvar, ob->pose);
expand_doit(fd, mainvar, ob->poselib);
expand_constraints(fd, mainvar, &ob->constraints);
@@ -9583,84 +9891,6 @@ 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;
- expand_doit(fd, mainvar, ms->fromObject);
- }
- }
-
- for (cont = ob->controllers.first; cont; cont = cont->next) {
- if (cont->type == CONT_PYTHON) {
- bPythonCont *pc = cont->data;
- expand_doit(fd, mainvar, pc->text);
- }
- }
-
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_SOUND) {
- bSoundActuator *sa = act->data;
- expand_doit(fd, mainvar, sa->sound);
- }
- else if (act->type == ACT_CAMERA) {
- bCameraActuator *ca = act->data;
- expand_doit(fd, mainvar, ca->ob);
- }
- else if (act->type == ACT_EDIT_OBJECT) {
- bEditObjectActuator *eoa = act->data;
- if (eoa) {
- expand_doit(fd, mainvar, eoa->ob);
- expand_doit(fd, mainvar, eoa->me);
- }
- }
- else if (act->type == ACT_OBJECT) {
- bObjectActuator *oa = act->data;
- expand_doit(fd, mainvar, oa->reference);
- }
- else if (act->type == ACT_ADD_OBJECT) {
- bAddObjectActuator *aoa = act->data;
- expand_doit(fd, mainvar, aoa->ob);
- }
- else if (act->type == ACT_SCENE) {
- bSceneActuator *sa = act->data;
- expand_doit(fd, mainvar, sa->camera);
- expand_doit(fd, mainvar, sa->scene);
- }
- else if (act->type == ACT_2DFILTER) {
- bTwoDFilterActuator *tdfa = act->data;
- expand_doit(fd, mainvar, tdfa->text);
- }
- else if (act->type == ACT_ACTION) {
- bActionActuator *aa = act->data;
- expand_doit(fd, mainvar, aa->act);
- }
- else if (act->type == ACT_SHAPEACTION) {
- bActionActuator *aa = act->data;
- expand_doit(fd, mainvar, aa->act);
- }
- else if (act->type == ACT_PROPERTY) {
- bPropertyActuator *pa = act->data;
- expand_doit(fd, mainvar, pa->ob);
- }
- else if (act->type == ACT_MESSAGE) {
- bMessageActuator *ma = act->data;
- expand_doit(fd, mainvar, ma->toObject);
- }
- else if (act->type == ACT_PARENT) {
- bParentActuator *pa = act->data;
- expand_doit(fd, mainvar, pa->ob);
- }
- else if (act->type == ACT_ARMATURE) {
- bArmatureActuator *arma = act->data;
- expand_doit(fd, mainvar, arma->target);
- }
- else if (act->type == ACT_STEERING) {
- bSteeringActuator *sta = act->data;
- expand_doit(fd, mainvar, sta->target);
- expand_doit(fd, mainvar, sta->navmesh);
- }
- }
-
if (ob->pd) {
expand_doit(fd, mainvar, ob->pd->tex);
expand_doit(fd, mainvar, ob->pd->f_source);
@@ -9687,15 +9917,27 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
}
}
+#ifdef USE_COLLECTION_COMPAT_28
+static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc)
+{
+ for (LinkData *link = sc->objects.first; link; link = link->next) {
+ expand_doit(fd, mainvar, link->data);
+ }
+
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ expand_scene_collection(fd, mainvar, nsc);
+ }
+}
+#endif
+
static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
{
- Base *base;
SceneRenderLayer *srl;
FreestyleModuleConfig *module;
FreestyleLineSet *lineset;
- for (base = sce->base.first; base; base = base->next) {
- expand_doit(fd, mainvar, base->object);
+ for (Base *base_legacy = sce->base.first; base_legacy; base_legacy = base_legacy->next) {
+ expand_doit(fd, mainvar, base_legacy->object);
}
expand_doit(fd, mainvar, sce->camera);
expand_doit(fd, mainvar, sce->world);
@@ -9712,7 +9954,6 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
for (srl = sce->r.layers.first; srl; srl = srl->next) {
expand_doit(fd, mainvar, srl->mat_override);
- expand_doit(fd, mainvar, srl->light_override);
for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
if (module->script)
expand_doit(fd, mainvar, module->script);
@@ -9724,8 +9965,22 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
}
}
- if (sce->r.dometext)
- expand_doit(fd, mainvar, sce->gm.dome.warptext);
+ for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ expand_idprops(fd, mainvar, view_layer->id_properties);
+
+ for (module = view_layer->freestyle_config.modules.first; module; module = module->next) {
+ if (module->script) {
+ expand_doit(fd, mainvar, module->script);
+ }
+ }
+
+ for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->group) {
+ expand_doit(fd, mainvar, lineset->group);
+ }
+ expand_doit(fd, mainvar, lineset->linestyle);
+ }
+ }
if (sce->gpd)
expand_doit(fd, mainvar, sce->gpd);
@@ -9757,6 +10012,16 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
}
expand_doit(fd, mainvar, sce->clip);
+
+#ifdef USE_COLLECTION_COMPAT_28
+ if (sce->collection) {
+ expand_scene_collection(fd, mainvar, sce->collection);
+ }
+#endif
+
+ if (sce->master_collection) {
+ expand_collection(fd, mainvar, sce->master_collection);
+ }
}
static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
@@ -9787,6 +10052,12 @@ static void expand_sound(FileData *fd, Main *mainvar, bSound *snd)
expand_doit(fd, mainvar, snd->ipo); // XXX deprecated - old animation system
}
+static void expand_lightprobe(FileData *fd, Main *mainvar, LightProbe *prb)
+{
+ if (prb->adt)
+ expand_animdata(fd, mainvar, prb->adt);
+}
+
static void expand_movieclip(FileData *fd, Main *mainvar, MovieClip *clip)
{
if (clip->adt)
@@ -9856,8 +10127,27 @@ static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *li
static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
{
- if (gpd->adt)
+ if (gpd->adt) {
expand_animdata(fd, mainvar, gpd->adt);
+ }
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ expand_doit(fd, mainvar, gpl->parent);
+ }
+
+ for (int a = 0; a < gpd->totcol; a++) {
+ expand_doit(fd, mainvar, gpd->mat[a]);
+ }
+
+}
+
+static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace)
+{
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ expand_doit(fd, mainvar, BKE_workspace_layout_screen_get(layout));
+ }
}
/**
@@ -9893,6 +10183,7 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
id = lbarray[a]->first;
while (id) {
if (id->tag & LIB_TAG_NEED_EXPAND) {
+ expand_id(fd, mainvar, id);
expand_idprops(fd, mainvar, id->properties);
switch (GS(id->name)) {
@@ -9938,6 +10229,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_SO:
expand_sound(fd, mainvar, (bSound *)id);
break;
+ case ID_LP:
+ expand_lightprobe(fd, mainvar, (LightProbe *)id);
+ break;
case ID_AR:
expand_armature(fd, mainvar, (bArmature *)id);
break;
@@ -9945,7 +10239,7 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
expand_action(fd, mainvar, (bAction *)id); // XXX deprecated - old animation system
break;
case ID_GR:
- expand_group(fd, mainvar, (Group *)id);
+ expand_collection(fd, mainvar, (Collection *)id);
break;
case ID_NT:
expand_nodetree(fd, mainvar, (bNodeTree *)id);
@@ -9974,6 +10268,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_CF:
expand_cachefile(fd, mainvar, (CacheFile *)id);
break;
+ case ID_WS:
+ expand_workspace(fd, mainvar, (WorkSpace *)id);
+ break;
default:
break;
}
@@ -9991,12 +10288,12 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
/* ***************************** */
-static bool object_in_any_scene(Main *mainvar, Object *ob)
+static bool object_in_any_scene(Main *bmain, Object *ob)
{
Scene *sce;
- for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
- if (BKE_scene_base_find(sce, ob)) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ if (BKE_scene_object_find(sce, ob)) {
return true;
}
}
@@ -10004,50 +10301,59 @@ static bool object_in_any_scene(Main *mainvar, Object *ob)
return false;
}
-static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Library *lib, const short flag)
+static Collection *get_collection_active(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag)
+{
+ if (flag & FILE_ACTIVE_COLLECTION) {
+ LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
+ return lc->collection;
+ }
+ else {
+ return BKE_collection_add(bmain, scene->master_collection, NULL);
+ }
+}
+
+static void add_loose_objects_to_scene(
+ Main *mainvar, Main *bmain, Scene *scene, ViewLayer *view_layer, Library *lib, const short flag)
{
- Object *ob;
- Base *base;
- const uint active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0;
const bool is_link = (flag & FILE_LINK) != 0;
BLI_assert(scene);
- /* give all objects which are LIB_TAG_INDIRECT a base, or for a group when *lib has been set */
- for (ob = mainvar->object.first; ob; ob = ob->id.next) {
+ /* Give all objects which are LIB_TAG_INDIRECT a base, or for a collection when *lib has been set. */
+ for (Object *ob = mainvar->object.first; ob; ob = ob->id.next) {
if ((ob->id.tag & LIB_TAG_INDIRECT) && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0) {
bool do_it = false;
- if (ob->id.us == 0) {
- do_it = true;
- }
- else if (!is_link && (ob->id.lib == lib) && (object_in_any_scene(mainvar, ob) == 0)) {
- /* When appending, make sure any indirectly loaded objects get a base, else they cant be accessed at all
- * (see T27437). */
- do_it = true;
+ if (!is_link) {
+ if (ob->id.us == 0) {
+ do_it = true;
+ }
+ else if ((ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == 0)) {
+ /* When appending, make sure any indirectly loaded objects get a base, else they cant be accessed at all
+ * (see T27437). */
+ do_it = true;
+ }
}
if (do_it) {
- base = MEM_callocN(sizeof(Base), __func__);
- BLI_addtail(&scene->base, base);
+ CLAMP_MIN(ob->id.us, 0);
+
+ Collection *active_collection = get_collection_active(bmain, scene, view_layer, FILE_ACTIVE_COLLECTION);
+ BKE_collection_object_add(bmain, active_collection, ob);
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_scene_object_base_flag_sync_from_base(base);
- if (active_lay) {
- ob->lay = active_lay;
- }
if (flag & FILE_AUTOSELECT) {
/* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag,
- * but it will miss objects from non-instantiated groups... */
- ob->flag |= SELECT;
- /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
+ * but it will miss objects from non-instantiated collections... */
+ if (base->flag & BASE_SELECTABLE) {
+ base->flag |= BASE_SELECTED;
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
+ /* Do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level. */
}
- base->object = ob;
- base->lay = ob->lay;
- base->flag = ob->flag;
-
- CLAMP_MIN(ob->id.us, 0);
- id_us_plus_no_lib((ID *)ob);
-
ob->id.tag &= ~LIB_TAG_INDIRECT;
ob->id.tag |= LIB_TAG_EXTERN;
}
@@ -10055,36 +10361,46 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra
}
}
-static void give_base_to_groups(
- Main *mainvar, Scene *scene, View3D *v3d, Library *UNUSED(lib), const short UNUSED(flag))
+static void add_collections_to_scene(
+ Main *mainvar, Main *bmain, Scene *scene, ViewLayer *view_layer, Library *UNUSED(lib), const short flag)
{
- Group *group;
- Base *base;
- Object *ob;
- const uint active_lay = BKE_screen_view3d_layer_active(v3d, scene);
+ Collection *active_collection = get_collection_active(bmain, scene, view_layer, FILE_ACTIVE_COLLECTION);
+
+ /* Give all objects which are tagged a base. */
+ for (Collection *collection = mainvar->collection.first; collection; collection = collection->id.next) {
+ if (collection->id.tag & LIB_TAG_DOIT) {
+ if (flag & FILE_GROUP_INSTANCE) {
+ /* Any indirect collection should not have been tagged. */
+ BLI_assert((collection->id.tag & LIB_TAG_INDIRECT) == 0);
- /* give all objects which are tagged a base */
- for (group = mainvar->group.first; group; group = group->id.next) {
- if (group->id.tag & LIB_TAG_DOIT) {
- /* any indirect group should not have been tagged */
- BLI_assert((group->id.tag & LIB_TAG_INDIRECT) == 0);
+ /* BKE_object_add(...) messes with the selection. */
+ Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
+ ob->type = OB_EMPTY;
- /* BKE_object_add(...) messes with the selection */
- ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2);
- ob->type = OB_EMPTY;
- ob->lay = active_lay;
+ BKE_collection_object_add(bmain, active_collection, ob);
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
- /* assign the base */
- base = BKE_scene_base_add(scene, ob);
- base->flag |= SELECT;
- base->object->flag = base->flag;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- scene->basact = base;
+ if (base->flag & BASE_SELECTABLE) {
+ base->flag |= BASE_SELECTED;
+ }
+
+ BKE_scene_object_base_flag_sync_from_base(base);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ view_layer->basact = base;
+
+ /* Assign the collection. */
+ ob->dup_group = collection;
+ id_us_plus(&collection->id);
+ ob->transflag |= OB_DUPLICOLLECTION;
+ copy_v3_v3(ob->loc, scene->cursor.location);
+ }
+ else {
+ /* Add collection as child of active collection. */
+ BKE_collection_child_add(bmain, active_collection, collection);
- /* assign the group */
- ob->dup_group = group;
- ob->transflag |= OB_DUPLIGROUP;
- copy_v3_v3(ob->loc, scene->cursor);
+ collection->id.tag &= ~LIB_TAG_INDIRECT;
+ collection->id.tag |= LIB_TAG_EXTERN;
+ }
}
}
}
@@ -10158,31 +10474,27 @@ static ID *link_named_part(
return id;
}
-static void link_object_postprocess(ID *id, Scene *scene, View3D *v3d, const int flag)
+static void link_object_postprocess(ID *id, Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag)
{
if (scene) {
+ /* link to scene */
Base *base;
Object *ob;
-
- base = MEM_callocN(sizeof(Base), "app_nam_part");
- BLI_addtail(&scene->base, base);
+ Collection *collection;
ob = (Object *)id;
-
- /* link at active layer (view3d if available in context, else scene one */
- if (flag & FILE_ACTIVELAY) {
- ob->lay = BKE_screen_view3d_layer_active(v3d, scene);
- }
-
ob->mode = OB_MODE_OBJECT;
- base->lay = ob->lay;
- base->object = ob;
- base->flag = ob->flag;
- id_us_plus_no_lib((ID *)ob);
+
+ collection = get_collection_active(bmain, scene, view_layer, flag);
+ BKE_collection_object_add(bmain, collection, ob);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_scene_object_base_flag_sync_from_base(base);
if (flag & FILE_AUTOSELECT) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
+ if (base->flag & BASE_SELECTABLE) {
+ base->flag |= BASE_SELECTED;
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
/* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
}
}
@@ -10212,11 +10524,11 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh)
id_sort_by_name(lb, id);
if (bhead->code == ID_OB) {
- /* Instead of instancing Base's directly, postpone until after groups are loaded
- * otherwise the base's flag is set incorrectly when groups are used */
+ /* Instead of instancing Base's directly, postpone until after collections are loaded
+ * otherwise the base's flag is set incorrectly when collections are used */
Object *ob = (Object *)id;
ob->mode = OB_MODE_OBJECT;
- /* ensure give_base_to_objects runs on this object */
+ /* ensure add_loose_objects_to_scene runs on this object */
BLI_assert(id->us == 0);
}
}
@@ -10225,17 +10537,16 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh)
static ID *link_named_part_ex(
Main *mainl, FileData *fd, const short idcode, const char *name, const int flag,
- Scene *scene, View3D *v3d)
+ Main *bmain, Scene *scene, ViewLayer *view_layer)
{
ID *id = link_named_part(mainl, fd, idcode, name, flag);
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
- link_object_postprocess(id, scene, v3d, flag);
+ link_object_postprocess(id, bmain, scene, view_layer, flag);
}
else if (id && (GS(id->name) == ID_GR)) {
- /* tag as needing to be instantiated */
- if (flag & FILE_GROUP_INSTANCE)
- id->tag |= LIB_TAG_DOIT;
+ /* tag as needing to be instantiated or linked */
+ id->tag |= LIB_TAG_DOIT;
}
return id;
@@ -10258,24 +10569,24 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod
/**
* Link a named datablock from an external blend file.
- * Optionally instantiate the object/group in the scene when the flags are set.
+ * Optionally instantiate the object/collection in the scene when the flags are set.
*
* \param mainl The main database to link from (not the active one).
* \param bh The blender file handle.
* \param idcode The kind of datablock to link.
* \param name The name of the datablock (without the 2 char ID prefix).
* \param flag Options for linking, used for instantiating.
- * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
- * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
+ * \param scene The scene in which to instantiate objects/collections (if NULL, no instantiation is done).
+ * \param v3d The active View3D (only to define active layers for instantiated objects & collections, can be NULL).
* \return the linked ID when found.
*/
ID *BLO_library_link_named_part_ex(
Main *mainl, BlendHandle **bh,
const short idcode, const char *name, const int flag,
- Scene *scene, View3D *v3d)
+ Main *bmain, Scene *scene, ViewLayer *view_layer)
{
FileData *fd = (FileData *)(*bh);
- return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d);
+ return link_named_part_ex(mainl, fd, idcode, name, flag, bmain, scene, view_layer);
}
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
@@ -10328,8 +10639,8 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
- /* clear for group instantiating tag */
- BKE_main_id_tag_listbase(&(mainvar->group), LIB_TAG_DOIT, false);
+ /* clear for collection instantiating tag */
+ BKE_main_id_tag_listbase(&(mainvar->collection), LIB_TAG_DOIT, false);
/* make mains */
blo_split_main((*fd)->mainlist, mainvar);
@@ -10388,7 +10699,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
}
/* scene and v3d may be NULL. */
-static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d)
+static void library_link_end(Main *mainl, FileData **fd, const short flag, Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Main *mainvar;
Library *curlib;
@@ -10418,19 +10729,21 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
mainl = NULL; /* blo_join_main free's mainl, cant use anymore */
lib_link_all(*fd, mainvar);
+ BKE_collections_after_lib_link(mainvar);
/* Yep, second splitting... but this is a very cheap operation, so no big deal. */
blo_split_main((*fd)->mainlist, mainvar);
- Main main_newid = {0};
+ Main *main_newid = BKE_main_new();
for (mainvar = ((Main *)(*fd)->mainlist->first)->next; mainvar; mainvar = mainvar->next) {
BLI_assert(mainvar->versionfile != 0);
/* We need to split out IDs already existing, or they will go again through do_versions - bad, very bad! */
- split_main_newid(mainvar, &main_newid);
+ split_main_newid(mainvar, main_newid);
- do_versions_after_linking(&main_newid);
+ do_versions_after_linking(main_newid);
- add_main_to_main(mainvar, &main_newid);
+ add_main_to_main(mainvar, main_newid);
}
+ BKE_main_free(main_newid);
blo_join_main((*fd)->mainlist);
mainvar = (*fd)->mainlist->first;
MEM_freeN((*fd)->mainlist);
@@ -10440,22 +10753,19 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
lib_verify_nodetree(mainvar, false);
fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar); /* make all relative paths, relative to the open blend file */
- /* Give a base to loose objects. If group append, do it for objects too.
- * Only directly linked objects & groups are instantiated by `BLO_library_link_named_part_ex()` & co,
+ /* Give a base to loose objects and collections.
+ * Only directly linked objects & collections are instantiated by `BLO_library_link_named_part_ex()` & co,
* here we handle indirect ones and other possible edge-cases. */
if (scene) {
- give_base_to_objects(mainvar, scene, v3d, curlib, flag);
-
- if (flag & FILE_GROUP_INSTANCE) {
- give_base_to_groups(mainvar, scene, v3d, curlib, flag);
- }
+ add_collections_to_scene(mainvar, bmain, scene, view_layer, curlib, flag);
+ add_loose_objects_to_scene(mainvar, bmain, scene, view_layer, curlib, flag);
}
else {
/* printf("library_append_end, scene is NULL (objects wont get bases)\n"); */
}
- /* clear group instantiating tag */
- BKE_main_id_tag_listbase(&(mainvar->group), LIB_TAG_DOIT, false);
+ /* clear collection instantiating tag */
+ BKE_main_id_tag_listbase(&(mainvar->collection), LIB_TAG_DOIT, false);
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
@@ -10466,19 +10776,20 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
/**
* Finalize linking from a given .blend file (library).
- * Optionally instance the indirect object/group in the scene when the flags are set.
+ * Optionally instance the indirect object/collection in the scene when the flags are set.
* \note Do not use \a bh after calling this function, it may frees it.
*
* \param mainl The main database to link from (not the active one).
* \param bh The blender file handle (WARNING! may be freed by this function!).
* \param flag Options for linking, used for instantiating.
- * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
- * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
+ * \param bmain The main database in which to instantiate objects/collections
+ * \param scene The scene in which to instantiate objects/collections (if NULL, no instantiation is done).
+ * \param view_layer The scene layer in which to instantiate objects/collections (if NULL, no instantiation is done).
*/
-void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, View3D *v3d)
+void BLO_library_link_end(Main *mainl, BlendHandle **bh, int flag, Main *bmain, Scene *scene, ViewLayer *view_layer)
{
FileData *fd = (FileData *)(*bh);
- library_link_end(mainl, &fd, flag, scene, v3d);
+ library_link_end(mainl, &fd, flag, bmain, scene, view_layer);
*bh = (BlendHandle *)fd;
}
@@ -10696,19 +11007,19 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
/* do versions, link, and free */
- Main main_newid = {0};
+ Main *main_newid = BKE_main_new();
for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
/* some mains still have to be read, then versionfile is still zero! */
if (mainptr->versionfile) {
/* We need to split out IDs already existing, or they will go again through do_versions - bad, very bad! */
- split_main_newid(mainptr, &main_newid);
+ split_main_newid(mainptr, main_newid);
if (mainptr->curlib->filedata) // can be zero... with shift+f1 append
- do_versions(mainptr->curlib->filedata, mainptr->curlib, &main_newid);
+ do_versions(mainptr->curlib->filedata, mainptr->curlib, main_newid);
else
- do_versions(basefd, NULL, &main_newid);
+ do_versions(basefd, NULL, main_newid);
- add_main_to_main(mainptr, &main_newid);
+ add_main_to_main(mainptr, main_newid);
}
if (mainptr->curlib->filedata)
@@ -10717,29 +11028,5 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
if (mainptr->curlib->filedata) blo_freefiledata(mainptr->curlib->filedata);
mainptr->curlib->filedata = NULL;
}
-}
-
-
-/* reading runtime */
-
-BlendFileData *blo_read_blendafterruntime(int file, const char *name, int actualsize, ReportList *reports)
-{
- BlendFileData *bfd = NULL;
- FileData *fd = filedata_new();
- fd->filedes = file;
- fd->buffersize = actualsize;
- fd->read = fd_read_from_file;
-
- /* needed for library_append and read_libraries */
- BLI_strncpy(fd->relabase, name, sizeof(fd->relabase));
-
- fd = blo_decode_and_check(fd, reports);
- if (!fd)
- return NULL;
-
- fd->reports = reports;
- bfd = blo_read_file_internal(fd, "");
- blo_freefiledata(fd);
-
- return bfd;
+ BKE_main_free(main_newid);
}
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 66161d86f02..10f0c7a2942 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -34,6 +34,8 @@
#define __READFILE_H__
#include "zlib.h"
+#include "DNA_sdna_types.h"
+#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h" /* for ReportType */
struct OldNewMap;
@@ -88,6 +90,7 @@ typedef struct FileData {
struct OldNewMap *libmap;
struct OldNewMap *imamap;
struct OldNewMap *movieclipmap;
+ struct OldNewMap *scenemap;
struct OldNewMap *soundmap;
struct OldNewMap *packedmap;
@@ -138,6 +141,8 @@ FileData *blo_openblendermemfile(struct MemFile *memfile, struct ReportList *rep
void blo_clear_proxy_pointers_from_lib(Main *oldmain);
void blo_make_image_pointer_map(FileData *fd, Main *oldmain);
void blo_end_image_pointer_map(FileData *fd, Main *oldmain);
+void blo_make_scene_pointer_map(FileData *fd, Main *oldmain);
+void blo_end_scene_pointer_map(FileData *fd, Main *oldmain);
void blo_make_movieclip_pointer_map(FileData *fd, Main *oldmain);
void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain);
void blo_make_sound_pointer_map(FileData *fd, Main *oldmain);
@@ -171,7 +176,9 @@ void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Mai
void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain);
void do_versions_after_linking_270(struct Main *bmain);
+void do_versions_after_linking_280(struct Main *bmain);
#endif
diff --git a/source/blender/blenloader/intern/runtime.c b/source/blender/blenloader/intern/runtime.c
deleted file mode 100644
index a4e7be2c2d8..00000000000
--- a/source/blender/blenloader/intern/runtime.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-/**
- * \file runtime.c
- * \brief This file handles the loading of .blend files embedded in runtimes
- * \ingroup blenloader
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#ifdef WIN32
-# include <io.h> // read, open
-# include "BLI_winstuff.h"
-#else // ! WIN32
-# include <unistd.h> // read
-#endif
-
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-
-#include "BLO_readfile.h"
-#include "BLO_runtime.h"
-
-#include "BKE_report.h"
-
-/* Runtime reading */
-
-static int handle_read_msb_int(int handle)
-{
- uchar buf[4];
-
- if (read(handle, buf, 4) != 4)
- return -1;
-
- return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0);
-}
-
-int BLO_is_a_runtime(const char *path)
-{
- int res = 0, fd = BLI_open(path, O_BINARY | O_RDONLY, 0);
- int datastart;
- char buf[8];
-
- if (fd == -1)
- goto cleanup;
-
- lseek(fd, -12, SEEK_END);
-
- datastart = handle_read_msb_int(fd);
-
- if (datastart == -1)
- goto cleanup;
- else if (read(fd, buf, 8) != 8)
- goto cleanup;
- else if (memcmp(buf, "BRUNTIME", 8) != 0)
- goto cleanup;
- else
- res = 1;
-
-cleanup:
- if (fd != -1)
- close(fd);
-
- return res;
-}
-
-BlendFileData *BLO_read_runtime(const char *path, ReportList *reports)
-{
- BlendFileData *bfd = NULL;
- size_t actualsize;
- int fd, datastart;
- char buf[8];
-
- fd = BLI_open(path, O_BINARY | O_RDONLY, 0);
-
- if (fd == -1) {
- BKE_reportf(reports, RPT_ERROR, "Unable to open '%s': %s", path, strerror(errno));
- goto cleanup;
- }
-
- actualsize = BLI_file_descriptor_size(fd);
-
- lseek(fd, -12, SEEK_END);
-
- datastart = handle_read_msb_int(fd);
-
- if (datastart == -1) {
- BKE_reportf(reports, RPT_ERROR, "Unable to read '%s' (problem seeking)", path);
- goto cleanup;
- }
- else if (read(fd, buf, 8) != 8) {
- BKE_reportf(reports, RPT_ERROR, "Unable to read '%s' (truncated header)", path);
- goto cleanup;
- }
- else if (memcmp(buf, "BRUNTIME", 8) != 0) {
- BKE_reportf(reports, RPT_ERROR, "Unable to read '%s' (not a blend file)", path);
- goto cleanup;
- }
- else {
- //printf("starting to read runtime from %s at datastart %d\n", path, datastart);
- lseek(fd, datastart, SEEK_SET);
- bfd = blo_read_blendafterruntime(fd, path, actualsize - datastart, reports);
- fd = -1; // file was closed in blo_read_blendafterruntime()
- }
-
-cleanup:
- if (fd != -1)
- close(fd);
-
- return bfd;
-}
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index f55d20b8145..8ee40da13c7 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -53,6 +53,7 @@
#include "BLO_undofile.h"
#include "BLO_readfile.h"
+#include "BKE_library.h"
#include "BKE_main.h"
/* keep last */
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index a6d8b6de606..54e1512c953 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -39,7 +39,6 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
@@ -73,8 +72,8 @@
#include "BKE_armature.h"
#include "BKE_colortools.h"
#include "BKE_global.h" // for G
-#include "BKE_library.h" // for which_libbase
-#include "BKE_main.h" // for Main
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_mesh.h" // for ME_ defines (patching)
#include "BKE_modifier.h"
#include "BKE_multires.h"
@@ -84,7 +83,6 @@
#include "BKE_sequencer.h"
#include "BKE_texture.h"
#include "BKE_sound.h"
-#include "BKE_sca.h"
#include "NOD_socket.h"
@@ -101,7 +99,7 @@ static void area_add_header_region(ScrArea *sa, ListBase *lb)
BLI_addtail(lb, ar);
ar->regiontype = RGN_TYPE_HEADER;
- if (sa->headertype == HEADERDOWN)
+ if (sa->headertype == 1)
ar->alignment = RGN_ALIGN_BOTTOM;
else
ar->alignment = RGN_ALIGN_TOP;
@@ -287,19 +285,6 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
//ar->v2d.flag |= V2D_IS_INITIALISED;
break;
}
- case SPACE_TIME:
- {
- SpaceTime *stime = (SpaceTime *)sl;
- memcpy(&ar->v2d, &stime->v2d, sizeof(View2D));
-
- ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL);
- ar->v2d.align |= V2D_ALIGN_NO_NEG_Y;
- ar->v2d.keepofs |= V2D_LOCKOFS_Y;
- ar->v2d.keepzoom |= V2D_LOCKZOOM_Y;
- ar->v2d.tot.ymin = ar->v2d.cur.ymin = -10.0;
- ar->v2d.min[1] = ar->v2d.max[1] = 20.0;
- break;
- }
case SPACE_IPO:
{
SpaceIpo *sipo = (SpaceIpo *)sl;
@@ -444,9 +429,6 @@ static void do_versions_windowmanager_2_50(bScreen *screen)
sl->spacetype = SPACE_EMPTY; /* spacedata then matches */
}
- /* it seems to be possible in 2.5 to have this saved, filewindow probably */
- sa->butspacetype = sa->spacetype;
-
/* pushed back spaces also need regions! */
if (sa->spacedata.first) {
sl = sa->spacedata.first;
@@ -517,70 +499,6 @@ static void do_versions_gpencil_2_50(Main *main, bScreen *screen)
}
}
-static void do_version_mtex_factor_2_50(MTex **mtex_array, short idtype)
-{
- MTex *mtex;
- float varfac, colfac;
- int a, neg;
-
- if (!mtex_array)
- return;
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (mtex_array[a]) {
- mtex = mtex_array[a];
-
- neg = mtex->maptoneg;
- varfac = mtex->varfac;
- colfac = mtex->colfac;
-
- if (neg & MAP_DISP) mtex->dispfac = -mtex->dispfac;
- if (neg & MAP_NORM) mtex->norfac = -mtex->norfac;
- if (neg & MAP_WARP) mtex->warpfac = -mtex->warpfac;
-
- mtex->colspecfac = (neg & MAP_COLSPEC) ? -colfac : colfac;
- mtex->mirrfac = (neg & MAP_COLMIR) ? -colfac : colfac;
- mtex->alphafac = (neg & MAP_ALPHA) ? -varfac : varfac;
- mtex->difffac = (neg & MAP_REF) ? -varfac : varfac;
- mtex->specfac = (neg & MAP_SPEC) ? -varfac : varfac;
- mtex->emitfac = (neg & MAP_EMIT) ? -varfac : varfac;
- mtex->hardfac = (neg & MAP_HAR) ? -varfac : varfac;
- mtex->raymirrfac = (neg & MAP_RAYMIRR) ? -varfac : varfac;
- mtex->translfac = (neg & MAP_TRANSLU) ? -varfac : varfac;
- mtex->ambfac = (neg & MAP_AMB) ? -varfac : varfac;
- mtex->colemitfac = (neg & MAP_EMISSION_COL) ? -colfac : colfac;
- mtex->colreflfac = (neg & MAP_REFLECTION_COL) ? -colfac : colfac;
- mtex->coltransfac = (neg & MAP_TRANSMISSION_COL) ? -colfac : colfac;
- mtex->densfac = (neg & MAP_DENSITY) ? -varfac : varfac;
- mtex->scatterfac = (neg & MAP_SCATTERING) ? -varfac : varfac;
- mtex->reflfac = (neg & MAP_REFLECTION) ? -varfac : varfac;
-
- mtex->timefac = (neg & MAP_PA_TIME) ? -varfac : varfac;
- mtex->lengthfac = (neg & MAP_PA_LENGTH) ? -varfac : varfac;
- mtex->clumpfac = (neg & MAP_PA_CLUMP) ? -varfac : varfac;
- mtex->kinkfac = (neg & MAP_PA_KINK) ? -varfac : varfac;
- mtex->roughfac = (neg & MAP_PA_ROUGH) ? -varfac : varfac;
- mtex->padensfac = (neg & MAP_PA_DENS) ? -varfac : varfac;
- mtex->lifefac = (neg & MAP_PA_LIFE) ? -varfac : varfac;
- mtex->sizefac = (neg & MAP_PA_SIZE) ? -varfac : varfac;
- mtex->ivelfac = (neg & MAP_PA_IVEL) ? -varfac : varfac;
-
- mtex->shadowfac = (neg & LAMAP_SHAD) ? -colfac : colfac;
-
- mtex->zenupfac = (neg & WOMAP_ZENUP) ? -colfac : colfac;
- mtex->zendownfac = (neg & WOMAP_ZENDOWN) ? -colfac : colfac;
- mtex->blendfac = (neg & WOMAP_BLEND) ? -varfac : varfac;
-
- if (idtype == ID_MA)
- mtex->colfac = (neg & MAP_COL) ? -colfac : colfac;
- else if (idtype == ID_LA)
- mtex->colfac = (neg & LAMAP_COL) ? -colfac : colfac;
- else if (idtype == ID_WO)
- mtex->colfac = (neg & WOMAP_HORIZ) ? -colfac : colfac;
- }
- }
-}
-
static void do_version_mdef_250(Main *main)
{
Object *ob;
@@ -610,13 +528,7 @@ static void do_version_constraints_radians_degrees_250(ListBase *lb)
bConstraint *con;
for (con = lb->first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_RIGIDBODYJOINT) {
- bRigidBodyJointConstraint *data = con->data;
- data->axX *= (float)(M_PI / 180.0);
- data->axY *= (float)(M_PI / 180.0);
- data->axZ *= (float)(M_PI / 180.0);
- }
- else if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
bKinematicConstraint *data = con->data;
data->poleangle *= (float)(M_PI / 180.0);
}
@@ -725,7 +637,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
Base *base;
Material *ma;
Camera *cam;
- Mesh *me;
Curve *cu;
Scene *sce;
Tex *tx;
@@ -736,8 +647,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
bSound *sound;
Sequence *seq;
- bActuator *act;
- int a;
for (sound = bmain->sound.first; sound; sound = sound->id.next) {
if (sound->newpackedfile) {
@@ -746,33 +655,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_SOUND) {
- bSoundActuator *sAct = (bSoundActuator *)act->data;
- if (sAct->sound) {
- sound = blo_do_versions_newlibadr(fd, lib, sAct->sound);
- sAct->flag = (sound->flags & SOUND_FLAGS_3D) ? ACT_SND_3D_SOUND : 0;
- sAct->pitch = sound->pitch;
- sAct->volume = sound->volume;
- sAct->sound3D.reference_distance = sound->distance;
- sAct->sound3D.max_gain = sound->max_gain;
- sAct->sound3D.min_gain = sound->min_gain;
- sAct->sound3D.rolloff_factor = sound->attenuation;
- }
- else {
- sAct->sound3D.reference_distance = 1.0f;
- sAct->volume = 1.0f;
- sAct->sound3D.max_gain = 1.0f;
- sAct->sound3D.rolloff_factor = 1.0f;
- }
- sAct->sound3D.cone_inner_angle = 360.0f;
- sAct->sound3D.cone_outer_angle = 360.0f;
- sAct->sound3D.max_distance = FLT_MAX;
- }
- }
- }
-
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->ed && scene->ed->seqbasep) {
SEQ_BEGIN(scene->ed, seq)
@@ -808,15 +690,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
if (ma->nodetree && ma->nodetree->id.name[0] == '\0')
strcpy(ma->nodetree->id.name, "NTShader Nodetree");
-
- /* which_output 0 is now "not specified" */
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- tx = blo_do_versions_newlibadr(fd, lib, ma->mtex[a]->tex);
- if (tx && tx->use_nodes)
- ma->mtex[a]->which_output++;
- }
- }
}
/* and composite trees */
@@ -854,10 +727,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
+#if 0 /* ME_DRAWEDGES and others was moved to viewport. */
/* copy standard draw flag to meshes(used to be global, is not available here) */
for (me = bmain->mesh.first; me; me = me->id.next) {
me->drawflag = ME_DRAWEDGES | ME_DRAWFACES | ME_DRAWCREASES;
}
+#endif
/* particle draw and render types */
for (part = bmain->particle.first; part; part = part->id.next) {
@@ -902,7 +777,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 1)) {
Object *ob;
- Material *ma;
Tex *tex;
Scene *sce;
ToolSettings *ts;
@@ -948,65 +822,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
tex->afmax = 8;
}
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- int a;
-
- if (ma->mode & MA_WIRE) {
- ma->material_type = MA_TYPE_WIRE;
- ma->mode &= ~MA_WIRE;
- }
-
- if (ma->mode & MA_HALO) {
- ma->material_type = MA_TYPE_HALO;
- ma->mode &= ~MA_HALO;
- }
-
- if (ma->mode & (MA_ZTRANSP | MA_RAYTRANSP)) {
- ma->mode |= MA_TRANSP;
- }
- else {
- /* ma->mode |= MA_ZTRANSP; */ /* leave ztransp as is even if its not used [#28113] */
- ma->mode &= ~MA_TRANSP;
- }
-
- /* set new bump for unused slots */
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- tex = ma->mtex[a]->tex;
- if (!tex) {
- ma->mtex[a]->texflag |= MTEX_3TAP_BUMP;
- ma->mtex[a]->texflag |= MTEX_BUMP_OBJECTSPACE;
- }
- else {
- tex = (Tex *)blo_do_versions_newlibadr(fd, ma->id.lib, tex);
- if (tex && tex->type == 0) { /* invalid type */
- ma->mtex[a]->texflag |= MTEX_3TAP_BUMP;
- ma->mtex[a]->texflag |= MTEX_BUMP_OBJECTSPACE;
- }
- }
- }
- }
-
- /* volume rendering settings */
- if (ma->vol.stepsize < 0.0001f) {
- ma->vol.density = 1.0f;
- ma->vol.emission = 0.0f;
- ma->vol.scattering = 1.0f;
- ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f;
- ma->vol.density_scale = 1.0f;
- ma->vol.depth_cutoff = 0.01f;
- ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
- ma->vol.stepsize = 0.2f;
- ma->vol.shade_type = MA_VOL_SHADE_SHADED;
- ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
- ma->vol.precache_resolution = 50;
- }
- }
-
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
ts = sce->toolsettings;
- if (ts->normalsize == 0.0f || !ts->uv_selectmode || ts->vgroup_weight == 0.0f) {
- ts->normalsize = 0.1f;
+ if (!ts->uv_selectmode || ts->vgroup_weight == 0.0f) {
ts->selectmode = SCE_SELECT_VERTEX;
/* autokeying - setting should be taken from the user-prefs
@@ -1019,95 +837,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
ts->uv_selectmode = UV_SELECT_VERTEX;
ts->vgroup_weight = 1.0f;
}
-
- /* Game Settings */
- /* Dome */
- sce->gm.dome.angle = sce->r.domeangle;
- sce->gm.dome.mode = sce->r.domemode;
- sce->gm.dome.res = sce->r.domeres;
- sce->gm.dome.resbuf = sce->r.domeresbuf;
- sce->gm.dome.tilt = sce->r.dometilt;
- sce->gm.dome.warptext = sce->r.dometext;
-
- /* Stand Alone */
- sce->gm.playerflag |= (sce->r.fullscreen ? GAME_PLAYER_FULLSCREEN : 0);
- sce->gm.xplay = sce->r.xplay;
- sce->gm.yplay = sce->r.yplay;
- sce->gm.freqplay = sce->r.freqplay;
- sce->gm.depth = sce->r.depth;
- sce->gm.attrib = sce->r.attrib;
-
- /* Stereo */
- sce->gm.stereomode = sce->r.stereomode;
- /* reassigning stereomode NO_STEREO and DOME to a separeted flag*/
- if (sce->gm.stereomode == 1) { // 1 = STEREO_NOSTEREO
- sce->gm.stereoflag = STEREO_NOSTEREO;
- sce->gm.stereomode = STEREO_ANAGLYPH;
- }
- else if (sce->gm.stereomode == 8) { // 8 = STEREO_DOME
- sce->gm.stereoflag = STEREO_DOME;
- sce->gm.stereomode = STEREO_ANAGLYPH;
- }
- else
- sce->gm.stereoflag = STEREO_ENABLED;
-
- /* Framing */
- sce->gm.framing = sce->framing;
- sce->gm.xplay = sce->r.xplay;
- sce->gm.yplay = sce->r.yplay;
- sce->gm.freqplay = sce->r.freqplay;
- sce->gm.depth = sce->r.depth;
-
- /* Physic (previously stored in world) */
- sce->gm.gravity = 9.8f;
- sce->gm.physicsEngine = WOPHY_BULLET; /* Bullet by default */
- sce->gm.mode = WO_DBVT_CULLING; /* DBVT culling by default */
- sce->gm.occlusionRes = 128;
- sce->gm.ticrate = 60;
- sce->gm.maxlogicstep = 5;
- sce->gm.physubstep = 1;
- sce->gm.maxphystep = 5;
}
}
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 2)) {
- Scene *sce;
Object *ob;
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (fd->fileflags & G_FILE_ENABLE_ALL_FRAMES)
- sce->gm.flag |= GAME_ENABLE_ALL_FRAMES;
- if (fd->fileflags & G_FILE_SHOW_DEBUG_PROPS)
- sce->gm.flag |= GAME_SHOW_DEBUG_PROPS;
- if (fd->fileflags & G_FILE_SHOW_FRAMERATE)
- sce->gm.flag |= GAME_SHOW_FRAMERATE;
- if (fd->fileflags & G_FILE_SHOW_PHYSICS)
- sce->gm.flag |= GAME_SHOW_PHYSICS;
- if (fd->fileflags & G_FILE_GLSL_NO_SHADOWS)
- sce->gm.flag |= GAME_GLSL_NO_SHADOWS;
- if (fd->fileflags & G_FILE_GLSL_NO_SHADERS)
- sce->gm.flag |= GAME_GLSL_NO_SHADERS;
- if (fd->fileflags & G_FILE_GLSL_NO_RAMPS)
- sce->gm.flag |= GAME_GLSL_NO_RAMPS;
- if (fd->fileflags & G_FILE_GLSL_NO_NODES)
- sce->gm.flag |= GAME_GLSL_NO_NODES;
- if (fd->fileflags & G_FILE_GLSL_NO_EXTRA_TEX)
- sce->gm.flag |= GAME_GLSL_NO_EXTRA_TEX;
- if (fd->fileflags & G_FILE_GLSL_NO_ENV_LIGHTING)
- sce->gm.flag |= GAME_GLSL_NO_ENV_LIGHTING;
- if (fd->fileflags & G_FILE_IGNORE_DEPRECATION_WARNINGS)
- sce->gm.flag |= GAME_IGNORE_DEPRECATION_WARNINGS;
-
- if (fd->fileflags & G_FILE_GAME_MAT_GLSL)
- sce->gm.matmode = GAME_MAT_GLSL;
- else if (fd->fileflags & G_FILE_GAME_MAT)
- sce->gm.matmode = GAME_MAT_MULTITEX;
- else
- sce->gm.matmode = GAME_MAT_TEXFACE;
-
- sce->gm.flag |= GAME_DISPLAY_LISTS;
- }
-
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->flag & 8192) // OB_POSEMODE = 8192
ob->mode |= OB_MODE_POSE;
@@ -1117,10 +852,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 4)) {
Scene *sce;
Object *ob;
- Material *ma;
- Lamp *la;
- World *wo;
- Tex *tex;
ParticleSettings *part;
bool do_gravity = false;
@@ -1138,27 +869,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
ob->rotmode = ROT_MODE_EUL;
}
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->vol.reflection == 0.f) {
- ma->vol.reflection = 1.f;
- ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f;
- ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f;
- }
-
- do_version_mtex_factor_2_50(ma->mtex, ID_MA);
- }
-
- for (la = bmain->lamp.first; la; la = la->id.next)
- do_version_mtex_factor_2_50(la->mtex, ID_LA);
-
- for (wo = bmain->world.first; wo; wo = wo->id.next)
- do_version_mtex_factor_2_50(wo->mtex, ID_WO);
-
- for (tex = bmain->tex.first; tex; tex = tex->id.next)
- if (tex->vd)
- if (tex->vd->extend == 0)
- tex->vd->extend = TEX_CLIP;
-
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->audio.main == 0.0f)
sce->audio.main = 1.0f;
@@ -1219,7 +929,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 6)) {
Object *ob;
- Lamp *la;
/* New variables for axis-angle rotations and/or quaternion rotations were added, and need proper initialization */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
@@ -1237,9 +946,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
}
-
- for (la = bmain->lamp.first; la; la = la->id.next)
- la->compressthresh = 0.05f;
}
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 7)) {
@@ -1308,8 +1014,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
while (sce) {
if (sce->r.frame_step == 0)
sce->r.frame_step = 1;
- if (sce->r.mblur_samples == 0)
- sce->r.mblur_samples = sce->r.osa;
sce = sce->id.next;
}
@@ -1362,7 +1066,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile == 250) {
Scene *sce = bmain->scene.first;
Material *ma = bmain->mat.first;
- World *wo = bmain->world.first;
Tex *tex = bmain->tex.first;
int i, convert = 0;
@@ -1380,26 +1083,8 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (convert) {
while (ma) {
- if (ma->ramp_col) {
- ColorBand *band = (ColorBand *)ma->ramp_col;
- for (i = 0; i < band->tot; i++) {
- CBData *data = band->data + i;
- srgb_to_linearrgb_v3_v3(&data->r, &data->r);
- }
- }
-
- if (ma->ramp_spec) {
- ColorBand *band = (ColorBand *)ma->ramp_spec;
- for (i = 0; i < band->tot; i++) {
- CBData *data = band->data + i;
- srgb_to_linearrgb_v3_v3(&data->r, &data->r);
- }
- }
-
srgb_to_linearrgb_v3_v3(&ma->r, &ma->r);
srgb_to_linearrgb_v3_v3(&ma->specr, &ma->specr);
- srgb_to_linearrgb_v3_v3(&ma->mirr, &ma->mirr);
- srgb_to_linearrgb_v3_v3(ma->sss_col, ma->sss_col);
ma = ma->id.next;
}
@@ -1413,13 +1098,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
tex = tex->id.next;
}
-
- while (wo) {
- srgb_to_linearrgb_v3_v3(&wo->ambr, &wo->ambr);
- srgb_to_linearrgb_v3_v3(&wo->horr, &wo->horr);
- srgb_to_linearrgb_v3_v3(&wo->zenr, &wo->zenr);
- wo = wo->id.next;
- }
}
}
}
@@ -1548,15 +1226,8 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 12)) {
- Scene *sce;
Object *ob;
Brush *brush;
- Material *ma;
-
- /* game engine changes */
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- sce->gm.eyeseparation = 0.10f;
- }
/* anim viz changes */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
@@ -1638,14 +1309,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
BKE_texture_mtex_default(&brush->mtex);
BKE_texture_mtex_default(&brush->mask_mtex);
}
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->vol.ms_spread < 0.0001f) {
- ma->vol.ms_spread = 0.2f;
- ma->vol.ms_diff = 1.f;
- ma->vol.ms_intensity = 1.f;
- }
- }
}
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 13)) {
@@ -1704,41 +1367,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 15)) {
- World *wo;
- Material *ma;
-
- /* ambient default from 0.5f to 1.0f */
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- ma->amb *= 2.0f;
-
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- /* ao splitting into ao/env/indirect */
- wo->ao_env_energy = wo->aoenergy;
- wo->aoenergy = 1.0f;
-
- if (wo->ao_indirect_bounces == 0)
- wo->ao_indirect_bounces = 1;
- else
- wo->mode |= WO_INDIRECT_LIGHT;
-
- if (wo->aomix == WO_AOSUB)
- wo->ao_env_energy = -wo->ao_env_energy;
- else if (wo->aomix == WO_AOADDSUB)
- wo->mode |= WO_AMB_OCC;
-
- wo->aomix = WO_AOMUL;
-
- /* ambient default from 0.5f to 1.0f */
- mul_v3_fl(&wo->ambr, 0.5f);
- wo->ao_env_energy *= 0.5f;
- }
- }
-
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 17)) {
Scene *sce;
Sequence *seq;
- Material *ma;
/* initialize to sane default so toggling on border shows something */
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
@@ -1754,7 +1385,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if ((sce->r.ffcodecdata.flags & FFMPEG_MULTIPLEX_AUDIO) == 0)
sce->r.ffcodecdata.audio_codec = 0x0; // CODEC_ID_NONE
- SEQ_BEGIN (sce->ed, seq)
+ SEQ_BEGIN(sce->ed, seq)
{
seq->volume = 1.0f;
} SEQ_END;
@@ -1769,10 +1400,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
pset->brush[a].strength /= 100.0f;
}
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->mode & MA_TRACEBLE)
- ma->shade_flag |= MA_APPROX_OCCLUSION;
-
/* sequencer changes */
{
bScreen *screen;
@@ -1950,14 +1577,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
}
- else if (sl->spacetype == SPACE_TIME) {
- SpaceTime *stime = (SpaceTime *)sl;
-
- /* enable all cache display */
- stime->cache_display |= TIME_CACHE_DISPLAY;
- stime->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
- stime->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
- }
}
}
}
@@ -2176,7 +1795,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
Brush *br;
ParticleSettings *part;
bScreen *sc;
- Object *ob;
for (br = bmain->brush.first; br; br = br->id.next) {
if (br->ob_mode == 0)
@@ -2216,41 +1834,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
}
-
- /* fix rotation actuators for objects so they use real angles (radians)
- * since before blender went opensource this strange scalar was used: (1 / 0.02) * 2 * math.pi/360 */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- bActuator *act = ob->actuators.first;
- while (act) {
- if (act->type == ACT_OBJECT) {
- /* multiply velocity with 50 in old files */
- bObjectActuator *oa = act->data;
- mul_v3_fl(oa->drot, 0.8726646259971648f);
- }
- act = act->next;
- }
- }
- }
-
- /* init facing axis property of steering actuators */
- {
- Object *ob;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- bActuator *act;
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_STEERING) {
- bSteeringActuator *stact = act->data;
- if (stact == NULL) {//HG1
- init_actuator(act);
- }
- else {
- if (stact->facingaxis == 0) {
- stact->facingaxis = 1;
- }
- }
- }
- }
- }
}
if (bmain->versionfile < 255 || (bmain->versionfile == 255 && bmain->subversionfile < 3)) {
@@ -2409,27 +1992,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
Brush *brush;
Object *ob;
ParticleSettings *part;
- Material *mat;
- int tex_nr, transp_tex;
-
- for (mat = bmain->mat.first; mat; mat = mat->id.next) {
- if (!(mat->mode & MA_TRANSP) && !(mat->material_type & MA_TYPE_VOLUME)) {
- transp_tex = 0;
-
- for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
- if (!mat->mtex[tex_nr])
- continue;
- if (mat->mtex[tex_nr]->mapto & MAP_ALPHA)
- transp_tex = 1;
- }
-
- /* weak! material alpha could be animated */
- if (mat->alpha < 1.0f || mat->fresnel_tra > 0.0f || transp_tex) {
- mat->mode |= MA_TRANSP;
- mat->mode &= ~(MA_ZTRANSP | MA_RAYTRANSP);
- }
- }
- }
/* redraws flag in SpaceTime has been moved to Screen level */
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
@@ -2523,41 +2085,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
{
- /* Initialize texture point density curve falloff */
- Tex *tex;
- for (tex = bmain->tex.first; tex; tex = tex->id.next) {
- if (tex->pd) {
- if (tex->pd->falloff_speed_scale == 0.0f)
- tex->pd->falloff_speed_scale = 100.0f;
-
- if (!tex->pd->falloff_curve) {
- tex->pd->falloff_curve = curvemapping_add(1, 0, 0, 1, 1);
-
- tex->pd->falloff_curve->preset = CURVE_PRESET_LINE;
- tex->pd->falloff_curve->cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
- curvemap_reset(tex->pd->falloff_curve->cm, &tex->pd->falloff_curve->clipr, tex->pd->falloff_curve->preset, CURVEMAP_SLOPE_POSITIVE);
- curvemapping_changed(tex->pd->falloff_curve, false);
- }
- }
- }
- }
-
- {
- /* add default value for behind strength of camera actuator */
- Object *ob;
- bActuator *act;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_CAMERA) {
- bCameraActuator *ba = act->data;
-
- ba->damping = 1.0 / 32.0;
- }
- }
- }
- }
-
- {
ParticleSettings *part;
for (part = bmain->particle.first; part; part = part->id.next) {
/* Initialize particle billboard scale */
@@ -2647,50 +2174,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
}
-
- {
- /* convert fcurve and shape action actuators to action actuators */
- Object *ob;
- bActuator *act;
- bIpoActuator *ia;
- bActionActuator *aa;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_IPO) {
- /* Create the new actuator */
- ia = act->data;
- aa = MEM_callocN(sizeof(bActionActuator), "fcurve -> action actuator do_version");
-
- /* Copy values */
- aa->type = ia->type;
- aa->flag = ia->flag;
- aa->sta = ia->sta;
- aa->end = ia->end;
- BLI_strncpy(aa->name, ia->name, sizeof(aa->name));
- BLI_strncpy(aa->frameProp, ia->frameProp, sizeof(aa->frameProp));
- if (ob->adt)
- aa->act = ob->adt->action;
-
- /* Get rid of the old actuator */
- MEM_freeN(ia);
-
- /* Assign the new actuator */
- act->data = aa;
- act->type = act->otype = ACT_ACTION;
-
- /* Fix for converting 2.4x files: if we don't have an action, but we have an
- * object IPO, then leave the actuator as an IPO actuator for now and let the
- * IPO conversion code handle it */
- if (ob->ipo && !aa->act)
- act->type = ACT_IPO;
- }
- else if (act->type == ACT_SHAPEACTION) {
- act->type = act->otype = ACT_ACTION;
- }
- }
- }
- }
}
if (bmain->versionfile < 259 || (bmain->versionfile == 259 && bmain->subversionfile < 2)) {
@@ -2737,41 +2220,5 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
part->time_flag &= ~PART_TIME_AUTOSF;
}
}
-
- {
- /* set defaults for obstacle avoidance, recast data */
- Scene *sce;
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->gm.levelHeight == 0.f)
- sce->gm.levelHeight = 2.f;
-
- if (sce->gm.recastData.cellsize == 0.0f)
- sce->gm.recastData.cellsize = 0.3f;
- if (sce->gm.recastData.cellheight == 0.0f)
- sce->gm.recastData.cellheight = 0.2f;
- if (sce->gm.recastData.agentmaxslope == 0.0f)
- sce->gm.recastData.agentmaxslope = (float)M_PI / 4;
- if (sce->gm.recastData.agentmaxclimb == 0.0f)
- sce->gm.recastData.agentmaxclimb = 0.9f;
- if (sce->gm.recastData.agentheight == 0.0f)
- sce->gm.recastData.agentheight = 2.0f;
- if (sce->gm.recastData.agentradius == 0.0f)
- sce->gm.recastData.agentradius = 0.6f;
- if (sce->gm.recastData.edgemaxlen == 0.0f)
- sce->gm.recastData.edgemaxlen = 12.0f;
- if (sce->gm.recastData.edgemaxerror == 0.0f)
- sce->gm.recastData.edgemaxerror = 1.3f;
- if (sce->gm.recastData.regionminsize == 0.0f)
- sce->gm.recastData.regionminsize = 8.f;
- if (sce->gm.recastData.regionmergesize == 0.0f)
- sce->gm.recastData.regionmergesize = 20.f;
- if (sce->gm.recastData.vertsperpoly < 3)
- sce->gm.recastData.vertsperpoly = 6;
- if (sce->gm.recastData.detailsampledist == 0.0f)
- sce->gm.recastData.detailsampledist = 6.0f;
- if (sce->gm.recastData.detailsamplemaxerror == 0.0f)
- sce->gm.recastData.detailsamplemaxerror = 1.0f;
- }
- }
}
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index af291981e7f..d1589aa0d5e 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -31,7 +31,6 @@
#define DNA_DEPRECATED_ALLOW
#include "DNA_anim_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
@@ -43,11 +42,9 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_fluidsim_types.h"
#include "DNA_object_types.h"
-#include "DNA_property_types.h"
#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
-#include "DNA_sensor_types.h"
#include "DNA_sdna_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
@@ -67,7 +64,6 @@
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "BKE_property.h" // for BKE_bproperty_object_get
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
@@ -432,25 +428,6 @@ static void do_versions_nodetree_frame_2_64_6(bNodeTree *ntree)
}
}
-static void do_version_logic_264(ListBase *regionbase)
-{
- ARegion *ar;
-
- /* view settings for logic changed */
- for (ar = regionbase->first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- if (ar->v2d.keeptot == 0) {
- ar->v2d.maxzoom = 1.5f;
-
- ar->v2d.keepzoom = V2D_KEEPZOOM | V2D_LIMITZOOM | V2D_KEEPASPECT;
- ar->v2d.keeptot = V2D_KEEPTOT_BOUNDS;
- ar->v2d.align = V2D_ALIGN_NO_POS_Y | V2D_ALIGN_NO_NEG_X;
- ar->v2d.keepofs = V2D_KEEPOFS_Y;
- }
- }
- }
-}
-
static void do_versions_affine_tracker_track(MovieTrackingTrack *track)
{
int i;
@@ -900,14 +877,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
{
- /* Initialize BGE exit key to esc key */
- Scene *scene;
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- if (!scene->gm.exitkey)
- scene->gm.exitkey = 218; // Blender key code for ESC
- }
- }
- {
MovieClip *clip;
Object *ob;
@@ -943,45 +912,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
- {
- /* Warn the user if he is using ["Text"] properties for Font objects */
- Object *ob;
- bProperty *prop;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->type == OB_FONT) {
- prop = BKE_bproperty_object_get(ob, "Text");
- if (prop) {
- blo_reportf_wrap(fd->reports, RPT_WARNING,
- TIP_("Game property name conflict in object '%s': text objects reserve the "
- "['Text'] game property to change their content through logic bricks"),
- ob->id.name + 2);
- }
- }
- }
- }
}
if (bmain->versionfile < 261 || (bmain->versionfile == 261 && bmain->subversionfile < 2)) {
{
- /* convert Camera Actuator values to defines */
- Object *ob;
- bActuator *act;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_CAMERA) {
- bCameraActuator *ba = act->data;
-
- if (ba->axis == (float)'x') ba->axis = OB_POSX;
- else if (ba->axis == (float)'y') ba->axis = OB_POSY;
- /* don't do an if/else to avoid imediate subversion bump*/
-// ba->axis=((ba->axis == (float)'x') ? OB_POSX_X : OB_POSY);
- }
- }
- }
- }
-
- {
/* convert deprecated sculpt_paint_unified_* fields to
* UnifiedPaintSettings */
Scene *scene;
@@ -1222,15 +1156,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 4)) {
- Lamp *la;
Camera *cam;
Curve *cu;
- for (la = bmain->lamp.first; la; la = la->id.next) {
- if (la->shadow_frustum_size == 0.0f)
- la->shadow_frustum_size = 10.0f;
- }
-
for (cam = bmain->camera.first; cam; cam = cam->id.next) {
if (cam->flag & CAM_PANORAMA) {
cam->type = CAM_PANO;
@@ -1316,19 +1244,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
-
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 8)) {
- /* set new deactivation values for game settings */
- Scene *sce;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- /* Game Settings */
- sce->gm.lineardeactthreshold = 0.8f;
- sce->gm.angulardeactthreshold = 1.0f;
- sce->gm.deactivationtime = 2.0f;
- }
- }
-
if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 9)) {
FOREACH_NODETREE_BEGIN(bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
@@ -1339,7 +1254,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
tex->iuser.frames = 1;
tex->iuser.sfra = 1;
- tex->iuser.fie_ima = 2;
tex->iuser.ok = 1;
}
}
@@ -1420,14 +1334,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 12)) {
- Material *ma;
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->strand_widthfade == 2.0f)
- ma->strand_widthfade = 0.0f;
- }
-
if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 13)) {
FOREACH_NODETREE_BEGIN(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
@@ -1573,20 +1479,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* remove texco */
if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 21)) {
- Material *ma;
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- int a;
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- if (ma->mtex[a]->texco == TEXCO_STICKY_) {
- ma->mtex[a]->texco = TEXCO_UV;
- }
- }
- }
- }
-
{
Mesh *me;
for (me = bmain->mesh.first; me; me = me->id.next) {
@@ -1737,24 +1630,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
} FOREACH_NODETREE_END;
}
- if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 6)) {
- bScreen *sc;
-
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- if (sa->spacetype == SPACE_LOGIC)
- do_version_logic_264(&sa->regionbase);
-
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_LOGIC)
- do_version_logic_264(&sl->regionbase);
- }
- }
- }
- }
-
if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 7)) {
/* convert tiles size from resolution and number of tiles */
{
@@ -1762,17 +1637,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->r.tilex == 0 || scene->r.tiley == 1) {
- if (scene->r.xparts && scene->r.yparts) {
- /* scene could be set for panoramic rendering, so clamp with the
- * lowest possible tile size value
- */
- scene->r.tilex = max_ii(scene->r.xsch * scene->r.size / scene->r.xparts / 100, 8);
- scene->r.tiley = max_ii(scene->r.ysch * scene->r.size / scene->r.yparts / 100, 8);
- }
- else {
- /* happens when mixing using current trunk and previous release */
- scene->r.tilex = scene->r.tiley = 64;
- }
+ scene->r.tilex = scene->r.tiley = 64;
}
}
}
@@ -1808,17 +1673,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- if (bmain->versionfile < 265) {
- Object *ob;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->step_height == 0.0f) {
- ob->step_height = 0.15f;
- ob->jump_speed = 10.0f;
- ob->fall_speed = 55.0f;
- }
- }
- }
-
if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 3)) {
bScreen *sc;
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
@@ -1830,7 +1684,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
case SPACE_VIEW3D:
{
View3D *v3d = (View3D *)sl;
- v3d->flag2 |= V3D_SHOW_GPENCIL;
+ v3d->flag2 |= V3D_SHOW_ANNOTATION;
break;
}
case SPACE_SEQ:
@@ -1854,7 +1708,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
case SPACE_CLIP:
{
SpaceClip *sclip = (SpaceClip *)sl;
- sclip->flag |= SC_SHOW_GPENCIL;
+ sclip->flag |= SC_SHOW_ANNOTATION;
break;
}
}
@@ -1869,7 +1723,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
- bool set_premul = false;
SEQ_BEGIN (scene->ed, seq)
{
@@ -1883,24 +1736,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (scene->r.bake_samples == 0)
scene->r.bake_samples = 256;
-
- if (scene->world) {
- World *world = blo_do_versions_newlibadr(fd, scene->id.lib, scene->world);
-
- if (world && is_zero_v3(&world->horr)) {
- if ((world->skytype & WO_SKYBLEND) == 0 || is_zero_v3(&world->zenr)) {
- set_premul = true;
- }
- }
- }
- else
- set_premul = true;
-
- if (set_premul) {
- printf("2.66 versioning fix: replacing black sky with premultiplied alpha for scene %s\n",
- scene->id.name + 2);
- scene->r.alphamode = R_ALPHAPREMUL;
- }
}
for (Image *image = bmain->image.first; image; image = image->id.next) {
@@ -2333,32 +2168,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- bSensor *sens;
- bTouchSensor *ts;
- bCollisionSensor *cs;
- Material *ma;
-
- for (sens = ob->sensors.first; sens; sens = sens->next) {
- if (sens->type == SENS_TOUCH) {
- ts = sens->data;
- cs = MEM_callocN(sizeof(bCollisionSensor), "touch -> collision sensor do_version");
-
- if (ts->ma) {
- ma = blo_do_versions_newlibadr(fd, ob->id.lib, ts->ma);
- BLI_strncpy(cs->materialName, ma->id.name + 2, sizeof(cs->materialName));
- }
-
- cs->mode = SENS_COLLISION_MATERIAL;
-
- MEM_freeN(ts);
-
- sens->data = cs;
- sens->type = sens->otype = SENS_COLLISION;
- }
- }
- }
}
if (!MAIN_VERSION_ATLEAST(bmain, 268, 5)) {
@@ -2451,11 +2260,13 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so = (SpaceOops *)sl;
- if (!ELEM(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE,
- SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS,
- SO_USERDEF))
+ if (!ELEM(so->outlinevis,
+ SO_SCENES,
+ SO_LIBRARIES,
+ SO_SEQUENCE,
+ SO_DATA_API))
{
- so->outlinevis = SO_ALL_SCENES;
+ so->outlinevis = SO_SCENES;
}
}
}
@@ -2509,10 +2320,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (ts->sculpt)
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE;
- /* single texture mode removed from game engine */
- if (scene->gm.matmode == GAME_MAT_TEXFACE)
- scene->gm.matmode = GAME_MAT_MULTITEX;
-
/* 'Increment' mode disabled for nodes, use true grid snapping instead */
if (scene->toolsettings->snap_node_mode == SCE_SNAP_MODE_INCREMENT)
scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
@@ -2539,8 +2346,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
- bSensor *bs;
- bActuator *ba;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_EdgeSplit) {
@@ -2552,28 +2357,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
bmd->bevel_angle = DEG2RADF(bmd->bevel_angle);
}
}
-
- for (bs = ob->sensors.first; bs; bs = bs->next) {
- if (bs->type == SENS_RADAR) {
- bRadarSensor *brs = bs->data;
- brs->angle = DEG2RADF(brs->angle);
- }
- }
-
- for (ba = ob->actuators.first; ba; ba = ba->next) {
- if (ba->type == ACT_CONSTRAINT) {
- bConstraintActuator *bca = ba->data;
- if (bca->type == ACT_CONST_TYPE_ORI) {
- bca->minloc[0] = DEG2RADF(bca->minloc[0]);
- bca->maxloc[0] = DEG2RADF(bca->maxloc[0]);
- }
- }
- else if (ba->type == ACT_SOUND) {
- bSoundActuator *bsa = ba->data;
- bsa->sound3D.cone_outer_angle = DEG2RADF(bsa->sound3D.cone_outer_angle);
- bsa->sound3D.cone_inner_angle = DEG2RADF(bsa->sound3D.cone_inner_angle);
- }
- }
}
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 7884a628147..568b3c580a2 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -52,7 +52,6 @@
#include "DNA_modifier_types.h"
#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_view3d_types.h"
#include "DNA_smoke_types.h"
#include "DNA_rigidbody_types.h"
@@ -77,6 +76,9 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
#include "BLO_readfile.h"
@@ -88,6 +90,64 @@
#include "MEM_guardedalloc.h"
+/* ************************************************** */
+/* GP Palettes API (Deprecated) */
+
+/* add a new gp-palette */
+static bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name)
+{
+ bGPDpalette *palette;
+
+ /* check that list is ok */
+ if (gpd == NULL) {
+ return NULL;
+ }
+
+ /* allocate memory and add to end of list */
+ palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette");
+
+ /* add to datablock */
+ BLI_addtail(&gpd->palettes, palette);
+
+ /* set basic settings */
+ /* auto-name */
+ BLI_strncpy(palette->info, name, sizeof(palette->info));
+ BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
+ sizeof(palette->info));
+
+ /* return palette */
+ return palette;
+}
+
+/* add a new gp-palettecolor */
+static bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name)
+{
+ bGPDpalettecolor *palcolor;
+
+ /* check that list is ok */
+ if (palette == NULL) {
+ return NULL;
+ }
+
+ /* allocate memory and add to end of list */
+ palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor");
+
+ /* add to datablock */
+ BLI_addtail(&palette->colors, palcolor);
+
+ /* set basic settings */
+ copy_v4_v4(palcolor->color, U.gpencil_new_layer_col);
+ ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f);
+
+ /* auto-name */
+ BLI_strncpy(palcolor->info, name, sizeof(palcolor->info));
+ BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
+ sizeof(palcolor->info));
+
+ /* return palette color */
+ return palcolor;
+}
+
/**
* Setup rotation stabilization from ancient single track spec.
* Former Version of 2D stabilization used a single tracking marker to determine the rotation
@@ -308,18 +368,6 @@ static char *replace_bbone_easing_rnapath(char *old_path)
}
}
-/* NOTE: this version patch is intended for versions < 2.52.2, but was initially introduced in 2.27 already.
- * But in 2.79 another case generating non-unique names was discovered (see T55668, involving Meta strips)... */
-static void do_versions_seq_unique_name_all_strips(Scene *sce, ListBase *seqbasep)
-{
- for (Sequence *seq = seqbasep->first; seq != NULL; seq = seq->next) {
- BKE_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq);
- if (seq->seqbase.first != NULL) {
- do_versions_seq_unique_name_all_strips(sce, &seq->seqbase);
- }
- }
-}
-
static void do_version_bbone_easing_fcurve_fix(ID *UNUSED(id), FCurve *fcu, void *UNUSED(user_data))
{
/* F-Curve's path (for bbone_in/out) */
@@ -418,7 +466,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 270, 1)) {
- Scene *sce;
Object *ob;
/* Update Transform constraint (another deg -> rad stuff). */
@@ -433,12 +480,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->r.raytrace_structure == R_RAYSTRUCTURE_BLIBVH) {
- sce->r.raytrace_structure = R_RAYSTRUCTURE_AUTO;
- }
- }
}
if (!MAIN_VERSION_ATLEAST(bmain, 270, 2)) {
@@ -501,13 +542,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 271, 0)) {
- if (!DNA_struct_elem_find(fd->filesdna, "Material", "int", "mode2")) {
- Material *ma;
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- ma->mode2 = MA_CASTSHADOW;
- }
-
if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "BakeData", "bake")) {
Scene *sce;
@@ -566,29 +600,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- if (!MAIN_VERSION_ATLEAST(bmain, 271, 2)) {
- /* init up & track axis property of trackto actuators */
- Object *ob;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- bActuator *act;
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_EDIT_OBJECT) {
- bEditObjectActuator *eoact = act->data;
- eoact->trackflag = ob->trackflag;
- /* if trackflag is pointing +-Z axis then upflag should point Y axis.
- * Rest of trackflag cases, upflag should be point z axis */
- if ((ob->trackflag == OB_POSZ) || (ob->trackflag == OB_NEGZ)) {
- eoact->upflag = 1;
- }
- else {
- eoact->upflag = 2;
- }
- }
- }
- }
- }
-
if (!MAIN_VERSION_ATLEAST(bmain, 271, 3)) {
Brush *br;
@@ -869,40 +880,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- if (!DNA_struct_elem_find(fd->filesdna, "GameData", "int", "scehysteresis")) {
- Scene *scene;
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- scene->gm.scehysteresis = 10;
- }
- }
- }
-
- if (!MAIN_VERSION_ATLEAST(bmain, 274, 2)) {
- FOREACH_NODETREE_BEGIN(bmain, ntree, id) {
- bNode *node;
- bNodeSocket *sock;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_MATERIAL) {
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Refl")) {
- BLI_strncpy(sock->name, "DiffuseIntensity", sizeof(sock->name));
- }
- }
- }
- else if (node->type == SH_NODE_MATERIAL_EXT) {
- for (sock = node->outputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Refl")) {
- BLI_strncpy(sock->name, "DiffuseIntensity", sizeof(sock->name));
- }
- else if (STREQ(sock->name, "Ray Mirror")) {
- BLI_strncpy(sock->name, "Reflectivity", sizeof(sock->name));
- }
- }
- }
- }
- } FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 274, 4)) {
@@ -1103,16 +1080,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
#undef LA_YF_PHOTON
}
-
- {
- Object *ob;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->body_type == OB_BODY_TYPE_CHARACTER && (ob->gameflag & OB_BOUNDS) && ob->collision_boundtype == OB_BOUND_TRIANGLE_MESH) {
- ob->boundtype = ob->collision_boundtype = OB_BOUND_BOX;
- }
- }
- }
-
}
if (!MAIN_VERSION_ATLEAST(bmain, 276, 3)) {
@@ -1135,45 +1102,45 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
ToolSettings *ts = scene->toolsettings;
if (ts->gp_sculpt.brush[0].size == 0) {
- GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
- GP_EditBrush_Data *brush;
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ GP_Sculpt_Data *brush;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
+ brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
brush->size = 25;
brush->strength = 0.3f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+ brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_SMOOTH_PRESSURE;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
+ brush = &gset->brush[GP_SCULPT_TYPE_THICKNESS];
brush->size = 25;
brush->strength = 0.5f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
+ brush = &gset->brush[GP_SCULPT_TYPE_GRAB];
brush->size = 50;
brush->strength = 0.3f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
+ brush = &gset->brush[GP_SCULPT_TYPE_PUSH];
brush->size = 25;
brush->strength = 0.3f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
+ brush = &gset->brush[GP_SCULPT_TYPE_TWIST];
brush->size = 50;
brush->strength = 0.3f; // XXX?
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
+ brush = &gset->brush[GP_SCULPT_TYPE_PINCH];
brush->size = 50;
brush->strength = 0.5f; // XXX?
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
+ brush = &gset->brush[GP_SCULPT_TYPE_RANDOMIZE];
brush->size = 25;
brush->strength = 0.5f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_CLONE];
+ brush = &gset->brush[GP_SCULPT_TYPE_CLONE];
brush->size = 50;
brush->strength = 1.0f;
}
@@ -1223,12 +1190,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
else
gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
}
-
- if (!DNA_struct_elem_find(fd->filesdna, "Object", "unsigned char", "max_jumps")) {
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- ob->max_jumps = 1;
- }
- }
}
if (!MAIN_VERSION_ATLEAST(bmain, 276, 5)) {
ListBase *lbarray[MAX_LIBARRAY];
@@ -1441,28 +1402,17 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (Scene *scene = bmain->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;
+ ts->gp_sculpt.flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
/* new strength sculpt brush */
if (ts->gp_sculpt.brush[0].size >= 11) {
- GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
- GP_EditBrush_Data *brush;
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ GP_Sculpt_Data *brush;
- brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
+ brush = &gset->brush[GP_SCULPT_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(&bmain->gpencil)) {
- for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
- ToolSettings *ts = scene->toolsettings;
- if (BLI_listbase_is_empty(&ts->gp_brushes)) {
- BKE_gpencil_brush_init_presets(ts);
- }
+ brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
}
}
/* Convert Grease Pencil to new palettes/brushes
@@ -1471,10 +1421,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
if (BLI_listbase_is_empty(&gpd->palettes)) {
/* create palette */
- bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette", true);
+ bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette");
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* create color using layer name */
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info, true);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info);
if (palcolor != NULL) {
/* set color attributes */
copy_v4_v4(palcolor->color, gpl->color);
@@ -1484,7 +1434,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (gpl->flag & GP_LAYER_LOCKED) palcolor->flag |= PC_COLOR_LOCKED;
if (gpl->flag & GP_LAYER_ONIONSKIN) palcolor->flag |= PC_COLOR_ONIONSKIN;
if (gpl->flag & GP_LAYER_VOLUMETRIC) palcolor->flag |= PC_COLOR_VOLUMETRIC;
- if (gpl->flag & GP_LAYER_HQ_FILL) palcolor->flag |= PC_COLOR_HQ_FILL;
/* set layer opacity to 1 */
gpl->opacity = 1.0f;
@@ -1497,8 +1446,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* set stroke to palette and force recalculation */
BLI_strncpy(gps->colorname, gpl->info, sizeof(gps->colorname));
- gps->palcolor = NULL;
- gps->flag |= GP_STROKE_RECALC_COLOR;
gps->thickness = gpl->thickness;
/* set alpha strength to 1 */
@@ -1508,13 +1455,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- /* set thickness to 0 (now it is a factor to override stroke thickness) */
- gpl->thickness = 0.0f;
}
- /* set first color as active */
- if (palette->colors.first)
- BKE_gpencil_palettecolor_setactive(palette, palette->colors.first);
}
}
}
@@ -1836,14 +1777,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- if (!MAIN_VERSION_ATLEAST(bmain, 279, 6)) {
- for (Scene *sce = bmain->scene.first; sce != NULL; sce = sce->id.next) {
- if (sce->ed != NULL && sce->ed->seqbase.first != NULL) {
- do_versions_seq_unique_name_all_strips(sce, &sce->ed->seqbase);
- }
- }
- }
}
void do_versions_after_linking_270(Main *bmain)
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
new file mode 100644
index 00000000000..434153fc7b9
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -0,0 +1,2484 @@
+/*
+ * ***** 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): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenloader/intern/versioning_280.c
+ * \ingroup blenloader
+ */
+
+/* allow readfile to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include <string.h>
+#include <float.h>
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_cloth_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_gpu_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_genfile.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_key_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_armature_types.h"
+
+#include "BKE_action.h"
+#include "BKE_cloth.h"
+#include "BKE_collection.h"
+#include "BKE_constraint.h"
+#include "BKE_colortools.h"
+#include "BKE_customdata.h"
+#include "BKE_freestyle.h"
+#include "BKE_gpencil.h"
+#include "BKE_idprop.h"
+#include "BKE_image.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_sequencer.h"
+#include "BKE_studiolight.h"
+#include "BKE_unit.h"
+#include "BKE_workspace.h"
+
+/* Only for IMB_BlendMode */
+#include "IMB_imbuf.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BLT_translation.h"
+
+#include "BLO_readfile.h"
+#include "readfile.h"
+
+#include "MEM_guardedalloc.h"
+
+static bScreen *screen_parent_find(const bScreen *screen)
+{
+ /* can avoid lookup if screen state isn't maximized/full (parent and child store the same state) */
+ if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
+ for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->full && sa->full != screen) {
+ BLI_assert(sa->full->state == screen->state);
+ return sa->full;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void do_version_workspaces_create_from_screens(Main *bmain)
+{
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ const bScreen *screen_parent = screen_parent_find(screen);
+ WorkSpace *workspace;
+ if (screen->temp) {
+ continue;
+ }
+
+ if (screen_parent) {
+ /* fullscreen with "Back to Previous" option, don't create
+ * a new workspace, add layout workspace containing parent */
+ workspace = BLI_findstring(
+ &bmain->workspaces, screen_parent->id.name + 2, offsetof(ID, name) + 2);
+ }
+ else {
+ workspace = BKE_workspace_add(bmain, screen->id.name + 2);
+ }
+ if (workspace == NULL) {
+ continue; /* Not much we can do.. */
+ }
+ BKE_workspace_layout_add(bmain, workspace, screen, screen->id.name + 2);
+ }
+}
+
+static void do_version_area_change_space_to_space_action(ScrArea *area, const Scene *scene)
+{
+ SpaceType *stype = BKE_spacetype_from_id(SPACE_ACTION);
+ SpaceAction *saction = (SpaceAction *)stype->new(area, scene);
+ ARegion *region_channels;
+
+ /* Properly free current regions */
+ for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ BKE_area_region_free(area->type, region);
+ }
+ BLI_freelistN(&area->regionbase);
+
+ area->type = stype;
+ area->spacetype = stype->spaceid;
+
+ BLI_addhead(&area->spacedata, saction);
+ area->regionbase = saction->regionbase;
+ BLI_listbase_clear(&saction->regionbase);
+
+ /* Different defaults for timeline */
+ region_channels = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
+ region_channels->flag |= RGN_FLAG_HIDDEN;
+
+ saction->mode = SACTCONT_TIMELINE;
+ saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED;
+ saction->ads.filterflag |= ADS_FILTER_SUMMARY;
+}
+
+/**
+ * \brief After lib-link versioning for new workspace design.
+ *
+ * - Adds a workspace for (almost) each screen of the old file
+ * and adds the needed workspace-layout to wrap the screen.
+ * - Active screen isn't stored directly in window anymore, but in the active workspace.
+ * - Active scene isn't stored in screen anymore, but in window.
+ * - Create workspace instance hook for each window.
+ *
+ * \note Some of the created workspaces might be deleted again in case of reading the default startup.blend.
+ */
+static void do_version_workspaces_after_lib_link(Main *bmain)
+{
+ BLI_assert(BLI_listbase_is_empty(&bmain->workspaces));
+
+ do_version_workspaces_create_from_screens(bmain);
+
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen_parent = screen_parent_find(win->screen);
+ bScreen *screen = screen_parent ? screen_parent : win->screen;
+
+ if (screen->temp) {
+ /* We do not generate a new workspace for those screens... still need to set some data in win. */
+ win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
+ win->scene = screen->scene;
+ /* Deprecated from now on! */
+ win->screen = NULL;
+ continue;
+ }
+
+ WorkSpace *workspace = BLI_findstring(&bmain->workspaces, screen->id.name + 2, offsetof(ID, name) + 2);
+ BLI_assert(workspace != NULL);
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
+
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ BKE_workspace_active_layout_set(win->workspace_hook, layouts->first);
+
+ /* Move scene and view layer to window. */
+ Scene *scene = screen->scene;
+ ViewLayer *layer = BLI_findlink(&scene->view_layers, scene->r.actlay);
+ if (!layer) {
+ layer = BKE_view_layer_default_view(scene);
+ }
+
+ win->scene = scene;
+ STRNCPY(win->view_layer_name, layer->name);
+
+ /* Deprecated from now on! */
+ win->screen = NULL;
+ }
+ }
+
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ /* Deprecated from now on! */
+ BLI_freelistN(&screen->scene->transform_spaces);
+ screen->scene = NULL;
+ }
+}
+
+#ifdef USE_COLLECTION_COMPAT_28
+enum {
+ COLLECTION_DEPRECATED_VISIBLE = (1 << 0),
+ COLLECTION_DEPRECATED_VIEWPORT = (1 << 0),
+ COLLECTION_DEPRECATED_SELECTABLE = (1 << 1),
+ COLLECTION_DEPRECATED_DISABLED = (1 << 2),
+ COLLECTION_DEPRECATED_RENDER = (1 << 3),
+};
+
+static void do_version_view_layer_visibility(ViewLayer *view_layer)
+{
+ /* Convert from deprecated VISIBLE flag to DISABLED */
+ LayerCollection *lc;
+ for (lc = view_layer->layer_collections.first;
+ lc;
+ lc = lc->next)
+ {
+ if (lc->flag & COLLECTION_DEPRECATED_DISABLED) {
+ lc->flag &= ~COLLECTION_DEPRECATED_DISABLED;
+ }
+
+ if ((lc->flag & COLLECTION_DEPRECATED_VISIBLE) == 0) {
+ lc->flag |= COLLECTION_DEPRECATED_DISABLED;
+ }
+
+ lc->flag |= COLLECTION_DEPRECATED_VIEWPORT | COLLECTION_DEPRECATED_RENDER;
+ }
+}
+
+static void do_version_layer_collection_pre(
+ ViewLayer *view_layer,
+ ListBase *lb,
+ GSet *enabled_set,
+ GSet *selectable_set)
+{
+ /* Convert from deprecated DISABLED to new layer collection and collection flags */
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ if (lc->scene_collection) {
+ if (!(lc->flag & COLLECTION_DEPRECATED_DISABLED)) {
+ BLI_gset_insert(enabled_set, lc->scene_collection);
+ }
+ if (lc->flag & COLLECTION_DEPRECATED_SELECTABLE) {
+ BLI_gset_insert(selectable_set, lc->scene_collection);
+ }
+ }
+
+ do_version_layer_collection_pre(view_layer, &lc->layer_collections, enabled_set, selectable_set);
+ }
+}
+
+static void do_version_layer_collection_post(
+ ViewLayer *view_layer,
+ ListBase *lb,
+ GSet *enabled_set,
+ GSet *selectable_set,
+ GHash *collection_map)
+{
+ /* Apply layer collection exclude flags. */
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ if (!(lc->collection->flag & COLLECTION_IS_MASTER)) {
+ SceneCollection *sc = BLI_ghash_lookup(collection_map, lc->collection);
+ const bool enabled = (sc && BLI_gset_haskey(enabled_set, sc));
+ const bool selectable = (sc && BLI_gset_haskey(selectable_set, sc));
+
+ if (!enabled) {
+ lc->flag |= LAYER_COLLECTION_EXCLUDE;
+ }
+ if (enabled && !selectable) {
+ lc->collection->flag |= COLLECTION_RESTRICT_SELECT;
+ }
+ }
+
+ do_version_layer_collection_post(
+ view_layer, &lc->layer_collections, enabled_set, selectable_set, collection_map);
+ }
+}
+
+static void do_version_scene_collection_convert(
+ Main *bmain,
+ ID *id,
+ SceneCollection *sc,
+ Collection *collection,
+ GHash *collection_map)
+{
+ if (collection_map) {
+ BLI_ghash_insert(collection_map, collection, sc);
+ }
+
+ for (SceneCollection *nsc = sc->scene_collections.first; nsc;) {
+ SceneCollection *nsc_next = nsc->next;
+ Collection *ncollection = BKE_collection_add(bmain, collection, nsc->name);
+ ncollection->id.lib = id->lib;
+ do_version_scene_collection_convert(bmain, id, nsc, ncollection, collection_map);
+ nsc = nsc_next;
+ }
+
+ for (LinkData *link = sc->objects.first; link; link = link->next) {
+ Object *ob = link->data;
+ if (ob) {
+ BKE_collection_object_add(bmain, collection, ob);
+ id_us_min(&ob->id);
+ }
+ }
+
+ BLI_freelistN(&sc->objects);
+ MEM_freeN(sc);
+}
+
+static void do_version_group_collection_to_collection(Main *bmain, Collection *group)
+{
+ /* Convert old 2.8 group collections to new unified collections. */
+ if (group->collection) {
+ do_version_scene_collection_convert(bmain, &group->id, group->collection, group, NULL);
+ }
+
+ group->collection = NULL;
+ group->view_layer = NULL;
+ id_fake_user_set(&group->id);
+}
+
+static void do_version_scene_collection_to_collection(Main *bmain, Scene *scene)
+{
+ /* Convert old 2.8 scene collections to new unified collections. */
+
+ /* Temporarily clear view layers so we don't do any layer collection syncing
+ * and destroy old flags that we want to restore. */
+ ListBase view_layers = scene->view_layers;
+ BLI_listbase_clear(&scene->view_layers);
+
+ if (!scene->master_collection) {
+ scene->master_collection = BKE_collection_master_add();
+ }
+
+ /* Convert scene collections. */
+ GHash *collection_map = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ if (scene->collection) {
+ do_version_scene_collection_convert(bmain, &scene->id, scene->collection, scene->master_collection, collection_map);
+ scene->collection = NULL;
+ }
+
+ scene->view_layers = view_layers;
+
+ /* Convert layer collections. */
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ GSet *enabled_set = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ GSet *selectable_set = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+
+ do_version_layer_collection_pre(
+ view_layer, &view_layer->layer_collections, enabled_set, selectable_set);
+
+ BKE_layer_collection_sync(scene, view_layer);
+
+ do_version_layer_collection_post(
+ view_layer, &view_layer->layer_collections, enabled_set, selectable_set, collection_map);
+
+ BLI_gset_free(enabled_set, NULL);
+ BLI_gset_free(selectable_set, NULL);
+
+ BKE_layer_collection_sync(scene, view_layer);
+ }
+
+ BLI_ghash_free(collection_map, NULL, NULL);
+}
+#endif
+
+
+static void do_version_layers_to_collections(Main *bmain, Scene *scene)
+{
+ /* Since we don't have access to FileData we check the (always valid) first
+ * render layer instead. */
+ if (!scene->master_collection) {
+ scene->master_collection = BKE_collection_master_add();
+ }
+
+ if (scene->view_layers.first) {
+ return;
+ }
+
+ /* Create collections from layers. */
+ Collection *collection_master = BKE_collection_master(scene);
+ Collection *collections[20] = {NULL};
+
+ for (int layer = 0; layer < 20; layer++) {
+ for (Base *base = scene->base.first; base; base = base->next) {
+ if (base->lay & (1 << layer)) {
+ /* Create collections when needed only. */
+ if (collections[layer] == NULL) {
+ char name[MAX_NAME];
+
+ BLI_snprintf(name,
+ sizeof(collection_master->id.name),
+ DATA_("Collection %d"),
+ layer + 1);
+
+ Collection *collection = BKE_collection_add(bmain, collection_master, name);
+ collection->id.lib = scene->id.lib;
+ collections[layer] = collection;
+
+ if (!(scene->lay & (1 << layer))) {
+ collection->flag |= COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER;
+ }
+ }
+
+ /* Note usually this would do slow collection syncing for view layers,
+ * but since no view layers exists yet at this point it's fast. */
+ BKE_collection_object_add(
+ bmain,
+ collections[layer], base->object);
+ }
+
+ if (base->flag & SELECT) {
+ base->object->flag |= SELECT;
+ }
+ else {
+ base->object->flag &= ~SELECT;
+ }
+ }
+ }
+
+ /* Handle legacy render layers. */
+ bool have_override = false;
+ const bool need_default_renderlayer = scene->r.layers.first == NULL;
+
+ for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
+ ViewLayer *view_layer = BKE_view_layer_add(scene, srl->name);
+
+ if (srl->samples != 0) {
+ have_override = true;
+
+ /* It is up to the external engine to handle
+ * its own doversion in this case. */
+ BKE_override_view_layer_int_add(
+ view_layer,
+ ID_SCE,
+ "samples",
+ srl->samples);
+ }
+
+ if (srl->mat_override) {
+ have_override = true;
+
+ BKE_override_view_layer_datablock_add(
+ view_layer,
+ ID_MA,
+ "self",
+ (ID *)srl->mat_override);
+ }
+
+ if (srl->layflag & SCE_LAY_DISABLE) {
+ view_layer->flag &= ~VIEW_LAYER_RENDER;
+ }
+
+ if ((srl->layflag & SCE_LAY_FRS) == 0) {
+ view_layer->flag &= ~VIEW_LAYER_FREESTYLE;
+ }
+
+ /* XXX If we are to keep layflag it should be merged with flag (dfelinto). */
+ view_layer->layflag = srl->layflag;
+ /* XXX Not sure if we should keep the passes (dfelinto). */
+ view_layer->passflag = srl->passflag;
+ view_layer->pass_xor = srl->pass_xor;
+ view_layer->pass_alpha_threshold = srl->pass_alpha_threshold;
+
+ BKE_freestyle_config_free(&view_layer->freestyle_config, true);
+ view_layer->freestyle_config = srl->freestyleConfig;
+ view_layer->id_properties = srl->prop;
+
+ /* Set exclusion and overrides. */
+ for (int layer = 0; layer < 20; layer++) {
+ Collection *collection = collections[layer];
+ if (collection) {
+ LayerCollection *lc = BKE_layer_collection_first_from_scene_collection(view_layer, collection);
+
+ if (srl->lay_exclude & (1 << layer)) {
+ /* Disable excluded layer. */
+ have_override = true;
+ lc->flag |= LAYER_COLLECTION_EXCLUDE;
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ nlc->flag |= LAYER_COLLECTION_EXCLUDE;
+ }
+ }
+ else {
+ if (srl->lay_zmask & (1 << layer)) {
+ have_override = true;
+ lc->flag |= LAYER_COLLECTION_HOLDOUT;
+ }
+
+ if ((srl->lay & (1 << layer)) == 0) {
+ have_override = true;
+ lc->flag |= LAYER_COLLECTION_INDIRECT_ONLY;
+ }
+ }
+ }
+ }
+
+ /* for convenience set the same active object in all the layers */
+ if (scene->basact) {
+ view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object);
+ }
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) {
+ base->flag |= BASE_SELECTED;
+ }
+ }
+ }
+
+ BLI_freelistN(&scene->r.layers);
+
+ /* If render layers included overrides, or there are no render layers,
+ * we also create a vanilla viewport layer. */
+ if (have_override || need_default_renderlayer) {
+ ViewLayer *view_layer = BKE_view_layer_add(scene, "Viewport");
+
+ /* Make it first in the list. */
+ BLI_remlink(&scene->view_layers, view_layer);
+ BLI_addhead(&scene->view_layers, view_layer);
+
+ /* If we ported all the original render layers, we don't need to make the viewport layer renderable. */
+ if (!BLI_listbase_is_single(&scene->view_layers)) {
+ view_layer->flag &= ~VIEW_LAYER_RENDER;
+ }
+
+ /* convert active base */
+ if (scene->basact) {
+ view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object);
+ }
+
+ /* convert selected bases */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) {
+ base->flag |= BASE_SELECTED;
+ }
+
+ /* keep lay around for forward compatibility (open those files in 2.79) */
+ base->lay = base->object->lay;
+ }
+ }
+
+ /* remove bases once and for all */
+ for (Base *base = scene->base.first; base; base = base->next) {
+ id_us_min(&base->object->id);
+ }
+
+ BLI_freelistN(&scene->base);
+ scene->basact = NULL;
+}
+
+static void do_version_collection_propagate_lib_to_children(Collection *collection)
+{
+ if (collection->id.lib != NULL) {
+ for (CollectionChild *collection_child = collection->children.first;
+ collection_child != NULL;
+ collection_child = collection_child->next)
+ {
+ if (collection_child->collection->id.lib == NULL) {
+ collection_child->collection->id.lib = collection->id.lib;
+ }
+ do_version_collection_propagate_lib_to_children(collection_child->collection);
+ }
+ }
+}
+
+void do_versions_after_linking_280(Main *bmain)
+{
+ bool use_collection_compat_28 = true;
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
+ use_collection_compat_28 = false;
+
+ /* Convert group layer visibility flags to hidden nested collection. */
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ /* Add fake user for all existing groups. */
+ id_fake_user_set(&collection->id);
+
+ if (collection->flag & (COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER)) {
+ continue;
+ }
+
+ Collection *hidden_collection_array[20] = {NULL};
+ for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
+ cob_next = cob->next;
+ Object *ob = cob->ob;
+
+ if (!(ob->lay & collection->layer)) {
+ /* Find or create hidden collection matching object's first layer. */
+ Collection **collection_hidden = NULL;
+ int coll_idx = 0;
+ for (; coll_idx < 20; coll_idx++) {
+ if (ob->lay & (1 << coll_idx)) {
+ collection_hidden = &hidden_collection_array[coll_idx];
+ break;
+ }
+ }
+ BLI_assert(collection_hidden != NULL);
+
+ if (*collection_hidden == NULL) {
+ char name[MAX_ID_NAME];
+ BLI_snprintf(name, sizeof(name), DATA_("Hidden %d"), coll_idx + 1);
+ *collection_hidden = BKE_collection_add(bmain, collection, name);
+ (*collection_hidden)->flag |= COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER;
+ }
+
+ BKE_collection_object_add(bmain, *collection_hidden, ob);
+ BKE_collection_object_remove(bmain, collection, ob, true);
+ }
+ }
+ }
+
+ /* We need to assign lib pointer to generated hidden collections *after* all have been created, otherwise we'll
+ * end up with several datablocks sharing same name/library, which is FORBIDDEN!
+ * Note: we need this to be recursive, since a child collection may be sorted before its parent in bmain... */
+ for (Collection *collection = bmain->collection.first; collection != NULL; collection = collection->id.next) {
+ do_version_collection_propagate_lib_to_children(collection);
+ }
+
+ /* Convert layers to collections. */
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ do_version_layers_to_collections(bmain, scene);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ /* same render-layer as do_version_workspaces_after_lib_link will activate,
+ * so same layer as BKE_view_layer_default_view would return */
+ ViewLayer *layer = screen->scene->view_layers.first;
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *space = sa->spacedata.first; space; space = space->next) {
+ if (space->spacetype == SPACE_OUTLINER) {
+ SpaceOops *soutliner = (SpaceOops *)space;
+
+ soutliner->outlinevis = SO_VIEW_LAYER;
+
+ if (BLI_listbase_count_at_most(&layer->layer_collections, 2) == 1) {
+ if (soutliner->treestore == NULL) {
+ soutliner->treestore = BLI_mempool_create(
+ sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
+ }
+
+ /* Create a tree store element for the collection. This is normally
+ * done in check_persistent (outliner_tree.c), but we need to access
+ * it here :/ (expand element if it's the only one) */
+ TreeStoreElem *tselem = BLI_mempool_calloc(soutliner->treestore);
+ tselem->type = TSE_LAYER_COLLECTION;
+ tselem->id = layer->layer_collections.first;
+ tselem->nr = tselem->used = 0;
+ tselem->flag &= ~TSE_CLOSED;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* New workspace design */
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) {
+ do_version_workspaces_after_lib_link(bmain);
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) {
+ /* Cleanup any remaining SceneRenderLayer data for files that were created
+ * with Blender 2.8 before the SceneRenderLayer > RenderLayer refactor. */
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
+ if (srl->prop) {
+ IDP_FreeProperty(srl->prop);
+ MEM_freeN(srl->prop);
+ }
+ BKE_freestyle_config_free(&srl->freestyleConfig, true);
+ }
+ BLI_freelistN(&scene->r.layers);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
+ /* Due to several changes to particle RNA and draw code particles from older files may no longer
+ * be visible. Here we correct this by setting a default draw size for those files. */
+ for (Object *object = bmain->object.first; object; object = object->id.next) {
+ for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) {
+ if (psys->part->draw_size == 0.0f) {
+ psys->part->draw_size = 0.1f;
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 4)) {
+ for (Object *object = bmain->object.first; object; object = object->id.next) {
+ if (object->particlesystem.first) {
+ object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
+ for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) {
+ if (psys->part->draw & PART_DRAW_EMITTER) {
+ object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER;
+ break;
+ }
+ }
+ }
+ else if (object->transflag & OB_DUPLI) {
+ object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
+ }
+ else {
+ object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
+ }
+ }
+
+ /* Cleanup deprecated flag from particlesettings data-blocks. */
+ for (ParticleSettings *part = bmain->particle.first; part; part = part->id.next) {
+ part->draw &= ~PART_DRAW_EMITTER;
+ }
+ }
+
+ /* SpaceTime & SpaceLogic removal/replacing */
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 9)) {
+ const wmWindowManager *wm = bmain->wm.first;
+ const Scene *scene = bmain->scene.first;
+
+ if (wm != NULL) {
+ /* Action editors need a scene for creation. First, update active
+ * screens using the active scene of the window they're displayed in.
+ * Next, update remaining screens using first scene in main listbase. */
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) {
+ do_version_area_change_space_to_space_action(area, win->scene);
+
+ /* Don't forget to unset! */
+ area->butspacetype = SPACE_EMPTY;
+ }
+ }
+ }
+ }
+ if (scene != NULL) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) {
+ /* Areas that were already handled won't be handled again */
+ do_version_area_change_space_to_space_action(area, scene);
+
+ /* Don't forget to unset! */
+ area->butspacetype = SPACE_EMPTY;
+ }
+ }
+ }
+ }
+ }
+
+#ifdef USE_COLLECTION_COMPAT_28
+ if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 14)) {
+ for (Collection *group = bmain->collection.first; group; group = group->id.next) {
+ do_version_group_collection_to_collection(bmain, group);
+ }
+
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ do_version_scene_collection_to_collection(bmain, scene);
+ }
+ }
+#endif
+
+ /* Update Curve object Shape Key data layout to include the Radius property */
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 23)) {
+ for (Curve *cu = bmain->curve.first; cu; cu = cu->id.next) {
+ if (!cu->key || cu->key->elemsize != sizeof(float[4]))
+ continue;
+
+ cu->key->elemstr[0] = 3; /*KEYELEM_ELEM_SIZE_CURVE*/
+ cu->key->elemsize = sizeof(float[3]);
+
+ int new_count = BKE_keyblock_curve_element_count(&cu->nurb);
+
+ for (KeyBlock *block = cu->key->block.first; block; block = block->next) {
+ int old_count = block->totelem;
+ void *old_data = block->data;
+
+ if (!old_data || old_count <= 0)
+ continue;
+
+ block->totelem = new_count;
+ block->data = MEM_callocN(sizeof(float[3]) * new_count, __func__);
+
+ float *oldptr = old_data;
+ float (*newptr)[3] = block->data;
+
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ BezTriple *bezt = nu->bezt;
+
+ for (int a = 0; a < nu->pntsu; a++, bezt++) {
+ if ((old_count -= 3) < 0) {
+ memcpy(newptr, bezt->vec, sizeof(float[3][3]));
+ newptr[3][0] = bezt->alfa;
+ }
+ else {
+ memcpy(newptr, oldptr, sizeof(float[3][4]));
+ }
+
+ newptr[3][1] = bezt->radius;
+
+ oldptr += 3 * 4;
+ newptr += 4; /*KEYELEM_ELEM_LEN_BEZTRIPLE*/
+ }
+ }
+ else if (nu->bp) {
+ BPoint *bp = nu->bp;
+
+ for (int a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) {
+ if (--old_count < 0) {
+ copy_v3_v3(newptr[0], bp->vec);
+ newptr[1][0] = bp->alfa;
+ }
+ else {
+ memcpy(newptr, oldptr, sizeof(float[4]));
+ }
+
+ newptr[1][1] = bp->radius;
+
+ oldptr += 4;
+ newptr += 2; /*KEYELEM_ELEM_LEN_BPOINT*/
+ }
+ }
+ }
+
+ MEM_freeN(old_data);
+ }
+ }
+ }
+
+ /* Move B-Bone custom handle settings from bPoseChannel to Bone. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 25)) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ bArmature *arm = ob->data;
+
+ /* If it is an armature from the same file. */
+ if (ob->pose && arm && arm->id.lib == ob->id.lib) {
+ bool rebuild = false;
+
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* If the 2.7 flag is enabled, processing is needed. */
+ if (pchan->bone && (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES)) {
+ /* If the settings in the Bone are not set, copy. */
+ if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO &&
+ pchan->bone->bbone_next_type == BBONE_HANDLE_AUTO &&
+ pchan->bone->bbone_prev == NULL && pchan->bone->bbone_next == NULL)
+ {
+ pchan->bone->bbone_prev_type = (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL) ? BBONE_HANDLE_RELATIVE : BBONE_HANDLE_ABSOLUTE;
+ pchan->bone->bbone_next_type = (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL) ? BBONE_HANDLE_RELATIVE : BBONE_HANDLE_ABSOLUTE;
+
+ if (pchan->bbone_prev) {
+ pchan->bone->bbone_prev = pchan->bbone_prev->bone;
+ }
+ if (pchan->bbone_next) {
+ pchan->bone->bbone_next = pchan->bbone_next->bone;
+ }
+ }
+
+ rebuild = true;
+ pchan->bboneflag = 0;
+ }
+ }
+
+ /* Tag pose rebuild for all objects that use this armature. */
+ if (rebuild) {
+ for (Object *ob2 = bmain->object.first; ob2; ob2 = ob2->id.next) {
+ if (ob2->pose && ob2->data == arm) {
+ ob2->pose->flag |= POSE_RECALC;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 30)) {
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if (brush->gpencil_settings != NULL) {
+ brush->gpencil_tool = brush->gpencil_settings->brush_type;
+ }
+ }
+ BKE_paint_toolslots_init_from_main(bmain);
+ }
+}
+
+/* NOTE: this version patch is intended for versions < 2.52.2, but was initially introduced in 2.27 already.
+ * But in 2.79 another case generating non-unique names was discovered (see T55668, involving Meta strips)... */
+static void do_versions_seq_unique_name_all_strips(Scene *sce, ListBase *seqbasep)
+{
+ for (Sequence *seq = seqbasep->first; seq != NULL; seq = seq->next) {
+ BKE_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq);
+ if (seq->seqbase.first != NULL) {
+ do_versions_seq_unique_name_all_strips(sce, &seq->seqbase);
+ }
+ }
+}
+
+void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
+{
+ bool use_collection_compat_28 = true;
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
+ use_collection_compat_28 = false;
+
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->r.gauss = 1.5f;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "bleedexp")) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
+ la->bleedexp = 2.5f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) {
+ for (Camera *ca = bmain->camera.first; ca; ca = ca->id.next) {
+ ca->gpu_dof.ratio = 1.0f;
+ }
+ }
+
+ /* MTexPoly now removed. */
+ if (DNA_struct_find(fd->filesdna, "MTexPoly")) {
+ const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */
+ for (Mesh *me = bmain->mesh.first; me; me = me->id.next) {
+ /* If we have UV's, so this file will have MTexPoly layers too! */
+ if (me->mloopuv != NULL) {
+ CustomData_update_typemap(&me->pdata);
+ CustomData_free_layers(&me->pdata, cd_mtexpoly, me->totpoly);
+ BKE_mesh_update_customdata_pointers(me, false);
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "cascade_max_dist")) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
+ la->cascade_max_dist = 1000.0f;
+ la->cascade_count = 4;
+ la->cascade_exponent = 0.8f;
+ la->cascade_fade = 0.1f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "contact_dist")) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
+ la->contact_dist = 0.2f;
+ la->contact_bias = 0.03f;
+ la->contact_spread = 0.2f;
+ la->contact_thickness = 0.2f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "vis_bias")) {
+ for (LightProbe *probe = bmain->lightprobe.first; probe; probe = probe->id.next) {
+ probe->vis_bias = 1.0f;
+ probe->vis_blur = 0.2f;
+ }
+ }
+
+ typedef enum eNTreeDoVersionErrors {
+ NTREE_DOVERSION_NO_ERROR = 0,
+ NTREE_DOVERSION_NEED_OUTPUT = (1 << 0),
+ NTREE_DOVERSION_TRANSPARENCY_EMISSION = (1 << 1),
+ } eNTreeDoVersionErrors;
+
+ /* Eevee shader nodes renamed because of the output node system.
+ * Note that a new output node is not being added here, because it would be overkill
+ * to handle this case in lib_verify_nodetree.
+ *
+ * Also, metallic node is now unified into the principled node. */
+ eNTreeDoVersionErrors error = NTREE_DOVERSION_NO_ERROR;
+
+ FOREACH_NODETREE_BEGIN(bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ &&
+ STREQ(node->idname, "ShaderNodeOutputMetallic"))
+ {
+ BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname));
+ error |= NTREE_DOVERSION_NEED_OUTPUT;
+ }
+
+ else if (node->type == SH_NODE_EEVEE_SPECULAR && STREQ(node->idname, "ShaderNodeOutputSpecular")) {
+ BLI_strncpy(node->idname, "ShaderNodeEeveeSpecular", sizeof(node->idname));
+ error |= NTREE_DOVERSION_NEED_OUTPUT;
+ }
+
+ else if (node->type == 196 /* SH_NODE_OUTPUT_EEVEE_MATERIAL */ &&
+ STREQ(node->idname, "ShaderNodeOutputEeveeMaterial"))
+ {
+ node->type = SH_NODE_OUTPUT_MATERIAL;
+ BLI_strncpy(node->idname, "ShaderNodeOutputMaterial", sizeof(node->idname));
+ }
+
+ else if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ &&
+ STREQ(node->idname, "ShaderNodeEeveeMetallic"))
+ {
+ node->type = SH_NODE_BSDF_PRINCIPLED;
+ BLI_strncpy(node->idname, "ShaderNodeBsdfPrincipled", sizeof(node->idname));
+ node->custom1 = SHD_GLOSSY_MULTI_GGX;
+ error |= NTREE_DOVERSION_TRANSPARENCY_EMISSION;
+ }
+ }
+ }
+ } FOREACH_NODETREE_END;
+
+ if (error & NTREE_DOVERSION_NEED_OUTPUT) {
+ BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
+ printf("You need to connect Principled and Eevee Specular shader nodes to new material output nodes.\n");
+ }
+
+ if (error & NTREE_DOVERSION_TRANSPARENCY_EMISSION) {
+ BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
+ printf("You need to combine transparency and emission shaders to the converted Principled shader nodes.\n");
+ }
+
+#ifdef USE_COLLECTION_COMPAT_28
+ if (use_collection_compat_28 &&
+ (DNA_struct_elem_find(fd->filesdna, "ViewLayer", "FreestyleConfig", "freestyle_config") == false) &&
+ DNA_struct_elem_find(fd->filesdna, "Scene", "ListBase", "view_layers"))
+ {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ view_layer->flag |= VIEW_LAYER_FREESTYLE;
+ view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */
+ view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
+ view_layer->pass_alpha_threshold = 0.5f;
+ BKE_freestyle_config_init(&view_layer->freestyle_config);
+ }
+ }
+ }
+#endif
+
+ {
+ /* Grease pencil sculpt and paint cursors */
+ if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "weighttype")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* sculpt brushes */
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ if (gset) {
+ gset->weighttype = GP_SCULPT_TYPE_WEIGHT;
+ }
+ }
+ }
+
+ {
+ float curcolor_add[3], curcolor_sub[3];
+ ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
+ ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
+ GP_Sculpt_Data *gp_brush;
+
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ /* sculpt brushes */
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ for (int i = 0; i < GP_SCULPT_TYPE_MAX; ++i) {
+ gp_brush = &gset->brush[i];
+ gp_brush->flag |= GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+ }
+ }
+ }
+
+ /* Init grease pencil edit line color */
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "float", "line_color[4]")) {
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
+ }
+ }
+
+ /* Init grease pencil pixel size factor */
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "int", "pixfactor")) {
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ }
+ }
+
+ /* Grease pencil multiframe falloff curve */
+ if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "CurveMapping", "cur_falloff")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* sculpt brushes */
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ if ((gset) && (gset->cur_falloff == NULL)) {
+ gset->cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(gset->cur_falloff);
+ curvemap_reset(gset->cur_falloff->cm,
+ &gset->cur_falloff->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+ }
+ }
+ }
+ }
+ }
+
+#ifdef USE_COLLECTION_COMPAT_28
+ if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ do_version_view_layer_visibility(view_layer);
+ }
+ }
+
+ for (Collection *group = bmain->collection.first; group; group = group->id.next) {
+ if (group->view_layer != NULL) {
+ do_version_view_layer_visibility(group->view_layer);
+ }
+ }
+ }
+#endif
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
+ /* init grease pencil grids and paper */
+ if (!DNA_struct_elem_find(fd->filesdna, "gp_paper_opacity", "float", "gpencil_paper_color[3]")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_paper_opacity = 0.5f;
+ v3d->overlay.gpencil_grid_opacity = 0.9f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) {
+ if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) {
+ bScreen *sc;
+ ScrArea *sa;
+ SpaceLink *sl;
+
+ /* Update files using invalid (outdated) outlinevis Outliner values. */
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOops *so = (SpaceOops *)sl;
+
+ if (!ELEM(so->outlinevis,
+ SO_SCENES,
+ SO_LIBRARIES,
+ SO_SEQUENCE,
+ SO_DATA_API,
+ SO_ID_ORPHANS))
+ {
+ so->outlinevis = SO_VIEW_LAYER;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) {
+ for (LightProbe *probe = bmain->lightprobe.first; probe; probe = probe->id.next) {
+ probe->intensity = 1.0f;
+ }
+ }
+
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ bConstraint *con, *con_next;
+ con = ob->constraints.first;
+ while (con) {
+ con_next = con->next;
+ if (con->type == 17) { /* CONSTRAINT_TYPE_RIGIDBODYJOINT */
+ BLI_remlink(&ob->constraints, con);
+ BKE_constraint_free_data(con);
+ MEM_freeN(con);
+ }
+ con = con_next;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Scene", "int", "orientation_index_custom")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->orientation_index_custom = -1;
+ }
+ }
+
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.light = V3D_LIGHTING_STUDIO;
+ v3d->shading.flag |= V3D_SHADING_OBJECT_OUTLINE;
+
+ /* Assume (demo) files written with 2.8 want to show
+ * Eevee renders in the viewport. */
+ if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
+ v3d->drawtype = OB_MATERIAL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 7)) {
+ /* Render engine storage moved elsewhere and back during 2.8
+ * development, we assume any files saved in 2.8 had Eevee set
+ * as scene render engine. */
+ if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine));
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 8)) {
+ /* Blender Internal removal */
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ if (STREQ(scene->r.engine, "BLENDER_RENDER") ||
+ STREQ(scene->r.engine, "BLENDER_GAME"))
+ {
+ BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine));
+ }
+
+ scene->r.bake_mode = 0;
+ }
+
+ for (Tex *tex = bmain->tex.first; tex; tex = tex->id.next) {
+ /* Removed envmap, pointdensity, voxeldata, ocean textures. */
+ if (ELEM(tex->type, 10, 14, 15, 16)) {
+ tex->type = 0;
+ }
+ }
+
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) {
+
+ /* Remove info editor, but only if at the top of the window. */
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ /* Calculate window width/height from screen vertices */
+ int win_width = 0, win_height = 0;
+ for (ScrVert *vert = screen->vertbase.first; vert; vert = vert->next) {
+ win_width = MAX2(win_width, vert->vec.x);
+ win_height = MAX2(win_height, vert->vec.y);
+ }
+
+ for (ScrArea *area = screen->areabase.first, *area_next; area; area = area_next) {
+ area_next = area->next;
+
+ if (area->spacetype == SPACE_INFO) {
+ if ((area->v2->vec.y == win_height) && (area->v1->vec.x == 0) && (area->v4->vec.x == win_width)) {
+ BKE_screen_area_free(area);
+
+ BLI_remlink(&screen->areabase, area);
+
+ BKE_screen_remove_double_scredges(screen);
+ BKE_screen_remove_unused_scredges(screen);
+ BKE_screen_remove_unused_scrverts(screen);
+
+ MEM_freeN(area);
+ }
+ }
+ /* AREA_TEMP_INFO is deprecated from now on, it should only be set for info areas
+ * which are deleted above, so don't need to unset it. Its slot/bit can be reused */
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) {
+ for (Lamp *lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) {
+ if (lamp->mode & (1 << 13)) { /* LA_SHAD_RAY */
+ lamp->mode |= LA_SHADOW;
+ lamp->mode &= ~(1 << 13);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 12)) {
+ /* Remove tool property regions. */
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_CLIP)) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+
+ for (ARegion *region = regionbase->first, *region_next; region; region = region_next) {
+ region_next = region->next;
+
+ if (region->regiontype == RGN_TYPE_TOOL_PROPS) {
+ BKE_area_region_free(NULL, region);
+ BLI_freelinkN(regionbase, region);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 13)) {
+ /* Initialize specular factor. */
+ if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "spec_fac")) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
+ la->spec_fac = 1.0f;
+ }
+ }
+
+ /* Initialize new view3D options. */
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.light = V3D_LIGHTING_STUDIO;
+ v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR;
+ copy_v3_fl(v3d->shading.single_color, 0.8f);
+ v3d->shading.shadow_intensity = 0.5;
+
+ v3d->overlay.backwire_opacity = 0.5f;
+ v3d->overlay.normals_length = 0.1f;
+ v3d->overlay.flag = 0;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_find(fd->filesdna, "View3DCursor")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ unit_qt(scene->cursor.rotation);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 14)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Scene", "SceneDisplay", "display")) {
+ /* Initialize new scene.SceneDisplay */
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ copy_v3_v3(scene->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3});
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "float", "shadow_shift")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->display.shadow_shift = 0.1;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Object", "ObjectDisplay", "display")) {
+ /* Initialize new object.ObjectDisplay */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ ob->display.flag = OB_SHOW_SHADOW;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "transform_pivot_point")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN;
+ }
+ }
+
+ if (!DNA_struct_find(fd->filesdna, "SceneEEVEE")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* First set the default for all the properties. */
+
+ scene->eevee.gi_diffuse_bounces = 3;
+ scene->eevee.gi_cubemap_resolution = 512;
+ scene->eevee.gi_visibility_resolution = 32;
+
+ scene->eevee.taa_samples = 16;
+ scene->eevee.taa_render_samples = 64;
+
+ scene->eevee.sss_samples = 7;
+ scene->eevee.sss_jitter_threshold = 0.3f;
+
+ scene->eevee.ssr_quality = 0.25f;
+ scene->eevee.ssr_max_roughness = 0.5f;
+ scene->eevee.ssr_thickness = 0.2f;
+ scene->eevee.ssr_border_fade = 0.075f;
+ scene->eevee.ssr_firefly_fac = 10.0f;
+
+ scene->eevee.volumetric_start = 0.1f;
+ scene->eevee.volumetric_end = 100.0f;
+ scene->eevee.volumetric_tile_size = 8;
+ scene->eevee.volumetric_samples = 64;
+ scene->eevee.volumetric_sample_distribution = 0.8f;
+ scene->eevee.volumetric_light_clamp = 0.0f;
+ scene->eevee.volumetric_shadow_samples = 16;
+
+ scene->eevee.gtao_distance = 0.2f;
+ scene->eevee.gtao_factor = 1.0f;
+ scene->eevee.gtao_quality = 0.25f;
+
+ scene->eevee.bokeh_max_size = 100.0f;
+ scene->eevee.bokeh_threshold = 1.0f;
+
+ copy_v3_fl(scene->eevee.bloom_color, 1.0f);
+ scene->eevee.bloom_threshold = 0.8f;
+ scene->eevee.bloom_knee = 0.5f;
+ scene->eevee.bloom_intensity = 0.8f;
+ scene->eevee.bloom_radius = 6.5f;
+ scene->eevee.bloom_clamp = 1.0f;
+
+ scene->eevee.motion_blur_samples = 8;
+ scene->eevee.motion_blur_shutter = 1.0f;
+
+ scene->eevee.shadow_method = SHADOW_ESM;
+ scene->eevee.shadow_cube_size = 512;
+ scene->eevee.shadow_cascade_size = 1024;
+
+ scene->eevee.flag =
+ SCE_EEVEE_VOLUMETRIC_LIGHTS |
+ SCE_EEVEE_GTAO_BENT_NORMALS |
+ SCE_EEVEE_GTAO_BOUNCE |
+ SCE_EEVEE_TAA_REPROJECTION |
+ SCE_EEVEE_SSR_HALF_RESOLUTION;
+
+
+ /* If the file is pre-2.80 move on. */
+ if (scene->layer_properties == NULL) {
+ continue;
+ }
+
+ /* Now we handle eventual properties that may be set in the file. */
+#define EEVEE_GET_BOOL(_props, _name, _flag) \
+ { \
+ IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \
+ if (_idprop != NULL) { \
+ const int _value = IDP_Int(_idprop); \
+ if (_value) { \
+ scene->eevee.flag |= _flag; \
+ } \
+ else { \
+ scene->eevee.flag &= ~_flag; \
+ } \
+ } \
+ }
+
+#define EEVEE_GET_INT(_props, _name) \
+ { \
+ IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \
+ if (_idprop != NULL) { \
+ scene->eevee._name = IDP_Int(_idprop); \
+ } \
+ }
+
+#define EEVEE_GET_FLOAT(_props, _name) \
+ { \
+ IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \
+ if (_idprop != NULL) { \
+ scene->eevee._name = IDP_Float(_idprop); \
+ } \
+ }
+
+#define EEVEE_GET_FLOAT_ARRAY(_props, _name, _length) \
+ { \
+ IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \
+ if (_idprop != NULL) { \
+ const float *_values = IDP_Array(_idprop); \
+ for (int _i = 0; _i < _length; _i++) { \
+ scene->eevee._name [_i] = _values[_i]; \
+ } \
+ } \
+ }
+
+ IDProperty *props = IDP_GetPropertyFromGroup(scene->layer_properties, RE_engine_id_BLENDER_EEVEE);
+ EEVEE_GET_BOOL(props, volumetric_enable, SCE_EEVEE_VOLUMETRIC_ENABLED);
+ EEVEE_GET_BOOL(props, volumetric_lights, SCE_EEVEE_VOLUMETRIC_LIGHTS);
+ EEVEE_GET_BOOL(props, volumetric_shadows, SCE_EEVEE_VOLUMETRIC_SHADOWS);
+ EEVEE_GET_BOOL(props, gtao_enable, SCE_EEVEE_GTAO_ENABLED);
+ EEVEE_GET_BOOL(props, gtao_use_bent_normals, SCE_EEVEE_GTAO_BENT_NORMALS);
+ EEVEE_GET_BOOL(props, gtao_bounce, SCE_EEVEE_GTAO_BOUNCE);
+ EEVEE_GET_BOOL(props, dof_enable, SCE_EEVEE_DOF_ENABLED);
+ EEVEE_GET_BOOL(props, bloom_enable, SCE_EEVEE_BLOOM_ENABLED);
+ EEVEE_GET_BOOL(props, motion_blur_enable, SCE_EEVEE_MOTION_BLUR_ENABLED);
+ EEVEE_GET_BOOL(props, shadow_high_bitdepth, SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
+ EEVEE_GET_BOOL(props, taa_reprojection, SCE_EEVEE_TAA_REPROJECTION);
+ EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED);
+ EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO);
+ EEVEE_GET_BOOL(props, ssr_enable, SCE_EEVEE_SSR_ENABLED);
+ EEVEE_GET_BOOL(props, ssr_refraction, SCE_EEVEE_SSR_REFRACTION);
+ EEVEE_GET_BOOL(props, ssr_halfres, SCE_EEVEE_SSR_HALF_RESOLUTION);
+
+ EEVEE_GET_INT(props, gi_diffuse_bounces);
+ EEVEE_GET_INT(props, gi_diffuse_bounces);
+ EEVEE_GET_INT(props, gi_cubemap_resolution);
+ EEVEE_GET_INT(props, gi_visibility_resolution);
+
+ EEVEE_GET_INT(props, taa_samples);
+ EEVEE_GET_INT(props, taa_render_samples);
+
+ EEVEE_GET_INT(props, sss_samples);
+ EEVEE_GET_FLOAT(props, sss_jitter_threshold);
+
+ EEVEE_GET_FLOAT(props, ssr_quality);
+ EEVEE_GET_FLOAT(props, ssr_max_roughness);
+ EEVEE_GET_FLOAT(props, ssr_thickness);
+ EEVEE_GET_FLOAT(props, ssr_border_fade);
+ EEVEE_GET_FLOAT(props, ssr_firefly_fac);
+
+ EEVEE_GET_FLOAT(props, volumetric_start);
+ EEVEE_GET_FLOAT(props, volumetric_end);
+ EEVEE_GET_INT(props, volumetric_tile_size);
+ EEVEE_GET_INT(props, volumetric_samples);
+ EEVEE_GET_FLOAT(props, volumetric_sample_distribution);
+ EEVEE_GET_FLOAT(props, volumetric_light_clamp);
+ EEVEE_GET_INT(props, volumetric_shadow_samples);
+
+ EEVEE_GET_FLOAT(props, gtao_distance);
+ EEVEE_GET_FLOAT(props, gtao_factor);
+ EEVEE_GET_FLOAT(props, gtao_quality);
+
+ EEVEE_GET_FLOAT(props, bokeh_max_size);
+ EEVEE_GET_FLOAT(props, bokeh_threshold);
+
+ EEVEE_GET_FLOAT_ARRAY(props, bloom_color, 3);
+ EEVEE_GET_FLOAT(props, bloom_threshold);
+ EEVEE_GET_FLOAT(props, bloom_knee);
+ EEVEE_GET_FLOAT(props, bloom_intensity);
+ EEVEE_GET_FLOAT(props, bloom_radius);
+ EEVEE_GET_FLOAT(props, bloom_clamp);
+
+ EEVEE_GET_INT(props, motion_blur_samples);
+ EEVEE_GET_FLOAT(props, motion_blur_shutter);
+
+ EEVEE_GET_INT(props, shadow_method);
+ EEVEE_GET_INT(props, shadow_cube_size);
+ EEVEE_GET_INT(props, shadow_cascade_size);
+
+ /* Cleanup. */
+ IDP_FreeProperty(scene->layer_properties);
+ MEM_freeN(scene->layer_properties);
+ scene->layer_properties = NULL;
+
+#undef EEVEE_GET_FLOAT_ARRAY
+#undef EEVEE_GET_FLOAT
+#undef EEVEE_GET_INT
+#undef EEVEE_GET_BOOL
+ }
+ }
+
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 15)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->display.matcap_ssao_distance = 0.2f;
+ scene->display.matcap_ssao_attenuation = 1.0f;
+ scene->display.matcap_ssao_samples = 16;
+ }
+
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOops *soops = (SpaceOops *)sl;
+ soops->filter_id_type = ID_GR;
+ soops->outlinevis = SO_VIEW_LAYER;
+ }
+ }
+ }
+ }
+
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ switch (scene->toolsettings->snap_mode) {
+ case 0: scene->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT; break;
+ case 1: scene->toolsettings->snap_mode = SCE_SNAP_MODE_VERTEX ; break;
+ case 2: scene->toolsettings->snap_mode = SCE_SNAP_MODE_EDGE ; break;
+ case 3: scene->toolsettings->snap_mode = SCE_SNAP_MODE_FACE ; break;
+ case 4: scene->toolsettings->snap_mode = SCE_SNAP_MODE_VOLUME ; break;
+ }
+ switch (scene->toolsettings->snap_node_mode) {
+ case 5: scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_X; break;
+ case 6: scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_Y; break;
+ case 7: scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y; break;
+ case 8: scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID ; break;
+ }
+ switch (scene->toolsettings->snap_uv_mode) {
+ case 0: scene->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT; break;
+ case 1: scene->toolsettings->snap_uv_mode = SCE_SNAP_MODE_VERTEX ; break;
+ }
+ }
+
+ ParticleSettings *part;
+ for (part = bmain->particle.first; part; part = part->id.next) {
+ part->shape_flag = PART_SHAPE_CLOSE_TIP;
+ part->shape = 0.0f;
+ part->rad_root = 1.0f;
+ part->rad_tip = 0.0f;
+ part->rad_scale = 0.01f;
+ }
+ }
+
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 18)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "roughness")) {
+ for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) {
+ if (mat->use_nodes) {
+ if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
+ mat->roughness = mat->gloss_mir;
+ }
+ else {
+ mat->roughness = 0.25f;
+ }
+ }
+ else {
+ mat->roughness = 1.0f - mat->gloss_mir;
+ }
+ mat->metallic = mat->ray_mirror;
+ }
+
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT;
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.xray_alpha = 0.5f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "matcap[256]")) {
+ StudioLight *default_matcap = BKE_studiolight_find_first(STUDIOLIGHT_TYPE_MATCAP);
+ /* when loading the internal file is loaded before the matcaps */
+ if (default_matcap) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ BLI_strncpy(v3d->shading.matcap, default_matcap->name, FILE_MAXFILE);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_threshold")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.wireframe_threshold = 0.5f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "cavity_valley_factor")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.cavity_valley_factor = 1.0f;
+ v3d->shading.cavity_ridge_factor = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "xray_alpha_bone")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.xray_alpha_bone = 0.5f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 19)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Image", "ListBase", "renderslot")) {
+ for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ for (int i = 0; i < 8; i++) {
+ RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image Render Slot Init");
+ BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", i + 1);
+ BLI_addtail(&ima->renderslots, slot);
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "SpaceAction", "char", "mode_prev")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)sl;
+ /* "Dopesheet" should be default here, unless it looks like the Action Editor was active instead */
+ if ((saction->mode_prev == 0) && (saction->action == NULL)) {
+ saction->mode_prev = SACTCONT_DOPESHEET;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->drawtype == OB_TEXTURE) {
+ v3d->drawtype = OB_SOLID;
+ v3d->shading.light = V3D_LIGHTING_STUDIO;
+ v3d->shading.color_type = V3D_SHADING_TEXTURE_COLOR;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 21)) {
+ for (Scene *sce = bmain->scene.first; sce != NULL; sce = sce->id.next) {
+ if (sce->ed != NULL && sce->ed->seqbase.first != NULL) {
+ do_versions_seq_unique_name_all_strips(sce, &sce->ed->seqbase);
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "texture_paint_mode_opacity")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ float alpha = v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE ? 0.0f : 0.8f;
+ float alpha_full = v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE ? 0.0f : 1.0f;
+ v3d->overlay.texture_paint_mode_opacity = alpha;
+ v3d->overlay.vertex_paint_mode_opacity = alpha;
+ v3d->overlay.weight_paint_mode_opacity = alpha_full;
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShadeing", "char", "background_type")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ copy_v3_fl(v3d->shading.background_color, 0.05f);
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_cubemap_draw_size")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->eevee.gi_irradiance_draw_size = 0.1f;
+ scene->eevee.gi_cubemap_draw_size = 0.3f;
+ }
+ }
+
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ if (scene->toolsettings->gizmo_flag == 0) {
+ scene->toolsettings->gizmo_flag = SCE_GIZMO_SHOW_TRANSLATE | SCE_GIZMO_SHOW_ROTATE | SCE_GIZMO_SHOW_SCALE;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyWorld", "RigidBodyWorld_Shared", "*shared")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ if (rbw == NULL) {
+ continue;
+ }
+
+ if (rbw->shared == NULL) {
+ rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared");
+ }
+
+ /* Move shared pointers from deprecated location to current location */
+ rbw->shared->pointcache = rbw->pointcache;
+ rbw->shared->ptcaches = rbw->ptcaches;
+
+ rbw->pointcache = NULL;
+ BLI_listbase_clear(&rbw->ptcaches);
+
+ if (rbw->shared->pointcache == NULL) {
+ rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches));
+ }
+
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SoftBody", "SoftBody_Shared", "*shared")) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ SoftBody *sb = ob->soft;
+ if (sb == NULL) {
+ continue;
+ }
+ if (sb->shared == NULL) {
+ sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared");
+ }
+
+ /* Move shared pointers from deprecated location to current location */
+ sb->shared->pointcache = sb->pointcache;
+ sb->shared->ptcaches = sb->ptcaches;
+
+ sb->pointcache = NULL;
+ BLI_listbase_clear(&sb->ptcaches);
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "short", "type")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->drawtype == OB_RENDER) {
+ v3d->drawtype = OB_SOLID;
+ }
+ v3d->shading.type = v3d->drawtype;
+ v3d->shading.prev_type = OB_SOLID;
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "View3DShading", "shading")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ BKE_screen_view3d_shading_init(&scene->display.shading);
+ }
+ }
+ /* initialize grease pencil view data */
+ if (!DNA_struct_elem_find(fd->filesdna, "SpaceView3D", "float", "vertex_opacity")) {
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->vertex_opacity = 1.0f;
+ v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 22)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "annotate_v3d_align")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ scene->toolsettings->annotate_thickness = 3;
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "short", "line_change")) {
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->line_change = gpl->thickness;
+ if ((gpl->thickness < 1) || (gpl->thickness > 10)) {
+ gpl->thickness = 3;
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_opacity")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_paper_opacity = 0.5f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_grid_opacity")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_grid_opacity = 0.5f;
+ }
+ }
+ }
+ }
+ }
+
+ /* default loc axis */
+ if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "lock_axis")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* lock axis */
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ if (gset) {
+ gset->lock_axis = GP_LOCKAXIS_Y;
+ }
+ }
+ }
+
+ /* Versioning code for Subsurf modifier. */
+ if (!DNA_struct_elem_find(fd->filesdna, "SubsurfModifier", "short", "uv_smooth")) {
+ for (Object *object = bmain->object.first; object != NULL; object = object->id.next) {
+ for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Subsurf) {
+ SubsurfModifierData *smd = (SubsurfModifierData *)md;
+ if (smd->flags & eSubsurfModifierFlag_SubsurfUv_DEPRECATED) {
+ smd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ }
+ else {
+ smd->uv_smooth = SUBSURF_UV_SMOOTH_NONE;
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SubsurfModifier", "short", "quality")) {
+ for (Object *object = bmain->object.first; object != NULL; object = object->id.next) {
+ for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Subsurf) {
+ SubsurfModifierData *smd = (SubsurfModifierData *)md;
+ smd->quality = min_ii(smd->renderLevels, 3);
+ }
+ }
+ }
+ }
+ /* Versioning code for Multires modifier. */
+ if (!DNA_struct_elem_find(fd->filesdna, "MultiresModifier", "short", "quality")) {
+ for (Object *object = bmain->object.first; object != NULL; object = object->id.next) {
+ for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Multires) {
+ MultiresModifierData *mmd = (MultiresModifierData *)md;
+ mmd->quality = 3;
+ if (mmd->flags & eMultiresModifierFlag_PlainUv_DEPRECATED) {
+ mmd->uv_smooth = SUBSURF_UV_SMOOTH_NONE;
+ }
+ else {
+ mmd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "short", "bending_model")) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+
+ clmd->sim_parms->bending_model = CLOTH_BENDING_LINEAR;
+ clmd->sim_parms->tension = clmd->sim_parms->structural;
+ clmd->sim_parms->compression = clmd->sim_parms->structural;
+ clmd->sim_parms->shear = clmd->sim_parms->structural;
+ clmd->sim_parms->max_tension = clmd->sim_parms->max_struct;
+ clmd->sim_parms->max_compression = clmd->sim_parms->max_struct;
+ clmd->sim_parms->max_shear = clmd->sim_parms->max_struct;
+ clmd->sim_parms->vgroup_shear = clmd->sim_parms->vgroup_struct;
+ clmd->sim_parms->tension_damp = clmd->sim_parms->Cdis;
+ clmd->sim_parms->compression_damp = clmd->sim_parms->Cdis;
+ clmd->sim_parms->shear_damp = clmd->sim_parms->Cdis;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "era_strength_f")) {
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if (brush->gpencil_settings != NULL) {
+ BrushGpencilSettings *gp = brush->gpencil_settings;
+ if (gp->brush_type == GPAINT_TOOL_ERASE) {
+ gp->era_strength_f = 100.0f;
+ gp->era_thickness_f = 10.0f;
+ }
+ }
+ }
+ }
+
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+
+ if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL)) {
+ clmd->sim_parms->vgroup_mass = 0;
+ }
+
+ if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING)) {
+ clmd->sim_parms->vgroup_struct = 0;
+ clmd->sim_parms->vgroup_shear = 0;
+ clmd->sim_parms->vgroup_bend = 0;
+ }
+
+ if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW)) {
+ clmd->sim_parms->shrink_min = 0.0f;
+ clmd->sim_parms->vgroup_shrink = 0;
+ }
+
+ if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED)) {
+ clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 24)) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.edit_flag |= V3D_OVERLAY_EDIT_FACES |
+ V3D_OVERLAY_EDIT_SEAMS |
+ V3D_OVERLAY_EDIT_SHARP |
+ V3D_OVERLAY_EDIT_FREESTYLE_EDGE |
+ V3D_OVERLAY_EDIT_FREESTYLE_FACE |
+ V3D_OVERLAY_EDIT_EDGES |
+ V3D_OVERLAY_EDIT_CREASES |
+ V3D_OVERLAY_EDIT_BWEIGHTS |
+ V3D_OVERLAY_EDIT_CU_HANDLES |
+ V3D_OVERLAY_EDIT_CU_NORMALS;
+ }
+ }
+ }
+ }
+ }
+
+ {
+ if (!DNA_struct_elem_find(fd->filesdna, "ShrinkwrapModifierData", "char", "shrinkMode")) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Shrinkwrap) {
+ ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
+ if (smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
+ smd->shrinkMode = MOD_SHRINKWRAP_ABOVE_SURFACE;
+ smd->shrinkOpts &= ~MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 24)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "PartDeflect", "float", "pdef_cfrict")) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->pd) {
+ ob->pd->pdef_cfrict = 5.0f;
+ }
+
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+
+ clmd->coll_parms->selfepsilon = 0.015f;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha_wire")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.xray_alpha_wire = 0.5f;
+ }
+ }
+ }
+ }
+
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.flag |= V3D_SHADING_XRAY_BONE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 25)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ UnitSettings *unit = &scene->unit;
+ if (unit->system != USER_UNIT_NONE) {
+ unit->length_unit = bUnit_GetBaseUnitOfType(scene->unit.system, B_UNIT_LENGTH);
+ unit->mass_unit = bUnit_GetBaseUnitOfType(scene->unit.system, B_UNIT_MASS);
+ }
+ unit->time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_NONE, B_UNIT_TIME);
+ }
+
+ /* gpencil grid settings */
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color
+ ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale
+ gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines
+ }
+ }
+
+ {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->flag2 & V3D_OCCLUDE_WIRE) {
+ v3d->overlay.edit_flag |= V3D_OVERLAY_EDIT_OCCLUDE_WIRE;
+ v3d->flag2 &= ~V3D_OCCLUDE_WIRE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 29)) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_BUTS) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ARegion *ar = MEM_callocN(sizeof(ARegion), "navigation bar for properties");
+ ARegion *ar_header = NULL;
+
+ for (ar_header = regionbase->first; ar_header; ar_header = ar_header->next) {
+ if (ar_header->regiontype == RGN_TYPE_HEADER) {
+ break;
+ }
+ }
+ BLI_assert(ar_header);
+
+ BLI_insertlinkafter(regionbase, ar_header, ar);
+
+ ar->regiontype = RGN_TYPE_NAV_BAR;
+ ar->alignment = RGN_ALIGN_LEFT;
+ }
+ }
+ }
+ }
+
+ /* grease pencil fade layer opacity */
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_fade_layer")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_fade_layer = 0.5f;
+ }
+ }
+ }
+ }
+ }
+
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ ob->empty_image_visibility_flag = (
+ OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE |
+ OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC |
+ OB_EMPTY_IMAGE_VISIBLE_BACKSIDE);
+ }
+
+
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 30)) {
+ /* grease pencil main material show switches */
+ for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) {
+ if (mat->gp_style) {
+ mat->gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ mat->gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 33)) {
+ /* Grease pencil reset sculpt brushes after struct rename */
+ if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "weighttype")) {
+ float curcolor_add[3], curcolor_sub[3];
+ ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
+ ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
+
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* sculpt brushes */
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ if (gset) {
+ for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
+ GP_Sculpt_Data *gp_brush = &gset->brush[i];
+ gp_brush->size = 30;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
+ }
+ }
+ }
+ }
+
+ /* Grease pencil target weight */
+ if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "float", "target_weight")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* sculpt brushes */
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ if (gset) {
+ for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
+ GP_Sculpt_Data *gp_brush = &gset->brush[i];
+ gp_brush->target_weight = 1.0f;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "overscan")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->eevee.overscan = 3.0f;
+ }
+ }
+
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
+ /* Removed Hemi lights. */
+ if (!ELEM(la->type, LA_LOCAL, LA_SUN, LA_SPOT, LA_AREA)) {
+ la->type = LA_SUN;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "light_threshold")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->eevee.light_threshold = 0.01f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_irradiance_smoothing")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->eevee.gi_irradiance_smoothing = 0.1f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_filter_quality")) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ scene->eevee.gi_filter_quality = 1.0f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "att_dist")) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
+ la->att_dist = la->clipend;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Brush", "char", "weightpaint_tool")) {
+ /* Magic defines from old files (2.7x) */
+
+#define PAINT_BLEND_MIX 0
+#define PAINT_BLEND_ADD 1
+#define PAINT_BLEND_SUB 2
+#define PAINT_BLEND_MUL 3
+#define PAINT_BLEND_BLUR 4
+#define PAINT_BLEND_LIGHTEN 5
+#define PAINT_BLEND_DARKEN 6
+#define PAINT_BLEND_AVERAGE 7
+#define PAINT_BLEND_SMEAR 8
+#define PAINT_BLEND_COLORDODGE 9
+#define PAINT_BLEND_DIFFERENCE 10
+#define PAINT_BLEND_SCREEN 11
+#define PAINT_BLEND_HARDLIGHT 12
+#define PAINT_BLEND_OVERLAY 13
+#define PAINT_BLEND_SOFTLIGHT 14
+#define PAINT_BLEND_EXCLUSION 15
+#define PAINT_BLEND_LUMINOSITY 16
+#define PAINT_BLEND_SATURATION 17
+#define PAINT_BLEND_HUE 18
+#define PAINT_BLEND_ALPHA_SUB 19
+#define PAINT_BLEND_ALPHA_ADD 20
+
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
+ const char tool_init = brush->vertexpaint_tool;
+ bool is_blend = false;
+
+ {
+ char tool = tool_init;
+ switch (tool_init) {
+ case PAINT_BLEND_MIX: tool = VPAINT_TOOL_DRAW; break;
+ case PAINT_BLEND_BLUR: tool = VPAINT_TOOL_BLUR; break;
+ case PAINT_BLEND_AVERAGE: tool = VPAINT_TOOL_AVERAGE; break;
+ case PAINT_BLEND_SMEAR: tool = VPAINT_TOOL_SMEAR; break;
+ default:
+ tool = VPAINT_TOOL_DRAW;
+ is_blend = true;
+ break;
+ }
+ brush->vertexpaint_tool = tool;
+ }
+
+ if (is_blend == false) {
+ brush->blend = IMB_BLEND_MIX;
+ }
+ else {
+ short blend = IMB_BLEND_MIX;
+ switch (tool_init) {
+ case PAINT_BLEND_ADD: blend = IMB_BLEND_ADD; break;
+ case PAINT_BLEND_SUB: blend = IMB_BLEND_SUB; break;
+ case PAINT_BLEND_MUL: blend = IMB_BLEND_MUL; break;
+ case PAINT_BLEND_LIGHTEN: blend = IMB_BLEND_LIGHTEN; break;
+ case PAINT_BLEND_DARKEN: blend = IMB_BLEND_DARKEN; break;
+ case PAINT_BLEND_COLORDODGE: blend = IMB_BLEND_COLORDODGE; break;
+ case PAINT_BLEND_DIFFERENCE: blend = IMB_BLEND_DIFFERENCE; break;
+ case PAINT_BLEND_SCREEN: blend = IMB_BLEND_SCREEN; break;
+ case PAINT_BLEND_HARDLIGHT: blend = IMB_BLEND_HARDLIGHT; break;
+ case PAINT_BLEND_OVERLAY: blend = IMB_BLEND_OVERLAY; break;
+ case PAINT_BLEND_SOFTLIGHT: blend = IMB_BLEND_SOFTLIGHT; break;
+ case PAINT_BLEND_EXCLUSION: blend = IMB_BLEND_EXCLUSION; break;
+ case PAINT_BLEND_LUMINOSITY: blend = IMB_BLEND_LUMINOSITY; break;
+ case PAINT_BLEND_SATURATION: blend = IMB_BLEND_SATURATION; break;
+ case PAINT_BLEND_HUE: blend = IMB_BLEND_HUE; break;
+ case PAINT_BLEND_ALPHA_SUB: blend = IMB_BLEND_ERASE_ALPHA; break;
+ case PAINT_BLEND_ALPHA_ADD: blend = IMB_BLEND_ADD_ALPHA; break;
+ }
+ brush->blend = blend;
+ }
+ }
+ /* For now these match, in the future new items may not. */
+ brush->weightpaint_tool = brush->vertexpaint_tool;
+ }
+
+#undef PAINT_BLEND_MIX
+#undef PAINT_BLEND_ADD
+#undef PAINT_BLEND_SUB
+#undef PAINT_BLEND_MUL
+#undef PAINT_BLEND_BLUR
+#undef PAINT_BLEND_LIGHTEN
+#undef PAINT_BLEND_DARKEN
+#undef PAINT_BLEND_AVERAGE
+#undef PAINT_BLEND_SMEAR
+#undef PAINT_BLEND_COLORDODGE
+#undef PAINT_BLEND_DIFFERENCE
+#undef PAINT_BLEND_SCREEN
+#undef PAINT_BLEND_HARDLIGHT
+#undef PAINT_BLEND_OVERLAY
+#undef PAINT_BLEND_SOFTLIGHT
+#undef PAINT_BLEND_EXCLUSION
+#undef PAINT_BLEND_LUMINOSITY
+#undef PAINT_BLEND_SATURATION
+#undef PAINT_BLEND_HUE
+#undef PAINT_BLEND_ALPHA_SUB
+#undef PAINT_BLEND_ALPHA_ADD
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 34)) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *slink = area->spacedata.first; slink; slink = slink->next) {
+ if (slink->spacetype == SPACE_USERPREF) {
+ ARegion *navigation_region = BKE_spacedata_find_region_type(slink, area, RGN_TYPE_NAV_BAR);
+
+ if (!navigation_region) {
+ ListBase *regionbase = (slink == area->spacedata.first) ?
+ &area->regionbase : &slink->regionbase;
+
+ navigation_region = MEM_callocN(sizeof(ARegion), "userpref navigation-region do_versions");
+
+ BLI_addhead(regionbase, navigation_region); /* order matters, addhead not addtail! */
+ navigation_region->regiontype = RGN_TYPE_NAV_BAR;
+ navigation_region->alignment = RGN_ALIGN_LEFT;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ {
+ /* Versioning code until next subversion bump goes here. */
+
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "curvature_ridge_factor")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.curvature_ridge_factor = 1.0f;
+ v3d->shading.curvature_valley_factor = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Rename OpenGL to Workbench. */
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ if (STREQ(scene->r.engine, "BLENDER_OPENGL")) {
+ STRNCPY(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH);
+ }
+ }
+
+ /* init Annotations onion skin */
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "int", "gstep")) {
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f);
+ ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f);
+ }
+ }
+ }
+
+ /* Move studio_light selection to lookdev_light. */
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "lookdev_light[256]")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ memcpy(v3d->shading.lookdev_light, v3d->shading.studio_light, sizeof(char) * 256);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 7ea39053bc7..b88618bf7db 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -25,53 +25,41 @@
* \ingroup blenloader
*/
+#include "MEM_guardedalloc.h"
+
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_string.h"
-#include "DNA_brush_types.h"
-#include "DNA_freestyle_types.h"
-#include "DNA_linestyle_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_material_types.h"
-#include "DNA_object_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
+#include "BKE_keyconfig.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_paint.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
-
/**
* Override values in in-memory startup.blend, avoids resaving for small changes.
*/
void BLO_update_defaults_userpref_blend(void)
{
- /* defaults from T37518 */
-
- U.uiflag |= USER_DEPTH_CURSOR;
- U.uiflag |= USER_QUIT_PROMPT;
- U.uiflag |= USER_CONTINUOUS_MOUSE;
-
- /* See T45301 */
- U.uiflag |= USER_LOCK_CURSOR_ADJUST;
-
- U.versions = 1;
- U.savetime = 2;
-
- /* default from T47064 */
- U.audiorate = 48000;
-
- /* Keep this a very small, non-zero number so zero-alpha doesn't mask out objects behind it.
- * but take care since some hardware has driver bugs here (T46962).
- * Further hardware workarounds should be made in gpu_extensions.c */
- U.glalphaclip = (1.0f / 255);
-
/* default so DPI is detected automatically */
U.dpi = 0;
U.ui_scale = 1.0f;
@@ -83,231 +71,234 @@ void BLO_update_defaults_userpref_blend(void)
#else
U.flag &= ~USER_SCRIPT_AUTOEXEC_DISABLE;
#endif
+
+ /* Transform tweak with single click and drag. */
+ U.flag |= USER_RELEASECONFIRM;
+
+ /* Ignore the theme saved in the blend file,
+ * instead use the theme from 'userdef_default_theme.c' */
+ {
+ bTheme *theme = U.themes.first;
+ memcpy(theme, &U_theme_default, sizeof(bTheme));
+ }
+
+ /* Leave temp directory empty, will then get appropriate value per OS. */
+ U.tempdir[0] = '\0';
+
+ /* Only enable tooltips translation by default, without actually enabling translation itself, for now. */
+ U.transopts = USER_TR_TOOLTIPS;
+ U.memcachelimit = 4096;
+
+ /* Default to left click select. */
+ BKE_keyconfig_pref_set_select_mouse(&U, 0, true);
}
/**
* Update defaults in startup.blend, without having to save and embed the file.
* This function can be emptied each time the startup.blend is updated. */
-void BLO_update_defaults_startup_blend(Main *bmain)
+void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
- for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
- scene->r.im_format.planes = R_IMF_PLANES_RGBA;
- scene->r.im_format.compress = 15;
-
- for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
- srl->freestyleConfig.sphere_radius = 0.1f;
- srl->pass_alpha_threshold = 0.5f;
- }
-
- if (scene->toolsettings) {
- ToolSettings *ts = scene->toolsettings;
-
- if (ts->sculpt) {
- Sculpt *sculpt = ts->sculpt;
- sculpt->paint.symmetry_flags |= PAINT_SYMM_X;
- sculpt->flags |= SCULPT_DYNTOPO_COLLAPSE;
- sculpt->detail_size = 12;
- }
+ /* For all startup.blend files. */
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
+ BKE_area_region_panels_free(&ar->panels);
- if (ts->vpaint) {
- VPaint *vp = ts->vpaint;
- vp->radial_symm[0] = vp->radial_symm[1] = vp->radial_symm[2] = 1;
+ /* some toolbars have been saved as initialized,
+ * we don't want them to have odd zoom-level or scrolling set, see: T47047 */
+ if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
+ ar->v2d.flag &= ~V2D_IS_INITIALISED;
+ }
}
- if (ts->wpaint) {
- VPaint *wp = ts->wpaint;
- wp->radial_symm[0] = wp->radial_symm[1] = wp->radial_symm[2] = 1;
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.weight_paint_mode_opacity = 1.0f;
+ /* grease pencil settings */
+ v3d->vertex_opacity = 1.0f;
+ v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
+ }
+ }
}
+ }
+ }
- if (ts->gp_sculpt.brush[0].size == 0) {
- GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
- GP_EditBrush_Data *brush;
-
- brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
- brush->size = 25;
- brush->strength = 0.3f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
-
- brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
- brush->size = 25;
- 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;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
- brush->size = 25;
- brush->strength = 0.3f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
- brush->size = 50;
- brush->strength = 0.3f; // XXX?
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
- brush->size = 50;
- brush->strength = 0.5f; // XXX?
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
- brush->size = 25;
- brush->strength = 0.5f;
- brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ if (app_template == NULL) {
+ /* Name all screens by their workspaces (avoids 'Default.###' names). */
+ {
+ /* Default only has one window. */
+ wmWindow *win = ((wmWindowManager *)bmain->wm.first)->windows.first;
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ WorkSpaceLayout *layout = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace);
+ bScreen *screen = layout->screen;
+ BLI_strncpy(screen->id.name + 2, workspace->id.name + 2, sizeof(screen->id.name) - 2);
}
+ }
- ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
- ts->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
- ts->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
- ts->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
-
- ParticleEditSettings *pset = &ts->particle;
- for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) {
- pset->brush[a].strength = 0.5f;
- pset->brush[a].count = 10;
+ {
+ /* 'UV Editing' should use UV mode. */
+ bScreen *screen = BLI_findstring(&bmain->screen, "UV Editing", offsetof(ID, name) + 2);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+ if (sima->mode == SI_MODE_VIEW) {
+ sima->mode = SI_MODE_UV;
+ }
+ }
+ }
}
- pset->brush[PE_BRUSH_CUT].strength = 1.0f;
}
-
- scene->gm.lodflag |= SCE_LOD_USE_HYST;
- scene->gm.scehysteresis = 10;
-
- scene->r.ffcodecdata.audio_mixrate = 48000;
}
- for (FreestyleLineStyle *linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
- linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE;
- linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
- linestyle->integration_type = LS_INTEGRATION_MEAN;
- linestyle->texstep = 1.0;
- linestyle->chain_count = 10;
- }
+ /* For 2D animation template. */
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ const char *name = workspace->id.name + 2;
- for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
- ScrArea *area;
- for (area = screen->areabase.first; area; area = area->next) {
- SpaceLink *space_link;
- ARegion *ar;
-
- for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
- if (space_link->spacetype == SPACE_CLIP) {
- SpaceClip *space_clip = (SpaceClip *)space_link;
- space_clip->flag &= ~SC_MANUAL_CALIBRATION;
- }
+ if (STREQ(name, "Drawing")) {
+ workspace->object_mode = OB_MODE_GPENCIL_PAINT;
}
-
- for (ar = area->regionbase.first; ar; ar = ar->next) {
- /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
- BLI_freelistN(&ar->panels);
-
- /* some toolbars have been saved as initialized,
- * we don't want them to have odd zoom-level or scrolling set, see: T47047 */
- if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
- ar->v2d.flag &= ~V2D_IS_INITIALISED;
- }
+ }
+ /* set object in drawing mode */
+ for (Object *object = bmain->object.first; object; object = object->id.next) {
+ if (object->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)object->data;
+ object->mode = OB_MODE_GPENCIL_PAINT;
+ gpd->flag |= GP_DATA_STROKE_PAINTMODE;
+ break;
}
}
- }
- for (Mesh *me = bmain->mesh.first; me; me = me->id.next) {
- me->smoothresh = DEG2RADF(180.0f);
- me->flag &= ~ME_TWOSIDED;
- }
-
- for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) {
- mat->line_col[0] = mat->line_col[1] = mat->line_col[2] = 0.0f;
- mat->line_col[3] = 1.0f;
+ /* Be sure curfalloff is initializated */
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ if (ts->gp_sculpt.cur_falloff == NULL) {
+ ts->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_falloff_curve = ts->gp_sculpt.cur_falloff;
+ curvemapping_initialize(gp_falloff_curve);
+ curvemap_reset(gp_falloff_curve->cm,
+ &gp_falloff_curve->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+ }
+ }
}
- {
- Object *ob;
+ /* For all builtin templates shipped with Blender. */
+ bool builtin_template = !app_template ||
+ STREQ(app_template, "2D_Animation") ||
+ STREQ(app_template, "Sculpting") ||
+ STREQ(app_template, "VFX") ||
+ STREQ(app_template, "Video_Editing");
+
+ if (builtin_template) {
+ /* Clear all tools to use default options instead, ignore the tool saved in the file. */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ while (!BLI_listbase_is_empty(&workspace->tools)) {
+ BKE_workspace_tool_remove(workspace, workspace->tools.first);
+ }
+ }
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, "Camera");
- if (ob) {
- ob->rot[1] = 0.0f;
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ /* Hide channels in timelines. */
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ SpaceAction *saction = (sa->spacetype == SPACE_ACTION) ? sa->spacedata.first : NULL;
+
+ if (saction && saction->mode == SACTCONT_TIMELINE) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_CHANNELS) {
+ ar->flag |= RGN_FLAG_HIDDEN;
+ }
+ }
+ }
+ }
}
- }
- {
- Brush *br;
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine));
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Fill");
- if (!br) {
- br = BKE_brush_add(bmain, "Fill", OB_MODE_TEXTURE_PAINT);
- id_us_min(&br->id); /* fake user only */
- br->imagepaint_tool = PAINT_TOOL_FILL;
- br->ob_mode = OB_MODE_TEXTURE_PAINT;
- }
+ scene->r.cfra = 1.0f;
+ scene->r.displaymode = R_OUTPUT_WINDOW;
- /* Vertex/Weight Paint */
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Average");
- if (!br) {
- br = BKE_brush_add(bmain, "Average", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT);
- id_us_min(&br->id); /* fake user only */
- br->vertexpaint_tool = PAINT_BLEND_AVERAGE;
- br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT;
- }
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Smear");
- if (!br) {
- br = BKE_brush_add(bmain, "Smear", OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT);
- id_us_min(&br->id); /* fake user only */
- br->vertexpaint_tool = PAINT_BLEND_SMEAR;
- br->ob_mode = OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT;
- }
+ /* AV Sync break physics sim caching, disable until that is fixed. */
+ if (!(app_template && STREQ(app_template, "Video_Editing"))) {
+ scene->audio.flag &= ~AUDIO_SYNC;
+ scene->flag &= ~SCE_FRAME_DROP;
+ }
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Mask");
- if (br) {
- br->imagepaint_tool = PAINT_TOOL_MASK;
- br->ob_mode |= OB_MODE_TEXTURE_PAINT;
- }
+ /* Don't enable compositing nodes. */
+ if (scene->nodetree) {
+ ntreeFreeTree(scene->nodetree);
+ MEM_freeN(scene->nodetree);
+ scene->nodetree = NULL;
+ scene->use_nodes = false;
+ }
- /* remove polish brush (flatten/contrast does the same) */
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Polish");
- if (br) {
- BKE_libblock_delete(bmain, br);
+ /* Rename render layers. */
+ BKE_view_layer_rename(bmain, scene, scene->view_layers.first, "View Layer");
}
- /* remove brush brush (huh?) from some modes (draw brushes do the same) */
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Brush");
- if (br) {
- BKE_libblock_delete(bmain, br);
+ /* Rename lamp objects. */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (STREQ(ob->id.name, "OBLamp")) {
+ STRNCPY(ob->id.name, "OBLight");
+ }
}
-
- /* remove draw brush from texpaint (draw brushes do the same) */
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Draw");
- if (br) {
- br->ob_mode &= ~OB_MODE_TEXTURE_PAINT;
+ for (Lamp *lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) {
+ if (STREQ(lamp->id.name, "LALamp")) {
+ STRNCPY(lamp->id.name, "LALight");
+ }
}
- /* rename twist brush to rotate brush to match rotate tool */
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Twist");
- if (br) {
- BKE_libblock_rename(bmain, &br->id, "Rotate");
+ for (Mesh *mesh = bmain->mesh.first; mesh; mesh = mesh->id.next) {
+ /* Match default for new meshes. */
+ mesh->smoothresh = DEG2RADF(30);
}
- /* use original normal for grab brush (otherwise flickers with normal weighting). */
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Grab");
+ /* Grease Pencil New Eraser Brush */
+ Brush *br;
+ /* Rename old Hard Eraser */
+ br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Eraser Hard");
if (br) {
- br->flag |= BRUSH_ORIGINAL_NORMAL;
+ strcpy(br->id.name, "BREraser Point");
}
-
- /* increase strength, better for smoothing method */
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Blur");
- if (br) {
- br->alpha = 1.0f;
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ /* create new hard brush (only create one, but need ToolSettings) */
+ br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Eraser Hard");
+ if (!br) {
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *old_brush = paint->brush;
+
+ br = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
+ br->size = 30.0f;
+ br->gpencil_settings->draw_strength = 1.0f;
+ br->gpencil_settings->flag = (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ br->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ br->gpencil_tool = GPAINT_TOOL_ERASE;
+ br->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+ br->gpencil_settings->era_strength_f = 100.0f;
+ br->gpencil_settings->era_thickness_f = 50.0f;
+
+ /* back to default brush */
+ BKE_paint_brush_set(paint, old_brush);
+ }
}
+ }
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Flatten/Contrast");
- if (br) {
- br->flag |= BRUSH_ACCUMULATE;
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT;
+ }
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 9708e24b351..3c8e69a5fba 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -45,11 +45,10 @@
#define DNA_DEPRECATED_ALLOW
#include "DNA_armature_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_effect_types.h"
-#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_lamp_types.h"
@@ -60,10 +59,8 @@
#include "DNA_node_types.h"
#include "DNA_object_fluidsim_types.h"
#include "DNA_object_types.h"
-#include "DNA_property_types.h"
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
-#include "DNA_sensor_types.h"
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
@@ -90,7 +87,6 @@
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "BKE_property.h" // for BKE_bproperty_object_get
#include "BKE_scene.h"
#include "BKE_sequencer.h"
@@ -128,38 +124,6 @@ static void vcol_to_fcol(Mesh *me)
me->mcol = (MCol *)mcolmain;
}
-static int map_223_keybd_code_to_224_keybd_code(int code)
-{
- switch (code) {
- case 312:
- return 311; /* F12KEY */
- case 159:
- return 161; /* PADSLASHKEY */
- case 161:
- return 150; /* PAD0 */
- case 154:
- return 151; /* PAD1 */
- case 150:
- return 152; /* PAD2 */
- case 155:
- return 153; /* PAD3 */
- case 151:
- return 154; /* PAD4 */
- case 156:
- return 155; /* PAD5 */
- case 152:
- return 156; /* PAD6 */
- case 157:
- return 157; /* PAD7 */
- case 153:
- return 158; /* PAD8 */
- case 158:
- return 159; /* PAD9 */
- default:
- return code;
- }
-}
-
static void do_version_bone_head_tail_237(Bone *bone)
{
Bone *child;
@@ -248,12 +212,6 @@ static void ntree_version_242(bNodeTree *ntree)
}
}
}
- else if (ntree->type == NTREE_SHADER) {
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->type == SH_NODE_GEOMETRY && node->storage == NULL)
- node->storage = MEM_callocN(sizeof(NodeGeometry), "NodeGeometry");
- }
-
}
static void ntree_version_245(FileData *fd, Library *lib, bNodeTree *ntree)
@@ -319,55 +277,6 @@ static void idproperties_fix_group_lengths(ListBase idlist)
}
}
-static void alphasort_version_246(FileData *fd, Library *lib, Mesh *me)
-{
- Material *ma;
- MFace *mf;
- MTFace *tf;
- int a, b, texalpha;
-
- /* verify we have a tface layer */
- for (b = 0; b < me->fdata.totlayer; b++)
- if (me->fdata.layers[b].type == CD_MTFACE)
- break;
-
- if (b == me->fdata.totlayer)
- return;
-
- /* if we do, set alpha sort if the game engine did it before */
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (mf->mat_nr < me->totcol) {
- ma = blo_do_versions_newlibadr(fd, lib, me->mat[mf->mat_nr]);
- texalpha = 0;
-
- /* we can't read from this if it comes from a library,
- * because direct_link might not have happened on it,
- * so ma->mtex is not pointing to valid memory yet */
- if (ma && ma->id.lib)
- ma = NULL;
-
- for (b = 0; ma && b < MAX_MTEX; b++)
- if (ma->mtex[b] && ma->mtex[b]->mapto & MAP_ALPHA)
- texalpha = 1;
- }
- else {
- ma = NULL;
- texalpha = 0;
- }
-
- for (b = 0; b < me->fdata.totlayer; b++) {
- if (me->fdata.layers[b].type == CD_MTFACE) {
- tf = ((MTFace *)me->fdata.layers[b].data) + a;
-
- tf->mode &= ~TF_ALPHASORT;
- if (ma && (ma->mode & MA_ZTRANSP))
- if (ELEM(tf->transp, TF_ALPHA, TF_ADD) || (texalpha && (tf->transp != TF_CLIP)))
- tf->mode |= TF_ALPHASORT;
- }
- }
- }
-}
-
static void customdata_version_242(Mesh *me)
{
CustomDataLayer *layer;
@@ -403,13 +312,6 @@ static void customdata_version_242(Mesh *me)
for (a = 0; a < me->totface; a++, mtf++, tf++, mcol += 4) {
memcpy(mcol, tf->col, sizeof(tf->col));
memcpy(mtf->uv, tf->uv, sizeof(tf->uv));
-
- mtf->flag = tf->flag;
- mtf->unwrap = tf->unwrap;
- mtf->mode = tf->mode;
- mtf->tile = tf->tile;
- mtf->tpage = tf->tpage;
- mtf->transp = tf->transp;
}
MEM_freeN(me->tface);
@@ -478,7 +380,6 @@ static void do_version_ntree_242_2(bNodeTree *ntree)
iuser->sfra = nia->sfra;
iuser->offset = nia->nr - 1;
iuser->cycl = nia->cyclic;
- iuser->fie_ima = 2;
iuser->ok = 1;
node->storage = iuser;
@@ -487,7 +388,6 @@ static void do_version_ntree_242_2(bNodeTree *ntree)
else {
ImageUser *iuser = node->storage = MEM_callocN(sizeof(ImageUser), "node image user");
iuser->sfra = 1;
- iuser->fie_ima = 2;
iuser->ok = 1;
}
}
@@ -617,15 +517,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile <= 102) {
- /* init halo's at 1.0 */
- Material *ma = bmain->mat.first;
- while (ma) {
- ma->add = 1.0;
- ma = ma->id.next;
- }
- }
-
if (bmain->versionfile <= 103) {
/* new variable in object: colbits */
Object *ob = bmain->object.first;
@@ -677,11 +568,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile <= 107) {
Object *ob;
- Scene *sce = bmain->scene.first;
- while (sce) {
- sce->r.mode |= R_GAMMA;
- sce = sce->id.next;
- }
ob = bmain->object.first;
while (ob) {
if (ob->dt == 0)
@@ -713,17 +599,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile <= 113) {
- Material *ma = bmain->mat.first;
- while (ma) {
- if (ma->flaresize == 0.0f)
- ma->flaresize = 1.0f;
- ma->subsize = 1.0f;
- ma->flareboost = 1.0f;
- ma = ma->id.next;
- }
- }
-
if (bmain->versionfile <= 134) {
Tex *tex = bmain->tex.first;
while (tex) {
@@ -888,148 +763,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile <= 191) {
- Object *ob = bmain->object.first;
- Material *ma = bmain->mat.first;
-
- /* let faces have default add factor of 0.0 */
- while (ma) {
- if (!(ma->mode & MA_HALO))
- ma->add = 0.0;
- ma = ma->id.next;
- }
-
- while (ob) {
- ob->mass = 1.0f;
- ob->damping = 0.1f;
- /*ob->quat[1] = 1.0f;*/ /* quats arnt used yet */
- ob = ob->id.next;
- }
- }
-
- if (bmain->versionfile <= 193) {
- Object *ob = bmain->object.first;
- while (ob) {
- ob->inertia = 1.0f;
- ob->rdamping = 0.1f;
- ob = ob->id.next;
- }
- }
-
- if (bmain->versionfile <= 196) {
- Mesh *me = bmain->mesh.first;
- int a, b;
- while (me) {
- if (me->tface) {
- TFace *tface = me->tface;
- for (a = 0; a < me->totface; a++, tface++) {
- for (b = 0; b < 4; b++) {
- tface->mode |= TF_DYNAMIC;
- tface->mode &= ~TF_INVISIBLE;
- }
- }
- }
- me = me->id.next;
- }
- }
-
- if (bmain->versionfile <= 200) {
- Object *ob = bmain->object.first;
- while (ob) {
- ob->scaflag = ob->gameflag & (OB_DO_FH | OB_ROT_FH | OB_ANISOTROPIC_FRICTION | OB_GHOST | OB_RIGID_BODY | OB_BOUNDS);
- /* 64 is do_fh */
- ob->gameflag &= ~(OB_ROT_FH | OB_ANISOTROPIC_FRICTION | OB_GHOST | OB_RIGID_BODY | OB_BOUNDS);
- ob = ob->id.next;
- }
- }
-
- if (bmain->versionfile <= 201) {
- /* add-object + end-object are joined to edit-object actuator */
- Object *ob = bmain->object.first;
- bProperty *prop;
- bActuator *act;
- bIpoActuator *ia;
- bEditObjectActuator *eoa;
- bAddObjectActuator *aoa;
- while (ob) {
- act = ob->actuators.first;
- while (act) {
- if (act->type == ACT_IPO) {
- ia = act->data;
- prop = BKE_bproperty_object_get(ob, ia->name);
- if (prop) {
- ia->type = ACT_IPO_FROM_PROP;
- }
- }
- else if (act->type == ACT_ADD_OBJECT) {
- aoa = act->data;
- eoa = MEM_callocN(sizeof(bEditObjectActuator), "edit ob act");
- eoa->type = ACT_EDOB_ADD_OBJECT;
- eoa->ob = aoa->ob;
- eoa->time = aoa->time;
- MEM_freeN(aoa);
- act->data = eoa;
- act->type = act->otype = ACT_EDIT_OBJECT;
- }
- else if (act->type == ACT_END_OBJECT) {
- eoa = MEM_callocN(sizeof(bEditObjectActuator), "edit ob act");
- eoa->type = ACT_EDOB_END_OBJECT;
- act->data = eoa;
- act->type = act->otype = ACT_EDIT_OBJECT;
- }
- act = act->next;
- }
- ob = ob->id.next;
- }
- }
-
- if (bmain->versionfile <= 202) {
- /* add-object and end-object are joined to edit-object
- * actuator */
- Object *ob = bmain->object.first;
- bActuator *act;
- bObjectActuator *oa;
- while (ob) {
- act = ob->actuators.first;
- while (act) {
- if (act->type == ACT_OBJECT) {
- oa = act->data;
- oa->flag &= ~(ACT_TORQUE_LOCAL | ACT_DROT_LOCAL); /* this actuator didn't do local/glob rot before */
- }
- act = act->next;
- }
- ob = ob->id.next;
- }
- }
-
if (bmain->versionfile <= 204) {
- /* patches for new physics */
- Object *ob = bmain->object.first;
- bActuator *act;
- bObjectActuator *oa;
bSound *sound;
- while (ob) {
-
- /* please check this for demo20 files like
- * original Egypt levels etc. converted
- * rotation factor of 50 is not workable */
- act = ob->actuators.first;
- while (act) {
- if (act->type == ACT_OBJECT) {
- oa = act->data;
-
- oa->forceloc[0] *= 25.0f;
- oa->forceloc[1] *= 25.0f;
- oa->forceloc[2] *= 25.0f;
-
- oa->forcerot[0] *= 10.0f;
- oa->forcerot[1] *= 10.0f;
- oa->forcerot[2] *= 10.0f;
- }
- act = act->next;
- }
- ob = ob->id.next;
- }
sound = bmain->sound.first;
while (sound) {
@@ -1040,120 +775,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile <= 205) {
- /* patches for new physics */
- Object *ob = bmain->object.first;
- bActuator *act;
- bSensor *sens;
- bEditObjectActuator *oa;
- bRaySensor *rs;
- bCollisionSensor *cs;
- while (ob) {
- /* Set anisotropic friction off for old objects,
- * values to 1.0. */
- ob->gameflag &= ~OB_ANISOTROPIC_FRICTION;
- ob->anisotropicFriction[0] = 1.0;
- ob->anisotropicFriction[1] = 1.0;
- ob->anisotropicFriction[2] = 1.0;
-
- act = ob->actuators.first;
- while (act) {
- if (act->type == ACT_EDIT_OBJECT) {
- /* Zero initial velocity for newly
- * added objects */
- oa = act->data;
- oa->linVelocity[0] = 0.0;
- oa->linVelocity[1] = 0.0;
- oa->linVelocity[2] = 0.0;
- oa->localflag = 0;
- }
- act = act->next;
- }
-
- sens = ob->sensors.first;
- while (sens) {
- /* Extra fields for radar sensors. */
- if (sens->type == SENS_RADAR) {
- bRadarSensor *s = sens->data;
- s->range = 10000.0;
- }
-
- /* Pulsing: defaults for new sensors. */
- if (sens->type != SENS_ALWAYS) {
- sens->pulse = 0;
- sens->freq = 0;
- }
- else {
- sens->pulse = 1;
- }
-
- /* Invert: off. */
- sens->invert = 0;
-
- /* Collision and ray: default = trigger
- * on property. The material field can
- * remain empty. */
- if (sens->type == SENS_COLLISION) {
- cs = (bCollisionSensor *)sens->data;
- cs->mode = 0;
- }
- if (sens->type == SENS_RAY) {
- rs = (bRaySensor *)sens->data;
- rs->mode = 0;
- }
- sens = sens->next;
- }
- ob = ob->id.next;
- }
- /* have to check the exact multiplier */
- }
-
- if (bmain->versionfile <= 211) {
- /* Render setting: per scene, the applicable gamma value
- * can be set. Default is 1.0, which means no
- * correction. */
- bActuator *act;
- bObjectActuator *oa;
- Object *ob;
-
- /* added alpha in obcolor */
- ob = bmain->object.first;
- while (ob) {
- ob->col[3] = 1.0;
- ob = ob->id.next;
- }
-
- /* added alpha in obcolor */
- ob = bmain->object.first;
- while (ob) {
- act = ob->actuators.first;
- while (act) {
- if (act->type == ACT_OBJECT) {
- /* multiply velocity with 50 in old files */
- oa = act->data;
- if (fabsf(oa->linearvelocity[0]) >= 0.01f)
- oa->linearvelocity[0] *= 50.0f;
- if (fabsf(oa->linearvelocity[1]) >= 0.01f)
- oa->linearvelocity[1] *= 50.0f;
- if (fabsf(oa->linearvelocity[2]) >= 0.01f)
- oa->linearvelocity[2] *= 50.0f;
- if (fabsf(oa->angularvelocity[0]) >= 0.01f)
- oa->angularvelocity[0] *= 50.0f;
- if (fabsf(oa->angularvelocity[1]) >= 0.01f)
- oa->angularvelocity[1] *= 50.0f;
- if (fabsf(oa->angularvelocity[2]) >= 0.01f)
- oa->angularvelocity[2] *= 50.0f;
- }
- act = act->next;
- }
- ob = ob->id.next;
- }
- }
-
if (bmain->versionfile <= 212) {
bSound *sound;
- bProperty *prop;
- Object *ob;
Mesh *me;
sound = bmain->sound.first;
@@ -1170,21 +793,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
sound = sound->id.next;
}
- ob = bmain->object.first;
-
- while (ob) {
- prop = ob->prop.first;
- while (prop) {
- if (prop->type == GPROP_TIME) {
- // convert old GPROP_TIME values from int to float
- *((float *)&prop->data) = (float)prop->data;
- }
-
- prop = prop->next;
- }
- ob = ob->id.next;
- }
-
/* me->subdiv changed to reflect the actual reparametization
* better, and smeshes were removed - if it was a smesh make
* it a subsurf, and reset the subdiv level because subsurf
@@ -1207,29 +815,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 220) {
- Object *ob;
Mesh *me;
- ob = bmain->object.first;
-
- /* adapt form factor in order to get the 'old' physics
- * behavior back...
- */
-
- while (ob) {
- /* in future, distinguish between different
- * object bounding shapes
- */
- ob->formfactor = 0.4f;
- /* patch form factor, note that inertia equiv radius
- * of a rotation symmetrical obj
- */
- if (ob->inertia != 1.0f) {
- ob->formfactor /= ob->inertia * ob->inertia;
- }
- ob = ob->id.next;
- }
-
/* Began using alpha component of vertex colors, but
* old file vertex colors are undefined, reset them
* to be fully opaque. -zr
@@ -1259,61 +846,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile <= 221) {
- Scene *sce = bmain->scene.first;
-
- /* new variables for std-alone player and runtime */
- while (sce) {
- sce->r.xplay = 640;
- sce->r.yplay = 480;
- sce->r.freqplay = 60;
-
- sce = sce->id.next;
- }
-
- }
-
- if (bmain->versionfile <= 222) {
- Scene *sce = bmain->scene.first;
-
- /* new variables for std-alone player and runtime */
- while (sce) {
- sce->r.depth = 32;
-
- sce = sce->id.next;
- }
- }
-
if (bmain->versionfile <= 223) {
VFont *vf;
- Image *ima;
- Object *ob;
-
for (vf = bmain->vfont.first; vf; vf = vf->id.next) {
if (STREQ(vf->name + strlen(vf->name) - 6, ".Bfont")) {
strcpy(vf->name, FO_BUILTIN_NAME);
}
}
-
- /* Old textures animate at 25 FPS */
- for (ima = bmain->image.first; ima; ima = ima->id.next) {
- ima->animspeed = 25;
- }
-
- /* Zr remapped some keyboard codes to be linear (stupid zr) */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- bSensor *sens;
-
- for (sens = ob->sensors.first; sens; sens = sens->next) {
- if (sens->type == SENS_KEYBOARD) {
- bKeyboardSensor *ks = sens->data;
-
- ks->key = map_223_keybd_code_to_224_keybd_code(ks->key);
- ks->qual = map_223_keybd_code_to_224_keybd_code(ks->qual);
- ks->qual2 = map_223_keybd_code_to_224_keybd_code(ks->qual2);
- }
- }
- }
}
if (bmain->versionfile <= 224) {
@@ -1357,17 +896,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile <= 225) {
- World *wo;
- /* Use Sumo for old games */
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- wo->physicsEngine = 2;
- }
- }
-
if (bmain->versionfile <= 227) {
Scene *sce;
- Material *ma;
bScreen *sc;
Object *ob;
@@ -1420,17 +950,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->audio.mixrate = 48000;
sce->audio.flag |= AUDIO_SCRUB;
- sce->r.mode |= R_ENVMAP;
- }
-
- /* init new shader vars */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- ma->refrac = 4.0f;
- ma->roughness = 0.5f;
- ma->param[0] = 0.5f;
- ma->param[1] = 0.1f;
- ma->param[2] = 0.1f;
- ma->param[3] = 0.05f;
}
/* patch for old wrong max view2d settings, allows zooming out more */
@@ -1455,7 +974,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 228) {
- Scene *sce;
bScreen *sc;
Object *ob;
@@ -1501,10 +1019,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
ob = ob->id.next;
}
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- sce->r.mode |= R_ENVMAP;
- }
-
/* convert old mainb values for new button panels */
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
@@ -1517,7 +1031,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
SpaceButs *sbuts = (SpaceButs *)sl;
sbuts->v2d.maxzoom = 1.2f;
- sbuts->align = 1; /* horizontal default */
if (sbuts->mainb == BUTS_LAMP) {
sbuts->mainb = CONTEXT_SHADING;
@@ -1542,9 +1055,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
sbuts->mainb = CONTEXT_SCENE;
//sbuts->tab[CONTEXT_SCENE] = TAB_SCENE_RENDER;
}
- else if (sbuts->mainb == BUTS_GAME) {
- sbuts->mainb = CONTEXT_LOGIC;
- }
else if (sbuts->mainb == BUTS_FPAINT) {
sbuts->mainb = CONTEXT_EDITING;
}
@@ -1598,57 +1108,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 231) {
- Material *ma = bmain->mat.first;
bScreen *sc = bmain->screen.first;
- Scene *sce;
- Lamp *la;
- World *wrld;
-
- /* introduction of raytrace */
- while (ma) {
- if (ma->fresnel_tra_i == 0.0f)
- ma->fresnel_tra_i = 1.25f;
- if (ma->fresnel_mir_i == 0.0f)
- ma->fresnel_mir_i = 1.25f;
-
- ma->ang = 1.0;
- ma->ray_depth = 2;
- ma->ray_depth_tra = 2;
- ma->fresnel_tra = 0.0;
- ma->fresnel_mir = 0.0;
-
- ma = ma->id.next;
- }
- sce = bmain->scene.first;
- while (sce) {
- if (sce->r.gauss == 0.0f)
- sce->r.gauss = 1.0f;
- sce = sce->id.next;
- }
- la = bmain->lamp.first;
- while (la) {
- if (la->k == 0.0f) la->k = 1.0;
- if (la->ray_samp == 0)
- la->ray_samp = 1;
- if (la->ray_sampy == 0)
- la->ray_sampy = 1;
- if (la->ray_sampz == 0)
- la->ray_sampz = 1;
- if (la->area_size == 0.0f)
- la->area_size = 1.0f;
- if (la->area_sizey == 0.0f)
- la->area_sizey = 1.0f;
- if (la->area_sizez == 0.0f)
- la->area_sizez = 1.0f;
- la = la->id.next;
- }
- wrld = bmain->world.first;
- while (wrld) {
- if (wrld->range == 0.0f) {
- wrld->range = 1.0f / wrld->exposure;
- }
- wrld = wrld->id.next;
- }
/* new bit flags for showing/hiding grid floor and axes */
@@ -1679,7 +1139,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
Tex *tex = bmain->tex.first;
World *wrld = bmain->world.first;
bScreen *sc;
- Scene *sce;
while (tex) {
if ((tex->flag & (TEX_CHECKER_ODD + TEX_CHECKER_EVEN)) == 0) {
@@ -1706,10 +1165,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
while (wrld) {
if (wrld->aodist == 0.0f) {
wrld->aodist = 10.0f;
- wrld->aobias = 0.05f;
}
- if (wrld->aosamp == 0)
- wrld->aosamp = 5;
if (wrld->aoenergy == 0.0f)
wrld->aoenergy = 1.0f;
wrld = wrld->id.next;
@@ -1731,13 +1187,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
}
- sce = bmain->scene.first;
- while (sce) {
- if (sce->r.ocres == 0)
- sce->r.ocres = 64;
- sce = sce->id.next;
- }
-
}
if (bmain->versionfile <= 233) {
@@ -1746,10 +1195,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
/* Object *ob = bmain->object.first; */
while (ma) {
- if (ma->rampfac_col == 0.0f)
- ma->rampfac_col = 1.0;
- if (ma->rampfac_spec == 0.0f)
- ma->rampfac_spec = 1.0;
if (ma->pr_lamp == 0)
ma->pr_lamp = 3;
ma = ma->id.next;
@@ -1770,15 +1215,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 234) {
- World *wo;
bScreen *sc;
- /* force sumo engine to be active */
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- if (wo->physicsEngine == 0)
- wo->physicsEngine = 2;
- }
-
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -1826,8 +1264,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile <= 236) {
Object *ob;
Camera *cam = bmain->camera.first;
- Material *ma;
- bScreen *sc;
while (cam) {
if (cam->ortho_scale == 0.0f) {
@@ -1837,29 +1273,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
cam = cam->id.next;
}
- /* set manipulator type */
/* force oops draw if depgraph was set*/
/* set time line var */
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- if (v3d->twtype == 0)
- v3d->twtype = V3D_MANIP_TRANSLATE;
- }
- }
- }
- }
- /* init new shader vars */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->darkness == 0.0f) {
- ma->rms = 0.1f;
- ma->darkness = 1.0f;
- }
- }
/* softbody init new vars */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
@@ -1911,7 +1326,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
BKE_pose_tag_recalc(bmain, ob->pose);
/* cannot call stuff now (pointers!), done in setup_app_data */
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+ ob->id.recalc |= ID_RECALC_ALL;
/* new generic xray option */
arm = blo_do_versions_newlibadr(fd, lib, ob->data);
@@ -2088,7 +1503,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
Object *ob;
Scene *sce = bmain->scene.first;
Camera *cam = bmain->camera.first;
- Material *ma = bmain->mat.first;
int set_passepartout = 0;
/* deformflag is local in modifier now */
@@ -2121,11 +1535,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
set_passepartout = 1;
sce->r.scemode &= ~R_PASSEPARTOUT;
}
- /* gauss is filter variable now */
- if (sce->r.mode & R_GAUSS) {
- sce->r.filtertype = R_FILTER_GAUSS;
- sce->r.mode &= ~R_GAUSS;
- }
}
for (; cam; cam = cam->id.next) {
@@ -2140,36 +1549,15 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (!(cam->passepartalpha))
cam->passepartalpha = 0.2f;
}
-
- for (; ma; ma = ma->id.next) {
- if (ma->strand_sta == 0.0f) {
- ma->strand_sta = ma->strand_end = 1.0f;
- ma->mode |= MA_TANGENT_STR;
- }
- if (ma->mode & MA_TRACEBLE)
- ma->mode |= MA_SHADBUF;
- }
}
if (bmain->versionfile <= 241) {
Object *ob;
- Tex *tex;
Scene *sce;
- World *wo;
Lamp *la;
- Material *ma;
bArmature *arm;
bNodeTree *ntree;
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- /* Migrate to Bullet for games, except for the NaN versions */
- /* People can still explicitly choose for Sumo (after 2.42 is out) */
- if (bmain->versionfile > 225)
- wo->physicsEngine = WOPHY_BULLET;
- if (WO_AODIST == wo->aomode)
- wo->aocolor = WO_AOPLAIN;
- }
-
/* updating layers still */
for (arm = bmain->armature.first; arm; arm = arm->id.next) {
bone_version_239(&arm->bonebase);
@@ -2180,23 +1568,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (sce->audio.mixrate == 0)
sce->audio.mixrate = 48000;
- if (sce->r.xparts < 2)
- sce->r.xparts = 4;
- if (sce->r.yparts < 2)
- sce->r.yparts = 4;
-
- /* adds default layer */
- if (BLI_listbase_is_empty(&sce->r.layers)) {
- BKE_scene_add_render_layer(sce, NULL);
- }
- else {
- SceneRenderLayer *srl;
- /* new layer flag for sky, was default for solid */
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- if (srl->layflag & SCE_LAY_SOLID)
- srl->layflag |= SCE_LAY_SKY;
- srl->passflag &= (SCE_PASS_COMBINED | SCE_PASS_Z | SCE_PASS_NORMAL | SCE_PASS_VECTOR);
- }
+ /* We don't add default layer since blender2.8 because the layers
+ * are now in Scene->view_layers and a default layer is created in
+ * the doversion later on.
+ */
+ SceneRenderLayer *srl;
+ /* new layer flag for sky, was default for solid */
+ for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ if (srl->layflag & SCE_LAY_SOLID)
+ srl->layflag |= SCE_LAY_SKY;
+ srl->passflag &= (SCE_PASS_COMBINED | SCE_PASS_Z | SCE_PASS_NORMAL | SCE_PASS_VECTOR);
}
/* node version changes */
@@ -2208,20 +1589,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
sce->toolsettings->uvcalc_flag = UVCALC_FILLHOLES;
sce->toolsettings->unwrapper = 1;
}
-
- if (sce->r.mode & R_PANORAMA) {
- /* all these checks to ensure saved files between released versions keep working... */
- if (sce->r.xsch < sce->r.ysch) {
- Object *obc = blo_do_versions_newlibadr(fd, lib, sce->camera);
- if (obc && obc->type == OB_CAMERA) {
- Camera *cam = blo_do_versions_newlibadr(fd, lib, obc->data);
- if (cam->lens >= 10.0f) {
- sce->r.xsch *= sce->r.xparts;
- cam->lens *= (float)sce->r.ysch / (float)sce->r.xsch;
- }
- }
- }
- }
}
for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
@@ -2231,12 +1598,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (la->buffers == 0)
la->buffers = 1;
- for (tex = bmain->tex.first; tex; tex = tex->id.next) {
- if (tex->env && tex->env->viewscale == 0.0f)
- tex->env->viewscale = 1.0f;
- //tex->imaflag |= TEX_GAUSS_MIP;
- }
-
/* for empty drawsize and drawtype */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->empty_drawsize == 0.0f) {
@@ -2245,21 +1606,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- /* stucci returns intensity from now on */
- int a;
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex) {
- tex = blo_do_versions_newlibadr(fd, lib, ma->mtex[a]->tex);
- if (tex && tex->type == TEX_STUCCI)
- ma->mtex[a]->mapto &= ~(MAP_COL | MAP_SPEC | MAP_REF);
- }
- }
- /* transmissivity defaults */
- if (ma->tx_falloff == 0.0f)
- ma->tx_falloff = 1.0f;
- }
-
/* during 2.41 images with this name were used for viewer node output, lets fix that */
if (bmain->versionfile == 241) {
Image *ima;
@@ -2279,7 +1625,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
Curve *cu;
Material *ma;
Mesh *me;
- Group *group;
+ Collection *collection;
Nurb *nu;
BezTriple *bezt;
BPoint *bp;
@@ -2429,8 +1775,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->shad_alpha == 0.0f)
- ma->shad_alpha = 1.0f;
if (ma->nodetree)
ntree_version_242(ma->nodetree);
}
@@ -2438,9 +1782,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (me = bmain->mesh.first; me; me = me->id.next)
customdata_version_242(me);
- for (group = bmain->group.first; group; group = group->id.next)
- if (group->layer == 0)
- group->layer = (1 << 20) - 1;
+ for (collection = bmain->collection.first; collection; collection = collection->id.next)
+ if (collection->layer == 0)
+ collection->layer = (1 << 20) - 1;
/* now, subversion control! */
if (bmain->subversionfile < 3) {
@@ -2470,13 +1814,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
ima = blo_do_versions_newlibadr(fd, lib, tex->ima);
if (tex->imaflag & TEX_ANIM5_)
ima->source = IMA_SRC_MOVIE;
- if (tex->imaflag & TEX_FIELDS_)
- ima->flag |= IMA_FIELDS;
- if (tex->imaflag & TEX_STD_FIELD_)
- ima->flag |= IMA_STD_FIELD;
}
tex->iuser.frames = tex->frames;
- tex->iuser.fie_ima = (char)tex->fie_ima;
tex->iuser.offset = tex->offset;
tex->iuser.sfra = tex->sfra;
tex->iuser.cycl = (tex->imaflag & TEX_ANIMCYCLIC_) != 0;
@@ -2490,30 +1829,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (ma = bmain->mat.first; ma; ma = ma->id.next)
if (ma->nodetree)
do_version_ntree_242_2(ma->nodetree);
-
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE)
- ((SpaceImage *)sl)->iuser.fie_ima = 2;
- else if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- BGpic *bgpic;
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next)
- bgpic->iuser.fie_ima = 2;
- }
- }
- }
- }
}
if (bmain->subversionfile < 4) {
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->r.bake_mode = 1; /* prevent to include render stuff here */
sce->r.bake_filter = 16;
- sce->r.bake_osa = 5;
sce->r.bake_flag = R_BAKE_CLEAR;
}
}
@@ -2521,32 +1842,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile <= 243) {
Object *ob = bmain->object.first;
- Material *ma;
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->sss_scale == 0.0f) {
- ma->sss_radius[0] = 1.0f;
- ma->sss_radius[1] = 1.0f;
- ma->sss_radius[2] = 1.0f;
- ma->sss_col[0] = 0.8f;
- ma->sss_col[1] = 0.8f;
- ma->sss_col[2] = 0.8f;
- ma->sss_error = 0.05f;
- ma->sss_scale = 0.1f;
- ma->sss_ior = 1.3f;
- ma->sss_colfac = 1.0f;
- ma->sss_texfac = 0.0f;
- }
- if (ma->sss_front == 0 && ma->sss_back == 0) {
- ma->sss_front = 1.0f;
- ma->sss_back = 1.0f;
- }
- if (ma->sss_col[0] == 0 && ma->sss_col[1] == 0 && ma->sss_col[2] == 0) {
- ma->sss_col[0] = ma->r;
- ma->sss_col[1] = ma->g;
- ma->sss_col[2] = ma->b;
- }
- }
for (; ob; ob = ob->id.next) {
bDeformGroup *curdef;
@@ -2594,15 +1889,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 244) {
- Scene *sce;
bScreen *sc;
- Lamp *la;
- World *wrld;
if (bmain->versionfile != 244 || bmain->subversionfile < 2) {
- for (sce = bmain->scene.first; sce; sce = sce->id.next)
- sce->r.mode |= R_SSS;
-
/* correct older action editors - incorrect scrolling */
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
@@ -2625,28 +1914,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
}
-
- if (bmain->versionfile != 244 || bmain->subversionfile < 3) {
- /* constraints recode version patch used to be here. Moved to 245 now... */
-
- for (wrld = bmain->world.first; wrld; wrld = wrld->id.next) {
- if (wrld->mode & WO_AMB_OCC)
- wrld->ao_samp_method = WO_AOSAMP_CONSTANT;
- else
- wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
-
- wrld->ao_adapt_thresh = 0.005f;
- }
-
- for (la = bmain->lamp.first; la; la = la->id.next) {
- if (la->type == LA_AREA)
- la->ray_samp_method = LA_SAMP_CONSTANT;
- else
- la->ray_samp_method = LA_SAMP_HALTON;
-
- la->adapt_thresh = 0.001f;
- }
- }
}
if (bmain->versionfile <= 245) {
@@ -2656,7 +1923,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
Lamp *la;
Material *ma;
ParticleSettings *part;
- World *wrld;
Mesh *me;
bNodeTree *ntree;
Tex *tex;
@@ -2788,10 +2054,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile != 245 || bmain->subversionfile < 1) {
for (la = bmain->lamp.first; la; la = la->id.next) {
- if (la->mode & LA_QUAD)
- la->falloff_type = LA_FALLOFF_SLIDERS;
- else
- la->falloff_type = LA_FALLOFF_INVLINEAR;
+ la->falloff_type = LA_FALLOFF_INVLINEAR;
if (la->curfalloff == NULL) {
la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
@@ -2801,51 +2064,23 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->samp_gloss_mir == 0) {
- ma->gloss_mir = ma->gloss_tra = 1.0f;
- ma->aniso_gloss_mir = 1.0f;
- ma->samp_gloss_mir = ma->samp_gloss_tra = 18;
- ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005f;
- ma->dist_mir = 0.0f;
- ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
+ if (ma->gloss_mir == 0.0f) {
+ ma->gloss_mir = 1.0f;
}
-
- if (ma->strand_min == 0.0f)
- ma->strand_min = 1.0f;
}
for (part = bmain->particle.first; part; part = part->id.next) {
if (part->ren_child_nbr == 0)
part->ren_child_nbr = part->child_nbr;
-
- if (part->simplify_refsize == 0) {
- part->simplify_refsize = 1920;
- part->simplify_rate = 1.0f;
- part->simplify_transition = 0.1f;
- part->simplify_viewport = 0.8f;
- }
- }
-
- for (wrld = bmain->world.first; wrld; wrld = wrld->id.next) {
- if (wrld->ao_approx_error == 0.0f)
- wrld->ao_approx_error = 0.25f;
}
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree)
ntree_version_245(fd, lib, sce->nodetree);
- if (sce->r.simplify_shadowsamples == 0) {
+ if (sce->r.simplify_subsurf == 0) {
sce->r.simplify_subsurf = 6;
sce->r.simplify_particles = 1.0f;
- sce->r.simplify_shadowsamples = 16;
- sce->r.simplify_aosss = 1.0f;
- }
-
- if (sce->r.cineongamma == 0) {
- sce->r.cineonblack = 95;
- sce->r.cineonwhite = 685;
- sce->r.cineongamma = 1.7f;
}
}
@@ -2873,22 +2108,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- /* sanity check for skgen */
- {
- Scene *sce;
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[1] ||
- sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] ||
- sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2])
- {
- sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
- sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
- }
- }
- }
-
-
if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 2)) {
Image *ima;
@@ -3125,16 +2344,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
}
- if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 9)) {
- Material *ma;
- int a;
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->mode & MA_NORMAP_TANG)
- for (a = 0; a < MAX_MTEX; a++)
- if (ma->mtex[a] && ma->mtex[a]->tex)
- ma->mtex[a]->normapspace = MTEX_NSPACE_TANGENT;
- }
if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 10)) {
Object *ob;
@@ -3208,7 +2417,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
idproperties_fix_group_lengths(bmain->vfont);
idproperties_fix_group_lengths(bmain->text);
idproperties_fix_group_lengths(bmain->sound);
- idproperties_fix_group_lengths(bmain->group);
+ idproperties_fix_group_lengths(bmain->collection);
idproperties_fix_group_lengths(bmain->armature);
idproperties_fix_group_lengths(bmain->action);
idproperties_fix_group_lengths(bmain->nodetree);
@@ -3216,25 +2425,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
idproperties_fix_group_lengths(bmain->particle);
}
- /* sun/sky */
- if (bmain->versionfile < 246) {
- Object *ob;
- bActuator *act;
-
- /* dRot actuator change direction in 2.46 */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_OBJECT) {
- bObjectActuator *ba = act->data;
-
- ba->drot[0] = -ba->drot[0];
- ba->drot[1] = -ba->drot[1];
- ba->drot[2] = -ba->drot[2];
- }
- }
- }
- }
-
/* convert fluids to modifier */
if (bmain->versionfile < 246 || (bmain->versionfile == 246 && bmain->subversionfile < 1)) {
Object *ob;
@@ -3256,14 +2446,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
-
- if (bmain->versionfile < 246 || (bmain->versionfile == 246 && bmain->subversionfile < 1)) {
- Mesh *me;
-
- for (me = bmain->mesh.first; me; me = me->id.next)
- alphasort_version_246(fd, lib, me);
- }
-
if (bmain->versionfile < 246 || (bmain->versionfile == 246 && bmain->subversionfile < 1)) {
Object *ob;
for (ob = bmain->object.first; ob; ob = ob->id.next) {
@@ -3272,33 +2454,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 2)) {
- Object *ob;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- ob->gameflag |= OB_COLLISION;
- ob->margin = 0.06f;
- }
- }
-
- if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 3)) {
- Object *ob;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- /* Starting from subversion 3, ACTOR is a separate feature.
- * Before it was conditioning all the other dynamic flags */
- if (!(ob->gameflag & OB_ACTOR))
- ob->gameflag &= ~(OB_GHOST | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION_RESPONSE);
- /* suitable default for older files */
- }
- }
-
- if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 5)) {
- Lamp *la = bmain->lamp.first;
- for (; la; la = la->id.next) {
- la->skyblendtype = MA_RAMP_ADD;
- la->skyblendfac = 1.0f;
- }
- }
-
/* set the curve radius interpolation to 2.47 default - easy */
if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 6)) {
Curve *cu;
@@ -3322,72 +2477,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- /* direction constraint actuators were always local in previous version */
- if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 7)) {
- bActuator *act;
- Object *ob;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_CONSTRAINT) {
- bConstraintActuator *coa = act->data;
- if (coa->type == ACT_CONST_TYPE_DIST) {
- coa->flag |= ACT_CONST_LOCAL;
- }
- }
- }
- }
- }
-
- if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 9)) {
- Lamp *la = bmain->lamp.first;
- for (; la; la = la->id.next) {
- la->sky_exposure = 1.0f;
- }
- }
-
- /* BGE message actuators needed OB prefix, very confusing */
- if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 10)) {
- bActuator *act;
- Object *ob;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- for (act = ob->actuators.first; act; act = act->next) {
- if (act->type == ACT_MESSAGE) {
- bMessageActuator *msgAct = (bMessageActuator *)act->data;
-
- if (BLI_strnlen(msgAct->toPropName, 3) > 2) {
- /* strip first 2 chars, would have only worked if these were OB anyway */
- memmove(msgAct->toPropName, msgAct->toPropName + 2, sizeof(msgAct->toPropName) - 2);
- }
- else {
- msgAct->toPropName[0] = '\0';
- }
- }
- }
- }
- }
-
- if (bmain->versionfile < 248) {
- Lamp *la;
-
- for (la = bmain->lamp.first; la; la = la->id.next) {
- if (la->atm_turbidity == 0.0f) {
- la->sun_effect_type = 0;
- la->horizon_brightness = 1.0f;
- la->spread = 1.0f;
- la->sun_brightness = 1.0f;
- la->sun_size = 1.0f;
- la->backscattered_light = 1.0f;
- la->atm_turbidity = 2.0f;
- la->atm_inscattering_factor = 1.0f;
- la->atm_extinction_factor = 1.0f;
- la->atm_distance_factor = 1.0f;
- la->sun_intensity = 1.0f;
- }
- }
- }
-
if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 2)) {
Scene *sce;
@@ -3395,31 +2484,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->toolsettings->imapaint.seam_bleed = 2;
sce->toolsettings->imapaint.normal_angle = 80;
-
- /* initialize skeleton generation toolsettings */
- sce->toolsettings->skgen_resolution = 250;
- sce->toolsettings->skgen_threshold_internal = 0.1f;
- sce->toolsettings->skgen_threshold_external = 0.1f;
- sce->toolsettings->skgen_angle_limit = 30.0f;
- sce->toolsettings->skgen_length_ratio = 1.3f;
- sce->toolsettings->skgen_length_limit = 1.5f;
- sce->toolsettings->skgen_correlation_limit = 0.98f;
- sce->toolsettings->skgen_symmetry_limit = 0.1f;
- sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
- sce->toolsettings->skgen_postpro_passes = 3;
- sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL | SKGEN_FILTER_EXTERNAL | SKGEN_FILTER_SMART | SKGEN_SUB_CORRELATION | SKGEN_HARMONIC;
- sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
- sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
-
-
- sce->toolsettings->skgen_retarget_angle_weight = 1.0f;
- sce->toolsettings->skgen_retarget_length_weight = 1.0f;
- sce->toolsettings->skgen_retarget_distance_weight = 1.0f;
-
- /* Skeleton Sketching */
- sce->toolsettings->bone_sketching = 0;
- sce->toolsettings->skgen_retarget_roll = SK_RETARGET_ROLL_VIEW;
}
}
@@ -3461,60 +2525,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 3)) {
- Object *ob;
-
- /* Adjustments needed after Bullets update */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- ob->damping *= 0.635f;
- ob->rdamping = 0.1f + (0.8f * ob->rdamping);
- }
- }
-
- if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 4)) {
- Scene *sce;
- World *wrld;
-
- /* Dome (Fisheye) default parameters */
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- sce->r.domeangle = 180;
- sce->r.domemode = 1;
- sce->r.domeres = 4;
- sce->r.domeresbuf = 1.0f;
- sce->r.dometilt = 0;
- }
- /* DBVT culling by default */
- for (wrld = bmain->world.first; wrld; wrld = wrld->id.next) {
- wrld->mode |= WO_DBVT_CULLING;
- wrld->occlusionRes = 128;
- }
- }
-
- if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 5)) {
- Object *ob;
- World *wrld;
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->parent) {
- /* check if top parent has compound shape set and if yes, set this object
- * to compound shaper as well (was the behavior before, now it's optional) */
- Object *parent = blo_do_versions_newlibadr(fd, lib, ob->parent);
- while (parent && parent != ob && parent->parent != NULL) {
- parent = blo_do_versions_newlibadr(fd, lib, parent->parent);
- }
- if (parent) {
- if (parent->gameflag & OB_CHILD)
- ob->gameflag |= OB_CHILD;
- }
- }
- }
- for (wrld = bmain->world.first; wrld; wrld = wrld->id.next) {
- wrld->ticrate = 60;
- wrld->maxlogicstep = 5;
- wrld->physubstep = 1;
- wrld->maxphystep = 5;
- }
- }
-
/* correct introduce of seed for wind force */
if (bmain->versionfile < 249 && bmain->subversionfile < 1) {
Object *ob;
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
new file mode 100644
index 00000000000..55c875e3412
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_userdef.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenloader/intern/versioning_userdef.c
+ * \ingroup blenloader
+ *
+ * Version patch user preferences.
+ */
+
+#include <string.h>
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_userdef_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_addon.h"
+#include "BKE_colorband.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_keyconfig.h"
+
+#include "BLO_readfile.h" /* Own include. */
+
+#include "wm_event_types.h"
+
+/* Disallow access to global userdef. */
+#define U (_error_)
+
+
+static void do_versions_theme(UserDef *userdef, bTheme *btheme)
+{
+
+#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(userdef, ver, subver)
+ if (!USER_VERSION_ATLEAST(280, 20)) {
+ memcpy(btheme, &U_theme_default, sizeof(*btheme));
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 25)) {
+ copy_v4_v4_char(btheme->tact.anim_preview_range, btheme->tact.anim_active);
+ copy_v4_v4_char(btheme->tnla.anim_preview_range, btheme->tnla.anim_active);
+ copy_v4_v4_char(btheme->tipo.anim_preview_range, btheme->tact.anim_active);
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 26)) {
+ copy_v4_v4_char(btheme->tui.icon_collection, U_theme_default.tui.icon_collection);
+ copy_v4_v4_char(btheme->tui.icon_object, U_theme_default.tui.icon_object);
+ copy_v4_v4_char(btheme->tui.icon_object_data, U_theme_default.tui.icon_object_data);
+ copy_v4_v4_char(btheme->tui.icon_modifier, U_theme_default.tui.icon_modifier);
+ copy_v4_v4_char(btheme->tui.icon_shading, U_theme_default.tui.icon_shading);
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 27)) {
+ copy_v4_v4_char(btheme->tact.shade2, U_theme_default.tact.shade2);
+ copy_v4_v4_char(btheme->tact.hilite, U_theme_default.tact.hilite);
+ copy_v4_v4_char(btheme->tact.group, U_theme_default.tact.group);
+ copy_v4_v4_char(btheme->tact.group_active, U_theme_default.tact.group_active);
+ copy_v4_v4_char(btheme->tact.strip_select, U_theme_default.tact.strip_select);
+ copy_v4_v4_char(btheme->tact.ds_channel, U_theme_default.tact.ds_channel);
+ copy_v4_v4_char(btheme->tact.ds_subchannel, U_theme_default.tact.ds_subchannel);
+ copy_v4_v4_char(btheme->tact.keytype_movehold, U_theme_default.tact.keytype_movehold);
+ copy_v4_v4_char(btheme->tact.keytype_movehold_select, U_theme_default.tact.keytype_movehold_select);
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 28)) {
+ copy_v4_v4_char(btheme->tact.ds_ipoline, U_theme_default.tact.ds_ipoline);
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 29)) {
+ copy_v4_v4_char(btheme->tbuts.navigation_bar, U_theme_default.ttopbar.header);
+ }
+ if (!USER_VERSION_ATLEAST(280, 31)) {
+ copy_v4_v4_char(btheme->tclip.list_text, U_theme_default.tclip.list_text);
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 33)) {
+ copy_v4_v4_char(btheme->tuserpref.navigation_bar, U_theme_default.tuserpref.navigation_bar);
+ }
+
+#undef USER_VERSION_ATLEAST
+}
+
+/* UserDef.flag */
+#define USER_LMOUSESELECT (1 << 14) /* deprecated */
+
+static void do_version_select_mouse(UserDef *userdef, wmKeyMapItem *kmi)
+{
+ /* Remove select/action mouse from user defined keymaps. */
+ enum {
+ ACTIONMOUSE = 0x0005,
+ SELECTMOUSE = 0x0006,
+ EVT_TWEAK_A = 0x5005,
+ EVT_TWEAK_S = 0x5006,
+ };
+ const bool left = (userdef->flag & USER_LMOUSESELECT) != 0;
+
+ switch (kmi->type) {
+ case SELECTMOUSE: kmi->type = (left) ? LEFTMOUSE : RIGHTMOUSE; break;
+ case ACTIONMOUSE: kmi->type = (left) ? RIGHTMOUSE : LEFTMOUSE; break;
+ case EVT_TWEAK_S: kmi->type = (left) ? EVT_TWEAK_L : EVT_TWEAK_R; break;
+ case EVT_TWEAK_A: kmi->type = (left) ? EVT_TWEAK_R : EVT_TWEAK_L; break;
+ default: break;
+ }
+}
+
+/* patching UserDef struct and Themes */
+void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
+{
+
+#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(bmain, ver, subver)
+
+ /* the UserDef struct is not corrected with do_versions() .... ugh! */
+ if (userdef->wheellinescroll == 0) userdef->wheellinescroll = 3;
+ if (userdef->menuthreshold1 == 0) {
+ userdef->menuthreshold1 = 5;
+ userdef->menuthreshold2 = 2;
+ }
+ if (userdef->tb_leftmouse == 0) {
+ userdef->tb_leftmouse = 5;
+ userdef->tb_rightmouse = 5;
+ }
+ if (userdef->mixbufsize == 0) userdef->mixbufsize = 2048;
+ if (userdef->autokey_mode == 0) {
+ /* 'add/replace' but not on */
+ userdef->autokey_mode = 2;
+ }
+ if (userdef->savetime <= 0) {
+ userdef->savetime = 1;
+// XXX error(STRINGIFY(BLENDER_STARTUP_FILE)" is buggy, please consider removing it.\n");
+ }
+ if (userdef->gizmo_size == 0) {
+ userdef->gizmo_size = 75;
+ userdef->gizmo_flag |= USER_GIZMO_DRAW;
+ }
+ if (userdef->pad_rot_angle == 0.0f)
+ userdef->pad_rot_angle = 15.0f;
+
+ /* graph editor - unselected F-Curve visibility */
+ if (userdef->fcu_inactive_alpha == 0) {
+ userdef->fcu_inactive_alpha = 0.25f;
+ }
+
+ if (!USER_VERSION_ATLEAST(192, 0)) {
+ strcpy(userdef->sounddir, "/");
+ }
+
+ /* patch to set Dupli Armature */
+ if (!USER_VERSION_ATLEAST(220, 0)) {
+ userdef->dupflag |= USER_DUP_ARM;
+ }
+
+ /* added seam, normal color, undo */
+ if (!USER_VERSION_ATLEAST(235, 0)) {
+ userdef->uiflag |= USER_GLOBALUNDO;
+ if (userdef->undosteps == 0) userdef->undosteps = 32;
+ }
+ if (!USER_VERSION_ATLEAST(236, 0)) {
+ /* illegal combo... */
+ if (userdef->flag & USER_LMOUSESELECT)
+ userdef->flag &= ~USER_TWOBUTTONMOUSE;
+ }
+ if (!USER_VERSION_ATLEAST(240, 0)) {
+ userdef->uiflag |= USER_PLAINMENUS;
+ if (userdef->obcenter_dia == 0) userdef->obcenter_dia = 6;
+ }
+ if (!USER_VERSION_ATLEAST(242, 0)) {
+ /* set defaults for 3D View rotating axis indicator */
+ /* since size can't be set to 0, this indicates it's not saved in startup.blend */
+ if (userdef->rvisize == 0) {
+ userdef->rvisize = 15;
+ userdef->rvibright = 8;
+ userdef->uiflag |= USER_SHOW_GIZMO_AXIS;
+ }
+
+ }
+ if (!USER_VERSION_ATLEAST(244, 0)) {
+ /* set default number of recently-used files (if not set) */
+ if (userdef->recent_files == 0) userdef->recent_files = 10;
+ }
+ if (!USER_VERSION_ATLEAST(245, 3)) {
+ if (userdef->coba_weight.tot == 0)
+ BKE_colorband_init(&userdef->coba_weight, true);
+ }
+ if (!USER_VERSION_ATLEAST(245, 3)) {
+ userdef->flag |= USER_ADD_VIEWALIGNED | USER_ADD_EDITMODE;
+ }
+ if (!USER_VERSION_ATLEAST(250, 0)) {
+ /* adjust grease-pencil distances */
+ userdef->gp_manhattendist = 1;
+ userdef->gp_euclideandist = 2;
+
+ /* adjust default interpolation for new IPO-curves */
+ userdef->ipo_new = BEZT_IPO_BEZ;
+ }
+
+ if (!USER_VERSION_ATLEAST(250, 3)) {
+ /* new audio system */
+ if (userdef->audiochannels == 0)
+ userdef->audiochannels = 2;
+ if (userdef->audioformat == 0)
+ userdef->audioformat = 0x24;
+ if (userdef->audiorate == 0)
+ userdef->audiorate = 48000;
+ }
+
+ if (!USER_VERSION_ATLEAST(250, 8)) {
+ wmKeyMap *km;
+
+ for (km = userdef->user_keymaps.first; km; km = km->next) {
+ if (STREQ(km->idname, "Armature_Sketch"))
+ strcpy(km->idname, "Armature Sketch");
+ else if (STREQ(km->idname, "View3D"))
+ strcpy(km->idname, "3D View");
+ else if (STREQ(km->idname, "View3D Generic"))
+ strcpy(km->idname, "3D View Generic");
+ else if (STREQ(km->idname, "EditMesh"))
+ strcpy(km->idname, "Mesh");
+ else if (STREQ(km->idname, "UVEdit"))
+ strcpy(km->idname, "UV Editor");
+ else if (STREQ(km->idname, "Animation_Channels"))
+ strcpy(km->idname, "Animation Channels");
+ else if (STREQ(km->idname, "GraphEdit Keys"))
+ strcpy(km->idname, "Graph Editor");
+ else if (STREQ(km->idname, "GraphEdit Generic"))
+ strcpy(km->idname, "Graph Editor Generic");
+ else if (STREQ(km->idname, "Action_Keys"))
+ strcpy(km->idname, "Dopesheet");
+ else if (STREQ(km->idname, "NLA Data"))
+ strcpy(km->idname, "NLA Editor");
+ else if (STREQ(km->idname, "Node Generic"))
+ strcpy(km->idname, "Node Editor");
+ else if (STREQ(km->idname, "Logic Generic"))
+ strcpy(km->idname, "Logic Editor");
+ else if (STREQ(km->idname, "File"))
+ strcpy(km->idname, "File Browser");
+ else if (STREQ(km->idname, "FileMain"))
+ strcpy(km->idname, "File Browser Main");
+ else if (STREQ(km->idname, "FileButtons"))
+ strcpy(km->idname, "File Browser Buttons");
+ else if (STREQ(km->idname, "Buttons Generic"))
+ strcpy(km->idname, "Property Editor");
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(252, 3)) {
+ if (userdef->flag & USER_LMOUSESELECT)
+ userdef->flag &= ~USER_TWOBUTTONMOUSE;
+ }
+ if (!USER_VERSION_ATLEAST(252, 4)) {
+ /* default new handle type is auto handles */
+ userdef->keyhandles_new = HD_AUTO;
+ }
+
+ if (!USER_VERSION_ATLEAST(257, 0)) {
+ /* clear "AUTOKEY_FLAG_ONLYKEYINGSET" flag from userprefs,
+ * so that it doesn't linger around from old configs like a ghost */
+ userdef->autokey_flag &= ~AUTOKEY_FLAG_ONLYKEYINGSET;
+ }
+
+ if (!USER_VERSION_ATLEAST(260, 3)) {
+ /* if new keyframes handle default is stuff "auto", make it "auto-clamped" instead
+ * was changed in 260 as part of GSoC11, but version patch was wrong
+ */
+ if (userdef->keyhandles_new == HD_AUTO)
+ userdef->keyhandles_new = HD_AUTO_ANIM;
+
+ /* enable (Cycles) addon by default */
+ BKE_addon_ensure(&userdef->addons, "cycles");
+ }
+
+ if (!USER_VERSION_ATLEAST(261, 4)) {
+ userdef->use_16bit_textures = true;
+ }
+
+ if (!USER_VERSION_ATLEAST(267, 0)) {
+
+ /* GL Texture Garbage Collection */
+ if (userdef->textimeout == 0) {
+ userdef->texcollectrate = 60;
+ userdef->textimeout = 120;
+ }
+ if (userdef->memcachelimit <= 0) {
+ userdef->memcachelimit = 32;
+ }
+ if (userdef->dbl_click_time == 0) {
+ userdef->dbl_click_time = 350;
+ }
+ if (userdef->v2d_min_gridsize == 0) {
+ userdef->v2d_min_gridsize = 35;
+ }
+ if (userdef->dragthreshold == 0)
+ userdef->dragthreshold = 5;
+ if (userdef->widget_unit == 0)
+ userdef->widget_unit = 20;
+ if (userdef->anisotropic_filter <= 0)
+ userdef->anisotropic_filter = 1;
+
+ if (userdef->ndof_sensitivity == 0.0f) {
+ userdef->ndof_sensitivity = 1.0f;
+ userdef->ndof_flag = (NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | NDOF_SHOULD_ROTATE);
+ }
+
+ if (userdef->ndof_orbit_sensitivity == 0.0f) {
+ userdef->ndof_orbit_sensitivity = userdef->ndof_sensitivity;
+
+ if (!(userdef->flag & USER_TRACKBALL))
+ userdef->ndof_flag |= NDOF_TURNTABLE;
+ }
+ if (userdef->tweak_threshold == 0)
+ userdef->tweak_threshold = 10;
+ }
+
+ /* NOTE!! from now on use userdef->versionfile and userdef->subversionfile */
+#undef USER_VERSION_ATLEAST
+#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(userdef, ver, subver)
+
+ if (!USER_VERSION_ATLEAST(271, 5)) {
+ userdef->pie_menu_radius = 100;
+ userdef->pie_menu_threshold = 12;
+ userdef->pie_animation_timeout = 6;
+ }
+
+ if (!USER_VERSION_ATLEAST(275, 2)) {
+ userdef->ndof_deadzone = 0.1;
+ }
+
+ if (!USER_VERSION_ATLEAST(275, 4)) {
+ userdef->node_margin = 80;
+ }
+
+ if (!USER_VERSION_ATLEAST(278, 6)) {
+ /* Clear preference flags for re-use. */
+ userdef->flag &= ~(
+ USER_FLAG_NUMINPUT_ADVANCED | USER_FLAG_DEPRECATED_2 | USER_FLAG_DEPRECATED_3 |
+ USER_FLAG_DEPRECATED_6 | USER_FLAG_DEPRECATED_7 |
+ USER_FLAG_DEPRECATED_9 | USER_DEVELOPER_UI);
+ userdef->uiflag &= ~(
+ USER_UIFLAG_DEPRECATED_7);
+ userdef->transopts &= ~(
+ USER_TR_DEPRECATED_2 | USER_TR_DEPRECATED_3 | USER_TR_DEPRECATED_4 |
+ USER_TR_DEPRECATED_6 | USER_TR_DEPRECATED_7);
+
+ userdef->uiflag |= USER_LOCK_CURSOR_ADJUST;
+ }
+
+
+ if (!USER_VERSION_ATLEAST(280, 20)) {
+ userdef->gpu_viewport_quality = 0.6f;
+
+ /* Reset theme, old themes will not be compatible with minor version updates from now on. */
+ for (bTheme *btheme = userdef->themes.first; btheme; btheme = btheme->next) {
+ memcpy(btheme, &U_theme_default, sizeof(*btheme));
+ }
+
+ /* Annotations - new layer color
+ * Replace anything that used to be set if it looks like was left
+ * on the old default (i.e. black), which most users used
+ */
+ if ((userdef->gpencil_new_layer_col[3] < 0.1f) || (userdef->gpencil_new_layer_col[0] < 0.1f)) {
+ /* - New color matches the annotation pencil icon
+ * - Non-full alpha looks better!
+ */
+ ARRAY_SET_ITEMS(userdef->gpencil_new_layer_col, 0.38f, 0.61f, 0.78f, 0.9f);
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 31)) {
+ /* Remove select/action mouse from user defined keymaps. */
+ for (wmKeyMap *keymap = userdef->user_keymaps.first; keymap; keymap = keymap->next) {
+ for (wmKeyMapDiffItem *kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) {
+ if (kmdi->remove_item) {
+ do_version_select_mouse(userdef, kmdi->remove_item);
+ }
+ if (kmdi->add_item) {
+ do_version_select_mouse(userdef, kmdi->add_item);
+ }
+ }
+
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ do_version_select_mouse(userdef, kmi);
+ }
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 33)) {
+ /* Enable GLTF addon by default. */
+ BKE_addon_ensure(&userdef->addons, "io_scene_gltf2");
+ }
+
+ if (!USER_VERSION_ATLEAST(280, 35)) {
+ /* Preserve RMB select setting after moving to Python and changing default value. */
+ if (USER_VERSION_ATLEAST(280, 32) || !(userdef->flag & USER_LMOUSESELECT)) {
+ BKE_keyconfig_pref_set_select_mouse(userdef, 1, false);
+ }
+
+ userdef->flag &= ~USER_LMOUSESELECT;
+ }
+
+ /**
+ * Include next version bump.
+ */
+ {
+ /* (keep this block even if it becomes empty). */
+ copy_v4_fl4(userdef->light[0].vec, -0.580952, 0.228571, 0.781185, 0.0);
+ copy_v4_fl4(userdef->light[0].col, 0.900000, 0.900000, 0.900000, 1.000000);
+ copy_v4_fl4(userdef->light[0].spec, 0.318547, 0.318547, 0.318547, 1.000000);
+ userdef->light[0].smooth = 0.1;
+
+ copy_v4_fl4(userdef->light[1].vec, 0.788218, 0.593482, -0.162765, 0.0);
+ copy_v4_fl4(userdef->light[1].col, 0.267115, 0.269928, 0.358840, 1.000000);
+ copy_v4_fl4(userdef->light[1].spec, 0.090838, 0.090838, 0.090838, 1.000000);
+ userdef->light[1].smooth = 0.25;
+
+ copy_v4_fl4(userdef->light[2].vec, 0.696472, -0.696472, -0.172785, 0.0);
+ copy_v4_fl4(userdef->light[2].col, 0.293216, 0.304662, 0.401968, 1.000000);
+ copy_v4_fl4(userdef->light[2].spec, 0.069399, 0.020331, 0.020331, 1.000000);
+ userdef->light[2].smooth = 0.5;
+
+ copy_v4_fl4(userdef->light_ambient, 0.025000, 0.025000, 0.025000, 1.000000);
+ }
+
+ if (userdef->pixelsize == 0.0f)
+ userdef->pixelsize = 1.0f;
+
+ if (userdef->image_draw_method == 0)
+ userdef->image_draw_method = IMAGE_DRAW_METHOD_2DTEXTURE;
+
+ // we default to the first audio device
+ userdef->audiodevice = 0;
+
+ for (bTheme *btheme = userdef->themes.first; btheme; btheme = btheme->next) {
+ do_versions_theme(userdef, btheme);
+ }
+#undef USER_VERSION_ATLEAST
+
+}
+
+#undef USER_LMOUSESELECT
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 4f48318582a..be708697ac6 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -102,24 +102,29 @@
/* allow writefile to use deprecated functionality (for forward compatibility code) */
#define DNA_DEPRECATED_ALLOW
+/* Allow using DNA struct members that are marked as private for read/write.
+ * Note: Each header that uses this needs to define its own way of handling
+ * it. There's no generic implementation, direct use does nothing. */
+#define DNA_PRIVATE_READ_WRITE_ALLOW
#include "DNA_anim_types.h"
#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_collection_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_controller_types.h"
#include "DNA_dynamicpaint_types.h"
#include "DNA_genfile.h"
-#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_fileglobal_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_lamp_types.h"
+#include "DNA_layer_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
@@ -130,12 +135,11 @@
#include "DNA_object_force_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
-#include "DNA_property_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_sensor_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
@@ -146,6 +150,7 @@
#include "DNA_vfont_types.h"
#include "DNA_world_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
@@ -158,20 +163,25 @@
#include "BKE_action.h"
#include "BKE_blender_version.h"
#include "BKE_bpath.h"
-#include "BKE_curve.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h" // for G
+#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
-#include "BKE_library.h" // for set_listbasepointers
+#include "BKE_layer.h"
+#include "BKE_library_override.h"
#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
#include "BKE_node.h"
+#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_sequencer.h"
+#include "BKE_shader_fx.h"
#include "BKE_subsurf.h"
-#include "BKE_modifier.h"
-#include "BKE_fcurve.h"
-#include "BKE_pointcache.h"
-#include "BKE_mesh.h"
+#include "BKE_workspace.h"
#ifdef USE_NODE_COMPAT_CUSTOMNODES
#include "NOD_socket.h" /* for sock->default_value data */
@@ -180,7 +190,6 @@
#include "BLO_writefile.h"
#include "BLO_readfile.h"
-#include "BLO_runtime.h"
#include "BLO_undofile.h"
#include "BLO_blend_defs.h"
@@ -709,6 +718,25 @@ static void write_iddata(void *wd, const ID *id)
if (id->properties && !ELEM(GS(id->name), ID_WM)) {
IDP_WriteProperty(id->properties, wd);
}
+
+ if (id->override_static) {
+ writestruct(wd, DATA, IDOverrideStatic, 1, id->override_static);
+
+ writelist(wd, DATA, IDOverrideStaticProperty, &id->override_static->properties);
+ for (IDOverrideStaticProperty *op = id->override_static->properties.first; op; op = op->next) {
+ writedata(wd, DATA, strlen(op->rna_path) + 1, op->rna_path);
+
+ writelist(wd, DATA, IDOverrideStaticPropertyOperation, &op->operations);
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ if (opop->subitem_reference_name) {
+ writedata(wd, DATA, strlen(opop->subitem_reference_name) + 1, opop->subitem_reference_name);
+ }
+ if (opop->subitem_local_name) {
+ writedata(wd, DATA, strlen(opop->subitem_local_name) + 1, opop->subitem_local_name);
+ }
+ }
+ }
+ }
}
static void write_previews(WriteData *wd, const PreviewImage *prv_orig)
@@ -1119,7 +1147,9 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree)
* Take care using 'use_active_win', since we wont want the currently active window
* to change which scene renders (currently only used for undo).
*/
-static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_active_win)
+static void current_screen_compat(
+ Main *mainvar, bool use_active_win,
+ bScreen **r_screen, Scene **r_scene, ViewLayer **r_view_layer)
{
wmWindowManager *wm;
wmWindow *window = NULL;
@@ -1147,7 +1177,9 @@ static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_ac
}
}
- *r_screen = (window) ? window->screen : NULL;
+ *r_screen = (window) ? BKE_workspace_active_screen_get(window->workspace_hook) : NULL;
+ *r_scene = (window) ? window->scene : NULL;
+ *r_view_layer = (window && *r_scene) ? BKE_view_layer_find(*r_scene, window->view_layer_name) : NULL;
}
typedef struct RenderInfo {
@@ -1163,13 +1195,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
{
bScreen *curscreen;
Scene *sce, *curscene = NULL;
+ ViewLayer *view_layer;
RenderInfo data;
/* XXX in future, handle multiple windows with multiple screens? */
- current_screen_compat(mainvar, &curscreen, false);
- if (curscreen) {
- curscene = curscreen->scene;
- }
+ current_screen_compat(mainvar, false, &curscreen, &curscene, &view_layer);
for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) {
@@ -1218,6 +1248,37 @@ static void write_userdef(WriteData *wd, const UserDef *userdef)
}
}
+ for (const wmKeyConfigPref *kpt = userdef->user_keyconfig_prefs.first; kpt; kpt = kpt->next) {
+ writestruct(wd, DATA, wmKeyConfigPref, 1, kpt);
+ if (kpt->prop) {
+ IDP_WriteProperty(kpt->prop, wd);
+ }
+ }
+
+ for (const bUserMenu *um = userdef->user_menus.first; um; um = um->next) {
+ writestruct(wd, DATA, bUserMenu, 1, um);
+ for (const bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ const bUserMenuItem_Op *umi_op = (const bUserMenuItem_Op *)umi;
+ writestruct(wd, DATA, bUserMenuItem_Op, 1, umi_op);
+ if (umi_op->prop) {
+ IDP_WriteProperty(umi_op->prop, wd);
+ }
+ }
+ else if (umi->type == USER_MENU_TYPE_MENU) {
+ const bUserMenuItem_Menu *umi_mt = (const bUserMenuItem_Menu *)umi;
+ writestruct(wd, DATA, bUserMenuItem_Menu, 1, umi_mt);
+ }
+ else if (umi->type == USER_MENU_TYPE_PROP) {
+ const bUserMenuItem_Prop *umi_pr = (const bUserMenuItem_Prop *)umi;
+ writestruct(wd, DATA, bUserMenuItem_Prop, 1, umi_pr);
+ }
+ else {
+ writestruct(wd, DATA, bUserMenuItem, 1, umi);
+ }
+ }
+ }
+
for (const bAddon *bext = userdef->addons.first; bext; bext = bext->next) {
writestruct(wd, DATA, bAddon, 1, bext);
if (bext->prop) {
@@ -1354,9 +1415,13 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part)
if (dw->ob != NULL) {
dw->index = 0;
if (part->dup_group) { /* can be NULL if lining fails or set to None */
- for (GroupObject *go = part->dup_group->gobject.first;
- go && go->ob != dw->ob;
- go = go->next, dw->index++);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
+ {
+ if (object != dw->ob) {
+ dw->index++;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
@@ -1433,180 +1498,6 @@ static void write_particlesystems(WriteData *wd, ListBase *particles)
}
}
-static void write_properties(WriteData *wd, ListBase *lb)
-{
- bProperty *prop;
-
- prop = lb->first;
- while (prop) {
- writestruct(wd, DATA, bProperty, 1, prop);
-
- if (prop->poin && prop->poin != &prop->data) {
- writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin);
- }
-
- prop = prop->next;
- }
-}
-
-static void write_sensors(WriteData *wd, ListBase *lb)
-{
- bSensor *sens;
-
- sens = lb->first;
- while (sens) {
- writestruct(wd, DATA, bSensor, 1, sens);
-
- writedata(wd, DATA, sizeof(void *) * sens->totlinks, sens->links);
-
- switch (sens->type) {
- case SENS_NEAR:
- writestruct(wd, DATA, bNearSensor, 1, sens->data);
- break;
- case SENS_MOUSE:
- writestruct(wd, DATA, bMouseSensor, 1, sens->data);
- break;
- case SENS_KEYBOARD:
- writestruct(wd, DATA, bKeyboardSensor, 1, sens->data);
- break;
- case SENS_PROPERTY:
- writestruct(wd, DATA, bPropertySensor, 1, sens->data);
- break;
- case SENS_ARMATURE:
- writestruct(wd, DATA, bArmatureSensor, 1, sens->data);
- break;
- case SENS_ACTUATOR:
- writestruct(wd, DATA, bActuatorSensor, 1, sens->data);
- break;
- case SENS_DELAY:
- writestruct(wd, DATA, bDelaySensor, 1, sens->data);
- break;
- case SENS_COLLISION:
- writestruct(wd, DATA, bCollisionSensor, 1, sens->data);
- break;
- case SENS_RADAR:
- writestruct(wd, DATA, bRadarSensor, 1, sens->data);
- break;
- case SENS_RANDOM:
- writestruct(wd, DATA, bRandomSensor, 1, sens->data);
- break;
- case SENS_RAY:
- writestruct(wd, DATA, bRaySensor, 1, sens->data);
- break;
- case SENS_MESSAGE:
- writestruct(wd, DATA, bMessageSensor, 1, sens->data);
- break;
- case SENS_JOYSTICK:
- writestruct(wd, DATA, bJoystickSensor, 1, sens->data);
- break;
- default:
- ; /* error: don't know how to write this file */
- }
-
- sens = sens->next;
- }
-}
-
-static void write_controllers(WriteData *wd, ListBase *lb)
-{
- bController *cont;
-
- cont = lb->first;
- while (cont) {
- writestruct(wd, DATA, bController, 1, cont);
-
- writedata(wd, DATA, sizeof(void *) * cont->totlinks, cont->links);
-
- switch (cont->type) {
- case CONT_EXPRESSION:
- writestruct(wd, DATA, bExpressionCont, 1, cont->data);
- break;
- case CONT_PYTHON:
- writestruct(wd, DATA, bPythonCont, 1, cont->data);
- break;
- default:
- ; /* error: don't know how to write this file */
- }
-
- cont = cont->next;
- }
-}
-
-static void write_actuators(WriteData *wd, ListBase *lb)
-{
- bActuator *act;
-
- act = lb->first;
- while (act) {
- writestruct(wd, DATA, bActuator, 1, act);
-
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- writestruct(wd, DATA, bActionActuator, 1, act->data);
- break;
- case ACT_SOUND:
- writestruct(wd, DATA, bSoundActuator, 1, act->data);
- break;
- case ACT_OBJECT:
- writestruct(wd, DATA, bObjectActuator, 1, act->data);
- break;
- case ACT_PROPERTY:
- writestruct(wd, DATA, bPropertyActuator, 1, act->data);
- break;
- case ACT_CAMERA:
- writestruct(wd, DATA, bCameraActuator, 1, act->data);
- break;
- case ACT_CONSTRAINT:
- writestruct(wd, DATA, bConstraintActuator, 1, act->data);
- break;
- case ACT_EDIT_OBJECT:
- writestruct(wd, DATA, bEditObjectActuator, 1, act->data);
- break;
- case ACT_SCENE:
- writestruct(wd, DATA, bSceneActuator, 1, act->data);
- break;
- case ACT_GROUP:
- writestruct(wd, DATA, bGroupActuator, 1, act->data);
- break;
- case ACT_RANDOM:
- writestruct(wd, DATA, bRandomActuator, 1, act->data);
- break;
- case ACT_MESSAGE:
- writestruct(wd, DATA, bMessageActuator, 1, act->data);
- break;
- case ACT_GAME:
- writestruct(wd, DATA, bGameActuator, 1, act->data);
- break;
- case ACT_VISIBILITY:
- writestruct(wd, DATA, bVisibilityActuator, 1, act->data);
- break;
- case ACT_2DFILTER:
- writestruct(wd, DATA, bTwoDFilterActuator, 1, act->data);
- break;
- case ACT_PARENT:
- writestruct(wd, DATA, bParentActuator, 1, act->data);
- break;
- case ACT_STATE:
- writestruct(wd, DATA, bStateActuator, 1, act->data);
- break;
- case ACT_ARMATURE:
- writestruct(wd, DATA, bArmatureActuator, 1, act->data);
- break;
- case ACT_STEERING:
- writestruct(wd, DATA, bSteeringActuator, 1, act->data);
- break;
- case ACT_MOUSE:
- writestruct(wd, DATA, bMouseActuator, 1, act->data);
- break;
- default:
- ; /* error: don't know how to write this file */
- }
-
- act = act->next;
- }
-}
-
static void write_motionpath(WriteData *wd, bMotionPath *mpath)
{
/* sanity checks */
@@ -1651,6 +1542,18 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
break;
}
+ case CONSTRAINT_TYPE_ARMATURE:
+ {
+ bArmatureConstraint *data = con->data;
+ bConstraintTarget *ct;
+
+ /* write targets */
+ for (ct = data->targets.first; ct; ct = ct->next) {
+ writestruct(wd, DATA, bConstraintTarget, 1, ct);
+ }
+
+ break;
+ }
case CONSTRAINT_TYPE_SPLINEIK:
{
bSplineIKConstraint *data = con->data;
@@ -1725,6 +1628,13 @@ static void write_defgroups(WriteData *wd, ListBase *defbase)
}
}
+static void write_fmaps(WriteData *wd, ListBase *fbase)
+{
+ for (bFaceMap *fmap = fbase->first; fmap; fmap = fmap->next) {
+ writestruct(wd, DATA, bFaceMap, 1, fmap);
+ }
+}
+
static void write_modifiers(WriteData *wd, ListBase *modbase)
{
ModifierData *md;
@@ -1762,6 +1672,8 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
SmokeModifierData *smd = (SmokeModifierData *)md;
if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
+
if (smd->domain) {
write_pointcaches(wd, &(smd->domain->ptcaches[0]));
@@ -1775,11 +1687,8 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
if (smd->domain->coba) {
writestruct(wd, DATA, ColorBand, 1, smd->domain->coba);
}
- }
- writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
- if (smd->domain) {
/* cleanup the fake pointcache */
BKE_ptcache_free_list(&smd->domain->ptcaches[1]);
smd->domain->point_cache[1] = NULL;
@@ -1900,6 +1809,57 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
}
}
+static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase)
+{
+ GpencilModifierData *md;
+
+ if (modbase == NULL) {
+ return;
+ }
+
+ for (md = modbase->first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ if (mti == NULL) {
+ return;
+ }
+
+ writestruct_id(wd, DATA, mti->struct_name, 1, md);
+
+ if (md->type == eGpencilModifierType_Thick) {
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+
+ if (gpmd->curve_thickness) {
+ write_curvemapping(wd, gpmd->curve_thickness);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Hook) {
+ HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
+
+ if (gpmd->curfalloff) {
+ write_curvemapping(wd, gpmd->curfalloff);
+ }
+ }
+ }
+}
+
+static void write_shaderfxs(WriteData *wd, ListBase *fxbase)
+{
+ ShaderFxData *fx;
+
+ if (fxbase == NULL) {
+ return;
+ }
+
+ for (fx = fxbase->first; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ if (fxi == NULL) {
+ return;
+ }
+
+ writestruct_id(wd, DATA, fxi->struct_name, 1, fx);
+ }
+}
+
static void write_object(WriteData *wd, Object *ob)
{
if (ob->id.us > 0 || wd->use_memfile) {
@@ -1915,10 +1875,6 @@ static void write_object(WriteData *wd, Object *ob)
writedata(wd, DATA, sizeof(void *) * ob->totcol, ob->mat);
writedata(wd, DATA, sizeof(char) * ob->totcol, ob->matbits);
/* write_effects(wd, &ob->effect); */ /* not used anymore */
- write_properties(wd, &ob->prop);
- write_sensors(wd, &ob->sensors);
- write_controllers(wd, &ob->controllers);
- write_actuators(wd, &ob->actuators);
if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
@@ -1929,16 +1885,20 @@ static void write_object(WriteData *wd, Object *ob)
write_pose(wd, ob->pose);
write_defgroups(wd, &ob->defbase);
+ write_fmaps(wd, &ob->fmaps);
write_constraints(wd, &ob->constraints);
write_motionpath(wd, ob->mpath);
writestruct(wd, DATA, PartDeflect, 1, ob->pd);
- writestruct(wd, DATA, SoftBody, 1, ob->soft);
if (ob->soft) {
- write_pointcaches(wd, &ob->soft->ptcaches);
+ /* Set deprecated pointers to prevent crashes of older Blenders */
+ ob->soft->pointcache = ob->soft->shared->pointcache;
+ ob->soft->ptcaches = ob->soft->shared->ptcaches;
+ writestruct(wd, DATA, SoftBody, 1, ob->soft);
+ writestruct(wd, DATA, SoftBody_Shared, 1, ob->soft->shared);
+ write_pointcaches(wd, &(ob->soft->shared->ptcaches));
writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights);
}
- writestruct(wd, DATA, BulletSoftBody, 1, ob->bsoft);
if (ob->rigidbody_object) {
/* TODO: if any extra data is added to handle duplis, will need separate function then */
@@ -1954,6 +1914,8 @@ static void write_object(WriteData *wd, Object *ob)
write_particlesystems(wd, &ob->particlesystem);
write_modifiers(wd, &ob->modifiers);
+ write_gpencil_modifiers(wd, &ob->greasepencil_modifiers);
+ write_shaderfxs(wd, &ob->shader_fx);
writelist(wd, DATA, LinkData, &ob->pc_ids);
writelist(wd, DATA, LodLevel, &ob->lodlevels);
@@ -2011,6 +1973,10 @@ static void write_camera(WriteData *wd, Camera *cam)
if (cam->adt) {
write_animdata(wd, cam->adt);
}
+
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ writestruct(wd, DATA, CameraBGImage, 1, bgpic);
+ }
}
}
@@ -2161,6 +2127,10 @@ static void write_customdata(
else if (layer->type == CD_GRID_PAINT_MASK) {
write_grid_paint_mask(wd, count, layer->data);
}
+ else if (layer->type == CD_FACEMAP) {
+ const int *layer_data = layer->data;
+ writedata(wd, DATA, sizeof(*layer_data) * count, layer_data);
+ }
else {
CustomData_file_write_info(layer->type, &structname, &structnum);
if (structnum) {
@@ -2315,6 +2285,8 @@ static void write_image(WriteData *wd, Image *ima)
writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
ima->packedfile = NULL;
+
+ writelist(wd, DATA, RenderSlot, &ima->renderslots);
}
}
@@ -2333,24 +2305,6 @@ static void write_texture(WriteData *wd, Tex *tex)
if (tex->coba) {
writestruct(wd, DATA, ColorBand, 1, tex->coba);
}
- if (tex->type == TEX_ENVMAP && tex->env) {
- writestruct(wd, DATA, EnvMap, 1, tex->env);
- }
- if (tex->type == TEX_POINTDENSITY && tex->pd) {
- writestruct(wd, DATA, PointDensity, 1, tex->pd);
- if (tex->pd->coba) {
- writestruct(wd, DATA, ColorBand, 1, tex->pd->coba);
- }
- if (tex->pd->falloff_curve) {
- write_curvemapping(wd, tex->pd->falloff_curve);
- }
- }
- if (tex->type == TEX_VOXELDATA) {
- writestruct(wd, DATA, VoxelData, 1, tex->vd);
- }
- if (tex->type == TEX_OCEAN && tex->ot) {
- writestruct(wd, DATA, OceanTex, 1, tex->ot);
- }
/* nodetree is integral part of texture, no libdata */
if (tex->nodetree) {
@@ -2373,19 +2327,6 @@ static void write_material(WriteData *wd, Material *ma)
write_animdata(wd, ma->adt);
}
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, ma->mtex[a]);
- }
- }
-
- if (ma->ramp_col) {
- writestruct(wd, DATA, ColorBand, 1, ma->ramp_col);
- }
- if (ma->ramp_spec) {
- writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec);
- }
-
/* nodetree is integral part of material, no libdata */
if (ma->nodetree) {
writestruct(wd, DATA, bNodeTree, 1, ma->nodetree);
@@ -2393,6 +2334,11 @@ static void write_material(WriteData *wd, Material *ma)
}
write_previews(wd, ma->preview);
+
+ /* grease pencil settings */
+ if (ma->gp_style) {
+ writestruct(wd, DATA, MaterialGPencilStyle, 1, ma->gp_style);
+ }
}
}
@@ -2407,12 +2353,6 @@ static void write_world(WriteData *wd, World *wrld)
write_animdata(wd, wrld->adt);
}
- for (int a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, wrld->mtex[a]);
- }
- }
-
/* nodetree is integral part of world, no libdata */
if (wrld->nodetree) {
writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree);
@@ -2434,13 +2374,6 @@ static void write_lamp(WriteData *wd, Lamp *la)
write_animdata(wd, la->adt);
}
- /* direct data */
- for (int a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a]) {
- writestruct(wd, DATA, MTex, 1, la->mtex[a]);
- }
- }
-
if (la->curfalloff) {
write_curvemapping(wd, la->curfalloff);
}
@@ -2455,6 +2388,31 @@ static void write_lamp(WriteData *wd, Lamp *la)
}
}
+static void write_collection_nolib(WriteData *wd, Collection *collection)
+{
+ /* Shared function for collection datablocks and scene master collection. */
+ write_previews(wd, collection->preview);
+
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ writestruct(wd, DATA, CollectionObject, 1, cob);
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ writestruct(wd, DATA, CollectionChild, 1, child);
+ }
+}
+
+static void write_collection(WriteData *wd, Collection *collection)
+{
+ if (collection->id.us > 0 || wd->use_memfile) {
+ /* write LibData */
+ writestruct(wd, ID_GR, Collection, 1, collection);
+ write_iddata(wd, &collection->id);
+
+ write_collection_nolib(wd, collection);
+ }
+}
+
static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
{
SequenceModifierData *smd;
@@ -2494,6 +2452,65 @@ static void write_paint(WriteData *wd, Paint *p)
if (p->cavity_curve) {
write_curvemapping(wd, p->cavity_curve);
}
+ writedata(wd, DATA, sizeof(PaintToolSlot) * p->tool_slots_len, p->tool_slots);
+}
+
+static void write_layer_collections(WriteData *wd, ListBase *lb)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ writestruct(wd, DATA, LayerCollection, 1, lc);
+
+ write_layer_collections(wd, &lc->layer_collections);
+ }
+}
+
+static void write_view_layer(WriteData *wd, ViewLayer *view_layer)
+{
+ writestruct(wd, DATA, ViewLayer, 1, view_layer);
+ writelist(wd, DATA, Base, &view_layer->object_bases);
+
+ if (view_layer->id_properties) {
+ IDP_WriteProperty(view_layer->id_properties, wd);
+ }
+
+ for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
+ writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
+ }
+
+ for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ writestruct(wd, DATA, FreestyleLineSet, 1, fls);
+ }
+ write_layer_collections(wd, &view_layer->layer_collections);
+}
+
+static void write_lightcache_texture(WriteData *wd, LightCacheTexture *tex)
+{
+ if (tex->data) {
+ size_t data_size = tex->components * tex->tex_size[0] * tex->tex_size[1] * tex->tex_size[2];
+ if (tex->data_type == LIGHTCACHETEX_FLOAT) {
+ data_size *= sizeof(float);
+ }
+ else if (tex->data_type == LIGHTCACHETEX_UINT) {
+ data_size *= sizeof(uint);
+ }
+ writedata(wd, DATA, data_size, tex->data);
+ }
+}
+
+static void write_lightcache(WriteData *wd, LightCache *cache)
+{
+ write_lightcache_texture(wd, &cache->grid_tx);
+ write_lightcache_texture(wd, &cache->cube_tx);
+
+ if (cache->cube_mips) {
+ writestruct(wd, DATA, LightCacheTexture, cache->mips_len, cache->cube_mips);
+ for (int i = 0; i < cache->mips_len; ++i) {
+ write_lightcache_texture(wd, &cache->cube_mips[i]);
+ }
+ }
+
+ writestruct(wd, DATA, LightGridCache, cache->grid_len, cache->grid_data);
+ writestruct(wd, DATA, LightProbeCache, cache->cube_len, cache->cube_data);
}
static void write_scene(WriteData *wd, Scene *sce)
@@ -2508,10 +2525,6 @@ static void write_scene(WriteData *wd, Scene *sce)
write_keyingsets(wd, &sce->keyingsets);
/* direct data */
- for (Base *base = sce->base.first; base; base = base->next) {
- writestruct(wd, DATA, Base, 1, base);
- }
-
ToolSettings *tos = sce->toolsettings;
writestruct(wd, DATA, ToolSettings, 1, tos);
if (tos->vpaint) {
@@ -2530,24 +2543,18 @@ static void write_scene(WriteData *wd, Scene *sce)
writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt);
write_paint(wd, &tos->uvsculpt->paint);
}
- /* write grease-pencil drawing brushes to file */
- writelist(wd, DATA, bGPDbrush, &tos->gp_brushes);
- for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) {
- if (brush->cur_sensitivity) {
- write_curvemapping(wd, brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- write_curvemapping(wd, brush->cur_strength);
- }
- if (brush->cur_jitter) {
- write_curvemapping(wd, brush->cur_jitter);
- }
+ if (tos->gp_paint) {
+ writestruct(wd, DATA, GpPaint, 1, tos->gp_paint);
+ write_paint(wd, &tos->gp_paint->paint);
}
/* write grease-pencil custom ipo curve to file */
if (tos->gp_interpolate.custom_ipo) {
write_curvemapping(wd, tos->gp_interpolate.custom_ipo);
}
-
+ /* write grease-pencil multiframe falloff curve to file */
+ if (tos->gp_sculpt.cur_falloff) {
+ write_curvemapping(wd, tos->gp_sculpt.cur_falloff);
+ }
write_paint(wd, &tos->imapaint.paint);
@@ -2662,19 +2669,6 @@ static void write_scene(WriteData *wd, Scene *sce)
writestruct(wd, DATA, TransformOrientation, 1, ts);
}
- for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) {
- writestruct(wd, DATA, SceneRenderLayer, 1, srl);
- if (srl->prop) {
- IDP_WriteProperty(srl->prop, wd);
- }
- for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
- }
- for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- writestruct(wd, DATA, FreestyleLineSet, 1, fls);
- }
- }
-
/* writing MultiView to the blend file */
for (SceneRenderView *srv = sce->r.views.first; srv; srv = srv->next) {
writestruct(wd, DATA, SceneRenderView, 1, srv);
@@ -2689,13 +2683,36 @@ static void write_scene(WriteData *wd, Scene *sce)
/* writing RigidBodyWorld data to the blend file */
if (sce->rigidbody_world) {
+ /* Set deprecated pointers to prevent crashes of older Blenders */
+ sce->rigidbody_world->pointcache = sce->rigidbody_world->shared->pointcache;
+ sce->rigidbody_world->ptcaches = sce->rigidbody_world->shared->ptcaches;
writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world);
+
+ writestruct(wd, DATA, RigidBodyWorld_Shared, 1, sce->rigidbody_world->shared);
writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights);
- write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
+ write_pointcaches(wd, &(sce->rigidbody_world->shared->ptcaches));
}
write_previews(wd, sce->preview);
write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
+
+ for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ write_view_layer(wd, view_layer);
+ }
+
+ if (sce->master_collection) {
+ writestruct(wd, DATA, Collection, 1, sce->master_collection);
+ write_collection_nolib(wd, sce->master_collection);
+ }
+
+ /* Eevee Lightcache */
+ if (sce->eevee.light_cache && !wd->use_memfile) {
+ writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache);
+ write_lightcache(wd, sce->eevee.light_cache);
+ }
+
+ /* Freed on doversion. */
+ BLI_assert(sce->layer_properties == NULL);
}
static void write_gpencil(WriteData *wd, bGPdata *gpd)
@@ -2709,6 +2726,8 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd)
write_animdata(wd, gpd->adt);
}
+ writedata(wd, DATA, sizeof(void *) * gpd->totcol, gpd->mat);
+
/* write grease-pencil layers to file */
writelist(wd, DATA, bGPDlayer, &gpd->layers);
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
@@ -2719,26 +2738,10 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd)
writelist(wd, DATA, bGPDstroke, &gpf->strokes);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points);
+ write_dverts(wd, gps->totpoints, gps->dvert);
}
}
}
-
- /* write grease-pencil palettes */
- writelist(wd, DATA, bGPDpalette, &gpd->palettes);
- for (bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- writelist(wd, DATA, bGPDpalettecolor, &palette->colors);
- }
- }
-}
-
-static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
-{
- writestruct(wd, ID_WM, wmWindowManager, 1, wm);
- write_iddata(wd, &wm->id);
-
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- writestruct(wd, DATA, wmWindow, 1, win);
- writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
}
}
@@ -2826,167 +2829,210 @@ static void write_soops(WriteData *wd, SpaceOops *so)
}
}
-static void write_screen(WriteData *wd, bScreen *sc)
+static void write_panel_list(WriteData *wd, ListBase *lb)
{
- /* write LibData */
- /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
- writestruct(wd, ID_SCRN, bScreen, 1, sc);
- write_iddata(wd, &sc->id);
-
- /* direct data */
- for (ScrVert *sv = sc->vertbase.first; sv; sv = sv->next) {
- writestruct(wd, DATA, ScrVert, 1, sv);
+ for (Panel *pa = lb->first; pa; pa = pa->next) {
+ writestruct(wd, DATA, Panel, 1, pa);
+ write_panel_list(wd, &pa->children);
}
+}
- for (ScrEdge *se = sc->edgebase.first; se; se = se->next) {
- writestruct(wd, DATA, ScrEdge, 1, se);
- }
+static void write_area_regions(WriteData *wd, ScrArea *area)
+{
+ for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ write_region(wd, region, area->spacetype);
+ write_panel_list(wd, &region->panels);
+
+ for (PanelCategoryStack *pc_act = region->panels_category_active.first; pc_act; pc_act = pc_act->next) {
+ writestruct(wd, DATA, PanelCategoryStack, 1, pc_act);
+ }
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- Panel *pa;
- uiList *ui_list;
- uiPreview *ui_preview;
- PanelCategoryStack *pc_act;
- ARegion *ar;
+ for (uiList *ui_list = region->ui_lists.first; ui_list; ui_list = ui_list->next) {
+ write_uilist(wd, ui_list);
+ }
- writestruct(wd, DATA, ScrArea, 1, sa);
+ for (uiPreview *ui_preview = region->ui_previews.first; ui_preview; ui_preview = ui_preview->next) {
+ writestruct(wd, DATA, uiPreview, 1, ui_preview);
+ }
+ }
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- write_region(wd, ar, sa->spacetype);
+ for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ for (ARegion *region = sl->regionbase.first; region; region = region->next) {
+ write_region(wd, region, sl->spacetype);
+ }
+
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ writestruct(wd, DATA, View3D, 1, v3d);
- for (pa = ar->panels.first; pa; pa = pa->next) {
- writestruct(wd, DATA, Panel, 1, pa);
+ if (v3d->localvd) {
+ writestruct(wd, DATA, View3D, 1, v3d->localvd);
}
- for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) {
- writestruct(wd, DATA, PanelCategoryStack, 1, pc_act);
+ if (v3d->fx_settings.ssao) {
+ writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao);
+ }
+ if (v3d->fx_settings.dof) {
+ writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
}
+ }
+ else if (sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo = (SpaceIpo *)sl;
+ ListBase tmpGhosts = sipo->ghostCurves;
+
+ /* temporarily disable ghost curves when saving */
+ sipo->ghostCurves.first = sipo->ghostCurves.last = NULL;
- for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
- write_uilist(wd, ui_list);
+ writestruct(wd, DATA, SpaceIpo, 1, sl);
+ if (sipo->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, sipo->ads);
}
- for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) {
- writestruct(wd, DATA, uiPreview, 1, ui_preview);
+ /* reenable ghost curves */
+ sipo->ghostCurves = tmpGhosts;
+ }
+ else if (sl->spacetype == SPACE_BUTS) {
+ writestruct(wd, DATA, SpaceButs, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = (SpaceFile *)sl;
+
+ writestruct(wd, DATA, SpaceFile, 1, sl);
+ if (sfile->params) {
+ writestruct(wd, DATA, FileSelectParams, 1, sfile->params);
}
}
+ else if (sl->spacetype == SPACE_SEQ) {
+ writestruct(wd, DATA, SpaceSeq, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOops *so = (SpaceOops *)sl;
+ write_soops(wd, so);
+ }
+ else if (sl->spacetype == SPACE_IMAGE) {
+ writestruct(wd, DATA, SpaceImage, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_TEXT) {
+ writestruct(wd, DATA, SpaceText, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_SCRIPT) {
+ SpaceScript *scr = (SpaceScript *)sl;
+ scr->but_refs = NULL;
+ writestruct(wd, DATA, SpaceScript, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_ACTION) {
+ writestruct(wd, DATA, SpaceAction, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_NLA) {
+ SpaceNla *snla = (SpaceNla *)sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- for (ar = sl->regionbase.first; ar; ar = ar->next) {
- write_region(wd, ar, sl->spacetype);
+ writestruct(wd, DATA, SpaceNla, 1, snla);
+ if (snla->ads) {
+ writestruct(wd, DATA, bDopeSheet, 1, snla->ads);
}
+ }
+ else if (sl->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)sl;
+ bNodeTreePath *path;
+ writestruct(wd, DATA, SpaceNode, 1, snode);
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- BGpic *bgpic;
- writestruct(wd, DATA, View3D, 1, v3d);
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- writestruct(wd, DATA, BGpic, 1, bgpic);
- }
- if (v3d->localvd) {
- writestruct(wd, DATA, View3D, 1, v3d->localvd);
- }
+ for (path = snode->treepath.first; path; path = path->next) {
+ writestruct(wd, DATA, bNodeTreePath, 1, path);
+ }
+ }
+ else if (sl->spacetype == SPACE_CONSOLE) {
+ SpaceConsole *con = (SpaceConsole *)sl;
+ ConsoleLine *cl;
- if (v3d->fx_settings.ssao) {
- writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao);
- }
- if (v3d->fx_settings.dof) {
- writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
- }
+ for (cl = con->history.first; cl; cl = cl->next) {
+ /* 'len_alloc' is invalid on write, set from 'len' on read */
+ writestruct(wd, DATA, ConsoleLine, 1, cl);
+ writedata(wd, DATA, cl->len + 1, cl->line);
}
- else if (sl->spacetype == SPACE_IPO) {
- SpaceIpo *sipo = (SpaceIpo *)sl;
- ListBase tmpGhosts = sipo->ghostCurves;
+ writestruct(wd, DATA, SpaceConsole, 1, sl);
+ }
+#ifdef WITH_GLOBAL_AREA_WRITING
+ else if (sl->spacetype == SPACE_TOPBAR) {
+ writestruct(wd, DATA, SpaceTopBar, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_STATUSBAR) {
+ writestruct(wd, DATA, SpaceStatusBar, 1, sl);
+ }
+#endif
+ else if (sl->spacetype == SPACE_USERPREF) {
+ writestruct(wd, DATA, SpaceUserPref, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_CLIP) {
+ writestruct(wd, DATA, SpaceClip, 1, sl);
+ }
+ else if (sl->spacetype == SPACE_INFO) {
+ writestruct(wd, DATA, SpaceInfo, 1, sl);
+ }
+ }
+}
- /* temporarily disable ghost curves when saving */
- sipo->ghostCurves.first = sipo->ghostCurves.last = NULL;
+static void write_area_map(WriteData *wd, ScrAreaMap *area_map)
+{
+ writelist(wd, DATA, ScrVert, &area_map->vertbase);
+ writelist(wd, DATA, ScrEdge, &area_map->edgebase);
+ for (ScrArea *area = area_map->areabase.first; area; area = area->next) {
+ area->butspacetype = area->spacetype; /* Just for compatibility, will be reset below. */
- writestruct(wd, DATA, SpaceIpo, 1, sl);
- if (sipo->ads) {
- writestruct(wd, DATA, bDopeSheet, 1, sipo->ads);
- }
+ writestruct(wd, DATA, ScrArea, 1, area);
- /* reenable ghost curves */
- sipo->ghostCurves = tmpGhosts;
- }
- else if (sl->spacetype == SPACE_BUTS) {
- writestruct(wd, DATA, SpaceButs, 1, sl);
- }
- else if (sl->spacetype == SPACE_FILE) {
- SpaceFile *sfile = (SpaceFile *)sl;
+#ifdef WITH_GLOBAL_AREA_WRITING
+ writestruct(wd, DATA, ScrGlobalAreaData, 1, area->global);
+#endif
- writestruct(wd, DATA, SpaceFile, 1, sl);
- if (sfile->params) {
- writestruct(wd, DATA, FileSelectParams, 1, sfile->params);
- }
- }
- else if (sl->spacetype == SPACE_SEQ) {
- writestruct(wd, DATA, SpaceSeq, 1, sl);
- }
- else if (sl->spacetype == SPACE_OUTLINER) {
- SpaceOops *so = (SpaceOops *)sl;
- write_soops(wd, so);
- }
- else if (sl->spacetype == SPACE_IMAGE) {
- writestruct(wd, DATA, SpaceImage, 1, sl);
- }
- else if (sl->spacetype == SPACE_TEXT) {
- writestruct(wd, DATA, SpaceText, 1, sl);
- }
- else if (sl->spacetype == SPACE_SCRIPT) {
- SpaceScript *scr = (SpaceScript *)sl;
- scr->but_refs = NULL;
- writestruct(wd, DATA, SpaceScript, 1, sl);
- }
- else if (sl->spacetype == SPACE_ACTION) {
- writestruct(wd, DATA, SpaceAction, 1, sl);
- }
- else if (sl->spacetype == SPACE_NLA) {
- SpaceNla *snla = (SpaceNla *)sl;
+ write_area_regions(wd, area);
- writestruct(wd, DATA, SpaceNla, 1, snla);
- if (snla->ads) {
- writestruct(wd, DATA, bDopeSheet, 1, snla->ads);
- }
- }
- else if (sl->spacetype == SPACE_TIME) {
- writestruct(wd, DATA, SpaceTime, 1, sl);
- }
- else if (sl->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)sl;
- bNodeTreePath *path;
- writestruct(wd, DATA, SpaceNode, 1, snode);
+ area->butspacetype = SPACE_EMPTY; /* Unset again, was changed above. */
+ }
+}
- for (path = snode->treepath.first; path; path = path->next) {
- writestruct(wd, DATA, bNodeTreePath, 1, path);
- }
- }
- else if (sl->spacetype == SPACE_LOGIC) {
- writestruct(wd, DATA, SpaceLogic, 1, sl);
- }
- else if (sl->spacetype == SPACE_CONSOLE) {
- SpaceConsole *con = (SpaceConsole *)sl;
- ConsoleLine *cl;
-
- for (cl = con->history.first; cl; cl = cl->next) {
- /* 'len_alloc' is invalid on write, set from 'len' on read */
- writestruct(wd, DATA, ConsoleLine, 1, cl);
- writedata(wd, DATA, cl->len + 1, cl->line);
- }
- writestruct(wd, DATA, SpaceConsole, 1, sl);
+static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
+{
+ writestruct(wd, ID_WM, wmWindowManager, 1, wm);
+ write_iddata(wd, &wm->id);
- }
- else if (sl->spacetype == SPACE_USERPREF) {
- writestruct(wd, DATA, SpaceUserPref, 1, sl);
- }
- else if (sl->spacetype == SPACE_CLIP) {
- writestruct(wd, DATA, SpaceClip, 1, sl);
- }
- else if (sl->spacetype == SPACE_INFO) {
- writestruct(wd, DATA, SpaceInfo, 1, sl);
- }
- }
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+#ifndef WITH_GLOBAL_AREA_WRITING
+ /* Don't write global areas yet, while we make changes to them. */
+ ScrAreaMap global_areas = win->global_areas;
+ memset(&win->global_areas, 0, sizeof(win->global_areas));
+#endif
+
+ /* update deprecated screen member (for so loading in 2.7x uses the correct screen) */
+ win->screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ writestruct(wd, DATA, wmWindow, 1, win);
+ writestruct(wd, DATA, WorkSpaceInstanceHook, 1, win->workspace_hook);
+ writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
+
+#ifdef WITH_GLOBAL_AREA_WRITING
+ write_area_map(wd, &win->global_areas);
+#else
+ win->global_areas = global_areas;
+#endif
+
+ /* data is written, clear deprecated data again */
+ win->screen = NULL;
+ }
+}
+
+static void write_screen(WriteData *wd, bScreen *sc)
+{
+ /* Screens are reference counted, only saved if used by a workspace. */
+ if (sc->id.us > 0 || wd->use_memfile) {
+ /* write LibData */
+ /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
+ writestruct(wd, ID_SCRN, bScreen, 1, sc);
+ write_iddata(wd, &sc->id);
+
+ write_previews(wd, sc->preview);
+
+ /* direct data */
+ write_area_map(wd, AREAMAP_FROM_SCREEN(sc));
}
}
@@ -3081,17 +3127,15 @@ static void write_sound(WriteData *wd, bSound *sound)
}
}
-static void write_group(WriteData *wd, Group *group)
+static void write_probe(WriteData *wd, LightProbe *prb)
{
- if (group->id.us > 0 || wd->use_memfile) {
+ if (prb->id.us > 0 || wd->use_memfile) {
/* write LibData */
- writestruct(wd, ID_GR, Group, 1, group);
- write_iddata(wd, &group->id);
+ writestruct(wd, ID_LP, LightProbe, 1, prb);
+ write_iddata(wd, &prb->id);
- write_previews(wd, group->preview);
-
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- writestruct(wd, DATA, GroupObject, 1, go);
+ if (prb->adt) {
+ write_animdata(wd, prb->adt);
}
}
}
@@ -3185,6 +3229,20 @@ static void write_brush(WriteData *wd, Brush *brush)
if (brush->curve) {
write_curvemapping(wd, brush->curve);
}
+
+ if (brush->gpencil_settings) {
+ writestruct(wd, DATA, BrushGpencilSettings, 1, brush->gpencil_settings);
+
+ if (brush->gpencil_settings->curve_sensitivity) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_sensitivity);
+ }
+ if (brush->gpencil_settings->curve_strength) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_strength);
+ }
+ if (brush->gpencil_settings->curve_jitter) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_jitter);
+ }
+ }
if (brush->gradient) {
writestruct(wd, DATA, ColorBand, 1, brush->gradient);
}
@@ -3624,6 +3682,22 @@ static void write_cachefile(WriteData *wd, CacheFile *cache_file)
}
}
+static void write_workspace(WriteData *wd, WorkSpace *workspace)
+{
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ writestruct(wd, ID_WS, WorkSpace, 1, workspace);
+ writelist(wd, DATA, WorkSpaceLayout, layouts);
+ writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations);
+ writelist(wd, DATA, wmOwnerID, &workspace->owner_ids);
+ writelist(wd, DATA, bToolRef, &workspace->tools);
+ for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ if (tref->properties) {
+ IDP_WriteProperty(tref->properties, wd);
+ }
+ }
+}
+
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
@@ -3655,6 +3729,8 @@ static void write_libraries(WriteData *wd, Main *main)
/* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the]
* quit.blend and temp saves */
if (found_one) {
+ /* Not overridable. */
+
writestruct(wd, ID_LI, Library, 1, main->curlib);
write_iddata(wd, &main->curlib->id);
@@ -3693,18 +3769,22 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
const bool is_undo = wd->use_memfile;
FileGlobal fg;
bScreen *screen;
+ Scene *scene;
+ ViewLayer *view_layer;
char subvstr[8];
/* prevent mem checkers from complaining */
memset(fg.pad, 0, sizeof(fg.pad));
memset(fg.filename, 0, sizeof(fg.filename));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
+ fg.pad1 = NULL;
- current_screen_compat(mainvar, &screen, is_undo);
+ current_screen_compat(mainvar, is_undo, &screen, &scene, &view_layer);
/* XXX still remap G */
fg.curscreen = screen;
- fg.curscene = screen ? screen->scene : NULL;
+ fg.curscene = scene;
+ fg.cur_view_layer = view_layer;
/* prevent to save this, is not good convention, and feature with concerns... */
fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME);
@@ -3788,131 +3868,159 @@ static bool write_file_handle(
* avoid thumbnail detecting changes because of this. */
mywrite_flush(wd);
- ListBase *lbarray[MAX_LIBARRAY];
- int a = set_listbasepointers(mainvar, lbarray);
- while (a--) {
- ID *id = lbarray[a]->first;
+ OverrideStaticStorage *override_storage = wd->use_memfile ? NULL : BKE_override_static_operations_store_initialize();
- if (id && GS(id->name) == ID_LI) {
- continue; /* Libraries are handled separately below. */
- }
+ /* This outer loop allows to save first datablocks from real mainvar, then the temp ones from override process,
+ * if needed, without duplicating whole code. */
+ Main *bmain = mainvar;
+ do {
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ID *id = lbarray[a]->first;
- for (; id; id = id->next) {
- /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */
- BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0);
+ if (id && GS(id->name) == ID_LI) {
+ continue; /* Libraries are handled separately below. */
+ }
- switch ((ID_Type)GS(id->name)) {
- case ID_WM:
- write_windowmanager(wd, (wmWindowManager *)id);
- break;
- case ID_SCR:
- write_screen(wd, (bScreen *)id);
- break;
- case ID_MC:
- write_movieclip(wd, (MovieClip *)id);
- break;
- case ID_MSK:
- write_mask(wd, (Mask *)id);
- break;
- case ID_SCE:
- write_scene(wd, (Scene *)id);
- break;
- case ID_CU:
- write_curve(wd, (Curve *)id);
- break;
- case ID_MB:
- write_mball(wd, (MetaBall *)id);
- break;
- case ID_IM:
- write_image(wd, (Image *)id);
- break;
- case ID_CA:
- write_camera(wd, (Camera *)id);
- break;
- case ID_LA:
- write_lamp(wd, (Lamp *)id);
- break;
- case ID_LT:
- write_lattice(wd, (Lattice *)id);
- break;
- case ID_VF:
- write_vfont(wd, (VFont *)id);
- break;
- case ID_KE:
- write_key(wd, (Key *)id);
- break;
- case ID_WO:
- write_world(wd, (World *)id);
- break;
- case ID_TXT:
- write_text(wd, (Text *)id);
- break;
- case ID_SPK:
- write_speaker(wd, (Speaker *)id);
- break;
- case ID_SO:
- write_sound(wd, (bSound *)id);
- break;
- case ID_GR:
- write_group(wd, (Group *)id);
- break;
- case ID_AR:
- write_armature(wd, (bArmature *)id);
- break;
- case ID_AC:
- write_action(wd, (bAction *)id);
- break;
- case ID_OB:
- write_object(wd, (Object *)id);
- break;
- case ID_MA:
- write_material(wd, (Material *)id);
- break;
- case ID_TE:
- write_texture(wd, (Tex *)id);
- break;
- case ID_ME:
- write_mesh(wd, (Mesh *)id);
- break;
- case ID_PA:
- write_particlesettings(wd, (ParticleSettings *)id);
- break;
- case ID_NT:
- write_nodetree(wd, (bNodeTree *)id);
- break;
- case ID_BR:
- write_brush(wd, (Brush *)id);
- break;
- case ID_PAL:
- write_palette(wd, (Palette *)id);
- break;
- case ID_PC:
- write_paintcurve(wd, (PaintCurve *)id);
- break;
- case ID_GD:
- write_gpencil(wd, (bGPdata *)id);
- break;
- case ID_LS:
- write_linestyle(wd, (FreestyleLineStyle *)id);
- break;
- case ID_CF:
- write_cachefile(wd, (CacheFile *)id);
- break;
- case ID_LI:
- /* Do nothing, handled below - and should never be reached. */
- BLI_assert(0);
- break;
- case ID_IP:
- /* Do nothing, deprecated. */
- break;
- default:
- /* Should never be reached. */
- BLI_assert(0);
- break;
+ for (; id; id = id->next) {
+ /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */
+ BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0);
+
+ const bool do_override = !ELEM(override_storage, NULL, bmain) && id->override_static;
+
+ if (do_override) {
+ BKE_override_static_operations_store_start(bmain, override_storage, id);
+ }
+
+ switch ((ID_Type)GS(id->name)) {
+ case ID_WM:
+ write_windowmanager(wd, (wmWindowManager *)id);
+ break;
+ case ID_WS:
+ write_workspace(wd, (WorkSpace *)id);
+ break;
+ case ID_SCR:
+ write_screen(wd, (bScreen *)id);
+ break;
+ case ID_MC:
+ write_movieclip(wd, (MovieClip *)id);
+ break;
+ case ID_MSK:
+ write_mask(wd, (Mask *)id);
+ break;
+ case ID_SCE:
+ write_scene(wd, (Scene *)id);
+ break;
+ case ID_CU:
+ write_curve(wd, (Curve *)id);
+ break;
+ case ID_MB:
+ write_mball(wd, (MetaBall *)id);
+ break;
+ case ID_IM:
+ write_image(wd, (Image *)id);
+ break;
+ case ID_CA:
+ write_camera(wd, (Camera *)id);
+ break;
+ case ID_LA:
+ write_lamp(wd, (Lamp *)id);
+ break;
+ case ID_LT:
+ write_lattice(wd, (Lattice *)id);
+ break;
+ case ID_VF:
+ write_vfont(wd, (VFont *)id);
+ break;
+ case ID_KE:
+ write_key(wd, (Key *)id);
+ break;
+ case ID_WO:
+ write_world(wd, (World *)id);
+ break;
+ case ID_TXT:
+ write_text(wd, (Text *)id);
+ break;
+ case ID_SPK:
+ write_speaker(wd, (Speaker *)id);
+ break;
+ case ID_LP:
+ write_probe(wd, (LightProbe *)id);
+ break;
+ case ID_SO:
+ write_sound(wd, (bSound *)id);
+ break;
+ case ID_GR:
+ write_collection(wd, (Collection *)id);
+ break;
+ case ID_AR:
+ write_armature(wd, (bArmature *)id);
+ break;
+ case ID_AC:
+ write_action(wd, (bAction *)id);
+ break;
+ case ID_OB:
+ write_object(wd, (Object *)id);
+ break;
+ case ID_MA:
+ write_material(wd, (Material *)id);
+ break;
+ case ID_TE:
+ write_texture(wd, (Tex *)id);
+ break;
+ case ID_ME:
+ write_mesh(wd, (Mesh *)id);
+ break;
+ case ID_PA:
+ write_particlesettings(wd, (ParticleSettings *)id);
+ break;
+ case ID_NT:
+ write_nodetree(wd, (bNodeTree *)id);
+ break;
+ case ID_BR:
+ write_brush(wd, (Brush *)id);
+ break;
+ case ID_PAL:
+ write_palette(wd, (Palette *)id);
+ break;
+ case ID_PC:
+ write_paintcurve(wd, (PaintCurve *)id);
+ break;
+ case ID_GD:
+ write_gpencil(wd, (bGPdata *)id);
+ break;
+ case ID_LS:
+ write_linestyle(wd, (FreestyleLineStyle *)id);
+ break;
+ case ID_CF:
+ write_cachefile(wd, (CacheFile *)id);
+ break;
+ case ID_LI:
+ /* Do nothing, handled below - and should never be reached. */
+ BLI_assert(0);
+ break;
+ case ID_IP:
+ /* Do nothing, deprecated. */
+ break;
+ default:
+ /* Should never be reached. */
+ BLI_assert(0);
+ break;
+ }
+
+ if (do_override) {
+ BKE_override_static_operations_store_end(override_storage, id);
+ }
}
+
+ mywrite_flush(wd);
}
+ } while ((bmain != override_storage) && (bmain = override_storage));
- mywrite_flush(wd);
+ if (override_storage) {
+ BKE_override_static_operations_store_finalize(override_storage);
+ override_storage = NULL;
}
/* Special handling, operating over split Mains... */
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index e9daf29a94c..cf9e3f6a66d 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -121,10 +121,10 @@ bool BLT_lang_is_ime_supported(void);
#define BLT_I18NCONTEXT_ID_BRUSH "Brush"
#define BLT_I18NCONTEXT_ID_CAMERA "Camera"
#define BLT_I18NCONTEXT_ID_CACHEFILE "CacheFile"
+#define BLT_I18NCONTEXT_ID_COLLECTION "Collection"
#define BLT_I18NCONTEXT_ID_CURVE "Curve"
#define BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle"
#define BLT_I18NCONTEXT_ID_GPENCIL "GPencil"
-#define BLT_I18NCONTEXT_ID_GROUP "Group"
#define BLT_I18NCONTEXT_ID_ID "ID"
#define BLT_I18NCONTEXT_ID_IMAGE "Image"
/*#define BLT_I18NCONTEXT_ID_IPO "Ipo"*/ /* Deprecated */
@@ -140,6 +140,7 @@ bool BLT_lang_is_ime_supported(void);
#define BLT_I18NCONTEXT_ID_PAINTCURVE "PaintCurve"
#define BLT_I18NCONTEXT_ID_PALETTE "Palette"
#define BLT_I18NCONTEXT_ID_PARTICLESETTINGS "ParticleSettings"
+#define BLT_I18NCONTEXT_ID_LIGHTPROBE "LightProbe"
#define BLT_I18NCONTEXT_ID_SCENE "Scene"
#define BLT_I18NCONTEXT_ID_SCREEN "Screen"
#define BLT_I18NCONTEXT_ID_SEQUENCE "Sequence"
@@ -149,6 +150,7 @@ bool BLT_lang_is_ime_supported(void);
#define BLT_I18NCONTEXT_ID_TEXT "Text"
#define BLT_I18NCONTEXT_ID_VFONT "VFont"
#define BLT_I18NCONTEXT_ID_WORLD "World"
+#define BLT_I18NCONTEXT_ID_WORKSPACE "WorkSpace"
#define BLT_I18NCONTEXT_ID_WINDOWMANAGER "WindowManager"
#define BLT_I18NCONTEXT_ID_MOVIECLIP "MovieClip"
#define BLT_I18NCONTEXT_ID_MASK "Mask"
@@ -173,10 +175,10 @@ typedef struct {
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_COLLECTION, "id_collection"), \
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"), \
- BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_GROUP, "id_group"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ID, "id_id"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_IMAGE, "id_image"), \
/*BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_IPO, "id_ipo"),*/ \
@@ -194,6 +196,7 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_PAINTCURVE, "id_paintcurve"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_PALETTE, "id_palette"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_PARTICLESETTINGS, "id_particlesettings"), \
+ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_LIGHTPROBE, "id_lightprobe"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SCENE, "id_scene"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SCREEN, "id_screen"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SEQUENCE, "id_sequence"), \
@@ -203,6 +206,7 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_TEXT, "id_text"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_VFONT, "id_vfont"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WORLD, "id_world"), \
+ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WORKSPACE, "id_workspace"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "id_windowmanager"), \
{NULL, NULL, NULL} \
}
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index f373ca24861..a36fe245a2a 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -157,9 +157,12 @@ static void fill_locales(void)
}
if (id == 0) {
- /* The DEFAULT item... */
+ /* The DEFAULT/Automatic item... */
if (BLI_strnlen(loc, 2)) {
- locales[id] = locales_menu[idx].description = BLI_strdup("");
+ locales[id] = "";
+ /* Keep this tip in sync with the one in rna_userdef (rna_enum_language_default_items). */
+ locales_menu[idx].description = BLI_strdup("Automatically choose system's defined language "
+ "if available, or fall-back to English");
}
/* Menu "label", not to be stored in locales! */
else {
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index bd3eb4cc1ac..e6317762842 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -70,7 +70,6 @@ set(SRC
operators/bmo_primitive.c
operators/bmo_removedoubles.c
operators/bmo_rotate_edges.c
- operators/bmo_similar.c
operators/bmo_smooth_laplacian.c
operators/bmo_split_edges.c
operators/bmo_subdivide.c
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 266b31aaeb3..138b8b7c51f 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -84,7 +84,7 @@
* Edges and Vertices in BMesh are primitive structures.
*
* \note There can be more than one edge between two vertices in BMesh,
- * though the rest of Blender (i.e. DerivedMesh, CDDM, CCGSubSurf, etc) does not support this.
+ * though the rest of Blender (i.e. DNA and evaluated Mesh) does not support this.
* So it should only occur temporarily during editing operations.
*
*
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 10e2892c5a5..70884454ce5 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -38,6 +38,8 @@ struct BMEdge;
struct BMLoop;
struct BMFace;
+struct MLoopNorSpaceArray;
+
struct BLI_mempool;
/* note: it is very important for BMHeader to start with two
@@ -236,6 +238,9 @@ typedef struct BMesh {
struct BLI_mempool *looplistpool;
#endif
+ struct MLoopNorSpaceArray *lnor_spacearr;
+ char spacearr_dirty;
+
/* should be copy of scene select mode */
/* stored in BMEditMesh too, this is a bit confusing,
* make sure they're in sync!
@@ -263,9 +268,33 @@ enum {
BM_FACE = 8
};
+typedef struct BMLoopNorEditData {
+ int loop_index;
+ BMLoop *loop;
+ float niloc[3];
+ float nloc[3];
+ float *loc;
+ short *clnors_data;
+} BMLoopNorEditData;
+
+typedef struct BMLoopNorEditDataArray {
+ BMLoopNorEditData *lnor_editdata;
+ /* This one has full amount of loops, used to map loop index to actual BMLoopNorEditData struct. */
+ BMLoopNorEditData **lidx_to_lnor_editdata;
+
+ int cd_custom_normal_offset;
+ int totloop;
+} BMLoopNorEditDataArray;
+
#define BM_ALL (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)
#define BM_ALL_NOLOOP (BM_VERT | BM_EDGE | BM_FACE)
+enum {
+ BM_SPACEARR_DIRTY = 1 << 0,
+ BM_SPACEARR_DIRTY_ALL = 1 << 1,
+ BM_SPACEARR_BMO_SET = 1 << 2,
+};
+
/* args for _Generic */
#define _BM_GENERIC_TYPE_ELEM_NONCONST \
void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index 97f1bad08b7..bb5199fa0c8 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -36,7 +36,8 @@
#include "BLT_translation.h"
-#include "BKE_DerivedMesh.h"
+#include "DNA_meshdata_types.h"
+
#include "BKE_mesh.h"
#include "bmesh.h"
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 3fe54b7229a..50aa3f08fbc 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -29,7 +29,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_listBase.h"
-#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_linklist_stack.h"
#include "BLI_listbase.h"
@@ -260,6 +260,11 @@ void BM_mesh_data_free(BMesh *bm)
BLI_freelistN(&bm->selected);
+ if (bm->lnor_spacearr) {
+ BKE_lnor_spacearr_free(bm->lnor_spacearr);
+ MEM_freeN(bm->lnor_spacearr);
+ }
+
BMO_error_clear(bm);
}
@@ -313,6 +318,9 @@ void BM_mesh_free(BMesh *bm)
* Helpers for #BM_mesh_normals_update and #BM_verts_calc_normal_vcos
*/
+/* We use that existing internal API flag, assuming no other tool using it would run concurrently to clnors editing. */
+#define BM_LNORSPACE_UPDATE _FLAG_MF
+
typedef struct BMEdgesCalcVectorsData {
/* Read-only data. */
const float (*vcos)[3];
@@ -647,7 +655,8 @@ bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
* Will use first clnors_data array, and fallback to cd_loop_clnors_offset (use NULL and -1 to not use clnors). */
static void bm_mesh_loops_calc_normals(
BMesh *bm, const float (*vcos)[3], const float (*fnos)[3], float (*r_lnos)[3],
- MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2],
+ const int cd_loop_clnors_offset, const bool do_rebuild)
{
BMIter fiter;
BMFace *f_curr;
@@ -703,6 +712,11 @@ static void bm_mesh_loops_calc_normals(
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
do {
+ if (do_rebuild && !BM_ELEM_API_FLAG_TEST(l_curr, BM_LNORSPACE_UPDATE) &&
+ !(bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL))
+ {
+ continue;
+ }
/* A smooth edge, we have to check for cyclic smooth fan case.
* If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as
* 'entry point', otherwise we can skip it. */
@@ -1022,7 +1036,7 @@ void BM_loops_calc_normal_vcos(
BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2],
- const int cd_loop_clnors_offset)
+ const int cd_loop_clnors_offset, const bool do_rebuild)
{
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
@@ -1033,7 +1047,7 @@ void BM_loops_calc_normal_vcos(
/* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
bm_mesh_loops_calc_normals(
- bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
+ bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, do_rebuild);
}
else {
BLI_assert(!r_lnors_spacearr);
@@ -1055,56 +1069,420 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
bm_mesh_edges_sharp_tag(bm, NULL, NULL, NULL, split_angle, true);
}
-static void UNUSED_FUNCTION(bm_mdisps_space_set)(Object *ob, BMesh *bm, int from, int to)
+void BM_lnorspacearr_store(BMesh *bm, float(*r_lnors)[3])
{
- /* switch multires data out of tangent space */
- if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
- BMEditMesh *em = BKE_editmesh_create(bm, false);
- DerivedMesh *dm = CDDM_from_editbmesh(em, true, false);
- MDisps *mdisps;
- BMFace *f;
- BMIter iter;
- // int i = 0; // UNUSED
+ BLI_assert(bm->lnor_spacearr != NULL);
- multires_set_space(dm, ob, from, to);
+ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL);
+ }
- mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
+ int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l;
- BMIter liter;
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- MDisps *lmd = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MDISPS);
+ BM_loops_calc_normal_vcos(
+ bm, NULL, NULL, NULL, true, M_PI, r_lnors, bm->lnor_spacearr, NULL, cd_loop_clnors_offset, false);
+ bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
+}
+
+#define CLEAR_SPACEARRAY_THRESHOLD(x) ((x) / 2)
+
+void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all)
+{
+ if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
+ return;
+ }
+ if (do_invalidate_all || bm->totvertsel > CLEAR_SPACEARRAY_THRESHOLD(bm->totvert)) {
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ return;
+ }
+ if (bm->lnor_spacearr == NULL) {
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ return;
+ }
+
+ BMVert *v;
+ BMLoop *l;
+ BMIter viter, liter;
+ /* Note: we could use temp tag of BMItem for that, but probably better not use it in such a low-level func?
+ * --mont29 */
+ BLI_bitmap *done_verts = BLI_BITMAP_NEW(bm->totvert, __func__);
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ /* When we affect a given vertex, we may affect following smooth fans:
+ * - all smooth fans of said vertex;
+ * - all smooth fans of all immediate loop-neighbors vertices;
+ * This can be simplified as 'all loops of selected vertices and their immediate neighbors'
+ * need to be tagged for update.
+ */
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+ BM_ELEM_API_FLAG_ENABLE(l, BM_LNORSPACE_UPDATE);
+
+ /* Note that we only handle unselected neighbor vertices here, main loop will take care of
+ * selected ones. */
+ if ((!BM_elem_flag_test(l->prev->v, BM_ELEM_SELECT)) &&
+ !BLI_BITMAP_TEST(done_verts, BM_elem_index_get(l->prev->v)))
+ {
+
+ BMLoop *l_prev;
+ BMIter liter_prev;
+ BM_ITER_ELEM(l_prev, &liter_prev, l->prev->v, BM_LOOPS_OF_VERT) {
+ BM_ELEM_API_FLAG_ENABLE(l_prev, BM_LNORSPACE_UPDATE);
+ }
+ BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(l_prev->v));
+ }
+
+ if ((!BM_elem_flag_test(l->next->v, BM_ELEM_SELECT)) &&
+ !BLI_BITMAP_TEST(done_verts, BM_elem_index_get(l->next->v)))
+ {
+
+ BMLoop *l_next;
+ BMIter liter_next;
+ BM_ITER_ELEM(l_next, &liter_next, l->next->v, BM_LOOPS_OF_VERT) {
+ BM_ELEM_API_FLAG_ENABLE(l_next, BM_LNORSPACE_UPDATE);
+ }
+ BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(l_next->v));
+ }
+ }
+
+ BLI_BITMAP_ENABLE(done_verts, BM_elem_index_get(v));
+ }
+ }
+
+ MEM_freeN(done_verts);
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY;
+}
+
+void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
+{
+ BLI_assert(bm->lnor_spacearr != NULL);
+
+ if (!(bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL))) {
+ return;
+ }
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+
+ float(*r_lnors)[3] = MEM_callocN(sizeof(*r_lnors) * bm->totloop, __func__);
+ float(*oldnors)[3] = preserve_clnor ? MEM_mallocN(sizeof(*oldnors) * bm->totloop, __func__) : NULL;
+
+ int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ if (preserve_clnor) {
+ BLI_assert(bm->lnor_spacearr->lspacearr != NULL);
+
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
+ short(*clnor)[2] = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset);
+ int l_index = BM_elem_index_get(l);
+
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[l_index], *clnor,
+ oldnors[l_index]);
+ }
+ }
+ }
+ }
- if (!lmd->disps) {
- printf("%s: warning - 'lmd->disps' == NULL\n", __func__);
+ if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
+ BKE_lnor_spacearr_clear(bm->lnor_spacearr);
+ }
+ BM_loops_calc_normal_vcos(
+ bm, NULL, NULL, NULL, true, M_PI, r_lnors, bm->lnor_spacearr, NULL, cd_loop_clnors_offset, true);
+ MEM_freeN(r_lnors);
+
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (BM_ELEM_API_FLAG_TEST(l, BM_LNORSPACE_UPDATE) || bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
+ if (preserve_clnor) {
+ short(*clnor)[2] = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset);
+ int l_index = BM_elem_index_get(l);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], oldnors[l_index],
+ *clnor);
}
+ BM_ELEM_API_FLAG_DISABLE(l, BM_LNORSPACE_UPDATE);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(oldnors);
+ bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
+
+#ifndef NDEBUG
+ BM_lnorspace_err(bm);
+#endif
+}
+
+void BM_lnorspace_update(BMesh *bm)
+{
+ if (bm->lnor_spacearr == NULL) {
+ bm->lnor_spacearr = MEM_callocN(sizeof(*bm->lnor_spacearr), __func__);
+ }
+ if (bm->lnor_spacearr->lspacearr == NULL) {
+ float(*lnors)[3] = MEM_callocN(sizeof(*lnors) * bm->totloop, __func__);
+
+ BM_lnorspacearr_store(bm, lnors);
+
+ MEM_freeN(lnors);
+ }
+ else if (bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL)) {
+ BM_lnorspace_rebuild(bm, false);
+ }
+}
+
+void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges)
+{
+ BMFace *f;
+ BMEdge *e;
+ BMIter fiter, eiter;
+ BMLoop *l_curr, *l_first;
+
+ if (do_edges) {
+ int index_edge;
+ BM_ITER_MESH_INDEX(e, &eiter, bm, BM_EDGES_OF_MESH, index_edge) {
+ BMLoop *l_a, *l_b;
+
+ BM_elem_index_set(e, index_edge); /* set_inline */
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
+ if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && l_a->v != l_b->v) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ }
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+ }
+
+ int index_face, index_loop = 0;
+ BM_ITER_MESH_INDEX(f, &fiter, bm, BM_FACES_OF_MESH, index_face) {
+ BM_elem_index_set(f, index_face); /* set_inline */
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_elem_index_set(l_curr, index_loop++); /* set_inline */
+ BM_elem_flag_disable(l_curr, BM_ELEM_TAG);
+ } while ((l_curr = l_curr->next) != l_first);
+ }
+ bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
+}
+
+/**
+ * Auxillary function only used by rebuild to detect if any spaces were not marked as invalid.
+ * Reports error if any of the lnor spaces change after rebuilding, meaning that all the possible
+ * lnor spaces to be rebuilt were not correctly marked.
+ */
+#ifndef NDEBUG
+void BM_lnorspace_err(BMesh *bm)
+{
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ bool clear = true;
- if (lmd->disps && lmd->totdisp == mdisps->totdisp) {
- memcpy(lmd->disps, mdisps->disps, sizeof(float) * 3 * lmd->totdisp);
+ MLoopNorSpaceArray *temp = MEM_callocN(sizeof(*temp), __func__);
+ temp->lspacearr = NULL;
+
+ BKE_lnor_spacearr_init(temp, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR);
+
+ int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ float(*lnors)[3] = MEM_callocN(sizeof(*lnors) * bm->totloop, __func__);
+ BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, M_PI, lnors, temp, NULL, cd_loop_clnors_offset, true);
+
+ for (int i = 0; i < bm->totloop; i++) {
+ int j = 0;
+ j += compare_ff(temp->lspacearr[i]->ref_alpha, bm->lnor_spacearr->lspacearr[i]->ref_alpha, 1e-4f);
+ j += compare_ff(temp->lspacearr[i]->ref_beta, bm->lnor_spacearr->lspacearr[i]->ref_beta, 1e-4f);
+ j += compare_v3v3(temp->lspacearr[i]->vec_lnor, bm->lnor_spacearr->lspacearr[i]->vec_lnor, 1e-4f);
+ j += compare_v3v3(temp->lspacearr[i]->vec_ortho, bm->lnor_spacearr->lspacearr[i]->vec_ortho, 1e-4f);
+ j += compare_v3v3(temp->lspacearr[i]->vec_ref, bm->lnor_spacearr->lspacearr[i]->vec_ref, 1e-4f);
+
+ if (j != 5) {
+ clear = false;
+ break;
+ }
+ }
+ BKE_lnor_spacearr_free(temp);
+ MEM_freeN(temp);
+ MEM_freeN(lnors);
+ BLI_assert(clear);
+
+ bm->spacearr_dirty &= ~BM_SPACEARR_DIRTY_ALL;
+}
+#endif
+
+static void bm_loop_normal_mark_indiv_do_loop(
+ BMLoop *l, BLI_bitmap *loops, MLoopNorSpaceArray *lnor_spacearr, int *totloopsel)
+{
+ if (l != NULL) {
+ const int l_idx = BM_elem_index_get(l);
+
+ if (!BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) {
+ /* If vert and face selected share a loop, mark it for editing. */
+ BLI_BITMAP_ENABLE(loops, l_idx);
+ (*totloopsel)++;
+
+ /* Mark all loops in same loop normal space (aka smooth fan). */
+ if ((lnor_spacearr->lspacearr[l_idx]->flags & MLNOR_SPACE_IS_SINGLE) == 0) {
+ for (LinkNode *node = lnor_spacearr->lspacearr[l_idx]->loops; node; node = node->next) {
+ const int lfan_idx = BM_elem_index_get((BMLoop *)node->link);
+ if (!BLI_BITMAP_TEST(loops, lfan_idx)) {
+ BLI_BITMAP_ENABLE(loops, lfan_idx);
+ (*totloopsel)++;
+ }
}
- else if (mdisps->disps) {
- if (lmd->disps)
- MEM_freeN(lmd->disps);
+ }
+ }
+ }
+}
- lmd->disps = MEM_dupallocN(mdisps->disps);
- lmd->totdisp = mdisps->totdisp;
- lmd->level = mdisps->level;
+/* Mark the individual clnors to be edited, if multiple selection methods are used. */
+static int bm_loop_normal_mark_indiv(BMesh *bm, BLI_bitmap *loops)
+{
+ BMEditSelection *ese, *ese_prev;
+ int totloopsel = 0;
+
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ BLI_assert(bm->lnor_spacearr != NULL);
+ BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR);
+
+ /* Goes from last selected to the first selected element. */
+ for (ese = bm->selected.last; ese; ese = ese->prev) {
+ if (ese->htype == BM_FACE) {
+ ese_prev = ese;
+ /* If current face is selected, then any verts to be edited must have been selected before it. */
+ while ((ese_prev = ese_prev->prev)) {
+ if (ese_prev->htype == BM_VERT) {
+ bm_loop_normal_mark_indiv_do_loop(
+ BM_face_vert_share_loop((BMFace *)ese->ele, (BMVert *)ese_prev->ele),
+ loops, bm->lnor_spacearr, &totloopsel);
}
+ else if (ese_prev->htype == BM_EDGE) {
+ bm_loop_normal_mark_indiv_do_loop(
+ BM_face_vert_share_loop((BMFace *)ese->ele, ((BMEdge *)ese_prev->ele)->v1),
+ loops, bm->lnor_spacearr, &totloopsel);
+
+ bm_loop_normal_mark_indiv_do_loop(
+ BM_face_vert_share_loop((BMFace *)ese->ele, ((BMEdge *)ese_prev->ele)->v2),
+ loops, bm->lnor_spacearr, &totloopsel);
+ }
+ }
+ }
+ }
+
+ return totloopsel;
+}
+
+static void loop_normal_editdata_init(BMesh *bm, BMLoopNorEditData *lnor_ed, BMVert *v, BMLoop *l, const int offset)
+{
+ BLI_assert(bm->lnor_spacearr != NULL);
+ BLI_assert(bm->lnor_spacearr->lspacearr != NULL);
+
+ const int l_index = BM_elem_index_get(l);
+ short *clnors_data = BM_ELEM_CD_GET_VOID_P(l, offset);
+
+ lnor_ed->loop_index = l_index;
+ lnor_ed->loop = l;
+
+ float custom_normal[3];
+ BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], clnors_data, custom_normal);
+
+ lnor_ed->clnors_data = clnors_data;
+ copy_v3_v3(lnor_ed->nloc, custom_normal);
+ copy_v3_v3(lnor_ed->niloc, custom_normal);
+
+ lnor_ed->loc = v->co;
+}
+
+BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm)
+{
+ BMLoop *l;
+ BMVert *v;
+ BMIter liter, viter;
+
+ bool verts = (bm->selectmode & SCE_SELECT_VERTEX) != 0;
+ bool edges = (bm->selectmode & SCE_SELECT_EDGE) != 0;
+ bool faces = (bm->selectmode & SCE_SELECT_FACE) != 0;
+ int totloopsel = 0;
+
+ BLI_assert(bm->spacearr_dirty == 0);
+
+ BMLoopNorEditDataArray *lnors_ed_arr = MEM_mallocN(
+ sizeof(*lnors_ed_arr), __func__);
+ lnors_ed_arr->lidx_to_lnor_editdata = MEM_callocN(
+ sizeof(*lnors_ed_arr->lidx_to_lnor_editdata) * bm->totloop, __func__);
+
+ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL);
+ }
+ const int cd_custom_normal_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ BLI_bitmap *loops = BLI_BITMAP_NEW(bm->totloop, __func__);
+ if (faces && (verts || edges)) {
+ /* More than one selection mode, check for individual normals to edit. */
+ totloopsel = bm_loop_normal_mark_indiv(bm, loops);
+ }
- mdisps++;
- // i += 1;
+ if (totloopsel) {
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = MEM_mallocN(sizeof(*lnor_ed) * totloopsel, __func__);
+
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+ if (BLI_BITMAP_TEST(loops, BM_elem_index_get(l))) {
+ loop_normal_editdata_init(bm, lnor_ed, v, l, cd_custom_normal_offset);
+ lnors_ed_arr->lidx_to_lnor_editdata[BM_elem_index_get(l)] = lnor_ed;
+ lnor_ed++;
+ }
+ }
+ }
+ lnors_ed_arr->totloop = totloopsel;
+ }
+ else { /* If multiple selection modes are inactive OR no such loop is found, fall back to editing all loops. */
+ totloopsel = BM_total_loop_select(bm);
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata = MEM_mallocN(sizeof(*lnor_ed) * totloopsel, __func__);
+
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+ loop_normal_editdata_init(bm, lnor_ed, v, l, cd_custom_normal_offset);
+ lnors_ed_arr->lidx_to_lnor_editdata[BM_elem_index_get(l)] = lnor_ed;
+ lnor_ed++;
+ }
}
}
+ lnors_ed_arr->totloop = totloopsel;
+ }
- dm->needsFree = 1;
- dm->release(dm);
+ MEM_freeN(loops);
+ lnors_ed_arr->cd_custom_normal_offset = cd_custom_normal_offset;
+ return lnors_ed_arr;
+}
- /* setting this to NULL prevents BKE_editmesh_free from freeing it */
- em->bm = NULL;
- BKE_editmesh_free(em);
- MEM_freeN(em);
+void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
+{
+ MEM_SAFE_FREE(lnors_ed_arr->lnor_editdata);
+ MEM_SAFE_FREE(lnors_ed_arr->lidx_to_lnor_editdata);
+ MEM_freeN(lnors_ed_arr);
+}
+
+int BM_total_loop_select(BMesh *bm)
+{
+ int r_sel = 0;
+ BMVert *v;
+ BMIter viter;
+
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ r_sel += BM_vert_face_count(v);
+ }
}
+ return r_sel;
}
/**
@@ -1155,6 +1533,7 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
/* compute normals, clear temp flags and flush selections */
if (type_flag & BMO_OPTYPE_FLAG_NORMALS_CALC) {
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
BM_mesh_normals_update(bm);
}
@@ -1171,30 +1550,36 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) {
bm->selected = select_history;
}
+ if (type_flag & BMO_OPTYPE_FLAG_INVALIDATE_CLNOR_ALL) {
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ }
}
-void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
+void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4])
{
- const char htype_needed = bm->elem_index_dirty & htype;
#ifdef DEBUG
BM_ELEM_INDEX_VALIDATE(bm, "Should Never Fail!", __func__);
#endif
- if (0 && htype_needed == 0) {
- goto finally;
+ if (elem_offset == NULL) {
+ /* Simple case. */
+ const char htype_needed = bm->elem_index_dirty & htype;
+ if (htype_needed == 0) {
+ goto finally;
+ }
}
if (htype & BM_VERT) {
- if (bm->elem_index_dirty & BM_VERT) {
+ if ((bm->elem_index_dirty & BM_VERT) || (elem_offset && elem_offset[0])) {
BMIter iter;
BMElem *ele;
- int index;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, index) {
- BM_elem_index_set(ele, index); /* set_ok */
+ int index = elem_offset ? elem_offset[0] : 0;
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_index_set(ele, index++); /* set_ok */
}
- BLI_assert(index == bm->totvert);
+ BLI_assert(elem_offset || index == bm->totvert);
}
else {
// printf("%s: skipping vert index calc!\n", __func__);
@@ -1202,15 +1587,15 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
if (htype & BM_EDGE) {
- if (bm->elem_index_dirty & BM_EDGE) {
+ if ((bm->elem_index_dirty & BM_EDGE) || (elem_offset && elem_offset[1])) {
BMIter iter;
BMElem *ele;
- int index;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, index) {
- BM_elem_index_set(ele, index); /* set_ok */
+ int index = elem_offset ? elem_offset[1] : 0;
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_index_set(ele, index++); /* set_ok */
}
- BLI_assert(index == bm->totedge);
+ BLI_assert(elem_offset || index == bm->totedge);
}
else {
// printf("%s: skipping edge index calc!\n", __func__);
@@ -1218,19 +1603,19 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
if (htype & (BM_FACE | BM_LOOP)) {
- if (bm->elem_index_dirty & (BM_FACE | BM_LOOP)) {
+ if ((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) || (elem_offset && (elem_offset[2] || elem_offset[3]))) {
BMIter iter;
BMElem *ele;
const bool update_face = (htype & BM_FACE) && (bm->elem_index_dirty & BM_FACE);
const bool update_loop = (htype & BM_LOOP) && (bm->elem_index_dirty & BM_LOOP);
- int index;
- int index_loop = 0;
+ int index_loop = elem_offset ? elem_offset[2] : 0;
+ int index = elem_offset ? elem_offset[3] : 0;
- BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, index) {
+ BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
if (update_face) {
- BM_elem_index_set(ele, index); /* set_ok */
+ BM_elem_index_set(ele, index++); /* set_ok */
}
if (update_loop) {
@@ -1243,9 +1628,9 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
}
}
- BLI_assert(index == bm->totface);
+ BLI_assert(elem_offset || !update_face || index == bm->totface);
if (update_loop) {
- BLI_assert(index_loop == bm->totloop);
+ BLI_assert(elem_offset || !update_loop || index_loop == bm->totloop);
}
}
else {
@@ -1255,6 +1640,37 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
finally:
bm->elem_index_dirty &= ~htype;
+ if (elem_offset) {
+ if (htype & BM_VERT) {
+ elem_offset[0] += bm->totvert;
+ if (elem_offset[0] != bm->totvert) {
+ bm->elem_index_dirty |= BM_VERT;
+ }
+ }
+ if (htype & BM_EDGE) {
+ elem_offset[1] += bm->totedge;
+ if (elem_offset[1] != bm->totedge) {
+ bm->elem_index_dirty |= BM_EDGE;
+ }
+ }
+ if (htype & BM_LOOP) {
+ elem_offset[2] += bm->totloop;
+ if (elem_offset[2] != bm->totloop) {
+ bm->elem_index_dirty |= BM_LOOP;
+ }
+ }
+ if (htype & BM_FACE) {
+ elem_offset[3] += bm->totface;
+ if (elem_offset[3] != bm->totface) {
+ bm->elem_index_dirty |= BM_FACE;
+ }
+ }
+ }
+}
+
+void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
+{
+ BM_mesh_elem_index_ensure_ex(bm, htype, NULL);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index cc056e1fa19..dfd76c6b89f 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -29,6 +29,7 @@
struct BMAllocTemplate;
struct MLoopNorSpaceArray;
+struct BMLoopNorEditDataArray;
void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
@@ -50,10 +51,23 @@ void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*
void BM_loops_calc_normal_vcos(
BMesh *bm, const float(*vcos)[3], const float(*vnos)[3], const float(*pnos)[3],
const bool use_split_normals, const float split_angle, float(*r_lnos)[3],
- struct MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2],
- const int cd_loop_clnors_offset);
+ struct MLoopNorSpaceArray *r_lnors_spacearr, short(*clnors_data)[2],
+ const int cd_loop_clnors_offset, const bool do_rebuild);
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
+void BM_lnorspacearr_store(BMesh *bm, float(*r_lnors)[3]);
+void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all);
+void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor);
+void BM_lnorspace_update(BMesh *bm);
+void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges);
+#ifndef NDEBUG
+void BM_lnorspace_err(BMesh *bm);
+#endif
+
+/* Loop Generics */
+struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm);
+void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
+int BM_total_loop_select(BMesh *bm);
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
@@ -61,6 +75,7 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
+void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4]);
void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag);
void BM_mesh_elem_index_validate(
BMesh *bm, const char *location, const char *func,
@@ -126,25 +141,22 @@ extern const BMAllocTemplate bm_mesh_chunksize_default;
#define BMALLOC_TEMPLATE_FROM_BM(bm) { (CHECK_TYPE_INLINE(bm, BMesh *), \
(bm)->totvert), (bm)->totedge, (bm)->totloop, (bm)->totface}
-#define BMALLOC_TEMPLATE_FROM_ME(me) { (CHECK_TYPE_INLINE(me, Mesh *), \
- (me)->totvert), (me)->totedge, (me)->totloop, (me)->totpoly}
-
-#define _VA_BMALLOC_TEMPLATE_FROM_DM_1(dm) { \
- (CHECK_TYPE_INLINE(dm, DerivedMesh *), \
- (dm)->getNumVerts(dm)), \
- (dm)->getNumEdges(dm), \
- (dm)->getNumLoops(dm), \
- (dm)->getNumPolys(dm), \
+
+#define _VA_BMALLOC_TEMPLATE_FROM_ME_1(me) { \
+ (CHECK_TYPE_INLINE(me, Mesh *), \
+ (me)->totvert), \
+ (me)->totedge, \
+ (me)->totloop, \
+ (me)->totpoly, \
}
-#define _VA_BMALLOC_TEMPLATE_FROM_DM_2(dm_a, dm_b) { \
- (CHECK_TYPE_INLINE(dm_a, DerivedMesh *), \
- CHECK_TYPE_INLINE(dm_b, DerivedMesh *), \
- (dm_a)->getNumVerts(dm_a)) + (dm_b)->getNumVerts(dm_b), \
- (dm_a)->getNumEdges(dm_a) + (dm_b)->getNumEdges(dm_b), \
- (dm_a)->getNumLoops(dm_a) + (dm_b)->getNumLoops(dm_b), \
- (dm_a)->getNumPolys(dm_a) + (dm_b)->getNumPolys(dm_b), \
+#define _VA_BMALLOC_TEMPLATE_FROM_ME_2(me_a, me_b) { \
+ (CHECK_TYPE_INLINE(me_a, Mesh *), \
+ CHECK_TYPE_INLINE(me_b, Mesh *), \
+ (me_a)->totvert + (me_b)->totvert), \
+ (me_a)->totedge + (me_b)->totedge, \
+ (me_a)->totloop + (me_b)->totloop, \
+ (me_a)->totpoly + (me_b)->totpoly, \
}
-
-#define BMALLOC_TEMPLATE_FROM_DM(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_DM_, __VA_ARGS__)
+#define BMALLOC_TEMPLATE_FROM_ME(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_ME_, __VA_ARGS__)
#endif /* __BMESH_MESH_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 2259a7dfe09..e7ee1d45dc3 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -88,6 +88,7 @@
#include "BLI_math_vector.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_customdata.h"
#include "BKE_multires.h"
@@ -98,42 +99,6 @@
#include "bmesh.h"
#include "intern/bmesh_private.h" /* for element checking */
-/**
- * Currently this is only used for Python scripts
- * which may fail to keep matching UV/TexFace layers.
- *
- * \note This should only perform any changes in exceptional cases,
- * if we need this to be faster we could inline #BM_data_layer_add and only
- * call #update_data_blocks once at the end.
- */
-void BM_mesh_cd_validate(BMesh *bm)
-{
- int totlayer_mtex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
- int totlayer_uv = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
-
- if (LIKELY(totlayer_mtex == totlayer_uv)) {
- /* pass */
- }
- else if (totlayer_mtex < totlayer_uv) {
- const int uv_index_first = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
- do {
- const char *from_name = bm->ldata.layers[uv_index_first + totlayer_mtex].name;
- BM_data_layer_add_named(bm, &bm->pdata, CD_MTEXPOLY, from_name);
- CustomData_set_layer_unique_name(&bm->pdata, totlayer_mtex);
- } while (totlayer_uv != ++totlayer_mtex);
- }
- else if (totlayer_uv < totlayer_mtex) {
- const int mtex_index_first = CustomData_get_layer_index(&bm->pdata, CD_MTEXPOLY);
- do {
- const char *from_name = bm->pdata.layers[mtex_index_first + totlayer_uv].name;
- BM_data_layer_add_named(bm, &bm->ldata, CD_MLOOPUV, from_name);
- CustomData_set_layer_unique_name(&bm->ldata, totlayer_uv);
- } while (totlayer_mtex != ++totlayer_uv);
- }
-
- BLI_assert(totlayer_mtex == totlayer_uv);
-}
-
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
{
const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag;
@@ -228,7 +193,7 @@ static BMFace *bm_face_create_from_mpoly(
* \warning This function doesn't calculate face normals.
*/
void BM_mesh_bm_from_me(
- BMesh *bm, Mesh *me,
+ BMesh *bm, const Mesh *me,
const struct BMeshFromMeshParams *params)
{
const bool is_new =
@@ -243,14 +208,16 @@ void BM_mesh_bm_from_me(
BMEdge *e, **etable = NULL;
BMFace *f, **ftable = NULL;
float (*keyco)[3] = NULL;
- int totuv, totloops, i;
+ int totloops, i;
+ const int64_t mask = CD_MASK_BMESH | params->cd_mask_extra;
+ const int64_t mask_loop_only = mask & ~CD_MASK_ORIGINDEX;
if (!me || !me->totvert) {
if (me && is_new) { /*no verts? still copy customdata layout*/
- CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0);
- CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0);
- CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0);
- CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_ASSIGN, 0);
+ CustomData_copy(&me->vdata, &bm->vdata, mask, CD_ASSIGN, 0);
+ CustomData_copy(&me->edata, &bm->edata, mask, CD_ASSIGN, 0);
+ CustomData_copy(&me->ldata, &bm->ldata, mask_loop_only, CD_ASSIGN, 0);
+ CustomData_copy(&me->pdata, &bm->pdata, mask, CD_ASSIGN, 0);
CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
@@ -261,17 +228,10 @@ void BM_mesh_bm_from_me(
}
if (is_new) {
- CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
- CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
-
- /* make sure uv layer names are consisten */
- totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
- for (i = 0; i < totuv; i++) {
- int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
- CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
- }
+ CustomData_copy(&me->vdata, &bm->vdata, mask, CD_CALLOC, 0);
+ CustomData_copy(&me->edata, &bm->edata, mask, CD_CALLOC, 0);
+ CustomData_copy(&me->ldata, &bm->ldata, mask_loop_only, CD_CALLOC, 0);
+ CustomData_copy(&me->pdata, &bm->pdata, mask, CD_CALLOC, 0);
}
/* -------------------------------------------------------------------- */
@@ -984,4 +944,156 @@ void BM_mesh_bm_to_me(
/* topology could be changed, ensure mdisps are ok */
multires_topology_changed(me);
+
+ /* to be removed as soon as COW is enabled by default. */
+ BKE_mesh_runtime_clear_geometry(me);
+}
+
+/**
+ * A version of #BM_mesh_bm_to_me intended for getting the mesh to pass to the modifier stack for evaluation,
+ * instad of mode switching (where we make sure all data is kept and do expensive lookups to maintain shape keys).
+ *
+ * Key differences:
+ *
+ * - Don't support merging with existing mesh.
+ * - Ignore shape-keys.
+ * - Ignore vertex-parents.
+ * - Ignore selection history.
+ * - Uses simpler method to calculate #ME_EDGEDRAW
+ * - Uses #CD_MASK_DERIVEDMESH instead of #CD_MASK_MESH.
+ *
+ * \note Was `cddm_from_bmesh_ex` in 2.7x, removed `MFace` support.
+ */
+void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const int64_t cd_mask_extra)
+{
+ /* must be an empty mesh. */
+ BLI_assert(me->totvert == 0);
+ BLI_assert((cd_mask_extra & CD_MASK_SHAPEKEY) == 0);
+
+ me->totvert = bm->totvert;
+ me->totedge = bm->totedge;
+ me->totface = 0;
+ me->totloop = bm->totloop;
+ me->totpoly = bm->totface;
+
+ CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totvert);
+ CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totedge);
+ CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totface);
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, bm->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, bm->totedge);
+ CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, bm->totloop);
+ CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, bm->totface);
+
+ /* don't process shapekeys, we only feed them through the modifier stack as needed,
+ * e.g. for applying modifiers or the like*/
+ const CustomDataMask mask = (CD_MASK_DERIVEDMESH | cd_mask_extra) & ~CD_MASK_SHAPEKEY;
+ CustomData_merge(&bm->vdata, &me->vdata, mask, CD_CALLOC, me->totvert);
+ CustomData_merge(&bm->edata, &me->edata, mask, CD_CALLOC, me->totedge);
+ CustomData_merge(&bm->ldata, &me->ldata, mask, CD_CALLOC, me->totloop);
+ CustomData_merge(&bm->pdata, &me->pdata, mask, CD_CALLOC, me->totpoly);
+
+ BKE_mesh_update_customdata_pointers(me, false);
+
+ BMIter iter;
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ MVert *mvert = me->mvert;
+ MEdge *medge = me->medge;
+ MLoop *mloop = me->mloop;
+ MPoly *mpoly = me->mpoly;
+ int *index, add_orig;
+ unsigned int i, j;
+
+ const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+ const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+
+ me->runtime.deformed_only = true;
+
+ /* don't add origindex layer if one already exists */
+ add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
+
+ index = CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ MVert *mv = &mvert[i];
+
+ copy_v3_v3(mv->co, eve->co);
+
+ BM_elem_index_set(eve, i); /* set_inline */
+
+ normal_float_to_short_v3(mv->no, eve->no);
+
+ mv->flag = BM_vert_flag_to_mflag(eve);
+
+ if (cd_vert_bweight_offset != -1) mv->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset);
+
+ if (add_orig) *index++ = i;
+
+ CustomData_from_bmesh_block(&bm->vdata, &me->vdata, eve->head.data, i);
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ index = CustomData_get_layer(&me->edata, CD_ORIGINDEX);
+ BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
+ MEdge *med = &medge[i];
+
+ BM_elem_index_set(eed, i); /* set_inline */
+
+ med->v1 = BM_elem_index_get(eed->v1);
+ med->v2 = BM_elem_index_get(eed->v2);
+
+ med->flag = BM_edge_flag_to_mflag(eed);
+
+ /* handle this differently to editmode switching,
+ * only enable draw for single user edges rather then calculating angle */
+ if ((med->flag & ME_EDGEDRAW) == 0) {
+ if (eed->l && eed->l == eed->l->radial_next) {
+ med->flag |= ME_EDGEDRAW;
+ }
+ }
+
+ if (cd_edge_crease_offset != -1) med->crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset);
+ if (cd_edge_bweight_offset != -1) med->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset);
+
+ CustomData_from_bmesh_block(&bm->edata, &me->edata, eed->head.data, i);
+ if (add_orig) *index++ = i;
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ index = CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
+ j = 0;
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ MPoly *mp = &mpoly[i];
+
+ BM_elem_index_set(efa, i); /* set_inline */
+
+ mp->totloop = efa->len;
+ mp->flag = BM_face_flag_to_mflag(efa);
+ mp->loopstart = j;
+ mp->mat_nr = efa->mat_nr;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ mloop->v = BM_elem_index_get(l_iter->v);
+ mloop->e = BM_elem_index_get(l_iter->e);
+ CustomData_from_bmesh_block(&bm->ldata, &me->ldata, l_iter->head.data, j);
+
+ BM_elem_index_set(l_iter, j); /* set_inline */
+
+ j++;
+ mloop++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ CustomData_from_bmesh_block(&bm->pdata, &me->pdata, efa->head.data, i);
+
+ if (add_orig) *index++ = i;
+ }
+ bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
+
+ me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h
index 008960e7f6e..8f389a8cf05 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h
@@ -49,9 +49,10 @@ struct BMeshFromMeshParams {
uint use_shapekey : 1;
/* define the active shape key (index + 1) */
int active_shapekey;
+ int64_t cd_mask_extra;
};
void BM_mesh_bm_from_me(
- BMesh *bm, struct Mesh *me,
+ BMesh *bm, const struct Mesh *me,
const struct BMeshFromMeshParams *params)
ATTR_NONNULL(1, 3);
@@ -65,4 +66,9 @@ void BM_mesh_bm_to_me(
const struct BMeshToMeshParams *params)
ATTR_NONNULL(2, 3, 4);
+void BM_mesh_bm_to_me_for_eval(
+ BMesh *bm, struct Mesh *me, const int64_t cd_mask_extra)
+ATTR_NONNULL(1, 2);
+
+
#endif /* __BMESH_MESH_CONV_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 7abf05044dd..b7df6d8f90b 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -59,6 +59,8 @@
#include "bmesh.h"
#include "intern/bmesh_operators_private.h"
+#include "DNA_modifier_types.h"
+
/* The formatting of these bmesh operators is parsed by
* 'doc/python_api/rst_from_bmesh_opdefines.py'
* for use in python docs, so reStructuredText may be used
@@ -95,6 +97,25 @@
* note that '//' comments are ignored.
*/
+/* enums shared between multiple operators */
+
+static BMO_FlagSet bmo_enum_axis_xyz[] = {
+ {0, "X"},
+ {1, "Y"},
+ {2, "Z"},
+ {0, NULL},
+};
+
+static BMO_FlagSet bmo_enum_falloff_type[] = {
+ {SUBD_FALLOFF_SMOOTH, "SMOOTH"},
+ {SUBD_FALLOFF_SPHERE, "SPHERE"},
+ {SUBD_FALLOFF_ROOT, "ROOT"},
+ {SUBD_FALLOFF_SHARP, "SHARP"},
+ {SUBD_FALLOFF_LIN, "LINEAR"},
+ {SUBD_FALLOFF_INVSQUARE, "INVERSE_SQUARE"},
+ {0, NULL},
+};
+
/*
* Vertex Smooth.
*
@@ -290,7 +311,7 @@ static BMOpDefine bmo_mirror_def = {
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input geometry */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix defining the mirror transformation */
{"merge_dist", BMO_OP_SLOT_FLT}, /* maximum distance for merging. does no merging if 0. */
- {"axis", BMO_OP_SLOT_INT}, /* the axis to use, 0, 1, or 2 for x, y, z */
+ {"axis", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_axis_xyz}, /* the axis to use. */
{"mirror_u", BMO_OP_SLOT_BOOL}, /* mirror UVs across the u axis */
{"mirror_v", BMO_OP_SLOT_BOOL}, /* mirror UVs across the v axis */
{{'\0'}},
@@ -1113,6 +1134,15 @@ static BMOpDefine bmo_dissolve_faces_def = {
BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
+static BMO_FlagSet bmo_enum_dissolve_limit_flags[] = {
+ {BMO_DELIM_NORMAL, "NORMAL"},
+ {BMO_DELIM_MATERIAL, "MATERIAL"},
+ {BMO_DELIM_SEAM, "SEAM"},
+ {BMO_DELIM_SHARP, "SHARP"},
+ {BMO_DELIM_UV, "UV"},
+ {0, NULL}
+};
+
/*
* Limited Dissolve.
*
@@ -1125,7 +1155,7 @@ static BMOpDefine bmo_dissolve_limit_def = {
{"use_dissolve_boundaries", BMO_OP_SLOT_BOOL},
{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}},
{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}},
- {"delimit", BMO_OP_SLOT_INT},
+ {"delimit", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_FLAG}, bmo_enum_dissolve_limit_flags},
{{'\0'}},
},
/* slots_out */
@@ -1159,6 +1189,20 @@ static BMOpDefine bmo_dissolve_degenerate_def = {
BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
+static BMO_FlagSet bmo_enum_triangulate_quad_method[] = {
+ {MOD_TRIANGULATE_QUAD_BEAUTY, "BEAUTY"},
+ {MOD_TRIANGULATE_QUAD_FIXED, "FIXED"},
+ {MOD_TRIANGULATE_QUAD_ALTERNATE, "ALTERNATE"},
+ {MOD_TRIANGULATE_QUAD_SHORTEDGE, "SHORT_EDGE"},
+ {0, NULL},
+};
+
+static BMO_FlagSet bmo_enum_triangulate_ngon_method[] = {
+ {MOD_TRIANGULATE_NGON_BEAUTY, "BEAUTY"},
+ {MOD_TRIANGULATE_NGON_EARCLIP, "EAR_CLIP"},
+ {0, NULL},
+};
+
/*
* Triangulate.
*/
@@ -1166,8 +1210,8 @@ static BMOpDefine bmo_triangulate_def = {
"triangulate",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
- {"quad_method", BMO_OP_SLOT_INT},
- {"ngon_method", BMO_OP_SLOT_INT},
+ {"quad_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_triangulate_quad_method},
+ {"ngon_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_triangulate_ngon_method},
{{'\0'}},
},
/* slots_out */
@@ -1203,6 +1247,14 @@ static BMOpDefine bmo_unsubdivide_def = {
BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
+static BMO_FlagSet bmo_enum_subdivide_edges_quad_corner_type[] = {
+ {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT"},
+ {SUBD_CORNER_INNERVERT, "INNER_VERT"},
+ {SUBD_CORNER_PATH, "PATH"},
+ {SUBD_CORNER_FAN, "FAN"},
+ {0, NULL},
+};
+
/*
* Subdivide Edges.
*
@@ -1214,15 +1266,14 @@ static BMOpDefine bmo_subdivide_edges_def = {
/* slots_in */
{{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}},
{"smooth", BMO_OP_SLOT_FLT},
- {"smooth_falloff", BMO_OP_SLOT_INT}, /* SUBD_FALLOFF_ROOT and friends */
+ {"smooth_falloff", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_falloff_type}, /* smooth falloff type */
{"fractal", BMO_OP_SLOT_FLT},
{"along_normal", BMO_OP_SLOT_FLT},
{"cuts", BMO_OP_SLOT_INT},
{"seed", BMO_OP_SLOT_INT},
{"custom_patterns", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL}}, /* uses custom pointers */
{"edge_percents", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_FLT}},
-
- {"quad_corner_type", BMO_OP_SLOT_INT}, /* quad corner type, see bmesh_operators.h */
+ {"quad_corner_type", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_subdivide_edges_quad_corner_type}, /* quad corner type */
{"use_grid_fill", BMO_OP_SLOT_BOOL}, /* fill in fully-selected faces with a grid */
{"use_single_edge", BMO_OP_SLOT_BOOL}, /* tessellate the case of one edge selected in a quad or triangle */
{"use_only_quads", BMO_OP_SLOT_BOOL}, /* only subdivide quads (for loopcut) */
@@ -1244,6 +1295,13 @@ static BMOpDefine bmo_subdivide_edges_def = {
BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
+static BMO_FlagSet bmo_enum_subdivide_edgering_interp_mode[] = {
+ {SUBD_RING_INTERP_LINEAR, "LINEAR"},
+ {SUBD_RING_INTERP_PATH, "PATH"},
+ {SUBD_RING_INTERP_SURF, "SURFACE"},
+ {0, NULL},
+};
+
/*
* Subdivide Edge-Ring.
*
@@ -1253,10 +1311,10 @@ static BMOpDefine bmo_subdivide_edgering_def = {
"subdivide_edgering",
/* slots_in */
{{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input vertices */
- {"interp_mode", BMO_OP_SLOT_INT},
+ {"interp_mode", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_subdivide_edgering_interp_mode}, /* interpolation method */
{"smooth", BMO_OP_SLOT_FLT},
{"cuts", BMO_OP_SLOT_INT},
- {"profile_shape", BMO_OP_SLOT_INT},
+ {"profile_shape", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_falloff_type}, /* profile shape type */
{"profile_shape_factor", BMO_OP_SLOT_FLT},
{{'\0'}},
},
@@ -1296,6 +1354,17 @@ static BMOpDefine bmo_bisect_plane_def = {
BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
+static BMO_FlagSet bmo_enum_delete_context[] = {
+ {DEL_VERTS, "VERTS"},
+ {DEL_EDGES, "EDGES"},
+ {DEL_ONLYFACES, "FACES_ONLY"},
+ {DEL_EDGESFACES, "EDGES_FACES"},
+ {DEL_FACES, "FACES"},
+ {DEL_FACES_KEEP_BOUNDARY, "FACES_KEEP_BOUNDARY"},
+ {DEL_ONLYTAGGED, "TAGGED_ONLY"},
+ {0, NULL},
+};
+
/*
* Delete Geometry.
*
@@ -1305,7 +1374,7 @@ static BMOpDefine bmo_delete_def = {
"delete",
/* slots_in */
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}},
- {"context", BMO_OP_SLOT_INT}, /* enum DEL_VERTS ... */
+ {"context", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_delete_context}, /* geometry types to delete */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -1403,73 +1472,6 @@ static BMOpDefine bmo_spin_def = {
BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
-
-/*
- * Similar Faces Search.
- *
- * Find similar faces (area/material/perimeter, ...).
- */
-static BMOpDefine bmo_similar_faces_def = {
- "similar_faces",
- /* slots_in */
- {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
- {"type", BMO_OP_SLOT_INT}, /* type of selection */
- {"thresh", BMO_OP_SLOT_FLT}, /* threshold of selection */
- {"compare", BMO_OP_SLOT_INT}, /* comparison method */
- {{'\0'}},
- },
- /* slots_out */
- {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */
- {{'\0'}},
- },
- bmo_similar_faces_exec,
- (BMO_OPTYPE_FLAG_SELECT_FLUSH),
-};
-
-/*
- * Similar Edges Search.
- *
- * Find similar edges (length, direction, edge, seam, ...).
- */
-static BMOpDefine bmo_similar_edges_def = {
- "similar_edges",
- /* slots_in */
- {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */
- {"type", BMO_OP_SLOT_INT}, /* type of selection */
- {"thresh", BMO_OP_SLOT_FLT}, /* threshold of selection */
- {"compare", BMO_OP_SLOT_INT}, /* comparison method */
- {{'\0'}},
- },
- /* slots_out */
- {{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output edges */
- {{'\0'}},
- },
- bmo_similar_edges_exec,
- (BMO_OPTYPE_FLAG_SELECT_FLUSH),
-};
-
-/*
- * Similar Verts Search.
- *
- * Find similar vertices (normal, face, vertex group, ...).
- */
-static BMOpDefine bmo_similar_verts_def = {
- "similar_verts",
- /* slots_in */
- {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */
- {"type", BMO_OP_SLOT_INT}, /* type of selection */
- {"thresh", BMO_OP_SLOT_FLT}, /* threshold of selection */
- {"compare", BMO_OP_SLOT_INT}, /* comparison method */
- {{'\0'}},
- },
- /* slots_out */
- {{"verts.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* output vertices */
- {{'\0'}},
- },
- bmo_similar_verts_exec,
- (BMO_OPTYPE_FLAG_SELECT_FLUSH),
-};
-
/*
* UV Rotation.
*
@@ -1724,6 +1726,22 @@ static BMOpDefine bmo_create_cube_def = {
BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
+static BMO_FlagSet bmo_enum_bevel_offset_type[] = {
+ {BEVEL_AMT_OFFSET, "OFFSET"},
+ {BEVEL_AMT_WIDTH, "WIDTH"},
+ {BEVEL_AMT_DEPTH, "DEPTH"},
+ {BEVEL_AMT_PERCENT, "PERCENT"},
+ {0, NULL},
+};
+
+static BMO_FlagSet bmo_enum_bevel_harden_normal_type[] = {
+ {BEVEL_HN_NONE, "NONE"},
+ {BEVEL_HN_FACE, "FACE"},
+ {BEVEL_HN_ADJ, "ADJACENT"},
+ {BEVEL_HN_FIX_SHA, "FIXED_NORMAL_SHADING"},
+ {0, NULL},
+};
+
/*
* Bevel.
*
@@ -1734,19 +1752,24 @@ static BMOpDefine bmo_bevel_def = {
/* slots_in */
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input edges and vertices */
{"offset", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */
- {"offset_type", BMO_OP_SLOT_INT}, /* how to measure offset (enum) */
+ {"offset_type", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_bevel_offset_type}, /* how to measure the offset */
{"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */
{"profile", BMO_OP_SLOT_FLT}, /* profile shape, 0->1 (.5=>round) */
{"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */
{"clamp_overlap", BMO_OP_SLOT_BOOL}, /* do not allow beveled edges/vertices to overlap each other */
{"material", BMO_OP_SLOT_INT}, /* material for bevel faces, -1 means get from adjacent faces */
{"loop_slide", BMO_OP_SLOT_BOOL}, /* prefer to slide along edges to having even widths */
+ {"mark_seam", BMO_OP_SLOT_BOOL}, /* extend edge data to allow seams to run across bevels */
+ {"mark_sharp", BMO_OP_SLOT_BOOL}, /* extend edge data to allow sharp edges to run across bevels */
+ {"strength", BMO_OP_SLOT_FLT}, /* strength of calculated normal in range (0, 1) for custom clnors */
+ {"hnmode", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_bevel_harden_normal_type}, /* harden normals mode used in bevel, if enabled */
{{'\0'}},
},
/* slots_out */
{{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */
{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output edges */
{"verts.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* output verts */
+ {"normals.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL}}, /* output normals per vertex for beveled edges */
{{'\0'}},
},
@@ -1757,6 +1780,13 @@ static BMOpDefine bmo_bevel_def = {
BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
+/* no enum is defined for this */
+static BMO_FlagSet bmo_enum_beautify_fill_method[] = {
+ {0, "AREA"},
+ {1, "ANGLE"},
+ {0, NULL},
+};
+
/*
* Beautify Fill.
*
@@ -1768,7 +1798,7 @@ static BMOpDefine bmo_beautify_fill_def = {
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* edges that can be flipped */
{"use_restrict_tag", BMO_OP_SLOT_BOOL}, /* restrict edge rotation to mixed tagged vertices */
- {"method", BMO_OP_SLOT_INT}, /* method to define what is beautiful */
+ {"method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_beautify_fill_method}, /* method to define what is beautiful */
{{'\0'}},
},
/* slots_out */
@@ -1932,6 +1962,13 @@ static BMOpDefine bmo_wireframe_def = {
BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
+static BMO_FlagSet bmo_enum_poke_center_mode[] = {
+ {BMOP_POKE_MEAN_WEIGHTED, "MEAN_WEIGHTED"},
+ {BMOP_POKE_MEAN, "MEAN"},
+ {BMOP_POKE_BOUNDS, "BOUNDS"},
+ {0, NULL},
+};
+
/*
* Pokes a face.
*
@@ -1942,7 +1979,7 @@ static BMOpDefine bmo_poke_def = {
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
{"offset", BMO_OP_SLOT_FLT}, /* center vertex offset along normal */
- {"center_mode", BMO_OP_SLOT_INT}, /* calculation mode for center vertex */
+ {"center_mode", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_poke_center_mode}, /* calculation mode for center vertex */
{"use_relative_offset", BMO_OP_SLOT_BOOL}, /* apply offset */
{{'\0'}},
},
@@ -2008,7 +2045,7 @@ static BMOpDefine bmo_symmetrize_def = {
"symmetrize",
/* slots_in */
{{"input", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}},
- {"direction", BMO_OP_SLOT_INT},
+ {"direction", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_axis_xyz}, /* axis to use */
{"dist", BMO_OP_SLOT_FLT}, /* minimum distance */
{{'\0'}},
},
@@ -2088,9 +2125,6 @@ const BMOpDefine *bmo_opdefines[] = {
&bmo_rotate_edges_def,
&bmo_rotate_uvs_def,
&bmo_scale_def,
- &bmo_similar_edges_def,
- &bmo_similar_faces_def,
- &bmo_similar_verts_def,
&bmo_smooth_vert_def,
&bmo_smooth_laplacian_vert_def,
&bmo_solidify_def,
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 30cd1df9c4e..fd01bec9531 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -193,13 +193,23 @@ typedef enum eBMOpSlotSubType_Ptr {
BMO_OP_SLOT_SUBTYPE_PTR_OBJECT = 102,
BMO_OP_SLOT_SUBTYPE_PTR_MESH = 103,
} eBMOpSlotSubType_Ptr;
+typedef enum eBMOpSlotSubType_Int {
+ BMO_OP_SLOT_SUBTYPE_INT_ENUM = 200,
+ BMO_OP_SLOT_SUBTYPE_INT_FLAG = 201,
+} eBMOpSlotSubType_Int;
typedef union eBMOpSlotSubType_Union {
eBMOpSlotSubType_Elem elem;
eBMOpSlotSubType_Ptr ptr;
eBMOpSlotSubType_Map map;
+ eBMOpSlotSubType_Int intg;
} eBMOpSlotSubType_Union;
+typedef struct BMO_FlagSet {
+ int value;
+ const char *identifier;
+} BMO_FlagSet;
+
/* please ignore all these structures, don't touch them in tool code, except
* for when your defining an operator with BMOpDefine.*/
@@ -218,6 +228,7 @@ typedef struct BMOpSlot {
float vec[3];
void **buf;
GHash *ghash;
+ BMO_FlagSet *enum_flags;
} data;
} BMOpSlot;
@@ -244,6 +255,7 @@ typedef enum {
BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1),
BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2),
BMO_OPTYPE_FLAG_SELECT_VALIDATE = (1 << 3),
+ BMO_OPTYPE_FLAG_INVALIDATE_CLNOR_ALL = (1 << 4),
} BMOpTypeFlag;
typedef struct BMOperator {
@@ -268,6 +280,7 @@ typedef struct BMOSlotType {
char name[MAX_SLOTNAME];
eBMOpSlotType type;
eBMOpSlotSubType_Union subtype;
+ BMO_FlagSet *enum_flags;
} BMOSlotType;
typedef struct BMOpDefine {
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index 62d892712fd..a8e1b1c3088 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -140,6 +140,10 @@ static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args
case BMO_OP_SLOT_MAPPING:
slot->data.ghash = BLI_ghash_ptr_new("bmesh slot map hash");
break;
+ case BMO_OP_SLOT_INT:
+ if (ELEM(slot->slot_subtype.intg, BMO_OP_SLOT_SUBTYPE_INT_ENUM, BMO_OP_SLOT_SUBTYPE_INT_FLAG)) {
+ slot->data.enum_flags = slot_types[i].enum_flags;
+ }
default:
break;
}
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index b670f31ad9f..3e96d5ff44a 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -56,12 +56,6 @@ enum {
SUBDIV_SELECT_LOOPCUT
};
-enum {
- SIM_CMP_EQ = 0,
- SIM_CMP_GT,
- SIM_CMP_LT
-};
-
/* subdivide_edgering */
enum {
/* just subdiv */
@@ -77,16 +71,14 @@ enum {
/* similar face selection slot values */
enum {
SIMFACE_MATERIAL = 201,
- SIMFACE_IMAGE,
SIMFACE_AREA,
SIMFACE_SIDES,
SIMFACE_PERIMETER,
SIMFACE_NORMAL,
SIMFACE_COPLANAR,
SIMFACE_SMOOTH,
-#ifdef WITH_FREESTYLE
+ SIMFACE_FACEMAP,
SIMFACE_FREESTYLE
-#endif
};
/* similar edge selection slot values */
@@ -99,9 +91,7 @@ enum {
SIMEDGE_BEVEL,
SIMEDGE_SEAM,
SIMEDGE_SHARP,
-#ifdef WITH_FREESTYLE
SIMEDGE_FREESTYLE
-#endif
};
/* similar vertex selection slot values */
@@ -127,6 +117,13 @@ enum {
BEVEL_AMT_PERCENT
};
+enum {
+ BEVEL_HN_NONE, /* Disable harden normals */
+ BEVEL_HN_FACE, /* harden normals according to face area */
+ BEVEL_HN_ADJ, /* harden normals according to adjacent 'beveled' faces */
+ BEVEL_HN_FIX_SHA, /* Special mode to fix normal shading continuity */
+};
+
extern const BMOpDefine *bmo_opdefines[];
extern const int bmo_opdefines_total;
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
index 5548ee7c361..8e9edfac1f9 100644
--- a/source/blender/bmesh/intern/bmesh_operators_private.h
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -94,9 +94,6 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op);
void bmo_rotate_exec(BMesh *bm, BMOperator *op);
void bmo_rotate_uvs_exec(BMesh *bm, BMOperator *op);
void bmo_scale_exec(BMesh *bm, BMOperator *op);
-void bmo_similar_edges_exec(BMesh *bm, BMOperator *op);
-void bmo_similar_faces_exec(BMesh *bm, BMOperator *op);
-void bmo_similar_verts_exec(BMesh *bm, BMOperator *op);
void bmo_smooth_vert_exec(BMesh *bm, BMOperator *op);
void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op);
void bmo_solidify_face_region_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 5e3f5958a32..9baae8e8a93 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -242,7 +242,7 @@ float BM_face_calc_area(const BMFace *f)
/**
* Get the area of the face in world space.
*/
-float BM_face_calc_area_with_mat3(const BMFace *f, float mat3[3][3])
+float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
{
/* inline 'area_poly_v3' logic, avoid creating a temp array */
const BMLoop *l_iter, *l_first;
@@ -280,7 +280,7 @@ float BM_face_calc_perimeter(const BMFace *f)
/**
* Calculate the perimeter of a ngon in world space.
*/
-float BM_face_calc_perimeter_with_mat3(const BMFace *f, float mat3[3][3])
+float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
{
const BMLoop *l_iter, *l_first;
float co[3];
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 1d5fb2cc620..2edfdaa8c03 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -44,9 +44,9 @@ float BM_face_calc_normal_vcos(
float const (*vertexCos)[3]) ATTR_NONNULL();
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_face_calc_area_with_mat3(const BMFace *f, float mat3[3][3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_face_calc_perimeter_with_mat3(const BMFace *f, float mat3[3][3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_face_calc_tangent_edge(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index e1f16508b8b..c446ce5ab49 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -1685,7 +1685,7 @@ float BM_edge_calc_face_angle(const BMEdge *e)
*
* \return angle in radians
*/
-float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e, float imat3[3][3], const float fallback)
+float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e, const float imat3[3][3], const float fallback)
{
if (BM_edge_is_manifold(e)) {
const BMLoop *l1 = e->l;
@@ -1706,7 +1706,7 @@ float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e, float imat3[3][3],
return fallback;
}
}
-float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, float imat3[3][3])
+float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3])
{
return BM_edge_calc_face_angle_with_imat3_ex(e, imat3, DEG2RADF(90.0f));
}
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index fb625c9acc8..7c087a5150f 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -123,8 +123,8 @@ void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e, float imat3[3][3], const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, float imat3[3][3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e, const float imat3[3][3], const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3]) ATTR_NONNULL();
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c
index 9247c64d3fb..656a446d5ab 100644
--- a/source/blender/bmesh/operators/bmo_bevel.c
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -43,6 +43,9 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
const bool clamp_overlap = BMO_slot_bool_get(op->slots_in, "clamp_overlap");
const int material = BMO_slot_int_get(op->slots_in, "material");
const bool loop_slide = BMO_slot_bool_get(op->slots_in, "loop_slide");
+ const bool mark_seam = BMO_slot_bool_get(op->slots_in, "mark_seam");
+ const bool mark_sharp = BMO_slot_bool_get(op->slots_in, "mark_sharp");
+ const int hnmode = BMO_slot_int_get(op->slots_in, "hnmode");
if (offset > 0) {
BMOIter siter;
@@ -60,12 +63,15 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
BMO_ITER (e, &siter, op->slots_in, "geom", BM_EDGE) {
if (BM_edge_is_manifold(e)) {
BM_elem_flag_enable(e, BM_ELEM_TAG);
+ /* in case verts were not also included in the geom */
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
}
}
BM_mesh_bevel(
bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material,
- loop_slide);
+ loop_slide, mark_seam, mark_sharp, hnmode, op);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG);
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index b9e5cd927c3..caf40c71756 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -30,7 +30,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLI_heap.h"
+#include "BLI_heap_simple.h"
#include "bmesh.h"
@@ -94,7 +94,7 @@
// #define DEBUG_PRINT
typedef struct PathContext {
- Heap *states;
+ HeapSimple *states;
float matrix[3][3];
float axis_sep;
@@ -331,7 +331,7 @@ static PathLinkState *state_link_add_test(
/* after adding a link so we use the updated 'state->dist' */
if (is_new) {
- BLI_heap_insert(pc->states, state->dist, state);
+ BLI_heapsimple_insert(pc->states, state->dist, state);
}
return state;
@@ -640,7 +640,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
/* setup context */
{
- pc.states = BLI_heap_new();
+ pc.states = BLI_heapsimple_new();
pc.link_pool = BLI_mempool_create(sizeof(PathLink), 0, 512, BLI_MEMPOOL_NOP);
}
@@ -655,18 +655,18 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
PathLinkState *state;
state = MEM_callocN(sizeof(*state), __func__);
state_link_add(&pc, state, (BMElem *)pc.v_a, NULL);
- BLI_heap_insert(pc.states, state->dist, state);
+ BLI_heapsimple_insert(pc.states, state->dist, state);
}
- while (!BLI_heap_is_empty(pc.states)) {
+ while (!BLI_heapsimple_is_empty(pc.states)) {
#ifdef DEBUG_PRINT
- printf("\n%s: stepping %u\n", __func__, BLI_heap_len(pc.states));
+ printf("\n%s: stepping %u\n", __func__, BLI_heapsimple_len(pc.states));
#endif
- while (!BLI_heap_is_empty(pc.states)) {
- PathLinkState *state = BLI_heap_pop_min(pc.states);
+ while (!BLI_heapsimple_is_empty(pc.states)) {
+ PathLinkState *state = BLI_heapsimple_pop_min(pc.states);
/* either we insert this into 'pc.states' or its freed */
bool continue_search;
@@ -679,7 +679,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
state_best = *state;
/* we're done, exit all loops */
- BLI_heap_clear(pc.states, MEM_freeN);
+ BLI_heapsimple_clear(pc.states, MEM_freeN);
continue_search = false;
}
else if (state_step(&pc, state)) {
@@ -696,7 +696,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
}
if (continue_search) {
- BLI_heap_insert(pc.states, state->dist, state);
+ BLI_heapsimple_insert(pc.states, state->dist, state);
}
else {
MEM_freeN(state);
@@ -732,7 +732,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
BLI_mempool_destroy(pc.link_pool);
- BLI_heap_free(pc.states, MEM_freeN);
+ BLI_heapsimple_free(pc.states, MEM_freeN);
#if 1
if (state_best.link_last) {
diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c
deleted file mode 100644
index 454d6d8c6c8..00000000000
--- a/source/blender/bmesh/operators/bmo_similar.c
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * ***** 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): Joseph Eagar, Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/bmesh/operators/bmo_similar.c
- * \ingroup bmesh
- *
- * bmesh operators to select based on
- * comparisons with the existing selection.
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_object_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BLI_math.h"
-
-#include "BKE_customdata.h"
-#include "BKE_deform.h"
-
-#include "bmesh.h"
-
-#include "intern/bmesh_operators_private.h" /* own include */
-
-/* in fact these could all be the same */
-
-/*
- * extra face data (computed data)
- */
-typedef struct SimSel_FaceExt {
- BMFace *f; /* the face */
- float c[3]; /* center */
- union {
- float area; /* area */
- float perim; /* perimeter */
- float d; /* 4th component of plane (the first three being the normal) */
- struct Image *t; /* image pointer */
- };
-} SimSel_FaceExt;
-
-static int bm_sel_similar_cmp_fl(const float delta, const float thresh, const int compare)
-{
- switch (compare) {
- case SIM_CMP_EQ:
- return (fabsf(delta) <= thresh);
- case SIM_CMP_GT:
- return ((delta + thresh) >= 0.0f);
- case SIM_CMP_LT:
- return ((delta - thresh) <= 0.0f);
- default:
- BLI_assert(0);
- return 0;
- }
-}
-
-static int bm_sel_similar_cmp_i(const int delta, const int compare)
-{
- switch (compare) {
- case SIM_CMP_EQ:
- return (delta == 0);
- case SIM_CMP_GT:
- return (delta > 0);
- case SIM_CMP_LT:
- return (delta < 0);
- default:
- BLI_assert(0);
- return 0;
- }
-}
-
-/*
- * Select similar faces, the choices are in the enum in source/blender/bmesh/bmesh_operators.h
- * We select either similar faces based on material, image, area, perimeter, normal, or the coplanar faces
- */
-void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
-{
-#define FACE_MARK 1
-
- BMIter fm_iter;
- BMFace *fs, *fm;
- BMOIter fs_iter;
- int num_sels = 0, num_total = 0, i = 0, idx = 0;
- float angle = 0.0f;
- SimSel_FaceExt *f_ext = NULL;
- int *indices = NULL;
- const int type = BMO_slot_int_get(op->slots_in, "type");
- const float thresh = BMO_slot_float_get(op->slots_in, "thresh");
- const float thresh_radians = thresh * (float)M_PI;
- const int compare = BMO_slot_int_get(op->slots_in, "compare");
-
- /* initial_elem - other_elem */
- float delta_fl;
- int delta_i;
-
- num_total = BM_mesh_elem_count(bm, BM_FACE);
-
- /*
- * The first thing to do is to iterate through all the selected items and mark them since
- * they will be in the selection anyway.
- * This will increase performance, (especially when the number of originally selected faces is high)
- * so the overall complexity will be less than $O(mn)$ where is the total number of selected faces,
- * and n is the total number of faces
- */
- BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
- if (!BMO_face_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */
- BMO_face_flag_enable(bm, fs, FACE_MARK);
- num_sels++;
- }
- }
-
- /* allocate memory for the selected faces indices and for all temporary faces */
- indices = (int *)MEM_callocN(sizeof(int) * num_sels, "face indices util.c");
- f_ext = (SimSel_FaceExt *)MEM_callocN(sizeof(SimSel_FaceExt) * num_total, "f_ext util.c");
-
- /* loop through all the faces and fill the faces/indices structure */
- BM_ITER_MESH (fm, &fm_iter, bm, BM_FACES_OF_MESH) {
- f_ext[i].f = fm;
- if (BMO_face_flag_test(bm, fm, FACE_MARK)) {
- indices[idx] = i;
- idx++;
- }
- i++;
- }
-
- /*
- * Save us some computation burden: In case of perimeter/area/coplanar selection we compute
- * only once.
- */
- if (type == SIMFACE_PERIMETER || type == SIMFACE_AREA || type == SIMFACE_COPLANAR || type == SIMFACE_IMAGE) {
- for (i = 0; i < num_total; i++) {
- switch (type) {
- case SIMFACE_PERIMETER:
- /* set the perimeter */
- f_ext[i].perim = BM_face_calc_perimeter(f_ext[i].f);
- break;
-
- case SIMFACE_COPLANAR:
- /* compute the center of the polygon */
- BM_face_calc_center_mean(f_ext[i].f, f_ext[i].c);
-
- /* compute the plane distance */
- f_ext[i].d = dot_v3v3(f_ext[i].f->no, f_ext[i].c);
- break;
-
- case SIMFACE_AREA:
- f_ext[i].area = BM_face_calc_area(f_ext[i].f);
- break;
-
- case SIMFACE_IMAGE:
- f_ext[i].t = NULL;
- if (CustomData_has_layer(&(bm->pdata), CD_MTEXPOLY)) {
- MTexPoly *mtpoly = CustomData_bmesh_get(&bm->pdata, f_ext[i].f->head.data, CD_MTEXPOLY);
- f_ext[i].t = mtpoly->tpage;
- }
- break;
- }
- }
- }
-
- /* now select the rest (if any) */
- for (i = 0; i < num_total; i++) {
- fm = f_ext[i].f;
- if (!BMO_face_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) {
- bool cont = true;
- for (idx = 0; idx < num_sels && cont == true; idx++) {
- fs = f_ext[indices[idx]].f;
- switch (type) {
- case SIMFACE_MATERIAL:
- if (fm->mat_nr == fs->mat_nr) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- break;
-
- case SIMFACE_IMAGE:
- if (f_ext[i].t == f_ext[indices[idx]].t) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- break;
-
- case SIMFACE_NORMAL:
- angle = angle_normalized_v3v3(fs->no, fm->no); /* if the angle between the normals -> 0 */
- if (angle <= thresh_radians) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- break;
-
- case SIMFACE_COPLANAR:
- {
- float sign = 1.0f;
- angle = angle_normalized_v3v3(fs->no, fm->no); /* angle -> 0 */
- /* allow for normal pointing in either direction (just check the plane) */
- if (angle > (float)M_PI * 0.5f) {
- angle = (float)M_PI - angle;
- sign = -1.0f;
- }
- if (angle <= thresh_radians) { /* and dot product difference -> 0 */
- delta_fl = f_ext[i].d - (f_ext[indices[idx]].d * sign);
- if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- }
- break;
- }
- case SIMFACE_AREA:
- delta_fl = f_ext[i].area - f_ext[indices[idx]].area;
- if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- break;
-
- case SIMFACE_SIDES:
- delta_i = fm->len - fs->len;
- if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- break;
-
- case SIMFACE_PERIMETER:
- delta_fl = f_ext[i].perim - f_ext[indices[idx]].perim;
- if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- break;
-
- case SIMFACE_SMOOTH:
- if (BM_elem_flag_test(fm, BM_ELEM_SMOOTH) == BM_elem_flag_test(fs, BM_ELEM_SMOOTH)) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- break;
-#ifdef WITH_FREESTYLE
- case SIMFACE_FREESTYLE:
- if (CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) {
- FreestyleEdge *ffa1, *ffa2;
-
- ffa1 = CustomData_bmesh_get(&bm->pdata, fs->head.data, CD_FREESTYLE_FACE);
- ffa2 = CustomData_bmesh_get(&bm->pdata, fm->head.data, CD_FREESTYLE_FACE);
-
- if (ffa1 && ffa2 && (ffa1->flag & FREESTYLE_FACE_MARK) == (ffa2->flag & FREESTYLE_FACE_MARK)) {
- BMO_face_flag_enable(bm, fm, FACE_MARK);
- cont = false;
- }
- }
- break;
-#endif
- default:
- BLI_assert(0);
- break;
- }
- }
- }
- }
-
- MEM_freeN(f_ext);
- MEM_freeN(indices);
-
- /* transfer all marked faces to the output slot */
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_MARK);
-#undef FACE_MARK
-}
-
-/**************************************************************************** *
- * Similar Edges
- **************************************************************************** */
-
-/*
- * extra edge information
- */
-typedef struct SimSel_EdgeExt {
- BMEdge *e;
- union {
- float dir[3];
- float angle; /* angle between the face */
- };
-
- union {
- float length; /* edge length */
- int faces; /* faces count */
- };
-} SimSel_EdgeExt;
-
-/*
- * select similar edges: the choices are in the enum in source/blender/bmesh/bmesh_operators.h
- * choices are length, direction, face, ...
- */
-void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
-{
-#define EDGE_MARK 1
-
- BMOIter es_iter; /* selected edges iterator */
- BMIter e_iter; /* mesh edges iterator */
- BMEdge *es; /* selected edge */
- BMEdge *e; /* mesh edge */
- int idx = 0, i = 0 /* , f = 0 */;
- int *indices = NULL;
- SimSel_EdgeExt *e_ext = NULL;
- // float *angles = NULL;
- float angle;
-
- int num_sels = 0, num_total = 0;
- const int type = BMO_slot_int_get(op->slots_in, "type");
- const float thresh = BMO_slot_float_get(op->slots_in, "thresh");
- const int compare = BMO_slot_int_get(op->slots_in, "compare");
-
- /* initial_elem - other_elem */
- float delta_fl;
- int delta_i;
-
- /* sanity checks that the data we need is available */
- switch (type) {
- case SIMEDGE_CREASE:
- if (!CustomData_has_layer(&bm->edata, CD_CREASE)) {
- return;
- }
- break;
- case SIMEDGE_BEVEL:
- if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
- return;
- }
- break;
- }
-
- num_total = BM_mesh_elem_count(bm, BM_EDGE);
-
- /* iterate through all selected edges and mark them */
- BMO_ITER (es, &es_iter, op->slots_in, "edges", BM_EDGE) {
- BMO_edge_flag_enable(bm, es, EDGE_MARK);
- num_sels++;
- }
-
- /* allocate memory for the selected edges indices and for all temporary edges */
- indices = (int *)MEM_callocN(sizeof(int) * num_sels, __func__);
- e_ext = (SimSel_EdgeExt *)MEM_callocN(sizeof(SimSel_EdgeExt) * num_total, __func__);
-
- /* loop through all the edges and fill the edges/indices structure */
- BM_ITER_MESH (e, &e_iter, bm, BM_EDGES_OF_MESH) {
- e_ext[i].e = e;
- if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
- indices[idx] = i;
- idx++;
- }
- i++;
- }
-
- /* save us some computation time by doing heavy computation once */
- if (type == SIMEDGE_LENGTH || type == SIMEDGE_FACE || type == SIMEDGE_DIR || type == SIMEDGE_FACE_ANGLE) {
- for (i = 0; i < num_total; i++) {
- switch (type) {
- case SIMEDGE_LENGTH: /* compute the length of the edge */
- e_ext[i].length = len_v3v3(e_ext[i].e->v1->co, e_ext[i].e->v2->co);
- break;
-
- case SIMEDGE_DIR: /* compute the direction */
- sub_v3_v3v3(e_ext[i].dir, e_ext[i].e->v1->co, e_ext[i].e->v2->co);
- normalize_v3(e_ext[i].dir);
- break;
-
- case SIMEDGE_FACE: /* count the faces around the edge */
- e_ext[i].faces = BM_edge_face_count(e_ext[i].e);
- break;
-
- case SIMEDGE_FACE_ANGLE:
- e_ext[i].faces = BM_edge_face_count(e_ext[i].e);
- if (e_ext[i].faces == 2)
- e_ext[i].angle = BM_edge_calc_face_angle(e_ext[i].e);
- break;
- }
- }
- }
-
- /* select the edges if any */
- for (i = 0; i < num_total; i++) {
- e = e_ext[i].e;
- if (!BMO_edge_flag_test(bm, e, EDGE_MARK) &&
- !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
- {
- bool cont = true;
- for (idx = 0; idx < num_sels && cont == true; idx++) {
- es = e_ext[indices[idx]].e;
- switch (type) {
- case SIMEDGE_LENGTH:
- delta_fl = e_ext[i].length - e_ext[indices[idx]].length;
- if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- break;
-
- case SIMEDGE_DIR:
- /* compute the angle between the two edges */
- angle = angle_normalized_v3v3(e_ext[i].dir, e_ext[indices[idx]].dir);
-
- if (angle > (float)M_PI_2) /* use the smallest angle between the edges */
- angle = fabsf(angle - (float)M_PI);
-
- if (angle / (float)M_PI_2 <= thresh) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- break;
-
- case SIMEDGE_FACE:
- delta_i = e_ext[i].faces - e_ext[indices[idx]].faces;
- if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- break;
-
- case SIMEDGE_FACE_ANGLE:
- if (e_ext[i].faces == 2) {
- if (e_ext[indices[idx]].faces == 2) {
- if (fabsf(e_ext[i].angle - e_ext[indices[idx]].angle) <= thresh) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- }
- }
- else {
- cont = false;
- }
- break;
-
- case SIMEDGE_CREASE:
- {
- const float *c1, *c2;
-
- c1 = CustomData_bmesh_get(&bm->edata, e->head.data, CD_CREASE);
- c2 = CustomData_bmesh_get(&bm->edata, es->head.data, CD_CREASE);
- delta_fl = *c1 - *c2;
-
- if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- }
- break;
-
- case SIMEDGE_BEVEL:
- {
- const float *c1, *c2;
-
- c1 = CustomData_bmesh_get(&bm->edata, e->head.data, CD_BWEIGHT);
- c2 = CustomData_bmesh_get(&bm->edata, es->head.data, CD_BWEIGHT);
- delta_fl = *c1 - *c2;
-
- if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- }
- break;
-
- case SIMEDGE_SEAM:
- if (BM_elem_flag_test(e, BM_ELEM_SEAM) == BM_elem_flag_test(es, BM_ELEM_SEAM)) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- break;
-
- case SIMEDGE_SHARP:
- if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == BM_elem_flag_test(es, BM_ELEM_SMOOTH)) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- break;
-#ifdef WITH_FREESTYLE
- case SIMEDGE_FREESTYLE:
- if (CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
- FreestyleEdge *fed1, *fed2;
-
- fed1 = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
- fed2 = CustomData_bmesh_get(&bm->edata, es->head.data, CD_FREESTYLE_EDGE);
-
- if (fed1 && fed2 && (fed1->flag & FREESTYLE_EDGE_MARK) == (fed2->flag & FREESTYLE_EDGE_MARK)) {
- BMO_edge_flag_enable(bm, e, EDGE_MARK);
- cont = false;
- }
- }
- break;
-#endif
- default:
- BLI_assert(0);
- break;
- }
- }
- }
- }
-
- MEM_freeN(e_ext);
- MEM_freeN(indices);
-
- /* transfer all marked edges to the output slot */
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_MARK);
-
-#undef EDGE_MARK
-}
-
-/**************************************************************************** *
- * Similar Vertices
- **************************************************************************** */
-
-typedef struct SimSel_VertExt {
- BMVert *v;
- union {
- int num_faces; /* adjacent faces */
- int num_edges; /* adjacent edges */
- MDeformVert *dvert; /* deform vertex */
- };
-} SimSel_VertExt;
-
-/*
- * select similar vertices: the choices are in the enum in source/blender/bmesh/bmesh_operators.h
- * choices are normal, face, vertex group...
- */
-void bmo_similar_verts_exec(BMesh *bm, BMOperator *op)
-{
-#define VERT_MARK 1
-
- const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
- BMOIter vs_iter; /* selected verts iterator */
- BMIter v_iter; /* mesh verts iterator */
- BMVert *vs; /* selected vertex */
- BMVert *v; /* mesh vertex */
- SimSel_VertExt *v_ext = NULL;
- int *indices = NULL;
- int num_total = 0, num_sels = 0, i = 0, idx = 0;
- const int type = BMO_slot_int_get(op->slots_in, "type");
- const float thresh = BMO_slot_float_get(op->slots_in, "thresh");
- const float thresh_radians = thresh * (float)M_PI;
- const int compare = BMO_slot_int_get(op->slots_in, "compare");
-
- /* initial_elem - other_elem */
-// float delta_fl;
- int delta_i;
-
- num_total = BM_mesh_elem_count(bm, BM_VERT);
-
- /* iterate through all selected edges and mark them */
- BMO_ITER (vs, &vs_iter, op->slots_in, "verts", BM_VERT) {
- BMO_vert_flag_enable(bm, vs, VERT_MARK);
- num_sels++;
- }
-
- /* allocate memory for the selected vertices indices and for all temporary vertices */
- indices = (int *)MEM_mallocN(sizeof(int) * num_sels, "vertex indices");
- v_ext = (SimSel_VertExt *)MEM_mallocN(sizeof(SimSel_VertExt) * num_total, "vertex extra");
-
- /* loop through all the vertices and fill the vertices/indices structure */
- BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) {
- v_ext[i].v = v;
- if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
- indices[idx] = i;
- idx++;
- }
-
- switch (type) {
- case SIMVERT_FACE:
- /* calling BM_vert_face_count every time is time consumming, so call it only once per vertex */
- v_ext[i].num_faces = BM_vert_face_count(v);
- break;
-
- case SIMVERT_VGROUP:
- v_ext[i].dvert = (cd_dvert_offset != -1) ? BM_ELEM_CD_GET_VOID_P(v_ext[i].v, cd_dvert_offset) : NULL;
- break;
-
- case SIMVERT_EDGE:
- v_ext[i].num_edges = BM_vert_edge_count(v);
- break;
- }
-
- i++;
- }
-
- /* select the vertices if any */
- for (i = 0; i < num_total; i++) {
- v = v_ext[i].v;
- if (!BMO_vert_flag_test(bm, v, VERT_MARK) &&
- !BM_elem_flag_test(v, BM_ELEM_HIDDEN))
- {
- bool cont = true;
- for (idx = 0; idx < num_sels && cont == true; idx++) {
- vs = v_ext[indices[idx]].v;
- switch (type) {
- case SIMVERT_NORMAL:
- /* compare the angle between the normals */
- if (angle_normalized_v3v3(v->no, vs->no) <= thresh_radians) {
- BMO_vert_flag_enable(bm, v, VERT_MARK);
- cont = false;
- }
- break;
- case SIMVERT_FACE:
- /* number of adjacent faces */
- delta_i = v_ext[i].num_faces - v_ext[indices[idx]].num_faces;
- if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_vert_flag_enable(bm, v, VERT_MARK);
- cont = false;
- }
- break;
-
- case SIMVERT_VGROUP:
- if (v_ext[i].dvert != NULL && v_ext[indices[idx]].dvert != NULL) {
- if (defvert_find_shared(v_ext[i].dvert, v_ext[indices[idx]].dvert) != -1) {
- BMO_vert_flag_enable(bm, v, VERT_MARK);
- cont = false;
- }
- }
- break;
- case SIMVERT_EDGE:
- /* number of adjacent edges */
- delta_i = v_ext[i].num_edges - v_ext[indices[idx]].num_edges;
- if (bm_sel_similar_cmp_i(delta_i, compare)) {
- BMO_vert_flag_enable(bm, v, VERT_MARK);
- cont = false;
- }
- break;
- default:
- BLI_assert(0);
- break;
- }
- }
- }
- }
-
- MEM_freeN(indices);
- MEM_freeN(v_ext);
-
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
-
-#undef VERT_MARK
-}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index e55e11e0bdb..ad576e61acb 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "BLI_array.h"
#include "BLI_alloca.h"
@@ -42,6 +43,7 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
+#include "BKE_mesh.h"
#include "eigen_capi.h"
@@ -149,6 +151,8 @@ typedef struct BoundVert {
Profile profile; /* edge profile between this and next BoundVert */
bool any_seam; /* are any of the edges attached here seams? */
bool visited; /* used during delta adjust pass */
+ int seam_len; /* length of seam starting from current boundvert to next boundvert with ccw ordering */
+ int sharp_len; /* Same as seam_len but defines length of sharp edges */
// int _pad;
} BoundVert;
@@ -187,6 +191,8 @@ typedef struct BevelParams {
/* hash of BevVert for each vertex involved in bevel
* GHash: (key=(BMVert *), value=(BevVert *)) */
GHash *vert_hash;
+ /* Hash set used to store resultant beveled faces for VMesh when poly is ring */
+ GHash *faceHash;
MemArena *mem_arena; /* use for all allocs while bevel runs, if we need to free we can switch to mempool */
ProfileSpacing pro_spacing; /* parameter values for evenly spaced profiles */
@@ -199,9 +205,12 @@ typedef struct BevelParams {
bool loop_slide; /* should bevel prefer to slide along edges rather than keep widths spec? */
bool limit_offset; /* should offsets be limited by collisions? */
bool offset_adjust; /* should offsets be adjusted to try to get even widths? */
+ bool mark_seam;
+ bool mark_sharp;
const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
int vertex_group; /* vertex group index, maybe set if vertex_only */
int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
+ int hnmode;
} BevelParams;
// #pragma GCC diagnostic ignored "-Wpadded"
@@ -766,6 +775,11 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co);
sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co);
}
+ else {
+ /* shup up 'maybe unused' warnings */
+ zero_v3(dir1n);
+ zero_v3(dir2p);
+ }
ang = angle_v3v3(dir1, dir2);
if (ang < BEVEL_EPSILON_ANG) {
@@ -1521,8 +1535,219 @@ static void snap_to_superellipsoid(float co[3], const float super_r, bool midlin
co[2] = z;
}
+#define BEV_EXTEND_EDGE_DATA_CHECK(eh, flag) (BM_elem_flag_test(eh->e, flag))
+
+static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg)
+{
+ EdgeHalf *e = &bv->edges[0], *efirst = &bv->edges[0];
+
+ /* First first edge with seam or sharp edge data */
+ while ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag))) {
+ e = e->next;
+ if (e == efirst)
+ break;
+ }
+
+ /* If no such edge found, return */
+ if ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag)))
+ return;
+
+ /* Set efirst to this first encountered edge. */
+ efirst = e;
+
+ do {
+ int flag_count = 0;
+ EdgeHalf *ne = e->next;
+
+ while (((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(ne, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(ne, flag))) &&
+ ne != efirst)
+ {
+ if (ne->is_bev)
+ flag_count++;
+ ne = ne->next;
+ }
+ if (ne == e || (ne == efirst && ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag)) ||
+ (neg && BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag)))))
+ {
+ break;
+ }
+ /* Set seam_len / sharp_len of starting edge */
+ if (flag == BM_ELEM_SEAM) {
+ e->rightv->seam_len = flag_count;
+ }
+ else if (flag == BM_ELEM_SMOOTH) {
+ e->rightv->sharp_len = flag_count;
+ }
+ e = ne;
+ } while (e != efirst);
+}
+
+static void bevel_extend_edge_data(BevVert *bv)
+{
+ VMesh *vm = bv->vmesh;
+
+ BoundVert *bcur = bv->vmesh->boundstart, *start = bcur;
+
+ do {
+ /* If current boundvert has a seam length > 0 then it has a seam running along its edges */
+ if (bcur->seam_len) {
+ if (!bv->vmesh->boundstart->seam_len && start == bv->vmesh->boundstart)
+ start = bcur; /* set start to first boundvert with seam_len > 0 */
+
+ /* Now for all the mesh_verts starting at current index and ending at idxlen
+ * We go through outermost ring and through all its segments and add seams
+ * for those edges */
+ int idxlen = bcur->index + bcur->seam_len;
+ for (int i = bcur->index; i < idxlen; i++) {
+ BMVert *v1 = mesh_vert(vm, i % vm->count, 0, 0)->v, *v2;
+ BMEdge *e;
+ for (int k = 1; k < vm->seg; k++) {
+ v2 = mesh_vert(vm, i % vm->count, 0, k)->v;
+
+ /* Here v1 & v2 are current and next BMverts, we find common edge and set its edge data */
+ e = v1->e;
+ while (e->v1 != v2 && e->v2 != v2) {
+ if (e->v1 == v1)
+ e = e->v1_disk_link.next;
+ else
+ e = e->v2_disk_link.next;
+ }
+ BM_elem_flag_set(e, BM_ELEM_SEAM, true);
+ v1 = v2;
+ }
+ BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v;
+ e = v1->e; //Do same as above for first and last vert
+ while (e->v1 != v3 && e->v2 != v3) {
+ if (e->v1 == v1)
+ e = e->v1_disk_link.next;
+ else
+ e = e->v2_disk_link.next;
+ }
+ BM_elem_flag_set(e, BM_ELEM_SEAM, true);
+ bcur = bcur->next;
+ }
+ }
+ else
+ bcur = bcur->next;
+ } while (bcur != start);
+
+
+ bcur = bv->vmesh->boundstart;
+ start = bcur;
+ do {
+ if (bcur->sharp_len) {
+ if (!bv->vmesh->boundstart->sharp_len && start == bv->vmesh->boundstart)
+ start = bcur;
+
+ int idxlen = bcur->index + bcur->sharp_len;
+ for (int i = bcur->index; i < idxlen; i++) {
+ BMVert *v1 = mesh_vert(vm, i % vm->count, 0, 0)->v, *v2;
+ BMEdge *e;
+ for (int k = 1; k < vm->seg; k++) {
+ v2 = mesh_vert(vm, i % vm->count, 0, k)->v;
+
+ e = v1->e;
+ while (e->v1 != v2 && e->v2 != v2) {
+ if (e->v1 == v1)
+ e = e->v1_disk_link.next;
+ else
+ e = e->v2_disk_link.next;
+ }
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, false);
+ v1 = v2;
+ }
+ BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v;
+ e = v1->e;
+ while (e->v1 != v3 && e->v2 != v3) {
+ if (e->v1 == v1)
+ e = e->v1_disk_link.next;
+ else
+ e = e->v2_disk_link.next;
+ }
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, false);
+ bcur = bcur->next;
+ }
+ }
+ else
+ bcur = bcur->next;
+ } while (bcur != start);
+}
+
+static void bevel_harden_normals_mode(BevelParams *bp, BevVert *bv, BMOperator *op)
+{
+ if (bp->hnmode == BEVEL_HN_NONE)
+ return;
+
+ VMesh *vm = bv->vmesh;
+ BoundVert *bcur = vm->boundstart, *bstart = bcur;
+
+ BMEdge *e;
+ BMIter eiter;
+
+ BMOpSlot *nslot = BMO_slot_get(op->slots_out, "normals.out");
+ float n_final[3] = { 0.0f, 0.0f, 0.0f };
+
+ if (bp->hnmode == BEVEL_HN_FACE) {
+ GHash *tempfaceHash = BLI_ghash_int_new(__func__);
+
+ /* Iterate through all faces of current BMVert and add their normal*face_area to n_final */
+ BM_ITER_ELEM(e, &eiter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+
+ BMFace *f_a, *f_b;
+ BM_edge_face_pair(e, &f_a, &f_b);
+
+ if (f_a && !BLI_ghash_haskey(tempfaceHash, POINTER_FROM_UINT(BM_elem_index_get(f_a)))) {
+ int f_area = BM_face_calc_area(f_a);
+ float f_no[3];
+ copy_v3_v3(f_no, f_a->no);
+ mul_v3_fl(f_no, f_area);
+ add_v3_v3(n_final, f_no);
+ BLI_ghash_insert(tempfaceHash, POINTER_FROM_UINT(BM_elem_index_get(f_a)), NULL);
+ }
+ if (f_b && !BLI_ghash_haskey(tempfaceHash, POINTER_FROM_UINT(BM_elem_index_get(f_b)))) {
+ int f_area = BM_face_calc_area(f_b);
+ float f_no[3];
+ copy_v3_v3(f_no, f_b->no);
+ mul_v3_fl(f_no, f_area);
+ add_v3_v3(n_final, f_no);
+ BLI_ghash_insert(tempfaceHash, POINTER_FROM_UINT(BM_elem_index_get(f_b)), NULL);
+ }
+ }
+ }
+ BLI_ghash_free(tempfaceHash, NULL, NULL);
+ normalize_v3(n_final);
+ }
+ else if (bp->hnmode == BEVEL_HN_ADJ) {
+ BM_ITER_ELEM(e, &eiter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ if (e->v1 == bv->v) {
+ add_v3_v3(n_final, e->v2->no);
+ }
+ else {
+ add_v3_v3(n_final, e->v1->no);
+ }
+ }
+ }
+ normalize_v3(n_final);
+ }
+
+ do {
+ /* Set normals.out for vertices as computed earlier */
+ if (BMO_slot_map_contains(nslot, bcur->nv.v) != true) {
+
+ float(*vert_normal) = MEM_callocN(sizeof(*vert_normal) * 3, __func__);
+ add_v3_v3(vert_normal, n_final);
+ normalize_v3(vert_normal);
+
+ BMO_slot_map_insert(op, nslot, bcur->nv.v, vert_normal);
+ }
+ bcur = bcur->next;
+ } while (bcur != bstart);
+}
+
/* Set the any_seam property for a BevVert and all its BoundVerts */
-static void set_bound_vert_seams(BevVert *bv)
+static void set_bound_vert_seams(BevVert *bv, bool mark_seam, bool mark_sharp)
{
BoundVert *v;
EdgeHalf *e;
@@ -1538,6 +1763,13 @@ static void set_bound_vert_seams(BevVert *bv)
}
bv->any_seam |= v->any_seam;
} while ((v = v->next) != bv->vmesh->boundstart);
+
+ if (mark_seam) {
+ check_edge_data_seam_sharp_edges(bv, BM_ELEM_SEAM, false);
+ }
+ if (mark_sharp) {
+ check_edge_data_seam_sharp_edges(bv, BM_ELEM_SMOOTH, true);
+ }
}
static int count_bound_vert_seams(BevVert *bv)
@@ -1608,7 +1840,7 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
calculate_vm_profiles(bp, bv, vm);
if (construct) {
- set_bound_vert_seams(bv);
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
if (vm->count == 2)
vm->mesh_kind = M_NONE;
else if (bp->seg == 1)
@@ -1663,7 +1895,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
e->next->leftv = e->next->rightv = v;
/* could use M_POLY too, but tri-fan looks nicer)*/
vm->mesh_kind = M_TRI_FAN;
- set_bound_vert_seams(bv);
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
}
else {
adjust_bound_vert(e->next->leftv, co);
@@ -1722,7 +1954,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
}
if (construct) {
- set_bound_vert_seams(bv);
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
if (vm->count == 2 && bv->edgecount == 3) {
vm->mesh_kind = M_NONE;
@@ -1864,7 +2096,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
calculate_vm_profiles(bp, bv, vm);
if (construct) {
- set_bound_vert_seams(bv);
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
if (vm->count == 2) {
vm->mesh_kind = M_NONE;
@@ -2918,29 +3150,36 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
}
/* Is this a good candidate for using tri_corner_adj_vmesh? */
-static bool tri_corner_test(BevelParams *bp, BevVert *bv)
+static int tri_corner_test(BevelParams *bp, BevVert *bv)
{
float ang, totang, angdiff;
EdgeHalf *e;
int i;
+ int in_plane_e = 0;
- if (bv->edgecount != 3 || bv->selcount != 3)
- return false;
+ if (bp->vertex_only)
+ return -1;
totang = 0.0f;
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < bv->edgecount; i++) {
e = &bv->edges[i];
ang = BM_edge_calc_face_angle_signed_ex(e->e, 0.0f);
- if (ang <= (float) M_PI_4 || ang >= 3.0f * (float) M_PI_4)
- return false;
+ if (ang <= M_PI_4)
+ in_plane_e++;
+ else if (ang >= 3.0f * (float) M_PI_4)
+ return -1;
totang += ang;
}
+ if (in_plane_e != bv->edgecount - 3)
+ return -1;
angdiff = fabsf(totang - 3.0f * (float)M_PI_2);
if ((bp->pro_super_r == PRO_SQUARE_R && angdiff > (float)M_PI / 16.0f) ||
(angdiff > (float)M_PI_4))
{
- return false;
+ return -1;
}
- return true;
+ if (bv->edgecount != 3 || bv->selcount != 3)
+ return 0;
+ return 1;
}
static VMesh *tri_corner_adj_vmesh(BevelParams *bp, BevVert *bv)
@@ -2951,7 +3190,7 @@ static VMesh *tri_corner_adj_vmesh(BevelParams *bp, BevVert *bv)
VMesh *vm;
BoundVert *bndv;
- BLI_assert(bv->edgecount == 3 && bv->selcount == 3);
+ /*BLI_assert(bv->edgecount == 3 && bv->selcount == 3); Add support for in plane edges */
bndv = bv->vmesh->boundstart;
copy_v3_v3(co0, bndv->nv.co);
bndv = bndv->next;
@@ -2984,9 +3223,14 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv)
BoundVert *bndv;
MemArena *mem_arena = bp->mem_arena;
float r, fac, fullness;
+ n = bv->vmesh->count;
+
+ /* Same bevel as that of 3 edges of vert in a cube */
+ if (n == 3 && tri_corner_test(bp, bv) != -1 && bp->pro_super_r != PRO_SQUARE_IN_R) {
+ return tri_corner_adj_vmesh(bp, bv);
+ }
/* First construct an initial control mesh, with nseg==2 */
- n = bv->vmesh->count;
ns = bv->vmesh->seg;
vm0 = new_adj_vmesh(mem_arena, n, 2, bv->vmesh->boundstart);
@@ -3429,7 +3673,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
VMesh *vm1, *vm;
BoundVert *v;
BMVert *bmv1, *bmv2, *bmv3, *bmv4;
- BMFace *f, *f2;
+ BMFace *f, *f2, *r_f;
BMEdge *bme, *bme1, *bme2, *bme3;
EdgeHalf *e;
BoundVert *vpipe;
@@ -3441,6 +3685,17 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
odd = ns % 2;
BLI_assert(n >= 3 && ns > 1);
+ /* Add support for profiles in vertex only in-plane bevels */
+ if (bp->vertex_only) {
+ v = bv->vmesh->boundstart;
+ do {
+ Profile *pro = &v->profile;
+ pro->super_r = bp->pro_super_r;
+ copy_v3_v3(pro->midco, bv->v->co);
+ calculate_profile(bp, v);
+ v = v->next;
+ } while (v != bv->vmesh->boundstart);
+ }
vpipe = pipe_test(bv);
@@ -3450,7 +3705,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
else if (vpipe) {
vm1 = pipe_adj_vmesh(bp, bv, vpipe);
}
- else if (tri_corner_test(bp, bv)) {
+ else if (tri_corner_test(bp, bv) == 1) {
vm1 = tri_corner_adj_vmesh(bp, bv);
/* the PRO_SQUARE_IN_R profile has boundary edges that merge
* and no internal ring polys except possibly center ngon */
@@ -3463,6 +3718,8 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
vm1 = adj_vmesh(bp, bv);
}
+ bool do_fix_shading_bv = bp->faceHash != NULL;
+
/* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */
vm = bv->vmesh;
for (i = 0; i < n; i++) {
@@ -3504,24 +3761,24 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
if (bp->vertex_only) {
if (j < k) {
if (k == ns2 && j == ns2 - 1) {
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
NULL, NULL, v->next->efirst->e, bme, mat_nr);
}
else {
- bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
}
}
else if (j > k) {
- bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
}
else { /* j == k */
/* only one edge attached to v, since vertex_only */
if (e->is_seam) {
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
bme, NULL, bme, NULL, mat_nr);
}
else {
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f,
bme, NULL, bme, NULL, mat_nr);
}
}
@@ -3530,25 +3787,27 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
if (odd) {
if (k == ns2) {
if (e->is_seam) {
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
NULL, bme, bme, NULL, mat_nr);
}
else {
- bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, mat_nr);
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, mat_nr);
}
}
else {
- bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
}
}
else {
bme1 = k == ns2 - 1 ? bme : NULL;
bme3 = j == ns2 - 1 ? v->prev->ebev->e : NULL;
bme2 = bme1 != NULL ? bme1 : bme3;
- bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
+ r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
NULL, bme1, bme2, bme3, mat_nr);
}
}
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, r_f, NULL);
}
}
} while ((v = v->next) != vm->boundstart);
@@ -3621,6 +3880,8 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
+ bool do_fix_shading_bv = bp->faceHash != NULL;
+
if (bv->any_seam) {
frep = boundvert_rep_face(vm->boundstart, &frep2);
if (frep2 && frep && is_bad_uv_poly(bv, frep)) {
@@ -3666,6 +3927,8 @@ static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
} while ((v = v->next) != vm->boundstart);
if (n > 2) {
f = bev_create_ngon(bm, vv, n, vf, frep, ve, bp->mat_nr, true);
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f, NULL);
}
else {
f = NULL;
@@ -3680,6 +3943,7 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1);
+ bool do_fix_shading_bv = bp->faceHash != NULL;
f = bevel_build_poly(bp, bm, bv);
@@ -3688,6 +3952,11 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
BMLoop *l_fan = BM_FACE_FIRST_LOOP(f)->prev;
BMVert *v_fan = l_fan->v;
+ if (f->len == 3) {
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f, NULL);
+ }
+
while (f->len > 3) {
BMLoop *l_new;
BMFace *f_new;
@@ -3708,6 +3977,8 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
else if (l_fan->prev->v == v_fan) { l_fan = l_fan->prev; }
else { BLI_assert(0); }
}
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f_new, NULL);
}
}
}
@@ -3716,6 +3987,7 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
BLI_assert(bv->selcount == 2);
+ bool do_fix_shading_bv = bp->faceHash != NULL;
f = bevel_build_poly(bp, bm, bv);
@@ -3727,6 +3999,11 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
BMLoop *l_b = BM_face_vert_share_loop(f, eh_b->leftv->nv.v);
int split_count = bv->vmesh->seg + 1; /* ensure we don't walk past the segments */
+ if (f->len == 4) {
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f, NULL);
+ }
+
while (f->len > 4 && split_count > 0) {
BMLoop *l_new;
BLI_assert(l_a->f == f);
@@ -3745,6 +4022,9 @@ static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
/* walk around the new face to get the next verts to split */
l_a = l_new->prev;
l_b = l_new->next->next;
+
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, f, NULL);
}
split_count--;
}
@@ -3807,6 +4087,13 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
flag_out_edge(bm, bme);
}
}
+ else if (bp->faceHash) {
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_ELEM(f, &fiter, bv->v, BM_FACES_OF_VERT) {
+ BLI_ghash_insert(bp->faceHash, f, NULL);
+ }
+ }
}
/* Given that the boundary is built, now make the actual BMVerts
@@ -4721,13 +5008,15 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
VMesh *vm1, *vm2;
EdgeHalf *e1, *e2;
BMEdge *bme1, *bme2, *center_bme;
- BMFace *f1, *f2, *f;
+ BMFace *f1, *f2, *f, *r_f;
BMVert *verts[4];
BMFace *faces[4];
BMEdge *edges[4];
int k, nseg, i1, i2, odd, mid;
int mat_nr = bp->mat_nr;
+ bool do_fix_shading_bv = bp->faceHash != NULL;
+
if (!BM_edge_is_manifold(bme))
return;
@@ -4783,18 +5072,18 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
/* straddles a seam: choose to interpolate in f1 and snap right edge to bme */
edges[0] = edges[1] = NULL;
edges[2] = edges[3] = bme;
- bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
}
else {
/* straddles but not a seam: interpolate left half in f1, right half in f2 */
- bev_create_ngon(bm, verts, 4, faces, NULL, NULL, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, faces, NULL, NULL, mat_nr, true);
}
}
else if (!odd && k == mid) {
/* left poly that touches an even center line on right */
edges[0] = edges[1] = NULL;
edges[2] = edges[3] = bme;
- bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
center_bme = BM_edge_exists(verts[2], verts[3]);
BLI_assert(center_bme != NULL);
}
@@ -4802,13 +5091,15 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
/* right poly that touches an even center line on left */
edges[0] = edges[1] = bme;
edges[2] = edges[3] = NULL;
- bev_create_ngon(bm, verts, 4, NULL, f2, edges, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f2, edges, mat_nr, true);
}
else {
/* doesn't cross or touch the center line, so interpolate in appropriate f1 or f2 */
f = (k <= mid) ? f1 : f2;
- bev_create_ngon(bm, verts, 4, NULL, f, NULL, mat_nr, true);
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f, NULL, mat_nr, true);
}
+ if (do_fix_shading_bv)
+ BLI_ghash_insert(bp->faceHash, r_f, NULL);
verts[0] = verts[3];
verts[1] = verts[2];
}
@@ -5348,7 +5639,8 @@ void BM_mesh_bevel(
const float segments, const float profile,
const bool vertex_only, const bool use_weights, const bool limit_offset,
const struct MDeformVert *dvert, const int vertex_group, const int mat,
- const bool loop_slide)
+ const bool loop_slide, const bool mark_seam, const bool mark_sharp,
+ const int hnmode, void *mod_bmop_customdata)
{
BMIter iter;
BMVert *v, *v_next;
@@ -5357,6 +5649,9 @@ void BM_mesh_bevel(
BevelParams bp = {NULL};
GHashIterator giter;
+ BMOperator *op = NULL;
+ BevelModNorEditData *clnordata;
+
bp.offset = offset;
bp.offset_type = offset_type;
bp.seg = segments;
@@ -5369,8 +5664,12 @@ void BM_mesh_bevel(
bp.dvert = dvert;
bp.vertex_group = vertex_group;
bp.mat_nr = mat;
+ bp.mark_seam = mark_seam;
+ bp.mark_sharp = mark_sharp;
+ bp.hnmode = hnmode;
+ bp.faceHash = NULL;
- if (profile >= 0.999f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */
+ if (profile >= 0.950f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */
bp.pro_super_r = PRO_SQUARE_R;
}
@@ -5381,6 +5680,16 @@ void BM_mesh_bevel(
BLI_memarena_use_calloc(bp.mem_arena);
set_profile_spacing(&bp);
+ /* Stores BMOp if executed through tool else stores BevelModNorEditData */
+ if (bm->use_toolflags)
+ op = mod_bmop_customdata;
+ else {
+ clnordata = mod_bmop_customdata;
+ clnordata->faceHash = BLI_ghash_ptr_new(__func__);
+ BLI_ghash_flag_set(clnordata->faceHash, GHASH_FLAG_ALLOW_DUPES);
+ bp.faceHash = clnordata->faceHash;
+ }
+
/* Analyze input vertices, sorting edges and assigning initial new vertex positions */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
@@ -5425,6 +5734,15 @@ void BM_mesh_bevel(
}
}
+ /* Extend edge data like sharp edges and precompute normals for harden */
+ GHASH_ITER(giter, bp.vert_hash) {
+ bv = BLI_ghashIterator_getValue(&giter);
+ bevel_extend_edge_data(bv);
+ if (bm->use_toolflags) {
+ bevel_harden_normals_mode(&bp, bv, op);
+ }
+ }
+
/* Rebuild face polygons around affected vertices */
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index 386dc8a1fce..f8a77d431cc 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -33,6 +33,7 @@ void BM_mesh_bevel(
BMesh *bm, const float offset, const int offset_type, const float segments,
const float profile, const bool vertex_only, const bool use_weights,
const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
- const int mat, const bool loop_slide);
+ const int mat, const bool loop_slide, const bool mark_seam, const bool mark_sharp,
+ const int hnmode, void *mod_bmop_customdata);
#endif /* __BMESH_BEVEL_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index c1b2bc2625b..fa427b3b9eb 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -1354,7 +1354,7 @@ void BM_mesh_decimate_collapse(
/* simple non-mirror case */
while ((bm->totface > face_tot_target) &&
(BLI_heap_is_empty(eheap) == false) &&
- (BLI_heap_node_value(BLI_heap_top(eheap)) != COST_INVALID))
+ (BLI_heap_top_value(eheap) != COST_INVALID))
{
// const float value = BLI_heap_node_value(BLI_heap_top(eheap));
BMEdge *e = BLI_heap_pop_min(eheap);
@@ -1379,7 +1379,7 @@ void BM_mesh_decimate_collapse(
else {
while ((bm->totface > face_tot_target) &&
(BLI_heap_is_empty(eheap) == false) &&
- (BLI_heap_node_value(BLI_heap_top(eheap)) != COST_INVALID))
+ (BLI_heap_top_value(eheap) != COST_INVALID))
{
/**
* \note
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 49165b48668..1b37b7721b2 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -81,12 +81,6 @@
/* use accelerated overlap check */
#define USE_BVH
-// #define USE_BOOLEAN_RAYCAST_DRAW
-
-#ifdef USE_BOOLEAN_RAYCAST_DRAW
-/* insert bl_debug_draw_quad_clear... here */
-#endif
-
// #define USE_DUMP
static void tri_v3_scale(
@@ -1006,10 +1000,6 @@ bool BM_mesh_intersect(
int i_a, i_b;
#endif
-#ifdef USE_BOOLEAN_RAYCAST_DRAW
- bl_debug_draw_quad_clear();
-#endif
-
s.bm = bm;
s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
@@ -1607,17 +1597,6 @@ bool BM_mesh_intersect(
do_flip = (side == 0);
break;
}
-
-#ifdef USE_BOOLEAN_RAYCAST_DRAW
- {
- uint colors[4] = {0x00000000, 0xffffffff, 0xff000000, 0x0000ff};
- float co_other[3] = {UNPACK3(co)};
- co_other[0] += 1000.0f;
- bl_debug_color_set(colors[(hits & 1) == 1]);
- bl_debug_draw_edge_add(co, co_other);
- }
-#endif
-
}
if (do_remove) {
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index cc5ac6dd8ce..07e3c2a2d78 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -29,7 +29,7 @@
#include "BLI_math.h"
#include "BLI_linklist.h"
-#include "BLI_heap.h"
+#include "BLI_heap_simple.h"
#include "bmesh.h"
#include "bmesh_path.h" /* own include */
@@ -72,7 +72,7 @@ static float step_cost_3_v3(
/* BM_mesh_calc_path_vert */
static void verttag_add_adjacent(
- Heap *heap, BMVert *v_a, BMVert **verts_prev, float *cost,
+ HeapSimple *heap, BMVert *v_a, BMVert **verts_prev, float *cost,
const struct BMCalcPathParams *params)
{
const int v_a_index = BM_elem_index_get(v_a);
@@ -93,7 +93,7 @@ static void verttag_add_adjacent(
if (cost[v_b_index] > cost_new) {
cost[v_b_index] = cost_new;
verts_prev[v_b_index] = v_a;
- BLI_heap_insert(heap, cost_new, v_b);
+ BLI_heapsimple_insert(heap, cost_new, v_b);
}
}
}
@@ -119,7 +119,7 @@ static void verttag_add_adjacent(
if (cost[v_b_index] > cost_new) {
cost[v_b_index] = cost_new;
verts_prev[v_b_index] = v_a;
- BLI_heap_insert(heap, cost_new, v_b);
+ BLI_heapsimple_insert(heap, cost_new, v_b);
}
}
} while ((l_iter = l_iter->next) != l->prev);
@@ -136,7 +136,7 @@ LinkNode *BM_mesh_calc_path_vert(
/* BM_ELEM_TAG flag is used to store visited edges */
BMVert *v;
BMIter viter;
- Heap *heap;
+ HeapSimple *heap;
float *cost;
BMVert **verts_prev;
int i, totvert;
@@ -169,12 +169,12 @@ LinkNode *BM_mesh_calc_path_vert(
*/
/* regular dijkstra shortest path, but over faces instead of vertices */
- heap = BLI_heap_new();
- BLI_heap_insert(heap, 0.0f, v_src);
+ heap = BLI_heapsimple_new();
+ BLI_heapsimple_insert(heap, 0.0f, v_src);
cost[BM_elem_index_get(v_src)] = 0.0f;
- while (!BLI_heap_is_empty(heap)) {
- v = BLI_heap_pop_min(heap);
+ while (!BLI_heapsimple_is_empty(heap)) {
+ v = BLI_heapsimple_pop_min(heap);
if (v == v_dst)
break;
@@ -193,7 +193,7 @@ LinkNode *BM_mesh_calc_path_vert(
MEM_freeN(verts_prev);
MEM_freeN(cost);
- BLI_heap_free(heap, NULL);
+ BLI_heapsimple_free(heap, NULL);
return path;
}
@@ -221,7 +221,7 @@ static float edgetag_cut_cost_face(BMEdge *e_a, BMEdge *e_b, BMFace *f)
}
static void edgetag_add_adjacent(
- Heap *heap, BMEdge *e_a, BMEdge **edges_prev, float *cost,
+ HeapSimple *heap, BMEdge *e_a, BMEdge **edges_prev, float *cost,
const struct BMCalcPathParams *params)
{
const int e_a_index = BM_elem_index_get(e_a);
@@ -255,7 +255,7 @@ static void edgetag_add_adjacent(
if (cost[e_b_index] > cost_new) {
cost[e_b_index] = cost_new;
edges_prev[e_b_index] = e_a;
- BLI_heap_insert(heap, cost_new, e_b);
+ BLI_heapsimple_insert(heap, cost_new, e_b);
}
}
}
@@ -291,7 +291,7 @@ static void edgetag_add_adjacent(
if (cost[e_b_index] > cost_new) {
cost[e_b_index] = cost_new;
edges_prev[e_b_index] = e_a;
- BLI_heap_insert(heap, cost_new, e_b);
+ BLI_heapsimple_insert(heap, cost_new, e_b);
}
}
} while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_end);
@@ -308,7 +308,7 @@ LinkNode *BM_mesh_calc_path_edge(
/* BM_ELEM_TAG flag is used to store visited edges */
BMEdge *e;
BMIter eiter;
- Heap *heap;
+ HeapSimple *heap;
float *cost;
BMEdge **edges_prev;
int i, totedge;
@@ -341,12 +341,12 @@ LinkNode *BM_mesh_calc_path_edge(
*/
/* regular dijkstra shortest path, but over edges instead of vertices */
- heap = BLI_heap_new();
- BLI_heap_insert(heap, 0.0f, e_src);
+ heap = BLI_heapsimple_new();
+ BLI_heapsimple_insert(heap, 0.0f, e_src);
cost[BM_elem_index_get(e_src)] = 0.0f;
- while (!BLI_heap_is_empty(heap)) {
- e = BLI_heap_pop_min(heap);
+ while (!BLI_heapsimple_is_empty(heap)) {
+ e = BLI_heapsimple_pop_min(heap);
if (e == e_dst)
break;
@@ -365,7 +365,7 @@ LinkNode *BM_mesh_calc_path_edge(
MEM_freeN(edges_prev);
MEM_freeN(cost);
- BLI_heap_free(heap, NULL);
+ BLI_heapsimple_free(heap, NULL);
return path;
}
@@ -421,7 +421,7 @@ static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v, const vo
}
static void facetag_add_adjacent(
- Heap *heap, BMFace *f_a, BMFace **faces_prev, float *cost,
+ HeapSimple *heap, BMFace *f_a, BMFace **faces_prev, float *cost,
const void * const f_endpoints[2], const struct BMCalcPathParams *params)
{
const int f_a_index = BM_elem_index_get(f_a);
@@ -447,7 +447,7 @@ static void facetag_add_adjacent(
if (cost[f_b_index] > cost_new) {
cost[f_b_index] = cost_new;
faces_prev[f_b_index] = f_a;
- BLI_heap_insert(heap, cost_new, f_b);
+ BLI_heapsimple_insert(heap, cost_new, f_b);
}
}
} while ((l_iter = l_iter->radial_next) != l_first);
@@ -474,7 +474,7 @@ static void facetag_add_adjacent(
if (cost[f_b_index] > cost_new) {
cost[f_b_index] = cost_new;
faces_prev[f_b_index] = f_a;
- BLI_heap_insert(heap, cost_new, f_b);
+ BLI_heapsimple_insert(heap, cost_new, f_b);
}
}
}
@@ -491,7 +491,7 @@ LinkNode *BM_mesh_calc_path_face(
/* BM_ELEM_TAG flag is used to store visited edges */
BMFace *f;
BMIter fiter;
- Heap *heap;
+ HeapSimple *heap;
float *cost;
BMFace **faces_prev;
int i, totface;
@@ -527,12 +527,12 @@ LinkNode *BM_mesh_calc_path_face(
*/
/* regular dijkstra shortest path, but over faces instead of vertices */
- heap = BLI_heap_new();
- BLI_heap_insert(heap, 0.0f, f_src);
+ heap = BLI_heapsimple_new();
+ BLI_heapsimple_insert(heap, 0.0f, f_src);
cost[BM_elem_index_get(f_src)] = 0.0f;
- while (!BLI_heap_is_empty(heap)) {
- f = BLI_heap_pop_min(heap);
+ while (!BLI_heapsimple_is_empty(heap)) {
+ f = BLI_heapsimple_pop_min(heap);
if (f == f_dst)
break;
@@ -551,7 +551,7 @@ LinkNode *BM_mesh_calc_path_face(
MEM_freeN(faces_prev);
MEM_freeN(cost);
- BLI_heap_free(heap, NULL);
+ BLI_heapsimple_free(heap, NULL);
return path;
}
diff --git a/source/blender/collada/AnimationClipExporter.cpp b/source/blender/collada/AnimationClipExporter.cpp
new file mode 100644
index 00000000000..a2c4b388b7e
--- /dev/null
+++ b/source/blender/collada/AnimationClipExporter.cpp
@@ -0,0 +1,55 @@
+/*
+* ***** 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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "GeometryExporter.h"
+#include "AnimationClipExporter.h"
+#include "MaterialExporter.h"
+
+void AnimationClipExporter::exportAnimationClips(Scene *sce)
+{
+ openLibrary();
+ std::map<std::string, COLLADASW::ColladaAnimationClip *> clips;
+
+ std::vector<std::vector<std::string>>::iterator anim_meta_entry;
+ for (anim_meta_entry = anim_meta.begin(); anim_meta_entry != anim_meta.end(); ++anim_meta_entry) {
+ std::vector<std::string> entry = *anim_meta_entry;
+ std::string action_id = entry[0];
+ std::string action_name = entry[1];
+
+ std::map<std::string, COLLADASW::ColladaAnimationClip *>::iterator it = clips.find(action_name);
+ if (it == clips.end())
+ {
+ COLLADASW::ColladaAnimationClip *clip = new COLLADASW::ColladaAnimationClip(action_name);
+ clips[action_name] = clip;
+ }
+ COLLADASW::ColladaAnimationClip *clip = clips[action_name];
+ clip->setInstancedAnimation(action_id);
+ }
+
+ std::map<std::string, COLLADASW::ColladaAnimationClip *>::iterator clips_it;
+ for (clips_it = clips.begin(); clips_it != clips.end(); clips_it++) {
+ COLLADASW::ColladaAnimationClip *clip = (COLLADASW::ColladaAnimationClip *)clips_it->second;
+ addAnimationClip(*clip);
+ }
+
+ closeLibrary();
+}
diff --git a/source/blender/collada/AnimationClipExporter.h b/source/blender/collada/AnimationClipExporter.h
new file mode 100644
index 00000000000..8a9394ce88a
--- /dev/null
+++ b/source/blender/collada/AnimationClipExporter.h
@@ -0,0 +1,50 @@
+/*
+ * ***** 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): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "COLLADASWLibraryAnimationClips.h"
+
+
+class AnimationClipExporter:COLLADASW::LibraryAnimationClips {
+private:
+ Depsgraph *depsgraph;
+ Scene *scene;
+ COLLADASW::StreamWriter *sw;
+ const ExportSettings *export_settings;
+ std::vector<std::vector<std::string>> anim_meta;
+
+public:
+
+ AnimationClipExporter(Depsgraph *depsgraph , COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, std::vector<std::vector<std::string>> anim_meta) :
+ COLLADASW::LibraryAnimationClips(sw),
+ depsgraph(depsgraph),
+ scene(nullptr),
+ sw(sw),
+ export_settings(export_settings),
+ anim_meta(anim_meta)
+ {}
+
+ void exportAnimationClips(Scene *sce);
+};
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index e5c54fd9917..69a25ac7a82 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -20,658 +20,344 @@
* ***** END GPL LICENSE BLOCK *****
*/
+/** \file AnimationExporter.cpp
+ * \ingroup collada
+ */
+
#include "GeometryExporter.h"
#include "AnimationExporter.h"
+#include "AnimationClipExporter.h"
+#include "BCAnimationSampler.h"
#include "MaterialExporter.h"
+#include "collada_utils.h"
-template<class Functor>
-void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
-{
- LinkNode *node;
- for (node = export_set; node; node = node->next) {
- Object *ob = (Object *)node->link;
- f(ob);
- }
-}
+std::string EMPTY_STRING;
-bool AnimationExporter::exportAnimations(Main *bmain, Scene *sce)
+std::string AnimationExporter::get_axis_name(std::string channel, int id)
{
- bool has_animations = hasAnimations(sce);
- m_bmain = bmain;
- if (has_animations) {
- this->scene = sce;
+ static std::map<std::string, std::vector<std::string>> BC_COLLADA_AXIS_FROM_TYPE = {
+ { "color" ,{ "R", "G", "B" } },
+ { "specular_color",{ "R", "G", "B" } },
+ { "diffuse_color",{ "R", "G", "B" } },
+ { "alpha",{ "R", "G", "B" } },
+ { "scale",{ "X", "Y", "Z" } },
+ { "location",{ "X", "Y", "Z" } },
+ { "rotation_euler",{ "X", "Y", "Z" } }
+ };
- openLibrary();
+ std::map<std::string, std::vector<std::string>>::const_iterator it;
+ it = BC_COLLADA_AXIS_FROM_TYPE.find(channel);
+ if (it == BC_COLLADA_AXIS_FROM_TYPE.end())
+ return "";
- forEachObjectInExportSet(sce, *this, this->export_settings->export_set);
-
- closeLibrary();
- }
- return has_animations;
+ const std::vector<std::string> &subchannel = it->second;
+ if (id >= subchannel.size())
+ return "";
+ return subchannel[id];
}
-bool AnimationExporter::is_flat_line(std::vector<float> &values, int channel_count)
+bool AnimationExporter::open_animation_container(bool has_container, Object *ob)
{
- for (int i = 0; i < values.size(); i += channel_count) {
- for (int j = 0; j < channel_count; j++) {
- if (!bc_in_range(values[j], values[i+j], 0.000001))
- return false;
- }
+ if (!has_container) {
+ char anim_id[200];
+ sprintf(anim_id, "action_container-%s", translate_id(id_name(ob)).c_str());
+ openAnimation(anim_id, encode_xml(id_name(ob)));
}
return true;
}
-/*
- * This function creates a complete LINEAR Collada <Animation> Entry with all needed
- * <source>, <sampler>, and <channel> entries.
- * This is is used for creating sampled Transformation Animations for either:
- *
- * 1-axis animation:
- * times contains the time points in seconds from within the timeline
- * values contains the data (list of single floats)
- * channel_count = 1
- * axis_name = ['X' | 'Y' | 'Z']
- * is_rot indicates if the animation is a rotation
- *
- * 3-axis animation:
- * times contains the time points in seconds from within the timeline
- * values contains the data (list of floats where each 3 entries are one vector)
- * channel_count = 3
- * axis_name = "" (actually not used)
- * is_rot = false (see xxx below)
- *
- * xxx:
- * I tried to create a 3 axis rotation animation
- * like for translation or scale. But i could not
- * figure out how to setup the channel for this case.
- * So for now rotations are exported as 3 separate 1-axis collada animations
- * See export_sampled_animation() further down.
- */
-void AnimationExporter::create_sampled_animation(int channel_count,
- std::vector<float> &times,
- std::vector<float> &values,
- std::string ob_name,
- std::string label,
- std::string axis_name,
- bool is_rot)
-{
- char anim_id[200];
-
- if (is_flat_line(values, channel_count))
- return;
-
- BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), label.c_str(), axis_name.c_str());
-
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
- /* create input source */
- std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, times, false, anim_id, "");
-
- /* create output source */
- std::string output_id;
- if (channel_count == 1)
- output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, &values[0], values.size(), is_rot, anim_id, axis_name.c_str());
- else if (channel_count == 3)
- output_id = create_xyz_source(&values[0], times.size(), anim_id);
- else if (channel_count == 16)
- output_id = create_4x4_source(times, values, anim_id);
-
- std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
- COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
- std::string empty;
- sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
- sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
-
- /* TODO create in/out tangents source (LINEAR) */
- std::string interpolation_id = fake_interpolation_source(times.size(), anim_id, "");
-
- /* Create Sampler */
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
- addSampler(sampler);
-
- /* Create channel */
- std::string target = translate_id(ob_name) + "/" + label + axis_name + ((is_rot) ? ".ANGLE" : "");
- addChannel(COLLADABU::URI(empty, sampler_id), target);
-
- closeAnimation();
-
-}
-
-/*
- * Export all animation FCurves of an Object.
- *
- * Note: This uses the keyframes as sample points,
- * and exports "baked keyframes" while keeping the tangent information
- * of the FCurves intact. This works for simple cases, but breaks
- * especially when negative scales are involved in the animation.
- *
- * If it is necessary to conserve the Animation precisely then
- * use export_sampled_animation_set() instead.
- */
-void AnimationExporter::export_keyframed_animation_set(Object *ob)
+void AnimationExporter::openAnimationWithClip(std::string action_id, std::string action_name)
{
- FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
- if (!fcu) {
- return; /* object has no animation */
- }
-
- if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) {
+ std::vector<std::string> anim_meta_entry;
+ anim_meta_entry.push_back(translate_id(action_id));
+ anim_meta_entry.push_back(action_name);
+ anim_meta.push_back(anim_meta_entry);
- std::vector<float> ctimes;
- find_keyframes(ob, ctimes);
- if (ctimes.size() > 0)
- export_sampled_matrix_animation(ob, ctimes);
- }
- else {
- char *transformName;
- while (fcu) {
- //for armature animations as objects
- if (ob->type == OB_ARMATURE)
- transformName = fcu->rna_path;
- else
- transformName = extract_transform_name(fcu->rna_path);
-
- if (
- STREQ(transformName, "location") ||
- STREQ(transformName, "scale") ||
- (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
- STREQ(transformName, "rotation_quaternion"))
- {
- create_keyframed_animation(ob, fcu, transformName, false);
- }
- fcu = fcu->next;
- }
- }
+ openAnimation(translate_id(action_id), action_name);
}
-/*
- * Export the sampled animation of an Object.
- *
- * Note: This steps over all animation frames (step size is given in export_settings.sample_size)
- * and then evaluates the transformation,
- * and exports "baked samples" This works always, however currently the interpolation type is set
- * to LINEAR for now. (maybe later this can be changed to BEZIER)
- *
- * Note: If it is necessary to keep the FCurves intact, then use export_keyframed_animation_set() instead.
- * However be aware that exporting keyframed animation may modify the animation slightly.
- * Also keyframed animation exports tend to break when negative scales are involved.
- */
-void AnimationExporter::export_sampled_animation_set(Object *ob)
+void AnimationExporter::close_animation_container(bool has_container)
{
- std::vector<float>ctimes;
- find_sampleframes(ob, ctimes);
- if (ctimes.size() > 0) {
- if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX)
- export_sampled_matrix_animation(ob, ctimes);
- else
- export_sampled_transrotloc_animation(ob, ctimes);
- }
+ if (has_container)
+ closeAnimation();
}
-void AnimationExporter::export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes)
+bool AnimationExporter::exportAnimations()
{
- UnitConverter converter;
+ Scene *sce = blender_context.get_scene();
- std::vector<float> values;
+ LinkNode &export_set = *this->export_settings->export_set;
+ bool has_anim_data = bc_has_animations(sce, export_set);
+ int animation_count = 0;
+ if (has_anim_data) {
- for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime) {
- float fmat[4][4];
+ BCObjectSet animated_subset;
+ BCAnimationSampler::get_animated_from_export_set(animated_subset, export_set);
+ animation_count = animated_subset.size();
+ BCAnimationSampler animation_sampler(blender_context, animated_subset);
- bc_update_scene(m_bmain, scene, *ctime);
- BKE_object_matrix_local_get(ob, fmat);
- if (this->export_settings->limit_precision)
- bc_sanitize_mat(fmat, 6);
+ try {
+ animation_sampler.sample_scene(
+ export_settings->sampling_rate,
+ /*keyframe_at_end = */ true,
+ export_settings->open_sim,
+ export_settings->keep_keyframes,
+ export_settings->export_animation_type
+ );
- for (int i = 0; i < 4; i++)
- for (int j = 0; j < 4; j++)
- values.push_back(fmat[i][j]);
- }
-
- std::string ob_name = id_name(ob);
+ openLibrary();
- create_sampled_animation(16, ctimes, values, ob_name, "transform", "", false);
-}
+ BCObjectSet::iterator it;
+ for (it = animated_subset.begin(); it != animated_subset.end(); ++it) {
+ Object *ob = *it;
+ exportAnimation(ob, animation_sampler);
+ }
+ }
+ catch (std::invalid_argument &iae)
+ {
+ fprintf(stderr, "Animation export interrupted");
+ fprintf(stderr, "Exception was: %s", iae.what());
+ }
-void AnimationExporter::export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes)
-{
- static int LOC = 0;
- static int EULX = 1;
- static int EULY = 2;
- static int EULZ = 3;
- static int SCALE = 4;
-
- std::vector<float> baked_curves[5];
-
- for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime ) {
- float fmat[4][4];
- float floc[3];
- float fquat[4];
- float fsize[3];
- float feul[3];
-
- bc_update_scene(m_bmain, scene, *ctime);
- BKE_object_matrix_local_get(ob, fmat);
- mat4_decompose(floc, fquat, fsize, fmat);
- quat_to_eul(feul, fquat);
-
- baked_curves[LOC].push_back(floc[0]);
- baked_curves[LOC].push_back(floc[1]);
- baked_curves[LOC].push_back(floc[2]);
-
- baked_curves[EULX].push_back(feul[0]);
- baked_curves[EULY].push_back(feul[1]);
- baked_curves[EULZ].push_back(feul[2]);
-
- baked_curves[SCALE].push_back(fsize[0]);
- baked_curves[SCALE].push_back(fsize[1]);
- baked_curves[SCALE].push_back(fsize[2]);
+ closeLibrary();
+#if 0
+ /* TODO: If all actions shall be exported, we need to call the
+ * AnimationClipExporter which will figure out which actions
+ * need to be exported for which objects
+ */
+ if (this->export_settings->include_all_actions) {
+ AnimationClipExporter ace(eval_ctx, sw, export_settings, anim_meta);
+ ace.exportAnimationClips(sce);
+ }
+#endif
}
-
- std::string ob_name = id_name(ob);
-
- create_sampled_animation(3, ctimes, baked_curves[SCALE], ob_name, "scale", "", false);
- create_sampled_animation(3, ctimes, baked_curves[LOC], ob_name, "location", "", false);
-
- /* Not sure how to export rotation as a 3channel animation,
- * so separate into 3 single animations for now:
- */
-
- create_sampled_animation(1, ctimes, baked_curves[EULX], ob_name, "rotation", "X", true);
- create_sampled_animation(1, ctimes, baked_curves[EULY], ob_name, "rotation", "Y", true);
- create_sampled_animation(1, ctimes, baked_curves[EULZ], ob_name, "rotation", "Z", true);
-
- fprintf(stdout, "Animation Export: Baked %d frames for %s (sampling rate: %d)\n",
- (int)baked_curves[0].size(),
- ob->id.name,
- this->export_settings->sampling_rate);
+ return animation_count;
}
/* called for each exported object */
-void AnimationExporter::operator()(Object *ob)
+void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
{
- char *transformName;
+ bool container_is_open = false;
- /* bool isMatAnim = false; */ /* UNUSED */
+ //Transform animations (trans, rot, scale)
+ container_is_open = open_animation_container(container_is_open, ob);
- //Export transform animations
- if (ob->adt && ob->adt->action) {
+ /* Now take care of the Object Animations
+ * Note: For Armatures the skeletal animation has already been exported (see above)
+ * However Armatures also can have Object animation.
+ */
+ bool export_as_matrix = this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX;
+ if (export_as_matrix) {
+ export_matrix_animation(ob, sampler); // export all transform_curves as one single matrix animation
+ }
- if (ob->type == OB_ARMATURE) {
- /* Export skeletal animation (if any)*/
- bArmature *arm = (bArmature *)ob->data;
- for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next)
- write_bone_animation_matrix(ob, bone);
- }
+ export_curve_animation_set(ob, sampler, export_as_matrix);
- /* Armatures can have object animation and skeletal animation*/
- if (this->export_settings->sampling_rate < 1) {
- export_keyframed_animation_set(ob);
- }
- else {
- export_sampled_animation_set(ob);
- }
- }
+ if (ob->type == OB_ARMATURE) {
- export_object_constraint_animation(ob);
+#ifdef WITH_MORPH_ANIMATION
+ /* TODO: This needs to be handled by extra profiles, postponed for now */
+ export_morph_animation(ob);
+#endif
- //This needs to be handled by extra profiles, so postponed for now
- //export_morph_animation(ob);
+ /* Export skeletal animation (if any) */
+ bArmature *arm = (bArmature *)ob->data;
+ for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next)
+ export_bone_animations_recursive(ob, root_bone, sampler);
+ }
- //Export Lamp parameter animations
- if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
- FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
- while (fcu) {
- transformName = extract_transform_name(fcu->rna_path);
+ close_animation_container(container_is_open);
+}
- if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) ||
- (STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance")))
- {
- create_keyframed_animation(ob, fcu, transformName, true);
- }
- fcu = fcu->next;
+/*
+ * Export all animation FCurves of an Object.
+ *
+ * Note: This uses the keyframes as sample points,
+ * and exports "baked keyframes" while keeping the tangent information
+ * of the FCurves intact. This works for simple cases, but breaks
+ * especially when negative scales are involved in the animation.
+ * And when parent inverse matrices are involved (when exporting
+ * object hierarchies)
+ *
+ */
+void AnimationExporter::export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix)
+{
+ BCAnimationCurveMap *curves = sampler.get_curves(ob);
+
+ BCAnimationCurveMap::iterator it;
+ for (it = curves->begin(); it != curves->end(); ++it) {
+ BCAnimationCurve &curve = *it->second;
+ if (curve.get_channel_target() == "rotation_quaternion") {
+ /*
+ Can not export Quaternion animation in Collada as far as i know)
+ Maybe automatically convert to euler rotation?
+ Discard for now.
+ */
+ continue;
+ }
+
+ if (export_as_matrix && curve.is_transform_curve()) {
+ /* All Transform curves will be exported within a single matrix animation,
+ * see export_matrix_animation()
+ * No need to export the curves here again.
+ */
+ continue;
}
- }
- //Export Camera parameter animations
- if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) {
- FCurve *fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
- while (fcu) {
- transformName = extract_transform_name(fcu->rna_path);
-
- if ((STREQ(transformName, "lens")) ||
- (STREQ(transformName, "ortho_scale")) ||
- (STREQ(transformName, "clip_end")) ||
- (STREQ(transformName, "clip_start")))
- {
- create_keyframed_animation(ob, fcu, transformName, true);
- }
- fcu = fcu->next;
+ if (!curve.is_animated()) {
+ continue;
}
- }
- //Export Material parameter animations.
- for (int a = 0; a < ob->totcol; a++) {
- Material *ma = give_current_material(ob, a + 1);
- if (!ma) continue;
- if (ma->adt && ma->adt->action) {
- /* isMatAnim = true; */
- FCurve *fcu = (FCurve *)ma->adt->action->curves.first;
- while (fcu) {
- transformName = extract_transform_name(fcu->rna_path);
-
- if ((STREQ(transformName, "specular_hardness")) || (STREQ(transformName, "specular_color")) ||
- (STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) ||
- (STREQ(transformName, "ior")))
- {
- create_keyframed_animation(ob, fcu, transformName, true, ma);
- }
- fcu = fcu->next;
- }
+ BCAnimationCurve *mcurve = get_modified_export_curve(ob, curve, *curves);
+ if (mcurve) {
+ export_curve_animation(ob, *mcurve);
+ delete mcurve;
+ }
+ else {
+ export_curve_animation(ob, curve);
}
}
}
-void AnimationExporter::export_object_constraint_animation(Object *ob)
+void AnimationExporter::export_matrix_animation(Object *ob, BCAnimationSampler &sampler)
{
- std::vector<float> fra;
- //Takes frames of target animations
- make_anim_frames_from_targets(ob, fra);
+ std::vector<float> frames;
+ sampler.get_object_frames(frames, ob);
+ if (frames.size() > 0) {
+ BCMatrixSampleMap samples;
+ bool is_animated = sampler.get_object_samples(samples, ob);
+ if (is_animated) {
+ bAction *action = bc_getSceneObjectAction(ob);
+ std::string name = encode_xml(id_name(ob));
+ std::string action_name = (action == NULL) ? name + "-action" : id_name(action);
+ std::string channel_type = "transform";
+ std::string axis = "";
+ std::string id = bc_get_action_id(action_name, name, channel_type, axis);
- if (fra.size())
- dae_baked_object_animation(fra, ob);
-}
+ std::string target = translate_id(name) + '/' + channel_type;
-void AnimationExporter::export_morph_animation(Object *ob)
-{
- FCurve *fcu;
- char *transformName;
- Key *key = BKE_key_from_object(ob);
- if (!key) return;
-
- if (key->adt && key->adt->action) {
- fcu = (FCurve *)key->adt->action->curves.first;
-
- while (fcu) {
- transformName = extract_transform_name(fcu->rna_path);
-
- create_keyframed_animation(ob, fcu, transformName, true);
-
- fcu = fcu->next;
+ export_collada_matrix_animation(id, name, target, frames, samples);
}
}
-
}
-void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<float> &frames )
+//write bone animations in transform matrix sources
+void AnimationExporter::export_bone_animations_recursive(Object *ob, Bone *bone, BCAnimationSampler &sampler)
{
- ListBase *conlist = get_active_constraints(ob);
- if (conlist == NULL) return;
- bConstraint *con;
- for (con = (bConstraint *)conlist->first; con; con = con->next) {
- ListBase targets = {NULL, NULL};
-
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- if (!validateConstraints(con)) continue;
-
- if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
- Object *obtar;
- /* get targets
- * - constraints should use ct->matrix, not directly accessing values
- * - ct->matrix members have not yet been calculated here!
- */
- cti->get_constraint_targets(con, &targets);
+ std::vector<float> frames;
+ sampler.get_bone_frames(frames, ob, bone);
- for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
- obtar = ct->tar;
-
- if (obtar)
- find_keyframes(obtar, frames);
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
+ if (frames.size()) {
+ BCMatrixSampleMap samples;
+ bool is_animated = sampler.get_bone_samples(samples, ob, bone);
+ if (is_animated) {
+ export_bone_animation(ob, bone, frames, samples);
}
}
+
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
+ export_bone_animations_recursive(ob, child, sampler);
}
-//euler sources from quternion sources
-float *AnimationExporter::get_eul_source_for_quat(Object *ob)
-{
- FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
- const int keys = fcu->totvert;
- float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");
- float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
- float temp_quat[4];
- float temp_eul[3];
- while (fcu) {
- char *transformName = extract_transform_name(fcu->rna_path);
-
- if (STREQ(transformName, "rotation_quaternion") ) {
- for (int i = 0; i < fcu->totvert; i++) {
- *(quat + (i * 4) + fcu->array_index) = fcu->bezt[i].vec[1][1];
+/*
+* In some special cases the exported Curve needs to be replaced
+* by a modified curve (for collada purposes)
+* This method checks if a conversion is necessary and if applicable
+* returns a pointer to the modified BCAnimationCurve.
+* IMPORTANT: the modified curve must be deleted by the caller when no longer needed
+* if no conversion is needed this method returns a NULL;
+*/
+BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves)
+{
+ std::string channel_target = curve.get_channel_target();
+ BCAnimationCurve *mcurve = NULL;
+ if (channel_target == "lens") {
+
+ /* Create an xfov curve */
+
+ BCCurveKey key(BC_ANIMATION_TYPE_CAMERA, "xfov", 0);
+ mcurve = new BCAnimationCurve(key, ob);
+
+ // now tricky part: transform the fcurve
+ BCValueMap lens_values;
+ curve.get_value_map(lens_values);
+
+ BCAnimationCurve *sensor_curve = NULL;
+ BCCurveKey sensor_key(BC_ANIMATION_TYPE_CAMERA, "sensor_width", 0);
+ BCAnimationCurveMap::iterator cit = curves.find(sensor_key);
+ if (cit != curves.end()) {
+ sensor_curve = cit->second;
+ }
+
+ BCValueMap::const_iterator vit;
+ for (vit = lens_values.begin(); vit != lens_values.end(); ++vit) {
+ int frame = vit->first;
+ float lens_value = vit->second;
+
+ float sensor_value;
+ if (sensor_curve) {
+ sensor_value = sensor_curve->get_value(frame);
+ }
+ else {
+ sensor_value = ((Camera *)ob->data)->sensor_x;
}
+ float value = RAD2DEGF(focallength_to_fov(lens_value, sensor_value));
+ mcurve->add_value(value, frame);
}
- fcu = fcu->next;
+ mcurve->clean_handles(); // to reset the handles
}
-
- for (int i = 0; i < keys; i++) {
- for (int j = 0; j < 4; j++)
- temp_quat[j] = quat[(i * 4) + j];
-
- quat_to_eul(temp_eul, temp_quat);
-
- for (int k = 0; k < 3; k++)
- eul[i * 3 + k] = temp_eul[k];
-
- }
- MEM_freeN(quat);
- return eul;
-
-}
-
-//Get proper name for bones
-std::string AnimationExporter::getObjectBoneName(Object *ob, const FCurve *fcu)
-{
- //hard-way to derive the bone name from rna_path. Must find more compact method
- std::string rna_path = std::string(fcu->rna_path);
-
- char *boneName = strtok((char *)rna_path.c_str(), "\"");
- boneName = strtok(NULL, "\"");
-
- if (boneName != NULL)
- return /*id_name(ob) + "_" +*/ std::string(boneName);
- else
- return id_name(ob);
+ return mcurve;
}
-std::string AnimationExporter::getAnimationPathId(const FCurve *fcu)
+void AnimationExporter::export_curve_animation(
+ Object *ob,
+ BCAnimationCurve &curve)
{
- std::string rna_path = std::string(fcu->rna_path);
- return translate_id(rna_path);
-}
-
-/* convert f-curves to animation curves and write */
-void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma)
-{
- const char *axis_name = NULL;
- char anim_id[200];
-
- bool has_tangents = false;
- bool quatRotation = false;
-
- Object *obj = NULL;
-
- if (STREQ(transformName, "rotation_quaternion") ) {
- fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
- quatRotation = true;
- return;
- }
-
- //axis names for colors
- else if (STREQ(transformName, "color") ||
- STREQ(transformName, "specular_color") ||
- STREQ(transformName, "diffuse_color") ||
- STREQ(transformName, "alpha"))
- {
- const char *axis_names[] = {"R", "G", "B"};
- if (fcu->array_index < 3)
- axis_name = axis_names[fcu->array_index];
- }
+ std::string channel_target = curve.get_channel_target();
/*
- * Note: Handle transformation animations separately (to apply matrix inverse to fcurves)
- * We will use the object to evaluate the animation on all keyframes and calculate the
- * resulting object matrix. We need this to incorporate the
- * effects of the parent inverse matrix (when it contains a rotation component)
- *
- * TODO: try to combine exported fcurves into 3 channel animations like done
- * in export_sampled_animation(). For now each channel is exported as separate <Animation>.
+ * Some curves can not be exported as is and need some conversion
+ * For more information see implementation oif get_modified_export_curve()
+ * note: if mcurve is not NULL then it must be deleted at end of this method;
*/
- else if (
- STREQ(transformName, "scale") ||
- STREQ(transformName, "location") ||
- STREQ(transformName, "rotation_euler"))
- {
- const char *axis_names[] = {"X", "Y", "Z"};
- if (fcu->array_index < 3) {
- axis_name = axis_names[fcu->array_index];
- obj = ob;
- }
- }
- else {
- /* no axis name. single parameter */
- axis_name = "";
- }
+ int channel_index = curve.get_channel_index();
+ std::string axis = get_axis_name(channel_target, channel_index); // RGB or XYZ or ""
- std::string ob_name = std::string("null");
+ std::string action_name;
+ bAction *action = bc_getSceneObjectAction(ob);
+ action_name = (action) ? id_name(action) : "constraint_anim";
- /* Create anim Id */
- if (ob->type == OB_ARMATURE) {
- ob_name = getObjectBoneName(ob, fcu);
- BLI_snprintf(
- anim_id,
- sizeof(anim_id),
- "%s_%s.%s",
- (char *)translate_id(ob_name).c_str(),
- (char *)translate_id(transformName).c_str(),
- axis_name);
- }
- else {
- if (ma)
- ob_name = id_name(ob) + "_material";
- else
- ob_name = id_name(ob);
-
- BLI_snprintf(
- anim_id,
- sizeof(anim_id),
- "%s_%s_%s",
- (char *)translate_id(ob_name).c_str(),
- (char *)getAnimationPathId(fcu).c_str(),
- axis_name);
- }
-
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
-
- // create input source
- std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
+ const std::string curve_name = encode_xml(curve.get_animation_name(ob));
+ std::string id = bc_get_action_id(action_name, curve_name, channel_target, axis, ".");
- // create output source
- std::string output_id;
+ std::string collada_target = translate_id(curve_name);
- //quat rotations are skipped for now, because of complications with determining axis.
- if (quatRotation) {
- float *eul = get_eul_source_for_quat(ob);
- float *eul_axis = (float *)MEM_callocN(sizeof(float) * fcu->totvert, "quat output source values");
- for (int i = 0; i < fcu->totvert; i++) {
- eul_axis[i] = eul[i * 3 + fcu->array_index];
+ if (curve.is_of_animation_type(BC_ANIMATION_TYPE_MATERIAL)) {
+ int material_index = curve.get_subindex();
+ Material *ma = give_current_material(ob, material_index + 1);
+ if (ma) {
+ collada_target = translate_id(id_name(ma)) + "-effect/common/" + get_collada_sid(curve, axis);
}
- output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis, fcu->totvert, quatRotation, anim_id, axis_name);
- MEM_freeN(eul);
- MEM_freeN(eul_axis);
- }
- else if (STREQ(transformName, "lens") && (ob->type == OB_CAMERA)) {
- output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id);
}
else {
- output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name, obj);
+ collada_target += "/" + get_collada_sid(curve, axis);
}
- // create interpolations source
- std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents);
-
- // handle tangents (if required)
- std::string intangent_id;
- std::string outtangent_id;
+ export_collada_curve_animation(id, curve_name, collada_target, axis, curve);
- if (has_tangents) {
- // create in_tangent source
- intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name, obj);
-
- // create out_tangent source
- outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name, obj);
- }
-
- std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
- COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
- std::string empty;
- sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
- sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
-
- // this input is required
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
-
- if (has_tangents) {
- sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id));
- sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id));
- }
-
- addSampler(sampler);
-
- std::string target;
-
- if (!is_param)
- target = translate_id(ob_name) +
- "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
- else {
- if (ob->type == OB_LAMP)
- target = get_light_id(ob) +
- "/" + get_light_param_sid(fcu->rna_path, -1, axis_name, true);
-
- if (ob->type == OB_CAMERA)
- target = get_camera_id(ob) +
- "/" + get_camera_param_sid(fcu->rna_path, -1, axis_name, true);
-
- if (ma)
- target = translate_id(id_name(ma)) + "-effect" +
- "/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
- //if shape key animation, this is the main problem, how to define the channel targets.
- /*target = get_morph_id(ob) +
- "/value" +*/
- }
- addChannel(COLLADABU::URI(empty, sampler_id), target);
-
- closeAnimation();
}
-
-
-//write bone animations in transform matrix sources
-void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone)
+void AnimationExporter::export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples)
{
- if (!ob_arm->adt)
- return;
-
- //This will only export animations of bones in deform group.
- /* if (!is_bone_deform_group(bone)) return; */
+ bAction* action = bc_getSceneObjectAction(ob);
+ std::string bone_name(bone->name);
+ std::string name = encode_xml(id_name(ob));
+ std::string id = bc_get_action_id(id_name(action), name, bone_name, "pose_matrix");
+ std::string target = translate_id(id_name(ob) + "_" + bone_name) + "/transform";
- sample_and_write_bone_animation_matrix(ob_arm, bone);
-
- for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
- write_bone_animation_matrix(ob_arm, child);
+ export_collada_matrix_animation(id, name, target, frames, samples);
}
bool AnimationExporter::is_bone_deform_group(Bone *bone)
@@ -691,204 +377,86 @@ bool AnimationExporter::is_bone_deform_group(Bone *bone)
return false;
}
-void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone)
-{
- bArmature *arm = (bArmature *)ob_arm->data;
- int flag = arm->flag;
- std::vector<float> fra;
- //char prefix[256];
-
- //Check if there is a fcurve in the armature for the bone in param
- //when baking this check is not needed, solve every bone for every frame.
- /*FCurve *fcu = (FCurve *)ob_arm->adt->action->curves.first;
-
- while (fcu) {
- std::string bone_name = getObjectBoneName(ob_arm, fcu);
- int val = BLI_strcasecmp((char *)bone_name.c_str(), bone->name);
- if (val == 0) break;
- fcu = fcu->next;
- }
- if (!(fcu)) return;*/
+void AnimationExporter::export_collada_curve_animation(
+ std::string id,
+ std::string name,
+ std::string collada_target,
+ std::string axis,
+ BCAnimationCurve &curve)
+{
+ BCFrames frames;
+ BCValues values;
+ curve.get_frames(frames);
+ curve.get_values(values);
+ std::string channel_target = curve.get_channel_target();
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
- if (!pchan)
- return;
+ fprintf(stdout, "Export animation curve %s (%d control points)\n", id.c_str(), int(frames.size()));
+ openAnimation(id, name);
+ BC_animation_source_type source_type = (curve.is_rotation_curve()) ? BC_SOURCE_TYPE_ANGLE : BC_SOURCE_TYPE_VALUE;
+ std::string input_id = collada_source_from_values(BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, axis);
+ std::string output_id = collada_source_from_values(source_type, COLLADASW::InputSemantic::OUTPUT, values, id, axis);
- if (this->export_settings->sampling_rate < 1)
- find_keyframes(ob_arm, fra);
+ bool has_tangents = false;
+ std::string interpolation_id;
+ if (this->export_settings->keep_smooth_curves)
+ interpolation_id = collada_interpolation_source(curve, id, axis, &has_tangents);
else
- find_sampleframes(ob_arm, fra);
+ interpolation_id = collada_linear_interpolation_source(frames.size(), id);
- if (flag & ARM_RESTPOS) {
- arm->flag &= ~ARM_RESTPOS;
- BKE_pose_where_is(scene, ob_arm);
- }
-
- if (fra.size()) {
- dae_baked_animation(fra, ob_arm, bone);
+ std::string intangent_id;
+ std::string outtangent_id;
+ if (has_tangents) {
+ intangent_id = collada_tangent_from_curve(COLLADASW::InputSemantic::IN_TANGENT, curve, id, axis);
+ outtangent_id = collada_tangent_from_curve(COLLADASW::InputSemantic::OUT_TANGENT, curve, id, axis);
}
- if (flag & ARM_RESTPOS)
- arm->flag = flag;
- BKE_pose_where_is(scene, ob_arm);
-}
-
-void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_arm, Bone *bone)
-{
- std::string ob_name = id_name(ob_arm);
- std::string bone_name = bone->name;
- char anim_id[200];
-
- if (!fra.size())
- return;
-
- BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(),
- (char *)translate_id(bone_name).c_str(), "pose_matrix");
+ std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
-
- // create input source
- std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
-
- // create output source
- std::string output_id;
-
- output_id = create_4x4_source(fra, ob_arm, bone, anim_id);
-
- // create interpolations source
- std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
-
- std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
- std::string empty;
- sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
- sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
- // TODO create in/out tangents source
+ sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
+ sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
+ sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(EMPTY_STRING, interpolation_id));
- // this input is required
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+ if (has_tangents) {
+ sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(EMPTY_STRING, intangent_id));
+ sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(EMPTY_STRING, outtangent_id));
+ }
addSampler(sampler);
-
- std::string target = get_joint_id(ob_arm, bone) + "/transform";
- addChannel(COLLADABU::URI(empty, sampler_id), target);
+ addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), collada_target);
closeAnimation();
}
-void AnimationExporter::dae_baked_object_animation(std::vector<float> &fra, Object *ob)
+void AnimationExporter::export_collada_matrix_animation(std::string id, std::string name, std::string target, BCFrames &frames, BCMatrixSampleMap &samples)
{
- std::string ob_name = id_name(ob);
- char anim_id[200];
-
- if (!fra.size())
- return;
+ fprintf(stdout, "Export animation matrix %s (%d control points)\n", id.c_str(), int(frames.size()));
- BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s", (char *)translate_id(ob_name).c_str(),
- "object_matrix");
+ openAnimationWithClip(id, name);
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
+ std::string input_id = collada_source_from_values(BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, "");
+ std::string output_id = collada_source_from_values(samples, id);
+ std::string interpolation_id = collada_linear_interpolation_source(frames.size(), id);
- // create input source
- std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
-
- // create output source
- std::string output_id;
- output_id = create_4x4_source( fra, ob, NULL, anim_id);
-
- // create interpolations source
- std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
-
- std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
+ std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
- std::string empty;
- sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
- sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
- // TODO create in/out tangents source
- // this input is required
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
-
- addSampler(sampler);
+ sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
+ sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
+ sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(EMPTY_STRING, interpolation_id));
- std::string target = translate_id(ob_name) + "/transform";
- addChannel(COLLADABU::URI(empty, sampler_id), target);
-
- closeAnimation();
-}
-
-// dae_bone_animation -> add_bone_animation
-// (blend this into dae_bone_animation)
-void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, int tm_type, int axis, std::string ob_name, std::string bone_name)
-{
- const char *axis_names[] = {"X", "Y", "Z"};
- const char *axis_name = NULL;
- char anim_id[200];
- bool is_rot = tm_type == 0;
-
- if (!fra.size())
- return;
-
- char rna_path[200];
- BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
- tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
-
- if (axis > -1)
- axis_name = axis_names[axis];
-
- std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name, false);
-
- BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(),
- (char *)translate_id(bone_name).c_str(), (char *)transform_sid.c_str());
-
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
-
- // create input source
- std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
-
- // create output source
- std::string output_id;
- if (axis == -1)
- output_id = create_xyz_source(values, fra.size(), anim_id);
- else
- output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name);
-
- // create interpolations source
- std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name);
-
- std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
- COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
- std::string empty;
- sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
- sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
-
- // TODO create in/out tangents source
-
- // this input is required
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+ // Matrix animation has no tangents
addSampler(sampler);
-
- std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
- addChannel(COLLADABU::URI(empty, sampler_id), target);
+ addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), target);
closeAnimation();
}
-float AnimationExporter::convert_time(float frame)
-{
- return FRA2TIME(frame);
-}
-
-float AnimationExporter::convert_angle(float angle)
-{
- return COLLADABU::Math::Utils::radToDegF(angle);
-}
-
std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
{
switch (semantic) {
@@ -909,7 +477,10 @@ std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Sem
}
void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
- COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform)
+ COLLADASW::InputSemantic::Semantics semantic,
+ bool is_rot,
+ const std::string axis,
+ bool transform)
{
switch (semantic) {
case COLLADASW::InputSemantic::INPUT:
@@ -920,7 +491,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa
param.push_back("ANGLE");
}
else {
- if (axis) {
+ if (axis != "") {
param.push_back(axis);
}
else
@@ -944,262 +515,83 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa
}
}
-void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length)
+std::string AnimationExporter::collada_tangent_from_curve(COLLADASW::InputSemantic::Semantics semantic, BCAnimationCurve &curve, const std::string& anim_id, std::string axis_name)
{
- switch (semantic) {
- case COLLADASW::InputSemantic::INPUT:
- *length = 1;
- values[0] = convert_time(bezt->vec[1][0]);
- break;
- case COLLADASW::InputSemantic::OUTPUT:
- *length = 1;
- if (is_angle) {
- values[0] = RAD2DEGF(bezt->vec[1][1]);
- }
- else {
- values[0] = bezt->vec[1][1];
- }
- break;
+ Scene *scene = blender_context.get_scene();
+ std::string channel = curve.get_channel_target();
- case COLLADASW::InputSemantic::IN_TANGENT:
- *length = 2;
- values[0] = convert_time(bezt->vec[0][0]);
- if (bezt->ipo != BEZT_IPO_BEZ) {
- // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
- values[0] = 0;
- values[1] = 0;
- }
- else if (is_angle) {
- values[1] = RAD2DEGF(bezt->vec[0][1]);
- }
- else {
- values[1] = bezt->vec[0][1];
- }
- break;
+ const std::string source_id = anim_id + get_semantic_suffix(semantic);
- case COLLADASW::InputSemantic::OUT_TANGENT:
- *length = 2;
- values[0] = convert_time(bezt->vec[2][0]);
- if (bezt->ipo != BEZT_IPO_BEZ) {
- // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
- values[0] = 0;
- values[1] = 0;
- }
- else if (is_angle) {
- values[1] = RAD2DEGF(bezt->vec[2][1]);
- }
- else {
- values[1] = bezt->vec[2][1];
- }
- break;
- default:
- *length = 0;
- break;
- }
-}
-
-// old function to keep compatibility for calls where offset and object are not needed
-std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
-{
- return create_source_from_fcurve(semantic, fcu, anim_id, axis_name, NULL);
-}
-
-void AnimationExporter::evaluate_anim_with_constraints(Object *ob, float ctime)
-{
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
- ListBase *conlist = get_active_constraints(ob);
- bConstraint *con;
- for (con = (bConstraint *)conlist->first; con; con = con->next) {
- ListBase targets = { NULL, NULL };
-
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
- Object *obtar;
- cti->get_constraint_targets(con, &targets);
- for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
- obtar = ct->tar;
-
- if (obtar) {
- BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM);
- BKE_object_where_is_calc_time(scene, obtar, ctime);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
- BKE_object_where_is_calc_time(scene, ob, ctime);
-}
-
-/*
- * ob is needed to aply parent inverse information to fcurve.
- * TODO: Here we have to step over all keyframes for each object and for each fcurve.
- * Instead of processing each fcurve one by one,
- * step over the animation from keyframe to keyframe,
- * then create adjusted fcurves (and entries) for all affected objects.
- * Then we would need to step through the scene only once.
- */
-std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob)
-{
- std::string source_id = anim_id + get_semantic_suffix(semantic);
-
- bool is_angle = (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path, "spot_size"));
- bool is_euler = strstr(fcu->rna_path, "rotation_euler");
- bool is_translation = strstr(fcu->rna_path, "location");
- bool is_scale = strstr(fcu->rna_path, "scale");
- bool is_tangent = false;
- int offset_index = 0;
+ bool is_angle = (bc_startswith(channel, "rotation") || channel == "spot_size");
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(fcu->totvert);
-
- switch (semantic) {
- case COLLADASW::InputSemantic::INPUT:
- case COLLADASW::InputSemantic::OUTPUT:
- source.setAccessorStride(1);
- offset_index = 0;
- break;
- case COLLADASW::InputSemantic::IN_TANGENT:
- case COLLADASW::InputSemantic::OUT_TANGENT:
- source.setAccessorStride(2);
- offset_index = 1;
- is_tangent = true;
- break;
- default:
- break;
- }
+ source.setAccessorCount(curve.sample_count());
+ source.setAccessorStride(2);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, is_angle, axis_name, false);
source.prepareToAppendValues();
- for (unsigned int frame_index = 0; frame_index < fcu->totvert; frame_index++) {
- float fixed_val = 0;
- if (ob) {
- float fmat[4][4];
- float frame = fcu->bezt[frame_index].vec[1][0];
- float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
-
- evaluate_anim_with_constraints(ob, ctime); // set object transforms to fcurve's i'th keyframe
-
- BKE_object_matrix_local_get(ob, fmat);
- float floc[3];
- float fquat[4];
- float fsize[3];
- mat4_decompose(floc, fquat, fsize, fmat);
-
- if (is_euler) {
- float eul[3];
- quat_to_eul(eul, fquat);
- fixed_val = RAD2DEGF(eul[fcu->array_index]);
- }
- else if (is_translation) {
- fixed_val = floc[fcu->array_index];
- }
- else if (is_scale) {
- fixed_val = fsize[fcu->array_index];
- }
- }
+ const FCurve *fcu = curve.get_fcurve();
+ int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2;
- float values[3]; // be careful!
- float offset = 0;
- int length = 0;
- get_source_values(&fcu->bezt[frame_index], semantic, is_angle, values, &length);
- if (is_tangent) {
- float bases[3];
- int len = 0;
- get_source_values(&fcu->bezt[frame_index], COLLADASW::InputSemantic::OUTPUT, is_angle, bases, &len);
- offset = values[offset_index] - bases[0];
- }
+ for (int i = 0; i < fcu->totvert; ++i) {
+ BezTriple &bezt = fcu->bezt[i];
- for (int j = 0; j < length; j++) {
- float val;
- if (j == offset_index) {
- if (ob) {
- val = fixed_val + offset;
- }
- else {
- val = values[j] + offset;
- }
- } else {
- val = values[j];
- }
- source.appendValues(val);
- }
- }
-
- source.finish();
+ float sampled_time = bezt.vec[tangent][0];
+ float sampled_val = bezt.vec[tangent][1];
- return source_id;
-}
-
-/*
- * Similar to create_source_from_fcurve, but adds conversion of lens
- * animation data from focal length to FOV.
- */
-std::string AnimationExporter::create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id)
-{
- std::string source_id = anim_id + get_semantic_suffix(semantic);
-
- COLLADASW::FloatSourceF source(mSW);
- source.setId(source_id);
- source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(fcu->totvert);
-
- source.setAccessorStride(1);
-
- COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, false, "", false);
+ if (is_angle) {
+ sampled_val = RAD2DEGF(sampled_val);
+ }
- source.prepareToAppendValues();
+ source.appendValues(FRA2TIME(sampled_time));
+ source.appendValues(sampled_val);
- for (unsigned int i = 0; i < fcu->totvert; i++) {
- float values[3]; // be careful!
- int length = 0;
- get_source_values(&fcu->bezt[i], semantic, false, values, &length);
- for (int j = 0; j < length; j++)
- {
- float val = RAD2DEGF(focallength_to_fov(values[j], cam->sensor_x));
- source.appendValues(val);
- }
}
-
source.finish();
-
return source_id;
}
-/*
- * only to get OUTPUT source values ( if rotation and hence the axis is also specified )
- */
-std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
+std::string AnimationExporter::collada_source_from_values(
+ BC_animation_source_type source_type,
+ COLLADASW::InputSemantic::Semantics semantic,
+ std::vector<float> &values,
+ const std::string& anim_id,
+ const std::string axis_name)
{
+ Scene *scene = blender_context.get_scene();
+ /* T can be float, int or double */
+
+ int stride = 1;
+ int entry_count = values.size() / stride;
std::string source_id = anim_id + get_semantic_suffix(semantic);
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(tot);
- source.setAccessorStride(1);
+ source.setAccessorCount(entry_count);
+ source.setAccessorStride(stride);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, is_rot, axis_name, false);
+ add_source_parameters(param, semantic, source_type== BC_SOURCE_TYPE_ANGLE, axis_name, false);
source.prepareToAppendValues();
- for (int i = 0; i < tot; i++) {
- float val = v[i];
- ////if (semantic == COLLADASW::InputSemantic::INPUT)
- // val = convert_time(val);
- //else
- if (is_rot)
+ for (int i = 0; i < entry_count; i++) {
+ float val = values[i];
+ switch (source_type) {
+ case BC_SOURCE_TYPE_TIMEFRAME:
+ val = FRA2TIME(val);
+ break;
+ case BC_SOURCE_TYPE_ANGLE:
val = RAD2DEGF(val);
+ break;
+ default: break;
+ }
source.appendValues(val);
}
@@ -1209,39 +601,9 @@ std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic
}
/*
- * only used for sources with INPUT semantic
- */
-std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
-{
- std::string source_id = anim_id + get_semantic_suffix(semantic);
-
- COLLADASW::FloatSourceF source(mSW);
- source.setId(source_id);
- source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(fra.size());
- source.setAccessorStride(1);
-
- COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, is_rot, axis_name, false);
-
- source.prepareToAppendValues();
-
- std::vector<float>::iterator it;
- for (it = fra.begin(); it != fra.end(); it++) {
- float val = *it;
- //if (semantic == COLLADASW::InputSemantic::INPUT)
- val = convert_time(val);
- /*else if (is_rot)
- val = convert_angle(val);*/
- source.appendValues(val);
- }
-
- source.finish();
-
- return source_id;
-}
-
-std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std::vector<float> &values , const std::string &anim_id)
+ * Create a collada matrix source for a set of samples
+*/
+std::string AnimationExporter::collada_source_from_values(BCMatrixSampleMap &samples, const std::string &anim_id)
{
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
std::string source_id = anim_id + get_semantic_suffix(semantic);
@@ -1249,180 +611,38 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std
COLLADASW::Float4x4Source source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(ctimes.size());
+ source.setAccessorCount(samples.size());
source.setAccessorStride(16);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, false, NULL, true);
+ add_source_parameters(param, semantic, false, "", true);
source.prepareToAppendValues();
- std::vector<float>::iterator it;
-
- for (it = values.begin(); it != values.end(); it+=16) {
- float mat[4][4];
-
- bc_copy_m4_farray(mat, &*it);
-
- UnitConverter converter;
- double outmat[4][4];
- converter.mat4_to_dae_double(outmat, mat);
-
- if (this->export_settings->limit_precision)
- bc_sanitize_mat(outmat, 6);
-
- source.appendValues(outmat);
+ BCMatrixSampleMap::iterator it;
+ int precision = (this->export_settings->limit_precision) ? 6 : -1; // could be made configurable
+ for (it = samples.begin(); it != samples.end(); it++) {
+ const BCMatrix *sample = it->second;
+ double daemat[4][4];
+ sample->get_matrix(daemat, true, precision);
+ source.appendValues(daemat);
}
source.finish();
return source_id;
}
-std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id)
-{
- bool is_bone_animation = ob->type == OB_ARMATURE && bone;
-
- COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
- std::string source_id = anim_id + get_semantic_suffix(semantic);
-
- COLLADASW::Float4x4Source source(mSW);
- source.setId(source_id);
- source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(frames.size());
- source.setAccessorStride(16);
-
- COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, false, NULL, true);
-
- source.prepareToAppendValues();
-
- bPoseChannel *parchan = NULL;
- bPoseChannel *pchan = NULL;
-
- if (is_bone_animation) {
- bPose *pose = ob->pose;
- pchan = BKE_pose_channel_find_name(pose, bone->name);
- if (!pchan)
- return "";
-
- parchan = pchan->parent;
-
- enable_fcurves(ob->adt->action, bone->name);
- }
-
- std::vector<float>::iterator it;
- int j = 0;
- for (it = frames.begin(); it != frames.end(); it++) {
- float mat[4][4], ipar[4][4];
- float frame = *it;
-
- float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
- bc_update_scene(m_bmain, scene, ctime);
- if (is_bone_animation) {
- if (pchan->flag & POSE_CHAIN) {
- enable_fcurves(ob->adt->action, NULL);
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
- BKE_pose_where_is(scene, ob);
- }
- else {
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
- }
-
- // compute bone local mat
- if (bone->parent) {
- invert_m4_m4(ipar, parchan->pose_mat);
- mul_m4_m4m4(mat, ipar, pchan->pose_mat);
- }
- else
- copy_m4_m4(mat, pchan->pose_mat);
-
- /* OPEN_SIM_COMPATIBILITY
- * AFAIK animation to second life is via BVH, but no
- * reason to not have the collada-animation be correct
- */
- if (export_settings->open_sim) {
- float temp[4][4];
- copy_m4_m4(temp, bone->arm_mat);
- temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
- invert_m4(temp);
-
- mul_m4_m4m4(mat, mat, temp);
-
- if (bone->parent) {
- copy_m4_m4(temp, bone->parent->arm_mat);
- temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
-
- mul_m4_m4m4(mat, temp, mat);
- }
- }
-
- }
- else {
- copy_m4_m4(mat, ob->obmat);
- }
-
- UnitConverter converter;
-
- double outmat[4][4];
- converter.mat4_to_dae_double(outmat, mat);
-
- if (this->export_settings->limit_precision)
- bc_sanitize_mat(outmat, 6);
-
- source.appendValues(outmat);
-
- j++;
-
- BIK_release_tree(scene, ob, ctime);
- }
-
- if (ob->adt) {
- enable_fcurves(ob->adt->action, NULL);
- }
-
- source.finish();
-
- return source_id;
-}
-
-
-/*
- * only used for sources with OUTPUT semantic ( locations and scale)
- */
-std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
-{
- COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
- std::string source_id = anim_id + get_semantic_suffix(semantic);
-
- COLLADASW::FloatSourceF source(mSW);
- source.setId(source_id);
- source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(tot);
- source.setAccessorStride(3);
-
- COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, false, NULL, false);
-
- source.prepareToAppendValues();
-
- for (int i = 0; i < tot; i++) {
- source.appendValues(*v, *(v + 1), *(v + 2));
- v += 3;
- }
-
- source.finish();
-
- return source_id;
-}
-
-std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
+std::string AnimationExporter::collada_interpolation_source(const BCAnimationCurve &curve,
+ const std::string& anim_id,
+ const std::string axis,
+ bool *has_tangents)
{
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
COLLADASW::NameSource source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(fcu->totvert);
+ source.setAccessorCount(curve.sample_count());
source.setAccessorStride(1);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
@@ -1432,12 +652,17 @@ std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const st
*has_tangents = false;
- for (unsigned int i = 0; i < fcu->totvert; i++) {
- if (fcu->bezt[i].ipo == BEZT_IPO_BEZ) {
+ std::vector<float>frames;
+ curve.get_frames(frames);
+
+ for (unsigned int i = 0; i < curve.sample_count(); i++) {
+ float frame = frames[i];
+ int ipo = curve.get_interpolation_type(frame);
+ if (ipo == BEZT_IPO_BEZ) {
source.appendValues(BEZIER_NAME);
*has_tangents = true;
}
- else if (fcu->bezt[i].ipo == BEZT_IPO_CONST) {
+ else if (ipo == BEZT_IPO_CONST) {
source.appendValues(STEP_NAME);
}
else { // BEZT_IPO_LIN
@@ -1451,7 +676,7 @@ std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const st
return source_id;
}
-std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
+std::string AnimationExporter::collada_linear_interpolation_source(int tot, const std::string& anim_id)
{
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
@@ -1475,474 +700,102 @@ std::string AnimationExporter::fake_interpolation_source(int tot, const std::str
return source_id;
}
-std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
-{
- std::string tm_name;
- // when given rna_path, determine tm_type from it
- if (rna_path) {
- char *name = extract_transform_name(rna_path);
-
- if (STREQ(name, "color"))
- tm_type = 1;
- else if (STREQ(name, "spot_size"))
- tm_type = 2;
- else if (STREQ(name, "spot_blend"))
- tm_type = 3;
- else if (STREQ(name, "distance"))
- tm_type = 4;
- else
- tm_type = -1;
- }
-
- switch (tm_type) {
- case 1:
- tm_name = "color";
- break;
- case 2:
- tm_name = "fall_off_angle";
- break;
- case 3:
- tm_name = "fall_off_exponent";
- break;
- case 4:
- tm_name = "blender/blender_dist";
- break;
-
- default:
- tm_name = "";
- break;
- }
-
- if (tm_name.size()) {
- if (axis_name[0])
- return tm_name + "." + std::string(axis_name);
- else
- return tm_name;
- }
-
- return std::string("");
-}
-
-std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
+const std::string AnimationExporter::get_collada_name(std::string channel_target) const
{
- std::string tm_name;
- // when given rna_path, determine tm_type from it
- if (rna_path) {
- char *name = extract_transform_name(rna_path);
-
- if (STREQ(name, "lens"))
- tm_type = 0;
- else if (STREQ(name, "ortho_scale"))
- tm_type = 1;
- else if (STREQ(name, "clip_end"))
- tm_type = 2;
- else if (STREQ(name, "clip_start"))
- tm_type = 3;
-
- else
- tm_type = -1;
- }
-
- switch (tm_type) {
- case 0:
- tm_name = "xfov";
- break;
- case 1:
- tm_name = "xmag";
- break;
- case 2:
- tm_name = "zfar";
- break;
- case 3:
- tm_name = "znear";
- break;
-
- default:
- tm_name = "";
- break;
- }
-
- if (tm_name.size()) {
- if (axis_name[0])
- return tm_name + "." + std::string(axis_name);
- else
- return tm_name;
- }
-
- return std::string("");
+ /*
+ * Translation table to map FCurve animation types to Collada animation.
+ * Todo: Maybe we can keep the names from the fcurves here instead of
+ * mapping. However this is what i found in the old code. So keep
+ * this map for now.
+ */
+ static std::map<std::string, std::string> BC_CHANNEL_BLENDER_TO_COLLADA = {
+ { "rotation", "rotation" },
+ { "rotation_euler", "rotation" },
+ { "rotation_quaternion", "rotation" },
+ { "scale", "scale" },
+ { "location", "location" },
+
+ /* Materials */
+ { "specular_color", "specular" },
+ { "diffuse_color", "diffuse" },
+ { "ior", "index_of_refraction" },
+ { "specular_hardness", "specular_hardness" },
+ { "alpha", "alpha" },
+
+ /* Lamps */
+ { "color", "color" },
+ { "fall_off_angle", "falloff_angle" },
+ { "spot_size", "falloff_angle" },
+ { "fall_off_exponent", "falloff_exponent" },
+ { "spot_blend", "falloff_exponent" },
+ { "blender/blender_dist", "blender/blender_dist" }, // special blender profile (todo: make this more elegant)
+ { "distance", "blender/blender_dist" }, // special blender profile (todo: make this more elegant)
+
+ /* Cameras */
+ { "lens", "xfov" },
+ { "xfov", "xfov" },
+ { "xmag", "xmag" },
+ { "zfar", "zfar" },
+ { "znear", "znear" },
+ { "ortho_scale", "xmag" },
+ { "clip_end", "zfar" },
+ { "clip_start", "znear" }
+ };
+
+ std::map<std::string, std::string>::iterator name_it = BC_CHANNEL_BLENDER_TO_COLLADA.find(channel_target);
+ if (name_it == BC_CHANNEL_BLENDER_TO_COLLADA.end())
+ return "";
+
+ std::string tm_name = name_it->second;
+ return tm_name;
}
/*
* Assign sid of the animated parameter or transform for rotation,
* axis name is always appended and the value of append_axis is ignored
*/
-std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
+std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name)
{
- std::string tm_name;
- bool is_angle = false;
- // when given rna_path, determine tm_type from it
- if (rna_path) {
- char *name = extract_transform_name(rna_path);
-
- if (STREQ(name, "rotation_euler"))
- tm_type = 0;
- else if (STREQ(name, "rotation_quaternion"))
- tm_type = 1;
- else if (STREQ(name, "scale"))
- tm_type = 2;
- else if (STREQ(name, "location"))
- tm_type = 3;
- else if (STREQ(name, "specular_hardness"))
- tm_type = 4;
- else if (STREQ(name, "specular_color"))
- tm_type = 5;
- else if (STREQ(name, "diffuse_color"))
- tm_type = 6;
- else if (STREQ(name, "alpha"))
- tm_type = 7;
- else if (STREQ(name, "ior"))
- tm_type = 8;
+ std::string channel_target = curve.get_channel_target();
+ std::string tm_name = get_collada_name(channel_target);
- else
- tm_type = -1;
- }
+ bool is_angle = curve.is_rotation_curve();
- switch (tm_type) {
- case 0:
- case 1:
- tm_name = "rotation";
- is_angle = true;
- break;
- case 2:
- tm_name = "scale";
- break;
- case 3:
- tm_name = "location";
- break;
- case 4:
- tm_name = "shininess";
- break;
- case 5:
- tm_name = "specular";
- break;
- case 6:
- tm_name = "diffuse";
- break;
- case 7:
- tm_name = "transparency";
- break;
- case 8:
- tm_name = "index_of_refraction";
- break;
-
- default:
- tm_name = "";
- break;
- }
if (tm_name.size()) {
if (is_angle)
return tm_name + std::string(axis_name) + ".ANGLE";
else
- if (axis_name[0])
- return tm_name + "." + std::string(axis_name);
- else
- return tm_name;
- }
-
- return std::string("");
-}
-
-char *AnimationExporter::extract_transform_name(char *rna_path)
-{
- char *dot = strrchr(rna_path, '.');
- return dot ? (dot + 1) : rna_path;
-}
-
-/*
- * enable fcurves driving a specific bone, disable all the rest
- * if bone_name = NULL enable all fcurves
- */
-void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
-{
- FCurve *fcu;
- char prefix[200];
-
- if (bone_name)
- BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
-
- for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
- if (bone_name) {
- if (STREQLEN(fcu->rna_path, prefix, strlen(prefix)))
- fcu->flag &= ~FCURVE_DISABLED;
+ if (axis_name != "")
+ return tm_name + "." + std::string(axis_name);
else
- fcu->flag |= FCURVE_DISABLED;
- }
- else {
- fcu->flag &= ~FCURVE_DISABLED;
- }
+ return tm_name;
}
-}
-bool AnimationExporter::hasAnimations(Scene *sce)
-{
- LinkNode *node;
-
- for (node=this->export_settings->export_set; node; node=node->next) {
- Object *ob = (Object *)node->link;
-
- FCurve *fcu = 0;
- //Check for object transform animations
- if (ob->adt && ob->adt->action)
- fcu = (FCurve *)ob->adt->action->curves.first;
- //Check for Lamp parameter animations
- else if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action)
- fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
- //Check for Camera parameter animations
- else if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action)
- fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
-
- //Check Material Effect parameter animations.
- for (int a = 0; a < ob->totcol; a++) {
- Material *ma = give_current_material(ob, a + 1);
- if (!ma) continue;
- if (ma->adt && ma->adt->action) {
- fcu = (FCurve *)ma->adt->action->curves.first;
- }
- }
-
- //check shape key animation
- if (!fcu) {
- Key *key = BKE_key_from_object(ob);
- if (key && key->adt && key->adt->action)
- fcu = (FCurve *)key->adt->action->curves.first;
- }
- if (fcu)
- return true;
- }
- return false;
-}
-
-//------------------------------- Not used in the new system.--------------------------------------------------------
-void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
-{
- if (rotmode > 0)
- find_keyframes(ob, fra, prefix, "rotation_euler");
- else if (rotmode == ROT_MODE_QUAT)
- find_keyframes(ob, fra, prefix, "rotation_quaternion");
- /*else if (rotmode == ROT_MODE_AXISANGLE)
- ;*/
+ return tm_name;
}
-/* Take care to always have the first frame and the last frame in the animation
- * regardless of the sampling_rate setting
- */
-void AnimationExporter::find_sampleframes(Object *ob, std::vector<float> &fra)
+#ifdef WITH_MORPH_ANIMATION
+/* TODO: This function needs to be implemented similar to the material animation export
+So we have to update BCSample for this to work.
+*/
+void AnimationExporter::export_morph_animation(Object *ob, BCAnimationSampler &sampler)
{
- int frame = scene->r.sfra;
- do {
- float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
- fra.push_back(ctime);
- if (frame == scene->r.efra)
- break;
- frame += this->export_settings->sampling_rate;
- if (frame > scene->r.efra)
- frame = scene->r.efra; // make sure the last frame is always exported
-
- } while (true);
-}
-
-/*
- * find keyframes of all the objects animations
- */
-void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra)
-{
- if (ob->adt && ob->adt->action) {
- FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
-
- for (; fcu; fcu = fcu->next) {
- for (unsigned int i = 0; i < fcu->totvert; i++) {
- float f = fcu->bezt[i].vec[1][0];
- if (std::find(fra.begin(), fra.end(), f) == fra.end())
- fra.push_back(f);
- }
- }
-
- // keep the keys in ascending order
- std::sort(fra.begin(), fra.end());
- }
-}
-
-void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
-{
- if (ob->adt && ob->adt->action) {
- FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
-
- for (; fcu; fcu = fcu->next) {
- if (prefix && !STREQLEN(prefix, fcu->rna_path, strlen(prefix)))
- continue;
-
- char *name = extract_transform_name(fcu->rna_path);
- if (STREQ(name, tm_name)) {
- for (unsigned int i = 0; i < fcu->totvert; i++) {
- float f = fcu->bezt[i].vec[1][0];
- if (std::find(fra.begin(), fra.end(), f) == fra.end())
- fra.push_back(f);
- }
- }
- }
-
- // keep the keys in ascending order
- std::sort(fra.begin(), fra.end());
- }
-}
-
-void AnimationExporter::write_bone_animation(Object *ob_arm, Bone *bone)
-{
- if (!ob_arm->adt)
- return;
-
- //write bone animations for 3 transform types
- //i=0 --> rotations
- //i=1 --> scale
- //i=2 --> location
- for (int i = 0; i < 3; i++)
- sample_and_write_bone_animation(ob_arm, bone, i);
-
- for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
- write_bone_animation(ob_arm, child);
-}
-
-void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
-{
- bArmature *arm = (bArmature *)ob_arm->data;
- int flag = arm->flag;
- std::vector<float> fra;
- char prefix[256];
-
- BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
-
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
- if (!pchan)
- return;
- //Fill frame array with key frame values framed at \param:transform_type
- switch (transform_type) {
- case 0:
- find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
- break;
- case 1:
- find_keyframes(ob_arm, fra, prefix, "scale");
- break;
- case 2:
- find_keyframes(ob_arm, fra, prefix, "location");
- break;
- default:
- return;
- }
-
- // exit rest position
- if (flag & ARM_RESTPOS) {
- arm->flag &= ~ARM_RESTPOS;
- BKE_pose_where_is(scene, ob_arm);
- }
- //v array will hold all values which will be exported.
- if (fra.size()) {
- float *values = (float *)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
- sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
-
- if (transform_type == 0) {
- // write x, y, z curves separately if it is rotation
- float *axisValues = (float *)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
-
- for (int i = 0; i < 3; i++) {
- for (unsigned int j = 0; j < fra.size(); j++)
- axisValues[j] = values[j * 3 + i];
-
- dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
- }
- MEM_freeN(axisValues);
- }
- else {
- // write xyz at once if it is location or scale
- dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
- }
-
- MEM_freeN(values);
- }
-
- // restore restpos
- if (flag & ARM_RESTPOS)
- arm->flag = flag;
- BKE_pose_where_is(scene, ob_arm);
-}
-
-void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
-{
- bPoseChannel *parchan = NULL;
- bPose *pose = ob_arm->pose;
-
- pchan = BKE_pose_channel_find_name(pose, bone->name);
-
- if (!pchan)
- return;
-
- parchan = pchan->parent;
-
- enable_fcurves(ob_arm->adt->action, bone->name);
-
- std::vector<float>::iterator it;
- for (it = frames.begin(); it != frames.end(); it++) {
- float mat[4][4], ipar[4][4];
+ FCurve *fcu;
+ Key *key = BKE_key_from_object(ob);
+ if (!key) return;
- float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
+ if (key->adt && key->adt->action) {
+ fcu = (FCurve *)key->adt->action->curves.first;
+ while (fcu) {
+ BC_animation_transform_type tm_type = get_transform_type(fcu->rna_path);
- BKE_animsys_evaluate_animdata(scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
- BKE_pose_where_is_bone(scene, ob_arm, pchan, ctime, 1);
+ create_keyframed_animation(ob, fcu, tm_type, true, sampler);
- // compute bone local mat
- if (bone->parent) {
- invert_m4_m4(ipar, parchan->pose_mat);
- mul_m4_m4m4(mat, ipar, pchan->pose_mat);
- }
- else
- copy_m4_m4(mat, pchan->pose_mat);
-
- switch (type) {
- case 0:
- mat4_to_eul(v, mat);
- break;
- case 1:
- mat4_to_size(v, mat);
- break;
- case 2:
- copy_v3_v3(v, mat[3]);
- break;
+ fcu = fcu->next;
}
-
- v += 3;
}
- enable_fcurves(ob_arm->adt->action, NULL);
-}
-
-bool AnimationExporter::validateConstraints(bConstraint *con)
-{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- /* these we can skip completely (invalid constraints...) */
- if (cti == NULL)
- return false;
- if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))
- return false;
-
- /* these constraints can't be evaluated anyway */
- if (cti->evaluate_constraint == NULL)
- return false;
-
- /* influence == 0 should be ignored */
- if (con->enforce == 0.0f)
- return false;
-
- /* validation passed */
- return true;
}
+#endif
diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h
index b6b67847f4e..969669ef11d 100644
--- a/source/blender/collada/AnimationExporter.h
+++ b/source/blender/collada/AnimationExporter.h
@@ -20,9 +20,15 @@
* ***** END GPL LICENSE BLOCK *****
*/
+#ifndef __BC_ANIMATION_EXPORTER_H__
+#define __BC_ANIMATION_EXPORTER_H__
+
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
+
+#include "BCAnimationCurve.h"
+
extern "C"
{
#include "DNA_scene_types.h"
@@ -42,7 +48,6 @@ extern "C"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_fcurve.h"
#include "BKE_animsys.h"
#include "BKE_scene.h"
@@ -71,40 +76,45 @@ extern "C"
#include "COLLADASWBaseInputElement.h"
#include "EffectExporter.h"
-
+#include "BCAnimationSampler.h"
#include "collada_internal.h"
#include "IK_solver.h"
#include <vector>
+#include <map>
#include <algorithm> // std::find
+struct Depsgraph;
+typedef enum BC_animation_source_type {
+ BC_SOURCE_TYPE_VALUE,
+ BC_SOURCE_TYPE_ANGLE,
+ BC_SOURCE_TYPE_TIMEFRAME
+} BC_animation_source_type;
class AnimationExporter: COLLADASW::LibraryAnimations
{
private:
- Main *m_bmain;
- Scene *scene;
+ BlenderContext &blender_context;
COLLADASW::StreamWriter *sw;
+ const ExportSettings *export_settings;
public:
- AnimationExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings):
+ AnimationExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings):
COLLADASW::LibraryAnimations(sw),
+ blender_context(blender_context),
+ sw(sw),
export_settings(export_settings)
- {
- this->sw = sw;
- }
+ {}
- bool exportAnimations(Main *bmain, Scene *sce);
+ bool exportAnimations();
// called for each exported object
void operator() (Object *ob);
protected:
- const ExportSettings *export_settings;
-
void export_object_constraint_animation(Object *ob);
@@ -116,8 +126,6 @@ protected:
void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type);
- bool is_bone_deform_group(Bone * bone);
-
void sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone);
void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pChan);
@@ -136,70 +144,123 @@ protected:
float convert_angle(float angle);
+ std::vector<std::vector<std::string>> anim_meta;
+
+ /* Main entry point into Animation export (called for each exported object) */
+ void exportAnimation(Object *ob, BCAnimationSampler &sampler);
+
+ /* export animation as separate trans/rot/scale curves */
+ void export_curve_animation_set(
+ Object *ob,
+ BCAnimationSampler &sampler,
+ bool export_tm_curves);
+
+ /* export one single curve */
+ void export_curve_animation(
+ Object *ob,
+ BCAnimationCurve &curve);
+
+ /* export animation as matrix data */
+ void export_matrix_animation(
+ Object *ob,
+ BCAnimationSampler &sampler);
+
+ /* step through the bone hierarchy */
+ void export_bone_animations_recursive(
+ Object *ob_arm,
+ Bone *bone,
+ BCAnimationSampler &sampler);
+
+ /* Export for one bone */
+ void export_bone_animation(
+ Object *ob,
+ Bone *bone,
+ BCFrames &frames,
+ BCMatrixSampleMap &outmats);
+
+ /* call to the low level collada exporter */
+ void export_collada_curve_animation(
+ std::string id,
+ std::string name,
+ std::string target,
+ std::string axis,
+ BCAnimationCurve &curve);
+
+ /* call to the low level collada exporter */
+ void export_collada_matrix_animation(
+ std::string id,
+ std::string name,
+ std::string target,
+ BCFrames &frames,
+ BCMatrixSampleMap &outmats);
+
+ BCAnimationCurve *get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves);
+
+ /* Helper functions */
+ void openAnimationWithClip(std::string id, std::string name);
+ bool open_animation_container(bool has_container, Object *ob);
+ void close_animation_container(bool has_container);
+
+ /* Input and Output sources (single valued) */
+ std::string collada_source_from_values(
+ BC_animation_source_type tm_channel,
+ COLLADASW::InputSemantic::Semantics semantic,
+ std::vector<float> &values,
+ const std::string& anim_id,
+ const std::string axis_name);
+
+ /* Output sources (matrix data) */
+ std::string collada_source_from_values(
+ BCMatrixSampleMap &samples,
+ const std::string& anim_id);
+
+ /* Interpolation sources */
+ std::string collada_linear_interpolation_source(
+ int tot,
+ const std::string& anim_id);
+
+ /* source ID = animation_name + semantic_suffix */
+
std::string get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic);
void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
- COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform);
-
- void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length);
-
- float* get_eul_source_for_quat(Object *ob );
-
- bool is_flat_line(std::vector<float> &values, int channel_count);
- void export_keyframed_animation_set(Object *ob);
- void create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma = NULL);
- void export_sampled_animation_set(Object *ob);
- void export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes);
- void export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes);
- void create_sampled_animation(int channel_count, std::vector<float> &times, std::vector<float> &values, std::string, std::string label, std::string axis_name, bool is_rot);
-
- void evaluate_anim_with_constraints(Object *ob, float ctime);
+ COLLADASW::InputSemantic::Semantics semantic,
+ bool is_rot,
+ const std::string axis,
+ bool transform);
- std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name);
- std::string create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob);
+ int get_point_in_curve(BCBezTriple &bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values);
+ int get_point_in_curve(const BCAnimationCurve &curve, float sample_frame, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values);
- std::string create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id);
+ std::string collada_tangent_from_curve(
+ COLLADASW::InputSemantic::Semantics semantic,
+ BCAnimationCurve &curve,
+ const std::string& anim_id,
+ const std::string axis_name);
- std::string create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name);
+ std::string collada_interpolation_source(const BCAnimationCurve &curve, const std::string& anim_id, std::string axis_name, bool *has_tangents);
- std::string create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name);
+ std::string get_axis_name(std::string channel, int id);
+ const std::string get_collada_name(std::string channel_target) const;
+ std::string get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name);
- std::string create_xyz_source(float *v, int tot, const std::string& anim_id);
- std::string create_4x4_source(std::vector<float> &times, std::vector<float> &values, const std::string& anim_id);
- std::string create_4x4_source(std::vector<float> &frames, Object * ob_arm, Bone *bone, const std::string& anim_id);
+ /* ===================================== */
+ /* Currently unused or not (yet?) needed */
+ /* ===================================== */
- std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents);
-
- std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name);
-
- // for rotation, axis name is always appended and the value of append_axis is ignored
- std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
- std::string get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
- std::string get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
-
- void find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name);
- void find_keyframes(Object *ob, std::vector<float> &fra);
- void find_sampleframes(Object *ob, std::vector<float> &fra);
-
-
- void make_anim_frames_from_targets(Object *ob, std::vector<float> &frames );
-
- void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode);
-
- // enable fcurves driving a specific bone, disable all the rest
- // if bone_name = NULL enable all fcurves
- void enable_fcurves(bAction *act, char *bone_name);
-
- bool hasAnimations(Scene *sce);
-
- char *extract_transform_name(char *rna_path);
-
- std::string getObjectBoneName(Object *ob, const FCurve * fcu);
- std::string getAnimationPathId(const FCurve *fcu);
-
- void getBakedPoseData(Object *obarm, int startFrame, int endFrame, bool ActionBake, bool ActionBakeFirstFrame);
+ bool is_bone_deform_group(Bone * bone);
- bool validateConstraints(bConstraint *con);
+#if 0
+ BC_animation_transform_type _get_transform_type(const std::string path);
+ void get_eul_source_for_quat(std::vector<float> &cache, Object *ob);
+#endif
+#ifdef WITH_MORPH_ANIMATION
+ void export_morph_animation(
+ Object *ob,
+ BCAnimationSampler &sampler);
+#endif
};
+
+#endif
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 3dda67abbba..e3a8e517352 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -107,11 +107,9 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve");
fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED);
- // fcu->rna_path = BLI_strdupn(path, strlen(path));
fcu->array_index = 0;
- //fcu->totvert = curve->getKeyCount();
+ fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
- // create beztriple for each key
for (unsigned int j = 0; j < curve->getKeyCount(); j++) {
BezTriple bez;
memset(&bez, 0, sizeof(BezTriple));
@@ -120,7 +118,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
// input, output
bez.vec[1][0] = bc_get_float_value(input, j) * fps;
bez.vec[1][1] = bc_get_float_value(output, j * dim + i);
-
+ bez.h1 = bez.h2 = HD_AUTO;
if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER ||
curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_STEP)
@@ -135,14 +133,15 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
// outtangent
bez.vec[2][0] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i)) * fps;
bez.vec[2][1] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i) + 1);
- if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER)
+ if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER) {
bez.ipo = BEZT_IPO_BEZ;
- else
+ bez.h1 = bez.h2 = HD_AUTO_ANIM;
+ }
+ else {
bez.ipo = BEZT_IPO_CONST;
- //bez.h1 = bez.h2 = HD_AUTO;
+ }
}
else {
- bez.h1 = bez.h2 = HD_AUTO;
bez.ipo = BEZT_IPO_LIN;
}
// bez.ipo = U.ipo_new; /* use default interpolation mode here... */
@@ -245,10 +244,6 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain, Object *ob, std::vect
}
}
-AnimationImporter::AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
- TransformReader(conv), armature_importer(arm), scene(scene) {
-}
-
AnimationImporter::~AnimationImporter()
{
// free unused FCurves
@@ -304,7 +299,6 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim)
bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *animlist)
{
const COLLADAFW::UniqueId& animlist_id = animlist->getUniqueId();
-
animlist_map[animlist_id] = animlist;
#if 0
@@ -725,7 +719,7 @@ void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId& listid
}
}
-void AnimationImporter::apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node,
+void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node,
COLLADAFW::Transformation *tm)
{
bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
@@ -840,6 +834,7 @@ void AnimationImporter::apply_matrix_curves(Main *bmain, Object *ob, std::vector
add_bezt(newcu[i], fra, scale[i - 7]);
}
}
+ Main *bmain = CTX_data_main(mContext);
verify_adt_action(bmain, (ID *)&ob->id, 1);
ListBase *curves = &ob->adt->action->curves;
@@ -908,7 +903,7 @@ static ListBase &get_animation_curves(Main *bmain, Material *ma)
return act->curves;
}
-void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
+void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map,
std::multimap<COLLADAFW::UniqueId, Object *>& object_map,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map,
@@ -932,6 +927,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
AnimationImporter::AnimMix *animType = get_animation_type(node, FW_object_map);
bAction *act;
+ Main *bmain = CTX_data_main(mContext);
if ( (animType->transform) != 0) {
/* const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL; */ /* UNUSED */
@@ -940,9 +936,11 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
if (is_joint)
armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path));
+ if (!ob->adt || !ob->adt->action)
+ act = verify_adt_action(bmain, (ID *)&ob->id, 1);
- if (!ob->adt || !ob->adt->action) act = verify_adt_action(bmain, (ID *)&ob->id, 1);
- else act = ob->adt->action;
+ else
+ act = ob->adt->action;
//Get the list of animation curves of the object
ListBase *AnimCurves = &(act->curves);
@@ -972,11 +970,11 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
for (unsigned int j = 0; j < bindings.getCount(); j++) {
animcurves = curve_map[bindings[j].animation];
if (is_matrix) {
- apply_matrix_curves(bmain, ob, animcurves, root, node, transform);
+ apply_matrix_curves(ob, animcurves, root, node, transform);
}
else {
if (is_joint) {
- add_bone_animation_sampled(bmain, ob, animcurves, root, node, transform);
+ add_bone_animation_sampled(ob, animcurves, root, node, transform);
}
else {
//calculate rnapaths and array index of fcurves according to transformation and animation class
@@ -1003,9 +1001,10 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
if ((animType->light) != 0) {
Lamp *lamp = (Lamp *) ob->data;
-
- if (!lamp->adt || !lamp->adt->action) act = verify_adt_action(bmain, (ID *)&lamp->id, 1);
- else act = lamp->adt->action;
+ if (!lamp->adt || !lamp->adt->action)
+ act = verify_adt_action(bmain, (ID *)&lamp->id, 1);
+ else
+ act = lamp->adt->action;
ListBase *AnimCurves = &(act->curves);
const COLLADAFW::InstanceLightPointerArray& nodeLights = node->getInstanceLights();
@@ -1036,6 +1035,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
}
if (animType->camera != 0) {
+
Camera *cam = (Camera *) ob->data;
if (!cam->adt || !cam->adt->action)
act = verify_adt_action(bmain, (ID *)&cam->id, 1);
@@ -1090,6 +1090,12 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
}
if (animType->material != 0) {
+ Material *ma = give_current_material(ob, 1);
+ if (!ma->adt || !ma->adt->action)
+ act = verify_adt_action(bmain, (ID *)&ma->id, 1);
+ else
+ act = ma->adt->action;
+
const COLLADAFW::InstanceGeometryPointerArray& nodeGeoms = node->getInstanceGeometries();
for (unsigned int i = 0; i < nodeGeoms.getCount(); i++) {
const COLLADAFW::MaterialBindingArray& matBinds = nodeGeoms[i]->getMaterialBindings();
@@ -1136,7 +1142,7 @@ void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
delete animType;
}
-void AnimationImporter::add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm)
+void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm)
{
const char *bone_name = bc_get_joint_name(node);
char joint_path[200];
@@ -1259,6 +1265,7 @@ void AnimationImporter::add_bone_animation_sampled(Main *bmain, Object *ob, std:
add_bezt(newcu[i], fra, scale[i - 7]);
}
}
+ Main *bmain = CTX_data_main(mContext);
verify_adt_action(bmain, (ID *)&ob->id, 1);
// add curves
@@ -1291,7 +1298,7 @@ AnimationImporter::AnimMix *AnimationImporter::get_animation_type(const COLLADAF
continue;
}
else {
- types->transform = types->transform | NODE_TRANSFORM;
+ types->transform = types->transform | BC_NODE_TRANSFORM;
break;
}
}
@@ -1435,7 +1442,7 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::N
// prerequisites:
// animlist_map - map animlist id -> animlist
// curve_map - map anim id -> curve(s)
-Object *AnimationImporter::translate_animation_OLD(Main *bmain, COLLADAFW::Node *node,
+Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object *>& object_map,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map,
COLLADAFW::Transformation::TransformationType tm_type,
@@ -1657,7 +1664,7 @@ Object *AnimationImporter::translate_animation_OLD(Main *bmain, COLLADAFW::Node
}
#endif
}
-
+ Main *bmain = CTX_data_main(mContext);
verify_adt_action(bmain, (ID *)&ob->id, 1);
ListBase *curves = &ob->adt->action->curves;
@@ -1775,24 +1782,24 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float
else if (is_translate)
dae_translate_to_v3(tm, vec);
- for (unsigned int j = 0; j < bindings.getCount(); j++) {
- const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[j];
+ for (unsigned int index = 0; index < bindings.getCount(); index++) {
+ const COLLADAFW::AnimationList::AnimationBinding& binding = bindings[index];
std::vector<FCurve *>& curves = curve_map[binding.animation];
COLLADAFW::AnimationList::AnimationClass animclass = binding.animationClass;
char path[100];
switch (type) {
case COLLADAFW::Transformation::ROTATE:
- BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, j);
+ BLI_snprintf(path, sizeof(path), "%s.rotate (binding %u)", node_id, index);
break;
case COLLADAFW::Transformation::SCALE:
- BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, j);
+ BLI_snprintf(path, sizeof(path), "%s.scale (binding %u)", node_id, index);
break;
case COLLADAFW::Transformation::TRANSLATE:
- BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, j);
+ BLI_snprintf(path, sizeof(path), "%s.translate (binding %u)", node_id, index);
break;
case COLLADAFW::Transformation::MATRIX:
- BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, j);
+ BLI_snprintf(path, sizeof(path), "%s.matrix (binding %u)", node_id, index);
break;
default:
break;
@@ -1938,7 +1945,7 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::No
job->lay = BKE_scene_base_find(scene, job)->lay = 2;
mul_v3_fl(job->size, 0.5f);
- DAG_id_tag_update(&job->id, OB_RECALC_OB);
+ DEG_id_tag_update(&job->id, OB_RECALC_OB);
verify_adt_action((ID *)&job->id, 1);
@@ -1959,14 +1966,14 @@ Object *AnimationImporter::get_joint_object(COLLADAFW::Node *root, COLLADAFW::No
if (par_job) {
job->parent = par_job;
- DAG_id_tag_update(&par_job->id, OB_RECALC_OB);
+ DEG_id_tag_update(&par_job->id, OB_RECALC_OB);
job->parsubstr[0] = 0;
}
BKE_object_where_is_calc(scene, job);
// after parenting and layer change
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
joint_objects[node->getUniqueId()] = job;
}
diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h
index ff49bc369cf..d6d5ad03a88 100644
--- a/source/blender/collada/AnimationImporter.h
+++ b/source/blender/collada/AnimationImporter.h
@@ -42,6 +42,7 @@
#include "COLLADAFWInstanceGeometry.h"
extern "C" {
+#include "BKE_context.h"
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -65,7 +66,7 @@ public:
class AnimationImporter : private TransformReader, public AnimationImporterBase
{
private:
-
+ bContext *mContext;
ArmatureImporter *armature_importer;
Scene *scene;
@@ -124,8 +125,8 @@ private:
enum AnimationType
{
- INANIMATE = 0,
- NODE_TRANSFORM = 1,
+ BC_INANIMATE = 0,
+ BC_NODE_TRANSFORM = 1
};
struct AnimMix
@@ -138,7 +139,11 @@ private:
};
public:
- AnimationImporter(UnitConverter *conv, ArmatureImporter *arm, Scene *scene);
+ AnimationImporter(bContext *C, UnitConverter *conv, ArmatureImporter *arm, Scene *scene) :
+ TransformReader(conv),
+ mContext(C),
+ armature_importer(arm),
+ scene(scene) {}
~AnimationImporter();
@@ -153,7 +158,7 @@ public:
virtual void change_eul_to_quat(Object *ob, bAction *act);
#endif
- void translate_Animations(Main *bmain, COLLADAFW::Node * Node,
+ void translate_Animations(COLLADAFW::Node * Node,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
std::multimap<COLLADAFW::UniqueId, Object*>& object_map,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map,
@@ -161,10 +166,10 @@ public:
AnimMix* get_animation_type( const COLLADAFW::Node * node, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map );
- void apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node,
+ void apply_matrix_curves(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node,
COLLADAFW::Transformation * tm );
- void add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm);
+ void add_bone_animation_sampled(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm);
void Assign_transform_animations(COLLADAFW::Transformation* transform,
const COLLADAFW::AnimationList::AnimationBinding *binding,
@@ -181,12 +186,11 @@ public:
// prerequisites:
// animlist_map - map animlist id -> animlist
// curve_map - map anim id -> curve(s)
- Object *translate_animation_OLD(
- Main *bmain, COLLADAFW::Node *node,
- std::map<COLLADAFW::UniqueId, Object*>& object_map,
- std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
- COLLADAFW::Transformation::TransformationType tm_type,
- Object *par_job = NULL);
+ Object *translate_animation_OLD(COLLADAFW::Node *node,
+ std::map<COLLADAFW::UniqueId, Object *>& object_map,
+ std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map,
+ COLLADAFW::Transformation::TransformationType tm_type,
+ Object *par_job = NULL);
void find_frames( std::vector<float>* frames, std::vector<FCurve*>* curves );
void find_frames_old( std::vector<float>* frames, COLLADAFW::Node * node, COLLADAFW::Transformation::TransformationType tm_type );
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 432ce92b49d..055ffc39e9a 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -39,10 +39,8 @@
#include "BKE_armature.h"
extern "C" {
-#include "BKE_main.h"
-#include "BKE_mesh.h"
#include "BKE_global.h"
-#include "BKE_library.h"
+#include "BKE_mesh.h"
}
#include "ED_armature.h"
@@ -55,42 +53,41 @@ extern "C" {
#include "collada_utils.h"
-// XXX exporter writes wrong data for shared armatures. A separate
-// controller should be written for each armature-mesh binding how do
-// we make controller ids then?
-ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) {
-}
-
// write bone nodes
-void ArmatureExporter::add_armature_bones(bContext *C, Object *ob_arm, Scene *sce,
- SceneExporter *se,
- std::list<Object *>& child_objects)
+void ArmatureExporter::add_armature_bones(
+ Object *ob_arm,
+ ViewLayer *view_layer,
+ SceneExporter *se,
+ std::vector<Object *>& child_objects)
+
{
- Main *bmain = CTX_data_main(C);
// write bone nodes
bArmature *armature = (bArmature *)ob_arm->data;
bool is_edited = armature->edbo != NULL;
- if (!is_edited)
+ if (!is_edited) {
ED_armature_to_edit(armature);
+ }
for (Bone *bone = (Bone *)armature->bonebase.first; bone; bone = bone->next) {
// start from root bones
- if (!bone->parent)
- add_bone_node(C, bone, ob_arm, sce, se, child_objects);
+ if (!bone->parent) {
+ add_bone_node(bone, ob_arm, se, child_objects);
+ }
}
if (!is_edited) {
- ED_armature_from_edit(bmain, armature);
ED_armature_edit_free(armature);
}
}
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
{
- if (bc_is_root_bone(bone, this->export_settings->deform_bones_only))
- ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone)));
+ if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) {
+ std::string joint_id = translate_id(id_name(ob_arm) + "_" + bone->name);
+ ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, joint_id));
+ }
else {
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
write_bone_URLs(ins, ob_arm, child);
@@ -117,10 +114,7 @@ bool ArmatureExporter::add_instance_controller(Object *ob)
write_bone_URLs(ins, ob_arm, bone);
}
- InstanceWriter::add_material_bindings(ins.getBindMaterial(),
- ob,
- this->export_settings->active_uv_only,
- this->export_settings->export_texture_type);
+ InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only);
ins.add();
return true;
@@ -161,12 +155,14 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
#endif
// parent_mat is armature-space
-void ArmatureExporter::add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Scene *sce,
- SceneExporter *se,
- std::list<Object *>& child_objects)
+void ArmatureExporter::add_bone_node(
+ Bone *bone,
+ Object *ob_arm,
+ SceneExporter *se,
+ std::vector<Object *>& child_objects)
{
if (!(this->export_settings->deform_bones_only && bone->flag & BONE_NO_DEFORM)) {
- std::string node_id = get_joint_id(ob_arm, bone);
+ std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name);
std::string node_name = std::string(bone->name);
std::string node_sid = get_joint_sid(bone);
@@ -206,7 +202,7 @@ void ArmatureExporter::add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Sc
add_bone_transform(ob_arm, bone, node);
// Write nodes of childobjects, remove written objects from list
- std::list<Object *>::iterator i = child_objects.begin();
+ std::vector<Object *>::iterator i = child_objects.begin();
while (i != child_objects.end()) {
if ((*i)->partype == PARBONE && STREQ((*i)->parsubstr, bone->name)) {
@@ -235,8 +231,7 @@ void ArmatureExporter::add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Sc
mul_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv);
}
- se->writeNodes(C, *i, sce);
-
+ se->writeNodes(*i);
copy_m4_m4((*i)->parentinv, backup_parinv);
child_objects.erase(i++);
}
@@ -244,13 +239,13 @@ void ArmatureExporter::add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Sc
}
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- add_bone_node(C, child, ob_arm, sce, se, child_objects);
+ add_bone_node(child, ob_arm, se, child_objects);
}
node.end();
}
else {
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- add_bone_node(C, child, ob_arm, sce, se, child_objects);
+ add_bone_node(child, ob_arm, se, child_objects);
}
}
}
@@ -309,7 +304,7 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW:
}
if (this->export_settings->limit_precision)
- bc_sanitize_mat(mat, 6);
+ bc_sanitize_mat(mat, LIMITTED_PRECISION);
TransformWriter::add_node_transform(node, mat, NULL);
diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h
index 3199703cb20..1a8080ad613 100644
--- a/source/blender/collada/ArmatureExporter.h
+++ b/source/blender/collada/ArmatureExporter.h
@@ -57,20 +57,26 @@ class SceneExporter;
class ArmatureExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
{
public:
- ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
- // write bone nodes
- void add_armature_bones(bContext *C, Object *ob_arm, Scene *sce, SceneExporter *se,
- std::list<Object *>& child_objects);
+ // XXX exporter writes wrong data for shared armatures. A separate
+ // controller should be written for each armature-mesh binding how do
+ // we make controller ids then?
+ ArmatureExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) :
+ COLLADASW::LibraryControllers(sw),
+ blender_context(blender_context),
+ export_settings(export_settings)
+ {}
+
+ void add_armature_bones(
+ Object *ob_arm,
+ ViewLayer *view_layer,
+ SceneExporter *se,
+ std::vector<Object *>& child_objects);
bool add_instance_controller(Object *ob);
- //void export_controllers(Scene *sce);*/
-
- //void operator()(Object *ob);
-
private:
- UnitConverter converter;
+ BlenderContext &blender_context;
const ExportSettings *export_settings;
#if 0
@@ -85,8 +91,11 @@ private:
// Scene, SceneExporter and the list of child_objects
// are required for writing bone parented objects
- void add_bone_node(bContext *C, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se,
- std::list<Object *>& child_objects);
+ void add_bone_node(
+ Bone *bone,
+ Object *ob_arm,
+ SceneExporter *se,
+ std::vector<Object *>& child_objects);
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index a96d1e76a99..2644eef5e4a 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -34,7 +34,6 @@
extern "C" {
#include "BKE_action.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_armature.h"
#include "BLI_string.h"
@@ -42,6 +41,8 @@ extern "C" {
#include "ED_armature.h"
}
+#include "DEG_depsgraph.h"
+
#include "collada_utils.h"
#include "ArmatureImporter.h"
@@ -54,10 +55,12 @@ static const char *bc_get_joint_name(T *node)
}
-ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Main *bmain, Scene *sce, const ImportSettings *import_settings) :
+ArmatureImporter::ArmatureImporter(
+ UnitConverter *conv, MeshImporterBase *mesh, Main *bmain, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings) :
TransformReader(conv),
m_bmain(bmain),
scene(sce),
+ view_layer(view_layer),
unit_converter(conv),
import_settings(import_settings),
empty(NULL),
@@ -169,7 +172,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
}
copy_v3_v3(bone->head, mat[3]);
- if (bone_is_skinned)
+ if (bone_is_skinned && this->import_settings->keep_bind_info)
{
float rest_mat[4][4];
get_node_mat(rest_mat, node, NULL, NULL, NULL);
@@ -410,7 +413,7 @@ Object *ArmatureImporter::get_empty_for_leaves()
{
if (empty) return empty;
- empty = bc_add_object(m_bmain, scene, OB_EMPTY, NULL);
+ empty = bc_add_object(m_bmain, scene, view_layer, OB_EMPTY, NULL);
empty->empty_drawtype = OB_EMPTY_SPHERE;
return empty;
@@ -496,7 +499,7 @@ void ArmatureImporter::create_armature_bones(Main *bmain, std::vector<Object *>
ob_arms.push_back(ob_arm);
}
- DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
}
}
@@ -585,7 +588,7 @@ Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo& skin)
ob_arm = skin.set_armature(shared);
}
else {
- ob_arm = skin.create_armature(m_bmain, scene); //once for every armature
+ ob_arm = skin.create_armature(m_bmain, scene, view_layer); //once for every armature
}
// enter armature edit mode
@@ -629,7 +632,7 @@ Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo& skin)
ED_armature_from_edit(bmain, armature);
ED_armature_edit_free(armature);
- DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
return ob_arm;
}
@@ -879,7 +882,7 @@ void ArmatureImporter::make_shape_keys(bContext *C)
//insert basis key
kb = BKE_keyblock_add_ctime(key, "Basis", false);
- BKE_keyblock_convert_from_mesh(source_me, kb);
+ BKE_keyblock_convert_from_mesh(source_me, key, kb);
//insert other shape keys
for (int i = 0 ; i < morphTargetIds.getCount() ; i++ ) {
@@ -893,7 +896,7 @@ void ArmatureImporter::make_shape_keys(bContext *C)
std::string morph_name = *this->mesh_importer->get_geometry_name(me->id.name);
kb = BKE_keyblock_add_ctime(key, morph_name.c_str(), false);
- BKE_keyblock_convert_from_mesh(me, kb);
+ BKE_keyblock_convert_from_mesh(me, key, kb);
//apply weights
weight = morphWeights.getFloatValues()->getData()[i];
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index a215b186f75..419861554f4 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -64,6 +64,7 @@ class ArmatureImporter : private TransformReader
private:
Main *m_bmain;
Scene *scene;
+ ViewLayer *view_layer;
UnitConverter *unit_converter;
const ImportSettings *import_settings;
@@ -138,7 +139,8 @@ private:
TagsMap uid_tags_map;
public:
- ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Main *bmain, Scene *sce, const ImportSettings *import_settings);
+ ArmatureImporter(
+ UnitConverter *conv, MeshImporterBase *mesh, Main *bmain, Scene *sce, ViewLayer *view_layer, const ImportSettings *import_settings);
~ArmatureImporter();
void add_root_joint(COLLADAFW::Node *node, Object *parent);
diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp
new file mode 100644
index 00000000000..87cf07cc21c
--- /dev/null
+++ b/source/blender/collada/BCAnimationCurve.cpp
@@ -0,0 +1,678 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "BCAnimationCurve.h"
+
+BCAnimationCurve::BCAnimationCurve()
+{
+ this->curve_key.set_object_type(BC_ANIMATION_TYPE_OBJECT);
+ this->fcurve = NULL;
+ this->curve_is_local_copy = false;
+}
+
+BCAnimationCurve::BCAnimationCurve(const BCAnimationCurve &other)
+{
+ this->min = other.min;
+ this->max = other.max;
+ this->fcurve = other.fcurve;
+ this->curve_key = other.curve_key;
+ this->curve_is_local_copy = false;
+ this->id_ptr = other.id_ptr;
+
+ /* The fcurve of the new instance is a copy and can be modified */
+
+ get_edit_fcurve();
+}
+
+BCAnimationCurve::BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu)
+{
+ this->min = 0;
+ this->max = 0;
+ this->curve_key = key;
+ this->fcurve = fcu;
+ this->curve_is_local_copy = false;
+ init_pointer_rna(ob);
+}
+
+BCAnimationCurve::BCAnimationCurve(const BCCurveKey &key, Object *ob)
+{
+ this->curve_key = key;
+ this->fcurve = NULL;
+ this->curve_is_local_copy = false;
+ init_pointer_rna(ob);
+}
+
+void BCAnimationCurve::init_pointer_rna(Object *ob)
+{
+ switch (this->curve_key.get_animation_type()) {
+ case BC_ANIMATION_TYPE_BONE:
+ {
+ bArmature * arm = (bArmature *)ob->data;
+ RNA_id_pointer_create(&arm->id, &id_ptr);
+ }
+ break;
+ case BC_ANIMATION_TYPE_OBJECT:
+ {
+ RNA_id_pointer_create(&ob->id, &id_ptr);
+ }
+ break;
+ case BC_ANIMATION_TYPE_MATERIAL:
+ {
+ Material *ma = give_current_material(ob, curve_key.get_subindex() + 1);
+ RNA_id_pointer_create(&ma->id, &id_ptr);
+ }
+ break;
+ case BC_ANIMATION_TYPE_CAMERA:
+ {
+ Camera * camera = (Camera *)ob->data;
+ RNA_id_pointer_create(&camera->id, &id_ptr);
+ }
+ break;
+ case BC_ANIMATION_TYPE_LIGHT:
+ {
+ Lamp * lamp = (Lamp *)ob->data;
+ RNA_id_pointer_create(&lamp->id, &id_ptr);
+ }
+ break;
+ default:
+ fprintf(stderr, "BC_animation_curve_type %d not supported", this->curve_key.get_array_index());
+ break;
+ }
+}
+
+void BCAnimationCurve::delete_fcurve(FCurve *fcu)
+{
+ free_fcurve(fcu);
+}
+
+FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path)
+{
+ FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve");
+ fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED);
+ fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+ fcu->array_index = array_index;
+ return fcu;
+}
+
+void BCAnimationCurve::create_bezt(float frame, float output)
+{
+ FCurve *fcu = get_edit_fcurve();
+ BezTriple bez;
+ memset(&bez, 0, sizeof(BezTriple));
+ bez.vec[1][0] = frame;
+ bez.vec[1][1] = output;
+ bez.ipo = U.ipo_new; /* use default interpolation mode here... */
+ bez.f1 = bez.f2 = bez.f3 = SELECT;
+ bez.h1 = bez.h2 = HD_AUTO;
+ insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
+ calchandles_fcurve(fcu);
+}
+
+BCAnimationCurve::~BCAnimationCurve()
+{
+ if (curve_is_local_copy && fcurve) {
+ //fprintf(stderr, "removed fcurve %s\n", fcurve->rna_path);
+ delete_fcurve(fcurve);
+ this->fcurve = NULL;
+ }
+}
+
+const bool BCAnimationCurve::is_of_animation_type(BC_animation_type type) const
+{
+ return curve_key.get_animation_type() == type;
+}
+
+const std::string BCAnimationCurve::get_channel_target() const
+{
+ const std::string path = curve_key.get_path();
+ return bc_string_after(path, '.');
+}
+
+const std::string BCAnimationCurve::get_animation_name(Object *ob) const
+{
+ std::string name;
+
+ switch (curve_key.get_animation_type()) {
+ case BC_ANIMATION_TYPE_OBJECT:
+ {
+ name = id_name(ob);
+ }
+ break;
+
+ case BC_ANIMATION_TYPE_BONE:
+ {
+ if (fcurve == NULL || fcurve->rna_path == NULL)
+ name = "";
+ else {
+ const char *boneName = BLI_str_quoted_substrN(fcurve->rna_path, "pose.bones[");
+ name = (boneName) ? std::string(boneName) : "";
+ }
+ }
+ break;
+
+ case BC_ANIMATION_TYPE_CAMERA:
+ {
+ Camera *camera = (Camera *)ob->data;
+ name = id_name(ob) + "-" + id_name(camera) + "-camera";
+ }
+ break;
+
+ case BC_ANIMATION_TYPE_LIGHT:
+ {
+ Lamp *lamp = (Lamp *)ob->data;
+ name = id_name(ob) + "-" + id_name(lamp) + "-light";
+ }
+ break;
+
+ case BC_ANIMATION_TYPE_MATERIAL:
+ {
+ Material * ma = give_current_material(ob, this->curve_key.get_subindex() + 1);
+ name = id_name(ob) + "-" + id_name(ma) + "-material";
+ }
+ break;
+
+ default:
+ {
+ name = "";
+ }
+ }
+
+ return name;
+}
+
+const int BCAnimationCurve::get_channel_index() const
+{
+ return curve_key.get_array_index();
+}
+
+const int BCAnimationCurve::get_subindex() const
+{
+ return curve_key.get_subindex();
+}
+
+const std::string BCAnimationCurve::get_rna_path() const
+{
+ return curve_key.get_path();
+}
+
+const int BCAnimationCurve::sample_count() const
+{
+ if (fcurve == NULL)
+ return 0;
+ return fcurve->totvert;
+}
+
+const int BCAnimationCurve::closest_index_above(const float sample_frame, const int start_at) const
+{
+ if (fcurve == NULL)
+ return -1;
+
+ const int cframe = fcurve->bezt[start_at].vec[1][0]; // inacurate!
+
+ if (fabs(cframe - sample_frame) < 0.00001)
+ return start_at;
+ return (fcurve->totvert > start_at + 1) ? start_at + 1 : start_at;
+}
+
+const int BCAnimationCurve::closest_index_below(const float sample_frame) const
+{
+ if (fcurve == NULL)
+ return -1;
+
+ float lower_frame = sample_frame;
+ float upper_frame = sample_frame;
+ int lower_index = 0;
+ int upper_index = 0;
+
+ for (int fcu_index = 0; fcu_index < fcurve->totvert; ++fcu_index) {
+ upper_index = fcu_index;
+
+ const int cframe = fcurve->bezt[fcu_index].vec[1][0]; // inacurate!
+ if (cframe <= sample_frame) {
+ lower_frame = cframe;
+ lower_index = fcu_index;
+ }
+ if (cframe >= sample_frame) {
+ upper_frame = cframe;
+ break;
+ }
+ }
+
+ if (lower_index == upper_index)
+ return lower_index;
+
+ const float fraction = float(sample_frame - lower_frame) / (upper_frame - lower_frame);
+ return (fraction < 0.5) ? lower_index : upper_index;
+}
+
+const int BCAnimationCurve::get_interpolation_type(float sample_frame) const
+{
+ const int index = closest_index_below(sample_frame);
+ if (index < 0)
+ return BEZT_IPO_BEZ;
+ return fcurve->bezt[index].ipo;
+}
+
+const FCurve *BCAnimationCurve::get_fcurve() const
+{
+ return fcurve;
+}
+
+FCurve *BCAnimationCurve::get_edit_fcurve()
+{
+ if (!curve_is_local_copy) {
+ const int index = curve_key.get_array_index();
+ const std::string &path = curve_key.get_path();
+ fcurve = create_fcurve(index, path.c_str());
+
+ /* Caution here:
+ Replacing the pointer here is OK only because the original value
+ of FCurve was a const pointer into Blender territory. We do not
+ touch that! We use the local copy to prepare data for export.
+ */
+
+ curve_is_local_copy = true;
+ }
+ return fcurve;
+}
+
+void BCAnimationCurve::clean_handles()
+{
+ if (fcurve == NULL)
+ fcurve = get_edit_fcurve();
+
+ /* Keep old bezt data for copy)*/
+ BezTriple *old_bezts = fcurve->bezt;
+ int totvert = fcurve->totvert;
+ fcurve->bezt = NULL;
+ fcurve->totvert = 0;
+
+ for (int i = 0; i < totvert; i++) {
+ BezTriple *bezt = &old_bezts[i];
+ float x = bezt->vec[1][0];
+ float y = bezt->vec[1][1];
+ insert_vert_fcurve(fcurve, x, y, (eBezTriple_KeyframeType)BEZKEYTYPE(bezt), INSERTKEY_NOFLAGS);
+ BezTriple *lastb = fcurve->bezt + (fcurve->totvert - 1);
+ lastb->f1 = lastb->f2 = lastb->f3 = 0;
+ }
+
+ /* now free the memory used by the old BezTriples */
+ if (old_bezts)
+ MEM_freeN(old_bezts);
+}
+
+const bool BCAnimationCurve::is_transform_curve() const
+{
+ std::string channel_target = this->get_channel_target();
+ return (
+ is_rotation_curve() ||
+ channel_target == "scale" ||
+ channel_target == "location"
+ );
+}
+
+const bool BCAnimationCurve::is_rotation_curve() const
+{
+ std::string channel_target = this->get_channel_target();
+ return (
+ channel_target == "rotation" ||
+ channel_target == "rotation_euler" ||
+ channel_target == "rotation_quaternion"
+ );
+}
+
+const float BCAnimationCurve::get_value(const float frame)
+{
+ if (fcurve) {
+ return evaluate_fcurve(fcurve, frame);
+ }
+ return 0; // TODO: handle case where neither sample nor fcu exist
+}
+
+void BCAnimationCurve::update_range(float val)
+{
+ if (val < min) {
+ min = val;
+ }
+ if (val > max) {
+ max = val;
+ }
+}
+
+void BCAnimationCurve::init_range(float val)
+{
+ min = max = val;
+}
+
+void BCAnimationCurve::adjust_range(const int frame_index)
+{
+ if (fcurve && fcurve->totvert > 1) {
+ const float eval = evaluate_fcurve(fcurve, frame_index);
+
+ int first_frame = fcurve->bezt[0].vec[1][0];
+ if (first_frame == frame_index) {
+ init_range(eval);
+ }
+ else {
+ update_range(eval);
+ }
+ }
+}
+
+void BCAnimationCurve::add_value(const float val, const int frame_index)
+{
+ FCurve *fcu = get_edit_fcurve();
+ fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ insert_vert_fcurve(
+ fcu,
+ frame_index, val,
+ BEZT_KEYTYPE_KEYFRAME,
+ INSERTKEY_NOFLAGS);
+
+ if (fcu->totvert == 1) {
+ init_range(val);
+ }
+ else {
+ update_range(val);
+ }
+}
+
+bool BCAnimationCurve::add_value_from_matrix(const BCSample &sample, const int frame_index)
+{
+ int array_index = curve_key.get_array_index();
+
+ /* transformation curves are feeded directly from the transformation matrix
+ * to resolve parent inverse matrix issues with object hierarchies.
+ * Maybe this can be unified with the
+ */
+ const std::string channel_target = get_channel_target();
+ float val = 0;
+ /* Pick the value from the sample according to the definition of the FCurve */
+ bool good = sample.get_value(channel_target, array_index, &val);
+ if (good) {
+ add_value(val, frame_index);
+ }
+ return good;
+}
+
+bool BCAnimationCurve::add_value_from_rna(const int frame_index)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ float value = 0.0f;
+ int array_index = curve_key.get_array_index();
+ const std::string full_path = curve_key.get_full_path();
+
+ /* get property to read from, and get value as appropriate */
+ bool path_resolved = RNA_path_resolve_full(&id_ptr, full_path.c_str(), &ptr, &prop, &array_index);
+ if (!path_resolved && array_index == 0) {
+ const std::string rna_path = curve_key.get_path();
+ path_resolved = RNA_path_resolve_full(&id_ptr, rna_path.c_str(), &ptr, &prop, &array_index);
+ }
+
+ if (path_resolved) {
+ bool is_array = RNA_property_array_check(prop);
+ if (is_array) {
+ /* array */
+ if ((array_index >= 0) && (array_index < RNA_property_array_length(&ptr, prop))) {
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value = (float)RNA_property_boolean_get_index(&ptr, prop, array_index);
+ break;
+ case PROP_INT:
+ value = (float)RNA_property_int_get_index(&ptr, prop, array_index);
+ break;
+ case PROP_FLOAT:
+ value = RNA_property_float_get_index(&ptr, prop, array_index);
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ fprintf(stderr, "Out of Bounds while reading data for Curve %s\n", curve_key.get_full_path().c_str());
+ return false;
+ }
+ }
+ else {
+ /* not an array */
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value = (float)RNA_property_boolean_get(&ptr, prop);
+ break;
+ case PROP_INT:
+ value = (float)RNA_property_int_get(&ptr, prop);
+ break;
+ case PROP_FLOAT:
+ value = RNA_property_float_get(&ptr, prop);
+ break;
+ case PROP_ENUM:
+ value = (float)RNA_property_enum_get(&ptr, prop);
+ break;
+ default:
+ fprintf(stderr, "property type %d not supported for Curve %s\n", RNA_property_type(prop), curve_key.get_full_path().c_str());
+ return false;
+ break;
+ }
+ }
+ }
+ else {
+ /* path couldn't be resolved */
+ fprintf(stderr, "Path not recognized for Curve %s\n", curve_key.get_full_path().c_str());
+ return false;
+ }
+
+ add_value(value, frame_index);
+ return true;
+}
+
+void BCAnimationCurve::get_value_map(BCValueMap &value_map)
+{
+ value_map.clear();
+ if (fcurve == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < fcurve->totvert; i++) {
+ const float frame = fcurve->bezt[i].vec[1][0];
+ const float val = fcurve->bezt[i].vec[1][1];
+ value_map[frame] = val;
+ }
+}
+
+void BCAnimationCurve::get_frames(BCFrames &frames) const
+{
+ frames.clear();
+ if (fcurve) {
+ for (int i = 0; i < fcurve->totvert; i++) {
+ const float val = fcurve->bezt[i].vec[1][0];
+ frames.push_back(val);
+ }
+ }
+}
+
+void BCAnimationCurve::get_values(BCValues &values) const
+{
+ values.clear();
+ if (fcurve) {
+ for (int i = 0; i < fcurve->totvert; i++) {
+ const float val = fcurve->bezt[i].vec[1][1];
+ values.push_back(val);
+ }
+ }
+}
+
+bool BCAnimationCurve::is_animated()
+{
+ static float MIN_DISTANCE = 0.00001;
+ return fabs(max - min) > MIN_DISTANCE;
+}
+
+
+bool BCAnimationCurve::is_keyframe(int frame) {
+ if (this->fcurve == NULL)
+ return false;
+
+ for (int i = 0; i < fcurve->totvert; ++i) {
+ const int cframe = nearbyint(fcurve->bezt[i].vec[1][0]);
+ if (cframe == frame)
+ return true;
+ if (cframe > frame)
+ break;
+ }
+ return false;
+}
+
+/* Needed for adding a BCAnimationCurve into a BCAnimationCurveSet */
+inline bool operator< (const BCAnimationCurve& lhs, const BCAnimationCurve& rhs) {
+ std::string lhtgt = lhs.get_channel_target();
+ std::string rhtgt = rhs.get_channel_target();
+ if (lhtgt == rhtgt)
+ {
+ const int lha = lhs.get_channel_index();
+ const int rha = rhs.get_channel_index();
+ return lha < rha;
+ }
+ else
+ return lhtgt < rhtgt;
+}
+
+BCCurveKey::BCCurveKey()
+{
+ this->key_type = BC_ANIMATION_TYPE_OBJECT;
+ this->rna_path = "";
+ this->curve_array_index = 0;
+ this->curve_subindex = -1;
+}
+
+BCCurveKey::BCCurveKey(const BC_animation_type type, const std::string path, const int array_index, const int subindex)
+{
+ this->key_type = type;
+ this->rna_path = path;
+ this->curve_array_index = array_index;
+ this->curve_subindex = subindex;
+}
+
+void BCCurveKey::operator=(const BCCurveKey &other)
+{
+ this->key_type = other.key_type;
+ this->rna_path = other.rna_path;
+ this->curve_array_index = other.curve_array_index;
+ this->curve_subindex = other.curve_subindex;
+}
+
+const std::string BCCurveKey::get_full_path() const
+{
+ return this->rna_path + '[' + std::to_string(this->curve_array_index) + ']';
+}
+
+const std::string BCCurveKey::get_path() const
+{
+ return this->rna_path;
+}
+
+const int BCCurveKey::get_array_index() const
+{
+ return this->curve_array_index;
+}
+
+const int BCCurveKey::get_subindex() const
+{
+ return this->curve_subindex;
+}
+
+void BCCurveKey::set_object_type(BC_animation_type object_type)
+{
+ this->key_type = object_type;
+}
+
+const BC_animation_type BCCurveKey::get_animation_type() const
+{
+ return this->key_type;
+}
+
+const bool BCCurveKey::operator<(const BCCurveKey &other) const
+{
+ /* needed for using this class as key in maps and sets */
+ if (this->key_type != other.key_type)
+ return this->key_type < other.key_type;
+
+ if (this->curve_subindex != other.curve_subindex)
+ return this->curve_subindex < other.curve_subindex;
+
+ if (this->rna_path != other.rna_path)
+ return this->rna_path < other.rna_path;
+
+ return this->curve_array_index < other.curve_array_index;
+}
+
+BCBezTriple::BCBezTriple(BezTriple &bezt) :
+ bezt(bezt) {}
+
+const float BCBezTriple::get_frame() const
+{
+ return bezt.vec[1][0];
+}
+
+const float BCBezTriple::get_time(Scene *scene) const
+{
+ return FRA2TIME(bezt.vec[1][0]);
+}
+
+const float BCBezTriple::get_value() const
+{
+ return bezt.vec[1][1];
+}
+
+const float BCBezTriple::get_angle() const
+{
+ return RAD2DEGF(get_value());
+}
+
+void BCBezTriple::get_in_tangent(Scene *scene, float point[2], bool as_angle) const
+{
+ get_tangent(scene, point, as_angle, 0);
+}
+
+void BCBezTriple::get_out_tangent(Scene *scene, float point[2], bool as_angle) const
+{
+ get_tangent(scene, point, as_angle, 2);
+}
+
+void BCBezTriple::get_tangent(Scene *scene, float point[2], bool as_angle, int index) const
+{
+ point[0] = FRA2TIME(bezt.vec[index][0]);
+ if (bezt.ipo != BEZT_IPO_BEZ) {
+ /* We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data */
+ point[0] = 0;
+ point[1] = 0;
+ }
+ else if (as_angle) {
+ point[1] = RAD2DEGF(bezt.vec[index][1]);
+ }
+ else {
+ point[1] = bezt.vec[index][1];
+ }
+}
diff --git a/source/blender/collada/BCAnimationCurve.h b/source/blender/collada/BCAnimationCurve.h
new file mode 100644
index 00000000000..c575c969e0f
--- /dev/null
+++ b/source/blender/collada/BCAnimationCurve.h
@@ -0,0 +1,156 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#ifndef __BC_ANIMATION_CURVE_H__
+#define __BC_ANIMATION_CURVE_H__
+
+#include "collada_utils.h"
+#include "BCSampleData.h"
+
+extern "C"
+{
+#include "MEM_guardedalloc.h"
+#include "BKE_fcurve.h"
+#include "BKE_armature.h"
+#include "BKE_material.h"
+#include "ED_anim_api.h"
+#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
+}
+
+typedef float(TangentPoint)[2];
+
+typedef std::set<float> BCFrameSet;
+typedef std::vector<float> BCFrames;
+typedef std::vector<float> BCValues;
+typedef std::vector<float> BCTimes;
+typedef std::map<int, float> BCValueMap;
+
+typedef enum BC_animation_type {
+ BC_ANIMATION_TYPE_OBJECT,
+ BC_ANIMATION_TYPE_BONE,
+ BC_ANIMATION_TYPE_CAMERA,
+ BC_ANIMATION_TYPE_MATERIAL,
+ BC_ANIMATION_TYPE_LIGHT
+} BC_animation_type;
+
+class BCCurveKey {
+private:
+ BC_animation_type key_type;
+ std::string rna_path;
+ int curve_array_index;
+ int curve_subindex; /* only needed for materials */
+
+public:
+
+ BCCurveKey();
+ BCCurveKey(const BC_animation_type type, const std::string path, const int array_index, const int subindex = -1);
+ void operator=(const BCCurveKey &other);
+ const std::string get_full_path() const;
+ const std::string get_path() const;
+ const int get_array_index() const;
+ const int get_subindex() const;
+ void set_object_type(BC_animation_type object_type);
+ const BC_animation_type get_animation_type() const;
+ const bool operator<(const BCCurveKey &other) const;
+
+};
+
+class BCBezTriple {
+public:
+ BezTriple & bezt;
+
+ BCBezTriple(BezTriple &bezt);
+ const float get_frame() const;
+ const float get_time(Scene *scene) const;
+ const float get_value() const;
+ const float get_angle() const;
+ void get_in_tangent(Scene *scene, float point[2], bool as_angle) const;
+ void get_out_tangent(Scene *scene, float point[2], bool as_angle) const;
+ void get_tangent(Scene *scene, float point[2], bool as_angle, int index) const;
+
+};
+
+class BCAnimationCurve {
+private:
+ BCCurveKey curve_key;
+ float min = 0;
+ float max = 0;
+
+ bool curve_is_local_copy = false;
+ FCurve *fcurve;
+ PointerRNA id_ptr;
+ void init_pointer_rna(Object *ob);
+ void delete_fcurve(FCurve *fcu);
+ FCurve *create_fcurve(int array_index, const char *rna_path);
+ void create_bezt(float frame, float output);
+ void update_range(float val);
+ void init_range(float val);
+
+public:
+ BCAnimationCurve();
+ BCAnimationCurve(const BCAnimationCurve &other);
+ BCAnimationCurve(const BCCurveKey &key, Object *ob);
+ BCAnimationCurve(BCCurveKey key, Object *ob, FCurve *fcu);
+ ~BCAnimationCurve();
+
+ const bool is_of_animation_type(BC_animation_type type) const;
+ const int get_interpolation_type(float sample_frame) const;
+ bool is_animated();
+ const bool is_transform_curve() const;
+ const bool is_rotation_curve() const;
+ bool is_keyframe(int frame);
+ void adjust_range(int frame);
+
+ const std::string get_animation_name(Object *ob) const; /* xxx: this is collada specific */
+ const std::string get_channel_target() const;
+ const int get_channel_index() const;
+ const int get_subindex() const;
+ const std::string get_rna_path() const;
+ const FCurve *get_fcurve() const;
+ const int sample_count() const;
+
+ const float get_value(const float frame);
+ void get_values(BCValues &values) const;
+ void get_value_map(BCValueMap &value_map);
+
+ void get_frames(BCFrames &frames) const;
+
+ /* Curve edit functions create a copy of the underlaying FCurve */
+ FCurve *get_edit_fcurve();
+ bool add_value_from_rna(const int frame);
+ bool add_value_from_matrix(const BCSample &sample, const int frame);
+ void add_value(const float val, const int frame);
+ void clean_handles();
+
+ /* experimental stuff */
+ const int closest_index_above(const float sample_frame, const int start_at) const;
+ const int closest_index_below(const float sample_frame) const;
+
+};
+
+typedef std::map<BCCurveKey, BCAnimationCurve *> BCAnimationCurveMap;
+
+#endif
diff --git a/source/blender/collada/BCAnimationSampler.cpp b/source/blender/collada/BCAnimationSampler.cpp
new file mode 100644
index 00000000000..5c0c1b4316d
--- /dev/null
+++ b/source/blender/collada/BCAnimationSampler.cpp
@@ -0,0 +1,645 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include <vector>
+#include <map>
+#include <algorithm> // std::find
+
+#include "ExportSettings.h"
+#include "BCAnimationCurve.h"
+#include "BCAnimationSampler.h"
+#include "collada_utils.h"
+
+extern "C" {
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BLI_listbase.h"
+#include "DNA_anim_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_key_types.h"
+#include "DNA_constraint_types.h"
+#include "ED_object.h"
+}
+
+static std::string EMPTY_STRING;
+static BCAnimationCurveMap BCEmptyAnimationCurves;
+
+BCAnimationSampler::BCAnimationSampler(BlenderContext &blender_context, BCObjectSet &object_set):
+ blender_context(blender_context)
+{
+ BCObjectSet::iterator it;
+ for (it = object_set.begin(); it != object_set.end(); ++it) {
+ Object *ob = *it;
+ add_object(ob);
+ }
+}
+
+BCAnimationSampler::~BCAnimationSampler()
+{
+ BCAnimationObjectMap::iterator it;
+ for (it = objects.begin(); it != objects.end(); ++it) {
+ BCAnimation *animation = it->second;
+ delete animation;
+ }
+}
+
+void BCAnimationSampler::add_object(Object *ob)
+{
+ BCAnimation *animation = new BCAnimation(blender_context.get_context(), ob);
+ objects[ob] = animation;
+
+ initialize_keyframes(animation->frame_set, ob);
+ initialize_curves(animation->curve_map, ob);
+}
+
+BCAnimationCurveMap *BCAnimationSampler::get_curves(Object *ob)
+{
+ BCAnimation &animation = *objects[ob];
+ if (animation.curve_map.size() == 0)
+ initialize_curves(animation.curve_map, ob);
+ return &animation.curve_map;
+}
+
+static void get_sample_frames(BCFrameSet &sample_frames, int sampling_rate, bool keyframe_at_end, Scene *scene)
+{
+ sample_frames.clear();
+
+ if (sampling_rate < 1)
+ return; // no sample frames in this case
+
+ float sfra = scene->r.sfra;
+ float efra = scene->r.efra;
+
+ int frame_index;
+ for (frame_index = nearbyint(sfra); frame_index < efra; frame_index += sampling_rate) {
+ sample_frames.insert(frame_index);
+ }
+
+ if (frame_index >= efra && keyframe_at_end)
+ {
+ sample_frames.insert(efra);
+ }
+}
+
+static bool is_object_keyframe(Object *ob, int frame_index)
+{
+ return false;
+}
+
+static void add_keyframes_from(bAction *action, BCFrameSet &frameset)
+{
+ if (action) {
+ FCurve *fcu = NULL;
+ for (fcu = (FCurve *)action->curves.first; fcu; fcu = fcu->next) {
+ BezTriple *bezt = fcu->bezt;
+ for (int i = 0; i < fcu->totvert; bezt++, i++) {
+ int frame_index = nearbyint(bezt->vec[1][0]);
+ frameset.insert(frame_index);
+ }
+ }
+ }
+}
+
+void BCAnimationSampler::check_property_is_animated(BCAnimation &animation, float *ref, float *val, std::string data_path, int length)
+{
+ for (int array_index =0; array_index < length; ++array_index) {
+ if (!bc_in_range(ref[length], val[length], 0.00001)) {
+ BCCurveKey key(BC_ANIMATION_TYPE_OBJECT, data_path, array_index);
+ BCAnimationCurveMap::iterator it = animation.curve_map.find(key);
+ if (it == animation.curve_map.end()) {
+ animation.curve_map[key] = new BCAnimationCurve(key, animation.get_reference());
+ }
+ }
+ }
+}
+
+void BCAnimationSampler::update_animation_curves(BCAnimation &animation, BCSample &sample, Object *ob, int frame)
+{
+ BCAnimationCurveMap::iterator it;
+ for (it = animation.curve_map.begin(); it != animation.curve_map.end(); ++it) {
+ BCAnimationCurve *curve = it->second;
+ if (curve->is_transform_curve()) {
+ curve->add_value_from_matrix(sample, frame);
+ }
+ else {
+ curve->add_value_from_rna(frame);
+ }
+ }
+}
+
+BCSample &BCAnimationSampler::sample_object(Object *ob, int frame_index, bool for_opensim)
+{
+ BCSample &ob_sample = sample_data.add(ob, frame_index);
+
+ if (ob->type == OB_ARMATURE) {
+ bPoseChannel *pchan;
+ for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ Bone *bone = pchan->bone;
+ Matrix bmat;
+ if (bc_bone_matrix_local_get(ob, bone, bmat, for_opensim)) {
+ ob_sample.add_bone_matrix(bone, bmat);
+ }
+ }
+ }
+ return ob_sample;
+}
+
+void BCAnimationSampler::sample_scene(
+ int sampling_rate,
+ int keyframe_at_end,
+ bool for_opensim,
+ bool keep_keyframes,
+ BC_export_animation_type export_animation_type)
+{
+ Scene *scene = blender_context.get_scene();
+ BCFrameSet scene_sample_frames;
+ get_sample_frames(scene_sample_frames, sampling_rate, keyframe_at_end, scene);
+ BCFrameSet::iterator it;
+
+ int startframe = scene->r.sfra;
+ int endframe = scene->r.efra;
+
+ for (int frame_index = startframe; frame_index <= endframe; ++frame_index) {
+ /* Loop over all frames and decide for each frame if sampling is necessary */
+ bool is_scene_sample_frame = false;
+ bool needs_update = true;
+ if (scene_sample_frames.find(frame_index) != scene_sample_frames.end()) {
+ bc_update_scene(blender_context, frame_index);
+ needs_update = false;
+ is_scene_sample_frame = true;
+ }
+
+ bool needs_sampling = is_scene_sample_frame || keep_keyframes || export_animation_type == BC_ANIMATION_EXPORT_KEYS;
+ if (!needs_sampling) {
+ continue;
+ }
+
+ BCAnimationObjectMap::iterator obit;
+ for (obit = objects.begin(); obit != objects.end(); ++obit) {
+ Object *ob = obit->first;
+ BCAnimation *animation = obit->second;
+ BCFrameSet &object_keyframes = animation->frame_set;
+ if (is_scene_sample_frame || object_keyframes.find(frame_index) != object_keyframes.end()) {
+
+ if (needs_update) {
+ bc_update_scene(blender_context, frame_index);
+ needs_update = false;
+ }
+
+ BCSample &sample = sample_object(ob, frame_index, for_opensim);
+ update_animation_curves(*animation, sample, ob, frame_index);
+ }
+ }
+ }
+}
+
+bool BCAnimationSampler::is_animated_by_constraint(Object *ob, ListBase *conlist, std::set<Object *> &animated_objects)
+{
+ bConstraint *con;
+ for (con = (bConstraint *)conlist->first; con; con = con->next) {
+ ListBase targets = { NULL, NULL };
+
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (!bc_validateConstraints(con))
+ continue;
+
+ if (cti && cti->get_constraint_targets) {
+ bConstraintTarget *ct;
+ Object *obtar;
+ cti->get_constraint_targets(con, &targets);
+ for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
+ obtar = ct->tar;
+ if (obtar) {
+ if (animated_objects.find(obtar) != animated_objects.end())
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void BCAnimationSampler::find_depending_animated(std::set<Object *> &animated_objects, std::set<Object *> &candidates)
+{
+ bool found_more;
+ do {
+ found_more = false;
+ std::set<Object *>::iterator it;
+ for (it = candidates.begin(); it != candidates.end(); ++it) {
+ Object *cob = *it;
+ ListBase *conlist = get_active_constraints(cob);
+ if (is_animated_by_constraint(cob, conlist, animated_objects)) {
+ animated_objects.insert(cob);
+ candidates.erase(cob);
+ found_more = true;
+ break;
+ }
+ }
+ } while (found_more && candidates.size() > 0);
+}
+
+void BCAnimationSampler::get_animated_from_export_set(std::set<Object *> &animated_objects, LinkNode &export_set)
+{
+ /*
+ Check if this object is animated. That is: Check if it has its own action, or
+
+ - Check if it has constraints to other objects
+ - at least one of the other objects is animated as well
+ */
+
+ animated_objects.clear();
+ std::set<Object *> static_objects;
+ std::set<Object *> candidates;
+
+ LinkNode *node;
+ for (node = &export_set; node; node = node->next) {
+ Object *cob = (Object *)node->link;
+ if (bc_has_animations(cob)) {
+ animated_objects.insert(cob);
+ }
+ else {
+ ListBase conlist = cob->constraints;
+ if (conlist.first)
+ candidates.insert(cob);
+ }
+ }
+ find_depending_animated(animated_objects, candidates);
+}
+
+void BCAnimationSampler::get_object_frames(BCFrames &frames, Object *ob)
+{
+ sample_data.get_frames(ob, frames);
+}
+
+void BCAnimationSampler::get_bone_frames(BCFrames &frames, Object *ob, Bone *bone)
+{
+ sample_data.get_frames(ob, bone, frames);
+}
+
+bool BCAnimationSampler::get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone)
+{
+ sample_data.get_matrices(ob, bone, samples);
+ return bc_is_animated(samples);
+}
+
+bool BCAnimationSampler::get_object_samples(BCMatrixSampleMap &samples, Object *ob)
+{
+ sample_data.get_matrices(ob, samples);
+ return bc_is_animated(samples);
+}
+
+#if 0
+/*
+ Add sampled values to FCurve
+ If no FCurve exists, create a temporary FCurve;
+ Note: The temporary FCurve will later be removed when the
+ BCAnimationSampler is removed (by its destructor)
+
+ curve: The curve to whioch the data is added
+ matrices: The set of matrix values from where the data is taken
+ animation_type BC_ANIMATION_EXPORT_SAMPLES: Use all matrix data
+ animation_type BC_ANIMATION_EXPORT_KEYS: Only take data from matrices for keyframes
+*/
+
+void BCAnimationSampler::add_value_set(
+ BCAnimationCurve &curve,
+ BCFrameSampleMap &samples,
+ BC_export_animation_type animation_type)
+{
+ int array_index = curve.get_array_index();
+ const BC_animation_transform_type tm_type = curve.get_transform_type();
+
+ BCFrameSampleMap::iterator it;
+ for (it = samples.begin(); it != samples.end(); ++it) {
+ const int frame_index = nearbyint(it->first);
+ if (animation_type == BC_ANIMATION_EXPORT_SAMPLES || curve.is_keyframe(frame_index)) {
+
+ const BCSample *sample = it->second;
+ float val = 0;
+
+ int subindex = curve.get_subindex();
+ bool good;
+ if (subindex == -1) {
+ good = sample->get_value(tm_type, array_index, &val);
+ }
+ else {
+ good = sample->get_value(tm_type, array_index, &val, subindex);
+ }
+
+ if (good) {
+ curve.add_value(val, frame_index);
+ }
+ }
+ }
+ curve.remove_unused_keyframes();
+ curve.calchandles();
+}
+#endif
+
+void BCAnimationSampler::generate_transform(
+ Object *ob,
+ const BCCurveKey &key,
+ BCAnimationCurveMap &curves)
+{
+ BCAnimationCurveMap::const_iterator it = curves.find(key);
+ if (it == curves.end()) {
+ curves[key] = new BCAnimationCurve(key, ob);
+ }
+}
+
+void BCAnimationSampler::generate_transforms(
+ Object *ob,
+ const std::string prep,
+ const BC_animation_type type,
+ BCAnimationCurveMap &curves)
+{
+ generate_transform(ob, BCCurveKey(type, prep+"location", 0), curves);
+ generate_transform(ob, BCCurveKey(type, prep+"location", 1), curves);
+ generate_transform(ob, BCCurveKey(type, prep+"location", 2), curves);
+ generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 0), curves);
+ generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 1), curves);
+ generate_transform(ob, BCCurveKey(type, prep+"rotation_euler", 2), curves);
+ generate_transform(ob, BCCurveKey(type, prep+"scale", 0), curves);
+ generate_transform(ob, BCCurveKey(type, prep+"scale", 1), curves);
+ generate_transform(ob, BCCurveKey(type, prep+"scale", 2), curves);
+}
+
+void BCAnimationSampler::generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves)
+{
+ std::string prep = "pose.bones[\"" + std::string(bone->name) + "\"].";
+ generate_transforms(ob, prep, BC_ANIMATION_TYPE_BONE, curves);
+
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
+ generate_transforms(ob, child, curves);
+}
+
+/*
+* Collect all keyframes from all animation curves related to the object
+* The bc_get... functions check for NULL and correct object type
+* The add_keyframes_from() function checks for NULL
+*/
+void BCAnimationSampler::initialize_keyframes(BCFrameSet &frameset, Object *ob)
+{
+ frameset.clear();
+ add_keyframes_from(bc_getSceneObjectAction(ob), frameset);
+ add_keyframes_from(bc_getSceneCameraAction(ob), frameset);
+ add_keyframes_from(bc_getSceneLampAction(ob), frameset);
+
+ for (int a = 0; a < ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a + 1);
+ add_keyframes_from(bc_getSceneMaterialAction(ma), frameset);
+ }
+}
+
+void BCAnimationSampler::initialize_curves(BCAnimationCurveMap &curves, Object *ob)
+{
+ BC_animation_type object_type = BC_ANIMATION_TYPE_OBJECT;
+
+ bAction *action = bc_getSceneObjectAction(ob);
+ if (action) {
+ FCurve *fcu = (FCurve *)action->curves.first;
+
+ for (; fcu; fcu = fcu->next) {
+ object_type = BC_ANIMATION_TYPE_OBJECT;
+ if (ob->type == OB_ARMATURE) {
+ char *boneName = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ if (boneName) {
+ object_type = BC_ANIMATION_TYPE_BONE;
+ }
+ }
+
+ /* Adding action curves on object */
+ BCCurveKey key(object_type, fcu->rna_path, fcu->array_index);
+ curves[key] = new BCAnimationCurve(key, ob, fcu);
+ }
+ }
+
+ /* Add missing curves */
+ object_type = BC_ANIMATION_TYPE_OBJECT;
+ generate_transforms(ob, EMPTY_STRING, object_type, curves);
+ if (ob->type == OB_ARMATURE) {
+ bArmature *arm = (bArmature *)ob->data;
+ for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next)
+ generate_transforms(ob, root_bone, curves);
+ }
+
+ /* Add curves on Object->data actions */
+ action = NULL;
+ if (ob->type == OB_CAMERA) {
+ action = bc_getSceneCameraAction(ob);
+ object_type = BC_ANIMATION_TYPE_CAMERA;
+ }
+ else if (ob->type == OB_LAMP) {
+ action = bc_getSceneLampAction(ob);
+ object_type = BC_ANIMATION_TYPE_LIGHT;
+ }
+
+ if (action) {
+ /* Add lamp action or Camera action */
+ FCurve *fcu = (FCurve *)action->curves.first;
+ for (; fcu; fcu = fcu->next) {
+ BCCurveKey key(object_type, fcu->rna_path, fcu->array_index);
+ curves[key] = new BCAnimationCurve(key, ob, fcu);
+ }
+ }
+
+ /* Add curves on Object->material actions*/
+ object_type = BC_ANIMATION_TYPE_MATERIAL;
+ for (int a = 0; a < ob->totcol; a++) {
+ /* Export Material parameter animations. */
+ Material *ma = give_current_material(ob, a + 1);
+ if (ma) {
+ action = bc_getSceneMaterialAction(ma);
+ if (action) {
+ /* isMatAnim = true; */
+ FCurve *fcu = (FCurve *)action->curves.first;
+ for (; fcu; fcu = fcu->next) {
+ BCCurveKey key(object_type, fcu->rna_path, fcu->array_index, a);
+ curves[key] = new BCAnimationCurve(key, ob, fcu);
+ }
+ }
+ }
+ }
+}
+
+/* ==================================================================== */
+
+BCSample &BCSampleFrame::add(Object *ob)
+{
+ BCSample *sample = new BCSample(ob);
+ sampleMap[ob] = sample;
+ return *sample;
+}
+
+/* Get the matrix for the given key, returns Unity when the key does not exist */
+const BCSample *BCSampleFrame::get_sample(Object *ob) const
+{
+ BCSampleMap::const_iterator it = sampleMap.find(ob);
+ if (it == sampleMap.end()) {
+ return NULL;
+ }
+ return it->second;
+}
+
+const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob) const
+{
+ BCSampleMap::const_iterator it = sampleMap.find(ob);
+ if (it == sampleMap.end()) {
+ return NULL;
+ }
+ BCSample *sample = it->second;
+ return &sample->get_matrix();
+}
+
+/* Get the matrix for the given Bone, returns Unity when the Objewct is not sampled */
+const BCMatrix *BCSampleFrame::get_sample_matrix(Object *ob, Bone *bone) const
+{
+ BCSampleMap::const_iterator it = sampleMap.find(ob);
+ if (it == sampleMap.end()) {
+ return NULL;
+ }
+
+ BCSample *sample = it->second;
+ const BCMatrix *bc_bone = sample->get_matrix(bone);
+ return bc_bone;
+}
+
+/* Check if the key is in this BCSampleFrame */
+const bool BCSampleFrame::has_sample_for(Object *ob) const
+{
+ return sampleMap.find(ob) != sampleMap.end();
+}
+
+/* Check if the Bone is in this BCSampleFrame */
+const bool BCSampleFrame::has_sample_for(Object *ob, Bone *bone) const
+{
+ const BCMatrix *bc_bone = get_sample_matrix(ob, bone);
+ return (bc_bone);
+}
+
+/* ==================================================================== */
+
+BCSample &BCSampleFrameContainer::add(Object *ob, int frame_index)
+{
+ BCSampleFrame &frame = sample_frames[frame_index];
+ return frame.add(ob);
+}
+
+
+/* ====================================================== */
+/* Below are the getters which we need to export the data */
+/* ====================================================== */
+
+/* Return either the BCSampleFrame or NULL if frame does not exist*/
+BCSampleFrame * BCSampleFrameContainer::get_frame(int frame_index)
+{
+ BCSampleFrameMap::iterator it = sample_frames.find(frame_index);
+ BCSampleFrame *frame = (it == sample_frames.end()) ? NULL : &it->second;
+ return frame;
+}
+
+/* Return a list of all frames that need to be sampled */
+const int BCSampleFrameContainer::get_frames(std::vector<int> &frames) const
+{
+ frames.clear(); // safety;
+ BCSampleFrameMap::const_iterator it;
+ for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+ frames.push_back(it->first);
+ }
+ return frames.size();
+}
+
+const int BCSampleFrameContainer::get_frames(Object *ob, BCFrames &frames) const
+{
+ frames.clear(); // safety;
+ BCSampleFrameMap::const_iterator it;
+ for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+ const BCSampleFrame &frame = it->second;
+ if (frame.has_sample_for(ob)) {
+ frames.push_back(it->first);
+ }
+ }
+ return frames.size();
+}
+
+const int BCSampleFrameContainer::get_frames(Object *ob, Bone *bone, BCFrames &frames) const
+{
+ frames.clear(); // safety;
+ BCSampleFrameMap::const_iterator it;
+ for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+ const BCSampleFrame &frame = it->second;
+ if (frame.has_sample_for(ob, bone)) {
+ frames.push_back(it->first);
+ }
+ }
+ return frames.size();
+}
+
+const int BCSampleFrameContainer::get_samples(Object *ob, BCFrameSampleMap &samples) const
+{
+ samples.clear(); // safety;
+ BCSampleFrameMap::const_iterator it;
+ for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+ const BCSampleFrame &frame = it->second;
+ const BCSample *sample = frame.get_sample(ob);
+ if (sample) {
+ samples[it->first] = sample;
+ }
+ }
+ return samples.size();
+}
+
+const int BCSampleFrameContainer::get_matrices(Object *ob, BCMatrixSampleMap &samples) const
+{
+ samples.clear(); // safety;
+ BCSampleFrameMap::const_iterator it;
+ for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+ const BCSampleFrame &frame = it->second;
+ const BCMatrix *matrix = frame.get_sample_matrix(ob);
+ if (matrix) {
+ samples[it->first] = matrix;
+ }
+ }
+ return samples.size();
+}
+
+const int BCSampleFrameContainer::get_matrices(Object *ob, Bone *bone, BCMatrixSampleMap &samples) const
+{
+ samples.clear(); // safety;
+ BCSampleFrameMap::const_iterator it;
+ for (it = sample_frames.begin(); it != sample_frames.end(); ++it) {
+ const BCSampleFrame &frame = it->second;
+ const BCMatrix *sample = frame.get_sample_matrix(ob, bone);
+ if (sample) {
+ samples[it->first] = sample;
+ }
+ }
+ return samples.size();
+}
diff --git a/source/blender/collada/BCAnimationSampler.h b/source/blender/collada/BCAnimationSampler.h
new file mode 100644
index 00000000000..8bf2967a44f
--- /dev/null
+++ b/source/blender/collada/BCAnimationSampler.h
@@ -0,0 +1,205 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#ifndef __BC_ANIMATION_CURVE_CONTAINER_H__
+#define __BC_ANIMATION_CURVE_CONTAINER_H__
+
+#include "BCAnimationCurve.h"
+#include "BCSampleData.h"
+#include "collada_utils.h"
+
+extern "C" {
+#include "BKE_action.h"
+#include "BKE_library.h"
+#include "BLI_math_rotation.h"
+#include "DNA_action_types.h"
+}
+
+/* Collection of animation curves */
+class BCAnimation {
+private:
+ Object *reference = NULL;
+ bContext *mContext;
+
+
+public:
+ BCFrameSet frame_set;
+ BCAnimationCurveMap curve_map;
+
+ BCAnimation(bContext *C, Object *ob):
+ mContext(C)
+ {
+ Main *bmain = CTX_data_main(mContext);
+ reference = BKE_object_copy(bmain, ob);
+ }
+
+ ~BCAnimation()
+ {
+ BCAnimationCurveMap::iterator it;
+ for (it = curve_map.begin(); it != curve_map.end(); ++it) {
+ delete it->second;
+ }
+
+ if (reference && reference->id.us == 0)
+ {
+ Main *bmain = CTX_data_main(mContext);
+ BKE_libblock_delete(bmain, &reference->id);
+ }
+ curve_map.clear();
+ }
+
+ Object *get_reference()
+ {
+ return reference;
+ }
+};
+
+typedef std::map<Object *, BCAnimation *> BCAnimationObjectMap;
+
+class BCSampleFrame {
+
+ /*
+ Each frame on the timeline that needs to be sampled will have
+ one BCSampleFrame where we collect sample information about all objects
+ that need to be sampled for that frame.
+ */
+
+private:
+ BCSampleMap sampleMap;
+
+public:
+
+ ~BCSampleFrame()
+ {
+ BCSampleMap::iterator it;
+ for (it = sampleMap.begin(); it != sampleMap.end(); ++it) {
+ BCSample *sample = it->second;
+ delete sample;
+ }
+ sampleMap.clear();
+ }
+
+ BCSample &add(Object *ob);
+
+ /* Following methods return NULL if object is not in the sampleMap*/
+ const BCSample *get_sample(Object *ob) const;
+ const BCMatrix *get_sample_matrix(Object *ob) const;
+ const BCMatrix *get_sample_matrix(Object *ob, Bone *bone) const;
+
+ const bool has_sample_for(Object *ob) const;
+ const bool has_sample_for(Object *ob, Bone *bone) const;
+};
+
+typedef std::map<int, BCSampleFrame> BCSampleFrameMap;
+
+class BCSampleFrameContainer {
+
+ /*
+ * The BCSampleFrameContainer stores a map of BCSampleFrame objects
+ * with the timeline frame as key.
+ *
+ * Some details on the purpose:
+ * An Animation is made of multiple FCurves where each FCurve can
+ * have multiple keyframes. When we want to export the animation we
+ * also can decide whether we want to export the keyframes or a set
+ * of sample frames at equidistant locations (sample period).
+ * In any case we must resample first need to resample it fully
+ * to resolve things like:
+ *
+ * - animations by constraints
+ * - animations by drivers
+ *
+ * For this purpose we need to step through the entire animation and
+ * then sample each frame that contains at least one keyFrame or
+ * sampleFrame. Then for each frame we have to store the transform
+ * information for all exported objects in a BCSampleframe
+ *
+ * The entire set of BCSampleframes is finally collected into
+ * a BCSampleframneContainer
+ */
+
+private:
+ BCSampleFrameMap sample_frames;
+
+public:
+
+ ~BCSampleFrameContainer()
+ {
+ }
+
+ BCSample &add(Object *ob, int frame_index);
+ BCSampleFrame * get_frame(int frame_index); // returns NULL if frame does not exist
+
+ const int get_frames(std::vector<int> &frames) const;
+ const int get_frames(Object *ob, BCFrames &frames) const;
+ const int get_frames(Object *ob, Bone *bone, BCFrames &frames) const;
+
+ const int get_samples(Object *ob, BCFrameSampleMap &samples) const;
+ const int get_matrices(Object *ob, BCMatrixSampleMap &matrices) const;
+ const int get_matrices(Object *ob, Bone *bone, BCMatrixSampleMap &bones) const;
+};
+
+class BCAnimationSampler {
+private:
+ BlenderContext &blender_context;
+ BCSampleFrameContainer sample_data;
+ BCAnimationObjectMap objects;
+
+ void generate_transform(Object *ob, const BCCurveKey &key, BCAnimationCurveMap &curves);
+ void generate_transforms(Object *ob, const std::string prep, const BC_animation_type type, BCAnimationCurveMap &curves);
+ void generate_transforms(Object *ob, Bone *bone, BCAnimationCurveMap &curves);
+
+ void initialize_curves(BCAnimationCurveMap &curves, Object *ob);
+ void initialize_keyframes(BCFrameSet &frameset, Object *ob);
+ BCSample &sample_object(Object *ob, int frame_index, bool for_opensim);
+ void update_animation_curves(BCAnimation &animation, BCSample &sample, Object *ob, int frame_index);
+ void check_property_is_animated(BCAnimation &animation, float *ref, float *val, std::string data_path, int length);
+
+public:
+ BCAnimationSampler(BlenderContext &blender_context, BCObjectSet &animated_subset);
+ ~BCAnimationSampler();
+
+ void add_object(Object *ob);
+
+ void sample_scene(
+ int sampling_rate,
+ int keyframe_at_end,
+ bool for_opensim,
+ bool keep_keyframes,
+ BC_export_animation_type export_animation_type);
+
+ BCAnimationCurveMap *get_curves(Object *ob);
+ void get_object_frames(BCFrames &frames, Object *ob);
+ bool get_object_samples(BCMatrixSampleMap &samples, Object *ob);
+ void get_bone_frames(BCFrames &frames, Object *ob, Bone *bone);
+ bool get_bone_samples(BCMatrixSampleMap &samples, Object *ob, Bone *bone);
+
+ static void get_animated_from_export_set(std::set<Object *> &animated_objects, LinkNode &export_set);
+ static void find_depending_animated(std::set<Object *> &animated_objects, std::set<Object *> &candidates);
+ static bool is_animated_by_constraint(Object *ob, ListBase *conlist, std::set<Object *> &animated_objects);
+
+};
+
+#endif
diff --git a/source/blender/collada/BCSampleData.cpp b/source/blender/collada/BCSampleData.cpp
new file mode 100644
index 00000000000..95898bb5429
--- /dev/null
+++ b/source/blender/collada/BCSampleData.cpp
@@ -0,0 +1,186 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "BCSampleData.h"
+#include "collada_utils.h"
+
+BCSample::BCSample(Object *ob):
+ obmat(ob)
+{}
+
+BCSample::~BCSample()
+{
+ BCBoneMatrixMap::iterator it;
+ for (it = bonemats.begin(); it != bonemats.end(); ++it) {
+ delete it->second;
+ }
+}
+
+void BCSample::add_bone_matrix(Bone *bone, Matrix &mat)
+{
+ BCMatrix *matrix;
+ BCBoneMatrixMap::const_iterator it = bonemats.find(bone);
+ if (it != bonemats.end()) {
+ throw std::invalid_argument("bone " + std::string(bone->name) + " already defined before");
+ }
+ matrix = new BCMatrix(mat);
+ bonemats[bone] = matrix;
+}
+
+BCMatrix::BCMatrix(Matrix &mat)
+{
+ set_transform(mat);
+}
+
+BCMatrix::BCMatrix(Object *ob)
+{
+ set_transform(ob);
+}
+
+void BCMatrix::set_transform(Matrix &mat)
+{
+ copy_m4_m4(matrix, mat);
+ mat4_decompose(this->loc, this->q, this->size, mat);
+ quat_to_eul(this->rot, this->q);
+}
+
+void BCMatrix::set_transform(Object *ob)
+{
+ Matrix lmat;
+
+ BKE_object_matrix_local_get(ob, lmat);
+ copy_m4_m4(matrix, lmat);
+
+ mat4_decompose(this->loc, this->q, this->size, lmat);
+ quat_to_compatible_eul(this->rot, ob->rot, this->q);
+}
+
+const BCMatrix *BCSample::get_matrix(Bone *bone) const
+{
+ BCBoneMatrixMap::const_iterator it = bonemats.find(bone);
+ if (it == bonemats.end()) {
+ return NULL;
+ }
+ return it->second;
+}
+
+const BCMatrix &BCSample::get_matrix() const
+{
+ return obmat;
+}
+
+
+/* Get channel value */
+const bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const
+{
+ if (channel_target == "location") {
+ *val = obmat.location()[array_index];
+ }
+ else if (channel_target == "scale") {
+ *val = obmat.scale()[array_index];
+ }
+ else if (
+ channel_target == "rotation" ||
+ channel_target == "rotation_euler") {
+ *val = obmat.rotation()[array_index];
+ }
+ else if (channel_target == "rotation_quat") {
+ *val = obmat.quat()[array_index];
+ }
+ else {
+ *val = 0;
+ return false;
+ }
+
+ return true;
+}
+
+void BCMatrix::copy(Matrix &out, Matrix &in)
+{
+ /* destination comes first: */
+ memcpy(out, in, sizeof(Matrix));
+}
+
+void BCMatrix::transpose(Matrix &mat)
+{
+ transpose_m4(mat);
+}
+
+void BCMatrix::sanitize(Matrix &mat, int precision)
+{
+ bc_sanitize_mat(mat, precision);
+}
+
+void BCMatrix::unit()
+{
+ unit_m4(matrix);
+}
+
+/*
+We need double here because the OpenCollada API needs it.
+precision = -1 indicates to not limit the precision
+*/
+void BCMatrix::get_matrix(double(&mat)[4][4], const bool transposed, const int precision) const
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++) {
+ float val = (transposed) ? matrix[j][i] : matrix[i][j];
+ if (precision >= 0)
+ val = floor((val * pow(10, precision) + 0.5)) / pow(10, precision);
+ mat[i][j] = val;
+ }
+}
+
+const bool BCMatrix::in_range(const BCMatrix &other, float distance) const
+{
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ if (fabs(other.matrix[i][j] - matrix[i][j]) > distance) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+float(&BCMatrix::location() const)[3]
+{
+ return loc;
+}
+
+float(&BCMatrix::rotation() const)[3]
+{
+ return rot;
+}
+
+float(&BCMatrix::scale() const)[3]
+{
+ return size;
+}
+
+float(&BCMatrix::quat() const)[4]
+{
+ return q;
+}
diff --git a/source/blender/collada/BCSampleData.h b/source/blender/collada/BCSampleData.h
new file mode 100644
index 00000000000..a685cb30fa6
--- /dev/null
+++ b/source/blender/collada/BCSampleData.h
@@ -0,0 +1,102 @@
+/*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* The Original Code is Copyright (C) 2008 Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Blender Foundation
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#ifndef __BC_SAMPLE_H__
+#define __BC_SAMPLE_H__
+
+#include <string>
+#include <map>
+#include <algorithm>
+
+extern "C"
+{
+#include "BKE_object.h"
+#include "BLI_math_rotation.h"
+#include "DNA_object_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_material_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_camera_types.h"
+}
+
+typedef float(Matrix)[4][4];
+
+class BCMatrix {
+
+private:
+ mutable float matrix[4][4];
+ mutable float size[3];
+ mutable float rot[3];
+ mutable float loc[3];
+ mutable float q[4];
+
+ void unit();
+ void copy(Matrix &r, Matrix &a);
+ void set_transform(Object *ob);
+ void set_transform(Matrix &mat);
+
+public:
+
+ float(&location() const)[3];
+ float(&rotation() const)[3];
+ float(&scale() const)[3];
+ float(&quat() const)[4];
+
+ BCMatrix(Matrix &mat);
+ BCMatrix(Object *ob);
+
+ void get_matrix(double(&mat)[4][4], const bool transposed = false, const int precision = -1) const;
+
+ const bool in_range(const BCMatrix &other, float distance) const;
+ static void sanitize(Matrix &matrix, int precision);
+ static void transpose(Matrix &matrix);
+
+};
+
+typedef std::map<Bone *, BCMatrix *> BCBoneMatrixMap;
+
+class BCSample{
+private:
+
+ BCMatrix obmat;
+ BCBoneMatrixMap bonemats; /* For Armature animation */
+
+public:
+ BCSample(Object *ob);
+ ~BCSample();
+
+ void add_bone_matrix(Bone *bone, Matrix &mat);
+
+ const bool get_value(std::string channel_target, const int array_index, float *val) const;
+ const BCMatrix &get_matrix() const;
+ const BCMatrix *get_matrix(Bone *bone) const; // returns NULL if bone is not animated
+
+};
+
+typedef std::map<Object *, BCSample *> BCSampleMap;
+typedef std::map<int, const BCSample *> BCFrameSampleMap;
+typedef std::map<int, const BCMatrix *> BCMatrixSampleMap;
+
+#endif
diff --git a/source/blender/collada/BlenderContext.cpp b/source/blender/collada/BlenderContext.cpp
new file mode 100644
index 00000000000..fcfd9241649
--- /dev/null
+++ b/source/blender/collada/BlenderContext.cpp
@@ -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.
+ *
+ * Contributor(s): Gaia Clary,
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+ /** \file CameraExporter.h
+ * \ingroup collada
+ */
+
+#include "BlenderContext.h"
+#include "BKE_scene.h"
+
+BlenderContext::BlenderContext(bContext *C)
+{
+ context = C;
+ main = CTX_data_main(C);
+ scene = CTX_data_scene(C);
+ view_layer = CTX_data_view_layer(C);
+ depsgraph = nullptr; // create only when needed
+}
+
+bContext *BlenderContext::get_context()
+{
+ return context;
+}
+
+Depsgraph *BlenderContext::get_depsgraph()
+{
+ if (!depsgraph) {
+ depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ }
+ return depsgraph;
+}
+
+Scene *BlenderContext::get_scene()
+{
+ return scene;
+}
+
+ViewLayer *BlenderContext::get_view_layer()
+{
+ return view_layer;
+}
+
+Main *BlenderContext::get_main()
+{
+ return main;
+}
diff --git a/source/blender/collada/BlenderContext.h b/source/blender/collada/BlenderContext.h
new file mode 100644
index 00000000000..648d97a7e86
--- /dev/null
+++ b/source/blender/collada/BlenderContext.h
@@ -0,0 +1,56 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Gaia Clary,
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+ /** \file CameraExporter.h
+ * \ingroup collada
+ */
+
+#ifndef __BLENDERCONTEXT_H__
+#define __BLENDERCONTEXT_H__
+
+extern "C" {
+#include "DNA_object_types.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+}
+
+class BlenderContext
+{
+private:
+ bContext *context;
+ Depsgraph *depsgraph;
+ Scene *scene;
+ ViewLayer *view_layer;
+ Main *main;
+
+public:
+ BlenderContext(bContext *C);
+ bContext *get_context();
+ Depsgraph *get_depsgraph();
+ Scene *get_scene();
+ ViewLayer *get_view_layer();
+ Main *get_main();
+};
+
+#endif
diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt
index 293049a1a05..f860dfac08b 100644
--- a/source/blender/collada/CMakeLists.txt
+++ b/source/blender/collada/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../blenkernel
../blenlib
../blentranslation
+ ../depsgraph
../editors/include
../makesdna
../makesrna
@@ -48,8 +49,13 @@ set(INC_SYS
set(SRC
AnimationImporter.cpp
AnimationExporter.cpp
+ AnimationClipExporter.cpp
ArmatureExporter.cpp
ArmatureImporter.cpp
+ BlenderContext.cpp
+ BCAnimationCurve.cpp
+ BCAnimationSampler.cpp
+ BCSampleData.cpp
CameraExporter.cpp
ControllerExporter.cpp
DocumentExporter.cpp
@@ -67,6 +73,7 @@ set(SRC
MaterialExporter.cpp
MeshImporter.cpp
SkinInfo.cpp
+ Materials.cpp
SceneExporter.cpp
TransformReader.cpp
TransformWriter.cpp
@@ -76,8 +83,13 @@ set(SRC
AnimationImporter.h
AnimationExporter.h
+ AnimationClipExporter.h
ArmatureExporter.h
ArmatureImporter.h
+ BlenderContext.h
+ BCAnimationCurve.h
+ BCAnimationSampler.h
+ BCSampleData.h
CameraExporter.h
ControllerExporter.h
DocumentExporter.h
@@ -94,6 +106,7 @@ set(SRC
LightExporter.h
MaterialExporter.h
MeshImporter.h
+ Materials.h
SkinInfo.h
SceneExporter.h
TransformReader.h
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index a5f96123fd4..5ec199f086b 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -38,11 +38,10 @@
#include "BKE_armature.h"
extern "C" {
-#include "BKE_main.h"
-#include "BKE_mesh.h"
#include "BKE_global.h"
-#include "BKE_library.h"
#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
}
#include "ED_armature.h"
@@ -56,22 +55,18 @@ extern "C" {
#include "collada_utils.h"
-// XXX exporter writes wrong data for shared armatures. A separate
-// controller should be written for each armature-mesh binding how do
-// we make controller ids then?
-ControllerExporter::ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryControllers(sw), export_settings(export_settings) {
-}
bool ControllerExporter::is_skinned_mesh(Object *ob)
{
return bc_get_assigned_armature(ob) != NULL;
}
-
void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
{
- if (bc_is_root_bone(bone, this->export_settings->deform_bones_only))
- ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone)));
+ if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) {
+ std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name);
+ ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, node_id));
+ }
else {
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
write_bone_URLs(ins, ob_arm, child);
@@ -98,20 +93,15 @@ bool ControllerExporter::add_instance_controller(Object *ob)
write_bone_URLs(ins, ob_arm, bone);
}
- InstanceWriter::add_material_bindings(ins.getBindMaterial(),
- ob,
- this->export_settings->active_uv_only,
- this->export_settings->export_texture_type);
+ InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only);
ins.add();
return true;
}
-void ControllerExporter::export_controllers(Main *bmain, Scene *sce)
+void ControllerExporter::export_controllers()
{
- m_bmain = bmain;
- scene = sce;
-
+ Scene *sce = blender_context.get_scene();
openLibrary();
GeometryFunctor gf;
@@ -201,16 +191,17 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
bool use_instantiation = this->export_settings->use_object_instantiation;
Mesh *me;
+ if (((Mesh *)ob->data)->dvert == NULL) {
+ return;
+ }
+
me = bc_get_mesh_copy(
- m_bmain,
- scene,
+ blender_context,
ob,
this->export_settings->export_mesh_type,
this->export_settings->apply_modifiers,
this->export_settings->triangulate);
- if (!me->dvert) return;
-
std::string controller_name = id_name(ob_arm);
std::string controller_id = get_controller_id(ob_arm, ob);
@@ -294,7 +285,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints);
- BKE_libblock_free_us(m_bmain, me);
+ BKE_id_free(NULL, me);
closeSkin();
closeController();
@@ -306,8 +297,7 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
Mesh *me;
me = bc_get_mesh_copy(
- m_bmain,
- scene,
+ blender_context,
ob,
this->export_settings->export_mesh_type,
this->export_settings->apply_modifiers,
@@ -332,8 +322,7 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, morph_weights_id)));
targets.add();
- BKE_libblock_free_us(m_bmain, me);
-
+ BKE_id_free(NULL, me);
//support for animations
//can also try the base element and param alternative
@@ -432,8 +421,13 @@ void ControllerExporter::add_joints_element(ListBase *defbase,
void ControllerExporter::add_bind_shape_mat(Object *ob)
{
double bind_mat[4][4];
+ float f_obmat[4][4];
+ BKE_object_matrix_local_get(ob, f_obmat);
- converter.mat4_to_dae_double(bind_mat, ob->obmat);
+ //UnitConverter::mat4_to_dae_double(bind_mat, ob->obmat);
+ UnitConverter::mat4_to_dae_double(bind_mat, f_obmat);
+ if (this->export_settings->limit_precision)
+ bc_sanitize_mat(bind_mat, LIMITTED_PRECISION);
addBindShapeTransform(bind_mat);
}
@@ -501,8 +495,11 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
// put armature in rest position
if (!(arm->flag & ARM_RESTPOS)) {
+ Depsgraph *depsgraph = blender_context.get_depsgraph();
+ Scene *scene = blender_context.get_scene();
+
arm->flag |= ARM_RESTPOS;
- BKE_pose_where_is(scene, ob_arm);
+ BKE_pose_where_is(depsgraph, scene, ob_arm);
}
for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) {
@@ -540,17 +537,19 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
mul_m4_m4m4(world, ob_arm->obmat, bind_mat);
invert_m4_m4(mat, world);
- converter.mat4_to_dae(inv_bind_mat, mat);
+ UnitConverter::mat4_to_dae(inv_bind_mat, mat);
if (this->export_settings->limit_precision)
- bc_sanitize_mat(inv_bind_mat, 6);
+ bc_sanitize_mat(inv_bind_mat, LIMITTED_PRECISION);
source.appendValues(inv_bind_mat);
}
}
- // back from rest positon
+ // back from rest position
if (!(flag & ARM_RESTPOS)) {
+ Depsgraph *depsgraph = blender_context.get_depsgraph();
+ Scene *scene = blender_context.get_scene();
arm->flag = flag;
- BKE_pose_where_is(scene, ob_arm);
+ BKE_pose_where_is(depsgraph, scene, ob_arm);
}
source.finish();
diff --git a/source/blender/collada/ControllerExporter.h b/source/blender/collada/ControllerExporter.h
index 2e258c63b6f..309bdbd37f0 100644
--- a/source/blender/collada/ControllerExporter.h
+++ b/source/blender/collada/ControllerExporter.h
@@ -54,25 +54,31 @@
#include "BKE_key.h"
+struct Depsgraph;
class SceneExporter;
class ControllerExporter : public COLLADASW::LibraryControllers, protected TransformWriter, protected InstanceWriter
{
public:
- ControllerExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
+ // XXX exporter writes wrong data for shared armatures. A separate
+ // controller should be written for each armature-mesh binding how do
+ // we make controller ids then?
+ ControllerExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) :
+ COLLADASW::LibraryControllers(sw),
+ blender_context(blender_context),
+ export_settings(export_settings) {
+ }
bool is_skinned_mesh(Object *ob);
bool add_instance_controller(Object *ob);
- void export_controllers(Main *bmain, Scene *sce);
+ void export_controllers();
void operator()(Object *ob);
private:
- Main *m_bmain;
- Scene *scene;
- UnitConverter converter;
+ BlenderContext &blender_context;
const ExportSettings *export_settings;
#if 0
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index bf29ec42c42..4d0dd7605f9 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -66,12 +66,11 @@ extern "C"
{
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_image_types.h"
#include "DNA_material_types.h"
-#include "DNA_texture_types.h"
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_curve_types.h"
@@ -86,11 +85,11 @@ extern "C"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_action.h" // pose functions
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_blender_version.h"
+#include "BKE_customdata.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -138,8 +137,7 @@ extern bool bc_has_object_type(LinkNode *export_set, short obtype);
char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n)
{
int layer_index = CustomData_get_layer_index(data, type);
- if (layer_index < 0)
- return NULL;
+ if (layer_index < 0) return NULL;
return data->layers[layer_index + n].name;
}
@@ -148,13 +146,14 @@ char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
{
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
- if (layer_index < 1)
- return NULL;
+ if (layer_index < 0) return NULL;
- return bc_CustomData_get_layer_name(data, type, layer_index-1);
+ return data->layers[layer_index].name;
}
-DocumentExporter::DocumentExporter(const ExportSettings *export_settings) : export_settings(export_settings) {
+DocumentExporter::DocumentExporter(BlenderContext &blender_context, const ExportSettings *export_settings) :
+ blender_context(blender_context),
+ export_settings(export_settings) {
}
static COLLADABU::NativeString make_temp_filepath(const char *name, const char *extension)
@@ -181,9 +180,11 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char *
// COLLADA allows this through multiple <channel>s in <animation>.
// For this to work, we need to know objects that use a certain action.
-int DocumentExporter::exportCurrentScene(bContext *C, const EvaluationContext *eval_ctx, Scene *sce)
+int DocumentExporter::exportCurrentScene()
{
- Main *bmain = CTX_data_main(C);
+ Scene *sce = blender_context.get_scene();
+ bContext *C = blender_context.get_context();
+
PointerRNA sceneptr, unit_settings;
PropertyRNA *system; /* unused , *scale; */
@@ -273,42 +274,43 @@ int DocumentExporter::exportCurrentScene(bContext *C, const EvaluationContext *e
le.exportLights(sce);
}
+ // <library_effects>
+ EffectsExporter ee(writer, this->export_settings, key_image_map);
+ ee.exportEffects(C, sce);
+
// <library_images>
- ImagesExporter ie(writer, this->export_settings);
+ ImagesExporter ie(writer, this->export_settings, key_image_map);
ie.exportImages(sce);
- // <library_effects>
- EffectsExporter ee(writer, this->export_settings);
- ee.exportEffects(sce);
-
// <library_materials>
MaterialsExporter me(writer, this->export_settings);
me.exportMaterials(sce);
// <library_geometries>
if (bc_has_object_type(export_set, OB_MESH)) {
- GeometryExporter ge(writer, this->export_settings);
- ge.exportGeom(bmain, sce);
+ GeometryExporter ge(blender_context, writer, this->export_settings);
+ ge.exportGeom();
}
// <library_controllers>
- ArmatureExporter arm_exporter(writer, this->export_settings);
- ControllerExporter controller_exporter(writer, this->export_settings);
+ ArmatureExporter arm_exporter(blender_context, writer, this->export_settings);
+ ControllerExporter controller_exporter(blender_context, writer, this->export_settings);
if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys)
{
- controller_exporter.export_controllers(bmain, sce);
+ controller_exporter.export_controllers();
}
// <library_visual_scenes>
- SceneExporter se(writer, &arm_exporter, this->export_settings);
+ SceneExporter se(blender_context, writer, &arm_exporter, this->export_settings);
if (this->export_settings->include_animations) {
// <library_animations>
- AnimationExporter ae(writer, this->export_settings);
- ae.exportAnimations(bmain, sce);
+ AnimationExporter ae(blender_context, writer, this->export_settings);
+ ae.exportAnimations();
}
- se.exportScene(C, sce);
+
+ se.exportScene();
// <scene>
std::string scene_name(translate_id(id_name(sce)));
diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h
index 817df3735da..cb55dbc459e 100644
--- a/source/blender/collada/DocumentExporter.h
+++ b/source/blender/collada/DocumentExporter.h
@@ -28,22 +28,24 @@
#define __DOCUMENTEXPORTER_H__
#include "collada.h"
+#include "collada_utils.h"
+#include "BlenderContext.h"
extern "C" {
#include "DNA_customdata_types.h"
-#include "BKE_depsgraph.h"
-}
-struct Scene;
+}
class DocumentExporter
{
public:
- DocumentExporter(const ExportSettings *export_settings);
- int exportCurrentScene(bContext *C, const EvaluationContext *eval_ctx, Scene *sce);
+ DocumentExporter(BlenderContext &blender_context, const ExportSettings *export_settings);
+ int exportCurrentScene();
void exportScenes(const char *filename);
private:
+ BlenderContext &blender_context;
const ExportSettings *export_settings;
+ KeyImageMap key_image_map;
};
#endif
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 67fd9d648c7..8eb9e5c969e 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -57,16 +57,15 @@ extern "C" {
#include "BLI_fileops.h"
#include "BKE_camera.h"
-#include "BKE_main.h"
-#include "BKE_lamp.h"
-#include "BKE_library.h"
-#include "BKE_texture.h"
+#include "BKE_collection.h"
#include "BKE_fcurve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_scene.h"
#include "BKE_global.h"
-#include "BKE_material.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
+#include "BKE_lamp.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_scene.h"
#include "BLI_path_util.h"
@@ -82,6 +81,9 @@ extern "C" {
}
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ExtraHandler.h"
#include "ErrorHandler.h"
#include "DocumentImporter.h"
@@ -89,7 +91,7 @@ extern "C" {
#include "collada_internal.h"
#include "collada_utils.h"
-
+#include "Materials.h"
/*
* COLLADA Importer limitations:
@@ -102,11 +104,12 @@ extern "C" {
DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_settings) :
import_settings(import_settings),
- mImportStage(General),
+ mImportStage(Fetching_Scene_data),
mContext(C),
- armature_importer(&unit_converter, &mesh_importer, CTX_data_main(C), CTX_data_scene(C), import_settings),
- mesh_importer(&unit_converter, &armature_importer, CTX_data_main(C), CTX_data_scene(C)),
- anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C))
+ view_layer(CTX_data_view_layer(mContext)),
+ armature_importer(&unit_converter, &mesh_importer, CTX_data_main(C), CTX_data_scene(C), view_layer, import_settings),
+ mesh_importer(&unit_converter, &armature_importer, CTX_data_main(C), CTX_data_scene(C), view_layer),
+ anim_importer(C, &unit_converter, &armature_importer, CTX_data_scene(C))
{
}
@@ -130,7 +133,7 @@ bool DocumentImporter::import()
loader.registerExtraDataCallbackHandler(ehandler);
// deselect all to select new objects
- BKE_scene_base_deselect_all(CTX_data_scene(mContext));
+ BKE_view_layer_base_deselect_all(view_layer);
std::string mFilename = std::string(this->import_settings->filepath);
const std::string encodedFilename = bc_url_encode(mFilename);
@@ -146,9 +149,7 @@ bool DocumentImporter::import()
}
/** TODO set up scene graph and such here */
-
- mImportStage = Controller;
-
+ mImportStage = Fetching_Controller_data;
COLLADASaxFWL::Loader loader2;
COLLADAFW::Root root2(&loader2, this);
@@ -179,7 +180,7 @@ void DocumentImporter::start()
void DocumentImporter::finish()
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return;
Main *bmain = CTX_data_main(mContext);
@@ -222,6 +223,7 @@ void DocumentImporter::finish()
}
// Write nodes to scene
+ fprintf(stderr, "+-- Import Scene --------\n");
const COLLADAFW::NodePointerArray& roots = (*sit)->getRootNodes();
for (unsigned int i = 0; i < roots.getCount(); i++) {
std::vector<Object *> *objects_done = write_node(roots[i], NULL, sce, NULL, false);
@@ -229,10 +231,6 @@ void DocumentImporter::finish()
delete objects_done;
}
- // update scene
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, NULL);
-
}
@@ -241,7 +239,6 @@ void DocumentImporter::finish()
armature_importer.set_tags_map(this->uid_tags_map);
armature_importer.make_armatures(mContext, *objects_to_scale);
armature_importer.make_shape_keys(mContext);
- DAG_relations_tag_update(bmain);
#if 0
armature_importer.fix_animation();
@@ -257,35 +254,29 @@ void DocumentImporter::finish()
if (libnode_ob.size()) {
- fprintf(stderr, "got %d library nodes to free\n", (int)libnode_ob.size());
+ fprintf(stderr, "| Cleanup: free %d library nodes\n", (int)libnode_ob.size());
// free all library_nodes
- std::vector<Object *>::iterator lit;
- for (lit = libnode_ob.begin(); lit != libnode_ob.end(); lit++) {
- Object *ob = *lit;
-
- Base *base = BKE_scene_base_find(sce, ob);
- if (base) {
- BLI_remlink(&sce->base, base);
- BKE_libblock_free_us(bmain, base->object);
- if (sce->basact == base)
- sce->basact = NULL;
- MEM_freeN(base);
- }
+ std::vector<Object *>::iterator it;
+ for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
+ Object *ob = *it;
+ BKE_scene_collections_object_remove(bmain, sce, ob, true);
}
libnode_ob.clear();
-
- DAG_relations_tag_update(bmain);
}
bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units);
delete objects_to_scale;
+
+ // update scene
+ DEG_id_tag_update(&sce->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(mContext, NC_OBJECT | ND_TRANSFORM, NULL);
}
void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL)
{
- Main *bmain = CTX_data_main(mContext);
// The split in #29246, rootmap must point at actual root when
// calculating bones in apply_curves_as_matrix. - actual root is the root node.
// This has to do with inverse bind poses being world space
@@ -320,7 +311,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW
translate_anim_recursive(node, node, parob);
}
else {
- anim_importer.translate_Animations(bmain, node, root_map, object_map, FW_object_map, uid_material_map);
+ anim_importer.translate_Animations(node, root_map, object_map, FW_object_map, uid_material_map);
COLLADAFW::NodePointerArray &children = node->getChildNodes();
for (i = 0; i < children.getCount(); i++) {
translate_anim_recursive(children[i], node, NULL);
@@ -384,7 +375,7 @@ Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera
}
Main *bmain = CTX_data_main(mContext);
- Object *ob = bc_add_object(bmain, sce, OB_CAMERA, NULL);
+ Object *ob = bc_add_object(bmain, sce, view_layer, OB_CAMERA, NULL);
Camera *cam = uid_camera_map[cam_uid];
Camera *old_cam = (Camera *)ob->data;
ob->data = cam;
@@ -396,12 +387,12 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce
{
const COLLADAFW::UniqueId& lamp_uid = lamp->getInstanciatedObjectId();
if (uid_lamp_map.find(lamp_uid) == uid_lamp_map.end()) {
- fprintf(stderr, "Couldn't find lamp by UID.\n");
+ fprintf(stderr, "Couldn't find light by UID.\n");
return NULL;
}
Main *bmain = CTX_data_main(mContext);
- Object *ob = bc_add_object(bmain, sce, OB_LAMP, NULL);
+ Object *ob = bc_add_object(bmain, sce, view_layer, OB_LAMP, NULL);
Lamp *la = uid_lamp_map[lamp_uid];
Lamp *old_lamp = (Lamp *)ob->data;
ob->data = la;
@@ -411,12 +402,12 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce
Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Node *source_node, COLLADAFW::Node *instance_node, Scene *sce, bool is_library_node)
{
- fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL);
+ //fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL);
Main *bmain = CTX_data_main(mContext);
Object *obn = BKE_object_copy(bmain, source_ob);
- DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- BKE_scene_base_add(sce, obn);
+ DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ BKE_collection_object_add_from(bmain, sce, source_ob, obn);
if (instance_node) {
anim_importer.read_node_transform(instance_node, obn);
@@ -511,15 +502,16 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
std::vector<Object *> *root_objects = new std::vector<Object *>();
fprintf(stderr,
- "Writing node id='%s', name='%s'\n",
- id.c_str(),
- name.c_str());
+ "| %s id='%s', name='%s'\n",
+ is_joint ? "JOINT" : "NODE ",
+ id.c_str(),
+ name.c_str() );
if (is_joint) {
if (parent_node == NULL && !is_library_node) {
// A Joint on root level is a skeleton without root node.
// Here we add the armature "on the fly":
- par = bc_add_object(bmain, sce, OB_ARMATURE, std::string("Armature").c_str());
+ par = bc_add_object(bmain, sce, view_layer, OB_ARMATURE, std::string("Armature").c_str());
objects_done->push_back(par);
root_objects->push_back(par);
object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), par));
@@ -551,8 +543,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
// maybe join multiple <instance_...> meshes into 1, and link object with it? not sure...
// <instance_geometry>
while (geom_done < geom.getCount()) {
- ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map,
- material_texture_mapping_map);
+ ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map);
if (ob == NULL) {
report_unknown_reference(*node, "instance_mesh");
}
@@ -592,7 +583,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
}
while (controller_done < controller.getCount()) {
COLLADAFW::InstanceGeometry *geometry = (COLLADAFW::InstanceGeometry *)controller[controller_done];
- ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map, material_texture_mapping_map);
+ ob = mesh_importer.create_mesh_object(node, geometry, true, uid_material_map);
if (ob == NULL) {
report_unknown_reference(*node, "instance_controller");
}
@@ -633,10 +624,10 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
if ( (geom_done + camera_done + lamp_done + controller_done + inst_done) < 1) {
//Check if Object is armature, by checking if immediate child is a JOINT node.
if (is_armature(node)) {
- ob = bc_add_object(bmain, sce, OB_ARMATURE, name.c_str());
+ ob = bc_add_object(bmain, sce, view_layer, OB_ARMATURE, name.c_str());
}
else {
- ob = bc_add_object(bmain, sce, OB_EMPTY, NULL);
+ ob = bc_add_object(bmain, sce, view_layer, OB_EMPTY, NULL);
}
objects_done->push_back(ob);
if (parent_node == NULL) {
@@ -709,7 +700,7 @@ finally:
*/
bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScene)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
// this method called on post process after writeGeometry, writeMaterial, etc.
@@ -732,19 +723,19 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen
* \return The writer should return true, if writing succeeded, false otherwise.*/
bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
Scene *sce = CTX_data_scene(mContext);
const COLLADAFW::NodePointerArray& nodes = libraryNodes->getNodes();
+ fprintf(stderr, "+-- Read Library nodes ----------\n");
for (unsigned int i = 0; i < nodes.getCount(); i++) {
std::vector<Object *> *child_objects;
child_objects = write_node(nodes[i], NULL, sce, NULL, true);
delete child_objects;
}
-
return true;
}
@@ -752,7 +743,7 @@ bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryN
* \return The writer should return true, if writing succeeded, false otherwise.*/
bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
return mesh_importer.write_geometry(geom);
@@ -762,7 +753,7 @@ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
* \return The writer should return true, if writing succeeded, false otherwise.*/
bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
Main *bmain = CTX_data_main(mContext);
@@ -775,181 +766,18 @@ bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
return true;
}
-// create mtex, create texture, set texture image
-MTex *DocumentImporter::create_texture(COLLADAFW::EffectCommon *ef, COLLADAFW::Texture &ctex, Material *ma,
- int i, TexIndexTextureArrayMap &texindex_texarray_map)
-{
- COLLADAFW::SamplerPointerArray& samp_array = ef->getSamplerPointerArray();
- COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
-
- const COLLADAFW::UniqueId& ima_uid = sampler->getSourceImage();
-
- if (uid_image_map.find(ima_uid) == uid_image_map.end()) {
- fprintf(stderr, "Couldn't find an image by UID.\n");
- return NULL;
- }
-
- Main *bmain = CTX_data_main(mContext);
- ma->mtex[i] = BKE_texture_mtex_add();
- ma->mtex[i]->texco = TEXCO_UV;
- ma->mtex[i]->tex = BKE_texture_add(bmain, "Texture");
- ma->mtex[i]->tex->type = TEX_IMAGE;
- ma->mtex[i]->tex->ima = uid_image_map[ima_uid];
-
- texindex_texarray_map[ctex.getTextureMapId()].push_back(ma->mtex[i]);
-
- return ma->mtex[i];
-}
void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Material *ma)
{
- COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
-
- // blinn
- if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
- ma->spec_shader = MA_SPEC_BLINN;
- ma->spec = ef->getShininess().getFloatValue();
- }
- // phong
- else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
- ma->spec_shader = MA_SPEC_PHONG;
- ma->har = ef->getShininess().getFloatValue();
- }
- // lambert
- else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
- ma->diff_shader = MA_DIFF_LAMBERT;
- }
- // default - lambert
- else {
- ma->diff_shader = MA_DIFF_LAMBERT;
- fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
- }
- // reflectivity
- ma->ray_mirror = ef->getReflectivity().getFloatValue();
- // index of refraction
- ma->ang = ef->getIndexOfRefraction().getFloatValue();
-
- int i = 0;
- COLLADAFW::Color col;
- MTex *mtex = NULL;
- TexIndexTextureArrayMap texindex_texarray_map;
-
- // DIFFUSE
- // color
- if (ef->getDiffuse().isColor()) {
- /* too high intensity can create artefacts (fireflies)
- So here we take care that intensity is set to 0.8 wherever possible
- */
- col = ef->getDiffuse().getColor();
- ma->ref = max_ffff(col.getRed(), col.getGreen(), col.getBlue(), 0.8);
- ma->r = col.getRed() / ma->ref;
- ma->g = col.getGreen() / ma->ref;
- ma->b = col.getBlue() / ma->ref;
- }
- // texture
- else if (ef->getDiffuse().isTexture()) {
- COLLADAFW::Texture ctex = ef->getDiffuse().getTexture();
- mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
- if (mtex != NULL) {
- mtex->mapto = MAP_COL;
- ma->texact = (int)i;
- i++;
- }
- }
- // AMBIENT
- // color
- if (ef->getAmbient().isColor()) {
- col = ef->getAmbient().getColor();
- ma->ambr = col.getRed();
- ma->ambg = col.getGreen();
- ma->ambb = col.getBlue();
- }
- // texture
- else if (ef->getAmbient().isTexture()) {
- COLLADAFW::Texture ctex = ef->getAmbient().getTexture();
- mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
- if (mtex != NULL) {
- mtex->mapto = MAP_AMB;
- i++;
- }
- }
- // SPECULAR
- // color
- if (ef->getSpecular().isColor()) {
- col = ef->getSpecular().getColor();
- ma->specr = col.getRed();
- ma->specg = col.getGreen();
- ma->specb = col.getBlue();
- }
- // texture
- else if (ef->getSpecular().isTexture()) {
- COLLADAFW::Texture ctex = ef->getSpecular().getTexture();
- mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
- if (mtex != NULL) {
- mtex->mapto = MAP_SPEC;
- i++;
- }
- }
- // REFLECTIVE
- // color
- if (ef->getReflective().isColor()) {
- col = ef->getReflective().getColor();
- ma->mirr = col.getRed();
- ma->mirg = col.getGreen();
- ma->mirb = col.getBlue();
- }
- // texture
- else if (ef->getReflective().isTexture()) {
- COLLADAFW::Texture ctex = ef->getReflective().getTexture();
- mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
- if (mtex != NULL) {
- mtex->mapto = MAP_REF;
- i++;
- }
- }
-
- // EMISSION
- // color
- if (ef->getEmission().isColor()) {
- // XXX there is no emission color in blender
- // but I am not sure
- }
- // texture
- else if (ef->getEmission().isTexture()) {
- COLLADAFW::Texture ctex = ef->getEmission().getTexture();
- mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
- if (mtex != NULL) {
- mtex->mapto = MAP_EMIT;
- i++;
- }
- }
-
- // TRANSPARENT
- // color
- if (ef->getOpacity().isColor()) {
- col = ef->getTransparent().getColor();
- float alpha = ef->getTransparency().getFloatValue();
- if (col.isValid()) {
- alpha *= col.getAlpha(); // Assuming A_ONE opaque mode
- }
- if (col.isValid() || alpha < 1.0) {
- ma->alpha = alpha;
- ma->mode |= MA_ZTRANSP | MA_TRANSP;
- }
- }
- // texture
- else if (ef->getOpacity().isTexture()) {
- COLLADAFW::Texture ctex = ef->getOpacity().getTexture();
- mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
- if (mtex != NULL) {
- mtex->mapto = MAP_ALPHA;
- i++;
- ma->spectra = ma->alpha = 0;
- ma->mode |= MA_ZTRANSP | MA_TRANSP;
- }
- }
-
- material_texture_mapping_map[ma] = texindex_texarray_map;
+ MaterialNode matNode = MaterialNode(mContext, ef, ma, uid_image_map);
+ matNode.set_reflectivity(ef->getReflectivity().getFloatValue());
+ matNode.set_ior(ef->getIndexOfRefraction().getFloatValue());
+ matNode.set_diffuse(ef->getDiffuse(), "Diffuse");
+ matNode.set_ambient(ef->getAmbient(), "Ambient");
+ matNode.set_specular(ef->getSpecular(), "Specular");
+ matNode.set_reflective(ef->getReflective(), "Reflective");
+ matNode.set_emission(ef->getEmission(), "Emission");
+ matNode.set_opacity(ef->getOpacity(), "Opacity");
}
/** When this method is called, the writer must write the effect.
@@ -957,7 +785,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
const COLLADAFW::UniqueId& uid = effect->getUniqueId();
@@ -994,7 +822,7 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
* \return The writer should return true, if writing succeeded, false otherwise.*/
bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
Main *bmain = CTX_data_main(mContext);
@@ -1120,7 +948,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
* \return The writer should return true, if writing succeeded, false otherwise.*/
bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
const std::string& imagepath = image->getImageURI().toNativePath();
@@ -1137,7 +965,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
else {
// Maybe imagepath was already absolute ?
if (!BLI_exists(imagepath.c_str())) {
- fprintf(stderr, "Image not found: %s.\n", imagepath.c_str() );
+ fprintf(stderr, "|! Image not found: %s\n", imagepath.c_str() );
return true;
}
workpath = imagepath.c_str();
@@ -1145,11 +973,11 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
Image *ima = BKE_image_load_exists(CTX_data_main(mContext), workpath);
if (!ima) {
- fprintf(stderr, "Cannot create image: %s\n", workpath);
+ fprintf(stderr, "|! Cannot create image: %s\n", workpath);
return true;
}
this->uid_image_map[image->getUniqueId()] = ima;
-
+ fprintf(stderr, "| import Image: %s\n", workpath);
return true;
}
@@ -1157,7 +985,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
* \return The writer should return true, if writing succeeded, false otherwise.*/
bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
Main *bmain = CTX_data_main(mContext);
@@ -1177,7 +1005,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
else lamp = (Lamp *)BKE_lamp_add(bmain, (char *)la_id.c_str());
if (!lamp) {
- fprintf(stderr, "Cannot create lamp.\n");
+ fprintf(stderr, "Cannot create light.\n");
return true;
}
@@ -1198,7 +1026,6 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
et->setData("spotsize", &(lamp->spotsize));
lamp->spotsize = DEG2RADF(lamp->spotsize);
et->setData("spotblend", &(lamp->spotblend));
- et->setData("halo_intensity", &(lamp->haint));
et->setData("att1", &(lamp->att1));
et->setData("att2", &(lamp->att2));
et->setData("falloff_type", &(lamp->falloff_type));
@@ -1206,38 +1033,12 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
et->setData("clipend", &(lamp->clipend));
et->setData("bias", &(lamp->bias));
et->setData("soft", &(lamp->soft));
- et->setData("compressthresh", &(lamp->compressthresh));
et->setData("bufsize", &(lamp->bufsize));
- et->setData("samp", &(lamp->samp));
et->setData("buffers", &(lamp->buffers));
- et->setData("filtertype", &(lamp->filtertype));
- et->setData("bufflag", &(lamp->bufflag));
- et->setData("buftype", &(lamp->buftype));
- et->setData("ray_samp", &(lamp->ray_samp));
- et->setData("ray_sampy", &(lamp->ray_sampy));
- et->setData("ray_sampz", &(lamp->ray_sampz));
- et->setData("ray_samp_type", &(lamp->ray_samp_type));
et->setData("area_shape", &(lamp->area_shape));
et->setData("area_size", &(lamp->area_size));
et->setData("area_sizey", &(lamp->area_sizey));
et->setData("area_sizez", &(lamp->area_sizez));
- et->setData("adapt_thresh", &(lamp->adapt_thresh));
- et->setData("ray_samp_method", &(lamp->ray_samp_method));
- et->setData("shadhalostep", &(lamp->shadhalostep));
- et->setData("sun_effect_type", &(lamp->shadhalostep));
- et->setData("skyblendtype", &(lamp->skyblendtype));
- et->setData("horizon_brightness", &(lamp->horizon_brightness));
- et->setData("spread", &(lamp->spread));
- et->setData("sun_brightness", &(lamp->sun_brightness));
- et->setData("sun_size", &(lamp->sun_size));
- et->setData("backscattered_light", &(lamp->backscattered_light));
- et->setData("sun_intensity", &(lamp->sun_intensity));
- et->setData("atm_turbidity", &(lamp->atm_turbidity));
- et->setData("atm_extinction_factor", &(lamp->atm_extinction_factor));
- et->setData("atm_distance_factor", &(lamp->atm_distance_factor));
- et->setData("skyblendfac", &(lamp->skyblendfac));
- et->setData("sky_exposure", &(lamp->sky_exposure));
- et->setData("sky_colorspace", &(lamp->sky_colorspace));
}
else {
float constatt = light->getConstantAttenuation().getValue();
@@ -1277,11 +1078,10 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
lamp->energy = e;
lamp->dist = d;
- COLLADAFW::Light::LightType type = light->getLightType();
- switch (type) {
+ switch (light->getLightType()) {
case COLLADAFW::Light::AMBIENT_LIGHT:
{
- lamp->type = LA_HEMI;
+ lamp->type = LA_SUN; //TODO needs more thoughts
}
break;
case COLLADAFW::Light::SPOT_LIGHT:
@@ -1301,7 +1101,6 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
{
/* our sun is very strong, so pick a smaller energy level */
lamp->type = LA_SUN;
- lamp->mode |= LA_NO_SPEC;
}
break;
case COLLADAFW::Light::POINT_LIGHT:
@@ -1317,7 +1116,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
break;
case COLLADAFW::Light::UNDEFINED:
{
- fprintf(stderr, "Current lamp type is not supported.\n");
+ fprintf(stderr, "Current light type is not supported.\n");
lamp->type = LA_LOCAL;
}
break;
@@ -1332,7 +1131,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
// this function is called only for animations that pass COLLADAFW::validate
bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
// return true;
@@ -1342,7 +1141,7 @@ bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
// called on post-process stage after writeVisualScenes
bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animationList)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
// return true;
@@ -1359,7 +1158,7 @@ bool DocumentImporter::writeSkinControllerData(const COLLADAFW::SkinControllerDa
// this is called on postprocess, before writeVisualScenes
bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
{
- if (mImportStage != General)
+ if (mImportStage == Fetching_Controller_data)
return true;
return armature_importer.write_controller(controller);
diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h
index 17e61326032..26ded417aa6 100644
--- a/source/blender/collada/DocumentImporter.h
+++ b/source/blender/collada/DocumentImporter.h
@@ -59,8 +59,8 @@ class DocumentImporter : COLLADAFW::IWriter
public:
//! Enumeration to denote the stage of import
enum ImportStage {
- General, //!< First pass to collect all data except controller
- Controller, //!< Second pass to collect controller data
+ Fetching_Scene_data, /* First pass to collect all data except controller */
+ Fetching_Controller_data, /* Second pass to collect controller data */
};
/** Constructor */
DocumentImporter(bContext *C, const ImportSettings *import_settings);
@@ -77,7 +77,6 @@ public:
Object* create_instance_node(Object*, COLLADAFW::Node*, COLLADAFW::Node*, Scene*, bool);
void create_constraints(ExtraTags *et, Object *ob);
std::vector<Object *> *write_node(COLLADAFW::Node*, COLLADAFW::Node*, Scene*, Object*, bool);
- MTex* create_texture(COLLADAFW::EffectCommon*, COLLADAFW::Texture&, Material*, int, TexIndexTextureArrayMap&);
void write_profile_COMMON(COLLADAFW::EffectCommon*, Material*);
void translate_anim_recursive(COLLADAFW::Node*, COLLADAFW::Node*, Object*);
@@ -144,6 +143,7 @@ private:
ImportStage mImportStage;
bContext *mContext;
+ ViewLayer *view_layer;
UnitConverter unit_converter;
ArmatureImporter armature_importer;
@@ -155,7 +155,7 @@ private:
/** Tags map of unique id as a string and ExtraTags instance. */
TagsMap uid_tags_map;
- std::map<COLLADAFW::UniqueId, Image*> uid_image_map;
+ UidImageMap uid_image_map;
std::map<COLLADAFW::UniqueId, Material*> uid_material_map;
std::map<COLLADAFW::UniqueId, Material*> uid_effect_map;
std::map<COLLADAFW::UniqueId, Camera*> uid_camera_map;
@@ -172,6 +172,7 @@ private:
std::string import_from_version;
void report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type);
+
};
#endif
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index d33ce725e58..f16392cdc1c 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -27,6 +27,7 @@
#include <map>
+#include <set>
#include "COLLADASWEffectProfile.h"
#include "COLLADAFWColorOrTexture.h"
@@ -40,24 +41,36 @@
extern "C" {
#include "DNA_mesh_types.h"
- #include "DNA_texture_types.h"
#include "DNA_world_types.h"
+ #include "BKE_collection.h"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
}
-EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryEffects(sw), export_settings(export_settings) {
+static std::string getActiveUVLayerName(Object *ob)
+{
+ Mesh *me = (Mesh *)ob->data;
+
+ int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
+ if (num_layers)
+ return std::string(bc_CustomData_get_active_layer_name(&me->ldata, CD_MLOOPUV));
+
+ return "";
}
+EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map) :
+ COLLADASW::LibraryEffects(sw),
+ export_settings(export_settings),
+ key_image_map(key_image_map)
+{}
+
bool EffectsExporter::hasEffects(Scene *sce)
{
- Base *base = (Base *)sce->base.first;
-
- while (base) {
- Object *ob = base->object;
+ FOREACH_SCENE_OBJECT_BEGIN(sce, ob)
+ {
int a;
for (a = 0; a < ob->totcol; a++) {
Material *ma = give_current_material(ob, a + 1);
@@ -67,234 +80,123 @@ bool EffectsExporter::hasEffects(Scene *sce)
return true;
}
- base = base->next;
}
+ FOREACH_SCENE_OBJECT_END;
return false;
}
-void EffectsExporter::exportEffects(Scene *sce)
+void EffectsExporter::exportEffects(bContext *C, Scene *sce)
{
- this->scene = sce;
-
- if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) {
- if (hasEffects(sce)) {
- MaterialFunctor mf;
- openLibrary();
- mf.forEachMaterialInExportSet<EffectsExporter>(sce, *this, this->export_settings->export_set);
- closeLibrary();
- }
- }
- else {
- std::set<Object *> uv_textured_obs = bc_getUVTexturedObjects(sce, !this->export_settings->active_uv_only);
- std::set<Image *> uv_images = bc_getUVImages(sce, !this->export_settings->active_uv_only);
- if (uv_images.size() > 0) {
- openLibrary();
- std::set<Image *>::iterator uv_images_iter;
- for (uv_images_iter = uv_images.begin();
- uv_images_iter != uv_images.end();
- uv_images_iter++)
- {
-
- Image *ima = *uv_images_iter;
- std::string key(id_name(ima));
- key = translate_id(key);
- COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
- key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
- key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
- sampler.setImageId(key);
-
- openEffect(key + "-effect");
- COLLADASW::EffectProfile ep(mSW);
- ep.setProfileType(COLLADASW::EffectProfile::COMMON);
- ep.setShaderType(COLLADASW::EffectProfile::PHONG);
- ep.setDiffuse(createTexture(ima, key, &sampler), false, "diffuse");
- COLLADASW::ColorOrTexture cot = getcol(0, 0, 0, 1.0f);
- ep.setSpecular(cot, false, "specular");
- ep.openProfile();
- ep.addProfileElements();
- ep.addExtraTechniques(mSW);
- ep.closeProfile();
- closeEffect();
- }
- closeLibrary();
- }
+ if (hasEffects(sce)) {
+ this->mContext = C;
+ this->scene = sce;
+ openLibrary();
+ MaterialFunctor mf;
+ mf.forEachMaterialInExportSet<EffectsExporter>(sce, *this, this->export_settings->export_set);
+
+ closeLibrary();
}
}
-void EffectsExporter::writeBlinn(COLLADASW::EffectProfile &ep, Material *ma)
+void EffectsExporter::set_shader_type(COLLADASW::EffectProfile &ep, Material *ma)
{
- COLLADASW::ColorOrTexture cot;
- ep.setShaderType(COLLADASW::EffectProfile::BLINN);
- // shininess
- ep.setShininess(ma->har, false, "shininess");
- // specular
- cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
- ep.setSpecular(cot, false, "specular");
+ ep.setShaderType(COLLADASW::EffectProfile::LAMBERT); //XXX check if BLINN and PHONG can be supported as well
}
-void EffectsExporter::writeLambert(COLLADASW::EffectProfile &ep, Material *ma)
+void EffectsExporter::set_transparency(COLLADASW::EffectProfile &ep, Material *ma)
{
- COLLADASW::ColorOrTexture cot;
- ep.setShaderType(COLLADASW::EffectProfile::LAMBERT);
+ if (ma->alpha == 1.0f) {
+ return; // have no transparency
+ }
+
+ // Tod: because we are in A_ONE mode transparency is calculated like this:
+ COLLADASW::ColorOrTexture cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha);
+ ep.setTransparent(cot);
+ ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
+}
+void EffectsExporter::set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma)
+{
+ // get diffuse color
+ COLLADASW::ColorOrTexture cot = bc_get_base_color(ma);
+ ep.setDiffuse(cot, false, "diffuse");
}
-void EffectsExporter::writePhong(COLLADASW::EffectProfile &ep, Material *ma)
+void EffectsExporter::set_specular_color(COLLADASW::EffectProfile &ep, Material *ma)
{
- COLLADASW::ColorOrTexture cot;
- ep.setShaderType(COLLADASW::EffectProfile::PHONG);
- // shininess
- ep.setShininess(ma->har, false, "shininess");
- // specular
- cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
+ bool use_fallback = ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT;
+ COLLADASW::ColorOrTexture cot = bc_get_specular_color(ma, use_fallback);
ep.setSpecular(cot, false, "specular");
}
-void EffectsExporter::writeTextures(
- COLLADASW::EffectProfile &ep,
- std::string &key,
- COLLADASW::Sampler *sampler,
- MTex *t, Image *ima,
- std::string &uvname )
+void EffectsExporter::set_emission(COLLADASW::EffectProfile &ep, Material *ma)
{
- // Image not set for texture
- if (!ima) return;
+ // not yet supported (needs changes in principled shader
+}
- // color
- if (t->mapto & MAP_COL) {
- ep.setDiffuse(createTexture(ima, uvname, sampler), false, "diffuse");
- }
- // ambient
- if (t->mapto & MAP_AMB) {
- ep.setAmbient(createTexture(ima, uvname, sampler), false, "ambient");
- }
- // specular
- if (t->mapto & (MAP_SPEC | MAP_COLSPEC)) {
- ep.setSpecular(createTexture(ima, uvname, sampler), false, "specular");
- }
- // emission
- if (t->mapto & MAP_EMIT) {
- ep.setEmission(createTexture(ima, uvname, sampler), false, "emission");
- }
- // reflective
- if (t->mapto & MAP_REF) {
- ep.setReflective(createTexture(ima, uvname, sampler));
+void EffectsExporter::get_images(Material *ma, KeyImageMap &material_image_map)
+{
+ if (!ma->use_nodes) {
+ return;
}
- // alpha
- if (t->mapto & MAP_ALPHA) {
- ep.setTransparent(createTexture(ima, uvname, sampler));
+
+ MaterialNode material = MaterialNode(mContext, ma, key_image_map);
+ Image *image = material.get_diffuse_image();
+ if (image == nullptr) {
+ return;
}
- // extension:
- // Normal map --> Must be stored with <extra> tag as different technique,
- // since COLLADA doesn't support normal maps, even in current COLLADA 1.5.
- if (t->mapto & MAP_NORM) {
- COLLADASW::Texture texture(key);
- texture.setTexcoord(uvname);
- texture.setSampler(*sampler);
- // technique FCOLLADA, with the <bump> tag, is most likely the best understood,
- // most widespread de-facto standard.
- texture.setProfileName("FCOLLADA");
- texture.setChildElementName("bump");
- ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
+
+ std::string uid(id_name(image));
+ std::string key = translate_id(uid);
+
+ if (material_image_map.find(key) == material_image_map.end()) {
+ material_image_map[key] = image;
+ key_image_map[key] = image;
}
}
-void EffectsExporter::operator()(Material *ma, Object *ob)
+void EffectsExporter::create_image_samplers(COLLADASW::EffectProfile &ep, KeyImageMap &material_image_map, std::string &active_uv)
{
- // create a list of indices to textures of type TEX_IMAGE
- std::vector<int> tex_indices;
- createTextureIndices(ma, tex_indices);
+ KeyImageMap::iterator iter;
- openEffect(translate_id(id_name(ma)) + "-effect");
+ for (iter = material_image_map.begin(); iter != material_image_map.end(); iter++) {
- COLLADASW::EffectProfile ep(mSW);
- ep.setProfileType(COLLADASW::EffectProfile::COMMON);
- ep.openProfile();
- // set shader type - one of three blinn, phong or lambert
- if (ma->spec > 0.0f) {
- if (ma->spec_shader == MA_SPEC_BLINN) {
- writeBlinn(ep, ma);
- }
- else {
- // \todo figure out handling of all spec+diff shader combos blender has, for now write phong
- // for now set phong in case spec shader is not blinn
- writePhong(ep, ma);
- }
- }
- else {
- if (ma->diff_shader == MA_DIFF_LAMBERT) {
- writeLambert(ep, ma);
- }
- else {
- // \todo figure out handling of all spec+diff shader combos blender has, for now write phong
- writePhong(ep, ma);
- }
- }
+ Image *image = iter->second;
+ std::string uid(id_name(image));
+ std::string key = translate_id(uid);
- // index of refraction
- if (ma->mode & MA_RAYTRANSP) {
- ep.setIndexOfRefraction(ma->ang, false, "index_of_refraction");
- }
- else {
- ep.setIndexOfRefraction(1.0f, false, "index_of_refraction");
- }
+ COLLADASW::Sampler *sampler = new COLLADASW::Sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
+ key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
+ key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
- COLLADASW::ColorOrTexture cot;
+ sampler->setImageId(key);
- // transparency
- if (ma->mode & MA_TRANSP) {
- // Tod: because we are in A_ONE mode transparency is calculated like this:
- cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha);
- ep.setTransparent(cot);
- ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
+ ep.setDiffuse(createTexture(image, active_uv, sampler), false, "diffuse");
}
+}
- // emission
- cot = getcol(ma->emit, ma->emit, ma->emit, 1.0f);
- ep.setEmission(cot, false, "emission");
-
- // diffuse multiplied by diffuse intensity
- cot = getcol(ma->r * ma->ref, ma->g * ma->ref, ma->b * ma->ref, 1.0f);
- ep.setDiffuse(cot, false, "diffuse");
-
- // ambient
- /* ma->ambX is calculated only on render, so lets do it here manually and not rely on ma->ambX. */
- if (this->scene->world)
- cot = getcol(this->scene->world->ambr * ma->amb, this->scene->world->ambg * ma->amb, this->scene->world->ambb * ma->amb, 1.0f);
- else
- cot = getcol(ma->amb, ma->amb, ma->amb, 1.0f);
+void EffectsExporter::operator()(Material *ma, Object *ob)
+{
+ KeyImageMap material_image_map;
- ep.setAmbient(cot, false, "ambient");
+ openEffect(get_effect_id(ma));
- // reflective, reflectivity
- if (ma->mode & MA_RAYMIRROR) {
- cot = getcol(ma->mirr, ma->mirg, ma->mirb, 1.0f);
- ep.setReflective(cot);
- ep.setReflectivity(ma->ray_mirror);
- }
- // else {
- // cot = getcol(ma->specr, ma->specg, ma->specb, 1.0f);
- // ep.setReflective(cot);
- // ep.setReflectivity(ma->spec);
- // }
-
- // specular
- if (ep.getShaderType() != COLLADASW::EffectProfile::LAMBERT) {
- cot = getcol(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f);
- ep.setSpecular(cot, false, "specular");
- }
+ COLLADASW::EffectProfile ep(mSW);
+ ep.setProfileType(COLLADASW::EffectProfile::COMMON);
+ ep.openProfile();
+ set_shader_type(ep, ma);
- // XXX make this more readable if possible
+ COLLADASW::ColorOrTexture cot;
- // create <sampler> and <surface> for each image
- COLLADASW::Sampler samplers[MAX_MTEX];
- //COLLADASW::Surface surfaces[MAX_MTEX];
- //void *samp_surf[MAX_MTEX][2];
- void *samp_surf[MAX_MTEX];
+ set_transparency(ep, ma);
+ set_diffuse_color(ep, ma);
+ set_specular_color(ep, ma);
+ set_emission(ep, ma);
- // image to index to samp_surf map
- // samp_surf[index] stores 2 pointers, sampler and surface
- std::map<std::string, int> im_samp_map;
+ get_images(ma, material_image_map);
+ std::string active_uv(getActiveUVLayerName(ob));
+ create_image_samplers(ep, material_image_map, active_uv);
+#if 0
unsigned int a, b;
for (a = 0, b = 0; a < tex_indices.size(); a++) {
MTex *t = ma->mtex[tex_indices[a]];
@@ -308,24 +210,13 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
// create only one <sampler>/<surface> pair for each unique image
if (im_samp_map.find(key) == im_samp_map.end()) {
- // //<newparam> <surface> <init_from>
- // COLLADASW::Surface surface(COLLADASW::Surface::SURFACE_TYPE_2D,
- // key + COLLADASW::Surface::SURFACE_SID_SUFFIX);
- // COLLADASW::SurfaceInitOption sio(COLLADASW::SurfaceInitOption::INIT_FROM);
- // sio.setImageReference(key);
- // surface.setInitOption(sio);
-
- // COLLADASW::NewParamSurface surface(mSW);
- // surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D);
-
//<newparam> <sampler> <source>
COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
- key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
- key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
+ key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
+ key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
sampler.setImageId(key);
// copy values to arrays since they will live longer
samplers[a] = sampler;
- //surfaces[a] = surface;
// store pointers so they can be used later when we create <texture>s
samp_surf[b] = &samplers[a];
@@ -336,12 +227,6 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
}
}
- // used as fallback when MTex->uvname is "" (this is pretty common)
- // it is indeed the correct value to use in that case
- std::string active_uv(bc_get_active_uvlayer_name(ob));
-
- // write textures
- // XXX very slow
for (a = 0; a < tex_indices.size(); a++) {
MTex *t = ma->mtex[tex_indices[a]];
Image *ima = t->tex->ima;
@@ -354,9 +239,10 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
key = translate_id(key);
int i = im_samp_map[key];
std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
- COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i];
+ COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i]; // possibly uninitialised memory ...
writeTextures(ep, key, sampler, t, ima, uvname);
}
+#endif
// performs the actual writing
ep.addProfileElements();
@@ -397,20 +283,3 @@ COLLADASW::ColorOrTexture EffectsExporter::getcol(float r, float g, float b, flo
COLLADASW::ColorOrTexture cot(color);
return cot;
}
-
-//returns the array of mtex indices which have image
-//need this for exporting textures
-void EffectsExporter::createTextureIndices(Material *ma, std::vector<int> &indices)
-{
- indices.clear();
-
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] &&
- ma->mtex[a]->tex &&
- ma->mtex[a]->tex->type == TEX_IMAGE &&
- ma->mtex[a]->texco == TEXCO_UV)
- {
- indices.push_back(a);
- }
- }
-}
diff --git a/source/blender/collada/EffectExporter.h b/source/blender/collada/EffectExporter.h
index 278e1ebcfce..462f1548586 100644
--- a/source/blender/collada/EffectExporter.h
+++ b/source/blender/collada/EffectExporter.h
@@ -42,12 +42,14 @@
#include "DNA_scene_types.h"
#include "ExportSettings.h"
+#include "collada_utils.h"
class EffectsExporter: COLLADASW::LibraryEffects
{
public:
- EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
- void exportEffects(Scene *sce);
+ EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map);
+ void exportEffects(bContext *C, Scene *sce);
+
void operator()(Material *ma, Object *ob);
COLLADASW::ColorOrTexture createTexture(Image *ima,
@@ -57,12 +59,14 @@ public:
COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a);
private:
- /** Fills the array of mtex indices which have image. Used for exporting images. */
- void createTextureIndices(Material *ma, std::vector<int> &indices);
+ void set_shader_type(COLLADASW::EffectProfile &ep, Material *ma);
+ void set_transparency(COLLADASW::EffectProfile &ep, Material *ma);
+ void set_diffuse_color(COLLADASW::EffectProfile &ep, Material *ma);
+ void set_specular_color(COLLADASW::EffectProfile &ep, Material *ma);
+ void set_emission(COLLADASW::EffectProfile &ep, Material *ma);
+ void get_images(Material *ma, KeyImageMap &uid_image_map);
+ void create_image_samplers(COLLADASW::EffectProfile &ep, KeyImageMap &uid_image_map, std::string &active_uv);
- void writeBlinn(COLLADASW::EffectProfile &ep, Material *ma);
- void writeLambert(COLLADASW::EffectProfile &ep, Material *ma);
- void writePhong(COLLADASW::EffectProfile &ep, Material *ma);
void writeTextures(COLLADASW::EffectProfile &ep,
std::string &key,
COLLADASW::Sampler *sampler,
@@ -72,8 +76,9 @@ private:
bool hasEffects(Scene *sce);
const ExportSettings *export_settings;
-
+ KeyImageMap &key_image_map;
Scene *scene;
+ bContext *mContext;
};
#endif
diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp
index caa73900632..e708cc9fc8c 100644
--- a/source/blender/collada/ErrorHandler.cpp
+++ b/source/blender/collada/ErrorHandler.cpp
@@ -49,47 +49,67 @@ ErrorHandler::~ErrorHandler()
//--------------------------------------------------------------------
bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
{
- /* This method must return true when Collada should continue.
+ /* This method must return false when Collada should continue.
* See https://github.com/KhronosGroup/OpenCOLLADA/issues/442
*/
- bool isWarning = false;
+ bool isError = true;
+ std::string error_context;
+ std::string error_message;
if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) {
+ error_context = "Schema validation";
+
COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *) error;
const GeneratedSaxParser::ParserError& parserError = saxParserError->getError();
+ error_message = parserError.getErrorMessage();
- // Workaround to avoid wrong error
if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_MIN_OCCURS_UNMATCHED) {
if (STREQ(parserError.getElement(), "effect")) {
- isWarning = true;
+ isError = false;
}
}
- if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT) {
+
+ else if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT) {
if (!(STREQ(parserError.getElement(), "extra") &&
STREQ(parserError.getAdditionalText().c_str(), "sibling: fx_profile_abstract")))
{
- isWarning = true;
+ isError = false;
}
}
- if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_COULD_NOT_OPEN_FILE) {
- std::cout << "Couldn't open file" << std::endl;
+ else if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_COULD_NOT_OPEN_FILE) {
+ isError = true;
+ error_context = "File access";
}
- std::cout << "Schema validation error: " << parserError.getErrorMessage() << std::endl;
+ else isError = (parserError.getSeverity() != GeneratedSaxParser::ParserError::Severity::SEVERITY_ERROR_NONCRITICAL);
+
}
else if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXFWL) {
+ error_context = "Sax FWL";
COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *) error;
+ error_message = saxFWLError->getErrorMessage();
+
/*
* Accept non critical errors as warnings (i.e. texture not found)
* This makes the importer more graceful, so it now imports what makes sense.
*/
- isWarning = (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL);
- std::cout << "Sax FWL Error: " << saxFWLError->getErrorMessage() << std::endl;
+
+ isError = (saxFWLError->getSeverity() != COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL);
+
}
else {
- std::cout << "opencollada error: " << error->getFullErrorMessage() << std::endl;
+ error_context = "OpenCollada";
+ error_message = error->getFullErrorMessage();
+ isError = true;
}
- return isWarning;
+ std::string severity = (isError) ? "Error" : "Warning";
+ std::cout << error_context << " (" << severity << "): " << error_message << std::endl;
+ if (isError) {
+ std::cout << "The Collada import has been forced to stop." << std::endl;
+ std::cout << "Please fix the reported error and then try again.";
+ mError = true;
+ }
+ return isError;
}
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index fa6751bef60..3b4397a6093 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -43,10 +43,19 @@ typedef enum BC_export_transformation_type {
BC_TRANSFORMATION_TYPE_TRANSROTLOC
} BC_export_transformation_type;
-typedef enum BC_export_texture_type {
- BC_TEXTURE_TYPE_MAT,
- BC_TEXTURE_TYPE_UV
-} BC_export_texture_type;
+
+typedef enum BC_export_animation_type {
+ BC_ANIMATION_EXPORT_SAMPLES,
+ BC_ANIMATION_EXPORT_KEYS
+} BC_export_animation_type;
+
+typedef enum BC_ui_export_section {
+ BC_UI_SECTION_MAIN,
+ BC_UI_SECTION_GEOMETRY,
+ BC_UI_SECTION_ARMATURE,
+ BC_UI_SECTION_ANIMATION,
+ BC_UI_SECTION_COLLADA
+} BC_ui_export_section;
typedef struct ExportSettings {
bool apply_modifiers;
@@ -58,10 +67,13 @@ typedef struct ExportSettings {
bool include_shapekeys;
bool deform_bones_only;
bool include_animations;
+ bool include_all_actions;
int sampling_rate;
+ bool keep_smooth_curves;
+ bool keep_keyframes;
bool active_uv_only;
- BC_export_texture_type export_texture_type;
+ BC_export_animation_type export_animation_type;
bool use_texture_copies;
bool triangulate;
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index eb627b5c066..a82d07d53dd 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -40,11 +40,9 @@
extern "C" {
#include "BLI_utildefines.h"
- #include "BKE_DerivedMesh.h"
- #include "BKE_main.h"
+ #include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_library.h"
- #include "BKE_customdata.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
}
@@ -53,17 +51,11 @@ extern "C" {
#include "collada_utils.h"
-// TODO: optimize UV sets by making indexed list with duplicates removed
-GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings)
-{
-}
-
-void GeometryExporter::exportGeom(Main *bmain, Scene *sce)
+void GeometryExporter::exportGeom()
{
+ Scene *sce = blender_context.get_scene();
openLibrary();
- m_bmain = bmain;
- mScene = sce;
GeometryFunctor gf;
gf.forEachMeshObjectInExportSet<GeometryExporter>(sce, *this, this->export_settings->export_set);
@@ -72,15 +64,9 @@ void GeometryExporter::exportGeom(Main *bmain, Scene *sce)
void GeometryExporter::operator()(Object *ob)
{
- // XXX don't use DerivedMesh, Mesh instead?
-#if 0
- DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
-#endif
-
bool use_instantiation = this->export_settings->use_object_instantiation;
Mesh *me = bc_get_mesh_copy(
- m_bmain,
- mScene,
+ blender_context,
ob,
this->export_settings->export_mesh_type,
this->export_settings->apply_modifiers,
@@ -98,6 +84,7 @@ void GeometryExporter::operator()(Object *ob)
}
std::string geom_name = (use_instantiation) ? id_name(ob->data) : id_name(ob);
+ geom_name = encode_xml(geom_name);
exportedGeometry.insert(geom_id);
@@ -114,7 +101,7 @@ void GeometryExporter::operator()(Object *ob)
// writes <source> for normal coords
createNormalsSource(geom_id, me, nor);
- bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
+ bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
// writes <source> for uv coords if mesh has uv coords
if (has_uvs) {
@@ -138,22 +125,13 @@ void GeometryExporter::operator()(Object *ob)
// Only create Polylists if number of faces > 0
if (me->totface > 0) {
// XXX slow
- std::set<Image *> uv_images = bc_getUVImages(ob, !this->export_settings->active_uv_only);
- if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT || uv_images.size() == 0) {
- if (ob->totcol) {
- for (int a = 0; a < ob->totcol; a++) {
- createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
- }
- }
- else {
- int i = 0;
- createPolylist(i, has_uvs, has_color, ob, me, geom_id, norind);
+ if (ob->totcol) {
+ for (int a = 0; a < ob->totcol; a++) {
+ createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
}
}
else {
- bool all_uv_layers = !this->export_settings->active_uv_only;
- std::set<Image *> uv_image_set = bc_getUVImages(ob, all_uv_layers);
- createPolylists(uv_image_set, has_uvs, has_color, ob, me, geom_id, norind);
+ createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
}
}
@@ -178,8 +156,7 @@ void GeometryExporter::operator()(Object *ob)
}
}
- BKE_libblock_free_us(m_bmain, me);
-
+ BKE_id_free(NULL, me);
}
void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
@@ -210,7 +187,7 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
// writes <source> for normal coords
createNormalsSource(geom_id, me, nor);
- bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
+ bool has_uvs = (bool)CustomData_has_layer(&me->ldata, CD_MLOOPUV);
// writes <source> for uv coords if mesh has uv coords
if (has_uvs) {
@@ -233,15 +210,13 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
//createLooseEdgeList(ob, me, geom_id, norind);
// XXX slow
- if (ob->totcol && this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) {
+ if (ob->totcol) {
for (int a = 0; a < ob->totcol; a++) {
createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
}
}
else {
- bool all_uv_layers = !this->export_settings->active_uv_only;
- std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers);
- createPolylists(uv_images, has_uvs, has_color, ob, me, geom_id, norind);
+ createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
}
closeMesh();
@@ -310,44 +285,7 @@ std::string GeometryExporter::makeVertexColorSourceId(std::string& geom_id, char
return result;
}
-static void prepareToAppendValues(bool is_triangulated, COLLADASW::PrimitivesBase *facelist, std::vector<unsigned long> &vcount_list)
-{
- // performs the actual writing
- if (is_triangulated) {
- ((COLLADASW::Triangles *)facelist)->prepareToAppendValues();
- }
- else {
- // sets <vcount>
- facelist->setVCountList(vcount_list);
- ((COLLADASW::Polylist *)facelist)-> prepareToAppendValues();
- }
-}
-
-static void finishList(bool is_triangulated, COLLADASW::PrimitivesBase *facelist)
-{
- if (is_triangulated) {
- ((COLLADASW::Triangles *)facelist)->finish();
- }
- else {
- ((COLLADASW::Polylist *)facelist)->finish();
- }
-}
-
-COLLADASW::PrimitivesBase *getFacelist(bool is_triangulated, COLLADASW::StreamWriter *mSW)
-{
- COLLADASW::PrimitivesBase *facelist;
-
- if (is_triangulated)
- {
- facelist = new COLLADASW::Triangles(mSW);
- }
- else {
- facelist = new COLLADASW::Polylist(mSW);
- }
- return facelist;
-}
-
-// Export meshes with Materials
+// powerful because it handles both cases when there is material and when there's not
void GeometryExporter::createPolylist(short material_index,
bool has_uvs,
bool has_color,
@@ -365,7 +303,7 @@ void GeometryExporter::createPolylist(short material_index,
int i;
int faces_in_polylist = 0;
std::vector<unsigned long> vcount_list;
- bool is_triangulated = true;
+
// count faces with this material
for (i = 0; i < totpolys; i++) {
MPoly *p = &mpolys[i];
@@ -373,9 +311,6 @@ void GeometryExporter::createPolylist(short material_index,
if (p->mat_nr == material_index) {
faces_in_polylist++;
vcount_list.push_back(p->totloop);
- if (p->totloop != 3) {
- is_triangulated = false;
- }
}
}
@@ -386,21 +321,20 @@ void GeometryExporter::createPolylist(short material_index,
}
Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
- COLLADASW::PrimitivesBase *facelist = getFacelist(is_triangulated, mSW);
-
+ COLLADASW::Polylist polylist(mSW);
// sets count attribute in <polylist>
- facelist->setCount(faces_in_polylist);
+ polylist.setCount(faces_in_polylist);
// sets material name
if (ma) {
std::string material_id = get_material_id(ma);
std::ostringstream ostr;
ostr << translate_id(material_id);
- facelist->setMaterial(ostr.str());
+ polylist.setMaterial(ostr.str());
}
- COLLADASW::InputList &til = facelist->getInputList();
+ COLLADASW::InputList &til = polylist.getInputList();
// creates <input> in <polylist> for vertices
COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
@@ -412,25 +346,17 @@ void GeometryExporter::createPolylist(short material_index,
til.push_back(input2);
// if mesh has uv coords writes <input> for TEXCOORD
- int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
- int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
+ int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
+ int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
for (i = 0; i < num_layers; i++) {
if (!this->export_settings->active_uv_only || i == active_uv_index) {
- std::string uv_name(bc_get_uvlayer_name(me, i));
- std::string effective_id = geom_id; // (uv_name == "") ? geom_id : uv_name;
- std::string layer_id = makeTexcoordSourceId(
- effective_id,
- i, this->export_settings->active_uv_only);
-
- /* Note: the third parameter denotes the offset of TEXCOORD in polylist elements
- For now this is always 2 (This may change sometime/maybe)
- */
+ // char *name = CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, i);
COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
- makeUrl(layer_id),
- 2, // this is only until we have optimized UV sets
- (this->export_settings->active_uv_only) ? 0 : i // only_active_uv exported -> we have only one set
- );
+ makeUrl(makeTexcoordSourceId(geom_id, i, this->export_settings->active_uv_only)),
+ 2, // this is only until we have optimized UV sets
+ (this->export_settings->active_uv_only) ? 0 : i // only_active_uv exported -> we have only one set
+ );
til.push_back(input3);
}
}
@@ -451,9 +377,11 @@ void GeometryExporter::createPolylist(short material_index,
}
}
+ // sets <vcount>
+ polylist.setVCountList(vcount_list);
// performs the actual writing
- prepareToAppendValues(is_triangulated, facelist, vcount_list);
+ polylist.prepareToAppendValues();
// <p>
int texindex = 0;
@@ -466,202 +394,20 @@ void GeometryExporter::createPolylist(short material_index,
BCPolygonNormalsIndices normal_indices = norind[i];
for (int j = 0; j < loop_count; j++) {
- facelist->appendValues(l[j].v);
- facelist->appendValues(normal_indices[j]);
+ polylist.appendValues(l[j].v);
+ polylist.appendValues(normal_indices[j]);
if (has_uvs)
- facelist->appendValues(texindex + j);
+ polylist.appendValues(texindex + j);
if (has_color)
- facelist->appendValues(texindex + j);
+ polylist.appendValues(texindex + j);
}
}
texindex += loop_count;
}
- finishList(is_triangulated, facelist);
- delete facelist;
-}
-
-void GeometryExporter::createPolylists(std::set<Image *> uv_images,
- bool has_uvs,
- bool has_color,
- Object *ob,
- Mesh *me,
- std::string& geom_id,
- std::vector<BCPolygonNormalsIndices>& norind)
-{
- std::set<Image *>::iterator uv_images_iter;
- for (uv_images_iter = uv_images.begin();
- uv_images_iter != uv_images.end();
- uv_images_iter++)
- {
-
- Image *ima = *uv_images_iter;
- std::string imageid(id_name(ima));
- createPolylist(imageid, has_uvs,
- has_color,
- ob,
- me,
- geom_id,
- norind);
- }
-
- /* We msut add an additional collector for the case when
- * some parts of the object are not textured at all.
- * The next call creates a polylist for all untextured polygons
- */
-
- createPolylist("", has_uvs,
- has_color,
- ob,
- me,
- geom_id,
- norind);
-
-}
-
-/* ===========================================================================
- * Export Meshes with UV Textures (export as materials, see also in
- * effectExporter and MaterialExporter)
- *
- * If imageid is the empty string, then collect only untextured polygons
- * =========================================================================== */
-void GeometryExporter::createPolylist(std::string imageid,
- bool has_uvs,
- bool has_color,
- Object *ob,
- Mesh *me,
- std::string& geom_id,
- std::vector<BCPolygonNormalsIndices>& norind)
-{
-
- MPoly *mpolys = me->mpoly;
- MLoop *mloops = me->mloop;
- MTexPoly *mtpolys = me->mtpoly;
-
- int totpolys = me->totpoly;
-
- // <vcount>
- int i;
- int faces_in_polylist = 0;
- std::vector<unsigned long> vcount_list;
- bool is_triangulated = true;
- // count faces with this material
- for (i = 0; i < totpolys; i++) {
- MTexPoly *tp = &mtpolys[i];
- MPoly *p = &mpolys[i];
-
- std::string tpageid = (mtpolys && tp->tpage) ? id_name(tp->tpage) : "";
- if (tpageid == imageid) {
- faces_in_polylist++;
- vcount_list.push_back(p->totloop);
- if (p->totloop != 3) {
- is_triangulated = false;
- }
- }
- }
-
- // no faces using this imageid
- if (faces_in_polylist == 0) {
- if (imageid != "")
- fprintf(stderr, "%s: Image %s is not used.\n", id_name(ob).c_str(), imageid.c_str());
- return;
- }
-
- COLLADASW::PrimitivesBase *facelist = getFacelist(is_triangulated, mSW);
-
- // sets count attribute in <polylist>
- facelist->setCount(faces_in_polylist);
-
- if (imageid != "") {
- // sets material name
- std::string material_id = get_material_id_from_id(imageid);
- std::ostringstream ostr;
- ostr << translate_id(material_id);
- facelist->setMaterial(ostr.str());
- }
- COLLADASW::InputList &til = facelist->getInputList();
-
- // creates <input> in <polylist> for vertices
- COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
-
- // creates <input> in <polylist> for normals
- COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
-
- til.push_back(input1);
- til.push_back(input2);
-
- // if mesh has uv coords writes <input> for TEXCOORD
- int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
- int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1;
- for (i = 0; i < num_layers; i++) {
- if (!this->export_settings->active_uv_only || i == active_uv_index) {
-
- std::string uv_name(bc_get_uvlayer_name(me, i));
- std::string effective_id = geom_id; // (uv_name == "") ? geom_id : uv_name;
- std::string layer_id = makeTexcoordSourceId(
- effective_id,
- i, this->export_settings->active_uv_only);
-
- /* Note: the third parameter denotes the offset of TEXCOORD in polylist elements
- For now this is always 2 (This may change sometime/maybe)
- */
- COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
- makeUrl(layer_id),
- 2, // this is only until we have optimized UV sets
- (this->export_settings->active_uv_only) ? 0 : i // only_active_uv exported -> we have only one set
- );
- til.push_back(input3);
- }
- }
-
- int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
- if (totlayer_mcol > 0) {
- int map_index = 0;
-
- for (int a = 0; a < totlayer_mcol; a++) {
- char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPCOL, a);
- COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR,
- makeUrl(makeVertexColorSourceId(geom_id, layer_name)),
- (has_uvs) ? 3 : 2, // all color layers have same index order
- map_index // set number equals color map index
- );
- til.push_back(input4);
- map_index++;
- }
- }
-
- // performs the actual writing
- prepareToAppendValues(is_triangulated, facelist, vcount_list);
-
- // <p>
- int texindex = 0;
- for (i = 0; i < totpolys; i++) {
- MTexPoly *tp = &mtpolys[i];
- MPoly *p = &mpolys[i];
- int loop_count = p->totloop;
- std::string tpageid = (mtpolys && tp->tpage) ? id_name(tp->tpage) : "";
- if (tpageid == imageid) {
- MLoop *l = &mloops[p->loopstart];
- BCPolygonNormalsIndices normal_indices = norind[i];
-
- for (int j = 0; j < loop_count; j++) {
- facelist->appendValues(l[j].v);
- facelist->appendValues(normal_indices[j]);
- if (has_uvs)
- facelist->appendValues(texindex + j);
-
- if (has_color)
- facelist->appendValues(texindex + j);
- }
- }
-
- texindex += loop_count;
- }
-
- finishList(is_triangulated, facelist);
- delete facelist;
+ polylist.finish();
}
// creates <source> for positions
@@ -782,13 +528,7 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
COLLADASW::FloatSourceF source(mSW);
- std::string active_uv_name(bc_get_active_uvlayer_name(me));
- std::string effective_id = geom_id; // (active_uv_name == "") ? geom_id : active_uv_name;
- std::string layer_id = makeTexcoordSourceId(
- effective_id,
- a,
- this->export_settings->active_uv_only );
-
+ std::string layer_id = makeTexcoordSourceId(geom_id, a, this->export_settings->active_uv_only);
source.setId(layer_id);
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h
index fd9db7b1fd2..bd629946d01 100644
--- a/source/blender/collada/GeometryExporter.h
+++ b/source/blender/collada/GeometryExporter.h
@@ -43,9 +43,11 @@
#include "ExportSettings.h"
#include "collada_utils.h"
-
+#include "BlenderContext.h"
#include "BKE_key.h"
+struct Depsgraph;
+
extern Object *bc_get_highest_selected_ancestor_or_self(Object *ob);
class Normal
@@ -72,13 +74,16 @@ class GeometryExporter : COLLADASW::LibraryGeometries
Normal n;
- Main *m_bmain;
- Scene *mScene;
-
public:
- GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
- void exportGeom(Main *bmain, Scene *sce);
+ // TODO: optimize UV sets by making indexed list with duplicates removed
+ GeometryExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) :
+ COLLADASW::LibraryGeometries(sw),
+ blender_context(blender_context),
+ export_settings(export_settings)
+ {}
+
+ void exportGeom();
void operator()(Object *ob);
@@ -86,32 +91,14 @@ public:
Mesh *me,
std::string& geom_id);
- // Create polylists for meshes with Materials
+ // powerful because it handles both cases when there is material and when there's not
void createPolylist(short material_index,
- bool has_uvs,
- bool has_color,
- Object *ob,
- Mesh *me,
- std::string& geom_id,
- std::vector<BCPolygonNormalsIndices>& norind);
-
- // Create polylists for meshes with UV Textures
- void createPolylists(std::set<Image *> uv_images,
- bool has_uvs,
- bool has_color,
- Object *ob,
- Mesh *me,
- std::string& geom_id,
- std::vector<BCPolygonNormalsIndices>& norind);
-
- // Create polylists for meshes with UV Textures
- void createPolylist(std::string imageid,
- bool has_uvs,
- bool has_color,
- Object *ob,
- Mesh *me,
- std::string& geom_id,
- std::vector<BCPolygonNormalsIndices>& norind);
+ bool has_uvs,
+ bool has_color,
+ Object *ob,
+ Mesh *me,
+ std::string& geom_id,
+ std::vector<BCPolygonNormalsIndices>& norind);
// creates <source> for positions
void createVertsSource(std::string geom_id, Mesh *me);
@@ -140,7 +127,7 @@ public:
private:
std::set<std::string> exportedGeometry;
-
+ BlenderContext &blender_context;
const ExportSettings *export_settings;
Mesh *get_mesh(Scene *sce, Object *ob, int apply_modifiers);
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index 87f1197e3af..d7ab16f81e7 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -39,9 +39,11 @@ extern "C" {
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+
#include "IMB_imbuf_types.h"
}
@@ -49,217 +51,121 @@ extern "C" {
#include "MaterialExporter.h"
-ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryImages(sw), export_settings(export_settings)
+ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map) :
+ COLLADASW::LibraryImages(sw),
+ export_settings(export_settings),
+ key_image_map(key_image_map)
{
}
void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
{
- std::string id(id_name(image));
- std::string translated_id(translate_id(id));
- bool not_yet_exported = find(mImages.begin(), mImages.end(), translated_id) == mImages.end();
+ std::string name(id_name(image));
+ std::string translated_name(translate_id(name));
- if (not_yet_exported) {
-
- ImBuf *imbuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- if (!imbuf) {
- fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name);
- return;
- }
+ ImBuf *imbuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (!imbuf) {
+ fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name);
+ return;
+ }
- bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0;
+ bool is_dirty = (imbuf->userflags & IB_BITMAPDIRTY) != 0;
- ImageFormatData imageFormat;
- BKE_imbuf_to_image_format(&imageFormat, imbuf);
+ ImageFormatData imageFormat;
+ BKE_imbuf_to_image_format(&imageFormat, imbuf);
- short image_source = image->source;
- bool is_generated = image_source == IMA_SRC_GENERATED;
- bool is_packed = BKE_image_has_packedfile(image);
+ short image_source = image->source;
+ bool is_generated = image_source == IMA_SRC_GENERATED;
+ bool is_packed = BKE_image_has_packedfile(image);
- char export_path[FILE_MAX];
- char source_path[FILE_MAX];
- char export_dir[FILE_MAX];
- char export_file[FILE_MAX];
+ char export_path[FILE_MAX];
+ char source_path[FILE_MAX];
+ char export_dir[FILE_MAX];
+ char export_file[FILE_MAX];
- // Destination folder for exported assets
- BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir));
+ // Destination folder for exported assets
+ BLI_split_dir_part(this->export_settings->filepath, export_dir, sizeof(export_dir));
- if (is_generated || is_dirty || use_copies || is_packed) {
+ if (is_generated || is_dirty || use_copies || is_packed) {
- // make absolute destination path
+ // make absolute destination path
- BLI_strncpy(export_file, id.c_str(), sizeof(export_file));
- BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
+ BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
+ BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
- BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
+ BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
- // make dest directory if it doesn't exist
- BLI_make_existing_file(export_path);
- }
+ // make dest directory if it doesn't exist
+ BLI_make_existing_file(export_path);
+ }
- if (is_generated || is_dirty || is_packed) {
+ if (is_generated || is_dirty || is_packed) {
- // This image in its current state only exists in Blender memory.
- // So we have to export it. The export will keep the image state intact,
- // so the exported file will not be associated with the image.
+ // This image in its current state only exists in Blender memory.
+ // So we have to export it. The export will keep the image state intact,
+ // so the exported file will not be associated with the image.
- if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
- fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path);
- return;
- }
- BLI_strncpy(export_path, export_file, sizeof(export_path));
+ if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
+ fprintf(stderr, "Collada export: Cannot export image to:\n%s\n", export_path);
+ return;
}
- else {
+ BLI_strncpy(export_path, export_file, sizeof(export_path));
+ }
+ else {
- // make absolute source path
- BLI_strncpy(source_path, image->name, sizeof(source_path));
- BLI_path_abs(source_path, BKE_main_blendfile_path_from_global());
- BLI_cleanup_path(NULL, source_path);
+ // make absolute source path
+ BLI_strncpy(source_path, image->name, sizeof(source_path));
+ BLI_path_abs(source_path, BKE_main_blendfile_path_from_global());
+ BLI_cleanup_path(NULL, source_path);
- if (use_copies) {
+ if (use_copies) {
- // This image is already located on the file system.
- // But we want to create copies here.
- // To move images into the same export directory.
- // Note: If an image is already located in the export folder,
- // then skip the copy (as it would result in a file copy error).
+ // This image is already located on the file system.
+ // But we want to create copies here.
+ // To move images into the same export directory.
+ // Note: If an image is already located in the export folder,
+ // then skip the copy (as it would result in a file copy error).
- if (BLI_path_cmp(source_path, export_path) != 0) {
- if (BLI_copy(source_path, export_path) != 0) {
- fprintf(stderr, "Collada export: Cannot copy image:\n source:%s\ndest :%s\n", source_path, export_path);
- return;
- }
+ if (BLI_path_cmp(source_path, export_path) != 0) {
+ if (BLI_copy(source_path, export_path) != 0) {
+ fprintf(stderr, "Collada export: Cannot copy image:\n source:%s\ndest :%s\n", source_path, export_path);
+ return;
}
-
- BLI_strncpy(export_path, export_file, sizeof(export_path));
-
}
- else {
- // Do not make any copies, but use the source path directly as reference
- // to the original image
+ BLI_strncpy(export_path, export_file, sizeof(export_path));
- BLI_strncpy(export_path, source_path, sizeof(export_path));
- }
}
+ else {
- /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
- COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_id, translated_id);
- img.add(mSW);
- fprintf(stdout, "Collada export: Added image: %s\n", export_file);
- mImages.push_back(translated_id);
+ // Do not make any copies, but use the source path directly as reference
+ // to the original image
- BKE_image_release_ibuf(image, imbuf, NULL);
- }
-}
-
-void ImagesExporter::export_UV_Images()
-{
- std::set<Image *> uv_textures;
- LinkNode *node;
- bool use_texture_copies = this->export_settings->use_texture_copies;
- bool active_uv_only = this->export_settings->active_uv_only;
-
- for (node = this->export_settings->export_set; node; node = node->next) {
- Object *ob = (Object *)node->link;
- if (ob->type == OB_MESH) {
- Mesh *me = (Mesh *) ob->data;
- BKE_mesh_tessface_ensure(me);
- int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
- for (int i = 0; i < me->pdata.totlayer; i++) {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- if (!active_uv_only || active_uv_layer == i)
- {
- MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
- for (int j = 0; j < me->totpoly; j++, txface++) {
-
- Image *ima = txface->tpage;
- if (ima == NULL)
- continue;
-
- bool not_in_list = uv_textures.find(ima) == uv_textures.end();
- if (not_in_list) {
- uv_textures.insert(ima);
- export_UV_Image(ima, use_texture_copies);
- }
- }
- }
- }
- }
+ BLI_strncpy(export_path, source_path, sizeof(export_path));
}
}
-}
-
-/* ============================================================
- * Check if there are any images to be exported
- * Returns true as soon as an object is detected that
- * either has an UV Texture assigned, or has a material
- * assigned that uses an Image Texture.
- * ============================================================
- */
-bool ImagesExporter::hasImages(Scene *sce)
-{
- LinkNode *node;
- for (node = this->export_settings->export_set; node; node = node->next) {
- Object *ob = (Object *)node->link;
-
- for (int a = 0; a < ob->totcol; a++) {
- Material *ma = give_current_material(ob, a + 1);
-
- // no material, but check all of the slots
- if (!ma) continue;
- int b;
- for (b = 0; b < MAX_MTEX; b++) {
- MTex *mtex = ma->mtex[b];
- if (mtex && mtex->tex && mtex->tex->ima) return true;
- }
+ COLLADASW::Image img(COLLADABU::URI(COLLADABU::URI::nativePathToUri(export_path)), translated_name, translated_name); /* set name also to mNameNC. This helps other viewers import files exported from Blender better */
+ img.add(mSW);
+ fprintf(stdout, "Collada export: Added image: %s\n", export_file);
- }
- if (ob->type == OB_MESH) {
- Mesh *me = (Mesh *) ob->data;
- BKE_mesh_tessface_ensure(me);
- bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
- if (has_uvs) {
- int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
- for (int a = 0; a < num_layers; a++) {
- MTFace *tface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
- Image *img = tface->tpage;
- if (img) return true;
- }
- }
- }
-
- }
- return false;
+ BKE_image_release_ibuf(image, imbuf, NULL);
}
void ImagesExporter::exportImages(Scene *sce)
{
+ bool use_texture_copies = this->export_settings->use_texture_copies;
openLibrary();
- MaterialFunctor mf;
- if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT) {
- mf.forEachMaterialInExportSet<ImagesExporter>(sce, *this, this->export_settings->export_set);
- }
- else {
- export_UV_Images();
- }
-
- closeLibrary();
-}
+ KeyImageMap::iterator iter;
+ for (iter = key_image_map.begin(); iter != key_image_map.end(); iter++) {
+ Image *image = iter->second;
+ std::string uid(id_name(image));
+ std::string key = translate_id(uid);
-
-void ImagesExporter::operator()(Material *ma, Object *ob)
-{
- int a;
- bool use_texture_copies = this->export_settings->use_texture_copies;
- for (a = 0; a < MAX_MTEX; a++) {
- MTex *mtex = ma->mtex[a];
- if (mtex && mtex->tex && mtex->tex->ima) {
- Image *image = mtex->tex->ima;
- export_UV_Image(image, use_texture_copies);
- }
+ export_UV_Image(image, use_texture_copies);
}
+
+ closeLibrary();
}
diff --git a/source/blender/collada/ImageExporter.h b/source/blender/collada/ImageExporter.h
index 524260891ae..7ce312a52b1 100644
--- a/source/blender/collada/ImageExporter.h
+++ b/source/blender/collada/ImageExporter.h
@@ -40,21 +40,19 @@
#include "DNA_scene_types.h"
#include "ExportSettings.h"
+#include "collada_utils.h"
class ImagesExporter: COLLADASW::LibraryImages
{
public:
- ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
-
+ ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings, KeyImageMap &key_image_map);
void exportImages(Scene *sce);
- void operator()(Material *ma, Object *ob);
-private:
- std::vector<std::string> mImages; // contains list of written images, to avoid duplicates
- void export_UV_Images();
- void export_UV_Image(Image *image, bool use_texture_copies);
- bool hasImages(Scene *sce);
+private:
const ExportSettings *export_settings;
+ KeyImageMap &key_image_map;
+ void export_UV_Image(Image *image, bool use_texture_copies);
+
};
#endif
diff --git a/source/blender/collada/InstanceWriter.cpp b/source/blender/collada/InstanceWriter.cpp
index 4d846693e50..0c0b1a15653 100644
--- a/source/blender/collada/InstanceWriter.cpp
+++ b/source/blender/collada/InstanceWriter.cpp
@@ -41,35 +41,30 @@ extern "C" {
#include "collada_internal.h"
#include "collada_utils.h"
-void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only, BC_export_texture_type export_texture_type)
+void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only)
{
- bool all_uv_layers = !active_uv_only;
- COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
+ for (int a = 0; a < ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a + 1);
- if (export_texture_type == BC_TEXTURE_TYPE_UV)
- {
- std::set<Image *> uv_images = bc_getUVImages(ob, all_uv_layers);
- std::set<Image *>::iterator uv_images_iter;
- for (uv_images_iter = uv_images.begin();
- uv_images_iter != uv_images.end();
- uv_images_iter++)
- {
- Image *ima = *uv_images_iter;
- std::string matid(id_name(ima));
- matid = get_material_id_from_id(matid);
+ COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
+
+ if (ma) {
+ std::string matid(get_material_id(ma));
+ matid = translate_id(matid);
std::ostringstream ostr;
ostr << matid;
COLLADASW::InstanceMaterial im(ostr.str(), COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
// create <bind_vertex_input> for each uv map
Mesh *me = (Mesh *)ob->data;
- int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+
+ int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
int map_index = 0;
- int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1;
- for (int b = 0; b < totlayer; b++) {
+ int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
+ for (int b = 0; b < num_layers; b++) {
if (!active_uv_only || b == active_uv_index) {
- char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
+ char *name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, b);
im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++));
}
}
@@ -77,32 +72,4 @@ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_materia
iml.push_back(im);
}
}
-
- else {
- for (int a = 0; a < ob->totcol; a++) {
- Material *ma = give_current_material(ob, a + 1);
- if (ma) {
- std::string matid(get_material_id(ma));
- matid = translate_id(matid);
- std::ostringstream ostr;
- ostr << matid;
- COLLADASW::InstanceMaterial im(ostr.str(), COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
-
- // create <bind_vertex_input> for each uv map
- Mesh *me = (Mesh *)ob->data;
- int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
-
- int map_index = 0;
- int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) - 1;
- for (int b = 0; b < totlayer; b++) {
- if (!active_uv_only || b == active_uv_index) {
- char *name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, b);
- im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++));
- }
- }
-
- iml.push_back(im);
- }
- }
- }
}
diff --git a/source/blender/collada/InstanceWriter.h b/source/blender/collada/InstanceWriter.h
index a46027325a2..49ddf091b1c 100644
--- a/source/blender/collada/InstanceWriter.h
+++ b/source/blender/collada/InstanceWriter.h
@@ -31,12 +31,11 @@
#include "COLLADASWBindMaterial.h"
#include "DNA_object_types.h"
-#include "collada.h"
class InstanceWriter
{
protected:
- void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only, BC_export_texture_type export_texture_type);
+ void add_material_bindings(COLLADASW::BindMaterial& bind_material, Object *ob, bool active_uv_only);
};
#endif
diff --git a/source/blender/collada/LightExporter.cpp b/source/blender/collada/LightExporter.cpp
index 02c5438ec47..b1f805bfb87 100644
--- a/source/blender/collada/LightExporter.cpp
+++ b/source/blender/collada/LightExporter.cpp
@@ -89,14 +89,7 @@ void LightsExporter::operator()(Object *ob)
exportBlenderProfile(cla, la);
addLight(cla);
}
- // hemi
- else if (la->type == LA_HEMI) {
- COLLADASW::AmbientLight cla(mSW, la_id, la_name);
- cla.setColor(col, false, "color");
- cla.setConstantAttenuation(constatt);
- exportBlenderProfile(cla, la);
- addLight(cla);
- }
+
// spot
else if (la->type == LA_SPOT) {
COLLADASW::SpotLight cla(mSW, la_id, la_name);
@@ -149,7 +142,6 @@ bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la)
cla.addExtraTechniqueParameter("blender", "dist", la->dist, "blender_dist");
cla.addExtraTechniqueParameter("blender", "spotsize", RAD2DEGF(la->spotsize));
cla.addExtraTechniqueParameter("blender", "spotblend", la->spotblend);
- cla.addExtraTechniqueParameter("blender", "halo_intensity", la->haint, "blnder_halo_intensity");
cla.addExtraTechniqueParameter("blender", "att1", la->att1);
cla.addExtraTechniqueParameter("blender", "att2", la->att2);
// \todo figure out how we can have falloff curve supported here
@@ -158,38 +150,13 @@ bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la)
cla.addExtraTechniqueParameter("blender", "clipend", la->clipend);
cla.addExtraTechniqueParameter("blender", "bias", la->bias);
cla.addExtraTechniqueParameter("blender", "soft", la->soft);
- cla.addExtraTechniqueParameter("blender", "compressthresh", la->compressthresh);
cla.addExtraTechniqueParameter("blender", "bufsize", la->bufsize);
cla.addExtraTechniqueParameter("blender", "samp", la->samp);
cla.addExtraTechniqueParameter("blender", "buffers", la->buffers);
- cla.addExtraTechniqueParameter("blender", "filtertype", la->filtertype);
- cla.addExtraTechniqueParameter("blender", "bufflag", la->bufflag);
- cla.addExtraTechniqueParameter("blender", "buftype", la->buftype);
- cla.addExtraTechniqueParameter("blender", "ray_samp", la->ray_samp);
- cla.addExtraTechniqueParameter("blender", "ray_sampy", la->ray_sampy);
- cla.addExtraTechniqueParameter("blender", "ray_sampz", la->ray_sampz);
- cla.addExtraTechniqueParameter("blender", "ray_samp_type", la->ray_samp_type);
cla.addExtraTechniqueParameter("blender", "area_shape", la->area_shape);
cla.addExtraTechniqueParameter("blender", "area_size", la->area_size);
cla.addExtraTechniqueParameter("blender", "area_sizey", la->area_sizey);
cla.addExtraTechniqueParameter("blender", "area_sizez", la->area_sizez);
- cla.addExtraTechniqueParameter("blender", "adapt_thresh", la->adapt_thresh);
- cla.addExtraTechniqueParameter("blender", "ray_samp_method", la->ray_samp_method);
- cla.addExtraTechniqueParameter("blender", "shadhalostep", la->shadhalostep);
- cla.addExtraTechniqueParameter("blender", "sun_effect_type", la->shadhalostep);
- cla.addExtraTechniqueParameter("blender", "skyblendtype", la->skyblendtype);
- cla.addExtraTechniqueParameter("blender", "horizon_brightness", la->horizon_brightness);
- cla.addExtraTechniqueParameter("blender", "spread", la->spread);
- cla.addExtraTechniqueParameter("blender", "sun_brightness", la->sun_brightness);
- cla.addExtraTechniqueParameter("blender", "sun_size", la->sun_size);
- cla.addExtraTechniqueParameter("blender", "backscattered_light", la->backscattered_light);
- cla.addExtraTechniqueParameter("blender", "sun_intensity", la->sun_intensity);
- cla.addExtraTechniqueParameter("blender", "atm_turbidity", la->atm_turbidity);
- cla.addExtraTechniqueParameter("blender", "atm_extinction_factor", la->atm_extinction_factor);
- cla.addExtraTechniqueParameter("blender", "atm_distance_factor", la->atm_distance_factor);
- cla.addExtraTechniqueParameter("blender", "skyblendfac", la->skyblendfac);
- cla.addExtraTechniqueParameter("blender", "sky_exposure", la->sky_exposure);
- cla.addExtraTechniqueParameter("blender", "sky_colorspace", la->sky_colorspace);
return true;
}
diff --git a/source/blender/collada/MaterialExporter.cpp b/source/blender/collada/MaterialExporter.cpp
index 0c0395f2a21..2fa71817ac8 100644
--- a/source/blender/collada/MaterialExporter.cpp
+++ b/source/blender/collada/MaterialExporter.cpp
@@ -38,40 +38,14 @@ MaterialsExporter::MaterialsExporter(COLLADASW::StreamWriter *sw, const ExportSe
void MaterialsExporter::exportMaterials(Scene *sce)
{
- if (this->export_settings->export_texture_type == BC_TEXTURE_TYPE_MAT)
- {
- if (hasMaterials(sce)) {
- openLibrary();
+ if (hasMaterials(sce)) {
+ openLibrary();
- MaterialFunctor mf;
- mf.forEachMaterialInExportSet<MaterialsExporter>(sce, *this, this->export_settings->export_set);
+ MaterialFunctor mf;
+ mf.forEachMaterialInExportSet<MaterialsExporter>(sce, *this, this->export_settings->export_set);
- closeLibrary();
- }
- }
-
- else {
- std::set<Image *> uv_images = bc_getUVImages(sce, !this->export_settings->active_uv_only);
- if (uv_images.size() > 0) {
- openLibrary();
- std::set<Image *>::iterator uv_images_iter;
- for (uv_images_iter = uv_images.begin();
- uv_images_iter != uv_images.end();
- uv_images_iter++)
- {
-
- Image *ima = *uv_images_iter;
- std::string matid(id_name(ima));
-
- openMaterial(get_material_id_from_id(matid), translate_id(matid));
- std::string efid = translate_id(matid) + "-effect";
- addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid));
- closeMaterial();
- }
- closeLibrary();
- }
+ closeLibrary();
}
-
}
bool MaterialsExporter::hasMaterials(Scene *sce)
@@ -94,12 +68,12 @@ bool MaterialsExporter::hasMaterials(Scene *sce)
void MaterialsExporter::operator()(Material *ma, Object *ob)
{
- std::string name(id_name(ma));
-
- openMaterial(get_material_id(ma), translate_id(name));
+ std::string mat_name = encode_xml(id_name(ma));
+ std::string mat_id = get_material_id(ma);
+ std::string eff_id = get_effect_id(ma);
- std::string efid = translate_id(name) + "-effect";
- addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, efid));
+ openMaterial(mat_id, mat_name);
+ addInstanceEffect(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, eff_id));
closeMaterial();
}
diff --git a/source/blender/collada/MaterialExporter.h b/source/blender/collada/MaterialExporter.h
index e830a433432..171c05fcea7 100644
--- a/source/blender/collada/MaterialExporter.h
+++ b/source/blender/collada/MaterialExporter.h
@@ -44,6 +44,7 @@ extern "C" {
#include "GeometryExporter.h"
#include "collada_internal.h"
#include "ExportSettings.h"
+#include "Materials.h"
class MaterialsExporter: COLLADASW::LibraryMaterials
{
diff --git a/source/blender/collada/Materials.cpp b/source/blender/collada/Materials.cpp
new file mode 100644
index 00000000000..3173c2592c4
--- /dev/null
+++ b/source/blender/collada/Materials.cpp
@@ -0,0 +1,329 @@
+/*
+* ***** 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): Gaia Clary.
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include "Materials.h"
+
+MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map) :
+ mContext(C),
+ material(ma),
+ effect(nullptr),
+ key_image_map(&key_image_map)
+{
+ ntree = prepare_material_nodetree();
+ setShaderType();
+}
+
+MaterialNode::MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map) :
+ mContext(C),
+ material(ma),
+ effect(ef),
+ uid_image_map(&uid_image_map)
+{
+ ntree = prepare_material_nodetree();
+ setShaderType();
+
+ std::map<std::string, bNode *> nmap;
+#if 0
+ nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
+ nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
+ nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
+ nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
+ nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
+ nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
+ nmap["out"]->flag &= ~NODE_SELECT;
+
+ add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
+ add_link(ntree, nmap["main"], 0, nmap["add"], 1);
+ add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
+ add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
+
+ add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
+ // experimental, probably not used.
+ make_group(C, ntree, nmap);
+#else
+ shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, "");
+ output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, "");
+ add_link(shader_node, 0, output_node, 0);
+#endif
+}
+
+void MaterialNode::setShaderType()
+{
+#if 0
+ COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
+ // Currently we only support PBR based shaders
+ // TODO: simulate the effects with PBR
+
+ // blinn
+ if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
+ ma->spec_shader = MA_SPEC_BLINN;
+ ma->spec = ef->getShininess().getFloatValue();
+ }
+ // phong
+ else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) {
+ ma->spec_shader = MA_SPEC_PHONG;
+ ma->har = ef->getShininess().getFloatValue();
+ }
+ // lambert
+ else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) {
+ ma->diff_shader = MA_DIFF_LAMBERT;
+ }
+ // default - lambert
+ else {
+ ma->diff_shader = MA_DIFF_LAMBERT;
+ fprintf(stderr, "Current shader type is not supported, default to lambert.\n");
+ }
+#endif
+}
+
+bNodeTree *MaterialNode::prepare_material_nodetree()
+{
+ if (material->nodetree == NULL) {
+ material->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree");
+ material->use_nodes = true;
+ }
+ return material->nodetree;
+}
+
+bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
+{
+ bNode *node = nodeAddStaticNode(mContext, ntree, node_type);
+ if (node) {
+ if (label.length() > 0) {
+ strcpy(node->label, label.c_str());
+ }
+ node->locx = locx;
+ node->locy = locy;
+ node->flag |= NODE_SELECT;
+ }
+ node_map[label] = node;
+ return node;
+}
+
+void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, int to_index)
+{
+ bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
+ bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
+
+ nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
+}
+
+void MaterialNode::set_reflectivity(float val)
+{
+ material->metallic = val;
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_METALLIC);
+ *(float *)socket->default_value = val;
+}
+
+void MaterialNode::set_ior(float val)
+{
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_IOR);
+ *(float *)socket->default_value = val;
+}
+
+void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot, std::string label)
+{
+ int locy = -300 * (node_map.size()-2);
+ if (cot.isColor()) {
+ COLLADAFW::Color col = cot.getColor();
+ material->r = col.getRed();
+ material->g = col.getGreen();
+ material->b = col.getBlue();
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_DIFFUSE);
+ float *fcol = (float *)socket->default_value;
+ fcol[0] = col.getRed();
+ fcol[1] = col.getGreen();
+ fcol[2] = col.getBlue();
+ }
+ else if (cot.isTexture()) {
+ bNode *texture_node = add_texture_node(cot, -300, locy, label);
+ if (texture_node != NULL) {
+ add_link(texture_node, 0, shader_node, 0);
+ }
+ }
+}
+
+Image *MaterialNode::get_diffuse_image()
+{
+ bNode *shader = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
+ if (shader == nullptr) {
+ return nullptr;
+ }
+
+ bNodeSocket *in_socket = (bNodeSocket *)BLI_findlink(&shader->inputs, BC_PBR_DIFFUSE);
+ if (in_socket == nullptr) {
+ return nullptr;
+ }
+
+ bNodeLink *link = in_socket->link;
+ if (link == nullptr) {
+ return nullptr;
+ }
+
+ bNode *texture = link->fromnode;
+ if (texture == nullptr) {
+ return nullptr;
+ }
+
+ if (texture->type != SH_NODE_TEX_IMAGE) {
+ return nullptr;
+ }
+
+ Image *image = (Image *)texture->id;
+ return image;
+
+}
+
+static bNodeSocket *set_color(bNode *node, COLLADAFW::Color col)
+{
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
+ float *fcol = (float *)socket->default_value;
+ fcol[0] = col.getRed();
+ fcol[1] = col.getGreen();
+ fcol[2] = col.getBlue();
+
+ return socket;
+}
+
+void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot, std::string label)
+{
+ int locy = -300 * (node_map.size() - 2);
+ if (cot.isColor()) {
+ COLLADAFW::Color col = cot.getColor();
+ bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
+ set_color(node, col);
+ // TODO: Connect node
+ }
+ // texture
+ else if (cot.isTexture()) {
+ add_texture_node(cot, -300, locy, label);
+ // TODO: Connect node
+ }
+}
+void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot, std::string label)
+{
+ int locy = -300 * (node_map.size() - 2);
+ if (cot.isColor()) {
+ COLLADAFW::Color col = cot.getColor();
+ bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
+ set_color(node, col);
+ // TODO: Connect node
+ }
+ // texture
+ else if (cot.isTexture()) {
+ add_texture_node(cot, -300, locy, label);
+ // TODO: Connect node
+ }
+}
+
+void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot, std::string label)
+{
+ int locy = -300 * (node_map.size() - 2);
+ if (cot.isColor()) {
+ COLLADAFW::Color col = cot.getColor();
+ bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
+ set_color(node, col);
+ // TODO: Connect node
+ }
+ // texture
+ else if (cot.isTexture()) {
+ add_texture_node(cot, -300, locy, label);
+ // TODO: Connect node
+ }
+}
+
+void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot, std::string label)
+{
+ if (effect == nullptr) {
+ return;
+ }
+
+ int locy = -300 * (node_map.size() - 2);
+ if (cot.isColor()) {
+ COLLADAFW::Color col = effect->getTransparent().getColor();
+ float alpha = effect->getTransparency().getFloatValue();
+
+ if (col.isValid()) {
+ alpha *= col.getAlpha(); // Assuming A_ONE opaque mode
+ }
+ if (col.isValid() || alpha < 1.0) {
+ // not sure what to do here
+ }
+
+ bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
+ set_color(node, col);
+ // TODO: Connect node
+ }
+ // texture
+ else if (cot.isTexture()) {
+ add_texture_node(cot, -300, locy, label);
+ // TODO: Connect node
+ }
+}
+
+void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot, std::string label)
+{
+ int locy = -300 * (node_map.size() - 2);
+ if (cot.isColor()) {
+ COLLADAFW::Color col = cot.getColor();
+ material->specr = col.getRed();
+ material->specg = col.getGreen();
+ material->specb = col.getBlue();
+
+ bNode *node = add_node(SH_NODE_RGB, -300, locy, label);
+ set_color(node, col);
+ // TODO: Connect node
+ }
+ // texture
+ else if (cot.isTexture()) {
+ add_texture_node(cot, -300, locy, label);
+ // TODO: Connect node
+ }
+}
+
+bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label)
+{
+ if (effect == nullptr) {
+ return nullptr;
+ }
+
+ UidImageMap &image_map = *uid_image_map;
+
+ COLLADAFW::Texture ctex = cot.getTexture();
+
+ COLLADAFW::SamplerPointerArray& samp_array = effect->getSamplerPointerArray();
+ COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()];
+
+ const COLLADAFW::UniqueId& ima_uid = sampler->getSourceImage();
+
+ if (image_map.find(ima_uid) == image_map.end()) {
+ fprintf(stderr, "Couldn't find an image by UID.\n");
+ return NULL;
+ }
+
+ Image *ima = image_map[ima_uid];
+ bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label);
+ texture_node->id = &ima->id;
+ return texture_node;
+
+}
diff --git a/source/blender/collada/Materials.h b/source/blender/collada/Materials.h
new file mode 100644
index 00000000000..69f64a6280d
--- /dev/null
+++ b/source/blender/collada/Materials.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.
+ *
+ * Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Nathan Letwory.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __MATERIAL_H__
+#define __MATERIAL_H__
+
+#include <map>
+#include <string>
+
+extern "C" {
+#include "BKE_context.h"
+#include "BKE_node.h"
+#include "BLI_listbase.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+}
+
+#include "collada_utils.h"
+#include "COLLADAFWEffectCommon.h"
+
+typedef enum BC_pbr_inputs {
+ BC_PBR_DIFFUSE = 0,
+ BC_PBR_METALLIC = 4,
+ BC_PBR_IOR = 14
+} BC_pbr_inputs;
+
+typedef std::map<std::string, bNode *> NodeMap;
+
+class MaterialNode {
+
+private:
+ bContext *mContext;
+ Material *material;
+ COLLADAFW::EffectCommon *effect;
+ UidImageMap *uid_image_map = nullptr;
+ KeyImageMap *key_image_map = nullptr;
+
+ NodeMap node_map;
+ bNodeTree *ntree;
+
+ bNode *shader_node;
+ bNode *output_node;
+
+ bNodeTree *prepare_material_nodetree();
+ bNode *add_node(int node_type, int locx, int locy, std::string label);
+ void add_link(bNode *from_node, int from_index, bNode *to_node, int to_index);
+ bNode *add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label);
+ void setShaderType();
+
+public:
+ MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map);
+ MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map);
+ void set_diffuse(COLLADAFW::ColorOrTexture &cot, std::string label);
+ Image *get_diffuse_image();
+ void set_specular(COLLADAFW::ColorOrTexture &cot, std::string label);
+ void set_ambient(COLLADAFW::ColorOrTexture &cot, std::string label);
+ void set_reflective(COLLADAFW::ColorOrTexture &cot, std::string label);
+ void set_emission(COLLADAFW::ColorOrTexture &cot, std::string label);
+ void set_opacity(COLLADAFW::ColorOrTexture &cot, std::string label);
+ void set_reflectivity(float val);
+ void set_ior(float val);
+
+};
+
+#endif
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 1f24010b04e..4dd3f1cc219 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -43,7 +43,6 @@ extern "C" {
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_library.h"
- #include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
@@ -207,11 +206,12 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
}
-MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce) :
- unitconverter(unitconv),
- m_bmain(bmain),
- scene(sce),
- armature_importer(arm) {
+MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce, ViewLayer *view_layer):
+ unitconverter(unitconv),
+ m_bmain(bmain),
+ scene(sce),
+ view_layer(view_layer),
+ armature_importer(arm) {
}
bool MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
@@ -476,11 +476,9 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getUVCoords().getInputInfosArray()[i];
COLLADAFW::String &uvname = info->mName;
// Allocate space for UV_data
- CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname.c_str());
CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, uvname.c_str());
}
// activate the first uv map
- me->mtpoly = (MTexPoly *)CustomData_get_layer_n(&me->pdata, CD_MTEXPOLY, 0);
me->mloopuv = (MLoopUV *) CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0);
}
@@ -601,9 +599,8 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
- for (int i = 0; i < prim_arr.getCount(); i++) {
-
- COLLADAFW::MeshPrimitive *mp = prim_arr[i];
+ for (int index = 0; index < prim_arr.getCount(); index++) {
+ COLLADAFW::MeshPrimitive *mp = prim_arr[index];
int type = mp->getPrimitiveType();
if (type == COLLADAFW::MeshPrimitive::LINES) {
@@ -881,48 +878,6 @@ std::string *MeshImporter::get_geometry_name(const std::string &mesh_name)
return NULL;
}
-MTex *MeshImporter::assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture,
- Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map,
- MTex *color_texture)
-{
- const COLLADAFW::TextureMapId texture_index = ctexture.getTextureMapId();
- size_t setindex = ctexture.getSetIndex();
- std::string uvname = ctexture.getSemantic();
-
- if (setindex == -1) return NULL;
-
- const CustomData *data = &me->fdata;
- int layer_index = CustomData_get_layer_index(data, CD_MTFACE);
-
- if (layer_index == -1) return NULL;
-
- CustomDataLayer *cdl = &data->layers[layer_index + setindex];
-
- /* set uvname to bind_vertex_input semantic */
- BLI_strncpy(cdl->name, uvname.c_str(), sizeof(cdl->name));
-
- if (texindex_texarray_map.find(texture_index) == texindex_texarray_map.end()) {
-
- fprintf(stderr, "Cannot find texture array by texture index.\n");
- return color_texture;
- }
-
- std::vector<MTex *> textures = texindex_texarray_map[texture_index];
-
- std::vector<MTex *>::iterator it;
-
- for (it = textures.begin(); it != textures.end(); it++) {
-
- MTex *texture = *it;
-
- if (texture) {
- BLI_strncpy(texture->uvname, uvname.c_str(), sizeof(texture->uvname));
- if (texture->mapto == MAP_COL) color_texture = texture;
- }
- }
- return color_texture;
-}
-
/**
* this function checks if both objects have the same
* materials assigned to Object (in the same order)
@@ -1056,21 +1011,19 @@ void MeshImporter::optimize_material_assignements()
* which materials shall be moved to the created geometries. Also see
* optimize_material_assignements() above.
*/
-MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
- std::map<COLLADAFW::UniqueId, Material *>& uid_material_map,
- Object *ob, const COLLADAFW::UniqueId *geom_uid,
- char *layername, MTFace *texture_face,
- std::map<Material *, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index)
+void MeshImporter::assign_material_to_geom(
+ COLLADAFW::MaterialBinding cmaterial,
+ std::map<COLLADAFW::UniqueId, Material *>& uid_material_map,
+ Object *ob, const COLLADAFW::UniqueId *geom_uid,
+ short mat_index)
{
- MTex *color_texture = NULL;
- Mesh *me = (Mesh *)ob->data;
const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial();
// do we know this material?
if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
fprintf(stderr, "Cannot find material by UID.\n");
- return NULL;
+ return;
}
// first time we get geom_uid, ma_uid pair. Save for later check.
@@ -1083,27 +1036,6 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
ob->actcol=0;
assign_material(m_bmain, ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT);
- COLLADAFW::TextureCoordinateBindingArray& tex_array =
- cmaterial.getTextureCoordinateBindingArray();
- TexIndexTextureArrayMap texindex_texarray_map = material_texture_mapping_map[ma];
- unsigned int i;
- // loop through <bind_vertex_inputs>
- for (i = 0; i < tex_array.getCount(); i++) {
-
- color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
- color_texture);
- }
-
- // set texture face
- if (color_texture &&
- strlen((color_texture)->uvname) &&
- !STREQ(layername, color_texture->uvname))
- {
- texture_face = (MTFace *)CustomData_get_layer_named(&me->fdata, CD_MTFACE,
- color_texture->uvname);
- strcpy(layername, color_texture->uvname);
- }
-
MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
@@ -1118,23 +1050,16 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
Primitive& prim = *it;
MPoly *mpoly = prim.mpoly;
- for (i = 0; i < prim.totpoly; i++, mpoly++) {
+ for (int i = 0; i < prim.totpoly; i++, mpoly++) {
mpoly->mat_nr = mat_index;
- // bind texture images to faces
- if (texture_face && color_texture) {
- texture_face->tpage = (Image *)color_texture->tex->ima;
- texture_face++;
- }
}
}
}
- return texture_face;
}
Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
bool isController,
- std::map<COLLADAFW::UniqueId, Material *>& uid_material_map,
- std::map<Material *, TexIndexTextureArrayMap>& material_texture_mapping_map)
+ std::map<COLLADAFW::UniqueId, Material *>& uid_material_map)
{
const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
@@ -1164,8 +1089,8 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
const char *name = (id.length()) ? id.c_str() : NULL;
// add object
- Object *ob = bc_add_object(m_bmain, scene, OB_MESH, name);
- bc_set_mark(ob); // used later for material assignement optimization
+ Object *ob = bc_add_object(m_bmain, scene, view_layer, OB_MESH, name);
+ bc_set_mark(ob); // used later for material assignment optimization
// store object pointer for ArmatureImporter
@@ -1182,10 +1107,6 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
id_us_plus(&old_mesh->id); /* Because BKE_mesh_assign_object would have already decreased it... */
BKE_libblock_free_us(m_bmain, old_mesh);
- char layername[100];
- layername[0] = '\0';
- MTFace *texture_face = NULL;
-
COLLADAFW::MaterialBindingArray& mat_array =
geom->getMaterialBindings();
@@ -1193,9 +1114,9 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
for (unsigned int i = 0; i < mat_array.getCount(); i++) {
if (mat_array[i].getReferencedMaterial().isValid()) {
- texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid,
- layername, texture_face,
- material_texture_mapping_map, i);
+ assign_material_to_geom(
+ mat_array[i], uid_material_map, ob, geom_uid,
+ i);
}
else {
fprintf(stderr, "invalid referenced material for %s\n", mat_array[i].getName().c_str());
diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h
index 23926bf1ce5..4583242808b 100644
--- a/source/blender/collada/MeshImporter.h
+++ b/source/blender/collada/MeshImporter.h
@@ -51,7 +51,6 @@ extern "C" {
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
}
@@ -93,6 +92,8 @@ private:
Main *m_bmain;
Scene *scene;
+ ViewLayer *view_layer;
+
ArmatureImporter *armature_importer;
std::map<std::string, std::string> mesh_geom_map; // needed for correct shape key naming
@@ -160,29 +161,24 @@ private:
public:
- MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce);
+ MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Main *bmain, Scene *sce, ViewLayer *view_layer);
virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid);
virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId& geom_uid);
- MTex *assign_textures_to_uvlayer(COLLADAFW::TextureCoordinateBinding &ctexture,
- Mesh *me, TexIndexTextureArrayMap& texindex_texarray_map,
- MTex *color_texture);
-
void optimize_material_assignements();
- MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
- std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
- Object *ob, const COLLADAFW::UniqueId *geom_uid,
- char *layername, MTFace *texture_face,
- std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index);
+ void assign_material_to_geom(
+ COLLADAFW::MaterialBinding cmaterial,
+ std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
+ Object *ob, const COLLADAFW::UniqueId *geom_uid,
+ short mat_index);
Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
bool isController,
- std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
- std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map);
+ std::map<COLLADAFW::UniqueId, Material*>& uid_material_map);
// create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
bool write_geometry(const COLLADAFW::Geometry* geom);
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index b571b7503d5..3e375b14e44 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -26,6 +26,7 @@
extern "C" {
#include "BLI_utildefines.h"
+ #include "BKE_collection.h"
#include "BKE_object.h"
#include "BLI_listbase.h"
}
@@ -33,22 +34,19 @@ extern "C" {
#include "SceneExporter.h"
#include "collada_utils.h"
-SceneExporter::SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings)
- : COLLADASW::LibraryVisualScenes(sw), arm_exporter(arm), export_settings(export_settings)
+void SceneExporter::exportScene()
{
-}
+ Scene *scene = blender_context.get_scene();
-void SceneExporter::exportScene(bContext *C, Scene *sce)
-{
// <library_visual_scenes> <visual_scene>
- std::string id_naming = id_name(sce);
- openVisualScene(translate_id(id_naming), id_naming);
- exportHierarchy(C, sce);
+ std::string name = id_name(scene);
+ openVisualScene(translate_id(name), encode_xml(name));
+ exportHierarchy();
closeVisualScene();
closeLibrary();
}
-void SceneExporter::exportHierarchy(bContext *C, Scene *sce)
+void SceneExporter::exportHierarchy()
{
LinkNode *node;
std::vector<Object *> base_objects;
@@ -68,6 +66,7 @@ void SceneExporter::exportHierarchy(bContext *C, Scene *sce)
case OB_CAMERA:
case OB_LAMP:
case OB_EMPTY:
+ case OB_GPENCIL:
case OB_ARMATURE:
base_objects.push_back(ob);
break;
@@ -80,165 +79,162 @@ void SceneExporter::exportHierarchy(bContext *C, Scene *sce)
Object *ob = base_objects[index];
if (bc_is_marked(ob)) {
bc_remove_mark(ob);
- writeNodes(C, ob, sce);
+ writeNodes(ob);
}
}
}
+void SceneExporter::writeNodeList(std::vector<Object *> &child_objects, Object *parent)
+{
+ /* TODO: Handle the case where a parent is not exported
+ Actually i am not even sure if this can be done at all
+ in a good way.
+ I really prefer to enforce the export of hidden
+ elements in an object hierarchy. When the children of
+ the hidden elements are exported as well.
+ */
+ for (int i = 0; i < child_objects.size(); ++i) {
+ Object *child = child_objects[i];
+ if (bc_is_marked(child)) {
+ bc_remove_mark(child);
+ writeNodes(child);
+ }
+ }
+}
-void SceneExporter::writeNodes(bContext *C, Object *ob, Scene *sce)
+void SceneExporter::writeNodes(Object *ob)
{
+ ViewLayer *view_layer = blender_context.get_view_layer();
+
+ std::vector<Object *> child_objects;
+ bc_get_children(child_objects, ob, view_layer);
+ bool can_export = bc_is_in_Export_set(this->export_settings->export_set, ob, view_layer);
+
// Add associated armature first if available
bool armature_exported = false;
Object *ob_arm = bc_get_assigned_armature(ob);
+
if (ob_arm != NULL) {
- armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm);
+ armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm, view_layer);
if (armature_exported && bc_is_marked(ob_arm)) {
bc_remove_mark(ob_arm);
- writeNodes(C, ob_arm, sce);
+ writeNodes(ob_arm);
armature_exported = true;
}
}
- COLLADASW::Node colladaNode(mSW);
- colladaNode.setNodeId(translate_id(id_name(ob)));
- colladaNode.setNodeName(translate_id(id_name(ob)));
- colladaNode.setType(COLLADASW::Node::NODE);
+ if (can_export) {
+ COLLADASW::Node colladaNode(mSW);
+ colladaNode.setNodeId(translate_id(id_name(ob)));
+ colladaNode.setNodeName(encode_xml(id_name(ob)));
+ colladaNode.setType(COLLADASW::Node::NODE);
- colladaNode.start();
+ colladaNode.start();
- std::list<Object *> child_objects;
-
- // list child objects
- LinkNode *node;
- for (node=this->export_settings->export_set; node; node=node->next) {
- // cob - child object
- Object *cob = (Object *)node->link;
+ if (ob->type == OB_MESH && armature_exported) {
+ // for skinned mesh we write obmat in <bind_shape_matrix>
+ TransformWriter::add_node_transform_identity(colladaNode);
+ }
+ else {
+ TransformWriter::add_node_transform_ob(
+ colladaNode,
+ ob,
+ this->export_settings->export_transformation_type,
+ this->export_settings->limit_precision
+ );
+ }
- if (cob->parent == ob) {
- switch (cob->type) {
- case OB_MESH:
- case OB_CAMERA:
- case OB_LAMP:
- case OB_EMPTY:
- case OB_ARMATURE:
- if (bc_is_marked(cob))
- child_objects.push_back(cob);
- break;
+ // <instance_geometry>
+ if (ob->type == OB_MESH) {
+ bool instance_controller_created = false;
+ if (armature_exported) {
+ instance_controller_created = arm_exporter->add_instance_controller(ob);
+ }
+ if (!instance_controller_created) {
+ COLLADASW::InstanceGeometry instGeom(mSW);
+ instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation)));
+ instGeom.setName(encode_xml(id_name(ob)));
+ InstanceWriter::add_material_bindings(instGeom.getBindMaterial(),
+ ob,
+ this->export_settings->active_uv_only);
+ instGeom.add();
}
}
- }
-
- if (ob->type == OB_MESH && armature_exported)
- // for skinned mesh we write obmat in <bind_shape_matrix>
- TransformWriter::add_node_transform_identity(colladaNode);
- else {
- TransformWriter::add_node_transform_ob(colladaNode, ob, this->export_settings->export_transformation_type);
- }
- // <instance_geometry>
- if (ob->type == OB_MESH) {
- bool instance_controller_created = false;
- if (armature_exported) {
- instance_controller_created = arm_exporter->add_instance_controller(ob);
+ // <instance_controller>
+ else if (ob->type == OB_ARMATURE) {
+ arm_exporter->add_armature_bones(ob, view_layer, this, child_objects);
}
- if (!instance_controller_created) {
- COLLADASW::InstanceGeometry instGeom(mSW);
- instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation)));
- instGeom.setName(translate_id(id_name(ob)));
- InstanceWriter::add_material_bindings(instGeom.getBindMaterial(),
- ob,
- this->export_settings->active_uv_only,
- this->export_settings->export_texture_type);
-
- instGeom.add();
- }
- }
-
- // <instance_controller>
- else if (ob->type == OB_ARMATURE) {
- arm_exporter->add_armature_bones(C, ob, sce, this, child_objects);
- }
-
- // <instance_camera>
- else if (ob->type == OB_CAMERA) {
- COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
- instCam.add();
- }
- // <instance_light>
- else if (ob->type == OB_LAMP) {
- COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
- instLa.add();
- }
-
- // empty object
- else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLIGROUP
- if ((ob->transflag & OB_DUPLIGROUP) == OB_DUPLIGROUP && ob->dup_group) {
- GroupObject *go = NULL;
- Group *gr = ob->dup_group;
- /* printf("group detected '%s'\n", gr->id.name + 2); */
- for (go = (GroupObject *)(gr->gobject.first); go; go = go->next) {
- printf("\t%s\n", go->ob->id.name);
- }
+ // <instance_camera>
+ else if (ob->type == OB_CAMERA) {
+ COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
+ instCam.add();
}
- }
- if (ob->type == OB_ARMATURE) {
- colladaNode.end();
- }
+ // <instance_light>
+ else if (ob->type == OB_LAMP) {
+ COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
+ instLa.add();
+ }
- if (BLI_listbase_is_empty(&ob->constraints) == false) {
- bConstraint *con = (bConstraint *) ob->constraints.first;
- while (con) {
- std::string con_name(translate_id(con->name));
- std::string con_tag = con_name + "_constraint";
- printf("%s\n", con_name.c_str());
- printf("%s\n\n", con_tag.c_str());
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"type",con->type);
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"enforce",con->enforce);
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"flag",con->flag);
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"headtail",con->headtail);
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"own_space",con->ownspace);
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"rot_error",con->rot_error);
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"tar_space",con->tarspace);
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
-
- //not ideal: add the target object name as another parameter.
- //No real mapping in the .dae
- //Need support for multiple target objects also.
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- if (cti && cti->get_constraint_targets) {
-
- bConstraintTarget *ct;
- Object *obtar;
-
- cti->get_constraint_targets(con, &targets);
-
- for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
- obtar = ct->tar;
- std::string tar_id((obtar) ? id_name(obtar) : "");
- colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"target_id",tar_id);
+ // empty object
+ else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLICOLLECTION
+ if ((ob->transflag & OB_DUPLICOLLECTION) == OB_DUPLICOLLECTION && ob->dup_group) {
+ Collection *collection = ob->dup_group;
+ /* printf("group detected '%s'\n", group->id.name + 2); */
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
+ {
+ printf("\t%s\n", object->id.name);
}
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
-
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
- con = con->next;
- }
- }
-
- for (std::list<Object *>::iterator i = child_objects.begin(); i != child_objects.end(); ++i) {
- if (bc_is_marked(*i)) {
- bc_remove_mark(*i);
- writeNodes(C, *i, sce);
+ if (BLI_listbase_is_empty(&ob->constraints) == false) {
+ bConstraint *con = (bConstraint *)ob->constraints.first;
+ while (con) {
+ std::string con_name(encode_xml(con->name));
+ std::string con_tag = con_name + "_constraint";
+ printf("%s\n", con_name.c_str());
+ printf("%s\n\n", con_tag.c_str());
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "type", con->type);
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "enforce", con->enforce);
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "flag", con->flag);
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "headtail", con->headtail);
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "lin_error", con->lin_error);
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "own_space", con->ownspace);
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "rot_error", con->rot_error);
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "tar_space", con->tarspace);
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "lin_error", con->lin_error);
+
+ //not ideal: add the target object name as another parameter.
+ //No real mapping in the .dae
+ //Need support for multiple target objects also.
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = { NULL, NULL };
+ if (cti && cti->get_constraint_targets) {
+
+ bConstraintTarget *ct;
+ Object *obtar;
+
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
+ obtar = ct->tar;
+ std::string tar_id((obtar) ? id_name(obtar) : "");
+ colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+
+ }
+
+ con = con->next;
+ }
+ }
}
- }
-
- if (ob->type != OB_ARMATURE)
+ writeNodeList(child_objects, ob);
colladaNode.end();
+ }
}
diff --git a/source/blender/collada/SceneExporter.h b/source/blender/collada/SceneExporter.h
index 6cf561749de..f6525d5438d 100644
--- a/source/blender/collada/SceneExporter.h
+++ b/source/blender/collada/SceneExporter.h
@@ -34,7 +34,7 @@
extern "C" {
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_image_types.h"
@@ -48,7 +48,6 @@ extern "C" {
#include "DNA_modifier_types.h"
#include "DNA_userdef_types.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_fcurve.h"
#include "BKE_animsys.h"
#include "BLI_path_util.h"
@@ -95,16 +94,26 @@ extern "C" {
class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, protected InstanceWriter
{
public:
- SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings);
- void exportScene(bContext *C, Scene *sce);
+
+ SceneExporter(BlenderContext &blender_context, COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings) :
+ COLLADASW::LibraryVisualScenes(sw),
+ blender_context(blender_context),
+ arm_exporter(arm),
+ export_settings(export_settings)
+ {}
+
+ void exportScene();
private:
+ BlenderContext &blender_context;
friend class ArmatureExporter;
- void exportHierarchy(bContext *C, Scene *sce);
- void writeNodes(bContext *C, Object *ob, Scene *sce);
-
ArmatureExporter *arm_exporter;
const ExportSettings *export_settings;
+
+ void exportHierarchy();
+ void writeNodeList(std::vector<Object *> &child_objects, Object *parent);
+ void writeNodes(Object *ob);
+
};
#endif
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp
index b270ac87976..c55aca7976f 100644
--- a/source/blender/collada/SkinInfo.cpp
+++ b/source/blender/collada/SkinInfo.cpp
@@ -159,9 +159,9 @@ void SkinInfo::set_controller(const COLLADAFW::SkinController *co)
}
// called from write_controller
-Object *SkinInfo::create_armature(Main *bmain, Scene *scene)
+Object *SkinInfo::create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
- ob_arm = bc_add_object(bmain, scene, OB_ARMATURE, NULL);
+ ob_arm = bc_add_object(bmain, scene, view_layer, OB_ARMATURE, NULL);
return ob_arm;
}
@@ -232,7 +232,10 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique
amd->object = ob_arm;
#if 1
- bc_set_parent(ob, ob_arm, C);
+ /* XXX Why do we enforce objects to be children of Armatures if they weren't so before ?*/
+ if (!BKE_object_is_child_recursive(ob_arm, ob)) {
+ bc_set_parent(ob, ob_arm, C);
+ }
#else
Object workob;
ob->parent = ob_arm;
@@ -241,10 +244,7 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique
BKE_object_workob_calc_parent(scene, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
- DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA);
-
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA);
#endif
copy_m4_m4(ob->obmat, bind_shape_matrix);
BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h
index 500ae3878a6..39808c546b1 100644
--- a/source/blender/collada/SkinInfo.h
+++ b/source/blender/collada/SkinInfo.h
@@ -99,7 +99,7 @@ public:
void set_controller(const COLLADAFW::SkinController* co);
// called from write_controller
- Object *create_armature(Main *bmain, Scene *scene);
+ Object *create_armature(Main *bmain, Scene *scene, ViewLayer *view_layer);
Object* set_armature(Object *ob_arm);
diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp
index bf9c34153b7..0c2ea9cb7c4 100644
--- a/source/blender/collada/TransformReader.cpp
+++ b/source/blender/collada/TransformReader.cpp
@@ -80,8 +80,10 @@ void TransformReader::get_node_mat(
dae_scale_to_mat4(tm, cur);
break;
case COLLADAFW::Transformation::LOOKAT:
+ fprintf(stderr, "|! LOOKAT transformations are not supported yet.\n");
+ break;
case COLLADAFW::Transformation::SKEW:
- fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
+ fprintf(stderr, "|! SKEW transformations are not supported yet.\n");
break;
}
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index 89653c139f3..4ff9e0af50f 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -26,12 +26,14 @@
*/
-#include "BKE_object.h"
#include "BLI_math.h"
+#include "BLI_sys_types.h"
+
+#include "BKE_object.h"
#include "TransformWriter.h"
-void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4])
+void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4], bool limit_precision)
{
float loc[3], rot[3], scale[3];
float local[4][4];
@@ -61,7 +63,11 @@ void TransformWriter::add_node_transform(COLLADASW::Node& node, float mat[4][4],
}
}
-void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, BC_export_transformation_type transformation_type)
+void TransformWriter::add_node_transform_ob(
+ COLLADASW::Node& node,
+ Object *ob,
+ BC_export_transformation_type transformation_type,
+ bool limit_precision)
{
#if 0
float rot[3], loc[3], scale[3];
@@ -98,17 +104,18 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B
add_transform(node, loc, rot, scale);
#endif
- UnitConverter converter;
- double d_obmat[4][4];
- float f_obmat[4][4];
-
/* Export the local Matrix (relative to the object parent, be it an object, bone or vertex(-tices)) */
+ float f_obmat[4][4];
BKE_object_matrix_local_get(ob, f_obmat);
- converter.mat4_to_dae_double(d_obmat, f_obmat);
switch (transformation_type) {
case BC_TRANSFORMATION_TYPE_MATRIX:
{
+ UnitConverter converter;
+ double d_obmat[4][4];
+ converter.mat4_to_dae_double(d_obmat, f_obmat);
+ if (limit_precision)
+ bc_sanitize_mat(d_obmat, LIMITTED_PRECISION);
node.addMatrix("transform",d_obmat);
break;
}
@@ -116,6 +123,11 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B
{
float loc[3], rot[3], scale[3];
bc_decompose(f_obmat, loc, rot, NULL, scale);
+ if (limit_precision) {
+ bc_sanitize_v3(loc, LIMITTED_PRECISION);
+ bc_sanitize_v3(rot, LIMITTED_PRECISION);
+ bc_sanitize_v3(scale, LIMITTED_PRECISION);
+ }
add_transform(node, loc, rot, scale);
break;
}
diff --git a/source/blender/collada/TransformWriter.h b/source/blender/collada/TransformWriter.h
index 5bb13d4aac9..2c7fedb9f34 100644
--- a/source/blender/collada/TransformWriter.h
+++ b/source/blender/collada/TransformWriter.h
@@ -39,9 +39,17 @@
class TransformWriter
{
protected:
- void add_node_transform(COLLADASW::Node& node, float mat[4][4], float parent_mat[4][4]);
-
- void add_node_transform_ob(COLLADASW::Node& node, Object *ob, BC_export_transformation_type transformation_type);
+ void add_node_transform(
+ COLLADASW::Node& node,
+ float mat[4][4],
+ float parent_mat[4][4],
+ bool limit_precision=false);
+
+ void add_node_transform_ob(
+ COLLADASW::Node& node,
+ Object *ob,
+ BC_export_transformation_type transformation_type,
+ bool limit_precision = false);
void add_node_transform_identity(COLLADASW::Node& node);
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index ecaa7fba08c..c6321a4047e 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -32,34 +32,67 @@
#include "DocumentImporter.h"
#include "ExportSettings.h"
#include "ImportSettings.h"
+#include "collada.h"
extern "C"
{
#include "BKE_scene.h"
#include "BKE_context.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
/* make dummy file */
#include "BLI_fileops.h"
#include "BLI_linklist.h"
+
+static void print_import_header(ImportSettings &import_settings)
+{
+ fprintf(stderr, "+-- Collada Import parameters------\n");
+ fprintf(stderr, "| input file : %s\n", import_settings.filepath);
+ fprintf(stderr, "| use units : %s\n", (import_settings.import_units)?"yes":"no");
+ fprintf(stderr, "| autoconnect : %s\n", (import_settings.auto_connect) ? "yes" : "no");
+ fprintf(stderr, "+-- Armature Import parameters ----\n");
+ fprintf(stderr, "| find bone chains: %s\n", (import_settings.find_chains) ? "yes" : "no");
+ fprintf(stderr, "| min chain len : %d\n", import_settings.min_chain_length);
+ fprintf(stderr, "| fix orientation : %s\n", (import_settings.fix_orientation) ? "yes" : "no");
+ fprintf(stderr, "| keep bind info : %s\n", (import_settings.keep_bind_info) ? "yes" : "no");
+
+}
+
+static void print_import_footer(int status)
+{
+ fprintf(stderr, "+----------------------------------\n");
+ fprintf(stderr, "| Collada Import : %s\n", (status)? "OK":"FAIL");
+ fprintf(stderr, "+----------------------------------\n");
+}
+
int collada_import(bContext *C, ImportSettings *import_settings)
{
+ print_import_header(*import_settings);
DocumentImporter imp(C, import_settings);
- return (imp.import())? 1:0;
+ int status = imp.import()? 1:0;
+ print_import_footer(status);
+
+ return status;
}
int collada_export(bContext *C,
- EvaluationContext *eval_ctx,
- Scene *sce,
ExportSettings *export_settings)
{
+ BlenderContext blender_context(C);
+ ViewLayer *view_layer = blender_context.get_view_layer();
int includeFilter = OB_REL_NONE;
if (export_settings->include_armatures) includeFilter |= OB_REL_MOD_ARMATURE;
if (export_settings->include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE;
+ /* Fetch the complete set of exported objects
+ * ATTENTION: Invisible objects will not be exported
+ */
eObjectSet objectSet = (export_settings->selected) ? OB_SET_SELECTED : OB_SET_ALL;
- export_settings->export_set = BKE_object_relational_superset(sce, objectSet, (eObRelationTypes)includeFilter);
+ export_settings->export_set = BKE_object_relational_superset(view_layer, objectSet, (eObRelationTypes)includeFilter);
+
int export_count = BLI_linklist_count(export_settings->export_set);
if (export_count == 0) {
@@ -75,8 +108,8 @@ int collada_export(bContext *C,
bc_bubble_sort_by_Object_name(export_settings->export_set);
}
- DocumentExporter exporter(export_settings);
- int status = exporter.exportCurrentScene(C, eval_ctx, sce);
+ DocumentExporter exporter(blender_context, export_settings);
+ int status = exporter.exportCurrentScene();
BLI_linklist_free(export_settings->export_set, NULL);
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 907c94855f7..7882542ca44 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -36,15 +36,14 @@
extern "C" {
#endif
-#include "BKE_depsgraph.h"
#include "BLI_linklist.h"
#include "BLI_path_util.h"
#include "RNA_types.h"
-
-struct EvaluationContext;
struct bContext;
+struct Depsgraph;
struct Scene;
+struct ViewLayer;
/*
* both return 1 on success, 0 on error
@@ -53,8 +52,6 @@ int collada_import(struct bContext *C,
ImportSettings *import_settings);
int collada_export(struct bContext *C,
- struct EvaluationContext *eval_ctx,
- struct Scene *sce,
ExportSettings *export_settings);
#ifdef __cplusplus
diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp
index 14f3e811797..64de0596ac5 100644
--- a/source/blender/collada/collada_internal.cpp
+++ b/source/blender/collada/collada_internal.cpp
@@ -30,6 +30,7 @@
#include "collada_utils.h"
#include "BLI_linklist.h"
+#include "ED_armature.h"
UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP)
{
@@ -310,6 +311,33 @@ std::string id_name(void *id)
return ((ID *)id)->name + 2;
}
+std::string encode_xml(std::string xml)
+{
+ const std::map<char, std::string> escape {
+ {'<' , "&lt;" },
+ {'>' , "&gt;" },
+ {'"' , "&quot;"},
+ {'\'', "&apos;"},
+ {'&' , "&amp;" }
+ };
+
+ std::map<char, std::string>::const_iterator it;
+ std::string encoded_xml = "";
+
+ for (unsigned int i = 0; i < xml.size(); i++) {
+ char c = xml.at(i);
+ it = escape.find(c);
+
+ if (it == escape.end()) {
+ encoded_xml += c;
+ }
+ else {
+ encoded_xml += it->second;
+ }
+ }
+ return encoded_xml;
+}
+
std::string get_geometry_id(Object *ob)
{
return translate_id(id_name(ob->data)) + "-mesh";
@@ -327,12 +355,11 @@ std::string get_light_id(Object *ob)
return translate_id(id_name(ob)) + "-light";
}
-std::string get_joint_id(Object *ob, Bone *bone)
+std::string get_joint_sid(Bone *bone)
{
- return translate_id(id_name(ob) + "_" + bone->name);
+ return translate_id(bone->name);
}
-
-std::string get_joint_sid(Bone *bone)
+std::string get_joint_sid(EditBone *bone)
{
return translate_id(bone->name);
}
@@ -342,15 +369,14 @@ std::string get_camera_id(Object *ob)
return translate_id(id_name(ob)) + "-camera";
}
-std::string get_material_id(Material *mat)
+std::string get_effect_id(Material *mat)
{
- std::string id = id_name(mat);
- return get_material_id_from_id(id);
+ return translate_id(id_name(mat)) + "-effect";
}
-std::string get_material_id_from_id(std::string id)
+std::string get_material_id(Material *mat)
{
- return translate_id(id) + "-material";
+ return translate_id(id_name(mat)) + "-material";
}
std::string get_morph_id(Object *ob)
diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h
index ff998a94685..f16e3a7cf4a 100644
--- a/source/blender/collada/collada_internal.h
+++ b/source/blender/collada/collada_internal.h
@@ -73,11 +73,9 @@ public:
// TODO need also for angle conversion, time conversion...
- void dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4& in);
-
- void mat4_to_dae(float out[4][4], float in[4][4]);
-
- void mat4_to_dae_double(double out[4][4], float in[4][4]);
+ static void dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4& in);
+ static void mat4_to_dae(float out[4][4], float in[4][4]);
+ static void mat4_to_dae_double(double out[4][4], float in[4][4]);
float(&get_rotation())[4][4];
float(&get_scale())[4][4];
@@ -91,20 +89,19 @@ extern std::string translate_id(const std::string &id);
extern std::string translate_id(const char *idString);
extern std::string id_name(void *id);
+extern std::string encode_xml(std::string xml);
extern std::string get_geometry_id(Object *ob);
extern std::string get_geometry_id(Object *ob, bool use_instantiation);
extern std::string get_light_id(Object *ob);
-extern std::string get_joint_id(Object *ob, Bone *bone);
extern std::string get_joint_sid(Bone *bone);
extern std::string get_camera_id(Object *ob);
+extern std::string get_morph_id(Object *ob);
+extern std::string get_effect_id(Material *mat);
extern std::string get_material_id(Material *mat);
-extern std::string get_material_id_from_id(std::string id);
-
-extern std::string get_morph_id(Object *ob);
#endif /* __COLLADA_INTERNAL_H__ */
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index b25a35a5452..f5be93195ab 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -33,39 +33,59 @@
#include "COLLADAFWMeshVertexData.h"
#include <set>
-
+#include <string>
extern "C" {
#include "DNA_modifier_types.h"
#include "DNA_customdata_types.h"
+#include "DNA_key_types.h"
#include "DNA_object_types.h"
+#include "DNA_constraint_types.h"
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "DNA_armature_types.h"
#include "BLI_math.h"
#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BKE_action.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
+#include "BKE_constraint.h"
+#include "BKE_key.h"
+#include "BKE_material.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_object.h"
#include "BKE_scene.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_main.h"
#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_node.h"
+
+#include "MEM_guardedalloc.h"
#include "WM_api.h" // XXX hrm, see if we can do without this
#include "WM_types.h"
#include "bmesh.h"
#include "bmesh_tools.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#if 0
+#include "NOD_common.h"
+#endif
}
#include "collada_utils.h"
#include "ExportSettings.h"
+#include "BlenderContext.h"
float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
{
@@ -89,11 +109,53 @@ int bc_test_parent_loop(Object *par, Object *ob)
return bc_test_parent_loop(par->parent, ob);
}
+void bc_get_children(std::vector<Object *> &child_set, Object *ob, ViewLayer *view_layer)
+{
+ Base *base;
+ for (base = (Base *)view_layer->object_bases.first; base; base = base->next) {
+ Object *cob = base->object;
+ if (cob->parent == ob) {
+ switch (ob->type) {
+ case OB_MESH:
+ case OB_CAMERA:
+ case OB_LAMP:
+ case OB_EMPTY:
+ case OB_ARMATURE:
+ child_set.push_back(cob);
+ default: break;
+ }
+ }
+ }
+}
+
+bool bc_validateConstraints(bConstraint *con)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ /* these we can skip completely (invalid constraints...) */
+ if (cti == NULL)
+ return false;
+ if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))
+ return false;
+
+ /* these constraints can't be evaluated anyway */
+ if (cti->evaluate_constraint == NULL)
+ return false;
+
+ /* influence == 0 should be ignored */
+ if (con->enforce == 0.0f)
+ return false;
+
+ /* validation passed */
+ return true;
+}
+
// a shortened version of parent_set_exec()
// if is_parent_space is true then ob->obmat will be multiplied by par->obmat before parenting
int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
{
Object workob;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *sce = CTX_data_scene(C);
if (!par || bc_test_parent_loop(par, ob))
@@ -107,7 +169,7 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
if (is_parent_space) {
float mat[4][4];
// calc par->obmat
- BKE_object_where_is_calc(sce, par);
+ BKE_object_where_is_calc(depsgraph, sce, par);
// move child obmat into world space
mul_m4_m4m4(mat, par->obmat, ob->obmat);
@@ -118,74 +180,121 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
// compute parentinv
- BKE_object_workob_calc_parent(sce, ob, &workob);
+ BKE_object_workob_calc_parent(depsgraph, sce, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
- DAG_id_tag_update(&par->id, OB_RECALC_OB);
-
- /** done once after import */
-#if 0
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-#endif
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&par->id, OB_RECALC_OB);
return true;
}
-EvaluationContext *bc_get_evaluation_context(Main *bmain)
+std::vector<bAction *> bc_getSceneActions(const bContext *C, Object *ob, bool all_actions)
{
- return bmain->eval_ctx;
+ std::vector<bAction *> actions;
+ if (all_actions) {
+ Main *bmain = CTX_data_main(C);
+ ID *id;
+
+ for (id = (ID *)bmain->action.first; id; id = (ID *)(id->next)) {
+ bAction *act = (bAction *)id;
+ /* XXX This currently creates too many actions.
+ TODO Need to check if the action is compatible to the given object
+ */
+ actions.push_back(act);
+ }
+ }
+ else
+ {
+ bAction *action = bc_getSceneObjectAction(ob);
+ actions.push_back(action);
+ }
+
+ return actions;
+}
+
+std::string bc_get_action_id(std::string action_name, std::string ob_name, std::string channel_type, std::string axis_name, std::string axis_separator)
+{
+ std::string result = action_name + "_" + channel_type;
+ if (ob_name.length() > 0)
+ result = ob_name + "_" + result;
+ if (axis_name.length() > 0)
+ result += axis_separator + axis_name;
+ return translate_id(result);
}
-void bc_update_scene(Main *bmain, Scene *scene, float ctime)
+void bc_update_scene(BlenderContext &blender_context, float ctime)
{
+ Main *bmain = blender_context.get_main();
+ Scene *scene = blender_context.get_scene();
+ Depsgraph *depsgraph = blender_context.get_depsgraph();
+
+ /*
+ * See remark in physics_fluid.c lines 395...)
+ * BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay);
+ */
BKE_scene_frame_set(scene, ctime);
- EvaluationContext *ev_context = bc_get_evaluation_context(bmain);
- BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay);
+ ED_update_for_newframe(bmain, depsgraph);
}
-Object *bc_add_object(Main *bmain, Scene *scene, int type, const char *name)
+Object *bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name)
{
Object *ob = BKE_object_add_only_object(bmain, type, name);
ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
ob->lay = scene->lay;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- BKE_scene_base_select(scene, BKE_scene_base_add(scene, ob));
+ LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
+
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ /* TODO: is setting active needed? */
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
return ob;
}
Mesh *bc_get_mesh_copy(
- Main *bmain, Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate)
+ BlenderContext &blender_context,
+ Object *ob,
+ BC_export_mesh_type export_mesh_type,
+ bool apply_modifiers,
+ bool triangulate)
{
- Mesh *tmpmesh;
CustomDataMask mask = CD_MASK_MESH;
Mesh *mesh = (Mesh *)ob->data;
- DerivedMesh *dm = NULL;
+ Mesh *tmpmesh = NULL;
if (apply_modifiers) {
+#if 0 /* Not supported by new system currently... */
switch (export_mesh_type) {
case BC_MESH_TYPE_VIEW:
{
- dm = mesh_create_derived_view(scene, ob, mask);
+ dm = mesh_create_derived_view(depsgraph, scene, ob, mask);
break;
}
case BC_MESH_TYPE_RENDER:
{
- dm = mesh_create_derived_render(scene, ob, mask);
+ dm = mesh_create_derived_render(depsgraph, scene, ob, mask);
break;
}
}
+#else
+ Depsgraph *depsgraph = blender_context.get_depsgraph();
+ Scene *scene = blender_context.get_scene();
+ tmpmesh = mesh_get_eval_final(depsgraph, scene, ob, mask);
+#endif
}
else {
- dm = mesh_create_derived((Mesh *)ob->data, NULL);
+ tmpmesh = mesh;
}
- tmpmesh = BKE_mesh_add(bmain, "ColladaMesh"); // name is not important here
- DM_to_mesh(dm, tmpmesh, ob, CD_MASK_MESH, true);
- tmpmesh->flag = mesh->flag;
+ BKE_id_copy_ex(NULL, &tmpmesh->id, (ID **)&tmpmesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
if (triangulate) {
bc_triangulate_mesh(tmpmesh);
@@ -213,12 +322,14 @@ Object *bc_get_assigned_armature(Object *ob)
return ob_arm;
}
-// Returns the highest selected ancestor
-// returns NULL if no ancestor is selected
-// IMPORTANT: This function expects that
-// all exported objects have set:
-// ob->id.tag & LIB_TAG_DOIT
+/*
+* Returns the highest selected ancestor
+* returns NULL if no ancestor is selected
+* IMPORTANT: This function expects that all exported objects have set:
+* ob->id.tag & LIB_TAG_DOIT
+*/
Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob)
+
{
Object *ancestor = ob;
while (ob->parent && bc_is_marked(ob->parent)) {
@@ -228,16 +339,31 @@ Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *o
return ancestor;
}
-
bool bc_is_base_node(LinkNode *export_set, Object *ob)
{
Object *root = bc_get_highest_selected_ancestor_or_self(export_set, ob);
return (root == ob);
}
-bool bc_is_in_Export_set(LinkNode *export_set, Object *ob)
+bool bc_is_in_Export_set(LinkNode *export_set, Object *ob, ViewLayer *view_layer)
{
- return (BLI_linklist_index(export_set, ob) != -1);
+ bool to_export = (BLI_linklist_index(export_set, ob) != -1);
+
+ if (!to_export)
+ {
+ /* Mark this object as to_export even if it is not in the
+ export list, but it contains children to export */
+
+ std::vector<Object *> children;
+ bc_get_children(children, ob, view_layer);
+ for (int i = 0; i < children.size(); i++) {
+ if (bc_is_in_Export_set(export_set, children[i], view_layer)) {
+ to_export = true;
+ break;
+ }
+ }
+ }
+ return to_export;
}
bool bc_has_object_type(LinkNode *export_set, short obtype)
@@ -317,7 +443,7 @@ bool bc_is_root_bone(Bone *aBone, bool deform_bones_only)
int bc_get_active_UVLayer(Object *ob)
{
Mesh *me = (Mesh *)ob->data;
- return CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
+ return CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
}
std::string bc_url_encode(std::string data)
@@ -811,6 +937,133 @@ static bool has_custom_props(Bone *bone, bool enabled, std::string key)
}
+void bc_enable_fcurves(bAction *act, char *bone_name)
+{
+ FCurve *fcu;
+ char prefix[200];
+
+ if (bone_name)
+ BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
+
+ for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
+ if (bone_name) {
+ if (STREQLEN(fcu->rna_path, prefix, strlen(prefix)))
+ fcu->flag &= ~FCURVE_DISABLED;
+ else
+ fcu->flag |= FCURVE_DISABLED;
+ }
+ else {
+ fcu->flag &= ~FCURVE_DISABLED;
+ }
+ }
+}
+
+bool bc_bone_matrix_local_get(Object *ob, Bone *bone, Matrix &mat, bool for_opensim)
+{
+
+ /* Ok, lets be super cautious and check if the bone exists */
+ bPose *pose = ob->pose;
+ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
+ if (!pchan) {
+ return false;
+ }
+
+ bAction *action = bc_getSceneObjectAction(ob);
+ bPoseChannel *parchan = pchan->parent;
+
+ bc_enable_fcurves(action, bone->name);
+ float ipar[4][4];
+
+ if (bone->parent) {
+ invert_m4_m4(ipar, parchan->pose_mat);
+ mul_m4_m4m4(mat, ipar, pchan->pose_mat);
+ }
+ else
+ copy_m4_m4(mat, pchan->pose_mat);
+
+ /* OPEN_SIM_COMPATIBILITY
+ * AFAIK animation to second life is via BVH, but no
+ * reason to not have the collada-animation be correct
+ */
+ if (for_opensim) {
+ float temp[4][4];
+ copy_m4_m4(temp, bone->arm_mat);
+ temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+ invert_m4(temp);
+
+ mul_m4_m4m4(mat, mat, temp);
+
+ if (bone->parent) {
+ copy_m4_m4(temp, bone->parent->arm_mat);
+ temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
+
+ mul_m4_m4m4(mat, temp, mat);
+ }
+ }
+ bc_enable_fcurves(action, NULL);
+ return true;
+}
+
+bool bc_is_animated(BCMatrixSampleMap &values)
+{
+ static float MIN_DISTANCE = 0.00001;
+
+ if (values.size() < 2)
+ return false; // need at least 2 entries to be not flat
+
+ BCMatrixSampleMap::iterator it;
+ const BCMatrix *refmat = NULL;
+ for (it = values.begin(); it != values.end(); ++it) {
+ const BCMatrix *matrix = it->second;
+
+ if (refmat == NULL) {
+ refmat = matrix;
+ continue;
+ }
+
+ if (!matrix->in_range(*refmat, MIN_DISTANCE))
+ return true;
+ }
+ return false;
+}
+
+bool bc_has_animations(Object *ob)
+{
+ /* Check for object,lamp and camera transform animations */
+ if ((bc_getSceneObjectAction(ob) && bc_getSceneObjectAction(ob)->curves.first) ||
+ (bc_getSceneLampAction(ob) && bc_getSceneLampAction(ob)->curves.first) ||
+ (bc_getSceneCameraAction(ob) && bc_getSceneCameraAction(ob)->curves.first))
+ return true;
+
+ //Check Material Effect parameter animations.
+ for (int a = 0; a < ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a + 1);
+ if (!ma) continue;
+ if (ma->adt && ma->adt->action && ma->adt->action->curves.first)
+ return true;
+ }
+
+ Key *key = BKE_key_from_object(ob);
+ if ((key && key->adt && key->adt->action) && key->adt->action->curves.first)
+ return true;
+
+ return false;
+}
+
+
+bool bc_has_animations(Scene *sce, LinkNode &export_set)
+{
+ LinkNode *node;
+
+ for (node = &export_set; node; node = node->next) {
+ Object *ob = (Object *)node->link;
+
+ if (bc_has_animations(ob))
+ return true;
+ }
+ return false;
+}
+
/**
* Check if custom information about bind matrix exists and modify the from_mat
* accordingly.
@@ -875,8 +1128,20 @@ void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, f
void bc_sanitize_mat(float mat[4][4], int precision)
{
for (int i = 0; i < 4; i++)
- for (int j = 0; j < 4; j++)
- mat[i][j] = double_round(mat[i][j], precision);
+ for (int j = 0; j < 4; j++) {
+ double val = (double)mat[i][j];
+ val = double_round(val, precision);
+ mat[i][j] = (float)val;
+ }
+}
+
+void bc_sanitize_v3(float v[3], int precision)
+{
+ for (int i = 0; i < 3; i++) {
+ double val = (double)v[i];
+ val = double_round(val, precision);
+ v[i] = (float)val;
+ }
}
void bc_sanitize_mat(double mat[4][4], int precision)
@@ -886,6 +1151,13 @@ void bc_sanitize_mat(double mat[4][4], int precision)
mat[i][j] = double_round(mat[i][j], precision);
}
+void bc_sanitize_v3(double v[3], int precision)
+{
+ for (int i = 0; i < 3; i++) {
+ v[i] = double_round(v[i], precision);
+ }
+}
+
void bc_copy_m4_farray(float r[4][4], float *a)
{
for (int i = 0; i < 4; i++)
@@ -898,17 +1170,31 @@ void bc_copy_farray_m4(float *r, float a[4][4])
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
*r++ = a[i][j];
+}
+
+void bc_copy_darray_m4d(double *r, double a[4][4])
+{
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ *r++ = a[i][j];
+}
+void bc_copy_v44_m4d(std::vector<std::vector<double>> &r, double(&a)[4][4])
+{
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ r[i][j] = a[i][j];
+ }
+ }
}
-/*
-* Returns name of Active UV Layer or empty String if no active UV Layer defined.
-* Assuming the Object is of type MESH
-*/
-std::string bc_get_active_uvlayer_name(Object *ob)
+void bc_copy_m4d_v44(double (&r)[4][4], std::vector<std::vector<double>> &a)
{
- Mesh *me = (Mesh *)ob->data;
- return bc_get_active_uvlayer_name(me);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ r[i][j] = a[i][j];
+ }
+ }
}
/**
@@ -916,9 +1202,9 @@ std::string bc_get_active_uvlayer_name(Object *ob)
*/
std::string bc_get_active_uvlayer_name(Mesh *me)
{
- int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (num_layers) {
- char *layer_name = bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE);
+ char *layer_name = bc_CustomData_get_active_layer_name(&me->ldata, CD_MLOOPUV);
if (layer_name) {
return std::string(layer_name);
}
@@ -926,14 +1212,24 @@ std::string bc_get_active_uvlayer_name(Mesh *me)
return "";
}
-/*
+/**
+ * Returns name of Active UV Layer or empty String if no active UV Layer defined.
+ * Assuming the Object is of type MESH
+ */
+std::string bc_get_active_uvlayer_name(Object *ob)
+{
+ Mesh *me = (Mesh *)ob->data;
+ return bc_get_active_uvlayer_name(me);
+}
+
+/**
* Returns UV Layer name or empty string if layer index is out of range
*/
std::string bc_get_uvlayer_name(Mesh *me, int layer)
{
- int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (num_layers && layer < num_layers) {
- char *layer_name = bc_CustomData_get_layer_name(&me->fdata, CD_MTFACE, layer);
+ char *layer_name = bc_CustomData_get_layer_name(&me->ldata, CD_MLOOPUV, layer);
if (layer_name) {
return std::string(layer_name);
}
@@ -941,124 +1237,202 @@ std::string bc_get_uvlayer_name(Mesh *me, int layer)
return "";
}
-/**********************************************************************
-*
-* Return the list of Mesh objects with assigned UVtextures and Images
-* Note: We need to create artificaial materials for each of them
-*
-***********************************************************************/
-std::set<Object *> bc_getUVTexturedObjects(Scene *sce, bool all_uv_layers)
-{
- std::set <Object *> UVObjects;
- Base *base = (Base *)sce->base.first;
-
- while (base) {
- Object *ob = base->object;
- bool has_uvimage = false;
- if (ob->type == OB_MESH) {
- Mesh *me = (Mesh *)ob->data;
- int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
-
- for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
- if (all_uv_layers || active_uv_layer == i)
- {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
- MPoly *mpoly = me->mpoly;
- for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
-
- Image *ima = txface->tpage;
- if (ima != NULL) {
- has_uvimage = true;
- break;
- }
- }
- }
- }
- }
+std::string bc_find_bonename_in_path(std::string path, std::string probe)
+{
+ std::string result;
+ char *boneName = BLI_str_quoted_substrN(path.c_str(), probe.c_str());
+ if (boneName) {
+ result = std::string(boneName);
+ MEM_freeN(boneName);
+ }
+ return result;
+}
- if (has_uvimage) {
- UVObjects.insert(ob);
- }
- }
- base = base->next;
+static bNodeTree *prepare_material_nodetree(Material *ma)
+{
+ if (ma->nodetree == NULL) {
+ ma->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree");
+ ma->use_nodes = true;
}
- return UVObjects;
-}
-
-/**********************************************************************
-*
-* Return the list of UV Texture images from all exported Mesh Items
-* Note: We need to create one artificial material for each Image.
-*
-***********************************************************************/
-std::set<Image *> bc_getUVImages(Scene *sce, bool all_uv_layers)
-{
- std::set <Image *> UVImages;
- Base *base = (Base *)sce->base.first;
-
- while (base) {
- Object *ob = base->object;
- bool has_uvimage = false;
- if (ob->type == OB_MESH) {
- Mesh *me = (Mesh *)ob->data;
- int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
-
- for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
- if (all_uv_layers || active_uv_layer == i)
- {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
- MPoly *mpoly = me->mpoly;
- for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
-
- Image *ima = txface->tpage;
- if (ima != NULL) {
- if (UVImages.find(ima) == UVImages.end())
- UVImages.insert(ima);
- }
- }
- }
- }
- }
+ return ma->nodetree;
+}
+
+bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy, std::string label)
+{
+ bNode *node = nodeAddStaticNode(C, ntree, node_type);
+ if (node) {
+ if (label.length() > 0) {
+ strcpy(node->label, label.c_str());
}
- base = base->next;
+ node->locx = locx;
+ node->locy = locy;
+ node->flag |= NODE_SELECT;
}
- return UVImages;
+ return node;
}
-/**********************************************************************
-*
-* Return the list of UV Texture images for the given Object
-* Note: We need to create one artificial material for each Image.
-*
-***********************************************************************/
-std::set<Image *> bc_getUVImages(Object *ob, bool all_uv_layers)
+
+bNode *bc_add_node(bContext *C, bNodeTree *ntree, int node_type, int locx, int locy)
{
- std::set <Image *> UVImages;
+ return bc_add_node(C, ntree, node_type, locx, locy, "");
+}
+
+#if 0
+// experimental, probably not used
+static bNodeSocket *bc_group_add_input_socket(bNodeTree *ntree, bNode *to_node, int to_index, std::string label)
+{
+ bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
- bool has_uvimage = false;
- if (ob->type == OB_MESH) {
- Mesh *me = (Mesh *)ob->data;
- int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+ //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
+ //return socket;
- for (int i = 0; i < me->pdata.totlayer && !has_uvimage; i++) {
- if (all_uv_layers || active_uv_layer == i)
- {
- if (me->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data;
- MPoly *mpoly = me->mpoly;
- for (int j = 0; j < me->totpoly; j++, mpoly++, txface++) {
-
- Image *ima = txface->tpage;
- if (ima != NULL) {
- if (UVImages.find(ima) == UVImages.end())
- UVImages.insert(ima);
- }
- }
- }
+ bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
+ bNode *inputGroup = ntreeFindType(ntree, NODE_GROUP_INPUT);
+ node_group_input_verify(ntree, inputGroup, (ID *)ntree);
+ bNodeSocket *newsock = node_group_input_find_socket(inputGroup, gsock->identifier);
+ nodeAddLink(ntree, inputGroup, newsock, to_node, to_socket);
+ strcpy(newsock->name, label.c_str());
+ return newsock;
+}
+
+static bNodeSocket *bc_group_add_output_socket(bNodeTree *ntree, bNode *from_node, int from_index, std::string label)
+{
+ bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
+
+ //bNodeSocket *socket = ntreeAddSocketInterfaceFromSocket(ntree, to_node, to_socket);
+ //return socket;
+
+ bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(ntree, from_node, from_socket);
+ bNode *outputGroup = ntreeFindType(ntree, NODE_GROUP_OUTPUT);
+ node_group_output_verify(ntree, outputGroup, (ID *)ntree);
+ bNodeSocket *newsock = node_group_output_find_socket(outputGroup, gsock->identifier);
+ nodeAddLink(ntree, from_node, from_socket, outputGroup, newsock);
+ strcpy(newsock->name, label.c_str());
+ return newsock;
+}
+
+
+void bc_make_group(bContext *C, bNodeTree *ntree, std::map<std::string, bNode *> nmap)
+{
+ bNode * gnode = node_group_make_from_selected(C, ntree, "ShaderNodeGroup", "ShaderNodeTree");
+ bNodeTree *gtree = (bNodeTree *)gnode->id;
+
+ bc_group_add_input_socket(gtree, nmap["main"], 0, "Diffuse");
+ bc_group_add_input_socket(gtree, nmap["emission"], 0, "Emission");
+ bc_group_add_input_socket(gtree, nmap["mix"], 0, "Transparency");
+ bc_group_add_input_socket(gtree, nmap["emission"], 1, "Emission");
+ bc_group_add_input_socket(gtree, nmap["main"], 4, "Metallic");
+ bc_group_add_input_socket(gtree, nmap["main"], 5, "Specular");
+
+ bc_group_add_output_socket(gtree, nmap["mix"], 0, "Shader");
+}
+#endif
+
+static void bc_node_add_link(bNodeTree *ntree, bNode *from_node, int from_index, bNode *to_node, int to_index)
+{
+ bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index);
+ bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index);
+
+ nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
+}
+
+void bc_add_default_shader(bContext *C, Material *ma)
+{
+ bNodeTree *ntree = prepare_material_nodetree(ma);
+ std::map<std::string, bNode *> nmap;
+#if 0
+ nmap["main"] = bc_add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300);
+ nmap["emission"] = bc_add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission");
+ nmap["add"] = bc_add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400);
+ nmap["transparent"] = bc_add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200);
+ nmap["mix"] = bc_add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency");
+ nmap["out"] = bc_add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300);
+ nmap["out"]->flag &= ~NODE_SELECT;
+
+ bc_node_add_link(ntree, nmap["emission"], 0, nmap["add"], 0);
+ bc_node_add_link(ntree, nmap["main"], 0, nmap["add"], 1);
+ bc_node_add_link(ntree, nmap["add"], 0, nmap["mix"], 1);
+ bc_node_add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2);
+
+ bc_node_add_link(ntree, nmap["mix"], 0, nmap["out"], 0);
+ // experimental, probably not used.
+ bc_make_group(C, ntree, nmap);
+#else
+nmap["main"] = bc_add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, 0, 300);
+nmap["out"] = bc_add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 300, 300);
+bc_node_add_link(ntree, nmap["main"], 0, nmap["out"], 0);
+#endif
+}
+
+COLLADASW::ColorOrTexture bc_get_base_color(Material *ma)
+{
+ bNode *master_shader = bc_get_master_shader(ma);
+ if (master_shader) {
+ return bc_get_base_color(master_shader);
+ }
+ else {
+ return bc_get_cot(ma->r, ma->g, ma->b, ma->alpha);
+ }
+}
+
+COLLADASW::ColorOrTexture bc_get_specular_color(Material *ma, bool use_fallback)
+{
+ bNode *master_shader = bc_get_master_shader(ma);
+ if (master_shader) {
+ return bc_get_specular_color(master_shader);
+ }
+ else if (use_fallback) {
+ return bc_get_cot(ma->specr * ma->spec, ma->specg * ma->spec, ma->specb * ma->spec, 1.0f);
+ }
+ else {
+ return bc_get_cot(0.0, 0.0, 0.0, 1.0); // no specular
+ }
+}
+
+COLLADASW::ColorOrTexture bc_get_base_color(bNode *shader)
+{
+ bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, "Base Color");
+ if (socket)
+ {
+ bNodeSocketValueRGBA *dcol = (bNodeSocketValueRGBA *)socket->default_value;
+ float* col = dcol->value;
+ return bc_get_cot(col[0], col[1], col[2], col[3]);
+ }
+ else {
+ return bc_get_cot(0.8, 0.8, 0.8, 1.0); //default white
+ }
+}
+
+COLLADASW::ColorOrTexture bc_get_specular_color(bNode *shader)
+{
+ bNodeSocket *socket = nodeFindSocket(shader, SOCK_IN, "Specular");
+ if (socket)
+ {
+ bNodeSocketValueRGBA *dcol = (bNodeSocketValueRGBA *)socket->default_value;
+ float* col = dcol->value;
+ return bc_get_cot(col[0], col[1], col[2], col[3]);
+ }
+ else {
+ return bc_get_cot(0.8, 0.8, 0.8, 1.0); //default white
+ }
+}
+
+bNode *bc_get_master_shader(Material *ma)
+{
+ bNodeTree *nodetree = ma->nodetree;
+ if (nodetree) {
+ for (bNode *node = (bNode *)nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->type == SH_NODE_BSDF_PRINCIPLED) {
+ return node;
}
}
}
- return UVImages;
+ return NULL;
+}
+
+COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a)
+{
+ COLLADASW::Color color(r, g, b, a);
+ COLLADASW::ColorOrTexture cot(color);
+ return cot;
}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index d1591a34cce..a79085f0282 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -31,6 +31,9 @@
#include "COLLADAFWGeometry.h"
#include "COLLADAFWFloatOrDoubleArray.h"
#include "COLLADAFWTypes.h"
+#include "COLLADASWEffectProfile.h"
+#include "COLLADAFWColorOrTexture.h"
+
#include <vector>
#include <map>
@@ -39,7 +42,12 @@
extern "C" {
#include "DNA_object_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_constraint_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_camera_types.h"
+
#include "DNA_customdata_types.h"
#include "DNA_texture_types.h"
#include "DNA_scene_types.h"
@@ -50,33 +58,97 @@ extern "C" {
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BKE_main.h"
#include "BKE_context.h"
#include "BKE_object.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_scene.h"
#include "BKE_idprop.h"
+#include "BKE_node.h"
}
+#include "DEG_depsgraph_query.h"
+
#include "ImportSettings.h"
#include "ExportSettings.h"
#include "collada_internal.h"
+#include "BCSampleData.h"
+#include "BlenderContext.h"
+constexpr int LIMITTED_PRECISION = 6;
+
+struct Depsgraph;
+
+typedef std::map<COLLADAFW::UniqueId, Image*> UidImageMap;
+typedef std::map<std::string, Image*> KeyImageMap;
typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex *> > TexIndexTextureArrayMap;
+typedef std::set<Object *> BCObjectSet;
+
+extern void bc_update_scene(BlenderContext &blender_context, float ctime);
+
+/* Action helpers */
+
+std::vector<bAction *> bc_getSceneActions(const bContext *C, Object *ob, bool all_actions);
+
+/* Action helpers */
+
+inline bAction *bc_getSceneObjectAction(Object *ob)
+{
+ return (ob->adt && ob->adt->action) ? ob->adt->action : NULL;
+}
+
+/* Returns Lamp Action or NULL */
+inline bAction *bc_getSceneLampAction(Object *ob)
+{
+ if (ob->type != OB_LAMP)
+ return NULL;
+
+ Lamp *lamp = (Lamp *)ob->data;
+ return (lamp->adt && lamp->adt->action) ? lamp->adt->action : NULL;
+}
+
+/* Return Camera Action or NULL */
+inline bAction *bc_getSceneCameraAction(Object *ob)
+{
+ if (ob->type != OB_CAMERA)
+ return NULL;
+
+ Camera *camera = (Camera *)ob->data;
+ return (camera->adt && camera->adt->action) ? camera->adt->action : NULL;
+}
+
+/* returns material action or NULL */
+inline bAction *bc_getSceneMaterialAction(Material *ma)
+{
+ if (ma == NULL)
+ return NULL;
+
+ return (ma->adt && ma->adt->action) ? ma->adt->action : NULL;
+}
+
+inline void bc_setSceneObjectAction(bAction *action, Object *ob)
+{
+ if (ob->adt)
+ ob->adt->action = action;
+}
+
+std::string bc_get_action_id(std::string action_name, std::string ob_name, std::string channel_type, std::string axis_name, std::string axis_separator = "_");
-extern EvaluationContext *bc_get_evaluation_context(Main *bmain);
-extern void bc_update_scene(Main *bmain, Scene *scene, float ctime);
extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index);
extern int bc_test_parent_loop(Object *par, Object *ob);
+
+extern void bc_get_children(std::vector<Object *> &child_set, Object *ob, ViewLayer *view_layer);
+extern bool bc_validateConstraints(bConstraint *con);
+
extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space = true);
-extern Object *bc_add_object(Main *bmain, Scene *scene, int type, const char *name);
+extern Object *bc_add_object(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name);
extern Mesh *bc_get_mesh_copy(
- Main *bmain, Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate);
+ BlenderContext &blender_context, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate);
extern Object *bc_get_assigned_armature(Object *ob);
extern Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob);
extern bool bc_is_base_node(LinkNode *export_set, Object *ob);
-extern bool bc_is_in_Export_set(LinkNode *export_set, Object *ob);
+extern bool bc_is_in_Export_set(LinkNode *export_set, Object *ob, ViewLayer *view_layer);
extern bool bc_has_object_type(LinkNode *export_set, short obtype);
extern int bc_is_marked(Object *ob);
@@ -90,6 +162,30 @@ extern void bc_bubble_sort_by_Object_name(LinkNode *export_set);
extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only);
extern int bc_get_active_UVLayer(Object *ob);
+std::string bc_find_bonename_in_path(std::string path, std::string probe);
+
+inline std::string bc_string_after(const std::string& s, const char c)
+{
+ size_t i = s.rfind(c, s.length());
+ if (i != std::string::npos) {
+ return(s.substr(i + 1, s.length() - i));
+ }
+ return(s);
+}
+
+inline bool bc_startswith(std::string const & value, std::string const & starting)
+{
+ if (starting.size() > value.size())
+ return false;
+ return (value.substr(0, starting.size()) == starting);
+}
+
+inline bool bc_endswith(std::string const & value, std::string const & ending)
+{
+ if (ending.size() > value.size()) return false;
+ return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
+}
+
extern std::string bc_replace_string(std::string data, const std::string& pattern, const std::string& replacement);
extern std::string bc_url_encode(std::string data);
extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene);
@@ -109,9 +205,14 @@ inline bool bc_in_range(float a, float b, float range) {
}
void bc_copy_m4_farray(float r[4][4], float *a);
void bc_copy_farray_m4(float *r, float a[4][4]);
+void bc_copy_darray_m4d(double *r, double a[4][4]);
+void bc_copy_m4d_v44(double(&r)[4][4], std::vector<std::vector<double>> &a);
+void bc_copy_v44_m4d(std::vector<std::vector<double>> &a, double(&r)[4][4]);
-extern void bc_sanitize_mat(float mat[4][4], int precision);
-extern void bc_sanitize_mat(double mat[4][4], int precision);
+void bc_sanitize_mat(float mat[4][4], int precision);
+void bc_sanitize_mat(double mat[4][4], int precision);
+void bc_sanitize_v3(double v[3], int precision);
+void bc_sanitize_v3(float v[3], int precision);
extern IDProperty *bc_get_IDProperty(Bone *bone, std::string key);
extern void bc_set_IDProperty(EditBone *ebone, const char *key, float value);
@@ -121,15 +222,14 @@ extern float bc_get_property(Bone *bone, std::string key, float def);
extern void bc_get_property_vector(Bone *bone, std::string key, float val[3], const float def[3]);
extern bool bc_get_property_matrix(Bone *bone, std::string key, float mat[4][4]);
-extern void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float world[4][4], bool use_local_space);
+extern void bc_enable_fcurves(bAction *act, char *bone_name);
+extern bool bc_bone_matrix_local_get(Object *ob, Bone *bone, Matrix &mat, bool for_opensim);
+extern bool bc_is_animated(BCMatrixSampleMap &values);
+extern bool bc_has_animations(Scene *sce, LinkNode &node);
+extern bool bc_has_animations(Object *ob);
-extern std::string bc_get_active_uvlayer_name(Object *ob);
-extern std::string bc_get_active_uvlayer_name(Mesh *me);
-extern std::string bc_get_uvlayer_name(Mesh *me, int layer);
-extern std::set<Image *> bc_getUVImages(Scene *sce, bool all_uv_layers);
-extern std::set<Image *> bc_getUVImages(Object *ob, bool all_uv_layers);
-extern std::set<Object *> bc_getUVTexturedObjects(Scene *sce, bool all_uv_layers);
+extern void bc_create_restpose_mat(const ExportSettings *export_settings, Bone *bone, float to_mat[4][4], float world[4][4], bool use_local_space);
class BCPolygonNormalsIndices
{
@@ -210,4 +310,12 @@ public:
~BoneExtensionManager();
};
+void bc_add_default_shader(bContext *C, Material *ma);
+bNode *bc_get_master_shader(Material *ma);
+COLLADASW::ColorOrTexture bc_get_cot(float r, float g, float b, float a);
+COLLADASW::ColorOrTexture bc_get_base_color(bNode *shader);
+COLLADASW::ColorOrTexture bc_get_base_color(Material *ma);
+COLLADASW::ColorOrTexture bc_get_specular_color(bNode *shader);
+COLLADASW::ColorOrTexture bc_get_specular_color(Material *ma, bool use_fallback);
+
#endif
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 0ad53d3ab80..261a1218d2d 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../blenkernel
../blenlib
../blentranslation
+ ../depsgraph
../imbuf
../makesdna
../makesrna
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index e3fb50828e8..53029b037f1 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -78,7 +78,7 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
int framenumber = context.getFramenumber();
int numberOfOutputs = this->getNumberOfOutputSockets();
bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0;
- BKE_image_user_frame_calc(imageuser, context.getFramenumber(), 0);
+ BKE_image_user_frame_calc(imageuser, context.getFramenumber());
/* force a load, we assume iuser index will be set OK anyway */
if (image && image->type == IMA_TYPE_MULTILAYER) {
bool is_multilayer_ok = false;
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
index 6d3dd22f1bd..59e09b8427b 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
@@ -65,12 +65,12 @@ void RenderLayersNode::testRenderLink(NodeConverter &converter,
missingRenderLink(converter);
return;
}
- SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId);
- if (srl == NULL) {
+ ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, layerId);
+ if (view_layer == NULL) {
missingRenderLink(converter);
return;
}
- RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
+ RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name);
if (rl == NULL) {
missingRenderLink(converter);
return;
@@ -157,6 +157,11 @@ void RenderLayersNode::missingSocketLink(NodeConverter &converter,
operation = value_operation;
break;
}
+ default:
+ {
+ BLI_assert("!Unexpected data type");
+ return;
+ }
}
converter.mapOutputSocket(output, operation->getOutputSocket());
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
index c52d50bdb8c..6529b533361 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
@@ -26,12 +26,13 @@
#include "COM_OutputFileMultiViewOperation.h"
#include <string.h>
+
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
-#include "BKE_image.h"
+
#include "BKE_global.h"
-#include "BKE_library.h"
+#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_scene.h"
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index e73f2e46fb9..0397d172ab3 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -22,13 +22,15 @@
*/
#include "COM_OutputFileOperation.h"
+
#include <string.h>
+
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
-#include "BKE_image.h"
+
#include "BKE_global.h"
-#include "BKE_library.h"
+#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_scene.h"
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 2388e9e3302..58ea2ffe38b 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -55,10 +55,10 @@ void RenderLayersProg::initExecution()
rr = RE_AcquireResultRead(re);
if (rr) {
- SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, getLayerId());
- if (srl) {
+ ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId());
+ if (view_layer) {
- RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
+ RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name);
if (rl) {
this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_passName.c_str(), this->m_viewName);
}
@@ -189,9 +189,9 @@ void RenderLayersProg::determineResolution(unsigned int resolution[2], unsigned
rr = RE_AcquireResultRead(re);
if (rr) {
- SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&sce->r.layers, getLayerId());
- if (srl) {
- RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
+ ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&sce->view_layers, getLayerId());
+ if (view_layer) {
+ RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name);
if (rl) {
resolution[0] = rl->rectx;
resolution[1] = rl->recty;
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
index 5a05d14087f..f1746323d78 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
@@ -26,6 +26,7 @@ extern "C" {
# include "BLI_math.h"
# include "BLI_utildefines.h"
# include "BLI_rand.h"
+# include "PIL_time.h"
}
ScreenLensDistortionOperation::ScreenLensDistortionOperation() : NodeOperation()
@@ -60,6 +61,10 @@ void ScreenLensDistortionOperation::initExecution()
this->m_inputProgram = this->getInputSocketReader(0);
this->initMutex();
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= (uint)POINTER_AS_INT(m_inputProgram);
+ this->m_rng = BLI_rng_new(rng_seed);
+
this->m_cx = 0.5f * (float)getWidth();
this->m_cy = 0.5f * (float)getHeight();
@@ -142,7 +147,7 @@ void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer,
float dk4 = m_dk4[a];
for (float z = 0; z < ds; ++z) {
- float tz = (z + (m_jitter ? BLI_frand() : 0.5f)) * sd;
+ float tz = (z + (m_jitter ? BLI_rng_get_float(m_rng) : 0.5f)) * sd;
float t = 1.0f - (k4 + tz * dk4) * r_sq;
float xy[2];
@@ -192,6 +197,7 @@ void ScreenLensDistortionOperation::deinitExecution()
{
this->deinitMutex();
this->m_inputProgram = NULL;
+ BLI_rng_free(this->m_rng);
}
void ScreenLensDistortionOperation::determineUV(float result[6], float x, float y) const
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
index 2e1343694cc..654acc177d8 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h
@@ -31,6 +31,7 @@ private:
* Cached reference to the inputProgram
*/
SocketReader *m_inputProgram;
+ struct RNG *m_rng;
bool m_fit;
bool m_jitter;
diff --git a/source/blender/datatoc/datatoc_icon_split.py b/source/blender/datatoc/datatoc_icon_split.py
index 399d7df4d8d..44fedca4398 100755
--- a/source/blender/datatoc/datatoc_icon_split.py
+++ b/source/blender/datatoc/datatoc_icon_split.py
@@ -128,21 +128,27 @@ def dice_icon_name(
# Init on demand
if not _dice_icon_name_cache:
import re
+ count = 0
# Search for eg: DEF_ICON(BRUSH_NUDGE) --> BRUSH_NUDGE
- re_icon = re.compile(r'^\s*DEF_ICON\(\s*([A-Za-z0-9_]+)\s*\).*$')
+ re_icon = re.compile(r'^\s*DEF_ICON.*\(\s*([A-Za-z0-9_]+)\s*\).*$')
ui_icons_h = os.path.join(SOURCE_DIR, "source", "blender", "editors", "include", "UI_icons.h")
with open(ui_icons_h, 'r', encoding="utf-8") as f:
for l in f:
match = re_icon.search(l)
if match:
- icon_name = match.group(1).lower()
- # print(l.rstrip())
- _dice_icon_name_cache[len(_dice_icon_name_cache)] = icon_name
+ if l.find('DEF_ICON_BLANK') == -1:
+ icon_name = match.group(1).lower()
+ print(icon_name)
+ _dice_icon_name_cache[count] = icon_name
+ count += 1
# ---- Done with icon cache
index = (y * parts_x) + x
+ if index not in _dice_icon_name_cache:
+ return None
+
icon_name = _dice_icon_name_cache[index]
# for debugging its handy to sort by number
@@ -209,6 +215,9 @@ def dice(
parts_x, parts_y,
name_style=name_style, prefix=output_prefix
)
+ if not id_str:
+ continue
+
filepath = os.path.join(output, id_str)
if VERBOSE:
print(" writing:", filepath)
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index ced045e9e2f..884f1d272a5 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../blenkernel
../blenlib
../bmesh
+ ../draw
../makesdna
../makesrna
../modifiers
@@ -45,16 +46,17 @@ set(SRC
intern/builder/deg_builder_map.cc
intern/builder/deg_builder_nodes.cc
intern/builder/deg_builder_nodes_rig.cc
- intern/builder/deg_builder_nodes_scene.cc
+ intern/builder/deg_builder_nodes_view_layer.cc
intern/builder/deg_builder_pchanmap.cc
intern/builder/deg_builder_relations.cc
intern/builder/deg_builder_relations_keys.cc
intern/builder/deg_builder_relations_rig.cc
- intern/builder/deg_builder_relations_scene.cc
+ intern/builder/deg_builder_relations_view_layer.cc
intern/builder/deg_builder_transitive.cc
intern/debug/deg_debug_relations_graphviz.cc
intern/debug/deg_debug_stats_gnuplot.cc
intern/eval/deg_eval.cc
+ intern/eval/deg_eval_copy_on_write.cc
intern/eval/deg_eval_flush.cc
intern/eval/deg_eval_stats.cc
intern/nodes/deg_node.cc
@@ -66,14 +68,18 @@ set(SRC
intern/depsgraph_build.cc
intern/depsgraph_debug.cc
intern/depsgraph_eval.cc
+ intern/depsgraph_physics.cc
intern/depsgraph_query.cc
+ intern/depsgraph_query_filter.cc
intern/depsgraph_query_foreach.cc
+ intern/depsgraph_query_iter.cc
intern/depsgraph_tag.cc
intern/depsgraph_type_defines.cc
DEG_depsgraph.h
DEG_depsgraph_build.h
DEG_depsgraph_debug.h
+ DEG_depsgraph_physics.h
DEG_depsgraph_query.h
intern/builder/deg_builder.h
@@ -85,6 +91,7 @@ set(SRC
intern/builder/deg_builder_relations_impl.h
intern/builder/deg_builder_transitive.h
intern/eval/deg_eval.h
+ intern/eval/deg_eval_copy_on_write.h
intern/eval/deg_eval_flush.h
intern/eval/deg_eval_stats.h
intern/nodes/deg_node.h
@@ -100,10 +107,6 @@ set(SRC
util/deg_util_function.h
)
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
-endif()
-
if(WITH_BOOST)
list(APPEND INC_SYS
${BOOST_INCLUDE_DIR}
@@ -111,8 +114,4 @@ if(WITH_BOOST)
add_definitions(-DHAVE_BOOST_FUNCTION_BINDINGS)
endif()
-if(WITH_OPENSUBDIV)
- add_definitions(-DWITH_OPENSUBDIV)
-endif()
-
blender_add_lib(bf_depsgraph "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index d9672732ffc..c87ba188677 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -60,20 +60,36 @@ typedef struct Depsgraph Depsgraph;
/* ------------------------------------------------ */
-struct EvaluationContext;
struct Main;
struct PointerRNA;
struct PropertyRNA;
+struct RenderEngineType;
+struct Scene;
+struct ViewLayer;
+
+typedef enum eEvaluationMode {
+ DAG_EVAL_VIEWPORT = 0, /* evaluate for OpenGL viewport */
+ DAG_EVAL_RENDER = 1, /* evaluate for render purposes */
+} eEvaluationMode;
+
+/* DagNode->eval_flags */
+enum {
+ /* Regardless to curve->path animation flag path is to be evaluated anyway,
+ * to meet dependencies with such a things as curve modifier and other guys
+ * who're using curve deform, where_on_path and so.
+ */
+ DAG_EVAL_NEED_CURVE_PATH = (1 << 0),
+ /* A shrinkwrap modifier or constraint targeting this mesh needs information
+ * about non-manifold boundary edges for the Target Normal Project mode.
+ */
+ DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY = (1 << 1),
+};
#ifdef __cplusplus
extern "C" {
#endif
-bool DEG_depsgraph_use_legacy(void);
-void DEG_depsgraph_switch_to_legacy(void);
-void DEG_depsgraph_switch_to_new(void);
-
/* ************************************************ */
/* Depsgraph API */
@@ -83,7 +99,9 @@ void DEG_depsgraph_switch_to_new(void);
/* Create new Depsgraph instance */
// TODO: what args are needed here? What's the building-graph entry point?
-Depsgraph *DEG_graph_new(void);
+Depsgraph *DEG_graph_new(struct Scene *scene,
+ struct ViewLayer *view_layer,
+ eEvaluationMode mode);
/* Free Depsgraph itself and all its data */
void DEG_graph_free(Depsgraph *graph);
@@ -98,92 +116,93 @@ void DEG_free_node_types(void);
/* Update Tagging -------------------------------- */
-/* Tag node(s) associated with states such as time and visibility */
-void DEG_scene_update_flags(Depsgraph *graph, const bool do_time);
-
/* Update dependency graph when visible scenes/layers changes. */
-void DEG_graph_on_visible_update(struct Main *bmain, struct Scene *scene);
+void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph);
/* Update all dependency graphs when visible scenes/layers changes. */
void DEG_on_visible_update(struct Main *bmain, const bool do_time);
-/* Tag node(s) associated with changed data for later updates */
-void DEG_graph_id_tag_update(struct Main *bmain,
- Depsgraph *graph,
- struct ID *id);
-
/* Tag given ID for an update in all the dependency graphs. */
-void DEG_id_tag_update(struct ID *id, short flag);
-void DEG_id_tag_update_ex(struct Main *bmain,
- struct ID *id,
- short flag);
+typedef enum eDepsgraph_Tag {
+ /* Object transformation changed, corresponds to OB_RECALC_OB. */
+ DEG_TAG_TRANSFORM = (1 << 0),
+ /* Object geometry changed, corresponds to OB_RECALC_DATA. */
+ DEG_TAG_GEOMETRY = (1 << 1),
+ /* Time changed and animation is to be re-evaluated, OB_RECALC_TIME. */
+ DEG_TAG_TIME = (1 << 2),
+ /* Particle system changed; values are aligned with PSYS_RECALC_xxx. */
+ DEG_TAG_PSYS_REDO = (1 << 3),
+ DEG_TAG_PSYS_RESET = (1 << 4),
+ DEG_TAG_PSYS_TYPE = (1 << 5),
+ DEG_TAG_PSYS_CHILD = (1 << 6),
+ DEG_TAG_PSYS_PHYS = (1 << 7),
+ DEG_TAG_PSYS_ALL = (DEG_TAG_PSYS_REDO |
+ DEG_TAG_PSYS_RESET |
+ DEG_TAG_PSYS_TYPE |
+ DEG_TAG_PSYS_CHILD |
+ DEG_TAG_PSYS_PHYS),
+ /* Update copy on write component without flushing down the road. */
+ DEG_TAG_COPY_ON_WRITE = (1 << 8),
+ /* Tag shading components for update.
+ * Only parameters of material changed).
+ */
+ DEG_TAG_SHADING_UPDATE = (1 << 9),
+ DEG_TAG_SELECT_UPDATE = (1 << 10),
+ DEG_TAG_BASE_FLAGS_UPDATE = (1 << 11),
+ DEG_TAG_POINT_CACHE_UPDATE = (1 << 12),
+ /* Only inform editors about the change. Don't modify datablock itself. */
+ DEG_TAG_EDITORS_UPDATE = (1 << 13),
+} eDepsgraph_Tag;
+
+const char *DEG_update_tag_as_string(eDepsgraph_Tag flag);
+
+void DEG_id_tag_update(struct ID *id, int flag);
+void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag);
+
+void DEG_graph_id_tag_update(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ struct ID *id,
+ int flag);
/* Mark a particular datablock type as having changing. This does
* not cause any updates but is used by external render engines to detect if for
* example a datablock was removed.
*/
-void DEG_id_type_tag(struct Main *bmain, short idtype);
+void DEG_id_type_tag(struct Main *bmain, short id_type);
-void DEG_ids_clear_recalc(struct Main *bmain);
+void DEG_ids_clear_recalc(struct Main *bmain, Depsgraph *depsgraph);
/* Update Flushing ------------------------------- */
-/* Flush updates for all IDs */
-void DEG_ids_flush_tagged(struct Main *bmain);
-
/* Flush updates for IDs in a single scene. */
-void DEG_scene_flush_update(struct Main *bmain, struct Scene *scene);
+void DEG_graph_flush_update(struct Main *bmain, Depsgraph *depsgraph);
/* Check if something was changed in the database and inform
* editors about this.
*/
void DEG_ids_check_recalc(struct Main *bmain,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
+ struct ViewLayer *view_layer,
bool time);
/* ************************************************ */
/* Evaluation Engine API */
-/* Evaluation Context ---------------------------- */
-
-/* Create new evaluation context. */
-struct EvaluationContext *DEG_evaluation_context_new(int mode);
-
-/* Initialize evaluation context.
- * Used by the areas which currently overrides the context or doesn't have
- * access to a proper one.
- */
-void DEG_evaluation_context_init(struct EvaluationContext *eval_ctx, int mode);
-
-/* Free evaluation context. */
-void DEG_evaluation_context_free(struct EvaluationContext *eval_ctx);
-
/* Graph Evaluation ----------------------------- */
/* Frame changed recalculation entry point
* < context_type: context to perform evaluation for
* < ctime: (frame) new frame to evaluate values on
*/
-void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
- struct Main *bmain,
+void DEG_evaluate_on_framechange(struct Main *bmain,
Depsgraph *graph,
- float ctime,
- const unsigned int layer);
+ float ctime);
/* Data changed recalculation entry point.
* < context_type: context to perform evaluation for
- * < layers: visible layers bitmask to update the graph for
*/
-void DEG_evaluate_on_refresh_ex(struct EvaluationContext *eval_ctx,
- Depsgraph *graph,
- const unsigned int layers);
-
-/* Data changed recalculation entry point.
- * < context_type: context to perform evaluation for
- */
-void DEG_evaluate_on_refresh(struct EvaluationContext *eval_ctx,
- Depsgraph *graph,
- struct Scene *scene);
+void DEG_evaluate_on_refresh(Depsgraph *graph);
bool DEG_needs_eval(Depsgraph *graph);
@@ -193,35 +212,48 @@ bool DEG_needs_eval(Depsgraph *graph);
* to do their own updates based on changes.
*/
-typedef void (*DEG_EditorUpdateIDCb)(struct Main *bmain, struct ID *id);
-typedef void (*DEG_EditorUpdateSceneCb)(struct Main *bmain,
- struct Scene *scene,
- int updated);
-typedef void (*DEG_EditorUpdateScenePreCb)(struct Main *bmain,
- struct Scene *scene,
- bool time);
+typedef struct DEGEditorUpdateContext {
+ struct Main *bmain;
+ struct Depsgraph *depsgraph;
+ struct Scene *scene;
+ struct ViewLayer *view_layer;
+} DEGEditorUpdateContext;
+
+typedef void (*DEG_EditorUpdateIDCb)(
+ const DEGEditorUpdateContext *update_ctx,
+ struct ID *id);
+typedef void (*DEG_EditorUpdateSceneCb)(
+ const DEGEditorUpdateContext *update_ctx, int updated);
/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
- DEG_EditorUpdateSceneCb scene_func,
- DEG_EditorUpdateScenePreCb scene_pre_func);
+ DEG_EditorUpdateSceneCb scene_func);
-void DEG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time);
+/* Evaluation ----------------------------------- */
+
+bool DEG_is_active(const struct Depsgraph *depsgraph);
+void DEG_make_active(struct Depsgraph *depsgraph);
+void DEG_make_inactive(struct Depsgraph *depsgraph);
/* Evaluation Debug ------------------------------ */
-void DEG_debug_print_eval(const char* function_name,
- const char* object_name,
- const void* object_address);
+void DEG_debug_print_begin(struct Depsgraph *depsgraph);
+
+void DEG_debug_print_eval(struct Depsgraph *depsgraph,
+ const char *function_name,
+ const char *object_name,
+ const void *object_address);
-void DEG_debug_print_eval_subdata(const char *function_name,
+void DEG_debug_print_eval_subdata(struct Depsgraph *depsgraph,
+ const char *function_name,
const char *object_name,
const void *object_address,
const char *subdata_comment,
const char *subdata_name,
const void *subdata_address);
-void DEG_debug_print_eval_subdata_index(const char *function_name,
+void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph,
+ const char *function_name,
const char *object_name,
const void *object_address,
const char *subdata_comment,
@@ -229,9 +261,18 @@ void DEG_debug_print_eval_subdata_index(const char *function_name,
const void *subdata_address,
const int subdata_index);
-void DEG_debug_print_eval_time(const char* function_name,
- const char* object_name,
- const void* object_address,
+void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph,
+ const char *function_name,
+ const char *object_name,
+ const void *object_address,
+ const char *parent_comment,
+ const char *parent_name,
+ const void *parent_address);
+
+void DEG_debug_print_eval_time(struct Depsgraph *depsgraph,
+ const char *function_name,
+ const char *object_name,
+ const void *object_address,
float time);
#ifdef __cplusplus
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index b268822f659..93e9b5be2cc 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -40,44 +40,43 @@ struct Depsgraph;
/* ------------------------------------------------ */
-struct Main;
-struct Scene;
-struct Group;
+struct CacheFile;
struct EffectorWeights;
+struct Collection;
+struct Main;
struct ModifierData;
struct Object;
+struct Scene;
+struct ViewLayer;
#ifdef __cplusplus
extern "C" {
#endif
+#include "BLI_sys_types.h"
+
/* Graph Building -------------------------------- */
/* Build depsgraph for the given scene, and dump results in given
* graph container.
*/
-void DEG_graph_build_from_scene(struct Depsgraph *graph,
- struct Main *bmain,
- struct Scene *scene);
+void DEG_graph_build_from_view_layer(struct Depsgraph *graph,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
/* Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
+/* Create or update relations in the specified graph. */
+void DEG_graph_relations_update(struct Depsgraph *graph,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
+
/* Tag all relations in the database for update.*/
void DEG_relations_tag_update(struct Main *bmain);
-/* Create new graph if didn't exist yet,
- * or update relations if graph was tagged for update.
- */
-void DEG_scene_relations_update(struct Main *bmain, struct Scene *scene);
-
-/* Rebuild dependency graph only for a given scene. */
-void DEG_scene_relations_rebuild(struct Main *bmain,
- struct Scene *scene);
-
-/* Delete scene graph. */
-void DEG_scene_graph_free(struct Scene *scene);
-
/* Add Dependencies ----------------------------- */
/* Handle for components to define their dependencies from callbacks.
@@ -87,9 +86,6 @@ void DEG_scene_graph_free(struct Scene *scene);
*/
struct DepsNodeHandle;
-struct CacheFile;
-struct Object;
-
typedef enum eDepsSceneComponentType {
/* Parameters Component - Default when nothing else fits
* (i.e. just SDNA property setting).
@@ -119,7 +115,7 @@ typedef enum eDepsObjectComponentType {
DEG_OB_COMP_ANIMATION,
/* Transform Component (Parenting/Constraints) */
DEG_OB_COMP_TRANSFORM,
- /* Geometry Component (DerivedMesh/Displist) */
+ /* Geometry Component (Mesh/Displist) */
DEG_OB_COMP_GEOMETRY,
/* Evaluation-Related Outer Types (with Subdata) */
@@ -129,22 +125,25 @@ typedef enum eDepsObjectComponentType {
/* Bone Component - Child/Subcomponent of Pose */
DEG_OB_COMP_BONE,
- /* Particle Systems Component */
- DEG_OB_COMP_EVAL_PARTICLES,
/* Material Shading Component */
DEG_OB_COMP_SHADING,
/* Cache Component */
DEG_OB_COMP_CACHE,
} eDepsObjectComponentType;
-void DEG_add_scene_relation(struct DepsNodeHandle *node,
+void DEG_add_scene_relation(struct DepsNodeHandle *node_handle,
struct Scene *scene,
eDepsSceneComponentType component,
const char *description);
-void DEG_add_object_relation(struct DepsNodeHandle *node,
+void DEG_add_object_relation(struct DepsNodeHandle *node_handle,
struct Object *object,
eDepsObjectComponentType component,
const char *description);
+void DEG_add_object_relation_with_customdata(struct DepsNodeHandle *node_handle,
+ struct Object *object,
+ eDepsObjectComponentType component,
+ uint64_t customdata_mask,
+ const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle,
struct Object *object,
const char *bone_name,
@@ -155,29 +154,18 @@ void DEG_add_object_cache_relation(struct DepsNodeHandle *handle,
eDepsObjectComponentType component,
const char *description);
+/* Adds relations from the given component of a given object to the given node
+ * handle AND the component to the point cache component of the node's ID.
+ */
+void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle,
+ struct Object *object,
+ eDepsObjectComponentType component,
+ const char *description);
+
+void DEG_add_special_eval_flag(struct DepsNodeHandle *handle, struct ID *id, uint32_t flag);
-struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *handle);
-void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
-
-/* Utility functions for physics modifiers */
-typedef bool (*DEG_CollobjFilterFunction)(struct Object *obj, struct ModifierData *md);
-
-void DEG_add_collision_relations(struct DepsNodeHandle *handle,
- struct Scene *scene,
- struct Object *object,
- struct Group *group,
- int layer,
- unsigned int modifier_type,
- DEG_CollobjFilterFunction fn,
- bool dupli,
- const char *name);
-void DEG_add_forcefield_relations(struct DepsNodeHandle *handle,
- struct Scene *scene,
- struct Object *object,
- struct EffectorWeights *eff,
- bool add_absorption,
- int skip_forcefield,
- const char *name);
+struct ID *DEG_get_id_from_handle(struct DepsNodeHandle *node_handle);
+struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *node_handle);
/* ************************************************ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
index bc93fcc94cb..7c0f9ef3121 100644
--- a/source/blender/depsgraph/DEG_depsgraph_debug.h
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -40,6 +40,18 @@ extern "C" {
#endif
struct Depsgraph;
+struct Scene;
+struct ViewLayer;
+
+/* ------------------------------------------------ */
+
+/* NOTE: Those flags are same bitmask as G.debug_flags */
+
+void DEG_debug_flags_set(struct Depsgraph *depsgraph, int flags);
+int DEG_debug_flags_get(const struct Depsgraph *depsgraph);
+
+void DEG_debug_name_set(struct Depsgraph *depsgraph, const char *name);
+const char *DEG_debug_name_get(struct Depsgraph *depsgraph);
/* ------------------------------------------------ */
@@ -67,9 +79,10 @@ bool DEG_debug_compare(const struct Depsgraph *graph1,
const struct Depsgraph *graph2);
/* Check that dependnecies in the graph are really up to date. */
-bool DEG_debug_scene_relations_validate(struct Main *bmain,
- struct Scene *scene);
-
+bool DEG_debug_graph_relations_validate(struct Depsgraph *graph,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
/* Perform consistency check on the graph. */
bool DEG_debug_consistency_check(struct Depsgraph *graph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_physics.h b/source/blender/depsgraph/DEG_depsgraph_physics.h
new file mode 100644
index 00000000000..642b3cbfc30
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_physics.h
@@ -0,0 +1,85 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/DEG_depsgraph_physics.h
+ * \ingroup depsgraph
+ *
+ * Physics utilities for effectors and collision.
+ */
+
+#ifndef __DEG_DEPSGRAPH_PHYSICS_H__
+#define __DEG_DEPSGRAPH_PHYSICS_H__
+
+#include "DEG_depsgraph.h"
+
+struct Colllection;
+struct Depsgraph;
+struct DepsNodeHandle;
+struct EffectorWeights;
+struct ListBase;
+struct Object;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum ePhysicsRelationType {
+ DEG_PHYSICS_EFFECTOR = 0,
+ DEG_PHYSICS_COLLISION = 1,
+ DEG_PHYSICS_SMOKE_COLLISION = 2,
+ DEG_PHYSICS_DYNAMIC_BRUSH = 3,
+ DEG_PHYSICS_RELATIONS_NUM = 4
+} ePhysicsRelationType;
+
+/* Get collision/effector relations from collection or entire scene. These
+ * created during depsgraph relations building and should only be accessed
+ * during evaluation. */
+struct ListBase *DEG_get_effector_relations(const struct Depsgraph *depsgraph,
+ struct Collection *collection);
+struct ListBase *DEG_get_collision_relations(const struct Depsgraph *depsgraph,
+ struct Collection *collection,
+ unsigned int modifier_type);
+
+
+/* Build collision/effector relations for depsgraph. */
+typedef bool (*DEG_CollobjFilterFunction)(struct Object *obj,
+ struct ModifierData *md);
+
+void DEG_add_collision_relations(struct DepsNodeHandle *handle,
+ struct Object *object,
+ struct Collection *collection,
+ unsigned int modifier_type,
+ DEG_CollobjFilterFunction filter_function,
+ const char *name);
+void DEG_add_forcefield_relations(struct DepsNodeHandle *handle,
+ struct Object *object,
+ struct EffectorWeights *eff,
+ bool add_absorption,
+ int skip_forcefield,
+ const char *name);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_PHYSICS_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index f8cfb407831..e3fa30cf688 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -33,19 +33,163 @@
#ifndef __DEG_DEPSGRAPH_QUERY_H__
#define __DEG_DEPSGRAPH_QUERY_H__
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
struct ID;
+struct Base;
+struct BLI_Iterator;
struct Depsgraph;
+struct DupliObject;
+struct ListBase;
+struct Scene;
+struct ViewLayer;
#ifdef __cplusplus
extern "C" {
#endif
+/* *********************** DEG input data ********************* */
+
+/* Get scene that depsgraph was built for. */
+struct Scene *DEG_get_input_scene(const Depsgraph *graph);
+
+/* Get view layer that depsgraph was built for. */
+struct ViewLayer *DEG_get_input_view_layer(const Depsgraph *graph);
+
+/* Get evaluation mode that depsgraph was built for. */
+eEvaluationMode DEG_get_mode(const Depsgraph *graph);
+
+/* Get time that depsgraph is being evaluated or was last evaluated at. */
+float DEG_get_ctime(const Depsgraph *graph);
+
+/* ********************* DEG evaluated data ******************* */
+
/* Check if given ID type was tagged for update. */
-bool DEG_id_type_tagged(struct Main *bmain, short idtype);
+bool DEG_id_type_updated(const struct Depsgraph *depsgraph, short id_type);
+bool DEG_id_type_any_updated(const struct Depsgraph *depsgraph);
/* Get additional evaluation flags for the given ID. */
-short DEG_get_eval_flags_for_id(struct Depsgraph *graph, struct ID *id);
+uint32_t DEG_get_eval_flags_for_id(const struct Depsgraph *graph, struct ID *id);
+
+/* Get scene the despgraph is created for. */
+struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph);
+
+/* Get scene layer the despgraph is created for. */
+struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph);
+
+/* Get evaluated version of object for given original one. */
+struct Object *DEG_get_evaluated_object(const struct Depsgraph *depsgraph,
+ struct Object *object);
+
+/* Get evaluated version of given ID datablock. */
+struct ID *DEG_get_evaluated_id(const struct Depsgraph *depsgraph,
+ struct ID *id);
+
+/* Get evaluated version of data pointed to by RNA pointer */
+void DEG_get_evaluated_rna_pointer(const struct Depsgraph *depsgraph,
+ struct PointerRNA *ptr,
+ struct PointerRNA *r_ptr_eval);
+
+/* Get original version of object for given evaluated one. */
+struct Object *DEG_get_original_object(struct Object *object);
+
+/* Get original version of given evaluated ID datablock. */
+struct ID *DEG_get_original_id(struct ID *id);
+
+/* ************************ DEG object iterators ********************* */
+
+enum {
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY = (1 << 0),
+ DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY = (1 << 1),
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET = (1 << 2),
+ DEG_ITER_OBJECT_FLAG_VISIBLE = (1 << 3),
+ DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 4),
+};
+
+typedef struct DEGObjectIterData {
+ struct Depsgraph *graph;
+ int flag;
+
+ struct Scene *scene;
+
+ int visibility_check; /* eObjectVisibilityCheck. */
+
+ /* **** Iteration over dupli-list. *** */
+
+ /* Object which created the dupli-list. */
+ struct Object *dupli_parent;
+ /* List of duplicated objects. */
+ struct ListBase *dupli_list;
+ /* Next duplicated object to step into. */
+ struct DupliObject *dupli_object_next;
+ /* Corresponds to current object: current iterator object is evaluated from
+ * this duplicated object.
+ */
+ struct DupliObject *dupli_object_current;
+ /* Temporary storage to report fully populated DNA to the render engine or
+ * other users of the iterator.
+ */
+ struct Object temp_dupli_object;
+
+ /* **** Iteration over ID nodes **** */
+ size_t id_node_index;
+ size_t num_id_nodes;
+} DEGObjectIterData;
+
+void DEG_iterator_objects_begin(struct BLI_Iterator *iter, DEGObjectIterData *data);
+void DEG_iterator_objects_next(struct BLI_Iterator *iter);
+void DEG_iterator_objects_end(struct BLI_Iterator *iter);
+
+/**
+ * Note: Be careful with DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY objects.
+ * Although they are available they have no overrides (collection_properties)
+ * and will crash if you try to access it.
+ */
+#define DEG_OBJECT_ITER_BEGIN(graph_, instance_, flag_) \
+ { \
+ DEGObjectIterData data_ = { \
+ graph_, \
+ flag_ \
+ }; \
+ \
+ ITER_BEGIN(DEG_iterator_objects_begin, \
+ DEG_iterator_objects_next, \
+ DEG_iterator_objects_end, \
+ &data_, Object *, instance_)
+
+#define DEG_OBJECT_ITER_END \
+ ITER_END; \
+ }
+
+/**
+ * Depsgraph objects iterator for draw manager and final render
+ */
+#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(graph_, instance_) \
+ DEG_OBJECT_ITER_BEGIN(graph_, instance_, \
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | \
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | \
+ DEG_ITER_OBJECT_FLAG_VISIBLE | \
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+
+#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END \
+ DEG_OBJECT_ITER_END
+
+
+/* ************************ DEG ID iterators ********************* */
+
+typedef struct DEGIDIterData {
+ struct Depsgraph *graph;
+ bool only_updated;
+
+ size_t id_node_index;
+ size_t num_id_nodes;
+} DEGIDIterData;
+
+void DEG_iterator_ids_begin(struct BLI_Iterator *iter, DEGIDIterData *data);
+void DEG_iterator_ids_next(struct BLI_Iterator *iter);
+void DEG_iterator_ids_end(struct BLI_Iterator *iter);
/* ************************ DEG traversal ********************* */
@@ -54,10 +198,47 @@ typedef void (*DEGForeachIDCallback)(ID *id, void *user_data);
/* NOTE: Modifies runtime flags in depsgraph nodes, so can not be used in
* parallel. Keep an eye on that!
*/
+void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
+ const ID *id,
+ DEGForeachIDCallback callback, void *user_data);
void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
const ID *id,
DEGForeachIDCallback callback, void *user_data);
+void DEG_foreach_ID(const Depsgraph *depsgraph,
+ DEGForeachIDCallback callback, void *user_data);
+
+/* ********************* DEG graph filtering ****************** */
+
+/* ComponentKey for nodes we want to be able to evaluate in the filtered graph */
+typedef struct DEG_FilterTarget {
+ struct DEG_FilterTarget *next, *prev;
+
+ struct ID *id;
+ /* TODO: component identifiers - Component Type, Subdata/Component Name */
+} DEG_FilterTarget;
+
+typedef enum eDEG_FilterQuery_Granularity {
+ DEG_FILTER_NODES_ALL = 0,
+ DEG_FILTER_NODES_NO_OPS = 1,
+ DEG_FILTER_NODES_ID_ONLY = 2,
+} eDEG_FilterQuery_Granularity;
+
+
+typedef struct DEG_FilterQuery {
+ /* List of DEG_FilterTarget's */
+ struct ListBase targets;
+
+ /* Level of detail in the resulting graph */
+ eDEG_FilterQuery_Granularity detail_level;
+} DEG_FilterQuery;
+
+/* Obtain a new graph instance that only contains the subset of desired nodes
+ * WARNING: Do NOT pass an already filtered depsgraph through this function again,
+ * as we are currently unable to accurately recreate it.
+ */
+Depsgraph *DEG_graph_filter(const Depsgraph *depsgraph, struct Main *bmain, DEG_FilterQuery *query);
+
#ifdef __cplusplus
} /* extern "C" */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 5713297d658..f7b2b482b1f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -38,79 +38,80 @@
#include "BLI_ghash.h"
#include "BLI_stack.h"
+extern "C" {
+#include "BKE_animsys.h"
+}
+
#include "intern/depsgraph.h"
#include "intern/depsgraph_types.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node.h"
-#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_id.h"
+#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
#include "util/deg_util_foreach.h"
-#include <cstdio>
+#include "DEG_depsgraph.h"
namespace DEG {
-static bool check_object_needs_evaluation(Object *object)
-{
- if (object->recalc & OB_RECALC_ALL) {
- /* Object is tagged for update anyway, no need to re-tag it. */
- return false;
- }
- if (object->type == OB_MESH) {
- return object->derivedFinal == NULL;
- }
- else if (ELEM(object->type,
- OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE))
- {
- return object->curve_cache == NULL;
- }
- return false;
-}
+namespace {
-void deg_graph_build_flush_layers(Depsgraph *graph)
+void deg_graph_build_flush_visibility(Depsgraph *graph)
{
+ enum {
+ DEG_NODE_VISITED = (1 << 0),
+ };
+
BLI_Stack *stack = BLI_stack_new(sizeof(OperationDepsNode *),
"DEG flush layers stack");
- foreach (OperationDepsNode *node, graph->operations) {
- IDDepsNode *id_node = node->owner->owner;
- node->done = 0;
- node->num_links_pending = 0;
- foreach (DepsRelation *rel, node->outlinks) {
+ foreach (IDDepsNode *id_node, graph->id_nodes) {
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ comp_node->affects_directly_visible |= id_node->is_directly_visible;
+ }
+ GHASH_FOREACH_END();
+ }
+ foreach (OperationDepsNode *op_node, graph->operations) {
+ op_node->custom_flags = 0;
+ op_node->num_links_pending = 0;
+ foreach (DepsRelation *rel, op_node->outlinks) {
if ((rel->from->type == DEG_NODE_TYPE_OPERATION) &&
(rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
{
- ++node->num_links_pending;
+ ++op_node->num_links_pending;
}
}
- if (node->num_links_pending == 0) {
- BLI_stack_push(stack, &node);
- node->done = 1;
+ if (op_node->num_links_pending == 0) {
+ BLI_stack_push(stack, &op_node);
+ op_node->custom_flags |= DEG_NODE_VISITED;
}
- node->owner->layers = id_node->layers;
- id_node->id->tag |= LIB_TAG_DOIT;
}
while (!BLI_stack_is_empty(stack)) {
- OperationDepsNode *node;
- BLI_stack_pop(stack, &node);
+ OperationDepsNode *op_node;
+ BLI_stack_pop(stack, &op_node);
/* Flush layers to parents. */
- foreach (DepsRelation *rel, node->inlinks) {
+ foreach (DepsRelation *rel, op_node->inlinks) {
if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
- from->owner->layers |= node->owner->layers;
+ OperationDepsNode *op_from = (OperationDepsNode *)rel->from;
+ op_from->owner->affects_directly_visible |=
+ op_node->owner->affects_directly_visible;
}
}
/* Schedule parent nodes. */
- foreach (DepsRelation *rel, node->inlinks) {
+ foreach (DepsRelation *rel, op_node->inlinks) {
if (rel->from->type == DEG_NODE_TYPE_OPERATION) {
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ OperationDepsNode *op_from = (OperationDepsNode *)rel->from;
if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(from->num_links_pending > 0);
- --from->num_links_pending;
+ BLI_assert(op_from->num_links_pending > 0);
+ --op_from->num_links_pending;
}
- if (from->num_links_pending == 0 && from->done == 0) {
- BLI_stack_push(stack, &from);
- from->done = 1;
+ if ((op_from->num_links_pending == 0) &&
+ (op_from->custom_flags & DEG_NODE_VISITED) == 0)
+ {
+ BLI_stack_push(stack, &op_from);
+ op_from->custom_flags |= DEG_NODE_VISITED;
}
}
}
@@ -118,54 +119,44 @@ void deg_graph_build_flush_layers(Depsgraph *graph)
BLI_stack_free(stack);
}
-void deg_graph_build_finalize(Depsgraph *graph)
+} // namespace
+
+void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
{
- /* STEP 1: Make sure new invisible dependencies are ready for use.
- *
- * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice
- * to do it ahead of a time and don't spend time on flushing updates on
- * every frame change.
+ /* Make sure dependencies of visible ID datablocks are visible. */
+ deg_graph_build_flush_visibility(graph);
+ /* Re-tag IDs for update if it was tagged before the relations
+ * update tag.
*/
foreach (IDDepsNode *id_node, graph->id_nodes) {
- if (id_node->layers == 0) {
- ID *id = id_node->id;
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if (check_object_needs_evaluation(object)) {
- id_node->tag_update(graph);
- }
+ ID *id = id_node->id_orig;
+ id_node->finalize_build(graph);
+ int flag = 0;
+ if ((id->recalc & ID_RECALC_ALL)) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt != NULL && (adt->recalc & ADT_RECALC_ANIM) != 0) {
+ flag |= DEG_TAG_TIME;
}
}
- }
- /* STEP 2: Flush visibility layers from children to parent. */
- deg_graph_build_flush_layers(graph);
- /* STEP 3: Re-tag IDs for update if it was tagged before the relations
- * update tag.
- */
- foreach (IDDepsNode *id_node, graph->id_nodes) {
- GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components)
- {
- id_node->layers |= comp->layers;
+ /* Tag rebuild if special evaluation flags changed. */
+ if (id_node->eval_flags != id_node->previous_eval_flags) {
+ flag |= DEG_TAG_TRANSFORM | DEG_TAG_GEOMETRY;
}
- GHASH_FOREACH_END();
-
- if ((id_node->layers & graph->layers) != 0 || graph->layers == 0) {
- ID *id = id_node->id;
- if ((id->recalc & ID_RECALC_ALL) &&
- (id->tag & LIB_TAG_DOIT))
- {
- id_node->tag_update(graph);
- id->tag &= ~LIB_TAG_DOIT;
- }
- else if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if (object->recalc & OB_RECALC_ALL) {
- id_node->tag_update(graph);
- id->tag &= ~LIB_TAG_DOIT;
- }
+ if (!deg_copy_on_write_is_expanded(id_node->id_cow)) {
+ flag |= DEG_TAG_COPY_ON_WRITE;
+ /* This means ID is being added to the dependency graph first
+ * time, which is similar to "ob-visible-change"
+ */
+ if (GS(id->name) == ID_OB) {
+ flag |= OB_RECALC_OB | OB_RECALC_DATA;
}
}
- id_node->finalize_build();
+ if (flag != 0) {
+ DEG_graph_id_tag_update(bmain,
+ (::Depsgraph *)graph,
+ id_node->id_orig,
+ flag);
+ }
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index b8ea8c8e599..c7ff668504c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -30,15 +30,12 @@
#pragma once
-#include "intern/depsgraph_types.h"
-
-struct FCurve;
+struct Main;
namespace DEG {
struct Depsgraph;
-void deg_graph_build_finalize(struct Depsgraph *graph);
-void deg_graph_build_flush_layers(struct Depsgraph *graph);
+void deg_graph_build_finalize(struct Main *bmain, struct Depsgraph *graph);
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index feaba1a4aa8..a8768c899ad 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -86,22 +86,22 @@ struct CyclesSolverState {
BLI_INLINE void set_node_visited_state(DepsNode *node,
eCyclicCheckVisitedState state)
{
- node->done = (node->done & ~0x3) | (int)state;
+ node->custom_flags = (node->custom_flags & ~0x3) | (int)state;
}
BLI_INLINE eCyclicCheckVisitedState get_node_visited_state(DepsNode *node)
{
- return (eCyclicCheckVisitedState)(node->done & 0x3);
+ return (eCyclicCheckVisitedState)(node->custom_flags & 0x3);
}
BLI_INLINE void set_node_num_visited_children(DepsNode *node, int num_children)
{
- node->done = (node->done & 0x3) | (num_children << 2);
+ node->custom_flags = (node->custom_flags & 0x3) | (num_children << 2);
}
BLI_INLINE int get_node_num_visited_children(DepsNode *node)
{
- return node->done >> 2;
+ return node->custom_flags >> 2;
}
void schedule_node_to_stack(CyclesSolverState *state, OperationDepsNode *node)
@@ -124,7 +124,7 @@ void schedule_leaf_nodes(CyclesSolverState *state)
has_inlinks = true;
}
}
- node->done = 0;
+ node->custom_flags = 0;
if (has_inlinks == false) {
schedule_node_to_stack(state, node);
}
@@ -148,6 +148,35 @@ bool schedule_non_checked_node(CyclesSolverState *state)
return false;
}
+bool check_relation_can_murder(DepsRelation *relation)
+{
+ if (relation->flag & DEPSREL_FLAG_GODMODE) {
+ return false;
+ }
+ return true;
+}
+
+DepsRelation *select_relation_to_murder(DepsRelation *relation,
+ StackEntry *cycle_start_entry)
+{
+ /* More or less russian roulette solver, which will make sure only
+ * specially marked relations are kept alive.
+ *
+ * TODO(sergey): There might be better strategies here. */
+ if (check_relation_can_murder(relation)) {
+ return relation;
+ }
+ StackEntry *current = cycle_start_entry;
+ OperationDepsNode *to_node = (OperationDepsNode *)relation->to;
+ while (current->node != to_node) {
+ if (check_relation_can_murder(current->via_relation)) {
+ return current->via_relation;
+ }
+ current = current->from;
+ }
+ return relation;
+}
+
/* Solve cycles with all nodes which are scheduled for traversal. */
void solve_cycles(CyclesSolverState *state)
{
@@ -168,7 +197,6 @@ void solve_cycles(CyclesSolverState *state)
to->full_identifier().c_str(),
node->full_identifier().c_str(),
rel->name);
-
StackEntry *current = entry;
while (current->node != to) {
BLI_assert(current != NULL);
@@ -178,8 +206,9 @@ void solve_cycles(CyclesSolverState *state)
current->via_relation->name);
current = current->from;
}
- /* TODO(sergey): So called russian roulette cycle solver. */
- rel->flag |= DEPSREL_FLAG_CYCLIC;
+ DepsRelation *sacrificial_relation =
+ select_relation_to_murder(rel, entry);
+ sacrificial_relation->flag |= DEPSREL_FLAG_CYCLIC;
++state->num_cycles;
}
else if (to_state == NODE_NOT_VISITED) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 92640718b03..1485079c418 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -47,11 +47,11 @@ extern "C" {
#include "DNA_armature_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_effect_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@@ -62,25 +62,26 @@ extern "C" {
#include "DNA_node_types.h"
#include "DNA_particle_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
+#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
-#include "BKE_group.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -90,7 +91,9 @@ extern "C" {
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
+#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
+#include "BKE_shader_fx.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
#include "BKE_world.h"
@@ -103,6 +106,7 @@ extern "C" {
#include "DEG_depsgraph_build.h"
#include "intern/builder/deg_builder.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_id.h"
@@ -114,6 +118,21 @@ extern "C" {
namespace DEG {
+namespace {
+
+void free_copy_on_write_datablock(void *id_info_v)
+{
+ DepsgraphNodeBuilder::IDInfo *id_info =
+ (DepsgraphNodeBuilder::IDInfo *)id_info_v;
+ if (id_info->id_cow != NULL) {
+ deg_free_copy_on_write_datablock(id_info->id_cow);
+ MEM_freeN(id_info->id_cow);
+ }
+ MEM_freeN(id_info);
+}
+
+} /* namespace */
+
/* ************ */
/* Node Builder */
@@ -122,17 +141,60 @@ namespace DEG {
DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph)
: bmain_(bmain),
graph_(graph),
- scene_(NULL)
+ scene_(NULL),
+ view_layer_(NULL),
+ view_layer_index_(-1),
+ collection_(NULL),
+ is_parent_collection_visible_(true),
+ id_info_hash_(NULL)
{
}
DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
{
+ if (id_info_hash_ != NULL) {
+ BLI_ghash_free(id_info_hash_, NULL, free_copy_on_write_datablock);
+ }
}
IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
{
- return graph_->add_id_node(id, id->name);
+ IDDepsNode *id_node = NULL;
+ ID *id_cow = NULL;
+ IDComponentsMask previously_visible_components_mask = 0;
+ uint32_t previous_eval_flags = 0;
+ IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id);
+ if (id_info != NULL) {
+ id_cow = id_info->id_cow;
+ previously_visible_components_mask =
+ id_info->previously_visible_components_mask;
+ previous_eval_flags = id_info->previous_eval_flags;
+ /* Tag ID info to not free the CoW ID pointer. */
+ id_info->id_cow = NULL;
+ }
+ id_node = graph_->add_id_node(id, id_cow);
+ id_node->previously_visible_components_mask =
+ previously_visible_components_mask;
+ id_node->previous_eval_flags = previous_eval_flags;
+ /* Currently all ID nodes are supposed to have copy-on-write logic.
+ *
+ * NOTE: Zero number of components indicates that ID node was just created.
+ */
+ if (BLI_ghash_len(id_node->components) == 0) {
+ ComponentDepsNode *comp_cow =
+ id_node->add_component(DEG_NODE_TYPE_COPY_ON_WRITE);
+ OperationDepsNode *op_cow = comp_cow->add_operation(
+ function_bind(deg_evaluate_copy_on_write, _1, id_node),
+ DEG_OPCODE_COPY_ON_WRITE,
+ "", -1);
+ graph_->operations.push_back(op_cow);
+ }
+ return id_node;
+}
+
+IDDepsNode *DepsgraphNodeBuilder::find_id_node(ID *id)
+{
+ return graph_->find_id_node(id);
}
TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source()
@@ -259,9 +321,89 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
return find_operation_node(id, comp_type, "", opcode, name, name_tag);
}
+ID *DepsgraphNodeBuilder::get_cow_id(const ID *id_orig) const
+{
+ return graph_->get_cow_id(id_orig);
+}
+
+ID *DepsgraphNodeBuilder::ensure_cow_id(ID *id_orig)
+{
+ if (id_orig->tag & LIB_TAG_COPIED_ON_WRITE) {
+ /* ID is already remapped to copy-on-write. */
+ return id_orig;
+ }
+ IDDepsNode *id_node = add_id_node(id_orig);
+ return id_node->id_cow;
+}
+
/* **** Build functions for entity nodes **** */
-void DepsgraphNodeBuilder::begin_build() {
+void DepsgraphNodeBuilder::begin_build()
+{
+ /* Store existing copy-on-write versions of datablock, so we can re-use
+ * them for new ID nodes.
+ */
+ id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash");
+ foreach (IDDepsNode *id_node, graph_->id_nodes) {
+ IDInfo *id_info = (IDInfo *)MEM_mallocN(
+ sizeof(IDInfo), "depsgraph id info");
+ if (deg_copy_on_write_is_expanded(id_node->id_cow) &&
+ id_node->id_orig != id_node->id_cow)
+ {
+ id_info->id_cow = id_node->id_cow;
+ }
+ else {
+ id_info->id_cow = NULL;
+ }
+ id_info->previously_visible_components_mask =
+ id_node->visible_components_mask;
+ id_info->previous_eval_flags = id_node->eval_flags;
+ BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info);
+ id_node->id_cow = NULL;
+ }
+
+ GSET_FOREACH_BEGIN(OperationDepsNode *, op_node, graph_->entry_tags)
+ {
+ ComponentDepsNode *comp_node = op_node->owner;
+ IDDepsNode *id_node = comp_node->owner;
+
+ SavedEntryTag entry_tag;
+ entry_tag.id_orig = id_node->id_orig;
+ entry_tag.component_type = comp_node->type;
+ entry_tag.opcode = op_node->opcode;
+ entry_tag.name = op_node->name;
+ entry_tag.name_tag = op_node->name_tag;
+ saved_entry_tags_.push_back(entry_tag);
+ };
+ GSET_FOREACH_END();
+
+ /* Make sure graph has no nodes left from previous state. */
+ graph_->clear_all_nodes();
+ graph_->operations.clear();
+ BLI_gset_clear(graph_->entry_tags, NULL);
+}
+
+void DepsgraphNodeBuilder::end_build()
+{
+ foreach (const SavedEntryTag& entry_tag, saved_entry_tags_) {
+ IDDepsNode *id_node = find_id_node(entry_tag.id_orig);
+ if (id_node == NULL) {
+ continue;
+ }
+ ComponentDepsNode *comp_node =
+ id_node->find_component(entry_tag.component_type);
+ if (comp_node == NULL) {
+ continue;
+ }
+ OperationDepsNode *op_node = comp_node->find_operation(entry_tag.opcode, entry_tag.name, entry_tag.name_tag);
+ if (op_node == NULL) {
+ continue;
+ }
+ /* Since the tag is coming from a saved copy of entry tags, this means
+ * that originally node was explicitly tagged for user update.
+ */
+ op_node->tag_update(graph_, DEG_UPDATE_SOURCE_USER_EDIT);
+ }
}
void DepsgraphNodeBuilder::build_id(ID *id)
@@ -270,14 +412,40 @@ void DepsgraphNodeBuilder::build_id(ID *id)
return;
}
switch (GS(id->name)) {
- case ID_SCE:
- build_scene((Scene *)id);
+ case ID_AC:
+ build_action((bAction *)id);
+ break;
+ case ID_AR:
+ build_armature((bArmature *)id);
+ break;
+ case ID_CA:
+ build_camera((Camera *)id);
break;
case ID_GR:
- build_group(NULL, (Group *)id);
+ build_collection(NULL, (Collection *)id);
break;
case ID_OB:
- build_object(NULL, (Object *)id);
+ /* TODO(sergey): Get visibility from a "parent" somehow.
+ *
+ * NOTE: Using `false` visibility here should be fine, since if this
+ * driver affects on something invisible we don't really care if the
+ * driver gets evaluated (and even don't want this to force object
+ * to become visible).
+ *
+ * If this happened to be affecting visible object, then it is up to
+ * deg_graph_build_flush_visibility() to ensure visibility of the
+ * object is true.
+ */
+ build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false);
+ break;
+ case ID_KE:
+ build_shapekeys((Key *)id);
+ break;
+ case ID_LA:
+ build_lamp((Lamp *)id);
+ break;
+ case ID_LP:
+ build_lightprobe((LightProbe *)id);
break;
case ID_NT:
build_nodetree((bNodeTree *)id);
@@ -300,67 +468,157 @@ void DepsgraphNodeBuilder::build_id(ID *id)
case ID_MC:
build_movieclip((MovieClip *)id);
break;
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ case ID_LT:
+ /* TODO(sergey): Get visibility from a "parent" somehow.
+ *
+ * NOTE: Similarly to above, we don't want false-positives on
+ * visibility.
+ */
+ build_object_data_geometry_datablock(id, false);
+ break;
+ case ID_SPK:
+ build_speaker((Speaker *)id);
+ break;
+ case ID_TXT:
+ /* Not a part of dependency graph. */
+ break;
default:
- /* fprintf(stderr, "Unhandled ID %s\n", id->name); */
+ fprintf(stderr, "Unhandled ID %s\n", id->name);
+ BLI_assert(!"Should never happen");
break;
}
}
-void DepsgraphNodeBuilder::build_group(Base *base, Group *group)
+void DepsgraphNodeBuilder::build_collection(
+ LayerCollection *from_layer_collection,
+ Collection *collection)
{
- if (built_map_.checkIsBuiltAndTag(group)) {
+ const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT)
+ ? COLLECTION_RESTRICT_VIEW
+ : COLLECTION_RESTRICT_RENDER;
+ const bool is_collection_restricted = (collection->flag & restrict_flag);
+ const bool is_collection_visible =
+ !is_collection_restricted && is_parent_collection_visible_;
+ IDDepsNode *id_node;
+ if (built_map_.checkIsBuiltAndTag(collection)) {
+ id_node = find_id_node(&collection->id);
+ if (is_collection_visible &&
+ id_node->is_directly_visible == false &&
+ id_node->is_collection_fully_expanded == true)
+ {
+ /* Collection became visible, make sure nested collections and
+ * objects are poked with the new visibility flag, since they
+ * might become visible too. */
+ }
+ else {
+ return;
+ }
+ }
+ else {
+ /* Collection itself. */
+ id_node = add_id_node(&collection->id);
+ id_node->is_directly_visible = is_collection_visible;
+ }
+ if (from_layer_collection != NULL) {
+ /* If we came from layer collection we don't go deeper, view layer
+ * builder takes care of going deeper. */
return;
}
- LISTBASE_FOREACH (GroupObject *, go, &group->gobject) {
- build_object(base, go->ob);
+ /* Backup state. */
+ Collection *current_state_collection = collection_;
+ const bool is_current_parent_collection_visible =
+ is_parent_collection_visible_;
+ /* Modify state as we've entered new collection/ */
+ collection_ = collection;
+ is_parent_collection_visible_ = is_collection_visible;
+ /* Build collection objects. */
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ build_object(
+ -1, cob->ob, DEG_ID_LINKED_INDIRECTLY, is_collection_visible);
}
+ /* Build child collections. */
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
+ build_collection(NULL, child->collection);
+ }
+ /* Restore state. */
+ collection_ = current_state_collection;
+ is_parent_collection_visible_ = is_current_parent_collection_visible;
+ id_node->is_collection_fully_expanded = true;
}
-void DepsgraphNodeBuilder::build_object(Base *base, Object *object)
+void DepsgraphNodeBuilder::build_object(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state,
+ bool is_visible)
{
const bool has_object = built_map_.checkIsBuiltAndTag(object);
- IDDepsNode *id_node = (has_object)
- ? graph_->find_id_node(&object->id)
- : add_id_node(&object->id);
- /* Update node layers.
- * Do it for both new and existing ID nodes. This is so because several
- * bases might be sharing same object.
- */
- if (base != NULL) {
- id_node->layers |= base->lay;
- }
- if (object->type == OB_CAMERA) {
- /* Camera should always be updated, it used directly by viewport.
- *
- * TODO(sergey): Make it only for active scene camera.
- */
- id_node->layers |= (unsigned int)(-1);
- }
/* Skip rest of components if the ID node was already there. */
if (has_object) {
+ IDDepsNode *id_node = find_id_node(&object->id);
+ /* We need to build some extra stuff if object becomes linked
+ * directly.
+ */
+ if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) {
+ build_object_flags(base_index, object, linked_state);
+ }
+ id_node->linked_state = max(id_node->linked_state, linked_state);
+ if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) {
+ id_node->is_directly_visible |= is_visible;
+ }
return;
}
+ /* Create ID node for object and begin init. */
+ IDDepsNode *id_node = add_id_node(&object->id);
+ id_node->linked_state = linked_state;
+ if (object == scene_->camera) {
+ id_node->is_directly_visible = true;
+ }
+ else {
+ id_node->is_directly_visible = is_visible;
+ }
object->customdata_mask = 0;
+ /* Various flags, flushing from bases/collections. */
+ build_object_flags(base_index, object, linked_state);
/* Transform. */
build_object_transform(object);
/* Parent. */
if (object->parent != NULL) {
- build_object(NULL, object->parent);
+ build_object(
+ -1, object->parent, DEG_ID_LINKED_INDIRECTLY, is_visible);
}
/* Modifiers. */
if (object->modifiers.first != NULL) {
BuilderWalkUserData data;
data.builder = this;
+ data.is_parent_visible = is_visible;
modifiers_foreachIDLink(object, modifier_walk, &data);
}
+ /* Grease Pencil Modifiers. */
+ if (object->greasepencil_modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.is_parent_visible = is_visible;
+ BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data);
+ }
+ /* Shader FX. */
+ if (object->shader_fx.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ data.is_parent_visible = is_visible;
+ BKE_shaderfx_foreachIDLink(object, modifier_walk, &data);
+ }
/* Constraints. */
if (object->constraints.first != NULL) {
BuilderWalkUserData data;
data.builder = this;
+ data.is_parent_visible = is_visible;
BKE_constraints_id_loop(&object->constraints, constraint_walk, &data);
}
/* Object data. */
- build_object_data(object);
+ build_object_data(object, is_visible);
/* Build animation data,
*
* Do it now because it's possible object data will affect
@@ -375,61 +633,91 @@ void DepsgraphNodeBuilder::build_object(Base *base, Object *object)
build_animdata(&object->id);
/* Particle systems. */
if (object->particlesystem.first != NULL) {
- build_particles(object);
+ build_particles(object, is_visible);
}
- /* Grease pencil. */
- if (object->gpd != NULL) {
- build_gpencil(object->gpd);
+ /* Proxy object to copy from. */
+ if (object->proxy_from != NULL) {
+ build_object(
+ -1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible);
}
- /* Object that this is a proxy for. */
- if (object->proxy) {
- object->proxy->proxy_from = object;
- build_object(base, object->proxy);
+ if (object->proxy_group != NULL) {
+ build_object(
+ -1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible);
}
/* Object dupligroup. */
if (object->dup_group != NULL) {
- build_group(base, object->dup_group);
+ const bool is_current_parent_collection_visible =
+ is_parent_collection_visible_;
+ is_parent_collection_visible_ = is_visible;
+ build_collection(NULL, object->dup_group);
+ is_parent_collection_visible_ = is_current_parent_collection_visible;
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_DUPLI,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Dupli");
}
}
-void DepsgraphNodeBuilder::build_object_data(Object *object)
+void DepsgraphNodeBuilder::build_object_flags(
+ int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state)
+{
+ if (base_index == -1) {
+ return;
+ }
+ Scene *scene_cow = get_cow_datablock(scene_);
+ Object *object_cow = get_cow_datablock(object);
+ const bool is_from_set = (linked_state == DEG_ID_LINKED_VIA_SET);
+ /* TODO(sergey): Is this really best component to be used? */
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_OBJECT_FROM_LAYER,
+ function_bind(BKE_object_eval_flush_base_flags,
+ _1,
+ scene_cow,
+ view_layer_index_,
+ object_cow, base_index,
+ is_from_set),
+ DEG_OPCODE_OBJECT_BASE_FLAGS);
+}
+
+void DepsgraphNodeBuilder::build_object_data(
+ Object *object, bool is_object_visible)
{
if (object->data == NULL) {
return;
}
- IDDepsNode *id_node = graph_->find_id_node(&object->id);
- /* type-specific data... */
+ /* type-specific data. */
switch (object->type) {
- case OB_MESH: /* Geometry */
+ case OB_MESH:
case OB_CURVE:
case OB_FONT:
case OB_SURF:
case OB_MBALL:
case OB_LATTICE:
- build_obdata_geom(object);
- /* TODO(sergey): Only for until we support granular
- * update of curves.
- */
- if (object->type == OB_FONT) {
- Curve *curve = (Curve *)object->data;
- if (curve->textoncurve) {
- id_node->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
- }
- }
+ case OB_GPENCIL:
+ build_object_data_geometry(object, is_object_visible);
break;
case OB_ARMATURE:
if (ID_IS_LINKED(object) && object->proxy_from != NULL) {
build_proxy_rig(object);
}
else {
- build_rig(object);
+ build_rig(object, is_object_visible);
}
break;
case OB_LAMP:
- build_lamp(object);
+ build_object_data_lamp(object);
break;
case OB_CAMERA:
- build_camera(object);
+ build_object_data_camera(object);
+ break;
+ case OB_LIGHTPROBE:
+ build_object_data_lightprobe(object);
+ break;
+ case OB_SPEAKER:
+ build_object_data_speaker(object);
break;
default:
{
@@ -442,42 +730,79 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
}
}
+void DepsgraphNodeBuilder::build_object_data_camera(Object *object)
+{
+ Camera *camera = (Camera *)object->data;
+ build_camera(camera);
+}
+
+void DepsgraphNodeBuilder::build_object_data_lamp(Object *object)
+{
+ Lamp *lamp = (Lamp *)object->data;
+ build_lamp(lamp);
+}
+
+void DepsgraphNodeBuilder::build_object_data_lightprobe(Object *object)
+{
+ LightProbe *probe = (LightProbe *)object->data;
+ build_lightprobe(probe);
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_LIGHT_PROBE_EVAL);
+}
+
+void DepsgraphNodeBuilder::build_object_data_speaker(Object *object)
+{
+ Speaker *speaker = (Speaker *)object->data;
+ build_speaker(speaker);
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_SPEAKER_EVAL);
+}
+
void DepsgraphNodeBuilder::build_object_transform(Object *object)
{
OperationDepsNode *op_node;
+ Scene *scene_cow = get_cow_datablock(scene_);
+ Object *ob_cow = get_cow_datablock(object);
/* local transforms (from transform channels - loc/rot/scale + deltas) */
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
- function_bind(BKE_object_eval_local_transform, _1, object),
+ function_bind(BKE_object_eval_local_transform,
+ _1,
+ ob_cow),
DEG_OPCODE_TRANSFORM_LOCAL);
op_node->set_as_entry();
/* object parent */
- if (object->parent) {
+ if (object->parent != NULL) {
add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
- function_bind(BKE_object_eval_parent, _1, scene_, object),
+ function_bind(BKE_object_eval_parent,
+ _1,
+ scene_cow,
+ ob_cow),
DEG_OPCODE_TRANSFORM_PARENT);
}
/* object constraints */
- if (object->constraints.first) {
+ if (object->constraints.first != NULL) {
build_object_constraints(object);
}
- /* Temporary uber-update node, which does everything.
- * It is for the being we're porting old dependencies into the new system.
- * We'll get rid of this node as soon as all the granular update functions
- * are filled in.
- *
- * TODO(sergey): Get rid of this node.
- */
+ /* Rest of transformation update. */
add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
- function_bind(BKE_object_eval_uber_transform, _1, object),
+ function_bind(BKE_object_eval_uber_transform,
+ _1,
+ ob_cow),
DEG_OPCODE_TRANSFORM_OBJECT_UBEREVAL);
/* object transform is done */
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
- function_bind(BKE_object_eval_done, _1, object),
+ function_bind(BKE_object_eval_transform_final,
+ _1,
+ ob_cow),
DEG_OPCODE_TRANSFORM_FINAL);
op_node->set_as_exit();
}
@@ -503,10 +828,29 @@ void DepsgraphNodeBuilder::build_object_constraints(Object *object)
{
/* create node for constraint stack */
add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
- function_bind(BKE_object_eval_constraints, _1, scene_, object),
+ function_bind(BKE_object_eval_constraints,
+ _1,
+ get_cow_datablock(scene_),
+ get_cow_datablock(object)),
DEG_OPCODE_TRANSFORM_CONSTRAINTS);
}
+void DepsgraphNodeBuilder::build_object_pointcache(Object *object)
+{
+ if (!BKE_ptcache_object_has(scene_, object, 0)) {
+ return;
+ }
+ Scene *scene_cow = get_cow_datablock(scene_);
+ Object *object_cow = get_cow_datablock(object);
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_POINT_CACHE,
+ function_bind(BKE_object_eval_ptcache_reset,
+ _1,
+ scene_cow,
+ object_cow),
+ DEG_OPCODE_POINT_CACHE_RESET);
+}
+
/**
* Build graph nodes for AnimData block
* \param id: ID-Block which hosts the AnimData
@@ -514,44 +858,94 @@ void DepsgraphNodeBuilder::build_object_constraints(Object *object)
void DepsgraphNodeBuilder::build_animdata(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
-
- if (adt == NULL)
+ if (adt == NULL) {
return;
-
+ }
+ if (adt->action != NULL) {
+ build_action(adt->action);
+ }
/* animation */
if (adt->action || adt->nla_tracks.first || adt->drivers.first) {
- // XXX: Hook up specific update callbacks for special properties which may need it...
+ (void) add_id_node(id);
+ ID *id_cow = get_cow_id(id);
+
+ // XXX: Hook up specific update callbacks for special properties which
+ // may need it...
- /* actions and NLA - as a single unit for now, as it gets complicated to schedule otherwise */
+ /* actions and NLA - as a single unit for now, as it gets complicated to
+ * schedule otherwise.
+ */
if ((adt->action) || (adt->nla_tracks.first)) {
/* create the node */
add_operation_node(id, DEG_NODE_TYPE_ANIMATION,
- function_bind(BKE_animsys_eval_animdata, _1, id),
- DEG_OPCODE_ANIMATION, id->name);
+ function_bind(BKE_animsys_eval_animdata,
+ _1,
+ id_cow),
+ DEG_OPCODE_ANIMATION,
+ id->name);
+
+ /* TODO: for each channel affected, we might also want to add some
+ * support for running RNA update callbacks on them
+ * (which will be needed for proper handling of drivers later)
+ */
+ }
- // TODO: for each channel affected, we might also want to add some support for running RNA update callbacks on them
- // (which will be needed for proper handling of drivers later)
+ /* NLA strips contain actions */
+ LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
+ build_animdata_nlastrip_targets(&nlt->strips);
}
/* drivers */
+ int driver_index = 0;
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
/* create driver */
- build_driver(id, fcu);
+ build_driver(id, fcu, driver_index++);
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
+{
+ LISTBASE_FOREACH (NlaStrip *, strip, strips) {
+ if (strip->act != NULL) {
+ build_action(strip->act);
+ }
+ else if (strip->strips.first != NULL) {
+ build_animdata_nlastrip_targets(&strip->strips);
}
}
}
+void DepsgraphNodeBuilder::build_action(bAction *action)
+{
+ if (built_map_.checkIsBuiltAndTag(action)) {
+ return;
+ }
+ add_operation_node(&action->id,
+ DEG_NODE_TYPE_ANIMATION,
+ NULL,
+ DEG_OPCODE_ANIMATION);
+}
+
/**
* Build graph node(s) for Driver
* \param id: ID-Block that driver is attached to
* \param fcu: Driver-FCurve
+ * \param driver_index: Index in animation data drivers list
*/
-void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve)
+void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index)
{
/* Create data node for this driver */
+ ID *id_cow = get_cow_id(id);
+ ChannelDriver *driver_orig = fcurve->driver;
+
+ /* TODO(sergey): ideally we could pass the COW of fcu, but since it
+ * has not yet been allocated at this point we can't. As a workaround
+ * the animation systems allocates an array so we can do a fast lookup
+ * with the driver index. */
ensure_operation_node(id,
DEG_NODE_TYPE_PARAMETERS,
- function_bind(BKE_animsys_eval_driver, _1, id, fcurve),
+ function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig),
DEG_OPCODE_DRIVER,
fcurve->rna_path ? fcurve->rna_path : "",
fcurve->array_index);
@@ -564,8 +958,19 @@ void DepsgraphNodeBuilder::build_driver_variables(ID * id, FCurve *fcurve)
LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) {
DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
{
+ if (dtar->id == NULL) {
+ continue;
+ }
build_id(dtar->id);
build_driver_id_property(dtar->id, dtar->rna_path);
+ /* Corresponds to dtar_id_ensure_proxy_from(). */
+ if ((GS(dtar->id->name) == ID_OB) &&
+ (((Object *)dtar->id)->proxy_from != NULL))
+ {
+ Object *proxy_from = ((Object *)dtar->id)->proxy_from;
+ build_id(&proxy_from->id);
+ build_driver_id_property(&proxy_from->id, dtar->rna_path);
+ }
}
DRIVER_TARGETS_LOOPER_END;
}
@@ -603,80 +1008,95 @@ void DepsgraphNodeBuilder::build_world(World *world)
if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
- ID *world_id = &world->id;
- build_animdata(world_id);
- /* world itself */
- add_operation_node(world_id,
- DEG_NODE_TYPE_PARAMETERS,
- NULL,
- DEG_OPCODE_PARAMETERS_EVAL);
- /* textures */
- build_texture_stack(world->mtex);
- /* world's nodetree */
- if (world->nodetree) {
- build_nodetree(world->nodetree);
- }
+ /* World itself. */
+ add_id_node(&world->id);
+ World *world_cow = get_cow_datablock(world);
+ /* Shading update. */
+ add_operation_node(&world->id,
+ DEG_NODE_TYPE_SHADING,
+ function_bind(BKE_world_eval,
+ _1,
+ world_cow),
+ DEG_OPCODE_WORLD_UPDATE);
+ /* Animation. */
+ build_animdata(&world->id);
+ /* World's nodetree. */
+ build_nodetree(world->nodetree);
}
/* Rigidbody Simulation - Scene Level */
void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
+ Scene *scene_cow = get_cow_datablock(scene);
/**
* Rigidbody Simulation Nodes
* ==========================
*
* There are 3 nodes related to Rigidbody Simulation:
- * 1) "Initialize/Rebuild World" - this is called sparingly, only when the simulation
- * needs to be rebuilt (mainly after file reload, or moving back to start frame)
- * 2) "Do Simulation" - perform a simulation step - interleaved between the evaluation
- * steps for clusters of objects (i.e. between those affected and/or not affected by
- * the sim for instance)
+ * 1) "Initialize/Rebuild World" - this is called sparingly, only when the
+ * simulation needs to be rebuilt (mainly after file reload, or moving
+ * back to start frame)
+ * 2) "Do Simulation" - perform a simulation step - interleaved between the
+ * evaluation steps for clusters of objects (i.e. between those affected
+ * and/or not affected by the sim for instance).
*
- * 3) "Pull Results" - grab the specific transforms applied for a specific object -
- * performed as part of object's transform-stack building
+ * 3) "Pull Results" - grab the specific transforms applied for a specific
+ * object - performed as part of object's transform-stack building.
*/
- /* create nodes ------------------------------------------------------------------------ */
- /* XXX: is this the right component, or do we want to use another one instead? */
+ /* Create nodes --------------------------------------------------------- */
+
+ /* XXX: is this the right component, or do we want to use another one
+ * instead?
+ */
/* init/rebuild operation */
- /*OperationDepsNode *init_node =*/ add_operation_node(&scene->id, DEG_NODE_TYPE_TRANSFORM,
- function_bind(BKE_rigidbody_rebuild_sim, _1, scene),
- DEG_OPCODE_RIGIDBODY_REBUILD);
+ /*OperationDepsNode *init_node =*/ add_operation_node(
+ &scene->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_rigidbody_rebuild_sim, _1, scene_cow),
+ DEG_OPCODE_RIGIDBODY_REBUILD);
/* do-sim operation */
// XXX: what happens if we need to split into several groups?
- OperationDepsNode *sim_node = add_operation_node(&scene->id, DEG_NODE_TYPE_TRANSFORM,
- function_bind(BKE_rigidbody_eval_simulation, _1, scene),
- DEG_OPCODE_RIGIDBODY_SIM);
+ OperationDepsNode *sim_node = add_operation_node(
+ &scene->id, DEG_NODE_TYPE_TRANSFORM,
+ function_bind(BKE_rigidbody_eval_simulation, _1, scene_cow),
+ DEG_OPCODE_RIGIDBODY_SIM);
- /* XXX: For now, the sim node is the only one that really matters here. If any other
- * sims get added later, we may have to remove these hacks...
+ /* XXX: For now, the sim node is the only one that really matters here.
+ * If any other sims get added later, we may have to remove these hacks...
*/
sim_node->owner->entry_operation = sim_node;
sim_node->owner->exit_operation = sim_node;
-
/* objects - simulation participants */
if (rbw->group) {
- LISTBASE_FOREACH (GroupObject *, go, &rbw->group->gobject) {
- Object *object = go->ob;
+ build_collection(NULL, rbw->group);
- if (!object || (object->type != OB_MESH))
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ if (object->type != OB_MESH)
continue;
/* 2) create operation for flushing results */
- /* object's transform component - where the rigidbody operation lives */
+ /* object's transform component - where the rigidbody operation
+ * lives. */
add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
- function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, object),
+ function_bind(
+ BKE_rigidbody_object_sync_transforms,
+ _1,
+ scene_cow,
+ get_cow_datablock(object)),
DEG_OPCODE_RIGIDBODY_TRANSFORM_COPY);
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
-void DepsgraphNodeBuilder::build_particles(Object *object)
+void DepsgraphNodeBuilder::build_particles(Object *object,
+ bool is_object_visible)
{
/**
* Particle Systems Nodes
@@ -695,20 +1115,26 @@ void DepsgraphNodeBuilder::build_particles(Object *object)
/* Component for all particle systems. */
ComponentDepsNode *psys_comp =
add_component_node(&object->id, DEG_NODE_TYPE_EVAL_PARTICLES);
+
+ /* TODO(sergey): Need to get COW of PSYS. */
+ Scene *scene_cow = get_cow_datablock(scene_);
+ Object *ob_cow = get_cow_datablock(object);
+
add_operation_node(psys_comp,
function_bind(BKE_particle_system_eval_init,
_1,
- scene_,
- object),
+ scene_cow,
+ ob_cow),
DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT);
/* Build all particle systems. */
LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
ParticleSettings *part = psys->part;
- /* Particle settings. */
- // XXX: what if this is used more than once!
- build_animdata(&part->id);
- /* This particle system evaluation. */
- // TODO: for now, this will just be a placeholder "ubereval" node
+ /* Build particle settings operations.
+ *
+ * NOTE: The call itself ensures settings are only build once.
+ */
+ build_particle_settings(part);
+ /* Particle system evaluation. */
add_operation_node(psys_comp,
NULL,
DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
@@ -717,35 +1143,40 @@ void DepsgraphNodeBuilder::build_particles(Object *object)
switch (part->ren_as) {
case PART_DRAW_OB:
if (part->dup_ob != NULL) {
- build_object(NULL, part->dup_ob);
+ build_object(-1,
+ part->dup_ob,
+ DEG_ID_LINKED_INDIRECTLY,
+ is_object_visible);
}
break;
case PART_DRAW_GR:
if (part->dup_group != NULL) {
- build_group(NULL, part->dup_group);
+ build_collection(NULL, part->dup_group);
}
break;
}
}
-
- /* pointcache */
- // TODO...
}
-void DepsgraphNodeBuilder::build_cloth(Object *object)
-{
- add_operation_node(&object->id,
- DEG_NODE_TYPE_CACHE,
- function_bind(BKE_object_eval_cloth,
- _1,
- scene_,
- object),
- DEG_OPCODE_GEOMETRY_CLOTH_MODIFIER);
+void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *part) {
+ if (built_map_.checkIsBuiltAndTag(part)) {
+ return;
+ }
+ /* Animation data. */
+ build_animdata(&part->id);
+ /* Parameters change. */
+ add_operation_node(&part->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PARTICLE_SETTINGS_EVAL);
}
/* Shapekeys */
void DepsgraphNodeBuilder::build_shapekeys(Key *key)
{
+ if (built_map_.checkIsBuiltAndTag(key)) {
+ return;
+ }
build_animdata(&key->id);
add_operation_node(&key->id,
DEG_NODE_TYPE_GEOMETRY,
@@ -755,11 +1186,13 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
/* ObData Geometry Evaluation */
// XXX: what happens if the datablock is shared!
-void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
+void DepsgraphNodeBuilder::build_object_data_geometry(
+ Object *object,
+ bool is_object_visible)
{
- ID *obdata = (ID *)object->data;
OperationDepsNode *op_node;
-
+ Scene *scene_cow = get_cow_datablock(scene_);
+ Object *object_cow = get_cow_datablock(object);
/* Temporary uber-update node, which does everything.
* It is for the being we're porting old dependencies into the new system.
* We'll get rid of this node as soon as all the granular update functions
@@ -770,10 +1203,9 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_object_eval_uber_data,
- bmain_,
_1,
- scene_,
- object),
+ scene_cow,
+ object_cow),
DEG_OPCODE_GEOMETRY_UBEREVAL);
op_node->set_as_exit();
@@ -783,182 +1215,197 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
DEG_OPCODE_PLACEHOLDER,
"Eval Init");
op_node->set_as_entry();
-
- // TODO: "Done" operation
-
- /* Cloth modifier. */
- LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
- if (md->type == eModifierType_Cloth) {
- build_cloth(object);
+ /* Materials. */
+ if (object->totcol != 0) {
+ if (object->type == OB_MESH) {
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_SHADING,
+ function_bind(BKE_object_eval_update_shading,
+ _1,
+ object_cow),
+ DEG_OPCODE_SHADING);
}
- }
-
- /* materials */
- for (int a = 1; a <= object->totcol; a++) {
- Material *ma = give_current_material(object, a);
- if (ma != NULL) {
- build_material(ma);
+ for (int a = 1; a <= object->totcol; a++) {
+ Material *ma = give_current_material(object, a);
+ if (ma != NULL) {
+ build_material(ma);
+ }
}
}
+ /* Point caches. */
+ build_object_pointcache(object);
+ /* Geometry. */
+ build_object_data_geometry_datablock((ID *)object->data, is_object_visible);
+}
- /* geometry collision */
- if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
- // add geometry collider relations
- }
-
+void DepsgraphNodeBuilder::build_object_data_geometry_datablock(
+ ID *obdata,
+ bool is_object_visible)
+{
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
-
+ OperationDepsNode *op_node;
+ /* Make sure we've got an ID node before requesting CoW pointer. */
+ (void) add_id_node((ID *)obdata);
+ ID *obdata_cow = get_cow_id(obdata);
+ /* Animation. */
+ build_animdata(obdata);
/* ShapeKeys */
- Key *key = BKE_key_from_object(object);
+ Key *key = BKE_key_from_id(obdata);
if (key) {
build_shapekeys(key);
}
-
- build_animdata(obdata);
-
/* Nodes for result of obdata's evaluation, and geometry
* evaluation on object.
*/
- switch (object->type) {
- case OB_MESH:
+ const ID_Type id_type = GS(obdata->name);
+ switch (id_type) {
+ case ID_ME:
{
- //Mesh *me = (Mesh *)object->data;
-
- /* evaluation operations */
op_node = add_operation_node(obdata,
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_mesh_eval_geometry,
_1,
- (Mesh *)obdata),
+ (Mesh *)obdata_cow),
DEG_OPCODE_PLACEHOLDER,
"Geometry Eval");
op_node->set_as_entry();
break;
}
-
- case OB_MBALL:
+ case ID_MB:
{
- Object *mom = BKE_mball_basis_find(bmain_, bmain_->eval_ctx, scene_, object);
- /* NOTE: Only the motherball gets evaluated, it's children are
- * having empty placeholders for the correct relations being built.
- */
- if (mom == object) {
- /* metaball evaluation operations */
- op_node = add_operation_node(obdata,
- DEG_NODE_TYPE_GEOMETRY,
- function_bind(BKE_mball_eval_geometry,
- _1,
- (MetaBall *)obdata),
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
- }
- else {
- op_node = add_operation_node(obdata,
- DEG_NODE_TYPE_GEOMETRY,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
- op_node->set_as_entry();
- }
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
break;
}
-
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
+ case ID_CU:
{
- /* Curve/nurms evaluation operations. */
- /* - calculate curve geometry (including path) */
op_node = add_operation_node(obdata,
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_curve_eval_geometry,
_1,
- (Curve *)obdata),
+ (Curve *)obdata_cow),
DEG_OPCODE_PLACEHOLDER,
"Geometry Eval");
op_node->set_as_entry();
-
/* Make sure objects used for bevel.taper are in the graph.
* NOTE: This objects might be not linked to the scene.
*/
Curve *cu = (Curve *)obdata;
if (cu->bevobj != NULL) {
- build_object(NULL, cu->bevobj);
+ build_object(-1,
+ cu->bevobj,
+ DEG_ID_LINKED_INDIRECTLY,
+ is_object_visible);
}
if (cu->taperobj != NULL) {
- build_object(NULL, cu->taperobj);
+ build_object(-1,
+ cu->taperobj,
+ DEG_ID_LINKED_INDIRECTLY,
+ is_object_visible);
}
- if (object->type == OB_FONT && cu->textoncurve != NULL) {
- build_object(NULL, cu->textoncurve);
+ if (cu->textoncurve != NULL) {
+ build_object(-1,
+ cu->textoncurve,
+ DEG_ID_LINKED_INDIRECTLY,
+ is_object_visible);
}
break;
}
-
- case OB_LATTICE:
+ case ID_LT:
{
- /* Lattice evaluation operations. */
op_node = add_operation_node(obdata,
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_lattice_eval_geometry,
_1,
- (Lattice *)obdata),
+ (Lattice *)obdata_cow),
DEG_OPCODE_PLACEHOLDER,
"Geometry Eval");
op_node->set_as_entry();
break;
}
- }
+ case ID_GD:
+ {
+ /* GPencil evaluation operations. */
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ function_bind(BKE_gpencil_eval_geometry,
+ _1,
+ (bGPdata *)obdata_cow),
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
+ break;
+ }
+ default:
+ BLI_assert(!"Should not happen");
+ break;
+ }
op_node = add_operation_node(obdata, DEG_NODE_TYPE_GEOMETRY, NULL,
DEG_OPCODE_PLACEHOLDER, "Eval Done");
op_node->set_as_exit();
-
/* Parameters for driver sources. */
add_operation_node(obdata,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PARAMETERS_EVAL);
+ /* Batch cache. */
+ add_operation_node(obdata,
+ DEG_NODE_TYPE_BATCH_CACHE,
+ function_bind(BKE_object_data_select_update,
+ _1,
+ obdata_cow),
+ DEG_OPCODE_GEOMETRY_SELECT_UPDATE);
}
-/* Cameras */
-void DepsgraphNodeBuilder::build_camera(Object *object)
+void DepsgraphNodeBuilder::build_armature(bArmature *armature)
{
- /* TODO: Link scene-camera links in somehow... */
- Camera *camera = (Camera *)object->data;
- if (built_map_.checkIsBuiltAndTag(camera)) {
+ if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
- build_animdata(&camera->id);
- add_operation_node(&camera->id,
+ build_animdata(&armature->id);
+ /* Make sure pose is up-to-date with armature updates. */
+ add_operation_node(&armature->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
- DEG_OPCODE_PARAMETERS_EVAL);
- if (camera->dof_ob != NULL) {
- /* TODO(sergey): For now parametrs are on object level. */
- add_operation_node(&object->id, DEG_NODE_TYPE_PARAMETERS, NULL,
- DEG_OPCODE_PLACEHOLDER, "Camera DOF");
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
+}
+
+void DepsgraphNodeBuilder::build_camera(Camera *camera)
+{
+ if (built_map_.checkIsBuiltAndTag(camera)) {
+ return;
}
+ OperationDepsNode *op_node;
+ build_animdata(&camera->id);
+ op_node = add_operation_node(&camera->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PARAMETERS_EVAL);
+ op_node->set_as_exit();
}
-/* Lamps */
-void DepsgraphNodeBuilder::build_lamp(Object *object)
+void DepsgraphNodeBuilder::build_lamp(Lamp *lamp)
{
- Lamp *lamp = (Lamp *)object->data;
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+ OperationDepsNode *op_node;
build_animdata(&lamp->id);
- /* TODO(sergey): Is it really how we're supposed to work with drivers? */
- add_operation_node(&lamp->id,
- DEG_NODE_TYPE_PARAMETERS,
- NULL,
- DEG_OPCODE_PARAMETERS_EVAL);
+ op_node = add_operation_node(&lamp->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PARAMETERS_EVAL);
+ op_node->set_as_exit();
/* lamp's nodetree */
build_nodetree(lamp->nodetree);
- /* textures */
- build_texture_stack(lamp->mtex);
}
void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
@@ -969,16 +1416,26 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
if (built_map_.checkIsBuiltAndTag(ntree)) {
return;
}
-
/* nodetree itself */
- OperationDepsNode *op_node;
+ add_id_node(&ntree->id);
+ bNodeTree *ntree_cow = get_cow_datablock(ntree);
+ /* Animation, */
build_animdata(&ntree->id);
- /* Parameters for drivers. */
- op_node = add_operation_node(&ntree->id,
- DEG_NODE_TYPE_PARAMETERS,
- NULL,
- DEG_OPCODE_PARAMETERS_EVAL);
- op_node->set_as_exit();
+ /* Shading update. */
+ add_operation_node(&ntree->id,
+ DEG_NODE_TYPE_SHADING,
+ NULL,
+ DEG_OPCODE_MATERIAL_UPDATE);
+ /* NOTE: We really pass original and CoW node trees here, this is how the
+ * callback works. Ideally we need to find a better way for that.
+ */
+ add_operation_node(&ntree->id,
+ DEG_NODE_TYPE_SHADING_PARAMETERS,
+ function_bind(BKE_nodetree_shading_params_eval,
+ _1,
+ ntree_cow,
+ ntree),
+ DEG_OPCODE_MATERIAL_UPDATE);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
ID *id = bnode->id;
@@ -996,7 +1453,8 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
build_image((Image *)id);
}
else if (id_type == ID_OB) {
- build_object(NULL, (Object *)id);
+ /* TODO(sergey): Use visibility of owner of the node tree. */
+ build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, true);
}
else if (id_type == ID_SCE) {
/* Scenes are used by compositor trees, and handled by render
@@ -1006,6 +1464,12 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
else if (id_type == ID_TXT) {
/* Ignore script nodes. */
}
+ else if (id_type == ID_MSK) {
+ build_mask((Mask *)id);
+ }
+ else if (id_type == ID_MC) {
+ build_movieclip((MovieClip *)id);
+ }
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)id;
build_nodetree(group_ntree);
@@ -1024,30 +1488,22 @@ void DepsgraphNodeBuilder::build_material(Material *material)
if (built_map_.checkIsBuiltAndTag(material)) {
return;
}
- add_operation_node(&material->id, DEG_NODE_TYPE_SHADING, NULL,
- DEG_OPCODE_PLACEHOLDER, "Material Update");
-
- /* material animation */
+ /* Material itself. */
+ add_id_node(&material->id);
+ Material *material_cow = get_cow_datablock(material);
+ /* Shading update. */
+ add_operation_node(&material->id,
+ DEG_NODE_TYPE_SHADING,
+ function_bind(BKE_material_eval,
+ _1,
+ material_cow),
+ DEG_OPCODE_MATERIAL_UPDATE);
+ /* Material animation. */
build_animdata(&material->id);
- /* textures */
- build_texture_stack(material->mtex);
- /* material's nodetree */
+ /* Material's nodetree. */
build_nodetree(material->nodetree);
}
-/* Texture-stack attached to some shading datablock */
-void DepsgraphNodeBuilder::build_texture_stack(MTex **texture_stack)
-{
- int i;
-
- /* for now assume that all texture-stacks have same number of max items */
- for (i = 0; i < MAX_MTEX; i++) {
- MTex *mtex = texture_stack[i];
- if (mtex && mtex->tex)
- build_texture(mtex->tex);
- }
-}
-
/* Recursively build graph for texture */
void DepsgraphNodeBuilder::build_texture(Tex *texture)
{
@@ -1090,13 +1546,18 @@ void DepsgraphNodeBuilder::build_compositor(Scene *scene)
// XXX: component type undefined!
//graph->get_node(&scene->id, NULL, DEG_NODE_TYPE_COMPOSITING, NULL);
- /* for now, nodetrees are just parameters; compositing occurs in internals of renderer... */
+ /* for now, nodetrees are just parameters; compositing occurs in internals
+ * of renderer...
+ */
add_component_node(&scene->id, DEG_NODE_TYPE_PARAMETERS);
build_nodetree(scene->nodetree);
}
void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
{
+ if (built_map_.checkIsBuiltAndTag(gpd)) {
+ return;
+ }
ID *gpd_id = &gpd->id;
/* TODO(sergey): what about multiple users of same datablock? This should
@@ -1111,6 +1572,9 @@ void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
{
+ if (built_map_.checkIsBuiltAndTag(cache_file)) {
+ return;
+ }
ID *cache_file_id = &cache_file->id;
/* Animation, */
build_animdata(cache_file_id);
@@ -1121,30 +1585,71 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
void DepsgraphNodeBuilder::build_mask(Mask *mask)
{
+ if (built_map_.checkIsBuiltAndTag(mask)) {
+ return;
+ }
ID *mask_id = &mask->id;
+ Mask *mask_cow = get_cow_datablock(mask);
/* F-Curve based animation. */
build_animdata(mask_id);
/* Animation based on mask's shapes. */
add_operation_node(mask_id,
DEG_NODE_TYPE_ANIMATION,
- function_bind(BKE_mask_eval_animation, _1, mask),
+ function_bind(BKE_mask_eval_animation, _1, mask_cow),
DEG_OPCODE_MASK_ANIMATION);
/* Final mask evaluation. */
add_operation_node(mask_id,
DEG_NODE_TYPE_PARAMETERS,
- function_bind(BKE_mask_eval_update, _1, mask),
+ function_bind(BKE_mask_eval_update, _1, mask_cow),
DEG_OPCODE_MASK_EVAL);
}
-void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) {
+void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip)
+{
+ if (built_map_.checkIsBuiltAndTag(clip)) {
+ return;
+ }
ID *clip_id = &clip->id;
+ MovieClip *clip_cow = (MovieClip *)ensure_cow_id(clip_id);
/* Animation. */
build_animdata(clip_id);
/* Movie clip evaluation. */
add_operation_node(clip_id,
DEG_NODE_TYPE_PARAMETERS,
- function_bind(BKE_movieclip_eval_update, _1, clip),
+ function_bind(BKE_movieclip_eval_update, _1, clip_cow),
DEG_OPCODE_MOVIECLIP_EVAL);
+
+ add_operation_node(clip_id,
+ DEG_NODE_TYPE_BATCH_CACHE,
+ function_bind(BKE_movieclip_eval_selection_update, _1, clip_cow),
+ DEG_OPCODE_MOVIECLIP_SELECT_UPDATE);
+}
+
+void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe)
+{
+ if (built_map_.checkIsBuiltAndTag(probe)) {
+ return;
+ }
+ /* Placeholder so we can add relations and tag ID node for update. */
+ add_operation_node(&probe->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_LIGHT_PROBE_EVAL);
+
+ build_animdata(&probe->id);
+}
+
+void DepsgraphNodeBuilder::build_speaker(Speaker *speaker)
+{
+ if (built_map_.checkIsBuiltAndTag(speaker)) {
+ return;
+ }
+ /* Placeholder so we can add relations and tag ID node for update. */
+ add_operation_node(&speaker->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_SPEAKER_EVAL);
+ build_animdata(&speaker->id);
}
/* **** ID traversal callbacks functions **** */
@@ -1161,13 +1666,15 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data,
}
switch (GS(id->name)) {
case ID_OB:
- data->builder->build_object(NULL, (Object *)id);
- break;
- case ID_TE:
- data->builder->build_texture((Tex *)id);
+ /* Special case for object, so we take owner visibility into
+ * account. */
+ data->builder->build_object(-1,
+ (Object *)id,
+ DEG_ID_LINKED_INDIRECTLY,
+ data->is_parent_visible);
break;
default:
- /* pass */
+ data->builder->build_id(id);
break;
}
}
@@ -1184,13 +1691,17 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/,
}
switch (GS(id->name)) {
case ID_OB:
- data->builder->build_object(NULL, (Object *)id);
+ /* Special case for object, so we take owner visibility into
+ * account. */
+ data->builder->build_object(-1,
+ (Object *)id,
+ DEG_ID_LINKED_INDIRECTLY,
+ data->is_parent_visible);
break;
default:
- /* pass */
+ data->builder->build_id(id);
break;
}
}
-
} // 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 5ecfbf2f692..3b795bf9d58 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -33,16 +33,26 @@
#include "intern/builder/deg_builder_map.h"
#include "intern/depsgraph_types.h"
+#include "DEG_depsgraph.h"
+
+#include "intern/nodes/deg_node_id.h"
+
struct Base;
+struct bArmature;
+struct bAction;
struct CacheFile;
+struct Camera;
struct bGPdata;
struct ListBase;
struct GHash;
struct ID;
struct Image;
struct FCurve;
-struct Group;
+struct Collection;
struct Key;
+struct Lamp;
+struct LayerCollection;
+struct LightProbe;
struct Main;
struct Material;
struct Mask;
@@ -50,9 +60,12 @@ struct MTex;
struct MovieClip;
struct bNodeTree;
struct Object;
+struct ParticleSettings;
+struct Probe;
struct bPoseChannel;
struct bConstraint;
struct Scene;
+struct Speaker;
struct Tex;
struct World;
@@ -71,9 +84,30 @@ struct DepsgraphNodeBuilder {
DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
~DepsgraphNodeBuilder();
+ /* For given original ID get ID which is created by CoW system. */
+ ID *get_cow_id(const ID *id_orig) const;
+ /* Similar to above, but for the cases when there is no ID node we create
+ * one.
+ */
+ ID *ensure_cow_id(ID *id_orig);
+
+ /* Helper wrapper function which wraps get_cow_id with a needed type cast. */
+ template<typename T>
+ T *get_cow_datablock(const T *orig) const {
+ return (T *)get_cow_id(&orig->id);
+ }
+
+ /* For a given COW datablock get corresponding original one. */
+ template<typename T>
+ T *get_orig_datablock(const T *cow) const {
+ return (T *)cow->id.orig_id;
+ }
+
void begin_build();
+ void end_build();
IDDepsNode *add_id_node(ID *id);
+ IDDepsNode *find_id_node(ID *id);
TimeSourceDepsNode *add_time_source();
ComponentDepsNode *add_component_node(ID *id,
@@ -127,18 +161,41 @@ struct DepsgraphNodeBuilder {
int name_tag = -1);
void build_id(ID *id);
- void build_scene(Scene *scene);
- void build_group(Base *base, Group *group);
- void build_object(Base *base, Object *object);
- void build_object_data(Object *object);
+ void build_layer_collections(ListBase *lb);
+ void build_view_layer(Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state);
+ void build_collection(LayerCollection *from_layer_collection,
+ Collection *collection);
+ void build_object(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state,
+ bool is_visible);
+ void build_object_flags(int base_index,
+ Object *object,
+ eDepsNode_LinkedState_Type linked_state);
+ void build_object_data(Object *object, bool is_object_visible);
+ void build_object_data_camera(Object *object);
+ void build_object_data_geometry(Object *object, bool is_object_visible);
+ void build_object_data_geometry_datablock(ID *obdata,
+ bool is_object_visible);
+ void build_object_data_lamp(Object *object);
+ void build_object_data_lightprobe(Object *object);
+ void build_object_data_speaker(Object *object);
void build_object_transform(Object *object);
void build_object_constraints(Object *object);
- void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index);
+ void build_object_pointcache(Object *object);
+ void build_pose_constraints(Object *object,
+ bPoseChannel *pchan,
+ int pchan_index,
+ bool is_object_visible);
void build_rigidbody(Scene *scene);
- void build_particles(Object *object);
- void build_cloth(Object *object);
+ void build_particles(Object *object, bool is_object_visible);
+ void build_particle_settings(ParticleSettings *part);
void build_animdata(ID *id);
- void build_driver(ID *id, FCurve *fcurve);
+ void build_animdata_nlastrip_targets(ListBase *strips);
+ void build_action(bAction *action);
+ void build_driver(ID *id, FCurve *fcurve, int driver_index);
void build_driver_variables(ID *id, FCurve *fcurve);
void build_driver_id_property(ID *id, const char *rna_path);
void build_ik_pose(Object *object,
@@ -147,16 +204,15 @@ struct DepsgraphNodeBuilder {
void build_splineik_pose(Object *object,
bPoseChannel *pchan,
bConstraint *con);
- void build_rig(Object *object);
+ void build_rig(Object *object, bool is_object_visible);
void build_proxy_rig(Object *object);
+ void build_armature(bArmature *armature);
void build_shapekeys(Key *key);
- void build_obdata_geom(Object *object);
- void build_camera(Object *object);
- void build_lamp(Object *object);
+ void build_camera(Camera *camera);
+ void build_lamp(Lamp *lamp);
void build_nodetree(bNodeTree *ntree);
void build_material(Material *ma);
void build_texture(Tex *tex);
- void build_texture_stack(MTex **texture_stack);
void build_image(Image *image);
void build_world(World *world);
void build_compositor(Scene *scene);
@@ -164,17 +220,46 @@ struct DepsgraphNodeBuilder {
void build_cachefile(CacheFile *cache_file);
void build_mask(Mask *mask);
void build_movieclip(MovieClip *clip);
+ void build_lightprobe(LightProbe *probe);
+ void build_speaker(Speaker *speaker);
+
+ /* Per-ID information about what was already in the dependency graph.
+ * Allows to re-use certain values, to speed up following evaluation.
+ */
+ struct IDInfo {
+ /* Copy-on-written pointer of the corresponding ID. */
+ ID *id_cow;
+ /* Mask of visible components from previous state of the
+ * dependency graph.
+ */
+ IDComponentsMask previously_visible_components_mask;
+ /* Special evaluation flag mask from the previous depsgraph. */
+ uint32_t previous_eval_flags;
+ };
protected:
+ /* Allows to identify an operation which was tagged for update at the time
+ * relations are being updated. We can not reuse operation node pointer
+ * since it will change during dependency graph construction.
+ */
+ struct SavedEntryTag {
+ ID *id_orig;
+ eDepsNode_Type component_type;
+ eDepsOperation_Code opcode;
+ const char *name;
+ int name_tag;
+ };
+ vector<SavedEntryTag> saved_entry_tags_;
+
struct BuilderWalkUserData {
DepsgraphNodeBuilder *builder;
+ /* Denotes whether object the walk is invoked from is visible. */
+ bool is_parent_visible;
};
-
static void modifier_walk(void *user_data,
struct Object *object,
struct ID **idpoin,
int cb_flag);
-
static void constraint_walk(bConstraint *constraint,
ID **idpoin,
bool is_reference,
@@ -186,7 +271,24 @@ protected:
/* State which demotes currently built entities. */
Scene *scene_;
+ ViewLayer *view_layer_;
+ int view_layer_index_;
+ /* NOTE: Collection are possibly built recursively, so be careful when
+ * setting the current state.
+ */
+ Collection *collection_;
+ /* Accumulated flag over the hierarchy opf currently building collections.
+ * Denotes whether all the hierarchy from parent of collection_ to the
+ * very root is visible (aka not restricted.).
+ */
+ bool is_parent_collection_visible_;
+
+ /* Indexed by original ID, values are IDInfo. */
+ GHash *id_info_hash_;
+ /* Set of IDs which were already build. Makes it easier to keep track of
+ * what was already built and what was not.
+ */
BuilderMap built_map_;
};
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 5824858d7ed..8c349b7067f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -46,6 +46,7 @@ extern "C" {
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -56,6 +57,7 @@ extern "C" {
#include "DEG_depsgraph_build.h"
#include "intern/builder/deg_builder.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -65,20 +67,23 @@ extern "C" {
namespace DEG {
-void DepsgraphNodeBuilder::build_pose_constraints(Object *object,
- bPoseChannel *pchan,
- int pchan_index)
+void DepsgraphNodeBuilder::build_pose_constraints(
+ Object *object,
+ bPoseChannel *pchan,
+ int pchan_index,
+ bool is_object_visible)
{
/* Pull indirect dependencies via constraints. */
BuilderWalkUserData data;
data.builder = this;
+ data.is_parent_visible = is_object_visible;
BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
/* Create node for constraint stack. */
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
function_bind(BKE_pose_constraints_evaluate,
_1,
- scene_,
- object,
+ get_cow_datablock(scene_),
+ get_cow_datablock(object),
pchan_index),
DEG_OPCODE_BONE_CONSTRAINTS);
}
@@ -108,8 +113,8 @@ void DepsgraphNodeBuilder::build_ik_pose(Object *object,
add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
function_bind(BKE_pose_iktree_evaluate,
_1,
- scene_,
- object,
+ get_cow_datablock(scene_),
+ get_cow_datablock(object),
rootchan_index),
DEG_OPCODE_POSE_IK_SOLVER);
}
@@ -125,44 +130,42 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object,
bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
/* Operation node for evaluating/running Spline IK Solver.
- * Store the "root bone" of this chain in the solver, so it knows where to start.
+ * Store the "root bone" of this chain in the solver, so it knows where to
+ * start.
*/
int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan);
BLI_assert(rootchan_index != -1);
add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
function_bind(BKE_pose_splineik_evaluate,
_1,
- scene_,
- object,
+ get_cow_datablock(scene_),
+ get_cow_datablock(object),
rootchan_index),
DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
}
/* Pose/Armature Bones Graph */
-void DepsgraphNodeBuilder::build_rig(Object *object)
+void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
{
- bArmature *arm = (bArmature *)object->data;
+ bArmature *armature = (bArmature *)object->data;
+ Scene *scene_cow = get_cow_datablock(scene_);
+ Object *object_cow = get_cow_datablock(object);
OperationDepsNode *op_node;
-
- /* animation and/or drivers linking posebones to base-armature used to define them
+ /* Animation and/or drivers linking posebones to base-armature used to
+ * define them.
+ *
* NOTE: AnimData here is really used to control animated deform properties,
- * which ideally should be able to be unique across different instances.
- * Eventually, we need some type of proxy/isolation mechanism in-between here
- * to ensure that we can use same rig multiple times in same scene...
+ * which ideally should be able to be unique across different
+ * instances. Eventually, we need some type of proxy/isolation
+ * mechanism in-between here to ensure that we can use same rig
+ * multiple times in same scene.
*/
- if (!built_map_.checkIsBuiltAndTag(arm)) {
- build_animdata(&arm->id);
- /* Make sure pose is up-to-date with armature updates. */
- add_operation_node(&arm->id,
- DEG_NODE_TYPE_PARAMETERS,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Armature Eval");
- }
-
+ /* Armature. */
+ build_armature(armature);
/* Rebuild pose if not up to date. */
if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild_ex(object, arm, false);
+ /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */
+ BKE_pose_rebuild(NULL, object, armature, true);
/* XXX: Without this animation gets lost in certain circumstances
* after loading file. Need to investigate further since it does
* not happen with simple scenes..
@@ -171,15 +174,13 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
object->adt->recalc |= ADT_RECALC_ANIM;
}
}
-
- /* speed optimization for animation lookups */
- if (object->pose) {
+ /* Speed optimization for animation lookups. */
+ if (object->pose != NULL) {
BKE_pose_channels_hash_make(object->pose);
if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(object->pose);
}
}
-
/**
* Pose Rig Graph
* ==============
@@ -197,18 +198,17 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
* - Used for representing each bone within the rig
* - Acts to encapsulate the evaluation operations (base matrix + parenting,
* and constraint stack) so that they can be easily found.
- * - Everything else which depends on bone-results hook up to the component only
- * so that we can redirect those to point at either the the post-IK/
+ * - Everything else which depends on bone-results hook up to the component
+ * only so that we can redirect those to point at either the the post-IK/
* post-constraint/post-matrix steps, as needed.
*/
-
- /* pose eval context */
+ /* Pose eval context. */
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
function_bind(BKE_pose_eval_init,
_1,
- scene_,
- object),
+ scene_cow,
+ object_cow),
DEG_OPCODE_POSE_INIT);
op_node->set_as_entry();
@@ -216,20 +216,26 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
DEG_NODE_TYPE_EVAL_POSE,
function_bind(BKE_pose_eval_init_ik,
_1,
- scene_,
- object),
+ scene_cow,
+ object_cow),
DEG_OPCODE_POSE_INIT_IK);
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_cleanup,
+ _1,
+ scene_cow,
+ object_cow),
+ DEG_OPCODE_POSE_CLEANUP);
+
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
- function_bind(BKE_pose_eval_flush,
+ function_bind(BKE_pose_eval_done,
_1,
- scene_,
- object),
+ object_cow),
DEG_OPCODE_POSE_DONE);
op_node->set_as_exit();
-
- /* bones */
+ /* Bones. */
int pchan_index = 0;
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
/* Node for bone evaluation. */
@@ -238,20 +244,35 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
op_node->set_as_entry();
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
- function_bind(BKE_pose_eval_bone, _1, scene_, object, pchan_index),
+ function_bind(BKE_pose_eval_bone, _1,
+ scene_cow,
+ object_cow,
+ pchan_index),
DEG_OPCODE_BONE_POSE_PARENT);
+ /* NOTE: Dedicated noop for easier relationship construction. */
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
- NULL, /* NOTE: dedicated noop for easier relationship construction */
+ NULL,
DEG_OPCODE_BONE_READY);
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
function_bind(BKE_pose_bone_done,
_1,
- object,
+ object_cow,
pchan_index),
DEG_OPCODE_BONE_DONE);
+
+ /* B-Bone shape computation - the real last step if present. */
+ if (pchan->bone != NULL && pchan->bone->segments > 1) {
+ op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
+ function_bind(BKE_pose_eval_bbone_segments, _1,
+ object_cow,
+ pchan_index),
+ DEG_OPCODE_BONE_SEGMENTS);
+ }
+
op_node->set_as_exit();
+
/* Custom properties. */
if (pchan->prop != NULL) {
add_operation_node(&object->id,
@@ -260,9 +281,10 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
DEG_OPCODE_PARAMETERS_EVAL,
pchan->name);
}
- /* Constraints. */
+ /* Build constraints. */
if (pchan->constraints.first != NULL) {
- build_pose_constraints(object, pchan, pchan_index);
+ build_pose_constraints(
+ object, pchan, pchan_index, is_object_visible);
}
/**
* IK Solvers.
@@ -273,8 +295,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
*
* Unsolved Issues:
* - Care is needed to ensure that multi-headed trees work out the same
- * as in ik-tree building.
- * - Animated chain-lengths are a problem...
+ * as in ik-tree building
+ * - Animated chain-lengths are a problem.
*/
LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
switch (con->type) {
@@ -290,48 +312,65 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
break;
}
}
-
/* Custom shape. */
if (pchan->custom != NULL) {
- build_object(NULL, pchan->custom);
+ /* TODO(sergey): Use own visibility. */
+ build_object(
+ -1,
+ pchan->custom,
+ DEG_ID_LINKED_INDIRECTLY,
+ is_object_visible);
}
-
pchan_index++;
}
}
void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
{
- bArmature *arm = (bArmature *)object->data;
+ bArmature *armature = (bArmature *)object->data;
OperationDepsNode *op_node;
-
- build_animdata(&arm->id);
-
+ Object *object_cow = get_cow_datablock(object);
+ /* Sanity check. */
BLI_assert(object->pose != NULL);
-
+ /* Armature. */
+ build_armature(armature);
/* speed optimization for animation lookups */
BKE_pose_channels_hash_make(object->pose);
if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(object->pose);
}
-
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
- function_bind(BKE_pose_eval_proxy_copy, _1, object),
+ function_bind(BKE_pose_eval_proxy_init,
+ _1,
+ object_cow),
DEG_OPCODE_POSE_INIT);
op_node->set_as_entry();
-
+ int pchan_index = 0;
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
- NULL, DEG_OPCODE_BONE_LOCAL);
+ op_node = add_operation_node(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ NULL,
+ DEG_OPCODE_BONE_LOCAL);
op_node->set_as_entry();
-
- add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
- NULL, DEG_OPCODE_BONE_READY);
-
- op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
- NULL, DEG_OPCODE_BONE_DONE);
+ /* Bone is ready for solvers. */
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ NULL,
+ DEG_OPCODE_BONE_READY);
+ /* Bone is fully evaluated. */
+ op_node = add_operation_node(
+ &object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ function_bind(BKE_pose_eval_proxy_copy_bone,
+ _1,
+ object_cow,
+ pchan_index),
+ DEG_OPCODE_BONE_DONE);
op_node->set_as_exit();
/* Custom properties. */
@@ -342,10 +381,21 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
DEG_OPCODE_PARAMETERS_EVAL,
pchan->name);
}
- }
- op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE,
- NULL, DEG_OPCODE_POSE_DONE);
+ pchan_index++;
+ }
+ op_node = add_operation_node(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_proxy_cleanup,
+ _1,
+ object_cow),
+ DEG_OPCODE_POSE_CLEANUP);
+ op_node = add_operation_node(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ function_bind(BKE_pose_eval_proxy_done,
+ _1,
+ object_cow),
+ DEG_OPCODE_POSE_DONE);
op_node->set_as_exit();
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
index 4bb15350f3a..70bd533647c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph's nodes
@@ -43,9 +43,11 @@
extern "C" {
#include "DNA_node_types.h"
+#include "DNA_layer_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
} /* extern "C" */
@@ -63,24 +65,63 @@ extern "C" {
namespace DEG {
-void DepsgraphNodeBuilder::build_scene(Scene *scene)
+void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb)
{
+ const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ?
+ COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER;
+
+ for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) {
+ if (lc->collection->flag & restrict_flag) {
+ continue;
+ }
+ if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
+ build_collection(lc, lc->collection);
+ }
+ build_layer_collections(&lc->layer_collections);
+ }
+}
+
+void DepsgraphNodeBuilder::build_view_layer(
+ Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state)
+{
+ /* NOTE: Pass view layer index of 0 since after scene CoW there is
+ * only one view layer in there. */
+ view_layer_index_ = 0;
/* Scene ID block. */
add_id_node(&scene->id);
- /* timesource */
+ /* Time source. */
add_time_source();
- /* build subgraph for set, and link this in... */
- // XXX: depending on how this goes, that scene itself could probably store its
- // own little partial depsgraph?
- if (scene->set != NULL) {
- build_scene(scene->set);
- }
/* Setup currently building context. */
scene_ = scene;
- /* scene objects */
- LISTBASE_FOREACH (Base *, base, &scene->base) {
- Object *object = base->object;
- build_object(base, object);
+ view_layer_ = view_layer;
+ /* Get pointer to a CoW version of scene ID. */
+ Scene *scene_cow = get_cow_datablock(scene);
+ /* Scene objects. */
+ int select_color = 1;
+ /* NOTE: Base is used for function bindings as-is, so need to pass CoW base,
+ * but object is expected to be an original one. Hence we go into some
+ * tricks here iterating over the view layer.
+ */
+ int base_index = 0;
+ const int base_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ?
+ BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER;
+ LISTBASE_FOREACH(Base *, base, &view_layer->object_bases) {
+ /* object itself */
+ const bool is_object_visible = (base->flag & base_flag);
+ if (is_object_visible) {
+ build_object(base_index,
+ base->object,
+ linked_state,
+ is_object_visible);
+ ++base_index;
+ }
+ base->object->select_color = select_color++;
+ }
+ build_layer_collections(&view_layer->layer_collections);
+ if (scene->camera != NULL) {
+ build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true);
}
/* Rigidbody. */
if (scene->rigidbody_world != NULL) {
@@ -94,14 +135,10 @@ void DepsgraphNodeBuilder::build_scene(Scene *scene)
if (scene->world != NULL) {
build_world(scene->world);
}
- /* Compositor nodes. */
+ /* Compositor nodes */
if (scene->nodetree != NULL) {
build_compositor(scene);
}
- /* Grease pencil. */
- if (scene->gpd != NULL) {
- build_gpencil(scene->gpd);
- }
/* Cache file. */
LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) {
build_cachefile(cachefile);
@@ -114,12 +151,25 @@ void DepsgraphNodeBuilder::build_scene(Scene *scene)
LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
build_movieclip(clip);
}
+ /* Collections. */
+ add_operation_node(&scene->id,
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ function_bind(BKE_layer_eval_view_layer_indexed,
+ _1,
+ scene_cow,
+ view_layer_index_),
+ DEG_OPCODE_VIEW_LAYER_EVAL);
/* Parameters evaluation for scene relations mainly. */
add_operation_node(&scene->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PLACEHOLDER,
"Scene Eval");
+ /* Build all set scenes. */
+ if (scene->set != NULL) {
+ ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set);
+ build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET);
+ }
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 19bf2983033..8af6b2f3a97 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -47,11 +47,11 @@ extern "C" {
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
#include "DNA_cachefile_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_effect_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@@ -61,9 +61,11 @@ extern "C" {
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
#include "DNA_particle_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
+#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "DNA_object_force_types.h"
@@ -71,22 +73,24 @@ extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_collision.h"
#include "BKE_fcurve.h"
-#include "BKE_group.h"
#include "BKE_key.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
+#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
+#include "BKE_shader_fx.h"
+#include "BKE_shrinkwrap.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
#include "BKE_world.h"
@@ -100,6 +104,7 @@ extern "C" {
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_pchanmap.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
@@ -160,6 +165,9 @@ static bool particle_system_depends_on_time(ParticleSystem *psys)
static bool object_particles_depends_on_time(Object *object)
{
+ if (object->type != OB_MESH) {
+ return false;
+ }
LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
if (particle_system_depends_on_time(psys)) {
return true;
@@ -168,6 +176,47 @@ static bool object_particles_depends_on_time(Object *object)
return false;
}
+static bool check_id_has_anim_component(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
+ return false;
+ }
+ return (adt->action != NULL) ||
+ (!BLI_listbase_is_empty(&adt->nla_tracks));
+}
+
+static eDepsOperation_Code bone_target_opcode(ID *target,
+ const char *subtarget,
+ ID *id,
+ const char *component_subdata,
+ RootPChanMap *root_map)
+{
+ /* Same armature. */
+ if (target == id) {
+ /* Using "done" here breaks in-chain deps, while using
+ * "ready" here breaks most production rigs instead.
+ * So, we do a compromise here, and only do this when an
+ * IK chain conflict may occur.
+ */
+ if (root_map->has_common_root(component_subdata, subtarget)) {
+ return DEG_OPCODE_BONE_READY;
+ }
+ }
+ return DEG_OPCODE_BONE_DONE;
+}
+
+static bool bone_has_segments(Object *object, const char *bone_name)
+{
+ /* Proxies don't have BONE_SEGMENTS */
+ if (ID_IS_LINKED(object) && object->proxy_from != NULL) {
+ return false;
+ }
+ /* Only B-Bones have segments. */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name);
+ return pchan && pchan->bone && pchan->bone->segments > 1;
+}
+
/* **** General purpose functions **** */
DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain,
@@ -210,7 +259,7 @@ OperationDepsNode *DepsgraphRelationBuilder::get_node(
OperationDepsNode *op_node = find_node(key);
if (op_node == NULL) {
fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n",
- DEG_OPNAMES[key.opcode], key.name);
+ operationCodeAsString(key.opcode), key.name);
}
return op_node;
}
@@ -240,17 +289,42 @@ bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const
return find_node(key) != NULL;
}
+void DepsgraphRelationBuilder::add_customdata_mask(const ComponentKey &key, uint64_t mask)
+{
+ if (mask != 0) {
+ OperationDepsNode *node = find_operation_node(key);
+
+ if (node != NULL) {
+ node->customdata_mask |= mask;
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::add_special_eval_flag(ID *id, uint32_t flag)
+{
+ DEG::IDDepsNode *id_node = graph_->find_id_node(id);
+ if (id_node == NULL) {
+ BLI_assert(!"ID should always be valid");
+ }
+ else {
+ id_node->eval_flags |= flag;
+ }
+}
+
DepsRelation *DepsgraphRelationBuilder::add_time_relation(
TimeSourceDepsNode *timesrc,
DepsNode *node_to,
const char *description,
- bool check_unique)
+ bool check_unique,
+ int flags)
{
if (timesrc && node_to) {
- return graph_->add_new_relation(timesrc, node_to, description, check_unique);
+ return graph_->add_new_relation(
+ timesrc, node_to, description, check_unique, flags);
}
else {
- DEG_DEBUG_PRINTF(BUILD, "add_time_relation(%p = %s, %p = %s, %s) Failed\n",
+ DEG_DEBUG_PRINTF((::Depsgraph *)graph_,
+ BUILD, "add_time_relation(%p = %s, %p = %s, %s) Failed\n",
timesrc, (timesrc) ? timesrc->identifier().c_str() : "<None>",
node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
description);
@@ -262,16 +336,19 @@ DepsRelation *DepsgraphRelationBuilder::add_operation_relation(
OperationDepsNode *node_from,
OperationDepsNode *node_to,
const char *description,
- bool check_unique)
+ bool check_unique,
+ int flags)
{
if (node_from && node_to) {
return graph_->add_new_relation(node_from,
node_to,
description,
- check_unique);
+ check_unique,
+ flags);
}
else {
- DEG_DEBUG_PRINTF(BUILD, "add_operation_relation(%p = %s, %p = %s, %s) Failed\n",
+ DEG_DEBUG_PRINTF((::Depsgraph *)graph_,
+ BUILD, "add_operation_relation(%p = %s, %p = %s, %s) Failed\n",
node_from, (node_from) ? node_from->identifier().c_str() : "<None>",
node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
description);
@@ -281,93 +358,72 @@ DepsRelation *DepsgraphRelationBuilder::add_operation_relation(
void DepsgraphRelationBuilder::add_collision_relations(
const OperationKey &key,
- Scene *scene,
Object *object,
- Group *group,
- int layer,
- bool dupli,
+ Collection *collection,
const char *name)
{
- unsigned int numcollobj;
- Object **collobjs = get_collisionobjects_ext(
- scene,
- object,
- group,
- layer,
- &numcollobj,
- eModifierType_Collision,
- dupli);
- for (unsigned int i = 0; i < numcollobj; i++) {
- Object *ob1 = collobjs[i];
+ ListBase *relations = deg_build_collision_relations(graph_, collection, eModifierType_Collision);
- ComponentKey trf_key(&ob1->id, DEG_NODE_TYPE_TRANSFORM);
- add_relation(trf_key, key, name);
+ LISTBASE_FOREACH (CollisionRelation *, relation, relations) {
+ if (relation->ob != object) {
+ ComponentKey trf_key(&relation->ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(trf_key, key, name);
- ComponentKey coll_key(&ob1->id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(coll_key, key, name);
- }
- if (collobjs != NULL) {
- MEM_freeN(collobjs);
+ ComponentKey coll_key(&relation->ob->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(coll_key, key, name);
+ }
}
}
void DepsgraphRelationBuilder::add_forcefield_relations(
const OperationKey &key,
- Scene *scene,
Object *object,
ParticleSystem *psys,
EffectorWeights *eff,
bool add_absorption,
const char *name)
{
- ListBase *effectors = pdInitEffectors(scene, object, psys, eff, false);
- if (effectors != NULL) {
- LISTBASE_FOREACH(EffectorCache *, eff, effectors) {
- if (eff->ob != object) {
- ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM);
- add_relation(eff_key, key, name);
- }
- if (eff->psys != NULL) {
- if (eff->ob != object) {
- ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
- add_relation(eff_key, key, name);
+ ListBase *relations = deg_build_effector_relations(graph_, eff->group);
- /* TODO: remove this when/if EVAL_PARTICLES is sufficient
- * for up to date particles.
- */
- ComponentKey mod_key(&eff->ob->id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(mod_key, key, name);
- }
- else if (eff->psys != psys) {
- OperationKey eff_key(&eff->ob->id,
- DEG_NODE_TYPE_EVAL_PARTICLES,
- DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
- eff->psys->name);
- add_relation(eff_key, key, name);
- }
- }
- if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- ComponentKey trf_key(&eff->pd->f_source->id,
+ LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
+ if (relation->ob != object) {
+ ComponentKey eff_key(&relation->ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(eff_key, key, name);
+
+ if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source) {
+ ComponentKey trf_key(&relation->pd->f_source->id,
DEG_NODE_TYPE_TRANSFORM);
add_relation(trf_key, key, "Smoke Force Domain");
-
- ComponentKey eff_key(&eff->pd->f_source->id,
+ ComponentKey eff_key(&relation->pd->f_source->id,
DEG_NODE_TYPE_GEOMETRY);
add_relation(eff_key, key, "Smoke Force Domain");
}
- if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
+ if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) {
add_collision_relations(key,
- scene,
object,
NULL,
- eff->ob->lay,
- true,
"Force Absorption");
}
}
+ if (relation->psys) {
+ if (relation->ob != object) {
+ ComponentKey eff_key(&relation->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
+ add_relation(eff_key, key, name);
+ /* TODO: remove this when/if EVAL_PARTICLES is sufficient
+ * for up to date particles.
+ */
+ ComponentKey mod_key(&relation->ob->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(mod_key, key, name);
+ }
+ else if (relation->psys != psys) {
+ OperationKey eff_key(&relation->ob->id,
+ DEG_NODE_TYPE_EVAL_PARTICLES,
+ DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
+ relation->psys->name);
+ add_relation(eff_key, key, name);
+ }
+ }
}
-
- pdEndEffectors(&effectors);
}
Depsgraph *DepsgraphRelationBuilder::getGraph()
@@ -381,26 +437,132 @@ void DepsgraphRelationBuilder::begin_build()
{
}
-void DepsgraphRelationBuilder::build_group(Object *object, Group *group)
+void DepsgraphRelationBuilder::build_id(ID *id)
+{
+ if (id == NULL) {
+ return;
+ }
+ switch (GS(id->name)) {
+ case ID_AC:
+ build_action((bAction *)id);
+ break;
+ case ID_AR:
+ build_armature((bArmature *)id);
+ break;
+ case ID_CA:
+ build_camera((Camera *)id);
+ break;
+ case ID_GR:
+ build_collection(NULL, NULL, (Collection *)id);
+ break;
+ case ID_OB:
+ build_object(NULL, (Object *)id);
+ break;
+ case ID_KE:
+ build_shapekeys((Key *)id);
+ break;
+ case ID_LA:
+ build_lamp((Lamp *)id);
+ break;
+ case ID_LP:
+ build_lightprobe((LightProbe *)id);
+ break;
+ case ID_NT:
+ build_nodetree((bNodeTree *)id);
+ break;
+ case ID_MA:
+ build_material((Material *)id);
+ break;
+ case ID_TE:
+ build_texture((Tex *)id);
+ break;
+ case ID_WO:
+ build_world((World *)id);
+ break;
+ case ID_MSK:
+ build_mask((Mask *)id);
+ break;
+ case ID_MC:
+ build_movieclip((MovieClip *)id);
+ break;
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ case ID_LT:
+ build_object_data_geometry_datablock(id);
+ break;
+ case ID_SPK:
+ build_speaker((Speaker *)id);
+ break;
+ case ID_TXT:
+ /* Not a part of dependency graph. */
+ break;
+ default:
+ fprintf(stderr, "Unhandled ID %s\n", id->name);
+ BLI_assert(!"Should never happen");
+ break;
+ }
+}
+
+void DepsgraphRelationBuilder::build_collection(
+ LayerCollection *from_layer_collection,
+ Object *object,
+ Collection *collection)
{
- const bool group_done = built_map_.checkIsBuiltAndTag(group);
- OperationKey object_local_transform_key(object != NULL ? &object->id : NULL,
+ if (from_layer_collection != NULL) {
+ /* If we came from layer collection we don't go deeper, view layer
+ * builder takes care of going deeper.
+ *
+ * NOTE: Do early output before tagging build as done, so possbile
+ * subsequent builds from outside of the layer collection properly
+ * recurses into all the nested objects and collections. */
+ return;
+ }
+ const bool group_done = built_map_.checkIsBuiltAndTag(collection);
+ OperationKey object_transform_final_key(object != NULL ? &object->id : NULL,
DEG_NODE_TYPE_TRANSFORM,
- DEG_OPCODE_TRANSFORM_LOCAL);
- LISTBASE_FOREACH (GroupObject *, go, &group->gobject) {
- if (!group_done) {
- build_object(go->ob);
+ DEG_OPCODE_TRANSFORM_FINAL);
+ ComponentKey duplicator_key(object != NULL ? &object->id : NULL,
+ DEG_NODE_TYPE_DUPLI);
+ if (!group_done) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ build_object(NULL, cob->ob);
}
- if (object != NULL) {
- ComponentKey dupli_transform_key(&go->ob->id, DEG_NODE_TYPE_TRANSFORM);
- add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup");
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
+ build_collection(NULL, NULL, child->collection);
}
}
+ if (object != NULL) {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(collection, ob, graph_->mode)
+ {
+ ComponentKey dupli_transform_key(&ob->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(dupli_transform_key,
+ object_transform_final_key,
+ "Dupligroup");
+ /* Hook to special component, to ensure proper visibility/evaluation
+ * optimizations.
+ */
+ add_relation(dupli_transform_key, duplicator_key, "Dupligroup");
+ const eDepsNode_Type dupli_geometry_component_type =
+ deg_geometry_tag_to_component(&ob->id);
+ if (dupli_geometry_component_type != DEG_NODE_TYPE_UNDEFINED) {
+ ComponentKey dupli_geometry_component_key(
+ &ob->id, dupli_geometry_component_type);
+ add_relation(dupli_geometry_component_key,
+ duplicator_key,
+ "Dupligroup");
+ }
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
}
-void DepsgraphRelationBuilder::build_object(Object *object)
+void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
{
if (built_map_.checkIsBuiltAndTag(object)) {
+ if (base != NULL) {
+ build_object_flags(base, object);
+ }
return;
}
/* Object Transforms */
@@ -419,10 +581,12 @@ void DepsgraphRelationBuilder::build_object(Object *object)
OperationKey ob_ubereval_key(&object->id,
DEG_NODE_TYPE_TRANSFORM,
DEG_OPCODE_TRANSFORM_OBJECT_UBEREVAL);
+ /* Various flags, flushing from bases/collections. */
+ build_object_flags(base, object);
/* Parenting. */
if (object->parent != NULL) {
/* Make sure parent object's relations are built. */
- build_object(object->parent);
+ build_object(NULL, object->parent);
/* Parent relationship. */
build_object_parent(object);
/* Local -> parent. */
@@ -436,6 +600,18 @@ void DepsgraphRelationBuilder::build_object(Object *object)
data.builder = this;
modifiers_foreachIDLink(object, modifier_walk, &data);
}
+ /* Grease Pencil Modifiers. */
+ if (object->greasepencil_modifiers.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data);
+ }
+ /* Shader FX. */
+ if (object->shader_fx.first != NULL) {
+ BuilderWalkUserData data;
+ data.builder = this;
+ BKE_shaderfx_foreachIDLink(object, modifier_walk, &data);
+ }
/* Constraints. */
if (object->constraints.first != NULL) {
BuilderWalkUserData data;
@@ -481,25 +657,40 @@ void DepsgraphRelationBuilder::build_object(Object *object)
if (object->particlesystem.first != NULL) {
build_particles(object);
}
- /* Grease pencil. */
- if (object->gpd != NULL) {
- build_gpencil(object->gpd);
+ /* Proxy object to copy from. */
+ if (object->proxy_from != NULL) {
+ build_object(NULL, object->proxy_from);
+ ComponentKey ob_transform_key(&object->proxy_from->id, DEG_NODE_TYPE_TRANSFORM);
+ ComponentKey proxy_transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform");
}
- /* Object that this is a proxy for. */
- if (object->proxy != NULL) {
- object->proxy->proxy_from = object;
- build_object(object->proxy);
- /* TODO(sergey): This is an inverted relation, matches old depsgraph
- * behavior and need to be investigated if it still need to be inverted.
- */
- ComponentKey ob_pose_key(&object->id, DEG_NODE_TYPE_EVAL_POSE);
- ComponentKey proxy_pose_key(&object->proxy->id, DEG_NODE_TYPE_EVAL_POSE);
- add_relation(ob_pose_key, proxy_pose_key, "Proxy");
+ if (object->proxy_group != NULL) {
+ build_object(NULL, object->proxy_group);
+ OperationKey proxy_group_ubereval_key(&object->proxy_group->id,
+ DEG_NODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_OBJECT_UBEREVAL);
+ add_relation(proxy_group_ubereval_key, final_transform_key, "Proxy Group Transform");
}
/* Object dupligroup. */
if (object->dup_group != NULL) {
- build_group(object, object->dup_group);
+ build_collection(NULL, object, object->dup_group);
}
+ /* Point caches. */
+ build_object_pointcache(object);
+}
+
+void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object)
+{
+ if (base == NULL) {
+ return;
+ }
+ OperationKey view_layer_done_key(&scene_->id,
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ DEG_OPCODE_VIEW_LAYER_EVAL);
+ OperationKey object_flags_key(&object->id,
+ DEG_NODE_TYPE_OBJECT_FROM_LAYER,
+ DEG_OPCODE_OBJECT_BASE_FLAGS);
+ add_relation(view_layer_done_key, object_flags_key, "Base flags flush");
}
void DepsgraphRelationBuilder::build_object_data(Object *object)
@@ -520,8 +711,18 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
case OB_SURF:
case OB_MBALL:
case OB_LATTICE:
+ case OB_GPENCIL:
{
- build_obdata_geom(object);
+ build_object_data_geometry(object);
+ /* TODO(sergey): Only for until we support granular
+ * update of curves.
+ */
+ if (object->type == OB_FONT) {
+ Curve *curve = (Curve *)object->data;
+ if (curve->textoncurve) {
+ add_special_eval_flag(&curve->textoncurve->id, DAG_EVAL_NEED_CURVE_PATH);
+ }
+ }
break;
}
case OB_ARMATURE:
@@ -533,10 +734,16 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
}
break;
case OB_LAMP:
- build_lamp(object);
+ build_object_data_lamp(object);
break;
case OB_CAMERA:
- build_camera(object);
+ build_object_data_camera(object);
+ break;
+ case OB_LIGHTPROBE:
+ build_object_data_lightprobe(object);
+ break;
+ case OB_SPEAKER:
+ build_object_data_speaker(object);
break;
}
Key *key = BKE_key_from_object(object);
@@ -544,9 +751,54 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
ComponentKey geometry_key((ID *)object->data, DEG_NODE_TYPE_GEOMETRY);
ComponentKey key_key(&key->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(key_key, geometry_key, "Shapekeys");
+ build_nested_shapekey(&object->id, key);
}
}
+void DepsgraphRelationBuilder::build_object_data_camera(Object *object)
+{
+ Camera *camera = (Camera *)object->data;
+ build_camera(camera);
+ ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(camera_parameters_key, object_parameters_key, "Camera -> Object");
+}
+
+void DepsgraphRelationBuilder::build_object_data_lamp(Object *object)
+{
+ Lamp *lamp = (Lamp *)object->data;
+ build_lamp(lamp);
+ ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(lamp_parameters_key, object_parameters_key, "Light -> Object");
+}
+
+void DepsgraphRelationBuilder::build_object_data_lightprobe(Object *object)
+{
+ LightProbe *probe = (LightProbe *)object->data;
+ build_lightprobe(probe);
+ OperationKey probe_key(&probe->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_LIGHT_PROBE_EVAL);
+ OperationKey object_key(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_LIGHT_PROBE_EVAL);
+ add_relation(probe_key, object_key, "LightProbe Update");
+}
+
+void DepsgraphRelationBuilder::build_object_data_speaker(Object *object)
+{
+ Speaker *speaker = (Speaker *)object->data;
+ build_speaker(speaker);
+ OperationKey probe_key(&speaker->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_SPEAKER_EVAL);
+ OperationKey object_key(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_SPEAKER_EVAL);
+ add_relation(probe_key, object_key, "Speaker Update");
+}
+
void DepsgraphRelationBuilder::build_object_parent(Object *object)
{
/* XXX: for now, need to use the component key (not just direct to the parent op),
@@ -573,10 +825,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
add_relation(parent_key, ob_key, "Vertex Parent");
/* XXX not sure what this is for or how you could be done properly - lukas */
- OperationDepsNode *parent_node = find_operation_node(parent_key);
- if (parent_node != NULL) {
- parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
- }
+ add_customdata_mask(parent_key, CD_MASK_ORIGINDEX);
ComponentKey transform_key(&object->parent->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(transform_key, ob_key, "Vertex Parent TFM");
@@ -632,11 +881,47 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object)
break;
}
}
+}
- /* exception case: parent is duplivert */
- if ((object->type == OB_MBALL) && (object->parent->transflag & OB_DUPLIVERTS)) {
- //dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert");
+void DepsgraphRelationBuilder::build_object_pointcache(Object *object)
+{
+ ComponentKey point_cache_key(&object->id, DEG_NODE_TYPE_POINT_CACHE);
+ /* Different point caches are affecting different aspects of life of the
+ * object. We keep track of those aspects and avoid duplicate relations. */
+ enum {
+ FLAG_TRANSFORM = (1 << 0),
+ FLAG_GEOMETRY = (1 << 1),
+ FLAG_ALL = (FLAG_TRANSFORM | FLAG_GEOMETRY),
+ };
+ ListBase ptcache_id_list;
+ BKE_ptcache_ids_from_object(&ptcache_id_list, object, scene_, 0);
+ int handled_components = 0;
+ LISTBASE_FOREACH (PTCacheID *, ptcache_id, &ptcache_id_list) {
+ /* Check which components needs the point cache. */
+ int flag;
+ if (ptcache_id->type == PTCACHE_TYPE_RIGIDBODY) {
+ flag = FLAG_TRANSFORM;
+ ComponentKey transform_key(&object->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ add_relation(point_cache_key,
+ transform_key,
+ "Point Cache -> Rigid Body");
+ }
+ else {
+ flag = FLAG_GEOMETRY;
+ ComponentKey geometry_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(point_cache_key,
+ geometry_key,
+ "Point Cache -> Geometry");
+ }
+ /* Tag that we did handle that component. */
+ handled_components |= flag;
+ if (handled_components == FLAG_ALL) {
+ break;
+ }
}
+ BLI_freelistN(&ptcache_id_list);
}
void DepsgraphRelationBuilder::build_constraints(ID *id,
@@ -739,39 +1024,25 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(target_transform_key, constraint_op_key, cti->name);
}
else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) {
- /* bone */
- if (&ct->tar->id == id) {
- /* same armature */
- eDepsOperation_Code target_key_opcode;
- /* Using "done" here breaks in-chain deps, while using
- * "ready" here breaks most production rigs instead.
- * So, we do a compromise here, and only do this when an
- * IK chain conflict may occur.
- */
- if (root_map->has_common_root(component_subdata,
- ct->subtarget))
- {
- target_key_opcode = DEG_OPCODE_BONE_READY;
- }
- else {
- target_key_opcode = DEG_OPCODE_BONE_DONE;
- }
- OperationKey target_key(&ct->tar->id,
- DEG_NODE_TYPE_BONE,
- ct->subtarget,
- target_key_opcode);
- add_relation(target_key, constraint_op_key, cti->name);
+ eDepsOperation_Code opcode;
+ /* relation to bone */
+ opcode = bone_target_opcode(&ct->tar->id, ct->subtarget,
+ id, component_subdata, root_map);
+ /* Armature constraint always wants the final position and chan_mat. */
+ if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
+ opcode = DEG_OPCODE_BONE_DONE;
}
- else {
- /* Different armature - we can safely use the result
- * of that.
- */
- OperationKey target_key(&ct->tar->id,
- DEG_NODE_TYPE_BONE,
- ct->subtarget,
- DEG_OPCODE_BONE_DONE);
- add_relation(target_key, constraint_op_key, cti->name);
+ /* if needs bbone shape, reference the segment computation */
+ if (BKE_constraint_target_uses_bbone(con, ct) &&
+ bone_has_segments(ct->tar, ct->subtarget))
+ {
+ opcode = DEG_OPCODE_BONE_SEGMENTS;
}
+ OperationKey target_key(&ct->tar->id,
+ DEG_NODE_TYPE_BONE,
+ ct->subtarget,
+ opcode);
+ add_relation(target_key, constraint_op_key, cti->name);
}
else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) &&
(ct->subtarget[0]))
@@ -783,16 +1054,27 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(target_key, constraint_op_key, cti->name);
if (ct->tar->type == OB_MESH) {
- OperationDepsNode *node2 = find_operation_node(target_key);
- if (node2 != NULL) {
- node2->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
+ add_customdata_mask(target_key, CD_MASK_MDEFORMVERT);
}
}
else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
+ bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data;
+
/* Constraints which requires the target object surface. */
ComponentKey target_key(&ct->tar->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(target_key, constraint_op_key, cti->name);
+
+ /* Add dependency on normal layers if necessary. */
+ if (ct->tar->type == OB_MESH && scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) {
+ bool track = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0;
+ if (track || BKE_shrinkwrap_needs_normals(scon->shrinkType, scon->shrinkMode)) {
+ add_customdata_mask(target_key, CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL);
+ }
+ if (scon->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ add_special_eval_flag(&ct->tar->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
+ }
+
/* NOTE: obdata eval now doesn't necessarily depend on the
* object's transform.
*/
@@ -871,13 +1153,19 @@ void DepsgraphRelationBuilder::build_animdata_curves(ID *id)
if (adt == NULL) {
return;
}
+ if (adt->action != NULL) {
+ build_action(adt->action);
+ }
if (adt->action == NULL && adt->nla_tracks.first == NULL) {
return;
}
/* Wire up dependency to time source. */
ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
- TimeSourceKey time_src_key;
- add_relation(time_src_key, adt_key, "TimeSrc -> Animation");
+ /* Relation from action itself. */
+ if (adt->action != NULL) {
+ ComponentKey action_key(&adt->action->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(action_key, adt_key, "Action -> Animation");
+ }
/* Get source operations. */
DepsNode *node_from = get_node(adt_key);
BLI_assert(node_from != NULL);
@@ -935,6 +1223,16 @@ void DepsgraphRelationBuilder::build_animdata_curves_targets(
graph_->add_new_relation(operation_from, operation_to,
"Animation -> Prop",
true);
+ /* It is possible that animation is writing to a nested ID datablock,
+ * need to make sure animation is evaluated after target ID is copied.
+ */
+ const IDDepsNode *id_node_from = operation_from->owner->owner;
+ const IDDepsNode *id_node_to = operation_to->owner->owner;
+ if (id_node_from != id_node_to) {
+ ComponentKey cow_key(id_node_to->id_orig,
+ DEG_NODE_TYPE_COPY_ON_WRITE);
+ add_relation(cow_key, adt_key, "Target CoW -> Animation", true);
+ }
}
}
@@ -945,6 +1243,11 @@ void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(
{
LISTBASE_FOREACH(NlaStrip *, strip, strips) {
if (strip->act != NULL) {
+ build_action(strip->act);
+
+ ComponentKey action_key(&strip->act->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(action_key, adt_key, "Action -> Animation");
+
build_animdata_curves_targets(id, adt_key,
operation_from,
&strip->act->curves);
@@ -973,7 +1276,6 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
/* create the driver's relations to targets */
build_driver(id, fcu);
-
/* Special case for array drivers: we can not multithread them because
* of the way how they work internally: animation system will write the
* whole array back to RNA even when changing individual array value.
@@ -1027,6 +1329,16 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
}
}
+void DepsgraphRelationBuilder::build_action(bAction *action)
+{
+ if (built_map_.checkIsBuiltAndTag(action)) {
+ return;
+ }
+ TimeSourceKey time_src_key;
+ ComponentKey animation_key(&action->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(time_src_key, animation_key, "TimeSrc -> Animation");
+}
+
void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
{
ChannelDriver *driver = fcu->driver;
@@ -1068,18 +1380,18 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
*/
IDDepsNode *arm_node = graph_->find_id_node(id);
char *bone_name = BLI_str_quoted_substrN(rna_path, "bones[");
- if (arm_node && bone_name) {
+ if (arm_node != NULL && bone_name != NULL) {
/* Find objects which use this, and make their eval callbacks
* depend on this.
*/
foreach (DepsRelation *rel, arm_node->outlinks) {
IDDepsNode *to_node = (IDDepsNode *)rel->to;
/* We only care about objects with pose data which use this. */
- if (GS(to_node->id->name) == ID_OB) {
- Object *object = (Object *)to_node->id;
- /* NOTE: object->pose may be NULL. */
- bPoseChannel *pchan = BKE_pose_channel_find_name(
- object->pose, bone_name);
+ if (GS(to_node->id_orig->name) == ID_OB) {
+ Object *object = (Object *)to_node->id_orig;
+ // NOTE: object->pose may be NULL
+ bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose,
+ bone_name);
if (pchan != NULL) {
OperationKey bone_key(&object->id,
DEG_NODE_TYPE_BONE,
@@ -1101,7 +1413,7 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
rna_path);
}
}
- else {
+ else if (rna_path != NULL && rna_path[0] != '\0') {
RNAPathKey target_key(id, rna_path);
if (RNA_pointer_is_null(&target_key.ptr)) {
/* TODO(sergey): This would only mean that driver is broken.
@@ -1109,19 +1421,37 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
* adding drivers which are known to be buggy to a dependency
* graph, in order to save computational power.
*/
+ return;
}
- else {
- if (target_key.prop != NULL &&
- RNA_property_is_idprop(target_key.prop))
- {
- OperationKey parameters_key(id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PARAMETERS_EVAL);
- add_relation(target_key,
- parameters_key,
- "Driver Target -> Properties");
+ add_relation(driver_key, target_key, "Driver -> Target");
+ /* Similar to the case with f-curves, driver might drive a nested
+ * datablock, which means driver execution should wait for that
+ * datablock to be copied.
+ */
+ {
+ PointerRNA id_ptr;
+ PointerRNA ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+ if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) {
+ if (id_ptr.id.data != ptr.id.data) {
+ ComponentKey cow_key((ID *)ptr.id.data,
+ DEG_NODE_TYPE_COPY_ON_WRITE);
+ add_relation(cow_key,
+ driver_key,
+ "Target CoW -> Driver",
+ true);
+ }
}
- add_relation(driver_key, target_key, "Driver -> Target");
+ }
+ if (target_key.prop != NULL &&
+ RNA_property_is_idprop(target_key.prop))
+ {
+ OperationKey parameters_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PARAMETERS_EVAL);
+ add_relation(target_key,
+ parameters_key,
+ "Driver Target -> Properties");
}
}
}
@@ -1144,6 +1474,15 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
if (dtar->id == NULL) {
continue;
}
+ build_id(dtar->id);
+ /* Initialize relations coming to proxy_from. */
+ Object *proxy_from = NULL;
+ if ((GS(dtar->id->name) == ID_OB) &&
+ (((Object *)dtar->id)->proxy_from != NULL))
+ {
+ proxy_from = ((Object *)dtar->id)->proxy_from;
+ build_id(&proxy_from->id);
+ }
/* Special handling for directly-named bones. */
if ((dtar->flag & DTAR_FLAG_STRUCT_REF) &&
(((Object *)dtar->id)->type == OB_ARMATURE) &&
@@ -1179,7 +1518,7 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
DEG_OPCODE_TRANSFORM_FINAL);
add_relation(target_key, driver_key, "Target -> Driver");
}
- else if (dtar->rna_path) {
+ else if (dtar->rna_path != NULL && dtar->rna_path[0] != '\0') {
RNAPathKey variable_key(dtar->id, dtar->rna_path);
if (RNA_pointer_is_null(&variable_key.ptr)) {
continue;
@@ -1191,19 +1530,17 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
continue;
}
add_relation(variable_key, driver_key, "RNA Target -> Driver");
+ if (proxy_from != NULL) {
+ RNAPathKey proxy_from_variable_key(&proxy_from->id,
+ dtar->rna_path);
+ add_relation(proxy_from_variable_key,
+ variable_key,
+ "Proxy From -> Variable");
+ }
}
else {
- if (dtar->id == id) {
- /* Ignore input dependency if we're driving properties of
- * the same ID, otherwise we'll be ending up in a cyclic
- * dependency here.
- */
- continue;
- }
- /* Resolve path to get node. */
- RNAPathKey target_key(dtar->id,
- dtar->rna_path ? dtar->rna_path : "");
- add_relation(target_key, driver_key, "RNA Target -> Driver");
+ /* If rna_path is NULL, and DTAR_FLAG_STRUCT_REF isn't set, this
+ * is an incomplete target reference, so nothing to do here. */
}
}
DRIVER_TARGETS_LOOPER_END;
@@ -1215,16 +1552,19 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
+ /* animation */
build_animdata(&world->id);
- /* TODO: other settings? */
- /* textures */
- build_texture_stack(world->mtex);
/* world's nodetree */
if (world->nodetree != NULL) {
build_nodetree(world->nodetree);
- ComponentKey ntree_key(&world->nodetree->id, DEG_NODE_TYPE_PARAMETERS);
- ComponentKey world_key(&world->id, DEG_NODE_TYPE_PARAMETERS);
- add_relation(ntree_key, world_key, "NTree->World Parameters");
+ OperationKey ntree_key(&world->nodetree->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_MATERIAL_UPDATE);
+ OperationKey world_key(&world->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_WORLD_UPDATE);
+ add_relation(ntree_key, world_key, "World's NTree");
+ build_nested_nodetree(&world->id, world->nodetree);
}
}
@@ -1246,9 +1586,11 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* objects - simulation participants */
if (rbw->group) {
- LISTBASE_FOREACH (GroupObject *, go, &rbw->group->gobject) {
- Object *object = go->ob;
- if (object == NULL || object->type != OB_MESH) {
+ build_collection(NULL, NULL, rbw->group);
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ if (object->type != OB_MESH) {
continue;
}
@@ -1267,6 +1609,13 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
add_relation(sim_key, rbo_key, "Rigidbody Sim Eval -> RBO Sync");
+ /* Geometry must be known to create the rigid body. RBO_MESH_BASE uses the non-evaluated
+ * mesh, so then the evaluation is unnecessary. */
+ if (object->rigidbody_object->mesh_source != RBO_MESH_BASE) {
+ ComponentKey geom_key(&object->id, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(geom_key, init_key, "Object Geom Eval -> Rigidbody Rebuild");
+ }
+
/* if constraints exist, those depend on the result of the rigidbody sim
* - This allows constraints to modify the result of the sim (i.e. clamping)
* while still allowing the sim to depend on some changes to the objects.
@@ -1296,18 +1645,19 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* Needed to get correct base values. */
add_relation(trans_op, sim_key, "Base Ob Transform -> Rigidbody Sim Eval");
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* constraints */
if (rbw->constraints) {
- LISTBASE_FOREACH (GroupObject *, go, &rbw->constraints->gobject) {
- Object *object = go->ob;
- if (object == NULL || !object->rigidbody_constraint) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object)
+ {
+ RigidBodyCon *rbc = object->rigidbody_constraint;
+ if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) {
+ /* When either ob1 or ob2 is NULL, the constraint doesn't work. */
continue;
}
- RigidBodyCon *rbc = object->rigidbody_constraint;
-
/* final result of the constraint object's transform controls how the
* constraint affects the physics sim for these objects
*/
@@ -1322,6 +1672,7 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* - ensure that sim depends on this constraint's transform */
add_relation(trans_key, sim_key, "RigidBodyConstraint Transform -> RB Simulation");
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
@@ -1338,13 +1689,24 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
/* Particle systems. */
LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
ParticleSettings *part = psys->part;
- /* Animation of particle settings, */
- build_animdata(&part->id);
+
+ /* Build particle settings relations.
+ *
+ * NOTE: The call itself ensures settings are only build once.
+ */
+ build_particle_settings(part);
+
/* This particle system. */
OperationKey psys_key(&object->id,
DEG_NODE_TYPE_EVAL_PARTICLES,
DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
psys->name);
+
+ /* Update particle system when settings changes. */
+ OperationKey particle_settings_key(&part->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PARTICLE_SETTINGS_EVAL);
+ add_relation(particle_settings_key, eval_init_key, "Particle Settings Change");
add_relation(eval_init_key, psys_key, "Init -> PSys");
/* TODO(sergey): Currently particle update is just a placeholder,
* hook it to the ubereval node so particle system is getting updated
@@ -1354,33 +1716,27 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
/* Collisions */
if (part->type != PART_HAIR) {
add_collision_relations(psys_key,
- scene_,
object,
part->collision_group,
- object->lay,
- true,
"Particle Collision");
}
else if ((psys->flag & PSYS_HAIR_DYNAMICS) &&
- psys->clmd && psys->clmd->coll_parms)
+ psys->clmd != NULL &&
+ psys->clmd->coll_parms != NULL)
{
add_collision_relations(psys_key,
- scene_,
object,
psys->clmd->coll_parms->group,
- object->lay | scene_->lay,
- true,
"Hair Collision");
}
/* Effectors. */
add_forcefield_relations(psys_key,
- scene_,
object,
psys,
part->effector_weights,
part->type == PART_HAIR,
"Particle Field");
- /* Boids. */
+ /* Boids .*/
if (part->boids) {
LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
@@ -1399,12 +1755,11 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
}
}
}
-
switch (part->ren_as) {
case PART_DRAW_OB:
if (part->dup_ob != NULL) {
/* Make sure object's relations are all built. */
- build_object(part->dup_ob);
+ build_object(NULL, part->dup_ob);
/* Build relation for the particle visualization. */
build_particles_visualization_object(object,
psys,
@@ -1413,8 +1768,8 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
break;
case PART_DRAW_GR:
if (part->dup_group != NULL) {
- build_group(NULL, part->dup_group);
- LISTBASE_FOREACH (GroupObject *, go, &part->dup_group->gobject) {
+ build_collection(NULL, NULL, part->dup_group);
+ LISTBASE_FOREACH (CollectionObject *, go, &part->dup_group->gobject) {
build_particles_visualization_object(object,
psys,
go->ob);
@@ -1432,9 +1787,15 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
*/
ComponentKey transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(transform_key, obdata_ubereval_key, "Partcile Eval");
+}
- /* pointcache */
- // TODO...
+void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
+{
+ if (built_map_.checkIsBuiltAndTag(part)) {
+ return;
+ }
+ /* Animation data relations. */
+ build_animdata(&part->id);
}
void DepsgraphRelationBuilder::build_particles_visualization_object(
@@ -1459,41 +1820,14 @@ void DepsgraphRelationBuilder::build_particles_visualization_object(
}
}
-void DepsgraphRelationBuilder::build_cloth(Object *object,
- ModifierData * /*md*/)
-{
- OperationKey cache_key(&object->id,
- DEG_NODE_TYPE_CACHE,
- DEG_OPCODE_GEOMETRY_CLOTH_MODIFIER);
- /* Cache component affects on modifier. */
- OperationKey modifier_key(&object->id,
- DEG_NODE_TYPE_GEOMETRY,
- DEG_OPCODE_GEOMETRY_UBEREVAL);
- add_relation(cache_key, modifier_key, "Cloth Cache -> Cloth");
-}
-
/* Shapekeys */
-void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
+void DepsgraphRelationBuilder::build_shapekeys(Key *key)
{
- ComponentKey obdata_key(obdata, DEG_NODE_TYPE_GEOMETRY);
-
+ if (built_map_.checkIsBuiltAndTag(key)) {
+ return;
+ }
/* attach animdata to geometry */
build_animdata(&key->id);
-
- if (key->adt) {
- // TODO: this should really be handled in build_animdata, since many of these cases will need it
- if (key->adt->action || key->adt->nla_tracks.first) {
- ComponentKey adt_key(&key->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(adt_key, obdata_key, "Animation");
- }
-
- /* NOTE: individual shapekey drivers are handled above already */
- }
-
- /* attach to geometry */
- // XXX: aren't shapekeys now done as a pseudo-modifier on object?
- //ComponentKey key_key(&key->id, DEG_NODE_TYPE_GEOMETRY); // FIXME: this doesn't exist
- //add_relation(key_key, obdata_key, "Shapekeys");
}
/**
@@ -1501,44 +1835,53 @@ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
* ==========================
*
* The evaluation of geometry on objects is as follows:
- * - The actual evaluated of the derived geometry (e.g. DerivedMesh, DispList, etc.)
- * occurs in the Geometry component of the object which references this. This includes
- * modifiers, and the temporary "ubereval" for geometry.
- * - Therefore, each user of a piece of shared geometry data ends up evaluating its own
- * version of the stuff, complete with whatever modifiers it may use.
+ * - The actual evaluated of the derived geometry (e.g. Mesh, DispList)
+ * occurs in the Geometry component of the object which references this.
+ * This includes modifiers, and the temporary "ubereval" for geometry.
+ * Therefore, each user of a piece of shared geometry data ends up evaluating
+ * its own version of the stuff, complete with whatever modifiers it may use.
*
- * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT, etc.) are used for
+ * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT.)
+ * are used for
* 1) calculating the bounding boxes of the geometry data,
- * 2) aggregating inward links from other objects (e.g. for text on curve, etc.)
+ * 2) aggregating inward links from other objects (e.g. for text on curve)
* and also for the links coming from the shapekey datablocks
- * - Animation/Drivers affecting the parameters of the geometry are made to trigger
- * updates on the obdata geometry component, which then trigger downstream
- * re-evaluation of the individual instances of this geometry.
+ * - Animation/Drivers affecting the parameters of the geometry are made to
+ * trigger updates on the obdata geometry component, which then trigger
+ * downstream re-evaluation of the individual instances of this geometry.
*/
-// TODO: Materials and lighting should probably get their own component, instead of being lumped under geometry?
-void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
+void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
{
ID *obdata = (ID *)object->data;
-
/* Init operation of object-level geometry evaluation. */
- OperationKey geom_init_key(&object->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Init");
-
- /* get nodes for result of obdata's evaluation, and geometry evaluation on object */
+ OperationKey geom_init_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Init");
+ /* Get nodes for result of obdata's evaluation, and geometry evaluation
+ * on object.
+ */
ComponentKey obdata_geom_key(obdata, DEG_NODE_TYPE_GEOMETRY);
ComponentKey geom_key(&object->id, DEG_NODE_TYPE_GEOMETRY);
-
- /* link components to each other */
+ /* Link components to each other. */
add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data");
-
+ OperationKey obdata_ubereval_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ /* Special case: modifiers evaluation queries scene for various things like
+ * data mask to be used. We add relation here to ensure object is never
+ * evaluated prior to Scene's CoW is ready.
+ */
+ OperationKey scene_key(&scene_->id,
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ DEG_OPCODE_VIEW_LAYER_EVAL);
+ DepsRelation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation");
+ rel->flag |= DEPSREL_FLAG_NO_FLUSH;
/* Modifiers */
if (object->modifiers.first != NULL) {
- OperationKey obdata_ubereval_key(&object->id,
- DEG_NODE_TYPE_GEOMETRY,
- DEG_OPCODE_GEOMETRY_UBEREVAL);
ModifierUpdateDepsgraphContext ctx = {};
ctx.scene = scene_;
ctx.object = object;
-
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
if (mti->updateDepsgraph) {
@@ -1550,163 +1893,271 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
TimeSourceKey time_src_key;
add_relation(time_src_key, obdata_ubereval_key, "Time Source");
}
- if (md->type == eModifierType_Cloth) {
- build_cloth(object, md);
+ }
+ }
+ /* Grease Pencil Modifiers */
+ if (object->greasepencil_modifiers.first != NULL) {
+ ModifierUpdateDepsgraphContext ctx = {};
+ ctx.scene = scene_;
+ ctx.object = object;
+ LISTBASE_FOREACH(GpencilModifierData *, md, &object->greasepencil_modifiers) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo((GpencilModifierType)md->type);
+ if (mti->updateDepsgraph) {
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
+ ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle);
+ mti->updateDepsgraph(md, &ctx);
+ }
+ if (BKE_object_modifier_gpencil_use_time(object, md)) {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
+ }
+ }
+ }
+ /* Shader FX */
+ if (object->shader_fx.first != NULL) {
+ ModifierUpdateDepsgraphContext ctx = {};
+ ctx.scene = scene_;
+ ctx.object = object;
+ LISTBASE_FOREACH(ShaderFxData *, fx, &object->shader_fx) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo((ShaderFxType)fx->type);
+ if (fxi->updateDepsgraph) {
+ DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
+ ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle);
+ fxi->updateDepsgraph(fx, &ctx);
+ }
+ if (BKE_object_shaderfx_use_time(object, fx)) {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source");
}
}
}
-
- /* materials */
+ /* Materials. */
if (object->totcol) {
for (int a = 1; a <= object->totcol; a++) {
Material *ma = give_current_material(object, a);
if (ma != NULL) {
build_material(ma);
+
+ if (object->type == OB_MESH) {
+ OperationKey material_key(&ma->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_MATERIAL_UPDATE);
+ OperationKey shading_key(&object->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_SHADING);
+ add_relation(material_key, shading_key, "Material Update");
+ }
}
}
}
-
- /* geometry collision */
+ /* Geometry collision. */
if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
// add geometry collider relations
}
-
/* Make sure uber update is the last in the dependencies.
*
* TODO(sergey): Get rid of this node.
*/
if (object->type != OB_ARMATURE) {
/* Armatures does no longer require uber node. */
- OperationKey obdata_ubereval_key(&object->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
- add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval");
+ OperationKey obdata_ubereval_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(geom_init_key,
+ obdata_ubereval_key,
+ "Object Geometry UberEval");
+ if (object->totcol != 0 && object->type == OB_MESH) {
+ ComponentKey object_shading_key(&object->id, DEG_NODE_TYPE_SHADING);
+ DepsRelation *rel = add_relation(obdata_ubereval_key,
+ object_shading_key,
+ "Object Geometry batch Update");
+ rel->flag |= DEPSREL_FLAG_NO_FLUSH;
+ }
}
+ if (object->type == OB_MBALL) {
+ Object *mom = BKE_mball_basis_find(scene_, object);
+ ComponentKey mom_geom_key(&mom->id, DEG_NODE_TYPE_GEOMETRY);
+ /* motherball - mom depends on children! */
+ if (mom == object) {
+ ComponentKey mom_transform_key(&mom->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ add_relation(mom_transform_key,
+ mom_geom_key,
+ "Metaball Motherball Transform -> Geometry");
+ }
+ else {
+ ComponentKey transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(geom_key, mom_geom_key, "Metaball Motherball");
+ add_relation(transform_key, mom_geom_key, "Metaball Motherball");
+ }
+ }
+ /* NOTE: This is compatibility code to support particle systems
+ *
+ * for viewport being properly rendered in final render mode.
+ * This relation is similar to what dag_object_time_update_flags()
+ * was doing for mesh objects with particle system.
+ *
+ * Ideally we need to get rid of this relation.
+ */
+ if (object_particles_depends_on_time(object)) {
+ TimeSourceKey time_key;
+ OperationKey obdata_ubereval_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(time_key, obdata_ubereval_key, "Legacy particle time");
+ }
+ /* Object data datablock. */
+ build_object_data_geometry_datablock((ID *)object->data);
+ Key *key = BKE_key_from_object(object);
+ if (key != NULL) {
+ if (key->adt != NULL) {
+ if (key->adt->action || key->adt->nla_tracks.first) {
+ ComponentKey obdata_key((ID *)object->data,
+ DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey adt_key(&key->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(adt_key, obdata_key, "Animation");
+ }
+ }
+ }
+}
+void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
+{
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
-
+ /* Animation. */
+ build_animdata(obdata);
+ /* ShapeKeys. */
+ Key *key = BKE_key_from_id(obdata);
+ if (key != NULL) {
+ build_shapekeys(key);
+ }
/* Link object data evaluation node to exit operation. */
- OperationKey obdata_geom_eval_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
- OperationKey obdata_geom_done_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Done");
- add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done");
-
- /* type-specific node/links */
- switch (object->type) {
- case OB_MESH:
- /* NOTE: This is compatibility code to support particle systems
- *
- * for viewport being properly rendered in final render mode.
- * This relation is similar to what dag_object_time_update_flags()
- * was doing for mesh objects with particle system.
- *
- * Ideally we need to get rid of this relation.
- */
- if (object_particles_depends_on_time(object)) {
- TimeSourceKey time_key;
- OperationKey obdata_ubereval_key(&object->id,
- DEG_NODE_TYPE_GEOMETRY,
- DEG_OPCODE_GEOMETRY_UBEREVAL);
- add_relation(time_key, obdata_ubereval_key, "Legacy particle time");
- }
+ OperationKey obdata_geom_eval_key(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ OperationKey obdata_geom_done_key(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Done");
+ add_relation(obdata_geom_eval_key,
+ obdata_geom_done_key,
+ "ObData Geom Eval Done");
+ /* Type-specific links. */
+ const ID_Type id_type = GS(obdata->name);
+ switch (id_type) {
+ case ID_ME:
break;
-
- case OB_MBALL:
- {
- Object *mom = BKE_mball_basis_find(bmain_, bmain_->eval_ctx, scene_, object);
- ComponentKey mom_geom_key(&mom->id, DEG_NODE_TYPE_GEOMETRY);
- /* motherball - mom depends on children! */
- if (mom == object) {
- ComponentKey mom_transform_key(&mom->id,
- DEG_NODE_TYPE_TRANSFORM);
- add_relation(mom_transform_key,
- mom_geom_key,
- "Metaball Motherball Transform -> Geometry");
- }
- else {
- ComponentKey transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM);
- add_relation(geom_key, mom_geom_key, "Metaball Motherball");
- add_relation(transform_key, mom_geom_key, "Metaball Motherball");
- }
+ case ID_MB:
break;
- }
-
- case OB_CURVE:
- case OB_FONT:
+ case ID_CU:
{
Curve *cu = (Curve *)obdata;
-
- /* curve's dependencies */
- // XXX: these needs geom data, but where is geom stored?
- if (cu->bevobj) {
- ComponentKey bevob_key(&cu->bevobj->id, DEG_NODE_TYPE_GEOMETRY);
- build_object(cu->bevobj);
- add_relation(bevob_key, geom_key, "Curve Bevel");
+ if (cu->bevobj != NULL) {
+ ComponentKey bevob_geom_key(&cu->bevobj->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(bevob_geom_key,
+ obdata_geom_eval_key,
+ "Curve Bevel Geometry");
+ ComponentKey bevob_key(&cu->bevobj->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ add_relation(bevob_key,
+ obdata_geom_eval_key,
+ "Curve Bevel Transform");
+ build_object(NULL, cu->bevobj);
}
- if (cu->taperobj) {
- ComponentKey taperob_key(&cu->taperobj->id, DEG_NODE_TYPE_GEOMETRY);
- build_object(cu->taperobj);
- add_relation(taperob_key, geom_key, "Curve Taper");
+ if (cu->taperobj != NULL) {
+ ComponentKey taperob_key(&cu->taperobj->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper");
+ build_object(NULL, cu->taperobj);
}
- if (object->type == OB_FONT) {
- if (cu->textoncurve) {
- ComponentKey textoncurve_key(&cu->textoncurve->id, DEG_NODE_TYPE_GEOMETRY);
- build_object(cu->textoncurve);
- add_relation(textoncurve_key, geom_key, "Text on Curve");
- }
+ if (cu->textoncurve != NULL) {
+ ComponentKey textoncurve_key(&cu->textoncurve->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(textoncurve_key,
+ obdata_geom_eval_key,
+ "Text on Curve");
+ build_object(NULL, cu->textoncurve);
}
break;
}
-
- case OB_SURF: /* Nurbs Surface */
- {
+ case ID_LT:
break;
- }
-
- case OB_LATTICE: /* Lattice */
+ case ID_GD: /* Grease Pencil */
{
+ bGPdata *gpd = (bGPdata *)obdata;
+
+ /* Geometry cache needs to be recalculated on frame change
+ * (e.g. to fix crashes after scrubbing the timeline when
+ * onion skinning is enabled, since the ghosts need to be
+ * re-added to the cache once scrubbing ends)
+ */
+ TimeSourceKey time_key;
+ ComponentKey geometry_key(obdata, DEG_NODE_TYPE_GEOMETRY);
+ add_relation(time_key,
+ geometry_key,
+ "GP Frame Change");
+
+ /* Geometry cache also needs to be recalculated when Material
+ * settings change (e.g. when fill.opacity changes on/off,
+ * we need to rebuild the bGPDstroke->triangles caches)
+ */
+ for (int i = 0; i < gpd->totcol; i++) {
+ Material *ma = gpd->mat[i];
+ if ((ma != NULL) && (ma->gp_style != NULL)) {
+ OperationKey material_key(&ma->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_MATERIAL_UPDATE);
+ add_relation(material_key,
+ geometry_key,
+ "Material -> GP Data");
+ }
+ }
break;
}
+ default:
+ BLI_assert(!"Should not happen");
+ break;
}
+}
- /* ShapeKeys */
- Key *key = BKE_key_from_object(object);
- if (key) {
- build_shapekeys(obdata, key);
+void DepsgraphRelationBuilder::build_armature(bArmature *armature)
+{
+ if (built_map_.checkIsBuiltAndTag(armature)) {
+ return;
}
+ build_animdata(&armature->id);
}
-/* Cameras */
-// TODO: Link scene-camera links in somehow...
-void DepsgraphRelationBuilder::build_camera(Object *object)
+void DepsgraphRelationBuilder::build_camera(Camera *camera)
{
- Camera *camera = (Camera *)object->data;
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
- /* DOF */
- if (camera->dof_ob) {
- ComponentKey ob_param_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
+ if (camera->dof_ob != NULL) {
+ ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS);
ComponentKey dof_ob_key(&camera->dof_ob->id, DEG_NODE_TYPE_TRANSFORM);
- add_relation(dof_ob_key, ob_param_key, "Camera DOF");
+ add_relation(dof_ob_key, camera_parameters_key, "Camera DOF");
}
}
/* Lamps */
-void DepsgraphRelationBuilder::build_lamp(Object *object)
+void DepsgraphRelationBuilder::build_lamp(Lamp *lamp)
{
- Lamp *lamp = (Lamp *)object->data;
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
/* lamp's nodetree */
if (lamp->nodetree != NULL) {
build_nodetree(lamp->nodetree);
- ComponentKey parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS);
- ComponentKey nodetree_key(&lamp->nodetree->id, DEG_NODE_TYPE_PARAMETERS);
- add_relation(nodetree_key, parameters_key, "NTree->Lamp Parameters");
+ ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey nodetree_key(&lamp->nodetree->id, DEG_NODE_TYPE_SHADING);
+ add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters");
+ build_nested_nodetree(&lamp->id, lamp->nodetree);
}
- /* textures */
- build_texture_stack(lamp->mtex);
}
void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
@@ -1718,9 +2169,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
return;
}
build_animdata(&ntree->id);
- OperationKey parameters_key(&ntree->id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PARAMETERS_EVAL);
+ ComponentKey shading_key(&ntree->id, DEG_NODE_TYPE_SHADING);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
ID *id = bnode->id;
@@ -1738,7 +2187,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
/* nothing for now. */
}
else if (id_type == ID_OB) {
- build_object((Object *)id);
+ build_object(NULL, (Object *)id);
}
else if (id_type == ID_SCE) {
/* Scenes are used by compositor trees, and handled by render
@@ -1748,18 +2197,36 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
else if (id_type == ID_TXT) {
/* Ignore script nodes. */
}
+ else if (id_type == ID_MSK) {
+ build_mask((Mask *)id);
+ }
+ else if (id_type == ID_MC) {
+ build_movieclip((MovieClip *)id);
+ }
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)id;
build_nodetree(group_ntree);
- OperationKey group_parameters_key(&group_ntree->id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PARAMETERS_EVAL);
- add_relation(group_parameters_key, parameters_key, "Group Node");
+ ComponentKey group_shading_key(&group_ntree->id,
+ DEG_NODE_TYPE_SHADING);
+ add_relation(group_shading_key, shading_key, "Group Node");
}
else {
BLI_assert(!"Unknown ID type used for node");
}
}
+
+ OperationKey shading_update_key(&ntree->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_MATERIAL_UPDATE);
+ OperationKey shading_parameters_key(&ntree->id,
+ DEG_NODE_TYPE_SHADING_PARAMETERS,
+ DEG_OPCODE_MATERIAL_UPDATE);
+ add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters");
+
+ if (check_id_has_anim_component(&ntree->id)) {
+ ComponentKey animation_key(&ntree->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters");
+ }
}
/* Recursively build graph for material */
@@ -1770,19 +2237,17 @@ void DepsgraphRelationBuilder::build_material(Material *material)
}
/* animation */
build_animdata(&material->id);
- /* textures */
- build_texture_stack(material->mtex);
/* material's nodetree */
if (material->nodetree != NULL) {
build_nodetree(material->nodetree);
OperationKey ntree_key(&material->nodetree->id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PARAMETERS_EVAL);
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_MATERIAL_UPDATE);
OperationKey material_key(&material->id,
DEG_NODE_TYPE_SHADING,
- DEG_OPCODE_PLACEHOLDER,
- "Material Update");
+ DEG_OPCODE_MATERIAL_UPDATE);
add_relation(ntree_key, material_key, "Material's NTree");
+ build_nested_nodetree(&material->id, material->nodetree);
}
}
@@ -1796,17 +2261,7 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
build_animdata(&texture->id);
/* texture's nodetree */
build_nodetree(texture->nodetree);
-}
-
-/* Texture-stack attached to some shading datablock */
-void DepsgraphRelationBuilder::build_texture_stack(MTex **texture_stack)
-{
- /* for now assume that all texture-stacks have same number of max items */
- for (int i = 0; i < MAX_MTEX; i++) {
- MTex *mtex = texture_stack[i];
- if (mtex && mtex->tex)
- build_texture(mtex->tex);
- }
+ build_nested_nodetree(&texture->id, texture->nodetree);
}
void DepsgraphRelationBuilder::build_compositor(Scene *scene)
@@ -1817,6 +2272,9 @@ void DepsgraphRelationBuilder::build_compositor(Scene *scene)
void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd)
{
+ if (built_map_.checkIsBuiltAndTag(gpd)) {
+ return;
+ }
/* animation */
build_animdata(&gpd->id);
@@ -1825,12 +2283,18 @@ void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd)
void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
{
+ if (built_map_.checkIsBuiltAndTag(cache_file)) {
+ return;
+ }
/* Animation. */
build_animdata(&cache_file->id);
}
void DepsgraphRelationBuilder::build_mask(Mask *mask)
{
+ if (built_map_.checkIsBuiltAndTag(mask)) {
+ return;
+ }
ID *mask_id = &mask->id;
/* F-Curve animation. */
build_animdata(mask_id);
@@ -1847,10 +2311,203 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask)
void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
{
+ if (built_map_.checkIsBuiltAndTag(clip)) {
+ return;
+ }
/* Animation. */
build_animdata(&clip->id);
}
+void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe)
+{
+ if (built_map_.checkIsBuiltAndTag(probe)) {
+ return;
+ }
+ build_animdata(&probe->id);
+}
+
+void DepsgraphRelationBuilder::build_speaker(Speaker *speaker)
+{
+ if (built_map_.checkIsBuiltAndTag(speaker)) {
+ return;
+ }
+ build_animdata(&speaker->id);
+}
+
+void DepsgraphRelationBuilder::build_copy_on_write_relations()
+{
+ foreach (IDDepsNode *id_node, graph_->id_nodes) {
+ build_copy_on_write_relations(id_node);
+ }
+}
+
+/* Nested datablocks (node trees, shape keys) requires special relation to
+ * ensure owner's datablock remapping happens after node tree itself is ready.
+ *
+ * This is similar to what happens in ntree_hack_remap_pointers().
+ */
+void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id)
+{
+ OperationKey owner_copy_on_write_key(owner,
+ DEG_NODE_TYPE_COPY_ON_WRITE,
+ DEG_OPCODE_COPY_ON_WRITE);
+ OperationKey id_copy_on_write_key(id,
+ DEG_NODE_TYPE_COPY_ON_WRITE,
+ DEG_OPCODE_COPY_ON_WRITE);
+ add_relation(id_copy_on_write_key,
+ owner_copy_on_write_key,
+ "Eval Order");
+}
+
+void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner,
+ bNodeTree *ntree)
+{
+ if (ntree == NULL) {
+ return;
+ }
+ build_nested_datablock(owner, &ntree->id);
+}
+
+void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
+{
+ if (key == NULL) {
+ return;
+ }
+ build_nested_datablock(owner, &key->id);
+}
+
+void DepsgraphRelationBuilder::build_copy_on_write_relations(IDDepsNode *id_node)
+{
+ ID *id_orig = id_node->id_orig;
+ const ID_Type id_type = GS(id_orig->name);
+ TimeSourceKey time_source_key;
+ OperationKey copy_on_write_key(id_orig,
+ DEG_NODE_TYPE_COPY_ON_WRITE,
+ DEG_OPCODE_COPY_ON_WRITE);
+ /* XXX: This is a quick hack to make Alt-A to work. */
+ // add_relation(time_source_key, copy_on_write_key, "Fluxgate capacitor hack");
+ /* Resat of code is using rather low level trickery, so need to get some
+ * explicit pointers. */
+ DepsNode *node_cow = find_node(copy_on_write_key);
+ OperationDepsNode *op_cow = node_cow->get_exit_operation();
+ /* Plug any other components to this one. */
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ if (comp_node->type == DEG_NODE_TYPE_COPY_ON_WRITE) {
+ /* Copy-on-write component never depends on itself. */
+ continue;
+ }
+ if (!comp_node->depends_on_cow()) {
+ /* Component explicitly requests to not add relation. */
+ continue;
+ }
+ int rel_flag = (DEPSREL_FLAG_NO_FLUSH | DEPSREL_FLAG_GODMODE);
+ if (id_type == ID_ME && comp_node->type == DEG_NODE_TYPE_GEOMETRY) {
+ rel_flag &= ~DEPSREL_FLAG_NO_FLUSH;
+ }
+ /* materials need update grease pencil objects */
+ if (id_type == ID_MA) {
+ rel_flag &= ~DEPSREL_FLAG_NO_FLUSH;
+ }
+ /* Notes on exceptions:
+ * - Parameters component is where drivers are living. Changing any
+ * of the (custom) properties in the original datablock (even the
+ * ones which do not imply other component update) need to make
+ * sure drivers are properly updated.
+ * This way, for example, changing ID property will properly poke
+ * all drivers to be updated.
+ *
+ * - View layers have cached array of bases in them, which is not
+ * copied by copy-on-write, and not preserved. PROBABLY it is better
+ * to preserve that cache in copy-on-write, but for the time being
+ * we allow flush to layer collections component which will ensure
+ * that cached array fo bases exists and is up-to-date.
+ *
+ * - Action is allowed to flush as well, this way it's possible to
+ * keep current tagging in animation editors (which tags action for
+ * CoW update when it's changed) but yet guarantee evaluation order
+ * with objects which are using that action.
+ */
+ if (comp_node->type == DEG_NODE_TYPE_PARAMETERS ||
+ comp_node->type == DEG_NODE_TYPE_LAYER_COLLECTIONS ||
+ (comp_node->type == DEG_NODE_TYPE_ANIMATION && id_type == ID_AC))
+ {
+ rel_flag &= ~DEPSREL_FLAG_NO_FLUSH;
+ }
+ /* All entry operations of each component should wait for a proper
+ * copy of ID.
+ */
+ OperationDepsNode *op_entry = comp_node->get_entry_operation();
+ if (op_entry != NULL) {
+ DepsRelation *rel = graph_->add_new_relation(
+ op_cow, op_entry, "CoW Dependency");
+ rel->flag |= rel_flag;
+ }
+ /* All dangling operations should also be executed after copy-on-write. */
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, comp_node->operations_map)
+ {
+ if (op_node == op_entry) {
+ continue;
+ }
+ if (op_node->inlinks.size() == 0) {
+ DepsRelation *rel = graph_->add_new_relation(
+ op_cow, op_node, "CoW Dependency");
+ rel->flag |= rel_flag;
+ }
+ else {
+ bool has_same_comp_dependency = false;
+ foreach (DepsRelation *rel_current, op_node->inlinks) {
+ if (rel_current->from->type != DEG_NODE_TYPE_OPERATION) {
+ continue;
+ }
+ OperationDepsNode *op_node_from =
+ (OperationDepsNode *)rel_current->from;
+ if (op_node_from->owner == op_node->owner) {
+ has_same_comp_dependency = true;
+ break;
+ }
+ }
+ if (!has_same_comp_dependency) {
+ DepsRelation *rel = graph_->add_new_relation(
+ op_cow, op_node, "CoW Dependency");
+ rel->flag |= rel_flag;
+ }
+ }
+ }
+ GHASH_FOREACH_END();
+ /* NOTE: We currently ignore implicit relations to an external
+ * datablocks for copy-on-write operations. This means, for example,
+ * copy-on-write component of Object will not wait for copy-on-write
+ * component of it's Mesh. This is because pointers are all known
+ * already so remapping will happen all correct. And then If some object
+ * evaluation step needs geometry, it will have transitive dependency
+ * to Mesh copy-on-write already.
+ */
+ }
+ GHASH_FOREACH_END();
+ /* TODO(sergey): This solves crash for now, but causes too many
+ * updates potentially.
+ */
+ if (GS(id_orig->name) == ID_OB) {
+ Object *object = (Object *)id_orig;
+ ID *object_data_id = (ID *)object->data;
+ if (object_data_id != NULL) {
+ if (deg_copy_on_write_is_needed(object_data_id)) {
+ OperationKey data_copy_on_write_key(object_data_id,
+ DEG_NODE_TYPE_COPY_ON_WRITE,
+ DEG_OPCODE_COPY_ON_WRITE);
+ add_relation(data_copy_on_write_key,
+ copy_on_write_key,
+ "Eval Order",
+ DEPSREL_FLAG_GODMODE);
+ }
+ }
+ else {
+ BLI_assert(object->type == OB_EMPTY);
+ }
+ }
+}
+
/* **** ID traversal callbacks functions **** */
void DepsgraphRelationBuilder::modifier_walk(void *user_data,
@@ -1863,17 +2520,7 @@ void DepsgraphRelationBuilder::modifier_walk(void *user_data,
if (id == NULL) {
return;
}
- switch (GS(id->name)) {
- case ID_OB:
- data->builder->build_object((Object *)id);
- break;
- case ID_TE:
- data->builder->build_texture((Tex *)id);
- break;
- default:
- /* pass */
- break;
- }
+ data->builder->build_id(id);
}
void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/,
@@ -1882,12 +2529,11 @@ void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/,
void *user_data)
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
- if (*idpoin) {
- ID *id = *idpoin;
- if (GS(id->name) == ID_OB) {
- data->builder->build_object((Object *)id);
- }
+ ID *id = *idpoin;
+ if (id == NULL) {
+ return;
}
+ data->builder->build_id(id);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 35e17cd0dc1..c6db975c6c2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -44,19 +44,26 @@
#include "BLI_string.h"
#include "intern/builder/deg_builder_map.h"
+#include "intern/depsgraph.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
struct Base;
+struct bArmature;
+struct bAction;
struct bGPdata;
struct CacheFile;
+struct Camera;
struct ListBase;
struct GHash;
struct ID;
struct FCurve;
-struct Group;
+struct Collection;
struct Key;
+struct Lamp;
+struct LayerCollection;
+struct LightProbe;
struct Main;
struct Mask;
struct Material;
@@ -68,7 +75,10 @@ struct Object;
struct bPoseChannel;
struct bConstraint;
struct ParticleSystem;
+struct ParticleSettings;
struct Scene;
+struct Speaker;
+struct ViewLayer;
struct Tex;
struct World;
struct EffectorWeights;
@@ -177,25 +187,49 @@ struct DepsgraphRelationBuilder
DepsRelation *add_relation(const KeyFrom& key_from,
const KeyTo& key_to,
const char *description,
- bool check_unique = false);
+ bool check_unique = false,
+ int flags = 0);
+
+ template <typename KeyFrom, typename KeyTo>
+ DepsRelation *add_relation(const KeyFrom& key_from,
+ const KeyTo& key_to,
+ const char *description,
+ eDepsRelation_Flag flag);
template <typename KeyTo>
DepsRelation *add_relation(const TimeSourceKey& key_from,
const KeyTo& key_to,
const char *description,
- bool check_unique = false);
+ bool check_unique = false,
+ int flags = 0);
template <typename KeyType>
DepsRelation *add_node_handle_relation(const KeyType& key_from,
const DepsNodeHandle *handle,
const char *description,
- bool check_unique = false);
-
- void build_scene(Scene *scene);
- void build_group(Object *object, Group *group);
- void build_object(Object *object);
+ bool check_unique = false,
+ int flags = 0);
+
+ void add_customdata_mask(const ComponentKey &key, uint64_t mask);
+ void add_special_eval_flag(ID *object, uint32_t flag);
+
+ void build_id(ID *id);
+ void build_layer_collections(ListBase *lb);
+ void build_view_layer(Scene *scene, ViewLayer *view_layer);
+ void build_collection(LayerCollection *from_layer_collection,
+ Object *object,
+ Collection *collection);
+ void build_object(Base *base, Object *object);
+ void build_object_flags(Base *base, Object *object);
void build_object_data(Object *object);
+ void build_object_data_camera(Object *object);
+ void build_object_data_geometry(Object *object);
+ void build_object_data_geometry_datablock(ID *obdata);
+ void build_object_data_lamp(Object *object);
+ void build_object_data_lightprobe(Object *object);
+ void build_object_data_speaker(Object *object);
void build_object_parent(Object *object);
+ void build_object_pointcache(Object *object);
void build_constraints(ID *id,
eDepsNode_Type component_type,
const char *component_subdata,
@@ -212,16 +246,17 @@ struct DepsgraphRelationBuilder
OperationDepsNode *operation_from,
ListBase *strips);
void build_animdata_drivers(ID *id);
+ void build_action(bAction *action);
void build_driver(ID *id, FCurve *fcurve);
void build_driver_data(ID *id, FCurve *fcurve);
void build_driver_variables(ID *id, FCurve *fcurve);
void build_world(World *world);
void build_rigidbody(Scene *scene);
void build_particles(Object *object);
+ void build_particle_settings(ParticleSettings *part);
void build_particles_visualization_object(Object *object,
ParticleSystem *psys,
Object *draw_object);
- void build_cloth(Object *object, ModifierData *md);
void build_ik_pose(Object *object,
bPoseChannel *pchan,
bConstraint *con,
@@ -232,34 +267,37 @@ struct DepsgraphRelationBuilder
RootPChanMap *root_map);
void build_rig(Object *object);
void build_proxy_rig(Object *object);
- void build_shapekeys(ID *obdata, Key *key);
- void build_obdata_geom(Object *object);
- void build_camera(Object *object);
- void build_lamp(Object *object);
+ void build_shapekeys(Key *key);
+ void build_armature(bArmature *armature);
+ void build_camera(Camera *camera);
+ void build_lamp(Lamp *lamp);
void build_nodetree(bNodeTree *ntree);
void build_material(Material *ma);
void build_texture(Tex *tex);
- void build_texture_stack(MTex **texture_stack);
void build_compositor(Scene *scene);
void build_gpencil(bGPdata *gpd);
void build_cachefile(CacheFile *cache_file);
void build_mask(Mask *mask);
void build_movieclip(MovieClip *clip);
+ void build_lightprobe(LightProbe *probe);
+ void build_speaker(Speaker *speaker);
+
+ void build_nested_datablock(ID *owner, ID *id);
+ void build_nested_nodetree(ID *owner, bNodeTree *ntree);
+ void build_nested_shapekey(ID *owner, Key *key);
void add_collision_relations(const OperationKey &key,
- Scene *scene,
Object *object,
- Group *group,
- int layer,
- bool dupli,
+ Collection *collection,
const char *name);
void add_forcefield_relations(const OperationKey &key,
- Scene *scene,
Object *object,
ParticleSystem *psys,
EffectorWeights *eff,
- bool add_absorption,
- const char *name);
+ bool add_absorption, const char *name);
+
+ void build_copy_on_write_relations();
+ void build_copy_on_write_relations(IDDepsNode *id_node);
template <typename KeyType>
OperationDepsNode *find_operation_node(const KeyType &key);
@@ -278,11 +316,13 @@ protected:
DepsRelation *add_time_relation(TimeSourceDepsNode *timesrc,
DepsNode *node_to,
const char *description,
- bool check_unique = false);
+ bool check_unique = false,
+ int flags = 0);
DepsRelation *add_operation_relation(OperationDepsNode *node_from,
OperationDepsNode *node_to,
const char *description,
- bool check_unique = false);
+ bool check_unique = false,
+ int flags = 0);
template <typename KeyType>
DepsNodeHandle create_node_handle(const KeyType& key,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
index 570227601db..726393f39b9 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -49,14 +49,16 @@ template <typename KeyFrom, typename KeyTo>
DepsRelation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
const KeyTo &key_to,
const char *description,
- bool check_unique)
+ bool check_unique,
+ int flags)
{
DepsNode *node_from = get_node(key_from);
DepsNode *node_to = get_node(key_to);
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
if (op_from && op_to) {
- return add_operation_relation(op_from, op_to, description, check_unique);
+ return add_operation_relation(
+ op_from, op_to, description, check_unique, flags);
}
else {
if (!op_from) {
@@ -81,18 +83,31 @@ DepsRelation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
return NULL;
}
+template <typename KeyFrom, typename KeyTo>
+DepsRelation *DepsgraphRelationBuilder::add_relation(
+ const KeyFrom& key_from,
+ const KeyTo& key_to,
+ const char *description,
+ eDepsRelation_Flag flag)
+{
+ return add_relation(
+ key_from, key_to, description, false, static_cast<int>(flag));
+}
+
template <typename KeyTo>
DepsRelation *DepsgraphRelationBuilder::add_relation(
const TimeSourceKey &key_from,
const KeyTo &key_to,
const char *description,
- bool check_unique)
+ bool check_unique,
+ int flags)
{
TimeSourceDepsNode *time_from = get_node(key_from);
DepsNode *node_to = get_node(key_to);
OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
if (time_from != NULL && op_to != NULL) {
- return add_time_relation(time_from, op_to, description, check_unique);
+ return add_time_relation(
+ time_from, op_to, description, check_unique, flags);
}
return NULL;
}
@@ -102,13 +117,15 @@ DepsRelation *DepsgraphRelationBuilder::add_node_handle_relation(
const KeyType &key_from,
const DepsNodeHandle *handle,
const char *description,
- bool check_unique)
+ bool check_unique,
+ int flags)
{
DepsNode *node_from = get_node(key_from);
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
OperationDepsNode *op_to = handle->node->get_entry_operation();
if (op_from != NULL && op_to != NULL) {
- return add_operation_relation(op_from, op_to, description, check_unique);
+ return add_operation_relation(
+ op_from, op_to, description, check_unique, flags);
}
else {
if (!op_from) {
@@ -184,7 +201,7 @@ bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency(
return false;
}
/* Check if this is actually a node tree. */
- if (GS(op_from->owner->owner->id->name) != ID_NT) {
+ if (GS(op_from->owner->owner->id_orig->name) != ID_NT) {
return false;
}
/* Different node trees. */
@@ -217,7 +234,7 @@ bool DepsgraphRelationBuilder::is_same_shapekey_dependency(
return false;
}
/* Check if this is actually a shape key datablock. */
- if (GS(op_from->owner->owner->id->name) != ID_KE) {
+ if (GS(op_from->owner->owner->id_orig->name) != ID_KE) {
return false;
}
/* Different key data blocks. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
index 4b8e4faae3f..3aae358dda3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
@@ -72,10 +72,14 @@ ComponentKey::ComponentKey(ID *id, eDepsNode_Type type, const char *name)
string ComponentKey::identifier() const
{
const char *idname = (id) ? id->name : "<None>";
- char typebuf[5];
- BLI_snprintf(typebuf, sizeof(typebuf), "%d", type);
- return string("ComponentKey(") +
- idname + ", " + typebuf + ", '" + name + "')";
+ string result = string("ComponentKey(");
+ result += idname;
+ result += ", " + string(nodeTypeAsString(type));
+ if (name[0] != '\0') {
+ result += ", '" + string(name) + "'";
+ }
+ result += ')';
+ return result;
}
/////////////////////////////////////////
@@ -174,13 +178,15 @@ OperationKey::OperationKey(ID *id,
string OperationKey::identifier() const
{
- char typebuf[5];
- BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type);
- return string("OperationKey(") +
- "t: " + typebuf +
- ", cn: '" + component_name +
- "', c: " + DEG_OPNAMES[opcode] +
- ", n: '" + name + "')";
+ string result = string("OperationKey(");
+ result += "type: " + string(nodeTypeAsString(component_type));
+ result += ", component name: '" + string(component_name) + "'";
+ result += ", operation code: " + string(operationCodeAsString(opcode));
+ if (name[0] != '\0') {
+ result += ", '" + string(name) + "'";
+ }
+ result += ")";
+ return result;
}
/////////////////////////////////////////
@@ -212,7 +218,7 @@ string RNAPathKey::identifier() const
const char *id_name = (id) ? id->name : "<No ID>";
const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>";
return string("RnaPathKey(") + "id: " + id_name +
- ", prop: " + prop_name + "')";
+ ", prop: '" + prop_name + "')";
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 43df6d2a94b..1260ce013ea 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -78,96 +78,102 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
RootPChanMap *root_map)
{
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
-
- /* attach owner to IK Solver too
- * - assume that owner is always part of chain
- * - see notes on direction of rel below...
- */
+ /* Attach owner to IK Solver to. */
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
if (rootchan == NULL) {
return;
}
- OperationKey pchan_local_key(&object->id, DEG_NODE_TYPE_BONE,
- pchan->name, DEG_OPCODE_BONE_LOCAL);
- OperationKey init_ik_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK);
- OperationKey solver_key(&object->id, DEG_NODE_TYPE_EVAL_POSE,
+ OperationKey pchan_local_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_LOCAL);
+ OperationKey init_ik_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK);
+ OperationKey solver_key(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
rootchan->name,
DEG_OPCODE_POSE_IK_SOLVER);
-
+ OperationKey pose_cleanup_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_CLEANUP);
add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree");
add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
-
+ /* Never cleanup before solver is run. */
+ add_relation(solver_key,
+ pose_cleanup_key,
+ "IK Solver -> Cleanup",
+ DEPSREL_FLAG_GODMODE);
/* IK target */
- // XXX: this should get handled as part of the constraint code
+ /* TODO(sergey): This should get handled as part of the constraint code. */
if (data->tar != NULL) {
- /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
- * we create dependency between target object and pose eval component.
+ /* TODO(sergey): For until we'll store partial matricies in the
+ * depsgraph, we create dependency between target object and pose eval
+ * component.
*
- * This way we ensuring the whole subtree is updated from scratch without
- * need of intermediate matricies. This is an overkill, but good enough for
- * testing IK solver.
- */
- // FIXME: geometry targets...
+ * This way we ensuring the whole subtree is updated from scratch
+ * without need of intermediate matricies. This is an overkill, but good
+ * enough for testing IK solver. */
ComponentKey pose_key(&object->id, DEG_NODE_TYPE_EVAL_POSE);
if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
- /* TODO(sergey): This is only for until granular update stores intermediate result. */
+ /* TODO(sergey): This is only for until granular update stores
+ * intermediate result. */
if (data->tar != object) {
- /* different armature - can just read the results */
- ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_BONE, data->subtarget);
+ /* Different armature - can just read the results. */
+ ComponentKey target_key(
+ &data->tar->id, DEG_NODE_TYPE_BONE, data->subtarget);
add_relation(target_key, pose_key, con->name);
}
else {
- /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
- OperationKey target_key(&data->tar->id, DEG_NODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
+ /* Same armature - we'll use the ready state only, just in case
+ * this bone is in the chain we're solving. */
+ OperationKey target_key(&data->tar->id,
+ DEG_NODE_TYPE_BONE,
+ data->subtarget,
+ DEG_OPCODE_BONE_DONE);
add_relation(target_key, solver_key, con->name);
}
}
- else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
- /* vertex group target */
- /* NOTE: for now, we don't need to represent vertex groups separately... */
+ else if (data->subtarget[0] &&
+ ELEM(data->tar->type, OB_MESH, OB_LATTICE))
+ {
+ /* Vertex group target. */
+ /* NOTE: for now, we don't need to represent vertex groups
+ * separately. */
ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(target_key, solver_key, con->name);
-
if (data->tar->type == OB_MESH) {
- OperationDepsNode *node2 = find_operation_node(target_key);
- if (node2 != NULL) {
- node2->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
+ add_customdata_mask(target_key, CD_MASK_MDEFORMVERT);
}
}
else {
- /* Standard Object Target */
+ /* Standard Object Target. */
ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(target_key, pose_key, con->name);
}
-
- if ((data->tar == object) && (data->subtarget[0])) {
+ if (data->tar == object && data->subtarget[0]) {
/* Prevent target's constraints from linking to anything from same
- * chain that it controls.
- */
+ * chain that it controls. */
root_map->add_bone(data->subtarget, rootchan->name);
}
}
-
- /* Pole Target */
- // XXX: this should get handled as part of the constraint code
+ /* Pole Target. */
+ /* TODO(sergey): This should get handled as part of the constraint code. */
if (data->poletar != NULL) {
if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
- // XXX: same armature issues - ready vs done?
- ComponentKey target_key(&data->poletar->id, DEG_NODE_TYPE_BONE, data->polesubtarget);
+ ComponentKey target_key(&data->poletar->id,
+ DEG_NODE_TYPE_BONE,
+ data->polesubtarget);
add_relation(target_key, solver_key, con->name);
}
- else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
- /* vertex group target */
- /* NOTE: for now, we don't need to represent vertex groups separately... */
+ else if (data->polesubtarget[0] &&
+ ELEM(data->poletar->type, OB_MESH, OB_LATTICE))
+ {
+ /* Vertex group target. */
+ /* NOTE: for now, we don't need to represent vertex groups
+ * separately. */
ComponentKey target_key(&data->poletar->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(target_key, solver_key, con->name);
-
if (data->poletar->type == OB_MESH) {
- OperationDepsNode *node2 = find_operation_node(target_key);
- if (node2 != NULL) {
- node2->customdata_mask |= CD_MASK_MDEFORMVERT;
- }
+ add_customdata_mask(target_key, CD_MASK_MDEFORMVERT);
}
}
else {
@@ -175,59 +181,65 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
add_relation(target_key, solver_key, con->name);
}
}
-
- DEG_DEBUG_PRINTF(BUILD, "\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
- pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
-
+ DEG_DEBUG_PRINTF(
+ (::Depsgraph *)graph_,
+ BUILD,
+ "\nStarting IK Build: pchan = %s, target = (%s, %s), "
+ "segcount = %d\n",
+ pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
bPoseChannel *parchan = pchan;
- /* exclude tip from chain? */
+ /* Exclude tip from chain if needed. */
if (!(data->flag & CONSTRAINT_IK_TIP)) {
parchan = pchan->parent;
}
-
root_map->add_bone(parchan->name, rootchan->name);
-
OperationKey parchan_transforms_key(&object->id, DEG_NODE_TYPE_BONE,
parchan->name, DEG_OPCODE_BONE_READY);
add_relation(parchan_transforms_key, solver_key, "IK Solver Owner");
-
- /* Walk to the chain's root */
- //size_t segcount = 0;
+ /* Walk to the chain's root. */
int segcount = 0;
-
- while (parchan) {
- /* Make IK-solver dependent on this bone's result,
- * since it can only run after the standard results
- * of the bone are know. Validate links step on the
- * bone will ensure that users of this bone only
- * grab the result with IK solver results...
- */
+ while (parchan != NULL) {
+ /* Make IK-solver dependent on this bone's result, since it can only run
+ * after the standard results of the bone are know. Validate links step
+ * on the bone will ensure that users of this bone only grab the result
+ * with IK solver results. */
if (parchan != pchan) {
- OperationKey parent_key(&object->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey parent_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ parchan->name,
+ DEG_OPCODE_BONE_READY);
add_relation(parent_key, solver_key, "IK Chain Parent");
-
- OperationKey done_key(&object->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, done_key, "IK Chain Result");
+ OperationKey bone_done_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ parchan->name,
+ DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, bone_done_key, "IK Chain Result");
}
else {
- OperationKey final_transforms_key(&object->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ OperationKey final_transforms_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ parchan->name,
+ DEG_OPCODE_BONE_DONE);
add_relation(solver_key, final_transforms_key, "IK Solver Result");
}
parchan->flag |= POSE_DONE;
-
-
root_map->add_bone(parchan->name, rootchan->name);
-
- /* continue up chain, until we reach target number of items... */
- DEG_DEBUG_PRINTF(BUILD, " %d = %s\n", segcount, parchan->name);
+ /* continue up chain, until we reach target number of items. */
+ DEG_DEBUG_PRINTF((::Depsgraph *)graph_,
+ BUILD,
+ " %d = %s\n",
+ segcount, parchan->name);
+ /* TODO(sergey): This is an arbitrary value, which was just following
+ * old code convention. */
segcount++;
- if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
-
+ if ((segcount == data->rootbone) || (segcount > 255)) {
+ break;
+ }
parchan = parchan->parent;
}
-
- OperationKey flush_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- add_relation(solver_key, flush_key, "PoseEval Result-Bone Link");
+ OperationKey pose_done_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link");
}
/* Spline IK Eval Steps */
@@ -238,107 +250,130 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object,
{
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
- OperationKey transforms_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
- OperationKey solver_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
-
- /* attach owner to IK Solver too
- * - assume that owner is always part of chain
- * - see notes on direction of rel below...
- */
- add_relation(transforms_key, solver_key, "Spline IK Solver Owner");
-
- /* attach path dependency to solver */
- if (data->tar) {
- /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
- * we create dependency between target object and pose eval component.
- * See IK pose for a bit more information.
+ OperationKey transforms_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_READY);
+ OperationKey init_ik_key(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ DEG_OPCODE_POSE_INIT_IK);
+ OperationKey solver_key(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ rootchan->name,
+ DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+ OperationKey pose_cleanup_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_CLEANUP);
+ /* Solver depends on initialization. */
+ add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
+ /* Never cleanup before solver is run. */
+ add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup");
+ /* Attach owner to IK Solver. */
+ add_relation(transforms_key,
+ solver_key,
+ "Spline IK Solver Owner",
+ DEPSREL_FLAG_GODMODE);
+ /* Attach path dependency to solver. */
+ if (data->tar != NULL) {
+ /* TODO(sergey): For until we'll store partial matricies in the
+ * depsgraph, we create dependency between target object and pose eval
+ * component. See IK pose for a bit more information.
*/
- // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
+ /* TODO: the bigggest point here is that we need the curve PATH and not
+ * just the general geometry. */
ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_GEOMETRY);
ComponentKey pose_key(&object->id, DEG_NODE_TYPE_EVAL_POSE);
add_relation(target_key, pose_key, "Curve.Path -> Spline IK");
}
-
pchan->flag |= POSE_DONE;
- OperationKey final_transforms_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+ OperationKey final_transforms_key(
+ &object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
add_relation(solver_key, final_transforms_key, "Spline IK Result");
-
root_map->add_bone(pchan->name, rootchan->name);
-
- /* Walk to the chain's root */
- //size_t segcount = 0;
+ /* Walk to the chain's root/ */
int segcount = 0;
-
- for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
- /* Make Spline IK solver dependent on this bone's result,
- * since it can only run after the standard results
- * of the bone are know. Validate links step on the
- * bone will ensure that users of this bone only
- * grab the result with IK solver results...
- */
+ for (bPoseChannel *parchan = pchan->parent;
+ parchan != NULL;
+ parchan = parchan->parent)
+ {
+ /* Make Spline IK solver dependent on this bone's result, since it can
+ * only run after the standard results of the bone are know. Validate
+ * links step on the bone will ensure that users of this bone only grab
+ * the result with IK solver results. */
if (parchan != pchan) {
- OperationKey parent_key(&object->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey parent_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ parchan->name,
+ DEG_OPCODE_BONE_READY);
add_relation(parent_key, solver_key, "Spline IK Solver Update");
-
- OperationKey done_key(&object->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, done_key, "IK Chain Result");
+ OperationKey bone_done_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ parchan->name,
+ DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, bone_done_key, "IK Chain Result");
}
parchan->flag |= POSE_DONE;
-
- OperationKey final_transforms_key(&object->id, DEG_NODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
- add_relation(solver_key, final_transforms_key, "Spline IK Solver Result");
-
+ OperationKey final_transforms_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ parchan->name,
+ DEG_OPCODE_BONE_DONE);
+ add_relation(
+ solver_key, final_transforms_key, "Spline IK Solver Result");
root_map->add_bone(parchan->name, rootchan->name);
-
- /* continue up chain, until we reach target number of items... */
+ /* TODO(sergey): This is an arbitrary value, which was just following
+ * old code convention. */
segcount++;
- if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */
+ if ((segcount == data->chainlen) || (segcount > 255)) {
+ break;
+ }
}
-
- OperationKey flush_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
- add_relation(solver_key, flush_key, "PoseEval Result-Bone Link");
+ OperationKey pose_done_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link");
}
/* Pose/Armature Bones Graph */
void DepsgraphRelationBuilder::build_rig(Object *object)
{
/* Armature-Data */
- bArmature *arm = (bArmature *)object->data;
-
+ bArmature *armature = (bArmature *)object->data;
// TODO: selection status?
-
- /* attach links between pose operations */
- OperationKey init_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
- OperationKey init_ik_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK);
- OperationKey flush_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-
- add_relation(init_key, init_ik_key, "Pose Init -> Pose Init IK");
- add_relation(init_ik_key, flush_key, "Pose Init IK -> Pose Cleanup");
-
+ /* Attach links between pose operations. */
+ ComponentKey local_transform(&object->id, DEG_NODE_TYPE_TRANSFORM);
+ OperationKey pose_init_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey pose_init_ik_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK);
+ OperationKey pose_cleanup_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_CLEANUP);
+ OperationKey pose_done_key(
+ &object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(
+ local_transform, pose_init_key, "Local Transform -> Pose Init");
+ add_relation(pose_init_key, pose_init_ik_key, "Pose Init -> Pose Init IK");
+ add_relation(
+ pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup");
/* Make sure pose is up-to-date with armature updates. */
- if (!built_map_.checkIsBuiltAndTag(arm)) {
- OperationKey armature_key(&arm->id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PLACEHOLDER,
- "Armature Eval");
- add_relation(armature_key, init_key, "Data dependency");
- }
-
- /* IK Solvers...
- * - These require separate processing steps are pose-level
- * to be executed between chains of bones (i.e. once the
- * base transforms of a bunch of bones is done)
+ build_armature(armature);
+ OperationKey armature_key(&armature->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
+ add_relation(armature_key, pose_init_key, "Data dependency");
+ /* IK Solvers.
*
- * - We build relations for these before the dependencies
- * between ops in the same component as it is necessary
- * to check whether such bones are in the same IK chain
- * (or else we get weird issues with either in-chain
- * references, or with bones being parented to IK'd bones)
+ * - These require separate processing steps are pose-level to be executed
+ * between chains of bones (i.e. once the base transforms of a bunch of
+ * bones is done).
+ *
+ * - We build relations for these before the dependencies between operations
+ * in the same component as it is necessary to check whether such bones
+ * are in the same IK chain (or else we get weird issues with either
+ * in-chain references, or with bones being parented to IK'd bones).
*
* Unsolved Issues:
- * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
- * - Animated chain-lengths are a problem...
- */
+ * - Care is needed to ensure that multi-headed trees work out the same as
+ * in ik-tree building
+ * - Animated chain-lengths are a problem. */
RootPChanMap root_map;
bool pose_depends_on_local_transform = false;
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
@@ -348,15 +383,12 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
build_ik_pose(object, pchan, con, &root_map);
pose_depends_on_local_transform = true;
break;
-
case CONSTRAINT_TYPE_SPLINEIK:
build_splineik_pose(object, pchan, con, &root_map);
pose_depends_on_local_transform = true;
break;
-
/* Constraints which needs world's matrix for transform.
- * TODO(sergey): More constraints here?
- */
+ * TODO(sergey): More constraints here? */
case CONSTRAINT_TYPE_ROTLIKE:
case CONSTRAINT_TYPE_SIZELIKE:
case CONSTRAINT_TYPE_LOCLIKE:
@@ -364,43 +396,50 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
/* TODO(sergey): Add used space check. */
pose_depends_on_local_transform = true;
break;
-
default:
break;
}
}
}
- //root_map.print_debug();
-
+ // root_map.print_debug();
if (pose_depends_on_local_transform) {
/* TODO(sergey): Once partial updates are possible use relation between
- * object transform and solver itself in it's build function.
- */
+ * object transform and solver itself in it's build function. */
ComponentKey pose_key(&object->id, DEG_NODE_TYPE_EVAL_POSE);
ComponentKey local_transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(local_transform_key, pose_key, "Local Transforms");
}
-
- /* links between operations for each bone */
+ /* Links between operations for each bone. */
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
- OperationKey bone_pose_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
- OperationKey bone_ready_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
- OperationKey bone_done_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
-
+ OperationKey bone_local_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_pose_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_POSE_PARENT);
+ OperationKey bone_ready_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_DONE);
pchan->flag &= ~POSE_DONE;
-
- /* pose init to bone local */
- add_relation(init_key, bone_local_key, "PoseEval Source-Bone Link");
-
- /* local to pose parenting operation */
- add_relation(bone_local_key, bone_pose_key, "Bone Local - PoseSpace Link");
-
- /* parent relation */
+ /* Pose init to bone local. */
+ add_relation(pose_init_key,
+ bone_local_key,
+ "Pose Init - Bone Local",
+ DEPSREL_FLAG_GODMODE);
+ /* Local to pose parenting operation. */
+ add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose");
+ /* Parent relation. */
if (pchan->parent != NULL) {
eDepsOperation_Code parent_key_opcode;
-
- /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
+ /* NOTE: this difference in handling allows us to prevent lockups
+ * while ensuring correct poses for separate chains. */
if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
parent_key_opcode = DEG_OPCODE_BONE_READY;
}
@@ -408,59 +447,103 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
parent_key_opcode = DEG_OPCODE_BONE_DONE;
}
- OperationKey parent_key(&object->id, DEG_NODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
- add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone");
+ OperationKey parent_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->parent->name,
+ parent_key_opcode);
+ add_relation(
+ parent_key, bone_pose_key, "Parent Bone -> Child Bone");
}
-
- /* constraints */
+ /* Build constraints. */
if (pchan->constraints.first != NULL) {
/* Build relations for indirectly linked objects. */
BuilderWalkUserData data;
data.builder = this;
- BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
-
- /* constraints stack and constraint dependencies */
- build_constraints(&object->id, DEG_NODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
-
- /* pose -> constraints */
- OperationKey constraints_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
+ BKE_constraints_id_loop(
+ &pchan->constraints, constraint_walk, &data);
+ /* Constraints stack and constraint dependencies. */
+ build_constraints(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ &pchan->constraints,
+ &root_map);
+ /* Pose -> constraints. */
+ OperationKey constraints_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_CONSTRAINTS);
add_relation(bone_pose_key, constraints_key, "Constraints Stack");
-
- /* constraints -> ready */
- // TODO: when constraint stack is exploded, this step should occur before the first IK solver
- add_relation(constraints_key, bone_ready_key, "Constraints -> Ready");
+ /* Constraints -> ready/ */
+ /* TODO(sergey): When constraint stack is exploded, this step should
+ * occur before the first IK solver. */
+ add_relation(
+ constraints_key, bone_ready_key, "Constraints -> Ready");
}
else {
- /* pose -> ready */
+ /* Pose -> Ready */
add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready");
}
-
- /* bone ready -> done
+ /* Bone ready -> Bone done.
* NOTE: For bones without IK, this is all that's needed.
- * For IK chains however, an additional rel is created from IK to done,
- * with transitive reduction removing this one...
- */
+ * For IK chains however, an additional rel is created from IK
+ * to done, with transitive reduction removing this one. */
add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
-
- /* assume that all bones must be done for the pose to be ready (for deformers) */
- add_relation(bone_done_key, flush_key, "PoseEval Result-Bone Link");
-
+ /* B-Bone shape is the real final step after Done if present. */
+ if (pchan->bone != NULL && pchan->bone->segments > 1) {
+ OperationKey bone_segments_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_SEGMENTS);
+ /* B-Bone shape depends on the final position of the bone. */
+ add_relation(bone_done_key, bone_segments_key, "Done -> B-Bone Segments");
+ /* B-Bone shape depends on final position of handle bones. */
+ bPoseChannel *prev, *next;
+ BKE_pchan_get_bbone_handles(pchan, &prev, &next);
+ if (prev) {
+ OperationKey prev_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ prev->name,
+ DEG_OPCODE_BONE_DONE);
+ add_relation(prev_key, bone_segments_key, "Prev Handle -> B-Bone Segments");
+ }
+ if (next) {
+ OperationKey next_key(&object->id,
+ DEG_NODE_TYPE_BONE,
+ next->name,
+ DEG_OPCODE_BONE_DONE);
+ add_relation(next_key, bone_segments_key, "Next Handle -> B-Bone Segments");
+ }
+ /* Pose requires the B-Bone shape. */
+ add_relation(bone_segments_key, pose_done_key, "PoseEval Result-Bone Link");
+ add_relation(bone_segments_key, pose_cleanup_key, "Cleanup dependency");
+ }
+ else {
+ /* Assume that all bones must be done for the pose to be ready
+ * (for deformers). */
+ add_relation(bone_done_key, pose_done_key, "PoseEval Result-Bone Link");
+ add_relation(bone_done_key, pose_cleanup_key, "Cleanup dependency");
+ }
/* Custom shape. */
if (pchan->custom != NULL) {
- build_object(pchan->custom);
+ build_object(NULL, pchan->custom);
}
}
}
void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
{
+ bArmature *armature = (bArmature *)object->data;
Object *proxy_from = object->proxy_from;
+ build_armature(armature);
OperationKey pose_init_key(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
DEG_OPCODE_POSE_INIT);
OperationKey pose_done_key(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
DEG_OPCODE_POSE_DONE);
+ OperationKey pose_cleanup_key(&object->id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ DEG_OPCODE_POSE_CLEANUP);
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
OperationKey bone_local_key(&object->id,
DEG_NODE_TYPE_BONE, pchan->name,
@@ -473,11 +556,33 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
DEG_NODE_TYPE_BONE,
pchan->name,
DEG_OPCODE_BONE_DONE);
+ OperationKey from_bone_done_key(&proxy_from->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_DONE);
add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local");
add_relation(bone_local_key, bone_ready_key, "Local -> Ready");
add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
+ add_relation(
+ bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup");
add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done");
+ /* Make sure bone in the proxy is not done before it's FROM is done. */
+ if (pchan->bone && pchan->bone->segments > 1) {
+ OperationKey from_bone_segments_key(&proxy_from->id,
+ DEG_NODE_TYPE_BONE,
+ pchan->name,
+ DEG_OPCODE_BONE_SEGMENTS);
+ add_relation(from_bone_segments_key,
+ bone_done_key,
+ "From Bone Segments -> Bone Done");
+ }
+ else {
+ add_relation(from_bone_done_key,
+ bone_done_key,
+ "From Bone Done -> Bone Done");
+ }
+
if (pchan->prop != NULL) {
OperationKey bone_parameters(&object->id,
DEG_NODE_TYPE_PARAMETERS,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
index c51addbd206..999508cffed 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph
@@ -46,6 +46,7 @@ extern "C" {
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
} /* extern "C" */
@@ -68,17 +69,44 @@ extern "C" {
namespace DEG {
-void DepsgraphRelationBuilder::build_scene(Scene *scene)
+void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb)
{
- if (scene->set != NULL) {
- build_scene(scene->set);
+ const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ?
+ COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER;
+
+ for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) {
+ if ((lc->collection->flag & restrict_flag)) {
+ continue;
+ }
+ if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
+ build_collection(lc, NULL, lc->collection);
+ }
+ build_layer_collections(&lc->layer_collections);
}
+}
+
+void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_layer)
+{
/* Setup currently building context. */
scene_ = scene;
/* Scene objects. */
- LISTBASE_FOREACH (Base *, base, &scene->base) {
- Object *object = base->object;
- build_object(object);
+ /* NOTE: Nodes builder requires us to pass CoW base because it's being
+ * passed to the evaluation functions. During relations builder we only
+ * do NULL-pointer check of the base, so it's fine to pass original one.
+ */
+ const int base_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ?
+ BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER;
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ const bool is_object_visible = (base->flag & base_flag);
+ if (is_object_visible) {
+ build_object(base, base->object);
+ }
+ }
+
+ build_layer_collections(&view_layer->layer_collections);
+
+ if (scene->camera != NULL) {
+ build_object(NULL, scene->camera);
}
/* Rigidbody. */
if (scene->rigidbody_world != NULL) {
@@ -96,10 +124,6 @@ void DepsgraphRelationBuilder::build_scene(Scene *scene)
if (scene->nodetree != NULL) {
build_compositor(scene);
}
- /* Grease pencil. */
- if (scene->gpd != NULL) {
- build_gpencil(scene->gpd);
- }
/* Masks. */
LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) {
build_mask(mask);
@@ -108,18 +132,20 @@ void DepsgraphRelationBuilder::build_scene(Scene *scene)
LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
build_movieclip(clip);
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph_->operations.begin();
- it_op != graph_->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ /* TODO(sergey): Do this flush on CoW object? */
+ foreach (OperationDepsNode *node, graph_->operations) {
IDDepsNode *id_node = node->owner->owner;
- ID *id = id_node->id;
+ ID *id = id_node->id_orig;
if (GS(id->name) == ID_OB) {
Object *object = (Object *)id;
object->customdata_mask |= node->customdata_mask;
}
}
+ /* Build all set scenes. */
+ if (scene->set != NULL) {
+ ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set);
+ build_view_layer(scene->set, set_view_layer);
+ }
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 12760cad73c..a39b18f2f0a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -65,16 +65,16 @@ enum {
static void deg_graph_tag_paths_recursive(DepsNode *node)
{
- if (node->done & OP_VISITED) {
+ if (node->custom_flags & OP_VISITED) {
return;
}
- node->done |= OP_VISITED;
+ node->custom_flags |= OP_VISITED;
foreach (DepsRelation *rel, node->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
/* Do this only in inlinks loop, so the target node does not get
* flagged.
*/
- rel->from->done |= OP_REACHABLE;
+ rel->from->custom_flags |= OP_REACHABLE;
}
}
@@ -84,13 +84,13 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
foreach (OperationDepsNode *target, graph->operations) {
/* Clear tags. */
foreach (OperationDepsNode *node, graph->operations) {
- node->done = 0;
+ node->custom_flags = 0;
}
/* Mark nodes from which we can reach the target
* start with children, so the target node and direct children are not
* flagged.
*/
- target->done |= OP_VISITED;
+ target->custom_flags |= OP_VISITED;
foreach (DepsRelation *rel, target->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
}
@@ -101,13 +101,14 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
{
DepsRelation *rel = *it_rel;
if (rel->from->type == DEG_NODE_TYPE_TIMESOURCE) {
- /* HACK: time source nodes don't get "done" flag set/cleared. */
+ /* HACK: time source nodes don't get "custom_flags" flag
+ * set/cleared. */
/* TODO: there will be other types in future, so iterators above
* need modifying.
*/
++it_rel;
}
- else if (rel->from->done & OP_REACHABLE) {
+ else if (rel->from->custom_flags & OP_REACHABLE) {
rel->unlink();
OBJECT_GUARDED_DELETE(rel, DepsRelation);
++num_removed_relations;
@@ -117,7 +118,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
}
}
}
- DEG_DEBUG_PRINTF(BUILD, "Removed %d relations\n", num_removed_relations);
+ DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 80772f9595f..ec1ea1e02b2 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -69,6 +69,7 @@ static const char *deg_debug_colors[] = {
"#33a02c", "#fb9a99", "#e31a1c",
"#fdbf6f", "#ff7f00", "#cab2d6",
"#6a3d9a", "#ffff99", "#b15928",
+ "#ff00ff",
};
#endif
static const char *deg_debug_colors_light[] = {
@@ -76,23 +77,28 @@ static const char *deg_debug_colors_light[] = {
"#fb8072", "#80b1d3", "#fdb462",
"#b3de69", "#fccde5", "#d9d9d9",
"#bc80bd", "#ccebc5", "#ffed6f",
+ "#ff00ff",
};
#ifdef COLOR_SCHEME_NODE_TYPE
static const int deg_debug_node_type_color_map[][2] = {
{DEG_NODE_TYPE_TIMESOURCE, 0},
- {DEG_NODE_TYPE_ID_REF, 2},
+ {DEG_NODE_TYPE_ID_REF, 1},
/* Outer Types */
- {DEG_NODE_TYPE_PARAMETERS, 2},
- {DEG_NODE_TYPE_PROXY, 3},
- {DEG_NODE_TYPE_ANIMATION, 4},
- {DEG_NODE_TYPE_TRANSFORM, 5},
- {DEG_NODE_TYPE_GEOMETRY, 6},
- {DEG_NODE_TYPE_SEQUENCER, 7},
- {DEG_NODE_TYPE_SHADING, 8},
- {DEG_NODE_TYPE_CACHE, 9},
- {-1, 0}
+ {DEG_NODE_TYPE_PARAMETERS, 2},
+ {DEG_NODE_TYPE_PROXY, 3},
+ {DEG_NODE_TYPE_ANIMATION, 4},
+ {DEG_NODE_TYPE_TRANSFORM, 5},
+ {DEG_NODE_TYPE_GEOMETRY, 6},
+ {DEG_NODE_TYPE_SEQUENCER, 7},
+ {DEG_NODE_TYPE_SHADING, 8},
+ {DEG_NODE_TYPE_SHADING_PARAMETERS, 9},
+ {DEG_NODE_TYPE_CACHE, 10},
+ {DEG_NODE_TYPE_POINT_CACHE, 11},
+ {DEG_NODE_TYPE_LAYER_COLLECTIONS, 12},
+ {DEG_NODE_TYPE_COPY_ON_WRITE, 13},
+ {-1, 0}
};
#endif
@@ -248,10 +254,14 @@ static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
const DepsRelation *rel)
{
const char *color_default = "black";
- const char *color_error = "red4";
+ const char *color_cyclic = "red4"; /* The color of crime scene. */
+ const char *color_godmode = "blue4"; /* The color of beautiful sky. */
const char *color = color_default;
if (rel->flag & DEPSREL_FLAG_CYCLIC) {
- color = color_error;
+ color = color_cyclic;
+ }
+ else if (rel->flag & DEPSREL_FLAG_GODMODE) {
+ color = color_godmode;
}
deg_debug_fprintf(ctx, "%s", color);
}
@@ -261,13 +271,37 @@ static void deg_debug_graphviz_relation_style(const DebugContext &ctx,
{
const char *style_default = "solid";
const char *style_no_flush = "dashed";
+ const char *style_flush_user_only = "dotted";
const char *style = style_default;
if (rel->flag & DEPSREL_FLAG_NO_FLUSH) {
style = style_no_flush;
}
+ if (rel->flag & DEPSREL_FLAG_FLUSH_USER_EDIT_ONLY) {
+ style = style_flush_user_only;
+ }
deg_debug_fprintf(ctx, "%s", style);
}
+static void deg_debug_graphviz_relation_arrowhead(const DebugContext &ctx,
+ const DepsRelation *rel)
+{
+ const char *shape_default = "normal";
+ const char *shape_no_cow = "box";
+ const char *shape = shape_default;
+ if (rel->from->get_class() == DEG_NODE_CLASS_OPERATION &&
+ rel->to->get_class() == DEG_NODE_CLASS_OPERATION)
+ {
+ OperationDepsNode *op_from = (OperationDepsNode *)rel->from;
+ OperationDepsNode *op_to = (OperationDepsNode *)rel->to;
+ if (op_from->owner->type == DEG_NODE_TYPE_COPY_ON_WRITE &&
+ !op_to->owner->need_tag_cow_before_update())
+ {
+ shape = shape_no_cow;
+ }
+ }
+ deg_debug_fprintf(ctx, "%s", shape);
+}
+
static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
{
const char *base_style = "filled"; /* default style */
@@ -297,12 +331,6 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx,
{
const char *shape = "box";
string name = node->identifier();
- if (node->type == DEG_NODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
- name += buf;
- }
deg_debug_fprintf(ctx, "// %s\n", name.c_str());
deg_debug_fprintf(ctx, "\"node_%p\"", node);
deg_debug_fprintf(ctx, "[");
@@ -323,12 +351,6 @@ static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
const DepsNode *node)
{
string name = node->identifier();
- if (node->type == DEG_NODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %u)", id_node->layers);
- name += buf;
- }
deg_debug_fprintf(ctx, "// %s\n", name.c_str());
deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
@@ -390,8 +412,15 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
case DEG_NODE_TYPE_EVAL_POSE:
case DEG_NODE_TYPE_BONE:
case DEG_NODE_TYPE_SHADING:
+ case DEG_NODE_TYPE_SHADING_PARAMETERS:
case DEG_NODE_TYPE_CACHE:
+ case DEG_NODE_TYPE_POINT_CACHE:
+ case DEG_NODE_TYPE_LAYER_COLLECTIONS:
case DEG_NODE_TYPE_EVAL_PARTICLES:
+ case DEG_NODE_TYPE_COPY_ON_WRITE:
+ case DEG_NODE_TYPE_OBJECT_FROM_LAYER:
+ case DEG_NODE_TYPE_BATCH_CACHE:
+ case DEG_NODE_TYPE_DUPLI:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
if (!comp_node->operations.empty()) {
@@ -406,9 +435,13 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
}
break;
}
- default:
+ case DEG_NODE_TYPE_UNDEFINED:
+ case DEG_NODE_TYPE_TIMESOURCE:
+ case DEG_NODE_TYPE_OPERATION:
deg_debug_graphviz_node_single(ctx, node);
break;
+ case NUM_DEG_NODE_TYPES:
+ break;
}
}
@@ -485,6 +518,8 @@ static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
deg_debug_graphviz_relation_color(ctx, rel);
deg_debug_fprintf(ctx, ",style=");
deg_debug_graphviz_relation_style(ctx, rel);
+ deg_debug_fprintf(ctx, ",arrowhead=");
+ deg_debug_graphviz_relation_arrowhead(ctx, rel);
deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth);
/* NOTE: edge from node to own cluster is not possible and gives graphviz
* warning, avoid this here by just linking directly to the invisible
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
index e92c7730482..0ea9f564fb1 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
@@ -84,7 +84,26 @@ BLI_INLINE double get_node_time(const DebugContext& /*ctx*/,
bool stat_entry_comparator(const StatsEntry& a, const StatsEntry& b)
{
- return a.time < b.time;
+ return a.time > b.time;
+}
+
+string gnuplotify_id_code(const string& name)
+{
+ return string("") + name[0] + name[1];
+}
+
+string gnuplotify_name(const string& name)
+{
+ string result = "";
+ const int length = name.length();
+ for (int i = 0; i < length; ++i) {
+ const char ch = name[i];
+ if (ch == '_') {
+ result += "\\\\\\";
+ }
+ result += ch;
+ }
+ return result;
}
void write_stats_data(const DebugContext& ctx)
@@ -106,12 +125,15 @@ void write_stats_data(const DebugContext& ctx)
std::sort(stats.begin(), stats.end(), stat_entry_comparator);
// We limit number of entries, otherwise things become unreadable.
stats.resize(min_ii(stats.size(), 32));
+ std::reverse(stats.begin(), stats.end());
// Print data to the file stream.
deg_debug_fprintf(ctx, "$data << EOD" NL);
foreach (const StatsEntry& entry, stats) {
- deg_debug_fprintf(ctx, "\"%s\",%f" NL,
- entry.id_node->id->name + 2,
- entry.time);
+ deg_debug_fprintf(
+ ctx, "\"[%s] %s\",%f" NL,
+ gnuplotify_id_code(entry.id_node->id_orig->name).c_str(),
+ gnuplotify_name(entry.id_node->id_orig->name + 2).c_str(),
+ entry.time);
}
deg_debug_fprintf(ctx, "EOD" NL);
}
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 681af26637c..6dd7ae97073 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -48,15 +48,19 @@ extern "C" {
#include "DNA_object_types.h"
#include "DNA_sequence_types.h"
-#include "BKE_depsgraph.h"
-
#include "RNA_access.h"
+
+#include "BKE_scene.h"
+#include "BKE_constraint.h"
}
#include <algorithm>
#include <cstring>
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
@@ -71,7 +75,6 @@ namespace DEG {
static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
-static DEG_EditorUpdateScenePreCb deg_editor_update_scene_pre_cb = NULL;
/* TODO(sergey): Find a better place for this. */
template <typename T>
@@ -81,14 +84,24 @@ static void remove_from_vector(vector<T> *vector, const T& value)
vector->end());
}
-Depsgraph::Depsgraph()
+Depsgraph::Depsgraph(Scene *scene,
+ ViewLayer *view_layer,
+ eEvaluationMode mode)
: time_source(NULL),
- need_update(false),
- layers(0)
+ need_update(true),
+ scene(scene),
+ view_layer(view_layer),
+ mode(mode),
+ ctime(BKE_scene_frame_get(scene)),
+ scene_cow(NULL),
+ is_active(false)
{
BLI_spin_init(&lock);
id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
+ debug_flags = G.debug;
+ memset(id_type_updated, 0, sizeof(id_type_updated));
+ memset(physics_relations, 0, sizeof(physics_relations));
}
Depsgraph::~Depsgraph()
@@ -171,6 +184,25 @@ static bool pointer_to_component_node_criteria(
}
}
}
+ else if (ELEM(ptr->type, &RNA_ConstraintTarget, &RNA_ConstraintTargetBone)) {
+ Object *object = (Object *)ptr->id.data;
+ bConstraintTarget *tgt = (bConstraintTarget *)ptr->data;
+ /* Check whether is object or bone constraint. */
+ bPoseChannel *pchan = NULL;
+ bConstraint *con = BKE_constraint_find_from_target(object, tgt, &pchan);
+ if (con != NULL) {
+ if (pchan != NULL) {
+ *type = DEG_NODE_TYPE_BONE;
+ *operation_code = DEG_OPCODE_BONE_LOCAL;
+ *subdata = pchan->name;
+ }
+ else {
+ *type = DEG_NODE_TYPE_TRANSFORM;
+ *operation_code = DEG_OPCODE_TRANSFORM_LOCAL;
+ }
+ return true;
+ }
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
*type = DEG_NODE_TYPE_GEOMETRY;
return true;
@@ -214,6 +246,14 @@ static bool pointer_to_component_node_criteria(
*subdata = seq->name; // xxx?
return true;
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
+ *type = DEG_NODE_TYPE_SHADING;
+ return true;
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) {
+ *type = DEG_NODE_TYPE_SHADING;
+ return true;
+ }
else if (ptr->type == &RNA_Curve) {
*id = (ID *)ptr->id.data;
*type = DEG_NODE_TYPE_GEOMETRY;
@@ -274,12 +314,6 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
/* Node Management ---------------------------- */
-static void id_node_deleter(void *value)
-{
- IDDepsNode *id_node = reinterpret_cast<IDDepsNode *>(value);
- OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
-}
-
TimeSourceDepsNode *Depsgraph::add_time_source()
{
if (time_source == NULL) {
@@ -299,71 +333,100 @@ IDDepsNode *Depsgraph::find_id_node(const ID *id) const
return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id));
}
-IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name)
+IDDepsNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint)
{
+ BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) == 0);
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_ID_REF);
- id_node = (IDDepsNode *)factory->create_node(id, "", name);
- /* register */
+ id_node = (IDDepsNode *)factory->create_node(id, "", id->name);
+ id_node->init_copy_on_write(id_cow_hint);
+ /* Register node in ID hash.
+ *
+ * NOTE: We address ID nodes by the original ID pointer they are
+ * referencing to.
+ */
BLI_ghash_insert(id_hash, id, id_node);
id_nodes.push_back(id_node);
}
return id_node;
}
+void Depsgraph::clear_id_nodes_conditional(const std::function <bool (ID_Type id_type)>& filter)
+{
+ foreach (IDDepsNode *id_node, id_nodes) {
+ if (id_node->id_cow == NULL) {
+ /* This means builder "stole" ownership of the copy-on-written
+ * datablock for her own dirty needs.
+ */
+ continue;
+ }
+ if (!deg_copy_on_write_is_expanded(id_node->id_cow)) {
+ continue;
+ }
+ const ID_Type id_type = GS(id_node->id_cow->name);
+ if (filter(id_type)) {
+ id_node->destroy();
+ }
+ }
+}
+
void Depsgraph::clear_id_nodes()
{
- BLI_ghash_clear(id_hash, NULL, id_node_deleter);
+ /* Free memory used by ID nodes. */
+
+ /* Stupid workaround to ensure we free IDs in a proper order. */
+ clear_id_nodes_conditional([](ID_Type id_type) { return id_type == ID_SCE; });
+ clear_id_nodes_conditional([](ID_Type id_type) { return id_type != ID_PA; });
+
+ foreach (IDDepsNode *id_node, id_nodes) {
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+ }
+ /* Clear containers. */
+ BLI_ghash_clear(id_hash, NULL, NULL);
id_nodes.clear();
+ /* Clear physics relation caches. */
+ deg_clear_physics_relations(this);
}
/* Add new relationship between two nodes. */
DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
const char *description,
- bool check_unique)
+ bool check_unique,
+ int flags)
{
DepsRelation *rel = NULL;
if (check_unique) {
rel = check_nodes_connected(from, to, description);
}
if (rel != NULL) {
+ rel->flag |= flags;
return rel;
}
/* Create new relation, and add it to the graph. */
rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
- /* TODO(sergey): Find a better place for this. */
-#ifdef WITH_OPENSUBDIV
- ComponentDepsNode *comp_node = from->owner;
- if (comp_node->type == DEG_NODE_TYPE_GEOMETRY) {
- IDDepsNode *id_to = to->owner->owner;
- IDDepsNode *id_from = from->owner->owner;
- if (id_to != id_from && (id_to->id->recalc & ID_RECALC_ALL)) {
- if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) {
- id_from->tag_update(this);
- id_from->eval_flags |= DAG_EVAL_NEED_CPU;
- }
- }
- }
-#endif
+ rel->flag |= flags;
return rel;
}
/* Add new relation between two nodes */
DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
const char *description,
- bool check_unique)
+ bool check_unique,
+ int flags)
{
DepsRelation *rel = NULL;
if (check_unique) {
rel = check_nodes_connected(from, to, description);
}
if (rel != NULL) {
+ rel->flag |= flags;
return rel;
}
/* Create new relation, and add it to the graph. */
rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
+ rel->flag |= flags;
return rel;
}
@@ -433,9 +496,9 @@ void DepsRelation::unlink()
void Depsgraph::add_entry_tag(OperationDepsNode *node)
{
/* Sanity check. */
- if (!node)
+ if (node == NULL) {
return;
-
+ }
/* Add to graph-level set of directly modified nodes to start searching from.
* NOTE: this is necessary since we have several thousand nodes to play with...
*/
@@ -451,17 +514,46 @@ void Depsgraph::clear_all_nodes()
}
}
-void deg_editors_id_update(Main *bmain, ID *id)
+ID *Depsgraph::get_cow_id(const ID *id_orig) const
+{
+ IDDepsNode *id_node = find_id_node(id_orig);
+ if (id_node == NULL) {
+ /* This function is used from places where we expect ID to be either
+ * already a copy-on-write version or have a corresponding copy-on-write
+ * version.
+ *
+ * We try to enforce that in debug builds, for for release we play a bit
+ * safer game here.
+ */
+ if ((id_orig->tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+ /* TODO(sergey): This is nice sanity check to have, but it fails
+ * in following situations:
+ *
+ * - Material has link to texture, which is not needed by new
+ * shading system and hence can be ignored at construction.
+ * - Object or mesh has material at a slot which is not used (for
+ * example, object has material slot by materials are set to
+ * object data).
+ */
+ // BLI_assert(!"Request for non-existing copy-on-write ID");
+ }
+ return (ID *)id_orig;
+ }
+ return id_node->id_cow;
+}
+
+void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, ID *id)
{
if (deg_editor_update_id_cb != NULL) {
- deg_editor_update_id_cb(bmain, id);
+ deg_editor_update_id_cb(update_ctx, id);
}
}
-void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
+ bool updated)
{
if (deg_editor_update_scene_cb != NULL) {
- deg_editor_update_scene_cb(bmain, scene, updated);
+ deg_editor_update_scene_cb(update_ctx, updated);
}
}
@@ -496,9 +588,14 @@ string deg_color_end(void)
/* Public Graph API */
/* Initialize a new Depsgraph */
-Depsgraph *DEG_graph_new()
-{
- DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph);
+Depsgraph *DEG_graph_new(Scene *scene,
+ ViewLayer *view_layer,
+ eEvaluationMode mode)
+{
+ DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph,
+ scene,
+ view_layer,
+ mode);
return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
@@ -512,32 +609,68 @@ void DEG_graph_free(Depsgraph *graph)
/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
- DEG_EditorUpdateSceneCb scene_func,
- DEG_EditorUpdateScenePreCb scene_pre_func)
+ DEG_EditorUpdateSceneCb scene_func)
{
DEG::deg_editor_update_id_cb = id_func;
DEG::deg_editor_update_scene_cb = scene_func;
- DEG::deg_editor_update_scene_pre_cb = scene_pre_func;
}
-void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time)
+bool DEG_is_active(const struct Depsgraph *depsgraph)
{
- if (DEG::deg_editor_update_scene_pre_cb != NULL) {
- DEG::deg_editor_update_scene_pre_cb(bmain, scene, time);
+ if (depsgraph == NULL) {
+ /* Happens for such cases as work object in what_does_obaction(),
+ * and sine render pipeline parts. Shouldn't really be accepting
+ * NULL depsgraph, but is quite hard to get proper one in those
+ * cases.
+ */
+ return false;
}
+ const DEG::Depsgraph *deg_graph =
+ reinterpret_cast<const DEG::Depsgraph *>(depsgraph);
+ return deg_graph->is_active;
+}
+
+void DEG_make_active(struct Depsgraph *depsgraph)
+{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ deg_graph->is_active = true;
+ /* TODO(sergey): Copy data from evaluated state to original. */
+}
+
+void DEG_make_inactive(struct Depsgraph *depsgraph)
+{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ deg_graph->is_active = false;
}
/* Evaluation and debug */
-void DEG_debug_print_eval(const char *function_name,
+static DEG::string depsgraph_name_for_logging(struct Depsgraph *depsgraph)
+{
+ const char *name = DEG_debug_name_get(depsgraph);
+ if (name[0] == '\0') {
+ return "";
+ }
+ return "[" + DEG::string(name) + "]: ";
+}
+
+void DEG_debug_print_begin(struct Depsgraph *depsgraph)
+{
+ fprintf(stdout, "%s",
+ depsgraph_name_for_logging(depsgraph).c_str());
+}
+
+void DEG_debug_print_eval(struct Depsgraph *depsgraph,
+ const char *function_name,
const char *object_name,
const void *object_address)
{
- if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
return;
}
fprintf(stdout,
- "%s on %s %s(%p)%s\n",
+ "%s%s on %s %s(%p)%s\n",
+ depsgraph_name_for_logging(depsgraph).c_str(),
function_name,
object_name,
DEG::deg_color_for_pointer(object_address).c_str(),
@@ -546,18 +679,20 @@ void DEG_debug_print_eval(const char *function_name,
fflush(stdout);
}
-void DEG_debug_print_eval_subdata(const char *function_name,
+void DEG_debug_print_eval_subdata(struct Depsgraph *depsgraph,
+ const char *function_name,
const char *object_name,
const void *object_address,
const char *subdata_comment,
const char *subdata_name,
const void *subdata_address)
{
- if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
return;
}
fprintf(stdout,
- "%s on %s %s(%p)%s %s %s %s(%p)%s\n",
+ "%s%s on %s %s(%p)%s %s %s %s(%p)%s\n",
+ depsgraph_name_for_logging(depsgraph).c_str(),
function_name,
object_name,
DEG::deg_color_for_pointer(object_address).c_str(),
@@ -571,7 +706,8 @@ void DEG_debug_print_eval_subdata(const char *function_name,
fflush(stdout);
}
-void DEG_debug_print_eval_subdata_index(const char *function_name,
+void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph,
+ const char *function_name,
const char *object_name,
const void *object_address,
const char *subdata_comment,
@@ -579,11 +715,12 @@ void DEG_debug_print_eval_subdata_index(const char *function_name,
const void *subdata_address,
const int subdata_index)
{
- if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
return;
}
fprintf(stdout,
- "%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n",
+ "%s%s on %s %s(%p)%s %s %s[%d] %s(%p)%s\n",
+ depsgraph_name_for_logging(depsgraph).c_str(),
function_name,
object_name,
DEG::deg_color_for_pointer(object_address).c_str(),
@@ -598,16 +735,45 @@ void DEG_debug_print_eval_subdata_index(const char *function_name,
fflush(stdout);
}
-void DEG_debug_print_eval_time(const char *function_name,
+void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph,
+ const char *function_name,
+ const char *object_name,
+ const void *object_address,
+ const char *parent_comment,
+ const char *parent_name,
+ const void *parent_address)
+{
+ if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ return;
+ }
+ fprintf(stdout,
+ "%s%s on %s %s(%p) [%s] %s %s %s(%p)%s\n",
+ depsgraph_name_for_logging(depsgraph).c_str(),
+ function_name,
+ object_name,
+ DEG::deg_color_for_pointer(object_address).c_str(),
+ object_address,
+ DEG::deg_color_end().c_str(),
+ parent_comment,
+ parent_name,
+ DEG::deg_color_for_pointer(parent_address).c_str(),
+ parent_address,
+ DEG::deg_color_end().c_str());
+ fflush(stdout);
+}
+
+void DEG_debug_print_eval_time(struct Depsgraph *depsgraph,
+ const char *function_name,
const char *object_name,
const void *object_address,
float time)
{
- if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
+ if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
return;
}
fprintf(stdout,
- "%s on %s %s(%p)%s at time %f\n",
+ "%s%s on %s %s(%p)%s at time %f\n",
+ depsgraph_name_for_logging(depsgraph).c_str(),
function_name,
object_name,
DEG::deg_color_for_pointer(object_address).c_str(),
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index dda4da7bc13..fd45c482bb5 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -36,15 +36,27 @@
#pragma once
+#include <stdlib.h>
+
+#include "DNA_ID.h" /* for ID_Type */
+
+#include "BKE_main.h" /* for MAX_LIBARRAY */
+
#include "BLI_threads.h" /* for SpinLock */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+
#include "intern/depsgraph_types.h"
struct ID;
struct GHash;
+struct Main;
struct GSet;
struct PointerRNA;
struct PropertyRNA;
+struct Scene;
+struct ViewLayer;
namespace DEG {
@@ -60,11 +72,15 @@ struct OperationDepsNode;
/* Settings/Tags on Relationship */
typedef enum eDepsRelation_Flag {
/* "cyclic" link - when detecting cycles, this relationship was the one
- * which triggers a cyclic relationship to exist in the graph.
- */
- DEPSREL_FLAG_CYCLIC = (1 << 0),
+ * which triggers a cyclic relationship to exist in the graph. */
+ DEPSREL_FLAG_CYCLIC = (1 << 0),
/* Update flush will not go through this relation. */
- DEPSREL_FLAG_NO_FLUSH = (1 << 1),
+ DEPSREL_FLAG_NO_FLUSH = (1 << 1),
+ /* Only flush along the relation is update comes from a node which was
+ * affected by user input. */
+ DEPSREL_FLAG_FLUSH_USER_EDIT_ONLY = (1 << 2),
+ /* The relation can not be killed by the cyclic dependencies solver. */
+ DEPSREL_FLAG_GODMODE = (1 << 3),
} eDepsRelation_Flag;
/* B depends on A (A -> B) */
@@ -96,14 +112,17 @@ struct Depsgraph {
typedef vector<OperationDepsNode *> OperationNodes;
typedef vector<IDDepsNode *> IDDepsNodes;
- Depsgraph();
+ Depsgraph(Scene *scene,
+ ViewLayer *view_layer,
+ eEvaluationMode mode);
~Depsgraph();
/**
* Convenience wrapper to find node given just pointer + property.
*
* \param ptr: pointer to the data that node will represent
- * \param prop: optional property affected - providing this effectively results in inner nodes being returned
+ * \param prop: optional property affected - providing this effectively
+ * results in inner nodes being returned
*
* \return A node matching the required characteristics if it exists
* or NULL if no such node exists in the graph
@@ -114,19 +133,22 @@ struct Depsgraph {
TimeSourceDepsNode *find_time_source() const;
IDDepsNode *find_id_node(const ID *id) const;
- IDDepsNode *add_id_node(ID *id, const char *name = "");
+ IDDepsNode *add_id_node(ID *id, ID *id_cow_hint = NULL);
void clear_id_nodes();
+ void clear_id_nodes_conditional(const std::function <bool (ID_Type id_type)>& filter);
/* Add new relationship between two nodes. */
DepsRelation *add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
const char *description,
- bool check_unique = false);
+ bool check_unique = false,
+ int flags = 0);
DepsRelation *add_new_relation(DepsNode *from,
DepsNode *to,
const char *description,
- bool check_unique = false);
+ bool check_unique = false,
+ int flags = 0);
/* Check whether two nodes are connected by relation with given
* description. Description might be NULL to check ANY relation between
@@ -142,6 +164,11 @@ struct Depsgraph {
/* Clear storage used by all nodes. */
void clear_all_nodes();
+ /* Copy-on-Write Functionality ........ */
+
+ /* For given original ID get ID which is created by CoW system. */
+ ID *get_cow_id(const ID *id_orig) const;
+
/* Core Graph Functionality ........... */
/* <ID : IDDepsNode> mapping from ID blocks to nodes representing these
@@ -161,6 +188,9 @@ struct Depsgraph {
/* Indicates whether relations needs to be updated. */
bool need_update;
+ /* Indicates which ID types were updated. */
+ char id_type_updated[MAX_LIBARRAY];
+
/* Quick-Access Temp Data ............. */
/* Nodes which have been tagged as "directly modified". */
@@ -177,12 +207,36 @@ struct Depsgraph {
*/
SpinLock lock;
- /* Layers Visibility .................. */
+ /* Scene, layer, mode this dependency graph is built for. */
+ Scene *scene;
+ ViewLayer *view_layer;
+ eEvaluationMode mode;
+
+ /* Time at which dependency graph is being or was last evaluated. */
+ float ctime;
+
+ /* Evaluated version of datablocks we access a lot.
+ * Stored here to save us form doing hash lookup.
+ */
+ Scene *scene_cow;
+
+ /* Active dependency graph is a dependency graph which is used by the
+ * currently active window. When dependency graph is active, it is allowed
+ * for evaluation functions to write animation f-curve result, drivers
+ * result and other selective things (object matrix?) to original object.
+ *
+ * This way we simplify operators, which don't need to worry about where
+ * to read stuff from.
+ */
+ bool is_active;
- /* Visible layers bitfield, used for skipping invisible objects updates. */
- unsigned int layers;
+ /* NITE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */
+ int debug_flags;
+ string debug_name;
- // XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
+ /* Cached list of colliders/effectors for collections and the scene
+ * created along with relations, for fast lookup during evaluation. */
+ GHash *physics_relations[DEG_PHYSICS_RELATIONS_NUM];
};
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index d3c34cc63a9..d56c47a0d2a 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -34,6 +34,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_listbase.h"
#include "PIL_time.h"
#include "PIL_time_utildefines.h"
@@ -42,12 +43,9 @@ extern "C" {
#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_object_force_types.h"
#include "BKE_main.h"
-#include "BKE_collision.h"
-#include "BKE_effect.h"
-#include "BKE_modifier.h"
+#include "BKE_scene.h"
} /* extern "C" */
#include "DEG_depsgraph.h"
@@ -95,58 +93,74 @@ static DEG::eDepsNode_Type deg_build_object_component_type(
case DEG_OB_COMP_GEOMETRY: return DEG::DEG_NODE_TYPE_GEOMETRY;
case DEG_OB_COMP_EVAL_POSE: return DEG::DEG_NODE_TYPE_EVAL_POSE;
case DEG_OB_COMP_BONE: return DEG::DEG_NODE_TYPE_BONE;
- case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEG_NODE_TYPE_EVAL_PARTICLES;
case DEG_OB_COMP_SHADING: return DEG::DEG_NODE_TYPE_SHADING;
case DEG_OB_COMP_CACHE: return DEG::DEG_NODE_TYPE_CACHE;
}
return DEG::DEG_NODE_TYPE_UNDEFINED;
}
-static DEG::DepsNodeHandle *get_handle(DepsNodeHandle *handle)
+static DEG::DepsNodeHandle *get_node_handle(DepsNodeHandle *node_handle)
{
- return reinterpret_cast<DEG::DepsNodeHandle *>(handle);
+ return reinterpret_cast<DEG::DepsNodeHandle *>(node_handle);
}
-void DEG_add_scene_relation(DepsNodeHandle *handle,
+void DEG_add_scene_relation(DepsNodeHandle *node_handle,
Scene *scene,
eDepsSceneComponentType component,
const char *description)
{
DEG::eDepsNode_Type type = deg_build_scene_component_type(component);
DEG::ComponentKey comp_key(&scene->id, type);
- DEG::DepsNodeHandle *deg_handle = get_handle(handle);
- deg_handle->builder->add_node_handle_relation(comp_key,
- deg_handle,
- description);
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ deg_node_handle->builder->add_node_handle_relation(comp_key,
+ deg_node_handle,
+ description);
}
-void DEG_add_object_relation(DepsNodeHandle *handle,
+void DEG_add_object_relation(DepsNodeHandle *node_handle,
Object *object,
eDepsObjectComponentType component,
const char *description)
{
DEG::eDepsNode_Type type = deg_build_object_component_type(component);
DEG::ComponentKey comp_key(&object->id, type);
- DEG::DepsNodeHandle *deg_handle = get_handle(handle);
- deg_handle->builder->add_node_handle_relation(comp_key,
- deg_handle,
- description);
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ deg_node_handle->builder->add_node_handle_relation(comp_key,
+ deg_node_handle,
+ description);
}
-void DEG_add_object_cache_relation(DepsNodeHandle *handle,
+void DEG_add_object_relation_with_customdata(DepsNodeHandle *node_handle,
+ Object *object,
+ eDepsObjectComponentType component,
+ uint64_t customdata_mask,
+ const char *description)
+{
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&object->id, type);
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ deg_node_handle->builder->add_node_handle_relation(comp_key,
+ deg_node_handle,
+ description);
+ if (object->type == OB_MESH) {
+ deg_node_handle->builder->add_customdata_mask(comp_key, customdata_mask);
+ }
+}
+
+void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
CacheFile *cache_file,
eDepsObjectComponentType component,
const char *description)
{
DEG::eDepsNode_Type type = deg_build_object_component_type(component);
DEG::ComponentKey comp_key(&cache_file->id, type);
- DEG::DepsNodeHandle *deg_handle = get_handle(handle);
- deg_handle->builder->add_node_handle_relation(comp_key,
- deg_handle,
- description);
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ deg_node_handle->builder->add_node_handle_relation(comp_key,
+ deg_node_handle,
+ description);
}
-void DEG_add_bone_relation(DepsNodeHandle *handle,
+void DEG_add_bone_relation(DepsNodeHandle *node_handle,
Object *object,
const char *bone_name,
eDepsObjectComponentType component,
@@ -154,89 +168,119 @@ void DEG_add_bone_relation(DepsNodeHandle *handle,
{
DEG::eDepsNode_Type type = deg_build_object_component_type(component);
DEG::ComponentKey comp_key(&object->id, type, bone_name);
- DEG::DepsNodeHandle *deg_handle = get_handle(handle);
- /* XXX: "Geometry Eval" might not always be true, but this only gets called
- * from modifier building now.
- */
- deg_handle->builder->add_node_handle_relation(comp_key,
- deg_handle,
- description);
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ deg_node_handle->builder->add_node_handle_relation(comp_key,
+ deg_node_handle,
+ description);
}
-struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *handle)
+void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle,
+ struct Object *object,
+ eDepsObjectComponentType component,
+ const char *description)
{
- DEG::DepsNodeHandle *deg_handle = get_handle(handle);
- DEG::DepsgraphRelationBuilder *relation_builder = deg_handle->builder;
- return reinterpret_cast<Depsgraph *>(relation_builder->getGraph());
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&object->id, type);
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder;
+ /* Add relation from source to the node handle. */
+ relation_builder->add_node_handle_relation(
+ comp_key, deg_node_handle, description);
+ /* Node deduct point cache component and connect source to it. */
+ ID *id = DEG_get_id_from_handle(node_handle);
+ DEG::ComponentKey point_cache_key(id, DEG::DEG_NODE_TYPE_POINT_CACHE);
+ DEG::DepsRelation *rel = relation_builder->add_relation(
+ comp_key, point_cache_key, "Point Cache");
+ if (rel != NULL) {
+ rel->flag |= DEG::DEPSREL_FLAG_FLUSH_USER_EDIT_ONLY;
+ }
+ else {
+ fprintf(stderr,
+ "Error in point cache relation from %s to ^%s.\n",
+ object->id.name,
+ id->name);
+ }
}
-void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
+void DEG_add_special_eval_flag(struct DepsNodeHandle *node_handle,
+ ID *id,
+ uint32_t flag)
{
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
- if (graph == NULL) {
- BLI_assert(!"Graph should always be valid");
- return;
- }
- DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
- if (id_node == NULL) {
- BLI_assert(!"ID should always be valid");
- return;
- }
- id_node->eval_flags |= flag;
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ deg_node_handle->builder->add_special_eval_flag(id, flag);
+}
+
+struct ID *DEG_get_id_from_handle(struct DepsNodeHandle *node_handle)
+{
+ DEG::DepsNodeHandle *deg_handle = get_node_handle(node_handle);
+ return deg_handle->node->owner->owner->id_orig;
+}
+
+struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *node_handle)
+{
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder;
+ return reinterpret_cast<Depsgraph *>(relation_builder->getGraph());
}
/* ******************** */
/* Graph Building API's */
-/* Build depsgraph for the given scene, and dump results in given
+/* Build depsgraph for the given scene layer, and dump results in given
* graph container.
*/
-/* XXX: assume that this is called from outside, given the current scene as
- * the "main" scene.
- */
-void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
+void DEG_graph_build_from_view_layer(Depsgraph *graph,
+ Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer)
{
- double start_time;
+ double start_time = 0.0;
if (G.debug & G_DEBUG_DEPSGRAPH_BUILD) {
start_time = PIL_check_seconds_timer();
}
-
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
-
- /* 1) Generate all the nodes in the graph first */
+ /* Perform sanity checks. */
+ BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1);
+ BLI_assert(deg_graph->scene == scene);
+ BLI_assert(deg_graph->view_layer == view_layer);
+ /* Generate all the nodes in the graph first */
DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph);
node_builder.begin_build();
- node_builder.build_scene(scene);
-
- /* 2) Hook up relationships between operations - to determine evaluation
- * order.
+ node_builder.build_view_layer(scene,
+ view_layer,
+ DEG::DEG_ID_LINKED_DIRECTLY);
+ node_builder.end_build();
+ /* Hook up relationships between operations - to determine evaluation
+ * order.
*/
DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph);
relation_builder.begin_build();
- relation_builder.build_scene(scene);
-
+ relation_builder.build_view_layer(scene, view_layer);
+ relation_builder.build_copy_on_write_relations();
/* Detect and solve cycles. */
DEG::deg_graph_detect_cycles(deg_graph);
-
- /* 3) Simplify the graph by removing redundant relations (to optimize
- * traversal later). */
+ /* Simplify the graph by removing redundant relations (to optimize
+ * traversal later). */
/* TODO: it would be useful to have an option to disable this in cases where
* it is causing trouble.
*/
if (G.debug_value == 799) {
DEG::deg_graph_transitive_reduction(deg_graph);
}
-
- /* 4) Flush visibility layer and re-schedule nodes for update. */
- DEG::deg_graph_build_finalize(deg_graph);
-
+ /* Store pointers to commonly used valuated datablocks. */
+ deg_graph->scene_cow = (Scene *)deg_graph->get_cow_id(&deg_graph->scene->id);
+ /* Flush visibility layer and re-schedule nodes for update. */
+ DEG::deg_graph_build_finalize(bmain, deg_graph);
+ DEG_graph_on_visible_update(bmain, graph);
#if 0
if (!DEG_debug_consistency_check(deg_graph)) {
printf("Consistency validation failed, ABORTING!\n");
abort();
}
#endif
-
+ /* Relations are up to date. */
+ deg_graph->need_update = false;
+ /* Finish statistics. */
if (G.debug & G_DEBUG_DEPSGRAPH_BUILD) {
printf("Depsgraph built in %f seconds.\n",
PIL_check_seconds_timer() - start_time);
@@ -246,141 +290,49 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
+ DEG_DEBUG_PRINTF(graph, TAG, "%s: Tagging relations for update.\n", __func__);
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
deg_graph->need_update = true;
-}
-
-/* Tag all relations for update. */
-void DEG_relations_tag_update(Main *bmain)
-{
- for (Scene *scene = (Scene *)bmain->scene.first;
- scene != NULL;
- scene = (Scene *)scene->id.next)
- {
- if (scene->depsgraph != NULL) {
- DEG_graph_tag_relations_update(scene->depsgraph);
- }
+ /* NOTE: When relations are updated, it's quite possible that
+ * we've got new bases in the scene. This means, we need to
+ * re-create flat array of bases in view layer.
+ *
+ * TODO(sergey): Try to make it so we don't flush updates
+ * to the whole depsgraph.
+ */
+ DEG::IDDepsNode *id_node = deg_graph->find_id_node(&deg_graph->scene->id);
+ if (id_node != NULL) {
+ id_node->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_RELATIONS);
}
}
-/* Create new graph if didn't exist yet,
- * or update relations if graph was tagged for update.
- */
-void DEG_scene_relations_update(Main *bmain, Scene *scene)
+/* Create or update relations in the specified graph. */
+void DEG_graph_relations_update(Depsgraph *graph,
+ Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer)
{
- if (scene->depsgraph == NULL) {
- /* Rebuild graph from scratch and exit. */
- scene->depsgraph = DEG_graph_new();
- DEG_graph_build_from_scene(scene->depsgraph, bmain, scene);
- return;
- }
-
- DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
- if (!graph->need_update) {
+ DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)graph;
+ if (!deg_graph->need_update) {
/* Graph is up to date, nothing to do. */
return;
}
-
- /* Clear all previous nodes and operations. */
- graph->clear_all_nodes();
- graph->operations.clear();
- BLI_gset_clear(graph->entry_tags, NULL);
-
- /* Build new nodes and relations. */
- DEG_graph_build_from_scene(reinterpret_cast< ::Depsgraph *>(graph),
- bmain,
- scene);
-
- graph->need_update = false;
-}
-
-/* Rebuild dependency graph only for a given scene. */
-void DEG_scene_relations_rebuild(Main *bmain, Scene *scene)
-{
- if (scene->depsgraph != NULL) {
- DEG_graph_tag_relations_update(scene->depsgraph);
- }
- DEG_scene_relations_update(bmain, scene);
-}
-
-void DEG_scene_graph_free(Scene *scene)
-{
- if (scene->depsgraph) {
- DEG_graph_free(scene->depsgraph);
- scene->depsgraph = NULL;
- }
+ DEG_graph_build_from_view_layer(graph, bmain, scene, view_layer);
}
-void DEG_add_collision_relations(DepsNodeHandle *handle,
- Scene *scene,
- Object *object,
- Group *group,
- int layer,
- unsigned int modifier_type,
- DEG_CollobjFilterFunction fn,
- bool dupli,
- const char *name)
-{
- unsigned int numcollobj;
- Object **collobjs = get_collisionobjects_ext(scene, object, group, layer, &numcollobj, modifier_type, dupli);
-
- for (unsigned int i = 0; i < numcollobj; i++) {
- Object *ob1 = collobjs[i];
-
- if (!fn || fn(ob1, modifiers_findByType(ob1, (ModifierType)modifier_type))) {
- DEG_add_object_relation(handle, ob1, DEG_OB_COMP_TRANSFORM, name);
- DEG_add_object_relation(handle, ob1, DEG_OB_COMP_GEOMETRY, name);
- }
- }
-
- if (collobjs)
- MEM_freeN(collobjs);
-}
-
-void DEG_add_forcefield_relations(DepsNodeHandle *handle,
- Scene *scene,
- Object *object,
- EffectorWeights *effector_weights,
- bool add_absorption,
- int skip_forcefield,
- const char *name)
+/* Tag all relations for update. */
+void DEG_relations_tag_update(Main *bmain)
{
- ListBase *effectors = pdInitEffectors(scene, object, NULL, effector_weights, false);
- if (effectors == NULL) {
- return;
- }
- for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
- if (eff->ob != object && eff->pd->forcefield != skip_forcefield) {
- DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_TRANSFORM, name);
- if (eff->psys) {
- DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_EVAL_PARTICLES, name);
- /* TODO: remove this when/if EVAL_PARTICLES is sufficient
- * for up to date particles.
- */
- DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_GEOMETRY, name);
- }
- if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- DEG_add_object_relation(handle,
- eff->pd->f_source,
- DEG_OB_COMP_TRANSFORM,
- "Smoke Force Domain");
- DEG_add_object_relation(handle,
- eff->pd->f_source,
- DEG_OB_COMP_GEOMETRY,
- "Smoke Force Domain");
- }
- if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
- DEG_add_collision_relations(handle,
- scene,
- object,
- NULL,
- eff->ob->lay,
- eModifierType_Collision,
- NULL,
- true,
- "Force Absorption");
+ DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__);
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ Depsgraph *depsgraph =
+ (Depsgraph *)BKE_scene_get_depsgraph(scene,
+ view_layer,
+ false);
+ if (depsgraph != NULL) {
+ DEG_graph_tag_relations_update(depsgraph);
}
}
}
- pdEndEffectors(&effectors);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index b7bf63e0cb0..91db054b006 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -37,16 +37,48 @@ extern "C" {
#include "DNA_scene_types.h"
} /* extern "C" */
+#include "DNA_object_types.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "intern/depsgraph_intern.h"
+#include "intern/depsgraph_types.h"
#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_time.h"
#include "util/deg_util_foreach.h"
+void DEG_debug_flags_set(Depsgraph *depsgraph, int flags)
+{
+ DEG::Depsgraph *deg_graph =
+ reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ deg_graph->debug_flags = flags;
+}
+
+int DEG_debug_flags_get(const Depsgraph *depsgraph)
+{
+ const DEG::Depsgraph *deg_graph =
+ reinterpret_cast<const DEG::Depsgraph *>(depsgraph);
+ return deg_graph->debug_flags;
+}
+
+void DEG_debug_name_set(struct Depsgraph *depsgraph, const char *name)
+{
+ DEG::Depsgraph *deg_graph =
+ reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ deg_graph->debug_name = name;
+}
+
+const char *DEG_debug_name_get(struct Depsgraph *depsgraph)
+{
+ const DEG::Depsgraph *deg_graph =
+ reinterpret_cast<const DEG::Depsgraph *>(depsgraph);
+ return deg_graph->debug_name.c_str();
+}
+
bool DEG_debug_compare(const struct Depsgraph *graph1,
const struct Depsgraph *graph2)
{
@@ -67,18 +99,20 @@ bool DEG_debug_compare(const struct Depsgraph *graph1,
return true;
}
-bool DEG_debug_scene_relations_validate(Main *bmain,
- Scene *scene)
+bool DEG_debug_graph_relations_validate(Depsgraph *graph,
+ Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer)
{
- Depsgraph *depsgraph = DEG_graph_new();
+ Depsgraph *temp_depsgraph = DEG_graph_new(scene, view_layer, DEG_get_mode(graph));
bool valid = true;
- DEG_graph_build_from_scene(depsgraph, bmain, scene);
- if (!DEG_debug_compare(depsgraph, scene->depsgraph)) {
+ DEG_graph_build_from_view_layer(temp_depsgraph, bmain, scene, view_layer);
+ if (!DEG_debug_compare(temp_depsgraph, graph)) {
fprintf(stderr, "ERROR! Depsgraph wasn't tagged for update when it should have!\n");
BLI_assert(!"This should not happen!");
valid = false;
}
- DEG_graph_free(depsgraph);
+ DEG_graph_free(temp_depsgraph);
return valid;
}
@@ -137,11 +171,11 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
/* Validate node valency calculated in both directions. */
foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
node->num_links_pending = 0;
- node->done = 0;
+ node->custom_flags = 0;
}
foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
- if (node->done) {
+ if (node->custom_flags) {
printf("Node %s is twice in the operations!\n",
node->identifier().c_str());
return false;
@@ -153,7 +187,7 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
++to->num_links_pending;
}
}
- node->done = 1;
+ node->custom_flags = 1;
}
foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index a6bdcdca19d..49eccd76f38 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -32,17 +32,19 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
extern "C" {
-#include "DNA_scene_types.h"
-
-#include "BKE_depsgraph.h"
#include "BKE_scene.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
} /* extern "C" */
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "intern/eval/deg_eval.h"
#include "intern/eval/deg_eval_flush.h"
@@ -53,103 +55,39 @@ extern "C" {
#include "intern/depsgraph.h"
-#ifdef WITH_LEGACY_DEPSGRAPH
-static bool use_legacy_depsgraph = true;
-#endif
-
-bool DEG_depsgraph_use_legacy(void)
-{
-#ifdef DISABLE_NEW_DEPSGRAPH
- return true;
-#elif defined(WITH_LEGACY_DEPSGRAPH)
- return use_legacy_depsgraph;
-#else
- BLI_assert(!"Should not be used with new depsgraph");
- return false;
-#endif
-}
-
-void DEG_depsgraph_switch_to_legacy(void)
-{
-#ifdef WITH_LEGACY_DEPSGRAPH
- use_legacy_depsgraph = true;
-#else
- BLI_assert(!"Should not be used with new depsgraph");
-#endif
-}
-
-void DEG_depsgraph_switch_to_new(void)
-{
-#ifdef WITH_LEGACY_DEPSGRAPH
- use_legacy_depsgraph = false;
-#else
- BLI_assert(!"Should not be used with new depsgraph");
-#endif
-}
-
-/* ****************** */
-/* Evaluation Context */
-
-/* Create new evaluation context. */
-EvaluationContext *DEG_evaluation_context_new(int mode)
-{
- EvaluationContext *eval_ctx =
- (EvaluationContext *)MEM_callocN(sizeof(EvaluationContext),
- "EvaluationContext");
- eval_ctx->mode = mode;
- return eval_ctx;
-}
-
-/**
- * Initialize evaluation context.
- * Used by the areas which currently overrides the context or doesn't have
- * access to a proper one.
- */
-void DEG_evaluation_context_init(EvaluationContext *eval_ctx, int mode)
-{
- eval_ctx->mode = mode;
-}
-
-/* Free evaluation context. */
-void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
-{
- MEM_freeN(eval_ctx);
-}
-
/* Evaluate all nodes tagged for updating. */
-void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
- Depsgraph *graph,
- Scene *scene)
+void DEG_evaluate_on_refresh(Depsgraph *graph)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ deg_graph->ctime = BKE_scene_frame_get(deg_graph->scene);
/* Update time on primary timesource. */
DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
- tsrc->cfra = BKE_scene_frame_get(scene);
- unsigned int layers = deg_graph->layers;
- /* XXX(sergey): This works around missing updates in temp scenes used
- * by various scripts, but is weak and needs closer investigation.
- */
- if (layers == 0) {
- layers = scene->lay;
+ tsrc->cfra = deg_graph->ctime;
+ /* Update time in scene. */
+ if (deg_graph->scene_cow) {
+ BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime);
}
- DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, layers);
+ DEG::deg_evaluate_on_refresh(deg_graph);
}
/* Frame-change happened for root scene that graph belongs to. */
-void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
- Main *bmain,
+void DEG_evaluate_on_framechange(Main *bmain,
Depsgraph *graph,
- float ctime,
- const unsigned int layers)
+ float ctime)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ deg_graph->ctime = ctime;
/* Update time on primary timesource. */
DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = ctime;
- tsrc->tag_update(deg_graph);
+ tsrc->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_TIME);
DEG::deg_graph_flush_updates(bmain, deg_graph);
+ /* Update time in scene. */
+ if (deg_graph->scene_cow) {
+ BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime);
+ }
/* Perform recalculation updates. */
- DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, layers);
+ DEG::deg_evaluate_on_refresh(deg_graph);
}
bool DEG_needs_eval(Depsgraph *graph)
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index 89432e17f87..069407e855e 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -46,8 +46,12 @@ extern "C" {
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+
+struct DEGEditorUpdateContext;
+struct Collection;
+struct ListBase;
struct Main;
-struct Group;
struct Scene;
namespace DEG {
@@ -105,19 +109,45 @@ DepsNodeFactory *deg_type_get_factory(const eDepsNode_Type type);
/* Editors Integration -------------------------------------------------- */
-void deg_editors_id_update(struct Main *bmain, struct ID *id);
+void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx,
+ struct ID *id);
+
+void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
+ bool updated);
-void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
+#define DEG_DEBUG_PRINTF(depsgraph, type, ...) \
+ do { \
+ if (DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_ ## type) { \
+ DEG_debug_print_begin(depsgraph); \
+ fprintf(stdout, __VA_ARGS__); \
+ } \
+ } while (0)
-#define DEG_DEBUG_PRINTF(type, ...) \
+#define DEG_GLOBAL_DEBUG_PRINTF(type, ...) \
do { \
if (G.debug & G_DEBUG_DEPSGRAPH_ ## type) { \
- fprintf(stderr, __VA_ARGS__); \
+ fprintf(stdout, __VA_ARGS__); \
} \
} while (0)
+#define DEG_ERROR_PRINTF(...) \
+ do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ } while (0)
+
bool deg_terminal_do_color(void);
string deg_color_for_pointer(const void *pointer);
string deg_color_end(void);
+/* Physics Utilities -------------------------------------------------- */
+
+struct ListBase *deg_build_effector_relations(Depsgraph *graph, struct Collection *collection);
+struct ListBase *deg_build_collision_relations(Depsgraph *graph, struct Collection *collection, unsigned int modifier_type);
+void deg_clear_physics_relations(Depsgraph *graph);
+
+/* Tagging Utilities -------------------------------------------------------- */
+
+eDepsNode_Type deg_geometry_tag_to_component(const ID *id);
+
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc
new file mode 100644
index 00000000000..88d4c25f726
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_physics.cc
@@ -0,0 +1,270 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_physics.cc
+ * \ingroup depsgraph
+ *
+ * Physics utilities for effectors and collision.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_compiler_compat.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+
+extern "C" {
+#include "BKE_collision.h"
+#include "BKE_effect.h"
+#include "BKE_modifier.h"
+} /* extern "C" */
+
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force_types.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
+
+#include "depsgraph.h"
+#include "depsgraph_intern.h"
+
+/*************************** Evaluation Query API *****************************/
+
+static ePhysicsRelationType modifier_to_relation_type(
+ unsigned int modifier_type)
+{
+ switch (modifier_type) {
+ case eModifierType_Collision:
+ return DEG_PHYSICS_COLLISION;
+ case eModifierType_Smoke:
+ return DEG_PHYSICS_SMOKE_COLLISION;
+ case eModifierType_DynamicPaint:
+ return DEG_PHYSICS_DYNAMIC_BRUSH;
+ }
+
+ BLI_assert(!"Unknown collision modifier type");
+ return DEG_PHYSICS_RELATIONS_NUM;
+}
+
+ListBase *DEG_get_effector_relations(const Depsgraph *graph,
+ Collection *collection)
+{
+ const DEG::Depsgraph *deg_graph =
+ reinterpret_cast<const DEG::Depsgraph *>(graph);
+ if (deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR] == NULL) {
+ return NULL;
+ }
+
+ ID *collection_orig = DEG_get_original_id(&collection->id);
+ return (ListBase *)BLI_ghash_lookup(
+ deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR],
+ collection_orig);
+}
+
+ListBase *DEG_get_collision_relations(const Depsgraph *graph,
+ Collection *collection,
+ unsigned int modifier_type)
+{
+ const DEG::Depsgraph *deg_graph =
+ reinterpret_cast<const DEG::Depsgraph *>(graph);
+ const ePhysicsRelationType type = modifier_to_relation_type(modifier_type);
+ if (deg_graph->physics_relations[type] == NULL) {
+ return NULL;
+ }
+ ID *collection_orig = DEG_get_original_id(&collection->id);
+ return (ListBase *)BLI_ghash_lookup(
+ deg_graph->physics_relations[type],
+ collection_orig);
+}
+
+/********************** Depsgraph Building API ************************/
+
+void DEG_add_collision_relations(DepsNodeHandle *handle,
+ Object *object,
+ Collection *collection,
+ unsigned int modifier_type,
+ DEG_CollobjFilterFunction filter_function,
+ const char *name)
+{
+ Depsgraph *depsgraph = DEG_get_graph_from_handle(handle);
+ DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph;
+ ListBase *relations = deg_build_collision_relations(
+ deg_graph, collection, modifier_type);
+ LISTBASE_FOREACH (CollisionRelation *, relation, relations) {
+ Object *ob1 = relation->ob;
+ if (ob1 == object) {
+ continue;
+ }
+ if (filter_function == NULL ||
+ filter_function(
+ ob1,
+ modifiers_findByType(ob1, (ModifierType)modifier_type)))
+ {
+ DEG_add_object_pointcache_relation(
+ handle, ob1, DEG_OB_COMP_TRANSFORM, name);
+ DEG_add_object_pointcache_relation(
+ handle, ob1, DEG_OB_COMP_GEOMETRY, name);
+ }
+ }
+}
+
+void DEG_add_forcefield_relations(DepsNodeHandle *handle,
+ Object *object,
+ EffectorWeights *effector_weights,
+ bool add_absorption,
+ int skip_forcefield,
+ const char *name)
+{
+ Depsgraph *depsgraph = DEG_get_graph_from_handle(handle);
+ DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph;
+ ListBase *relations =
+ deg_build_effector_relations(deg_graph, effector_weights->group);
+ LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
+ if (relation->ob == object) {
+ continue;
+ }
+ if (relation->pd->forcefield == skip_forcefield) {
+ continue;
+ }
+ DEG_add_object_pointcache_relation(
+ handle, relation->ob, DEG_OB_COMP_TRANSFORM, name);
+ if (relation->psys) {
+ /* TODO(sergey): Consider going more granular with more dedicated
+ * particle system operation. */
+ DEG_add_object_pointcache_relation(
+ handle, relation->ob, DEG_OB_COMP_GEOMETRY, name);
+ }
+ if (relation->pd->forcefield == PFIELD_SMOKEFLOW &&
+ relation->pd->f_source != NULL)
+ {
+ DEG_add_object_pointcache_relation(handle,
+ relation->pd->f_source,
+ DEG_OB_COMP_TRANSFORM,
+ "Smoke Force Domain");
+ DEG_add_object_pointcache_relation(handle,
+ relation->pd->f_source,
+ DEG_OB_COMP_GEOMETRY,
+ "Smoke Force Domain");
+ }
+ if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) {
+ DEG_add_collision_relations(handle,
+ object,
+ NULL,
+ eModifierType_Collision,
+ NULL,
+ "Force Absorption");
+ }
+ }
+}
+
+/******************************** Internal API ********************************/
+
+namespace DEG
+{
+
+ListBase *deg_build_effector_relations(Depsgraph *graph,
+ Collection *collection)
+{
+ GHash *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
+ if (hash == NULL) {
+ graph->physics_relations[DEG_PHYSICS_EFFECTOR] =
+ BLI_ghash_ptr_new("Depsgraph physics relations hash");
+ hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
+ }
+ ListBase *relations =
+ reinterpret_cast<ListBase*>(BLI_ghash_lookup(hash, collection));
+ if (relations == NULL) {
+ ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph*>(graph);
+ relations = BKE_effector_relations_create(
+ depsgraph, graph->view_layer, collection);
+ BLI_ghash_insert(hash, &collection->id, relations);
+ }
+ return relations;
+}
+
+ListBase *deg_build_collision_relations(Depsgraph *graph,
+ Collection *collection,
+ unsigned int modifier_type)
+{
+ const ePhysicsRelationType type = modifier_to_relation_type(modifier_type);
+ GHash *hash = graph->physics_relations[type];
+ if (hash == NULL) {
+ graph->physics_relations[type] =
+ BLI_ghash_ptr_new("Depsgraph physics relations hash");
+ hash = graph->physics_relations[type];
+ }
+ ListBase *relations =
+ reinterpret_cast<ListBase*>(BLI_ghash_lookup(hash, collection));
+ if (relations == NULL) {
+ ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph*>(graph);
+ relations = BKE_collision_relations_create(
+ depsgraph, collection, modifier_type);
+ BLI_ghash_insert(hash, &collection->id, relations);
+ }
+ return relations;
+}
+
+namespace {
+
+void free_effector_relations(void *value)
+{
+ BKE_effector_relations_free(reinterpret_cast<ListBase*>(value));
+}
+
+void free_collision_relations(void *value)
+{
+ BKE_collision_relations_free(reinterpret_cast<ListBase*>(value));
+}
+
+} // namespace
+
+void deg_clear_physics_relations(Depsgraph *graph)
+{
+ for (int i = 0; i < DEG_PHYSICS_RELATIONS_NUM; i++) {
+ if (graph->physics_relations[i]) {
+ ePhysicsRelationType type = (ePhysicsRelationType)i;
+
+ switch (type) {
+ case DEG_PHYSICS_EFFECTOR:
+ BLI_ghash_free(graph->physics_relations[i],
+ NULL,
+ free_effector_relations);
+ break;
+ case DEG_PHYSICS_COLLISION:
+ case DEG_PHYSICS_SMOKE_COLLISION:
+ case DEG_PHYSICS_DYNAMIC_BRUSH:
+ BLI_ghash_free(graph->physics_relations[i],
+ NULL,
+ free_collision_relations);
+ break;
+ case DEG_PHYSICS_RELATIONS_NUM:
+ break;
+ }
+ graph->physics_relations[i] = NULL;
+ }
+ }
+}
+
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 9b1961baa48..946917afb26 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -27,27 +27,80 @@
/** \file blender/depsgraph/intern/depsgraph_query.cc
* \ingroup depsgraph
*
- * Implementation of Querying and Filtering API's
+ * Implementation of Querying API
*/
#include "MEM_guardedalloc.h"
extern "C" {
+#include <string.h> // XXX: memcpy
+
+#include "BLI_utildefines.h"
#include "BKE_idcode.h"
#include "BKE_main.h"
+#include "BLI_listbase.h"
+
+#include "BKE_action.h" // XXX: BKE_pose_channel_from_name
} /* extern "C" */
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/depsgraph_intern.h"
#include "intern/nodes/deg_node_id.h"
-bool DEG_id_type_tagged(Main *bmain, short idtype)
+struct Scene *DEG_get_input_scene(const Depsgraph *graph)
{
- return bmain->id_tag_update[BKE_idcode_to_index(idtype)] != 0;
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ return deg_graph->scene;
}
-short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
+struct ViewLayer *DEG_get_input_view_layer(const Depsgraph *graph)
+{
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ return deg_graph->view_layer;
+}
+
+eEvaluationMode DEG_get_mode(const Depsgraph *graph)
+{
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ return deg_graph->mode;
+}
+
+float DEG_get_ctime(const Depsgraph *graph)
+{
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ return deg_graph->ctime;
+}
+
+
+bool DEG_id_type_updated(const Depsgraph *graph, short id_type)
+{
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ return deg_graph->id_type_updated[BKE_idcode_to_index(id_type)] != 0;
+}
+
+bool DEG_id_type_any_updated(const Depsgraph *graph)
+{
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+
+ /* Loop over all ID types. */
+ for (int id_type_index = 0; id_type_index < MAX_LIBARRAY; id_type_index++) {
+ if (deg_graph->id_type_updated[id_type_index]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id)
{
if (graph == NULL) {
/* Happens when converting objects to mesh from a python script
@@ -59,9 +112,8 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
return 0;
}
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
-
- DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ const DEG::IDDepsNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id));
if (id_node == NULL) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
@@ -69,3 +121,128 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
return id_node->eval_flags;
}
+
+Scene *DEG_get_evaluated_scene(const Depsgraph *graph)
+{
+ const DEG::Depsgraph *deg_graph =
+ reinterpret_cast<const DEG::Depsgraph *>(graph);
+ Scene *scene_cow = deg_graph->scene_cow;
+ /* TODO(sergey): Shall we expand datablock here? Or is it OK to assume
+ * that calleer is OK with just a pointer in case scene is not updated
+ * yet?
+ */
+ BLI_assert(scene_cow != NULL && DEG::deg_copy_on_write_is_expanded(&scene_cow->id));
+ return scene_cow;
+}
+
+ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph)
+{
+ const DEG::Depsgraph *deg_graph =
+ reinterpret_cast<const DEG::Depsgraph *>(graph);
+ Scene *scene_cow = DEG_get_evaluated_scene(graph);
+ if (scene_cow == NULL) {
+ return NULL; /* Happens with new, not-yet-built/evaluated graphes. */
+ }
+ /* Do name-based lookup. */
+ /* TODO(sergey): Can this be optimized? */
+ ViewLayer *view_layer_orig = deg_graph->view_layer;
+ ViewLayer *view_layer_cow =
+ (ViewLayer *)BLI_findstring(&scene_cow->view_layers,
+ view_layer_orig->name,
+ offsetof(ViewLayer, name));
+ BLI_assert(view_layer_cow != NULL);
+ return view_layer_cow;
+}
+
+Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
+{
+ return (Object *)DEG_get_evaluated_id(depsgraph, &object->id);
+}
+
+ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
+{
+ if (id == NULL) {
+ return NULL;
+ }
+ /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(),
+ * but here we never do assert, since we don't know nature of the
+ * incoming ID datablock.
+ */
+ const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph;
+ const DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
+ if (id_node == NULL) {
+ return id;
+ }
+ return id_node->id_cow;
+}
+
+/* Get evaluated version of data pointed to by RNA pointer */
+void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph, PointerRNA *ptr, PointerRNA *r_ptr_eval)
+{
+ if ((ptr == NULL) || (r_ptr_eval == NULL)) {
+ return;
+ }
+ ID *orig_id = (ID *)ptr->id.data;
+ ID *cow_id = DEG_get_evaluated_id(depsgraph, orig_id);
+ if (ptr->id.data == ptr->data) {
+ /* For ID pointers, it's easy... */
+ r_ptr_eval->id.data = (void *)cow_id;
+ r_ptr_eval->data = (void *)cow_id;
+ r_ptr_eval->type = ptr->type;
+ }
+ else if (ptr->type == &RNA_PoseBone) {
+ /* HACK: Since bone keyframing is quite commonly used,
+ * speed things up for this case by doing a special lookup
+ * for bones
+ */
+ const Object *ob_eval = (Object *)cow_id;
+ bPoseChannel *pchan = (bPoseChannel *)ptr->data;
+ const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ r_ptr_eval->id.data = (void *)cow_id;
+ r_ptr_eval->data = (void *)pchan_eval;
+ r_ptr_eval->type = ptr->type;
+ }
+ else {
+ /* For everything else, try to get RNA Path of the BMain-pointer,
+ * then use that to look up what the COW-domain one should be
+ * given the COW ID pointer as the new lookup point
+ */
+ /* TODO: Find a faster alternative, or implement support for other
+ * common types too above (e.g. modifiers)
+ */
+ char *path = RNA_path_from_ID_to_struct(ptr);
+ if (path) {
+ PointerRNA cow_id_ptr;
+ RNA_id_pointer_create(cow_id, &cow_id_ptr);
+ if (!RNA_path_resolve(&cow_id_ptr, path, r_ptr_eval, NULL)) {
+ /* Couldn't find COW copy of data */
+ fprintf(stderr,
+ "%s: Couldn't resolve RNA path ('%s') relative to COW ID (%p) for '%s'\n",
+ __func__, path, (void *)cow_id, orig_id->name);
+ }
+ }
+ else {
+ /* Path resolution failed - XXX: Hide this behind a debug flag */
+ fprintf(stderr,
+ "%s: Couldn't get RNA path for %s relative to %s\n",
+ __func__, RNA_struct_identifier(ptr->type), orig_id->name);
+ }
+ }
+}
+
+Object *DEG_get_original_object(Object *object)
+{
+ return (Object *)DEG_get_original_id(&object->id);
+}
+
+ID *DEG_get_original_id(ID *id)
+{
+ if (id == NULL) {
+ return NULL;
+ }
+ if (id->orig_id == NULL) {
+ return id;
+ }
+ BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ return (ID *)id->orig_id;
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_filter.cc b/source/blender/depsgraph/intern/depsgraph_query_filter.cc
new file mode 100644
index 00000000000..1b44d4229e6
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_query_filter.cc
@@ -0,0 +1,257 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_query_filter.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of Graph Filtering API
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include <string.h> // XXX: memcpy
+
+#include "BLI_utildefines.h"
+#include "BKE_idcode.h"
+#include "BKE_main.h"
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+
+#include "BKE_action.h" // XXX: BKE_pose_channel_from_name
+} /* extern "C" */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#include "DEG_depsgraph_debug.h"
+
+#include "util/deg_util_foreach.h"
+
+#include "intern/eval/deg_eval_copy_on_write.h"
+
+#include "intern/depsgraph.h"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_id.h"
+#include "intern/nodes/deg_node_operation.h"
+
+
+/* *************************************************** */
+/* Graph Filtering Internals */
+
+namespace DEG {
+
+/* UserData for deg_add_retained_id_cb */
+struct RetainedIdUserData {
+ DEG_FilterQuery *query;
+ GSet *set;
+};
+
+/* Helper for DEG_foreach_ancestor_id()
+ * Keep track of all ID's encountered in a set
+ */
+static void deg_add_retained_id_cb(ID *id, void *user_data)
+{
+ RetainedIdUserData *data = (RetainedIdUserData *)user_data;
+ BLI_gset_add(data->set, (void *)id);
+}
+
+/* ------------------------------------------- */
+
+/* Remove relations pointing to the given OperationDepsNode */
+/* TODO: Make this part of OperationDepsNode? */
+static void deg_unlink_opnode(Depsgraph *graph, OperationDepsNode *op_node)
+{
+ std::vector<DepsRelation *> all_links;
+
+ /* Collect all inlinks to this operation */
+ foreach (DepsRelation *rel, op_node->inlinks) {
+ all_links.push_back(rel);
+ }
+ /* Collect all outlinks from this operation */
+ foreach (DepsRelation *rel, op_node->outlinks) {
+ all_links.push_back(rel);
+ }
+
+ /* Delete all collected relations */
+ foreach (DepsRelation *rel, all_links) {
+ rel->unlink();
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+
+ /* Remove from entry tags */
+ if (BLI_gset_haskey(graph->entry_tags, op_node)) {
+ BLI_gset_remove(graph->entry_tags, op_node, NULL);
+ }
+}
+
+/* Remove every ID Node (and its associated subnodes, COW data) */
+static void deg_filter_remove_unwanted_ids(Depsgraph *graph, GSet *retained_ids)
+{
+ /* 1) First pass over ID nodes + their operations
+ * - Identify and tag ID's (via "custom_flags = 1") to be removed
+ * - Remove all links to/from operations that will be removed
+ */
+ foreach (IDDepsNode *id_node, graph->id_nodes) {
+ id_node->custom_flags = !BLI_gset_haskey(retained_ids, (void *)id_node->id_orig);
+ if (id_node->custom_flags) {
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ foreach (OperationDepsNode *op_node, comp_node->operations) {
+ deg_unlink_opnode(graph, op_node);
+ }
+ }
+ GHASH_FOREACH_END();
+ }
+ }
+
+ /* 2) Remove unwanted operations from graph->operations */
+ for (Depsgraph::OperationNodes::iterator it_opnode = graph->operations.begin();
+ it_opnode != graph->operations.end();
+ )
+ {
+ OperationDepsNode *op_node = *it_opnode;
+ IDDepsNode *id_node = op_node->owner->owner;
+ if (id_node->custom_flags) {
+ it_opnode = graph->operations.erase(it_opnode);
+ }
+ else {
+ ++it_opnode;
+ }
+ }
+
+ /* Free ID nodes that are no longer wanted
+ *
+ * This is loosely based on Depsgraph::clear_id_nodes().
+ * However, we don't worry about the conditional freeing for physics
+ * stuff, since it's rarely needed currently.
+ */
+ for (Depsgraph::IDDepsNodes::iterator it_id = graph->id_nodes.begin();
+ it_id != graph->id_nodes.end();
+ )
+ {
+ IDDepsNode *id_node = *it_id;
+ ID *id = id_node->id_orig;
+
+ if (id_node->custom_flags) {
+ /* Destroy node data, then remove from collections, and free */
+ id_node->destroy();
+
+ BLI_ghash_remove(graph->id_hash, id, NULL, NULL);
+ it_id = graph->id_nodes.erase(it_id);
+
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+ }
+ else {
+ /* This node has not been marked for deletion. Increment iterator */
+ ++it_id;
+ }
+ }
+}
+
+} //namespace DEG
+
+/* *************************************************** */
+/* Graph Filtering API */
+
+/* Obtain a new graph instance that only contains the subset of desired nodes
+ * WARNING: Do NOT pass an already filtered depsgraph through this function again,
+ * as we are currently unable to accurately recreate it.
+ */
+Depsgraph *DEG_graph_filter(const Depsgraph *graph_src, Main *bmain, DEG_FilterQuery *query)
+{
+ const DEG::Depsgraph *deg_graph_src = reinterpret_cast<const DEG::Depsgraph *>(graph_src);
+ if (deg_graph_src == NULL) {
+ return NULL;
+ }
+
+ /* Construct a full new depsgraph based on the one we got */
+ /* TODO: Improve the builders to not add any ID nodes we don't need later (e.g. ProxyBuilder?) */
+ Depsgraph *graph_new = DEG_graph_new(deg_graph_src->scene,
+ deg_graph_src->view_layer,
+ deg_graph_src->mode);
+ DEG_graph_build_from_view_layer(graph_new,
+ bmain,
+ deg_graph_src->scene,
+ deg_graph_src->view_layer);
+
+ /* Build a set of all the id's we want to keep */
+ GSet *retained_ids = BLI_gset_ptr_new(__func__);
+ DEG::RetainedIdUserData retained_id_data = {query, retained_ids};
+
+ LISTBASE_FOREACH(DEG_FilterTarget *, target, &query->targets) {
+ /* Target Itself */
+ BLI_gset_add(retained_ids, (void *)target->id);
+
+ /* Target's Ancestors (i.e. things it depends on) */
+ DEG_foreach_ancestor_ID(graph_new,
+ target->id,
+ DEG::deg_add_retained_id_cb,
+ &retained_id_data);
+ }
+
+ /* Remove everything we don't want to keep around anymore */
+ DEG::Depsgraph *deg_graph_new = reinterpret_cast<DEG::Depsgraph *>(graph_new);
+ if (BLI_gset_len(retained_ids) > 0) {
+ DEG::deg_filter_remove_unwanted_ids(deg_graph_new, retained_ids);
+ }
+ // TODO: query->LOD filters
+
+ /* Free temp data */
+ BLI_gset_free(retained_ids, NULL);
+ retained_ids = NULL;
+
+ /* Print Stats */
+ // XXX: Hide behind debug flags
+ size_t s_outer, s_operations, s_relations;
+ size_t s_ids = deg_graph_src->id_nodes.size();
+ unsigned int s_idh = BLI_ghash_len(deg_graph_src->id_hash);
+
+ size_t n_outer, n_operations, n_relations;
+ size_t n_ids = deg_graph_new->id_nodes.size();
+ unsigned int n_idh = BLI_ghash_len(deg_graph_new->id_hash);
+
+ DEG_stats_simple(graph_src, &s_outer, &s_operations, &s_relations);
+ DEG_stats_simple(graph_new, &n_outer, &n_operations, &n_relations);
+
+ printf("%s: src = (ID's: %zu (%u), Out: %zu, Op: %zu, Rel: %zu)\n",
+ __func__, s_ids, s_idh, s_outer, s_operations, s_relations);
+ printf("%s: new = (ID's: %zu (%u), Out: %zu, Op: %zu, Rel: %zu)\n",
+ __func__, n_ids, n_idh, n_outer, n_operations, n_relations);
+
+ /* Return this new graph instance */
+ return graph_new;
+}
+
+/* *************************************************** */
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index 65d8f58b851..b6138e4e81c 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -60,6 +60,9 @@ extern "C" {
namespace DEG {
typedef std::deque<OperationDepsNode *> TraversalQueue;
+enum {
+ DEG_NODE_VISITED = (1 << 0),
+};
static void deg_foreach_clear_flags(const Depsgraph *graph)
{
@@ -67,7 +70,7 @@ static void deg_foreach_clear_flags(const Depsgraph *graph)
op_node->scheduled = false;
}
foreach (IDDepsNode *id_node, graph->id_nodes) {
- id_node->done = false;
+ id_node->custom_flags = 0;
}
}
@@ -77,8 +80,8 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph,
void *user_data)
{
/* Start with getting ID node from the graph. */
- IDDepsNode *id_node = graph->find_id_node(id);
- if (id_node == NULL) {
+ IDDepsNode *target_id_node = graph->find_id_node(id);
+ if (target_id_node == NULL) {
/* TODO(sergey): Shall we inform or assert here about attempt to start
* iterating over non-existing ID?
*/
@@ -88,7 +91,7 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph,
deg_foreach_clear_flags(graph);
/* Start with scheduling all operations from ID node. */
TraversalQueue queue;
- GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, target_id_node->components)
{
foreach (OperationDepsNode *op_node, comp_node->operations) {
queue.push_back(op_node);
@@ -96,7 +99,7 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph,
}
}
GHASH_FOREACH_END();
- id_node->done = true;
+ target_id_node->custom_flags |= DEG_NODE_VISITED;
/* Process the queue. */
while (!queue.empty()) {
/* get next operation node to process. */
@@ -106,10 +109,10 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph,
/* Check whether we need to inform callee about corresponding ID node. */
ComponentDepsNode *comp_node = op_node->owner;
IDDepsNode *id_node = comp_node->owner;
- if (!id_node->done) {
+ if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) {
/* TODO(sergey): Is it orig or CoW? */
- callback(id_node->id, user_data);
- id_node->done = true;
+ callback(id_node->id_orig, user_data);
+ id_node->custom_flags |= DEG_NODE_VISITED;
}
/* Schedule outgoing operation nodes. */
if (op_node->outlinks.size() == 1) {
@@ -136,6 +139,85 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph,
}
}
+static void deg_foreach_ancestor_ID(const Depsgraph *graph,
+ const ID *id,
+ DEGForeachIDCallback callback,
+ void *user_data)
+{
+ /* Start with getting ID node from the graph. */
+ IDDepsNode *target_id_node = graph->find_id_node(id);
+ if (target_id_node == NULL) {
+ /* TODO(sergey): Shall we inform or assert here about attempt to start
+ * iterating over non-existing ID?
+ */
+ return;
+ }
+ /* Make sure all runtime flags are ready and clear. */
+ deg_foreach_clear_flags(graph);
+ /* Start with scheduling all operations from ID node. */
+ TraversalQueue queue;
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, target_id_node->components)
+ {
+ foreach (OperationDepsNode *op_node, comp_node->operations) {
+ queue.push_back(op_node);
+ op_node->scheduled = true;
+ }
+ }
+ GHASH_FOREACH_END();
+ target_id_node->custom_flags |= DEG_NODE_VISITED;
+ /* Process the queue. */
+ while (!queue.empty()) {
+ /* get next operation node to process. */
+ OperationDepsNode *op_node = queue.front();
+ queue.pop_front();
+ for (;;) {
+ /* Check whether we need to inform callee about corresponding ID node. */
+ ComponentDepsNode *comp_node = op_node->owner;
+ IDDepsNode *id_node = comp_node->owner;
+ if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) {
+ /* TODO(sergey): Is it orig or CoW? */
+ callback(id_node->id_orig, user_data);
+ id_node->custom_flags |= DEG_NODE_VISITED;
+ }
+ /* Schedule incoming operation nodes. */
+ if (op_node->inlinks.size() == 1) {
+ DepsNode *from = op_node->inlinks[0]->from;
+ if (from->get_class() == DEG_NODE_CLASS_OPERATION) {
+ OperationDepsNode *from_node = (OperationDepsNode *)from;
+ if (from_node->scheduled == false) {
+ from_node->scheduled = true;
+ op_node = from_node;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ else {
+ foreach (DepsRelation *rel, op_node->inlinks) {
+ DepsNode *from = rel->from;
+ if (from->get_class() == DEG_NODE_CLASS_OPERATION) {
+ OperationDepsNode *from_node = (OperationDepsNode *)from;
+ if (from_node->scheduled == false) {
+ queue.push_front(from_node);
+ from_node->scheduled = true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void deg_foreach_id(const Depsgraph *depsgraph,
+ DEGForeachIDCallback callback, void *user_data)
+{
+ foreach (const IDDepsNode *id_node, depsgraph->id_nodes) {
+ callback(id_node->id_orig, user_data);
+ }
+}
+
} // namespace DEG
void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
@@ -146,3 +228,18 @@ void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
id,
callback, user_data);
}
+
+void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
+ const ID *id,
+ DEGForeachIDCallback callback, void *user_data)
+{
+ DEG::deg_foreach_ancestor_ID((const DEG::Depsgraph *)depsgraph,
+ id,
+ callback, user_data);
+}
+
+void DEG_foreach_ID(const Depsgraph *depsgraph,
+ DEGForeachIDCallback callback, void *user_data)
+{
+ DEG::deg_foreach_id((const DEG::Depsgraph *)depsgraph, callback, user_data);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
new file mode 100644
index 00000000000..52c4ab33dc6
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -0,0 +1,372 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Dalai Felinto
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_query_iter.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of Querying and Filtering API's
+ */
+
+/* Silence warnings from copying deprecated fields. */
+#define DNA_DEPRECATED_ALLOW
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BKE_anim.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+} /* extern "C" */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+#include "intern/nodes/deg_node_id.h"
+
+#ifndef NDEBUG
+# include "intern/eval/deg_eval_copy_on_write.h"
+#endif
+
+// If defined, all working data will be set to an invalid state, helping
+// to catch issues when areas accessing data which is considered to be no
+// longer available.
+#undef INVALIDATE_WORK_DATA
+
+#ifndef NDEBUG
+# define INVALIDATE_WORK_DATA
+#endif
+
+/* ************************ DEG ITERATORS ********************* */
+
+namespace {
+
+void deg_invalidate_iterator_work_data(DEGObjectIterData *data)
+{
+#ifdef INVALIDATE_WORK_DATA
+ BLI_assert(data != NULL);
+ memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
+#else
+ (void) data;
+#endif
+}
+
+void verify_id_properties_freed(DEGObjectIterData *data)
+{
+ if (data->dupli_object_current == NULL) {
+ // We didn't enter duplication yet, so we can't have any dangling
+ // pointers.
+ return;
+ }
+ const Object *dupli_object = data->dupli_object_current->ob;
+ Object *temp_dupli_object = &data->temp_dupli_object;
+ if (temp_dupli_object->id.properties == NULL) {
+ // No ID properties in temp datablock -- no leak is possible.
+ return;
+ }
+ if (temp_dupli_object->id.properties == dupli_object->id.properties) {
+ // Temp copy of object did not modify ID properties.
+ return;
+ }
+ // Free memory which is owned by temporary storage which is about to
+ // get overwritten.
+ IDP_FreeProperty(temp_dupli_object->id.properties);
+ MEM_freeN(temp_dupli_object->id.properties);
+ temp_dupli_object->id.properties = NULL;
+}
+
+bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
+{
+ DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
+ while (data->dupli_object_next != NULL) {
+ DupliObject *dob = data->dupli_object_next;
+ Object *obd = dob->ob;
+
+ data->dupli_object_next = data->dupli_object_next->next;
+
+ /* Group duplis need to set ob matrices correct, for deform. so no_draw
+ * is part handled.
+ */
+ if ((obd->transflag & OB_RENDER_DUPLI) == 0 && dob->no_draw) {
+ continue;
+ }
+
+ if (obd->type == OB_MBALL) {
+ continue;
+ }
+
+ verify_id_properties_freed(data);
+
+ data->dupli_object_current = dob;
+
+ /* Temporary object to evaluate. */
+ Object *dupli_parent = data->dupli_parent;
+ Object *temp_dupli_object = &data->temp_dupli_object;
+ *temp_dupli_object = *dob->ob;
+ temp_dupli_object->select_color = dupli_parent->select_color;
+ temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI;
+ temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits;
+
+ /* Duplicated elements shouldn't care whether their original collection is visible or not. */
+ temp_dupli_object->base_flag |= BASE_VISIBLE;
+
+ if (BKE_object_is_visible(temp_dupli_object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) {
+ continue;
+ }
+
+ temp_dupli_object->transflag &= ~OB_DUPLI;
+
+ copy_m4_m4(data->temp_dupli_object.obmat, dob->mat);
+ iter->current = &data->temp_dupli_object;
+ BLI_assert(
+ DEG::deg_validate_copy_on_write_datablock(
+ &data->temp_dupli_object.id));
+ return true;
+ }
+
+ return false;
+}
+
+void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node)
+{
+ /* Set it early in case we need to exit and we are running from within a loop. */
+ iter->skip = true;
+
+ if (!id_node->is_directly_visible) {
+ return;
+ }
+
+ DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
+ const ID_Type id_type = GS(id_node->id_orig->name);
+
+ if (id_type != ID_OB) {
+ return;
+ }
+
+ switch (id_node->linked_state) {
+ case DEG::DEG_ID_LINKED_DIRECTLY:
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) {
+ return;
+ }
+ break;
+ case DEG::DEG_ID_LINKED_VIA_SET:
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) {
+ return;
+ }
+ break;
+ case DEG::DEG_ID_LINKED_INDIRECTLY:
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) {
+ return;
+ }
+ break;
+ }
+
+ Object *object = (Object *)id_node->id_cow;
+ BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id));
+
+ if ((BKE_object_is_visible(object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) &&
+ ((data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) != 0))
+ {
+ return;
+ }
+
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) &&
+ (object->transflag & OB_DUPLI))
+ {
+ data->dupli_parent = object;
+ data->dupli_list = object_duplilist(data->graph, data->scene, object);
+ data->dupli_object_next = (DupliObject *)data->dupli_list->first;
+ if (BKE_object_is_visible(object, (eObjectVisibilityCheck)data->visibility_check) == false) {
+ return;
+ }
+ }
+
+ iter->current = object;
+ iter->skip = false;
+}
+
+} // namespace
+
+void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
+{
+ Depsgraph *depsgraph = data->graph;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ const size_t num_id_nodes = deg_graph->id_nodes.size();
+
+ iter->data = data;
+
+ if (num_id_nodes == 0) {
+ iter->valid = false;
+ return;
+ }
+
+ data->dupli_parent = NULL;
+ data->dupli_list = NULL;
+ data->dupli_object_next = NULL;
+ data->dupli_object_current = NULL;
+ data->scene = DEG_get_evaluated_scene(depsgraph);
+ data->id_node_index = 0;
+ data->num_id_nodes = num_id_nodes;
+ eEvaluationMode eval_mode = DEG_get_mode(depsgraph);
+ data->visibility_check = (eval_mode == DAG_EVAL_RENDER)
+ ? OB_VISIBILITY_CHECK_FOR_RENDER
+ : OB_VISIBILITY_CHECK_FOR_VIEWPORT;
+ deg_invalidate_iterator_work_data(data);
+
+ DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
+ deg_iterator_objects_step(iter, id_node);
+
+ if (iter->skip) {
+ DEG_iterator_objects_next(iter);
+ }
+}
+
+void DEG_iterator_objects_next(BLI_Iterator *iter)
+{
+ DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
+ Depsgraph *depsgraph = data->graph;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ do {
+ iter->skip = false;
+ if (data->dupli_list) {
+ if (deg_objects_dupli_iterator_next(iter)) {
+ return;
+ }
+ else {
+ verify_id_properties_freed(data);
+ free_object_duplilist(data->dupli_list);
+ data->dupli_parent = NULL;
+ data->dupli_list = NULL;
+ data->dupli_object_next = NULL;
+ data->dupli_object_current = NULL;
+ deg_invalidate_iterator_work_data(data);
+ }
+ }
+
+ ++data->id_node_index;
+ if (data->id_node_index == data->num_id_nodes) {
+ iter->valid = false;
+ return;
+ }
+
+ DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
+ deg_iterator_objects_step(iter, id_node);
+ } while (iter->skip);
+}
+
+void DEG_iterator_objects_end(BLI_Iterator *iter)
+{
+ DEGObjectIterData *data = (DEGObjectIterData *)iter->data;
+ if (data != NULL) {
+ /* Force crash in case the iterator data is referenced and accessed down
+ * the line. (T51718)
+ */
+ deg_invalidate_iterator_work_data(data);
+ }
+}
+
+/* ************************ DEG ID ITERATOR ********************* */
+
+static void DEG_iterator_ids_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node, bool only_updated)
+{
+ ID *id_cow = id_node->id_cow;
+
+ if (!id_node->is_directly_visible) {
+ iter->skip = true;
+ return;
+ }
+ else if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) {
+ bNodeTree *ntree = ntreeFromID(id_cow);
+
+ /* Nodetree is considered part of the datablock. */
+ if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) {
+ iter->skip = true;
+ return;
+ }
+ }
+
+ iter->current = id_cow;
+ iter->skip = false;
+}
+
+void DEG_iterator_ids_begin(BLI_Iterator *iter, DEGIDIterData *data)
+{
+ Depsgraph *depsgraph = data->graph;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ const size_t num_id_nodes = deg_graph->id_nodes.size();
+
+ iter->data = data;
+
+ if ((num_id_nodes == 0) ||
+ (data->only_updated && !DEG_id_type_any_updated(depsgraph)))
+ {
+ iter->valid = false;
+ return;
+ }
+
+ data->id_node_index = 0;
+ data->num_id_nodes = num_id_nodes;
+
+ DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
+ DEG_iterator_ids_step(iter, id_node, data->only_updated);
+
+ if (iter->skip) {
+ DEG_iterator_ids_next(iter);
+ }
+}
+
+void DEG_iterator_ids_next(BLI_Iterator *iter)
+{
+ DEGIDIterData *data = (DEGIDIterData *)iter->data;
+ Depsgraph *depsgraph = data->graph;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+
+ do {
+ iter->skip = false;
+
+ ++data->id_node_index;
+ if (data->id_node_index == data->num_id_nodes) {
+ iter->valid = false;
+ return;
+ }
+
+ DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
+ DEG_iterator_ids_step(iter, id_node, data->only_updated);
+ } while (iter->skip);
+}
+
+void DEG_iterator_ids_end(BLI_Iterator *UNUSED(iter))
+{
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 948e4fc1f1b..6374354a154 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -35,20 +35,26 @@
#include <queue>
#include "BLI_utildefines.h"
-#include "BLI_task.h"
#include "BLI_listbase.h"
+#include "BLI_math_bits.h"
+#include "BLI_task.h"
extern "C" {
+#include "DNA_anim_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
-
+#include "BKE_animsys.h"
#include "BKE_idcode.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
#define new new_
#include "BKE_screen.h"
@@ -56,8 +62,10 @@ extern "C" {
} /* extern "C" */
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "intern/builder/deg_builder.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/eval/deg_eval_flush.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
@@ -70,298 +78,616 @@ extern "C" {
/* *********************** */
/* Update Tagging/Flushing */
-/* Legacy depsgraph did some special trickery for things like particle systems
- * when tagging ID for an update. Ideally that tagging needs to become obsolete
- * in favor of havng dedicated node for that which gets tagged, but for until
- * design of those areas is more clear we'll do the same legacy code here.
- * - sergey -
- */
-#define DEPSGRAPH_USE_LEGACY_TAGGING
+namespace DEG {
namespace {
-/* Data-Based Tagging ------------------------------- */
+void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag);
-void lib_id_recalc_tag(Main *bmain, ID *id)
+void depsgraph_geometry_tag_to_component(const ID *id,
+ eDepsNode_Type *component_type)
{
- id->recalc |= ID_RECALC;
- DEG_id_type_tag(bmain, GS(id->name));
-}
-
-void lib_id_recalc_data_tag(Main *bmain, ID *id)
-{
- id->recalc |= ID_RECALC_DATA;
- DEG_id_type_tag(bmain, GS(id->name));
+ const eDepsNode_Type result = deg_geometry_tag_to_component(id);
+ if (result != DEG_NODE_TYPE_UNDEFINED) {
+ *component_type = result;
+ }
}
-void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
+void depsgraph_select_tag_to_component_opcode(
+ const ID *id,
+ eDepsNode_Type *component_type,
+ eDepsOperation_Code *operation_code)
{
- if (flag) {
- /* This bit of code ensures legacy object->recalc flags
- * are still filled in the same way as it was expected
- * with the old dependency graph.
+ const ID_Type id_type = GS(id->name);
+ if (id_type == ID_SCE) {
+ /* We need to flush base flags to all objects in a scene since we
+ * don't know which ones changed. However, we don't want to update
+ * the whole scene, so pick up some operation which will do as less
+ * as possible.
*
- * This is because some areas like motion paths and likely
- * some other physics baking process are doing manual scene
- * update on all the frames, trying to minimize number of
- * updates.
- *
- * But this flag will also let us to re-construct entry
- * nodes for update after relations update and after layer
- * visibility changes.
+ * TODO(sergey): We can introduce explicit exit operation which
+ * does nothing and which is only used to cascade flush down the
+ * road.
*/
- ID_Type idtype = GS(id->name);
- if (idtype == ID_OB) {
- Object *object = (Object *)id;
- object->recalc |= (flag & OB_RECALC_ALL);
- }
-
- if (flag & OB_RECALC_OB)
- lib_id_recalc_tag(bmain, id);
- if (flag & (OB_RECALC_DATA | PSYS_RECALC))
- lib_id_recalc_data_tag(bmain, id);
+ *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS;
+ *operation_code = DEG_OPCODE_VIEW_LAYER_EVAL;
+ }
+ else if (id_type == ID_OB) {
+ *component_type = DEG_NODE_TYPE_OBJECT_FROM_LAYER;
+ *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS;
+ }
+ else if (id_type == ID_MC) {
+ *component_type = DEG_NODE_TYPE_BATCH_CACHE;
+ *operation_code = DEG_OPCODE_MOVIECLIP_SELECT_UPDATE;
}
else {
- lib_id_recalc_tag(bmain, id);
+ *component_type = DEG_NODE_TYPE_BATCH_CACHE;
+ *operation_code = DEG_OPCODE_GEOMETRY_SELECT_UPDATE;
}
}
-#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
-void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag)
+void depsgraph_base_flags_tag_to_component_opcode(
+ const ID *id,
+ eDepsNode_Type *component_type,
+ eDepsOperation_Code *operation_code)
{
- if (flag) {
- Object *object;
- short idtype = GS(id->name);
- if (idtype == ID_PA) {
- ParticleSystem *psys;
- for (object = (Object *)bmain->object.first;
- object != NULL;
- object = (Object *)object->id.next)
- {
- for (psys = (ParticleSystem *)object->particlesystem.first;
- psys != NULL;
- psys = (ParticleSystem *)psys->next)
- {
- if (&psys->part->id == id) {
- DEG_id_tag_update_ex(bmain, &object->id, flag & OB_RECALC_ALL);
- psys->recalc |= (flag & PSYS_RECALC);
- }
- }
- }
- }
+ const ID_Type id_type = GS(id->name);
+ if (id_type == ID_SCE) {
+ *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS;
+ *operation_code = DEG_OPCODE_VIEW_LAYER_EVAL;
+ }
+ else if (id_type == ID_OB) {
+ *component_type = DEG_NODE_TYPE_OBJECT_FROM_LAYER;
+ *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS;
}
}
-#endif
-} /* namespace */
+void depsgraph_tag_to_component_opcode(const ID *id,
+ eDepsgraph_Tag tag,
+ eDepsNode_Type *component_type,
+ eDepsOperation_Code *operation_code)
+{
+ const ID_Type id_type = GS(id->name);
+ *component_type = DEG_NODE_TYPE_UNDEFINED;
+ *operation_code = DEG_OPCODE_OPERATION;
+ /* Special case for now, in the future we should get rid of this. */
+ if (tag == 0) {
+ *component_type = DEG_NODE_TYPE_ID_REF;
+ *operation_code = DEG_OPCODE_OPERATION;
+ return;
+ }
+ switch (tag) {
+ case DEG_TAG_TRANSFORM:
+ *component_type = DEG_NODE_TYPE_TRANSFORM;
+ break;
+ case DEG_TAG_GEOMETRY:
+ depsgraph_geometry_tag_to_component(id, component_type);
+ break;
+ case DEG_TAG_TIME:
+ *component_type = DEG_NODE_TYPE_ANIMATION;
+ break;
+ case DEG_TAG_PSYS_REDO:
+ case DEG_TAG_PSYS_RESET:
+ case DEG_TAG_PSYS_TYPE:
+ case DEG_TAG_PSYS_CHILD:
+ case DEG_TAG_PSYS_PHYS:
+ if (id_type == ID_PA) {
+ /* NOTES:
+ * - For particle settings node we need to use different
+ * component. Will be nice to get this unified with object,
+ * but we can survive for now with single exception here.
+ * Particles needs reconsideration anyway,
+ */
+ *component_type = DEG_NODE_TYPE_PARAMETERS;
+ }
+ else {
+ *component_type = DEG_NODE_TYPE_EVAL_PARTICLES;
+ }
+ break;
+ case DEG_TAG_COPY_ON_WRITE:
+ *component_type = DEG_NODE_TYPE_COPY_ON_WRITE;
+ break;
+ case DEG_TAG_SHADING_UPDATE:
+ if (id_type == ID_NT) {
+ *component_type = DEG_NODE_TYPE_SHADING_PARAMETERS;
+ }
+ else {
+ *component_type = DEG_NODE_TYPE_SHADING;
+ }
+ break;
+ case DEG_TAG_SELECT_UPDATE:
+ depsgraph_select_tag_to_component_opcode(id,
+ component_type,
+ operation_code);
+ break;
+ case DEG_TAG_BASE_FLAGS_UPDATE:
+ depsgraph_base_flags_tag_to_component_opcode(id,
+ component_type,
+ operation_code);
+ break;
+ case DEG_TAG_POINT_CACHE_UPDATE:
+ *component_type = DEG_NODE_TYPE_POINT_CACHE;
+ break;
+ case DEG_TAG_EDITORS_UPDATE:
+ /* There is no such node in depsgraph, this tag is to be handled
+ * separately.
+ */
+ break;
+ case DEG_TAG_PSYS_ALL:
+ BLI_assert(!"Should not happen");
+ break;
+ }
+}
-/* Tag all nodes in ID-block for update.
- * This is a crude measure, but is most convenient for old code.
- */
-void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
+void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag)
{
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
- DEG::IDDepsNode *node = deg_graph->find_id_node(id);
- lib_id_recalc_tag(bmain, id);
- if (node != NULL) {
- node->tag_update(deg_graph);
+ bNodeTree *ntree = ntreeFromID(id);
+ if (ntree == NULL) {
+ return;
}
+ deg_graph_id_tag_update(bmain, graph, &ntree->id, flag);
}
-/* Tag given ID for an update in all the dependency graphs. */
-void DEG_id_tag_update(ID *id, short flag)
+void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id)
{
- DEG_id_tag_update_ex(G.main, id, flag);
+ /* NOTE: We handle this immediately, without delaying anything, to be
+ * sure we don't cause threading issues with OpenGL.
+ */
+ /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */
+ DEGEditorUpdateContext update_ctx = {NULL};
+ update_ctx.bmain = bmain;
+ update_ctx.depsgraph = (::Depsgraph *)graph;
+ update_ctx.scene = graph->scene;
+ update_ctx.view_layer = graph->view_layer;
+ deg_editors_id_update(&update_ctx, id);
}
-void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
+void depsgraph_tag_component(Depsgraph *graph,
+ IDDepsNode *id_node,
+ eDepsNode_Type component_type,
+ eDepsOperation_Code operation_code)
{
- if (id == NULL) {
- /* Ideally should not happen, but old depsgraph allowed this. */
+ ComponentDepsNode *component_node =
+ id_node->find_component(component_type);
+ if (component_node == NULL) {
return;
}
- DEG_DEBUG_PRINTF(TAG, "%s: id=%s flag=%d\n", __func__, id->name, flag);
- lib_id_recalc_tag_flag(bmain, id, flag);
- for (Scene *scene = (Scene *)bmain->scene.first;
- scene != NULL;
- scene = (Scene *)scene->id.next)
- {
- if (scene->depsgraph) {
- Depsgraph *graph = scene->depsgraph;
- if (flag == 0) {
- /* TODO(sergey): Currently blender is still tagging IDs
- * for recalc just using flag=0. This isn't totally correct
- * but we'd better deal with such cases and don't fail.
- */
- DEG_graph_id_tag_update(bmain, graph, id);
- continue;
- }
- if (flag & OB_RECALC_DATA && GS(id->name) == ID_OB) {
+ if (operation_code == DEG_OPCODE_OPERATION) {
+ component_node->tag_update(graph, DEG_UPDATE_SOURCE_USER_EDIT);
+ }
+ else {
+ OperationDepsNode *operation_node =
+ component_node->find_operation(operation_code);
+ if (operation_node != NULL) {
+ operation_node->tag_update(graph, DEG_UPDATE_SOURCE_USER_EDIT);
+ }
+ }
+ /* If component depends on copy-on-write, tag it as well. */
+ if (component_node->need_tag_cow_before_update()) {
+ ComponentDepsNode *cow_comp =
+ id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
+ cow_comp->tag_update(graph, DEG_UPDATE_SOURCE_USER_EDIT);
+ id_node->id_orig->recalc |= ID_RECALC_COPY_ON_WRITE;
+ }
+}
+
+/* This is a tag compatibility with legacy code.
+ *
+ * Mainly, old code was tagging object with OB_RECALC_DATA tag to inform
+ * that object's data datablock changed. Now API expects that ID is given
+ * explicitly, but not all areas are aware of this yet.
+ */
+void deg_graph_id_tag_legacy_compat(Main *bmain,
+ Depsgraph *depsgraph,
+ ID *id,
+ eDepsgraph_Tag tag)
+{
+ if (tag == DEG_TAG_GEOMETRY || tag == 0) {
+ switch (GS(id->name)) {
+ case ID_OB:
+ {
Object *object = (Object *)id;
- if (object->data != NULL) {
- DEG_graph_id_tag_update(bmain,
- graph,
- (ID *)object->data);
+ ID *data_id = (ID *)object->data;
+ if (data_id != NULL) {
+ deg_graph_id_tag_update(bmain, depsgraph, data_id, 0);
}
+ break;
}
- if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) {
- DEG_graph_id_tag_update(bmain, graph, id);
+ /* TODO(sergey): Shape keys are annoying, maybe we should find a
+ * way to chain geometry evaluation to them, so we don't need extra
+ * tagging here.
+ */
+ case ID_ME:
+ {
+ Mesh *mesh = (Mesh *)id;
+ ID *key_id = &mesh->key->id;
+ if (key_id != NULL) {
+ deg_graph_id_tag_update(bmain, depsgraph, key_id, 0);
+ }
+ break;
+ }
+ case ID_LT:
+ {
+ Lattice *lattice = (Lattice *)id;
+ ID *key_id = &lattice->key->id;
+ if (key_id != NULL) {
+ deg_graph_id_tag_update(bmain, depsgraph, key_id, 0);
+ }
+ break;
}
- else if (flag & OB_RECALC_TIME) {
- DEG_graph_id_tag_update(bmain, graph, id);
+ case ID_CU:
+ {
+ Curve *curve = (Curve *)id;
+ ID *key_id = &curve->key->id;
+ if (key_id != NULL) {
+ deg_graph_id_tag_update(bmain, depsgraph, key_id, 0);
+ }
+ break;
}
+ default:
+ break;
}
}
+}
-#ifdef DEPSGRAPH_USE_LEGACY_TAGGING
- /* Special handling from the legacy depsgraph.
- * TODO(sergey): Need to get rid of those once all the areas
- * are re-formulated in terms of franular nodes.
+static void deg_graph_id_tag_update_single_flag(Main *bmain,
+ Depsgraph *graph,
+ ID *id,
+ IDDepsNode *id_node,
+ eDepsgraph_Tag tag)
+{
+ if (tag == DEG_TAG_EDITORS_UPDATE) {
+ if (graph != NULL) {
+ depsgraph_update_editors_tag(bmain, graph, id);
+ }
+ return;
+ }
+ /* Get description of what is to be tagged. */
+ eDepsNode_Type component_type;
+ eDepsOperation_Code operation_code;
+ depsgraph_tag_to_component_opcode(id,
+ tag,
+ &component_type,
+ &operation_code);
+ /* Check whether we've got something to tag. */
+ if (component_type == DEG_NODE_TYPE_UNDEFINED) {
+ /* Given ID does not support tag. */
+ /* TODO(sergey): Shall we raise some panic here? */
+ return;
+ }
+ /* Tag ID recalc flag. */
+ DepsNodeFactory *factory = deg_type_get_factory(component_type);
+ BLI_assert(factory != NULL);
+ id->recalc |= factory->id_recalc_tag();
+ /* Some sanity checks before moving forward. */
+ if (id_node == NULL) {
+ /* Happens when object is tagged for update and not yet in the
+ * dependency graph (but will be after relations update).
+ */
+ return;
+ }
+ /* Tag corresponding dependency graph operation for update. */
+ if (component_type == DEG_NODE_TYPE_ID_REF) {
+ id_node->tag_update(graph, DEG_UPDATE_SOURCE_USER_EDIT);
+ }
+ else {
+ depsgraph_tag_component(graph, id_node, component_type, operation_code);
+ }
+ /* TODO(sergey): Get rid of this once all areas are using proper data ID
+ * for tagging.
*/
- depsgraph_legacy_handle_update_tag(bmain, id, flag);
-#endif
+ deg_graph_id_tag_legacy_compat(bmain, graph, id, tag);
+
}
-/* Mark a particular datablock type as having changing. */
-void DEG_id_type_tag(Main *bmain, short idtype)
+string stringify_append_bit(const string& str, eDepsgraph_Tag tag)
{
- if (idtype == ID_NT) {
- /* Stupid workaround so parent datablocks of nested nodetree get looped
- * over when we loop over tagged datablock types.
- */
- DEG_id_type_tag(bmain, ID_MA);
- DEG_id_type_tag(bmain, ID_TE);
- DEG_id_type_tag(bmain, ID_LA);
- DEG_id_type_tag(bmain, ID_WO);
- DEG_id_type_tag(bmain, ID_SCE);
+ string result = str;
+ if (!result.empty()) {
+ result += ", ";
}
+ result += DEG_update_tag_as_string(tag);
+ return result;
+}
- bmain->id_tag_update[BKE_idcode_to_index(idtype)] = 1;
+string stringify_update_bitfield(int flag)
+{
+ if (flag == 0) {
+ return "LEGACY_0";
+ }
+ string result = "";
+ int current_flag = flag;
+ /* Special cases to avoid ALL flags form being split into
+ * individual bits.
+ */
+ if ((current_flag & DEG_TAG_PSYS_ALL) == DEG_TAG_PSYS_ALL) {
+ result = stringify_append_bit(result, DEG_TAG_PSYS_ALL);
+ }
+ /* Handle all the rest of the flags. */
+ while (current_flag != 0) {
+ eDepsgraph_Tag tag =
+ (eDepsgraph_Tag)(1 << bitscan_forward_clear_i(&current_flag));
+ result = stringify_append_bit(result, tag);
+ }
+ return result;
}
-/* Recursively push updates out to all nodes dependent on this,
- * until all affected are tagged and/or scheduled up for eval
+/* Special tag function which tags all components which needs to be tagged
+ * for update flag=0.
+ *
+ * TODO(sergey): This is something to be avoid in the future, make it more
+ * explicit and granular for users to tag what they really need.
*/
-void DEG_ids_flush_tagged(Main *bmain)
+void deg_graph_node_tag_zero(Main *bmain, Depsgraph *graph, IDDepsNode *id_node)
{
- for (Scene *scene = (Scene *)bmain->scene.first;
- scene != NULL;
- scene = (Scene *)scene->id.next)
+ if (id_node == NULL) {
+ return;
+ }
+ ID *id = id_node->id_orig;
+ /* TODO(sergey): Which recalc flags to set here? */
+ id->recalc |= ID_RECALC_ALL & ~(DEG_TAG_PSYS_ALL | ID_RECALC_ANIMATION);
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
{
- DEG_scene_flush_update(bmain, scene);
+ if (comp_node->type == DEG_NODE_TYPE_ANIMATION) {
+ continue;
+ }
+ comp_node->tag_update(graph, DEG_UPDATE_SOURCE_USER_EDIT);
}
+ GHASH_FOREACH_END();
+ deg_graph_id_tag_legacy_compat(bmain, graph, id, (eDepsgraph_Tag)0);
}
-void DEG_scene_flush_update(Main *bmain, Scene *scene)
+void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag)
{
- if (scene->depsgraph == NULL) {
- return;
+ const int debug_flags = (graph != NULL)
+ ? DEG_debug_flags_get((::Depsgraph *)graph)
+ : G.debug;
+ if (debug_flags & G_DEBUG_DEPSGRAPH_TAG) {
+ printf("%s: id=%s flags=%s\n",
+ __func__,
+ id->name,
+ stringify_update_bitfield(flag).c_str());
+ }
+ IDDepsNode *id_node = (graph != NULL) ? graph->find_id_node(id)
+ : NULL;
+ DEG_id_type_tag(bmain, GS(id->name));
+ if (flag == 0) {
+ deg_graph_node_tag_zero(bmain, graph, id_node);
}
- DEG::deg_graph_flush_updates(
- bmain,
- reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph));
+ id->recalc |= (flag & PSYS_RECALC);
+ int current_flag = flag;
+ while (current_flag != 0) {
+ eDepsgraph_Tag tag =
+ (eDepsgraph_Tag)(1 << bitscan_forward_clear_i(&current_flag));
+ deg_graph_id_tag_update_single_flag(bmain,
+ graph,
+ id,
+ id_node,
+ tag);
+ }
+ /* Special case for nested node tree datablocks. */
+ id_tag_update_ntree_special(bmain, graph, id, flag);
+ /* Direct update tags means that something outside of simulated/cached
+ * physics did change and that cache is to be invalidated.
+ */
+ deg_graph_id_tag_update_single_flag(
+ bmain, graph, id, id_node, DEG_TAG_POINT_CACHE_UPDATE);
}
-/* Update dependency graph when visible scenes/layers changes. */
-void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
+void deg_id_tag_update(Main *bmain, ID *id, int flag)
{
- DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
- wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
- int old_layers = graph->layers;
- if (wm != NULL) {
- BKE_main_id_tag_listbase(&bmain->scene, LIB_TAG_DOIT, true);
- graph->layers = 0;
- for (wmWindow *win = (wmWindow *)wm->windows.first;
- win != NULL;
- win = (wmWindow *)win->next)
- {
- Scene *scene = win->screen->scene;
- if (scene->id.tag & LIB_TAG_DOIT) {
- graph->layers |= BKE_screen_visible_layers(win->screen, scene);
- scene->id.tag &= ~LIB_TAG_DOIT;
+ deg_graph_id_tag_update(bmain, NULL, id, flag);
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ Depsgraph *depsgraph =
+ (Depsgraph *)BKE_scene_get_depsgraph(scene,
+ view_layer,
+ false);
+ if (depsgraph != NULL) {
+ deg_graph_id_tag_update(bmain, depsgraph, id, flag);
}
}
}
- else {
- /* All the layers for background render for now. */
- graph->layers = (1 << 20) - 1;
- }
- if (old_layers != graph->layers) {
- /* Tag all objects which becomes visible (or which becomes needed for dependencies)
- * for recalc.
+}
+
+void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph)
+{
+ foreach (DEG::IDDepsNode *id_node, graph->id_nodes) {
+ if (!id_node->visible_components_mask) {
+ /* ID has no components which affects anything visible. no meed
+ * bother with it to tag or anything.
+ */
+ continue;
+ }
+ if (id_node->visible_components_mask ==
+ id_node->previously_visible_components_mask)
+ {
+ /* The ID was already visible and evaluated, all the subsequent
+ * updates and tags are to be done explicitly.
+ */
+ continue;
+ }
+ int flag = 0;
+ if (!DEG::deg_copy_on_write_is_expanded(id_node->id_cow)) {
+ flag |= DEG_TAG_COPY_ON_WRITE;
+ }
+ /* We only tag components which needs an update. Tagging everything is
+ * not a good idea because that might reset particles cache (or any
+ * other type of cache).
*
- * This is mainly needed on file load only, after that updates of invisible objects
- * will be stored in the pending list.
+ * TODO(sergey): Need to generalize this somehow.
*/
- foreach (DEG::IDDepsNode *id_node, graph->id_nodes) {
- ID *id = id_node->id;
- if ((id->recalc & ID_RECALC_ALL) != 0 ||
- (id_node->layers & scene->lay_updated) == 0)
- {
- id_node->tag_update(graph);
- }
- /* A bit of magic: if object->recalc is set it means somebody tagged
- * it for update. If corresponding ID recalc flags are zero it means
- * graph has been evaluated after that and the recalc was skipped
- * because of visibility check.
- */
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if ((id->recalc & ID_RECALC_ALL) == 0 &&
- (object->recalc & OB_RECALC_ALL) != 0)
- {
- id_node->tag_update(graph);
- DEG::ComponentDepsNode *anim_comp =
- id_node->find_component(DEG::DEG_NODE_TYPE_ANIMATION);
- if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
- anim_comp->tag_update(graph);
- }
- }
+ const ID_Type id_type = GS(id_node->id_orig->name);
+ if (id_type == ID_OB) {
+ flag |= OB_RECALC_OB | OB_RECALC_DATA;
+ }
+ deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag);
+ if (id_type == ID_SCE) {
+ /* Make sure collection properties are up to date. */
+ id_node->tag_update(graph, DEG_UPDATE_SOURCE_VISIBILITY);
+ }
+ /* Now when ID is updated to the new visibility state, prevent it from
+ * being re-tagged again. Simplest way to do so is to pretend that it
+ * was already updated by the "previous" dependency graph.
+ *
+ * NOTE: Even if the on_visible_update() is called from the state when
+ * dependency graph is tagged for relations update, it will be fine:
+ * since dependency graph builder re-schedules entry tags, all the
+ * tags we request from here will be applied in the updated state of
+ * dependency graph.
+ */
+ id_node->previously_visible_components_mask =
+ id_node->visible_components_mask;
+ }
+}
+
+} /* namespace */
+
+eDepsNode_Type deg_geometry_tag_to_component(const ID *id)
+{
+ const ID_Type id_type = GS(id->name);
+ switch (id_type) {
+ case ID_OB:
+ {
+ const Object *object = (Object *)id;
+ switch (object->type) {
+ case OB_MESH:
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ case OB_LATTICE:
+ case OB_MBALL:
+ case OB_GPENCIL:
+ return DEG_NODE_TYPE_GEOMETRY;
+ case OB_ARMATURE:
+ return DEG_NODE_TYPE_EVAL_POSE;
+ /* TODO(sergey): More cases here? */
}
+ break;
}
+ case ID_ME:
+ return DEG_NODE_TYPE_GEOMETRY;
+ case ID_PA: /* Particles */
+ return DEG_NODE_TYPE_UNDEFINED;
+ case ID_LP:
+ return DEG_NODE_TYPE_PARAMETERS;
+ case ID_GD:
+ return DEG_NODE_TYPE_GEOMETRY;
+ case ID_PAL: /* Palettes */
+ return DEG_NODE_TYPE_PARAMETERS;
+ default:
+ break;
}
- scene->lay_updated |= graph->layers;
- /* If graph is tagged for update, we don't need to bother with updates here,
- * nodes will be re-created.
- */
- if (graph->need_update) {
+ return DEG_NODE_TYPE_UNDEFINED;
+}
+
+} // namespace DEG
+
+const char *DEG_update_tag_as_string(eDepsgraph_Tag flag)
+{
+ switch (flag) {
+ case DEG_TAG_TRANSFORM: return "TRANSFORM";
+ case DEG_TAG_GEOMETRY: return "GEOMETRY";
+ case DEG_TAG_TIME: return "TIME";
+ case DEG_TAG_PSYS_REDO: return "PSYS_REDO";
+ case DEG_TAG_PSYS_RESET: return "PSYS_RESET";
+ case DEG_TAG_PSYS_TYPE: return "PSYS_TYPE";
+ case DEG_TAG_PSYS_CHILD: return "PSYS_CHILD";
+ case DEG_TAG_PSYS_PHYS: return "PSYS_PHYS";
+ case DEG_TAG_PSYS_ALL: return "PSYS_ALL";
+ case DEG_TAG_COPY_ON_WRITE: return "COPY_ON_WRITE";
+ case DEG_TAG_SHADING_UPDATE: return "SHADING_UPDATE";
+ case DEG_TAG_SELECT_UPDATE: return "SELECT_UPDATE";
+ case DEG_TAG_BASE_FLAGS_UPDATE: return "BASE_FLAGS_UPDATE";
+ case DEG_TAG_POINT_CACHE_UPDATE: return "POINT_CACHE_UPDATE";
+ case DEG_TAG_EDITORS_UPDATE: return "EDITORS_UPDATE";
+ }
+ BLI_assert(!"Unhandled update flag, should never happen!");
+ return "UNKNOWN";
+}
+
+/* Data-Based Tagging */
+
+/* Tag given ID for an update in all the dependency graphs. */
+void DEG_id_tag_update(ID *id, int flag)
+{
+ DEG_id_tag_update_ex(G.main, id, flag);
+}
+
+void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag)
+{
+ if (id == NULL) {
+ /* Ideally should not happen, but old depsgraph allowed this. */
return;
}
- /* Special trick to get local view to work. */
- LISTBASE_FOREACH (Base *, base, &scene->base) {
- Object *object = base->object;
- DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
- id_node->layers = 0;
- }
- LISTBASE_FOREACH (Base *, base, &scene->base) {
- Object *object = base->object;
- DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
- id_node->layers |= base->lay;
- if (object == scene->camera || object->type == OB_CAMERA) {
- /* Camera should always be updated, it used directly by viewport. */
- id_node->layers |= (unsigned int)(-1);
- }
+ DEG::deg_id_tag_update(bmain, id, flag);
+}
+
+void DEG_graph_id_tag_update(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ struct ID *id,
+ int flag)
+{
+ DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph;
+ DEG::deg_graph_id_tag_update(bmain, graph, id, flag);
+}
+
+/* Mark a particular datablock type as having changing. */
+void DEG_id_type_tag(Main *bmain, short id_type)
+{
+ if (id_type == ID_NT) {
+ /* Stupid workaround so parent datablocks of nested nodetree get looped
+ * over when we loop over tagged datablock types.
+ */
+ DEG_id_type_tag(bmain, ID_MA);
+ DEG_id_type_tag(bmain, ID_TE);
+ DEG_id_type_tag(bmain, ID_LA);
+ DEG_id_type_tag(bmain, ID_WO);
+ DEG_id_type_tag(bmain, ID_SCE);
}
- DEG::deg_graph_build_flush_layers(graph);
- LISTBASE_FOREACH (Base *, base, &scene->base) {
- Object *object = base->object;
- DEG::IDDepsNode *id_node = graph->find_id_node(&object->id);
- GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp, id_node->components)
- {
- id_node->layers |= comp->layers;
+
+ int id_type_index = BKE_idcode_to_index(id_type);
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ Depsgraph *depsgraph =
+ (Depsgraph *)BKE_scene_get_depsgraph(scene,
+ view_layer,
+ false);
+ if (depsgraph != NULL) {
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ deg_graph->id_type_updated[id_type_index] = 1;
+ }
}
- GHASH_FOREACH_END();
}
}
+void DEG_graph_flush_update(Main *bmain, Depsgraph *depsgraph)
+{
+ if (depsgraph == NULL) {
+ return;
+ }
+ DEG::deg_graph_flush_updates(bmain, (DEG::Depsgraph *)depsgraph);
+}
+
+/* Update dependency graph when visible scenes/layers changes. */
+void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph)
+{
+ DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph;
+ DEG::deg_graph_on_visible_update(bmain, graph);
+}
+
void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
{
- for (Scene *scene = (Scene *)bmain->scene.first;
- scene != NULL;
- scene = (Scene *)scene->id.next)
- {
- if (scene->depsgraph != NULL) {
- DEG_graph_on_visible_update(bmain, scene);
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scene) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ Depsgraph *depsgraph =
+ (Depsgraph *)BKE_scene_get_depsgraph(scene,
+ view_layer,
+ false);
+ if (depsgraph != NULL) {
+ DEG_graph_on_visible_update(bmain, depsgraph);
+ }
}
}
}
@@ -369,55 +695,68 @@ void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
/* Check if something was changed in the database and inform
* editors about this.
*/
-void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+void DEG_ids_check_recalc(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ ViewLayer *view_layer,
+ bool time)
{
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
- bool updated = false;
-
- /* Loop over all ID types. */
- a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id = (ID *)lb->first;
-
- if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
- updated = true;
- break;
- }
- }
+ bool updated = time || DEG_id_type_any_updated(depsgraph);
+
+ DEGEditorUpdateContext update_ctx = {NULL};
+ update_ctx.bmain = bmain;
+ update_ctx.depsgraph = depsgraph;
+ update_ctx.scene = scene;
+ update_ctx.view_layer = view_layer;
+ DEG::deg_editors_scene_update(&update_ctx, updated);
+}
- DEG::deg_editors_scene_update(bmain, scene, (updated || time));
+static void deg_graph_clear_id_node_func(
+ void *__restrict data_v,
+ const int i,
+ const ParallelRangeTLS *__restrict /*tls*/)
+{
+ /* TODO: we clear original ID recalc flags here, but this may not work
+ * correctly when there are multiple depsgraph with others still using
+ * the recalc flag. */
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(data_v);
+ DEG::IDDepsNode *id_node = deg_graph->id_nodes[i];
+ id_node->id_cow->recalc &= ~ID_RECALC_ALL;
+ id_node->id_orig->recalc &= ~ID_RECALC_ALL;
+
+ /* Clear embedded node trees too. */
+ bNodeTree *ntree_cow = ntreeFromID(id_node->id_cow);
+ if (ntree_cow) {
+ ntree_cow->id.recalc &= ~ID_RECALC_ALL;
+ }
+ bNodeTree *ntree_orig = ntreeFromID(id_node->id_orig);
+ if (ntree_orig) {
+ ntree_orig->id.recalc &= ~ID_RECALC_ALL;
+ }
}
-void DEG_ids_clear_recalc(Main *bmain)
+void DEG_ids_clear_recalc(Main *UNUSED(bmain),
+ Depsgraph *depsgraph)
{
- ListBase *lbarray[MAX_LIBARRAY];
- bNodeTree *ntree;
- int a;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
/* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags
* and id_tags storage from the new dependency graph.
*/
- /* Loop over all ID types. */
- a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id = (ID *)lb->first;
-
- if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) {
- for (; id; id = (ID *)id->next) {
- id->recalc &= ~ID_RECALC_ALL;
-
- /* Some ID's contain semi-datablock nodetree */
- ntree = ntreeFromID(id);
- if (ntree != NULL) {
- ntree->id.recalc &= ~ID_RECALC_ALL;
- }
- }
- }
+ if (!DEG_id_type_any_updated(depsgraph)) {
+ return;
}
- memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update));
+ /* Go over all ID nodes nodes, clearing tags. */
+ const int num_id_nodes = deg_graph->id_nodes.size();
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
+ BLI_task_parallel_range(0, num_id_nodes,
+ deg_graph,
+ deg_graph_clear_id_node_func,
+ &settings);
+
+ memset(deg_graph->id_type_updated, 0, sizeof(deg_graph->id_type_updated));
}
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 41c72d11eac..3f36b9f7831 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -71,11 +71,50 @@ DepsNodeFactory *deg_type_get_factory(const eDepsNode_Type type)
return depsnode_typeinfo_registry[type];
}
-/* Stringified opcodes ------------------------------------- */
+/* Stringified node types ---------------------------------- */
+
+const char *nodeTypeAsString(eDepsNode_Type type)
+{
+ switch (type) {
+#define STRINGIFY_TYPE(name) case DEG_NODE_TYPE_##name: return #name
+
+ STRINGIFY_TYPE(UNDEFINED);
+ STRINGIFY_TYPE(OPERATION);
+ /* **** Generic Types **** */
+ STRINGIFY_TYPE(TIMESOURCE);
+ STRINGIFY_TYPE(ID_REF);
+ /* **** Outer Types **** */
+ STRINGIFY_TYPE(PARAMETERS);
+ STRINGIFY_TYPE(PROXY);
+ STRINGIFY_TYPE(ANIMATION);
+ STRINGIFY_TYPE(TRANSFORM);
+ STRINGIFY_TYPE(GEOMETRY);
+ STRINGIFY_TYPE(SEQUENCER);
+ STRINGIFY_TYPE(LAYER_COLLECTIONS);
+ STRINGIFY_TYPE(COPY_ON_WRITE);
+ STRINGIFY_TYPE(OBJECT_FROM_LAYER);
+ /* **** Evaluation-Related Outer Types (with Subdata) **** */
+ STRINGIFY_TYPE(EVAL_POSE);
+ STRINGIFY_TYPE(BONE);
+ STRINGIFY_TYPE(EVAL_PARTICLES);
+ STRINGIFY_TYPE(SHADING);
+ STRINGIFY_TYPE(SHADING_PARAMETERS);
+ STRINGIFY_TYPE(CACHE);
+ STRINGIFY_TYPE(POINT_CACHE);
+ STRINGIFY_TYPE(BATCH_CACHE);
+ /* Duplication. */
+ STRINGIFY_TYPE(DUPLI);
+
+ /* Total number of meaningful node types. */
+ case NUM_DEG_NODE_TYPES: return "SpecialCase";
+#undef STRINGIFY_TYPE
+ }
+ return "UNKNOWN";
+}
-DepsOperationStringifier DEG_OPNAMES;
+/* Stringified opcodes ------------------------------------- */
-static const char *stringify_opcode(eDepsOperation_Code opcode)
+const char *operationCodeAsString(eDepsOperation_Code opcode)
{
switch (opcode) {
#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name
@@ -87,6 +126,8 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
/* Animation, Drivers, etc. */
STRINGIFY_OPCODE(ANIMATION);
STRINGIFY_OPCODE(DRIVER);
+ /* Object related. */
+ STRINGIFY_OPCODE(OBJECT_BASE_FLAGS);
/* Transform. */
STRINGIFY_OPCODE(TRANSFORM_LOCAL);
STRINGIFY_OPCODE(TRANSFORM_PARENT);
@@ -99,11 +140,14 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
STRINGIFY_OPCODE(RIGIDBODY_TRANSFORM_COPY);
/* Geometry. */
STRINGIFY_OPCODE(GEOMETRY_UBEREVAL);
- STRINGIFY_OPCODE(GEOMETRY_CLOTH_MODIFIER);
STRINGIFY_OPCODE(GEOMETRY_SHAPEKEY);
+ /* Object data. */
+ STRINGIFY_OPCODE(LIGHT_PROBE_EVAL);
+ STRINGIFY_OPCODE(SPEAKER_EVAL);
/* Pose. */
STRINGIFY_OPCODE(POSE_INIT);
STRINGIFY_OPCODE(POSE_INIT_IK);
+ STRINGIFY_OPCODE(POSE_CLEANUP);
STRINGIFY_OPCODE(POSE_DONE);
STRINGIFY_OPCODE(POSE_IK_SOLVER);
STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER);
@@ -113,16 +157,29 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
STRINGIFY_OPCODE(BONE_CONSTRAINTS);
STRINGIFY_OPCODE(BONE_READY);
STRINGIFY_OPCODE(BONE_DONE);
+ STRINGIFY_OPCODE(BONE_SEGMENTS);
/* Particles. */
STRINGIFY_OPCODE(PARTICLE_SYSTEM_EVAL_INIT);
STRINGIFY_OPCODE(PARTICLE_SYSTEM_EVAL);
+ STRINGIFY_OPCODE(PARTICLE_SETTINGS_EVAL);
+ /* Point Cache. */
+ STRINGIFY_OPCODE(POINT_CACHE_RESET);
+ /* Batch cache. */
+ STRINGIFY_OPCODE(GEOMETRY_SELECT_UPDATE);
/* Masks. */
STRINGIFY_OPCODE(MASK_ANIMATION);
STRINGIFY_OPCODE(MASK_EVAL);
+ /* Collections. */
+ STRINGIFY_OPCODE(VIEW_LAYER_EVAL);
+ /* Copy on write. */
+ STRINGIFY_OPCODE(COPY_ON_WRITE);
/* Shading. */
STRINGIFY_OPCODE(SHADING);
+ STRINGIFY_OPCODE(MATERIAL_UPDATE);
+ STRINGIFY_OPCODE(WORLD_UPDATE);
/* Movie clip. */
STRINGIFY_OPCODE(MOVIECLIP_EVAL);
+ STRINGIFY_OPCODE(MOVIECLIP_SELECT_UPDATE);
case DEG_NUM_OPCODES: return "SpecialCase";
#undef STRINGIFY_OPCODE
@@ -130,22 +187,6 @@ static const char *stringify_opcode(eDepsOperation_Code opcode)
return "UNKNOWN";
}
-DepsOperationStringifier::DepsOperationStringifier()
-{
- for (int i = 0; i < DEG_NUM_OPCODES; ++i) {
- names_[i] = stringify_opcode((eDepsOperation_Code)i);
- }
-}
-
-const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode)
-{
- BLI_assert((opcode >= 0) && (opcode < DEG_NUM_OPCODES));
- if (opcode >= 0 && opcode < DEG_NUM_OPCODES) {
- return names_[opcode];
- }
- return "UnknownOpcode";
-}
-
} // namespace DEG
/* Register all node types */
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index 0478d97cf6b..f8b519cb1aa 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -49,17 +49,19 @@ struct bAction;
struct ChannelDriver;
struct ModifierData;
struct PointerRNA;
-struct EvaluationContext;
struct FCurve;
+struct Depsgraph;
namespace DEG {
+/* TODO(sergey): Find a better place for this. */
using std::string;
using std::vector;
+using std::max;
/* Evaluation Operation for atomic operation */
// XXX: move this to another header that can be exposed?
-typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb;
+typedef function<void(struct ::Depsgraph *)> DepsEvalOperationCb;
/* Metatype of Nodes - The general "level" in the graph structure
* the node serves.
@@ -80,6 +82,18 @@ typedef enum eDepsNode_Class {
DEG_NODE_CLASS_OPERATION = 2,
} eDepsNode_Class;
+/* Note: We use max comparison to mark an id node that is linked more than once
+ * So keep this enum ordered accordingly.
+ */
+typedef enum eDepsNode_LinkedState_Type {
+ /* Generic indirectly linked id node. */
+ DEG_ID_LINKED_INDIRECTLY = 0,
+ /* Id node present in the set (background) only. */
+ DEG_ID_LINKED_VIA_SET = 1,
+ /* Id node directly linked via the ScenLayer. */
+ DEG_ID_LINKED_DIRECTLY = 2,
+} eDepsNode_LinkedState_Type;
+
/* Types of Nodes */
typedef enum eDepsNode_Type {
/* Fallback type for invalid return value */
@@ -108,10 +122,22 @@ typedef enum eDepsNode_Type {
DEG_NODE_TYPE_ANIMATION,
/* Transform Component (Parenting/Constraints) */
DEG_NODE_TYPE_TRANSFORM,
- /* Geometry Component (DerivedMesh/Displist) */
+ /* Geometry Component (Mesh/Displist) */
DEG_NODE_TYPE_GEOMETRY,
/* Sequencer Component (Scene Only) */
DEG_NODE_TYPE_SEQUENCER,
+ /* Component which contains all operations needed for layer collections
+ * evaluation.
+ */
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ /* Entry component of majority of ID nodes: prepares CoW pointers for
+ * execution.
+ */
+ DEG_NODE_TYPE_COPY_ON_WRITE,
+ /* Used by all operations which are updating object when something is
+ * changed in view layer.
+ */
+ DEG_NODE_TYPE_OBJECT_FROM_LAYER,
/* **** Evaluation-Related Outer Types (with Subdata) **** */
@@ -123,12 +149,24 @@ typedef enum eDepsNode_Type {
DEG_NODE_TYPE_EVAL_PARTICLES,
/* Material Shading Component */
DEG_NODE_TYPE_SHADING,
+ DEG_NODE_TYPE_SHADING_PARAMETERS,
+ /* Point cache Component */
+ DEG_NODE_TYPE_POINT_CACHE,
/* Cache Component */
+ /* TODO(sergey); Verify that we really need this. */
DEG_NODE_TYPE_CACHE,
+ /* Batch Cache Component - TODO (dfelinto/sergey) rename to make it more generic. */
+ DEG_NODE_TYPE_BATCH_CACHE,
+
+ /* Duplication system. Used to force duplicated objects visible when
+ * when duplicator is visible.
+ */
+ DEG_NODE_TYPE_DUPLI,
/* Total number of meaningful node types. */
NUM_DEG_NODE_TYPES,
} eDepsNode_Type;
+const char *nodeTypeAsString(eDepsNode_Type type);
/* Identifiers for common operations (as an enum). */
typedef enum eDepsOperation_Code {
@@ -150,6 +188,9 @@ typedef enum eDepsOperation_Code {
/* Driver */
DEG_OPCODE_DRIVER,
+ /* Object related. --------------------------------- */
+ DEG_OPCODE_OBJECT_BASE_FLAGS,
+
/* Transform. -------------------------------------- */
/* Transform entry point - local transforms only */
DEG_OPCODE_TRANSFORM_LOCAL,
@@ -170,17 +211,24 @@ typedef enum eDepsOperation_Code {
DEG_OPCODE_RIGIDBODY_TRANSFORM_COPY,
/* Geometry. ---------------------------------------- */
+
/* Evaluate the whole geometry, including modifiers. */
DEG_OPCODE_GEOMETRY_UBEREVAL,
- DEG_OPCODE_GEOMETRY_CLOTH_MODIFIER,
+ /* Evaluation of a shape key. */
DEG_OPCODE_GEOMETRY_SHAPEKEY,
+ /* Object data. ------------------------------------- */
+ DEG_OPCODE_LIGHT_PROBE_EVAL,
+ DEG_OPCODE_SPEAKER_EVAL,
+
/* Pose. -------------------------------------------- */
/* Init pose, clear flags, etc. */
DEG_OPCODE_POSE_INIT,
/* Initialize IK solver related pose stuff. */
DEG_OPCODE_POSE_INIT_IK,
- /* Free IK Trees + Compute Deform Matrices */
+ /* Pose is evaluated, and runtime data can be freed. */
+ DEG_OPCODE_POSE_CLEANUP,
+ /* Pose has been fully evaluated and ready to be used by others. */
DEG_OPCODE_POSE_DONE,
/* IK/Spline Solvers */
DEG_OPCODE_POSE_IK_SOLVER,
@@ -206,14 +254,31 @@ typedef enum eDepsOperation_Code {
// TODO: deform mats could get calculated in the final_transform ops...
DEG_OPCODE_BONE_READY,
DEG_OPCODE_BONE_DONE,
+ /* B-Bone segment shape computation (after DONE) */
+ DEG_OPCODE_BONE_SEGMENTS,
/* Particles. --------------------------------------- */
/* Particle System evaluation. */
DEG_OPCODE_PARTICLE_SYSTEM_EVAL_INIT,
DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
+ DEG_OPCODE_PARTICLE_SETTINGS_EVAL,
+
+ /* Point Cache. ------------------------------------- */
+ DEG_OPCODE_POINT_CACHE_RESET,
+
+ /* Collections. ------------------------------------- */
+ DEG_OPCODE_VIEW_LAYER_EVAL,
+
+ /* Copy on Write. ------------------------------------ */
+ DEG_OPCODE_COPY_ON_WRITE,
/* Shading. ------------------------------------------- */
DEG_OPCODE_SHADING,
+ DEG_OPCODE_MATERIAL_UPDATE,
+ DEG_OPCODE_WORLD_UPDATE,
+
+ /* Batch caches. -------------------------------------- */
+ DEG_OPCODE_GEOMETRY_SELECT_UPDATE,
/* Masks. ------------------------------------------ */
DEG_OPCODE_MASK_ANIMATION,
@@ -221,20 +286,25 @@ typedef enum eDepsOperation_Code {
/* Movie clips. ------------------------------------ */
DEG_OPCODE_MOVIECLIP_EVAL,
+ DEG_OPCODE_MOVIECLIP_SELECT_UPDATE,
DEG_NUM_OPCODES,
} eDepsOperation_Code;
+const char *operationCodeAsString(eDepsOperation_Code opcode);
-/* Some magic to stringify operation codes. */
-class DepsOperationStringifier {
-public:
- DepsOperationStringifier();
- const char *operator[](eDepsOperation_Code opcodex);
-protected:
- const char *names_[DEG_NUM_OPCODES];
-};
-
-/* String defines for these opcodes, defined in depsgraph_type_defines.cpp */
-extern DepsOperationStringifier DEG_OPNAMES;
+/* Source of the dependency graph node update tag.
+ *
+ * NOTE: This is a bit mask, so accumulation of sources is possible.
+ */
+typedef enum eDepsTag_Source {
+ /* Update is caused by a time change. */
+ DEG_UPDATE_SOURCE_TIME = (1 << 0),
+ /* Update caused by user directly or indirectly influencing the node. */
+ DEG_UPDATE_SOURCE_USER_EDIT = (1 << 1),
+ /* Update is happening as a special response for the relations update. */
+ DEG_UPDATE_SOURCE_RELATIONS = (1 << 2),
+ /* Update is happening due to visibility change. */
+ DEG_UPDATE_SOURCE_VISIBILITY = (1 << 3),
+} eDepsTag_Source;
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index fc71b5ccb7b..0097fc95948 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -38,15 +38,15 @@
#include "BLI_task.h"
#include "BLI_ghash.h"
-extern "C" {
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-} /* extern "C" */
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "atomic_ops.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/eval/deg_eval_flush.h"
#include "intern/eval/deg_eval_stats.h"
#include "intern/nodes/deg_node.h"
@@ -68,13 +68,10 @@ namespace DEG {
static void schedule_children(TaskPool *pool,
Depsgraph *graph,
OperationDepsNode *node,
- const unsigned int layers,
const int thread_id);
struct DepsgraphEvalState {
- EvaluationContext *eval_ctx;
Depsgraph *graph;
- unsigned int layers;
bool do_stats;
};
@@ -90,63 +87,80 @@ static void deg_task_run_func(TaskPool *pool,
/* Perform operation. */
if (state->do_stats) {
const double start_time = PIL_check_seconds_timer();
- node->evaluate(state->eval_ctx);
+ node->evaluate((::Depsgraph *)state->graph);
node->stats.current_time += PIL_check_seconds_timer() - start_time;
}
else {
- node->evaluate(state->eval_ctx);
+ node->evaluate((::Depsgraph *)state->graph);
}
/* Schedule children. */
BLI_task_pool_delayed_push_begin(pool, thread_id);
- schedule_children(pool, state->graph, node, state->layers, thread_id);
+ schedule_children(pool, state->graph, node, thread_id);
BLI_task_pool_delayed_push_end(pool, thread_id);
}
-typedef struct CalculatePengindData {
+typedef struct CalculatePendingData {
Depsgraph *graph;
- unsigned int layers;
-} CalculatePengindData;
+} CalculatePendingData;
+
+static bool check_operation_node_visible(OperationDepsNode *op_node)
+{
+ const ComponentDepsNode *comp_node = op_node->owner;
+ /* Special exception, copy on write component is to be always evaluated,
+ * to keep copied "database" in a consistent state.
+ */
+ if (comp_node->type == DEG_NODE_TYPE_COPY_ON_WRITE) {
+ return true;
+ }
+ return comp_node->affects_directly_visible;
+}
static void calculate_pending_func(
void *__restrict data_v,
const int i,
const ParallelRangeTLS *__restrict /*tls*/)
{
- CalculatePengindData *data = (CalculatePengindData *)data_v;
+ CalculatePendingData *data = (CalculatePendingData *)data_v;
Depsgraph *graph = data->graph;
- unsigned int layers = data->layers;
OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
-
+ /* Update counters, applies for both visible and invisible IDs. */
node->num_links_pending = 0;
node->scheduled = false;
-
- /* count number of inputs that need updates */
- if ((id_node->layers & layers) != 0 &&
- (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- foreach (DepsRelation *rel, node->inlinks) {
- if (rel->from->type == DEG_NODE_TYPE_OPERATION &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
- {
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
- IDDepsNode *id_from_node = from->owner->owner;
- if ((id_from_node->layers & layers) != 0 &&
- (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- ++node->num_links_pending;
- }
+ /* Invisible IDs requires no pending operations. */
+ if (!check_operation_node_visible(node)) {
+ return;
+ }
+ /* No need to bother with anything if node is not tagged for update. */
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) {
+ return;
+ }
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEG_NODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ /* TODO(sergey): This is how old layer system was checking for the
+ * calculation, but how is it possible that visible object depends
+ * on an invisible? This is something what is prohibited after
+ * deg_graph_build_flush_layers().
+ */
+ if (!check_operation_node_visible(from)) {
+ continue;
+ }
+ /* No need to vait for operation which is up to date. */
+ if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) {
+ continue;
}
+ ++node->num_links_pending;
}
}
}
-static void calculate_pending_parents(Depsgraph *graph, unsigned int layers)
+static void calculate_pending_parents(Depsgraph *graph)
{
const int num_operations = graph->operations.size();
- CalculatePengindData data;
+ CalculatePendingData data;
data.graph = graph;
- data.layers = layers;
ParallelRangeSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.min_iter_per_thread = 1024;
@@ -160,10 +174,9 @@ static void calculate_pending_parents(Depsgraph *graph, unsigned int layers)
static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
{
const bool do_stats = state->do_stats;
- calculate_pending_parents(graph, state->layers);
+ calculate_pending_parents(graph);
/* Clear tags and other things which needs to be clear. */
foreach (OperationDepsNode *node, graph->operations) {
- node->done = 0;
if (do_stats) {
node->stats.reset_current();
}
@@ -174,55 +187,62 @@ static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
* 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, unsigned int layers,
+static void schedule_node(TaskPool *pool, Depsgraph *graph,
OperationDepsNode *node, bool dec_parents,
const int thread_id)
{
- unsigned int id_layers = node->owner->owner->layers;
-
- if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & layers) != 0)
- {
- if (dec_parents) {
- BLI_assert(node->num_links_pending > 0);
- atomic_sub_and_fetch_uint32(&node->num_links_pending, 1);
+ /* No need to schedule nodes of invisible ID. */
+ if (!check_operation_node_visible(node)) {
+ return;
+ }
+ /* No need to schedule operations which are not tagged for update, they are
+ * considered to be up to date.
+ */
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) {
+ return;
+ }
+ /* TODO(sergey): This is not strictly speaking safe to read
+ * num_links_pending.
+ */
+ if (dec_parents) {
+ BLI_assert(node->num_links_pending > 0);
+ atomic_sub_and_fetch_uint32(&node->num_links_pending, 1);
+ }
+ /* Cal not schedule operation while its dependencies are not yet
+ * evaluated.
+ */
+ if (node->num_links_pending != 0) {
+ return;
+ }
+ bool is_scheduled = atomic_fetch_and_or_uint8(
+ (uint8_t *)&node->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ if (node->is_noop()) {
+ /* skip NOOP node, schedule children right away */
+ schedule_children(pool, graph, node, thread_id);
}
-
- if (node->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8(
- (uint8_t *)&node->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- if (node->is_noop()) {
- /* skip NOOP node, schedule children right away */
- schedule_children(pool, graph, node, layers, thread_id);
- }
- else {
- /* children are scheduled once this task is completed */
- BLI_task_pool_push_from_thread(pool,
- deg_task_run_func,
- node,
- false,
- TASK_PRIORITY_HIGH,
- thread_id);
- }
- }
+ else {
+ /* children are scheduled once this task is completed */
+ BLI_task_pool_push_from_thread(pool,
+ deg_task_run_func,
+ node,
+ false,
+ TASK_PRIORITY_HIGH,
+ thread_id);
}
}
}
-static void schedule_graph(TaskPool *pool,
- Depsgraph *graph,
- const unsigned int layers)
+static void schedule_graph(TaskPool *pool, Depsgraph *graph)
{
foreach (OperationDepsNode *node, graph->operations) {
- schedule_node(pool, graph, layers, node, false, 0);
+ schedule_node(pool, graph, node, false, 0);
}
}
static void schedule_children(TaskPool *pool,
Depsgraph *graph,
OperationDepsNode *node,
- const unsigned int layers,
const int thread_id)
{
foreach (DepsRelation *rel, node->outlinks) {
@@ -234,13 +254,28 @@ static void schedule_children(TaskPool *pool,
}
schedule_node(pool,
graph,
- layers,
child,
(rel->flag & DEPSREL_FLAG_CYCLIC) == 0,
thread_id);
}
}
+static void depsgraph_ensure_view_layer(Depsgraph *graph)
+{
+ /* We update copy-on-write scene in the following cases:
+ * - It was not expanded yet.
+ * - It was tagged for update of CoW component.
+ * This allows us to have proper view layer pointer.
+ */
+ Scene *scene_cow = graph->scene_cow;
+ if (!deg_copy_on_write_is_expanded(&scene_cow->id) ||
+ scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE)
+ {
+ const IDDepsNode *id_node = graph->find_id_node(&graph->scene->id);
+ deg_update_copy_on_write_datablock(graph, id_node);
+ }
+}
+
/**
* Evaluate all nodes tagged for updating,
* \warning This is usually done as part of main loop, but may also be
@@ -248,28 +283,18 @@ static void schedule_children(TaskPool *pool,
*
* \note Time sources should be all valid!
*/
-void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
- Depsgraph *graph,
- const unsigned int layers)
+void deg_evaluate_on_refresh(Depsgraph *graph)
{
- /* Set time for the current graph evaluation context. */
- TimeSourceDepsNode *time_src = graph->find_time_source();
- eval_ctx->ctime = time_src->cfra;
/* Nothing to update, early out. */
if (BLI_gset_len(graph->entry_tags) == 0) {
return;
}
- DEG_DEBUG_PRINTF(EVAL, "%s: layers:%u, graph->layers:%u\n",
- __func__,
- layers,
- graph->layers);
const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0;
- /* Set up evaluation context for depsgraph itself. */
+ depsgraph_ensure_view_layer(graph);
+ /* Set up evaluation state. */
DepsgraphEvalState state;
- state.eval_ctx = eval_ctx;
state.graph = graph;
- state.layers = layers;
state.do_stats = do_time_debug;
/* Set up task scheduler and pull for threaded evaluation. */
TaskScheduler *task_scheduler;
@@ -286,7 +311,7 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
/* Prepare all nodes for evaluation. */
initialize_execution(&state, graph);
/* Do actual evaluation now. */
- schedule_graph(task_pool, graph, layers);
+ schedule_graph(task_pool, graph);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
/* Finalize statistics gathering. This is because we only gather single
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
index 49c0379939e..a8f5f7c145f 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -32,8 +32,6 @@
#pragma once
-struct EvaluationContext;
-
namespace DEG {
struct Depsgraph;
@@ -45,8 +43,6 @@ struct Depsgraph;
*
* \note Time sources should be all valid!
*/
-void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
- Depsgraph *graph,
- const unsigned int layers);
+void deg_evaluate_on_refresh(Depsgraph *graph);
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
new file mode 100644
index 00000000000..89d3740c43e
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -0,0 +1,1151 @@
+/*
+ * ***** 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) 20137Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+/** \file blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+ * \ingroup depsgraph
+ */
+
+/* Enable special; trickery to treat nested owned IDs (such as nodetree of
+ * material) to be handled in same way as "real" datablocks, even tho some
+ * internal BKE routines doesn't treat them like that.
+ *
+ * TODO(sergey): Re-evaluate that after new ID handling is in place.
+ */
+#define NESTED_ID_NASTY_WORKAROUND
+
+/* Silence warnings from copying deprecated fields. */
+#define DNA_DEPRECATED_ALLOW
+
+#include "intern/eval/deg_eval_copy_on_write.h"
+
+#include <cstring>
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
+#include "BLI_string.h"
+
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "DNA_ID.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+
+#include "DRW_engine.h"
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+# include "DNA_curve_types.h"
+# include "DNA_key_types.h"
+# include "DNA_lamp_types.h"
+# include "DNA_lattice_types.h"
+# include "DNA_linestyle_types.h"
+# include "DNA_material_types.h"
+# include "DNA_meta_types.h"
+# include "DNA_node_types.h"
+# include "DNA_texture_types.h"
+# include "DNA_world_types.h"
+#endif
+
+#include "BKE_action.h"
+#include "BKE_animsys.h"
+#include "BKE_armature.h"
+#include "BKE_editmesh.h"
+#include "BKE_library_query.h"
+#include "BKE_object.h"
+}
+
+#include "intern/depsgraph.h"
+#include "intern/builder/deg_builder_nodes.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_id.h"
+
+namespace DEG {
+
+#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf
+
+namespace {
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+union NestedIDHackTempStorage {
+ Curve curve;
+ FreestyleLineStyle linestyle;
+ Lamp lamp;
+ Lattice lattice;
+ Material material;
+ Mesh mesh;
+ Scene scene;
+ Tex tex;
+ World world;
+};
+
+/* Set nested owned ID pointers to NULL. */
+void nested_id_hack_discard_pointers(ID *id_cow)
+{
+ switch (GS(id_cow->name)) {
+# define SPECIAL_CASE(id_type, dna_type, field) \
+ case id_type: \
+ { \
+ ((dna_type *)id_cow)->field = NULL; \
+ break; \
+ }
+
+ SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree)
+ SPECIAL_CASE(ID_LA, Lamp, nodetree)
+ SPECIAL_CASE(ID_MA, Material, nodetree)
+ SPECIAL_CASE(ID_TE, Tex, nodetree)
+ SPECIAL_CASE(ID_WO, World, nodetree)
+
+ SPECIAL_CASE(ID_CU, Curve, key)
+ SPECIAL_CASE(ID_LT, Lattice, key)
+ SPECIAL_CASE(ID_ME, Mesh, key)
+
+ case ID_SCE:
+ {
+ Scene *scene_cow = (Scene *)id_cow;
+ /* Node trees always have their own ID node in the graph, and are
+ * being copied as part of their copy-on-write process. */
+ scene_cow->nodetree = NULL;
+ /* Tool settings pointer is shared with the original scene. */
+ scene_cow->toolsettings = NULL;
+ break;
+ }
+
+ case ID_OB:
+ {
+ /* Clear the ParticleSettings pointer to prevent doubly-freeing it. */
+ Object *ob = (Object *)id_cow;
+ LISTBASE_FOREACH(ParticleSystem *, psys, &ob->particlesystem) {
+ psys->part = NULL;
+ }
+ break;
+ }
+# undef SPECIAL_CASE
+
+ default:
+ break;
+ }
+}
+
+/* Set ID pointer of nested owned IDs (nodetree, key) to NULL.
+ *
+ * Return pointer to a new ID to be used.
+ */
+const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage,
+ const ID *id)
+{
+ switch (GS(id->name)) {
+# define SPECIAL_CASE(id_type, dna_type, field, variable) \
+ case id_type: \
+ { \
+ storage->variable = *(dna_type *)id; \
+ storage->variable.field = NULL; \
+ return &storage->variable.id; \
+ }
+
+ SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree, linestyle)
+ SPECIAL_CASE(ID_LA, Lamp, nodetree, lamp)
+ SPECIAL_CASE(ID_MA, Material, nodetree, material)
+ SPECIAL_CASE(ID_TE, Tex, nodetree, tex)
+ SPECIAL_CASE(ID_WO, World, nodetree, world)
+
+ SPECIAL_CASE(ID_CU, Curve, key, curve)
+ SPECIAL_CASE(ID_LT, Lattice, key, lattice)
+ SPECIAL_CASE(ID_ME, Mesh, key, mesh)
+
+ case ID_SCE:
+ {
+ storage->scene = *(Scene *)id;
+ storage->scene.toolsettings = NULL;
+ storage->scene.nodetree = NULL;
+ return &storage->scene.id;
+ }
+
+# undef SPECIAL_CASE
+
+ default:
+ break;
+ }
+ return id;
+}
+
+/* Set ID pointer of nested owned IDs (nodetree, key) to the original value. */
+void nested_id_hack_restore_pointers(const ID *old_id, ID *new_id)
+{
+ if (new_id == NULL) {
+ return;
+ }
+ switch (GS(old_id->name)) {
+# define SPECIAL_CASE(id_type, dna_type, field) \
+ case id_type: \
+ { \
+ ((dna_type *)(new_id))->field = \
+ ((dna_type *)(old_id))->field; \
+ break; \
+ }
+
+ SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree)
+ SPECIAL_CASE(ID_LA, Lamp, nodetree)
+ SPECIAL_CASE(ID_MA, Material, nodetree)
+ SPECIAL_CASE(ID_SCE, Scene, nodetree)
+ SPECIAL_CASE(ID_TE, Tex, nodetree)
+ SPECIAL_CASE(ID_WO, World, nodetree)
+
+ SPECIAL_CASE(ID_CU, Curve, key)
+ SPECIAL_CASE(ID_LT, Lattice, key)
+ SPECIAL_CASE(ID_ME, Mesh, key)
+
+#undef SPECIAL_CASE
+ default:
+ break;
+ }
+}
+
+/* Remap pointer of nested owned IDs (nodetree. key) to the new ID values. */
+void ntree_hack_remap_pointers(const Depsgraph *depsgraph, ID *id_cow)
+{
+ switch (GS(id_cow->name)) {
+# define SPECIAL_CASE(id_type, dna_type, field, field_type) \
+ case id_type: \
+ { \
+ dna_type *data = (dna_type *)id_cow; \
+ if (data->field != NULL) { \
+ ID *ntree_id_cow = depsgraph->get_cow_id(&data->field->id); \
+ if (ntree_id_cow != NULL) { \
+ DEG_COW_PRINT(" Remapping datablock for %s: id_orig=%p id_cow=%p\n", \
+ data->field->id.name, \
+ data->field, \
+ ntree_id_cow); \
+ data->field = (field_type *)ntree_id_cow; \
+ } \
+ } \
+ break; \
+ }
+
+ SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree, bNodeTree)
+ SPECIAL_CASE(ID_LA, Lamp, nodetree, bNodeTree)
+ SPECIAL_CASE(ID_MA, Material, nodetree, bNodeTree)
+ SPECIAL_CASE(ID_SCE, Scene, nodetree, bNodeTree)
+ SPECIAL_CASE(ID_TE, Tex, nodetree, bNodeTree)
+ SPECIAL_CASE(ID_WO, World, nodetree, bNodeTree)
+
+ SPECIAL_CASE(ID_CU, Curve, key, Key)
+ SPECIAL_CASE(ID_LT, Lattice, key, Key)
+ SPECIAL_CASE(ID_ME, Mesh, key, Key)
+
+#undef SPECIAL_CASE
+ default:
+ break;
+ }
+}
+#endif /* NODETREE_NASTY_WORKAROUND */
+
+struct ValidateData {
+ bool is_valid;
+};
+
+/* Similar to generic id_copy() but does not require main and assumes pointer
+ * is already allocated,
+ */
+bool id_copy_inplace_no_main(const ID *id, ID *newid)
+{
+ const ID *id_for_copy = id;
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ NestedIDHackTempStorage id_hack_storage;
+ id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage, id);
+#endif
+
+ bool result = BKE_id_copy_ex(NULL,
+ (ID *)id_for_copy,
+ &newid,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_ALLOCATE |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_CACHES),
+ false);
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ if (result) {
+ nested_id_hack_restore_pointers(id, newid);
+ }
+#endif
+
+ return result;
+}
+
+/* Similar to BKE_scene_copy() but does not require main and assumes pointer
+ * is already allocated.
+ */
+bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene)
+{
+ const ID *id_for_copy = &scene->id;
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ NestedIDHackTempStorage id_hack_storage;
+ id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage,
+ &scene->id);
+#endif
+
+ bool result = BKE_id_copy_ex(NULL,
+ id_for_copy,
+ (ID **)&new_scene,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_ALLOCATE |
+ LIB_ID_CREATE_NO_DEG_TAG,
+ false);
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ if (result) {
+ nested_id_hack_restore_pointers(&scene->id, &new_scene->id);
+ }
+#endif
+
+ return result;
+}
+
+/* Remove all view layers but the one which corresponds to an input one. */
+void scene_remove_unused_view_layers(const Depsgraph *depsgraph,
+ Scene *scene_cow)
+{
+ ViewLayer *view_layer_input = depsgraph->view_layer;
+ ViewLayer *view_layer_eval = NULL;
+ /* Find evaluated view layer. At the same time we free memory used by
+ * all other of the view layers. */
+ for (ViewLayer *view_layer_cow =
+ reinterpret_cast<ViewLayer *>(scene_cow->view_layers.first),
+ *view_layer_next;
+ view_layer_cow != NULL;
+ view_layer_cow = view_layer_next)
+ {
+ view_layer_next = view_layer_cow->next;
+ if (STREQ(view_layer_input->name, view_layer_cow->name)) {
+ view_layer_eval = view_layer_cow;
+ }
+ else {
+ BKE_view_layer_free_ex(view_layer_cow, false);
+ }
+ }
+ BLI_assert(view_layer_eval != NULL);
+ /* Make evaluated view layer the only one in the evaluated scene. */
+ view_layer_eval->prev = view_layer_eval->next = NULL;
+ scene_cow->view_layers.first = view_layer_eval;
+ scene_cow->view_layers.last = view_layer_eval;
+}
+
+/* Makes it so given view layer only has bases corresponding to a visible
+ * objects. */
+void view_layer_remove_invisible_bases(const Depsgraph *depsgraph,
+ ViewLayer *view_layer)
+{
+ const int base_visible_flag = (depsgraph->mode == DAG_EVAL_VIEWPORT) ?
+ BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER;
+ ListBase visible_bases = {NULL, NULL};
+ for (Base *base = reinterpret_cast<Base *>(view_layer->object_bases.first),
+ *base_next;
+ base != NULL;
+ base = base_next)
+ {
+ base_next = base->next;
+ const bool is_object_visible = (base->flag & base_visible_flag);
+ if (is_object_visible) {
+ BLI_addtail(&visible_bases, base);
+ }
+ else {
+ if (base == view_layer->basact) {
+ view_layer->basact = NULL;
+ }
+ MEM_freeN(base);
+ }
+ }
+ view_layer->object_bases = visible_bases;
+}
+
+void scene_cleanup_view_layers(const Depsgraph *depsgraph, Scene *scene_cow)
+{
+ scene_remove_unused_view_layers(depsgraph, scene_cow);
+ view_layer_remove_invisible_bases(
+ depsgraph,
+ reinterpret_cast<ViewLayer *>(scene_cow->view_layers.first));
+ /* TODO(sergey): Remove objects from collections as well.
+ * Not a HUGE deal for now, nobody is looking into those CURRENTLY.
+ * Still not an excuse to have those. */
+}
+
+/* Check whether given ID is expanded or still a shallow copy. */
+BLI_INLINE bool check_datablock_expanded(const ID *id_cow)
+{
+ return (id_cow->name[0] != '\0');
+}
+
+/* Those are datablocks which are not covered by dependency graph and hence
+ * does not need any remapping or anything.
+ *
+ * TODO(sergey): How to make it more robust for the future, so we don't have
+ * to maintain exception lists all over the code?
+ */
+bool check_datablocks_copy_on_writable(const ID *id_orig)
+{
+ const ID_Type id_type = GS(id_orig->name);
+ /* We shouldn't bother if copied ID is same as original one. */
+ if (!deg_copy_on_write_is_needed(id_orig)) {
+ return false;
+ }
+ return !ELEM(id_type, ID_BR,
+ ID_LS,
+ ID_PAL);
+}
+
+/* Callback for BKE_library_foreach_ID_link which remaps original ID pointer
+ * with the one created by CoW system.
+ */
+
+struct RemapCallbackUserData {
+ /* Dependency graph for which remapping is happening. */
+ const Depsgraph *depsgraph;
+ /* Create placeholder for ID nodes for cases when we need to remap original
+ * ID to it[s CoW version but we don't have required ID node yet.
+ *
+ * This happens when expansion happens a ta construction time.
+ */
+ DepsgraphNodeBuilder *node_builder;
+ bool create_placeholders;
+};
+
+int foreach_libblock_remap_callback(void *user_data_v,
+ ID *id_self,
+ ID **id_p,
+ int /*cb_flag*/)
+{
+ if (*id_p == NULL) {
+ return IDWALK_RET_NOP;
+ }
+ RemapCallbackUserData *user_data = (RemapCallbackUserData *)user_data_v;
+ const Depsgraph *depsgraph = user_data->depsgraph;
+ ID *id_orig = *id_p;
+ if (check_datablocks_copy_on_writable(id_orig)) {
+ ID *id_cow;
+ if (user_data->create_placeholders) {
+ /* Special workaround to stop creating temp datablocks for
+ * objects which are coming from scene's collection and which
+ * are never linked to any of layers.
+ *
+ * TODO(sergey): Ideally we need to tell ID looper to ignore
+ * those or at least make it more reliable check where the
+ * pointer is coming from.
+ */
+ const ID_Type id_type = GS(id_orig->name);
+ const ID_Type id_type_self = GS(id_self->name);
+ if (id_type == ID_OB && id_type_self == ID_SCE) {
+ IDDepsNode *id_node = depsgraph->find_id_node(id_orig);
+ if (id_node == NULL) {
+ id_cow = id_orig;
+ }
+ else {
+ id_cow = id_node->id_cow;
+ }
+ }
+ else {
+ id_cow = user_data->node_builder->ensure_cow_id(id_orig);
+ }
+ }
+ else {
+ id_cow = depsgraph->get_cow_id(id_orig);
+ }
+ BLI_assert(id_cow != NULL);
+ DEG_COW_PRINT(" Remapping datablock for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+ *id_p = id_cow;
+ }
+ return IDWALK_RET_NOP;
+}
+
+void update_armature_edit_mode_pointers(const Depsgraph * /*depsgraph*/,
+ const ID *id_orig, ID *id_cow)
+{
+ const bArmature *armature_orig = (const bArmature *)id_orig;
+ bArmature *armature_cow = (bArmature *)id_cow;
+ armature_cow->edbo = armature_orig->edbo;
+}
+
+void update_curve_edit_mode_pointers(const Depsgraph * /*depsgraph*/,
+ const ID *id_orig, ID *id_cow)
+{
+ const Curve *curve_orig = (const Curve *)id_orig;
+ Curve *curve_cow = (Curve *)id_cow;
+ curve_cow->editnurb = curve_orig->editnurb;
+ curve_cow->editfont = curve_orig->editfont;
+}
+
+void update_mball_edit_mode_pointers(const Depsgraph * /*depsgraph*/,
+ const ID *id_orig, ID *id_cow)
+{
+ const MetaBall *mball_orig = (const MetaBall *)id_orig;
+ MetaBall *mball_cow = (MetaBall *)id_cow;
+ mball_cow->editelems = mball_orig->editelems;
+}
+
+void update_lattice_edit_mode_pointers(const Depsgraph * /*depsgraph*/,
+ const ID *id_orig, ID *id_cow)
+{
+ const Lattice *lt_orig = (const Lattice *)id_orig;
+ Lattice *lt_cow = (Lattice *)id_cow;
+ lt_cow->editlatt = lt_orig->editlatt;
+}
+
+void update_mesh_edit_mode_pointers(const Depsgraph *depsgraph,
+ const ID *id_orig, ID *id_cow)
+{
+ /* For meshes we need to update edit_btmesh to make it to point
+ * to the CoW version of object.
+ *
+ * This is kind of confusing, because actual bmesh is not owned by
+ * the CoW object, so need to be accurate about using link from
+ * edit_btmesh to object.
+ */
+ const Mesh *mesh_orig = (const Mesh *)id_orig;
+ Mesh *mesh_cow = (Mesh *)id_cow;
+ if (mesh_orig->edit_btmesh == NULL) {
+ return;
+ }
+ mesh_cow->edit_btmesh = (BMEditMesh *)MEM_dupallocN(mesh_orig->edit_btmesh);
+ mesh_cow->edit_btmesh->ob =
+ (Object *)depsgraph->get_cow_id(&mesh_orig->edit_btmesh->ob->id);
+ mesh_cow->edit_btmesh->mesh_eval_cage = NULL;
+ mesh_cow->edit_btmesh->mesh_eval_final = NULL;
+}
+
+/* Edit data is stored and owned by original datablocks, copied ones
+ * are simply referencing to them.
+ */
+void update_edit_mode_pointers(const Depsgraph *depsgraph,
+ const ID *id_orig, ID *id_cow)
+{
+ const ID_Type type = GS(id_orig->name);
+ switch (type) {
+ case ID_AR:
+ update_armature_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ break;
+ case ID_ME:
+ update_mesh_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ break;
+ case ID_CU:
+ update_curve_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ break;
+ case ID_MB:
+ update_mball_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ break;
+ case ID_LT:
+ update_lattice_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ break;
+ default:
+ break;
+ }
+}
+
+void update_particle_system_orig_pointers(const Object *object_orig,
+ Object *object_cow)
+{
+ ParticleSystem *psys_cow =
+ (ParticleSystem *) object_cow->particlesystem.first;
+ ParticleSystem *psys_orig =
+ (ParticleSystem *) object_orig->particlesystem.first;
+ while (psys_orig != NULL) {
+ psys_cow->orig_psys = psys_orig;
+ psys_cow = psys_cow->next;
+ psys_orig = psys_orig->next;
+ }
+}
+
+void update_pose_orig_pointers(const bPose *pose_orig, bPose *pose_cow)
+{
+ bPoseChannel *pchan_cow = (bPoseChannel *) pose_cow->chanbase.first;
+ bPoseChannel *pchan_orig = (bPoseChannel *) pose_orig->chanbase.first;
+ while (pchan_orig != NULL) {
+ pchan_cow->orig_pchan = pchan_orig;
+ pchan_cow = pchan_cow->next;
+ pchan_orig = pchan_orig->next;
+ }
+}
+
+/* Do some special treatment of data transfer from original ID to it's
+ * CoW complementary part.
+ *
+ * Only use for the newly created CoW datablocks.
+ */
+void update_special_pointers(const Depsgraph *depsgraph,
+ const ID *id_orig, ID *id_cow)
+{
+ const ID_Type type = GS(id_orig->name);
+ switch (type) {
+ case ID_OB:
+ {
+ /* Ensure we don't drag someone's else derived mesh to the
+ * new copy of the object.
+ */
+ Object *object_cow = (Object *)id_cow;
+ const Object *object_orig = (const Object *)id_orig;
+ object_cow->mode = object_orig->mode;
+ object_cow->sculpt = object_orig->sculpt;
+ if (object_cow->type == OB_MESH) {
+ object_cow->runtime.mesh_orig = (Mesh *)object_cow->data;
+ }
+ if (object_cow->type == OB_ARMATURE) {
+ const bArmature *armature_orig = (bArmature *)object_orig->data;
+ bArmature *armature_cow = (bArmature *)object_cow->data;
+ BKE_pose_remap_bone_pointers(armature_cow, object_cow->pose);
+ if (armature_orig->edbo == NULL) {
+ update_pose_orig_pointers(object_orig->pose,
+ object_cow->pose);
+ }
+ }
+ update_particle_system_orig_pointers(object_orig, object_cow);
+ break;
+ }
+ case ID_SCE:
+ {
+ Scene *scene_cow = (Scene *)id_cow;
+ const Scene *scene_orig = (const Scene *)id_orig;
+ scene_cow->toolsettings = scene_orig->toolsettings;
+ scene_cow->eevee.light_cache = scene_orig->eevee.light_cache;
+ break;
+ }
+ default:
+ break;
+ }
+ update_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ BKE_animsys_update_driver_array(id_cow);
+}
+
+/* This callback is used to validate that all nested ID datablocks are
+ * properly expanded.
+ */
+int foreach_libblock_validate_callback(void *user_data,
+ ID * /*id_self*/,
+ ID **id_p,
+ int /*cb_flag*/)
+{
+ ValidateData *data = (ValidateData *)user_data;
+ if (*id_p != NULL) {
+ if (!check_datablock_expanded(*id_p)) {
+ data->is_valid = false;
+ /* TODO(sergey): Store which is is not valid? */
+ }
+ }
+ return IDWALK_RET_NOP;
+}
+
+} // namespace
+
+/* Actual implementation of logic which "expands" all the data which was not
+ * yet copied-on-write.
+ *
+ * NOTE: Expects that CoW datablock is empty.
+ */
+ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
+ const IDDepsNode *id_node,
+ DepsgraphNodeBuilder *node_builder,
+ bool create_placeholders)
+{
+ const ID *id_orig = id_node->id_orig;
+ ID *id_cow = id_node->id_cow;
+ const int id_cow_recalc = id_cow->recalc;
+ /* No need to expand such datablocks, their copied ID is same as original
+ * one already.
+ */
+ if (!deg_copy_on_write_is_needed(id_orig)) {
+ return id_cow;
+ }
+ DEG_COW_PRINT("Expanding datablock for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+ /* Sanity checks. */
+ /* NOTE: Disabled for now, conflicts when re-using evaluated datablock when
+ * rebuilding dependencies.
+ */
+ if (check_datablock_expanded(id_cow) && create_placeholders) {
+ deg_free_copy_on_write_datablock(id_cow);
+ }
+ // BLI_assert(check_datablock_expanded(id_cow) == false);
+ /* Copy data from original ID to a copied version. */
+ /* TODO(sergey): Avoid doing full ID copy somehow, make Mesh to reference
+ * original geometry arrays for until those are modified.
+ */
+ /* TODO(sergey): We do some trickery with temp bmain and extra ID pointer
+ * just to be able to use existing API. Ideally we need to replace this with
+ * in-place copy from existing datablock to a prepared memory.
+ *
+ * NOTE: We don't use BKE_main_{new,free} because:
+ * - We don't want heap-allocations here.
+ * - We don't want bmain's content to be freed when main is freed.
+ */
+ bool done = false;
+ /* First we handle special cases which are not covered by id_copy() yet.
+ * or cases where we want to do something smarter than simple datablock
+ * copy.
+ */
+ const ID_Type id_type = GS(id_orig->name);
+ switch (id_type) {
+ case ID_SCE:
+ {
+ done = scene_copy_inplace_no_main((Scene *)id_orig, (Scene *)id_cow);
+ if (done) {
+ scene_cleanup_view_layers(depsgraph, (Scene *)id_cow);
+ }
+ break;
+ }
+ case ID_ME:
+ {
+ /* TODO(sergey): Ideally we want to handle meshes in a special
+ * manner here to avoid initial copy of all the geometry arrays.
+ */
+ break;
+ }
+ default:
+ break;
+ }
+ if (!done) {
+ done = id_copy_inplace_no_main(id_orig, id_cow);
+ }
+ if (!done) {
+ BLI_assert(!"No idea how to perform CoW on datablock");
+ }
+ /* Update pointers to nested ID datablocks. */
+ DEG_COW_PRINT(" Remapping ID links for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ ntree_hack_remap_pointers(depsgraph, id_cow);
+#endif
+ /* Do it now, so remapping will understand that possibly remapped self ID
+ * is not to be remapped again.
+ */
+ deg_tag_copy_on_write_id(id_cow, id_orig);
+ /* Perform remapping of the nodes. */
+ RemapCallbackUserData user_data = {NULL};
+ user_data.depsgraph = depsgraph;
+ user_data.node_builder = node_builder;
+ user_data.create_placeholders = create_placeholders;
+ BKE_library_foreach_ID_link(NULL,
+ id_cow,
+ foreach_libblock_remap_callback,
+ (void *)&user_data,
+ IDWALK_NOP);
+ /* Correct or tweak some pointers which are not taken care by foreach
+ * from above.
+ */
+ update_special_pointers(depsgraph, id_orig, id_cow);
+ id_cow->recalc = id_orig->recalc | id_cow_recalc;
+ return id_cow;
+}
+
+/* NOTE: Depsgraph is supposed to have ID node already. */
+ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
+ ID *id_orig,
+ DepsgraphNodeBuilder *node_builder,
+ bool create_placeholders)
+{
+ DEG::IDDepsNode *id_node = depsgraph->find_id_node(id_orig);
+ BLI_assert(id_node != NULL);
+ return deg_expand_copy_on_write_datablock(depsgraph,
+ id_node,
+ node_builder,
+ create_placeholders);
+}
+
+static void deg_update_copy_on_write_animation(const Depsgraph *depsgraph,
+ const IDDepsNode *id_node)
+{
+ DEG_debug_print_eval((::Depsgraph *)depsgraph,
+ __func__,
+ id_node->id_orig->name,
+ id_node->id_cow);
+ BKE_animdata_copy_id(NULL, id_node->id_cow, id_node->id_orig, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ RemapCallbackUserData user_data = {NULL};
+ user_data.depsgraph = depsgraph;
+ BKE_library_foreach_ID_link(NULL,
+ id_node->id_cow,
+ foreach_libblock_remap_callback,
+ (void *)&user_data,
+ IDWALK_NOP);
+}
+
+typedef struct ObjectRuntimeBackup {
+ Object_Runtime runtime;
+ short base_flag;
+ CustomDataMask lastDataMask;
+} ObjectRuntimeBackup;
+
+/* Make a backup of object's evaluation runtime data, additionally
+ * make object to be safe for free without invalidating backed up
+ * pointers.
+ */
+static void deg_backup_object_runtime(
+ Object *object,
+ ObjectRuntimeBackup *object_runtime_backup)
+{
+ /* Store evaluated mesh and curve_cache, and make sure we don't free it. */
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ object_runtime_backup->runtime = object->runtime;
+ BKE_object_runtime_reset(object);
+ /* Object update will override actual object->data to an evaluated version.
+ * Need to make sure we don't have data set to evaluated one before free
+ * anything.
+ */
+ if (mesh_eval != NULL && object->data == mesh_eval) {
+ object->data = object->runtime.mesh_orig;
+ }
+ /* Make a backup of base flags. */
+ object_runtime_backup->base_flag = object->base_flag;
+ object_runtime_backup->lastDataMask = object->lastDataMask;
+}
+
+static void deg_restore_object_runtime(
+ Object *object,
+ const ObjectRuntimeBackup *object_runtime_backup)
+{
+ Mesh *mesh_orig = object->runtime.mesh_orig;
+ object->runtime = object_runtime_backup->runtime;
+ object->runtime.mesh_orig = mesh_orig;
+ if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) {
+ if (object->id.recalc & ID_RECALC_GEOMETRY) {
+ /* If geometry is tagged for update it means, that part of
+ * evaluated mesh are not valid anymore. In this case we can not
+ * have any "persistent" pointers to point to an invalid data.
+ *
+ * We restore object's data datablock to an original copy of
+ * that datablock.
+ */
+ object->data = mesh_orig;
+ }
+ else {
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ /* Do same thing as object update: override actual object data
+ * pointer with evaluated datablock.
+ */
+ object->data = mesh_eval;
+ /* Evaluated mesh simply copied edit_btmesh pointer from
+ * original mesh during update, need to make sure no dead
+ * pointers are left behind.
+ */
+ mesh_eval->edit_btmesh = mesh_orig->edit_btmesh;
+ }
+ }
+ object->base_flag = object_runtime_backup->base_flag;
+ object->lastDataMask = object_runtime_backup->lastDataMask;
+}
+
+ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
+ const IDDepsNode *id_node)
+{
+ const ID *id_orig = id_node->id_orig;
+ const ID_Type id_type = GS(id_orig->name);
+ ID *id_cow = id_node->id_cow;
+ /* Similar to expansion, no need to do anything here. */
+ if (!deg_copy_on_write_is_needed(id_orig)) {
+ return id_cow;
+ }
+ /* For the rest if datablock types we use simple logic:
+ * - Free previously expanded data, if any.
+ * - Perform full datablock copy.
+ *
+ * Note that we never free GPU materials from here since that's not
+ * safe for threading and GPU materials are likely to be re-used.
+ */
+ /* TODO(sergey): Either move this to an utility function or redesign
+ * Copy-on-Write components in a way that only needed parts are being
+ * copied over.
+ */
+ /* TODO(sergey): Wrap GPU material backup and object runtime backup to a
+ * generic backup structure.
+ */
+ ListBase gpumaterial_backup;
+ ListBase *gpumaterial_ptr = NULL;
+ DrawDataList drawdata_backup;
+ DrawDataList *drawdata_ptr = NULL;
+ ObjectRuntimeBackup object_runtime_backup = {{NULL}};
+ if (check_datablock_expanded(id_cow)) {
+ switch (id_type) {
+ case ID_MA:
+ {
+ Material *material = (Material *)id_cow;
+ gpumaterial_ptr = &material->gpumaterial;
+ break;
+ }
+ case ID_WO:
+ {
+ World *world = (World *)id_cow;
+ gpumaterial_ptr = &world->gpumaterial;
+ break;
+ }
+ case ID_NT:
+ {
+ /* Node trees should try to preserve their socket pointers
+ * as much as possible. This is due to UBOs code in GPU,
+ * which references sockets from trees.
+ *
+ * These flags CURRENTLY don't need full datablock update,
+ * everything is done by node tree update function which
+ * only copies socket values.
+ */
+ const int ignore_flag = (ID_RECALC_DRAW |
+ ID_RECALC_ANIMATION |
+ ID_RECALC_COPY_ON_WRITE);
+ if ((id_cow->recalc & ~ignore_flag) == 0) {
+ deg_update_copy_on_write_animation(depsgraph, id_node);
+ return id_cow;
+ }
+ break;
+ }
+ case ID_OB:
+ {
+ Object *ob = (Object *)id_cow;
+ deg_backup_object_runtime(ob, &object_runtime_backup);
+ break;
+ }
+ default:
+ break;
+ }
+ if (gpumaterial_ptr != NULL) {
+ gpumaterial_backup = *gpumaterial_ptr;
+ gpumaterial_ptr->first = gpumaterial_ptr->last = NULL;
+ }
+ drawdata_ptr = DRW_drawdatalist_from_id(id_cow);
+ if (drawdata_ptr != NULL) {
+ drawdata_backup = *drawdata_ptr;
+ drawdata_ptr->first = drawdata_ptr->last = NULL;
+ }
+ }
+ deg_free_copy_on_write_datablock(id_cow);
+ deg_expand_copy_on_write_datablock(depsgraph, id_node);
+ /* Restore GPU materials. */
+ if (gpumaterial_ptr != NULL) {
+ *gpumaterial_ptr = gpumaterial_backup;
+ }
+ /* Restore DrawData. */
+ if (drawdata_ptr != NULL) {
+ *drawdata_ptr = drawdata_backup;
+ }
+ if (id_type == ID_OB) {
+ deg_restore_object_runtime((Object *)id_cow, &object_runtime_backup);
+ }
+ return id_cow;
+}
+
+/* NOTE: Depsgraph is supposed to have ID node already. */
+ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
+ ID *id_orig)
+{
+ DEG::IDDepsNode *id_node = depsgraph->find_id_node(id_orig);
+ BLI_assert(id_node != NULL);
+ return deg_update_copy_on_write_datablock(depsgraph, id_node);
+}
+
+namespace {
+
+void discard_armature_edit_mode_pointers(ID *id_cow)
+{
+ bArmature *armature_cow = (bArmature *)id_cow;
+ armature_cow->edbo = NULL;
+}
+
+void discard_curve_edit_mode_pointers(ID *id_cow)
+{
+ Curve *curve_cow = (Curve *)id_cow;
+ curve_cow->editnurb = NULL;
+ curve_cow->editfont = NULL;
+}
+
+void discard_mball_edit_mode_pointers(ID *id_cow)
+{
+ MetaBall *mball_cow = (MetaBall *)id_cow;
+ mball_cow->editelems = NULL;
+}
+
+void discard_lattice_edit_mode_pointers(ID *id_cow)
+{
+ Lattice *lt_cow = (Lattice *)id_cow;
+ lt_cow->editlatt = NULL;
+}
+
+void discard_mesh_edit_mode_pointers(ID *id_cow)
+{
+ Mesh *mesh_cow = (Mesh *)id_cow;
+ if (mesh_cow->edit_btmesh == NULL) {
+ return;
+ }
+ BKE_editmesh_free_derivedmesh(mesh_cow->edit_btmesh);
+ MEM_freeN(mesh_cow->edit_btmesh);
+ mesh_cow->edit_btmesh = NULL;
+}
+
+void discard_scene_pointers(ID *id_cow)
+{
+ Scene *scene_cow = (Scene *)id_cow;
+ scene_cow->toolsettings = NULL;
+ scene_cow->eevee.light_cache = NULL;
+}
+
+/* NULL-ify all edit mode pointers which points to data from
+ * original object.
+ */
+void discard_edit_mode_pointers(ID *id_cow)
+{
+ const ID_Type type = GS(id_cow->name);
+ switch (type) {
+ case ID_AR:
+ discard_armature_edit_mode_pointers(id_cow);
+ break;
+ case ID_ME:
+ discard_mesh_edit_mode_pointers(id_cow);
+ break;
+ case ID_CU:
+ discard_curve_edit_mode_pointers(id_cow);
+ break;
+ case ID_MB:
+ discard_mball_edit_mode_pointers(id_cow);
+ break;
+ case ID_LT:
+ discard_lattice_edit_mode_pointers(id_cow);
+ break;
+ case ID_SCE:
+ /* Not really edit mode but still needs to run before
+ * BKE_libblock_free_datablock() */
+ discard_scene_pointers(id_cow);
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace
+
+/* Free content of the CoW datablock
+ * Notes:
+ * - Does not recurs into nested ID datablocks.
+ * - Does not free datablock itself.
+ */
+void deg_free_copy_on_write_datablock(ID *id_cow)
+{
+ if (!check_datablock_expanded(id_cow)) {
+ /* Actual content was never copied on top of CoW block, we have
+ * nothing to free.
+ */
+ return;
+ }
+ const ID_Type type = GS(id_cow->name);
+#ifdef NESTED_ID_NASTY_WORKAROUND
+ nested_id_hack_discard_pointers(id_cow);
+#endif
+ switch (type) {
+ case ID_OB:
+ {
+ /* TODO(sergey): This workaround is only to prevent free derived
+ * caches from modifying object->data. This is currently happening
+ * due to mesh/curve datablock boundbox tagging dirty.
+ */
+ Object *ob_cow = (Object *)id_cow;
+ ob_cow->data = NULL;
+ ob_cow->sculpt = NULL;
+ break;
+ }
+ default:
+ break;
+ }
+ discard_edit_mode_pointers(id_cow);
+ BKE_libblock_free_datablock(id_cow, 0);
+ BKE_libblock_free_data(id_cow, false);
+ /* Signal datablock as not being expanded. */
+ id_cow->name[0] = '\0';
+}
+
+void deg_evaluate_copy_on_write(struct ::Depsgraph *graph,
+ const IDDepsNode *id_node)
+{
+ const DEG::Depsgraph *depsgraph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ DEG_debug_print_eval(graph, __func__, id_node->id_orig->name, id_node->id_cow);
+ if (id_node->id_orig == &depsgraph->scene->id) {
+ /* NOTE: This is handled by eval_ctx setup routines, which
+ * ensures scene and view layer pointers are valid.
+ */
+ return;
+ }
+ deg_update_copy_on_write_datablock(depsgraph, id_node);
+}
+
+bool deg_validate_copy_on_write_datablock(ID *id_cow)
+{
+ if (id_cow == NULL) {
+ return false;
+ }
+ ValidateData data;
+ data.is_valid = true;
+ BKE_library_foreach_ID_link(NULL,
+ id_cow,
+ foreach_libblock_validate_callback,
+ &data,
+ IDWALK_NOP);
+ return data.is_valid;
+}
+
+void deg_tag_copy_on_write_id(ID *id_cow, const ID *id_orig)
+{
+ BLI_assert(id_cow != id_orig);
+ BLI_assert((id_orig->tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ id_cow->tag |= LIB_TAG_COPIED_ON_WRITE;
+ /* This ID is no longer localized, is a self-sustaining copy now. */
+ id_cow->tag &= ~LIB_TAG_LOCALIZED;
+ id_cow->orig_id = (ID *)id_orig;
+}
+
+bool deg_copy_on_write_is_expanded(const ID *id_cow)
+{
+ return check_datablock_expanded(id_cow);
+}
+
+bool deg_copy_on_write_is_needed(const ID *id_orig)
+{
+ const ID_Type id_type = GS(id_orig->name);
+ return !ELEM(id_type, ID_IM);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
new file mode 100644
index 00000000000..e9f5bc1e918
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
@@ -0,0 +1,109 @@
+/*
+ * ***** 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) 20137Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_copy_on_write.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+struct ID;
+
+/* Uncomment this to have verbose log about original and CoW pointers
+ * logged, with detailed information when they are allocated, expanded
+ * and remapped.
+ */
+// #define DEG_DEBUG_COW_POINTERS
+
+#ifdef DEG_DEBUG_COW_POINTERS
+# define DEG_COW_PRINT(format, ...) printf(format, __VA_ARGS__);
+#else
+# define DEG_COW_PRINT(format, ...)
+#endif
+
+struct Depsgraph;
+
+namespace DEG {
+
+struct Depsgraph;
+struct DepsgraphNodeBuilder;
+struct IDDepsNode;
+
+/* Get fully expanded (ready for use) copy-on-write datablock for the given
+ * original datablock.
+ */
+ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph,
+ const IDDepsNode *id_node,
+ DepsgraphNodeBuilder *node_builder = NULL,
+ bool create_placeholders = false);
+ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph,
+ struct ID *id_orig,
+ DepsgraphNodeBuilder *node_builder = NULL,
+ bool create_placeholders = false);
+
+/* Makes sure given CoW datablock is brought back to state of the original
+ * datablock.
+ */
+ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph,
+ const IDDepsNode *id_node);
+ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph,
+ struct ID *id_orig);
+
+/* Helper function which frees memory used by copy-on-written databnlock. */
+void deg_free_copy_on_write_datablock(struct ID *id_cow);
+
+/* Callback function for depsgraph operation node which ensures copy-on-write
+ * datablock is ready for use by further evaluation routines.
+ */
+void deg_evaluate_copy_on_write(struct ::Depsgraph *depsgraph,
+ const struct IDDepsNode *id_node);
+
+/* Check that given ID is properly expanded and does not have any shallow
+ * copies inside.
+ */
+bool deg_validate_copy_on_write_datablock(ID *id_cow);
+
+/* Tag given ID block as being copy-on-wtritten. */
+void deg_tag_copy_on_write_id(struct ID *id_cow, const struct ID *id_orig);
+
+/* Check whether ID datablock is expanded.
+ *
+ * TODO(sergey): Make it an inline function or a macro.
+ */
+bool deg_copy_on_write_is_expanded(const struct ID *id_cow);
+
+/* Check whether copy-on-write datablock is needed for given ID.
+ *
+ * There are some exceptions on datablocks which are covered by dependency graph
+ * but which we don't want to start duplicating.
+ *
+ * This includes images.
+ */
+bool deg_copy_on_write_is_needed(const ID *id_orig);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index e7764cf5a27..61edc1e3795 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -34,13 +34,20 @@
// TODO(sergey): Use some sort of wrapper.
#include <deque>
+#include <cmath>
+
+#include "BKE_object.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_task.h"
#include "BLI_ghash.h"
extern "C" {
#include "DNA_object_types.h"
+
+#include "DRW_engine.h"
} /* extern "C" */
#include "DEG_depsgraph.h"
@@ -51,8 +58,20 @@ extern "C" {
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph_intern.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "util/deg_util_foreach.h"
+// Invalidate datablock data when update is flushed on it.
+//
+// The idea of this is to help catching cases when area is accessing data which
+// is not yet evaluated, which could happen due to missing relations. The issue
+// is that usually that data will be kept from previous frame, and it looks to
+// be plausible.
+//
+// This ensures that data does not look plausible, making it much easier to
+// catch usage of invalid state.
+#undef INVALIDATE_ON_FLUSH
+
namespace DEG {
enum {
@@ -70,19 +89,6 @@ typedef std::deque<OperationDepsNode *> FlushQueue;
namespace {
-// TODO(sergey): De-duplicate with depsgraph_tag,cc
-void lib_id_recalc_tag(Main *bmain, ID *id)
-{
- id->recalc |= ID_RECALC;
- DEG_id_type_tag(bmain, GS(id->name));
-}
-
-void lib_id_recalc_data_tag(Main *bmain, ID *id)
-{
- id->recalc |= ID_RECALC_DATA;
- DEG_id_type_tag(bmain, GS(id->name));
-}
-
void flush_init_operation_node_func(
void *__restrict data_v,
const int i,
@@ -100,9 +106,9 @@ void flush_init_id_node_func(
{
Depsgraph *graph = (Depsgraph *)data_v;
IDDepsNode *id_node = graph->id_nodes[i];
- id_node->done = ID_STATE_NONE;
+ id_node->custom_flags = ID_STATE_NONE;
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
- comp_node->done = COMPONENT_STATE_NONE;
+ comp_node->custom_flags = COMPONENT_STATE_NONE;
GHASH_FOREACH_END();
}
@@ -136,77 +142,50 @@ BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
{
queue->push_back(op_node);
op_node->scheduled = true;
+ DEG_DEBUG_PRINTF((::Depsgraph *)graph,
+ EVAL, "Operation is entry point for update: %s\n",
+ op_node->identifier().c_str());
}
GSET_FOREACH_END();
}
BLI_INLINE void flush_handle_id_node(IDDepsNode *id_node)
{
- id_node->done = ID_STATE_MODIFIED;
+ id_node->custom_flags = ID_STATE_MODIFIED;
}
/* TODO(sergey): We can reduce number of arguments here. */
-BLI_INLINE void flush_handle_component_node(Depsgraph * /*graph*/,
- IDDepsNode *id_node,
+BLI_INLINE void flush_handle_component_node(IDDepsNode *id_node,
ComponentDepsNode *comp_node,
FlushQueue *queue)
{
/* We only handle component once. */
- if (comp_node->done == COMPONENT_STATE_DONE) {
+ if (comp_node->custom_flags == COMPONENT_STATE_DONE) {
return;
}
- comp_node->done = COMPONENT_STATE_DONE;
+ comp_node->custom_flags = COMPONENT_STATE_DONE;
/* Tag all required operations in component for update. */
foreach (OperationDepsNode *op, comp_node->operations) {
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
- if (GS(id_node->id->name) == ID_OB) {
- Object *object = (Object *)id_node->id;
- /* This code is used to preserve those areas which does
- * direct object update,
+ /* We don't want to flush tags in "upstream" direction for
+ * certain types of operations.
*
- * Plus it ensures visibility changes and relations and
- * layers visibility update has proper flags to work with.
+ * TODO(sergey): Need a more generic solution for this.
*/
- switch (comp_node->type) {
- case DEG_NODE_TYPE_UNDEFINED:
- case DEG_NODE_TYPE_OPERATION:
- case DEG_NODE_TYPE_TIMESOURCE:
- case DEG_NODE_TYPE_ID_REF:
- case DEG_NODE_TYPE_SEQUENCER:
- case NUM_DEG_NODE_TYPES:
- /* Ignore, does not translate to object component. */
- BLI_assert(!"This should never happen!");
- break;
- case DEG_NODE_TYPE_ANIMATION:
- object->recalc |= OB_RECALC_TIME;
- break;
- case DEG_NODE_TYPE_TRANSFORM:
- object->recalc |= OB_RECALC_OB;
- break;
- case DEG_NODE_TYPE_GEOMETRY:
- case DEG_NODE_TYPE_EVAL_POSE:
- case DEG_NODE_TYPE_BONE:
- case DEG_NODE_TYPE_EVAL_PARTICLES:
- case DEG_NODE_TYPE_SHADING:
- case DEG_NODE_TYPE_CACHE:
- case DEG_NODE_TYPE_PROXY:
- object->recalc |= OB_RECALC_DATA;
- break;
- case DEG_NODE_TYPE_PARAMETERS:
- break;
+ if (op->opcode == DEG_OPCODE_PARTICLE_SETTINGS_EVAL) {
+ continue;
}
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
}
- /* When some target changes bone, we might need to re-run the
+ /* when some target changes bone, we might need to re-run the
* whole IK solver, otherwise result might be unpredictable.
*/
if (comp_node->type == DEG_NODE_TYPE_BONE) {
ComponentDepsNode *pose_comp =
id_node->find_component(DEG_NODE_TYPE_EVAL_POSE);
BLI_assert(pose_comp != NULL);
- if (pose_comp->done == COMPONENT_STATE_NONE) {
+ if (pose_comp->custom_flags == COMPONENT_STATE_NONE) {
queue->push_front(pose_comp->get_entry_operation());
- pose_comp->done = COMPONENT_STATE_SCHEDULED;
+ pose_comp->custom_flags = COMPONENT_STATE_SCHEDULED;
}
}
}
@@ -223,39 +202,166 @@ BLI_INLINE OperationDepsNode *flush_schedule_children(
{
OperationDepsNode *result = NULL;
foreach (DepsRelation *rel, op_node->outlinks) {
+ /* Flush is forbidden, completely. */
if (rel->flag & DEPSREL_FLAG_NO_FLUSH) {
continue;
}
+ /* Relation only allows flushes on user changes, but the node was not
+ * affected by user. */
+ if ((rel->flag & DEPSREL_FLAG_FLUSH_USER_EDIT_ONLY) &&
+ (op_node->flag & DEPSOP_FLAG_USER_MODIFIED) == 0)
+ {
+ continue;
+ }
OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
- if (to_node->scheduled == false) {
- if (result != NULL) {
- queue->push_front(to_node);
- }
- else {
- result = to_node;
- }
- to_node->scheduled = true;
+ /* Always flush flushable flags, so children always know what happened
+ * to their parents. */
+ to_node->flag |= (op_node->flag & DEPSOP_FLAG_FLUSH);
+ /* Flush update over the relation, if it was not flushed yet. */
+ if (to_node->scheduled) {
+ continue;
+ }
+ if (result != NULL) {
+ queue->push_front(to_node);
}
+ else {
+ result = to_node;
+ }
+ to_node->scheduled = true;
}
return result;
}
-BLI_INLINE void flush_editors_id_update(Main *bmain,
- Depsgraph *graph)
+void flush_engine_data_update(ID *id)
+{
+ DrawDataList *draw_data_list = DRW_drawdatalist_from_id(id);
+ if (draw_data_list == NULL) {
+ return;
+ }
+ LISTBASE_FOREACH(DrawData *, draw_data, draw_data_list) {
+ draw_data->recalc |= id->recalc;
+ }
+}
+
+/* NOTE: It will also accumulate flags from changed components. */
+void flush_editors_id_update(Main *bmain,
+ Depsgraph *graph,
+ const DEGEditorUpdateContext *update_ctx)
{
foreach (IDDepsNode *id_node, graph->id_nodes) {
- if (id_node->done != ID_STATE_MODIFIED) {
+ if (id_node->custom_flags != ID_STATE_MODIFIED) {
continue;
}
+ DEG_id_type_tag(bmain, GS(id_node->id_orig->name));
/* TODO(sergey): Do we need to pass original or evaluated ID here? */
- ID *id = id_node->id;
- deg_editors_id_update(bmain, id);
- lib_id_recalc_tag(bmain, id);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id);
+ ID *id_orig = id_node->id_orig;
+ ID *id_cow = id_node->id_cow;
+ /* Copy tag from original data to CoW storage.
+ * This is because DEG_id_tag_update() sets tags on original
+ * data.
+ */
+ id_cow->recalc |= (id_orig->recalc & ID_RECALC_ALL);
+ /* Gather recalc flags from all changed components. */
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ if (comp_node->custom_flags != COMPONENT_STATE_DONE) {
+ continue;
+ }
+ DepsNodeFactory *factory = deg_type_get_factory(comp_node->type);
+ BLI_assert(factory != NULL);
+ id_cow->recalc |= factory->id_recalc_tag();
+ }
+ GHASH_FOREACH_END();
+ DEG_DEBUG_PRINTF((::Depsgraph *)graph,
+ EVAL, "Accumulated recalc bits for %s: %u\n",
+ id_orig->name, (unsigned int)id_cow->recalc);
+
+ /* Inform editors. Only if the datablock is being evaluated a second
+ * time, to distinguish between user edits and initial evaluation when
+ * the datablock becomes visible.
+ *
+ * TODO: image datablocks do not use COW, so might not be detected
+ * correctly. */
+ if (deg_copy_on_write_is_expanded(id_cow)) {
+ if (graph->is_active) {
+ deg_editors_id_update(update_ctx, id_orig);
+ }
+ /* ID may need to get its auto-override operations refreshed. */
+ if (ID_IS_STATIC_OVERRIDE_AUTO(id_orig)) {
+ id_orig->tag |= LIB_TAG_OVERRIDESTATIC_AUTOREFRESH;
+ }
+ /* Inform draw engines that something was changed. */
+ flush_engine_data_update(id_cow);
+ }
}
}
+#ifdef INVALIDATE_ON_FLUSH
+void invalidate_tagged_evaluated_transform(ID *id)
+{
+ const ID_Type id_type = GS(id->name);
+ switch (id_type) {
+ case ID_OB:
+ {
+ Object *object = (Object *)id;
+ copy_vn_fl((float *)object->obmat, 16, NAN);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void invalidate_tagged_evaluated_geometry(ID *id)
+{
+ const ID_Type id_type = GS(id->name);
+ switch (id_type) {
+ case ID_OB:
+ {
+ Object *object = (Object *)id;
+ BKE_object_free_derived_caches(object);
+ break;
+ }
+ default:
+ break;
+ }
+}
+#endif
+
+void invalidate_tagged_evaluated_data(Depsgraph *graph)
+{
+#ifdef INVALIDATE_ON_FLUSH
+ foreach (IDDepsNode *id_node, graph->id_nodes) {
+ if (id_node->custom_flags != ID_STATE_MODIFIED) {
+ continue;
+ }
+ ID *id_cow = id_node->id_cow;
+ if (!deg_copy_on_write_is_expanded(id_cow)) {
+ continue;
+ }
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ if (comp_node->custom_flags != COMPONENT_STATE_DONE) {
+ continue;
+ }
+ switch (comp_node->type) {
+ case DEG_TAG_TRANSFORM:
+ invalidate_tagged_evaluated_transform(id_cow);
+ break;
+ case DEG_TAG_GEOMETRY:
+ invalidate_tagged_evaluated_geometry(id_cow);
+ break;
+ default:
+ break;
+ }
+ }
+ GHASH_FOREACH_END();
+ }
+#else
+ (void) graph;
+#endif
+}
+
} // namespace
/* Flush updates from tagged nodes outwards until all affected nodes
@@ -275,6 +381,12 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
/* Starting from the tagged "entry" nodes, flush outwards. */
FlushQueue queue;
flush_schedule_entrypoints(graph, &queue);
+ /* Prepare update context for editors. */
+ DEGEditorUpdateContext update_ctx;
+ update_ctx.bmain = bmain;
+ update_ctx.depsgraph = (::Depsgraph *)graph;
+ update_ctx.scene = graph->scene;
+ update_ctx.view_layer = graph->view_layer;
/* Do actual flush. */
while (!queue.empty()) {
OperationDepsNode *op_node = queue.front();
@@ -286,8 +398,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
ComponentDepsNode *comp_node = op_node->owner;
IDDepsNode *id_node = comp_node->owner;
flush_handle_id_node(id_node);
- flush_handle_component_node(graph,
- id_node,
+ flush_handle_component_node(id_node,
comp_node,
&queue);
/* Flush to nodes along links. */
@@ -295,10 +406,14 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
}
}
/* Inform editors about all changes. */
- flush_editors_id_update(bmain, graph);
+ flush_editors_id_update(bmain, graph, &update_ctx);
+ /* Reset evaluation result tagged which is tagged for update to some state
+ * which is obvious to catch.
+ */
+ invalidate_tagged_evaluated_data(graph);
}
-static void graph_clear_func(
+static void graph_clear_operation_func(
void *__restrict data_v,
const int i,
const ParallelRangeTLS *__restrict /*tls*/)
@@ -306,21 +421,25 @@ static void graph_clear_func(
Depsgraph *graph = (Depsgraph *)data_v;
OperationDepsNode *node = graph->operations[i];
/* Clear node's "pending update" settings. */
- node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED |
+ DEPSOP_FLAG_NEEDS_UPDATE |
+ DEPSOP_FLAG_USER_MODIFIED);
}
/* Clear tags from all operation nodes. */
void deg_graph_clear_tags(Depsgraph *graph)
{
/* Go over all operation nodes, clearing tags. */
- const int num_operations = graph->operations.size();
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = 1024;
- BLI_task_parallel_range(0, num_operations,
- graph,
- graph_clear_func,
- &settings);
+ {
+ const int num_operations = graph->operations.size();
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.min_iter_per_thread = 1024;
+ BLI_task_parallel_range(0, num_operations,
+ graph,
+ graph_clear_operation_func,
+ &settings);
+ }
/* Clear any entry tags which haven't been flushed. */
BLI_gset_clear(graph->entry_tags, NULL);
}
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index d72ca384044..3e2c48e9096 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -34,6 +34,7 @@
#include "BLI_utildefines.h"
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_id.h"
#include "intern/nodes/deg_node_operation.h"
@@ -41,6 +42,7 @@
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
+#include "util/deg_util_function.h"
namespace DEG {
@@ -101,10 +103,7 @@ DepsNode::~DepsNode()
/* Generic identifier for Depsgraph Nodes. */
string DepsNode::identifier() const
{
- char typebuf[7];
- sprintf(typebuf, "(%d)", type);
-
- return string(typebuf) + " : " + name;
+ return string(nodeTypeAsString(type)) + " : " + name;
}
eDepsNode_Class DepsNode::get_class() const {
@@ -122,7 +121,7 @@ eDepsNode_Class DepsNode::get_class() const {
/*******************************************************************************
* Generic nodes definition.
*/
-\
+
DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source");
static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index 603a6be7ceb..7a837d17ceb 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -80,9 +80,15 @@ struct DepsNode {
eDepsNode_Type type; /* Structural type of node. */
Relations inlinks; /* Nodes which this one depends on. */
Relations outlinks; /* Nodes which depend on this one. */
- int done; /* Generic tags for traversal algorithms. */
Stats stats; /* Evaluation statistics. */
+ /* Generic tags for traversal algorithms and such.
+ *
+ * Actual meaning of values depends on a specific area. Every area is to
+ * clean this before use.
+ */
+ int custom_flags;
+
/* Methods. */
DepsNode();
virtual ~DepsNode();
@@ -92,7 +98,8 @@ struct DepsNode {
virtual void init(const ID * /*id*/,
const char * /*subdata*/) {}
- virtual void tag_update(Depsgraph * /*graph*/) {}
+ virtual void tag_update(Depsgraph * /*graph*/,
+ eDepsTag_Source /*source*/) {}
virtual OperationDepsNode *get_entry_operation() { return NULL; }
virtual OperationDepsNode *get_exit_operation() { return NULL; }
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index 755b10c3f1d..4bb9b9d17b3 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -125,7 +125,7 @@ static void comp_node_hash_value_free(void *value_v)
ComponentDepsNode::ComponentDepsNode() :
entry_operation(NULL),
exit_operation(NULL),
- layers(0)
+ affects_directly_visible(false)
{
operations_map = BLI_ghash_new(comp_node_hash_key,
comp_node_hash_key_cmp,
@@ -158,10 +158,11 @@ string ComponentDepsNode::identifier() const
char typebuf[16];
sprintf(typebuf, "(%d)", type);
- char layers[16];
- sprintf(layers, "%u", this->layers);
-
- return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")";
+ return string(typebuf) + name + " : " + idname +
+ "( affects_directly_visible: " +
+ (affects_directly_visible ? "true"
+ : "false") + ")";
+;
}
OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
@@ -171,9 +172,9 @@ OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
node = (OperationDepsNode *)BLI_ghash_lookup(operations_map, &key);
}
else {
- BLI_assert(key.name_tag == -1);
foreach (OperationDepsNode *op_node, operations) {
if (op_node->opcode == key.opcode &&
+ op_node->name_tag == key.name_tag &&
STREQ(op_node->name, key.name))
{
node = op_node;
@@ -233,7 +234,7 @@ OperationDepsNode *ComponentDepsNode::add_operation(const DepsEvalOperationCb& o
OperationDepsNode *op_node = find_operation(opcode, name, name_tag);
if (!op_node) {
DepsNodeFactory *factory = deg_type_get_factory(DEG_NODE_TYPE_OPERATION);
- op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
+ op_node = (OperationDepsNode *)factory->create_node(this->owner->id_orig, "", name);
/* register opnode in this component's operation set */
OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag);
@@ -252,6 +253,7 @@ OperationDepsNode *ComponentDepsNode::add_operation(const DepsEvalOperationCb& o
op_node->evaluate = op;
op_node->opcode = opcode;
op_node->name = name;
+ op_node->name_tag = name_tag;
return op_node;
}
@@ -281,20 +283,20 @@ void ComponentDepsNode::clear_operations()
operations.clear();
}
-void ComponentDepsNode::tag_update(Depsgraph *graph)
+void ComponentDepsNode::tag_update(Depsgraph *graph, eDepsTag_Source source)
{
OperationDepsNode *entry_op = get_entry_operation();
if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
return;
}
foreach (OperationDepsNode *op_node, operations) {
- op_node->tag_update(graph);
+ op_node->tag_update(graph, source);
}
// It is possible that tag happens before finalization.
if (operations_map != NULL) {
GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
{
- op_node->tag_update(graph);
+ op_node->tag_update(graph, source);
}
GHASH_FOREACH_END();
}
@@ -346,7 +348,7 @@ OperationDepsNode *ComponentDepsNode::get_exit_operation()
return NULL;
}
-void ComponentDepsNode::finalize_build()
+void ComponentDepsNode::finalize_build(Depsgraph * /*graph*/)
{
operations.reserve(BLI_ghash_len(operations_map));
GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
@@ -381,36 +383,47 @@ void BoneComponentDepsNode::init(const ID *id, const char *subdata)
/* Register all components. =============================== */
-DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Bone, BONE, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Geometry, GEOMETRY, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Particles, EVAL_PARTICLES, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_NONE);
-DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_NONE);
+DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION);
+DEG_COMPONENT_NODE_DEFINE(BatchCache, BATCH_CACHE, ID_RECALC_DRAW_CACHE);
+DEG_COMPONENT_NODE_DEFINE(Bone, BONE, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, ID_RECALC);
+DEG_COMPONENT_NODE_DEFINE(CopyOnWrite, COPY_ON_WRITE, ID_RECALC_COPY_ON_WRITE);
+DEG_COMPONENT_NODE_DEFINE(Geometry, GEOMETRY, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(LayerCollections, LAYER_COLLECTIONS, 0);
+DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, ID_RECALC);
+DEG_COMPONENT_NODE_DEFINE(Particles, EVAL_PARTICLES, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(PointCache, POINT_CACHE, 0);
+DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY);
+DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, ID_RECALC);
+DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_DRAW);
+DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_DRAW);
+DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM);
+DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, ID_RECALC);
+DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0);
/* Node Types Register =================================== */
void deg_register_component_depsnodes()
{
- deg_register_node_typeinfo(&DNTI_PARAMETERS);
- deg_register_node_typeinfo(&DNTI_PROXY);
deg_register_node_typeinfo(&DNTI_ANIMATION);
- deg_register_node_typeinfo(&DNTI_TRANSFORM);
- deg_register_node_typeinfo(&DNTI_GEOMETRY);
- deg_register_node_typeinfo(&DNTI_SEQUENCER);
-
- deg_register_node_typeinfo(&DNTI_EVAL_POSE);
deg_register_node_typeinfo(&DNTI_BONE);
-
+ deg_register_node_typeinfo(&DNTI_CACHE);
+ deg_register_node_typeinfo(&DNTI_BATCH_CACHE);
+ deg_register_node_typeinfo(&DNTI_COPY_ON_WRITE);
+ deg_register_node_typeinfo(&DNTI_GEOMETRY);
+ deg_register_node_typeinfo(&DNTI_LAYER_COLLECTIONS);
+ deg_register_node_typeinfo(&DNTI_PARAMETERS);
deg_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
+ deg_register_node_typeinfo(&DNTI_POINT_CACHE);
+ deg_register_node_typeinfo(&DNTI_PROXY);
+ deg_register_node_typeinfo(&DNTI_EVAL_POSE);
+ deg_register_node_typeinfo(&DNTI_SEQUENCER);
deg_register_node_typeinfo(&DNTI_SHADING);
-
- deg_register_node_typeinfo(&DNTI_CACHE);
+ deg_register_node_typeinfo(&DNTI_SHADING_PARAMETERS);
+ deg_register_node_typeinfo(&DNTI_TRANSFORM);
+ deg_register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER);
+ deg_register_node_typeinfo(&DNTI_DUPLI);
}
} // 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 985716deaac..e3057e1d3ce 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -39,8 +39,6 @@ struct ID;
struct bPoseChannel;
struct GHash;
-struct EvaluationContext;
-
namespace DEG {
struct Depsgraph;
@@ -71,9 +69,9 @@ struct ComponentDepsNode : public DepsNode {
ComponentDepsNode();
~ComponentDepsNode();
- void init(const ID *id, const char *subdata);
+ void init(const ID *id, const char *subdata) override;
- string identifier() const;
+ virtual string identifier() const override;
/* Find an existing operation, if requested operation does not exist
* NULL will be returned.
@@ -122,12 +120,12 @@ struct ComponentDepsNode : public DepsNode {
void clear_operations();
- void tag_update(Depsgraph *graph);
+ virtual void tag_update(Depsgraph *graph, eDepsTag_Source source) override;
- OperationDepsNode *get_entry_operation();
- OperationDepsNode *get_exit_operation();
+ virtual OperationDepsNode *get_entry_operation() override;
+ virtual OperationDepsNode *get_exit_operation() override;
- void finalize_build();
+ void finalize_build(Depsgraph *graph);
IDDepsNode *owner;
@@ -146,10 +144,17 @@ struct ComponentDepsNode : public DepsNode {
OperationDepsNode *entry_operation;
OperationDepsNode *exit_operation;
- // XXX: a poll() callback to check if component's first node can be started?
+ virtual bool depends_on_cow() { return true; }
+
+ /* Denotes whether COW component is to be tagged when this component
+ * is tagged for update.
+ */
+ virtual bool need_tag_cow_before_update() { return true; }
- /* Temporary bitmask, used during graph construction. */
- unsigned int layers;
+ /* Denotes whether this component affects (possibly indirectly) on a
+ * directly visible object.
+ */
+ bool affects_directly_visible;
};
/* ---------------------------------------- */
@@ -172,16 +177,29 @@ struct ComponentDepsNode : public DepsNode {
DEG_COMPONENT_NODE_DECLARE; \
}
+#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(name) \
+ struct name ## ComponentDepsNode : public ComponentDepsNode { \
+ DEG_COMPONENT_NODE_DECLARE; \
+ virtual bool need_tag_cow_before_update() { return false; } \
+ }
+
DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation);
+DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(BatchCache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(CopyOnWrite);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Geometry);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(LayerCollections);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Parameters);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles);
-DEG_COMPONENT_NODE_DECLARE_GENERIC(Proxy);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Pose);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(PointCache);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Proxy);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Sequencer);
-DEG_COMPONENT_NODE_DECLARE_GENERIC(Shading);
+DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(Shading);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(ShadingParameters);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Transform);
+DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(ObjectFromLayer);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Dupli);
/* Bone Component */
struct BoneComponentDepsNode : public ComponentDepsNode {
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_id.cc b/source/blender/depsgraph/intern/nodes/deg_node_id.cc
index 478cc2863b0..b194e304e99 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_id.cc
@@ -41,8 +41,12 @@ extern "C" {
#include "DNA_anim_types.h"
#include "BKE_animsys.h"
+#include "BKE_library.h"
}
+#include "DEG_depsgraph.h"
+
+#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node_time.h"
#include "intern/depsgraph_intern.h"
@@ -58,8 +62,8 @@ IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type,
bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const
{
- return type == other.type &&
- STREQ(name, other.name);
+ return type == other.type &&
+ STREQ(name, other.name);
}
static unsigned int id_deps_node_hash_key(const void *key_v)
@@ -95,33 +99,87 @@ static void id_deps_node_hash_value_free(void *value_v)
/* Initialize 'id' node - from pointer data given. */
void IDDepsNode::init(const ID *id, const char *UNUSED(subdata))
{
- /* Store ID-pointer. */
BLI_assert(id != NULL);
- this->id = (ID *)id;
- this->layers = (1 << 20) - 1;
- this->eval_flags = 0;
+ /* Store ID-pointer. */
+ id_orig = (ID *)id;
+ eval_flags = 0;
+ previous_eval_flags = 0;
+ linked_state = DEG_ID_LINKED_INDIRECTLY;
+ is_directly_visible = true;
+ is_collection_fully_expanded = false;
- /* For object we initialize layers to layer from base. */
- if (GS(id->name) == ID_OB) {
- this->layers = 0;
- }
+ visible_components_mask = 0;
+ previously_visible_components_mask = 0;
components = BLI_ghash_new(id_deps_node_hash_key,
id_deps_node_hash_key_cmp,
"Depsgraph id components hash");
+}
- /* NOTE: components themselves are created if/when needed.
- * This prevents problems with components getting added
- * twice if an ID-Ref needs to be created to house it...
+void IDDepsNode::init_copy_on_write(ID *id_cow_hint)
+{
+ /* Create pointer as early as possible, so we can use it for function
+ * bindings. Rest of data we'll be copying to the new datablock when
+ * it is actually needed.
*/
+ if (id_cow_hint != NULL) {
+ // BLI_assert(deg_copy_on_write_is_needed(id_orig));
+ if (deg_copy_on_write_is_needed(id_orig)) {
+ id_cow = id_cow_hint;
+ }
+ else {
+ id_cow = id_orig;
+ }
+ }
+ else if (deg_copy_on_write_is_needed(id_orig)) {
+ id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name));
+ DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+ deg_tag_copy_on_write_id(id_cow, id_orig);
+ }
+ else {
+ id_cow = id_orig;
+ }
}
/* Free 'id' node. */
IDDepsNode::~IDDepsNode()
{
+ destroy();
+}
+
+void IDDepsNode::destroy()
+{
+ if (id_orig == NULL) {
+ return;
+ }
+
BLI_ghash_free(components,
id_deps_node_hash_key_free,
id_deps_node_hash_value_free);
+
+ /* Free memory used by this CoW ID. */
+ if (id_cow != id_orig && id_cow != NULL) {
+ deg_free_copy_on_write_datablock(id_cow);
+ MEM_freeN(id_cow);
+ id_cow = NULL;
+ DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n",
+ id_orig->name, id_orig, id_cow);
+ }
+
+ /* Tag that the node is freed. */
+ id_orig = NULL;
+}
+
+string IDDepsNode::identifier() const
+{
+ char orig_ptr[24], cow_ptr[24];
+ BLI_snprintf(orig_ptr, sizeof(orig_ptr), "%p", id_orig);
+ BLI_snprintf(cow_ptr, sizeof(cow_ptr), "%p", id_cow);
+ return string(nodeTypeAsString(type)) + " : " + name +
+ " (orig: " + orig_ptr + ", eval: " + cow_ptr +
+ ", is_directly_visible " + (is_directly_visible ? "true"
+ : "false") + ")";
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
@@ -137,7 +195,7 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
ComponentDepsNode *comp_node = find_component(type, name);
if (!comp_node) {
DepsNodeFactory *factory = deg_type_get_factory(type);
- comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name);
+ comp_node = (ComponentDepsNode *)factory->create_node(this->id_orig, "", name);
/* Register. */
ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name);
@@ -147,33 +205,38 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
return comp_node;
}
-void IDDepsNode::tag_update(Depsgraph *graph)
+void IDDepsNode::tag_update(Depsgraph *graph, eDepsTag_Source source)
{
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
{
- /* TODO(sergey): What about drievrs? */
- bool do_component_tag = comp_node->type != DEG_NODE_TYPE_ANIMATION;
- if (comp_node->type == DEG_NODE_TYPE_ANIMATION) {
- AnimData *adt = BKE_animdata_from_id(id);
- /* Animation data might be null if relations are tagged for update. */
- if (adt != NULL && (adt->recalc & ADT_RECALC_ANIM)) {
- do_component_tag = true;
- }
- }
- if (do_component_tag) {
- comp_node->tag_update(graph);
- }
+ comp_node->tag_update(graph, source);
}
GHASH_FOREACH_END();
}
-void IDDepsNode::finalize_build()
+void IDDepsNode::finalize_build(Depsgraph *graph)
{
+ /* Finalize build of all components. */
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
{
- comp_node->finalize_build();
+ comp_node->finalize_build(graph);
+ }
+ GHASH_FOREACH_END();
+ visible_components_mask = get_visible_components_mask();
+}
+
+IDComponentsMask IDDepsNode::get_visible_components_mask() const {
+ IDComponentsMask result = 0;
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
+ {
+ if (comp_node->affects_directly_visible) {
+ const int component_type = comp_node->type;
+ BLI_assert(component_type < 64);
+ result |= (1ULL << component_type);
+ }
}
GHASH_FOREACH_END();
+ return result;
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_id.h b/source/blender/depsgraph/intern/nodes/deg_node_id.h
index 55022916c4d..f8d05eddffd 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_id.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_id.h
@@ -31,11 +31,14 @@
#pragma once
#include "intern/nodes/deg_node.h"
+#include "BLI_sys_types.h"
namespace DEG {
struct ComponentDepsNode;
+typedef uint64_t IDComponentsMask;
+
/* ID-Block Reference */
struct IDDepsNode : public DepsNode {
struct ComponentIDKey {
@@ -46,32 +49,49 @@ struct IDDepsNode : public DepsNode {
const char *name;
};
- void init(const ID *id, const char *subdata);
+ virtual void init(const ID *id, const char *subdata) override;
+ void init_copy_on_write(ID *id_cow_hint = NULL);
~IDDepsNode();
+ void destroy();
+
+ virtual string identifier() const override;
ComponentDepsNode *find_component(eDepsNode_Type type,
const char *name = "") const;
ComponentDepsNode *add_component(eDepsNode_Type type,
const char *name = "");
- void tag_update(Depsgraph *graph);
+ virtual void tag_update(Depsgraph *graph, eDepsTag_Source source) override;
- void finalize_build();
+ void finalize_build(Depsgraph *graph);
+
+ IDComponentsMask get_visible_components_mask() const;
/* ID Block referenced. */
- ID *id;
+ ID *id_orig;
+ ID *id_cow;
/* Hash to make it faster to look up components. */
GHash *components;
- /* Layers of this node with accumulated layers of it's output relations. */
- unsigned int layers;
-
/* Additional flags needed for scene evaluation.
* TODO(sergey): Only needed for until really granular updates
* of all the entities.
*/
- int eval_flags;
+ uint32_t eval_flags;
+ uint32_t previous_eval_flags;
+
+ eDepsNode_LinkedState_Type linked_state;
+
+ /* Indicates the datablock is visible in the evaluated scene. */
+ bool is_directly_visible;
+
+ /* For the collection type of ID, denotes whether collection was fully
+ * recursed into. */
+ bool is_collection_fully_expanded;
+
+ IDComponentsMask visible_components_mask;
+ IDComponentsMask previously_visible_components_mask;
DEG_DEPSNODE_DECLARE;
};
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index cbc0fbb4241..ef1882dd715 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -45,6 +45,7 @@ namespace DEG {
/* Inner Nodes */
OperationDepsNode::OperationDepsNode() :
+ name_tag(-1),
flag(0),
customdata_mask(0)
{
@@ -56,7 +57,7 @@ OperationDepsNode::~OperationDepsNode()
string OperationDepsNode::identifier() const
{
- return string(DEG_OPNAMES[opcode]) + "(" + name + ")";
+ return string(operationCodeAsString(opcode)) + "(" + name + ")";
}
/* Full node identifier, including owner name.
@@ -74,14 +75,23 @@ string OperationDepsNode::full_identifier() const
return owner_str + "." + identifier();
}
-void OperationDepsNode::tag_update(Depsgraph *graph)
+void OperationDepsNode::tag_update(Depsgraph *graph, eDepsTag_Source source)
{
- if (flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- return;
+ if ((flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) {
+ graph->add_entry_tag(this);
}
/* Tag for update, but also note that this was the source of an update. */
flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED);
- graph->add_entry_tag(this);
+ switch (source) {
+ case DEG_UPDATE_SOURCE_TIME:
+ case DEG_UPDATE_SOURCE_RELATIONS:
+ case DEG_UPDATE_SOURCE_VISIBILITY:
+ /* Currently nothing. */
+ break;
+ case DEG_UPDATE_SOURCE_USER_EDIT:
+ flag |= DEPSOP_FLAG_USER_MODIFIED;
+ break;
+ }
}
void OperationDepsNode::set_as_entry()
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
index c172f73be5f..71c03945d48 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
@@ -40,13 +40,17 @@ namespace DEG {
struct ComponentDepsNode;
-/* Flags for Depsgraph Nodes */
+/* Flags for Depsgraph Nodes. */
typedef enum eDepsOperation_Flag {
- /* node needs to be updated */
+ /* Node needs to be updated. */
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
-
- /* node was directly modified, causing need for update */
+ /* Node was directly modified, causing need for update. */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
+ /* Node was updated due to user input. */
+ DEPSOP_FLAG_USER_MODIFIED = (1 << 2),
+
+ /* Set of flags which gets flushed along the relations. */
+ DEPSOP_FLAG_FLUSH = (DEPSOP_FLAG_USER_MODIFIED)
} eDepsOperation_Flag;
/* Atomic Operation - Base type for all operations */
@@ -54,17 +58,21 @@ struct OperationDepsNode : public DepsNode {
OperationDepsNode();
~OperationDepsNode();
- string identifier() const;
+ virtual string identifier() const override;
string full_identifier() const;
- void tag_update(Depsgraph *graph);
+ virtual void tag_update(Depsgraph *graph, eDepsTag_Source source) override;
bool is_noop() const { return (bool)evaluate == false; }
- OperationDepsNode *get_entry_operation() { return this; }
- OperationDepsNode *get_exit_operation() { return this; }
+ virtual OperationDepsNode *get_entry_operation() override {
+ return this;
+ }
+ virtual OperationDepsNode *get_exit_operation() override {
+ return this;
+ }
- /* Set this operation as compoonent's entry/exit operation. */
+ /* Set this operation as component's entry/exit operation. */
void set_as_entry();
void set_as_exit();
@@ -80,6 +88,7 @@ struct OperationDepsNode : public DepsNode {
/* Identifier for the operation being performed. */
eDepsOperation_Code opcode;
+ int name_tag;
/* (eDepsOperation_Flag) extra settings affecting evaluation. */
int flag;
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_time.cc b/source/blender/depsgraph/intern/nodes/deg_node_time.cc
index 230488b2328..a788b999305 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_time.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_time.cc
@@ -33,13 +33,16 @@
#include "intern/depsgraph_intern.h"
#include "util/deg_util_foreach.h"
+#include "DNA_scene_types.h"
+
namespace DEG {
-void TimeSourceDepsNode::tag_update(Depsgraph *graph)
+void TimeSourceDepsNode::tag_update(Depsgraph *graph,
+ eDepsTag_Source /*source*/)
{
foreach (DepsRelation *rel, outlinks) {
DepsNode *node = rel->to;
- node->tag_update(graph);
+ node->tag_update(graph, DEG_UPDATE_SOURCE_TIME);
}
}
diff --git a/source/blender/depsgraph/intern/nodes/deg_node_time.h b/source/blender/depsgraph/intern/nodes/deg_node_time.h
index 93f3edef9cf..7253dc106d4 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node_time.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_time.h
@@ -44,7 +44,7 @@ struct TimeSourceDepsNode : public DepsNode {
// TODO: evaluate() operation needed
- void tag_update(Depsgraph *graph);
+ virtual void tag_update(Depsgraph *graph, eDepsTag_Source source) override;
DEG_DEPSNODE_DECLARE;
};
diff --git a/source/blender/depsgraph/util/deg_util_function.h b/source/blender/depsgraph/util/deg_util_function.h
index 8863d92eb74..0ec41412d7b 100644
--- a/source/blender/depsgraph/util/deg_util_function.h
+++ b/source/blender/depsgraph/util/deg_util_function.h
@@ -32,6 +32,10 @@
#include <functional>
+namespace DEG {
+
using std::function;
using namespace std::placeholders;
#define function_bind std::bind
+
+} // namespace
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
new file mode 100644
index 00000000000..70dfa589cdc
--- /dev/null
+++ b/source/blender/draw/CMakeLists.txt
@@ -0,0 +1,362 @@
+# ***** 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): Blender Institute
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ modes
+
+ ../blenfont
+ ../blenkernel
+ ../blenlib
+ ../blentranslation
+ ../bmesh
+ ../depsgraph
+ ../editors/include
+ ../editors/space_view3d
+ ../gpu
+ ../imbuf
+ ../makesdna
+ ../makesrna
+ ../render/extern/include
+ ../render/intern/include
+ ../windowmanager
+
+ ../../../intern/glew-mx
+ ../../../intern/guardedalloc
+)
+
+set(INC_SYS
+ ${GLEW_INCLUDE_PATH}
+)
+
+set(SRC
+ intern/draw_anim_viz.c
+ intern/draw_armature.c
+ intern/draw_cache.c
+ intern/draw_cache_impl_curve.c
+ intern/draw_cache_impl_displist.c
+ intern/draw_cache_impl_lattice.c
+ intern/draw_cache_impl_mesh.c
+ intern/draw_cache_impl_metaball.c
+ intern/draw_cache_impl_particles.c
+ intern/draw_common.c
+ intern/draw_debug.c
+ intern/draw_hair.c
+ intern/draw_instance_data.c
+ intern/draw_manager.c
+ intern/draw_manager_data.c
+ intern/draw_manager_exec.c
+ intern/draw_manager_shader.c
+ intern/draw_manager_text.c
+ intern/draw_manager_texture.c
+ intern/draw_manager_profiling.c
+ intern/draw_view.c
+ modes/edit_armature_mode.c
+ modes/edit_curve_mode.c
+ modes/edit_lattice_mode.c
+ modes/edit_mesh_mode.c
+ modes/edit_mesh_mode_text.c
+ modes/edit_metaball_mode.c
+ modes/edit_text_mode.c
+ modes/object_mode.c
+ modes/overlay_mode.c
+ modes/paint_texture_mode.c
+ modes/paint_vertex_mode.c
+ modes/paint_weight_mode.c
+ modes/particle_mode.c
+ modes/pose_mode.c
+ modes/sculpt_mode.c
+ engines/basic/basic_engine.c
+ engines/eevee/eevee_bloom.c
+ engines/eevee/eevee_data.c
+ engines/eevee/eevee_depth_of_field.c
+ engines/eevee/eevee_effects.c
+ engines/eevee/eevee_engine.c
+ engines/eevee/eevee_lightcache.c
+ engines/eevee/eevee_lightprobes.c
+ engines/eevee/eevee_lights.c
+ engines/eevee/eevee_lookdev.c
+ engines/eevee/eevee_materials.c
+ engines/eevee/eevee_mist.c
+ engines/eevee/eevee_motion_blur.c
+ engines/eevee/eevee_occlusion.c
+ engines/eevee/eevee_render.c
+ engines/eevee/eevee_screen_raytrace.c
+ engines/eevee/eevee_shaders.c
+ engines/eevee/eevee_subsurface.c
+ engines/eevee/eevee_temporal_sampling.c
+ engines/eevee/eevee_volumes.c
+ engines/workbench/workbench_data.c
+ engines/workbench/workbench_engine.c
+ engines/workbench/workbench_deferred.c
+ engines/workbench/workbench_effect_aa.c
+ engines/workbench/workbench_effect_fxaa.c
+ engines/workbench/workbench_effect_taa.c
+ engines/workbench/workbench_forward.c
+ engines/workbench/workbench_materials.c
+ engines/workbench/workbench_render.c
+ engines/workbench/workbench_studiolight.c
+ engines/workbench/workbench_volume.c
+ engines/workbench/solid_mode.c
+ engines/workbench/transparent_mode.c
+ engines/external/external_engine.c
+ engines/gpencil/gpencil_engine.h
+ engines/gpencil/gpencil_engine.c
+ engines/gpencil/gpencil_render.c
+ engines/gpencil/gpencil_cache_utils.c
+ engines/gpencil/gpencil_draw_utils.c
+ engines/gpencil/gpencil_draw_cache_impl.c
+ engines/gpencil/gpencil_shader_fx.c
+
+ DRW_engine.h
+ intern/DRW_render.h
+ intern/draw_cache.h
+ intern/draw_cache_impl.h
+ intern/draw_common.h
+ intern/draw_debug.h
+ intern/draw_hair_private.h
+ intern/draw_instance_data.h
+ intern/draw_manager.h
+ intern/draw_manager_text.h
+ intern/draw_manager_profiling.h
+ intern/draw_view.h
+ modes/draw_mode_engines.h
+ modes/edit_mesh_mode_intern.h
+ engines/basic/basic_engine.h
+ engines/eevee/eevee_engine.h
+ engines/eevee/eevee_lightcache.h
+ engines/eevee/eevee_lut.h
+ engines/eevee/eevee_private.h
+ engines/external/external_engine.h
+ engines/workbench/workbench_engine.h
+ engines/workbench/workbench_private.h
+)
+
+data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/concentric_samples_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_geom.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_grid_display_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_grid_display_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_grid_fill_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lit_surface_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lit_surface_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_dof_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_velocity_resolve_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_ssr_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_subsurface_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/shadow_store_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/shadow_copy_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/volumetric_lib.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/volumetric_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/volumetric_geom.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/volumetric_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/volumetric_resolve_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC)
+
+data_to_c_simple(engines/workbench/shaders/workbench_background_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_checkerboard_depth_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_forward_depth_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_ghost_resolve_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_object_outline_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
+
+data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC)
+data_to_c_simple(modes/shaders/common_hair_lib.glsl SRC)
+data_to_c_simple(modes/shaders/common_hair_refine_vert.glsl SRC)
+data_to_c_simple(modes/shaders/common_view_lib.glsl SRC)
+data_to_c_simple(modes/shaders/common_fxaa_lib.glsl SRC)
+data_to_c_simple(modes/shaders/common_fullscreen_vert.glsl SRC)
+data_to_c_simple(modes/shaders/animviz_mpath_lines_vert.glsl SRC)
+data_to_c_simple(modes/shaders/animviz_mpath_lines_geom.glsl SRC)
+data_to_c_simple(modes/shaders/animviz_mpath_points_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_axes_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_sphere_solid_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_sphere_solid_frag.glsl SRC)
+data_to_c_simple(modes/shaders/armature_sphere_outline_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_envelope_solid_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_envelope_solid_frag.glsl SRC)
+data_to_c_simple(modes/shaders/armature_envelope_outline_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_envelope_distance_frag.glsl SRC)
+data_to_c_simple(modes/shaders/armature_shape_solid_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_shape_solid_frag.glsl SRC)
+data_to_c_simple(modes/shaders/armature_shape_outline_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_shape_outline_geom.glsl SRC)
+data_to_c_simple(modes/shaders/armature_stick_vert.glsl SRC)
+data_to_c_simple(modes/shaders/armature_stick_frag.glsl SRC)
+data_to_c_simple(modes/shaders/armature_dof_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_common_lib.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_frag.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_geom_tri.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_geom_edge.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_points_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_facedot_frag.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_facedot_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_mix_frag.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC)
+data_to_c_simple(modes/shaders/edit_curve_overlay_handle_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC)
+data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_lattice_overlay_frag.glsl SRC)
+data_to_c_simple(modes/shaders/edit_lattice_overlay_loosevert_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_normals_vert.glsl SRC)
+data_to_c_simple(modes/shaders/edit_normals_geom.glsl SRC)
+data_to_c_simple(modes/shaders/overlay_face_orientation_frag.glsl SRC)
+data_to_c_simple(modes/shaders/overlay_face_orientation_vert.glsl SRC)
+data_to_c_simple(modes/shaders/overlay_face_wireframe_vert.glsl SRC)
+data_to_c_simple(modes/shaders/overlay_face_wireframe_geom.glsl SRC)
+data_to_c_simple(modes/shaders/overlay_face_wireframe_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_empty_axes_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_empty_image_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_empty_image_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_outline_resolve_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_outline_expand_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_outline_detect_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_outline_prepass_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_outline_prepass_geom.glsl SRC)
+data_to_c_simple(modes/shaders/object_outline_prepass_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_grid_frag.glsl SRC)
+data_to_c_simple(modes/shaders/object_grid_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_lightprobe_grid_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_mball_handles_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_particle_prim_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_particle_dot_vert.glsl SRC)
+data_to_c_simple(modes/shaders/object_particle_dot_frag.glsl SRC)
+data_to_c_simple(modes/shaders/paint_texture_frag.glsl SRC)
+data_to_c_simple(modes/shaders/paint_texture_vert.glsl SRC)
+data_to_c_simple(modes/shaders/paint_vertex_frag.glsl SRC)
+data_to_c_simple(modes/shaders/paint_vertex_vert.glsl SRC)
+data_to_c_simple(modes/shaders/paint_weight_frag.glsl SRC)
+data_to_c_simple(modes/shaders/paint_weight_vert.glsl SRC)
+data_to_c_simple(modes/shaders/paint_wire_frag.glsl SRC)
+data_to_c_simple(modes/shaders/paint_wire_vert.glsl SRC)
+data_to_c_simple(modes/shaders/paint_vert_frag.glsl SRC)
+data_to_c_simple(modes/shaders/particle_strand_frag.glsl SRC)
+data_to_c_simple(modes/shaders/particle_strand_vert.glsl SRC)
+data_to_c_simple(modes/shaders/sculpt_mask_vert.glsl SRC)
+data_to_c_simple(modes/shaders/volume_velocity_vert.glsl SRC)
+
+data_to_c_simple(engines/gpencil/shaders/gpencil_fill_vert.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_fill_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_vert.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_geom.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_simple_mix_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_blend_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_point_vert.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_point_geom.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_point_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_background_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_paper_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_vert.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_geom.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_frag.glsl SRC)
+
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl SRC)
+
+
+list(APPEND INC
+)
+
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
+blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
new file mode 100644
index 00000000000..d790cee48bb
--- /dev/null
+++ b/source/blender/draw/DRW_engine.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file DRW_engine.h
+ * \ingroup draw
+ */
+
+#ifndef __DRW_ENGINE_H__
+#define __DRW_ENGINE_H__
+
+#include "BLI_sys_types.h" /* for bool */
+
+struct ARegion;
+struct CollectionEngineSettings;
+struct Depsgraph;
+struct DRWPass;
+struct DRWInstanceDataList;
+struct Main;
+struct Material;
+struct Scene;
+struct DrawEngineType;
+struct ID;
+struct IDProperty;
+struct bContext;
+struct Object;
+struct ViewLayer;
+struct ViewContext;
+struct ViewportEngineData;
+struct View3D;
+struct rcti;
+struct GPUMaterial;
+struct GPUOffScreen;
+struct GPUViewport;
+struct RenderEngine;
+struct RenderEngineType;
+struct WorkSpace;
+
+#include "DNA_object_enums.h"
+
+/* Buffer and textures used by the viewport by default */
+typedef struct DefaultFramebufferList {
+ struct GPUFrameBuffer *default_fb;
+ struct GPUFrameBuffer *color_only_fb;
+ struct GPUFrameBuffer *depth_only_fb;
+ struct GPUFrameBuffer *multisample_fb;
+} DefaultFramebufferList;
+
+typedef struct DefaultTextureList {
+ struct GPUTexture *color;
+ struct GPUTexture *depth;
+ struct GPUTexture *multisample_color;
+ struct GPUTexture *multisample_depth;
+} DefaultTextureList;
+
+void DRW_engines_register(void);
+void DRW_engines_free(void);
+
+bool DRW_engine_render_support(struct DrawEngineType *draw_engine_type);
+void DRW_engine_register(struct DrawEngineType *draw_engine_type);
+void DRW_engine_viewport_data_size_get(
+ const void *engine_type,
+ int *r_fbl_len, int *r_txl_len, int *r_psl_len, int *r_stl_len);
+
+typedef struct DRWUpdateContext {
+ struct Main *bmain;
+ struct Depsgraph *depsgraph;
+ struct Scene *scene;
+ struct ViewLayer *view_layer;
+ struct ARegion *ar;
+ struct View3D *v3d;
+ struct RenderEngineType *engine_type;
+} DRWUpdateContext;
+void DRW_notify_view_update(const DRWUpdateContext *update_ctx);
+
+
+typedef enum eDRWSelectStage { DRW_SELECT_PASS_PRE = 1, DRW_SELECT_PASS_POST, } eDRWSelectStage;
+typedef bool (*DRW_SelectPassFn)(
+ eDRWSelectStage stage, void *user_data);
+typedef bool (*DRW_ObjectFilterFn)(
+ struct Object *ob, void *user_data);
+
+void DRW_draw_view(const struct bContext *C);
+void DRW_draw_region_engine_info(int xoffset, int yoffset);
+
+void DRW_draw_render_loop_ex(
+ struct Depsgraph *depsgraph,
+ struct RenderEngineType *engine_type,
+ struct ARegion *ar, struct View3D *v3d,
+ struct GPUViewport *viewport,
+ const struct bContext *evil_C);
+void DRW_draw_render_loop(
+ struct Depsgraph *depsgraph,
+ struct ARegion *ar, struct View3D *v3d,
+ struct GPUViewport *viewport);
+void DRW_draw_render_loop_offscreen(
+ struct Depsgraph *depsgraph,
+ struct RenderEngineType *engine_type,
+ struct ARegion *ar, struct View3D *v3d,
+ const bool draw_background,
+ struct GPUOffScreen *ofs,
+ struct GPUViewport *viewport);
+void DRW_draw_select_loop(
+ struct Depsgraph *depsgraph,
+ struct ARegion *ar, struct View3D *v3d,
+ bool use_obedit_skip, bool draw_surface, bool use_nearest, const struct rcti *rect,
+ DRW_SelectPassFn select_pass_fn, void *select_pass_user_data,
+ DRW_ObjectFilterFn object_filter_fn, void *object_filter_user_data);
+void DRW_draw_depth_loop(
+ struct Depsgraph *depsgraph,
+ struct ARegion *ar, struct View3D *v3d);
+
+/* grease pencil render */
+bool DRW_render_check_grease_pencil(struct Depsgraph *depsgraph);
+void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void DRW_gpencil_freecache(struct Object *ob);
+
+/* This is here because GPUViewport needs it */
+void DRW_pass_free(struct DRWPass *pass);
+struct DRWInstanceDataList *DRW_instance_data_list_create(void);
+void DRW_instance_data_list_free(struct DRWInstanceDataList *idatalist);
+
+void DRW_opengl_context_create(void);
+void DRW_opengl_context_destroy(void);
+void DRW_opengl_context_enable(void);
+void DRW_opengl_context_disable(void);
+
+/* Never use this. Only for closing blender. */
+void DRW_opengl_context_enable_ex(bool restore);
+void DRW_opengl_context_disable_ex(bool restore);
+
+void DRW_opengl_render_context_enable(void *re_gl_context);
+void DRW_opengl_render_context_disable(void *re_gl_context);
+void DRW_gawain_render_context_enable(void *re_gpu_context);
+void DRW_gawain_render_context_disable(void *re_gpu_context);
+
+void DRW_deferred_shader_remove(struct GPUMaterial *mat);
+
+struct DrawDataList *DRW_drawdatalist_from_id(struct ID *id);
+void DRW_drawdata_free(struct ID *id);
+
+#endif /* __DRW_ENGINE_H__ */
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
new file mode 100644
index 00000000000..8356838a885
--- /dev/null
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file basic_engine.c
+ * \ingroup draw_engine
+ *
+ * Simple engine for drawing color and/or depth.
+ * When we only need simple flat shaders.
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_icons.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_particle.h"
+
+#include "DNA_particle_types.h"
+
+#include "GPU_shader.h"
+
+#include "basic_engine.h"
+/* Shaders */
+
+#define BASIC_ENGINE "BLENDER_BASIC"
+
+/* *********** LISTS *********** */
+
+/* GPUViewport.storage
+ * Is freed everytime the viewport engine changes */
+typedef struct BASIC_StorageList {
+ struct BASIC_PrivateData *g_data;
+} BASIC_StorageList;
+
+typedef struct BASIC_PassList {
+ struct DRWPass *depth_pass;
+ struct DRWPass *depth_pass_cull;
+} BASIC_PassList;
+
+typedef struct BASIC_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ BASIC_PassList *psl;
+ BASIC_StorageList *stl;
+} BASIC_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Depth Pre Pass */
+ struct GPUShader *depth_sh;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct BASIC_PrivateData {
+ DRWShadingGroup *depth_shgrp;
+ DRWShadingGroup *depth_shgrp_cull;
+ DRWShadingGroup *depth_shgrp_hair;
+} BASIC_PrivateData; /* Transient data */
+
+/* Functions */
+
+static void basic_engine_init(void *UNUSED(vedata))
+{
+ /* Depth prepass */
+ if (!e_data.depth_sh) {
+ e_data.depth_sh = DRW_shader_create_3D_depth_only();
+ }
+}
+
+static void basic_cache_init(void *vedata)
+{
+ BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
+ BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ psl->depth_pass = DRW_pass_create(
+ "Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE);
+ stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass);
+
+ psl->depth_pass_cull = DRW_pass_create(
+ "Depth Pass Cull",
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK);
+ stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull);
+ }
+}
+
+static void basic_cache_populate(void *vedata, Object *ob)
+{
+ BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
+
+ /* TODO(fclem) fix selection of smoke domains. */
+
+ if (!DRW_object_is_renderable(ob) || (ob->dt < OB_SOLID)) {
+ return;
+ }
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ if (ob != draw_ctx->object_edit) {
+ for (ParticleSystem *psys = ob->particlesystem.first;
+ psys != NULL;
+ psys = psys->next)
+ {
+ if (!psys_check_enabled(ob, psys, false)) {
+ continue;
+ }
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+ if (draw_as == PART_DRAW_PATH) {
+ struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp, hairs, NULL);
+ }
+ }
+ }
+
+ /* Make flat object selectable in ortho view if wireframe is enabled. */
+ if ((draw_ctx->v3d->overlay.flag & V3D_OVERLAY_WIREFRAMES) ||
+ (ob->dtx & OB_DRAWWIRE) ||
+ (ob->dt == OB_WIRE))
+ {
+ int flat_axis = 0;
+ bool is_flat_object_viewed_from_side = (draw_ctx->rv3d->persp == RV3D_ORTHO) &&
+ DRW_object_is_flat(ob, &flat_axis) &&
+ DRW_object_axis_orthogonal_to_view(ob, flat_axis);
+
+ if (is_flat_object_viewed_from_side) {
+ /* Avoid losing flat objects when in ortho views (see T56549) */
+ struct GPUBatch *geom = DRW_cache_object_wire_outline_get(ob);
+ DRW_shgroup_call_object_add(stl->g_data->depth_shgrp, geom, ob);
+ return;
+ }
+ }
+
+ const bool is_active = (ob == draw_ctx->obact);
+ const bool use_hide = is_active && DRW_object_use_hide_faces(ob);
+
+ struct GPUBatch *geom = DRW_cache_object_surface_get_ex(ob, use_hide);
+ if (geom) {
+ const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->flag2 & V3D_BACKFACE_CULLING));
+ /* Depth Prepass */
+ DRW_shgroup_call_add((do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob->obmat);
+ }
+}
+
+static void basic_cache_finish(void *vedata)
+{
+ BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
+
+ UNUSED_VARS(stl);
+}
+
+static void basic_draw_scene(void *vedata)
+{
+ BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
+
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+}
+
+static void basic_engine_free(void)
+{
+ /* all shaders are builtin */
+}
+
+static const DrawEngineDataSize basic_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data);
+
+DrawEngineType draw_engine_basic_type = {
+ NULL, NULL,
+ N_("Basic"),
+ &basic_data_size,
+ &basic_engine_init,
+ &basic_engine_free,
+ &basic_cache_init,
+ &basic_cache_populate,
+ &basic_cache_finish,
+ NULL,
+ &basic_draw_scene,
+ NULL,
+ NULL,
+ NULL,
+};
+
+/* Note: currently unused, we may want to register so we can see this when debugging the view. */
+
+RenderEngineType DRW_engine_viewport_basic_type = {
+ NULL, NULL,
+ BASIC_ENGINE, N_("Basic"), RE_INTERNAL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &draw_engine_basic_type,
+ {NULL, NULL, NULL}
+};
+
+
+#undef BASIC_ENGINE
diff --git a/source/blender/draw/engines/basic/basic_engine.h b/source/blender/draw/engines/basic/basic_engine.h
new file mode 100644
index 00000000000..0adf99835a2
--- /dev/null
+++ b/source/blender/draw/engines/basic/basic_engine.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file basic_engine.h
+ * \ingroup draw_engine
+ */
+
+#ifndef __BASIC_ENGINE_H__
+#define __BASIC_ENGINE_H__
+
+extern DrawEngineType draw_engine_basic_type;
+extern RenderEngineType DRW_engine_viewport_basic_type;
+
+#endif /* __BASIC_ENGINE_H__ */
diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c
new file mode 100644
index 00000000000..d111c28b256
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_bloom.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_bloom.c
+ * \ingroup draw_engine
+ *
+ * Eevee's bloom shader.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+
+#include "BKE_global.h" /* for G.debug_value */
+
+#include "GPU_extensions.h"
+#include "GPU_texture.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+
+static struct {
+ /* Bloom */
+ struct GPUShader *bloom_blit_sh[2];
+ struct GPUShader *bloom_downsample_sh[2];
+ struct GPUShader *bloom_upsample_sh[2];
+ struct GPUShader *bloom_resolve_sh[2];
+} e_data = {{NULL}}; /* Engine data */
+
+extern char datatoc_effect_bloom_frag_glsl[];
+
+static void eevee_create_shader_bloom(void)
+{
+ e_data.bloom_blit_sh[0] = DRW_shader_create_fullscreen(
+ datatoc_effect_bloom_frag_glsl,
+ "#define STEP_BLIT\n");
+ e_data.bloom_blit_sh[1] = DRW_shader_create_fullscreen(
+ datatoc_effect_bloom_frag_glsl,
+ "#define STEP_BLIT\n"
+ "#define HIGH_QUALITY\n");
+
+ e_data.bloom_downsample_sh[0] = DRW_shader_create_fullscreen(
+ datatoc_effect_bloom_frag_glsl,
+ "#define STEP_DOWNSAMPLE\n");
+ e_data.bloom_downsample_sh[1] = DRW_shader_create_fullscreen(
+ datatoc_effect_bloom_frag_glsl,
+ "#define STEP_DOWNSAMPLE\n"
+ "#define HIGH_QUALITY\n");
+
+ e_data.bloom_upsample_sh[0] = DRW_shader_create_fullscreen(
+ datatoc_effect_bloom_frag_glsl,
+ "#define STEP_UPSAMPLE\n");
+ e_data.bloom_upsample_sh[1] = DRW_shader_create_fullscreen(
+ datatoc_effect_bloom_frag_glsl,
+ "#define STEP_UPSAMPLE\n"
+ "#define HIGH_QUALITY\n");
+
+ e_data.bloom_resolve_sh[0] = DRW_shader_create_fullscreen(
+ datatoc_effect_bloom_frag_glsl,
+ "#define STEP_RESOLVE\n");
+ e_data.bloom_resolve_sh[1] = DRW_shader_create_fullscreen(
+ datatoc_effect_bloom_frag_glsl,
+ "#define STEP_RESOLVE\n"
+ "#define HIGH_QUALITY\n");
+}
+
+int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) {
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* Shaders */
+ if (!e_data.bloom_blit_sh[0]) {
+ eevee_create_shader_bloom();
+ }
+
+ /* Bloom */
+ int blitsize[2], texsize[2];
+
+ /* Blit Buffer */
+ effects->source_texel_size[0] = 1.0f / viewport_size[0];
+ effects->source_texel_size[1] = 1.0f / viewport_size[1];
+
+ blitsize[0] = (int)viewport_size[0];
+ blitsize[1] = (int)viewport_size[1];
+
+ effects->blit_texel_size[0] = 1.0f / (float)blitsize[0];
+ effects->blit_texel_size[1] = 1.0f / (float)blitsize[1];
+
+ effects->bloom_blit = DRW_texture_pool_query_2D(blitsize[0], blitsize[1], GPU_R11F_G11F_B10F,
+ &draw_engine_eevee_type);
+
+ GPU_framebuffer_ensure_config(&fbl->bloom_blit_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->bloom_blit)
+ });
+
+ /* Parameters */
+ const float threshold = scene_eval->eevee.bloom_threshold;
+ const float knee = scene_eval->eevee.bloom_knee;
+ const float intensity = scene_eval->eevee.bloom_intensity;
+ const float *color = scene_eval->eevee.bloom_color;
+ const float radius = scene_eval->eevee.bloom_radius;
+ effects->bloom_clamp = scene_eval->eevee.bloom_clamp;
+
+ /* determine the iteration count */
+ const float minDim = (float)MIN2(blitsize[0], blitsize[1]);
+ const float maxIter = (radius - 8.0f) + log(minDim) / log(2);
+ const int maxIterInt = effects->bloom_iteration_len = (int)maxIter;
+
+ CLAMP(effects->bloom_iteration_len, 1, MAX_BLOOM_STEP);
+
+ effects->bloom_sample_scale = 0.5f + maxIter - (float)maxIterInt;
+ effects->bloom_curve_threshold[0] = threshold - knee;
+ effects->bloom_curve_threshold[1] = knee * 2.0f;
+ effects->bloom_curve_threshold[2] = 0.25f / max_ff(1e-5f, knee);
+ effects->bloom_curve_threshold[3] = threshold;
+
+ mul_v3_v3fl(effects->bloom_color, color, intensity);
+
+ /* Downsample buffers */
+ copy_v2_v2_int(texsize, blitsize);
+ for (int i = 0; i < effects->bloom_iteration_len; ++i) {
+ texsize[0] /= 2; texsize[1] /= 2;
+
+ texsize[0] = MAX2(texsize[0], 2);
+ texsize[1] = MAX2(texsize[1], 2);
+
+ effects->downsamp_texel_size[i][0] = 1.0f / (float)texsize[0];
+ effects->downsamp_texel_size[i][1] = 1.0f / (float)texsize[1];
+
+ effects->bloom_downsample[i] = DRW_texture_pool_query_2D(texsize[0], texsize[1], GPU_R11F_G11F_B10F,
+ &draw_engine_eevee_type);
+ GPU_framebuffer_ensure_config(&fbl->bloom_down_fb[i], {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->bloom_downsample[i])
+ });
+ }
+
+ /* Upsample buffers */
+ copy_v2_v2_int(texsize, blitsize);
+ for (int i = 0; i < effects->bloom_iteration_len - 1; ++i) {
+ texsize[0] /= 2; texsize[1] /= 2;
+
+ texsize[0] = MAX2(texsize[0], 2);
+ texsize[1] = MAX2(texsize[1], 2);
+
+ effects->bloom_upsample[i] = DRW_texture_pool_query_2D(texsize[0], texsize[1], GPU_R11F_G11F_B10F,
+ &draw_engine_eevee_type);
+ GPU_framebuffer_ensure_config(&fbl->bloom_accum_fb[i], {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->bloom_upsample[i])
+ });
+ }
+
+ return EFFECT_BLOOM | EFFECT_POST_BUFFER;
+ }
+
+ /* Cleanup to release memory */
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_blit_fb);
+
+ for (int i = 0; i < MAX_BLOOM_STEP - 1; ++i) {
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_down_fb[i]);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_accum_fb[i]);
+ }
+
+ return 0;
+}
+
+static DRWShadingGroup *eevee_create_bloom_pass(
+ const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, bool upsample)
+{
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ *pass = DRW_pass_create(name, DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, *pass);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ DRW_shgroup_uniform_texture_ref(grp, "sourceBuffer", &effects->unf_source_buffer);
+ DRW_shgroup_uniform_vec2(grp, "sourceBufferTexelSize", effects->unf_source_texel_size, 1);
+ if (upsample) {
+ DRW_shgroup_uniform_texture_ref(grp, "baseBuffer", &effects->unf_base_buffer);
+ DRW_shgroup_uniform_float(grp, "sampleScale", &effects->bloom_sample_scale, 1);
+ }
+
+ return grp;
+}
+
+void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & EFFECT_BLOOM) != 0) {
+ /** Bloom algorithm
+ *
+ * Overview :
+ * - Downsample the color buffer doing a small blur during each step.
+ * - Accumulate bloom color using previously downsampled color buffers
+ * and do an upsample blur for each new accumulated layer.
+ * - Finally add accumulation buffer onto the source color buffer.
+ *
+ * [1/1] is original copy resolution (can be half or quater res for performance)
+ *
+ * [DOWNSAMPLE CHAIN] [UPSAMPLE CHAIN]
+ *
+ * Source Color ── [Blit] ──> Bright Color Extract [1/1] Final Color
+ * | Λ
+ * [Downsample First] Source Color ─> + [Resolve]
+ * v |
+ * Color Downsampled [1/2] ────────────> + Accumulation Buffer [1/2]
+ * | Λ
+ * ─── ───
+ * Repeat Repeat
+ * ─── ───
+ * v |
+ * Color Downsampled [1/N-1] ──────────> + Accumulation Buffer [1/N-1]
+ * | Λ
+ * [Downsample] [Upsample]
+ * v |
+ * Color Downsampled [1/N] ─────────────────────────┘
+ **/
+ DRWShadingGroup *grp;
+ const bool use_highres = true;
+ const bool use_antiflicker = true;
+ eevee_create_bloom_pass("Bloom Downsample First", effects, e_data.bloom_downsample_sh[use_antiflicker], &psl->bloom_downsample_first, false);
+ eevee_create_bloom_pass("Bloom Downsample", effects, e_data.bloom_downsample_sh[0], &psl->bloom_downsample, false);
+ eevee_create_bloom_pass("Bloom Upsample", effects, e_data.bloom_upsample_sh[use_highres], &psl->bloom_upsample, true);
+
+ grp = eevee_create_bloom_pass("Bloom Blit", effects, e_data.bloom_blit_sh[use_antiflicker], &psl->bloom_blit, false);
+ DRW_shgroup_uniform_vec4(grp, "curveThreshold", effects->bloom_curve_threshold, 1);
+ DRW_shgroup_uniform_float(grp, "clampIntensity", &effects->bloom_clamp, 1);
+
+ grp = eevee_create_bloom_pass("Bloom Resolve", effects, e_data.bloom_resolve_sh[use_highres], &psl->bloom_resolve, true);
+ DRW_shgroup_uniform_vec3(grp, "bloomColor", effects->bloom_color, 1);
+ }
+}
+
+void EEVEE_bloom_draw(EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ /* Bloom */
+ if ((effects->enabled_effects & EFFECT_BLOOM) != 0) {
+ struct GPUTexture *last;
+
+ /* Extract bright pixels */
+ copy_v2_v2(effects->unf_source_texel_size, effects->source_texel_size);
+ effects->unf_source_buffer = effects->source_buffer;
+
+ GPU_framebuffer_bind(fbl->bloom_blit_fb);
+ DRW_draw_pass(psl->bloom_blit);
+
+ /* Downsample */
+ copy_v2_v2(effects->unf_source_texel_size, effects->blit_texel_size);
+ effects->unf_source_buffer = effects->bloom_blit;
+
+ GPU_framebuffer_bind(fbl->bloom_down_fb[0]);
+ DRW_draw_pass(psl->bloom_downsample_first);
+
+ last = effects->bloom_downsample[0];
+
+ for (int i = 1; i < effects->bloom_iteration_len; ++i) {
+ copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i - 1]);
+ effects->unf_source_buffer = last;
+
+ GPU_framebuffer_bind(fbl->bloom_down_fb[i]);
+ DRW_draw_pass(psl->bloom_downsample);
+
+ /* Used in next loop */
+ last = effects->bloom_downsample[i];
+ }
+
+ /* Upsample and accumulate */
+ for (int i = effects->bloom_iteration_len - 2; i >= 0; --i) {
+ copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]);
+ effects->unf_source_buffer = effects->bloom_downsample[i];
+ effects->unf_base_buffer = last;
+
+ GPU_framebuffer_bind(fbl->bloom_accum_fb[i]);
+ DRW_draw_pass(psl->bloom_upsample);
+
+ last = effects->bloom_upsample[i];
+ }
+
+ /* Resolve */
+ copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[0]);
+ effects->unf_source_buffer = last;
+ effects->unf_base_buffer = effects->source_buffer;
+
+ GPU_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->bloom_resolve);
+ SWAP_BUFFERS();
+ }
+}
+
+void EEVEE_bloom_free(void)
+{
+ for (int i = 0; i < 2; ++i) {
+ DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[i]);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
new file mode 100644
index 00000000000..636e532555f
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_data.c
+ * \ingroup draw_engine
+ *
+ * All specific data handler for Objects, Lights, ViewLayers, ...
+ */
+
+#include "DRW_render.h"
+
+#include "eevee_private.h"
+#include "eevee_lightcache.h"
+
+void EEVEE_view_layer_data_free(void *storage)
+{
+ EEVEE_ViewLayerData *sldata = (EEVEE_ViewLayerData *)storage;
+
+ /* Lights */
+ MEM_SAFE_FREE(sldata->lamps);
+ DRW_UBO_FREE_SAFE(sldata->light_ubo);
+ DRW_UBO_FREE_SAFE(sldata->shadow_ubo);
+ DRW_UBO_FREE_SAFE(sldata->shadow_render_ubo);
+ GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_target_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_store_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_target_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_store_fb);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[0].shadow_casters);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[0].flags);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[1].shadow_casters);
+ MEM_SAFE_FREE(sldata->shcasters_buffers[1].flags);
+
+ if (sldata->fallback_lightcache) {
+ EEVEE_lightcache_free(sldata->fallback_lightcache);
+ sldata->fallback_lightcache = NULL;
+ }
+
+ /* Probes */
+ MEM_SAFE_FREE(sldata->probes);
+ DRW_UBO_FREE_SAFE(sldata->probe_ubo);
+ DRW_UBO_FREE_SAFE(sldata->grid_ubo);
+ DRW_UBO_FREE_SAFE(sldata->planar_ubo);
+ DRW_UBO_FREE_SAFE(sldata->common_ubo);
+ DRW_UBO_FREE_SAFE(sldata->clip_ubo);
+}
+
+EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void)
+{
+ return (EEVEE_ViewLayerData *)DRW_view_layer_engine_data_get(
+ &draw_engine_eevee_type);
+}
+
+EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer)
+{
+ EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_ensure_ex(
+ view_layer, &draw_engine_eevee_type, &EEVEE_view_layer_data_free);
+
+ if (*sldata == NULL) {
+ *sldata = MEM_callocN(sizeof(**sldata), "EEVEE_ViewLayerData");
+ }
+
+ return *sldata;
+}
+
+EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void)
+{
+ EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_ensure(
+ &draw_engine_eevee_type, &EEVEE_view_layer_data_free);
+
+ if (*sldata == NULL) {
+ *sldata = MEM_callocN(sizeof(**sldata), "EEVEE_ViewLayerData");
+ }
+
+ return *sldata;
+}
+
+/* Object data. */
+
+static void eevee_object_data_init(DrawData *dd)
+{
+ EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)dd;
+ eevee_data->shadow_caster_id = -1;
+}
+
+EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob)
+{
+ if (ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP)) {
+ return NULL;
+ }
+ return (EEVEE_ObjectEngineData *)DRW_drawdata_get(
+ &ob->id, &draw_engine_eevee_type);
+}
+
+EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob)
+{
+ BLI_assert(!ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP));
+ return (EEVEE_ObjectEngineData *)DRW_drawdata_ensure(
+ &ob->id,
+ &draw_engine_eevee_type,
+ sizeof(EEVEE_ObjectEngineData),
+ eevee_object_data_init,
+ NULL);
+}
+
+/* Light probe data. */
+
+static void eevee_lightprobe_data_init(DrawData *dd)
+{
+ EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)dd;
+ ped->need_update = false;
+}
+
+EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob)
+{
+ if (ob->type != OB_LIGHTPROBE) {
+ return NULL;
+ }
+ return (EEVEE_LightProbeEngineData *)DRW_drawdata_get(
+ &ob->id, &draw_engine_eevee_type);
+}
+
+EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob)
+{
+ BLI_assert(ob->type == OB_LIGHTPROBE);
+ return (EEVEE_LightProbeEngineData *)DRW_drawdata_ensure(
+ &ob->id,
+ &draw_engine_eevee_type,
+ sizeof(EEVEE_LightProbeEngineData),
+ eevee_lightprobe_data_init,
+ NULL);
+}
+
+/* Lamp data. */
+
+static void eevee_lamp_data_init(DrawData *dd)
+{
+ EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)dd;
+ led->need_update = true;
+ led->prev_cube_shadow_id = -1;
+}
+
+EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob)
+{
+ if (ob->type != OB_LAMP) {
+ return NULL;
+ }
+ return (EEVEE_LampEngineData *)DRW_drawdata_get(
+ &ob->id, &draw_engine_eevee_type);
+}
+
+EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob)
+{
+ BLI_assert(ob->type == OB_LAMP);
+ return (EEVEE_LampEngineData *)DRW_drawdata_ensure(
+ &ob->id,
+ &draw_engine_eevee_type,
+ sizeof(EEVEE_LampEngineData),
+ eevee_lamp_data_init,
+ NULL);
+}
+
+/* World data. */
+
+static void eevee_world_data_init(DrawData *dd)
+{
+ EEVEE_WorldEngineData *wed = (EEVEE_WorldEngineData *)dd;
+ wed->dd.recalc |= 1;
+}
+
+EEVEE_WorldEngineData *EEVEE_world_data_get(World *wo)
+{
+ return (EEVEE_WorldEngineData *)DRW_drawdata_get(
+ &wo->id, &draw_engine_eevee_type);
+}
+
+EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo)
+{
+ return (EEVEE_WorldEngineData *)DRW_drawdata_ensure(
+ &wo->id,
+ &draw_engine_eevee_type,
+ sizeof(EEVEE_WorldEngineData),
+ eevee_world_data_init,
+ NULL);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
new file mode 100644
index 00000000000..602654068ff
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_depth_of_field.c
+ * \ingroup draw_engine
+ *
+ * Depth of field post process effect.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_rand.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_global.h" /* for G.debug_value */
+#include "BKE_camera.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_animsys.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
+
+#include "ED_screen.h"
+
+static struct {
+ /* Depth Of Field */
+ struct GPUShader *dof_downsample_sh[2];
+ struct GPUShader *dof_scatter_sh[2];
+ struct GPUShader *dof_resolve_sh[2];
+} e_data = {{NULL}}; /* Engine data */
+
+extern char datatoc_effect_dof_vert_glsl[];
+extern char datatoc_effect_dof_frag_glsl[];
+
+static void eevee_create_shader_depth_of_field(const bool use_alpha)
+{
+ e_data.dof_downsample_sh[use_alpha] = DRW_shader_create_fullscreen(
+ datatoc_effect_dof_frag_glsl, use_alpha ?
+ "#define USE_ALPHA_DOF\n"
+ "#define STEP_DOWNSAMPLE\n" :
+ "#define STEP_DOWNSAMPLE\n");
+ e_data.dof_scatter_sh[use_alpha] = DRW_shader_create(
+ datatoc_effect_dof_vert_glsl, NULL,
+ datatoc_effect_dof_frag_glsl, use_alpha ?
+ "#define USE_ALPHA_DOF\n"
+ "#define STEP_SCATTER\n" :
+ "#define STEP_SCATTER\n");
+ e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(
+ datatoc_effect_dof_frag_glsl, use_alpha ?
+ "#define USE_ALPHA_DOF\n"
+ "#define STEP_RESOLVE\n" :
+ "#define STEP_RESOLVE\n");
+}
+
+int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_DOF_ENABLED) {
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ const bool use_alpha = !DRW_state_draw_background();
+
+ if (!e_data.dof_downsample_sh[use_alpha]) {
+ eevee_create_shader_depth_of_field(use_alpha);
+ }
+
+ if (camera) {
+ const float *viewport_size = DRW_viewport_size_get();
+ Camera *cam = (Camera *)camera->data;
+
+ /* Retrieve Near and Far distance */
+ effects->dof_near_far[0] = -cam->clipsta;
+ effects->dof_near_far[1] = -cam->clipend;
+
+ int buffer_size[2] = {(int)viewport_size[0] / 2, (int)viewport_size[1] / 2};
+
+ GPUTextureFormat down_format = DRW_state_draw_background() ? GPU_R11F_G11F_B10F : GPU_RGBA16F;
+
+ effects->dof_down_near = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], down_format,
+ &draw_engine_eevee_type);
+ effects->dof_down_far = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], down_format,
+ &draw_engine_eevee_type);
+ effects->dof_coc = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], GPU_RG16F,
+ &draw_engine_eevee_type);
+
+ GPU_framebuffer_ensure_config(&fbl->dof_down_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->dof_down_near),
+ GPU_ATTACHMENT_TEXTURE(effects->dof_down_far),
+ GPU_ATTACHMENT_TEXTURE(effects->dof_coc)
+ });
+
+ /* Go full 32bits for rendering and reduce the color artifacts. */
+ GPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F;
+
+ effects->dof_blur = DRW_texture_pool_query_2D(buffer_size[0] * 2, buffer_size[1], fb_format,
+ &draw_engine_eevee_type);
+
+ GPU_framebuffer_ensure_config(&fbl->dof_scatter_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->dof_blur),
+ });
+
+ if (!DRW_state_draw_background()) {
+ effects->dof_blur_alpha = DRW_texture_pool_query_2D(buffer_size[0] * 2, buffer_size[1], GPU_R32F,
+ &draw_engine_eevee_type);
+ GPU_framebuffer_texture_attach(fbl->dof_scatter_fb, effects->dof_blur_alpha, 1, 0);
+ }
+
+ /* Parameters */
+ /* TODO UI Options */
+ float fstop = cam->gpu_dof.fstop;
+ float blades = cam->gpu_dof.num_blades;
+ float rotation = cam->gpu_dof.rotation;
+ float ratio = 1.0f / cam->gpu_dof.ratio;
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ float focus_dist = BKE_camera_object_dof_distance(camera);
+ float focal_len = cam->lens;
+
+ /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
+ * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though
+ * because the shader reads coordinates in world space, which is in blender units.
+ * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */
+ float scale = (scene_eval->unit.system) ? scene_eval->unit.scale_length : 1.0f;
+ float scale_camera = 0.001f / scale;
+ /* we want radius here for the aperture number */
+ float aperture = 0.5f * scale_camera * focal_len / fstop;
+ float focal_len_scaled = scale_camera * focal_len;
+ float sensor_scaled = scale_camera * sensor;
+
+ if (rv3d != NULL) {
+ sensor_scaled *= rv3d->viewcamtexcofac[0];
+ }
+
+ effects->dof_params[0] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
+ effects->dof_params[1] = -focus_dist;
+ effects->dof_params[2] = viewport_size[0] / sensor_scaled;
+ effects->dof_bokeh[0] = rotation;
+ effects->dof_bokeh[1] = ratio;
+ effects->dof_bokeh[2] = scene_eval->eevee.bokeh_max_size;
+
+ /* Precompute values to save instructions in fragment shader. */
+ effects->dof_bokeh_sides[0] = blades;
+ effects->dof_bokeh_sides[1] = 2.0f * M_PI / blades;
+ effects->dof_bokeh_sides[2] = blades / (2.0f * M_PI);
+ effects->dof_bokeh_sides[3] = cosf(M_PI / blades);
+
+ return EFFECT_DOF | EFFECT_POST_BUFFER;
+ }
+ }
+
+ /* Cleanup to release memory */
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->dof_down_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->dof_scatter_fb);
+
+ return 0;
+}
+
+void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ if ((effects->enabled_effects & EFFECT_DOF) != 0) {
+ /** Depth of Field algorithm
+ *
+ * Overview :
+ * - Downsample the color buffer into 2 buffers weighted with
+ * CoC values. Also output CoC into a texture.
+ * - Shoot quads for every pixel and expand it depending on the CoC.
+ * Do one pass for near Dof and one pass for far Dof.
+ * - Finally composite the 2 blurred buffers with the original render.
+ **/
+ DRWShadingGroup *grp;
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ const bool use_alpha = !DRW_state_draw_background();
+
+ psl->dof_down = DRW_pass_create("DoF Downsample", DRW_STATE_WRITE_COLOR);
+
+ grp = DRW_shgroup_create(e_data.dof_downsample_sh[use_alpha], psl->dof_down);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1);
+ DRW_shgroup_uniform_vec3(grp, "dofParams", effects->dof_params, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->dof_scatter = DRW_pass_create("DoF Scatter", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE_FULL);
+
+ /* This create an empty batch of N triangles to be positioned
+ * by the vertex shader 0.4ms against 6ms with instancing */
+ const float *viewport_size = DRW_viewport_size_get();
+ const int sprite_len = ((int)viewport_size[0] / 2) * ((int)viewport_size[1] / 2); /* brackets matters */
+ grp = DRW_shgroup_empty_tri_batch_create(e_data.dof_scatter_sh[use_alpha], psl->dof_scatter, sprite_len);
+ DRW_shgroup_uniform_texture_ref(grp, "nearBuffer", &effects->dof_down_near);
+ DRW_shgroup_uniform_texture_ref(grp, "farBuffer", &effects->dof_down_far);
+ DRW_shgroup_uniform_texture_ref(grp, "cocBuffer", &effects->dof_coc);
+ DRW_shgroup_uniform_vec4(grp, "bokehParams", effects->dof_bokeh, 2);
+
+ psl->dof_resolve = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR);
+
+ grp = DRW_shgroup_create(e_data.dof_resolve_sh[use_alpha], psl->dof_resolve);
+ DRW_shgroup_uniform_texture_ref(grp, "scatterBuffer", &effects->dof_blur);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1);
+ DRW_shgroup_uniform_vec3(grp, "dofParams", effects->dof_params, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ if (use_alpha) {
+ DRW_shgroup_uniform_texture_ref(grp, "scatterAlphaBuffer", &effects->dof_blur_alpha);
+ }
+ }
+}
+
+void EEVEE_depth_of_field_draw(EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ /* Depth Of Field */
+ if ((effects->enabled_effects & EFFECT_DOF) != 0) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* Downsample */
+ GPU_framebuffer_bind(fbl->dof_down_fb);
+ DRW_draw_pass(psl->dof_down);
+
+ /* Scatter */
+ GPU_framebuffer_bind(fbl->dof_scatter_fb);
+ GPU_framebuffer_clear_color(fbl->dof_scatter_fb, clear_col);
+ DRW_draw_pass(psl->dof_scatter);
+
+ /* Resolve */
+ GPU_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->dof_resolve);
+ SWAP_BUFFERS();
+ }
+}
+
+void EEVEE_depth_of_field_free(void)
+{
+ for (int i = 0; i < 2; ++i) {
+ DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.dof_scatter_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh[i]);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
new file mode 100644
index 00000000000..48a73ccef18
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_effects.c
+ * \ingroup draw_engine
+ *
+ * Gather all screen space effects technique such as Bloom, Motion Blur, DoF, SSAO, SSR, ...
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_global.h" /* for G.debug_value */
+
+#include "BLI_string_utils.h"
+
+#include "eevee_private.h"
+#include "GPU_texture.h"
+#include "GPU_extensions.h"
+#include "GPU_state.h"
+
+static struct {
+ /* Downsample Depth */
+ struct GPUShader *minz_downlevel_sh;
+ struct GPUShader *maxz_downlevel_sh;
+ struct GPUShader *minz_downdepth_sh;
+ struct GPUShader *maxz_downdepth_sh;
+ struct GPUShader *minz_downdepth_layer_sh;
+ struct GPUShader *maxz_downdepth_layer_sh;
+ struct GPUShader *maxz_copydepth_layer_sh;
+ struct GPUShader *minz_copydepth_sh;
+ struct GPUShader *maxz_copydepth_sh;
+
+ /* Simple Downsample */
+ struct GPUShader *downsample_sh;
+ struct GPUShader *downsample_cube_sh;
+
+ /* Theses are just references, not actually allocated */
+ struct GPUTexture *depth_src;
+ struct GPUTexture *color_src;
+
+ int depth_src_layer;
+ float cube_texel_size;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_effect_minmaxz_frag_glsl[];
+extern char datatoc_effect_downsample_frag_glsl[];
+extern char datatoc_effect_downsample_cube_frag_glsl[];
+extern char datatoc_lightprobe_vert_glsl[];
+extern char datatoc_lightprobe_geom_glsl[];
+
+
+static void eevee_create_shader_downsample(void)
+{
+ e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
+ e_data.downsample_cube_sh = DRW_shader_create(
+ datatoc_lightprobe_vert_glsl,
+ datatoc_lightprobe_geom_glsl,
+ datatoc_effect_downsample_cube_frag_glsl, NULL);
+
+ e_data.minz_downlevel_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MIN_PASS\n");
+ e_data.maxz_downlevel_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MAX_PASS\n");
+ e_data.minz_downdepth_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MIN_PASS\n");
+ e_data.maxz_downdepth_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MAX_PASS\n");
+ e_data.minz_downdepth_layer_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MIN_PASS\n"
+ "#define LAYERED\n");
+ e_data.maxz_downdepth_layer_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MAX_PASS\n"
+ "#define LAYERED\n");
+ e_data.maxz_copydepth_layer_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MAX_PASS\n"
+ "#define COPY_DEPTH\n"
+ "#define LAYERED\n");
+ e_data.minz_copydepth_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MIN_PASS\n"
+ "#define COPY_DEPTH\n");
+ e_data.maxz_copydepth_sh = DRW_shader_create_fullscreen(
+ datatoc_effect_minmaxz_frag_glsl,
+ "#define MAX_PASS\n"
+ "#define COPY_DEPTH\n");
+}
+
+#define SETUP_BUFFER(tex, fb, fb_color) { \
+ GPUTextureFormat format = (DRW_state_is_scene_render()) ? GPU_RGBA32F : GPU_RGBA16F; \
+ DRW_texture_ensure_fullscreen_2D(&tex, format, DRW_TEX_FILTER | DRW_TEX_MIPMAP); \
+ GPU_framebuffer_ensure_config(&fb, { \
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth), \
+ GPU_ATTACHMENT_TEXTURE(tex), \
+ }); \
+ GPU_framebuffer_ensure_config(&fb_color, { \
+ GPU_ATTACHMENT_NONE, \
+ GPU_ATTACHMENT_TEXTURE(tex), \
+ }); \
+}
+
+#define CLEANUP_BUFFER(tex, fb, fb_color) { \
+ /* Cleanup to release memory */ \
+ DRW_TEXTURE_FREE_SAFE(tex); \
+ GPU_FRAMEBUFFER_FREE_SAFE(fb); \
+ GPU_FRAMEBUFFER_FREE_SAFE(fb_color); \
+}
+
+void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera, const bool minimal)
+{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ const float *viewport_size = DRW_viewport_size_get();
+ int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ /* Shaders */
+ if (!e_data.downsample_sh) {
+ eevee_create_shader_downsample();
+ }
+
+ if (!stl->effects) {
+ stl->effects = MEM_callocN(sizeof(EEVEE_EffectsInfo), "EEVEE_EffectsInfo");
+ }
+
+ effects = stl->effects;
+
+ effects->enabled_effects = 0;
+ effects->enabled_effects |= (G.debug_value == 9) ? EFFECT_VELOCITY_BUFFER : 0;
+ effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata, camera);
+ effects->enabled_effects |= EEVEE_bloom_init(sldata, vedata);
+ effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata, camera);
+ effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata);
+ effects->enabled_effects |= EEVEE_occlusion_init(sldata, vedata);
+ effects->enabled_effects |= EEVEE_subsurface_init(sldata, vedata);
+ effects->enabled_effects |= EEVEE_screen_raytrace_init(sldata, vedata);
+ effects->enabled_effects |= EEVEE_volumes_init(sldata, vedata);
+
+ /* Force normal buffer creation. */
+ if (DRW_state_is_image_render() && !minimal &&
+ (view_layer->passflag & SCE_PASS_NORMAL) != 0)
+ {
+ effects->enabled_effects |= EFFECT_NORMAL_BUFFER;
+ }
+
+ /**
+ * Ping Pong buffer
+ */
+ if ((effects->enabled_effects & EFFECT_POST_BUFFER) != 0) {
+ SETUP_BUFFER(txl->color_post, fbl->effect_fb, fbl->effect_color_fb);
+ }
+ else {
+ CLEANUP_BUFFER(txl->color_post, fbl->effect_fb, fbl->effect_color_fb);
+ }
+
+ /**
+ * MinMax Pyramid
+ */
+ const bool half_res_hiz = true;
+ int size[2], div;
+ common_data->hiz_mip_offset = (half_res_hiz) ? 1 : 0;
+ div = (half_res_hiz) ? 2 : 1;
+ size[0] = max_ii(size_fs[0] / div, 1);
+ size[1] = max_ii(size_fs[1] / div, 1);
+
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ /* Intel gpu seems to have problem rendering to only depth format */
+ DRW_texture_ensure_2D(&txl->maxzbuffer, size[0], size[1], GPU_R32F, DRW_TEX_MIPMAP);
+ }
+ else {
+ DRW_texture_ensure_2D(&txl->maxzbuffer, size[0], size[1], GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP);
+ }
+
+ if (fbl->downsample_fb == NULL) {
+ fbl->downsample_fb = GPU_framebuffer_create();
+ }
+
+ /**
+ * Compute Mipmap texel alignment.
+ */
+ for (int i = 0; i < 10; ++i) {
+ int mip_size[2];
+ GPU_texture_get_mipmap_size(txl->color, i, mip_size);
+ common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, i));
+ common_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, i));
+ }
+
+ /**
+ * Normal buffer for deferred passes.
+ */
+ if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) {
+ effects->ssr_normal_input = DRW_texture_pool_query_2D(size_fs[0], size_fs[1], GPU_RG16,
+ &draw_engine_eevee_type);
+
+ GPU_framebuffer_texture_attach(fbl->main_fb, effects->ssr_normal_input, 1, 0);
+ }
+ else {
+ effects->ssr_normal_input = NULL;
+ }
+
+ /**
+ * Motion vector buffer for correct TAA / motion blur.
+ */
+ if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) {
+ effects->velocity_tx = DRW_texture_pool_query_2D(size_fs[0], size_fs[1], GPU_RG16,
+ &draw_engine_eevee_type);
+
+ /* TODO output objects velocity during the mainpass. */
+ // GPU_framebuffer_texture_attach(fbl->main_fb, effects->velocity_tx, 1, 0);
+
+ GPU_framebuffer_ensure_config(&fbl->velocity_resolve_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->velocity_tx)
+ });
+ }
+ else {
+ effects->velocity_tx = NULL;
+ }
+
+ /**
+ * Setup depth double buffer.
+ */
+ if ((effects->enabled_effects & EFFECT_DEPTH_DOUBLE_BUFFER) != 0) {
+ DRW_texture_ensure_fullscreen_2D(&txl->depth_double_buffer, GPU_DEPTH24_STENCIL8, 0);
+
+ GPU_framebuffer_ensure_config(&fbl->double_buffer_depth_fb, {
+ GPU_ATTACHMENT_TEXTURE(txl->depth_double_buffer)
+ });
+ }
+ else {
+ /* Cleanup to release memory */
+ DRW_TEXTURE_FREE_SAFE(txl->depth_double_buffer);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer_depth_fb);
+ }
+
+ /**
+ * Setup double buffer so we can access last frame as it was before post processes.
+ */
+ if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) {
+ SETUP_BUFFER(txl->color_double_buffer, fbl->double_buffer_fb, fbl->double_buffer_color_fb);
+ }
+ else {
+ CLEANUP_BUFFER(txl->color_double_buffer, fbl->double_buffer_fb, fbl->double_buffer_color_fb);
+ }
+
+ if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) {
+ SETUP_BUFFER(txl->taa_history, fbl->taa_history_fb, fbl->taa_history_color_fb);
+ }
+ else {
+ CLEANUP_BUFFER(txl->taa_history, fbl->taa_history_fb, fbl->taa_history_color_fb);
+ }
+}
+
+void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ int downsample_write = DRW_STATE_WRITE_DEPTH;
+
+ /* Intel gpu seems to have problem rendering to only depth format.
+ * Use color texture instead. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ downsample_write = DRW_STATE_WRITE_COLOR;
+ }
+
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ {
+ psl->color_downsample_ps = DRW_pass_create(
+ "Downsample", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src);
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
+ static int zero = 0;
+ static uint six = 6;
+ psl->color_downsample_cube_ps = DRW_pass_create(
+ "Downsample Cube", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_cube_sh, psl->color_downsample_cube_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src);
+ DRW_shgroup_uniform_float(grp, "texelSize", &e_data.cube_texel_size, 1);
+ DRW_shgroup_uniform_int(grp, "Layer", &zero, 1);
+ DRW_shgroup_call_instances_add(grp, quad, NULL, &six);
+ }
+
+ {
+ /* Perform min/max downsample */
+ DRWShadingGroup *grp;
+
+ psl->maxz_downlevel_ps = DRW_pass_create(
+ "HiZ Max Down Level", downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_downlevel_sh, psl->maxz_downlevel_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &txl->maxzbuffer);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ /* Copy depth buffer to halfres top level of HiZ */
+
+ psl->maxz_downdepth_ps = DRW_pass_create(
+ "HiZ Max Copy Depth Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_downdepth_sh, psl->maxz_downdepth_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->maxz_downdepth_layer_ps = DRW_pass_create(
+ "HiZ Max Copy DepthLayer Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_downdepth_layer_sh, psl->maxz_downdepth_layer_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->maxz_copydepth_ps = DRW_pass_create(
+ "HiZ Max Copy Depth Fullres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_copydepth_sh, psl->maxz_copydepth_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->maxz_copydepth_layer_ps = DRW_pass_create(
+ "HiZ Max Copy DepthLayer Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.maxz_copydepth_layer_sh, psl->maxz_copydepth_layer_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) {
+ /* This pass compute camera motions to the non moving objects. */
+ psl->velocity_resolve = DRW_pass_create(
+ "Velocity Resolve", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv);
+ DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+}
+
+#if 0 /* Not required for now */
+static void min_downsample_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->minz_downlevel_ps);
+}
+#endif
+
+static void max_downsample_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->maxz_downlevel_ps);
+}
+
+static void simple_downsample_cb(void *vedata, int UNUSED(level))
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ DRW_draw_pass(psl->color_downsample_ps);
+}
+
+static void simple_downsample_cube_cb(void *vedata, int level)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ e_data.cube_texel_size = (float)(1 << level) / (float)GPU_texture_width(e_data.color_src);
+ DRW_draw_pass(psl->color_downsample_cube_ps);
+}
+
+void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int layer)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+
+ e_data.depth_src = depth_src;
+ e_data.depth_src_layer = layer;
+
+#if 0 /* Not required for now */
+ DRW_stats_group_start("Min buffer");
+ /* Copy depth buffer to min texture top level */
+ GPU_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0);
+ GPU_framebuffer_bind(fbl->downsample_fb);
+ if (layer >= 0) {
+ DRW_draw_pass(psl->minz_downdepth_layer_ps);
+ }
+ else {
+ DRW_draw_pass(psl->minz_downdepth_ps);
+ }
+ GPU_framebuffer_texture_detach(stl->g_data->minzbuffer);
+
+ /* Create lower levels */
+ GPU_framebuffer_recursive_downsample(fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata);
+ DRW_stats_group_end();
+#endif
+ int minmax_size[3], depth_size[3];
+ GPU_texture_get_mipmap_size(depth_src, 0, depth_size);
+ GPU_texture_get_mipmap_size(txl->maxzbuffer, 0, minmax_size);
+ bool is_full_res_minmaxz = (minmax_size[0] == depth_size[0] && minmax_size[1] == depth_size[1]);
+
+ DRW_stats_group_start("Max buffer");
+ /* Copy depth buffer to max texture top level */
+ GPU_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0);
+ GPU_framebuffer_bind(fbl->downsample_fb);
+ if (layer >= 0) {
+ if (is_full_res_minmaxz) {
+ DRW_draw_pass(psl->maxz_copydepth_layer_ps);
+ }
+ else {
+ DRW_draw_pass(psl->maxz_downdepth_layer_ps);
+ }
+ }
+ else {
+ if (is_full_res_minmaxz) {
+ DRW_draw_pass(psl->maxz_copydepth_ps);
+ }
+ else {
+ DRW_draw_pass(psl->maxz_downdepth_ps);
+ }
+ }
+
+ /* Create lower levels */
+ GPU_framebuffer_recursive_downsample(fbl->downsample_fb, 8, &max_downsample_cb, vedata);
+ GPU_framebuffer_texture_detach(fbl->downsample_fb, txl->maxzbuffer);
+ DRW_stats_group_end();
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+
+ if (GPU_mip_render_workaround()) {
+ /* Fix dot corruption on intel HD5XX/HD6XX series.
+ * It seems affected drivers are the same that needs
+ * GPU_mip_render_workaround. */
+ GPU_flush();
+ }
+}
+
+/**
+ * Simple downsampling algorithm. Reconstruct mip chain up to mip level.
+ **/
+void EEVEE_downsample_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ e_data.color_src = texture_src;
+
+ /* Create lower levels */
+ DRW_stats_group_start("Downsample buffer");
+ GPU_framebuffer_texture_attach(fbl->downsample_fb, texture_src, 0, 0);
+ GPU_framebuffer_recursive_downsample(fbl->downsample_fb, level, &simple_downsample_cb, vedata);
+ GPU_framebuffer_texture_detach(fbl->downsample_fb, texture_src);
+ DRW_stats_group_end();
+}
+
+/**
+ * Simple downsampling algorithm for cubemap. Reconstruct mip chain up to mip level.
+ **/
+void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ e_data.color_src = texture_src;
+
+ /* Create lower levels */
+ DRW_stats_group_start("Downsample Cube buffer");
+ GPU_framebuffer_texture_attach(fbl->downsample_fb, texture_src, 0, 0);
+ GPU_framebuffer_recursive_downsample(fbl->downsample_fb, level, &simple_downsample_cube_cb, vedata);
+ GPU_framebuffer_texture_detach(fbl->downsample_fb, texture_src);
+ DRW_stats_group_end();
+}
+
+void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ /* First resolve the velocity. */
+ if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) {
+ DRW_viewport_matrix_get(effects->velocity_curr_persinv, DRW_MAT_PERSINV);
+
+ GPU_framebuffer_bind(fbl->velocity_resolve_fb);
+ DRW_draw_pass(psl->velocity_resolve);
+ }
+ DRW_viewport_matrix_get(effects->velocity_past_persmat, DRW_MAT_PERS);
+
+ /* only once per frame after the first post process */
+ effects->swap_double_buffer = ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0);
+
+ /* Init pointers */
+ effects->source_buffer = txl->color; /* latest updated texture */
+ effects->target_buffer = fbl->effect_color_fb; /* next target to render to */
+
+ /* Post process stack (order matters) */
+ EEVEE_motion_blur_draw(vedata);
+ EEVEE_depth_of_field_draw(vedata);
+ EEVEE_temporal_sampling_draw(vedata);
+ EEVEE_bloom_draw(vedata);
+
+ /* Save the final texture and framebuffer for final transformation or read. */
+ effects->final_tx = effects->source_buffer;
+ effects->final_fb = (effects->target_buffer != fbl->main_color_fb) ? fbl->main_fb : fbl->effect_fb;
+ if ((effects->enabled_effects & EFFECT_TAA) &&
+ (effects->source_buffer == txl->taa_history))
+ {
+ effects->final_fb = fbl->taa_history_fb;
+ }
+
+ /* If no post processes is enabled, buffers are still not swapped, do it now. */
+ SWAP_DOUBLE_BUFFERS();
+
+ if (!stl->g_data->valid_double_buffer &&
+ ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) &&
+ (DRW_state_is_image_render() == false))
+ {
+ /* If history buffer is not valid request another frame.
+ * This fix black reflections on area resize. */
+ DRW_viewport_request_redraw();
+ }
+
+ /* Record pers matrix for the next frame. */
+ DRW_viewport_matrix_get(stl->effects->prev_persmat, DRW_MAT_PERS);
+
+ /* Update double buffer status if render mode. */
+ if (DRW_state_is_image_render()) {
+ stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
+ stl->g_data->valid_taa_history = (txl->taa_history != NULL);
+ }
+}
+
+void EEVEE_effects_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.minz_downlevel_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_downlevel_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minz_downdepth_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_downdepth_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minz_downdepth_layer_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_downdepth_layer_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_copydepth_layer_sh);
+ DRW_SHADER_FREE_SAFE(e_data.minz_copydepth_sh);
+ DRW_SHADER_FREE_SAFE(e_data.maxz_copydepth_sh);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
new file mode 100644
index 00000000000..aa2cf3fede3
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_engine.c
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_rand.h"
+
+#include "BKE_object.h"
+#include "BKE_global.h" /* for G.debug_value */
+#include "BKE_screen.h"
+
+#include "DNA_world_types.h"
+
+#include "ED_screen.h"
+
+#include "GPU_material.h"
+#include "GPU_glew.h"
+
+#include "eevee_engine.h"
+#include "eevee_private.h"
+
+#define EEVEE_ENGINE "BLENDER_EEVEE"
+
+extern GlobalsUboStorage ts;
+
+/* *********** FUNCTIONS *********** */
+
+static void eevee_engine_init(void *ved)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ Object *camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+ stl->g_data->use_color_view_settings = USE_SCENE_LIGHT(v3d) || !LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d);
+ stl->g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f;
+ stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
+ stl->g_data->valid_taa_history = (txl->taa_history != NULL);
+
+ /* Main Buffer */
+ DRW_texture_ensure_fullscreen_2D(&txl->color, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
+
+ GPU_framebuffer_ensure_config(&fbl->main_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(txl->color),
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->main_color_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->color)
+ });
+
+ if (sldata->common_ubo == NULL) {
+ sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
+ }
+ if (sldata->clip_ubo == NULL) {
+ sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data);
+ }
+
+ /* EEVEE_effects_init needs to go first for TAA */
+ EEVEE_effects_init(sldata, vedata, camera, false);
+ EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_lights_init(sldata);
+ EEVEE_lightprobes_init(sldata, vedata);
+
+ if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) {
+ /* XXX otherwise it would break the other engines. */
+ DRW_viewport_matrix_override_unset_all();
+ }
+}
+
+static void eevee_cache_init(void *vedata)
+{
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+
+ EEVEE_bloom_cache_init(sldata, vedata);
+ EEVEE_depth_of_field_cache_init(sldata, vedata);
+ EEVEE_effects_cache_init(sldata, vedata);
+ EEVEE_lightprobes_cache_init(sldata, vedata);
+ EEVEE_lights_cache_init(sldata, vedata);
+ EEVEE_materials_cache_init(sldata, vedata);
+ EEVEE_motion_blur_cache_init(sldata, vedata);
+ EEVEE_occlusion_cache_init(sldata, vedata);
+ EEVEE_screen_raytrace_cache_init(sldata, vedata);
+ EEVEE_subsurface_cache_init(sldata, vedata);
+ EEVEE_temporal_sampling_cache_init(sldata, vedata);
+ EEVEE_volumes_cache_init(sldata, vedata);
+}
+
+void EEVEE_cache_populate(void *vedata, Object *ob)
+{
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ bool cast_shadow = false;
+
+ if (ob->base_flag & BASE_VISIBLE) {
+ EEVEE_hair_cache_populate(vedata, sldata, ob, &cast_shadow);
+ }
+
+ if (DRW_object_is_renderable(ob) &&
+ DRW_object_is_visible_in_active_context(ob))
+ {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
+ EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
+ }
+ else if (!USE_SCENE_LIGHT(draw_ctx->v3d)) {
+ /* do not add any scene light sources to the cache */
+ }
+ else if (ob->type == OB_LIGHTPROBE) {
+ if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
+ /* TODO: Special case for dupli objects because we cannot save the object pointer. */
+ }
+ else {
+ EEVEE_lightprobes_cache_add(sldata, vedata, ob);
+ }
+ }
+ else if (ob->type == OB_LAMP) {
+ EEVEE_lights_cache_add(sldata, ob);
+ }
+ }
+
+ if (cast_shadow) {
+ EEVEE_lights_cache_shcaster_object_add(sldata, ob);
+ }
+}
+
+static void eevee_cache_finish(void *vedata)
+{
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+
+ EEVEE_materials_cache_finish(vedata);
+ EEVEE_lights_cache_finish(sldata, vedata);
+ EEVEE_lightprobes_cache_finish(sldata, vedata);
+}
+
+/* As renders in an HDR offscreen buffer, we need draw everything once
+ * during the background pass. This way the other drawing callback between
+ * the background and the scene pass are visible.
+ * Note: we could break it up in two passes using some depth test
+ * to reduce the fillrate */
+static void eevee_draw_background(void *vedata)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_TextureList *txl = ((EEVEE_Data *)vedata)->txl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+
+ /* Default framebuffer and texture */
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ /* Sort transparents before the loop. */
+ DRW_pass_sort_shgroup_z(psl->transparent_pass);
+
+ /* Number of iteration: needed for all temporal effect (SSR, volumetrics)
+ * when using opengl render. */
+ int loop_len = (DRW_state_is_image_render() &&
+ (stl->effects->enabled_effects & (EFFECT_VOLUMETRIC | EFFECT_SSR)) != 0) ? 4 : 1;
+
+ while (loop_len--) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float clear_depth = 1.0f;
+ uint clear_stencil = 0x0;
+ uint primes[3] = {2, 3, 7};
+ double offset[3] = {0.0, 0.0, 0.0};
+ double r[3];
+
+ bool taa_use_reprojection = (stl->effects->enabled_effects & EFFECT_TAA_REPROJECT) != 0;
+
+ if (DRW_state_is_image_render() ||
+ taa_use_reprojection ||
+ ((stl->effects->enabled_effects & EFFECT_TAA) != 0))
+ {
+ int samp = taa_use_reprojection
+ ? stl->effects->taa_reproject_sample + 1
+ : stl->effects->taa_current_sample;
+ BLI_halton_3D(primes, offset, samp, r);
+ EEVEE_update_noise(psl, fbl, r);
+ EEVEE_volumes_set_jitter(sldata, samp - 1);
+ EEVEE_materials_init(sldata, stl, fbl);
+ }
+ /* Copy previous persmat to UBO data */
+ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat);
+
+ if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) &&
+ (stl->effects->taa_current_sample > 1) &&
+ !DRW_state_is_image_render() &&
+ !taa_use_reprojection)
+ {
+ DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV);
+ }
+
+ /* Refresh Probes */
+ DRW_stats_group_start("Probes Refresh");
+ EEVEE_lightprobes_refresh(sldata, vedata);
+ /* Probes refresh can have reset the current sample. */
+ if (stl->effects->taa_current_sample == 1) {
+ DRW_viewport_matrix_override_unset_all();
+ }
+ EEVEE_lightprobes_refresh_planar(sldata, vedata);
+ DRW_stats_group_end();
+
+ /* Refresh shadows */
+ DRW_stats_group_start("Shadows");
+ EEVEE_draw_shadows(sldata, vedata);
+ DRW_stats_group_end();
+
+ /* Set ray type. */
+ sldata->common_data.ray_type = EEVEE_RAY_CAMERA;
+ sldata->common_data.ray_depth = 0.0f;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ GPU_framebuffer_bind(fbl->main_fb);
+ GPUFrameBufferBits clear_bits = GPU_DEPTH_BIT;
+ clear_bits |= (DRW_state_draw_background()) ? 0 : GPU_COLOR_BIT;
+ clear_bits |= ((stl->effects->enabled_effects & EFFECT_SSS) != 0) ? GPU_STENCIL_BIT : 0;
+ GPU_framebuffer_clear(fbl->main_fb, clear_bits, clear_col, clear_depth, clear_stencil);
+
+ /* Depth prepass */
+ DRW_stats_group_start("Prepass");
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+ DRW_stats_group_end();
+
+ /* Create minmax texture */
+ DRW_stats_group_start("Main MinMax buffer");
+ EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
+ DRW_stats_group_end();
+
+ EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
+ EEVEE_volumes_compute(sldata, vedata);
+
+ /* Shading pass */
+ DRW_stats_group_start("Shading");
+ if (DRW_state_draw_background()) {
+ DRW_draw_pass(psl->background_pass);
+ }
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+ EEVEE_subsurface_data_render(sldata, vedata);
+ DRW_stats_group_end();
+
+ /* Effects pre-transparency */
+ EEVEE_subsurface_compute(sldata, vedata);
+ EEVEE_reflection_compute(sldata, vedata);
+ EEVEE_occlusion_draw_debug(sldata, vedata);
+ if (psl->probe_display) {
+ DRW_draw_pass(psl->probe_display);
+ }
+ EEVEE_refraction_compute(sldata, vedata);
+
+ /* Opaque refraction */
+ DRW_stats_group_start("Opaque Refraction");
+ DRW_draw_pass(psl->refract_depth_pass);
+ DRW_draw_pass(psl->refract_depth_pass_cull);
+ DRW_draw_pass(psl->refract_pass);
+ DRW_stats_group_end();
+
+ /* Volumetrics Resolve Opaque */
+ EEVEE_volumes_resolve(sldata, vedata);
+
+ /* Transparent */
+ DRW_draw_pass(psl->transparent_pass);
+
+ /* Post Process */
+ DRW_stats_group_start("Post FX");
+ EEVEE_draw_effects(sldata, vedata);
+ DRW_stats_group_end();
+
+ if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) {
+ DRW_viewport_matrix_override_unset_all();
+ }
+ }
+
+ /* LookDev */
+ EEVEE_lookdev_draw_background(vedata);
+ /* END */
+
+
+ /* Tonemapping and transfer result to default framebuffer. */
+ bool use_view_settings = stl->g_data->use_color_view_settings;
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_transform_to_display(stl->effects->final_tx, use_view_settings);
+
+ /* Debug : Output buffer to view. */
+ switch (G.debug_value) {
+ case 1:
+ if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer, use_view_settings);
+ break;
+ case 2:
+ if (effects->ssr_pdf_output) DRW_transform_to_display(effects->ssr_pdf_output, use_view_settings);
+ break;
+ case 3:
+ if (effects->ssr_normal_input) DRW_transform_to_display(effects->ssr_normal_input, use_view_settings);
+ break;
+ case 4:
+ if (effects->ssr_specrough_input) DRW_transform_to_display(effects->ssr_specrough_input, use_view_settings);
+ break;
+ case 5:
+ if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer, use_view_settings);
+ break;
+ case 6:
+ if (effects->gtao_horizons_debug) DRW_transform_to_display(effects->gtao_horizons_debug, use_view_settings);
+ break;
+ case 7:
+ if (effects->gtao_horizons) DRW_transform_to_display(effects->gtao_horizons, use_view_settings);
+ break;
+ case 8:
+ if (effects->sss_data) DRW_transform_to_display(effects->sss_data, use_view_settings);
+ break;
+ case 9:
+ if (effects->velocity_tx) DRW_transform_to_display(effects->velocity_tx, use_view_settings);
+ break;
+ default:
+ break;
+ }
+
+ EEVEE_volumes_free_smoke_textures();
+
+ stl->g_data->view_updated = false;
+}
+
+static void eevee_view_update(void *vedata)
+{
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ if (stl->g_data) {
+ stl->g_data->view_updated = true;
+ }
+}
+
+static void eevee_id_object_update(void *UNUSED(vedata), Object *object)
+{
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object);
+ if (ped != NULL && ped->dd.recalc != 0) {
+ ped->need_update = (ped->dd.recalc & (ID_RECALC_TRANSFORM | ID_RECALC_COPY_ON_WRITE)) != 0;
+ ped->dd.recalc = 0;
+ }
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object);
+ if (led != NULL && led->dd.recalc != 0) {
+ led->need_update = true;
+ led->dd.recalc = 0;
+ }
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object);
+ if (oedata != NULL && oedata->dd.recalc != 0) {
+ oedata->need_update = true;
+ oedata->dd.recalc = 0;
+ }
+}
+
+static void eevee_id_world_update(void *vedata, World *wo)
+{
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ LightCache *lcache = stl->g_data->light_cache;
+
+ EEVEE_WorldEngineData *wedata = EEVEE_world_data_ensure(wo);
+
+ if (wedata != NULL && wedata->dd.recalc != 0) {
+ if ((lcache->flag & (LIGHTCACHE_BAKED | LIGHTCACHE_BAKING)) == 0) {
+ lcache->flag |= LIGHTCACHE_UPDATE_WORLD;
+ }
+ wedata->dd.recalc = 0;
+ }
+}
+
+static void eevee_id_update(void *vedata, ID *id)
+{
+ /* Handle updates based on ID type. */
+ switch (GS(id->name)) {
+ case ID_WO:
+ eevee_id_world_update(vedata, (World *)id);
+ break;
+ case ID_OB:
+ eevee_id_object_update(vedata, (Object *)id);
+ break;
+ default:
+ /* pass */
+ break;
+ }
+}
+
+static void eevee_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ EEVEE_render_init(vedata, engine, draw_ctx->depsgraph);
+
+ DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, EEVEE_render_cache);
+
+ /* Actually do the rendering. */
+ EEVEE_render_draw(vedata, engine, render_layer, rect);
+}
+
+static void eevee_engine_free(void)
+{
+ EEVEE_shaders_free();
+ EEVEE_bloom_free();
+ EEVEE_depth_of_field_free();
+ EEVEE_effects_free();
+ EEVEE_lightprobes_free();
+ EEVEE_lights_free();
+ EEVEE_materials_free();
+ EEVEE_mist_free();
+ EEVEE_motion_blur_free();
+ EEVEE_occlusion_free();
+ EEVEE_screen_raytrace_free();
+ EEVEE_subsurface_free();
+ EEVEE_volumes_free();
+}
+
+static const DrawEngineDataSize eevee_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);
+
+DrawEngineType draw_engine_eevee_type = {
+ NULL, NULL,
+ N_("Eevee"),
+ &eevee_data_size,
+ &eevee_engine_init,
+ &eevee_engine_free,
+ &eevee_cache_init,
+ &EEVEE_cache_populate,
+ &eevee_cache_finish,
+ &eevee_draw_background,
+ NULL, /* Everything is drawn in the background pass (see comment on function) */
+ &eevee_view_update,
+ &eevee_id_update,
+ &eevee_render_to_image,
+};
+
+RenderEngineType DRW_engine_viewport_eevee_type = {
+ NULL, NULL,
+ EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES | RE_USE_PREVIEW,
+ NULL, &DRW_render_to_image, NULL, NULL, NULL, NULL,
+ &EEVEE_render_update_passes,
+ &draw_engine_eevee_type,
+ {NULL, NULL, NULL}
+};
+
+
+#undef EEVEE_ENGINE
diff --git a/source/blender/draw/engines/eevee/eevee_engine.h b/source/blender/draw/engines/eevee/eevee_engine.h
new file mode 100644
index 00000000000..b7de3a055b9
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_engine.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_engine.h
+ * \ingroup DNA
+ */
+
+#ifndef __EEVEE_ENGINE_H__
+#define __EEVEE_ENGINE_H__
+
+extern RenderEngineType DRW_engine_viewport_eevee_type;
+
+#endif /* __EEVEE_ENGINE_H__ */
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
new file mode 100644
index 00000000000..451e7174a94
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -0,0 +1,1215 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_lightcache.c
+ * \ingroup draw_engine
+ *
+ * Eevee's indirect lighting cache.
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_global.h"
+#include "BKE_blender.h"
+
+#include "BLI_threads.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "BKE_object.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_lightprobe_types.h"
+
+#include "PIL_time.h"
+
+#include "eevee_lightcache.h"
+#include "eevee_private.h"
+
+#include "GPU_context.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_window.h"
+
+/* Rounded to nearest PowerOfTwo */
+#if defined(IRRADIANCE_SH_L2)
+#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */
+#define IRRADIANCE_SAMPLE_SIZE_Y 4 /* 3 in reality */
+#elif defined(IRRADIANCE_CUBEMAP)
+#define IRRADIANCE_SAMPLE_SIZE_X 8
+#define IRRADIANCE_SAMPLE_SIZE_Y 8
+#elif defined(IRRADIANCE_HL2)
+#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */
+#define IRRADIANCE_SAMPLE_SIZE_Y 2
+#endif
+
+#ifdef IRRADIANCE_SH_L2
+/* we need a signed format for Spherical Harmonics */
+# define IRRADIANCE_FORMAT GPU_RGBA16F
+#else
+# define IRRADIANCE_FORMAT GPU_RGBA8
+#endif
+
+#define IRRADIANCE_MAX_POOL_LAYER 256 /* OpenGL 3.3 core requirement, can be extended but it's already very big */
+#define IRRADIANCE_MAX_POOL_SIZE 1024
+#define MAX_IRRADIANCE_SAMPLES \
+ (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_X) * \
+ (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y)
+
+/* TODO should be replace by a more elegant alternative. */
+extern void DRW_opengl_context_enable(void);
+extern void DRW_opengl_context_disable(void);
+
+extern void DRW_opengl_render_context_enable(void *re_gl_context);
+extern void DRW_opengl_render_context_disable(void *re_gl_context);
+extern void DRW_gawain_render_context_enable(void *re_gpu_context);
+extern void DRW_gawain_render_context_disable(void *re_gpu_context);
+
+typedef struct EEVEE_LightBake {
+ Depsgraph *depsgraph;
+ ViewLayer *view_layer;
+ ViewLayer *view_layer_input;
+ LightCache *lcache;
+ Scene *scene;
+ struct Main *bmain;
+ EEVEE_ViewLayerData *sldata;
+
+ LightProbe **probe; /* Current probe being rendered. */
+ GPUTexture *rt_color; /* Target cube color texture. */
+ GPUTexture *rt_depth; /* Target cube depth texture. */
+ GPUFrameBuffer *rt_fb[6]; /* Target cube framebuffers. */
+ GPUFrameBuffer *store_fb; /* Storage framebuffer. */
+ int rt_res; /* Cube render target resolution. */
+
+ /* Shared */
+ int layer; /* Target layer to store the data to. */
+ float samples_ct, invsamples_ct; /* Sample count for the convolution. */
+ float lod_factor; /* Sampling bias during convolution step. */
+ float lod_max; /* Max cubemap LOD to sample when convolving. */
+ int cube_len, grid_len; /* Number of probes to render + world probe. */
+
+ /* Irradiance grid */
+ EEVEE_LightGrid *grid; /* Current probe being rendered (UBO data). */
+ int irr_cube_res; /* Target cubemap at MIP 0. */
+ int irr_size[3]; /* Size of the irradiance texture. */
+ int total_irr_samples; /* Total for all grids */
+ int grid_sample; /* Nth sample of the current grid being rendered. */
+ int grid_sample_len; /* Total number of samples for the current grid. */
+ int grid_curr; /* Nth grid in the cache being rendered. */
+ int bounce_curr, bounce_len; /* The current light bounce being evaluated. */
+ float vis_res; /* Resolution of the Visibility shadowmap. */
+ GPUTexture *grid_prev; /* Result of previous light bounce. */
+ LightProbe **grid_prb; /* Pointer to the id.data of the probe object. */
+
+ /* Reflection probe */
+ EEVEE_LightProbe *cube; /* Current probe being rendered (UBO data). */
+ int ref_cube_res; /* Target cubemap at MIP 0. */
+ int cube_offset; /* Index of the current cube. */
+ LightProbe **cube_prb; /* Pointer to the id.data of the probe object. */
+
+ /* Dummy Textures */
+ struct GPUTexture *dummy_color, *dummy_depth;
+ struct GPUTexture *dummy_layer_color;
+
+ int total, done; /* to compute progress */
+ short *stop, *do_update;
+ float *progress;
+
+ bool resource_only; /* For only handling the resources. */
+ bool own_resources;
+ bool own_light_cache; /* If the lightcache was created for baking, it's first owned by the baker. */
+ int delay; /* ms. delay the start of the baking to not slowdown interactions (TODO remove) */
+
+ void *gl_context, *gpu_context; /* If running in parallel (in a separate thread), use this context. */
+
+ ThreadMutex *mutex;
+} EEVEE_LightBake;
+
+/* -------------------------------------------------------------------- */
+
+/** \name Light Cache
+ * \{ */
+
+/* Return memory footprint in bytes. */
+static unsigned int eevee_lightcache_memsize_get(LightCache *lcache)
+{
+ unsigned int size = 0;
+ if (lcache->grid_tx.data) {
+ size += MEM_allocN_len(lcache->grid_tx.data);
+ }
+ if (lcache->cube_tx.data) {
+ size += MEM_allocN_len(lcache->cube_tx.data);
+ for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ size += MEM_allocN_len(lcache->cube_mips[mip].data);
+ }
+ }
+ return size;
+}
+
+static int eevee_lightcache_irradiance_sample_count(LightCache *lcache)
+{
+ int total_irr_samples = 0;
+
+ for (int i = 1; i < lcache->grid_len; ++i) {
+ EEVEE_LightGrid *egrid = lcache->grid_data + i;
+ total_irr_samples += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2];
+ }
+ return total_irr_samples;
+}
+
+void EEVEE_lightcache_info_update(SceneEEVEE *eevee)
+{
+ LightCache *lcache = eevee->light_cache;
+
+ if (lcache != NULL) {
+ if (lcache->flag & LIGHTCACHE_BAKING) {
+ BLI_strncpy(eevee->light_cache_info, IFACE_("Baking light cache."), sizeof(eevee->light_cache_info));
+ return;
+ }
+
+ char formatted_mem[15];
+ BLI_str_format_byte_unit(formatted_mem, eevee_lightcache_memsize_get(lcache), true);
+
+ int irr_samples = eevee_lightcache_irradiance_sample_count(lcache);
+
+ BLI_snprintf(eevee->light_cache_info, sizeof(eevee->light_cache_info), IFACE_("%d Ref. Cubemaps, %d Irr. Samples (%s in memory)"), lcache->cube_len - 1, irr_samples, formatted_mem);
+ }
+ else {
+ BLI_strncpy(eevee->light_cache_info, IFACE_("No light cache in this scene."), sizeof(eevee->light_cache_info));
+ }
+}
+
+static void irradiance_pool_size_get(int visibility_size, int total_samples, int r_size[3])
+{
+ /* Compute how many irradiance samples we can store per visibility sample. */
+ int irr_per_vis = (visibility_size / IRRADIANCE_SAMPLE_SIZE_X) *
+ (visibility_size / IRRADIANCE_SAMPLE_SIZE_Y);
+
+ /* The irradiance itself take one layer, hence the +1 */
+ int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER);
+
+ int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1));
+ r_size[0] = visibility_size * max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ r_size[1] = visibility_size * max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ r_size[2] = layer_ct;
+}
+
+static bool EEVEE_lightcache_validate(
+ const LightCache *light_cache,
+ const int cube_len,
+ const int cube_res,
+ const int grid_len,
+ const int irr_size[3])
+{
+ if (light_cache) {
+ /* See if we need the same amount of texture space. */
+ if ((irr_size[0] == light_cache->grid_tx.tex_size[0]) &&
+ (irr_size[1] == light_cache->grid_tx.tex_size[1]) &&
+ (irr_size[2] == light_cache->grid_tx.tex_size[2]) &&
+ (grid_len == light_cache->grid_len))
+ {
+ int mip_len = (int)(floorf(log2f(cube_res)) - MIN_CUBE_LOD_LEVEL);
+ if ((cube_res == light_cache->cube_tx.tex_size[0]) &&
+ (cube_len == light_cache->cube_tx.tex_size[2]) &&
+ (mip_len == light_cache->mips_len))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+LightCache *EEVEE_lightcache_create(
+ const int grid_len,
+ const int cube_len,
+ const int cube_size,
+ const int vis_size,
+ const int irr_size[3])
+{
+ LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache");
+
+ light_cache->cube_data = MEM_callocN(sizeof(EEVEE_LightProbe) * cube_len, "EEVEE_LightProbe");
+ light_cache->grid_data = MEM_callocN(sizeof(EEVEE_LightGrid) * grid_len, "EEVEE_LightGrid");
+
+ light_cache->grid_tx.tex = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], IRRADIANCE_FORMAT, DRW_TEX_FILTER, NULL);
+ light_cache->grid_tx.tex_size[0] = irr_size[0];
+ light_cache->grid_tx.tex_size[1] = irr_size[1];
+ light_cache->grid_tx.tex_size[2] = irr_size[2];
+
+ light_cache->cube_tx.tex = DRW_texture_create_2D_array(cube_size, cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ light_cache->cube_tx.tex_size[0] = cube_size;
+ light_cache->cube_tx.tex_size[1] = cube_size;
+ light_cache->cube_tx.tex_size[2] = cube_len;
+
+ light_cache->mips_len = (int)(floorf(log2f(cube_size)) - MIN_CUBE_LOD_LEVEL);
+ light_cache->vis_res = vis_size;
+ light_cache->ref_res = cube_size;
+
+ light_cache->cube_mips = MEM_callocN(sizeof(LightCacheTexture) * light_cache->mips_len, "LightCacheTexture");
+
+ for (int mip = 0; mip < light_cache->mips_len; ++mip) {
+ GPU_texture_get_mipmap_size(light_cache->cube_tx.tex, mip + 1, light_cache->cube_mips[mip].tex_size);
+ }
+
+ light_cache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE | LIGHTCACHE_UPDATE_GRID;
+
+ return light_cache;
+}
+
+void EEVEE_lightcache_load(LightCache *lcache)
+{
+ if (lcache->grid_tx.tex == NULL && lcache->grid_tx.data) {
+ lcache->grid_tx.tex = GPU_texture_create_nD(lcache->grid_tx.tex_size[0],
+ lcache->grid_tx.tex_size[1],
+ lcache->grid_tx.tex_size[2],
+ 2,
+ lcache->grid_tx.data,
+ IRRADIANCE_FORMAT,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+ GPU_texture_bind(lcache->grid_tx.tex, 0);
+ GPU_texture_filter_mode(lcache->grid_tx.tex, true);
+ GPU_texture_unbind(lcache->grid_tx.tex);
+ }
+
+ if (lcache->cube_tx.tex == NULL && lcache->cube_tx.data) {
+ lcache->cube_tx.tex = GPU_texture_create_nD(lcache->cube_tx.tex_size[0],
+ lcache->cube_tx.tex_size[1],
+ lcache->cube_tx.tex_size[2],
+ 2,
+ lcache->cube_tx.data,
+ GPU_R11F_G11F_B10F,
+ GPU_DATA_10_11_11_REV,
+ 0,
+ false,
+ NULL);
+ GPU_texture_bind(lcache->cube_tx.tex, 0);
+ GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true);
+ for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ GPU_texture_add_mipmap(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data);
+ }
+ GPU_texture_unbind(lcache->cube_tx.tex);
+ }
+}
+
+static void eevee_lightbake_readback_irradiance(LightCache *lcache)
+{
+ MEM_SAFE_FREE(lcache->grid_tx.data);
+ lcache->grid_tx.data = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_UNSIGNED_BYTE, 0);
+ lcache->grid_tx.data_type = LIGHTCACHETEX_BYTE;
+ lcache->grid_tx.components = 4;
+}
+
+static void eevee_lightbake_readback_reflections(LightCache *lcache)
+{
+ MEM_SAFE_FREE(lcache->cube_tx.data);
+ lcache->cube_tx.data = GPU_texture_read(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, 0);
+ lcache->cube_tx.data_type = LIGHTCACHETEX_UINT;
+ lcache->cube_tx.components = 1;
+
+ for (int mip = 0; mip < lcache->mips_len; ++mip) {
+ LightCacheTexture *cube_mip = lcache->cube_mips + mip;
+ MEM_SAFE_FREE(cube_mip->data);
+ GPU_texture_get_mipmap_size(lcache->cube_tx.tex, mip + 1, cube_mip->tex_size);
+
+ cube_mip->data = GPU_texture_read(lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1);
+ cube_mip->data_type = LIGHTCACHETEX_UINT;
+ cube_mip->components = 1;
+ }
+}
+
+void EEVEE_lightcache_free(LightCache *lcache)
+{
+ DRW_TEXTURE_FREE_SAFE(lcache->cube_tx.tex);
+ MEM_SAFE_FREE(lcache->cube_tx.data);
+ DRW_TEXTURE_FREE_SAFE(lcache->grid_tx.tex);
+ MEM_SAFE_FREE(lcache->grid_tx.data);
+
+ if (lcache->cube_mips) {
+ for (int i = 0; i < lcache->mips_len; ++i) {
+ MEM_SAFE_FREE(lcache->cube_mips[i].data);
+ }
+ MEM_SAFE_FREE(lcache->cube_mips);
+ }
+
+ MEM_SAFE_FREE(lcache->cube_data);
+ MEM_SAFE_FREE(lcache->grid_data);
+ MEM_freeN(lcache);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Light Bake Context
+ * \{ */
+
+static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake)
+{
+ if (lbake->gl_context) {
+ DRW_opengl_render_context_enable(lbake->gl_context);
+ if (lbake->gpu_context == NULL) {
+ lbake->gpu_context = GPU_context_create();
+ }
+ DRW_gawain_render_context_enable(lbake->gpu_context);
+ }
+ else {
+ DRW_opengl_context_enable();
+ }
+}
+
+static void eevee_lightbake_context_disable(EEVEE_LightBake *lbake)
+{
+ if (lbake->gl_context) {
+ DRW_gawain_render_context_disable(lbake->gpu_context);
+ DRW_opengl_render_context_disable(lbake->gl_context);
+ }
+ else {
+ DRW_opengl_context_disable();
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Light Bake Job
+ * \{ */
+
+static void eevee_lightbake_count_probes(EEVEE_LightBake *lbake)
+{
+ Depsgraph *depsgraph = lbake->depsgraph;
+
+ /* At least one of each for the world */
+ lbake->grid_len = lbake->cube_len = lbake->total_irr_samples = 1;
+
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
+ {
+ if (!BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_FOR_RENDER)) {
+ continue;
+ }
+
+ if (ob->type == OB_LIGHTPROBE) {
+ LightProbe *prb = (LightProbe *)ob->data;
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ lbake->total_irr_samples += prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+ lbake->grid_len++;
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ lbake->cube_len++;
+ }
+ }
+ }
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
+}
+
+static void eevee_lightbake_create_render_target(EEVEE_LightBake *lbake, int rt_res)
+{
+ lbake->rt_depth = DRW_texture_create_cube(rt_res, GPU_DEPTH_COMPONENT24, 0, NULL);
+ lbake->rt_color = DRW_texture_create_cube(rt_res, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+
+ for (int i = 0; i < 6; ++i) {
+ GPU_framebuffer_ensure_config(&lbake->rt_fb[i], {
+ GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_depth, i),
+ GPU_ATTACHMENT_TEXTURE_CUBEFACE(lbake->rt_color, i)
+ });
+ }
+
+ GPU_framebuffer_ensure_config(&lbake->store_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE
+ });
+}
+
+static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake)
+{
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ SceneEEVEE *eevee = &scene_eval->eevee;
+
+ lbake->bounce_len = eevee->gi_diffuse_bounces;
+ lbake->vis_res = eevee->gi_visibility_resolution;
+ lbake->rt_res = eevee->gi_cubemap_resolution;
+
+ irradiance_pool_size_get(lbake->vis_res, lbake->total_irr_samples, lbake->irr_size);
+
+ lbake->ref_cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(lbake->rt_res);
+
+ lbake->cube_prb = MEM_callocN(sizeof(LightProbe *) * lbake->cube_len, "EEVEE Cube visgroup ptr");
+ lbake->grid_prb = MEM_callocN(sizeof(LightProbe *) * lbake->grid_len, "EEVEE Grid visgroup ptr");
+
+ lbake->grid_prev = DRW_texture_create_2D_array(lbake->irr_size[0], lbake->irr_size[1], lbake->irr_size[2],
+ IRRADIANCE_FORMAT, DRW_TEX_FILTER, NULL);
+
+ /* Ensure Light Cache is ready to accept new data. If not recreate one.
+ * WARNING: All the following must be threadsafe. It's currently protected
+ * by the DRW mutex. */
+ lbake->lcache = eevee->light_cache;
+
+ /* TODO validate irradiance and reflection cache independently... */
+ if (!EEVEE_lightcache_validate(
+ lbake->lcache, lbake->cube_len, lbake->ref_cube_res, lbake->grid_len, lbake->irr_size))
+ {
+ eevee->light_cache = lbake->lcache = NULL;
+ }
+
+ if (lbake->lcache == NULL) {
+ lbake->lcache = EEVEE_lightcache_create(
+ lbake->grid_len,
+ lbake->cube_len,
+ lbake->ref_cube_res,
+ lbake->vis_res,
+ lbake->irr_size);
+ lbake->lcache->flag = LIGHTCACHE_UPDATE_WORLD | LIGHTCACHE_UPDATE_CUBE | LIGHTCACHE_UPDATE_GRID;
+ lbake->lcache->vis_res = lbake->vis_res;
+ lbake->own_light_cache = true;
+
+ eevee->light_cache = lbake->lcache;
+ }
+
+ EEVEE_lightcache_load(eevee->light_cache);
+
+ lbake->lcache->flag |= LIGHTCACHE_BAKING;
+ lbake->lcache->cube_len = 1;
+}
+
+wmJob *EEVEE_lightbake_job_create(
+ struct wmWindowManager *wm, struct wmWindow *win, struct Main *bmain,
+ struct ViewLayer *view_layer, struct Scene *scene, int delay)
+{
+ EEVEE_LightBake *lbake = NULL;
+
+ /* only one render job at a time */
+ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER))
+ return NULL;
+
+ wmJob *wm_job = WM_jobs_get(wm, win, scene, "Bake Lighting",
+ WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_LIGHT_BAKE);
+
+ /* If job exists do not recreate context and depsgraph. */
+ EEVEE_LightBake *old_lbake = (EEVEE_LightBake *)WM_jobs_customdata_get(wm_job);
+
+ if (old_lbake && (old_lbake->view_layer_input == view_layer) && (old_lbake->bmain == bmain)) {
+ lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake");
+ /* Cannot reuse depsgraph for now because we cannot get the update from the
+ * main database directly. TODO reuse depsgraph and only update positions. */
+ /* lbake->depsgraph = old_lbake->depsgraph; */
+ lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+
+ lbake->mutex = BLI_mutex_alloc();
+
+ BLI_mutex_lock(old_lbake->mutex);
+ old_lbake->own_resources = false;
+
+ lbake->scene = scene;
+ lbake->bmain = bmain;
+ lbake->view_layer_input = view_layer;
+ lbake->gl_context = old_lbake->gl_context;
+ lbake->own_resources = true;
+ lbake->delay = delay;
+
+ if (lbake->gl_context == NULL) {
+ lbake->gl_context = WM_opengl_context_create();
+ wm_window_reset_drawable();
+ }
+
+ if (old_lbake->stop != NULL) {
+ *old_lbake->stop = 1;
+ }
+ BLI_mutex_unlock(old_lbake->mutex);
+ }
+ else {
+ lbake = EEVEE_lightbake_job_data_alloc(bmain, view_layer, scene, true);
+ lbake->delay = delay;
+ }
+
+ WM_jobs_customdata_set(wm_job, lbake, EEVEE_lightbake_job_data_free);
+ WM_jobs_timer(wm_job, 0.4, NC_SCENE | NA_EDITED, 0);
+ WM_jobs_callbacks(wm_job, EEVEE_lightbake_job, NULL, EEVEE_lightbake_update, EEVEE_lightbake_update);
+
+ G.is_break = false;
+
+ return wm_job;
+}
+
+/* MUST run on the main thread. */
+void *EEVEE_lightbake_job_data_alloc(
+ struct Main *bmain, struct ViewLayer *view_layer, struct Scene *scene, bool run_as_job)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ EEVEE_LightBake *lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake");
+
+ lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ lbake->scene = scene;
+ lbake->bmain = bmain;
+ lbake->view_layer_input = view_layer;
+ lbake->own_resources = true;
+ lbake->own_light_cache = false;
+ lbake->mutex = BLI_mutex_alloc();
+
+ if (run_as_job) {
+ lbake->gl_context = WM_opengl_context_create();
+ wm_window_reset_drawable();
+ }
+
+ return lbake;
+}
+
+void EEVEE_lightbake_job_data_free(void *custom_data)
+{
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data;
+
+
+
+ /* TODO reuse depsgraph. */
+ /* if (lbake->own_resources) { */
+ DEG_graph_free(lbake->depsgraph);
+ /* } */
+
+ MEM_SAFE_FREE(lbake->cube_prb);
+ MEM_SAFE_FREE(lbake->grid_prb);
+
+ BLI_mutex_free(lbake->mutex);
+
+ MEM_freeN(lbake);
+}
+
+static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
+{
+ if (!lbake->resource_only) {
+ BLI_mutex_lock(lbake->mutex);
+ }
+
+ if (lbake->gl_context) {
+ DRW_opengl_render_context_enable(lbake->gl_context);
+ DRW_gawain_render_context_enable(lbake->gpu_context);
+ }
+ else if (!lbake->resource_only) {
+ DRW_opengl_context_enable();
+ }
+
+ /* XXX Free the resources contained in the viewlayer data
+ * to be able to free the context before deleting the depsgraph. */
+ if (lbake->sldata) {
+ EEVEE_view_layer_data_free(lbake->sldata);
+ }
+
+ DRW_TEXTURE_FREE_SAFE(lbake->rt_depth);
+ DRW_TEXTURE_FREE_SAFE(lbake->rt_color);
+ DRW_TEXTURE_FREE_SAFE(lbake->grid_prev);
+ GPU_FRAMEBUFFER_FREE_SAFE(lbake->store_fb);
+ for (int i = 0; i < 6; ++i) {
+ GPU_FRAMEBUFFER_FREE_SAFE(lbake->rt_fb[i]);
+ }
+
+ if (lbake->gpu_context) {
+ DRW_gawain_render_context_disable(lbake->gpu_context);
+ DRW_gawain_render_context_enable(lbake->gpu_context);
+ GPU_context_discard(lbake->gpu_context);
+ }
+
+ if (lbake->gl_context && lbake->own_resources) {
+ /* Delete the baking context. */
+ DRW_opengl_render_context_disable(lbake->gl_context);
+ WM_opengl_context_dispose(lbake->gl_context);
+ lbake->gpu_context = NULL;
+ lbake->gl_context = NULL;
+ }
+ else if (lbake->gl_context) {
+ DRW_opengl_render_context_disable(lbake->gl_context);
+ }
+ else if (!lbake->resource_only) {
+ DRW_opengl_context_disable();
+ }
+
+ if (!lbake->resource_only) {
+ BLI_mutex_unlock(lbake->mutex);
+ }
+}
+
+/* Cache as in draw cache not light cache. */
+static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lbake)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ lbake->sldata = sldata;
+
+ /* Disable all effects BUT high bitdepth shadows. */
+ scene_eval->eevee.flag &= SCE_EEVEE_SHADOW_HIGH_BITDEPTH;
+ scene_eval->eevee.taa_samples = 1;
+ scene_eval->eevee.gi_irradiance_smoothing = 0.0f;
+
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ stl->g_data->background_alpha = 1.0f;
+
+ /* XXX TODO remove this. This is in order to make the init functions work. */
+ DRWMatrixState dummy_mats = {{{{{0}}}}};
+ DRW_viewport_matrix_override_set_all(&dummy_mats);
+
+ if (sldata->common_ubo == NULL) {
+ sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
+ }
+ if (sldata->clip_ubo == NULL) {
+ sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data);
+ }
+
+ /* HACK: set txl->color but unset it before Draw Manager frees it. */
+ txl->color = lbake->rt_color;
+ int viewport_size[2] = {
+ GPU_texture_width(txl->color),
+ GPU_texture_height(txl->color)
+ };
+ DRW_render_viewport_size_set(viewport_size);
+
+ EEVEE_effects_init(sldata, vedata, NULL, true);
+ EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_lights_init(sldata);
+ EEVEE_lightprobes_init(sldata, vedata);
+
+ EEVEE_effects_cache_init(sldata, vedata);
+ EEVEE_materials_cache_init(sldata, vedata);
+ EEVEE_lights_cache_init(sldata, vedata);
+ EEVEE_lightprobes_cache_init(sldata, vedata);
+
+ EEVEE_lightbake_cache_init(sldata, vedata, lbake->rt_color, lbake->rt_depth);
+
+ if (lbake->probe) {
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightProbe *prb = *lbake->probe;
+ pinfo->vis_data.collection = prb->visibility_grp;
+ pinfo->vis_data.invert = prb->flag & LIGHTPROBE_FLAG_INVERT_GROUP;
+ pinfo->vis_data.cached = false;
+ }
+ DRW_render_object_iter(vedata, NULL, lbake->depsgraph, EEVEE_render_cache);
+
+ EEVEE_materials_cache_finish(vedata);
+ EEVEE_lights_cache_finish(sldata, vedata);
+ EEVEE_lightprobes_cache_finish(sldata, vedata);
+
+ txl->color = NULL;
+
+ DRW_render_instance_buffer_finish();
+ DRW_hair_update();
+}
+
+static void eevee_lightbake_copy_irradiance(EEVEE_LightBake *lbake, LightCache *lcache)
+{
+ DRW_TEXTURE_FREE_SAFE(lbake->grid_prev);
+
+ /* Copy texture by reading back and reuploading it. */
+ float *tex = GPU_texture_read(lcache->grid_tx.tex, GPU_DATA_FLOAT, 0);
+ lbake->grid_prev = DRW_texture_create_2D_array(lbake->irr_size[0], lbake->irr_size[1], lbake->irr_size[2],
+ IRRADIANCE_FORMAT, DRW_TEX_FILTER, tex);
+
+ MEM_freeN(tex);
+}
+
+static void eevee_lightbake_render_world_sample(void *ved, void *user_data)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data;
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ LightCache *lcache = scene_eval->eevee.light_cache;
+ float clamp = scene_eval->eevee.gi_glossy_clamp;
+ float filter_quality = scene_eval->eevee.gi_filter_quality;
+
+ /* TODO do this once for the whole bake when we have independent DRWManagers. */
+ eevee_lightbake_cache_create(vedata, lbake);
+
+ sldata->common_data.ray_type = EEVEE_RAY_GLOSSY;
+ sldata->common_data.ray_depth = 1;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb);
+ EEVEE_lightbake_filter_glossy(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f, lcache->mips_len, filter_quality, clamp);
+
+ sldata->common_data.ray_type = EEVEE_RAY_DIFFUSE;
+ sldata->common_data.ray_depth = 1;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ EEVEE_lightbake_render_world(sldata, vedata, lbake->rt_fb);
+ EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, 0, 1.0f);
+
+ /* Clear the cache to avoid white values in the grid. */
+ GPU_framebuffer_texture_attach(lbake->store_fb, lbake->grid_prev, 0, 0);
+ GPU_framebuffer_bind(lbake->store_fb);
+ /* Clear to 1.0f for visibility. */
+ GPU_framebuffer_clear_color(lbake->store_fb, ((float[4]){1.0f, 1.0f, 1.0f, 1.0f}));
+ DRW_draw_pass(vedata->psl->probe_grid_fill);
+
+ SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
+
+ /* Make a copy for later. */
+ eevee_lightbake_copy_irradiance(lbake, lcache);
+
+ lcache->cube_len = 1;
+ lcache->grid_len = lbake->grid_len;
+
+ lcache->flag |= LIGHTCACHE_CUBE_READY | LIGHTCACHE_GRID_READY;
+ lcache->flag &= ~LIGHTCACHE_UPDATE_WORLD;
+}
+
+static void cell_id_to_grid_loc(EEVEE_LightGrid *egrid, int cell_idx, int r_local_cell[3])
+{
+ /* Keep in sync with lightprobe_grid_display_vert */
+ r_local_cell[2] = cell_idx % egrid->resolution[2];
+ r_local_cell[1] = (cell_idx / egrid->resolution[2]) % egrid->resolution[1];
+ r_local_cell[0] = cell_idx / (egrid->resolution[2] * egrid->resolution[1]);
+}
+
+static void compute_cell_id(
+ EEVEE_LightGrid *egrid, LightProbe *probe,
+ int cell_idx, int *r_final_idx, int r_local_cell[3], int *r_stride)
+{
+ const int cell_count = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z;
+
+ /* Add one for level 0 */
+ int max_lvl = (int)floorf(log2f((float)MAX3(probe->grid_resolution_x,
+ probe->grid_resolution_y,
+ probe->grid_resolution_z)));
+
+ int visited_cells = 0;
+ *r_stride = 0;
+ *r_final_idx = 0;
+ r_local_cell[0] = r_local_cell[1] = r_local_cell[2] = 0;
+ for (int lvl = max_lvl; lvl >= 0; --lvl) {
+ *r_stride = 1 << lvl;
+ int prev_stride = *r_stride << 1;
+ for (int i = 0; i < cell_count; ++i) {
+ *r_final_idx = i;
+ cell_id_to_grid_loc(egrid, *r_final_idx, r_local_cell);
+ if (((r_local_cell[0] % *r_stride) == 0) &&
+ ((r_local_cell[1] % *r_stride) == 0) &&
+ ((r_local_cell[2] % *r_stride) == 0))
+ {
+ if (!(((r_local_cell[0] % prev_stride) == 0) &&
+ ((r_local_cell[1] % prev_stride) == 0) &&
+ ((r_local_cell[2] % prev_stride) == 0)) ||
+ ((i == 0) && (lvl == max_lvl)))
+ {
+ if (visited_cells == cell_idx) {
+ return;
+ }
+ else {
+ visited_cells++;
+ }
+ }
+ }
+ }
+ }
+
+ BLI_assert(0);
+}
+
+static void grid_loc_to_world_loc(EEVEE_LightGrid *egrid, int local_cell[3], float r_pos[3])
+{
+ copy_v3_v3(r_pos, egrid->corner);
+ madd_v3_v3fl(r_pos, egrid->increment_x, local_cell[0]);
+ madd_v3_v3fl(r_pos, egrid->increment_y, local_cell[1]);
+ madd_v3_v3fl(r_pos, egrid->increment_z, local_cell[2]);
+}
+
+static void eevee_lightbake_render_grid_sample(void *ved, void *user_data)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data;
+ EEVEE_LightGrid *egrid = lbake->grid;
+ LightProbe *prb = *lbake->probe;
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ LightCache *lcache = scene_eval->eevee.light_cache;
+ int grid_loc[3], sample_id, sample_offset, stride;
+ float pos[3];
+ const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) == (lbake->total_irr_samples - 1));
+
+ /* No bias for rendering the probe. */
+ egrid->level_bias = 1.0f;
+
+ /* Use the previous bounce for rendering this bounce. */
+ SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
+
+ /* TODO do this once for the whole bake when we have independent DRWManagers.
+ * Warning: Some of the things above require this. */
+ eevee_lightbake_cache_create(vedata, lbake);
+
+ /* Compute sample position */
+ compute_cell_id(egrid, prb, lbake->grid_sample, &sample_id, grid_loc, &stride);
+ sample_offset = egrid->offset + sample_id;
+
+ grid_loc_to_world_loc(egrid, grid_loc, pos);
+
+ /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
+ common_data->spec_toggle = false;
+ common_data->prb_num_planar = 0;
+ common_data->prb_num_render_cube = 0;
+ common_data->ray_type = EEVEE_RAY_DIFFUSE;
+ common_data->ray_depth = lbake->bounce_curr + 1;
+ if (lbake->bounce_curr == 0) {
+ common_data->prb_num_render_grid = 0;
+ }
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ EEVEE_lightbake_render_scene(sldata, vedata, lbake->rt_fb, pos, prb->clipsta, prb->clipend);
+
+ /* Restore before filtering. */
+ SWAP(GPUTexture *, lbake->grid_prev, lcache->grid_tx.tex);
+
+ EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake->rt_color, lbake->store_fb, sample_offset, prb->intensity);
+
+ if (lbake->bounce_curr == 0) {
+ /* We only need to filter the visibility for the first bounce. */
+ EEVEE_lightbake_filter_visibility(sldata, vedata, lbake->rt_depth, lbake->store_fb, sample_offset,
+ prb->clipsta, prb->clipend, egrid->visibility_range,
+ prb->vis_blur, lbake->vis_res);
+ }
+
+ /* Update level for progressive update. */
+ if (is_last_bounce_sample) {
+ egrid->level_bias = 1.0f;
+ }
+ else if (lbake->bounce_curr == 0) {
+ egrid->level_bias = (float)(stride << 1);
+ }
+
+ /* Only run this for the last sample of a bounce. */
+ if (is_last_bounce_sample) {
+ eevee_lightbake_copy_irradiance(lbake, lcache);
+ }
+
+ /* If it is the last sample grid sample (and last bounce). */
+ if ((lbake->bounce_curr == lbake->bounce_len - 1) &&
+ (lbake->grid_curr == lbake->grid_len - 1) &&
+ (lbake->grid_sample == lbake->grid_sample_len - 1))
+ {
+ lcache->flag &= ~LIGHTCACHE_UPDATE_GRID;
+ }
+}
+
+static void eevee_lightbake_render_probe_sample(void *ved, void *user_data)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data;
+ Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph);
+ LightCache *lcache = scene_eval->eevee.light_cache;
+ EEVEE_LightProbe *eprobe = lbake->cube;
+ LightProbe *prb = *lbake->probe;
+ float clamp = scene_eval->eevee.gi_glossy_clamp;
+ float filter_quality = scene_eval->eevee.gi_filter_quality;
+
+ /* TODO do this once for the whole bake when we have independent DRWManagers. */
+ eevee_lightbake_cache_create(vedata, lbake);
+
+ /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */
+ common_data->spec_toggle = false;
+ common_data->prb_num_planar = 0;
+ common_data->prb_num_render_cube = 0;
+ common_data->ray_type = EEVEE_RAY_GLOSSY;
+ common_data->ray_depth = 1;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ EEVEE_lightbake_render_scene(sldata, vedata, lbake->rt_fb, eprobe->position, prb->clipsta, prb->clipend);
+ EEVEE_lightbake_filter_glossy(
+ sldata, vedata, lbake->rt_color, lbake->store_fb, lbake->cube_offset, prb->intensity,
+ lcache->mips_len, filter_quality, clamp);
+
+ lcache->cube_len += 1;
+
+ /* If it's the last probe. */
+ if (lbake->cube_offset == lbake->cube_len - 1) {
+ lcache->flag &= ~LIGHTCACHE_UPDATE_CUBE;
+ }
+}
+
+static float eevee_lightbake_grid_influence_volume(EEVEE_LightGrid *grid)
+{
+ return mat4_to_scale(grid->mat);
+}
+
+static float eevee_lightbake_cube_influence_volume(EEVEE_LightProbe *eprb)
+{
+ return mat4_to_scale(eprb->attenuationmat);
+}
+
+static bool eevee_lightbake_grid_comp(EEVEE_LightGrid *grid_a, EEVEE_LightGrid *grid_b)
+{
+ float vol_a = eevee_lightbake_grid_influence_volume(grid_a);
+ float vol_b = eevee_lightbake_grid_influence_volume(grid_b);
+ return (vol_a < vol_b);
+}
+
+static bool eevee_lightbake_cube_comp(EEVEE_LightProbe *prb_a, EEVEE_LightProbe *prb_b)
+{
+ float vol_a = eevee_lightbake_cube_influence_volume(prb_a);
+ float vol_b = eevee_lightbake_cube_influence_volume(prb_b);
+ return (vol_a < vol_b);
+}
+
+#define SORT_PROBE(elems_type, prbs, elems, elems_len, comp_fn) \
+{ \
+ bool sorted = false; \
+ while (!sorted) { \
+ sorted = true; \
+ for (int i = 0; i < (elems_len) - 1; ++i) { \
+ if ((comp_fn)((elems) + i, (elems) + i+1)) { \
+ SWAP(elems_type, (elems)[i], (elems)[i+1]); \
+ SWAP(LightProbe *, (prbs)[i], (prbs)[i+1]); \
+ sorted = false; \
+ } \
+ } \
+ } \
+}
+
+static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake)
+{
+ Depsgraph *depsgraph = lbake->depsgraph;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ LightCache *lcache = scene_eval->eevee.light_cache;
+
+ /* At least one for the world */
+ int grid_len = 1;
+ int cube_len = 1;
+ int total_irr_samples = 1;
+
+ /* Convert all lightprobes to tight UBO data from all lightprobes in the scene.
+ * This allows a large number of probe to be precomputed (even dupli ones). */
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
+ {
+ if (!BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_FOR_RENDER)) {
+ continue;
+ }
+
+ if (ob->type == OB_LIGHTPROBE) {
+ LightProbe *prb = (LightProbe *)ob->data;
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ lbake->grid_prb[grid_len] = prb;
+ EEVEE_LightGrid *egrid = &lcache->grid_data[grid_len++];
+ EEVEE_lightprobes_grid_data_from_object(ob, egrid, &total_irr_samples);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ lbake->cube_prb[cube_len] = prb;
+ EEVEE_LightProbe *eprobe = &lcache->cube_data[cube_len++];
+ EEVEE_lightprobes_cube_data_from_object(ob, eprobe);
+ }
+ }
+ }
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
+
+ SORT_PROBE(EEVEE_LightGrid, lbake->grid_prb + 1, lcache->grid_data + 1, lbake->grid_len - 1, eevee_lightbake_grid_comp);
+ SORT_PROBE(EEVEE_LightProbe, lbake->cube_prb + 1, lcache->cube_data + 1, lbake->cube_len - 1, eevee_lightbake_cube_comp);
+
+ lbake->total = lbake->total_irr_samples * lbake->bounce_len + lbake->cube_len;
+ lbake->done = 0;
+}
+
+void EEVEE_lightbake_update(void *custom_data)
+{
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data;
+ Scene *scene_orig = lbake->scene;
+
+ /* If a new lightcache was created, free the old one and reference the new. */
+ if (lbake->lcache && scene_orig->eevee.light_cache != lbake->lcache) {
+ if (scene_orig->eevee.light_cache != NULL) {
+ EEVEE_lightcache_free(scene_orig->eevee.light_cache);
+ }
+ scene_orig->eevee.light_cache = lbake->lcache;
+ lbake->own_light_cache = false;
+ }
+
+ EEVEE_lightcache_info_update(&lbake->scene->eevee);
+
+ DEG_id_tag_update(&scene_orig->id, DEG_TAG_COPY_ON_WRITE);
+}
+
+static bool lightbake_do_sample(EEVEE_LightBake *lbake, void (*render_callback)(void *ved, void *user_data))
+{
+ if (G.is_break == true || *lbake->stop) {
+ return false;
+ }
+
+ Depsgraph *depsgraph = lbake->depsgraph;
+
+ /* TODO: make DRW manager instanciable (and only lock on drawing) */
+ eevee_lightbake_context_enable(lbake);
+ DRW_custom_pipeline(&draw_engine_eevee_type, depsgraph, render_callback, lbake);
+ lbake->done += 1;
+ *lbake->progress = lbake->done / (float)lbake->total;
+ *lbake->do_update = 1;
+ eevee_lightbake_context_disable(lbake);
+
+ return true;
+}
+
+void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float *progress)
+{
+ EEVEE_LightBake *lbake = (EEVEE_LightBake *)custom_data;
+ Depsgraph *depsgraph = lbake->depsgraph;
+ int frame = 0; /* TODO make it user param. */
+
+ DEG_graph_relations_update(depsgraph, lbake->bmain, lbake->scene, lbake->view_layer_input);
+ DEG_evaluate_on_framechange(lbake->bmain, depsgraph, frame);
+
+ lbake->view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ lbake->stop = stop;
+ lbake->do_update = do_update;
+ lbake->progress = progress;
+
+ /* Count lightprobes */
+ eevee_lightbake_count_probes(lbake);
+
+ /* We need to create the FBOs in the right context.
+ * We cannot do it in the main thread. */
+ eevee_lightbake_context_enable(lbake);
+ eevee_lightbake_create_resources(lbake);
+ eevee_lightbake_create_render_target(lbake, lbake->rt_res);
+ eevee_lightbake_context_disable(lbake);
+
+ /* Gather all probes data */
+ eevee_lightbake_gather_probes(lbake);
+
+ LightCache *lcache = lbake->lcache;
+
+ /* HACK: Sleep to delay the first rendering operation
+ * that causes a small freeze (caused by VBO generation)
+ * because this step is locking at this moment. */
+ /* TODO remove this. */
+ if (lbake->delay) {
+ PIL_sleep_ms(lbake->delay);
+ }
+
+ /* Render world irradiance and reflection first */
+ if (lcache->flag & LIGHTCACHE_UPDATE_WORLD) {
+ lbake->probe = NULL;
+ lightbake_do_sample(lbake, eevee_lightbake_render_world_sample);
+ }
+
+ /* Render irradiance grids */
+ if (lcache->flag & LIGHTCACHE_UPDATE_GRID) {
+ for (lbake->bounce_curr = 0; lbake->bounce_curr < lbake->bounce_len; ++lbake->bounce_curr) {
+ /* Bypass world, start at 1. */
+ lbake->probe = lbake->grid_prb + 1;
+ lbake->grid = lcache->grid_data + 1;
+ for (lbake->grid_curr = 1;
+ lbake->grid_curr < lbake->grid_len;
+ ++lbake->grid_curr, ++lbake->probe, ++lbake->grid)
+ {
+ LightProbe *prb = *lbake->probe;
+ lbake->grid_sample_len = prb->grid_resolution_x *
+ prb->grid_resolution_y *
+ prb->grid_resolution_z;
+ for (lbake->grid_sample = 0;
+ lbake->grid_sample < lbake->grid_sample_len;
+ ++lbake->grid_sample)
+ {
+ lightbake_do_sample(lbake, eevee_lightbake_render_grid_sample);
+ }
+ }
+ }
+ }
+
+ /* Render reflections */
+ if (lcache->flag & LIGHTCACHE_UPDATE_CUBE) {
+ /* Bypass world, start at 1. */
+ lbake->probe = lbake->cube_prb + 1;
+ lbake->cube = lcache->cube_data + 1;
+ for (lbake->cube_offset = 1;
+ lbake->cube_offset < lbake->cube_len;
+ ++lbake->cube_offset, ++lbake->probe, ++lbake->cube)
+ {
+ lightbake_do_sample(lbake, eevee_lightbake_render_probe_sample);
+ }
+ }
+
+ /* Read the resulting lighting data to save it to file/disk. */
+ eevee_lightbake_context_enable(lbake);
+ eevee_lightbake_readback_irradiance(lcache);
+ eevee_lightbake_readback_reflections(lcache);
+ eevee_lightbake_context_disable(lbake);
+
+ lcache->flag |= LIGHTCACHE_BAKED;
+ lcache->flag &= ~LIGHTCACHE_BAKING;
+
+ /* Assume that if lbake->gl_context is NULL
+ * we are not running in this in a job, so update
+ * the scene lightcache pointer before deleting it. */
+ if (lbake->gl_context == NULL) {
+ BLI_assert(BLI_thread_is_main());
+ EEVEE_lightbake_update(lbake);
+ }
+
+ eevee_lightbake_delete_resources(lbake);
+}
+
+/* This is to update the world irradiance and reflection contribution from
+ * within the viewport drawing (does not have the overhead of a full light cache rebuild.) */
+void EEVEE_lightbake_update_world_quick(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, const Scene *scene)
+{
+ LightCache *lcache = vedata->stl->g_data->light_cache;
+ float clamp = scene->eevee.gi_glossy_clamp;
+ float filter_quality = scene->eevee.gi_filter_quality;
+
+ EEVEE_LightBake lbake = {
+ .resource_only = true
+ };
+
+ /* Create resources. */
+ eevee_lightbake_create_render_target(&lbake, scene->eevee.gi_cubemap_resolution);
+
+ EEVEE_lightbake_cache_init(sldata, vedata, lbake.rt_color, lbake.rt_depth);
+
+ sldata->common_data.ray_type = EEVEE_RAY_GLOSSY;
+ sldata->common_data.ray_depth = 1;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ EEVEE_lightbake_render_world(sldata, vedata, lbake.rt_fb);
+ EEVEE_lightbake_filter_glossy(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f, lcache->mips_len,
+ filter_quality, clamp);
+
+ sldata->common_data.ray_type = EEVEE_RAY_DIFFUSE;
+ sldata->common_data.ray_depth = 1;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+ EEVEE_lightbake_render_world(sldata, vedata, lbake.rt_fb);
+ EEVEE_lightbake_filter_diffuse(sldata, vedata, lbake.rt_color, lbake.store_fb, 0, 1.0f);
+
+ /* Don't hide grids if they are already rendered. */
+ lcache->grid_len = max_ii(1, lcache->grid_len);
+ lcache->cube_len = 1;
+
+ lcache->flag |= LIGHTCACHE_CUBE_READY | LIGHTCACHE_GRID_READY;
+ lcache->flag &= ~LIGHTCACHE_UPDATE_WORLD;
+
+ eevee_lightbake_delete_resources(&lbake);
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
new file mode 100644
index 00000000000..3c6fc73a849
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_lightcache.h
+ * \ingroup eevee
+ */
+
+#ifndef __EEVEE_LIGHTCACHE_H__
+#define __EEVEE_LIGHTCACHE_H__
+
+#include "BLI_sys_types.h" /* for bool */
+
+struct ViewLayer;
+struct Scene;
+struct SceneEEVEE;
+struct LightCache;
+struct EEVEE_ViewLayerData;
+struct EEVEE_Data;
+struct EEVEE_LightBake;
+
+/* Light Bake */
+struct wmJob *EEVEE_lightbake_job_create(
+ struct wmWindowManager *wm, struct wmWindow *win, struct Main *bmain,
+ struct ViewLayer *view_layer, struct Scene *scene, int delay);
+void *EEVEE_lightbake_job_data_alloc(struct Main *bmain, struct ViewLayer *viewlayer, struct Scene *scene, bool run_as_job);
+void EEVEE_lightbake_job_data_free(void *custom_data);
+void EEVEE_lightbake_update(void *custom_data);
+void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float *progress);
+
+void EEVEE_lightbake_update_world_quick(struct EEVEE_ViewLayerData *sldata, struct EEVEE_Data *vedata, const Scene *scene);
+
+/* Light Cache */
+struct LightCache *EEVEE_lightcache_create(
+ const int grid_len, const int cube_len,
+ const int cube_size, const int vis_size,
+ const int irr_size[3]);
+void EEVEE_lightcache_free(struct LightCache *lcache);
+void EEVEE_lightcache_load(struct LightCache *lcache);
+void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee);
+
+#endif /* __EEVEE_LIGHTCACHE_H__ */
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
new file mode 100644
index 00000000000..0b4341f5cb9
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -0,0 +1,1239 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_lightprobes.c
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
+#include "BLI_rand.h"
+
+#include "DNA_world_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_collection.h"
+#include "BKE_object.h"
+#include "MEM_guardedalloc.h"
+
+#include "GPU_material.h"
+#include "GPU_texture.h"
+#include "GPU_glew.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_engine.h"
+#include "eevee_lightcache.h"
+#include "eevee_private.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+static struct {
+ struct GPUTexture *hammersley;
+ struct GPUTexture *planar_pool_placeholder;
+ struct GPUTexture *depth_placeholder;
+ struct GPUTexture *depth_array_placeholder;
+ struct GPUTexture *cube_face_minmaxz;
+
+ struct GPUVertFormat *format_probe_display_cube;
+ struct GPUVertFormat *format_probe_display_planar;
+} e_data = {NULL}; /* Engine data */
+
+extern GlobalsUboStorage ts;
+
+/* *********** FUNCTIONS *********** */
+
+/* TODO find a better way than this. This does not support dupli objects if
+ * the original object is hidden. */
+bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data)
+{
+ EEVEE_ObjectEngineData *oed = (EEVEE_ObjectEngineData *)user_data;
+
+ /* test disabled if group is NULL */
+ if (oed->test_data->collection == NULL)
+ return vis_in;
+
+ if (oed->test_data->cached == false)
+ oed->ob_vis_dirty = true;
+
+ /* early out, don't need to compute ob_vis yet. */
+ if (vis_in == false)
+ return vis_in;
+
+ if (oed->ob_vis_dirty) {
+ oed->ob_vis_dirty = false;
+ oed->ob_vis = BKE_collection_has_object_recursive(oed->test_data->collection, oed->ob);
+ oed->ob_vis = (oed->test_data->invert) ? !oed->ob_vis : oed->ob_vis;
+ }
+
+ return vis_in && oed->ob_vis;
+}
+
+static struct GPUTexture *create_hammersley_sample_texture(int samples)
+{
+ struct GPUTexture *tex;
+ float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * samples, "hammersley_tex");
+ int i;
+
+ for (i = 0; i < samples; i++) {
+ double dphi;
+ BLI_hammersley_1D(i, &dphi);
+ float phi = (float)dphi * 2.0f * M_PI;
+ texels[i][0] = cosf(phi);
+ texels[i][1] = sinf(phi);
+ }
+
+ tex = DRW_texture_create_1D(samples, GPU_RG16F, DRW_TEX_WRAP, (float *)texels);
+ MEM_freeN(texels);
+ return tex;
+}
+
+static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+
+ /* XXX TODO OPTIMISATION : This is a complete waist of texture memory.
+ * Instead of allocating each planar probe for each viewport,
+ * only alloc them once using the biggest viewport resolution. */
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* TODO get screen percentage from layer setting */
+ // const DRWContextState *draw_ctx = DRW_context_state_get();
+ // ViewLayer *view_layer = draw_ctx->view_layer;
+ float screen_percentage = 1.0f;
+
+ int width = (int)(viewport_size[0] * screen_percentage);
+ int height = (int)(viewport_size[1] * screen_percentage);
+
+ /* We need an Array texture so allocate it ourself */
+ if (!txl->planar_pool) {
+ if (num_planar_ref > 0) {
+ txl->planar_pool = DRW_texture_create_2D_array(width, height, max_ff(1, num_planar_ref),
+ GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ txl->planar_depth = DRW_texture_create_2D_array(width, height, max_ff(1, num_planar_ref),
+ GPU_DEPTH_COMPONENT24, 0, NULL);
+ }
+ else if (num_planar_ref == 0) {
+ /* Makes Opengl Happy : Create a placeholder texture that will never be sampled but still bound to shader. */
+ txl->planar_pool = DRW_texture_create_2D_array(1, 1, 1, GPU_RGBA8, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+ txl->planar_depth = DRW_texture_create_2D_array(1, 1, 1, GPU_DEPTH_COMPONENT24, 0, NULL);
+ }
+ }
+}
+
+void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_StorageList *stl = vedata->stl;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (!e_data.hammersley) {
+ EEVEE_shaders_lightprobe_shaders_init();
+ e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE);
+ }
+
+ /* Use fallback if we don't have gpu texture allocated an we cannot restore them. */
+ bool use_fallback_lightcache = (scene_eval->eevee.light_cache == NULL) ||
+ ((scene_eval->eevee.light_cache->grid_tx.tex == NULL) &&
+ (scene_eval->eevee.light_cache->grid_tx.data == NULL)) ||
+ ((scene_eval->eevee.light_cache->cube_tx.tex == NULL) &&
+ (scene_eval->eevee.light_cache->cube_tx.data == NULL));
+
+ if (use_fallback_lightcache && (sldata->fallback_lightcache == NULL)) {
+#if defined(IRRADIANCE_SH_L2)
+ int grid_res = 4;
+#elif defined(IRRADIANCE_CUBEMAP)
+ int grid_res = 8;
+#elif defined(IRRADIANCE_HL2)
+ int grid_res = 4;
+#endif
+ int cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(scene_eval->eevee.gi_cubemap_resolution);
+ int vis_res = scene_eval->eevee.gi_visibility_resolution;
+ sldata->fallback_lightcache = EEVEE_lightcache_create(1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1});
+ }
+
+ stl->g_data->light_cache = (use_fallback_lightcache) ? sldata->fallback_lightcache : scene_eval->eevee.light_cache;
+
+ EEVEE_lightcache_load(stl->g_data->light_cache);
+
+ if (!sldata->probes) {
+ sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo");
+ sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL);
+ sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL);
+ sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL);
+ }
+
+ common_data->prb_num_planar = 0;
+ common_data->prb_num_render_cube = 1;
+ common_data->prb_num_render_grid = 1;
+
+ common_data->spec_toggle = true;
+ common_data->ssr_toggle = true;
+ common_data->sss_toggle = true;
+
+ /* Placeholder planar pool: used when rendering planar reflections (avoid dependency loop). */
+ if (!e_data.planar_pool_placeholder) {
+ e_data.planar_pool_placeholder = DRW_texture_create_2D_array(1, 1, 1, GPU_RGBA8, DRW_TEX_FILTER, NULL);
+ }
+}
+
+/* Only init the passes useful for rendering the light cache. */
+void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPUTexture *rt_color, GPUTexture *rt_depth)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+
+ {
+ psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(
+ EEVEE_shaders_probe_filter_glossy_sh_get(), psl->probe_glossy_compute);
+
+ DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1);
+ DRW_shgroup_uniform_float(grp, "roughnessSquared", &pinfo->roughness, 1);
+ DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1);
+ DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1);
+ DRW_shgroup_uniform_float(grp, "texelSize", &pinfo->texel_size, 1);
+ DRW_shgroup_uniform_float(grp, "paddingSize", &pinfo->padding_size, 1);
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &pinfo->firefly_fac, 1);
+ DRW_shgroup_uniform_int(grp, "Layer", &pinfo->layer, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+ // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
+ DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+
+ {
+ psl->probe_diffuse_compute = DRW_pass_create("LightProbe Diffuse Compute", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(
+ EEVEE_shaders_probe_filter_diffuse_sh_get(), psl->probe_diffuse_compute);
+#ifdef IRRADIANCE_SH_L2
+ DRW_shgroup_uniform_int(grp, "probeSize", &pinfo->shres, 1);
+#else
+ DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1);
+ DRW_shgroup_uniform_float(grp, "lodFactor", &pinfo->lodfactor, 1);
+ DRW_shgroup_uniform_float(grp, "lodMax", &pinfo->lod_rt_max, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+#endif
+ DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
+ DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+
+ {
+ psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_filter_visibility_sh_get(), psl->probe_visibility_compute);
+ DRW_shgroup_uniform_int(grp, "outputSize", &pinfo->shres, 1);
+ DRW_shgroup_uniform_float(grp, "visibilityRange", &pinfo->visibility_range, 1);
+ DRW_shgroup_uniform_float(grp, "visibilityBlur", &pinfo->visibility_blur, 1);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_len, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->samples_len_inv, 1);
+ DRW_shgroup_uniform_float(grp, "storedTexelSize", &pinfo->texel_size, 1);
+ DRW_shgroup_uniform_float(grp, "nearClip", &pinfo->near_clip, 1);
+ DRW_shgroup_uniform_float(grp, "farClip", &pinfo->far_clip, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+ DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+
+ {
+ psl->probe_grid_fill = DRW_pass_create("LightProbe Grid Floodfill", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(
+ EEVEE_shaders_probe_grid_fill_sh_get(), psl->probe_grid_fill);
+
+ DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &light_cache->grid_tx.tex);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+}
+
+void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *lcache = stl->g_data->light_cache;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ pinfo->num_planar = 0;
+ pinfo->vis_data.collection = NULL;
+ pinfo->do_grid_update = false;
+ pinfo->do_cube_update = false;
+
+ {
+ psl->probe_background = DRW_pass_create("World Probe Background Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRWShadingGroup *grp = NULL;
+
+ Scene *scene = draw_ctx->scene;
+ World *wo = scene->world;
+
+ float *col = ts.colorBackground;
+
+ /* LookDev */
+ EEVEE_lookdev_cache_init(vedata, &grp, psl->probe_background, wo, pinfo);
+ /* END */
+ if (!grp && wo) {
+ col = &wo->horr;
+
+ if (wo->use_nodes && wo->nodetree) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo);
+
+ GPUMaterialStatus status = GPU_material_status(gpumat);
+
+ switch (status) {
+ case GPU_MAT_SUCCESS:
+ grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ /* TODO (fclem): remove those (need to clean the GLSL files). */
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ break;
+ default:
+ col = error_col;
+ break;
+ }
+ }
+ }
+
+ /* Fallback if shader fails or if not using nodetree. */
+ if (grp == NULL) {
+ grp = DRW_shgroup_create(EEVEE_shaders_probe_default_sh_get(), psl->probe_background);
+ DRW_shgroup_uniform_vec3(grp, "color", col, 1);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+ }
+
+ if (DRW_state_draw_support() && !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ psl->probe_display = DRW_pass_create("LightProbe Display", state);
+
+ /* Cube Display */
+ if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_CUBEMAPS && lcache->cube_len > 1) {
+ int cube_len = lcache->cube_len - 1; /* don't count the world. */
+ DRWShadingGroup *grp = DRW_shgroup_empty_tri_batch_create(
+ EEVEE_shaders_probe_cube_display_sh_get(), psl->probe_display, cube_len * 2);
+
+ DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+ DRW_shgroup_uniform_float_copy(grp, "sphere_size", scene_eval->eevee.gi_cubemap_draw_size * 0.5f);
+ /* TODO (fclem) get rid of those UBO. */
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ }
+
+ /* Grid Display */
+ if (scene_eval->eevee.flag & SCE_EEVEE_SHOW_IRRADIANCE) {
+ EEVEE_LightGrid *egrid = lcache->grid_data + 1;
+ for (int p = 1; p < lcache->grid_len; ++p, egrid++) {
+ DRWShadingGroup *shgrp = DRW_shgroup_create(
+ EEVEE_shaders_probe_grid_display_sh_get(), psl->probe_display);
+
+ DRW_shgroup_uniform_int(shgrp, "offset", &egrid->offset, 1);
+ DRW_shgroup_uniform_ivec3(shgrp, "grid_resolution", egrid->resolution, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "corner", egrid->corner, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "increment_x", egrid->increment_x, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "increment_y", egrid->increment_y, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "increment_z", egrid->increment_z, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+ DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex);
+ DRW_shgroup_uniform_float_copy(shgrp, "sphere_size", scene_eval->eevee.gi_irradiance_draw_size * 0.5f);
+ /* TODO (fclem) get rid of those UBO. */
+ DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ int tri_count = egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2] * 2;
+ DRW_shgroup_call_procedural_triangles_add(shgrp, tri_count, NULL);
+ }
+ }
+
+ /* Planar Display */
+ DRW_shgroup_instance_format(e_data.format_probe_display_planar, {
+ {"probe_id", DRW_ATTRIB_INT, 1},
+ {"probe_mat", DRW_ATTRIB_FLOAT, 16},
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ EEVEE_shaders_probe_planar_display_sh_get(),
+ psl->probe_display,
+ DRW_cache_quad_get(),
+ e_data.format_probe_display_planar);
+ stl->g_data->planar_display_shgrp = grp;
+ DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool);
+ }
+ else {
+ stl->g_data->planar_display_shgrp = NULL;
+ }
+
+ {
+ psl->probe_planar_downsample_ps = DRW_pass_create("LightProbe Planar Downsample", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(
+ EEVEE_shaders_probe_planar_downsample_sh_get(), psl->probe_planar_downsample_ps);
+
+ DRW_shgroup_uniform_texture_ref(grp, "source", &txl->planar_pool);
+ DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1);
+ DRW_shgroup_call_instances_add(grp, DRW_cache_fullscreen_quad_get(), NULL, (uint *)&pinfo->num_planar);
+ }
+}
+
+static bool eevee_lightprobes_culling_test(Object *ob)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
+
+ switch (probe->type) {
+ case LIGHTPROBE_TYPE_PLANAR:
+ {
+ /* See if this planar probe is inside the view frustum. If not, no need to update it. */
+ /* NOTE: this could be bypassed if we want feedback loop mirrors for rendering. */
+ BoundBox bbox; float tmp[4][4];
+ const float min[3] = {-1.0f, -1.0f, -1.0f};
+ const float max[3] = { 1.0f, 1.0f, 1.0f};
+ BKE_boundbox_init_from_minmax(&bbox, min, max);
+
+ copy_m4_m4(tmp, ob->obmat);
+ normalize_v3(tmp[2]);
+ mul_v3_fl(tmp[2], probe->distinf);
+
+ for (int v = 0; v < 8; ++v) {
+ mul_m4_v3(tmp, bbox.vec[v]);
+ }
+ return DRW_culling_box_test(&bbox);
+ }
+ case LIGHTPROBE_TYPE_CUBE:
+ return true; /* TODO */
+ case LIGHTPROBE_TYPE_GRID:
+ return true; /* TODO */
+ }
+ BLI_assert(0);
+ return true;
+}
+
+void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *ob)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightProbe *probe = (LightProbe *)ob->data;
+
+ if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) ||
+ (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE) ||
+ (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_planar >= MAX_PLANAR))
+ {
+ printf("Too many probes in the view !!!\n");
+ return;
+ }
+
+ if (probe->type == LIGHTPROBE_TYPE_PLANAR) {
+ if (!eevee_lightprobes_culling_test(ob)) {
+ return; /* Culled */
+ }
+ EEVEE_lightprobes_planar_data_from_object(ob,
+ &pinfo->planar_data[pinfo->num_planar],
+ &pinfo->planar_vis_tests[pinfo->num_planar]);
+ /* Debug Display */
+ DRWShadingGroup *grp = vedata->stl->g_data->planar_display_shgrp;
+ if (grp && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ DRW_shgroup_call_dynamic_add(grp, &pinfo->num_planar, ob->obmat);
+ }
+
+ pinfo->num_planar++;
+ }
+ else {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ if (ped->need_update) {
+ if (probe->type == LIGHTPROBE_TYPE_GRID) {
+ pinfo->do_grid_update = true;
+ }
+ else {
+ pinfo->do_cube_update = true;
+ }
+ ped->need_update = false;
+ }
+ }
+}
+
+void EEVEE_lightprobes_grid_data_from_object(Object *ob, EEVEE_LightGrid *egrid, int *offset)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
+
+ copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x);
+
+ /* Save current offset and advance it for the next grid. */
+ egrid->offset = *offset;
+ *offset += egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2];
+
+ /* Add one for level 0 */
+ float fac = 1.0f / max_ff(1e-8f, probe->falloff);
+ egrid->attenuation_scale = fac / max_ff(1e-8f, probe->distinf);
+ egrid->attenuation_bias = fac;
+
+ /* Update transforms */
+ float cell_dim[3], half_cell_dim[3];
+ cell_dim[0] = 2.0f / egrid->resolution[0];
+ cell_dim[1] = 2.0f / egrid->resolution[1];
+ cell_dim[2] = 2.0f / egrid->resolution[2];
+
+ mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
+
+ /* Matrix converting world space to cell ranges. */
+ invert_m4_m4(egrid->mat, ob->obmat);
+
+ /* First cell. */
+ copy_v3_fl(egrid->corner, -1.0f);
+ add_v3_v3(egrid->corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, egrid->corner);
+
+ /* Opposite neighbor cell. */
+ copy_v3_fl3(egrid->increment_x, cell_dim[0], 0.0f, 0.0f);
+ add_v3_v3(egrid->increment_x, half_cell_dim);
+ add_v3_fl(egrid->increment_x, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_x);
+ sub_v3_v3(egrid->increment_x, egrid->corner);
+
+ copy_v3_fl3(egrid->increment_y, 0.0f, cell_dim[1], 0.0f);
+ add_v3_v3(egrid->increment_y, half_cell_dim);
+ add_v3_fl(egrid->increment_y, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_y);
+ sub_v3_v3(egrid->increment_y, egrid->corner);
+
+ copy_v3_fl3(egrid->increment_z, 0.0f, 0.0f, cell_dim[2]);
+ add_v3_v3(egrid->increment_z, half_cell_dim);
+ add_v3_fl(egrid->increment_z, -1.0f);
+ mul_m4_v3(ob->obmat, egrid->increment_z);
+ sub_v3_v3(egrid->increment_z, egrid->corner);
+
+ /* Visibility bias */
+ egrid->visibility_bias = 0.05f * probe->vis_bias;
+ egrid->visibility_bleed = probe->vis_bleedbias;
+ egrid->visibility_range = 1.0f + sqrtf(max_fff(len_squared_v3(egrid->increment_x),
+ len_squared_v3(egrid->increment_y),
+ len_squared_v3(egrid->increment_z)));
+}
+
+void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *eprobe)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
+
+ /* Update transforms */
+ copy_v3_v3(eprobe->position, ob->obmat[3]);
+
+ /* Attenuation */
+ eprobe->attenuation_type = probe->attenuation_type;
+ eprobe->attenuation_fac = 1.0f / max_ff(1e-8f, probe->falloff);
+
+ unit_m4(eprobe->attenuationmat);
+ scale_m4_fl(eprobe->attenuationmat, probe->distinf);
+ mul_m4_m4m4(eprobe->attenuationmat, ob->obmat, eprobe->attenuationmat);
+ invert_m4(eprobe->attenuationmat);
+
+ /* Parallax */
+ unit_m4(eprobe->parallaxmat);
+
+ if ((probe->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) {
+ eprobe->parallax_type = probe->parallax_type;
+ scale_m4_fl(eprobe->parallaxmat, probe->distpar);
+ }
+ else {
+ eprobe->parallax_type = probe->attenuation_type;
+ scale_m4_fl(eprobe->parallaxmat, probe->distinf);
+ }
+
+ mul_m4_m4m4(eprobe->parallaxmat, ob->obmat, eprobe->parallaxmat);
+ invert_m4(eprobe->parallaxmat);
+}
+
+void EEVEE_lightprobes_planar_data_from_object(Object *ob, EEVEE_PlanarReflection *eplanar, EEVEE_LightProbeVisTest *vis_test)
+{
+ LightProbe *probe = (LightProbe *)ob->data;
+ float normat[4][4], imat[4][4];
+
+ vis_test->collection = probe->visibility_grp;
+ vis_test->invert = probe->flag & LIGHTPROBE_FLAG_INVERT_GROUP;
+ vis_test->cached = false;
+
+ /* Computing mtx : matrix that mirror position around object's XY plane. */
+ normalize_m4_m4(normat, ob->obmat); /* object > world */
+ invert_m4_m4(imat, normat); /* world > object */
+ /* XY reflection plane */
+ imat[0][2] = -imat[0][2];
+ imat[1][2] = -imat[1][2];
+ imat[2][2] = -imat[2][2];
+ imat[3][2] = -imat[3][2]; /* world > object > mirrored obj */
+ mul_m4_m4m4(eplanar->mtx, normat, imat); /* world > object > mirrored obj > world */
+
+ /* Compute clip plane equation / normal. */
+ copy_v3_v3(eplanar->plane_equation, ob->obmat[2]);
+ normalize_v3(eplanar->plane_equation); /* plane normal */
+ eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, ob->obmat[3]);
+ eplanar->clipsta = probe->clipsta;
+
+ /* Compute XY clip planes. */
+ normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]);
+ normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]);
+
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
+ mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+ eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec);
+
+ vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f;
+ mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+ eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec);
+
+ vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
+ mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+ eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec);
+
+ vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f;
+ mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+ eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec);
+
+ /* Facing factors */
+ float max_angle = max_ff(1e-2f, 1.0f - probe->falloff) * M_PI * 0.5f;
+ float min_angle = 0.0f;
+ eplanar->facing_scale = 1.0f / max_ff(1e-8f, cosf(min_angle) - cosf(max_angle));
+ eplanar->facing_bias = -min_ff(1.0f - 1e-8f, cosf(max_angle)) * eplanar->facing_scale;
+
+ /* Distance factors */
+ float max_dist = probe->distinf;
+ float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf;
+ eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist);
+ eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale;
+}
+
+static void lightbake_planar_compute_render_matrices(
+ EEVEE_PlanarReflection *eplanar, DRWMatrixState *r_matstate, const float viewmat[4][4])
+{
+ /* Reflect Camera Matrix. */
+ mul_m4_m4m4(r_matstate->viewmat, viewmat, eplanar->mtx);
+ /* TODO FOV margin */
+ /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */
+ DRW_viewport_matrix_get(r_matstate->winmat, DRW_MAT_WIN);
+ /* Apply Projection Matrix. */
+ mul_m4_m4m4(r_matstate->persmat, r_matstate->winmat, r_matstate->viewmat);
+
+ /* This is the matrix used to reconstruct texture coordinates.
+ * We use the original view matrix because it does not create
+ * visual artifacts if receiver is not perfectly aligned with
+ * the planar reflection probe. */
+ mul_m4_m4m4(eplanar->reflectionmat, r_matstate->winmat, viewmat); /* TODO FOV margin */
+ /* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */
+ mul_m4_m4m4(eplanar->reflectionmat, texcomat, eplanar->reflectionmat);
+}
+
+static void eevee_lightprobes_extract_from_cache(EEVEE_LightProbesInfo *pinfo, LightCache *lcache)
+{
+ /* copy the entire cache for now (up to MAX_PROBE) */
+ /* TODO Frutum cull to only add visible probes. */
+ memcpy(pinfo->probe_data, lcache->cube_data, sizeof(EEVEE_LightProbe) * max_ii(1, min_ii(lcache->cube_len, MAX_PROBE)));
+ /* TODO compute the max number of grid based on sample count. */
+ memcpy(pinfo->grid_data, lcache->grid_data, sizeof(EEVEE_LightGrid) * max_ii(1, min_ii(lcache->grid_len, MAX_GRID)));
+}
+
+void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ LightCache *light_cache = stl->g_data->light_cache;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ eevee_lightprobes_extract_from_cache(sldata->probes, light_cache);
+
+ DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data);
+ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
+
+ /* For shading, save max level of the octahedron map */
+ sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len - 1.0f;
+ sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL;
+ sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res;
+ sldata->common_data.prb_irradiance_smooth = SQUARE(scene_eval->eevee.gi_irradiance_smoothing);
+ sldata->common_data.prb_num_render_cube = max_ii(1, light_cache->cube_len);
+ sldata->common_data.prb_num_render_grid = max_ii(1, light_cache->grid_len);
+ sldata->common_data.prb_num_planar = pinfo->num_planar;
+
+ if (pinfo->num_planar != pinfo->cache_num_planar) {
+ DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_pool);
+ DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_depth);
+ pinfo->cache_num_planar = pinfo->num_planar;
+ }
+ planar_pool_ensure_alloc(vedata, pinfo->num_planar);
+
+ /* If lightcache auto-update is enable we tag the relevant part
+ * of the cache to update and fire up a baking job. */
+ if (!DRW_state_is_image_render() && !DRW_state_is_opengl_render() &&
+ (pinfo->do_grid_update || pinfo->do_cube_update))
+ {
+ BLI_assert(draw_ctx->evil_C);
+
+ if (draw_ctx->scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) {
+ Scene *scene_orig = DEG_get_input_scene(draw_ctx->depsgraph);
+ if (scene_orig->eevee.light_cache != NULL) {
+ if (pinfo->do_grid_update) {
+ scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID;
+ }
+ /* If we update grid we need to update the cubemaps too.
+ * So always refresh cubemaps. */
+ scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE;
+ /* Tag the lightcache to auto update. */
+ scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_AUTO;
+ /* Use a notifier to trigger the operator after drawing. */
+ WM_event_add_notifier(draw_ctx->evil_C, NC_LIGHTPROBE, scene_orig);
+ }
+ }
+ }
+}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Rendering
+ * \{ */
+
+typedef struct EEVEE_BakeRenderData {
+ EEVEE_Data *vedata;
+ EEVEE_ViewLayerData *sldata;
+ struct GPUFrameBuffer **face_fb; /* should contain 6 framebuffer */
+} EEVEE_BakeRenderData;
+
+static void render_cubemap(
+ void (*callback)(int face, EEVEE_BakeRenderData *user_data), EEVEE_BakeRenderData *user_data,
+ const float pos[3], float clipsta, float clipend)
+{
+ DRWMatrixState matstate;
+
+ /* Move to capture position */
+ float posmat[4][4];
+ unit_m4(posmat);
+ negate_v3_v3(posmat[3], pos);
+
+ perspective_m4(matstate.winmat, -clipsta, clipsta, -clipsta, clipsta, clipsta, clipend);
+ invert_m4_m4(matstate.wininv, matstate.winmat);
+
+ /* 1 - Render to each cubeface individually.
+ * We do this instead of using geometry shader because a) it's faster,
+ * b) it's easier than fixing the nodetree shaders (for view dependent effects). */
+ for (int i = 0; i < 6; ++i) {
+ /* Setup custom matrices */
+ mul_m4_m4m4(matstate.viewmat, cubefacemat[i], posmat);
+ mul_m4_m4m4(matstate.persmat, matstate.winmat, matstate.viewmat);
+ invert_m4_m4(matstate.persinv, matstate.persmat);
+ invert_m4_m4(matstate.viewinv, matstate.viewmat);
+ invert_m4_m4(matstate.wininv, matstate.winmat);
+
+ DRW_viewport_matrix_override_set_all(&matstate);
+
+ callback(i, user_data);
+ }
+}
+
+static void render_reflections(
+ void (*callback)(int face, EEVEE_BakeRenderData *user_data), EEVEE_BakeRenderData *user_data,
+ EEVEE_PlanarReflection *planar_data, int ref_count)
+{
+ DRWMatrixState matstate;
+
+ float original_viewmat[4][4];
+ DRW_viewport_matrix_get(original_viewmat, DRW_MAT_VIEW);
+
+ for (int i = 0; i < ref_count; ++i) {
+ /* Setup custom matrices */
+ lightbake_planar_compute_render_matrices(planar_data + i, &matstate, original_viewmat);
+ invert_m4_m4(matstate.persinv, matstate.persmat);
+ invert_m4_m4(matstate.viewinv, matstate.viewmat);
+ invert_m4_m4(matstate.wininv, matstate.winmat);
+ DRW_viewport_matrix_override_set_all(&matstate);
+
+ callback(i, user_data);
+ }
+}
+
+static void lightbake_render_world_face(int face, EEVEE_BakeRenderData *user_data)
+{
+ EEVEE_PassList *psl = user_data->vedata->psl;
+ struct GPUFrameBuffer **face_fb = user_data->face_fb;
+
+ /* For world probe, we don't need to clear the color buffer
+ * since we render the background directly. */
+ GPU_framebuffer_bind(face_fb[face]);
+ GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
+ DRW_draw_pass(psl->probe_background);
+}
+
+void EEVEE_lightbake_render_world(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6])
+{
+ EEVEE_BakeRenderData brdata = {
+ .vedata = vedata,
+ .face_fb = face_fb
+ };
+
+ render_cubemap(lightbake_render_world_face, &brdata, (float[3]){0.0f}, 1.0f, 10.0f);
+}
+
+static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_data)
+{
+ EEVEE_ViewLayerData *sldata = user_data->sldata;
+ EEVEE_PassList *psl = user_data->vedata->psl;
+ struct GPUFrameBuffer **face_fb = user_data->face_fb;
+
+ /* Be sure that cascaded shadow maps are updated. */
+ EEVEE_draw_shadows(sldata, user_data->vedata);
+
+ GPU_framebuffer_bind(face_fb[face]);
+ GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
+
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+ DRW_draw_pass(psl->probe_background);
+ DRW_draw_pass(psl->material_pass);
+ DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
+ EEVEE_draw_default_passes(psl);
+}
+
+/* Render the scene to the probe_rt texture. */
+void EEVEE_lightbake_render_scene(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6],
+ const float pos[3], float near_clip, float far_clip)
+{
+ EEVEE_BakeRenderData brdata = {
+ .vedata = vedata,
+ .sldata = sldata,
+ .face_fb = face_fb
+ };
+
+ render_cubemap(lightbake_render_scene_face, &brdata, pos, near_clip, far_clip);
+}
+
+static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *user_data)
+{
+ EEVEE_Data *vedata = user_data->vedata;
+ EEVEE_ViewLayerData *sldata = user_data->sldata;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ EEVEE_PlanarReflection *eplanar = pinfo->planar_data + layer;
+
+ GPU_framebuffer_ensure_config(&fbl->planarref_fb, {
+ GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_depth, layer),
+ GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_pool, layer)
+ });
+
+ /* Use visibility info for this planar reflection. */
+ pinfo->vis_data = pinfo->planar_vis_tests[layer];
+
+ /* Avoid using the texture attached to framebuffer when rendering. */
+ /* XXX */
+ GPUTexture *tmp_planar_pool = txl->planar_pool;
+ GPUTexture *tmp_planar_depth = txl->planar_depth;
+ txl->planar_pool = e_data.planar_pool_placeholder;
+ txl->planar_depth = e_data.depth_array_placeholder;
+
+ /* Be sure that cascaded shadow maps are updated. */
+ DRW_stats_group_start("Planar Reflection");
+
+ /* Be sure that cascaded shadow maps are updated. */
+ EEVEE_draw_shadows(sldata, vedata);
+ /* Since we are rendering with an inverted view matrix, we need
+ * to invert the facing for backface culling to be the same. */
+ DRW_state_invert_facing();
+ /* Compute offset plane equation (fix missing texels near reflection plane). */
+ copy_v4_v4(sldata->clip_data.clip_planes[0], eplanar->plane_equation);
+ sldata->clip_data.clip_planes[0][3] += eplanar->clipsta;
+ /* Set clipping plane */
+ DRW_uniformbuffer_update(sldata->clip_ubo, &sldata->clip_data);
+ DRW_state_clip_planes_count_set(1);
+
+ GPU_framebuffer_bind(fbl->planarref_fb);
+ GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0);
+
+ /* Slight modification: we handle refraction as normal
+ * shading and don't do SSRefraction. */
+
+ DRW_draw_pass(psl->depth_pass_clip);
+ DRW_draw_pass(psl->depth_pass_clip_cull);
+ DRW_draw_pass(psl->refract_depth_pass);
+ DRW_draw_pass(psl->refract_depth_pass_cull);
+
+ DRW_draw_pass(psl->probe_background);
+ EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer);
+ EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer);
+
+ GPU_framebuffer_bind(fbl->planarref_fb);
+
+ /* Shading pass */
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+ DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
+ DRW_draw_pass(psl->refract_pass);
+
+ /* Transparent */
+ if (DRW_state_is_image_render()) {
+ /* Do the reordering only for offline because it can be costly. */
+ DRW_pass_sort_shgroup_z(psl->transparent_pass);
+ }
+ DRW_draw_pass(psl->transparent_pass);
+
+ DRW_state_invert_facing();
+ DRW_state_clip_planes_reset();
+
+ DRW_stats_group_end();
+
+ /* Restore */
+ txl->planar_pool = tmp_planar_pool;
+ txl->planar_depth = tmp_planar_depth;
+}
+
+static void eevee_lightbake_render_scene_to_planars(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_BakeRenderData brdata = {
+ .vedata = vedata,
+ .sldata = sldata,
+ };
+
+ render_reflections(lightbake_render_scene_reflected, &brdata, sldata->probes->planar_data, sldata->probes->num_planar);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Filtering
+ * \{ */
+
+/* Glossy filter rt_color to light_cache->cube_tx.tex at index probe_idx */
+void EEVEE_lightbake_filter_glossy(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ struct GPUTexture *rt_color, struct GPUFrameBuffer *fb,
+ int probe_idx, float intensity, int maxlevel, float filter_quality, float firefly_fac)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
+
+ float target_size = (float)GPU_texture_width(rt_color);
+
+ /* Max lod used from the render target probe */
+ pinfo->lod_rt_max = floorf(log2f(target_size)) - 2.0f;
+ pinfo->intensity_fac = intensity;
+
+ /* Start fresh */
+ GPU_framebuffer_ensure_config(&fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE
+ });
+
+ /* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */
+ /* Bind next framebuffer to be able to gen. mips for probe_rt. */
+ EEVEE_downsample_cube_buffer(vedata, rt_color, (int)(pinfo->lod_rt_max));
+
+ /* 3 - Render to probe array to the specified layer, do prefiltering. */
+ int mipsize = GPU_texture_width(light_cache->cube_tx.tex);
+ for (int i = 0; i < maxlevel + 1; i++) {
+ float bias = (i == 0) ? -1.0f : 1.0f;
+ pinfo->texel_size = 1.0f / (float)mipsize;
+ pinfo->padding_size = (i == maxlevel) ? 0 : (float)(1 << (maxlevel - i - 1));
+ pinfo->padding_size *= pinfo->texel_size;
+ pinfo->layer = probe_idx;
+ pinfo->roughness = i / (float)maxlevel;
+ pinfo->roughness *= pinfo->roughness; /* Disney Roughness */
+ pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */
+ CLAMP(pinfo->roughness, 1e-8f, 0.99999f); /* Avoid artifacts */
+
+#if 1 /* Variable Sample count (fast) */
+ switch (i) {
+ case 0: pinfo->samples_len = 1.0f; break;
+ case 1: pinfo->samples_len = 16.0f; break;
+ case 2: pinfo->samples_len = 32.0f; break;
+ case 3: pinfo->samples_len = 64.0f; break;
+ default: pinfo->samples_len = 128.0f; break;
+ }
+#else /* Constant Sample count (slow) */
+ pinfo->samples_len = 1024.0f;
+#endif
+ /* Cannot go higher than HAMMERSLEY_SIZE */
+ CLAMP(filter_quality, 1.0f, 8.0f);
+ pinfo->samples_len *= filter_quality;
+
+ pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
+ pinfo->lodfactor = bias + 0.5f * log((float)(target_size * target_size) * pinfo->samples_len_inv) / log(2);
+ pinfo->firefly_fac = (firefly_fac > 0.0) ? firefly_fac : 1e16;
+
+ GPU_framebuffer_ensure_config(&fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE_MIP(light_cache->cube_tx.tex, i)
+ });
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, 0, 0, mipsize, mipsize);
+ DRW_draw_pass(psl->probe_glossy_compute);
+
+ mipsize /= 2;
+ CLAMP_MIN(mipsize, 1);
+ }
+}
+
+/* Diffuse filter rt_color to light_cache->grid_tx.tex at index grid_offset */
+void EEVEE_lightbake_filter_diffuse(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ struct GPUTexture *rt_color, struct GPUFrameBuffer *fb,
+ int grid_offset, float intensity)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
+
+ float target_size = (float)GPU_texture_width(rt_color);
+
+ pinfo->intensity_fac = intensity;
+
+ /* find cell position on the virtual 3D texture */
+ /* NOTE : Keep in sync with load_irradiance_cell() */
+#if defined(IRRADIANCE_SH_L2)
+ int size[2] = {3, 3};
+#elif defined(IRRADIANCE_CUBEMAP)
+ int size[2] = {8, 8};
+ pinfo->samples_len = 1024.0f;
+#elif defined(IRRADIANCE_HL2)
+ int size[2] = {3, 2};
+ pinfo->samples_len = 1024.0f;
+#endif
+
+ int cell_per_row = GPU_texture_width(light_cache->grid_tx.tex) / size[0];
+ int x = size[0] * (grid_offset % cell_per_row);
+ int y = size[1] * (grid_offset / cell_per_row);
+
+#ifndef IRRADIANCE_SH_L2
+ /* Tweaking parameters to balance perf. vs precision */
+ const float bias = 0.0f;
+ pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
+ pinfo->lodfactor = bias + 0.5f * log((float)(target_size * target_size) * pinfo->samples_len_inv) / log(2);
+ pinfo->lod_rt_max = floorf(log2f(target_size)) - 2.0f;
+#else
+ pinfo->shres = 32; /* Less texture fetches & reduce branches */
+ pinfo->lod_rt_max = 2.0f; /* Improve cache reuse */
+#endif
+
+ /* Start fresh */
+ GPU_framebuffer_ensure_config(&fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE
+ });
+
+ /* 4 - Compute diffuse irradiance */
+ EEVEE_downsample_cube_buffer(vedata, rt_color, (int)(pinfo->lod_rt_max));
+
+ GPU_framebuffer_ensure_config(&fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE_LAYER(light_cache->grid_tx.tex, 0)
+ });
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, x, y, size[0], size[1]);
+ DRW_draw_pass(psl->probe_diffuse_compute);
+}
+
+/* Filter rt_depth to light_cache->grid_tx.tex at index grid_offset */
+void EEVEE_lightbake_filter_visibility(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ struct GPUTexture *UNUSED(rt_depth), struct GPUFrameBuffer *fb,
+ int grid_offset, float clipsta, float clipend,
+ float vis_range, float vis_blur, int vis_size)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
+
+ pinfo->samples_len = 512.0f; /* TODO refine */
+ pinfo->samples_len_inv = 1.0f / pinfo->samples_len;
+ pinfo->shres = vis_size;
+ pinfo->visibility_range = vis_range;
+ pinfo->visibility_blur = vis_blur;
+ pinfo->near_clip = -clipsta;
+ pinfo->far_clip = -clipend;
+ pinfo->texel_size = 1.0f / (float)vis_size;
+
+ int cell_per_col = GPU_texture_height(light_cache->grid_tx.tex) / vis_size;
+ int cell_per_row = GPU_texture_width(light_cache->grid_tx.tex) / vis_size;
+ int x = vis_size * (grid_offset % cell_per_row);
+ int y = vis_size * ((grid_offset / cell_per_row) % cell_per_col);
+ int layer = 1 + ((grid_offset / cell_per_row) / cell_per_col);
+
+ GPU_framebuffer_ensure_config(&fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE_LAYER(light_cache->grid_tx.tex, layer)
+ });
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, x, y, vis_size, vis_size);
+ DRW_draw_pass(psl->probe_visibility_compute);
+}
+
+/* Actually a simple downsampling */
+static void downsample_planar(void *vedata, int level)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+
+ const float *size = DRW_viewport_size_get();
+ copy_v2_v2(stl->g_data->planar_texel_size, size);
+ for (int i = 0; i < level - 1; ++i) {
+ stl->g_data->planar_texel_size[0] /= 2.0f;
+ stl->g_data->planar_texel_size[1] /= 2.0f;
+ min_ff(floorf(stl->g_data->planar_texel_size[0]), 1.0f);
+ min_ff(floorf(stl->g_data->planar_texel_size[1]), 1.0f);
+ }
+ invert_v2(stl->g_data->planar_texel_size);
+
+ DRW_draw_pass(psl->probe_planar_downsample_ps);
+}
+
+static void EEVEE_lightbake_filter_planar(EEVEE_Data *vedata)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+
+ DRW_stats_group_start("Planar Probe Downsample");
+
+ GPU_framebuffer_ensure_config(&fbl->planar_downsample_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->planar_pool)
+ });
+
+ GPU_framebuffer_recursive_downsample(fbl->planar_downsample_fb, MAX_PLANAR_LOD_LEVEL, &downsample_planar, vedata);
+ DRW_stats_group_end();
+}
+
+/** \} */
+
+void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ DRWMatrixState saved_mats;
+
+ if (pinfo->num_planar == 0) {
+ /* Disable SSR if we cannot read previous frame */
+ common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer;
+ common_data->prb_num_planar = 0;
+ return;
+ }
+
+ /* We need to save the Matrices before overidding them */
+ DRW_viewport_matrix_get_all(&saved_mats);
+
+ /* Temporary Remove all planar reflections (avoid lag effect). */
+ common_data->prb_num_planar = 0;
+ /* Turn off ssr to avoid black specular */
+ common_data->ssr_toggle = false;
+ common_data->sss_toggle = false;
+
+ common_data->ray_type = EEVEE_RAY_GLOSSY;
+ common_data->ray_depth = 1.0f;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ /* Rendering happens here! */
+ eevee_lightbake_render_scene_to_planars(sldata, vedata);
+
+ /* Make sure no aditionnal visibility check runs after this. */
+ pinfo->vis_data.collection = NULL;
+
+ DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data);
+
+ /* Restore */
+ common_data->prb_num_planar = pinfo->num_planar;
+ common_data->ssr_toggle = true;
+ common_data->sss_toggle = true;
+
+ /* Prefilter for SSR */
+ if ((vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) {
+ EEVEE_lightbake_filter_planar(vedata);
+ }
+
+ DRW_viewport_matrix_override_set_all(&saved_mats);
+
+ if (DRW_state_is_image_render()) {
+ /* Sort transparents because planar reflections could have re-sorted them. */
+ DRW_pass_sort_shgroup_z(vedata->psl->transparent_pass);
+ }
+
+ /* Disable SSR if we cannot read previous frame */
+ common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer;
+}
+
+void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ LightCache *light_cache = vedata->stl->g_data->light_cache;
+
+ if (light_cache->flag & LIGHTCACHE_UPDATE_WORLD) {
+ DRWMatrixState saved_mats;
+ DRW_viewport_matrix_get_all(&saved_mats);
+ EEVEE_lightbake_update_world_quick(sldata, vedata, scene_eval);
+ DRW_viewport_matrix_override_set_all(&saved_mats);
+ }
+}
+
+void EEVEE_lightprobes_free(void)
+{
+ MEM_SAFE_FREE(e_data.format_probe_display_cube);
+ MEM_SAFE_FREE(e_data.format_probe_display_planar);
+ DRW_TEXTURE_FREE_SAFE(e_data.hammersley);
+ DRW_TEXTURE_FREE_SAFE(e_data.planar_pool_placeholder);
+ DRW_TEXTURE_FREE_SAFE(e_data.depth_placeholder);
+ DRW_TEXTURE_FREE_SAFE(e_data.depth_array_placeholder);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
new file mode 100644
index 00000000000..b946a49ea14
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -0,0 +1,1486 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_lights.c
+ * \ingroup DNA
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_rand.h"
+#include "BLI_rect.h"
+
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_engine.h"
+#include "eevee_private.h"
+
+#define SHADOW_CASTER_ALLOC_CHUNK 16
+
+// #define DEBUG_CSM
+// #define DEBUG_SHADOW_DISTRIBUTION
+
+static struct {
+ struct GPUShader *shadow_sh;
+ struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX];
+ struct GPUShader *shadow_store_cube_high_sh[SHADOW_METHOD_MAX];
+ struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX];
+ struct GPUShader *shadow_store_cascade_high_sh[SHADOW_METHOD_MAX];
+ struct GPUShader *shadow_copy_cube_sh[SHADOW_METHOD_MAX];
+ struct GPUShader *shadow_copy_cascade_sh[SHADOW_METHOD_MAX];
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_shadow_vert_glsl[];
+extern char datatoc_shadow_frag_glsl[];
+extern char datatoc_shadow_store_frag_glsl[];
+extern char datatoc_shadow_copy_frag_glsl[];
+extern char datatoc_concentric_samples_lib_glsl[];
+
+/* Prototypes */
+static void eevee_light_setup(Object *ob, EEVEE_Light *evli);
+static float light_attenuation_radius_get(Lamp *la, float light_threshold);
+
+/* *********** LIGHT BITS *********** */
+static void lightbits_set_single(EEVEE_LightBits *bitf, uint idx, bool val)
+{
+ if (val) {
+ bitf->fields[idx / 8] |= (1 << (idx % 8));
+ }
+ else {
+ bitf->fields[idx / 8] &= ~(1 << (idx % 8));
+ }
+}
+
+static void lightbits_set_all(EEVEE_LightBits *bitf, bool val)
+{
+ memset(bitf, (val) ? 0xFF : 0x00, sizeof(EEVEE_LightBits));
+}
+
+static void lightbits_or(EEVEE_LightBits *r, const EEVEE_LightBits *v)
+{
+ for (int i = 0; i < MAX_LIGHTBITS_FIELDS; ++i) {
+ r->fields[i] |= v->fields[i];
+ }
+}
+
+static bool lightbits_get(const EEVEE_LightBits *r, uint idx)
+{
+ return r->fields[idx / 8] & (1 << (idx % 8));
+}
+
+static void lightbits_convert(
+ EEVEE_LightBits *r, const EEVEE_LightBits *bitf, const int *light_bit_conv_table, uint table_length)
+{
+ for (int i = 0; i < table_length; ++i) {
+ if (lightbits_get(bitf, i) != 0) {
+ if (light_bit_conv_table[i] >= 0) {
+ r->fields[i / 8] |= (1 << (i % 8));
+ }
+ }
+ }
+}
+
+/* *********** FUNCTIONS *********** */
+
+void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
+{
+ const uint shadow_ubo_size = sizeof(EEVEE_Shadow) * MAX_SHADOW +
+ sizeof(EEVEE_ShadowCube) * MAX_SHADOW_CUBE +
+ sizeof(EEVEE_ShadowCascade) * MAX_SHADOW_CASCADE;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (!e_data.shadow_sh) {
+ e_data.shadow_sh = DRW_shader_create(
+ datatoc_shadow_vert_glsl, NULL, datatoc_shadow_frag_glsl, NULL);
+ }
+
+ if (!sldata->lamps) {
+ sldata->lamps = MEM_callocN(sizeof(EEVEE_LampsInfo), "EEVEE_LampsInfo");
+ sldata->light_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_Light) * MAX_LIGHT, NULL);
+ sldata->shadow_ubo = DRW_uniformbuffer_create(shadow_ubo_size, NULL);
+ sldata->shadow_render_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_ShadowRender), NULL);
+
+ for (int i = 0; i < 2; ++i) {
+ sldata->shcasters_buffers[i].shadow_casters = MEM_callocN(sizeof(EEVEE_ShadowCaster) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_ShadowCaster buf");
+ sldata->shcasters_buffers[i].flags = MEM_callocN(sizeof(sldata->shcasters_buffers[0].flags) * SHADOW_CASTER_ALLOC_CHUNK, "EEVEE_shcast_buffer flags buf");
+ sldata->shcasters_buffers[i].alloc_count = SHADOW_CASTER_ALLOC_CHUNK;
+ sldata->shcasters_buffers[i].count = 0;
+ }
+
+ sldata->lamps->shcaster_frontbuffer = &sldata->shcasters_buffers[0];
+ sldata->lamps->shcaster_backbuffer = &sldata->shcasters_buffers[1];
+ }
+
+ /* Flip buffers */
+ SWAP(EEVEE_ShadowCasterBuffer *, sldata->lamps->shcaster_frontbuffer, sldata->lamps->shcaster_backbuffer);
+
+ const int sh_method = scene_eval->eevee.shadow_method;
+ int sh_cube_size = scene_eval->eevee.shadow_cube_size;
+ int sh_cascade_size = scene_eval->eevee.shadow_cascade_size;
+ const bool sh_high_bitdepth = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_HIGH_BITDEPTH) != 0;
+ sldata->lamps->soft_shadows = (scene_eval->eevee.flag & SCE_EEVEE_SHADOW_SOFT) != 0;
+
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ if ((linfo->shadow_cube_size != sh_cube_size) ||
+ (linfo->shadow_method != sh_method) ||
+ (linfo->shadow_high_bitdepth != sh_high_bitdepth))
+ {
+ BLI_assert((sh_cube_size > 0) && (sh_cube_size <= 4096));
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur);
+
+ /* Compute adequate size for the octahedral map. */
+ linfo->shadow_cube_store_size = OCTAHEDRAL_SIZE_FROM_CUBESIZE(sh_cube_size);
+
+ CLAMP(linfo->shadow_cube_store_size, 1, 4096);
+ CLAMP(sh_cube_size, 1, 4096);
+
+ linfo->shadow_render_data.cube_texel_size = 1.0f / sh_cube_size;
+ }
+
+ if ((linfo->shadow_cascade_size != sh_cascade_size) ||
+ (linfo->shadow_method != sh_method) ||
+ (linfo->shadow_high_bitdepth != sh_high_bitdepth))
+ {
+ BLI_assert((sh_cascade_size > 0) && (sh_cascade_size <= 4096));
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target);
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_blur);
+
+ CLAMP(sh_cascade_size, 1, 4096);
+ }
+
+ linfo->shadow_high_bitdepth = sh_high_bitdepth;
+ linfo->shadow_method = sh_method;
+ linfo->shadow_cube_size = sh_cube_size;
+ linfo->shadow_cascade_size = sh_cascade_size;
+
+ /* only compile the ones needed. reduce startup time. */
+ if ((sh_method == SHADOW_ESM) && !e_data.shadow_copy_cube_sh[SHADOW_ESM]) {
+ e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(
+ datatoc_shadow_copy_frag_glsl,
+ "#define ESM\n"
+ "#define COPY\n");
+ e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(
+ datatoc_shadow_copy_frag_glsl,
+ "#define ESM\n"
+ "#define COPY\n"
+ "#define CSM\n");
+ }
+ else if ((sh_method == SHADOW_VSM) && !e_data.shadow_copy_cube_sh[SHADOW_VSM]) {
+ e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(
+ datatoc_shadow_copy_frag_glsl,
+ "#define VSM\n"
+ "#define COPY\n");
+ e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(
+ datatoc_shadow_copy_frag_glsl,
+ "#define VSM\n"
+ "#define COPY\n"
+ "#define CSM\n");
+ }
+}
+
+static GPUShader *eevee_lights_get_store_sh(int shadow_method, bool high_blur, bool cascade)
+{
+ GPUShader **shader;
+
+ if (cascade) {
+ shader = (high_blur) ? &e_data.shadow_store_cascade_high_sh[shadow_method]
+ : &e_data.shadow_store_cascade_sh[shadow_method];
+ }
+ else {
+ shader = (high_blur) ? &e_data.shadow_store_cube_high_sh[shadow_method]
+ : &e_data.shadow_store_cube_sh[shadow_method];
+ }
+
+ if (*shader == NULL) {
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl);
+ char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, (shadow_method == SHADOW_VSM) ? "#define VSM\n" : "#define ESM\n");
+ if (high_blur) BLI_dynstr_append(ds_frag, "#define HIGH_BLUR\n");
+ if (cascade) BLI_dynstr_append(ds_frag, "#define CSM\n");
+ char *define_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ *shader = DRW_shader_create_fullscreen(
+ store_shadow_shader_str, define_str);
+
+ MEM_freeN(store_shadow_shader_str);
+ MEM_freeN(define_str);
+ }
+
+ return *shader;
+}
+
+static DRWPass *eevee_lights_cube_store_pass_get(EEVEE_PassList *psl, EEVEE_ViewLayerData *sldata, int shadow_method, int shadow_samples_len)
+{
+ bool high_blur = shadow_samples_len > 16;
+ DRWPass **pass = (high_blur) ? &psl->shadow_cube_store_pass : &psl->shadow_cube_store_high_pass;
+ if (*pass == NULL) {
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ *pass = DRW_pass_create("Shadow Cube Storage Pass", DRW_STATE_WRITE_COLOR);
+ GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, false);
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+ return *pass;
+}
+
+static DRWPass *eevee_lights_cascade_store_pass_get(EEVEE_PassList *psl, EEVEE_ViewLayerData *sldata, int shadow_method, int shadow_samples_len)
+{
+ bool high_blur = shadow_samples_len > 16;
+ DRWPass **pass = (high_blur) ? &psl->shadow_cascade_store_pass : &psl->shadow_cascade_store_high_pass;
+ if (*pass == NULL) {
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ *pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR);
+ GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, true);
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1);
+ DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+ return *pass;
+}
+
+void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PassList *psl = vedata->psl;
+
+ linfo->shcaster_frontbuffer->count = 0;
+ linfo->num_light = 0;
+ linfo->num_cube_layer = 0;
+ linfo->num_cascade_layer = 0;
+ linfo->gpu_cube_len = linfo->gpu_cascade_len = linfo->gpu_shadow_len = 0;
+ linfo->cpu_cube_len = linfo->cpu_cascade_len = 0;
+ memset(linfo->light_ref, 0, sizeof(linfo->light_ref));
+ memset(linfo->shadow_cube_ref, 0, sizeof(linfo->shadow_cube_ref));
+ memset(linfo->shadow_cascade_ref, 0, sizeof(linfo->shadow_cascade_ref));
+ memset(linfo->new_shadow_id, -1, sizeof(linfo->new_shadow_id));
+
+ /* Shadow Casters: Reset flags. */
+ memset(linfo->shcaster_backbuffer->flags, (char)SHADOW_CASTER_PRUNED, linfo->shcaster_backbuffer->alloc_count);
+ memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count);
+
+ psl->shadow_cube_store_pass = NULL;
+ psl->shadow_cube_store_high_pass = NULL;
+ psl->shadow_cascade_store_pass = NULL;
+ psl->shadow_cascade_store_high_pass = NULL;
+
+ {
+ psl->shadow_cube_copy_pass = DRW_pass_create("Shadow Copy Pass", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(
+ e_data.shadow_copy_cube_sh[linfo->shadow_method], psl->shadow_cube_copy_pass);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_target);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+ DRW_shgroup_uniform_int(grp, "faceId", &linfo->current_shadow_face, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+
+ {
+ psl->shadow_cascade_copy_pass = DRW_pass_create("Shadow Cascade Copy Pass", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(
+ e_data.shadow_copy_cascade_sh[linfo->shadow_method], psl->shadow_cascade_copy_pass);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_target);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+ DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ psl->shadow_pass = DRW_pass_create("Shadow Pass", state);
+
+ stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass);
+ }
+}
+
+void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
+{
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const float threshold = draw_ctx->scene->eevee.light_threshold;
+
+ /* Step 1 find all lamps in the scene and setup them */
+ if (linfo->num_light >= MAX_LIGHT) {
+ printf("Too many lights in the scene !!!\n");
+ }
+ else {
+ Lamp *la = (Lamp *)ob->data;
+ EEVEE_Light *evli = linfo->light_data + linfo->num_light;
+ eevee_light_setup(ob, evli);
+
+ /* We do not support shadowmaps for dupli lamps. */
+ if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
+ linfo->num_light++;
+ return;
+ }
+
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
+
+ /* Save previous shadow id. */
+ int prev_cube_sh_id = led->prev_cube_shadow_id;
+
+ /* Default light without shadows */
+ led->data.ld.shadow_id = -1;
+ led->prev_cube_shadow_id = -1;
+
+ if (la->mode & LA_SHADOW) {
+ if (la->type == LA_SUN) {
+ int cascade_nbr = la->cascade_count;
+
+ if ((linfo->gpu_cascade_len + 1) <= MAX_SHADOW_CASCADE) {
+ /* Save Light object. */
+ linfo->shadow_cascade_ref[linfo->cpu_cascade_len] = ob;
+
+ /* Store indices. */
+ EEVEE_ShadowCascadeData *data = &led->data.scad;
+ data->shadow_id = linfo->gpu_shadow_len;
+ data->cascade_id = linfo->gpu_cascade_len;
+ data->layer_id = linfo->num_cascade_layer;
+
+ /* Increment indices. */
+ linfo->gpu_shadow_len += 1;
+ linfo->gpu_cascade_len += 1;
+ linfo->num_cascade_layer += cascade_nbr;
+
+ linfo->cpu_cascade_len += 1;
+ }
+ }
+ else if (la->type == LA_SPOT || la->type == LA_LOCAL || la->type == LA_AREA) {
+ if ((linfo->gpu_cube_len + 1) <= MAX_SHADOW_CUBE) {
+ /* Save Light object. */
+ linfo->shadow_cube_ref[linfo->cpu_cube_len] = ob;
+
+ /* For light update tracking. */
+ if ((prev_cube_sh_id >= 0) &&
+ (prev_cube_sh_id < linfo->shcaster_backbuffer->count))
+ {
+ linfo->new_shadow_id[prev_cube_sh_id] = linfo->cpu_cube_len;
+ }
+ led->prev_cube_shadow_id = linfo->cpu_cube_len;
+
+ /* Saving lamp bounds for later. */
+ BLI_assert(linfo->cpu_cube_len >= 0 && linfo->cpu_cube_len < MAX_LIGHT);
+ copy_v3_v3(linfo->shadow_bounds[linfo->cpu_cube_len].center, ob->obmat[3]);
+ linfo->shadow_bounds[linfo->cpu_cube_len].radius = light_attenuation_radius_get(la, threshold);
+
+ EEVEE_ShadowCubeData *data = &led->data.scd;
+ /* Store indices. */
+ data->shadow_id = linfo->gpu_shadow_len;
+ data->cube_id = linfo->gpu_cube_len;
+ data->layer_id = linfo->num_cube_layer;
+
+ /* Increment indices. */
+ linfo->gpu_shadow_len += 1;
+ linfo->gpu_cube_len += 1;
+ linfo->num_cube_layer += 1;
+
+ linfo->cpu_cube_len += 1;
+ }
+ }
+ }
+
+ led->data.ld.light_id = linfo->num_light;
+ linfo->light_ref[linfo->num_light] = ob;
+ linfo->num_light++;
+ }
+}
+
+/* Add a shadow caster to the shadowpasses */
+void EEVEE_lights_cache_shcaster_add(
+ EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_StorageList *stl, struct GPUBatch *geom, Object *ob)
+{
+ DRW_shgroup_call_object_add(
+ stl->g_data->shadow_shgrp,
+ geom, ob);
+}
+
+void EEVEE_lights_cache_shcaster_material_add(
+ EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, struct GPUMaterial *gpumat,
+ struct GPUBatch *geom, struct Object *ob, float *alpha_threshold)
+{
+ /* TODO / PERF : reuse the same shading group for objects with the same material */
+ DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
+
+ if (grp == NULL) return;
+
+ /* Grrr needed for correctness but not 99% of the time not needed.
+ * TODO detect when needed? */
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ if (alpha_threshold != NULL)
+ DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
+
+ DRW_shgroup_call_object_add(grp, geom, ob);
+}
+
+/* Make that object update shadow casting lamps inside its influence bounding box. */
+void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, Object *ob)
+{
+ if ((ob->base_flag & BASE_FROMDUPLI) != 0) {
+ /* TODO: Special case for dupli objects because we cannot save the object pointer. */
+ return;
+ }
+
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ int past_id = oedata->shadow_caster_id;
+
+ /* Update flags in backbuffer. */
+ if (past_id > -1 && past_id < backbuffer->count) {
+ backbuffer->flags[past_id] &= ~SHADOW_CASTER_PRUNED;
+
+ if (oedata->need_update) {
+ backbuffer->flags[past_id] |= SHADOW_CASTER_UPDATED;
+ }
+ }
+
+ /* Update id. */
+ oedata->shadow_caster_id = frontbuffer->count++;
+
+ /* Make sure shadow_casters is big enough. */
+ if (oedata->shadow_caster_id >= frontbuffer->alloc_count) {
+ frontbuffer->alloc_count += SHADOW_CASTER_ALLOC_CHUNK;
+ frontbuffer->shadow_casters = MEM_reallocN(frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ frontbuffer->flags = MEM_reallocN(frontbuffer->flags, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ }
+
+ EEVEE_ShadowCaster *shcaster = frontbuffer->shadow_casters + oedata->shadow_caster_id;
+
+ if (oedata->need_update) {
+ frontbuffer->flags[oedata->shadow_caster_id] = SHADOW_CASTER_UPDATED;
+ }
+
+ /* Update World AABB in frontbuffer. */
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (int i = 0; i < 8; ++i) {
+ float vec[3];
+ copy_v3_v3(vec, bb->vec[i]);
+ mul_m4_v3(ob->obmat, vec);
+ minmax_v3v3_v3(min, max, vec);
+ }
+
+ EEVEE_BoundBox *aabb = &shcaster->bbox;
+ add_v3_v3v3(aabb->center, min, max);
+ mul_v3_fl(aabb->center, 0.5f);
+ sub_v3_v3v3(aabb->halfdim, aabb->center, max);
+
+ aabb->halfdim[0] = fabsf(aabb->halfdim[0]);
+ aabb->halfdim[1] = fabsf(aabb->halfdim[1]);
+ aabb->halfdim[2] = fabsf(aabb->halfdim[2]);
+
+ oedata->need_update = false;
+}
+
+void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ GPUTextureFormat shadow_pool_format = GPU_R32F;
+
+ sldata->common_data.la_num_light = linfo->num_light;
+
+ /* Setup enough layers. */
+ /* Free textures if number mismatch. */
+ if (linfo->num_cube_layer != linfo->cache_num_cube_layer) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_pool);
+ linfo->cache_num_cube_layer = linfo->num_cube_layer;
+ linfo->update_flag |= LIGHT_UPDATE_SHADOW_CUBE;
+ }
+
+ if (linfo->num_cascade_layer != linfo->cache_num_cascade_layer) {
+ DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_pool);
+ linfo->cache_num_cascade_layer = linfo->num_cascade_layer;
+ }
+
+ switch (linfo->shadow_method) {
+ case SHADOW_ESM: shadow_pool_format = ((linfo->shadow_high_bitdepth) ? GPU_R32F : GPU_R16F); break;
+ case SHADOW_VSM: shadow_pool_format = ((linfo->shadow_high_bitdepth) ? GPU_RG32F : GPU_RG16F); break;
+ default:
+ BLI_assert(!"Incorrect Shadow Method");
+ break;
+ }
+
+ /* Cubemaps */
+ if (!sldata->shadow_cube_target) {
+ sldata->shadow_cube_target = DRW_texture_create_cube(
+ linfo->shadow_cube_size, GPU_DEPTH_COMPONENT24, 0, NULL);
+ sldata->shadow_cube_blur = DRW_texture_create_cube(
+ linfo->shadow_cube_size, shadow_pool_format, DRW_TEX_FILTER, NULL);
+ }
+ if (!sldata->shadow_cube_pool) {
+ sldata->shadow_cube_pool = DRW_texture_create_2D_array(
+ linfo->shadow_cube_store_size, linfo->shadow_cube_store_size, max_ii(1, linfo->num_cube_layer),
+ shadow_pool_format, DRW_TEX_FILTER, NULL);
+ }
+ GPU_framebuffer_ensure_config(&sldata->shadow_cube_target_fb, {
+ GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_target)
+ });
+ GPU_framebuffer_ensure_config(&sldata->shadow_cube_store_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_pool)
+ });
+
+ /* CSM */
+ if (!sldata->shadow_cascade_target) {
+ sldata->shadow_cascade_target = DRW_texture_create_2D_array(
+ linfo->shadow_cascade_size, linfo->shadow_cascade_size, MAX_CASCADE_NUM, GPU_DEPTH_COMPONENT24, 0, NULL);
+ sldata->shadow_cascade_blur = DRW_texture_create_2D_array(
+ linfo->shadow_cascade_size, linfo->shadow_cascade_size, MAX_CASCADE_NUM, shadow_pool_format, DRW_TEX_FILTER, NULL);
+ }
+ if (!sldata->shadow_cascade_pool) {
+ sldata->shadow_cascade_pool = DRW_texture_create_2D_array(
+ linfo->shadow_cascade_size, linfo->shadow_cascade_size, max_ii(1, linfo->num_cascade_layer),
+ shadow_pool_format, DRW_TEX_FILTER, NULL);
+ }
+ GPU_framebuffer_ensure_config(&sldata->shadow_cascade_target_fb, {
+ GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_target)
+ });
+ GPU_framebuffer_ensure_config(&sldata->shadow_cascade_store_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_pool)
+ });
+
+ /* Update Lamps UBOs. */
+ EEVEE_lights_update(sldata, vedata);
+}
+
+float light_attenuation_radius_get(Lamp *la, float light_threshold)
+{
+ if (la->mode & LA_CUSTOM_ATTENUATION)
+ return la->att_dist;
+
+ /* Compute max light power. */
+ float power = max_fff(la->r, la->g, la->b);
+ power *= fabsf(la->energy);
+ power *= max_ff(1.0f, la->spec_fac);
+ /* Compute the distance (using the inverse square law)
+ * at which the light power reaches the light_threshold. */
+ float distance = sqrtf(max_ff(1e-16, power / max_ff(1e-16, light_threshold)));
+ return distance;
+}
+
+static void light_shape_parameters_set(EEVEE_Light *evli, const Lamp *la, float scale[3])
+{
+ if (la->type == LA_SPOT) {
+ /* Spot size & blend */
+ evli->sizex = scale[0] / scale[2];
+ evli->sizey = scale[1] / scale[2];
+ evli->spotsize = cosf(la->spotsize * 0.5f);
+ evli->spotblend = (1.0f - evli->spotsize) * la->spotblend;
+ evli->radius = max_ff(0.001f, la->area_size);
+ }
+ else if (la->type == LA_AREA) {
+ evli->sizex = max_ff(0.003f, la->area_size * scale[0] * 0.5f);
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
+ evli->sizey = max_ff(0.003f, la->area_sizey * scale[1] * 0.5f);
+ }
+ else {
+ evli->sizey = max_ff(0.003f, la->area_size * scale[1] * 0.5f);
+ }
+ }
+ else {
+ evli->radius = max_ff(0.001f, la->area_size);
+ }
+}
+
+static float light_shape_power_get(const Lamp *la, const EEVEE_Light *evli)
+{
+ float power;
+ /* Make illumination power constant */
+ if (la->type == LA_AREA) {
+ power = 1.0f / (evli->sizex * evli->sizey * 4.0f * M_PI) * /* 1/(w*h*Pi) */
+ 80.0f; /* XXX : Empirical, Fit cycles power */
+ if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
+ /* Scale power to account for the lower area of the ellipse compared to the surrounding rectangle. */
+ power *= 4.0f / M_PI;
+ }
+ }
+ else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
+ power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */
+ M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
+
+ /* for point lights (a.k.a radius == 0.0) */
+ // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */
+ }
+ else {
+ power = 1.0f / (evli->radius * evli->radius * M_PI); /* 1/(r²*Pi) */
+ /* Make illumation power closer to cycles for bigger radii. Cycles uses a cos^3 term that we cannot reproduce
+ * so we account for that by scaling the light power. This function is the result of a rough manual fitting. */
+ power += 1.0f / (2.0f * M_PI); /* power *= 1 + r²/2 */
+ }
+ return power;
+}
+
+/* Update buffer with lamp data */
+static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
+{
+ Lamp *la = (Lamp *)ob->data;
+ float mat[4][4], scale[3], power, att_radius;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const float light_threshold = draw_ctx->scene->eevee.light_threshold;
+
+ /* Position */
+ copy_v3_v3(evli->position, ob->obmat[3]);
+
+ /* Color */
+ copy_v3_v3(evli->color, &la->r);
+
+ evli->spec = la->spec_fac;
+
+ /* Influence Radius */
+ att_radius = light_attenuation_radius_get(la, light_threshold);
+ /* Take the inverse square of this distance. */
+ evli->invsqrdist = 1.0 / max_ff(1e-4f, att_radius * att_radius);
+
+ /* Vectors */
+ normalize_m4_m4_ex(mat, ob->obmat, scale);
+ copy_v3_v3(evli->forwardvec, mat[2]);
+ normalize_v3(evli->forwardvec);
+ negate_v3(evli->forwardvec);
+
+ copy_v3_v3(evli->rightvec, mat[0]);
+ normalize_v3(evli->rightvec);
+
+ copy_v3_v3(evli->upvec, mat[1]);
+ normalize_v3(evli->upvec);
+
+ light_shape_parameters_set(evli, la, scale);
+
+ /* Lamp Type */
+ evli->lamptype = (float)la->type;
+ if ((la->type == LA_AREA) && ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
+ evli->lamptype = LAMPTYPE_AREA_ELLIPSE;
+ }
+
+ power = light_shape_power_get(la, evli);
+ mul_v3_fl(evli->color, power * la->energy);
+
+ /* No shadow by default */
+ evli->shadowid = -1.0f;
+}
+
+/**
+ * Special ball distribution:
+ * Point are distributed in a way that when they are orthogonaly
+ * projected into any plane, the resulting distribution is (close to)
+ * a uniform disc distribution.
+ **/
+static void sample_ball(int sample_ofs, float radius, float rsample[3])
+{
+ double ht_point[3];
+ double ht_offset[3] = {0.0, 0.0, 0.0};
+ uint ht_primes[3] = {2, 3, 7};
+
+ BLI_halton_3D(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ float omega = ht_point[1] * 2.0f * M_PI;
+
+ rsample[2] = ht_point[0] * 2.0f - 1.0f; /* cos theta */
+
+ float r = sqrtf(fmaxf(0.0f, 1.0f - rsample[2] * rsample[2])); /* sin theta */
+
+ rsample[0] = r * cosf(omega);
+ rsample[1] = r * sinf(omega);
+
+ radius *= sqrt(sqrt(ht_point[2]));
+ mul_v3_fl(rsample, radius);
+}
+
+static void sample_rectangle(
+ int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y,
+ float rsample[3])
+{
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2D(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Change ditribution center to be 0,0 */
+ ht_point[0] = (ht_point[0] > 0.5f) ? ht_point[0] - 1.0f : ht_point[0];
+ ht_point[1] = (ht_point[1] > 0.5f) ? ht_point[1] - 1.0f : ht_point[1];
+
+ zero_v3(rsample);
+ madd_v3_v3fl(rsample, x_axis, (ht_point[0] * 2.0f) * size_x);
+ madd_v3_v3fl(rsample, y_axis, (ht_point[1] * 2.0f) * size_y);
+}
+
+static void sample_ellipse(
+ int sample_ofs, float x_axis[3], float y_axis[3], float size_x, float size_y,
+ float rsample[3])
+{
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2D(ht_primes, ht_offset, sample_ofs, ht_point);
+
+ /* Uniform disc sampling. */
+ float omega = ht_point[1] * 2.0f * M_PI;
+ float r = sqrtf(ht_point[0]);
+ ht_point[0] = r * cosf(omega) * size_x;
+ ht_point[1] = r * sinf(omega) * size_y;
+
+ zero_v3(rsample);
+ madd_v3_v3fl(rsample, x_axis, ht_point[0]);
+ madd_v3_v3fl(rsample, y_axis, ht_point[1]);
+}
+
+
+static void shadow_cube_random_position_set(
+ EEVEE_Light *evli, Lamp *la,
+ int sample_ofs,
+ float ws_sample_pos[3])
+{
+ float jitter[3];
+
+#ifndef DEBUG_SHADOW_DISTRIBUTION
+ int i = sample_ofs;
+#else
+ for (int i = 0; i <= sample_ofs; ++i) {
+#endif
+ switch (la->type) {
+ case LA_AREA:
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_SQUARE)) {
+ sample_rectangle(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
+ }
+ else {
+ sample_ellipse(i, evli->rightvec, evli->upvec, evli->sizex, evli->sizey, jitter);
+ }
+ break;
+ default:
+ sample_ball(i, evli->radius, jitter);
+ }
+#ifdef DEBUG_SHADOW_DISTRIBUTION
+ float p[3];
+ add_v3_v3v3(p, jitter, ws_sample_pos);
+ DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
+ }
+#endif
+ add_v3_v3(ws_sample_pos, jitter);
+}
+
+static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led, int sample_ofs)
+{
+ EEVEE_ShadowCubeData *sh_data = &led->data.scd;
+ EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
+ EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
+ EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + sh_data->cube_id;
+ Lamp *la = (Lamp *)ob->data;
+
+ copy_v3_v3(cube_data->position, ob->obmat[3]);
+
+ if (linfo->soft_shadows) {
+ shadow_cube_random_position_set(evli, la, sample_ofs, cube_data->position);
+ }
+
+ ubo_data->bias = 0.05f * la->bias;
+ ubo_data->near = la->clipsta;
+ ubo_data->far = 1.0f / (evli->invsqrdist * evli->invsqrdist);
+ ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp;
+
+ evli->shadowid = (float)(sh_data->shadow_id);
+ ubo_data->shadow_start = (float)(sh_data->layer_id);
+ ubo_data->data_start = (float)(sh_data->cube_id);
+ ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */
+
+ ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
+ ubo_data->contact_bias = 0.05f * la->contact_bias;
+ ubo_data->contact_spread = la->contact_spread;
+ ubo_data->contact_thickness = la->contact_thickness;
+}
+
+static void shadow_cascade_random_matrix_set(float mat[4][4], float radius, int sample_ofs)
+{
+ float jitter[3];
+
+#ifndef DEBUG_SHADOW_DISTRIBUTION
+ int i = sample_ofs;
+#else
+ for (int i = 0; i <= sample_ofs; ++i) {
+#endif
+ sample_ellipse(i, mat[0], mat[1], radius, radius, jitter);
+#ifdef DEBUG_SHADOW_DISTRIBUTION
+ float p[3];
+ add_v3_v3v3(p, jitter, mat[2]);
+ DRW_debug_sphere(p, 0.01f, (float[4]){1.0f, (sample_ofs == i) ? 1.0f : 0.0f, 0.0f, 1.0f});
+ }
+#endif
+
+ add_v3_v3(mat[2], jitter);
+ orthogonalize_m4(mat, 2);
+}
+
+#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
+
+static double round_to_digits(double value, int digits)
+{
+ double factor = pow(10.0, digits - ceil(log10(fabs(value))));
+ return round(value * factor) / factor;
+}
+
+static void frustum_min_bounding_sphere(const float corners[8][3], float r_center[3], float *r_radius)
+{
+#if 0 /* Simple solution but waste too much space. */
+ float minvec[3], maxvec[3];
+
+ /* compute the bounding box */
+ INIT_MINMAX(minvec, maxvec);
+ for (int i = 0; i < 8; ++i) {
+ minmax_v3v3_v3(minvec, maxvec, corners[i]);
+ }
+
+ /* compute the bounding sphere of this box */
+ r_radius = len_v3v3(minvec, maxvec) * 0.5f;
+ add_v3_v3v3(r_center, minvec, maxvec);
+ mul_v3_fl(r_center, 0.5f);
+#else
+ /* Find averaged center. */
+ zero_v3(r_center);
+ for (int i = 0; i < 8; ++i) {
+ add_v3_v3(r_center, corners[i]);
+ }
+ mul_v3_fl(r_center, 1.0f / 8.0f);
+
+ /* Search the largest distance from the sphere center. */
+ *r_radius = 0.0f;
+ for (int i = 0; i < 8; ++i) {
+ float rad = len_squared_v3v3(corners[i], r_center);
+ if (rad > *r_radius) {
+ *r_radius = rad;
+ }
+ }
+
+ /* TODO try to reduce the radius further by moving the center.
+ * Remember we need a __stable__ solution! */
+
+ /* Try to reduce float imprecision leading to shimmering. */
+ *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3);
+#endif
+}
+
+static void eevee_shadow_cascade_setup(
+ Object *ob, EEVEE_LampsInfo *linfo, EEVEE_LampEngineData *led,
+ DRWMatrixState *saved_mats, float view_near, float view_far, int sample_ofs)
+{
+ Lamp *la = (Lamp *)ob->data;
+
+ /* Camera Matrices */
+ float (*persinv)[4] = saved_mats->mat[DRW_MAT_PERSINV];
+ float (*vp_projmat)[4] = saved_mats->mat[DRW_MAT_WIN];
+ bool is_persp = DRW_viewport_is_persp_get();
+
+ /* Lamps Matrices */
+ int cascade_nbr = la->cascade_count;
+
+ EEVEE_ShadowCascadeData *sh_data = &led->data.scad;
+ EEVEE_Light *evli = linfo->light_data + sh_data->light_id;
+ EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id;
+ EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id;
+
+ /* obmat = Object Space > World Space */
+ /* viewmat = World Space > View Space */
+ float (*viewmat)[4] = sh_data->viewmat;
+#if 0 /* done at culling time */
+ normalize_m4_m4(viewmat, ob->obmat);
+#endif
+
+ if (linfo->soft_shadows) {
+ shadow_cascade_random_matrix_set(viewmat, evli->radius, sample_ofs);
+ }
+
+ copy_m4_m4(sh_data->viewinv, viewmat);
+ invert_m4(viewmat);
+
+ /* The technique consists into splitting
+ * the view frustum into several sub-frustum
+ * that are individually receiving one shadow map */
+
+ float csm_start, csm_end;
+
+ if (is_persp) {
+ csm_start = view_near;
+ csm_end = max_ff(view_far, -la->cascade_max_dist);
+ /* Avoid artifacts */
+ csm_end = min_ff(view_near, csm_end);
+ }
+ else {
+ csm_start = -view_far;
+ csm_end = view_far;
+ }
+
+ /* init near/far */
+ for (int c = 0; c < MAX_CASCADE_NUM; ++c) {
+ cascade_data->split_start[c] = csm_end;
+ cascade_data->split_end[c] = csm_end;
+ }
+
+ /* Compute split planes */
+ float splits_start_ndc[MAX_CASCADE_NUM];
+ float splits_end_ndc[MAX_CASCADE_NUM];
+
+ {
+ /* Nearest plane */
+ float p[4] = {1.0f, 1.0f, csm_start, 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_start_ndc[0] = p[2];
+ if (is_persp) {
+ splits_start_ndc[0] /= p[3];
+ }
+ }
+
+ {
+ /* Farthest plane */
+ float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_end_ndc[cascade_nbr - 1] = p[2];
+ if (is_persp) {
+ splits_end_ndc[cascade_nbr - 1] /= p[3];
+ }
+ }
+
+ cascade_data->split_start[0] = csm_start;
+ cascade_data->split_end[cascade_nbr - 1] = csm_end;
+
+ for (int c = 1; c < cascade_nbr; ++c) {
+ /* View Space */
+ float linear_split = LERP(((float)(c) / (float)cascade_nbr), csm_start, csm_end);
+ float exp_split = csm_start * powf(csm_end / csm_start, (float)(c) / (float)cascade_nbr);
+
+ if (is_persp) {
+ cascade_data->split_start[c] = LERP(la->cascade_exponent, linear_split, exp_split);
+ }
+ else {
+ cascade_data->split_start[c] = linear_split;
+ }
+ cascade_data->split_end[c - 1] = cascade_data->split_start[c];
+
+ /* Add some overlap for smooth transition */
+ cascade_data->split_start[c] = LERP(la->cascade_fade, cascade_data->split_end[c - 1],
+ (c > 1) ? cascade_data->split_end[c - 2] : cascade_data->split_start[0]);
+
+ /* NDC Space */
+ {
+ float p[4] = {1.0f, 1.0f, cascade_data->split_start[c], 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_start_ndc[c] = p[2];
+
+ if (is_persp) {
+ splits_start_ndc[c] /= p[3];
+ }
+ }
+
+ {
+ float p[4] = {1.0f, 1.0f, cascade_data->split_end[c - 1], 1.0f};
+ /* TODO: we don't need full m4 multiply here */
+ mul_m4_v4(vp_projmat, p);
+ splits_end_ndc[c - 1] = p[2];
+
+ if (is_persp) {
+ splits_end_ndc[c - 1] /= p[3];
+ }
+ }
+ }
+
+ /* Set last cascade split fade distance into the first split_start. */
+ float prev_split = (cascade_nbr > 1) ? cascade_data->split_end[cascade_nbr - 2] : cascade_data->split_start[0];
+ cascade_data->split_start[0] = LERP(la->cascade_fade, cascade_data->split_end[cascade_nbr - 1], prev_split);
+
+ /* For each cascade */
+ for (int c = 0; c < cascade_nbr; ++c) {
+ float (*projmat)[4] = sh_data->projmat[c];
+ /* Given 8 frustum corners */
+ float corners[8][3] = {
+ /* Near Cap */
+ { 1.0f, -1.0f, splits_start_ndc[c]},
+ {-1.0f, -1.0f, splits_start_ndc[c]},
+ {-1.0f, 1.0f, splits_start_ndc[c]},
+ { 1.0f, 1.0f, splits_start_ndc[c]},
+ /* Far Cap */
+ { 1.0f, -1.0f, splits_end_ndc[c]},
+ {-1.0f, -1.0f, splits_end_ndc[c]},
+ {-1.0f, 1.0f, splits_end_ndc[c]},
+ { 1.0f, 1.0f, splits_end_ndc[c]}
+ };
+
+ /* Transform them into world space */
+ for (int i = 0; i < 8; ++i) {
+ mul_project_m4_v3(persinv, corners[i]);
+ }
+
+ float center[3];
+ frustum_min_bounding_sphere(corners, center, &(sh_data->radius[c]));
+
+#ifdef DEBUG_CSM
+ float dbg_col[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ if (c < 3) {
+ dbg_col[c] = 1.0f;
+ }
+ DRW_debug_bbox((BoundBox *)&corners, dbg_col);
+ DRW_debug_sphere(center, sh_data->radius[c], dbg_col);
+#endif
+
+ /* Project into lightspace */
+ mul_m4_v3(viewmat, center);
+
+ /* Snap projection center to nearest texel to cancel shimmering. */
+ float shadow_origin[2], shadow_texco[2];
+ /* Light to texture space. */
+ mul_v2_v2fl(shadow_origin, center, linfo->shadow_cascade_size / (2.0f * sh_data->radius[c]));
+
+ /* Find the nearest texel. */
+ shadow_texco[0] = roundf(shadow_origin[0]);
+ shadow_texco[1] = roundf(shadow_origin[1]);
+
+ /* Compute offset. */
+ sub_v2_v2(shadow_texco, shadow_origin);
+ mul_v2_fl(shadow_texco, (2.0f * sh_data->radius[c]) / linfo->shadow_cascade_size); /* Texture to light space. */
+
+ /* Apply offset. */
+ add_v2_v2(center, shadow_texco);
+
+ /* Expand the projection to cover frustum range */
+ rctf rect_cascade;
+ BLI_rctf_init_pt_radius(&rect_cascade, center, sh_data->radius[c]);
+ orthographic_m4(projmat,
+ rect_cascade.xmin, rect_cascade.xmax,
+ rect_cascade.ymin, rect_cascade.ymax,
+ la->clipsta, la->clipend);
+
+ mul_m4_m4m4(sh_data->viewprojmat[c], projmat, viewmat);
+ mul_m4_m4m4(cascade_data->shadowmat[c], texcomat, sh_data->viewprojmat[c]);
+
+#ifdef DEBUG_CSM
+ DRW_debug_m4_as_bbox(sh_data->viewprojmat[c], dbg_col, true);
+#endif
+ }
+
+ ubo_data->bias = 0.05f * la->bias;
+ ubo_data->near = la->clipsta;
+ ubo_data->far = la->clipend;
+ ubo_data->exp = (linfo->shadow_method == SHADOW_VSM) ? la->bleedbias : la->bleedexp;
+
+ evli->shadowid = (float)(sh_data->shadow_id);
+ ubo_data->shadow_start = (float)(sh_data->layer_id);
+ ubo_data->data_start = (float)(sh_data->cascade_id);
+ ubo_data->shadow_blur = la->soft * 0.02f; /* Used by translucence shadowmap blur */
+
+ ubo_data->contact_dist = (la->mode & LA_SHAD_CONTACT) ? la->contact_dist : 0.0f;
+ ubo_data->contact_bias = 0.05f * la->contact_bias;
+ ubo_data->contact_spread = la->contact_spread;
+ ubo_data->contact_thickness = la->contact_thickness;
+}
+
+/* Used for checking if object is inside the shadow volume. */
+static bool sphere_bbox_intersect(const EEVEE_BoundSphere *bs, const EEVEE_BoundBox *bb)
+{
+ /* We are testing using a rougher AABB vs AABB test instead of full AABB vs Sphere. */
+ /* TODO test speed with AABB vs Sphere. */
+ bool x = fabsf(bb->center[0] - bs->center[0]) <= (bb->halfdim[0] + bs->radius);
+ bool y = fabsf(bb->center[1] - bs->center[1]) <= (bb->halfdim[1] + bs->radius);
+ bool z = fabsf(bb->center[2] - bs->center[2]) <= (bb->halfdim[2] + bs->radius);
+
+ return x && y && z;
+}
+
+void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ Object *ob;
+ int i;
+ char *flag;
+ EEVEE_ShadowCaster *shcaster;
+ EEVEE_BoundSphere *bsphere;
+ EEVEE_ShadowCasterBuffer *frontbuffer = linfo->shcaster_frontbuffer;
+ EEVEE_ShadowCasterBuffer *backbuffer = linfo->shcaster_backbuffer;
+
+ EEVEE_LightBits update_bits = {{0}};
+ if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
+ /* Update all lights. */
+ lightbits_set_all(&update_bits, true);
+ }
+ else {
+ /* Search for deleted shadow casters and if shcaster WAS in shadow radius. */
+ /* No need to run this if we already update all lamps. */
+ EEVEE_LightBits past_bits = {{0}};
+ EEVEE_LightBits curr_bits = {{0}};
+ shcaster = backbuffer->shadow_casters;
+ flag = backbuffer->flags;
+ for (i = 0; i < backbuffer->count; ++i, ++flag, ++shcaster) {
+ /* If the shadowcaster has been deleted or updated. */
+ if (*flag != 0) {
+ /* Add the lamps that were intersecting with its BBox. */
+ lightbits_or(&past_bits, &shcaster->bits);
+ }
+ }
+ /* Convert old bits to new bits and add result to final update bits. */
+ /* NOTE: This might be overkill since all lights are tagged to refresh if
+ * the light count changes. */
+ lightbits_convert(&curr_bits, &past_bits, linfo->new_shadow_id, MAX_LIGHT);
+ lightbits_or(&update_bits, &curr_bits);
+ }
+
+ /* Search for updates in current shadow casters. */
+ shcaster = frontbuffer->shadow_casters;
+ flag = frontbuffer->flags;
+ for (i = 0; i < frontbuffer->count; i++, flag++, shcaster++) {
+ /* Run intersection checks to fill the bitfields. */
+ bsphere = linfo->shadow_bounds;
+ for (int j = 0; j < linfo->cpu_cube_len; j++, bsphere++) {
+ bool iter = sphere_bbox_intersect(bsphere, &shcaster->bbox);
+ lightbits_set_single(&shcaster->bits, j, iter);
+ }
+ /* Only add to final bits if objects has been updated. */
+ if (*flag != 0) {
+ lightbits_or(&update_bits, &shcaster->bits);
+ }
+ }
+
+ /* Setup shadow cube in UBO and tag for update if necessary. */
+ for (i = 0; (i < MAX_SHADOW_CUBE) && (ob = linfo->shadow_cube_ref[i]); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
+
+ eevee_shadow_cube_setup(ob, linfo, led, effects->taa_current_sample - 1);
+ if (lightbits_get(&update_bits, i) != 0 || linfo->soft_shadows) {
+ led->need_update = true;
+ }
+ }
+
+ /* Resize shcasters buffers if too big. */
+ if (frontbuffer->alloc_count - frontbuffer->count > SHADOW_CASTER_ALLOC_CHUNK) {
+ frontbuffer->alloc_count = (frontbuffer->count / SHADOW_CASTER_ALLOC_CHUNK) * SHADOW_CASTER_ALLOC_CHUNK;
+ frontbuffer->alloc_count += (frontbuffer->count % SHADOW_CASTER_ALLOC_CHUNK != 0) ? SHADOW_CASTER_ALLOC_CHUNK : 0;
+ frontbuffer->shadow_casters = MEM_reallocN(frontbuffer->shadow_casters, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ frontbuffer->flags = MEM_reallocN(frontbuffer->flags, sizeof(EEVEE_ShadowCaster) * frontbuffer->alloc_count);
+ }
+}
+
+/* this refresh lamps shadow buffers */
+void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const float light_threshold = draw_ctx->scene->eevee.light_threshold;
+ Object *ob;
+ int i;
+
+ DRWMatrixState saved_mats;
+ int saved_ray_type = sldata->common_data.ray_type;
+
+ /* TODO: make it optionnal if we don't draw shadows. */
+ sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ /* Precompute all shadow/view test before rendering and trashing the culling cache. */
+ bool cube_visible[MAX_SHADOW_CUBE];
+ for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
+ Lamp *la = (Lamp *)ob->data;
+ BoundSphere bsphere = {
+ .center = {ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]},
+ .radius = light_attenuation_radius_get(la, light_threshold)
+ };
+ cube_visible[i] = DRW_culling_sphere_test(&bsphere);
+ }
+ bool cascade_visible[MAX_SHADOW_CASCADE];
+ for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ EEVEE_ShadowCascadeData *sh_data = &led->data.scad;
+ float plane[4];
+ normalize_m4_m4(sh_data->viewmat, ob->obmat);
+
+ plane_from_point_normal_v3(plane, sh_data->viewmat[3], sh_data->viewmat[2]);
+ /* TODO: check against near/far instead of "local Z = 0" plane.
+ * Or even the cascades AABB. */
+ cascade_visible[i] = DRW_culling_plane_test(plane);
+ }
+
+ /* We need to save the Matrices before overidding them */
+ DRW_viewport_matrix_get_all(&saved_mats);
+
+ /* Cube Shadow Maps */
+ DRW_stats_group_start("Cube Shadow Maps");
+ /* Render each shadow to one layer of the array */
+ for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
+ Lamp *la = (Lamp *)ob->data;
+
+ if (!led->need_update || !cube_visible[i]) {
+ continue;
+ }
+
+ DRWMatrixState render_mats;
+ float (*winmat)[4] = render_mats.mat[DRW_MAT_WIN];
+ float (*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW];
+ float (*persmat)[4] = render_mats.mat[DRW_MAT_PERS];
+
+ EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
+ EEVEE_ShadowCubeData *evscd = &led->data.scd;
+ EEVEE_ShadowCube *cube_data = linfo->shadow_cube_data + evscd->cube_id;
+
+ srd->clip_near = la->clipsta;
+ srd->clip_far = light_attenuation_radius_get(la, light_threshold);
+ srd->stored_texel_size = 1.0 / (float)linfo->shadow_cube_store_size;
+ srd->exponent = la->bleedexp;
+ copy_v3_v3(srd->position, cube_data->position);
+
+ perspective_m4(winmat, -srd->clip_near, srd->clip_near, -srd->clip_near, srd->clip_near, srd->clip_near, srd->clip_far);
+
+ DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
+
+ /* Render shadow cube */
+ /* Render 6 faces separately: seems to be faster for the general case.
+ * The only time it's more beneficial is when the CPU culling overhead
+ * outweigh the instancing overhead. which is rarely the case. */
+ for (int j = 0; j < 6; j++) {
+ /* TODO optimize */
+ float tmp[4][4];
+ unit_m4(tmp);
+ negate_v3_v3(tmp[3], srd->position);
+ mul_m4_m4m4(viewmat, cubefacemat[j], tmp);
+ mul_m4_m4m4(persmat, winmat, viewmat);
+ invert_m4_m4(render_mats.mat[DRW_MAT_WININV], winmat);
+ invert_m4_m4(render_mats.mat[DRW_MAT_VIEWINV], viewmat);
+ invert_m4_m4(render_mats.mat[DRW_MAT_PERSINV], persmat);
+
+ DRW_viewport_matrix_override_set_all(&render_mats);
+
+ GPU_framebuffer_texture_cubeface_attach(sldata->shadow_cube_target_fb,
+ sldata->shadow_cube_target, 0, j, 0);
+ GPU_framebuffer_bind(sldata->shadow_cube_target_fb);
+ GPU_framebuffer_clear_depth(sldata->shadow_cube_target_fb, 1.0f);
+ DRW_draw_pass(psl->shadow_pass);
+ }
+
+ /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. */
+ float filter_texture_size = la->soft * 0.001f;
+ float filter_pixel_size = ceil(filter_texture_size / srd->cube_texel_size);
+ linfo->filter_size = srd->cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f);
+
+ /* TODO: OPTI: Filter all faces in one/two draw call */
+ /* TODO: OPTI: Don't do this intermediate step if no filter is needed. */
+ for (linfo->current_shadow_face = 0;
+ linfo->current_shadow_face < 6;
+ linfo->current_shadow_face++)
+ {
+ /* Copy using a small 3x3 box filter */
+ GPU_framebuffer_texture_cubeface_attach(sldata->shadow_cube_store_fb, sldata->shadow_cube_blur, 0,
+ linfo->current_shadow_face, 0);
+ GPU_framebuffer_bind(sldata->shadow_cube_store_fb);
+ DRW_draw_pass(psl->shadow_cube_copy_pass);
+ }
+
+ /* Push it to shadowmap array */
+
+ /* Adjust constants if concentric samples change. */
+ const float max_filter_size = 7.5f;
+ const float magic = 4.5f; /* Dunno why but that works. */
+ const int max_sample = 256;
+
+ if (filter_pixel_size > 2.0f) {
+ linfo->filter_size = srd->cube_texel_size * max_filter_size * magic;
+ filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
+ /* Compute number of concentric samples. Depends directly on filter size. */
+ float pix_size_sqr = filter_pixel_size * filter_pixel_size;
+ srd->shadow_samples_len = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
+ }
+ else {
+ linfo->filter_size = 0.0f;
+ srd->shadow_samples_len = 4;
+ }
+ srd->shadow_samples_len_inv = 1.0f / (float)srd->shadow_samples_len;
+ DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
+
+ GPU_framebuffer_texture_layer_attach(sldata->shadow_cube_store_fb, sldata->shadow_cube_pool, 0, evscd->layer_id, 0);
+ GPU_framebuffer_bind(sldata->shadow_cube_store_fb);
+
+ DRWPass *store_pass = eevee_lights_cube_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_len);
+ DRW_draw_pass(store_pass);
+
+ if (linfo->soft_shadows == false) {
+ led->need_update = false;
+ }
+ }
+ linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE;
+ DRW_stats_group_end();
+
+ DRW_viewport_matrix_override_set_all(&saved_mats);
+ float near = DRW_viewport_near_distance_get();
+ float far = DRW_viewport_far_distance_get();
+
+ /* Cascaded Shadow Maps */
+ DRW_stats_group_start("Cascaded Shadow Maps");
+ for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
+ if (!cascade_visible[i]) {
+ continue;
+ }
+
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
+ Lamp *la = (Lamp *)ob->data;
+
+ EEVEE_ShadowCascadeData *evscd = &led->data.scad;
+ EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
+
+ DRWMatrixState render_mats;
+ float (*winmat)[4] = render_mats.mat[DRW_MAT_WIN];
+ float (*viewmat)[4] = render_mats.mat[DRW_MAT_VIEW];
+ float (*persmat)[4] = render_mats.mat[DRW_MAT_PERS];
+
+ eevee_shadow_cascade_setup(ob, linfo, led, &saved_mats, near, far, effects->taa_current_sample - 1);
+
+ srd->clip_near = la->clipsta;
+ srd->clip_far = la->clipend;
+ srd->stored_texel_size = 1.0 / (float)linfo->shadow_cascade_size;
+
+ DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
+
+ copy_m4_m4(viewmat, evscd->viewmat);
+ invert_m4_m4(render_mats.mat[DRW_MAT_VIEWINV], viewmat);
+
+ /* Render shadow cascades */
+ /* Render cascade separately: seems to be faster for the general case.
+ * The only time it's more beneficial is when the CPU culling overhead
+ * outweigh the instancing overhead. which is rarely the case. */
+ for (int j = 0; j < la->cascade_count; j++) {
+ copy_m4_m4(winmat, evscd->projmat[j]);
+ copy_m4_m4(persmat, evscd->viewprojmat[j]);
+ invert_m4_m4(render_mats.mat[DRW_MAT_WININV], winmat);
+ invert_m4_m4(render_mats.mat[DRW_MAT_PERSINV], persmat);
+
+ DRW_viewport_matrix_override_set_all(&render_mats);
+
+ GPU_framebuffer_texture_layer_attach(sldata->shadow_cascade_target_fb,
+ sldata->shadow_cascade_target, 0, j, 0);
+ GPU_framebuffer_bind(sldata->shadow_cascade_target_fb);
+ GPU_framebuffer_clear_depth(sldata->shadow_cascade_target_fb, 1.0f);
+ DRW_draw_pass(psl->shadow_pass);
+ }
+
+ /* TODO: OPTI: Filter all cascade in one/two draw call */
+ for (linfo->current_shadow_cascade = 0;
+ linfo->current_shadow_cascade < la->cascade_count;
+ ++linfo->current_shadow_cascade)
+ {
+ /* 0.01f factor to convert to percentage */
+ float filter_texture_size = la->soft * 0.01f / evscd->radius[linfo->current_shadow_cascade];
+ float filter_pixel_size = ceil(linfo->shadow_cascade_size * filter_texture_size);
+
+ /* Copy using a small 3x3 box filter */
+ /* NOTE: We always do it in the case of CSM because of artifacts in the farthest cascade. */
+ linfo->filter_size = srd->stored_texel_size;
+ GPU_framebuffer_texture_layer_attach(
+ sldata->shadow_cascade_store_fb, sldata->shadow_cascade_blur, 0, linfo->current_shadow_cascade, 0);
+ GPU_framebuffer_bind(sldata->shadow_cascade_store_fb);
+ DRW_draw_pass(psl->shadow_cascade_copy_pass);
+
+ /* Push it to shadowmap array and blur more */
+
+ /* Adjust constants if concentric samples change. */
+ const float max_filter_size = 7.5f;
+ const float magic = 3.2f; /* Arbitrary: less banding */
+ const int max_sample = 256;
+
+ if (filter_pixel_size > 2.0f) {
+ linfo->filter_size = srd->stored_texel_size * max_filter_size * magic;
+ filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
+ /* Compute number of concentric samples. Depends directly on filter size. */
+ float pix_size_sqr = filter_pixel_size * filter_pixel_size;
+ srd->shadow_samples_len = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
+ }
+ else {
+ linfo->filter_size = 0.0f;
+ srd->shadow_samples_len = 4;
+ }
+ srd->shadow_samples_len_inv = 1.0f / (float)srd->shadow_samples_len;
+ DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data);
+
+ int layer = evscd->layer_id + linfo->current_shadow_cascade;
+ GPU_framebuffer_texture_layer_attach(sldata->shadow_cascade_store_fb, sldata->shadow_cascade_pool, 0, layer, 0);
+ GPU_framebuffer_bind(sldata->shadow_cascade_store_fb);
+
+ DRWPass *store_pass = eevee_lights_cascade_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_len);
+ DRW_draw_pass(store_pass);
+ }
+ }
+
+ DRW_stats_group_end();
+
+ DRW_viewport_matrix_override_set_all(&saved_mats);
+
+ DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data);
+ DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
+
+ sldata->common_data.ray_type = saved_ray_type;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+}
+
+void EEVEE_lights_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
+ for (int i = 0; i < SHADOW_METHOD_MAX; ++i) {
+ DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_high_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_high_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cube_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cascade_sh[i]);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
new file mode 100644
index 00000000000..aa2f480597b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_lookdev.c
+ * \ingroup draw_engine
+ */
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+#include "BKE_studiolight.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_world_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_screen.h"
+
+#include "UI_resources.h"
+
+#include "eevee_private.h"
+#include "eevee_lightcache.h"
+
+#include "draw_common.h"
+
+static void eevee_lookdev_lightcache_delete(EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+
+ MEM_SAFE_FREE(stl->lookdev_lightcache);
+ MEM_SAFE_FREE(stl->lookdev_grid_data);
+ MEM_SAFE_FREE(stl->lookdev_cube_data);
+ DRW_TEXTURE_FREE_SAFE(txl->lookdev_grid_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->lookdev_cube_tx);
+}
+
+void EEVEE_lookdev_cache_init(
+ EEVEE_Data *vedata, DRWShadingGroup **grp, DRWPass *pass,
+ World *UNUSED(world), EEVEE_LightProbesInfo *pinfo)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) {
+ StudioLight *sl = BKE_studiolight_find(v3d->shading.lookdev_light, STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE);
+ if (sl && (sl->flag & STUDIOLIGHT_TYPE_WORLD)) {
+ GPUShader *shader = EEVEE_shaders_default_studiolight_sh_get();
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ GPUTexture *tex = NULL;
+
+ /* If one of the component is missing we start from scratch. */
+ if ((stl->lookdev_grid_data == NULL) ||
+ (stl->lookdev_cube_data == NULL) ||
+ (txl->lookdev_grid_tx == NULL) ||
+ (txl->lookdev_cube_tx == NULL))
+ {
+ eevee_lookdev_lightcache_delete(vedata);
+ }
+
+ if (stl->lookdev_lightcache == NULL) {
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+#if defined(IRRADIANCE_SH_L2)
+ int grid_res = 4;
+#elif defined(IRRADIANCE_CUBEMAP)
+ int grid_res = 8;
+#elif defined(IRRADIANCE_HL2)
+ int grid_res = 4;
+#endif
+ int cube_res = OCTAHEDRAL_SIZE_FROM_CUBESIZE(scene_eval->eevee.gi_cubemap_resolution);
+ int vis_res = scene_eval->eevee.gi_visibility_resolution;
+
+ stl->lookdev_lightcache = EEVEE_lightcache_create(1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1});
+
+ /* XXX: Fix memleak. TODO find out why. */
+ MEM_SAFE_FREE(stl->lookdev_cube_mips);
+
+ /* We do this to use a special light cache for lookdev.
+ * This lightcache needs to be per viewport. But we need to
+ * have correct freeing when the viewport is closed. So we
+ * need to reference all textures to the txl and the memblocks
+ * to the stl. */
+ stl->lookdev_grid_data = stl->lookdev_lightcache->grid_data;
+ stl->lookdev_cube_data = stl->lookdev_lightcache->cube_data;
+ stl->lookdev_cube_mips = stl->lookdev_lightcache->cube_mips;
+ txl->lookdev_grid_tx = stl->lookdev_lightcache->grid_tx.tex;
+ txl->lookdev_cube_tx = stl->lookdev_lightcache->cube_tx.tex;
+ }
+
+ stl->g_data->light_cache = stl->lookdev_lightcache;
+
+ static float background_color[4];
+ UI_GetThemeColor4fv(TH_HIGH_GRAD, background_color);
+ /* XXX: Really quick conversion to avoid washed out background.
+ * Needs to be addressed properly (color managed using ocio). */
+ srgb_to_linearrgb_v4(background_color, background_color);
+
+ *grp = DRW_shgroup_create(shader, pass);
+ axis_angle_to_mat3_single(stl->g_data->studiolight_matrix, 'Z', v3d->shading.studiolight_rot_z);
+ DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->g_data->studiolight_matrix);
+ DRW_shgroup_uniform_float(*grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_uniform_vec3(*grp, "color", background_color, 1);
+ DRW_shgroup_call_add(*grp, geom, NULL);
+ if (!pinfo) {
+ /* Do not fadeout when doing probe rendering, only when drawing the background */
+ DRW_shgroup_uniform_float(*grp, "studioLightBackground", &v3d->shading.studiolight_background, 1);
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE);
+ tex = sl->equirect_irradiance_gputexture;
+ }
+ else {
+ DRW_shgroup_uniform_float_copy(*grp, "studioLightBackground", 1.0f);
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ tex = sl->equirect_radiance_gputexture;
+ }
+ DRW_shgroup_uniform_texture(*grp, "image", tex);
+
+ /* Do we need to recalc the lightprobes? */
+ if (pinfo &&
+ ((pinfo->studiolight_index != sl->index) ||
+ (pinfo->studiolight_rot_z != v3d->shading.studiolight_rot_z)))
+ {
+ stl->lookdev_lightcache->flag |= LIGHTCACHE_UPDATE_WORLD;
+ pinfo->studiolight_index = sl->index;
+ pinfo->studiolight_rot_z = v3d->shading.studiolight_rot_z;
+ }
+ }
+ }
+}
+
+void EEVEE_lookdev_draw_background(EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (psl->lookdev_pass && LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) {
+ DRW_stats_group_start("Look Dev");
+ CameraParams params;
+ BKE_camera_params_init(&params);
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ARegion *ar = draw_ctx->ar;
+
+ const float *viewport_size = DRW_viewport_size_get();
+ rcti rect;
+ ED_region_visible_rect(draw_ctx->ar, &rect);
+
+ const float viewport_size_target[2] = {
+ viewport_size[0] / 4,
+ viewport_size[1] / 4,
+ };
+ const int viewport_inset[2] = {
+ max_ii(viewport_size_target[0], 300),
+ max_ii(viewport_size_target[0], 300) / 2, /* intentionally use 'x' here for 'y' value. */
+ };
+
+ /* minimum size for preview spheres viewport */
+ const float aspect[2] = {
+ viewport_inset[0] / viewport_size_target[0],
+ viewport_inset[1] / viewport_size_target[1],
+ };
+
+ BKE_camera_params_from_view3d(&params, draw_ctx->depsgraph, v3d, rv3d);
+ params.is_ortho = true;
+ params.ortho_scale = 3.0f;
+ params.zoom = CAMERA_PARAM_ZOOM_INIT_PERSP;
+ params.offsetx = 0.0f;
+ params.offsety = 0.0f;
+ params.shiftx = 0.0f;
+ params.shifty = 0.0f;
+ params.clipsta = 0.001f;
+ params.clipend = 20.0f;
+ BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, aspect[0], aspect[1]);
+ BKE_camera_params_compute_matrix(&params);
+
+ EEVEE_CommonUniformBuffer *common = &sldata->common_data;
+ common->la_num_light = 0;
+ common->prb_num_planar = 0;
+ common->prb_num_render_cube = 1;
+ common->prb_num_render_grid = 1;
+ common->ao_dist = 0.0f;
+ common->ao_factor = 0.0f;
+ common->ao_settings = 0.0f;
+ DRW_uniformbuffer_update(sldata->common_ubo, common);
+
+ /* override matrices */
+ float winmat[4][4];
+ float winmat_inv[4][4];
+ copy_m4_m4(winmat, params.winmat);
+ invert_m4_m4(winmat_inv, winmat);
+ DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(winmat_inv, DRW_MAT_WININV);
+ float viewmat[4][4];
+ DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+ float persmat[4][4];
+ float persmat_inv[4][4];
+ mul_m4_m4m4(persmat, winmat, viewmat);
+ invert_m4_m4(persmat_inv, persmat);
+ DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(persmat_inv, DRW_MAT_PERSINV);
+
+ GPUFrameBuffer *fb = effects->final_fb;
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, rect.xmax - viewport_inset[0], rect.ymin, viewport_inset[0], viewport_inset[1]);
+ DRW_draw_pass(psl->lookdev_pass);
+
+ fb = dfbl->depth_only_fb;
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_viewport_set(fb, rect.xmax - viewport_inset[0], rect.ymin, viewport_inset[0], viewport_inset[1]);
+ DRW_draw_pass(psl->lookdev_pass);
+
+ DRW_viewport_matrix_override_unset_all();
+ DRW_stats_group_end();
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_lut.h b/source/blender/draw/engines/eevee/eevee_lut.h
new file mode 100644
index 00000000000..da765b3e53a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lut.h
@@ -0,0 +1,16926 @@
+/*
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Clement Foucault.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file eevee_lut.h
+ * \ingroup gpu
+ */
+
+#ifndef __EEVEE_LUT_H__
+#define __EEVEE_LUT_H__
+
+static float ltc_mat_ggx[64 * 64 * 4] = {
+ 0.000200, -0.000000, 1.000000, -0.000000, 0.000504, -0.000000, 1.000000, -0.000000, 0.002016,
+ -0.000000, 1.000000, -0.000000, 0.004535, -0.000000, 1.000000, -0.000000, 0.008063, -0.000000,
+ 1.000000, -0.000000, 0.012598, -0.000000, 1.000000, -0.000000, 0.018141, -0.000000, 1.000000,
+ -0.000000, 0.024692, -0.000000, 1.000000, -0.000000, 0.032252, -0.000000, 1.000000, -0.000000,
+ 0.040821, -0.000000, 1.000000, -0.000000, 0.050400, -0.000000, 1.000000, -0.000000, 0.060989,
+ -0.000000, 1.000000, -0.000000, 0.072591, -0.000000, 1.000000, -0.000000, 0.085206, -0.000000,
+ 1.000000, -0.000000, 0.098836, -0.000000, 1.000000, -0.000000, 0.113483, -0.000000, 1.000000,
+ -0.000000, 0.129147, -0.000000, 1.000000, -0.000000, 0.145828, -0.000000, 1.000000, -0.000000,
+ 0.163499, -0.000000, 1.000000, -0.000000, 0.181972, -0.000000, 1.000000, -0.000000, 0.199498,
+ -0.000000, 1.000000, -0.000000, 0.220031, -0.000000, 1.000000, -0.000000, 0.241588, -0.000000,
+ 1.000000, -0.000000, 0.264120, -0.000000, 1.000000, -0.000000, 0.287521, -0.000000, 1.000000,
+ -0.000000, 0.311478, -0.000000, 1.000000, -0.000000, 0.335127, -0.000000, 1.000000, -0.000000,
+ 0.359811, -0.000000, 1.000000, -0.000000, 0.386446, -0.000000, 1.000000, -0.000000, 0.413161,
+ -0.000000, 1.000000, -0.000000, 0.439142, -0.000000, 1.000000, -0.000000, 0.467039, -0.000000,
+ 1.000000, -0.000000, 0.495170, -0.000000, 1.000000, -0.000000, 0.522324, -0.000000, 1.000000,
+ -0.000000, 0.551482, -0.000000, 1.000000, -0.000000, 0.579621, -0.000000, 1.000000, -0.000000,
+ 0.608255, -0.000000, 1.000000, -0.000000, 0.636515, -0.000000, 1.000000, -0.000000, 0.664835,
+ -0.000000, 1.000000, -0.000000, 0.692549, -0.000000, 1.000000, -0.000000, 0.720375, -0.000000,
+ 1.000000, -0.000000, 0.747238, -0.000000, 1.000000, -0.000000, 0.773956, -0.000000, 1.000000,
+ -0.000000, 0.799879, -0.000000, 1.000000, -0.000000, 0.824889, -0.000000, 1.000000, -0.000000,
+ 0.849357, -0.000000, 1.000000, -0.000000, 0.873016, -0.000000, 1.000000, -0.000000, 0.895670,
+ -0.000000, 1.000000, -0.000000, 0.917194, -0.000000, 1.000000, -0.000000, 0.937978, -0.000000,
+ 1.000000, -0.000000, 0.957872, -0.000000, 1.000000, -0.000000, 0.976736, -0.000000, 1.000000,
+ -0.000000, 0.994433, -0.000000, 1.000000, -0.000000, 1.011206, -0.000000, 1.000000, -0.000000,
+ 1.026820, -0.000000, 1.000000, -0.000000, 1.041720, -0.000000, 1.000000, -0.000000, 1.055657,
+ -0.000000, 1.000000, -0.000000, 1.068642, -0.000000, 1.000000, -0.000000, 1.080646, -0.000000,
+ 1.000000, -0.000000, 1.091637, -0.000000, 1.000000, -0.000000, 1.101837, -0.000000, 1.000000,
+ -0.000000, 1.111292, -0.000000, 1.000000, -0.000000, 1.120025, -0.000000, 1.000000, -0.000000,
+ 1.127918, -0.000000, 1.000000, -0.000000, 0.000200, -0.000005, 1.000623, 0.024938, 0.000504,
+ -0.000013, 1.000643, 0.024938, 0.002016, -0.000050, 1.000618, 0.024938, 0.004535, -0.000113,
+ 1.000621, 0.024938, 0.008063, -0.000201, 1.000746, 0.024938, 0.012596, -0.000314, 1.000463,
+ 0.024937, 0.018140, -0.000452, 1.000511, 0.024939, 0.024693, -0.000616, 1.000541, 0.024938,
+ 0.032253, -0.000804, 1.000684, 0.024938, 0.040815, -0.001018, 1.000524, 0.024940, 0.050399,
+ -0.001257, 1.000582, 0.024937, 0.060989, -0.001521, 1.000655, 0.024937, 0.072591, -0.001810,
+ 1.000608, 0.024938, 0.085204, -0.002125, 1.000622, 0.024939, 0.098835, -0.002465, 1.000632,
+ 0.024937, 0.113483, -0.002830, 1.000640, 0.024939, 0.129143, -0.003220, 1.000568, 0.024938,
+ 0.145830, -0.003633, 1.000635, 0.024938, 0.163497, -0.004062, 1.000626, 0.024938, 0.181956,
+ -0.004424, 1.000612, 0.024924, 0.199791, -0.004593, 1.000627, 0.024890, 0.220029, -0.005480,
+ 1.000594, 0.024935, 0.241586, -0.006010, 1.000616, 0.024933, 0.264115, -0.006550, 1.000607,
+ 0.024927, 0.287514, -0.007072, 1.000595, 0.024909, 0.311455, -0.007472, 1.000616, 0.024872,
+ 0.335083, -0.007491, 1.000589, 0.024755, 0.359805, -0.008810, 1.000601, 0.024877, 0.386438,
+ -0.009282, 1.000640, 0.024824, 0.413131, -0.009534, 1.000599, 0.024708, 0.439249, -0.009701,
+ 1.000497, 0.024573, 0.466997, -0.010878, 1.000467, 0.024652, 0.495138, -0.010959, 1.000539,
+ 0.024455, 0.522654, -0.011386, 1.000518, 0.024318, 0.551415, -0.012022, 1.000533, 0.024216,
+ 0.579610, -0.011805, 1.000495, 0.023867, 0.608185, -0.012773, 1.000474, 0.023834, 0.636492,
+ -0.012377, 1.000488, 0.023327, 0.664826, -0.013172, 1.000576, 0.023205, 0.692674, -0.012847,
+ 1.000505, 0.022708, 0.720341, -0.013141, 1.000424, 0.022349, 0.747373, -0.013227, 1.000449,
+ 0.021871, 0.773980, -0.012739, 1.000478, 0.021171, 0.799839, -0.012999, 1.000396, 0.020606,
+ 0.825113, -0.012727, 1.000425, 0.020006, 0.849579, -0.012170, 1.000469, 0.019089, 0.873046,
+ -0.011855, 1.000411, 0.018291, 0.895777, -0.011711, 1.000426, 0.017534, 0.917518, -0.011107,
+ 1.000373, 0.016542, 0.938264, -0.010439, 1.000322, 0.015512, 0.958032, -0.009807, 1.000324,
+ 0.014491, 0.976838, -0.009268, 1.000341, 0.013468, 0.994631, -0.008662, 1.000318, 0.012376,
+ 1.011434, -0.007923, 1.000289, 0.011187, 1.027169, -0.007132, 1.000216, 0.010078, 1.041929,
+ -0.006332, 1.000096, 0.008924, 1.055767, -0.005554, 1.000156, 0.007770, 1.068595, -0.004811,
+ 1.000084, 0.006611, 1.080612, -0.003950, 1.000047, 0.005485, 1.091785, -0.003174, 1.000109,
+ 0.004352, 1.101998, -0.002363, 1.000029, 0.003180, 1.111423, -0.001552, 0.999985, 0.002091,
+ 1.120007, -0.000786, 0.999947, 0.000991, 1.127918, 0.000004, 1.000000, -0.000004, 0.000200,
+ -0.000010, 1.002495, 0.049907, 0.000504, -0.000025, 1.002476, 0.049908, 0.002016, -0.000101,
+ 1.002500, 0.049908, 0.004535, -0.000226, 1.002487, 0.049908, 0.008062, -0.000402, 1.002364,
+ 0.049908, 0.012598, -0.000629, 1.002412, 0.049908, 0.018140, -0.000905, 1.002379, 0.049908,
+ 0.024691, -0.001232, 1.002490, 0.049907, 0.032251, -0.001610, 1.002398, 0.049908, 0.040821,
+ -0.002037, 1.002392, 0.049908, 0.050398, -0.002515, 1.002431, 0.049907, 0.060989, -0.003044,
+ 1.002475, 0.049908, 0.072592, -0.003623, 1.002546, 0.049907, 0.085204, -0.004252, 1.002467,
+ 0.049907, 0.098832, -0.004932, 1.002450, 0.049908, 0.113481, -0.005663, 1.002482, 0.049907,
+ 0.129145, -0.006443, 1.002443, 0.049907, 0.145825, -0.007271, 1.002495, 0.049906, 0.163491,
+ -0.008128, 1.002475, 0.049903, 0.181911, -0.008826, 1.002459, 0.049879, 0.200065, -0.009285,
+ 1.002443, 0.049824, 0.220025, -0.010966, 1.002450, 0.049897, 0.241581, -0.012025, 1.002463,
+ 0.049893, 0.264099, -0.013105, 1.002395, 0.049881, 0.287493, -0.014145, 1.002390, 0.049855,
+ 0.311399, -0.014925, 1.002414, 0.049769, 0.335096, -0.015239, 1.002363, 0.049591, 0.359815,
+ -0.017559, 1.002415, 0.049777, 0.386365, -0.018554, 1.002354, 0.049675, 0.413017, -0.019043,
+ 1.002297, 0.049444, 0.439519, -0.019815, 1.002284, 0.049253, 0.466938, -0.021741, 1.002307,
+ 0.049327, 0.494999, -0.021887, 1.002181, 0.048922, 0.522922, -0.022844, 1.002107, 0.048677,
+ 0.551270, -0.024014, 1.002101, 0.048478, 0.579771, -0.024156, 1.002060, 0.047904, 0.608156,
+ -0.025317, 1.002077, 0.047594, 0.636662, -0.025321, 1.001975, 0.046876, 0.664846, -0.026018,
+ 1.001992, 0.046354, 0.692877, -0.026041, 1.001846, 0.045504, 0.720316, -0.026252, 1.001846,
+ 0.044655, 0.747658, -0.026159, 1.001931, 0.043670, 0.774252, -0.026086, 1.001845, 0.042515,
+ 0.800179, -0.025653, 1.001794, 0.041211, 0.825525, -0.025170, 1.001787, 0.039823, 0.850013,
+ -0.024788, 1.001806, 0.038409, 0.873593, -0.023992, 1.001688, 0.036767, 0.896343, -0.022985,
+ 1.001666, 0.034900, 0.918062, -0.022005, 1.001548, 0.033010, 0.938928, -0.021110, 1.001503,
+ 0.031143, 0.958667, -0.019893, 1.001341, 0.029059, 0.977457, -0.018546, 1.001194, 0.026888,
+ 0.995243, -0.017152, 1.001095, 0.024713, 1.012023, -0.015750, 1.001100, 0.022496, 1.027614,
+ -0.014289, 1.000851, 0.020153, 1.042389, -0.012688, 1.000724, 0.017839, 1.056161, -0.011118,
+ 1.000572, 0.015529, 1.068968, -0.009540, 1.000407, 0.013240, 1.080866, -0.007963, 1.000258,
+ 0.010940, 1.091944, -0.006416, 1.000254, 0.008716, 1.102104, -0.004771, 1.000175, 0.006434,
+ 1.111571, -0.003056, 1.000148, 0.004169, 1.120084, -0.001458, 1.000050, 0.002033, 1.127981,
+ 0.000021, 0.999987, -0.000027, 0.000200, -0.000015, 1.005620, 0.074940, 0.000504, -0.000038,
+ 1.005650, 0.074939, 0.002016, -0.000151, 1.005613, 0.074939, 0.004535, -0.000340, 1.005618,
+ 0.074939, 0.008062, -0.000604, 1.005614, 0.074939, 0.012597, -0.000944, 1.005616, 0.074940,
+ 0.018141, -0.001359, 1.005558, 0.074939, 0.024695, -0.001851, 1.005495, 0.074940, 0.032253,
+ -0.002417, 1.005616, 0.074939, 0.040822, -0.003059, 1.005591, 0.074940, 0.050399, -0.003777,
+ 1.005596, 0.074940, 0.060989, -0.004570, 1.005599, 0.074939, 0.072591, -0.005440, 1.005616,
+ 0.074940, 0.085203, -0.006385, 1.005616, 0.074939, 0.098833, -0.007406, 1.005595, 0.074938,
+ 0.113481, -0.008502, 1.005605, 0.074938, 0.129147, -0.009674, 1.005605, 0.074937, 0.145817,
+ -0.010916, 1.005513, 0.074937, 0.163485, -0.012199, 1.005579, 0.074928, 0.181824, -0.013172,
+ 1.005552, 0.074885, 0.200274, -0.014100, 1.005524, 0.074825, 0.220017, -0.016464, 1.005529,
+ 0.074928, 0.241568, -0.018052, 1.005490, 0.074914, 0.264084, -0.019671, 1.005457, 0.074898,
+ 0.287450, -0.021217, 1.005431, 0.074860, 0.311281, -0.022341, 1.005395, 0.074717, 0.335228,
+ -0.023296, 1.005320, 0.074526, 0.360047, -0.025965, 1.005302, 0.074649, 0.386273, -0.027808,
+ 1.005285, 0.074575, 0.412855, -0.028504, 1.005167, 0.074237, 0.439705, -0.030007, 1.005129,
+ 0.074013, 0.466975, -0.032263, 1.005082, 0.073967, 0.494874, -0.032931, 1.004960, 0.073475,
+ 0.523066, -0.034348, 1.004834, 0.073084, 0.551198, -0.035739, 1.004806, 0.072657, 0.579889,
+ -0.036575, 1.004687, 0.072029, 0.608282, -0.037434, 1.004605, 0.071309, 0.636812, -0.038323,
+ 1.004589, 0.070507, 0.665010, -0.038676, 1.004403, 0.069424, 0.693063, -0.039237, 1.004340,
+ 0.068370, 0.720750, -0.039332, 1.004224, 0.066988, 0.747911, -0.039179, 1.004117, 0.065447,
+ 0.774576, -0.039110, 1.004035, 0.063838, 0.800737, -0.038542, 1.004027, 0.061923, 0.825966,
+ -0.037966, 1.003825, 0.059859, 0.850534, -0.036943, 1.003786, 0.057529, 0.874289, -0.035853,
+ 1.003560, 0.055081, 0.897152, -0.034730, 1.003549, 0.052476, 0.919029, -0.033242, 1.003454,
+ 0.049647, 0.939851, -0.031508, 1.003215, 0.046670, 0.959599, -0.029695, 1.002916, 0.043588,
+ 0.978293, -0.027845, 1.002720, 0.040401, 0.996085, -0.025775, 1.002445, 0.037060, 1.012768,
+ -0.023607, 1.002133, 0.033726, 1.028404, -0.021374, 1.001822, 0.030217, 1.043150, -0.019108,
+ 1.001602, 0.026820, 1.056760, -0.016823, 1.001274, 0.023372, 1.069471, -0.014378, 1.000964,
+ 0.019891, 1.081283, -0.011884, 1.000684, 0.016405, 1.092238, -0.009398, 1.000514, 0.012950,
+ 1.102384, -0.007030, 1.000319, 0.009579, 1.111737, -0.004751, 1.000225, 0.006384, 1.120274,
+ -0.002404, 1.000046, 0.003192, 1.128182, 0.000031, 1.000020, 0.000033, 0.000200, -0.000020,
+ 1.010006, 0.100065, 0.000504, -0.000050, 1.009927, 0.100065, 0.002016, -0.000202, 1.010026,
+ 0.100064, 0.004535, -0.000454, 1.010018, 0.100065, 0.008062, -0.000807, 1.009891, 0.100064,
+ 0.012599, -0.001261, 1.010175, 0.100064, 0.018141, -0.001815, 1.010067, 0.100065, 0.024692,
+ -0.002471, 1.010014, 0.100066, 0.032251, -0.003227, 1.009950, 0.100065, 0.040818, -0.004084,
+ 1.009963, 0.100067, 0.050401, -0.005043, 1.010032, 0.100064, 0.060988, -0.006102, 1.009979,
+ 0.100064, 0.072588, -0.007263, 1.009984, 0.100063, 0.085205, -0.008525, 1.010023, 0.100063,
+ 0.098832, -0.009888, 1.009960, 0.100062, 0.113479, -0.011352, 1.009974, 0.100063, 0.129142,
+ -0.012916, 1.009945, 0.100062, 0.145817, -0.014573, 1.009924, 0.100058, 0.163468, -0.016276,
+ 1.009912, 0.100050, 0.181674, -0.017411, 1.009859, 0.099975, 0.200435, -0.019002, 1.009842,
+ 0.099932, 0.220005, -0.021978, 1.009820, 0.100043, 0.241550, -0.024096, 1.009778, 0.100031,
+ 0.264058, -0.026250, 1.009765, 0.100002, 0.287399, -0.028286, 1.009724, 0.099939, 0.311134,
+ -0.029698, 1.009596, 0.099748, 0.335350, -0.031442, 1.009508, 0.099582, 0.360295, -0.034401,
+ 1.009475, 0.099613, 0.386112, -0.037030, 1.009329, 0.099558, 0.412733, -0.038163, 1.009250,
+ 0.099137, 0.439833, -0.040250, 1.009125, 0.098866, 0.467099, -0.042583, 1.009011, 0.098626,
+ 0.494828, -0.044299, 1.008803, 0.098149, 0.523217, -0.045876, 1.008712, 0.097600, 0.551338,
+ -0.047440, 1.008509, 0.096929, 0.579917, -0.048995, 1.008371, 0.096178, 0.608454, -0.049901,
+ 1.008212, 0.095145, 0.636785, -0.051224, 1.007963, 0.094151, 0.665220, -0.051675, 1.007741,
+ 0.092728, 0.693194, -0.052278, 1.007616, 0.091195, 0.721008, -0.052406, 1.007327, 0.089384,
+ 0.748196, -0.052529, 1.007219, 0.087461, 0.774975, -0.051950, 1.006851, 0.085133, 0.801129,
+ -0.051456, 1.006732, 0.082628, 0.826668, -0.050569, 1.006612, 0.079817, 0.851291, -0.049328,
+ 1.006374, 0.076710, 0.875056, -0.047988, 1.006183, 0.073481, 0.897872, -0.046149, 1.005742,
+ 0.069943, 0.919803, -0.044144, 1.005514, 0.066151, 0.940701, -0.042095, 1.005153, 0.062247,
+ 0.960580, -0.039730, 1.004843, 0.058158, 0.979427, -0.037104, 1.004535, 0.053850, 0.997157,
+ -0.034369, 1.004023, 0.049403, 1.013777, -0.031555, 1.003622, 0.044944, 1.029452, -0.028571,
+ 1.003212, 0.040414, 1.044029, -0.025416, 1.002698, 0.035723, 1.057586, -0.022217, 1.002202,
+ 0.031072, 1.070148, -0.019037, 1.001703, 0.026429, 1.081875, -0.015936, 1.001322, 0.021896,
+ 1.092789, -0.012734, 1.001053, 0.017288, 1.102704, -0.009454, 1.000604, 0.012841, 1.112011,
+ -0.006199, 1.000387, 0.008446, 1.120590, -0.003010, 1.000166, 0.004122, 1.128283, 0.000027,
+ 0.999956, -0.000038, 0.000200, -0.000025, 1.015664, 0.125315, 0.000504, -0.000063, 1.015664,
+ 0.125316, 0.002016, -0.000253, 1.015727, 0.125315, 0.004535, -0.000568, 1.015695, 0.125314,
+ 0.008063, -0.001010, 1.015823, 0.125316, 0.012599, -0.001579, 1.015867, 0.125315, 0.018141,
+ -0.002273, 1.015758, 0.125316, 0.024691, -0.003094, 1.015662, 0.125316, 0.032252, -0.004042,
+ 1.015674, 0.125316, 0.040820, -0.005115, 1.015678, 0.125316, 0.050400, -0.006316, 1.015684,
+ 0.125315, 0.060989, -0.007642, 1.015685, 0.125315, 0.072590, -0.009096, 1.015703, 0.125314,
+ 0.085203, -0.010676, 1.015654, 0.125314, 0.098833, -0.012383, 1.015670, 0.125315, 0.113477,
+ -0.014215, 1.015635, 0.125312, 0.129138, -0.016173, 1.015599, 0.125311, 0.145815, -0.018246,
+ 1.015610, 0.125306, 0.163450, -0.020360, 1.015564, 0.125294, 0.181595, -0.021807, 1.015460,
+ 0.125204, 0.200563, -0.023971, 1.015440, 0.125165, 0.220186, -0.027280, 1.015412, 0.125250,
+ 0.241528, -0.030164, 1.015342, 0.125267, 0.264020, -0.032847, 1.015269, 0.125233, 0.287311,
+ -0.035345, 1.015232, 0.125138, 0.310993, -0.037108, 1.015063, 0.124903, 0.335467, -0.039653,
+ 1.014970, 0.124749, 0.360497, -0.042914, 1.014819, 0.124702, 0.385986, -0.046142, 1.014685,
+ 0.124623, 0.412703, -0.048050, 1.014543, 0.124193, 0.439929, -0.050527, 1.014315, 0.123833,
+ 0.467163, -0.052880, 1.014087, 0.123375, 0.494824, -0.055672, 1.013898, 0.122982, 0.523222,
+ -0.057388, 1.013647, 0.122166, 0.551557, -0.059328, 1.013403, 0.121343, 0.579884, -0.061315,
+ 1.013059, 0.120430, 0.608619, -0.062531, 1.012745, 0.119140, 0.637014, -0.063778, 1.012425,
+ 0.117721, 0.665425, -0.064734, 1.012067, 0.116069, 0.693580, -0.065315, 1.011712, 0.114146,
+ 0.721194, -0.065535, 1.011200, 0.111846, 0.748586, -0.065501, 1.010896, 0.109309, 0.775437,
+ -0.065091, 1.010576, 0.106504, 0.801554, -0.064332, 1.010136, 0.103308, 0.827079, -0.063078,
+ 1.009629, 0.099695, 0.851693, -0.061728, 1.009233, 0.095946, 0.875586, -0.059853, 1.008726,
+ 0.091802, 0.898589, -0.057727, 1.008412, 0.087339, 0.920421, -0.055377, 1.007767, 0.082687,
+ 0.941533, -0.052571, 1.007529, 0.077716, 0.961426, -0.049544, 1.006929, 0.072574, 0.980287,
+ -0.046400, 1.006393, 0.067217, 0.998080, -0.042966, 1.005872, 0.061757, 1.014940, -0.039321,
+ 1.005346, 0.056072, 1.030455, -0.035585, 1.004609, 0.050410, 1.045078, -0.031823, 1.004151,
+ 0.044622, 1.058555, -0.027947, 1.003421, 0.038893, 1.071009, -0.023891, 1.002704, 0.032977,
+ 1.082594, -0.019822, 1.002023, 0.027290, 1.093265, -0.015765, 1.001403, 0.021543, 1.103132,
+ -0.011790, 1.000944, 0.016072, 1.112348, -0.007784, 1.000550, 0.010511, 1.120845, -0.003849,
+ 1.000224, 0.005174, 1.128573, 0.000057, 0.999975, -0.000039, 0.000200, -0.000030, 1.022609,
+ 0.150725, 0.000504, -0.000076, 1.022728, 0.150725, 0.002016, -0.000304, 1.022728, 0.150725,
+ 0.004535, -0.000684, 1.022733, 0.150725, 0.008062, -0.001215, 1.022715, 0.150725, 0.012598,
+ -0.001899, 1.022720, 0.150725, 0.018141, -0.002734, 1.022659, 0.150725, 0.024694, -0.003722,
+ 1.022801, 0.150724, 0.032254, -0.004861, 1.022779, 0.150726, 0.040815, -0.006152, 1.022693,
+ 0.150724, 0.050400, -0.007596, 1.022716, 0.150725, 0.060990, -0.009192, 1.022733, 0.150725,
+ 0.072587, -0.010939, 1.022630, 0.150723, 0.085203, -0.012839, 1.022676, 0.150725, 0.098828,
+ -0.014891, 1.022659, 0.150725, 0.113473, -0.017095, 1.022589, 0.150720, 0.129137, -0.019449,
+ 1.022572, 0.150716, 0.145803, -0.021938, 1.022508, 0.150712, 0.163417, -0.024443, 1.022471,
+ 0.150691, 0.181580, -0.026329, 1.022406, 0.150600, 0.200667, -0.028997, 1.022336, 0.150553,
+ 0.220429, -0.032584, 1.022296, 0.150610, 0.241497, -0.036260, 1.022202, 0.150658, 0.263975,
+ -0.039465, 1.022119, 0.150619, 0.287210, -0.042385, 1.021988, 0.150490, 0.310935, -0.044758,
+ 1.021771, 0.150241, 0.335556, -0.047922, 1.021658, 0.150076, 0.360667, -0.051493, 1.021437,
+ 0.149931, 0.386028, -0.054931, 1.021228, 0.149754, 0.412665, -0.058007, 1.021023, 0.149400,
+ 0.439951, -0.060813, 1.020723, 0.148913, 0.467262, -0.063461, 1.020332, 0.148319, 0.494972,
+ -0.066738, 1.020097, 0.147798, 0.523153, -0.068976, 1.019630, 0.146903, 0.551700, -0.071268,
+ 1.019245, 0.145863, 0.580046, -0.073439, 1.018797, 0.144695, 0.608649, -0.075193, 1.018201,
+ 0.143237, 0.637239, -0.076536, 1.017746, 0.141463, 0.665388, -0.077771, 1.017111, 0.139462,
+ 0.693755, -0.078344, 1.016609, 0.137082, 0.721345, -0.078817, 1.015863, 0.134403, 0.748879,
+ -0.078512, 1.015390, 0.131252, 0.775560, -0.078128, 1.014652, 0.127866, 0.801897, -0.077094,
+ 1.013877, 0.123928, 0.827193, -0.075863, 1.013021, 0.119733, 0.851990, -0.073973, 1.012395,
+ 0.115055, 0.875823, -0.071765, 1.011595, 0.110098, 0.898655, -0.069241, 1.010862, 0.104722,
+ 0.920915, -0.066232, 1.010185, 0.098991, 0.941969, -0.062980, 1.009588, 0.093044, 0.961882,
+ -0.059507, 1.008777, 0.086925, 0.980952, -0.055606, 1.008252, 0.080520, 0.998955, -0.051503,
+ 1.007633, 0.073890, 1.015756, -0.047292, 1.006908, 0.067302, 1.031571, -0.042804, 1.006338,
+ 0.060412, 1.046095, -0.038132, 1.005512, 0.053497, 1.059542, -0.033380, 1.004592, 0.046569,
+ 1.072006, -0.028613, 1.003731, 0.039679, 1.083348, -0.023811, 1.002871, 0.032772, 1.093969,
+ -0.018930, 1.002068, 0.025894, 1.103697, -0.014098, 1.001284, 0.019178, 1.112813, -0.009339,
+ 1.000820, 0.012652, 1.121193, -0.004661, 1.000324, 0.006226, 1.128930, 0.000052, 0.999988,
+ -0.000008, 0.000200, -0.000035, 1.030857, 0.176327, 0.000504, -0.000089, 1.031137, 0.176326,
+ 0.002016, -0.000355, 1.031049, 0.176325, 0.004535, -0.000800, 1.031105, 0.176326, 0.008062,
+ -0.001422, 1.030973, 0.176326, 0.012598, -0.002221, 1.031168, 0.176326, 0.018141, -0.003199,
+ 1.031093, 0.176326, 0.024695, -0.004354, 1.031297, 0.176326, 0.032253, -0.005687, 1.031091,
+ 0.176327, 0.040821, -0.007197, 1.031012, 0.176326, 0.050399, -0.008886, 1.031068, 0.176325,
+ 0.060987, -0.010752, 1.030967, 0.176323, 0.072588, -0.012797, 1.031028, 0.176324, 0.085200,
+ -0.015019, 1.030985, 0.176322, 0.098829, -0.017419, 1.030983, 0.176320, 0.113474, -0.019997,
+ 1.030953, 0.176317, 0.129133, -0.022748, 1.030891, 0.176312, 0.145800, -0.025655, 1.030825,
+ 0.176306, 0.163372, -0.028510, 1.030781, 0.176279, 0.181578, -0.030914, 1.030683, 0.176187,
+ 0.200761, -0.034076, 1.030574, 0.176139, 0.220645, -0.037985, 1.030476, 0.176160, 0.241473,
+ -0.042391, 1.030384, 0.176238, 0.263922, -0.046105, 1.030241, 0.176175, 0.287074, -0.049390,
+ 1.030049, 0.176013, 0.310915, -0.052511, 1.029839, 0.175776, 0.335604, -0.056236, 1.029608,
+ 0.175578, 0.360775, -0.060118, 1.029355, 0.175359, 0.386196, -0.063907, 1.029052, 0.175083,
+ 0.412599, -0.067997, 1.028766, 0.174791, 0.439916, -0.071088, 1.028326, 0.174174, 0.467444,
+ -0.074247, 1.027890, 0.173487, 0.495132, -0.077728, 1.027374, 0.172774, 0.523117, -0.080822,
+ 1.026763, 0.171824, 0.551783, -0.083228, 1.026205, 0.170554, 0.580234, -0.085682, 1.025614,
+ 0.169090, 0.608568, -0.087860, 1.024668, 0.167468, 0.637357, -0.089346, 1.023939, 0.165283,
+ 0.665507, -0.090704, 1.022946, 0.162966, 0.693704, -0.091388, 1.022010, 0.160131, 0.721396,
+ -0.091783, 1.021085, 0.156957, 0.748676, -0.091688, 1.019894, 0.153292, 0.775370, -0.090992,
+ 1.018608, 0.149158, 0.801547, -0.089881, 1.017646, 0.144551, 0.827013, -0.088267, 1.016355,
+ 0.139614, 0.851708, -0.086132, 1.015446, 0.134026, 0.875652, -0.083707, 1.014321, 0.128101,
+ 0.898703, -0.080619, 1.013454, 0.121841, 0.920904, -0.077280, 1.012634, 0.115379, 0.942077,
+ -0.073484, 1.011770, 0.108355, 0.962245, -0.069252, 1.010894, 0.101153, 0.981385, -0.064807,
+ 1.010114, 0.093666, 0.999379, -0.060080, 1.009294, 0.086007, 1.016494, -0.055007, 1.008591,
+ 0.078194, 1.032357, -0.049760, 1.007821, 0.070328, 1.047061, -0.044468, 1.006871, 0.062358,
+ 1.060675, -0.038960, 1.006062, 0.054279, 1.073032, -0.033343, 1.004911, 0.046158, 1.084293,
+ -0.027699, 1.003791, 0.038111, 1.094724, -0.022130, 1.002744, 0.030239, 1.104302, -0.016508,
+ 1.001815, 0.022397, 1.113290, -0.010846, 1.001083, 0.014747, 1.121649, -0.005294, 1.000490,
+ 0.007234, 1.129230, 0.000071, 0.999975, -0.000053, 0.000200, -0.000040, 1.040431, 0.202155,
+ 0.000504, -0.000102, 1.040912, 0.202154, 0.002016, -0.000407, 1.041328, 0.202152, 0.004535,
+ -0.000917, 1.040877, 0.202154, 0.008063, -0.001630, 1.040867, 0.202153, 0.012598, -0.002547,
+ 1.040870, 0.202153, 0.018140, -0.003667, 1.040808, 0.202153, 0.024692, -0.004991, 1.040861,
+ 0.202153, 0.032252, -0.006519, 1.040861, 0.202153, 0.040822, -0.008252, 1.040864, 0.202153,
+ 0.050397, -0.010187, 1.040717, 0.202151, 0.060988, -0.012327, 1.040791, 0.202152, 0.072582,
+ -0.014669, 1.040640, 0.202149, 0.085198, -0.017217, 1.040716, 0.202147, 0.098827, -0.019968,
+ 1.040748, 0.202141, 0.113467, -0.022921, 1.040632, 0.202142, 0.129129, -0.026074, 1.040606,
+ 0.202137, 0.145793, -0.029399, 1.040566, 0.202127, 0.163294, -0.032524, 1.040459, 0.202078,
+ 0.181589, -0.035552, 1.040315, 0.201996, 0.200844, -0.039208, 1.040221, 0.201948, 0.220835,
+ -0.043489, 1.040047, 0.201945, 0.241471, -0.048523, 1.039921, 0.202031, 0.263854, -0.052764,
+ 1.039756, 0.201957, 0.286935, -0.056387, 1.039497, 0.201743, 0.310902, -0.060338, 1.039252,
+ 0.201531, 0.335642, -0.064594, 1.038954, 0.201286, 0.360859, -0.068772, 1.038582, 0.200983,
+ 0.386419, -0.073086, 1.038160, 0.200651, 0.412588, -0.077887, 1.037724, 0.200343, 0.439836,
+ -0.081391, 1.037182, 0.199618, 0.467538, -0.085121, 1.036602, 0.198839, 0.495286, -0.088718,
+ 1.035893, 0.197895, 0.523231, -0.092514, 1.035121, 0.196887, 0.551730, -0.095238, 1.034127,
+ 0.195390, 0.580302, -0.097949, 1.033131, 0.193668, 0.608559, -0.100418, 1.031962, 0.191773,
+ 0.637224, -0.102129, 1.030838, 0.189319, 0.665597, -0.103578, 1.029511, 0.186529, 0.693535,
+ -0.104652, 1.028263, 0.183303, 0.721325, -0.104766, 1.026611, 0.179497, 0.748384, -0.104717,
+ 1.025128, 0.175283, 0.775058, -0.103846, 1.023385, 0.170493, 0.801387, -0.102728, 1.022236,
+ 0.165187, 0.826412, -0.100679, 1.019908, 0.159362, 0.851314, -0.098451, 1.018839, 0.153059,
+ 0.875100, -0.095363, 1.017306, 0.146284, 0.898280, -0.092008, 1.016151, 0.138975, 0.920450,
+ -0.088095, 1.014880, 0.131361, 0.941727, -0.083690, 1.013556, 0.123417, 0.962308, -0.079077,
+ 1.012998, 0.115201, 0.981364, -0.073894, 1.011841, 0.106711, 0.999798, -0.068435, 1.011021,
+ 0.098063, 1.016983, -0.062830, 1.010194, 0.089183, 1.033039, -0.056914, 1.009292, 0.080190,
+ 1.047994, -0.050721, 1.008474, 0.071010, 1.061580, -0.044454, 1.007386, 0.061867, 1.074023,
+ -0.038145, 1.006135, 0.052711, 1.085470, -0.031679, 1.004890, 0.043595, 1.095673, -0.025157,
+ 1.003627, 0.034506, 1.105000, -0.018702, 1.002331, 0.025468, 1.113795, -0.012458, 1.001278,
+ 0.016834, 1.122012, -0.006169, 1.000548, 0.008265, 1.129683, 0.000078, 0.999988, -0.000072,
+ 0.000200, -0.000046, 1.052496, 0.228243, 0.000504, -0.000115, 1.052079, 0.228243, 0.002016,
+ -0.000460, 1.052079, 0.228241, 0.004535, -0.001035, 1.052091, 0.228242, 0.008062, -0.001840,
+ 1.051962, 0.228242, 0.012598, -0.002875, 1.052087, 0.228242, 0.018141, -0.004140, 1.052088,
+ 0.228242, 0.024692, -0.005636, 1.052096, 0.228239, 0.032251, -0.007361, 1.052029, 0.228243,
+ 0.040820, -0.009316, 1.052038, 0.228241, 0.050399, -0.011501, 1.052042, 0.228239, 0.060990,
+ -0.013917, 1.052046, 0.228238, 0.072586, -0.016562, 1.051990, 0.228236, 0.085198, -0.019437,
+ 1.051946, 0.228234, 0.098824, -0.022542, 1.051879, 0.228229, 0.113467, -0.025875, 1.051841,
+ 0.228227, 0.129121, -0.029430, 1.051724, 0.228219, 0.145780, -0.033170, 1.051672, 0.228205,
+ 0.163222, -0.036567, 1.051556, 0.228143, 0.181604, -0.040245, 1.051382, 0.228069, 0.200913,
+ -0.044395, 1.051230, 0.228010, 0.221005, -0.049088, 1.051062, 0.227988, 0.241667, -0.054506,
+ 1.050881, 0.228044, 0.263777, -0.059437, 1.050643, 0.227986, 0.286841, -0.063590, 1.050312,
+ 0.227755, 0.310879, -0.068224, 1.050009, 0.227525, 0.335650, -0.072986, 1.049597, 0.227253,
+ 0.360869, -0.077435, 1.049121, 0.226845, 0.386609, -0.082385, 1.048587, 0.226466, 0.412742,
+ -0.087570, 1.047987, 0.226059, 0.439789, -0.091929, 1.047308, 0.225331, 0.467558, -0.096038,
+ 1.046423, 0.224409, 0.495406, -0.099938, 1.045481, 0.223288, 0.523417, -0.104050, 1.044512,
+ 0.222066, 0.551755, -0.107503, 1.043408, 0.220487, 0.580468, -0.110234, 1.042016, 0.218451,
+ 0.608904, -0.112993, 1.040535, 0.216200, 0.637230, -0.115173, 1.038934, 0.213458, 0.665566,
+ -0.116433, 1.036961, 0.210158, 0.693413, -0.117589, 1.035130, 0.206457, 0.721025, -0.117885,
+ 1.033080, 0.202197, 0.748054, -0.117606, 1.030752, 0.197296, 0.774631, -0.116771, 1.028608,
+ 0.191813, 0.800677, -0.115194, 1.026350, 0.185691, 0.826062, -0.113138, 1.024472, 0.179053,
+ 0.850590, -0.110359, 1.022174, 0.171839, 0.874550, -0.107072, 1.020381, 0.164067, 0.897567,
+ -0.103268, 1.018777, 0.155959, 0.919609, -0.098794, 1.016886, 0.147320, 0.941177, -0.094067,
+ 1.015880, 0.138365, 0.961752, -0.088670, 1.014616, 0.129051, 0.981518, -0.082965, 1.013807,
+ 0.119515, 0.999880, -0.076971, 1.012793, 0.109897, 1.017370, -0.070518, 1.011894, 0.099872,
+ 1.033661, -0.063830, 1.010943, 0.089883, 1.048672, -0.057040, 1.009802, 0.079691, 1.062479,
+ -0.049917, 1.008670, 0.069458, 1.075052, -0.042735, 1.007429, 0.059191, 1.086371, -0.035513,
+ 1.005991, 0.048894, 1.096623, -0.028359, 1.004468, 0.038770, 1.105871, -0.021111, 1.002927,
+ 0.028745, 1.114481, -0.013908, 1.001728, 0.018884, 1.122610, -0.006843, 1.000740, 0.009264,
+ 1.130165, 0.000062, 0.999983, -0.000006, 0.000200, -0.000051, 1.064931, 0.254630, 0.000504,
+ -0.000128, 1.064668, 0.254630, 0.002016, -0.000513, 1.064794, 0.254630, 0.004535, -0.001155,
+ 1.064851, 0.254630, 0.008063, -0.002053, 1.064966, 0.254630, 0.012598, -0.003208, 1.064840,
+ 0.254630, 0.018140, -0.004619, 1.064602, 0.254631, 0.024695, -0.006288, 1.064965, 0.254632,
+ 0.032251, -0.008211, 1.064795, 0.254630, 0.040821, -0.010393, 1.064802, 0.254628, 0.050398,
+ -0.012830, 1.064758, 0.254627, 0.060987, -0.015525, 1.064731, 0.254625, 0.072584, -0.018474,
+ 1.064615, 0.254621, 0.085199, -0.021682, 1.064672, 0.254619, 0.098826, -0.025144, 1.064630,
+ 0.254613, 0.113465, -0.028860, 1.064515, 0.254606, 0.129119, -0.032823, 1.064416, 0.254598,
+ 0.145767, -0.036969, 1.064347, 0.254579, 0.163190, -0.040754, 1.064132, 0.254506, 0.181622,
+ -0.044989, 1.063951, 0.254437, 0.200981, -0.049642, 1.063745, 0.254370, 0.221145, -0.054776,
+ 1.063547, 0.254324, 0.241896, -0.060538, 1.063289, 0.254346, 0.263684, -0.066113, 1.063013,
+ 0.254296, 0.286796, -0.070925, 1.062625, 0.254059, 0.310867, -0.076187, 1.062216, 0.253817,
+ 0.335644, -0.081406, 1.061703, 0.253481, 0.360917, -0.086336, 1.061066, 0.253005, 0.386786,
+ -0.091790, 1.060454, 0.252558, 0.412921, -0.097230, 1.059568, 0.252008, 0.439722, -0.102574,
+ 1.058706, 0.251323, 0.467559, -0.106972, 1.057682, 0.250239, 0.495605, -0.111329, 1.056612,
+ 0.248944, 0.523589, -0.115561, 1.055101, 0.247471, 0.551787, -0.119732, 1.053745, 0.245777,
+ 0.580426, -0.122711, 1.051829, 0.243448, 0.608778, -0.125436, 1.049642, 0.240769, 0.637069,
+ -0.127993, 1.047749, 0.237739, 0.665251, -0.129448, 1.045244, 0.233928, 0.692977, -0.130408,
+ 1.042279, 0.229640, 0.720346, -0.130931, 1.039693, 0.224829, 0.747365, -0.130392, 1.036675,
+ 0.219144, 0.773734, -0.129540, 1.033719, 0.212965, 0.799578, -0.127689, 1.030774, 0.206047,
+ 0.825002, -0.125456, 1.028551, 0.198576, 0.849564, -0.122291, 1.025800, 0.190471, 0.873412,
+ -0.118720, 1.023657, 0.181739, 0.896628, -0.114323, 1.021381, 0.172586, 0.918952, -0.109587,
+ 1.019674, 0.162914, 0.940602, -0.104093, 1.018126, 0.153039, 0.960917, -0.098187, 1.016339,
+ 0.142774, 0.980911, -0.091963, 1.015440, 0.132316, 0.999686, -0.085159, 1.014377, 0.121453,
+ 1.017538, -0.078139, 1.013498, 0.110527, 1.033918, -0.070797, 1.012332, 0.099437, 1.049390,
+ -0.063129, 1.011368, 0.088157, 1.063402, -0.055354, 1.010111, 0.076951, 1.076096, -0.047522,
+ 1.008774, 0.065616, 1.087562, -0.039447, 1.007202, 0.054310, 1.097591, -0.031359, 1.005346,
+ 0.042948, 1.106782, -0.023393, 1.003710, 0.031799, 1.115234, -0.015461, 1.002116, 0.020943,
+ 1.123166, -0.007589, 1.000858, 0.010288, 1.130796, 0.000104, 1.000032, -0.000024, 0.000200,
+ -0.000056, 1.078780, 0.281356, 0.000504, -0.000142, 1.079271, 0.281355, 0.002015, -0.000567,
+ 1.078635, 0.281355, 0.004535, -0.001276, 1.079164, 0.281356, 0.008064, -0.002269, 1.079300,
+ 0.281355, 0.012598, -0.003544, 1.079149, 0.281355, 0.018143, -0.005104, 1.079329, 0.281355,
+ 0.024691, -0.006947, 1.079073, 0.281353, 0.032254, -0.009074, 1.079253, 0.281354, 0.040822,
+ -0.011484, 1.079176, 0.281353, 0.050399, -0.014177, 1.079057, 0.281349, 0.060987, -0.017153,
+ 1.079007, 0.281347, 0.072586, -0.020412, 1.078998, 0.281343, 0.085203, -0.023956, 1.078962,
+ 0.281336, 0.098823, -0.027778, 1.078839, 0.281332, 0.113464, -0.031882, 1.078783, 0.281325,
+ 0.129114, -0.036255, 1.078633, 0.281315, 0.145748, -0.040790, 1.078545, 0.281287, 0.163179,
+ -0.045024, 1.078311, 0.281208, 0.181649, -0.049791, 1.078135, 0.281137, 0.201042, -0.054953,
+ 1.077845, 0.281063, 0.221267, -0.060551, 1.077576, 0.281006, 0.242114, -0.066663, 1.077257,
+ 0.280978, 0.263568, -0.072771, 1.076897, 0.280925, 0.286744, -0.078349, 1.076405, 0.280689,
+ 0.310840, -0.084201, 1.075898, 0.280418, 0.335612, -0.089846, 1.075287, 0.280020, 0.360975,
+ -0.095394, 1.074482, 0.279513, 0.386932, -0.101290, 1.073617, 0.278961, 0.413171, -0.107042,
+ 1.072719, 0.278283, 0.439886, -0.113083, 1.071698, 0.277547, 0.467535, -0.118010, 1.070213,
+ 0.276311, 0.495701, -0.122793, 1.068857, 0.274867, 0.523772, -0.127278, 1.067037, 0.273153,
+ 0.551849, -0.131671, 1.064923, 0.271176, 0.580338, -0.135293, 1.062749, 0.268626, 0.608771,
+ -0.138065, 1.059944, 0.265569, 0.636756, -0.140565, 1.056851, 0.262054, 0.664574, -0.142434,
+ 1.053461, 0.257807, 0.692151, -0.143237, 1.049910, 0.252930, 0.719376, -0.143717, 1.046426,
+ 0.247414, 0.745852, -0.143117, 1.042377, 0.241001, 0.772300, -0.141975, 1.038789, 0.233797,
+ 0.798050, -0.140114, 1.035290, 0.226218, 0.823370, -0.137379, 1.032374, 0.217785, 0.847735,
+ -0.134119, 1.028853, 0.208748, 0.871897, -0.129985, 1.026395, 0.198877, 0.894950, -0.125324,
+ 1.023787, 0.188803, 0.917909, -0.120007, 1.022073, 0.178493, 0.939567, -0.114099, 1.020098,
+ 0.167466, 0.960534, -0.107748, 1.018851, 0.156223, 0.980423, -0.100748, 1.017362, 0.144716,
+ 0.999334, -0.093494, 1.015961, 0.133028, 1.017561, -0.085728, 1.015059, 0.120953, 1.034225,
+ -0.077627, 1.013888, 0.108943, 1.049937, -0.069375, 1.012898, 0.096678, 1.064265, -0.060807,
+ 1.011635, 0.084350, 1.077188, -0.052052, 1.010095, 0.071964, 1.088637, -0.043304, 1.008399,
+ 0.059531, 1.098766, -0.034458, 1.006397, 0.047134, 1.107697, -0.025637, 1.004354, 0.034887,
+ 1.116055, -0.016932, 1.002611, 0.022948, 1.123819, -0.008437, 1.001023, 0.011386, 1.131333,
+ 0.000087, 0.999952, -0.000097, 0.000200, -0.000062, 1.095622, 0.308458, 0.000504, -0.000155,
+ 1.094863, 0.308458, 0.002016, -0.000622, 1.095169, 0.308458, 0.004535, -0.001399, 1.095156,
+ 0.308458, 0.008063, -0.002487, 1.095413, 0.308455, 0.012598, -0.003886, 1.095147, 0.308458,
+ 0.018141, -0.005596, 1.095150, 0.308457, 0.024692, -0.007616, 1.095140, 0.308457, 0.032252,
+ -0.009947, 1.095098, 0.308456, 0.040822, -0.012589, 1.095096, 0.308453, 0.050399, -0.015541,
+ 1.095070, 0.308451, 0.060985, -0.018803, 1.094922, 0.308448, 0.072583, -0.022375, 1.094902,
+ 0.308444, 0.085197, -0.026258, 1.094882, 0.308438, 0.098822, -0.030448, 1.094775, 0.308429,
+ 0.113460, -0.034944, 1.094641, 0.308419, 0.129112, -0.039731, 1.094530, 0.308403, 0.145711,
+ -0.044610, 1.094332, 0.308365, 0.163178, -0.049362, 1.094149, 0.308285, 0.181679, -0.054666,
+ 1.093876, 0.308210, 0.201109, -0.060336, 1.093603, 0.308132, 0.221388, -0.066414, 1.093250,
+ 0.308047, 0.242315, -0.072881, 1.092835, 0.307985, 0.263651, -0.079453, 1.092391, 0.307902,
+ 0.286720, -0.085882, 1.091866, 0.307688, 0.310817, -0.092274, 1.091225, 0.307379, 0.335562,
+ -0.098306, 1.090346, 0.306906, 0.361043, -0.104572, 1.089423, 0.306374, 0.387051, -0.110843,
+ 1.088437, 0.305710, 0.413405, -0.117062, 1.087228, 0.304906, 0.440122, -0.123501, 1.085879,
+ 0.304017, 0.467522, -0.129245, 1.084197, 0.302783, 0.495721, -0.134285, 1.082284, 0.301104,
+ 0.523925, -0.139143, 1.080109, 0.299142, 0.551814, -0.143638, 1.077043, 0.296825, 0.579878,
+ -0.147774, 1.074071, 0.294071, 0.608316, -0.150724, 1.070621, 0.290519, 0.636059, -0.153168,
+ 1.066390, 0.286424, 0.663481, -0.155139, 1.062069, 0.281559, 0.690753, -0.155944, 1.057211,
+ 0.276024, 0.717767, -0.156176, 1.052682, 0.269622, 0.743937, -0.155783, 1.047747, 0.262532,
+ 0.770214, -0.154245, 1.043510, 0.254609, 0.795542, -0.152192, 1.039121, 0.246007, 0.821099,
+ -0.149256, 1.035962, 0.236663, 0.845452, -0.145605, 1.032320, 0.226751, 0.869780, -0.141186,
+ 1.029390, 0.216165, 0.893141, -0.136137, 1.026485, 0.204937, 0.916034, -0.130332, 1.024389,
+ 0.193624, 0.938089, -0.124040, 1.022270, 0.181756, 0.959488, -0.117011, 1.020457, 0.169339,
+ 0.979594, -0.109617, 1.018871, 0.156875, 0.998912, -0.101562, 1.017533, 0.144288, 1.017100,
+ -0.093164, 1.016445, 0.131370, 1.034413, -0.084488, 1.015453, 0.118322, 1.050347, -0.075377,
+ 1.014259, 0.104963, 1.064958, -0.066108, 1.013057, 0.091722, 1.078045, -0.056702, 1.011491,
+ 0.078231, 1.089749, -0.047106, 1.009662, 0.064797, 1.099831, -0.037467, 1.007417, 0.051315,
+ 1.108789, -0.027990, 1.005144, 0.038064, 1.116865, -0.018464, 1.002925, 0.025008, 1.124609,
+ -0.009068, 1.001221, 0.012250, 1.132040, 0.000093, 0.999984, -0.000071, 0.000200, -0.000067,
+ 1.112554, 0.335981, 0.000504, -0.000169, 1.112660, 0.335981, 0.002016, -0.000677, 1.112827,
+ 0.335981, 0.004533, -0.001523, 1.112147, 0.335982, 0.008063, -0.002709, 1.112882, 0.335979,
+ 0.012598, -0.004233, 1.112891, 0.335980, 0.018141, -0.006095, 1.112882, 0.335980, 0.024693,
+ -0.008296, 1.112877, 0.335978, 0.032252, -0.010834, 1.112860, 0.335976, 0.040824, -0.013713,
+ 1.112965, 0.335974, 0.050398, -0.016927, 1.112753, 0.335971, 0.060991, -0.020482, 1.112826,
+ 0.335970, 0.072587, -0.024371, 1.112676, 0.335962, 0.085199, -0.028597, 1.112593, 0.335955,
+ 0.098822, -0.033159, 1.112453, 0.335943, 0.113461, -0.038052, 1.112329, 0.335930, 0.129108,
+ -0.043255, 1.112144, 0.335910, 0.145665, -0.048412, 1.111905, 0.335857, 0.163185, -0.053786,
+ 1.111668, 0.335781, 0.181710, -0.059608, 1.111345, 0.335696, 0.201166, -0.065794, 1.110979,
+ 0.335606, 0.221489, -0.072361, 1.110553, 0.335505, 0.242471, -0.079184, 1.110112, 0.335396,
+ 0.263900, -0.086213, 1.109584, 0.335271, 0.286688, -0.093491, 1.108927, 0.335089, 0.310773,
+ -0.100406, 1.108091, 0.334737, 0.335573, -0.106987, 1.107169, 0.334208, 0.361117, -0.113844,
+ 1.106097, 0.333600, 0.387175, -0.120463, 1.104826, 0.332828, 0.413665, -0.127245, 1.103415,
+ 0.331929, 0.440386, -0.133927, 1.101632, 0.330851, 0.467527, -0.140496, 1.099563, 0.329538,
+ 0.495630, -0.145874, 1.096956, 0.327618, 0.523864, -0.150997, 1.094201, 0.325390, 0.551705,
+ -0.155713, 1.090342, 0.322688, 0.579383, -0.159993, 1.086010, 0.319483, 0.607301, -0.163238,
+ 1.081226, 0.315522, 0.634873, -0.165667, 1.076065, 0.310840, 0.662028, -0.167606, 1.070466,
+ 0.305377, 0.688755, -0.168626, 1.064601, 0.299056, 0.715612, -0.168578, 1.059269, 0.291963,
+ 0.741604, -0.167961, 1.053648, 0.284018, 0.767757, -0.166439, 1.048928, 0.275474, 0.793264,
+ -0.164023, 1.044343, 0.266056, 0.818165, -0.160965, 1.039909, 0.255750, 0.843255, -0.156896,
+ 1.036180, 0.244843, 0.867249, -0.152262, 1.032303, 0.233464, 0.890994, -0.146655, 1.029365,
+ 0.221128, 0.913829, -0.140574, 1.026607, 0.208554, 0.936508, -0.133640, 1.024512, 0.195772,
+ 0.957720, -0.126220, 1.022421, 0.182420, 0.978940, -0.118164, 1.021293, 0.168852, 0.998285,
+ -0.109558, 1.019444, 0.155261, 1.016764, -0.100562, 1.017825, 0.141395, 1.034387, -0.091064,
+ 1.016996, 0.127311, 1.050916, -0.081468, 1.015945, 0.113089, 1.065652, -0.071463, 1.014547,
+ 0.098879, 1.079155, -0.061240, 1.013066, 0.084468, 1.090822, -0.050980, 1.010788, 0.069940,
+ 1.101100, -0.040549, 1.008563, 0.055475, 1.109824, -0.030101, 1.005950, 0.041033, 1.117828,
+ -0.019884, 1.003453, 0.027022, 1.125443, -0.009900, 1.001484, 0.013306, 1.132869, 0.000094,
+ 1.000004, -0.000046, 0.000200, -0.000073, 1.132849, 0.363970, 0.000504, -0.000183, 1.132155,
+ 0.363969, 0.002016, -0.000734, 1.132516, 0.363969, 0.004535, -0.001651, 1.132256, 0.363969,
+ 0.008062, -0.002934, 1.132318, 0.363966, 0.012597, -0.004585, 1.132386, 0.363968, 0.018141,
+ -0.006602, 1.132457, 0.363967, 0.024693, -0.008987, 1.132511, 0.363967, 0.032252, -0.011737,
+ 1.132488, 0.363965, 0.040819, -0.014853, 1.132241, 0.363959, 0.050398, -0.018336, 1.132372,
+ 0.363958, 0.060988, -0.022185, 1.132373, 0.363954, 0.072582, -0.026396, 1.132137, 0.363943,
+ 0.085195, -0.030973, 1.132071, 0.363935, 0.098822, -0.035913, 1.131978, 0.363922, 0.113461,
+ -0.041209, 1.131801, 0.363905, 0.129116, -0.046833, 1.131535, 0.363867, 0.145640, -0.052346,
+ 1.131290, 0.363814, 0.163199, -0.058275, 1.131046, 0.363734, 0.181742, -0.064623, 1.130671,
+ 0.363642, 0.201227, -0.071336, 1.130224, 0.363539, 0.221587, -0.078396, 1.129758, 0.363419,
+ 0.242625, -0.085545, 1.129213, 0.363256, 0.264183, -0.093110, 1.128549, 0.363097, 0.286668,
+ -0.101206, 1.127767, 0.362939, 0.310745, -0.108586, 1.126796, 0.362516, 0.335602, -0.115827,
+ 1.125686, 0.361953, 0.361202, -0.123212, 1.124451, 0.361275, 0.387298, -0.130294, 1.122861,
+ 0.360376, 0.413918, -0.137553, 1.121154, 0.359362, 0.440680, -0.144577, 1.118825, 0.358069,
+ 0.467667, -0.151558, 1.116002, 0.356581, 0.495449, -0.157621, 1.112778, 0.354531, 0.523514,
+ -0.162844, 1.108842, 0.351915, 0.551250, -0.167744, 1.104075, 0.348797, 0.578629, -0.172132,
+ 1.098733, 0.345222, 0.605757, -0.175733, 1.092224, 0.340665, 0.633392, -0.178109, 1.086201,
+ 0.335286, 0.660783, -0.180009, 1.080110, 0.329286, 0.687219, -0.181105, 1.073419, 0.322319,
+ 0.713873, -0.181046, 1.067410, 0.314616, 0.740094, -0.180219, 1.061414, 0.306014, 0.765233,
+ -0.178559, 1.055287, 0.296704, 0.790885, -0.175806, 1.049727, 0.286394, 0.815464, -0.172354,
+ 1.044519, 0.275189, 0.840259, -0.168048, 1.040375, 0.263441, 0.864285, -0.162904, 1.036010,
+ 0.250918, 0.888806, -0.157194, 1.033525, 0.237611, 0.911682, -0.150486, 1.029490, 0.223809,
+ 0.934481, -0.143212, 1.026778, 0.209705, 0.956337, -0.135233, 1.024632, 0.195281, 0.977380,
+ -0.126650, 1.022737, 0.180878, 0.997427, -0.117552, 1.021110, 0.166112, 1.016666, -0.107814,
+ 1.019869, 0.151231, 1.034337, -0.097814, 1.018543, 0.136375, 1.051082, -0.087330, 1.017476,
+ 0.121187, 1.066326, -0.076614, 1.016083, 0.106043, 1.079897, -0.065793, 1.014227, 0.090566,
+ 1.092136, -0.054654, 1.012334, 0.074988, 1.102315, -0.043516, 1.009627, 0.059577, 1.111105,
+ -0.032509, 1.006808, 0.044202, 1.118861, -0.021381, 1.003917, 0.028995, 1.126363, -0.010489,
+ 1.001670, 0.014269, 1.133598, 0.000083, 0.999989, -0.000035, 0.000200, -0.000079, 1.155026,
+ 0.392470, 0.000504, -0.000198, 1.154184, 0.392469, 0.002016, -0.000791, 1.153990, 0.392469,
+ 0.004535, -0.001780, 1.154045, 0.392469, 0.008063, -0.003164, 1.154007, 0.392466, 0.012598,
+ -0.004944, 1.154022, 0.392469, 0.018141, -0.007119, 1.154015, 0.392468, 0.024692, -0.009690,
+ 1.154017, 0.392466, 0.032254, -0.012656, 1.154069, 0.392465, 0.040826, -0.016018, 1.153980,
+ 0.392459, 0.050399, -0.019771, 1.153911, 0.392456, 0.060987, -0.023919, 1.153860, 0.392447,
+ 0.072588, -0.028461, 1.153777, 0.392442, 0.085197, -0.033393, 1.153582, 0.392428, 0.098822,
+ -0.038716, 1.153434, 0.392412, 0.113462, -0.044422, 1.153271, 0.392390, 0.129101, -0.050455,
+ 1.153019, 0.392359, 0.145642, -0.056392, 1.152721, 0.392283, 0.163223, -0.062859, 1.152404,
+ 0.392201, 0.181779, -0.069721, 1.151941, 0.392099, 0.201289, -0.076968, 1.151422, 0.391978,
+ 0.221678, -0.084518, 1.150861, 0.391833, 0.242752, -0.092017, 1.150156, 0.391618, 0.264474,
+ -0.100184, 1.149402, 0.391421, 0.286768, -0.108921, 1.148545, 0.391249, 0.310719, -0.116815,
+ 1.147388, 0.390773, 0.335638, -0.124785, 1.146042, 0.390168, 0.361240, -0.132630, 1.144529,
+ 0.389394, 0.387443, -0.140298, 1.142602, 0.388391, 0.414067, -0.147913, 1.140361, 0.387199,
+ 0.440904, -0.155362, 1.137612, 0.385742, 0.467771, -0.162574, 1.133659, 0.383926, 0.494907,
+ -0.169312, 1.129246, 0.381715, 0.522801, -0.174778, 1.124228, 0.378678, 0.550751, -0.179824,
+ 1.118697, 0.375158, 0.578018, -0.184284, 1.112019, 0.370851, 0.605291, -0.188215, 1.105151,
+ 0.365928, 0.632269, -0.190760, 1.097677, 0.360114, 0.659432, -0.192457, 1.090816, 0.353498,
+ 0.685839, -0.193458, 1.083286, 0.346094, 0.711876, -0.193502, 1.076245, 0.337754, 0.738184,
+ -0.192371, 1.069684, 0.328412, 0.763723, -0.190531, 1.063249, 0.318164, 0.789192, -0.187726,
+ 1.057265, 0.306900, 0.813744, -0.183783, 1.051177, 0.295021, 0.838408, -0.179328, 1.045902,
+ 0.282144, 0.862116, -0.173573, 1.040853, 0.268438, 0.885636, -0.167350, 1.036515, 0.254108,
+ 0.909342, -0.160229, 1.033269, 0.239082, 0.931962, -0.152529, 1.029627, 0.224024, 0.954671,
+ -0.144080, 1.027507, 0.208393, 0.975707, -0.135023, 1.024657, 0.192630, 0.996644, -0.125258,
+ 1.022998, 0.176741, 1.015817, -0.115089, 1.021234, 0.160926, 1.034301, -0.104317, 1.020025,
+ 0.145042, 1.051131, -0.093218, 1.018739, 0.129052, 1.066836, -0.081828, 1.017419, 0.112905,
+ 1.081027, -0.070132, 1.015714, 0.096578, 1.093225, -0.058382, 1.013465, 0.080077, 1.103691,
+ -0.046527, 1.010853, 0.063580, 1.112431, -0.034624, 1.007702, 0.047118, 1.120035, -0.022913,
+ 1.004551, 0.031018, 1.127336, -0.011284, 1.001924, 0.015283, 1.134510, 0.000170, 0.999937,
+ -0.000058, 0.000200, -0.000084, 1.177044, 0.421534, 0.000504, -0.000212, 1.177312, 0.421533,
+ 0.002016, -0.000850, 1.177730, 0.421533, 0.004535, -0.001912, 1.177722, 0.421533, 0.008063,
+ -0.003399, 1.177844, 0.421529, 0.012598, -0.005310, 1.177768, 0.421533, 0.018141, -0.007646,
+ 1.177730, 0.421531, 0.024692, -0.010407, 1.177663, 0.421530, 0.032252, -0.013592, 1.177681,
+ 0.421527, 0.040821, -0.017201, 1.177562, 0.421524, 0.050401, -0.021234, 1.177445, 0.421516,
+ 0.060988, -0.025688, 1.177461, 0.421509, 0.072590, -0.030565, 1.177364, 0.421498, 0.085200,
+ -0.035860, 1.177205, 0.421482, 0.098823, -0.041572, 1.177011, 0.421462, 0.113465, -0.047694,
+ 1.176794, 0.421436, 0.129094, -0.054122, 1.176504, 0.421396, 0.145652, -0.060530, 1.176203,
+ 0.421311, 0.163245, -0.067517, 1.175805, 0.421218, 0.181825, -0.074919, 1.175271, 0.421108,
+ 0.201360, -0.082700, 1.174717, 0.420974, 0.221773, -0.090727, 1.174021, 0.420795, 0.242908,
+ -0.098719, 1.173173, 0.420536, 0.264742, -0.107417, 1.172285, 0.420296, 0.287091, -0.116601,
+ 1.171326, 0.420065, 0.310723, -0.125265, 1.169907, 0.419582, 0.335685, -0.133876, 1.168352,
+ 0.418912, 0.361285, -0.142140, 1.166322, 0.418006, 0.387562, -0.150436, 1.164136, 0.416899,
+ 0.414175, -0.158388, 1.161162, 0.415513, 0.441021, -0.166258, 1.157608, 0.413836, 0.467698,
+ -0.173720, 1.152519, 0.411702, 0.494730, -0.180843, 1.147020, 0.409102, 0.522524, -0.186906,
+ 1.141256, 0.405789, 0.550055, -0.192004, 1.134114, 0.401759, 0.577512, -0.196588, 1.127086,
+ 0.397153, 0.604348, -0.200420, 1.119029, 0.391767, 0.630970, -0.203320, 1.110308, 0.385573,
+ 0.658023, -0.204883, 1.102643, 0.378245, 0.684422, -0.205716, 1.094573, 0.370191, 0.710405,
+ -0.205767, 1.086405, 0.361231, 0.736417, -0.204513, 1.078712, 0.351106, 0.761836, -0.202281,
+ 1.071619, 0.340096, 0.787140, -0.199395, 1.064873, 0.328139, 0.812197, -0.195185, 1.058313,
+ 0.315044, 0.836342, -0.190191, 1.052085, 0.300933, 0.860311, -0.184343, 1.046705, 0.286411,
+ 0.883597, -0.177415, 1.041072, 0.270897, 0.906852, -0.170003, 1.036797, 0.254825, 0.929991,
+ -0.161592, 1.033264, 0.238176, 0.952478, -0.152792, 1.030250, 0.221581, 0.974216, -0.143032,
+ 1.027331, 0.204378, 0.995372, -0.132922, 1.025135, 0.187470, 1.015330, -0.122009, 1.023250,
+ 0.170538, 1.034070, -0.110740, 1.022021, 0.153777, 1.051295, -0.099016, 1.020271, 0.136916,
+ 1.067460, -0.086920, 1.018948, 0.119880, 1.082022, -0.074729, 1.017336, 0.102565, 1.094378,
+ -0.062036, 1.014820, 0.084994, 1.104998, -0.049413, 1.011999, 0.067650, 1.113773, -0.036812,
+ 1.008711, 0.050148, 1.121263, -0.024274, 1.005141, 0.032976, 1.128420, -0.012038, 1.002196,
+ 0.016239, 1.135496, 0.000106, 1.000042, -0.000062, 0.000200, -0.000090, 1.203048, 0.451217,
+ 0.000504, -0.000227, 1.203226, 0.451215, 0.002016, -0.000909, 1.203450, 0.451215, 0.004535,
+ -0.002046, 1.203569, 0.451215, 0.008062, -0.003638, 1.203609, 0.451209, 0.012598, -0.005684,
+ 1.203580, 0.451214, 0.018141, -0.008185, 1.203515, 0.451212, 0.024694, -0.011141, 1.203618,
+ 0.451211, 0.032253, -0.014549, 1.203609, 0.451207, 0.040815, -0.018409, 1.203302, 0.451203,
+ 0.050401, -0.022727, 1.203454, 0.451195, 0.060990, -0.027495, 1.203480, 0.451188, 0.072591,
+ -0.032713, 1.203220, 0.451172, 0.085203, -0.038378, 1.203058, 0.451154, 0.098829, -0.044489,
+ 1.202838, 0.451130, 0.113466, -0.051031, 1.202530, 0.451098, 0.129084, -0.057808, 1.202270,
+ 0.451041, 0.145669, -0.064769, 1.201904, 0.450956, 0.163278, -0.072278, 1.201411, 0.450853,
+ 0.181880, -0.080224, 1.200825, 0.450721, 0.201436, -0.088537, 1.200164, 0.450566, 0.221865,
+ -0.097009, 1.199335, 0.450351, 0.243083, -0.105591, 1.198383, 0.450062, 0.265033, -0.114818,
+ 1.197380, 0.449769, 0.287456, -0.124372, 1.196137, 0.449438, 0.310758, -0.133892, 1.194554,
+ 0.448974, 0.335721, -0.143052, 1.192649, 0.448216, 0.361348, -0.151868, 1.190233, 0.447202,
+ 0.387573, -0.160644, 1.187211, 0.445926, 0.414159, -0.169028, 1.183452, 0.444313, 0.440950,
+ -0.177169, 1.178562, 0.442315, 0.467998, -0.185090, 1.173540, 0.439960, 0.494566, -0.192396,
+ 1.166344, 0.436989, 0.521730, -0.198915, 1.159283, 0.433439, 0.549405, -0.204240, 1.151503,
+ 0.428984, 0.576755, -0.208861, 1.143004, 0.423839, 0.603635, -0.212734, 1.134099, 0.418012,
+ 0.629979, -0.215712, 1.124555, 0.411445, 0.656597, -0.217385, 1.115293, 0.403628, 0.683317,
+ -0.218093, 1.106460, 0.394639, 0.708990, -0.217835, 1.097389, 0.385012, 0.734898, -0.216774,
+ 1.088940, 0.373999, 0.760342, -0.214120, 1.080385, 0.362128, 0.785517, -0.210821, 1.072959,
+ 0.349184, 0.809933, -0.206443, 1.065450, 0.335080, 0.834339, -0.200942, 1.058701, 0.320257,
+ 0.858793, -0.194938, 1.052711, 0.304133, 0.882300, -0.187615, 1.047044, 0.287771, 0.905560,
+ -0.179626, 1.042083, 0.270571, 0.927916, -0.170753, 1.037077, 0.252741, 0.950415, -0.161270,
+ 1.033200, 0.234656, 0.972920, -0.151239, 1.030418, 0.216652, 0.993893, -0.140358, 1.027479,
+ 0.198252, 1.014204, -0.128963, 1.024897, 0.180113, 1.033878, -0.117128, 1.023648, 0.162282,
+ 1.051754, -0.104678, 1.022230, 0.144366, 1.067924, -0.092000, 1.020453, 0.126455, 1.082643,
+ -0.078837, 1.018518, 0.108194, 1.095503, -0.065669, 1.016199, 0.089966, 1.106290, -0.052345,
+ 1.013113, 0.071530, 1.115219, -0.039024, 1.009636, 0.053158, 1.122587, -0.025789, 1.005801,
+ 0.034959, 1.129461, -0.012622, 1.002442, 0.017222, 1.136468, 0.000152, 0.999964, -0.000065,
+ 0.000200, -0.000096, 1.231156, 0.481574, 0.000504, -0.000243, 1.232187, 0.481572, 0.002016,
+ -0.000971, 1.231948, 0.481572, 0.004535, -0.002184, 1.231919, 0.481572, 0.008061, -0.003882,
+ 1.231453, 0.481566, 0.012597, -0.006066, 1.231800, 0.481572, 0.018142, -0.008736, 1.231756,
+ 0.481569, 0.024693, -0.011889, 1.232062, 0.481570, 0.032254, -0.015528, 1.231915, 0.481563,
+ 0.040822, -0.019650, 1.231863, 0.481559, 0.050402, -0.024255, 1.231737, 0.481550, 0.060992,
+ -0.029342, 1.231678, 0.481537, 0.072592, -0.034908, 1.231537, 0.481521, 0.085207, -0.040953,
+ 1.231336, 0.481499, 0.098834, -0.047469, 1.231071, 0.481469, 0.113474, -0.054441, 1.230757,
+ 0.481431, 0.129077, -0.061556, 1.230424, 0.481359, 0.145691, -0.069091, 1.230022, 0.481269,
+ 0.163321, -0.077151, 1.229461, 0.481156, 0.181936, -0.085636, 1.228718, 0.481011, 0.201516,
+ -0.094484, 1.228023, 0.480830, 0.221963, -0.103362, 1.227057, 0.480562, 0.243264, -0.112628,
+ 1.225997, 0.480247, 0.265291, -0.122366, 1.224744, 0.479891, 0.287824, -0.132256, 1.223255,
+ 0.479461, 0.310927, -0.142614, 1.221348, 0.478978, 0.335749, -0.152326, 1.218953, 0.478132,
+ 0.361361, -0.161747, 1.215806, 0.476971, 0.387480, -0.170879, 1.211853, 0.475477, 0.414231,
+ -0.179865, 1.207783, 0.473686, 0.441065, -0.188331, 1.202051, 0.471415, 0.467923, -0.196454,
+ 1.195463, 0.468647, 0.494526, -0.204048, 1.187542, 0.465459, 0.521318, -0.211020, 1.179235,
+ 0.461650, 0.548654, -0.216520, 1.170110, 0.456868, 0.575778, -0.221098, 1.160163, 0.451227,
+ 0.602610, -0.224923, 1.149751, 0.444866, 0.628891, -0.227895, 1.139169, 0.437577, 0.655635,
+ -0.230020, 1.129736, 0.429369, 0.682115, -0.230419, 1.119516, 0.419673, 0.707514, -0.229789,
+ 1.108277, 0.409143, 0.733169, -0.228520, 1.099159, 0.397296, 0.758342, -0.225793, 1.089839,
+ 0.384578, 0.783477, -0.222049, 1.081428, 0.370323, 0.808497, -0.217562, 1.073742, 0.355253,
+ 0.832790, -0.211697, 1.065850, 0.339282, 0.856677, -0.204989, 1.058834, 0.322181, 0.880662,
+ -0.197653, 1.053291, 0.304610, 0.903474, -0.188858, 1.046822, 0.286042, 0.926313, -0.179746,
+ 1.041663, 0.267224, 0.948458, -0.169542, 1.036532, 0.247978, 0.970873, -0.159005, 1.033008,
+ 0.228535, 0.992958, -0.147658, 1.029844, 0.208819, 1.013413, -0.135771, 1.026930, 0.189486,
+ 1.033483, -0.123256, 1.025545, 0.170422, 1.051872, -0.110401, 1.023935, 0.152075, 1.068396,
+ -0.096860, 1.022092, 0.133169, 1.083731, -0.083259, 1.020221, 0.114022, 1.096849, -0.069266,
+ 1.017663, 0.094772, 1.107864, -0.055203, 1.014524, 0.075432, 1.116600, -0.041097, 1.010514,
+ 0.055980, 1.123871, -0.027083, 1.006313, 0.036839, 1.130718, -0.013510, 1.002778, 0.018156,
+ 1.137649, 0.000154, 1.000033, -0.000028, 0.000200, -0.000103, 1.264025, 0.512670, 0.000504,
+ -0.000258, 1.262437, 0.512667, 0.002016, -0.001033, 1.262691, 0.512668, 0.004535, -0.002325,
+ 1.262834, 0.512667, 0.008063, -0.004133, 1.262783, 0.512659, 0.012598, -0.006458, 1.262803,
+ 0.512666, 0.018141, -0.009299, 1.262720, 0.512665, 0.024683, -0.012652, 1.262061, 0.512655,
+ 0.032257, -0.016532, 1.262858, 0.512656, 0.040826, -0.020919, 1.262709, 0.512649, 0.050403,
+ -0.025820, 1.262685, 0.512639, 0.060993, -0.031233, 1.262544, 0.512625, 0.072597, -0.037157,
+ 1.262435, 0.512607, 0.085211, -0.043587, 1.262209, 0.512581, 0.098842, -0.050520, 1.261907,
+ 0.512544, 0.113484, -0.057926, 1.261575, 0.512500, 0.129097, -0.065460, 1.261293, 0.512420,
+ 0.145727, -0.073543, 1.260736, 0.512316, 0.163375, -0.082134, 1.260117, 0.512190, 0.182011,
+ -0.091173, 1.259299, 0.512024, 0.201598, -0.100540, 1.258381, 0.511810, 0.222084, -0.109931,
+ 1.257293, 0.511505, 0.243446, -0.119838, 1.256050, 0.511151, 0.265574, -0.130090, 1.254607,
+ 0.510724, 0.288230, -0.140421, 1.252808, 0.510191, 0.311336, -0.151343, 1.250489, 0.509627,
+ 0.335719, -0.161689, 1.247279, 0.508688, 0.361314, -0.171748, 1.243467, 0.507393, 0.387541,
+ -0.181399, 1.239145, 0.505758, 0.414204, -0.190768, 1.233760, 0.503676, 0.441092, -0.199659,
+ 1.227433, 0.501129, 0.467789, -0.207934, 1.219247, 0.498078, 0.494454, -0.215747, 1.210441,
+ 0.494630, 0.520950, -0.222869, 1.200559, 0.490467, 0.547802, -0.228881, 1.189872, 0.485444,
+ 0.575563, -0.233760, 1.180081, 0.479268, 0.602426, -0.237566, 1.168544, 0.472272, 0.628772,
+ -0.240447, 1.156546, 0.464390, 0.654963, -0.242427, 1.145123, 0.455345, 0.681384, -0.242980,
+ 1.134322, 0.444885, 0.707173, -0.242150, 1.122665, 0.433338, 0.732477, -0.240435, 1.111733,
+ 0.420647, 0.757567, -0.237806, 1.101271, 0.406799, 0.782341, -0.233503, 1.091341, 0.391761,
+ 0.806690, -0.228346, 1.082042, 0.375576, 0.830804, -0.222386, 1.073504, 0.358545, 0.854940,
+ -0.215141, 1.065880, 0.340431, 0.878709, -0.207207, 1.058850, 0.321690, 0.901928, -0.198273,
+ 1.052588, 0.301930, 0.924845, -0.188476, 1.046521, 0.281513, 0.946932, -0.177996, 1.040966,
+ 0.261234, 0.969256, -0.166644, 1.036670, 0.240356, 0.991323, -0.154968, 1.032694, 0.219748,
+ 1.013013, -0.142425, 1.030061, 0.199103, 1.032845, -0.129456, 1.027254, 0.178936, 1.051887,
+ -0.115763, 1.025497, 0.159243, 1.069179, -0.101851, 1.023807, 0.139560, 1.084499, -0.087357,
+ 1.021441, 0.119607, 1.097921, -0.072796, 1.018780, 0.099501, 1.109281, -0.058037, 1.015566,
+ 0.079211, 1.118194, -0.043226, 1.011494, 0.058873, 1.125351, -0.028633, 1.007089, 0.038736,
+ 1.132002, -0.013996, 1.003014, 0.019063, 1.138951, 0.000132, 1.000036, -0.000007, 0.000200,
+ -0.000109, 1.296791, 0.544571, 0.000504, -0.000274, 1.296055, 0.544568, 0.002016, -0.001098,
+ 1.297239, 0.544568, 0.004535, -0.002470, 1.296600, 0.544568, 0.008062, -0.004390, 1.296368,
+ 0.544559, 0.012597, -0.006860, 1.296454, 0.544566, 0.018141, -0.009878, 1.296522, 0.544565,
+ 0.024693, -0.013444, 1.296536, 0.544560, 0.032256, -0.017559, 1.296638, 0.544557, 0.040824,
+ -0.022218, 1.296491, 0.544547, 0.050408, -0.027426, 1.296552, 0.544532, 0.060997, -0.033173,
+ 1.296283, 0.544518, 0.072600, -0.039463, 1.296113, 0.544496, 0.085220, -0.046292, 1.295894,
+ 0.544466, 0.098851, -0.053648, 1.295545, 0.544422, 0.113496, -0.061487, 1.295201, 0.544371,
+ 0.129112, -0.069467, 1.294754, 0.544273, 0.145765, -0.078092, 1.294209, 0.544160, 0.163431,
+ -0.087231, 1.293534, 0.544017, 0.182088, -0.096837, 1.292580, 0.543828, 0.201698, -0.106713,
+ 1.291586, 0.543585, 0.222231, -0.116699, 1.290325, 0.543238, 0.243653, -0.127208, 1.288888,
+ 0.542836, 0.265855, -0.137949, 1.287131, 0.542329, 0.288623, -0.148847, 1.284936, 0.541700,
+ 0.311830, -0.160204, 1.282109, 0.540997, 0.335728, -0.171324, 1.278036, 0.540045, 0.361403,
+ -0.181915, 1.273912, 0.538603, 0.387647, -0.192124, 1.268881, 0.536741, 0.414217, -0.201807,
+ 1.262363, 0.534432, 0.441090, -0.211093, 1.254755, 0.531623, 0.467823, -0.219678, 1.245456,
+ 0.528314, 0.494361, -0.227581, 1.234953, 0.524391, 0.521264, -0.235087, 1.224839, 0.519902,
+ 0.547881, -0.241508, 1.213175, 0.514574, 0.574965, -0.246315, 1.200505, 0.507837, 0.601847,
+ -0.250061, 1.187901, 0.500286, 0.628207, -0.252822, 1.174601, 0.491502, 0.654445, -0.254691,
+ 1.161944, 0.481726, 0.680175, -0.255318, 1.149305, 0.470727, 0.706168, -0.254257, 1.136708,
+ 0.458045, 0.731458, -0.252100, 1.124047, 0.444438, 0.756378, -0.249115, 1.112942, 0.429611,
+ 0.781311, -0.244899, 1.101800, 0.413501, 0.805755, -0.239225, 1.091662, 0.395889, 0.829867,
+ -0.232830, 1.082291, 0.377860, 0.853067, -0.225193, 1.072820, 0.358704, 0.877084, -0.216648,
+ 1.065415, 0.338413, 0.900123, -0.207390, 1.058403, 0.317596, 0.923370, -0.197095, 1.051412,
+ 0.296301, 0.946021, -0.186084, 1.045877, 0.274498, 0.967669, -0.174262, 1.040316, 0.252565,
+ 0.989761, -0.161814, 1.035489, 0.230312, 1.012163, -0.149076, 1.032540, 0.208746, 1.032547,
+ -0.135299, 1.029598, 0.187180, 1.052032, -0.121277, 1.027355, 0.166482, 1.069907, -0.106582,
+ 1.025622, 0.145939, 1.085563, -0.091589, 1.023244, 0.125362, 1.099447, -0.076263, 1.020661,
+ 0.104087, 1.110848, -0.060825, 1.017035, 0.083036, 1.119923, -0.045319, 1.012675, 0.061719,
+ 1.126805, -0.029852, 1.007668, 0.040583, 1.133282, -0.014846, 1.003335, 0.019969, 1.140128,
+ 0.000149, 1.000024, -0.000037, 0.000200, -0.000116, 1.334863, 0.577350, 0.000504, -0.000291,
+ 1.333350, 0.577348, 0.002015, -0.001164, 1.332853, 0.577347, 0.004535, -0.002618, 1.333295,
+ 0.577347, 0.008062, -0.004655, 1.333189, 0.577336, 0.012598, -0.007273, 1.333309, 0.577345,
+ 0.018141, -0.010472, 1.333274, 0.577342, 0.024694, -0.014253, 1.333231, 0.577339, 0.032254,
+ -0.018614, 1.333265, 0.577332, 0.040827, -0.023556, 1.333261, 0.577321, 0.050400, -0.029069,
+ 1.332893, 0.577309, 0.061000, -0.035166, 1.332998, 0.577288, 0.072608, -0.041833, 1.332901,
+ 0.577263, 0.085227, -0.049067, 1.332603, 0.577226, 0.098864, -0.056860, 1.332264, 0.577177,
+ 0.113507, -0.065114, 1.331825, 0.577109, 0.129146, -0.073610, 1.331311, 0.577005, 0.145808,
+ -0.082766, 1.330639, 0.576872, 0.163494, -0.092458, 1.329878, 0.576709, 0.182176, -0.102639,
+ 1.328889, 0.576501, 0.201804, -0.112983, 1.327710, 0.576207, 0.222394, -0.123650, 1.326256,
+ 0.575823, 0.243881, -0.134780, 1.324593, 0.575363, 0.266122, -0.145931, 1.322426, 0.574751,
+ 0.289043, -0.157500, 1.319837, 0.574033, 0.312330, -0.169208, 1.316301, 0.573181, 0.336120,
+ -0.181125, 1.312251, 0.572188, 0.361506, -0.192232, 1.307003, 0.570631, 0.387757, -0.202981,
+ 1.301068, 0.568558, 0.414365, -0.213160, 1.293695, 0.566027, 0.440986, -0.222617, 1.283958,
+ 0.562942, 0.467943, -0.231583, 1.274057, 0.559219, 0.494821, -0.239881, 1.262864, 0.554913,
+ 0.521486, -0.247336, 1.250633, 0.549953, 0.547884, -0.253921, 1.237448, 0.544251, 0.574582,
+ -0.259099, 1.223164, 0.537120, 0.601342, -0.262695, 1.208784, 0.528650, 0.627861, -0.265337,
+ 1.194424, 0.518978, 0.653745, -0.266872, 1.179361, 0.508525, 0.679348, -0.267403, 1.165010,
+ 0.496705, 0.705068, -0.266429, 1.151693, 0.482926, 0.730312, -0.263829, 1.137584, 0.468519,
+ 0.755576, -0.260491, 1.125328, 0.452213, 0.780371, -0.256166, 1.113759, 0.435127, 0.804632,
+ -0.250079, 1.101656, 0.416833, 0.828983, -0.243181, 1.091235, 0.397009, 0.852585, -0.235383,
+ 1.081475, 0.376647, 0.875237, -0.226031, 1.071806, 0.355506, 0.899152, -0.216343, 1.064453,
+ 0.333133, 0.922121, -0.205772, 1.057161, 0.311073, 0.944523, -0.193980, 1.050447, 0.287781,
+ 0.967313, -0.181920, 1.044531, 0.264350, 0.989042, -0.168822, 1.039312, 0.241128, 1.010881,
+ -0.155350, 1.035298, 0.218138, 1.032368, -0.141231, 1.032073, 0.195579, 1.052254, -0.126521,
+ 1.029395, 0.173399, 1.070207, -0.111243, 1.026938, 0.151866, 1.086528, -0.095617, 1.024957,
+ 0.130711, 1.100670, -0.079687, 1.021924, 0.108865, 1.112461, -0.063593, 1.018281, 0.086760,
+ 1.121588, -0.047313, 1.013747, 0.064575, 1.128522, -0.031385, 1.008433, 0.042499, 1.134759,
+ -0.015356, 1.003569, 0.020840, 1.141448, 0.000114, 0.999978, -0.000056, 0.000200, -0.000122,
+ 1.372763, 0.611086, 0.000503, -0.000308, 1.371456, 0.611084, 0.002016, -0.001232, 1.373440,
+ 0.611084, 0.004535, -0.002771, 1.373387, 0.611083, 0.008061, -0.004926, 1.372916, 0.611083,
+ 0.012601, -0.007700, 1.373956, 0.611084, 0.018142, -0.011084, 1.373419, 0.611078, 0.024695,
+ -0.015087, 1.373492, 0.611074, 0.032255, -0.019701, 1.373360, 0.611066, 0.040827, -0.024930,
+ 1.373327, 0.611055, 0.050408, -0.030769, 1.373222, 0.611037, 0.061004, -0.037217, 1.373079,
+ 0.611014, 0.072613, -0.044270, 1.372895, 0.610982, 0.085238, -0.051923, 1.372624, 0.610941,
+ 0.098878, -0.060161, 1.372252, 0.610883, 0.113522, -0.068785, 1.371785, 0.610798, 0.129176,
+ -0.077863, 1.371103, 0.610683, 0.145876, -0.087593, 1.370541, 0.610537, 0.163570, -0.097847,
+ 1.369496, 0.610349, 0.182283, -0.108592, 1.368477, 0.610109, 0.201930, -0.119420, 1.366980,
+ 0.609763, 0.222570, -0.130789, 1.365375, 0.609343, 0.244123, -0.142514, 1.363456, 0.608815,
+ 0.266437, -0.154232, 1.360916, 0.608114, 0.289467, -0.166370, 1.357909, 0.607291, 0.312861,
+ -0.178505, 1.353588, 0.606272, 0.336736, -0.190980, 1.349211, 0.605153, 0.361740, -0.202859,
+ 1.343319, 0.603548, 0.387878, -0.213997, 1.335908, 0.601268, 0.414357, -0.224584, 1.326676,
+ 0.598499, 0.441442, -0.234664, 1.317331, 0.595066, 0.468409, -0.243875, 1.305818, 0.590996,
+ 0.494999, -0.252121, 1.291863, 0.586293, 0.521730, -0.259714, 1.278212, 0.580840, 0.547894,
+ -0.266242, 1.262656, 0.574494, 0.573865, -0.271578, 1.246364, 0.567007, 0.601124, -0.275503,
+ 1.231274, 0.557771, 0.627606, -0.277954, 1.215252, 0.547255, 0.654004, -0.279404, 1.199977,
+ 0.535766, 0.679554, -0.279632, 1.183995, 0.522792, 0.704280, -0.278457, 1.167428, 0.508488,
+ 0.729830, -0.275706, 1.152760, 0.492425, 0.754376, -0.271640, 1.137942, 0.475285, 0.779209,
+ -0.266911, 1.125222, 0.456679, 0.803562, -0.260838, 1.112179, 0.437267, 0.827985, -0.253353,
+ 1.101439, 0.416227, 0.851737, -0.245027, 1.089890, 0.394728, 0.874850, -0.235719, 1.080018,
+ 0.372244, 0.897680, -0.225051, 1.070807, 0.348846, 0.921351, -0.214051, 1.063180, 0.324961,
+ 0.943818, -0.202039, 1.056148, 0.300836, 0.966368, -0.189134, 1.049277, 0.276333, 0.987426,
+ -0.175613, 1.042176, 0.251862, 1.010162, -0.161473, 1.038567, 0.227217, 1.031224, -0.146866,
+ 1.034102, 0.203582, 1.052317, -0.131644, 1.031600, 0.180629, 1.070879, -0.115909, 1.028913,
+ 0.158165, 1.087407, -0.099638, 1.026193, 0.135905, 1.102159, -0.083091, 1.023567, 0.113394,
+ 1.114006, -0.066178, 1.019567, 0.090325, 1.123374, -0.049430, 1.014856, 0.067302, 1.130310,
+ -0.032557, 1.009141, 0.044264, 1.136334, -0.016157, 1.003984, 0.021807, 1.142961, 0.000172,
+ 0.999951, -0.000077, 0.000200, -0.000129, 1.416584, 0.645866, 0.000504, -0.000326, 1.417762,
+ 0.645865, 0.002016, -0.001302, 1.417825, 0.645866, 0.004535, -0.002929, 1.417142, 0.645865,
+ 0.008062, -0.005207, 1.416968, 0.645864, 0.012598, -0.008136, 1.417109, 0.645862, 0.018141,
+ -0.011715, 1.417001, 0.645859, 0.024690, -0.015941, 1.416878, 0.645853, 0.032257, -0.020823,
+ 1.417134, 0.645843, 0.040827, -0.026347, 1.416983, 0.645829, 0.050411, -0.032518, 1.416949,
+ 0.645808, 0.061007, -0.039330, 1.416694, 0.645781, 0.072621, -0.046783, 1.416599, 0.645746,
+ 0.085249, -0.054865, 1.416241, 0.645695, 0.098897, -0.063563, 1.415832, 0.645630, 0.113546,
+ -0.072607, 1.415264, 0.645529, 0.129220, -0.082257, 1.414482, 0.645396, 0.145888, -0.092515,
+ 1.413626, 0.645268, 0.163659, -0.103393, 1.412710, 0.645018, 0.182385, -0.114684, 1.411418,
+ 0.644739, 0.202078, -0.126098, 1.409822, 0.644348, 0.222772, -0.138145, 1.407948, 0.643872,
+ 0.244370, -0.150405, 1.405678, 0.643255, 0.266787, -0.162798, 1.402763, 0.642463, 0.289844,
+ -0.175434, 1.398863, 0.641504, 0.313540, -0.188158, 1.394695, 0.640346, 0.337489, -0.201014,
+ 1.389376, 0.639042, 0.362008, -0.213719, 1.382439, 0.637412, 0.387990, -0.225248, 1.373281,
+ 0.634930, 0.414728, -0.236348, 1.363729, 0.631861, 0.441635, -0.246701, 1.352304, 0.628155,
+ 0.468588, -0.256167, 1.339162, 0.623625, 0.495337, -0.264662, 1.323811, 0.618458, 0.521886,
+ -0.272207, 1.307630, 0.612373, 0.548355, -0.278890, 1.291265, 0.605263, 0.574535, -0.284442,
+ 1.273752, 0.597048, 0.600870, -0.288389, 1.256171, 0.587401, 0.627715, -0.290816, 1.238447,
+ 0.576001, 0.653830, -0.291886, 1.221036, 0.563198, 0.679175, -0.291629, 1.202283, 0.549249,
+ 0.704539, -0.290489, 1.185866, 0.533881, 0.729126, -0.287529, 1.168822, 0.516966, 0.754297,
+ -0.283184, 1.152934, 0.498501, 0.778678, -0.277732, 1.137821, 0.478728, 0.802473, -0.271203,
+ 1.123387, 0.457814, 0.826596, -0.263494, 1.110573, 0.435865, 0.850835, -0.254572, 1.099099,
+ 0.412597, 0.874203, -0.244815, 1.088403, 0.388995, 0.897271, -0.233993, 1.078085, 0.364487,
+ 0.919667, -0.221934, 1.068543, 0.339344, 0.943001, -0.209714, 1.061081, 0.313770, 0.965688,
+ -0.196367, 1.054023, 0.287928, 0.987598, -0.182263, 1.047247, 0.262157, 1.009280, -0.167775,
+ 1.041376, 0.236855, 1.031762, -0.152530, 1.037647, 0.211847, 1.051965, -0.136809, 1.033396,
+ 0.187546, 1.071699, -0.120418, 1.031021, 0.164186, 1.088881, -0.103618, 1.028403, 0.141184,
+ 1.103482, -0.086271, 1.024987, 0.117665, 1.115646, -0.068973, 1.020884, 0.093896, 1.125258,
+ -0.051285, 1.015966, 0.069978, 1.132045, -0.033998, 1.009990, 0.046126, 1.138004, -0.016696,
+ 1.004270, 0.022635, 1.144463, 0.000089, 0.999987, -0.000016, 0.000200, -0.000136, 1.463614,
+ 0.681786, 0.000504, -0.000344, 1.465345, 0.681785, 0.002015, -0.001374, 1.464172, 0.681783,
+ 0.004535, -0.003092, 1.464846, 0.681784, 0.008062, -0.005496, 1.464783, 0.681784, 0.012598,
+ -0.008588, 1.464883, 0.681781, 0.018141, -0.012366, 1.464740, 0.681777, 0.024692, -0.016829,
+ 1.464665, 0.681770, 0.032258, -0.021980, 1.464720, 0.681760, 0.040829, -0.027811, 1.464625,
+ 0.681742, 0.050415, -0.034324, 1.464571, 0.681720, 0.061013, -0.041513, 1.464346, 0.681688,
+ 0.072628, -0.049375, 1.464131, 0.681644, 0.085264, -0.057903, 1.463847, 0.681588, 0.098918,
+ -0.067067, 1.463369, 0.681509, 0.113568, -0.076570, 1.462549, 0.681389, 0.129265, -0.086782,
+ 1.461703, 0.681239, 0.145997, -0.097637, 1.460840, 0.681047, 0.163751, -0.109101, 1.459737,
+ 0.680806, 0.182505, -0.120922, 1.458231, 0.680480, 0.202241, -0.133007, 1.456393, 0.680042,
+ 0.222987, -0.145693, 1.454258, 0.679503, 0.244638, -0.158488, 1.451543, 0.678792, 0.267132,
+ -0.171585, 1.448115, 0.677907, 0.290365, -0.184746, 1.443992, 0.676796, 0.314178, -0.198101,
+ 1.439271, 0.675498, 0.338289, -0.211370, 1.432830, 0.673922, 0.362543, -0.224489, 1.424163,
+ 0.672151, 0.388470, -0.236914, 1.415160, 0.669601, 0.415105, -0.248342, 1.403811, 0.666255,
+ 0.441925, -0.258957, 1.390149, 0.662166, 0.468668, -0.268556, 1.374104, 0.657229, 0.495720,
+ -0.277359, 1.358102, 0.651347, 0.522574, -0.285078, 1.340754, 0.644598, 0.548981, -0.291718,
+ 1.322033, 0.636820, 0.574946, -0.297087, 1.302148, 0.627812, 0.600744, -0.301079, 1.282130,
+ 0.617485, 0.627565, -0.303566, 1.263339, 0.605047, 0.653598, -0.304330, 1.242712, 0.591167,
+ 0.679239, -0.303820, 1.223212, 0.576025, 0.704043, -0.302064, 1.203763, 0.559649, 0.728796,
+ -0.299095, 1.185434, 0.541271, 0.753581, -0.294392, 1.167630, 0.521800, 0.778577, -0.288603,
+ 1.151930, 0.500628, 0.802550, -0.281604, 1.136072, 0.478434, 0.825803, -0.273472, 1.121673,
+ 0.455384, 0.849768, -0.264011, 1.108491, 0.430811, 0.873250, -0.253653, 1.096550, 0.405524,
+ 0.896725, -0.242642, 1.085905, 0.380038, 0.919158, -0.230191, 1.075091, 0.353482, 0.942236,
+ -0.217145, 1.066848, 0.326605, 0.965031, -0.203555, 1.059310, 0.299842, 0.987048, -0.188777,
+ 1.051749, 0.272859, 1.008718, -0.173613, 1.044999, 0.246040, 1.031097, -0.157972, 1.040066,
+ 0.219826, 1.052493, -0.141589, 1.035951, 0.194278, 1.071773, -0.124814, 1.032520, 0.169830,
+ 1.089646, -0.107321, 1.029803, 0.146135, 1.104932, -0.089726, 1.026612, 0.122127, 1.117687,
+ -0.071433, 1.022391, 0.097461, 1.127188, -0.053395, 1.017113, 0.072556, 1.134010, -0.035151,
+ 1.010934, 0.047749, 1.139746, -0.017427, 1.004633, 0.023530, 1.146205, 0.000151, 1.000020,
+ -0.000106, 0.000200, -0.000144, 1.517643, 0.718949, 0.000504, -0.000362, 1.516387, 0.718947,
+ 0.002016, -0.001449, 1.516742, 0.718946, 0.004536, -0.003261, 1.517196, 0.718946, 0.008063,
+ -0.005796, 1.516806, 0.718945, 0.012598, -0.009057, 1.516986, 0.718943, 0.018140, -0.013039,
+ 1.516603, 0.718937, 0.024694, -0.017747, 1.516739, 0.718929, 0.032260, -0.023178, 1.516994,
+ 0.718917, 0.040831, -0.029325, 1.516649, 0.718896, 0.050419, -0.036192, 1.516594, 0.718870,
+ 0.061019, -0.043770, 1.516327, 0.718833, 0.072638, -0.052056, 1.516054, 0.718782, 0.085274,
+ -0.061039, 1.515628, 0.718714, 0.098938, -0.070676, 1.515199, 0.718623, 0.113607, -0.080679,
+ 1.514222, 0.718483, 0.129329, -0.091485, 1.513354, 0.718316, 0.146077, -0.102931, 1.512301,
+ 0.718096, 0.163856, -0.114986, 1.510977, 0.717818, 0.182640, -0.127305, 1.509225, 0.717432,
+ 0.202432, -0.140147, 1.507152, 0.716939, 0.223229, -0.153468, 1.504780, 0.716331, 0.244943,
+ -0.166875, 1.501612, 0.715527, 0.267559, -0.180658, 1.497898, 0.714523, 0.290926, -0.194405,
+ 1.493208, 0.713266, 0.314863, -0.208302, 1.487388, 0.711758, 0.339053, -0.222020, 1.479677,
+ 0.709982, 0.363627, -0.235683, 1.470950, 0.707958, 0.388887, -0.248723, 1.459907, 0.705346,
+ 0.415474, -0.260563, 1.446579, 0.701644, 0.442065, -0.271352, 1.429962, 0.697134, 0.469418,
+ -0.281541, 1.414343, 0.691665, 0.496419, -0.290429, 1.395681, 0.685227, 0.523071, -0.298032,
+ 1.375347, 0.677815, 0.549641, -0.304679, 1.354816, 0.669063, 0.575489, -0.309902, 1.332505,
+ 0.659071, 0.601108, -0.313771, 1.309752, 0.647799, 0.627199, -0.316225, 1.288381, 0.634856,
+ 0.653243, -0.316679, 1.265785, 0.619627, 0.678960, -0.315816, 1.244333, 0.603244, 0.704055,
+ -0.313776, 1.223315, 0.585191, 0.728713, -0.310417, 1.203142, 0.565969, 0.753301, -0.305786,
+ 1.184323, 0.545347, 0.777890, -0.299262, 1.166070, 0.522753, 0.802354, -0.291830, 1.149599,
+ 0.499017, 0.826005, -0.283281, 1.133655, 0.474335, 0.848920, -0.273512, 1.118132, 0.449019,
+ 0.872765, -0.262525, 1.105606, 0.422329, 0.895950, -0.250769, 1.093539, 0.395057, 0.918816,
+ -0.238257, 1.082388, 0.367709, 0.941089, -0.224381, 1.072484, 0.339350, 0.964514, -0.210289,
+ 1.064054, 0.311239, 0.987128, -0.195488, 1.056645, 0.283272, 1.009064, -0.179491, 1.049549,
+ 0.255163, 1.030163, -0.163172, 1.042741, 0.227757, 1.052502, -0.146457, 1.038270, 0.200970,
+ 1.072971, -0.129054, 1.035014, 0.175767, 1.091223, -0.111285, 1.032231, 0.151118, 1.106518,
+ -0.092617, 1.028211, 0.126196, 1.119235, -0.074168, 1.023686, 0.100828, 1.129311, -0.055212,
+ 1.018311, 0.075240, 1.135983, -0.036571, 1.011485, 0.049558, 1.141648, -0.017954, 1.004952,
+ 0.024273, 1.147938, 0.000125, 1.000009, -0.000048, 0.000199, -0.000151, 1.566887, 0.757466,
+ 0.000504, -0.000382, 1.574111, 0.757466, 0.002016, -0.001527, 1.573735, 0.757466, 0.004535,
+ -0.003435, 1.573737, 0.757466, 0.008062, -0.006107, 1.573782, 0.757464, 0.012599, -0.009542,
+ 1.573796, 0.757460, 0.018142, -0.013739, 1.573710, 0.757455, 0.024694, -0.018697, 1.573562,
+ 0.757446, 0.032259, -0.024418, 1.573667, 0.757429, 0.040834, -0.030895, 1.573555, 0.757407,
+ 0.050422, -0.038127, 1.573383, 0.757376, 0.061025, -0.046108, 1.573086, 0.757332, 0.072650,
+ -0.054835, 1.572833, 0.757274, 0.085296, -0.064294, 1.572395, 0.757195, 0.098962, -0.074376,
+ 1.571729, 0.757087, 0.113649, -0.084955, 1.570571, 0.756925, 0.129389, -0.096334, 1.569582,
+ 0.756729, 0.146167, -0.108406, 1.568444, 0.756481, 0.163973, -0.121056, 1.566905, 0.756158,
+ 0.182798, -0.133970, 1.564939, 0.755715, 0.202650, -0.147522, 1.562666, 0.755167, 0.223502,
+ -0.161466, 1.559877, 0.754465, 0.245269, -0.175539, 1.556008, 0.753552, 0.268010, -0.189957,
+ 1.552013, 0.752420, 0.291474, -0.204361, 1.546509, 0.751008, 0.315527, -0.218714, 1.539575,
+ 0.749266, 0.339954, -0.233029, 1.530968, 0.747232, 0.364649, -0.247149, 1.520994, 0.744906,
+ 0.389520, -0.260672, 1.507748, 0.742123, 0.415717, -0.272873, 1.491777, 0.738187, 0.442862,
+ -0.284317, 1.475658, 0.733189, 0.469939, -0.294552, 1.456572, 0.727165, 0.496916, -0.303517,
+ 1.435237, 0.720043, 0.523480, -0.311061, 1.412192, 0.711640, 0.550092, -0.317596, 1.389033,
+ 0.702174, 0.576384, -0.322921, 1.365086, 0.691225, 0.602280, -0.326806, 1.341317, 0.678841,
+ 0.627676, -0.329057, 1.316518, 0.664815, 0.653458, -0.329372, 1.291877, 0.648548, 0.679227,
+ -0.328067, 1.268126, 0.630676, 0.704476, -0.325585, 1.244424, 0.611585, 0.729232, -0.321775,
+ 1.223010, 0.590803, 0.753405, -0.316713, 1.201297, 0.568653, 0.777274, -0.309858, 1.181071,
+ 0.544763, 0.801882, -0.301866, 1.162826, 0.519747, 0.826030, -0.292861, 1.145704, 0.493531,
+ 0.849359, -0.282794, 1.129629, 0.466900, 0.871837, -0.271197, 1.114155, 0.439230, 0.895896,
+ -0.258954, 1.102334, 0.410570, 0.918951, -0.245878, 1.090163, 0.381314, 0.941148, -0.231897,
+ 1.078738, 0.352268, 0.963464, -0.216743, 1.068862, 0.322688, 0.986628, -0.201486, 1.061077,
+ 0.293523, 1.009289, -0.185521, 1.053561, 0.264125, 1.030659, -0.168429, 1.046627, 0.235706,
+ 1.052382, -0.151210, 1.040953, 0.208022, 1.073476, -0.133289, 1.036534, 0.181245, 1.092237,
+ -0.114768, 1.033580, 0.155661, 1.108200, -0.095917, 1.029997, 0.130223, 1.121435, -0.076492,
+ 1.025374, 0.104098, 1.131382, -0.057204, 1.019485, 0.077776, 1.137994, -0.037747, 1.012188,
+ 0.051250, 1.143441, -0.018673, 1.005309, 0.025245, 1.149714, 0.000216, 1.000004, -0.000120,
+ 0.000200, -0.000159, 1.633988, 0.797469, 0.000504, -0.000402, 1.636076, 0.797469, 0.002016,
+ -0.001607, 1.635679, 0.797467, 0.004535, -0.003617, 1.636040, 0.797468, 0.008063, -0.006430,
+ 1.636159, 0.797467, 0.012599, -0.010046, 1.636128, 0.797462, 0.018141, -0.014464, 1.635730,
+ 0.797457, 0.024696, -0.019685, 1.635836, 0.797445, 0.032259, -0.025705, 1.635719, 0.797426,
+ 0.040835, -0.032523, 1.635610, 0.797401, 0.050425, -0.040135, 1.635460, 0.797363, 0.061033,
+ -0.048536, 1.635182, 0.797313, 0.072661, -0.057718, 1.634817, 0.797243, 0.085315, -0.067666,
+ 1.634314, 0.797150, 0.098985, -0.078179, 1.633350, 0.797016, 0.113699, -0.089383, 1.632253,
+ 0.796839, 0.129456, -0.101364, 1.631025, 0.796623, 0.146275, -0.114081, 1.629867, 0.796331,
+ 0.164108, -0.127318, 1.628043, 0.795956, 0.182983, -0.140901, 1.625813, 0.795458, 0.202891,
+ -0.155174, 1.623149, 0.794834, 0.223787, -0.169654, 1.619686, 0.794015, 0.245678, -0.184540,
+ 1.615694, 0.793013, 0.268495, -0.199543, 1.610812, 0.791727, 0.292093, -0.214639, 1.604629,
+ 0.790107, 0.316184, -0.229499, 1.596061, 0.788154, 0.340986, -0.244407, 1.587195, 0.785797,
+ 0.365808, -0.258907, 1.575031, 0.783093, 0.390528, -0.272746, 1.559448, 0.779970, 0.416510,
+ -0.285845, 1.543294, 0.775852, 0.443443, -0.297404, 1.523476, 0.770323, 0.470442, -0.307757,
+ 1.501515, 0.763721, 0.497499, -0.316846, 1.477841, 0.755889, 0.524316, -0.324561, 1.452427,
+ 0.746662, 0.551212, -0.331060, 1.427421, 0.736004, 0.577323, -0.335956, 1.400369, 0.723810,
+ 0.602976, -0.339501, 1.373093, 0.710184, 0.628357, -0.341577, 1.345853, 0.695017, 0.653642,
+ -0.342031, 1.319040, 0.677972, 0.679440, -0.340342, 1.292490, 0.658877, 0.704744, -0.337356,
+ 1.267182, 0.638085, 0.729692, -0.333042, 1.243280, 0.615615, 0.753920, -0.327504, 1.219751,
+ 0.592054, 0.777695, -0.320537, 1.197796, 0.566967, 0.801426, -0.311880, 1.176872, 0.540643,
+ 0.825649, -0.302211, 1.158160, 0.512906, 0.849282, -0.291665, 1.141257, 0.484587, 0.872341,
+ -0.280050, 1.125469, 0.455556, 0.895110, -0.266978, 1.110222, 0.425652, 0.918841, -0.253326,
+ 1.097419, 0.395015, 0.941209, -0.238899, 1.086101, 0.364948, 0.963142, -0.223523, 1.075023,
+ 0.334151, 0.985996, -0.207346, 1.065628, 0.303708, 1.008718, -0.190889, 1.057256, 0.273008,
+ 1.030554, -0.173517, 1.049720, 0.243221, 1.053085, -0.155645, 1.043837, 0.214426, 1.074267,
+ -0.137472, 1.039312, 0.187036, 1.093591, -0.118385, 1.035457, 0.160512, 1.109850, -0.098883,
+ 1.031630, 0.134384, 1.123516, -0.079050, 1.026762, 0.107424, 1.133578, -0.058977, 1.020640,
+ 0.080317, 1.140289, -0.039013, 1.013096, 0.052944, 1.145610, -0.019228, 1.005694, 0.025989,
+ 1.151704, 0.000105, 0.999981, -0.000019, 0.000200, -0.000168, 1.704841, 0.839096, 0.000504,
+ -0.000423, 1.704242, 0.839097, 0.002016, -0.001691, 1.703821, 0.839091, 0.004534, -0.003805,
+ 1.703804, 0.839094, 0.008063, -0.006765, 1.704224, 0.839092, 0.012598, -0.010570, 1.704013,
+ 0.839087, 0.018142, -0.015219, 1.703889, 0.839079, 0.024697, -0.020712, 1.704023, 0.839066,
+ 0.032261, -0.027046, 1.703836, 0.839045, 0.040837, -0.034218, 1.703608, 0.839014, 0.050429,
+ -0.042224, 1.703414, 0.838972, 0.061041, -0.051061, 1.703148, 0.838912, 0.072676, -0.060717,
+ 1.702744, 0.838831, 0.085340, -0.071175, 1.702223, 0.838724, 0.099023, -0.082182, 1.700984,
+ 0.838567, 0.113759, -0.094007, 1.699764, 0.838367, 0.129546, -0.106621, 1.698462, 0.838112,
+ 0.146382, -0.119956, 1.696938, 0.837782, 0.164260, -0.133760, 1.694868, 0.837346, 0.183188,
+ -0.148108, 1.692262, 0.836780, 0.203158, -0.163075, 1.689251, 0.836073, 0.224147, -0.178255,
+ 1.685408, 0.835148, 0.246147, -0.193900, 1.680946, 0.833992, 0.269072, -0.209553, 1.675277,
+ 0.832546, 0.292718, -0.225226, 1.667626, 0.830727, 0.317159, -0.240836, 1.658952, 0.828510,
+ 0.341979, -0.256103, 1.647624, 0.825843, 0.366844, -0.270887, 1.633014, 0.822760, 0.392043,
+ -0.285324, 1.617191, 0.819159, 0.417356, -0.298817, 1.597501, 0.814788, 0.444093, -0.310711,
+ 1.575184, 0.808751, 0.471379, -0.321410, 1.551590, 0.801294, 0.498267, -0.330421, 1.524134,
+ 0.792711, 0.525401, -0.338331, 1.496672, 0.782480, 0.551846, -0.344430, 1.467062, 0.770659,
+ 0.578009, -0.349047, 1.436943, 0.757348, 0.604054, -0.352490, 1.407611, 0.742541, 0.629387,
+ -0.354158, 1.377441, 0.726071, 0.654435, -0.354422, 1.347651, 0.707524, 0.679845, -0.352663,
+ 1.318769, 0.687067, 0.704892, -0.348994, 1.290600, 0.664637, 0.729763, -0.344105, 1.263997,
+ 0.640663, 0.754345, -0.338129, 1.239273, 0.615484, 0.778629, -0.330905, 1.215858, 0.589210,
+ 0.801939, -0.322113, 1.192318, 0.561550, 0.825723, -0.311673, 1.171380, 0.532175, 0.849387,
+ -0.300410, 1.152991, 0.502055, 0.872792, -0.288328, 1.136139, 0.471308, 0.895083, -0.275087,
+ 1.119534, 0.440427, 0.918335, -0.260700, 1.105542, 0.409260, 0.941577, -0.245717, 1.093070,
+ 0.377142, 0.963992, -0.230079, 1.081207, 0.345289, 0.986510, -0.213523, 1.071488, 0.313508,
+ 1.008806, -0.196157, 1.062011, 0.281962, 1.030724, -0.178467, 1.053240, 0.251177, 1.053782,
+ -0.160291, 1.047057, 0.220986, 1.075451, -0.141308, 1.041842, 0.192256, 1.094947, -0.121975,
+ 1.037704, 0.165023, 1.111783, -0.101744, 1.033300, 0.138228, 1.125525, -0.081476, 1.028234,
+ 0.110679, 1.135873, -0.060770, 1.021695, 0.082672, 1.142478, -0.040207, 1.013838, 0.054506,
+ 1.147889, -0.019908, 1.006166, 0.026938, 1.153852, 0.000204, 0.999983, -0.000123, 0.000199,
+ -0.000176, 1.771601, 0.882501, 0.000504, -0.000445, 1.779195, 0.882504, 0.002016, -0.001779,
+ 1.779635, 0.882498, 0.004536, -0.004003, 1.779586, 0.882499, 0.008062, -0.007115, 1.778613,
+ 0.882496, 0.012598, -0.011116, 1.778678, 0.882492, 0.018142, -0.016005, 1.778531, 0.882481,
+ 0.024696, -0.021782, 1.778556, 0.882466, 0.032262, -0.028444, 1.778507, 0.882442, 0.040842,
+ -0.035987, 1.778385, 0.882408, 0.050436, -0.044404, 1.778034, 0.882364, 0.061053, -0.053695,
+ 1.777761, 0.882287, 0.072692, -0.063842, 1.777256, 0.882190, 0.085364, -0.074821, 1.776518,
+ 0.882067, 0.099064, -0.086368, 1.775080, 0.881884, 0.113828, -0.098805, 1.773836, 0.881657,
+ 0.129649, -0.112090, 1.772370, 0.881361, 0.146518, -0.126067, 1.770594, 0.880982, 0.164440,
+ -0.140493, 1.768089, 0.880484, 0.183437, -0.155646, 1.765301, 0.879843, 0.203468, -0.171266,
+ 1.761698, 0.879035, 0.224562, -0.187231, 1.757518, 0.877982, 0.246665, -0.203540, 1.752318,
+ 0.876667, 0.269652, -0.219916, 1.745356, 0.875028, 0.293531, -0.236255, 1.737186, 0.872977,
+ 0.318048, -0.252410, 1.726709, 0.870448, 0.342963, -0.268192, 1.713109, 0.867400, 0.368336,
+ -0.283587, 1.698087, 0.863882, 0.393512, -0.298186, 1.678638, 0.859724, 0.418602, -0.311882,
+ 1.655604, 0.854835, 0.445080, -0.324500, 1.632250, 0.848353, 0.472289, -0.335295, 1.605069,
+ 0.840218, 0.499128, -0.344256, 1.573846, 0.830556, 0.525834, -0.351716, 1.541120, 0.819269,
+ 0.553177, -0.358241, 1.511385, 0.806222, 0.579480, -0.362640, 1.477866, 0.791647, 0.605205,
+ -0.365513, 1.444218, 0.775398, 0.630617, -0.366822, 1.410954, 0.757144, 0.655730, -0.366785,
+ 1.379010, 0.737323, 0.680529, -0.364904, 1.347280, 0.715601, 0.705800, -0.360990, 1.316416,
+ 0.691547, 0.730550, -0.355397, 1.286344, 0.666141, 0.754970, -0.348664, 1.258954, 0.638929,
+ 0.779042, -0.340774, 1.232965, 0.611015, 0.802839, -0.331767, 1.209775, 0.581877, 0.825793,
+ -0.321054, 1.185813, 0.551509, 0.849512, -0.309016, 1.165080, 0.519698, 0.873120, -0.296369,
+ 1.147091, 0.487506, 0.895942, -0.282704, 1.129658, 0.455320, 0.917996, -0.268007, 1.113463,
+ 0.422605, 0.941281, -0.252329, 1.100040, 0.389347, 0.964584, -0.236203, 1.087973, 0.356430,
+ 0.986371, -0.219209, 1.075983, 0.323089, 1.009522, -0.201588, 1.066940, 0.290806, 1.031976,
+ -0.183296, 1.057999, 0.258682, 1.053461, -0.164509, 1.049542, 0.227722, 1.076121, -0.145165,
+ 1.043718, 0.197439, 1.096597, -0.125199, 1.039607, 0.169578, 1.113908, -0.104921, 1.035528,
+ 0.142222, 1.127939, -0.083623, 1.029807, 0.113802, 1.138391, -0.062589, 1.023312, 0.085164,
+ 1.145110, -0.041376, 1.014806, 0.056186, 1.150141, -0.020433, 1.006501, 0.027654, 1.156069,
+ 0.000097, 0.999949, -0.000046, 0.000200, -0.000185, 1.858268, 0.927857, 0.000504, -0.000468,
+ 1.861583, 0.927859, 0.002016, -0.001870, 1.860659, 0.927855, 0.004535, -0.004208, 1.860963,
+ 0.927867, 0.008063, -0.007480, 1.860766, 0.927855, 0.012594, -0.011683, 1.859996, 0.927851,
+ 0.018142, -0.016828, 1.860739, 0.927839, 0.024698, -0.022901, 1.860763, 0.927818, 0.032263,
+ -0.029903, 1.860501, 0.927791, 0.040846, -0.037834, 1.860431, 0.927751, 0.050440, -0.046680,
+ 1.859827, 0.927690, 0.061066, -0.056446, 1.859624, 0.927610, 0.072713, -0.067109, 1.859039,
+ 0.927505, 0.085393, -0.078613, 1.858144, 0.927357, 0.099120, -0.090747, 1.856618, 0.927145,
+ 0.113910, -0.103850, 1.855221, 0.926884, 0.129755, -0.117777, 1.853470, 0.926546, 0.146669,
+ -0.132441, 1.851413, 0.926104, 0.164648, -0.147565, 1.848498, 0.925530, 0.183708, -0.163470,
+ 1.845281, 0.924802, 0.203832, -0.179763, 1.841273, 0.923871, 0.225029, -0.196564, 1.836481,
+ 0.922691, 0.247221, -0.213537, 1.830273, 0.921198, 0.270343, -0.230662, 1.822374, 0.919320,
+ 0.294399, -0.247740, 1.812975, 0.917008, 0.319040, -0.264448, 1.800693, 0.914141, 0.344269,
+ -0.280831, 1.785923, 0.910707, 0.369625, -0.296478, 1.767203, 0.906585, 0.394925, -0.311287,
+ 1.744434, 0.901918, 0.420583, -0.325578, 1.720938, 0.896240, 0.446200, -0.338384, 1.693005,
+ 0.889335, 0.472969, -0.349187, 1.660901, 0.880394, 0.500490, -0.358687, 1.628806, 0.869705,
+ 0.527312, -0.366042, 1.593001, 0.857145, 0.554207, -0.372045, 1.557046, 0.842943, 0.580620,
+ -0.376134, 1.520192, 0.826837, 0.606480, -0.378636, 1.482947, 0.808891, 0.631815, -0.379414,
+ 1.445954, 0.789119, 0.657021, -0.378972, 1.410833, 0.767564, 0.681686, -0.376728, 1.376575,
+ 0.744338, 0.706498, -0.372844, 1.342935, 0.718799, 0.731258, -0.366649, 1.311052, 0.691756,
+ 0.755937, -0.359354, 1.280478, 0.662683, 0.779259, -0.350487, 1.250585, 0.632892, 0.803295,
+ -0.340941, 1.225722, 0.602160, 0.826570, -0.330174, 1.201003, 0.570520, 0.849954, -0.317854,
+ 1.178488, 0.537651, 0.873696, -0.304426, 1.158302, 0.503799, 0.896695, -0.290120, 1.139886,
+ 0.469645, 0.919149, -0.275106, 1.122884, 0.435625, 0.942121, -0.259282, 1.107691, 0.401228,
+ 0.964627, -0.242123, 1.093661, 0.367086, 0.986614, -0.224575, 1.081580, 0.332885, 1.009623,
+ -0.206837, 1.071375, 0.299209, 1.033126, -0.188092, 1.062241, 0.266187, 1.054954, -0.168637,
+ 1.052912, 0.233733, 1.077660, -0.149166, 1.047047, 0.203192, 1.097983, -0.128587, 1.041607,
+ 0.173918, 1.115586, -0.107339, 1.036850, 0.145531, 1.130170, -0.086203, 1.031427, 0.116890,
+ 1.141018, -0.064171, 1.024395, 0.087388, 1.147681, -0.042530, 1.015719, 0.057733, 1.152560,
+ -0.021011, 1.006883, 0.028413, 1.158406, 0.000158, 0.999897, -0.000106, 0.000200, -0.000195,
+ 1.950982, 0.975366, 0.000504, -0.000491, 1.950207, 0.975365, 0.002015, -0.001966, 1.950675,
+ 0.975362, 0.004535, -0.004423, 1.951281, 0.975370, 0.008062, -0.007863, 1.951045, 0.975362,
+ 0.012597, -0.012285, 1.951199, 0.975356, 0.018145, -0.017692, 1.951528, 0.975340, 0.024699,
+ -0.024074, 1.951194, 0.975321, 0.032266, -0.031434, 1.950865, 0.975288, 0.040853, -0.039771,
+ 1.951038, 0.975244, 0.050452, -0.049067, 1.950336, 0.975173, 0.061077, -0.059324, 1.949805,
+ 0.975078, 0.072736, -0.070526, 1.949133, 0.974951, 0.085431, -0.082528, 1.947947, 0.974777,
+ 0.099182, -0.095345, 1.946337, 0.974540, 0.113999, -0.109118, 1.944725, 0.974241, 0.129888,
+ -0.123741, 1.942857, 0.973852, 0.146842, -0.139071, 1.940251, 0.973342, 0.164890, -0.154986,
+ 1.937086, 0.972684, 0.184025, -0.171661, 1.933404, 0.971856, 0.204245, -0.188672, 1.928770,
+ 0.970785, 0.225528, -0.206252, 1.923041, 0.969448, 0.247841, -0.223972, 1.915788, 0.967742,
+ 0.271157, -0.241827, 1.907008, 0.965607, 0.295297, -0.259562, 1.895854, 0.963007, 0.320121,
+ -0.276909, 1.881289, 0.959722, 0.345566, -0.293883, 1.864528, 0.955831, 0.371012, -0.309816,
+ 1.842062, 0.951127, 0.396834, -0.325157, 1.818068, 0.945725, 0.422277, -0.339357, 1.788874,
+ 0.939318, 0.447928, -0.352387, 1.758283, 0.931470, 0.474315, -0.363680, 1.723668, 0.921900,
+ 0.501560, -0.372963, 1.686081, 0.909996, 0.528391, -0.380159, 1.645816, 0.896244, 0.554754,
+ -0.385545, 1.603709, 0.880326, 0.581888, -0.389778, 1.565475, 0.862716, 0.607791, -0.391839,
+ 1.524196, 0.843146, 0.633511, -0.392331, 1.483921, 0.821554, 0.658621, -0.391193, 1.445013,
+ 0.798336, 0.683160, -0.388424, 1.406963, 0.773299, 0.707429, -0.384104, 1.370996, 0.746668,
+ 0.732212, -0.377945, 1.335879, 0.717502, 0.756871, -0.369856, 1.302489, 0.686954, 0.781065,
+ -0.360707, 1.271815, 0.655372, 0.804167, -0.350091, 1.242416, 0.622683, 0.827948, -0.338941,
+ 1.217208, 0.589185, 0.850901, -0.326427, 1.192354, 0.555005, 0.873589, -0.312199, 1.169639,
+ 0.519594, 0.897085, -0.297374, 1.150181, 0.484105, 0.920459, -0.281932, 1.132858, 0.448661,
+ 0.942637, -0.265625, 1.115401, 0.413051, 0.965341, -0.248332, 1.101078, 0.377329, 0.987530,
+ -0.229983, 1.087377, 0.342349, 1.010739, -0.211647, 1.076582, 0.307824, 1.033449, -0.192725,
+ 1.065900, 0.273368, 1.055618, -0.172726, 1.056958, 0.240238, 1.079345, -0.152640, 1.049620,
+ 0.208322, 1.100058, -0.131931, 1.044084, 0.178242, 1.118547, -0.110351, 1.039387, 0.149493,
+ 1.132748, -0.088128, 1.033049, 0.119673, 1.143419, -0.066069, 1.025521, 0.089728, 1.150316,
+ -0.043513, 1.016378, 0.059253, 1.155208, -0.021593, 1.007506, 0.029140, 1.160871, 0.000111,
+ 0.999916, -0.000035, 0.000201, -0.000206, 2.061000, 1.025243, 0.000504, -0.000516, 2.049647,
+ 1.025237, 0.002015, -0.002066, 2.050169, 1.025237, 0.004535, -0.004650, 2.051254, 1.025255,
+ 0.008063, -0.008266, 2.051302, 1.025236, 0.012600, -0.012915, 2.051508, 1.025226, 0.018144,
+ -0.018594, 2.050981, 1.025215, 0.024700, -0.025304, 2.050841, 1.025190, 0.032267, -0.033038,
+ 2.050537, 1.025152, 0.040852, -0.041795, 2.050660, 1.025090, 0.050460, -0.051570, 2.049921,
+ 1.025017, 0.061094, -0.062347, 2.049350, 1.024908, 0.072762, -0.074111, 2.048517, 1.024760,
+ 0.085475, -0.086661, 2.047009, 1.024555, 0.099249, -0.100160, 2.045261, 1.024278, 0.114106,
+ -0.114628, 2.043508, 1.023941, 0.130032, -0.130002, 2.041321, 1.023488, 0.147050, -0.145985,
+ 2.038299, 1.022905, 0.165164, -0.162762, 2.034658, 1.022151, 0.184380, -0.180172, 2.030312,
+ 1.021200, 0.204704, -0.198022, 2.024944, 1.019966, 0.226129, -0.216359, 2.018546, 1.018424,
+ 0.248582, -0.234923, 2.010153, 1.016519, 0.272011, -0.253474, 1.999659, 1.014072, 0.296259,
+ -0.271820, 1.986076, 1.011071, 0.321423, -0.289959, 1.970618, 1.007389, 0.346897, -0.307283,
+ 1.949667, 1.002955, 0.372750, -0.323817, 1.925287, 0.997633, 0.398603, -0.339241, 1.896006,
+ 0.991354, 0.424351, -0.353633, 1.863658, 0.983937, 0.449887, -0.366660, 1.827430, 0.975254,
+ 0.475715, -0.378213, 1.789521, 0.964753, 0.502204, -0.387133, 1.745632, 0.951594, 0.530179,
+ -0.394976, 1.705347, 0.936344, 0.556732, -0.400134, 1.658928, 0.918907, 0.583123, -0.403439,
+ 1.613077, 0.899504, 0.609477, -0.405285, 1.567884, 0.878172, 0.634927, -0.405055, 1.523507,
+ 0.854396, 0.660357, -0.403494, 1.481712, 0.829259, 0.684851, -0.400104, 1.439000, 0.802359,
+ 0.709654, -0.395536, 1.400956, 0.773534, 0.733472, -0.388996, 1.362156, 0.743230, 0.757502,
+ -0.380263, 1.325113, 0.711090, 0.782249, -0.370594, 1.292913, 0.677166, 0.806017, -0.359509,
+ 1.262088, 0.642527, 0.828687, -0.347126, 1.232059, 0.607589, 0.852372, -0.334474, 1.207160,
+ 0.571938, 0.874266, -0.320074, 1.181978, 0.535518, 0.898168, -0.304719, 1.161156, 0.498375,
+ 0.920456, -0.288246, 1.140667, 0.461179, 0.942832, -0.271311, 1.122780, 0.424533, 0.966458,
+ -0.254154, 1.108743, 0.387784, 0.988907, -0.235659, 1.093872, 0.351689, 1.011557, -0.216322,
+ 1.081959, 0.315743, 1.035099, -0.197007, 1.070885, 0.280402, 1.056354, -0.176878, 1.059968,
+ 0.246472, 1.079854, -0.156058, 1.051815, 0.212818, 1.101494, -0.134772, 1.045757, 0.182143,
+ 1.120587, -0.113071, 1.041169, 0.152867, 1.135399, -0.090411, 1.034844, 0.122796, 1.146612,
+ -0.067477, 1.026974, 0.091888, 1.153168, -0.044849, 1.017303, 0.060779, 1.157912, -0.021998,
+ 1.007735, 0.029919, 1.163607, 0.000121, 0.999959, 0.000003, 0.000200, -0.000216, 2.163956,
+ 1.077737, 0.000504, -0.000543, 2.161128, 1.077732, 0.002016, -0.002173, 2.162732, 1.077729,
+ 0.004535, -0.004887, 2.161402, 1.077749, 0.008066, -0.008692, 2.163252, 1.077732, 0.012599,
+ -0.013576, 2.161300, 1.077727, 0.018145, -0.019546, 2.161151, 1.077702, 0.024702, -0.026599,
+ 2.161223, 1.077675, 0.032272, -0.034729, 2.160949, 1.077632, 0.040862, -0.043936, 2.160967,
+ 1.077575, 0.050470, -0.054203, 2.160035, 1.077473, 0.061113, -0.065528, 2.159490, 1.077348,
+ 0.072794, -0.077882, 2.158517, 1.077178, 0.085528, -0.091030, 2.156605, 1.076937, 0.099337,
+ -0.105251, 2.154828, 1.076631, 0.114228, -0.120456, 2.152812, 1.076229, 0.130202, -0.136573,
+ 2.150298, 1.075713, 0.147284, -0.153306, 2.146752, 1.075031, 0.165480, -0.170931, 2.142744,
+ 1.074173, 0.184793, -0.189083, 2.137475, 1.073063, 0.205224, -0.207840, 2.131320, 1.071683,
+ 0.226743, -0.226939, 2.123154, 1.069914, 0.249401, -0.246344, 2.114086, 1.067718, 0.272955,
+ -0.265640, 2.101599, 1.064924, 0.297494, -0.284846, 2.086612, 1.061512, 0.322731, -0.303452,
+ 2.067356, 1.057359, 0.348451, -0.321330, 2.043711, 1.052294, 0.374451, -0.338201, 2.015033,
+ 1.046153, 0.400454, -0.353816, 1.981139, 1.039003, 0.426434, -0.368216, 1.944128, 1.030498,
+ 0.452088, -0.381251, 1.903094, 1.020454, 0.477901, -0.392833, 1.860402, 1.008793, 0.504173,
+ -0.402408, 1.814402, 0.994791, 0.531520, -0.409545, 1.766273, 0.977733, 0.558049, -0.414351,
+ 1.714119, 0.958625, 0.584778, -0.417437, 1.664612, 0.937189, 0.610808, -0.418519, 1.613793,
+ 0.913543, 0.636915, -0.418094, 1.565942, 0.888137, 0.662204, -0.415742, 1.518783, 0.860728,
+ 0.686848, -0.411746, 1.473306, 0.831793, 0.710992, -0.406153, 1.430153, 0.800862, 0.735382,
+ -0.399519, 1.389824, 0.768768, 0.759079, -0.390927, 1.350744, 0.734825, 0.782912, -0.380111,
+ 1.313559, 0.699450, 0.806746, -0.368383, 1.280028, 0.663191, 0.830269, -0.355606, 1.249814,
+ 0.625927, 0.853305, -0.341988, 1.221138, 0.588644, 0.876326, -0.327545, 1.195837, 0.550849,
+ 0.898322, -0.311779, 1.171844, 0.512694, 0.921811, -0.294944, 1.150671, 0.474225, 0.944563,
+ -0.277333, 1.132224, 0.435772, 0.967089, -0.259340, 1.115422, 0.398001, 0.989754, -0.240836,
+ 1.100405, 0.360802, 1.012470, -0.221293, 1.086533, 0.323566, 1.036426, -0.201191, 1.075496,
+ 0.287387, 1.058709, -0.180590, 1.064233, 0.252184, 1.081593, -0.159810, 1.055296, 0.218441,
+ 1.103146, -0.137772, 1.047978, 0.186223, 1.122814, -0.115347, 1.042693, 0.156019, 1.137790,
+ -0.092582, 1.036049, 0.125579, 1.149184, -0.069152, 1.027944, 0.093986, 1.156062, -0.045661,
+ 1.018039, 0.062122, 1.160733, -0.022719, 1.008072, 0.030650, 1.166487, 0.000231, 1.000063,
+ -0.000120, 0.000201, -0.000228, 2.308308, 1.133128, 0.000504, -0.000571, 2.283756, 1.133123,
+ 0.002016, -0.002284, 2.283756, 1.133123, 0.004535, -0.005138, 2.283310, 1.133144, 0.008048,
+ -0.009119, 2.266192, 1.133138, 0.012600, -0.014274, 2.284377, 1.133110, 0.018147, -0.020553,
+ 2.284204, 1.133093, 0.024702, -0.027964, 2.283517, 1.133060, 0.032272, -0.036510, 2.282997,
+ 1.133007, 0.040866, -0.046188, 2.282986, 1.132930, 0.050481, -0.056979, 2.282260, 1.132824,
+ 0.061133, -0.068881, 2.281533, 1.132678, 0.072830, -0.081850, 2.280504, 1.132481, 0.085592,
+ -0.095657, 2.278304, 1.132202, 0.099431, -0.110594, 2.276269, 1.131845, 0.114360, -0.126590,
+ 2.273890, 1.131383, 0.130388, -0.143454, 2.270761, 1.130784, 0.147547, -0.161029, 2.266794,
+ 1.130003, 0.165836, -0.179523, 2.262332, 1.129016, 0.185269, -0.198527, 2.256326, 1.127738,
+ 0.205822, -0.218138, 2.249031, 1.126156, 0.227527, -0.238141, 2.239993, 1.124132, 0.250325,
+ -0.258302, 2.228878, 1.121594, 0.274070, -0.278329, 2.214204, 1.118449, 0.298793, -0.298310,
+ 2.196654, 1.114528, 0.324131, -0.317462, 2.173394, 1.109783, 0.350101, -0.335853, 2.146395,
+ 1.103901, 0.376293, -0.353064, 2.112341, 1.096954, 0.402547, -0.368950, 2.073700, 1.088642,
+ 0.428791, -0.383462, 2.031152, 1.078946, 0.454976, -0.396635, 1.986661, 1.067536, 0.480566,
+ -0.407873, 1.937038, 1.054403, 0.506154, -0.417303, 1.885155, 1.038894, 0.532862, -0.424194,
+ 1.830369, 1.020535, 0.560354, -0.429344, 1.776976, 0.999295, 0.587114, -0.431949, 1.721214,
+ 0.975990, 0.613345, -0.432547, 1.665739, 0.950239, 0.639335, -0.431338, 1.612200, 0.922467,
+ 0.664996, -0.428473, 1.561035, 0.892593, 0.688947, -0.423355, 1.508240, 0.861325, 0.713403,
+ -0.417235, 1.461776, 0.828289, 0.737649, -0.409848, 1.418888, 0.793863, 0.761275, -0.400901,
+ 1.376807, 0.758074, 0.784778, -0.390174, 1.337204, 0.721974, 0.808762, -0.377683, 1.301527,
+ 0.682718, 0.831993, -0.364037, 1.267144, 0.644001, 0.854696, -0.349494, 1.236023, 0.605478,
+ 0.877933, -0.334499, 1.209284, 0.565588, 0.900180, -0.318435, 1.183967, 0.526138, 0.923039,
+ -0.301669, 1.161513, 0.486524, 0.945895, -0.283298, 1.140838, 0.446747, 0.968069, -0.264438,
+ 1.122475, 0.408041, 0.991179, -0.245463, 1.106968, 0.369477, 1.012926, -0.225680, 1.091435,
+ 0.331626, 1.036995, -0.205401, 1.079561, 0.294288, 1.060909, -0.184310, 1.068215, 0.257696,
+ 1.083531, -0.162846, 1.058133, 0.223343, 1.105644, -0.141040, 1.050851, 0.190541, 1.125691,
+ -0.117965, 1.045001, 0.159310, 1.141297, -0.094377, 1.038028, 0.128238, 1.152672, -0.070831,
+ 1.029694, 0.096282, 1.159333, -0.046853, 1.019136, 0.063720, 1.163819, -0.022991, 1.008518,
+ 0.031234, 1.169564, 0.000125, 1.000069, -0.000024, 0.000202, -0.000241, 2.458341, 1.191742,
+ 0.000504, -0.000600, 2.418738, 1.191740, 0.002015, -0.002401, 2.418821, 1.191730, 0.004535,
+ -0.005405, 2.421986, 1.191756, 0.008071, -0.009618, 2.424988, 1.191753, 0.012600, -0.015012,
+ 2.420242, 1.191727, 0.018145, -0.021612, 2.419937, 1.191703, 0.024704, -0.029410, 2.419746,
+ 1.191662, 0.032278, -0.038398, 2.419409, 1.191604, 0.040874, -0.048574, 2.418995, 1.191515,
+ 0.050496, -0.059920, 2.418190, 1.191389, 0.061160, -0.072432, 2.417487, 1.191221, 0.072871,
+ -0.086009, 2.415853, 1.190984, 0.085664, -0.100559, 2.413669, 1.190664, 0.099543, -0.116283,
+ 2.411423, 1.190256, 0.114520, -0.133071, 2.408711, 1.189719, 0.130616, -0.150670, 2.404900,
+ 1.189019, 0.147856, -0.169197, 2.400512, 1.188125, 0.166235, -0.188545, 2.394939, 1.186972,
+ 0.185804, -0.208480, 2.388232, 1.185515, 0.206488, -0.228883, 2.379190, 1.183673, 0.228383,
+ -0.249897, 2.369208, 1.181382, 0.251305, -0.270851, 2.355459, 1.178478, 0.275349, -0.291780,
+ 2.339142, 1.174857, 0.300106, -0.312257, 2.316655, 1.170411, 0.325849, -0.332225, 2.291540,
+ 1.164883, 0.351782, -0.350862, 2.257242, 1.158196, 0.378248, -0.368431, 2.218671, 1.150173,
+ 0.404674, -0.384428, 2.173680, 1.140703, 0.431385, -0.399230, 2.127083, 1.129555, 0.457407,
+ -0.411875, 2.073236, 1.116436, 0.483275, -0.423013, 2.018223, 1.101373, 0.509278, -0.432624,
+ 1.962674, 1.084257, 0.534751, -0.439261, 1.900814, 1.064592, 0.561895, -0.443801, 1.839558,
+ 1.040881, 0.588677, -0.445872, 1.777763, 1.015208, 0.614900, -0.445896, 1.716550, 0.987252,
+ 0.641051, -0.444148, 1.657984, 0.957271, 0.666409, -0.440299, 1.600832, 0.924841, 0.691872,
+ -0.435318, 1.548237, 0.891185, 0.716638, -0.428631, 1.497572, 0.855929, 0.739864, -0.419872,
+ 1.447043, 0.819676, 0.763707, -0.410456, 1.403648, 0.781455, 0.786744, -0.399390, 1.360844,
+ 0.742965, 0.809585, -0.386381, 1.320529, 0.703260, 0.834164, -0.372622, 1.286467, 0.662385,
+ 0.856713, -0.357177, 1.252306, 0.621379, 0.879820, -0.341458, 1.223070, 0.580238, 0.902721,
+ -0.325024, 1.197115, 0.539028, 0.924650, -0.307543, 1.172314, 0.498592, 0.947613, -0.289557,
+ 1.151171, 0.457980, 0.969590, -0.269799, 1.129986, 0.417696, 0.992961, -0.250111, 1.113321,
+ 0.377529, 1.014582, -0.229761, 1.097149, 0.339096, 1.038069, -0.209375, 1.083913, 0.301119,
+ 1.061661, -0.188038, 1.071241, 0.263506, 1.085069, -0.165874, 1.060508, 0.227921, 1.107744,
+ -0.143437, 1.052930, 0.194062, 1.127982, -0.120574, 1.046396, 0.162506, 1.144541, -0.096569,
+ 1.039880, 0.130788, 1.155876, -0.072039, 1.030946, 0.098057, 1.162719, -0.047888, 1.020124,
+ 0.064956, 1.167089, -0.023740, 1.008953, 0.031966, 1.172775, 0.000277, 1.000067, -0.000111,
+ 0.000200, -0.000251, 2.573709, 1.253951, 0.000504, -0.000632, 2.572401, 1.253940, 0.002015,
+ -0.002527, 2.571267, 1.253927, 0.004535, -0.005687, 2.572481, 1.253948, 0.008062, -0.010108,
+ 2.571851, 1.253941, 0.012588, -0.015780, 2.568431, 1.253934, 0.018139, -0.022731, 2.569765,
+ 1.253893, 0.024709, -0.030948, 2.572115, 1.253853, 0.032283, -0.040401, 2.571456, 1.253785,
+ 0.040883, -0.051105, 2.571041, 1.253683, 0.050514, -0.063041, 2.570153, 1.253538, 0.061188,
+ -0.076195, 2.569085, 1.253336, 0.072926, -0.090402, 2.567184, 1.253065, 0.085746, -0.105745,
+ 2.564731, 1.252697, 0.099661, -0.122296, 2.561995, 1.252218, 0.114699, -0.139912, 2.559019,
+ 1.251590, 0.130882, -0.158362, 2.555017, 1.250766, 0.148202, -0.177856, 2.549419, 1.249744,
+ 0.166706, -0.198049, 2.542908, 1.248423, 0.186404, -0.219014, 2.535205, 1.246741, 0.207272,
+ -0.240376, 2.524893, 1.244596, 0.229345, -0.262230, 2.512804, 1.241917, 0.252494, -0.284134,
+ 2.496923, 1.238610, 0.276690, -0.305828, 2.476583, 1.234474, 0.301798, -0.327107, 2.451548,
+ 1.229292, 0.327423, -0.347300, 2.418630, 1.222997, 0.353848, -0.366699, 2.381002, 1.215366,
+ 0.380342, -0.384421, 2.334413, 1.206199, 0.407390, -0.400855, 2.285660, 1.195374, 0.433913,
+ -0.415241, 2.228604, 1.182290, 0.460837, -0.428275, 2.171532, 1.167385, 0.486381, -0.438573,
+ 2.105639, 1.150401, 0.511959, -0.447348, 2.040835, 1.130990, 0.537586, -0.454152, 1.974797,
+ 1.109302, 0.564035, -0.458684, 1.907895, 1.084131, 0.590690, -0.460058, 1.839482, 1.055803,
+ 0.617250, -0.459662, 1.772332, 1.025103, 0.643406, -0.457260, 1.707313, 0.992502, 0.668794,
+ -0.452666, 1.644722, 0.957657, 0.693930, -0.446641, 1.586832, 0.921340, 0.718708, -0.439121,
+ 1.531197, 0.883841, 0.743469, -0.430429, 1.480765, 0.844931, 0.766080, -0.419622, 1.430338,
+ 0.804786, 0.789801, -0.408368, 1.386295, 0.764206, 0.812718, -0.395392, 1.343758, 0.722565,
+ 0.835453, -0.380699, 1.304655, 0.680585, 0.858801, -0.364834, 1.269287, 0.637235, 0.881537,
+ -0.348092, 1.237493, 0.594579, 0.904656, -0.331087, 1.208862, 0.552313, 0.926357, -0.312966,
+ 1.182365, 0.510080, 0.949001, -0.294684, 1.159452, 0.468677, 0.971598, -0.275361, 1.138706,
+ 0.426723, 0.994905, -0.254947, 1.120552, 0.385875, 1.017981, -0.234109, 1.104215, 0.345751,
+ 1.040840, -0.213040, 1.089276, 0.306762, 1.063893, -0.191616, 1.075845, 0.269066, 1.086907,
+ -0.169272, 1.063788, 0.232171, 1.109937, -0.146076, 1.054977, 0.197826, 1.130808, -0.122544,
+ 1.048572, 0.165272, 1.146831, -0.098492, 1.040742, 0.133280, 1.158955, -0.073710, 1.031818,
+ 0.100262, 1.166161, -0.048610, 1.020747, 0.066165, 1.170491, -0.024209, 1.009380, 0.032741,
+ 1.176111, 0.000010, 1.000042, 0.000056, 0.000202, -0.000267, 2.786357, 1.320169, 0.000504,
+ -0.000665, 2.741889, 1.320168, 0.002015, -0.002660, 2.740000, 1.320143, 0.004536, -0.005987,
+ 2.744276, 1.320161, 0.008063, -0.010644, 2.743432, 1.320162, 0.012600, -0.016628, 2.741741,
+ 1.320148, 0.018144, -0.023937, 2.741314, 1.320127, 0.024708, -0.032577, 2.741916, 1.320061,
+ 0.032290, -0.042536, 2.742132, 1.319976, 0.040894, -0.053799, 2.741199, 1.319861, 0.050533,
+ -0.066361, 2.740258, 1.319691, 0.061223, -0.080202, 2.739045, 1.319458, 0.072985, -0.095109,
+ 2.736519, 1.319138, 0.085841, -0.111296, 2.733903, 1.318715, 0.099808, -0.128685, 2.730944,
+ 1.318156, 0.114903, -0.147202, 2.727293, 1.317424, 0.131164, -0.166575, 2.722169, 1.316485,
+ 0.148599, -0.187019, 2.716148, 1.315274, 0.167245, -0.208240, 2.708701, 1.313733, 0.187078,
+ -0.230151, 2.698998, 1.311792, 0.208153, -0.252538, 2.687341, 1.309343, 0.230418, -0.275295,
+ 2.672621, 1.306247, 0.253802, -0.298066, 2.653619, 1.302374, 0.278261, -0.320673, 2.629943,
+ 1.297573, 0.303527, -0.342528, 2.599228, 1.291625, 0.329571, -0.363531, 2.562226, 1.284374,
+ 0.355939, -0.382963, 2.515491, 1.275478, 0.382987, -0.401306, 2.464858, 1.264866, 0.409917,
+ -0.417455, 2.404877, 1.252184, 0.437015, -0.432067, 2.341408, 1.237415, 0.463474, -0.444204,
+ 2.271837, 1.220687, 0.489835, -0.454631, 2.200593, 1.200973, 0.516054, -0.463338, 2.129733,
+ 1.179346, 0.541397, -0.469425, 2.055635, 1.155039, 0.566798, -0.473526, 1.980812, 1.127866,
+ 0.593114, -0.474632, 1.904723, 1.097304, 0.619945, -0.473597, 1.832456, 1.063603, 0.646325,
+ -0.470656, 1.761501, 1.027971, 0.672320, -0.465675, 1.694248, 0.990692, 0.697163, -0.458527,
+ 1.629227, 0.951582, 0.721472, -0.449904, 1.568132, 0.911197, 0.745855, -0.440140, 1.512084,
+ 0.869745, 0.770089, -0.429338, 1.460694, 0.827648, 0.792546, -0.416701, 1.410739, 0.784728,
+ 0.815161, -0.403151, 1.365438, 0.741884, 0.837994, -0.388714, 1.324811, 0.697800, 0.861220,
+ -0.372573, 1.287723, 0.653341, 0.883737, -0.355024, 1.252491, 0.609455, 0.906784, -0.337092,
+ 1.221844, 0.565275, 0.928493, -0.318370, 1.192881, 0.521558, 0.951495, -0.299605, 1.169131,
+ 0.478149, 0.973586, -0.280067, 1.146316, 0.436325, 0.996400, -0.259823, 1.127860, 0.394409,
+ 1.019780, -0.238313, 1.110521, 0.353045, 1.042775, -0.216506, 1.093915, 0.312803, 1.066822,
+ -0.194695, 1.080326, 0.274100, 1.089869, -0.172290, 1.067722, 0.236657, 1.113606, -0.149264,
+ 1.058471, 0.201603, 1.134229, -0.124814, 1.050701, 0.168398, 1.150922, -0.100070, 1.043051,
+ 0.135616, 1.163224, -0.075155, 1.033742, 0.102144, 1.169965, -0.049933, 1.021818, 0.067532,
+ 1.174200, -0.024461, 1.009916, 0.033215, 1.179766, 0.000188, 1.000045, -0.000014, 0.000202,
+ -0.000281, 2.964186, 1.390880, 0.000505, -0.000702, 2.945157, 1.390903, 0.002015, -0.002802,
+ 2.931184, 1.390863, 0.004535, -0.006307, 2.935673, 1.390900, 0.008063, -0.011213, 2.934274,
+ 1.390890, 0.012598, -0.017516, 2.932216, 1.390876, 0.018147, -0.025221, 2.933324, 1.390832,
+ 0.024711, -0.034322, 2.933945, 1.390769, 0.032295, -0.044810, 2.933496, 1.390674, 0.040904,
+ -0.056673, 2.932487, 1.390538, 0.050555, -0.069906, 2.931571, 1.390342, 0.061259, -0.084468,
+ 2.929914, 1.390064, 0.073053, -0.100152, 2.927039, 1.389695, 0.085948, -0.117202, 2.924241,
+ 1.389201, 0.099968, -0.135531, 2.920760, 1.388548, 0.115135, -0.154906, 2.915998, 1.387692,
+ 0.131496, -0.175352, 2.910285, 1.386611, 0.149049, -0.196783, 2.903174, 1.385190, 0.167848,
+ -0.219066, 2.894584, 1.383407, 0.187879, -0.241983, 2.883171, 1.381148, 0.209143, -0.265398,
+ 2.869102, 1.378261, 0.231689, -0.289254, 2.852238, 1.374690, 0.255223, -0.312776, 2.828264,
+ 1.370166, 0.279952, -0.336260, 2.800175, 1.364591, 0.305572, -0.358865, 2.764282, 1.357758,
+ 0.331650, -0.380223, 2.717845, 1.349413, 0.358491, -0.400252, 2.665326, 1.339084, 0.385445,
+ -0.418422, 2.602293, 1.326773, 0.412947, -0.434993, 2.536973, 1.312141, 0.439681, -0.448757,
+ 2.459463, 1.295205, 0.467272, -0.461427, 2.386250, 1.275573, 0.493568, -0.471102, 2.303225,
+ 1.253400, 0.519743, -0.478930, 2.221945, 1.228890, 0.544882, -0.484098, 2.136425, 1.201730,
+ 0.570690, -0.488125, 2.057093, 1.172022, 0.595905, -0.489185, 1.975334, 1.139312, 0.622747,
+ -0.487535, 1.895055, 1.103038, 0.648695, -0.483482, 1.815995, 1.064364, 0.675159, -0.478096,
+ 1.744272, 1.024098, 0.700714, -0.470492, 1.675257, 0.982186, 0.725641, -0.461398, 1.609135,
+ 0.939137, 0.748552, -0.449825, 1.545091, 0.894791, 0.772808, -0.438185, 1.489394, 0.850373,
+ 0.795928, -0.425073, 1.437026, 0.805287, 0.818900, -0.411028, 1.389654, 0.760003, 0.841633,
+ -0.396047, 1.345873, 0.714914, 0.863213, -0.379637, 1.305185, 0.669271, 0.886662, -0.362227,
+ 1.269147, 0.622935, 0.908504, -0.343068, 1.234714, 0.577757, 0.931425, -0.323982, 1.204997,
+ 0.532922, 0.953835, -0.304347, 1.178871, 0.488154, 0.975813, -0.284219, 1.155019, 0.444885,
+ 0.997662, -0.263544, 1.133941, 0.402224, 1.021167, -0.242611, 1.116100, 0.360530, 1.044038,
+ -0.220065, 1.098348, 0.318968, 1.068837, -0.197580, 1.084605, 0.279107, 1.092548, -0.174779,
+ 1.071217, 0.241111, 1.116157, -0.151596, 1.060486, 0.204913, 1.137486, -0.127478, 1.052751,
+ 0.171410, 1.154694, -0.101915, 1.044807, 0.137999, 1.166867, -0.076246, 1.034824, 0.103807,
+ 1.173715, -0.050661, 1.022501, 0.068802, 1.178236, -0.025355, 1.010324, 0.034155, 1.183545,
+ 0.000205, 1.000059, -0.000110, 0.000201, -0.000294, 3.161080, 1.466721, 0.000505, -0.000740,
+ 3.155526, 1.466737, 0.002016, -0.002957, 3.152852, 1.466688, 0.004537, -0.006655, 3.150654,
+ 1.466667, 0.008066, -0.011828, 3.153109, 1.466694, 0.012604, -0.018479, 3.152143, 1.466721,
+ 0.018150, -0.026598, 3.151025, 1.466636, 0.024714, -0.036191, 3.150300, 1.466562, 0.032301,
+ -0.047249, 3.149861, 1.466450, 0.040924, -0.059766, 3.149548, 1.466289, 0.050579, -0.073703,
+ 3.147516, 1.466055, 0.061306, -0.089022, 3.145680, 1.465738, 0.073135, -0.105563, 3.142428,
+ 1.465301, 0.086075, -0.123544, 3.139113, 1.464715, 0.100153, -0.142853, 3.135064, 1.463956,
+ 0.115411, -0.163183, 3.129509, 1.462962, 0.131876, -0.184760, 3.122959, 1.461670, 0.149570,
+ -0.207172, 3.114153, 1.460045, 0.168523, -0.230578, 3.103626, 1.457945, 0.188784, -0.254658,
+ 3.090818, 1.455279, 0.210264, -0.279114, 3.073352, 1.451998, 0.233030, -0.303930, 3.052592,
+ 1.447780, 0.256959, -0.328517, 3.025187, 1.442568, 0.281901, -0.352755, 2.990341, 1.436026,
+ 0.307728, -0.375894, 2.946820, 1.427979, 0.334197, -0.397924, 2.892845, 1.418249, 0.360966,
+ -0.417914, 2.827937, 1.406370, 0.388478, -0.436526, 2.758006, 1.392134, 0.415567, -0.452366,
+ 2.674696, 1.375244, 0.443518, -0.466917, 2.595136, 1.355660, 0.470631, -0.478417, 2.504173,
+ 1.333123, 0.497419, -0.487825, 2.413227, 1.308181, 0.523961, -0.495064, 2.321239, 1.280227,
+ 0.549708, -0.499844, 2.228911, 1.249894, 0.575296, -0.502844, 2.138834, 1.217130, 0.600168,
+ -0.503368, 2.049030, 1.181412, 0.625874, -0.501622, 1.962267, 1.142648, 0.652164, -0.496936,
+ 1.876900, 1.101268, 0.678029, -0.490319, 1.796344, 1.057782, 0.703248, -0.481575, 1.718925,
+ 1.012884, 0.728520, -0.471822, 1.648358, 0.966487, 0.752577, -0.460134, 1.581989, 0.919880,
+ 0.776163, -0.447164, 1.520109, 0.873087, 0.800016, -0.433601, 1.465081, 0.825803, 0.822176,
+ -0.418388, 1.412564, 0.778249, 0.844873, -0.402704, 1.366184, 0.730849, 0.865955, -0.385633,
+ 1.321865, 0.684037, 0.888173, -0.368255, 1.283464, 0.637192, 0.910994, -0.349332, 1.249215,
+ 0.590131, 0.934270, -0.329612, 1.218366, 0.543213, 0.956653, -0.309228, 1.189808, 0.497752,
+ 0.978476, -0.288310, 1.163674, 0.452837, 1.000755, -0.267243, 1.141389, 0.409481, 1.023827,
+ -0.246015, 1.122012, 0.367354, 1.045572, -0.223777, 1.103303, 0.325171, 1.070445, -0.200837,
+ 1.088010, 0.284442, 1.094268, -0.177211, 1.073650, 0.245138, 1.118639, -0.153531, 1.063051,
+ 0.208289, 1.139786, -0.129074, 1.053921, 0.173607, 1.157848, -0.104051, 1.045968, 0.140467,
+ 1.170697, -0.077694, 1.035782, 0.105594, 1.177874, -0.051393, 1.023483, 0.069898, 1.182242,
+ -0.025392, 1.010620, 0.034532, 1.187612, -0.000032, 1.000062, -0.000035, 0.000202, -0.000313,
+ 3.450327, 1.548291, 0.000504, -0.000780, 3.396162, 1.548289, 0.002015, -0.003120, 3.395621,
+ 1.548260, 0.004533, -0.007019, 3.394299, 1.548217, 0.008066, -0.012486, 3.398803, 1.548274,
+ 0.012600, -0.019500, 3.396363, 1.548245, 0.018151, -0.028076, 3.396805, 1.548192, 0.024722,
+ -0.038209, 3.396384, 1.548109, 0.032306, -0.049868, 3.395158, 1.547979, 0.040936, -0.063077,
+ 3.394303, 1.547785, 0.050610, -0.077791, 3.392979, 1.547513, 0.061360, -0.093869, 3.389910,
+ 1.547134, 0.073227, -0.111380, 3.386669, 1.546619, 0.086217, -0.130371, 3.382974, 1.545938,
+ 0.100364, -0.150684, 3.378046, 1.545039, 0.115733, -0.172116, 3.371719, 1.543880, 0.132309,
+ -0.194809, 3.363764, 1.542380, 0.150174, -0.218431, 3.353699, 1.540462, 0.169340, -0.242954,
+ 3.341397, 1.538002, 0.189788, -0.268175, 3.324957, 1.534894, 0.211581, -0.293776, 3.304776,
+ 1.530954, 0.234561, -0.319619, 3.278192, 1.526033, 0.258776, -0.345089, 3.244910, 1.519926,
+ 0.284059, -0.370176, 3.203338, 1.512296, 0.310312, -0.394171, 3.152477, 1.502956, 0.336748,
+ -0.416137, 3.083616, 1.491463, 0.364029, -0.436752, 3.010481, 1.477493, 0.391575, -0.455102,
+ 2.925454, 1.460933, 0.419409, -0.471378, 2.834380, 1.441554, 0.446811, -0.484714, 2.733329,
+ 1.418861, 0.474489, -0.496021, 2.633630, 1.393405, 0.501751, -0.504991, 2.530935, 1.364633,
+ 0.528488, -0.511392, 2.426653, 1.333234, 0.554428, -0.515395, 2.323633, 1.299138, 0.580434,
+ -0.517761, 2.224964, 1.262462, 0.605474, -0.517598, 2.127228, 1.223784, 0.629888, -0.514946,
+ 2.030545, 1.182321, 0.655579, -0.510177, 1.939070, 1.138515, 0.681940, -0.503097, 1.852355,
+ 1.091502, 0.707228, -0.493537, 1.768084, 1.043464, 0.731894, -0.482372, 1.690840, 0.994242,
+ 0.756741, -0.470312, 1.619277, 0.944749, 0.780160, -0.456412, 1.553430, 0.894816, 0.803384,
+ -0.441492, 1.493357, 0.845202, 0.826347, -0.425944, 1.437830, 0.795954, 0.849145, -0.409532,
+ 1.388578, 0.746915, 0.870617, -0.391988, 1.341527, 0.698025, 0.892943, -0.374229, 1.302188,
+ 0.649579, 0.913828, -0.355148, 1.262877, 0.601833, 0.936830, -0.335238, 1.230136, 0.554521,
+ 0.958687, -0.313939, 1.199596, 0.507208, 0.982008, -0.292741, 1.173619, 0.461357, 1.003691,
+ -0.270940, 1.149015, 0.416031, 1.027223, -0.249102, 1.128689, 0.372457, 1.050048, -0.226899,
+ 1.109444, 0.330281, 1.074105, -0.204329, 1.092943, 0.288987, 1.098971, -0.180560, 1.078591,
+ 0.249075, 1.123324, -0.155987, 1.066885, 0.211519, 1.145445, -0.130929, 1.057617, 0.176506,
+ 1.162856, -0.105269, 1.048453, 0.142345, 1.175360, -0.079267, 1.037439, 0.107452, 1.182514,
+ -0.052547, 1.024393, 0.071252, 1.186575, -0.025744, 1.011093, 0.035019, 1.192050, 0.000318,
+ 1.000013, -0.000152, 0.000204, -0.000334, 3.909175, 1.636412, 0.000504, -0.000825, 3.678647,
+ 1.636410, 0.002015, -0.003298, 3.678315, 1.636387, 0.004533, -0.007417, 3.674126, 1.636310,
+ 0.008062, -0.013190, 3.676771, 1.636376, 0.012603, -0.020613, 3.678135, 1.636369, 0.018153,
+ -0.029675, 3.677315, 1.636299, 0.024723, -0.040378, 3.676872, 1.636196, 0.032318, -0.052708,
+ 3.675750, 1.636038, 0.040955, -0.066660, 3.674803, 1.635810, 0.050645, -0.082203, 3.672735,
+ 1.635494, 0.061429, -0.099150, 3.669047, 1.635048, 0.073333, -0.117679, 3.665401, 1.634437,
+ 0.086388, -0.137725, 3.661315, 1.633634, 0.100620, -0.159081, 3.654992, 1.632571, 0.116087,
+ -0.181721, 3.647341, 1.631202, 0.132820, -0.205611, 3.637877, 1.629432, 0.150867, -0.230542,
+ 3.626333, 1.627161, 0.170234, -0.256239, 3.610671, 1.624266, 0.190981, -0.282751, 3.591685,
+ 1.620589, 0.213013, -0.309430, 3.565864, 1.615999, 0.236387, -0.336427, 3.534826, 1.610216,
+ 0.260943, -0.362931, 3.493984, 1.603047, 0.286497, -0.388644, 3.442075, 1.593920, 0.312769,
+ -0.412912, 3.375973, 1.582961, 0.339832, -0.435635, 3.299355, 1.569343, 0.367214, -0.456181,
+ 3.208994, 1.553137, 0.394935, -0.474325, 3.108910, 1.533791, 0.422935, -0.490318, 3.001767,
+ 1.511093, 0.451166, -0.503827, 2.891735, 1.485145, 0.478695, -0.514185, 2.773430, 1.455617,
+ 0.506313, -0.522502, 2.657639, 1.422946, 0.533427, -0.528119, 2.541132, 1.387843, 0.559942,
+ -0.531430, 2.426950, 1.349542, 0.585150, -0.531978, 2.312437, 1.309303, 0.610500, -0.531054,
+ 2.205966, 1.266280, 0.635380, -0.528058, 2.101993, 1.221709, 0.659852, -0.522751, 2.002950,
+ 1.175062, 0.685151, -0.515026, 1.908647, 1.125078, 0.710920, -0.505020, 1.819389, 1.074296,
+ 0.736066, -0.493268, 1.735806, 1.022420, 0.760503, -0.480032, 1.658607, 0.970230, 0.785091,
+ -0.465986, 1.589424, 0.917077, 0.807523, -0.449721, 1.522533, 0.864888, 0.830974, -0.433461,
+ 1.465416, 0.813006, 0.852659, -0.415808, 1.409076, 0.761689, 0.874841, -0.397855, 1.360758,
+ 0.711258, 0.896322, -0.379041, 1.316829, 0.661721, 0.918134, -0.360048, 1.278574, 0.612263,
+ 0.939356, -0.340108, 1.242200, 0.564369, 0.961025, -0.318877, 1.210305, 0.516506, 0.984371,
+ -0.297130, 1.183689, 0.469342, 1.006905, -0.274661, 1.157466, 0.423080, 1.029941, -0.252234,
+ 1.135066, 0.378315, 1.052751, -0.229268, 1.114518, 0.335169, 1.077981, -0.206662, 1.097760,
+ 0.293336, 1.102542, -0.183331, 1.082051, 0.252984, 1.126539, -0.158797, 1.068935, 0.214990,
+ 1.149023, -0.133014, 1.058996, 0.178903, 1.167550, -0.106641, 1.050245, 0.144559, 1.179994,
+ -0.079952, 1.038648, 0.108667, 1.187104, -0.053316, 1.025284, 0.072209, 1.191406, -0.026826,
+ 1.011453, 0.035833, 1.196748, 0.000226, 1.000034, -0.000061, 0.000200, -0.000346, 3.996419,
+ 1.732034, 0.000504, -0.000873, 4.000138, 1.732038, 0.002016, -0.003492, 4.002078, 1.732012,
+ 0.004538, -0.007859, 4.005626, 1.731962, 0.008064, -0.013963, 3.998500, 1.731999, 0.012590,
+ -0.021794, 3.995024, 1.732004, 0.018154, -0.031406, 3.999233, 1.731901, 0.024727, -0.042733,
+ 3.998497, 1.731774, 0.032327, -0.055781, 3.997064, 1.731599, 0.040974, -0.070543, 3.995856,
+ 1.731325, 0.050685, -0.086984, 3.993839, 1.730945, 0.061506, -0.104897, 3.989519, 1.730417,
+ 0.073458, -0.124506, 3.985313, 1.729697, 0.086573, -0.145706, 3.979984, 1.728747, 0.100909,
+ -0.168211, 3.972562, 1.727491, 0.116509, -0.192198, 3.963836, 1.725854, 0.133404, -0.217280,
+ 3.951919, 1.723749, 0.151659, -0.243556, 3.937734, 1.721093, 0.171288, -0.270611, 3.919021,
+ 1.717640, 0.192301, -0.298389, 3.895171, 1.713272, 0.214683, -0.326338, 3.864171, 1.707825,
+ 0.238392, -0.354394, 3.824682, 1.700956, 0.263151, -0.381636, 3.771168, 1.692392, 0.289155,
+ -0.408266, 3.709961, 1.681769, 0.315832, -0.433070, 3.630302, 1.668539, 0.342942, -0.455741,
+ 3.534719, 1.652513, 0.370892, -0.476655, 3.431531, 1.633428, 0.398985, -0.494692, 3.314933,
+ 1.610694, 0.427206, -0.510313, 3.189741, 1.584240, 0.455266, -0.522760, 3.058325, 1.554195,
+ 0.483472, -0.532872, 2.927213, 1.520805, 0.511192, -0.540229, 2.794112, 1.484026, 0.538706,
+ -0.545105, 2.663786, 1.443796, 0.565422, -0.547251, 2.534841, 1.401429, 0.591270, -0.547115,
+ 2.408437, 1.356231, 0.616787, -0.545113, 2.291284, 1.308887, 0.641380, -0.540853, 2.177478,
+ 1.260447, 0.665344, -0.534561, 2.069265, 1.210634, 0.690147, -0.527115, 1.969776, 1.158569,
+ 0.714578, -0.516171, 1.870847, 1.104593, 0.740349, -0.504048, 1.782674, 1.049578, 0.764563,
+ -0.489683, 1.698614, 0.994458, 0.788710, -0.474541, 1.624447, 0.938612, 0.812154, -0.458099,
+ 1.554453, 0.883694, 0.834566, -0.440345, 1.490045, 0.830220, 0.857486, -0.422491, 1.432889,
+ 0.776499, 0.879224, -0.403588, 1.380669, 0.724257, 0.899971, -0.383819, 1.333124, 0.673311,
+ 0.922111, -0.364250, 1.292648, 0.622999, 0.942842, -0.343873, 1.253933, 0.573304, 0.964398,
+ -0.323206, 1.221027, 0.525090, 0.986860, -0.301711, 1.191806, 0.477580, 1.009760, -0.278695,
+ 1.165162, 0.430624, 1.033347, -0.255591, 1.141715, 0.384482, 1.055937, -0.232039, 1.119739,
+ 0.340532, 1.081178, -0.208664, 1.102117, 0.297311, 1.105696, -0.184935, 1.085062, 0.256227,
+ 1.129575, -0.160673, 1.070918, 0.217709, 1.152135, -0.135414, 1.060642, 0.181471, 1.171221,
+ -0.108462, 1.051041, 0.146380, 1.184412, -0.081008, 1.039694, 0.110120, 1.191820, -0.053710,
+ 1.025903, 0.073052, 1.196195, -0.026625, 1.011816, 0.036129, 1.201677, -0.000175, 0.999945,
+ 0.000098, 0.000196, -0.000360, 4.100786, 1.836290, 0.000504, -0.000925, 4.370184, 1.836295,
+ 0.002018, -0.003706, 4.385247, 1.836243, 0.004534, -0.008324, 4.370146, 1.836210, 0.008064,
+ -0.014805, 4.372335, 1.836256, 0.012597, -0.023116, 4.359918, 1.836259, 0.018158, -0.033299,
+ 4.371503, 1.836123, 0.024732, -0.045301, 4.370533, 1.835988, 0.032344, -0.059143, 4.369649,
+ 1.835768, 0.040999, -0.074779, 4.367861, 1.835454, 0.050739, -0.092178, 4.364322, 1.834974,
+ 0.061594, -0.111161, 4.359221, 1.834355, 0.073604, -0.131958, 4.354620, 1.833499, 0.086796,
+ -0.154393, 4.347915, 1.832355, 0.101246, -0.178201, 4.339152, 1.830880, 0.116990, -0.203531,
+ 4.328327, 1.828936, 0.134086, -0.230043, 4.314240, 1.826442, 0.152589, -0.257718, 4.296795,
+ 1.823230, 0.172514, -0.286176, 4.273985, 1.819124, 0.193853, -0.315295, 4.244136, 1.813909,
+ 0.216582, -0.344507, 4.205152, 1.807410, 0.240668, -0.373646, 4.154781, 1.799084, 0.265904,
+ -0.401897, 4.091563, 1.788905, 0.292226, -0.429136, 4.013199, 1.776206, 0.319045, -0.454057,
+ 3.912886, 1.760500, 0.346721, -0.477219, 3.800927, 1.741586, 0.374849, -0.497883, 3.675652,
+ 1.718818, 0.403078, -0.515504, 3.536892, 1.692138, 0.431597, -0.530621, 3.391351, 1.661434,
+ 0.460246, -0.542852, 3.242817, 1.626989, 0.488899, -0.552238, 3.093685, 1.588582, 0.517215,
+ -0.559045, 2.944163, 1.546300, 0.544480, -0.562351, 2.794189, 1.501299, 0.571542, -0.563394,
+ 2.650239, 1.453758, 0.598167, -0.562590, 2.513757, 1.403321, 0.624104, -0.559636, 2.384203,
+ 1.352431, 0.648789, -0.554148, 2.259149, 1.298758, 0.672715, -0.546779, 2.140250, 1.244943,
+ 0.696258, -0.537896, 2.030401, 1.189971, 0.720048, -0.527401, 1.928311, 1.134526, 0.744078,
+ -0.514142, 1.830175, 1.076504, 0.768895, -0.499352, 1.740731, 1.018032, 0.792551, -0.482982,
+ 1.658911, 0.960250, 0.817007, -0.466406, 1.586579, 0.903029, 0.839035, -0.447616, 1.516969,
+ 0.846484, 0.862742, -0.429261, 1.458675, 0.791420, 0.884307, -0.409479, 1.402989, 0.737125,
+ 0.905641, -0.389303, 1.352817, 0.683912, 0.926185, -0.368344, 1.306684, 0.632690, 0.947229,
+ -0.347366, 1.267395, 0.581739, 0.969502, -0.326720, 1.233192, 0.532305, 0.990758, -0.304973,
+ 1.201017, 0.484166, 1.012749, -0.282816, 1.173018, 0.437385, 1.035533, -0.259084, 1.147184,
+ 0.390755, 1.059915, -0.235239, 1.125388, 0.345399, 1.084348, -0.211044, 1.105859, 0.301356,
+ 1.109544, -0.186698, 1.088888, 0.259708, 1.133770, -0.161900, 1.073848, 0.220324, 1.157553,
+ -0.136604, 1.063190, 0.183857, 1.176461, -0.110428, 1.053110, 0.148521, 1.190137, -0.082898,
+ 1.041484, 0.112124, 1.197215, -0.054554, 1.026844, 0.074160, 1.201654, -0.026744, 1.012264,
+ 0.036527, 1.207085, 0.000399, 1.000034, -0.000201, 0.000191, -0.000373, 4.194318, 1.950551,
+ 0.000504, -0.000983, 4.804350, 1.950552, 0.002015, -0.003931, 4.802820, 1.950518, 0.004536,
+ -0.008847, 4.805254, 1.950472, 0.008064, -0.015725, 4.804152, 1.950517, 0.012693, -0.024740,
+ 4.826828, 1.949914, 0.018159, -0.035365, 4.803103, 1.950349, 0.024740, -0.048122, 4.803220,
+ 1.950183, 0.032361, -0.062822, 4.801522, 1.949917, 0.041034, -0.079430, 4.799593, 1.949538,
+ 0.050815, -0.097841, 4.797179, 1.948972, 0.061702, -0.118026, 4.789557, 1.948246, 0.073766,
+ -0.140112, 4.783293, 1.947204, 0.087066, -0.163819, 4.775698, 1.945855, 0.101637, -0.189122,
+ 4.764612, 1.944052, 0.117558, -0.215884, 4.751486, 1.941710, 0.134884, -0.243968, 4.734791,
+ 1.938727, 0.153637, -0.273170, 4.712078, 1.934891, 0.173890, -0.303146, 4.683575, 1.929976,
+ 0.195643, -0.333704, 4.646766, 1.923740, 0.218767, -0.364170, 4.596814, 1.915888, 0.243337,
+ -0.394530, 4.535509, 1.905970, 0.268860, -0.423512, 4.452006, 1.893623, 0.295173, -0.450609,
+ 4.345682, 1.878286, 0.322784, -0.476488, 4.231632, 1.859391, 0.350616, -0.499420, 4.093553,
+ 1.836912, 0.379127, -0.519862, 3.944127, 1.809625, 0.407860, -0.537373, 3.782223, 1.778529,
+ 0.436717, -0.551802, 3.615563, 1.742684, 0.465345, -0.562951, 3.440672, 1.702289, 0.494158,
+ -0.571334, 3.268070, 1.658666, 0.522896, -0.577227, 3.100668, 1.611027, 0.551379, -0.580514,
+ 2.937615, 1.559742, 0.578992, -0.580610, 2.778703, 1.507257, 0.605095, -0.577729, 2.621626,
+ 1.451941, 0.630653, -0.573000, 2.476506, 1.395218, 0.656175, -0.566944, 2.341592, 1.337862,
+ 0.681036, -0.558988, 2.216478, 1.279275, 0.704713, -0.549211, 2.096972, 1.220526, 0.726894,
+ -0.537190, 1.983311, 1.161709, 0.749865, -0.524167, 1.881100, 1.102095, 0.773553, -0.508991,
+ 1.785637, 1.042039, 0.797102, -0.491658, 1.697234, 0.981588, 0.821187, -0.474093, 1.620250,
+ 0.921265, 0.843848, -0.454980, 1.547071, 0.862757, 0.866662, -0.435421, 1.482008, 0.804700,
+ 0.888696, -0.414990, 1.424116, 0.749432, 0.910945, -0.394472, 1.372658, 0.694767, 0.932300,
+ -0.373239, 1.325157, 0.641106, 0.952850, -0.351347, 1.282217, 0.589689, 0.974718, -0.329809,
+ 1.244897, 0.539322, 0.996445, -0.307902, 1.212306, 0.490083, 1.017580, -0.285392, 1.181402,
+ 0.442702, 1.040342, -0.262782, 1.155996, 0.395911, 1.064399, -0.238995, 1.131708, 0.350206,
+ 1.089464, -0.214297, 1.111215, 0.305175, 1.115565, -0.189293, 1.093094, 0.262686, 1.140640,
+ -0.163843, 1.077994, 0.223078, 1.163824, -0.137789, 1.066014, 0.185651, 1.182577, -0.111087,
+ 1.055615, 0.150045, 1.195775, -0.083945, 1.042940, 0.113457, 1.203175, -0.056145, 1.028015,
+ 0.075453, 1.207282, -0.027685, 1.012552, 0.037217, 1.213019, 0.000362, 0.999938, -0.000293,
+ 0.000187, -0.000388, 4.316009, 2.076500, 0.000504, -0.001048, 5.317799, 2.076499, 0.002014,
+ -0.004182, 5.306557, 2.076523, 0.004539, -0.009425, 5.317505, 2.076453, 0.008063, -0.016737,
+ 5.312143, 2.076410, 0.012614, -0.026171, 5.316434, 2.076389, 0.018158, -0.037641, 5.307836,
+ 2.076265, 0.024767, -0.051266, 5.315297, 2.076044, 0.032372, -0.066859, 5.307433, 2.075743,
+ 0.041066, -0.084538, 5.304809, 2.075270, 0.050871, -0.104062, 5.299277, 2.074622, 0.061821,
+ -0.125613, 5.293419, 2.073708, 0.073970, -0.149085, 5.286629, 2.072457, 0.087375, -0.174214,
+ 5.275937, 2.070804, 0.102105, -0.201136, 5.263267, 2.068647, 0.118223, -0.229505, 5.246309,
+ 2.065846, 0.135814, -0.259217, 5.225496, 2.062189, 0.154887, -0.289990, 5.196580, 2.057566,
+ 0.175510, -0.321618, 5.160716, 2.051593, 0.197636, -0.353632, 5.112202, 2.043949, 0.221168,
+ -0.385303, 5.046981, 2.034445, 0.246099, -0.416511, 4.965386, 2.022368, 0.272070, -0.446377,
+ 4.860735, 2.007160, 0.299090, -0.474279, 4.735140, 1.988598, 0.326702, -0.499809, 4.584962,
+ 1.965865, 0.355017, -0.522790, 4.420447, 1.938705, 0.383856, -0.542755, 4.241942, 1.906370,
+ 0.413059, -0.559903, 4.053302, 1.869455, 0.441882, -0.573174, 3.852753, 1.827946, 0.471516,
+ -0.584151, 3.660377, 1.781652, 0.500872, -0.591843, 3.466027, 1.730885, 0.529677, -0.596253,
+ 3.272812, 1.676821, 0.557683, -0.597604, 3.084286, 1.620064, 0.585652, -0.596591, 2.906111,
+ 1.560909, 0.612819, -0.593138, 2.738258, 1.500318, 0.639848, -0.588245, 2.584172, 1.438127,
+ 0.664758, -0.580140, 2.430697, 1.375746, 0.688754, -0.570189, 2.290701, 1.312727, 0.712848,
+ -0.559420, 2.162679, 1.250063, 0.735111, -0.546570, 2.042186, 1.187840, 0.757521, -0.532944,
+ 1.933435, 1.125513, 0.780056, -0.517981, 1.833524, 1.063827, 0.802513, -0.500724, 1.739053,
+ 1.002154, 0.825462, -0.481625, 1.652381, 0.939811, 0.848973, -0.462327, 1.577560, 0.878279,
+ 0.871521, -0.441928, 1.509291, 0.819200, 0.892325, -0.420297, 1.443799, 0.761607, 0.914935,
+ -0.399072, 1.389647, 0.705351, 0.936429, -0.377232, 1.339903, 0.650213, 0.957614, -0.355091,
+ 1.295467, 0.597773, 0.979578, -0.332767, 1.256692, 0.545914, 1.000860, -0.310147, 1.221666,
+ 0.495661, 1.022550, -0.287395, 1.190775, 0.448026, 1.045005, -0.264582, 1.162641, 0.400490,
+ 1.068703, -0.241464, 1.138358, 0.354088, 1.093098, -0.217504, 1.115973, 0.309812, 1.119230,
+ -0.192140, 1.096284, 0.266297, 1.144608, -0.165975, 1.080042, 0.225831, 1.168599, -0.139174,
+ 1.067749, 0.187761, 1.187970, -0.111910, 1.056635, 0.151322, 1.201240, -0.083978, 1.043566,
+ 0.114337, 1.208895, -0.056089, 1.028366, 0.076083, 1.213344, -0.028369, 1.013074, 0.037735,
+ 1.219220, -0.000534, 0.999968, 0.000076, 0.000182, -0.000404, 4.433519, 2.216201, 0.000504,
+ -0.001117, 5.911693, 2.216198, 0.002017, -0.004469, 5.919142, 2.216190, 0.004536, -0.010051,
+ 5.913172, 2.216130, 0.008065, -0.017867, 5.911791, 2.216145, 0.012467, -0.027603, 5.785357,
+ 2.216447, 0.018156, -0.040159, 5.901121, 2.215958, 0.024758, -0.054670, 5.908781, 2.215654,
+ 0.032395, -0.071352, 5.906098, 2.215283, 0.041108, -0.090201, 5.902558, 2.214715, 0.050955,
+ -0.111004, 5.895707, 2.213905, 0.061968, -0.134002, 5.888736, 2.212807, 0.074206, -0.159038,
+ 5.880633, 2.211303, 0.087742, -0.185801, 5.867001, 2.209297, 0.102652, -0.214368, 5.851446,
+ 2.206657, 0.119006, -0.244573, 5.830722, 2.203232, 0.136883, -0.276067, 5.802688, 2.198778,
+ 0.156335, -0.308660, 5.767185, 2.193091, 0.177396, -0.341940, 5.719726, 2.185858, 0.200070,
+ -0.375591, 5.658792, 2.176584, 0.224067, -0.408564, 5.573508, 2.164759, 0.249420, -0.440668,
+ 5.465696, 2.149777, 0.275879, -0.471138, 5.332207, 2.131225, 0.303307, -0.499204, 5.173339,
+ 2.108794, 0.331189, -0.524547, 4.985102, 2.080585, 0.359932, -0.547256, 4.785788, 2.047792,
+ 0.389063, -0.566479, 4.569344, 2.009518, 0.418725, -0.583031, 4.349557, 1.965601, 0.448181,
+ -0.595809, 4.121278, 1.916911, 0.477703, -0.605102, 3.892291, 1.863530, 0.507999, -0.612462,
+ 3.676557, 1.806286, 0.536889, -0.615451, 3.456241, 1.745841, 0.565778, -0.616029, 3.249464,
+ 1.681137, 0.593863, -0.613644, 3.050273, 1.615238, 0.620770, -0.608268, 2.859599, 1.548003,
+ 0.647171, -0.601116, 2.683287, 1.480447, 0.673458, -0.592840, 2.524036, 1.412084, 0.698064,
+ -0.581973, 2.371046, 1.345130, 0.721011, -0.568963, 2.229104, 1.278440, 0.744293, -0.555642,
+ 2.103213, 1.212448, 0.766314, -0.540934, 1.985370, 1.146287, 0.788164, -0.525271, 1.878842,
+ 1.082600, 0.809019, -0.507986, 1.779821, 1.019978, 0.830947, -0.489717, 1.691630, 0.956931,
+ 0.853732, -0.469345, 1.607513, 0.894207, 0.874904, -0.447618, 1.531176, 0.833436, 0.897289,
+ -0.426124, 1.467302, 0.773611, 0.919226, -0.404025, 1.408321, 0.716016, 0.940860, -0.381454,
+ 1.356209, 0.659515, 0.962764, -0.358901, 1.310082, 0.604629, 0.984322, -0.335983, 1.268485,
+ 0.552335, 1.005343, -0.312533, 1.230662, 0.501591, 1.028153, -0.289452, 1.199168, 0.452032,
+ 1.049283, -0.265754, 1.168575, 0.404347, 1.073687, -0.242571, 1.143533, 0.357445, 1.097546,
+ -0.218681, 1.119859, 0.312534, 1.123340, -0.194465, 1.099634, 0.269437, 1.148166, -0.168797,
+ 1.081968, 0.228586, 1.172518, -0.141552, 1.068789, 0.189866, 1.192930, -0.113325, 1.057548,
+ 0.152772, 1.206816, -0.084800, 1.044145, 0.115390, 1.215045, -0.056019, 1.028938, 0.076493,
+ 1.220048, -0.027733, 1.013338, 0.037767, 1.225852, 0.000050, 0.999927, -0.000160, 0.000178,
+ -0.000422, 4.587902, 2.372253, 0.000504, -0.001195, 6.624675, 2.372248, 0.002016, -0.004782,
+ 6.626884, 2.372187, 0.004531, -0.010746, 6.607379, 2.372318, 0.008081, -0.019161, 6.640102,
+ 2.372084, 0.012637, -0.029945, 6.653708, 2.372128, 0.018167, -0.042999, 6.623837, 2.371902,
+ 0.024769, -0.058516, 6.624484, 2.371595, 0.032421, -0.076370, 6.620877, 2.371120, 0.041164,
+ -0.096474, 6.615235, 2.370428, 0.051057, -0.118786, 6.607844, 2.369440, 0.062136, -0.143390,
+ 6.599216, 2.368075, 0.074490, -0.170034, 6.588018, 2.366218, 0.088179, -0.198717, 6.572526,
+ 2.363747, 0.103307, -0.229147, 6.551868, 2.360517, 0.119964, -0.261253, 6.526089, 2.356304,
+ 0.138173, -0.294703, 6.489593, 2.350797, 0.158072, -0.329261, 6.443573, 2.343783, 0.179592,
+ -0.364298, 6.379764, 2.334673, 0.202709, -0.399375, 6.295845, 2.323125, 0.227335, -0.433616,
+ 6.184929, 2.308547, 0.253230, -0.466794, 6.045905, 2.289980, 0.280100, -0.497509, 5.871803,
+ 2.266964, 0.308146, -0.525956, 5.672422, 2.239074, 0.336544, -0.551101, 5.443256, 2.204809,
+ 0.365223, -0.572471, 5.188034, 2.164827, 0.395484, -0.592088, 4.943783, 2.119489, 0.424416,
+ -0.606026, 4.666400, 2.067262, 0.455641, -0.619671, 4.418961, 2.009937, 0.485298, -0.627583,
+ 4.152737, 1.948900, 0.514774, -0.632072, 3.893344, 1.882692, 0.544172, -0.634033, 3.645332,
+ 1.814073, 0.573283, -0.633239, 3.414651, 1.742717, 0.602155, -0.630008, 3.195712, 1.669703,
+ 0.630520, -0.624550, 2.994536, 1.596021, 0.657121, -0.615749, 2.799373, 1.522572, 0.682071,
+ -0.604738, 2.616102, 1.448978, 0.707605, -0.593301, 2.456112, 1.376250, 0.731492, -0.579628,
+ 2.303517, 1.305297, 0.754139, -0.564473, 2.165340, 1.235548, 0.776505, -0.548787, 2.041646,
+ 1.167051, 0.796833, -0.531415, 1.923334, 1.100534, 0.817565, -0.513778, 1.818176, 1.035144,
+ 0.837981, -0.495167, 1.723830, 0.971583, 0.858513, -0.475690, 1.638448, 0.908841, 0.879892,
+ -0.454099, 1.559420, 0.846701, 0.902258, -0.432038, 1.491471, 0.785332, 0.924114, -0.409316,
+ 1.428878, 0.726409, 0.944230, -0.385618, 1.370785, 0.668588, 0.967001, -0.362604, 1.323529,
+ 0.612943, 0.988579, -0.339117, 1.279679, 0.559038, 1.010210, -0.315355, 1.240104, 0.506867,
+ 1.032084, -0.291408, 1.205261, 0.456934, 1.054671, -0.267387, 1.175197, 0.407792, 1.078314,
+ -0.243346, 1.148153, 0.360992, 1.102443, -0.219205, 1.123799, 0.315577, 1.128524, -0.194996,
+ 1.102624, 0.271742, 1.153989, -0.169897, 1.085134, 0.230702, 1.179420, -0.143960, 1.071699,
+ 0.192146, 1.200098, -0.116173, 1.060179, 0.155164, 1.214837, -0.086655, 1.046290, 0.117071,
+ 1.222749, -0.056956, 1.030040, 0.077450, 1.227273, -0.027883, 1.013650, 0.038092, 1.233293,
+ 0.000831, 1.000043, -0.000462, 0.000173, -0.000442, 4.741539, 2.547922, 0.000504, -0.001284,
+ 7.491127, 2.547919, 0.002014, -0.005132, 7.484889, 2.547844, 0.004523, -0.011521, 7.439875,
+ 2.547587, 0.008059, -0.020524, 7.483694, 2.547725, 0.012586, -0.032029, 7.470912, 2.547685,
+ 0.018081, -0.045948, 7.422534, 2.547686, 0.024783, -0.062844, 7.487581, 2.547107, 0.032451,
+ -0.082011, 7.483603, 2.546522, 0.041233, -0.103540, 7.475124, 2.545684, 0.051181, -0.127537,
+ 7.467521, 2.544438, 0.062347, -0.153921, 7.456266, 2.542744, 0.074829, -0.182427, 7.440422,
+ 2.540459, 0.088703, -0.213134, 7.420694, 2.537380, 0.104080, -0.245750, 7.394875, 2.533347,
+ 0.121050, -0.279941, 7.358515, 2.528069, 0.139697, -0.315591, 7.313001, 2.521237, 0.160036,
+ -0.351980, 7.246342, 2.512378, 0.182147, -0.388993, 7.163688, 2.500993, 0.205799, -0.425570,
+ 7.048339, 2.486450, 0.231091, -0.461093, 6.902586, 2.468174, 0.257405, -0.494668, 6.712721,
+ 2.444774, 0.284956, -0.525889, 6.491261, 2.415538, 0.313180, -0.553693, 6.232833, 2.380610,
+ 0.342327, -0.578724, 5.953834, 2.338525, 0.371689, -0.599706, 5.649698, 2.290256, 0.401919,
+ -0.617615, 5.347900, 2.235157, 0.432204, -0.631632, 5.036417, 2.173932, 0.463151, -0.643082,
+ 4.735976, 2.107298, 0.493388, -0.649970, 4.432044, 2.036121, 0.524128, -0.654188, 4.145472,
+ 1.961595, 0.553930, -0.654671, 3.866877, 1.883602, 0.583856, -0.653051, 3.607848, 1.804521,
+ 0.611762, -0.646994, 3.356237, 1.724047, 0.639117, -0.638860, 3.122531, 1.643016, 0.666279,
+ -0.629093, 2.913178, 1.563932, 0.692936, -0.617862, 2.722675, 1.484614, 0.716498, -0.603279,
+ 2.536926, 1.406734, 0.742273, -0.589878, 2.381054, 1.331469, 0.764031, -0.572744, 2.228312,
+ 1.256796, 0.786601, -0.555933, 2.095451, 1.185290, 0.807776, -0.537992, 1.972866, 1.115940,
+ 0.828400, -0.519596, 1.863394, 1.048371, 0.847412, -0.499847, 1.760630, 0.982934, 0.866850,
+ -0.479920, 1.670998, 0.919972, 0.886340, -0.459434, 1.587962, 0.858100, 0.906933, -0.437767,
+ 1.515505, 0.796714, 0.927490, -0.414068, 1.448243, 0.736162, 0.950217, -0.390910, 1.390505,
+ 0.677613, 0.971545, -0.366964, 1.337865, 0.620477, 0.992901, -0.342603, 1.291104, 0.565807,
+ 1.015460, -0.318596, 1.251138, 0.513086, 1.037859, -0.294242, 1.214291, 0.461573, 1.060535,
+ -0.269601, 1.182517, 0.411838, 1.086885, -0.245608, 1.155300, 0.363221, 1.111237, -0.220589,
+ 1.129715, 0.317174, 1.138718, -0.196008, 1.108103, 0.273213, 1.164223, -0.170408, 1.089640,
+ 0.231968, 1.187256, -0.144205, 1.074145, 0.192987, 1.207851, -0.116945, 1.061615, 0.156118,
+ 1.222217, -0.088852, 1.047599, 0.118674, 1.230315, -0.059381, 1.030869, 0.078993, 1.235052,
+ -0.029145, 1.014126, 0.038924, 1.241359, 0.000479, 1.000114, -0.000211, 0.000169, -0.000465,
+ 4.953966, 2.747437, 0.000504, -0.001384, 8.544530, 2.747430, 0.002015, -0.005537, 8.545147,
+ 2.747339, 0.004542, -0.012477, 8.557734, 2.747125, 0.008064, -0.022143, 8.530193, 2.747341,
+ 0.012543, -0.034411, 8.465151, 2.747411, 0.018178, -0.049792, 8.543328, 2.746874, 0.024810,
+ -0.067784, 8.547247, 2.746396, 0.032489, -0.088416, 8.537436, 2.745730, 0.041313, -0.111580,
+ 8.526655, 2.744596, 0.051332, -0.137462, 8.517438, 2.743082, 0.062603, -0.165860, 8.502803,
+ 2.740950, 0.075240, -0.196548, 8.481507, 2.738057, 0.089341, -0.229440, 8.454287, 2.734174,
+ 0.105021, -0.264395, 8.420289, 2.729086, 0.122399, -0.301020, 8.373503, 2.722420, 0.141526,
+ -0.338997, 8.309059, 2.713686, 0.162451, -0.377589, 8.221539, 2.702492, 0.185098, -0.416349,
+ 8.100116, 2.687893, 0.209406, -0.454284, 7.941704, 2.669386, 0.235098, -0.490450, 7.733318,
+ 2.645590, 0.262100, -0.524592, 7.486120, 2.615709, 0.290103, -0.555558, 7.193498, 2.579231,
+ 0.319135, -0.583516, 6.874796, 2.534957, 0.348286, -0.606714, 6.516118, 2.483017, 0.378840,
+ -0.627850, 6.163912, 2.424214, 0.409608, -0.644715, 5.801404, 2.357563, 0.440553, -0.657657,
+ 5.435955, 2.285835, 0.470599, -0.665621, 5.063481, 2.207940, 0.503172, -0.673767, 4.743532,
+ 2.126440, 0.533884, -0.676009, 4.413409, 2.040694, 0.563808, -0.674536, 4.092169, 1.953979,
+ 0.591849, -0.668913, 3.787057, 1.865897, 0.621474, -0.663159, 3.520578, 1.777762, 0.650500,
+ -0.655018, 3.275065, 1.689902, 0.678011, -0.643949, 3.043141, 1.603528, 0.703490, -0.630030,
+ 2.827104, 1.519484, 0.728250, -0.614910, 2.632620, 1.436677, 0.752165, -0.598649, 2.455570,
+ 1.355753, 0.775894, -0.581771, 2.295932, 1.278884, 0.797650, -0.563193, 2.152291, 1.202767,
+ 0.818505, -0.543750, 2.022099, 1.130338, 0.838596, -0.524017, 1.903562, 1.060263, 0.858396,
+ -0.504064, 1.797204, 0.993077, 0.877088, -0.483418, 1.701208, 0.928606, 0.896606, -0.462786,
+ 1.617736, 0.866039, 0.914342, -0.440943, 1.539227, 0.804293, 0.933550, -0.419129, 1.470383,
+ 0.745206, 0.955237, -0.396100, 1.409100, 0.685832, 0.976700, -0.371743, 1.354930, 0.627953,
+ 0.997681, -0.346882, 1.305249, 0.572127, 1.020784, -0.322391, 1.262603, 0.517941, 1.043840,
+ -0.297564, 1.225115, 0.466188, 1.067224, -0.272639, 1.190817, 0.415499, 1.092358, -0.247664,
+ 1.161265, 0.366782, 1.117573, -0.222260, 1.133935, 0.319377, 1.145730, -0.196933, 1.111750,
+ 0.275293, 1.170822, -0.170577, 1.091981, 0.233306, 1.194559, -0.143878, 1.075810, 0.193950,
+ 1.214819, -0.116347, 1.062438, 0.156724, 1.229830, -0.088233, 1.048092, 0.118984, 1.238185,
+ -0.059408, 1.031325, 0.079385, 1.243527, -0.030703, 1.014698, 0.039893, 1.249724, -0.001520,
+ 0.999819, 0.000760, 0.000164, -0.000489, 5.157359, 2.976300, 0.000505, -0.001502, 9.891415,
+ 2.976286, 0.002016, -0.006000, 9.857730, 2.976197, 0.004543, -0.013519, 9.870651, 2.975832,
+ 0.008064, -0.023985, 9.855780, 2.976170, 0.012611, -0.037471, 9.850209, 2.975941, 0.018162,
+ -0.053866, 9.827134, 2.974968, 0.024820, -0.073390, 9.849955, 2.975010, 0.032545, -0.095758,
+ 9.842021, 2.974073, 0.041418, -0.120834, 9.829989, 2.972700, 0.051511, -0.148861, 9.817421,
+ 2.970736, 0.062920, -0.179456, 9.797347, 2.968033, 0.075744, -0.212674, 9.771533, 2.964371,
+ 0.090131, -0.248193, 9.735924, 2.959437, 0.106187, -0.285748, 9.687707, 2.952881, 0.124035,
+ -0.325017, 9.622684, 2.944273, 0.143733, -0.365463, 9.531452, 2.933093, 0.165262, -0.406157,
+ 9.401732, 2.918484, 0.188622, -0.446833, 9.232451, 2.899529, 0.213693, -0.486209, 9.013432,
+ 2.875137, 0.239987, -0.522925, 8.725671, 2.844166, 0.267796, -0.557452, 8.400028, 2.805649,
+ 0.296547, -0.588266, 8.023041, 2.758720, 0.325838, -0.614837, 7.606773, 2.702676, 0.355479,
+ -0.636760, 7.160680, 2.638483, 0.386984, -0.657230, 6.736765, 2.566849, 0.418853, -0.673592,
+ 6.313742, 2.488091, 0.450302, -0.684966, 5.884479, 2.402458, 0.481149, -0.691591, 5.455771,
+ 2.311816, 0.512177, -0.695337, 5.055698, 2.217330, 0.543437, -0.696370, 4.681506, 2.121285,
+ 0.574309, -0.694186, 4.334716, 2.024160, 0.604787, -0.689158, 4.008524, 1.927738, 0.633483,
+ -0.680580, 3.703505, 1.830456, 0.660766, -0.669088, 3.418386, 1.734934, 0.688471, -0.656673,
+ 3.168101, 1.642316, 0.715729, -0.642820, 2.941735, 1.550744, 0.740435, -0.626155, 2.730570,
+ 1.463345, 0.764114, -0.608299, 2.537561, 1.378151, 0.787028, -0.589519, 2.364323, 1.297630,
+ 0.807985, -0.569257, 2.207970, 1.217830, 0.830663, -0.550055, 2.076646, 1.142746, 0.850416,
+ -0.528812, 1.948085, 1.070757, 0.869609, -0.507478, 1.834684, 1.001282, 0.888324, -0.486131,
+ 1.734879, 0.934987, 0.907482, -0.464910, 1.645974, 0.871203, 0.924829, -0.442742, 1.563550,
+ 0.809260, 0.942958, -0.420777, 1.491264, 0.750037, 0.961999, -0.398842, 1.428069, 0.691715,
+ 0.981043, -0.375967, 1.369668, 0.635669, 1.002371, -0.351469, 1.318588, 0.578689, 1.025343,
+ -0.326601, 1.273628, 0.524424, 1.048511, -0.301395, 1.234572, 0.471403, 1.072242, -0.275835,
+ 1.198354, 0.419950, 1.096758, -0.250200, 1.166392, 0.370733, 1.122781, -0.224474, 1.138991,
+ 0.322864, 1.150871, -0.198592, 1.114313, 0.277723, 1.177319, -0.171805, 1.093534, 0.234950,
+ 1.201765, -0.144291, 1.077462, 0.195376, 1.222629, -0.115949, 1.063288, 0.157315, 1.237334,
+ -0.087140, 1.048366, 0.118843, 1.246153, -0.058094, 1.031224, 0.079207, 1.252570, -0.029194,
+ 1.014695, 0.039376, 1.259060, -0.000418, 0.999881, 0.000307, 0.000159, -0.000515, 5.393984,
+ 3.241865, 0.000505, -0.001636, 11.548038, 3.241848, 0.002016, -0.006534, 11.506640, 3.241718,
+ 0.004537, -0.014706, 11.513460, 3.241196, 0.008068, -0.026134, 11.510533, 3.241693, 0.012573,
+ -0.040676, 11.428978, 3.241030, 0.018212, -0.058794, 11.510745, 3.240924, 0.024847, -0.079926,
+ 11.497339, 3.240201, 0.032603, -0.104160, 11.484607, 3.238994, 0.041543, -0.131552, 11.470801,
+ 3.237182, 0.051738, -0.162012, 11.453219, 3.234635, 0.063313, -0.195260, 11.427244, 3.231153,
+ 0.076381, -0.231205, 11.388534, 3.226361, 0.091096, -0.269678, 11.340406, 3.219943, 0.107600,
+ -0.310170, 11.270127, 3.211448, 0.126017, -0.352435, 11.178583, 3.200168, 0.146411, -0.395551,
+ 11.046559, 3.185328, 0.168663, -0.438627, 10.858624, 3.165972, 0.192730, -0.480660, 10.606379,
+ 3.140735, 0.218497, -0.520987, 10.288093, 3.108388, 0.245752, -0.558483, 9.907480, 3.067586,
+ 0.273993, -0.592090, 9.453246, 3.016931, 0.303495, -0.622416, 8.966138, 2.956444, 0.333717,
+ -0.648303, 8.443776, 2.885116, 0.363928, -0.668640, 7.894122, 2.805963, 0.396240, -0.687748,
+ 7.385728, 2.718338, 0.427161, -0.699903, 6.838511, 2.622346, 0.460175, -0.711210, 6.356371,
+ 2.522476, 0.492593, -0.717734, 5.878312, 2.417984, 0.524449, -0.719956, 5.423285, 2.310941,
+ 0.556010, -0.719127, 4.997909, 2.201885, 0.587032, -0.715077, 4.600426, 2.093330, 0.617030,
+ -0.707574, 4.235885, 1.986585, 0.644684, -0.695781, 3.881712, 1.881279, 0.674483, -0.685313,
+ 3.590960, 1.777918, 0.700290, -0.669619, 3.303138, 1.678004, 0.727892, -0.654728, 3.057771,
+ 1.581162, 0.751694, -0.635727, 2.826642, 1.487769, 0.776271, -0.617343, 2.622178, 1.399628,
+ 0.799502, -0.597683, 2.441265, 1.313195, 0.821768, -0.577090, 2.276954, 1.232316, 0.841960,
+ -0.555165, 2.125744, 1.153914, 0.861582, -0.532983, 1.991236, 1.079598, 0.881460, -0.510933,
+ 1.874027, 1.008883, 0.899952, -0.488321, 1.766812, 0.940802, 0.918954, -0.466405, 1.673436,
+ 0.875653, 0.936130, -0.443623, 1.586986, 0.813130, 0.954799, -0.421532, 1.513558, 0.752241,
+ 0.972435, -0.398897, 1.445787, 0.694711, 0.990147, -0.376302, 1.384382, 0.638770, 1.009189,
+ -0.353623, 1.331934, 0.583826, 1.029687, -0.330635, 1.284478, 0.530476, 1.052604, -0.305698,
+ 1.243632, 0.477187, 1.076524, -0.279917, 1.204997, 0.425349, 1.101701, -0.253951, 1.171750,
+ 0.375165, 1.127264, -0.227541, 1.142519, 0.326869, 1.156397, -0.201265, 1.116817, 0.280912,
+ 1.183020, -0.173943, 1.095289, 0.237447, 1.208448, -0.145860, 1.078296, 0.196694, 1.230417,
+ -0.116901, 1.064416, 0.158409, 1.248617, -0.087507, 1.050504, 0.119483, 1.257310, -0.057353,
+ 1.032796, 0.079092, 1.263076, -0.027785, 1.015128, 0.038883, 1.269870, 0.001331, 0.999935,
+ -0.000557, 0.000154, -0.000549, 5.705205, 3.554136, 0.000506, -0.001797, 13.703335, 3.554133,
+ 0.002014, -0.007156, 13.614074, 3.553937, 0.004544, -0.016145, 13.657344, 3.553096, 0.008070,
+ -0.028652, 13.627997, 3.553894, 0.012584, -0.044617, 13.606235, 3.554000, 0.018180, -0.064288,
+ 13.581339, 3.549637, 0.024887, -0.087627, 13.608851, 3.552006, 0.032690, -0.114134, 13.599099,
+ 3.550341, 0.041705, -0.144154, 13.579829, 3.547982, 0.052035, -0.177400, 13.552845, 3.544641,
+ 0.063810, -0.213813, 13.515619, 3.539941, 0.077171, -0.252978, 13.460460, 3.533696, 0.092329,
+ -0.294852, 13.393559, 3.524977, 0.109390, -0.338688, 13.292376, 3.513655, 0.128455, -0.384018,
+ 13.147332, 3.498484, 0.149661, -0.429960, 12.945774, 3.478323, 0.172694, -0.475024, 12.658979,
+ 3.451862, 0.197650, -0.518614, 12.289564, 3.417602, 0.224156, -0.559298, 11.828307, 3.372913,
+ 0.252008, -0.596110, 11.285162, 3.317454, 0.281165, -0.629292, 10.684922, 3.251171, 0.311434,
+ -0.658379, 10.052939, 3.172222, 0.342741, -0.683455, 9.405296, 3.082825, 0.373543, -0.701674,
+ 8.716078, 2.983976, 0.407008, -0.719664, 8.108425, 2.876244, 0.438623, -0.729882, 7.461252,
+ 2.763279, 0.471872, -0.738696, 6.880182, 2.645590, 0.504700, -0.743136, 6.324308, 2.524680,
+ 0.537118, -0.743676, 5.808302, 2.402723, 0.569412, -0.741181, 5.332306, 2.281437, 0.598202,
+ -0.732348, 4.857402, 2.161401, 0.629640, -0.724832, 4.465554, 2.043872, 0.659239, -0.713435,
+ 4.093661, 1.930129, 0.686547, -0.698539, 3.752593, 1.817654, 0.715529, -0.684471, 3.457593,
+ 1.712567, 0.739456, -0.664983, 3.171220, 1.610687, 0.764892, -0.646322, 2.929674, 1.512031,
+ 0.789301, -0.626393, 2.710719, 1.419033, 0.809881, -0.603498, 2.506139, 1.330115, 0.833385,
+ -0.582934, 2.336089, 1.245859, 0.854254, -0.560419, 2.178470, 1.165042, 0.873964, -0.537294,
+ 2.040087, 1.086633, 0.893433, -0.514264, 1.911969, 1.015028, 0.911756, -0.490657, 1.799840,
+ 0.944938, 0.930894, -0.467601, 1.703188, 0.878743, 0.948078, -0.444043, 1.612092, 0.815356,
+ 0.966162, -0.421155, 1.534444, 0.753883, 0.984166, -0.398238, 1.462397, 0.695534, 1.002184,
+ -0.375278, 1.400793, 0.638806, 1.019669, -0.352159, 1.344172, 0.584549, 1.039571, -0.329651,
+ 1.295227, 0.531660, 1.059989, -0.306804, 1.251281, 0.480529, 1.081116, -0.283345, 1.211504,
+ 0.430071, 1.105742, -0.258568, 1.176400, 0.380277, 1.133080, -0.232146, 1.144519, 0.331076,
+ 1.161888, -0.205244, 1.118059, 0.284040, 1.192408, -0.177932, 1.097561, 0.239958, 1.221043,
+ -0.149532, 1.082021, 0.198751, 1.244141, -0.120046, 1.067634, 0.160114, 1.259465, -0.089542,
+ 1.051626, 0.121101, 1.268124, -0.058593, 1.033296, 0.079898, 1.274330, -0.028011, 1.015382,
+ 0.039038, 1.281590, 0.002330, 1.000087, -0.001259, 0.000149, -0.000587, 6.059834, 3.927143,
+ 0.000507, -0.001992, 16.560400, 3.927149, 0.002014, -0.007910, 16.406326, 3.926821, 0.004549,
+ -0.017856, 16.545532, 3.927027, 0.008064, -0.031632, 16.375853, 3.925487, 0.012450, -0.048749,
+ 15.928564, 3.928272, 0.018030, -0.070371, 16.072989, 3.917862, 0.024964, -0.096897, 16.458925,
+ 3.924489, 0.032807, -0.126073, 16.377851, 3.921896, 0.041917, -0.159205, 16.351561, 3.918860,
+ 0.052416, -0.195762, 16.307037, 3.914339, 0.064464, -0.235784, 16.255514, 3.907954, 0.078225,
+ -0.278812, 16.176226, 3.899254, 0.093900, -0.324457, 16.066530, 3.887455, 0.111657, -0.372174,
+ 15.913818, 3.871777, 0.131478, -0.420530, 15.669197, 3.850776, 0.153574, -0.469330, 15.355453,
+ 3.822348, 0.177505, -0.516029, 14.908978, 3.785168, 0.203383, -0.560585, 14.352687, 3.736602,
+ 0.230569, -0.600607, 13.666022, 3.675046, 0.259188, -0.636296, 12.900244, 3.599811, 0.289272,
+ -0.668312, 12.111226, 3.510550, 0.320490, -0.695986, 11.292102, 3.408535, 0.353031, -0.719848,
+ 10.493485, 3.295667, 0.385228, -0.737073, 9.661955, 3.171998, 0.419219, -0.752419, 8.909942,
+ 3.042428, 0.452096, -0.761179, 8.155107, 2.907108, 0.484909, -0.766166, 7.450609, 2.769858,
+ 0.518306, -0.768596, 6.811866, 2.631935, 0.550067, -0.765683, 6.205275, 2.492870, 0.582562,
+ -0.761197, 5.663215, 2.358645, 0.614450, -0.753834, 5.165358, 2.227377, 0.644563, -0.742860,
+ 4.712554, 2.097547, 0.673658, -0.729294, 4.306101, 1.974920, 0.702857, -0.714839, 3.943352,
+ 1.857613, 0.729350, -0.696774, 3.609432, 1.743601, 0.754958, -0.677394, 3.308389, 1.636607,
+ 0.779575, -0.657018, 3.043803, 1.533841, 0.800491, -0.633342, 2.793592, 1.437092, 0.825030,
+ -0.612471, 2.590307, 1.344272, 0.847535, -0.589882, 2.406477, 1.256436, 0.865979, -0.564850,
+ 2.231999, 1.173938, 0.886254, -0.541357, 2.083556, 1.094722, 0.905566, -0.517353, 1.950928,
+ 1.021107, 0.924607, -0.493320, 1.835979, 0.948941, 0.943365, -0.469366, 1.731417, 0.881060,
+ 0.960405, -0.444745, 1.635838, 0.816479, 0.977893, -0.420493, 1.552981, 0.754604, 0.996573,
+ -0.397150, 1.481595, 0.694917, 1.014000, -0.373483, 1.414070, 0.638445, 1.031807, -0.349985,
+ 1.356031, 0.584035, 1.051877, -0.327062, 1.305041, 0.530010, 1.071701, -0.304134, 1.258836,
+ 0.479439, 1.093109, -0.280962, 1.217297, 0.429763, 1.116681, -0.258121, 1.182063, 0.381050,
+ 1.143886, -0.235365, 1.150039, 0.333395, 1.175163, -0.211621, 1.125074, 0.287477, 1.203675,
+ -0.184061, 1.102339, 0.243301, 1.230477, -0.154815, 1.083927, 0.201826, 1.253134, -0.124513,
+ 1.067989, 0.162271, 1.270092, -0.093383, 1.052032, 0.122855, 1.279576, -0.061770, 1.033685,
+ 0.081639, 1.286472, -0.030317, 1.015583, 0.040411, 1.294476, 0.000964, 1.000206, -0.000454,
+ 0.000144, -0.000630, 6.467978, 4.381146, 0.000504, -0.002208, 20.193617, 4.381151, 0.002017,
+ -0.008834, 20.206446, 4.380687, 0.004536, -0.019864, 20.183254, 4.380550, 0.008174, -0.035759,
+ 20.564249, 4.381247, 0.012608, -0.055034, 20.111612, 4.382390, 0.018198, -0.079119, 20.106096,
+ 4.379815, 0.025057, -0.108067, 20.215635, 4.376874, 0.032962, -0.140630, 20.153549, 4.374143,
+ 0.042199, -0.177350, 20.084061, 4.369558, 0.052928, -0.218094, 20.026609, 4.363287, 0.065327,
+ -0.262407, 19.940054, 4.354386, 0.079568, -0.309833, 19.806814, 4.342127, 0.095961, -0.360074,
+ 19.641878, 4.325533, 0.114516, -0.411747, 19.370914, 4.302950, 0.135349, -0.463726, 18.983900,
+ 4.271991, 0.158293, -0.514211, 18.433926, 4.230856, 0.183348, -0.562511, 17.733471, 4.176250,
+ 0.209959, -0.606310, 16.864214, 4.105895, 0.238736, -0.646958, 15.935207, 4.020104, 0.268543,
+ -0.681574, 14.890014, 3.916094, 0.299996, -0.712458, 13.846786, 3.798239, 0.331930, -0.737130,
+ 12.758296, 3.664191, 0.365222, -0.758156, 11.732940, 3.521867, 0.399061, -0.774364, 10.741743,
+ 3.369831, 0.433480, -0.786412, 9.812527, 3.212079, 0.467002, -0.792373, 8.915130, 3.053715,
+ 0.500754, -0.795410, 8.094276, 2.894526, 0.534023, -0.794617, 7.342067, 2.735959, 0.566988,
+ -0.790689, 6.664186, 2.581160, 0.599960, -0.784433, 6.052983, 2.432318, 0.630599, -0.773378,
+ 5.486277, 2.287630, 0.660807, -0.760334, 4.982516, 2.150183, 0.690103, -0.745430, 4.531104,
+ 2.017266, 0.717315, -0.727511, 4.120734, 1.891699, 0.743819, -0.708376, 3.759599, 1.772680,
+ 0.770147, -0.688632, 3.441912, 1.660620, 0.793510, -0.665931, 3.152600, 1.553166, 0.816535,
+ -0.643045, 2.898883, 1.452080, 0.839163, -0.619917, 2.674488, 1.355544, 0.859066, -0.594923,
+ 2.469262, 1.267232, 0.879489, -0.570343, 2.292209, 1.181702, 0.898525, -0.544975, 2.131086,
+ 1.102089, 0.918359, -0.520585, 1.994526, 1.024744, 0.937502, -0.496044, 1.873079, 0.951712,
+ 0.955573, -0.471010, 1.761232, 0.883374, 0.972957, -0.445712, 1.661604, 0.818008, 0.991248,
+ -0.421201, 1.577169, 0.754446, 1.008997, -0.396444, 1.499653, 0.694518, 1.028127, -0.372362,
+ 1.432030, 0.637259, 1.045710, -0.347895, 1.369870, 0.581515, 1.065977, -0.324409, 1.317341,
+ 0.527713, 1.087469, -0.301181, 1.270447, 0.476281, 1.109943, -0.277866, 1.228398, 0.426403,
+ 1.134440, -0.254849, 1.190986, 0.377822, 1.160986, -0.231754, 1.157681, 0.330740, 1.188458,
+ -0.207973, 1.128665, 0.286014, 1.214405, -0.183424, 1.103711, 0.243600, 1.239504, -0.157972,
+ 1.084253, 0.203686, 1.262961, -0.130607, 1.068258, 0.165214, 1.280340, -0.099652, 1.051919,
+ 0.126067, 1.292129, -0.067363, 1.034016, 0.084791, 1.299876, -0.035026, 1.015775, 0.042786,
+ 1.308328, -0.002944, 0.999963, 0.001385, 0.000138, -0.000681, 6.943771, 4.946556, 0.000503,
+ -0.002486, 25.346689, 4.946532, 0.002016, -0.009973, 25.494320, 4.946311, 0.004539, -0.022440,
+ 25.484949, 4.945823, 0.008069, -0.039836, 25.420902, 4.945311, 0.012628, -0.062172, 25.394403,
+ 4.945041, 0.018294, -0.089609, 25.440279, 4.943295, 0.025079, -0.121584, 25.399988, 4.939368,
+ 0.033142, -0.158595, 25.356537, 4.936200, 0.042596, -0.199971, 25.295067, 4.929842, 0.053628,
+ -0.245624, 25.196465, 4.920586, 0.066496, -0.295240, 25.055311, 4.907700, 0.081434, -0.348006,
+ 24.846170, 4.889647, 0.098640, -0.403167, 24.527803, 4.864680, 0.118231, -0.459106, 24.051735,
+ 4.830574, 0.140139, -0.513907, 23.352467, 4.783530, 0.164198, -0.565953, 22.418245, 4.720530,
+ 0.190502, -0.614858, 21.324049, 4.638075, 0.218530, -0.658304, 20.038671, 4.535464, 0.248094,
+ -0.696133, 18.639786, 4.411646, 0.279435, -0.729388, 17.234526, 4.268872, 0.312002, -0.757534,
+ 15.830426, 4.109603, 0.346173, -0.781866, 14.495901, 3.938782, 0.379435, -0.797579, 13.136444,
+ 3.756138, 0.414945, -0.812334, 11.946491, 3.571258, 0.449991, -0.821119, 10.811908, 3.384217,
+ 0.484636, -0.825066, 9.763482, 3.198076, 0.518675, -0.824728, 8.796811, 3.015808, 0.552559,
+ -0.821710, 7.932528, 2.836886, 0.587272, -0.817478, 7.185156, 2.664995, 0.616960, -0.804441,
+ 6.445302, 2.502223, 0.648054, -0.792063, 5.818812, 2.345851, 0.678575, -0.777793, 5.264731,
+ 2.197150, 0.707287, -0.760476, 4.766033, 2.056042, 0.735851, -0.742541, 4.335871, 1.922805,
+ 0.760594, -0.720503, 3.928021, 1.798585, 0.784534, -0.697719, 3.579153, 1.680605, 0.811029,
+ -0.677036, 3.285307, 1.568942, 0.831809, -0.651479, 3.001423, 1.465496, 0.854364, -0.627376,
+ 2.760672, 1.367849, 0.872639, -0.600496, 2.540697, 1.275644, 0.894296, -0.576297, 2.355273,
+ 1.188638, 0.913123, -0.550377, 2.188563, 1.105652, 0.932025, -0.524640, 2.040739, 1.028614,
+ 0.949876, -0.498402, 1.910315, 0.954421, 0.968933, -0.473220, 1.795750, 0.884061, 0.985366,
+ -0.447086, 1.690336, 0.817765, 1.004940, -0.422394, 1.599626, 0.753295, 1.022217, -0.396726,
+ 1.519055, 0.693380, 1.041490, -0.371854, 1.448745, 0.635747, 1.059920, -0.346769, 1.384292,
+ 0.579508, 1.080408, -0.322343, 1.328798, 0.525045, 1.101632, -0.297979, 1.279898, 0.473773,
+ 1.124812, -0.274059, 1.234005, 0.422949, 1.148503, -0.249954, 1.195373, 0.374609, 1.174554,
+ -0.225988, 1.160362, 0.327350, 1.202931, -0.201932, 1.131307, 0.283494, 1.229335, -0.176886,
+ 1.105885, 0.241092, 1.254254, -0.151225, 1.085802, 0.201514, 1.275743, -0.124282, 1.068524,
+ 0.162866, 1.292929, -0.097122, 1.051493, 0.124991, 1.305805, -0.068939, 1.033890, 0.085521,
+ 1.314991, -0.040082, 1.015927, 0.045247, 1.324033, -0.009923, 0.999893, 0.004738, 0.000131,
+ -0.000745, 7.562414, 5.671075, 0.000473, -0.002681, 27.216688, 5.670949, 0.002021, -0.011462,
+ 32.962402, 5.670177, 0.004540, -0.025728, 33.183949, 5.670197, 0.008087, -0.045746, 33.185688,
+ 5.667313, 0.012673, -0.071427, 33.170441, 5.668396, 0.018358, -0.102673, 33.145138, 5.665252,
+ 0.025299, -0.139780, 33.303326, 5.653404, 0.033469, -0.181718, 33.107243, 5.652829, 0.043139,
+ -0.228698, 32.859524, 5.645676, 0.054622, -0.280648, 32.694893, 5.631547, 0.068115, -0.336524,
+ 32.422569, 5.611561, 0.083957, -0.395671, 32.035511, 5.583449, 0.102259, -0.456164, 31.415047,
+ 5.543651, 0.123021, -0.515765, 30.470440, 5.488278, 0.146127, -0.572309, 29.186451, 5.413118,
+ 0.171749, -0.625710, 27.653852, 5.312369, 0.199549, -0.673853, 25.902435, 5.185774, 0.229188,
+ -0.715905, 23.978609, 5.030582, 0.260421, -0.751533, 21.999035, 4.853484, 0.293421, -0.782309,
+ 20.087366, 4.656137, 0.327077, -0.806332, 18.186535, 4.443975, 0.361892, -0.825818, 16.418409,
+ 4.223844, 0.397146, -0.840019, 14.774344, 3.998959, 0.434169, -0.852434, 13.321097, 3.775443,
+ 0.469288, -0.856632, 11.929448, 3.552818, 0.504319, -0.857130, 10.675201, 3.338825, 0.540067,
+ -0.855903, 9.591900, 3.130547, 0.575404, -0.851565, 8.607655, 2.932930, 0.606782, -0.839818,
+ 7.690560, 2.743876, 0.638660, -0.827508, 6.900781, 2.565115, 0.670577, -0.814154, 6.216821,
+ 2.395215, 0.696718, -0.793162, 5.551886, 2.238233, 0.725990, -0.775291, 5.015406, 2.090264,
+ 0.754140, -0.755758, 4.546843, 1.950834, 0.775992, -0.729824, 4.094254, 1.820582, 0.802990,
+ -0.708909, 3.732984, 1.699191, 0.828291, -0.686483, 3.413194, 1.583805, 0.847406, -0.659162,
+ 3.103861, 1.478093, 0.864951, -0.631051, 2.832976, 1.378496, 0.887154, -0.606590, 2.616645,
+ 1.282127, 0.906337, -0.580124, 2.413988, 1.194643, 0.927184, -0.554835, 2.244380, 1.110354,
+ 0.943810, -0.527583, 2.081964, 1.031996, 0.963630, -0.502243, 1.948979, 0.956718, 0.979691,
+ -0.475006, 1.822701, 0.886957, 0.997690, -0.448815, 1.715714, 0.819006, 1.016460, -0.423044,
+ 1.621868, 0.754892, 1.035485, -0.397637, 1.539537, 0.693707, 1.053165, -0.371775, 1.462285,
+ 0.634867, 1.072394, -0.346372, 1.396193, 0.578574, 1.093397, -0.321291, 1.338344, 0.524341,
+ 1.115194, -0.296102, 1.287594, 0.472059, 1.137943, -0.271023, 1.240495, 0.421674, 1.164163,
+ -0.246367, 1.201224, 0.371963, 1.191457, -0.221414, 1.164472, 0.325040, 1.220253, -0.196228,
+ 1.134325, 0.280343, 1.245456, -0.169991, 1.108214, 0.238098, 1.270647, -0.143314, 1.087277,
+ 0.197886, 1.292124, -0.115881, 1.069397, 0.159560, 1.309091, -0.087816, 1.051426, 0.120547,
+ 1.321130, -0.059301, 1.032904, 0.080834, 1.332484, -0.030912, 1.015767, 0.040933, 1.342834,
+ -0.002172, 0.999591, 0.001185, 0.000125, -0.000830, 8.392562, 6.634228, 0.000443, -0.002936,
+ 29.687805, 6.634032, 0.002016, -0.013374, 45.025234, 6.633008, 0.004540, -0.030089, 45.020294,
+ 6.633056, 0.008092, -0.053499, 45.066029, 6.626466, 0.012710, -0.083610, 44.810101, 6.630330,
+ 0.018485, -0.120260, 45.216747, 6.614516, 0.025134, -0.161031, 44.674168, 6.600349, 0.033897,
+ -0.212161, 44.819195, 6.610186, 0.043978, -0.266661, 44.450245, 6.593605, 0.056094, -0.326582,
+ 44.134544, 6.570142, 0.070528, -0.390342, 43.591648, 6.536712, 0.087498, -0.456162, 42.708160,
+ 6.488329, 0.107138, -0.521609, 41.365093, 6.420198, 0.129461, -0.584225, 39.525822, 6.323702,
+ 0.154245, -0.641931, 37.186111, 6.193606, 0.181228, -0.692829, 34.478470, 6.026897, 0.210711,
+ -0.738440, 31.680904, 5.825769, 0.242181, -0.777397, 28.828054, 5.595428, 0.275337, -0.809980,
+ 26.042755, 5.342321, 0.309698, -0.835990, 23.376804, 5.073076, 0.345702, -0.858077, 20.965754,
+ 4.794572, 0.382135, -0.874122, 18.710079, 4.516676, 0.419871, -0.887133, 16.713011, 4.241767,
+ 0.455609, -0.891199, 14.819674, 3.972124, 0.492617, -0.894082, 13.187921, 3.717271, 0.528186,
+ -0.891270, 11.708584, 3.471719, 0.563462, -0.885719, 10.422834, 3.237760, 0.596013, -0.874241,
+ 9.237741, 3.019060, 0.629455, -0.862814, 8.248549, 2.813572, 0.661110, -0.848126, 7.358398,
+ 2.621046, 0.690314, -0.829798, 6.569392, 2.441627, 0.720589, -0.812314, 5.905934, 2.274629,
+ 0.745631, -0.788704, 5.276800, 2.119423, 0.771488, -0.766133, 4.752773, 1.974380, 0.798704,
+ -0.744726, 4.306095, 1.839482, 0.820172, -0.718062, 3.889792, 1.713244, 0.844368, -0.693972,
+ 3.545456, 1.594809, 0.863128, -0.665748, 3.212762, 1.487512, 0.880094, -0.637003, 2.926572,
+ 1.386724, 0.904252, -0.613728, 2.704260, 1.288131, 0.920506, -0.585217, 2.483164, 1.199845,
+ 0.940919, -0.559603, 2.300348, 1.114958, 0.957044, -0.531597, 2.130516, 1.034754, 0.972648,
+ -0.503583, 1.979313, 0.960912, 0.994318, -0.478813, 1.859664, 0.889786, 1.008754, -0.450943,
+ 1.742705, 0.820833, 1.028667, -0.425516, 1.645220, 0.756332, 1.046145, -0.398977, 1.557184,
+ 0.693921, 1.067212, -0.373657, 1.480814, 0.635955, 1.084111, -0.346657, 1.408762, 0.578832,
+ 1.106749, -0.321392, 1.350468, 0.523561, 1.128440, -0.295773, 1.294865, 0.471146, 1.151073,
+ -0.270028, 1.246118, 0.420298, 1.178601, -0.244816, 1.204226, 0.370575, 1.206845, -0.219027,
+ 1.166896, 0.323716, 1.235963, -0.192622, 1.135756, 0.278058, 1.263030, -0.165331, 1.109240,
+ 0.235743, 1.288937, -0.137489, 1.088379, 0.195390, 1.310681, -0.108685, 1.068987, 0.156439,
+ 1.334352, -0.079710, 1.054273, 0.117096, 1.344847, -0.049947, 1.034598, 0.076554, 1.354943,
+ -0.020272, 1.016079, 0.035585, 1.365515, 0.009170, 0.999969, -0.004771, 0.000117, -0.000935,
+ 9.424866, 7.979243, 0.000410, -0.003275, 33.013195, 7.979422, 0.002009, -0.016024, 64.370331,
+ 7.977156, 0.004541, -0.036176, 64.655952, 7.976128, 0.008109, -0.064384, 64.864494, 7.964988,
+ 0.012694, -0.099984, 64.487198, 7.971348, 0.018554, -0.143991, 64.637970, 7.923116, 0.025303,
+ -0.192040, 61.930538, 7.953975, 0.035297, -0.259442, 66.274422, 7.921861, 0.045226, -0.318370,
+ 63.334690, 7.909609, 0.058370, -0.388821, 62.686401, 7.864696, 0.074083, -0.461667, 61.332054,
+ 7.801843, 0.092537, -0.533744, 59.125607, 7.708949, 0.113781, -0.601905, 55.997845, 7.575799,
+ 0.137786, -0.664409, 52.177567, 7.393524, 0.164770, -0.721193, 48.019485, 7.161756, 0.193894,
+ -0.768842, 43.460278, 6.882018, 0.225586, -0.810332, 39.086590, 6.564607, 0.259311, -0.845096,
+ 34.896049, 6.221983, 0.294517, -0.872849, 30.952213, 5.865831, 0.331163, -0.895159, 27.375792,
+ 5.507064, 0.368964, -0.912860, 24.213310, 5.149763, 0.407255, -0.925338, 21.364958, 4.806172,
+ 0.444704, -0.930956, 18.791691, 4.472272, 0.482041, -0.932576, 16.521160, 4.160864, 0.519572,
+ -0.931547, 14.589918, 3.865206, 0.556236, -0.926554, 12.887797, 3.590445, 0.590431, -0.915839,
+ 11.352402, 3.332747, 0.622723, -0.901266, 10.002660, 3.093264, 0.657029, -0.888747, 8.905210,
+ 2.873842, 0.686164, -0.868666, 7.876704, 2.666740, 0.719168, -0.853152, 7.051816, 2.479017,
+ 0.742294, -0.826169, 6.226034, 2.306498, 0.770320, -0.804936, 5.590831, 2.141328, 0.792337,
+ -0.777772, 4.984083, 1.994663, 0.819050, -0.755478, 4.507655, 1.853950, 0.837684, -0.726072,
+ 4.049884, 1.725590, 0.861324, -0.701424, 3.678201, 1.606303, 0.880741, -0.673615, 3.337163,
+ 1.495452, 0.903335, -0.648506, 3.055720, 1.391162, 0.920311, -0.619640, 2.792068, 1.294734,
+ 0.935769, -0.590245, 2.554566, 1.204518, 0.956592, -0.564944, 2.366468, 1.118630, 0.972424,
+ -0.536842, 2.187863, 1.038323, 0.986269, -0.508020, 2.023480, 0.963803, 1.006122, -0.482411,
+ 1.895137, 0.890986, 1.022504, -0.455110, 1.775886, 0.820936, 1.037905, -0.427450, 1.665951,
+ 0.758556, 1.059281, -0.402198, 1.577363, 0.696126, 1.076613, -0.375156, 1.493391, 0.636676,
+ 1.097828, -0.349577, 1.421129, 0.579947, 1.116671, -0.322955, 1.355205, 0.525140, 1.140514,
+ -0.297406, 1.299979, 0.471460, 1.166473, -0.271786, 1.249847, 0.420473, 1.192591, -0.245461,
+ 1.204625, 0.371118, 1.223349, -0.219412, 1.166686, 0.322600, 1.254833, -0.192660, 1.134121,
+ 0.277572, 1.285808, -0.165167, 1.108617, 0.234417, 1.322015, -0.137236, 1.093841, 0.194640,
+ 1.342172, -0.106871, 1.074616, 0.155001, 1.357238, -0.075759, 1.053550, 0.114648, 1.367725,
+ -0.044279, 1.033851, 0.073254, 1.379461, -0.013001, 1.015713, 0.031895, 1.391625, 0.018075,
+ 1.000203, -0.009397, 0.000109, -0.001093, 10.986820, 9.992467, 0.000378, -0.003779, 37.989063,
+ 9.992861, 0.002028, -0.020252, 101.850441, 9.988345, 0.004557, -0.045429, 101.106750, 9.983879,
+ 0.008115, -0.080453, 100.646606, 9.953411, 0.012864, -0.125836, 101.366592, 9.943727, 0.018734,
+ -0.179350, 100.786118, 9.908408, 0.026314, -0.243680, 99.779343, 9.821631, 0.035500, -0.313552,
+ 98.608231, 9.782450, 0.047562, -0.394644, 97.689568, 9.845875, 0.062065, -0.476697, 95.177795,
+ 9.755218, 0.079552, -0.557933, 91.095581, 9.615121, 0.099905, -0.632818, 85.110382, 9.408299,
+ 0.123231, -0.699926, 77.948921, 9.120996, 0.149980, -0.760671, 70.491119, 8.764173, 0.179550,
+ -0.812251, 62.821407, 8.341752, 0.211839, -0.855909, 55.512890, 7.876337, 0.246434, -0.892023,
+ 48.744549, 7.386268, 0.282317, -0.919200, 42.462059, 6.886009, 0.319580, -0.940333, 36.901031,
+ 6.400318, 0.360135, -0.962176, 32.353752, 5.937503, 0.397805, -0.969755, 27.996445, 5.489783,
+ 0.437077, -0.976494, 24.359192, 5.072855, 0.474388, -0.975265, 21.124300, 4.684682, 0.513695,
+ -0.975335, 18.476677, 4.326597, 0.551542, -0.970264, 16.167391, 3.999049, 0.587525, -0.960365,
+ 14.143442, 3.696317, 0.621251, -0.945944, 12.374341, 3.414176, 0.654738, -0.930709, 10.877112,
+ 3.160455, 0.685794, -0.911702, 9.580887, 2.921461, 0.717135, -0.892948, 8.481939, 2.707478,
+ 0.740798, -0.865086, 7.435941, 2.510382, 0.770920, -0.845137, 6.650625, 2.329648, 0.792303,
+ -0.815956, 5.879976, 2.163206, 0.818363, -0.792225, 5.274404, 2.008042, 0.837362, -0.762396,
+ 4.700960, 1.867576, 0.862266, -0.738465, 4.254798, 1.735819, 0.880069, -0.708890, 3.828697,
+ 1.614690, 0.896021, -0.678588, 3.451655, 1.503477, 0.920156, -0.654832, 3.168722, 1.395800,
+ 0.934948, -0.624740, 2.879533, 1.299955, 0.949686, -0.595203, 2.628258, 1.208597, 0.970989,
+ -0.570041, 2.433689, 1.122310, 0.985606, -0.541116, 2.241461, 1.042168, 1.000819, -0.512835,
+ 2.075567, 0.966543, 1.012209, -0.483024, 1.919932, 0.895758, 1.035320, -0.459125, 1.807884,
+ 0.825668, 1.052077, -0.432333, 1.695689, 0.760812, 1.070459, -0.406131, 1.595491, 0.699897,
+ 1.088704, -0.379721, 1.508512, 0.640575, 1.103817, -0.352104, 1.428159, 0.583765, 1.131711,
+ -0.328122, 1.366565, 0.528240, 1.156448, -0.302568, 1.306843, 0.473988, 1.181821, -0.276487,
+ 1.252861, 0.422189, 1.211347, -0.250540, 1.205265, 0.372005, 1.243636, -0.224264, 1.165943,
+ 0.324184, 1.283038, -0.198289, 1.137772, 0.278419, 1.316722, -0.170179, 1.115057, 0.235425,
+ 1.342715, -0.140095, 1.092994, 0.195084, 1.363288, -0.108794, 1.071875, 0.155439, 1.380656,
+ -0.076774, 1.052475, 0.114636, 1.394826, -0.044509, 1.032525, 0.072890, 1.408830, -0.011968,
+ 1.015459, 0.031101, 1.422370, 0.020555, 0.999808, -0.011002, 0.000100, -0.001334, 13.377127,
+ 13.342275, 0.000342, -0.004563, 45.758434, 13.342710, 0.002026, -0.027004, 179.672058,
+ 13.331846, 0.004559, -0.060563, 179.294235, 13.314877, 0.008232, -0.108154, 181.242035,
+ 13.222856, 0.013031, -0.167590, 179.684509, 13.153860, 0.019526, -0.242041, 181.004608,
+ 12.986094, 0.026364, -0.309289, 159.606293, 13.247752, 0.037670, -0.409755, 179.468521,
+ 12.368877, 0.051804, -0.512051, 167.955582, 12.981333, 0.068214, -0.601994, 156.278793,
+ 12.704532, 0.088295, -0.686849, 143.096878, 12.316531, 0.111478, -0.758670, 127.423111,
+ 11.793048, 0.138336, -0.821348, 111.763031, 11.157992, 0.168447, -0.873616, 96.887924,
+ 10.447472, 0.201411, -0.916322, 83.225327, 9.696606, 0.237443, -0.953090, 71.403137, 8.949244,
+ 0.274234, -0.977751, 60.739277, 8.225874, 0.314566, -1.003135, 52.115578, 7.547433, 0.353932,
+ -1.016312, 44.341869, 6.910326, 0.393858, -1.024848, 37.827263, 6.324401, 0.433805, -1.028950,
+ 32.380932, 5.790555, 0.475812, -1.034084, 27.955982, 5.312826, 0.513254, -1.026743, 23.977417,
+ 4.866118, 0.549965, -1.016740, 20.628025, 4.468437, 0.590300, -1.012030, 18.036856, 4.105483,
+ 0.626420, -0.998919, 15.669224, 3.780593, 0.658897, -0.979874, 13.603898, 3.482054, 0.687252,
+ -0.955238, 11.788331, 3.211213, 0.718941, -0.935663, 10.355552, 2.962083, 0.749877, -0.915206,
+ 9.131123, 2.741382, 0.772094, -0.884837, 7.973935, 2.536501, 0.799495, -0.861214, 7.086230,
+ 2.347282, 0.820136, -0.830976, 6.240769, 2.179332, 0.846715, -0.807408, 5.604792, 2.018005,
+ 0.865176, -0.776657, 4.975034, 1.877021, 0.881100, -0.744657, 4.442767, 1.743528, 0.907637,
+ -0.722088, 4.035177, 1.621563, 0.922239, -0.690432, 3.633160, 1.506158, 0.936558, -0.659650,
+ 3.281798, 1.403606, 0.950047, -0.629105, 2.974179, 1.304276, 0.961959, -0.598277, 2.704483,
+ 1.213888, 0.987410, -0.576085, 2.510453, 1.125569, 0.999996, -0.546494, 2.304016, 1.045567,
+ 1.014127, -0.518186, 2.127867, 0.970718, 1.036275, -0.494009, 1.985804, 0.897557, 1.049695,
+ -0.465659, 1.845074, 0.830584, 1.064617, -0.438159, 1.725130, 0.766083, 1.077131, -0.409813,
+ 1.613818, 0.705101, 1.101054, -0.385632, 1.528694, 0.644828, 1.122361, -0.360045, 1.447086,
+ 0.587878, 1.147359, -0.335186, 1.377588, 0.532130, 1.169881, -0.309040, 1.313673, 0.478843,
+ 1.200554, -0.284590, 1.257256, 0.426855, 1.232047, -0.259332, 1.208431, 0.376125, 1.275402,
+ -0.235215, 1.174692, 0.326614, 1.306595, -0.207508, 1.141042, 0.281524, 1.334304, -0.178290,
+ 1.111778, 0.238694, 1.364678, -0.148530, 1.090976, 0.198549, 1.387168, -0.117114, 1.069308,
+ 0.158529, 1.408657, -0.084977, 1.050625, 0.118042, 1.426214, -0.052052, 1.031444, 0.076541,
+ 1.444257, -0.018653, 1.014298, 0.034061, 1.460618, 0.015206, 0.999413, -0.008132, 0.000100,
+ -0.002003, 20.052612, 20.032721, 0.000297, -0.005947, 59.540512, 20.033842, 0.002022,
+ -0.040439, 404.848511, 20.032743, 0.004588, -0.090999, 403.741241, 19.910591, 0.008769,
+ -0.169802, 441.471558, 19.572552, 0.013708, -0.253629, 411.667816, 19.145721, 0.020331,
+ -0.349396, 371.322571, 18.591049, 0.030259, -0.468121, 385.816498, 18.331083, 0.045190,
+ -0.611444, 391.924133, 15.807686, 0.058476, -0.676875, 319.638641, 16.947781, 0.079894,
+ -0.781421, 278.804260, 17.512903, 0.103871, -0.855116, 235.999786, 16.290295, 0.131756,
+ -0.915747, 197.168076, 14.956566, 0.163487, -0.966333, 163.452347, 13.608010, 0.198693,
+ -1.008386, 135.632706, 12.299661, 0.236157, -1.039862, 111.919281, 11.088790, 0.274579,
+ -1.059988, 92.136581, 9.983883, 0.317164, -1.084069, 77.063034, 9.008505, 0.357624, -1.092124,
+ 63.963051, 8.127298, 0.399009, -1.097560, 53.483341, 7.347628, 0.441182, -1.100981, 45.052429,
+ 6.658191, 0.481606, -1.097318, 37.932640, 6.047333, 0.524253, -1.096570, 32.395638, 5.505878,
+ 0.564351, -1.088739, 27.679380, 5.018494, 0.600843, -1.073396, 23.611519, 4.580770, 0.635527,
+ -1.055024, 20.207081, 4.194785, 0.672045, -1.039775, 17.469036, 3.847436, 0.698372, -1.009545,
+ 14.928226, 3.532546, 0.729336, -0.987168, 12.953170, 3.248834, 0.761147, -0.966299, 11.346271,
+ 2.994166, 0.782270, -0.932841, 9.813129, 2.762244, 0.811832, -0.910431, 8.672224, 2.549933,
+ 0.832053, -0.878369, 7.578633, 2.363132, 0.849383, -0.844673, 6.648379, 2.189266, 0.866020,
+ -0.811703, 5.850784, 2.031716, 0.893083, -0.789181, 5.273372, 1.884480, 0.909212, -0.757541,
+ 4.700618, 1.750298, 0.923169, -0.725157, 4.196640, 1.627590, 0.937112, -0.693769, 3.764841,
+ 1.514906, 0.961901, -0.670828, 3.444598, 1.406839, 0.975245, -0.640240, 3.120745, 1.307873,
+ 0.989696, -0.611032, 2.840732, 1.216417, 1.002057, -0.581144, 2.591596, 1.132553, 1.014022,
+ -0.551620, 2.373820, 1.051695, 1.025307, -0.522268, 2.177992, 0.977500, 1.052190, -0.500826,
+ 2.042511, 0.904301, 1.064408, -0.472355, 1.891934, 0.837557, 1.077876, -0.444815, 1.761054,
+ 0.773004, 1.088939, -0.416531, 1.638939, 0.713958, 1.118551, -0.395057, 1.555724, 0.652485,
+ 1.134469, -0.368289, 1.465490, 0.596330, 1.162778, -0.345095, 1.390977, 0.539703, 1.185298,
+ -0.319527, 1.321225, 0.486250, 1.208419, -0.293590, 1.259318, 0.434178, 1.261013, -0.273471,
+ 1.219767, 0.382032, 1.297811, -0.248226, 1.176422, 0.334190, 1.326591, -0.220354, 1.139881,
+ 0.289075, 1.357918, -0.191937, 1.111418, 0.246259, 1.387590, -0.162282, 1.086511, 0.205129,
+ 1.415797, -0.131515, 1.067072, 0.165601, 1.440194, -0.099555, 1.047799, 0.125462, 1.465600,
+ -0.066957, 1.030406, 0.084082, 1.487714, -0.033496, 1.013889, 0.041981, 1.509947, 0.000663,
+ 0.998773, -0.000485, 0.000100, -0.004009, 40.102047, 40.087105, 0.000228, -0.009141, 91.431366,
+ 40.074432, 0.001522, -0.060544, 605.651733, 39.918827, 0.004919, -0.188871, 1712.982300,
+ 38.873421, 0.009053, -0.320325, 1583.453125, 39.715633, 0.015375, -0.471415, 1486.033691,
+ 39.162876, 0.029306, -0.735111, 1751.701050, 28.083200, 0.043450, -0.859759, 1392.475220,
+ 24.599945, 0.079075, -1.220033, 1629.972656, 18.507019, 0.090130, -1.091255, 940.347351,
+ 17.961655, 0.098008, -0.945965, 425.901093, 24.478010, 0.138246, -1.084105, 416.823944,
+ 20.003433, 0.174489, -1.133148, 302.730042, 18.550846, 0.207969, -1.138483, 242.853577,
+ 15.923334, 0.249132, -1.168197, 191.649445, 13.940813, 0.291391, -1.187038, 152.910309,
+ 12.263267, 0.332856, -1.192793, 121.905075, 10.822873, 0.377473, -1.202846, 99.145561,
+ 9.618412, 0.422601, -1.208871, 81.343315, 8.591735, 0.465276, -1.204545, 66.742569, 7.692911,
+ 0.504710, -1.190839, 54.787876, 6.915612, 0.544909, -1.178827, 45.507313, 6.242786, 0.582125,
+ -1.160590, 37.819912, 5.651690, 0.620694, -1.145481, 31.926588, 5.123660, 0.659127, -1.130178,
+ 27.147310, 4.669475, 0.684358, -1.093728, 22.650702, 4.258717, 0.719453, -1.074591, 19.454103,
+ 3.901225, 0.751695, -1.051678, 16.735672, 3.576870, 0.775082, -1.017716, 14.281039, 3.287471,
+ 0.796233, -0.982759, 12.261332, 3.023708, 0.827404, -0.961227, 10.767912, 2.787740, 0.848149,
+ -0.928433, 9.371350, 2.570737, 0.864891, -0.892838, 8.142364, 2.379204, 0.880979, -0.858193,
+ 7.118954, 2.204470, 0.910434, -0.837281, 6.389041, 2.041554, 0.925396, -0.803638, 5.643217,
+ 1.893353, 0.942463, -0.772925, 5.031223, 1.757331, 0.955217, -0.739720, 4.486978, 1.633572,
+ 0.968570, -0.708048, 4.014621, 1.520414, 0.981672, -0.677109, 3.617768, 1.412506, 0.992829,
+ -0.645712, 3.258773, 1.317079, 1.021270, -0.625746, 3.006640, 1.222611, 1.031247, -0.594628,
+ 2.733073, 1.137911, 1.043581, -0.565540, 2.498495, 1.058439, 1.055930, -0.536962, 2.289843,
+ 0.984428, 1.066727, -0.508076, 2.108603, 0.912794, 1.081225, -0.481297, 1.951454, 0.845536,
+ 1.088198, -0.451563, 1.801891, 0.782718, 1.123316, -0.433247, 1.704316, 0.721664, 1.133206,
+ -0.404812, 1.586153, 0.662761, 1.152889, -0.379901, 1.490958, 0.606866, 1.188158, -0.359421,
+ 1.415730, 0.550666, 1.217064, -0.336049, 1.344172, 0.496748, 1.257727, -0.314816, 1.283196,
+ 0.443538, 1.286647, -0.289530, 1.225903, 0.394018, 1.308729, -0.262053, 1.173928, 0.346255,
+ 1.351453, -0.237704, 1.139992, 0.300393, 1.380284, -0.209733, 1.105997, 0.256661, 1.414621,
+ -0.181613, 1.082109, 0.215429, 1.453045, -0.152797, 1.063853, 0.177098, 1.481066, -0.121803,
+ 1.043185, 0.137203, 1.514113, -0.090250, 1.027072, 0.096998, 1.547317, -0.057603, 1.012551,
+ 0.055328, 1.577983, -0.023799, 0.999267, 0.013094, 0.000108, -0.124970, 1249.704346,
+ 1249.703491, 0.000140, -0.119585, 1195.855469, 1195.854370, 0.003995, -0.927433, 9274.246094,
+ 232.443573, 0.012013, -1.131580, 11315.999023, 98.211105, 0.023892, -1.216018, 12162.739258,
+ 67.214500, 0.047506, -1.517865, 15186.294922, 42.410069, 0.082523, -1.812564, 18145.718750,
+ 24.421545, 0.112452, -1.805072, 11112.966797, 18.450365, 0.164460, -2.016784, 8086.032715,
+ 14.043465, 0.195870, -1.898199, 4245.658203, 13.178202, 0.197797, -1.556158, 1315.561768,
+ 30.760096, 0.219540, -1.433455, 802.380371, 25.037956, 0.268696, -1.483235, 579.715515,
+ 20.975695, 0.265968, -1.261051, 386.583649, 12.017023, 0.325369, -1.343349, 316.795959,
+ 12.612406, 0.387968, -1.411606, 232.491623, 13.296940, 0.435543, -1.411236, 181.515228,
+ 11.646996, 0.482729, -1.405722, 143.425354, 10.265131, 0.531742, -1.402782, 114.920082,
+ 9.114828, 0.559383, -1.346165, 88.589005, 8.089214, 0.607851, -1.342407, 73.056610, 7.249064,
+ 0.656928, -1.338238, 60.826897, 6.531094, 0.681212, -1.285692, 48.727219, 5.868711, 0.729238,
+ -1.279951, 41.256016, 5.324553, 0.751172, -1.230045, 33.728260, 4.816513, 0.773107, -1.184288,
+ 27.913816, 4.377203, 0.815726, -1.171653, 24.065962, 3.999965, 0.837886, -1.130636, 20.254860,
+ 3.658493, 0.857674, -1.089071, 17.138168, 3.347930, 0.876120, -1.048303, 14.572968, 3.072666,
+ 0.893935, -1.009040, 12.496377, 2.825165, 0.927998, -0.989064, 11.040731, 2.605520, 0.928445,
+ -0.935017, 9.365102, 2.401481, 0.945279, -0.899993, 8.177711, 2.222282, 0.959378, -0.863854,
+ 7.155303, 2.059342, 0.971761, -0.827684, 6.284632, 1.909314, 0.987812, -0.795878, 5.583837,
+ 1.771094, 1.001958, -0.763540, 4.962345, 1.645968, 1.014357, -0.730897, 4.435898, 1.527438,
+ 1.025946, -0.698675, 3.973241, 1.421337, 1.036435, -0.666662, 3.568025, 1.323677, 1.046807,
+ -0.635466, 3.218647, 1.232678, 1.052974, -0.602660, 2.902273, 1.147675, 1.086089, -0.585364,
+ 2.694939, 1.068352, 1.094660, -0.554784, 2.454491, 0.993445, 1.117131, -0.531500, 2.270746,
+ 0.923758, 1.114009, -0.496581, 2.063934, 0.858381, 1.137328, -0.473914, 1.917990, 0.794980,
+ 1.158671, -0.450127, 1.786523, 0.735697, 1.177878, -0.425306, 1.662454, 0.677498, 1.207510,
+ -0.403797, 1.559058, 0.621762, 1.244496, -0.383812, 1.466801, 0.566190, 1.240412, -0.351080,
+ 1.366853, 0.514288, 1.321257, -0.341200, 1.309808, 0.464621, 1.336512, -0.312710, 1.241822,
+ 0.413228, 1.365047, -0.286935, 1.186612, 0.366092, 1.418984, -0.265184, 1.152120, 0.321528,
+ 1.388864, -0.227750, 1.089937, 0.271827, 1.464383, -0.207168, 1.077271, 0.232838, 1.473125,
+ -0.175770, 1.041835, 0.193289, 1.542908, -0.150424, 1.036794, 0.156153, 1.563005, -0.118748,
+ 1.013029, 0.114866, 1.637048, -0.089604, 1.013493, 0.076804, 1.670777, -0.056398, 0.999208,
+ 0.032691,
+};
+static float ltc_mag_ggx[64 * 64] = {
+ 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 0.999995, 0.999990, 0.999971, 0.999937, 0.999853, 0.999670,
+ 0.999138, 0.996746, 0.979578, 0.979309, 0.978836, 0.977972, 0.976223, 0.972205, 0.962466,
+ 0.953919, 0.949829, 0.942492, 0.929870, 0.921319, 0.911112, 0.896015, 0.885105, 0.869971,
+ 0.855017, 0.838328, 0.821241, 0.802352, 0.783873, 0.763309, 0.743058, 0.721929, 0.699755,
+ 0.677721, 0.655456, 0.632681, 0.609629, 0.586831, 0.564287, 0.541772, 0.519428, 0.497353,
+ 0.475624, 0.454606, 0.434099, 0.414085, 0.394605, 0.375698, 0.357386, 0.339871, 0.323085,
+ 0.306905, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 0.999999, 0.999999, 0.999998, 0.999995, 0.999990, 0.999980, 0.999959, 0.999923, 0.999842,
+ 0.999660, 0.999119, 0.996613, 0.981824, 0.979298, 0.978826, 0.977957, 0.976184, 0.972091,
+ 0.962188, 0.953875, 0.949746, 0.942335, 0.930166, 0.921211, 0.910927, 0.896979, 0.884940,
+ 0.869864, 0.854835, 0.838200, 0.821049, 0.802552, 0.783659, 0.763512, 0.742927, 0.721715,
+ 0.699938, 0.677775, 0.655246, 0.632555, 0.609805, 0.586996, 0.564225, 0.541606, 0.519346,
+ 0.497419, 0.475863, 0.454738, 0.434099, 0.414003, 0.394547, 0.375747, 0.357564, 0.340012,
+ 0.323099, 0.306861, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 0.999999, 0.999998, 0.999995, 0.999991, 0.999979, 0.999959, 0.999917,
+ 0.999839, 0.999648, 0.999074, 0.996168, 0.983770, 0.979279, 0.978800, 0.977905, 0.976058,
+ 0.971727, 0.962120, 0.953901, 0.949485, 0.941859, 0.930911, 0.920853, 0.910394, 0.897600,
+ 0.884427, 0.870101, 0.854522, 0.838325, 0.820754, 0.802707, 0.783223, 0.763605, 0.742872,
+ 0.721565, 0.699935, 0.677726, 0.655242, 0.632580, 0.609766, 0.586946, 0.564275, 0.541759,
+ 0.519467, 0.497478, 0.475886, 0.454794, 0.434233, 0.414207, 0.394751, 0.375892, 0.357683,
+ 0.340146, 0.323287, 0.307095, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 0.999999, 0.999999, 0.999998, 0.999996, 0.999992, 0.999987, 0.999975, 0.999953,
+ 0.999913, 0.999830, 0.999630, 0.998993, 0.995279, 0.985142, 0.979252, 0.978754, 0.977821,
+ 0.975838, 0.971088, 0.962563, 0.954785, 0.949048, 0.941052, 0.931420, 0.920812, 0.909750,
+ 0.897867, 0.883856, 0.870091, 0.854353, 0.838166, 0.820661, 0.802465, 0.783308, 0.763346,
+ 0.742734, 0.721608, 0.699747, 0.677626, 0.655245, 0.632547, 0.609793, 0.587044, 0.564340,
+ 0.541779, 0.519529, 0.497633, 0.476114, 0.455030, 0.434430, 0.414406, 0.394974, 0.376154,
+ 0.357979, 0.340443, 0.323572, 0.307379, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 0.999998, 0.999998, 0.999996, 0.999991, 0.999984, 0.999970,
+ 0.999946, 0.999905, 0.999815, 0.999599, 0.998856, 0.993704, 0.986135, 0.979212, 0.978690,
+ 0.977691, 0.975504, 0.970133, 0.962951, 0.955649, 0.948405, 0.940418, 0.931660, 0.920881,
+ 0.909376, 0.897785, 0.883844, 0.869756, 0.854326, 0.837732, 0.820617, 0.802053, 0.783195,
+ 0.763119, 0.742610, 0.721344, 0.699709, 0.677624, 0.655114, 0.632523, 0.609812, 0.587052,
+ 0.564417, 0.541966, 0.519751, 0.497824, 0.476309, 0.455271, 0.434735, 0.414736, 0.395317,
+ 0.376524, 0.358364, 0.340852, 0.323988, 0.307786, 1.000000, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 0.999999, 0.999999, 0.999997, 0.999996, 0.999994, 0.999989, 0.999980,
+ 0.999965, 0.999940, 0.999895, 0.999796, 0.999559, 0.998638, 0.992774, 0.986878, 0.980297,
+ 0.978602, 0.977514, 0.975026, 0.969169, 0.963214, 0.956267, 0.947689, 0.940054, 0.931637,
+ 0.920678, 0.908990, 0.897349, 0.883905, 0.869139, 0.854177, 0.837476, 0.820295, 0.801977,
+ 0.782798, 0.762978, 0.742418, 0.721193, 0.699560, 0.677402, 0.655108, 0.632543, 0.609804,
+ 0.587158, 0.564557, 0.542096, 0.519908, 0.498088, 0.476632, 0.455623, 0.435104, 0.415161,
+ 0.395783, 0.377005, 0.358843, 0.341345, 0.324529, 0.308355, 1.000000, 1.000000, 1.000000,
+ 1.000000, 1.000000, 0.999999, 0.999999, 0.999998, 0.999997, 0.999992, 0.999991, 0.999985,
+ 0.999977, 0.999959, 0.999935, 0.999878, 0.999773, 0.999505, 0.998284, 0.992353, 0.987457,
+ 0.981665, 0.978492, 0.977277, 0.974360, 0.968716, 0.963373, 0.956629, 0.947397, 0.939657,
+ 0.931339, 0.920588, 0.908975, 0.896712, 0.883763, 0.868890, 0.853731, 0.837333, 0.819702,
+ 0.801738, 0.782454, 0.762712, 0.742024, 0.721037, 0.699325, 0.677359, 0.655030, 0.632439,
+ 0.609869, 0.587221, 0.564663, 0.542328, 0.520220, 0.498400, 0.476997, 0.456053, 0.435593,
+ 0.415658, 0.396300, 0.377577, 0.359473, 0.342004, 0.325170, 0.308997, 1.000000, 1.000000,
+ 1.000000, 1.000000, 1.000000, 0.999999, 0.999998, 0.999998, 0.999996, 0.999993, 0.999988,
+ 0.999981, 0.999971, 0.999951, 0.999921, 0.999863, 0.999748, 0.999433, 0.997681, 0.992120,
+ 0.987920, 0.982864, 0.978353, 0.976961, 0.973451, 0.968396, 0.963400, 0.956680, 0.947529,
+ 0.939151, 0.930747, 0.920511, 0.908867, 0.896142, 0.883335, 0.868764, 0.853025, 0.837015,
+ 0.819452, 0.801249, 0.782176, 0.762345, 0.741843, 0.720721, 0.699135, 0.677194, 0.654889,
+ 0.632487, 0.609902, 0.587328, 0.564891, 0.542567, 0.520501, 0.498793, 0.477442, 0.456528,
+ 0.436131, 0.416273, 0.396980, 0.378276, 0.360176, 0.342738, 0.325950, 0.309803, 1.000000,
+ 1.000000, 1.000000, 1.000000, 0.999999, 0.999998, 0.999999, 0.999997, 0.999995, 0.999991,
+ 0.999985, 0.999978, 0.999963, 0.999942, 0.999907, 0.999844, 0.999715, 0.999332, 0.996612,
+ 0.991974, 0.988297, 0.983843, 0.978349, 0.976540, 0.972351, 0.968109, 0.963280, 0.956464,
+ 0.947779, 0.938754, 0.929952, 0.920253, 0.908530, 0.895785, 0.882679, 0.868456, 0.852669,
+ 0.836406, 0.819138, 0.800708, 0.781803, 0.761855, 0.741534, 0.720405, 0.698959, 0.676964,
+ 0.654827, 0.632411, 0.609922, 0.587477, 0.565051, 0.542829, 0.520889, 0.499225, 0.477951,
+ 0.457148, 0.436792, 0.416963, 0.397723, 0.379068, 0.361025, 0.343608, 0.326842, 0.310718,
+ 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999999, 0.999998, 0.999995, 0.999994,
+ 0.999990, 0.999983, 0.999971, 0.999954, 0.999932, 0.999892, 0.999820, 0.999675, 0.999190,
+ 0.995492, 0.991911, 0.988610, 0.984662, 0.979221, 0.975975, 0.971671, 0.967788, 0.963002,
+ 0.955938, 0.947965, 0.938692, 0.929309, 0.919781, 0.908268, 0.895518, 0.882022, 0.867884,
+ 0.852346, 0.835746, 0.818607, 0.800261, 0.781335, 0.761539, 0.741063, 0.720116, 0.698617,
+ 0.676815, 0.654700, 0.632389, 0.610037, 0.587591, 0.565328, 0.543205, 0.521293, 0.499745,
+ 0.478562, 0.457776, 0.437515, 0.417776, 0.398586, 0.379963, 0.361984, 0.344616, 0.327857,
+ 0.311751, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999999, 0.999997, 0.999996,
+ 0.999992, 0.999986, 0.999977, 0.999965, 0.999947, 0.999916, 0.999873, 0.999794, 0.999628,
+ 0.998966, 0.994914, 0.991849, 0.988873, 0.985288, 0.980170, 0.975207, 0.971156, 0.967476,
+ 0.962538, 0.955601, 0.947978, 0.938542, 0.928618, 0.919056, 0.907890, 0.895098, 0.881352,
+ 0.867263, 0.851806, 0.835168, 0.818003, 0.799785, 0.780633, 0.761080, 0.740618, 0.719795,
+ 0.698332, 0.676629, 0.654544, 0.632411, 0.610042, 0.587805, 0.565593, 0.543549, 0.521793,
+ 0.500309, 0.479195, 0.458546, 0.438353, 0.418669, 0.399557, 0.381012, 0.363049, 0.345710,
+ 0.329006, 0.312948, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999999, 0.999997,
+ 0.999993, 0.999990, 0.999984, 0.999972, 0.999960, 0.999939, 0.999906, 0.999853, 0.999765,
+ 0.999567, 0.998603, 0.994519, 0.991794, 0.989089, 0.985781, 0.980956, 0.974161, 0.970688,
+ 0.967064, 0.961890, 0.955292, 0.947848, 0.938359, 0.928226, 0.918214, 0.907361, 0.894702,
+ 0.880834, 0.866500, 0.851209, 0.834627, 0.817211, 0.799250, 0.780131, 0.760512, 0.740218,
+ 0.719264, 0.698063, 0.676325, 0.654450, 0.632316, 0.610170, 0.587988, 0.565891, 0.544013,
+ 0.522305, 0.500958, 0.479971, 0.459376, 0.439271, 0.419699, 0.400620, 0.382126, 0.364246,
+ 0.346967, 0.330273, 0.314236, 1.000000, 1.000000, 1.000000, 1.000000, 0.999999, 0.999998,
+ 0.999996, 0.999994, 0.999988, 0.999979, 0.999967, 0.999952, 0.999924, 0.999888, 0.999833,
+ 0.999733, 0.999490, 0.997946, 0.994192, 0.991812, 0.989274, 0.986224, 0.981547, 0.974000,
+ 0.970269, 0.966545, 0.961031, 0.954921, 0.947416, 0.938226, 0.928003, 0.917390, 0.906553,
+ 0.894191, 0.880329, 0.865540, 0.850476, 0.834058, 0.816467, 0.798509, 0.779561, 0.759828,
+ 0.739738, 0.718878, 0.697718, 0.676138, 0.654342, 0.632317, 0.610292, 0.588207, 0.566289,
+ 0.544443, 0.522927, 0.501674, 0.480765, 0.460314, 0.440304, 0.420782, 0.401824, 0.383410,
+ 0.365538, 0.348312, 0.331692, 0.315688, 1.000000, 1.000000, 1.000000, 1.000000, 0.999999,
+ 0.999998, 0.999996, 0.999993, 0.999985, 0.999976, 0.999961, 0.999943, 0.999913, 0.999872,
+ 0.999807, 0.999691, 0.999390, 0.996859, 0.994003, 0.991808, 0.989423, 0.986523, 0.981783,
+ 0.974511, 0.969791, 0.965933, 0.960377, 0.954434, 0.946803, 0.938026, 0.927620, 0.916545,
+ 0.905639, 0.893489, 0.879820, 0.864852, 0.849513, 0.833311, 0.815878, 0.797621, 0.778938,
+ 0.759253, 0.739142, 0.718479, 0.697274, 0.675902, 0.654135, 0.632357, 0.610364, 0.588497,
+ 0.566631, 0.545012, 0.523579, 0.502429, 0.481680, 0.461304, 0.441425, 0.422039, 0.403135,
+ 0.384779, 0.366976, 0.349796, 0.333231, 0.317277, 1.000000, 1.000000, 1.000000, 1.000000,
+ 0.999999, 0.999998, 0.999996, 0.999991, 0.999983, 0.999974, 0.999956, 0.999932, 0.999901,
+ 0.999852, 0.999780, 0.999646, 0.999248, 0.996193, 0.993784, 0.991782, 0.989539, 0.986694,
+ 0.981765, 0.975135, 0.969309, 0.965128, 0.959788, 0.953831, 0.946255, 0.937664, 0.927351,
+ 0.916044, 0.904715, 0.892528, 0.879111, 0.864256, 0.848452, 0.832434, 0.815129, 0.796806,
+ 0.778118, 0.758668, 0.738466, 0.718024, 0.696958, 0.675642, 0.654067, 0.632325, 0.610546,
+ 0.588786, 0.567123, 0.545617, 0.524312, 0.503348, 0.482637, 0.462418, 0.442657, 0.423338,
+ 0.404564, 0.386277, 0.368545, 0.351448, 0.334906, 0.318961, 1.000000, 1.000000, 1.000000,
+ 0.999999, 0.999999, 0.999998, 0.999994, 0.999989, 0.999979, 0.999968, 0.999949, 0.999921,
+ 0.999886, 0.999833, 0.999747, 0.999596, 0.999029, 0.995749, 0.993677, 0.991724, 0.989620,
+ 0.986723, 0.981515, 0.975767, 0.969056, 0.964124, 0.959142, 0.953036, 0.945650, 0.937022,
+ 0.926971, 0.915515, 0.903584, 0.891603, 0.878212, 0.863472, 0.847652, 0.831398, 0.814299,
+ 0.796105, 0.777231, 0.757977, 0.737895, 0.717415, 0.696595, 0.675317, 0.653980, 0.632343,
+ 0.610735, 0.589076, 0.567620, 0.546251, 0.525165, 0.504255, 0.483759, 0.463666, 0.443987,
+ 0.424783, 0.406042, 0.387891, 0.370293, 0.353221, 0.336715, 0.320806, 1.000000, 1.000000,
+ 1.000000, 0.999999, 0.999998, 0.999998, 0.999993, 0.999987, 0.999977, 0.999964, 0.999943,
+ 0.999911, 0.999867, 0.999807, 0.999714, 0.999531, 0.998645, 0.995399, 0.993512, 0.991717,
+ 0.989661, 0.986652, 0.981559, 0.976183, 0.969411, 0.963317, 0.958457, 0.952091, 0.944951,
+ 0.936307, 0.926454, 0.915043, 0.902668, 0.890462, 0.877245, 0.862672, 0.846823, 0.830201,
+ 0.813293, 0.795306, 0.776393, 0.757199, 0.737324, 0.716808, 0.696187, 0.675094, 0.653814,
+ 0.632453, 0.610885, 0.589483, 0.568099, 0.546975, 0.525953, 0.505268, 0.484936, 0.464988,
+ 0.445458, 0.426314, 0.407750, 0.389670, 0.372098, 0.355105, 0.338682, 0.322825, 1.000000,
+ 1.000000, 1.000000, 1.000000, 0.999999, 0.999996, 0.999992, 0.999983, 0.999976, 0.999959,
+ 0.999933, 0.999898, 0.999849, 0.999780, 0.999676, 0.999454, 0.997884, 0.995166, 0.993394,
+ 0.991723, 0.989654, 0.986389, 0.981632, 0.976607, 0.969701, 0.962555, 0.957605, 0.951232,
+ 0.944099, 0.935556, 0.925699, 0.914492, 0.902027, 0.889116, 0.876093, 0.861649, 0.845956,
+ 0.829238, 0.812220, 0.794420, 0.775657, 0.756265, 0.736673, 0.716372, 0.695669, 0.674886,
+ 0.653728, 0.632568, 0.611217, 0.589929, 0.568783, 0.547752, 0.526931, 0.506425, 0.486238,
+ 0.466425, 0.446945, 0.428026, 0.409536, 0.391551, 0.374087, 0.357155, 0.340787, 0.324974,
+ 1.000000, 1.000000, 1.000000, 1.000000, 0.999998, 0.999996, 0.999990, 0.999984, 0.999970,
+ 0.999952, 0.999925, 0.999886, 0.999831, 0.999757, 0.999633, 0.999356, 0.997017, 0.994868,
+ 0.993337, 0.991710, 0.989580, 0.985848, 0.981640, 0.976711, 0.969755, 0.962166, 0.956609,
+ 0.950365, 0.943026, 0.934693, 0.924880, 0.913729, 0.901350, 0.887966, 0.874726, 0.860474,
+ 0.844905, 0.828269, 0.810905, 0.793364, 0.774812, 0.755478, 0.735886, 0.715847, 0.695231,
+ 0.674537, 0.653667, 0.632527, 0.611475, 0.590363, 0.569462, 0.548571, 0.527976, 0.507634,
+ 0.487632, 0.467901, 0.448680, 0.429833, 0.411467, 0.393568, 0.376197, 0.359374, 0.343034,
+ 0.327273, 1.000000, 1.000000, 1.000000, 0.999999, 0.999998, 0.999993, 0.999989, 0.999980,
+ 0.999965, 0.999945, 0.999913, 0.999869, 0.999810, 0.999723, 0.999583, 0.999213, 0.996540,
+ 0.994740, 0.993244, 0.991671, 0.989411, 0.985533, 0.981616, 0.976847, 0.969968, 0.962315,
+ 0.955468, 0.949420, 0.942016, 0.933617, 0.923949, 0.912899, 0.900495, 0.887022, 0.873283,
+ 0.859153, 0.843830, 0.827325, 0.809888, 0.792172, 0.773832, 0.754686, 0.735035, 0.715297,
+ 0.694955, 0.674242, 0.653660, 0.632752, 0.611804, 0.590993, 0.570154, 0.549539, 0.529087,
+ 0.508974, 0.489030, 0.469599, 0.450466, 0.431761, 0.413508, 0.395761, 0.378480, 0.361679,
+ 0.345465, 0.329752, 1.000000, 1.000000, 1.000000, 1.000000, 0.999997, 0.999994, 0.999987,
+ 0.999978, 0.999961, 0.999936, 0.999903, 0.999855, 0.999786, 0.999689, 0.999527, 0.998988,
+ 0.996137, 0.994527, 0.993108, 0.991599, 0.989084, 0.985308, 0.981527, 0.976677, 0.970079,
+ 0.962535, 0.954490, 0.948271, 0.940942, 0.932422, 0.922836, 0.911896, 0.899632, 0.886118,
+ 0.871864, 0.857719, 0.842536, 0.826163, 0.808849, 0.790860, 0.772802, 0.753860, 0.734335,
+ 0.714582, 0.694543, 0.674071, 0.653544, 0.632922, 0.612153, 0.591573, 0.570951, 0.550520,
+ 0.530352, 0.510311, 0.490707, 0.471359, 0.452396, 0.433837, 0.415736, 0.398052, 0.380874,
+ 0.364232, 0.348023, 0.332368, 1.000000, 1.000000, 1.000000, 0.999999, 0.999998, 0.999994,
+ 0.999988, 0.999976, 0.999957, 0.999928, 0.999891, 0.999837, 0.999759, 0.999650, 0.999463,
+ 0.998551, 0.995879, 0.994366, 0.992964, 0.991479, 0.988521, 0.985101, 0.981482, 0.976168,
+ 0.970242, 0.962585, 0.953950, 0.946973, 0.939686, 0.931248, 0.921614, 0.910765, 0.898617,
+ 0.885183, 0.870772, 0.856138, 0.841120, 0.824962, 0.807732, 0.789813, 0.771638, 0.753008,
+ 0.733686, 0.713927, 0.694082, 0.673967, 0.653549, 0.633135, 0.612702, 0.592200, 0.571904,
+ 0.551679, 0.531678, 0.511898, 0.492437, 0.473239, 0.454451, 0.436067, 0.418054, 0.400542,
+ 0.383486, 0.366848, 0.350781, 0.335182, 1.000000, 1.000000, 1.000000, 0.999999, 0.999997,
+ 0.999993, 0.999985, 0.999972, 0.999951, 0.999919, 0.999877, 0.999817, 0.999733, 0.999608,
+ 0.999380, 0.997685, 0.995603, 0.994264, 0.992911, 0.991287, 0.987923, 0.984871, 0.981239,
+ 0.975933, 0.970149, 0.962511, 0.953824, 0.945699, 0.938285, 0.929907, 0.920343, 0.909537,
+ 0.897435, 0.884056, 0.869626, 0.854490, 0.839459, 0.823511, 0.806511, 0.788752, 0.770440,
+ 0.751995, 0.732962, 0.713424, 0.693525, 0.673798, 0.653622, 0.633301, 0.613224, 0.592938,
+ 0.572833, 0.552904, 0.533030, 0.513556, 0.494215, 0.475279, 0.456673, 0.438411, 0.420583,
+ 0.403178, 0.386178, 0.369728, 0.353688, 0.338147, 1.000000, 1.000000, 1.000000, 0.999999,
+ 0.999997, 0.999991, 0.999984, 0.999967, 0.999944, 0.999912, 0.999863, 0.999796, 0.999703,
+ 0.999563, 0.999279, 0.997104, 0.995394, 0.994111, 0.992825, 0.990979, 0.987529, 0.984661,
+ 0.980774, 0.975758, 0.969866, 0.962465, 0.953678, 0.944489, 0.936886, 0.928356, 0.918820,
+ 0.908073, 0.896092, 0.882833, 0.868463, 0.853212, 0.837744, 0.822048, 0.805333, 0.787643,
+ 0.769414, 0.750830, 0.732178, 0.712972, 0.693227, 0.673569, 0.653744, 0.633739, 0.613735,
+ 0.593822, 0.573916, 0.554158, 0.534652, 0.515248, 0.496233, 0.477436, 0.459009, 0.440929,
+ 0.423259, 0.405951, 0.389136, 0.372690, 0.356789, 0.341329, 1.000000, 1.000000, 1.000000,
+ 0.999999, 0.999996, 0.999991, 0.999981, 0.999966, 0.999939, 0.999903, 0.999847, 0.999771,
+ 0.999666, 0.999510, 0.999131, 0.996690, 0.995147, 0.993882, 0.992696, 0.990474, 0.987227,
+ 0.984334, 0.980153, 0.975438, 0.969406, 0.962238, 0.953598, 0.943868, 0.935356, 0.926721,
+ 0.917122, 0.906430, 0.894550, 0.881354, 0.867131, 0.851954, 0.835972, 0.820331, 0.803911,
+ 0.786452, 0.768420, 0.749821, 0.731298, 0.712393, 0.692979, 0.673418, 0.653859, 0.634232,
+ 0.614327, 0.594732, 0.575131, 0.555584, 0.536346, 0.517175, 0.498323, 0.479744, 0.461485,
+ 0.443645, 0.426061, 0.408969, 0.392155, 0.375921, 0.360060, 0.344677, 1.000000, 1.000000,
+ 1.000000, 0.999999, 0.999997, 0.999991, 0.999979, 0.999960, 0.999931, 0.999891, 0.999832,
+ 0.999748, 0.999629, 0.999449, 0.998880, 0.996305, 0.995024, 0.993812, 0.992508, 0.989721,
+ 0.986936, 0.983936, 0.979629, 0.974979, 0.968928, 0.961970, 0.953291, 0.943458, 0.933644,
+ 0.925007, 0.915388, 0.904755, 0.892932, 0.879831, 0.865794, 0.850672, 0.834591, 0.818398,
+ 0.802304, 0.785151, 0.767450, 0.748987, 0.730325, 0.711758, 0.692761, 0.673417, 0.653908,
+ 0.634686, 0.615168, 0.595707, 0.576393, 0.557198, 0.538018, 0.519253, 0.500555, 0.482220,
+ 0.464197, 0.446414, 0.429106, 0.412035, 0.395508, 0.379284, 0.363538, 0.348220, 1.000000,
+ 1.000000, 1.000000, 0.999999, 0.999995, 0.999989, 0.999977, 0.999955, 0.999924, 0.999879,
+ 0.999813, 0.999722, 0.999590, 0.999381, 0.998335, 0.996088, 0.994814, 0.993709, 0.992220,
+ 0.989209, 0.986575, 0.983383, 0.979084, 0.974272, 0.968359, 0.961275, 0.953025, 0.943098,
+ 0.932434, 0.923101, 0.913477, 0.902861, 0.891059, 0.878072, 0.864118, 0.849188, 0.833281,
+ 0.816808, 0.800596, 0.783745, 0.766331, 0.748123, 0.729686, 0.711078, 0.692527, 0.673491,
+ 0.654296, 0.635113, 0.616048, 0.596847, 0.577720, 0.558879, 0.540028, 0.521371, 0.502996,
+ 0.484858, 0.466997, 0.449477, 0.432217, 0.415426, 0.398924, 0.382890, 0.367206, 0.351955,
+ 1.000000, 1.000000, 1.000000, 0.999998, 0.999996, 0.999988, 0.999974, 0.999953, 0.999918,
+ 0.999865, 0.999791, 0.999690, 0.999542, 0.999293, 0.997535, 0.995790, 0.994609, 0.993557,
+ 0.991766, 0.988767, 0.986255, 0.982544, 0.978541, 0.973528, 0.967700, 0.960596, 0.952299,
+ 0.942684, 0.931653, 0.921211, 0.911489, 0.900818, 0.889018, 0.876245, 0.862406, 0.847517,
+ 0.831852, 0.815367, 0.798719, 0.782224, 0.765167, 0.747304, 0.729133, 0.710485, 0.692196,
+ 0.673589, 0.654770, 0.635717, 0.616986, 0.598119, 0.579298, 0.560560, 0.542163, 0.523669,
+ 0.505564, 0.487642, 0.469991, 0.452658, 0.435620, 0.418937, 0.402612, 0.386633, 0.371091,
+ 0.355949, 1.000000, 1.000000, 0.999999, 0.999998, 0.999995, 0.999986, 0.999973, 0.999948,
+ 0.999909, 0.999852, 0.999769, 0.999656, 0.999490, 0.999186, 0.997059, 0.995624, 0.994510,
+ 0.993327, 0.991020, 0.988379, 0.985771, 0.981971, 0.978051, 0.972892, 0.967020, 0.959965,
+ 0.951625, 0.941902, 0.930951, 0.919370, 0.909285, 0.898562, 0.886809, 0.874251, 0.860597,
+ 0.845808, 0.830365, 0.813972, 0.797260, 0.780597, 0.763854, 0.746401, 0.728519, 0.710203,
+ 0.691882, 0.673687, 0.655275, 0.636621, 0.617909, 0.599473, 0.581032, 0.562560, 0.544295,
+ 0.526228, 0.508293, 0.490652, 0.473242, 0.456004, 0.439212, 0.422663, 0.406476, 0.390647,
+ 0.375204, 0.360129, 1.000000, 1.000000, 1.000000, 0.999999, 0.999994, 0.999984, 0.999969,
+ 0.999940, 0.999898, 0.999837, 0.999746, 0.999617, 0.999438, 0.999016, 0.996703, 0.995302,
+ 0.994356, 0.992993, 0.990390, 0.988072, 0.985152, 0.981447, 0.977273, 0.972234, 0.966113,
+ 0.959033, 0.950869, 0.941217, 0.930175, 0.918279, 0.906941, 0.896201, 0.884509, 0.871920,
+ 0.858420, 0.843906, 0.828730, 0.812524, 0.795978, 0.778979, 0.762450, 0.745459, 0.727966,
+ 0.710046, 0.691808, 0.673739, 0.655756, 0.637574, 0.619153, 0.600887, 0.582796, 0.564748,
+ 0.546636, 0.528904, 0.511252, 0.493791, 0.476563, 0.459695, 0.442942, 0.426632, 0.410558,
+ 0.394895, 0.379517, 0.364560, 1.000000, 1.000000, 1.000000, 0.999998, 0.999994, 0.999984,
+ 0.999966, 0.999934, 0.999887, 0.999819, 0.999720, 0.999578, 0.999367, 0.998696, 0.996353,
+ 0.995201, 0.994115, 0.992665, 0.989948, 0.987633, 0.984331, 0.980827, 0.976390, 0.971327,
+ 0.965201, 0.957977, 0.949712, 0.940128, 0.929187, 0.917237, 0.904645, 0.893711, 0.882112,
+ 0.869516, 0.856236, 0.841929, 0.826924, 0.810991, 0.794686, 0.777761, 0.760980, 0.744384,
+ 0.727314, 0.709877, 0.691988, 0.674098, 0.656243, 0.638603, 0.620606, 0.602574, 0.584694,
+ 0.567018, 0.549311, 0.531673, 0.514403, 0.497148, 0.480177, 0.463439, 0.446998, 0.430743,
+ 0.414943, 0.399304, 0.384121, 0.369251, 1.000000, 1.000000, 1.000000, 0.999997, 0.999992,
+ 0.999981, 0.999962, 0.999927, 0.999874, 0.999798, 0.999691, 0.999533, 0.999291, 0.997909,
+ 0.996117, 0.995029, 0.993880, 0.992142, 0.989576, 0.987185, 0.983587, 0.980055, 0.975487,
+ 0.970172, 0.963998, 0.956738, 0.948637, 0.939083, 0.928169, 0.916144, 0.903147, 0.890916,
+ 0.879389, 0.866895, 0.853826, 0.839729, 0.824957, 0.809472, 0.793341, 0.776743, 0.759808,
+ 0.743277, 0.726643, 0.709685, 0.692249, 0.674639, 0.657008, 0.639576, 0.622114, 0.604471,
+ 0.586851, 0.569340, 0.552135, 0.534806, 0.517599, 0.500765, 0.484035, 0.467440, 0.451212,
+ 0.435240, 0.419399, 0.404083, 0.388944, 0.374182, 1.000000, 1.000000, 1.000000, 0.999998,
+ 0.999993, 0.999979, 0.999958, 0.999919, 0.999861, 0.999774, 0.999656, 0.999482, 0.999195,
+ 0.997307, 0.995837, 0.994722, 0.993707, 0.991391, 0.989169, 0.986461, 0.982904, 0.979062,
+ 0.974536, 0.969035, 0.962653, 0.955486, 0.947243, 0.937747, 0.926861, 0.914936, 0.901835,
+ 0.888472, 0.876571, 0.864223, 0.851252, 0.837374, 0.822985, 0.807788, 0.791927, 0.775702,
+ 0.758928, 0.742347, 0.725914, 0.709495, 0.692569, 0.675363, 0.658085, 0.640639, 0.623698,
+ 0.606505, 0.589267, 0.572008, 0.554939, 0.538132, 0.521211, 0.504487, 0.488048, 0.471807,
+ 0.455651, 0.439858, 0.424332, 0.408983, 0.394071, 0.379402, 1.000000, 1.000000, 1.000000,
+ 0.999997, 0.999992, 0.999978, 0.999954, 0.999913, 0.999844, 0.999753, 0.999618, 0.999424,
+ 0.999067, 0.996875, 0.995659, 0.994603, 0.993420, 0.990874, 0.988713, 0.985585, 0.982193,
+ 0.978145, 0.973416, 0.967801, 0.961483, 0.954069, 0.945704, 0.936138, 0.925374, 0.913395,
+ 0.900339, 0.886675, 0.873512, 0.861326, 0.848513, 0.834956, 0.820820, 0.805943, 0.790574,
+ 0.774677, 0.758279, 0.741807, 0.725271, 0.709231, 0.692874, 0.676189, 0.659352, 0.642296,
+ 0.625250, 0.608700, 0.591823, 0.575012, 0.558143, 0.541491, 0.525075, 0.508558, 0.492277,
+ 0.476270, 0.460459, 0.444740, 0.429400, 0.414309, 0.399421, 0.384907, 1.000000, 1.000000,
+ 1.000000, 0.999997, 0.999990, 0.999977, 0.999947, 0.999902, 0.999832, 0.999730, 0.999577,
+ 0.999359, 0.998845, 0.996554, 0.995328, 0.994442, 0.992919, 0.990393, 0.988170, 0.984855,
+ 0.981312, 0.977149, 0.972137, 0.966207, 0.959967, 0.952454, 0.943873, 0.934434, 0.923813,
+ 0.911942, 0.898928, 0.885120, 0.871043, 0.858248, 0.845666, 0.832346, 0.818482, 0.804029,
+ 0.788982, 0.773571, 0.757700, 0.741484, 0.725186, 0.708915, 0.693244, 0.677028, 0.660656,
+ 0.644079, 0.627377, 0.610804, 0.594542, 0.578112, 0.561650, 0.545163, 0.528962, 0.512926,
+ 0.496893, 0.481007, 0.465397, 0.450042, 0.434740, 0.419831, 0.405156, 0.390692, 1.000000,
+ 1.000000, 0.999999, 0.999997, 0.999989, 0.999973, 0.999942, 0.999891, 0.999813, 0.999698,
+ 0.999532, 0.999285, 0.998286, 0.996295, 0.995215, 0.994182, 0.992032, 0.989855, 0.987415,
+ 0.984047, 0.980050, 0.976017, 0.970845, 0.964767, 0.958269, 0.950600, 0.942033, 0.932501,
+ 0.921807, 0.910017, 0.897149, 0.883414, 0.869182, 0.855055, 0.842687, 0.829548, 0.816162,
+ 0.802072, 0.787436, 0.772533, 0.757043, 0.741263, 0.725330, 0.709262, 0.693497, 0.678038,
+ 0.662128, 0.646068, 0.629824, 0.613437, 0.597334, 0.581401, 0.565372, 0.549288, 0.533182,
+ 0.517405, 0.501765, 0.486143, 0.470675, 0.455465, 0.440532, 0.425630, 0.411113, 0.396887,
+ 1.000000, 1.000000, 0.999999, 0.999996, 0.999989, 0.999970, 0.999934, 0.999879, 0.999793,
+ 0.999665, 0.999481, 0.999192, 0.997506, 0.995926, 0.995009, 0.993736, 0.991298, 0.989326,
+ 0.986371, 0.983199, 0.979032, 0.974596, 0.969364, 0.963198, 0.956385, 0.948509, 0.939993,
+ 0.930421, 0.919590, 0.908140, 0.895349, 0.881699, 0.867456, 0.852784, 0.839500, 0.826629,
+ 0.813602, 0.799983, 0.785873, 0.771340, 0.756480, 0.741190, 0.725687, 0.709997, 0.694192,
+ 0.678975, 0.663673, 0.648135, 0.632442, 0.616477, 0.600565, 0.584772, 0.569202, 0.553595,
+ 0.537881, 0.522193, 0.506784, 0.491554, 0.476349, 0.461278, 0.446419, 0.431913, 0.417443,
+ 0.403271, 1.000000, 1.000000, 0.999999, 0.999995, 0.999986, 0.999966, 0.999927, 0.999867,
+ 0.999772, 0.999629, 0.999423, 0.999075, 0.997024, 0.995773, 0.994651, 0.993353, 0.990822,
+ 0.988569, 0.985596, 0.982182, 0.977871, 0.973140, 0.967584, 0.961408, 0.954294, 0.946398,
+ 0.937603, 0.927937, 0.917305, 0.905833, 0.893138, 0.879770, 0.865720, 0.851023, 0.836801,
+ 0.823784, 0.810909, 0.797886, 0.784177, 0.770243, 0.755925, 0.741144, 0.726214, 0.710971,
+ 0.695563, 0.680212, 0.665304, 0.650297, 0.635168, 0.619796, 0.604217, 0.588692, 0.573254,
+ 0.557998, 0.542839, 0.527470, 0.512162, 0.497115, 0.482296, 0.467477, 0.452812, 0.438310,
+ 0.424184, 0.410163, 1.000000, 1.000000, 0.999999, 0.999996, 0.999984, 0.999962, 0.999920,
+ 0.999852, 0.999745, 0.999586, 0.999354, 0.998894, 0.996686, 0.995485, 0.994493, 0.992573,
+ 0.990323, 0.987772, 0.984692, 0.980887, 0.976446, 0.971625, 0.965717, 0.959421, 0.951975,
+ 0.944086, 0.935066, 0.925403, 0.914814, 0.903208, 0.890958, 0.877817, 0.863828, 0.849289,
+ 0.834872, 0.820889, 0.808183, 0.795660, 0.782556, 0.769066, 0.755386, 0.741229, 0.726726,
+ 0.712170, 0.697209, 0.682170, 0.667203, 0.652689, 0.637938, 0.623262, 0.608190, 0.593002,
+ 0.577817, 0.562737, 0.547836, 0.533036, 0.518052, 0.503135, 0.488422, 0.473986, 0.459552,
+ 0.445282, 0.431149, 0.417407, 1.000000, 1.000000, 0.999999, 0.999994, 0.999983, 0.999957,
+ 0.999914, 0.999835, 0.999718, 0.999538, 0.999275, 0.998454, 0.996341, 0.995246, 0.994222,
+ 0.991844, 0.989829, 0.986688, 0.983562, 0.979638, 0.974932, 0.969827, 0.963621, 0.957146,
+ 0.949365, 0.941398, 0.932245, 0.922556, 0.911949, 0.900627, 0.888440, 0.875544, 0.862005,
+ 0.847810, 0.833372, 0.819134, 0.805508, 0.793339, 0.780916, 0.767837, 0.754858, 0.741307,
+ 0.727496, 0.713386, 0.699131, 0.684542, 0.669878, 0.655261, 0.641035, 0.626685, 0.612377,
+ 0.597625, 0.582805, 0.568030, 0.553204, 0.538684, 0.524269, 0.509662, 0.495119, 0.480735,
+ 0.466634, 0.452593, 0.438748, 0.424915, 1.000000, 1.000000, 0.999998, 0.999994, 0.999982,
+ 0.999956, 0.999901, 0.999818, 0.999683, 0.999487, 0.999185, 0.997584, 0.996004, 0.995050,
+ 0.993715, 0.991212, 0.989057, 0.985879, 0.982243, 0.978206, 0.973119, 0.967919, 0.961343,
+ 0.954603, 0.946712, 0.938378, 0.929266, 0.919443, 0.908911, 0.897725, 0.885589, 0.873254,
+ 0.859889, 0.846123, 0.832094, 0.817898, 0.803866, 0.791061, 0.779235, 0.766885, 0.754292,
+ 0.741565, 0.728331, 0.714861, 0.701179, 0.687166, 0.673012, 0.658716, 0.644442, 0.630472,
+ 0.616519, 0.602514, 0.588172, 0.573689, 0.559281, 0.544768, 0.530543, 0.516485, 0.502303,
+ 0.488100, 0.474095, 0.460245, 0.446598, 0.433169, 1.000000, 1.000000, 0.999997, 0.999993,
+ 0.999980, 0.999947, 0.999891, 0.999794, 0.999647, 0.999425, 0.999062, 0.997049, 0.995778,
+ 0.994652, 0.992778, 0.990482, 0.988004, 0.984893, 0.980881, 0.976605, 0.971199, 0.965610,
+ 0.958925, 0.951746, 0.943791, 0.935200, 0.926018, 0.916028, 0.905724, 0.894528, 0.882914,
+ 0.870740, 0.857802, 0.844552, 0.830857, 0.816921, 0.803102, 0.789625, 0.777480, 0.765891,
+ 0.753908, 0.741795, 0.729390, 0.716440, 0.703411, 0.690068, 0.676438, 0.662586, 0.648697,
+ 0.634732, 0.620997, 0.607451, 0.593765, 0.579748, 0.565661, 0.551594, 0.537396, 0.523433,
+ 0.509708, 0.495972, 0.482082, 0.468427, 0.454890, 0.441623, 1.000000, 1.000000, 0.999999,
+ 0.999991, 0.999977, 0.999940, 0.999875, 0.999769, 0.999605, 0.999352, 0.998882, 0.996665,
+ 0.995459, 0.994380, 0.992014, 0.989912, 0.986796, 0.983537, 0.979326, 0.974792, 0.969140,
+ 0.963160, 0.956222, 0.948807, 0.940518, 0.931755, 0.922452, 0.912319, 0.902227, 0.891142,
+ 0.879838, 0.868047, 0.855745, 0.842718, 0.829827, 0.816398, 0.802786, 0.789396, 0.776581,
+ 0.764901, 0.753710, 0.742102, 0.730448, 0.718337, 0.705768, 0.693172, 0.680153, 0.666882,
+ 0.653401, 0.639837, 0.626152, 0.612676, 0.599435, 0.586109, 0.572473, 0.558715, 0.544964,
+ 0.531112, 0.517416, 0.503992, 0.490653, 0.477162, 0.463832, 0.450645, 1.000000, 1.000000,
+ 0.999999, 0.999992, 0.999973, 0.999933, 0.999861, 0.999741, 0.999554, 0.999267, 0.998411,
+ 0.996303, 0.995191, 0.993945, 0.991406, 0.989019, 0.985720, 0.982057, 0.977501, 0.972605,
+ 0.966697, 0.960340, 0.953031, 0.945347, 0.936866, 0.927917, 0.918562, 0.908598, 0.898486,
+ 0.887794, 0.876545, 0.865379, 0.853428, 0.841167, 0.828649, 0.815967, 0.802957, 0.789865,
+ 0.777077, 0.764695, 0.753544, 0.742694, 0.731571, 0.720304, 0.708490, 0.696351, 0.684134,
+ 0.671470, 0.658541, 0.645376, 0.632209, 0.618776, 0.605511, 0.592527, 0.579546, 0.566310,
+ 0.552860, 0.539492, 0.526005, 0.512564, 0.499340, 0.486360, 0.473357, 0.460306, 1.000000,
+ 1.000000, 0.999998, 0.999991, 0.999970, 0.999926, 0.999842, 0.999710, 0.999498, 0.999164,
+ 0.997464, 0.995870, 0.994917, 0.992911, 0.990682, 0.987816, 0.984410, 0.980551, 0.975693,
+ 0.970263, 0.963946, 0.957248, 0.949765, 0.941571, 0.932941, 0.923873, 0.914332, 0.904560,
+ 0.894394, 0.884127, 0.873294, 0.862503, 0.851335, 0.839566, 0.827776, 0.815708, 0.803370,
+ 0.790821, 0.778386, 0.766121, 0.754193, 0.743420, 0.732975, 0.722326, 0.711376, 0.699992,
+ 0.688180, 0.676354, 0.664004, 0.651449, 0.638600, 0.625776, 0.612660, 0.599603, 0.586719,
+ 0.574078, 0.561273, 0.548129, 0.535155, 0.522015, 0.508851, 0.495837, 0.483190, 0.470624,
+ 1.000000, 1.000000, 0.999998, 0.999988, 0.999965, 0.999916, 0.999823, 0.999669, 0.999425,
+ 0.999025, 0.996874, 0.995670, 0.994415, 0.991991, 0.989766, 0.986646, 0.982812, 0.978356,
+ 0.973317, 0.967612, 0.960820, 0.953603, 0.945969, 0.937323, 0.928661, 0.919507, 0.909833,
+ 0.900245, 0.890390, 0.880252, 0.870000, 0.859518, 0.849163, 0.838101, 0.826960, 0.815688,
+ 0.804126, 0.792234, 0.780356, 0.768474, 0.756678, 0.745159, 0.734601, 0.724624, 0.714339,
+ 0.703751, 0.692766, 0.681267, 0.669799, 0.657871, 0.645577, 0.633102, 0.620560, 0.607737,
+ 0.594890, 0.582143, 0.569779, 0.557360, 0.544651, 0.531942, 0.519228, 0.506467, 0.493710,
+ 0.481143, 1.000000, 1.000000, 0.999998, 0.999988, 0.999961, 0.999902, 0.999798, 0.999622,
+ 0.999341, 0.998801, 0.996397, 0.995225, 0.993927, 0.991338, 0.988500, 0.985327, 0.981195,
+ 0.976383, 0.970726, 0.964471, 0.957386, 0.949813, 0.941694, 0.932681, 0.923974, 0.914755,
+ 0.905026, 0.895649, 0.886178, 0.876277, 0.866629, 0.856890, 0.846934, 0.836887, 0.826373,
+ 0.815885, 0.805169, 0.794133, 0.782812, 0.771547, 0.760175, 0.748896, 0.737687, 0.727152,
+ 0.717601, 0.707670, 0.697425, 0.686788, 0.675664, 0.664513, 0.652962, 0.640965, 0.628851,
+ 0.616551, 0.604168, 0.591559, 0.579009, 0.566648, 0.554597, 0.542382, 0.529999, 0.517655,
+ 0.505254, 0.492894, 1.000000, 1.000000, 0.999997, 0.999986, 0.999956, 0.999889, 0.999766,
+ 0.999562, 0.999240, 0.997952, 0.996094, 0.994979, 0.992773, 0.990536, 0.987214, 0.983322,
+ 0.978938, 0.973714, 0.967681, 0.960981, 0.953144, 0.945475, 0.936909, 0.927734, 0.918826,
+ 0.909590, 0.900085, 0.890867, 0.881801, 0.872565, 0.863236, 0.854239, 0.845060, 0.835686,
+ 0.826251, 0.816284, 0.806586, 0.796419, 0.785914, 0.775210, 0.764461, 0.753599, 0.742805,
+ 0.731872, 0.721370, 0.711898, 0.702337, 0.692383, 0.682137, 0.671365, 0.660479, 0.649314,
+ 0.637685, 0.625899, 0.613898, 0.601865, 0.589582, 0.577285, 0.565013, 0.553106, 0.541280,
+ 0.529367, 0.517320, 0.505411, 1.000000, 1.000000, 0.999997, 0.999983, 0.999948, 0.999869,
+ 0.999732, 0.999499, 0.999111, 0.997167, 0.995720, 0.994349, 0.991727, 0.989197, 0.985883,
+ 0.981483, 0.976618, 0.970597, 0.964122, 0.956994, 0.948639, 0.940500, 0.931606, 0.922385,
+ 0.913291, 0.904205, 0.894938, 0.885890, 0.877334, 0.868754, 0.860053, 0.851683, 0.843447,
+ 0.834889, 0.826304, 0.817441, 0.808285, 0.799141, 0.789570, 0.779600, 0.769510, 0.759155,
+ 0.748882, 0.738346, 0.727629, 0.717273, 0.707467, 0.698283, 0.688609, 0.678748, 0.668371,
+ 0.657739, 0.646951, 0.635765, 0.624254, 0.612647, 0.600900, 0.589061, 0.576998, 0.564991,
+ 0.553102, 0.541517, 0.530027, 0.518495, 1.000000, 1.000000, 0.999997, 0.999983, 0.999939,
+ 0.999851, 0.999684, 0.999412, 0.998925, 0.996597, 0.995207, 0.993603, 0.990903, 0.987594,
+ 0.983814, 0.979016, 0.973647, 0.967048, 0.960109, 0.952123, 0.943560, 0.934900, 0.925747,
+ 0.916566, 0.907305, 0.898441, 0.889629, 0.881042, 0.872874, 0.865064, 0.857225, 0.849446,
+ 0.842063, 0.834561, 0.826814, 0.818875, 0.810748, 0.802316, 0.793699, 0.784704, 0.775198,
+ 0.765643, 0.755735, 0.745873, 0.735526, 0.725229, 0.714892, 0.704807, 0.695502, 0.686241,
+ 0.676633, 0.666688, 0.656384, 0.645871, 0.635174, 0.624113, 0.612788, 0.601426, 0.589925,
+ 0.578399, 0.566612, 0.554931, 0.543383, 0.532065, 1.000000, 1.000000, 0.999996, 0.999977,
+ 0.999928, 0.999824, 0.999633, 0.999306, 0.998429, 0.996133, 0.994890, 0.992316, 0.989752,
+ 0.986095, 0.981564, 0.976234, 0.970081, 0.962779, 0.955232, 0.946702, 0.937716, 0.928604,
+ 0.919281, 0.910167, 0.901046, 0.892446, 0.884183, 0.876253, 0.868619, 0.861545, 0.854673,
+ 0.847885, 0.841074, 0.834610, 0.827984, 0.820945, 0.813648, 0.806232, 0.798444, 0.790232,
+ 0.781853, 0.772897, 0.763648, 0.754227, 0.744542, 0.734689, 0.724526, 0.714204, 0.704152,
+ 0.694222, 0.685143, 0.675860, 0.666319, 0.656415, 0.646273, 0.635902, 0.625399, 0.614563,
+ 0.603490, 0.592413, 0.581217, 0.570000, 0.558608, 0.547242, 1.000000, 0.999999, 0.999995,
+ 0.999972, 0.999915, 0.999790, 0.999562, 0.999168, 0.997237, 0.995672, 0.994074, 0.991220,
+ 0.987792, 0.983822, 0.978599, 0.972804, 0.965718, 0.958053, 0.949460, 0.940503, 0.931011,
+ 0.921608, 0.912409, 0.903378, 0.894606, 0.886369, 0.878756, 0.871573, 0.864862, 0.858421,
+ 0.852541, 0.846802, 0.841027, 0.835206, 0.829628, 0.823730, 0.817415, 0.810655, 0.803873,
+ 0.796659, 0.788887, 0.780940, 0.772537, 0.763507, 0.754487, 0.745163, 0.735572, 0.725687,
+ 0.715611, 0.705398, 0.695418, 0.685592, 0.676518, 0.667304, 0.657875, 0.648182, 0.638235,
+ 0.628062, 0.617813, 0.607283, 0.596552, 0.585770, 0.575033, 0.564153, 1.000000, 1.000000,
+ 0.999995, 0.999970, 0.999898, 0.999748, 0.999472, 0.998969, 0.996528, 0.995102, 0.992701,
+ 0.989963, 0.985981, 0.981194, 0.975183, 0.968501, 0.960502, 0.952012, 0.942861, 0.933376,
+ 0.923506, 0.914042, 0.904921, 0.896282, 0.887987, 0.880341, 0.873536, 0.867293, 0.861556,
+ 0.856148, 0.850987, 0.846352, 0.841684, 0.836880, 0.832036, 0.827091, 0.821900, 0.816206,
+ 0.810042, 0.803629, 0.796918, 0.789653, 0.781915, 0.774014, 0.765530, 0.756526, 0.747669,
+ 0.738342, 0.728770, 0.718942, 0.708942, 0.698855, 0.688933, 0.679131, 0.669855, 0.660811,
+ 0.651549, 0.642127, 0.632454, 0.622651, 0.612709, 0.602606, 0.592344, 0.581877, 1.000000,
+ 0.999999, 0.999993, 0.999963, 0.999874, 0.999691, 0.999350, 0.998431, 0.995873, 0.994456,
+ 0.991327, 0.987798, 0.983232, 0.977500, 0.970828, 0.962815, 0.954228, 0.944752, 0.935126,
+ 0.925179, 0.915102, 0.905763, 0.897087, 0.888933, 0.881452, 0.874687, 0.868716, 0.863585,
+ 0.858931, 0.854662, 0.850569, 0.846719, 0.843151, 0.839426, 0.835588, 0.831443, 0.827004,
+ 0.822395, 0.817254, 0.811630, 0.805464, 0.799124, 0.792382, 0.785091, 0.777315, 0.769360,
+ 0.760908, 0.751957, 0.743128, 0.733917, 0.724340, 0.714713, 0.704721, 0.694835, 0.684862,
+ 0.675099, 0.665570, 0.656644, 0.647651, 0.638581, 0.629337, 0.619926, 0.610358, 0.600707,
+ 1.000000, 1.000000, 0.999990, 0.999953, 0.999843, 0.999613, 0.999186, 0.997025, 0.995317,
+ 0.992850, 0.989760, 0.985270, 0.979807, 0.973049, 0.965228, 0.956248, 0.946394, 0.936324,
+ 0.926124, 0.915808, 0.905942, 0.897060, 0.889001, 0.881755, 0.875351, 0.869688, 0.864736,
+ 0.860745, 0.857305, 0.854190, 0.851261, 0.848484, 0.845642, 0.842948, 0.840060, 0.836901,
+ 0.833379, 0.829393, 0.825103, 0.820431, 0.815288, 0.809575, 0.803326, 0.796949, 0.790174,
+ 0.782873, 0.775048, 0.767139, 0.758772, 0.750019, 0.741120, 0.732127, 0.722743, 0.713225,
+ 0.703637, 0.693768, 0.684016, 0.674277, 0.664703, 0.655328, 0.646550, 0.637812, 0.629036,
+ 0.620129, 1.000000, 1.000000, 0.999988, 0.999933, 0.999800, 0.999508, 0.998917, 0.996236,
+ 0.994617, 0.991176, 0.987089, 0.981880, 0.974966, 0.967156, 0.957914, 0.947585, 0.936937,
+ 0.926318, 0.915662, 0.905567, 0.896223, 0.888166, 0.881117, 0.875079, 0.869981, 0.865675,
+ 0.862091, 0.859183, 0.856981, 0.855065, 0.853273, 0.851572, 0.849782, 0.847768, 0.845668,
+ 0.843345, 0.840703, 0.837646, 0.834094, 0.830030, 0.825631, 0.820873, 0.815619, 0.809856,
+ 0.803578, 0.797096, 0.790359, 0.783152, 0.775507, 0.767504, 0.759411, 0.750982, 0.742208,
+ 0.733383, 0.724445, 0.715190, 0.705827, 0.696440, 0.686773, 0.677242, 0.667735, 0.658471,
+ 0.649236, 0.640305, 1.000000, 0.999999, 0.999984, 0.999918, 0.999737, 0.999350, 0.997576,
+ 0.995476, 0.992614, 0.988817, 0.983601, 0.976880, 0.968694, 0.959092, 0.948297, 0.936831,
+ 0.925592, 0.914494, 0.904159, 0.894643, 0.886417, 0.879620, 0.874023, 0.869533, 0.865967,
+ 0.863238, 0.861113, 0.859527, 0.858367, 0.857594, 0.856882, 0.856172, 0.855316, 0.854197,
+ 0.852818, 0.851062, 0.849046, 0.846747, 0.844043, 0.840842, 0.837164, 0.832985, 0.828344,
+ 0.823544, 0.818276, 0.812543, 0.806374, 0.799838, 0.793170, 0.786246, 0.778956, 0.771297,
+ 0.763278, 0.755252, 0.746984, 0.738445, 0.729688, 0.721045, 0.712189, 0.703099, 0.694045,
+ 0.684930, 0.675601, 0.666480, 1.000000, 0.999999, 0.999978, 0.999888, 0.999639, 0.999093,
+ 0.996310, 0.994405, 0.990527, 0.985186, 0.978518, 0.969748, 0.959597, 0.948104, 0.935724,
+ 0.923704, 0.912023, 0.901356, 0.891850, 0.883847, 0.877280, 0.872289, 0.868583, 0.865913,
+ 0.864098, 0.862993, 0.862356, 0.862125, 0.862107, 0.862168, 0.862359, 0.862490, 0.862430,
+ 0.862063, 0.861431, 0.860386, 0.858950, 0.857090, 0.854848, 0.852381, 0.849503, 0.846167,
+ 0.842399, 0.838194, 0.833566, 0.828579, 0.823464, 0.817951, 0.812079, 0.805873, 0.799320,
+ 0.792533, 0.785715, 0.778636, 0.771260, 0.763618, 0.755719, 0.747815, 0.739825, 0.731602,
+ 0.723212, 0.714845, 0.706465, 0.697933, 1.000000, 0.999998, 0.999969, 0.999836, 0.999475,
+ 0.997943, 0.995219, 0.991760, 0.986663, 0.979592, 0.970218, 0.959155, 0.946575, 0.933047,
+ 0.920022, 0.907749, 0.896801, 0.887506, 0.880077, 0.874322, 0.870126, 0.867481, 0.865949,
+ 0.865293, 0.865287, 0.865746, 0.866502, 0.867439, 0.868442, 0.869382, 0.870161, 0.870782,
+ 0.871303, 0.871511, 0.871427, 0.870978, 0.870136, 0.868892, 0.867248, 0.865209, 0.862775,
+ 0.859944, 0.857004, 0.853671, 0.849984, 0.845927, 0.841518, 0.836774, 0.831750, 0.826407,
+ 0.821001, 0.815333, 0.809412, 0.803238, 0.796802, 0.790204, 0.783457, 0.776713, 0.769749,
+ 0.762596, 0.755239, 0.747690, 0.740127, 0.732595, 1.000000, 0.999997, 0.999950, 0.999744,
+ 0.999162, 0.996124, 0.992844, 0.987757, 0.980062, 0.969642, 0.957087, 0.942735, 0.927747,
+ 0.913622, 0.900889, 0.890115, 0.881584, 0.875288, 0.870926, 0.868307, 0.867033, 0.866972,
+ 0.867692, 0.868950, 0.870549, 0.872320, 0.874144, 0.875947, 0.877674, 0.879192, 0.880478,
+ 0.881539, 0.882307, 0.882739, 0.882902, 0.882847, 0.882461, 0.881725, 0.880636, 0.879197,
+ 0.877422, 0.875296, 0.872849, 0.870076, 0.866988, 0.863637, 0.860159, 0.856475, 0.852525,
+ 0.848328, 0.843883, 0.839198, 0.834322, 0.829221, 0.823907, 0.818461, 0.812972, 0.807316,
+ 0.801474, 0.795459, 0.789276, 0.783025, 0.776615, 0.770223, 0.999999, 0.999994, 0.999909,
+ 0.999536, 0.997195, 0.994123, 0.988168, 0.979344, 0.967003, 0.951763, 0.934724, 0.917948,
+ 0.902918, 0.890432, 0.880902, 0.874401, 0.870394, 0.868503, 0.868209, 0.869062, 0.870725,
+ 0.873006, 0.875558, 0.878230, 0.880893, 0.883445, 0.885832, 0.888059, 0.890058, 0.891782,
+ 0.893247, 0.894460, 0.895397, 0.896023, 0.896380, 0.896433, 0.896198, 0.895673, 0.894865,
+ 0.893908, 0.892700, 0.891224, 0.889501, 0.887539, 0.885336, 0.882903, 0.880244, 0.877373,
+ 0.874296, 0.871019, 0.867549, 0.863933, 0.860153, 0.856355, 0.852395, 0.848277, 0.844006,
+ 0.839587, 0.835045, 0.830378, 0.825579, 0.820649, 0.815592, 0.810432, 0.999998, 0.999988,
+ 0.999795, 0.998892, 0.994635, 0.987290, 0.975397, 0.958508, 0.938352, 0.917733, 0.899800,
+ 0.885878, 0.876516, 0.871200, 0.869099, 0.869317, 0.871112, 0.873870, 0.877160, 0.880682,
+ 0.884228, 0.887737, 0.891076, 0.894161, 0.896981, 0.899543, 0.901847, 0.903882, 0.905672,
+ 0.907188, 0.908451, 0.909480, 0.910289, 0.910878, 0.911259, 0.911430, 0.911396, 0.911154,
+ 0.910712, 0.910081, 0.909266, 0.908264, 0.907094, 0.905752, 0.904244, 0.902577, 0.900799,
+ 0.898931, 0.896923, 0.894782, 0.892513, 0.890117, 0.887600, 0.884968, 0.882222, 0.879369,
+ 0.876408, 0.873345, 0.870183, 0.866926, 0.863575, 0.860160, 0.856672, 0.853098, 0.999991,
+ 0.999947, 0.999158, 0.992842, 0.980107, 0.957230, 0.928231, 0.901539, 0.882688, 0.872588,
+ 0.869394, 0.870671, 0.874458, 0.879378, 0.884639, 0.889770, 0.894601, 0.898972, 0.902930,
+ 0.906456, 0.909568, 0.912329, 0.914750, 0.916893, 0.918774, 0.920429, 0.921868, 0.923110,
+ 0.924185, 0.925089, 0.925842, 0.926457, 0.926934, 0.927285, 0.927522, 0.927639, 0.927650,
+ 0.927553, 0.927356, 0.927061, 0.926671, 0.926187, 0.925617, 0.924962, 0.924224, 0.923409,
+ 0.922519, 0.921555, 0.920521, 0.919419, 0.918252, 0.917021, 0.915729, 0.914377, 0.912967,
+ 0.911503, 0.909984, 0.908414, 0.906791, 0.905122, 0.903401, 0.901637, 0.899826, 0.897972,
+ 0.987461, 0.940121, 0.871507, 0.898572, 0.916705, 0.926425, 0.931922, 0.935265, 0.937431,
+ 0.938899, 0.939950, 0.940717, 0.941301, 0.941754, 0.942111, 0.942397, 0.942631, 0.942823,
+ 0.942983, 0.943117, 0.943231, 0.943329, 0.943412, 0.943484, 0.943545, 0.943599, 0.943644,
+ 0.943682, 0.943716, 0.943744, 0.943766, 0.943785, 0.943799, 0.943808, 0.943815, 0.943818,
+ 0.943818, 0.943814, 0.943807, 0.943797, 0.943784, 0.943769, 0.943751, 0.943730, 0.943707,
+ 0.943681, 0.943652, 0.943623, 0.943589, 0.943554, 0.943518, 0.943479, 0.943438, 0.943396,
+ 0.943351, 0.943305, 0.943257, 0.943207, 0.943156, 0.943104, 0.943049, 0.942993, 0.942936,
+ 0.942877,
+};
+
+static float bsdf_split_sum_ggx[64 * 64 * 2] = {
+ 1.000000f, 0.000000f, 1.000000f, 0.000000f, 1.000000f, 0.000000f, 1.000000f, 0.000000f,
+ 1.000000f, 0.000000f, 1.000000f, 0.000000f, 0.999512f, 0.000000f, 0.999512f, 0.000000f,
+ 0.999512f, 0.000000f, 0.999023f, 0.000001f, 0.999023f, 0.000001f, 0.998535f, 0.000001f,
+ 0.998047f, 0.000001f, 0.997559f, 0.000002f, 0.997070f, 0.000003f, 0.996094f, 0.000004f,
+ 0.994629f, 0.000004f, 0.993652f, 0.000006f, 0.991699f, 0.000007f, 0.989746f, 0.000008f,
+ 0.987305f, 0.000010f, 0.984375f, 0.000012f, 0.980957f, 0.000013f, 0.977539f, 0.000016f,
+ 0.973145f, 0.000018f, 0.967773f, 0.000020f, 0.961914f, 0.000023f, 0.955566f, 0.000025f,
+ 0.947754f, 0.000028f, 0.939941f, 0.000031f, 0.930664f, 0.000033f, 0.920410f, 0.000036f,
+ 0.909180f, 0.000039f, 0.896973f, 0.000042f, 0.884277f, 0.000044f, 0.870117f, 0.000047f,
+ 0.854980f, 0.000049f, 0.838867f, 0.000051f, 0.821777f, 0.000053f, 0.803711f, 0.000055f,
+ 0.785156f, 0.000057f, 0.765625f, 0.000058f, 0.745605f, 0.000059f, 0.724609f, 0.000060f,
+ 0.703613f, 0.000061f, 0.681641f, 0.000061f, 0.659668f, 0.000061f, 0.637695f, 0.000061f,
+ 0.615234f, 0.000061f, 0.592773f, 0.000060f, 0.570801f, 0.000060f, 0.548340f, 0.000059f,
+ 0.526855f, 0.000058f, 0.504883f, 0.000057f, 0.483887f, 0.000055f, 0.462891f, 0.000054f,
+ 0.442627f, 0.000053f, 0.422607f, 0.000051f, 0.403320f, 0.000050f, 0.384766f, 0.000048f,
+ 0.366455f, 0.000046f, 0.348877f, 0.000045f, 0.332031f, 0.000043f, 0.315918f, 0.000041f,
+ 0.999512f, 0.000000f, 0.999512f, 0.000000f, 1.000000f, 0.000000f, 1.000000f, 0.000000f,
+ 0.999512f, 0.000000f, 1.000000f, 0.000000f, 0.999512f, 0.000000f, 0.999512f, 0.000000f,
+ 0.999512f, 0.000000f, 0.999023f, 0.000001f, 0.999023f, 0.000001f, 0.998535f, 0.000002f,
+ 0.998047f, 0.000003f, 0.997559f, 0.000004f, 0.997070f, 0.000005f, 0.996094f, 0.000006f,
+ 0.994629f, 0.000008f, 0.993164f, 0.000010f, 0.991699f, 0.000012f, 0.989746f, 0.000015f,
+ 0.987305f, 0.000018f, 0.984375f, 0.000020f, 0.980957f, 0.000024f, 0.977051f, 0.000027f,
+ 0.972168f, 0.000031f, 0.967285f, 0.000035f, 0.961426f, 0.000039f, 0.954590f, 0.000043f,
+ 0.947266f, 0.000048f, 0.938965f, 0.000052f, 0.929199f, 0.000057f, 0.919434f, 0.000061f,
+ 0.908203f, 0.000065f, 0.895996f, 0.000069f, 0.882812f, 0.000073f, 0.868652f, 0.000077f,
+ 0.853027f, 0.000080f, 0.837402f, 0.000083f, 0.820312f, 0.000086f, 0.802246f, 0.000088f,
+ 0.783691f, 0.000090f, 0.764160f, 0.000092f, 0.744141f, 0.000093f, 0.723633f, 0.000093f,
+ 0.702637f, 0.000094f, 0.681152f, 0.000094f, 0.659180f, 0.000093f, 0.637207f, 0.000093f,
+ 0.615234f, 0.000091f, 0.593262f, 0.000090f, 0.571289f, 0.000088f, 0.549316f, 0.000087f,
+ 0.527344f, 0.000085f, 0.505859f, 0.000082f, 0.485107f, 0.000080f, 0.464355f, 0.000078f,
+ 0.444336f, 0.000075f, 0.424561f, 0.000072f, 0.405273f, 0.000070f, 0.386719f, 0.000067f,
+ 0.368652f, 0.000065f, 0.351318f, 0.000062f, 0.334473f, 0.000059f, 0.318115f, 0.000057f,
+ 0.999512f, 0.000000f, 0.999512f, 0.000000f, 0.999512f, 0.000000f, 1.000000f, 0.000000f,
+ 0.999512f, 0.000000f, 0.999512f, 0.000000f, 0.999512f, 0.000001f, 0.999512f, 0.000001f,
+ 0.999512f, 0.000001f, 0.999512f, 0.000003f, 0.999023f, 0.000002f, 0.998535f, 0.000004f,
+ 0.998047f, 0.000005f, 0.997559f, 0.000007f, 0.997070f, 0.000009f, 0.996094f, 0.000011f,
+ 0.994629f, 0.000013f, 0.993164f, 0.000017f, 0.991211f, 0.000020f, 0.989258f, 0.000024f,
+ 0.986816f, 0.000028f, 0.983887f, 0.000033f, 0.980469f, 0.000038f, 0.976562f, 0.000043f,
+ 0.971680f, 0.000049f, 0.966797f, 0.000055f, 0.960449f, 0.000062f, 0.953613f, 0.000068f,
+ 0.946289f, 0.000075f, 0.937500f, 0.000081f, 0.928223f, 0.000088f, 0.917969f, 0.000094f,
+ 0.906738f, 0.000100f, 0.894531f, 0.000106f, 0.880859f, 0.000111f, 0.866699f, 0.000116f,
+ 0.851562f, 0.000120f, 0.835449f, 0.000124f, 0.818359f, 0.000127f, 0.800781f, 0.000130f,
+ 0.782227f, 0.000132f, 0.762695f, 0.000134f, 0.742676f, 0.000134f, 0.722656f, 0.000135f,
+ 0.701660f, 0.000134f, 0.680176f, 0.000133f, 0.658691f, 0.000132f, 0.636719f, 0.000130f,
+ 0.615234f, 0.000128f, 0.593262f, 0.000125f, 0.571289f, 0.000123f, 0.549805f, 0.000119f,
+ 0.528320f, 0.000116f, 0.507324f, 0.000112f, 0.486328f, 0.000109f, 0.466064f, 0.000105f,
+ 0.446045f, 0.000101f, 0.426514f, 0.000097f, 0.407471f, 0.000093f, 0.388916f, 0.000089f,
+ 0.370850f, 0.000085f, 0.353516f, 0.000082f, 0.336914f, 0.000078f, 0.320557f, 0.000074f,
+ 1.000000f, 0.000000f, 0.999512f, 0.000000f, 0.999512f, 0.000000f, 0.999512f, 0.000000f,
+ 1.000000f, 0.000000f, 1.000000f, 0.000001f, 0.999512f, 0.000001f, 0.999512f, 0.000002f,
+ 0.999512f, 0.000002f, 0.999023f, 0.000003f, 0.999023f, 0.000005f, 0.998535f, 0.000006f,
+ 0.998535f, 0.000008f, 0.997559f, 0.000011f, 0.997070f, 0.000014f, 0.996094f, 0.000017f,
+ 0.994629f, 0.000020f, 0.993164f, 0.000026f, 0.991211f, 0.000030f, 0.989258f, 0.000036f,
+ 0.986816f, 0.000043f, 0.983398f, 0.000050f, 0.979980f, 0.000058f, 0.976074f, 0.000066f,
+ 0.971191f, 0.000074f, 0.965820f, 0.000082f, 0.959961f, 0.000093f, 0.952637f, 0.000101f,
+ 0.945312f, 0.000111f, 0.936523f, 0.000120f, 0.927246f, 0.000129f, 0.916504f, 0.000137f,
+ 0.905273f, 0.000145f, 0.892578f, 0.000153f, 0.879395f, 0.000160f, 0.865234f, 0.000166f,
+ 0.850098f, 0.000171f, 0.833984f, 0.000176f, 0.816895f, 0.000179f, 0.799316f, 0.000182f,
+ 0.780762f, 0.000184f, 0.761230f, 0.000185f, 0.741699f, 0.000185f, 0.721191f, 0.000184f,
+ 0.700684f, 0.000183f, 0.679688f, 0.000181f, 0.658203f, 0.000178f, 0.636719f, 0.000175f,
+ 0.615234f, 0.000171f, 0.593262f, 0.000167f, 0.571777f, 0.000162f, 0.550293f, 0.000158f,
+ 0.529297f, 0.000152f, 0.508301f, 0.000147f, 0.487793f, 0.000142f, 0.467529f, 0.000136f,
+ 0.447754f, 0.000131f, 0.428223f, 0.000125f, 0.409424f, 0.000120f, 0.391113f, 0.000115f,
+ 0.373291f, 0.000109f, 0.355957f, 0.000104f, 0.339355f, 0.000099f, 0.323242f, 0.000094f,
+ 0.999512f, 0.000002f, 0.999512f, 0.000002f, 1.000000f, 0.000002f, 0.999512f, 0.000002f,
+ 1.000000f, 0.000002f, 0.999512f, 0.000002f, 0.999512f, 0.000002f, 0.999512f, 0.000003f,
+ 0.999512f, 0.000004f, 0.999512f, 0.000005f, 0.999023f, 0.000007f, 0.998535f, 0.000010f,
+ 0.998047f, 0.000012f, 0.997559f, 0.000017f, 0.996582f, 0.000020f, 0.995605f, 0.000025f,
+ 0.994629f, 0.000032f, 0.993164f, 0.000038f, 0.991211f, 0.000047f, 0.988770f, 0.000055f,
+ 0.986328f, 0.000063f, 0.983398f, 0.000074f, 0.979492f, 0.000085f, 0.975586f, 0.000095f,
+ 0.970703f, 0.000108f, 0.965332f, 0.000121f, 0.958984f, 0.000132f, 0.952148f, 0.000145f,
+ 0.944336f, 0.000157f, 0.935547f, 0.000170f, 0.925781f, 0.000181f, 0.915039f, 0.000192f,
+ 0.903809f, 0.000203f, 0.891113f, 0.000212f, 0.877930f, 0.000220f, 0.863281f, 0.000227f,
+ 0.848145f, 0.000234f, 0.832031f, 0.000239f, 0.814941f, 0.000242f, 0.797363f, 0.000245f,
+ 0.778809f, 0.000247f, 0.759766f, 0.000247f, 0.740234f, 0.000246f, 0.720215f, 0.000244f,
+ 0.699707f, 0.000241f, 0.678711f, 0.000237f, 0.657715f, 0.000233f, 0.636230f, 0.000228f,
+ 0.614746f, 0.000222f, 0.593750f, 0.000216f, 0.572266f, 0.000209f, 0.551270f, 0.000202f,
+ 0.530273f, 0.000195f, 0.509277f, 0.000187f, 0.489014f, 0.000180f, 0.468994f, 0.000172f,
+ 0.449463f, 0.000165f, 0.430176f, 0.000157f, 0.411377f, 0.000150f, 0.393311f, 0.000143f,
+ 0.375488f, 0.000136f, 0.358398f, 0.000129f, 0.341797f, 0.000123f, 0.325684f, 0.000116f,
+ 0.999512f, 0.000005f, 0.999512f, 0.000005f, 0.999512f, 0.000005f, 0.999512f, 0.000005f,
+ 0.999512f, 0.000005f, 0.999512f, 0.000005f, 0.999512f, 0.000006f, 0.999512f, 0.000007f,
+ 0.999512f, 0.000008f, 0.999512f, 0.000011f, 0.999023f, 0.000013f, 0.998535f, 0.000015f,
+ 0.998047f, 0.000019f, 0.997559f, 0.000026f, 0.996582f, 0.000033f, 0.995605f, 0.000040f,
+ 0.994141f, 0.000047f, 0.993164f, 0.000058f, 0.991211f, 0.000069f, 0.988770f, 0.000080f,
+ 0.985840f, 0.000093f, 0.982910f, 0.000106f, 0.979004f, 0.000121f, 0.975098f, 0.000137f,
+ 0.970215f, 0.000153f, 0.964355f, 0.000169f, 0.958008f, 0.000186f, 0.951172f, 0.000201f,
+ 0.943359f, 0.000218f, 0.934082f, 0.000233f, 0.924316f, 0.000248f, 0.914062f, 0.000262f,
+ 0.902344f, 0.000275f, 0.889648f, 0.000286f, 0.875977f, 0.000295f, 0.861816f, 0.000304f,
+ 0.846680f, 0.000311f, 0.830566f, 0.000316f, 0.813477f, 0.000319f, 0.795898f, 0.000321f,
+ 0.777344f, 0.000322f, 0.758301f, 0.000320f, 0.739258f, 0.000318f, 0.719238f, 0.000314f,
+ 0.698730f, 0.000309f, 0.678223f, 0.000303f, 0.657227f, 0.000296f, 0.636230f, 0.000288f,
+ 0.614746f, 0.000280f, 0.593750f, 0.000271f, 0.572754f, 0.000262f, 0.551758f, 0.000252f,
+ 0.531250f, 0.000243f, 0.510742f, 0.000233f, 0.490479f, 0.000223f, 0.470703f, 0.000213f,
+ 0.451172f, 0.000203f, 0.432129f, 0.000194f, 0.413574f, 0.000184f, 0.395508f, 0.000175f,
+ 0.377930f, 0.000166f, 0.360840f, 0.000157f, 0.344238f, 0.000149f, 0.328125f, 0.000141f,
+ 0.999512f, 0.000011f, 0.999512f, 0.000011f, 0.999512f, 0.000011f, 0.999512f, 0.000011f,
+ 0.999512f, 0.000011f, 0.999512f, 0.000012f, 0.999512f, 0.000014f, 0.999512f, 0.000015f,
+ 0.999512f, 0.000017f, 0.999023f, 0.000020f, 0.998535f, 0.000022f, 0.998535f, 0.000028f,
+ 0.998047f, 0.000034f, 0.997559f, 0.000042f, 0.996582f, 0.000050f, 0.995605f, 0.000060f,
+ 0.994141f, 0.000072f, 0.992676f, 0.000084f, 0.990723f, 0.000099f, 0.988281f, 0.000115f,
+ 0.985840f, 0.000133f, 0.982422f, 0.000150f, 0.978516f, 0.000171f, 0.974609f, 0.000191f,
+ 0.969238f, 0.000211f, 0.963867f, 0.000232f, 0.957520f, 0.000253f, 0.950195f, 0.000274f,
+ 0.941895f, 0.000294f, 0.933105f, 0.000314f, 0.922852f, 0.000332f, 0.912109f, 0.000348f,
+ 0.900879f, 0.000363f, 0.888184f, 0.000377f, 0.874512f, 0.000387f, 0.859863f, 0.000397f,
+ 0.844727f, 0.000404f, 0.828613f, 0.000408f, 0.811523f, 0.000411f, 0.793945f, 0.000412f,
+ 0.775879f, 0.000411f, 0.756836f, 0.000407f, 0.737793f, 0.000403f, 0.717773f, 0.000396f,
+ 0.697754f, 0.000389f, 0.677246f, 0.000380f, 0.656738f, 0.000370f, 0.635742f, 0.000359f,
+ 0.614746f, 0.000347f, 0.594238f, 0.000335f, 0.573242f, 0.000323f, 0.552734f, 0.000310f,
+ 0.532227f, 0.000297f, 0.511719f, 0.000284f, 0.491943f, 0.000272f, 0.472412f, 0.000259f,
+ 0.453125f, 0.000246f, 0.434082f, 0.000234f, 0.415771f, 0.000222f, 0.397705f, 0.000211f,
+ 0.380127f, 0.000199f, 0.363281f, 0.000189f, 0.346680f, 0.000178f, 0.330811f, 0.000168f,
+ 0.999512f, 0.000022f, 0.999512f, 0.000022f, 0.999512f, 0.000022f, 0.999512f, 0.000022f,
+ 0.999512f, 0.000023f, 0.999512f, 0.000025f, 0.999512f, 0.000024f, 0.999512f, 0.000028f,
+ 0.999023f, 0.000030f, 0.999023f, 0.000035f, 0.999023f, 0.000040f, 0.998535f, 0.000046f,
+ 0.998047f, 0.000056f, 0.997559f, 0.000063f, 0.996094f, 0.000077f, 0.995605f, 0.000089f,
+ 0.994141f, 0.000106f, 0.992188f, 0.000123f, 0.990234f, 0.000143f, 0.987793f, 0.000163f,
+ 0.985352f, 0.000185f, 0.981934f, 0.000211f, 0.978027f, 0.000236f, 0.973633f, 0.000261f,
+ 0.968750f, 0.000288f, 0.962891f, 0.000314f, 0.956055f, 0.000341f, 0.949219f, 0.000366f,
+ 0.940918f, 0.000391f, 0.931641f, 0.000414f, 0.921875f, 0.000436f, 0.910645f, 0.000455f,
+ 0.898926f, 0.000471f, 0.886230f, 0.000487f, 0.872559f, 0.000499f, 0.858398f, 0.000509f,
+ 0.842773f, 0.000515f, 0.826660f, 0.000518f, 0.810059f, 0.000520f, 0.792480f, 0.000519f,
+ 0.774414f, 0.000515f, 0.755371f, 0.000509f, 0.736328f, 0.000501f, 0.716797f, 0.000492f,
+ 0.696777f, 0.000480f, 0.676758f, 0.000468f, 0.656250f, 0.000454f, 0.635742f, 0.000439f,
+ 0.615234f, 0.000424f, 0.594238f, 0.000408f, 0.573730f, 0.000392f, 0.553223f, 0.000375f,
+ 0.533203f, 0.000359f, 0.513184f, 0.000342f, 0.493408f, 0.000326f, 0.474121f, 0.000310f,
+ 0.455078f, 0.000294f, 0.436279f, 0.000279f, 0.417969f, 0.000264f, 0.400146f, 0.000250f,
+ 0.382812f, 0.000237f, 0.365723f, 0.000223f, 0.349365f, 0.000211f, 0.333496f, 0.000199f,
+ 0.999512f, 0.000041f, 0.999512f, 0.000041f, 0.999512f, 0.000041f, 0.999512f, 0.000042f,
+ 0.999512f, 0.000042f, 0.999512f, 0.000044f, 0.999512f, 0.000046f, 0.999512f, 0.000049f,
+ 0.999512f, 0.000054f, 0.999512f, 0.000059f, 0.999023f, 0.000065f, 0.998535f, 0.000076f,
+ 0.998047f, 0.000087f, 0.997070f, 0.000098f, 0.996582f, 0.000117f, 0.995117f, 0.000135f,
+ 0.993652f, 0.000152f, 0.992188f, 0.000176f, 0.989746f, 0.000201f, 0.987793f, 0.000228f,
+ 0.984863f, 0.000256f, 0.981445f, 0.000286f, 0.977539f, 0.000318f, 0.973145f, 0.000352f,
+ 0.967773f, 0.000384f, 0.961914f, 0.000417f, 0.955566f, 0.000451f, 0.947754f, 0.000481f,
+ 0.939453f, 0.000510f, 0.930176f, 0.000537f, 0.919922f, 0.000563f, 0.909180f, 0.000585f,
+ 0.897461f, 0.000604f, 0.884766f, 0.000620f, 0.871094f, 0.000632f, 0.856445f, 0.000641f,
+ 0.841309f, 0.000647f, 0.825195f, 0.000648f, 0.808105f, 0.000648f, 0.790527f, 0.000643f,
+ 0.772949f, 0.000637f, 0.754395f, 0.000627f, 0.735352f, 0.000615f, 0.715820f, 0.000601f,
+ 0.695801f, 0.000585f, 0.675781f, 0.000568f, 0.655762f, 0.000550f, 0.635742f, 0.000530f,
+ 0.615234f, 0.000510f, 0.594727f, 0.000490f, 0.574707f, 0.000469f, 0.554199f, 0.000448f,
+ 0.534180f, 0.000428f, 0.514648f, 0.000407f, 0.495117f, 0.000387f, 0.475830f, 0.000367f,
+ 0.456787f, 0.000348f, 0.438232f, 0.000329f, 0.420166f, 0.000311f, 0.402344f, 0.000294f,
+ 0.385254f, 0.000277f, 0.368408f, 0.000262f, 0.352051f, 0.000246f, 0.336182f, 0.000232f,
+ 0.999512f, 0.000072f, 0.999512f, 0.000072f, 0.999512f, 0.000072f, 0.999512f, 0.000072f,
+ 0.999512f, 0.000073f, 0.999512f, 0.000076f, 0.999512f, 0.000078f, 0.999512f, 0.000082f,
+ 0.999023f, 0.000086f, 0.999023f, 0.000095f, 0.998535f, 0.000102f, 0.998047f, 0.000116f,
+ 0.998047f, 0.000131f, 0.997070f, 0.000147f, 0.996094f, 0.000167f, 0.995117f, 0.000195f,
+ 0.993652f, 0.000219f, 0.991699f, 0.000246f, 0.989746f, 0.000278f, 0.987305f, 0.000315f,
+ 0.984375f, 0.000350f, 0.980957f, 0.000385f, 0.976562f, 0.000427f, 0.972168f, 0.000467f,
+ 0.967285f, 0.000509f, 0.960938f, 0.000548f, 0.954102f, 0.000587f, 0.946777f, 0.000623f,
+ 0.937988f, 0.000657f, 0.928711f, 0.000690f, 0.918457f, 0.000718f, 0.907715f, 0.000741f,
+ 0.895508f, 0.000762f, 0.882812f, 0.000778f, 0.869141f, 0.000791f, 0.854492f, 0.000798f,
+ 0.839355f, 0.000802f, 0.823242f, 0.000801f, 0.806152f, 0.000796f, 0.789062f, 0.000788f,
+ 0.770996f, 0.000777f, 0.752930f, 0.000762f, 0.733887f, 0.000745f, 0.714844f, 0.000726f,
+ 0.695312f, 0.000704f, 0.675293f, 0.000682f, 0.655273f, 0.000658f, 0.635254f, 0.000633f,
+ 0.615234f, 0.000607f, 0.595215f, 0.000582f, 0.575195f, 0.000556f, 0.555176f, 0.000530f,
+ 0.535645f, 0.000504f, 0.515625f, 0.000479f, 0.496582f, 0.000455f, 0.477539f, 0.000431f,
+ 0.458984f, 0.000407f, 0.440430f, 0.000385f, 0.422363f, 0.000363f, 0.404785f, 0.000343f,
+ 0.387695f, 0.000323f, 0.370850f, 0.000304f, 0.354736f, 0.000286f, 0.338867f, 0.000268f,
+ 0.999512f, 0.000119f, 0.999512f, 0.000119f, 0.999512f, 0.000119f, 0.999512f, 0.000119f,
+ 0.999512f, 0.000121f, 0.999512f, 0.000122f, 0.999512f, 0.000128f, 0.999512f, 0.000131f,
+ 0.999512f, 0.000139f, 0.999023f, 0.000149f, 0.998535f, 0.000161f, 0.998047f, 0.000179f,
+ 0.998047f, 0.000194f, 0.997070f, 0.000220f, 0.996094f, 0.000247f, 0.994629f, 0.000275f,
+ 0.993652f, 0.000309f, 0.991699f, 0.000344f, 0.989746f, 0.000385f, 0.986816f, 0.000429f,
+ 0.983887f, 0.000471f, 0.980469f, 0.000519f, 0.976074f, 0.000565f, 0.971680f, 0.000614f,
+ 0.966309f, 0.000664f, 0.959961f, 0.000710f, 0.953125f, 0.000754f, 0.945312f, 0.000797f,
+ 0.936523f, 0.000837f, 0.927246f, 0.000873f, 0.916992f, 0.000902f, 0.905762f, 0.000929f,
+ 0.893555f, 0.000950f, 0.880859f, 0.000966f, 0.866699f, 0.000977f, 0.852539f, 0.000981f,
+ 0.836914f, 0.000981f, 0.821289f, 0.000977f, 0.804688f, 0.000968f, 0.787109f, 0.000955f,
+ 0.769531f, 0.000937f, 0.751465f, 0.000917f, 0.732422f, 0.000894f, 0.713379f, 0.000868f,
+ 0.694336f, 0.000840f, 0.674805f, 0.000811f, 0.655273f, 0.000780f, 0.635254f, 0.000749f,
+ 0.615723f, 0.000716f, 0.595703f, 0.000685f, 0.575684f, 0.000653f, 0.556152f, 0.000621f,
+ 0.536621f, 0.000590f, 0.517090f, 0.000559f, 0.498291f, 0.000530f, 0.479492f, 0.000501f,
+ 0.460938f, 0.000473f, 0.442627f, 0.000446f, 0.424805f, 0.000420f, 0.407227f, 0.000396f,
+ 0.390137f, 0.000373f, 0.373535f, 0.000350f, 0.357422f, 0.000329f, 0.341553f, 0.000309f,
+ 0.999512f, 0.000187f, 0.999512f, 0.000187f, 0.999512f, 0.000188f, 0.999512f, 0.000188f,
+ 0.999512f, 0.000190f, 0.999512f, 0.000194f, 0.999512f, 0.000201f, 0.999023f, 0.000204f,
+ 0.999023f, 0.000213f, 0.999023f, 0.000228f, 0.998535f, 0.000242f, 0.998535f, 0.000264f,
+ 0.997559f, 0.000285f, 0.997070f, 0.000311f, 0.996094f, 0.000351f, 0.995117f, 0.000386f,
+ 0.993164f, 0.000429f, 0.991211f, 0.000470f, 0.989258f, 0.000520f, 0.986328f, 0.000575f,
+ 0.983398f, 0.000628f, 0.979492f, 0.000683f, 0.975586f, 0.000741f, 0.970703f, 0.000801f,
+ 0.965332f, 0.000855f, 0.958984f, 0.000910f, 0.951660f, 0.000961f, 0.943848f, 0.001009f,
+ 0.935059f, 0.001053f, 0.925781f, 0.001090f, 0.915039f, 0.001123f, 0.903809f, 0.001152f,
+ 0.891602f, 0.001172f, 0.878906f, 0.001186f, 0.864746f, 0.001194f, 0.850586f, 0.001195f,
+ 0.835449f, 0.001191f, 0.819336f, 0.001181f, 0.802734f, 0.001164f, 0.785645f, 0.001144f,
+ 0.768066f, 0.001121f, 0.750000f, 0.001092f, 0.731445f, 0.001061f, 0.712402f, 0.001027f,
+ 0.693359f, 0.000992f, 0.674316f, 0.000955f, 0.654785f, 0.000916f, 0.635254f, 0.000877f,
+ 0.615723f, 0.000838f, 0.596191f, 0.000799f, 0.576660f, 0.000760f, 0.557129f, 0.000721f,
+ 0.538086f, 0.000684f, 0.518555f, 0.000648f, 0.500000f, 0.000612f, 0.481445f, 0.000578f,
+ 0.462891f, 0.000545f, 0.444824f, 0.000513f, 0.427246f, 0.000483f, 0.409912f, 0.000454f,
+ 0.392822f, 0.000427f, 0.376221f, 0.000401f, 0.360107f, 0.000376f, 0.344482f, 0.000353f,
+ 0.999512f, 0.000284f, 0.999512f, 0.000284f, 0.999512f, 0.000284f, 0.999512f, 0.000285f,
+ 0.999512f, 0.000287f, 0.999512f, 0.000292f, 0.999512f, 0.000296f, 0.999023f, 0.000307f,
+ 0.999023f, 0.000320f, 0.999023f, 0.000338f, 0.998535f, 0.000349f, 0.998047f, 0.000381f,
+ 0.997559f, 0.000407f, 0.996582f, 0.000447f, 0.995605f, 0.000480f, 0.994629f, 0.000531f,
+ 0.992676f, 0.000579f, 0.990723f, 0.000637f, 0.988770f, 0.000693f, 0.985840f, 0.000755f,
+ 0.982422f, 0.000824f, 0.979004f, 0.000889f, 0.975098f, 0.000958f, 0.969727f, 0.001024f,
+ 0.963867f, 0.001090f, 0.957520f, 0.001152f, 0.950684f, 0.001211f, 0.942383f, 0.001263f,
+ 0.933594f, 0.001309f, 0.923828f, 0.001353f, 0.913086f, 0.001387f, 0.901855f, 0.001413f,
+ 0.889648f, 0.001432f, 0.876465f, 0.001443f, 0.862793f, 0.001446f, 0.848145f, 0.001442f,
+ 0.833008f, 0.001431f, 0.817383f, 0.001413f, 0.800781f, 0.001390f, 0.783691f, 0.001362f,
+ 0.766113f, 0.001328f, 0.748535f, 0.001291f, 0.729980f, 0.001250f, 0.711426f, 0.001207f,
+ 0.692871f, 0.001163f, 0.673828f, 0.001116f, 0.654785f, 0.001068f, 0.635254f, 0.001020f,
+ 0.616211f, 0.000973f, 0.596680f, 0.000926f, 0.577637f, 0.000878f, 0.558105f, 0.000833f,
+ 0.539062f, 0.000788f, 0.520508f, 0.000745f, 0.501465f, 0.000702f, 0.483154f, 0.000663f,
+ 0.465088f, 0.000624f, 0.447266f, 0.000587f, 0.429443f, 0.000552f, 0.412354f, 0.000518f,
+ 0.395508f, 0.000486f, 0.378906f, 0.000456f, 0.363037f, 0.000427f, 0.347168f, 0.000400f,
+ 0.999512f, 0.000417f, 0.999512f, 0.000417f, 0.999512f, 0.000418f, 0.999512f, 0.000419f,
+ 0.999512f, 0.000422f, 0.999512f, 0.000425f, 0.999023f, 0.000434f, 0.999023f, 0.000447f,
+ 0.999023f, 0.000462f, 0.999023f, 0.000480f, 0.998047f, 0.000508f, 0.998047f, 0.000538f,
+ 0.997070f, 0.000576f, 0.996582f, 0.000621f, 0.995605f, 0.000669f, 0.993652f, 0.000721f,
+ 0.992188f, 0.000784f, 0.990723f, 0.000849f, 0.987793f, 0.000918f, 0.985840f, 0.000996f,
+ 0.982422f, 0.001071f, 0.978516f, 0.001148f, 0.973633f, 0.001225f, 0.968750f, 0.001304f,
+ 0.962891f, 0.001378f, 0.956543f, 0.001447f, 0.948730f, 0.001511f, 0.940918f, 0.001568f,
+ 0.931641f, 0.001617f, 0.921875f, 0.001660f, 0.911621f, 0.001697f, 0.899902f, 0.001719f,
+ 0.887695f, 0.001735f, 0.874512f, 0.001740f, 0.860840f, 0.001738f, 0.846191f, 0.001725f,
+ 0.831055f, 0.001706f, 0.815430f, 0.001679f, 0.798828f, 0.001646f, 0.782227f, 0.001607f,
+ 0.764648f, 0.001562f, 0.747070f, 0.001514f, 0.729004f, 0.001462f, 0.710449f, 0.001409f,
+ 0.691895f, 0.001352f, 0.673340f, 0.001295f, 0.654297f, 0.001237f, 0.635254f, 0.001179f,
+ 0.616211f, 0.001122f, 0.597168f, 0.001065f, 0.578125f, 0.001010f, 0.559570f, 0.000955f,
+ 0.540527f, 0.000902f, 0.521973f, 0.000852f, 0.503418f, 0.000803f, 0.485352f, 0.000755f,
+ 0.467285f, 0.000710f, 0.449463f, 0.000668f, 0.431885f, 0.000626f, 0.414795f, 0.000587f,
+ 0.398193f, 0.000551f, 0.381836f, 0.000516f, 0.365723f, 0.000483f, 0.350098f, 0.000452f,
+ 0.999023f, 0.000597f, 0.999023f, 0.000597f, 0.999023f, 0.000597f, 0.999023f, 0.000598f,
+ 0.999023f, 0.000602f, 0.999023f, 0.000610f, 0.999023f, 0.000618f, 0.999023f, 0.000632f,
+ 0.998535f, 0.000651f, 0.998535f, 0.000675f, 0.998047f, 0.000704f, 0.997559f, 0.000742f,
+ 0.997070f, 0.000787f, 0.996094f, 0.000843f, 0.995117f, 0.000902f, 0.993652f, 0.000966f,
+ 0.992188f, 0.001039f, 0.990234f, 0.001117f, 0.987793f, 0.001197f, 0.984863f, 0.001286f,
+ 0.981445f, 0.001372f, 0.977539f, 0.001464f, 0.972656f, 0.001553f, 0.967773f, 0.001639f,
+ 0.961914f, 0.001722f, 0.955078f, 0.001798f, 0.947754f, 0.001868f, 0.938965f, 0.001928f,
+ 0.930176f, 0.001982f, 0.920410f, 0.002026f, 0.909668f, 0.002056f, 0.897949f, 0.002075f,
+ 0.885254f, 0.002085f, 0.872559f, 0.002083f, 0.858398f, 0.002071f, 0.844238f, 0.002048f,
+ 0.828613f, 0.002018f, 0.812988f, 0.001980f, 0.796875f, 0.001934f, 0.780273f, 0.001883f,
+ 0.763184f, 0.001824f, 0.745605f, 0.001763f, 0.728027f, 0.001698f, 0.709473f, 0.001632f,
+ 0.691406f, 0.001563f, 0.672852f, 0.001494f, 0.654297f, 0.001422f, 0.635254f, 0.001355f,
+ 0.616699f, 0.001286f, 0.598145f, 0.001218f, 0.579102f, 0.001152f, 0.560547f, 0.001089f,
+ 0.541992f, 0.001027f, 0.523438f, 0.000968f, 0.505371f, 0.000911f, 0.487305f, 0.000857f,
+ 0.469482f, 0.000804f, 0.451904f, 0.000755f, 0.434570f, 0.000708f, 0.417480f, 0.000663f,
+ 0.400879f, 0.000621f, 0.384521f, 0.000581f, 0.368652f, 0.000544f, 0.353027f, 0.000508f,
+ 0.999023f, 0.000833f, 0.999023f, 0.000833f, 0.999023f, 0.000834f, 0.999023f, 0.000835f,
+ 0.999023f, 0.000840f, 0.999023f, 0.000845f, 0.998535f, 0.000861f, 0.998535f, 0.000875f,
+ 0.998535f, 0.000897f, 0.998047f, 0.000928f, 0.997559f, 0.000965f, 0.997070f, 0.001007f,
+ 0.996582f, 0.001061f, 0.995605f, 0.001128f, 0.994629f, 0.001195f, 0.993164f, 0.001276f,
+ 0.991699f, 0.001362f, 0.989258f, 0.001453f, 0.986816f, 0.001539f, 0.983887f, 0.001645f,
+ 0.980469f, 0.001747f, 0.976562f, 0.001849f, 0.971680f, 0.001945f, 0.966309f, 0.002045f,
+ 0.959961f, 0.002136f, 0.953613f, 0.002218f, 0.945801f, 0.002291f, 0.937500f, 0.002357f,
+ 0.928223f, 0.002407f, 0.917969f, 0.002447f, 0.907227f, 0.002472f, 0.895508f, 0.002487f,
+ 0.883301f, 0.002485f, 0.870117f, 0.002474f, 0.856445f, 0.002451f, 0.841797f, 0.002417f,
+ 0.826660f, 0.002373f, 0.811035f, 0.002317f, 0.794922f, 0.002258f, 0.778320f, 0.002190f,
+ 0.761230f, 0.002117f, 0.744141f, 0.002041f, 0.726562f, 0.001961f, 0.708496f, 0.001880f,
+ 0.690430f, 0.001796f, 0.672363f, 0.001713f, 0.654297f, 0.001630f, 0.635742f, 0.001547f,
+ 0.617188f, 0.001466f, 0.598633f, 0.001387f, 0.580078f, 0.001310f, 0.561523f, 0.001235f,
+ 0.543457f, 0.001164f, 0.524902f, 0.001095f, 0.507324f, 0.001029f, 0.489258f, 0.000967f,
+ 0.471680f, 0.000906f, 0.454346f, 0.000850f, 0.437012f, 0.000796f, 0.420166f, 0.000745f,
+ 0.403564f, 0.000698f, 0.387451f, 0.000652f, 0.371582f, 0.000609f, 0.356201f, 0.000569f,
+ 0.998535f, 0.001139f, 0.998535f, 0.001139f, 0.998535f, 0.001140f, 0.998535f, 0.001142f,
+ 0.998535f, 0.001147f, 0.998535f, 0.001159f, 0.998535f, 0.001168f, 0.998047f, 0.001190f,
+ 0.998047f, 0.001217f, 0.997559f, 0.001254f, 0.997559f, 0.001301f, 0.997070f, 0.001356f,
+ 0.996094f, 0.001416f, 0.995605f, 0.001493f, 0.994141f, 0.001574f, 0.992676f, 0.001663f,
+ 0.990723f, 0.001759f, 0.988770f, 0.001867f, 0.986328f, 0.001980f, 0.982910f, 0.002087f,
+ 0.979492f, 0.002199f, 0.975586f, 0.002319f, 0.970703f, 0.002422f, 0.965332f, 0.002531f,
+ 0.958496f, 0.002628f, 0.952148f, 0.002714f, 0.944336f, 0.002792f, 0.935547f, 0.002851f,
+ 0.926270f, 0.002903f, 0.916016f, 0.002935f, 0.904785f, 0.002954f, 0.893066f, 0.002956f,
+ 0.880859f, 0.002947f, 0.867676f, 0.002920f, 0.853516f, 0.002882f, 0.839355f, 0.002831f,
+ 0.824219f, 0.002769f, 0.809082f, 0.002699f, 0.792969f, 0.002619f, 0.776367f, 0.002533f,
+ 0.759766f, 0.002443f, 0.742676f, 0.002350f, 0.725586f, 0.002251f, 0.708008f, 0.002151f,
+ 0.689941f, 0.002052f, 0.671875f, 0.001953f, 0.653809f, 0.001854f, 0.635742f, 0.001758f,
+ 0.617676f, 0.001663f, 0.599121f, 0.001572f, 0.581055f, 0.001482f, 0.562988f, 0.001395f,
+ 0.544922f, 0.001313f, 0.526855f, 0.001234f, 0.508789f, 0.001158f, 0.491455f, 0.001086f,
+ 0.473877f, 0.001018f, 0.456787f, 0.000954f, 0.439697f, 0.000892f, 0.422852f, 0.000834f,
+ 0.406494f, 0.000780f, 0.390381f, 0.000729f, 0.374512f, 0.000680f, 0.359131f, 0.000635f,
+ 0.998047f, 0.001528f, 0.998047f, 0.001528f, 0.998047f, 0.001529f, 0.998047f, 0.001532f,
+ 0.998047f, 0.001539f, 0.998047f, 0.001546f, 0.998047f, 0.001562f, 0.998047f, 0.001589f,
+ 0.997559f, 0.001621f, 0.997559f, 0.001668f, 0.996582f, 0.001715f, 0.996582f, 0.001777f,
+ 0.995605f, 0.001859f, 0.994629f, 0.001939f, 0.993652f, 0.002035f, 0.992188f, 0.002140f,
+ 0.990234f, 0.002243f, 0.987793f, 0.002369f, 0.985352f, 0.002489f, 0.981934f, 0.002621f,
+ 0.978516f, 0.002750f, 0.974121f, 0.002876f, 0.969238f, 0.002991f, 0.963867f, 0.003105f,
+ 0.957031f, 0.003206f, 0.950195f, 0.003300f, 0.942383f, 0.003374f, 0.933594f, 0.003431f,
+ 0.923828f, 0.003473f, 0.913574f, 0.003498f, 0.902344f, 0.003506f, 0.890625f, 0.003494f,
+ 0.878418f, 0.003468f, 0.865234f, 0.003426f, 0.851074f, 0.003366f, 0.836914f, 0.003296f,
+ 0.822266f, 0.003216f, 0.806641f, 0.003122f, 0.791016f, 0.003023f, 0.774902f, 0.002916f,
+ 0.758301f, 0.002804f, 0.741211f, 0.002689f, 0.724121f, 0.002573f, 0.707031f, 0.002453f,
+ 0.689453f, 0.002335f, 0.671875f, 0.002216f, 0.653809f, 0.002102f, 0.636230f, 0.001987f,
+ 0.618164f, 0.001878f, 0.600098f, 0.001771f, 0.582031f, 0.001668f, 0.564453f, 0.001569f,
+ 0.546387f, 0.001475f, 0.528809f, 0.001384f, 0.511230f, 0.001297f, 0.493652f, 0.001217f,
+ 0.476318f, 0.001139f, 0.459229f, 0.001065f, 0.442383f, 0.000996f, 0.425781f, 0.000930f,
+ 0.409424f, 0.000869f, 0.393311f, 0.000811f, 0.377686f, 0.000757f, 0.362305f, 0.000707f,
+ 0.997559f, 0.002018f, 0.997559f, 0.002018f, 0.997559f, 0.002018f, 0.997559f, 0.002022f,
+ 0.997559f, 0.002028f, 0.997559f, 0.002045f, 0.997559f, 0.002066f, 0.997559f, 0.002092f,
+ 0.997559f, 0.002129f, 0.996582f, 0.002176f, 0.996094f, 0.002235f, 0.995605f, 0.002312f,
+ 0.995605f, 0.002407f, 0.993652f, 0.002491f, 0.992676f, 0.002605f, 0.991211f, 0.002729f,
+ 0.989258f, 0.002846f, 0.987305f, 0.002987f, 0.984375f, 0.003120f, 0.980957f, 0.003263f,
+ 0.977051f, 0.003403f, 0.972656f, 0.003542f, 0.967285f, 0.003666f, 0.961914f, 0.003782f,
+ 0.955566f, 0.003889f, 0.947754f, 0.003967f, 0.939941f, 0.004044f, 0.931152f, 0.004097f,
+ 0.921387f, 0.004131f, 0.911133f, 0.004139f, 0.899902f, 0.004131f, 0.888184f, 0.004108f,
+ 0.875488f, 0.004055f, 0.862305f, 0.003990f, 0.848633f, 0.003914f, 0.834473f, 0.003819f,
+ 0.819824f, 0.003712f, 0.804199f, 0.003593f, 0.788574f, 0.003469f, 0.772949f, 0.003338f,
+ 0.756348f, 0.003201f, 0.739746f, 0.003063f, 0.723145f, 0.002924f, 0.706055f, 0.002781f,
+ 0.688965f, 0.002644f, 0.671387f, 0.002506f, 0.653809f, 0.002371f, 0.636230f, 0.002239f,
+ 0.618652f, 0.002111f, 0.601074f, 0.001989f, 0.583496f, 0.001871f, 0.565430f, 0.001759f,
+ 0.547852f, 0.001650f, 0.530273f, 0.001547f, 0.513184f, 0.001449f, 0.495850f, 0.001356f,
+ 0.478760f, 0.001269f, 0.461670f, 0.001185f, 0.445068f, 0.001107f, 0.428467f, 0.001035f,
+ 0.412354f, 0.000965f, 0.396240f, 0.000901f, 0.380615f, 0.000840f, 0.365479f, 0.000783f,
+ 0.997070f, 0.002625f, 0.997070f, 0.002625f, 0.997070f, 0.002626f, 0.997070f, 0.002630f,
+ 0.997070f, 0.002640f, 0.997070f, 0.002659f, 0.997070f, 0.002676f, 0.996582f, 0.002708f,
+ 0.996582f, 0.002752f, 0.996094f, 0.002813f, 0.995605f, 0.002886f, 0.995117f, 0.002956f,
+ 0.994141f, 0.003071f, 0.992676f, 0.003172f, 0.991699f, 0.003292f, 0.990234f, 0.003433f,
+ 0.988281f, 0.003580f, 0.985840f, 0.003727f, 0.982910f, 0.003870f, 0.979492f, 0.004028f,
+ 0.975586f, 0.004177f, 0.971191f, 0.004322f, 0.966309f, 0.004456f, 0.959961f, 0.004570f,
+ 0.953125f, 0.004669f, 0.945801f, 0.004757f, 0.937500f, 0.004826f, 0.928711f, 0.004864f,
+ 0.918945f, 0.004883f, 0.908691f, 0.004875f, 0.897461f, 0.004845f, 0.885254f, 0.004795f,
+ 0.872559f, 0.004723f, 0.859863f, 0.004631f, 0.846191f, 0.004520f, 0.832031f, 0.004398f,
+ 0.817383f, 0.004261f, 0.802246f, 0.004116f, 0.786621f, 0.003963f, 0.770996f, 0.003805f,
+ 0.754883f, 0.003639f, 0.738770f, 0.003475f, 0.722168f, 0.003307f, 0.705078f, 0.003143f,
+ 0.688477f, 0.002981f, 0.671387f, 0.002821f, 0.653809f, 0.002665f, 0.636719f, 0.002512f,
+ 0.619141f, 0.002367f, 0.602051f, 0.002226f, 0.584473f, 0.002090f, 0.566895f, 0.001963f,
+ 0.549805f, 0.001840f, 0.532227f, 0.001722f, 0.515137f, 0.001613f, 0.498047f, 0.001508f,
+ 0.481201f, 0.001409f, 0.464355f, 0.001316f, 0.447754f, 0.001228f, 0.431396f, 0.001145f,
+ 0.415283f, 0.001069f, 0.399414f, 0.000997f, 0.383789f, 0.000929f, 0.368652f, 0.000865f,
+ 0.996582f, 0.003370f, 0.996582f, 0.003370f, 0.996582f, 0.003372f, 0.996582f, 0.003378f,
+ 0.996582f, 0.003389f, 0.996094f, 0.003410f, 0.996094f, 0.003435f, 0.996094f, 0.003471f,
+ 0.996094f, 0.003523f, 0.995117f, 0.003588f, 0.995117f, 0.003664f, 0.994141f, 0.003754f,
+ 0.993164f, 0.003864f, 0.992676f, 0.003990f, 0.990723f, 0.004128f, 0.989746f, 0.004288f,
+ 0.987793f, 0.004429f, 0.984375f, 0.004601f, 0.981445f, 0.004757f, 0.978027f, 0.004925f,
+ 0.974121f, 0.005089f, 0.969727f, 0.005241f, 0.964355f, 0.005375f, 0.958008f, 0.005486f,
+ 0.951172f, 0.005596f, 0.943848f, 0.005665f, 0.935547f, 0.005718f, 0.925781f, 0.005737f,
+ 0.916016f, 0.005733f, 0.905762f, 0.005707f, 0.894531f, 0.005650f, 0.882324f, 0.005569f,
+ 0.870117f, 0.005466f, 0.856934f, 0.005341f, 0.843262f, 0.005199f, 0.829102f, 0.005043f,
+ 0.814941f, 0.004871f, 0.799805f, 0.004692f, 0.784668f, 0.004505f, 0.769043f, 0.004314f,
+ 0.753418f, 0.004116f, 0.737305f, 0.003922f, 0.721191f, 0.003729f, 0.704590f, 0.003536f,
+ 0.687988f, 0.003347f, 0.670898f, 0.003162f, 0.654297f, 0.002983f, 0.637207f, 0.002810f,
+ 0.620117f, 0.002642f, 0.603027f, 0.002481f, 0.585938f, 0.002329f, 0.568359f, 0.002182f,
+ 0.551270f, 0.002045f, 0.534180f, 0.001913f, 0.517090f, 0.001788f, 0.500488f, 0.001671f,
+ 0.483643f, 0.001560f, 0.467041f, 0.001456f, 0.450684f, 0.001358f, 0.434326f, 0.001266f,
+ 0.418213f, 0.001181f, 0.402588f, 0.001101f, 0.386963f, 0.001025f, 0.371826f, 0.000954f,
+ 0.995605f, 0.004276f, 0.995605f, 0.004276f, 0.995605f, 0.004280f, 0.995605f, 0.004284f,
+ 0.995605f, 0.004299f, 0.995117f, 0.004318f, 0.995117f, 0.004349f, 0.995117f, 0.004383f,
+ 0.994629f, 0.004456f, 0.994629f, 0.004524f, 0.994141f, 0.004612f, 0.993164f, 0.004704f,
+ 0.992676f, 0.004848f, 0.991699f, 0.004974f, 0.990234f, 0.005142f, 0.987793f, 0.005291f,
+ 0.986328f, 0.005474f, 0.982910f, 0.005638f, 0.980469f, 0.005825f, 0.976562f, 0.005989f,
+ 0.972656f, 0.006157f, 0.967773f, 0.006313f, 0.961914f, 0.006443f, 0.955566f, 0.006554f,
+ 0.948730f, 0.006645f, 0.940918f, 0.006702f, 0.932617f, 0.006733f, 0.923340f, 0.006733f,
+ 0.913574f, 0.006699f, 0.902832f, 0.006645f, 0.891602f, 0.006550f, 0.879395f, 0.006435f,
+ 0.867188f, 0.006294f, 0.854004f, 0.006130f, 0.840332f, 0.005951f, 0.826660f, 0.005756f,
+ 0.812500f, 0.005543f, 0.797363f, 0.005325f, 0.782715f, 0.005100f, 0.767090f, 0.004871f,
+ 0.751465f, 0.004642f, 0.735840f, 0.004414f, 0.719727f, 0.004185f, 0.703613f, 0.003960f,
+ 0.687500f, 0.003744f, 0.670898f, 0.003531f, 0.654297f, 0.003326f, 0.637695f, 0.003128f,
+ 0.620605f, 0.002939f, 0.604004f, 0.002756f, 0.586914f, 0.002584f, 0.569824f, 0.002420f,
+ 0.553223f, 0.002264f, 0.536133f, 0.002117f, 0.519531f, 0.001978f, 0.502930f, 0.001847f,
+ 0.486328f, 0.001723f, 0.469727f, 0.001607f, 0.453369f, 0.001498f, 0.437256f, 0.001395f,
+ 0.421387f, 0.001300f, 0.405762f, 0.001211f, 0.390381f, 0.001127f, 0.375244f, 0.001050f,
+ 0.994141f, 0.005367f, 0.994141f, 0.005367f, 0.994141f, 0.005371f, 0.994141f, 0.005375f,
+ 0.994141f, 0.005394f, 0.994141f, 0.005413f, 0.994141f, 0.005447f, 0.994141f, 0.005508f,
+ 0.993652f, 0.005558f, 0.993652f, 0.005650f, 0.992676f, 0.005741f, 0.991699f, 0.005848f,
+ 0.991211f, 0.006004f, 0.990234f, 0.006149f, 0.988281f, 0.006317f, 0.986328f, 0.006504f,
+ 0.984863f, 0.006687f, 0.981934f, 0.006866f, 0.978516f, 0.007050f, 0.974609f, 0.007233f,
+ 0.970215f, 0.007393f, 0.965820f, 0.007553f, 0.959961f, 0.007675f, 0.953125f, 0.007774f,
+ 0.946289f, 0.007843f, 0.938477f, 0.007889f, 0.929688f, 0.007889f, 0.920410f, 0.007858f,
+ 0.910156f, 0.007793f, 0.899414f, 0.007694f, 0.888672f, 0.007565f, 0.876465f, 0.007401f,
+ 0.864258f, 0.007214f, 0.851074f, 0.007008f, 0.837402f, 0.006779f, 0.823730f, 0.006535f,
+ 0.809570f, 0.006279f, 0.794922f, 0.006023f, 0.780273f, 0.005753f, 0.765137f, 0.005482f,
+ 0.750000f, 0.005215f, 0.734375f, 0.004944f, 0.718750f, 0.004681f, 0.703125f, 0.004425f,
+ 0.687012f, 0.004173f, 0.670898f, 0.003929f, 0.654297f, 0.003700f, 0.638184f, 0.003473f,
+ 0.621582f, 0.003260f, 0.604980f, 0.003056f, 0.588379f, 0.002861f, 0.571777f, 0.002676f,
+ 0.555176f, 0.002502f, 0.538574f, 0.002337f, 0.521973f, 0.002180f, 0.505371f, 0.002035f,
+ 0.488770f, 0.001898f, 0.472656f, 0.001769f, 0.456299f, 0.001649f, 0.440430f, 0.001534f,
+ 0.424561f, 0.001430f, 0.408936f, 0.001329f, 0.393555f, 0.001238f, 0.378418f, 0.001151f,
+ 0.993164f, 0.006672f, 0.993164f, 0.006672f, 0.993164f, 0.006676f, 0.993164f, 0.006687f,
+ 0.993164f, 0.006699f, 0.993164f, 0.006721f, 0.992676f, 0.006760f, 0.992676f, 0.006821f,
+ 0.992188f, 0.006897f, 0.991699f, 0.006973f, 0.991211f, 0.007099f, 0.990234f, 0.007206f,
+ 0.990234f, 0.007366f, 0.988281f, 0.007519f, 0.986328f, 0.007706f, 0.984863f, 0.007912f,
+ 0.982422f, 0.008087f, 0.979980f, 0.008286f, 0.977051f, 0.008476f, 0.972656f, 0.008667f,
+ 0.968262f, 0.008827f, 0.962891f, 0.008980f, 0.957520f, 0.009079f, 0.951172f, 0.009171f,
+ 0.943848f, 0.009216f, 0.935547f, 0.009224f, 0.926758f, 0.009193f, 0.917480f, 0.009125f,
+ 0.906738f, 0.009010f, 0.895996f, 0.008865f, 0.885254f, 0.008682f, 0.873047f, 0.008469f,
+ 0.860840f, 0.008232f, 0.847656f, 0.007973f, 0.834473f, 0.007690f, 0.820801f, 0.007397f,
+ 0.807129f, 0.007092f, 0.792969f, 0.006783f, 0.778320f, 0.006462f, 0.763184f, 0.006145f,
+ 0.748535f, 0.005833f, 0.733398f, 0.005524f, 0.717773f, 0.005219f, 0.702148f, 0.004925f,
+ 0.686523f, 0.004639f, 0.670898f, 0.004364f, 0.654785f, 0.004097f, 0.638672f, 0.003847f,
+ 0.622559f, 0.003605f, 0.605957f, 0.003376f, 0.589844f, 0.003157f, 0.573242f, 0.002951f,
+ 0.556641f, 0.002756f, 0.540527f, 0.002573f, 0.523926f, 0.002399f, 0.507812f, 0.002237f,
+ 0.491455f, 0.002085f, 0.475342f, 0.001943f, 0.459229f, 0.001809f, 0.443359f, 0.001684f,
+ 0.427734f, 0.001567f, 0.412109f, 0.001457f, 0.396973f, 0.001356f, 0.382080f, 0.001261f,
+ 0.991699f, 0.008217f, 0.991699f, 0.008217f, 0.991699f, 0.008217f, 0.991699f, 0.008232f,
+ 0.991211f, 0.008240f, 0.991211f, 0.008270f, 0.991211f, 0.008324f, 0.991211f, 0.008377f,
+ 0.990723f, 0.008461f, 0.990234f, 0.008553f, 0.989746f, 0.008682f, 0.988770f, 0.008820f,
+ 0.987793f, 0.008972f, 0.986816f, 0.009163f, 0.985352f, 0.009338f, 0.982910f, 0.009567f,
+ 0.980957f, 0.009758f, 0.977539f, 0.009956f, 0.974609f, 0.010155f, 0.970215f, 0.010330f,
+ 0.965820f, 0.010483f, 0.960449f, 0.010597f, 0.954590f, 0.010696f, 0.947754f, 0.010750f,
+ 0.940430f, 0.010757f, 0.932129f, 0.010735f, 0.923340f, 0.010651f, 0.913574f, 0.010536f,
+ 0.903809f, 0.010376f, 0.892578f, 0.010162f, 0.881348f, 0.009926f, 0.869629f, 0.009651f,
+ 0.857422f, 0.009354f, 0.844727f, 0.009026f, 0.831543f, 0.008690f, 0.817871f, 0.008331f,
+ 0.804199f, 0.007973f, 0.790527f, 0.007603f, 0.775879f, 0.007233f, 0.761719f, 0.006866f,
+ 0.747070f, 0.006500f, 0.731934f, 0.006145f, 0.716797f, 0.005798f, 0.701660f, 0.005466f,
+ 0.686523f, 0.005138f, 0.670898f, 0.004829f, 0.655273f, 0.004532f, 0.639160f, 0.004246f,
+ 0.623535f, 0.003975f, 0.607422f, 0.003719f, 0.591309f, 0.003477f, 0.575195f, 0.003246f,
+ 0.558594f, 0.003029f, 0.542480f, 0.002827f, 0.526367f, 0.002634f, 0.510254f, 0.002455f,
+ 0.494141f, 0.002285f, 0.478271f, 0.002129f, 0.462402f, 0.001980f, 0.446533f, 0.001843f,
+ 0.430908f, 0.001715f, 0.415527f, 0.001594f, 0.400391f, 0.001483f, 0.385498f, 0.001378f,
+ 0.989746f, 0.010040f, 0.989746f, 0.010040f, 0.989746f, 0.010040f, 0.989746f, 0.010048f,
+ 0.989746f, 0.010071f, 0.989746f, 0.010094f, 0.989258f, 0.010147f, 0.989258f, 0.010223f,
+ 0.988770f, 0.010300f, 0.988770f, 0.010406f, 0.987793f, 0.010529f, 0.986816f, 0.010696f,
+ 0.986328f, 0.010857f, 0.984863f, 0.011055f, 0.982422f, 0.011238f, 0.981445f, 0.011467f,
+ 0.978516f, 0.011673f, 0.975098f, 0.011871f, 0.972168f, 0.012062f, 0.967285f, 0.012215f,
+ 0.962402f, 0.012352f, 0.957031f, 0.012459f, 0.951172f, 0.012535f, 0.944336f, 0.012535f,
+ 0.937012f, 0.012520f, 0.928711f, 0.012428f, 0.919922f, 0.012299f, 0.910156f, 0.012115f,
+ 0.899414f, 0.011879f, 0.889160f, 0.011612f, 0.877441f, 0.011299f, 0.865723f, 0.010956f,
+ 0.853516f, 0.010582f, 0.841309f, 0.010193f, 0.828125f, 0.009773f, 0.814941f, 0.009361f,
+ 0.801270f, 0.008926f, 0.787598f, 0.008499f, 0.773926f, 0.008064f, 0.759766f, 0.007641f,
+ 0.745117f, 0.007225f, 0.730469f, 0.006817f, 0.716309f, 0.006424f, 0.701172f, 0.006042f,
+ 0.686035f, 0.005676f, 0.670898f, 0.005329f, 0.655273f, 0.004993f, 0.640137f, 0.004673f,
+ 0.624512f, 0.004372f, 0.608398f, 0.004086f, 0.592773f, 0.003817f, 0.576660f, 0.003561f,
+ 0.561035f, 0.003323f, 0.544922f, 0.003098f, 0.528809f, 0.002884f, 0.512695f, 0.002686f,
+ 0.497070f, 0.002501f, 0.481201f, 0.002327f, 0.465332f, 0.002165f, 0.449707f, 0.002014f,
+ 0.434326f, 0.001873f, 0.418945f, 0.001740f, 0.403809f, 0.001617f, 0.388916f, 0.001504f,
+ 0.987793f, 0.012169f, 0.987793f, 0.012169f, 0.987793f, 0.012169f, 0.987793f, 0.012184f,
+ 0.987305f, 0.012207f, 0.987305f, 0.012245f, 0.987305f, 0.012291f, 0.986816f, 0.012360f,
+ 0.986816f, 0.012459f, 0.986328f, 0.012573f, 0.985840f, 0.012695f, 0.984863f, 0.012878f,
+ 0.983887f, 0.013046f, 0.982422f, 0.013237f, 0.980469f, 0.013466f, 0.979004f, 0.013680f,
+ 0.976074f, 0.013878f, 0.972656f, 0.014069f, 0.969238f, 0.014259f, 0.964355f, 0.014397f,
+ 0.959961f, 0.014488f, 0.954102f, 0.014580f, 0.947754f, 0.014595f, 0.940430f, 0.014557f,
+ 0.933105f, 0.014481f, 0.925293f, 0.014328f, 0.915527f, 0.014122f, 0.906250f, 0.013870f,
+ 0.895996f, 0.013565f, 0.885254f, 0.013206f, 0.873535f, 0.012817f, 0.862305f, 0.012383f,
+ 0.850098f, 0.011932f, 0.837891f, 0.011452f, 0.824707f, 0.010963f, 0.812012f, 0.010460f,
+ 0.798828f, 0.009964f, 0.785156f, 0.009460f, 0.771484f, 0.008965f, 0.757812f, 0.008484f,
+ 0.743652f, 0.008003f, 0.729492f, 0.007542f, 0.715332f, 0.007095f, 0.700684f, 0.006668f,
+ 0.686035f, 0.006256f, 0.670898f, 0.005863f, 0.655762f, 0.005489f, 0.640625f, 0.005135f,
+ 0.625488f, 0.004799f, 0.609863f, 0.004478f, 0.594238f, 0.004181f, 0.578613f, 0.003901f,
+ 0.562988f, 0.003635f, 0.547363f, 0.003386f, 0.531250f, 0.003153f, 0.515625f, 0.002935f,
+ 0.500000f, 0.002729f, 0.484131f, 0.002539f, 0.468506f, 0.002361f, 0.453125f, 0.002195f,
+ 0.437744f, 0.002041f, 0.422363f, 0.001897f, 0.407471f, 0.001763f, 0.392578f, 0.001637f,
+ 0.985352f, 0.014641f, 0.985352f, 0.014641f, 0.984863f, 0.014648f, 0.984863f, 0.014656f,
+ 0.984863f, 0.014679f, 0.984863f, 0.014717f, 0.984863f, 0.014771f, 0.984375f, 0.014839f,
+ 0.984375f, 0.014938f, 0.983398f, 0.015060f, 0.983398f, 0.015244f, 0.981934f, 0.015388f,
+ 0.980957f, 0.015587f, 0.979492f, 0.015778f, 0.977539f, 0.015976f, 0.975586f, 0.016190f,
+ 0.972656f, 0.016388f, 0.969727f, 0.016571f, 0.965820f, 0.016739f, 0.961426f, 0.016861f,
+ 0.956055f, 0.016922f, 0.950684f, 0.016953f, 0.943848f, 0.016922f, 0.937012f, 0.016815f,
+ 0.929199f, 0.016663f, 0.920410f, 0.016434f, 0.911621f, 0.016144f, 0.901855f, 0.015793f,
+ 0.891602f, 0.015411f, 0.880859f, 0.014954f, 0.869629f, 0.014473f, 0.857910f, 0.013947f,
+ 0.846191f, 0.013390f, 0.833984f, 0.012825f, 0.821289f, 0.012253f, 0.809082f, 0.011665f,
+ 0.795898f, 0.011086f, 0.782715f, 0.010506f, 0.769531f, 0.009933f, 0.755859f, 0.009377f,
+ 0.742188f, 0.008842f, 0.728516f, 0.008316f, 0.714355f, 0.007812f, 0.700195f, 0.007336f,
+ 0.685547f, 0.006874f, 0.670898f, 0.006435f, 0.656250f, 0.006020f, 0.641602f, 0.005623f,
+ 0.626465f, 0.005253f, 0.611328f, 0.004902f, 0.596191f, 0.004570f, 0.580566f, 0.004261f,
+ 0.564941f, 0.003967f, 0.549316f, 0.003695f, 0.533691f, 0.003437f, 0.518066f, 0.003199f,
+ 0.502930f, 0.002975f, 0.487305f, 0.002766f, 0.471680f, 0.002571f, 0.456299f, 0.002388f,
+ 0.441162f, 0.002220f, 0.426025f, 0.002062f, 0.411133f, 0.001916f, 0.396240f, 0.001781f,
+ 0.982422f, 0.017502f, 0.982422f, 0.017502f, 0.982422f, 0.017502f, 0.982422f, 0.017517f,
+ 0.981934f, 0.017532f, 0.981934f, 0.017593f, 0.981934f, 0.017639f, 0.981934f, 0.017731f,
+ 0.981445f, 0.017838f, 0.980957f, 0.017960f, 0.979980f, 0.018112f, 0.979004f, 0.018295f,
+ 0.978027f, 0.018478f, 0.975586f, 0.018677f, 0.974609f, 0.018860f, 0.972168f, 0.019073f,
+ 0.969238f, 0.019287f, 0.965820f, 0.019455f, 0.962402f, 0.019562f, 0.958008f, 0.019653f,
+ 0.952637f, 0.019653f, 0.946289f, 0.019623f, 0.939453f, 0.019516f, 0.932617f, 0.019348f,
+ 0.924316f, 0.019089f, 0.916016f, 0.018784f, 0.907227f, 0.018387f, 0.897461f, 0.017944f,
+ 0.887207f, 0.017426f, 0.876465f, 0.016861f, 0.865234f, 0.016266f, 0.854004f, 0.015640f,
+ 0.842285f, 0.014999f, 0.830078f, 0.014320f, 0.818359f, 0.013641f, 0.805664f, 0.012962f,
+ 0.792969f, 0.012291f, 0.780273f, 0.011627f, 0.767090f, 0.010979f, 0.753906f, 0.010345f,
+ 0.740723f, 0.009735f, 0.727539f, 0.009155f, 0.713867f, 0.008591f, 0.699707f, 0.008049f,
+ 0.685547f, 0.007534f, 0.671387f, 0.007050f, 0.656738f, 0.006588f, 0.642578f, 0.006149f,
+ 0.627441f, 0.005737f, 0.612793f, 0.005352f, 0.597656f, 0.004986f, 0.582520f, 0.004642f,
+ 0.567383f, 0.004322f, 0.551758f, 0.004021f, 0.536621f, 0.003744f, 0.520996f, 0.003481f,
+ 0.505859f, 0.003235f, 0.490479f, 0.003006f, 0.475098f, 0.002794f, 0.459717f, 0.002596f,
+ 0.444580f, 0.002411f, 0.429688f, 0.002241f, 0.414795f, 0.002081f, 0.400146f, 0.001933f,
+ 0.979004f, 0.020798f, 0.979004f, 0.020798f, 0.979004f, 0.020798f, 0.979004f, 0.020813f,
+ 0.979004f, 0.020844f, 0.978516f, 0.020874f, 0.978516f, 0.020935f, 0.978027f, 0.021027f,
+ 0.978027f, 0.021149f, 0.977539f, 0.021286f, 0.977051f, 0.021454f, 0.975586f, 0.021622f,
+ 0.974121f, 0.021820f, 0.972656f, 0.021988f, 0.970215f, 0.022186f, 0.968750f, 0.022385f,
+ 0.965820f, 0.022552f, 0.961914f, 0.022675f, 0.958008f, 0.022736f, 0.953613f, 0.022751f,
+ 0.948242f, 0.022736f, 0.942383f, 0.022614f, 0.935547f, 0.022415f, 0.927734f, 0.022156f,
+ 0.919922f, 0.021790f, 0.911621f, 0.021362f, 0.901855f, 0.020859f, 0.892090f, 0.020279f,
+ 0.882324f, 0.019638f, 0.872070f, 0.018951f, 0.860840f, 0.018234f, 0.849609f, 0.017487f,
+ 0.838379f, 0.016708f, 0.826172f, 0.015930f, 0.814453f, 0.015144f, 0.802246f, 0.014359f,
+ 0.790527f, 0.013588f, 0.777832f, 0.012833f, 0.765137f, 0.012100f, 0.752441f, 0.011383f,
+ 0.739258f, 0.010696f, 0.726074f, 0.010040f, 0.712891f, 0.009415f, 0.699219f, 0.008812f,
+ 0.685547f, 0.008240f, 0.671875f, 0.007698f, 0.657715f, 0.007191f, 0.643555f, 0.006710f,
+ 0.628906f, 0.006252f, 0.614258f, 0.005829f, 0.599609f, 0.005428f, 0.584473f, 0.005051f,
+ 0.569336f, 0.004704f, 0.554199f, 0.004372f, 0.539062f, 0.004063f, 0.523926f, 0.003780f,
+ 0.508789f, 0.003513f, 0.493652f, 0.003263f, 0.478271f, 0.003033f, 0.463135f, 0.002817f,
+ 0.448242f, 0.002615f, 0.433350f, 0.002430f, 0.418457f, 0.002256f, 0.403809f, 0.002094f,
+ 0.975098f, 0.024582f, 0.975098f, 0.024567f, 0.975098f, 0.024582f, 0.975098f, 0.024597f,
+ 0.975098f, 0.024628f, 0.975098f, 0.024658f, 0.975098f, 0.024734f, 0.974609f, 0.024826f,
+ 0.973633f, 0.024933f, 0.973633f, 0.025055f, 0.972656f, 0.025223f, 0.972168f, 0.025421f,
+ 0.970215f, 0.025589f, 0.968262f, 0.025742f, 0.966309f, 0.025925f, 0.964355f, 0.026108f,
+ 0.960938f, 0.026230f, 0.957520f, 0.026321f, 0.953613f, 0.026352f, 0.948242f, 0.026260f,
+ 0.943848f, 0.026154f, 0.937500f, 0.025970f, 0.930664f, 0.025650f, 0.922852f, 0.025253f,
+ 0.915039f, 0.024765f, 0.906738f, 0.024200f, 0.897461f, 0.023560f, 0.887207f, 0.022827f,
+ 0.877441f, 0.022064f, 0.866699f, 0.021225f, 0.855957f, 0.020370f, 0.845215f, 0.019470f,
+ 0.833984f, 0.018570f, 0.822266f, 0.017654f, 0.811035f, 0.016754f, 0.799316f, 0.015854f,
+ 0.787109f, 0.014984f, 0.775391f, 0.014122f, 0.763184f, 0.013298f, 0.750488f, 0.012489f,
+ 0.737793f, 0.011726f, 0.725098f, 0.010986f, 0.712402f, 0.010284f, 0.699219f, 0.009621f,
+ 0.685547f, 0.008987f, 0.671875f, 0.008392f, 0.658203f, 0.007828f, 0.644531f, 0.007305f,
+ 0.630371f, 0.006802f, 0.615723f, 0.006336f, 0.601562f, 0.005898f, 0.586914f, 0.005489f,
+ 0.571777f, 0.005104f, 0.557129f, 0.004745f, 0.541992f, 0.004414f, 0.526855f, 0.004101f,
+ 0.511719f, 0.003809f, 0.496826f, 0.003538f, 0.481689f, 0.003286f, 0.466797f, 0.003052f,
+ 0.451904f, 0.002832f, 0.437012f, 0.002630f, 0.422363f, 0.002441f, 0.407715f, 0.002268f,
+ 0.970703f, 0.028870f, 0.970703f, 0.028870f, 0.970703f, 0.028885f, 0.970703f, 0.028900f,
+ 0.970703f, 0.028915f, 0.970703f, 0.028961f, 0.970215f, 0.029022f, 0.970215f, 0.029114f,
+ 0.969727f, 0.029251f, 0.968750f, 0.029373f, 0.968262f, 0.029526f, 0.966797f, 0.029678f,
+ 0.966309f, 0.029877f, 0.964844f, 0.030045f, 0.962402f, 0.030167f, 0.959473f, 0.030304f,
+ 0.956543f, 0.030411f, 0.953125f, 0.030411f, 0.948242f, 0.030319f, 0.943359f, 0.030197f,
+ 0.938477f, 0.029968f, 0.931641f, 0.029648f, 0.924805f, 0.029221f, 0.917969f, 0.028687f,
+ 0.909180f, 0.028030f, 0.900879f, 0.027313f, 0.891602f, 0.026505f, 0.881836f, 0.025620f,
+ 0.871582f, 0.024673f, 0.861816f, 0.023697f, 0.851074f, 0.022659f, 0.840820f, 0.021622f,
+ 0.829590f, 0.020569f, 0.818359f, 0.019516f, 0.807129f, 0.018478f, 0.795898f, 0.017456f,
+ 0.784180f, 0.016464f, 0.772461f, 0.015503f, 0.760742f, 0.014572f, 0.748535f, 0.013672f,
+ 0.736816f, 0.012817f, 0.724121f, 0.012001f, 0.711914f, 0.011215f, 0.698730f, 0.010483f,
+ 0.686035f, 0.009789f, 0.672852f, 0.009132f, 0.659180f, 0.008514f, 0.645508f, 0.007935f,
+ 0.631836f, 0.007389f, 0.617676f, 0.006878f, 0.603516f, 0.006397f, 0.588867f, 0.005951f,
+ 0.574219f, 0.005531f, 0.559570f, 0.005142f, 0.544922f, 0.004776f, 0.529785f, 0.004436f,
+ 0.515137f, 0.004120f, 0.500000f, 0.003828f, 0.485352f, 0.003555f, 0.470215f, 0.003302f,
+ 0.455566f, 0.003065f, 0.440918f, 0.002844f, 0.426270f, 0.002642f, 0.411621f, 0.002451f,
+ 0.965820f, 0.033752f, 0.965820f, 0.033752f, 0.965820f, 0.033752f, 0.965820f, 0.033783f,
+ 0.965820f, 0.033783f, 0.965820f, 0.033875f, 0.965332f, 0.033905f, 0.965332f, 0.033997f,
+ 0.964844f, 0.034088f, 0.963867f, 0.034241f, 0.963379f, 0.034393f, 0.962402f, 0.034546f,
+ 0.960938f, 0.034698f, 0.958496f, 0.034851f, 0.957520f, 0.034973f, 0.954102f, 0.035034f,
+ 0.951172f, 0.035034f, 0.947754f, 0.034943f, 0.942871f, 0.034821f, 0.937988f, 0.034576f,
+ 0.932129f, 0.034180f, 0.926270f, 0.033722f, 0.918945f, 0.033142f, 0.911133f, 0.032410f,
+ 0.902832f, 0.031616f, 0.894531f, 0.030685f, 0.885254f, 0.029694f, 0.876465f, 0.028641f,
+ 0.866699f, 0.027512f, 0.856445f, 0.026337f, 0.846191f, 0.025146f, 0.835449f, 0.023926f,
+ 0.825195f, 0.022720f, 0.814453f, 0.021515f, 0.803711f, 0.020340f, 0.792480f, 0.019165f,
+ 0.781250f, 0.018051f, 0.770020f, 0.016968f, 0.758789f, 0.015915f, 0.747070f, 0.014931f,
+ 0.735352f, 0.013977f, 0.723145f, 0.013069f, 0.710938f, 0.012215f, 0.698730f, 0.011398f,
+ 0.686035f, 0.010635f, 0.673340f, 0.009918f, 0.660156f, 0.009239f, 0.646484f, 0.008598f,
+ 0.633301f, 0.008003f, 0.619141f, 0.007446f, 0.605469f, 0.006927f, 0.591309f, 0.006439f,
+ 0.576660f, 0.005985f, 0.562500f, 0.005562f, 0.547852f, 0.005165f, 0.533203f, 0.004795f,
+ 0.518066f, 0.004456f, 0.503418f, 0.004135f, 0.488770f, 0.003841f, 0.474121f, 0.003565f,
+ 0.459229f, 0.003311f, 0.444580f, 0.003073f, 0.430176f, 0.002853f, 0.415771f, 0.002647f,
+ 0.960449f, 0.039276f, 0.960449f, 0.039276f, 0.960449f, 0.039276f, 0.960449f, 0.039307f,
+ 0.960449f, 0.039337f, 0.959961f, 0.039368f, 0.959961f, 0.039429f, 0.959961f, 0.039520f,
+ 0.959473f, 0.039612f, 0.958984f, 0.039764f, 0.958008f, 0.039886f, 0.956543f, 0.040009f,
+ 0.955566f, 0.040131f, 0.953125f, 0.040253f, 0.951172f, 0.040314f, 0.948242f, 0.040283f,
+ 0.945801f, 0.040222f, 0.940918f, 0.040039f, 0.936523f, 0.039764f, 0.931152f, 0.039368f,
+ 0.926270f, 0.038879f, 0.919434f, 0.038208f, 0.913086f, 0.037445f, 0.905273f, 0.036530f,
+ 0.897461f, 0.035522f, 0.888184f, 0.034393f, 0.879395f, 0.033173f, 0.870117f, 0.031891f,
+ 0.860352f, 0.030563f, 0.850586f, 0.029190f, 0.840820f, 0.027802f, 0.830566f, 0.026398f,
+ 0.820312f, 0.025009f, 0.810059f, 0.023636f, 0.799805f, 0.022308f, 0.789062f, 0.020996f,
+ 0.778809f, 0.019730f, 0.767578f, 0.018524f, 0.756348f, 0.017365f, 0.745605f, 0.016251f,
+ 0.733887f, 0.015213f, 0.722656f, 0.014206f, 0.710938f, 0.013260f, 0.698730f, 0.012367f,
+ 0.686523f, 0.011536f, 0.673828f, 0.010742f, 0.661133f, 0.010002f, 0.647949f, 0.009308f,
+ 0.634766f, 0.008659f, 0.621094f, 0.008057f, 0.607422f, 0.007488f, 0.593262f, 0.006958f,
+ 0.579102f, 0.006466f, 0.564941f, 0.006004f, 0.550781f, 0.005577f, 0.536133f, 0.005177f,
+ 0.521484f, 0.004807f, 0.506836f, 0.004463f, 0.492432f, 0.004143f, 0.477783f, 0.003847f,
+ 0.463135f, 0.003571f, 0.448730f, 0.003315f, 0.434082f, 0.003077f, 0.419922f, 0.002857f,
+ 0.954102f, 0.045502f, 0.954102f, 0.045502f, 0.954102f, 0.045502f, 0.954102f, 0.045532f,
+ 0.954102f, 0.045563f, 0.954102f, 0.045593f, 0.953613f, 0.045654f, 0.953613f, 0.045715f,
+ 0.953125f, 0.045868f, 0.952148f, 0.045990f, 0.951660f, 0.046082f, 0.950195f, 0.046143f,
+ 0.948242f, 0.046265f, 0.946777f, 0.046265f, 0.943848f, 0.046265f, 0.941895f, 0.046204f,
+ 0.938477f, 0.046021f, 0.935059f, 0.045685f, 0.929199f, 0.045258f, 0.925293f, 0.044708f,
+ 0.919434f, 0.044006f, 0.912109f, 0.043121f, 0.905273f, 0.042145f, 0.897949f, 0.041016f,
+ 0.890137f, 0.039734f, 0.881348f, 0.038391f, 0.872559f, 0.036926f, 0.863770f, 0.035431f,
+ 0.854004f, 0.033813f, 0.844727f, 0.032227f, 0.835449f, 0.030640f, 0.825195f, 0.029037f,
+ 0.815430f, 0.027451f, 0.806152f, 0.025909f, 0.795898f, 0.024399f, 0.785645f, 0.022934f,
+ 0.775391f, 0.021530f, 0.765137f, 0.020187f, 0.754883f, 0.018890f, 0.743652f, 0.017670f,
+ 0.732910f, 0.016510f, 0.721680f, 0.015411f, 0.710449f, 0.014374f, 0.698730f, 0.013405f,
+ 0.686523f, 0.012482f, 0.674316f, 0.011620f, 0.662109f, 0.010811f, 0.649414f, 0.010063f,
+ 0.636230f, 0.009354f, 0.623047f, 0.008698f, 0.609375f, 0.008080f, 0.595703f, 0.007507f,
+ 0.582031f, 0.006973f, 0.567871f, 0.006477f, 0.553711f, 0.006016f, 0.539551f, 0.005585f,
+ 0.524902f, 0.005180f, 0.510254f, 0.004810f, 0.496094f, 0.004463f, 0.481689f, 0.004147f,
+ 0.467041f, 0.003847f, 0.452637f, 0.003571f, 0.438232f, 0.003315f, 0.424072f, 0.003077f,
+ 0.947266f, 0.052490f, 0.947266f, 0.052490f, 0.947266f, 0.052490f, 0.947266f, 0.052521f,
+ 0.947266f, 0.052551f, 0.946777f, 0.052582f, 0.946777f, 0.052612f, 0.946289f, 0.052734f,
+ 0.945801f, 0.052795f, 0.945312f, 0.052887f, 0.944336f, 0.052948f, 0.942871f, 0.053040f,
+ 0.941406f, 0.053009f, 0.939941f, 0.053009f, 0.937012f, 0.052917f, 0.934570f, 0.052704f,
+ 0.931641f, 0.052399f, 0.926758f, 0.051971f, 0.922852f, 0.051331f, 0.917480f, 0.050568f,
+ 0.911133f, 0.049622f, 0.904297f, 0.048523f, 0.898438f, 0.047272f, 0.890137f, 0.045868f,
+ 0.882812f, 0.044312f, 0.874512f, 0.042694f, 0.865723f, 0.040955f, 0.856934f, 0.039154f,
+ 0.847656f, 0.037354f, 0.838867f, 0.035522f, 0.829590f, 0.033661f, 0.820312f, 0.031830f,
+ 0.811035f, 0.030060f, 0.801270f, 0.028305f, 0.791992f, 0.026611f, 0.782227f, 0.024994f,
+ 0.772461f, 0.023422f, 0.762695f, 0.021927f, 0.752441f, 0.020508f, 0.742188f, 0.019165f,
+ 0.731445f, 0.017883f, 0.721191f, 0.016678f, 0.709961f, 0.015556f, 0.698730f, 0.014488f,
+ 0.687012f, 0.013489f, 0.675293f, 0.012550f, 0.663086f, 0.011673f, 0.650879f, 0.010849f,
+ 0.638184f, 0.010086f, 0.625000f, 0.009369f, 0.611816f, 0.008705f, 0.598145f, 0.008087f,
+ 0.584961f, 0.007511f, 0.570801f, 0.006977f, 0.556641f, 0.006474f, 0.542480f, 0.006012f,
+ 0.528320f, 0.005581f, 0.514160f, 0.005180f, 0.499756f, 0.004807f, 0.485596f, 0.004459f,
+ 0.471191f, 0.004139f, 0.456787f, 0.003843f, 0.442383f, 0.003569f, 0.428467f, 0.003313f,
+ 0.939453f, 0.060333f, 0.939453f, 0.060333f, 0.939453f, 0.060333f, 0.939453f, 0.060333f,
+ 0.939453f, 0.060394f, 0.938965f, 0.060394f, 0.938965f, 0.060455f, 0.938477f, 0.060516f,
+ 0.937988f, 0.060577f, 0.937500f, 0.060638f, 0.936035f, 0.060669f, 0.935547f, 0.060669f,
+ 0.933594f, 0.060608f, 0.931641f, 0.060516f, 0.929688f, 0.060272f, 0.927246f, 0.059967f,
+ 0.922363f, 0.059448f, 0.918945f, 0.058868f, 0.914062f, 0.057953f, 0.908691f, 0.056946f,
+ 0.902832f, 0.055786f, 0.897461f, 0.054382f, 0.890137f, 0.052826f, 0.882324f, 0.051117f,
+ 0.874023f, 0.049255f, 0.866211f, 0.047302f, 0.858398f, 0.045288f, 0.849609f, 0.043213f,
+ 0.840820f, 0.041107f, 0.832031f, 0.038971f, 0.823730f, 0.036896f, 0.814453f, 0.034821f,
+ 0.806152f, 0.032806f, 0.796875f, 0.030853f, 0.788086f, 0.028961f, 0.778809f, 0.027161f,
+ 0.769531f, 0.025421f, 0.760254f, 0.023788f, 0.750488f, 0.022217f, 0.740723f, 0.020737f,
+ 0.730957f, 0.019333f, 0.720703f, 0.018021f, 0.709961f, 0.016785f, 0.698730f, 0.015625f,
+ 0.687500f, 0.014549f, 0.676270f, 0.013535f, 0.664551f, 0.012573f, 0.652344f, 0.011688f,
+ 0.640137f, 0.010864f, 0.627441f, 0.010086f, 0.614258f, 0.009369f, 0.601074f, 0.008698f,
+ 0.587402f, 0.008080f, 0.573730f, 0.007500f, 0.560059f, 0.006962f, 0.545898f, 0.006462f,
+ 0.531738f, 0.006001f, 0.517578f, 0.005569f, 0.503418f, 0.005165f, 0.489502f, 0.004795f,
+ 0.475098f, 0.004452f, 0.460938f, 0.004131f, 0.446777f, 0.003838f, 0.432861f, 0.003563f,
+ 0.930664f, 0.069031f, 0.930664f, 0.069031f, 0.930664f, 0.069031f, 0.930664f, 0.069031f,
+ 0.930664f, 0.069092f, 0.930664f, 0.069092f, 0.930176f, 0.069214f, 0.929688f, 0.069153f,
+ 0.929199f, 0.069214f, 0.929199f, 0.069275f, 0.927246f, 0.069214f, 0.926758f, 0.069153f,
+ 0.925293f, 0.069031f, 0.923340f, 0.068787f, 0.920410f, 0.068420f, 0.917480f, 0.067932f,
+ 0.914551f, 0.067261f, 0.911133f, 0.066345f, 0.905273f, 0.065247f, 0.900391f, 0.063965f,
+ 0.894043f, 0.062469f, 0.888184f, 0.060699f, 0.880859f, 0.058807f, 0.873535f, 0.056763f,
+ 0.866211f, 0.054565f, 0.858887f, 0.052277f, 0.850586f, 0.049896f, 0.841797f, 0.047485f,
+ 0.833496f, 0.045105f, 0.825684f, 0.042664f, 0.817383f, 0.040283f, 0.809082f, 0.037964f,
+ 0.800781f, 0.035706f, 0.792480f, 0.033539f, 0.784180f, 0.031433f, 0.775391f, 0.029449f,
+ 0.766602f, 0.027542f, 0.757812f, 0.025726f, 0.748535f, 0.024017f, 0.739258f, 0.022400f,
+ 0.729980f, 0.020874f, 0.719727f, 0.019440f, 0.709961f, 0.018097f, 0.699219f, 0.016830f,
+ 0.688477f, 0.015656f, 0.677246f, 0.014557f, 0.665527f, 0.013527f, 0.653809f, 0.012573f,
+ 0.641602f, 0.011681f, 0.629395f, 0.010841f, 0.616699f, 0.010071f, 0.603516f, 0.009346f,
+ 0.590332f, 0.008682f, 0.577148f, 0.008057f, 0.563477f, 0.007481f, 0.549316f, 0.006943f,
+ 0.535645f, 0.006443f, 0.521484f, 0.005978f, 0.507324f, 0.005550f, 0.493408f, 0.005150f,
+ 0.479248f, 0.004780f, 0.465332f, 0.004436f, 0.451172f, 0.004124f, 0.437256f, 0.003828f,
+ 0.920898f, 0.078735f, 0.920898f, 0.078735f, 0.920898f, 0.078735f, 0.920898f, 0.078735f,
+ 0.920898f, 0.078796f, 0.920898f, 0.078796f, 0.920410f, 0.078796f, 0.919922f, 0.078857f,
+ 0.919922f, 0.078857f, 0.918945f, 0.078796f, 0.917480f, 0.078735f, 0.916992f, 0.078613f,
+ 0.915039f, 0.078308f, 0.913086f, 0.077942f, 0.910645f, 0.077454f, 0.908691f, 0.076660f,
+ 0.905273f, 0.075745f, 0.899902f, 0.074585f, 0.895996f, 0.073181f, 0.889648f, 0.071533f,
+ 0.883789f, 0.069641f, 0.877930f, 0.067566f, 0.872070f, 0.065247f, 0.864258f, 0.062805f,
+ 0.856934f, 0.060242f, 0.849121f, 0.057556f, 0.841797f, 0.054810f, 0.833984f, 0.052063f,
+ 0.827148f, 0.049316f, 0.818848f, 0.046570f, 0.811035f, 0.043915f, 0.803223f, 0.041290f,
+ 0.795898f, 0.038788f, 0.788086f, 0.036377f, 0.779785f, 0.034058f, 0.771973f, 0.031830f,
+ 0.763672f, 0.029755f, 0.755371f, 0.027771f, 0.747070f, 0.025894f, 0.738281f, 0.024139f,
+ 0.729004f, 0.022476f, 0.719238f, 0.020935f, 0.709473f, 0.019470f, 0.699707f, 0.018097f,
+ 0.688965f, 0.016830f, 0.678223f, 0.015640f, 0.666992f, 0.014534f, 0.655762f, 0.013496f,
+ 0.643555f, 0.012535f, 0.631348f, 0.011642f, 0.619141f, 0.010803f, 0.606445f, 0.010033f,
+ 0.593262f, 0.009308f, 0.580078f, 0.008644f, 0.566406f, 0.008018f, 0.553223f, 0.007446f,
+ 0.539062f, 0.006908f, 0.525391f, 0.006413f, 0.511230f, 0.005951f, 0.497559f, 0.005527f,
+ 0.483643f, 0.005131f, 0.469482f, 0.004765f, 0.455566f, 0.004421f, 0.441650f, 0.004108f,
+ 0.910156f, 0.089539f, 0.910156f, 0.089539f, 0.910156f, 0.089539f, 0.910156f, 0.089539f,
+ 0.910156f, 0.089539f, 0.909668f, 0.089539f, 0.909668f, 0.089539f, 0.909180f, 0.089539f,
+ 0.908691f, 0.089478f, 0.907715f, 0.089417f, 0.907227f, 0.089233f, 0.905762f, 0.088989f,
+ 0.904297f, 0.088562f, 0.902832f, 0.088013f, 0.900391f, 0.087280f, 0.896973f, 0.086243f,
+ 0.895020f, 0.085083f, 0.889160f, 0.083557f, 0.884766f, 0.081787f, 0.878906f, 0.079712f,
+ 0.874512f, 0.077393f, 0.867676f, 0.074951f, 0.860840f, 0.072205f, 0.854492f, 0.069275f,
+ 0.848145f, 0.066223f, 0.840820f, 0.063171f, 0.833008f, 0.060059f, 0.826172f, 0.056885f,
+ 0.819336f, 0.053741f, 0.812012f, 0.050690f, 0.804688f, 0.047699f, 0.797852f, 0.044800f,
+ 0.790527f, 0.042023f, 0.783691f, 0.039337f, 0.776367f, 0.036804f, 0.768555f, 0.034393f,
+ 0.761230f, 0.032074f, 0.753418f, 0.029922f, 0.745117f, 0.027893f, 0.736816f, 0.025970f,
+ 0.728516f, 0.024170f, 0.719238f, 0.022491f, 0.709961f, 0.020905f, 0.700195f, 0.019440f,
+ 0.689941f, 0.018066f, 0.679688f, 0.016785f, 0.668457f, 0.015587f, 0.657227f, 0.014473f,
+ 0.645996f, 0.013443f, 0.633789f, 0.012474f, 0.621582f, 0.011581f, 0.609375f, 0.010750f,
+ 0.596191f, 0.009972f, 0.583496f, 0.009262f, 0.569824f, 0.008591f, 0.556641f, 0.007973f,
+ 0.542969f, 0.007404f, 0.529297f, 0.006874f, 0.515625f, 0.006378f, 0.501465f, 0.005920f,
+ 0.487793f, 0.005501f, 0.474121f, 0.005108f, 0.460205f, 0.004742f, 0.446289f, 0.004406f,
+ 0.898438f, 0.101440f, 0.898438f, 0.101440f, 0.898438f, 0.101440f, 0.898438f, 0.101440f,
+ 0.897949f, 0.101440f, 0.897949f, 0.101440f, 0.897461f, 0.101440f, 0.896973f, 0.101379f,
+ 0.896973f, 0.101318f, 0.895996f, 0.101135f, 0.895508f, 0.100830f, 0.894043f, 0.100464f,
+ 0.893066f, 0.099854f, 0.890625f, 0.099121f, 0.888184f, 0.098083f, 0.885254f, 0.096802f,
+ 0.882324f, 0.095215f, 0.878418f, 0.093323f, 0.872559f, 0.091125f, 0.869629f, 0.088623f,
+ 0.862793f, 0.085815f, 0.855957f, 0.082764f, 0.850098f, 0.079590f, 0.844727f, 0.076172f,
+ 0.837402f, 0.072693f, 0.831055f, 0.069092f, 0.824219f, 0.065491f, 0.817871f, 0.061981f,
+ 0.811035f, 0.058472f, 0.804688f, 0.055023f, 0.797852f, 0.051697f, 0.791992f, 0.048492f,
+ 0.785645f, 0.045410f, 0.778809f, 0.042480f, 0.771973f, 0.039673f, 0.765625f, 0.037018f,
+ 0.758789f, 0.034515f, 0.750977f, 0.032166f, 0.743652f, 0.029968f, 0.735840f, 0.027878f,
+ 0.727539f, 0.025940f, 0.718750f, 0.024124f, 0.709961f, 0.022430f, 0.700684f, 0.020844f,
+ 0.690918f, 0.019363f, 0.680664f, 0.017975f, 0.670410f, 0.016693f, 0.659180f, 0.015495f,
+ 0.647949f, 0.014389f, 0.636230f, 0.013359f, 0.624512f, 0.012398f, 0.611816f, 0.011505f,
+ 0.599609f, 0.010681f, 0.586426f, 0.009911f, 0.573730f, 0.009201f, 0.560547f, 0.008537f,
+ 0.546875f, 0.007927f, 0.533203f, 0.007355f, 0.519531f, 0.006828f, 0.505859f, 0.006340f,
+ 0.492432f, 0.005890f, 0.478516f, 0.005470f, 0.464844f, 0.005077f, 0.450928f, 0.004719f,
+ 0.885254f, 0.114624f, 0.885254f, 0.114624f, 0.885254f, 0.114624f, 0.885254f, 0.114624f,
+ 0.884766f, 0.114624f, 0.884766f, 0.114563f, 0.884766f, 0.114502f, 0.884277f, 0.114380f,
+ 0.883789f, 0.114258f, 0.883301f, 0.114014f, 0.882324f, 0.113525f, 0.881348f, 0.112976f,
+ 0.879395f, 0.112183f, 0.877441f, 0.111145f, 0.875977f, 0.109802f, 0.872559f, 0.108215f,
+ 0.869141f, 0.106201f, 0.865723f, 0.103821f, 0.860352f, 0.101196f, 0.854492f, 0.098145f,
+ 0.850586f, 0.094849f, 0.845215f, 0.091187f, 0.838379f, 0.087463f, 0.833496f, 0.083496f,
+ 0.826660f, 0.079468f, 0.820801f, 0.075378f, 0.814453f, 0.071289f, 0.809082f, 0.067322f,
+ 0.803711f, 0.063354f, 0.797363f, 0.059540f, 0.791992f, 0.055878f, 0.786133f, 0.052338f,
+ 0.780762f, 0.048950f, 0.774414f, 0.045746f, 0.768555f, 0.042664f, 0.762207f, 0.039795f,
+ 0.755859f, 0.037079f, 0.749023f, 0.034546f, 0.741699f, 0.032135f, 0.734863f, 0.029892f,
+ 0.727051f, 0.027802f, 0.718750f, 0.025833f, 0.710449f, 0.024002f, 0.701172f, 0.022293f,
+ 0.691895f, 0.020706f, 0.682129f, 0.019226f, 0.671875f, 0.017853f, 0.661133f, 0.016571f,
+ 0.650391f, 0.015381f, 0.639160f, 0.014282f, 0.626953f, 0.013252f, 0.615234f, 0.012299f,
+ 0.602539f, 0.011414f, 0.590332f, 0.010597f, 0.577148f, 0.009834f, 0.563965f, 0.009132f,
+ 0.550781f, 0.008476f, 0.537598f, 0.007866f, 0.523926f, 0.007309f, 0.510254f, 0.006786f,
+ 0.496826f, 0.006306f, 0.483154f, 0.005856f, 0.469482f, 0.005440f, 0.455811f, 0.005054f,
+ 0.870605f, 0.129028f, 0.870605f, 0.129028f, 0.870605f, 0.129028f, 0.870605f, 0.129028f,
+ 0.870605f, 0.129028f, 0.870605f, 0.129028f, 0.870117f, 0.128906f, 0.870117f, 0.128784f,
+ 0.869629f, 0.128540f, 0.869141f, 0.128052f, 0.868164f, 0.127563f, 0.867188f, 0.126709f,
+ 0.865723f, 0.125732f, 0.863281f, 0.124329f, 0.862305f, 0.122742f, 0.858887f, 0.120544f,
+ 0.854980f, 0.118103f, 0.850098f, 0.115173f, 0.847168f, 0.111938f, 0.843750f, 0.108276f,
+ 0.836426f, 0.104309f, 0.832031f, 0.100159f, 0.827148f, 0.095764f, 0.821289f, 0.091187f,
+ 0.815918f, 0.086609f, 0.810547f, 0.081970f, 0.806152f, 0.077393f, 0.800781f, 0.072937f,
+ 0.795410f, 0.068542f, 0.790039f, 0.064270f, 0.785645f, 0.060242f, 0.780762f, 0.056335f,
+ 0.775391f, 0.052643f, 0.770020f, 0.049133f, 0.765137f, 0.045807f, 0.759766f, 0.042694f,
+ 0.753906f, 0.039734f, 0.747559f, 0.036987f, 0.740723f, 0.034393f, 0.733887f, 0.031982f,
+ 0.726562f, 0.029739f, 0.719238f, 0.027618f, 0.710449f, 0.025650f, 0.702148f, 0.023834f,
+ 0.692871f, 0.022125f, 0.683594f, 0.020538f, 0.673828f, 0.019058f, 0.663574f, 0.017685f,
+ 0.652832f, 0.016418f, 0.641602f, 0.015244f, 0.629883f, 0.014153f, 0.618164f, 0.013138f,
+ 0.605957f, 0.012192f, 0.593750f, 0.011314f, 0.581055f, 0.010506f, 0.567871f, 0.009750f,
+ 0.555176f, 0.009056f, 0.541504f, 0.008408f, 0.528320f, 0.007809f, 0.514648f, 0.007252f,
+ 0.501465f, 0.006741f, 0.487793f, 0.006260f, 0.474365f, 0.005817f, 0.460938f, 0.005409f,
+ 0.854492f, 0.145020f, 0.854492f, 0.145020f, 0.854492f, 0.145020f, 0.854492f, 0.145020f,
+ 0.854492f, 0.144897f, 0.854492f, 0.144897f, 0.854004f, 0.144653f, 0.854492f, 0.144531f,
+ 0.854004f, 0.144165f, 0.853027f, 0.143555f, 0.852051f, 0.142822f, 0.851074f, 0.141724f,
+ 0.850586f, 0.140503f, 0.848145f, 0.138672f, 0.846191f, 0.136475f, 0.843262f, 0.133911f,
+ 0.839844f, 0.130859f, 0.835449f, 0.127319f, 0.832031f, 0.123474f, 0.828613f, 0.119141f,
+ 0.823242f, 0.114502f, 0.819824f, 0.109558f, 0.813477f, 0.104431f, 0.809570f, 0.099304f,
+ 0.804199f, 0.094055f, 0.799316f, 0.088867f, 0.794922f, 0.083740f, 0.791992f, 0.078735f,
+ 0.786621f, 0.073914f, 0.783203f, 0.069214f, 0.779297f, 0.064758f, 0.774902f, 0.060516f,
+ 0.770508f, 0.056488f, 0.765625f, 0.052673f, 0.761230f, 0.049072f, 0.756348f, 0.045715f,
+ 0.750977f, 0.042511f, 0.745605f, 0.039551f, 0.739746f, 0.036774f, 0.733398f, 0.034180f,
+ 0.726562f, 0.031738f, 0.719238f, 0.029495f, 0.711426f, 0.027390f, 0.703125f, 0.025421f,
+ 0.694336f, 0.023605f, 0.685059f, 0.021912f, 0.675781f, 0.020340f, 0.665527f, 0.018875f,
+ 0.655273f, 0.017517f, 0.644043f, 0.016251f, 0.632812f, 0.015091f, 0.621582f, 0.014008f,
+ 0.609375f, 0.013000f, 0.597168f, 0.012070f, 0.584473f, 0.011200f, 0.571777f, 0.010406f,
+ 0.559082f, 0.009659f, 0.545898f, 0.008972f, 0.532715f, 0.008339f, 0.519531f, 0.007748f,
+ 0.505859f, 0.007198f, 0.492676f, 0.006691f, 0.479248f, 0.006218f, 0.465820f, 0.005783f,
+ 0.837402f, 0.162476f, 0.837402f, 0.162476f, 0.837402f, 0.162476f, 0.837402f, 0.162354f,
+ 0.837402f, 0.162354f, 0.836914f, 0.162231f, 0.836914f, 0.161987f, 0.836426f, 0.161743f,
+ 0.836426f, 0.161133f, 0.835449f, 0.160522f, 0.835449f, 0.159546f, 0.834473f, 0.158203f,
+ 0.833496f, 0.156372f, 0.831055f, 0.154175f, 0.830078f, 0.151489f, 0.826660f, 0.148315f,
+ 0.823242f, 0.144531f, 0.821289f, 0.140381f, 0.817383f, 0.135620f, 0.812012f, 0.130615f,
+ 0.810547f, 0.125122f, 0.805176f, 0.119507f, 0.800293f, 0.113647f, 0.797852f, 0.107788f,
+ 0.792480f, 0.101868f, 0.788574f, 0.096008f, 0.785156f, 0.090332f, 0.782715f, 0.084839f,
+ 0.779297f, 0.079468f, 0.774902f, 0.074341f, 0.772461f, 0.069458f, 0.769531f, 0.064819f,
+ 0.765137f, 0.060486f, 0.761719f, 0.056366f, 0.758301f, 0.052490f, 0.753418f, 0.048828f,
+ 0.749023f, 0.045410f, 0.743652f, 0.042206f, 0.738770f, 0.039215f, 0.732422f, 0.036438f,
+ 0.726074f, 0.033844f, 0.719238f, 0.031433f, 0.711914f, 0.029190f, 0.704102f, 0.027100f,
+ 0.695801f, 0.025146f, 0.687012f, 0.023346f, 0.677734f, 0.021667f, 0.667969f, 0.020111f,
+ 0.657715f, 0.018646f, 0.646973f, 0.017319f, 0.636230f, 0.016068f, 0.624512f, 0.014923f,
+ 0.612793f, 0.013855f, 0.601074f, 0.012863f, 0.588379f, 0.011948f, 0.576172f, 0.011093f,
+ 0.563477f, 0.010300f, 0.550293f, 0.009567f, 0.537109f, 0.008896f, 0.523926f, 0.008263f,
+ 0.510742f, 0.007687f, 0.497559f, 0.007145f, 0.484375f, 0.006645f, 0.470947f, 0.006180f,
+ 0.818359f, 0.181519f, 0.818359f, 0.181519f, 0.818359f, 0.181519f, 0.817871f, 0.181519f,
+ 0.817871f, 0.181396f, 0.817871f, 0.181274f, 0.817871f, 0.181030f, 0.817871f, 0.180542f,
+ 0.817871f, 0.179932f, 0.817383f, 0.178955f, 0.816406f, 0.177612f, 0.815918f, 0.175903f,
+ 0.814941f, 0.173584f, 0.812500f, 0.170898f, 0.811035f, 0.167603f, 0.808594f, 0.163696f,
+ 0.805664f, 0.159180f, 0.802246f, 0.154175f, 0.799805f, 0.148560f, 0.796875f, 0.142700f,
+ 0.792480f, 0.136353f, 0.789551f, 0.129883f, 0.787598f, 0.123230f, 0.782227f, 0.116577f,
+ 0.780273f, 0.109985f, 0.777344f, 0.103516f, 0.774414f, 0.097168f, 0.771973f, 0.091125f,
+ 0.770508f, 0.085205f, 0.767578f, 0.079651f, 0.765625f, 0.074341f, 0.763184f, 0.069336f,
+ 0.760254f, 0.064636f, 0.757812f, 0.060181f, 0.754395f, 0.056000f, 0.750977f, 0.052063f,
+ 0.747559f, 0.048431f, 0.742188f, 0.044983f, 0.737793f, 0.041779f, 0.732422f, 0.038818f,
+ 0.726074f, 0.036041f, 0.719727f, 0.033447f, 0.712891f, 0.031052f, 0.705566f, 0.028824f,
+ 0.697266f, 0.026749f, 0.688965f, 0.024826f, 0.679688f, 0.023041f, 0.670410f, 0.021393f,
+ 0.660645f, 0.019852f, 0.649902f, 0.018433f, 0.639160f, 0.017105f, 0.627930f, 0.015869f,
+ 0.616211f, 0.014748f, 0.604492f, 0.013687f, 0.592773f, 0.012718f, 0.580078f, 0.011818f,
+ 0.567871f, 0.010979f, 0.554688f, 0.010201f, 0.541992f, 0.009483f, 0.528809f, 0.008812f,
+ 0.515625f, 0.008194f, 0.502441f, 0.007626f, 0.489502f, 0.007088f, 0.476318f, 0.006599f,
+ 0.797363f, 0.202393f, 0.797363f, 0.202393f, 0.797363f, 0.202393f, 0.797363f, 0.202393f,
+ 0.797363f, 0.202148f, 0.797363f, 0.202026f, 0.797363f, 0.201660f, 0.797363f, 0.201050f,
+ 0.796875f, 0.200195f, 0.796875f, 0.198975f, 0.796387f, 0.197266f, 0.795898f, 0.195068f,
+ 0.794922f, 0.192261f, 0.792969f, 0.188843f, 0.792480f, 0.184937f, 0.789551f, 0.180298f,
+ 0.787598f, 0.174927f, 0.785645f, 0.168823f, 0.782715f, 0.162231f, 0.779297f, 0.155273f,
+ 0.775879f, 0.148071f, 0.775391f, 0.140747f, 0.772461f, 0.133179f, 0.770508f, 0.125732f,
+ 0.767578f, 0.118347f, 0.766113f, 0.111206f, 0.764648f, 0.104248f, 0.763184f, 0.097595f,
+ 0.762695f, 0.091187f, 0.761719f, 0.085144f, 0.759277f, 0.079407f, 0.758301f, 0.073975f,
+ 0.755859f, 0.068909f, 0.754395f, 0.064087f, 0.751465f, 0.059631f, 0.748535f, 0.055450f,
+ 0.745117f, 0.051514f, 0.741211f, 0.047852f, 0.737305f, 0.044434f, 0.731934f, 0.041260f,
+ 0.726562f, 0.038300f, 0.720215f, 0.035553f, 0.713867f, 0.032990f, 0.706543f, 0.030624f,
+ 0.699219f, 0.028427f, 0.690918f, 0.026382f, 0.682129f, 0.024475f, 0.672852f, 0.022720f,
+ 0.663086f, 0.021088f, 0.652832f, 0.019577f, 0.642578f, 0.018173f, 0.631348f, 0.016876f,
+ 0.620117f, 0.015671f, 0.608398f, 0.014565f, 0.596680f, 0.013535f, 0.584473f, 0.012573f,
+ 0.572266f, 0.011681f, 0.559570f, 0.010857f, 0.546875f, 0.010101f, 0.533691f, 0.009392f,
+ 0.520996f, 0.008736f, 0.507812f, 0.008125f, 0.494629f, 0.007565f, 0.481689f, 0.007042f,
+ 0.774414f, 0.225098f, 0.774414f, 0.225098f, 0.774414f, 0.225098f, 0.774414f, 0.225098f,
+ 0.774414f, 0.224854f, 0.774902f, 0.224609f, 0.774414f, 0.224121f, 0.774414f, 0.223389f,
+ 0.774414f, 0.222290f, 0.773926f, 0.220581f, 0.773926f, 0.218628f, 0.773926f, 0.215942f,
+ 0.773438f, 0.212524f, 0.772461f, 0.208374f, 0.771484f, 0.203491f, 0.770508f, 0.197754f,
+ 0.769043f, 0.191284f, 0.766113f, 0.184204f, 0.763672f, 0.176514f, 0.760742f, 0.168457f,
+ 0.760742f, 0.160278f, 0.757812f, 0.151855f, 0.757812f, 0.143433f, 0.756836f, 0.135132f,
+ 0.754395f, 0.126953f, 0.755371f, 0.119141f, 0.755371f, 0.111511f, 0.754395f, 0.104309f,
+ 0.753418f, 0.097351f, 0.754395f, 0.090820f, 0.753906f, 0.084595f, 0.752441f, 0.078796f,
+ 0.751465f, 0.073303f, 0.750000f, 0.068176f, 0.748535f, 0.063354f, 0.746094f, 0.058899f,
+ 0.743164f, 0.054718f, 0.740234f, 0.050812f, 0.736816f, 0.047150f, 0.731934f, 0.043793f,
+ 0.727051f, 0.040649f, 0.721191f, 0.037720f, 0.714844f, 0.035004f, 0.708008f, 0.032501f,
+ 0.700684f, 0.030167f, 0.692871f, 0.027985f, 0.684570f, 0.025986f, 0.675781f, 0.024124f,
+ 0.666016f, 0.022385f, 0.656250f, 0.020782f, 0.645996f, 0.019302f, 0.635254f, 0.017929f,
+ 0.624023f, 0.016647f, 0.612793f, 0.015480f, 0.601074f, 0.014381f, 0.588867f, 0.013367f,
+ 0.576660f, 0.012428f, 0.563965f, 0.011559f, 0.551270f, 0.010750f, 0.539062f, 0.010002f,
+ 0.525879f, 0.009308f, 0.513184f, 0.008659f, 0.500000f, 0.008064f, 0.487061f, 0.007511f,
+ 0.750000f, 0.249878f, 0.749512f, 0.249878f, 0.750000f, 0.249878f, 0.750000f, 0.249756f,
+ 0.750000f, 0.249512f, 0.750000f, 0.249146f, 0.750000f, 0.248413f, 0.750488f, 0.247559f,
+ 0.750488f, 0.246094f, 0.750488f, 0.244141f, 0.750488f, 0.241577f, 0.750488f, 0.238281f,
+ 0.748535f, 0.234009f, 0.749512f, 0.229004f, 0.749023f, 0.223022f, 0.747070f, 0.216309f,
+ 0.745117f, 0.208496f, 0.743164f, 0.200195f, 0.744629f, 0.191406f, 0.741211f, 0.182251f,
+ 0.741699f, 0.172852f, 0.740234f, 0.163330f, 0.742676f, 0.154053f, 0.741211f, 0.144775f,
+ 0.743652f, 0.135864f, 0.744629f, 0.127197f, 0.743164f, 0.118958f, 0.744629f, 0.111145f,
+ 0.745605f, 0.103638f, 0.746582f, 0.096558f, 0.748047f, 0.089966f, 0.747559f, 0.083679f,
+ 0.747559f, 0.077820f, 0.746582f, 0.072327f, 0.745605f, 0.067261f, 0.744629f, 0.062469f,
+ 0.742676f, 0.058014f, 0.739746f, 0.053864f, 0.735840f, 0.049988f, 0.731934f, 0.046417f,
+ 0.727539f, 0.043091f, 0.722168f, 0.039978f, 0.716309f, 0.037079f, 0.709473f, 0.034424f,
+ 0.702637f, 0.031952f, 0.695312f, 0.029663f, 0.687012f, 0.027542f, 0.678223f, 0.025558f,
+ 0.668945f, 0.023743f, 0.659180f, 0.022049f, 0.649414f, 0.020477f, 0.638672f, 0.019028f,
+ 0.627930f, 0.017670f, 0.616699f, 0.016434f, 0.604980f, 0.015274f, 0.593262f, 0.014198f,
+ 0.581055f, 0.013206f, 0.568848f, 0.012283f, 0.556641f, 0.011429f, 0.543945f, 0.010643f,
+ 0.531250f, 0.009903f, 0.518066f, 0.009224f, 0.505371f, 0.008591f, 0.492676f, 0.008003f,
+ 0.723145f, 0.276611f, 0.723145f, 0.276611f, 0.723145f, 0.276611f, 0.723145f, 0.276611f,
+ 0.723145f, 0.276123f, 0.723145f, 0.275635f, 0.723145f, 0.274902f, 0.723633f, 0.273682f,
+ 0.723633f, 0.271973f, 0.724121f, 0.269531f, 0.724609f, 0.266113f, 0.725098f, 0.262207f,
+ 0.725098f, 0.257080f, 0.724609f, 0.250732f, 0.722656f, 0.243652f, 0.725586f, 0.235474f,
+ 0.724121f, 0.226685f, 0.723145f, 0.216919f, 0.722656f, 0.206787f, 0.720703f, 0.196289f,
+ 0.723145f, 0.185791f, 0.723633f, 0.175171f, 0.724121f, 0.164795f, 0.728027f, 0.154663f,
+ 0.730469f, 0.144897f, 0.731934f, 0.135498f, 0.734863f, 0.126587f, 0.737305f, 0.118103f,
+ 0.739258f, 0.110107f, 0.739746f, 0.102478f, 0.741699f, 0.095398f, 0.743164f, 0.088745f,
+ 0.743652f, 0.082520f, 0.743652f, 0.076660f, 0.743652f, 0.071228f, 0.742676f, 0.066101f,
+ 0.741211f, 0.061401f, 0.739258f, 0.057007f, 0.735840f, 0.052887f, 0.732422f, 0.049103f,
+ 0.728516f, 0.045563f, 0.723145f, 0.042297f, 0.717773f, 0.039246f, 0.711914f, 0.036438f,
+ 0.704590f, 0.033813f, 0.697754f, 0.031403f, 0.689453f, 0.029160f, 0.681152f, 0.027069f,
+ 0.671875f, 0.025146f, 0.662598f, 0.023346f, 0.652832f, 0.021698f, 0.642578f, 0.020157f,
+ 0.631836f, 0.018738f, 0.621094f, 0.017426f, 0.609375f, 0.016205f, 0.597656f, 0.015076f,
+ 0.585938f, 0.014023f, 0.573730f, 0.013054f, 0.561523f, 0.012146f, 0.548828f, 0.011314f,
+ 0.536621f, 0.010536f, 0.523926f, 0.009811f, 0.511230f, 0.009148f, 0.498291f, 0.008530f,
+ 0.693848f, 0.305664f, 0.693848f, 0.305664f, 0.693848f, 0.305664f, 0.693848f, 0.305664f,
+ 0.693848f, 0.305176f, 0.694336f, 0.304443f, 0.694824f, 0.303467f, 0.695312f, 0.302002f,
+ 0.695312f, 0.299561f, 0.696289f, 0.296631f, 0.696777f, 0.292725f, 0.696777f, 0.287598f,
+ 0.697754f, 0.281250f, 0.698242f, 0.273926f, 0.698730f, 0.265137f, 0.697266f, 0.255615f,
+ 0.699707f, 0.245239f, 0.699707f, 0.234131f, 0.700195f, 0.222412f, 0.702637f, 0.210693f,
+ 0.705078f, 0.198853f, 0.708496f, 0.187134f, 0.708984f, 0.175781f, 0.715332f, 0.164673f,
+ 0.718750f, 0.154053f, 0.722168f, 0.143921f, 0.724121f, 0.134277f, 0.727539f, 0.125244f,
+ 0.731934f, 0.116638f, 0.733398f, 0.108582f, 0.736816f, 0.101013f, 0.738281f, 0.093872f,
+ 0.740234f, 0.087219f, 0.741699f, 0.081055f, 0.741211f, 0.075256f, 0.741211f, 0.069885f,
+ 0.740723f, 0.064880f, 0.738281f, 0.060211f, 0.736328f, 0.055908f, 0.732910f, 0.051849f,
+ 0.729004f, 0.048157f, 0.724609f, 0.044678f, 0.719727f, 0.041473f, 0.713379f, 0.038483f,
+ 0.707031f, 0.035736f, 0.699707f, 0.033173f, 0.692383f, 0.030823f, 0.684082f, 0.028625f,
+ 0.675293f, 0.026596f, 0.666016f, 0.024704f, 0.656738f, 0.022964f, 0.646484f, 0.021347f,
+ 0.636230f, 0.019852f, 0.625488f, 0.018463f, 0.614258f, 0.017181f, 0.602539f, 0.015976f,
+ 0.590820f, 0.014877f, 0.578613f, 0.013855f, 0.566895f, 0.012901f, 0.554688f, 0.012024f,
+ 0.541992f, 0.011200f, 0.529297f, 0.010437f, 0.516602f, 0.009735f, 0.503906f, 0.009079f,
+ 0.662598f, 0.337158f, 0.662598f, 0.337158f, 0.662598f, 0.337158f, 0.662598f, 0.336914f,
+ 0.662598f, 0.336670f, 0.663086f, 0.335938f, 0.663086f, 0.334473f, 0.664062f, 0.332520f,
+ 0.665039f, 0.329834f, 0.666016f, 0.325928f, 0.665527f, 0.320801f, 0.667969f, 0.314697f,
+ 0.667480f, 0.306885f, 0.669922f, 0.298096f, 0.669434f, 0.287842f, 0.671387f, 0.276367f,
+ 0.675781f, 0.264404f, 0.675781f, 0.251465f, 0.677734f, 0.238403f, 0.681152f, 0.225342f,
+ 0.686035f, 0.212036f, 0.690430f, 0.199219f, 0.694824f, 0.186768f, 0.700684f, 0.174805f,
+ 0.702637f, 0.163330f, 0.708008f, 0.152466f, 0.714844f, 0.142212f, 0.718750f, 0.132446f,
+ 0.724609f, 0.123291f, 0.728516f, 0.114685f, 0.731445f, 0.106628f, 0.734375f, 0.099121f,
+ 0.736816f, 0.092102f, 0.738770f, 0.085510f, 0.740723f, 0.079407f, 0.740234f, 0.073730f,
+ 0.739258f, 0.068420f, 0.738770f, 0.063538f, 0.736328f, 0.058960f, 0.734375f, 0.054718f,
+ 0.730469f, 0.050781f, 0.726562f, 0.047150f, 0.721191f, 0.043762f, 0.715332f, 0.040619f,
+ 0.709473f, 0.037720f, 0.702637f, 0.035034f, 0.695312f, 0.032532f, 0.687500f, 0.030243f,
+ 0.678711f, 0.028107f, 0.669922f, 0.026123f, 0.660645f, 0.024277f, 0.650391f, 0.022583f,
+ 0.640137f, 0.021011f, 0.629395f, 0.019547f, 0.618652f, 0.018188f, 0.607422f, 0.016937f,
+ 0.595703f, 0.015778f, 0.583984f, 0.014694f, 0.572266f, 0.013695f, 0.560059f, 0.012764f,
+ 0.547852f, 0.011902f, 0.535156f, 0.011101f, 0.522461f, 0.010353f, 0.510254f, 0.009666f,
+ 0.628418f, 0.371338f, 0.628418f, 0.371338f, 0.628418f, 0.371094f, 0.628418f, 0.371094f,
+ 0.628418f, 0.370361f, 0.629395f, 0.369385f, 0.629883f, 0.367920f, 0.630859f, 0.365234f,
+ 0.631836f, 0.361816f, 0.633301f, 0.357178f, 0.634766f, 0.350830f, 0.635742f, 0.343262f,
+ 0.638184f, 0.333984f, 0.640137f, 0.322998f, 0.641113f, 0.311035f, 0.645508f, 0.297852f,
+ 0.647949f, 0.283691f, 0.652344f, 0.269043f, 0.657227f, 0.254395f, 0.662598f, 0.239868f,
+ 0.669922f, 0.225464f, 0.673340f, 0.211426f, 0.680664f, 0.197876f, 0.685547f, 0.184937f,
+ 0.693359f, 0.172729f, 0.700684f, 0.161011f, 0.705566f, 0.150146f, 0.711426f, 0.139771f,
+ 0.718750f, 0.130005f, 0.722168f, 0.120911f, 0.727051f, 0.112427f, 0.732422f, 0.104431f,
+ 0.733887f, 0.097046f, 0.737305f, 0.090088f, 0.738770f, 0.083618f, 0.740234f, 0.077637f,
+ 0.739258f, 0.072083f, 0.738281f, 0.066895f, 0.736816f, 0.062073f, 0.734375f, 0.057648f,
+ 0.731934f, 0.053497f, 0.728027f, 0.049683f, 0.723145f, 0.046112f, 0.717773f, 0.042816f,
+ 0.712402f, 0.039764f, 0.705566f, 0.036957f, 0.698242f, 0.034332f, 0.690430f, 0.031891f,
+ 0.682617f, 0.029663f, 0.673340f, 0.027573f, 0.664551f, 0.025650f, 0.654785f, 0.023865f,
+ 0.644531f, 0.022202f, 0.634277f, 0.020676f, 0.623535f, 0.019257f, 0.612305f, 0.017929f,
+ 0.601074f, 0.016708f, 0.589355f, 0.015579f, 0.577637f, 0.014526f, 0.565430f, 0.013550f,
+ 0.553223f, 0.012642f, 0.541016f, 0.011787f, 0.528809f, 0.011009f, 0.516113f, 0.010277f,
+ 0.591309f, 0.407959f, 0.591797f, 0.407959f, 0.591797f, 0.407959f, 0.591797f, 0.407471f,
+ 0.592285f, 0.406982f, 0.592773f, 0.405762f, 0.593750f, 0.403564f, 0.594727f, 0.400391f,
+ 0.596680f, 0.396240f, 0.598145f, 0.390137f, 0.600098f, 0.382568f, 0.602539f, 0.373047f,
+ 0.604980f, 0.361816f, 0.606934f, 0.348877f, 0.611816f, 0.334473f, 0.616699f, 0.319336f,
+ 0.620605f, 0.302979f, 0.627930f, 0.286865f, 0.634277f, 0.270508f, 0.638672f, 0.254150f,
+ 0.647949f, 0.238525f, 0.654297f, 0.223389f, 0.663086f, 0.208862f, 0.673828f, 0.195068f,
+ 0.680176f, 0.182007f, 0.689941f, 0.169678f, 0.696289f, 0.157959f, 0.705078f, 0.147095f,
+ 0.713867f, 0.136841f, 0.719727f, 0.127197f, 0.724121f, 0.118225f, 0.729980f, 0.109863f,
+ 0.731934f, 0.101990f, 0.735840f, 0.094727f, 0.737305f, 0.087952f, 0.738770f, 0.081604f,
+ 0.740234f, 0.075745f, 0.739258f, 0.070312f, 0.738281f, 0.065247f, 0.735840f, 0.060608f,
+ 0.733398f, 0.056274f, 0.729492f, 0.052246f, 0.725098f, 0.048523f, 0.720703f, 0.045074f,
+ 0.714355f, 0.041870f, 0.708496f, 0.038910f, 0.701660f, 0.036163f, 0.693848f, 0.033630f,
+ 0.686035f, 0.031281f, 0.677734f, 0.029099f, 0.668457f, 0.027069f, 0.659180f, 0.025192f,
+ 0.648926f, 0.023453f, 0.639160f, 0.021851f, 0.628418f, 0.020355f, 0.617676f, 0.018967f,
+ 0.605957f, 0.017685f, 0.594727f, 0.016495f, 0.583008f, 0.015388f, 0.571289f, 0.014366f,
+ 0.559570f, 0.013412f, 0.546875f, 0.012520f, 0.534668f, 0.011696f, 0.522461f, 0.010925f,
+ 0.551758f, 0.447754f, 0.551758f, 0.447754f, 0.552246f, 0.447510f, 0.552246f, 0.447266f,
+ 0.552734f, 0.446289f, 0.553223f, 0.444580f, 0.555176f, 0.441895f, 0.556152f, 0.438232f,
+ 0.558594f, 0.432617f, 0.561035f, 0.425049f, 0.563477f, 0.415527f, 0.566406f, 0.404053f,
+ 0.570312f, 0.390381f, 0.575195f, 0.375000f, 0.578613f, 0.358154f, 0.584473f, 0.340332f,
+ 0.593750f, 0.322266f, 0.600098f, 0.303955f, 0.611328f, 0.286133f, 0.617676f, 0.268555f,
+ 0.629395f, 0.251709f, 0.640625f, 0.235352f, 0.649902f, 0.219849f, 0.661621f, 0.205078f,
+ 0.671387f, 0.191284f, 0.678711f, 0.178223f, 0.688965f, 0.166016f, 0.699707f, 0.154419f,
+ 0.707031f, 0.143555f, 0.714844f, 0.133545f, 0.719727f, 0.124084f, 0.726074f, 0.115295f,
+ 0.731445f, 0.107056f, 0.734863f, 0.099365f, 0.737305f, 0.092285f, 0.739258f, 0.085632f,
+ 0.740234f, 0.079529f, 0.739746f, 0.073792f, 0.739258f, 0.068542f, 0.737793f, 0.063599f,
+ 0.734863f, 0.059082f, 0.731934f, 0.054871f, 0.727539f, 0.050964f, 0.723633f, 0.047394f,
+ 0.717773f, 0.044006f, 0.711426f, 0.040924f, 0.705078f, 0.038055f, 0.697754f, 0.035400f,
+ 0.689941f, 0.032928f, 0.681641f, 0.030655f, 0.672852f, 0.028534f, 0.663574f, 0.026581f,
+ 0.653809f, 0.024750f, 0.644043f, 0.023071f, 0.633301f, 0.021515f, 0.622559f, 0.020050f,
+ 0.611328f, 0.018707f, 0.600098f, 0.017456f, 0.588867f, 0.016296f, 0.577148f, 0.015221f,
+ 0.565430f, 0.014221f, 0.553223f, 0.013290f, 0.541504f, 0.012421f, 0.528809f, 0.011620f,
+ 0.509277f, 0.490234f, 0.509277f, 0.490234f, 0.509277f, 0.489990f, 0.509766f, 0.489502f,
+ 0.510254f, 0.488525f, 0.511230f, 0.486328f, 0.512695f, 0.482910f, 0.514160f, 0.478027f,
+ 0.517578f, 0.470947f, 0.520996f, 0.461670f, 0.523926f, 0.449707f, 0.528809f, 0.435303f,
+ 0.534180f, 0.418945f, 0.540527f, 0.400635f, 0.548340f, 0.381348f, 0.554688f, 0.361328f,
+ 0.566895f, 0.340820f, 0.577637f, 0.320801f, 0.588867f, 0.301270f, 0.601074f, 0.282471f,
+ 0.610352f, 0.264404f, 0.624023f, 0.247070f, 0.637207f, 0.230591f, 0.649414f, 0.215210f,
+ 0.662109f, 0.200562f, 0.672852f, 0.186768f, 0.685547f, 0.173828f, 0.693359f, 0.161743f,
+ 0.702148f, 0.150391f, 0.711426f, 0.139771f, 0.720703f, 0.129883f, 0.726074f, 0.120667f,
+ 0.730469f, 0.112061f, 0.733887f, 0.104065f, 0.738281f, 0.096619f, 0.739258f, 0.089722f,
+ 0.740234f, 0.083252f, 0.741699f, 0.077332f, 0.740723f, 0.071777f, 0.739258f, 0.066711f,
+ 0.736816f, 0.061951f, 0.734375f, 0.057556f, 0.730469f, 0.053497f, 0.726074f, 0.049713f,
+ 0.720703f, 0.046234f, 0.714844f, 0.042999f, 0.708496f, 0.039978f, 0.701172f, 0.037231f,
+ 0.693848f, 0.034637f, 0.685547f, 0.032257f, 0.677246f, 0.030060f, 0.667969f, 0.028000f,
+ 0.658691f, 0.026108f, 0.648926f, 0.024338f, 0.638672f, 0.022705f, 0.627930f, 0.021194f,
+ 0.617188f, 0.019775f, 0.605957f, 0.018463f, 0.594727f, 0.017258f, 0.583008f, 0.016129f,
+ 0.571289f, 0.015076f, 0.559570f, 0.014099f, 0.547852f, 0.013191f, 0.535645f, 0.012337f,
+ 0.463623f, 0.536133f, 0.463623f, 0.536133f, 0.463867f, 0.535645f, 0.464111f, 0.535156f,
+ 0.465088f, 0.533691f, 0.466064f, 0.530762f, 0.468506f, 0.526367f, 0.471191f, 0.520020f,
+ 0.474609f, 0.511230f, 0.478516f, 0.499268f, 0.483643f, 0.484375f, 0.489990f, 0.466797f,
+ 0.495361f, 0.447266f, 0.502441f, 0.425537f, 0.515137f, 0.403564f, 0.526855f, 0.380859f,
+ 0.540039f, 0.358887f, 0.553711f, 0.336914f, 0.564453f, 0.315918f, 0.587891f, 0.295898f,
+ 0.600098f, 0.276611f, 0.610840f, 0.258545f, 0.624512f, 0.241211f, 0.641113f, 0.225098f,
+ 0.657715f, 0.209717f, 0.668457f, 0.195312f, 0.678223f, 0.181763f, 0.687988f, 0.169067f,
+ 0.701172f, 0.157104f, 0.707031f, 0.146118f, 0.715332f, 0.135620f, 0.723145f, 0.125977f,
+ 0.728516f, 0.117126f, 0.734375f, 0.108704f, 0.736328f, 0.100952f, 0.739746f, 0.093750f,
+ 0.741699f, 0.087036f, 0.742188f, 0.080872f, 0.741699f, 0.075134f, 0.741211f, 0.069763f,
+ 0.739258f, 0.064819f, 0.736816f, 0.060272f, 0.733398f, 0.056030f, 0.729004f, 0.052124f,
+ 0.724121f, 0.048492f, 0.718750f, 0.045105f, 0.712402f, 0.041992f, 0.705078f, 0.039093f,
+ 0.698242f, 0.036407f, 0.689941f, 0.033905f, 0.681641f, 0.031616f, 0.672852f, 0.029480f,
+ 0.663574f, 0.027512f, 0.653809f, 0.025665f, 0.644043f, 0.023956f, 0.633301f, 0.022369f,
+ 0.622559f, 0.020889f, 0.611816f, 0.019516f, 0.601074f, 0.018250f, 0.589355f, 0.017059f,
+ 0.578125f, 0.015961f, 0.565918f, 0.014946f, 0.554199f, 0.013992f, 0.542480f, 0.013107f,
+ 0.414551f, 0.584961f, 0.414551f, 0.584961f, 0.414795f, 0.584961f, 0.415039f, 0.583984f,
+ 0.416260f, 0.582031f, 0.418457f, 0.578613f, 0.420166f, 0.572754f, 0.424072f, 0.563965f,
+ 0.428467f, 0.552246f, 0.433838f, 0.537109f, 0.441162f, 0.518066f, 0.448730f, 0.497070f,
+ 0.458984f, 0.473633f, 0.467773f, 0.449219f, 0.480713f, 0.424072f, 0.497559f, 0.399414f,
+ 0.511719f, 0.375244f, 0.529297f, 0.352051f, 0.543945f, 0.329834f, 0.566895f, 0.308838f,
+ 0.581543f, 0.288574f, 0.598633f, 0.269531f, 0.619629f, 0.251465f, 0.635742f, 0.234497f,
+ 0.646973f, 0.218506f, 0.659668f, 0.203369f, 0.674805f, 0.189331f, 0.684570f, 0.176025f,
+ 0.695801f, 0.163696f, 0.707031f, 0.152222f, 0.718750f, 0.141357f, 0.723145f, 0.131348f,
+ 0.729004f, 0.122009f, 0.734375f, 0.113342f, 0.738281f, 0.105286f, 0.741211f, 0.097778f,
+ 0.743164f, 0.090820f, 0.744629f, 0.084412f, 0.744629f, 0.078430f, 0.743652f, 0.072876f,
+ 0.742676f, 0.067749f, 0.739746f, 0.062988f, 0.735840f, 0.058624f, 0.731934f, 0.054535f,
+ 0.727539f, 0.050751f, 0.721680f, 0.047241f, 0.715820f, 0.044006f, 0.709473f, 0.040985f,
+ 0.702148f, 0.038208f, 0.694824f, 0.035614f, 0.686523f, 0.033234f, 0.677734f, 0.031006f,
+ 0.668457f, 0.028946f, 0.659180f, 0.027023f, 0.649414f, 0.025238f, 0.639160f, 0.023590f,
+ 0.628906f, 0.022049f, 0.618164f, 0.020630f, 0.606934f, 0.019287f, 0.595703f, 0.018051f,
+ 0.584473f, 0.016907f, 0.572754f, 0.015839f, 0.561035f, 0.014839f, 0.549316f, 0.013908f,
+ 0.361816f, 0.637695f, 0.361816f, 0.637695f, 0.362061f, 0.637207f, 0.362793f, 0.636230f,
+ 0.364258f, 0.633301f, 0.366455f, 0.628906f, 0.369873f, 0.621094f, 0.374512f, 0.609375f,
+ 0.378906f, 0.593750f, 0.387451f, 0.573730f, 0.396484f, 0.550293f, 0.407471f, 0.524414f,
+ 0.419189f, 0.497314f, 0.433594f, 0.469971f, 0.453613f, 0.442627f, 0.473633f, 0.416016f,
+ 0.488037f, 0.390381f, 0.509277f, 0.365967f, 0.528809f, 0.343262f, 0.549805f, 0.320801f,
+ 0.574707f, 0.299805f, 0.590332f, 0.280029f, 0.609375f, 0.261475f, 0.631836f, 0.243774f,
+ 0.641602f, 0.227173f, 0.659668f, 0.211426f, 0.671387f, 0.196777f, 0.685059f, 0.183105f,
+ 0.698730f, 0.170166f, 0.705078f, 0.158203f, 0.715820f, 0.146973f, 0.723145f, 0.136597f,
+ 0.730469f, 0.126831f, 0.737793f, 0.117920f, 0.740723f, 0.109558f, 0.741699f, 0.101807f,
+ 0.745117f, 0.094604f, 0.747559f, 0.087891f, 0.747070f, 0.081726f, 0.747070f, 0.075989f,
+ 0.744141f, 0.070679f, 0.742676f, 0.065796f, 0.739258f, 0.061218f, 0.735840f, 0.056976f,
+ 0.730957f, 0.053070f, 0.725586f, 0.049438f, 0.719727f, 0.046082f, 0.713867f, 0.042938f,
+ 0.706543f, 0.040070f, 0.699219f, 0.037384f, 0.690918f, 0.034882f, 0.682617f, 0.032562f,
+ 0.673828f, 0.030426f, 0.664551f, 0.028442f, 0.654785f, 0.026581f, 0.645020f, 0.024857f,
+ 0.634766f, 0.023254f, 0.624023f, 0.021774f, 0.613281f, 0.020386f, 0.602051f, 0.019089f,
+ 0.590820f, 0.017899f, 0.579590f, 0.016769f, 0.567871f, 0.015732f, 0.556641f, 0.014755f,
+ 0.305420f, 0.694336f, 0.305420f, 0.694336f, 0.305664f, 0.693848f, 0.306641f, 0.691895f,
+ 0.308105f, 0.687988f, 0.311279f, 0.681152f, 0.316162f, 0.669922f, 0.321777f, 0.654297f,
+ 0.330078f, 0.632812f, 0.344238f, 0.606934f, 0.353027f, 0.578125f, 0.367432f, 0.547852f,
+ 0.385498f, 0.517578f, 0.405273f, 0.487793f, 0.422852f, 0.458496f, 0.448730f, 0.431152f,
+ 0.473633f, 0.404541f, 0.493896f, 0.379639f, 0.519531f, 0.355469f, 0.539551f, 0.332520f,
+ 0.563477f, 0.310791f, 0.583008f, 0.290283f, 0.604004f, 0.270752f, 0.626953f, 0.252686f,
+ 0.642090f, 0.235352f, 0.657715f, 0.218994f, 0.672852f, 0.203857f, 0.686523f, 0.189575f,
+ 0.699219f, 0.176270f, 0.707031f, 0.163818f, 0.717285f, 0.152344f, 0.723633f, 0.141602f,
+ 0.730469f, 0.131592f, 0.739258f, 0.122375f, 0.741699f, 0.113708f, 0.745605f, 0.105713f,
+ 0.747559f, 0.098267f, 0.748047f, 0.091370f, 0.749023f, 0.085022f, 0.748535f, 0.079102f,
+ 0.747070f, 0.073608f, 0.746582f, 0.068542f, 0.742188f, 0.063843f, 0.739258f, 0.059448f,
+ 0.734375f, 0.055420f, 0.730469f, 0.051666f, 0.724609f, 0.048187f, 0.717773f, 0.044952f,
+ 0.710938f, 0.041962f, 0.704102f, 0.039154f, 0.695801f, 0.036591f, 0.687988f, 0.034180f,
+ 0.679199f, 0.031952f, 0.670410f, 0.029892f, 0.660645f, 0.027969f, 0.650879f, 0.026184f,
+ 0.640625f, 0.024521f, 0.630371f, 0.022964f, 0.619629f, 0.021515f, 0.608887f, 0.020172f,
+ 0.598145f, 0.018921f, 0.586914f, 0.017761f, 0.575195f, 0.016663f, 0.563965f, 0.015656f,
+ 0.244995f, 0.754395f, 0.245117f, 0.754395f, 0.245483f, 0.753418f, 0.246704f, 0.750977f,
+ 0.249634f, 0.745117f, 0.253662f, 0.734863f, 0.260010f, 0.717773f, 0.268555f, 0.694336f,
+ 0.277344f, 0.665527f, 0.292480f, 0.632812f, 0.309814f, 0.599121f, 0.331787f, 0.565918f,
+ 0.352539f, 0.533203f, 0.376465f, 0.501953f, 0.405518f, 0.472412f, 0.433838f, 0.444336f,
+ 0.456787f, 0.417236f, 0.488281f, 0.391357f, 0.510254f, 0.366211f, 0.540039f, 0.343018f,
+ 0.564941f, 0.320557f, 0.579590f, 0.299561f, 0.606445f, 0.279541f, 0.627441f, 0.260498f,
+ 0.638184f, 0.242676f, 0.666504f, 0.226074f, 0.670898f, 0.210327f, 0.687988f, 0.195801f,
+ 0.700684f, 0.182129f, 0.706055f, 0.169312f, 0.718262f, 0.157471f, 0.727539f, 0.146362f,
+ 0.735840f, 0.136108f, 0.738770f, 0.126587f, 0.743164f, 0.117737f, 0.746582f, 0.109497f,
+ 0.751953f, 0.101868f, 0.751953f, 0.094788f, 0.753906f, 0.088257f, 0.752930f, 0.082153f,
+ 0.750977f, 0.076538f, 0.749512f, 0.071289f, 0.745605f, 0.066406f, 0.742188f, 0.061951f,
+ 0.738281f, 0.057770f, 0.734375f, 0.053894f, 0.729004f, 0.050293f, 0.722656f, 0.046967f,
+ 0.715332f, 0.043854f, 0.708496f, 0.040985f, 0.701172f, 0.038330f, 0.693359f, 0.035828f,
+ 0.684570f, 0.033539f, 0.676270f, 0.031403f, 0.666992f, 0.029404f, 0.657227f, 0.027542f,
+ 0.646973f, 0.025818f, 0.636719f, 0.024200f, 0.626465f, 0.022705f, 0.615723f, 0.021301f,
+ 0.604980f, 0.020004f, 0.593750f, 0.018784f, 0.582520f, 0.017654f, 0.571289f, 0.016586f,
+ 0.180542f, 0.818848f, 0.180664f, 0.818848f, 0.181274f, 0.817383f, 0.183350f, 0.812988f,
+ 0.187134f, 0.802734f, 0.193237f, 0.784180f, 0.201416f, 0.757324f, 0.214355f, 0.723145f,
+ 0.231445f, 0.685547f, 0.248901f, 0.648438f, 0.272217f, 0.611816f, 0.302979f, 0.577148f,
+ 0.329834f, 0.544922f, 0.364258f, 0.514160f, 0.394043f, 0.484619f, 0.425781f, 0.456055f,
+ 0.456543f, 0.428467f, 0.481934f, 0.402344f, 0.512207f, 0.376709f, 0.540039f, 0.352783f,
+ 0.566406f, 0.329346f, 0.579102f, 0.307617f, 0.607910f, 0.286865f, 0.627930f, 0.267822f,
+ 0.645996f, 0.249512f, 0.661621f, 0.232178f, 0.677734f, 0.216309f, 0.691406f, 0.201172f,
+ 0.702637f, 0.187256f, 0.711426f, 0.174194f, 0.721680f, 0.161987f, 0.730957f, 0.150879f,
+ 0.736328f, 0.140259f, 0.742188f, 0.130493f, 0.746582f, 0.121582f, 0.750488f, 0.113159f,
+ 0.751953f, 0.105347f, 0.752930f, 0.098083f, 0.756836f, 0.091370f, 0.755859f, 0.085144f,
+ 0.755371f, 0.079346f, 0.752441f, 0.073975f, 0.750488f, 0.069031f, 0.746582f, 0.064392f,
+ 0.743652f, 0.060120f, 0.737793f, 0.056152f, 0.733398f, 0.052460f, 0.727051f, 0.049011f,
+ 0.720215f, 0.045837f, 0.713867f, 0.042847f, 0.706543f, 0.040100f, 0.699219f, 0.037537f,
+ 0.690430f, 0.035156f, 0.682129f, 0.032928f, 0.672852f, 0.030884f, 0.663086f, 0.028961f,
+ 0.653809f, 0.027161f, 0.644043f, 0.025497f, 0.633301f, 0.023941f, 0.622559f, 0.022491f,
+ 0.612305f, 0.021133f, 0.601074f, 0.019867f, 0.590332f, 0.018692f, 0.579102f, 0.017578f,
+ 0.111816f, 0.888184f, 0.112000f, 0.887207f, 0.112976f, 0.883789f, 0.115845f, 0.873047f,
+ 0.122864f, 0.849609f, 0.133301f, 0.813477f, 0.147217f, 0.770996f, 0.167236f, 0.728027f,
+ 0.196411f, 0.688965f, 0.222290f, 0.653320f, 0.258057f, 0.619629f, 0.293457f, 0.587402f,
+ 0.328613f, 0.556152f, 0.361328f, 0.524902f, 0.392578f, 0.495850f, 0.430420f, 0.466064f,
+ 0.459961f, 0.437744f, 0.482422f, 0.410889f, 0.511230f, 0.385010f, 0.536621f, 0.359863f,
+ 0.568848f, 0.336182f, 0.592773f, 0.313721f, 0.614258f, 0.293213f, 0.626953f, 0.273193f,
+ 0.646484f, 0.254639f, 0.657227f, 0.237427f, 0.683105f, 0.221191f, 0.693359f, 0.205933f,
+ 0.698242f, 0.191772f, 0.709473f, 0.178589f, 0.724609f, 0.166260f, 0.733398f, 0.154907f,
+ 0.739746f, 0.144165f, 0.745605f, 0.134399f, 0.750977f, 0.125122f, 0.753906f, 0.116577f,
+ 0.754883f, 0.108704f, 0.758301f, 0.101257f, 0.759766f, 0.094482f, 0.757812f, 0.088074f,
+ 0.759766f, 0.082092f, 0.758301f, 0.076660f, 0.756348f, 0.071594f, 0.752441f, 0.066833f,
+ 0.748047f, 0.062469f, 0.741699f, 0.058380f, 0.736816f, 0.054596f, 0.732910f, 0.051086f,
+ 0.726074f, 0.047791f, 0.719727f, 0.044769f, 0.711914f, 0.041901f, 0.704590f, 0.039276f,
+ 0.696289f, 0.036804f, 0.688477f, 0.034546f, 0.678711f, 0.032410f, 0.669922f, 0.030411f,
+ 0.660156f, 0.028564f, 0.650391f, 0.026840f, 0.640625f, 0.025223f, 0.630371f, 0.023727f,
+ 0.619629f, 0.022324f, 0.608887f, 0.020996f, 0.597656f, 0.019775f, 0.586914f, 0.018631f,
+ 0.038452f, 0.960938f, 0.039124f, 0.957520f, 0.042480f, 0.933594f, 0.051575f, 0.879395f,
+ 0.069275f, 0.824219f, 0.091064f, 0.785156f, 0.126343f, 0.753906f, 0.154419f, 0.725586f,
+ 0.192139f, 0.695312f, 0.234375f, 0.663086f, 0.273438f, 0.630371f, 0.305908f, 0.597656f,
+ 0.338379f, 0.565430f, 0.379150f, 0.532227f, 0.413818f, 0.501465f, 0.444336f, 0.471191f,
+ 0.471436f, 0.442383f, 0.504395f, 0.414795f, 0.531250f, 0.388672f, 0.547363f, 0.364014f,
+ 0.579590f, 0.340088f, 0.603516f, 0.317627f, 0.622559f, 0.297119f, 0.635742f, 0.276855f,
+ 0.669434f, 0.258301f, 0.670410f, 0.241089f, 0.685547f, 0.224854f, 0.699219f, 0.209717f,
+ 0.712402f, 0.195190f, 0.720703f, 0.182373f, 0.729980f, 0.169678f, 0.746582f, 0.158325f,
+ 0.744629f, 0.147705f, 0.748535f, 0.137695f, 0.760254f, 0.128296f, 0.757812f, 0.119629f,
+ 0.761230f, 0.111755f, 0.762207f, 0.104248f, 0.764160f, 0.097290f, 0.763184f, 0.090881f,
+ 0.762207f, 0.084900f, 0.760742f, 0.079285f, 0.759766f, 0.074097f, 0.755859f, 0.069275f,
+ 0.752930f, 0.064758f, 0.747559f, 0.060669f, 0.742676f, 0.056793f, 0.737305f, 0.053131f,
+ 0.731445f, 0.049774f, 0.725586f, 0.046661f, 0.718262f, 0.043732f, 0.710449f, 0.041077f,
+ 0.702637f, 0.038544f, 0.694336f, 0.036163f, 0.685547f, 0.033966f, 0.676758f, 0.031921f,
+ 0.667480f, 0.030014f, 0.657715f, 0.028229f, 0.647461f, 0.026566f, 0.637207f, 0.025009f,
+ 0.626953f, 0.023544f, 0.616699f, 0.022186f, 0.605957f, 0.020920f, 0.594727f, 0.019730f
+};
+
+static float ltc_disk_integral[64 * 64] = {
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.015873f, 0.047619f, 0.079365f, 0.111111f, 0.142857f, 0.174603f, 0.206349f, 0.238095f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000148f, 0.002454f, 0.008675f, 0.019560f,
+ 0.035433f, 0.056294f, 0.081819f, 0.111259f, 0.142857f, 0.174603f, 0.206349f, 0.238095f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000002f, 0.000761f, 0.003673f, 0.009403f, 0.018333f, 0.030683f,
+ 0.046556f, 0.065952f, 0.088768f, 0.114784f, 0.143618f, 0.174606f, 0.206349f, 0.238095f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000039f, 0.000969f, 0.003703f, 0.008684f, 0.016189f, 0.026395f, 0.039409f,
+ 0.055282f, 0.074014f, 0.095554f, 0.119795f, 0.146560f, 0.175573f, 0.206388f, 0.238095f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000047f, 0.000895f, 0.003265f, 0.007514f, 0.013873f, 0.022495f, 0.033483f, 0.046897f,
+ 0.062770f, 0.081102f, 0.101860f, 0.124985f, 0.150372f, 0.177868f, 0.207245f, 0.238143f,
+ 0.269841f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000028f,
+ 0.000695f, 0.002655f, 0.006230f, 0.011623f, 0.018976f, 0.028384f, 0.039915f, 0.053606f,
+ 0.069479f, 0.087534f, 0.107749f, 0.130087f, 0.154481f, 0.180833f, 0.209005f, 0.238791f,
+ 0.269869f, 0.301587f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000007f, 0.000465f,
+ 0.002017f, 0.004975f, 0.009533f, 0.015821f, 0.023934f, 0.033937f, 0.045874f, 0.059772f,
+ 0.075645f, 0.093493f, 0.113302f, 0.135045f, 0.158678f, 0.184136f, 0.211325f, 0.240113f,
+ 0.270306f, 0.301594f, 0.333333f, 0.365079f, 0.396825f, 0.428571f, 0.460317f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000260f, 0.001426f,
+ 0.003823f, 0.007642f, 0.013012f, 0.020025f, 0.028745f, 0.039218f, 0.051475f, 0.065535f,
+ 0.081408f, 0.099094f, 0.118583f, 0.139856f, 0.162882f, 0.187615f, 0.213991f, 0.241918f,
+ 0.271267f, 0.301847f, 0.333333f, 0.365079f, 0.396826f, 0.428572f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000109f, 0.000921f, 0.002807f,
+ 0.005966f, 0.010528f, 0.016585f, 0.024200f, 0.033420f, 0.044278f, 0.056796f, 0.070988f,
+ 0.086861f, 0.104415f, 0.123643f, 0.144531f, 0.167057f, 0.191188f, 0.216878f, 0.244062f,
+ 0.272649f, 0.302509f, 0.333442f, 0.365079f, 0.396826f, 0.428572f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000024f, 0.000524f, 0.001947f, 0.004511f,
+ 0.008351f, 0.013561f, 0.020206f, 0.028332f, 0.037974f, 0.049155f, 0.061892f, 0.076194f,
+ 0.092067f, 0.109511f, 0.128520f, 0.149085f, 0.171189f, 0.194809f, 0.219910f, 0.246447f,
+ 0.274352f, 0.303535f, 0.333857f, 0.365104f, 0.396826f, 0.428572f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000242f, 0.001250f, 0.003275f, 0.006463f,
+ 0.010913f, 0.016693f, 0.023849f, 0.032418f, 0.042423f, 0.053881f, 0.066805f, 0.081201f,
+ 0.097074f, 0.114424f, 0.133246f, 0.153534f, 0.175275f, 0.198453f, 0.223042f, 0.249009f,
+ 0.276304f, 0.304862f, 0.334584f, 0.365322f, 0.396826f, 0.428571f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000074f, 0.000716f, 0.002252f, 0.004848f, 0.008610f,
+ 0.013608f, 0.019894f, 0.027502f, 0.036458f, 0.046780f, 0.058480f, 0.071567f, 0.086045f,
+ 0.101918f, 0.119186f, 0.137845f, 0.157891f, 0.179316f, 0.202106f, 0.226243f, 0.251704f,
+ 0.278451f, 0.306436f, 0.335586f, 0.365796f, 0.396900f, 0.428571f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000006f, 0.000342f, 0.001437f, 0.003492f, 0.006624f, 0.010911f,
+ 0.016406f, 0.023146f, 0.031157f, 0.040457f, 0.051059f, 0.062972f, 0.076203f, 0.090753f,
+ 0.106626f, 0.123822f, 0.142337f, 0.162170f, 0.183314f, 0.205760f, 0.229496f, 0.254502f,
+ 0.280753f, 0.308212f, 0.336825f, 0.366517f, 0.397167f, 0.428578f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000114f, 0.000820f, 0.002381f, 0.004935f, 0.008569f, 0.013339f,
+ 0.019286f, 0.026437f, 0.034810f, 0.044418f, 0.055271f, 0.067375f, 0.080733f, 0.095348f,
+ 0.111221f, 0.128352f, 0.146740f, 0.166382f, 0.187276f, 0.209413f, 0.232786f, 0.257382f,
+ 0.283181f, 0.310156f, 0.338269f, 0.367461f, 0.397646f, 0.428685f, 0.460318f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000014f, 0.000390f, 0.001503f, 0.003525f, 0.006554f, 0.010655f, 0.015872f,
+ 0.022233f, 0.029758f, 0.038460f, 0.048347f, 0.059427f, 0.071702f, 0.085175f, 0.099848f,
+ 0.115721f, 0.132794f, 0.151067f, 0.170538f, 0.191204f, 0.213063f, 0.236107f, 0.260329f,
+ 0.285714f, 0.312243f, 0.339887f, 0.368604f, 0.398329f, 0.428961f, 0.460331f, 0.492064f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000130f, 0.000845f, 0.002376f, 0.004845f, 0.008325f, 0.012864f, 0.018495f,
+ 0.025237f, 0.033105f, 0.042107f, 0.052249f, 0.063534f, 0.075965f, 0.089543f, 0.104269f,
+ 0.120142f, 0.137163f, 0.155330f, 0.174645f, 0.195106f, 0.216710f, 0.239454f, 0.263332f,
+ 0.288336f, 0.314451f, 0.341658f, 0.369924f, 0.399202f, 0.429416f, 0.460447f, 0.492064f,
+ 0.523809f, 0.555555f, 0.587301f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000016f, 0.000391f, 0.001475f, 0.003423f, 0.006322f, 0.010230f, 0.015179f, 0.021195f,
+ 0.028290f, 0.036474f, 0.045752f, 0.056128f, 0.067602f, 0.080176f, 0.093850f, 0.108623f,
+ 0.124496f, 0.141469f, 0.159541f, 0.178713f, 0.198985f, 0.220355f, 0.242823f, 0.266385f,
+ 0.291036f, 0.316767f, 0.343563f, 0.371402f, 0.400248f, 0.430047f, 0.460709f, 0.492079f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000123f, 0.000807f, 0.002272f, 0.004628f, 0.007942f, 0.012253f, 0.017589f, 0.023963f,
+ 0.031387f, 0.039864f, 0.049398f, 0.059990f, 0.071638f, 0.084344f, 0.098106f, 0.112923f,
+ 0.128796f, 0.145725f, 0.163709f, 0.182749f, 0.202847f, 0.224001f, 0.246214f, 0.269482f,
+ 0.293805f, 0.319176f, 0.345587f, 0.373021f, 0.401454f, 0.430844f, 0.461125f, 0.492187f,
+ 0.523810f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000012f,
+ 0.000356f, 0.001378f, 0.003225f, 0.005979f, 0.009689f, 0.014384f, 0.020083f, 0.026795f,
+ 0.034525f, 0.043276f, 0.053047f, 0.063839f, 0.075649f, 0.088476f, 0.102320f, 0.117178f,
+ 0.133051f, 0.149939f, 0.167841f, 0.186760f, 0.206696f, 0.227650f, 0.249625f, 0.272620f,
+ 0.296636f, 0.321671f, 0.347718f, 0.374768f, 0.402804f, 0.431796f, 0.461695f, 0.492420f,
+ 0.523822f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000100f,
+ 0.000725f, 0.002097f, 0.004323f, 0.007463f, 0.011553f, 0.016613f, 0.022655f, 0.029684f,
+ 0.037702f, 0.046708f, 0.056701f, 0.067680f, 0.079640f, 0.092581f, 0.106501f, 0.121397f,
+ 0.137270f, 0.154120f, 0.171946f, 0.190751f, 0.210537f, 0.231305f, 0.253057f, 0.275797f,
+ 0.299525f, 0.324242f, 0.349947f, 0.376633f, 0.404289f, 0.432895f, 0.462415f, 0.492788f,
+ 0.523909f, 0.555556f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000005f, 0.000296f,
+ 0.001231f, 0.002960f, 0.005558f, 0.009072f, 0.013526f, 0.018933f, 0.025299f, 0.032627f,
+ 0.040916f, 0.050162f, 0.060364f, 0.071517f, 0.083619f, 0.096666f, 0.110656f, 0.125588f,
+ 0.141461f, 0.158275f, 0.176031f, 0.194730f, 0.214374f, 0.234967f, 0.256512f, 0.279011f,
+ 0.302468f, 0.326887f, 0.352266f, 0.378605f, 0.405897f, 0.434130f, 0.463277f, 0.493295f,
+ 0.524106f, 0.555561f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000068f, 0.000613f,
+ 0.001874f, 0.003958f, 0.006921f, 0.010796f, 0.015599f, 0.021336f, 0.028011f, 0.035623f,
+ 0.044167f, 0.053640f, 0.064038f, 0.075355f, 0.087589f, 0.100736f, 0.114793f, 0.129759f,
+ 0.145632f, 0.162412f, 0.180101f, 0.198700f, 0.218213f, 0.238641f, 0.259989f, 0.282262f,
+ 0.305464f, 0.329599f, 0.354670f, 0.380678f, 0.407622f, 0.435493f, 0.464275f, 0.493938f,
+ 0.524422f, 0.555624f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000223f, 0.001054f,
+ 0.002649f, 0.005086f, 0.008406f, 0.012629f, 0.017766f, 0.023820f, 0.030789f, 0.038669f,
+ 0.047455f, 0.057143f, 0.067726f, 0.079199f, 0.091558f, 0.104798f, 0.118918f, 0.133915f,
+ 0.149788f, 0.166537f, 0.184164f, 0.202669f, 0.222056f, 0.242329f, 0.263492f, 0.285551f,
+ 0.308510f, 0.332376f, 0.357153f, 0.382845f, 0.409454f, 0.436977f, 0.465404f, 0.494713f,
+ 0.524864f, 0.555779f, 0.587302f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000037f, 0.000486f, 0.001621f,
+ 0.003553f, 0.006338f, 0.010004f, 0.014565f, 0.020024f, 0.026380f, 0.033629f, 0.041765f,
+ 0.050782f, 0.060673f, 0.071431f, 0.083052f, 0.095529f, 0.108859f, 0.123038f, 0.138065f,
+ 0.153938f, 0.170657f, 0.188224f, 0.206640f, 0.225909f, 0.246035f, 0.267022f, 0.288878f,
+ 0.311607f, 0.335216f, 0.359713f, 0.385103f, 0.411390f, 0.438576f, 0.466656f, 0.495617f,
+ 0.525431f, 0.556041f, 0.587338f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000149f, 0.000861f, 0.002312f,
+ 0.004581f, 0.007709f, 0.011713f, 0.016599f, 0.022367f, 0.029014f, 0.036531f, 0.044912f,
+ 0.054148f, 0.064233f, 0.075158f, 0.086918f, 0.099507f, 0.112922f, 0.127157f, 0.142212f,
+ 0.158085f, 0.174776f, 0.192287f, 0.210619f, 0.229775f, 0.249761f, 0.270582f, 0.292243f,
+ 0.314753f, 0.338118f, 0.362347f, 0.387447f, 0.413424f, 0.440284f, 0.468027f, 0.496645f,
+ 0.526122f, 0.556417f, 0.587451f, 0.619048f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000012f, 0.000355f, 0.001353f, 0.003126f,
+ 0.005730f, 0.009194f, 0.013526f, 0.018728f, 0.024795f, 0.031720f, 0.039494f, 0.048109f,
+ 0.057555f, 0.067824f, 0.078909f, 0.090802f, 0.103499f, 0.116993f, 0.131282f, 0.146364f,
+ 0.162237f, 0.178902f, 0.196358f, 0.214610f, 0.233660f, 0.253512f, 0.274174f, 0.295650f,
+ 0.317950f, 0.341081f, 0.365053f, 0.389874f, 0.415553f, 0.442098f, 0.469512f, 0.497794f,
+ 0.526935f, 0.556908f, 0.587657f, 0.619060f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000083f, 0.000665f, 0.001962f, 0.004059f,
+ 0.006997f, 0.010790f, 0.015442f, 0.020949f, 0.027304f, 0.034497f, 0.042518f, 0.051358f,
+ 0.061005f, 0.071451f, 0.082688f, 0.094709f, 0.107507f, 0.121078f, 0.135419f, 0.150526f,
+ 0.166399f, 0.183038f, 0.200443f, 0.218618f, 0.237566f, 0.257291f, 0.277800f, 0.299100f,
+ 0.321199f, 0.344106f, 0.367830f, 0.392383f, 0.417774f, 0.444013f, 0.471107f, 0.499060f,
+ 0.527869f, 0.557517f, 0.587966f, 0.619130f, 0.650794f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000233f, 0.001082f, 0.002688f, 0.005111f,
+ 0.008377f, 0.012493f, 0.017456f, 0.023260f, 0.029893f, 0.037345f, 0.045604f, 0.054659f,
+ 0.064499f, 0.075115f, 0.086498f, 0.098641f, 0.111537f, 0.125182f, 0.139571f, 0.154703f,
+ 0.170576f, 0.187190f, 0.204547f, 0.222648f, 0.241498f, 0.261101f, 0.281465f, 0.302595f,
+ 0.324501f, 0.347192f, 0.370679f, 0.394973f, 0.420085f, 0.446027f, 0.472810f, 0.500441f,
+ 0.528921f, 0.558244f, 0.588384f, 0.619281f, 0.650795f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000033f, 0.000477f, 0.001611f, 0.003532f, 0.006280f,
+ 0.009869f, 0.014301f, 0.019568f, 0.025659f, 0.032563f, 0.040265f, 0.048753f, 0.058016f,
+ 0.068042f, 0.078821f, 0.090344f, 0.102604f, 0.115594f, 0.129309f, 0.143745f, 0.158901f,
+ 0.174774f, 0.191365f, 0.208674f, 0.226705f, 0.245461f, 0.264947f, 0.285170f, 0.306137f,
+ 0.327857f, 0.350341f, 0.373598f, 0.397642f, 0.422485f, 0.448139f, 0.474619f, 0.501933f,
+ 0.530089f, 0.559087f, 0.588913f, 0.619525f, 0.650826f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000130f, 0.000821f, 0.002252f, 0.004491f, 0.007562f,
+ 0.011472f, 0.016213f, 0.021776f, 0.028147f, 0.035312f, 0.043256f, 0.051966f, 0.061430f,
+ 0.071635f, 0.082571f, 0.094229f, 0.106602f, 0.119682f, 0.133465f, 0.147947f, 0.163125f,
+ 0.178998f, 0.195566f, 0.212830f, 0.230793f, 0.249459f, 0.268832f, 0.288920f, 0.309730f,
+ 0.331271f, 0.353554f, 0.376590f, 0.400391f, 0.424973f, 0.450347f, 0.476531f, 0.503535f,
+ 0.531372f, 0.560047f, 0.589554f, 0.619869f, 0.650923f, 0.682540f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000005f, 0.000309f, 0.001270f, 0.003008f, 0.005566f, 0.008959f,
+ 0.013183f, 0.018228f, 0.024080f, 0.030723f, 0.038142f, 0.046321f, 0.055246f, 0.064903f,
+ 0.075281f, 0.086369f, 0.098158f, 0.110639f, 0.123806f, 0.137655f, 0.152180f, 0.167380f,
+ 0.183253f, 0.199799f, 0.217020f, 0.234918f, 0.253496f, 0.272761f, 0.292719f, 0.313377f,
+ 0.334745f, 0.356833f, 0.379654f, 0.403221f, 0.427548f, 0.452651f, 0.478545f, 0.505246f,
+ 0.532768f, 0.561122f, 0.590309f, 0.620318f, 0.651102f, 0.682545f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000053f, 0.000579f, 0.001828f, 0.003878f, 0.006757f, 0.010468f,
+ 0.015002f, 0.020344f, 0.026479f, 0.033388f, 0.041054f, 0.049461f, 0.058594f, 0.068440f,
+ 0.078985f, 0.090220f, 0.102134f, 0.114721f, 0.127972f, 0.141884f, 0.156451f, 0.171672f,
+ 0.187545f, 0.204070f, 0.221249f, 0.239083f, 0.257578f, 0.276738f, 0.296569f, 0.317080f,
+ 0.338281f, 0.360181f, 0.382794f, 0.406133f, 0.430213f, 0.455050f, 0.480662f, 0.507065f,
+ 0.534278f, 0.562313f, 0.591180f, 0.620875f, 0.651373f, 0.682593f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000169f, 0.000949f, 0.002497f, 0.004864f, 0.008063f, 0.012089f,
+ 0.016929f, 0.022563f, 0.028974f, 0.036142f, 0.044049f, 0.052678f, 0.062014f, 0.072042f,
+ 0.082750f, 0.094127f, 0.106164f, 0.118852f, 0.132185f, 0.146157f, 0.160766f, 0.176007f,
+ 0.191880f, 0.208385f, 0.225523f, 0.243296f, 0.261709f, 0.280767f, 0.300476f, 0.320845f,
+ 0.341883f, 0.363601f, 0.386011f, 0.409128f, 0.432967f, 0.457545f, 0.482881f, 0.508992f,
+ 0.535899f, 0.563619f, 0.592165f, 0.621544f, 0.651743f, 0.682709f, 0.714286f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000010f, 0.000368f, 0.001423f, 0.003279f, 0.005966f, 0.009485f, 0.013824f,
+ 0.018964f, 0.024886f, 0.031567f, 0.038988f, 0.047130f, 0.055975f, 0.065508f, 0.075714f,
+ 0.086580f, 0.098095f, 0.110251f, 0.123038f, 0.136450f, 0.150482f, 0.165129f, 0.180390f,
+ 0.196263f, 0.212748f, 0.229847f, 0.247561f, 0.265895f, 0.284854f, 0.304445f, 0.324675f,
+ 0.345555f, 0.367095f, 0.389309f, 0.412210f, 0.435814f, 0.460138f, 0.485203f, 0.511028f,
+ 0.537634f, 0.565041f, 0.593268f, 0.622327f, 0.652217f, 0.682907f, 0.714296f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000068f, 0.000658f, 0.002006f, 0.004178f, 0.007186f, 0.011024f, 0.015672f,
+ 0.021109f, 0.027312f, 0.034259f, 0.041928f, 0.050300f, 0.059356f, 0.069081f, 0.079460f,
+ 0.090480f, 0.102130f, 0.114400f, 0.127284f, 0.140772f, 0.154862f, 0.169548f, 0.184828f,
+ 0.200701f, 0.217167f, 0.234227f, 0.251884f, 0.270141f, 0.289004f, 0.308479f, 0.328575f,
+ 0.349301f, 0.370668f, 0.392689f, 0.415379f, 0.438754f, 0.462830f, 0.487630f, 0.513173f,
+ 0.539482f, 0.566579f, 0.594488f, 0.623226f, 0.652800f, 0.683198f, 0.714354f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000196f, 0.001048f, 0.002702f, 0.005194f, 0.008526f, 0.012680f, 0.017635f,
+ 0.023365f, 0.029846f, 0.037053f, 0.044965f, 0.053561f, 0.062824f, 0.072737f, 0.083284f,
+ 0.094454f, 0.106236f, 0.118619f, 0.131595f, 0.145159f, 0.159305f, 0.174028f, 0.189327f,
+ 0.205200f, 0.221647f, 0.238670f, 0.256270f, 0.274453f, 0.293222f, 0.312585f, 0.332550f,
+ 0.353126f, 0.374324f, 0.396158f, 0.418641f, 0.441790f, 0.465624f, 0.490163f, 0.515429f,
+ 0.541445f, 0.568236f, 0.595828f, 0.624242f, 0.653496f, 0.683588f, 0.714482f, 0.746032f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000012f, 0.000407f, 0.001545f, 0.003514f, 0.006332f, 0.009987f, 0.014457f, 0.019715f,
+ 0.025734f, 0.032488f, 0.039952f, 0.048102f, 0.056919f, 0.066384f, 0.076480f, 0.087193f,
+ 0.098509f, 0.110419f, 0.122912f, 0.135980f, 0.149617f, 0.163817f, 0.178577f, 0.193894f,
+ 0.209767f, 0.226196f, 0.243182f, 0.260728f, 0.278837f, 0.297515f, 0.316768f, 0.336605f,
+ 0.357034f, 0.378067f, 0.399717f, 0.421998f, 0.444928f, 0.468523f, 0.492806f, 0.517798f,
+ 0.543525f, 0.570012f, 0.597288f, 0.625379f, 0.654307f, 0.684084f, 0.714693f, 0.746044f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000074f, 0.000713f, 0.002152f, 0.004446f, 0.007592f, 0.011571f, 0.016356f, 0.021915f,
+ 0.028220f, 0.035243f, 0.042959f, 0.051344f, 0.060377f, 0.070040f, 0.080316f, 0.091191f,
+ 0.102651f, 0.114686f, 0.127286f, 0.140443f, 0.154151f, 0.168405f, 0.183201f, 0.198536f,
+ 0.214409f, 0.230820f, 0.247770f, 0.265263f, 0.283301f, 0.301889f, 0.321035f, 0.340746f,
+ 0.361032f, 0.381904f, 0.403374f, 0.425457f, 0.448169f, 0.471530f, 0.495561f, 0.520284f,
+ 0.545725f, 0.571911f, 0.598873f, 0.626640f, 0.655239f, 0.684692f, 0.714999f, 0.746106f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000208f, 0.001121f, 0.002877f, 0.005501f, 0.008979f, 0.013283f, 0.018380f, 0.024238f,
+ 0.030826f, 0.038115f, 0.046079f, 0.054695f, 0.063941f, 0.073799f, 0.084252f, 0.095285f,
+ 0.106886f, 0.119044f, 0.131749f, 0.144994f, 0.158772f, 0.173078f, 0.187908f, 0.203261f,
+ 0.219134f, 0.235527f, 0.252443f, 0.269883f, 0.287851f, 0.306352f, 0.325393f, 0.344981f,
+ 0.365126f, 0.385839f, 0.407132f, 0.429020f, 0.451520f, 0.474651f, 0.498433f, 0.522890f,
+ 0.548048f, 0.573936f, 0.600584f, 0.628027f, 0.656295f, 0.685417f, 0.715406f, 0.746240f,
+ 0.777778f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000011f,
+ 0.000427f, 0.001638f, 0.003724f, 0.006685f, 0.010497f, 0.015125f, 0.020534f, 0.026688f,
+ 0.033557f, 0.041109f, 0.049318f, 0.058161f, 0.067617f, 0.077666f, 0.088293f, 0.099482f,
+ 0.111221f, 0.123499f, 0.136308f, 0.149639f, 0.163485f, 0.177843f, 0.192707f, 0.208077f,
+ 0.223950f, 0.240326f, 0.257208f, 0.274596f, 0.292496f, 0.310911f, 0.329849f, 0.349316f,
+ 0.369323f, 0.389880f, 0.410999f, 0.432696f, 0.454987f, 0.477890f, 0.501426f, 0.525620f,
+ 0.550498f, 0.576089f, 0.602427f, 0.629544f, 0.657479f, 0.686264f, 0.715924f, 0.746459f,
+ 0.777789f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000071f,
+ 0.000744f, 0.002274f, 0.004698f, 0.008002f, 0.012149f, 0.017102f, 0.022822f, 0.029271f,
+ 0.036417f, 0.044229f, 0.052681f, 0.061749f, 0.071411f, 0.081649f, 0.092447f, 0.103790f,
+ 0.115665f, 0.128062f, 0.140972f, 0.154387f, 0.168301f, 0.182709f, 0.197608f, 0.212994f,
+ 0.228867f, 0.245227f, 0.262074f, 0.279412f, 0.297244f, 0.315575f, 0.334412f, 0.353760f,
+ 0.373631f, 0.394034f, 0.414983f, 0.436491f, 0.458575f, 0.481253f, 0.504547f, 0.528481f,
+ 0.553081f, 0.578377f, 0.604404f, 0.631197f, 0.658795f, 0.687238f, 0.716559f, 0.746776f,
+ 0.777849f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000205f,
+ 0.001168f, 0.003033f, 0.005806f, 0.009456f, 0.013942f, 0.019220f, 0.025250f, 0.031992f,
+ 0.039414f, 0.047484f, 0.056176f, 0.065466f, 0.075333f, 0.085757f, 0.096724f, 0.108218f,
+ 0.120227f, 0.132741f, 0.145751f, 0.159249f, 0.173230f, 0.187687f, 0.202619f, 0.218021f,
+ 0.233894f, 0.250238f, 0.267052f, 0.284341f, 0.302106f, 0.320354f, 0.339090f, 0.358322f,
+ 0.378059f, 0.398311f, 0.419090f, 0.440412f, 0.462292f, 0.484748f, 0.507802f, 0.531477f,
+ 0.555802f, 0.580805f, 0.606522f, 0.632990f, 0.660250f, 0.688346f, 0.717319f, 0.747200f,
+ 0.777982f, 0.809524f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000007f, 0.000427f,
+ 0.001710f, 0.003925f, 0.007054f, 0.011055f, 0.015881f, 0.021485f, 0.027824f, 0.034859f,
+ 0.042554f, 0.050881f, 0.059811f, 0.069321f, 0.079390f, 0.089998f, 0.101132f, 0.112775f,
+ 0.124917f, 0.137547f, 0.150655f, 0.164236f, 0.178281f, 0.192788f, 0.207752f, 0.223171f,
+ 0.239044f, 0.255371f, 0.272153f, 0.289393f, 0.307093f, 0.325259f, 0.343896f, 0.363012f,
+ 0.382617f, 0.402719f, 0.423332f, 0.444469f, 0.466146f, 0.488383f, 0.511199f, 0.534618f,
+ 0.558668f, 0.583380f, 0.608787f, 0.634929f, 0.661849f, 0.689594f, 0.718211f, 0.747742f,
+ 0.778205f, 0.809530f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000059f, 0.000754f,
+ 0.002379f, 0.004956f, 0.008449f, 0.012806f, 0.017974f, 0.023905f, 0.030553f, 0.037879f,
+ 0.045847f, 0.054429f, 0.063595f, 0.073323f, 0.083592f, 0.094384f, 0.105682f, 0.117474f,
+ 0.129747f, 0.142491f, 0.155697f, 0.169358f, 0.183469f, 0.198024f, 0.213020f, 0.228455f,
+ 0.244329f, 0.260639f, 0.277389f, 0.294580f, 0.312216f, 0.330300f, 0.348840f, 0.367842f,
+ 0.387315f, 0.407270f, 0.427717f, 0.448671f, 0.470149f, 0.492167f, 0.514746f, 0.537911f,
+ 0.561688f, 0.586108f, 0.611206f, 0.637022f, 0.663599f, 0.690989f, 0.719242f, 0.748411f,
+ 0.778531f, 0.809583f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000187f, 0.001196f,
+ 0.003184f, 0.006136f, 0.010000f, 0.014716f, 0.020230f, 0.026488f, 0.033445f, 0.041062f,
+ 0.049303f, 0.058138f, 0.067540f, 0.077485f, 0.087953f, 0.098926f, 0.110388f, 0.122327f,
+ 0.134729f, 0.147587f, 0.160889f, 0.174631f, 0.188806f, 0.203409f, 0.218437f, 0.233888f,
+ 0.249761f, 0.266056f, 0.282774f, 0.299917f, 0.317488f, 0.335493f, 0.353936f, 0.372825f,
+ 0.392168f, 0.411976f, 0.432259f, 0.453032f, 0.474310f, 0.496111f, 0.518456f, 0.541367f,
+ 0.564872f, 0.589001f, 0.613789f, 0.639277f, 0.665510f, 0.692539f, 0.720422f, 0.749216f,
+ 0.778974f, 0.809711f, 0.841270f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000002f, 0.000409f, 0.001767f,
+ 0.004137f, 0.007474f, 0.011716f, 0.016797f, 0.022657f, 0.029244f, 0.036512f, 0.044420f,
+ 0.052933f, 0.062021f, 0.071657f, 0.081819f, 0.092485f, 0.103638f, 0.115263f, 0.127348f,
+ 0.139880f, 0.152849f, 0.166248f, 0.180070f, 0.194308f, 0.208958f, 0.224018f, 0.239485f,
+ 0.255359f, 0.271638f, 0.288324f, 0.305419f, 0.322927f, 0.340851f, 0.359199f, 0.377975f,
+ 0.397189f, 0.416851f, 0.436971f, 0.457564f, 0.478644f, 0.500229f, 0.522339f, 0.544997f,
+ 0.568230f, 0.592068f, 0.616546f, 0.641705f, 0.667590f, 0.694255f, 0.721760f, 0.750168f,
+ 0.779545f, 0.809933f, 0.841272f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000041f, 0.000744f, 0.002481f,
+ 0.005248f, 0.008982f, 0.013608f, 0.019058f, 0.025269f, 0.032188f, 0.039767f, 0.047967f,
+ 0.056752f, 0.066093f, 0.075963f, 0.086340f, 0.097203f, 0.108537f, 0.120325f, 0.132554f,
+ 0.145215f, 0.158296f, 0.171790f, 0.185691f, 0.199993f, 0.214691f, 0.229782f, 0.245265f,
+ 0.261138f, 0.277401f, 0.294056f, 0.311104f, 0.328548f, 0.346394f, 0.364645f, 0.383310f,
+ 0.402396f, 0.421912f, 0.441870f, 0.462283f, 0.483165f, 0.504535f, 0.526410f, 0.548816f,
+ 0.571776f, 0.595323f, 0.619489f, 0.644317f, 0.669852f, 0.696148f, 0.723267f, 0.751280f,
+ 0.780258f, 0.810268f, 0.841311f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000156f, 0.001209f, 0.003349f,
+ 0.006531f, 0.010672f, 0.015691f, 0.021515f, 0.028080f, 0.035332f, 0.043225f, 0.051717f,
+ 0.060775f, 0.070370f, 0.080474f, 0.091067f, 0.102128f, 0.113641f, 0.125591f, 0.137965f,
+ 0.150754f, 0.163947f, 0.177537f, 0.191516f, 0.205881f, 0.220626f, 0.235749f, 0.251248f,
+ 0.267121f, 0.283368f, 0.299992f, 0.316992f, 0.334374f, 0.352140f, 0.370296f, 0.388849f,
+ 0.407807f, 0.427178f, 0.446974f, 0.467207f, 0.487892f, 0.509046f, 0.530687f, 0.552839f,
+ 0.575527f, 0.598780f, 0.622634f, 0.647128f, 0.672308f, 0.698231f, 0.724958f, 0.752563f,
+ 0.781127f, 0.810733f, 0.841426f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000374f, 0.001821f, 0.004389f,
+ 0.008001f, 0.012559f, 0.017979f, 0.024182f, 0.031106f, 0.038695f, 0.046903f, 0.055690f,
+ 0.065023f, 0.074872f, 0.085211f, 0.096020f, 0.107279f, 0.118971f, 0.131084f, 0.143604f,
+ 0.156521f, 0.169825f, 0.183510f, 0.197569f, 0.211997f, 0.226789f, 0.241944f, 0.257458f,
+ 0.273331f, 0.289563f, 0.306154f, 0.323108f, 0.340426f, 0.358113f, 0.376175f, 0.394616f,
+ 0.413445f, 0.432671f, 0.452305f, 0.472358f, 0.492845f, 0.513783f, 0.535189f, 0.557087f,
+ 0.579500f, 0.602459f, 0.625997f, 0.650154f, 0.674976f, 0.700518f, 0.726845f, 0.754032f,
+ 0.782167f, 0.811344f, 0.841644f, 0.873016f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000020f, 0.000719f, 0.002598f, 0.005618f,
+ 0.009675f, 0.014663f, 0.020490f, 0.027080f, 0.034367f, 0.042297f, 0.050824f, 0.059909f,
+ 0.069517f, 0.079622f, 0.090198f, 0.101224f, 0.112682f, 0.124555f, 0.136831f, 0.149496f,
+ 0.162542f, 0.175958f, 0.189739f, 0.203877f, 0.218368f, 0.233208f, 0.248393f, 0.263923f,
+ 0.279796f, 0.296012f, 0.312573f, 0.329479f, 0.346734f, 0.364342f, 0.382307f, 0.400637f,
+ 0.419337f, 0.438418f, 0.457889f, 0.477761f, 0.498050f, 0.518770f, 0.539940f, 0.561581f,
+ 0.583718f, 0.606380f, 0.629599f, 0.653415f, 0.677874f, 0.703030f, 0.728948f, 0.755706f,
+ 0.783396f, 0.812121f, 0.841989f, 0.873035f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000114f, 0.001215f, 0.003561f, 0.007056f,
+ 0.011574f, 0.017003f, 0.023248f, 0.030232f, 0.037888f, 0.046164f, 0.055014f, 0.064399f,
+ 0.074287f, 0.084650f, 0.095464f, 0.106709f, 0.118367f, 0.130423f, 0.142862f, 0.155674f,
+ 0.168849f, 0.182378f, 0.196255f, 0.210473f, 0.225027f, 0.239915f, 0.255132f, 0.270678f,
+ 0.286551f, 0.302751f, 0.319280f, 0.336138f, 0.353330f, 0.370858f, 0.388728f, 0.406944f,
+ 0.425515f, 0.444449f, 0.463756f, 0.483447f, 0.503535f, 0.524036f, 0.544968f, 0.566350f,
+ 0.588208f, 0.610569f, 0.633466f, 0.656936f, 0.681025f, 0.705788f, 0.731289f, 0.757606f,
+ 0.784834f, 0.813085f, 0.842485f, 0.873130f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000324f, 0.001887f, 0.004735f, 0.008727f,
+ 0.013724f, 0.019607f, 0.026280f, 0.033666f, 0.041699f, 0.050326f, 0.059504f, 0.069194f,
+ 0.079365f, 0.089989f, 0.101045f, 0.112512f, 0.124372f, 0.136611f, 0.149216f, 0.162176f,
+ 0.175482f, 0.189125f, 0.203098f, 0.217396f, 0.232015f, 0.246950f, 0.262200f, 0.277761f,
+ 0.293634f, 0.309819f, 0.326315f, 0.343126f, 0.360254f, 0.377701f, 0.395474f, 0.413577f,
+ 0.432018f, 0.450804f, 0.469944f, 0.489451f, 0.509337f, 0.529617f, 0.550307f, 0.571428f,
+ 0.593003f, 0.615059f, 0.637628f, 0.660746f, 0.684460f, 0.708820f, 0.733893f, 0.759756f,
+ 0.786505f, 0.814259f, 0.843157f, 0.873340f, 0.904762f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000003f, 0.000683f, 0.002764f, 0.006148f, 0.010661f,
+ 0.016155f, 0.022506f, 0.029620f, 0.037417f, 0.045835f, 0.054821f, 0.064333f, 0.074333f,
+ 0.084792f, 0.095683f, 0.106984f, 0.118675f, 0.130741f, 0.143166f, 0.155939f, 0.169049f,
+ 0.182487f, 0.196245f, 0.210317f, 0.224697f, 0.239380f, 0.254364f, 0.269646f, 0.285223f,
+ 0.301096f, 0.317265f, 0.333729f, 0.350491f, 0.367554f, 0.384920f, 0.402594f, 0.420582f,
+ 0.438891f, 0.457527f, 0.476499f, 0.495820f, 0.515500f, 0.535555f, 0.556000f, 0.576855f,
+ 0.598143f, 0.619888f, 0.642123f, 0.664883f, 0.688211f, 0.712160f, 0.736792f, 0.762186f,
+ 0.788439f, 0.815672f, 0.844034f, 0.873699f, 0.904765f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000066f, 0.001228f, 0.003880f, 0.007835f, 0.012895f,
+ 0.018905f, 0.025742f, 0.033309f, 0.041530f, 0.050342f, 0.059696f, 0.069550f, 0.079868f,
+ 0.090620f, 0.101783f, 0.113333f, 0.125254f, 0.137529f, 0.150144f, 0.163088f, 0.176351f,
+ 0.189924f, 0.203799f, 0.217970f, 0.232433f, 0.247182f, 0.262216f, 0.277530f, 0.293124f,
+ 0.308997f, 0.325149f, 0.341581f, 0.358294f, 0.375290f, 0.392573f, 0.410148f, 0.428019f,
+ 0.446192f, 0.464676f, 0.483478f, 0.502608f, 0.522079f, 0.541905f, 0.562100f, 0.582684f,
+ 0.603677f, 0.625106f, 0.646998f, 0.669390f, 0.692324f, 0.715849f, 0.740028f, 0.764937f,
+ 0.790673f, 0.817358f, 0.845150f, 0.874244f, 0.904828f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000260f, 0.002001f, 0.005278f, 0.009840f, 0.015475f,
+ 0.022025f, 0.029365f, 0.037402f, 0.046060f, 0.055280f, 0.065013f, 0.075218f, 0.085861f,
+ 0.096916f, 0.108356f, 0.120163f, 0.132319f, 0.144808f, 0.157618f, 0.170737f, 0.184155f,
+ 0.197866f, 0.211861f, 0.226134f, 0.240682f, 0.255499f, 0.270583f, 0.285931f, 0.301542f,
+ 0.317415f, 0.333550f, 0.349948f, 0.366610f, 0.383539f, 0.400738f, 0.418210f, 0.435961f,
+ 0.453997f, 0.472324f, 0.490951f, 0.509887f, 0.529144f, 0.548735f, 0.568674f, 0.588979f,
+ 0.609671f, 0.630773f, 0.652314f, 0.674328f, 0.696854f, 0.719942f, 0.743651f, 0.768057f,
+ 0.793253f, 0.819363f, 0.846547f, 0.875017f, 0.905021f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000642f, 0.003053f, 0.007010f, 0.012219f, 0.018462f,
+ 0.025577f, 0.033444f, 0.041970f, 0.051082f, 0.060724f, 0.070849f, 0.081417f, 0.092397f,
+ 0.103763f, 0.115491f, 0.127562f, 0.139960f, 0.152670f, 0.165679f, 0.178979f, 0.192558f,
+ 0.206410f, 0.220529f, 0.234907f, 0.249542f, 0.264428f, 0.279564f, 0.294947f, 0.310575f,
+ 0.326448f, 0.342566f, 0.358929f, 0.375540f, 0.392399f, 0.409511f, 0.426878f, 0.444506f,
+ 0.462400f, 0.480566f, 0.499013f, 0.517749f, 0.536785f, 0.556134f, 0.575809f, 0.595827f,
+ 0.616207f, 0.636973f, 0.658150f, 0.679772f, 0.701876f, 0.724509f, 0.747730f, 0.771609f,
+ 0.796240f, 0.821743f, 0.848280f, 0.876069f, 0.905404f, 0.936508f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000020f, 0.001278f, 0.004450f, 0.009147f, 0.015050f, 0.021937f,
+ 0.029649f, 0.038068f, 0.047106f, 0.056694f, 0.066777f, 0.077310f, 0.088257f, 0.099588f,
+ 0.111277f, 0.123304f, 0.135650f, 0.148299f, 0.161237f, 0.174455f, 0.187941f, 0.201687f,
+ 0.215687f, 0.229933f, 0.244420f, 0.259145f, 0.274103f, 0.289293f, 0.304711f, 0.320357f,
+ 0.336230f, 0.352330f, 0.368658f, 0.385214f, 0.402002f, 0.419023f, 0.436282f, 0.453782f,
+ 0.471529f, 0.489528f, 0.507788f, 0.526317f, 0.545124f, 0.564221f, 0.583621f, 0.603341f,
+ 0.623397f, 0.643812f, 0.664611f, 0.685824f, 0.707488f, 0.729646f, 0.752354f, 0.775680f,
+ 0.799715f, 0.824574f, 0.850417f, 0.877466f, 0.906040f, 0.936528f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000183f, 0.002253f, 0.006282f, 0.011786f, 0.018436f, 0.026011f,
+ 0.034358f, 0.043364f, 0.052944f, 0.063033f, 0.073580f, 0.084544f, 0.095889f, 0.107588f,
+ 0.119617f, 0.131957f, 0.144591f, 0.157503f, 0.170682f, 0.184117f, 0.197799f, 0.211720f,
+ 0.225873f, 0.240253f, 0.254854f, 0.269673f, 0.284707f, 0.299953f, 0.315408f, 0.331073f,
+ 0.346946f, 0.363028f, 0.379318f, 0.395818f, 0.412530f, 0.429457f, 0.446602f, 0.463968f,
+ 0.481561f, 0.499386f, 0.517450f, 0.535761f, 0.554328f, 0.573162f, 0.592275f, 0.611681f,
+ 0.631398f, 0.651445f, 0.671845f, 0.692628f, 0.713827f, 0.735484f, 0.757650f, 0.780390f,
+ 0.803789f, 0.827960f, 0.853056f, 0.879298f, 0.907014f, 0.936691f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000617f, 0.003679f, 0.008674f, 0.015068f, 0.022531f, 0.030851f,
+ 0.039880f, 0.049515f, 0.059675f, 0.070300f, 0.081343f, 0.092764f, 0.104533f, 0.116624f,
+ 0.129015f, 0.141687f, 0.154626f, 0.167818f, 0.181252f, 0.194918f, 0.208807f, 0.222913f,
+ 0.237229f, 0.251750f, 0.266473f, 0.281392f, 0.296505f, 0.311811f, 0.327306f, 0.342991f,
+ 0.358864f, 0.374925f, 0.391176f, 0.407616f, 0.424249f, 0.441076f, 0.458100f, 0.475324f,
+ 0.492754f, 0.510394f, 0.528251f, 0.546331f, 0.564644f, 0.583198f, 0.602005f, 0.621078f,
+ 0.640434f, 0.660089f, 0.680066f, 0.700390f, 0.721094f, 0.742215f, 0.763800f, 0.785912f,
+ 0.808628f, 0.832055f, 0.856338f, 0.881690f, 0.908441f, 0.937125f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000000f, 0.001477f, 0.005732f, 0.011826f, 0.019212f, 0.027573f, 0.036710f,
+ 0.046487f, 0.056807f, 0.067598f, 0.078806f, 0.090386f, 0.102304f, 0.114532f, 0.127047f,
+ 0.139828f, 0.152861f, 0.166130f, 0.179624f, 0.193332f, 0.207247f, 0.221360f, 0.235666f,
+ 0.250158f, 0.264832f, 0.279684f, 0.294711f, 0.309911f, 0.325280f, 0.340819f, 0.356524f,
+ 0.372397f, 0.388438f, 0.404645f, 0.421022f, 0.437569f, 0.454287f, 0.471181f, 0.488253f,
+ 0.505507f, 0.522947f, 0.540580f, 0.558412f, 0.576449f, 0.594701f, 0.613178f, 0.631892f,
+ 0.650856f, 0.670088f, 0.689606f, 0.709434f, 0.729600f, 0.750138f, 0.771093f, 0.792519f,
+ 0.814488f, 0.837097f, 0.860481f, 0.884842f, 0.910494f, 0.937985f, 0.968254f, 1.000000f,
+ 0.000000f, 0.000096f, 0.003012f, 0.008704f, 0.016071f, 0.024590f, 0.033968f, 0.044025f,
+ 0.054641f, 0.065728f, 0.077225f, 0.089081f, 0.101260f, 0.113731f, 0.126469f, 0.139454f,
+ 0.152670f, 0.166101f, 0.179736f, 0.193565f, 0.207578f, 0.221769f, 0.236130f, 0.250656f,
+ 0.265343f, 0.280187f, 0.295183f, 0.310330f, 0.325624f, 0.341065f, 0.356650f, 0.372380f,
+ 0.388253f, 0.404269f, 0.420430f, 0.436735f, 0.453187f, 0.469786f, 0.486536f, 0.503439f,
+ 0.520498f, 0.537717f, 0.555102f, 0.572657f, 0.590390f, 0.608307f, 0.626419f, 0.644733f,
+ 0.663264f, 0.682025f, 0.701032f, 0.720308f, 0.739875f, 0.759764f, 0.780014f, 0.800673f,
+ 0.821803f, 0.843492f, 0.865860f, 0.889087f, 0.913466f, 0.939520f, 0.968350f, 1.000000f,
+ 0.000000f, 0.000727f, 0.005696f, 0.013170f, 0.022074f, 0.031940f, 0.042520f, 0.053660f,
+ 0.065258f, 0.077243f, 0.089562f, 0.102175f, 0.115050f, 0.128164f, 0.141495f, 0.155026f,
+ 0.168745f, 0.182639f, 0.196699f, 0.210915f, 0.225282f, 0.239792f, 0.254440f, 0.269223f,
+ 0.284135f, 0.299174f, 0.314337f, 0.329622f, 0.345026f, 0.360549f, 0.376189f, 0.391946f,
+ 0.407819f, 0.423808f, 0.439914f, 0.456137f, 0.472479f, 0.488940f, 0.505523f, 0.522230f,
+ 0.539064f, 0.556028f, 0.573125f, 0.590361f, 0.607741f, 0.625270f, 0.642957f, 0.660809f,
+ 0.678836f, 0.697050f, 0.715465f, 0.734098f, 0.752968f, 0.772101f, 0.791529f, 0.811290f,
+ 0.831438f, 0.852044f, 0.873210f, 0.895090f, 0.917932f, 0.942204f, 0.968981f, 1.000000f,
+ 0.000000f, 0.002796f, 0.010764f, 0.020645f, 0.031576f, 0.043202f, 0.055340f, 0.067877f,
+ 0.080740f, 0.093877f, 0.107250f, 0.120832f, 0.134598f, 0.148533f, 0.162620f, 0.176849f,
+ 0.191210f, 0.205694f, 0.220294f, 0.235005f, 0.249820f, 0.264737f, 0.279751f, 0.294859f,
+ 0.310058f, 0.325346f, 0.340721f, 0.356181f, 0.371725f, 0.387353f, 0.403063f, 0.418854f,
+ 0.434727f, 0.450682f, 0.466718f, 0.482837f, 0.499038f, 0.515324f, 0.531695f, 0.548153f,
+ 0.564700f, 0.581338f, 0.598070f, 0.614900f, 0.631830f, 0.648865f, 0.666011f, 0.683273f,
+ 0.700659f, 0.718176f, 0.735834f, 0.753646f, 0.771625f, 0.789790f, 0.808162f, 0.826771f,
+ 0.845654f, 0.864863f, 0.884472f, 0.904592f, 0.925407f, 0.947271f, 0.971050f, 1.000000f,
+ 0.000000f, 0.015873f, 0.031746f, 0.047619f, 0.063492f, 0.079365f, 0.095238f, 0.111111f,
+ 0.126984f, 0.142857f, 0.158730f, 0.174603f, 0.190476f, 0.206349f, 0.222222f, 0.238095f,
+ 0.253968f, 0.269841f, 0.285714f, 0.301587f, 0.317460f, 0.333333f, 0.349206f, 0.365079f,
+ 0.380952f, 0.396825f, 0.412698f, 0.428571f, 0.444444f, 0.460317f, 0.476190f, 0.492063f,
+ 0.507937f, 0.523810f, 0.539683f, 0.555556f, 0.571429f, 0.587302f, 0.603175f, 0.619048f,
+ 0.634921f, 0.650794f, 0.666667f, 0.682540f, 0.698413f, 0.714286f, 0.730159f, 0.746032f,
+ 0.761905f, 0.777778f, 0.793651f, 0.809524f, 0.825397f, 0.841270f, 0.857143f, 0.873016f,
+ 0.888889f, 0.904762f, 0.920635f, 0.936508f, 0.952381f, 0.968254f, 0.984127f, 1.000000f
+};
+
+static float btdf_split_sum_ggx[32][64 * 64] = {
+ {
+ 0.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f,
+ 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 0.999512f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.039917f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f,
+ 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.999512f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ },
+ {
+ 0.000122f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000122f, 0.004147f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.897949f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000732f, 0.996094f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.002439f,
+ 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000366f, 0.078308f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.001098f, 0.992188f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.999512f,
+ 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.005001f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.999512f,
+ 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000732f, 0.902344f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.002928f, 0.997070f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 1.000000f, 0.999512f, 0.999512f, 1.000000f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000732f, 0.301758f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.999512f, 1.000000f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.002562f, 0.996094f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000732f, 0.433594f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000244f, 0.004021f, 0.996582f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.001098f, 0.949219f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000610f,
+ 0.012039f, 0.998047f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.002073f, 0.993652f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000854f, 0.725586f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000610f, 0.011856f, 0.998047f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.002905f, 0.995117f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.001098f, 0.978027f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000732f, 0.314941f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000731f, 0.017670f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000366f, 0.005852f, 0.997559f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.003050f,
+ 0.996094f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.001957f, 0.993652f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.001586f, 0.990234f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.001220f, 0.986816f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.001220f, 0.984375f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f,
+ 0.001098f, 0.985352f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.001220f, 0.989258f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.001341f, 0.993652f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.001586f, 0.996094f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.002802f, 0.997559f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000117f, 0.000122f, 0.000122f,
+ 0.000243f, 0.006088f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000366f, 0.026321f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000732f, 0.892578f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000975f, 0.993652f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.002317f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.017944f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000731f, 0.983887f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000119f, 0.000122f, 0.000122f, 0.001653f, 0.998535f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.026108f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000732f, 0.995605f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.003777f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000365f, 0.991211f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.002195f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000364f, 0.993164f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.002672f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000360f, 0.998047f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.017075f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000731f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.997070f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.006874f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000480f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.996582f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000067f, 0.005440f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000365f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.995605f, 0.995117f,
+ 0.995117f, 0.995605f, 0.995117f, 0.995117f,
+ },
+ {
+ 0.003168f, 0.995605f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000976f, 0.053314f, 0.994629f, 0.998535f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000122f, 0.000122f, 0.000732f, 0.003660f,
+ 0.653809f, 0.995117f, 0.998047f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000488f, 0.001463f, 0.010452f, 0.947266f, 0.995605f, 0.998535f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000365f, 0.000853f, 0.002928f, 0.037750f,
+ 0.980957f, 0.996582f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000243f, 0.000610f, 0.001342f, 0.006100f, 0.314453f, 0.989746f, 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000487f, 0.001091f, 0.002317f, 0.015839f, 0.910645f,
+ 0.993652f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000366f, 0.000732f, 0.001463f, 0.005302f, 0.068909f, 0.977539f, 0.995605f, 0.998047f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000244f, 0.000732f, 0.001098f, 0.002560f, 0.011551f, 0.658691f, 0.989746f,
+ 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000366f,
+ 0.000732f, 0.001585f, 0.004868f, 0.041077f, 0.958984f, 0.994141f, 0.997559f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000244f, 0.000732f, 0.001215f, 0.002802f, 0.010834f, 0.441895f, 0.987305f, 0.996094f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000242f, 0.000488f, 0.000850f,
+ 0.001586f, 0.004753f, 0.039154f, 0.948242f, 0.993652f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000366f, 0.000732f, 0.001220f, 0.003159f, 0.012032f, 0.480713f, 0.985840f, 0.996094f, 0.998047f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000240f, 0.000731f, 0.001097f, 0.001950f,
+ 0.005966f, 0.054413f, 0.957520f, 0.994141f, 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000486f, 0.000732f, 0.001534f, 0.003536f, 0.016937f, 0.726562f, 0.988281f, 0.996582f, 0.998047f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000365f, 0.000732f, 0.001098f, 0.002192f, 0.008278f,
+ 0.125244f, 0.974121f, 0.994629f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000365f, 0.000731f, 0.000947f, 0.001828f, 0.005314f, 0.031677f, 0.916016f, 0.991699f, 0.997070f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000488f, 0.000732f, 0.001339f, 0.003294f, 0.014389f, 0.562012f,
+ 0.985840f, 0.996094f, 0.998047f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000487f,
+ 0.000732f, 0.001098f, 0.002310f, 0.008163f, 0.123779f, 0.973633f, 0.994629f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000365f, 0.000732f, 0.001097f, 0.002071f, 0.005669f, 0.041199f, 0.937988f, 0.992676f,
+ 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000118f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000366f, 0.000728f, 0.000732f,
+ 0.001585f, 0.004143f, 0.020813f, 0.813965f, 0.989746f, 0.996582f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000116f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000488f, 0.000732f, 0.001220f, 0.003292f, 0.012581f, 0.446533f, 0.984863f, 0.996094f, 0.998047f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000471f, 0.000732f, 0.001220f, 0.002796f,
+ 0.009338f, 0.161865f, 0.977051f, 0.995117f, 0.997559f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000365f, 0.000732f, 0.001098f, 0.002285f, 0.006870f, 0.074097f, 0.965820f, 0.994141f, 0.997559f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000366f, 0.000731f, 0.001086f, 0.001945f, 0.005238f, 0.043732f,
+ 0.947754f, 0.993652f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000366f,
+ 0.000730f, 0.000893f, 0.001826f, 0.004871f, 0.030411f, 0.922852f, 0.992188f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000609f, 0.000732f, 0.001407f, 0.004375f, 0.023758f, 0.892090f, 0.992188f,
+ 0.997070f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000605f, 0.000732f,
+ 0.001579f, 0.003941f, 0.020767f, 0.862793f, 0.991699f, 0.997559f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000238f, 0.000483f, 0.000732f, 0.001449f, 0.003654f, 0.018951f, 0.847656f, 0.991699f, 0.997559f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000233f, 0.000485f, 0.000732f, 0.001308f, 0.003353f,
+ 0.018997f, 0.855469f, 0.991699f, 0.997559f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000118f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000487f, 0.000732f, 0.001292f, 0.003649f, 0.019791f, 0.881836f, 0.992188f, 0.997559f, 0.998535f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000432f, 0.000732f, 0.001220f, 0.003635f, 0.021912f, 0.916992f,
+ 0.993652f, 0.997559f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000116f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000487f,
+ 0.000732f, 0.001245f, 0.004002f, 0.028107f, 0.946289f, 0.994141f, 0.998047f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000085f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000475f, 0.000732f, 0.001611f, 0.004581f, 0.040466f, 0.966309f, 0.995605f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000487f, 0.000732f, 0.001703f,
+ 0.005589f, 0.073486f, 0.979980f, 0.996094f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000475f, 0.000732f, 0.001706f, 0.006809f, 0.198730f, 0.987305f, 0.997559f, 0.998535f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000488f, 0.000732f, 0.002071f, 0.009590f, 0.647949f,
+ 0.992188f, 0.997559f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000710f, 0.001093f, 0.002541f, 0.015533f, 0.922852f, 0.995117f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000116f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000242f, 0.000728f, 0.001218f, 0.003387f, 0.034454f, 0.975586f, 0.996582f, 0.998535f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000365f, 0.000731f, 0.001219f,
+ 0.004959f, 0.161865f, 0.989746f, 0.998047f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000366f, 0.000731f, 0.001767f, 0.009331f, 0.849121f, 0.994629f, 0.998535f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000487f, 0.000732f, 0.002644f, 0.024231f, 0.977051f,
+ 0.997559f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000685f, 0.001217f, 0.004139f, 0.195435f, 0.992676f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000362f, 0.000731f, 0.001570f, 0.010086f, 0.944824f, 0.997070f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000365f, 0.000745f, 0.002781f,
+ 0.051758f, 0.990723f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000599f, 0.001176f, 0.006641f, 0.899414f, 0.997070f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000731f, 0.002066f, 0.032654f, 0.991211f, 0.998535f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000119f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000448f,
+ 0.001088f, 0.005440f, 0.918457f, 0.997070f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000119f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000725f, 0.001822f, 0.038452f, 0.994141f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000329f, 0.000848f, 0.005672f, 0.972168f,
+ 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000581f, 0.001982f, 0.155273f, 0.997070f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000330f, 0.000848f, 0.009247f, 0.992676f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000589f, 0.002625f,
+ 0.958496f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.001199f, 0.083374f, 0.998047f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000716f, 0.007244f, 0.996582f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f,
+ 0.002277f, 0.991211f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000070f, 0.000121f, 0.000122f, 0.000122f, 0.000854f, 0.950684f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000111f, 0.000121f, 0.000122f, 0.000475f, 0.067139f, 0.999512f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000118f, 0.000122f,
+ 0.000002f, 0.005859f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000014f, 0.001376f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000572f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000077f, 0.000002f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000103f, 0.992188f, 0.991699f, 0.991699f, 0.992188f, 0.992188f, 0.991699f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.940430f, 0.940430f,
+ 0.940918f, 0.940918f, 0.940430f, 0.940430f,
+ },
+ {
+ 0.014023f, 0.979492f, 0.994629f, 0.997070f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000488f, 0.004757f, 0.163330f, 0.975098f, 0.993164f, 0.996582f, 0.997559f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000610f, 0.002928f, 0.017166f,
+ 0.563965f, 0.978027f, 0.992676f, 0.996094f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000364f, 0.000732f, 0.002192f, 0.006573f, 0.044952f, 0.830566f, 0.980957f, 0.992676f, 0.996094f, 0.997070f, 0.998047f,
+ 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 1.000000f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000366f, 0.000854f, 0.001586f, 0.004253f, 0.014313f, 0.130371f,
+ 0.919922f, 0.984375f, 0.993652f, 0.996094f, 0.997070f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000488f,
+ 0.000854f, 0.001342f, 0.003025f, 0.007305f, 0.028870f, 0.407715f, 0.954590f, 0.987305f, 0.993652f, 0.996094f, 0.997070f, 0.998047f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000609f, 0.000842f, 0.000976f, 0.002193f, 0.005112f, 0.012505f, 0.066589f, 0.768066f,
+ 0.970703f, 0.989746f, 0.994629f, 0.996582f, 0.997070f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000244f, 0.000599f, 0.000609f, 0.000976f,
+ 0.001829f, 0.003046f, 0.007256f, 0.023499f, 0.194946f, 0.908691f, 0.979980f, 0.991699f, 0.995117f, 0.996582f, 0.997559f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000244f, 0.000488f, 0.000609f, 0.000976f, 0.001583f, 0.002647f, 0.004726f, 0.012169f, 0.050537f, 0.568359f, 0.954102f,
+ 0.985840f, 0.993164f, 0.995605f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000244f, 0.000488f, 0.000610f, 0.000975f, 0.001211f, 0.001946f,
+ 0.003532f, 0.007793f, 0.022446f, 0.139648f, 0.856445f, 0.974121f, 0.989746f, 0.994141f, 0.996094f, 0.997559f, 0.998047f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000241f,
+ 0.000310f, 0.000609f, 0.000807f, 0.001098f, 0.001822f, 0.002794f, 0.005699f, 0.012878f, 0.047821f, 0.469238f, 0.941406f, 0.982910f,
+ 0.991699f, 0.995117f, 0.996582f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000244f, 0.000244f, 0.000609f, 0.000732f, 0.001098f, 0.001461f, 0.002274f, 0.004025f,
+ 0.008247f, 0.023254f, 0.135254f, 0.833984f, 0.969727f, 0.987793f, 0.993652f, 0.995605f, 0.997070f, 0.998047f, 0.998535f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000207f, 0.000244f, 0.000609f,
+ 0.000610f, 0.001096f, 0.001098f, 0.002071f, 0.003370f, 0.006172f, 0.014442f, 0.052795f, 0.486572f, 0.940430f, 0.981934f, 0.991699f,
+ 0.994629f, 0.996582f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000244f, 0.000485f, 0.000610f, 0.001080f, 0.001098f, 0.001742f, 0.002668f, 0.004692f, 0.010147f,
+ 0.028076f, 0.168701f, 0.854004f, 0.970703f, 0.988770f, 0.993652f, 0.996094f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000244f, 0.000487f, 0.000610f, 0.000731f,
+ 0.001098f, 0.001413f, 0.002411f, 0.003895f, 0.007072f, 0.017242f, 0.069580f, 0.605957f, 0.948730f, 0.983398f, 0.992188f, 0.995117f,
+ 0.996582f, 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000244f, 0.000244f, 0.000609f, 0.000610f, 0.001094f, 0.001337f, 0.001828f, 0.003275f, 0.005814f, 0.012054f, 0.036987f,
+ 0.270752f, 0.899414f, 0.975586f, 0.989746f, 0.993652f, 0.996094f, 0.997070f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000241f, 0.000365f, 0.000597f, 0.000610f, 0.000970f, 0.001098f,
+ 0.001815f, 0.002771f, 0.005009f, 0.008888f, 0.023804f, 0.115845f, 0.775879f, 0.962891f, 0.986328f, 0.993164f, 0.995605f, 0.997070f,
+ 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000244f, 0.000536f, 0.000731f, 0.000937f, 0.001203f, 0.001581f, 0.002186f, 0.004005f, 0.007061f, 0.016830f, 0.061218f, 0.522949f,
+ 0.940430f, 0.981934f, 0.991211f, 0.994629f, 0.996582f, 0.997559f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000363f, 0.000487f, 0.000731f, 0.000732f, 0.001097f, 0.001339f, 0.002071f,
+ 0.003498f, 0.005947f, 0.012390f, 0.037964f, 0.268799f, 0.896973f, 0.975586f, 0.989258f, 0.994141f, 0.996094f, 0.997070f, 0.998047f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000244f, 0.000366f,
+ 0.000609f, 0.000610f, 0.001094f, 0.001215f, 0.002056f, 0.003183f, 0.004742f, 0.009880f, 0.026337f, 0.139526f, 0.813477f, 0.966309f,
+ 0.986816f, 0.993164f, 0.996094f, 0.997070f, 0.997559f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000163f, 0.000363f, 0.000600f, 0.000731f, 0.001088f, 0.001216f, 0.001616f, 0.002640f, 0.004402f,
+ 0.008156f, 0.019669f, 0.083191f, 0.664062f, 0.953125f, 0.984375f, 0.992188f, 0.995117f, 0.997070f, 0.998047f, 0.998535f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000244f, 0.000523f, 0.000731f,
+ 0.000732f, 0.001097f, 0.001690f, 0.002169f, 0.003998f, 0.006939f, 0.015808f, 0.055634f, 0.471191f, 0.935059f, 0.980957f, 0.991211f,
+ 0.995117f, 0.996582f, 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000336f, 0.000486f, 0.000731f, 0.000732f, 0.001097f, 0.001558f, 0.002069f, 0.003525f, 0.006058f, 0.013062f,
+ 0.040894f, 0.306396f, 0.910156f, 0.978027f, 0.990234f, 0.994141f, 0.996582f, 0.997559f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000113f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000360f, 0.000515f, 0.000731f, 0.000731f, 0.001094f,
+ 0.001219f, 0.002148f, 0.003159f, 0.005577f, 0.011360f, 0.031952f, 0.203979f, 0.874512f, 0.973633f, 0.989258f, 0.994141f, 0.996582f,
+ 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000325f, 0.000366f, 0.000731f, 0.000731f, 0.001093f, 0.001219f, 0.001820f, 0.002916f, 0.005291f, 0.009758f, 0.026352f, 0.145020f,
+ 0.832520f, 0.969238f, 0.988281f, 0.993652f, 0.996094f, 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000244f, 0.000440f, 0.000605f, 0.000731f, 0.001086f, 0.001097f, 0.001646f,
+ 0.002670f, 0.004230f, 0.008835f, 0.022415f, 0.112183f, 0.786133f, 0.966309f, 0.987793f, 0.993652f, 0.996094f, 0.997559f, 0.998047f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000272f, 0.000358f,
+ 0.000565f, 0.000731f, 0.000790f, 0.001210f, 0.001573f, 0.002434f, 0.004360f, 0.008102f, 0.020660f, 0.092896f, 0.741699f, 0.962891f,
+ 0.987305f, 0.993164f, 0.996094f, 0.997070f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000364f, 0.000723f, 0.000731f, 0.000731f, 0.001216f, 0.001698f, 0.002510f, 0.003998f,
+ 0.007484f, 0.018463f, 0.082336f, 0.709961f, 0.961426f, 0.986816f, 0.993652f, 0.996094f, 0.997559f, 0.998535f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000242f, 0.000362f, 0.000704f, 0.000730f,
+ 0.000845f, 0.001096f, 0.001513f, 0.002302f, 0.003941f, 0.007168f, 0.017746f, 0.076782f, 0.693848f, 0.961426f, 0.987305f, 0.993652f,
+ 0.996094f, 0.997559f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000364f, 0.000579f, 0.000728f, 0.000731f, 0.001096f, 0.001491f, 0.002069f, 0.003899f, 0.007195f, 0.017059f,
+ 0.075439f, 0.701172f, 0.962402f, 0.987793f, 0.993652f, 0.996094f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000119f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000357f, 0.000482f, 0.000730f, 0.000731f, 0.001094f,
+ 0.001334f, 0.002230f, 0.003708f, 0.007217f, 0.017410f, 0.079163f, 0.730469f, 0.965820f, 0.988281f, 0.994141f, 0.996582f, 0.998047f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000112f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000238f,
+ 0.000243f, 0.000365f, 0.000729f, 0.000731f, 0.001095f, 0.001330f, 0.002066f, 0.003637f, 0.007118f, 0.018112f, 0.087708f, 0.775391f,
+ 0.969238f, 0.989258f, 0.994629f, 0.997070f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000073f, 0.000121f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000323f, 0.000390f, 0.000729f, 0.000731f, 0.001094f, 0.001332f, 0.002275f,
+ 0.003782f, 0.007252f, 0.019379f, 0.105042f, 0.827637f, 0.973145f, 0.990723f, 0.994629f, 0.997070f, 0.998047f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000114f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000240f, 0.000369f,
+ 0.000729f, 0.000731f, 0.001093f, 0.001330f, 0.002209f, 0.003937f, 0.007896f, 0.021805f, 0.137207f, 0.876953f, 0.979004f, 0.991699f,
+ 0.995605f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000119f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000272f, 0.000479f, 0.000727f, 0.000731f, 0.001085f, 0.001331f, 0.002291f, 0.004105f, 0.008446f,
+ 0.025024f, 0.202271f, 0.916504f, 0.982910f, 0.993164f, 0.996094f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000120f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000360f, 0.000469f, 0.000681f, 0.000731f,
+ 0.001092f, 0.001331f, 0.002184f, 0.004227f, 0.009521f, 0.030899f, 0.335205f, 0.945312f, 0.986816f, 0.993652f, 0.996582f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000116f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000241f, 0.000429f, 0.000726f, 0.000731f, 0.001091f, 0.001649f, 0.002464f, 0.004810f, 0.010895f, 0.041931f, 0.563477f,
+ 0.963867f, 0.989746f, 0.995117f, 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000101f, 0.000120f,
+ 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000288f, 0.000481f, 0.000720f, 0.000731f, 0.001093f, 0.001571f,
+ 0.002735f, 0.005405f, 0.013199f, 0.064880f, 0.786133f, 0.976562f, 0.992188f, 0.995605f, 0.997559f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000112f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000240f,
+ 0.000481f, 0.000727f, 0.000731f, 0.001093f, 0.001655f, 0.003132f, 0.005909f, 0.017181f, 0.123169f, 0.904297f, 0.984375f, 0.993652f,
+ 0.996582f, 0.998047f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000110f, 0.000120f, 0.000121f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000264f, 0.000392f, 0.000727f, 0.000835f, 0.001196f, 0.001765f, 0.003252f, 0.007343f,
+ 0.024521f, 0.304199f, 0.954102f, 0.989258f, 0.995605f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000034f, 0.000119f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000235f, 0.000375f, 0.000728f,
+ 0.000822f, 0.001095f, 0.002024f, 0.003952f, 0.009193f, 0.040894f, 0.694824f, 0.975586f, 0.992676f, 0.996582f, 0.998047f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000112f, 0.000121f, 0.000121f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000307f, 0.000475f, 0.000728f, 0.000943f, 0.001216f, 0.002283f, 0.004829f, 0.013008f, 0.092224f, 0.908203f,
+ 0.986328f, 0.995117f, 0.997559f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000073f, 0.000118f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000240f, 0.000576f, 0.000728f, 0.001073f, 0.001569f,
+ 0.002668f, 0.005947f, 0.020889f, 0.331543f, 0.965820f, 0.992188f, 0.996582f, 0.998047f, 0.998535f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000100f, 0.000120f, 0.000121f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000362f, 0.000630f, 0.000729f, 0.001087f, 0.001567f, 0.003241f, 0.008240f, 0.043793f, 0.824219f, 0.984375f, 0.994629f, 0.997559f,
+ 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000075f, 0.000119f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000363f, 0.000689f, 0.000730f, 0.001185f, 0.002022f, 0.004108f, 0.013702f,
+ 0.161011f, 0.957031f, 0.991699f, 0.996582f, 0.998047f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000003f, 0.000105f, 0.000120f, 0.000121f, 0.000121f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000156f, 0.000372f, 0.000689f,
+ 0.000730f, 0.001198f, 0.002651f, 0.006214f, 0.028854f, 0.750000f, 0.984375f, 0.995605f, 0.998047f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000102f,
+ 0.000118f, 0.000120f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000472f, 0.000724f, 0.000966f, 0.001658f, 0.003397f, 0.010582f, 0.116028f, 0.959473f, 0.993164f,
+ 0.997559f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000111f, 0.000119f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000130f, 0.000479f, 0.000726f, 0.001163f, 0.002157f,
+ 0.004829f, 0.024338f, 0.776855f, 0.987793f, 0.996582f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000097f, 0.000117f,
+ 0.000120f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000219f, 0.000580f, 0.000728f, 0.001203f, 0.002872f, 0.009109f, 0.130371f, 0.972168f, 0.995117f, 0.998047f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000112f, 0.000118f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000333f, 0.000681f, 0.000940f, 0.001629f, 0.004120f, 0.025467f, 0.890625f,
+ 0.991699f, 0.997559f, 0.999512f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000083f, 0.000116f, 0.000120f,
+ 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000353f, 0.000722f,
+ 0.000961f, 0.002403f, 0.009354f, 0.295166f, 0.985840f, 0.997070f, 0.999512f, 0.999023f, 0.999512f, 0.999023f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000105f, 0.000118f, 0.000120f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000130f, 0.000427f, 0.000605f, 0.001345f, 0.004620f, 0.041229f, 0.966797f, 0.996094f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000074f, 0.000114f, 0.000119f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000089f, 0.000562f, 0.000942f, 0.002352f, 0.012459f,
+ 0.854004f, 0.994141f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000103f, 0.000117f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000007f, 0.000002f,
+ 0.000231f, 0.000596f, 0.001180f, 0.005474f, 0.211426f, 0.991211f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000111f, 0.000118f, 0.000120f, 0.000121f,
+ 0.000121f, 0.000122f, 0.000029f, 0.000004f, 0.000001f, 0.000348f, 0.000896f, 0.002764f, 0.032562f, 0.984375f, 0.998535f, 0.998535f,
+ 0.999023f, 0.998535f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000089f, 0.000116f, 0.000119f, 0.000121f, 0.000121f, 0.000121f, 0.000013f, 0.000003f, 0.000075f, 0.000586f, 0.001508f,
+ 0.010292f, 0.963379f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000006f, 0.000107f, 0.000118f, 0.000120f, 0.000121f, 0.000116f,
+ 0.000008f, 0.000002f, 0.000233f, 0.000857f, 0.004566f, 0.834961f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000083f, 0.000114f, 0.000119f, 0.000120f, 0.000060f, 0.000005f, 0.000001f, 0.000557f, 0.002064f, 0.182373f, 0.997559f, 0.997559f,
+ 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000103f, 0.000117f, 0.000120f, 0.000024f, 0.000003f, 0.000168f,
+ 0.000968f, 0.026428f, 0.996582f, 0.997070f, 0.996582f, 0.996582f, 0.996582f, 0.997070f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000047f,
+ 0.000110f, 0.000118f, 0.000017f, 0.000002f, 0.000513f, 0.006870f, 0.995605f, 0.995605f, 0.995117f, 0.995117f, 0.995117f, 0.995117f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000096f, 0.000115f, 0.000011f, 0.000042f, 0.001919f, 0.992676f, 0.992676f,
+ 0.992676f, 0.992676f, 0.992676f, 0.992676f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000044f, 0.000109f,
+ 0.000008f, 0.000314f, 0.985840f, 0.985840f, 0.985840f, 0.985840f, 0.986328f, 0.985840f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000089f, 0.000060f, 0.964355f, 0.964355f, 0.963867f, 0.963867f, 0.963379f, 0.964355f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000022f, 0.818848f, 0.819824f,
+ 0.819336f, 0.819824f, 0.819824f, 0.819824f,
+ },
+ {
+ 0.038849f, 0.941406f, 0.984375f, 0.992188f, 0.994141f, 0.996094f, 0.996582f, 0.997070f, 0.998047f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 1.000000f, 1.000000f, 1.000000f, 0.999512f, 0.001582f, 0.014984f, 0.262451f, 0.930664f, 0.979980f, 0.989258f, 0.993164f, 0.995117f,
+ 0.996094f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.999512f, 0.000244f, 0.002317f, 0.009003f, 0.047180f,
+ 0.524902f, 0.936523f, 0.978027f, 0.988281f, 0.992188f, 0.994629f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 1.000000f,
+ 0.000122f, 0.001098f, 0.002560f, 0.006824f, 0.020493f, 0.108826f, 0.715820f, 0.946289f, 0.978516f, 0.988281f, 0.992188f, 0.994141f,
+ 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000607f, 0.001098f, 0.002310f, 0.005646f, 0.012825f, 0.040131f, 0.231201f,
+ 0.825195f, 0.954590f, 0.979980f, 0.988281f, 0.992188f, 0.994141f, 0.995117f, 0.996582f, 0.996582f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000244f, 0.000609f, 0.001341f,
+ 0.002310f, 0.004208f, 0.008865f, 0.021591f, 0.074585f, 0.439209f, 0.885742f, 0.962402f, 0.981934f, 0.989258f, 0.992676f, 0.994141f,
+ 0.995605f, 0.996582f, 0.997070f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.999512f,
+ 0.000000f, 0.000122f, 0.000483f, 0.000610f, 0.001460f, 0.002192f, 0.003994f, 0.007030f, 0.013847f, 0.036316f, 0.146362f, 0.661621f,
+ 0.921875f, 0.969238f, 0.983398f, 0.989746f, 0.993164f, 0.994141f, 0.995605f, 0.996582f, 0.996582f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000243f, 0.000604f, 0.000730f, 0.001307f, 0.001944f, 0.003017f,
+ 0.004997f, 0.009834f, 0.021606f, 0.063416f, 0.295410f, 0.808594f, 0.944336f, 0.974609f, 0.985352f, 0.990234f, 0.993652f, 0.995117f,
+ 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 1.000000f, 0.000000f, 0.000000f, 0.000119f, 0.000366f,
+ 0.000495f, 0.000731f, 0.001217f, 0.001823f, 0.002796f, 0.004398f, 0.007656f, 0.015366f, 0.035828f, 0.119263f, 0.531738f, 0.886230f,
+ 0.958496f, 0.979004f, 0.986816f, 0.991699f, 0.993652f, 0.995117f, 0.996094f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000244f, 0.000366f, 0.000607f, 0.000731f, 0.001211f, 0.001650f, 0.002441f, 0.003975f, 0.006207f,
+ 0.011536f, 0.023315f, 0.060822f, 0.242798f, 0.744141f, 0.927734f, 0.969238f, 0.982422f, 0.989258f, 0.992188f, 0.994141f, 0.995605f,
+ 0.996094f, 0.996582f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000211f, 0.000455f, 0.000486f, 0.000853f,
+ 0.001081f, 0.001810f, 0.002426f, 0.003759f, 0.005501f, 0.009094f, 0.016876f, 0.037109f, 0.114075f, 0.475586f, 0.862305f, 0.951172f,
+ 0.975586f, 0.985840f, 0.990234f, 0.992676f, 0.995117f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000364f, 0.000366f, 0.000464f, 0.000731f, 0.001093f, 0.001577f, 0.002235f, 0.002798f, 0.004841f, 0.007637f, 0.013008f,
+ 0.025635f, 0.063965f, 0.238403f, 0.720215f, 0.919434f, 0.965820f, 0.981445f, 0.987793f, 0.991211f, 0.993652f, 0.995117f, 0.996094f,
+ 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000238f, 0.000609f, 0.000712f, 0.000974f, 0.000976f, 0.001507f,
+ 0.002031f, 0.002680f, 0.004066f, 0.006294f, 0.010284f, 0.018326f, 0.040924f, 0.124146f, 0.485596f, 0.859375f, 0.949707f, 0.975586f,
+ 0.984375f, 0.989746f, 0.992676f, 0.994629f, 0.995605f, 0.996582f, 0.997070f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000113f, 0.000487f,
+ 0.000488f, 0.000610f, 0.000961f, 0.000976f, 0.001337f, 0.001705f, 0.002663f, 0.003521f, 0.005417f, 0.008408f, 0.014809f, 0.028793f,
+ 0.073120f, 0.270996f, 0.741699f, 0.922363f, 0.965332f, 0.980957f, 0.987793f, 0.991699f, 0.993652f, 0.995117f, 0.996094f, 0.997070f,
+ 0.997070f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000244f, 0.000224f, 0.000486f, 0.000609f, 0.000610f, 0.000973f, 0.000975f, 0.001306f, 0.001703f, 0.002350f,
+ 0.003239f, 0.004848f, 0.007122f, 0.011955f, 0.021820f, 0.048859f, 0.152710f, 0.554199f, 0.875977f, 0.953125f, 0.976562f, 0.985352f,
+ 0.990234f, 0.993164f, 0.994629f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000234f, 0.000244f, 0.000485f, 0.000488f, 0.000610f,
+ 0.000969f, 0.000975f, 0.001335f, 0.001693f, 0.001991f, 0.002811f, 0.004097f, 0.006397f, 0.009903f, 0.017303f, 0.035034f, 0.094421f,
+ 0.354736f, 0.795898f, 0.933594f, 0.969238f, 0.981934f, 0.988281f, 0.991699f, 0.993652f, 0.995117f, 0.996094f, 0.997070f, 0.997559f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000244f, 0.000244f, 0.000480f, 0.000608f, 0.000488f, 0.000922f, 0.000975f, 0.000976f, 0.001339f, 0.001827f, 0.002674f, 0.003891f,
+ 0.005688f, 0.008324f, 0.014320f, 0.026917f, 0.064392f, 0.216431f, 0.668945f, 0.904785f, 0.959961f, 0.978516f, 0.986816f, 0.990723f,
+ 0.993652f, 0.994141f, 0.996094f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 1.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000188f, 0.000220f, 0.000480f, 0.000608f, 0.000609f, 0.000876f, 0.000975f,
+ 0.000976f, 0.001454f, 0.002068f, 0.002649f, 0.003481f, 0.004757f, 0.007801f, 0.012230f, 0.021698f, 0.046814f, 0.138306f, 0.506348f,
+ 0.859375f, 0.947754f, 0.974121f, 0.984375f, 0.989746f, 0.992188f, 0.994141f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000244f,
+ 0.000446f, 0.000487f, 0.000609f, 0.000731f, 0.000973f, 0.000975f, 0.001310f, 0.001823f, 0.002304f, 0.002869f, 0.004890f, 0.006813f,
+ 0.010475f, 0.017731f, 0.036163f, 0.095337f, 0.353516f, 0.792480f, 0.932129f, 0.968262f, 0.982422f, 0.988770f, 0.992188f, 0.993652f,
+ 0.995605f, 0.996094f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000241f, 0.000362f, 0.000487f, 0.000609f, 0.000609f, 0.000973f, 0.001213f, 0.001419f,
+ 0.001807f, 0.002068f, 0.002794f, 0.004070f, 0.005917f, 0.009140f, 0.015129f, 0.029053f, 0.070068f, 0.242554f, 0.700684f, 0.911621f,
+ 0.961914f, 0.979492f, 0.987305f, 0.991211f, 0.993164f, 0.995117f, 0.995605f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000243f, 0.000483f, 0.000603f,
+ 0.000609f, 0.000730f, 0.001076f, 0.000975f, 0.001327f, 0.001598f, 0.002056f, 0.002848f, 0.003519f, 0.005589f, 0.008041f, 0.013321f,
+ 0.024155f, 0.054718f, 0.171875f, 0.590332f, 0.885742f, 0.955566f, 0.977051f, 0.985840f, 0.990723f, 0.993164f, 0.994629f, 0.995605f,
+ 0.997070f, 0.997070f, 0.997559f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000192f, 0.000122f, 0.000244f, 0.000483f, 0.000606f, 0.000608f, 0.000731f, 0.000953f, 0.001095f, 0.001258f, 0.001575f, 0.002066f,
+ 0.002594f, 0.003857f, 0.004734f, 0.007683f, 0.011642f, 0.021179f, 0.044464f, 0.127930f, 0.476807f, 0.850586f, 0.947266f, 0.974121f,
+ 0.984375f, 0.989746f, 0.992676f, 0.994141f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000229f, 0.000239f, 0.000244f, 0.000343f, 0.000483f, 0.000608f, 0.000609f,
+ 0.000857f, 0.000973f, 0.001097f, 0.001571f, 0.002041f, 0.002399f, 0.002922f, 0.004471f, 0.006836f, 0.010643f, 0.018661f, 0.037354f,
+ 0.100037f, 0.378418f, 0.810547f, 0.937988f, 0.971191f, 0.983887f, 0.989258f, 0.992188f, 0.994141f, 0.995605f, 0.996582f, 0.997070f,
+ 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000161f,
+ 0.000230f, 0.000244f, 0.000486f, 0.000607f, 0.000609f, 0.000819f, 0.000972f, 0.000975f, 0.001431f, 0.001945f, 0.002283f, 0.003031f,
+ 0.004238f, 0.006424f, 0.009995f, 0.016068f, 0.032104f, 0.081360f, 0.302246f, 0.765625f, 0.928223f, 0.968750f, 0.982422f, 0.988770f,
+ 0.992676f, 0.994629f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000240f, 0.000240f, 0.000244f, 0.000450f, 0.000607f, 0.000609f, 0.000731f, 0.001084f,
+ 0.000974f, 0.001341f, 0.001910f, 0.002254f, 0.003216f, 0.004017f, 0.005692f, 0.008980f, 0.014832f, 0.028854f, 0.069641f, 0.248657f,
+ 0.719238f, 0.918945f, 0.965820f, 0.981445f, 0.988770f, 0.992188f, 0.994629f, 0.995605f, 0.996094f, 0.997070f, 0.997559f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000360f,
+ 0.000461f, 0.000607f, 0.000608f, 0.000731f, 0.001086f, 0.001202f, 0.001307f, 0.001592f, 0.002066f, 0.003134f, 0.003990f, 0.005611f,
+ 0.008133f, 0.013680f, 0.025986f, 0.061462f, 0.211670f, 0.676758f, 0.910156f, 0.963867f, 0.980957f, 0.988281f, 0.991699f, 0.994629f,
+ 0.995605f, 0.996582f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000240f, 0.000243f, 0.000482f, 0.000604f, 0.000608f, 0.000730f, 0.001040f, 0.001188f, 0.001287f,
+ 0.001574f, 0.002064f, 0.002613f, 0.003721f, 0.005428f, 0.008018f, 0.013161f, 0.024200f, 0.055573f, 0.186401f, 0.642578f, 0.904785f,
+ 0.962402f, 0.980469f, 0.987793f, 0.991699f, 0.994141f, 0.995605f, 0.996582f, 0.997070f, 0.998047f, 0.998535f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000480f, 0.000602f,
+ 0.000721f, 0.000705f, 0.000907f, 0.001094f, 0.001096f, 0.001493f, 0.002058f, 0.002607f, 0.003639f, 0.004826f, 0.007595f, 0.012413f,
+ 0.022171f, 0.051697f, 0.171143f, 0.619629f, 0.899414f, 0.961426f, 0.980957f, 0.987793f, 0.992188f, 0.994629f, 0.995605f, 0.996582f,
+ 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000172f, 0.000232f, 0.000243f, 0.000244f, 0.000576f, 0.000711f, 0.000608f, 0.000767f, 0.001089f, 0.001213f, 0.001509f, 0.002029f,
+ 0.002684f, 0.003550f, 0.005161f, 0.007107f, 0.011871f, 0.021545f, 0.049347f, 0.163086f, 0.609863f, 0.900391f, 0.962891f, 0.980957f,
+ 0.988281f, 0.992676f, 0.994629f, 0.996094f, 0.996582f, 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000210f, 0.000122f, 0.000337f, 0.000290f, 0.000594f, 0.000726f, 0.000730f,
+ 0.000731f, 0.001090f, 0.001212f, 0.001506f, 0.002029f, 0.002335f, 0.003489f, 0.005077f, 0.007000f, 0.011398f, 0.021027f, 0.048218f,
+ 0.161133f, 0.614258f, 0.903809f, 0.963379f, 0.981934f, 0.988770f, 0.992188f, 0.994629f, 0.996094f, 0.997070f, 0.997559f, 0.998047f,
+ 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000281f, 0.000440f, 0.000683f, 0.000726f, 0.000730f, 0.000731f, 0.001087f, 0.001095f, 0.001485f, 0.001793f, 0.002214f, 0.002991f,
+ 0.004951f, 0.006912f, 0.011162f, 0.020905f, 0.048187f, 0.165527f, 0.633789f, 0.910156f, 0.965820f, 0.982422f, 0.989746f, 0.993164f,
+ 0.995117f, 0.996094f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000241f, 0.000243f, 0.000480f, 0.000725f, 0.000697f, 0.000731f, 0.001007f,
+ 0.001094f, 0.001360f, 0.001795f, 0.002161f, 0.003244f, 0.004871f, 0.006966f, 0.011330f, 0.020706f, 0.049591f, 0.178345f, 0.667969f,
+ 0.918457f, 0.968262f, 0.983887f, 0.990234f, 0.993652f, 0.995605f, 0.996582f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000086f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000243f,
+ 0.000465f, 0.000592f, 0.000729f, 0.000730f, 0.001079f, 0.001093f, 0.001332f, 0.001885f, 0.002129f, 0.003254f, 0.004818f, 0.006889f,
+ 0.011429f, 0.021957f, 0.052521f, 0.201294f, 0.714355f, 0.929199f, 0.972168f, 0.985352f, 0.991211f, 0.994141f, 0.995605f, 0.997070f,
+ 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000115f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000184f, 0.000241f, 0.000347f, 0.000453f, 0.000579f, 0.000728f, 0.000729f, 0.001034f, 0.001093f, 0.001292f,
+ 0.001857f, 0.002131f, 0.003296f, 0.004826f, 0.006958f, 0.011726f, 0.023071f, 0.057983f, 0.239258f, 0.767578f, 0.939453f, 0.976074f,
+ 0.987305f, 0.992676f, 0.994629f, 0.996094f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000088f, 0.000119f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000191f, 0.000242f, 0.000425f, 0.000558f,
+ 0.000723f, 0.000730f, 0.001058f, 0.001092f, 0.001297f, 0.001653f, 0.002352f, 0.003124f, 0.004860f, 0.007072f, 0.012131f, 0.024551f,
+ 0.066406f, 0.300537f, 0.820312f, 0.951172f, 0.979492f, 0.988281f, 0.993164f, 0.995117f, 0.996582f, 0.997070f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000119f,
+ 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000227f, 0.000239f, 0.000341f, 0.000359f, 0.000587f, 0.000605f, 0.000729f, 0.001040f, 0.001185f, 0.001275f, 0.001849f, 0.002390f,
+ 0.003399f, 0.005001f, 0.007404f, 0.012871f, 0.027237f, 0.079529f, 0.395264f, 0.868164f, 0.960938f, 0.982910f, 0.990234f, 0.993164f,
+ 0.995605f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000119f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000211f, 0.000239f, 0.000307f, 0.000394f, 0.000704f, 0.000711f, 0.000728f,
+ 0.001001f, 0.001088f, 0.001204f, 0.001713f, 0.002367f, 0.003151f, 0.004639f, 0.007820f, 0.014084f, 0.030609f, 0.102722f, 0.527344f,
+ 0.906250f, 0.969727f, 0.985840f, 0.991699f, 0.994629f, 0.996094f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000117f, 0.000115f, 0.000121f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000196f,
+ 0.000332f, 0.000363f, 0.000686f, 0.000719f, 0.000723f, 0.000963f, 0.001089f, 0.001290f, 0.001849f, 0.002394f, 0.003458f, 0.004833f,
+ 0.008301f, 0.015579f, 0.036926f, 0.143188f, 0.676270f, 0.934570f, 0.976562f, 0.988281f, 0.992676f, 0.995605f, 0.996582f, 0.998047f,
+ 0.998047f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000102f, 0.000120f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000311f, 0.000345f, 0.000479f, 0.000723f, 0.000728f, 0.000934f, 0.001085f,
+ 0.001282f, 0.001821f, 0.002399f, 0.003355f, 0.005524f, 0.008881f, 0.017807f, 0.047058f, 0.222046f, 0.803223f, 0.954102f, 0.981445f,
+ 0.990723f, 0.994141f, 0.996582f, 0.997559f, 0.998047f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000090f, 0.000116f, 0.000121f, 0.000121f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000201f, 0.000239f, 0.000358f,
+ 0.000618f, 0.000719f, 0.000727f, 0.000863f, 0.001087f, 0.001350f, 0.001945f, 0.002689f, 0.003731f, 0.005817f, 0.010033f, 0.021332f,
+ 0.064514f, 0.374512f, 0.885254f, 0.969238f, 0.986328f, 0.992676f, 0.995605f, 0.996582f, 0.998047f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000086f, 0.000117f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000164f, 0.000238f, 0.000353f, 0.000596f, 0.000591f, 0.000727f, 0.000901f, 0.001085f, 0.001266f, 0.001767f,
+ 0.002663f, 0.003914f, 0.006153f, 0.011612f, 0.026871f, 0.100525f, 0.605957f, 0.934082f, 0.978027f, 0.989746f, 0.994141f, 0.996094f,
+ 0.997559f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999023f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000107f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000195f, 0.000323f, 0.000339f, 0.000461f, 0.000706f,
+ 0.000726f, 0.000845f, 0.001086f, 0.001298f, 0.001843f, 0.003027f, 0.004387f, 0.007011f, 0.013832f, 0.036530f, 0.183228f, 0.805664f,
+ 0.959961f, 0.984863f, 0.991699f, 0.995605f, 0.997070f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000117f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000224f, 0.000336f, 0.000464f, 0.000708f, 0.000726f, 0.000965f, 0.001083f, 0.001458f, 0.002180f, 0.003096f, 0.004425f,
+ 0.008377f, 0.017639f, 0.056610f, 0.390869f, 0.909180f, 0.975586f, 0.989746f, 0.994141f, 0.996582f, 0.998047f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000110f, 0.000113f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000135f, 0.000336f, 0.000467f, 0.000713f, 0.000725f, 0.000959f,
+ 0.001191f, 0.001287f, 0.001939f, 0.003231f, 0.005306f, 0.009888f, 0.024414f, 0.105835f, 0.709961f, 0.955078f, 0.984863f, 0.993164f,
+ 0.996094f, 0.997559f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000061f, 0.000089f,
+ 0.000118f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000309f,
+ 0.000299f, 0.000460f, 0.000710f, 0.000724f, 0.000997f, 0.001073f, 0.001410f, 0.002117f, 0.003506f, 0.006031f, 0.012863f, 0.038391f,
+ 0.260742f, 0.892090f, 0.975098f, 0.990723f, 0.995117f, 0.997559f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000085f, 0.000110f, 0.000118f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000317f, 0.000499f, 0.000706f, 0.000599f, 0.000851f, 0.001069f, 0.001633f,
+ 0.002367f, 0.003918f, 0.007580f, 0.017929f, 0.074646f, 0.645508f, 0.956055f, 0.986328f, 0.994141f, 0.996582f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000099f, 0.000113f,
+ 0.000119f, 0.000119f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000160f, 0.000326f, 0.000308f,
+ 0.000578f, 0.000602f, 0.000921f, 0.001071f, 0.001807f, 0.002783f, 0.004620f, 0.010017f, 0.029465f, 0.211792f, 0.896484f, 0.979004f,
+ 0.992188f, 0.996094f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000027f, 0.000103f, 0.000114f, 0.000118f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000090f, 0.000212f, 0.000309f, 0.000586f, 0.000602f, 0.000937f, 0.001147f, 0.002031f, 0.003237f, 0.006134f,
+ 0.014969f, 0.063171f, 0.665527f, 0.964355f, 0.989258f, 0.995117f, 0.999023f, 0.998535f, 0.999023f, 0.999023f, 0.998535f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000018f, 0.000103f, 0.000113f,
+ 0.000117f, 0.000119f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000004f, 0.000002f, 0.000199f, 0.000390f, 0.000586f, 0.000665f,
+ 0.000946f, 0.001365f, 0.002207f, 0.003767f, 0.008308f, 0.025955f, 0.227661f, 0.924316f, 0.984863f, 0.994141f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000098f, 0.000109f, 0.000117f, 0.000119f, 0.000120f, 0.000120f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000011f, 0.000005f, 0.000003f,
+ 0.000002f, 0.000193f, 0.000388f, 0.000586f, 0.000659f, 0.000952f, 0.001580f, 0.002762f, 0.005363f, 0.013153f, 0.066589f, 0.781738f,
+ 0.977051f, 0.993164f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000075f, 0.000112f,
+ 0.000116f, 0.000118f, 0.000119f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000122f,
+ 0.000088f, 0.000026f, 0.000010f, 0.000005f, 0.000003f, 0.000002f, 0.000186f, 0.000407f, 0.000586f, 0.000760f, 0.000986f, 0.001796f,
+ 0.003275f, 0.007565f, 0.026794f, 0.363281f, 0.959473f, 0.990723f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000010f, 0.000090f, 0.000110f, 0.000115f, 0.000117f, 0.000119f, 0.000120f, 0.000120f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000077f, 0.000023f, 0.000011f, 0.000005f, 0.000003f, 0.000002f, 0.000158f,
+ 0.000407f, 0.000587f, 0.000826f, 0.001264f, 0.002174f, 0.004894f, 0.013359f, 0.098511f, 0.911133f, 0.987793f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000084f, 0.000107f,
+ 0.000114f, 0.000117f, 0.000119f, 0.000119f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000093f, 0.000024f,
+ 0.000011f, 0.000005f, 0.000003f, 0.000002f, 0.000220f, 0.000476f, 0.000585f, 0.000913f, 0.001374f, 0.002951f, 0.007511f, 0.034973f,
+ 0.736328f, 0.982910f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000056f, 0.000102f, 0.000112f, 0.000116f, 0.000117f, 0.000119f, 0.000120f, 0.000120f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000075f, 0.000025f, 0.000010f, 0.000005f, 0.000003f, 0.000034f, 0.000222f, 0.000491f, 0.000589f,
+ 0.001020f, 0.001881f, 0.004669f, 0.015717f, 0.298340f, 0.974609f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000048f, 0.000095f,
+ 0.000106f, 0.000114f, 0.000117f, 0.000118f, 0.000119f, 0.000120f, 0.000120f, 0.000121f, 0.000089f, 0.000029f, 0.000012f, 0.000006f,
+ 0.000003f, 0.000002f, 0.000223f, 0.000525f, 0.000687f, 0.001122f, 0.002672f, 0.008255f, 0.079590f, 0.954590f, 0.996582f, 0.996582f,
+ 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000077f, 0.000104f, 0.000112f, 0.000115f, 0.000117f, 0.000119f, 0.000119f,
+ 0.000120f, 0.000109f, 0.000031f, 0.000013f, 0.000006f, 0.000003f, 0.000002f, 0.000254f, 0.000550f, 0.000846f, 0.001545f, 0.004223f,
+ 0.027771f, 0.901855f, 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000037f,
+ 0.000090f, 0.000107f, 0.000113f, 0.000116f, 0.000118f, 0.000119f, 0.000120f, 0.000041f, 0.000015f, 0.000007f, 0.000004f, 0.000002f,
+ 0.000271f, 0.000563f, 0.000786f, 0.002211f, 0.012207f, 0.711426f, 0.994629f, 0.994629f, 0.995117f, 0.994629f, 0.994629f, 0.994629f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000028f, 0.000083f, 0.000102f, 0.000110f, 0.000114f, 0.000117f, 0.000118f,
+ 0.000052f, 0.000019f, 0.000008f, 0.000004f, 0.000002f, 0.000314f, 0.000444f, 0.001049f, 0.005669f, 0.266846f, 0.993164f, 0.993652f,
+ 0.993164f, 0.993652f, 0.993164f, 0.993164f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000048f, 0.000089f, 0.000106f, 0.000112f, 0.000115f, 0.000077f, 0.000026f, 0.000010f, 0.000005f, 0.000079f, 0.000425f, 0.000405f,
+ 0.002468f, 0.064209f, 0.990234f, 0.990723f, 0.990234f, 0.990234f, 0.990234f, 0.991211f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000020f, 0.000075f, 0.000098f, 0.000108f, 0.000113f, 0.000044f,
+ 0.000016f, 0.000006f, 0.000027f, 0.000270f, 0.000825f, 0.018448f, 0.986328f, 0.986328f, 0.986328f, 0.986328f, 0.986328f, 0.986328f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000049f, 0.000085f, 0.000102f, 0.000070f, 0.000022f, 0.000008f, 0.000133f, 0.000295f, 0.005318f, 0.978516f, 0.979004f,
+ 0.977539f, 0.977539f, 0.978027f, 0.978516f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000066f, 0.000092f, 0.000036f, 0.000011f,
+ 0.000135f, 0.000925f, 0.959473f, 0.959961f, 0.959961f, 0.959473f, 0.959961f, 0.959473f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000027f, 0.000065f, 0.000016f, 0.000109f, 0.907715f, 0.907227f, 0.907715f, 0.907227f, 0.907715f, 0.907715f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000017f, 0.711914f, 0.712402f,
+ 0.711426f, 0.711426f, 0.711914f, 0.712402f,
+ },
+ {
+ 0.076172f, 0.877441f, 0.964355f, 0.980957f, 0.987305f, 0.990723f, 0.992676f, 0.993652f, 0.994629f, 0.995605f, 0.996094f, 0.996582f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.003897f, 0.033173f, 0.320557f, 0.863770f, 0.953613f, 0.975586f, 0.984863f, 0.988770f,
+ 0.991211f, 0.992676f, 0.994141f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997559f, 0.997559f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000975f, 0.005951f, 0.020935f, 0.093140f,
+ 0.501465f, 0.873047f, 0.950684f, 0.973145f, 0.981934f, 0.986816f, 0.990234f, 0.992188f, 0.993164f, 0.994629f, 0.995605f, 0.996094f,
+ 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998047f, 0.998535f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000610f, 0.002430f, 0.006081f, 0.015915f, 0.045593f, 0.179810f, 0.635254f, 0.889648f, 0.951172f, 0.972168f, 0.981445f, 0.986328f,
+ 0.989746f, 0.991699f, 0.993652f, 0.994629f, 0.995117f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.997559f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000244f, 0.001219f, 0.002796f, 0.006172f, 0.012848f, 0.028458f, 0.081177f, 0.301758f,
+ 0.733398f, 0.905273f, 0.953613f, 0.972168f, 0.981445f, 0.986328f, 0.989258f, 0.991699f, 0.993652f, 0.994141f, 0.995117f, 0.996094f,
+ 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000244f, 0.000731f, 0.001706f, 0.003166f,
+ 0.005470f, 0.010406f, 0.020813f, 0.047089f, 0.136719f, 0.449951f, 0.803223f, 0.919434f, 0.957520f, 0.973633f, 0.981934f, 0.986328f,
+ 0.989746f, 0.991699f, 0.993164f, 0.994629f, 0.995117f, 0.995605f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000244f, 0.000366f, 0.001214f, 0.001894f, 0.003159f, 0.005108f, 0.008720f, 0.015839f, 0.031586f, 0.074951f, 0.224121f, 0.596680f,
+ 0.851074f, 0.932617f, 0.962402f, 0.975586f, 0.982910f, 0.987305f, 0.989746f, 0.991699f, 0.993164f, 0.994141f, 0.995117f, 0.995605f,
+ 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000366f, 0.000731f, 0.000976f, 0.001827f, 0.002987f, 0.004757f, 0.007988f,
+ 0.013023f, 0.023544f, 0.048431f, 0.120239f, 0.352783f, 0.717285f, 0.887207f, 0.943848f, 0.966309f, 0.978027f, 0.983887f, 0.987305f,
+ 0.990234f, 0.992188f, 0.993652f, 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000434f, 0.000488f, 0.000704f,
+ 0.001218f, 0.002190f, 0.002783f, 0.004723f, 0.006878f, 0.011040f, 0.018372f, 0.034241f, 0.073242f, 0.194336f, 0.510742f, 0.803711f,
+ 0.912598f, 0.952637f, 0.970703f, 0.979004f, 0.984863f, 0.988281f, 0.991211f, 0.992676f, 0.994141f, 0.994629f, 0.995605f, 0.996094f,
+ 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000243f, 0.000488f, 0.000488f, 0.000916f, 0.001219f, 0.002308f, 0.002914f, 0.004124f, 0.006523f, 0.009537f, 0.014793f,
+ 0.025833f, 0.050446f, 0.116089f, 0.312744f, 0.661133f, 0.860840f, 0.931641f, 0.960449f, 0.974121f, 0.981445f, 0.986328f, 0.989258f,
+ 0.991211f, 0.992676f, 0.994141f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000121f, 0.000356f, 0.000488f, 0.000609f, 0.000944f, 0.001339f, 0.002296f,
+ 0.002964f, 0.003880f, 0.005676f, 0.008476f, 0.012909f, 0.020874f, 0.036926f, 0.075500f, 0.187988f, 0.474854f, 0.774414f, 0.900391f,
+ 0.946289f, 0.966309f, 0.978027f, 0.983887f, 0.987793f, 0.990234f, 0.991699f, 0.993164f, 0.994141f, 0.995117f, 0.995605f, 0.996094f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000244f, 0.000483f,
+ 0.000488f, 0.000731f, 0.001070f, 0.001551f, 0.002024f, 0.002520f, 0.003990f, 0.004738f, 0.007584f, 0.010834f, 0.016800f, 0.028763f,
+ 0.054535f, 0.120728f, 0.309082f, 0.642090f, 0.848145f, 0.926270f, 0.957031f, 0.971191f, 0.980469f, 0.985352f, 0.988770f, 0.990723f,
+ 0.992188f, 0.993652f, 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000242f, 0.000485f, 0.000608f, 0.000731f, 0.001091f, 0.001339f, 0.001943f, 0.002602f, 0.003466f,
+ 0.004845f, 0.006649f, 0.009529f, 0.014824f, 0.023407f, 0.041351f, 0.083496f, 0.199951f, 0.482422f, 0.770996f, 0.896484f, 0.944336f,
+ 0.965332f, 0.976562f, 0.982910f, 0.986816f, 0.990234f, 0.991699f, 0.993164f, 0.994141f, 0.995117f, 0.995117f, 0.996094f, 0.996582f,
+ 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000121f, 0.000243f, 0.000243f, 0.000602f, 0.000609f, 0.000799f,
+ 0.001088f, 0.001459f, 0.001822f, 0.002432f, 0.003033f, 0.004375f, 0.006042f, 0.008560f, 0.012810f, 0.019791f, 0.032715f, 0.061584f,
+ 0.135254f, 0.335693f, 0.660156f, 0.853027f, 0.926758f, 0.956543f, 0.972168f, 0.980469f, 0.984863f, 0.988281f, 0.991211f, 0.992676f,
+ 0.993652f, 0.994141f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000119f,
+ 0.000243f, 0.000366f, 0.000605f, 0.000730f, 0.000731f, 0.001201f, 0.001458f, 0.001804f, 0.002428f, 0.003593f, 0.004234f, 0.005745f,
+ 0.007755f, 0.011139f, 0.016754f, 0.027054f, 0.047424f, 0.097107f, 0.231323f, 0.525879f, 0.791016f, 0.902832f, 0.945801f, 0.966797f,
+ 0.977051f, 0.982910f, 0.987793f, 0.990234f, 0.991699f, 0.993164f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f,
+ 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000116f, 0.000122f, 0.000365f, 0.000244f, 0.000602f, 0.000721f, 0.000730f, 0.000852f, 0.001451f,
+ 0.001842f, 0.002518f, 0.002993f, 0.004097f, 0.005253f, 0.007099f, 0.009865f, 0.014908f, 0.022827f, 0.038879f, 0.072815f, 0.163940f,
+ 0.396484f, 0.707031f, 0.869141f, 0.932129f, 0.960449f, 0.973145f, 0.980957f, 0.986328f, 0.988770f, 0.991211f, 0.992676f, 0.993652f,
+ 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000110f, 0.000361f, 0.000242f, 0.000244f,
+ 0.000602f, 0.000728f, 0.000853f, 0.001260f, 0.001569f, 0.001704f, 0.002287f, 0.003103f, 0.003857f, 0.004848f, 0.006680f, 0.009003f,
+ 0.012978f, 0.019897f, 0.032135f, 0.057983f, 0.121033f, 0.291504f, 0.604980f, 0.827148f, 0.915039f, 0.953125f, 0.969238f, 0.978516f,
+ 0.984375f, 0.988281f, 0.991211f, 0.992188f, 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.996582f, 0.996582f, 0.997070f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000241f, 0.000241f, 0.000365f, 0.000365f, 0.000589f, 0.000852f, 0.000852f, 0.001246f, 0.001562f, 0.001812f, 0.002241f,
+ 0.002794f, 0.003633f, 0.004669f, 0.006069f, 0.008202f, 0.011772f, 0.016891f, 0.027618f, 0.047089f, 0.093506f, 0.216309f, 0.495605f,
+ 0.771484f, 0.894531f, 0.942383f, 0.965332f, 0.976074f, 0.982910f, 0.987305f, 0.989746f, 0.991699f, 0.993164f, 0.994629f, 0.995117f,
+ 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000364f, 0.000242f, 0.000487f, 0.000737f, 0.000730f,
+ 0.000974f, 0.001083f, 0.001520f, 0.001701f, 0.001938f, 0.002768f, 0.003658f, 0.004227f, 0.005741f, 0.007671f, 0.010796f, 0.015511f,
+ 0.023529f, 0.040009f, 0.074158f, 0.165405f, 0.395264f, 0.703613f, 0.868164f, 0.932129f, 0.959473f, 0.973633f, 0.980957f, 0.985840f,
+ 0.988770f, 0.991699f, 0.992676f, 0.994141f, 0.995117f, 0.995117f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000100f, 0.000000f, 0.000241f,
+ 0.000224f, 0.000487f, 0.000488f, 0.000710f, 0.000972f, 0.000848f, 0.001181f, 0.001333f, 0.001910f, 0.001830f, 0.002661f, 0.003298f,
+ 0.004154f, 0.005386f, 0.007271f, 0.009735f, 0.013908f, 0.021149f, 0.034149f, 0.062042f, 0.130371f, 0.313477f, 0.627930f, 0.837402f,
+ 0.919922f, 0.954590f, 0.970215f, 0.979492f, 0.985352f, 0.988770f, 0.991211f, 0.992676f, 0.993652f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996582f, 0.996582f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000049f, 0.000242f, 0.000483f, 0.000606f, 0.000487f, 0.000695f, 0.000970f, 0.000974f, 0.001136f,
+ 0.001328f, 0.001694f, 0.002028f, 0.002617f, 0.002953f, 0.003847f, 0.004951f, 0.006653f, 0.009193f, 0.012672f, 0.018661f, 0.029968f,
+ 0.052673f, 0.106689f, 0.250977f, 0.549805f, 0.801758f, 0.907227f, 0.948242f, 0.967773f, 0.978027f, 0.984375f, 0.987793f, 0.990723f,
+ 0.992188f, 0.993652f, 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000166f, 0.000243f, 0.000485f, 0.000487f,
+ 0.000487f, 0.000945f, 0.000834f, 0.000974f, 0.000974f, 0.001300f, 0.001810f, 0.002058f, 0.002573f, 0.002703f, 0.003761f, 0.004887f,
+ 0.006393f, 0.008514f, 0.011818f, 0.016937f, 0.026672f, 0.046051f, 0.089478f, 0.204712f, 0.476807f, 0.762207f, 0.891602f, 0.942383f,
+ 0.965820f, 0.976562f, 0.983398f, 0.987793f, 0.990234f, 0.992188f, 0.993652f, 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.997070f,
+ 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000224f, 0.000358f, 0.000477f, 0.000486f, 0.000487f, 0.000580f, 0.000841f, 0.000973f, 0.001079f, 0.001255f, 0.001649f,
+ 0.002045f, 0.002241f, 0.002995f, 0.003841f, 0.004826f, 0.005920f, 0.007866f, 0.010925f, 0.015930f, 0.024109f, 0.040619f, 0.077454f,
+ 0.171509f, 0.412354f, 0.720215f, 0.876953f, 0.936035f, 0.962402f, 0.975098f, 0.982422f, 0.987305f, 0.990234f, 0.992188f, 0.993164f,
+ 0.994629f, 0.995117f, 0.996094f, 0.996582f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000165f, 0.000205f, 0.000411f, 0.000480f, 0.000486f, 0.000608f, 0.000688f,
+ 0.000966f, 0.000968f, 0.000974f, 0.001421f, 0.001489f, 0.001695f, 0.002090f, 0.002886f, 0.003326f, 0.004608f, 0.005604f, 0.007317f,
+ 0.010414f, 0.014862f, 0.022232f, 0.036469f, 0.067810f, 0.146973f, 0.359375f, 0.680664f, 0.861816f, 0.931152f, 0.959961f, 0.974609f,
+ 0.981934f, 0.986816f, 0.989746f, 0.991699f, 0.993652f, 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000242f,
+ 0.000453f, 0.000539f, 0.000486f, 0.000487f, 0.000487f, 0.000957f, 0.000969f, 0.001202f, 0.001139f, 0.001393f, 0.001986f, 0.002045f,
+ 0.002863f, 0.003216f, 0.004128f, 0.005417f, 0.007378f, 0.009689f, 0.013466f, 0.020432f, 0.033722f, 0.060883f, 0.129395f, 0.318115f,
+ 0.642090f, 0.847656f, 0.926270f, 0.958008f, 0.973145f, 0.981934f, 0.986328f, 0.989746f, 0.992188f, 0.993164f, 0.994629f, 0.995605f,
+ 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000380f, 0.000482f, 0.000606f, 0.000607f, 0.000608f, 0.000829f, 0.000970f,
+ 0.000972f, 0.001070f, 0.001402f, 0.001812f, 0.002138f, 0.002619f, 0.003246f, 0.004082f, 0.005318f, 0.006699f, 0.009262f, 0.012764f,
+ 0.019318f, 0.031052f, 0.055878f, 0.116821f, 0.286621f, 0.610352f, 0.835938f, 0.922852f, 0.956543f, 0.973145f, 0.981445f, 0.986328f,
+ 0.989746f, 0.991699f, 0.993652f, 0.995117f, 0.995605f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000243f, 0.000350f, 0.000480f,
+ 0.000605f, 0.000596f, 0.000608f, 0.000890f, 0.000963f, 0.000972f, 0.000974f, 0.001316f, 0.001798f, 0.002058f, 0.002560f, 0.002811f,
+ 0.003983f, 0.005108f, 0.006489f, 0.008888f, 0.012314f, 0.018021f, 0.029495f, 0.051941f, 0.107422f, 0.263428f, 0.585449f, 0.827148f,
+ 0.919434f, 0.956055f, 0.971680f, 0.981445f, 0.986816f, 0.989746f, 0.992188f, 0.994141f, 0.995117f, 0.995605f, 0.996582f, 0.996582f,
+ 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000130f, 0.000176f, 0.000462f, 0.000483f, 0.000604f, 0.000607f, 0.000638f, 0.000922f, 0.000965f, 0.000971f, 0.001235f,
+ 0.001376f, 0.001769f, 0.002041f, 0.002575f, 0.003130f, 0.003487f, 0.004936f, 0.006264f, 0.008415f, 0.012047f, 0.017517f, 0.027786f,
+ 0.049164f, 0.101257f, 0.249512f, 0.568848f, 0.821777f, 0.918945f, 0.956055f, 0.972168f, 0.981445f, 0.986816f, 0.990234f, 0.992188f,
+ 0.993652f, 0.995117f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000130f, 0.000122f, 0.000242f, 0.000352f, 0.000560f, 0.000602f, 0.000604f,
+ 0.000606f, 0.000767f, 0.001046f, 0.001089f, 0.000973f, 0.001327f, 0.001583f, 0.002033f, 0.002272f, 0.002657f, 0.003563f, 0.004589f,
+ 0.006138f, 0.008194f, 0.011299f, 0.016861f, 0.026718f, 0.047119f, 0.097656f, 0.240967f, 0.562500f, 0.821289f, 0.919922f, 0.957031f,
+ 0.973145f, 0.981934f, 0.987305f, 0.990234f, 0.992676f, 0.994141f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000241f, 0.000314f, 0.000459f, 0.000600f, 0.000605f, 0.000598f, 0.000804f, 0.000958f, 0.001084f, 0.001104f, 0.001389f, 0.001709f,
+ 0.002041f, 0.002211f, 0.002645f, 0.003635f, 0.004467f, 0.005718f, 0.008072f, 0.011185f, 0.016846f, 0.026184f, 0.046112f, 0.094971f,
+ 0.239014f, 0.565430f, 0.825684f, 0.922363f, 0.958496f, 0.973633f, 0.983398f, 0.987793f, 0.990723f, 0.992676f, 0.994141f, 0.995605f,
+ 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000238f, 0.000122f, 0.000173f, 0.000246f, 0.000387f, 0.000480f, 0.000604f, 0.000604f, 0.000701f,
+ 0.000951f, 0.000968f, 0.001184f, 0.001315f, 0.001597f, 0.001899f, 0.002268f, 0.002813f, 0.003716f, 0.004372f, 0.005886f, 0.007759f,
+ 0.010918f, 0.015915f, 0.025726f, 0.045685f, 0.095459f, 0.243774f, 0.579102f, 0.833984f, 0.926270f, 0.960449f, 0.976074f, 0.983887f,
+ 0.988770f, 0.991211f, 0.993164f, 0.994629f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999023f, 0.999512f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000238f, 0.000237f, 0.000242f,
+ 0.000463f, 0.000585f, 0.000587f, 0.000718f, 0.000607f, 0.000885f, 0.001081f, 0.001087f, 0.001299f, 0.001553f, 0.001982f, 0.002104f,
+ 0.002777f, 0.003494f, 0.004406f, 0.005798f, 0.007645f, 0.010750f, 0.016159f, 0.025467f, 0.045959f, 0.097778f, 0.256104f, 0.603516f,
+ 0.847168f, 0.931152f, 0.963379f, 0.977539f, 0.985352f, 0.989258f, 0.991699f, 0.993652f, 0.995117f, 0.996094f, 0.996582f, 0.997559f,
+ 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000231f, 0.000122f, 0.000242f, 0.000242f, 0.000400f, 0.000525f, 0.000495f, 0.000605f, 0.000607f, 0.000898f, 0.001075f,
+ 0.001191f, 0.001133f, 0.001420f, 0.001794f, 0.002041f, 0.002733f, 0.003548f, 0.004448f, 0.005585f, 0.007656f, 0.010735f, 0.015671f,
+ 0.025589f, 0.047363f, 0.102783f, 0.276855f, 0.637695f, 0.862793f, 0.938477f, 0.966797f, 0.979004f, 0.985840f, 0.990234f, 0.992676f,
+ 0.994141f, 0.995117f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000226f, 0.000242f, 0.000470f, 0.000469f,
+ 0.000547f, 0.000711f, 0.000723f, 0.000829f, 0.001024f, 0.001188f, 0.001081f, 0.001415f, 0.001765f, 0.002048f, 0.002708f, 0.003252f,
+ 0.004448f, 0.005711f, 0.007557f, 0.010780f, 0.016220f, 0.026398f, 0.048950f, 0.111267f, 0.309082f, 0.680664f, 0.880371f, 0.945801f,
+ 0.970703f, 0.980957f, 0.986816f, 0.990723f, 0.993164f, 0.994629f, 0.995605f, 0.996582f, 0.997559f, 0.998047f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000204f, 0.000239f, 0.000242f, 0.000283f, 0.000479f, 0.000594f, 0.000603f, 0.000606f, 0.000779f, 0.001068f, 0.001084f, 0.001118f,
+ 0.001515f, 0.001926f, 0.002098f, 0.002674f, 0.002975f, 0.004040f, 0.005478f, 0.007488f, 0.010651f, 0.016327f, 0.027222f, 0.052460f,
+ 0.123718f, 0.355713f, 0.729980f, 0.899902f, 0.952637f, 0.973145f, 0.983887f, 0.988770f, 0.991699f, 0.994141f, 0.995117f, 0.996094f,
+ 0.997070f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000122f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000236f, 0.000207f, 0.000240f, 0.000435f, 0.000534f, 0.000594f, 0.000602f,
+ 0.000722f, 0.000727f, 0.000947f, 0.001081f, 0.001090f, 0.001471f, 0.001829f, 0.002010f, 0.002478f, 0.002956f, 0.004051f, 0.005753f,
+ 0.007717f, 0.011040f, 0.017105f, 0.028748f, 0.057159f, 0.142944f, 0.421387f, 0.780762f, 0.916992f, 0.960449f, 0.976562f, 0.985352f,
+ 0.989746f, 0.992676f, 0.994629f, 0.996094f, 0.997070f, 0.997559f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000224f, 0.000232f,
+ 0.000230f, 0.000382f, 0.000472f, 0.000576f, 0.000715f, 0.000721f, 0.000727f, 0.001046f, 0.001078f, 0.001186f, 0.001434f, 0.001674f,
+ 0.002066f, 0.002546f, 0.003407f, 0.004181f, 0.005634f, 0.007542f, 0.011330f, 0.017609f, 0.031189f, 0.064392f, 0.172729f, 0.506836f,
+ 0.828125f, 0.933105f, 0.966309f, 0.980469f, 0.987305f, 0.991211f, 0.993652f, 0.995117f, 0.996582f, 0.997070f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000232f, 0.000234f, 0.000352f, 0.000461f, 0.000535f, 0.000594f, 0.000722f, 0.000725f,
+ 0.000921f, 0.001116f, 0.001192f, 0.001416f, 0.001637f, 0.001911f, 0.002380f, 0.002949f, 0.003948f, 0.005589f, 0.007942f, 0.011650f,
+ 0.018631f, 0.034302f, 0.075867f, 0.219238f, 0.607422f, 0.870605f, 0.946777f, 0.972656f, 0.983887f, 0.989258f, 0.992676f, 0.995117f,
+ 0.996094f, 0.997070f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000239f, 0.000302f,
+ 0.000396f, 0.000564f, 0.000674f, 0.000617f, 0.000722f, 0.001003f, 0.001068f, 0.001084f, 0.001302f, 0.001598f, 0.001929f, 0.002375f,
+ 0.002935f, 0.004349f, 0.005714f, 0.007957f, 0.012306f, 0.020493f, 0.039001f, 0.092590f, 0.293213f, 0.711426f, 0.905762f, 0.958984f,
+ 0.978027f, 0.986328f, 0.990723f, 0.994141f, 0.995605f, 0.996582f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000232f, 0.000227f, 0.000240f, 0.000282f, 0.000542f, 0.000703f, 0.000718f, 0.000724f, 0.000833f, 0.001069f,
+ 0.001184f, 0.001346f, 0.001464f, 0.001898f, 0.002649f, 0.003164f, 0.004467f, 0.005863f, 0.008400f, 0.013199f, 0.022614f, 0.046051f,
+ 0.120605f, 0.406738f, 0.801270f, 0.931641f, 0.968262f, 0.982422f, 0.988770f, 0.992676f, 0.994629f, 0.996094f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000120f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000219f, 0.000237f, 0.000235f, 0.000241f, 0.000480f,
+ 0.000584f, 0.000715f, 0.000723f, 0.000775f, 0.001061f, 0.000959f, 0.001139f, 0.001526f, 0.001770f, 0.002546f, 0.003151f, 0.004250f,
+ 0.006195f, 0.009071f, 0.014595f, 0.026413f, 0.056763f, 0.169067f, 0.557617f, 0.869141f, 0.951172f, 0.976074f, 0.986328f, 0.990723f,
+ 0.994141f, 0.995605f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000120f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000216f, 0.000228f, 0.000285f, 0.000339f, 0.000454f, 0.000572f, 0.000595f, 0.000721f, 0.000604f, 0.000930f, 0.000958f, 0.001171f,
+ 0.001431f, 0.001888f, 0.002663f, 0.003256f, 0.004402f, 0.006527f, 0.009964f, 0.016281f, 0.031189f, 0.074524f, 0.258301f, 0.714355f,
+ 0.916016f, 0.965332f, 0.982422f, 0.989746f, 0.992676f, 0.995117f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000000f, 0.000063f, 0.000120f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000194f, 0.000184f, 0.000228f, 0.000340f, 0.000396f, 0.000668f, 0.000571f,
+ 0.000478f, 0.000602f, 0.000919f, 0.000956f, 0.001061f, 0.001497f, 0.001888f, 0.002565f, 0.003523f, 0.004578f, 0.006935f, 0.010765f,
+ 0.018417f, 0.038635f, 0.107727f, 0.416260f, 0.832520f, 0.946289f, 0.975586f, 0.986328f, 0.991699f, 0.994629f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000045f, 0.000118f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000234f, 0.000294f, 0.000220f, 0.000486f, 0.000579f, 0.000588f, 0.000669f, 0.000878f, 0.001038f, 0.001135f, 0.001451f, 0.001820f,
+ 0.002529f, 0.003551f, 0.005199f, 0.007542f, 0.012230f, 0.022369f, 0.051910f, 0.174927f, 0.630859f, 0.905273f, 0.965332f, 0.982910f,
+ 0.990234f, 0.993652f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000091f,
+ 0.000117f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000171f, 0.000151f, 0.000166f, 0.000195f, 0.000342f, 0.000452f, 0.000594f, 0.000599f,
+ 0.000862f, 0.001019f, 0.001135f, 0.001465f, 0.002031f, 0.002676f, 0.003714f, 0.005497f, 0.008286f, 0.014320f, 0.028854f, 0.077332f,
+ 0.322754f, 0.809082f, 0.946289f, 0.977051f, 0.987793f, 0.993164f, 0.998047f, 0.998535f, 0.998047f, 0.998047f, 0.998535f, 0.998047f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000079f, 0.000105f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000008f, 0.000006f, 0.000098f, 0.000137f,
+ 0.000233f, 0.000324f, 0.000566f, 0.000589f, 0.000618f, 0.000874f, 0.000941f, 0.001108f, 0.001621f, 0.001880f, 0.002726f, 0.003788f,
+ 0.005840f, 0.009583f, 0.017563f, 0.039368f, 0.133545f, 0.582520f, 0.906738f, 0.968262f, 0.984863f, 0.992188f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000069f, 0.000114f,
+ 0.000117f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000021f,
+ 0.000013f, 0.000009f, 0.000006f, 0.000004f, 0.000090f, 0.000206f, 0.000305f, 0.000538f, 0.000585f, 0.000596f, 0.000869f, 0.000941f,
+ 0.001149f, 0.001516f, 0.002150f, 0.002729f, 0.004475f, 0.006660f, 0.011360f, 0.022690f, 0.061401f, 0.281494f, 0.813965f, 0.952148f,
+ 0.980957f, 0.990723f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000006f, 0.000085f, 0.000114f, 0.000117f, 0.000119f, 0.000119f, 0.000120f, 0.000120f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000122f, 0.000122f, 0.000077f, 0.000041f, 0.000022f, 0.000013f, 0.000009f, 0.000006f, 0.000066f, 0.000107f, 0.000223f, 0.000250f,
+ 0.000532f, 0.000576f, 0.000593f, 0.000784f, 0.000937f, 0.001126f, 0.001523f, 0.002306f, 0.003193f, 0.004574f, 0.007717f, 0.014191f,
+ 0.032410f, 0.116577f, 0.595215f, 0.921875f, 0.974609f, 0.988770f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000056f, 0.000112f,
+ 0.000114f, 0.000118f, 0.000119f, 0.000120f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000074f, 0.000038f, 0.000021f, 0.000013f, 0.000009f,
+ 0.000006f, 0.000004f, 0.000003f, 0.000179f, 0.000258f, 0.000367f, 0.000469f, 0.000583f, 0.000770f, 0.000932f, 0.001131f, 0.001758f,
+ 0.002483f, 0.003517f, 0.005432f, 0.009232f, 0.019302f, 0.054504f, 0.293457f, 0.853516f, 0.964844f, 0.986816f, 0.997070f, 0.997070f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000015f, 0.000084f, 0.000107f, 0.000113f, 0.000117f, 0.000118f, 0.000119f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000076f, 0.000042f, 0.000023f, 0.000015f, 0.000009f, 0.000007f, 0.000005f, 0.000004f, 0.000147f, 0.000238f, 0.000457f, 0.000545f,
+ 0.000586f, 0.000821f, 0.000936f, 0.001139f, 0.001849f, 0.002665f, 0.003687f, 0.006367f, 0.011810f, 0.028931f, 0.120605f, 0.687988f,
+ 0.947754f, 0.982910f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000082f, 0.000095f,
+ 0.000111f, 0.000115f, 0.000117f, 0.000118f, 0.000119f, 0.000119f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000083f, 0.000042f, 0.000026f, 0.000015f, 0.000010f, 0.000007f, 0.000005f,
+ 0.000013f, 0.000086f, 0.000185f, 0.000309f, 0.000552f, 0.000577f, 0.000796f, 0.000925f, 0.001251f, 0.001838f, 0.002878f, 0.004509f,
+ 0.007572f, 0.016617f, 0.054932f, 0.391602f, 0.912109f, 0.978516f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.996094f, 0.996094f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000095f, 0.000106f, 0.000112f, 0.000113f, 0.000115f, 0.000118f, 0.000118f,
+ 0.000119f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000099f, 0.000048f,
+ 0.000027f, 0.000017f, 0.000011f, 0.000008f, 0.000006f, 0.000004f, 0.000089f, 0.000182f, 0.000347f, 0.000495f, 0.000570f, 0.000777f,
+ 0.000922f, 0.001316f, 0.001831f, 0.003004f, 0.005028f, 0.010078f, 0.028183f, 0.161865f, 0.833496f, 0.972168f, 0.995117f, 0.995605f,
+ 0.995605f, 0.995117f, 0.995117f, 0.995605f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000074f,
+ 0.000093f, 0.000107f, 0.000111f, 0.000115f, 0.000116f, 0.000117f, 0.000118f, 0.000119f, 0.000119f, 0.000119f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000120f, 0.000120f, 0.000121f, 0.000057f, 0.000032f, 0.000021f, 0.000013f, 0.000008f, 0.000006f, 0.000005f, 0.000034f,
+ 0.000159f, 0.000267f, 0.000514f, 0.000566f, 0.000714f, 0.000888f, 0.001348f, 0.001995f, 0.003302f, 0.006447f, 0.015945f, 0.069153f,
+ 0.646484f, 0.960449f, 0.994629f, 0.995117f, 0.994629f, 0.995117f, 0.994629f, 0.995117f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000080f, 0.000095f, 0.000102f, 0.000109f, 0.000114f, 0.000115f,
+ 0.000116f, 0.000118f, 0.000118f, 0.000119f, 0.000119f, 0.000119f, 0.000120f, 0.000120f, 0.000120f, 0.000077f, 0.000044f, 0.000025f,
+ 0.000015f, 0.000011f, 0.000007f, 0.000005f, 0.000004f, 0.000106f, 0.000244f, 0.000476f, 0.000561f, 0.000622f, 0.000893f, 0.001266f,
+ 0.001968f, 0.003990f, 0.009476f, 0.033234f, 0.342529f, 0.940918f, 0.993652f, 0.993652f, 0.993652f, 0.993652f, 0.993652f, 0.993652f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000046f, 0.000079f, 0.000093f, 0.000104f, 0.000110f, 0.000111f, 0.000113f, 0.000116f, 0.000117f, 0.000118f, 0.000118f, 0.000119f,
+ 0.000119f, 0.000119f, 0.000092f, 0.000050f, 0.000029f, 0.000019f, 0.000012f, 0.000009f, 0.000006f, 0.000004f, 0.000061f, 0.000188f,
+ 0.000324f, 0.000456f, 0.000525f, 0.000657f, 0.001371f, 0.002445f, 0.005634f, 0.017563f, 0.135986f, 0.902832f, 0.992188f, 0.992188f,
+ 0.992676f, 0.992188f, 0.992676f, 0.992188f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000038f, 0.000075f, 0.000092f, 0.000100f, 0.000105f,
+ 0.000111f, 0.000112f, 0.000114f, 0.000116f, 0.000117f, 0.000117f, 0.000118f, 0.000118f, 0.000074f, 0.000041f, 0.000024f, 0.000016f,
+ 0.000010f, 0.000007f, 0.000005f, 0.000033f, 0.000167f, 0.000423f, 0.000410f, 0.000413f, 0.000575f, 0.001446f, 0.003387f, 0.009644f,
+ 0.056183f, 0.817383f, 0.990234f, 0.990234f, 0.990234f, 0.990723f, 0.990234f, 0.990723f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000011f, 0.000067f, 0.000084f, 0.000096f, 0.000103f, 0.000108f, 0.000110f, 0.000113f, 0.000115f, 0.000115f,
+ 0.000116f, 0.000104f, 0.000057f, 0.000035f, 0.000021f, 0.000013f, 0.000009f, 0.000006f, 0.000054f, 0.000161f, 0.000317f, 0.000332f,
+ 0.000393f, 0.000723f, 0.001760f, 0.005203f, 0.025345f, 0.617676f, 0.987793f, 0.987793f, 0.987793f, 0.988281f, 0.988281f, 0.988281f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000017f, 0.000052f, 0.000075f,
+ 0.000091f, 0.000097f, 0.000105f, 0.000108f, 0.000111f, 0.000113f, 0.000114f, 0.000085f, 0.000050f, 0.000031f, 0.000018f, 0.000012f,
+ 0.000008f, 0.000005f, 0.000095f, 0.000314f, 0.000306f, 0.000363f, 0.000813f, 0.002583f, 0.011734f, 0.308105f, 0.983887f, 0.984375f,
+ 0.984375f, 0.984375f, 0.983887f, 0.983887f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000037f, 0.000065f, 0.000083f, 0.000093f, 0.000099f, 0.000105f, 0.000108f,
+ 0.000110f, 0.000082f, 0.000045f, 0.000027f, 0.000017f, 0.000011f, 0.000007f, 0.000114f, 0.000245f, 0.000209f, 0.000379f, 0.001151f,
+ 0.005260f, 0.107971f, 0.977539f, 0.979004f, 0.978027f, 0.978027f, 0.978027f, 0.978027f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000007f, 0.000045f, 0.000069f, 0.000084f, 0.000093f, 0.000099f, 0.000104f, 0.000076f, 0.000044f, 0.000026f, 0.000016f, 0.000010f,
+ 0.000012f, 0.000152f, 0.000179f, 0.000373f, 0.001760f, 0.035522f, 0.969238f, 0.968750f, 0.968750f, 0.968750f, 0.968750f, 0.968750f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000014f, 0.000050f, 0.000070f, 0.000082f,
+ 0.000092f, 0.000075f, 0.000044f, 0.000026f, 0.000015f, 0.000009f, 0.000121f, 0.000117f, 0.000611f, 0.010231f, 0.951172f, 0.951172f,
+ 0.951172f, 0.951172f, 0.950684f, 0.951660f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000020f, 0.000047f, 0.000069f, 0.000077f, 0.000042f, 0.000024f, 0.000013f, 0.000078f,
+ 0.000130f, 0.001914f, 0.915039f, 0.915527f, 0.915039f, 0.915527f, 0.916016f, 0.915039f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000017f, 0.000047f, 0.000040f, 0.000019f, 0.000035f, 0.000188f, 0.833984f, 0.833496f, 0.833496f, 0.834473f, 0.834473f, 0.833984f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000014f, 0.000007f, 0.642578f, 0.643555f,
+ 0.643066f, 0.643555f, 0.642578f, 0.642578f,
+ },
+ {
+ 0.113464f, 0.797852f, 0.930176f, 0.961914f, 0.974609f, 0.980469f, 0.984863f, 0.987793f, 0.989258f, 0.991211f, 0.992188f, 0.993164f,
+ 0.993652f, 0.994141f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997559f,
+ 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.007183f, 0.058716f, 0.349609f, 0.784668f, 0.912598f, 0.952148f, 0.968262f, 0.977539f,
+ 0.981934f, 0.985352f, 0.988281f, 0.990234f, 0.991211f, 0.992188f, 0.993652f, 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.995605f,
+ 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.002432f, 0.011818f, 0.039581f, 0.143677f,
+ 0.482910f, 0.800293f, 0.908691f, 0.947266f, 0.964844f, 0.974609f, 0.980469f, 0.984375f, 0.987305f, 0.989258f, 0.990723f, 0.991699f,
+ 0.992676f, 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f,
+ 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.001096f, 0.005062f, 0.012482f, 0.030151f, 0.079956f, 0.239014f, 0.581055f, 0.819824f, 0.909180f, 0.946289f, 0.963379f, 0.973145f,
+ 0.979492f, 0.983398f, 0.986328f, 0.988281f, 0.990234f, 0.991699f, 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995605f, 0.996094f,
+ 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000610f, 0.002434f, 0.005779f, 0.012207f, 0.023972f, 0.052765f, 0.129883f, 0.342773f,
+ 0.660156f, 0.841309f, 0.914062f, 0.947266f, 0.963379f, 0.973145f, 0.979004f, 0.982910f, 0.985840f, 0.987793f, 0.989746f, 0.991211f,
+ 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f,
+ 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000397f, 0.001559f, 0.003397f, 0.006058f,
+ 0.011177f, 0.020355f, 0.039307f, 0.083130f, 0.196777f, 0.452148f, 0.724121f, 0.862305f, 0.920410f, 0.949219f, 0.964355f, 0.973145f,
+ 0.979004f, 0.982910f, 0.985840f, 0.988770f, 0.989258f, 0.991211f, 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995605f, 0.995605f,
+ 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000366f, 0.001097f, 0.002163f, 0.003523f, 0.006268f, 0.010941f, 0.017487f, 0.030930f, 0.058411f, 0.122925f, 0.281738f, 0.556152f,
+ 0.776367f, 0.881348f, 0.928223f, 0.951660f, 0.966309f, 0.973633f, 0.979492f, 0.983398f, 0.986328f, 0.988281f, 0.989746f, 0.991211f,
+ 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000244f, 0.000728f, 0.001340f, 0.002533f, 0.003813f, 0.006081f, 0.009750f, 0.015419f,
+ 0.025177f, 0.044067f, 0.084473f, 0.179077f, 0.384033f, 0.649902f, 0.818848f, 0.897949f, 0.935547f, 0.956055f, 0.967285f, 0.975098f,
+ 0.980957f, 0.983887f, 0.986328f, 0.988281f, 0.990234f, 0.991699f, 0.992676f, 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000244f, 0.000609f, 0.000854f, 0.001898f,
+ 0.002781f, 0.004246f, 0.006218f, 0.008835f, 0.013504f, 0.021362f, 0.035400f, 0.062347f, 0.121460f, 0.255127f, 0.495361f, 0.726562f,
+ 0.852539f, 0.912598f, 0.943359f, 0.959473f, 0.969238f, 0.976562f, 0.981445f, 0.984375f, 0.987305f, 0.988770f, 0.990234f, 0.991699f,
+ 0.992676f, 0.993652f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000244f, 0.000244f, 0.000731f, 0.001295f, 0.002159f, 0.003092f, 0.004051f, 0.005836f, 0.008560f, 0.011925f, 0.018585f, 0.029373f,
+ 0.048950f, 0.088013f, 0.174194f, 0.354980f, 0.604492f, 0.788086f, 0.880371f, 0.925293f, 0.950195f, 0.963867f, 0.972168f, 0.978027f,
+ 0.982422f, 0.985840f, 0.987793f, 0.990234f, 0.991699f, 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000114f, 0.000244f, 0.000709f, 0.001089f, 0.001580f, 0.002100f, 0.002848f, 0.004028f,
+ 0.005646f, 0.008232f, 0.011276f, 0.016647f, 0.024948f, 0.039215f, 0.067566f, 0.125244f, 0.249878f, 0.471436f, 0.698242f, 0.834961f,
+ 0.902344f, 0.937012f, 0.955078f, 0.967773f, 0.974609f, 0.979492f, 0.983887f, 0.987305f, 0.988770f, 0.990723f, 0.991699f, 0.992676f,
+ 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f,
+ 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000244f, 0.000480f, 0.001081f,
+ 0.001216f, 0.001684f, 0.002287f, 0.003113f, 0.004246f, 0.005711f, 0.007412f, 0.010658f, 0.014900f, 0.021408f, 0.033173f, 0.053711f,
+ 0.094299f, 0.179688f, 0.351807f, 0.591309f, 0.774902f, 0.871582f, 0.919922f, 0.946289f, 0.961426f, 0.971191f, 0.977051f, 0.981934f,
+ 0.984863f, 0.987305f, 0.989258f, 0.991211f, 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000364f, 0.000366f, 0.000729f, 0.001195f, 0.001218f, 0.001693f, 0.002209f, 0.003038f, 0.004192f, 0.005249f, 0.006981f,
+ 0.009926f, 0.013405f, 0.019165f, 0.028473f, 0.044250f, 0.073975f, 0.134521f, 0.260010f, 0.476562f, 0.696289f, 0.830566f, 0.898438f,
+ 0.933594f, 0.954102f, 0.966309f, 0.974609f, 0.979492f, 0.982910f, 0.986328f, 0.988281f, 0.989746f, 0.991699f, 0.992676f, 0.993652f,
+ 0.994141f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000226f, 0.000365f, 0.000488f, 0.000731f, 0.001090f, 0.001245f, 0.002028f,
+ 0.002169f, 0.003023f, 0.003952f, 0.005043f, 0.006790f, 0.009026f, 0.012276f, 0.016754f, 0.024628f, 0.037384f, 0.060120f, 0.104431f,
+ 0.196045f, 0.372803f, 0.604980f, 0.779785f, 0.872070f, 0.919922f, 0.945312f, 0.960938f, 0.970703f, 0.977539f, 0.980957f, 0.984863f,
+ 0.987305f, 0.989258f, 0.991211f, 0.992188f, 0.993164f, 0.993652f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996582f,
+ 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000364f, 0.000487f,
+ 0.000488f, 0.000608f, 0.001092f, 0.001323f, 0.001909f, 0.002028f, 0.002829f, 0.003754f, 0.004940f, 0.006329f, 0.008850f, 0.011353f,
+ 0.015572f, 0.022110f, 0.032196f, 0.050293f, 0.083984f, 0.151978f, 0.288574f, 0.507812f, 0.715332f, 0.839844f, 0.902832f, 0.936035f,
+ 0.955566f, 0.966797f, 0.974609f, 0.979492f, 0.983887f, 0.986816f, 0.988281f, 0.989746f, 0.991699f, 0.992676f, 0.993652f, 0.994141f,
+ 0.994629f, 0.995605f, 0.995605f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000341f, 0.000486f, 0.000487f, 0.000591f, 0.000846f, 0.001213f, 0.001407f, 0.002018f, 0.002306f, 0.003119f,
+ 0.003736f, 0.004700f, 0.005936f, 0.007858f, 0.010498f, 0.013939f, 0.019913f, 0.028564f, 0.043060f, 0.069275f, 0.120972f, 0.225830f,
+ 0.416748f, 0.642090f, 0.798828f, 0.881836f, 0.924805f, 0.948730f, 0.962891f, 0.971191f, 0.978516f, 0.982422f, 0.985352f, 0.987793f,
+ 0.989746f, 0.991211f, 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996582f, 0.996582f, 0.996582f, 0.997070f,
+ 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000121f, 0.000122f, 0.000475f, 0.000486f, 0.000487f, 0.000714f, 0.000913f,
+ 0.001296f, 0.001350f, 0.001884f, 0.002163f, 0.002871f, 0.003702f, 0.004578f, 0.005573f, 0.007278f, 0.009819f, 0.013039f, 0.017883f,
+ 0.025589f, 0.037445f, 0.058655f, 0.099243f, 0.180542f, 0.338867f, 0.563965f, 0.751465f, 0.857422f, 0.912109f, 0.941406f, 0.958496f,
+ 0.968262f, 0.976074f, 0.980957f, 0.984375f, 0.986816f, 0.989258f, 0.990723f, 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995117f,
+ 0.995605f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000122f, 0.000242f,
+ 0.000417f, 0.000607f, 0.000602f, 0.000644f, 0.001016f, 0.001223f, 0.001337f, 0.002010f, 0.002087f, 0.002752f, 0.003380f, 0.004486f,
+ 0.005760f, 0.007523f, 0.009048f, 0.012169f, 0.016312f, 0.022949f, 0.033295f, 0.050812f, 0.082886f, 0.146851f, 0.275635f, 0.486572f,
+ 0.696777f, 0.828613f, 0.896484f, 0.933594f, 0.953613f, 0.965820f, 0.973633f, 0.979980f, 0.983887f, 0.986328f, 0.988770f, 0.990723f,
+ 0.992188f, 0.993164f, 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997559f, 0.997559f, 0.997559f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000262f, 0.000463f, 0.000603f, 0.000665f, 0.000716f, 0.001069f, 0.001322f, 0.001538f,
+ 0.001895f, 0.002293f, 0.003120f, 0.003323f, 0.004166f, 0.005638f, 0.006828f, 0.008942f, 0.011368f, 0.015465f, 0.021057f, 0.029663f,
+ 0.044861f, 0.070923f, 0.123169f, 0.228149f, 0.416504f, 0.640137f, 0.797363f, 0.880859f, 0.924805f, 0.948730f, 0.963379f, 0.971680f,
+ 0.978516f, 0.982422f, 0.985840f, 0.988281f, 0.990723f, 0.991699f, 0.992676f, 0.993652f, 0.994141f, 0.995117f, 0.995117f, 0.996094f,
+ 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000120f, 0.000172f, 0.000243f, 0.000365f, 0.000475f, 0.000607f,
+ 0.000608f, 0.000609f, 0.001013f, 0.001424f, 0.001456f, 0.001904f, 0.002411f, 0.002903f, 0.003145f, 0.004314f, 0.004944f, 0.006607f,
+ 0.008156f, 0.010719f, 0.014297f, 0.018906f, 0.027069f, 0.040070f, 0.062103f, 0.104858f, 0.191162f, 0.355469f, 0.581543f, 0.762695f,
+ 0.863281f, 0.915039f, 0.943848f, 0.960449f, 0.970703f, 0.977051f, 0.981445f, 0.985840f, 0.987793f, 0.989746f, 0.991211f, 0.992676f,
+ 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.997070f, 0.997070f, 0.998047f, 0.997559f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000000f, 0.000000f, 0.000096f,
+ 0.000239f, 0.000241f, 0.000336f, 0.000482f, 0.000719f, 0.000729f, 0.000831f, 0.001049f, 0.001552f, 0.001576f, 0.001710f, 0.002373f,
+ 0.002846f, 0.003254f, 0.004051f, 0.005035f, 0.006405f, 0.007706f, 0.009987f, 0.013092f, 0.017715f, 0.024872f, 0.035980f, 0.055328f,
+ 0.091248f, 0.163330f, 0.305664f, 0.524902f, 0.726562f, 0.845215f, 0.906250f, 0.938965f, 0.957031f, 0.969238f, 0.976074f, 0.981445f,
+ 0.984863f, 0.987305f, 0.989258f, 0.991211f, 0.992188f, 0.993164f, 0.994141f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996582f,
+ 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000118f, 0.000120f, 0.000351f, 0.000364f, 0.000421f, 0.000480f, 0.000606f, 0.000728f, 0.000852f,
+ 0.001175f, 0.001535f, 0.001673f, 0.001671f, 0.002277f, 0.002743f, 0.003220f, 0.003922f, 0.004868f, 0.005951f, 0.007488f, 0.009430f,
+ 0.012527f, 0.016266f, 0.022964f, 0.033142f, 0.049805f, 0.080688f, 0.141846f, 0.265625f, 0.473145f, 0.688477f, 0.825684f, 0.897949f,
+ 0.934082f, 0.954102f, 0.966797f, 0.975098f, 0.980469f, 0.984375f, 0.987305f, 0.989258f, 0.991211f, 0.992676f, 0.993164f, 0.993652f,
+ 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000058f, 0.000235f, 0.000360f, 0.000243f,
+ 0.000440f, 0.000583f, 0.000847f, 0.000851f, 0.000852f, 0.001189f, 0.001411f, 0.001645f, 0.001898f, 0.002417f, 0.002617f, 0.003435f,
+ 0.003695f, 0.004616f, 0.005733f, 0.007278f, 0.009216f, 0.012016f, 0.015701f, 0.021561f, 0.030396f, 0.045746f, 0.073120f, 0.125732f,
+ 0.233521f, 0.428223f, 0.653320f, 0.807617f, 0.887695f, 0.929688f, 0.951660f, 0.965820f, 0.974121f, 0.980469f, 0.984375f, 0.986816f,
+ 0.989746f, 0.991211f, 0.992676f, 0.993164f, 0.994141f, 0.995117f, 0.995605f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000237f, 0.000237f, 0.000362f, 0.000365f, 0.000558f, 0.000814f, 0.000727f, 0.000729f, 0.000935f, 0.001189f, 0.001403f,
+ 0.001569f, 0.001989f, 0.002216f, 0.002533f, 0.003307f, 0.003906f, 0.004463f, 0.005646f, 0.006908f, 0.008980f, 0.011230f, 0.014755f,
+ 0.020020f, 0.028320f, 0.041931f, 0.065979f, 0.113098f, 0.209229f, 0.389648f, 0.620605f, 0.789551f, 0.879395f, 0.924805f, 0.950684f,
+ 0.964844f, 0.974121f, 0.979980f, 0.983398f, 0.987305f, 0.989258f, 0.991211f, 0.992676f, 0.993652f, 0.993652f, 0.995117f, 0.995605f,
+ 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000121f, 0.000241f, 0.000486f, 0.000575f, 0.000707f,
+ 0.000726f, 0.000971f, 0.000849f, 0.000966f, 0.001350f, 0.001660f, 0.001678f, 0.002224f, 0.002483f, 0.003197f, 0.003611f, 0.004200f,
+ 0.005318f, 0.006744f, 0.008476f, 0.010506f, 0.014145f, 0.019089f, 0.026627f, 0.039001f, 0.061096f, 0.103333f, 0.189819f, 0.358887f,
+ 0.591309f, 0.773438f, 0.872559f, 0.922363f, 0.948730f, 0.963867f, 0.973145f, 0.979492f, 0.983887f, 0.986816f, 0.989258f, 0.991211f,
+ 0.992188f, 0.993164f, 0.994629f, 0.995117f, 0.995605f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000175f, 0.000361f,
+ 0.000481f, 0.000485f, 0.000364f, 0.000562f, 0.000703f, 0.000827f, 0.000842f, 0.000972f, 0.001172f, 0.001321f, 0.001675f, 0.001684f,
+ 0.002153f, 0.002455f, 0.003122f, 0.003391f, 0.004177f, 0.005314f, 0.006325f, 0.007896f, 0.010368f, 0.013527f, 0.018082f, 0.025162f,
+ 0.037140f, 0.057343f, 0.095886f, 0.175659f, 0.334473f, 0.567871f, 0.760742f, 0.866699f, 0.919922f, 0.947754f, 0.963379f, 0.972656f,
+ 0.979492f, 0.984375f, 0.987305f, 0.989258f, 0.991211f, 0.992676f, 0.993652f, 0.994629f, 0.995117f, 0.996094f, 0.996582f, 0.997070f,
+ 0.998047f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000325f, 0.000311f, 0.000243f, 0.000484f, 0.000486f, 0.000536f, 0.000698f, 0.000723f, 0.000844f,
+ 0.000972f, 0.001081f, 0.001312f, 0.001658f, 0.001914f, 0.001932f, 0.002390f, 0.003017f, 0.003668f, 0.004353f, 0.005199f, 0.006336f,
+ 0.007812f, 0.009972f, 0.012802f, 0.017029f, 0.024200f, 0.035034f, 0.053833f, 0.090027f, 0.164185f, 0.316162f, 0.549805f, 0.751465f,
+ 0.863281f, 0.918457f, 0.947266f, 0.963379f, 0.974121f, 0.979492f, 0.984375f, 0.987793f, 0.989746f, 0.991699f, 0.993164f, 0.994141f,
+ 0.995117f, 0.995605f, 0.996094f, 0.997070f, 0.997559f, 0.997559f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000231f, 0.000453f, 0.000480f, 0.000484f,
+ 0.000485f, 0.000486f, 0.000917f, 0.000963f, 0.000969f, 0.000970f, 0.001043f, 0.001288f, 0.001523f, 0.001684f, 0.001885f, 0.002464f,
+ 0.002531f, 0.003565f, 0.004124f, 0.004745f, 0.006077f, 0.007580f, 0.009605f, 0.012634f, 0.016953f, 0.023346f, 0.033386f, 0.051697f,
+ 0.085632f, 0.156250f, 0.303955f, 0.537598f, 0.746582f, 0.860840f, 0.918457f, 0.947754f, 0.963867f, 0.973633f, 0.979980f, 0.984863f,
+ 0.987793f, 0.990234f, 0.991699f, 0.993652f, 0.994141f, 0.995117f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000235f, 0.000239f, 0.000359f, 0.000484f, 0.000485f, 0.000486f, 0.000628f, 0.000957f, 0.000967f, 0.000969f, 0.001065f,
+ 0.001288f, 0.001602f, 0.001850f, 0.001995f, 0.002409f, 0.002523f, 0.003462f, 0.003838f, 0.004993f, 0.005917f, 0.007233f, 0.009338f,
+ 0.012230f, 0.015610f, 0.022415f, 0.032288f, 0.049805f, 0.082947f, 0.151489f, 0.296631f, 0.532715f, 0.745117f, 0.862793f, 0.919434f,
+ 0.948242f, 0.964844f, 0.974609f, 0.980957f, 0.985352f, 0.988281f, 0.990723f, 0.992676f, 0.994141f, 0.994629f, 0.995605f, 0.996094f,
+ 0.996582f, 0.997070f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000187f, 0.000437f, 0.000473f, 0.000483f, 0.000485f, 0.000606f,
+ 0.000583f, 0.000711f, 0.000772f, 0.000968f, 0.001107f, 0.001287f, 0.001434f, 0.001662f, 0.001984f, 0.002449f, 0.002634f, 0.003145f,
+ 0.003777f, 0.004410f, 0.005722f, 0.007114f, 0.008926f, 0.011696f, 0.016006f, 0.021683f, 0.031342f, 0.048309f, 0.080750f, 0.149170f,
+ 0.294678f, 0.534668f, 0.749512f, 0.866211f, 0.922363f, 0.950684f, 0.966309f, 0.975586f, 0.981934f, 0.985840f, 0.989258f, 0.991699f,
+ 0.992676f, 0.994141f, 0.994629f, 0.996094f, 0.996582f, 0.997070f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000247f,
+ 0.000238f, 0.000407f, 0.000482f, 0.000484f, 0.000604f, 0.000869f, 0.000909f, 0.000721f, 0.000955f, 0.001000f, 0.001241f, 0.001342f,
+ 0.001655f, 0.001721f, 0.002329f, 0.002623f, 0.003086f, 0.003677f, 0.004349f, 0.005600f, 0.006962f, 0.008835f, 0.011581f, 0.015274f,
+ 0.021286f, 0.030884f, 0.047760f, 0.079895f, 0.148926f, 0.298584f, 0.543945f, 0.758301f, 0.872559f, 0.925781f, 0.953125f, 0.967773f,
+ 0.977051f, 0.982910f, 0.986816f, 0.989258f, 0.991211f, 0.993164f, 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000237f, 0.000410f, 0.000472f, 0.000481f, 0.000483f, 0.000485f, 0.000687f, 0.000913f,
+ 0.000956f, 0.000966f, 0.000997f, 0.001341f, 0.001415f, 0.001813f, 0.002029f, 0.002043f, 0.002594f, 0.003210f, 0.003641f, 0.004734f,
+ 0.005356f, 0.006882f, 0.008675f, 0.011360f, 0.014816f, 0.020920f, 0.030380f, 0.047485f, 0.080200f, 0.151733f, 0.308105f, 0.561523f,
+ 0.772949f, 0.881348f, 0.931152f, 0.956055f, 0.969727f, 0.978516f, 0.983887f, 0.987793f, 0.990234f, 0.992188f, 0.993652f, 0.994629f,
+ 0.995605f, 0.996094f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000254f, 0.000345f, 0.000468f,
+ 0.000585f, 0.000482f, 0.000603f, 0.000485f, 0.000862f, 0.000928f, 0.000965f, 0.001174f, 0.001162f, 0.001405f, 0.001761f, 0.002016f,
+ 0.002182f, 0.002733f, 0.002831f, 0.003504f, 0.004456f, 0.005440f, 0.006775f, 0.008553f, 0.011055f, 0.014694f, 0.020859f, 0.030334f,
+ 0.047852f, 0.081970f, 0.157593f, 0.325439f, 0.586914f, 0.790527f, 0.890137f, 0.936523f, 0.959473f, 0.973145f, 0.980469f, 0.985352f,
+ 0.988770f, 0.990723f, 0.992676f, 0.994141f, 0.995117f, 0.996094f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000241f, 0.000237f, 0.000340f, 0.000457f, 0.000580f, 0.000481f, 0.000601f, 0.000605f, 0.000742f, 0.000951f, 0.000953f,
+ 0.001131f, 0.001257f, 0.001396f, 0.001730f, 0.001936f, 0.002102f, 0.002682f, 0.002762f, 0.003733f, 0.004425f, 0.005344f, 0.006516f,
+ 0.008354f, 0.010971f, 0.014793f, 0.020859f, 0.030640f, 0.048859f, 0.085144f, 0.167358f, 0.350586f, 0.620117f, 0.811035f, 0.900391f,
+ 0.942383f, 0.963379f, 0.975098f, 0.981934f, 0.986816f, 0.989746f, 0.992188f, 0.993164f, 0.994629f, 0.995117f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000131f, 0.000301f, 0.000430f, 0.000470f, 0.000593f,
+ 0.000571f, 0.000587f, 0.000693f, 0.000906f, 0.000959f, 0.000965f, 0.001094f, 0.001364f, 0.001522f, 0.001783f, 0.002094f, 0.002615f,
+ 0.003038f, 0.003365f, 0.004307f, 0.005135f, 0.006493f, 0.008347f, 0.011055f, 0.014824f, 0.020844f, 0.031204f, 0.050507f, 0.090027f,
+ 0.182129f, 0.385498f, 0.659668f, 0.834473f, 0.913086f, 0.949219f, 0.967285f, 0.978027f, 0.983887f, 0.987793f, 0.991211f, 0.992188f,
+ 0.994141f, 0.995117f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000189f, 0.000122f, 0.000122f,
+ 0.000241f, 0.000295f, 0.000425f, 0.000457f, 0.000592f, 0.000481f, 0.000603f, 0.000697f, 0.000926f, 0.000943f, 0.000960f, 0.001022f,
+ 0.001435f, 0.001632f, 0.001658f, 0.002024f, 0.002468f, 0.003010f, 0.003210f, 0.004124f, 0.005219f, 0.006351f, 0.008163f, 0.010933f,
+ 0.015030f, 0.021271f, 0.032257f, 0.053009f, 0.097534f, 0.203003f, 0.432373f, 0.704102f, 0.858887f, 0.924805f, 0.955566f, 0.970703f,
+ 0.979492f, 0.985840f, 0.989258f, 0.991699f, 0.993164f, 0.995117f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000214f, 0.000201f, 0.000239f, 0.000241f, 0.000383f, 0.000461f, 0.000474f, 0.000479f, 0.000598f,
+ 0.000736f, 0.000905f, 0.000947f, 0.001072f, 0.001180f, 0.001376f, 0.001572f, 0.001752f, 0.001900f, 0.002258f, 0.002792f, 0.003487f,
+ 0.004055f, 0.005161f, 0.006424f, 0.008209f, 0.010933f, 0.015030f, 0.021942f, 0.033630f, 0.056671f, 0.107666f, 0.233276f, 0.492188f,
+ 0.752441f, 0.881836f, 0.937012f, 0.961914f, 0.975098f, 0.982910f, 0.987305f, 0.990234f, 0.992676f, 0.994629f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998047f, 0.998535f, 0.998535f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000132f, 0.000224f, 0.000129f, 0.000237f, 0.000240f,
+ 0.000337f, 0.000430f, 0.000468f, 0.000579f, 0.000593f, 0.000602f, 0.000881f, 0.000936f, 0.000956f, 0.000963f, 0.001282f, 0.001519f,
+ 0.001607f, 0.001852f, 0.002150f, 0.002737f, 0.003508f, 0.003990f, 0.005077f, 0.006516f, 0.008179f, 0.011185f, 0.015511f, 0.022446f,
+ 0.035614f, 0.061859f, 0.122681f, 0.275879f, 0.563965f, 0.798828f, 0.903809f, 0.946777f, 0.967773f, 0.978516f, 0.984863f, 0.988770f,
+ 0.991699f, 0.993652f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000149f, 0.000122f, 0.000207f, 0.000371f, 0.000430f, 0.000573f, 0.000591f, 0.000598f, 0.000597f, 0.000804f,
+ 0.000901f, 0.000948f, 0.001053f, 0.001083f, 0.001376f, 0.001584f, 0.001878f, 0.002331f, 0.002529f, 0.003376f, 0.003944f, 0.005230f,
+ 0.006504f, 0.008537f, 0.011459f, 0.015747f, 0.024002f, 0.038361f, 0.069458f, 0.144409f, 0.336914f, 0.644043f, 0.841797f, 0.922363f,
+ 0.957520f, 0.972656f, 0.981934f, 0.987305f, 0.990234f, 0.993164f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998047f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000230f, 0.000234f, 0.000235f, 0.000268f, 0.000400f,
+ 0.000448f, 0.000585f, 0.000590f, 0.000599f, 0.000641f, 0.000788f, 0.000930f, 0.000968f, 0.001107f, 0.001251f, 0.001656f, 0.001701f,
+ 0.002047f, 0.002691f, 0.003437f, 0.003998f, 0.004829f, 0.006329f, 0.008492f, 0.011757f, 0.016525f, 0.025345f, 0.042297f, 0.080200f,
+ 0.177490f, 0.420654f, 0.724121f, 0.878906f, 0.938965f, 0.964355f, 0.977539f, 0.984863f, 0.989746f, 0.992188f, 0.997559f, 0.997559f,
+ 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000214f, 0.000235f, 0.000228f, 0.000240f, 0.000429f, 0.000439f, 0.000574f, 0.000654f, 0.000583f, 0.000493f, 0.000788f, 0.000813f,
+ 0.000947f, 0.001062f, 0.001225f, 0.001569f, 0.001721f, 0.002048f, 0.002844f, 0.002979f, 0.003902f, 0.004997f, 0.006454f, 0.008698f,
+ 0.012192f, 0.018143f, 0.027634f, 0.047913f, 0.095886f, 0.228394f, 0.526855f, 0.796875f, 0.910156f, 0.953125f, 0.973145f, 0.982422f,
+ 0.987793f, 0.991699f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000205f, 0.000236f, 0.000232f, 0.000299f, 0.000446f, 0.000417f,
+ 0.000466f, 0.000580f, 0.000508f, 0.000710f, 0.000800f, 0.000940f, 0.000954f, 0.001228f, 0.001496f, 0.001631f, 0.002043f, 0.002798f,
+ 0.003359f, 0.004139f, 0.004951f, 0.006680f, 0.008995f, 0.012764f, 0.018860f, 0.030823f, 0.056061f, 0.120911f, 0.307617f, 0.645508f,
+ 0.855957f, 0.934082f, 0.964355f, 0.978516f, 0.985840f, 0.990234f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000226f,
+ 0.000122f, 0.000226f, 0.000373f, 0.000272f, 0.000325f, 0.000460f, 0.000471f, 0.000477f, 0.000673f, 0.000877f, 0.000929f, 0.000951f,
+ 0.001129f, 0.001446f, 0.001614f, 0.002096f, 0.002619f, 0.002939f, 0.003941f, 0.005363f, 0.006844f, 0.009491f, 0.013596f, 0.020905f,
+ 0.035370f, 0.068420f, 0.161743f, 0.426270f, 0.755859f, 0.900879f, 0.952148f, 0.973145f, 0.983398f, 0.989746f, 0.997070f, 0.997070f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000111f, 0.000236f, 0.000297f, 0.000368f, 0.000449f, 0.000467f,
+ 0.000588f, 0.000641f, 0.000813f, 0.000924f, 0.001035f, 0.001124f, 0.001348f, 0.001764f, 0.001922f, 0.002439f, 0.003160f, 0.004005f,
+ 0.005280f, 0.007107f, 0.010109f, 0.014748f, 0.023148f, 0.041595f, 0.088440f, 0.232910f, 0.578125f, 0.841797f, 0.933594f, 0.965820f,
+ 0.980469f, 0.987305f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000014f, 0.000011f, 0.000116f,
+ 0.000148f, 0.000128f, 0.000369f, 0.000418f, 0.000563f, 0.000470f, 0.000592f, 0.000776f, 0.000901f, 0.000937f, 0.001112f, 0.001348f,
+ 0.001743f, 0.001904f, 0.002470f, 0.003187f, 0.003986f, 0.005360f, 0.007557f, 0.010674f, 0.016068f, 0.026871f, 0.051666f, 0.122925f,
+ 0.356445f, 0.729492f, 0.901855f, 0.955078f, 0.976074f, 0.985840f, 0.996094f, 0.996582f, 0.996094f, 0.996582f, 0.996094f, 0.996582f,
+ 0.000122f, 0.000122f, 0.000121f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000028f, 0.000019f, 0.000014f, 0.000011f, 0.000033f, 0.000118f, 0.000247f, 0.000305f, 0.000412f, 0.000447f, 0.000576f, 0.000587f,
+ 0.000693f, 0.000850f, 0.000949f, 0.001083f, 0.001319f, 0.001557f, 0.001957f, 0.002424f, 0.003340f, 0.004417f, 0.005688f, 0.007774f,
+ 0.011497f, 0.017731f, 0.032257f, 0.068604f, 0.189575f, 0.541992f, 0.843262f, 0.938477f, 0.970703f, 0.983887f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.000121f, 0.000118f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000067f, 0.000042f, 0.000028f, 0.000020f, 0.000015f, 0.000066f, 0.000009f, 0.000101f, 0.000118f,
+ 0.000260f, 0.000358f, 0.000520f, 0.000456f, 0.000563f, 0.000711f, 0.000872f, 0.000980f, 0.001059f, 0.001309f, 0.001699f, 0.002066f,
+ 0.002708f, 0.003248f, 0.004166f, 0.005836f, 0.008224f, 0.012619f, 0.021484f, 0.041260f, 0.101074f, 0.323486f, 0.733887f, 0.912109f,
+ 0.962402f, 0.980957f, 0.995117f, 0.995117f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.000000f, 0.000000f, 0.000119f, 0.000119f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000105f, 0.000067f, 0.000042f, 0.000029f, 0.000022f,
+ 0.000015f, 0.000011f, 0.000040f, 0.000033f, 0.000153f, 0.000204f, 0.000313f, 0.000501f, 0.000554f, 0.000575f, 0.000585f, 0.000778f,
+ 0.000925f, 0.000980f, 0.001245f, 0.001634f, 0.001989f, 0.002413f, 0.003433f, 0.004028f, 0.005989f, 0.008911f, 0.014374f, 0.026443f,
+ 0.057495f, 0.170166f, 0.549805f, 0.864746f, 0.951172f, 0.977051f, 0.994629f, 0.994629f, 0.994629f, 0.994629f, 0.995605f, 0.994629f,
+ 0.000000f, 0.000046f, 0.000088f, 0.000118f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000108f, 0.000069f, 0.000047f, 0.000030f, 0.000022f, 0.000016f, 0.000012f, 0.000052f, 0.000081f, 0.000100f, 0.000184f, 0.000226f,
+ 0.000400f, 0.000467f, 0.000452f, 0.000597f, 0.000807f, 0.000895f, 0.000942f, 0.001219f, 0.001611f, 0.002022f, 0.002352f, 0.003222f,
+ 0.004177f, 0.006481f, 0.009850f, 0.017517f, 0.034668f, 0.090637f, 0.331055f, 0.776367f, 0.932129f, 0.972656f, 0.994141f, 0.994141f,
+ 0.994629f, 0.994141f, 0.994629f, 0.994629f, 0.000000f, 0.000000f, 0.000000f, 0.000107f, 0.000115f, 0.000112f, 0.000119f, 0.000118f,
+ 0.000119f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000117f, 0.000072f, 0.000049f, 0.000032f, 0.000023f, 0.000017f, 0.000013f,
+ 0.000011f, 0.000008f, 0.000075f, 0.000151f, 0.000207f, 0.000305f, 0.000509f, 0.000499f, 0.000560f, 0.000704f, 0.000863f, 0.000917f,
+ 0.001220f, 0.001505f, 0.001740f, 0.002174f, 0.003153f, 0.004559f, 0.007095f, 0.011826f, 0.022247f, 0.051147f, 0.173462f, 0.618652f,
+ 0.902344f, 0.966309f, 0.993164f, 0.993652f, 0.992676f, 0.992676f, 0.993164f, 0.993164f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000060f, 0.000102f, 0.000113f, 0.000117f, 0.000118f, 0.000119f, 0.000119f, 0.000119f, 0.000120f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000078f,
+ 0.000052f, 0.000038f, 0.000027f, 0.000019f, 0.000015f, 0.000011f, 0.000054f, 0.000007f, 0.000085f, 0.000108f, 0.000258f, 0.000466f,
+ 0.000533f, 0.000560f, 0.000662f, 0.000849f, 0.000856f, 0.000965f, 0.001180f, 0.001678f, 0.002075f, 0.003193f, 0.005016f, 0.008095f,
+ 0.014343f, 0.030899f, 0.090820f, 0.401367f, 0.848145f, 0.956543f, 0.992188f, 0.992188f, 0.992188f, 0.992676f, 0.991699f, 0.992188f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000059f, 0.000096f, 0.000107f, 0.000112f, 0.000115f, 0.000116f,
+ 0.000117f, 0.000118f, 0.000118f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000088f, 0.000059f, 0.000041f, 0.000031f, 0.000022f, 0.000017f, 0.000013f, 0.000010f,
+ 0.000056f, 0.000091f, 0.000183f, 0.000201f, 0.000309f, 0.000506f, 0.000547f, 0.000525f, 0.000629f, 0.000613f, 0.000817f, 0.001012f,
+ 0.001640f, 0.002420f, 0.003588f, 0.005520f, 0.009453f, 0.019119f, 0.050415f, 0.214722f, 0.751465f, 0.943848f, 0.990723f, 0.990723f,
+ 0.991211f, 0.991211f, 0.991211f, 0.991211f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000055f, 0.000095f, 0.000103f, 0.000105f, 0.000112f, 0.000114f, 0.000115f, 0.000117f, 0.000117f, 0.000117f, 0.000118f,
+ 0.000118f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000120f, 0.000120f, 0.000105f, 0.000069f, 0.000048f,
+ 0.000035f, 0.000025f, 0.000019f, 0.000015f, 0.000011f, 0.000014f, 0.000008f, 0.000071f, 0.000193f, 0.000311f, 0.000315f, 0.000524f,
+ 0.000483f, 0.000558f, 0.000591f, 0.000705f, 0.000950f, 0.001389f, 0.002428f, 0.003494f, 0.006321f, 0.012306f, 0.029480f, 0.108948f,
+ 0.581543f, 0.924316f, 0.989746f, 0.989746f, 0.989258f, 0.989746f, 0.989258f, 0.989746f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000069f, 0.000096f, 0.000103f, 0.000107f,
+ 0.000109f, 0.000112f, 0.000113f, 0.000115f, 0.000115f, 0.000116f, 0.000117f, 0.000117f, 0.000118f, 0.000118f, 0.000118f, 0.000118f,
+ 0.000119f, 0.000119f, 0.000119f, 0.000084f, 0.000061f, 0.000042f, 0.000031f, 0.000023f, 0.000018f, 0.000014f, 0.000011f, 0.000009f,
+ 0.000095f, 0.000127f, 0.000223f, 0.000402f, 0.000432f, 0.000399f, 0.000494f, 0.000535f, 0.000557f, 0.000933f, 0.001474f, 0.002300f,
+ 0.004192f, 0.007919f, 0.017838f, 0.057068f, 0.360840f, 0.890625f, 0.986816f, 0.987793f, 0.987305f, 0.987305f, 0.987793f, 0.987305f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000035f, 0.000041f, 0.000088f, 0.000098f, 0.000103f, 0.000106f, 0.000110f, 0.000110f, 0.000113f, 0.000113f,
+ 0.000115f, 0.000116f, 0.000116f, 0.000117f, 0.000117f, 0.000117f, 0.000117f, 0.000118f, 0.000111f, 0.000074f, 0.000053f, 0.000038f,
+ 0.000029f, 0.000022f, 0.000016f, 0.000013f, 0.000010f, 0.000008f, 0.000073f, 0.000152f, 0.000296f, 0.000369f, 0.000365f, 0.000437f,
+ 0.000507f, 0.000661f, 0.000876f, 0.001451f, 0.002531f, 0.004898f, 0.010384f, 0.031113f, 0.183838f, 0.833008f, 0.984375f, 0.984863f,
+ 0.984863f, 0.984375f, 0.984863f, 0.984863f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000024f, 0.000044f, 0.000073f,
+ 0.000087f, 0.000097f, 0.000102f, 0.000105f, 0.000108f, 0.000110f, 0.000111f, 0.000113f, 0.000114f, 0.000114f, 0.000115f, 0.000115f,
+ 0.000116f, 0.000116f, 0.000101f, 0.000070f, 0.000052f, 0.000037f, 0.000027f, 0.000021f, 0.000016f, 0.000013f, 0.000010f, 0.000008f,
+ 0.000083f, 0.000183f, 0.000352f, 0.000355f, 0.000362f, 0.000365f, 0.000528f, 0.000790f, 0.001469f, 0.003029f, 0.005970f, 0.017242f,
+ 0.089050f, 0.728516f, 0.980957f, 0.981445f, 0.981445f, 0.980957f, 0.980957f, 0.981445f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000033f, 0.000041f, 0.000073f, 0.000083f, 0.000088f, 0.000097f, 0.000102f,
+ 0.000105f, 0.000108f, 0.000108f, 0.000111f, 0.000112f, 0.000113f, 0.000113f, 0.000114f, 0.000097f, 0.000068f, 0.000049f, 0.000038f,
+ 0.000028f, 0.000021f, 0.000016f, 0.000013f, 0.000010f, 0.000056f, 0.000151f, 0.000243f, 0.000264f, 0.000221f, 0.000328f, 0.000449f,
+ 0.000850f, 0.001612f, 0.003340f, 0.009361f, 0.043121f, 0.548340f, 0.976074f, 0.976562f, 0.975586f, 0.976074f, 0.976074f, 0.976562f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000019f, 0.000052f, 0.000065f, 0.000077f, 0.000088f, 0.000094f, 0.000098f, 0.000100f, 0.000104f, 0.000106f, 0.000108f,
+ 0.000109f, 0.000110f, 0.000095f, 0.000069f, 0.000052f, 0.000037f, 0.000028f, 0.000021f, 0.000017f, 0.000013f, 0.000025f, 0.000063f,
+ 0.000195f, 0.000233f, 0.000205f, 0.000264f, 0.000401f, 0.000789f, 0.001532f, 0.004520f, 0.020844f, 0.321289f, 0.969238f, 0.968750f,
+ 0.969238f, 0.968750f, 0.969238f, 0.969238f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000018f, 0.000039f, 0.000053f,
+ 0.000066f, 0.000079f, 0.000086f, 0.000090f, 0.000096f, 0.000100f, 0.000102f, 0.000105f, 0.000098f, 0.000074f, 0.000053f, 0.000041f,
+ 0.000031f, 0.000023f, 0.000017f, 0.000013f, 0.000028f, 0.000139f, 0.000189f, 0.000179f, 0.000219f, 0.000333f, 0.000840f, 0.002119f,
+ 0.009193f, 0.144775f, 0.958496f, 0.958496f, 0.958008f, 0.958496f, 0.958008f, 0.958008f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000025f, 0.000040f, 0.000052f, 0.000067f, 0.000077f, 0.000082f,
+ 0.000089f, 0.000093f, 0.000097f, 0.000079f, 0.000059f, 0.000044f, 0.000033f, 0.000024f, 0.000018f, 0.000014f, 0.000034f, 0.000084f,
+ 0.000157f, 0.000199f, 0.000309f, 0.000817f, 0.003424f, 0.054901f, 0.940918f, 0.940918f, 0.940918f, 0.940918f, 0.941406f, 0.940430f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000021f, 0.000040f, 0.000054f, 0.000063f, 0.000072f, 0.000078f, 0.000085f, 0.000065f, 0.000049f,
+ 0.000036f, 0.000026f, 0.000019f, 0.000014f, 0.000042f, 0.000114f, 0.000122f, 0.000276f, 0.001024f, 0.016357f, 0.912109f, 0.912598f,
+ 0.911621f, 0.912598f, 0.911621f, 0.913086f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000016f, 0.000032f, 0.000045f, 0.000056f, 0.000065f, 0.000054f, 0.000039f, 0.000028f, 0.000019f, 0.000013f, 0.000049f, 0.000079f,
+ 0.000226f, 0.003199f, 0.860840f, 0.859863f, 0.860352f, 0.860840f, 0.860840f, 0.860352f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000004f, 0.000021f, 0.000035f,
+ 0.000040f, 0.000027f, 0.000018f, 0.000013f, 0.000033f, 0.000333f, 0.764160f, 0.765137f, 0.764648f, 0.764648f, 0.764648f, 0.765137f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000006f, 0.000011f, 0.000009f, 0.600586f, 0.602051f,
+ 0.602051f, 0.601562f, 0.601074f, 0.601074f,
+ },
+ {
+ 0.142456f, 0.713867f, 0.883789f, 0.933105f, 0.953613f, 0.964844f, 0.972168f, 0.977539f, 0.980957f, 0.983398f, 0.985352f, 0.987305f,
+ 0.989258f, 0.989746f, 0.990723f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.993652f, 0.994141f, 0.995117f, 0.995117f, 0.995605f,
+ 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.012886f, 0.087646f, 0.360840f, 0.709473f, 0.859863f, 0.916992f, 0.943848f, 0.958496f,
+ 0.967773f, 0.973633f, 0.978516f, 0.980957f, 0.984375f, 0.986328f, 0.987793f, 0.988770f, 0.990234f, 0.991211f, 0.992188f, 0.993164f,
+ 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.997070f,
+ 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.003895f, 0.020126f, 0.063599f, 0.188721f,
+ 0.464844f, 0.727539f, 0.853027f, 0.909668f, 0.938477f, 0.954590f, 0.965332f, 0.971680f, 0.976562f, 0.979980f, 0.982910f, 0.985840f,
+ 0.986816f, 0.988770f, 0.990234f, 0.990723f, 0.991699f, 0.992188f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f,
+ 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.002062f, 0.008438f, 0.021774f, 0.049713f, 0.117676f, 0.279541f, 0.541016f, 0.751465f, 0.855469f, 0.909180f, 0.936035f, 0.952637f,
+ 0.963379f, 0.970703f, 0.975098f, 0.979492f, 0.982910f, 0.984863f, 0.986328f, 0.987793f, 0.989258f, 0.990234f, 0.990723f, 0.992188f,
+ 0.992676f, 0.993164f, 0.993652f, 0.994629f, 0.995117f, 0.995117f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.997070f,
+ 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.001335f, 0.004597f, 0.010628f, 0.020844f, 0.040283f, 0.082764f, 0.177612f, 0.366211f,
+ 0.605469f, 0.773926f, 0.863281f, 0.910156f, 0.936035f, 0.952148f, 0.962402f, 0.969727f, 0.975098f, 0.979004f, 0.982422f, 0.984863f,
+ 0.986328f, 0.988281f, 0.988770f, 0.989746f, 0.991211f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994629f, 0.995117f, 0.995117f,
+ 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000851f, 0.002769f, 0.006130f, 0.010994f,
+ 0.019394f, 0.034943f, 0.063293f, 0.122253f, 0.244019f, 0.448242f, 0.660156f, 0.798828f, 0.872559f, 0.914062f, 0.937988f, 0.954102f,
+ 0.961914f, 0.970215f, 0.974609f, 0.978516f, 0.981934f, 0.984375f, 0.986328f, 0.987793f, 0.988770f, 0.989746f, 0.991211f, 0.991699f,
+ 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f,
+ 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000466f, 0.001933f, 0.003809f, 0.007095f, 0.011353f, 0.018204f, 0.030029f, 0.050568f, 0.090759f, 0.170898f, 0.318848f, 0.526367f,
+ 0.708496f, 0.820801f, 0.884277f, 0.918457f, 0.940918f, 0.954102f, 0.963867f, 0.970215f, 0.975098f, 0.978516f, 0.981934f, 0.984863f,
+ 0.986328f, 0.988281f, 0.988770f, 0.990234f, 0.991211f, 0.991699f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.994629f, 0.995605f,
+ 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000487f, 0.001685f, 0.002766f, 0.004467f, 0.007305f, 0.011215f, 0.017136f, 0.026489f,
+ 0.042419f, 0.071716f, 0.125244f, 0.228271f, 0.399658f, 0.599609f, 0.751953f, 0.842773f, 0.894531f, 0.924805f, 0.943359f, 0.955566f,
+ 0.965820f, 0.971191f, 0.976562f, 0.979980f, 0.981934f, 0.984863f, 0.986816f, 0.988281f, 0.989258f, 0.990723f, 0.991211f, 0.992188f,
+ 0.992676f, 0.993652f, 0.994141f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997070f,
+ 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000244f, 0.000965f, 0.002024f, 0.003202f,
+ 0.005009f, 0.007050f, 0.011070f, 0.015869f, 0.023987f, 0.036835f, 0.058563f, 0.097168f, 0.169800f, 0.297852f, 0.484131f, 0.664062f,
+ 0.789062f, 0.861816f, 0.905273f, 0.930176f, 0.947266f, 0.958984f, 0.967285f, 0.972168f, 0.976562f, 0.980469f, 0.982910f, 0.984863f,
+ 0.986816f, 0.988770f, 0.989746f, 0.990723f, 0.992188f, 0.992188f, 0.993652f, 0.993652f, 0.994629f, 0.995117f, 0.995117f, 0.995605f,
+ 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000244f, 0.000974f, 0.001576f, 0.002403f, 0.003510f, 0.005344f, 0.007332f, 0.010567f, 0.015099f, 0.022064f, 0.032104f, 0.048706f,
+ 0.078003f, 0.130249f, 0.224243f, 0.378174f, 0.566406f, 0.720703f, 0.820312f, 0.879883f, 0.915039f, 0.936523f, 0.951660f, 0.961426f,
+ 0.968262f, 0.974121f, 0.978027f, 0.980957f, 0.983887f, 0.985840f, 0.987793f, 0.989258f, 0.990234f, 0.991211f, 0.992188f, 0.992676f,
+ 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997070f,
+ 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000240f, 0.000609f, 0.001096f, 0.001580f, 0.002674f, 0.004131f, 0.005245f, 0.007660f,
+ 0.010757f, 0.014221f, 0.019775f, 0.028381f, 0.041870f, 0.064697f, 0.103638f, 0.173706f, 0.293945f, 0.466553f, 0.642090f, 0.769531f,
+ 0.849121f, 0.895996f, 0.924316f, 0.942871f, 0.956055f, 0.963867f, 0.970703f, 0.975098f, 0.979004f, 0.981934f, 0.984863f, 0.986328f,
+ 0.988770f, 0.989746f, 0.990723f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000000f, 0.000608f, 0.001062f, 0.001268f,
+ 0.002001f, 0.003099f, 0.003937f, 0.005379f, 0.007595f, 0.010078f, 0.013176f, 0.018524f, 0.025787f, 0.036896f, 0.054932f, 0.085327f,
+ 0.137573f, 0.229980f, 0.376953f, 0.555664f, 0.708984f, 0.810547f, 0.873047f, 0.909180f, 0.933594f, 0.948730f, 0.959961f, 0.967285f,
+ 0.973145f, 0.977539f, 0.980469f, 0.983398f, 0.985840f, 0.986816f, 0.988770f, 0.989746f, 0.991211f, 0.992188f, 0.993164f, 0.993652f,
+ 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000244f, 0.000606f, 0.000609f, 0.001317f, 0.001564f, 0.002674f, 0.003273f, 0.004402f, 0.005630f, 0.007141f, 0.009514f, 0.012398f,
+ 0.016678f, 0.023331f, 0.032776f, 0.047363f, 0.071594f, 0.112610f, 0.183960f, 0.303711f, 0.470215f, 0.639648f, 0.766113f, 0.844727f,
+ 0.892090f, 0.921875f, 0.941895f, 0.954590f, 0.963379f, 0.970215f, 0.975098f, 0.979004f, 0.981934f, 0.984863f, 0.986328f, 0.987793f,
+ 0.989746f, 0.991211f, 0.991699f, 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f, 0.996094f,
+ 0.996582f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000244f, 0.000244f, 0.000727f, 0.000803f, 0.001575f, 0.002035f, 0.002821f, 0.003527f,
+ 0.004475f, 0.005421f, 0.007023f, 0.009491f, 0.011879f, 0.015976f, 0.021530f, 0.029587f, 0.041809f, 0.061737f, 0.094360f, 0.150146f,
+ 0.246460f, 0.393066f, 0.566406f, 0.712891f, 0.812500f, 0.872070f, 0.909180f, 0.933105f, 0.948242f, 0.959961f, 0.967773f, 0.972656f,
+ 0.977539f, 0.980957f, 0.982910f, 0.986328f, 0.987305f, 0.988770f, 0.989746f, 0.991211f, 0.992188f, 0.993164f, 0.993652f, 0.994629f,
+ 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000244f, 0.000244f, 0.000471f, 0.000727f,
+ 0.000967f, 0.001572f, 0.002161f, 0.002680f, 0.003246f, 0.004337f, 0.005241f, 0.006950f, 0.009087f, 0.011497f, 0.015038f, 0.019913f,
+ 0.026688f, 0.037537f, 0.054352f, 0.080383f, 0.125122f, 0.202515f, 0.327148f, 0.493652f, 0.656250f, 0.774414f, 0.849609f, 0.895508f,
+ 0.923828f, 0.942383f, 0.954590f, 0.963867f, 0.971191f, 0.975586f, 0.979004f, 0.982422f, 0.984863f, 0.987305f, 0.988281f, 0.989746f,
+ 0.990723f, 0.992188f, 0.992676f, 0.993652f, 0.994141f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f,
+ 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999023f,
+ 0.000121f, 0.000244f, 0.000244f, 0.000715f, 0.001089f, 0.001278f, 0.001781f, 0.002275f, 0.002548f, 0.003334f, 0.004150f, 0.005314f,
+ 0.006824f, 0.008430f, 0.011200f, 0.014145f, 0.018631f, 0.024750f, 0.033905f, 0.047760f, 0.069885f, 0.106445f, 0.169312f, 0.273682f,
+ 0.426270f, 0.596191f, 0.732422f, 0.823242f, 0.879883f, 0.914062f, 0.936035f, 0.950684f, 0.960938f, 0.968750f, 0.973633f, 0.978516f,
+ 0.981934f, 0.984375f, 0.986328f, 0.988281f, 0.989258f, 0.990234f, 0.991699f, 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.995117f,
+ 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999512f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999023f, 0.000241f, 0.000244f, 0.000365f, 0.000600f, 0.000961f, 0.000972f, 0.001621f, 0.001697f,
+ 0.002274f, 0.002684f, 0.003359f, 0.004238f, 0.005573f, 0.006691f, 0.008057f, 0.010529f, 0.013832f, 0.017593f, 0.022812f, 0.031174f,
+ 0.042786f, 0.061462f, 0.092407f, 0.143799f, 0.231201f, 0.366943f, 0.535645f, 0.688477f, 0.794922f, 0.861816f, 0.902832f, 0.928711f,
+ 0.945801f, 0.957520f, 0.966797f, 0.972656f, 0.976562f, 0.980469f, 0.983398f, 0.985840f, 0.987793f, 0.989258f, 0.990234f, 0.991699f,
+ 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f, 0.997070f, 0.997070f, 0.997559f, 0.997559f,
+ 0.998047f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000243f, 0.000365f, 0.000365f,
+ 0.000798f, 0.000968f, 0.001249f, 0.001528f, 0.001798f, 0.002457f, 0.002798f, 0.003494f, 0.004353f, 0.005306f, 0.006363f, 0.008141f,
+ 0.010147f, 0.012596f, 0.016006f, 0.021423f, 0.028503f, 0.039185f, 0.055420f, 0.081116f, 0.124390f, 0.198120f, 0.316895f, 0.478516f,
+ 0.641113f, 0.763672f, 0.842773f, 0.891113f, 0.921387f, 0.941406f, 0.954590f, 0.963867f, 0.970215f, 0.975586f, 0.979492f, 0.982910f,
+ 0.985352f, 0.987305f, 0.988770f, 0.989746f, 0.991211f, 0.992188f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f,
+ 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000238f, 0.000365f, 0.000365f, 0.000598f, 0.000820f, 0.001200f, 0.001279f, 0.001631f, 0.001736f, 0.002172f, 0.002874f,
+ 0.003576f, 0.004391f, 0.005096f, 0.006176f, 0.007545f, 0.009674f, 0.012505f, 0.015945f, 0.020187f, 0.026550f, 0.035706f, 0.049835f,
+ 0.072510f, 0.109253f, 0.171631f, 0.275391f, 0.426514f, 0.594238f, 0.730469f, 0.822754f, 0.877930f, 0.913574f, 0.936523f, 0.951172f,
+ 0.961426f, 0.969727f, 0.974609f, 0.978027f, 0.982422f, 0.984863f, 0.986816f, 0.988770f, 0.989746f, 0.991699f, 0.992188f, 0.993164f,
+ 0.993652f, 0.994629f, 0.994629f, 0.995117f, 0.996094f, 0.996094f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000364f, 0.000486f, 0.000487f, 0.000562f, 0.000822f, 0.000967f,
+ 0.001213f, 0.001871f, 0.001803f, 0.002485f, 0.002796f, 0.003410f, 0.004242f, 0.005070f, 0.006153f, 0.007698f, 0.009262f, 0.011635f,
+ 0.014709f, 0.019104f, 0.024521f, 0.033295f, 0.045746f, 0.065674f, 0.096741f, 0.150635f, 0.241455f, 0.380127f, 0.548828f, 0.698242f,
+ 0.802246f, 0.867188f, 0.906738f, 0.931152f, 0.948242f, 0.959473f, 0.967285f, 0.973633f, 0.978516f, 0.981445f, 0.984375f, 0.986328f,
+ 0.988281f, 0.989258f, 0.990723f, 0.992188f, 0.993164f, 0.993652f, 0.994629f, 0.994629f, 0.995117f, 0.996094f, 0.996582f, 0.996582f,
+ 0.997559f, 0.997559f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000350f, 0.000483f,
+ 0.000486f, 0.000604f, 0.000743f, 0.001093f, 0.001187f, 0.001297f, 0.001601f, 0.001921f, 0.002501f, 0.002922f, 0.003296f, 0.004200f,
+ 0.005211f, 0.006054f, 0.007603f, 0.008904f, 0.011169f, 0.014091f, 0.017685f, 0.023331f, 0.030991f, 0.042358f, 0.059326f, 0.087646f,
+ 0.134521f, 0.213867f, 0.341309f, 0.506348f, 0.665039f, 0.780762f, 0.854492f, 0.899414f, 0.927246f, 0.945312f, 0.957520f, 0.966309f,
+ 0.973145f, 0.977539f, 0.981445f, 0.984375f, 0.986328f, 0.988770f, 0.989746f, 0.991211f, 0.992188f, 0.993164f, 0.993652f, 0.994629f,
+ 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000000f, 0.000120f, 0.000360f, 0.000485f, 0.000486f, 0.000487f, 0.000604f, 0.000947f, 0.001201f, 0.001374f, 0.001715f,
+ 0.002127f, 0.002239f, 0.002876f, 0.003426f, 0.004063f, 0.005276f, 0.005810f, 0.006744f, 0.008713f, 0.010597f, 0.013680f, 0.016754f,
+ 0.021744f, 0.028778f, 0.039093f, 0.054901f, 0.079956f, 0.121399f, 0.191895f, 0.307861f, 0.468262f, 0.633301f, 0.760742f, 0.842285f,
+ 0.892090f, 0.923340f, 0.942383f, 0.956543f, 0.965332f, 0.972168f, 0.977539f, 0.980469f, 0.983887f, 0.985840f, 0.988281f, 0.989746f,
+ 0.990723f, 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000121f, 0.000219f, 0.000474f, 0.000484f, 0.000486f, 0.000487f,
+ 0.000720f, 0.001108f, 0.001199f, 0.001209f, 0.001689f, 0.002253f, 0.002489f, 0.002916f, 0.003714f, 0.004040f, 0.005054f, 0.006001f,
+ 0.006737f, 0.008713f, 0.010376f, 0.012665f, 0.016251f, 0.020615f, 0.027145f, 0.036499f, 0.050720f, 0.073181f, 0.110474f, 0.174072f,
+ 0.280518f, 0.434570f, 0.604980f, 0.742188f, 0.830566f, 0.885742f, 0.918945f, 0.940918f, 0.954102f, 0.964355f, 0.971680f, 0.977051f,
+ 0.980957f, 0.984375f, 0.986816f, 0.988281f, 0.989746f, 0.990723f, 0.992188f, 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996582f, 0.997070f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000000f, 0.000120f, 0.000239f,
+ 0.000319f, 0.000475f, 0.000484f, 0.000485f, 0.000618f, 0.000844f, 0.001094f, 0.001201f, 0.001570f, 0.001782f, 0.002010f, 0.002407f,
+ 0.003046f, 0.003099f, 0.004208f, 0.004700f, 0.005882f, 0.006878f, 0.007980f, 0.009949f, 0.012344f, 0.015358f, 0.019821f, 0.026047f,
+ 0.034271f, 0.047455f, 0.067993f, 0.102112f, 0.160034f, 0.258057f, 0.406494f, 0.578613f, 0.723633f, 0.820312f, 0.880371f, 0.916016f,
+ 0.938965f, 0.953125f, 0.963867f, 0.971191f, 0.976562f, 0.980469f, 0.983887f, 0.985840f, 0.988770f, 0.989746f, 0.991699f, 0.992676f,
+ 0.993652f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.999023f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000242f, 0.000455f, 0.000481f, 0.000583f, 0.000601f, 0.000804f, 0.000912f, 0.001247f,
+ 0.001319f, 0.001571f, 0.001793f, 0.002337f, 0.002464f, 0.003099f, 0.003164f, 0.003809f, 0.004627f, 0.005764f, 0.006397f, 0.008118f,
+ 0.009605f, 0.011917f, 0.015083f, 0.018692f, 0.024384f, 0.032806f, 0.044983f, 0.063477f, 0.095337f, 0.148560f, 0.240112f, 0.382324f,
+ 0.556641f, 0.708984f, 0.812500f, 0.875488f, 0.913574f, 0.937500f, 0.953125f, 0.963867f, 0.971191f, 0.977051f, 0.980957f, 0.983887f,
+ 0.986816f, 0.988281f, 0.990234f, 0.992188f, 0.993164f, 0.993652f, 0.994141f, 0.995605f, 0.995605f, 0.996094f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000240f, 0.000242f, 0.000524f, 0.000597f,
+ 0.000604f, 0.000606f, 0.000674f, 0.001040f, 0.001238f, 0.001427f, 0.001637f, 0.001670f, 0.002104f, 0.002432f, 0.002775f, 0.003416f,
+ 0.003860f, 0.004482f, 0.005573f, 0.006374f, 0.007828f, 0.009384f, 0.011635f, 0.014175f, 0.018219f, 0.023224f, 0.031052f, 0.042603f,
+ 0.060730f, 0.089661f, 0.139526f, 0.225464f, 0.363525f, 0.538574f, 0.696289f, 0.806152f, 0.872559f, 0.912109f, 0.937012f, 0.952637f,
+ 0.963867f, 0.971191f, 0.976562f, 0.981445f, 0.984863f, 0.987305f, 0.988770f, 0.990723f, 0.992188f, 0.993164f, 0.994141f, 0.994629f,
+ 0.995117f, 0.996094f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000119f,
+ 0.000192f, 0.000240f, 0.000242f, 0.000535f, 0.000478f, 0.000600f, 0.000843f, 0.000925f, 0.001027f, 0.001236f, 0.001502f, 0.001490f,
+ 0.001658f, 0.002256f, 0.002430f, 0.002880f, 0.003056f, 0.003983f, 0.004292f, 0.005333f, 0.006264f, 0.007393f, 0.009064f, 0.011131f,
+ 0.013741f, 0.017242f, 0.022690f, 0.029922f, 0.040680f, 0.057831f, 0.085022f, 0.132446f, 0.214844f, 0.349121f, 0.524414f, 0.688477f,
+ 0.801758f, 0.871094f, 0.912109f, 0.937500f, 0.953125f, 0.964355f, 0.971680f, 0.977539f, 0.981445f, 0.985352f, 0.987305f, 0.989258f,
+ 0.991211f, 0.992188f, 0.993652f, 0.994629f, 0.995117f, 0.995605f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000119f, 0.000232f, 0.000233f, 0.000363f, 0.000457f, 0.000714f, 0.000724f, 0.000727f,
+ 0.000847f, 0.000992f, 0.001177f, 0.001525f, 0.001560f, 0.001740f, 0.002090f, 0.002329f, 0.002718f, 0.003372f, 0.003902f, 0.004307f,
+ 0.005184f, 0.005886f, 0.007446f, 0.008667f, 0.010574f, 0.013588f, 0.016556f, 0.021744f, 0.028854f, 0.039124f, 0.055176f, 0.081726f,
+ 0.127075f, 0.206421f, 0.338867f, 0.515625f, 0.683105f, 0.800293f, 0.870605f, 0.912598f, 0.937500f, 0.954590f, 0.965332f, 0.973145f,
+ 0.978516f, 0.982422f, 0.985840f, 0.988281f, 0.989746f, 0.991211f, 0.992676f, 0.993652f, 0.994141f, 0.995117f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000103f, 0.000120f, 0.000240f, 0.000240f,
+ 0.000484f, 0.000574f, 0.000596f, 0.000837f, 0.000820f, 0.000859f, 0.000985f, 0.001070f, 0.001509f, 0.001554f, 0.001785f, 0.002214f,
+ 0.002476f, 0.002754f, 0.002991f, 0.003487f, 0.004303f, 0.005074f, 0.005920f, 0.007126f, 0.008743f, 0.010361f, 0.013023f, 0.016403f,
+ 0.021011f, 0.027817f, 0.037811f, 0.053375f, 0.079041f, 0.123291f, 0.201172f, 0.333252f, 0.511719f, 0.682129f, 0.801270f, 0.872070f,
+ 0.914062f, 0.939941f, 0.955078f, 0.966309f, 0.973633f, 0.979004f, 0.982910f, 0.986328f, 0.988770f, 0.990234f, 0.991699f, 0.992676f,
+ 0.993652f, 0.995117f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000079f, 0.000053f, 0.000118f, 0.000418f, 0.000358f, 0.000363f, 0.000678f, 0.000708f, 0.000825f, 0.000838f, 0.000878f, 0.001146f,
+ 0.000978f, 0.001483f, 0.001541f, 0.001769f, 0.001812f, 0.002434f, 0.002699f, 0.003225f, 0.003298f, 0.004002f, 0.004948f, 0.005932f,
+ 0.007084f, 0.008461f, 0.010414f, 0.012665f, 0.015915f, 0.020615f, 0.027023f, 0.036743f, 0.051941f, 0.077332f, 0.120789f, 0.198608f,
+ 0.331543f, 0.512695f, 0.686523f, 0.805664f, 0.875488f, 0.917480f, 0.941406f, 0.957031f, 0.968262f, 0.975098f, 0.980469f, 0.983887f,
+ 0.986816f, 0.989258f, 0.990723f, 0.992188f, 0.993164f, 0.994629f, 0.998047f, 0.998047f, 0.998535f, 0.998047f, 0.998535f, 0.998535f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000109f, 0.000232f, 0.000349f, 0.000478f, 0.000483f, 0.000483f, 0.000609f,
+ 0.000795f, 0.000835f, 0.000806f, 0.000726f, 0.001022f, 0.001222f, 0.001442f, 0.001536f, 0.001650f, 0.001714f, 0.002377f, 0.002588f,
+ 0.003159f, 0.003643f, 0.004036f, 0.004929f, 0.005718f, 0.006813f, 0.008072f, 0.009880f, 0.012527f, 0.015854f, 0.020035f, 0.026352f,
+ 0.035950f, 0.051178f, 0.076416f, 0.119751f, 0.198730f, 0.334229f, 0.519531f, 0.694824f, 0.812988f, 0.880859f, 0.920898f, 0.944336f,
+ 0.958984f, 0.969727f, 0.976562f, 0.980957f, 0.984863f, 0.987793f, 0.989746f, 0.991211f, 0.992676f, 0.993652f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000068f, 0.000265f,
+ 0.000361f, 0.000478f, 0.000480f, 0.000479f, 0.000568f, 0.000693f, 0.000714f, 0.000806f, 0.000843f, 0.000919f, 0.001222f, 0.001376f,
+ 0.001531f, 0.001554f, 0.001987f, 0.002342f, 0.002558f, 0.002798f, 0.003132f, 0.004021f, 0.004864f, 0.005455f, 0.006664f, 0.008110f,
+ 0.009613f, 0.011955f, 0.015335f, 0.019608f, 0.025879f, 0.035522f, 0.050629f, 0.075623f, 0.120239f, 0.201416f, 0.342041f, 0.533203f,
+ 0.707031f, 0.821777f, 0.887695f, 0.925293f, 0.946777f, 0.961914f, 0.971680f, 0.977539f, 0.982422f, 0.985352f, 0.988281f, 0.989746f,
+ 0.992188f, 0.993164f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000000f, 0.000122f, 0.000322f, 0.000241f, 0.000478f, 0.000480f, 0.000480f, 0.000510f, 0.000695f, 0.000710f,
+ 0.000958f, 0.000765f, 0.001075f, 0.001116f, 0.001318f, 0.001606f, 0.001546f, 0.001916f, 0.002306f, 0.002499f, 0.002905f, 0.003202f,
+ 0.003914f, 0.004498f, 0.005459f, 0.006611f, 0.007687f, 0.009331f, 0.011757f, 0.014923f, 0.019241f, 0.025833f, 0.035492f, 0.050507f,
+ 0.076233f, 0.122131f, 0.207153f, 0.355225f, 0.551758f, 0.724609f, 0.833496f, 0.894531f, 0.930664f, 0.951660f, 0.964844f, 0.973145f,
+ 0.979492f, 0.983887f, 0.986816f, 0.989258f, 0.991211f, 0.993164f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.997559f, 0.997559f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000351f, 0.000458f, 0.000476f,
+ 0.000480f, 0.000482f, 0.000528f, 0.000650f, 0.000704f, 0.000956f, 0.000828f, 0.000963f, 0.001111f, 0.001265f, 0.001474f, 0.001806f,
+ 0.001872f, 0.002308f, 0.002445f, 0.002701f, 0.003229f, 0.003851f, 0.004375f, 0.005356f, 0.006317f, 0.007458f, 0.009300f, 0.011574f,
+ 0.014725f, 0.019165f, 0.025696f, 0.035461f, 0.050812f, 0.077637f, 0.125977f, 0.216797f, 0.374756f, 0.576660f, 0.745117f, 0.848145f,
+ 0.904785f, 0.936523f, 0.956055f, 0.967773f, 0.975586f, 0.980957f, 0.984863f, 0.987793f, 0.990234f, 0.992188f, 0.997070f, 0.997559f,
+ 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000292f, 0.000224f, 0.000452f, 0.000453f, 0.000479f, 0.000480f, 0.000517f, 0.000614f, 0.000902f, 0.000712f, 0.000959f,
+ 0.000978f, 0.001100f, 0.001276f, 0.001461f, 0.001524f, 0.001651f, 0.002041f, 0.002350f, 0.002853f, 0.003433f, 0.003622f, 0.004166f,
+ 0.005043f, 0.006187f, 0.007534f, 0.009209f, 0.011551f, 0.014908f, 0.019012f, 0.025406f, 0.035461f, 0.051575f, 0.079651f, 0.131714f,
+ 0.230957f, 0.401367f, 0.607910f, 0.769531f, 0.863281f, 0.914062f, 0.942871f, 0.959961f, 0.970703f, 0.978027f, 0.982910f, 0.986816f,
+ 0.988770f, 0.991699f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000238f, 0.000355f, 0.000449f, 0.000462f, 0.000474f, 0.000477f,
+ 0.000482f, 0.000846f, 0.000726f, 0.000706f, 0.000953f, 0.000889f, 0.001012f, 0.001259f, 0.001390f, 0.001755f, 0.001658f, 0.002060f,
+ 0.002369f, 0.002539f, 0.003170f, 0.003460f, 0.004131f, 0.004993f, 0.006008f, 0.007431f, 0.009109f, 0.011444f, 0.014252f, 0.019058f,
+ 0.025574f, 0.036011f, 0.053162f, 0.083435f, 0.140381f, 0.250488f, 0.436035f, 0.645996f, 0.795898f, 0.880371f, 0.924316f, 0.949219f,
+ 0.963867f, 0.973145f, 0.980469f, 0.984863f, 0.988281f, 0.990723f, 0.997070f, 0.997559f, 0.997070f, 0.997559f, 0.997559f, 0.997070f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000239f,
+ 0.000306f, 0.000440f, 0.000437f, 0.000474f, 0.000478f, 0.000481f, 0.000523f, 0.000664f, 0.000731f, 0.000802f, 0.000935f, 0.001022f,
+ 0.001173f, 0.001314f, 0.001504f, 0.001831f, 0.001984f, 0.002317f, 0.002472f, 0.003199f, 0.003370f, 0.004189f, 0.004868f, 0.005924f,
+ 0.007320f, 0.008926f, 0.011421f, 0.014595f, 0.019119f, 0.026260f, 0.036987f, 0.055176f, 0.088440f, 0.152466f, 0.277832f, 0.479980f,
+ 0.686523f, 0.823242f, 0.895508f, 0.933105f, 0.955566f, 0.969238f, 0.976562f, 0.982422f, 0.986816f, 0.989746f, 0.996582f, 0.997070f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000194f, 0.000280f, 0.000417f, 0.000448f, 0.000468f, 0.000476f, 0.000479f, 0.000490f,
+ 0.000845f, 0.000688f, 0.000740f, 0.000945f, 0.000998f, 0.001148f, 0.001266f, 0.001414f, 0.001475f, 0.001667f, 0.002262f, 0.002537f,
+ 0.003019f, 0.003288f, 0.004223f, 0.004768f, 0.005890f, 0.007259f, 0.009026f, 0.011360f, 0.014297f, 0.019272f, 0.026474f, 0.038116f,
+ 0.058197f, 0.095032f, 0.168945f, 0.313965f, 0.533203f, 0.731445f, 0.850098f, 0.911133f, 0.942871f, 0.961914f, 0.972656f, 0.979980f,
+ 0.984863f, 0.988770f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.000000f, 0.000000f, 0.000122f, 0.000000f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000187f, 0.000233f, 0.000141f, 0.000271f, 0.000341f,
+ 0.000380f, 0.000465f, 0.000473f, 0.000590f, 0.000605f, 0.000798f, 0.000847f, 0.000934f, 0.000946f, 0.000836f, 0.001009f, 0.001142f,
+ 0.001430f, 0.001495f, 0.001850f, 0.002111f, 0.002541f, 0.003035f, 0.003300f, 0.004139f, 0.004913f, 0.005718f, 0.007141f, 0.008934f,
+ 0.011475f, 0.014832f, 0.019653f, 0.027573f, 0.039917f, 0.062225f, 0.104919f, 0.192017f, 0.362305f, 0.594238f, 0.775879f, 0.875977f,
+ 0.925293f, 0.952148f, 0.967773f, 0.977051f, 0.983398f, 0.988281f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.996094f, 0.996582f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000238f, 0.000243f, 0.000238f, 0.000424f, 0.000453f, 0.000467f, 0.000475f, 0.000581f, 0.000689f, 0.000795f,
+ 0.000634f, 0.000823f, 0.001014f, 0.000900f, 0.001083f, 0.001485f, 0.001731f, 0.001851f, 0.002056f, 0.002373f, 0.002621f, 0.003445f,
+ 0.004082f, 0.004578f, 0.005821f, 0.007217f, 0.008881f, 0.011330f, 0.014778f, 0.020416f, 0.028473f, 0.042419f, 0.067993f, 0.118286f,
+ 0.225342f, 0.425293f, 0.661621f, 0.818848f, 0.899902f, 0.939453f, 0.960449f, 0.973145f, 0.980957f, 0.985840f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000205f, 0.000224f, 0.000122f, 0.000231f, 0.000245f, 0.000411f, 0.000520f,
+ 0.000463f, 0.000470f, 0.000587f, 0.000361f, 0.000712f, 0.000694f, 0.000815f, 0.000978f, 0.001055f, 0.001105f, 0.001390f, 0.001438f,
+ 0.001705f, 0.001984f, 0.002333f, 0.002546f, 0.003408f, 0.003876f, 0.004627f, 0.005783f, 0.007198f, 0.008995f, 0.011383f, 0.015396f,
+ 0.020828f, 0.030029f, 0.045654f, 0.075439f, 0.137451f, 0.271973f, 0.503418f, 0.728516f, 0.857910f, 0.920410f, 0.951172f, 0.968262f,
+ 0.977539f, 0.984375f, 0.995117f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000173f, 0.000150f, 0.000278f, 0.000376f, 0.000427f, 0.000470f, 0.000352f, 0.000356f, 0.000475f, 0.000441f, 0.000709f, 0.000774f,
+ 0.000970f, 0.001013f, 0.000998f, 0.001193f, 0.001397f, 0.001677f, 0.001957f, 0.002268f, 0.002529f, 0.003353f, 0.003874f, 0.004555f,
+ 0.005692f, 0.007160f, 0.008987f, 0.011543f, 0.015732f, 0.021896f, 0.032135f, 0.050140f, 0.086548f, 0.165894f, 0.337646f, 0.593750f,
+ 0.791504f, 0.892090f, 0.938477f, 0.961914f, 0.974609f, 0.982422f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.995117f, 0.995605f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000187f, 0.000130f, 0.000231f, 0.000315f, 0.000298f, 0.000332f, 0.000343f,
+ 0.000465f, 0.000472f, 0.000579f, 0.000717f, 0.000839f, 0.000932f, 0.000817f, 0.001086f, 0.001090f, 0.001545f, 0.001735f, 0.001837f,
+ 0.002485f, 0.002493f, 0.003288f, 0.003828f, 0.004520f, 0.005833f, 0.007156f, 0.009193f, 0.012123f, 0.015839f, 0.022934f, 0.034760f,
+ 0.056488f, 0.102600f, 0.208862f, 0.427734f, 0.687988f, 0.846191f, 0.919434f, 0.952637f, 0.969727f, 0.979980f, 0.993652f, 0.994629f,
+ 0.994141f, 0.994629f, 0.994629f, 0.994629f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000133f,
+ 0.000141f, 0.000234f, 0.000300f, 0.000397f, 0.000436f, 0.000456f, 0.000465f, 0.000534f, 0.000663f, 0.000810f, 0.000796f, 0.000812f,
+ 0.001062f, 0.001237f, 0.001428f, 0.001565f, 0.001818f, 0.002182f, 0.002783f, 0.002943f, 0.003773f, 0.004715f, 0.005482f, 0.007195f,
+ 0.009285f, 0.012207f, 0.016922f, 0.024567f, 0.038483f, 0.066101f, 0.127563f, 0.274170f, 0.540527f, 0.774414f, 0.891113f, 0.940430f,
+ 0.965332f, 0.977539f, 0.993652f, 0.994141f, 0.994629f, 0.994141f, 0.994629f, 0.994141f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000124f, 0.000116f, 0.000119f, 0.000125f, 0.000121f, 0.000197f, 0.000323f, 0.000418f, 0.000446f, 0.000433f,
+ 0.000467f, 0.000612f, 0.000710f, 0.000783f, 0.000911f, 0.000817f, 0.001161f, 0.001343f, 0.001514f, 0.001707f, 0.002081f, 0.002386f,
+ 0.002882f, 0.003609f, 0.004627f, 0.005478f, 0.007011f, 0.009384f, 0.012695f, 0.017960f, 0.026901f, 0.044067f, 0.080078f, 0.167114f,
+ 0.374023f, 0.664062f, 0.845703f, 0.923340f, 0.957031f, 0.974121f, 0.992676f, 0.993652f, 0.993164f, 0.993652f, 0.993652f, 0.993164f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000121f, 0.000121f, 0.000052f, 0.000039f, 0.000029f, 0.000054f, 0.000045f, 0.000118f,
+ 0.000128f, 0.000231f, 0.000387f, 0.000429f, 0.000446f, 0.000544f, 0.000539f, 0.000648f, 0.000749f, 0.000790f, 0.000978f, 0.001102f,
+ 0.001195f, 0.001501f, 0.001761f, 0.001978f, 0.002661f, 0.003170f, 0.003519f, 0.004509f, 0.005344f, 0.007004f, 0.009361f, 0.013229f,
+ 0.019196f, 0.030258f, 0.052002f, 0.102661f, 0.234131f, 0.511230f, 0.774902f, 0.898438f, 0.947754f, 0.970215f, 0.992188f, 0.992676f,
+ 0.993164f, 0.992676f, 0.992188f, 0.992188f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000070f, 0.000052f,
+ 0.000038f, 0.000030f, 0.000023f, 0.000060f, 0.000116f, 0.000121f, 0.000252f, 0.000337f, 0.000306f, 0.000435f, 0.000450f, 0.000562f,
+ 0.000584f, 0.000722f, 0.000858f, 0.000888f, 0.000969f, 0.001230f, 0.001429f, 0.001576f, 0.001827f, 0.002361f, 0.002863f, 0.003267f,
+ 0.004047f, 0.005394f, 0.007256f, 0.009781f, 0.013855f, 0.021439f, 0.035034f, 0.065063f, 0.141724f, 0.346680f, 0.665527f, 0.859375f,
+ 0.934570f, 0.965820f, 0.991699f, 0.991699f, 0.991699f, 0.992188f, 0.991699f, 0.991699f, 0.000000f, 0.000000f, 0.000122f, 0.000121f,
+ 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000099f, 0.000069f, 0.000051f, 0.000039f, 0.000030f, 0.000023f, 0.000024f, 0.000115f, 0.000103f, 0.000224f,
+ 0.000204f, 0.000339f, 0.000407f, 0.000437f, 0.000452f, 0.000489f, 0.000663f, 0.000821f, 0.000922f, 0.001004f, 0.001086f, 0.001279f,
+ 0.001554f, 0.001651f, 0.001997f, 0.002390f, 0.003136f, 0.004223f, 0.005508f, 0.007339f, 0.010094f, 0.014854f, 0.024048f, 0.042664f,
+ 0.087036f, 0.213867f, 0.516113f, 0.799805f, 0.915527f, 0.958984f, 0.990723f, 0.991211f, 0.990723f, 0.990723f, 0.990723f, 0.991211f,
+ 0.000000f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000096f, 0.000073f, 0.000053f, 0.000040f, 0.000031f,
+ 0.000025f, 0.000020f, 0.000017f, 0.000105f, 0.000110f, 0.000135f, 0.000235f, 0.000380f, 0.000462f, 0.000513f, 0.000556f, 0.000638f,
+ 0.000804f, 0.000868f, 0.000897f, 0.001002f, 0.001079f, 0.001246f, 0.001596f, 0.002153f, 0.002213f, 0.003094f, 0.004158f, 0.005306f,
+ 0.007458f, 0.010887f, 0.017166f, 0.028748f, 0.055176f, 0.128174f, 0.350586f, 0.703613f, 0.888184f, 0.951172f, 0.988770f, 0.989746f,
+ 0.989746f, 0.989746f, 0.989746f, 0.989746f, 0.000122f, 0.000120f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000101f, 0.000073f, 0.000057f, 0.000043f, 0.000033f, 0.000027f, 0.000021f, 0.000018f, 0.000105f, 0.000112f, 0.000111f, 0.000161f,
+ 0.000320f, 0.000390f, 0.000421f, 0.000438f, 0.000559f, 0.000665f, 0.000735f, 0.000719f, 0.000704f, 0.000887f, 0.001223f, 0.001384f,
+ 0.001867f, 0.002462f, 0.003216f, 0.004032f, 0.005367f, 0.007988f, 0.012054f, 0.019943f, 0.035919f, 0.078064f, 0.215332f, 0.566895f,
+ 0.845703f, 0.939941f, 0.987793f, 0.988281f, 0.987793f, 0.987793f, 0.988281f, 0.988281f, 0.000000f, 0.000120f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000103f, 0.000077f, 0.000061f, 0.000046f, 0.000037f, 0.000030f, 0.000023f,
+ 0.000019f, 0.000016f, 0.000039f, 0.000094f, 0.000181f, 0.000205f, 0.000350f, 0.000392f, 0.000423f, 0.000510f, 0.000619f, 0.000672f,
+ 0.000705f, 0.000632f, 0.000807f, 0.001038f, 0.001278f, 0.001894f, 0.002245f, 0.002758f, 0.003883f, 0.005863f, 0.008636f, 0.013672f,
+ 0.023880f, 0.048828f, 0.127441f, 0.400879f, 0.779297f, 0.925781f, 0.985840f, 0.986328f, 0.986328f, 0.985840f, 0.986328f, 0.986328f,
+ 0.000000f, 0.000100f, 0.000108f, 0.000118f, 0.000119f, 0.000118f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000111f, 0.000086f,
+ 0.000066f, 0.000051f, 0.000041f, 0.000032f, 0.000026f, 0.000021f, 0.000018f, 0.000015f, 0.000086f, 0.000131f, 0.000190f, 0.000293f,
+ 0.000419f, 0.000481f, 0.000477f, 0.000438f, 0.000542f, 0.000564f, 0.000599f, 0.000700f, 0.000916f, 0.001122f, 0.001589f, 0.001997f,
+ 0.002678f, 0.004017f, 0.005814f, 0.009361f, 0.015808f, 0.031250f, 0.075989f, 0.250732f, 0.676758f, 0.904297f, 0.983887f, 0.983887f,
+ 0.983887f, 0.984375f, 0.984375f, 0.983887f, 0.000000f, 0.000000f, 0.000077f, 0.000112f, 0.000104f, 0.000115f, 0.000115f, 0.000117f,
+ 0.000117f, 0.000117f, 0.000118f, 0.000118f, 0.000118f, 0.000118f, 0.000119f, 0.000118f, 0.000119f, 0.000119f, 0.000119f, 0.000119f,
+ 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000097f, 0.000076f, 0.000060f, 0.000046f, 0.000037f, 0.000030f, 0.000024f, 0.000020f,
+ 0.000045f, 0.000063f, 0.000091f, 0.000140f, 0.000202f, 0.000333f, 0.000305f, 0.000399f, 0.000462f, 0.000452f, 0.000535f, 0.000531f,
+ 0.000631f, 0.000866f, 0.000858f, 0.001307f, 0.001844f, 0.002823f, 0.004070f, 0.006264f, 0.010536f, 0.020035f, 0.045990f, 0.145996f,
+ 0.532227f, 0.874023f, 0.980957f, 0.981445f, 0.980957f, 0.981445f, 0.980957f, 0.981445f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000091f, 0.000103f, 0.000105f, 0.000106f, 0.000111f, 0.000113f, 0.000115f, 0.000114f, 0.000116f, 0.000116f, 0.000117f, 0.000117f,
+ 0.000117f, 0.000117f, 0.000117f, 0.000118f, 0.000118f, 0.000118f, 0.000118f, 0.000118f, 0.000118f, 0.000112f, 0.000084f, 0.000069f,
+ 0.000055f, 0.000043f, 0.000036f, 0.000028f, 0.000024f, 0.000020f, 0.000028f, 0.000039f, 0.000083f, 0.000141f, 0.000211f, 0.000262f,
+ 0.000413f, 0.000305f, 0.000370f, 0.000358f, 0.000489f, 0.000564f, 0.000599f, 0.000893f, 0.001084f, 0.001696f, 0.002697f, 0.004074f,
+ 0.006836f, 0.012878f, 0.028122f, 0.083496f, 0.364014f, 0.826660f, 0.976562f, 0.977539f, 0.977051f, 0.977539f, 0.978027f, 0.977051f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000015f, 0.000086f, 0.000077f, 0.000103f, 0.000100f, 0.000109f,
+ 0.000110f, 0.000111f, 0.000112f, 0.000112f, 0.000114f, 0.000114f, 0.000115f, 0.000115f, 0.000116f, 0.000115f, 0.000116f, 0.000116f,
+ 0.000117f, 0.000117f, 0.000117f, 0.000100f, 0.000079f, 0.000066f, 0.000053f, 0.000041f, 0.000035f, 0.000028f, 0.000023f, 0.000019f,
+ 0.000017f, 0.000034f, 0.000113f, 0.000174f, 0.000257f, 0.000325f, 0.000356f, 0.000324f, 0.000409f, 0.000454f, 0.000474f, 0.000659f,
+ 0.000778f, 0.001243f, 0.001575f, 0.002472f, 0.004105f, 0.007957f, 0.016800f, 0.047852f, 0.217529f, 0.755371f, 0.972656f, 0.973145f,
+ 0.973145f, 0.973145f, 0.973145f, 0.973145f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000028f, 0.000049f, 0.000085f, 0.000081f, 0.000096f, 0.000101f, 0.000104f, 0.000106f, 0.000108f, 0.000109f, 0.000110f,
+ 0.000111f, 0.000112f, 0.000113f, 0.000113f, 0.000114f, 0.000114f, 0.000114f, 0.000115f, 0.000115f, 0.000096f, 0.000078f, 0.000064f,
+ 0.000051f, 0.000043f, 0.000035f, 0.000029f, 0.000024f, 0.000020f, 0.000026f, 0.000055f, 0.000087f, 0.000135f, 0.000248f, 0.000261f,
+ 0.000274f, 0.000258f, 0.000296f, 0.000359f, 0.000474f, 0.000627f, 0.001012f, 0.001484f, 0.002630f, 0.004536f, 0.010277f, 0.027405f,
+ 0.119507f, 0.645996f, 0.966797f, 0.967285f, 0.967285f, 0.967285f, 0.966797f, 0.966797f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000014f, 0.000021f, 0.000065f, 0.000074f,
+ 0.000077f, 0.000091f, 0.000091f, 0.000099f, 0.000098f, 0.000103f, 0.000103f, 0.000106f, 0.000107f, 0.000108f, 0.000109f, 0.000110f,
+ 0.000111f, 0.000111f, 0.000112f, 0.000096f, 0.000079f, 0.000064f, 0.000053f, 0.000043f, 0.000036f, 0.000030f, 0.000024f, 0.000021f,
+ 0.000018f, 0.000028f, 0.000072f, 0.000125f, 0.000233f, 0.000243f, 0.000220f, 0.000258f, 0.000320f, 0.000353f, 0.000630f, 0.000932f,
+ 0.001324f, 0.002357f, 0.005402f, 0.014534f, 0.062561f, 0.493164f, 0.958008f, 0.958008f, 0.958984f, 0.958496f, 0.958496f, 0.958008f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000011f, 0.000035f, 0.000041f, 0.000064f, 0.000074f, 0.000081f, 0.000082f, 0.000090f,
+ 0.000092f, 0.000096f, 0.000099f, 0.000100f, 0.000102f, 0.000104f, 0.000105f, 0.000106f, 0.000107f, 0.000099f, 0.000082f, 0.000067f,
+ 0.000055f, 0.000047f, 0.000038f, 0.000031f, 0.000026f, 0.000022f, 0.000018f, 0.000037f, 0.000071f, 0.000111f, 0.000190f, 0.000204f,
+ 0.000153f, 0.000245f, 0.000299f, 0.000482f, 0.000790f, 0.001330f, 0.002619f, 0.007282f, 0.031097f, 0.318115f, 0.946289f, 0.946777f,
+ 0.946777f, 0.946777f, 0.946777f, 0.946777f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000008f, 0.000029f, 0.000044f, 0.000055f, 0.000063f, 0.000073f, 0.000075f, 0.000081f, 0.000087f, 0.000090f, 0.000092f,
+ 0.000094f, 0.000097f, 0.000099f, 0.000100f, 0.000087f, 0.000071f, 0.000059f, 0.000049f, 0.000040f, 0.000034f, 0.000028f, 0.000024f,
+ 0.000020f, 0.000016f, 0.000072f, 0.000114f, 0.000169f, 0.000147f, 0.000181f, 0.000246f, 0.000367f, 0.000626f, 0.001325f, 0.003117f,
+ 0.013741f, 0.167480f, 0.929688f, 0.929688f, 0.929688f, 0.930176f, 0.930664f, 0.930176f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000019f,
+ 0.000030f, 0.000044f, 0.000049f, 0.000062f, 0.000068f, 0.000072f, 0.000078f, 0.000081f, 0.000084f, 0.000087f, 0.000090f, 0.000079f,
+ 0.000065f, 0.000054f, 0.000044f, 0.000037f, 0.000030f, 0.000025f, 0.000021f, 0.000017f, 0.000052f, 0.000100f, 0.000132f, 0.000130f,
+ 0.000164f, 0.000297f, 0.000552f, 0.001273f, 0.005009f, 0.071594f, 0.903809f, 0.905273f, 0.904297f, 0.904785f, 0.904785f, 0.904785f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000013f, 0.000028f, 0.000036f,
+ 0.000045f, 0.000053f, 0.000060f, 0.000066f, 0.000071f, 0.000075f, 0.000071f, 0.000058f, 0.000049f, 0.000040f, 0.000033f, 0.000027f,
+ 0.000022f, 0.000018f, 0.000032f, 0.000078f, 0.000090f, 0.000123f, 0.000175f, 0.000441f, 0.001637f, 0.022537f, 0.865234f, 0.865234f,
+ 0.865723f, 0.865723f, 0.865234f, 0.864746f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000004f, 0.000017f, 0.000027f, 0.000036f, 0.000042f,
+ 0.000050f, 0.000056f, 0.000052f, 0.000043f, 0.000035f, 0.000028f, 0.000022f, 0.000018f, 0.000049f, 0.000055f, 0.000047f, 0.000108f,
+ 0.000342f, 0.004566f, 0.802734f, 0.803711f, 0.803711f, 0.803711f, 0.803711f, 0.803711f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000013f, 0.000022f, 0.000030f, 0.000033f, 0.000027f,
+ 0.000021f, 0.000015f, 0.000011f, 0.000031f, 0.000045f, 0.000449f, 0.708496f, 0.707520f, 0.708984f, 0.708496f, 0.707520f, 0.708008f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000004f, 0.000011f, 0.000006f, 0.000007f, 0.575195f, 0.575195f,
+ 0.575195f, 0.575195f, 0.575195f, 0.575195f,
+ },
+ {
+ 0.158813f, 0.632812f, 0.824219f, 0.891602f, 0.924805f, 0.942383f, 0.954102f, 0.962402f, 0.968262f, 0.972656f, 0.976074f, 0.978516f,
+ 0.980957f, 0.982910f, 0.984375f, 0.985840f, 0.986816f, 0.988770f, 0.989746f, 0.989746f, 0.990234f, 0.991211f, 0.992188f, 0.992676f,
+ 0.993652f, 0.993652f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.996582f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.019775f, 0.115845f, 0.361084f, 0.642578f, 0.798340f, 0.872559f, 0.911133f, 0.933594f,
+ 0.947266f, 0.957031f, 0.964355f, 0.968750f, 0.973145f, 0.976562f, 0.979492f, 0.981934f, 0.983398f, 0.984863f, 0.986816f, 0.987793f,
+ 0.988770f, 0.989258f, 0.990234f, 0.991211f, 0.991699f, 0.992676f, 0.993164f, 0.993164f, 0.993652f, 0.994141f, 0.995117f, 0.995117f,
+ 0.995605f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.006638f, 0.031082f, 0.089661f, 0.222168f,
+ 0.448242f, 0.663086f, 0.794434f, 0.864258f, 0.903320f, 0.926758f, 0.942383f, 0.953613f, 0.961426f, 0.966797f, 0.972168f, 0.975586f,
+ 0.978027f, 0.980469f, 0.982910f, 0.984375f, 0.985840f, 0.986816f, 0.988281f, 0.989258f, 0.990234f, 0.991211f, 0.991699f, 0.992188f,
+ 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.996582f,
+ 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.003246f, 0.013367f, 0.032806f, 0.072754f, 0.152954f, 0.304199f, 0.509766f, 0.687500f, 0.797852f, 0.862305f, 0.900391f, 0.923828f,
+ 0.940430f, 0.950684f, 0.959473f, 0.965820f, 0.970703f, 0.974121f, 0.977051f, 0.979492f, 0.981934f, 0.983887f, 0.985840f, 0.987305f,
+ 0.987793f, 0.989258f, 0.989746f, 0.990723f, 0.991211f, 0.992188f, 0.992188f, 0.993164f, 0.993652f, 0.993652f, 0.994629f, 0.995117f,
+ 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.002029f, 0.007267f, 0.016678f, 0.032288f, 0.061462f, 0.115051f, 0.215088f, 0.376709f,
+ 0.562988f, 0.712891f, 0.807617f, 0.865234f, 0.901367f, 0.923828f, 0.939453f, 0.950684f, 0.958984f, 0.965332f, 0.970215f, 0.974609f,
+ 0.977051f, 0.979980f, 0.981934f, 0.983887f, 0.984863f, 0.986328f, 0.988281f, 0.988770f, 0.989746f, 0.990723f, 0.990723f, 0.991699f,
+ 0.992188f, 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995117f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.996582f,
+ 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.001274f, 0.004623f, 0.009880f, 0.017792f,
+ 0.030869f, 0.052673f, 0.091431f, 0.160645f, 0.277832f, 0.442383f, 0.610352f, 0.737793f, 0.819824f, 0.870605f, 0.902832f, 0.924805f,
+ 0.939941f, 0.950195f, 0.958496f, 0.964844f, 0.970215f, 0.973633f, 0.977051f, 0.979980f, 0.981934f, 0.983398f, 0.984863f, 0.986328f,
+ 0.987305f, 0.988770f, 0.989746f, 0.990723f, 0.991211f, 0.992188f, 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f,
+ 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000943f, 0.003231f, 0.006317f, 0.011040f, 0.018051f, 0.029190f, 0.046936f, 0.075867f, 0.125488f, 0.210449f, 0.341797f, 0.503906f,
+ 0.652344f, 0.761230f, 0.832031f, 0.877441f, 0.906738f, 0.927734f, 0.940918f, 0.951172f, 0.959473f, 0.965820f, 0.970703f, 0.974121f,
+ 0.977051f, 0.979492f, 0.981934f, 0.983398f, 0.985352f, 0.987305f, 0.988281f, 0.989258f, 0.990234f, 0.990723f, 0.991211f, 0.992188f,
+ 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.996582f,
+ 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000731f, 0.001970f, 0.004425f, 0.007351f, 0.011627f, 0.017975f, 0.027161f, 0.041779f,
+ 0.064270f, 0.101685f, 0.164917f, 0.265137f, 0.406494f, 0.561035f, 0.692383f, 0.785156f, 0.845703f, 0.884766f, 0.911621f, 0.930176f,
+ 0.942871f, 0.953125f, 0.959961f, 0.965332f, 0.970703f, 0.974121f, 0.977539f, 0.979492f, 0.982422f, 0.983887f, 0.985840f, 0.987305f,
+ 0.987793f, 0.989258f, 0.990234f, 0.991211f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.995117f, 0.995117f, 0.995605f,
+ 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.000487f, 0.001872f, 0.003445f, 0.005367f,
+ 0.008400f, 0.012405f, 0.017822f, 0.025345f, 0.037964f, 0.056244f, 0.085327f, 0.132935f, 0.210327f, 0.325928f, 0.471924f, 0.615723f,
+ 0.729004f, 0.807617f, 0.859375f, 0.894043f, 0.916504f, 0.934570f, 0.945801f, 0.955078f, 0.961426f, 0.967285f, 0.972168f, 0.975586f,
+ 0.978516f, 0.980957f, 0.982422f, 0.984863f, 0.985840f, 0.986816f, 0.988770f, 0.989258f, 0.990723f, 0.991699f, 0.992188f, 0.992676f,
+ 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.997070f, 0.997070f, 0.997559f,
+ 0.997559f, 0.998047f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.000363f, 0.001300f, 0.002499f, 0.003784f, 0.006153f, 0.008896f, 0.012367f, 0.017227f, 0.024185f, 0.034241f, 0.049591f, 0.072754f,
+ 0.111023f, 0.170776f, 0.263184f, 0.391113f, 0.535645f, 0.665527f, 0.761719f, 0.828613f, 0.871582f, 0.902344f, 0.922852f, 0.937988f,
+ 0.949219f, 0.957031f, 0.963867f, 0.968750f, 0.972656f, 0.976074f, 0.979004f, 0.981445f, 0.983887f, 0.984863f, 0.986328f, 0.988281f,
+ 0.989258f, 0.990234f, 0.991211f, 0.991699f, 0.992676f, 0.993652f, 0.993652f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999023f, 0.999023f, 0.000365f, 0.000972f, 0.001874f, 0.003323f, 0.004669f, 0.006599f, 0.008919f, 0.012360f,
+ 0.016785f, 0.022720f, 0.031616f, 0.044647f, 0.064026f, 0.094055f, 0.141235f, 0.215332f, 0.323486f, 0.459229f, 0.597168f, 0.710449f,
+ 0.791992f, 0.847656f, 0.885254f, 0.910645f, 0.929199f, 0.941895f, 0.952148f, 0.960449f, 0.965332f, 0.970703f, 0.974121f, 0.977539f,
+ 0.979980f, 0.981934f, 0.984375f, 0.985840f, 0.987305f, 0.988770f, 0.989746f, 0.990723f, 0.991211f, 0.992188f, 0.993164f, 0.993164f,
+ 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.997559f,
+ 0.998047f, 0.998535f, 0.999023f, 0.999512f, 0.999023f, 0.999512f, 0.999512f, 0.999023f, 0.000244f, 0.000764f, 0.001375f, 0.002415f,
+ 0.003582f, 0.004963f, 0.006973f, 0.008751f, 0.011726f, 0.016113f, 0.021683f, 0.029129f, 0.040283f, 0.057098f, 0.081421f, 0.119019f,
+ 0.178955f, 0.268311f, 0.390625f, 0.528809f, 0.654785f, 0.751465f, 0.820312f, 0.866211f, 0.896973f, 0.919434f, 0.935547f, 0.946777f,
+ 0.956055f, 0.962402f, 0.968262f, 0.972168f, 0.975098f, 0.979004f, 0.981445f, 0.983398f, 0.985352f, 0.986816f, 0.987793f, 0.989258f,
+ 0.990723f, 0.991211f, 0.992188f, 0.992188f, 0.993164f, 0.993652f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996094f,
+ 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000122f, 0.000606f, 0.001439f, 0.002058f, 0.002743f, 0.004169f, 0.005035f, 0.006775f, 0.009010f, 0.012085f, 0.015717f, 0.020813f,
+ 0.027573f, 0.037170f, 0.050812f, 0.071472f, 0.102905f, 0.151489f, 0.225708f, 0.332031f, 0.463623f, 0.596191f, 0.707031f, 0.787598f,
+ 0.844238f, 0.881348f, 0.908691f, 0.927246f, 0.940918f, 0.951660f, 0.958984f, 0.965820f, 0.970215f, 0.974121f, 0.977539f, 0.979980f,
+ 0.982422f, 0.984375f, 0.985840f, 0.987305f, 0.988281f, 0.990234f, 0.990723f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994141f,
+ 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000118f, 0.000846f, 0.001303f, 0.001593f, 0.002180f, 0.003050f, 0.004353f, 0.005577f,
+ 0.006954f, 0.009331f, 0.011826f, 0.015007f, 0.019653f, 0.025391f, 0.034119f, 0.046112f, 0.063660f, 0.090210f, 0.130737f, 0.192139f,
+ 0.283203f, 0.404053f, 0.537598f, 0.658691f, 0.753418f, 0.818848f, 0.865234f, 0.896973f, 0.918945f, 0.934570f, 0.946289f, 0.955566f,
+ 0.962402f, 0.967285f, 0.972168f, 0.976074f, 0.979004f, 0.981445f, 0.983398f, 0.985840f, 0.986816f, 0.988281f, 0.989258f, 0.990723f,
+ 0.991211f, 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f,
+ 0.997559f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000117f, 0.000487f, 0.000957f, 0.001514f,
+ 0.002008f, 0.002619f, 0.003424f, 0.004551f, 0.005836f, 0.007381f, 0.009155f, 0.011459f, 0.014366f, 0.018646f, 0.024017f, 0.031281f,
+ 0.042664f, 0.057068f, 0.080139f, 0.113586f, 0.165894f, 0.243164f, 0.352051f, 0.481934f, 0.610840f, 0.716309f, 0.793945f, 0.847168f,
+ 0.884766f, 0.910645f, 0.928223f, 0.942383f, 0.952637f, 0.959961f, 0.965332f, 0.970703f, 0.975098f, 0.978027f, 0.980957f, 0.983398f,
+ 0.984863f, 0.986816f, 0.988281f, 0.989258f, 0.990723f, 0.991211f, 0.992188f, 0.992676f, 0.993164f, 0.993652f, 0.994629f, 0.995117f,
+ 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997559f, 0.997070f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000000f, 0.000608f, 0.000952f, 0.001111f, 0.001660f, 0.002102f, 0.002817f, 0.003517f, 0.004742f, 0.005585f, 0.007080f, 0.008980f,
+ 0.011078f, 0.014191f, 0.017838f, 0.022614f, 0.029404f, 0.038940f, 0.052551f, 0.071533f, 0.100769f, 0.145020f, 0.211548f, 0.307373f,
+ 0.430176f, 0.561523f, 0.676758f, 0.764648f, 0.828613f, 0.872070f, 0.900879f, 0.921875f, 0.937012f, 0.948730f, 0.957520f, 0.964355f,
+ 0.969238f, 0.973633f, 0.977539f, 0.979980f, 0.982422f, 0.984863f, 0.986328f, 0.987793f, 0.988770f, 0.990234f, 0.991211f, 0.991699f,
+ 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000244f, 0.000576f, 0.000727f, 0.001083f, 0.001186f, 0.001810f, 0.002558f, 0.002968f,
+ 0.003725f, 0.004913f, 0.005955f, 0.007011f, 0.008759f, 0.010918f, 0.013718f, 0.016953f, 0.021423f, 0.027832f, 0.035980f, 0.047913f,
+ 0.064941f, 0.090332f, 0.128174f, 0.185791f, 0.270264f, 0.384033f, 0.514160f, 0.638184f, 0.736328f, 0.807617f, 0.856934f, 0.891602f,
+ 0.915039f, 0.932617f, 0.945801f, 0.954102f, 0.962402f, 0.968262f, 0.972168f, 0.976562f, 0.979492f, 0.981445f, 0.983887f, 0.985840f,
+ 0.987305f, 0.988281f, 0.990234f, 0.990723f, 0.992188f, 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996582f, 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000000f, 0.000244f, 0.000708f, 0.000903f,
+ 0.001129f, 0.001511f, 0.002031f, 0.002565f, 0.003189f, 0.004112f, 0.004696f, 0.005989f, 0.006954f, 0.008865f, 0.010826f, 0.013031f,
+ 0.016312f, 0.020493f, 0.026154f, 0.033966f, 0.044159f, 0.059845f, 0.081665f, 0.114929f, 0.164917f, 0.239624f, 0.343750f, 0.469971f,
+ 0.598145f, 0.706055f, 0.786133f, 0.842773f, 0.881348f, 0.908203f, 0.927246f, 0.941895f, 0.952148f, 0.959961f, 0.966797f, 0.971191f,
+ 0.976074f, 0.978516f, 0.981445f, 0.983887f, 0.985352f, 0.987305f, 0.988281f, 0.989258f, 0.990723f, 0.991699f, 0.992676f, 0.993652f,
+ 0.994141f, 0.994629f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000122f, 0.000244f, 0.000482f, 0.000674f, 0.001029f, 0.001440f, 0.001746f, 0.002153f, 0.002804f, 0.003206f, 0.003859f, 0.004948f,
+ 0.005722f, 0.007206f, 0.008568f, 0.010498f, 0.012413f, 0.015793f, 0.019989f, 0.024826f, 0.031799f, 0.041382f, 0.054932f, 0.074768f,
+ 0.103882f, 0.147949f, 0.213867f, 0.308838f, 0.429932f, 0.560059f, 0.675781f, 0.765625f, 0.827148f, 0.871582f, 0.901367f, 0.923340f,
+ 0.937988f, 0.949707f, 0.958496f, 0.965820f, 0.969727f, 0.974609f, 0.978027f, 0.980469f, 0.983398f, 0.985840f, 0.986816f, 0.988281f,
+ 0.989258f, 0.990723f, 0.992188f, 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996582f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000244f, 0.000244f, 0.000363f, 0.000604f, 0.000834f, 0.001020f, 0.001548f, 0.001970f,
+ 0.002262f, 0.002548f, 0.003157f, 0.003914f, 0.004681f, 0.005962f, 0.006943f, 0.008263f, 0.010277f, 0.012589f, 0.015144f, 0.018951f,
+ 0.023788f, 0.030014f, 0.039001f, 0.051056f, 0.069092f, 0.094666f, 0.133911f, 0.192993f, 0.279053f, 0.394287f, 0.524414f, 0.646484f,
+ 0.743652f, 0.812988f, 0.861328f, 0.895020f, 0.917969f, 0.935547f, 0.947754f, 0.957520f, 0.963867f, 0.969238f, 0.974121f, 0.978027f,
+ 0.980469f, 0.983398f, 0.984863f, 0.987305f, 0.988281f, 0.989258f, 0.990723f, 0.991699f, 0.992676f, 0.993652f, 0.994141f, 0.994629f,
+ 0.995117f, 0.996094f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000118f, 0.000244f, 0.000244f, 0.000584f,
+ 0.000837f, 0.000847f, 0.001295f, 0.001681f, 0.002018f, 0.002348f, 0.003014f, 0.003157f, 0.004124f, 0.004547f, 0.005432f, 0.006607f,
+ 0.008163f, 0.010071f, 0.011925f, 0.014786f, 0.017990f, 0.022659f, 0.028824f, 0.036621f, 0.047882f, 0.063477f, 0.087158f, 0.122559f,
+ 0.175781f, 0.254639f, 0.363037f, 0.492188f, 0.618652f, 0.722168f, 0.799805f, 0.852051f, 0.889648f, 0.914551f, 0.932129f, 0.944824f,
+ 0.955078f, 0.962891f, 0.968262f, 0.973633f, 0.977051f, 0.980469f, 0.982910f, 0.984863f, 0.987305f, 0.988281f, 0.990234f, 0.991211f,
+ 0.992188f, 0.993164f, 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000242f, 0.000243f, 0.000243f, 0.000481f, 0.000742f, 0.000843f, 0.000969f, 0.001348f, 0.001726f, 0.001791f, 0.002348f, 0.002853f,
+ 0.003452f, 0.003735f, 0.004757f, 0.005516f, 0.006744f, 0.008102f, 0.009621f, 0.011948f, 0.014320f, 0.017365f, 0.021698f, 0.027298f,
+ 0.034546f, 0.044891f, 0.059875f, 0.081055f, 0.112915f, 0.161255f, 0.234009f, 0.335693f, 0.462646f, 0.592285f, 0.702637f, 0.785645f,
+ 0.843750f, 0.883301f, 0.911133f, 0.929688f, 0.944336f, 0.954590f, 0.961914f, 0.967773f, 0.973633f, 0.977539f, 0.980469f, 0.982910f,
+ 0.985352f, 0.986816f, 0.988770f, 0.990234f, 0.991211f, 0.992188f, 0.993164f, 0.993652f, 0.994629f, 0.995117f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000100f, 0.000216f, 0.000243f, 0.000365f, 0.000517f, 0.000836f, 0.000964f, 0.001148f,
+ 0.001472f, 0.001674f, 0.001785f, 0.002438f, 0.002815f, 0.003490f, 0.004070f, 0.004837f, 0.005608f, 0.006630f, 0.008095f, 0.009483f,
+ 0.011551f, 0.013847f, 0.016953f, 0.020584f, 0.025879f, 0.033051f, 0.042664f, 0.055817f, 0.075500f, 0.105103f, 0.149536f, 0.216553f,
+ 0.312988f, 0.436768f, 0.568359f, 0.685059f, 0.773926f, 0.835449f, 0.878418f, 0.907227f, 0.927734f, 0.943359f, 0.953125f, 0.962402f,
+ 0.967285f, 0.973145f, 0.977051f, 0.980469f, 0.983887f, 0.985352f, 0.987305f, 0.989258f, 0.990234f, 0.991699f, 0.992188f, 0.993164f,
+ 0.994141f, 0.994629f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000150f, 0.000242f, 0.000364f,
+ 0.000441f, 0.000627f, 0.000916f, 0.000959f, 0.000968f, 0.001463f, 0.001671f, 0.002222f, 0.002577f, 0.002714f, 0.003479f, 0.004208f,
+ 0.004723f, 0.005669f, 0.006886f, 0.007637f, 0.009315f, 0.011154f, 0.013596f, 0.016205f, 0.019821f, 0.024963f, 0.031250f, 0.040375f,
+ 0.053009f, 0.071167f, 0.098511f, 0.139648f, 0.202271f, 0.293457f, 0.414307f, 0.548340f, 0.669434f, 0.762695f, 0.829590f, 0.874512f,
+ 0.904785f, 0.926758f, 0.941895f, 0.953613f, 0.961914f, 0.968262f, 0.973633f, 0.977539f, 0.980957f, 0.983398f, 0.985352f, 0.987793f,
+ 0.989258f, 0.990234f, 0.991211f, 0.992188f, 0.993164f, 0.994629f, 0.998047f, 0.998535f, 0.998047f, 0.998047f, 0.998047f, 0.998047f,
+ 0.000000f, 0.000231f, 0.000232f, 0.000363f, 0.000486f, 0.000503f, 0.000724f, 0.001104f, 0.001080f, 0.001271f, 0.001509f, 0.001976f,
+ 0.002247f, 0.002476f, 0.002895f, 0.003553f, 0.004192f, 0.004871f, 0.005623f, 0.006332f, 0.007584f, 0.008957f, 0.010849f, 0.012917f,
+ 0.015396f, 0.019226f, 0.023941f, 0.030060f, 0.038513f, 0.050385f, 0.067627f, 0.093140f, 0.131714f, 0.190674f, 0.278076f, 0.395752f,
+ 0.530273f, 0.655762f, 0.753906f, 0.823242f, 0.870605f, 0.903320f, 0.925781f, 0.941406f, 0.953125f, 0.961914f, 0.969238f, 0.974121f,
+ 0.978027f, 0.980957f, 0.983887f, 0.985840f, 0.988281f, 0.989258f, 0.990723f, 0.991699f, 0.992676f, 0.993652f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000000f, 0.000009f, 0.000116f, 0.000360f, 0.000484f, 0.000485f, 0.000536f, 0.000827f,
+ 0.000935f, 0.001077f, 0.001204f, 0.001561f, 0.001974f, 0.002136f, 0.002777f, 0.002964f, 0.003517f, 0.004192f, 0.004711f, 0.005505f,
+ 0.006283f, 0.007408f, 0.008713f, 0.010674f, 0.012375f, 0.015099f, 0.018677f, 0.022797f, 0.028732f, 0.036835f, 0.047974f, 0.064270f,
+ 0.088318f, 0.124634f, 0.180664f, 0.264893f, 0.380615f, 0.516113f, 0.645020f, 0.747559f, 0.819824f, 0.870117f, 0.902344f, 0.925293f,
+ 0.941406f, 0.953613f, 0.962402f, 0.969238f, 0.974121f, 0.978027f, 0.981934f, 0.984375f, 0.986328f, 0.988281f, 0.989746f, 0.990723f,
+ 0.992676f, 0.993164f, 0.997559f, 0.998047f, 0.998047f, 0.997559f, 0.998047f, 0.998047f, 0.000000f, 0.000000f, 0.000074f, 0.000337f,
+ 0.000481f, 0.000484f, 0.000485f, 0.000556f, 0.000823f, 0.001143f, 0.001187f, 0.001391f, 0.001781f, 0.002155f, 0.002327f, 0.002760f,
+ 0.003008f, 0.003433f, 0.004101f, 0.004681f, 0.005417f, 0.006443f, 0.007393f, 0.008560f, 0.010345f, 0.012177f, 0.014496f, 0.018127f,
+ 0.022125f, 0.027740f, 0.035736f, 0.046173f, 0.061920f, 0.084717f, 0.119324f, 0.173218f, 0.254883f, 0.368652f, 0.505371f, 0.637207f,
+ 0.742676f, 0.818359f, 0.868164f, 0.902832f, 0.925781f, 0.942383f, 0.953613f, 0.963379f, 0.970215f, 0.975098f, 0.979004f, 0.982422f,
+ 0.984863f, 0.986328f, 0.988770f, 0.990723f, 0.991699f, 0.992676f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000188f, 0.000358f, 0.000481f, 0.000484f, 0.000484f, 0.000704f, 0.000852f, 0.001165f, 0.001316f,
+ 0.001500f, 0.001685f, 0.001933f, 0.002079f, 0.002720f, 0.003136f, 0.003727f, 0.003723f, 0.004513f, 0.005207f, 0.006275f, 0.007236f,
+ 0.008453f, 0.010056f, 0.011848f, 0.014191f, 0.017212f, 0.021652f, 0.026978f, 0.034241f, 0.044678f, 0.058990f, 0.081421f, 0.114929f,
+ 0.167236f, 0.247070f, 0.360596f, 0.498291f, 0.632812f, 0.741211f, 0.818359f, 0.869629f, 0.903809f, 0.927734f, 0.943848f, 0.955566f,
+ 0.964355f, 0.970703f, 0.976074f, 0.979492f, 0.982422f, 0.985840f, 0.987793f, 0.989258f, 0.990723f, 0.992188f, 0.997070f, 0.997559f,
+ 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000000f, 0.000121f, 0.000120f, 0.000288f, 0.000357f, 0.000479f, 0.000483f,
+ 0.000535f, 0.000711f, 0.000862f, 0.001256f, 0.001351f, 0.001502f, 0.001719f, 0.002146f, 0.002037f, 0.002653f, 0.003248f, 0.003222f,
+ 0.003820f, 0.004456f, 0.005173f, 0.006008f, 0.007072f, 0.008247f, 0.009758f, 0.011826f, 0.013771f, 0.016861f, 0.020935f, 0.025986f,
+ 0.032928f, 0.043030f, 0.057587f, 0.078918f, 0.111755f, 0.162964f, 0.241943f, 0.355713f, 0.495117f, 0.632324f, 0.742676f, 0.819336f,
+ 0.871582f, 0.905762f, 0.929688f, 0.945312f, 0.957031f, 0.965332f, 0.972168f, 0.976562f, 0.980957f, 0.983887f, 0.986328f, 0.988281f,
+ 0.990234f, 0.991699f, 0.997070f, 0.997559f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000000f, 0.000000f, 0.000121f,
+ 0.000200f, 0.000412f, 0.000471f, 0.000599f, 0.000598f, 0.000596f, 0.000805f, 0.001099f, 0.001334f, 0.001417f, 0.001456f, 0.001723f,
+ 0.002102f, 0.002283f, 0.002579f, 0.003208f, 0.003233f, 0.003740f, 0.004574f, 0.005287f, 0.006012f, 0.006870f, 0.008018f, 0.009354f,
+ 0.011208f, 0.013542f, 0.016495f, 0.020370f, 0.025284f, 0.032410f, 0.041901f, 0.056183f, 0.077087f, 0.109558f, 0.160278f, 0.239380f,
+ 0.354492f, 0.496094f, 0.635254f, 0.747070f, 0.823730f, 0.875488f, 0.908691f, 0.931641f, 0.947266f, 0.958008f, 0.966309f, 0.972656f,
+ 0.978027f, 0.981445f, 0.984863f, 0.986816f, 0.989258f, 0.990723f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997070f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000117f, 0.000237f, 0.000239f, 0.000430f, 0.000465f, 0.000599f, 0.000724f, 0.000716f, 0.000815f,
+ 0.000981f, 0.001334f, 0.001299f, 0.001545f, 0.001617f, 0.001935f, 0.002110f, 0.002501f, 0.002823f, 0.003408f, 0.003790f, 0.004467f,
+ 0.005112f, 0.005848f, 0.006718f, 0.007942f, 0.009514f, 0.011093f, 0.013092f, 0.015945f, 0.019608f, 0.024689f, 0.031494f, 0.041046f,
+ 0.054901f, 0.075989f, 0.108032f, 0.158936f, 0.239014f, 0.356201f, 0.500488f, 0.642090f, 0.753418f, 0.830566f, 0.880859f, 0.912598f,
+ 0.935059f, 0.950195f, 0.960449f, 0.968262f, 0.975098f, 0.979980f, 0.982910f, 0.985352f, 0.987793f, 0.990234f, 0.996582f, 0.997070f,
+ 0.997070f, 0.996582f, 0.997070f, 0.996582f, 0.000000f, 0.000000f, 0.000000f, 0.000117f, 0.000120f, 0.000121f, 0.000312f, 0.000407f,
+ 0.000707f, 0.000597f, 0.000648f, 0.000720f, 0.000941f, 0.001008f, 0.001229f, 0.001289f, 0.001423f, 0.001726f, 0.002060f, 0.002211f,
+ 0.002506f, 0.002985f, 0.003036f, 0.003683f, 0.004066f, 0.004833f, 0.005592f, 0.006611f, 0.007675f, 0.008965f, 0.010811f, 0.012833f,
+ 0.015854f, 0.019485f, 0.024429f, 0.031036f, 0.040466f, 0.054108f, 0.074890f, 0.107727f, 0.159180f, 0.241699f, 0.362549f, 0.510742f,
+ 0.653809f, 0.763184f, 0.837891f, 0.887207f, 0.917480f, 0.938477f, 0.953613f, 0.962891f, 0.970703f, 0.976562f, 0.980469f, 0.984375f,
+ 0.986816f, 0.988770f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.000000f, 0.000000f, 0.000000f, 0.000117f,
+ 0.000118f, 0.000120f, 0.000129f, 0.000434f, 0.000536f, 0.000613f, 0.000716f, 0.000799f, 0.000720f, 0.000768f, 0.001024f, 0.001202f,
+ 0.001501f, 0.001530f, 0.001568f, 0.001897f, 0.002190f, 0.002502f, 0.002893f, 0.003105f, 0.003551f, 0.004021f, 0.004791f, 0.005405f,
+ 0.006313f, 0.007309f, 0.008720f, 0.010712f, 0.012657f, 0.015472f, 0.018982f, 0.023697f, 0.030579f, 0.040009f, 0.054138f, 0.075012f,
+ 0.107849f, 0.161377f, 0.247070f, 0.373047f, 0.525391f, 0.667969f, 0.776855f, 0.847656f, 0.894043f, 0.923340f, 0.942871f, 0.956543f,
+ 0.965820f, 0.973145f, 0.978027f, 0.982422f, 0.985352f, 0.987793f, 0.996094f, 0.996094f, 0.996582f, 0.996094f, 0.996582f, 0.996094f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000081f, 0.000116f, 0.000227f, 0.000360f, 0.000366f, 0.000642f, 0.000691f, 0.000711f,
+ 0.000806f, 0.000721f, 0.000925f, 0.000947f, 0.001155f, 0.001478f, 0.001554f, 0.001612f, 0.001929f, 0.002354f, 0.002291f, 0.002712f,
+ 0.003029f, 0.003441f, 0.003876f, 0.004452f, 0.005276f, 0.006256f, 0.007149f, 0.008568f, 0.010040f, 0.012566f, 0.015160f, 0.018677f,
+ 0.023376f, 0.030411f, 0.039642f, 0.053986f, 0.075134f, 0.109436f, 0.165527f, 0.255127f, 0.387695f, 0.544434f, 0.686523f, 0.791016f,
+ 0.858398f, 0.901367f, 0.928711f, 0.947266f, 0.959961f, 0.968262f, 0.975098f, 0.980469f, 0.983887f, 0.987305f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000088f, 0.000085f, 0.000338f, 0.000351f,
+ 0.000359f, 0.000480f, 0.000539f, 0.000698f, 0.000798f, 0.000793f, 0.000834f, 0.000891f, 0.000941f, 0.001143f, 0.001422f, 0.001512f,
+ 0.001833f, 0.001955f, 0.002144f, 0.002426f, 0.002716f, 0.003262f, 0.003572f, 0.003860f, 0.004456f, 0.005173f, 0.006191f, 0.006939f,
+ 0.008545f, 0.010162f, 0.012375f, 0.014969f, 0.018555f, 0.023376f, 0.029953f, 0.039673f, 0.054077f, 0.076477f, 0.112000f, 0.171509f,
+ 0.268066f, 0.408203f, 0.569336f, 0.709961f, 0.808105f, 0.872070f, 0.910645f, 0.935059f, 0.951660f, 0.963379f, 0.971680f, 0.977539f,
+ 0.982422f, 0.985840f, 0.995117f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000116f, 0.000340f, 0.000353f, 0.000349f, 0.000480f, 0.000576f, 0.000668f, 0.000700f, 0.000818f, 0.000833f,
+ 0.000787f, 0.001125f, 0.001110f, 0.001407f, 0.001489f, 0.001563f, 0.001804f, 0.002073f, 0.002285f, 0.002409f, 0.002985f, 0.003052f,
+ 0.003853f, 0.004433f, 0.005100f, 0.006046f, 0.007046f, 0.008156f, 0.009827f, 0.012138f, 0.014740f, 0.018311f, 0.023071f, 0.029770f,
+ 0.040009f, 0.054810f, 0.078003f, 0.116150f, 0.180176f, 0.284668f, 0.434570f, 0.599121f, 0.735352f, 0.827637f, 0.885254f, 0.919922f,
+ 0.941895f, 0.957031f, 0.967285f, 0.975098f, 0.979980f, 0.984375f, 0.995117f, 0.995117f, 0.995117f, 0.995117f, 0.995117f, 0.995605f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000000f, 0.000122f, 0.000235f, 0.000320f, 0.000351f, 0.000353f, 0.000478f,
+ 0.000602f, 0.000651f, 0.000793f, 0.000706f, 0.000816f, 0.000814f, 0.000898f, 0.001062f, 0.001259f, 0.001441f, 0.001564f, 0.001772f,
+ 0.001743f, 0.002134f, 0.002512f, 0.002668f, 0.003193f, 0.003746f, 0.004341f, 0.004902f, 0.005909f, 0.006920f, 0.008125f, 0.009605f,
+ 0.011711f, 0.014549f, 0.018280f, 0.023163f, 0.030334f, 0.040375f, 0.055939f, 0.080566f, 0.122070f, 0.192383f, 0.307373f, 0.467773f,
+ 0.634277f, 0.763184f, 0.846191f, 0.897461f, 0.928711f, 0.948730f, 0.962402f, 0.971680f, 0.978516f, 0.982422f, 0.994141f, 0.994629f,
+ 0.994629f, 0.995117f, 0.995117f, 0.995117f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000185f, 0.000190f,
+ 0.000272f, 0.000281f, 0.000464f, 0.000466f, 0.000476f, 0.000521f, 0.000654f, 0.000680f, 0.000699f, 0.000815f, 0.000814f, 0.000890f,
+ 0.001110f, 0.001283f, 0.001311f, 0.001590f, 0.001727f, 0.001801f, 0.002020f, 0.002312f, 0.002897f, 0.003267f, 0.003592f, 0.004143f,
+ 0.004810f, 0.005844f, 0.006618f, 0.008018f, 0.009697f, 0.011597f, 0.014374f, 0.018127f, 0.023056f, 0.030258f, 0.041107f, 0.057373f,
+ 0.084045f, 0.129517f, 0.208618f, 0.337646f, 0.508789f, 0.673828f, 0.793457f, 0.866211f, 0.911133f, 0.938965f, 0.955566f, 0.967285f,
+ 0.975586f, 0.980469f, 0.994141f, 0.994141f, 0.994629f, 0.994629f, 0.994629f, 0.994141f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000226f, 0.000431f, 0.000456f, 0.000467f, 0.000352f, 0.000496f, 0.000588f,
+ 0.000891f, 0.000771f, 0.000803f, 0.000947f, 0.000972f, 0.001078f, 0.001033f, 0.001279f, 0.001436f, 0.001483f, 0.001831f, 0.002033f,
+ 0.002264f, 0.002710f, 0.002996f, 0.003582f, 0.004032f, 0.004665f, 0.005592f, 0.006527f, 0.007820f, 0.009323f, 0.011581f, 0.014328f,
+ 0.018219f, 0.023239f, 0.030777f, 0.042084f, 0.059448f, 0.089233f, 0.140869f, 0.230713f, 0.375977f, 0.556641f, 0.715332f, 0.822266f,
+ 0.885742f, 0.924316f, 0.947266f, 0.962402f, 0.972656f, 0.978516f, 0.993164f, 0.994141f, 0.994141f, 0.994141f, 0.994141f, 0.994141f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000283f, 0.000229f, 0.000425f,
+ 0.000303f, 0.000336f, 0.000469f, 0.000474f, 0.000728f, 0.000663f, 0.000883f, 0.000695f, 0.000679f, 0.000858f, 0.000919f, 0.000980f,
+ 0.001218f, 0.001330f, 0.001665f, 0.001637f, 0.002054f, 0.002335f, 0.002508f, 0.002880f, 0.003323f, 0.004055f, 0.004730f, 0.005463f,
+ 0.006485f, 0.007740f, 0.009293f, 0.011566f, 0.014175f, 0.017944f, 0.023346f, 0.031433f, 0.043304f, 0.063232f, 0.096313f, 0.155518f,
+ 0.260498f, 0.424561f, 0.611328f, 0.758789f, 0.852051f, 0.904785f, 0.937012f, 0.955566f, 0.968262f, 0.977051f, 0.992676f, 0.992676f,
+ 0.993164f, 0.993652f, 0.993164f, 0.993652f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000256f, 0.000216f, 0.000406f, 0.000426f, 0.000457f, 0.000453f, 0.000472f, 0.000651f, 0.000593f, 0.000876f,
+ 0.000571f, 0.000590f, 0.000819f, 0.000809f, 0.001000f, 0.001224f, 0.001293f, 0.001637f, 0.001790f, 0.001863f, 0.002298f, 0.002550f,
+ 0.002995f, 0.003201f, 0.003933f, 0.004677f, 0.005360f, 0.006447f, 0.007763f, 0.009377f, 0.011330f, 0.014420f, 0.017944f, 0.023560f,
+ 0.032196f, 0.045380f, 0.067383f, 0.105469f, 0.175659f, 0.301025f, 0.484375f, 0.669922f, 0.801270f, 0.879395f, 0.922852f, 0.948242f,
+ 0.963379f, 0.974121f, 0.992188f, 0.992188f, 0.992188f, 0.993164f, 0.992188f, 0.993164f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000230f, 0.000206f, 0.000355f, 0.000335f, 0.000305f,
+ 0.000461f, 0.000565f, 0.000474f, 0.000429f, 0.000520f, 0.000758f, 0.000777f, 0.000668f, 0.000821f, 0.001013f, 0.001089f, 0.001325f,
+ 0.001570f, 0.001787f, 0.001707f, 0.002037f, 0.002457f, 0.002892f, 0.003359f, 0.003881f, 0.004616f, 0.005203f, 0.006336f, 0.007477f,
+ 0.009048f, 0.011345f, 0.014015f, 0.018356f, 0.024307f, 0.033661f, 0.048279f, 0.073303f, 0.118774f, 0.204102f, 0.354492f, 0.554688f,
+ 0.729492f, 0.840332f, 0.902832f, 0.937988f, 0.958008f, 0.971191f, 0.991699f, 0.992188f, 0.992188f, 0.991699f, 0.992188f, 0.991699f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000205f, 0.000248f, 0.000213f, 0.000344f, 0.000437f, 0.000351f, 0.000352f, 0.000359f, 0.000389f, 0.000482f, 0.000676f, 0.000560f,
+ 0.000806f, 0.000813f, 0.000927f, 0.001230f, 0.001392f, 0.001526f, 0.001627f, 0.001629f, 0.002047f, 0.002321f, 0.002661f, 0.003317f,
+ 0.003752f, 0.004406f, 0.005119f, 0.005936f, 0.007156f, 0.009003f, 0.010941f, 0.013985f, 0.018539f, 0.025131f, 0.035248f, 0.051880f,
+ 0.081543f, 0.137207f, 0.244507f, 0.424561f, 0.632812f, 0.787598f, 0.876465f, 0.924805f, 0.951172f, 0.966797f, 0.990723f, 0.991211f,
+ 0.991211f, 0.991211f, 0.991211f, 0.991211f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000224f, 0.000171f, 0.000276f, 0.000278f, 0.000288f, 0.000329f, 0.000365f,
+ 0.000459f, 0.000483f, 0.000626f, 0.000716f, 0.000767f, 0.000793f, 0.000800f, 0.000897f, 0.000976f, 0.001156f, 0.001322f, 0.001427f,
+ 0.001799f, 0.001997f, 0.002256f, 0.002773f, 0.002806f, 0.003515f, 0.004040f, 0.004910f, 0.005730f, 0.007046f, 0.008858f, 0.011124f,
+ 0.014374f, 0.018982f, 0.026123f, 0.037659f, 0.057129f, 0.093445f, 0.164062f, 0.301514f, 0.511230f, 0.712402f, 0.838867f, 0.906738f,
+ 0.942383f, 0.961914f, 0.989746f, 0.990234f, 0.989746f, 0.990234f, 0.989746f, 0.990234f, 0.000000f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000173f, 0.000140f,
+ 0.000138f, 0.000232f, 0.000291f, 0.000318f, 0.000338f, 0.000346f, 0.000422f, 0.000368f, 0.000680f, 0.000722f, 0.000765f, 0.000766f,
+ 0.000803f, 0.001069f, 0.001103f, 0.001185f, 0.001611f, 0.001593f, 0.001939f, 0.002211f, 0.002569f, 0.003008f, 0.003239f, 0.003952f,
+ 0.004681f, 0.005630f, 0.007008f, 0.008720f, 0.011200f, 0.014587f, 0.019653f, 0.027527f, 0.040955f, 0.064514f, 0.110413f, 0.204224f,
+ 0.381104f, 0.609863f, 0.785645f, 0.881836f, 0.931152f, 0.956543f, 0.988770f, 0.989258f, 0.989258f, 0.989258f, 0.989258f, 0.988770f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000121f,
+ 0.000121f, 0.000123f, 0.000121f, 0.000090f, 0.000102f, 0.000063f, 0.000156f, 0.000248f, 0.000333f, 0.000321f, 0.000431f, 0.000392f,
+ 0.000349f, 0.000434f, 0.000674f, 0.000741f, 0.000776f, 0.000936f, 0.000888f, 0.001049f, 0.001179f, 0.001326f, 0.001686f, 0.001732f,
+ 0.002050f, 0.002150f, 0.002453f, 0.003016f, 0.003601f, 0.004444f, 0.005692f, 0.006741f, 0.008324f, 0.011093f, 0.014709f, 0.020752f,
+ 0.029800f, 0.045654f, 0.074951f, 0.136108f, 0.264893f, 0.486816f, 0.710938f, 0.848145f, 0.916992f, 0.950684f, 0.987305f, 0.987793f,
+ 0.987793f, 0.988281f, 0.987793f, 0.987793f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000100f, 0.000049f, 0.000039f, 0.000125f, 0.000121f,
+ 0.000184f, 0.000280f, 0.000366f, 0.000392f, 0.000333f, 0.000341f, 0.000477f, 0.000597f, 0.000607f, 0.000747f, 0.000767f, 0.000961f,
+ 0.000936f, 0.001056f, 0.001306f, 0.001388f, 0.001633f, 0.001836f, 0.001997f, 0.002348f, 0.002878f, 0.003332f, 0.004131f, 0.005165f,
+ 0.006519f, 0.008568f, 0.011444f, 0.015419f, 0.021881f, 0.032532f, 0.052032f, 0.091187f, 0.177246f, 0.357910f, 0.610352f, 0.800781f,
+ 0.897461f, 0.942871f, 0.985352f, 0.986328f, 0.986816f, 0.986328f, 0.986328f, 0.986328f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000099f, 0.000076f,
+ 0.000060f, 0.000108f, 0.000040f, 0.000127f, 0.000127f, 0.000121f, 0.000200f, 0.000265f, 0.000360f, 0.000316f, 0.000428f, 0.000455f,
+ 0.000456f, 0.000583f, 0.000682f, 0.000750f, 0.000773f, 0.000824f, 0.000937f, 0.001220f, 0.001262f, 0.001384f, 0.001622f, 0.001862f,
+ 0.002157f, 0.002817f, 0.003414f, 0.004082f, 0.004993f, 0.006561f, 0.008560f, 0.011696f, 0.016022f, 0.023529f, 0.036469f, 0.062286f,
+ 0.117126f, 0.245605f, 0.487549f, 0.732910f, 0.870605f, 0.933105f, 0.983887f, 0.984863f, 0.984863f, 0.984863f, 0.984375f, 0.984863f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000096f, 0.000075f, 0.000061f, 0.000083f, 0.000096f, 0.000034f, 0.000101f, 0.000121f, 0.000137f,
+ 0.000211f, 0.000324f, 0.000381f, 0.000373f, 0.000420f, 0.000472f, 0.000494f, 0.000690f, 0.000793f, 0.000768f, 0.000853f, 0.000867f,
+ 0.000978f, 0.001003f, 0.001145f, 0.001416f, 0.001888f, 0.002125f, 0.002491f, 0.003004f, 0.003864f, 0.005028f, 0.006500f, 0.008682f,
+ 0.011856f, 0.016922f, 0.025757f, 0.042603f, 0.078247f, 0.161743f, 0.358398f, 0.641602f, 0.833496f, 0.920410f, 0.981934f, 0.982910f,
+ 0.982910f, 0.982910f, 0.982910f, 0.982910f, 0.000122f, 0.000000f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000120f, 0.000097f, 0.000078f, 0.000062f, 0.000051f,
+ 0.000043f, 0.000072f, 0.000030f, 0.000060f, 0.000109f, 0.000206f, 0.000216f, 0.000333f, 0.000347f, 0.000395f, 0.000415f, 0.000458f,
+ 0.000568f, 0.000664f, 0.000709f, 0.000598f, 0.000781f, 0.000628f, 0.001053f, 0.001046f, 0.001179f, 0.001579f, 0.001649f, 0.002386f,
+ 0.002857f, 0.003727f, 0.004894f, 0.006363f, 0.008789f, 0.012314f, 0.018616f, 0.029709f, 0.052429f, 0.105652f, 0.244385f, 0.524414f,
+ 0.782715f, 0.904785f, 0.979492f, 0.980957f, 0.979980f, 0.979980f, 0.980469f, 0.980469f, 0.000000f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000097f, 0.000079f, 0.000065f, 0.000054f, 0.000045f, 0.000073f, 0.000032f, 0.000089f, 0.000038f, 0.000134f, 0.000138f,
+ 0.000211f, 0.000333f, 0.000370f, 0.000400f, 0.000420f, 0.000496f, 0.000566f, 0.000494f, 0.000584f, 0.000714f, 0.000708f, 0.000843f,
+ 0.001056f, 0.001019f, 0.001327f, 0.001812f, 0.001908f, 0.002798f, 0.003479f, 0.004578f, 0.006195f, 0.008881f, 0.012901f, 0.020599f,
+ 0.035339f, 0.069214f, 0.159058f, 0.394531f, 0.709961f, 0.882812f, 0.977051f, 0.978027f, 0.977539f, 0.976562f, 0.977051f, 0.977539f,
+ 0.000000f, 0.000121f, 0.000120f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f,
+ 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000119f, 0.000120f, 0.000102f, 0.000084f, 0.000071f, 0.000059f, 0.000048f, 0.000041f,
+ 0.000035f, 0.000062f, 0.000026f, 0.000098f, 0.000103f, 0.000136f, 0.000230f, 0.000327f, 0.000356f, 0.000338f, 0.000387f, 0.000499f,
+ 0.000577f, 0.000627f, 0.000669f, 0.000611f, 0.000699f, 0.000904f, 0.000893f, 0.001340f, 0.001666f, 0.002068f, 0.002377f, 0.003105f,
+ 0.004345f, 0.006218f, 0.009178f, 0.013962f, 0.024170f, 0.045441f, 0.101868f, 0.271973f, 0.612305f, 0.853027f, 0.973145f, 0.974121f,
+ 0.973633f, 0.974121f, 0.973633f, 0.974121f, 0.000121f, 0.000120f, 0.000119f, 0.000120f, 0.000119f, 0.000119f, 0.000119f, 0.000119f,
+ 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000108f,
+ 0.000091f, 0.000075f, 0.000063f, 0.000053f, 0.000045f, 0.000039f, 0.000034f, 0.000040f, 0.000090f, 0.000068f, 0.000104f, 0.000127f,
+ 0.000220f, 0.000302f, 0.000412f, 0.000316f, 0.000444f, 0.000495f, 0.000428f, 0.000510f, 0.000463f, 0.000614f, 0.000726f, 0.000719f,
+ 0.001164f, 0.001533f, 0.001707f, 0.002079f, 0.002848f, 0.004189f, 0.006142f, 0.009491f, 0.016113f, 0.029343f, 0.064758f, 0.175415f,
+ 0.490723f, 0.812012f, 0.968750f, 0.969727f, 0.969238f, 0.969727f, 0.969727f, 0.969727f, 0.000000f, 0.000117f, 0.000117f, 0.000115f,
+ 0.000118f, 0.000118f, 0.000117f, 0.000117f, 0.000117f, 0.000117f, 0.000118f, 0.000117f, 0.000117f, 0.000118f, 0.000117f, 0.000117f,
+ 0.000117f, 0.000117f, 0.000117f, 0.000118f, 0.000117f, 0.000100f, 0.000082f, 0.000070f, 0.000060f, 0.000051f, 0.000043f, 0.000038f,
+ 0.000033f, 0.000053f, 0.000027f, 0.000089f, 0.000105f, 0.000137f, 0.000227f, 0.000277f, 0.000293f, 0.000284f, 0.000300f, 0.000420f,
+ 0.000367f, 0.000473f, 0.000467f, 0.000555f, 0.000625f, 0.000870f, 0.001177f, 0.001563f, 0.001982f, 0.002714f, 0.004051f, 0.006134f,
+ 0.010384f, 0.018967f, 0.040314f, 0.108887f, 0.358643f, 0.755859f, 0.962891f, 0.963867f, 0.964355f, 0.963867f, 0.963379f, 0.963379f,
+ 0.000000f, 0.000000f, 0.000098f, 0.000103f, 0.000111f, 0.000112f, 0.000112f, 0.000114f, 0.000113f, 0.000115f, 0.000114f, 0.000115f,
+ 0.000115f, 0.000115f, 0.000115f, 0.000115f, 0.000116f, 0.000116f, 0.000116f, 0.000116f, 0.000116f, 0.000116f, 0.000109f, 0.000094f,
+ 0.000078f, 0.000067f, 0.000058f, 0.000050f, 0.000043f, 0.000038f, 0.000033f, 0.000054f, 0.000025f, 0.000078f, 0.000091f, 0.000173f,
+ 0.000203f, 0.000252f, 0.000331f, 0.000277f, 0.000264f, 0.000407f, 0.000342f, 0.000444f, 0.000470f, 0.000542f, 0.000773f, 0.001081f,
+ 0.001245f, 0.001682f, 0.002602f, 0.003744f, 0.006248f, 0.011566f, 0.025040f, 0.065491f, 0.236938f, 0.678223f, 0.956055f, 0.956543f,
+ 0.956543f, 0.956543f, 0.957031f, 0.957031f, 0.000000f, 0.000000f, 0.000021f, 0.000080f, 0.000072f, 0.000089f, 0.000100f, 0.000099f,
+ 0.000105f, 0.000107f, 0.000107f, 0.000110f, 0.000109f, 0.000110f, 0.000111f, 0.000111f, 0.000112f, 0.000112f, 0.000112f, 0.000113f,
+ 0.000113f, 0.000113f, 0.000113f, 0.000113f, 0.000105f, 0.000090f, 0.000078f, 0.000067f, 0.000057f, 0.000050f, 0.000043f, 0.000038f,
+ 0.000033f, 0.000029f, 0.000025f, 0.000055f, 0.000091f, 0.000130f, 0.000225f, 0.000275f, 0.000254f, 0.000290f, 0.000259f, 0.000378f,
+ 0.000333f, 0.000362f, 0.000458f, 0.000587f, 0.000876f, 0.001062f, 0.001382f, 0.002398f, 0.003763f, 0.006603f, 0.014496f, 0.038300f,
+ 0.143677f, 0.573730f, 0.946777f, 0.947266f, 0.947266f, 0.947266f, 0.948242f, 0.947266f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000014f, 0.000036f, 0.000072f, 0.000082f, 0.000080f, 0.000094f, 0.000096f, 0.000099f, 0.000098f, 0.000103f, 0.000103f,
+ 0.000103f, 0.000106f, 0.000105f, 0.000107f, 0.000107f, 0.000108f, 0.000108f, 0.000109f, 0.000109f, 0.000109f, 0.000105f, 0.000090f,
+ 0.000078f, 0.000067f, 0.000059f, 0.000051f, 0.000045f, 0.000039f, 0.000034f, 0.000030f, 0.000026f, 0.000045f, 0.000086f, 0.000108f,
+ 0.000143f, 0.000212f, 0.000227f, 0.000204f, 0.000231f, 0.000263f, 0.000315f, 0.000354f, 0.000481f, 0.000702f, 0.000888f, 0.001257f,
+ 0.002018f, 0.003738f, 0.007675f, 0.021317f, 0.080933f, 0.444336f, 0.934082f, 0.935059f, 0.935059f, 0.935059f, 0.935059f, 0.935059f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000024f, 0.000038f, 0.000059f,
+ 0.000063f, 0.000076f, 0.000080f, 0.000085f, 0.000089f, 0.000091f, 0.000092f, 0.000095f, 0.000097f, 0.000099f, 0.000098f, 0.000101f,
+ 0.000101f, 0.000102f, 0.000103f, 0.000104f, 0.000104f, 0.000091f, 0.000080f, 0.000069f, 0.000062f, 0.000053f, 0.000046f, 0.000041f,
+ 0.000035f, 0.000032f, 0.000027f, 0.000039f, 0.000052f, 0.000103f, 0.000139f, 0.000178f, 0.000190f, 0.000178f, 0.000185f, 0.000247f,
+ 0.000274f, 0.000368f, 0.000528f, 0.000637f, 0.001027f, 0.001937f, 0.003853f, 0.010445f, 0.041718f, 0.304199f, 0.917480f, 0.917480f,
+ 0.917969f, 0.917480f, 0.918457f, 0.917969f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000023f, 0.000037f, 0.000048f, 0.000048f, 0.000063f, 0.000063f,
+ 0.000074f, 0.000077f, 0.000080f, 0.000083f, 0.000086f, 0.000088f, 0.000090f, 0.000091f, 0.000092f, 0.000094f, 0.000095f, 0.000096f,
+ 0.000084f, 0.000073f, 0.000064f, 0.000057f, 0.000049f, 0.000043f, 0.000037f, 0.000033f, 0.000029f, 0.000025f, 0.000060f, 0.000061f,
+ 0.000087f, 0.000118f, 0.000156f, 0.000131f, 0.000175f, 0.000226f, 0.000230f, 0.000373f, 0.000507f, 0.000992f, 0.001814f, 0.004639f,
+ 0.018799f, 0.176758f, 0.894043f, 0.894531f, 0.895508f, 0.895020f, 0.895020f, 0.895996f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000019f, 0.000028f, 0.000034f, 0.000043f, 0.000052f, 0.000057f, 0.000062f, 0.000067f,
+ 0.000070f, 0.000074f, 0.000075f, 0.000079f, 0.000081f, 0.000083f, 0.000085f, 0.000076f, 0.000068f, 0.000059f, 0.000051f, 0.000046f,
+ 0.000040f, 0.000035f, 0.000030f, 0.000026f, 0.000028f, 0.000038f, 0.000072f, 0.000100f, 0.000120f, 0.000107f, 0.000152f, 0.000156f,
+ 0.000254f, 0.000436f, 0.000722f, 0.001875f, 0.007088f, 0.083069f, 0.863281f, 0.862305f, 0.863281f, 0.862305f, 0.863281f, 0.862793f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000005f, 0.000015f, 0.000022f, 0.000030f, 0.000037f, 0.000042f, 0.000048f, 0.000053f, 0.000058f, 0.000060f,
+ 0.000064f, 0.000067f, 0.000069f, 0.000061f, 0.000053f, 0.000047f, 0.000041f, 0.000036f, 0.000031f, 0.000027f, 0.000023f, 0.000020f,
+ 0.000036f, 0.000063f, 0.000082f, 0.000081f, 0.000104f, 0.000149f, 0.000263f, 0.000616f, 0.002337f, 0.028168f, 0.816406f, 0.816895f,
+ 0.816895f, 0.816895f, 0.817383f, 0.816895f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000003f, 0.000011f, 0.000019f, 0.000026f, 0.000031f, 0.000036f, 0.000041f, 0.000045f, 0.000050f, 0.000047f,
+ 0.000041f, 0.000036f, 0.000031f, 0.000027f, 0.000023f, 0.000019f, 0.000028f, 0.000029f, 0.000053f, 0.000052f, 0.000072f, 0.000165f,
+ 0.000511f, 0.006050f, 0.751465f, 0.752441f, 0.752930f, 0.752441f, 0.752441f, 0.752930f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000004f, 0.000011f, 0.000017f, 0.000021f, 0.000027f, 0.000028f, 0.000024f, 0.000020f, 0.000017f,
+ 0.000013f, 0.000020f, 0.000021f, 0.000029f, 0.000057f, 0.000588f, 0.665039f, 0.664551f, 0.665527f, 0.665039f, 0.665039f, 0.665039f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000003f, 0.000009f, 0.000006f, 0.000004f, 0.000007f, 0.557129f, 0.558105f,
+ 0.557617f, 0.557617f, 0.558594f, 0.558105f,
+ },
+ {
+ 0.163818f, 0.558105f, 0.755859f, 0.841797f, 0.886230f, 0.912109f, 0.929199f, 0.941406f, 0.950195f, 0.957031f, 0.961914f, 0.966309f,
+ 0.970215f, 0.972656f, 0.975586f, 0.978027f, 0.979492f, 0.981445f, 0.982910f, 0.984375f, 0.985840f, 0.986328f, 0.987305f, 0.988770f,
+ 0.989258f, 0.989746f, 0.990234f, 0.991211f, 0.991699f, 0.992188f, 0.993164f, 0.993652f, 0.993652f, 0.993652f, 0.994141f, 0.995117f,
+ 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.027023f, 0.138184f, 0.353760f, 0.583984f, 0.735352f, 0.819336f, 0.868652f, 0.898926f,
+ 0.918945f, 0.933594f, 0.943848f, 0.952148f, 0.958984f, 0.963867f, 0.967773f, 0.971680f, 0.974121f, 0.976562f, 0.978516f, 0.980469f,
+ 0.982422f, 0.983398f, 0.984863f, 0.986328f, 0.986816f, 0.988281f, 0.989258f, 0.989746f, 0.990723f, 0.990723f, 0.991699f, 0.992676f,
+ 0.993164f, 0.993164f, 0.993652f, 0.994141f, 0.994141f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997070f,
+ 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.009819f, 0.044250f, 0.113525f, 0.244995f,
+ 0.430420f, 0.608887f, 0.733887f, 0.810547f, 0.860352f, 0.892578f, 0.913086f, 0.929688f, 0.940918f, 0.949219f, 0.956055f, 0.961426f,
+ 0.966309f, 0.970215f, 0.972656f, 0.975586f, 0.977539f, 0.979980f, 0.980957f, 0.983398f, 0.983887f, 0.985352f, 0.986328f, 0.987793f,
+ 0.988281f, 0.989746f, 0.989746f, 0.991211f, 0.991699f, 0.992188f, 0.992676f, 0.993164f, 0.993652f, 0.993652f, 0.994141f, 0.995117f,
+ 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.004848f, 0.020447f, 0.046814f, 0.096313f, 0.183228f, 0.319092f, 0.484375f, 0.631836f, 0.739258f, 0.810547f, 0.857422f, 0.888672f,
+ 0.910645f, 0.925781f, 0.938965f, 0.947754f, 0.954590f, 0.960449f, 0.964355f, 0.968750f, 0.971191f, 0.974609f, 0.977051f, 0.979004f,
+ 0.980957f, 0.982422f, 0.983887f, 0.985840f, 0.986816f, 0.987793f, 0.988770f, 0.989258f, 0.990234f, 0.990723f, 0.991211f, 0.991699f,
+ 0.992676f, 0.992676f, 0.993652f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.996582f,
+ 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.003096f, 0.011017f, 0.024399f, 0.046600f, 0.083191f, 0.145386f, 0.243774f, 0.379395f,
+ 0.529297f, 0.656738f, 0.750977f, 0.813965f, 0.857910f, 0.887695f, 0.909668f, 0.925293f, 0.937500f, 0.946289f, 0.953613f, 0.959473f,
+ 0.964355f, 0.968262f, 0.971191f, 0.974121f, 0.976562f, 0.979004f, 0.980957f, 0.982910f, 0.984375f, 0.985840f, 0.986328f, 0.987793f,
+ 0.988281f, 0.989258f, 0.989746f, 0.991211f, 0.991699f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f,
+ 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.001808f, 0.006992f, 0.014923f, 0.026413f,
+ 0.044403f, 0.073120f, 0.119446f, 0.193115f, 0.300537f, 0.433594f, 0.568848f, 0.680664f, 0.763184f, 0.821289f, 0.860840f, 0.890137f,
+ 0.909668f, 0.925293f, 0.937500f, 0.945801f, 0.953613f, 0.959473f, 0.963867f, 0.968262f, 0.971680f, 0.974609f, 0.977051f, 0.979004f,
+ 0.980957f, 0.982422f, 0.983887f, 0.984863f, 0.986816f, 0.987305f, 0.987793f, 0.989746f, 0.989746f, 0.991211f, 0.991699f, 0.992188f,
+ 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.994629f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997070f,
+ 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.001668f, 0.005253f, 0.010010f, 0.016602f, 0.026459f, 0.042023f, 0.065369f, 0.101868f, 0.158081f, 0.241455f, 0.354248f, 0.483887f,
+ 0.606934f, 0.706055f, 0.777832f, 0.830566f, 0.867188f, 0.893066f, 0.912109f, 0.926270f, 0.938477f, 0.946289f, 0.953125f, 0.959473f,
+ 0.964355f, 0.968750f, 0.971680f, 0.975098f, 0.977051f, 0.979492f, 0.980957f, 0.982910f, 0.984375f, 0.985840f, 0.986328f, 0.987305f,
+ 0.988770f, 0.989746f, 0.990234f, 0.991211f, 0.992188f, 0.993164f, 0.993164f, 0.994141f, 0.994629f, 0.994629f, 0.995117f, 0.995605f,
+ 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998047f, 0.998535f, 0.999023f, 0.999023f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999023f, 0.001086f, 0.003477f, 0.006756f, 0.011604f, 0.018066f, 0.027222f, 0.039978f, 0.059448f,
+ 0.088257f, 0.132690f, 0.198120f, 0.291504f, 0.408447f, 0.531250f, 0.641602f, 0.728516f, 0.793457f, 0.839844f, 0.873047f, 0.896973f,
+ 0.915527f, 0.929199f, 0.939941f, 0.948730f, 0.955566f, 0.960938f, 0.965332f, 0.969238f, 0.972168f, 0.975098f, 0.977539f, 0.979492f,
+ 0.981445f, 0.983398f, 0.984375f, 0.985840f, 0.986816f, 0.988281f, 0.989258f, 0.989746f, 0.990723f, 0.991699f, 0.992188f, 0.993164f,
+ 0.993652f, 0.994141f, 0.994629f, 0.994629f, 0.995605f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.997559f, 0.997559f,
+ 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000982f, 0.002764f, 0.004925f, 0.008194f,
+ 0.012703f, 0.018417f, 0.026154f, 0.037964f, 0.053894f, 0.078552f, 0.113770f, 0.166626f, 0.242310f, 0.343262f, 0.460449f, 0.576660f,
+ 0.675293f, 0.753418f, 0.809570f, 0.851074f, 0.879883f, 0.902344f, 0.919434f, 0.931152f, 0.941895f, 0.950195f, 0.956055f, 0.960938f,
+ 0.965820f, 0.969727f, 0.973145f, 0.976074f, 0.978027f, 0.980469f, 0.981934f, 0.983887f, 0.985352f, 0.986328f, 0.987793f, 0.988770f,
+ 0.989746f, 0.990234f, 0.991211f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996582f, 0.996582f, 0.997559f, 0.997559f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000723f, 0.002268f, 0.003639f, 0.006371f, 0.009392f, 0.013046f, 0.018570f, 0.026016f, 0.035919f, 0.049957f, 0.070618f, 0.099609f,
+ 0.142212f, 0.204590f, 0.290039f, 0.396973f, 0.512207f, 0.619141f, 0.707520f, 0.775391f, 0.825195f, 0.860352f, 0.887207f, 0.907715f,
+ 0.923340f, 0.935547f, 0.944824f, 0.951660f, 0.958496f, 0.963379f, 0.967773f, 0.971191f, 0.974121f, 0.977051f, 0.979492f, 0.980957f,
+ 0.982910f, 0.984375f, 0.985352f, 0.987305f, 0.988281f, 0.989258f, 0.989746f, 0.990723f, 0.991699f, 0.992188f, 0.993164f, 0.993164f,
+ 0.994141f, 0.994629f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000364f, 0.001690f, 0.003056f, 0.004982f, 0.007217f, 0.010124f, 0.013931f, 0.018738f,
+ 0.025177f, 0.034332f, 0.045990f, 0.063599f, 0.088501f, 0.124146f, 0.175781f, 0.248047f, 0.341797f, 0.451416f, 0.562012f, 0.659668f,
+ 0.738281f, 0.797852f, 0.841797f, 0.872559f, 0.896484f, 0.914062f, 0.928711f, 0.938477f, 0.947266f, 0.954590f, 0.959473f, 0.964844f,
+ 0.969238f, 0.972168f, 0.975098f, 0.977539f, 0.979980f, 0.981934f, 0.983398f, 0.985352f, 0.986816f, 0.987793f, 0.988770f, 0.989746f,
+ 0.990723f, 0.991211f, 0.992188f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.996094f, 0.996582f,
+ 0.997070f, 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000365f, 0.001221f, 0.002531f, 0.003979f,
+ 0.005829f, 0.007874f, 0.010475f, 0.013962f, 0.018402f, 0.024368f, 0.032257f, 0.042847f, 0.057983f, 0.079346f, 0.109375f, 0.153198f,
+ 0.214233f, 0.295898f, 0.397705f, 0.506836f, 0.609863f, 0.698730f, 0.767578f, 0.817871f, 0.854980f, 0.883301f, 0.903809f, 0.920410f,
+ 0.933105f, 0.942871f, 0.950195f, 0.957031f, 0.962402f, 0.966797f, 0.970703f, 0.973633f, 0.976562f, 0.979004f, 0.981445f, 0.982910f,
+ 0.984375f, 0.985840f, 0.986816f, 0.988281f, 0.989746f, 0.989746f, 0.991211f, 0.992188f, 0.992676f, 0.993164f, 0.993652f, 0.994141f,
+ 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.000343f, 0.001357f, 0.002039f, 0.003130f, 0.004398f, 0.006432f, 0.008141f, 0.010925f, 0.014008f, 0.018326f, 0.023331f, 0.030655f,
+ 0.040558f, 0.053680f, 0.071960f, 0.098206f, 0.134644f, 0.187012f, 0.258057f, 0.349854f, 0.455566f, 0.562012f, 0.656738f, 0.734863f,
+ 0.792969f, 0.836914f, 0.868652f, 0.894043f, 0.912598f, 0.926758f, 0.937988f, 0.947266f, 0.954590f, 0.960449f, 0.964355f, 0.968750f,
+ 0.972656f, 0.975586f, 0.978027f, 0.980469f, 0.981934f, 0.983398f, 0.985840f, 0.986816f, 0.988281f, 0.989258f, 0.990723f, 0.990723f,
+ 0.991699f, 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000244f, 0.001185f, 0.001561f, 0.002504f, 0.003990f, 0.005272f, 0.006573f, 0.008606f,
+ 0.010933f, 0.013878f, 0.017715f, 0.022415f, 0.029068f, 0.038086f, 0.049774f, 0.066162f, 0.088257f, 0.120361f, 0.164917f, 0.227173f,
+ 0.308838f, 0.407959f, 0.515137f, 0.615723f, 0.700684f, 0.767090f, 0.817383f, 0.854492f, 0.882812f, 0.904297f, 0.920898f, 0.932617f,
+ 0.943359f, 0.951172f, 0.957520f, 0.962891f, 0.967773f, 0.971191f, 0.974121f, 0.977539f, 0.979492f, 0.981445f, 0.983887f, 0.985352f,
+ 0.986816f, 0.988281f, 0.988770f, 0.989258f, 0.990723f, 0.991699f, 0.992188f, 0.993164f, 0.993652f, 0.994141f, 0.995117f, 0.995605f,
+ 0.995605f, 0.996582f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000243f, 0.000847f, 0.001555f, 0.002224f,
+ 0.003141f, 0.004093f, 0.005264f, 0.006817f, 0.008850f, 0.010948f, 0.014053f, 0.017456f, 0.022339f, 0.028351f, 0.036011f, 0.046326f,
+ 0.060791f, 0.080444f, 0.107788f, 0.146851f, 0.201660f, 0.274658f, 0.366699f, 0.470215f, 0.574707f, 0.666016f, 0.740234f, 0.797363f,
+ 0.839355f, 0.871094f, 0.895508f, 0.913574f, 0.927734f, 0.938965f, 0.947754f, 0.955566f, 0.960449f, 0.965332f, 0.969727f, 0.973145f,
+ 0.976074f, 0.979004f, 0.981445f, 0.982910f, 0.984863f, 0.986328f, 0.987305f, 0.988770f, 0.989258f, 0.990723f, 0.991699f, 0.992188f,
+ 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.996094f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000244f, 0.000767f, 0.001042f, 0.001934f, 0.002502f, 0.003588f, 0.004292f, 0.005558f, 0.006824f, 0.008667f, 0.010872f, 0.013802f,
+ 0.017426f, 0.021637f, 0.027176f, 0.033936f, 0.043304f, 0.056549f, 0.073914f, 0.098083f, 0.132446f, 0.180664f, 0.245239f, 0.330078f,
+ 0.429199f, 0.533203f, 0.631348f, 0.711914f, 0.775879f, 0.823242f, 0.860352f, 0.886230f, 0.907227f, 0.923340f, 0.935059f, 0.944824f,
+ 0.952148f, 0.958984f, 0.964844f, 0.968750f, 0.972168f, 0.975586f, 0.978516f, 0.980957f, 0.982422f, 0.983887f, 0.985840f, 0.987305f,
+ 0.988770f, 0.989746f, 0.990234f, 0.992188f, 0.992676f, 0.992676f, 0.994141f, 0.994141f, 0.995117f, 0.995605f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000000f, 0.000485f, 0.001062f, 0.001658f, 0.002398f, 0.002998f, 0.003805f, 0.004723f,
+ 0.006004f, 0.007084f, 0.009102f, 0.011093f, 0.013489f, 0.016876f, 0.020813f, 0.025803f, 0.032257f, 0.040924f, 0.052673f, 0.068298f,
+ 0.090149f, 0.120239f, 0.162598f, 0.221313f, 0.298096f, 0.392822f, 0.496582f, 0.597656f, 0.684082f, 0.754883f, 0.807617f, 0.848145f,
+ 0.877930f, 0.900391f, 0.917969f, 0.931641f, 0.941406f, 0.950684f, 0.957031f, 0.962402f, 0.967773f, 0.971680f, 0.974609f, 0.978027f,
+ 0.980469f, 0.982422f, 0.984375f, 0.985840f, 0.987305f, 0.988281f, 0.989746f, 0.990723f, 0.991699f, 0.992188f, 0.993164f, 0.993652f,
+ 0.994141f, 0.995117f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000244f, 0.000477f, 0.000852f, 0.001439f,
+ 0.002045f, 0.002424f, 0.003101f, 0.004093f, 0.004887f, 0.005989f, 0.007751f, 0.008606f, 0.011002f, 0.013420f, 0.016251f, 0.020035f,
+ 0.024628f, 0.030579f, 0.039093f, 0.049255f, 0.063599f, 0.083191f, 0.109924f, 0.148071f, 0.200928f, 0.270996f, 0.359863f, 0.461670f,
+ 0.564453f, 0.656738f, 0.732910f, 0.791992f, 0.836426f, 0.869629f, 0.894531f, 0.913086f, 0.928223f, 0.939453f, 0.949219f, 0.956055f,
+ 0.961914f, 0.966797f, 0.970703f, 0.975098f, 0.977051f, 0.979492f, 0.982422f, 0.983887f, 0.985352f, 0.987305f, 0.988770f, 0.989746f,
+ 0.990723f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994629f, 0.998047f, 0.998535f, 0.998535f, 0.998047f, 0.998047f, 0.998535f,
+ 0.000242f, 0.000650f, 0.000847f, 0.001138f, 0.001621f, 0.002239f, 0.002527f, 0.003325f, 0.004227f, 0.005165f, 0.006462f, 0.007389f,
+ 0.008904f, 0.011024f, 0.013130f, 0.015915f, 0.019272f, 0.023819f, 0.029205f, 0.036652f, 0.046417f, 0.059418f, 0.077209f, 0.101562f,
+ 0.136230f, 0.183350f, 0.248047f, 0.331055f, 0.429688f, 0.533203f, 0.630859f, 0.711426f, 0.776367f, 0.824219f, 0.861328f, 0.887695f,
+ 0.908691f, 0.924805f, 0.937500f, 0.946777f, 0.954102f, 0.960938f, 0.966309f, 0.970215f, 0.974121f, 0.977539f, 0.979492f, 0.981934f,
+ 0.983887f, 0.985840f, 0.987305f, 0.989258f, 0.989746f, 0.990723f, 0.991211f, 0.992676f, 0.993164f, 0.994141f, 0.997559f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000089f, 0.000243f, 0.000827f, 0.000964f, 0.001418f, 0.001579f, 0.002296f, 0.002914f,
+ 0.003632f, 0.004280f, 0.005344f, 0.006130f, 0.007545f, 0.008949f, 0.010498f, 0.012733f, 0.015686f, 0.018646f, 0.023010f, 0.028229f,
+ 0.034851f, 0.044098f, 0.056122f, 0.072388f, 0.094788f, 0.125610f, 0.168945f, 0.228271f, 0.306396f, 0.401123f, 0.504883f, 0.604492f,
+ 0.691895f, 0.760742f, 0.813477f, 0.853027f, 0.881836f, 0.904297f, 0.921387f, 0.934570f, 0.944824f, 0.953125f, 0.959961f, 0.964844f,
+ 0.969727f, 0.973633f, 0.976562f, 0.979492f, 0.981934f, 0.983887f, 0.986328f, 0.987305f, 0.988281f, 0.989258f, 0.991211f, 0.992188f,
+ 0.992676f, 0.993652f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000069f, 0.000461f, 0.000609f, 0.000933f,
+ 0.001088f, 0.001488f, 0.001900f, 0.002378f, 0.003101f, 0.003687f, 0.004547f, 0.005276f, 0.006233f, 0.007282f, 0.008820f, 0.010239f,
+ 0.012581f, 0.015312f, 0.018341f, 0.022095f, 0.027344f, 0.034027f, 0.041687f, 0.053467f, 0.067810f, 0.088440f, 0.117126f, 0.156616f,
+ 0.211426f, 0.284180f, 0.375977f, 0.478760f, 0.581543f, 0.672363f, 0.746094f, 0.802734f, 0.845703f, 0.877441f, 0.900879f, 0.918457f,
+ 0.933105f, 0.943848f, 0.951660f, 0.959473f, 0.964355f, 0.968750f, 0.974121f, 0.977051f, 0.979492f, 0.982422f, 0.984375f, 0.985840f,
+ 0.987305f, 0.988770f, 0.990234f, 0.991211f, 0.992188f, 0.993164f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f,
+ 0.000244f, 0.000348f, 0.000606f, 0.000737f, 0.001079f, 0.001458f, 0.001783f, 0.002192f, 0.002924f, 0.003231f, 0.003862f, 0.004551f,
+ 0.005169f, 0.006367f, 0.007381f, 0.008682f, 0.010590f, 0.012199f, 0.014900f, 0.017761f, 0.021530f, 0.026108f, 0.032349f, 0.039642f,
+ 0.050446f, 0.064392f, 0.083313f, 0.109436f, 0.145996f, 0.197021f, 0.266357f, 0.354248f, 0.455811f, 0.560059f, 0.654785f, 0.732910f,
+ 0.793457f, 0.837891f, 0.873047f, 0.897461f, 0.917480f, 0.931641f, 0.941895f, 0.951172f, 0.958984f, 0.964844f, 0.969727f, 0.973633f,
+ 0.977051f, 0.979980f, 0.981934f, 0.984375f, 0.985840f, 0.988281f, 0.989258f, 0.990234f, 0.991211f, 0.992676f, 0.997070f, 0.997559f,
+ 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000244f, 0.000520f, 0.000592f, 0.000720f, 0.000812f, 0.001174f, 0.001500f, 0.001884f,
+ 0.002178f, 0.002831f, 0.003321f, 0.003885f, 0.004471f, 0.005436f, 0.006275f, 0.007584f, 0.008675f, 0.010521f, 0.012238f, 0.014557f,
+ 0.017197f, 0.020874f, 0.025467f, 0.030960f, 0.038208f, 0.047821f, 0.061249f, 0.078552f, 0.103149f, 0.136841f, 0.184937f, 0.249878f,
+ 0.334473f, 0.435059f, 0.539551f, 0.638184f, 0.720215f, 0.784668f, 0.832031f, 0.868164f, 0.894531f, 0.914062f, 0.929688f, 0.942383f,
+ 0.950684f, 0.958984f, 0.964844f, 0.970215f, 0.974121f, 0.977539f, 0.979980f, 0.982422f, 0.984863f, 0.985840f, 0.988281f, 0.989258f,
+ 0.990723f, 0.992188f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997559f, 0.997559f, 0.000000f, 0.000243f, 0.000351f, 0.000603f,
+ 0.000708f, 0.001079f, 0.001493f, 0.001752f, 0.001936f, 0.002171f, 0.002911f, 0.003382f, 0.003906f, 0.004578f, 0.005222f, 0.006161f,
+ 0.007362f, 0.008850f, 0.010010f, 0.011971f, 0.014145f, 0.016983f, 0.020477f, 0.024582f, 0.029739f, 0.036804f, 0.045837f, 0.057648f,
+ 0.074829f, 0.097534f, 0.130127f, 0.174438f, 0.236572f, 0.318604f, 0.416992f, 0.523926f, 0.624023f, 0.709961f, 0.777344f, 0.827148f,
+ 0.865234f, 0.893066f, 0.914062f, 0.929688f, 0.941406f, 0.951660f, 0.958496f, 0.965820f, 0.969238f, 0.974609f, 0.977539f, 0.980469f,
+ 0.983398f, 0.985352f, 0.986816f, 0.988281f, 0.989746f, 0.990723f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997070f,
+ 0.000243f, 0.000244f, 0.000456f, 0.000592f, 0.000602f, 0.001025f, 0.001282f, 0.001656f, 0.001856f, 0.002073f, 0.002535f, 0.002768f,
+ 0.003487f, 0.003822f, 0.004574f, 0.005589f, 0.006519f, 0.007336f, 0.008453f, 0.009911f, 0.011581f, 0.013985f, 0.016373f, 0.019638f,
+ 0.023819f, 0.028473f, 0.035339f, 0.043945f, 0.055939f, 0.071350f, 0.093140f, 0.123474f, 0.165771f, 0.225342f, 0.304199f, 0.402344f,
+ 0.509277f, 0.612305f, 0.702148f, 0.771973f, 0.824219f, 0.863281f, 0.891113f, 0.913086f, 0.930176f, 0.942383f, 0.951660f, 0.959473f,
+ 0.965820f, 0.970215f, 0.974609f, 0.977539f, 0.980957f, 0.983887f, 0.985352f, 0.987305f, 0.988770f, 0.990723f, 0.996582f, 0.996582f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.000000f, 0.000243f, 0.000276f, 0.000557f, 0.000594f, 0.000849f, 0.000845f, 0.001282f,
+ 0.001520f, 0.001774f, 0.002119f, 0.002499f, 0.002840f, 0.003252f, 0.004005f, 0.004555f, 0.005245f, 0.006168f, 0.007233f, 0.008301f,
+ 0.009911f, 0.011330f, 0.013748f, 0.015945f, 0.019089f, 0.023071f, 0.027786f, 0.034058f, 0.042542f, 0.053619f, 0.068237f, 0.089539f,
+ 0.117798f, 0.158325f, 0.215698f, 0.293213f, 0.389893f, 0.498291f, 0.603027f, 0.694824f, 0.767090f, 0.821777f, 0.862305f, 0.891113f,
+ 0.914062f, 0.930176f, 0.942383f, 0.952148f, 0.959473f, 0.965820f, 0.971680f, 0.975098f, 0.978516f, 0.981445f, 0.983887f, 0.985840f,
+ 0.988281f, 0.989258f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.996094f, 0.996582f, 0.000240f, 0.000240f, 0.000242f, 0.000365f,
+ 0.000678f, 0.000779f, 0.000957f, 0.001003f, 0.001390f, 0.001656f, 0.001828f, 0.002274f, 0.002455f, 0.003210f, 0.003704f, 0.004097f,
+ 0.004616f, 0.005409f, 0.006180f, 0.007092f, 0.008453f, 0.009521f, 0.011154f, 0.013397f, 0.015656f, 0.018509f, 0.022247f, 0.026810f,
+ 0.032928f, 0.041046f, 0.051727f, 0.065613f, 0.085205f, 0.113098f, 0.152832f, 0.208496f, 0.284424f, 0.380371f, 0.489258f, 0.596680f,
+ 0.690918f, 0.764648f, 0.821777f, 0.862305f, 0.892578f, 0.914551f, 0.931152f, 0.943848f, 0.953613f, 0.960938f, 0.967773f, 0.971680f,
+ 0.976074f, 0.979492f, 0.982422f, 0.984863f, 0.986816f, 0.988281f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.996094f,
+ 0.000000f, 0.000242f, 0.000242f, 0.000364f, 0.000465f, 0.000803f, 0.000927f, 0.000956f, 0.001275f, 0.001335f, 0.001570f, 0.001968f,
+ 0.002184f, 0.002726f, 0.003069f, 0.003294f, 0.003906f, 0.004662f, 0.005245f, 0.006027f, 0.007191f, 0.008202f, 0.009460f, 0.010735f,
+ 0.012970f, 0.015404f, 0.018051f, 0.021484f, 0.026321f, 0.032135f, 0.039581f, 0.049805f, 0.063538f, 0.082458f, 0.109497f, 0.147827f,
+ 0.202393f, 0.277344f, 0.373535f, 0.483887f, 0.593262f, 0.688477f, 0.764648f, 0.821289f, 0.863281f, 0.894043f, 0.916016f, 0.932129f,
+ 0.944336f, 0.954590f, 0.962402f, 0.968262f, 0.973633f, 0.977051f, 0.980957f, 0.983398f, 0.985352f, 0.987793f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.000000f, 0.000239f, 0.000360f, 0.000362f, 0.000363f, 0.000475f, 0.000767f, 0.000931f,
+ 0.000951f, 0.001211f, 0.001491f, 0.001634f, 0.002129f, 0.002457f, 0.002678f, 0.002995f, 0.003393f, 0.003922f, 0.004711f, 0.005135f,
+ 0.005955f, 0.006935f, 0.008072f, 0.009270f, 0.010841f, 0.012558f, 0.014618f, 0.017502f, 0.020828f, 0.025269f, 0.030884f, 0.038269f,
+ 0.048218f, 0.061554f, 0.080505f, 0.106567f, 0.144287f, 0.197998f, 0.272705f, 0.369141f, 0.480469f, 0.591797f, 0.690430f, 0.767090f,
+ 0.824707f, 0.866699f, 0.896484f, 0.918457f, 0.934570f, 0.946777f, 0.956543f, 0.963379f, 0.969727f, 0.974609f, 0.978027f, 0.981934f,
+ 0.984375f, 0.986328f, 0.995117f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.000000f, 0.000208f, 0.000238f, 0.000362f,
+ 0.000363f, 0.000555f, 0.000600f, 0.000888f, 0.001140f, 0.001140f, 0.001272f, 0.001661f, 0.001811f, 0.002041f, 0.002550f, 0.002636f,
+ 0.002941f, 0.003492f, 0.004032f, 0.004593f, 0.005062f, 0.005875f, 0.007015f, 0.007965f, 0.009079f, 0.010300f, 0.012291f, 0.014229f,
+ 0.016937f, 0.020248f, 0.024689f, 0.030151f, 0.037354f, 0.047028f, 0.060211f, 0.078491f, 0.104431f, 0.141602f, 0.195068f, 0.270264f,
+ 0.367676f, 0.480957f, 0.594238f, 0.693848f, 0.770996f, 0.828613f, 0.869629f, 0.898438f, 0.921875f, 0.937012f, 0.949219f, 0.958008f,
+ 0.964844f, 0.971680f, 0.976074f, 0.979980f, 0.982422f, 0.985840f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.995117f, 0.995117f,
+ 0.000000f, 0.000000f, 0.000229f, 0.000358f, 0.000479f, 0.000362f, 0.000498f, 0.000634f, 0.000836f, 0.000927f, 0.001288f, 0.001244f,
+ 0.001605f, 0.001732f, 0.002106f, 0.002478f, 0.002613f, 0.003183f, 0.003510f, 0.004021f, 0.004528f, 0.005047f, 0.005768f, 0.006859f,
+ 0.007759f, 0.008865f, 0.009933f, 0.011742f, 0.013741f, 0.016678f, 0.019897f, 0.024017f, 0.029297f, 0.036469f, 0.045990f, 0.058990f,
+ 0.077026f, 0.102722f, 0.140015f, 0.193604f, 0.269531f, 0.369141f, 0.485107f, 0.600098f, 0.700195f, 0.777344f, 0.833984f, 0.873535f,
+ 0.903809f, 0.924316f, 0.940430f, 0.951172f, 0.960938f, 0.968262f, 0.973145f, 0.978027f, 0.980957f, 0.983887f, 0.994629f, 0.995117f,
+ 0.995117f, 0.995605f, 0.995117f, 0.995117f, 0.000000f, 0.000000f, 0.000078f, 0.000353f, 0.000354f, 0.000360f, 0.000482f, 0.000573f,
+ 0.000757f, 0.000923f, 0.001230f, 0.001266f, 0.001485f, 0.001679f, 0.001963f, 0.002161f, 0.002235f, 0.002739f, 0.003115f, 0.003563f,
+ 0.003933f, 0.004436f, 0.004917f, 0.005623f, 0.006599f, 0.007469f, 0.008484f, 0.010101f, 0.011665f, 0.013695f, 0.016403f, 0.019531f,
+ 0.023300f, 0.028870f, 0.035889f, 0.045135f, 0.058014f, 0.075928f, 0.101746f, 0.139160f, 0.193848f, 0.271729f, 0.374023f, 0.492920f,
+ 0.609863f, 0.709473f, 0.786133f, 0.842285f, 0.880859f, 0.908691f, 0.928711f, 0.943848f, 0.954102f, 0.963867f, 0.969727f, 0.975098f,
+ 0.979004f, 0.982422f, 0.994141f, 0.994629f, 0.994141f, 0.994141f, 0.994141f, 0.994629f, 0.000000f, 0.000000f, 0.000000f, 0.000330f,
+ 0.000336f, 0.000352f, 0.000478f, 0.000481f, 0.000676f, 0.000822f, 0.001072f, 0.001228f, 0.001283f, 0.001417f, 0.001621f, 0.001938f,
+ 0.001953f, 0.002377f, 0.002737f, 0.002914f, 0.003624f, 0.003721f, 0.004555f, 0.004845f, 0.005531f, 0.006325f, 0.007244f, 0.008255f,
+ 0.009911f, 0.011467f, 0.013496f, 0.016068f, 0.018951f, 0.022888f, 0.028183f, 0.035126f, 0.044617f, 0.057220f, 0.075134f, 0.101501f,
+ 0.139526f, 0.195679f, 0.276123f, 0.381592f, 0.503418f, 0.622070f, 0.721680f, 0.796387f, 0.850098f, 0.887207f, 0.914551f, 0.933594f,
+ 0.947266f, 0.957520f, 0.966797f, 0.972656f, 0.977539f, 0.980957f, 0.993164f, 0.994141f, 0.994141f, 0.994141f, 0.994141f, 0.994141f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000243f, 0.000466f, 0.000474f, 0.000475f, 0.000600f, 0.000740f, 0.000796f, 0.001130f,
+ 0.001333f, 0.001339f, 0.001440f, 0.001575f, 0.001961f, 0.002031f, 0.002388f, 0.002563f, 0.003174f, 0.003345f, 0.003555f, 0.004143f,
+ 0.004681f, 0.005333f, 0.006191f, 0.007111f, 0.008278f, 0.009666f, 0.011177f, 0.013451f, 0.015511f, 0.018707f, 0.022629f, 0.027847f,
+ 0.034515f, 0.043976f, 0.056671f, 0.075012f, 0.101685f, 0.140869f, 0.199341f, 0.282959f, 0.393311f, 0.519043f, 0.639160f, 0.736328f,
+ 0.809082f, 0.860352f, 0.896484f, 0.920898f, 0.939453f, 0.951660f, 0.961914f, 0.969238f, 0.975098f, 0.979492f, 0.993164f, 0.993652f,
+ 0.994141f, 0.993652f, 0.993652f, 0.993652f, 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000120f, 0.000367f, 0.000448f, 0.000589f,
+ 0.000595f, 0.000719f, 0.000707f, 0.000809f, 0.000966f, 0.001217f, 0.001369f, 0.001405f, 0.001579f, 0.001786f, 0.002100f, 0.002260f,
+ 0.002600f, 0.002762f, 0.003023f, 0.003531f, 0.004219f, 0.004810f, 0.005409f, 0.006092f, 0.007053f, 0.008064f, 0.009163f, 0.010941f,
+ 0.012733f, 0.015251f, 0.018280f, 0.022202f, 0.027573f, 0.034271f, 0.043732f, 0.056458f, 0.075134f, 0.102661f, 0.143433f, 0.205078f,
+ 0.293701f, 0.409668f, 0.538574f, 0.658203f, 0.753418f, 0.823242f, 0.870605f, 0.905273f, 0.927734f, 0.943848f, 0.956055f, 0.964844f,
+ 0.972168f, 0.977539f, 0.992188f, 0.992676f, 0.993164f, 0.993652f, 0.993164f, 0.992676f, 0.000000f, 0.000000f, 0.000000f, 0.000111f,
+ 0.000224f, 0.000231f, 0.000314f, 0.000562f, 0.000589f, 0.000699f, 0.000717f, 0.000776f, 0.000926f, 0.000968f, 0.001242f, 0.001360f,
+ 0.001487f, 0.001564f, 0.001713f, 0.002073f, 0.002169f, 0.002380f, 0.002941f, 0.003229f, 0.003534f, 0.003914f, 0.004509f, 0.005127f,
+ 0.005939f, 0.006596f, 0.007812f, 0.009354f, 0.010559f, 0.012581f, 0.015007f, 0.018021f, 0.022079f, 0.027191f, 0.034119f, 0.043427f,
+ 0.057190f, 0.075623f, 0.104492f, 0.147949f, 0.213135f, 0.308105f, 0.430664f, 0.562500f, 0.681641f, 0.772949f, 0.839355f, 0.884277f,
+ 0.913574f, 0.934570f, 0.950195f, 0.961426f, 0.969238f, 0.975098f, 0.991211f, 0.992676f, 0.992676f, 0.992676f, 0.992676f, 0.992188f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000084f, 0.000117f, 0.000119f, 0.000367f, 0.000473f, 0.000555f, 0.000576f, 0.000674f, 0.000713f,
+ 0.000816f, 0.000913f, 0.001049f, 0.001168f, 0.001263f, 0.001473f, 0.001580f, 0.001781f, 0.002005f, 0.002123f, 0.002316f, 0.002674f,
+ 0.003094f, 0.003475f, 0.003967f, 0.004318f, 0.004833f, 0.005798f, 0.006699f, 0.007801f, 0.008888f, 0.010429f, 0.012268f, 0.014824f,
+ 0.017792f, 0.021790f, 0.026978f, 0.033844f, 0.043518f, 0.057068f, 0.077148f, 0.107605f, 0.154053f, 0.224609f, 0.326904f, 0.456543f,
+ 0.591797f, 0.708984f, 0.795410f, 0.855957f, 0.895508f, 0.923340f, 0.942383f, 0.955566f, 0.965332f, 0.973145f, 0.991211f, 0.991699f,
+ 0.992188f, 0.992188f, 0.992188f, 0.991699f, 0.000000f, 0.000000f, 0.000000f, 0.000092f, 0.000070f, 0.000236f, 0.000119f, 0.000376f,
+ 0.000433f, 0.000561f, 0.000688f, 0.000586f, 0.000742f, 0.000842f, 0.000881f, 0.000937f, 0.001141f, 0.001300f, 0.001434f, 0.001464f,
+ 0.001598f, 0.001829f, 0.002062f, 0.002338f, 0.002583f, 0.003036f, 0.003460f, 0.003704f, 0.004383f, 0.004986f, 0.005615f, 0.006439f,
+ 0.007267f, 0.008797f, 0.010330f, 0.012146f, 0.014473f, 0.017532f, 0.021622f, 0.026535f, 0.033539f, 0.043579f, 0.058044f, 0.079041f,
+ 0.111572f, 0.162109f, 0.239746f, 0.350830f, 0.488770f, 0.625000f, 0.737305f, 0.817871f, 0.871582f, 0.908203f, 0.932129f, 0.949219f,
+ 0.961914f, 0.970215f, 0.990234f, 0.991211f, 0.991211f, 0.991211f, 0.991211f, 0.991211f, 0.000000f, 0.000000f, 0.000000f, 0.000080f,
+ 0.000100f, 0.000115f, 0.000335f, 0.000350f, 0.000355f, 0.000473f, 0.000633f, 0.000678f, 0.000695f, 0.000694f, 0.000812f, 0.000733f,
+ 0.001109f, 0.001098f, 0.001260f, 0.001452f, 0.001377f, 0.001534f, 0.001972f, 0.001982f, 0.002232f, 0.002567f, 0.002764f, 0.003273f,
+ 0.003542f, 0.004181f, 0.004738f, 0.005466f, 0.006268f, 0.007126f, 0.008614f, 0.010170f, 0.012093f, 0.014359f, 0.017075f, 0.021042f,
+ 0.026459f, 0.033722f, 0.044159f, 0.059113f, 0.082092f, 0.117249f, 0.173218f, 0.259766f, 0.382080f, 0.526367f, 0.662598f, 0.768066f,
+ 0.840332f, 0.889648f, 0.920410f, 0.940918f, 0.956543f, 0.966309f, 0.989746f, 0.990234f, 0.990723f, 0.990723f, 0.990723f, 0.990723f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000191f, 0.000236f, 0.000335f, 0.000337f, 0.000466f, 0.000399f, 0.000608f,
+ 0.000626f, 0.000669f, 0.000696f, 0.000808f, 0.000859f, 0.000915f, 0.000903f, 0.001168f, 0.001245f, 0.001500f, 0.001525f, 0.001863f,
+ 0.001941f, 0.002121f, 0.002399f, 0.002861f, 0.002953f, 0.003632f, 0.004105f, 0.004745f, 0.005333f, 0.006317f, 0.007236f, 0.008255f,
+ 0.009857f, 0.011414f, 0.014015f, 0.016922f, 0.020828f, 0.026321f, 0.034149f, 0.044861f, 0.061279f, 0.085571f, 0.124878f, 0.187866f,
+ 0.285645f, 0.420654f, 0.570801f, 0.703125f, 0.799805f, 0.864258f, 0.905273f, 0.932129f, 0.950684f, 0.963379f, 0.988770f, 0.989258f,
+ 0.989746f, 0.989746f, 0.989746f, 0.989746f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000000f, 0.000122f, 0.000125f, 0.000232f,
+ 0.000360f, 0.000342f, 0.000463f, 0.000388f, 0.000569f, 0.000638f, 0.000671f, 0.000791f, 0.000774f, 0.000943f, 0.000774f, 0.001018f,
+ 0.001044f, 0.001245f, 0.001377f, 0.001410f, 0.001643f, 0.001970f, 0.002041f, 0.002316f, 0.002758f, 0.003023f, 0.003433f, 0.003859f,
+ 0.004444f, 0.005180f, 0.006134f, 0.006920f, 0.008102f, 0.009354f, 0.011475f, 0.013649f, 0.016739f, 0.021011f, 0.026566f, 0.034454f,
+ 0.046051f, 0.063843f, 0.090942f, 0.135498f, 0.207642f, 0.319580f, 0.467529f, 0.620605f, 0.745605f, 0.830566f, 0.886230f, 0.920898f,
+ 0.943848f, 0.958984f, 0.987793f, 0.988281f, 0.988770f, 0.988770f, 0.988281f, 0.988770f, 0.000000f, 0.000000f, 0.000000f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000188f, 0.000200f, 0.000332f, 0.000417f, 0.000338f, 0.000459f, 0.000349f, 0.000558f, 0.000642f, 0.000636f,
+ 0.000629f, 0.000807f, 0.000695f, 0.000747f, 0.000827f, 0.001058f, 0.001182f, 0.001269f, 0.001422f, 0.001472f, 0.001921f, 0.002100f,
+ 0.002337f, 0.002462f, 0.003073f, 0.003374f, 0.003708f, 0.004265f, 0.004826f, 0.005646f, 0.006596f, 0.007710f, 0.008926f, 0.011063f,
+ 0.013580f, 0.016495f, 0.020737f, 0.026459f, 0.035126f, 0.047791f, 0.066833f, 0.097778f, 0.149170f, 0.233887f, 0.363037f, 0.523438f,
+ 0.674805f, 0.788086f, 0.860352f, 0.906250f, 0.935547f, 0.954102f, 0.986328f, 0.987305f, 0.987305f, 0.987305f, 0.987305f, 0.987793f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000175f, 0.000155f, 0.000319f, 0.000241f, 0.000318f,
+ 0.000455f, 0.000462f, 0.000496f, 0.000593f, 0.000516f, 0.000564f, 0.000667f, 0.000668f, 0.000715f, 0.000749f, 0.000925f, 0.001111f,
+ 0.001246f, 0.001381f, 0.001443f, 0.001856f, 0.001997f, 0.002264f, 0.002363f, 0.002880f, 0.003212f, 0.003727f, 0.004208f, 0.004673f,
+ 0.005394f, 0.006367f, 0.007404f, 0.009003f, 0.010651f, 0.013138f, 0.016312f, 0.020767f, 0.027054f, 0.036377f, 0.050262f, 0.071655f,
+ 0.107361f, 0.167969f, 0.269287f, 0.418457f, 0.587402f, 0.730957f, 0.828125f, 0.888184f, 0.924805f, 0.948242f, 0.984863f, 0.986328f,
+ 0.986328f, 0.985840f, 0.986328f, 0.986328f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f,
+ 0.000202f, 0.000133f, 0.000215f, 0.000263f, 0.000304f, 0.000442f, 0.000332f, 0.000365f, 0.000403f, 0.000549f, 0.000607f, 0.000750f,
+ 0.000788f, 0.000802f, 0.000841f, 0.000958f, 0.001049f, 0.001188f, 0.001354f, 0.001318f, 0.001582f, 0.001928f, 0.002064f, 0.002321f,
+ 0.002594f, 0.003042f, 0.003222f, 0.003796f, 0.004440f, 0.005112f, 0.006081f, 0.007259f, 0.008736f, 0.010612f, 0.013077f, 0.016464f,
+ 0.020950f, 0.027664f, 0.037506f, 0.052795f, 0.077698f, 0.120361f, 0.194336f, 0.317627f, 0.486572f, 0.657227f, 0.785156f, 0.865234f,
+ 0.913086f, 0.942871f, 0.983887f, 0.984863f, 0.984375f, 0.984863f, 0.984375f, 0.984863f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000152f, 0.000257f, 0.000243f, 0.000288f, 0.000345f, 0.000228f,
+ 0.000358f, 0.000363f, 0.000432f, 0.000494f, 0.000530f, 0.000582f, 0.000762f, 0.000771f, 0.000913f, 0.000978f, 0.001100f, 0.001305f,
+ 0.001373f, 0.001706f, 0.001712f, 0.001922f, 0.002155f, 0.002569f, 0.002573f, 0.003094f, 0.003401f, 0.004272f, 0.004978f, 0.005829f,
+ 0.006924f, 0.008453f, 0.010452f, 0.012871f, 0.016617f, 0.021072f, 0.028427f, 0.039429f, 0.056732f, 0.086243f, 0.138916f, 0.231812f,
+ 0.381592f, 0.566406f, 0.726562f, 0.833496f, 0.896973f, 0.933594f, 0.981934f, 0.982910f, 0.982910f, 0.982910f, 0.982910f, 0.982910f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000121f, 0.000127f, 0.000215f,
+ 0.000159f, 0.000233f, 0.000284f, 0.000326f, 0.000339f, 0.000339f, 0.000352f, 0.000394f, 0.000623f, 0.000622f, 0.000731f, 0.000730f,
+ 0.000741f, 0.000829f, 0.000914f, 0.001017f, 0.001151f, 0.001469f, 0.001263f, 0.001480f, 0.001740f, 0.002069f, 0.002104f, 0.002443f,
+ 0.002831f, 0.003519f, 0.003929f, 0.004627f, 0.005455f, 0.006634f, 0.008316f, 0.009949f, 0.012596f, 0.016495f, 0.021729f, 0.029877f,
+ 0.042084f, 0.062805f, 0.098694f, 0.165283f, 0.284668f, 0.465088f, 0.654297f, 0.793945f, 0.877930f, 0.924805f, 0.979980f, 0.980957f,
+ 0.980957f, 0.981445f, 0.981445f, 0.980957f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000150f, 0.000163f, 0.000069f, 0.000057f, 0.000121f, 0.000231f, 0.000291f, 0.000304f, 0.000334f, 0.000339f,
+ 0.000346f, 0.000569f, 0.000648f, 0.000674f, 0.000649f, 0.000697f, 0.000772f, 0.000834f, 0.000972f, 0.001005f, 0.001189f, 0.001359f,
+ 0.001237f, 0.001567f, 0.001794f, 0.001963f, 0.002378f, 0.002712f, 0.002867f, 0.003853f, 0.004330f, 0.005196f, 0.006516f, 0.008026f,
+ 0.009888f, 0.012703f, 0.016479f, 0.022110f, 0.031158f, 0.045746f, 0.070557f, 0.117004f, 0.204956f, 0.360596f, 0.564453f, 0.740723f,
+ 0.852051f, 0.912598f, 0.977539f, 0.979492f, 0.979492f, 0.979004f, 0.979492f, 0.979004f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000098f, 0.000082f, 0.000067f, 0.000056f, 0.000124f,
+ 0.000193f, 0.000240f, 0.000258f, 0.000310f, 0.000326f, 0.000335f, 0.000341f, 0.000471f, 0.000613f, 0.000494f, 0.000716f, 0.000742f,
+ 0.000804f, 0.000873f, 0.000832f, 0.001070f, 0.001120f, 0.001146f, 0.001225f, 0.001696f, 0.001814f, 0.002041f, 0.002419f, 0.002941f,
+ 0.003433f, 0.004154f, 0.004818f, 0.006077f, 0.007652f, 0.009521f, 0.012444f, 0.017029f, 0.023193f, 0.033539f, 0.050690f, 0.082092f,
+ 0.144043f, 0.265869f, 0.463379f, 0.672363f, 0.818848f, 0.898438f, 0.975586f, 0.976562f, 0.976562f, 0.976562f, 0.976074f, 0.976562f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000114f,
+ 0.000096f, 0.000079f, 0.000125f, 0.000056f, 0.000142f, 0.000120f, 0.000195f, 0.000246f, 0.000321f, 0.000305f, 0.000319f, 0.000395f,
+ 0.000442f, 0.000540f, 0.000642f, 0.000638f, 0.000696f, 0.000674f, 0.000687f, 0.000857f, 0.000955f, 0.001128f, 0.001224f, 0.001364f,
+ 0.001347f, 0.001555f, 0.001910f, 0.002245f, 0.002714f, 0.003229f, 0.003824f, 0.004673f, 0.005676f, 0.007225f, 0.009293f, 0.012802f,
+ 0.017273f, 0.024368f, 0.036682f, 0.058075f, 0.100952f, 0.188721f, 0.358154f, 0.587891f, 0.775879f, 0.881348f, 0.972168f, 0.972656f,
+ 0.972656f, 0.973145f, 0.973145f, 0.973633f, 0.000000f, 0.000000f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000120f, 0.000112f, 0.000093f, 0.000079f, 0.000067f, 0.000057f, 0.000049f, 0.000133f, 0.000137f,
+ 0.000163f, 0.000244f, 0.000328f, 0.000366f, 0.000356f, 0.000415f, 0.000436f, 0.000543f, 0.000555f, 0.000638f, 0.000597f, 0.000702f,
+ 0.000786f, 0.000648f, 0.000891f, 0.000804f, 0.001218f, 0.001070f, 0.001355f, 0.001731f, 0.002171f, 0.002352f, 0.002796f, 0.003546f,
+ 0.004189f, 0.005558f, 0.006939f, 0.009209f, 0.012337f, 0.017776f, 0.026016f, 0.040833f, 0.069946f, 0.130981f, 0.262207f, 0.489258f,
+ 0.719238f, 0.859375f, 0.968262f, 0.969238f, 0.969727f, 0.969727f, 0.969727f, 0.969727f, 0.000000f, 0.000122f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000110f, 0.000093f, 0.000080f,
+ 0.000068f, 0.000094f, 0.000119f, 0.000117f, 0.000120f, 0.000123f, 0.000173f, 0.000263f, 0.000263f, 0.000359f, 0.000386f, 0.000390f,
+ 0.000401f, 0.000556f, 0.000549f, 0.000573f, 0.000502f, 0.000707f, 0.000789f, 0.000629f, 0.000847f, 0.001003f, 0.001024f, 0.001242f,
+ 0.001423f, 0.001877f, 0.002012f, 0.002571f, 0.003071f, 0.003925f, 0.005131f, 0.006767f, 0.009140f, 0.012672f, 0.018509f, 0.028992f,
+ 0.048309f, 0.089233f, 0.183838f, 0.383545f, 0.646973f, 0.830078f, 0.963867f, 0.964844f, 0.964844f, 0.965820f, 0.965820f, 0.965820f,
+ 0.000000f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000120f,
+ 0.000119f, 0.000119f, 0.000113f, 0.000095f, 0.000083f, 0.000070f, 0.000061f, 0.000054f, 0.000048f, 0.000042f, 0.000115f, 0.000112f,
+ 0.000151f, 0.000213f, 0.000309f, 0.000298f, 0.000359f, 0.000337f, 0.000382f, 0.000440f, 0.000576f, 0.000477f, 0.000453f, 0.000690f,
+ 0.000687f, 0.000795f, 0.000776f, 0.000911f, 0.001117f, 0.001119f, 0.001352f, 0.002001f, 0.002140f, 0.002832f, 0.003609f, 0.004715f,
+ 0.006302f, 0.008835f, 0.013115f, 0.020004f, 0.032867f, 0.060333f, 0.124512f, 0.281982f, 0.557617f, 0.794434f, 0.959473f, 0.959961f,
+ 0.960449f, 0.960449f, 0.960449f, 0.959961f, 0.000122f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000119f, 0.000119f,
+ 0.000119f, 0.000119f, 0.000119f, 0.000119f, 0.000118f, 0.000118f, 0.000118f, 0.000116f, 0.000098f, 0.000087f, 0.000076f, 0.000065f,
+ 0.000057f, 0.000050f, 0.000045f, 0.000091f, 0.000074f, 0.000106f, 0.000185f, 0.000193f, 0.000228f, 0.000328f, 0.000323f, 0.000399f,
+ 0.000429f, 0.000498f, 0.000552f, 0.000432f, 0.000542f, 0.000592f, 0.000599f, 0.000729f, 0.000734f, 0.000885f, 0.001304f, 0.001273f,
+ 0.001756f, 0.001931f, 0.002445f, 0.003120f, 0.004456f, 0.006165f, 0.008751f, 0.013466f, 0.022141f, 0.040192f, 0.082397f, 0.195679f,
+ 0.455322f, 0.745117f, 0.952637f, 0.953613f, 0.953613f, 0.954102f, 0.952637f, 0.953613f, 0.000000f, 0.000120f, 0.000120f, 0.000119f,
+ 0.000119f, 0.000119f, 0.000118f, 0.000118f, 0.000118f, 0.000118f, 0.000118f, 0.000117f, 0.000117f, 0.000117f, 0.000117f, 0.000117f,
+ 0.000117f, 0.000104f, 0.000092f, 0.000079f, 0.000071f, 0.000062f, 0.000055f, 0.000049f, 0.000044f, 0.000039f, 0.000099f, 0.000106f,
+ 0.000158f, 0.000169f, 0.000241f, 0.000274f, 0.000293f, 0.000389f, 0.000360f, 0.000399f, 0.000387f, 0.000446f, 0.000401f, 0.000530f,
+ 0.000565f, 0.000691f, 0.000722f, 0.000848f, 0.001147f, 0.001418f, 0.001677f, 0.002087f, 0.002972f, 0.004169f, 0.005623f, 0.008835f,
+ 0.014404f, 0.026077f, 0.053467f, 0.129395f, 0.346924f, 0.685059f, 0.943848f, 0.945801f, 0.945801f, 0.945312f, 0.945801f, 0.945801f,
+ 0.000000f, 0.000000f, 0.000117f, 0.000116f, 0.000117f, 0.000117f, 0.000116f, 0.000116f, 0.000115f, 0.000116f, 0.000115f, 0.000116f,
+ 0.000115f, 0.000115f, 0.000115f, 0.000115f, 0.000115f, 0.000115f, 0.000110f, 0.000097f, 0.000086f, 0.000077f, 0.000067f, 0.000060f,
+ 0.000053f, 0.000048f, 0.000043f, 0.000061f, 0.000090f, 0.000083f, 0.000139f, 0.000139f, 0.000216f, 0.000254f, 0.000307f, 0.000358f,
+ 0.000269f, 0.000377f, 0.000324f, 0.000369f, 0.000405f, 0.000455f, 0.000524f, 0.000706f, 0.000701f, 0.001012f, 0.001206f, 0.001316f,
+ 0.001663f, 0.002350f, 0.003571f, 0.005505f, 0.008873f, 0.016006f, 0.033234f, 0.081848f, 0.244751f, 0.605469f, 0.934082f, 0.935059f,
+ 0.936035f, 0.935547f, 0.935547f, 0.935547f, 0.000105f, 0.000114f, 0.000113f, 0.000113f, 0.000111f, 0.000111f, 0.000112f, 0.000111f,
+ 0.000112f, 0.000112f, 0.000112f, 0.000112f, 0.000111f, 0.000112f, 0.000112f, 0.000112f, 0.000112f, 0.000112f, 0.000112f, 0.000112f,
+ 0.000105f, 0.000093f, 0.000083f, 0.000074f, 0.000066f, 0.000059f, 0.000053f, 0.000048f, 0.000043f, 0.000062f, 0.000052f, 0.000063f,
+ 0.000092f, 0.000146f, 0.000176f, 0.000216f, 0.000227f, 0.000263f, 0.000244f, 0.000267f, 0.000370f, 0.000326f, 0.000360f, 0.000391f,
+ 0.000505f, 0.000618f, 0.000726f, 0.000969f, 0.001117f, 0.001651f, 0.002131f, 0.003090f, 0.005188f, 0.009499f, 0.019836f, 0.049042f,
+ 0.159180f, 0.509766f, 0.921875f, 0.922852f, 0.922852f, 0.922363f, 0.923340f, 0.922852f, 0.000000f, 0.000000f, 0.000065f, 0.000098f,
+ 0.000096f, 0.000101f, 0.000100f, 0.000104f, 0.000104f, 0.000103f, 0.000106f, 0.000106f, 0.000106f, 0.000105f, 0.000107f, 0.000107f,
+ 0.000106f, 0.000107f, 0.000107f, 0.000108f, 0.000107f, 0.000108f, 0.000104f, 0.000092f, 0.000082f, 0.000075f, 0.000067f, 0.000059f,
+ 0.000054f, 0.000048f, 0.000044f, 0.000039f, 0.000037f, 0.000058f, 0.000066f, 0.000122f, 0.000137f, 0.000175f, 0.000208f, 0.000194f,
+ 0.000208f, 0.000240f, 0.000270f, 0.000281f, 0.000323f, 0.000364f, 0.000479f, 0.000591f, 0.000712f, 0.000986f, 0.001224f, 0.001896f,
+ 0.002996f, 0.005196f, 0.010506f, 0.027527f, 0.095581f, 0.399658f, 0.905762f, 0.906738f, 0.906250f, 0.905762f, 0.905762f, 0.907227f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000017f, 0.000030f, 0.000054f, 0.000061f, 0.000081f, 0.000087f, 0.000088f, 0.000089f, 0.000093f,
+ 0.000093f, 0.000096f, 0.000096f, 0.000097f, 0.000098f, 0.000099f, 0.000098f, 0.000100f, 0.000100f, 0.000101f, 0.000100f, 0.000101f,
+ 0.000101f, 0.000092f, 0.000082f, 0.000074f, 0.000067f, 0.000060f, 0.000054f, 0.000049f, 0.000045f, 0.000040f, 0.000036f, 0.000037f,
+ 0.000059f, 0.000077f, 0.000093f, 0.000143f, 0.000155f, 0.000188f, 0.000178f, 0.000184f, 0.000231f, 0.000234f, 0.000272f, 0.000352f,
+ 0.000420f, 0.000525f, 0.000764f, 0.001091f, 0.001653f, 0.002705f, 0.005474f, 0.013939f, 0.051880f, 0.283691f, 0.883789f, 0.884766f,
+ 0.885254f, 0.885254f, 0.885742f, 0.885254f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000013f,
+ 0.000032f, 0.000046f, 0.000050f, 0.000060f, 0.000065f, 0.000065f, 0.000075f, 0.000078f, 0.000080f, 0.000079f, 0.000084f, 0.000083f,
+ 0.000087f, 0.000087f, 0.000089f, 0.000090f, 0.000091f, 0.000091f, 0.000092f, 0.000092f, 0.000083f, 0.000075f, 0.000068f, 0.000062f,
+ 0.000056f, 0.000050f, 0.000046f, 0.000042f, 0.000037f, 0.000039f, 0.000044f, 0.000072f, 0.000068f, 0.000089f, 0.000125f, 0.000124f,
+ 0.000126f, 0.000153f, 0.000183f, 0.000212f, 0.000219f, 0.000311f, 0.000363f, 0.000566f, 0.000846f, 0.001332f, 0.002522f, 0.006252f,
+ 0.023834f, 0.175415f, 0.855957f, 0.856934f, 0.856934f, 0.856934f, 0.857422f, 0.856934f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000007f, 0.000024f, 0.000028f,
+ 0.000040f, 0.000044f, 0.000051f, 0.000053f, 0.000060f, 0.000063f, 0.000064f, 0.000067f, 0.000071f, 0.000072f, 0.000074f, 0.000076f,
+ 0.000077f, 0.000079f, 0.000079f, 0.000075f, 0.000068f, 0.000062f, 0.000056f, 0.000051f, 0.000046f, 0.000042f, 0.000038f, 0.000034f,
+ 0.000031f, 0.000030f, 0.000045f, 0.000079f, 0.000081f, 0.000107f, 0.000114f, 0.000106f, 0.000144f, 0.000136f, 0.000171f, 0.000254f,
+ 0.000377f, 0.000531f, 0.001037f, 0.002504f, 0.009140f, 0.088379f, 0.818848f, 0.820801f, 0.819824f, 0.820312f, 0.819336f, 0.820801f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000007f, 0.000014f, 0.000021f, 0.000028f,
+ 0.000034f, 0.000036f, 0.000042f, 0.000046f, 0.000049f, 0.000052f, 0.000054f, 0.000056f, 0.000059f, 0.000061f, 0.000064f, 0.000061f,
+ 0.000055f, 0.000050f, 0.000045f, 0.000041f, 0.000037f, 0.000033f, 0.000030f, 0.000027f, 0.000024f, 0.000033f, 0.000060f, 0.000059f,
+ 0.000075f, 0.000073f, 0.000101f, 0.000089f, 0.000144f, 0.000226f, 0.000384f, 0.000847f, 0.003033f, 0.031860f, 0.770020f, 0.770996f,
+ 0.772461f, 0.771973f, 0.772461f, 0.771973f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000006f, 0.000010f, 0.000016f,
+ 0.000021f, 0.000023f, 0.000029f, 0.000032f, 0.000036f, 0.000039f, 0.000042f, 0.000044f, 0.000042f, 0.000038f, 0.000035f, 0.000031f,
+ 0.000028f, 0.000025f, 0.000022f, 0.000020f, 0.000017f, 0.000024f, 0.000040f, 0.000047f, 0.000053f, 0.000063f, 0.000087f, 0.000190f,
+ 0.000666f, 0.007278f, 0.708496f, 0.709961f, 0.710449f, 0.710938f, 0.710938f, 0.710449f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f,
+ 0.000005f, 0.000010f, 0.000014f, 0.000018f, 0.000021f, 0.000024f, 0.000024f, 0.000021f, 0.000018f, 0.000016f, 0.000014f, 0.000012f,
+ 0.000008f, 0.000020f, 0.000022f, 0.000025f, 0.000073f, 0.000744f, 0.632324f, 0.632812f, 0.633789f, 0.633789f, 0.633301f, 0.632812f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000003f, 0.000007f, 0.000006f, 0.000004f, 0.000005f, 0.000007f, 0.543945f, 0.545410f,
+ 0.545410f, 0.545410f, 0.546387f, 0.545898f,
+ },
+ {
+ 0.159546f, 0.492676f, 0.684570f, 0.783203f, 0.838379f, 0.873535f, 0.897949f, 0.913574f, 0.926270f, 0.936035f, 0.943359f, 0.950195f,
+ 0.955566f, 0.959473f, 0.963379f, 0.966797f, 0.969238f, 0.972168f, 0.973633f, 0.976562f, 0.978027f, 0.979492f, 0.980957f, 0.982422f,
+ 0.983887f, 0.984863f, 0.985840f, 0.986816f, 0.987793f, 0.988770f, 0.989258f, 0.989746f, 0.990234f, 0.990723f, 0.991699f, 0.992676f,
+ 0.993164f, 0.993652f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995117f, 0.995605f, 0.996582f, 0.996582f, 0.997070f, 0.997070f,
+ 0.997070f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.034119f, 0.154175f, 0.341309f, 0.532227f, 0.672363f, 0.763184f, 0.820801f, 0.858398f,
+ 0.885742f, 0.904297f, 0.918945f, 0.929199f, 0.938965f, 0.945801f, 0.951660f, 0.956543f, 0.961426f, 0.964355f, 0.968262f, 0.970703f,
+ 0.973145f, 0.975586f, 0.977539f, 0.979004f, 0.980469f, 0.981934f, 0.983398f, 0.984375f, 0.985352f, 0.986328f, 0.987305f, 0.988281f,
+ 0.988770f, 0.989746f, 0.990234f, 0.991211f, 0.991699f, 0.992676f, 0.993164f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f,
+ 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.999023f,
+ 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.013390f, 0.056915f, 0.134155f, 0.257080f,
+ 0.412109f, 0.560547f, 0.675781f, 0.755859f, 0.812012f, 0.851074f, 0.877930f, 0.898926f, 0.913574f, 0.925781f, 0.935059f, 0.942871f,
+ 0.949707f, 0.954590f, 0.959473f, 0.963379f, 0.966797f, 0.969238f, 0.971680f, 0.975098f, 0.976562f, 0.978516f, 0.979980f, 0.980957f,
+ 0.982422f, 0.984375f, 0.985352f, 0.985840f, 0.987305f, 0.987793f, 0.988770f, 0.989746f, 0.990723f, 0.991211f, 0.991699f, 0.992188f,
+ 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995605f, 0.995605f, 0.995605f, 0.996582f, 0.996582f, 0.997070f, 0.997070f,
+ 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f,
+ 0.006939f, 0.027863f, 0.061951f, 0.117859f, 0.204834f, 0.324707f, 0.460205f, 0.585449f, 0.684570f, 0.757324f, 0.810059f, 0.847168f,
+ 0.874023f, 0.895996f, 0.910645f, 0.922852f, 0.933105f, 0.940918f, 0.947754f, 0.953613f, 0.958496f, 0.961914f, 0.965820f, 0.968750f,
+ 0.971680f, 0.974121f, 0.976074f, 0.978027f, 0.979492f, 0.981445f, 0.982910f, 0.983887f, 0.984863f, 0.986328f, 0.987305f, 0.988281f,
+ 0.988770f, 0.989746f, 0.990234f, 0.990723f, 0.991699f, 0.992188f, 0.993164f, 0.993652f, 0.993652f, 0.994141f, 0.995117f, 0.995605f,
+ 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.998535f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.004211f, 0.016022f, 0.034119f, 0.061432f, 0.104797f, 0.170288f, 0.262695f, 0.377686f,
+ 0.499756f, 0.608887f, 0.696777f, 0.762207f, 0.810547f, 0.847168f, 0.873535f, 0.893066f, 0.910156f, 0.922852f, 0.932617f, 0.939941f,
+ 0.946777f, 0.953125f, 0.958496f, 0.961914f, 0.965332f, 0.968750f, 0.971680f, 0.973633f, 0.975586f, 0.977539f, 0.979492f, 0.981445f,
+ 0.982910f, 0.984375f, 0.985840f, 0.986328f, 0.987793f, 0.987793f, 0.989258f, 0.989746f, 0.990723f, 0.991211f, 0.992188f, 0.992676f,
+ 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f,
+ 0.998047f, 0.998535f, 0.999512f, 0.999512f, 0.999023f, 0.999512f, 0.999023f, 0.999023f, 0.002724f, 0.010384f, 0.020813f, 0.036285f,
+ 0.059784f, 0.093933f, 0.145508f, 0.218018f, 0.313232f, 0.424072f, 0.534180f, 0.632812f, 0.709961f, 0.769531f, 0.815918f, 0.848145f,
+ 0.874512f, 0.894043f, 0.909668f, 0.922363f, 0.932129f, 0.939941f, 0.946777f, 0.953125f, 0.958008f, 0.961914f, 0.965332f, 0.968750f,
+ 0.971680f, 0.973633f, 0.976562f, 0.978516f, 0.979980f, 0.981445f, 0.982910f, 0.984863f, 0.985352f, 0.986816f, 0.987793f, 0.988281f,
+ 0.988770f, 0.989746f, 0.990723f, 0.991211f, 0.992188f, 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996582f, 0.996582f, 0.997559f, 0.997559f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f,
+ 0.002113f, 0.007004f, 0.014091f, 0.023895f, 0.037811f, 0.057373f, 0.085632f, 0.127075f, 0.185425f, 0.263672f, 0.360596f, 0.465576f,
+ 0.566895f, 0.655762f, 0.725586f, 0.779297f, 0.822266f, 0.853516f, 0.877441f, 0.895996f, 0.911621f, 0.923828f, 0.933105f, 0.940918f,
+ 0.947754f, 0.953613f, 0.957520f, 0.962402f, 0.965820f, 0.968750f, 0.972168f, 0.974121f, 0.976074f, 0.978027f, 0.980469f, 0.981934f,
+ 0.983398f, 0.984863f, 0.985352f, 0.986328f, 0.988281f, 0.988281f, 0.989258f, 0.990234f, 0.991211f, 0.992188f, 0.992676f, 0.993164f,
+ 0.993652f, 0.994629f, 0.994629f, 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.001575f, 0.005211f, 0.010040f, 0.016220f, 0.025665f, 0.037415f, 0.054138f, 0.078491f,
+ 0.112915f, 0.160156f, 0.225464f, 0.308594f, 0.405029f, 0.506348f, 0.599121f, 0.678711f, 0.743164f, 0.791016f, 0.829590f, 0.859375f,
+ 0.881836f, 0.899414f, 0.913086f, 0.924805f, 0.934570f, 0.942383f, 0.948730f, 0.955078f, 0.958984f, 0.963379f, 0.966797f, 0.970215f,
+ 0.972168f, 0.974609f, 0.977051f, 0.979004f, 0.980957f, 0.981934f, 0.983398f, 0.984863f, 0.986328f, 0.987305f, 0.988281f, 0.989258f,
+ 0.990234f, 0.991211f, 0.991699f, 0.992188f, 0.993164f, 0.993652f, 0.994629f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996094f,
+ 0.996582f, 0.997559f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.000985f, 0.004086f, 0.007362f, 0.011887f,
+ 0.018127f, 0.026199f, 0.036804f, 0.052002f, 0.072754f, 0.101318f, 0.140747f, 0.195190f, 0.266113f, 0.352539f, 0.448730f, 0.543945f,
+ 0.630371f, 0.702637f, 0.759277f, 0.803711f, 0.839355f, 0.865234f, 0.886719f, 0.903320f, 0.916504f, 0.927734f, 0.936523f, 0.944336f,
+ 0.950195f, 0.955566f, 0.959961f, 0.964355f, 0.967773f, 0.970215f, 0.973145f, 0.975586f, 0.978027f, 0.979004f, 0.980957f, 0.982910f,
+ 0.984375f, 0.985352f, 0.987305f, 0.987305f, 0.988770f, 0.990234f, 0.990234f, 0.991699f, 0.991699f, 0.993164f, 0.993164f, 0.993652f,
+ 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.998535f, 0.999023f,
+ 0.000829f, 0.002878f, 0.005596f, 0.009109f, 0.013359f, 0.019089f, 0.026901f, 0.036774f, 0.049347f, 0.067200f, 0.091736f, 0.125854f,
+ 0.171631f, 0.232544f, 0.308594f, 0.397461f, 0.491455f, 0.581055f, 0.659668f, 0.724609f, 0.775879f, 0.817383f, 0.848633f, 0.873047f,
+ 0.892090f, 0.907715f, 0.920410f, 0.930664f, 0.939453f, 0.946289f, 0.951660f, 0.957520f, 0.960938f, 0.965820f, 0.968750f, 0.972168f,
+ 0.974609f, 0.976562f, 0.978516f, 0.980469f, 0.981934f, 0.983887f, 0.984863f, 0.986328f, 0.986816f, 0.988770f, 0.989746f, 0.990234f,
+ 0.991211f, 0.991699f, 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996582f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000836f, 0.002403f, 0.004837f, 0.006950f, 0.010269f, 0.014679f, 0.019699f, 0.026291f,
+ 0.035431f, 0.046875f, 0.062744f, 0.084045f, 0.113403f, 0.152588f, 0.204712f, 0.271729f, 0.353271f, 0.443115f, 0.532715f, 0.617188f,
+ 0.688477f, 0.748047f, 0.793945f, 0.829102f, 0.857422f, 0.880371f, 0.898438f, 0.912598f, 0.924316f, 0.934082f, 0.941406f, 0.948242f,
+ 0.954590f, 0.959473f, 0.963379f, 0.967285f, 0.970215f, 0.973145f, 0.975586f, 0.977539f, 0.979980f, 0.981445f, 0.982910f, 0.984375f,
+ 0.985840f, 0.987305f, 0.988281f, 0.988770f, 0.990234f, 0.990723f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.995117f,
+ 0.995605f, 0.996094f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.000698f, 0.002052f, 0.003618f, 0.005703f,
+ 0.008430f, 0.011230f, 0.015083f, 0.019821f, 0.026474f, 0.034393f, 0.044922f, 0.059204f, 0.077698f, 0.102661f, 0.136963f, 0.182373f,
+ 0.241089f, 0.314941f, 0.398926f, 0.489014f, 0.575195f, 0.652344f, 0.717285f, 0.769043f, 0.810059f, 0.842773f, 0.869141f, 0.888672f,
+ 0.904785f, 0.917969f, 0.928711f, 0.936523f, 0.945312f, 0.951660f, 0.957031f, 0.961426f, 0.964844f, 0.968750f, 0.971680f, 0.974121f,
+ 0.976562f, 0.979004f, 0.980469f, 0.982422f, 0.983887f, 0.985352f, 0.986816f, 0.987793f, 0.988770f, 0.990234f, 0.990723f, 0.991699f,
+ 0.992676f, 0.993164f, 0.994141f, 0.994141f, 0.994629f, 0.995605f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f,
+ 0.000244f, 0.001565f, 0.002975f, 0.004433f, 0.006596f, 0.008957f, 0.012215f, 0.015533f, 0.020294f, 0.026062f, 0.033722f, 0.042816f,
+ 0.055237f, 0.071960f, 0.094543f, 0.124023f, 0.164185f, 0.216309f, 0.281738f, 0.360352f, 0.446533f, 0.534180f, 0.615234f, 0.686523f,
+ 0.743652f, 0.790527f, 0.825684f, 0.855957f, 0.878418f, 0.895996f, 0.911133f, 0.923340f, 0.933105f, 0.941406f, 0.948242f, 0.953613f,
+ 0.959473f, 0.963379f, 0.966797f, 0.970703f, 0.973145f, 0.976074f, 0.978516f, 0.980469f, 0.982422f, 0.983398f, 0.984863f, 0.986328f,
+ 0.987305f, 0.989258f, 0.989746f, 0.990723f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994141f, 0.995117f, 0.998047f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998047f, 0.000365f, 0.001394f, 0.002546f, 0.004055f, 0.005394f, 0.007465f, 0.009674f, 0.012070f,
+ 0.015556f, 0.019913f, 0.025696f, 0.032623f, 0.041046f, 0.052643f, 0.067383f, 0.087463f, 0.113708f, 0.148315f, 0.194946f, 0.254395f,
+ 0.326416f, 0.408691f, 0.495117f, 0.579102f, 0.654297f, 0.716797f, 0.768066f, 0.809570f, 0.843262f, 0.868652f, 0.888184f, 0.904785f,
+ 0.918457f, 0.929199f, 0.937500f, 0.945801f, 0.951660f, 0.957520f, 0.961914f, 0.965820f, 0.969238f, 0.972656f, 0.975098f, 0.978027f,
+ 0.979492f, 0.981934f, 0.983398f, 0.984863f, 0.986328f, 0.987793f, 0.989258f, 0.989746f, 0.991211f, 0.991211f, 0.992188f, 0.993164f,
+ 0.993652f, 0.994629f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.000596f, 0.001077f, 0.001882f, 0.003033f,
+ 0.004559f, 0.006241f, 0.007805f, 0.010002f, 0.012840f, 0.015900f, 0.019974f, 0.025131f, 0.031250f, 0.039337f, 0.049988f, 0.063843f,
+ 0.080933f, 0.105164f, 0.135986f, 0.176880f, 0.230103f, 0.296631f, 0.374268f, 0.459961f, 0.544434f, 0.623535f, 0.691895f, 0.748535f,
+ 0.792969f, 0.829102f, 0.857422f, 0.880371f, 0.897949f, 0.913086f, 0.924805f, 0.934570f, 0.942383f, 0.949219f, 0.955566f, 0.960938f,
+ 0.964844f, 0.968750f, 0.971191f, 0.974121f, 0.977051f, 0.979004f, 0.980957f, 0.982910f, 0.984863f, 0.985840f, 0.987305f, 0.989258f,
+ 0.989746f, 0.991211f, 0.991211f, 0.992676f, 0.993164f, 0.993652f, 0.997559f, 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.998047f,
+ 0.000243f, 0.001173f, 0.001889f, 0.002661f, 0.003933f, 0.005131f, 0.006496f, 0.008324f, 0.010574f, 0.013115f, 0.015839f, 0.019913f,
+ 0.024445f, 0.030609f, 0.037781f, 0.047333f, 0.059906f, 0.075928f, 0.097229f, 0.124939f, 0.161743f, 0.209595f, 0.271240f, 0.343994f,
+ 0.426758f, 0.511719f, 0.592773f, 0.666504f, 0.727051f, 0.776855f, 0.815918f, 0.847656f, 0.871582f, 0.892090f, 0.907715f, 0.920898f,
+ 0.931152f, 0.940918f, 0.947754f, 0.953613f, 0.958496f, 0.963867f, 0.967773f, 0.970703f, 0.974121f, 0.976074f, 0.979004f, 0.980469f,
+ 0.982910f, 0.984375f, 0.985840f, 0.987305f, 0.988770f, 0.990234f, 0.990234f, 0.992188f, 0.992188f, 0.993164f, 0.997070f, 0.997559f,
+ 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.000351f, 0.000842f, 0.001560f, 0.002363f, 0.003258f, 0.004131f, 0.005272f, 0.007179f,
+ 0.008682f, 0.010643f, 0.013016f, 0.016037f, 0.019516f, 0.024078f, 0.029602f, 0.036591f, 0.045044f, 0.056641f, 0.071350f, 0.090576f,
+ 0.116211f, 0.149414f, 0.193237f, 0.248779f, 0.317871f, 0.396973f, 0.481201f, 0.564453f, 0.640137f, 0.705566f, 0.759766f, 0.802734f,
+ 0.836914f, 0.863281f, 0.885742f, 0.902832f, 0.916992f, 0.927734f, 0.937012f, 0.945801f, 0.952637f, 0.958008f, 0.961914f, 0.966309f,
+ 0.970703f, 0.974121f, 0.976074f, 0.978516f, 0.980957f, 0.982910f, 0.984863f, 0.985840f, 0.987305f, 0.988281f, 0.989746f, 0.990723f,
+ 0.991211f, 0.992676f, 0.997070f, 0.997559f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.000000f, 0.000886f, 0.001405f, 0.001915f,
+ 0.002651f, 0.003870f, 0.004845f, 0.006035f, 0.006912f, 0.008812f, 0.010887f, 0.013229f, 0.016022f, 0.019196f, 0.023590f, 0.028992f,
+ 0.035248f, 0.043304f, 0.053711f, 0.066956f, 0.085083f, 0.107727f, 0.138428f, 0.178589f, 0.229980f, 0.293945f, 0.370117f, 0.453369f,
+ 0.537109f, 0.616699f, 0.685059f, 0.743164f, 0.790039f, 0.826660f, 0.856445f, 0.878906f, 0.897949f, 0.913574f, 0.925293f, 0.935547f,
+ 0.943848f, 0.951172f, 0.957031f, 0.961914f, 0.966797f, 0.970215f, 0.973145f, 0.976562f, 0.979004f, 0.980469f, 0.982910f, 0.984375f,
+ 0.985840f, 0.987305f, 0.988770f, 0.989746f, 0.991211f, 0.992188f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997070f,
+ 0.000104f, 0.000719f, 0.001065f, 0.001970f, 0.002544f, 0.003149f, 0.004230f, 0.005138f, 0.006119f, 0.007580f, 0.009201f, 0.010902f,
+ 0.013260f, 0.015526f, 0.019272f, 0.022858f, 0.027512f, 0.033569f, 0.041199f, 0.050873f, 0.063782f, 0.079895f, 0.101135f, 0.128906f,
+ 0.165771f, 0.213745f, 0.273193f, 0.345703f, 0.427002f, 0.511719f, 0.592773f, 0.666016f, 0.727051f, 0.776367f, 0.817871f, 0.848633f,
+ 0.875000f, 0.894531f, 0.909668f, 0.922852f, 0.934082f, 0.942383f, 0.949707f, 0.956055f, 0.961914f, 0.966309f, 0.970215f, 0.973145f,
+ 0.976562f, 0.978516f, 0.980957f, 0.982910f, 0.984375f, 0.986328f, 0.987305f, 0.988281f, 0.989746f, 0.991211f, 0.996582f, 0.997070f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.000240f, 0.000686f, 0.001052f, 0.001375f, 0.002308f, 0.002735f, 0.003510f, 0.004269f,
+ 0.005173f, 0.006649f, 0.007442f, 0.009109f, 0.011246f, 0.012886f, 0.015732f, 0.018829f, 0.022354f, 0.026672f, 0.032867f, 0.039764f,
+ 0.048492f, 0.060455f, 0.075806f, 0.095276f, 0.121033f, 0.155273f, 0.199097f, 0.255859f, 0.324463f, 0.404053f, 0.488525f, 0.571289f,
+ 0.646484f, 0.711426f, 0.765625f, 0.808105f, 0.841797f, 0.869141f, 0.890137f, 0.907227f, 0.920898f, 0.931641f, 0.940918f, 0.948730f,
+ 0.955078f, 0.960449f, 0.965820f, 0.969727f, 0.972656f, 0.976562f, 0.978516f, 0.980957f, 0.982910f, 0.984863f, 0.986328f, 0.987793f,
+ 0.989746f, 0.990723f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.000244f, 0.000597f, 0.000939f, 0.001369f,
+ 0.001999f, 0.002329f, 0.003105f, 0.003786f, 0.004395f, 0.005413f, 0.006474f, 0.007793f, 0.009254f, 0.010971f, 0.012970f, 0.015526f,
+ 0.018112f, 0.022049f, 0.026581f, 0.031586f, 0.038666f, 0.046967f, 0.057617f, 0.071777f, 0.089783f, 0.113953f, 0.145264f, 0.186646f,
+ 0.239990f, 0.305908f, 0.383301f, 0.467285f, 0.551270f, 0.629883f, 0.697266f, 0.754883f, 0.799805f, 0.835938f, 0.864258f, 0.886719f,
+ 0.905273f, 0.918945f, 0.931152f, 0.940918f, 0.948242f, 0.955078f, 0.961426f, 0.965332f, 0.969727f, 0.973633f, 0.976074f, 0.979004f,
+ 0.980957f, 0.983398f, 0.984863f, 0.987305f, 0.988281f, 0.989258f, 0.996094f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.996582f,
+ 0.000000f, 0.000475f, 0.000891f, 0.001390f, 0.001730f, 0.002060f, 0.002501f, 0.003109f, 0.003836f, 0.004837f, 0.005852f, 0.006859f,
+ 0.007740f, 0.009216f, 0.010918f, 0.012863f, 0.014915f, 0.017731f, 0.021317f, 0.025482f, 0.030930f, 0.037262f, 0.044891f, 0.055115f,
+ 0.068298f, 0.085510f, 0.107910f, 0.137207f, 0.176025f, 0.226929f, 0.289551f, 0.364746f, 0.447998f, 0.532715f, 0.613770f, 0.685547f,
+ 0.744629f, 0.791992f, 0.830078f, 0.860352f, 0.884277f, 0.903320f, 0.917969f, 0.930176f, 0.939941f, 0.947754f, 0.954590f, 0.961426f,
+ 0.966309f, 0.970215f, 0.973145f, 0.976562f, 0.979492f, 0.981445f, 0.983398f, 0.985352f, 0.987793f, 0.988281f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996582f, 0.996094f, 0.996094f, 0.000102f, 0.000243f, 0.000844f, 0.001124f, 0.001554f, 0.002077f, 0.002098f, 0.002682f,
+ 0.003357f, 0.004280f, 0.005035f, 0.005764f, 0.006805f, 0.007633f, 0.009354f, 0.010872f, 0.012665f, 0.015099f, 0.017258f, 0.020599f,
+ 0.024887f, 0.029495f, 0.035522f, 0.042999f, 0.053070f, 0.065125f, 0.081299f, 0.102661f, 0.130371f, 0.166992f, 0.215088f, 0.275635f,
+ 0.348877f, 0.431641f, 0.517578f, 0.600098f, 0.672852f, 0.735352f, 0.785645f, 0.826172f, 0.856934f, 0.881836f, 0.900879f, 0.916992f,
+ 0.930176f, 0.940430f, 0.947754f, 0.955078f, 0.960938f, 0.966309f, 0.969238f, 0.973633f, 0.977051f, 0.979492f, 0.981934f, 0.983887f,
+ 0.986328f, 0.987793f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.000241f, 0.000242f, 0.000823f, 0.000956f,
+ 0.001225f, 0.001549f, 0.002031f, 0.002613f, 0.003124f, 0.003574f, 0.004467f, 0.004955f, 0.005672f, 0.006752f, 0.007603f, 0.009186f,
+ 0.010704f, 0.012741f, 0.014366f, 0.017487f, 0.020142f, 0.024002f, 0.028915f, 0.034943f, 0.041656f, 0.050964f, 0.062622f, 0.077881f,
+ 0.097961f, 0.124207f, 0.158936f, 0.204590f, 0.263184f, 0.334961f, 0.416748f, 0.502930f, 0.587891f, 0.664062f, 0.728516f, 0.780762f,
+ 0.822266f, 0.854492f, 0.879395f, 0.900879f, 0.916504f, 0.928711f, 0.940430f, 0.948730f, 0.955566f, 0.961914f, 0.967285f, 0.970215f,
+ 0.974121f, 0.977539f, 0.979980f, 0.982422f, 0.984863f, 0.986816f, 0.994629f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.995605f,
+ 0.000000f, 0.000473f, 0.000607f, 0.000921f, 0.000957f, 0.001448f, 0.001884f, 0.002270f, 0.002703f, 0.002998f, 0.003862f, 0.004307f,
+ 0.005074f, 0.005665f, 0.006737f, 0.007851f, 0.009216f, 0.010735f, 0.012459f, 0.014572f, 0.016998f, 0.019821f, 0.023605f, 0.027969f,
+ 0.033783f, 0.040192f, 0.049286f, 0.060303f, 0.074829f, 0.093750f, 0.118774f, 0.152222f, 0.195801f, 0.252441f, 0.322754f, 0.404053f,
+ 0.491943f, 0.577637f, 0.655273f, 0.722168f, 0.776367f, 0.820312f, 0.854004f, 0.878906f, 0.900879f, 0.916992f, 0.929688f, 0.940430f,
+ 0.949707f, 0.956055f, 0.962402f, 0.967285f, 0.971191f, 0.975586f, 0.978516f, 0.980957f, 0.983398f, 0.985352f, 0.994141f, 0.995117f,
+ 0.995117f, 0.995605f, 0.995117f, 0.995605f, 0.000000f, 0.000444f, 0.000605f, 0.000649f, 0.000926f, 0.001096f, 0.001624f, 0.001669f,
+ 0.002373f, 0.002716f, 0.003231f, 0.003769f, 0.004395f, 0.005005f, 0.005878f, 0.006710f, 0.007793f, 0.008957f, 0.010712f, 0.012230f,
+ 0.014244f, 0.016693f, 0.019531f, 0.022827f, 0.027100f, 0.032318f, 0.038971f, 0.047302f, 0.058105f, 0.072021f, 0.089966f, 0.114319f,
+ 0.146362f, 0.188965f, 0.244019f, 0.312988f, 0.394287f, 0.482178f, 0.569824f, 0.650391f, 0.718262f, 0.774414f, 0.819336f, 0.853027f,
+ 0.880371f, 0.900879f, 0.917969f, 0.930664f, 0.940918f, 0.950684f, 0.957031f, 0.962891f, 0.968262f, 0.972656f, 0.976562f, 0.979004f,
+ 0.981934f, 0.984375f, 0.994141f, 0.994629f, 0.994629f, 0.995117f, 0.994629f, 0.995117f, 0.000000f, 0.000336f, 0.000601f, 0.000712f,
+ 0.000810f, 0.001174f, 0.001286f, 0.001618f, 0.002037f, 0.002592f, 0.002920f, 0.003223f, 0.003847f, 0.004463f, 0.005119f, 0.006020f,
+ 0.006783f, 0.007957f, 0.008888f, 0.010590f, 0.012230f, 0.013885f, 0.016220f, 0.019318f, 0.022278f, 0.026474f, 0.031403f, 0.037781f,
+ 0.046021f, 0.055969f, 0.069397f, 0.086975f, 0.110413f, 0.140991f, 0.182739f, 0.236694f, 0.304932f, 0.385986f, 0.475586f, 0.563965f,
+ 0.646484f, 0.716797f, 0.772461f, 0.818359f, 0.853027f, 0.880859f, 0.901855f, 0.918945f, 0.932129f, 0.942383f, 0.951172f, 0.958496f,
+ 0.964355f, 0.969238f, 0.973633f, 0.977051f, 0.979980f, 0.982910f, 0.993652f, 0.994141f, 0.994629f, 0.994141f, 0.994141f, 0.994629f,
+ 0.000000f, 0.000244f, 0.000418f, 0.000597f, 0.000600f, 0.001085f, 0.001236f, 0.001535f, 0.001970f, 0.002096f, 0.002354f, 0.002834f,
+ 0.003323f, 0.003822f, 0.004463f, 0.005146f, 0.005798f, 0.006859f, 0.007587f, 0.008827f, 0.009956f, 0.011833f, 0.013725f, 0.015945f,
+ 0.018585f, 0.021988f, 0.025665f, 0.030807f, 0.036774f, 0.044373f, 0.054108f, 0.067383f, 0.084229f, 0.106812f, 0.137207f, 0.177734f,
+ 0.230835f, 0.299072f, 0.380127f, 0.470215f, 0.560547f, 0.644531f, 0.715820f, 0.774414f, 0.820312f, 0.854980f, 0.882324f, 0.903809f,
+ 0.921387f, 0.933594f, 0.944824f, 0.952637f, 0.960449f, 0.965820f, 0.971191f, 0.974609f, 0.978027f, 0.981934f, 0.993164f, 0.994629f,
+ 0.994141f, 0.994141f, 0.994141f, 0.994141f, 0.000000f, 0.000244f, 0.000411f, 0.000589f, 0.000820f, 0.000729f, 0.001086f, 0.001301f,
+ 0.001677f, 0.001935f, 0.002312f, 0.002678f, 0.002846f, 0.003590f, 0.003914f, 0.004578f, 0.005020f, 0.005753f, 0.006706f, 0.007710f,
+ 0.008911f, 0.010155f, 0.011528f, 0.013504f, 0.015747f, 0.018036f, 0.021408f, 0.024994f, 0.029816f, 0.035858f, 0.043152f, 0.053009f,
+ 0.065491f, 0.082031f, 0.104065f, 0.133789f, 0.174072f, 0.226929f, 0.294434f, 0.376465f, 0.467773f, 0.560059f, 0.644531f, 0.717285f,
+ 0.777344f, 0.823242f, 0.857910f, 0.885742f, 0.906738f, 0.922852f, 0.936523f, 0.947266f, 0.955078f, 0.961426f, 0.967285f, 0.972656f,
+ 0.976562f, 0.979980f, 0.992676f, 0.993164f, 0.993652f, 0.993652f, 0.993652f, 0.993652f, 0.000000f, 0.000243f, 0.000243f, 0.000442f,
+ 0.000695f, 0.000759f, 0.000837f, 0.001089f, 0.001625f, 0.001702f, 0.002045f, 0.002176f, 0.002756f, 0.003063f, 0.003687f, 0.003893f,
+ 0.004456f, 0.005337f, 0.006062f, 0.006523f, 0.007572f, 0.008430f, 0.009880f, 0.011612f, 0.013237f, 0.015114f, 0.017487f, 0.020584f,
+ 0.024445f, 0.028931f, 0.034729f, 0.042023f, 0.051788f, 0.063843f, 0.079956f, 0.102295f, 0.131592f, 0.171021f, 0.223877f, 0.292236f,
+ 0.375000f, 0.468018f, 0.562012f, 0.648438f, 0.721191f, 0.781250f, 0.826660f, 0.862305f, 0.888672f, 0.909668f, 0.926270f, 0.938965f,
+ 0.949707f, 0.957520f, 0.964355f, 0.969727f, 0.974121f, 0.978027f, 0.992676f, 0.993164f, 0.993164f, 0.992676f, 0.993164f, 0.993164f,
+ 0.000000f, 0.000242f, 0.000242f, 0.000242f, 0.000564f, 0.000692f, 0.000826f, 0.001094f, 0.001280f, 0.001457f, 0.001673f, 0.002232f,
+ 0.002411f, 0.002789f, 0.003174f, 0.003649f, 0.003859f, 0.004349f, 0.004990f, 0.005898f, 0.006622f, 0.007496f, 0.008209f, 0.009583f,
+ 0.011284f, 0.013062f, 0.014763f, 0.017120f, 0.020020f, 0.023804f, 0.028412f, 0.033905f, 0.041016f, 0.050140f, 0.062469f, 0.078552f,
+ 0.100159f, 0.129272f, 0.169067f, 0.222290f, 0.291504f, 0.376465f, 0.470703f, 0.566406f, 0.653320f, 0.728027f, 0.786621f, 0.832031f,
+ 0.866699f, 0.893555f, 0.914062f, 0.929688f, 0.942383f, 0.952148f, 0.959961f, 0.966797f, 0.972168f, 0.976074f, 0.991211f, 0.992188f,
+ 0.992676f, 0.992188f, 0.992676f, 0.992676f, 0.000241f, 0.000241f, 0.000240f, 0.000242f, 0.000486f, 0.000637f, 0.000916f, 0.000933f,
+ 0.001003f, 0.001284f, 0.001584f, 0.001925f, 0.002134f, 0.002502f, 0.002731f, 0.003134f, 0.003435f, 0.004036f, 0.004379f, 0.005077f,
+ 0.005688f, 0.006557f, 0.007347f, 0.007942f, 0.009506f, 0.010712f, 0.012527f, 0.014603f, 0.016693f, 0.019592f, 0.023285f, 0.027512f,
+ 0.033173f, 0.040283f, 0.049347f, 0.061432f, 0.077271f, 0.098938f, 0.128052f, 0.168091f, 0.222168f, 0.292725f, 0.379150f, 0.476807f,
+ 0.573730f, 0.662598f, 0.735840f, 0.794434f, 0.839844f, 0.873535f, 0.898926f, 0.918945f, 0.934082f, 0.945312f, 0.955566f, 0.962402f,
+ 0.969238f, 0.974609f, 0.990723f, 0.991699f, 0.992188f, 0.992188f, 0.992188f, 0.992188f, 0.000000f, 0.000238f, 0.000240f, 0.000362f,
+ 0.000362f, 0.000521f, 0.000631f, 0.000909f, 0.000937f, 0.001249f, 0.001373f, 0.001693f, 0.001746f, 0.002184f, 0.002436f, 0.002680f,
+ 0.003094f, 0.003576f, 0.003828f, 0.004463f, 0.004990f, 0.005589f, 0.006439f, 0.006943f, 0.008217f, 0.009384f, 0.010719f, 0.012184f,
+ 0.014130f, 0.016373f, 0.019241f, 0.022675f, 0.027161f, 0.032379f, 0.039307f, 0.048645f, 0.060455f, 0.076416f, 0.097778f, 0.127441f,
+ 0.168213f, 0.223633f, 0.296387f, 0.385986f, 0.485107f, 0.583984f, 0.673340f, 0.746582f, 0.804199f, 0.848633f, 0.880371f, 0.905273f,
+ 0.923828f, 0.938477f, 0.949707f, 0.958984f, 0.965820f, 0.972656f, 0.990234f, 0.991211f, 0.991211f, 0.991211f, 0.991211f, 0.991211f,
+ 0.000000f, 0.000234f, 0.000238f, 0.000236f, 0.000360f, 0.000482f, 0.000614f, 0.000786f, 0.000900f, 0.001056f, 0.001336f, 0.001466f,
+ 0.001671f, 0.001907f, 0.002333f, 0.002546f, 0.002871f, 0.003067f, 0.003500f, 0.003813f, 0.004425f, 0.004574f, 0.005459f, 0.006092f,
+ 0.006660f, 0.007660f, 0.008987f, 0.010071f, 0.011841f, 0.013847f, 0.016022f, 0.018829f, 0.022339f, 0.026779f, 0.031677f, 0.038910f,
+ 0.047913f, 0.059601f, 0.075684f, 0.097290f, 0.127319f, 0.169189f, 0.226807f, 0.302490f, 0.394775f, 0.497314f, 0.598633f, 0.686523f,
+ 0.759766f, 0.814941f, 0.857422f, 0.888672f, 0.912109f, 0.930176f, 0.943359f, 0.954102f, 0.962402f, 0.968750f, 0.988770f, 0.990234f,
+ 0.990234f, 0.990234f, 0.991211f, 0.990723f, 0.000000f, 0.000036f, 0.000166f, 0.000357f, 0.000356f, 0.000478f, 0.000566f, 0.000638f,
+ 0.000893f, 0.001146f, 0.001242f, 0.001330f, 0.001502f, 0.001773f, 0.001918f, 0.002024f, 0.002501f, 0.002604f, 0.003067f, 0.003334f,
+ 0.003708f, 0.004044f, 0.004646f, 0.005268f, 0.006241f, 0.006931f, 0.007774f, 0.008911f, 0.010277f, 0.011475f, 0.013542f, 0.015732f,
+ 0.018417f, 0.022049f, 0.026154f, 0.031189f, 0.038269f, 0.047119f, 0.059265f, 0.075256f, 0.097534f, 0.128906f, 0.172119f, 0.231934f,
+ 0.311035f, 0.407715f, 0.513184f, 0.615723f, 0.703613f, 0.773926f, 0.827637f, 0.867188f, 0.897461f, 0.919434f, 0.936035f, 0.948730f,
+ 0.958984f, 0.966309f, 0.988770f, 0.989746f, 0.989746f, 0.990234f, 0.989746f, 0.989746f, 0.000000f, 0.000028f, 0.000093f, 0.000334f,
+ 0.000465f, 0.000472f, 0.000373f, 0.000685f, 0.000695f, 0.001027f, 0.001128f, 0.001155f, 0.001419f, 0.001435f, 0.001760f, 0.001850f,
+ 0.002241f, 0.002373f, 0.002604f, 0.002821f, 0.003334f, 0.003666f, 0.004139f, 0.004627f, 0.005207f, 0.005886f, 0.006596f, 0.007580f,
+ 0.008705f, 0.009911f, 0.011520f, 0.013237f, 0.015427f, 0.017944f, 0.021423f, 0.025497f, 0.030945f, 0.037537f, 0.046692f, 0.058624f,
+ 0.075317f, 0.098267f, 0.130493f, 0.176025f, 0.239136f, 0.323242f, 0.424561f, 0.533691f, 0.636230f, 0.723145f, 0.790039f, 0.841797f,
+ 0.880371f, 0.906738f, 0.926758f, 0.941406f, 0.953613f, 0.963379f, 0.987793f, 0.988770f, 0.988770f, 0.989258f, 0.989258f, 0.989258f,
+ 0.000000f, 0.000000f, 0.000047f, 0.000321f, 0.000332f, 0.000351f, 0.000470f, 0.000596f, 0.000655f, 0.000727f, 0.001008f, 0.001112f,
+ 0.001350f, 0.001379f, 0.001380f, 0.001751f, 0.002008f, 0.002151f, 0.002327f, 0.002548f, 0.002691f, 0.003056f, 0.003475f, 0.003925f,
+ 0.004749f, 0.005161f, 0.005863f, 0.006538f, 0.007153f, 0.008453f, 0.009789f, 0.010986f, 0.013168f, 0.015121f, 0.017563f, 0.020966f,
+ 0.025009f, 0.030151f, 0.037048f, 0.046570f, 0.058624f, 0.075623f, 0.099243f, 0.133667f, 0.181641f, 0.249756f, 0.338623f, 0.445312f,
+ 0.556641f, 0.659180f, 0.744141f, 0.808594f, 0.855957f, 0.890137f, 0.916992f, 0.934570f, 0.949219f, 0.959473f, 0.986816f, 0.987793f,
+ 0.987793f, 0.987793f, 0.987793f, 0.988281f, 0.000000f, 0.000000f, 0.000000f, 0.000244f, 0.000429f, 0.000440f, 0.000348f, 0.000592f,
+ 0.000606f, 0.000755f, 0.000690f, 0.000935f, 0.001172f, 0.001257f, 0.001368f, 0.001458f, 0.001786f, 0.001809f, 0.002060f, 0.002274f,
+ 0.002478f, 0.002642f, 0.002987f, 0.003435f, 0.003866f, 0.004337f, 0.005066f, 0.005409f, 0.006355f, 0.007111f, 0.008011f, 0.009392f,
+ 0.011032f, 0.012321f, 0.014717f, 0.017319f, 0.020432f, 0.024551f, 0.029953f, 0.036835f, 0.045929f, 0.058716f, 0.076416f, 0.101562f,
+ 0.137695f, 0.189453f, 0.262451f, 0.358154f, 0.470215f, 0.584961f, 0.686523f, 0.767578f, 0.828125f, 0.871582f, 0.903809f, 0.926270f,
+ 0.941895f, 0.956055f, 0.985352f, 0.986328f, 0.986816f, 0.986816f, 0.986816f, 0.986816f, 0.000000f, 0.000000f, 0.000000f, 0.000119f,
+ 0.000237f, 0.000314f, 0.000570f, 0.000575f, 0.000583f, 0.000632f, 0.000651f, 0.000789f, 0.000947f, 0.001097f, 0.001300f, 0.001320f,
+ 0.001384f, 0.001443f, 0.001641f, 0.001869f, 0.002047f, 0.002396f, 0.002634f, 0.003025f, 0.003412f, 0.003757f, 0.004238f, 0.004620f,
+ 0.005463f, 0.006168f, 0.007072f, 0.008080f, 0.009155f, 0.010590f, 0.012306f, 0.014175f, 0.016769f, 0.020081f, 0.023972f, 0.029495f,
+ 0.036560f, 0.045959f, 0.059265f, 0.078125f, 0.104797f, 0.143677f, 0.199951f, 0.279785f, 0.382812f, 0.500977f, 0.616699f, 0.716309f,
+ 0.791992f, 0.847168f, 0.887207f, 0.915527f, 0.936523f, 0.950684f, 0.984375f, 0.985352f, 0.986328f, 0.985840f, 0.986328f, 0.985840f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000205f, 0.000239f, 0.000299f, 0.000537f, 0.000574f, 0.000696f, 0.000583f, 0.000740f,
+ 0.000778f, 0.000867f, 0.001013f, 0.001257f, 0.001325f, 0.001277f, 0.001416f, 0.001718f, 0.001965f, 0.002079f, 0.002356f, 0.002577f,
+ 0.002771f, 0.003305f, 0.003693f, 0.004028f, 0.004593f, 0.005234f, 0.005905f, 0.006802f, 0.007698f, 0.008553f, 0.009995f, 0.011635f,
+ 0.013824f, 0.016174f, 0.019547f, 0.023544f, 0.029114f, 0.036377f, 0.046417f, 0.060211f, 0.080017f, 0.108643f, 0.151611f, 0.213379f,
+ 0.301758f, 0.414062f, 0.537598f, 0.653320f, 0.748047f, 0.817871f, 0.868164f, 0.903320f, 0.928711f, 0.945801f, 0.982910f, 0.983887f,
+ 0.984375f, 0.984375f, 0.984863f, 0.984375f, 0.000000f, 0.000000f, 0.000045f, 0.000105f, 0.000114f, 0.000340f, 0.000371f, 0.000501f,
+ 0.000639f, 0.000554f, 0.000687f, 0.000675f, 0.000711f, 0.000738f, 0.000824f, 0.001092f, 0.001040f, 0.001185f, 0.001212f, 0.001408f,
+ 0.001624f, 0.001813f, 0.001982f, 0.002182f, 0.002634f, 0.002748f, 0.003252f, 0.003540f, 0.004089f, 0.004505f, 0.005001f, 0.005657f,
+ 0.006500f, 0.007195f, 0.008286f, 0.009750f, 0.011208f, 0.013420f, 0.015762f, 0.019226f, 0.023209f, 0.029144f, 0.036591f, 0.047150f,
+ 0.061615f, 0.082947f, 0.114014f, 0.161621f, 0.231323f, 0.329834f, 0.451416f, 0.579590f, 0.692871f, 0.780273f, 0.844238f, 0.888184f,
+ 0.917969f, 0.939453f, 0.981445f, 0.982422f, 0.982910f, 0.982910f, 0.982910f, 0.982910f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000208f, 0.000311f, 0.000238f, 0.000337f, 0.000524f, 0.000617f, 0.000533f, 0.000675f, 0.000665f, 0.000776f, 0.000840f, 0.000819f,
+ 0.000902f, 0.001169f, 0.001130f, 0.001178f, 0.001382f, 0.001571f, 0.001941f, 0.001932f, 0.002138f, 0.002306f, 0.002586f, 0.002937f,
+ 0.003468f, 0.003740f, 0.004292f, 0.004704f, 0.005444f, 0.006081f, 0.007019f, 0.008255f, 0.009521f, 0.010796f, 0.012840f, 0.015503f,
+ 0.018784f, 0.023178f, 0.029129f, 0.036774f, 0.047699f, 0.063416f, 0.086548f, 0.121399f, 0.175293f, 0.254883f, 0.365234f, 0.496582f,
+ 0.626953f, 0.733398f, 0.813477f, 0.869629f, 0.906738f, 0.933105f, 0.979980f, 0.980957f, 0.981445f, 0.981445f, 0.980957f, 0.981445f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000208f, 0.000312f, 0.000236f, 0.000343f, 0.000475f, 0.000496f, 0.000528f,
+ 0.000659f, 0.000582f, 0.000685f, 0.000710f, 0.000761f, 0.000784f, 0.000941f, 0.001013f, 0.001117f, 0.001339f, 0.001500f, 0.001623f,
+ 0.001769f, 0.002039f, 0.002298f, 0.002565f, 0.002802f, 0.003119f, 0.003471f, 0.003857f, 0.004658f, 0.005177f, 0.005836f, 0.006752f,
+ 0.007324f, 0.008911f, 0.010422f, 0.012527f, 0.015373f, 0.018585f, 0.022964f, 0.029037f, 0.037231f, 0.049072f, 0.066345f, 0.091492f,
+ 0.131470f, 0.193359f, 0.285645f, 0.409912f, 0.548828f, 0.676758f, 0.776367f, 0.845703f, 0.893066f, 0.924805f, 0.978027f, 0.979492f,
+ 0.979492f, 0.979004f, 0.979492f, 0.979492f, 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000166f, 0.000228f, 0.000227f,
+ 0.000369f, 0.000337f, 0.000368f, 0.000452f, 0.000500f, 0.000547f, 0.000543f, 0.000575f, 0.000623f, 0.000723f, 0.000783f, 0.000874f,
+ 0.001141f, 0.001226f, 0.001279f, 0.001336f, 0.001499f, 0.001655f, 0.001922f, 0.002090f, 0.002453f, 0.002298f, 0.003139f, 0.003181f,
+ 0.003674f, 0.004166f, 0.004814f, 0.005447f, 0.006348f, 0.007179f, 0.008736f, 0.010406f, 0.012321f, 0.014984f, 0.018219f, 0.022934f,
+ 0.028824f, 0.037598f, 0.050476f, 0.069397f, 0.098694f, 0.144775f, 0.218018f, 0.325439f, 0.464111f, 0.607910f, 0.729492f, 0.817383f,
+ 0.876953f, 0.915527f, 0.976562f, 0.977539f, 0.977539f, 0.977051f, 0.977051f, 0.977539f, 0.000000f, 0.000000f, 0.000000f, 0.000122f,
+ 0.000122f, 0.000122f, 0.000154f, 0.000200f, 0.000267f, 0.000316f, 0.000324f, 0.000449f, 0.000319f, 0.000379f, 0.000515f, 0.000519f,
+ 0.000558f, 0.000628f, 0.000645f, 0.000690f, 0.000777f, 0.000940f, 0.001096f, 0.001204f, 0.001278f, 0.001485f, 0.001670f, 0.001929f,
+ 0.001961f, 0.002016f, 0.002367f, 0.002785f, 0.003025f, 0.003248f, 0.003805f, 0.004539f, 0.004845f, 0.005733f, 0.006851f, 0.008278f,
+ 0.010017f, 0.011841f, 0.014542f, 0.017807f, 0.022705f, 0.029190f, 0.038544f, 0.052612f, 0.073853f, 0.108093f, 0.162842f, 0.250977f,
+ 0.377930f, 0.529785f, 0.672363f, 0.782715f, 0.855957f, 0.904297f, 0.973145f, 0.974121f, 0.974609f, 0.975586f, 0.974609f, 0.975098f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000158f, 0.000121f, 0.000190f, 0.000238f, 0.000397f, 0.000354f,
+ 0.000364f, 0.000365f, 0.000440f, 0.000474f, 0.000509f, 0.000612f, 0.000611f, 0.000648f, 0.000804f, 0.000755f, 0.000943f, 0.001050f,
+ 0.001221f, 0.001340f, 0.001338f, 0.001443f, 0.001635f, 0.001822f, 0.002083f, 0.002226f, 0.002480f, 0.002682f, 0.003185f, 0.003609f,
+ 0.003948f, 0.005074f, 0.005558f, 0.006741f, 0.007904f, 0.009384f, 0.011360f, 0.014000f, 0.017883f, 0.022675f, 0.029648f, 0.039917f,
+ 0.055695f, 0.080261f, 0.120728f, 0.188354f, 0.296143f, 0.443848f, 0.603027f, 0.737793f, 0.831055f, 0.891113f, 0.970703f, 0.971680f,
+ 0.972168f, 0.972656f, 0.971680f, 0.972168f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000122f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000251f, 0.000260f, 0.000278f, 0.000315f, 0.000334f, 0.000235f, 0.000357f, 0.000442f, 0.000513f, 0.000504f, 0.000598f,
+ 0.000556f, 0.000771f, 0.000831f, 0.000886f, 0.000977f, 0.001145f, 0.001105f, 0.001244f, 0.001281f, 0.001431f, 0.001544f, 0.001850f,
+ 0.001986f, 0.002131f, 0.002537f, 0.002737f, 0.003252f, 0.003826f, 0.004555f, 0.005184f, 0.006199f, 0.007195f, 0.009041f, 0.011337f,
+ 0.013878f, 0.017395f, 0.022552f, 0.030502f, 0.041962f, 0.059875f, 0.089111f, 0.139404f, 0.224609f, 0.357910f, 0.524902f, 0.684082f,
+ 0.800781f, 0.875977f, 0.967773f, 0.968750f, 0.968262f, 0.968750f, 0.969238f, 0.969238f, 0.000000f, 0.000000f, 0.000122f, 0.000122f,
+ 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000095f, 0.000081f, 0.000217f, 0.000149f, 0.000204f, 0.000212f, 0.000338f,
+ 0.000345f, 0.000348f, 0.000456f, 0.000463f, 0.000495f, 0.000570f, 0.000583f, 0.000748f, 0.000799f, 0.000731f, 0.000965f, 0.001041f,
+ 0.001071f, 0.001210f, 0.001318f, 0.001238f, 0.001410f, 0.001631f, 0.001932f, 0.002327f, 0.002577f, 0.003057f, 0.003452f, 0.003956f,
+ 0.004639f, 0.005714f, 0.006817f, 0.008446f, 0.010605f, 0.013443f, 0.017319f, 0.022964f, 0.031021f, 0.044281f, 0.065857f, 0.102112f,
+ 0.166504f, 0.277344f, 0.439941f, 0.617188f, 0.762207f, 0.856445f, 0.963379f, 0.964355f, 0.965332f, 0.964844f, 0.965332f, 0.965332f,
+ 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000107f, 0.000091f, 0.000161f,
+ 0.000119f, 0.000184f, 0.000266f, 0.000284f, 0.000314f, 0.000319f, 0.000334f, 0.000344f, 0.000565f, 0.000455f, 0.000488f, 0.000667f,
+ 0.000710f, 0.000713f, 0.000787f, 0.000755f, 0.000849f, 0.000972f, 0.001097f, 0.001286f, 0.001427f, 0.001556f, 0.001667f, 0.001687f,
+ 0.002155f, 0.002369f, 0.002674f, 0.003086f, 0.003710f, 0.004536f, 0.005585f, 0.006783f, 0.007957f, 0.010262f, 0.013115f, 0.017212f,
+ 0.023102f, 0.032715f, 0.047943f, 0.074158f, 0.121155f, 0.207520f, 0.353027f, 0.541504f, 0.715332f, 0.834473f, 0.959473f, 0.960449f,
+ 0.960938f, 0.960938f, 0.960938f, 0.961426f, 0.000000f, 0.000000f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000121f,
+ 0.000120f, 0.000120f, 0.000103f, 0.000089f, 0.000077f, 0.000080f, 0.000121f, 0.000218f, 0.000209f, 0.000245f, 0.000303f, 0.000316f,
+ 0.000388f, 0.000341f, 0.000549f, 0.000594f, 0.000604f, 0.000679f, 0.000625f, 0.000628f, 0.000795f, 0.000883f, 0.000857f, 0.000991f,
+ 0.001166f, 0.000955f, 0.001194f, 0.001347f, 0.001548f, 0.001804f, 0.002048f, 0.002388f, 0.002911f, 0.003130f, 0.003933f, 0.004845f,
+ 0.006031f, 0.007385f, 0.009705f, 0.012688f, 0.017044f, 0.023788f, 0.034882f, 0.053284f, 0.086670f, 0.151123f, 0.271484f, 0.457031f,
+ 0.658203f, 0.805176f, 0.954102f, 0.955078f, 0.956055f, 0.956055f, 0.956055f, 0.955566f, 0.000000f, 0.000122f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000116f, 0.000101f, 0.000088f, 0.000077f, 0.000131f, 0.000071f,
+ 0.000146f, 0.000200f, 0.000237f, 0.000270f, 0.000289f, 0.000302f, 0.000311f, 0.000441f, 0.000396f, 0.000588f, 0.000630f, 0.000570f,
+ 0.000575f, 0.000537f, 0.000589f, 0.000750f, 0.000721f, 0.001048f, 0.001122f, 0.000951f, 0.001243f, 0.001346f, 0.001703f, 0.001592f,
+ 0.001880f, 0.002340f, 0.002804f, 0.003637f, 0.004356f, 0.005329f, 0.006805f, 0.009094f, 0.012566f, 0.017181f, 0.025040f, 0.038147f,
+ 0.061249f, 0.107788f, 0.200195f, 0.369629f, 0.587891f, 0.771973f, 0.948242f, 0.949707f, 0.950195f, 0.949707f, 0.950195f, 0.950195f,
+ 0.000000f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000120f, 0.000119f, 0.000119f, 0.000114f,
+ 0.000101f, 0.000088f, 0.000079f, 0.000070f, 0.000063f, 0.000136f, 0.000136f, 0.000183f, 0.000207f, 0.000277f, 0.000271f, 0.000291f,
+ 0.000369f, 0.000344f, 0.000494f, 0.000459f, 0.000515f, 0.000509f, 0.000532f, 0.000504f, 0.000716f, 0.000589f, 0.000691f, 0.000902f,
+ 0.000972f, 0.000968f, 0.001067f, 0.001483f, 0.001780f, 0.001652f, 0.002090f, 0.002602f, 0.003113f, 0.003738f, 0.004738f, 0.006420f,
+ 0.008522f, 0.012100f, 0.017334f, 0.026489f, 0.042786f, 0.074524f, 0.142578f, 0.283936f, 0.509277f, 0.729492f, 0.940918f, 0.941895f,
+ 0.942383f, 0.942383f, 0.942383f, 0.942871f, 0.000122f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000119f, 0.000119f,
+ 0.000119f, 0.000118f, 0.000118f, 0.000118f, 0.000116f, 0.000102f, 0.000090f, 0.000081f, 0.000091f, 0.000066f, 0.000059f, 0.000110f,
+ 0.000109f, 0.000155f, 0.000184f, 0.000227f, 0.000297f, 0.000333f, 0.000355f, 0.000349f, 0.000344f, 0.000421f, 0.000459f, 0.000561f,
+ 0.000600f, 0.000563f, 0.000630f, 0.000563f, 0.000682f, 0.000737f, 0.000892f, 0.001037f, 0.001026f, 0.001163f, 0.001743f, 0.001782f,
+ 0.002117f, 0.002573f, 0.003389f, 0.004429f, 0.005871f, 0.007942f, 0.011841f, 0.018066f, 0.029190f, 0.050842f, 0.098511f, 0.207397f,
+ 0.422363f, 0.677734f, 0.932129f, 0.933594f, 0.933594f, 0.934082f, 0.934082f, 0.934082f, 0.000000f, 0.000121f, 0.000120f, 0.000119f,
+ 0.000119f, 0.000119f, 0.000118f, 0.000118f, 0.000118f, 0.000117f, 0.000117f, 0.000117f, 0.000117f, 0.000116f, 0.000104f, 0.000093f,
+ 0.000084f, 0.000076f, 0.000069f, 0.000091f, 0.000057f, 0.000051f, 0.000112f, 0.000120f, 0.000179f, 0.000232f, 0.000225f, 0.000283f,
+ 0.000301f, 0.000308f, 0.000353f, 0.000437f, 0.000395f, 0.000523f, 0.000486f, 0.000504f, 0.000469f, 0.000614f, 0.000581f, 0.000755f,
+ 0.000789f, 0.001121f, 0.000981f, 0.001218f, 0.001565f, 0.001795f, 0.002296f, 0.002958f, 0.003866f, 0.005329f, 0.007675f, 0.011658f,
+ 0.019043f, 0.033478f, 0.065430f, 0.144043f, 0.331299f, 0.613770f, 0.921387f, 0.922852f, 0.923340f, 0.923340f, 0.923340f, 0.923340f,
+ 0.000000f, 0.000000f, 0.000119f, 0.000118f, 0.000118f, 0.000117f, 0.000116f, 0.000116f, 0.000116f, 0.000116f, 0.000115f, 0.000115f,
+ 0.000115f, 0.000115f, 0.000114f, 0.000108f, 0.000097f, 0.000087f, 0.000079f, 0.000072f, 0.000065f, 0.000060f, 0.000094f, 0.000050f,
+ 0.000104f, 0.000104f, 0.000121f, 0.000164f, 0.000195f, 0.000247f, 0.000265f, 0.000328f, 0.000290f, 0.000355f, 0.000395f, 0.000356f,
+ 0.000361f, 0.000459f, 0.000470f, 0.000515f, 0.000580f, 0.000624f, 0.000751f, 0.000964f, 0.001105f, 0.001279f, 0.001413f, 0.001823f,
+ 0.002441f, 0.003407f, 0.004852f, 0.007210f, 0.011803f, 0.021225f, 0.041473f, 0.095032f, 0.244019f, 0.537598f, 0.907715f, 0.910156f,
+ 0.910156f, 0.909180f, 0.909668f, 0.911133f, 0.000120f, 0.000118f, 0.000117f, 0.000116f, 0.000114f, 0.000114f, 0.000114f, 0.000113f,
+ 0.000113f, 0.000112f, 0.000112f, 0.000112f, 0.000111f, 0.000112f, 0.000111f, 0.000111f, 0.000111f, 0.000101f, 0.000093f, 0.000084f,
+ 0.000077f, 0.000070f, 0.000064f, 0.000059f, 0.000074f, 0.000079f, 0.000059f, 0.000087f, 0.000097f, 0.000128f, 0.000185f, 0.000213f,
+ 0.000265f, 0.000235f, 0.000239f, 0.000288f, 0.000299f, 0.000371f, 0.000341f, 0.000369f, 0.000460f, 0.000446f, 0.000490f, 0.000602f,
+ 0.000694f, 0.000904f, 0.001012f, 0.001234f, 0.001544f, 0.002096f, 0.002989f, 0.004299f, 0.006840f, 0.012383f, 0.024948f, 0.059204f,
+ 0.166626f, 0.452637f, 0.892578f, 0.894043f, 0.894043f, 0.894531f, 0.894531f, 0.894043f, 0.000115f, 0.000107f, 0.000108f, 0.000111f,
+ 0.000108f, 0.000109f, 0.000108f, 0.000108f, 0.000108f, 0.000107f, 0.000108f, 0.000107f, 0.000107f, 0.000106f, 0.000107f, 0.000107f,
+ 0.000106f, 0.000107f, 0.000106f, 0.000097f, 0.000090f, 0.000082f, 0.000075f, 0.000069f, 0.000063f, 0.000058f, 0.000053f, 0.000070f,
+ 0.000073f, 0.000085f, 0.000077f, 0.000088f, 0.000136f, 0.000168f, 0.000190f, 0.000204f, 0.000199f, 0.000252f, 0.000233f, 0.000270f,
+ 0.000325f, 0.000295f, 0.000348f, 0.000383f, 0.000435f, 0.000534f, 0.000581f, 0.000803f, 0.001004f, 0.001330f, 0.001812f, 0.002489f,
+ 0.003944f, 0.006832f, 0.013748f, 0.033997f, 0.104858f, 0.356689f, 0.873047f, 0.873047f, 0.875000f, 0.874023f, 0.874023f, 0.874023f,
+ 0.000000f, 0.000071f, 0.000063f, 0.000094f, 0.000092f, 0.000094f, 0.000093f, 0.000098f, 0.000098f, 0.000098f, 0.000098f, 0.000099f,
+ 0.000098f, 0.000099f, 0.000099f, 0.000099f, 0.000099f, 0.000099f, 0.000099f, 0.000100f, 0.000100f, 0.000094f, 0.000087f, 0.000080f,
+ 0.000074f, 0.000068f, 0.000062f, 0.000058f, 0.000053f, 0.000049f, 0.000059f, 0.000059f, 0.000045f, 0.000078f, 0.000082f, 0.000118f,
+ 0.000155f, 0.000160f, 0.000174f, 0.000180f, 0.000226f, 0.000213f, 0.000248f, 0.000258f, 0.000288f, 0.000352f, 0.000396f, 0.000465f,
+ 0.000566f, 0.000789f, 0.000941f, 0.001343f, 0.002199f, 0.003616f, 0.006912f, 0.017380f, 0.058960f, 0.259521f, 0.847656f, 0.849121f,
+ 0.850586f, 0.850098f, 0.849121f, 0.850586f, 0.000000f, 0.000000f, 0.000019f, 0.000044f, 0.000048f, 0.000061f, 0.000071f, 0.000073f,
+ 0.000076f, 0.000079f, 0.000079f, 0.000082f, 0.000082f, 0.000082f, 0.000085f, 0.000086f, 0.000087f, 0.000086f, 0.000088f, 0.000087f,
+ 0.000089f, 0.000089f, 0.000089f, 0.000090f, 0.000084f, 0.000078f, 0.000072f, 0.000067f, 0.000062f, 0.000057f, 0.000052f, 0.000049f,
+ 0.000045f, 0.000041f, 0.000038f, 0.000040f, 0.000062f, 0.000092f, 0.000100f, 0.000121f, 0.000144f, 0.000133f, 0.000137f, 0.000170f,
+ 0.000181f, 0.000168f, 0.000215f, 0.000286f, 0.000327f, 0.000397f, 0.000504f, 0.000738f, 0.001039f, 0.001729f, 0.003317f, 0.007721f,
+ 0.028458f, 0.166626f, 0.815430f, 0.818359f, 0.818359f, 0.817383f, 0.818848f, 0.818359f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000008f, 0.000016f, 0.000031f, 0.000035f, 0.000048f, 0.000050f, 0.000053f, 0.000058f, 0.000059f,
+ 0.000063f, 0.000064f, 0.000067f, 0.000067f, 0.000070f, 0.000071f, 0.000072f, 0.000073f, 0.000075f, 0.000075f, 0.000076f, 0.000075f,
+ 0.000069f, 0.000064f, 0.000060f, 0.000055f, 0.000051f, 0.000047f, 0.000043f, 0.000040f, 0.000037f, 0.000034f, 0.000040f, 0.000041f,
+ 0.000054f, 0.000069f, 0.000096f, 0.000111f, 0.000109f, 0.000113f, 0.000142f, 0.000136f, 0.000158f, 0.000196f, 0.000237f, 0.000349f,
+ 0.000423f, 0.000744f, 0.001380f, 0.003214f, 0.011124f, 0.088135f, 0.777344f, 0.779297f, 0.780273f, 0.779785f, 0.779785f, 0.779785f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000003f, 0.000007f, 0.000021f, 0.000023f, 0.000031f, 0.000034f, 0.000038f, 0.000041f, 0.000043f, 0.000047f,
+ 0.000049f, 0.000050f, 0.000053f, 0.000055f, 0.000056f, 0.000057f, 0.000059f, 0.000060f, 0.000055f, 0.000051f, 0.000048f, 0.000044f,
+ 0.000041f, 0.000038f, 0.000035f, 0.000032f, 0.000029f, 0.000028f, 0.000028f, 0.000037f, 0.000044f, 0.000064f, 0.000078f, 0.000072f,
+ 0.000089f, 0.000098f, 0.000104f, 0.000146f, 0.000200f, 0.000272f, 0.000479f, 0.001077f, 0.003733f, 0.033752f, 0.729492f, 0.730957f,
+ 0.732422f, 0.731934f, 0.732422f, 0.732422f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000002f, 0.000006f, 0.000009f, 0.000013f, 0.000019f, 0.000021f, 0.000025f, 0.000027f, 0.000030f,
+ 0.000033f, 0.000034f, 0.000037f, 0.000039f, 0.000041f, 0.000039f, 0.000036f, 0.000033f, 0.000031f, 0.000028f, 0.000026f, 0.000024f,
+ 0.000021f, 0.000019f, 0.000017f, 0.000023f, 0.000033f, 0.000041f, 0.000043f, 0.000058f, 0.000061f, 0.000081f, 0.000121f, 0.000248f,
+ 0.000821f, 0.008255f, 0.673340f, 0.674805f, 0.674316f, 0.674805f, 0.674805f, 0.673828f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000004f, 0.000006f, 0.000010f, 0.000013f,
+ 0.000015f, 0.000017f, 0.000020f, 0.000022f, 0.000021f, 0.000019f, 0.000017f, 0.000015f, 0.000013f, 0.000012f, 0.000010f, 0.000011f,
+ 0.000016f, 0.000019f, 0.000019f, 0.000036f, 0.000090f, 0.000897f, 0.606934f, 0.609863f, 0.609375f, 0.609863f, 0.609863f, 0.610352f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000001f, 0.000003f, 0.000006f, 0.000005f, 0.000004f, 0.000003f, 0.000004f, 0.000008f, 0.534668f, 0.536621f,
+ 0.537109f, 0.537109f, 0.536621f, 0.536621f,
+ },
+ {
+ 0.149292f, 0.432373f, 0.614258f, 0.719238f, 0.784180f, 0.826660f, 0.856934f, 0.879883f, 0.896484f, 0.909180f, 0.919922f, 0.928711f,
+ 0.936035f, 0.942383f, 0.947266f, 0.952148f, 0.956055f, 0.959473f, 0.962891f, 0.965820f, 0.968262f, 0.970703f, 0.972656f, 0.974609f,
+ 0.976562f, 0.978027f, 0.979492f, 0.980469f, 0.981934f, 0.983398f, 0.984863f, 0.985352f, 0.986328f, 0.987305f, 0.988281f, 0.989258f,
+ 0.989746f, 0.990234f, 0.990723f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.993652f, 0.994629f, 0.995117f, 0.995117f, 0.996094f,
+ 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.998047f, 0.998047f, 0.998535f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999512f, 0.999512f, 0.999512f, 0.999023f, 0.040161f, 0.161255f, 0.324951f, 0.486572f, 0.612305f, 0.704590f, 0.767090f, 0.811523f,
+ 0.844238f, 0.868652f, 0.887695f, 0.902344f, 0.913574f, 0.924316f, 0.932129f, 0.937988f, 0.944336f, 0.949707f, 0.954102f, 0.957520f,
+ 0.960938f, 0.964355f, 0.966797f, 0.969727f, 0.971191f, 0.973633f, 0.975586f, 0.977539f, 0.979004f, 0.980469f, 0.981445f, 0.982910f,
+ 0.983887f, 0.985352f, 0.985840f, 0.987305f, 0.987793f, 0.988770f, 0.989258f, 0.990234f, 0.991211f, 0.992188f, 0.992676f, 0.993164f,
+ 0.993164f, 0.993652f, 0.994141f, 0.995117f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998535f,
+ 0.999023f, 0.999023f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999023f, 0.017395f, 0.068542f, 0.149292f, 0.262451f,
+ 0.392822f, 0.518066f, 0.621582f, 0.700195f, 0.759766f, 0.803711f, 0.836426f, 0.862305f, 0.880859f, 0.896484f, 0.909668f, 0.919434f,
+ 0.929199f, 0.935547f, 0.941895f, 0.947754f, 0.952637f, 0.956055f, 0.959961f, 0.963867f, 0.965820f, 0.968750f, 0.970703f, 0.973145f,
+ 0.975098f, 0.977051f, 0.979004f, 0.979980f, 0.981934f, 0.983398f, 0.983887f, 0.984863f, 0.985840f, 0.986816f, 0.987793f, 0.989258f,
+ 0.989746f, 0.990234f, 0.991211f, 0.991699f, 0.992188f, 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.995605f, 0.996094f, 0.996094f,
+ 0.996582f, 0.997070f, 0.997559f, 0.997559f, 0.998047f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999512f, 0.999023f,
+ 0.009125f, 0.035492f, 0.075806f, 0.135864f, 0.219971f, 0.324707f, 0.437012f, 0.543457f, 0.633789f, 0.704102f, 0.758789f, 0.802246f,
+ 0.833496f, 0.857910f, 0.878418f, 0.894043f, 0.906738f, 0.917480f, 0.925781f, 0.933594f, 0.940918f, 0.946777f, 0.951172f, 0.954590f,
+ 0.959473f, 0.962891f, 0.965820f, 0.968262f, 0.971191f, 0.973145f, 0.975098f, 0.976562f, 0.978516f, 0.979980f, 0.981445f, 0.982422f,
+ 0.983887f, 0.985840f, 0.986328f, 0.987305f, 0.988281f, 0.988770f, 0.989746f, 0.990234f, 0.991699f, 0.992188f, 0.992676f, 0.993652f,
+ 0.994141f, 0.994629f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996582f, 0.997559f, 0.997559f, 0.998047f, 0.999023f, 0.999023f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.005848f, 0.021225f, 0.043640f, 0.076782f, 0.124084f, 0.189575f, 0.274414f, 0.372559f,
+ 0.473633f, 0.567383f, 0.646973f, 0.711426f, 0.761230f, 0.801758f, 0.833496f, 0.857422f, 0.876953f, 0.893066f, 0.905273f, 0.916504f,
+ 0.925293f, 0.932617f, 0.939941f, 0.945801f, 0.950684f, 0.955566f, 0.958984f, 0.962402f, 0.965820f, 0.968262f, 0.970703f, 0.972656f,
+ 0.975098f, 0.977051f, 0.978516f, 0.980469f, 0.981934f, 0.982422f, 0.983887f, 0.985840f, 0.986328f, 0.987305f, 0.988281f, 0.989258f,
+ 0.989746f, 0.990723f, 0.991211f, 0.992188f, 0.993164f, 0.993652f, 0.994629f, 0.995117f, 0.995117f, 0.996094f, 0.996094f, 0.997070f,
+ 0.997559f, 0.997559f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.998535f, 0.998535f, 0.003937f, 0.014107f, 0.027664f, 0.047211f,
+ 0.075195f, 0.113953f, 0.166748f, 0.236328f, 0.320312f, 0.412354f, 0.504395f, 0.589844f, 0.661621f, 0.719727f, 0.768066f, 0.805664f,
+ 0.834961f, 0.858398f, 0.877441f, 0.893066f, 0.906738f, 0.916992f, 0.926270f, 0.933105f, 0.940430f, 0.946289f, 0.951172f, 0.955566f,
+ 0.959473f, 0.962891f, 0.965820f, 0.968262f, 0.970703f, 0.973145f, 0.975098f, 0.977051f, 0.979004f, 0.980469f, 0.981934f, 0.983398f,
+ 0.984375f, 0.985840f, 0.986328f, 0.987305f, 0.988770f, 0.989746f, 0.990723f, 0.991211f, 0.992188f, 0.992676f, 0.993652f, 0.994629f,
+ 0.994629f, 0.995117f, 0.995605f, 0.995605f, 0.996582f, 0.997070f, 0.998535f, 0.999023f, 0.999023f, 0.999023f, 0.998535f, 0.998535f,
+ 0.002962f, 0.009674f, 0.019348f, 0.031708f, 0.049255f, 0.072754f, 0.105164f, 0.149048f, 0.206665f, 0.278076f, 0.361572f, 0.448730f,
+ 0.534668f, 0.611816f, 0.677734f, 0.730957f, 0.775879f, 0.809570f, 0.837891f, 0.861328f, 0.879395f, 0.894531f, 0.907227f, 0.916992f,
+ 0.926270f, 0.934082f, 0.940918f, 0.946289f, 0.951172f, 0.956055f, 0.959473f, 0.962891f, 0.966797f, 0.969238f, 0.971191f, 0.973633f,
+ 0.976074f, 0.977539f, 0.979492f, 0.980957f, 0.982422f, 0.983398f, 0.984863f, 0.986328f, 0.986816f, 0.988281f, 0.989746f, 0.989746f,
+ 0.991211f, 0.991699f, 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.994629f, 0.995605f, 0.996094f, 0.997070f, 0.998535f, 0.999023f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.001900f, 0.007225f, 0.013733f, 0.022552f, 0.033661f, 0.049164f, 0.070374f, 0.097534f,
+ 0.135132f, 0.183350f, 0.244507f, 0.317871f, 0.400146f, 0.483643f, 0.562988f, 0.633301f, 0.693848f, 0.743652f, 0.784180f, 0.816895f,
+ 0.842773f, 0.865234f, 0.882812f, 0.896973f, 0.908691f, 0.919434f, 0.927734f, 0.935547f, 0.942383f, 0.947266f, 0.952637f, 0.957031f,
+ 0.960938f, 0.964355f, 0.967285f, 0.969727f, 0.971680f, 0.974609f, 0.976074f, 0.978027f, 0.979980f, 0.981445f, 0.982910f, 0.984375f,
+ 0.985840f, 0.986328f, 0.988281f, 0.988770f, 0.989746f, 0.990723f, 0.991699f, 0.992188f, 0.993164f, 0.993652f, 0.994629f, 0.995117f,
+ 0.995605f, 0.996094f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998047f, 0.001921f, 0.005543f, 0.010223f, 0.016312f,
+ 0.024918f, 0.035217f, 0.049164f, 0.067017f, 0.091125f, 0.122986f, 0.164673f, 0.217896f, 0.282471f, 0.356934f, 0.436768f, 0.516602f,
+ 0.590820f, 0.656250f, 0.711426f, 0.757812f, 0.794922f, 0.825684f, 0.850098f, 0.870605f, 0.885742f, 0.900879f, 0.912109f, 0.921387f,
+ 0.929688f, 0.937500f, 0.943848f, 0.949219f, 0.953125f, 0.958496f, 0.961426f, 0.964844f, 0.967773f, 0.970703f, 0.973145f, 0.975098f,
+ 0.977539f, 0.979004f, 0.980957f, 0.982422f, 0.983887f, 0.985352f, 0.986328f, 0.987793f, 0.988770f, 0.989258f, 0.990723f, 0.991211f,
+ 0.992188f, 0.993164f, 0.993652f, 0.994141f, 0.994629f, 0.995117f, 0.998047f, 0.998535f, 0.998535f, 0.998535f, 0.998047f, 0.998047f,
+ 0.001360f, 0.004257f, 0.007988f, 0.013092f, 0.018753f, 0.026352f, 0.035645f, 0.048096f, 0.064270f, 0.085449f, 0.113770f, 0.149292f,
+ 0.195190f, 0.251953f, 0.320557f, 0.395020f, 0.474121f, 0.549316f, 0.618652f, 0.678223f, 0.729492f, 0.770996f, 0.805176f, 0.833496f,
+ 0.855957f, 0.875977f, 0.891113f, 0.904785f, 0.915039f, 0.924316f, 0.933105f, 0.939453f, 0.945312f, 0.950684f, 0.955078f, 0.959473f,
+ 0.962891f, 0.966309f, 0.969727f, 0.972168f, 0.974121f, 0.976562f, 0.978516f, 0.979980f, 0.981934f, 0.983398f, 0.984375f, 0.986328f,
+ 0.986816f, 0.988281f, 0.989746f, 0.990234f, 0.991699f, 0.992188f, 0.992676f, 0.994141f, 0.994141f, 0.994629f, 0.998047f, 0.998047f,
+ 0.998535f, 0.998047f, 0.998047f, 0.998047f, 0.001075f, 0.003492f, 0.006275f, 0.010223f, 0.014473f, 0.019821f, 0.026581f, 0.035492f,
+ 0.046967f, 0.061829f, 0.080750f, 0.105164f, 0.136475f, 0.177246f, 0.227783f, 0.288818f, 0.358154f, 0.433594f, 0.509277f, 0.581543f,
+ 0.645508f, 0.701172f, 0.747070f, 0.783691f, 0.817383f, 0.842773f, 0.864258f, 0.881836f, 0.896484f, 0.908691f, 0.918945f, 0.928223f,
+ 0.935547f, 0.941895f, 0.948730f, 0.952637f, 0.957031f, 0.962402f, 0.964844f, 0.967773f, 0.970703f, 0.973633f, 0.975586f, 0.977539f,
+ 0.979492f, 0.981445f, 0.982910f, 0.984375f, 0.985840f, 0.986816f, 0.988281f, 0.988770f, 0.990234f, 0.991211f, 0.992188f, 0.992676f,
+ 0.993164f, 0.994141f, 0.997559f, 0.997559f, 0.998047f, 0.997559f, 0.997559f, 0.998047f, 0.000967f, 0.002928f, 0.005283f, 0.007759f,
+ 0.011612f, 0.015823f, 0.020966f, 0.027802f, 0.035461f, 0.045959f, 0.059235f, 0.075928f, 0.097778f, 0.126099f, 0.162598f, 0.207153f,
+ 0.261963f, 0.326416f, 0.398193f, 0.471680f, 0.543945f, 0.612305f, 0.671875f, 0.722656f, 0.765137f, 0.799805f, 0.828125f, 0.854004f,
+ 0.872070f, 0.888184f, 0.902344f, 0.914062f, 0.923340f, 0.931641f, 0.938965f, 0.945312f, 0.950684f, 0.955566f, 0.958984f, 0.962891f,
+ 0.966309f, 0.969727f, 0.972168f, 0.974609f, 0.977051f, 0.978516f, 0.980469f, 0.982422f, 0.984375f, 0.985352f, 0.987305f, 0.987793f,
+ 0.988770f, 0.990234f, 0.991211f, 0.992188f, 0.992676f, 0.993164f, 0.997559f, 0.997559f, 0.997559f, 0.998047f, 0.997559f, 0.998047f,
+ 0.000602f, 0.002605f, 0.004345f, 0.006706f, 0.009590f, 0.012650f, 0.016617f, 0.021423f, 0.027893f, 0.035004f, 0.044495f, 0.056610f,
+ 0.072327f, 0.092285f, 0.116821f, 0.148926f, 0.189697f, 0.238892f, 0.298340f, 0.365723f, 0.437988f, 0.511230f, 0.579590f, 0.642090f,
+ 0.698242f, 0.744141f, 0.781738f, 0.814453f, 0.840332f, 0.861816f, 0.880371f, 0.895996f, 0.907715f, 0.918945f, 0.928223f, 0.935547f,
+ 0.942871f, 0.948730f, 0.953125f, 0.958008f, 0.961914f, 0.965332f, 0.968750f, 0.971680f, 0.973633f, 0.976562f, 0.978516f, 0.979980f,
+ 0.981934f, 0.983398f, 0.985352f, 0.986816f, 0.988281f, 0.988770f, 0.989746f, 0.990723f, 0.991699f, 0.992676f, 0.997070f, 0.997559f,
+ 0.997559f, 0.997070f, 0.997070f, 0.997070f, 0.000607f, 0.001955f, 0.003616f, 0.005772f, 0.007656f, 0.010269f, 0.013496f, 0.017273f,
+ 0.022018f, 0.027466f, 0.034729f, 0.043488f, 0.054932f, 0.068359f, 0.086365f, 0.108765f, 0.137939f, 0.174316f, 0.219360f, 0.273926f,
+ 0.336670f, 0.406494f, 0.478516f, 0.549316f, 0.614746f, 0.673340f, 0.722656f, 0.765137f, 0.800293f, 0.828125f, 0.853516f, 0.872070f,
+ 0.888672f, 0.902832f, 0.914551f, 0.924316f, 0.932129f, 0.940430f, 0.946289f, 0.951660f, 0.956055f, 0.960449f, 0.964355f, 0.967773f,
+ 0.970703f, 0.972656f, 0.975586f, 0.978027f, 0.980469f, 0.981934f, 0.983398f, 0.985352f, 0.986328f, 0.988281f, 0.988770f, 0.990234f,
+ 0.990723f, 0.992188f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.000600f, 0.001813f, 0.003101f, 0.004559f,
+ 0.006580f, 0.008873f, 0.011047f, 0.014091f, 0.017639f, 0.022049f, 0.027557f, 0.033997f, 0.042297f, 0.052704f, 0.065369f, 0.081238f,
+ 0.101929f, 0.127930f, 0.161255f, 0.202515f, 0.252686f, 0.311523f, 0.378174f, 0.449707f, 0.519531f, 0.587891f, 0.647949f, 0.701660f,
+ 0.746582f, 0.784668f, 0.817383f, 0.843262f, 0.864746f, 0.882324f, 0.896973f, 0.910156f, 0.920898f, 0.929688f, 0.937012f, 0.943848f,
+ 0.949707f, 0.955078f, 0.959473f, 0.963379f, 0.966797f, 0.970215f, 0.973145f, 0.975098f, 0.978027f, 0.980469f, 0.982422f, 0.983887f,
+ 0.984863f, 0.986328f, 0.987793f, 0.988770f, 0.989746f, 0.991211f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.997070f,
+ 0.000604f, 0.001429f, 0.002676f, 0.003708f, 0.005745f, 0.006973f, 0.009270f, 0.011452f, 0.014503f, 0.018295f, 0.022369f, 0.027222f,
+ 0.033417f, 0.040833f, 0.050171f, 0.062744f, 0.077454f, 0.095886f, 0.119995f, 0.150391f, 0.187622f, 0.234253f, 0.289307f, 0.353027f,
+ 0.421631f, 0.492676f, 0.561523f, 0.625488f, 0.681152f, 0.730469f, 0.770996f, 0.806152f, 0.833984f, 0.857422f, 0.876465f, 0.893066f,
+ 0.906250f, 0.916992f, 0.926758f, 0.935059f, 0.942871f, 0.948242f, 0.954102f, 0.958496f, 0.962891f, 0.966309f, 0.969727f, 0.972168f,
+ 0.975098f, 0.977539f, 0.979492f, 0.981934f, 0.983398f, 0.984863f, 0.986328f, 0.987793f, 0.989258f, 0.990234f, 0.996094f, 0.996582f,
+ 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.000365f, 0.001367f, 0.002123f, 0.003353f, 0.004692f, 0.006054f, 0.007675f, 0.009819f,
+ 0.012314f, 0.014862f, 0.018066f, 0.022064f, 0.026901f, 0.032471f, 0.039764f, 0.048584f, 0.060089f, 0.073730f, 0.090698f, 0.112854f,
+ 0.140381f, 0.175415f, 0.218018f, 0.269775f, 0.329834f, 0.396240f, 0.467285f, 0.537598f, 0.603516f, 0.662109f, 0.712891f, 0.757324f,
+ 0.793945f, 0.823730f, 0.849121f, 0.869629f, 0.887695f, 0.902344f, 0.914062f, 0.924805f, 0.932129f, 0.940430f, 0.947266f, 0.952148f,
+ 0.957031f, 0.962402f, 0.966309f, 0.969238f, 0.972656f, 0.975586f, 0.977051f, 0.979492f, 0.981934f, 0.983398f, 0.984863f, 0.986328f,
+ 0.988281f, 0.988770f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.000356f, 0.001341f, 0.001913f, 0.002897f,
+ 0.003983f, 0.005322f, 0.006607f, 0.008514f, 0.010399f, 0.012451f, 0.015282f, 0.018356f, 0.021912f, 0.026443f, 0.031982f, 0.038635f,
+ 0.047150f, 0.057495f, 0.070007f, 0.086609f, 0.106689f, 0.131714f, 0.164429f, 0.203613f, 0.252441f, 0.310059f, 0.374512f, 0.444092f,
+ 0.514160f, 0.582031f, 0.643066f, 0.697266f, 0.743652f, 0.783691f, 0.814941f, 0.842773f, 0.865234f, 0.882812f, 0.897949f, 0.910645f,
+ 0.922363f, 0.931152f, 0.938965f, 0.945801f, 0.952148f, 0.957520f, 0.961426f, 0.965820f, 0.969727f, 0.972168f, 0.975098f, 0.977539f,
+ 0.979980f, 0.981934f, 0.983887f, 0.985352f, 0.986816f, 0.988281f, 0.995117f, 0.995605f, 0.996094f, 0.996094f, 0.996094f, 0.996094f,
+ 0.000243f, 0.000937f, 0.001662f, 0.002617f, 0.003527f, 0.004555f, 0.005642f, 0.007217f, 0.008820f, 0.010483f, 0.012383f, 0.015175f,
+ 0.018341f, 0.022049f, 0.026245f, 0.031067f, 0.037903f, 0.045563f, 0.054962f, 0.066956f, 0.082092f, 0.101074f, 0.124939f, 0.154663f,
+ 0.191528f, 0.237305f, 0.291992f, 0.354492f, 0.422852f, 0.492676f, 0.562012f, 0.625488f, 0.682617f, 0.731934f, 0.772949f, 0.807129f,
+ 0.835449f, 0.859863f, 0.878906f, 0.895020f, 0.908203f, 0.920898f, 0.929199f, 0.937988f, 0.945312f, 0.951660f, 0.957031f, 0.961914f,
+ 0.965332f, 0.968750f, 0.972656f, 0.975098f, 0.977539f, 0.979980f, 0.982422f, 0.983887f, 0.986328f, 0.987793f, 0.995117f, 0.995605f,
+ 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.000362f, 0.000970f, 0.001489f, 0.002251f, 0.002892f, 0.003727f, 0.004978f, 0.006264f,
+ 0.007530f, 0.009125f, 0.010551f, 0.012756f, 0.015259f, 0.018097f, 0.021637f, 0.025986f, 0.030594f, 0.036804f, 0.044006f, 0.053162f,
+ 0.064148f, 0.078003f, 0.096130f, 0.118042f, 0.146118f, 0.181030f, 0.224487f, 0.276123f, 0.336670f, 0.403320f, 0.473633f, 0.543457f,
+ 0.609375f, 0.667480f, 0.719238f, 0.763184f, 0.799316f, 0.829590f, 0.854492f, 0.875488f, 0.892578f, 0.906738f, 0.918945f, 0.928711f,
+ 0.937012f, 0.944336f, 0.951172f, 0.956543f, 0.961426f, 0.965820f, 0.968750f, 0.972656f, 0.975098f, 0.978027f, 0.980469f, 0.982910f,
+ 0.984375f, 0.985840f, 0.994629f, 0.995117f, 0.995117f, 0.995117f, 0.995117f, 0.995117f, 0.000346f, 0.000923f, 0.001273f, 0.002010f,
+ 0.002619f, 0.003689f, 0.004452f, 0.005177f, 0.006290f, 0.007561f, 0.009033f, 0.010902f, 0.012970f, 0.015495f, 0.018280f, 0.021576f,
+ 0.024948f, 0.030304f, 0.035400f, 0.042480f, 0.051086f, 0.061401f, 0.074890f, 0.091187f, 0.112427f, 0.138794f, 0.171631f, 0.212158f,
+ 0.262451f, 0.320557f, 0.385986f, 0.456055f, 0.525391f, 0.593262f, 0.654297f, 0.708984f, 0.754883f, 0.792969f, 0.824707f, 0.850098f,
+ 0.872070f, 0.890137f, 0.904785f, 0.917480f, 0.927734f, 0.937012f, 0.944336f, 0.951172f, 0.956055f, 0.961914f, 0.966309f, 0.969727f,
+ 0.973145f, 0.976074f, 0.978516f, 0.980469f, 0.982910f, 0.984863f, 0.993652f, 0.995117f, 0.994629f, 0.994629f, 0.994629f, 0.994629f,
+ 0.000242f, 0.000666f, 0.001081f, 0.001806f, 0.002512f, 0.003397f, 0.003866f, 0.004894f, 0.005566f, 0.006859f, 0.007957f, 0.009506f,
+ 0.011009f, 0.013046f, 0.015266f, 0.018173f, 0.021027f, 0.024811f, 0.029526f, 0.034790f, 0.041443f, 0.049835f, 0.059265f, 0.071899f,
+ 0.087769f, 0.107422f, 0.132202f, 0.163208f, 0.201782f, 0.249512f, 0.305908f, 0.370361f, 0.440430f, 0.511230f, 0.578613f, 0.642090f,
+ 0.698730f, 0.746582f, 0.787109f, 0.819824f, 0.848145f, 0.869141f, 0.888672f, 0.903809f, 0.916992f, 0.927246f, 0.936523f, 0.943848f,
+ 0.951660f, 0.957031f, 0.961426f, 0.965820f, 0.970215f, 0.973145f, 0.976074f, 0.979004f, 0.981445f, 0.983398f, 0.994141f, 0.994141f,
+ 0.994629f, 0.994141f, 0.994629f, 0.994141f, 0.000242f, 0.000709f, 0.000917f, 0.001194f, 0.002018f, 0.002634f, 0.003504f, 0.003918f,
+ 0.005020f, 0.005726f, 0.006935f, 0.008141f, 0.009666f, 0.011040f, 0.012848f, 0.014961f, 0.017624f, 0.020660f, 0.024368f, 0.028381f,
+ 0.033905f, 0.040283f, 0.047760f, 0.057312f, 0.069214f, 0.083984f, 0.102539f, 0.126221f, 0.155640f, 0.193359f, 0.238892f, 0.293701f,
+ 0.356689f, 0.425537f, 0.497070f, 0.568359f, 0.632812f, 0.690918f, 0.739746f, 0.782227f, 0.816406f, 0.845703f, 0.868652f, 0.887695f,
+ 0.903320f, 0.916992f, 0.927734f, 0.937012f, 0.944824f, 0.951660f, 0.957031f, 0.962891f, 0.966797f, 0.971191f, 0.973633f, 0.976562f,
+ 0.979492f, 0.981934f, 0.992676f, 0.993652f, 0.994141f, 0.993652f, 0.993652f, 0.994141f, 0.000244f, 0.000660f, 0.000918f, 0.001343f,
+ 0.002117f, 0.002407f, 0.002779f, 0.003626f, 0.004246f, 0.005207f, 0.005913f, 0.007145f, 0.008163f, 0.009438f, 0.011101f, 0.012871f,
+ 0.014999f, 0.017426f, 0.020096f, 0.024185f, 0.027725f, 0.032623f, 0.038910f, 0.046387f, 0.055298f, 0.066467f, 0.080627f, 0.098328f,
+ 0.120972f, 0.149658f, 0.184814f, 0.229492f, 0.282715f, 0.344727f, 0.414062f, 0.486084f, 0.556641f, 0.624023f, 0.683594f, 0.735352f,
+ 0.778320f, 0.814453f, 0.843750f, 0.867188f, 0.887207f, 0.903320f, 0.916504f, 0.928223f, 0.937500f, 0.945312f, 0.953125f, 0.958008f,
+ 0.964355f, 0.967285f, 0.971680f, 0.975098f, 0.978516f, 0.980957f, 0.992676f, 0.993652f, 0.994141f, 0.993652f, 0.993652f, 0.993164f,
+ 0.000200f, 0.000480f, 0.000808f, 0.001303f, 0.001680f, 0.002104f, 0.002510f, 0.002934f, 0.003468f, 0.004429f, 0.005539f, 0.006046f,
+ 0.006889f, 0.008438f, 0.009415f, 0.011108f, 0.012787f, 0.014572f, 0.017517f, 0.020279f, 0.023483f, 0.027359f, 0.031860f, 0.037964f,
+ 0.045227f, 0.053711f, 0.064148f, 0.077759f, 0.095093f, 0.116272f, 0.143311f, 0.177856f, 0.221191f, 0.273193f, 0.334473f, 0.403320f,
+ 0.476318f, 0.548828f, 0.617188f, 0.677734f, 0.730957f, 0.775879f, 0.812500f, 0.842285f, 0.866699f, 0.887695f, 0.903809f, 0.916992f,
+ 0.928711f, 0.938477f, 0.946777f, 0.953125f, 0.959473f, 0.963867f, 0.968750f, 0.972656f, 0.976074f, 0.979004f, 0.992188f, 0.992676f,
+ 0.993164f, 0.993164f, 0.992676f, 0.993164f, 0.000243f, 0.000469f, 0.000878f, 0.001158f, 0.001382f, 0.001801f, 0.002220f, 0.002699f,
+ 0.003273f, 0.004063f, 0.004715f, 0.005447f, 0.005917f, 0.007099f, 0.008385f, 0.009521f, 0.011032f, 0.012627f, 0.014870f, 0.016922f,
+ 0.019836f, 0.023010f, 0.026642f, 0.031174f, 0.036926f, 0.043549f, 0.051941f, 0.062561f, 0.075317f, 0.091553f, 0.112427f, 0.138428f,
+ 0.172485f, 0.213867f, 0.265381f, 0.326172f, 0.394775f, 0.467773f, 0.541504f, 0.610840f, 0.673340f, 0.728516f, 0.774414f, 0.812012f,
+ 0.842773f, 0.867676f, 0.887695f, 0.904297f, 0.918457f, 0.929688f, 0.939453f, 0.948242f, 0.955078f, 0.959961f, 0.965820f, 0.970215f,
+ 0.974121f, 0.977051f, 0.991211f, 0.993164f, 0.993164f, 0.992188f, 0.993164f, 0.992188f, 0.000000f, 0.000242f, 0.000799f, 0.000998f,
+ 0.001273f, 0.001671f, 0.002069f, 0.002485f, 0.003212f, 0.003578f, 0.003948f, 0.004559f, 0.005524f, 0.006321f, 0.007046f, 0.008438f,
+ 0.009438f, 0.010986f, 0.012390f, 0.014320f, 0.016663f, 0.019165f, 0.022476f, 0.025833f, 0.030487f, 0.035675f, 0.042358f, 0.050018f,
+ 0.060211f, 0.072693f, 0.088379f, 0.108948f, 0.134766f, 0.166626f, 0.208008f, 0.258545f, 0.318848f, 0.387451f, 0.461670f, 0.536621f,
+ 0.606934f, 0.671387f, 0.727539f, 0.773438f, 0.811523f, 0.843750f, 0.868164f, 0.889160f, 0.906250f, 0.920410f, 0.932617f, 0.941895f,
+ 0.949707f, 0.956055f, 0.962402f, 0.967285f, 0.971680f, 0.975586f, 0.990723f, 0.991699f, 0.991699f, 0.992188f, 0.992188f, 0.991699f,
+ 0.000237f, 0.000482f, 0.000772f, 0.000877f, 0.001109f, 0.001494f, 0.001991f, 0.002041f, 0.002537f, 0.002975f, 0.003469f, 0.004128f,
+ 0.004841f, 0.005550f, 0.006306f, 0.007359f, 0.008369f, 0.009415f, 0.010788f, 0.012306f, 0.014160f, 0.016571f, 0.018921f, 0.021896f,
+ 0.025497f, 0.029587f, 0.034576f, 0.041260f, 0.049011f, 0.058319f, 0.070557f, 0.086060f, 0.105774f, 0.130737f, 0.162720f, 0.203247f,
+ 0.252930f, 0.313477f, 0.382568f, 0.457275f, 0.532715f, 0.605469f, 0.671387f, 0.728027f, 0.774902f, 0.814453f, 0.844727f, 0.870605f,
+ 0.891113f, 0.909180f, 0.922852f, 0.934082f, 0.943359f, 0.951660f, 0.958008f, 0.964355f, 0.968750f, 0.973145f, 0.990234f, 0.990723f,
+ 0.991699f, 0.991211f, 0.991211f, 0.991211f, 0.000235f, 0.000461f, 0.000484f, 0.000891f, 0.001105f, 0.001346f, 0.001634f, 0.001936f,
+ 0.002438f, 0.002874f, 0.003353f, 0.003925f, 0.004189f, 0.004887f, 0.005684f, 0.006279f, 0.007298f, 0.008339f, 0.009384f, 0.010674f,
+ 0.012360f, 0.013901f, 0.016113f, 0.018677f, 0.021469f, 0.024841f, 0.029144f, 0.033783f, 0.039948f, 0.047272f, 0.056915f, 0.068726f,
+ 0.083801f, 0.102905f, 0.127563f, 0.159058f, 0.199341f, 0.248901f, 0.309570f, 0.379395f, 0.454834f, 0.532715f, 0.606934f, 0.672852f,
+ 0.729980f, 0.778320f, 0.817383f, 0.849121f, 0.874512f, 0.895020f, 0.911621f, 0.924805f, 0.937012f, 0.946289f, 0.954102f, 0.960938f,
+ 0.965820f, 0.971191f, 0.989258f, 0.990234f, 0.990723f, 0.991211f, 0.990723f, 0.990723f, 0.000000f, 0.000360f, 0.000477f, 0.000756f,
+ 0.000896f, 0.001065f, 0.001570f, 0.001622f, 0.002064f, 0.002525f, 0.002819f, 0.003004f, 0.003700f, 0.004356f, 0.005077f, 0.005428f,
+ 0.006283f, 0.007370f, 0.008339f, 0.009323f, 0.010567f, 0.012070f, 0.013672f, 0.015839f, 0.018066f, 0.020844f, 0.024002f, 0.028183f,
+ 0.033051f, 0.039246f, 0.046417f, 0.055450f, 0.067200f, 0.082031f, 0.100586f, 0.125122f, 0.156250f, 0.196167f, 0.245972f, 0.307129f,
+ 0.378174f, 0.454834f, 0.533203f, 0.608398f, 0.675781f, 0.734375f, 0.782715f, 0.821777f, 0.853516f, 0.878906f, 0.898926f, 0.915039f,
+ 0.929199f, 0.939941f, 0.948730f, 0.956055f, 0.963379f, 0.968262f, 0.988770f, 0.989746f, 0.990234f, 0.989746f, 0.989746f, 0.990234f,
+ 0.000000f, 0.000256f, 0.000467f, 0.000590f, 0.000772f, 0.001095f, 0.001356f, 0.001781f, 0.001984f, 0.002161f, 0.002546f, 0.002956f,
+ 0.003338f, 0.003899f, 0.004440f, 0.004986f, 0.005486f, 0.006310f, 0.006969f, 0.008148f, 0.009148f, 0.010284f, 0.011902f, 0.013573f,
+ 0.015465f, 0.017853f, 0.020340f, 0.023590f, 0.027298f, 0.032227f, 0.038208f, 0.045563f, 0.054047f, 0.065796f, 0.080322f, 0.098999f,
+ 0.122864f, 0.153809f, 0.193970f, 0.244629f, 0.306396f, 0.378662f, 0.457031f, 0.536621f, 0.613770f, 0.681641f, 0.740723f, 0.788574f,
+ 0.827637f, 0.858398f, 0.884277f, 0.903320f, 0.919922f, 0.932129f, 0.942871f, 0.951660f, 0.959961f, 0.965820f, 0.987305f, 0.988281f,
+ 0.989258f, 0.989258f, 0.989258f, 0.989258f, 0.000244f, 0.000243f, 0.000583f, 0.000585f, 0.000822f, 0.001073f, 0.001159f, 0.001452f,
+ 0.001525f, 0.002001f, 0.002201f, 0.002714f, 0.002932f, 0.003525f, 0.003904f, 0.004482f, 0.004997f, 0.005581f, 0.006233f, 0.006954f,
+ 0.007820f, 0.008949f, 0.009941f, 0.011482f, 0.013168f, 0.015099f, 0.017151f, 0.020111f, 0.022949f, 0.026947f, 0.031647f, 0.037354f,
+ 0.044342f, 0.053375f, 0.064331f, 0.078857f, 0.097351f, 0.121033f, 0.152588f, 0.192749f, 0.244263f, 0.307129f, 0.380615f, 0.461426f,
+ 0.543457f, 0.621582f, 0.690430f, 0.748047f, 0.796387f, 0.834961f, 0.865723f, 0.889160f, 0.908691f, 0.924316f, 0.937500f, 0.946777f,
+ 0.955078f, 0.962891f, 0.986328f, 0.987793f, 0.988770f, 0.988770f, 0.988770f, 0.988770f, 0.000000f, 0.000243f, 0.000308f, 0.000541f,
+ 0.000801f, 0.000827f, 0.001057f, 0.001280f, 0.001460f, 0.001781f, 0.002090f, 0.002481f, 0.002756f, 0.003054f, 0.003321f, 0.003948f,
+ 0.004303f, 0.004898f, 0.005306f, 0.006405f, 0.006954f, 0.007851f, 0.008537f, 0.009918f, 0.011208f, 0.012825f, 0.014534f, 0.016861f,
+ 0.019379f, 0.022629f, 0.026276f, 0.030838f, 0.036407f, 0.043488f, 0.051819f, 0.063416f, 0.077209f, 0.095825f, 0.119812f, 0.151489f,
+ 0.192749f, 0.245361f, 0.309814f, 0.385986f, 0.469238f, 0.552246f, 0.630859f, 0.699707f, 0.757324f, 0.805176f, 0.842773f, 0.873047f,
+ 0.895508f, 0.914062f, 0.929688f, 0.941406f, 0.952148f, 0.959473f, 0.985840f, 0.986816f, 0.987305f, 0.987305f, 0.987305f, 0.987305f,
+ 0.000000f, 0.000243f, 0.000242f, 0.000548f, 0.000695f, 0.000803f, 0.001053f, 0.001198f, 0.001363f, 0.001513f, 0.001886f, 0.002069f,
+ 0.002447f, 0.002676f, 0.003138f, 0.003551f, 0.003868f, 0.004261f, 0.004936f, 0.005337f, 0.005852f, 0.006615f, 0.007519f, 0.008575f,
+ 0.009705f, 0.010872f, 0.012688f, 0.014397f, 0.016479f, 0.019119f, 0.022064f, 0.025589f, 0.030304f, 0.035828f, 0.042603f, 0.050812f,
+ 0.062012f, 0.076355f, 0.094971f, 0.119263f, 0.151367f, 0.193726f, 0.247925f, 0.314941f, 0.393311f, 0.478271f, 0.563965f, 0.642578f,
+ 0.711914f, 0.769043f, 0.815430f, 0.851562f, 0.881348f, 0.902832f, 0.921387f, 0.934570f, 0.945801f, 0.955078f, 0.984375f, 0.986328f,
+ 0.986328f, 0.986328f, 0.986328f, 0.986328f, 0.000000f, 0.000234f, 0.000239f, 0.000308f, 0.000597f, 0.000690f, 0.000868f, 0.000937f,
+ 0.001189f, 0.001404f, 0.001696f, 0.001854f, 0.002180f, 0.002249f, 0.002672f, 0.002979f, 0.003494f, 0.003761f, 0.004257f, 0.004745f,
+ 0.005154f, 0.005821f, 0.006561f, 0.007557f, 0.008575f, 0.009575f, 0.010963f, 0.012238f, 0.014130f, 0.016113f, 0.018539f, 0.021545f,
+ 0.025162f, 0.029404f, 0.034851f, 0.041626f, 0.050354f, 0.061218f, 0.075562f, 0.094482f, 0.119507f, 0.152344f, 0.196167f, 0.252197f,
+ 0.322266f, 0.404053f, 0.490967f, 0.577637f, 0.658203f, 0.726074f, 0.782715f, 0.827637f, 0.861816f, 0.889648f, 0.910645f, 0.926758f,
+ 0.940918f, 0.950684f, 0.983398f, 0.985352f, 0.984863f, 0.985352f, 0.985840f, 0.985352f, 0.000000f, 0.000240f, 0.000237f, 0.000239f,
+ 0.000436f, 0.000648f, 0.000661f, 0.000892f, 0.001089f, 0.001484f, 0.001446f, 0.001586f, 0.001896f, 0.002176f, 0.002325f, 0.002634f,
+ 0.003057f, 0.003315f, 0.003561f, 0.004150f, 0.004578f, 0.005180f, 0.005768f, 0.006485f, 0.007286f, 0.008400f, 0.009453f, 0.010429f,
+ 0.011795f, 0.013680f, 0.015671f, 0.018005f, 0.020981f, 0.024521f, 0.028748f, 0.034119f, 0.040863f, 0.049622f, 0.060303f, 0.074829f,
+ 0.094116f, 0.119995f, 0.154297f, 0.199341f, 0.258301f, 0.331787f, 0.416504f, 0.507812f, 0.595703f, 0.675781f, 0.743164f, 0.797852f,
+ 0.840820f, 0.873535f, 0.899414f, 0.919434f, 0.934082f, 0.947266f, 0.982422f, 0.983887f, 0.983887f, 0.984375f, 0.984375f, 0.983887f,
+ 0.000136f, 0.000115f, 0.000237f, 0.000238f, 0.000358f, 0.000452f, 0.000759f, 0.000961f, 0.001026f, 0.001113f, 0.001433f, 0.001564f,
+ 0.001659f, 0.001955f, 0.002024f, 0.002384f, 0.002647f, 0.002974f, 0.003267f, 0.003611f, 0.003971f, 0.004498f, 0.005043f, 0.005539f,
+ 0.006344f, 0.007168f, 0.007942f, 0.009010f, 0.010353f, 0.011711f, 0.013458f, 0.015213f, 0.017548f, 0.020279f, 0.023926f, 0.028061f,
+ 0.033356f, 0.040283f, 0.048615f, 0.060455f, 0.074890f, 0.094727f, 0.121216f, 0.156860f, 0.204102f, 0.266846f, 0.344238f, 0.433105f,
+ 0.526855f, 0.616699f, 0.696289f, 0.761230f, 0.813965f, 0.854492f, 0.884766f, 0.909180f, 0.927734f, 0.941895f, 0.980957f, 0.982422f,
+ 0.982910f, 0.982422f, 0.982422f, 0.982910f, 0.000000f, 0.000103f, 0.000208f, 0.000356f, 0.000355f, 0.000400f, 0.000454f, 0.000861f,
+ 0.000922f, 0.001202f, 0.001088f, 0.001401f, 0.001493f, 0.001779f, 0.001881f, 0.002180f, 0.002329f, 0.002483f, 0.002846f, 0.003178f,
+ 0.003542f, 0.003914f, 0.004406f, 0.004871f, 0.005352f, 0.006119f, 0.006927f, 0.007904f, 0.008759f, 0.009972f, 0.011284f, 0.013046f,
+ 0.014938f, 0.016998f, 0.019943f, 0.023224f, 0.027161f, 0.032776f, 0.039917f, 0.048218f, 0.059937f, 0.075134f, 0.095642f, 0.123169f,
+ 0.160767f, 0.211670f, 0.278320f, 0.360352f, 0.454102f, 0.550293f, 0.640625f, 0.718262f, 0.781738f, 0.831055f, 0.869141f, 0.897461f,
+ 0.919434f, 0.936035f, 0.979492f, 0.980957f, 0.980957f, 0.981934f, 0.981445f, 0.981445f, 0.000000f, 0.000192f, 0.000191f, 0.000350f,
+ 0.000352f, 0.000354f, 0.000599f, 0.000721f, 0.000835f, 0.001044f, 0.000988f, 0.001141f, 0.001255f, 0.001479f, 0.001705f, 0.001815f,
+ 0.001843f, 0.002151f, 0.002369f, 0.002831f, 0.003067f, 0.003431f, 0.003698f, 0.004295f, 0.004738f, 0.005352f, 0.005859f, 0.006615f,
+ 0.007587f, 0.008583f, 0.009682f, 0.010735f, 0.012405f, 0.014381f, 0.016708f, 0.018921f, 0.022736f, 0.026947f, 0.032104f, 0.039032f,
+ 0.048004f, 0.059784f, 0.075500f, 0.096924f, 0.125977f, 0.166626f, 0.221069f, 0.292969f, 0.380371f, 0.479004f, 0.577637f, 0.667969f,
+ 0.743164f, 0.803711f, 0.849609f, 0.883789f, 0.910645f, 0.930176f, 0.977539f, 0.979492f, 0.979492f, 0.979492f, 0.979980f, 0.979492f,
+ 0.000000f, 0.000000f, 0.000191f, 0.000214f, 0.000441f, 0.000465f, 0.000351f, 0.000656f, 0.000672f, 0.000957f, 0.000881f, 0.001092f,
+ 0.001209f, 0.001259f, 0.001315f, 0.001583f, 0.001630f, 0.001834f, 0.002033f, 0.002367f, 0.002596f, 0.002924f, 0.003387f, 0.003693f,
+ 0.004063f, 0.004601f, 0.004986f, 0.005676f, 0.006557f, 0.006973f, 0.007801f, 0.008781f, 0.010475f, 0.012100f, 0.013817f, 0.015625f,
+ 0.018784f, 0.021927f, 0.026260f, 0.031677f, 0.038879f, 0.048004f, 0.059845f, 0.076233f, 0.098633f, 0.130005f, 0.173950f, 0.233032f,
+ 0.311035f, 0.405518f, 0.507812f, 0.608887f, 0.698242f, 0.769531f, 0.826172f, 0.868164f, 0.899414f, 0.922852f, 0.976074f, 0.977539f,
+ 0.977539f, 0.977051f, 0.978027f, 0.978027f, 0.000000f, 0.000000f, 0.000117f, 0.000211f, 0.000326f, 0.000573f, 0.000574f, 0.000583f,
+ 0.000584f, 0.000659f, 0.000901f, 0.001014f, 0.001064f, 0.001033f, 0.001163f, 0.001234f, 0.001546f, 0.001585f, 0.001894f, 0.002085f,
+ 0.002361f, 0.002504f, 0.003023f, 0.003147f, 0.003580f, 0.004032f, 0.004314f, 0.004936f, 0.005215f, 0.006081f, 0.006725f, 0.007927f,
+ 0.008743f, 0.009918f, 0.011642f, 0.013367f, 0.015404f, 0.018219f, 0.021545f, 0.025787f, 0.031174f, 0.038361f, 0.047577f, 0.060425f,
+ 0.077881f, 0.102051f, 0.135376f, 0.182861f, 0.249023f, 0.333984f, 0.436035f, 0.542969f, 0.644043f, 0.730469f, 0.798340f, 0.848633f,
+ 0.886719f, 0.914062f, 0.973633f, 0.974609f, 0.975098f, 0.976074f, 0.975098f, 0.976074f, 0.000000f, 0.000000f, 0.000114f, 0.000112f,
+ 0.000271f, 0.000510f, 0.000450f, 0.000565f, 0.000572f, 0.000581f, 0.000654f, 0.000825f, 0.000954f, 0.001085f, 0.001050f, 0.001087f,
+ 0.001282f, 0.001547f, 0.001585f, 0.001825f, 0.002066f, 0.002182f, 0.002384f, 0.002659f, 0.003172f, 0.003357f, 0.003721f, 0.004238f,
+ 0.004505f, 0.005024f, 0.005878f, 0.006512f, 0.007324f, 0.008293f, 0.009201f, 0.011040f, 0.012993f, 0.015007f, 0.017639f, 0.020920f,
+ 0.025131f, 0.030899f, 0.038269f, 0.047760f, 0.061188f, 0.079651f, 0.105469f, 0.142944f, 0.195801f, 0.268799f, 0.363525f, 0.472168f,
+ 0.582520f, 0.683594f, 0.765137f, 0.826660f, 0.872070f, 0.905273f, 0.972168f, 0.973633f, 0.973145f, 0.973633f, 0.973633f, 0.973633f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000111f, 0.000224f, 0.000412f, 0.000494f, 0.000543f, 0.000561f, 0.000680f, 0.000665f, 0.000675f,
+ 0.000679f, 0.000797f, 0.000926f, 0.001122f, 0.001132f, 0.001207f, 0.001375f, 0.001606f, 0.001838f, 0.001963f, 0.002163f, 0.002314f,
+ 0.002480f, 0.002956f, 0.003189f, 0.003489f, 0.003744f, 0.004311f, 0.004749f, 0.005276f, 0.005867f, 0.006962f, 0.008186f, 0.008987f,
+ 0.010498f, 0.012283f, 0.014374f, 0.017075f, 0.020355f, 0.024719f, 0.030640f, 0.037720f, 0.048309f, 0.062134f, 0.082336f, 0.110840f,
+ 0.151978f, 0.212891f, 0.294922f, 0.399170f, 0.515137f, 0.628418f, 0.724609f, 0.799805f, 0.854980f, 0.894043f, 0.968750f, 0.970215f,
+ 0.970703f, 0.971191f, 0.970703f, 0.970703f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000228f, 0.000233f, 0.000436f, 0.000457f,
+ 0.000621f, 0.000546f, 0.000622f, 0.000633f, 0.000576f, 0.000644f, 0.000717f, 0.000909f, 0.000994f, 0.001127f, 0.001179f, 0.001267f,
+ 0.001513f, 0.001628f, 0.001742f, 0.001974f, 0.002111f, 0.002403f, 0.002810f, 0.003139f, 0.003231f, 0.003466f, 0.004021f, 0.004459f,
+ 0.004971f, 0.005581f, 0.006809f, 0.007568f, 0.008759f, 0.010002f, 0.011665f, 0.013847f, 0.016342f, 0.019714f, 0.024368f, 0.030106f,
+ 0.037811f, 0.048706f, 0.063843f, 0.085327f, 0.118042f, 0.164917f, 0.234131f, 0.328125f, 0.443359f, 0.565430f, 0.677246f, 0.767578f,
+ 0.833496f, 0.882812f, 0.965820f, 0.967285f, 0.967773f, 0.968262f, 0.967773f, 0.968262f, 0.000000f, 0.000000f, 0.000000f, 0.000214f,
+ 0.000210f, 0.000296f, 0.000309f, 0.000386f, 0.000462f, 0.000482f, 0.000525f, 0.000572f, 0.000525f, 0.000558f, 0.000689f, 0.000685f,
+ 0.000841f, 0.000934f, 0.001008f, 0.001182f, 0.001271f, 0.001412f, 0.001757f, 0.001787f, 0.001769f, 0.002110f, 0.002321f, 0.002331f,
+ 0.002737f, 0.002951f, 0.003189f, 0.003588f, 0.004253f, 0.004627f, 0.005505f, 0.006119f, 0.006969f, 0.008018f, 0.009583f, 0.010971f,
+ 0.013245f, 0.015915f, 0.019257f, 0.023651f, 0.030014f, 0.038086f, 0.049683f, 0.066406f, 0.091125f, 0.127441f, 0.182617f, 0.262939f,
+ 0.370605f, 0.497070f, 0.623047f, 0.729004f, 0.810547f, 0.867188f, 0.962891f, 0.963867f, 0.964844f, 0.964844f, 0.964355f, 0.964355f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000200f, 0.000215f, 0.000229f, 0.000319f, 0.000330f, 0.000411f, 0.000491f, 0.000527f,
+ 0.000547f, 0.000560f, 0.000634f, 0.000648f, 0.000716f, 0.000778f, 0.000855f, 0.000998f, 0.001182f, 0.001111f, 0.001274f, 0.001625f,
+ 0.001584f, 0.001559f, 0.001864f, 0.002037f, 0.002296f, 0.002438f, 0.002600f, 0.002993f, 0.003290f, 0.003801f, 0.004467f, 0.005085f,
+ 0.005508f, 0.006519f, 0.007645f, 0.008743f, 0.010757f, 0.012558f, 0.014946f, 0.018661f, 0.023422f, 0.029556f, 0.038574f, 0.050964f,
+ 0.069702f, 0.097351f, 0.140015f, 0.205566f, 0.301025f, 0.424561f, 0.559082f, 0.683594f, 0.781250f, 0.852051f, 0.958496f, 0.960449f,
+ 0.960938f, 0.960938f, 0.960938f, 0.960449f, 0.000000f, 0.000000f, 0.000122f, 0.000122f, 0.000122f, 0.000194f, 0.000214f, 0.000251f,
+ 0.000302f, 0.000365f, 0.000370f, 0.000429f, 0.000495f, 0.000521f, 0.000504f, 0.000547f, 0.000632f, 0.000656f, 0.000695f, 0.000795f,
+ 0.000922f, 0.001074f, 0.001125f, 0.001192f, 0.001166f, 0.001303f, 0.001555f, 0.001575f, 0.001763f, 0.001970f, 0.002232f, 0.002560f,
+ 0.002657f, 0.003082f, 0.003559f, 0.003799f, 0.004620f, 0.005241f, 0.006081f, 0.007103f, 0.008385f, 0.009796f, 0.012192f, 0.014702f,
+ 0.018234f, 0.022934f, 0.029556f, 0.039307f, 0.053009f, 0.073547f, 0.106628f, 0.157715f, 0.237793f, 0.351318f, 0.490479f, 0.629883f,
+ 0.746094f, 0.832031f, 0.954590f, 0.956055f, 0.956055f, 0.957031f, 0.956543f, 0.956055f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000121f, 0.000146f, 0.000191f, 0.000200f, 0.000255f, 0.000232f, 0.000252f, 0.000359f, 0.000291f, 0.000342f, 0.000406f, 0.000498f,
+ 0.000520f, 0.000533f, 0.000632f, 0.000605f, 0.000689f, 0.000768f, 0.000908f, 0.001013f, 0.001087f, 0.001030f, 0.001211f, 0.001318f,
+ 0.001497f, 0.001609f, 0.001753f, 0.001957f, 0.002234f, 0.002352f, 0.002663f, 0.003040f, 0.003635f, 0.004082f, 0.004723f, 0.005516f,
+ 0.006367f, 0.007675f, 0.009224f, 0.011360f, 0.013695f, 0.017868f, 0.022598f, 0.029724f, 0.040222f, 0.055542f, 0.080078f, 0.119202f,
+ 0.182617f, 0.281738f, 0.417725f, 0.568848f, 0.705566f, 0.807129f, 0.948730f, 0.951172f, 0.951172f, 0.951172f, 0.951660f, 0.951660f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000203f, 0.000186f, 0.000184f, 0.000321f,
+ 0.000231f, 0.000337f, 0.000359f, 0.000430f, 0.000455f, 0.000531f, 0.000502f, 0.000517f, 0.000728f, 0.000643f, 0.000673f, 0.000816f,
+ 0.000930f, 0.000991f, 0.001028f, 0.001161f, 0.001284f, 0.001369f, 0.001474f, 0.001719f, 0.001781f, 0.001883f, 0.002258f, 0.002518f,
+ 0.002831f, 0.003201f, 0.003744f, 0.004349f, 0.005127f, 0.006130f, 0.007210f, 0.008423f, 0.010696f, 0.013405f, 0.017136f, 0.022522f,
+ 0.030029f, 0.041321f, 0.059631f, 0.089050f, 0.138062f, 0.218994f, 0.343750f, 0.500488f, 0.657227f, 0.780762f, 0.943848f, 0.945312f,
+ 0.945312f, 0.945801f, 0.945801f, 0.946289f, 0.000000f, 0.000000f, 0.000122f, 0.000121f, 0.000121f, 0.000121f, 0.000121f, 0.000120f,
+ 0.000118f, 0.000137f, 0.000139f, 0.000241f, 0.000202f, 0.000304f, 0.000313f, 0.000332f, 0.000357f, 0.000420f, 0.000435f, 0.000463f,
+ 0.000645f, 0.000544f, 0.000700f, 0.000717f, 0.000669f, 0.000834f, 0.000865f, 0.000916f, 0.001109f, 0.001193f, 0.001246f, 0.001300f,
+ 0.001488f, 0.001538f, 0.001806f, 0.001929f, 0.002001f, 0.002462f, 0.002666f, 0.003260f, 0.003904f, 0.004364f, 0.005325f, 0.006306f,
+ 0.008041f, 0.009720f, 0.012718f, 0.016525f, 0.022217f, 0.030579f, 0.043854f, 0.065247f, 0.101929f, 0.166016f, 0.273193f, 0.428223f,
+ 0.600586f, 0.748047f, 0.936523f, 0.938477f, 0.938965f, 0.939453f, 0.938965f, 0.938965f, 0.000000f, 0.000122f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000114f, 0.000102f, 0.000090f, 0.000096f, 0.000131f, 0.000245f, 0.000276f, 0.000257f,
+ 0.000307f, 0.000316f, 0.000322f, 0.000373f, 0.000411f, 0.000440f, 0.000433f, 0.000650f, 0.000578f, 0.000704f, 0.000746f, 0.000723f,
+ 0.000819f, 0.000756f, 0.000758f, 0.000878f, 0.001009f, 0.001270f, 0.001399f, 0.001530f, 0.001798f, 0.001803f, 0.002151f, 0.002317f,
+ 0.002728f, 0.003222f, 0.003782f, 0.004612f, 0.005951f, 0.006985f, 0.009308f, 0.011955f, 0.016052f, 0.022324f, 0.031525f, 0.047272f,
+ 0.073853f, 0.122192f, 0.209717f, 0.352783f, 0.537109f, 0.709473f, 0.928223f, 0.930664f, 0.931152f, 0.930664f, 0.931641f, 0.931152f,
+ 0.000000f, 0.000000f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000120f, 0.000119f, 0.000119f, 0.000111f, 0.000100f, 0.000139f,
+ 0.000082f, 0.000154f, 0.000121f, 0.000216f, 0.000147f, 0.000271f, 0.000288f, 0.000298f, 0.000386f, 0.000463f, 0.000370f, 0.000485f,
+ 0.000555f, 0.000530f, 0.000578f, 0.000574f, 0.000612f, 0.000712f, 0.000776f, 0.000716f, 0.000931f, 0.000831f, 0.000967f, 0.001154f,
+ 0.001176f, 0.001284f, 0.001497f, 0.001884f, 0.002270f, 0.002415f, 0.002947f, 0.003412f, 0.004032f, 0.005066f, 0.006485f, 0.008400f,
+ 0.011215f, 0.015404f, 0.022079f, 0.033264f, 0.052124f, 0.087646f, 0.155029f, 0.279297f, 0.465820f, 0.664062f, 0.918945f, 0.921387f,
+ 0.921875f, 0.922363f, 0.922363f, 0.921875f, 0.000000f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000119f, 0.000119f, 0.000119f,
+ 0.000118f, 0.000118f, 0.000110f, 0.000100f, 0.000091f, 0.000082f, 0.000075f, 0.000095f, 0.000166f, 0.000113f, 0.000163f, 0.000248f,
+ 0.000258f, 0.000277f, 0.000336f, 0.000301f, 0.000445f, 0.000495f, 0.000473f, 0.000505f, 0.000494f, 0.000470f, 0.000584f, 0.000752f,
+ 0.000821f, 0.000814f, 0.000845f, 0.000807f, 0.000932f, 0.000996f, 0.001380f, 0.001481f, 0.001507f, 0.001757f, 0.002146f, 0.002443f,
+ 0.002869f, 0.003546f, 0.004559f, 0.005878f, 0.007561f, 0.010475f, 0.015320f, 0.022675f, 0.036133f, 0.060883f, 0.110352f, 0.211670f,
+ 0.389160f, 0.610352f, 0.908691f, 0.909180f, 0.910645f, 0.912109f, 0.909668f, 0.910156f, 0.000000f, 0.000121f, 0.000120f, 0.000119f,
+ 0.000119f, 0.000118f, 0.000118f, 0.000117f, 0.000117f, 0.000117f, 0.000116f, 0.000110f, 0.000100f, 0.000099f, 0.000083f, 0.000077f,
+ 0.000071f, 0.000081f, 0.000087f, 0.000166f, 0.000177f, 0.000233f, 0.000238f, 0.000273f, 0.000325f, 0.000357f, 0.000292f, 0.000406f,
+ 0.000418f, 0.000440f, 0.000428f, 0.000568f, 0.000459f, 0.000628f, 0.000678f, 0.000688f, 0.000647f, 0.000830f, 0.000925f, 0.001111f,
+ 0.001011f, 0.001420f, 0.001504f, 0.001771f, 0.001997f, 0.002495f, 0.003147f, 0.003944f, 0.005077f, 0.006958f, 0.010040f, 0.015053f,
+ 0.023727f, 0.040680f, 0.075989f, 0.153076f, 0.312012f, 0.547363f, 0.894531f, 0.897461f, 0.897949f, 0.897949f, 0.897949f, 0.898438f,
+ 0.000000f, 0.000000f, 0.000119f, 0.000118f, 0.000118f, 0.000117f, 0.000116f, 0.000116f, 0.000115f, 0.000115f, 0.000114f, 0.000114f,
+ 0.000111f, 0.000101f, 0.000093f, 0.000086f, 0.000079f, 0.000095f, 0.000095f, 0.000090f, 0.000117f, 0.000109f, 0.000158f, 0.000199f,
+ 0.000207f, 0.000223f, 0.000286f, 0.000288f, 0.000267f, 0.000347f, 0.000368f, 0.000450f, 0.000377f, 0.000460f, 0.000504f, 0.000498f,
+ 0.000494f, 0.000616f, 0.000632f, 0.000699f, 0.000755f, 0.000938f, 0.000978f, 0.001222f, 0.001355f, 0.001673f, 0.002016f, 0.002539f,
+ 0.003258f, 0.004410f, 0.006332f, 0.009285f, 0.014847f, 0.025864f, 0.049042f, 0.104736f, 0.236572f, 0.477295f, 0.879395f, 0.881348f,
+ 0.882324f, 0.881836f, 0.882324f, 0.882324f, 0.000000f, 0.000119f, 0.000118f, 0.000116f, 0.000115f, 0.000114f, 0.000114f, 0.000113f,
+ 0.000112f, 0.000112f, 0.000111f, 0.000111f, 0.000110f, 0.000110f, 0.000103f, 0.000095f, 0.000088f, 0.000081f, 0.000076f, 0.000070f,
+ 0.000065f, 0.000100f, 0.000104f, 0.000099f, 0.000120f, 0.000145f, 0.000190f, 0.000204f, 0.000213f, 0.000230f, 0.000241f, 0.000279f,
+ 0.000325f, 0.000322f, 0.000328f, 0.000381f, 0.000351f, 0.000466f, 0.000452f, 0.000516f, 0.000591f, 0.000622f, 0.000733f, 0.000882f,
+ 0.000895f, 0.001092f, 0.001456f, 0.001765f, 0.002069f, 0.002821f, 0.003851f, 0.005558f, 0.008865f, 0.015579f, 0.029999f, 0.066895f,
+ 0.167480f, 0.400391f, 0.860352f, 0.862793f, 0.863281f, 0.864258f, 0.863281f, 0.863770f, 0.000119f, 0.000114f, 0.000113f, 0.000113f,
+ 0.000111f, 0.000110f, 0.000109f, 0.000109f, 0.000108f, 0.000107f, 0.000107f, 0.000107f, 0.000106f, 0.000105f, 0.000106f, 0.000105f,
+ 0.000098f, 0.000090f, 0.000084f, 0.000078f, 0.000073f, 0.000068f, 0.000063f, 0.000063f, 0.000066f, 0.000053f, 0.000080f, 0.000107f,
+ 0.000126f, 0.000150f, 0.000188f, 0.000187f, 0.000206f, 0.000205f, 0.000235f, 0.000242f, 0.000277f, 0.000340f, 0.000323f, 0.000308f,
+ 0.000417f, 0.000411f, 0.000445f, 0.000536f, 0.000622f, 0.000673f, 0.000887f, 0.000985f, 0.001289f, 0.001623f, 0.002337f, 0.003241f,
+ 0.004929f, 0.008560f, 0.016739f, 0.039307f, 0.109619f, 0.317383f, 0.837402f, 0.840332f, 0.841309f, 0.840820f, 0.840820f, 0.841309f,
+ 0.000000f, 0.000106f, 0.000099f, 0.000104f, 0.000102f, 0.000101f, 0.000100f, 0.000101f, 0.000101f, 0.000100f, 0.000099f, 0.000100f,
+ 0.000099f, 0.000099f, 0.000099f, 0.000098f, 0.000098f, 0.000098f, 0.000093f, 0.000086f, 0.000080f, 0.000075f, 0.000070f, 0.000065f,
+ 0.000061f, 0.000057f, 0.000059f, 0.000054f, 0.000061f, 0.000080f, 0.000087f, 0.000101f, 0.000136f, 0.000147f, 0.000163f, 0.000171f,
+ 0.000179f, 0.000205f, 0.000223f, 0.000237f, 0.000281f, 0.000272f, 0.000299f, 0.000364f, 0.000373f, 0.000448f, 0.000507f, 0.000643f,
+ 0.000801f, 0.001000f, 0.001276f, 0.001765f, 0.002712f, 0.004585f, 0.008492f, 0.020462f, 0.063721f, 0.233643f, 0.811035f, 0.813477f,
+ 0.814453f, 0.813965f, 0.813965f, 0.814453f, 0.000000f, 0.000057f, 0.000085f, 0.000085f, 0.000083f, 0.000085f, 0.000087f, 0.000086f,
+ 0.000087f, 0.000087f, 0.000086f, 0.000087f, 0.000087f, 0.000086f, 0.000087f, 0.000087f, 0.000088f, 0.000086f, 0.000088f, 0.000087f,
+ 0.000087f, 0.000081f, 0.000076f, 0.000071f, 0.000067f, 0.000063f, 0.000058f, 0.000055f, 0.000051f, 0.000048f, 0.000046f, 0.000042f,
+ 0.000051f, 0.000063f, 0.000081f, 0.000101f, 0.000122f, 0.000137f, 0.000147f, 0.000143f, 0.000157f, 0.000183f, 0.000205f, 0.000188f,
+ 0.000196f, 0.000249f, 0.000310f, 0.000329f, 0.000413f, 0.000534f, 0.000679f, 0.000944f, 0.001365f, 0.002199f, 0.004150f, 0.009369f,
+ 0.031677f, 0.153564f, 0.779297f, 0.781250f, 0.782227f, 0.782715f, 0.781738f, 0.781250f, 0.000000f, 0.000000f, 0.000000f, 0.000009f,
+ 0.000030f, 0.000048f, 0.000051f, 0.000054f, 0.000055f, 0.000059f, 0.000060f, 0.000065f, 0.000065f, 0.000066f, 0.000068f, 0.000068f,
+ 0.000070f, 0.000070f, 0.000071f, 0.000071f, 0.000072f, 0.000073f, 0.000073f, 0.000073f, 0.000071f, 0.000066f, 0.000062f, 0.000058f,
+ 0.000055f, 0.000051f, 0.000048f, 0.000045f, 0.000042f, 0.000039f, 0.000044f, 0.000036f, 0.000046f, 0.000056f, 0.000067f, 0.000085f,
+ 0.000099f, 0.000108f, 0.000107f, 0.000113f, 0.000139f, 0.000144f, 0.000165f, 0.000169f, 0.000196f, 0.000266f, 0.000311f, 0.000426f,
+ 0.000598f, 0.000948f, 0.001744f, 0.003975f, 0.012856f, 0.084351f, 0.739746f, 0.743164f, 0.743652f, 0.743652f, 0.743652f, 0.743164f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000012f, 0.000012f, 0.000020f,
+ 0.000028f, 0.000030f, 0.000033f, 0.000034f, 0.000041f, 0.000041f, 0.000045f, 0.000047f, 0.000048f, 0.000049f, 0.000051f, 0.000052f,
+ 0.000054f, 0.000054f, 0.000056f, 0.000057f, 0.000056f, 0.000052f, 0.000049f, 0.000046f, 0.000043f, 0.000041f, 0.000038f, 0.000035f,
+ 0.000033f, 0.000031f, 0.000029f, 0.000029f, 0.000036f, 0.000055f, 0.000048f, 0.000067f, 0.000067f, 0.000073f, 0.000075f, 0.000097f,
+ 0.000085f, 0.000111f, 0.000137f, 0.000191f, 0.000233f, 0.000371f, 0.000609f, 0.001319f, 0.004341f, 0.033844f, 0.696289f, 0.698730f,
+ 0.699219f, 0.698242f, 0.698730f, 0.698730f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000003f, 0.000007f,
+ 0.000009f, 0.000012f, 0.000015f, 0.000020f, 0.000022f, 0.000023f, 0.000026f, 0.000029f, 0.000030f, 0.000032f, 0.000033f, 0.000035f,
+ 0.000037f, 0.000037f, 0.000036f, 0.000034f, 0.000032f, 0.000030f, 0.000028f, 0.000026f, 0.000024f, 0.000022f, 0.000021f, 0.000019f,
+ 0.000024f, 0.000024f, 0.000029f, 0.000037f, 0.000043f, 0.000046f, 0.000059f, 0.000058f, 0.000075f, 0.000095f, 0.000160f, 0.000306f,
+ 0.001006f, 0.008865f, 0.643066f, 0.647461f, 0.647949f, 0.647461f, 0.647949f, 0.648438f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000003f, 0.000005f, 0.000007f, 0.000010f, 0.000012f, 0.000013f, 0.000015f, 0.000017f,
+ 0.000019f, 0.000020f, 0.000018f, 0.000017f, 0.000015f, 0.000014f, 0.000013f, 0.000012f, 0.000010f, 0.000012f, 0.000014f, 0.000018f,
+ 0.000018f, 0.000025f, 0.000028f, 0.000045f, 0.000110f, 0.001030f, 0.586914f, 0.589844f, 0.590820f, 0.591309f, 0.591309f, 0.590820f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000002f, 0.000004f, 0.000005f, 0.000004f, 0.000004f, 0.000003f, 0.000003f, 0.000004f, 0.000009f, 0.527344f, 0.529785f,
+ 0.529785f, 0.530273f, 0.530762f, 0.530762f,
+ },
+ {
+ 0.135132f, 0.377441f, 0.544434f, 0.653320f, 0.724609f, 0.773926f, 0.811035f, 0.838867f, 0.860840f, 0.876465f, 0.891113f, 0.902832f,
+ 0.912109f, 0.920898f, 0.928223f, 0.934082f, 0.938965f, 0.943848f, 0.948242f, 0.952637f, 0.955566f, 0.958984f, 0.961914f, 0.964844f,
+ 0.966797f, 0.969238f, 0.971191f, 0.973145f, 0.975098f, 0.976562f, 0.978027f, 0.979492f, 0.980469f, 0.982422f, 0.983398f, 0.984863f,
+ 0.985840f, 0.986328f, 0.987793f, 0.988770f, 0.989746f, 0.989746f, 0.990234f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994141f,
+ 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999512f, 0.999512f, 0.999512f,
+ 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.044891f, 0.163330f, 0.306885f, 0.444336f, 0.559570f, 0.645020f, 0.710938f, 0.760742f,
+ 0.797852f, 0.827148f, 0.850098f, 0.868652f, 0.883789f, 0.895996f, 0.907227f, 0.916016f, 0.923340f, 0.930176f, 0.936523f, 0.941406f,
+ 0.946777f, 0.950684f, 0.954102f, 0.957031f, 0.960938f, 0.963379f, 0.965820f, 0.968262f, 0.970703f, 0.972168f, 0.974609f, 0.976562f,
+ 0.977539f, 0.979492f, 0.980469f, 0.981934f, 0.982910f, 0.984375f, 0.985840f, 0.986816f, 0.987793f, 0.988770f, 0.988770f, 0.990234f,
+ 0.991211f, 0.991699f, 0.992676f, 0.993164f, 0.993164f, 0.994141f, 0.995605f, 0.995605f, 0.996094f, 0.996582f, 0.997070f, 0.997559f,
+ 0.998047f, 0.998535f, 0.999512f, 0.999512f, 0.999512f, 0.999023f, 0.999023f, 0.999023f, 0.020325f, 0.077820f, 0.158936f, 0.260498f,
+ 0.372314f, 0.479736f, 0.572754f, 0.648438f, 0.707520f, 0.754883f, 0.791016f, 0.820312f, 0.843750f, 0.862793f, 0.878906f, 0.891602f,
+ 0.903320f, 0.912598f, 0.920898f, 0.928223f, 0.933594f, 0.939941f, 0.944824f, 0.949219f, 0.952637f, 0.956543f, 0.959961f, 0.962402f,
+ 0.965332f, 0.967773f, 0.970215f, 0.971680f, 0.974121f, 0.976074f, 0.977539f, 0.979004f, 0.980957f, 0.981445f, 0.983398f, 0.984375f,
+ 0.985352f, 0.986328f, 0.987793f, 0.988770f, 0.989746f, 0.990234f, 0.991211f, 0.992188f, 0.992676f, 0.993164f, 0.994141f, 0.994629f,
+ 0.995605f, 0.996094f, 0.996582f, 0.996582f, 0.997559f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.999023f, 0.998535f, 0.998535f,
+ 0.012032f, 0.042908f, 0.088196f, 0.149292f, 0.228027f, 0.319824f, 0.415527f, 0.506348f, 0.586914f, 0.653809f, 0.709473f, 0.752441f,
+ 0.787598f, 0.817383f, 0.840820f, 0.860352f, 0.876465f, 0.889648f, 0.900879f, 0.910156f, 0.918945f, 0.926270f, 0.933105f, 0.938965f,
+ 0.944336f, 0.948730f, 0.952637f, 0.956055f, 0.958984f, 0.962402f, 0.965332f, 0.967773f, 0.970215f, 0.972656f, 0.974609f, 0.976562f,
+ 0.978027f, 0.979492f, 0.980957f, 0.982422f, 0.983887f, 0.984375f, 0.985352f, 0.986816f, 0.987793f, 0.988770f, 0.989746f, 0.990234f,
+ 0.991211f, 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.996094f, 0.996094f, 0.996582f, 0.997559f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.007637f, 0.026825f, 0.053436f, 0.090759f, 0.140137f, 0.203125f, 0.279053f, 0.363281f,
+ 0.449463f, 0.529785f, 0.601562f, 0.663574f, 0.713379f, 0.756348f, 0.789551f, 0.816895f, 0.840332f, 0.858887f, 0.875488f, 0.887695f,
+ 0.900391f, 0.909668f, 0.918945f, 0.926270f, 0.932617f, 0.938477f, 0.943848f, 0.948242f, 0.952148f, 0.955566f, 0.959473f, 0.962402f,
+ 0.965332f, 0.967773f, 0.970215f, 0.972168f, 0.974121f, 0.976562f, 0.978516f, 0.979492f, 0.980957f, 0.981934f, 0.984375f, 0.985352f,
+ 0.985840f, 0.987793f, 0.988281f, 0.989258f, 0.990723f, 0.991211f, 0.991699f, 0.992676f, 0.993652f, 0.994141f, 0.994629f, 0.995605f,
+ 0.996094f, 0.997070f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998535f, 0.998047f, 0.004784f, 0.018082f, 0.035400f, 0.058868f,
+ 0.089783f, 0.130981f, 0.183716f, 0.248047f, 0.321289f, 0.400391f, 0.478760f, 0.552734f, 0.617188f, 0.673828f, 0.720703f, 0.759766f,
+ 0.792480f, 0.818359f, 0.840820f, 0.859863f, 0.875000f, 0.888184f, 0.899902f, 0.910645f, 0.918945f, 0.926270f, 0.931641f, 0.938965f,
+ 0.943848f, 0.948242f, 0.952148f, 0.957031f, 0.959473f, 0.962891f, 0.965332f, 0.968262f, 0.970215f, 0.972656f, 0.975098f, 0.977051f,
+ 0.978516f, 0.979980f, 0.981445f, 0.982910f, 0.984863f, 0.985352f, 0.986328f, 0.987305f, 0.988770f, 0.989746f, 0.990723f, 0.991699f,
+ 0.992676f, 0.993164f, 0.994141f, 0.994629f, 0.995605f, 0.996094f, 0.998047f, 0.998535f, 0.998047f, 0.998047f, 0.998047f, 0.998047f,
+ 0.004044f, 0.012550f, 0.024628f, 0.040466f, 0.060760f, 0.087708f, 0.122742f, 0.167236f, 0.222534f, 0.287109f, 0.358643f, 0.432617f,
+ 0.506348f, 0.573242f, 0.632812f, 0.685059f, 0.728516f, 0.766602f, 0.797363f, 0.822266f, 0.843750f, 0.861328f, 0.877441f, 0.890625f,
+ 0.901367f, 0.910645f, 0.919434f, 0.926758f, 0.933105f, 0.940430f, 0.944824f, 0.948730f, 0.953125f, 0.957520f, 0.960449f, 0.963867f,
+ 0.966309f, 0.969238f, 0.970703f, 0.973633f, 0.976074f, 0.977539f, 0.979004f, 0.980469f, 0.982422f, 0.983398f, 0.984863f, 0.986816f,
+ 0.986816f, 0.988281f, 0.989746f, 0.990723f, 0.991211f, 0.992188f, 0.993164f, 0.994141f, 0.994629f, 0.995117f, 0.998047f, 0.998047f,
+ 0.998047f, 0.998047f, 0.998047f, 0.998047f, 0.002975f, 0.009315f, 0.017868f, 0.029129f, 0.043243f, 0.062012f, 0.084961f, 0.115540f,
+ 0.154419f, 0.201660f, 0.257812f, 0.322754f, 0.391846f, 0.463135f, 0.530762f, 0.594727f, 0.650391f, 0.698730f, 0.739258f, 0.773926f,
+ 0.803711f, 0.826660f, 0.847656f, 0.865723f, 0.879883f, 0.892090f, 0.903809f, 0.913086f, 0.921387f, 0.928223f, 0.935059f, 0.940918f,
+ 0.945801f, 0.950684f, 0.954102f, 0.958008f, 0.961426f, 0.964844f, 0.967285f, 0.970215f, 0.972168f, 0.974609f, 0.976074f, 0.978027f,
+ 0.979980f, 0.981934f, 0.983398f, 0.984375f, 0.985352f, 0.987305f, 0.988281f, 0.989258f, 0.990234f, 0.991211f, 0.992188f, 0.993164f,
+ 0.993652f, 0.994629f, 0.997559f, 0.998047f, 0.998047f, 0.997559f, 0.997559f, 0.997559f, 0.002329f, 0.007256f, 0.013611f, 0.021790f,
+ 0.032043f, 0.044617f, 0.061554f, 0.082336f, 0.108765f, 0.142578f, 0.184448f, 0.234375f, 0.292725f, 0.357422f, 0.424805f, 0.493164f,
+ 0.556641f, 0.615723f, 0.666504f, 0.711914f, 0.750977f, 0.782715f, 0.809570f, 0.832520f, 0.853516f, 0.868652f, 0.882812f, 0.895508f,
+ 0.905762f, 0.916016f, 0.923340f, 0.931152f, 0.936523f, 0.942383f, 0.947266f, 0.951172f, 0.956055f, 0.958984f, 0.962402f, 0.965820f,
+ 0.968750f, 0.971191f, 0.973633f, 0.975586f, 0.977539f, 0.979980f, 0.980957f, 0.982422f, 0.983887f, 0.985352f, 0.985840f, 0.988281f,
+ 0.989746f, 0.990234f, 0.991211f, 0.991699f, 0.993164f, 0.993652f, 0.997070f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f,
+ 0.001871f, 0.006084f, 0.010963f, 0.016953f, 0.024277f, 0.033722f, 0.046234f, 0.060669f, 0.079224f, 0.103638f, 0.132812f, 0.169678f,
+ 0.214478f, 0.267090f, 0.326172f, 0.390137f, 0.456543f, 0.519531f, 0.581543f, 0.636230f, 0.685547f, 0.726562f, 0.762207f, 0.792969f,
+ 0.818359f, 0.839844f, 0.858398f, 0.874023f, 0.887695f, 0.898926f, 0.909668f, 0.918945f, 0.926270f, 0.933105f, 0.938965f, 0.944336f,
+ 0.949219f, 0.953613f, 0.958008f, 0.961426f, 0.964844f, 0.967773f, 0.969727f, 0.972168f, 0.974609f, 0.976074f, 0.979004f, 0.979980f,
+ 0.981934f, 0.983887f, 0.985352f, 0.986328f, 0.987793f, 0.989746f, 0.989746f, 0.990723f, 0.991211f, 0.992676f, 0.996582f, 0.997070f,
+ 0.997559f, 0.997070f, 0.997070f, 0.997070f, 0.001322f, 0.004795f, 0.008530f, 0.013504f, 0.018921f, 0.026154f, 0.035065f, 0.045807f,
+ 0.059662f, 0.076416f, 0.098267f, 0.124512f, 0.157715f, 0.197388f, 0.244873f, 0.299805f, 0.359619f, 0.423096f, 0.487549f, 0.549316f,
+ 0.605957f, 0.657715f, 0.703125f, 0.741211f, 0.774902f, 0.802734f, 0.827148f, 0.847656f, 0.865234f, 0.879883f, 0.893066f, 0.903320f,
+ 0.913086f, 0.920898f, 0.929199f, 0.935547f, 0.941406f, 0.947266f, 0.951172f, 0.956055f, 0.959473f, 0.962891f, 0.965332f, 0.969238f,
+ 0.971191f, 0.974121f, 0.976562f, 0.977539f, 0.979980f, 0.981445f, 0.982910f, 0.984863f, 0.986328f, 0.988281f, 0.988281f, 0.989746f,
+ 0.990723f, 0.991699f, 0.996582f, 0.996582f, 0.997070f, 0.997070f, 0.997070f, 0.996582f, 0.001077f, 0.003971f, 0.006985f, 0.010750f,
+ 0.015579f, 0.020920f, 0.027420f, 0.035522f, 0.045776f, 0.058228f, 0.074097f, 0.093140f, 0.117310f, 0.146851f, 0.182495f, 0.225952f,
+ 0.276611f, 0.332764f, 0.394287f, 0.456543f, 0.518555f, 0.577637f, 0.630371f, 0.679199f, 0.720703f, 0.756836f, 0.787598f, 0.813477f,
+ 0.836426f, 0.855469f, 0.872070f, 0.885742f, 0.897949f, 0.908203f, 0.917480f, 0.925293f, 0.933105f, 0.939453f, 0.944336f, 0.949219f,
+ 0.954590f, 0.957520f, 0.961426f, 0.964844f, 0.968262f, 0.970703f, 0.974121f, 0.975586f, 0.978027f, 0.979492f, 0.981445f, 0.983398f,
+ 0.984863f, 0.986328f, 0.987793f, 0.988770f, 0.989746f, 0.991211f, 0.996094f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.996582f,
+ 0.000954f, 0.003330f, 0.005733f, 0.008904f, 0.012505f, 0.016617f, 0.022446f, 0.028351f, 0.036041f, 0.045807f, 0.056854f, 0.071350f,
+ 0.088867f, 0.110596f, 0.137451f, 0.170654f, 0.209717f, 0.256592f, 0.309326f, 0.366943f, 0.427979f, 0.489502f, 0.549316f, 0.604980f,
+ 0.655762f, 0.700195f, 0.738770f, 0.772461f, 0.801270f, 0.825195f, 0.845703f, 0.864258f, 0.879395f, 0.893066f, 0.903809f, 0.914062f,
+ 0.922363f, 0.929688f, 0.936523f, 0.942871f, 0.947266f, 0.952148f, 0.956055f, 0.960449f, 0.963867f, 0.966797f, 0.969727f, 0.972656f,
+ 0.975586f, 0.976562f, 0.979004f, 0.981445f, 0.982910f, 0.984375f, 0.985840f, 0.986816f, 0.988770f, 0.989746f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996094f, 0.996094f, 0.996094f, 0.000949f, 0.002804f, 0.004730f, 0.007236f, 0.010384f, 0.014160f, 0.018478f, 0.023102f,
+ 0.028992f, 0.036346f, 0.044647f, 0.055542f, 0.068481f, 0.085144f, 0.105286f, 0.130005f, 0.159668f, 0.195557f, 0.238647f, 0.287842f,
+ 0.343018f, 0.402588f, 0.463135f, 0.522949f, 0.580566f, 0.632812f, 0.680664f, 0.721680f, 0.757812f, 0.788574f, 0.814453f, 0.836914f,
+ 0.856934f, 0.872070f, 0.887207f, 0.899414f, 0.909668f, 0.918945f, 0.926758f, 0.933594f, 0.940430f, 0.946289f, 0.950684f, 0.954590f,
+ 0.959473f, 0.963379f, 0.966797f, 0.969238f, 0.972168f, 0.975098f, 0.977051f, 0.979492f, 0.980957f, 0.982910f, 0.984375f, 0.986328f,
+ 0.987793f, 0.988770f, 0.995117f, 0.996094f, 0.995605f, 0.996094f, 0.996094f, 0.995605f, 0.000828f, 0.002361f, 0.004116f, 0.006119f,
+ 0.008797f, 0.011391f, 0.014854f, 0.018890f, 0.023666f, 0.029083f, 0.036011f, 0.044434f, 0.053986f, 0.066589f, 0.081543f, 0.100159f,
+ 0.122314f, 0.149536f, 0.183350f, 0.222900f, 0.269043f, 0.321533f, 0.378418f, 0.438477f, 0.499023f, 0.556641f, 0.611328f, 0.661133f,
+ 0.703613f, 0.742188f, 0.775391f, 0.804199f, 0.828613f, 0.849121f, 0.866211f, 0.881348f, 0.894043f, 0.905762f, 0.916016f, 0.924316f,
+ 0.931641f, 0.938477f, 0.944336f, 0.949707f, 0.954590f, 0.958496f, 0.962402f, 0.966309f, 0.969238f, 0.972168f, 0.974121f, 0.977051f,
+ 0.979004f, 0.980957f, 0.982910f, 0.984863f, 0.985840f, 0.987793f, 0.995117f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.995605f,
+ 0.000606f, 0.001948f, 0.003483f, 0.005394f, 0.007290f, 0.009735f, 0.012352f, 0.015747f, 0.019485f, 0.023788f, 0.029358f, 0.035706f,
+ 0.043732f, 0.053162f, 0.064331f, 0.077942f, 0.094971f, 0.116089f, 0.140991f, 0.172485f, 0.209473f, 0.252686f, 0.302002f, 0.356934f,
+ 0.415283f, 0.475830f, 0.534180f, 0.589844f, 0.641602f, 0.687500f, 0.728516f, 0.763184f, 0.792969f, 0.819336f, 0.841309f, 0.860840f,
+ 0.876953f, 0.890625f, 0.902344f, 0.913086f, 0.921875f, 0.930176f, 0.937012f, 0.943359f, 0.948242f, 0.954102f, 0.958008f, 0.961914f,
+ 0.965820f, 0.969238f, 0.971680f, 0.974609f, 0.977051f, 0.979004f, 0.981445f, 0.983398f, 0.984863f, 0.986816f, 0.994141f, 0.994629f,
+ 0.995117f, 0.995117f, 0.995117f, 0.994629f, 0.000672f, 0.001569f, 0.002895f, 0.004528f, 0.006180f, 0.008324f, 0.010864f, 0.013161f,
+ 0.016357f, 0.020096f, 0.024216f, 0.029327f, 0.035583f, 0.042664f, 0.051453f, 0.062073f, 0.075012f, 0.091125f, 0.110291f, 0.134155f,
+ 0.162476f, 0.197266f, 0.238037f, 0.285156f, 0.337646f, 0.395020f, 0.454590f, 0.513672f, 0.570312f, 0.624023f, 0.672363f, 0.714844f,
+ 0.750977f, 0.783691f, 0.811035f, 0.834473f, 0.854004f, 0.872070f, 0.886230f, 0.899414f, 0.911133f, 0.918945f, 0.928223f, 0.936035f,
+ 0.942871f, 0.948242f, 0.953613f, 0.957031f, 0.961426f, 0.965820f, 0.968750f, 0.972168f, 0.974121f, 0.976562f, 0.979492f, 0.981445f,
+ 0.983398f, 0.985352f, 0.994141f, 0.994629f, 0.995117f, 0.995117f, 0.995117f, 0.994629f, 0.000413f, 0.001430f, 0.002577f, 0.004269f,
+ 0.005703f, 0.007137f, 0.008888f, 0.011124f, 0.013885f, 0.016891f, 0.020355f, 0.024384f, 0.029221f, 0.035217f, 0.041748f, 0.049988f,
+ 0.060059f, 0.072083f, 0.086914f, 0.105286f, 0.126953f, 0.154175f, 0.186523f, 0.224731f, 0.269287f, 0.320557f, 0.375732f, 0.434570f,
+ 0.493896f, 0.552246f, 0.606934f, 0.655762f, 0.701660f, 0.740723f, 0.774902f, 0.803711f, 0.827637f, 0.848633f, 0.867188f, 0.882812f,
+ 0.895996f, 0.908203f, 0.917969f, 0.926758f, 0.934570f, 0.941895f, 0.947266f, 0.952637f, 0.957520f, 0.960938f, 0.965820f, 0.968750f,
+ 0.971680f, 0.974609f, 0.977051f, 0.979980f, 0.981934f, 0.983887f, 0.993652f, 0.994629f, 0.994141f, 0.994141f, 0.994141f, 0.994141f,
+ 0.000240f, 0.001406f, 0.002373f, 0.003283f, 0.004620f, 0.006264f, 0.007744f, 0.009552f, 0.011711f, 0.014069f, 0.017273f, 0.020584f,
+ 0.024429f, 0.028946f, 0.034393f, 0.041046f, 0.048798f, 0.058289f, 0.070312f, 0.083618f, 0.100403f, 0.121338f, 0.146118f, 0.177002f,
+ 0.213257f, 0.255371f, 0.304443f, 0.358887f, 0.416504f, 0.476562f, 0.534668f, 0.590332f, 0.642090f, 0.688965f, 0.729492f, 0.766113f,
+ 0.796387f, 0.822754f, 0.844727f, 0.862305f, 0.880371f, 0.894043f, 0.905762f, 0.916992f, 0.926270f, 0.934082f, 0.940918f, 0.946777f,
+ 0.953125f, 0.956543f, 0.961426f, 0.964844f, 0.969238f, 0.972656f, 0.974609f, 0.977539f, 0.979980f, 0.982422f, 0.992676f, 0.994141f,
+ 0.993652f, 0.993652f, 0.993652f, 0.993652f, 0.000242f, 0.001257f, 0.001991f, 0.003138f, 0.004299f, 0.005302f, 0.006584f, 0.008308f,
+ 0.010048f, 0.012283f, 0.014526f, 0.017578f, 0.020340f, 0.023972f, 0.028671f, 0.033661f, 0.040161f, 0.047821f, 0.056213f, 0.067261f,
+ 0.080444f, 0.096191f, 0.115784f, 0.139771f, 0.168457f, 0.203125f, 0.243286f, 0.290527f, 0.343506f, 0.400879f, 0.459473f, 0.519043f,
+ 0.576172f, 0.629395f, 0.678223f, 0.721191f, 0.757324f, 0.789062f, 0.816895f, 0.839844f, 0.859863f, 0.877930f, 0.892578f, 0.904297f,
+ 0.915527f, 0.925293f, 0.933105f, 0.940430f, 0.946777f, 0.952148f, 0.957031f, 0.961914f, 0.965820f, 0.969238f, 0.973145f, 0.975586f,
+ 0.978516f, 0.980469f, 0.992188f, 0.993652f, 0.993164f, 0.993164f, 0.993652f, 0.993164f, 0.000434f, 0.001172f, 0.001865f, 0.002825f,
+ 0.003633f, 0.004757f, 0.005722f, 0.007175f, 0.009010f, 0.010651f, 0.012520f, 0.014412f, 0.017532f, 0.020599f, 0.024139f, 0.028488f,
+ 0.033356f, 0.039001f, 0.046295f, 0.054749f, 0.064758f, 0.077209f, 0.092834f, 0.111084f, 0.134033f, 0.160767f, 0.193604f, 0.233032f,
+ 0.278320f, 0.329590f, 0.386230f, 0.445068f, 0.504395f, 0.563477f, 0.617188f, 0.666504f, 0.711426f, 0.750000f, 0.783691f, 0.812500f,
+ 0.836426f, 0.857422f, 0.875488f, 0.891113f, 0.903809f, 0.915039f, 0.924805f, 0.933105f, 0.940430f, 0.947266f, 0.953125f, 0.958496f,
+ 0.962402f, 0.966309f, 0.969727f, 0.973145f, 0.976562f, 0.978516f, 0.991699f, 0.992188f, 0.992676f, 0.993164f, 0.993164f, 0.992676f,
+ 0.000358f, 0.000835f, 0.001738f, 0.002270f, 0.002996f, 0.004078f, 0.005157f, 0.006416f, 0.007904f, 0.009331f, 0.010826f, 0.012245f,
+ 0.014938f, 0.017303f, 0.020233f, 0.023926f, 0.027954f, 0.032715f, 0.038147f, 0.045166f, 0.053070f, 0.062561f, 0.074768f, 0.089661f,
+ 0.106689f, 0.128052f, 0.154175f, 0.185547f, 0.223022f, 0.266846f, 0.317383f, 0.373047f, 0.431152f, 0.491943f, 0.550293f, 0.606445f,
+ 0.658203f, 0.704102f, 0.744141f, 0.779297f, 0.809082f, 0.833984f, 0.855957f, 0.875000f, 0.889648f, 0.903320f, 0.915039f, 0.924805f,
+ 0.933594f, 0.940918f, 0.947754f, 0.954102f, 0.958984f, 0.962402f, 0.966797f, 0.970703f, 0.974121f, 0.977539f, 0.990723f, 0.992188f,
+ 0.992676f, 0.992676f, 0.992188f, 0.992676f, 0.000428f, 0.000789f, 0.001460f, 0.002172f, 0.002695f, 0.003561f, 0.004608f, 0.005848f,
+ 0.006886f, 0.007736f, 0.009560f, 0.011078f, 0.012817f, 0.015015f, 0.017563f, 0.020157f, 0.023666f, 0.027145f, 0.031891f, 0.037384f,
+ 0.044189f, 0.051788f, 0.061188f, 0.072327f, 0.085999f, 0.102966f, 0.123413f, 0.148071f, 0.178101f, 0.214478f, 0.256836f, 0.306396f,
+ 0.360840f, 0.419678f, 0.479736f, 0.540527f, 0.597656f, 0.649902f, 0.697754f, 0.738770f, 0.775391f, 0.805664f, 0.831543f, 0.854004f,
+ 0.873535f, 0.889160f, 0.902832f, 0.915039f, 0.925293f, 0.934082f, 0.941895f, 0.948730f, 0.954102f, 0.959961f, 0.963867f, 0.968262f,
+ 0.971680f, 0.975586f, 0.990723f, 0.991699f, 0.991699f, 0.991699f, 0.991699f, 0.991211f, 0.000237f, 0.000782f, 0.001245f, 0.001923f,
+ 0.002417f, 0.003225f, 0.004101f, 0.005062f, 0.005920f, 0.007030f, 0.008102f, 0.009743f, 0.011009f, 0.013054f, 0.015190f, 0.017380f,
+ 0.020126f, 0.023346f, 0.027161f, 0.031464f, 0.036316f, 0.042664f, 0.050110f, 0.058807f, 0.069946f, 0.083191f, 0.099121f, 0.118835f,
+ 0.142822f, 0.171997f, 0.206665f, 0.248413f, 0.296143f, 0.350586f, 0.408936f, 0.469727f, 0.530762f, 0.589844f, 0.643555f, 0.691895f,
+ 0.734375f, 0.772461f, 0.803223f, 0.830566f, 0.854492f, 0.873047f, 0.889648f, 0.903809f, 0.916016f, 0.926270f, 0.935059f, 0.943359f,
+ 0.949219f, 0.955566f, 0.960938f, 0.965332f, 0.969727f, 0.973145f, 0.989746f, 0.990723f, 0.990723f, 0.990723f, 0.991211f, 0.990723f,
+ 0.000243f, 0.000793f, 0.001210f, 0.001616f, 0.002260f, 0.003069f, 0.003649f, 0.004444f, 0.005322f, 0.006088f, 0.006954f, 0.008278f,
+ 0.009766f, 0.011139f, 0.012970f, 0.014908f, 0.016968f, 0.019897f, 0.023193f, 0.026962f, 0.030792f, 0.035522f, 0.041931f, 0.048920f,
+ 0.057404f, 0.067993f, 0.080383f, 0.095825f, 0.114929f, 0.137695f, 0.165771f, 0.199585f, 0.241089f, 0.287842f, 0.341553f, 0.400391f,
+ 0.462402f, 0.523438f, 0.583008f, 0.638184f, 0.687988f, 0.732422f, 0.770020f, 0.802246f, 0.830566f, 0.854004f, 0.873047f, 0.891113f,
+ 0.904785f, 0.916992f, 0.926758f, 0.936523f, 0.943848f, 0.951172f, 0.956543f, 0.961914f, 0.966797f, 0.971191f, 0.989258f, 0.990234f,
+ 0.990234f, 0.990234f, 0.990234f, 0.989746f, 0.000000f, 0.000484f, 0.000973f, 0.001453f, 0.001999f, 0.002689f, 0.003359f, 0.003864f,
+ 0.004726f, 0.005444f, 0.006516f, 0.007404f, 0.008461f, 0.009720f, 0.011261f, 0.012985f, 0.014908f, 0.017120f, 0.019699f, 0.022614f,
+ 0.026093f, 0.030228f, 0.034668f, 0.040619f, 0.047699f, 0.055756f, 0.066284f, 0.078308f, 0.092834f, 0.111328f, 0.133423f, 0.160889f,
+ 0.194214f, 0.233765f, 0.281006f, 0.334473f, 0.392822f, 0.455078f, 0.517090f, 0.578125f, 0.634766f, 0.686035f, 0.730957f, 0.768555f,
+ 0.803223f, 0.831055f, 0.854492f, 0.875488f, 0.892090f, 0.906250f, 0.918457f, 0.929688f, 0.937988f, 0.945801f, 0.952148f, 0.958496f,
+ 0.963867f, 0.968750f, 0.988281f, 0.989258f, 0.989746f, 0.989258f, 0.989746f, 0.989258f, 0.000241f, 0.000699f, 0.000835f, 0.001354f,
+ 0.002066f, 0.002405f, 0.003073f, 0.003466f, 0.003847f, 0.004868f, 0.005798f, 0.006325f, 0.007446f, 0.008553f, 0.009789f, 0.011375f,
+ 0.013031f, 0.014702f, 0.016937f, 0.019455f, 0.022171f, 0.025467f, 0.029541f, 0.034271f, 0.039734f, 0.046295f, 0.054291f, 0.063904f,
+ 0.075745f, 0.089966f, 0.107727f, 0.129395f, 0.156250f, 0.188965f, 0.228394f, 0.274658f, 0.327637f, 0.386963f, 0.449219f, 0.512695f,
+ 0.574707f, 0.632324f, 0.684570f, 0.730469f, 0.770508f, 0.804688f, 0.832520f, 0.857422f, 0.876953f, 0.893066f, 0.908691f, 0.920410f,
+ 0.931152f, 0.940430f, 0.947754f, 0.954590f, 0.960938f, 0.965820f, 0.986816f, 0.988770f, 0.988770f, 0.988770f, 0.988770f, 0.988770f,
+ 0.000122f, 0.000480f, 0.000793f, 0.001184f, 0.001847f, 0.002220f, 0.002459f, 0.003109f, 0.003740f, 0.004234f, 0.005127f, 0.005730f,
+ 0.006557f, 0.007458f, 0.008469f, 0.009911f, 0.011162f, 0.012848f, 0.014519f, 0.016693f, 0.019135f, 0.021820f, 0.025024f, 0.028931f,
+ 0.033508f, 0.038757f, 0.045135f, 0.052856f, 0.062042f, 0.073547f, 0.087646f, 0.104736f, 0.126099f, 0.152588f, 0.184570f, 0.223511f,
+ 0.269775f, 0.323242f, 0.382324f, 0.445801f, 0.510254f, 0.573242f, 0.631348f, 0.685059f, 0.731934f, 0.772461f, 0.806641f, 0.834961f,
+ 0.859375f, 0.879883f, 0.897461f, 0.911133f, 0.923828f, 0.933594f, 0.942383f, 0.950195f, 0.956055f, 0.962402f, 0.985840f, 0.987305f,
+ 0.987793f, 0.987793f, 0.988281f, 0.987793f, 0.000244f, 0.000471f, 0.000666f, 0.001267f, 0.001592f, 0.001838f, 0.002251f, 0.002855f,
+ 0.003225f, 0.003828f, 0.004372f, 0.005112f, 0.005695f, 0.006340f, 0.007534f, 0.008797f, 0.009895f, 0.011215f, 0.012604f, 0.014503f,
+ 0.016602f, 0.018738f, 0.021408f, 0.024567f, 0.028305f, 0.032654f, 0.037872f, 0.043732f, 0.051239f, 0.060669f, 0.071716f, 0.085510f,
+ 0.102356f, 0.123230f, 0.149170f, 0.180664f, 0.219849f, 0.265869f, 0.319092f, 0.379150f, 0.443604f, 0.508789f, 0.572754f, 0.633301f,
+ 0.686523f, 0.734863f, 0.775391f, 0.809570f, 0.838379f, 0.862305f, 0.883301f, 0.900391f, 0.914551f, 0.926270f, 0.937012f, 0.944824f,
+ 0.953125f, 0.959473f, 0.985352f, 0.986816f, 0.986816f, 0.986816f, 0.986816f, 0.986816f, 0.000242f, 0.000346f, 0.000827f, 0.001065f,
+ 0.001428f, 0.001572f, 0.001984f, 0.002367f, 0.002851f, 0.003277f, 0.003786f, 0.004501f, 0.005253f, 0.005955f, 0.006573f, 0.007736f,
+ 0.008659f, 0.009880f, 0.011177f, 0.012459f, 0.014153f, 0.016403f, 0.018173f, 0.020859f, 0.024017f, 0.027496f, 0.031708f, 0.036682f,
+ 0.042877f, 0.050446f, 0.059174f, 0.070068f, 0.083374f, 0.100159f, 0.120728f, 0.145874f, 0.177612f, 0.216187f, 0.262695f, 0.316650f,
+ 0.377686f, 0.443115f, 0.509766f, 0.575195f, 0.635742f, 0.691406f, 0.738281f, 0.779785f, 0.813965f, 0.843750f, 0.866699f, 0.887207f,
+ 0.904297f, 0.918945f, 0.930176f, 0.940918f, 0.948730f, 0.956055f, 0.984375f, 0.985840f, 0.985840f, 0.985840f, 0.986328f, 0.985840f,
+ 0.000242f, 0.000540f, 0.000708f, 0.000830f, 0.001143f, 0.001451f, 0.001861f, 0.002249f, 0.002661f, 0.003010f, 0.003435f, 0.003922f,
+ 0.004707f, 0.005165f, 0.005787f, 0.006840f, 0.007374f, 0.008545f, 0.009651f, 0.011147f, 0.012581f, 0.014084f, 0.015991f, 0.017899f,
+ 0.020325f, 0.023392f, 0.026978f, 0.031113f, 0.035919f, 0.042023f, 0.049103f, 0.057831f, 0.068420f, 0.081543f, 0.098145f, 0.118530f,
+ 0.143921f, 0.175293f, 0.213989f, 0.260742f, 0.316162f, 0.377441f, 0.444336f, 0.512207f, 0.579590f, 0.641113f, 0.696289f, 0.744629f,
+ 0.786621f, 0.820801f, 0.849609f, 0.872559f, 0.892578f, 0.908691f, 0.922363f, 0.934570f, 0.944336f, 0.951660f, 0.982910f, 0.984375f,
+ 0.984863f, 0.984863f, 0.985352f, 0.984863f, 0.000106f, 0.000477f, 0.000649f, 0.000901f, 0.001110f, 0.001206f, 0.001630f, 0.002121f,
+ 0.002192f, 0.002743f, 0.003128f, 0.003538f, 0.003941f, 0.004688f, 0.005276f, 0.005905f, 0.006546f, 0.007568f, 0.008461f, 0.009483f,
+ 0.010674f, 0.011864f, 0.013649f, 0.015549f, 0.017731f, 0.020111f, 0.023010f, 0.026199f, 0.030304f, 0.035278f, 0.040833f, 0.047821f,
+ 0.056580f, 0.066895f, 0.079895f, 0.096191f, 0.116760f, 0.141968f, 0.173584f, 0.212646f, 0.260498f, 0.316162f, 0.379883f, 0.447754f,
+ 0.517578f, 0.584961f, 0.647949f, 0.704102f, 0.752930f, 0.792969f, 0.827148f, 0.855957f, 0.877930f, 0.898438f, 0.914062f, 0.928223f,
+ 0.938965f, 0.948242f, 0.981445f, 0.983398f, 0.983887f, 0.983887f, 0.983887f, 0.983398f, 0.000208f, 0.000456f, 0.000582f, 0.000788f,
+ 0.001016f, 0.001428f, 0.001507f, 0.001769f, 0.002203f, 0.002525f, 0.002718f, 0.003187f, 0.003761f, 0.004238f, 0.004635f, 0.005348f,
+ 0.005901f, 0.006805f, 0.007500f, 0.008545f, 0.009270f, 0.010437f, 0.011742f, 0.013344f, 0.015198f, 0.017242f, 0.019516f, 0.022430f,
+ 0.025665f, 0.029922f, 0.034180f, 0.040161f, 0.046936f, 0.055420f, 0.065735f, 0.078552f, 0.094666f, 0.114563f, 0.140503f, 0.172485f,
+ 0.212646f, 0.260986f, 0.318359f, 0.383545f, 0.453125f, 0.524414f, 0.593750f, 0.656738f, 0.712891f, 0.761230f, 0.801270f, 0.835938f,
+ 0.862305f, 0.885742f, 0.904785f, 0.919922f, 0.933594f, 0.943359f, 0.980469f, 0.982422f, 0.982422f, 0.981934f, 0.982422f, 0.982422f,
+ 0.000170f, 0.000350f, 0.000583f, 0.000682f, 0.000845f, 0.001036f, 0.001265f, 0.001821f, 0.001953f, 0.002163f, 0.002525f, 0.002771f,
+ 0.003418f, 0.003729f, 0.004040f, 0.004871f, 0.005188f, 0.005726f, 0.006512f, 0.007130f, 0.008087f, 0.009018f, 0.010216f, 0.011490f,
+ 0.013084f, 0.014565f, 0.016891f, 0.019073f, 0.021851f, 0.025253f, 0.029022f, 0.033539f, 0.039124f, 0.045563f, 0.054230f, 0.064270f,
+ 0.077271f, 0.093323f, 0.113403f, 0.139648f, 0.172485f, 0.213379f, 0.262939f, 0.322266f, 0.389404f, 0.461426f, 0.534180f, 0.604492f,
+ 0.668457f, 0.724609f, 0.772461f, 0.812500f, 0.845703f, 0.872070f, 0.894043f, 0.911621f, 0.926758f, 0.938477f, 0.979004f, 0.980469f,
+ 0.980957f, 0.980957f, 0.980957f, 0.980957f, 0.000000f, 0.000332f, 0.000583f, 0.000583f, 0.000848f, 0.000959f, 0.001125f, 0.001425f,
+ 0.001810f, 0.001899f, 0.002300f, 0.002529f, 0.002996f, 0.003162f, 0.003607f, 0.004150f, 0.004761f, 0.005146f, 0.005791f, 0.006329f,
+ 0.007099f, 0.008110f, 0.008949f, 0.009941f, 0.011253f, 0.012756f, 0.014565f, 0.016434f, 0.018707f, 0.021271f, 0.024475f, 0.028290f,
+ 0.032745f, 0.037964f, 0.044769f, 0.052795f, 0.063416f, 0.076050f, 0.092102f, 0.113464f, 0.139526f, 0.172974f, 0.214600f, 0.266602f,
+ 0.327637f, 0.397461f, 0.471191f, 0.546387f, 0.617188f, 0.682129f, 0.737793f, 0.784668f, 0.823730f, 0.854980f, 0.881348f, 0.902344f,
+ 0.918945f, 0.933105f, 0.977539f, 0.979492f, 0.979492f, 0.979492f, 0.979492f, 0.979492f, 0.000000f, 0.000243f, 0.000553f, 0.000575f,
+ 0.000591f, 0.000798f, 0.000991f, 0.001234f, 0.001419f, 0.001812f, 0.001935f, 0.002186f, 0.002518f, 0.002975f, 0.003202f, 0.003614f,
+ 0.004047f, 0.004425f, 0.005013f, 0.005718f, 0.006172f, 0.007046f, 0.007740f, 0.008835f, 0.009819f, 0.011192f, 0.012444f, 0.014114f,
+ 0.015884f, 0.018204f, 0.020844f, 0.023392f, 0.027420f, 0.031921f, 0.037170f, 0.043610f, 0.052032f, 0.062408f, 0.075256f, 0.091675f,
+ 0.112610f, 0.140015f, 0.173950f, 0.217651f, 0.271973f, 0.335693f, 0.407715f, 0.484619f, 0.561035f, 0.633789f, 0.698242f, 0.752930f,
+ 0.798828f, 0.836426f, 0.867676f, 0.891602f, 0.911621f, 0.926270f, 0.975098f, 0.977539f, 0.978516f, 0.977539f, 0.977539f, 0.978027f,
+ 0.000121f, 0.000121f, 0.000241f, 0.000385f, 0.000684f, 0.000693f, 0.000932f, 0.001156f, 0.001410f, 0.001648f, 0.001893f, 0.002184f,
+ 0.002367f, 0.002579f, 0.002872f, 0.003319f, 0.003653f, 0.003922f, 0.004425f, 0.004925f, 0.005436f, 0.006180f, 0.006836f, 0.007645f,
+ 0.008278f, 0.009476f, 0.010788f, 0.012169f, 0.013695f, 0.015305f, 0.017319f, 0.020111f, 0.022858f, 0.026718f, 0.030975f, 0.036255f,
+ 0.042938f, 0.051270f, 0.061493f, 0.074768f, 0.091187f, 0.112976f, 0.140747f, 0.176392f, 0.222168f, 0.278809f, 0.345703f, 0.421387f,
+ 0.500488f, 0.578613f, 0.651855f, 0.715820f, 0.769531f, 0.813965f, 0.850586f, 0.878418f, 0.901855f, 0.920410f, 0.973633f, 0.975586f,
+ 0.976074f, 0.976562f, 0.976562f, 0.975098f, 0.000240f, 0.000120f, 0.000281f, 0.000333f, 0.000498f, 0.000680f, 0.000684f, 0.001083f,
+ 0.001312f, 0.001618f, 0.001606f, 0.001834f, 0.002087f, 0.002316f, 0.002735f, 0.002792f, 0.003084f, 0.003386f, 0.003944f, 0.004353f,
+ 0.004761f, 0.005390f, 0.005997f, 0.006615f, 0.007389f, 0.008324f, 0.008987f, 0.010284f, 0.011703f, 0.013382f, 0.014717f, 0.016953f,
+ 0.019424f, 0.022278f, 0.026047f, 0.030029f, 0.035492f, 0.042145f, 0.050446f, 0.060608f, 0.073975f, 0.091187f, 0.113831f, 0.142700f,
+ 0.180176f, 0.228271f, 0.288086f, 0.359131f, 0.437988f, 0.519531f, 0.600098f, 0.673340f, 0.735352f, 0.787598f, 0.830566f, 0.865234f,
+ 0.891602f, 0.913086f, 0.971680f, 0.974121f, 0.974121f, 0.974121f, 0.974121f, 0.974609f, 0.000000f, 0.000239f, 0.000236f, 0.000425f,
+ 0.000487f, 0.000608f, 0.000850f, 0.001012f, 0.001140f, 0.001260f, 0.001410f, 0.001640f, 0.001953f, 0.002003f, 0.002342f, 0.002434f,
+ 0.002686f, 0.002934f, 0.003305f, 0.003771f, 0.004169f, 0.004692f, 0.005028f, 0.005817f, 0.006371f, 0.007179f, 0.007919f, 0.008965f,
+ 0.009857f, 0.011261f, 0.012703f, 0.014229f, 0.016312f, 0.018494f, 0.021744f, 0.025024f, 0.029633f, 0.034790f, 0.041199f, 0.049561f,
+ 0.060242f, 0.073608f, 0.091675f, 0.114502f, 0.144897f, 0.185547f, 0.236328f, 0.300049f, 0.375732f, 0.458496f, 0.542969f, 0.624023f,
+ 0.696289f, 0.758301f, 0.808105f, 0.847656f, 0.879395f, 0.903809f, 0.968750f, 0.971191f, 0.972168f, 0.971680f, 0.972168f, 0.971680f,
+ 0.000000f, 0.000217f, 0.000235f, 0.000235f, 0.000321f, 0.000560f, 0.000588f, 0.000897f, 0.001034f, 0.001040f, 0.001246f, 0.001369f,
+ 0.001611f, 0.001692f, 0.001942f, 0.002153f, 0.002337f, 0.002638f, 0.002878f, 0.003330f, 0.003672f, 0.003986f, 0.004498f, 0.004826f,
+ 0.005535f, 0.006176f, 0.006561f, 0.007538f, 0.008362f, 0.009544f, 0.010612f, 0.011879f, 0.013794f, 0.015839f, 0.018326f, 0.020889f,
+ 0.024567f, 0.028625f, 0.033783f, 0.040527f, 0.049133f, 0.059998f, 0.073608f, 0.092041f, 0.116394f, 0.148682f, 0.191528f, 0.246582f,
+ 0.315186f, 0.395508f, 0.482910f, 0.570312f, 0.651367f, 0.722168f, 0.781738f, 0.828613f, 0.866211f, 0.895508f, 0.966797f, 0.968750f,
+ 0.969238f, 0.969727f, 0.969238f, 0.969238f, 0.000000f, 0.000108f, 0.000215f, 0.000346f, 0.000352f, 0.000501f, 0.000783f, 0.000828f,
+ 0.000954f, 0.000980f, 0.001130f, 0.001353f, 0.001429f, 0.001522f, 0.001690f, 0.001760f, 0.002172f, 0.002363f, 0.002522f, 0.002777f,
+ 0.003202f, 0.003550f, 0.004040f, 0.004364f, 0.004734f, 0.005192f, 0.005909f, 0.006271f, 0.007015f, 0.007957f, 0.008774f, 0.010185f,
+ 0.011681f, 0.013306f, 0.015327f, 0.017517f, 0.020264f, 0.023636f, 0.027740f, 0.033234f, 0.039856f, 0.048340f, 0.059387f, 0.074097f,
+ 0.093567f, 0.118896f, 0.153931f, 0.200073f, 0.260254f, 0.334473f, 0.420410f, 0.511719f, 0.601562f, 0.682129f, 0.750488f, 0.807617f,
+ 0.851074f, 0.884277f, 0.963867f, 0.966309f, 0.966797f, 0.966797f, 0.966797f, 0.966797f, 0.000000f, 0.000059f, 0.000292f, 0.000331f,
+ 0.000344f, 0.000613f, 0.000532f, 0.000703f, 0.000853f, 0.000915f, 0.000936f, 0.001102f, 0.001284f, 0.001430f, 0.001417f, 0.001475f,
+ 0.001791f, 0.001989f, 0.002161f, 0.002388f, 0.002775f, 0.003017f, 0.003357f, 0.003763f, 0.004124f, 0.004383f, 0.004917f, 0.005436f,
+ 0.005840f, 0.006733f, 0.007511f, 0.008667f, 0.009567f, 0.011032f, 0.012474f, 0.014610f, 0.016739f, 0.019379f, 0.022873f, 0.027252f,
+ 0.032410f, 0.039062f, 0.048065f, 0.059296f, 0.074646f, 0.094971f, 0.123108f, 0.161011f, 0.211426f, 0.277344f, 0.358154f, 0.450195f,
+ 0.545410f, 0.636230f, 0.715332f, 0.781250f, 0.832520f, 0.872070f, 0.960449f, 0.962402f, 0.963867f, 0.963379f, 0.962891f, 0.963379f,
+ 0.000000f, 0.000000f, 0.000098f, 0.000301f, 0.000315f, 0.000566f, 0.000587f, 0.000627f, 0.000643f, 0.000795f, 0.000974f, 0.001023f,
+ 0.000987f, 0.001031f, 0.001245f, 0.001470f, 0.001637f, 0.001820f, 0.001884f, 0.002146f, 0.002357f, 0.002630f, 0.002913f, 0.003164f,
+ 0.003380f, 0.003824f, 0.004189f, 0.004353f, 0.004940f, 0.005688f, 0.006409f, 0.007347f, 0.008018f, 0.009163f, 0.010559f, 0.012039f,
+ 0.013695f, 0.016144f, 0.018723f, 0.022354f, 0.026337f, 0.031433f, 0.038818f, 0.047546f, 0.059662f, 0.075623f, 0.097473f, 0.127808f,
+ 0.169556f, 0.225830f, 0.299072f, 0.387451f, 0.486084f, 0.583984f, 0.674805f, 0.751465f, 0.812012f, 0.859375f, 0.957031f, 0.958984f,
+ 0.959473f, 0.959961f, 0.959961f, 0.959961f, 0.000000f, 0.000000f, 0.000004f, 0.000078f, 0.000408f, 0.000432f, 0.000563f, 0.000560f,
+ 0.000566f, 0.000623f, 0.000782f, 0.000829f, 0.000896f, 0.000956f, 0.001056f, 0.001249f, 0.001414f, 0.001473f, 0.001646f, 0.001764f,
+ 0.002066f, 0.002230f, 0.002436f, 0.002651f, 0.003012f, 0.003252f, 0.003414f, 0.004055f, 0.004143f, 0.004784f, 0.005356f, 0.006077f,
+ 0.006870f, 0.007538f, 0.008728f, 0.009834f, 0.011322f, 0.013130f, 0.015427f, 0.017914f, 0.021271f, 0.025436f, 0.030960f, 0.038086f,
+ 0.047485f, 0.060303f, 0.077087f, 0.101196f, 0.134521f, 0.180786f, 0.244507f, 0.326172f, 0.423584f, 0.527832f, 0.628418f, 0.716797f,
+ 0.788086f, 0.843262f, 0.953125f, 0.955566f, 0.955566f, 0.956543f, 0.956055f, 0.956543f, 0.000000f, 0.000000f, 0.000000f, 0.000236f,
+ 0.000320f, 0.000484f, 0.000521f, 0.000549f, 0.000556f, 0.000584f, 0.000574f, 0.000690f, 0.000758f, 0.000841f, 0.001003f, 0.001013f,
+ 0.001169f, 0.001292f, 0.001437f, 0.001658f, 0.001830f, 0.002001f, 0.002081f, 0.002146f, 0.002434f, 0.002712f, 0.002964f, 0.003220f,
+ 0.003513f, 0.003963f, 0.004410f, 0.004875f, 0.005608f, 0.006245f, 0.007179f, 0.008118f, 0.009201f, 0.010582f, 0.012360f, 0.014343f,
+ 0.016968f, 0.020401f, 0.024628f, 0.030365f, 0.037567f, 0.047455f, 0.060913f, 0.079529f, 0.105774f, 0.143555f, 0.196167f, 0.268799f,
+ 0.361084f, 0.467041f, 0.576172f, 0.676758f, 0.760254f, 0.825195f, 0.948242f, 0.951660f, 0.951660f, 0.951660f, 0.951660f, 0.951660f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000122f, 0.000257f, 0.000334f, 0.000390f, 0.000496f, 0.000520f, 0.000539f, 0.000590f, 0.000602f,
+ 0.000646f, 0.000725f, 0.000909f, 0.000949f, 0.001023f, 0.001121f, 0.001181f, 0.001308f, 0.001474f, 0.001457f, 0.001714f, 0.002007f,
+ 0.001929f, 0.002039f, 0.002468f, 0.002672f, 0.003025f, 0.003317f, 0.003635f, 0.004047f, 0.004433f, 0.004864f, 0.005756f, 0.006493f,
+ 0.007515f, 0.008331f, 0.009697f, 0.011383f, 0.014000f, 0.016235f, 0.019653f, 0.024185f, 0.029465f, 0.037109f, 0.047699f, 0.062164f,
+ 0.082642f, 0.112488f, 0.155151f, 0.216919f, 0.300049f, 0.404541f, 0.520020f, 0.631836f, 0.728516f, 0.805664f, 0.943848f, 0.946289f,
+ 0.946777f, 0.946777f, 0.947266f, 0.947266f, 0.000000f, 0.000000f, 0.000122f, 0.000088f, 0.000219f, 0.000229f, 0.000355f, 0.000414f,
+ 0.000482f, 0.000545f, 0.000559f, 0.000568f, 0.000481f, 0.000668f, 0.000636f, 0.000728f, 0.000924f, 0.000980f, 0.001017f, 0.001109f,
+ 0.001258f, 0.001353f, 0.001451f, 0.001564f, 0.001621f, 0.001740f, 0.002066f, 0.002289f, 0.002459f, 0.002621f, 0.002975f, 0.003349f,
+ 0.003588f, 0.003998f, 0.004723f, 0.005116f, 0.006035f, 0.006859f, 0.007957f, 0.009064f, 0.010658f, 0.012711f, 0.015511f, 0.018555f,
+ 0.023026f, 0.028854f, 0.037140f, 0.048035f, 0.064026f, 0.086914f, 0.121033f, 0.171387f, 0.244141f, 0.341797f, 0.458740f, 0.580078f,
+ 0.691895f, 0.780762f, 0.937988f, 0.940430f, 0.941406f, 0.940918f, 0.941895f, 0.941406f, 0.000000f, 0.000000f, 0.000000f, 0.000080f,
+ 0.000211f, 0.000221f, 0.000225f, 0.000192f, 0.000352f, 0.000368f, 0.000397f, 0.000529f, 0.000510f, 0.000504f, 0.000540f, 0.000671f,
+ 0.000694f, 0.000763f, 0.000902f, 0.000998f, 0.001063f, 0.001074f, 0.001128f, 0.001407f, 0.001370f, 0.001449f, 0.001682f, 0.001635f,
+ 0.001976f, 0.002108f, 0.002335f, 0.002558f, 0.002905f, 0.003176f, 0.003637f, 0.003948f, 0.004650f, 0.005341f, 0.006237f, 0.007034f,
+ 0.008415f, 0.009811f, 0.012032f, 0.014565f, 0.017731f, 0.022324f, 0.028427f, 0.036713f, 0.048859f, 0.066406f, 0.092957f, 0.133057f,
+ 0.193848f, 0.281250f, 0.395508f, 0.524902f, 0.648926f, 0.754395f, 0.931152f, 0.934570f, 0.934570f, 0.934570f, 0.935547f, 0.935059f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000181f, 0.000196f, 0.000236f, 0.000250f, 0.000226f, 0.000281f, 0.000335f, 0.000457f,
+ 0.000406f, 0.000511f, 0.000522f, 0.000593f, 0.000539f, 0.000663f, 0.000661f, 0.000779f, 0.000978f, 0.000855f, 0.000937f, 0.001128f,
+ 0.001163f, 0.001253f, 0.001241f, 0.001531f, 0.001595f, 0.001796f, 0.001888f, 0.002226f, 0.002350f, 0.002609f, 0.002787f, 0.003260f,
+ 0.003656f, 0.004303f, 0.004910f, 0.005577f, 0.006683f, 0.007603f, 0.009102f, 0.011017f, 0.013603f, 0.016968f, 0.021652f, 0.027939f,
+ 0.037109f, 0.050262f, 0.070374f, 0.101624f, 0.150391f, 0.225220f, 0.331543f, 0.463867f, 0.601074f, 0.723145f, 0.923828f, 0.927246f,
+ 0.927246f, 0.928223f, 0.927734f, 0.928223f, 0.000000f, 0.000000f, 0.000122f, 0.000121f, 0.000121f, 0.000174f, 0.000156f, 0.000204f,
+ 0.000180f, 0.000221f, 0.000246f, 0.000346f, 0.000313f, 0.000426f, 0.000468f, 0.000482f, 0.000559f, 0.000582f, 0.000536f, 0.000611f,
+ 0.000770f, 0.000666f, 0.000919f, 0.000947f, 0.001013f, 0.000948f, 0.001129f, 0.001169f, 0.001463f, 0.001579f, 0.001540f, 0.001555f,
+ 0.001888f, 0.002007f, 0.002390f, 0.002623f, 0.002708f, 0.003235f, 0.003584f, 0.004223f, 0.005001f, 0.005791f, 0.006905f, 0.008118f,
+ 0.010117f, 0.012512f, 0.015961f, 0.020798f, 0.027374f, 0.037628f, 0.052673f, 0.076172f, 0.114197f, 0.175659f, 0.270752f, 0.399658f,
+ 0.546875f, 0.687012f, 0.915527f, 0.918457f, 0.919434f, 0.919434f, 0.919434f, 0.919434f, 0.000000f, 0.000000f, 0.000121f, 0.000121f,
+ 0.000121f, 0.000120f, 0.000139f, 0.000141f, 0.000152f, 0.000186f, 0.000209f, 0.000222f, 0.000297f, 0.000330f, 0.000367f, 0.000403f,
+ 0.000433f, 0.000456f, 0.000457f, 0.000484f, 0.000521f, 0.000544f, 0.000594f, 0.000807f, 0.000790f, 0.000841f, 0.000784f, 0.001025f,
+ 0.001112f, 0.001014f, 0.001146f, 0.001287f, 0.001485f, 0.001541f, 0.001740f, 0.002014f, 0.002264f, 0.002460f, 0.002825f, 0.003124f,
+ 0.003683f, 0.004177f, 0.005024f, 0.006004f, 0.007454f, 0.009041f, 0.011833f, 0.014839f, 0.019791f, 0.027283f, 0.038361f, 0.055817f,
+ 0.084656f, 0.133057f, 0.213013f, 0.334717f, 0.488770f, 0.645996f, 0.905762f, 0.909668f, 0.909668f, 0.909180f, 0.910645f, 0.908691f,
+ 0.000000f, 0.000000f, 0.000121f, 0.000121f, 0.000120f, 0.000120f, 0.000119f, 0.000115f, 0.000104f, 0.000105f, 0.000203f, 0.000235f,
+ 0.000185f, 0.000290f, 0.000201f, 0.000306f, 0.000259f, 0.000370f, 0.000401f, 0.000428f, 0.000596f, 0.000617f, 0.000474f, 0.000593f,
+ 0.000641f, 0.000676f, 0.000682f, 0.000826f, 0.000897f, 0.000934f, 0.000972f, 0.000972f, 0.001213f, 0.001281f, 0.001410f, 0.001451f,
+ 0.001562f, 0.001786f, 0.002031f, 0.002417f, 0.002764f, 0.003162f, 0.003763f, 0.004406f, 0.005310f, 0.006454f, 0.008156f, 0.010849f,
+ 0.014305f, 0.019318f, 0.027328f, 0.039856f, 0.061310f, 0.097717f, 0.162354f, 0.270752f, 0.424805f, 0.599609f, 0.894043f, 0.897949f,
+ 0.898438f, 0.898438f, 0.898926f, 0.898438f, 0.000000f, 0.000121f, 0.000121f, 0.000120f, 0.000119f, 0.000119f, 0.000118f, 0.000118f,
+ 0.000112f, 0.000102f, 0.000094f, 0.000109f, 0.000131f, 0.000145f, 0.000232f, 0.000171f, 0.000278f, 0.000230f, 0.000347f, 0.000331f,
+ 0.000379f, 0.000381f, 0.000512f, 0.000427f, 0.000541f, 0.000566f, 0.000547f, 0.000613f, 0.000706f, 0.000660f, 0.000809f, 0.000941f,
+ 0.000950f, 0.001035f, 0.001069f, 0.001220f, 0.001149f, 0.001314f, 0.001603f, 0.001801f, 0.002062f, 0.002394f, 0.002737f, 0.003057f,
+ 0.003771f, 0.004471f, 0.005875f, 0.007217f, 0.009651f, 0.013344f, 0.018829f, 0.027710f, 0.043091f, 0.069214f, 0.119141f, 0.210571f,
+ 0.358398f, 0.544922f, 0.881348f, 0.883789f, 0.885254f, 0.885742f, 0.885254f, 0.885254f, 0.000000f, 0.000121f, 0.000120f, 0.000119f,
+ 0.000119f, 0.000118f, 0.000117f, 0.000116f, 0.000116f, 0.000110f, 0.000101f, 0.000094f, 0.000087f, 0.000157f, 0.000151f, 0.000168f,
+ 0.000146f, 0.000219f, 0.000214f, 0.000261f, 0.000313f, 0.000363f, 0.000311f, 0.000415f, 0.000476f, 0.000448f, 0.000429f, 0.000460f,
+ 0.000481f, 0.000560f, 0.000544f, 0.000695f, 0.000626f, 0.000789f, 0.000877f, 0.000894f, 0.000948f, 0.001177f, 0.001175f, 0.001366f,
+ 0.001487f, 0.001738f, 0.002008f, 0.002304f, 0.002663f, 0.003250f, 0.004002f, 0.004932f, 0.006416f, 0.008636f, 0.012344f, 0.018127f,
+ 0.028610f, 0.047150f, 0.083923f, 0.156860f, 0.291260f, 0.487305f, 0.866211f, 0.869141f, 0.870605f, 0.870117f, 0.871094f, 0.870117f,
+ 0.000000f, 0.000000f, 0.000119f, 0.000118f, 0.000117f, 0.000116f, 0.000115f, 0.000115f, 0.000114f, 0.000114f, 0.000109f, 0.000101f,
+ 0.000094f, 0.000087f, 0.000081f, 0.000085f, 0.000129f, 0.000150f, 0.000176f, 0.000193f, 0.000216f, 0.000257f, 0.000241f, 0.000302f,
+ 0.000259f, 0.000299f, 0.000397f, 0.000403f, 0.000384f, 0.000402f, 0.000425f, 0.000582f, 0.000467f, 0.000614f, 0.000660f, 0.000625f,
+ 0.000650f, 0.000819f, 0.000790f, 0.000879f, 0.001001f, 0.001140f, 0.001403f, 0.001555f, 0.001844f, 0.002213f, 0.002636f, 0.003235f,
+ 0.004082f, 0.005604f, 0.007896f, 0.011292f, 0.018005f, 0.030472f, 0.055786f, 0.109985f, 0.224976f, 0.421875f, 0.848145f, 0.852539f,
+ 0.853027f, 0.852539f, 0.852539f, 0.853027f, 0.000000f, 0.000119f, 0.000118f, 0.000116f, 0.000115f, 0.000114f, 0.000113f, 0.000112f,
+ 0.000111f, 0.000111f, 0.000110f, 0.000108f, 0.000101f, 0.000094f, 0.000088f, 0.000082f, 0.000077f, 0.000109f, 0.000068f, 0.000102f,
+ 0.000127f, 0.000158f, 0.000177f, 0.000192f, 0.000207f, 0.000214f, 0.000249f, 0.000278f, 0.000296f, 0.000320f, 0.000330f, 0.000342f,
+ 0.000415f, 0.000371f, 0.000389f, 0.000508f, 0.000463f, 0.000586f, 0.000606f, 0.000649f, 0.000724f, 0.000841f, 0.000910f, 0.001065f,
+ 0.001236f, 0.001475f, 0.001807f, 0.002138f, 0.002716f, 0.003622f, 0.004921f, 0.006950f, 0.010574f, 0.018433f, 0.034607f, 0.072449f,
+ 0.163818f, 0.352295f, 0.827637f, 0.831055f, 0.831543f, 0.832031f, 0.833008f, 0.832520f, 0.000120f, 0.000116f, 0.000114f, 0.000113f,
+ 0.000111f, 0.000110f, 0.000109f, 0.000108f, 0.000107f, 0.000106f, 0.000106f, 0.000105f, 0.000104f, 0.000101f, 0.000094f, 0.000088f,
+ 0.000083f, 0.000078f, 0.000073f, 0.000092f, 0.000064f, 0.000097f, 0.000073f, 0.000105f, 0.000125f, 0.000162f, 0.000179f, 0.000177f,
+ 0.000191f, 0.000221f, 0.000241f, 0.000235f, 0.000270f, 0.000277f, 0.000287f, 0.000329f, 0.000319f, 0.000428f, 0.000417f, 0.000409f,
+ 0.000524f, 0.000537f, 0.000612f, 0.000750f, 0.000770f, 0.000961f, 0.001153f, 0.001347f, 0.001702f, 0.002081f, 0.002903f, 0.003956f,
+ 0.006184f, 0.010368f, 0.019592f, 0.043427f, 0.109924f, 0.280518f, 0.803223f, 0.806152f, 0.807617f, 0.808594f, 0.809082f, 0.808105f,
+ 0.000000f, 0.000111f, 0.000106f, 0.000107f, 0.000104f, 0.000103f, 0.000101f, 0.000101f, 0.000101f, 0.000100f, 0.000099f, 0.000098f,
+ 0.000097f, 0.000097f, 0.000097f, 0.000094f, 0.000088f, 0.000083f, 0.000078f, 0.000073f, 0.000069f, 0.000070f, 0.000061f, 0.000068f,
+ 0.000059f, 0.000067f, 0.000084f, 0.000097f, 0.000128f, 0.000137f, 0.000165f, 0.000160f, 0.000176f, 0.000185f, 0.000217f, 0.000239f,
+ 0.000237f, 0.000238f, 0.000272f, 0.000281f, 0.000314f, 0.000372f, 0.000395f, 0.000430f, 0.000504f, 0.000578f, 0.000665f, 0.000856f,
+ 0.000969f, 0.001210f, 0.001594f, 0.002216f, 0.003370f, 0.005527f, 0.010170f, 0.023239f, 0.066101f, 0.207275f, 0.775391f, 0.779785f,
+ 0.780273f, 0.780762f, 0.780273f, 0.780762f, 0.000000f, 0.000094f, 0.000097f, 0.000095f, 0.000092f, 0.000091f, 0.000091f, 0.000090f,
+ 0.000089f, 0.000089f, 0.000088f, 0.000088f, 0.000087f, 0.000086f, 0.000087f, 0.000086f, 0.000086f, 0.000085f, 0.000081f, 0.000076f,
+ 0.000072f, 0.000068f, 0.000064f, 0.000060f, 0.000057f, 0.000054f, 0.000058f, 0.000048f, 0.000048f, 0.000069f, 0.000068f, 0.000092f,
+ 0.000110f, 0.000122f, 0.000133f, 0.000136f, 0.000146f, 0.000154f, 0.000175f, 0.000194f, 0.000204f, 0.000206f, 0.000238f, 0.000262f,
+ 0.000266f, 0.000338f, 0.000361f, 0.000432f, 0.000527f, 0.000659f, 0.000848f, 0.001183f, 0.001713f, 0.002661f, 0.004921f, 0.010887f,
+ 0.033936f, 0.138428f, 0.743652f, 0.747559f, 0.748047f, 0.748535f, 0.749512f, 0.749023f, 0.000045f, 0.000047f, 0.000059f, 0.000059f,
+ 0.000063f, 0.000068f, 0.000068f, 0.000068f, 0.000067f, 0.000069f, 0.000068f, 0.000070f, 0.000070f, 0.000070f, 0.000071f, 0.000070f,
+ 0.000071f, 0.000071f, 0.000071f, 0.000071f, 0.000071f, 0.000069f, 0.000065f, 0.000062f, 0.000058f, 0.000055f, 0.000052f, 0.000049f,
+ 0.000046f, 0.000044f, 0.000041f, 0.000050f, 0.000051f, 0.000048f, 0.000061f, 0.000070f, 0.000084f, 0.000095f, 0.000107f, 0.000104f,
+ 0.000111f, 0.000128f, 0.000143f, 0.000154f, 0.000157f, 0.000186f, 0.000198f, 0.000216f, 0.000268f, 0.000315f, 0.000414f, 0.000537f,
+ 0.000735f, 0.001149f, 0.002075f, 0.004669f, 0.014175f, 0.077881f, 0.707031f, 0.710449f, 0.712402f, 0.711914f, 0.712891f, 0.712402f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000012f, 0.000013f, 0.000029f, 0.000028f, 0.000037f, 0.000035f, 0.000039f,
+ 0.000043f, 0.000043f, 0.000045f, 0.000045f, 0.000048f, 0.000048f, 0.000050f, 0.000051f, 0.000052f, 0.000052f, 0.000053f, 0.000054f,
+ 0.000054f, 0.000053f, 0.000050f, 0.000048f, 0.000045f, 0.000043f, 0.000040f, 0.000038f, 0.000036f, 0.000034f, 0.000032f, 0.000030f,
+ 0.000028f, 0.000030f, 0.000038f, 0.000043f, 0.000057f, 0.000069f, 0.000072f, 0.000073f, 0.000082f, 0.000095f, 0.000101f, 0.000099f,
+ 0.000116f, 0.000130f, 0.000184f, 0.000211f, 0.000301f, 0.000443f, 0.000737f, 0.001601f, 0.004978f, 0.032593f, 0.666504f, 0.669922f,
+ 0.669922f, 0.672363f, 0.670898f, 0.670410f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000006f, 0.000010f, 0.000012f, 0.000015f, 0.000018f, 0.000021f,
+ 0.000022f, 0.000023f, 0.000025f, 0.000028f, 0.000029f, 0.000029f, 0.000031f, 0.000033f, 0.000033f, 0.000035f, 0.000035f, 0.000035f,
+ 0.000033f, 0.000031f, 0.000029f, 0.000028f, 0.000026f, 0.000024f, 0.000023f, 0.000021f, 0.000020f, 0.000019f, 0.000022f, 0.000022f,
+ 0.000030f, 0.000038f, 0.000042f, 0.000041f, 0.000052f, 0.000047f, 0.000064f, 0.000072f, 0.000078f, 0.000129f, 0.000201f, 0.000382f,
+ 0.001180f, 0.009117f, 0.620605f, 0.624512f, 0.625000f, 0.625000f, 0.625000f, 0.625488f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000003f, 0.000005f, 0.000007f, 0.000008f, 0.000010f, 0.000011f, 0.000012f, 0.000014f, 0.000016f, 0.000016f, 0.000018f, 0.000017f,
+ 0.000016f, 0.000015f, 0.000014f, 0.000013f, 0.000012f, 0.000011f, 0.000010f, 0.000009f, 0.000011f, 0.000014f, 0.000018f, 0.000018f,
+ 0.000021f, 0.000028f, 0.000035f, 0.000053f, 0.000136f, 0.001152f, 0.571777f, 0.575684f, 0.575684f, 0.576172f, 0.576660f, 0.576660f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f,
+ 0.000002f, 0.000004f, 0.000004f, 0.000004f, 0.000003f, 0.000003f, 0.000002f, 0.000004f, 0.000003f, 0.000011f, 0.520020f, 0.523926f,
+ 0.524902f, 0.524902f, 0.524902f, 0.524902f,
+ },
+ {
+ 0.119934f, 0.328857f, 0.480713f, 0.586914f, 0.663086f, 0.717773f, 0.759766f, 0.791504f, 0.818359f, 0.838867f, 0.856934f, 0.871094f,
+ 0.883301f, 0.894043f, 0.902832f, 0.911621f, 0.917969f, 0.924805f, 0.930664f, 0.936035f, 0.939941f, 0.944824f, 0.948242f, 0.951660f,
+ 0.954590f, 0.958008f, 0.961426f, 0.962891f, 0.966309f, 0.967285f, 0.970215f, 0.972656f, 0.973633f, 0.975586f, 0.977539f, 0.978516f,
+ 0.979980f, 0.981445f, 0.982910f, 0.984375f, 0.985352f, 0.986328f, 0.987793f, 0.988770f, 0.989746f, 0.990234f, 0.991699f, 0.992676f,
+ 0.993164f, 0.993652f, 0.994629f, 0.995117f, 0.996094f, 0.996582f, 0.997559f, 0.998047f, 0.998535f, 0.999023f, 0.999512f, 0.999023f,
+ 0.999023f, 0.998535f, 0.998535f, 0.998047f, 0.046875f, 0.160400f, 0.286621f, 0.405518f, 0.507812f, 0.590820f, 0.656250f, 0.708008f,
+ 0.748535f, 0.781250f, 0.809082f, 0.830566f, 0.848633f, 0.864258f, 0.877441f, 0.888672f, 0.898926f, 0.906738f, 0.915039f, 0.921387f,
+ 0.928223f, 0.933105f, 0.937988f, 0.942871f, 0.946777f, 0.950684f, 0.954102f, 0.957031f, 0.959961f, 0.962402f, 0.965332f, 0.966797f,
+ 0.969727f, 0.971191f, 0.973145f, 0.975098f, 0.977539f, 0.978027f, 0.980469f, 0.981934f, 0.982910f, 0.984375f, 0.985352f, 0.986816f,
+ 0.987793f, 0.988770f, 0.989258f, 0.990723f, 0.991699f, 0.992676f, 0.993164f, 0.993652f, 0.994629f, 0.995605f, 0.996582f, 0.996582f,
+ 0.997559f, 0.998047f, 0.999023f, 0.999023f, 0.999023f, 0.998535f, 0.998535f, 0.998047f, 0.023788f, 0.084473f, 0.163696f, 0.255615f,
+ 0.351807f, 0.445312f, 0.527832f, 0.597656f, 0.656738f, 0.703613f, 0.742676f, 0.775879f, 0.802734f, 0.824707f, 0.843262f, 0.858887f,
+ 0.873047f, 0.884766f, 0.895508f, 0.903809f, 0.913086f, 0.919434f, 0.925781f, 0.931641f, 0.937012f, 0.941406f, 0.945801f, 0.949707f,
+ 0.953125f, 0.956543f, 0.959473f, 0.962402f, 0.964844f, 0.967285f, 0.969238f, 0.972168f, 0.973633f, 0.975098f, 0.977539f, 0.979492f,
+ 0.980469f, 0.981445f, 0.982910f, 0.984375f, 0.985840f, 0.986816f, 0.988281f, 0.988770f, 0.989746f, 0.990723f, 0.992188f, 0.992676f,
+ 0.993652f, 0.994629f, 0.995605f, 0.996094f, 0.996582f, 0.997559f, 0.998535f, 0.998535f, 0.998535f, 0.998047f, 0.998047f, 0.997559f,
+ 0.014595f, 0.050110f, 0.097717f, 0.158569f, 0.230347f, 0.311523f, 0.394531f, 0.473145f, 0.544922f, 0.606934f, 0.660645f, 0.705566f,
+ 0.743164f, 0.775391f, 0.800781f, 0.822266f, 0.841309f, 0.856934f, 0.870605f, 0.883301f, 0.894043f, 0.902832f, 0.911133f, 0.918945f,
+ 0.925293f, 0.931152f, 0.936035f, 0.941406f, 0.945801f, 0.949707f, 0.953125f, 0.956055f, 0.959473f, 0.962402f, 0.964844f, 0.967285f,
+ 0.970215f, 0.972168f, 0.974121f, 0.975098f, 0.977539f, 0.979004f, 0.980957f, 0.981934f, 0.983398f, 0.984375f, 0.985840f, 0.987305f,
+ 0.988281f, 0.989258f, 0.990723f, 0.991699f, 0.992676f, 0.993652f, 0.994629f, 0.995117f, 0.995605f, 0.996582f, 0.998535f, 0.998535f,
+ 0.998535f, 0.998047f, 0.998047f, 0.997559f, 0.009178f, 0.032379f, 0.062561f, 0.102417f, 0.151611f, 0.210938f, 0.279785f, 0.352783f,
+ 0.426758f, 0.496826f, 0.561035f, 0.618164f, 0.666992f, 0.708496f, 0.744141f, 0.773926f, 0.800781f, 0.821777f, 0.840820f, 0.856445f,
+ 0.870117f, 0.882324f, 0.893066f, 0.901855f, 0.910645f, 0.918457f, 0.925293f, 0.930176f, 0.935547f, 0.941406f, 0.946289f, 0.949707f,
+ 0.953125f, 0.956543f, 0.959961f, 0.962891f, 0.965332f, 0.967773f, 0.969727f, 0.972656f, 0.974121f, 0.976074f, 0.977539f, 0.979492f,
+ 0.981445f, 0.982422f, 0.984375f, 0.985840f, 0.986328f, 0.987793f, 0.989258f, 0.990234f, 0.991211f, 0.992188f, 0.993164f, 0.994141f,
+ 0.994629f, 0.995605f, 0.998047f, 0.998047f, 0.998047f, 0.997559f, 0.997559f, 0.997559f, 0.006382f, 0.022430f, 0.042908f, 0.068970f,
+ 0.102844f, 0.144653f, 0.195557f, 0.253906f, 0.318848f, 0.386230f, 0.454590f, 0.518066f, 0.577148f, 0.628906f, 0.675293f, 0.714844f,
+ 0.748535f, 0.777344f, 0.802246f, 0.823730f, 0.841797f, 0.856934f, 0.871094f, 0.882812f, 0.893555f, 0.902832f, 0.911133f, 0.918457f,
+ 0.925293f, 0.930176f, 0.937012f, 0.940918f, 0.945801f, 0.950195f, 0.953613f, 0.957031f, 0.960449f, 0.963379f, 0.966309f, 0.968262f,
+ 0.970703f, 0.973145f, 0.974609f, 0.976562f, 0.978516f, 0.980469f, 0.981934f, 0.983398f, 0.984375f, 0.985840f, 0.988281f, 0.988770f,
+ 0.989746f, 0.990723f, 0.991699f, 0.992676f, 0.993652f, 0.994629f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997559f, 0.997070f,
+ 0.004585f, 0.015961f, 0.030930f, 0.049133f, 0.072144f, 0.101013f, 0.137451f, 0.181519f, 0.232544f, 0.290039f, 0.352539f, 0.416748f,
+ 0.479736f, 0.538574f, 0.592773f, 0.641602f, 0.684570f, 0.723145f, 0.754395f, 0.782715f, 0.805176f, 0.825195f, 0.843750f, 0.859863f,
+ 0.872559f, 0.884766f, 0.895020f, 0.904297f, 0.912109f, 0.919922f, 0.926270f, 0.932129f, 0.937500f, 0.942383f, 0.946289f, 0.950195f,
+ 0.955078f, 0.958008f, 0.961426f, 0.964355f, 0.967285f, 0.969238f, 0.971680f, 0.974121f, 0.975586f, 0.977539f, 0.979492f, 0.980957f,
+ 0.982910f, 0.984375f, 0.985840f, 0.986328f, 0.988281f, 0.989746f, 0.990723f, 0.992188f, 0.992676f, 0.993164f, 0.997559f, 0.997559f,
+ 0.997070f, 0.997070f, 0.997070f, 0.997070f, 0.003483f, 0.012291f, 0.023209f, 0.036041f, 0.052429f, 0.073486f, 0.099182f, 0.131226f,
+ 0.169678f, 0.214844f, 0.266846f, 0.323242f, 0.383545f, 0.444580f, 0.503418f, 0.559082f, 0.609375f, 0.655762f, 0.695312f, 0.730957f,
+ 0.760254f, 0.788086f, 0.810059f, 0.829590f, 0.847168f, 0.862793f, 0.875488f, 0.886719f, 0.896973f, 0.906250f, 0.914551f, 0.921387f,
+ 0.927734f, 0.933594f, 0.938965f, 0.944336f, 0.948242f, 0.952148f, 0.956543f, 0.958984f, 0.961914f, 0.965332f, 0.968262f, 0.970703f,
+ 0.972656f, 0.974609f, 0.977051f, 0.979004f, 0.980469f, 0.981934f, 0.983887f, 0.985352f, 0.986328f, 0.987793f, 0.989746f, 0.990234f,
+ 0.991699f, 0.992676f, 0.996582f, 0.997070f, 0.997070f, 0.996582f, 0.996582f, 0.996094f, 0.002962f, 0.009613f, 0.017792f, 0.027481f,
+ 0.039429f, 0.055176f, 0.073914f, 0.096985f, 0.125610f, 0.159180f, 0.199707f, 0.246216f, 0.297607f, 0.353760f, 0.412842f, 0.470215f,
+ 0.526367f, 0.578613f, 0.626953f, 0.669434f, 0.707031f, 0.740723f, 0.769043f, 0.794922f, 0.814941f, 0.835449f, 0.851074f, 0.866699f,
+ 0.879395f, 0.890137f, 0.899902f, 0.909180f, 0.916992f, 0.924316f, 0.929688f, 0.936035f, 0.941406f, 0.945312f, 0.950195f, 0.953613f,
+ 0.957520f, 0.960938f, 0.963867f, 0.966797f, 0.969238f, 0.971680f, 0.974121f, 0.976562f, 0.979004f, 0.979980f, 0.981934f, 0.982910f,
+ 0.984375f, 0.986816f, 0.987793f, 0.988770f, 0.990234f, 0.991699f, 0.996582f, 0.996582f, 0.996582f, 0.996582f, 0.996094f, 0.996094f,
+ 0.002077f, 0.007637f, 0.013802f, 0.021606f, 0.031006f, 0.042419f, 0.055969f, 0.073242f, 0.094055f, 0.119446f, 0.150513f, 0.186401f,
+ 0.228638f, 0.276123f, 0.328857f, 0.384277f, 0.440674f, 0.496338f, 0.549805f, 0.598633f, 0.644043f, 0.683594f, 0.719727f, 0.750977f,
+ 0.779297f, 0.802246f, 0.823730f, 0.840820f, 0.855957f, 0.871582f, 0.882324f, 0.893555f, 0.903809f, 0.911621f, 0.920410f, 0.926758f,
+ 0.932617f, 0.938477f, 0.943359f, 0.947754f, 0.953125f, 0.955566f, 0.959473f, 0.962402f, 0.965332f, 0.968262f, 0.970703f, 0.972656f,
+ 0.976074f, 0.977051f, 0.979492f, 0.981445f, 0.983398f, 0.984863f, 0.986328f, 0.987793f, 0.989258f, 0.990723f, 0.995605f, 0.996094f,
+ 0.996094f, 0.996094f, 0.996094f, 0.995605f, 0.002014f, 0.006035f, 0.011299f, 0.017410f, 0.024368f, 0.033020f, 0.043701f, 0.056458f,
+ 0.072205f, 0.091431f, 0.114807f, 0.141968f, 0.174316f, 0.213257f, 0.256836f, 0.306152f, 0.358887f, 0.413330f, 0.468018f, 0.520996f,
+ 0.572266f, 0.618652f, 0.661621f, 0.699707f, 0.732910f, 0.762695f, 0.788574f, 0.810547f, 0.830078f, 0.848145f, 0.862305f, 0.875977f,
+ 0.887695f, 0.898438f, 0.907227f, 0.915527f, 0.922852f, 0.929199f, 0.936035f, 0.940918f, 0.946289f, 0.950684f, 0.953613f, 0.958496f,
+ 0.960938f, 0.964355f, 0.967285f, 0.970215f, 0.972656f, 0.975586f, 0.977539f, 0.979492f, 0.980957f, 0.982910f, 0.984863f, 0.986328f,
+ 0.987793f, 0.988770f, 0.995117f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.001496f, 0.005196f, 0.009201f, 0.013985f,
+ 0.019806f, 0.026413f, 0.034943f, 0.044647f, 0.056641f, 0.070923f, 0.088623f, 0.109680f, 0.135254f, 0.164795f, 0.200073f, 0.240845f,
+ 0.285645f, 0.335449f, 0.387939f, 0.441650f, 0.495850f, 0.546875f, 0.595215f, 0.639160f, 0.679199f, 0.715820f, 0.746582f, 0.774414f,
+ 0.798828f, 0.819824f, 0.837402f, 0.854492f, 0.869629f, 0.881348f, 0.893066f, 0.902832f, 0.912109f, 0.918945f, 0.926758f, 0.933105f,
+ 0.938477f, 0.943359f, 0.948730f, 0.952637f, 0.956055f, 0.960449f, 0.963379f, 0.966797f, 0.969238f, 0.972656f, 0.975098f, 0.977051f,
+ 0.979004f, 0.981445f, 0.982910f, 0.984375f, 0.986328f, 0.987305f, 0.994629f, 0.995605f, 0.995117f, 0.995117f, 0.995117f, 0.994629f,
+ 0.001187f, 0.004314f, 0.007740f, 0.011337f, 0.016373f, 0.021759f, 0.028198f, 0.035889f, 0.045197f, 0.056580f, 0.069946f, 0.085938f,
+ 0.105408f, 0.128784f, 0.155884f, 0.187866f, 0.225830f, 0.268066f, 0.315186f, 0.365479f, 0.418213f, 0.471680f, 0.522949f, 0.572754f,
+ 0.617676f, 0.659668f, 0.697754f, 0.730957f, 0.760742f, 0.787109f, 0.809570f, 0.830078f, 0.846680f, 0.862793f, 0.875488f, 0.888184f,
+ 0.898926f, 0.907715f, 0.916016f, 0.923340f, 0.930664f, 0.936523f, 0.941895f, 0.947754f, 0.951660f, 0.955566f, 0.959473f, 0.963867f,
+ 0.966309f, 0.969238f, 0.972168f, 0.974121f, 0.976562f, 0.979004f, 0.980957f, 0.982910f, 0.984863f, 0.986816f, 0.994141f, 0.994629f,
+ 0.994629f, 0.994629f, 0.994629f, 0.994141f, 0.001187f, 0.003733f, 0.006496f, 0.009918f, 0.013634f, 0.017899f, 0.023026f, 0.029343f,
+ 0.036621f, 0.045227f, 0.055786f, 0.068298f, 0.083740f, 0.101135f, 0.122314f, 0.147827f, 0.177612f, 0.212891f, 0.252686f, 0.297119f,
+ 0.345215f, 0.395996f, 0.448730f, 0.500488f, 0.550781f, 0.597656f, 0.641113f, 0.680664f, 0.716309f, 0.747559f, 0.774414f, 0.799316f,
+ 0.820312f, 0.838867f, 0.855957f, 0.870117f, 0.883301f, 0.894531f, 0.904785f, 0.913086f, 0.920898f, 0.928223f, 0.935059f, 0.940430f,
+ 0.945312f, 0.950684f, 0.955566f, 0.958496f, 0.962891f, 0.965820f, 0.968750f, 0.971680f, 0.974609f, 0.976562f, 0.978516f, 0.980957f,
+ 0.982910f, 0.984863f, 0.994141f, 0.994141f, 0.994629f, 0.994141f, 0.994141f, 0.994629f, 0.000998f, 0.003178f, 0.005444f, 0.008179f,
+ 0.011337f, 0.015091f, 0.019058f, 0.024368f, 0.029587f, 0.037140f, 0.045197f, 0.055115f, 0.066772f, 0.080688f, 0.097229f, 0.117371f,
+ 0.140869f, 0.169312f, 0.201538f, 0.238770f, 0.280762f, 0.326660f, 0.376709f, 0.427490f, 0.479248f, 0.530273f, 0.578613f, 0.623535f,
+ 0.664551f, 0.701660f, 0.733887f, 0.763672f, 0.790039f, 0.812500f, 0.832520f, 0.849121f, 0.865234f, 0.878906f, 0.890625f, 0.901367f,
+ 0.910645f, 0.919434f, 0.926758f, 0.933105f, 0.939453f, 0.944824f, 0.949707f, 0.954590f, 0.958008f, 0.961914f, 0.965332f, 0.968750f,
+ 0.971680f, 0.974121f, 0.977051f, 0.979004f, 0.980957f, 0.982910f, 0.993164f, 0.993164f, 0.994141f, 0.993652f, 0.993652f, 0.993164f,
+ 0.000948f, 0.002638f, 0.004784f, 0.007153f, 0.009590f, 0.012505f, 0.016388f, 0.020599f, 0.025299f, 0.031097f, 0.037323f, 0.045197f,
+ 0.054047f, 0.065002f, 0.078674f, 0.094055f, 0.112305f, 0.134399f, 0.160889f, 0.191040f, 0.226318f, 0.265869f, 0.310303f, 0.358154f,
+ 0.409180f, 0.459473f, 0.510254f, 0.559082f, 0.606445f, 0.648926f, 0.687500f, 0.722168f, 0.753418f, 0.781250f, 0.804199f, 0.825684f,
+ 0.843262f, 0.860840f, 0.874512f, 0.886719f, 0.898926f, 0.907227f, 0.916992f, 0.924805f, 0.932129f, 0.937988f, 0.943848f, 0.949219f,
+ 0.954102f, 0.958496f, 0.961426f, 0.965332f, 0.968750f, 0.972168f, 0.974609f, 0.977051f, 0.979492f, 0.981445f, 0.992188f, 0.993164f,
+ 0.993164f, 0.993164f, 0.993164f, 0.992676f, 0.000696f, 0.002352f, 0.004002f, 0.006138f, 0.008446f, 0.010826f, 0.013840f, 0.017258f,
+ 0.021194f, 0.025970f, 0.031128f, 0.037140f, 0.044281f, 0.053436f, 0.063660f, 0.076050f, 0.090271f, 0.107727f, 0.128662f, 0.152832f,
+ 0.182007f, 0.214111f, 0.252930f, 0.295166f, 0.341553f, 0.390625f, 0.442139f, 0.492676f, 0.541992f, 0.589844f, 0.633301f, 0.674316f,
+ 0.710938f, 0.743652f, 0.772461f, 0.796875f, 0.819824f, 0.839355f, 0.854980f, 0.870605f, 0.884277f, 0.895508f, 0.906738f, 0.915527f,
+ 0.923828f, 0.931152f, 0.937500f, 0.944336f, 0.949219f, 0.953613f, 0.958008f, 0.962402f, 0.965332f, 0.968750f, 0.972168f, 0.974609f,
+ 0.977051f, 0.979980f, 0.991211f, 0.992676f, 0.992188f, 0.992188f, 0.992188f, 0.992676f, 0.000838f, 0.002033f, 0.003664f, 0.005077f,
+ 0.007282f, 0.009415f, 0.011749f, 0.014931f, 0.017853f, 0.021606f, 0.025864f, 0.031219f, 0.037231f, 0.044464f, 0.052338f, 0.062500f,
+ 0.073853f, 0.087463f, 0.104065f, 0.123230f, 0.146362f, 0.173340f, 0.205078f, 0.240845f, 0.281982f, 0.326660f, 0.374756f, 0.425049f,
+ 0.476807f, 0.526855f, 0.574219f, 0.620117f, 0.662598f, 0.699219f, 0.733398f, 0.764160f, 0.791016f, 0.813965f, 0.833984f, 0.851074f,
+ 0.867676f, 0.880859f, 0.893555f, 0.904785f, 0.914062f, 0.922852f, 0.930176f, 0.937012f, 0.942383f, 0.948242f, 0.953125f, 0.957520f,
+ 0.962402f, 0.966309f, 0.969238f, 0.973145f, 0.975098f, 0.978027f, 0.991699f, 0.991699f, 0.992676f, 0.992188f, 0.991699f, 0.992188f,
+ 0.000600f, 0.001687f, 0.003023f, 0.004963f, 0.006405f, 0.008163f, 0.010368f, 0.012718f, 0.015480f, 0.018311f, 0.022064f, 0.026169f,
+ 0.031097f, 0.036926f, 0.043457f, 0.051392f, 0.060669f, 0.071350f, 0.084473f, 0.100220f, 0.118103f, 0.140259f, 0.166016f, 0.195679f,
+ 0.230469f, 0.269531f, 0.313232f, 0.360596f, 0.410156f, 0.460693f, 0.511719f, 0.560547f, 0.607422f, 0.650879f, 0.689941f, 0.724609f,
+ 0.756348f, 0.784180f, 0.808594f, 0.828613f, 0.847656f, 0.864258f, 0.879395f, 0.892090f, 0.903320f, 0.912598f, 0.921875f, 0.929688f,
+ 0.936523f, 0.942871f, 0.947754f, 0.953125f, 0.957520f, 0.961914f, 0.966309f, 0.969238f, 0.972656f, 0.975586f, 0.990234f, 0.991211f,
+ 0.991211f, 0.991699f, 0.991211f, 0.991211f, 0.000269f, 0.001538f, 0.002800f, 0.003868f, 0.005524f, 0.007179f, 0.008987f, 0.011063f,
+ 0.013084f, 0.015747f, 0.019211f, 0.022324f, 0.026474f, 0.031311f, 0.036530f, 0.042969f, 0.050201f, 0.059174f, 0.069641f, 0.081543f,
+ 0.096680f, 0.114075f, 0.134644f, 0.158691f, 0.187622f, 0.220581f, 0.258301f, 0.300781f, 0.347168f, 0.395996f, 0.447266f, 0.498291f,
+ 0.547852f, 0.595215f, 0.640625f, 0.680176f, 0.717285f, 0.749512f, 0.778320f, 0.803223f, 0.825684f, 0.845215f, 0.862793f, 0.877441f,
+ 0.890625f, 0.901855f, 0.912109f, 0.920898f, 0.929688f, 0.937012f, 0.942871f, 0.949707f, 0.954102f, 0.958496f, 0.962402f, 0.966309f,
+ 0.970215f, 0.974121f, 0.989746f, 0.990234f, 0.990723f, 0.990723f, 0.990723f, 0.990234f, 0.000341f, 0.001337f, 0.002573f, 0.003475f,
+ 0.004765f, 0.006329f, 0.007717f, 0.009499f, 0.011642f, 0.014107f, 0.016556f, 0.019470f, 0.022491f, 0.026169f, 0.030945f, 0.036011f,
+ 0.042389f, 0.049042f, 0.057678f, 0.067993f, 0.079468f, 0.093384f, 0.110046f, 0.129883f, 0.152710f, 0.180420f, 0.212158f, 0.248291f,
+ 0.289551f, 0.334961f, 0.383301f, 0.434570f, 0.485596f, 0.536133f, 0.584473f, 0.630371f, 0.671875f, 0.710449f, 0.743652f, 0.773926f,
+ 0.799316f, 0.823242f, 0.843262f, 0.860352f, 0.875977f, 0.889648f, 0.901367f, 0.911621f, 0.921387f, 0.929688f, 0.937012f, 0.943848f,
+ 0.950195f, 0.955078f, 0.959473f, 0.963379f, 0.967773f, 0.971191f, 0.988770f, 0.989746f, 0.990234f, 0.990234f, 0.990234f, 0.990234f,
+ 0.000564f, 0.001324f, 0.002092f, 0.003191f, 0.004471f, 0.005348f, 0.007069f, 0.008438f, 0.010201f, 0.011810f, 0.014297f, 0.016586f,
+ 0.019470f, 0.022644f, 0.026428f, 0.030579f, 0.035797f, 0.041718f, 0.048248f, 0.056213f, 0.065857f, 0.076782f, 0.090271f, 0.106262f,
+ 0.125122f, 0.147095f, 0.173462f, 0.204224f, 0.239746f, 0.279785f, 0.323730f, 0.372314f, 0.422607f, 0.474121f, 0.526367f, 0.575195f,
+ 0.621582f, 0.664062f, 0.703613f, 0.738770f, 0.769043f, 0.796387f, 0.820312f, 0.841797f, 0.858887f, 0.875488f, 0.889648f, 0.900879f,
+ 0.912598f, 0.921875f, 0.930664f, 0.937500f, 0.944336f, 0.950195f, 0.955566f, 0.959961f, 0.964844f, 0.968750f, 0.987305f, 0.989258f,
+ 0.989258f, 0.989258f, 0.989258f, 0.988770f, 0.000369f, 0.001128f, 0.001871f, 0.002792f, 0.003712f, 0.004723f, 0.006016f, 0.007542f,
+ 0.008896f, 0.010773f, 0.012421f, 0.014381f, 0.016632f, 0.019791f, 0.022354f, 0.025955f, 0.030609f, 0.035065f, 0.040924f, 0.047333f,
+ 0.055084f, 0.064209f, 0.075012f, 0.087769f, 0.102966f, 0.120911f, 0.142456f, 0.167358f, 0.197144f, 0.231812f, 0.270752f, 0.314209f,
+ 0.362549f, 0.412598f, 0.464844f, 0.515625f, 0.566895f, 0.614258f, 0.657715f, 0.698730f, 0.734863f, 0.766602f, 0.794922f, 0.818848f,
+ 0.839844f, 0.858887f, 0.875000f, 0.889648f, 0.901855f, 0.912598f, 0.922852f, 0.931152f, 0.938965f, 0.945312f, 0.951660f, 0.957520f,
+ 0.961426f, 0.966309f, 0.986816f, 0.988281f, 0.988281f, 0.988770f, 0.988281f, 0.988281f, 0.000466f, 0.000900f, 0.001792f, 0.002695f,
+ 0.003458f, 0.004204f, 0.005356f, 0.006512f, 0.007896f, 0.009300f, 0.010895f, 0.012459f, 0.014786f, 0.016739f, 0.019424f, 0.022461f,
+ 0.026062f, 0.029831f, 0.034851f, 0.039764f, 0.046417f, 0.053711f, 0.062164f, 0.072388f, 0.085205f, 0.099365f, 0.117004f, 0.137573f,
+ 0.162231f, 0.190674f, 0.224121f, 0.262451f, 0.305664f, 0.353027f, 0.403809f, 0.456055f, 0.508301f, 0.559082f, 0.608398f, 0.652832f,
+ 0.694824f, 0.731445f, 0.764160f, 0.793945f, 0.817871f, 0.839355f, 0.858398f, 0.875488f, 0.890137f, 0.902832f, 0.913574f, 0.923828f,
+ 0.932617f, 0.940918f, 0.946777f, 0.953613f, 0.958984f, 0.963379f, 0.985840f, 0.987305f, 0.987305f, 0.987793f, 0.987305f, 0.987305f,
+ 0.000234f, 0.001040f, 0.001661f, 0.002392f, 0.003101f, 0.003681f, 0.004944f, 0.005844f, 0.007065f, 0.008217f, 0.009247f, 0.010925f,
+ 0.012894f, 0.014549f, 0.017090f, 0.019455f, 0.022385f, 0.025650f, 0.029449f, 0.033936f, 0.039215f, 0.045135f, 0.052612f, 0.060944f,
+ 0.070312f, 0.082397f, 0.096924f, 0.113525f, 0.133179f, 0.156860f, 0.184814f, 0.217773f, 0.255127f, 0.298340f, 0.345215f, 0.395996f,
+ 0.448242f, 0.501953f, 0.553223f, 0.603516f, 0.649414f, 0.691895f, 0.729980f, 0.763184f, 0.792480f, 0.818359f, 0.841309f, 0.858887f,
+ 0.877441f, 0.891113f, 0.904785f, 0.915527f, 0.925781f, 0.933594f, 0.941895f, 0.949219f, 0.955566f, 0.960449f, 0.984863f, 0.985840f,
+ 0.986328f, 0.986816f, 0.986328f, 0.986816f, 0.000241f, 0.000808f, 0.001395f, 0.001986f, 0.002731f, 0.003429f, 0.004131f, 0.005402f,
+ 0.006077f, 0.007347f, 0.008522f, 0.009544f, 0.011345f, 0.013046f, 0.014534f, 0.016953f, 0.019241f, 0.022339f, 0.025208f, 0.029175f,
+ 0.033691f, 0.038300f, 0.044067f, 0.051331f, 0.059143f, 0.068726f, 0.080322f, 0.093567f, 0.109802f, 0.129883f, 0.152466f, 0.179810f,
+ 0.211792f, 0.249390f, 0.291748f, 0.338623f, 0.389404f, 0.442139f, 0.496338f, 0.548340f, 0.599121f, 0.645996f, 0.689941f, 0.728516f,
+ 0.762695f, 0.792969f, 0.818848f, 0.842285f, 0.862793f, 0.878906f, 0.894043f, 0.906250f, 0.917969f, 0.927734f, 0.935547f, 0.944336f,
+ 0.951172f, 0.957031f, 0.983398f, 0.985352f, 0.985840f, 0.985352f, 0.985840f, 0.985352f, 0.000340f, 0.000735f, 0.001377f, 0.001853f,
+ 0.002382f, 0.003159f, 0.004021f, 0.004642f, 0.005604f, 0.006340f, 0.007298f, 0.008591f, 0.009895f, 0.011154f, 0.012871f, 0.014580f,
+ 0.016876f, 0.019180f, 0.022141f, 0.024979f, 0.028748f, 0.032745f, 0.037964f, 0.043213f, 0.050171f, 0.057831f, 0.066833f, 0.078247f,
+ 0.091553f, 0.107178f, 0.125977f, 0.148315f, 0.175415f, 0.207153f, 0.244019f, 0.286377f, 0.333008f, 0.383789f, 0.437744f, 0.491943f,
+ 0.545410f, 0.597168f, 0.645508f, 0.688965f, 0.729004f, 0.764160f, 0.794434f, 0.821289f, 0.843750f, 0.864258f, 0.881348f, 0.895996f,
+ 0.909180f, 0.920898f, 0.929199f, 0.938965f, 0.946777f, 0.952637f, 0.982910f, 0.983887f, 0.984863f, 0.984863f, 0.984375f, 0.984863f,
+ 0.000236f, 0.000605f, 0.001135f, 0.001415f, 0.002329f, 0.002747f, 0.003551f, 0.004158f, 0.004723f, 0.005535f, 0.006687f, 0.007534f,
+ 0.008545f, 0.009979f, 0.011375f, 0.012993f, 0.014656f, 0.016754f, 0.018921f, 0.021759f, 0.024506f, 0.028183f, 0.032043f, 0.036743f,
+ 0.042236f, 0.048645f, 0.056030f, 0.065125f, 0.075928f, 0.089050f, 0.104370f, 0.122681f, 0.145142f, 0.171509f, 0.202759f, 0.239258f,
+ 0.281250f, 0.328369f, 0.379639f, 0.433838f, 0.489014f, 0.543945f, 0.596191f, 0.645020f, 0.690430f, 0.730957f, 0.766113f, 0.797852f,
+ 0.824219f, 0.846680f, 0.867188f, 0.884766f, 0.899414f, 0.912109f, 0.923828f, 0.933105f, 0.942383f, 0.949707f, 0.980957f, 0.982910f,
+ 0.983398f, 0.983398f, 0.983887f, 0.982910f, 0.000214f, 0.000710f, 0.001021f, 0.001429f, 0.001858f, 0.002607f, 0.003220f, 0.003738f,
+ 0.004459f, 0.005032f, 0.005726f, 0.006748f, 0.007748f, 0.008659f, 0.010002f, 0.011368f, 0.012985f, 0.014656f, 0.016525f, 0.018921f,
+ 0.021286f, 0.024231f, 0.027649f, 0.031464f, 0.035858f, 0.041321f, 0.047363f, 0.054840f, 0.063538f, 0.074097f, 0.086609f, 0.101990f,
+ 0.120117f, 0.141846f, 0.168213f, 0.199219f, 0.235352f, 0.277344f, 0.324707f, 0.376953f, 0.432373f, 0.488037f, 0.543457f, 0.597168f,
+ 0.646973f, 0.692871f, 0.732910f, 0.769531f, 0.801270f, 0.828125f, 0.850586f, 0.871582f, 0.888184f, 0.903809f, 0.915527f, 0.927246f,
+ 0.936523f, 0.946289f, 0.979492f, 0.981445f, 0.981934f, 0.982422f, 0.981934f, 0.981934f, 0.000000f, 0.000468f, 0.001076f, 0.001489f,
+ 0.002048f, 0.002413f, 0.002853f, 0.003468f, 0.003952f, 0.004444f, 0.005211f, 0.005917f, 0.006733f, 0.007763f, 0.008713f, 0.010262f,
+ 0.011368f, 0.012733f, 0.014458f, 0.016296f, 0.018478f, 0.021072f, 0.023666f, 0.026810f, 0.030746f, 0.035278f, 0.040131f, 0.046295f,
+ 0.053711f, 0.062195f, 0.072327f, 0.084717f, 0.099487f, 0.117371f, 0.139038f, 0.164795f, 0.195923f, 0.232422f, 0.274414f, 0.322266f,
+ 0.374756f, 0.431641f, 0.488525f, 0.545410f, 0.599121f, 0.650879f, 0.697754f, 0.738770f, 0.774414f, 0.806641f, 0.832520f, 0.856445f,
+ 0.875488f, 0.893555f, 0.907715f, 0.920410f, 0.931152f, 0.940918f, 0.978027f, 0.980469f, 0.980469f, 0.980957f, 0.980957f, 0.980957f,
+ 0.000279f, 0.000497f, 0.000763f, 0.001353f, 0.001794f, 0.002079f, 0.002451f, 0.002956f, 0.003498f, 0.004150f, 0.004589f, 0.005310f,
+ 0.006130f, 0.006958f, 0.007828f, 0.008888f, 0.009895f, 0.011124f, 0.012772f, 0.014282f, 0.016235f, 0.018127f, 0.020630f, 0.022873f,
+ 0.026321f, 0.029938f, 0.034241f, 0.039368f, 0.045319f, 0.052338f, 0.060852f, 0.070801f, 0.082947f, 0.097595f, 0.115051f, 0.136353f,
+ 0.162231f, 0.193481f, 0.229858f, 0.272217f, 0.321777f, 0.375000f, 0.432373f, 0.490479f, 0.548340f, 0.604004f, 0.655762f, 0.702637f,
+ 0.743652f, 0.780273f, 0.812500f, 0.838867f, 0.862305f, 0.881348f, 0.897949f, 0.912598f, 0.925293f, 0.935547f, 0.976562f, 0.978516f,
+ 0.979492f, 0.979980f, 0.979492f, 0.979004f, 0.000110f, 0.000473f, 0.000781f, 0.001262f, 0.001584f, 0.001890f, 0.002270f, 0.002607f,
+ 0.003241f, 0.003704f, 0.004055f, 0.004795f, 0.005356f, 0.005997f, 0.006760f, 0.007896f, 0.008896f, 0.009918f, 0.011200f, 0.012451f,
+ 0.013802f, 0.015556f, 0.017838f, 0.020065f, 0.022751f, 0.025864f, 0.029358f, 0.033600f, 0.038574f, 0.044342f, 0.050995f, 0.059296f,
+ 0.069214f, 0.081116f, 0.095459f, 0.113159f, 0.133911f, 0.160400f, 0.191406f, 0.228638f, 0.272217f, 0.321289f, 0.375732f, 0.434326f,
+ 0.493896f, 0.552734f, 0.609863f, 0.662109f, 0.709961f, 0.750977f, 0.787598f, 0.819336f, 0.846680f, 0.868164f, 0.887695f, 0.904297f,
+ 0.917969f, 0.930176f, 0.975098f, 0.977539f, 0.977051f, 0.977539f, 0.977539f, 0.977539f, 0.000242f, 0.000464f, 0.000831f, 0.001027f,
+ 0.001271f, 0.001722f, 0.001965f, 0.002243f, 0.002714f, 0.003036f, 0.003651f, 0.004025f, 0.004902f, 0.005638f, 0.006176f, 0.006943f,
+ 0.007763f, 0.008789f, 0.009804f, 0.010872f, 0.012070f, 0.013695f, 0.015381f, 0.017395f, 0.019608f, 0.022232f, 0.025009f, 0.028885f,
+ 0.032623f, 0.037659f, 0.043182f, 0.050018f, 0.058167f, 0.067810f, 0.079224f, 0.093811f, 0.111328f, 0.132324f, 0.158569f, 0.190063f,
+ 0.228149f, 0.271973f, 0.322510f, 0.378906f, 0.438477f, 0.499756f, 0.560059f, 0.618164f, 0.671387f, 0.718750f, 0.760742f, 0.796875f,
+ 0.826660f, 0.854492f, 0.875000f, 0.894531f, 0.911133f, 0.923828f, 0.973145f, 0.976074f, 0.975586f, 0.976074f, 0.976074f, 0.977051f,
+ 0.000242f, 0.000552f, 0.000701f, 0.001063f, 0.001186f, 0.001462f, 0.001690f, 0.002340f, 0.002703f, 0.002728f, 0.003325f, 0.003828f,
+ 0.004333f, 0.004913f, 0.005474f, 0.006077f, 0.006943f, 0.007607f, 0.008553f, 0.009460f, 0.010582f, 0.011871f, 0.013451f, 0.015091f,
+ 0.016983f, 0.019165f, 0.021637f, 0.024673f, 0.027863f, 0.031525f, 0.036713f, 0.041962f, 0.048615f, 0.056396f, 0.066162f, 0.077942f,
+ 0.092590f, 0.110046f, 0.130981f, 0.157593f, 0.189331f, 0.228394f, 0.273926f, 0.325684f, 0.383301f, 0.444580f, 0.507324f, 0.569824f,
+ 0.627441f, 0.682129f, 0.729980f, 0.770508f, 0.807129f, 0.837402f, 0.863281f, 0.884766f, 0.902832f, 0.917969f, 0.971191f, 0.973633f,
+ 0.974609f, 0.974121f, 0.974609f, 0.974609f, 0.000239f, 0.000239f, 0.000658f, 0.000899f, 0.001204f, 0.001252f, 0.001629f, 0.001815f,
+ 0.002470f, 0.002430f, 0.003134f, 0.003321f, 0.003925f, 0.004238f, 0.004856f, 0.005341f, 0.006161f, 0.006615f, 0.007511f, 0.008224f,
+ 0.009277f, 0.010445f, 0.011818f, 0.013046f, 0.014473f, 0.016510f, 0.018814f, 0.021057f, 0.023834f, 0.027237f, 0.030853f, 0.035675f,
+ 0.040894f, 0.047241f, 0.055145f, 0.064758f, 0.076782f, 0.090942f, 0.108398f, 0.130371f, 0.157104f, 0.189819f, 0.229248f, 0.276367f,
+ 0.329834f, 0.390137f, 0.453125f, 0.517578f, 0.580566f, 0.640625f, 0.694336f, 0.741699f, 0.782715f, 0.817871f, 0.848145f, 0.872559f,
+ 0.893555f, 0.910645f, 0.969727f, 0.971191f, 0.972656f, 0.972168f, 0.972168f, 0.972168f, 0.000222f, 0.000463f, 0.000620f, 0.000837f,
+ 0.000900f, 0.001048f, 0.001381f, 0.001820f, 0.001957f, 0.002329f, 0.002747f, 0.002964f, 0.003330f, 0.003986f, 0.004322f, 0.004677f,
+ 0.005302f, 0.005760f, 0.006569f, 0.007359f, 0.008141f, 0.009293f, 0.010101f, 0.011452f, 0.012779f, 0.014496f, 0.016144f, 0.018097f,
+ 0.020157f, 0.023148f, 0.026611f, 0.029785f, 0.034515f, 0.039856f, 0.046478f, 0.054016f, 0.063843f, 0.075378f, 0.089233f, 0.107666f,
+ 0.129639f, 0.156860f, 0.190674f, 0.231445f, 0.280518f, 0.336426f, 0.398193f, 0.463379f, 0.530273f, 0.595215f, 0.654785f, 0.708984f,
+ 0.755371f, 0.796875f, 0.831543f, 0.860352f, 0.883789f, 0.903809f, 0.966797f, 0.968750f, 0.969727f, 0.970215f, 0.970215f, 0.969727f,
+ 0.000000f, 0.000345f, 0.000464f, 0.000686f, 0.000782f, 0.001030f, 0.001139f, 0.001598f, 0.001846f, 0.002237f, 0.002489f, 0.002684f,
+ 0.003067f, 0.003344f, 0.003895f, 0.004158f, 0.004845f, 0.005131f, 0.005886f, 0.006561f, 0.007195f, 0.007912f, 0.008965f, 0.009941f,
+ 0.010956f, 0.012383f, 0.013893f, 0.015602f, 0.017303f, 0.019623f, 0.022156f, 0.025452f, 0.028976f, 0.033722f, 0.038910f, 0.045288f,
+ 0.052887f, 0.062561f, 0.074097f, 0.088623f, 0.106812f, 0.129639f, 0.157715f, 0.192261f, 0.235107f, 0.285889f, 0.344482f, 0.408691f,
+ 0.476807f, 0.545410f, 0.610840f, 0.671387f, 0.725098f, 0.771484f, 0.811035f, 0.843750f, 0.871582f, 0.894043f, 0.964355f, 0.967285f,
+ 0.967285f, 0.967773f, 0.967773f, 0.967773f, 0.000000f, 0.000320f, 0.000576f, 0.000572f, 0.000767f, 0.000945f, 0.001066f, 0.001375f,
+ 0.001848f, 0.001980f, 0.002190f, 0.002399f, 0.002695f, 0.002943f, 0.003397f, 0.003664f, 0.004063f, 0.004566f, 0.005119f, 0.005688f,
+ 0.006130f, 0.007057f, 0.007778f, 0.008675f, 0.009590f, 0.010666f, 0.011971f, 0.013443f, 0.015129f, 0.016953f, 0.018875f, 0.021576f,
+ 0.024658f, 0.028488f, 0.032959f, 0.037811f, 0.043793f, 0.051819f, 0.061371f, 0.073181f, 0.088257f, 0.106506f, 0.129883f, 0.159180f,
+ 0.195679f, 0.240479f, 0.293457f, 0.355225f, 0.422852f, 0.492432f, 0.563477f, 0.629883f, 0.690918f, 0.743652f, 0.789062f, 0.827148f,
+ 0.858398f, 0.884277f, 0.961914f, 0.964844f, 0.964355f, 0.964844f, 0.964355f, 0.965332f, 0.000000f, 0.000242f, 0.000435f, 0.000547f,
+ 0.000688f, 0.000803f, 0.001175f, 0.001318f, 0.001593f, 0.001652f, 0.001961f, 0.002209f, 0.002481f, 0.002716f, 0.002911f, 0.003210f,
+ 0.003595f, 0.004005f, 0.004490f, 0.004894f, 0.005508f, 0.006107f, 0.006714f, 0.007462f, 0.008438f, 0.009277f, 0.010170f, 0.011436f,
+ 0.012756f, 0.014145f, 0.016205f, 0.018433f, 0.020966f, 0.023819f, 0.027405f, 0.031464f, 0.036713f, 0.043152f, 0.050842f, 0.060577f,
+ 0.071960f, 0.087219f, 0.106689f, 0.130371f, 0.161377f, 0.199585f, 0.246948f, 0.303467f, 0.367920f, 0.439697f, 0.512207f, 0.584473f,
+ 0.651855f, 0.712402f, 0.764160f, 0.808105f, 0.844727f, 0.875000f, 0.958008f, 0.961426f, 0.961914f, 0.961914f, 0.962402f, 0.961914f,
+ 0.000000f, 0.000237f, 0.000266f, 0.000387f, 0.000557f, 0.000691f, 0.000774f, 0.001221f, 0.001455f, 0.001492f, 0.001769f, 0.001896f,
+ 0.002151f, 0.002386f, 0.002529f, 0.002911f, 0.003147f, 0.003523f, 0.003862f, 0.004311f, 0.004848f, 0.005260f, 0.005795f, 0.006416f,
+ 0.007114f, 0.007942f, 0.008667f, 0.009666f, 0.010818f, 0.012184f, 0.013718f, 0.015541f, 0.017685f, 0.020126f, 0.023056f, 0.026306f,
+ 0.030853f, 0.035797f, 0.042053f, 0.049683f, 0.059784f, 0.072144f, 0.086914f, 0.106873f, 0.132202f, 0.164429f, 0.205200f, 0.255615f,
+ 0.315918f, 0.384521f, 0.458984f, 0.534668f, 0.607910f, 0.676758f, 0.735840f, 0.785645f, 0.828125f, 0.862305f, 0.955566f, 0.958008f,
+ 0.958984f, 0.958496f, 0.958984f, 0.958984f, 0.000000f, 0.000119f, 0.000234f, 0.000484f, 0.000603f, 0.000758f, 0.000934f, 0.000999f,
+ 0.001200f, 0.001343f, 0.001534f, 0.001725f, 0.001860f, 0.002056f, 0.002235f, 0.002445f, 0.002783f, 0.003115f, 0.003448f, 0.003757f,
+ 0.004192f, 0.004723f, 0.005077f, 0.005653f, 0.006172f, 0.006527f, 0.007328f, 0.008247f, 0.009140f, 0.010368f, 0.011711f, 0.013351f,
+ 0.014702f, 0.016937f, 0.019226f, 0.022156f, 0.025604f, 0.029877f, 0.034668f, 0.040710f, 0.048920f, 0.058624f, 0.071289f, 0.087219f,
+ 0.107727f, 0.134521f, 0.168701f, 0.212769f, 0.267090f, 0.331543f, 0.404785f, 0.482910f, 0.561523f, 0.635742f, 0.702637f, 0.760742f,
+ 0.809570f, 0.849121f, 0.951660f, 0.954590f, 0.955566f, 0.955566f, 0.956055f, 0.955566f, 0.000238f, 0.000218f, 0.000229f, 0.000242f,
+ 0.000313f, 0.000859f, 0.000623f, 0.000978f, 0.001021f, 0.001150f, 0.001320f, 0.001431f, 0.001546f, 0.001746f, 0.001895f, 0.002106f,
+ 0.002502f, 0.002630f, 0.002926f, 0.003296f, 0.003651f, 0.003918f, 0.004391f, 0.004910f, 0.005249f, 0.005558f, 0.006413f, 0.007114f,
+ 0.007866f, 0.008789f, 0.009872f, 0.011093f, 0.012413f, 0.013939f, 0.015945f, 0.018692f, 0.021225f, 0.024643f, 0.028687f, 0.033936f,
+ 0.040192f, 0.047791f, 0.058014f, 0.070923f, 0.087585f, 0.109131f, 0.137573f, 0.174683f, 0.222290f, 0.280762f, 0.350830f, 0.428955f,
+ 0.511230f, 0.592285f, 0.666992f, 0.733398f, 0.789062f, 0.834473f, 0.947754f, 0.951172f, 0.951660f, 0.951172f, 0.951660f, 0.951172f,
+ 0.000000f, 0.000205f, 0.000222f, 0.000344f, 0.000301f, 0.000775f, 0.000827f, 0.000719f, 0.000944f, 0.000976f, 0.001306f, 0.001249f,
+ 0.001404f, 0.001569f, 0.001604f, 0.001819f, 0.002182f, 0.002354f, 0.002569f, 0.002857f, 0.003113f, 0.003426f, 0.003649f, 0.004112f,
+ 0.004307f, 0.004925f, 0.005508f, 0.005802f, 0.006565f, 0.007450f, 0.008125f, 0.009079f, 0.010269f, 0.011665f, 0.013565f, 0.015213f,
+ 0.017410f, 0.020203f, 0.023743f, 0.028168f, 0.032684f, 0.039062f, 0.047058f, 0.057404f, 0.070984f, 0.088623f, 0.111389f, 0.142090f,
+ 0.182373f, 0.234253f, 0.298828f, 0.375000f, 0.458008f, 0.543945f, 0.627441f, 0.702148f, 0.765137f, 0.818359f, 0.942871f, 0.946289f,
+ 0.947266f, 0.947266f, 0.946777f, 0.947266f, 0.000064f, 0.000095f, 0.000197f, 0.000213f, 0.000459f, 0.000491f, 0.000647f, 0.000696f,
+ 0.000884f, 0.000911f, 0.001121f, 0.001115f, 0.001234f, 0.001371f, 0.001410f, 0.001743f, 0.001905f, 0.002016f, 0.002207f, 0.002438f,
+ 0.002714f, 0.002939f, 0.003183f, 0.003323f, 0.003727f, 0.004143f, 0.004555f, 0.005276f, 0.005531f, 0.006264f, 0.006702f, 0.007572f,
+ 0.008705f, 0.009712f, 0.011238f, 0.012650f, 0.014320f, 0.016815f, 0.019516f, 0.022400f, 0.026566f, 0.031799f, 0.038055f, 0.046417f,
+ 0.057037f, 0.071350f, 0.089722f, 0.114868f, 0.148193f, 0.192749f, 0.249878f, 0.321045f, 0.404053f, 0.493408f, 0.583008f, 0.666016f,
+ 0.739258f, 0.799316f, 0.937988f, 0.941406f, 0.941895f, 0.942383f, 0.942383f, 0.942383f, 0.000000f, 0.000007f, 0.000144f, 0.000427f,
+ 0.000443f, 0.000566f, 0.000589f, 0.000615f, 0.000725f, 0.000731f, 0.000896f, 0.000953f, 0.001062f, 0.001167f, 0.001344f, 0.001345f,
+ 0.001636f, 0.001774f, 0.001893f, 0.002069f, 0.002350f, 0.002457f, 0.002678f, 0.002743f, 0.003105f, 0.003513f, 0.003830f, 0.004227f,
+ 0.004589f, 0.005047f, 0.005669f, 0.006176f, 0.007153f, 0.007896f, 0.008911f, 0.010231f, 0.011818f, 0.013618f, 0.015465f, 0.018188f,
+ 0.021576f, 0.025452f, 0.030533f, 0.037048f, 0.045685f, 0.056915f, 0.071533f, 0.091675f, 0.118958f, 0.156006f, 0.205444f, 0.270020f,
+ 0.349609f, 0.439941f, 0.533691f, 0.625977f, 0.708984f, 0.778320f, 0.931641f, 0.936035f, 0.936523f, 0.937012f, 0.937012f, 0.937012f,
+ 0.000000f, 0.000000f, 0.000137f, 0.000262f, 0.000432f, 0.000437f, 0.000444f, 0.000590f, 0.000558f, 0.000606f, 0.000817f, 0.000877f,
+ 0.000909f, 0.000951f, 0.001191f, 0.001244f, 0.001373f, 0.001506f, 0.001702f, 0.001690f, 0.001955f, 0.001940f, 0.002283f, 0.002340f,
+ 0.002571f, 0.002871f, 0.003265f, 0.003475f, 0.003910f, 0.004181f, 0.004608f, 0.005112f, 0.005833f, 0.006416f, 0.007145f, 0.008209f,
+ 0.009636f, 0.010750f, 0.012642f, 0.014481f, 0.017197f, 0.020203f, 0.024353f, 0.029694f, 0.036041f, 0.045105f, 0.056702f, 0.072388f,
+ 0.094482f, 0.124329f, 0.166504f, 0.223022f, 0.295898f, 0.384766f, 0.482910f, 0.582031f, 0.675293f, 0.754883f, 0.926270f, 0.929688f,
+ 0.930664f, 0.930664f, 0.931152f, 0.930664f, 0.000000f, 0.000000f, 0.000000f, 0.000232f, 0.000357f, 0.000411f, 0.000513f, 0.000527f,
+ 0.000490f, 0.000504f, 0.000653f, 0.000750f, 0.000780f, 0.000976f, 0.000942f, 0.000967f, 0.001180f, 0.001252f, 0.001385f, 0.001425f,
+ 0.001559f, 0.001801f, 0.001886f, 0.002144f, 0.002111f, 0.002354f, 0.002645f, 0.002827f, 0.003187f, 0.003414f, 0.003792f, 0.004360f,
+ 0.004662f, 0.005146f, 0.005875f, 0.006783f, 0.007610f, 0.008797f, 0.010033f, 0.011566f, 0.013565f, 0.016006f, 0.019165f, 0.023163f,
+ 0.028320f, 0.035400f, 0.044647f, 0.057129f, 0.074402f, 0.098572f, 0.132812f, 0.180542f, 0.245728f, 0.330078f, 0.428955f, 0.535156f,
+ 0.638184f, 0.728516f, 0.919434f, 0.922852f, 0.923828f, 0.923828f, 0.923828f, 0.924316f, 0.000000f, 0.000000f, 0.000000f, 0.000114f,
+ 0.000248f, 0.000359f, 0.000386f, 0.000342f, 0.000465f, 0.000461f, 0.000490f, 0.000609f, 0.000638f, 0.000694f, 0.000807f, 0.000923f,
+ 0.000961f, 0.001074f, 0.001123f, 0.001268f, 0.001311f, 0.001494f, 0.001537f, 0.001754f, 0.001899f, 0.001917f, 0.002199f, 0.002241f,
+ 0.002583f, 0.002769f, 0.003101f, 0.003441f, 0.003775f, 0.004200f, 0.004787f, 0.005272f, 0.006062f, 0.006702f, 0.007732f, 0.009102f,
+ 0.010582f, 0.012466f, 0.014984f, 0.017990f, 0.021957f, 0.027222f, 0.034332f, 0.044128f, 0.057434f, 0.076538f, 0.104126f, 0.143799f,
+ 0.199829f, 0.275879f, 0.373047f, 0.482422f, 0.594727f, 0.698730f, 0.910645f, 0.914551f, 0.916504f, 0.916016f, 0.916504f, 0.915527f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000121f, 0.000221f, 0.000222f, 0.000392f, 0.000402f, 0.000396f, 0.000434f, 0.000476f, 0.000548f,
+ 0.000536f, 0.000644f, 0.000642f, 0.000793f, 0.000795f, 0.000912f, 0.000953f, 0.000989f, 0.001164f, 0.001197f, 0.001285f, 0.001480f,
+ 0.001511f, 0.001674f, 0.001703f, 0.001901f, 0.002075f, 0.002340f, 0.002499f, 0.002800f, 0.003019f, 0.003296f, 0.003695f, 0.004093f,
+ 0.004780f, 0.005260f, 0.006207f, 0.006939f, 0.008034f, 0.009598f, 0.011353f, 0.013702f, 0.016678f, 0.020874f, 0.026062f, 0.033539f,
+ 0.044006f, 0.058746f, 0.080139f, 0.111877f, 0.158447f, 0.226318f, 0.317627f, 0.428711f, 0.548828f, 0.665039f, 0.901367f, 0.907227f,
+ 0.907715f, 0.908203f, 0.908203f, 0.907227f, 0.000000f, 0.000000f, 0.000122f, 0.000173f, 0.000191f, 0.000215f, 0.000224f, 0.000261f,
+ 0.000340f, 0.000374f, 0.000380f, 0.000496f, 0.000416f, 0.000535f, 0.000592f, 0.000622f, 0.000701f, 0.000772f, 0.000742f, 0.000774f,
+ 0.000990f, 0.000945f, 0.001088f, 0.001105f, 0.001348f, 0.001231f, 0.001460f, 0.001620f, 0.001758f, 0.001941f, 0.002008f, 0.002092f,
+ 0.002430f, 0.002615f, 0.002886f, 0.003208f, 0.003519f, 0.004112f, 0.004704f, 0.005371f, 0.006149f, 0.007351f, 0.008659f, 0.010201f,
+ 0.012550f, 0.015549f, 0.019577f, 0.025436f, 0.032928f, 0.044220f, 0.060608f, 0.084961f, 0.123474f, 0.180664f, 0.263184f, 0.372314f,
+ 0.498291f, 0.626465f, 0.892578f, 0.895996f, 0.896973f, 0.896973f, 0.897949f, 0.897949f, 0.000000f, 0.000000f, 0.000121f, 0.000121f,
+ 0.000120f, 0.000192f, 0.000201f, 0.000222f, 0.000222f, 0.000276f, 0.000295f, 0.000344f, 0.000433f, 0.000470f, 0.000485f, 0.000549f,
+ 0.000555f, 0.000558f, 0.000566f, 0.000639f, 0.000678f, 0.000757f, 0.000840f, 0.000905f, 0.000999f, 0.000946f, 0.001018f, 0.001309f,
+ 0.001402f, 0.001417f, 0.001624f, 0.001692f, 0.001869f, 0.002003f, 0.002184f, 0.002602f, 0.002851f, 0.003157f, 0.003595f, 0.004063f,
+ 0.004734f, 0.005398f, 0.006275f, 0.007542f, 0.009148f, 0.011383f, 0.014275f, 0.018250f, 0.024063f, 0.032135f, 0.044922f, 0.063721f,
+ 0.093811f, 0.139648f, 0.211914f, 0.314697f, 0.444092f, 0.584961f, 0.879883f, 0.884766f, 0.885254f, 0.885742f, 0.886230f, 0.885742f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000120f, 0.000154f, 0.000150f, 0.000160f, 0.000202f, 0.000217f, 0.000308f, 0.000319f,
+ 0.000278f, 0.000392f, 0.000362f, 0.000432f, 0.000416f, 0.000448f, 0.000495f, 0.000526f, 0.000710f, 0.000754f, 0.000657f, 0.000755f,
+ 0.000806f, 0.000919f, 0.000815f, 0.001080f, 0.001152f, 0.001207f, 0.001218f, 0.001373f, 0.001320f, 0.001685f, 0.001764f, 0.001819f,
+ 0.002068f, 0.002380f, 0.002668f, 0.003033f, 0.003584f, 0.003979f, 0.004829f, 0.005402f, 0.006630f, 0.008080f, 0.010254f, 0.013069f,
+ 0.017044f, 0.023422f, 0.031647f, 0.046417f, 0.068604f, 0.104919f, 0.165161f, 0.258789f, 0.387207f, 0.537598f, 0.867188f, 0.871582f,
+ 0.872559f, 0.872559f, 0.872559f, 0.873047f, 0.000000f, 0.000121f, 0.000120f, 0.000120f, 0.000119f, 0.000118f, 0.000122f, 0.000108f,
+ 0.000143f, 0.000149f, 0.000184f, 0.000194f, 0.000189f, 0.000210f, 0.000321f, 0.000282f, 0.000376f, 0.000420f, 0.000533f, 0.000437f,
+ 0.000467f, 0.000477f, 0.000587f, 0.000519f, 0.000673f, 0.000662f, 0.000679f, 0.000845f, 0.000881f, 0.000863f, 0.001016f, 0.001093f,
+ 0.001176f, 0.001191f, 0.001336f, 0.001561f, 0.001573f, 0.001754f, 0.001919f, 0.002264f, 0.002596f, 0.002911f, 0.003372f, 0.003870f,
+ 0.004723f, 0.005733f, 0.007092f, 0.008965f, 0.011650f, 0.015701f, 0.022339f, 0.032043f, 0.048370f, 0.076050f, 0.124084f, 0.204834f,
+ 0.328369f, 0.485596f, 0.852539f, 0.856934f, 0.858887f, 0.858887f, 0.858887f, 0.858398f, 0.000000f, 0.000121f, 0.000120f, 0.000119f,
+ 0.000118f, 0.000117f, 0.000116f, 0.000114f, 0.000105f, 0.000110f, 0.000165f, 0.000133f, 0.000157f, 0.000240f, 0.000256f, 0.000257f,
+ 0.000249f, 0.000303f, 0.000342f, 0.000346f, 0.000485f, 0.000510f, 0.000398f, 0.000493f, 0.000492f, 0.000524f, 0.000590f, 0.000585f,
+ 0.000601f, 0.000740f, 0.000647f, 0.000871f, 0.000834f, 0.000969f, 0.001020f, 0.001190f, 0.001244f, 0.001432f, 0.001393f, 0.001702f,
+ 0.001912f, 0.002171f, 0.002445f, 0.002958f, 0.003330f, 0.004025f, 0.004860f, 0.006161f, 0.007896f, 0.010742f, 0.014671f, 0.021378f,
+ 0.032928f, 0.052612f, 0.089050f, 0.155884f, 0.268555f, 0.430664f, 0.836426f, 0.841309f, 0.841309f, 0.842285f, 0.842773f, 0.842285f,
+ 0.000000f, 0.000000f, 0.000119f, 0.000117f, 0.000116f, 0.000115f, 0.000114f, 0.000114f, 0.000111f, 0.000103f, 0.000097f, 0.000118f,
+ 0.000115f, 0.000130f, 0.000176f, 0.000130f, 0.000223f, 0.000235f, 0.000244f, 0.000252f, 0.000274f, 0.000389f, 0.000309f, 0.000430f,
+ 0.000340f, 0.000399f, 0.000408f, 0.000459f, 0.000514f, 0.000501f, 0.000519f, 0.000657f, 0.000588f, 0.000775f, 0.000813f, 0.000789f,
+ 0.000904f, 0.001076f, 0.001027f, 0.001170f, 0.001342f, 0.001425f, 0.001662f, 0.002005f, 0.002298f, 0.002699f, 0.003227f, 0.003990f,
+ 0.005062f, 0.006855f, 0.009415f, 0.013504f, 0.020905f, 0.034424f, 0.060333f, 0.112000f, 0.210693f, 0.371094f, 0.816406f, 0.822754f,
+ 0.822754f, 0.823242f, 0.823242f, 0.823730f, 0.000000f, 0.000119f, 0.000117f, 0.000116f, 0.000114f, 0.000113f, 0.000112f, 0.000111f,
+ 0.000110f, 0.000109f, 0.000102f, 0.000095f, 0.000090f, 0.000084f, 0.000093f, 0.000103f, 0.000118f, 0.000165f, 0.000162f, 0.000190f,
+ 0.000204f, 0.000218f, 0.000223f, 0.000237f, 0.000256f, 0.000272f, 0.000344f, 0.000365f, 0.000365f, 0.000396f, 0.000386f, 0.000412f,
+ 0.000530f, 0.000466f, 0.000492f, 0.000615f, 0.000611f, 0.000748f, 0.000712f, 0.000795f, 0.000908f, 0.000971f, 0.001106f, 0.001353f,
+ 0.001572f, 0.001822f, 0.002251f, 0.002676f, 0.003290f, 0.004349f, 0.005951f, 0.008316f, 0.012543f, 0.021149f, 0.038025f, 0.075500f,
+ 0.156006f, 0.308838f, 0.794922f, 0.800293f, 0.800781f, 0.801270f, 0.801758f, 0.802246f, 0.000121f, 0.000116f, 0.000114f, 0.000113f,
+ 0.000111f, 0.000109f, 0.000108f, 0.000107f, 0.000106f, 0.000104f, 0.000104f, 0.000100f, 0.000094f, 0.000088f, 0.000083f, 0.000078f,
+ 0.000074f, 0.000105f, 0.000078f, 0.000122f, 0.000113f, 0.000153f, 0.000174f, 0.000175f, 0.000207f, 0.000216f, 0.000225f, 0.000215f,
+ 0.000262f, 0.000308f, 0.000297f, 0.000287f, 0.000307f, 0.000342f, 0.000363f, 0.000411f, 0.000401f, 0.000453f, 0.000522f, 0.000555f,
+ 0.000680f, 0.000701f, 0.000751f, 0.000873f, 0.000966f, 0.001181f, 0.001445f, 0.001666f, 0.002077f, 0.002512f, 0.003359f, 0.004856f,
+ 0.007347f, 0.012001f, 0.022049f, 0.046417f, 0.107117f, 0.245361f, 0.770508f, 0.775879f, 0.776367f, 0.776855f, 0.777344f, 0.777832f,
+ 0.000000f, 0.000113f, 0.000108f, 0.000107f, 0.000104f, 0.000103f, 0.000101f, 0.000100f, 0.000099f, 0.000098f, 0.000097f, 0.000096f,
+ 0.000095f, 0.000091f, 0.000086f, 0.000081f, 0.000077f, 0.000073f, 0.000069f, 0.000079f, 0.000084f, 0.000091f, 0.000074f, 0.000100f,
+ 0.000117f, 0.000140f, 0.000144f, 0.000166f, 0.000174f, 0.000178f, 0.000225f, 0.000197f, 0.000234f, 0.000239f, 0.000273f, 0.000289f,
+ 0.000283f, 0.000293f, 0.000338f, 0.000386f, 0.000386f, 0.000432f, 0.000459f, 0.000525f, 0.000625f, 0.000691f, 0.000800f, 0.001004f,
+ 0.001227f, 0.001479f, 0.001984f, 0.002745f, 0.003983f, 0.006413f, 0.011642f, 0.025269f, 0.066040f, 0.182495f, 0.743164f, 0.748535f,
+ 0.749023f, 0.749512f, 0.750000f, 0.749512f, 0.000000f, 0.000102f, 0.000101f, 0.000098f, 0.000094f, 0.000093f, 0.000092f, 0.000090f,
+ 0.000089f, 0.000088f, 0.000087f, 0.000086f, 0.000085f, 0.000084f, 0.000085f, 0.000082f, 0.000078f, 0.000074f, 0.000070f, 0.000066f,
+ 0.000063f, 0.000060f, 0.000057f, 0.000056f, 0.000061f, 0.000060f, 0.000073f, 0.000087f, 0.000100f, 0.000105f, 0.000124f, 0.000136f,
+ 0.000140f, 0.000140f, 0.000159f, 0.000179f, 0.000186f, 0.000205f, 0.000214f, 0.000229f, 0.000248f, 0.000267f, 0.000299f, 0.000344f,
+ 0.000367f, 0.000422f, 0.000496f, 0.000557f, 0.000639f, 0.000837f, 0.001037f, 0.001419f, 0.002081f, 0.003202f, 0.005730f, 0.012199f,
+ 0.034943f, 0.122925f, 0.711426f, 0.716797f, 0.718750f, 0.718262f, 0.718262f, 0.718750f, 0.000094f, 0.000079f, 0.000078f, 0.000074f,
+ 0.000074f, 0.000075f, 0.000074f, 0.000073f, 0.000071f, 0.000072f, 0.000070f, 0.000071f, 0.000071f, 0.000070f, 0.000070f, 0.000069f,
+ 0.000070f, 0.000069f, 0.000068f, 0.000065f, 0.000062f, 0.000059f, 0.000056f, 0.000053f, 0.000050f, 0.000048f, 0.000045f, 0.000044f,
+ 0.000041f, 0.000050f, 0.000050f, 0.000061f, 0.000068f, 0.000085f, 0.000091f, 0.000101f, 0.000102f, 0.000107f, 0.000119f, 0.000129f,
+ 0.000144f, 0.000151f, 0.000160f, 0.000184f, 0.000212f, 0.000213f, 0.000235f, 0.000294f, 0.000315f, 0.000392f, 0.000505f, 0.000637f,
+ 0.000880f, 0.001400f, 0.002462f, 0.005333f, 0.015160f, 0.070312f, 0.678223f, 0.683105f, 0.684082f, 0.684570f, 0.684570f, 0.684570f,
+ 0.000000f, 0.000000f, 0.000023f, 0.000034f, 0.000032f, 0.000038f, 0.000037f, 0.000044f, 0.000043f, 0.000047f, 0.000045f, 0.000047f,
+ 0.000049f, 0.000049f, 0.000049f, 0.000048f, 0.000051f, 0.000050f, 0.000051f, 0.000051f, 0.000052f, 0.000052f, 0.000052f, 0.000049f,
+ 0.000047f, 0.000045f, 0.000042f, 0.000040f, 0.000038f, 0.000036f, 0.000035f, 0.000033f, 0.000031f, 0.000029f, 0.000038f, 0.000037f,
+ 0.000042f, 0.000051f, 0.000055f, 0.000067f, 0.000074f, 0.000073f, 0.000083f, 0.000093f, 0.000088f, 0.000102f, 0.000122f, 0.000122f,
+ 0.000142f, 0.000169f, 0.000206f, 0.000265f, 0.000355f, 0.000531f, 0.000897f, 0.001822f, 0.005493f, 0.030579f, 0.640137f, 0.644531f,
+ 0.647461f, 0.647949f, 0.647461f, 0.648438f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000001f, 0.000000f, 0.000008f, 0.000012f, 0.000014f, 0.000014f, 0.000019f, 0.000021f, 0.000022f, 0.000024f, 0.000026f, 0.000027f,
+ 0.000027f, 0.000028f, 0.000029f, 0.000031f, 0.000031f, 0.000032f, 0.000032f, 0.000033f, 0.000033f, 0.000032f, 0.000030f, 0.000029f,
+ 0.000027f, 0.000026f, 0.000024f, 0.000023f, 0.000022f, 0.000021f, 0.000019f, 0.000018f, 0.000021f, 0.000024f, 0.000028f, 0.000033f,
+ 0.000043f, 0.000041f, 0.000046f, 0.000053f, 0.000050f, 0.000059f, 0.000068f, 0.000094f, 0.000096f, 0.000140f, 0.000239f, 0.000447f,
+ 0.001340f, 0.009087f, 0.600098f, 0.605957f, 0.606934f, 0.606934f, 0.607422f, 0.606934f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000002f, 0.000004f, 0.000006f, 0.000006f,
+ 0.000009f, 0.000010f, 0.000011f, 0.000012f, 0.000013f, 0.000014f, 0.000015f, 0.000016f, 0.000017f, 0.000016f, 0.000015f, 0.000014f,
+ 0.000013f, 0.000012f, 0.000012f, 0.000011f, 0.000010f, 0.000009f, 0.000008f, 0.000012f, 0.000014f, 0.000018f, 0.000017f, 0.000022f,
+ 0.000022f, 0.000026f, 0.000040f, 0.000060f, 0.000157f, 0.001244f, 0.557129f, 0.563477f, 0.563477f, 0.564941f, 0.564941f, 0.564941f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000002f, 0.000003f,
+ 0.000003f, 0.000004f, 0.000003f, 0.000003f, 0.000003f, 0.000002f, 0.000003f, 0.000003f, 0.000003f, 0.000012f, 0.513672f, 0.520020f,
+ 0.520020f, 0.520508f, 0.521484f, 0.521484f,
+ },
+ {
+ 0.103943f, 0.284912f, 0.422119f, 0.523438f, 0.600586f, 0.659668f, 0.705078f, 0.741699f, 0.771484f, 0.795898f, 0.816895f, 0.834961f,
+ 0.850586f, 0.862793f, 0.874512f, 0.884277f, 0.894043f, 0.901855f, 0.909180f, 0.915039f, 0.921387f, 0.926270f, 0.932129f, 0.936035f,
+ 0.940430f, 0.944336f, 0.948242f, 0.951660f, 0.954590f, 0.957520f, 0.959961f, 0.962891f, 0.965332f, 0.967285f, 0.969727f, 0.971680f,
+ 0.973145f, 0.975586f, 0.977051f, 0.979004f, 0.979980f, 0.981934f, 0.983887f, 0.984375f, 0.985840f, 0.986816f, 0.988770f, 0.989258f,
+ 0.990723f, 0.992188f, 0.992676f, 0.993652f, 0.994629f, 0.995605f, 0.996582f, 0.997559f, 0.998535f, 0.999023f, 0.999512f, 0.999023f,
+ 0.998535f, 0.998047f, 0.997559f, 0.997070f, 0.046997f, 0.153564f, 0.264160f, 0.369385f, 0.460205f, 0.538574f, 0.602051f, 0.654785f,
+ 0.697754f, 0.733398f, 0.762695f, 0.787598f, 0.809082f, 0.827637f, 0.843262f, 0.856934f, 0.868652f, 0.880859f, 0.889648f, 0.898438f,
+ 0.906738f, 0.912598f, 0.918945f, 0.924805f, 0.929688f, 0.935059f, 0.938965f, 0.943359f, 0.947266f, 0.951172f, 0.954102f, 0.956543f,
+ 0.959961f, 0.961914f, 0.964844f, 0.966797f, 0.969727f, 0.971191f, 0.974121f, 0.975098f, 0.977051f, 0.979492f, 0.980469f, 0.981934f,
+ 0.983887f, 0.985352f, 0.985840f, 0.987305f, 0.989258f, 0.990234f, 0.991211f, 0.992188f, 0.993164f, 0.994141f, 0.995117f, 0.996094f,
+ 0.996582f, 0.997559f, 0.999023f, 0.998535f, 0.998047f, 0.997559f, 0.997070f, 0.997070f, 0.025940f, 0.088501f, 0.162964f, 0.246094f,
+ 0.331055f, 0.411865f, 0.486328f, 0.550293f, 0.606934f, 0.655762f, 0.695312f, 0.729980f, 0.758301f, 0.783691f, 0.804199f, 0.823730f,
+ 0.838867f, 0.853027f, 0.865723f, 0.877441f, 0.887207f, 0.895996f, 0.904785f, 0.911133f, 0.916992f, 0.923828f, 0.928223f, 0.933594f,
+ 0.937988f, 0.942871f, 0.946777f, 0.950195f, 0.953613f, 0.956543f, 0.959473f, 0.962402f, 0.964844f, 0.967285f, 0.970215f, 0.971680f,
+ 0.973633f, 0.976074f, 0.977539f, 0.979492f, 0.980469f, 0.982422f, 0.984863f, 0.985352f, 0.986816f, 0.987793f, 0.989258f, 0.990234f,
+ 0.991699f, 0.992676f, 0.994141f, 0.995117f, 0.995605f, 0.996582f, 0.998535f, 0.998047f, 0.998047f, 0.997559f, 0.997070f, 0.996582f,
+ 0.016159f, 0.055176f, 0.104126f, 0.162720f, 0.229126f, 0.300781f, 0.372803f, 0.442871f, 0.506836f, 0.563477f, 0.613281f, 0.657715f,
+ 0.696289f, 0.729004f, 0.757324f, 0.782227f, 0.802734f, 0.821289f, 0.837402f, 0.852539f, 0.865234f, 0.875977f, 0.885742f, 0.895508f,
+ 0.903320f, 0.910156f, 0.917480f, 0.922852f, 0.928711f, 0.934082f, 0.937988f, 0.942871f, 0.947266f, 0.950195f, 0.954102f, 0.957031f,
+ 0.959473f, 0.962402f, 0.964844f, 0.968262f, 0.969727f, 0.972168f, 0.974121f, 0.976562f, 0.978516f, 0.979980f, 0.981934f, 0.982910f,
+ 0.983887f, 0.985840f, 0.986816f, 0.988770f, 0.989746f, 0.991211f, 0.992188f, 0.993652f, 0.994141f, 0.995117f, 0.998047f, 0.997559f,
+ 0.997559f, 0.997070f, 0.996582f, 0.996582f, 0.010841f, 0.036865f, 0.070007f, 0.110962f, 0.159546f, 0.214355f, 0.276367f, 0.340576f,
+ 0.405029f, 0.465820f, 0.523926f, 0.576172f, 0.623535f, 0.664062f, 0.699707f, 0.731445f, 0.758301f, 0.782227f, 0.803223f, 0.821289f,
+ 0.837891f, 0.852051f, 0.864258f, 0.875488f, 0.884766f, 0.894531f, 0.903320f, 0.910156f, 0.916992f, 0.923828f, 0.928223f, 0.933594f,
+ 0.938477f, 0.943359f, 0.947266f, 0.950684f, 0.954102f, 0.957520f, 0.960449f, 0.962891f, 0.965820f, 0.968750f, 0.971191f, 0.973145f,
+ 0.975586f, 0.977539f, 0.978516f, 0.980957f, 0.982422f, 0.984375f, 0.985352f, 0.987305f, 0.988281f, 0.989746f, 0.990723f, 0.992188f,
+ 0.993164f, 0.994141f, 0.997559f, 0.997559f, 0.997070f, 0.996582f, 0.996582f, 0.996094f, 0.007637f, 0.026566f, 0.049896f, 0.078247f,
+ 0.113403f, 0.154663f, 0.202637f, 0.255371f, 0.313232f, 0.372314f, 0.431152f, 0.488037f, 0.540039f, 0.588867f, 0.633301f, 0.670898f,
+ 0.704102f, 0.734375f, 0.761230f, 0.785156f, 0.804688f, 0.822754f, 0.838867f, 0.852539f, 0.864746f, 0.876953f, 0.886230f, 0.895996f,
+ 0.903320f, 0.910645f, 0.917480f, 0.923828f, 0.929199f, 0.935059f, 0.938965f, 0.943359f, 0.948730f, 0.952148f, 0.954590f, 0.958496f,
+ 0.961426f, 0.964355f, 0.966797f, 0.969238f, 0.971680f, 0.974121f, 0.976074f, 0.978027f, 0.979980f, 0.981445f, 0.982910f, 0.984863f,
+ 0.986816f, 0.987793f, 0.989258f, 0.990723f, 0.991699f, 0.993164f, 0.996582f, 0.996582f, 0.996094f, 0.996094f, 0.996094f, 0.995605f,
+ 0.005714f, 0.019485f, 0.036194f, 0.056976f, 0.082336f, 0.113342f, 0.149048f, 0.191284f, 0.238770f, 0.290039f, 0.344727f, 0.400391f,
+ 0.454590f, 0.507324f, 0.557129f, 0.602539f, 0.642578f, 0.679199f, 0.711426f, 0.740234f, 0.766602f, 0.788574f, 0.807617f, 0.825195f,
+ 0.841309f, 0.854980f, 0.867676f, 0.877930f, 0.888184f, 0.896484f, 0.904785f, 0.912109f, 0.918945f, 0.925293f, 0.930176f, 0.935547f,
+ 0.940918f, 0.944336f, 0.948730f, 0.952637f, 0.956055f, 0.959473f, 0.962402f, 0.965332f, 0.967773f, 0.970703f, 0.972656f, 0.975098f,
+ 0.977051f, 0.979004f, 0.981445f, 0.982910f, 0.984375f, 0.985840f, 0.987793f, 0.989258f, 0.990234f, 0.991211f, 0.996094f, 0.996094f,
+ 0.996094f, 0.996094f, 0.995605f, 0.995117f, 0.004505f, 0.014908f, 0.027634f, 0.043274f, 0.061707f, 0.084045f, 0.111694f, 0.143921f,
+ 0.180542f, 0.223877f, 0.270996f, 0.320557f, 0.373291f, 0.425781f, 0.478027f, 0.526855f, 0.573242f, 0.615723f, 0.654785f, 0.688965f,
+ 0.720215f, 0.747559f, 0.771973f, 0.793457f, 0.812500f, 0.829102f, 0.844238f, 0.858398f, 0.870117f, 0.881348f, 0.890625f, 0.898926f,
+ 0.906738f, 0.914062f, 0.921387f, 0.926758f, 0.932617f, 0.937500f, 0.942383f, 0.945801f, 0.950684f, 0.954102f, 0.958008f, 0.960938f,
+ 0.964355f, 0.966797f, 0.969727f, 0.972656f, 0.974609f, 0.976562f, 0.978516f, 0.980469f, 0.981934f, 0.984375f, 0.985840f, 0.987793f,
+ 0.988281f, 0.990234f, 0.995605f, 0.995605f, 0.995605f, 0.995605f, 0.995117f, 0.994629f, 0.003691f, 0.011925f, 0.021622f, 0.033203f,
+ 0.047241f, 0.065247f, 0.085266f, 0.109558f, 0.138550f, 0.172363f, 0.210205f, 0.253418f, 0.299805f, 0.348877f, 0.400146f, 0.450195f,
+ 0.499512f, 0.546387f, 0.589844f, 0.629883f, 0.666016f, 0.700195f, 0.728516f, 0.755371f, 0.778320f, 0.798828f, 0.817383f, 0.833984f,
+ 0.848145f, 0.861816f, 0.874023f, 0.883789f, 0.893555f, 0.902344f, 0.910645f, 0.916992f, 0.922852f, 0.929688f, 0.934570f, 0.938965f,
+ 0.944336f, 0.948730f, 0.951660f, 0.956543f, 0.959473f, 0.962891f, 0.965820f, 0.968262f, 0.970703f, 0.974121f, 0.976074f, 0.978516f,
+ 0.979980f, 0.981934f, 0.983887f, 0.985840f, 0.987305f, 0.988281f, 0.994629f, 0.995117f, 0.995117f, 0.994629f, 0.994629f, 0.994141f,
+ 0.002726f, 0.009560f, 0.017136f, 0.026871f, 0.037415f, 0.050079f, 0.066406f, 0.084717f, 0.107849f, 0.133423f, 0.164062f, 0.198853f,
+ 0.238281f, 0.281250f, 0.327148f, 0.375977f, 0.424805f, 0.473877f, 0.521973f, 0.564941f, 0.606934f, 0.644531f, 0.679199f, 0.710449f,
+ 0.738770f, 0.764160f, 0.786133f, 0.805664f, 0.824219f, 0.838867f, 0.853516f, 0.866211f, 0.876953f, 0.887695f, 0.896484f, 0.905762f,
+ 0.912598f, 0.919922f, 0.925781f, 0.932129f, 0.937500f, 0.942383f, 0.946777f, 0.951660f, 0.955078f, 0.958984f, 0.961426f, 0.965332f,
+ 0.967773f, 0.970703f, 0.972656f, 0.975586f, 0.978027f, 0.979492f, 0.981934f, 0.983887f, 0.984863f, 0.986816f, 0.994629f, 0.994629f,
+ 0.994629f, 0.994141f, 0.994141f, 0.993652f, 0.002487f, 0.007553f, 0.013863f, 0.021439f, 0.029755f, 0.040771f, 0.052643f, 0.067444f,
+ 0.084473f, 0.104980f, 0.128784f, 0.157227f, 0.189087f, 0.224609f, 0.265381f, 0.308838f, 0.354004f, 0.401611f, 0.450439f, 0.496582f,
+ 0.541992f, 0.583984f, 0.623047f, 0.660645f, 0.693359f, 0.722168f, 0.749512f, 0.772949f, 0.793457f, 0.812988f, 0.830078f, 0.845215f,
+ 0.859375f, 0.871094f, 0.882812f, 0.892090f, 0.900879f, 0.908691f, 0.916504f, 0.922852f, 0.930176f, 0.935547f, 0.940430f, 0.944824f,
+ 0.949219f, 0.952637f, 0.956543f, 0.960449f, 0.963867f, 0.967285f, 0.970215f, 0.972656f, 0.974609f, 0.977539f, 0.979492f, 0.981934f,
+ 0.983887f, 0.985352f, 0.993652f, 0.994141f, 0.994141f, 0.993652f, 0.993652f, 0.993164f, 0.001893f, 0.006641f, 0.011551f, 0.017319f,
+ 0.024612f, 0.032959f, 0.042023f, 0.053772f, 0.067444f, 0.083435f, 0.102356f, 0.123840f, 0.150024f, 0.179688f, 0.213501f, 0.250488f,
+ 0.291992f, 0.335938f, 0.381592f, 0.427246f, 0.473877f, 0.518555f, 0.563477f, 0.603027f, 0.640625f, 0.676270f, 0.707031f, 0.735352f,
+ 0.760254f, 0.782715f, 0.802734f, 0.821777f, 0.838379f, 0.851562f, 0.865234f, 0.876953f, 0.886719f, 0.896484f, 0.905273f, 0.913086f,
+ 0.921387f, 0.927734f, 0.933105f, 0.938477f, 0.942871f, 0.948242f, 0.951660f, 0.955566f, 0.959961f, 0.963867f, 0.966309f, 0.969238f,
+ 0.972168f, 0.975098f, 0.977539f, 0.979492f, 0.981934f, 0.983887f, 0.993164f, 0.993652f, 0.993164f, 0.993164f, 0.993164f, 0.992676f,
+ 0.001740f, 0.005634f, 0.009407f, 0.014992f, 0.020157f, 0.026840f, 0.035156f, 0.043793f, 0.054718f, 0.067505f, 0.082092f, 0.099731f,
+ 0.120239f, 0.143921f, 0.171265f, 0.202393f, 0.237915f, 0.276367f, 0.318848f, 0.362793f, 0.407959f, 0.454346f, 0.499023f, 0.542480f,
+ 0.583984f, 0.623535f, 0.659180f, 0.691895f, 0.721680f, 0.748047f, 0.772461f, 0.793457f, 0.812988f, 0.829102f, 0.845215f, 0.859863f,
+ 0.872559f, 0.883789f, 0.893555f, 0.902344f, 0.911133f, 0.918457f, 0.924805f, 0.930664f, 0.937012f, 0.941895f, 0.947266f, 0.951172f,
+ 0.956055f, 0.959473f, 0.962402f, 0.966309f, 0.968750f, 0.972168f, 0.974609f, 0.977051f, 0.979492f, 0.981934f, 0.992188f, 0.992676f,
+ 0.992676f, 0.992676f, 0.992188f, 0.992676f, 0.001502f, 0.004482f, 0.008278f, 0.012276f, 0.016800f, 0.022644f, 0.029129f, 0.036194f,
+ 0.045197f, 0.055298f, 0.067017f, 0.080750f, 0.096863f, 0.115906f, 0.138184f, 0.163940f, 0.192993f, 0.225952f, 0.262695f, 0.302490f,
+ 0.344971f, 0.389648f, 0.434814f, 0.480469f, 0.523926f, 0.566406f, 0.605957f, 0.643066f, 0.677246f, 0.708496f, 0.736816f, 0.761719f,
+ 0.784668f, 0.804688f, 0.823242f, 0.840332f, 0.854004f, 0.867188f, 0.878906f, 0.890137f, 0.898438f, 0.907715f, 0.916016f, 0.922852f,
+ 0.930176f, 0.935547f, 0.940918f, 0.946289f, 0.950684f, 0.955078f, 0.959473f, 0.961914f, 0.966309f, 0.969238f, 0.972168f, 0.974609f,
+ 0.977539f, 0.979492f, 0.991211f, 0.992188f, 0.991699f, 0.992188f, 0.991699f, 0.991211f, 0.001411f, 0.003645f, 0.007160f, 0.010414f,
+ 0.014397f, 0.018677f, 0.024338f, 0.030426f, 0.037384f, 0.045654f, 0.055054f, 0.066101f, 0.079529f, 0.094543f, 0.112793f, 0.133057f,
+ 0.157227f, 0.183960f, 0.215210f, 0.250488f, 0.288086f, 0.329102f, 0.372314f, 0.416992f, 0.461914f, 0.505859f, 0.549316f, 0.589355f,
+ 0.627930f, 0.664062f, 0.695801f, 0.725098f, 0.752441f, 0.775879f, 0.797363f, 0.815918f, 0.833984f, 0.849121f, 0.863281f, 0.875488f,
+ 0.886230f, 0.895996f, 0.904785f, 0.914062f, 0.920898f, 0.928223f, 0.935059f, 0.940918f, 0.945312f, 0.950195f, 0.954102f, 0.958984f,
+ 0.962402f, 0.966309f, 0.969238f, 0.972656f, 0.974609f, 0.977539f, 0.990234f, 0.992188f, 0.991211f, 0.991211f, 0.990723f, 0.991211f,
+ 0.000926f, 0.003523f, 0.006207f, 0.008949f, 0.012718f, 0.016312f, 0.020447f, 0.025467f, 0.031128f, 0.037994f, 0.045532f, 0.054901f,
+ 0.065430f, 0.077576f, 0.091797f, 0.109131f, 0.128418f, 0.151245f, 0.176636f, 0.206055f, 0.238525f, 0.275146f, 0.314697f, 0.357178f,
+ 0.400391f, 0.445312f, 0.489746f, 0.531738f, 0.574219f, 0.613281f, 0.650391f, 0.683594f, 0.714355f, 0.742188f, 0.768066f, 0.790039f,
+ 0.810059f, 0.828125f, 0.843262f, 0.858398f, 0.871582f, 0.883789f, 0.893555f, 0.903809f, 0.912598f, 0.919434f, 0.926758f, 0.933594f,
+ 0.939453f, 0.944336f, 0.950195f, 0.954590f, 0.958008f, 0.962402f, 0.966309f, 0.969727f, 0.972656f, 0.975586f, 0.989746f, 0.990723f,
+ 0.990723f, 0.990234f, 0.990234f, 0.990234f, 0.001140f, 0.003021f, 0.005527f, 0.008102f, 0.010445f, 0.013977f, 0.017349f, 0.021637f,
+ 0.026535f, 0.031677f, 0.038330f, 0.045776f, 0.054382f, 0.064392f, 0.076233f, 0.089844f, 0.105713f, 0.123840f, 0.145020f, 0.169556f,
+ 0.196899f, 0.229248f, 0.263672f, 0.302002f, 0.342529f, 0.385986f, 0.429932f, 0.473877f, 0.517578f, 0.560547f, 0.600586f, 0.638184f,
+ 0.672852f, 0.704590f, 0.733398f, 0.759277f, 0.782715f, 0.803711f, 0.823242f, 0.840820f, 0.854980f, 0.869141f, 0.881348f, 0.892090f,
+ 0.902344f, 0.910645f, 0.919922f, 0.927246f, 0.933105f, 0.938965f, 0.944824f, 0.949707f, 0.954102f, 0.959473f, 0.962891f, 0.966309f,
+ 0.969727f, 0.972168f, 0.988770f, 0.990234f, 0.989746f, 0.989746f, 0.989746f, 0.989258f, 0.000870f, 0.002666f, 0.004578f, 0.006737f,
+ 0.009430f, 0.012077f, 0.015381f, 0.018463f, 0.022293f, 0.027313f, 0.032654f, 0.038727f, 0.045746f, 0.053619f, 0.063232f, 0.074524f,
+ 0.087219f, 0.102356f, 0.119324f, 0.139648f, 0.162842f, 0.189941f, 0.219482f, 0.253174f, 0.289795f, 0.329346f, 0.372070f, 0.415039f,
+ 0.459717f, 0.503418f, 0.546387f, 0.587402f, 0.625977f, 0.661621f, 0.694336f, 0.725586f, 0.752441f, 0.776855f, 0.798828f, 0.818359f,
+ 0.837402f, 0.852539f, 0.866699f, 0.878906f, 0.891113f, 0.900879f, 0.910156f, 0.918457f, 0.926270f, 0.932617f, 0.938965f, 0.944824f,
+ 0.950195f, 0.955078f, 0.958984f, 0.962891f, 0.966797f, 0.970703f, 0.987793f, 0.988770f, 0.989258f, 0.989258f, 0.988770f, 0.988770f,
+ 0.000835f, 0.002302f, 0.004078f, 0.005802f, 0.008026f, 0.010490f, 0.013153f, 0.016235f, 0.019485f, 0.023636f, 0.027847f, 0.033081f,
+ 0.038849f, 0.045441f, 0.053253f, 0.062500f, 0.072571f, 0.085205f, 0.098999f, 0.115662f, 0.135254f, 0.156860f, 0.182373f, 0.211060f,
+ 0.243042f, 0.279053f, 0.318115f, 0.359619f, 0.402832f, 0.447021f, 0.490234f, 0.533691f, 0.575195f, 0.615234f, 0.651855f, 0.686035f,
+ 0.717285f, 0.746094f, 0.771484f, 0.793945f, 0.813965f, 0.833496f, 0.848633f, 0.864258f, 0.877930f, 0.889648f, 0.900391f, 0.909180f,
+ 0.918945f, 0.926270f, 0.932129f, 0.939453f, 0.945312f, 0.950684f, 0.955566f, 0.959473f, 0.963867f, 0.967773f, 0.987305f, 0.988281f,
+ 0.988281f, 0.988281f, 0.988281f, 0.987793f, 0.000815f, 0.001984f, 0.003475f, 0.005302f, 0.007103f, 0.009354f, 0.011528f, 0.013977f,
+ 0.017197f, 0.020111f, 0.023788f, 0.027771f, 0.033447f, 0.038452f, 0.045013f, 0.052704f, 0.061066f, 0.071228f, 0.082886f, 0.096313f,
+ 0.112488f, 0.130737f, 0.151245f, 0.175659f, 0.203125f, 0.234619f, 0.269043f, 0.306885f, 0.347656f, 0.390381f, 0.434570f, 0.478760f,
+ 0.522461f, 0.564453f, 0.605957f, 0.644043f, 0.678223f, 0.710449f, 0.739746f, 0.766602f, 0.791016f, 0.811035f, 0.831055f, 0.847168f,
+ 0.862793f, 0.875977f, 0.888672f, 0.899414f, 0.909180f, 0.917480f, 0.926270f, 0.933105f, 0.939941f, 0.945801f, 0.950684f, 0.955566f,
+ 0.960938f, 0.964844f, 0.985840f, 0.987305f, 0.987793f, 0.987305f, 0.987305f, 0.987305f, 0.000587f, 0.002005f, 0.003122f, 0.004707f,
+ 0.006283f, 0.007778f, 0.009972f, 0.012581f, 0.014435f, 0.017426f, 0.020691f, 0.024475f, 0.028519f, 0.033203f, 0.038513f, 0.044708f,
+ 0.051727f, 0.060028f, 0.069763f, 0.080627f, 0.093506f, 0.109009f, 0.125977f, 0.146362f, 0.169678f, 0.196533f, 0.226685f, 0.259766f,
+ 0.297119f, 0.337646f, 0.380127f, 0.424072f, 0.468018f, 0.512207f, 0.555176f, 0.596680f, 0.635254f, 0.671387f, 0.704590f, 0.734863f,
+ 0.762207f, 0.787109f, 0.809082f, 0.828613f, 0.846191f, 0.860840f, 0.875977f, 0.888184f, 0.899902f, 0.908691f, 0.918457f, 0.926270f,
+ 0.934082f, 0.940430f, 0.947266f, 0.951660f, 0.958008f, 0.961914f, 0.984863f, 0.986328f, 0.986816f, 0.986816f, 0.986328f, 0.986328f,
+ 0.000475f, 0.001671f, 0.003019f, 0.004379f, 0.005592f, 0.006882f, 0.008682f, 0.010757f, 0.012856f, 0.015343f, 0.018112f, 0.021164f,
+ 0.024353f, 0.028595f, 0.033020f, 0.038086f, 0.044006f, 0.050812f, 0.058594f, 0.067993f, 0.078735f, 0.091248f, 0.105530f, 0.122009f,
+ 0.142212f, 0.164062f, 0.189697f, 0.219238f, 0.251953f, 0.288330f, 0.328125f, 0.369629f, 0.413818f, 0.458008f, 0.503418f, 0.547363f,
+ 0.588867f, 0.628418f, 0.665039f, 0.699707f, 0.730469f, 0.758301f, 0.784668f, 0.807129f, 0.826660f, 0.844727f, 0.862305f, 0.875977f,
+ 0.888672f, 0.900879f, 0.910156f, 0.919434f, 0.927734f, 0.935059f, 0.941406f, 0.947754f, 0.953125f, 0.958496f, 0.983887f, 0.985352f,
+ 0.985352f, 0.985352f, 0.984863f, 0.985352f, 0.000325f, 0.001517f, 0.002554f, 0.003811f, 0.004990f, 0.006638f, 0.007706f, 0.009399f,
+ 0.011177f, 0.013580f, 0.015671f, 0.018478f, 0.021393f, 0.024612f, 0.028442f, 0.032990f, 0.037750f, 0.043427f, 0.050354f, 0.057861f,
+ 0.066101f, 0.076294f, 0.088684f, 0.102417f, 0.119080f, 0.137451f, 0.159058f, 0.183838f, 0.212524f, 0.244385f, 0.280273f, 0.319336f,
+ 0.361084f, 0.405029f, 0.449707f, 0.494873f, 0.539551f, 0.582031f, 0.622559f, 0.660156f, 0.695801f, 0.727539f, 0.756348f, 0.782715f,
+ 0.805664f, 0.826172f, 0.845215f, 0.861328f, 0.875977f, 0.889648f, 0.901367f, 0.910645f, 0.920410f, 0.928711f, 0.937012f, 0.942871f,
+ 0.949219f, 0.955078f, 0.982422f, 0.983887f, 0.984375f, 0.984375f, 0.983887f, 0.983887f, 0.000349f, 0.001533f, 0.002413f, 0.003326f,
+ 0.004463f, 0.005524f, 0.006954f, 0.008202f, 0.010025f, 0.011864f, 0.013924f, 0.015884f, 0.018478f, 0.021484f, 0.024658f, 0.028671f,
+ 0.032562f, 0.037170f, 0.042969f, 0.049194f, 0.056641f, 0.065063f, 0.074951f, 0.086182f, 0.099731f, 0.115662f, 0.133789f, 0.154175f,
+ 0.178589f, 0.206421f, 0.237671f, 0.272949f, 0.312012f, 0.352783f, 0.396973f, 0.442627f, 0.487793f, 0.532227f, 0.576660f, 0.617188f,
+ 0.657227f, 0.692383f, 0.725586f, 0.754395f, 0.780762f, 0.805664f, 0.826172f, 0.845215f, 0.861816f, 0.876465f, 0.890137f, 0.902344f,
+ 0.912598f, 0.921875f, 0.930176f, 0.937988f, 0.945312f, 0.952148f, 0.981445f, 0.982910f, 0.982910f, 0.983398f, 0.983398f, 0.983398f,
+ 0.000475f, 0.001141f, 0.002058f, 0.002846f, 0.004120f, 0.005013f, 0.006207f, 0.007664f, 0.009193f, 0.010368f, 0.012222f, 0.014404f,
+ 0.016403f, 0.018799f, 0.021439f, 0.024567f, 0.028076f, 0.032379f, 0.036652f, 0.042145f, 0.048157f, 0.055389f, 0.063660f, 0.073059f,
+ 0.083740f, 0.097046f, 0.112366f, 0.129517f, 0.149780f, 0.173584f, 0.200684f, 0.231812f, 0.266357f, 0.304688f, 0.346680f, 0.390137f,
+ 0.435547f, 0.481445f, 0.526367f, 0.572266f, 0.613770f, 0.653320f, 0.690430f, 0.723633f, 0.754395f, 0.781250f, 0.806152f, 0.826172f,
+ 0.847168f, 0.862793f, 0.878906f, 0.892090f, 0.904297f, 0.914551f, 0.924316f, 0.933105f, 0.940430f, 0.947754f, 0.979492f, 0.981934f,
+ 0.981934f, 0.981934f, 0.981445f, 0.981445f, 0.000239f, 0.000882f, 0.001744f, 0.002878f, 0.003819f, 0.004532f, 0.005550f, 0.006653f,
+ 0.007942f, 0.009277f, 0.010628f, 0.012421f, 0.014397f, 0.016312f, 0.018845f, 0.021576f, 0.024536f, 0.027817f, 0.031860f, 0.036346f,
+ 0.041595f, 0.047333f, 0.054138f, 0.062317f, 0.071350f, 0.081970f, 0.094299f, 0.109070f, 0.126221f, 0.146118f, 0.169067f, 0.195801f,
+ 0.226196f, 0.260742f, 0.298584f, 0.340088f, 0.384277f, 0.429688f, 0.476807f, 0.522461f, 0.568359f, 0.611328f, 0.651855f, 0.689453f,
+ 0.723633f, 0.754395f, 0.782715f, 0.807617f, 0.829590f, 0.848145f, 0.865723f, 0.880859f, 0.894531f, 0.906738f, 0.917969f, 0.927246f,
+ 0.936035f, 0.943359f, 0.978027f, 0.979980f, 0.980469f, 0.980469f, 0.980469f, 0.980469f, 0.000240f, 0.000948f, 0.001495f, 0.002592f,
+ 0.003241f, 0.004055f, 0.004856f, 0.006111f, 0.007133f, 0.008125f, 0.009445f, 0.011108f, 0.012474f, 0.014374f, 0.016586f, 0.018784f,
+ 0.021286f, 0.024475f, 0.027481f, 0.031403f, 0.035828f, 0.040710f, 0.046204f, 0.052704f, 0.060577f, 0.069519f, 0.079651f, 0.092224f,
+ 0.106506f, 0.122986f, 0.142456f, 0.165161f, 0.191284f, 0.221924f, 0.255615f, 0.293457f, 0.335205f, 0.379395f, 0.425537f, 0.472900f,
+ 0.519531f, 0.566406f, 0.610840f, 0.652344f, 0.689941f, 0.724609f, 0.755371f, 0.784180f, 0.808594f, 0.831055f, 0.851562f, 0.869141f,
+ 0.884277f, 0.897461f, 0.909668f, 0.920410f, 0.930176f, 0.937988f, 0.976562f, 0.979004f, 0.979492f, 0.979492f, 0.979492f, 0.979492f,
+ 0.000302f, 0.000863f, 0.001315f, 0.002195f, 0.002905f, 0.003592f, 0.004784f, 0.005478f, 0.006199f, 0.007389f, 0.008545f, 0.009811f,
+ 0.011185f, 0.012787f, 0.014603f, 0.016342f, 0.018784f, 0.021347f, 0.024033f, 0.027496f, 0.031006f, 0.034790f, 0.039856f, 0.045288f,
+ 0.051636f, 0.059052f, 0.067566f, 0.078003f, 0.089905f, 0.103760f, 0.119934f, 0.139282f, 0.161865f, 0.187622f, 0.217407f, 0.251221f,
+ 0.288818f, 0.330811f, 0.375244f, 0.422607f, 0.470703f, 0.518066f, 0.565430f, 0.609863f, 0.651855f, 0.691406f, 0.726562f, 0.758301f,
+ 0.787109f, 0.812500f, 0.835449f, 0.855957f, 0.872559f, 0.887695f, 0.901367f, 0.913574f, 0.923828f, 0.933105f, 0.975098f, 0.977539f,
+ 0.977539f, 0.977539f, 0.978027f, 0.977051f, 0.000240f, 0.000808f, 0.001537f, 0.002106f, 0.002493f, 0.003729f, 0.004036f, 0.004982f,
+ 0.005539f, 0.006454f, 0.007526f, 0.008690f, 0.009987f, 0.011421f, 0.012894f, 0.014618f, 0.016464f, 0.018539f, 0.021118f, 0.023865f,
+ 0.026794f, 0.030487f, 0.034241f, 0.038879f, 0.044067f, 0.050690f, 0.057678f, 0.066040f, 0.076111f, 0.087524f, 0.101379f, 0.117737f,
+ 0.136353f, 0.158325f, 0.183594f, 0.213501f, 0.247192f, 0.284912f, 0.327393f, 0.372803f, 0.420410f, 0.468750f, 0.518066f, 0.565430f,
+ 0.611328f, 0.654297f, 0.694336f, 0.729980f, 0.762207f, 0.791504f, 0.817383f, 0.839844f, 0.859863f, 0.876953f, 0.891602f, 0.905762f,
+ 0.917480f, 0.928711f, 0.973633f, 0.975098f, 0.976562f, 0.975586f, 0.976562f, 0.976562f, 0.000240f, 0.000587f, 0.001223f, 0.001691f,
+ 0.002499f, 0.003008f, 0.003643f, 0.004295f, 0.004795f, 0.005726f, 0.006649f, 0.007671f, 0.008766f, 0.010002f, 0.011307f, 0.012764f,
+ 0.014465f, 0.016388f, 0.018387f, 0.020599f, 0.023453f, 0.026291f, 0.029572f, 0.033417f, 0.037964f, 0.043427f, 0.049316f, 0.056519f,
+ 0.064819f, 0.074219f, 0.085693f, 0.099121f, 0.115112f, 0.133301f, 0.155273f, 0.180420f, 0.210205f, 0.244751f, 0.282715f, 0.324951f,
+ 0.371338f, 0.419434f, 0.468994f, 0.518555f, 0.566895f, 0.613770f, 0.658203f, 0.698242f, 0.735352f, 0.766602f, 0.796875f, 0.821289f,
+ 0.844238f, 0.863770f, 0.881836f, 0.896973f, 0.910156f, 0.922363f, 0.971191f, 0.974121f, 0.974609f, 0.974121f, 0.974609f, 0.974609f,
+ 0.000228f, 0.000671f, 0.001122f, 0.001607f, 0.002291f, 0.002836f, 0.003319f, 0.003817f, 0.004509f, 0.005253f, 0.005894f, 0.006840f,
+ 0.007820f, 0.008972f, 0.010086f, 0.011391f, 0.012848f, 0.014328f, 0.016266f, 0.018158f, 0.020447f, 0.022720f, 0.026031f, 0.029053f,
+ 0.032593f, 0.037109f, 0.042236f, 0.048340f, 0.055115f, 0.063049f, 0.072632f, 0.083801f, 0.097351f, 0.112488f, 0.130493f, 0.152222f,
+ 0.178101f, 0.208008f, 0.241943f, 0.280762f, 0.323730f, 0.370117f, 0.419434f, 0.470459f, 0.520996f, 0.570801f, 0.617676f, 0.663086f,
+ 0.704102f, 0.740234f, 0.773438f, 0.802246f, 0.829102f, 0.850098f, 0.870117f, 0.887695f, 0.902832f, 0.916016f, 0.969238f, 0.972168f,
+ 0.972168f, 0.972656f, 0.972656f, 0.972168f, 0.000121f, 0.000526f, 0.001092f, 0.001670f, 0.001744f, 0.002420f, 0.002945f, 0.003237f,
+ 0.004013f, 0.004894f, 0.005421f, 0.005932f, 0.006996f, 0.007904f, 0.008873f, 0.009995f, 0.011391f, 0.012756f, 0.014053f, 0.015884f,
+ 0.017715f, 0.019775f, 0.022324f, 0.025406f, 0.028290f, 0.032349f, 0.036560f, 0.041412f, 0.047058f, 0.053772f, 0.061493f, 0.070862f,
+ 0.081848f, 0.094666f, 0.110229f, 0.128662f, 0.150024f, 0.175903f, 0.205566f, 0.239990f, 0.279785f, 0.323486f, 0.370850f, 0.421143f,
+ 0.473633f, 0.524902f, 0.576172f, 0.625000f, 0.668457f, 0.710938f, 0.748535f, 0.781250f, 0.810059f, 0.835449f, 0.857910f, 0.877441f,
+ 0.894531f, 0.908691f, 0.966797f, 0.970215f, 0.970703f, 0.970703f, 0.970703f, 0.970215f, 0.000127f, 0.000521f, 0.001083f, 0.001460f,
+ 0.001684f, 0.002111f, 0.002563f, 0.003048f, 0.003618f, 0.004124f, 0.004936f, 0.005543f, 0.006340f, 0.007111f, 0.008049f, 0.008774f,
+ 0.009865f, 0.011162f, 0.012360f, 0.013840f, 0.015465f, 0.017181f, 0.019531f, 0.021973f, 0.024582f, 0.027847f, 0.031342f, 0.035706f,
+ 0.040100f, 0.045990f, 0.052521f, 0.060089f, 0.069214f, 0.080017f, 0.093079f, 0.108521f, 0.126709f, 0.148071f, 0.174072f, 0.204224f,
+ 0.239502f, 0.279541f, 0.324219f, 0.373047f, 0.424805f, 0.477295f, 0.530762f, 0.583008f, 0.632324f, 0.677246f, 0.719727f, 0.756348f,
+ 0.789551f, 0.819336f, 0.842773f, 0.866211f, 0.885742f, 0.901855f, 0.965332f, 0.967773f, 0.968262f, 0.967773f, 0.968750f, 0.968262f,
+ 0.000244f, 0.000397f, 0.001001f, 0.001181f, 0.001642f, 0.001872f, 0.002460f, 0.002712f, 0.003061f, 0.003723f, 0.004520f, 0.005043f,
+ 0.005547f, 0.006451f, 0.007057f, 0.007828f, 0.008942f, 0.009872f, 0.010857f, 0.012131f, 0.013557f, 0.015198f, 0.017059f, 0.019241f,
+ 0.021454f, 0.024048f, 0.027069f, 0.030594f, 0.034332f, 0.039001f, 0.044952f, 0.050873f, 0.058716f, 0.067505f, 0.078369f, 0.091309f,
+ 0.106506f, 0.124695f, 0.146484f, 0.172852f, 0.203369f, 0.239014f, 0.280273f, 0.326172f, 0.376465f, 0.429443f, 0.483643f, 0.538574f,
+ 0.591309f, 0.641602f, 0.687500f, 0.729492f, 0.766602f, 0.800293f, 0.828613f, 0.854004f, 0.874512f, 0.893555f, 0.961914f, 0.965332f,
+ 0.965820f, 0.966309f, 0.966309f, 0.965820f, 0.000243f, 0.000453f, 0.000888f, 0.001245f, 0.001342f, 0.001847f, 0.002060f, 0.002541f,
+ 0.002991f, 0.003355f, 0.003679f, 0.004379f, 0.005177f, 0.005413f, 0.006283f, 0.007038f, 0.007896f, 0.008507f, 0.009552f, 0.010628f,
+ 0.011909f, 0.013306f, 0.015038f, 0.016388f, 0.018433f, 0.020752f, 0.023254f, 0.026413f, 0.029617f, 0.033447f, 0.037842f, 0.043701f,
+ 0.049896f, 0.057190f, 0.066101f, 0.076660f, 0.089600f, 0.104553f, 0.123230f, 0.145386f, 0.171387f, 0.202637f, 0.239624f, 0.281982f,
+ 0.329346f, 0.380859f, 0.436035f, 0.491943f, 0.547852f, 0.602539f, 0.653809f, 0.699707f, 0.741699f, 0.778320f, 0.811035f, 0.838867f,
+ 0.862793f, 0.884766f, 0.959961f, 0.963379f, 0.963379f, 0.963379f, 0.964355f, 0.963379f, 0.000241f, 0.000452f, 0.000798f, 0.001119f,
+ 0.001220f, 0.001430f, 0.001902f, 0.002277f, 0.002737f, 0.002893f, 0.003624f, 0.003937f, 0.004436f, 0.005089f, 0.005669f, 0.006226f,
+ 0.006680f, 0.007519f, 0.008568f, 0.009384f, 0.010422f, 0.011795f, 0.012840f, 0.014526f, 0.016235f, 0.017929f, 0.020218f, 0.022736f,
+ 0.025146f, 0.028580f, 0.032684f, 0.036896f, 0.042511f, 0.048431f, 0.055634f, 0.064453f, 0.075317f, 0.088196f, 0.103333f, 0.121948f,
+ 0.144287f, 0.171143f, 0.203491f, 0.241577f, 0.285156f, 0.334229f, 0.387939f, 0.444580f, 0.501953f, 0.559570f, 0.614746f, 0.666504f,
+ 0.712402f, 0.755371f, 0.791504f, 0.823242f, 0.851074f, 0.875000f, 0.956543f, 0.959961f, 0.960938f, 0.960449f, 0.960449f, 0.960449f,
+ 0.000000f, 0.000263f, 0.000693f, 0.000873f, 0.001183f, 0.001447f, 0.001476f, 0.002068f, 0.002171f, 0.002857f, 0.003164f, 0.003542f,
+ 0.003778f, 0.004326f, 0.004906f, 0.005436f, 0.006126f, 0.006687f, 0.007229f, 0.008377f, 0.009232f, 0.010223f, 0.011436f, 0.012527f,
+ 0.013832f, 0.015747f, 0.017365f, 0.019363f, 0.021667f, 0.024231f, 0.027695f, 0.031769f, 0.035889f, 0.041016f, 0.047028f, 0.054504f,
+ 0.063110f, 0.073975f, 0.086487f, 0.101807f, 0.120972f, 0.143555f, 0.171753f, 0.204956f, 0.244263f, 0.289551f, 0.340576f, 0.396484f,
+ 0.455078f, 0.514648f, 0.573730f, 0.630371f, 0.681152f, 0.729004f, 0.770020f, 0.806641f, 0.837402f, 0.863770f, 0.953613f, 0.956543f,
+ 0.957520f, 0.957031f, 0.957031f, 0.958008f, 0.000000f, 0.000356f, 0.000641f, 0.000870f, 0.000998f, 0.001134f, 0.001495f, 0.001724f,
+ 0.002436f, 0.002478f, 0.002775f, 0.003113f, 0.003435f, 0.003864f, 0.004314f, 0.004704f, 0.005276f, 0.005886f, 0.006599f, 0.007309f,
+ 0.008003f, 0.008987f, 0.009987f, 0.010941f, 0.012192f, 0.013466f, 0.015030f, 0.016708f, 0.018906f, 0.021103f, 0.023788f, 0.026886f,
+ 0.030457f, 0.034943f, 0.040009f, 0.045959f, 0.053162f, 0.061920f, 0.072144f, 0.085205f, 0.101257f, 0.120422f, 0.143555f, 0.172363f,
+ 0.206909f, 0.248047f, 0.295410f, 0.349121f, 0.407715f, 0.468750f, 0.530762f, 0.589844f, 0.647949f, 0.699707f, 0.746094f, 0.786621f,
+ 0.823242f, 0.852051f, 0.950195f, 0.953125f, 0.954102f, 0.954102f, 0.954102f, 0.954102f, 0.000231f, 0.000449f, 0.000516f, 0.000760f,
+ 0.000868f, 0.001152f, 0.001403f, 0.001773f, 0.002165f, 0.002245f, 0.002550f, 0.002783f, 0.003277f, 0.003660f, 0.003782f, 0.004120f,
+ 0.004631f, 0.005268f, 0.005795f, 0.006344f, 0.007053f, 0.007835f, 0.008598f, 0.009460f, 0.010689f, 0.011551f, 0.012726f, 0.014359f,
+ 0.016052f, 0.017975f, 0.020218f, 0.022812f, 0.025803f, 0.029251f, 0.033386f, 0.038574f, 0.044556f, 0.051941f, 0.060577f, 0.071045f,
+ 0.084106f, 0.100342f, 0.119751f, 0.144043f, 0.174194f, 0.209961f, 0.253418f, 0.303467f, 0.359619f, 0.420898f, 0.483887f, 0.547852f,
+ 0.609375f, 0.667480f, 0.719727f, 0.765625f, 0.804688f, 0.839844f, 0.946289f, 0.949707f, 0.950195f, 0.950684f, 0.950684f, 0.950195f,
+ 0.000201f, 0.000336f, 0.000452f, 0.000627f, 0.000793f, 0.000966f, 0.001134f, 0.001578f, 0.001790f, 0.001896f, 0.002254f, 0.002464f,
+ 0.002825f, 0.003012f, 0.003414f, 0.003626f, 0.004131f, 0.004608f, 0.005058f, 0.005642f, 0.006191f, 0.006771f, 0.007378f, 0.008057f,
+ 0.009132f, 0.009918f, 0.010826f, 0.012314f, 0.013794f, 0.015381f, 0.017197f, 0.019257f, 0.021912f, 0.024841f, 0.028259f, 0.032318f,
+ 0.037262f, 0.043427f, 0.050537f, 0.059021f, 0.070007f, 0.083191f, 0.099609f, 0.120239f, 0.145508f, 0.176636f, 0.214600f, 0.260254f,
+ 0.313232f, 0.372803f, 0.437012f, 0.503418f, 0.568359f, 0.631836f, 0.688965f, 0.741211f, 0.786621f, 0.825195f, 0.941406f, 0.946289f,
+ 0.946289f, 0.946777f, 0.946289f, 0.947266f, 0.000000f, 0.000317f, 0.000445f, 0.000453f, 0.000781f, 0.000794f, 0.001183f, 0.001289f,
+ 0.001479f, 0.001832f, 0.001874f, 0.002256f, 0.002270f, 0.002716f, 0.002960f, 0.003273f, 0.003630f, 0.003948f, 0.004467f, 0.004833f,
+ 0.005451f, 0.005962f, 0.006367f, 0.007088f, 0.007717f, 0.008400f, 0.009506f, 0.010445f, 0.011658f, 0.012993f, 0.014618f, 0.016357f,
+ 0.018524f, 0.021210f, 0.023712f, 0.027252f, 0.031219f, 0.036041f, 0.041962f, 0.049194f, 0.057892f, 0.068604f, 0.082642f, 0.099304f,
+ 0.120728f, 0.147217f, 0.180054f, 0.221191f, 0.269287f, 0.325928f, 0.388916f, 0.457275f, 0.525391f, 0.593262f, 0.657715f, 0.714355f,
+ 0.766113f, 0.809082f, 0.937500f, 0.940918f, 0.941895f, 0.941895f, 0.941895f, 0.942383f, 0.000243f, 0.000238f, 0.000411f, 0.000532f,
+ 0.000530f, 0.000764f, 0.000853f, 0.001171f, 0.001417f, 0.001545f, 0.001799f, 0.001900f, 0.002094f, 0.002354f, 0.002577f, 0.002703f,
+ 0.003155f, 0.003428f, 0.003809f, 0.004227f, 0.004677f, 0.004997f, 0.005386f, 0.005913f, 0.006741f, 0.007225f, 0.008057f, 0.008873f,
+ 0.009819f, 0.011101f, 0.012253f, 0.013725f, 0.015488f, 0.017410f, 0.019791f, 0.022598f, 0.025635f, 0.030014f, 0.034973f, 0.040527f,
+ 0.047729f, 0.056702f, 0.067505f, 0.081848f, 0.099609f, 0.121521f, 0.149902f, 0.185181f, 0.228516f, 0.280762f, 0.341553f, 0.408936f,
+ 0.480225f, 0.552246f, 0.622070f, 0.686035f, 0.742188f, 0.792480f, 0.932129f, 0.935547f, 0.937012f, 0.937012f, 0.936523f, 0.937500f,
+ 0.000000f, 0.000232f, 0.000330f, 0.000512f, 0.000523f, 0.000907f, 0.000953f, 0.001018f, 0.001234f, 0.001344f, 0.001610f, 0.001612f,
+ 0.001845f, 0.002054f, 0.002218f, 0.002453f, 0.002829f, 0.003105f, 0.003300f, 0.003712f, 0.003853f, 0.004280f, 0.004631f, 0.005112f,
+ 0.005665f, 0.006279f, 0.006779f, 0.007481f, 0.008362f, 0.009270f, 0.010338f, 0.011505f, 0.012848f, 0.014549f, 0.016403f, 0.018936f,
+ 0.021622f, 0.024750f, 0.028900f, 0.033447f, 0.039185f, 0.046448f, 0.055603f, 0.067078f, 0.081238f, 0.100037f, 0.123230f, 0.153564f,
+ 0.191284f, 0.238525f, 0.295166f, 0.361084f, 0.432861f, 0.507812f, 0.582520f, 0.653320f, 0.717285f, 0.772461f, 0.926270f, 0.931152f,
+ 0.931152f, 0.932129f, 0.932129f, 0.932129f, 0.000118f, 0.000219f, 0.000227f, 0.000405f, 0.000689f, 0.000726f, 0.000910f, 0.000847f,
+ 0.001072f, 0.001114f, 0.001388f, 0.001447f, 0.001656f, 0.001811f, 0.001897f, 0.002253f, 0.002373f, 0.002617f, 0.002796f, 0.003054f,
+ 0.003414f, 0.003681f, 0.003929f, 0.004353f, 0.004902f, 0.005322f, 0.005863f, 0.006424f, 0.007000f, 0.007755f, 0.008675f, 0.009506f,
+ 0.010704f, 0.012215f, 0.013557f, 0.015686f, 0.017807f, 0.020630f, 0.023376f, 0.027328f, 0.032013f, 0.038177f, 0.045288f, 0.054626f,
+ 0.066284f, 0.081543f, 0.100891f, 0.125977f, 0.158447f, 0.199951f, 0.251465f, 0.313965f, 0.384521f, 0.461670f, 0.540527f, 0.617188f,
+ 0.688965f, 0.750977f, 0.920410f, 0.924805f, 0.925781f, 0.926270f, 0.926758f, 0.925781f, 0.000230f, 0.000198f, 0.000217f, 0.000338f,
+ 0.000584f, 0.000786f, 0.000699f, 0.000893f, 0.000954f, 0.000959f, 0.001153f, 0.001165f, 0.001375f, 0.001545f, 0.001752f, 0.001752f,
+ 0.002062f, 0.002235f, 0.002399f, 0.002699f, 0.002853f, 0.002995f, 0.003372f, 0.003603f, 0.003944f, 0.004513f, 0.004704f, 0.005226f,
+ 0.005878f, 0.006527f, 0.006992f, 0.007889f, 0.008919f, 0.010002f, 0.011124f, 0.012604f, 0.014526f, 0.016510f, 0.019104f, 0.022308f,
+ 0.026077f, 0.030701f, 0.036774f, 0.044098f, 0.053558f, 0.065735f, 0.081299f, 0.101990f, 0.129517f, 0.164917f, 0.210938f, 0.268066f,
+ 0.336914f, 0.413818f, 0.496094f, 0.579102f, 0.657227f, 0.727539f, 0.913574f, 0.917969f, 0.918945f, 0.919434f, 0.919922f, 0.919922f,
+ 0.000000f, 0.000101f, 0.000214f, 0.000208f, 0.000339f, 0.000461f, 0.000577f, 0.000780f, 0.000777f, 0.000840f, 0.000853f, 0.001064f,
+ 0.001198f, 0.001327f, 0.001489f, 0.001687f, 0.001809f, 0.001884f, 0.002008f, 0.002129f, 0.002434f, 0.002514f, 0.002949f, 0.003000f,
+ 0.003351f, 0.003674f, 0.003918f, 0.004356f, 0.004875f, 0.005310f, 0.005768f, 0.006458f, 0.007244f, 0.008255f, 0.008949f, 0.010361f,
+ 0.011589f, 0.013290f, 0.015335f, 0.017776f, 0.020828f, 0.024521f, 0.029236f, 0.035431f, 0.042694f, 0.052490f, 0.065369f, 0.082336f,
+ 0.104492f, 0.134277f, 0.173828f, 0.225464f, 0.290039f, 0.365234f, 0.449707f, 0.536133f, 0.623047f, 0.702637f, 0.905273f, 0.911133f,
+ 0.912598f, 0.913086f, 0.913086f, 0.913086f, 0.000000f, 0.000167f, 0.000167f, 0.000316f, 0.000432f, 0.000444f, 0.000608f, 0.000611f,
+ 0.000678f, 0.000750f, 0.000899f, 0.000925f, 0.001043f, 0.001125f, 0.001222f, 0.001343f, 0.001470f, 0.001608f, 0.001679f, 0.001804f,
+ 0.001976f, 0.002234f, 0.002361f, 0.002710f, 0.002748f, 0.003035f, 0.003290f, 0.003647f, 0.003990f, 0.004295f, 0.004745f, 0.005318f,
+ 0.005920f, 0.006618f, 0.007347f, 0.008270f, 0.009361f, 0.010719f, 0.012291f, 0.014221f, 0.016693f, 0.019592f, 0.023239f, 0.027969f,
+ 0.033752f, 0.041534f, 0.051666f, 0.065369f, 0.083618f, 0.108276f, 0.141357f, 0.186035f, 0.244141f, 0.316650f, 0.400635f, 0.491699f,
+ 0.585938f, 0.672852f, 0.897461f, 0.903320f, 0.904297f, 0.903809f, 0.903809f, 0.904297f, 0.000000f, 0.000098f, 0.000145f, 0.000289f,
+ 0.000399f, 0.000424f, 0.000429f, 0.000382f, 0.000529f, 0.000613f, 0.000660f, 0.000836f, 0.000907f, 0.000940f, 0.001005f, 0.001188f,
+ 0.001306f, 0.001451f, 0.001420f, 0.001554f, 0.001667f, 0.001783f, 0.001955f, 0.002125f, 0.002357f, 0.002493f, 0.002760f, 0.002867f,
+ 0.003298f, 0.003626f, 0.003878f, 0.004341f, 0.004704f, 0.005356f, 0.005905f, 0.006512f, 0.007435f, 0.008377f, 0.009598f, 0.011055f,
+ 0.012978f, 0.015388f, 0.018036f, 0.021698f, 0.026337f, 0.032532f, 0.040192f, 0.050995f, 0.065125f, 0.085510f, 0.113037f, 0.150513f,
+ 0.201538f, 0.268799f, 0.351318f, 0.444824f, 0.543457f, 0.641602f, 0.888672f, 0.894043f, 0.894531f, 0.895508f, 0.895020f, 0.895508f,
+ 0.000000f, 0.000000f, 0.000032f, 0.000169f, 0.000338f, 0.000372f, 0.000468f, 0.000471f, 0.000460f, 0.000493f, 0.000588f, 0.000715f,
+ 0.000762f, 0.000912f, 0.000831f, 0.001001f, 0.001043f, 0.001133f, 0.001242f, 0.001312f, 0.001446f, 0.001529f, 0.001647f, 0.001829f,
+ 0.001982f, 0.002121f, 0.002165f, 0.002438f, 0.002628f, 0.002865f, 0.003113f, 0.003424f, 0.003622f, 0.004131f, 0.004639f, 0.005222f,
+ 0.005875f, 0.006622f, 0.007496f, 0.008575f, 0.009987f, 0.011665f, 0.013985f, 0.016617f, 0.019913f, 0.024704f, 0.030960f, 0.039185f,
+ 0.050323f, 0.066284f, 0.088196f, 0.119568f, 0.163208f, 0.223511f, 0.302002f, 0.395752f, 0.499756f, 0.605957f, 0.878418f, 0.883301f,
+ 0.884766f, 0.884766f, 0.885254f, 0.885254f, 0.000000f, 0.000000f, 0.000000f, 0.000216f, 0.000237f, 0.000338f, 0.000387f, 0.000341f,
+ 0.000435f, 0.000441f, 0.000461f, 0.000577f, 0.000544f, 0.000720f, 0.000813f, 0.000823f, 0.000912f, 0.000936f, 0.000994f, 0.001026f,
+ 0.001240f, 0.001268f, 0.001365f, 0.001415f, 0.001590f, 0.001565f, 0.001870f, 0.001929f, 0.002123f, 0.002377f, 0.002430f, 0.002565f,
+ 0.002947f, 0.003384f, 0.003662f, 0.004105f, 0.004513f, 0.005047f, 0.005741f, 0.006550f, 0.007549f, 0.008865f, 0.010612f, 0.012466f,
+ 0.015350f, 0.018677f, 0.023270f, 0.029800f, 0.038361f, 0.050323f, 0.067932f, 0.092590f, 0.129395f, 0.181274f, 0.253418f, 0.345459f,
+ 0.452637f, 0.567383f, 0.866699f, 0.872559f, 0.873047f, 0.873535f, 0.873047f, 0.873535f, 0.000000f, 0.000000f, 0.000121f, 0.000182f,
+ 0.000187f, 0.000237f, 0.000264f, 0.000360f, 0.000360f, 0.000397f, 0.000398f, 0.000412f, 0.000432f, 0.000546f, 0.000575f, 0.000690f,
+ 0.000731f, 0.000727f, 0.000807f, 0.000843f, 0.000924f, 0.001034f, 0.001093f, 0.001111f, 0.001251f, 0.001249f, 0.001334f, 0.001612f,
+ 0.001717f, 0.001820f, 0.002090f, 0.002161f, 0.002354f, 0.002600f, 0.002787f, 0.003119f, 0.003586f, 0.003878f, 0.004452f, 0.004913f,
+ 0.005772f, 0.006508f, 0.007679f, 0.009285f, 0.011086f, 0.013840f, 0.016968f, 0.021820f, 0.028259f, 0.037628f, 0.050812f, 0.070129f,
+ 0.099670f, 0.143433f, 0.207031f, 0.294922f, 0.403076f, 0.525879f, 0.853516f, 0.859375f, 0.860840f, 0.860352f, 0.862305f, 0.861328f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000181f, 0.000198f, 0.000181f, 0.000240f, 0.000275f, 0.000311f, 0.000427f, 0.000447f,
+ 0.000395f, 0.000472f, 0.000456f, 0.000557f, 0.000518f, 0.000562f, 0.000635f, 0.000664f, 0.000868f, 0.000887f, 0.000865f, 0.001025f,
+ 0.001014f, 0.001164f, 0.001096f, 0.001317f, 0.001382f, 0.001432f, 0.001445f, 0.001765f, 0.001744f, 0.002100f, 0.002144f, 0.002350f,
+ 0.002655f, 0.002947f, 0.003294f, 0.003780f, 0.004265f, 0.004971f, 0.005699f, 0.006786f, 0.007957f, 0.009636f, 0.011932f, 0.015823f,
+ 0.020142f, 0.026749f, 0.036530f, 0.051392f, 0.073792f, 0.109375f, 0.164185f, 0.244629f, 0.351562f, 0.479980f, 0.839355f, 0.844727f,
+ 0.846680f, 0.847656f, 0.847168f, 0.846680f, 0.000000f, 0.000121f, 0.000120f, 0.000119f, 0.000162f, 0.000133f, 0.000170f, 0.000201f,
+ 0.000204f, 0.000222f, 0.000258f, 0.000285f, 0.000324f, 0.000327f, 0.000422f, 0.000395f, 0.000431f, 0.000517f, 0.000632f, 0.000529f,
+ 0.000589f, 0.000592f, 0.000735f, 0.000714f, 0.000795f, 0.000778f, 0.000823f, 0.001063f, 0.001080f, 0.001141f, 0.001154f, 0.001308f,
+ 0.001439f, 0.001546f, 0.001689f, 0.001886f, 0.001978f, 0.002174f, 0.002377f, 0.002798f, 0.003277f, 0.003519f, 0.004181f, 0.004780f,
+ 0.005768f, 0.006863f, 0.008644f, 0.010750f, 0.014030f, 0.018448f, 0.025635f, 0.036194f, 0.053223f, 0.080811f, 0.125610f, 0.196533f,
+ 0.299316f, 0.430176f, 0.822754f, 0.830078f, 0.831055f, 0.831543f, 0.832031f, 0.831543f, 0.000000f, 0.000121f, 0.000120f, 0.000118f,
+ 0.000117f, 0.000120f, 0.000123f, 0.000151f, 0.000154f, 0.000175f, 0.000254f, 0.000190f, 0.000211f, 0.000306f, 0.000335f, 0.000358f,
+ 0.000394f, 0.000417f, 0.000443f, 0.000410f, 0.000565f, 0.000565f, 0.000491f, 0.000623f, 0.000616f, 0.000631f, 0.000738f, 0.000676f,
+ 0.000759f, 0.000924f, 0.000895f, 0.001030f, 0.001064f, 0.001176f, 0.001267f, 0.001438f, 0.001518f, 0.001704f, 0.001742f, 0.002028f,
+ 0.002384f, 0.002703f, 0.002972f, 0.003393f, 0.004051f, 0.004959f, 0.005993f, 0.007271f, 0.009277f, 0.012390f, 0.016968f, 0.024368f,
+ 0.036560f, 0.056610f, 0.091797f, 0.151245f, 0.246460f, 0.379639f, 0.805664f, 0.812500f, 0.813477f, 0.813965f, 0.813965f, 0.813965f,
+ 0.000000f, 0.000000f, 0.000118f, 0.000117f, 0.000116f, 0.000114f, 0.000113f, 0.000108f, 0.000127f, 0.000153f, 0.000133f, 0.000202f,
+ 0.000217f, 0.000223f, 0.000242f, 0.000186f, 0.000280f, 0.000304f, 0.000318f, 0.000342f, 0.000338f, 0.000473f, 0.000360f, 0.000484f,
+ 0.000422f, 0.000514f, 0.000527f, 0.000571f, 0.000633f, 0.000568f, 0.000639f, 0.000816f, 0.000789f, 0.000889f, 0.000891f, 0.000966f,
+ 0.001125f, 0.001276f, 0.001316f, 0.001496f, 0.001658f, 0.001818f, 0.002047f, 0.002502f, 0.002781f, 0.003201f, 0.003914f, 0.004795f,
+ 0.006096f, 0.007996f, 0.010918f, 0.015617f, 0.023697f, 0.037567f, 0.063477f, 0.111084f, 0.194824f, 0.324951f, 0.786133f, 0.792969f,
+ 0.794434f, 0.793945f, 0.794922f, 0.794434f, 0.000000f, 0.000119f, 0.000117f, 0.000115f, 0.000113f, 0.000112f, 0.000110f, 0.000109f,
+ 0.000104f, 0.000098f, 0.000099f, 0.000136f, 0.000112f, 0.000126f, 0.000175f, 0.000189f, 0.000196f, 0.000220f, 0.000216f, 0.000247f,
+ 0.000258f, 0.000274f, 0.000285f, 0.000309f, 0.000308f, 0.000321f, 0.000381f, 0.000390f, 0.000475f, 0.000511f, 0.000485f, 0.000501f,
+ 0.000641f, 0.000588f, 0.000652f, 0.000764f, 0.000808f, 0.000952f, 0.000906f, 0.001037f, 0.001110f, 0.001249f, 0.001411f, 0.001647f,
+ 0.001894f, 0.002159f, 0.002687f, 0.003223f, 0.004036f, 0.005150f, 0.006989f, 0.009644f, 0.014420f, 0.023361f, 0.040802f, 0.076050f,
+ 0.146362f, 0.269287f, 0.763184f, 0.770996f, 0.771973f, 0.771973f, 0.772461f, 0.772461f, 0.000121f, 0.000116f, 0.000114f, 0.000112f,
+ 0.000109f, 0.000108f, 0.000106f, 0.000105f, 0.000104f, 0.000101f, 0.000095f, 0.000090f, 0.000085f, 0.000083f, 0.000104f, 0.000097f,
+ 0.000094f, 0.000154f, 0.000127f, 0.000178f, 0.000197f, 0.000194f, 0.000233f, 0.000213f, 0.000279f, 0.000294f, 0.000293f, 0.000258f,
+ 0.000319f, 0.000394f, 0.000344f, 0.000369f, 0.000394f, 0.000410f, 0.000438f, 0.000509f, 0.000514f, 0.000580f, 0.000617f, 0.000684f,
+ 0.000807f, 0.000812f, 0.000914f, 0.001094f, 0.001183f, 0.001436f, 0.001639f, 0.002033f, 0.002523f, 0.003073f, 0.004063f, 0.005680f,
+ 0.008560f, 0.013466f, 0.024109f, 0.047791f, 0.102051f, 0.213867f, 0.740234f, 0.746582f, 0.748047f, 0.748535f, 0.749023f, 0.749023f,
+ 0.000000f, 0.000113f, 0.000108f, 0.000107f, 0.000104f, 0.000102f, 0.000099f, 0.000099f, 0.000097f, 0.000096f, 0.000095f, 0.000091f,
+ 0.000086f, 0.000081f, 0.000077f, 0.000073f, 0.000085f, 0.000091f, 0.000070f, 0.000102f, 0.000117f, 0.000131f, 0.000145f, 0.000148f,
+ 0.000171f, 0.000178f, 0.000178f, 0.000207f, 0.000225f, 0.000209f, 0.000285f, 0.000238f, 0.000260f, 0.000298f, 0.000331f, 0.000360f,
+ 0.000371f, 0.000346f, 0.000407f, 0.000443f, 0.000494f, 0.000516f, 0.000578f, 0.000662f, 0.000767f, 0.000847f, 0.001004f, 0.001149f,
+ 0.001451f, 0.001783f, 0.002310f, 0.003262f, 0.004593f, 0.007309f, 0.012985f, 0.026703f, 0.064026f, 0.158813f, 0.712891f, 0.719238f,
+ 0.722168f, 0.721680f, 0.722168f, 0.722656f, 0.000000f, 0.000105f, 0.000102f, 0.000098f, 0.000094f, 0.000092f, 0.000091f, 0.000089f,
+ 0.000088f, 0.000086f, 0.000085f, 0.000084f, 0.000083f, 0.000080f, 0.000076f, 0.000073f, 0.000069f, 0.000065f, 0.000062f, 0.000059f,
+ 0.000068f, 0.000063f, 0.000069f, 0.000074f, 0.000087f, 0.000102f, 0.000112f, 0.000130f, 0.000137f, 0.000129f, 0.000143f, 0.000168f,
+ 0.000180f, 0.000178f, 0.000189f, 0.000198f, 0.000222f, 0.000240f, 0.000262f, 0.000285f, 0.000304f, 0.000317f, 0.000339f, 0.000399f,
+ 0.000439f, 0.000490f, 0.000570f, 0.000658f, 0.000781f, 0.000988f, 0.001235f, 0.001674f, 0.002407f, 0.003725f, 0.006485f, 0.013199f,
+ 0.034546f, 0.107605f, 0.682129f, 0.691406f, 0.692871f, 0.691406f, 0.692871f, 0.692871f, 0.000105f, 0.000089f, 0.000085f, 0.000080f,
+ 0.000078f, 0.000078f, 0.000075f, 0.000074f, 0.000072f, 0.000072f, 0.000070f, 0.000071f, 0.000069f, 0.000069f, 0.000069f, 0.000068f,
+ 0.000066f, 0.000063f, 0.000060f, 0.000057f, 0.000054f, 0.000052f, 0.000049f, 0.000047f, 0.000046f, 0.000045f, 0.000048f, 0.000055f,
+ 0.000060f, 0.000068f, 0.000083f, 0.000087f, 0.000092f, 0.000103f, 0.000109f, 0.000117f, 0.000130f, 0.000150f, 0.000148f, 0.000142f,
+ 0.000167f, 0.000186f, 0.000210f, 0.000213f, 0.000232f, 0.000280f, 0.000292f, 0.000329f, 0.000391f, 0.000456f, 0.000596f, 0.000764f,
+ 0.001065f, 0.001633f, 0.002806f, 0.005909f, 0.015488f, 0.062378f, 0.651367f, 0.659668f, 0.661133f, 0.661133f, 0.660645f, 0.661621f,
+ 0.000034f, 0.000037f, 0.000048f, 0.000051f, 0.000047f, 0.000049f, 0.000047f, 0.000051f, 0.000049f, 0.000051f, 0.000049f, 0.000050f,
+ 0.000051f, 0.000050f, 0.000050f, 0.000049f, 0.000051f, 0.000050f, 0.000051f, 0.000050f, 0.000049f, 0.000047f, 0.000045f, 0.000043f,
+ 0.000041f, 0.000039f, 0.000037f, 0.000035f, 0.000033f, 0.000032f, 0.000030f, 0.000029f, 0.000034f, 0.000041f, 0.000046f, 0.000057f,
+ 0.000063f, 0.000067f, 0.000065f, 0.000072f, 0.000083f, 0.000093f, 0.000096f, 0.000102f, 0.000102f, 0.000135f, 0.000134f, 0.000151f,
+ 0.000184f, 0.000198f, 0.000245f, 0.000306f, 0.000425f, 0.000607f, 0.001032f, 0.002081f, 0.005886f, 0.027924f, 0.617188f, 0.625977f,
+ 0.627441f, 0.627930f, 0.626953f, 0.628418f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000006f, 0.000010f, 0.000014f,
+ 0.000016f, 0.000014f, 0.000019f, 0.000022f, 0.000022f, 0.000022f, 0.000025f, 0.000026f, 0.000027f, 0.000028f, 0.000029f, 0.000029f,
+ 0.000029f, 0.000030f, 0.000030f, 0.000031f, 0.000032f, 0.000032f, 0.000031f, 0.000030f, 0.000028f, 0.000027f, 0.000026f, 0.000024f,
+ 0.000023f, 0.000022f, 0.000021f, 0.000020f, 0.000019f, 0.000021f, 0.000022f, 0.000024f, 0.000027f, 0.000035f, 0.000041f, 0.000034f,
+ 0.000041f, 0.000052f, 0.000051f, 0.000051f, 0.000058f, 0.000070f, 0.000074f, 0.000103f, 0.000119f, 0.000169f, 0.000277f, 0.000510f,
+ 0.001495f, 0.008766f, 0.583008f, 0.590332f, 0.591797f, 0.591797f, 0.592285f, 0.592285f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000002f, 0.000003f, 0.000005f, 0.000006f, 0.000008f, 0.000009f, 0.000010f, 0.000010f,
+ 0.000012f, 0.000012f, 0.000013f, 0.000014f, 0.000015f, 0.000015f, 0.000015f, 0.000015f, 0.000014f, 0.000013f, 0.000013f, 0.000012f,
+ 0.000011f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000014f, 0.000011f, 0.000015f, 0.000017f, 0.000017f, 0.000021f, 0.000020f,
+ 0.000026f, 0.000026f, 0.000042f, 0.000069f, 0.000178f, 0.001302f, 0.544434f, 0.553711f, 0.554688f, 0.554688f, 0.556152f, 0.556641f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000002f, 0.000003f, 0.000003f,
+ 0.000003f, 0.000003f, 0.000003f, 0.000002f, 0.000002f, 0.000001f, 0.000003f, 0.000003f, 0.000004f, 0.000014f, 0.506836f, 0.515137f,
+ 0.516113f, 0.516602f, 0.517090f, 0.517578f,
+ },
+ {
+ 0.089539f, 0.244873f, 0.368164f, 0.464355f, 0.539551f, 0.599121f, 0.648438f, 0.688477f, 0.721680f, 0.749512f, 0.772461f, 0.793945f,
+ 0.811523f, 0.826172f, 0.841309f, 0.854004f, 0.863770f, 0.874512f, 0.883301f, 0.891602f, 0.898438f, 0.906250f, 0.912109f, 0.917969f,
+ 0.922852f, 0.928223f, 0.932617f, 0.937012f, 0.940918f, 0.944336f, 0.948242f, 0.951660f, 0.954590f, 0.957520f, 0.960449f, 0.962891f,
+ 0.965820f, 0.967773f, 0.970215f, 0.972656f, 0.974609f, 0.976074f, 0.978516f, 0.979492f, 0.981934f, 0.983398f, 0.984863f, 0.986328f,
+ 0.987793f, 0.988770f, 0.990234f, 0.991699f, 0.993164f, 0.994141f, 0.995117f, 0.996582f, 0.997559f, 0.998535f, 0.999023f, 0.998535f,
+ 0.997559f, 0.997070f, 0.996582f, 0.995605f, 0.045563f, 0.143921f, 0.242798f, 0.334717f, 0.417969f, 0.489258f, 0.550293f, 0.602051f,
+ 0.646484f, 0.683594f, 0.715820f, 0.743652f, 0.767090f, 0.788086f, 0.805664f, 0.822266f, 0.836426f, 0.849609f, 0.861328f, 0.870117f,
+ 0.879883f, 0.889160f, 0.896973f, 0.903320f, 0.909668f, 0.916016f, 0.921875f, 0.926758f, 0.931641f, 0.936523f, 0.940430f, 0.943848f,
+ 0.947266f, 0.951172f, 0.954102f, 0.957520f, 0.960449f, 0.962891f, 0.965820f, 0.968262f, 0.970215f, 0.973145f, 0.974121f, 0.976074f,
+ 0.979004f, 0.980469f, 0.982422f, 0.983887f, 0.985352f, 0.986816f, 0.988281f, 0.989746f, 0.991211f, 0.992188f, 0.994141f, 0.995117f,
+ 0.996094f, 0.997070f, 0.998535f, 0.997559f, 0.997070f, 0.996582f, 0.996094f, 0.995117f, 0.026855f, 0.089233f, 0.159790f, 0.234619f,
+ 0.308838f, 0.381348f, 0.447754f, 0.507812f, 0.561035f, 0.606934f, 0.646484f, 0.683105f, 0.712402f, 0.740234f, 0.763184f, 0.784668f,
+ 0.802246f, 0.819336f, 0.833984f, 0.846680f, 0.857910f, 0.868652f, 0.878418f, 0.886719f, 0.895508f, 0.903320f, 0.909668f, 0.915527f,
+ 0.920410f, 0.926270f, 0.931152f, 0.935547f, 0.940430f, 0.943848f, 0.947754f, 0.951172f, 0.954590f, 0.958008f, 0.960449f, 0.963379f,
+ 0.966309f, 0.968750f, 0.971191f, 0.973145f, 0.975586f, 0.977051f, 0.979004f, 0.981445f, 0.982910f, 0.983887f, 0.985840f, 0.987305f,
+ 0.988770f, 0.990723f, 0.992188f, 0.993164f, 0.994629f, 0.996094f, 0.998047f, 0.997070f, 0.996582f, 0.996094f, 0.995605f, 0.995117f,
+ 0.017746f, 0.058746f, 0.108276f, 0.163818f, 0.224365f, 0.288086f, 0.351562f, 0.413086f, 0.470947f, 0.522949f, 0.569824f, 0.612793f,
+ 0.650879f, 0.684570f, 0.713867f, 0.739258f, 0.762695f, 0.783203f, 0.800781f, 0.817871f, 0.833008f, 0.845215f, 0.857422f, 0.868164f,
+ 0.877441f, 0.886230f, 0.894043f, 0.902832f, 0.908691f, 0.915039f, 0.921387f, 0.925781f, 0.930664f, 0.936035f, 0.939941f, 0.944336f,
+ 0.948242f, 0.951660f, 0.955078f, 0.957520f, 0.961426f, 0.964355f, 0.967285f, 0.968750f, 0.971680f, 0.974121f, 0.975586f, 0.978027f,
+ 0.979980f, 0.981934f, 0.983887f, 0.985352f, 0.987305f, 0.988770f, 0.989746f, 0.991211f, 0.992676f, 0.993652f, 0.997070f, 0.996582f,
+ 0.996582f, 0.996094f, 0.995117f, 0.994629f, 0.012337f, 0.041229f, 0.075928f, 0.117065f, 0.163208f, 0.214478f, 0.270020f, 0.327148f,
+ 0.383301f, 0.437500f, 0.490234f, 0.536621f, 0.581543f, 0.621094f, 0.656250f, 0.688477f, 0.716797f, 0.741699f, 0.763672f, 0.784668f,
+ 0.802246f, 0.818359f, 0.832520f, 0.845703f, 0.857422f, 0.868164f, 0.877930f, 0.886230f, 0.895020f, 0.902344f, 0.909668f, 0.915039f,
+ 0.921875f, 0.926758f, 0.931641f, 0.937012f, 0.940430f, 0.946289f, 0.949219f, 0.952637f, 0.956055f, 0.958984f, 0.961914f, 0.964844f,
+ 0.967773f, 0.970215f, 0.972656f, 0.974609f, 0.976562f, 0.979004f, 0.980957f, 0.982910f, 0.984863f, 0.986816f, 0.987793f, 0.989746f,
+ 0.990723f, 0.992676f, 0.996582f, 0.996094f, 0.995605f, 0.995117f, 0.994629f, 0.994141f, 0.009315f, 0.030411f, 0.055756f, 0.085632f,
+ 0.121094f, 0.160889f, 0.206055f, 0.254150f, 0.305664f, 0.357422f, 0.408447f, 0.459717f, 0.506836f, 0.551270f, 0.592773f, 0.629395f,
+ 0.662598f, 0.692871f, 0.719727f, 0.745117f, 0.767090f, 0.786133f, 0.804688f, 0.819336f, 0.834473f, 0.847168f, 0.858398f, 0.869629f,
+ 0.879395f, 0.888672f, 0.895020f, 0.903320f, 0.910156f, 0.916016f, 0.922363f, 0.928223f, 0.933105f, 0.937012f, 0.941406f, 0.946289f,
+ 0.950195f, 0.954102f, 0.957031f, 0.960449f, 0.963379f, 0.965820f, 0.969238f, 0.971191f, 0.974121f, 0.976074f, 0.978027f, 0.979980f,
+ 0.982422f, 0.984375f, 0.985840f, 0.987793f, 0.989258f, 0.990723f, 0.995605f, 0.995605f, 0.995117f, 0.994629f, 0.994629f, 0.993652f,
+ 0.006634f, 0.022736f, 0.041962f, 0.064026f, 0.090759f, 0.122192f, 0.157593f, 0.197510f, 0.240356f, 0.287354f, 0.335693f, 0.384766f,
+ 0.432373f, 0.479736f, 0.523438f, 0.565430f, 0.604004f, 0.639160f, 0.670898f, 0.699219f, 0.726562f, 0.749023f, 0.770508f, 0.790527f,
+ 0.806641f, 0.822754f, 0.836426f, 0.848633f, 0.859863f, 0.871582f, 0.881348f, 0.889160f, 0.897949f, 0.905273f, 0.912598f, 0.918945f,
+ 0.924316f, 0.929199f, 0.935059f, 0.938965f, 0.943848f, 0.947266f, 0.951660f, 0.955078f, 0.958496f, 0.961914f, 0.964844f, 0.967773f,
+ 0.970703f, 0.973145f, 0.975098f, 0.977539f, 0.979492f, 0.981445f, 0.983887f, 0.985352f, 0.987305f, 0.989258f, 0.995117f, 0.994629f,
+ 0.994141f, 0.994141f, 0.993652f, 0.993164f, 0.005428f, 0.017807f, 0.032166f, 0.049652f, 0.070007f, 0.093811f, 0.121765f, 0.153564f,
+ 0.189087f, 0.228516f, 0.270752f, 0.316162f, 0.362061f, 0.408936f, 0.453857f, 0.498779f, 0.540527f, 0.579590f, 0.615723f, 0.649902f,
+ 0.679688f, 0.707520f, 0.732422f, 0.755371f, 0.775391f, 0.794922f, 0.811035f, 0.826172f, 0.839844f, 0.852051f, 0.864258f, 0.875000f,
+ 0.883301f, 0.892578f, 0.899902f, 0.907715f, 0.914062f, 0.920410f, 0.926270f, 0.931641f, 0.936035f, 0.940918f, 0.945312f, 0.949219f,
+ 0.954102f, 0.957031f, 0.960938f, 0.963379f, 0.966797f, 0.969238f, 0.972168f, 0.974609f, 0.977051f, 0.979492f, 0.980957f, 0.983398f,
+ 0.985352f, 0.987305f, 0.994141f, 0.994141f, 0.994141f, 0.993652f, 0.993164f, 0.992676f, 0.004223f, 0.014046f, 0.025452f, 0.039062f,
+ 0.055115f, 0.073608f, 0.095642f, 0.120239f, 0.149292f, 0.182251f, 0.217529f, 0.257080f, 0.298828f, 0.342773f, 0.387207f, 0.431152f,
+ 0.474609f, 0.516602f, 0.556641f, 0.593750f, 0.628418f, 0.660156f, 0.689453f, 0.715820f, 0.740723f, 0.762207f, 0.782227f, 0.799805f,
+ 0.816406f, 0.830566f, 0.844727f, 0.855469f, 0.867188f, 0.877441f, 0.886230f, 0.895020f, 0.903809f, 0.910645f, 0.917480f, 0.923340f,
+ 0.928711f, 0.934570f, 0.939453f, 0.943848f, 0.948242f, 0.952148f, 0.956055f, 0.959473f, 0.961914f, 0.965820f, 0.968750f, 0.971680f,
+ 0.974121f, 0.975586f, 0.979004f, 0.980957f, 0.983398f, 0.985352f, 0.993652f, 0.993652f, 0.993164f, 0.993164f, 0.992676f, 0.991699f,
+ 0.003532f, 0.011536f, 0.020645f, 0.031342f, 0.044098f, 0.058624f, 0.075989f, 0.096252f, 0.119141f, 0.145386f, 0.175049f, 0.208130f,
+ 0.244385f, 0.283203f, 0.324463f, 0.367432f, 0.410400f, 0.453369f, 0.495361f, 0.534668f, 0.572266f, 0.607910f, 0.641602f, 0.672852f,
+ 0.700195f, 0.725098f, 0.748047f, 0.769531f, 0.789062f, 0.806152f, 0.821777f, 0.835938f, 0.848633f, 0.860352f, 0.872070f, 0.881836f,
+ 0.890625f, 0.898926f, 0.906738f, 0.913086f, 0.919922f, 0.925781f, 0.931641f, 0.936523f, 0.941406f, 0.946289f, 0.950684f, 0.954590f,
+ 0.958008f, 0.961426f, 0.964844f, 0.968262f, 0.970703f, 0.973633f, 0.976074f, 0.978516f, 0.980469f, 0.982910f, 0.992676f, 0.992676f,
+ 0.992188f, 0.992188f, 0.991699f, 0.990723f, 0.002850f, 0.009483f, 0.016647f, 0.025833f, 0.035889f, 0.047424f, 0.061646f, 0.076660f,
+ 0.095642f, 0.117065f, 0.141113f, 0.168457f, 0.198975f, 0.233032f, 0.269775f, 0.308838f, 0.349854f, 0.391357f, 0.432861f, 0.474121f,
+ 0.515625f, 0.552734f, 0.589355f, 0.622559f, 0.654785f, 0.683594f, 0.710938f, 0.735352f, 0.757812f, 0.777344f, 0.795898f, 0.812988f,
+ 0.827637f, 0.842285f, 0.854492f, 0.866211f, 0.876953f, 0.886719f, 0.895508f, 0.902832f, 0.911133f, 0.917969f, 0.924316f, 0.929688f,
+ 0.935059f, 0.940430f, 0.945312f, 0.949219f, 0.953125f, 0.958008f, 0.961426f, 0.964844f, 0.967285f, 0.970703f, 0.973633f, 0.975586f,
+ 0.978516f, 0.981445f, 0.991699f, 0.992188f, 0.991699f, 0.991211f, 0.991211f, 0.990723f, 0.002628f, 0.007713f, 0.014069f, 0.021484f,
+ 0.029709f, 0.038910f, 0.050201f, 0.063171f, 0.078186f, 0.094849f, 0.114563f, 0.137329f, 0.162720f, 0.190918f, 0.222656f, 0.257568f,
+ 0.293945f, 0.332764f, 0.372803f, 0.414551f, 0.455078f, 0.495361f, 0.533691f, 0.571289f, 0.606445f, 0.639160f, 0.668457f, 0.697754f,
+ 0.723633f, 0.746094f, 0.767090f, 0.787598f, 0.804199f, 0.820801f, 0.834473f, 0.848633f, 0.860352f, 0.872559f, 0.882324f, 0.891602f,
+ 0.899902f, 0.907715f, 0.915039f, 0.921387f, 0.927734f, 0.934082f, 0.938965f, 0.944824f, 0.948730f, 0.953125f, 0.956543f, 0.960938f,
+ 0.963867f, 0.967285f, 0.970215f, 0.973145f, 0.976074f, 0.978516f, 0.990234f, 0.990723f, 0.990723f, 0.991211f, 0.990234f, 0.990234f,
+ 0.002131f, 0.006535f, 0.012016f, 0.017670f, 0.024780f, 0.032837f, 0.041199f, 0.051819f, 0.063904f, 0.077759f, 0.093689f, 0.112610f,
+ 0.133057f, 0.156860f, 0.183472f, 0.213257f, 0.245605f, 0.281006f, 0.318115f, 0.357422f, 0.397217f, 0.437500f, 0.478271f, 0.516602f,
+ 0.554688f, 0.589844f, 0.623535f, 0.654785f, 0.684082f, 0.710938f, 0.734375f, 0.757812f, 0.777832f, 0.795898f, 0.813477f, 0.828613f,
+ 0.843262f, 0.855957f, 0.867676f, 0.878906f, 0.888184f, 0.897461f, 0.905273f, 0.912598f, 0.919922f, 0.926758f, 0.932129f, 0.937988f,
+ 0.942871f, 0.947754f, 0.951660f, 0.955566f, 0.960449f, 0.964355f, 0.967285f, 0.970215f, 0.973145f, 0.976074f, 0.989746f, 0.990234f,
+ 0.990234f, 0.990234f, 0.989746f, 0.988770f, 0.001566f, 0.005798f, 0.010231f, 0.015259f, 0.020920f, 0.027176f, 0.034607f, 0.043335f,
+ 0.052887f, 0.064392f, 0.077576f, 0.092712f, 0.109802f, 0.129639f, 0.151611f, 0.176758f, 0.204346f, 0.235474f, 0.269043f, 0.304688f,
+ 0.342529f, 0.381836f, 0.421143f, 0.460449f, 0.500488f, 0.538086f, 0.574219f, 0.608887f, 0.640625f, 0.670898f, 0.699219f, 0.725098f,
+ 0.748535f, 0.769043f, 0.788574f, 0.807129f, 0.823242f, 0.837402f, 0.850586f, 0.863281f, 0.874512f, 0.885254f, 0.894043f, 0.902832f,
+ 0.910645f, 0.917969f, 0.924805f, 0.931152f, 0.936523f, 0.941895f, 0.947266f, 0.951172f, 0.955566f, 0.960449f, 0.963867f, 0.966797f,
+ 0.970703f, 0.973145f, 0.988281f, 0.989258f, 0.989258f, 0.989258f, 0.988770f, 0.988281f, 0.001427f, 0.004749f, 0.008934f, 0.012833f,
+ 0.017670f, 0.023483f, 0.029114f, 0.036438f, 0.044556f, 0.054047f, 0.064453f, 0.077148f, 0.091309f, 0.107544f, 0.125854f, 0.146729f,
+ 0.170776f, 0.197266f, 0.226440f, 0.257568f, 0.292236f, 0.329346f, 0.367188f, 0.405762f, 0.445557f, 0.484619f, 0.522949f, 0.559570f,
+ 0.595215f, 0.627441f, 0.659180f, 0.687012f, 0.714355f, 0.739258f, 0.761719f, 0.781738f, 0.800781f, 0.817383f, 0.833984f, 0.847168f,
+ 0.859375f, 0.872070f, 0.882324f, 0.891602f, 0.900879f, 0.909668f, 0.916504f, 0.923828f, 0.930176f, 0.936523f, 0.941895f, 0.946777f,
+ 0.951172f, 0.956055f, 0.960449f, 0.963867f, 0.967285f, 0.970703f, 0.987305f, 0.988770f, 0.988281f, 0.987793f, 0.987793f, 0.987793f,
+ 0.001357f, 0.004501f, 0.007557f, 0.011284f, 0.015236f, 0.019791f, 0.025101f, 0.030838f, 0.037628f, 0.045532f, 0.054596f, 0.064636f,
+ 0.076355f, 0.089905f, 0.105042f, 0.122498f, 0.142334f, 0.164307f, 0.189697f, 0.217896f, 0.248413f, 0.281494f, 0.316406f, 0.354004f,
+ 0.391846f, 0.430664f, 0.469971f, 0.508301f, 0.545898f, 0.582031f, 0.615723f, 0.647461f, 0.677734f, 0.704590f, 0.731445f, 0.754395f,
+ 0.775391f, 0.794922f, 0.811523f, 0.829102f, 0.842773f, 0.856934f, 0.868652f, 0.880371f, 0.891113f, 0.899414f, 0.908203f, 0.915527f,
+ 0.922852f, 0.930176f, 0.936035f, 0.941406f, 0.947266f, 0.951660f, 0.957031f, 0.960449f, 0.963867f, 0.968262f, 0.986328f, 0.987305f,
+ 0.987793f, 0.987305f, 0.987305f, 0.986816f, 0.001239f, 0.003864f, 0.006699f, 0.009621f, 0.013008f, 0.017059f, 0.021805f, 0.026703f,
+ 0.032562f, 0.039185f, 0.045807f, 0.054352f, 0.064514f, 0.075439f, 0.088257f, 0.102478f, 0.119263f, 0.138306f, 0.159546f, 0.183228f,
+ 0.209961f, 0.239258f, 0.271484f, 0.305176f, 0.341797f, 0.379639f, 0.417480f, 0.456787f, 0.495605f, 0.532227f, 0.570801f, 0.604980f,
+ 0.637207f, 0.666992f, 0.696289f, 0.722656f, 0.746582f, 0.768555f, 0.789062f, 0.808105f, 0.824219f, 0.839844f, 0.854492f, 0.865723f,
+ 0.878418f, 0.888672f, 0.897461f, 0.906738f, 0.915039f, 0.922363f, 0.929199f, 0.935547f, 0.941895f, 0.946289f, 0.952148f, 0.956543f,
+ 0.960449f, 0.964844f, 0.985352f, 0.986816f, 0.986816f, 0.986328f, 0.986328f, 0.985840f, 0.001151f, 0.003429f, 0.005753f, 0.008400f,
+ 0.011391f, 0.014877f, 0.018494f, 0.022858f, 0.028046f, 0.033112f, 0.039642f, 0.046661f, 0.054565f, 0.064026f, 0.074280f, 0.086243f,
+ 0.100403f, 0.116150f, 0.133789f, 0.154053f, 0.176636f, 0.202393f, 0.230957f, 0.261719f, 0.295166f, 0.330322f, 0.367432f, 0.405518f,
+ 0.445312f, 0.483398f, 0.520996f, 0.558105f, 0.594238f, 0.626465f, 0.659668f, 0.688477f, 0.714844f, 0.740723f, 0.763672f, 0.784180f,
+ 0.804199f, 0.821289f, 0.837402f, 0.852051f, 0.864258f, 0.876465f, 0.886719f, 0.897949f, 0.906250f, 0.915039f, 0.922363f, 0.929199f,
+ 0.935547f, 0.941406f, 0.946777f, 0.952637f, 0.958008f, 0.961914f, 0.983887f, 0.985840f, 0.985352f, 0.985352f, 0.984863f, 0.984863f,
+ 0.001000f, 0.002768f, 0.005127f, 0.007515f, 0.010155f, 0.013283f, 0.016205f, 0.019714f, 0.023987f, 0.028854f, 0.033905f, 0.040161f,
+ 0.046814f, 0.054199f, 0.063110f, 0.073303f, 0.084839f, 0.098145f, 0.112854f, 0.129883f, 0.149292f, 0.171387f, 0.195435f, 0.222778f,
+ 0.252686f, 0.285400f, 0.320312f, 0.356689f, 0.394531f, 0.433105f, 0.471924f, 0.510742f, 0.547852f, 0.584473f, 0.617676f, 0.650879f,
+ 0.680664f, 0.708984f, 0.734375f, 0.759277f, 0.780762f, 0.799805f, 0.817383f, 0.834473f, 0.849121f, 0.862793f, 0.875488f, 0.886719f,
+ 0.896484f, 0.906250f, 0.915039f, 0.923828f, 0.930176f, 0.936035f, 0.942871f, 0.948242f, 0.953613f, 0.958008f, 0.982910f, 0.983887f,
+ 0.984375f, 0.983887f, 0.984375f, 0.983398f, 0.000799f, 0.002705f, 0.004459f, 0.006573f, 0.008842f, 0.011375f, 0.014099f, 0.017487f,
+ 0.020798f, 0.024963f, 0.029465f, 0.034637f, 0.039703f, 0.046478f, 0.054047f, 0.062256f, 0.072388f, 0.082947f, 0.095764f, 0.110229f,
+ 0.126099f, 0.144775f, 0.165771f, 0.189697f, 0.216187f, 0.244995f, 0.276123f, 0.310303f, 0.346191f, 0.384521f, 0.422607f, 0.461670f,
+ 0.500000f, 0.538574f, 0.575195f, 0.609863f, 0.643555f, 0.673828f, 0.702637f, 0.730469f, 0.754395f, 0.777344f, 0.797363f, 0.815430f,
+ 0.833008f, 0.848633f, 0.861328f, 0.875000f, 0.886719f, 0.896973f, 0.906738f, 0.915039f, 0.923340f, 0.930176f, 0.936523f, 0.943848f,
+ 0.948730f, 0.954102f, 0.981445f, 0.983398f, 0.982910f, 0.983398f, 0.982910f, 0.982910f, 0.000774f, 0.002554f, 0.003899f, 0.005875f,
+ 0.007759f, 0.009949f, 0.012733f, 0.015060f, 0.018280f, 0.021667f, 0.025574f, 0.029678f, 0.034698f, 0.040405f, 0.046570f, 0.053650f,
+ 0.061462f, 0.071106f, 0.081360f, 0.093323f, 0.107300f, 0.122864f, 0.140747f, 0.160522f, 0.183960f, 0.209229f, 0.237305f, 0.268799f,
+ 0.302002f, 0.337402f, 0.374023f, 0.413330f, 0.451904f, 0.490967f, 0.529785f, 0.567383f, 0.603027f, 0.636719f, 0.668457f, 0.698242f,
+ 0.725586f, 0.750977f, 0.773926f, 0.793945f, 0.813965f, 0.831543f, 0.847656f, 0.861816f, 0.874512f, 0.886719f, 0.897461f, 0.906738f,
+ 0.915527f, 0.923828f, 0.931641f, 0.937988f, 0.944824f, 0.949707f, 0.979980f, 0.981934f, 0.981934f, 0.981934f, 0.981934f, 0.981445f,
+ 0.000657f, 0.001934f, 0.003330f, 0.005280f, 0.006748f, 0.009079f, 0.010994f, 0.013763f, 0.015945f, 0.019150f, 0.022003f, 0.026001f,
+ 0.030350f, 0.034790f, 0.040253f, 0.045898f, 0.052795f, 0.060852f, 0.069641f, 0.079346f, 0.091187f, 0.104492f, 0.119751f, 0.136963f,
+ 0.156372f, 0.178345f, 0.203247f, 0.230957f, 0.260742f, 0.294189f, 0.328613f, 0.365723f, 0.403564f, 0.443115f, 0.482910f, 0.521484f,
+ 0.559570f, 0.596680f, 0.630859f, 0.664062f, 0.694336f, 0.722168f, 0.747559f, 0.771484f, 0.793457f, 0.813477f, 0.830078f, 0.846191f,
+ 0.861816f, 0.874023f, 0.887207f, 0.898438f, 0.908691f, 0.916992f, 0.925293f, 0.933594f, 0.939941f, 0.946777f, 0.978516f, 0.980469f,
+ 0.980469f, 0.980469f, 0.980469f, 0.980469f, 0.000818f, 0.001935f, 0.003246f, 0.004658f, 0.006229f, 0.007912f, 0.010017f, 0.012093f,
+ 0.014259f, 0.016586f, 0.019653f, 0.022659f, 0.026413f, 0.030289f, 0.034790f, 0.039917f, 0.045441f, 0.052338f, 0.059479f, 0.068115f,
+ 0.077759f, 0.089050f, 0.102051f, 0.116272f, 0.133179f, 0.152344f, 0.173340f, 0.197876f, 0.224243f, 0.254150f, 0.286621f, 0.321533f,
+ 0.357666f, 0.396729f, 0.436279f, 0.475830f, 0.514648f, 0.553711f, 0.590332f, 0.626465f, 0.659180f, 0.689941f, 0.719238f, 0.746094f,
+ 0.770020f, 0.792480f, 0.812500f, 0.830566f, 0.846680f, 0.862305f, 0.875977f, 0.888184f, 0.899414f, 0.910156f, 0.918945f, 0.927246f,
+ 0.935059f, 0.941895f, 0.977051f, 0.979004f, 0.979492f, 0.979004f, 0.979492f, 0.979004f, 0.000583f, 0.001696f, 0.003044f, 0.004276f,
+ 0.005394f, 0.007111f, 0.009048f, 0.010727f, 0.012802f, 0.014549f, 0.017319f, 0.019943f, 0.023132f, 0.026459f, 0.030212f, 0.034576f,
+ 0.039612f, 0.045105f, 0.051422f, 0.058594f, 0.066833f, 0.076416f, 0.087341f, 0.099792f, 0.113647f, 0.130005f, 0.147827f, 0.168945f,
+ 0.192261f, 0.218750f, 0.247803f, 0.280029f, 0.314209f, 0.351074f, 0.389404f, 0.429199f, 0.468750f, 0.508301f, 0.547852f, 0.585938f,
+ 0.622070f, 0.655762f, 0.687988f, 0.718262f, 0.744629f, 0.769531f, 0.792480f, 0.812500f, 0.832520f, 0.848633f, 0.863770f, 0.877441f,
+ 0.890137f, 0.901367f, 0.912109f, 0.921387f, 0.929199f, 0.937500f, 0.975586f, 0.978027f, 0.978027f, 0.977539f, 0.977539f, 0.977051f,
+ 0.000463f, 0.001634f, 0.002899f, 0.003574f, 0.004932f, 0.006233f, 0.007866f, 0.009644f, 0.011055f, 0.012894f, 0.015518f, 0.017792f,
+ 0.020279f, 0.023178f, 0.026657f, 0.030136f, 0.034271f, 0.039062f, 0.044586f, 0.050446f, 0.057739f, 0.065613f, 0.074646f, 0.084900f,
+ 0.097107f, 0.111023f, 0.126099f, 0.143921f, 0.164673f, 0.187500f, 0.213257f, 0.242065f, 0.273926f, 0.308594f, 0.344971f, 0.383301f,
+ 0.423340f, 0.463623f, 0.503906f, 0.543945f, 0.582520f, 0.619629f, 0.653809f, 0.686523f, 0.717285f, 0.744629f, 0.770020f, 0.792969f,
+ 0.814453f, 0.833496f, 0.850098f, 0.866211f, 0.879395f, 0.893066f, 0.904297f, 0.914551f, 0.923828f, 0.932129f, 0.973145f, 0.976074f,
+ 0.976562f, 0.976074f, 0.976074f, 0.976074f, 0.000472f, 0.001289f, 0.002508f, 0.003481f, 0.004459f, 0.005894f, 0.007042f, 0.008232f,
+ 0.009972f, 0.011719f, 0.013435f, 0.015884f, 0.017899f, 0.020386f, 0.023422f, 0.026428f, 0.030411f, 0.034180f, 0.038757f, 0.043854f,
+ 0.049652f, 0.056549f, 0.064270f, 0.073303f, 0.083252f, 0.095093f, 0.107910f, 0.123169f, 0.141113f, 0.160645f, 0.183472f, 0.208618f,
+ 0.237305f, 0.268799f, 0.302734f, 0.339600f, 0.377930f, 0.418457f, 0.459473f, 0.500000f, 0.540527f, 0.579102f, 0.617188f, 0.652832f,
+ 0.685547f, 0.716309f, 0.745117f, 0.771484f, 0.794922f, 0.815918f, 0.834961f, 0.853027f, 0.868652f, 0.882324f, 0.895996f, 0.907227f,
+ 0.916992f, 0.927246f, 0.972168f, 0.974121f, 0.975098f, 0.973633f, 0.974609f, 0.973633f, 0.000238f, 0.001453f, 0.002047f, 0.002985f,
+ 0.004227f, 0.005272f, 0.006096f, 0.007309f, 0.008957f, 0.010437f, 0.012184f, 0.014214f, 0.015793f, 0.018082f, 0.020538f, 0.023270f,
+ 0.026505f, 0.029648f, 0.033813f, 0.038300f, 0.043457f, 0.049042f, 0.055298f, 0.062744f, 0.070984f, 0.081299f, 0.092590f, 0.105591f,
+ 0.120361f, 0.137695f, 0.156982f, 0.179443f, 0.204346f, 0.232788f, 0.263672f, 0.297363f, 0.334229f, 0.373047f, 0.414307f, 0.455322f,
+ 0.497314f, 0.538086f, 0.578613f, 0.616211f, 0.653320f, 0.686523f, 0.718262f, 0.747559f, 0.773438f, 0.797363f, 0.818848f, 0.838867f,
+ 0.856934f, 0.871582f, 0.885742f, 0.898926f, 0.910645f, 0.920410f, 0.970215f, 0.971680f, 0.972656f, 0.972656f, 0.972168f, 0.972168f,
+ 0.000376f, 0.001075f, 0.002052f, 0.002823f, 0.003603f, 0.004509f, 0.005619f, 0.007008f, 0.008064f, 0.009132f, 0.010849f, 0.012314f,
+ 0.013817f, 0.015945f, 0.018188f, 0.020676f, 0.022995f, 0.026230f, 0.029587f, 0.033234f, 0.037598f, 0.042328f, 0.048004f, 0.054230f,
+ 0.061188f, 0.069824f, 0.079468f, 0.090454f, 0.103271f, 0.117493f, 0.134644f, 0.153931f, 0.175293f, 0.200806f, 0.228149f, 0.259277f,
+ 0.293945f, 0.330566f, 0.370117f, 0.410889f, 0.453369f, 0.495605f, 0.537109f, 0.578125f, 0.616699f, 0.653809f, 0.689453f, 0.721191f,
+ 0.750000f, 0.776855f, 0.800293f, 0.822754f, 0.841309f, 0.859863f, 0.876465f, 0.890137f, 0.902832f, 0.914062f, 0.967773f, 0.970703f,
+ 0.970703f, 0.970703f, 0.970703f, 0.970703f, 0.000237f, 0.000972f, 0.001674f, 0.002413f, 0.003336f, 0.003956f, 0.005093f, 0.006039f,
+ 0.007069f, 0.008202f, 0.009613f, 0.011017f, 0.012520f, 0.014282f, 0.016068f, 0.017853f, 0.020508f, 0.023117f, 0.025986f, 0.029160f,
+ 0.032898f, 0.036865f, 0.041565f, 0.046997f, 0.052887f, 0.060089f, 0.068176f, 0.077515f, 0.088257f, 0.100586f, 0.114929f, 0.131592f,
+ 0.150635f, 0.172241f, 0.196411f, 0.224731f, 0.255859f, 0.290039f, 0.327393f, 0.367188f, 0.409180f, 0.451172f, 0.493896f, 0.536621f,
+ 0.578613f, 0.618164f, 0.655762f, 0.691406f, 0.724121f, 0.753906f, 0.781738f, 0.805176f, 0.827637f, 0.847656f, 0.864746f, 0.880859f,
+ 0.895508f, 0.907715f, 0.965332f, 0.968262f, 0.968750f, 0.969238f, 0.967773f, 0.967773f, 0.000450f, 0.001033f, 0.001554f, 0.002131f,
+ 0.002939f, 0.003662f, 0.004551f, 0.005722f, 0.006405f, 0.007542f, 0.008484f, 0.009750f, 0.011017f, 0.012596f, 0.014046f, 0.015854f,
+ 0.017975f, 0.020264f, 0.022736f, 0.025497f, 0.028671f, 0.031952f, 0.036011f, 0.040741f, 0.045746f, 0.051910f, 0.058868f, 0.066772f,
+ 0.075867f, 0.086304f, 0.098328f, 0.112244f, 0.128784f, 0.147217f, 0.168945f, 0.193848f, 0.221558f, 0.252441f, 0.287109f, 0.324951f,
+ 0.365234f, 0.407715f, 0.450684f, 0.494629f, 0.539062f, 0.580566f, 0.621094f, 0.659668f, 0.695801f, 0.729004f, 0.758789f, 0.786133f,
+ 0.810547f, 0.833008f, 0.852539f, 0.870117f, 0.886719f, 0.900879f, 0.962891f, 0.966309f, 0.966309f, 0.966797f, 0.966797f, 0.966309f,
+ 0.000304f, 0.001050f, 0.001257f, 0.002295f, 0.002689f, 0.003885f, 0.004284f, 0.004726f, 0.005547f, 0.006721f, 0.007595f, 0.008667f,
+ 0.009811f, 0.011330f, 0.012642f, 0.014130f, 0.016098f, 0.017975f, 0.019867f, 0.022247f, 0.024811f, 0.028030f, 0.031403f, 0.035461f,
+ 0.039642f, 0.044800f, 0.050720f, 0.057495f, 0.065002f, 0.073914f, 0.084290f, 0.095947f, 0.109985f, 0.126343f, 0.144409f, 0.166138f,
+ 0.190918f, 0.218750f, 0.250244f, 0.285400f, 0.323730f, 0.364258f, 0.407471f, 0.452148f, 0.496338f, 0.540527f, 0.584473f, 0.625977f,
+ 0.665039f, 0.701172f, 0.735352f, 0.765137f, 0.792480f, 0.817383f, 0.840332f, 0.859863f, 0.876953f, 0.893066f, 0.959961f, 0.963379f,
+ 0.963867f, 0.964355f, 0.963867f, 0.963867f, 0.000228f, 0.000682f, 0.001293f, 0.001717f, 0.002352f, 0.003160f, 0.003626f, 0.004360f,
+ 0.005348f, 0.005871f, 0.006870f, 0.007660f, 0.008957f, 0.010002f, 0.011299f, 0.012375f, 0.014099f, 0.015900f, 0.017670f, 0.019363f,
+ 0.022034f, 0.024216f, 0.027420f, 0.030930f, 0.034454f, 0.038910f, 0.044006f, 0.049530f, 0.055878f, 0.063477f, 0.072083f, 0.082275f,
+ 0.094177f, 0.107666f, 0.123840f, 0.142090f, 0.163452f, 0.188477f, 0.216919f, 0.248047f, 0.283447f, 0.322754f, 0.364990f, 0.408447f,
+ 0.453613f, 0.500000f, 0.544922f, 0.589355f, 0.631348f, 0.671387f, 0.708008f, 0.742188f, 0.773438f, 0.800781f, 0.824219f, 0.846680f,
+ 0.866699f, 0.884277f, 0.958008f, 0.960938f, 0.961426f, 0.962402f, 0.961914f, 0.960938f, 0.000239f, 0.000731f, 0.001204f, 0.001637f,
+ 0.002144f, 0.002913f, 0.003521f, 0.003828f, 0.004517f, 0.005291f, 0.006203f, 0.006954f, 0.007740f, 0.008911f, 0.010239f, 0.011017f,
+ 0.012413f, 0.013863f, 0.015396f, 0.017181f, 0.019196f, 0.021439f, 0.024078f, 0.026993f, 0.030182f, 0.033752f, 0.038055f, 0.042664f,
+ 0.048004f, 0.054657f, 0.061920f, 0.070312f, 0.080688f, 0.092041f, 0.105774f, 0.121094f, 0.140015f, 0.161255f, 0.186523f, 0.214966f,
+ 0.246948f, 0.283203f, 0.322998f, 0.365967f, 0.410400f, 0.457275f, 0.503906f, 0.550781f, 0.596191f, 0.638672f, 0.678711f, 0.716797f,
+ 0.750488f, 0.781738f, 0.809082f, 0.833496f, 0.855469f, 0.874512f, 0.954590f, 0.958008f, 0.958984f, 0.958984f, 0.958984f, 0.958984f,
+ 0.000226f, 0.000663f, 0.001073f, 0.001420f, 0.002163f, 0.002567f, 0.003052f, 0.003433f, 0.004181f, 0.004734f, 0.005516f, 0.006424f,
+ 0.007050f, 0.008003f, 0.008659f, 0.009827f, 0.011086f, 0.012398f, 0.013649f, 0.015266f, 0.016891f, 0.018921f, 0.021118f, 0.023560f,
+ 0.026505f, 0.029556f, 0.032715f, 0.036865f, 0.041077f, 0.046570f, 0.053314f, 0.060150f, 0.068787f, 0.078552f, 0.090027f, 0.103638f,
+ 0.119690f, 0.138184f, 0.159546f, 0.184692f, 0.213745f, 0.245972f, 0.283203f, 0.324219f, 0.367920f, 0.414062f, 0.461914f, 0.509766f,
+ 0.557129f, 0.604492f, 0.647461f, 0.688965f, 0.727051f, 0.761230f, 0.791504f, 0.819824f, 0.844238f, 0.865234f, 0.951660f, 0.955566f,
+ 0.955566f, 0.956055f, 0.955078f, 0.956543f, 0.000156f, 0.000587f, 0.001056f, 0.001499f, 0.001647f, 0.002380f, 0.002594f, 0.003469f,
+ 0.003777f, 0.004112f, 0.004925f, 0.005699f, 0.006180f, 0.007019f, 0.007957f, 0.008942f, 0.009560f, 0.010727f, 0.011963f, 0.013123f,
+ 0.014885f, 0.016556f, 0.018494f, 0.020355f, 0.022766f, 0.025330f, 0.028320f, 0.031830f, 0.035736f, 0.040161f, 0.045532f, 0.052032f,
+ 0.059113f, 0.066833f, 0.076782f, 0.088501f, 0.101868f, 0.117310f, 0.136108f, 0.157959f, 0.183105f, 0.212769f, 0.247070f, 0.284424f,
+ 0.326660f, 0.371338f, 0.419189f, 0.468994f, 0.518066f, 0.567383f, 0.613770f, 0.658691f, 0.700684f, 0.738770f, 0.771973f, 0.803223f,
+ 0.829590f, 0.854492f, 0.947266f, 0.952637f, 0.952637f, 0.952637f, 0.953125f, 0.952637f, 0.000155f, 0.000358f, 0.000859f, 0.001402f,
+ 0.001830f, 0.002092f, 0.002499f, 0.002672f, 0.003410f, 0.003763f, 0.004375f, 0.005077f, 0.005535f, 0.006554f, 0.007004f, 0.007874f,
+ 0.008537f, 0.009529f, 0.010742f, 0.011749f, 0.013016f, 0.014427f, 0.015945f, 0.017929f, 0.019775f, 0.022018f, 0.024460f, 0.027618f,
+ 0.030640f, 0.034668f, 0.039154f, 0.044250f, 0.050293f, 0.057068f, 0.065491f, 0.074951f, 0.086487f, 0.099670f, 0.115906f, 0.134277f,
+ 0.156860f, 0.182495f, 0.213135f, 0.248047f, 0.286621f, 0.329834f, 0.376709f, 0.426025f, 0.476562f, 0.527832f, 0.577637f, 0.626465f,
+ 0.671387f, 0.713379f, 0.752441f, 0.784668f, 0.815430f, 0.841797f, 0.944336f, 0.948242f, 0.949219f, 0.949219f, 0.949219f, 0.949707f,
+ 0.000233f, 0.000639f, 0.000930f, 0.001277f, 0.001579f, 0.001916f, 0.002041f, 0.002625f, 0.003035f, 0.003571f, 0.004124f, 0.004375f,
+ 0.004978f, 0.005379f, 0.006348f, 0.006886f, 0.007526f, 0.008430f, 0.009216f, 0.010262f, 0.011436f, 0.012779f, 0.014160f, 0.015549f,
+ 0.017120f, 0.019089f, 0.021164f, 0.023621f, 0.026352f, 0.029724f, 0.033447f, 0.037842f, 0.042603f, 0.048737f, 0.055573f, 0.063721f,
+ 0.073364f, 0.084778f, 0.098206f, 0.114197f, 0.133423f, 0.155762f, 0.182739f, 0.213623f, 0.249512f, 0.289795f, 0.335205f, 0.383789f,
+ 0.434814f, 0.487305f, 0.540039f, 0.591797f, 0.640137f, 0.686035f, 0.727539f, 0.765137f, 0.800293f, 0.830078f, 0.940430f, 0.944336f,
+ 0.945312f, 0.946289f, 0.945801f, 0.945312f, 0.000217f, 0.000519f, 0.000848f, 0.001180f, 0.001366f, 0.001589f, 0.001986f, 0.002354f,
+ 0.002987f, 0.003170f, 0.003576f, 0.003901f, 0.004440f, 0.004738f, 0.005543f, 0.006058f, 0.006508f, 0.007511f, 0.008163f, 0.009132f,
+ 0.010078f, 0.011246f, 0.012390f, 0.013412f, 0.014938f, 0.016632f, 0.018433f, 0.020676f, 0.022995f, 0.025726f, 0.028702f, 0.032227f,
+ 0.036377f, 0.041992f, 0.047394f, 0.053986f, 0.062195f, 0.071716f, 0.082825f, 0.096802f, 0.112732f, 0.132202f, 0.155273f, 0.182861f,
+ 0.215210f, 0.252441f, 0.294678f, 0.341553f, 0.392090f, 0.445557f, 0.499512f, 0.553711f, 0.606445f, 0.656250f, 0.703125f, 0.745605f,
+ 0.782715f, 0.816895f, 0.935547f, 0.939941f, 0.941406f, 0.941406f, 0.941406f, 0.940918f, 0.000242f, 0.000678f, 0.000781f, 0.000928f,
+ 0.001200f, 0.001592f, 0.001694f, 0.002096f, 0.002703f, 0.002903f, 0.003170f, 0.003531f, 0.003918f, 0.004433f, 0.004955f, 0.005390f,
+ 0.005939f, 0.006454f, 0.007298f, 0.007782f, 0.008759f, 0.009567f, 0.010559f, 0.011650f, 0.013046f, 0.014420f, 0.015793f, 0.017715f,
+ 0.019699f, 0.021774f, 0.024460f, 0.027481f, 0.031082f, 0.035065f, 0.039917f, 0.045715f, 0.052246f, 0.060486f, 0.070129f, 0.081482f,
+ 0.095093f, 0.111755f, 0.131714f, 0.155273f, 0.183838f, 0.217285f, 0.256348f, 0.300781f, 0.350342f, 0.403076f, 0.458252f, 0.514160f,
+ 0.570312f, 0.624512f, 0.675781f, 0.722168f, 0.763672f, 0.800293f, 0.930664f, 0.935547f, 0.937500f, 0.937012f, 0.937500f, 0.937012f,
+ 0.000239f, 0.000297f, 0.000667f, 0.000785f, 0.001044f, 0.001269f, 0.001569f, 0.001950f, 0.002224f, 0.002419f, 0.002810f, 0.003063f,
+ 0.003626f, 0.003895f, 0.004261f, 0.004749f, 0.005066f, 0.005726f, 0.006260f, 0.007019f, 0.007771f, 0.008369f, 0.008919f, 0.009941f,
+ 0.011101f, 0.012375f, 0.013519f, 0.015190f, 0.016891f, 0.018631f, 0.021011f, 0.023590f, 0.026581f, 0.029892f, 0.033875f, 0.038757f,
+ 0.044281f, 0.051147f, 0.058746f, 0.068481f, 0.079834f, 0.094116f, 0.110779f, 0.131348f, 0.155884f, 0.185669f, 0.220825f, 0.261963f,
+ 0.308594f, 0.360352f, 0.416260f, 0.473877f, 0.532715f, 0.589844f, 0.645508f, 0.696289f, 0.743652f, 0.784668f, 0.925781f, 0.930664f,
+ 0.932129f, 0.932129f, 0.932129f, 0.932129f, 0.000226f, 0.000351f, 0.000434f, 0.000624f, 0.000887f, 0.001040f, 0.001246f, 0.001665f,
+ 0.001856f, 0.002384f, 0.002420f, 0.002842f, 0.002874f, 0.003471f, 0.003735f, 0.004078f, 0.004639f, 0.004910f, 0.005531f, 0.006065f,
+ 0.006664f, 0.007370f, 0.007690f, 0.008690f, 0.009544f, 0.010536f, 0.011795f, 0.012833f, 0.014183f, 0.015900f, 0.017899f, 0.019684f,
+ 0.022430f, 0.025253f, 0.028412f, 0.032410f, 0.037201f, 0.042633f, 0.049316f, 0.057159f, 0.066772f, 0.078186f, 0.092590f, 0.110107f,
+ 0.131348f, 0.156982f, 0.188232f, 0.225342f, 0.269043f, 0.318604f, 0.373535f, 0.431641f, 0.492188f, 0.554199f, 0.613281f, 0.668945f,
+ 0.720703f, 0.766602f, 0.919922f, 0.925781f, 0.926758f, 0.926758f, 0.927246f, 0.926758f, 0.000000f, 0.000340f, 0.000458f, 0.000715f,
+ 0.000823f, 0.000895f, 0.001165f, 0.001518f, 0.001636f, 0.001876f, 0.002190f, 0.002472f, 0.002640f, 0.002964f, 0.003340f, 0.003527f,
+ 0.004005f, 0.004227f, 0.004803f, 0.005260f, 0.005878f, 0.006042f, 0.006805f, 0.007500f, 0.008469f, 0.009132f, 0.009949f, 0.011009f,
+ 0.012077f, 0.013687f, 0.014938f, 0.016785f, 0.018997f, 0.021194f, 0.023895f, 0.027283f, 0.030945f, 0.035583f, 0.040955f, 0.047760f,
+ 0.055573f, 0.065247f, 0.077209f, 0.091736f, 0.109619f, 0.131470f, 0.159058f, 0.192017f, 0.231812f, 0.278076f, 0.331543f, 0.389404f,
+ 0.450928f, 0.513672f, 0.577637f, 0.638672f, 0.695801f, 0.746582f, 0.914062f, 0.919922f, 0.920898f, 0.921387f, 0.921387f, 0.921387f,
+ 0.000146f, 0.000319f, 0.000443f, 0.000458f, 0.000704f, 0.000894f, 0.001199f, 0.001324f, 0.001549f, 0.001592f, 0.002081f, 0.002092f,
+ 0.002237f, 0.002604f, 0.002815f, 0.003159f, 0.003510f, 0.003937f, 0.004147f, 0.004425f, 0.004814f, 0.005318f, 0.005878f, 0.006413f,
+ 0.006924f, 0.007782f, 0.008408f, 0.009239f, 0.010414f, 0.011505f, 0.012642f, 0.014015f, 0.015884f, 0.017563f, 0.019852f, 0.022598f,
+ 0.025650f, 0.029663f, 0.033875f, 0.039307f, 0.045898f, 0.053955f, 0.063782f, 0.075928f, 0.090820f, 0.109497f, 0.132690f, 0.161621f,
+ 0.196777f, 0.239624f, 0.290039f, 0.346436f, 0.408203f, 0.473633f, 0.540527f, 0.605957f, 0.667969f, 0.725586f, 0.907715f, 0.914062f,
+ 0.914062f, 0.915039f, 0.915039f, 0.915039f, 0.000121f, 0.000251f, 0.000506f, 0.000532f, 0.000665f, 0.000830f, 0.001190f, 0.001164f,
+ 0.001290f, 0.001413f, 0.001755f, 0.001900f, 0.002157f, 0.002319f, 0.002422f, 0.002853f, 0.003042f, 0.003254f, 0.003529f, 0.003725f,
+ 0.004288f, 0.004585f, 0.005043f, 0.005539f, 0.005970f, 0.006386f, 0.007126f, 0.007812f, 0.008652f, 0.009598f, 0.010651f, 0.011803f,
+ 0.013130f, 0.014702f, 0.016510f, 0.018814f, 0.021011f, 0.024368f, 0.028122f, 0.032379f, 0.037506f, 0.044128f, 0.052277f, 0.062042f,
+ 0.075073f, 0.090088f, 0.110107f, 0.134766f, 0.165405f, 0.203613f, 0.249268f, 0.303955f, 0.365234f, 0.431396f, 0.501465f, 0.571777f,
+ 0.638672f, 0.702148f, 0.900879f, 0.906738f, 0.907227f, 0.908203f, 0.907227f, 0.908203f, 0.000241f, 0.000122f, 0.000417f, 0.000505f,
+ 0.000741f, 0.000782f, 0.000916f, 0.001145f, 0.001189f, 0.001289f, 0.001331f, 0.001565f, 0.001779f, 0.002020f, 0.002171f, 0.002228f,
+ 0.002623f, 0.002752f, 0.002949f, 0.003157f, 0.003515f, 0.003847f, 0.004082f, 0.004429f, 0.004990f, 0.005405f, 0.006008f, 0.006603f,
+ 0.007103f, 0.007889f, 0.008789f, 0.009766f, 0.010605f, 0.012177f, 0.013672f, 0.015305f, 0.017487f, 0.019913f, 0.022781f, 0.026245f,
+ 0.030670f, 0.035980f, 0.042389f, 0.050812f, 0.060883f, 0.073792f, 0.090088f, 0.111145f, 0.138062f, 0.171143f, 0.212524f, 0.262695f,
+ 0.322266f, 0.388184f, 0.460205f, 0.533203f, 0.606445f, 0.676758f, 0.893066f, 0.898926f, 0.899414f, 0.899414f, 0.900879f, 0.900391f,
+ 0.000000f, 0.000114f, 0.000227f, 0.000407f, 0.000532f, 0.000732f, 0.000714f, 0.000922f, 0.000993f, 0.001072f, 0.001190f, 0.001412f,
+ 0.001569f, 0.001726f, 0.001959f, 0.002071f, 0.002159f, 0.002350f, 0.002565f, 0.002729f, 0.003090f, 0.003248f, 0.003702f, 0.003761f,
+ 0.004192f, 0.004585f, 0.004925f, 0.005272f, 0.005966f, 0.006405f, 0.007275f, 0.007965f, 0.008850f, 0.009872f, 0.011017f, 0.012383f,
+ 0.014275f, 0.015900f, 0.018463f, 0.021194f, 0.024673f, 0.028870f, 0.034271f, 0.040955f, 0.048981f, 0.059723f, 0.073059f, 0.090149f,
+ 0.112549f, 0.141357f, 0.178467f, 0.223755f, 0.280029f, 0.345215f, 0.417969f, 0.494385f, 0.572266f, 0.648438f, 0.884277f, 0.890137f,
+ 0.891602f, 0.891602f, 0.893066f, 0.892090f, 0.000000f, 0.000219f, 0.000211f, 0.000333f, 0.000559f, 0.000609f, 0.000788f, 0.000805f,
+ 0.000869f, 0.000903f, 0.001101f, 0.001166f, 0.001302f, 0.001399f, 0.001456f, 0.001668f, 0.001853f, 0.001999f, 0.002102f, 0.002256f,
+ 0.002447f, 0.002728f, 0.002943f, 0.003178f, 0.003515f, 0.003836f, 0.004074f, 0.004475f, 0.004745f, 0.005325f, 0.005970f, 0.006569f,
+ 0.007248f, 0.008102f, 0.008888f, 0.010132f, 0.011169f, 0.012947f, 0.014763f, 0.016891f, 0.019760f, 0.023087f, 0.027176f, 0.032562f,
+ 0.038940f, 0.047516f, 0.058167f, 0.072754f, 0.090698f, 0.114929f, 0.146851f, 0.187744f, 0.239258f, 0.301514f, 0.373291f, 0.452637f,
+ 0.535645f, 0.617676f, 0.874512f, 0.880859f, 0.882324f, 0.883301f, 0.883301f, 0.882324f, 0.000204f, 0.000207f, 0.000204f, 0.000322f,
+ 0.000435f, 0.000480f, 0.000556f, 0.000615f, 0.000747f, 0.000782f, 0.000844f, 0.001006f, 0.001159f, 0.001191f, 0.001231f, 0.001450f,
+ 0.001585f, 0.001633f, 0.001790f, 0.001919f, 0.002117f, 0.002298f, 0.002432f, 0.002651f, 0.002939f, 0.003172f, 0.003399f, 0.003614f,
+ 0.003944f, 0.004421f, 0.004704f, 0.005203f, 0.005886f, 0.006454f, 0.007160f, 0.008049f, 0.009041f, 0.010201f, 0.011627f, 0.013237f,
+ 0.015404f, 0.018097f, 0.021469f, 0.025284f, 0.030884f, 0.036987f, 0.045990f, 0.056915f, 0.072083f, 0.092163f, 0.119141f, 0.154419f,
+ 0.200928f, 0.259277f, 0.328857f, 0.409424f, 0.495605f, 0.584473f, 0.864258f, 0.871094f, 0.872070f, 0.873047f, 0.872559f, 0.873047f,
+ 0.000000f, 0.000044f, 0.000176f, 0.000290f, 0.000410f, 0.000390f, 0.000513f, 0.000546f, 0.000647f, 0.000680f, 0.000827f, 0.000858f,
+ 0.000958f, 0.001131f, 0.001102f, 0.001223f, 0.001367f, 0.001401f, 0.001525f, 0.001610f, 0.001826f, 0.001821f, 0.002039f, 0.002253f,
+ 0.002459f, 0.002617f, 0.002708f, 0.003036f, 0.003279f, 0.003431f, 0.003805f, 0.004219f, 0.004471f, 0.004929f, 0.005569f, 0.006310f,
+ 0.007107f, 0.007988f, 0.009003f, 0.010384f, 0.011856f, 0.014015f, 0.016418f, 0.019669f, 0.023666f, 0.028809f, 0.035583f, 0.044159f,
+ 0.056458f, 0.072571f, 0.094604f, 0.124329f, 0.164917f, 0.218018f, 0.284912f, 0.364746f, 0.454102f, 0.549316f, 0.853027f, 0.859863f,
+ 0.861328f, 0.861816f, 0.861816f, 0.861816f, 0.000000f, 0.000069f, 0.000120f, 0.000345f, 0.000371f, 0.000398f, 0.000452f, 0.000396f,
+ 0.000498f, 0.000530f, 0.000596f, 0.000648f, 0.000781f, 0.000921f, 0.000995f, 0.001007f, 0.001101f, 0.001146f, 0.001282f, 0.001278f,
+ 0.001471f, 0.001554f, 0.001710f, 0.001811f, 0.001995f, 0.001986f, 0.002314f, 0.002399f, 0.002499f, 0.002903f, 0.002975f, 0.003305f,
+ 0.003605f, 0.004086f, 0.004425f, 0.005081f, 0.005402f, 0.006035f, 0.006889f, 0.007755f, 0.009041f, 0.010422f, 0.012672f, 0.014885f,
+ 0.017746f, 0.021530f, 0.026733f, 0.033691f, 0.043060f, 0.055847f, 0.073181f, 0.097473f, 0.132324f, 0.179077f, 0.241821f, 0.320068f,
+ 0.410400f, 0.510742f, 0.839844f, 0.847656f, 0.849121f, 0.849609f, 0.849121f, 0.849609f, 0.000000f, 0.000000f, 0.000121f, 0.000243f,
+ 0.000321f, 0.000354f, 0.000341f, 0.000431f, 0.000423f, 0.000444f, 0.000473f, 0.000508f, 0.000595f, 0.000706f, 0.000737f, 0.000861f,
+ 0.000869f, 0.000926f, 0.001055f, 0.001104f, 0.001199f, 0.001306f, 0.001360f, 0.001433f, 0.001530f, 0.001555f, 0.001673f, 0.001942f,
+ 0.002138f, 0.002247f, 0.002562f, 0.002609f, 0.002911f, 0.003204f, 0.003466f, 0.003757f, 0.004192f, 0.004845f, 0.005482f, 0.006008f,
+ 0.006874f, 0.007904f, 0.009171f, 0.011124f, 0.013260f, 0.015839f, 0.019821f, 0.024872f, 0.031982f, 0.041534f, 0.055054f, 0.075012f,
+ 0.103516f, 0.143677f, 0.199951f, 0.273438f, 0.364502f, 0.469482f, 0.825684f, 0.834473f, 0.834961f, 0.835938f, 0.835938f, 0.835938f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000120f, 0.000199f, 0.000272f, 0.000265f, 0.000363f, 0.000379f, 0.000388f, 0.000489f, 0.000500f,
+ 0.000488f, 0.000569f, 0.000604f, 0.000700f, 0.000683f, 0.000720f, 0.000784f, 0.000844f, 0.001009f, 0.001047f, 0.001108f, 0.001258f,
+ 0.001276f, 0.001388f, 0.001410f, 0.001565f, 0.001592f, 0.001814f, 0.001800f, 0.002167f, 0.002192f, 0.002556f, 0.002665f, 0.002905f,
+ 0.003195f, 0.003574f, 0.004028f, 0.004513f, 0.005127f, 0.005859f, 0.006847f, 0.008018f, 0.009491f, 0.011452f, 0.014099f, 0.017792f,
+ 0.022995f, 0.030258f, 0.040588f, 0.055878f, 0.078308f, 0.111450f, 0.160278f, 0.229248f, 0.318359f, 0.425781f, 0.810547f, 0.818359f,
+ 0.820312f, 0.821777f, 0.821777f, 0.820801f, 0.000000f, 0.000121f, 0.000120f, 0.000172f, 0.000195f, 0.000171f, 0.000208f, 0.000272f,
+ 0.000316f, 0.000333f, 0.000348f, 0.000355f, 0.000412f, 0.000410f, 0.000515f, 0.000485f, 0.000545f, 0.000656f, 0.000777f, 0.000659f,
+ 0.000705f, 0.000762f, 0.000874f, 0.000927f, 0.000959f, 0.000978f, 0.001045f, 0.001228f, 0.001294f, 0.001398f, 0.001443f, 0.001637f,
+ 0.001752f, 0.001925f, 0.002005f, 0.002230f, 0.002407f, 0.002670f, 0.002895f, 0.003267f, 0.003933f, 0.004280f, 0.005051f, 0.005772f,
+ 0.006718f, 0.008141f, 0.010117f, 0.012383f, 0.015930f, 0.020920f, 0.028671f, 0.039673f, 0.056702f, 0.083313f, 0.124695f, 0.185791f,
+ 0.270996f, 0.379639f, 0.793457f, 0.801270f, 0.803711f, 0.803711f, 0.804688f, 0.804688f, 0.000000f, 0.000121f, 0.000119f, 0.000144f,
+ 0.000149f, 0.000166f, 0.000173f, 0.000167f, 0.000214f, 0.000245f, 0.000334f, 0.000287f, 0.000303f, 0.000391f, 0.000401f, 0.000440f,
+ 0.000469f, 0.000493f, 0.000534f, 0.000513f, 0.000690f, 0.000682f, 0.000645f, 0.000712f, 0.000715f, 0.000747f, 0.000842f, 0.000849f,
+ 0.000967f, 0.000995f, 0.001178f, 0.001167f, 0.001273f, 0.001395f, 0.001586f, 0.001748f, 0.001796f, 0.001986f, 0.002132f, 0.002476f,
+ 0.002893f, 0.003294f, 0.003653f, 0.004086f, 0.004890f, 0.005821f, 0.006927f, 0.008553f, 0.010857f, 0.014137f, 0.019211f, 0.027084f,
+ 0.039642f, 0.059448f, 0.092468f, 0.144775f, 0.224487f, 0.332764f, 0.775391f, 0.784668f, 0.786133f, 0.786133f, 0.787109f, 0.786621f,
+ 0.000000f, 0.000000f, 0.000118f, 0.000116f, 0.000115f, 0.000113f, 0.000140f, 0.000140f, 0.000149f, 0.000220f, 0.000171f, 0.000255f,
+ 0.000274f, 0.000292f, 0.000318f, 0.000295f, 0.000346f, 0.000352f, 0.000380f, 0.000406f, 0.000401f, 0.000533f, 0.000490f, 0.000551f,
+ 0.000558f, 0.000648f, 0.000628f, 0.000723f, 0.000788f, 0.000749f, 0.000836f, 0.000941f, 0.000997f, 0.001065f, 0.001112f, 0.001207f,
+ 0.001328f, 0.001535f, 0.001621f, 0.001840f, 0.002022f, 0.002163f, 0.002522f, 0.002825f, 0.003391f, 0.003830f, 0.004616f, 0.005665f,
+ 0.007172f, 0.009247f, 0.012482f, 0.017532f, 0.025970f, 0.040161f, 0.064941f, 0.107422f, 0.178833f, 0.283447f, 0.754883f, 0.764648f,
+ 0.766113f, 0.767090f, 0.767578f, 0.767090f, 0.000000f, 0.000119f, 0.000116f, 0.000114f, 0.000112f, 0.000110f, 0.000109f, 0.000117f,
+ 0.000114f, 0.000117f, 0.000125f, 0.000193f, 0.000141f, 0.000196f, 0.000221f, 0.000235f, 0.000259f, 0.000278f, 0.000308f, 0.000316f,
+ 0.000323f, 0.000315f, 0.000329f, 0.000351f, 0.000388f, 0.000422f, 0.000465f, 0.000512f, 0.000571f, 0.000568f, 0.000588f, 0.000633f,
+ 0.000747f, 0.000751f, 0.000829f, 0.000958f, 0.000914f, 0.001104f, 0.001145f, 0.001255f, 0.001337f, 0.001499f, 0.001701f, 0.001966f,
+ 0.002275f, 0.002609f, 0.003119f, 0.003773f, 0.004658f, 0.005920f, 0.007935f, 0.010948f, 0.015900f, 0.025284f, 0.042511f, 0.075012f,
+ 0.135010f, 0.234619f, 0.733398f, 0.743164f, 0.744629f, 0.745117f, 0.745605f, 0.745605f, 0.000000f, 0.000116f, 0.000113f, 0.000111f,
+ 0.000108f, 0.000106f, 0.000104f, 0.000103f, 0.000098f, 0.000092f, 0.000099f, 0.000085f, 0.000098f, 0.000105f, 0.000163f, 0.000162f,
+ 0.000128f, 0.000193f, 0.000203f, 0.000214f, 0.000284f, 0.000239f, 0.000303f, 0.000268f, 0.000327f, 0.000326f, 0.000329f, 0.000330f,
+ 0.000407f, 0.000486f, 0.000406f, 0.000454f, 0.000465f, 0.000495f, 0.000535f, 0.000592f, 0.000648f, 0.000727f, 0.000753f, 0.000807f,
+ 0.000956f, 0.000992f, 0.001108f, 0.001294f, 0.001418f, 0.001703f, 0.001978f, 0.002390f, 0.002930f, 0.003643f, 0.004753f, 0.006519f,
+ 0.009499f, 0.014824f, 0.025497f, 0.048065f, 0.095154f, 0.185425f, 0.709961f, 0.719727f, 0.721191f, 0.721191f, 0.721680f, 0.721680f,
+ 0.000000f, 0.000113f, 0.000107f, 0.000106f, 0.000102f, 0.000100f, 0.000097f, 0.000096f, 0.000095f, 0.000092f, 0.000087f, 0.000083f,
+ 0.000078f, 0.000098f, 0.000077f, 0.000091f, 0.000114f, 0.000128f, 0.000114f, 0.000147f, 0.000154f, 0.000162f, 0.000186f, 0.000174f,
+ 0.000220f, 0.000233f, 0.000235f, 0.000245f, 0.000250f, 0.000253f, 0.000321f, 0.000296f, 0.000311f, 0.000354f, 0.000417f, 0.000419f,
+ 0.000438f, 0.000443f, 0.000495f, 0.000513f, 0.000585f, 0.000634f, 0.000705f, 0.000778f, 0.000912f, 0.001002f, 0.001163f, 0.001379f,
+ 0.001745f, 0.002092f, 0.002697f, 0.003721f, 0.005230f, 0.008194f, 0.013870f, 0.027359f, 0.061066f, 0.138062f, 0.685547f, 0.694336f,
+ 0.696777f, 0.696289f, 0.697754f, 0.697754f, 0.000000f, 0.000106f, 0.000102f, 0.000097f, 0.000093f, 0.000091f, 0.000089f, 0.000087f,
+ 0.000085f, 0.000084f, 0.000082f, 0.000080f, 0.000076f, 0.000072f, 0.000069f, 0.000074f, 0.000076f, 0.000059f, 0.000075f, 0.000062f,
+ 0.000085f, 0.000091f, 0.000103f, 0.000111f, 0.000121f, 0.000135f, 0.000128f, 0.000159f, 0.000171f, 0.000160f, 0.000178f, 0.000193f,
+ 0.000196f, 0.000202f, 0.000220f, 0.000230f, 0.000273f, 0.000289f, 0.000312f, 0.000330f, 0.000335f, 0.000397f, 0.000408f, 0.000463f,
+ 0.000517f, 0.000577f, 0.000691f, 0.000771f, 0.000919f, 0.001150f, 0.001436f, 0.001955f, 0.002737f, 0.004185f, 0.007103f, 0.013863f,
+ 0.033661f, 0.093628f, 0.657227f, 0.667480f, 0.668945f, 0.669434f, 0.670898f, 0.669922f, 0.000108f, 0.000093f, 0.000087f, 0.000082f,
+ 0.000079f, 0.000078f, 0.000075f, 0.000073f, 0.000071f, 0.000070f, 0.000069f, 0.000069f, 0.000067f, 0.000066f, 0.000064f, 0.000061f,
+ 0.000059f, 0.000056f, 0.000053f, 0.000051f, 0.000053f, 0.000049f, 0.000044f, 0.000047f, 0.000055f, 0.000058f, 0.000071f, 0.000077f,
+ 0.000093f, 0.000094f, 0.000103f, 0.000102f, 0.000110f, 0.000126f, 0.000130f, 0.000138f, 0.000143f, 0.000166f, 0.000166f, 0.000178f,
+ 0.000194f, 0.000217f, 0.000228f, 0.000231f, 0.000265f, 0.000330f, 0.000341f, 0.000411f, 0.000459f, 0.000549f, 0.000705f, 0.000867f,
+ 0.001228f, 0.001863f, 0.003143f, 0.006283f, 0.015594f, 0.054993f, 0.628418f, 0.638184f, 0.640137f, 0.640137f, 0.641602f, 0.641602f,
+ 0.000071f, 0.000058f, 0.000059f, 0.000058f, 0.000054f, 0.000054f, 0.000051f, 0.000053f, 0.000051f, 0.000052f, 0.000050f, 0.000050f,
+ 0.000051f, 0.000050f, 0.000049f, 0.000049f, 0.000049f, 0.000049f, 0.000047f, 0.000045f, 0.000043f, 0.000041f, 0.000039f, 0.000038f,
+ 0.000036f, 0.000034f, 0.000035f, 0.000037f, 0.000033f, 0.000034f, 0.000038f, 0.000047f, 0.000054f, 0.000061f, 0.000064f, 0.000068f,
+ 0.000069f, 0.000076f, 0.000083f, 0.000092f, 0.000098f, 0.000103f, 0.000112f, 0.000129f, 0.000113f, 0.000139f, 0.000152f, 0.000185f,
+ 0.000204f, 0.000238f, 0.000282f, 0.000365f, 0.000503f, 0.000685f, 0.001178f, 0.002274f, 0.006100f, 0.025162f, 0.597656f, 0.607910f,
+ 0.610840f, 0.611816f, 0.610352f, 0.611328f, 0.000000f, 0.000000f, 0.000004f, 0.000012f, 0.000014f, 0.000020f, 0.000022f, 0.000023f,
+ 0.000024f, 0.000022f, 0.000025f, 0.000027f, 0.000027f, 0.000026f, 0.000028f, 0.000029f, 0.000029f, 0.000029f, 0.000030f, 0.000030f,
+ 0.000030f, 0.000030f, 0.000030f, 0.000030f, 0.000029f, 0.000028f, 0.000027f, 0.000026f, 0.000024f, 0.000023f, 0.000022f, 0.000021f,
+ 0.000020f, 0.000019f, 0.000018f, 0.000019f, 0.000023f, 0.000024f, 0.000027f, 0.000032f, 0.000038f, 0.000040f, 0.000041f, 0.000045f,
+ 0.000054f, 0.000052f, 0.000055f, 0.000060f, 0.000068f, 0.000089f, 0.000089f, 0.000115f, 0.000146f, 0.000198f, 0.000318f, 0.000586f,
+ 0.001614f, 0.008278f, 0.565918f, 0.576660f, 0.578125f, 0.579102f, 0.579590f, 0.580078f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f,
+ 0.000003f, 0.000003f, 0.000005f, 0.000005f, 0.000006f, 0.000007f, 0.000009f, 0.000009f, 0.000010f, 0.000011f, 0.000012f, 0.000012f,
+ 0.000013f, 0.000014f, 0.000014f, 0.000015f, 0.000014f, 0.000014f, 0.000013f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000010f,
+ 0.000009f, 0.000009f, 0.000008f, 0.000010f, 0.000013f, 0.000013f, 0.000013f, 0.000017f, 0.000017f, 0.000022f, 0.000021f, 0.000023f,
+ 0.000031f, 0.000032f, 0.000049f, 0.000079f, 0.000204f, 0.001328f, 0.533203f, 0.543945f, 0.545410f, 0.546387f, 0.546875f, 0.546875f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000003f,
+ 0.000003f, 0.000003f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000004f, 0.000016f, 0.499756f, 0.510254f,
+ 0.513184f, 0.513672f, 0.514160f, 0.514160f,
+ },
+ {
+ 0.076172f, 0.209839f, 0.320312f, 0.408691f, 0.481689f, 0.541016f, 0.591309f, 0.633789f, 0.668945f, 0.699707f, 0.727051f, 0.749512f,
+ 0.770020f, 0.788086f, 0.803711f, 0.817871f, 0.832520f, 0.843750f, 0.854492f, 0.864258f, 0.873535f, 0.881836f, 0.889160f, 0.895996f,
+ 0.903320f, 0.909180f, 0.914551f, 0.920410f, 0.925781f, 0.929199f, 0.933594f, 0.938965f, 0.942383f, 0.946289f, 0.949219f, 0.953125f,
+ 0.955566f, 0.959473f, 0.961914f, 0.964355f, 0.967285f, 0.970215f, 0.971680f, 0.974609f, 0.976562f, 0.978516f, 0.980469f, 0.982422f,
+ 0.984375f, 0.986328f, 0.987793f, 0.989746f, 0.990723f, 0.992676f, 0.993652f, 0.995117f, 0.996582f, 0.998047f, 0.999023f, 0.997559f,
+ 0.996582f, 0.995605f, 0.994629f, 0.993652f, 0.043396f, 0.133301f, 0.221313f, 0.303223f, 0.377441f, 0.442871f, 0.500000f, 0.550781f,
+ 0.595215f, 0.632812f, 0.666992f, 0.696777f, 0.723145f, 0.745605f, 0.765137f, 0.783691f, 0.799805f, 0.815430f, 0.828613f, 0.839844f,
+ 0.851562f, 0.861328f, 0.871582f, 0.879395f, 0.887207f, 0.894531f, 0.901855f, 0.907227f, 0.914062f, 0.919434f, 0.924316f, 0.928711f,
+ 0.933594f, 0.937988f, 0.942383f, 0.945801f, 0.949219f, 0.953125f, 0.956055f, 0.959473f, 0.962402f, 0.964355f, 0.967773f, 0.970215f,
+ 0.972656f, 0.975098f, 0.977051f, 0.979492f, 0.980957f, 0.983398f, 0.985352f, 0.986816f, 0.988281f, 0.990234f, 0.991699f, 0.993652f,
+ 0.995117f, 0.996094f, 0.998047f, 0.997070f, 0.996094f, 0.995117f, 0.994141f, 0.993164f, 0.027832f, 0.088440f, 0.153198f, 0.221313f,
+ 0.288086f, 0.352051f, 0.411621f, 0.466797f, 0.515625f, 0.561523f, 0.601074f, 0.637207f, 0.667969f, 0.695312f, 0.721680f, 0.743652f,
+ 0.763184f, 0.781738f, 0.797852f, 0.812500f, 0.826172f, 0.838867f, 0.850098f, 0.859863f, 0.869141f, 0.877930f, 0.886230f, 0.893555f,
+ 0.900879f, 0.907227f, 0.912598f, 0.918457f, 0.922852f, 0.928711f, 0.934082f, 0.938477f, 0.942383f, 0.946289f, 0.950195f, 0.953125f,
+ 0.956543f, 0.959961f, 0.962402f, 0.965820f, 0.968262f, 0.970703f, 0.973145f, 0.975586f, 0.978027f, 0.979980f, 0.982422f, 0.984375f,
+ 0.985840f, 0.987793f, 0.989746f, 0.991211f, 0.993164f, 0.994141f, 0.997559f, 0.996582f, 0.995605f, 0.994629f, 0.993652f, 0.993164f,
+ 0.018921f, 0.061493f, 0.109497f, 0.161987f, 0.217041f, 0.273438f, 0.330811f, 0.384521f, 0.437500f, 0.486084f, 0.530273f, 0.570312f,
+ 0.607910f, 0.640137f, 0.670410f, 0.697266f, 0.722656f, 0.743652f, 0.763672f, 0.781250f, 0.797363f, 0.812012f, 0.825684f, 0.837891f,
+ 0.848633f, 0.859863f, 0.869141f, 0.878418f, 0.886719f, 0.893066f, 0.900879f, 0.906738f, 0.913574f, 0.919434f, 0.924316f, 0.930176f,
+ 0.934082f, 0.939453f, 0.942871f, 0.946777f, 0.950684f, 0.954590f, 0.958008f, 0.960449f, 0.963379f, 0.966797f, 0.969238f, 0.971680f,
+ 0.974121f, 0.977051f, 0.978516f, 0.980957f, 0.983398f, 0.985352f, 0.987305f, 0.989258f, 0.991211f, 0.992676f, 0.996094f, 0.995605f,
+ 0.994629f, 0.993652f, 0.993164f, 0.992188f, 0.013596f, 0.044495f, 0.080017f, 0.119873f, 0.164307f, 0.211670f, 0.261475f, 0.311523f,
+ 0.362793f, 0.410645f, 0.458008f, 0.501953f, 0.542969f, 0.580078f, 0.614746f, 0.645996f, 0.674805f, 0.701172f, 0.723633f, 0.745117f,
+ 0.765625f, 0.782227f, 0.798828f, 0.812988f, 0.826172f, 0.838867f, 0.849609f, 0.861328f, 0.870605f, 0.878906f, 0.887695f, 0.895020f,
+ 0.901855f, 0.907715f, 0.914551f, 0.920898f, 0.925781f, 0.930664f, 0.934570f, 0.940918f, 0.943848f, 0.947754f, 0.951660f, 0.955566f,
+ 0.958984f, 0.961914f, 0.964844f, 0.967773f, 0.970703f, 0.973145f, 0.975586f, 0.978027f, 0.979980f, 0.982422f, 0.984863f, 0.986328f,
+ 0.988770f, 0.990234f, 0.995117f, 0.995117f, 0.994141f, 0.993652f, 0.992676f, 0.991699f, 0.010414f, 0.033203f, 0.060364f, 0.090942f,
+ 0.125610f, 0.163818f, 0.206421f, 0.250488f, 0.295898f, 0.341797f, 0.388428f, 0.433350f, 0.475830f, 0.517090f, 0.555176f, 0.589844f,
+ 0.622559f, 0.652344f, 0.680176f, 0.704590f, 0.729004f, 0.748535f, 0.767578f, 0.784668f, 0.800293f, 0.814941f, 0.828125f, 0.839844f,
+ 0.852051f, 0.861816f, 0.871582f, 0.879883f, 0.888672f, 0.895996f, 0.903320f, 0.909180f, 0.916016f, 0.921387f, 0.927246f, 0.931641f,
+ 0.937012f, 0.940918f, 0.946289f, 0.950195f, 0.953125f, 0.957520f, 0.960449f, 0.963867f, 0.966309f, 0.969238f, 0.972168f, 0.975098f,
+ 0.976562f, 0.979492f, 0.981934f, 0.983887f, 0.985840f, 0.988281f, 0.994629f, 0.994141f, 0.993652f, 0.992676f, 0.991699f, 0.990723f,
+ 0.007889f, 0.025772f, 0.046539f, 0.070312f, 0.097168f, 0.128540f, 0.162354f, 0.200195f, 0.239868f, 0.281738f, 0.325195f, 0.368896f,
+ 0.411621f, 0.453125f, 0.493652f, 0.531738f, 0.566406f, 0.601074f, 0.631836f, 0.659668f, 0.687988f, 0.709961f, 0.732422f, 0.753418f,
+ 0.770996f, 0.788086f, 0.804199f, 0.818359f, 0.831543f, 0.843750f, 0.854492f, 0.864746f, 0.873535f, 0.882812f, 0.890137f, 0.898438f,
+ 0.905273f, 0.912598f, 0.917969f, 0.923828f, 0.929199f, 0.934570f, 0.938477f, 0.942871f, 0.948242f, 0.951660f, 0.955078f, 0.958496f,
+ 0.961914f, 0.965332f, 0.968262f, 0.971680f, 0.973633f, 0.976562f, 0.979492f, 0.981445f, 0.983398f, 0.985352f, 0.993164f, 0.993164f,
+ 0.992676f, 0.991699f, 0.991211f, 0.990234f, 0.006332f, 0.020325f, 0.036438f, 0.055573f, 0.077026f, 0.101562f, 0.129028f, 0.160278f,
+ 0.194458f, 0.230347f, 0.268555f, 0.309326f, 0.350830f, 0.391846f, 0.432373f, 0.472412f, 0.509277f, 0.545410f, 0.579102f, 0.611816f,
+ 0.640625f, 0.668945f, 0.693848f, 0.716797f, 0.739258f, 0.758789f, 0.775879f, 0.793945f, 0.807617f, 0.821777f, 0.834961f, 0.846680f,
+ 0.857422f, 0.867676f, 0.877441f, 0.885742f, 0.893555f, 0.900391f, 0.908203f, 0.915039f, 0.920898f, 0.926270f, 0.931152f, 0.937012f,
+ 0.940918f, 0.946289f, 0.949219f, 0.954102f, 0.958008f, 0.960938f, 0.964355f, 0.967773f, 0.970703f, 0.973145f, 0.975586f, 0.978516f,
+ 0.981445f, 0.983398f, 0.992188f, 0.992188f, 0.991699f, 0.990723f, 0.990723f, 0.989746f, 0.005226f, 0.016647f, 0.029556f, 0.044434f,
+ 0.061523f, 0.081543f, 0.103760f, 0.129150f, 0.157837f, 0.188477f, 0.221924f, 0.257812f, 0.295654f, 0.334473f, 0.374023f, 0.412842f,
+ 0.451904f, 0.489990f, 0.525391f, 0.560059f, 0.593262f, 0.623047f, 0.651855f, 0.678223f, 0.702148f, 0.725098f, 0.745605f, 0.764160f,
+ 0.781738f, 0.799316f, 0.812500f, 0.827148f, 0.838867f, 0.851074f, 0.861328f, 0.871582f, 0.880371f, 0.889648f, 0.896973f, 0.904297f,
+ 0.911621f, 0.917480f, 0.923340f, 0.929688f, 0.934570f, 0.939941f, 0.943848f, 0.948242f, 0.951660f, 0.957031f, 0.959473f, 0.963379f,
+ 0.966797f, 0.969727f, 0.972656f, 0.976074f, 0.979004f, 0.980957f, 0.991699f, 0.991211f, 0.990723f, 0.990234f, 0.989746f, 0.988770f,
+ 0.004108f, 0.013542f, 0.023819f, 0.036194f, 0.050262f, 0.066223f, 0.084717f, 0.104797f, 0.128174f, 0.153809f, 0.182861f, 0.213989f,
+ 0.247437f, 0.282471f, 0.319580f, 0.357422f, 0.395508f, 0.433350f, 0.470947f, 0.506348f, 0.542480f, 0.575684f, 0.605957f, 0.635254f,
+ 0.662109f, 0.687988f, 0.711426f, 0.732910f, 0.753418f, 0.771973f, 0.789062f, 0.804688f, 0.819336f, 0.831543f, 0.843750f, 0.855469f,
+ 0.866211f, 0.875488f, 0.884766f, 0.893066f, 0.901367f, 0.907715f, 0.914062f, 0.921387f, 0.927246f, 0.932129f, 0.937012f, 0.942383f,
+ 0.946777f, 0.951660f, 0.956055f, 0.959473f, 0.962891f, 0.966309f, 0.969238f, 0.972168f, 0.975098f, 0.978027f, 0.989746f, 0.990234f,
+ 0.990234f, 0.989258f, 0.989258f, 0.988281f, 0.003597f, 0.011330f, 0.020065f, 0.029938f, 0.041412f, 0.054504f, 0.068970f, 0.086182f,
+ 0.105469f, 0.126709f, 0.151123f, 0.177612f, 0.206909f, 0.237915f, 0.271484f, 0.305664f, 0.342529f, 0.378906f, 0.416748f, 0.453125f,
+ 0.489502f, 0.524414f, 0.558105f, 0.589844f, 0.619629f, 0.646973f, 0.673828f, 0.698242f, 0.721191f, 0.742676f, 0.761230f, 0.778809f,
+ 0.796387f, 0.810547f, 0.824707f, 0.837891f, 0.850098f, 0.861328f, 0.871094f, 0.881348f, 0.889648f, 0.896973f, 0.904785f, 0.912109f,
+ 0.919434f, 0.924316f, 0.931152f, 0.936523f, 0.941895f, 0.946289f, 0.951172f, 0.955078f, 0.959473f, 0.962402f, 0.965820f, 0.969238f,
+ 0.972656f, 0.975586f, 0.988770f, 0.989258f, 0.989258f, 0.988770f, 0.987793f, 0.987305f, 0.002836f, 0.009857f, 0.016693f, 0.025208f,
+ 0.034668f, 0.045288f, 0.057617f, 0.071106f, 0.087463f, 0.104858f, 0.125000f, 0.147461f, 0.172119f, 0.199829f, 0.229248f, 0.260742f,
+ 0.294434f, 0.329102f, 0.365479f, 0.400879f, 0.437012f, 0.472656f, 0.508301f, 0.541992f, 0.574219f, 0.604980f, 0.634766f, 0.660645f,
+ 0.686523f, 0.709473f, 0.731445f, 0.751953f, 0.770996f, 0.789062f, 0.804199f, 0.817871f, 0.832520f, 0.844727f, 0.856445f, 0.867188f,
+ 0.876953f, 0.886719f, 0.895020f, 0.902832f, 0.909668f, 0.916504f, 0.923340f, 0.929688f, 0.935547f, 0.939941f, 0.944824f, 0.949707f,
+ 0.954102f, 0.958496f, 0.961914f, 0.965820f, 0.969238f, 0.972656f, 0.987793f, 0.988281f, 0.988281f, 0.987793f, 0.986816f, 0.986328f,
+ 0.002541f, 0.008118f, 0.014244f, 0.021194f, 0.029480f, 0.037811f, 0.048584f, 0.060028f, 0.073242f, 0.088196f, 0.104370f, 0.123047f,
+ 0.144531f, 0.167114f, 0.193237f, 0.220947f, 0.250977f, 0.282227f, 0.316162f, 0.351074f, 0.386719f, 0.422119f, 0.457520f, 0.492432f,
+ 0.526367f, 0.559082f, 0.590332f, 0.621094f, 0.648438f, 0.674316f, 0.698730f, 0.721191f, 0.742188f, 0.762207f, 0.780762f, 0.797363f,
+ 0.812500f, 0.826172f, 0.840332f, 0.852051f, 0.863770f, 0.873535f, 0.883301f, 0.892090f, 0.900391f, 0.908203f, 0.915039f, 0.922363f,
+ 0.928711f, 0.933594f, 0.939453f, 0.944824f, 0.950195f, 0.953125f, 0.958008f, 0.962402f, 0.965332f, 0.969238f, 0.986816f, 0.987305f,
+ 0.986816f, 0.986328f, 0.985840f, 0.984863f, 0.002115f, 0.007030f, 0.012138f, 0.017944f, 0.024521f, 0.032318f, 0.040955f, 0.050476f,
+ 0.061676f, 0.073914f, 0.087769f, 0.103271f, 0.121033f, 0.140747f, 0.162598f, 0.187256f, 0.213379f, 0.242065f, 0.272705f, 0.305176f,
+ 0.338623f, 0.373047f, 0.408691f, 0.443848f, 0.478760f, 0.512695f, 0.545898f, 0.577637f, 0.607910f, 0.636719f, 0.663086f, 0.688965f,
+ 0.712402f, 0.734863f, 0.754395f, 0.774414f, 0.791016f, 0.806641f, 0.822266f, 0.835449f, 0.848145f, 0.859863f, 0.870605f, 0.880371f,
+ 0.890137f, 0.898438f, 0.906250f, 0.914551f, 0.921387f, 0.926758f, 0.933594f, 0.938965f, 0.944336f, 0.949219f, 0.954102f, 0.958984f,
+ 0.961914f, 0.965820f, 0.985840f, 0.986328f, 0.985840f, 0.985352f, 0.985352f, 0.984375f, 0.001999f, 0.006226f, 0.010384f, 0.015594f,
+ 0.021027f, 0.027435f, 0.034637f, 0.042969f, 0.052124f, 0.062469f, 0.074097f, 0.087646f, 0.102173f, 0.119141f, 0.137695f, 0.158203f,
+ 0.181396f, 0.206543f, 0.233643f, 0.263184f, 0.295166f, 0.327148f, 0.360596f, 0.395264f, 0.430420f, 0.464600f, 0.499023f, 0.532227f,
+ 0.564941f, 0.595703f, 0.625000f, 0.651855f, 0.679199f, 0.703613f, 0.726074f, 0.747559f, 0.766602f, 0.784668f, 0.801758f, 0.816895f,
+ 0.831055f, 0.843750f, 0.856934f, 0.867188f, 0.878418f, 0.887207f, 0.896484f, 0.904785f, 0.913086f, 0.919922f, 0.926270f, 0.932617f,
+ 0.938477f, 0.944336f, 0.949707f, 0.953613f, 0.958496f, 0.962891f, 0.983887f, 0.984863f, 0.984863f, 0.984375f, 0.983887f, 0.983398f,
+ 0.001891f, 0.004959f, 0.009300f, 0.013786f, 0.018433f, 0.023560f, 0.029892f, 0.037018f, 0.044586f, 0.053284f, 0.062805f, 0.074341f,
+ 0.086975f, 0.100586f, 0.116760f, 0.133789f, 0.154175f, 0.176025f, 0.200317f, 0.226318f, 0.254395f, 0.284424f, 0.316650f, 0.349365f,
+ 0.383301f, 0.418213f, 0.452393f, 0.487061f, 0.520508f, 0.553223f, 0.584473f, 0.613770f, 0.643066f, 0.668945f, 0.695312f, 0.718262f,
+ 0.740234f, 0.761230f, 0.778809f, 0.797363f, 0.812988f, 0.827148f, 0.840332f, 0.854004f, 0.865723f, 0.875977f, 0.886230f, 0.895020f,
+ 0.904297f, 0.912598f, 0.919922f, 0.926270f, 0.932617f, 0.938965f, 0.943359f, 0.949219f, 0.955078f, 0.958984f, 0.982422f, 0.983887f,
+ 0.983398f, 0.982910f, 0.982910f, 0.981934f, 0.001368f, 0.004715f, 0.008041f, 0.011948f, 0.016235f, 0.020889f, 0.025848f, 0.031921f,
+ 0.038391f, 0.045563f, 0.054108f, 0.063477f, 0.074036f, 0.085815f, 0.099304f, 0.114563f, 0.131104f, 0.150146f, 0.170654f, 0.193970f,
+ 0.219360f, 0.246338f, 0.275146f, 0.306396f, 0.338867f, 0.372559f, 0.406494f, 0.440918f, 0.474609f, 0.508789f, 0.541992f, 0.574219f,
+ 0.604492f, 0.634277f, 0.661133f, 0.687500f, 0.710938f, 0.733887f, 0.754883f, 0.774414f, 0.792480f, 0.809570f, 0.824707f, 0.838379f,
+ 0.852051f, 0.862793f, 0.874023f, 0.885254f, 0.895020f, 0.903320f, 0.912109f, 0.919434f, 0.926758f, 0.932617f, 0.939941f, 0.945312f,
+ 0.951172f, 0.955078f, 0.980957f, 0.982910f, 0.982422f, 0.982422f, 0.981445f, 0.981445f, 0.001393f, 0.004227f, 0.007011f, 0.010323f,
+ 0.014107f, 0.018234f, 0.022766f, 0.027649f, 0.032898f, 0.039581f, 0.046539f, 0.054230f, 0.063293f, 0.073608f, 0.085144f, 0.097961f,
+ 0.112305f, 0.127930f, 0.146362f, 0.166260f, 0.188599f, 0.212524f, 0.238647f, 0.266846f, 0.297363f, 0.328369f, 0.361816f, 0.395752f,
+ 0.429932f, 0.464844f, 0.498535f, 0.531250f, 0.564453f, 0.596191f, 0.625488f, 0.653320f, 0.680176f, 0.704590f, 0.728027f, 0.750977f,
+ 0.770020f, 0.788574f, 0.805176f, 0.821289f, 0.835449f, 0.849609f, 0.862793f, 0.874023f, 0.884277f, 0.894043f, 0.903320f, 0.911621f,
+ 0.919434f, 0.926758f, 0.933594f, 0.939453f, 0.945312f, 0.951172f, 0.979492f, 0.980957f, 0.980957f, 0.980957f, 0.980469f, 0.979980f,
+ 0.001163f, 0.003527f, 0.006229f, 0.009323f, 0.012199f, 0.015808f, 0.019928f, 0.024200f, 0.028870f, 0.033997f, 0.040161f, 0.046967f,
+ 0.054871f, 0.063477f, 0.073181f, 0.083618f, 0.096252f, 0.109863f, 0.125122f, 0.142334f, 0.161743f, 0.182739f, 0.206421f, 0.232300f,
+ 0.259277f, 0.288086f, 0.320068f, 0.352783f, 0.386475f, 0.420410f, 0.454590f, 0.489258f, 0.521973f, 0.555176f, 0.586914f, 0.617188f,
+ 0.646484f, 0.673828f, 0.699707f, 0.723633f, 0.746094f, 0.766113f, 0.785645f, 0.803223f, 0.819336f, 0.834961f, 0.848633f, 0.861328f,
+ 0.873535f, 0.884766f, 0.893555f, 0.903809f, 0.911621f, 0.920410f, 0.928223f, 0.934082f, 0.939941f, 0.946777f, 0.978027f, 0.979492f,
+ 0.979492f, 0.979004f, 0.979004f, 0.978516f, 0.000981f, 0.002987f, 0.005329f, 0.008186f, 0.010895f, 0.013832f, 0.017532f, 0.021149f,
+ 0.025253f, 0.029999f, 0.035034f, 0.040985f, 0.047485f, 0.054993f, 0.063049f, 0.072510f, 0.082581f, 0.094421f, 0.107727f, 0.122498f,
+ 0.138794f, 0.157471f, 0.178467f, 0.200562f, 0.225586f, 0.251953f, 0.281250f, 0.311279f, 0.343750f, 0.377197f, 0.411621f, 0.445557f,
+ 0.479736f, 0.513672f, 0.546875f, 0.579590f, 0.610352f, 0.640625f, 0.668457f, 0.694336f, 0.718750f, 0.742188f, 0.762695f, 0.782715f,
+ 0.801270f, 0.817871f, 0.833496f, 0.847168f, 0.860840f, 0.872559f, 0.884277f, 0.894531f, 0.904297f, 0.912598f, 0.920898f, 0.928711f,
+ 0.935547f, 0.942383f, 0.976074f, 0.978027f, 0.978516f, 0.978027f, 0.977539f, 0.977051f, 0.000880f, 0.002707f, 0.005089f, 0.007305f,
+ 0.010147f, 0.012596f, 0.015160f, 0.018616f, 0.022507f, 0.026230f, 0.030777f, 0.035767f, 0.041351f, 0.047455f, 0.054565f, 0.062256f,
+ 0.071289f, 0.081299f, 0.092346f, 0.105408f, 0.119812f, 0.135620f, 0.153320f, 0.173462f, 0.195068f, 0.219482f, 0.245361f, 0.273682f,
+ 0.303711f, 0.335938f, 0.368896f, 0.402588f, 0.437500f, 0.472168f, 0.505859f, 0.539551f, 0.573242f, 0.604492f, 0.634766f, 0.663086f,
+ 0.689453f, 0.714844f, 0.738770f, 0.760254f, 0.780762f, 0.799316f, 0.817383f, 0.833496f, 0.847168f, 0.860840f, 0.873535f, 0.884766f,
+ 0.895508f, 0.905273f, 0.914062f, 0.922363f, 0.930176f, 0.937012f, 0.974609f, 0.976074f, 0.976074f, 0.976562f, 0.976074f, 0.975586f,
+ 0.000851f, 0.002659f, 0.004692f, 0.006466f, 0.008545f, 0.011055f, 0.013649f, 0.016403f, 0.019714f, 0.023056f, 0.026962f, 0.031235f,
+ 0.035828f, 0.041656f, 0.047699f, 0.054077f, 0.061859f, 0.070496f, 0.080200f, 0.091125f, 0.103088f, 0.116882f, 0.132446f, 0.149780f,
+ 0.168701f, 0.190430f, 0.213379f, 0.239258f, 0.267334f, 0.296631f, 0.328369f, 0.360840f, 0.395020f, 0.429932f, 0.464355f, 0.499512f,
+ 0.533203f, 0.566406f, 0.599121f, 0.629883f, 0.658203f, 0.687012f, 0.712402f, 0.735840f, 0.758789f, 0.779297f, 0.798828f, 0.816406f,
+ 0.832520f, 0.847168f, 0.861328f, 0.874023f, 0.886230f, 0.896973f, 0.907227f, 0.915527f, 0.924805f, 0.931641f, 0.972168f, 0.975586f,
+ 0.975586f, 0.974609f, 0.974121f, 0.973633f, 0.000762f, 0.002214f, 0.004040f, 0.005859f, 0.007790f, 0.009689f, 0.012161f, 0.014786f,
+ 0.017441f, 0.020493f, 0.023956f, 0.027618f, 0.031860f, 0.036255f, 0.041595f, 0.047394f, 0.053894f, 0.061188f, 0.069214f, 0.078735f,
+ 0.089050f, 0.101135f, 0.114441f, 0.129150f, 0.145874f, 0.164673f, 0.185303f, 0.208862f, 0.233765f, 0.260742f, 0.290283f, 0.321045f,
+ 0.354248f, 0.388184f, 0.422607f, 0.457764f, 0.493652f, 0.526855f, 0.561523f, 0.594238f, 0.625977f, 0.655273f, 0.683594f, 0.710449f,
+ 0.734863f, 0.758301f, 0.779297f, 0.798828f, 0.817383f, 0.833984f, 0.848145f, 0.862793f, 0.875488f, 0.887207f, 0.899414f, 0.908691f,
+ 0.917969f, 0.926270f, 0.970215f, 0.972656f, 0.974121f, 0.973145f, 0.972656f, 0.972168f, 0.000732f, 0.001928f, 0.003513f, 0.005234f,
+ 0.007042f, 0.008629f, 0.010620f, 0.012985f, 0.015244f, 0.018158f, 0.020935f, 0.024475f, 0.027908f, 0.032013f, 0.036316f, 0.041290f,
+ 0.046661f, 0.053040f, 0.060089f, 0.068115f, 0.077087f, 0.087463f, 0.099121f, 0.111633f, 0.126221f, 0.142578f, 0.160767f, 0.181396f,
+ 0.203003f, 0.228149f, 0.255127f, 0.284180f, 0.315186f, 0.347900f, 0.381836f, 0.416748f, 0.451904f, 0.487549f, 0.522949f, 0.556641f,
+ 0.590332f, 0.623047f, 0.652832f, 0.682129f, 0.708984f, 0.733887f, 0.757324f, 0.779785f, 0.799316f, 0.818359f, 0.835449f, 0.850586f,
+ 0.865234f, 0.877441f, 0.890137f, 0.901367f, 0.912109f, 0.920410f, 0.968262f, 0.970703f, 0.971191f, 0.970703f, 0.971191f, 0.971191f,
+ 0.000524f, 0.001758f, 0.003185f, 0.004864f, 0.006081f, 0.007820f, 0.009705f, 0.011467f, 0.013634f, 0.016068f, 0.018707f, 0.021378f,
+ 0.024597f, 0.028030f, 0.032135f, 0.036224f, 0.041016f, 0.046692f, 0.052399f, 0.059265f, 0.067505f, 0.076050f, 0.085510f, 0.096558f,
+ 0.109253f, 0.123657f, 0.138794f, 0.157227f, 0.176880f, 0.198730f, 0.223267f, 0.250000f, 0.278809f, 0.309326f, 0.342041f, 0.375977f,
+ 0.410889f, 0.447021f, 0.483154f, 0.518555f, 0.554199f, 0.586914f, 0.620117f, 0.650879f, 0.681641f, 0.708496f, 0.734375f, 0.757324f,
+ 0.780762f, 0.801270f, 0.819336f, 0.837891f, 0.852539f, 0.867188f, 0.880371f, 0.893066f, 0.903809f, 0.914551f, 0.966309f, 0.968750f,
+ 0.969238f, 0.969727f, 0.968750f, 0.968750f, 0.000503f, 0.001896f, 0.002653f, 0.004128f, 0.005627f, 0.007004f, 0.008797f, 0.010361f,
+ 0.012230f, 0.014175f, 0.016647f, 0.019348f, 0.021454f, 0.024872f, 0.028290f, 0.031830f, 0.036163f, 0.040649f, 0.045715f, 0.051941f,
+ 0.058319f, 0.065979f, 0.074402f, 0.083618f, 0.094360f, 0.106812f, 0.120239f, 0.135742f, 0.153320f, 0.172974f, 0.194824f, 0.218506f,
+ 0.245117f, 0.273926f, 0.304688f, 0.336426f, 0.371094f, 0.406982f, 0.442627f, 0.479492f, 0.514648f, 0.550781f, 0.584961f, 0.618652f,
+ 0.650879f, 0.681152f, 0.709473f, 0.735352f, 0.760742f, 0.782715f, 0.803711f, 0.821777f, 0.838867f, 0.855957f, 0.870605f, 0.884277f,
+ 0.895996f, 0.906738f, 0.964355f, 0.966309f, 0.967285f, 0.966797f, 0.966309f, 0.966309f, 0.000636f, 0.001421f, 0.002768f, 0.003761f,
+ 0.004944f, 0.006462f, 0.007889f, 0.009262f, 0.010780f, 0.013000f, 0.014946f, 0.017029f, 0.019516f, 0.022049f, 0.024933f, 0.028091f,
+ 0.031616f, 0.035553f, 0.040161f, 0.045380f, 0.051239f, 0.057281f, 0.064270f, 0.072693f, 0.081970f, 0.092468f, 0.104736f, 0.117859f,
+ 0.132690f, 0.150391f, 0.169189f, 0.190796f, 0.214233f, 0.240601f, 0.268555f, 0.299561f, 0.332520f, 0.367188f, 0.402344f, 0.438965f,
+ 0.476074f, 0.512695f, 0.549805f, 0.584473f, 0.619141f, 0.651367f, 0.681152f, 0.709961f, 0.737305f, 0.762695f, 0.785156f, 0.806641f,
+ 0.826172f, 0.843262f, 0.859375f, 0.874023f, 0.888184f, 0.900391f, 0.961426f, 0.964355f, 0.965332f, 0.964844f, 0.964355f, 0.964844f,
+ 0.000295f, 0.001419f, 0.002342f, 0.003471f, 0.004539f, 0.005821f, 0.006882f, 0.008354f, 0.010155f, 0.011574f, 0.013283f, 0.015129f,
+ 0.017090f, 0.019333f, 0.022125f, 0.024643f, 0.028122f, 0.031586f, 0.035522f, 0.039825f, 0.044586f, 0.050110f, 0.056091f, 0.063354f,
+ 0.071045f, 0.080078f, 0.090637f, 0.102112f, 0.115479f, 0.130127f, 0.147217f, 0.165649f, 0.186768f, 0.210571f, 0.236694f, 0.265137f,
+ 0.295654f, 0.328857f, 0.363770f, 0.399902f, 0.436523f, 0.474365f, 0.511230f, 0.548828f, 0.584961f, 0.619141f, 0.652344f, 0.684082f,
+ 0.712891f, 0.741211f, 0.766113f, 0.789062f, 0.810547f, 0.830078f, 0.848633f, 0.864258f, 0.879395f, 0.892578f, 0.958496f, 0.962402f,
+ 0.962402f, 0.962402f, 0.961914f, 0.962402f, 0.000464f, 0.001313f, 0.002159f, 0.003134f, 0.004463f, 0.005001f, 0.006466f, 0.007595f,
+ 0.008842f, 0.010277f, 0.011971f, 0.013550f, 0.015434f, 0.017242f, 0.019348f, 0.021805f, 0.024734f, 0.027817f, 0.031174f, 0.034821f,
+ 0.039124f, 0.043823f, 0.049164f, 0.055237f, 0.062164f, 0.069336f, 0.078430f, 0.088501f, 0.099976f, 0.112854f, 0.127319f, 0.143555f,
+ 0.162354f, 0.183350f, 0.207031f, 0.233032f, 0.260986f, 0.291992f, 0.325195f, 0.361084f, 0.397217f, 0.435059f, 0.473389f, 0.510742f,
+ 0.549316f, 0.586426f, 0.620605f, 0.654785f, 0.686523f, 0.716797f, 0.744629f, 0.769043f, 0.793945f, 0.815918f, 0.834961f, 0.852539f,
+ 0.869141f, 0.884277f, 0.955078f, 0.959473f, 0.959473f, 0.959473f, 0.959961f, 0.959961f, 0.000541f, 0.001223f, 0.002172f, 0.002886f,
+ 0.003679f, 0.004681f, 0.005512f, 0.006683f, 0.008049f, 0.009346f, 0.010704f, 0.012024f, 0.013626f, 0.015213f, 0.017227f, 0.019516f,
+ 0.022079f, 0.024612f, 0.027313f, 0.030731f, 0.034180f, 0.038239f, 0.042969f, 0.048187f, 0.053864f, 0.060516f, 0.068298f, 0.076843f,
+ 0.086670f, 0.097473f, 0.110107f, 0.124268f, 0.140869f, 0.159302f, 0.180420f, 0.203613f, 0.229614f, 0.258057f, 0.289062f, 0.323486f,
+ 0.358398f, 0.395996f, 0.434082f, 0.472900f, 0.511719f, 0.550293f, 0.587402f, 0.624023f, 0.658203f, 0.690918f, 0.721191f, 0.749512f,
+ 0.774902f, 0.799316f, 0.821289f, 0.840820f, 0.859375f, 0.875488f, 0.952637f, 0.956543f, 0.957520f, 0.957520f, 0.957520f, 0.957031f,
+ 0.000252f, 0.001056f, 0.001923f, 0.002523f, 0.003414f, 0.003960f, 0.005146f, 0.006172f, 0.007130f, 0.008179f, 0.009567f, 0.010735f,
+ 0.012077f, 0.013878f, 0.015640f, 0.017456f, 0.019638f, 0.021622f, 0.024170f, 0.026978f, 0.030121f, 0.033630f, 0.037445f, 0.042053f,
+ 0.047119f, 0.052826f, 0.059174f, 0.066711f, 0.075012f, 0.084473f, 0.095276f, 0.107727f, 0.122070f, 0.138184f, 0.156250f, 0.177246f,
+ 0.200928f, 0.226929f, 0.255371f, 0.286865f, 0.321289f, 0.356934f, 0.395264f, 0.434326f, 0.473877f, 0.514160f, 0.553711f, 0.591797f,
+ 0.628418f, 0.663574f, 0.696777f, 0.728027f, 0.755859f, 0.782715f, 0.806152f, 0.829102f, 0.847656f, 0.867188f, 0.949707f, 0.954102f,
+ 0.954590f, 0.954590f, 0.954102f, 0.954590f, 0.000365f, 0.000963f, 0.001581f, 0.002337f, 0.002996f, 0.003952f, 0.004608f, 0.005459f,
+ 0.006489f, 0.007351f, 0.008484f, 0.009544f, 0.011108f, 0.012413f, 0.013901f, 0.015388f, 0.017181f, 0.019012f, 0.021439f, 0.023727f,
+ 0.026520f, 0.029449f, 0.032898f, 0.036835f, 0.041046f, 0.045868f, 0.051575f, 0.058075f, 0.064758f, 0.073120f, 0.082520f, 0.093079f,
+ 0.105652f, 0.119385f, 0.135620f, 0.153687f, 0.174683f, 0.198364f, 0.224365f, 0.253662f, 0.285400f, 0.320557f, 0.357178f, 0.395752f,
+ 0.435791f, 0.476318f, 0.516602f, 0.557129f, 0.596191f, 0.633789f, 0.669434f, 0.703613f, 0.734375f, 0.763672f, 0.790039f, 0.812988f,
+ 0.836914f, 0.855957f, 0.946289f, 0.949707f, 0.951172f, 0.951172f, 0.951172f, 0.951172f, 0.000404f, 0.001028f, 0.001410f, 0.002098f,
+ 0.002657f, 0.003445f, 0.004391f, 0.005039f, 0.005665f, 0.006569f, 0.007549f, 0.008614f, 0.009743f, 0.011108f, 0.012390f, 0.013611f,
+ 0.015396f, 0.017044f, 0.018921f, 0.020874f, 0.023453f, 0.025833f, 0.028809f, 0.032501f, 0.036011f, 0.040161f, 0.044952f, 0.050018f,
+ 0.056091f, 0.063477f, 0.071533f, 0.080200f, 0.091064f, 0.103027f, 0.117065f, 0.133057f, 0.151489f, 0.171997f, 0.196045f, 0.222290f,
+ 0.251709f, 0.284424f, 0.319824f, 0.357422f, 0.397217f, 0.438232f, 0.479492f, 0.521484f, 0.562500f, 0.602051f, 0.641113f, 0.677734f,
+ 0.711914f, 0.743164f, 0.772461f, 0.799316f, 0.822754f, 0.845215f, 0.942383f, 0.946777f, 0.947754f, 0.947754f, 0.948242f, 0.948242f,
+ 0.000406f, 0.000992f, 0.001447f, 0.001986f, 0.002499f, 0.003149f, 0.003769f, 0.004272f, 0.005016f, 0.005981f, 0.006924f, 0.007675f,
+ 0.008766f, 0.009727f, 0.010765f, 0.011986f, 0.013588f, 0.014915f, 0.016724f, 0.018478f, 0.020508f, 0.022873f, 0.025497f, 0.028336f,
+ 0.031525f, 0.034882f, 0.038818f, 0.043243f, 0.048615f, 0.054626f, 0.061707f, 0.069214f, 0.078430f, 0.089111f, 0.101013f, 0.115112f,
+ 0.130859f, 0.148926f, 0.170166f, 0.193604f, 0.220947f, 0.250732f, 0.283936f, 0.320068f, 0.358887f, 0.400391f, 0.442139f, 0.483887f,
+ 0.527344f, 0.569824f, 0.610352f, 0.649414f, 0.686523f, 0.722168f, 0.753906f, 0.782227f, 0.809570f, 0.833496f, 0.938477f, 0.942871f,
+ 0.944824f, 0.944336f, 0.943848f, 0.943848f, 0.000235f, 0.000984f, 0.001204f, 0.001706f, 0.002239f, 0.002998f, 0.003462f, 0.004093f,
+ 0.004372f, 0.005371f, 0.006149f, 0.006962f, 0.007736f, 0.008766f, 0.009804f, 0.010780f, 0.011887f, 0.013336f, 0.014618f, 0.016159f,
+ 0.018158f, 0.020050f, 0.022232f, 0.024597f, 0.027313f, 0.030334f, 0.033752f, 0.037872f, 0.042389f, 0.047516f, 0.053192f, 0.059937f,
+ 0.067749f, 0.076599f, 0.086975f, 0.098755f, 0.112610f, 0.128662f, 0.146973f, 0.168091f, 0.192383f, 0.220215f, 0.250732f, 0.284668f,
+ 0.322021f, 0.361572f, 0.403564f, 0.446777f, 0.490723f, 0.534668f, 0.577637f, 0.619629f, 0.660156f, 0.697754f, 0.731934f, 0.764648f,
+ 0.794922f, 0.820312f, 0.934082f, 0.939453f, 0.939941f, 0.941406f, 0.940430f, 0.940918f, 0.000237f, 0.000591f, 0.001098f, 0.001619f,
+ 0.002241f, 0.002636f, 0.003176f, 0.003521f, 0.004101f, 0.004631f, 0.005398f, 0.006378f, 0.007000f, 0.007767f, 0.008713f, 0.009758f,
+ 0.010475f, 0.011734f, 0.013016f, 0.014404f, 0.015762f, 0.017517f, 0.019440f, 0.021469f, 0.023651f, 0.026199f, 0.029495f, 0.033112f,
+ 0.036499f, 0.040955f, 0.045959f, 0.051849f, 0.058197f, 0.065552f, 0.074585f, 0.085022f, 0.096680f, 0.110535f, 0.126709f, 0.145264f,
+ 0.166626f, 0.191406f, 0.219482f, 0.250488f, 0.286133f, 0.323975f, 0.365723f, 0.408447f, 0.453125f, 0.498779f, 0.542969f, 0.588379f,
+ 0.631836f, 0.671387f, 0.709473f, 0.745117f, 0.777344f, 0.807617f, 0.930176f, 0.935059f, 0.936523f, 0.936523f, 0.936523f, 0.936035f,
+ 0.000242f, 0.000761f, 0.000943f, 0.001624f, 0.001858f, 0.002390f, 0.002638f, 0.003054f, 0.003805f, 0.004559f, 0.005035f, 0.005493f,
+ 0.006157f, 0.006878f, 0.007687f, 0.008530f, 0.009178f, 0.010406f, 0.011406f, 0.012520f, 0.014053f, 0.015579f, 0.017105f, 0.018661f,
+ 0.020737f, 0.022903f, 0.025650f, 0.028259f, 0.031433f, 0.035065f, 0.039581f, 0.044342f, 0.049988f, 0.056366f, 0.064026f, 0.072632f,
+ 0.082825f, 0.094666f, 0.108582f, 0.124634f, 0.143799f, 0.165405f, 0.190796f, 0.219360f, 0.251953f, 0.287842f, 0.328125f, 0.370605f,
+ 0.415283f, 0.461670f, 0.507812f, 0.555176f, 0.600586f, 0.645020f, 0.685547f, 0.724121f, 0.759277f, 0.792969f, 0.924805f, 0.931152f,
+ 0.931641f, 0.932129f, 0.932129f, 0.931641f, 0.000240f, 0.000685f, 0.000955f, 0.001395f, 0.001768f, 0.002157f, 0.002533f, 0.002970f,
+ 0.003223f, 0.003813f, 0.004601f, 0.004993f, 0.005428f, 0.005981f, 0.006878f, 0.007484f, 0.008110f, 0.009132f, 0.009964f, 0.011208f,
+ 0.012138f, 0.013374f, 0.015099f, 0.016190f, 0.018112f, 0.020187f, 0.022202f, 0.024780f, 0.027573f, 0.030411f, 0.034119f, 0.037964f,
+ 0.042755f, 0.048553f, 0.054474f, 0.061890f, 0.070984f, 0.080688f, 0.092590f, 0.106812f, 0.123291f, 0.142456f, 0.164551f, 0.190430f,
+ 0.220459f, 0.253418f, 0.291504f, 0.332520f, 0.376709f, 0.423340f, 0.471436f, 0.520508f, 0.567383f, 0.614746f, 0.660156f, 0.702148f,
+ 0.741211f, 0.776367f, 0.920410f, 0.925293f, 0.926270f, 0.926758f, 0.927246f, 0.926758f, 0.000244f, 0.000431f, 0.000799f, 0.001309f,
+ 0.001587f, 0.001945f, 0.002317f, 0.002514f, 0.003290f, 0.003548f, 0.004082f, 0.004349f, 0.004707f, 0.005348f, 0.006027f, 0.006565f,
+ 0.007141f, 0.008011f, 0.008850f, 0.009552f, 0.010757f, 0.011650f, 0.012794f, 0.014145f, 0.015778f, 0.017303f, 0.019028f, 0.021088f,
+ 0.023575f, 0.026169f, 0.029175f, 0.032562f, 0.036713f, 0.041382f, 0.046448f, 0.052948f, 0.060303f, 0.068787f, 0.079041f, 0.090942f,
+ 0.105103f, 0.121643f, 0.141113f, 0.164185f, 0.190308f, 0.221191f, 0.256836f, 0.295898f, 0.339355f, 0.385010f, 0.433838f, 0.484619f,
+ 0.534668f, 0.583496f, 0.631348f, 0.678223f, 0.719727f, 0.759766f, 0.913574f, 0.920410f, 0.921387f, 0.921875f, 0.921875f, 0.921387f,
+ 0.000243f, 0.000496f, 0.000847f, 0.001157f, 0.001426f, 0.001634f, 0.002020f, 0.002338f, 0.002607f, 0.003035f, 0.003502f, 0.003872f,
+ 0.004459f, 0.004726f, 0.005402f, 0.005779f, 0.006325f, 0.007095f, 0.007767f, 0.008568f, 0.009331f, 0.010086f, 0.011009f, 0.012314f,
+ 0.013611f, 0.015060f, 0.016312f, 0.018158f, 0.020401f, 0.022476f, 0.024979f, 0.027863f, 0.031036f, 0.034943f, 0.039581f, 0.044830f,
+ 0.050903f, 0.058289f, 0.066895f, 0.076782f, 0.088989f, 0.103210f, 0.120422f, 0.140259f, 0.164185f, 0.191772f, 0.223877f, 0.260742f,
+ 0.301758f, 0.347168f, 0.395508f, 0.446533f, 0.497803f, 0.551270f, 0.601562f, 0.651855f, 0.697754f, 0.741211f, 0.908203f, 0.915039f,
+ 0.916016f, 0.916016f, 0.916504f, 0.915527f, 0.000239f, 0.000345f, 0.000690f, 0.000913f, 0.001250f, 0.001343f, 0.001579f, 0.002050f,
+ 0.002331f, 0.002861f, 0.003048f, 0.003616f, 0.003696f, 0.004211f, 0.004723f, 0.005074f, 0.005657f, 0.006100f, 0.006893f, 0.007290f,
+ 0.008118f, 0.008659f, 0.009552f, 0.010704f, 0.011681f, 0.012764f, 0.014114f, 0.015533f, 0.017227f, 0.018982f, 0.021286f, 0.023560f,
+ 0.026489f, 0.029861f, 0.033417f, 0.037933f, 0.043121f, 0.049286f, 0.056519f, 0.065002f, 0.075073f, 0.087158f, 0.101624f, 0.118835f,
+ 0.139648f, 0.164185f, 0.193481f, 0.226929f, 0.265625f, 0.309570f, 0.356934f, 0.408203f, 0.461426f, 0.516113f, 0.569824f, 0.623047f,
+ 0.674316f, 0.720703f, 0.902344f, 0.908203f, 0.909668f, 0.910645f, 0.910645f, 0.911133f, 0.000000f, 0.000281f, 0.000560f, 0.000977f,
+ 0.001063f, 0.001171f, 0.001569f, 0.001903f, 0.002075f, 0.002413f, 0.002695f, 0.003004f, 0.003399f, 0.003553f, 0.003998f, 0.004333f,
+ 0.004971f, 0.005314f, 0.005806f, 0.006340f, 0.007015f, 0.007492f, 0.008377f, 0.009186f, 0.010094f, 0.010910f, 0.012199f, 0.013351f,
+ 0.014618f, 0.016266f, 0.018082f, 0.019852f, 0.022491f, 0.025085f, 0.028168f, 0.031799f, 0.036041f, 0.041107f, 0.047394f, 0.054321f,
+ 0.062866f, 0.073181f, 0.085327f, 0.100525f, 0.118408f, 0.139648f, 0.165527f, 0.196411f, 0.231812f, 0.273193f, 0.318848f, 0.369629f,
+ 0.423828f, 0.480225f, 0.536621f, 0.592773f, 0.647949f, 0.699707f, 0.894043f, 0.900879f, 0.903809f, 0.903320f, 0.903320f, 0.902832f,
+ 0.000232f, 0.000227f, 0.000555f, 0.000656f, 0.000937f, 0.000985f, 0.001351f, 0.001723f, 0.001925f, 0.002010f, 0.002445f, 0.002625f,
+ 0.002760f, 0.003220f, 0.003551f, 0.003870f, 0.004303f, 0.004826f, 0.005028f, 0.005451f, 0.005985f, 0.006523f, 0.007000f, 0.007744f,
+ 0.008499f, 0.009361f, 0.010109f, 0.011185f, 0.012413f, 0.013603f, 0.015121f, 0.016891f, 0.018753f, 0.020920f, 0.023407f, 0.026764f,
+ 0.030197f, 0.034302f, 0.039429f, 0.044891f, 0.052368f, 0.060822f, 0.071167f, 0.083557f, 0.098877f, 0.117493f, 0.139893f, 0.167725f,
+ 0.200195f, 0.238037f, 0.281982f, 0.331543f, 0.385010f, 0.442627f, 0.501465f, 0.561523f, 0.620605f, 0.675781f, 0.887207f, 0.894531f,
+ 0.895020f, 0.896484f, 0.896484f, 0.895996f, 0.000000f, 0.000332f, 0.000577f, 0.000723f, 0.000720f, 0.001210f, 0.001469f, 0.001456f,
+ 0.001546f, 0.001775f, 0.002159f, 0.002291f, 0.002659f, 0.002916f, 0.003046f, 0.003439f, 0.003752f, 0.003883f, 0.004375f, 0.004635f,
+ 0.005241f, 0.005638f, 0.006054f, 0.006630f, 0.007191f, 0.007744f, 0.008545f, 0.009178f, 0.010498f, 0.011536f, 0.012802f, 0.013931f,
+ 0.015808f, 0.017548f, 0.019379f, 0.022110f, 0.025040f, 0.028473f, 0.032471f, 0.037323f, 0.043152f, 0.050476f, 0.058807f, 0.069214f,
+ 0.082520f, 0.098145f, 0.116821f, 0.141602f, 0.170044f, 0.204834f, 0.245728f, 0.293213f, 0.346436f, 0.403564f, 0.464111f, 0.527832f,
+ 0.589844f, 0.650879f, 0.878418f, 0.886719f, 0.888184f, 0.887695f, 0.888672f, 0.888672f, 0.000243f, 0.000307f, 0.000526f, 0.000561f,
+ 0.000923f, 0.000980f, 0.001143f, 0.001386f, 0.001414f, 0.001683f, 0.001735f, 0.001972f, 0.002232f, 0.002481f, 0.002657f, 0.002754f,
+ 0.003193f, 0.003359f, 0.003603f, 0.003956f, 0.004368f, 0.004692f, 0.005119f, 0.005596f, 0.005955f, 0.006634f, 0.007256f, 0.007881f,
+ 0.008652f, 0.009552f, 0.010376f, 0.011719f, 0.012634f, 0.014595f, 0.016113f, 0.018219f, 0.020554f, 0.023254f, 0.026520f, 0.030502f,
+ 0.035553f, 0.041168f, 0.048065f, 0.057190f, 0.067261f, 0.080811f, 0.097107f, 0.117737f, 0.143066f, 0.173950f, 0.211182f, 0.256592f,
+ 0.307129f, 0.364502f, 0.427002f, 0.491943f, 0.557617f, 0.624023f, 0.869629f, 0.877930f, 0.879883f, 0.879883f, 0.879883f, 0.880371f,
+ 0.000000f, 0.000270f, 0.000342f, 0.000509f, 0.000668f, 0.000989f, 0.000945f, 0.001105f, 0.001230f, 0.001335f, 0.001492f, 0.001757f,
+ 0.001917f, 0.002140f, 0.002386f, 0.002501f, 0.002644f, 0.002884f, 0.003199f, 0.003441f, 0.003620f, 0.003891f, 0.004337f, 0.004631f,
+ 0.005119f, 0.005520f, 0.006100f, 0.006504f, 0.007301f, 0.007771f, 0.008751f, 0.009521f, 0.010658f, 0.011765f, 0.013145f, 0.014641f,
+ 0.016785f, 0.018829f, 0.021545f, 0.024719f, 0.028381f, 0.033203f, 0.038849f, 0.046112f, 0.055084f, 0.065552f, 0.079529f, 0.096985f,
+ 0.118530f, 0.145630f, 0.179321f, 0.220337f, 0.269287f, 0.325439f, 0.387207f, 0.454102f, 0.524414f, 0.595215f, 0.859863f, 0.868652f,
+ 0.870605f, 0.869629f, 0.870117f, 0.870605f, 0.000000f, 0.000230f, 0.000334f, 0.000416f, 0.000700f, 0.000726f, 0.000921f, 0.001008f,
+ 0.001065f, 0.001186f, 0.001365f, 0.001471f, 0.001627f, 0.001796f, 0.001843f, 0.002069f, 0.002266f, 0.002438f, 0.002596f, 0.002831f,
+ 0.003000f, 0.003298f, 0.003597f, 0.003887f, 0.004265f, 0.004581f, 0.004986f, 0.005505f, 0.005947f, 0.006454f, 0.007069f, 0.007801f,
+ 0.008621f, 0.009575f, 0.010612f, 0.011848f, 0.013321f, 0.015259f, 0.017410f, 0.019775f, 0.022934f, 0.026550f, 0.031464f, 0.036713f,
+ 0.043945f, 0.052887f, 0.064209f, 0.078735f, 0.096924f, 0.120361f, 0.149536f, 0.186768f, 0.232422f, 0.285889f, 0.347656f, 0.415527f,
+ 0.488281f, 0.563965f, 0.849121f, 0.857910f, 0.859375f, 0.860840f, 0.860840f, 0.860352f, 0.000233f, 0.000225f, 0.000219f, 0.000431f,
+ 0.000579f, 0.000648f, 0.000671f, 0.000744f, 0.000946f, 0.000994f, 0.001091f, 0.001307f, 0.001364f, 0.001490f, 0.001561f, 0.001712f,
+ 0.001892f, 0.001999f, 0.002190f, 0.002369f, 0.002512f, 0.002733f, 0.003014f, 0.003145f, 0.003553f, 0.003822f, 0.004135f, 0.004326f,
+ 0.004799f, 0.005344f, 0.005718f, 0.006378f, 0.007008f, 0.007721f, 0.008400f, 0.009537f, 0.010597f, 0.011917f, 0.013542f, 0.015579f,
+ 0.018051f, 0.020889f, 0.024765f, 0.029236f, 0.034668f, 0.041779f, 0.051056f, 0.062439f, 0.077576f, 0.097595f, 0.122864f, 0.155273f,
+ 0.196655f, 0.247437f, 0.307617f, 0.375977f, 0.450684f, 0.531250f, 0.837891f, 0.847168f, 0.848633f, 0.849609f, 0.849121f, 0.849609f,
+ 0.000202f, 0.000180f, 0.000206f, 0.000339f, 0.000479f, 0.000536f, 0.000687f, 0.000739f, 0.000771f, 0.000849f, 0.001051f, 0.001060f,
+ 0.001154f, 0.001219f, 0.001389f, 0.001505f, 0.001469f, 0.001729f, 0.001858f, 0.001980f, 0.002209f, 0.002243f, 0.002483f, 0.002695f,
+ 0.002951f, 0.003149f, 0.003374f, 0.003654f, 0.004002f, 0.004154f, 0.004539f, 0.005032f, 0.005428f, 0.005989f, 0.006760f, 0.007549f,
+ 0.008423f, 0.009499f, 0.010620f, 0.012016f, 0.013992f, 0.016434f, 0.019135f, 0.022583f, 0.026840f, 0.032501f, 0.039551f, 0.048828f,
+ 0.061066f, 0.077393f, 0.098755f, 0.127075f, 0.163208f, 0.209717f, 0.267578f, 0.334961f, 0.411133f, 0.494629f, 0.825684f, 0.834473f,
+ 0.836426f, 0.837402f, 0.837402f, 0.837402f, 0.000000f, 0.000185f, 0.000184f, 0.000404f, 0.000408f, 0.000454f, 0.000480f, 0.000506f,
+ 0.000660f, 0.000694f, 0.000742f, 0.000801f, 0.000989f, 0.001111f, 0.001167f, 0.001250f, 0.001311f, 0.001424f, 0.001541f, 0.001574f,
+ 0.001712f, 0.001930f, 0.001982f, 0.002201f, 0.002375f, 0.002439f, 0.002792f, 0.002905f, 0.003065f, 0.003412f, 0.003653f, 0.003952f,
+ 0.004463f, 0.004723f, 0.005230f, 0.005936f, 0.006386f, 0.007092f, 0.008240f, 0.009247f, 0.010765f, 0.012344f, 0.014420f, 0.017090f,
+ 0.020493f, 0.024551f, 0.030014f, 0.037689f, 0.047302f, 0.060028f, 0.077820f, 0.100830f, 0.132812f, 0.174561f, 0.228516f, 0.294434f,
+ 0.371582f, 0.457031f, 0.812012f, 0.820801f, 0.823730f, 0.824219f, 0.824707f, 0.824219f, 0.000000f, 0.000053f, 0.000206f, 0.000360f,
+ 0.000379f, 0.000391f, 0.000379f, 0.000478f, 0.000549f, 0.000589f, 0.000626f, 0.000674f, 0.000762f, 0.000832f, 0.000894f, 0.001050f,
+ 0.001111f, 0.001155f, 0.001286f, 0.001345f, 0.001449f, 0.001564f, 0.001666f, 0.001750f, 0.001856f, 0.001925f, 0.002056f, 0.002359f,
+ 0.002542f, 0.002728f, 0.003042f, 0.003164f, 0.003460f, 0.003786f, 0.004116f, 0.004578f, 0.005116f, 0.005688f, 0.006508f, 0.007229f,
+ 0.008125f, 0.009232f, 0.010796f, 0.012741f, 0.015137f, 0.018158f, 0.022186f, 0.028030f, 0.035248f, 0.045593f, 0.059052f, 0.078308f,
+ 0.105042f, 0.141602f, 0.190308f, 0.252930f, 0.329102f, 0.417969f, 0.797852f, 0.807129f, 0.810059f, 0.810547f, 0.811035f, 0.810547f,
+ 0.000000f, 0.000000f, 0.000082f, 0.000195f, 0.000309f, 0.000336f, 0.000324f, 0.000414f, 0.000439f, 0.000460f, 0.000599f, 0.000643f,
+ 0.000637f, 0.000690f, 0.000733f, 0.000834f, 0.000821f, 0.000922f, 0.000989f, 0.001067f, 0.001207f, 0.001293f, 0.001327f, 0.001476f,
+ 0.001581f, 0.001663f, 0.001725f, 0.001906f, 0.001934f, 0.002180f, 0.002258f, 0.002602f, 0.002701f, 0.003019f, 0.003229f, 0.003502f,
+ 0.003847f, 0.004261f, 0.004795f, 0.005318f, 0.006130f, 0.007008f, 0.008118f, 0.009277f, 0.011024f, 0.013229f, 0.016205f, 0.020203f,
+ 0.025620f, 0.033020f, 0.043854f, 0.059021f, 0.080383f, 0.111206f, 0.154419f, 0.212646f, 0.287354f, 0.378418f, 0.781250f, 0.792480f,
+ 0.793457f, 0.795410f, 0.795898f, 0.794922f, 0.000000f, 0.000121f, 0.000120f, 0.000198f, 0.000275f, 0.000249f, 0.000290f, 0.000360f,
+ 0.000375f, 0.000379f, 0.000391f, 0.000438f, 0.000505f, 0.000534f, 0.000669f, 0.000629f, 0.000659f, 0.000754f, 0.000890f, 0.000833f,
+ 0.000849f, 0.000975f, 0.001029f, 0.001117f, 0.001193f, 0.001203f, 0.001269f, 0.001424f, 0.001594f, 0.001675f, 0.001737f, 0.001957f,
+ 0.002094f, 0.002319f, 0.002342f, 0.002609f, 0.002928f, 0.003248f, 0.003523f, 0.003967f, 0.004547f, 0.005138f, 0.005871f, 0.006760f,
+ 0.007912f, 0.009430f, 0.011528f, 0.014236f, 0.017899f, 0.023346f, 0.031235f, 0.042694f, 0.059235f, 0.084229f, 0.120972f, 0.173950f,
+ 0.245239f, 0.334473f, 0.764160f, 0.775391f, 0.777344f, 0.778809f, 0.777832f, 0.778809f, 0.000000f, 0.000121f, 0.000119f, 0.000182f,
+ 0.000177f, 0.000179f, 0.000262f, 0.000239f, 0.000309f, 0.000322f, 0.000404f, 0.000370f, 0.000361f, 0.000430f, 0.000458f, 0.000540f,
+ 0.000589f, 0.000615f, 0.000648f, 0.000632f, 0.000777f, 0.000782f, 0.000798f, 0.000871f, 0.000857f, 0.000925f, 0.001000f, 0.001045f,
+ 0.001191f, 0.001223f, 0.001426f, 0.001419f, 0.001512f, 0.001635f, 0.001884f, 0.002092f, 0.002100f, 0.002293f, 0.002577f, 0.003012f,
+ 0.003258f, 0.003761f, 0.004253f, 0.004814f, 0.005619f, 0.006676f, 0.008064f, 0.009750f, 0.012268f, 0.015854f, 0.021255f, 0.029282f,
+ 0.041687f, 0.061005f, 0.091370f, 0.136230f, 0.202759f, 0.291504f, 0.746582f, 0.757324f, 0.759277f, 0.760254f, 0.760254f, 0.760254f,
+ 0.000000f, 0.000000f, 0.000117f, 0.000126f, 0.000113f, 0.000146f, 0.000158f, 0.000155f, 0.000189f, 0.000288f, 0.000254f, 0.000336f,
+ 0.000347f, 0.000353f, 0.000370f, 0.000355f, 0.000390f, 0.000417f, 0.000456f, 0.000480f, 0.000525f, 0.000587f, 0.000596f, 0.000620f,
+ 0.000676f, 0.000740f, 0.000758f, 0.000852f, 0.000907f, 0.000947f, 0.001057f, 0.001122f, 0.001170f, 0.001293f, 0.001316f, 0.001437f,
+ 0.001531f, 0.001813f, 0.001952f, 0.002090f, 0.002346f, 0.002560f, 0.002974f, 0.003334f, 0.003899f, 0.004547f, 0.005360f, 0.006516f,
+ 0.008179f, 0.010468f, 0.013947f, 0.019241f, 0.027832f, 0.041443f, 0.064941f, 0.102600f, 0.162231f, 0.247437f, 0.726074f, 0.737793f,
+ 0.739258f, 0.740723f, 0.741211f, 0.741211f, 0.000000f, 0.000118f, 0.000115f, 0.000113f, 0.000110f, 0.000126f, 0.000121f, 0.000139f,
+ 0.000147f, 0.000160f, 0.000161f, 0.000233f, 0.000199f, 0.000266f, 0.000286f, 0.000297f, 0.000329f, 0.000313f, 0.000347f, 0.000358f,
+ 0.000364f, 0.000394f, 0.000435f, 0.000446f, 0.000489f, 0.000506f, 0.000546f, 0.000625f, 0.000648f, 0.000674f, 0.000723f, 0.000782f,
+ 0.000865f, 0.000918f, 0.000979f, 0.001104f, 0.001100f, 0.001196f, 0.001352f, 0.001488f, 0.001586f, 0.001749f, 0.001955f, 0.002275f,
+ 0.002644f, 0.003054f, 0.003563f, 0.004322f, 0.005314f, 0.006786f, 0.008980f, 0.012115f, 0.017319f, 0.026520f, 0.043121f, 0.072693f,
+ 0.123535f, 0.203613f, 0.705566f, 0.716797f, 0.719238f, 0.719727f, 0.720703f, 0.721191f, 0.000000f, 0.000000f, 0.000112f, 0.000109f,
+ 0.000106f, 0.000104f, 0.000102f, 0.000096f, 0.000091f, 0.000113f, 0.000147f, 0.000129f, 0.000155f, 0.000134f, 0.000196f, 0.000205f,
+ 0.000181f, 0.000239f, 0.000297f, 0.000255f, 0.000317f, 0.000273f, 0.000335f, 0.000299f, 0.000379f, 0.000385f, 0.000398f, 0.000402f,
+ 0.000473f, 0.000552f, 0.000489f, 0.000543f, 0.000557f, 0.000606f, 0.000662f, 0.000698f, 0.000747f, 0.000810f, 0.000902f, 0.000961f,
+ 0.001063f, 0.001166f, 0.001312f, 0.001523f, 0.001662f, 0.001908f, 0.002298f, 0.002758f, 0.003365f, 0.004135f, 0.005394f, 0.007290f,
+ 0.010490f, 0.015991f, 0.026215f, 0.047180f, 0.087646f, 0.160645f, 0.682617f, 0.695801f, 0.697266f, 0.697266f, 0.697266f, 0.698730f,
+ 0.000000f, 0.000112f, 0.000106f, 0.000104f, 0.000100f, 0.000098f, 0.000095f, 0.000094f, 0.000090f, 0.000085f, 0.000080f, 0.000081f,
+ 0.000085f, 0.000123f, 0.000123f, 0.000138f, 0.000151f, 0.000158f, 0.000147f, 0.000171f, 0.000183f, 0.000192f, 0.000242f, 0.000215f,
+ 0.000253f, 0.000256f, 0.000269f, 0.000278f, 0.000293f, 0.000315f, 0.000377f, 0.000357f, 0.000357f, 0.000423f, 0.000479f, 0.000493f,
+ 0.000489f, 0.000535f, 0.000579f, 0.000628f, 0.000683f, 0.000731f, 0.000833f, 0.000935f, 0.001068f, 0.001200f, 0.001347f, 0.001581f,
+ 0.001995f, 0.002419f, 0.003109f, 0.004147f, 0.005829f, 0.008919f, 0.014641f, 0.027405f, 0.056885f, 0.119385f, 0.658691f, 0.669922f,
+ 0.673828f, 0.673828f, 0.675293f, 0.675293f, 0.000000f, 0.000105f, 0.000101f, 0.000096f, 0.000092f, 0.000089f, 0.000087f, 0.000085f,
+ 0.000083f, 0.000081f, 0.000077f, 0.000073f, 0.000070f, 0.000066f, 0.000080f, 0.000084f, 0.000089f, 0.000068f, 0.000101f, 0.000094f,
+ 0.000116f, 0.000118f, 0.000125f, 0.000129f, 0.000150f, 0.000168f, 0.000153f, 0.000192f, 0.000195f, 0.000185f, 0.000200f, 0.000217f,
+ 0.000226f, 0.000247f, 0.000257f, 0.000262f, 0.000319f, 0.000334f, 0.000347f, 0.000376f, 0.000395f, 0.000447f, 0.000504f, 0.000544f,
+ 0.000590f, 0.000670f, 0.000789f, 0.000887f, 0.001069f, 0.001345f, 0.001670f, 0.002167f, 0.003065f, 0.004562f, 0.007660f, 0.014290f,
+ 0.032135f, 0.081299f, 0.632812f, 0.645996f, 0.648926f, 0.649414f, 0.648926f, 0.649902f, 0.000109f, 0.000094f, 0.000087f, 0.000082f,
+ 0.000078f, 0.000076f, 0.000074f, 0.000071f, 0.000069f, 0.000068f, 0.000067f, 0.000066f, 0.000064f, 0.000061f, 0.000058f, 0.000055f,
+ 0.000053f, 0.000050f, 0.000051f, 0.000046f, 0.000059f, 0.000056f, 0.000057f, 0.000068f, 0.000078f, 0.000088f, 0.000096f, 0.000096f,
+ 0.000105f, 0.000107f, 0.000128f, 0.000121f, 0.000133f, 0.000141f, 0.000156f, 0.000151f, 0.000160f, 0.000200f, 0.000209f, 0.000198f,
+ 0.000222f, 0.000242f, 0.000258f, 0.000275f, 0.000314f, 0.000352f, 0.000410f, 0.000468f, 0.000537f, 0.000639f, 0.000799f, 0.001002f,
+ 0.001390f, 0.002092f, 0.003466f, 0.006653f, 0.015305f, 0.048004f, 0.606934f, 0.618652f, 0.622559f, 0.623047f, 0.623535f, 0.624023f,
+ 0.000084f, 0.000067f, 0.000064f, 0.000062f, 0.000057f, 0.000056f, 0.000053f, 0.000054f, 0.000051f, 0.000052f, 0.000050f, 0.000050f,
+ 0.000050f, 0.000049f, 0.000048f, 0.000047f, 0.000046f, 0.000044f, 0.000042f, 0.000040f, 0.000039f, 0.000037f, 0.000035f, 0.000036f,
+ 0.000037f, 0.000031f, 0.000040f, 0.000041f, 0.000042f, 0.000051f, 0.000058f, 0.000063f, 0.000067f, 0.000069f, 0.000072f, 0.000079f,
+ 0.000085f, 0.000092f, 0.000093f, 0.000101f, 0.000107f, 0.000123f, 0.000125f, 0.000139f, 0.000147f, 0.000154f, 0.000181f, 0.000204f,
+ 0.000229f, 0.000270f, 0.000327f, 0.000425f, 0.000559f, 0.000772f, 0.001265f, 0.002462f, 0.006191f, 0.022415f, 0.578613f, 0.592285f,
+ 0.595215f, 0.596191f, 0.596191f, 0.597656f, 0.000008f, 0.000022f, 0.000022f, 0.000024f, 0.000024f, 0.000027f, 0.000028f, 0.000028f,
+ 0.000028f, 0.000026f, 0.000028f, 0.000029f, 0.000029f, 0.000028f, 0.000029f, 0.000029f, 0.000029f, 0.000029f, 0.000030f, 0.000030f,
+ 0.000030f, 0.000029f, 0.000028f, 0.000027f, 0.000026f, 0.000025f, 0.000024f, 0.000023f, 0.000022f, 0.000021f, 0.000020f, 0.000019f,
+ 0.000021f, 0.000020f, 0.000022f, 0.000026f, 0.000028f, 0.000033f, 0.000037f, 0.000036f, 0.000039f, 0.000045f, 0.000051f, 0.000046f,
+ 0.000056f, 0.000059f, 0.000061f, 0.000071f, 0.000084f, 0.000098f, 0.000110f, 0.000133f, 0.000169f, 0.000223f, 0.000356f, 0.000648f,
+ 0.001702f, 0.007713f, 0.550293f, 0.564453f, 0.566895f, 0.567871f, 0.568359f, 0.568848f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000002f, 0.000003f, 0.000004f, 0.000006f,
+ 0.000007f, 0.000007f, 0.000008f, 0.000008f, 0.000009f, 0.000010f, 0.000011f, 0.000011f, 0.000012f, 0.000012f, 0.000013f, 0.000013f,
+ 0.000013f, 0.000014f, 0.000014f, 0.000013f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000009f, 0.000009f,
+ 0.000008f, 0.000008f, 0.000009f, 0.000011f, 0.000014f, 0.000017f, 0.000015f, 0.000018f, 0.000021f, 0.000022f, 0.000023f, 0.000026f,
+ 0.000035f, 0.000040f, 0.000056f, 0.000089f, 0.000225f, 0.001332f, 0.520996f, 0.535156f, 0.538086f, 0.540039f, 0.540039f, 0.540039f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000003f, 0.000003f,
+ 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000001f, 0.000002f, 0.000003f, 0.000003f, 0.000004f, 0.000017f, 0.491211f, 0.506348f,
+ 0.508789f, 0.510254f, 0.510254f, 0.510742f,
+ },
+ {
+ 0.064758f, 0.179688f, 0.277344f, 0.358398f, 0.427002f, 0.485107f, 0.535156f, 0.578613f, 0.615234f, 0.647949f, 0.677734f, 0.703125f,
+ 0.725586f, 0.745605f, 0.763672f, 0.780273f, 0.795410f, 0.810059f, 0.821777f, 0.833496f, 0.843750f, 0.854004f, 0.862793f, 0.871582f,
+ 0.879883f, 0.886719f, 0.894043f, 0.900879f, 0.906250f, 0.912109f, 0.917969f, 0.922852f, 0.927246f, 0.932129f, 0.936523f, 0.940918f,
+ 0.944824f, 0.948242f, 0.951660f, 0.955078f, 0.958496f, 0.961426f, 0.964844f, 0.967773f, 0.970215f, 0.973145f, 0.975586f, 0.977539f,
+ 0.979980f, 0.982422f, 0.984863f, 0.986328f, 0.988770f, 0.990234f, 0.992676f, 0.993652f, 0.995605f, 0.997559f, 0.998535f, 0.996582f,
+ 0.995117f, 0.993652f, 0.992188f, 0.990723f, 0.040344f, 0.121460f, 0.199341f, 0.272949f, 0.339600f, 0.401123f, 0.455078f, 0.501953f,
+ 0.546875f, 0.583984f, 0.618164f, 0.648926f, 0.676270f, 0.700195f, 0.723145f, 0.743164f, 0.761230f, 0.776855f, 0.793457f, 0.806641f,
+ 0.819336f, 0.831543f, 0.842285f, 0.852051f, 0.861328f, 0.869629f, 0.877930f, 0.886230f, 0.892578f, 0.899902f, 0.905273f, 0.911621f,
+ 0.917480f, 0.922852f, 0.927246f, 0.932129f, 0.936035f, 0.940430f, 0.945312f, 0.949219f, 0.952148f, 0.956055f, 0.958984f, 0.961914f,
+ 0.965332f, 0.967773f, 0.970703f, 0.973633f, 0.976074f, 0.978516f, 0.980957f, 0.983398f, 0.985840f, 0.987305f, 0.989258f, 0.991699f,
+ 0.993652f, 0.995117f, 0.997070f, 0.995605f, 0.994141f, 0.993164f, 0.991699f, 0.990234f, 0.027191f, 0.084961f, 0.145630f, 0.206177f,
+ 0.266113f, 0.323242f, 0.377930f, 0.428711f, 0.474609f, 0.517090f, 0.554688f, 0.591309f, 0.621582f, 0.650391f, 0.676758f, 0.700684f,
+ 0.723145f, 0.741699f, 0.760254f, 0.776855f, 0.791504f, 0.805664f, 0.818359f, 0.830566f, 0.841309f, 0.851074f, 0.861816f, 0.870117f,
+ 0.878418f, 0.885254f, 0.892090f, 0.899414f, 0.906250f, 0.912598f, 0.916992f, 0.922363f, 0.928223f, 0.932617f, 0.937500f, 0.941895f,
+ 0.945801f, 0.949219f, 0.953613f, 0.957031f, 0.960449f, 0.963379f, 0.966797f, 0.969727f, 0.971680f, 0.974609f, 0.977539f, 0.979980f,
+ 0.981934f, 0.984375f, 0.986328f, 0.989258f, 0.991211f, 0.992676f, 0.996094f, 0.994629f, 0.993652f, 0.992188f, 0.990723f, 0.989746f,
+ 0.019577f, 0.061340f, 0.108337f, 0.156860f, 0.207153f, 0.258789f, 0.310059f, 0.358887f, 0.405762f, 0.450928f, 0.491211f, 0.530273f,
+ 0.565430f, 0.597656f, 0.627441f, 0.654297f, 0.680176f, 0.702637f, 0.724121f, 0.743164f, 0.760742f, 0.776855f, 0.791992f, 0.806152f,
+ 0.817871f, 0.830078f, 0.841797f, 0.852539f, 0.861816f, 0.870117f, 0.878906f, 0.886230f, 0.893066f, 0.900391f, 0.906738f, 0.912598f,
+ 0.918457f, 0.923340f, 0.928223f, 0.933594f, 0.938477f, 0.942871f, 0.946777f, 0.950684f, 0.954590f, 0.958496f, 0.960938f, 0.964844f,
+ 0.967773f, 0.970703f, 0.973633f, 0.976074f, 0.979004f, 0.981445f, 0.983398f, 0.985840f, 0.987793f, 0.990234f, 0.995117f, 0.993652f,
+ 0.992676f, 0.991699f, 0.990234f, 0.989258f, 0.014397f, 0.046295f, 0.081543f, 0.120728f, 0.162842f, 0.206177f, 0.250977f, 0.296143f,
+ 0.342041f, 0.385986f, 0.427979f, 0.468262f, 0.506348f, 0.542480f, 0.575195f, 0.605469f, 0.633789f, 0.660156f, 0.684570f, 0.706543f,
+ 0.727539f, 0.745117f, 0.763184f, 0.778809f, 0.793945f, 0.807617f, 0.820312f, 0.833008f, 0.842773f, 0.852539f, 0.862305f, 0.872070f,
+ 0.879395f, 0.887207f, 0.894531f, 0.900879f, 0.907227f, 0.914551f, 0.919922f, 0.925293f, 0.930176f, 0.935547f, 0.938965f, 0.943359f,
+ 0.948730f, 0.952637f, 0.956055f, 0.959473f, 0.962891f, 0.966309f, 0.969238f, 0.972656f, 0.975098f, 0.977539f, 0.980957f, 0.982910f,
+ 0.984863f, 0.987793f, 0.994141f, 0.993164f, 0.991699f, 0.990723f, 0.989746f, 0.988281f, 0.010925f, 0.035828f, 0.063660f, 0.094360f,
+ 0.128174f, 0.164551f, 0.203247f, 0.244385f, 0.285645f, 0.326416f, 0.367432f, 0.409424f, 0.447998f, 0.484131f, 0.520508f, 0.553711f,
+ 0.584473f, 0.614258f, 0.641113f, 0.666016f, 0.689453f, 0.710938f, 0.730469f, 0.750488f, 0.766602f, 0.781250f, 0.796387f, 0.809570f,
+ 0.822266f, 0.833496f, 0.844727f, 0.854980f, 0.864258f, 0.873047f, 0.881348f, 0.889648f, 0.895996f, 0.903809f, 0.910156f, 0.916504f,
+ 0.921387f, 0.926758f, 0.932129f, 0.937500f, 0.941895f, 0.946777f, 0.950684f, 0.954102f, 0.958008f, 0.960938f, 0.965332f, 0.968262f,
+ 0.971680f, 0.975098f, 0.977539f, 0.979492f, 0.982422f, 0.984863f, 0.992676f, 0.991699f, 0.990723f, 0.989746f, 0.988770f, 0.987793f,
+ 0.008698f, 0.028244f, 0.049866f, 0.074463f, 0.102295f, 0.132935f, 0.165161f, 0.200073f, 0.236206f, 0.275391f, 0.313477f, 0.352051f,
+ 0.391113f, 0.428955f, 0.465088f, 0.500977f, 0.534180f, 0.565430f, 0.593750f, 0.622559f, 0.648438f, 0.671875f, 0.694824f, 0.715820f,
+ 0.734863f, 0.753906f, 0.771484f, 0.784668f, 0.799805f, 0.813477f, 0.825195f, 0.836914f, 0.847656f, 0.857910f, 0.866699f, 0.875488f,
+ 0.884766f, 0.892090f, 0.898438f, 0.906250f, 0.913086f, 0.918457f, 0.923828f, 0.929688f, 0.935059f, 0.939941f, 0.944336f, 0.948730f,
+ 0.952637f, 0.956055f, 0.959961f, 0.963379f, 0.967285f, 0.970703f, 0.973633f, 0.976074f, 0.979492f, 0.982422f, 0.991211f, 0.990723f,
+ 0.990234f, 0.988770f, 0.987793f, 0.986328f, 0.007210f, 0.022797f, 0.040039f, 0.060181f, 0.082153f, 0.107300f, 0.134155f, 0.164673f,
+ 0.196167f, 0.229492f, 0.265381f, 0.301025f, 0.338379f, 0.374756f, 0.411133f, 0.446533f, 0.481201f, 0.515625f, 0.546387f, 0.576660f,
+ 0.605957f, 0.631348f, 0.656738f, 0.681152f, 0.702148f, 0.722168f, 0.741699f, 0.758789f, 0.775391f, 0.791016f, 0.803711f, 0.817383f,
+ 0.829102f, 0.840820f, 0.851562f, 0.860840f, 0.871094f, 0.879395f, 0.887695f, 0.895020f, 0.901855f, 0.909180f, 0.915527f, 0.921387f,
+ 0.927734f, 0.932129f, 0.937500f, 0.941895f, 0.947266f, 0.950684f, 0.955078f, 0.958984f, 0.962891f, 0.966797f, 0.969727f, 0.973145f,
+ 0.976562f, 0.979004f, 0.990234f, 0.989746f, 0.988770f, 0.987793f, 0.986816f, 0.985840f, 0.005863f, 0.018936f, 0.032898f, 0.049377f,
+ 0.067261f, 0.088257f, 0.110535f, 0.135254f, 0.162231f, 0.191895f, 0.223389f, 0.255371f, 0.290039f, 0.324707f, 0.359863f, 0.395996f,
+ 0.429932f, 0.464355f, 0.497314f, 0.529297f, 0.559570f, 0.587891f, 0.616699f, 0.642090f, 0.665527f, 0.688965f, 0.709961f, 0.729492f,
+ 0.747559f, 0.765625f, 0.780762f, 0.794922f, 0.809082f, 0.822754f, 0.833984f, 0.844727f, 0.855957f, 0.864746f, 0.875000f, 0.883789f,
+ 0.891113f, 0.898926f, 0.906250f, 0.912598f, 0.918457f, 0.925293f, 0.930664f, 0.935059f, 0.940918f, 0.945312f, 0.950195f, 0.954590f,
+ 0.958496f, 0.962402f, 0.965820f, 0.969238f, 0.972656f, 0.976074f, 0.988770f, 0.988770f, 0.987793f, 0.986816f, 0.985840f, 0.984863f,
+ 0.004925f, 0.015518f, 0.027451f, 0.041199f, 0.055786f, 0.072998f, 0.091492f, 0.112427f, 0.135254f, 0.160767f, 0.187500f, 0.216919f,
+ 0.247314f, 0.280273f, 0.313477f, 0.346680f, 0.381592f, 0.415283f, 0.448730f, 0.481201f, 0.513184f, 0.543945f, 0.573242f, 0.601562f,
+ 0.627441f, 0.652344f, 0.675293f, 0.697754f, 0.718262f, 0.737793f, 0.754883f, 0.771973f, 0.787109f, 0.800781f, 0.815430f, 0.828125f,
+ 0.839844f, 0.851074f, 0.860840f, 0.870117f, 0.879883f, 0.887695f, 0.896484f, 0.902832f, 0.911133f, 0.916992f, 0.922852f, 0.928711f,
+ 0.934082f, 0.939941f, 0.944336f, 0.948730f, 0.954102f, 0.958008f, 0.961426f, 0.965332f, 0.969238f, 0.972168f, 0.987305f, 0.987305f,
+ 0.986816f, 0.985840f, 0.984863f, 0.983887f, 0.004139f, 0.012955f, 0.022781f, 0.034088f, 0.046997f, 0.061005f, 0.076538f, 0.094360f,
+ 0.113464f, 0.134888f, 0.158203f, 0.183716f, 0.210693f, 0.239990f, 0.270264f, 0.302734f, 0.334961f, 0.367676f, 0.400635f, 0.434082f,
+ 0.467041f, 0.497803f, 0.528809f, 0.558105f, 0.586426f, 0.614258f, 0.638672f, 0.663574f, 0.686035f, 0.707520f, 0.728027f, 0.745605f,
+ 0.762695f, 0.779297f, 0.794434f, 0.808594f, 0.821777f, 0.834473f, 0.845215f, 0.855957f, 0.866699f, 0.876465f, 0.884766f, 0.892090f,
+ 0.900391f, 0.908203f, 0.915039f, 0.920898f, 0.927246f, 0.932617f, 0.937988f, 0.943848f, 0.948730f, 0.952637f, 0.957520f, 0.961426f,
+ 0.965820f, 0.968750f, 0.985840f, 0.985840f, 0.985840f, 0.984375f, 0.983887f, 0.982910f, 0.003492f, 0.011307f, 0.019608f, 0.028793f,
+ 0.039246f, 0.051544f, 0.064392f, 0.078796f, 0.095337f, 0.113953f, 0.134033f, 0.155396f, 0.179688f, 0.205200f, 0.232300f, 0.261475f,
+ 0.291748f, 0.323730f, 0.355225f, 0.387939f, 0.420410f, 0.452637f, 0.483887f, 0.514648f, 0.544922f, 0.573730f, 0.601074f, 0.626953f,
+ 0.651367f, 0.675293f, 0.697266f, 0.717285f, 0.736816f, 0.755371f, 0.771973f, 0.786621f, 0.803223f, 0.815430f, 0.828613f, 0.840820f,
+ 0.851562f, 0.863281f, 0.873047f, 0.880859f, 0.890625f, 0.898438f, 0.905762f, 0.913086f, 0.919434f, 0.925781f, 0.931641f, 0.937500f,
+ 0.942871f, 0.947754f, 0.952637f, 0.957520f, 0.960938f, 0.965820f, 0.984375f, 0.984863f, 0.984375f, 0.983398f, 0.982422f, 0.981445f,
+ 0.002977f, 0.009415f, 0.016708f, 0.024811f, 0.033356f, 0.043457f, 0.054535f, 0.067017f, 0.080322f, 0.096130f, 0.113708f, 0.132080f,
+ 0.152710f, 0.175415f, 0.199829f, 0.226440f, 0.253662f, 0.282959f, 0.313232f, 0.343750f, 0.375000f, 0.406982f, 0.439453f, 0.471191f,
+ 0.501465f, 0.531738f, 0.560547f, 0.587891f, 0.615234f, 0.640625f, 0.664062f, 0.687500f, 0.708496f, 0.728516f, 0.747559f, 0.765137f,
+ 0.781738f, 0.795898f, 0.811523f, 0.824707f, 0.836426f, 0.847656f, 0.858887f, 0.869141f, 0.878906f, 0.887695f, 0.895996f, 0.904297f,
+ 0.911133f, 0.917969f, 0.925293f, 0.931152f, 0.937012f, 0.942383f, 0.947266f, 0.953125f, 0.957031f, 0.961426f, 0.982910f, 0.983398f,
+ 0.982910f, 0.982422f, 0.981445f, 0.980957f, 0.002743f, 0.008568f, 0.014305f, 0.021378f, 0.028732f, 0.037201f, 0.046387f, 0.057068f,
+ 0.068848f, 0.082336f, 0.096924f, 0.113159f, 0.130859f, 0.150146f, 0.171509f, 0.194824f, 0.219482f, 0.246338f, 0.273926f, 0.302734f,
+ 0.333496f, 0.364502f, 0.395752f, 0.426758f, 0.458252f, 0.489990f, 0.519531f, 0.548340f, 0.576660f, 0.604004f, 0.630859f, 0.654297f,
+ 0.678223f, 0.700684f, 0.720215f, 0.740234f, 0.758301f, 0.775391f, 0.790527f, 0.805176f, 0.818848f, 0.833008f, 0.844238f, 0.855469f,
+ 0.866699f, 0.876953f, 0.886230f, 0.894043f, 0.902832f, 0.910645f, 0.917480f, 0.924316f, 0.930664f, 0.937012f, 0.941895f, 0.947266f,
+ 0.952148f, 0.957031f, 0.981445f, 0.982422f, 0.981445f, 0.980957f, 0.980469f, 0.979004f, 0.002504f, 0.007004f, 0.012634f, 0.018555f,
+ 0.024933f, 0.032654f, 0.040283f, 0.048920f, 0.059357f, 0.070007f, 0.082642f, 0.096741f, 0.112122f, 0.128906f, 0.147339f, 0.167603f,
+ 0.189697f, 0.213257f, 0.238770f, 0.265869f, 0.293701f, 0.323242f, 0.354004f, 0.384766f, 0.415283f, 0.447021f, 0.478516f, 0.507812f,
+ 0.536621f, 0.565918f, 0.593750f, 0.620605f, 0.645508f, 0.668945f, 0.692383f, 0.712891f, 0.733398f, 0.751465f, 0.769531f, 0.785156f,
+ 0.801270f, 0.814941f, 0.828125f, 0.841797f, 0.853516f, 0.864746f, 0.874512f, 0.883789f, 0.893555f, 0.900879f, 0.910156f, 0.917480f,
+ 0.923340f, 0.930664f, 0.936523f, 0.942383f, 0.947754f, 0.952637f, 0.979492f, 0.980469f, 0.980469f, 0.979492f, 0.978516f, 0.978027f,
+ 0.002039f, 0.006287f, 0.010864f, 0.016129f, 0.021637f, 0.027786f, 0.034485f, 0.042450f, 0.051331f, 0.060760f, 0.071594f, 0.082886f,
+ 0.096313f, 0.110840f, 0.126587f, 0.145020f, 0.164185f, 0.185181f, 0.207520f, 0.232300f, 0.258301f, 0.285889f, 0.314941f, 0.344238f,
+ 0.374268f, 0.405029f, 0.436035f, 0.466797f, 0.498291f, 0.527344f, 0.555664f, 0.583984f, 0.611328f, 0.636230f, 0.661133f, 0.684082f,
+ 0.705566f, 0.726562f, 0.745605f, 0.764648f, 0.781250f, 0.797852f, 0.812500f, 0.825195f, 0.838867f, 0.851074f, 0.862305f, 0.873535f,
+ 0.883301f, 0.892578f, 0.901367f, 0.908203f, 0.916992f, 0.923828f, 0.931152f, 0.937012f, 0.942383f, 0.947266f, 0.978027f, 0.978516f,
+ 0.979004f, 0.978027f, 0.977051f, 0.977051f, 0.001762f, 0.005489f, 0.009804f, 0.013931f, 0.019028f, 0.024445f, 0.030518f, 0.036865f,
+ 0.044189f, 0.052460f, 0.061432f, 0.071960f, 0.083008f, 0.095642f, 0.109558f, 0.124756f, 0.141602f, 0.160156f, 0.180664f, 0.202148f,
+ 0.225952f, 0.250977f, 0.278076f, 0.305664f, 0.334961f, 0.364990f, 0.394775f, 0.425537f, 0.456543f, 0.487061f, 0.517090f, 0.546387f,
+ 0.575195f, 0.602539f, 0.627930f, 0.653809f, 0.676758f, 0.699707f, 0.721191f, 0.740723f, 0.759766f, 0.777832f, 0.793945f, 0.809082f,
+ 0.823242f, 0.836426f, 0.849609f, 0.861328f, 0.872070f, 0.881836f, 0.892578f, 0.900391f, 0.908691f, 0.916992f, 0.924316f, 0.931152f,
+ 0.937500f, 0.943359f, 0.976074f, 0.977051f, 0.977051f, 0.976562f, 0.976074f, 0.975098f, 0.001675f, 0.005020f, 0.008400f, 0.012253f,
+ 0.016724f, 0.021469f, 0.026428f, 0.032104f, 0.039062f, 0.045563f, 0.053741f, 0.062103f, 0.072205f, 0.082947f, 0.094666f, 0.107727f,
+ 0.122681f, 0.139038f, 0.156250f, 0.176514f, 0.197388f, 0.220581f, 0.244629f, 0.270752f, 0.297607f, 0.326172f, 0.355957f, 0.386475f,
+ 0.416748f, 0.447754f, 0.478027f, 0.507812f, 0.538086f, 0.566406f, 0.594727f, 0.621582f, 0.647461f, 0.671387f, 0.694336f, 0.716797f,
+ 0.737305f, 0.755859f, 0.773438f, 0.791016f, 0.807129f, 0.820801f, 0.834961f, 0.848145f, 0.860352f, 0.871582f, 0.881836f, 0.891602f,
+ 0.901367f, 0.909180f, 0.917480f, 0.925293f, 0.932129f, 0.938965f, 0.974609f, 0.975586f, 0.976074f, 0.974609f, 0.974121f, 0.973633f,
+ 0.001437f, 0.004513f, 0.007427f, 0.010994f, 0.014526f, 0.018829f, 0.023331f, 0.028229f, 0.034058f, 0.040192f, 0.046844f, 0.054321f,
+ 0.062683f, 0.071716f, 0.082397f, 0.093933f, 0.106567f, 0.120728f, 0.136230f, 0.153320f, 0.172485f, 0.192627f, 0.214233f, 0.237915f,
+ 0.263672f, 0.290527f, 0.318115f, 0.347412f, 0.377197f, 0.408203f, 0.438477f, 0.469482f, 0.499512f, 0.529785f, 0.558594f, 0.586914f,
+ 0.614258f, 0.641602f, 0.665527f, 0.689941f, 0.711914f, 0.732422f, 0.752930f, 0.771484f, 0.789062f, 0.805664f, 0.819824f, 0.833984f,
+ 0.847656f, 0.860840f, 0.871094f, 0.881836f, 0.891602f, 0.902344f, 0.910156f, 0.918457f, 0.926270f, 0.932617f, 0.972168f, 0.973633f,
+ 0.973633f, 0.973145f, 0.973145f, 0.971680f, 0.001390f, 0.003952f, 0.006779f, 0.009941f, 0.013062f, 0.017029f, 0.020905f, 0.024994f,
+ 0.029877f, 0.035187f, 0.041077f, 0.047119f, 0.055145f, 0.062500f, 0.071594f, 0.081543f, 0.092712f, 0.104736f, 0.118530f, 0.133179f,
+ 0.150024f, 0.168091f, 0.187378f, 0.209717f, 0.232178f, 0.256836f, 0.283447f, 0.311279f, 0.339844f, 0.369873f, 0.399658f, 0.429932f,
+ 0.461426f, 0.492188f, 0.521973f, 0.551758f, 0.580566f, 0.608887f, 0.635254f, 0.660645f, 0.685059f, 0.708008f, 0.729492f, 0.750488f,
+ 0.769043f, 0.786621f, 0.802734f, 0.818848f, 0.832520f, 0.846680f, 0.860352f, 0.871582f, 0.882324f, 0.892578f, 0.902832f, 0.911133f,
+ 0.919922f, 0.926758f, 0.970703f, 0.971680f, 0.971680f, 0.971680f, 0.971680f, 0.969238f, 0.001328f, 0.003641f, 0.006138f, 0.008690f,
+ 0.011444f, 0.014786f, 0.018311f, 0.022125f, 0.026337f, 0.031403f, 0.036011f, 0.041809f, 0.047943f, 0.054901f, 0.062622f, 0.071106f,
+ 0.081299f, 0.091614f, 0.103455f, 0.116333f, 0.130493f, 0.146484f, 0.164307f, 0.183228f, 0.204224f, 0.226685f, 0.251221f, 0.277100f,
+ 0.303711f, 0.332764f, 0.361572f, 0.391846f, 0.422852f, 0.454102f, 0.485352f, 0.515625f, 0.545410f, 0.574707f, 0.603027f, 0.630371f,
+ 0.656250f, 0.681641f, 0.705078f, 0.726562f, 0.747070f, 0.767578f, 0.784668f, 0.803223f, 0.818848f, 0.833008f, 0.847656f, 0.860352f,
+ 0.872559f, 0.883301f, 0.894043f, 0.903809f, 0.913574f, 0.921387f, 0.967773f, 0.970215f, 0.970215f, 0.968750f, 0.969238f, 0.968750f,
+ 0.001053f, 0.002905f, 0.005432f, 0.007912f, 0.010658f, 0.012901f, 0.016464f, 0.019363f, 0.023376f, 0.027237f, 0.031799f, 0.036346f,
+ 0.042145f, 0.048248f, 0.054871f, 0.062256f, 0.070618f, 0.079834f, 0.089844f, 0.101440f, 0.113831f, 0.128174f, 0.143433f, 0.160156f,
+ 0.179077f, 0.199707f, 0.222046f, 0.245483f, 0.271240f, 0.297363f, 0.325684f, 0.355469f, 0.385254f, 0.416016f, 0.447754f, 0.479004f,
+ 0.508789f, 0.539551f, 0.570312f, 0.598145f, 0.626465f, 0.652344f, 0.678223f, 0.702148f, 0.725098f, 0.746094f, 0.765625f, 0.785645f,
+ 0.803223f, 0.819336f, 0.834961f, 0.848145f, 0.861328f, 0.873535f, 0.884766f, 0.895508f, 0.905762f, 0.915527f, 0.965332f, 0.967773f,
+ 0.968262f, 0.967773f, 0.967285f, 0.966309f, 0.001106f, 0.002684f, 0.004913f, 0.006733f, 0.009300f, 0.011955f, 0.014435f, 0.017700f,
+ 0.020477f, 0.024124f, 0.028091f, 0.032532f, 0.037231f, 0.042511f, 0.048309f, 0.054596f, 0.061798f, 0.069885f, 0.078857f, 0.089050f,
+ 0.099915f, 0.112183f, 0.125488f, 0.140503f, 0.157104f, 0.175293f, 0.195068f, 0.216309f, 0.240356f, 0.265381f, 0.291748f, 0.319580f,
+ 0.348633f, 0.379150f, 0.410156f, 0.441406f, 0.472900f, 0.503418f, 0.534668f, 0.565430f, 0.594727f, 0.622070f, 0.649902f, 0.676270f,
+ 0.700195f, 0.723633f, 0.746094f, 0.766602f, 0.786133f, 0.802734f, 0.819824f, 0.835449f, 0.849609f, 0.863281f, 0.875977f, 0.887695f,
+ 0.898438f, 0.908203f, 0.962891f, 0.965820f, 0.966309f, 0.965332f, 0.964844f, 0.964355f, 0.000782f, 0.002707f, 0.004574f, 0.006184f,
+ 0.008286f, 0.010681f, 0.012878f, 0.015640f, 0.018478f, 0.021912f, 0.025208f, 0.028976f, 0.032867f, 0.037598f, 0.042938f, 0.048370f,
+ 0.054443f, 0.061432f, 0.069214f, 0.077515f, 0.087402f, 0.098145f, 0.109497f, 0.122803f, 0.137329f, 0.153564f, 0.171509f, 0.190918f,
+ 0.212158f, 0.235352f, 0.259766f, 0.286133f, 0.314209f, 0.343262f, 0.373535f, 0.404297f, 0.436279f, 0.467773f, 0.499512f, 0.530273f,
+ 0.561523f, 0.590820f, 0.620117f, 0.647461f, 0.674316f, 0.699219f, 0.722656f, 0.745605f, 0.766602f, 0.785645f, 0.804688f, 0.821777f,
+ 0.836426f, 0.852051f, 0.865234f, 0.878418f, 0.890625f, 0.901855f, 0.959961f, 0.962891f, 0.963867f, 0.963379f, 0.962402f, 0.962402f,
+ 0.000787f, 0.002195f, 0.004250f, 0.005775f, 0.007774f, 0.009445f, 0.011795f, 0.013725f, 0.016678f, 0.019531f, 0.022018f, 0.025665f,
+ 0.029495f, 0.033142f, 0.037598f, 0.042664f, 0.048248f, 0.053772f, 0.060699f, 0.067993f, 0.076416f, 0.085815f, 0.095764f, 0.107422f,
+ 0.120239f, 0.134277f, 0.150269f, 0.167358f, 0.186646f, 0.207764f, 0.230347f, 0.255127f, 0.281250f, 0.308838f, 0.337891f, 0.368408f,
+ 0.399414f, 0.431396f, 0.463135f, 0.495605f, 0.526855f, 0.558594f, 0.588379f, 0.618652f, 0.646973f, 0.673828f, 0.699707f, 0.723633f,
+ 0.746094f, 0.767090f, 0.788086f, 0.806641f, 0.823730f, 0.840332f, 0.854980f, 0.869141f, 0.881836f, 0.893555f, 0.957520f, 0.960938f,
+ 0.960938f, 0.961426f, 0.960449f, 0.959961f, 0.000765f, 0.002207f, 0.003666f, 0.005177f, 0.006973f, 0.008301f, 0.010704f, 0.012794f,
+ 0.015015f, 0.017303f, 0.020309f, 0.022568f, 0.026123f, 0.029587f, 0.033325f, 0.037659f, 0.042206f, 0.047516f, 0.053223f, 0.059814f,
+ 0.067017f, 0.075195f, 0.083801f, 0.094055f, 0.105042f, 0.117737f, 0.131470f, 0.146851f, 0.163940f, 0.182739f, 0.203369f, 0.225952f,
+ 0.250244f, 0.276367f, 0.304199f, 0.333008f, 0.364258f, 0.395264f, 0.427002f, 0.459961f, 0.491699f, 0.524414f, 0.555664f, 0.586914f,
+ 0.617676f, 0.645996f, 0.673340f, 0.699707f, 0.724121f, 0.748047f, 0.770020f, 0.790039f, 0.809082f, 0.827148f, 0.842773f, 0.858398f,
+ 0.873047f, 0.885742f, 0.954102f, 0.958008f, 0.958496f, 0.958496f, 0.958496f, 0.957520f, 0.000586f, 0.001937f, 0.003107f, 0.004745f,
+ 0.006168f, 0.007610f, 0.009590f, 0.011345f, 0.013321f, 0.015587f, 0.017593f, 0.020294f, 0.023346f, 0.026154f, 0.029205f, 0.033234f,
+ 0.037415f, 0.041962f, 0.046906f, 0.052673f, 0.058533f, 0.065796f, 0.073669f, 0.082642f, 0.092346f, 0.103027f, 0.115234f, 0.128784f,
+ 0.143799f, 0.160889f, 0.179199f, 0.199585f, 0.221802f, 0.246094f, 0.271973f, 0.299805f, 0.329102f, 0.359863f, 0.391357f, 0.423340f,
+ 0.456299f, 0.490234f, 0.522949f, 0.555176f, 0.586426f, 0.617188f, 0.645996f, 0.675293f, 0.701660f, 0.726074f, 0.750488f, 0.773926f,
+ 0.793945f, 0.812988f, 0.831543f, 0.847656f, 0.862793f, 0.877441f, 0.951660f, 0.955078f, 0.955566f, 0.955566f, 0.955078f, 0.954590f,
+ 0.000678f, 0.001864f, 0.003138f, 0.004333f, 0.005707f, 0.006893f, 0.008224f, 0.009850f, 0.012215f, 0.013954f, 0.015747f, 0.018219f,
+ 0.020584f, 0.023148f, 0.026047f, 0.029434f, 0.033020f, 0.037018f, 0.041626f, 0.046509f, 0.051910f, 0.058105f, 0.064636f, 0.072510f,
+ 0.080750f, 0.090149f, 0.100891f, 0.112549f, 0.126343f, 0.141113f, 0.157593f, 0.175537f, 0.195801f, 0.218018f, 0.242554f, 0.268311f,
+ 0.295898f, 0.325195f, 0.355713f, 0.388184f, 0.421143f, 0.454834f, 0.488281f, 0.522949f, 0.554199f, 0.587402f, 0.618164f, 0.648438f,
+ 0.676758f, 0.704102f, 0.730957f, 0.754395f, 0.776855f, 0.798340f, 0.817871f, 0.836426f, 0.852051f, 0.868164f, 0.948242f, 0.952637f,
+ 0.953125f, 0.952637f, 0.952148f, 0.951660f, 0.000470f, 0.001578f, 0.002934f, 0.003838f, 0.005032f, 0.006310f, 0.007725f, 0.008972f,
+ 0.010826f, 0.012657f, 0.014359f, 0.015991f, 0.018402f, 0.020721f, 0.023102f, 0.026230f, 0.029495f, 0.032867f, 0.036743f, 0.040680f,
+ 0.045654f, 0.050812f, 0.056763f, 0.063477f, 0.071045f, 0.078918f, 0.088440f, 0.098938f, 0.110657f, 0.123535f, 0.138062f, 0.154175f,
+ 0.172363f, 0.192627f, 0.214478f, 0.238770f, 0.264404f, 0.292236f, 0.322266f, 0.353271f, 0.385742f, 0.419189f, 0.453857f, 0.487549f,
+ 0.521484f, 0.555664f, 0.588867f, 0.621094f, 0.651367f, 0.680176f, 0.708008f, 0.733887f, 0.759766f, 0.780762f, 0.802734f, 0.821289f,
+ 0.840820f, 0.858398f, 0.943848f, 0.949219f, 0.949707f, 0.949707f, 0.949707f, 0.949219f, 0.000485f, 0.001689f, 0.002386f, 0.003698f,
+ 0.004547f, 0.005936f, 0.006851f, 0.008217f, 0.009834f, 0.011055f, 0.012810f, 0.014473f, 0.016449f, 0.018509f, 0.020950f, 0.023209f,
+ 0.025940f, 0.029114f, 0.032410f, 0.036133f, 0.040161f, 0.044861f, 0.050018f, 0.055664f, 0.061859f, 0.069153f, 0.077515f, 0.086365f,
+ 0.096680f, 0.108093f, 0.120605f, 0.135132f, 0.151489f, 0.169556f, 0.189209f, 0.211426f, 0.235352f, 0.261475f, 0.289307f, 0.319580f,
+ 0.351074f, 0.384521f, 0.418701f, 0.452881f, 0.487549f, 0.522461f, 0.556641f, 0.591309f, 0.623535f, 0.653809f, 0.684570f, 0.712891f,
+ 0.739258f, 0.764160f, 0.787109f, 0.809570f, 0.829102f, 0.847168f, 0.940918f, 0.945801f, 0.946289f, 0.946777f, 0.946777f, 0.945312f,
+ 0.000620f, 0.001351f, 0.002413f, 0.003273f, 0.004307f, 0.004971f, 0.006138f, 0.007542f, 0.008835f, 0.009972f, 0.011581f, 0.013069f,
+ 0.014717f, 0.016495f, 0.018738f, 0.020691f, 0.023315f, 0.025879f, 0.028793f, 0.031860f, 0.035309f, 0.039246f, 0.043762f, 0.048950f,
+ 0.054474f, 0.060669f, 0.067932f, 0.075378f, 0.084351f, 0.094055f, 0.105774f, 0.118469f, 0.132690f, 0.148315f, 0.166504f, 0.186401f,
+ 0.208130f, 0.232544f, 0.258789f, 0.287109f, 0.317627f, 0.349854f, 0.383057f, 0.417725f, 0.453125f, 0.488770f, 0.523926f, 0.559082f,
+ 0.594238f, 0.627441f, 0.659180f, 0.689941f, 0.719238f, 0.745117f, 0.770508f, 0.794434f, 0.815430f, 0.836914f, 0.936523f, 0.941895f,
+ 0.942871f, 0.942871f, 0.942871f, 0.942383f, 0.000404f, 0.001095f, 0.002087f, 0.002983f, 0.003986f, 0.004673f, 0.005844f, 0.006878f,
+ 0.007740f, 0.008873f, 0.010323f, 0.011757f, 0.013176f, 0.014915f, 0.016586f, 0.018585f, 0.020523f, 0.022720f, 0.025391f, 0.028244f,
+ 0.031219f, 0.034821f, 0.038788f, 0.042908f, 0.047943f, 0.053040f, 0.058960f, 0.066162f, 0.073547f, 0.082397f, 0.092285f, 0.102844f,
+ 0.115234f, 0.129883f, 0.146118f, 0.163452f, 0.183350f, 0.205688f, 0.229614f, 0.256592f, 0.285156f, 0.316162f, 0.348633f, 0.383057f,
+ 0.418457f, 0.454590f, 0.490967f, 0.526855f, 0.563477f, 0.598633f, 0.632812f, 0.665527f, 0.696777f, 0.726074f, 0.752930f, 0.779297f,
+ 0.803223f, 0.825684f, 0.933105f, 0.938477f, 0.938477f, 0.938965f, 0.938477f, 0.938477f, 0.000415f, 0.000864f, 0.001907f, 0.002775f,
+ 0.003519f, 0.004204f, 0.005352f, 0.006237f, 0.007019f, 0.008064f, 0.009239f, 0.010483f, 0.011742f, 0.013130f, 0.014877f, 0.016571f,
+ 0.018494f, 0.020126f, 0.022537f, 0.024826f, 0.027649f, 0.030701f, 0.033875f, 0.037964f, 0.042114f, 0.046356f, 0.051605f, 0.057587f,
+ 0.064209f, 0.071777f, 0.080261f, 0.089722f, 0.100952f, 0.113220f, 0.127075f, 0.143066f, 0.160767f, 0.180664f, 0.202759f, 0.227417f,
+ 0.254395f, 0.284180f, 0.315674f, 0.348633f, 0.383789f, 0.420166f, 0.457275f, 0.494385f, 0.531250f, 0.569336f, 0.605469f, 0.639160f,
+ 0.672363f, 0.705078f, 0.735352f, 0.762207f, 0.788574f, 0.811523f, 0.928711f, 0.934082f, 0.934570f, 0.935059f, 0.935059f, 0.935059f,
+ 0.000236f, 0.001136f, 0.001664f, 0.002502f, 0.003187f, 0.004082f, 0.004631f, 0.005386f, 0.006275f, 0.007385f, 0.008217f, 0.009453f,
+ 0.010567f, 0.011787f, 0.013115f, 0.014420f, 0.016083f, 0.017944f, 0.019867f, 0.022079f, 0.024414f, 0.026962f, 0.029755f, 0.033112f,
+ 0.036926f, 0.040771f, 0.045258f, 0.050232f, 0.056183f, 0.062500f, 0.069946f, 0.078430f, 0.087708f, 0.098389f, 0.110779f, 0.124634f,
+ 0.140259f, 0.158203f, 0.178223f, 0.200928f, 0.225708f, 0.253174f, 0.282715f, 0.315430f, 0.349365f, 0.385254f, 0.422363f, 0.460938f,
+ 0.499023f, 0.537109f, 0.574707f, 0.612305f, 0.646484f, 0.682129f, 0.713867f, 0.745117f, 0.772461f, 0.799316f, 0.923828f, 0.930176f,
+ 0.930664f, 0.931152f, 0.930664f, 0.930664f, 0.000229f, 0.000964f, 0.001582f, 0.002182f, 0.002838f, 0.003653f, 0.004341f, 0.004921f,
+ 0.005615f, 0.006626f, 0.007423f, 0.008545f, 0.009483f, 0.010666f, 0.011612f, 0.013000f, 0.014275f, 0.015900f, 0.017487f, 0.019333f,
+ 0.021484f, 0.023773f, 0.026276f, 0.028992f, 0.032135f, 0.035492f, 0.039398f, 0.044037f, 0.049072f, 0.054443f, 0.061035f, 0.067871f,
+ 0.076111f, 0.085632f, 0.096252f, 0.108154f, 0.122253f, 0.138306f, 0.156006f, 0.175903f, 0.199219f, 0.224243f, 0.251953f, 0.282715f,
+ 0.315918f, 0.350830f, 0.387451f, 0.425781f, 0.465332f, 0.504395f, 0.544434f, 0.583008f, 0.620117f, 0.657715f, 0.692383f, 0.725098f,
+ 0.755371f, 0.783691f, 0.919434f, 0.925781f, 0.926270f, 0.926758f, 0.926758f, 0.925781f, 0.000410f, 0.000856f, 0.001542f, 0.001844f,
+ 0.002565f, 0.003380f, 0.003971f, 0.004246f, 0.005047f, 0.005863f, 0.006653f, 0.007744f, 0.008568f, 0.009407f, 0.010529f, 0.011482f,
+ 0.012657f, 0.013924f, 0.015602f, 0.017105f, 0.018997f, 0.020859f, 0.022980f, 0.025192f, 0.028030f, 0.031036f, 0.034515f, 0.038300f,
+ 0.042236f, 0.047180f, 0.052795f, 0.059113f, 0.065857f, 0.074097f, 0.083374f, 0.094360f, 0.105896f, 0.119873f, 0.135620f, 0.154175f,
+ 0.174072f, 0.197632f, 0.223267f, 0.251465f, 0.283447f, 0.317139f, 0.353760f, 0.391113f, 0.431152f, 0.470703f, 0.512207f, 0.552734f,
+ 0.592285f, 0.631348f, 0.669434f, 0.704590f, 0.737793f, 0.768555f, 0.913574f, 0.919922f, 0.920898f, 0.920898f, 0.921387f, 0.921387f,
+ 0.000214f, 0.000619f, 0.001172f, 0.001941f, 0.002228f, 0.002960f, 0.003490f, 0.003994f, 0.004761f, 0.005180f, 0.005806f, 0.006622f,
+ 0.007565f, 0.008301f, 0.009262f, 0.010170f, 0.011208f, 0.012482f, 0.013855f, 0.015060f, 0.016739f, 0.018311f, 0.020248f, 0.022034f,
+ 0.024597f, 0.027084f, 0.030045f, 0.033051f, 0.036743f, 0.041016f, 0.045807f, 0.050964f, 0.056946f, 0.063904f, 0.071899f, 0.080994f,
+ 0.091675f, 0.103699f, 0.117920f, 0.133667f, 0.151978f, 0.172729f, 0.196533f, 0.222534f, 0.252197f, 0.284424f, 0.319580f, 0.356689f,
+ 0.396973f, 0.437500f, 0.479492f, 0.521484f, 0.562500f, 0.604004f, 0.644043f, 0.682129f, 0.718262f, 0.751465f, 0.907715f, 0.915039f,
+ 0.916016f, 0.916504f, 0.916504f, 0.916504f, 0.000405f, 0.000760f, 0.001116f, 0.001688f, 0.002180f, 0.002670f, 0.003313f, 0.003569f,
+ 0.003979f, 0.004543f, 0.005466f, 0.005985f, 0.006699f, 0.007359f, 0.008102f, 0.009094f, 0.009949f, 0.011055f, 0.012047f, 0.013412f,
+ 0.014488f, 0.016068f, 0.017532f, 0.019348f, 0.021210f, 0.023834f, 0.025986f, 0.028854f, 0.031891f, 0.035339f, 0.039490f, 0.043976f,
+ 0.049347f, 0.055084f, 0.061951f, 0.069763f, 0.078918f, 0.089478f, 0.101379f, 0.115479f, 0.131592f, 0.150024f, 0.171387f, 0.195068f,
+ 0.222900f, 0.252686f, 0.286621f, 0.323242f, 0.362061f, 0.402588f, 0.445312f, 0.488770f, 0.532715f, 0.575684f, 0.618652f, 0.659180f,
+ 0.698242f, 0.734375f, 0.901367f, 0.909180f, 0.911133f, 0.910645f, 0.911133f, 0.910645f, 0.000218f, 0.000539f, 0.001187f, 0.001617f,
+ 0.001987f, 0.002316f, 0.002666f, 0.003176f, 0.003841f, 0.004425f, 0.004917f, 0.005402f, 0.005768f, 0.006462f, 0.007233f, 0.008018f,
+ 0.008575f, 0.009758f, 0.010582f, 0.011520f, 0.012756f, 0.013832f, 0.015312f, 0.016968f, 0.018509f, 0.020279f, 0.022644f, 0.024857f,
+ 0.027740f, 0.030472f, 0.033783f, 0.037567f, 0.042175f, 0.047150f, 0.052979f, 0.059601f, 0.067505f, 0.076538f, 0.087158f, 0.099243f,
+ 0.113281f, 0.129272f, 0.148315f, 0.170532f, 0.194702f, 0.223267f, 0.254639f, 0.289795f, 0.327393f, 0.368408f, 0.410889f, 0.455322f,
+ 0.499756f, 0.544434f, 0.590332f, 0.633789f, 0.676270f, 0.716309f, 0.895508f, 0.902344f, 0.903809f, 0.905762f, 0.903809f, 0.904297f,
+ 0.000184f, 0.000612f, 0.001122f, 0.001464f, 0.001848f, 0.002150f, 0.002514f, 0.002651f, 0.003391f, 0.003666f, 0.004368f, 0.004677f,
+ 0.005219f, 0.005882f, 0.006531f, 0.007019f, 0.007675f, 0.008530f, 0.009224f, 0.010269f, 0.011017f, 0.012146f, 0.013321f, 0.014626f,
+ 0.016098f, 0.017639f, 0.019440f, 0.021317f, 0.023773f, 0.026123f, 0.029144f, 0.032410f, 0.036072f, 0.040314f, 0.045013f, 0.051086f,
+ 0.057587f, 0.065308f, 0.074402f, 0.084961f, 0.097107f, 0.111267f, 0.127930f, 0.147217f, 0.169556f, 0.195312f, 0.224365f, 0.257568f,
+ 0.294189f, 0.333496f, 0.375977f, 0.420166f, 0.467041f, 0.514160f, 0.561035f, 0.607422f, 0.652344f, 0.695312f, 0.888672f, 0.896484f,
+ 0.897461f, 0.897461f, 0.897949f, 0.897949f, 0.000159f, 0.000537f, 0.000830f, 0.001206f, 0.001578f, 0.001760f, 0.002050f, 0.002504f,
+ 0.002951f, 0.003397f, 0.003674f, 0.004238f, 0.004520f, 0.005245f, 0.005692f, 0.006138f, 0.006748f, 0.007240f, 0.008087f, 0.008728f,
+ 0.009636f, 0.010437f, 0.011543f, 0.012611f, 0.013763f, 0.015266f, 0.016617f, 0.018433f, 0.020248f, 0.022354f, 0.024887f, 0.027390f,
+ 0.030716f, 0.034454f, 0.038422f, 0.043365f, 0.048950f, 0.055511f, 0.062988f, 0.072021f, 0.082336f, 0.094727f, 0.109375f, 0.125977f,
+ 0.145874f, 0.169556f, 0.195679f, 0.226929f, 0.260986f, 0.299805f, 0.341309f, 0.385498f, 0.432129f, 0.480957f, 0.529297f, 0.579102f,
+ 0.627441f, 0.673828f, 0.881348f, 0.889160f, 0.890625f, 0.891113f, 0.891602f, 0.891113f, 0.000204f, 0.000566f, 0.000741f, 0.001033f,
+ 0.001378f, 0.001599f, 0.001961f, 0.002354f, 0.002609f, 0.002974f, 0.003300f, 0.003609f, 0.004101f, 0.004463f, 0.004906f, 0.005337f,
+ 0.006020f, 0.006290f, 0.007023f, 0.007656f, 0.008301f, 0.009140f, 0.009918f, 0.010933f, 0.011940f, 0.013107f, 0.014252f, 0.015656f,
+ 0.017136f, 0.019058f, 0.021057f, 0.023209f, 0.025940f, 0.029190f, 0.032715f, 0.036591f, 0.041138f, 0.046661f, 0.053253f, 0.060944f,
+ 0.069702f, 0.080444f, 0.092651f, 0.107788f, 0.124695f, 0.145630f, 0.169189f, 0.197632f, 0.229736f, 0.266113f, 0.306396f, 0.350586f,
+ 0.397217f, 0.447021f, 0.497803f, 0.549805f, 0.600586f, 0.650391f, 0.872559f, 0.881836f, 0.882812f, 0.883301f, 0.884277f, 0.884277f,
+ 0.000240f, 0.000349f, 0.000795f, 0.000892f, 0.001151f, 0.001377f, 0.001773f, 0.001984f, 0.002415f, 0.002602f, 0.002932f, 0.003168f,
+ 0.003483f, 0.003906f, 0.004257f, 0.004681f, 0.005173f, 0.005596f, 0.006119f, 0.006550f, 0.007126f, 0.007759f, 0.008522f, 0.009270f,
+ 0.010086f, 0.011108f, 0.012138f, 0.013199f, 0.014549f, 0.015884f, 0.017776f, 0.019623f, 0.022003f, 0.024384f, 0.027237f, 0.030624f,
+ 0.034515f, 0.039215f, 0.044342f, 0.050873f, 0.058411f, 0.067017f, 0.078003f, 0.090332f, 0.105530f, 0.123718f, 0.144775f, 0.170410f,
+ 0.200195f, 0.234131f, 0.272461f, 0.315674f, 0.362305f, 0.412354f, 0.465332f, 0.518555f, 0.572754f, 0.626465f, 0.863770f, 0.873047f,
+ 0.875488f, 0.875488f, 0.875977f, 0.875977f, 0.000102f, 0.000298f, 0.000604f, 0.000950f, 0.001089f, 0.001472f, 0.001760f, 0.001823f,
+ 0.001903f, 0.002325f, 0.002611f, 0.002775f, 0.003185f, 0.003405f, 0.003674f, 0.004005f, 0.004406f, 0.004814f, 0.005203f, 0.005665f,
+ 0.006062f, 0.006702f, 0.007317f, 0.007881f, 0.008560f, 0.009239f, 0.010193f, 0.010994f, 0.012161f, 0.013588f, 0.015068f, 0.016479f,
+ 0.018250f, 0.020386f, 0.022781f, 0.025665f, 0.028809f, 0.032501f, 0.037048f, 0.042297f, 0.048553f, 0.055908f, 0.065491f, 0.075378f,
+ 0.088501f, 0.104248f, 0.122742f, 0.145874f, 0.171997f, 0.203247f, 0.239990f, 0.281250f, 0.326904f, 0.376953f, 0.430176f, 0.486328f,
+ 0.542480f, 0.600586f, 0.855469f, 0.864746f, 0.866211f, 0.867188f, 0.867188f, 0.867188f, 0.000000f, 0.000357f, 0.000576f, 0.000692f,
+ 0.001013f, 0.001069f, 0.001383f, 0.001702f, 0.001789f, 0.002102f, 0.002182f, 0.002377f, 0.002686f, 0.002985f, 0.003347f, 0.003359f,
+ 0.003782f, 0.004036f, 0.004436f, 0.004749f, 0.005169f, 0.005672f, 0.006145f, 0.006649f, 0.007187f, 0.007828f, 0.008644f, 0.009529f,
+ 0.010269f, 0.011200f, 0.012337f, 0.013596f, 0.015038f, 0.017044f, 0.018784f, 0.021011f, 0.023727f, 0.026871f, 0.030457f, 0.034637f,
+ 0.039978f, 0.046478f, 0.053436f, 0.062622f, 0.073730f, 0.086792f, 0.102661f, 0.122437f, 0.146240f, 0.174561f, 0.208252f, 0.247437f,
+ 0.291748f, 0.341064f, 0.395020f, 0.451904f, 0.511230f, 0.571777f, 0.844238f, 0.854980f, 0.857422f, 0.858887f, 0.857910f, 0.857910f,
+ 0.000101f, 0.000326f, 0.000535f, 0.000683f, 0.000848f, 0.001161f, 0.001184f, 0.001284f, 0.001576f, 0.001701f, 0.001839f, 0.002167f,
+ 0.002321f, 0.002584f, 0.002645f, 0.002941f, 0.003141f, 0.003538f, 0.003817f, 0.004112f, 0.004395f, 0.004646f, 0.005165f, 0.005531f,
+ 0.006096f, 0.006496f, 0.007217f, 0.007767f, 0.008629f, 0.009163f, 0.010239f, 0.011276f, 0.012611f, 0.013779f, 0.015213f, 0.017120f,
+ 0.019379f, 0.021606f, 0.024994f, 0.028351f, 0.032379f, 0.037201f, 0.043640f, 0.050903f, 0.060120f, 0.071045f, 0.084900f, 0.101868f,
+ 0.122559f, 0.147827f, 0.178223f, 0.214722f, 0.257080f, 0.305664f, 0.358887f, 0.416992f, 0.478027f, 0.542969f, 0.834473f, 0.845215f,
+ 0.847656f, 0.847656f, 0.847656f, 0.848633f, 0.000092f, 0.000316f, 0.000410f, 0.000556f, 0.000808f, 0.000918f, 0.001094f, 0.001287f,
+ 0.001309f, 0.001411f, 0.001671f, 0.001780f, 0.001909f, 0.002092f, 0.002274f, 0.002523f, 0.002733f, 0.002974f, 0.003101f, 0.003401f,
+ 0.003677f, 0.003956f, 0.004311f, 0.004551f, 0.004940f, 0.005444f, 0.005768f, 0.006451f, 0.006977f, 0.007568f, 0.008270f, 0.009201f,
+ 0.010170f, 0.011230f, 0.012566f, 0.013939f, 0.015503f, 0.017761f, 0.020111f, 0.022873f, 0.025940f, 0.029938f, 0.035217f, 0.040985f,
+ 0.048431f, 0.057770f, 0.069092f, 0.083618f, 0.100891f, 0.123047f, 0.150146f, 0.183838f, 0.223633f, 0.269531f, 0.322510f, 0.381348f,
+ 0.444824f, 0.511719f, 0.823730f, 0.834473f, 0.835938f, 0.836914f, 0.836914f, 0.837402f, 0.000240f, 0.000273f, 0.000326f, 0.000564f,
+ 0.000682f, 0.000807f, 0.000854f, 0.000949f, 0.001139f, 0.001238f, 0.001404f, 0.001548f, 0.001637f, 0.001840f, 0.001893f, 0.002077f,
+ 0.002321f, 0.002434f, 0.002642f, 0.002821f, 0.003044f, 0.003271f, 0.003649f, 0.003763f, 0.004208f, 0.004448f, 0.004986f, 0.005169f,
+ 0.005657f, 0.006279f, 0.006680f, 0.007442f, 0.008194f, 0.008881f, 0.009895f, 0.010918f, 0.012138f, 0.013924f, 0.015915f, 0.018112f,
+ 0.020645f, 0.023743f, 0.027817f, 0.032745f, 0.038361f, 0.045990f, 0.055481f, 0.066895f, 0.082031f, 0.100769f, 0.124573f, 0.154541f,
+ 0.190796f, 0.235107f, 0.286133f, 0.344238f, 0.408936f, 0.478271f, 0.810547f, 0.822266f, 0.824707f, 0.825195f, 0.825684f, 0.825684f,
+ 0.000115f, 0.000222f, 0.000252f, 0.000524f, 0.000574f, 0.000673f, 0.000869f, 0.000928f, 0.000963f, 0.001022f, 0.001246f, 0.001292f,
+ 0.001404f, 0.001477f, 0.001652f, 0.001811f, 0.001822f, 0.002058f, 0.002237f, 0.002371f, 0.002588f, 0.002645f, 0.003019f, 0.003080f,
+ 0.003506f, 0.003689f, 0.003904f, 0.004383f, 0.004707f, 0.005020f, 0.005386f, 0.006023f, 0.006451f, 0.007038f, 0.007809f, 0.008911f,
+ 0.009949f, 0.011200f, 0.012222f, 0.014137f, 0.016068f, 0.018692f, 0.021683f, 0.025314f, 0.029861f, 0.035889f, 0.043335f, 0.052582f,
+ 0.065186f, 0.080627f, 0.101501f, 0.127441f, 0.159912f, 0.200806f, 0.250000f, 0.307129f, 0.371582f, 0.444580f, 0.798340f, 0.809570f,
+ 0.811523f, 0.812988f, 0.812988f, 0.812988f, 0.000000f, 0.000211f, 0.000204f, 0.000474f, 0.000555f, 0.000583f, 0.000600f, 0.000593f,
+ 0.000812f, 0.000865f, 0.000941f, 0.001013f, 0.001162f, 0.001348f, 0.001418f, 0.001465f, 0.001616f, 0.001722f, 0.001856f, 0.001888f,
+ 0.002048f, 0.002321f, 0.002396f, 0.002632f, 0.002821f, 0.002974f, 0.003265f, 0.003477f, 0.003632f, 0.004051f, 0.004299f, 0.004700f,
+ 0.005238f, 0.005592f, 0.006199f, 0.006756f, 0.007614f, 0.008324f, 0.009727f, 0.010811f, 0.012337f, 0.014168f, 0.016434f, 0.019257f,
+ 0.022858f, 0.027451f, 0.033295f, 0.040619f, 0.050690f, 0.063416f, 0.080261f, 0.102295f, 0.131104f, 0.168335f, 0.214355f, 0.270508f,
+ 0.334717f, 0.408936f, 0.783691f, 0.795898f, 0.798340f, 0.799316f, 0.800293f, 0.800293f, 0.000174f, 0.000090f, 0.000281f, 0.000397f,
+ 0.000401f, 0.000450f, 0.000488f, 0.000640f, 0.000674f, 0.000713f, 0.000753f, 0.000845f, 0.000872f, 0.001020f, 0.001115f, 0.001264f,
+ 0.001327f, 0.001373f, 0.001520f, 0.001616f, 0.001767f, 0.001875f, 0.001968f, 0.002090f, 0.002232f, 0.002333f, 0.002472f, 0.002802f,
+ 0.002926f, 0.003189f, 0.003569f, 0.003752f, 0.004009f, 0.004513f, 0.004860f, 0.005375f, 0.005997f, 0.006561f, 0.007378f, 0.008347f,
+ 0.009384f, 0.010612f, 0.012466f, 0.014526f, 0.017075f, 0.020447f, 0.024887f, 0.030533f, 0.038300f, 0.048584f, 0.062042f, 0.080383f,
+ 0.104736f, 0.137329f, 0.180176f, 0.232544f, 0.296875f, 0.371338f, 0.769043f, 0.781250f, 0.784180f, 0.784668f, 0.786133f, 0.786133f,
+ 0.000025f, 0.000135f, 0.000154f, 0.000260f, 0.000353f, 0.000364f, 0.000380f, 0.000520f, 0.000548f, 0.000587f, 0.000712f, 0.000735f,
+ 0.000772f, 0.000822f, 0.000886f, 0.001004f, 0.000946f, 0.001115f, 0.001177f, 0.001266f, 0.001454f, 0.001527f, 0.001575f, 0.001680f,
+ 0.001883f, 0.001961f, 0.002043f, 0.002193f, 0.002281f, 0.002520f, 0.002712f, 0.003021f, 0.003147f, 0.003561f, 0.003786f, 0.004116f,
+ 0.004570f, 0.005058f, 0.005634f, 0.006165f, 0.007095f, 0.008049f, 0.009201f, 0.010674f, 0.012550f, 0.014854f, 0.018051f, 0.022385f,
+ 0.027908f, 0.035522f, 0.046295f, 0.061035f, 0.081238f, 0.109131f, 0.146729f, 0.197021f, 0.258301f, 0.333008f, 0.752441f, 0.766113f,
+ 0.768555f, 0.769531f, 0.770020f, 0.769531f, 0.000000f, 0.000121f, 0.000209f, 0.000291f, 0.000337f, 0.000307f, 0.000324f, 0.000415f,
+ 0.000426f, 0.000453f, 0.000491f, 0.000573f, 0.000644f, 0.000650f, 0.000781f, 0.000746f, 0.000830f, 0.000803f, 0.000997f, 0.001017f,
+ 0.001020f, 0.001158f, 0.001241f, 0.001317f, 0.001375f, 0.001432f, 0.001524f, 0.001656f, 0.001858f, 0.001955f, 0.002050f, 0.002274f,
+ 0.002460f, 0.002724f, 0.002831f, 0.003050f, 0.003441f, 0.003790f, 0.004162f, 0.004623f, 0.005219f, 0.005951f, 0.006721f, 0.007729f,
+ 0.008926f, 0.010620f, 0.013000f, 0.015686f, 0.019852f, 0.025436f, 0.033295f, 0.044617f, 0.060608f, 0.083313f, 0.116211f, 0.161499f,
+ 0.220093f, 0.293945f, 0.734863f, 0.749512f, 0.752441f, 0.752930f, 0.753906f, 0.753906f, 0.000000f, 0.000121f, 0.000118f, 0.000246f,
+ 0.000233f, 0.000252f, 0.000338f, 0.000282f, 0.000353f, 0.000355f, 0.000448f, 0.000435f, 0.000464f, 0.000530f, 0.000578f, 0.000649f,
+ 0.000677f, 0.000710f, 0.000749f, 0.000792f, 0.000881f, 0.000903f, 0.000967f, 0.001049f, 0.001041f, 0.001100f, 0.001176f, 0.001254f,
+ 0.001402f, 0.001451f, 0.001697f, 0.001674f, 0.001804f, 0.001914f, 0.002195f, 0.002451f, 0.002474f, 0.002758f, 0.003029f, 0.003483f,
+ 0.003824f, 0.004272f, 0.004833f, 0.005573f, 0.006477f, 0.007629f, 0.009041f, 0.010918f, 0.013573f, 0.017319f, 0.022842f, 0.031036f,
+ 0.043030f, 0.061096f, 0.088440f, 0.127563f, 0.182861f, 0.254395f, 0.717285f, 0.731934f, 0.734863f, 0.735352f, 0.735840f, 0.736328f,
+ 0.000000f, 0.000000f, 0.000117f, 0.000163f, 0.000109f, 0.000208f, 0.000212f, 0.000208f, 0.000270f, 0.000356f, 0.000324f, 0.000377f,
+ 0.000391f, 0.000420f, 0.000449f, 0.000440f, 0.000484f, 0.000504f, 0.000534f, 0.000561f, 0.000639f, 0.000667f, 0.000715f, 0.000722f,
+ 0.000799f, 0.000845f, 0.000939f, 0.000945f, 0.001053f, 0.001149f, 0.001252f, 0.001310f, 0.001392f, 0.001507f, 0.001526f, 0.001710f,
+ 0.001773f, 0.002111f, 0.002300f, 0.002443f, 0.002661f, 0.002996f, 0.003376f, 0.003880f, 0.004482f, 0.005150f, 0.006115f, 0.007401f,
+ 0.009132f, 0.011696f, 0.015076f, 0.020416f, 0.029236f, 0.042389f, 0.063782f, 0.096802f, 0.146362f, 0.215576f, 0.698242f, 0.712891f,
+ 0.715332f, 0.716797f, 0.717285f, 0.717285f, 0.000000f, 0.000118f, 0.000115f, 0.000133f, 0.000144f, 0.000147f, 0.000162f, 0.000150f,
+ 0.000194f, 0.000215f, 0.000228f, 0.000299f, 0.000271f, 0.000313f, 0.000328f, 0.000358f, 0.000378f, 0.000360f, 0.000407f, 0.000438f,
+ 0.000441f, 0.000488f, 0.000515f, 0.000544f, 0.000576f, 0.000617f, 0.000659f, 0.000715f, 0.000741f, 0.000773f, 0.000850f, 0.000921f,
+ 0.000979f, 0.001066f, 0.001128f, 0.001292f, 0.001279f, 0.001400f, 0.001572f, 0.001668f, 0.001869f, 0.002029f, 0.002295f, 0.002607f,
+ 0.002985f, 0.003464f, 0.004066f, 0.004913f, 0.006023f, 0.007519f, 0.009827f, 0.013016f, 0.018524f, 0.027481f, 0.042847f, 0.068970f,
+ 0.111938f, 0.176392f, 0.675781f, 0.692871f, 0.695801f, 0.696777f, 0.698242f, 0.697754f, 0.000000f, 0.000000f, 0.000111f, 0.000108f,
+ 0.000104f, 0.000102f, 0.000118f, 0.000120f, 0.000134f, 0.000128f, 0.000188f, 0.000154f, 0.000197f, 0.000188f, 0.000245f, 0.000256f,
+ 0.000233f, 0.000266f, 0.000345f, 0.000281f, 0.000355f, 0.000322f, 0.000392f, 0.000358f, 0.000437f, 0.000425f, 0.000458f, 0.000477f,
+ 0.000564f, 0.000636f, 0.000578f, 0.000607f, 0.000668f, 0.000719f, 0.000769f, 0.000832f, 0.000880f, 0.000953f, 0.001060f, 0.001116f,
+ 0.001226f, 0.001363f, 0.001486f, 0.001760f, 0.001944f, 0.002216f, 0.002605f, 0.003107f, 0.003778f, 0.004715f, 0.005989f, 0.007942f,
+ 0.011292f, 0.016632f, 0.026550f, 0.045532f, 0.079956f, 0.138550f, 0.655762f, 0.671875f, 0.674805f, 0.675293f, 0.675781f, 0.678223f,
+ 0.000000f, 0.000112f, 0.000105f, 0.000102f, 0.000098f, 0.000095f, 0.000093f, 0.000088f, 0.000089f, 0.000085f, 0.000095f, 0.000126f,
+ 0.000109f, 0.000154f, 0.000153f, 0.000162f, 0.000176f, 0.000190f, 0.000202f, 0.000204f, 0.000212f, 0.000214f, 0.000266f, 0.000239f,
+ 0.000279f, 0.000293f, 0.000329f, 0.000329f, 0.000339f, 0.000365f, 0.000437f, 0.000424f, 0.000429f, 0.000474f, 0.000525f, 0.000596f,
+ 0.000572f, 0.000612f, 0.000666f, 0.000723f, 0.000791f, 0.000850f, 0.000977f, 0.001066f, 0.001225f, 0.001351f, 0.001555f, 0.001837f,
+ 0.002279f, 0.002760f, 0.003445f, 0.004612f, 0.006386f, 0.009438f, 0.015221f, 0.027008f, 0.052551f, 0.102966f, 0.633789f, 0.649414f,
+ 0.652832f, 0.653809f, 0.655273f, 0.655273f, 0.000000f, 0.000105f, 0.000099f, 0.000094f, 0.000090f, 0.000087f, 0.000084f, 0.000082f,
+ 0.000079f, 0.000075f, 0.000071f, 0.000068f, 0.000064f, 0.000072f, 0.000096f, 0.000105f, 0.000112f, 0.000088f, 0.000123f, 0.000129f,
+ 0.000132f, 0.000140f, 0.000147f, 0.000170f, 0.000188f, 0.000192f, 0.000171f, 0.000210f, 0.000217f, 0.000223f, 0.000237f, 0.000251f,
+ 0.000258f, 0.000294f, 0.000298f, 0.000316f, 0.000350f, 0.000382f, 0.000400f, 0.000437f, 0.000479f, 0.000514f, 0.000576f, 0.000620f,
+ 0.000688f, 0.000782f, 0.000916f, 0.001026f, 0.001219f, 0.001502f, 0.001892f, 0.002424f, 0.003359f, 0.004974f, 0.008118f, 0.014343f,
+ 0.030075f, 0.070068f, 0.610352f, 0.626953f, 0.629883f, 0.631348f, 0.632324f, 0.632324f, 0.000110f, 0.000094f, 0.000087f, 0.000081f,
+ 0.000077f, 0.000075f, 0.000072f, 0.000069f, 0.000067f, 0.000066f, 0.000064f, 0.000062f, 0.000058f, 0.000056f, 0.000053f, 0.000051f,
+ 0.000054f, 0.000047f, 0.000057f, 0.000055f, 0.000075f, 0.000078f, 0.000086f, 0.000093f, 0.000093f, 0.000102f, 0.000112f, 0.000113f,
+ 0.000130f, 0.000128f, 0.000142f, 0.000145f, 0.000156f, 0.000153f, 0.000180f, 0.000178f, 0.000183f, 0.000223f, 0.000230f, 0.000240f,
+ 0.000265f, 0.000276f, 0.000300f, 0.000332f, 0.000357f, 0.000411f, 0.000449f, 0.000540f, 0.000615f, 0.000741f, 0.000916f, 0.001144f,
+ 0.001566f, 0.002310f, 0.003731f, 0.006905f, 0.014793f, 0.041779f, 0.585938f, 0.603027f, 0.605957f, 0.608398f, 0.608398f, 0.609375f,
+ 0.000090f, 0.000071f, 0.000066f, 0.000062f, 0.000058f, 0.000056f, 0.000053f, 0.000053f, 0.000051f, 0.000051f, 0.000049f, 0.000048f,
+ 0.000048f, 0.000047f, 0.000045f, 0.000043f, 0.000042f, 0.000040f, 0.000038f, 0.000036f, 0.000036f, 0.000033f, 0.000034f, 0.000040f,
+ 0.000040f, 0.000040f, 0.000048f, 0.000053f, 0.000060f, 0.000064f, 0.000067f, 0.000070f, 0.000075f, 0.000081f, 0.000085f, 0.000090f,
+ 0.000091f, 0.000103f, 0.000106f, 0.000120f, 0.000134f, 0.000138f, 0.000142f, 0.000156f, 0.000174f, 0.000180f, 0.000212f, 0.000239f,
+ 0.000253f, 0.000310f, 0.000377f, 0.000479f, 0.000627f, 0.000875f, 0.001396f, 0.002623f, 0.006184f, 0.019897f, 0.560547f, 0.578125f,
+ 0.581543f, 0.583008f, 0.583984f, 0.583984f, 0.000038f, 0.000035f, 0.000031f, 0.000031f, 0.000030f, 0.000031f, 0.000031f, 0.000030f,
+ 0.000030f, 0.000028f, 0.000029f, 0.000030f, 0.000029f, 0.000028f, 0.000029f, 0.000029f, 0.000029f, 0.000029f, 0.000029f, 0.000028f,
+ 0.000027f, 0.000026f, 0.000025f, 0.000024f, 0.000023f, 0.000022f, 0.000021f, 0.000020f, 0.000019f, 0.000021f, 0.000019f, 0.000022f,
+ 0.000023f, 0.000027f, 0.000031f, 0.000035f, 0.000037f, 0.000039f, 0.000039f, 0.000043f, 0.000049f, 0.000052f, 0.000056f, 0.000050f,
+ 0.000068f, 0.000062f, 0.000070f, 0.000087f, 0.000094f, 0.000107f, 0.000122f, 0.000140f, 0.000191f, 0.000247f, 0.000388f, 0.000710f,
+ 0.001781f, 0.007076f, 0.535156f, 0.553223f, 0.556152f, 0.558105f, 0.559082f, 0.559082f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000003f, 0.000003f, 0.000005f, 0.000006f, 0.000007f, 0.000007f, 0.000009f,
+ 0.000009f, 0.000009f, 0.000010f, 0.000010f, 0.000011f, 0.000011f, 0.000012f, 0.000012f, 0.000012f, 0.000013f, 0.000013f, 0.000013f,
+ 0.000013f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000009f,
+ 0.000009f, 0.000010f, 0.000011f, 0.000015f, 0.000017f, 0.000016f, 0.000018f, 0.000021f, 0.000020f, 0.000024f, 0.000024f, 0.000032f,
+ 0.000035f, 0.000045f, 0.000065f, 0.000105f, 0.000246f, 0.001313f, 0.508789f, 0.527344f, 0.530762f, 0.531738f, 0.532715f, 0.533691f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000005f, 0.000018f, 0.481934f, 0.500977f,
+ 0.504883f, 0.505859f, 0.507324f, 0.507812f,
+ },
+ {
+ 0.053833f, 0.152832f, 0.239014f, 0.313477f, 0.377686f, 0.433838f, 0.481689f, 0.524414f, 0.562988f, 0.596680f, 0.626953f, 0.654785f,
+ 0.678711f, 0.700684f, 0.720703f, 0.739746f, 0.755859f, 0.771973f, 0.787109f, 0.798828f, 0.812012f, 0.823730f, 0.833984f, 0.844238f,
+ 0.853027f, 0.862793f, 0.870605f, 0.878418f, 0.885254f, 0.892090f, 0.898926f, 0.904297f, 0.910645f, 0.916504f, 0.921875f, 0.926270f,
+ 0.931641f, 0.936035f, 0.939941f, 0.944336f, 0.948242f, 0.952148f, 0.955566f, 0.959961f, 0.962402f, 0.966309f, 0.969238f, 0.972168f,
+ 0.975098f, 0.978027f, 0.980957f, 0.983398f, 0.985840f, 0.988281f, 0.990723f, 0.992676f, 0.995117f, 0.996582f, 0.998047f, 0.995117f,
+ 0.993164f, 0.990723f, 0.988770f, 0.986816f, 0.036804f, 0.109497f, 0.178589f, 0.244751f, 0.305908f, 0.361084f, 0.411621f, 0.457275f,
+ 0.498535f, 0.536133f, 0.569824f, 0.601562f, 0.629883f, 0.655273f, 0.679688f, 0.700195f, 0.720215f, 0.737793f, 0.755859f, 0.770508f,
+ 0.785645f, 0.798340f, 0.811035f, 0.822754f, 0.833008f, 0.843750f, 0.852539f, 0.861328f, 0.869629f, 0.877441f, 0.885742f, 0.892578f,
+ 0.898926f, 0.905273f, 0.911133f, 0.916504f, 0.921875f, 0.926758f, 0.931641f, 0.936523f, 0.940430f, 0.945312f, 0.949219f, 0.953613f,
+ 0.956543f, 0.960449f, 0.963867f, 0.967285f, 0.970703f, 0.973633f, 0.976562f, 0.979004f, 0.981934f, 0.984375f, 0.986816f, 0.989746f,
+ 0.992188f, 0.994141f, 0.996582f, 0.994141f, 0.992188f, 0.990234f, 0.988281f, 0.986328f, 0.025787f, 0.080383f, 0.136230f, 0.191650f,
+ 0.245239f, 0.297119f, 0.345947f, 0.392822f, 0.436035f, 0.476807f, 0.513184f, 0.547363f, 0.578125f, 0.607910f, 0.634766f, 0.658203f,
+ 0.681152f, 0.702637f, 0.721191f, 0.738770f, 0.755371f, 0.770508f, 0.784668f, 0.798828f, 0.810547f, 0.821777f, 0.833984f, 0.843262f,
+ 0.852539f, 0.861816f, 0.869629f, 0.877930f, 0.885254f, 0.893555f, 0.898926f, 0.906250f, 0.911621f, 0.917969f, 0.923340f, 0.928223f,
+ 0.933105f, 0.937500f, 0.941406f, 0.946289f, 0.950195f, 0.954102f, 0.958496f, 0.961914f, 0.965820f, 0.968750f, 0.971680f, 0.975098f,
+ 0.978027f, 0.980469f, 0.983887f, 0.985840f, 0.988770f, 0.991211f, 0.995117f, 0.993164f, 0.991211f, 0.989258f, 0.987305f, 0.985352f,
+ 0.019455f, 0.060944f, 0.104553f, 0.150513f, 0.196411f, 0.243164f, 0.289062f, 0.333740f, 0.376709f, 0.417725f, 0.454346f, 0.491211f,
+ 0.524414f, 0.556641f, 0.585938f, 0.613770f, 0.639160f, 0.662598f, 0.682617f, 0.703613f, 0.723633f, 0.740723f, 0.756836f, 0.771973f,
+ 0.787109f, 0.798828f, 0.812012f, 0.823242f, 0.833984f, 0.844238f, 0.853516f, 0.863281f, 0.871094f, 0.879395f, 0.886719f, 0.893555f,
+ 0.899902f, 0.907227f, 0.913086f, 0.918945f, 0.924805f, 0.928711f, 0.934082f, 0.938965f, 0.943848f, 0.947754f, 0.952637f, 0.955566f,
+ 0.959961f, 0.963867f, 0.966797f, 0.970215f, 0.973633f, 0.977051f, 0.979004f, 0.982422f, 0.985840f, 0.987793f, 0.993652f, 0.991699f,
+ 0.989746f, 0.988281f, 0.986328f, 0.984375f, 0.015221f, 0.047363f, 0.082092f, 0.119202f, 0.159058f, 0.199219f, 0.239380f, 0.280762f,
+ 0.321533f, 0.362061f, 0.400146f, 0.436768f, 0.472900f, 0.504883f, 0.536621f, 0.566406f, 0.594238f, 0.621094f, 0.645508f, 0.667969f,
+ 0.688477f, 0.707520f, 0.726562f, 0.742676f, 0.759277f, 0.773926f, 0.787598f, 0.800781f, 0.812988f, 0.825195f, 0.835938f, 0.846191f,
+ 0.856445f, 0.865234f, 0.872559f, 0.880859f, 0.888672f, 0.895020f, 0.902832f, 0.908203f, 0.914551f, 0.919922f, 0.926758f, 0.931152f,
+ 0.937012f, 0.941406f, 0.945312f, 0.949707f, 0.954102f, 0.958496f, 0.962402f, 0.965820f, 0.969238f, 0.972168f, 0.976074f, 0.978516f,
+ 0.981934f, 0.984863f, 0.992188f, 0.990723f, 0.988770f, 0.987305f, 0.985352f, 0.983887f, 0.011658f, 0.037170f, 0.065430f, 0.096008f,
+ 0.128784f, 0.162842f, 0.198975f, 0.235596f, 0.273926f, 0.310791f, 0.348145f, 0.385010f, 0.420410f, 0.454834f, 0.488037f, 0.519043f,
+ 0.548828f, 0.577148f, 0.603516f, 0.627441f, 0.650879f, 0.672363f, 0.693848f, 0.712402f, 0.729980f, 0.748535f, 0.762207f, 0.778809f,
+ 0.791504f, 0.804199f, 0.815918f, 0.827637f, 0.838867f, 0.848145f, 0.857910f, 0.866211f, 0.875977f, 0.883301f, 0.891602f, 0.898438f,
+ 0.905273f, 0.911133f, 0.917480f, 0.923340f, 0.928711f, 0.933594f, 0.938477f, 0.942871f, 0.948242f, 0.952637f, 0.956543f, 0.960449f,
+ 0.964355f, 0.968262f, 0.971191f, 0.974609f, 0.978027f, 0.980957f, 0.990723f, 0.989258f, 0.987793f, 0.985840f, 0.984375f, 0.983398f,
+ 0.009758f, 0.030121f, 0.052490f, 0.077576f, 0.104309f, 0.134277f, 0.164917f, 0.197510f, 0.231812f, 0.266113f, 0.301025f, 0.336426f,
+ 0.372070f, 0.405762f, 0.438721f, 0.471436f, 0.502441f, 0.531738f, 0.560059f, 0.587402f, 0.612793f, 0.634766f, 0.658691f, 0.679199f,
+ 0.699219f, 0.718262f, 0.735352f, 0.751953f, 0.767090f, 0.780762f, 0.794922f, 0.808105f, 0.820801f, 0.831055f, 0.842285f, 0.851562f,
+ 0.861328f, 0.870117f, 0.878906f, 0.886719f, 0.893555f, 0.900879f, 0.907715f, 0.913574f, 0.919434f, 0.926270f, 0.932129f, 0.936523f,
+ 0.941895f, 0.945801f, 0.951172f, 0.955078f, 0.959473f, 0.963867f, 0.966797f, 0.970703f, 0.974121f, 0.977539f, 0.989746f, 0.988281f,
+ 0.986328f, 0.984863f, 0.983398f, 0.982422f, 0.007744f, 0.024567f, 0.043365f, 0.063782f, 0.086487f, 0.111389f, 0.137451f, 0.166260f,
+ 0.195435f, 0.226929f, 0.259033f, 0.291748f, 0.324951f, 0.358398f, 0.391113f, 0.424316f, 0.456299f, 0.486328f, 0.516113f, 0.543945f,
+ 0.571289f, 0.597656f, 0.621094f, 0.644531f, 0.666504f, 0.686523f, 0.705078f, 0.724121f, 0.741211f, 0.757324f, 0.773438f, 0.786621f,
+ 0.801270f, 0.812988f, 0.823730f, 0.835938f, 0.846191f, 0.855957f, 0.865723f, 0.873047f, 0.882324f, 0.889648f, 0.897949f, 0.905762f,
+ 0.911133f, 0.917969f, 0.923828f, 0.929199f, 0.934082f, 0.940430f, 0.944824f, 0.949707f, 0.954102f, 0.958008f, 0.962891f, 0.966309f,
+ 0.970215f, 0.974121f, 0.987793f, 0.986816f, 0.985352f, 0.983887f, 0.981934f, 0.980469f, 0.006672f, 0.020828f, 0.035950f, 0.053345f,
+ 0.071594f, 0.092834f, 0.114624f, 0.139282f, 0.165649f, 0.192627f, 0.222290f, 0.252197f, 0.283203f, 0.314941f, 0.346680f, 0.377930f,
+ 0.409668f, 0.441650f, 0.471680f, 0.500977f, 0.529297f, 0.557129f, 0.583008f, 0.607422f, 0.630859f, 0.654297f, 0.674805f, 0.694824f,
+ 0.713867f, 0.731445f, 0.748535f, 0.763672f, 0.778320f, 0.791992f, 0.805664f, 0.817871f, 0.829590f, 0.840332f, 0.850098f, 0.860352f,
+ 0.869141f, 0.878906f, 0.886719f, 0.894043f, 0.901855f, 0.909180f, 0.915527f, 0.920898f, 0.927246f, 0.933105f, 0.938477f, 0.943848f,
+ 0.948730f, 0.953125f, 0.957520f, 0.961914f, 0.965820f, 0.970215f, 0.985840f, 0.985352f, 0.983887f, 0.981934f, 0.980957f, 0.979492f,
+ 0.005592f, 0.017181f, 0.030457f, 0.044739f, 0.060638f, 0.077454f, 0.097046f, 0.117981f, 0.140625f, 0.164673f, 0.190552f, 0.217896f,
+ 0.246582f, 0.275635f, 0.305176f, 0.336426f, 0.366943f, 0.397949f, 0.428711f, 0.457764f, 0.487061f, 0.515137f, 0.542480f, 0.568848f,
+ 0.593750f, 0.619141f, 0.641602f, 0.662598f, 0.683594f, 0.703613f, 0.721191f, 0.738281f, 0.755859f, 0.770996f, 0.784180f, 0.799316f,
+ 0.811035f, 0.823730f, 0.833984f, 0.845703f, 0.855957f, 0.865234f, 0.875000f, 0.883301f, 0.891602f, 0.898926f, 0.906738f, 0.912598f,
+ 0.919922f, 0.926270f, 0.931152f, 0.937988f, 0.942871f, 0.948242f, 0.952148f, 0.957520f, 0.961914f, 0.966309f, 0.984375f, 0.983398f,
+ 0.982422f, 0.981445f, 0.979492f, 0.978027f, 0.004829f, 0.014816f, 0.025711f, 0.037964f, 0.051300f, 0.065796f, 0.082458f, 0.100037f,
+ 0.120178f, 0.141357f, 0.163330f, 0.187622f, 0.213013f, 0.240601f, 0.268311f, 0.296387f, 0.325928f, 0.356445f, 0.385742f, 0.415771f,
+ 0.445557f, 0.474121f, 0.501465f, 0.530762f, 0.556152f, 0.581543f, 0.606445f, 0.630859f, 0.651855f, 0.672852f, 0.693359f, 0.712402f,
+ 0.730469f, 0.746582f, 0.762695f, 0.777832f, 0.791992f, 0.806152f, 0.818359f, 0.830566f, 0.840820f, 0.852051f, 0.862305f, 0.871094f,
+ 0.880371f, 0.888184f, 0.896484f, 0.904297f, 0.910645f, 0.917969f, 0.924316f, 0.931152f, 0.936035f, 0.942383f, 0.947266f, 0.951660f,
+ 0.957031f, 0.960938f, 0.982422f, 0.982422f, 0.981445f, 0.979492f, 0.978516f, 0.977051f, 0.004040f, 0.012436f, 0.022064f, 0.032440f,
+ 0.044006f, 0.056549f, 0.070068f, 0.085999f, 0.102539f, 0.120239f, 0.140625f, 0.161621f, 0.184448f, 0.208496f, 0.234253f, 0.260742f,
+ 0.288086f, 0.316406f, 0.345215f, 0.374512f, 0.404297f, 0.433350f, 0.462402f, 0.490234f, 0.518066f, 0.543945f, 0.570312f, 0.594727f,
+ 0.618652f, 0.642090f, 0.663086f, 0.683594f, 0.703613f, 0.721680f, 0.739258f, 0.755859f, 0.772461f, 0.786621f, 0.798828f, 0.812500f,
+ 0.825195f, 0.836914f, 0.848633f, 0.858887f, 0.869141f, 0.877441f, 0.886230f, 0.894531f, 0.902832f, 0.909668f, 0.916992f, 0.923340f,
+ 0.929688f, 0.935547f, 0.941406f, 0.947266f, 0.951660f, 0.957031f, 0.980469f, 0.980469f, 0.979492f, 0.978516f, 0.977051f, 0.976074f,
+ 0.003536f, 0.010872f, 0.018829f, 0.027893f, 0.037872f, 0.048492f, 0.060883f, 0.073425f, 0.088074f, 0.103638f, 0.120789f, 0.139038f,
+ 0.159912f, 0.181274f, 0.204102f, 0.227905f, 0.253906f, 0.280518f, 0.307861f, 0.335938f, 0.364746f, 0.393311f, 0.421631f, 0.451416f,
+ 0.479004f, 0.505859f, 0.533203f, 0.560059f, 0.584473f, 0.608398f, 0.631836f, 0.653320f, 0.674805f, 0.695801f, 0.714355f, 0.731934f,
+ 0.749512f, 0.765137f, 0.781250f, 0.794434f, 0.808594f, 0.821289f, 0.833496f, 0.844238f, 0.855469f, 0.866211f, 0.875000f, 0.883789f,
+ 0.892578f, 0.901855f, 0.908691f, 0.915527f, 0.922852f, 0.929199f, 0.935059f, 0.941406f, 0.947266f, 0.951172f, 0.978516f, 0.979004f,
+ 0.978027f, 0.977051f, 0.975586f, 0.974121f, 0.002989f, 0.009476f, 0.016785f, 0.024246f, 0.032745f, 0.041809f, 0.052246f, 0.063782f,
+ 0.076111f, 0.089722f, 0.104675f, 0.120605f, 0.138306f, 0.157959f, 0.178101f, 0.200073f, 0.223145f, 0.247192f, 0.273193f, 0.300293f,
+ 0.327148f, 0.354736f, 0.383545f, 0.411621f, 0.439941f, 0.468018f, 0.495605f, 0.522949f, 0.548828f, 0.574219f, 0.598145f, 0.622559f,
+ 0.645508f, 0.666016f, 0.687500f, 0.706543f, 0.725586f, 0.743164f, 0.759766f, 0.775391f, 0.791016f, 0.803711f, 0.817871f, 0.829590f,
+ 0.841797f, 0.852539f, 0.863281f, 0.873047f, 0.882812f, 0.891113f, 0.900391f, 0.906738f, 0.915039f, 0.922852f, 0.929688f, 0.936035f,
+ 0.941895f, 0.946777f, 0.976074f, 0.977051f, 0.976074f, 0.975586f, 0.974121f, 0.972656f, 0.002846f, 0.008568f, 0.014557f, 0.021484f,
+ 0.028442f, 0.036377f, 0.045074f, 0.055054f, 0.066101f, 0.077759f, 0.090759f, 0.104797f, 0.120483f, 0.136719f, 0.155029f, 0.175171f,
+ 0.196045f, 0.218262f, 0.241943f, 0.266357f, 0.292480f, 0.319336f, 0.345703f, 0.373535f, 0.402100f, 0.429932f, 0.457764f, 0.484863f,
+ 0.512207f, 0.539062f, 0.564941f, 0.589844f, 0.613281f, 0.636719f, 0.659180f, 0.680664f, 0.700684f, 0.718750f, 0.736816f, 0.754883f,
+ 0.770508f, 0.785645f, 0.799805f, 0.813965f, 0.826172f, 0.838867f, 0.850586f, 0.861328f, 0.871582f, 0.881836f, 0.890625f, 0.898926f,
+ 0.906738f, 0.915039f, 0.922363f, 0.928711f, 0.936035f, 0.941895f, 0.974609f, 0.975098f, 0.974609f, 0.973633f, 0.972656f, 0.971191f,
+ 0.002285f, 0.007290f, 0.012634f, 0.018280f, 0.024918f, 0.032074f, 0.039673f, 0.048157f, 0.057220f, 0.067810f, 0.078735f, 0.091248f,
+ 0.104370f, 0.119873f, 0.135742f, 0.152344f, 0.171631f, 0.191650f, 0.213501f, 0.236206f, 0.260010f, 0.285156f, 0.310547f, 0.338135f,
+ 0.364746f, 0.392578f, 0.420410f, 0.448242f, 0.476562f, 0.502441f, 0.529785f, 0.555664f, 0.581543f, 0.605469f, 0.629395f, 0.652344f,
+ 0.673340f, 0.693848f, 0.713867f, 0.732910f, 0.750000f, 0.767090f, 0.782715f, 0.797852f, 0.811035f, 0.825195f, 0.836914f, 0.848633f,
+ 0.860840f, 0.870605f, 0.880371f, 0.890137f, 0.898926f, 0.907227f, 0.915527f, 0.923340f, 0.929688f, 0.936523f, 0.972168f, 0.973145f,
+ 0.972656f, 0.972168f, 0.970703f, 0.969727f, 0.002064f, 0.006584f, 0.011154f, 0.016266f, 0.022263f, 0.028397f, 0.034973f, 0.042145f,
+ 0.050232f, 0.059235f, 0.069031f, 0.079346f, 0.091736f, 0.104553f, 0.118652f, 0.133789f, 0.150635f, 0.168457f, 0.188110f, 0.208984f,
+ 0.230225f, 0.253906f, 0.278076f, 0.303955f, 0.329346f, 0.356689f, 0.384033f, 0.411865f, 0.439941f, 0.467285f, 0.493896f, 0.520996f,
+ 0.547363f, 0.573730f, 0.597168f, 0.622559f, 0.645508f, 0.667969f, 0.688965f, 0.709473f, 0.728027f, 0.746094f, 0.762695f, 0.778809f,
+ 0.794922f, 0.809082f, 0.822754f, 0.834961f, 0.847168f, 0.858887f, 0.870117f, 0.880371f, 0.889648f, 0.898926f, 0.907227f, 0.915039f,
+ 0.923828f, 0.930176f, 0.970215f, 0.971680f, 0.970215f, 0.970215f, 0.968750f, 0.968262f, 0.001935f, 0.005634f, 0.010078f, 0.014389f,
+ 0.019669f, 0.024658f, 0.030716f, 0.037201f, 0.044098f, 0.051941f, 0.060333f, 0.070129f, 0.080383f, 0.091370f, 0.103638f, 0.116943f,
+ 0.131714f, 0.148193f, 0.165161f, 0.183838f, 0.203979f, 0.225220f, 0.247803f, 0.271240f, 0.296631f, 0.322510f, 0.349121f, 0.376221f,
+ 0.403076f, 0.431152f, 0.458984f, 0.485596f, 0.513672f, 0.540039f, 0.564941f, 0.590820f, 0.616211f, 0.638672f, 0.662109f, 0.683105f,
+ 0.704102f, 0.723633f, 0.741699f, 0.759766f, 0.776855f, 0.792480f, 0.807617f, 0.821777f, 0.833496f, 0.847168f, 0.858887f, 0.870117f,
+ 0.880859f, 0.889648f, 0.899414f, 0.908203f, 0.916992f, 0.924316f, 0.967285f, 0.968262f, 0.968750f, 0.968262f, 0.967285f, 0.966309f,
+ 0.001805f, 0.005119f, 0.009079f, 0.013023f, 0.017487f, 0.022278f, 0.027130f, 0.032684f, 0.038666f, 0.045959f, 0.052826f, 0.061401f,
+ 0.070801f, 0.080139f, 0.090698f, 0.102844f, 0.115845f, 0.130005f, 0.145264f, 0.162476f, 0.180176f, 0.199951f, 0.220459f, 0.242188f,
+ 0.265869f, 0.290283f, 0.315430f, 0.341309f, 0.368652f, 0.395752f, 0.423584f, 0.451416f, 0.479248f, 0.505859f, 0.532227f, 0.559082f,
+ 0.584961f, 0.609863f, 0.634277f, 0.656738f, 0.678711f, 0.700195f, 0.720703f, 0.738281f, 0.757324f, 0.774414f, 0.790527f, 0.805664f,
+ 0.820312f, 0.834473f, 0.846680f, 0.858887f, 0.869629f, 0.880859f, 0.890625f, 0.899902f, 0.909668f, 0.917969f, 0.964844f, 0.966797f,
+ 0.967285f, 0.965820f, 0.964844f, 0.963867f, 0.001437f, 0.004662f, 0.007919f, 0.011681f, 0.015404f, 0.019272f, 0.024261f, 0.029205f,
+ 0.034515f, 0.040619f, 0.046967f, 0.054138f, 0.061737f, 0.070496f, 0.080200f, 0.090271f, 0.101807f, 0.114136f, 0.127686f, 0.143188f,
+ 0.159058f, 0.176514f, 0.195190f, 0.215454f, 0.237305f, 0.260010f, 0.283936f, 0.309326f, 0.334717f, 0.361328f, 0.389160f, 0.416260f,
+ 0.444336f, 0.471436f, 0.499512f, 0.525879f, 0.552734f, 0.579590f, 0.604004f, 0.628906f, 0.651855f, 0.674805f, 0.696777f, 0.717773f,
+ 0.737305f, 0.755859f, 0.772949f, 0.789551f, 0.805664f, 0.819336f, 0.833984f, 0.847168f, 0.859375f, 0.871094f, 0.881836f, 0.892090f,
+ 0.902344f, 0.910156f, 0.962402f, 0.964355f, 0.964355f, 0.963867f, 0.962891f, 0.961914f, 0.001264f, 0.004036f, 0.007088f, 0.010170f,
+ 0.013672f, 0.017365f, 0.021423f, 0.025955f, 0.030533f, 0.035614f, 0.041321f, 0.047791f, 0.054626f, 0.062195f, 0.070679f, 0.080017f,
+ 0.089600f, 0.100769f, 0.112854f, 0.125977f, 0.139893f, 0.156128f, 0.172852f, 0.191650f, 0.211060f, 0.232056f, 0.254883f, 0.278076f,
+ 0.302979f, 0.328125f, 0.355225f, 0.381836f, 0.409912f, 0.437256f, 0.464844f, 0.492676f, 0.520508f, 0.547852f, 0.573242f, 0.599609f,
+ 0.625000f, 0.649414f, 0.672363f, 0.694336f, 0.714844f, 0.734863f, 0.753418f, 0.771484f, 0.788574f, 0.804688f, 0.820312f, 0.833496f,
+ 0.847656f, 0.859863f, 0.873047f, 0.883301f, 0.894043f, 0.903809f, 0.959961f, 0.961914f, 0.962402f, 0.960938f, 0.960449f, 0.959961f,
+ 0.001297f, 0.003721f, 0.006397f, 0.009308f, 0.012260f, 0.015808f, 0.019302f, 0.023010f, 0.027267f, 0.032013f, 0.037109f, 0.042419f,
+ 0.048523f, 0.054962f, 0.061920f, 0.070435f, 0.079407f, 0.088318f, 0.099121f, 0.111084f, 0.124023f, 0.137695f, 0.152832f, 0.169434f,
+ 0.187378f, 0.206421f, 0.227783f, 0.249268f, 0.272461f, 0.297363f, 0.322754f, 0.348389f, 0.376221f, 0.403809f, 0.431396f, 0.459229f,
+ 0.487305f, 0.515137f, 0.542480f, 0.569336f, 0.595215f, 0.621094f, 0.645996f, 0.669434f, 0.691406f, 0.712891f, 0.733887f, 0.753418f,
+ 0.770996f, 0.789062f, 0.805176f, 0.820801f, 0.835449f, 0.849121f, 0.861328f, 0.874512f, 0.885742f, 0.895508f, 0.956543f, 0.959473f,
+ 0.958984f, 0.958984f, 0.958008f, 0.957031f, 0.001267f, 0.003481f, 0.005955f, 0.008568f, 0.011185f, 0.014030f, 0.017151f, 0.020294f,
+ 0.024246f, 0.028427f, 0.032654f, 0.037476f, 0.042603f, 0.048523f, 0.054871f, 0.062408f, 0.070129f, 0.078552f, 0.087769f, 0.097534f,
+ 0.109192f, 0.121399f, 0.135010f, 0.150513f, 0.165894f, 0.183960f, 0.202881f, 0.222656f, 0.244385f, 0.267334f, 0.291260f, 0.317139f,
+ 0.343506f, 0.370605f, 0.397949f, 0.426025f, 0.454346f, 0.482666f, 0.511230f, 0.538086f, 0.565918f, 0.592285f, 0.618164f, 0.642578f,
+ 0.667480f, 0.690918f, 0.711914f, 0.732910f, 0.752930f, 0.771484f, 0.790039f, 0.806641f, 0.821777f, 0.837402f, 0.850586f, 0.864746f,
+ 0.875977f, 0.887695f, 0.953613f, 0.956543f, 0.957031f, 0.956055f, 0.956055f, 0.955078f, 0.001068f, 0.003025f, 0.005283f, 0.007442f,
+ 0.009857f, 0.012665f, 0.015930f, 0.018570f, 0.021820f, 0.025314f, 0.028931f, 0.033325f, 0.038147f, 0.042908f, 0.049011f, 0.055176f,
+ 0.061859f, 0.069397f, 0.077637f, 0.086792f, 0.096252f, 0.107117f, 0.119385f, 0.132690f, 0.147095f, 0.162720f, 0.180054f, 0.198486f,
+ 0.218384f, 0.239990f, 0.262207f, 0.287109f, 0.311523f, 0.337891f, 0.364990f, 0.392822f, 0.420654f, 0.449219f, 0.478027f, 0.505859f,
+ 0.535156f, 0.562012f, 0.588867f, 0.615723f, 0.641602f, 0.666016f, 0.688965f, 0.711914f, 0.732910f, 0.753906f, 0.773438f, 0.791016f,
+ 0.808594f, 0.823730f, 0.839355f, 0.854004f, 0.867188f, 0.879883f, 0.950195f, 0.954102f, 0.954102f, 0.953125f, 0.952637f, 0.952148f,
+ 0.000884f, 0.003082f, 0.004631f, 0.006931f, 0.008942f, 0.011513f, 0.013779f, 0.016663f, 0.019806f, 0.022934f, 0.026215f, 0.029999f,
+ 0.033813f, 0.038544f, 0.043365f, 0.048615f, 0.054352f, 0.061005f, 0.068420f, 0.076477f, 0.085022f, 0.095032f, 0.105469f, 0.117432f,
+ 0.130127f, 0.143799f, 0.159790f, 0.176270f, 0.194580f, 0.214478f, 0.235229f, 0.257568f, 0.281982f, 0.306641f, 0.332764f, 0.359863f,
+ 0.388184f, 0.416016f, 0.445557f, 0.474854f, 0.502441f, 0.531738f, 0.559570f, 0.586914f, 0.614258f, 0.640625f, 0.665039f, 0.689453f,
+ 0.712891f, 0.734863f, 0.755371f, 0.774902f, 0.793945f, 0.810547f, 0.827637f, 0.842773f, 0.857910f, 0.871094f, 0.946777f, 0.950684f,
+ 0.951172f, 0.950684f, 0.949707f, 0.949707f, 0.000848f, 0.002630f, 0.004330f, 0.006386f, 0.008148f, 0.010437f, 0.012436f, 0.014977f,
+ 0.017731f, 0.020645f, 0.023529f, 0.026413f, 0.030289f, 0.034302f, 0.038391f, 0.043365f, 0.048737f, 0.054413f, 0.060455f, 0.067383f,
+ 0.075134f, 0.083801f, 0.093262f, 0.103821f, 0.114746f, 0.127441f, 0.140991f, 0.156372f, 0.172729f, 0.190918f, 0.210449f, 0.231201f,
+ 0.253662f, 0.277344f, 0.302734f, 0.328857f, 0.355225f, 0.384033f, 0.413086f, 0.440918f, 0.471191f, 0.500488f, 0.529785f, 0.558594f,
+ 0.586426f, 0.613770f, 0.640137f, 0.666016f, 0.689453f, 0.714355f, 0.736328f, 0.757812f, 0.777832f, 0.796875f, 0.813965f, 0.831543f,
+ 0.847168f, 0.860840f, 0.943848f, 0.948242f, 0.947754f, 0.948242f, 0.946777f, 0.946777f, 0.000747f, 0.002462f, 0.004192f, 0.005573f,
+ 0.007454f, 0.009430f, 0.011253f, 0.013588f, 0.015762f, 0.018112f, 0.020859f, 0.023758f, 0.027084f, 0.030426f, 0.034332f, 0.038635f,
+ 0.042999f, 0.048340f, 0.053772f, 0.060028f, 0.066589f, 0.074402f, 0.082764f, 0.091553f, 0.101685f, 0.112854f, 0.125122f, 0.138184f,
+ 0.153320f, 0.169556f, 0.187500f, 0.206543f, 0.227539f, 0.249512f, 0.273193f, 0.298340f, 0.324463f, 0.351562f, 0.379883f, 0.409424f,
+ 0.438477f, 0.468750f, 0.498047f, 0.527832f, 0.556641f, 0.585449f, 0.614258f, 0.641113f, 0.666992f, 0.692383f, 0.716309f, 0.738281f,
+ 0.760742f, 0.780273f, 0.799805f, 0.818848f, 0.834473f, 0.851074f, 0.939941f, 0.944824f, 0.944336f, 0.944336f, 0.944336f, 0.943359f,
+ 0.000670f, 0.002079f, 0.003538f, 0.005146f, 0.006508f, 0.008247f, 0.010223f, 0.012260f, 0.014153f, 0.016479f, 0.018677f, 0.021515f,
+ 0.024323f, 0.027313f, 0.030518f, 0.034302f, 0.038422f, 0.042725f, 0.047760f, 0.053101f, 0.059113f, 0.065613f, 0.072937f, 0.080444f,
+ 0.089722f, 0.099426f, 0.110596f, 0.122314f, 0.135742f, 0.150513f, 0.166260f, 0.183716f, 0.202759f, 0.223633f, 0.245728f, 0.269287f,
+ 0.294189f, 0.320557f, 0.348633f, 0.376709f, 0.406494f, 0.436523f, 0.467285f, 0.497070f, 0.528320f, 0.557129f, 0.586426f, 0.614746f,
+ 0.642090f, 0.668945f, 0.694824f, 0.718750f, 0.742676f, 0.764648f, 0.786133f, 0.805176f, 0.823242f, 0.840820f, 0.936035f, 0.940918f,
+ 0.941406f, 0.941406f, 0.940430f, 0.939941f, 0.000645f, 0.001963f, 0.003384f, 0.004719f, 0.006042f, 0.007614f, 0.009384f, 0.011192f,
+ 0.012665f, 0.015083f, 0.016861f, 0.019165f, 0.021393f, 0.024445f, 0.027451f, 0.030716f, 0.034149f, 0.038116f, 0.042389f, 0.047028f,
+ 0.052277f, 0.058014f, 0.064270f, 0.071289f, 0.079041f, 0.087830f, 0.097351f, 0.108337f, 0.119995f, 0.132812f, 0.147217f, 0.163452f,
+ 0.180420f, 0.199585f, 0.219849f, 0.242065f, 0.265625f, 0.291260f, 0.318115f, 0.345703f, 0.375000f, 0.404541f, 0.434326f, 0.465820f,
+ 0.496582f, 0.526855f, 0.557617f, 0.587402f, 0.616699f, 0.645508f, 0.672363f, 0.698242f, 0.723145f, 0.747559f, 0.770020f, 0.791504f,
+ 0.810059f, 0.828613f, 0.931641f, 0.937012f, 0.937500f, 0.937500f, 0.937012f, 0.936523f, 0.000692f, 0.001705f, 0.003000f, 0.004238f,
+ 0.005798f, 0.006805f, 0.008659f, 0.009933f, 0.011681f, 0.013191f, 0.015259f, 0.017166f, 0.019379f, 0.021729f, 0.024796f, 0.027328f,
+ 0.030380f, 0.033661f, 0.037598f, 0.041718f, 0.046539f, 0.051270f, 0.056946f, 0.062988f, 0.069885f, 0.077271f, 0.085999f, 0.095398f,
+ 0.105652f, 0.117859f, 0.129883f, 0.144409f, 0.159912f, 0.177002f, 0.196045f, 0.216553f, 0.239014f, 0.262451f, 0.288086f, 0.314941f,
+ 0.343262f, 0.372314f, 0.403076f, 0.433594f, 0.465332f, 0.496826f, 0.527832f, 0.559082f, 0.589355f, 0.619629f, 0.648926f, 0.676758f,
+ 0.703125f, 0.728516f, 0.752930f, 0.775391f, 0.797363f, 0.817871f, 0.927246f, 0.933105f, 0.934082f, 0.933594f, 0.933594f, 0.933105f,
+ 0.000460f, 0.001622f, 0.002705f, 0.003983f, 0.004925f, 0.006363f, 0.007652f, 0.008965f, 0.010521f, 0.011963f, 0.013664f, 0.015480f,
+ 0.017258f, 0.019440f, 0.021912f, 0.024338f, 0.027084f, 0.030212f, 0.033356f, 0.037018f, 0.040833f, 0.045380f, 0.050110f, 0.055573f,
+ 0.061829f, 0.068359f, 0.075928f, 0.083984f, 0.093140f, 0.103333f, 0.115112f, 0.127441f, 0.141602f, 0.156982f, 0.174316f, 0.192871f,
+ 0.213257f, 0.235596f, 0.259766f, 0.285400f, 0.312256f, 0.341797f, 0.371094f, 0.402100f, 0.434082f, 0.465332f, 0.497314f, 0.529297f,
+ 0.562012f, 0.592773f, 0.623535f, 0.652832f, 0.681641f, 0.709473f, 0.735352f, 0.759766f, 0.783203f, 0.803711f, 0.922363f, 0.929199f,
+ 0.929688f, 0.929199f, 0.929688f, 0.928711f, 0.000341f, 0.001686f, 0.002537f, 0.003769f, 0.004745f, 0.005764f, 0.007034f, 0.008286f,
+ 0.009369f, 0.010742f, 0.012161f, 0.013931f, 0.015671f, 0.017563f, 0.019440f, 0.021851f, 0.024231f, 0.026672f, 0.029556f, 0.032776f,
+ 0.036255f, 0.040283f, 0.044464f, 0.049194f, 0.054413f, 0.060059f, 0.066589f, 0.074036f, 0.081909f, 0.091187f, 0.100769f, 0.112000f,
+ 0.124512f, 0.139038f, 0.154297f, 0.171265f, 0.189819f, 0.210571f, 0.232788f, 0.257324f, 0.283203f, 0.311035f, 0.339844f, 0.370850f,
+ 0.402100f, 0.433838f, 0.466797f, 0.499268f, 0.532227f, 0.565430f, 0.598145f, 0.628418f, 0.659180f, 0.687988f, 0.715820f, 0.742188f,
+ 0.767090f, 0.791504f, 0.917969f, 0.924805f, 0.925293f, 0.925293f, 0.924805f, 0.924805f, 0.000405f, 0.001282f, 0.002298f, 0.003269f,
+ 0.004448f, 0.005043f, 0.006294f, 0.007233f, 0.008606f, 0.009727f, 0.010849f, 0.012421f, 0.013885f, 0.015465f, 0.017426f, 0.019394f,
+ 0.021667f, 0.023819f, 0.026154f, 0.029175f, 0.032227f, 0.035706f, 0.039062f, 0.043427f, 0.047913f, 0.052856f, 0.058502f, 0.064880f,
+ 0.071960f, 0.079895f, 0.088867f, 0.098633f, 0.109619f, 0.122192f, 0.135742f, 0.151489f, 0.168457f, 0.187134f, 0.207764f, 0.230835f,
+ 0.254883f, 0.281494f, 0.310059f, 0.339355f, 0.370361f, 0.402588f, 0.435547f, 0.468994f, 0.502930f, 0.537109f, 0.569824f, 0.602051f,
+ 0.634766f, 0.665527f, 0.695801f, 0.724121f, 0.750488f, 0.776855f, 0.912598f, 0.919434f, 0.920410f, 0.920410f, 0.919922f, 0.920410f,
+ 0.000529f, 0.001217f, 0.002171f, 0.003035f, 0.003790f, 0.004784f, 0.005711f, 0.006756f, 0.007782f, 0.008987f, 0.009773f, 0.011185f,
+ 0.012650f, 0.013771f, 0.015656f, 0.017181f, 0.018890f, 0.021057f, 0.023239f, 0.025848f, 0.028488f, 0.031525f, 0.034607f, 0.038147f,
+ 0.042023f, 0.046539f, 0.051605f, 0.056793f, 0.063049f, 0.069946f, 0.078064f, 0.086548f, 0.096313f, 0.107117f, 0.119446f, 0.133301f,
+ 0.148560f, 0.165405f, 0.184570f, 0.205811f, 0.228394f, 0.253174f, 0.280029f, 0.308594f, 0.339111f, 0.370605f, 0.404053f, 0.437988f,
+ 0.471680f, 0.506348f, 0.541504f, 0.576172f, 0.609375f, 0.642578f, 0.674316f, 0.705078f, 0.734375f, 0.761719f, 0.907227f, 0.914062f,
+ 0.915527f, 0.915527f, 0.916016f, 0.915039f, 0.000402f, 0.001247f, 0.001841f, 0.002651f, 0.003414f, 0.004200f, 0.005337f, 0.005821f,
+ 0.006733f, 0.008041f, 0.008942f, 0.010201f, 0.011261f, 0.012749f, 0.013893f, 0.015472f, 0.016663f, 0.018829f, 0.020615f, 0.022873f,
+ 0.025299f, 0.027893f, 0.030533f, 0.033600f, 0.037140f, 0.040924f, 0.044983f, 0.049927f, 0.055359f, 0.061340f, 0.068176f, 0.075500f,
+ 0.084106f, 0.093933f, 0.104370f, 0.116638f, 0.130249f, 0.145996f, 0.162842f, 0.181885f, 0.203735f, 0.226562f, 0.251465f, 0.279297f,
+ 0.308594f, 0.339355f, 0.373047f, 0.406982f, 0.440918f, 0.477051f, 0.511719f, 0.548340f, 0.583496f, 0.618164f, 0.652344f, 0.684570f,
+ 0.715332f, 0.745605f, 0.901855f, 0.909180f, 0.910156f, 0.910645f, 0.910156f, 0.910156f, 0.000371f, 0.001090f, 0.001752f, 0.002409f,
+ 0.003042f, 0.003963f, 0.004898f, 0.005295f, 0.006077f, 0.006992f, 0.008102f, 0.009338f, 0.010101f, 0.011078f, 0.012375f, 0.013718f,
+ 0.015099f, 0.016403f, 0.018402f, 0.020203f, 0.022354f, 0.024475f, 0.026825f, 0.029388f, 0.032623f, 0.035522f, 0.039429f, 0.043762f,
+ 0.048462f, 0.053558f, 0.059265f, 0.065552f, 0.073120f, 0.081787f, 0.091431f, 0.102112f, 0.114136f, 0.127930f, 0.143066f, 0.160767f,
+ 0.179810f, 0.200928f, 0.224854f, 0.250732f, 0.279053f, 0.308838f, 0.340820f, 0.374756f, 0.410156f, 0.446045f, 0.482666f, 0.520020f,
+ 0.556152f, 0.593262f, 0.628906f, 0.663574f, 0.695801f, 0.728027f, 0.895508f, 0.903809f, 0.904297f, 0.904297f, 0.904297f, 0.904785f,
+ 0.000425f, 0.000937f, 0.001529f, 0.002129f, 0.002674f, 0.003696f, 0.004257f, 0.004990f, 0.005726f, 0.006161f, 0.007118f, 0.007919f,
+ 0.009109f, 0.009941f, 0.011055f, 0.011993f, 0.013191f, 0.014832f, 0.016281f, 0.017868f, 0.019562f, 0.021362f, 0.023514f, 0.025909f,
+ 0.028549f, 0.031189f, 0.034637f, 0.037994f, 0.042145f, 0.046570f, 0.051453f, 0.057129f, 0.063965f, 0.070984f, 0.079285f, 0.088806f,
+ 0.099426f, 0.111267f, 0.125366f, 0.140747f, 0.158203f, 0.178101f, 0.199585f, 0.223755f, 0.250732f, 0.279297f, 0.310059f, 0.343994f,
+ 0.377686f, 0.414307f, 0.451904f, 0.489258f, 0.527832f, 0.565918f, 0.603027f, 0.640137f, 0.675781f, 0.710449f, 0.888672f, 0.897461f,
+ 0.899902f, 0.900391f, 0.899414f, 0.899414f, 0.000317f, 0.000823f, 0.001386f, 0.002108f, 0.002684f, 0.003239f, 0.003883f, 0.004303f,
+ 0.004730f, 0.005569f, 0.006626f, 0.007214f, 0.008003f, 0.008865f, 0.009590f, 0.010948f, 0.011856f, 0.012871f, 0.014381f, 0.015640f,
+ 0.017075f, 0.018799f, 0.020569f, 0.022537f, 0.024704f, 0.027405f, 0.030090f, 0.033142f, 0.036346f, 0.040436f, 0.044830f, 0.049835f,
+ 0.055450f, 0.061584f, 0.068665f, 0.076904f, 0.086060f, 0.096741f, 0.109192f, 0.122559f, 0.138428f, 0.155762f, 0.176270f, 0.198242f,
+ 0.223145f, 0.250244f, 0.280518f, 0.312500f, 0.346680f, 0.382324f, 0.420410f, 0.458740f, 0.498779f, 0.538086f, 0.577637f, 0.616211f,
+ 0.654297f, 0.690918f, 0.881348f, 0.890625f, 0.892578f, 0.893066f, 0.893066f, 0.892578f, 0.000385f, 0.000766f, 0.001544f, 0.001925f,
+ 0.002359f, 0.002947f, 0.003176f, 0.003691f, 0.004288f, 0.005215f, 0.005917f, 0.006214f, 0.007019f, 0.007843f, 0.008469f, 0.009598f,
+ 0.010345f, 0.011559f, 0.012497f, 0.013634f, 0.014992f, 0.016373f, 0.017853f, 0.019608f, 0.021515f, 0.023788f, 0.026260f, 0.028931f,
+ 0.031860f, 0.034912f, 0.038635f, 0.042633f, 0.047638f, 0.053070f, 0.059540f, 0.066284f, 0.074524f, 0.083679f, 0.094177f, 0.106445f,
+ 0.120361f, 0.135620f, 0.154053f, 0.174072f, 0.197144f, 0.222900f, 0.251221f, 0.281982f, 0.315430f, 0.351318f, 0.388672f, 0.427734f,
+ 0.468506f, 0.508301f, 0.549805f, 0.591309f, 0.631348f, 0.670410f, 0.874512f, 0.884766f, 0.885742f, 0.886230f, 0.886230f, 0.886230f,
+ 0.000230f, 0.000832f, 0.001281f, 0.001865f, 0.002207f, 0.002605f, 0.003212f, 0.003284f, 0.004124f, 0.004597f, 0.005222f, 0.005703f,
+ 0.006260f, 0.007095f, 0.007790f, 0.008377f, 0.009010f, 0.010078f, 0.011009f, 0.011925f, 0.013153f, 0.014282f, 0.015610f, 0.017151f,
+ 0.018951f, 0.020416f, 0.022583f, 0.024826f, 0.027328f, 0.030136f, 0.033508f, 0.036835f, 0.040985f, 0.045410f, 0.050812f, 0.056854f,
+ 0.063965f, 0.071777f, 0.081177f, 0.091858f, 0.103699f, 0.117615f, 0.133423f, 0.152588f, 0.172974f, 0.196777f, 0.222900f, 0.252686f,
+ 0.284912f, 0.319824f, 0.356934f, 0.395996f, 0.436768f, 0.478516f, 0.521484f, 0.564453f, 0.607422f, 0.649414f, 0.866699f, 0.876953f,
+ 0.877930f, 0.879395f, 0.879883f, 0.878418f, 0.000228f, 0.000734f, 0.000993f, 0.001416f, 0.001935f, 0.002293f, 0.002541f, 0.003174f,
+ 0.003508f, 0.004040f, 0.004337f, 0.005039f, 0.005505f, 0.006054f, 0.006840f, 0.007366f, 0.008041f, 0.008644f, 0.009544f, 0.010460f,
+ 0.011238f, 0.012329f, 0.013542f, 0.014755f, 0.016083f, 0.017624f, 0.019424f, 0.021408f, 0.023422f, 0.025803f, 0.028366f, 0.031311f,
+ 0.034912f, 0.039124f, 0.043304f, 0.048492f, 0.054291f, 0.061188f, 0.069397f, 0.078552f, 0.089233f, 0.101074f, 0.115540f, 0.131226f,
+ 0.150757f, 0.172119f, 0.196533f, 0.224243f, 0.254883f, 0.288574f, 0.324707f, 0.364014f, 0.405029f, 0.447510f, 0.491699f, 0.536133f,
+ 0.581543f, 0.627441f, 0.858398f, 0.869141f, 0.870605f, 0.871582f, 0.871094f, 0.871582f, 0.000118f, 0.000713f, 0.000985f, 0.001328f,
+ 0.001612f, 0.001999f, 0.002399f, 0.002913f, 0.003139f, 0.003567f, 0.004055f, 0.004406f, 0.004986f, 0.005226f, 0.005856f, 0.006332f,
+ 0.007042f, 0.007553f, 0.008286f, 0.009064f, 0.009834f, 0.010696f, 0.011658f, 0.012726f, 0.013817f, 0.015289f, 0.016693f, 0.018265f,
+ 0.019699f, 0.021835f, 0.024307f, 0.026642f, 0.029770f, 0.033234f, 0.037048f, 0.041351f, 0.046478f, 0.052032f, 0.058960f, 0.066589f,
+ 0.075745f, 0.086182f, 0.099121f, 0.113037f, 0.129517f, 0.149048f, 0.171387f, 0.196899f, 0.225464f, 0.257812f, 0.293457f, 0.331787f,
+ 0.373291f, 0.416748f, 0.460938f, 0.507812f, 0.554688f, 0.602051f, 0.849609f, 0.859863f, 0.862793f, 0.863281f, 0.862793f, 0.862793f,
+ 0.000211f, 0.000522f, 0.000877f, 0.001204f, 0.001507f, 0.001724f, 0.002062f, 0.002426f, 0.002867f, 0.003157f, 0.003443f, 0.003752f,
+ 0.004192f, 0.004753f, 0.005154f, 0.005428f, 0.006065f, 0.006546f, 0.007210f, 0.007725f, 0.008530f, 0.009247f, 0.010025f, 0.010887f,
+ 0.011909f, 0.012970f, 0.014069f, 0.015335f, 0.017105f, 0.018433f, 0.020554f, 0.022552f, 0.025116f, 0.027802f, 0.031158f, 0.034485f,
+ 0.038971f, 0.044037f, 0.049469f, 0.055847f, 0.063843f, 0.072815f, 0.083618f, 0.095947f, 0.110840f, 0.128174f, 0.147949f, 0.171387f,
+ 0.198242f, 0.228271f, 0.262207f, 0.299805f, 0.340332f, 0.384277f, 0.430176f, 0.477295f, 0.527344f, 0.577637f, 0.839844f, 0.851074f,
+ 0.853516f, 0.854492f, 0.854980f, 0.854980f, 0.000218f, 0.000479f, 0.000706f, 0.001109f, 0.001245f, 0.001763f, 0.001800f, 0.002211f,
+ 0.002377f, 0.002783f, 0.003103f, 0.003223f, 0.003782f, 0.004089f, 0.004326f, 0.004711f, 0.005306f, 0.005569f, 0.006199f, 0.006653f,
+ 0.007168f, 0.007919f, 0.008560f, 0.009254f, 0.009979f, 0.010872f, 0.012054f, 0.012810f, 0.014221f, 0.015793f, 0.017181f, 0.018967f,
+ 0.021088f, 0.023361f, 0.026001f, 0.028915f, 0.032257f, 0.036469f, 0.040924f, 0.046875f, 0.053375f, 0.061218f, 0.070435f, 0.080811f,
+ 0.093628f, 0.108704f, 0.126709f, 0.147461f, 0.172241f, 0.199951f, 0.232788f, 0.268799f, 0.308594f, 0.351562f, 0.397705f, 0.447266f,
+ 0.498291f, 0.550293f, 0.830078f, 0.841797f, 0.843750f, 0.845215f, 0.845215f, 0.845703f, 0.000139f, 0.000379f, 0.000704f, 0.000896f,
+ 0.001095f, 0.001392f, 0.001649f, 0.002058f, 0.002235f, 0.002483f, 0.002621f, 0.002878f, 0.003214f, 0.003580f, 0.003820f, 0.004055f,
+ 0.004498f, 0.004791f, 0.005173f, 0.005692f, 0.006145f, 0.006691f, 0.007175f, 0.007874f, 0.008499f, 0.009239f, 0.010117f, 0.011032f,
+ 0.011864f, 0.012901f, 0.014282f, 0.015701f, 0.017242f, 0.019516f, 0.021469f, 0.024002f, 0.026749f, 0.029953f, 0.034027f, 0.038727f,
+ 0.044250f, 0.050568f, 0.058136f, 0.067139f, 0.078247f, 0.091614f, 0.106689f, 0.125366f, 0.147339f, 0.172974f, 0.202881f, 0.237671f,
+ 0.275879f, 0.318359f, 0.365234f, 0.415283f, 0.468018f, 0.521973f, 0.819336f, 0.832031f, 0.834473f, 0.834961f, 0.835449f, 0.835938f,
+ 0.000115f, 0.000396f, 0.000688f, 0.000885f, 0.000917f, 0.001393f, 0.001478f, 0.001590f, 0.001944f, 0.002123f, 0.002291f, 0.002644f,
+ 0.002666f, 0.003023f, 0.003197f, 0.003546f, 0.003714f, 0.004246f, 0.004551f, 0.004837f, 0.005108f, 0.005577f, 0.006054f, 0.006504f,
+ 0.007023f, 0.007633f, 0.008362f, 0.009148f, 0.009926f, 0.010742f, 0.011917f, 0.013062f, 0.014351f, 0.015991f, 0.017639f, 0.019455f,
+ 0.021729f, 0.024689f, 0.027740f, 0.031708f, 0.036102f, 0.041260f, 0.047882f, 0.055450f, 0.064392f, 0.075500f, 0.088928f, 0.104797f,
+ 0.124756f, 0.147949f, 0.175415f, 0.207275f, 0.244507f, 0.286133f, 0.332520f, 0.381836f, 0.436279f, 0.492432f, 0.808105f, 0.821289f,
+ 0.822754f, 0.824707f, 0.825195f, 0.824219f, 0.000209f, 0.000435f, 0.000493f, 0.000669f, 0.001040f, 0.001076f, 0.001254f, 0.001398f,
+ 0.001603f, 0.001697f, 0.001987f, 0.002140f, 0.002268f, 0.002472f, 0.002769f, 0.002991f, 0.003302f, 0.003572f, 0.003685f, 0.004002f,
+ 0.004337f, 0.004654f, 0.005062f, 0.005379f, 0.005871f, 0.006363f, 0.006733f, 0.007416f, 0.008102f, 0.008812f, 0.009727f, 0.010689f,
+ 0.011566f, 0.013145f, 0.014053f, 0.015762f, 0.017899f, 0.020096f, 0.022552f, 0.025528f, 0.028992f, 0.033325f, 0.038635f, 0.044952f,
+ 0.052582f, 0.061554f, 0.072998f, 0.086670f, 0.103577f, 0.124329f, 0.148804f, 0.178467f, 0.213501f, 0.253174f, 0.298828f, 0.348877f,
+ 0.403076f, 0.461914f, 0.795898f, 0.809570f, 0.812012f, 0.813477f, 0.813477f, 0.814453f, 0.000243f, 0.000322f, 0.000466f, 0.000710f,
+ 0.000863f, 0.000942f, 0.001051f, 0.001182f, 0.001369f, 0.001451f, 0.001716f, 0.001851f, 0.001968f, 0.002192f, 0.002323f, 0.002470f,
+ 0.002773f, 0.002850f, 0.003056f, 0.003399f, 0.003624f, 0.003832f, 0.004192f, 0.004467f, 0.004955f, 0.005276f, 0.005772f, 0.006084f,
+ 0.006672f, 0.007191f, 0.007828f, 0.008720f, 0.009575f, 0.010292f, 0.011505f, 0.012535f, 0.014114f, 0.016006f, 0.017838f, 0.020462f,
+ 0.023193f, 0.026489f, 0.030807f, 0.035858f, 0.041840f, 0.049652f, 0.059174f, 0.070435f, 0.084839f, 0.102783f, 0.124146f, 0.151489f,
+ 0.183472f, 0.221802f, 0.265137f, 0.315186f, 0.369629f, 0.430664f, 0.782715f, 0.796875f, 0.799805f, 0.800293f, 0.801758f, 0.801758f,
+ 0.000119f, 0.000369f, 0.000340f, 0.000595f, 0.000667f, 0.000841f, 0.001010f, 0.001086f, 0.001179f, 0.001225f, 0.001494f, 0.001555f,
+ 0.001654f, 0.001754f, 0.001965f, 0.002142f, 0.002197f, 0.002432f, 0.002619f, 0.002811f, 0.003021f, 0.003139f, 0.003567f, 0.003708f,
+ 0.004066f, 0.004360f, 0.004612f, 0.005123f, 0.005489f, 0.005878f, 0.006306f, 0.006824f, 0.007576f, 0.008286f, 0.008949f, 0.010155f,
+ 0.011322f, 0.012756f, 0.014046f, 0.015976f, 0.018250f, 0.020874f, 0.024094f, 0.027878f, 0.032867f, 0.039154f, 0.046509f, 0.055908f,
+ 0.068054f, 0.082886f, 0.102356f, 0.125732f, 0.155029f, 0.190674f, 0.232422f, 0.281006f, 0.335693f, 0.397949f, 0.770020f, 0.783691f,
+ 0.786621f, 0.787598f, 0.788086f, 0.789551f, 0.000000f, 0.000220f, 0.000275f, 0.000562f, 0.000618f, 0.000683f, 0.000733f, 0.000761f,
+ 0.000966f, 0.001022f, 0.001184f, 0.001237f, 0.001382f, 0.001552f, 0.001688f, 0.001724f, 0.001918f, 0.002024f, 0.002115f, 0.002243f,
+ 0.002403f, 0.002718f, 0.002840f, 0.003052f, 0.003330f, 0.003508f, 0.003860f, 0.004097f, 0.004314f, 0.004719f, 0.005074f, 0.005535f,
+ 0.006058f, 0.006584f, 0.007168f, 0.007874f, 0.008759f, 0.009651f, 0.011086f, 0.012459f, 0.013992f, 0.015945f, 0.018433f, 0.021408f,
+ 0.025192f, 0.029861f, 0.035950f, 0.043396f, 0.053406f, 0.065735f, 0.082031f, 0.102234f, 0.128052f, 0.160645f, 0.200073f, 0.247192f,
+ 0.301025f, 0.363281f, 0.755371f, 0.770996f, 0.772949f, 0.773926f, 0.775879f, 0.775879f, 0.000216f, 0.000102f, 0.000381f, 0.000487f,
+ 0.000429f, 0.000552f, 0.000579f, 0.000788f, 0.000804f, 0.000854f, 0.000937f, 0.000996f, 0.001078f, 0.001218f, 0.001315f, 0.001499f,
+ 0.001532f, 0.001642f, 0.001805f, 0.001825f, 0.002077f, 0.002178f, 0.002312f, 0.002396f, 0.002575f, 0.002735f, 0.002947f, 0.003317f,
+ 0.003428f, 0.003721f, 0.004185f, 0.004379f, 0.004704f, 0.005253f, 0.005650f, 0.006145f, 0.006870f, 0.007515f, 0.008415f, 0.009430f,
+ 0.010612f, 0.012093f, 0.013954f, 0.016052f, 0.018967f, 0.022476f, 0.027115f, 0.032898f, 0.040649f, 0.050690f, 0.063599f, 0.080811f,
+ 0.103210f, 0.132202f, 0.168823f, 0.213501f, 0.266602f, 0.329102f, 0.740234f, 0.756348f, 0.758789f, 0.760254f, 0.761230f, 0.761230f,
+ 0.000179f, 0.000181f, 0.000180f, 0.000289f, 0.000413f, 0.000458f, 0.000497f, 0.000620f, 0.000646f, 0.000688f, 0.000830f, 0.000868f,
+ 0.000904f, 0.000981f, 0.001024f, 0.001178f, 0.001146f, 0.001302f, 0.001382f, 0.001523f, 0.001679f, 0.001737f, 0.001824f, 0.001959f,
+ 0.002195f, 0.002283f, 0.002438f, 0.002579f, 0.002703f, 0.002939f, 0.003181f, 0.003454f, 0.003677f, 0.004051f, 0.004395f, 0.004738f,
+ 0.005283f, 0.005783f, 0.006420f, 0.007095f, 0.007988f, 0.009094f, 0.010384f, 0.011955f, 0.013939f, 0.016434f, 0.019836f, 0.024292f,
+ 0.030029f, 0.037659f, 0.048065f, 0.061890f, 0.080811f, 0.105774f, 0.138672f, 0.180542f, 0.231934f, 0.293213f, 0.724121f, 0.740234f,
+ 0.744141f, 0.745117f, 0.745605f, 0.746094f, 0.000000f, 0.000056f, 0.000263f, 0.000339f, 0.000369f, 0.000357f, 0.000376f, 0.000508f,
+ 0.000519f, 0.000558f, 0.000581f, 0.000678f, 0.000767f, 0.000775f, 0.000905f, 0.000849f, 0.000992f, 0.000942f, 0.001192f, 0.001169f,
+ 0.001204f, 0.001375f, 0.001439f, 0.001532f, 0.001634f, 0.001676f, 0.001799f, 0.001904f, 0.002165f, 0.002262f, 0.002377f, 0.002611f,
+ 0.002836f, 0.003103f, 0.003321f, 0.003550f, 0.004005f, 0.004356f, 0.004772f, 0.005295f, 0.005962f, 0.006756f, 0.007690f, 0.008690f,
+ 0.010078f, 0.011871f, 0.014252f, 0.017242f, 0.021393f, 0.027100f, 0.034851f, 0.046051f, 0.060455f, 0.081848f, 0.110474f, 0.148682f,
+ 0.197632f, 0.257568f, 0.706543f, 0.724121f, 0.727539f, 0.729492f, 0.729980f, 0.729492f, 0.000000f, 0.000130f, 0.000174f, 0.000312f,
+ 0.000290f, 0.000293f, 0.000372f, 0.000319f, 0.000397f, 0.000433f, 0.000550f, 0.000552f, 0.000564f, 0.000593f, 0.000638f, 0.000758f,
+ 0.000784f, 0.000797f, 0.000842f, 0.000937f, 0.001011f, 0.001068f, 0.001125f, 0.001231f, 0.001228f, 0.001288f, 0.001409f, 0.001465f,
+ 0.001644f, 0.001697f, 0.001965f, 0.001924f, 0.002136f, 0.002270f, 0.002436f, 0.002697f, 0.002916f, 0.003202f, 0.003492f, 0.003929f,
+ 0.004391f, 0.004887f, 0.005516f, 0.006233f, 0.007240f, 0.008461f, 0.010094f, 0.012070f, 0.014854f, 0.018585f, 0.024338f, 0.032379f,
+ 0.043884f, 0.060516f, 0.084656f, 0.118469f, 0.164185f, 0.222168f, 0.689941f, 0.708008f, 0.710449f, 0.711914f, 0.712891f, 0.712402f,
+ 0.000000f, 0.000000f, 0.000122f, 0.000226f, 0.000145f, 0.000282f, 0.000255f, 0.000247f, 0.000323f, 0.000389f, 0.000379f, 0.000435f,
+ 0.000461f, 0.000509f, 0.000535f, 0.000517f, 0.000557f, 0.000604f, 0.000649f, 0.000690f, 0.000757f, 0.000773f, 0.000836f, 0.000865f,
+ 0.000924f, 0.000957f, 0.001095f, 0.001104f, 0.001243f, 0.001361f, 0.001458f, 0.001486f, 0.001619f, 0.001745f, 0.001791f, 0.001993f,
+ 0.002100f, 0.002321f, 0.002539f, 0.002771f, 0.003084f, 0.003412f, 0.003866f, 0.004368f, 0.005062f, 0.005821f, 0.006882f, 0.008278f,
+ 0.010071f, 0.012756f, 0.016327f, 0.021774f, 0.029785f, 0.042206f, 0.061462f, 0.090149f, 0.131348f, 0.187378f, 0.669434f, 0.688965f,
+ 0.692383f, 0.694824f, 0.695801f, 0.695312f, 0.000000f, 0.000118f, 0.000113f, 0.000158f, 0.000158f, 0.000176f, 0.000224f, 0.000202f,
+ 0.000251f, 0.000260f, 0.000280f, 0.000332f, 0.000316f, 0.000365f, 0.000389f, 0.000419f, 0.000454f, 0.000435f, 0.000476f, 0.000494f,
+ 0.000516f, 0.000576f, 0.000609f, 0.000656f, 0.000678f, 0.000712f, 0.000792f, 0.000800f, 0.000852f, 0.000919f, 0.000961f, 0.001070f,
+ 0.001120f, 0.001238f, 0.001300f, 0.001480f, 0.001459f, 0.001634f, 0.001798f, 0.001947f, 0.002111f, 0.002377f, 0.002615f, 0.002966f,
+ 0.003410f, 0.003933f, 0.004585f, 0.005489f, 0.006706f, 0.008148f, 0.010757f, 0.013962f, 0.019257f, 0.027771f, 0.041931f, 0.065125f,
+ 0.101135f, 0.152832f, 0.650391f, 0.670898f, 0.674316f, 0.675293f, 0.675781f, 0.677246f, 0.000000f, 0.000000f, 0.000109f, 0.000106f,
+ 0.000121f, 0.000117f, 0.000130f, 0.000151f, 0.000161f, 0.000174f, 0.000234f, 0.000197f, 0.000205f, 0.000236f, 0.000272f, 0.000296f,
+ 0.000267f, 0.000296f, 0.000397f, 0.000344f, 0.000413f, 0.000395f, 0.000433f, 0.000434f, 0.000504f, 0.000488f, 0.000532f, 0.000550f,
+ 0.000602f, 0.000711f, 0.000675f, 0.000704f, 0.000752f, 0.000817f, 0.000896f, 0.000955f, 0.001009f, 0.001091f, 0.001223f, 0.001271f,
+ 0.001415f, 0.001560f, 0.001721f, 0.001989f, 0.002214f, 0.002508f, 0.002930f, 0.003504f, 0.004208f, 0.005169f, 0.006603f, 0.008606f,
+ 0.011864f, 0.017090f, 0.026367f, 0.043396f, 0.072571f, 0.119751f, 0.630859f, 0.650879f, 0.653809f, 0.656250f, 0.657227f, 0.657227f,
+ 0.000000f, 0.000111f, 0.000104f, 0.000100f, 0.000096f, 0.000094f, 0.000105f, 0.000096f, 0.000101f, 0.000115f, 0.000119f, 0.000155f,
+ 0.000129f, 0.000180f, 0.000186f, 0.000199f, 0.000208f, 0.000214f, 0.000232f, 0.000230f, 0.000237f, 0.000247f, 0.000303f, 0.000276f,
+ 0.000324f, 0.000332f, 0.000381f, 0.000371f, 0.000393f, 0.000428f, 0.000490f, 0.000468f, 0.000512f, 0.000540f, 0.000598f, 0.000670f,
+ 0.000673f, 0.000711f, 0.000767f, 0.000842f, 0.000894f, 0.000985f, 0.001120f, 0.001200f, 0.001416f, 0.001544f, 0.001768f, 0.002052f,
+ 0.002510f, 0.003044f, 0.003796f, 0.005016f, 0.006870f, 0.009918f, 0.015335f, 0.026077f, 0.048004f, 0.088745f, 0.610352f, 0.630859f,
+ 0.634277f, 0.636230f, 0.637207f, 0.638184f, 0.000000f, 0.000104f, 0.000098f, 0.000092f, 0.000087f, 0.000084f, 0.000081f, 0.000078f,
+ 0.000074f, 0.000070f, 0.000073f, 0.000075f, 0.000081f, 0.000081f, 0.000119f, 0.000124f, 0.000129f, 0.000115f, 0.000142f, 0.000169f,
+ 0.000155f, 0.000169f, 0.000172f, 0.000196f, 0.000209f, 0.000211f, 0.000203f, 0.000238f, 0.000245f, 0.000260f, 0.000282f, 0.000281f,
+ 0.000297f, 0.000333f, 0.000343f, 0.000374f, 0.000398f, 0.000428f, 0.000473f, 0.000494f, 0.000534f, 0.000591f, 0.000643f, 0.000708f,
+ 0.000790f, 0.000893f, 0.001040f, 0.001169f, 0.001381f, 0.001676f, 0.002123f, 0.002686f, 0.003658f, 0.005329f, 0.008347f, 0.014244f,
+ 0.027954f, 0.060638f, 0.587891f, 0.609375f, 0.613281f, 0.614746f, 0.616699f, 0.616211f, 0.000110f, 0.000094f, 0.000085f, 0.000079f,
+ 0.000075f, 0.000072f, 0.000069f, 0.000067f, 0.000065f, 0.000063f, 0.000059f, 0.000059f, 0.000054f, 0.000051f, 0.000055f, 0.000051f,
+ 0.000066f, 0.000066f, 0.000078f, 0.000074f, 0.000089f, 0.000091f, 0.000102f, 0.000109f, 0.000114f, 0.000126f, 0.000133f, 0.000130f,
+ 0.000141f, 0.000141f, 0.000156f, 0.000172f, 0.000180f, 0.000179f, 0.000206f, 0.000199f, 0.000214f, 0.000254f, 0.000247f, 0.000282f,
+ 0.000300f, 0.000324f, 0.000349f, 0.000374f, 0.000413f, 0.000459f, 0.000513f, 0.000619f, 0.000711f, 0.000823f, 0.001030f, 0.001269f,
+ 0.001724f, 0.002487f, 0.003948f, 0.007015f, 0.014122f, 0.036346f, 0.565430f, 0.586426f, 0.592285f, 0.592773f, 0.594238f, 0.594727f,
+ 0.000092f, 0.000073f, 0.000067f, 0.000062f, 0.000057f, 0.000055f, 0.000052f, 0.000052f, 0.000049f, 0.000049f, 0.000047f, 0.000046f,
+ 0.000046f, 0.000043f, 0.000041f, 0.000039f, 0.000038f, 0.000036f, 0.000039f, 0.000036f, 0.000039f, 0.000037f, 0.000039f, 0.000047f,
+ 0.000051f, 0.000057f, 0.000059f, 0.000060f, 0.000067f, 0.000071f, 0.000078f, 0.000085f, 0.000087f, 0.000091f, 0.000098f, 0.000095f,
+ 0.000102f, 0.000122f, 0.000122f, 0.000137f, 0.000143f, 0.000145f, 0.000168f, 0.000171f, 0.000197f, 0.000209f, 0.000234f, 0.000264f,
+ 0.000295f, 0.000349f, 0.000418f, 0.000520f, 0.000678f, 0.000958f, 0.001512f, 0.002745f, 0.006092f, 0.017456f, 0.542969f, 0.565430f,
+ 0.568848f, 0.569824f, 0.572266f, 0.572266f, 0.000052f, 0.000042f, 0.000037f, 0.000035f, 0.000033f, 0.000033f, 0.000032f, 0.000031f,
+ 0.000031f, 0.000029f, 0.000030f, 0.000030f, 0.000029f, 0.000028f, 0.000028f, 0.000028f, 0.000028f, 0.000028f, 0.000027f, 0.000026f,
+ 0.000024f, 0.000023f, 0.000022f, 0.000022f, 0.000021f, 0.000020f, 0.000019f, 0.000022f, 0.000020f, 0.000023f, 0.000024f, 0.000026f,
+ 0.000028f, 0.000035f, 0.000037f, 0.000038f, 0.000039f, 0.000043f, 0.000048f, 0.000050f, 0.000053f, 0.000055f, 0.000062f, 0.000059f,
+ 0.000072f, 0.000070f, 0.000087f, 0.000099f, 0.000100f, 0.000119f, 0.000142f, 0.000162f, 0.000217f, 0.000283f, 0.000425f, 0.000760f,
+ 0.001818f, 0.006405f, 0.519043f, 0.541504f, 0.546387f, 0.548828f, 0.549316f, 0.550781f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000004f, 0.000004f, 0.000006f, 0.000006f, 0.000008f, 0.000009f, 0.000009f, 0.000009f, 0.000010f,
+ 0.000010f, 0.000010f, 0.000011f, 0.000011f, 0.000011f, 0.000012f, 0.000012f, 0.000012f, 0.000012f, 0.000013f, 0.000012f, 0.000012f,
+ 0.000011f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000008f, 0.000008f, 0.000008f, 0.000008f, 0.000011f,
+ 0.000011f, 0.000012f, 0.000015f, 0.000016f, 0.000016f, 0.000018f, 0.000018f, 0.000020f, 0.000022f, 0.000024f, 0.000028f, 0.000035f,
+ 0.000036f, 0.000052f, 0.000071f, 0.000117f, 0.000260f, 0.001269f, 0.495605f, 0.518555f, 0.523926f, 0.525879f, 0.526855f, 0.527344f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000005f, 0.000021f, 0.473145f, 0.495605f,
+ 0.500000f, 0.502441f, 0.503418f, 0.503906f,
+ },
+ {
+ 0.045868f, 0.130493f, 0.205322f, 0.272705f, 0.331787f, 0.384521f, 0.431885f, 0.473389f, 0.511719f, 0.545898f, 0.576660f, 0.605469f,
+ 0.631348f, 0.654785f, 0.676758f, 0.696289f, 0.714355f, 0.732422f, 0.749023f, 0.763184f, 0.777832f, 0.790527f, 0.802734f, 0.813477f,
+ 0.824219f, 0.834961f, 0.844238f, 0.853027f, 0.862305f, 0.869629f, 0.877441f, 0.884277f, 0.892090f, 0.898926f, 0.904297f, 0.910645f,
+ 0.916992f, 0.921875f, 0.926758f, 0.931641f, 0.937012f, 0.941406f, 0.945801f, 0.950195f, 0.954102f, 0.958496f, 0.962402f, 0.966309f,
+ 0.969238f, 0.973145f, 0.976074f, 0.979492f, 0.982422f, 0.985352f, 0.988281f, 0.991211f, 0.993652f, 0.996094f, 0.997070f, 0.993164f,
+ 0.990234f, 0.987305f, 0.984375f, 0.981445f, 0.033447f, 0.097717f, 0.160400f, 0.219238f, 0.273438f, 0.323486f, 0.371582f, 0.414062f,
+ 0.454834f, 0.491211f, 0.524414f, 0.555176f, 0.583984f, 0.610840f, 0.635254f, 0.658203f, 0.678223f, 0.697754f, 0.716309f, 0.732422f,
+ 0.749023f, 0.763184f, 0.776855f, 0.790527f, 0.802734f, 0.812988f, 0.824707f, 0.834473f, 0.844238f, 0.853516f, 0.862305f, 0.870117f,
+ 0.877930f, 0.884766f, 0.892090f, 0.897949f, 0.905762f, 0.910645f, 0.917480f, 0.923340f, 0.927734f, 0.933105f, 0.937988f, 0.942871f,
+ 0.947266f, 0.951172f, 0.955566f, 0.960449f, 0.963379f, 0.967285f, 0.970703f, 0.974609f, 0.978027f, 0.981445f, 0.984863f, 0.986816f,
+ 0.989746f, 0.993164f, 0.995605f, 0.992188f, 0.988770f, 0.986328f, 0.983398f, 0.980957f, 0.024796f, 0.075195f, 0.126221f, 0.176025f,
+ 0.224976f, 0.271729f, 0.317383f, 0.359375f, 0.399902f, 0.437744f, 0.472656f, 0.505371f, 0.536133f, 0.565430f, 0.591797f, 0.615723f,
+ 0.639648f, 0.660156f, 0.681152f, 0.699219f, 0.718262f, 0.734375f, 0.749512f, 0.764648f, 0.777832f, 0.791016f, 0.802734f, 0.813965f,
+ 0.825195f, 0.835449f, 0.844727f, 0.854004f, 0.862305f, 0.871094f, 0.878418f, 0.886230f, 0.893555f, 0.900391f, 0.906738f, 0.912598f,
+ 0.917969f, 0.923828f, 0.929688f, 0.935059f, 0.939941f, 0.943848f, 0.949219f, 0.953613f, 0.958008f, 0.961914f, 0.965332f, 0.969238f,
+ 0.972656f, 0.976074f, 0.979492f, 0.982910f, 0.986328f, 0.989258f, 0.993652f, 0.990723f, 0.987793f, 0.985352f, 0.982910f, 0.979980f,
+ 0.019119f, 0.058624f, 0.100220f, 0.142578f, 0.185303f, 0.227417f, 0.269287f, 0.310059f, 0.348877f, 0.385254f, 0.421875f, 0.455566f,
+ 0.489014f, 0.518555f, 0.546875f, 0.574707f, 0.598633f, 0.624023f, 0.645508f, 0.666016f, 0.684082f, 0.702637f, 0.720703f, 0.736816f,
+ 0.751465f, 0.766113f, 0.779785f, 0.792969f, 0.804199f, 0.815918f, 0.826660f, 0.836426f, 0.846191f, 0.855957f, 0.864746f, 0.872559f,
+ 0.880371f, 0.888184f, 0.895508f, 0.902344f, 0.908691f, 0.914062f, 0.919922f, 0.925293f, 0.932129f, 0.936035f, 0.941895f, 0.946289f,
+ 0.951172f, 0.955566f, 0.959473f, 0.963867f, 0.967773f, 0.970703f, 0.975586f, 0.978516f, 0.981934f, 0.985352f, 0.991699f, 0.988770f,
+ 0.986328f, 0.983887f, 0.981445f, 0.979004f, 0.015175f, 0.046997f, 0.080688f, 0.116028f, 0.152466f, 0.189819f, 0.227417f, 0.264404f,
+ 0.301758f, 0.338623f, 0.374268f, 0.407471f, 0.439941f, 0.471924f, 0.501465f, 0.529785f, 0.556641f, 0.582031f, 0.606445f, 0.629395f,
+ 0.649902f, 0.670898f, 0.688965f, 0.708496f, 0.725098f, 0.740723f, 0.755371f, 0.769531f, 0.782715f, 0.795410f, 0.807129f, 0.818848f,
+ 0.829590f, 0.839844f, 0.849121f, 0.857910f, 0.866699f, 0.875488f, 0.882812f, 0.890625f, 0.897461f, 0.904297f, 0.910645f, 0.916992f,
+ 0.922363f, 0.928223f, 0.933594f, 0.938477f, 0.944824f, 0.949707f, 0.953613f, 0.958008f, 0.962402f, 0.966309f, 0.970703f, 0.974121f,
+ 0.977539f, 0.981934f, 0.990234f, 0.987793f, 0.984863f, 0.982910f, 0.980469f, 0.978516f, 0.012215f, 0.038452f, 0.066101f, 0.095825f,
+ 0.126831f, 0.159180f, 0.192749f, 0.226685f, 0.260986f, 0.294922f, 0.328857f, 0.363037f, 0.394531f, 0.426270f, 0.457520f, 0.486572f,
+ 0.514648f, 0.541016f, 0.567871f, 0.590820f, 0.614746f, 0.636230f, 0.657227f, 0.676270f, 0.694336f, 0.711914f, 0.729492f, 0.744141f,
+ 0.759277f, 0.773438f, 0.786621f, 0.798340f, 0.811523f, 0.822266f, 0.833496f, 0.842773f, 0.851562f, 0.861816f, 0.869629f, 0.878418f,
+ 0.885742f, 0.893066f, 0.900879f, 0.907715f, 0.913574f, 0.919922f, 0.925781f, 0.932129f, 0.937012f, 0.942871f, 0.946777f, 0.951660f,
+ 0.957031f, 0.960938f, 0.965332f, 0.969727f, 0.973633f, 0.977051f, 0.988281f, 0.986328f, 0.983887f, 0.981445f, 0.979492f, 0.976562f,
+ 0.009903f, 0.031525f, 0.054626f, 0.078979f, 0.105408f, 0.133789f, 0.162720f, 0.192993f, 0.224976f, 0.256592f, 0.288330f, 0.320312f,
+ 0.352295f, 0.383545f, 0.414062f, 0.443848f, 0.473389f, 0.500488f, 0.526367f, 0.553223f, 0.577637f, 0.600586f, 0.622070f, 0.644043f,
+ 0.664551f, 0.683105f, 0.701660f, 0.718262f, 0.734375f, 0.750000f, 0.764648f, 0.778320f, 0.791016f, 0.802734f, 0.815430f, 0.826172f,
+ 0.836426f, 0.845703f, 0.855957f, 0.864258f, 0.874023f, 0.881348f, 0.889648f, 0.896973f, 0.904297f, 0.911621f, 0.917480f, 0.922852f,
+ 0.929199f, 0.935059f, 0.939941f, 0.944824f, 0.950195f, 0.954590f, 0.959961f, 0.964355f, 0.968262f, 0.972656f, 0.986328f, 0.984375f,
+ 0.981934f, 0.979980f, 0.978027f, 0.975586f, 0.008385f, 0.026154f, 0.045319f, 0.066467f, 0.089111f, 0.113220f, 0.138916f, 0.165405f,
+ 0.192871f, 0.222290f, 0.252197f, 0.281494f, 0.311279f, 0.342285f, 0.372314f, 0.402832f, 0.431641f, 0.459473f, 0.486572f, 0.513672f,
+ 0.539062f, 0.562988f, 0.587402f, 0.609863f, 0.631348f, 0.652344f, 0.671875f, 0.689941f, 0.708008f, 0.724609f, 0.740234f, 0.755371f,
+ 0.768066f, 0.783203f, 0.795410f, 0.808105f, 0.819336f, 0.830078f, 0.840332f, 0.851074f, 0.860352f, 0.869141f, 0.877930f, 0.885742f,
+ 0.893555f, 0.900879f, 0.907715f, 0.915039f, 0.920410f, 0.926758f, 0.933105f, 0.938965f, 0.944336f, 0.949707f, 0.953613f, 0.958984f,
+ 0.962891f, 0.967285f, 0.984375f, 0.982910f, 0.980957f, 0.978516f, 0.976562f, 0.974609f, 0.006992f, 0.022324f, 0.038544f, 0.056396f,
+ 0.075317f, 0.095947f, 0.117981f, 0.141968f, 0.166504f, 0.192627f, 0.219238f, 0.246704f, 0.275879f, 0.304443f, 0.333252f, 0.362305f,
+ 0.390869f, 0.419678f, 0.447266f, 0.474121f, 0.500977f, 0.525879f, 0.551270f, 0.574219f, 0.597656f, 0.620117f, 0.641602f, 0.661133f,
+ 0.680664f, 0.698242f, 0.715332f, 0.731934f, 0.746582f, 0.761230f, 0.775391f, 0.789551f, 0.802246f, 0.813477f, 0.825195f, 0.835938f,
+ 0.846191f, 0.855957f, 0.865723f, 0.873535f, 0.882324f, 0.890625f, 0.898438f, 0.905762f, 0.912598f, 0.918945f, 0.925781f, 0.931641f,
+ 0.937012f, 0.943848f, 0.948730f, 0.954102f, 0.957520f, 0.963379f, 0.981934f, 0.980957f, 0.979004f, 0.977051f, 0.975098f, 0.973145f,
+ 0.006260f, 0.018387f, 0.032684f, 0.047821f, 0.064636f, 0.082153f, 0.101318f, 0.122009f, 0.143921f, 0.166870f, 0.191406f, 0.216187f,
+ 0.243164f, 0.269287f, 0.297119f, 0.324951f, 0.352783f, 0.380859f, 0.408691f, 0.435547f, 0.462402f, 0.489258f, 0.514160f, 0.540039f,
+ 0.563965f, 0.585938f, 0.608398f, 0.629395f, 0.649414f, 0.669434f, 0.689453f, 0.705566f, 0.722656f, 0.739258f, 0.753418f, 0.769043f,
+ 0.783203f, 0.795898f, 0.807617f, 0.819824f, 0.830566f, 0.842285f, 0.852051f, 0.862305f, 0.871094f, 0.878906f, 0.888184f, 0.895996f,
+ 0.902832f, 0.910645f, 0.917480f, 0.924316f, 0.930176f, 0.936523f, 0.942383f, 0.946777f, 0.953613f, 0.958496f, 0.979980f, 0.979004f,
+ 0.977539f, 0.975586f, 0.973633f, 0.972168f, 0.005268f, 0.016418f, 0.028091f, 0.041107f, 0.055420f, 0.070435f, 0.087341f, 0.105347f,
+ 0.124512f, 0.144531f, 0.166260f, 0.189453f, 0.213989f, 0.238037f, 0.263184f, 0.290039f, 0.317139f, 0.344238f, 0.370850f, 0.398438f,
+ 0.425293f, 0.451660f, 0.477539f, 0.503418f, 0.528320f, 0.551270f, 0.576172f, 0.598145f, 0.619629f, 0.640137f, 0.659668f, 0.680176f,
+ 0.697754f, 0.714844f, 0.731934f, 0.748047f, 0.762695f, 0.776367f, 0.790039f, 0.803223f, 0.814453f, 0.827148f, 0.837891f, 0.847656f,
+ 0.858398f, 0.868164f, 0.876953f, 0.885742f, 0.893066f, 0.901855f, 0.908691f, 0.916504f, 0.922852f, 0.929199f, 0.935059f, 0.941895f,
+ 0.947754f, 0.953125f, 0.978027f, 0.977539f, 0.975586f, 0.973633f, 0.971680f, 0.969727f, 0.004372f, 0.013802f, 0.024185f, 0.036011f,
+ 0.047729f, 0.060944f, 0.075684f, 0.090820f, 0.107788f, 0.125488f, 0.144653f, 0.165771f, 0.187012f, 0.210205f, 0.233643f, 0.258545f,
+ 0.283447f, 0.309326f, 0.335449f, 0.362305f, 0.388672f, 0.415771f, 0.441650f, 0.468018f, 0.492920f, 0.518066f, 0.542480f, 0.564941f,
+ 0.587891f, 0.609863f, 0.630859f, 0.651855f, 0.670898f, 0.689453f, 0.707520f, 0.724609f, 0.740723f, 0.755859f, 0.770996f, 0.785156f,
+ 0.799316f, 0.809570f, 0.822754f, 0.834473f, 0.845215f, 0.855469f, 0.865723f, 0.874023f, 0.883301f, 0.892090f, 0.899902f, 0.907715f,
+ 0.915039f, 0.922363f, 0.928711f, 0.935059f, 0.941406f, 0.947266f, 0.975586f, 0.975098f, 0.973633f, 0.971680f, 0.969727f, 0.968262f,
+ 0.003809f, 0.012253f, 0.021240f, 0.030884f, 0.041473f, 0.052887f, 0.065308f, 0.079224f, 0.094177f, 0.109558f, 0.126709f, 0.145142f,
+ 0.163940f, 0.184814f, 0.207397f, 0.229736f, 0.252686f, 0.276855f, 0.302246f, 0.327881f, 0.353271f, 0.380127f, 0.405762f, 0.432129f,
+ 0.457520f, 0.482422f, 0.507324f, 0.531250f, 0.556152f, 0.578125f, 0.600586f, 0.622559f, 0.642578f, 0.662109f, 0.681641f, 0.700195f,
+ 0.716797f, 0.734375f, 0.750000f, 0.766113f, 0.779297f, 0.793457f, 0.807129f, 0.819336f, 0.830078f, 0.842285f, 0.853027f, 0.862793f,
+ 0.872559f, 0.881348f, 0.890625f, 0.899414f, 0.907227f, 0.914551f, 0.920898f, 0.928223f, 0.935059f, 0.941406f, 0.973633f, 0.973145f,
+ 0.971680f, 0.970215f, 0.968262f, 0.966797f, 0.003462f, 0.010796f, 0.018646f, 0.026962f, 0.036377f, 0.046173f, 0.057190f, 0.068665f,
+ 0.081726f, 0.095520f, 0.110962f, 0.127563f, 0.144897f, 0.162476f, 0.182373f, 0.202881f, 0.225342f, 0.248291f, 0.271729f, 0.294922f,
+ 0.320312f, 0.345459f, 0.370850f, 0.397217f, 0.422607f, 0.447998f, 0.473145f, 0.498291f, 0.522461f, 0.546875f, 0.569824f, 0.591797f,
+ 0.614258f, 0.635742f, 0.655273f, 0.674805f, 0.693359f, 0.711426f, 0.729492f, 0.745605f, 0.760742f, 0.775391f, 0.789551f, 0.803223f,
+ 0.816406f, 0.828125f, 0.839844f, 0.850586f, 0.861328f, 0.871094f, 0.880371f, 0.889648f, 0.898438f, 0.906250f, 0.915039f, 0.921875f,
+ 0.928223f, 0.935547f, 0.970703f, 0.970215f, 0.970215f, 0.967773f, 0.966309f, 0.965332f, 0.002872f, 0.009338f, 0.016174f, 0.024231f,
+ 0.031525f, 0.040558f, 0.050140f, 0.060455f, 0.071472f, 0.084167f, 0.097168f, 0.111450f, 0.127197f, 0.143433f, 0.160889f, 0.179565f,
+ 0.199463f, 0.220825f, 0.242554f, 0.265625f, 0.288818f, 0.312744f, 0.338135f, 0.362793f, 0.387939f, 0.414307f, 0.439453f, 0.464355f,
+ 0.489014f, 0.514648f, 0.537598f, 0.561523f, 0.583984f, 0.606445f, 0.627930f, 0.648926f, 0.667480f, 0.687988f, 0.705566f, 0.723633f,
+ 0.740234f, 0.756348f, 0.771484f, 0.786621f, 0.799805f, 0.812012f, 0.825195f, 0.836426f, 0.849121f, 0.859375f, 0.870605f, 0.879883f,
+ 0.888672f, 0.897461f, 0.905762f, 0.915039f, 0.921387f, 0.928711f, 0.967773f, 0.969238f, 0.966797f, 0.966797f, 0.964355f, 0.963379f,
+ 0.002750f, 0.008202f, 0.014519f, 0.021301f, 0.028183f, 0.035828f, 0.044342f, 0.053375f, 0.063354f, 0.074219f, 0.085876f, 0.098083f,
+ 0.111938f, 0.126343f, 0.142212f, 0.158936f, 0.177124f, 0.196411f, 0.216553f, 0.237427f, 0.260010f, 0.282715f, 0.306641f, 0.330811f,
+ 0.355957f, 0.381104f, 0.405518f, 0.431152f, 0.456543f, 0.480957f, 0.504883f, 0.529785f, 0.553223f, 0.577148f, 0.599121f, 0.620605f,
+ 0.642090f, 0.662598f, 0.682617f, 0.701172f, 0.718750f, 0.735352f, 0.751953f, 0.768066f, 0.783691f, 0.796875f, 0.810547f, 0.822754f,
+ 0.835938f, 0.847656f, 0.858398f, 0.869141f, 0.879395f, 0.888672f, 0.897949f, 0.906250f, 0.914551f, 0.922363f, 0.965820f, 0.966797f,
+ 0.965820f, 0.963867f, 0.963379f, 0.961426f, 0.002264f, 0.007446f, 0.012741f, 0.018494f, 0.024536f, 0.031769f, 0.039154f, 0.047424f,
+ 0.056122f, 0.065308f, 0.075623f, 0.087219f, 0.098755f, 0.111328f, 0.125854f, 0.140869f, 0.157349f, 0.174805f, 0.193115f, 0.212402f,
+ 0.233643f, 0.254883f, 0.276855f, 0.300293f, 0.324463f, 0.348389f, 0.374023f, 0.398193f, 0.423340f, 0.448242f, 0.473877f, 0.498291f,
+ 0.521973f, 0.545898f, 0.569824f, 0.592773f, 0.614258f, 0.635742f, 0.657227f, 0.676270f, 0.695801f, 0.714844f, 0.731445f, 0.749512f,
+ 0.765137f, 0.779785f, 0.793945f, 0.808594f, 0.821777f, 0.833496f, 0.846191f, 0.858398f, 0.868652f, 0.879395f, 0.888672f, 0.897949f,
+ 0.906738f, 0.916016f, 0.962402f, 0.963867f, 0.962891f, 0.961914f, 0.960938f, 0.958984f, 0.002377f, 0.006668f, 0.011467f, 0.016693f,
+ 0.021820f, 0.028091f, 0.034485f, 0.041748f, 0.049347f, 0.057678f, 0.066589f, 0.076538f, 0.086975f, 0.098816f, 0.111816f, 0.125366f,
+ 0.139404f, 0.155151f, 0.171875f, 0.190186f, 0.208496f, 0.228760f, 0.250244f, 0.271973f, 0.294189f, 0.317871f, 0.341797f, 0.365479f,
+ 0.391357f, 0.415771f, 0.440430f, 0.466797f, 0.491699f, 0.515625f, 0.539551f, 0.563477f, 0.585938f, 0.608887f, 0.630371f, 0.651855f,
+ 0.672363f, 0.692383f, 0.710449f, 0.729492f, 0.745605f, 0.762695f, 0.778320f, 0.792480f, 0.807129f, 0.820801f, 0.833984f, 0.846680f,
+ 0.857910f, 0.869141f, 0.879395f, 0.889648f, 0.899414f, 0.907715f, 0.959473f, 0.961426f, 0.960449f, 0.959961f, 0.958496f, 0.957031f,
+ 0.002062f, 0.006180f, 0.010201f, 0.015053f, 0.019531f, 0.025116f, 0.030960f, 0.037292f, 0.043915f, 0.051117f, 0.059570f, 0.067749f,
+ 0.076843f, 0.087708f, 0.099060f, 0.110352f, 0.123413f, 0.138062f, 0.153198f, 0.169067f, 0.186768f, 0.204956f, 0.224487f, 0.244873f,
+ 0.265625f, 0.288330f, 0.311768f, 0.335205f, 0.359863f, 0.384521f, 0.409668f, 0.434082f, 0.459717f, 0.483887f, 0.508789f, 0.533203f,
+ 0.557617f, 0.580566f, 0.603516f, 0.626465f, 0.646484f, 0.667969f, 0.687500f, 0.708008f, 0.726074f, 0.744141f, 0.760742f, 0.776367f,
+ 0.791504f, 0.806641f, 0.820312f, 0.833496f, 0.846191f, 0.858398f, 0.869629f, 0.879883f, 0.890625f, 0.900879f, 0.956543f, 0.958496f,
+ 0.958008f, 0.956543f, 0.955566f, 0.954102f, 0.001774f, 0.005459f, 0.009155f, 0.013290f, 0.017807f, 0.022537f, 0.027527f, 0.033081f,
+ 0.038818f, 0.045380f, 0.052643f, 0.060516f, 0.068420f, 0.077942f, 0.087952f, 0.098572f, 0.109863f, 0.122925f, 0.136230f, 0.150146f,
+ 0.166382f, 0.183105f, 0.201172f, 0.219482f, 0.240112f, 0.261230f, 0.283203f, 0.305664f, 0.329590f, 0.353027f, 0.377930f, 0.402344f,
+ 0.427490f, 0.453369f, 0.478516f, 0.502930f, 0.527832f, 0.552246f, 0.575684f, 0.598145f, 0.621094f, 0.643555f, 0.664551f, 0.685547f,
+ 0.704590f, 0.723633f, 0.742188f, 0.759277f, 0.775879f, 0.791016f, 0.806152f, 0.820801f, 0.833496f, 0.847168f, 0.859375f, 0.870605f,
+ 0.881348f, 0.893066f, 0.953125f, 0.956055f, 0.955566f, 0.954102f, 0.953125f, 0.951660f, 0.001655f, 0.004757f, 0.008308f, 0.011993f,
+ 0.015808f, 0.020187f, 0.024780f, 0.029434f, 0.034851f, 0.040741f, 0.046997f, 0.053650f, 0.061096f, 0.069397f, 0.078064f, 0.087280f,
+ 0.097351f, 0.108887f, 0.121033f, 0.134277f, 0.148560f, 0.163330f, 0.180054f, 0.197144f, 0.215332f, 0.235718f, 0.255859f, 0.277588f,
+ 0.300049f, 0.323730f, 0.347656f, 0.371826f, 0.396729f, 0.422607f, 0.447021f, 0.472168f, 0.497803f, 0.521973f, 0.547363f, 0.571289f,
+ 0.594238f, 0.618164f, 0.640137f, 0.662109f, 0.682617f, 0.702637f, 0.722168f, 0.739746f, 0.758301f, 0.774902f, 0.790527f, 0.806641f,
+ 0.820801f, 0.834961f, 0.848633f, 0.860352f, 0.872559f, 0.883789f, 0.949707f, 0.953125f, 0.952148f, 0.951172f, 0.950684f, 0.948730f,
+ 0.001418f, 0.004456f, 0.007584f, 0.010803f, 0.014450f, 0.018005f, 0.022186f, 0.026398f, 0.031342f, 0.036224f, 0.041687f, 0.048126f,
+ 0.054382f, 0.061676f, 0.069641f, 0.077759f, 0.086914f, 0.097168f, 0.107910f, 0.119263f, 0.132446f, 0.145752f, 0.161011f, 0.176758f,
+ 0.193726f, 0.211914f, 0.231201f, 0.251709f, 0.272705f, 0.294922f, 0.318604f, 0.342041f, 0.366455f, 0.390869f, 0.416992f, 0.441895f,
+ 0.467285f, 0.493164f, 0.517578f, 0.541992f, 0.566895f, 0.590820f, 0.614746f, 0.637207f, 0.660156f, 0.681152f, 0.701172f, 0.720703f,
+ 0.739746f, 0.758301f, 0.775391f, 0.791992f, 0.807617f, 0.821289f, 0.836426f, 0.850586f, 0.863281f, 0.874512f, 0.946777f, 0.949707f,
+ 0.949707f, 0.948730f, 0.947266f, 0.946289f, 0.001213f, 0.003864f, 0.006721f, 0.009796f, 0.012932f, 0.016037f, 0.020218f, 0.024231f,
+ 0.028275f, 0.032379f, 0.037567f, 0.042603f, 0.048584f, 0.054993f, 0.061798f, 0.069519f, 0.077637f, 0.086182f, 0.095703f, 0.106323f,
+ 0.117676f, 0.130127f, 0.143555f, 0.158203f, 0.173462f, 0.189941f, 0.207886f, 0.226807f, 0.247192f, 0.267822f, 0.290527f, 0.312500f,
+ 0.336670f, 0.360352f, 0.385742f, 0.410889f, 0.437256f, 0.462646f, 0.488281f, 0.513184f, 0.539062f, 0.563477f, 0.588379f, 0.612305f,
+ 0.636230f, 0.657715f, 0.679199f, 0.700195f, 0.720703f, 0.740234f, 0.758301f, 0.775879f, 0.793945f, 0.809082f, 0.824219f, 0.838867f,
+ 0.852539f, 0.865234f, 0.942871f, 0.946777f, 0.946777f, 0.945312f, 0.944824f, 0.943359f, 0.001063f, 0.003754f, 0.005909f, 0.008789f,
+ 0.011780f, 0.014671f, 0.017792f, 0.021378f, 0.025238f, 0.029221f, 0.033417f, 0.038300f, 0.043488f, 0.048828f, 0.054779f, 0.061554f,
+ 0.068604f, 0.076721f, 0.085388f, 0.094482f, 0.104614f, 0.115845f, 0.128296f, 0.141113f, 0.155029f, 0.170044f, 0.186401f, 0.204224f,
+ 0.222778f, 0.242188f, 0.263916f, 0.285156f, 0.308350f, 0.331787f, 0.355957f, 0.381348f, 0.407227f, 0.432617f, 0.459229f, 0.484619f,
+ 0.509277f, 0.536133f, 0.560547f, 0.585938f, 0.609863f, 0.633301f, 0.657715f, 0.678711f, 0.699707f, 0.721191f, 0.740723f, 0.759277f,
+ 0.777344f, 0.794922f, 0.811035f, 0.826660f, 0.841797f, 0.855469f, 0.939453f, 0.943359f, 0.943359f, 0.942871f, 0.941895f, 0.940918f,
+ 0.001175f, 0.003069f, 0.005558f, 0.007912f, 0.010712f, 0.013199f, 0.016235f, 0.019547f, 0.022659f, 0.026138f, 0.030151f, 0.034424f,
+ 0.038940f, 0.044067f, 0.049255f, 0.054993f, 0.061493f, 0.068359f, 0.075928f, 0.084290f, 0.093262f, 0.103760f, 0.114319f, 0.126099f,
+ 0.138550f, 0.152466f, 0.167114f, 0.183472f, 0.200439f, 0.219238f, 0.239014f, 0.259277f, 0.281250f, 0.303711f, 0.327148f, 0.351807f,
+ 0.376709f, 0.402344f, 0.428955f, 0.453857f, 0.480713f, 0.507324f, 0.533203f, 0.558594f, 0.583984f, 0.609375f, 0.633301f, 0.656738f,
+ 0.678711f, 0.700195f, 0.722168f, 0.742188f, 0.761719f, 0.780273f, 0.797852f, 0.813477f, 0.830078f, 0.845703f, 0.935547f, 0.939453f,
+ 0.939453f, 0.938965f, 0.937988f, 0.937012f, 0.001089f, 0.002945f, 0.005066f, 0.007225f, 0.009575f, 0.012016f, 0.014656f, 0.017288f,
+ 0.020142f, 0.023712f, 0.026764f, 0.030640f, 0.034637f, 0.039490f, 0.043854f, 0.048706f, 0.054688f, 0.060913f, 0.067871f, 0.075256f,
+ 0.083191f, 0.092163f, 0.101868f, 0.111938f, 0.123657f, 0.136108f, 0.149658f, 0.164185f, 0.179932f, 0.196777f, 0.215454f, 0.234375f,
+ 0.255371f, 0.276611f, 0.299805f, 0.323486f, 0.347656f, 0.373047f, 0.398682f, 0.425293f, 0.451172f, 0.477783f, 0.504883f, 0.530762f,
+ 0.557617f, 0.583008f, 0.607910f, 0.632812f, 0.657227f, 0.680664f, 0.702637f, 0.724121f, 0.743652f, 0.764160f, 0.783691f, 0.800781f,
+ 0.818848f, 0.833984f, 0.930664f, 0.936035f, 0.936035f, 0.935547f, 0.934570f, 0.933594f, 0.000847f, 0.002800f, 0.004562f, 0.006786f,
+ 0.008804f, 0.011017f, 0.013145f, 0.015640f, 0.018509f, 0.021255f, 0.024277f, 0.027603f, 0.030991f, 0.035248f, 0.039642f, 0.043854f,
+ 0.048798f, 0.054504f, 0.060516f, 0.067017f, 0.073914f, 0.082092f, 0.090515f, 0.099854f, 0.109863f, 0.121521f, 0.133545f, 0.146851f,
+ 0.161133f, 0.176514f, 0.192993f, 0.211426f, 0.230957f, 0.251465f, 0.272705f, 0.295410f, 0.319092f, 0.343994f, 0.369385f, 0.395020f,
+ 0.421631f, 0.448242f, 0.475342f, 0.501953f, 0.529785f, 0.556152f, 0.582031f, 0.608887f, 0.633789f, 0.658203f, 0.681152f, 0.704590f,
+ 0.726074f, 0.748535f, 0.768555f, 0.787109f, 0.804199f, 0.822754f, 0.926758f, 0.931641f, 0.932129f, 0.931641f, 0.931152f, 0.930176f,
+ 0.001035f, 0.002598f, 0.004147f, 0.006062f, 0.007942f, 0.009933f, 0.012405f, 0.014565f, 0.016174f, 0.019135f, 0.021988f, 0.024811f,
+ 0.028259f, 0.031616f, 0.035065f, 0.039429f, 0.043884f, 0.048615f, 0.053833f, 0.059723f, 0.065796f, 0.072693f, 0.080383f, 0.088745f,
+ 0.098206f, 0.107727f, 0.119080f, 0.130981f, 0.143677f, 0.157959f, 0.173218f, 0.189941f, 0.207642f, 0.226929f, 0.247437f, 0.269043f,
+ 0.291748f, 0.315674f, 0.340576f, 0.366211f, 0.392578f, 0.419434f, 0.446533f, 0.473877f, 0.502441f, 0.528320f, 0.556152f, 0.583008f,
+ 0.609375f, 0.635254f, 0.660156f, 0.684082f, 0.706543f, 0.729980f, 0.751953f, 0.771973f, 0.792480f, 0.810547f, 0.922363f, 0.927734f,
+ 0.928223f, 0.928223f, 0.927246f, 0.926758f, 0.000775f, 0.002325f, 0.003843f, 0.005573f, 0.007397f, 0.009163f, 0.010857f, 0.012939f,
+ 0.015312f, 0.017273f, 0.019684f, 0.022537f, 0.025070f, 0.028183f, 0.031616f, 0.035461f, 0.038940f, 0.043671f, 0.048096f, 0.053131f,
+ 0.058411f, 0.064941f, 0.071777f, 0.078857f, 0.086731f, 0.096130f, 0.105835f, 0.116760f, 0.128296f, 0.140747f, 0.154907f, 0.170410f,
+ 0.186646f, 0.204834f, 0.223633f, 0.243896f, 0.265625f, 0.288330f, 0.312012f, 0.337402f, 0.363037f, 0.389648f, 0.417480f, 0.444824f,
+ 0.473633f, 0.500000f, 0.529297f, 0.556641f, 0.583984f, 0.610840f, 0.638184f, 0.662598f, 0.687988f, 0.711914f, 0.734375f, 0.755859f,
+ 0.777832f, 0.798828f, 0.916992f, 0.922852f, 0.923828f, 0.923828f, 0.923340f, 0.922363f, 0.000617f, 0.002234f, 0.003510f, 0.005035f,
+ 0.006397f, 0.008156f, 0.010033f, 0.011665f, 0.013481f, 0.015717f, 0.017700f, 0.020004f, 0.022766f, 0.025391f, 0.028214f, 0.031586f,
+ 0.035217f, 0.038757f, 0.042999f, 0.047668f, 0.052368f, 0.057434f, 0.063538f, 0.070190f, 0.077698f, 0.085449f, 0.094299f, 0.103394f,
+ 0.113953f, 0.125610f, 0.137817f, 0.151855f, 0.167236f, 0.183228f, 0.200806f, 0.219971f, 0.240479f, 0.262451f, 0.285645f, 0.309570f,
+ 0.334961f, 0.360596f, 0.387939f, 0.416016f, 0.444092f, 0.473145f, 0.501465f, 0.529785f, 0.558105f, 0.585938f, 0.614258f, 0.640137f,
+ 0.666992f, 0.692383f, 0.716797f, 0.739746f, 0.763184f, 0.784180f, 0.912109f, 0.918457f, 0.919434f, 0.919434f, 0.918457f, 0.917969f,
+ 0.000665f, 0.002039f, 0.003386f, 0.004520f, 0.005989f, 0.007511f, 0.009262f, 0.010902f, 0.012314f, 0.014320f, 0.015869f, 0.018127f,
+ 0.020248f, 0.022476f, 0.025284f, 0.028122f, 0.030991f, 0.034668f, 0.038239f, 0.042206f, 0.046539f, 0.051361f, 0.056610f, 0.062347f,
+ 0.068604f, 0.075623f, 0.083313f, 0.092041f, 0.101379f, 0.111572f, 0.122986f, 0.135132f, 0.148926f, 0.164062f, 0.180054f, 0.197510f,
+ 0.216797f, 0.237183f, 0.259521f, 0.282227f, 0.307129f, 0.332764f, 0.358887f, 0.386475f, 0.415527f, 0.443604f, 0.473389f, 0.501465f,
+ 0.530762f, 0.560059f, 0.588867f, 0.617676f, 0.645020f, 0.671387f, 0.698242f, 0.722656f, 0.746094f, 0.770020f, 0.906738f, 0.913574f,
+ 0.915039f, 0.914551f, 0.914062f, 0.914062f, 0.000661f, 0.001754f, 0.002831f, 0.004066f, 0.005333f, 0.006668f, 0.008286f, 0.009773f,
+ 0.011124f, 0.012794f, 0.014320f, 0.016357f, 0.018036f, 0.020386f, 0.022766f, 0.025192f, 0.027924f, 0.030807f, 0.034027f, 0.037628f,
+ 0.041321f, 0.045349f, 0.050262f, 0.055328f, 0.060699f, 0.066833f, 0.073669f, 0.081360f, 0.089600f, 0.099060f, 0.108826f, 0.119995f,
+ 0.132324f, 0.145874f, 0.160889f, 0.176880f, 0.194702f, 0.213379f, 0.234497f, 0.256104f, 0.280029f, 0.304688f, 0.330811f, 0.358154f,
+ 0.385986f, 0.415039f, 0.444092f, 0.474609f, 0.503418f, 0.534180f, 0.563965f, 0.592773f, 0.621094f, 0.650391f, 0.678223f, 0.704590f,
+ 0.730469f, 0.754883f, 0.901855f, 0.908691f, 0.910156f, 0.909668f, 0.909668f, 0.908691f, 0.000653f, 0.001667f, 0.002666f, 0.003887f,
+ 0.004986f, 0.006359f, 0.007202f, 0.008751f, 0.010300f, 0.011757f, 0.012939f, 0.014595f, 0.016281f, 0.018234f, 0.020142f, 0.022415f,
+ 0.025101f, 0.027466f, 0.030182f, 0.033539f, 0.036865f, 0.040680f, 0.044342f, 0.048798f, 0.053619f, 0.059479f, 0.065491f, 0.071716f,
+ 0.079285f, 0.087341f, 0.096497f, 0.106445f, 0.117615f, 0.129395f, 0.142822f, 0.157959f, 0.174194f, 0.192139f, 0.210938f, 0.231567f,
+ 0.253906f, 0.277832f, 0.302979f, 0.329590f, 0.357422f, 0.385986f, 0.415283f, 0.446045f, 0.475830f, 0.506348f, 0.537109f, 0.567871f,
+ 0.599121f, 0.628418f, 0.657227f, 0.685547f, 0.712891f, 0.739746f, 0.895508f, 0.902344f, 0.904297f, 0.904785f, 0.904297f, 0.904297f,
+ 0.000372f, 0.001397f, 0.002384f, 0.003529f, 0.004509f, 0.005505f, 0.007015f, 0.008026f, 0.009201f, 0.010292f, 0.011536f, 0.013130f,
+ 0.014915f, 0.016266f, 0.018387f, 0.020218f, 0.022034f, 0.024399f, 0.026901f, 0.029617f, 0.032623f, 0.035950f, 0.039032f, 0.043030f,
+ 0.047577f, 0.052612f, 0.057556f, 0.063477f, 0.070007f, 0.077209f, 0.085083f, 0.094177f, 0.103821f, 0.114563f, 0.126709f, 0.140015f,
+ 0.154785f, 0.171143f, 0.188477f, 0.208252f, 0.229004f, 0.251709f, 0.275879f, 0.302002f, 0.328613f, 0.356445f, 0.385986f, 0.416504f,
+ 0.447510f, 0.478760f, 0.510254f, 0.542480f, 0.573730f, 0.604980f, 0.635742f, 0.665527f, 0.694336f, 0.722656f, 0.887695f, 0.897949f,
+ 0.898926f, 0.899414f, 0.897949f, 0.898438f, 0.000661f, 0.001222f, 0.002275f, 0.003313f, 0.004181f, 0.005119f, 0.006275f, 0.007126f,
+ 0.007988f, 0.009354f, 0.010300f, 0.012062f, 0.013313f, 0.014786f, 0.016251f, 0.018021f, 0.019516f, 0.021896f, 0.024017f, 0.026428f,
+ 0.029022f, 0.031799f, 0.034698f, 0.038422f, 0.042236f, 0.046265f, 0.050598f, 0.055786f, 0.061493f, 0.067871f, 0.074951f, 0.082458f,
+ 0.091187f, 0.101135f, 0.111694f, 0.123779f, 0.137207f, 0.151978f, 0.167969f, 0.186157f, 0.205688f, 0.226929f, 0.249756f, 0.274658f,
+ 0.301025f, 0.328613f, 0.357178f, 0.387207f, 0.418457f, 0.450195f, 0.482422f, 0.516113f, 0.548340f, 0.580566f, 0.612305f, 0.644043f,
+ 0.674805f, 0.705566f, 0.882812f, 0.890625f, 0.892578f, 0.893066f, 0.892578f, 0.893066f, 0.000379f, 0.001211f, 0.002066f, 0.003040f,
+ 0.003834f, 0.004616f, 0.005608f, 0.006550f, 0.007347f, 0.008408f, 0.009529f, 0.010452f, 0.011940f, 0.013039f, 0.014313f, 0.015961f,
+ 0.017746f, 0.019180f, 0.021210f, 0.023239f, 0.025482f, 0.028030f, 0.030640f, 0.033661f, 0.036987f, 0.040466f, 0.044617f, 0.048828f,
+ 0.053894f, 0.059235f, 0.065674f, 0.072632f, 0.079956f, 0.089050f, 0.098267f, 0.109009f, 0.120789f, 0.134521f, 0.148926f, 0.165405f,
+ 0.183228f, 0.202881f, 0.224731f, 0.248779f, 0.273193f, 0.300049f, 0.329346f, 0.358887f, 0.390381f, 0.421387f, 0.454590f, 0.488770f,
+ 0.521484f, 0.555176f, 0.588379f, 0.621582f, 0.654785f, 0.686523f, 0.875488f, 0.885254f, 0.886719f, 0.886230f, 0.886719f, 0.886230f,
+ 0.000282f, 0.001126f, 0.002010f, 0.002661f, 0.003340f, 0.004269f, 0.005192f, 0.005711f, 0.006638f, 0.007278f, 0.008377f, 0.009483f,
+ 0.010567f, 0.011742f, 0.012871f, 0.014061f, 0.015480f, 0.017242f, 0.018799f, 0.020584f, 0.022461f, 0.024490f, 0.027100f, 0.029434f,
+ 0.032532f, 0.035706f, 0.038971f, 0.042969f, 0.047241f, 0.052094f, 0.057373f, 0.063232f, 0.070007f, 0.077637f, 0.086243f, 0.095764f,
+ 0.106323f, 0.118164f, 0.131470f, 0.146118f, 0.162720f, 0.181030f, 0.200928f, 0.223022f, 0.247070f, 0.272705f, 0.300537f, 0.330322f,
+ 0.360107f, 0.393066f, 0.426270f, 0.459473f, 0.494629f, 0.529297f, 0.564453f, 0.598633f, 0.633789f, 0.666504f, 0.868652f, 0.878418f,
+ 0.879395f, 0.880371f, 0.879883f, 0.879395f, 0.000340f, 0.000963f, 0.001826f, 0.002459f, 0.003307f, 0.003847f, 0.004719f, 0.004936f,
+ 0.005802f, 0.006695f, 0.007748f, 0.008522f, 0.009506f, 0.010376f, 0.011383f, 0.012787f, 0.013901f, 0.015182f, 0.016663f, 0.018051f,
+ 0.019821f, 0.021759f, 0.023590f, 0.025818f, 0.028519f, 0.030975f, 0.034210f, 0.037811f, 0.040802f, 0.045349f, 0.050201f, 0.055298f,
+ 0.061310f, 0.067688f, 0.074768f, 0.083557f, 0.092590f, 0.103149f, 0.115479f, 0.128906f, 0.142944f, 0.160278f, 0.178345f, 0.198975f,
+ 0.221802f, 0.246094f, 0.272949f, 0.301514f, 0.331543f, 0.363525f, 0.396729f, 0.430908f, 0.466553f, 0.501953f, 0.538086f, 0.574707f,
+ 0.610840f, 0.646973f, 0.860352f, 0.870605f, 0.873047f, 0.873047f, 0.873535f, 0.872559f, 0.000225f, 0.001021f, 0.001653f, 0.002302f,
+ 0.002827f, 0.003448f, 0.003937f, 0.004486f, 0.004986f, 0.006252f, 0.007000f, 0.007416f, 0.008224f, 0.009300f, 0.009972f, 0.011322f,
+ 0.012115f, 0.013428f, 0.014557f, 0.015991f, 0.017532f, 0.018982f, 0.020706f, 0.022781f, 0.024567f, 0.027161f, 0.029770f, 0.032623f,
+ 0.035828f, 0.039551f, 0.043030f, 0.047852f, 0.052795f, 0.058716f, 0.065125f, 0.072266f, 0.080566f, 0.089661f, 0.100403f, 0.112854f,
+ 0.125732f, 0.140991f, 0.157349f, 0.176514f, 0.197510f, 0.220581f, 0.245850f, 0.273438f, 0.302979f, 0.334717f, 0.367676f, 0.401855f,
+ 0.437256f, 0.474609f, 0.512695f, 0.549316f, 0.588379f, 0.625000f, 0.853027f, 0.863281f, 0.866211f, 0.866211f, 0.866699f, 0.866211f,
+ 0.000324f, 0.000845f, 0.001534f, 0.002172f, 0.002474f, 0.003115f, 0.003824f, 0.003937f, 0.004848f, 0.005417f, 0.006222f, 0.006760f,
+ 0.007446f, 0.008186f, 0.009102f, 0.009888f, 0.010620f, 0.011551f, 0.012878f, 0.013954f, 0.015106f, 0.016495f, 0.018143f, 0.019669f,
+ 0.021713f, 0.023468f, 0.025818f, 0.028183f, 0.031021f, 0.033783f, 0.037445f, 0.041534f, 0.045532f, 0.050598f, 0.056152f, 0.062500f,
+ 0.069580f, 0.077698f, 0.086914f, 0.097717f, 0.108948f, 0.123047f, 0.138184f, 0.155273f, 0.174438f, 0.196167f, 0.219604f, 0.246094f,
+ 0.274902f, 0.305420f, 0.338379f, 0.372314f, 0.408936f, 0.445801f, 0.484131f, 0.523438f, 0.562988f, 0.604492f, 0.843262f, 0.856445f,
+ 0.857422f, 0.857910f, 0.858398f, 0.858398f, 0.000331f, 0.000944f, 0.001288f, 0.001833f, 0.002388f, 0.002769f, 0.003216f, 0.003664f,
+ 0.004276f, 0.004822f, 0.005173f, 0.005951f, 0.006531f, 0.007156f, 0.007896f, 0.008438f, 0.009430f, 0.010117f, 0.011208f, 0.012253f,
+ 0.012970f, 0.014297f, 0.015572f, 0.017059f, 0.018692f, 0.020264f, 0.022125f, 0.024323f, 0.026474f, 0.029343f, 0.032288f, 0.035461f,
+ 0.039062f, 0.043335f, 0.047821f, 0.053558f, 0.059509f, 0.067078f, 0.074341f, 0.083862f, 0.094360f, 0.106323f, 0.120117f, 0.135254f,
+ 0.153442f, 0.172852f, 0.195190f, 0.220337f, 0.246948f, 0.276611f, 0.308594f, 0.343262f, 0.379150f, 0.416992f, 0.455811f, 0.496582f,
+ 0.537598f, 0.579590f, 0.834473f, 0.847656f, 0.850098f, 0.850098f, 0.849609f, 0.850098f, 0.000316f, 0.000824f, 0.001088f, 0.001693f,
+ 0.002062f, 0.002403f, 0.003027f, 0.003460f, 0.003712f, 0.004166f, 0.004765f, 0.005138f, 0.005871f, 0.006218f, 0.006924f, 0.007431f,
+ 0.008255f, 0.008850f, 0.009781f, 0.010590f, 0.011391f, 0.012367f, 0.013474f, 0.014709f, 0.015823f, 0.017685f, 0.018982f, 0.020844f,
+ 0.022629f, 0.025070f, 0.027496f, 0.030380f, 0.033447f, 0.037140f, 0.041168f, 0.045654f, 0.050720f, 0.057251f, 0.063965f, 0.071777f,
+ 0.080811f, 0.091248f, 0.103638f, 0.117126f, 0.133179f, 0.151001f, 0.171631f, 0.194580f, 0.220337f, 0.248413f, 0.279785f, 0.313965f,
+ 0.349365f, 0.386963f, 0.426514f, 0.468262f, 0.510742f, 0.555176f, 0.825684f, 0.838379f, 0.839844f, 0.841309f, 0.841309f, 0.841309f,
+ 0.000210f, 0.000717f, 0.001084f, 0.001454f, 0.001882f, 0.002096f, 0.002468f, 0.002996f, 0.003395f, 0.003632f, 0.004066f, 0.004467f,
+ 0.005020f, 0.005569f, 0.005917f, 0.006474f, 0.006958f, 0.007576f, 0.008453f, 0.009140f, 0.010002f, 0.010689f, 0.011520f, 0.012596f,
+ 0.013695f, 0.014938f, 0.016220f, 0.017593f, 0.019424f, 0.020996f, 0.023331f, 0.025696f, 0.028427f, 0.031067f, 0.034668f, 0.038422f,
+ 0.042908f, 0.048096f, 0.054016f, 0.060699f, 0.068909f, 0.077515f, 0.088501f, 0.100464f, 0.114624f, 0.130615f, 0.149048f, 0.170654f,
+ 0.194214f, 0.222046f, 0.251465f, 0.283936f, 0.319580f, 0.357422f, 0.397461f, 0.440186f, 0.484375f, 0.528320f, 0.814941f, 0.828613f,
+ 0.830078f, 0.832031f, 0.831543f, 0.833008f, 0.000234f, 0.000576f, 0.000939f, 0.001362f, 0.001481f, 0.001999f, 0.002228f, 0.002714f,
+ 0.002846f, 0.003218f, 0.003555f, 0.003933f, 0.004356f, 0.004787f, 0.005169f, 0.005604f, 0.006145f, 0.006554f, 0.007275f, 0.007675f,
+ 0.008293f, 0.009201f, 0.009979f, 0.010651f, 0.011497f, 0.012527f, 0.013893f, 0.014771f, 0.016373f, 0.017975f, 0.019455f, 0.021683f,
+ 0.023895f, 0.026077f, 0.029114f, 0.032257f, 0.036072f, 0.040405f, 0.045197f, 0.050903f, 0.057770f, 0.065613f, 0.074524f, 0.085388f,
+ 0.097656f, 0.111694f, 0.128540f, 0.147949f, 0.170166f, 0.195435f, 0.223389f, 0.255127f, 0.289551f, 0.327393f, 0.367432f, 0.410400f,
+ 0.455078f, 0.502441f, 0.804199f, 0.818848f, 0.821289f, 0.822266f, 0.822754f, 0.822266f, 0.000213f, 0.000506f, 0.000756f, 0.001184f,
+ 0.001396f, 0.001697f, 0.002010f, 0.002474f, 0.002569f, 0.002918f, 0.003090f, 0.003496f, 0.003855f, 0.004139f, 0.004478f, 0.004852f,
+ 0.005253f, 0.005665f, 0.006100f, 0.006638f, 0.007080f, 0.007744f, 0.008293f, 0.009132f, 0.009750f, 0.010658f, 0.011536f, 0.012413f,
+ 0.013779f, 0.014908f, 0.016510f, 0.017990f, 0.019623f, 0.021637f, 0.024109f, 0.026718f, 0.029922f, 0.033539f, 0.037567f, 0.042572f,
+ 0.048279f, 0.054413f, 0.062042f, 0.071472f, 0.081909f, 0.094604f, 0.109436f, 0.127075f, 0.146484f, 0.170044f, 0.196533f, 0.226929f,
+ 0.260254f, 0.296875f, 0.337402f, 0.380615f, 0.426025f, 0.475342f, 0.792969f, 0.807617f, 0.811035f, 0.811523f, 0.812012f, 0.813477f,
+ 0.000119f, 0.000422f, 0.000883f, 0.001027f, 0.001189f, 0.001604f, 0.001783f, 0.001913f, 0.002228f, 0.002522f, 0.002645f, 0.003086f,
+ 0.003199f, 0.003534f, 0.003790f, 0.004105f, 0.004421f, 0.004902f, 0.005283f, 0.005589f, 0.006039f, 0.006401f, 0.007088f, 0.007519f,
+ 0.008217f, 0.008812f, 0.009712f, 0.010460f, 0.011337f, 0.012413f, 0.013596f, 0.014687f, 0.016159f, 0.018051f, 0.019913f, 0.022018f,
+ 0.024551f, 0.027359f, 0.030792f, 0.035065f, 0.039703f, 0.044983f, 0.051392f, 0.059204f, 0.068176f, 0.079102f, 0.092041f, 0.106873f,
+ 0.125000f, 0.145874f, 0.170532f, 0.198975f, 0.230835f, 0.267090f, 0.306641f, 0.349854f, 0.395508f, 0.445801f, 0.780762f, 0.796875f,
+ 0.799805f, 0.801270f, 0.801270f, 0.801270f, 0.000227f, 0.000521f, 0.000698f, 0.000817f, 0.001236f, 0.001359f, 0.001540f, 0.001619f,
+ 0.001940f, 0.002089f, 0.002430f, 0.002552f, 0.002655f, 0.002932f, 0.003241f, 0.003532f, 0.003841f, 0.004120f, 0.004292f, 0.004761f,
+ 0.005051f, 0.005459f, 0.005886f, 0.006290f, 0.006821f, 0.007320f, 0.007889f, 0.008652f, 0.009399f, 0.010063f, 0.010887f, 0.012215f,
+ 0.013206f, 0.014648f, 0.016037f, 0.017853f, 0.019958f, 0.022491f, 0.024994f, 0.028091f, 0.032135f, 0.036530f, 0.041809f, 0.048096f,
+ 0.055908f, 0.064941f, 0.076050f, 0.089050f, 0.104980f, 0.123596f, 0.146118f, 0.172363f, 0.203003f, 0.237183f, 0.276123f, 0.318359f,
+ 0.365479f, 0.416504f, 0.768555f, 0.784668f, 0.788086f, 0.789551f, 0.790039f, 0.790039f, 0.000000f, 0.000448f, 0.000566f, 0.000688f,
+ 0.000985f, 0.001144f, 0.001305f, 0.001437f, 0.001622f, 0.001731f, 0.001989f, 0.002174f, 0.002338f, 0.002552f, 0.002739f, 0.002924f,
+ 0.003239f, 0.003405f, 0.003628f, 0.003933f, 0.004200f, 0.004463f, 0.004948f, 0.005245f, 0.005615f, 0.006138f, 0.006699f, 0.006989f,
+ 0.007793f, 0.008247f, 0.008980f, 0.009918f, 0.010857f, 0.011795f, 0.013016f, 0.014244f, 0.015930f, 0.017868f, 0.019882f, 0.022659f,
+ 0.025543f, 0.029160f, 0.033417f, 0.038635f, 0.044983f, 0.052338f, 0.061859f, 0.072693f, 0.086487f, 0.102966f, 0.122864f, 0.146973f,
+ 0.175049f, 0.207764f, 0.245605f, 0.287842f, 0.334229f, 0.385986f, 0.755371f, 0.771973f, 0.775879f, 0.777344f, 0.777832f, 0.778809f,
+ 0.000000f, 0.000303f, 0.000512f, 0.000752f, 0.000828f, 0.001036f, 0.001184f, 0.001292f, 0.001281f, 0.001460f, 0.001717f, 0.001843f,
+ 0.001955f, 0.002060f, 0.002317f, 0.002476f, 0.002542f, 0.002869f, 0.003088f, 0.003313f, 0.003559f, 0.003693f, 0.004082f, 0.004318f,
+ 0.004696f, 0.005070f, 0.005245f, 0.005741f, 0.006126f, 0.006771f, 0.007298f, 0.007828f, 0.008583f, 0.009338f, 0.010246f, 0.011528f,
+ 0.012794f, 0.014160f, 0.015717f, 0.017853f, 0.019958f, 0.022995f, 0.026291f, 0.030533f, 0.035553f, 0.041565f, 0.048981f, 0.058350f,
+ 0.069824f, 0.083801f, 0.101685f, 0.122437f, 0.148438f, 0.178833f, 0.215454f, 0.256104f, 0.302490f, 0.354736f, 0.741699f, 0.758789f,
+ 0.762695f, 0.763672f, 0.764648f, 0.765625f, 0.000097f, 0.000306f, 0.000370f, 0.000618f, 0.000713f, 0.000810f, 0.000953f, 0.000920f,
+ 0.001167f, 0.001238f, 0.001406f, 0.001483f, 0.001540f, 0.001794f, 0.001970f, 0.002028f, 0.002264f, 0.002354f, 0.002459f, 0.002636f,
+ 0.002827f, 0.003096f, 0.003342f, 0.003544f, 0.003881f, 0.003948f, 0.004459f, 0.004742f, 0.005005f, 0.005394f, 0.005867f, 0.006374f,
+ 0.006901f, 0.007507f, 0.008202f, 0.008881f, 0.010017f, 0.010986f, 0.012451f, 0.013809f, 0.015511f, 0.017776f, 0.020325f, 0.023453f,
+ 0.027390f, 0.032349f, 0.038330f, 0.045624f, 0.055359f, 0.067078f, 0.082275f, 0.101013f, 0.123657f, 0.151611f, 0.185791f, 0.225342f,
+ 0.270752f, 0.322754f, 0.727051f, 0.746094f, 0.749512f, 0.750977f, 0.751953f, 0.751953f, 0.000228f, 0.000211f, 0.000504f, 0.000443f,
+ 0.000523f, 0.000672f, 0.000703f, 0.000902f, 0.000975f, 0.001010f, 0.001122f, 0.001178f, 0.001257f, 0.001424f, 0.001575f, 0.001631f,
+ 0.001789f, 0.001910f, 0.002090f, 0.002144f, 0.002411f, 0.002520f, 0.002703f, 0.002827f, 0.003010f, 0.003195f, 0.003403f, 0.003750f,
+ 0.003960f, 0.004276f, 0.004780f, 0.005005f, 0.005432f, 0.005981f, 0.006428f, 0.007015f, 0.007812f, 0.008537f, 0.009415f, 0.010658f,
+ 0.011963f, 0.013443f, 0.015396f, 0.017731f, 0.020782f, 0.024414f, 0.029083f, 0.034912f, 0.042572f, 0.052216f, 0.064392f, 0.080017f,
+ 0.100220f, 0.126099f, 0.157227f, 0.194946f, 0.239136f, 0.290283f, 0.712402f, 0.731445f, 0.734863f, 0.736816f, 0.737305f, 0.737793f,
+ 0.000211f, 0.000198f, 0.000195f, 0.000413f, 0.000517f, 0.000531f, 0.000586f, 0.000736f, 0.000769f, 0.000809f, 0.000970f, 0.001007f,
+ 0.001067f, 0.001134f, 0.001211f, 0.001348f, 0.001341f, 0.001534f, 0.001617f, 0.001734f, 0.001942f, 0.002010f, 0.002110f, 0.002268f,
+ 0.002523f, 0.002607f, 0.002829f, 0.003004f, 0.003113f, 0.003403f, 0.003681f, 0.003990f, 0.004257f, 0.004601f, 0.005039f, 0.005444f,
+ 0.005993f, 0.006561f, 0.007278f, 0.008026f, 0.009041f, 0.010124f, 0.011513f, 0.013222f, 0.015320f, 0.017914f, 0.021408f, 0.025833f,
+ 0.031433f, 0.039429f, 0.049255f, 0.062286f, 0.079102f, 0.101135f, 0.130005f, 0.164917f, 0.207764f, 0.258057f, 0.696289f, 0.716309f,
+ 0.720215f, 0.722168f, 0.722656f, 0.723145f, 0.000000f, 0.000080f, 0.000286f, 0.000374f, 0.000434f, 0.000457f, 0.000460f, 0.000568f,
+ 0.000610f, 0.000669f, 0.000715f, 0.000773f, 0.000877f, 0.000918f, 0.001030f, 0.000998f, 0.001148f, 0.001134f, 0.001305f, 0.001369f,
+ 0.001410f, 0.001534f, 0.001688f, 0.001780f, 0.001899f, 0.001963f, 0.002081f, 0.002199f, 0.002470f, 0.002563f, 0.002758f, 0.003006f,
+ 0.003273f, 0.003531f, 0.003817f, 0.004093f, 0.004532f, 0.004993f, 0.005463f, 0.006027f, 0.006657f, 0.007492f, 0.008537f, 0.009689f,
+ 0.011246f, 0.012985f, 0.015518f, 0.018539f, 0.022827f, 0.028534f, 0.036072f, 0.046234f, 0.060028f, 0.078918f, 0.103943f, 0.136353f,
+ 0.176514f, 0.225952f, 0.679199f, 0.699707f, 0.703613f, 0.706055f, 0.706543f, 0.708008f, 0.000089f, 0.000176f, 0.000232f, 0.000342f,
+ 0.000317f, 0.000319f, 0.000420f, 0.000382f, 0.000494f, 0.000515f, 0.000612f, 0.000650f, 0.000671f, 0.000701f, 0.000732f, 0.000859f,
+ 0.000888f, 0.000923f, 0.001002f, 0.001048f, 0.001170f, 0.001234f, 0.001292f, 0.001426f, 0.001414f, 0.001476f, 0.001622f, 0.001723f,
+ 0.001892f, 0.001976f, 0.002237f, 0.002239f, 0.002476f, 0.002645f, 0.002817f, 0.003092f, 0.003355f, 0.003626f, 0.003979f, 0.004459f,
+ 0.004948f, 0.005527f, 0.006256f, 0.007027f, 0.008026f, 0.009270f, 0.010918f, 0.013184f, 0.016098f, 0.019913f, 0.025253f, 0.033112f,
+ 0.043762f, 0.059113f, 0.079956f, 0.109009f, 0.146729f, 0.193726f, 0.660645f, 0.682129f, 0.688477f, 0.690430f, 0.689941f, 0.690918f,
+ 0.000000f, 0.000063f, 0.000194f, 0.000281f, 0.000187f, 0.000325f, 0.000278f, 0.000272f, 0.000386f, 0.000466f, 0.000462f, 0.000510f,
+ 0.000519f, 0.000587f, 0.000613f, 0.000603f, 0.000671f, 0.000709f, 0.000744f, 0.000808f, 0.000858f, 0.000913f, 0.000963f, 0.000999f,
+ 0.001062f, 0.001106f, 0.001262f, 0.001266f, 0.001431f, 0.001562f, 0.001672f, 0.001693f, 0.001810f, 0.001976f, 0.002090f, 0.002289f,
+ 0.002422f, 0.002666f, 0.002916f, 0.003166f, 0.003513f, 0.003862f, 0.004318f, 0.004936f, 0.005646f, 0.006493f, 0.007626f, 0.009048f,
+ 0.010826f, 0.013519f, 0.017166f, 0.022476f, 0.030258f, 0.041687f, 0.058807f, 0.083435f, 0.117737f, 0.162598f, 0.644043f, 0.666504f,
+ 0.670410f, 0.673340f, 0.674316f, 0.675293f, 0.000000f, 0.000117f, 0.000112f, 0.000178f, 0.000216f, 0.000222f, 0.000271f, 0.000229f,
+ 0.000280f, 0.000283f, 0.000326f, 0.000376f, 0.000376f, 0.000443f, 0.000456f, 0.000470f, 0.000499f, 0.000507f, 0.000547f, 0.000566f,
+ 0.000613f, 0.000667f, 0.000692f, 0.000749f, 0.000773f, 0.000803f, 0.000917f, 0.000924f, 0.000997f, 0.001055f, 0.001096f, 0.001236f,
+ 0.001261f, 0.001376f, 0.001466f, 0.001693f, 0.001695f, 0.001826f, 0.002077f, 0.002226f, 0.002411f, 0.002686f, 0.002985f, 0.003368f,
+ 0.003801f, 0.004353f, 0.005131f, 0.005974f, 0.007370f, 0.008842f, 0.011345f, 0.014717f, 0.019699f, 0.027893f, 0.040619f, 0.060730f,
+ 0.090454f, 0.132080f, 0.625488f, 0.649414f, 0.653809f, 0.655273f, 0.656250f, 0.658203f, 0.000000f, 0.000000f, 0.000108f, 0.000121f,
+ 0.000136f, 0.000154f, 0.000158f, 0.000191f, 0.000203f, 0.000213f, 0.000270f, 0.000223f, 0.000232f, 0.000270f, 0.000296f, 0.000342f,
+ 0.000324f, 0.000352f, 0.000453f, 0.000407f, 0.000450f, 0.000459f, 0.000486f, 0.000524f, 0.000545f, 0.000565f, 0.000630f, 0.000620f,
+ 0.000678f, 0.000803f, 0.000763f, 0.000813f, 0.000860f, 0.000937f, 0.001035f, 0.001101f, 0.001141f, 0.001254f, 0.001399f, 0.001449f,
+ 0.001616f, 0.001779f, 0.001942f, 0.002220f, 0.002493f, 0.002808f, 0.003258f, 0.003895f, 0.004623f, 0.005714f, 0.007111f, 0.009178f,
+ 0.012367f, 0.017319f, 0.025879f, 0.040741f, 0.065552f, 0.103577f, 0.606934f, 0.630371f, 0.635254f, 0.637695f, 0.638672f, 0.639648f,
+ 0.000000f, 0.000109f, 0.000102f, 0.000098f, 0.000105f, 0.000110f, 0.000113f, 0.000122f, 0.000117f, 0.000132f, 0.000147f, 0.000189f,
+ 0.000163f, 0.000212f, 0.000213f, 0.000222f, 0.000224f, 0.000233f, 0.000258f, 0.000262f, 0.000274f, 0.000305f, 0.000340f, 0.000329f,
+ 0.000358f, 0.000376f, 0.000445f, 0.000418f, 0.000447f, 0.000478f, 0.000546f, 0.000530f, 0.000594f, 0.000626f, 0.000679f, 0.000745f,
+ 0.000763f, 0.000804f, 0.000869f, 0.000952f, 0.001025f, 0.001119f, 0.001254f, 0.001359f, 0.001584f, 0.001728f, 0.001993f, 0.002295f,
+ 0.002790f, 0.003298f, 0.004135f, 0.005363f, 0.007267f, 0.010277f, 0.015350f, 0.024994f, 0.043518f, 0.076599f, 0.585938f, 0.611816f,
+ 0.616211f, 0.619141f, 0.619629f, 0.620605f, 0.000000f, 0.000102f, 0.000095f, 0.000090f, 0.000085f, 0.000081f, 0.000078f, 0.000073f,
+ 0.000075f, 0.000079f, 0.000087f, 0.000092f, 0.000095f, 0.000094f, 0.000133f, 0.000143f, 0.000152f, 0.000155f, 0.000161f, 0.000195f,
+ 0.000174f, 0.000183f, 0.000188f, 0.000216f, 0.000233f, 0.000241f, 0.000241f, 0.000257f, 0.000269f, 0.000302f, 0.000325f, 0.000321f,
+ 0.000350f, 0.000363f, 0.000405f, 0.000426f, 0.000456f, 0.000486f, 0.000539f, 0.000560f, 0.000614f, 0.000671f, 0.000722f, 0.000811f,
+ 0.000891f, 0.000989f, 0.001162f, 0.001312f, 0.001545f, 0.001863f, 0.002340f, 0.002920f, 0.003963f, 0.005615f, 0.008499f, 0.013931f,
+ 0.025833f, 0.052094f, 0.566406f, 0.591797f, 0.597168f, 0.599609f, 0.601074f, 0.601562f, 0.000110f, 0.000092f, 0.000084f, 0.000077f,
+ 0.000073f, 0.000070f, 0.000067f, 0.000064f, 0.000061f, 0.000058f, 0.000055f, 0.000064f, 0.000051f, 0.000054f, 0.000071f, 0.000059f,
+ 0.000082f, 0.000081f, 0.000090f, 0.000087f, 0.000099f, 0.000103f, 0.000127f, 0.000131f, 0.000135f, 0.000139f, 0.000142f, 0.000143f,
+ 0.000156f, 0.000162f, 0.000173f, 0.000194f, 0.000206f, 0.000201f, 0.000233f, 0.000225f, 0.000246f, 0.000294f, 0.000279f, 0.000313f,
+ 0.000333f, 0.000356f, 0.000395f, 0.000432f, 0.000459f, 0.000511f, 0.000577f, 0.000664f, 0.000770f, 0.000916f, 0.001114f, 0.001400f,
+ 0.001881f, 0.002665f, 0.004093f, 0.006966f, 0.013290f, 0.031525f, 0.545410f, 0.571777f, 0.577637f, 0.579102f, 0.580566f, 0.581055f,
+ 0.000093f, 0.000073f, 0.000066f, 0.000061f, 0.000056f, 0.000054f, 0.000051f, 0.000050f, 0.000048f, 0.000047f, 0.000045f, 0.000044f,
+ 0.000042f, 0.000040f, 0.000038f, 0.000036f, 0.000039f, 0.000033f, 0.000041f, 0.000040f, 0.000046f, 0.000048f, 0.000051f, 0.000057f,
+ 0.000060f, 0.000066f, 0.000062f, 0.000067f, 0.000080f, 0.000085f, 0.000088f, 0.000092f, 0.000092f, 0.000097f, 0.000109f, 0.000109f,
+ 0.000117f, 0.000132f, 0.000134f, 0.000147f, 0.000154f, 0.000156f, 0.000188f, 0.000197f, 0.000219f, 0.000234f, 0.000266f, 0.000286f,
+ 0.000335f, 0.000397f, 0.000472f, 0.000566f, 0.000751f, 0.001039f, 0.001626f, 0.002834f, 0.005909f, 0.015411f, 0.524414f, 0.551270f,
+ 0.557129f, 0.559570f, 0.561035f, 0.561523f, 0.000060f, 0.000046f, 0.000039f, 0.000037f, 0.000034f, 0.000034f, 0.000032f, 0.000032f,
+ 0.000031f, 0.000029f, 0.000029f, 0.000029f, 0.000028f, 0.000028f, 0.000028f, 0.000027f, 0.000026f, 0.000025f, 0.000024f, 0.000023f,
+ 0.000022f, 0.000021f, 0.000020f, 0.000021f, 0.000020f, 0.000018f, 0.000018f, 0.000023f, 0.000024f, 0.000028f, 0.000032f, 0.000033f,
+ 0.000032f, 0.000038f, 0.000039f, 0.000043f, 0.000046f, 0.000050f, 0.000052f, 0.000053f, 0.000057f, 0.000067f, 0.000073f, 0.000068f,
+ 0.000076f, 0.000083f, 0.000097f, 0.000110f, 0.000116f, 0.000127f, 0.000157f, 0.000185f, 0.000246f, 0.000319f, 0.000466f, 0.000810f,
+ 0.001841f, 0.005795f, 0.503418f, 0.531250f, 0.536621f, 0.539062f, 0.540039f, 0.540527f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000004f, 0.000005f, 0.000005f, 0.000008f, 0.000008f, 0.000009f, 0.000009f, 0.000010f, 0.000010f, 0.000010f, 0.000010f, 0.000011f,
+ 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000012f, 0.000012f, 0.000012f, 0.000012f, 0.000012f, 0.000012f, 0.000011f, 0.000011f,
+ 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000008f, 0.000008f, 0.000009f, 0.000009f, 0.000010f, 0.000012f,
+ 0.000013f, 0.000014f, 0.000015f, 0.000017f, 0.000020f, 0.000021f, 0.000018f, 0.000023f, 0.000023f, 0.000025f, 0.000030f, 0.000038f,
+ 0.000043f, 0.000059f, 0.000079f, 0.000131f, 0.000279f, 0.001210f, 0.481934f, 0.510254f, 0.516113f, 0.518555f, 0.520020f, 0.520508f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000004f, 0.000006f, 0.000022f, 0.460449f, 0.489258f,
+ 0.495850f, 0.498291f, 0.499512f, 0.500000f,
+ },
+ {
+ 0.038544f, 0.111450f, 0.177368f, 0.237061f, 0.290771f, 0.339600f, 0.384277f, 0.425293f, 0.462402f, 0.497070f, 0.527344f, 0.556152f,
+ 0.583496f, 0.607910f, 0.630859f, 0.652344f, 0.672852f, 0.690918f, 0.708496f, 0.724609f, 0.740723f, 0.754883f, 0.768066f, 0.780273f,
+ 0.792480f, 0.803711f, 0.815430f, 0.825684f, 0.835449f, 0.844727f, 0.853516f, 0.861816f, 0.870117f, 0.877930f, 0.885254f, 0.892578f,
+ 0.899414f, 0.905762f, 0.912109f, 0.918945f, 0.923828f, 0.928711f, 0.934082f, 0.939941f, 0.944824f, 0.949707f, 0.953613f, 0.958496f,
+ 0.962402f, 0.967285f, 0.971191f, 0.974609f, 0.979004f, 0.982422f, 0.985352f, 0.989258f, 0.992188f, 0.996094f, 0.996094f, 0.990723f,
+ 0.986328f, 0.982422f, 0.978516f, 0.975098f, 0.029068f, 0.087219f, 0.142578f, 0.195190f, 0.244629f, 0.291016f, 0.334717f, 0.375000f,
+ 0.412842f, 0.446533f, 0.481201f, 0.511230f, 0.539062f, 0.565918f, 0.590820f, 0.614258f, 0.636719f, 0.656250f, 0.675293f, 0.693359f,
+ 0.710449f, 0.726562f, 0.741699f, 0.755371f, 0.769043f, 0.781738f, 0.793457f, 0.805176f, 0.815918f, 0.826660f, 0.835938f, 0.845703f,
+ 0.854980f, 0.862793f, 0.871582f, 0.879395f, 0.885742f, 0.894531f, 0.900879f, 0.907227f, 0.913086f, 0.919434f, 0.925293f, 0.931152f,
+ 0.936523f, 0.941406f, 0.946777f, 0.951172f, 0.956055f, 0.960449f, 0.964355f, 0.968750f, 0.972656f, 0.976562f, 0.980469f, 0.984375f,
+ 0.987793f, 0.991211f, 0.994141f, 0.989258f, 0.984863f, 0.981445f, 0.977539f, 0.974121f, 0.023346f, 0.069641f, 0.115601f, 0.160767f,
+ 0.205078f, 0.248047f, 0.289062f, 0.328125f, 0.365723f, 0.401367f, 0.435059f, 0.466309f, 0.495361f, 0.523926f, 0.550781f, 0.574707f,
+ 0.597168f, 0.620117f, 0.641113f, 0.660156f, 0.679688f, 0.696777f, 0.713379f, 0.728516f, 0.743652f, 0.757324f, 0.770996f, 0.784180f,
+ 0.795410f, 0.806641f, 0.817383f, 0.828125f, 0.837891f, 0.847168f, 0.855957f, 0.864258f, 0.873047f, 0.880859f, 0.888672f, 0.895996f,
+ 0.902832f, 0.909668f, 0.915039f, 0.921875f, 0.927246f, 0.934082f, 0.937988f, 0.943848f, 0.948242f, 0.953613f, 0.958496f, 0.962402f,
+ 0.967285f, 0.971191f, 0.975098f, 0.979492f, 0.983398f, 0.985840f, 0.992188f, 0.987305f, 0.983398f, 0.979980f, 0.977051f, 0.973633f,
+ 0.018600f, 0.056366f, 0.094299f, 0.133545f, 0.172729f, 0.211670f, 0.249756f, 0.285889f, 0.322021f, 0.356934f, 0.390869f, 0.421875f,
+ 0.452148f, 0.481201f, 0.509277f, 0.535156f, 0.560059f, 0.583496f, 0.605957f, 0.626465f, 0.647949f, 0.665527f, 0.684570f, 0.700684f,
+ 0.717285f, 0.731934f, 0.746582f, 0.760254f, 0.773926f, 0.786621f, 0.799316f, 0.809082f, 0.820312f, 0.830566f, 0.840332f, 0.850098f,
+ 0.858887f, 0.867188f, 0.875000f, 0.883789f, 0.890625f, 0.898926f, 0.904297f, 0.912109f, 0.916992f, 0.924316f, 0.930176f, 0.935547f,
+ 0.941406f, 0.945801f, 0.951172f, 0.956055f, 0.960938f, 0.964844f, 0.969727f, 0.974609f, 0.978516f, 0.981934f, 0.989746f, 0.985840f,
+ 0.981934f, 0.978516f, 0.975586f, 0.972168f, 0.015068f, 0.046143f, 0.077881f, 0.111816f, 0.145264f, 0.179688f, 0.214600f, 0.249023f,
+ 0.282715f, 0.316406f, 0.348389f, 0.380615f, 0.411133f, 0.440430f, 0.468018f, 0.494873f, 0.520508f, 0.546387f, 0.568848f, 0.591309f,
+ 0.613281f, 0.634277f, 0.653809f, 0.670898f, 0.688477f, 0.706055f, 0.721191f, 0.736328f, 0.751465f, 0.764648f, 0.776855f, 0.789551f,
+ 0.801270f, 0.812500f, 0.823730f, 0.833496f, 0.843262f, 0.853027f, 0.861328f, 0.869629f, 0.878418f, 0.885742f, 0.893555f, 0.900391f,
+ 0.908203f, 0.914551f, 0.921387f, 0.927246f, 0.932617f, 0.938965f, 0.943848f, 0.949219f, 0.953613f, 0.959473f, 0.963867f, 0.968262f,
+ 0.972656f, 0.977051f, 0.987305f, 0.983887f, 0.980957f, 0.977051f, 0.974121f, 0.970703f, 0.012444f, 0.037933f, 0.065613f, 0.093811f,
+ 0.123474f, 0.153809f, 0.185059f, 0.215820f, 0.247559f, 0.279297f, 0.310547f, 0.341309f, 0.370361f, 0.399658f, 0.428467f, 0.457031f,
+ 0.482910f, 0.507812f, 0.533203f, 0.556152f, 0.579590f, 0.600098f, 0.621094f, 0.641113f, 0.659668f, 0.676270f, 0.695312f, 0.710449f,
+ 0.726074f, 0.740723f, 0.756348f, 0.769043f, 0.780762f, 0.794434f, 0.805176f, 0.816895f, 0.827637f, 0.837891f, 0.847168f, 0.855957f,
+ 0.865723f, 0.873535f, 0.882324f, 0.889648f, 0.897949f, 0.904297f, 0.911133f, 0.917480f, 0.924316f, 0.930176f, 0.936523f, 0.941895f,
+ 0.947266f, 0.952637f, 0.958008f, 0.962891f, 0.967285f, 0.971680f, 0.984863f, 0.981934f, 0.978516f, 0.975586f, 0.972656f, 0.969238f,
+ 0.010353f, 0.032043f, 0.055359f, 0.079529f, 0.104980f, 0.131836f, 0.159424f, 0.187866f, 0.216431f, 0.245239f, 0.275146f, 0.304199f,
+ 0.333496f, 0.362061f, 0.390869f, 0.417969f, 0.445068f, 0.471191f, 0.496582f, 0.520508f, 0.543457f, 0.566895f, 0.588867f, 0.608398f,
+ 0.628906f, 0.648438f, 0.666992f, 0.684570f, 0.701660f, 0.716797f, 0.732422f, 0.746582f, 0.760254f, 0.773438f, 0.786133f, 0.798340f,
+ 0.810547f, 0.821777f, 0.832520f, 0.842773f, 0.851074f, 0.860352f, 0.869629f, 0.878906f, 0.886230f, 0.894043f, 0.901855f, 0.908691f,
+ 0.915527f, 0.922363f, 0.928223f, 0.935059f, 0.939941f, 0.945312f, 0.950684f, 0.956055f, 0.962402f, 0.966797f, 0.982910f, 0.979980f,
+ 0.977051f, 0.973633f, 0.970703f, 0.968262f, 0.008598f, 0.027328f, 0.046417f, 0.067871f, 0.089905f, 0.113220f, 0.137695f, 0.163330f,
+ 0.189087f, 0.216064f, 0.243164f, 0.270752f, 0.298340f, 0.326416f, 0.354004f, 0.381348f, 0.407715f, 0.434082f, 0.460205f, 0.484863f,
+ 0.508789f, 0.532227f, 0.555176f, 0.577637f, 0.598145f, 0.618652f, 0.637695f, 0.657227f, 0.674805f, 0.691406f, 0.708008f, 0.723633f,
+ 0.738770f, 0.751953f, 0.766113f, 0.779785f, 0.791992f, 0.804199f, 0.815918f, 0.825684f, 0.836914f, 0.846680f, 0.856934f, 0.866211f,
+ 0.874512f, 0.882324f, 0.890625f, 0.898438f, 0.905273f, 0.913086f, 0.919922f, 0.926758f, 0.933105f, 0.938477f, 0.944824f, 0.951172f,
+ 0.955566f, 0.960938f, 0.980469f, 0.978027f, 0.974609f, 0.972168f, 0.969238f, 0.966797f, 0.007561f, 0.023315f, 0.040344f, 0.058228f,
+ 0.077148f, 0.097534f, 0.119995f, 0.142212f, 0.165649f, 0.190063f, 0.214722f, 0.240601f, 0.266846f, 0.293457f, 0.319824f, 0.346924f,
+ 0.372314f, 0.398438f, 0.424561f, 0.449463f, 0.474609f, 0.498535f, 0.521973f, 0.544434f, 0.566895f, 0.587402f, 0.608398f, 0.628418f,
+ 0.645996f, 0.665039f, 0.683105f, 0.699219f, 0.716309f, 0.731445f, 0.745117f, 0.760254f, 0.772949f, 0.786133f, 0.799316f, 0.809570f,
+ 0.820801f, 0.832031f, 0.843262f, 0.852051f, 0.861816f, 0.871094f, 0.880371f, 0.887695f, 0.895996f, 0.904297f, 0.911133f, 0.917969f,
+ 0.924805f, 0.931641f, 0.937012f, 0.943848f, 0.949707f, 0.954590f, 0.978027f, 0.976074f, 0.973145f, 0.970215f, 0.967773f, 0.965332f,
+ 0.006416f, 0.020065f, 0.034943f, 0.050537f, 0.067078f, 0.084900f, 0.104065f, 0.123962f, 0.145264f, 0.166748f, 0.189575f, 0.213501f,
+ 0.237305f, 0.262451f, 0.288574f, 0.313477f, 0.338623f, 0.364502f, 0.389893f, 0.414551f, 0.440186f, 0.464600f, 0.487549f, 0.510742f,
+ 0.534668f, 0.556641f, 0.578613f, 0.598145f, 0.618652f, 0.637207f, 0.655273f, 0.674805f, 0.690430f, 0.707031f, 0.724121f, 0.739258f,
+ 0.752930f, 0.767090f, 0.779785f, 0.792969f, 0.805176f, 0.816895f, 0.827637f, 0.838379f, 0.849121f, 0.858398f, 0.868652f, 0.876465f,
+ 0.885742f, 0.894043f, 0.901855f, 0.909180f, 0.916992f, 0.923828f, 0.930176f, 0.937012f, 0.943359f, 0.949707f, 0.975586f, 0.973633f,
+ 0.971191f, 0.968262f, 0.965820f, 0.963379f, 0.005802f, 0.017502f, 0.030045f, 0.043823f, 0.058014f, 0.074280f, 0.090759f, 0.108459f,
+ 0.127197f, 0.146484f, 0.167725f, 0.189087f, 0.211304f, 0.234497f, 0.258301f, 0.282471f, 0.307373f, 0.331299f, 0.356689f, 0.381104f,
+ 0.405762f, 0.430420f, 0.455078f, 0.478516f, 0.502441f, 0.524414f, 0.545898f, 0.568359f, 0.588867f, 0.608887f, 0.628906f, 0.646973f,
+ 0.665527f, 0.684082f, 0.701172f, 0.715820f, 0.731934f, 0.746582f, 0.760742f, 0.774414f, 0.787598f, 0.800781f, 0.812500f, 0.823730f,
+ 0.834961f, 0.845703f, 0.855469f, 0.865234f, 0.874512f, 0.883789f, 0.892090f, 0.899902f, 0.908203f, 0.916016f, 0.922852f, 0.930176f,
+ 0.936523f, 0.942871f, 0.972656f, 0.971191f, 0.968750f, 0.966309f, 0.963867f, 0.961426f, 0.004734f, 0.014984f, 0.026169f, 0.038177f,
+ 0.051208f, 0.065186f, 0.079468f, 0.095276f, 0.111633f, 0.129639f, 0.148071f, 0.167969f, 0.188599f, 0.208984f, 0.231689f, 0.254639f,
+ 0.277832f, 0.301025f, 0.325439f, 0.349854f, 0.373779f, 0.397705f, 0.422607f, 0.446045f, 0.469727f, 0.492676f, 0.514648f, 0.537598f,
+ 0.559570f, 0.580078f, 0.600586f, 0.620117f, 0.639648f, 0.658203f, 0.676758f, 0.692871f, 0.708984f, 0.725586f, 0.740723f, 0.755859f,
+ 0.769531f, 0.783691f, 0.796875f, 0.808594f, 0.820801f, 0.832520f, 0.842285f, 0.852539f, 0.862793f, 0.872070f, 0.881836f, 0.890137f,
+ 0.898926f, 0.906738f, 0.915039f, 0.922363f, 0.929199f, 0.936523f, 0.969727f, 0.968750f, 0.966797f, 0.964355f, 0.961914f, 0.959473f,
+ 0.004055f, 0.013588f, 0.023132f, 0.033722f, 0.044891f, 0.057343f, 0.069763f, 0.083923f, 0.098389f, 0.114441f, 0.131226f, 0.148682f,
+ 0.167603f, 0.186768f, 0.207031f, 0.228516f, 0.250732f, 0.272949f, 0.295410f, 0.318604f, 0.342285f, 0.365967f, 0.390381f, 0.413574f,
+ 0.437744f, 0.460938f, 0.484131f, 0.506348f, 0.528320f, 0.550781f, 0.572266f, 0.592773f, 0.613281f, 0.632812f, 0.651367f, 0.669922f,
+ 0.687500f, 0.704102f, 0.720215f, 0.735840f, 0.751465f, 0.764160f, 0.778809f, 0.792480f, 0.803711f, 0.816895f, 0.829102f, 0.840332f,
+ 0.850586f, 0.860352f, 0.870605f, 0.880371f, 0.889648f, 0.897949f, 0.905762f, 0.914551f, 0.922363f, 0.929199f, 0.967285f, 0.966797f,
+ 0.964844f, 0.961426f, 0.959473f, 0.958008f, 0.003611f, 0.011971f, 0.020401f, 0.030029f, 0.039185f, 0.050415f, 0.061737f, 0.074341f,
+ 0.086975f, 0.101074f, 0.115845f, 0.131958f, 0.148682f, 0.166626f, 0.185059f, 0.205200f, 0.224854f, 0.245483f, 0.267334f, 0.290771f,
+ 0.312988f, 0.335449f, 0.359619f, 0.382080f, 0.406250f, 0.429443f, 0.452881f, 0.475830f, 0.498779f, 0.520996f, 0.542480f, 0.563477f,
+ 0.584473f, 0.604980f, 0.625977f, 0.643555f, 0.663086f, 0.681152f, 0.698242f, 0.714355f, 0.729980f, 0.746582f, 0.760742f, 0.774902f,
+ 0.788086f, 0.801758f, 0.814941f, 0.826660f, 0.838867f, 0.848633f, 0.859863f, 0.869141f, 0.879395f, 0.889160f, 0.897949f, 0.906250f,
+ 0.914551f, 0.922363f, 0.963867f, 0.964355f, 0.961914f, 0.959961f, 0.957520f, 0.955078f, 0.003393f, 0.010361f, 0.018494f, 0.026337f,
+ 0.035187f, 0.044556f, 0.054596f, 0.065186f, 0.077515f, 0.089783f, 0.102783f, 0.117249f, 0.132446f, 0.148071f, 0.165649f, 0.183838f,
+ 0.202026f, 0.221313f, 0.241943f, 0.262939f, 0.285156f, 0.307129f, 0.329102f, 0.352539f, 0.375977f, 0.398438f, 0.421875f, 0.445312f,
+ 0.468750f, 0.490723f, 0.512695f, 0.534668f, 0.556641f, 0.577637f, 0.598633f, 0.619141f, 0.637695f, 0.656738f, 0.674805f, 0.692383f,
+ 0.709473f, 0.726074f, 0.742188f, 0.756836f, 0.771973f, 0.786133f, 0.799316f, 0.812012f, 0.824707f, 0.835938f, 0.848145f, 0.858887f,
+ 0.868164f, 0.878906f, 0.888184f, 0.897949f, 0.906250f, 0.914551f, 0.960938f, 0.960938f, 0.959473f, 0.957520f, 0.955078f, 0.953125f,
+ 0.003084f, 0.009521f, 0.016144f, 0.023346f, 0.031204f, 0.039520f, 0.048523f, 0.057953f, 0.068359f, 0.079895f, 0.091309f, 0.104126f,
+ 0.117920f, 0.132324f, 0.147949f, 0.164062f, 0.181396f, 0.199219f, 0.218872f, 0.238403f, 0.258545f, 0.279541f, 0.301758f, 0.323486f,
+ 0.346191f, 0.368408f, 0.391846f, 0.414795f, 0.437256f, 0.460693f, 0.483643f, 0.505371f, 0.527832f, 0.550293f, 0.571289f, 0.591797f,
+ 0.612305f, 0.632324f, 0.651855f, 0.670898f, 0.687500f, 0.705566f, 0.722168f, 0.737793f, 0.753418f, 0.768555f, 0.783691f, 0.796875f,
+ 0.811035f, 0.823242f, 0.834473f, 0.846191f, 0.857422f, 0.868652f, 0.878418f, 0.887695f, 0.897949f, 0.906250f, 0.958008f, 0.958008f,
+ 0.957031f, 0.954590f, 0.952637f, 0.950684f, 0.002666f, 0.008293f, 0.014297f, 0.021225f, 0.027847f, 0.035156f, 0.043274f, 0.051666f,
+ 0.060791f, 0.070801f, 0.081543f, 0.092407f, 0.104858f, 0.118530f, 0.131836f, 0.146606f, 0.162598f, 0.179443f, 0.196777f, 0.215210f,
+ 0.234375f, 0.254150f, 0.274414f, 0.295898f, 0.317871f, 0.340088f, 0.362549f, 0.385010f, 0.407959f, 0.430664f, 0.454590f, 0.476562f,
+ 0.499268f, 0.521484f, 0.543945f, 0.564941f, 0.585938f, 0.606934f, 0.626465f, 0.646484f, 0.665527f, 0.683594f, 0.701660f, 0.717773f,
+ 0.735352f, 0.751465f, 0.766113f, 0.781738f, 0.794922f, 0.808105f, 0.821289f, 0.833496f, 0.846191f, 0.857910f, 0.868164f, 0.878906f,
+ 0.889160f, 0.899414f, 0.954102f, 0.955566f, 0.953613f, 0.952148f, 0.950195f, 0.948730f, 0.002396f, 0.007427f, 0.012978f, 0.018646f,
+ 0.025024f, 0.031403f, 0.038788f, 0.046112f, 0.054260f, 0.063354f, 0.072693f, 0.082886f, 0.093689f, 0.105469f, 0.118164f, 0.130859f,
+ 0.145996f, 0.161011f, 0.177124f, 0.193359f, 0.211670f, 0.230225f, 0.249634f, 0.270020f, 0.290771f, 0.311768f, 0.333740f, 0.356201f,
+ 0.378906f, 0.401855f, 0.424561f, 0.447754f, 0.470215f, 0.493408f, 0.515137f, 0.537109f, 0.559570f, 0.580078f, 0.601074f, 0.621582f,
+ 0.642090f, 0.661621f, 0.679688f, 0.697754f, 0.715820f, 0.732422f, 0.749512f, 0.765137f, 0.779785f, 0.794434f, 0.808594f, 0.821289f,
+ 0.833496f, 0.846191f, 0.857910f, 0.869141f, 0.879883f, 0.889648f, 0.950195f, 0.952637f, 0.950684f, 0.948730f, 0.947266f, 0.945801f,
+ 0.002029f, 0.006672f, 0.011658f, 0.016937f, 0.022476f, 0.028305f, 0.034332f, 0.041351f, 0.048584f, 0.056671f, 0.064697f, 0.073853f,
+ 0.083923f, 0.094482f, 0.105225f, 0.117798f, 0.130615f, 0.144287f, 0.159302f, 0.174683f, 0.190430f, 0.208740f, 0.226318f, 0.245483f,
+ 0.264893f, 0.285400f, 0.307129f, 0.328369f, 0.350342f, 0.372803f, 0.395264f, 0.418701f, 0.441650f, 0.462891f, 0.486816f, 0.509277f,
+ 0.532227f, 0.553711f, 0.575684f, 0.596680f, 0.617676f, 0.638672f, 0.657715f, 0.676758f, 0.695312f, 0.712402f, 0.729492f, 0.746582f,
+ 0.762695f, 0.778320f, 0.793457f, 0.807129f, 0.820801f, 0.833984f, 0.846191f, 0.858887f, 0.869629f, 0.881836f, 0.947266f, 0.949219f,
+ 0.947754f, 0.946289f, 0.944824f, 0.942871f, 0.002142f, 0.006401f, 0.010841f, 0.015251f, 0.019760f, 0.025055f, 0.031113f, 0.037201f,
+ 0.043671f, 0.050598f, 0.057892f, 0.066101f, 0.075012f, 0.084351f, 0.093994f, 0.105164f, 0.117432f, 0.129517f, 0.142822f, 0.157104f,
+ 0.172119f, 0.188110f, 0.204956f, 0.223145f, 0.241577f, 0.260498f, 0.280762f, 0.301758f, 0.322998f, 0.345215f, 0.366943f, 0.389893f,
+ 0.412842f, 0.435791f, 0.458008f, 0.482178f, 0.504395f, 0.526855f, 0.548828f, 0.571289f, 0.592285f, 0.612793f, 0.634277f, 0.654297f,
+ 0.673340f, 0.692383f, 0.710938f, 0.729004f, 0.745117f, 0.762207f, 0.777832f, 0.792480f, 0.807129f, 0.821289f, 0.834961f, 0.847168f,
+ 0.859863f, 0.871582f, 0.943359f, 0.946289f, 0.944824f, 0.943359f, 0.941895f, 0.940430f, 0.001760f, 0.005562f, 0.009621f, 0.013710f,
+ 0.018417f, 0.022736f, 0.027939f, 0.033264f, 0.039185f, 0.045166f, 0.052460f, 0.059143f, 0.067261f, 0.075745f, 0.084106f, 0.094177f,
+ 0.104980f, 0.116455f, 0.128174f, 0.141113f, 0.155151f, 0.169922f, 0.184937f, 0.201660f, 0.219238f, 0.237549f, 0.256348f, 0.276367f,
+ 0.296875f, 0.317871f, 0.339844f, 0.361572f, 0.383789f, 0.407227f, 0.430908f, 0.453857f, 0.476807f, 0.498779f, 0.521973f, 0.543945f,
+ 0.567383f, 0.589355f, 0.609863f, 0.631348f, 0.651855f, 0.671875f, 0.690918f, 0.709961f, 0.727539f, 0.744141f, 0.761719f, 0.777344f,
+ 0.793457f, 0.808594f, 0.823242f, 0.835449f, 0.848633f, 0.861328f, 0.938965f, 0.941895f, 0.941406f, 0.940430f, 0.938477f, 0.937012f,
+ 0.001594f, 0.005283f, 0.008789f, 0.012383f, 0.016342f, 0.020523f, 0.025284f, 0.029968f, 0.035217f, 0.040741f, 0.046417f, 0.052948f,
+ 0.060120f, 0.067566f, 0.076294f, 0.084534f, 0.093750f, 0.104614f, 0.115173f, 0.126831f, 0.139160f, 0.152832f, 0.166748f, 0.181885f,
+ 0.198853f, 0.215698f, 0.233521f, 0.252197f, 0.271973f, 0.291992f, 0.313477f, 0.334717f, 0.357178f, 0.379395f, 0.401855f, 0.425537f,
+ 0.448242f, 0.471924f, 0.495361f, 0.517578f, 0.541016f, 0.562988f, 0.585938f, 0.607422f, 0.627930f, 0.649414f, 0.670410f, 0.688965f,
+ 0.708496f, 0.727539f, 0.744629f, 0.761719f, 0.778809f, 0.794922f, 0.809082f, 0.824219f, 0.838379f, 0.851074f, 0.935059f, 0.938965f,
+ 0.937988f, 0.937012f, 0.936035f, 0.933594f, 0.001564f, 0.004665f, 0.007973f, 0.011276f, 0.014908f, 0.018600f, 0.022675f, 0.027176f,
+ 0.031464f, 0.036621f, 0.042023f, 0.047974f, 0.054108f, 0.060822f, 0.068237f, 0.075684f, 0.084229f, 0.093567f, 0.103210f, 0.113892f,
+ 0.125000f, 0.137329f, 0.150269f, 0.164307f, 0.179810f, 0.194946f, 0.212158f, 0.229248f, 0.247925f, 0.267578f, 0.287842f, 0.308350f,
+ 0.330322f, 0.352051f, 0.374756f, 0.397461f, 0.420654f, 0.444092f, 0.466797f, 0.490723f, 0.514160f, 0.537109f, 0.560059f, 0.582031f,
+ 0.604980f, 0.626953f, 0.648926f, 0.668457f, 0.688477f, 0.708008f, 0.727539f, 0.745117f, 0.763672f, 0.779297f, 0.795410f, 0.811523f,
+ 0.826660f, 0.840332f, 0.930664f, 0.934570f, 0.934082f, 0.933594f, 0.932129f, 0.930664f, 0.001424f, 0.004261f, 0.007122f, 0.010239f,
+ 0.013374f, 0.016693f, 0.020401f, 0.024368f, 0.028595f, 0.033325f, 0.037964f, 0.043152f, 0.048340f, 0.054962f, 0.060730f, 0.067749f,
+ 0.075684f, 0.083862f, 0.092041f, 0.102051f, 0.112305f, 0.123657f, 0.135376f, 0.148071f, 0.161987f, 0.176270f, 0.192139f, 0.208252f,
+ 0.226196f, 0.244141f, 0.263672f, 0.283447f, 0.304199f, 0.325195f, 0.346924f, 0.370605f, 0.392822f, 0.416260f, 0.439209f, 0.463623f,
+ 0.486084f, 0.511230f, 0.534180f, 0.558105f, 0.580566f, 0.603516f, 0.625000f, 0.647461f, 0.668457f, 0.688965f, 0.708496f, 0.727539f,
+ 0.746582f, 0.764160f, 0.781738f, 0.798340f, 0.813477f, 0.829590f, 0.926758f, 0.931152f, 0.930664f, 0.929199f, 0.928223f, 0.927246f,
+ 0.001294f, 0.004196f, 0.006538f, 0.009346f, 0.012306f, 0.015335f, 0.018845f, 0.022003f, 0.025558f, 0.029816f, 0.034149f, 0.038605f,
+ 0.043915f, 0.049042f, 0.054810f, 0.061188f, 0.067993f, 0.075256f, 0.083130f, 0.091553f, 0.100769f, 0.110779f, 0.121643f, 0.133057f,
+ 0.145630f, 0.159058f, 0.173218f, 0.188721f, 0.204590f, 0.222290f, 0.240234f, 0.259277f, 0.279053f, 0.299561f, 0.321533f, 0.343506f,
+ 0.365723f, 0.389404f, 0.412354f, 0.436035f, 0.459961f, 0.484131f, 0.508301f, 0.532227f, 0.555176f, 0.579102f, 0.601562f, 0.624512f,
+ 0.646484f, 0.668457f, 0.688965f, 0.709473f, 0.729004f, 0.748047f, 0.766602f, 0.784668f, 0.800293f, 0.817383f, 0.921875f, 0.926270f,
+ 0.926270f, 0.925781f, 0.924316f, 0.923340f, 0.001081f, 0.003603f, 0.006027f, 0.008575f, 0.010979f, 0.013847f, 0.016937f, 0.020020f,
+ 0.023315f, 0.026917f, 0.030930f, 0.035156f, 0.039429f, 0.044098f, 0.049622f, 0.054779f, 0.060791f, 0.067566f, 0.074341f, 0.082336f,
+ 0.090515f, 0.099548f, 0.109070f, 0.119263f, 0.130981f, 0.143188f, 0.156250f, 0.170288f, 0.185303f, 0.201294f, 0.218262f, 0.236450f,
+ 0.255615f, 0.275391f, 0.295654f, 0.316895f, 0.339111f, 0.362061f, 0.385498f, 0.408936f, 0.432861f, 0.457275f, 0.481689f, 0.505371f,
+ 0.529785f, 0.553711f, 0.577637f, 0.601074f, 0.624023f, 0.646484f, 0.669434f, 0.689941f, 0.711426f, 0.731445f, 0.750977f, 0.770020f,
+ 0.787598f, 0.804688f, 0.916992f, 0.922363f, 0.922363f, 0.921875f, 0.920898f, 0.918945f, 0.001064f, 0.003231f, 0.005322f, 0.007710f,
+ 0.010323f, 0.012489f, 0.015244f, 0.018051f, 0.020798f, 0.024338f, 0.027893f, 0.031738f, 0.035553f, 0.039795f, 0.044495f, 0.049133f,
+ 0.054657f, 0.060608f, 0.066895f, 0.073792f, 0.081421f, 0.089050f, 0.097717f, 0.106934f, 0.117554f, 0.128540f, 0.140503f, 0.153442f,
+ 0.167236f, 0.182129f, 0.197998f, 0.214966f, 0.232422f, 0.251465f, 0.271240f, 0.291992f, 0.313232f, 0.335693f, 0.358643f, 0.382080f,
+ 0.406006f, 0.430176f, 0.454590f, 0.479004f, 0.503906f, 0.528320f, 0.552734f, 0.577637f, 0.601562f, 0.625000f, 0.648438f, 0.670898f,
+ 0.691895f, 0.713867f, 0.733887f, 0.754883f, 0.774414f, 0.791992f, 0.912109f, 0.917969f, 0.918457f, 0.916992f, 0.916016f, 0.915039f,
+ 0.000998f, 0.003012f, 0.005123f, 0.007114f, 0.009438f, 0.011360f, 0.013763f, 0.016510f, 0.018951f, 0.022171f, 0.025101f, 0.028305f,
+ 0.031830f, 0.035736f, 0.039795f, 0.044067f, 0.048950f, 0.053864f, 0.059601f, 0.066345f, 0.072815f, 0.079956f, 0.087402f, 0.096375f,
+ 0.105835f, 0.115479f, 0.126343f, 0.138184f, 0.150635f, 0.164062f, 0.178711f, 0.194214f, 0.210815f, 0.229004f, 0.247314f, 0.267090f,
+ 0.288330f, 0.309570f, 0.332275f, 0.355469f, 0.378418f, 0.402832f, 0.427490f, 0.452637f, 0.477783f, 0.501953f, 0.527832f, 0.552734f,
+ 0.577637f, 0.602051f, 0.626465f, 0.649902f, 0.672852f, 0.695312f, 0.717773f, 0.737793f, 0.758789f, 0.778809f, 0.906250f, 0.913086f,
+ 0.913574f, 0.912598f, 0.911621f, 0.910645f, 0.001059f, 0.002985f, 0.004475f, 0.006496f, 0.008545f, 0.010300f, 0.012581f, 0.014969f,
+ 0.017471f, 0.019852f, 0.022507f, 0.025864f, 0.028824f, 0.032135f, 0.036041f, 0.039795f, 0.043884f, 0.048706f, 0.053680f, 0.059113f,
+ 0.064819f, 0.071472f, 0.078491f, 0.086365f, 0.094360f, 0.103577f, 0.113403f, 0.124023f, 0.135620f, 0.147705f, 0.160889f, 0.175537f,
+ 0.191284f, 0.207764f, 0.225464f, 0.244263f, 0.264160f, 0.284912f, 0.306641f, 0.329102f, 0.352295f, 0.376465f, 0.400635f, 0.426025f,
+ 0.451416f, 0.476562f, 0.502930f, 0.527344f, 0.553711f, 0.579102f, 0.603027f, 0.627930f, 0.652344f, 0.675781f, 0.700195f, 0.722168f,
+ 0.742676f, 0.764648f, 0.901367f, 0.907715f, 0.908691f, 0.908203f, 0.907227f, 0.906250f, 0.000988f, 0.002577f, 0.004124f, 0.006042f,
+ 0.007603f, 0.009506f, 0.011299f, 0.013680f, 0.015778f, 0.017883f, 0.020554f, 0.023102f, 0.025940f, 0.028946f, 0.031891f, 0.035431f,
+ 0.039825f, 0.043671f, 0.048157f, 0.053009f, 0.058075f, 0.063782f, 0.069885f, 0.077087f, 0.084839f, 0.092712f, 0.101379f, 0.110779f,
+ 0.121155f, 0.132446f, 0.144775f, 0.157837f, 0.172363f, 0.187744f, 0.204590f, 0.222290f, 0.240601f, 0.260254f, 0.281494f, 0.303223f,
+ 0.325439f, 0.349609f, 0.373535f, 0.399170f, 0.424561f, 0.450439f, 0.475586f, 0.501953f, 0.528320f, 0.554688f, 0.580566f, 0.605957f,
+ 0.630859f, 0.656250f, 0.680176f, 0.704102f, 0.727051f, 0.749512f, 0.895508f, 0.902344f, 0.903320f, 0.902832f, 0.901855f, 0.901855f,
+ 0.000842f, 0.002253f, 0.003597f, 0.005352f, 0.007195f, 0.008804f, 0.010460f, 0.012100f, 0.014130f, 0.016281f, 0.018341f, 0.021057f,
+ 0.023193f, 0.025742f, 0.029022f, 0.031830f, 0.035278f, 0.039246f, 0.042999f, 0.047211f, 0.052032f, 0.056946f, 0.062744f, 0.068848f,
+ 0.075195f, 0.082642f, 0.090332f, 0.099060f, 0.108215f, 0.118469f, 0.129517f, 0.141724f, 0.154907f, 0.169434f, 0.184448f, 0.201172f,
+ 0.218506f, 0.237427f, 0.257324f, 0.278320f, 0.300293f, 0.323242f, 0.347412f, 0.372070f, 0.397217f, 0.423340f, 0.449707f, 0.476807f,
+ 0.502930f, 0.529785f, 0.556641f, 0.582520f, 0.609863f, 0.635254f, 0.660645f, 0.686035f, 0.710938f, 0.733887f, 0.889648f, 0.897461f,
+ 0.898926f, 0.896973f, 0.896973f, 0.896484f, 0.000660f, 0.002014f, 0.003531f, 0.004951f, 0.006424f, 0.007935f, 0.009392f, 0.011322f,
+ 0.012924f, 0.014824f, 0.016754f, 0.018906f, 0.020935f, 0.023376f, 0.026245f, 0.028809f, 0.031860f, 0.034821f, 0.038330f, 0.042236f,
+ 0.046387f, 0.050812f, 0.056061f, 0.061279f, 0.066956f, 0.073547f, 0.080566f, 0.088074f, 0.096802f, 0.106079f, 0.116089f, 0.127075f,
+ 0.138672f, 0.151855f, 0.165649f, 0.180908f, 0.197754f, 0.215332f, 0.234375f, 0.254150f, 0.275391f, 0.298096f, 0.321533f, 0.344971f,
+ 0.370361f, 0.396973f, 0.422852f, 0.449219f, 0.477295f, 0.504395f, 0.532227f, 0.558594f, 0.586914f, 0.614258f, 0.640625f, 0.666016f,
+ 0.692871f, 0.718262f, 0.882812f, 0.891602f, 0.892578f, 0.892090f, 0.892090f, 0.890625f, 0.000623f, 0.002073f, 0.003298f, 0.004292f,
+ 0.005589f, 0.007401f, 0.008377f, 0.010315f, 0.011871f, 0.013596f, 0.015213f, 0.016632f, 0.018829f, 0.020920f, 0.023239f, 0.025726f,
+ 0.028381f, 0.031250f, 0.034241f, 0.037781f, 0.041473f, 0.045349f, 0.049469f, 0.054199f, 0.059448f, 0.065186f, 0.071716f, 0.078613f,
+ 0.085999f, 0.093872f, 0.103516f, 0.112976f, 0.123840f, 0.135620f, 0.148804f, 0.162720f, 0.178223f, 0.194824f, 0.212280f, 0.231079f,
+ 0.251953f, 0.273193f, 0.295410f, 0.319580f, 0.343994f, 0.370117f, 0.396729f, 0.422852f, 0.450684f, 0.478516f, 0.507324f, 0.534668f,
+ 0.562988f, 0.591797f, 0.619629f, 0.646484f, 0.674316f, 0.700195f, 0.875488f, 0.885254f, 0.886719f, 0.886719f, 0.885742f, 0.885254f,
+ 0.000583f, 0.001746f, 0.002840f, 0.004143f, 0.005234f, 0.006516f, 0.007835f, 0.009460f, 0.010788f, 0.012062f, 0.013428f, 0.015053f,
+ 0.017349f, 0.018753f, 0.021271f, 0.023163f, 0.025284f, 0.027924f, 0.030655f, 0.033478f, 0.036957f, 0.040527f, 0.044037f, 0.048309f,
+ 0.053223f, 0.058319f, 0.063660f, 0.069763f, 0.076172f, 0.083679f, 0.091431f, 0.100647f, 0.110229f, 0.120667f, 0.132690f, 0.145386f,
+ 0.159668f, 0.174805f, 0.191284f, 0.208984f, 0.228516f, 0.248535f, 0.270996f, 0.293701f, 0.317383f, 0.342529f, 0.369629f, 0.396240f,
+ 0.424072f, 0.452148f, 0.480957f, 0.509277f, 0.539551f, 0.567871f, 0.596680f, 0.625977f, 0.654785f, 0.682129f, 0.868652f, 0.878906f,
+ 0.880371f, 0.879883f, 0.879883f, 0.879395f, 0.000535f, 0.001538f, 0.002930f, 0.003725f, 0.004986f, 0.005920f, 0.006973f, 0.008247f,
+ 0.009575f, 0.010841f, 0.012115f, 0.013550f, 0.015343f, 0.016983f, 0.018814f, 0.020523f, 0.022568f, 0.024887f, 0.027206f, 0.029907f,
+ 0.032959f, 0.035828f, 0.039185f, 0.042877f, 0.046967f, 0.051605f, 0.056213f, 0.061432f, 0.067749f, 0.073730f, 0.081238f, 0.089111f,
+ 0.097656f, 0.107300f, 0.118042f, 0.129883f, 0.142334f, 0.156250f, 0.171875f, 0.187866f, 0.206665f, 0.225708f, 0.246704f, 0.268799f,
+ 0.291992f, 0.316650f, 0.342529f, 0.369629f, 0.397217f, 0.425537f, 0.454590f, 0.484131f, 0.513672f, 0.544434f, 0.574219f, 0.604492f,
+ 0.633789f, 0.664062f, 0.861328f, 0.871582f, 0.873535f, 0.874512f, 0.873047f, 0.872559f, 0.000581f, 0.001668f, 0.002563f, 0.003471f,
+ 0.004494f, 0.005562f, 0.006580f, 0.007782f, 0.008690f, 0.009766f, 0.011261f, 0.012314f, 0.013901f, 0.014969f, 0.016479f, 0.018265f,
+ 0.020294f, 0.022156f, 0.024353f, 0.026505f, 0.029053f, 0.031799f, 0.034607f, 0.037964f, 0.041382f, 0.045471f, 0.049591f, 0.054047f,
+ 0.059326f, 0.065186f, 0.071411f, 0.078735f, 0.086304f, 0.094971f, 0.104126f, 0.114807f, 0.126587f, 0.138916f, 0.153564f, 0.169067f,
+ 0.185669f, 0.203613f, 0.223389f, 0.244629f, 0.266602f, 0.291260f, 0.316406f, 0.342773f, 0.370361f, 0.398926f, 0.427734f, 0.458008f,
+ 0.488770f, 0.520020f, 0.550293f, 0.582031f, 0.613281f, 0.645020f, 0.854004f, 0.865234f, 0.866699f, 0.867188f, 0.866699f, 0.866699f,
+ 0.000571f, 0.001365f, 0.002483f, 0.003033f, 0.004120f, 0.005054f, 0.005981f, 0.006737f, 0.007603f, 0.008675f, 0.009789f, 0.011078f,
+ 0.012413f, 0.013626f, 0.014908f, 0.016174f, 0.017792f, 0.019699f, 0.021591f, 0.023499f, 0.025635f, 0.028000f, 0.030533f, 0.033417f,
+ 0.036499f, 0.039948f, 0.043762f, 0.047943f, 0.052460f, 0.057465f, 0.062622f, 0.068848f, 0.076111f, 0.083557f, 0.092102f, 0.101562f,
+ 0.111816f, 0.123230f, 0.135864f, 0.150024f, 0.165771f, 0.182373f, 0.200806f, 0.221191f, 0.242920f, 0.265869f, 0.290283f, 0.316406f,
+ 0.343262f, 0.371582f, 0.400879f, 0.431396f, 0.463623f, 0.494629f, 0.526367f, 0.558105f, 0.591309f, 0.624023f, 0.845215f, 0.856934f,
+ 0.859375f, 0.859375f, 0.859863f, 0.860352f, 0.000411f, 0.001296f, 0.002012f, 0.002808f, 0.003754f, 0.004543f, 0.005215f, 0.006012f,
+ 0.006725f, 0.007851f, 0.008888f, 0.009979f, 0.010994f, 0.012009f, 0.013062f, 0.014549f, 0.016113f, 0.017441f, 0.019073f, 0.020767f,
+ 0.022598f, 0.024689f, 0.026764f, 0.029358f, 0.032043f, 0.034760f, 0.038391f, 0.041779f, 0.045380f, 0.050110f, 0.055054f, 0.060394f,
+ 0.066650f, 0.073120f, 0.080688f, 0.089233f, 0.098450f, 0.108582f, 0.120178f, 0.133057f, 0.146973f, 0.162354f, 0.179565f, 0.198364f,
+ 0.218750f, 0.240967f, 0.264648f, 0.290039f, 0.316650f, 0.344971f, 0.374023f, 0.404541f, 0.435791f, 0.467773f, 0.500977f, 0.535156f,
+ 0.569336f, 0.601562f, 0.836914f, 0.850098f, 0.852051f, 0.852539f, 0.852539f, 0.852051f, 0.000408f, 0.001071f, 0.001857f, 0.002573f,
+ 0.003338f, 0.004078f, 0.004692f, 0.005379f, 0.006046f, 0.007275f, 0.007957f, 0.008606f, 0.009598f, 0.010864f, 0.011658f, 0.013084f,
+ 0.013977f, 0.015366f, 0.016724f, 0.018402f, 0.019669f, 0.021759f, 0.023697f, 0.025726f, 0.027954f, 0.030640f, 0.033356f, 0.036530f,
+ 0.039948f, 0.043701f, 0.047791f, 0.052704f, 0.057770f, 0.063782f, 0.070129f, 0.077881f, 0.085999f, 0.095337f, 0.105591f, 0.116882f,
+ 0.130005f, 0.143921f, 0.159302f, 0.177246f, 0.196411f, 0.217163f, 0.239746f, 0.263916f, 0.290039f, 0.317871f, 0.346924f, 0.377441f,
+ 0.408936f, 0.442139f, 0.476074f, 0.509766f, 0.545410f, 0.580078f, 0.828613f, 0.841309f, 0.843262f, 0.844238f, 0.843750f, 0.844238f,
+ 0.000322f, 0.001009f, 0.001674f, 0.002262f, 0.002949f, 0.003633f, 0.004250f, 0.004780f, 0.005478f, 0.006256f, 0.007248f, 0.007919f,
+ 0.008720f, 0.009552f, 0.010277f, 0.011391f, 0.012291f, 0.013466f, 0.014786f, 0.015976f, 0.017288f, 0.019043f, 0.020477f, 0.022385f,
+ 0.024292f, 0.026276f, 0.029175f, 0.031769f, 0.034546f, 0.037842f, 0.041626f, 0.045868f, 0.050293f, 0.055084f, 0.060669f, 0.067688f,
+ 0.074585f, 0.083008f, 0.092102f, 0.102234f, 0.113525f, 0.126587f, 0.140869f, 0.156860f, 0.174805f, 0.194214f, 0.215698f, 0.239014f,
+ 0.264404f, 0.291016f, 0.320068f, 0.350098f, 0.382080f, 0.414551f, 0.449463f, 0.485107f, 0.520996f, 0.557617f, 0.818848f, 0.833496f,
+ 0.836426f, 0.836914f, 0.836426f, 0.835938f, 0.000483f, 0.000841f, 0.001632f, 0.002142f, 0.002678f, 0.003359f, 0.003830f, 0.004333f,
+ 0.005077f, 0.005527f, 0.006104f, 0.006908f, 0.007675f, 0.008392f, 0.009216f, 0.009789f, 0.010880f, 0.011719f, 0.012817f, 0.013809f,
+ 0.015068f, 0.016357f, 0.017883f, 0.019485f, 0.021271f, 0.022995f, 0.025162f, 0.027359f, 0.029755f, 0.032806f, 0.036133f, 0.039459f,
+ 0.043091f, 0.047821f, 0.052368f, 0.058258f, 0.064514f, 0.071472f, 0.079224f, 0.088623f, 0.098694f, 0.109924f, 0.123230f, 0.137817f,
+ 0.154053f, 0.172363f, 0.192261f, 0.214478f, 0.238647f, 0.265137f, 0.292725f, 0.322998f, 0.354492f, 0.387695f, 0.422363f, 0.458740f,
+ 0.495605f, 0.533691f, 0.809570f, 0.824219f, 0.826660f, 0.827148f, 0.828125f, 0.827148f, 0.000240f, 0.000906f, 0.001379f, 0.001807f,
+ 0.002495f, 0.002916f, 0.003490f, 0.004139f, 0.004471f, 0.004898f, 0.005638f, 0.005978f, 0.006874f, 0.007313f, 0.007957f, 0.008698f,
+ 0.009560f, 0.010178f, 0.011345f, 0.012177f, 0.012985f, 0.014214f, 0.015274f, 0.016708f, 0.017929f, 0.019882f, 0.021393f, 0.023560f,
+ 0.025406f, 0.028137f, 0.030472f, 0.033752f, 0.036896f, 0.040619f, 0.044952f, 0.049622f, 0.055298f, 0.061249f, 0.068420f, 0.075928f,
+ 0.084900f, 0.095398f, 0.107300f, 0.119934f, 0.134766f, 0.151733f, 0.170410f, 0.191284f, 0.213867f, 0.238647f, 0.265869f, 0.295654f,
+ 0.326660f, 0.359863f, 0.394775f, 0.432129f, 0.469482f, 0.508789f, 0.798340f, 0.814941f, 0.817871f, 0.818359f, 0.818848f, 0.818848f,
+ 0.000376f, 0.000870f, 0.001291f, 0.001619f, 0.002251f, 0.002520f, 0.003016f, 0.003502f, 0.004036f, 0.004299f, 0.004723f, 0.005234f,
+ 0.005840f, 0.006512f, 0.006908f, 0.007595f, 0.008003f, 0.008797f, 0.009773f, 0.010536f, 0.011284f, 0.012161f, 0.013237f, 0.014465f,
+ 0.015579f, 0.016968f, 0.018402f, 0.019882f, 0.021759f, 0.023621f, 0.026138f, 0.028488f, 0.031738f, 0.034668f, 0.038239f, 0.042389f,
+ 0.046783f, 0.052094f, 0.058319f, 0.064941f, 0.072815f, 0.081726f, 0.092102f, 0.103516f, 0.117188f, 0.132202f, 0.149048f, 0.168091f,
+ 0.189941f, 0.213745f, 0.239990f, 0.268311f, 0.299316f, 0.332275f, 0.367188f, 0.403076f, 0.442871f, 0.483398f, 0.788086f, 0.805176f,
+ 0.808105f, 0.808594f, 0.809082f, 0.809082f, 0.000386f, 0.000765f, 0.000998f, 0.001537f, 0.001833f, 0.002407f, 0.002529f, 0.003113f,
+ 0.003334f, 0.003841f, 0.004192f, 0.004585f, 0.005096f, 0.005543f, 0.006073f, 0.006405f, 0.007118f, 0.007641f, 0.008278f, 0.008957f,
+ 0.009651f, 0.010498f, 0.011307f, 0.012184f, 0.013199f, 0.014343f, 0.015671f, 0.016678f, 0.018585f, 0.019852f, 0.021881f, 0.023987f,
+ 0.026398f, 0.029099f, 0.032227f, 0.035339f, 0.039246f, 0.043915f, 0.048859f, 0.054688f, 0.061554f, 0.069519f, 0.078247f, 0.088379f,
+ 0.100037f, 0.113770f, 0.129272f, 0.146606f, 0.166626f, 0.189575f, 0.214111f, 0.241577f, 0.271973f, 0.304199f, 0.339844f, 0.375977f,
+ 0.415527f, 0.457275f, 0.776855f, 0.794434f, 0.797363f, 0.797852f, 0.798828f, 0.799316f, 0.000232f, 0.000636f, 0.000996f, 0.001201f,
+ 0.001721f, 0.002029f, 0.002340f, 0.002802f, 0.003012f, 0.003462f, 0.003693f, 0.004059f, 0.004295f, 0.004822f, 0.005077f, 0.005623f,
+ 0.006126f, 0.006653f, 0.007027f, 0.007561f, 0.008049f, 0.008904f, 0.009399f, 0.010300f, 0.011200f, 0.012115f, 0.013092f, 0.014221f,
+ 0.015671f, 0.016891f, 0.018433f, 0.020294f, 0.022064f, 0.024277f, 0.026688f, 0.029678f, 0.032654f, 0.036499f, 0.040955f, 0.045715f,
+ 0.051514f, 0.058014f, 0.065674f, 0.074707f, 0.084717f, 0.096802f, 0.111023f, 0.126709f, 0.144775f, 0.165771f, 0.189209f, 0.215820f,
+ 0.244385f, 0.275879f, 0.310547f, 0.348145f, 0.387695f, 0.429932f, 0.765137f, 0.783203f, 0.787109f, 0.788574f, 0.788574f, 0.789551f,
+ 0.000171f, 0.000518f, 0.001106f, 0.001242f, 0.001475f, 0.001939f, 0.002092f, 0.002254f, 0.002607f, 0.002930f, 0.003084f, 0.003382f,
+ 0.003674f, 0.004040f, 0.004395f, 0.004780f, 0.005157f, 0.005653f, 0.006088f, 0.006355f, 0.006870f, 0.007420f, 0.008057f, 0.008667f,
+ 0.009361f, 0.010040f, 0.011101f, 0.011803f, 0.012711f, 0.013962f, 0.015343f, 0.016586f, 0.018036f, 0.020142f, 0.022079f, 0.024399f,
+ 0.027023f, 0.030075f, 0.033569f, 0.037750f, 0.042603f, 0.048096f, 0.054718f, 0.062134f, 0.071045f, 0.081299f, 0.093445f, 0.107605f,
+ 0.124268f, 0.142944f, 0.165405f, 0.189941f, 0.218262f, 0.249268f, 0.282227f, 0.319336f, 0.359375f, 0.402832f, 0.752930f, 0.771973f,
+ 0.775879f, 0.776855f, 0.777832f, 0.777832f, 0.000204f, 0.000608f, 0.000865f, 0.001011f, 0.001362f, 0.001632f, 0.001817f, 0.001930f,
+ 0.002274f, 0.002491f, 0.002796f, 0.002932f, 0.003139f, 0.003429f, 0.003736f, 0.004055f, 0.004448f, 0.004829f, 0.004971f, 0.005497f,
+ 0.005859f, 0.006298f, 0.006741f, 0.007080f, 0.007687f, 0.008308f, 0.009087f, 0.009880f, 0.010735f, 0.011528f, 0.012375f, 0.013664f,
+ 0.014862f, 0.016464f, 0.017868f, 0.019852f, 0.022156f, 0.024490f, 0.027435f, 0.030853f, 0.034637f, 0.039154f, 0.044495f, 0.050964f,
+ 0.058441f, 0.067383f, 0.077759f, 0.090332f, 0.104797f, 0.121826f, 0.142334f, 0.164795f, 0.191528f, 0.221313f, 0.254150f, 0.290771f,
+ 0.330078f, 0.374268f, 0.740234f, 0.759277f, 0.763672f, 0.766113f, 0.766602f, 0.766113f, 0.000150f, 0.000514f, 0.000666f, 0.000865f,
+ 0.001163f, 0.001389f, 0.001540f, 0.001672f, 0.001940f, 0.002110f, 0.002302f, 0.002419f, 0.002745f, 0.002974f, 0.003120f, 0.003366f,
+ 0.003695f, 0.003815f, 0.004173f, 0.004574f, 0.004879f, 0.005165f, 0.005646f, 0.006058f, 0.006481f, 0.006969f, 0.007626f, 0.007881f,
+ 0.008751f, 0.009445f, 0.010231f, 0.011246f, 0.012222f, 0.013268f, 0.014641f, 0.015976f, 0.017792f, 0.019867f, 0.021912f, 0.024704f,
+ 0.027786f, 0.031494f, 0.036011f, 0.041229f, 0.047363f, 0.054962f, 0.063904f, 0.074463f, 0.087036f, 0.102295f, 0.120483f, 0.141113f,
+ 0.166260f, 0.194214f, 0.226196f, 0.261719f, 0.301514f, 0.345459f, 0.727051f, 0.747070f, 0.751953f, 0.753418f, 0.754395f, 0.754883f,
+ 0.000103f, 0.000251f, 0.000628f, 0.000912f, 0.000978f, 0.001191f, 0.001365f, 0.001507f, 0.001513f, 0.001757f, 0.001980f, 0.002121f,
+ 0.002316f, 0.002373f, 0.002645f, 0.002909f, 0.003012f, 0.003305f, 0.003538f, 0.003775f, 0.004070f, 0.004246f, 0.004642f, 0.004986f,
+ 0.005394f, 0.005802f, 0.006031f, 0.006565f, 0.006969f, 0.007618f, 0.008293f, 0.008980f, 0.009766f, 0.010612f, 0.011528f, 0.012802f,
+ 0.014198f, 0.015671f, 0.017517f, 0.019592f, 0.021957f, 0.024918f, 0.028442f, 0.032562f, 0.037567f, 0.043762f, 0.051025f, 0.059753f,
+ 0.071045f, 0.084412f, 0.099792f, 0.119385f, 0.141846f, 0.167969f, 0.199341f, 0.233521f, 0.272461f, 0.315674f, 0.712891f, 0.733887f,
+ 0.738770f, 0.740234f, 0.741211f, 0.741699f, 0.000185f, 0.000434f, 0.000489f, 0.000732f, 0.000874f, 0.000968f, 0.001122f, 0.001124f,
+ 0.001371f, 0.001423f, 0.001639f, 0.001693f, 0.001805f, 0.002094f, 0.002241f, 0.002356f, 0.002567f, 0.002691f, 0.002871f, 0.003063f,
+ 0.003195f, 0.003582f, 0.003790f, 0.004089f, 0.004372f, 0.004536f, 0.005085f, 0.005314f, 0.005699f, 0.006153f, 0.006672f, 0.007202f,
+ 0.007805f, 0.008522f, 0.009216f, 0.010071f, 0.011086f, 0.012184f, 0.013596f, 0.015297f, 0.017014f, 0.019363f, 0.021988f, 0.025299f,
+ 0.029282f, 0.033936f, 0.040070f, 0.047028f, 0.056519f, 0.067932f, 0.080872f, 0.098083f, 0.118469f, 0.143188f, 0.171753f, 0.205200f,
+ 0.243286f, 0.286133f, 0.698730f, 0.721680f, 0.725098f, 0.727051f, 0.728027f, 0.728516f, 0.000116f, 0.000267f, 0.000565f, 0.000505f,
+ 0.000648f, 0.000772f, 0.000813f, 0.001031f, 0.001107f, 0.001184f, 0.001335f, 0.001391f, 0.001451f, 0.001633f, 0.001798f, 0.001874f,
+ 0.002090f, 0.002192f, 0.002392f, 0.002464f, 0.002707f, 0.002895f, 0.003044f, 0.003206f, 0.003468f, 0.003666f, 0.003887f, 0.004261f,
+ 0.004524f, 0.004898f, 0.005379f, 0.005711f, 0.006130f, 0.006721f, 0.007267f, 0.007912f, 0.008659f, 0.009575f, 0.010475f, 0.011749f,
+ 0.013252f, 0.014717f, 0.016815f, 0.019302f, 0.022369f, 0.025955f, 0.030502f, 0.036285f, 0.043579f, 0.052795f, 0.064453f, 0.078735f,
+ 0.096497f, 0.118591f, 0.145508f, 0.177368f, 0.213989f, 0.256592f, 0.683105f, 0.707031f, 0.710938f, 0.713379f, 0.714844f, 0.714844f,
+ 0.000223f, 0.000239f, 0.000286f, 0.000476f, 0.000580f, 0.000647f, 0.000715f, 0.000843f, 0.000914f, 0.000950f, 0.001090f, 0.001163f,
+ 0.001259f, 0.001328f, 0.001392f, 0.001560f, 0.001549f, 0.001775f, 0.001868f, 0.001999f, 0.002199f, 0.002235f, 0.002436f, 0.002575f,
+ 0.002842f, 0.002892f, 0.003111f, 0.003401f, 0.003563f, 0.003887f, 0.004196f, 0.004505f, 0.004791f, 0.005142f, 0.005684f, 0.006153f,
+ 0.006710f, 0.007378f, 0.008064f, 0.008881f, 0.009979f, 0.011177f, 0.012779f, 0.014435f, 0.016647f, 0.019150f, 0.022583f, 0.027252f,
+ 0.033051f, 0.040039f, 0.049561f, 0.061340f, 0.076843f, 0.096313f, 0.120544f, 0.150513f, 0.185547f, 0.227173f, 0.668457f, 0.692383f,
+ 0.696289f, 0.698242f, 0.699219f, 0.701172f, 0.000000f, 0.000109f, 0.000315f, 0.000449f, 0.000511f, 0.000507f, 0.000538f, 0.000653f,
+ 0.000724f, 0.000749f, 0.000830f, 0.000893f, 0.001007f, 0.001079f, 0.001189f, 0.001163f, 0.001335f, 0.001307f, 0.001502f, 0.001575f,
+ 0.001627f, 0.001778f, 0.001933f, 0.002029f, 0.002155f, 0.002254f, 0.002401f, 0.002535f, 0.002829f, 0.002943f, 0.003143f, 0.003422f,
+ 0.003710f, 0.003990f, 0.004318f, 0.004627f, 0.005108f, 0.005585f, 0.006142f, 0.006641f, 0.007378f, 0.008354f, 0.009430f, 0.010628f,
+ 0.012123f, 0.014015f, 0.016541f, 0.019836f, 0.023849f, 0.029312f, 0.036774f, 0.046356f, 0.058868f, 0.075562f, 0.097107f, 0.124634f,
+ 0.157837f, 0.197754f, 0.653320f, 0.677734f, 0.682129f, 0.684082f, 0.685547f, 0.684570f, 0.000166f, 0.000195f, 0.000256f, 0.000372f,
+ 0.000386f, 0.000415f, 0.000515f, 0.000432f, 0.000579f, 0.000606f, 0.000706f, 0.000745f, 0.000764f, 0.000837f, 0.000853f, 0.000993f,
+ 0.001034f, 0.001066f, 0.001156f, 0.001203f, 0.001339f, 0.001418f, 0.001470f, 0.001612f, 0.001614f, 0.001707f, 0.001850f, 0.001986f,
+ 0.002151f, 0.002254f, 0.002499f, 0.002560f, 0.002794f, 0.003000f, 0.003212f, 0.003510f, 0.003761f, 0.004086f, 0.004475f, 0.004967f,
+ 0.005428f, 0.006134f, 0.006840f, 0.007786f, 0.008858f, 0.010033f, 0.011909f, 0.014137f, 0.016907f, 0.020767f, 0.025894f, 0.033386f,
+ 0.043274f, 0.056854f, 0.075439f, 0.099548f, 0.130737f, 0.169434f, 0.634277f, 0.661133f, 0.667480f, 0.668945f, 0.669922f, 0.670898f,
+ 0.000115f, 0.000119f, 0.000230f, 0.000304f, 0.000221f, 0.000380f, 0.000322f, 0.000351f, 0.000453f, 0.000527f, 0.000535f, 0.000558f,
+ 0.000595f, 0.000675f, 0.000707f, 0.000670f, 0.000776f, 0.000812f, 0.000839f, 0.000911f, 0.000974f, 0.001033f, 0.001082f, 0.001154f,
+ 0.001209f, 0.001268f, 0.001416f, 0.001432f, 0.001607f, 0.001775f, 0.001877f, 0.001911f, 0.002041f, 0.002207f, 0.002380f, 0.002563f,
+ 0.002741f, 0.002956f, 0.003281f, 0.003513f, 0.003902f, 0.004353f, 0.004803f, 0.005405f, 0.006256f, 0.007072f, 0.008263f, 0.009659f,
+ 0.011627f, 0.014221f, 0.017792f, 0.022919f, 0.030075f, 0.040497f, 0.055878f, 0.076721f, 0.104980f, 0.141357f, 0.618652f, 0.644531f,
+ 0.650391f, 0.652832f, 0.653320f, 0.654785f, 0.000000f, 0.000122f, 0.000142f, 0.000227f, 0.000248f, 0.000246f, 0.000296f, 0.000254f,
+ 0.000308f, 0.000329f, 0.000387f, 0.000437f, 0.000443f, 0.000504f, 0.000515f, 0.000535f, 0.000566f, 0.000592f, 0.000618f, 0.000641f,
+ 0.000706f, 0.000746f, 0.000787f, 0.000839f, 0.000878f, 0.000920f, 0.001043f, 0.001041f, 0.001136f, 0.001199f, 0.001258f, 0.001393f,
+ 0.001428f, 0.001549f, 0.001632f, 0.001856f, 0.001945f, 0.002079f, 0.002310f, 0.002489f, 0.002708f, 0.002996f, 0.003315f, 0.003759f,
+ 0.004177f, 0.004803f, 0.005619f, 0.006527f, 0.007793f, 0.009468f, 0.011917f, 0.015152f, 0.019897f, 0.027298f, 0.038910f, 0.055908f,
+ 0.080811f, 0.114563f, 0.600586f, 0.628906f, 0.634277f, 0.636719f, 0.637207f, 0.638672f, 0.000000f, 0.000000f, 0.000106f, 0.000137f,
+ 0.000172f, 0.000211f, 0.000189f, 0.000226f, 0.000230f, 0.000248f, 0.000293f, 0.000251f, 0.000264f, 0.000321f, 0.000343f, 0.000399f,
+ 0.000368f, 0.000401f, 0.000499f, 0.000479f, 0.000498f, 0.000526f, 0.000550f, 0.000595f, 0.000631f, 0.000645f, 0.000726f, 0.000717f,
+ 0.000786f, 0.000902f, 0.000865f, 0.000916f, 0.000989f, 0.001059f, 0.001165f, 0.001246f, 0.001279f, 0.001408f, 0.001566f, 0.001628f,
+ 0.001808f, 0.001991f, 0.002165f, 0.002466f, 0.002766f, 0.003084f, 0.003534f, 0.004250f, 0.005016f, 0.006130f, 0.007584f, 0.009605f,
+ 0.012718f, 0.017395f, 0.025131f, 0.038269f, 0.058899f, 0.089661f, 0.582031f, 0.611328f, 0.616699f, 0.620117f, 0.621094f, 0.622559f,
+ 0.000000f, 0.000108f, 0.000104f, 0.000095f, 0.000117f, 0.000117f, 0.000122f, 0.000143f, 0.000147f, 0.000164f, 0.000174f, 0.000216f,
+ 0.000191f, 0.000227f, 0.000241f, 0.000250f, 0.000257f, 0.000271f, 0.000301f, 0.000298f, 0.000317f, 0.000344f, 0.000370f, 0.000392f,
+ 0.000404f, 0.000427f, 0.000491f, 0.000491f, 0.000519f, 0.000535f, 0.000611f, 0.000601f, 0.000668f, 0.000698f, 0.000767f, 0.000838f,
+ 0.000865f, 0.000895f, 0.000993f, 0.001066f, 0.001161f, 0.001242f, 0.001415f, 0.001521f, 0.001743f, 0.001901f, 0.002209f, 0.002523f,
+ 0.003038f, 0.003601f, 0.004478f, 0.005699f, 0.007545f, 0.010437f, 0.015175f, 0.023682f, 0.039429f, 0.066406f, 0.563477f, 0.593262f,
+ 0.598633f, 0.602051f, 0.602539f, 0.603516f, 0.000000f, 0.000101f, 0.000093f, 0.000087f, 0.000082f, 0.000078f, 0.000084f, 0.000087f,
+ 0.000093f, 0.000094f, 0.000099f, 0.000104f, 0.000114f, 0.000123f, 0.000158f, 0.000163f, 0.000166f, 0.000178f, 0.000177f, 0.000214f,
+ 0.000191f, 0.000208f, 0.000212f, 0.000247f, 0.000268f, 0.000263f, 0.000272f, 0.000287f, 0.000310f, 0.000336f, 0.000353f, 0.000368f,
+ 0.000396f, 0.000408f, 0.000453f, 0.000476f, 0.000511f, 0.000540f, 0.000615f, 0.000635f, 0.000682f, 0.000751f, 0.000812f, 0.000908f,
+ 0.000987f, 0.001116f, 0.001278f, 0.001431f, 0.001702f, 0.002047f, 0.002512f, 0.003126f, 0.004181f, 0.005817f, 0.008553f, 0.013489f,
+ 0.023697f, 0.045288f, 0.544922f, 0.575684f, 0.581543f, 0.584473f, 0.585938f, 0.587402f, 0.000109f, 0.000091f, 0.000081f, 0.000075f,
+ 0.000070f, 0.000067f, 0.000064f, 0.000061f, 0.000057f, 0.000054f, 0.000058f, 0.000075f, 0.000062f, 0.000064f, 0.000085f, 0.000068f,
+ 0.000092f, 0.000094f, 0.000103f, 0.000110f, 0.000113f, 0.000119f, 0.000141f, 0.000141f, 0.000148f, 0.000152f, 0.000159f, 0.000164f,
+ 0.000175f, 0.000188f, 0.000184f, 0.000218f, 0.000233f, 0.000223f, 0.000253f, 0.000265f, 0.000282f, 0.000321f, 0.000322f, 0.000351f,
+ 0.000371f, 0.000405f, 0.000443f, 0.000478f, 0.000515f, 0.000571f, 0.000652f, 0.000733f, 0.000856f, 0.001011f, 0.001227f, 0.001531f,
+ 0.002029f, 0.002817f, 0.004215f, 0.006874f, 0.012390f, 0.027405f, 0.525879f, 0.557129f, 0.563477f, 0.566895f, 0.568848f, 0.569824f,
+ 0.000094f, 0.000073f, 0.000065f, 0.000060f, 0.000055f, 0.000052f, 0.000049f, 0.000048f, 0.000046f, 0.000045f, 0.000042f, 0.000040f,
+ 0.000040f, 0.000037f, 0.000035f, 0.000035f, 0.000042f, 0.000036f, 0.000049f, 0.000051f, 0.000055f, 0.000056f, 0.000059f, 0.000062f,
+ 0.000064f, 0.000078f, 0.000071f, 0.000079f, 0.000088f, 0.000091f, 0.000093f, 0.000099f, 0.000103f, 0.000110f, 0.000125f, 0.000123f,
+ 0.000127f, 0.000151f, 0.000151f, 0.000161f, 0.000169f, 0.000179f, 0.000204f, 0.000219f, 0.000240f, 0.000267f, 0.000294f, 0.000321f,
+ 0.000378f, 0.000438f, 0.000524f, 0.000628f, 0.000818f, 0.001125f, 0.001693f, 0.002888f, 0.005638f, 0.013580f, 0.505859f, 0.539062f,
+ 0.544922f, 0.548340f, 0.550293f, 0.550781f, 0.000064f, 0.000048f, 0.000041f, 0.000037f, 0.000035f, 0.000034f, 0.000032f, 0.000031f,
+ 0.000030f, 0.000029f, 0.000028f, 0.000028f, 0.000027f, 0.000027f, 0.000026f, 0.000025f, 0.000024f, 0.000023f, 0.000022f, 0.000021f,
+ 0.000020f, 0.000019f, 0.000019f, 0.000023f, 0.000021f, 0.000022f, 0.000026f, 0.000029f, 0.000032f, 0.000031f, 0.000036f, 0.000037f,
+ 0.000036f, 0.000044f, 0.000046f, 0.000048f, 0.000052f, 0.000054f, 0.000056f, 0.000061f, 0.000070f, 0.000073f, 0.000076f, 0.000081f,
+ 0.000082f, 0.000095f, 0.000105f, 0.000120f, 0.000126f, 0.000143f, 0.000173f, 0.000203f, 0.000267f, 0.000346f, 0.000505f, 0.000853f,
+ 0.001829f, 0.005222f, 0.487061f, 0.519531f, 0.527344f, 0.529785f, 0.531738f, 0.532715f, 0.000000f, 0.000002f, 0.000003f, 0.000004f,
+ 0.000008f, 0.000008f, 0.000008f, 0.000010f, 0.000009f, 0.000010f, 0.000010f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f,
+ 0.000012f, 0.000011f, 0.000012f, 0.000011f, 0.000012f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000010f,
+ 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000008f, 0.000007f, 0.000008f, 0.000009f, 0.000010f, 0.000012f, 0.000012f, 0.000015f,
+ 0.000013f, 0.000015f, 0.000018f, 0.000020f, 0.000021f, 0.000022f, 0.000022f, 0.000024f, 0.000026f, 0.000027f, 0.000034f, 0.000043f,
+ 0.000049f, 0.000065f, 0.000089f, 0.000138f, 0.000293f, 0.001143f, 0.466553f, 0.500488f, 0.508301f, 0.510742f, 0.512207f, 0.513672f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000004f, 0.000006f, 0.000023f, 0.446777f, 0.482178f,
+ 0.489746f, 0.492676f, 0.494629f, 0.496094f,
+ },
+ {
+ 0.032318f, 0.095032f, 0.152344f, 0.205322f, 0.254883f, 0.299316f, 0.342041f, 0.380859f, 0.416504f, 0.449707f, 0.481201f, 0.508789f,
+ 0.537109f, 0.562012f, 0.584961f, 0.608398f, 0.628418f, 0.648926f, 0.666504f, 0.684570f, 0.701172f, 0.716797f, 0.731934f, 0.746094f,
+ 0.759766f, 0.770996f, 0.784668f, 0.795898f, 0.806641f, 0.817871f, 0.827637f, 0.837402f, 0.846680f, 0.855469f, 0.863770f, 0.872559f,
+ 0.879883f, 0.887695f, 0.895508f, 0.901367f, 0.909180f, 0.915527f, 0.921387f, 0.927734f, 0.934082f, 0.939453f, 0.944824f, 0.950684f,
+ 0.955566f, 0.960449f, 0.965332f, 0.969238f, 0.974121f, 0.978516f, 0.982910f, 0.986816f, 0.990723f, 0.994629f, 0.994629f, 0.987793f,
+ 0.981934f, 0.976562f, 0.971680f, 0.966797f, 0.025833f, 0.076965f, 0.125854f, 0.173096f, 0.217896f, 0.259766f, 0.299561f, 0.338135f,
+ 0.372559f, 0.407471f, 0.437500f, 0.468262f, 0.496582f, 0.522949f, 0.547852f, 0.571289f, 0.593750f, 0.614746f, 0.633789f, 0.652832f,
+ 0.671387f, 0.687988f, 0.705078f, 0.719727f, 0.734863f, 0.749023f, 0.761719f, 0.774414f, 0.786621f, 0.797363f, 0.808594f, 0.818848f,
+ 0.829590f, 0.838867f, 0.848633f, 0.858398f, 0.865723f, 0.874512f, 0.881836f, 0.890137f, 0.897949f, 0.904297f, 0.910645f, 0.917480f,
+ 0.923828f, 0.929688f, 0.935547f, 0.941895f, 0.947266f, 0.952637f, 0.957520f, 0.962402f, 0.967285f, 0.971680f, 0.976562f, 0.980957f,
+ 0.984863f, 0.989258f, 0.992676f, 0.985840f, 0.979980f, 0.975098f, 0.970703f, 0.966309f, 0.020828f, 0.063049f, 0.104797f, 0.146606f,
+ 0.187134f, 0.225464f, 0.263916f, 0.299072f, 0.333252f, 0.366943f, 0.398438f, 0.429199f, 0.457031f, 0.484131f, 0.509766f, 0.534668f,
+ 0.559082f, 0.579590f, 0.600586f, 0.622070f, 0.640625f, 0.659180f, 0.676758f, 0.692383f, 0.708984f, 0.722656f, 0.737793f, 0.751465f,
+ 0.764648f, 0.776367f, 0.789062f, 0.801270f, 0.811523f, 0.821289f, 0.832031f, 0.841309f, 0.850586f, 0.860352f, 0.868652f, 0.876953f,
+ 0.884766f, 0.892090f, 0.899902f, 0.906738f, 0.913086f, 0.920410f, 0.927246f, 0.933105f, 0.938477f, 0.944336f, 0.950195f, 0.955078f,
+ 0.959961f, 0.965332f, 0.970215f, 0.975098f, 0.979492f, 0.983887f, 0.989746f, 0.983398f, 0.978516f, 0.973633f, 0.969238f, 0.964844f,
+ 0.017273f, 0.052429f, 0.088745f, 0.124207f, 0.160034f, 0.195068f, 0.230103f, 0.263916f, 0.297119f, 0.329102f, 0.360596f, 0.390625f,
+ 0.418945f, 0.446289f, 0.472656f, 0.498535f, 0.521973f, 0.545898f, 0.567871f, 0.588867f, 0.609375f, 0.629395f, 0.646973f, 0.664551f,
+ 0.681641f, 0.698242f, 0.712402f, 0.727539f, 0.741699f, 0.755371f, 0.768555f, 0.780762f, 0.792480f, 0.803711f, 0.814941f, 0.825195f,
+ 0.834961f, 0.844727f, 0.854004f, 0.863281f, 0.871094f, 0.879883f, 0.887695f, 0.895508f, 0.902832f, 0.909668f, 0.916504f, 0.923828f,
+ 0.929688f, 0.936035f, 0.941895f, 0.947754f, 0.952637f, 0.958496f, 0.963379f, 0.968750f, 0.973633f, 0.978027f, 0.986816f, 0.980957f,
+ 0.976562f, 0.972168f, 0.967285f, 0.963379f, 0.014076f, 0.043915f, 0.074951f, 0.106140f, 0.137573f, 0.169189f, 0.201416f, 0.233154f,
+ 0.264648f, 0.295166f, 0.324707f, 0.354248f, 0.381836f, 0.410156f, 0.436279f, 0.462891f, 0.487793f, 0.510742f, 0.534180f, 0.556152f,
+ 0.576660f, 0.598145f, 0.616211f, 0.636719f, 0.653320f, 0.670410f, 0.687500f, 0.703125f, 0.718262f, 0.733398f, 0.746582f, 0.760742f,
+ 0.772949f, 0.785156f, 0.796875f, 0.808105f, 0.818848f, 0.829590f, 0.838867f, 0.848145f, 0.857910f, 0.867188f, 0.875977f, 0.883301f,
+ 0.891602f, 0.899414f, 0.906738f, 0.913086f, 0.919922f, 0.926270f, 0.932617f, 0.938477f, 0.944824f, 0.951660f, 0.957520f, 0.961914f,
+ 0.967285f, 0.972168f, 0.984863f, 0.979004f, 0.974609f, 0.970215f, 0.966309f, 0.961914f, 0.012077f, 0.037445f, 0.063660f, 0.090881f,
+ 0.118774f, 0.147827f, 0.176636f, 0.206055f, 0.234253f, 0.262939f, 0.291504f, 0.320312f, 0.347168f, 0.374756f, 0.401367f, 0.427734f,
+ 0.451904f, 0.477051f, 0.500488f, 0.523438f, 0.545898f, 0.566406f, 0.587402f, 0.605957f, 0.624512f, 0.643555f, 0.662109f, 0.676758f,
+ 0.693848f, 0.708984f, 0.724609f, 0.738770f, 0.751465f, 0.765137f, 0.777344f, 0.790039f, 0.800781f, 0.812500f, 0.823242f, 0.833984f,
+ 0.842773f, 0.853027f, 0.861816f, 0.871094f, 0.879395f, 0.887695f, 0.895508f, 0.903320f, 0.910156f, 0.917969f, 0.924316f, 0.931152f,
+ 0.937988f, 0.943848f, 0.949219f, 0.955566f, 0.960449f, 0.966309f, 0.981445f, 0.977051f, 0.972168f, 0.968262f, 0.964355f, 0.960938f,
+ 0.010445f, 0.032562f, 0.054657f, 0.078613f, 0.103333f, 0.128540f, 0.153564f, 0.181274f, 0.207520f, 0.234619f, 0.261475f, 0.288818f,
+ 0.315674f, 0.342041f, 0.368408f, 0.394287f, 0.418945f, 0.443604f, 0.467773f, 0.490479f, 0.512695f, 0.534180f, 0.555664f, 0.575684f,
+ 0.596191f, 0.616211f, 0.633301f, 0.651855f, 0.668457f, 0.685547f, 0.701172f, 0.714844f, 0.729492f, 0.743652f, 0.758301f, 0.770996f,
+ 0.783203f, 0.794922f, 0.806641f, 0.817383f, 0.827637f, 0.838867f, 0.847656f, 0.857422f, 0.866699f, 0.875000f, 0.884277f, 0.892578f,
+ 0.900391f, 0.907227f, 0.914551f, 0.922363f, 0.929199f, 0.935059f, 0.941895f, 0.948242f, 0.953125f, 0.959473f, 0.978516f, 0.974609f,
+ 0.970215f, 0.966309f, 0.962402f, 0.958984f, 0.009117f, 0.027466f, 0.047424f, 0.067871f, 0.089783f, 0.112244f, 0.135376f, 0.159668f,
+ 0.184082f, 0.209106f, 0.233887f, 0.259277f, 0.285400f, 0.311523f, 0.336182f, 0.360840f, 0.385986f, 0.410889f, 0.435059f, 0.458252f,
+ 0.480713f, 0.503418f, 0.524902f, 0.546387f, 0.566895f, 0.586426f, 0.605469f, 0.624512f, 0.642578f, 0.659668f, 0.676758f, 0.692383f,
+ 0.708008f, 0.722168f, 0.736816f, 0.749512f, 0.763184f, 0.776855f, 0.789062f, 0.800781f, 0.812012f, 0.823730f, 0.833496f, 0.843750f,
+ 0.854004f, 0.863281f, 0.872559f, 0.880371f, 0.889648f, 0.896973f, 0.905762f, 0.912598f, 0.919922f, 0.927734f, 0.934082f, 0.940918f,
+ 0.946289f, 0.952637f, 0.976074f, 0.972168f, 0.967773f, 0.963867f, 0.960938f, 0.957031f, 0.007561f, 0.024231f, 0.041077f, 0.059631f,
+ 0.078369f, 0.098145f, 0.119507f, 0.140747f, 0.163208f, 0.185913f, 0.209839f, 0.233154f, 0.257324f, 0.281494f, 0.305908f, 0.330566f,
+ 0.354736f, 0.378906f, 0.402588f, 0.425781f, 0.449219f, 0.471924f, 0.494385f, 0.516602f, 0.536621f, 0.557617f, 0.576660f, 0.596680f,
+ 0.616211f, 0.632812f, 0.650879f, 0.668457f, 0.684082f, 0.700684f, 0.715332f, 0.729492f, 0.744141f, 0.757812f, 0.771973f, 0.783691f,
+ 0.796387f, 0.807129f, 0.818359f, 0.829590f, 0.840820f, 0.850098f, 0.859375f, 0.868652f, 0.877930f, 0.886719f, 0.894531f, 0.903320f,
+ 0.910645f, 0.918945f, 0.925781f, 0.932617f, 0.939453f, 0.945801f, 0.972656f, 0.969727f, 0.965820f, 0.961914f, 0.958496f, 0.955078f,
+ 0.006832f, 0.020676f, 0.036224f, 0.051758f, 0.069214f, 0.086609f, 0.105225f, 0.124146f, 0.144653f, 0.165527f, 0.186646f, 0.209106f,
+ 0.232178f, 0.254883f, 0.277588f, 0.301758f, 0.325195f, 0.348633f, 0.371826f, 0.395264f, 0.418213f, 0.440674f, 0.463135f, 0.485596f,
+ 0.506348f, 0.527832f, 0.548340f, 0.567871f, 0.587891f, 0.606934f, 0.625977f, 0.642578f, 0.660645f, 0.677734f, 0.692871f, 0.708008f,
+ 0.723633f, 0.737793f, 0.752441f, 0.765137f, 0.778320f, 0.791504f, 0.802734f, 0.814453f, 0.825684f, 0.835449f, 0.847168f, 0.856934f,
+ 0.866699f, 0.875488f, 0.884766f, 0.893066f, 0.901367f, 0.910156f, 0.917480f, 0.924805f, 0.932129f, 0.938965f, 0.970215f, 0.966797f,
+ 0.963379f, 0.959961f, 0.956543f, 0.953125f, 0.006050f, 0.018585f, 0.031860f, 0.045807f, 0.060883f, 0.076538f, 0.093323f, 0.109985f,
+ 0.128174f, 0.147949f, 0.167480f, 0.186768f, 0.208496f, 0.230591f, 0.252441f, 0.274170f, 0.297363f, 0.319824f, 0.342773f, 0.365723f,
+ 0.388672f, 0.411133f, 0.433350f, 0.455811f, 0.477295f, 0.498291f, 0.519531f, 0.539551f, 0.560059f, 0.580566f, 0.599121f, 0.617676f,
+ 0.635254f, 0.653320f, 0.669434f, 0.686523f, 0.702148f, 0.717773f, 0.732422f, 0.747070f, 0.760742f, 0.773926f, 0.786621f, 0.798340f,
+ 0.811035f, 0.822754f, 0.833008f, 0.843750f, 0.854004f, 0.863770f, 0.873047f, 0.882812f, 0.891602f, 0.900879f, 0.908691f, 0.916504f,
+ 0.924316f, 0.931152f, 0.966309f, 0.964355f, 0.961426f, 0.957520f, 0.954102f, 0.951172f, 0.005352f, 0.016388f, 0.027985f, 0.040222f,
+ 0.053436f, 0.067261f, 0.082520f, 0.098022f, 0.114319f, 0.131836f, 0.150146f, 0.167969f, 0.187744f, 0.208008f, 0.228271f, 0.249634f,
+ 0.270996f, 0.292969f, 0.314697f, 0.337158f, 0.359375f, 0.380859f, 0.403809f, 0.426025f, 0.447510f, 0.469482f, 0.490967f, 0.511719f,
+ 0.532227f, 0.552734f, 0.571777f, 0.591309f, 0.609375f, 0.628418f, 0.645508f, 0.663086f, 0.680664f, 0.696289f, 0.711426f, 0.727051f,
+ 0.741699f, 0.755859f, 0.768555f, 0.782227f, 0.795410f, 0.807617f, 0.818359f, 0.830078f, 0.841309f, 0.851074f, 0.861816f, 0.871582f,
+ 0.880859f, 0.890625f, 0.898438f, 0.907715f, 0.915527f, 0.923828f, 0.962402f, 0.961914f, 0.958496f, 0.955078f, 0.951172f, 0.948730f,
+ 0.004700f, 0.014397f, 0.025208f, 0.035675f, 0.047485f, 0.060120f, 0.073242f, 0.087097f, 0.102173f, 0.117249f, 0.133789f, 0.150513f,
+ 0.168823f, 0.186890f, 0.206665f, 0.225830f, 0.246216f, 0.267334f, 0.288574f, 0.309814f, 0.331299f, 0.353271f, 0.375244f, 0.396729f,
+ 0.418701f, 0.440674f, 0.461182f, 0.483398f, 0.504883f, 0.524902f, 0.544434f, 0.564941f, 0.584473f, 0.603027f, 0.621582f, 0.639648f,
+ 0.656738f, 0.673828f, 0.690430f, 0.705566f, 0.721680f, 0.736816f, 0.750977f, 0.764648f, 0.778809f, 0.791016f, 0.804688f, 0.815918f,
+ 0.826660f, 0.838867f, 0.850098f, 0.860840f, 0.870605f, 0.879883f, 0.889648f, 0.898438f, 0.907227f, 0.915527f, 0.959961f, 0.958496f,
+ 0.955078f, 0.952148f, 0.949219f, 0.946777f, 0.004238f, 0.013138f, 0.022202f, 0.031769f, 0.042358f, 0.053040f, 0.065613f, 0.077637f,
+ 0.090759f, 0.104980f, 0.119995f, 0.135498f, 0.151855f, 0.167725f, 0.186646f, 0.205078f, 0.224121f, 0.243042f, 0.263672f, 0.283936f,
+ 0.305176f, 0.326416f, 0.347168f, 0.369629f, 0.390625f, 0.411865f, 0.433350f, 0.454590f, 0.475830f, 0.497314f, 0.517578f, 0.537109f,
+ 0.557617f, 0.577637f, 0.596191f, 0.615723f, 0.632812f, 0.651367f, 0.668945f, 0.685059f, 0.701172f, 0.716797f, 0.732422f, 0.747559f,
+ 0.761230f, 0.775391f, 0.788574f, 0.800781f, 0.813965f, 0.824707f, 0.837402f, 0.848145f, 0.859375f, 0.869141f, 0.879395f, 0.889160f,
+ 0.897949f, 0.906250f, 0.956055f, 0.955566f, 0.952148f, 0.950195f, 0.947266f, 0.943848f, 0.003944f, 0.011490f, 0.019943f, 0.028748f,
+ 0.037964f, 0.047485f, 0.058014f, 0.069702f, 0.081360f, 0.093994f, 0.107361f, 0.121277f, 0.136353f, 0.151978f, 0.167480f, 0.185669f,
+ 0.202637f, 0.222168f, 0.240601f, 0.259766f, 0.279541f, 0.300293f, 0.321533f, 0.342285f, 0.362549f, 0.384033f, 0.405762f, 0.427002f,
+ 0.447998f, 0.469238f, 0.490479f, 0.510742f, 0.532227f, 0.551758f, 0.570312f, 0.589844f, 0.609375f, 0.628418f, 0.645508f, 0.662598f,
+ 0.680664f, 0.696777f, 0.712402f, 0.728516f, 0.744141f, 0.757812f, 0.771973f, 0.785156f, 0.798828f, 0.811523f, 0.824707f, 0.835449f,
+ 0.847168f, 0.858887f, 0.869141f, 0.878906f, 0.888672f, 0.897949f, 0.952148f, 0.952148f, 0.949219f, 0.946777f, 0.944336f, 0.941406f,
+ 0.003448f, 0.010574f, 0.017807f, 0.025558f, 0.033875f, 0.042633f, 0.052307f, 0.062134f, 0.073059f, 0.084045f, 0.096375f, 0.109192f,
+ 0.122803f, 0.136475f, 0.151367f, 0.167603f, 0.183960f, 0.201416f, 0.218506f, 0.237427f, 0.256104f, 0.275635f, 0.295410f, 0.315918f,
+ 0.336426f, 0.357178f, 0.378906f, 0.399414f, 0.421143f, 0.442139f, 0.462891f, 0.484375f, 0.504883f, 0.524902f, 0.544922f, 0.564941f,
+ 0.583984f, 0.603516f, 0.622070f, 0.640625f, 0.658691f, 0.675781f, 0.692871f, 0.709473f, 0.725098f, 0.740234f, 0.754883f, 0.769531f,
+ 0.783203f, 0.796875f, 0.809570f, 0.823242f, 0.834473f, 0.846191f, 0.857422f, 0.868164f, 0.878906f, 0.889160f, 0.948730f, 0.948242f,
+ 0.946289f, 0.944336f, 0.940918f, 0.938477f, 0.003017f, 0.009422f, 0.015900f, 0.023041f, 0.030380f, 0.038574f, 0.047150f, 0.055969f,
+ 0.065735f, 0.075684f, 0.086426f, 0.098267f, 0.110535f, 0.123047f, 0.136841f, 0.151489f, 0.166138f, 0.182495f, 0.198975f, 0.216553f,
+ 0.233765f, 0.252930f, 0.271484f, 0.291016f, 0.310547f, 0.331299f, 0.351562f, 0.372559f, 0.393555f, 0.415039f, 0.435059f, 0.457275f,
+ 0.477539f, 0.498047f, 0.519043f, 0.538574f, 0.559570f, 0.579102f, 0.598633f, 0.617188f, 0.635742f, 0.654297f, 0.672363f, 0.688965f,
+ 0.706055f, 0.721191f, 0.737793f, 0.752930f, 0.768066f, 0.782227f, 0.795898f, 0.809082f, 0.821289f, 0.833496f, 0.846191f, 0.857422f,
+ 0.869141f, 0.879883f, 0.944824f, 0.945312f, 0.942871f, 0.940918f, 0.938477f, 0.936035f, 0.002802f, 0.008575f, 0.014763f, 0.020844f,
+ 0.027557f, 0.034576f, 0.042084f, 0.050476f, 0.058990f, 0.067993f, 0.077942f, 0.087952f, 0.098999f, 0.111267f, 0.122803f, 0.136719f,
+ 0.150269f, 0.165527f, 0.180542f, 0.196533f, 0.213257f, 0.230591f, 0.248779f, 0.267334f, 0.286865f, 0.306152f, 0.325928f, 0.346436f,
+ 0.367188f, 0.387695f, 0.409424f, 0.429199f, 0.450195f, 0.471680f, 0.492920f, 0.513184f, 0.534180f, 0.553711f, 0.573730f, 0.593750f,
+ 0.612793f, 0.631836f, 0.649414f, 0.668457f, 0.685059f, 0.703125f, 0.719238f, 0.735352f, 0.750000f, 0.766113f, 0.781738f, 0.794434f,
+ 0.808105f, 0.821777f, 0.833984f, 0.846191f, 0.858398f, 0.870117f, 0.940918f, 0.941895f, 0.939941f, 0.937500f, 0.935059f, 0.932617f,
+ 0.002573f, 0.007603f, 0.013100f, 0.018799f, 0.024719f, 0.031372f, 0.038147f, 0.045105f, 0.052795f, 0.061127f, 0.069519f, 0.079529f,
+ 0.089355f, 0.099976f, 0.111084f, 0.123718f, 0.136353f, 0.148926f, 0.163574f, 0.178345f, 0.194214f, 0.210083f, 0.227783f, 0.245361f,
+ 0.263672f, 0.282471f, 0.301758f, 0.321533f, 0.341797f, 0.361816f, 0.383057f, 0.403320f, 0.424316f, 0.445557f, 0.466797f, 0.487061f,
+ 0.507812f, 0.528809f, 0.549805f, 0.569336f, 0.589844f, 0.608887f, 0.627930f, 0.646973f, 0.665527f, 0.682129f, 0.700195f, 0.717773f,
+ 0.732910f, 0.749512f, 0.765137f, 0.779785f, 0.794434f, 0.808105f, 0.821777f, 0.834473f, 0.847168f, 0.859375f, 0.936523f, 0.937988f,
+ 0.936035f, 0.933594f, 0.932129f, 0.929688f, 0.002409f, 0.007107f, 0.011833f, 0.017075f, 0.022278f, 0.028351f, 0.034088f, 0.040558f,
+ 0.047943f, 0.055389f, 0.063232f, 0.072021f, 0.080322f, 0.090454f, 0.100220f, 0.111389f, 0.122986f, 0.135010f, 0.148438f, 0.162109f,
+ 0.176270f, 0.191772f, 0.207642f, 0.224121f, 0.241699f, 0.259277f, 0.278076f, 0.297363f, 0.316650f, 0.336670f, 0.356934f, 0.377686f,
+ 0.397949f, 0.418701f, 0.439941f, 0.461914f, 0.482178f, 0.502930f, 0.524414f, 0.544922f, 0.565918f, 0.585938f, 0.605957f, 0.625000f,
+ 0.643066f, 0.662109f, 0.680176f, 0.698730f, 0.715820f, 0.731934f, 0.748047f, 0.764648f, 0.780273f, 0.794434f, 0.808594f, 0.821777f,
+ 0.836914f, 0.848145f, 0.932129f, 0.934082f, 0.932617f, 0.930176f, 0.928711f, 0.926270f, 0.002066f, 0.006329f, 0.010986f, 0.015541f,
+ 0.020294f, 0.025452f, 0.030975f, 0.037201f, 0.043152f, 0.049835f, 0.056824f, 0.064331f, 0.072998f, 0.081177f, 0.090637f, 0.100525f,
+ 0.110718f, 0.122131f, 0.134033f, 0.146851f, 0.159912f, 0.173584f, 0.189331f, 0.204468f, 0.221191f, 0.237671f, 0.255615f, 0.273682f,
+ 0.292969f, 0.312012f, 0.331543f, 0.352295f, 0.372314f, 0.393311f, 0.413818f, 0.435547f, 0.456055f, 0.477539f, 0.499023f, 0.520508f,
+ 0.540039f, 0.561523f, 0.581543f, 0.602051f, 0.622070f, 0.641113f, 0.659668f, 0.678223f, 0.697266f, 0.714844f, 0.731445f, 0.748535f,
+ 0.765137f, 0.778809f, 0.794922f, 0.810059f, 0.824219f, 0.837402f, 0.926758f, 0.930176f, 0.928711f, 0.926758f, 0.924805f, 0.922852f,
+ 0.001840f, 0.005703f, 0.009918f, 0.014099f, 0.018311f, 0.023026f, 0.028000f, 0.033508f, 0.038971f, 0.045044f, 0.051880f, 0.058289f,
+ 0.065796f, 0.073425f, 0.081482f, 0.090698f, 0.100464f, 0.110413f, 0.121216f, 0.132812f, 0.145142f, 0.158203f, 0.171997f, 0.186401f,
+ 0.201538f, 0.217651f, 0.234497f, 0.251465f, 0.269287f, 0.288330f, 0.307129f, 0.327148f, 0.346924f, 0.367920f, 0.388428f, 0.409668f,
+ 0.430420f, 0.451416f, 0.474121f, 0.494873f, 0.516113f, 0.537598f, 0.558105f, 0.579102f, 0.598633f, 0.619629f, 0.639160f, 0.657715f,
+ 0.677734f, 0.695801f, 0.713867f, 0.731934f, 0.748047f, 0.764160f, 0.781738f, 0.796875f, 0.810547f, 0.826172f, 0.922363f, 0.925781f,
+ 0.924805f, 0.922852f, 0.921387f, 0.919434f, 0.001621f, 0.005188f, 0.008888f, 0.012939f, 0.016724f, 0.021271f, 0.025772f, 0.029984f,
+ 0.035553f, 0.040741f, 0.046417f, 0.052490f, 0.059265f, 0.066528f, 0.074097f, 0.081482f, 0.090271f, 0.100220f, 0.109741f, 0.120178f,
+ 0.131226f, 0.143188f, 0.156006f, 0.169189f, 0.183716f, 0.198486f, 0.214233f, 0.230713f, 0.247925f, 0.265381f, 0.284424f, 0.303711f,
+ 0.322754f, 0.342773f, 0.363525f, 0.384277f, 0.405518f, 0.427002f, 0.447754f, 0.469727f, 0.491455f, 0.512207f, 0.534180f, 0.554688f,
+ 0.576172f, 0.597168f, 0.617188f, 0.636719f, 0.657227f, 0.677734f, 0.695312f, 0.713379f, 0.731934f, 0.749512f, 0.766113f, 0.782715f,
+ 0.798340f, 0.813477f, 0.917480f, 0.920898f, 0.920410f, 0.919922f, 0.916992f, 0.915039f, 0.001581f, 0.004616f, 0.008049f, 0.011917f,
+ 0.015556f, 0.019547f, 0.023270f, 0.027908f, 0.031860f, 0.036652f, 0.041992f, 0.047577f, 0.053528f, 0.060150f, 0.066772f, 0.073914f,
+ 0.082153f, 0.090088f, 0.099304f, 0.108887f, 0.118835f, 0.129517f, 0.141357f, 0.154297f, 0.166992f, 0.180908f, 0.195557f, 0.210815f,
+ 0.227173f, 0.244141f, 0.261963f, 0.279785f, 0.299072f, 0.318359f, 0.338379f, 0.358887f, 0.380127f, 0.401123f, 0.422607f, 0.443848f,
+ 0.466309f, 0.487793f, 0.509277f, 0.530762f, 0.553223f, 0.573730f, 0.594727f, 0.616699f, 0.636719f, 0.656250f, 0.676270f, 0.695801f,
+ 0.713867f, 0.733398f, 0.750488f, 0.767090f, 0.784180f, 0.801270f, 0.912598f, 0.916992f, 0.916504f, 0.914551f, 0.913086f, 0.911133f,
+ 0.001476f, 0.004410f, 0.007374f, 0.010620f, 0.013931f, 0.017258f, 0.021057f, 0.024979f, 0.029144f, 0.033478f, 0.037872f, 0.042969f,
+ 0.048737f, 0.053986f, 0.060150f, 0.066895f, 0.074036f, 0.081665f, 0.089417f, 0.098083f, 0.107361f, 0.117371f, 0.127930f, 0.139648f,
+ 0.151489f, 0.164062f, 0.178589f, 0.192627f, 0.208130f, 0.223755f, 0.240601f, 0.258057f, 0.275879f, 0.295654f, 0.314697f, 0.334961f,
+ 0.354980f, 0.375977f, 0.396729f, 0.418945f, 0.440430f, 0.462402f, 0.484619f, 0.506348f, 0.528809f, 0.550781f, 0.572266f, 0.593750f,
+ 0.615234f, 0.637207f, 0.656738f, 0.676758f, 0.696289f, 0.716309f, 0.734863f, 0.752930f, 0.770508f, 0.788574f, 0.906738f, 0.911621f,
+ 0.912109f, 0.910156f, 0.908691f, 0.907227f, 0.001204f, 0.003998f, 0.006786f, 0.009850f, 0.012642f, 0.015762f, 0.019226f, 0.022751f,
+ 0.026749f, 0.030502f, 0.034698f, 0.038940f, 0.044006f, 0.048615f, 0.054352f, 0.060608f, 0.066711f, 0.073059f, 0.080505f, 0.088318f,
+ 0.097290f, 0.105835f, 0.115845f, 0.126343f, 0.137085f, 0.148804f, 0.161377f, 0.175049f, 0.189331f, 0.204346f, 0.219604f, 0.236816f,
+ 0.253662f, 0.272217f, 0.291260f, 0.310547f, 0.330811f, 0.350830f, 0.372314f, 0.393799f, 0.415771f, 0.437500f, 0.459717f, 0.481934f,
+ 0.504883f, 0.527344f, 0.549316f, 0.571777f, 0.593750f, 0.615723f, 0.636230f, 0.657715f, 0.678223f, 0.697754f, 0.718262f, 0.737793f,
+ 0.756348f, 0.774902f, 0.900879f, 0.907227f, 0.906738f, 0.905762f, 0.904297f, 0.902832f, 0.001290f, 0.003807f, 0.006207f, 0.008652f,
+ 0.011368f, 0.014618f, 0.017792f, 0.020813f, 0.023849f, 0.027588f, 0.031036f, 0.035400f, 0.039917f, 0.044250f, 0.049408f, 0.054321f,
+ 0.059937f, 0.065918f, 0.072937f, 0.079773f, 0.087463f, 0.095703f, 0.104553f, 0.113892f, 0.124146f, 0.134888f, 0.146606f, 0.159058f,
+ 0.171753f, 0.185913f, 0.201416f, 0.216309f, 0.232910f, 0.250000f, 0.268555f, 0.287354f, 0.306885f, 0.326904f, 0.347412f, 0.369141f,
+ 0.390381f, 0.412842f, 0.434570f, 0.457764f, 0.479736f, 0.502930f, 0.525879f, 0.547852f, 0.570801f, 0.592773f, 0.615723f, 0.637207f,
+ 0.659180f, 0.680176f, 0.700684f, 0.720703f, 0.740234f, 0.759766f, 0.895996f, 0.901855f, 0.901855f, 0.900879f, 0.899414f, 0.897949f,
+ 0.001030f, 0.003561f, 0.005718f, 0.008301f, 0.010582f, 0.013283f, 0.015839f, 0.018753f, 0.022156f, 0.025314f, 0.028427f, 0.032318f,
+ 0.035889f, 0.040039f, 0.044434f, 0.048737f, 0.054077f, 0.059723f, 0.065613f, 0.072083f, 0.079224f, 0.086426f, 0.094238f, 0.102966f,
+ 0.111938f, 0.122253f, 0.132568f, 0.143555f, 0.155884f, 0.168945f, 0.182861f, 0.197510f, 0.213379f, 0.229492f, 0.246948f, 0.264648f,
+ 0.283203f, 0.303467f, 0.322998f, 0.343994f, 0.365479f, 0.387451f, 0.409912f, 0.432129f, 0.455078f, 0.478760f, 0.501465f, 0.523926f,
+ 0.547852f, 0.570801f, 0.593750f, 0.616211f, 0.639160f, 0.661133f, 0.682617f, 0.703613f, 0.725098f, 0.745117f, 0.888672f, 0.896484f,
+ 0.896973f, 0.895020f, 0.895508f, 0.893555f, 0.001051f, 0.002956f, 0.005398f, 0.007523f, 0.009613f, 0.012024f, 0.014725f, 0.017059f,
+ 0.019714f, 0.022537f, 0.025681f, 0.029236f, 0.032715f, 0.036102f, 0.040100f, 0.043945f, 0.048859f, 0.053772f, 0.058838f, 0.064880f,
+ 0.070862f, 0.077576f, 0.084839f, 0.092712f, 0.101013f, 0.110229f, 0.119446f, 0.130005f, 0.141113f, 0.153198f, 0.166016f, 0.179565f,
+ 0.193970f, 0.209351f, 0.225830f, 0.242920f, 0.261230f, 0.280273f, 0.299316f, 0.320068f, 0.341309f, 0.363037f, 0.384521f, 0.407227f,
+ 0.429443f, 0.453369f, 0.477051f, 0.500977f, 0.524414f, 0.547852f, 0.571777f, 0.595215f, 0.619141f, 0.641602f, 0.664062f, 0.686035f,
+ 0.707520f, 0.729004f, 0.882812f, 0.891602f, 0.891113f, 0.890625f, 0.889160f, 0.888184f, 0.000934f, 0.002998f, 0.004883f, 0.006859f,
+ 0.009102f, 0.010925f, 0.012871f, 0.015656f, 0.017853f, 0.020767f, 0.023422f, 0.026413f, 0.029251f, 0.032593f, 0.036011f, 0.039825f,
+ 0.044495f, 0.048645f, 0.053284f, 0.058258f, 0.063782f, 0.069885f, 0.076111f, 0.083313f, 0.090881f, 0.099060f, 0.107788f, 0.117126f,
+ 0.127075f, 0.138428f, 0.150391f, 0.162720f, 0.176270f, 0.190796f, 0.206177f, 0.222290f, 0.239624f, 0.257568f, 0.276367f, 0.296387f,
+ 0.316895f, 0.338623f, 0.360352f, 0.382812f, 0.404785f, 0.428467f, 0.452148f, 0.476562f, 0.500488f, 0.524902f, 0.548828f, 0.572754f,
+ 0.597168f, 0.621094f, 0.644531f, 0.667480f, 0.689941f, 0.712402f, 0.875977f, 0.883789f, 0.884766f, 0.884766f, 0.883301f, 0.883789f,
+ 0.001108f, 0.002474f, 0.004707f, 0.006248f, 0.007744f, 0.009888f, 0.011787f, 0.014244f, 0.016205f, 0.018631f, 0.021286f, 0.023758f,
+ 0.026535f, 0.029510f, 0.032654f, 0.035919f, 0.039825f, 0.043762f, 0.047852f, 0.052368f, 0.057373f, 0.062561f, 0.068604f, 0.074707f,
+ 0.081360f, 0.088623f, 0.096802f, 0.105103f, 0.114624f, 0.124573f, 0.135498f, 0.147217f, 0.159424f, 0.172729f, 0.187378f, 0.202881f,
+ 0.219116f, 0.235962f, 0.254639f, 0.273438f, 0.293945f, 0.314453f, 0.335449f, 0.358154f, 0.380371f, 0.403564f, 0.428223f, 0.452148f,
+ 0.476074f, 0.500977f, 0.525879f, 0.550293f, 0.575195f, 0.599609f, 0.625000f, 0.649414f, 0.672852f, 0.695801f, 0.870117f, 0.879395f,
+ 0.879883f, 0.879395f, 0.878906f, 0.877441f, 0.000877f, 0.002495f, 0.003918f, 0.005669f, 0.007484f, 0.009148f, 0.010895f, 0.012634f,
+ 0.014717f, 0.017014f, 0.019302f, 0.021347f, 0.023849f, 0.026443f, 0.029388f, 0.032532f, 0.035492f, 0.039185f, 0.042816f, 0.046906f,
+ 0.051453f, 0.056122f, 0.061310f, 0.066895f, 0.072937f, 0.079590f, 0.086548f, 0.094360f, 0.103027f, 0.111938f, 0.121643f, 0.132568f,
+ 0.144043f, 0.156006f, 0.169434f, 0.184204f, 0.199341f, 0.215698f, 0.233032f, 0.251221f, 0.269531f, 0.290039f, 0.311768f, 0.333740f,
+ 0.355957f, 0.379395f, 0.402344f, 0.426758f, 0.451172f, 0.476562f, 0.501465f, 0.526855f, 0.552246f, 0.578613f, 0.603516f, 0.629395f,
+ 0.653809f, 0.679199f, 0.863281f, 0.872559f, 0.874023f, 0.873535f, 0.872559f, 0.871094f, 0.000779f, 0.002241f, 0.003813f, 0.005371f,
+ 0.006763f, 0.008186f, 0.009827f, 0.011574f, 0.013260f, 0.015274f, 0.017303f, 0.019119f, 0.021362f, 0.023972f, 0.026505f, 0.029144f,
+ 0.031860f, 0.035126f, 0.038422f, 0.041809f, 0.045929f, 0.050323f, 0.054840f, 0.059631f, 0.065002f, 0.070984f, 0.077759f, 0.084656f,
+ 0.091736f, 0.100037f, 0.109436f, 0.118835f, 0.129272f, 0.140625f, 0.152832f, 0.166138f, 0.180786f, 0.195679f, 0.211914f, 0.229736f,
+ 0.247803f, 0.267822f, 0.287598f, 0.309326f, 0.331055f, 0.354492f, 0.377686f, 0.401855f, 0.426270f, 0.451660f, 0.477051f, 0.503418f,
+ 0.529785f, 0.555664f, 0.583008f, 0.608887f, 0.635254f, 0.661133f, 0.855957f, 0.865234f, 0.866699f, 0.867188f, 0.866211f, 0.865723f,
+ 0.000778f, 0.002155f, 0.003584f, 0.004871f, 0.006149f, 0.007519f, 0.008858f, 0.010498f, 0.012100f, 0.013977f, 0.015511f, 0.017303f,
+ 0.019363f, 0.021515f, 0.023880f, 0.026230f, 0.028564f, 0.031555f, 0.034241f, 0.037476f, 0.041138f, 0.044983f, 0.048859f, 0.053436f,
+ 0.058014f, 0.063232f, 0.069214f, 0.075195f, 0.081848f, 0.089417f, 0.097168f, 0.106201f, 0.115479f, 0.126343f, 0.137695f, 0.149658f,
+ 0.162476f, 0.177002f, 0.192993f, 0.209473f, 0.226440f, 0.245239f, 0.264404f, 0.285156f, 0.306885f, 0.330078f, 0.353271f, 0.376465f,
+ 0.402100f, 0.426758f, 0.453857f, 0.479492f, 0.505859f, 0.532715f, 0.560547f, 0.587402f, 0.614258f, 0.640137f, 0.847168f, 0.858398f,
+ 0.860352f, 0.859863f, 0.859863f, 0.858887f, 0.000673f, 0.002026f, 0.003120f, 0.004242f, 0.005390f, 0.006874f, 0.008087f, 0.009346f,
+ 0.011192f, 0.012642f, 0.013855f, 0.015511f, 0.017502f, 0.019394f, 0.021301f, 0.023331f, 0.025681f, 0.028137f, 0.030792f, 0.033295f,
+ 0.036804f, 0.039917f, 0.043488f, 0.047363f, 0.051880f, 0.056580f, 0.061646f, 0.066956f, 0.072998f, 0.079407f, 0.086609f, 0.094971f,
+ 0.103027f, 0.112793f, 0.122742f, 0.134399f, 0.146118f, 0.159058f, 0.173828f, 0.188599f, 0.205444f, 0.223633f, 0.241943f, 0.262451f,
+ 0.283203f, 0.304932f, 0.328369f, 0.352051f, 0.376953f, 0.402100f, 0.428467f, 0.454834f, 0.481934f, 0.509766f, 0.537598f, 0.566406f,
+ 0.594238f, 0.622559f, 0.838867f, 0.852051f, 0.853516f, 0.853027f, 0.853027f, 0.852051f, 0.000419f, 0.001721f, 0.003044f, 0.003881f,
+ 0.005161f, 0.006329f, 0.007500f, 0.009117f, 0.009941f, 0.011147f, 0.013023f, 0.014053f, 0.015869f, 0.017181f, 0.018906f, 0.020889f,
+ 0.023026f, 0.025085f, 0.027435f, 0.029724f, 0.032440f, 0.035492f, 0.038605f, 0.042175f, 0.045898f, 0.049988f, 0.054504f, 0.059143f,
+ 0.064697f, 0.070435f, 0.076721f, 0.083984f, 0.091675f, 0.100037f, 0.109009f, 0.119629f, 0.130737f, 0.143066f, 0.156250f, 0.170654f,
+ 0.186157f, 0.202393f, 0.220825f, 0.239990f, 0.259521f, 0.281250f, 0.303467f, 0.327148f, 0.351318f, 0.376953f, 0.402832f, 0.430664f,
+ 0.458252f, 0.485596f, 0.514648f, 0.543457f, 0.572754f, 0.602051f, 0.830566f, 0.844238f, 0.845703f, 0.845703f, 0.845703f, 0.845215f,
+ 0.000503f, 0.001644f, 0.002455f, 0.003765f, 0.004906f, 0.005901f, 0.006805f, 0.007744f, 0.008789f, 0.009972f, 0.011314f, 0.012688f,
+ 0.014160f, 0.015480f, 0.016953f, 0.018555f, 0.020325f, 0.022232f, 0.024338f, 0.026535f, 0.028717f, 0.031403f, 0.034119f, 0.037384f,
+ 0.040680f, 0.044128f, 0.047943f, 0.052551f, 0.057098f, 0.062134f, 0.067871f, 0.074158f, 0.081543f, 0.088684f, 0.097107f, 0.106262f,
+ 0.116028f, 0.127563f, 0.139404f, 0.152344f, 0.167358f, 0.182739f, 0.199951f, 0.217773f, 0.237427f, 0.257812f, 0.279541f, 0.303223f,
+ 0.327148f, 0.351807f, 0.377441f, 0.405518f, 0.433105f, 0.460449f, 0.491211f, 0.520020f, 0.550293f, 0.581543f, 0.821777f, 0.835938f,
+ 0.837891f, 0.838867f, 0.838867f, 0.837891f, 0.000649f, 0.001432f, 0.002455f, 0.003469f, 0.004162f, 0.005192f, 0.006046f, 0.007053f,
+ 0.007919f, 0.009148f, 0.010185f, 0.011490f, 0.012558f, 0.013748f, 0.015083f, 0.016663f, 0.018341f, 0.019897f, 0.021561f, 0.023376f,
+ 0.025513f, 0.027725f, 0.030075f, 0.032745f, 0.035583f, 0.038544f, 0.041901f, 0.045898f, 0.049896f, 0.054443f, 0.059784f, 0.065186f,
+ 0.071228f, 0.078247f, 0.085632f, 0.093872f, 0.103088f, 0.113098f, 0.123840f, 0.135986f, 0.148682f, 0.163696f, 0.179321f, 0.196533f,
+ 0.214722f, 0.234985f, 0.256104f, 0.278320f, 0.302246f, 0.326660f, 0.352783f, 0.379395f, 0.406738f, 0.436279f, 0.465820f, 0.496338f,
+ 0.527344f, 0.559082f, 0.813477f, 0.827148f, 0.829590f, 0.830566f, 0.830566f, 0.829590f, 0.000427f, 0.001431f, 0.002077f, 0.002947f,
+ 0.004009f, 0.004860f, 0.005501f, 0.006416f, 0.007008f, 0.008171f, 0.009155f, 0.010063f, 0.011154f, 0.012474f, 0.013336f, 0.014793f,
+ 0.016006f, 0.017471f, 0.019119f, 0.020630f, 0.022079f, 0.024078f, 0.026505f, 0.028687f, 0.031128f, 0.033813f, 0.036804f, 0.040283f,
+ 0.043732f, 0.047882f, 0.052094f, 0.057281f, 0.062500f, 0.068726f, 0.075012f, 0.082581f, 0.090393f, 0.099487f, 0.109375f, 0.120728f,
+ 0.131958f, 0.145508f, 0.160278f, 0.176025f, 0.193848f, 0.212891f, 0.232788f, 0.253906f, 0.277344f, 0.302002f, 0.327637f, 0.354248f,
+ 0.382080f, 0.411621f, 0.441162f, 0.472656f, 0.504395f, 0.536621f, 0.803223f, 0.818359f, 0.821777f, 0.821777f, 0.822266f, 0.821777f,
+ 0.000574f, 0.001416f, 0.001961f, 0.002621f, 0.003527f, 0.004250f, 0.004894f, 0.005653f, 0.006340f, 0.007263f, 0.008255f, 0.008965f,
+ 0.009819f, 0.010857f, 0.011864f, 0.012917f, 0.014114f, 0.015358f, 0.016678f, 0.018005f, 0.019669f, 0.021347f, 0.023239f, 0.025070f,
+ 0.027267f, 0.029434f, 0.032318f, 0.035156f, 0.038269f, 0.041534f, 0.045624f, 0.049469f, 0.054321f, 0.059479f, 0.065369f, 0.071655f,
+ 0.078857f, 0.086853f, 0.095886f, 0.105652f, 0.116943f, 0.128662f, 0.142090f, 0.156860f, 0.173096f, 0.190918f, 0.210327f, 0.231201f,
+ 0.253418f, 0.277100f, 0.302490f, 0.328369f, 0.356445f, 0.385254f, 0.415771f, 0.446533f, 0.479736f, 0.513184f, 0.794434f, 0.810547f,
+ 0.812500f, 0.813477f, 0.812988f, 0.813477f, 0.000417f, 0.001152f, 0.002066f, 0.002480f, 0.003115f, 0.003778f, 0.004543f, 0.005001f,
+ 0.005936f, 0.006420f, 0.007130f, 0.007881f, 0.008789f, 0.009666f, 0.010605f, 0.011276f, 0.012352f, 0.013367f, 0.014626f, 0.015732f,
+ 0.017090f, 0.018509f, 0.020096f, 0.021759f, 0.023895f, 0.025681f, 0.027740f, 0.030121f, 0.032776f, 0.036011f, 0.039276f, 0.042694f,
+ 0.046906f, 0.051575f, 0.056488f, 0.061951f, 0.068481f, 0.075684f, 0.083191f, 0.092102f, 0.101990f, 0.112915f, 0.125122f, 0.138672f,
+ 0.153564f, 0.170410f, 0.188477f, 0.208008f, 0.229980f, 0.252441f, 0.276855f, 0.303711f, 0.331055f, 0.360596f, 0.391357f, 0.422607f,
+ 0.456299f, 0.490234f, 0.783203f, 0.799805f, 0.803223f, 0.804688f, 0.804199f, 0.805176f, 0.000422f, 0.000885f, 0.001743f, 0.002075f,
+ 0.002930f, 0.003460f, 0.004105f, 0.004696f, 0.005257f, 0.005753f, 0.006550f, 0.006916f, 0.007805f, 0.008308f, 0.009109f, 0.010056f,
+ 0.010918f, 0.011627f, 0.012787f, 0.013725f, 0.014732f, 0.016113f, 0.017319f, 0.018906f, 0.020264f, 0.022324f, 0.023911f, 0.026230f,
+ 0.028183f, 0.030884f, 0.033661f, 0.036865f, 0.040314f, 0.044189f, 0.048615f, 0.053284f, 0.058838f, 0.065491f, 0.072205f, 0.079651f,
+ 0.088379f, 0.098389f, 0.109314f, 0.121765f, 0.135010f, 0.150513f, 0.167358f, 0.186035f, 0.206543f, 0.228516f, 0.252197f, 0.278320f,
+ 0.305176f, 0.333496f, 0.364746f, 0.396973f, 0.430176f, 0.465820f, 0.772949f, 0.790527f, 0.794434f, 0.794922f, 0.795410f, 0.794922f,
+ 0.000211f, 0.000970f, 0.001484f, 0.002035f, 0.002586f, 0.003040f, 0.003540f, 0.004086f, 0.004696f, 0.005016f, 0.005508f, 0.006100f,
+ 0.006763f, 0.007401f, 0.008011f, 0.008675f, 0.009247f, 0.010071f, 0.011009f, 0.011940f, 0.012802f, 0.013870f, 0.014771f, 0.016281f,
+ 0.017487f, 0.018890f, 0.020584f, 0.022171f, 0.024200f, 0.026505f, 0.028870f, 0.031372f, 0.034363f, 0.037659f, 0.041412f, 0.045685f,
+ 0.050262f, 0.055664f, 0.061768f, 0.068359f, 0.076172f, 0.084717f, 0.094666f, 0.105835f, 0.117798f, 0.131958f, 0.147095f, 0.164795f,
+ 0.184326f, 0.204956f, 0.228271f, 0.253174f, 0.279785f, 0.307861f, 0.338379f, 0.370361f, 0.404785f, 0.440430f, 0.761230f, 0.780273f,
+ 0.783691f, 0.785645f, 0.786133f, 0.785156f, 0.000281f, 0.000954f, 0.001275f, 0.001745f, 0.002159f, 0.002810f, 0.003002f, 0.003622f,
+ 0.003918f, 0.004471f, 0.004776f, 0.005352f, 0.005852f, 0.006298f, 0.006989f, 0.007339f, 0.008087f, 0.008698f, 0.009499f, 0.010208f,
+ 0.010986f, 0.011871f, 0.012802f, 0.013809f, 0.014923f, 0.016129f, 0.017624f, 0.018753f, 0.020645f, 0.022156f, 0.024399f, 0.026382f,
+ 0.029037f, 0.031769f, 0.034851f, 0.038513f, 0.042542f, 0.047180f, 0.052063f, 0.058136f, 0.064819f, 0.072205f, 0.080933f, 0.090698f,
+ 0.101685f, 0.114441f, 0.128784f, 0.144287f, 0.162476f, 0.182617f, 0.203979f, 0.228149f, 0.253906f, 0.282227f, 0.312744f, 0.344482f,
+ 0.378418f, 0.415039f, 0.749023f, 0.770020f, 0.773438f, 0.774902f, 0.775391f, 0.776367f, 0.000200f, 0.000790f, 0.001209f, 0.001475f,
+ 0.002022f, 0.002375f, 0.002754f, 0.003136f, 0.003532f, 0.003851f, 0.004253f, 0.004719f, 0.004864f, 0.005455f, 0.005749f, 0.006435f,
+ 0.007053f, 0.007557f, 0.007988f, 0.008614f, 0.009216f, 0.010101f, 0.010712f, 0.011604f, 0.012596f, 0.013588f, 0.014877f, 0.016052f,
+ 0.017334f, 0.018753f, 0.020401f, 0.022415f, 0.024338f, 0.026642f, 0.029282f, 0.032196f, 0.035461f, 0.039215f, 0.043854f, 0.048706f,
+ 0.054413f, 0.060913f, 0.068237f, 0.076965f, 0.086792f, 0.097961f, 0.110657f, 0.125488f, 0.141846f, 0.160278f, 0.180542f, 0.203857f,
+ 0.229004f, 0.256348f, 0.286133f, 0.317627f, 0.351807f, 0.388184f, 0.737305f, 0.757812f, 0.762695f, 0.763672f, 0.764160f, 0.764648f,
+ 0.000214f, 0.000700f, 0.001134f, 0.001480f, 0.001724f, 0.002056f, 0.002468f, 0.002672f, 0.003069f, 0.003412f, 0.003618f, 0.003883f,
+ 0.004265f, 0.004627f, 0.004971f, 0.005508f, 0.005817f, 0.006397f, 0.006866f, 0.007244f, 0.007812f, 0.008446f, 0.009003f, 0.009872f,
+ 0.010544f, 0.011345f, 0.012375f, 0.013321f, 0.014275f, 0.015587f, 0.017075f, 0.018372f, 0.020050f, 0.022186f, 0.024246f, 0.026596f,
+ 0.029388f, 0.032562f, 0.036285f, 0.040344f, 0.045197f, 0.050568f, 0.056946f, 0.064514f, 0.072876f, 0.082886f, 0.093933f, 0.107056f,
+ 0.122070f, 0.139404f, 0.158325f, 0.180176f, 0.204590f, 0.231201f, 0.260010f, 0.290771f, 0.325195f, 0.361816f, 0.726074f, 0.747070f,
+ 0.751465f, 0.753418f, 0.753906f, 0.754395f, 0.000187f, 0.000637f, 0.001095f, 0.001133f, 0.001488f, 0.001872f, 0.002007f, 0.002253f,
+ 0.002590f, 0.002880f, 0.003010f, 0.003420f, 0.003593f, 0.003914f, 0.004322f, 0.004650f, 0.005051f, 0.005424f, 0.005733f, 0.006134f,
+ 0.006683f, 0.007183f, 0.007671f, 0.008072f, 0.008720f, 0.009483f, 0.010201f, 0.011070f, 0.011871f, 0.012863f, 0.013924f, 0.015167f,
+ 0.016434f, 0.018143f, 0.019669f, 0.021851f, 0.024109f, 0.026749f, 0.029587f, 0.033020f, 0.037109f, 0.041718f, 0.047119f, 0.053192f,
+ 0.060516f, 0.068848f, 0.078857f, 0.090149f, 0.104004f, 0.119202f, 0.136841f, 0.157471f, 0.180420f, 0.205322f, 0.234009f, 0.264648f,
+ 0.297852f, 0.335449f, 0.711914f, 0.735352f, 0.740234f, 0.741211f, 0.742676f, 0.742676f, 0.000201f, 0.000676f, 0.000884f, 0.001044f,
+ 0.001369f, 0.001633f, 0.001786f, 0.002001f, 0.002237f, 0.002460f, 0.002680f, 0.002777f, 0.003117f, 0.003408f, 0.003632f, 0.003910f,
+ 0.004211f, 0.004375f, 0.004772f, 0.005226f, 0.005520f, 0.005909f, 0.006302f, 0.006882f, 0.007385f, 0.007858f, 0.008553f, 0.008919f,
+ 0.009827f, 0.010582f, 0.011398f, 0.012520f, 0.013611f, 0.014725f, 0.016190f, 0.017593f, 0.019424f, 0.021622f, 0.023941f, 0.026703f,
+ 0.029938f, 0.033539f, 0.038055f, 0.043243f, 0.049408f, 0.056519f, 0.065002f, 0.074951f, 0.086548f, 0.100403f, 0.116394f, 0.135132f,
+ 0.156860f, 0.181030f, 0.208252f, 0.238281f, 0.271240f, 0.307861f, 0.698730f, 0.722656f, 0.727539f, 0.729980f, 0.730957f, 0.730469f,
+ 0.000185f, 0.000371f, 0.000784f, 0.001028f, 0.001153f, 0.001304f, 0.001567f, 0.001792f, 0.001790f, 0.002028f, 0.002283f, 0.002424f,
+ 0.002640f, 0.002764f, 0.003044f, 0.003313f, 0.003445f, 0.003748f, 0.004044f, 0.004337f, 0.004677f, 0.004879f, 0.005207f, 0.005661f,
+ 0.006027f, 0.006481f, 0.006870f, 0.007454f, 0.007874f, 0.008583f, 0.009239f, 0.009880f, 0.010849f, 0.011871f, 0.012833f, 0.014153f,
+ 0.015656f, 0.017151f, 0.018967f, 0.021118f, 0.023621f, 0.026703f, 0.030197f, 0.034576f, 0.039368f, 0.045441f, 0.052460f, 0.061157f,
+ 0.070862f, 0.083069f, 0.097290f, 0.114441f, 0.134155f, 0.157104f, 0.182983f, 0.212158f, 0.244507f, 0.281250f, 0.684570f, 0.710449f,
+ 0.715332f, 0.717285f, 0.717773f, 0.718750f, 0.000109f, 0.000455f, 0.000558f, 0.000757f, 0.000986f, 0.001166f, 0.001298f, 0.001310f,
+ 0.001566f, 0.001614f, 0.001852f, 0.001933f, 0.002062f, 0.002327f, 0.002571f, 0.002699f, 0.002909f, 0.003057f, 0.003254f, 0.003496f,
+ 0.003643f, 0.004066f, 0.004295f, 0.004665f, 0.004822f, 0.005161f, 0.005722f, 0.006008f, 0.006424f, 0.006897f, 0.007435f, 0.008049f,
+ 0.008789f, 0.009529f, 0.010284f, 0.011177f, 0.012321f, 0.013466f, 0.014885f, 0.016586f, 0.018417f, 0.020844f, 0.023575f, 0.026810f,
+ 0.030655f, 0.035400f, 0.041412f, 0.048462f, 0.056976f, 0.067322f, 0.079712f, 0.094543f, 0.112610f, 0.133789f, 0.158691f, 0.186279f,
+ 0.217896f, 0.253418f, 0.670898f, 0.696777f, 0.702148f, 0.704590f, 0.705078f, 0.705566f, 0.000000f, 0.000317f, 0.000556f, 0.000619f,
+ 0.000759f, 0.000889f, 0.001012f, 0.001163f, 0.001282f, 0.001353f, 0.001531f, 0.001621f, 0.001681f, 0.001862f, 0.001976f, 0.002140f,
+ 0.002392f, 0.002502f, 0.002745f, 0.002838f, 0.003019f, 0.003311f, 0.003477f, 0.003639f, 0.003889f, 0.004166f, 0.004429f, 0.004784f,
+ 0.005119f, 0.005547f, 0.006042f, 0.006317f, 0.006901f, 0.007442f, 0.008110f, 0.008751f, 0.009583f, 0.010590f, 0.011566f, 0.012894f,
+ 0.014404f, 0.015930f, 0.018158f, 0.020569f, 0.023697f, 0.027374f, 0.031830f, 0.037567f, 0.044434f, 0.053009f, 0.063599f, 0.076538f,
+ 0.092346f, 0.111511f, 0.134521f, 0.161133f, 0.191772f, 0.227173f, 0.654297f, 0.684082f, 0.687988f, 0.690918f, 0.691895f, 0.691895f,
+ 0.000000f, 0.000275f, 0.000368f, 0.000572f, 0.000683f, 0.000731f, 0.000877f, 0.000979f, 0.001039f, 0.001091f, 0.001234f, 0.001332f,
+ 0.001447f, 0.001547f, 0.001601f, 0.001760f, 0.001790f, 0.002007f, 0.002119f, 0.002245f, 0.002493f, 0.002565f, 0.002747f, 0.002920f,
+ 0.003168f, 0.003235f, 0.003551f, 0.003830f, 0.004040f, 0.004368f, 0.004658f, 0.005001f, 0.005337f, 0.005798f, 0.006287f, 0.006794f,
+ 0.007488f, 0.008087f, 0.008865f, 0.009773f, 0.010963f, 0.012199f, 0.013649f, 0.015610f, 0.017822f, 0.020493f, 0.023849f, 0.028320f,
+ 0.033752f, 0.040466f, 0.049377f, 0.060028f, 0.073853f, 0.090698f, 0.111572f, 0.136841f, 0.166016f, 0.199341f, 0.640137f, 0.667969f,
+ 0.675781f, 0.676758f, 0.678223f, 0.678223f, 0.000017f, 0.000193f, 0.000383f, 0.000487f, 0.000586f, 0.000597f, 0.000618f, 0.000733f,
+ 0.000826f, 0.000863f, 0.000902f, 0.001037f, 0.001121f, 0.001244f, 0.001342f, 0.001329f, 0.001514f, 0.001506f, 0.001719f, 0.001793f,
+ 0.001851f, 0.002016f, 0.002182f, 0.002281f, 0.002432f, 0.002554f, 0.002708f, 0.002859f, 0.003168f, 0.003344f, 0.003563f, 0.003845f,
+ 0.004158f, 0.004478f, 0.004852f, 0.005154f, 0.005714f, 0.006207f, 0.006752f, 0.007370f, 0.008186f, 0.009155f, 0.010193f, 0.011490f,
+ 0.013016f, 0.015144f, 0.017517f, 0.020752f, 0.024811f, 0.029922f, 0.036835f, 0.045593f, 0.056946f, 0.071533f, 0.090576f, 0.113159f,
+ 0.140991f, 0.173340f, 0.624023f, 0.653809f, 0.660156f, 0.663574f, 0.664551f, 0.664062f, 0.000194f, 0.000227f, 0.000316f, 0.000451f,
+ 0.000449f, 0.000482f, 0.000610f, 0.000511f, 0.000654f, 0.000673f, 0.000804f, 0.000844f, 0.000880f, 0.000955f, 0.000961f, 0.001127f,
+ 0.001169f, 0.001210f, 0.001318f, 0.001330f, 0.001507f, 0.001592f, 0.001657f, 0.001771f, 0.001839f, 0.001953f, 0.002083f, 0.002214f,
+ 0.002399f, 0.002518f, 0.002815f, 0.002882f, 0.003132f, 0.003361f, 0.003605f, 0.003925f, 0.004177f, 0.004528f, 0.004963f, 0.005527f,
+ 0.006027f, 0.006783f, 0.007381f, 0.008469f, 0.009644f, 0.010849f, 0.012772f, 0.014748f, 0.017578f, 0.021332f, 0.026367f, 0.033142f,
+ 0.042389f, 0.054413f, 0.070129f, 0.091064f, 0.116943f, 0.147339f, 0.608887f, 0.640137f, 0.645996f, 0.647461f, 0.650391f, 0.651367f,
+ 0.000166f, 0.000146f, 0.000248f, 0.000320f, 0.000288f, 0.000446f, 0.000375f, 0.000407f, 0.000468f, 0.000514f, 0.000629f, 0.000638f,
+ 0.000681f, 0.000773f, 0.000806f, 0.000766f, 0.000883f, 0.000927f, 0.000959f, 0.001036f, 0.001097f, 0.001172f, 0.001224f, 0.001297f,
+ 0.001392f, 0.001425f, 0.001592f, 0.001631f, 0.001793f, 0.001965f, 0.002089f, 0.002157f, 0.002321f, 0.002495f, 0.002680f, 0.002874f,
+ 0.003054f, 0.003305f, 0.003632f, 0.003902f, 0.004314f, 0.004753f, 0.005306f, 0.005901f, 0.006828f, 0.007645f, 0.008896f, 0.010323f,
+ 0.012283f, 0.014816f, 0.018234f, 0.023010f, 0.029678f, 0.039276f, 0.052307f, 0.070190f, 0.093811f, 0.123474f, 0.591797f, 0.623535f,
+ 0.631348f, 0.633301f, 0.634766f, 0.635254f, 0.000000f, 0.000154f, 0.000184f, 0.000257f, 0.000265f, 0.000266f, 0.000323f, 0.000291f,
+ 0.000369f, 0.000384f, 0.000450f, 0.000472f, 0.000505f, 0.000572f, 0.000577f, 0.000604f, 0.000636f, 0.000675f, 0.000699f, 0.000736f,
+ 0.000787f, 0.000840f, 0.000890f, 0.000945f, 0.000988f, 0.001039f, 0.001165f, 0.001165f, 0.001266f, 0.001318f, 0.001410f, 0.001550f,
+ 0.001618f, 0.001743f, 0.001866f, 0.001997f, 0.002151f, 0.002319f, 0.002562f, 0.002779f, 0.002975f, 0.003298f, 0.003674f, 0.004131f,
+ 0.004604f, 0.005268f, 0.006065f, 0.007027f, 0.008316f, 0.009949f, 0.012390f, 0.015526f, 0.019852f, 0.026733f, 0.036682f, 0.051666f,
+ 0.072449f, 0.099792f, 0.574707f, 0.608398f, 0.614746f, 0.618164f, 0.619629f, 0.621094f, 0.000000f, 0.000008f, 0.000146f, 0.000181f,
+ 0.000203f, 0.000243f, 0.000206f, 0.000250f, 0.000257f, 0.000283f, 0.000335f, 0.000293f, 0.000304f, 0.000368f, 0.000373f, 0.000435f,
+ 0.000418f, 0.000468f, 0.000539f, 0.000540f, 0.000564f, 0.000598f, 0.000628f, 0.000657f, 0.000716f, 0.000724f, 0.000797f, 0.000807f,
+ 0.000883f, 0.001002f, 0.000974f, 0.001037f, 0.001104f, 0.001196f, 0.001316f, 0.001394f, 0.001445f, 0.001574f, 0.001746f, 0.001829f,
+ 0.002005f, 0.002222f, 0.002401f, 0.002699f, 0.003057f, 0.003372f, 0.003874f, 0.004505f, 0.005360f, 0.006500f, 0.007927f, 0.009972f,
+ 0.012878f, 0.017258f, 0.024155f, 0.035339f, 0.052795f, 0.077637f, 0.558105f, 0.592285f, 0.600586f, 0.602539f, 0.604004f, 0.605469f,
+ 0.000000f, 0.000107f, 0.000122f, 0.000093f, 0.000133f, 0.000142f, 0.000149f, 0.000174f, 0.000174f, 0.000184f, 0.000190f, 0.000234f,
+ 0.000214f, 0.000250f, 0.000273f, 0.000286f, 0.000292f, 0.000302f, 0.000329f, 0.000336f, 0.000366f, 0.000391f, 0.000408f, 0.000444f,
+ 0.000452f, 0.000495f, 0.000531f, 0.000559f, 0.000578f, 0.000611f, 0.000659f, 0.000675f, 0.000757f, 0.000771f, 0.000854f, 0.000906f,
+ 0.000957f, 0.001004f, 0.001102f, 0.001187f, 0.001267f, 0.001394f, 0.001546f, 0.001683f, 0.001922f, 0.002094f, 0.002420f, 0.002754f,
+ 0.003254f, 0.003878f, 0.004757f, 0.005997f, 0.007812f, 0.010544f, 0.014786f, 0.022324f, 0.035522f, 0.057465f, 0.541504f, 0.576172f,
+ 0.583984f, 0.585938f, 0.588379f, 0.590332f, 0.000000f, 0.000099f, 0.000091f, 0.000084f, 0.000084f, 0.000086f, 0.000089f, 0.000101f,
+ 0.000105f, 0.000109f, 0.000122f, 0.000124f, 0.000132f, 0.000146f, 0.000171f, 0.000172f, 0.000176f, 0.000198f, 0.000197f, 0.000239f,
+ 0.000218f, 0.000235f, 0.000240f, 0.000281f, 0.000309f, 0.000301f, 0.000312f, 0.000321f, 0.000347f, 0.000370f, 0.000387f, 0.000419f,
+ 0.000444f, 0.000458f, 0.000513f, 0.000536f, 0.000570f, 0.000607f, 0.000688f, 0.000703f, 0.000754f, 0.000834f, 0.000890f, 0.000997f,
+ 0.001100f, 0.001238f, 0.001410f, 0.001584f, 0.001859f, 0.002207f, 0.002665f, 0.003323f, 0.004353f, 0.005947f, 0.008492f, 0.012909f,
+ 0.021606f, 0.039368f, 0.522461f, 0.559082f, 0.566406f, 0.569824f, 0.572266f, 0.572754f, 0.000108f, 0.000089f, 0.000079f, 0.000072f,
+ 0.000068f, 0.000065f, 0.000061f, 0.000057f, 0.000061f, 0.000062f, 0.000063f, 0.000086f, 0.000070f, 0.000071f, 0.000095f, 0.000080f,
+ 0.000107f, 0.000113f, 0.000115f, 0.000124f, 0.000121f, 0.000130f, 0.000151f, 0.000154f, 0.000164f, 0.000170f, 0.000176f, 0.000189f,
+ 0.000193f, 0.000215f, 0.000211f, 0.000242f, 0.000252f, 0.000260f, 0.000280f, 0.000293f, 0.000312f, 0.000350f, 0.000359f, 0.000389f,
+ 0.000410f, 0.000452f, 0.000481f, 0.000535f, 0.000578f, 0.000643f, 0.000718f, 0.000812f, 0.000939f, 0.001107f, 0.001329f, 0.001644f,
+ 0.002155f, 0.002930f, 0.004284f, 0.006706f, 0.011452f, 0.023895f, 0.504395f, 0.542480f, 0.550293f, 0.553711f, 0.555664f, 0.557129f,
+ 0.000093f, 0.000072f, 0.000063f, 0.000058f, 0.000053f, 0.000050f, 0.000047f, 0.000046f, 0.000044f, 0.000042f, 0.000039f, 0.000037f,
+ 0.000042f, 0.000035f, 0.000036f, 0.000037f, 0.000051f, 0.000046f, 0.000057f, 0.000058f, 0.000061f, 0.000062f, 0.000066f, 0.000069f,
+ 0.000072f, 0.000087f, 0.000077f, 0.000088f, 0.000093f, 0.000099f, 0.000103f, 0.000109f, 0.000115f, 0.000122f, 0.000139f, 0.000134f,
+ 0.000142f, 0.000170f, 0.000175f, 0.000179f, 0.000192f, 0.000203f, 0.000228f, 0.000245f, 0.000265f, 0.000291f, 0.000326f, 0.000360f,
+ 0.000420f, 0.000481f, 0.000574f, 0.000686f, 0.000887f, 0.001203f, 0.001759f, 0.002892f, 0.005318f, 0.011955f, 0.487305f, 0.524902f,
+ 0.534180f, 0.538086f, 0.539551f, 0.540527f, 0.000066f, 0.000049f, 0.000041f, 0.000037f, 0.000034f, 0.000033f, 0.000032f, 0.000030f,
+ 0.000029f, 0.000028f, 0.000028f, 0.000027f, 0.000026f, 0.000025f, 0.000024f, 0.000023f, 0.000022f, 0.000021f, 0.000022f, 0.000023f,
+ 0.000019f, 0.000018f, 0.000019f, 0.000024f, 0.000026f, 0.000029f, 0.000032f, 0.000032f, 0.000036f, 0.000034f, 0.000040f, 0.000041f,
+ 0.000043f, 0.000049f, 0.000049f, 0.000050f, 0.000056f, 0.000059f, 0.000067f, 0.000067f, 0.000074f, 0.000078f, 0.000082f, 0.000092f,
+ 0.000094f, 0.000103f, 0.000120f, 0.000130f, 0.000141f, 0.000163f, 0.000191f, 0.000230f, 0.000286f, 0.000374f, 0.000543f, 0.000890f,
+ 0.001802f, 0.004650f, 0.468994f, 0.507812f, 0.516602f, 0.520508f, 0.522461f, 0.523926f, 0.000007f, 0.000008f, 0.000008f, 0.000008f,
+ 0.000011f, 0.000010f, 0.000010f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000012f,
+ 0.000012f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000010f, 0.000009f, 0.000009f,
+ 0.000008f, 0.000008f, 0.000009f, 0.000009f, 0.000009f, 0.000009f, 0.000010f, 0.000011f, 0.000012f, 0.000014f, 0.000013f, 0.000016f,
+ 0.000015f, 0.000018f, 0.000020f, 0.000021f, 0.000022f, 0.000025f, 0.000024f, 0.000025f, 0.000030f, 0.000031f, 0.000040f, 0.000046f,
+ 0.000052f, 0.000071f, 0.000099f, 0.000147f, 0.000306f, 0.001072f, 0.450439f, 0.491211f, 0.499756f, 0.503418f, 0.505859f, 0.507324f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000004f, 0.000007f, 0.000024f, 0.432129f, 0.474121f,
+ 0.482666f, 0.486572f, 0.489014f, 0.490234f,
+ },
+ {
+ 0.027573f, 0.080750f, 0.130981f, 0.177734f, 0.222290f, 0.263672f, 0.302002f, 0.338623f, 0.373291f, 0.405029f, 0.435791f, 0.464111f,
+ 0.490967f, 0.516602f, 0.540039f, 0.563477f, 0.584961f, 0.605469f, 0.625000f, 0.644043f, 0.660645f, 0.677246f, 0.693848f, 0.708496f,
+ 0.724121f, 0.738281f, 0.751465f, 0.764648f, 0.776855f, 0.789062f, 0.799805f, 0.810547f, 0.821289f, 0.831055f, 0.840820f, 0.850098f,
+ 0.859863f, 0.867676f, 0.876953f, 0.884277f, 0.892578f, 0.900391f, 0.907227f, 0.914551f, 0.921875f, 0.928223f, 0.934082f, 0.940430f,
+ 0.946777f, 0.952637f, 0.957520f, 0.964355f, 0.968262f, 0.974121f, 0.979004f, 0.983887f, 0.989258f, 0.994141f, 0.993164f, 0.983398f,
+ 0.976074f, 0.969238f, 0.962891f, 0.957031f, 0.022873f, 0.067871f, 0.111511f, 0.153809f, 0.193359f, 0.232788f, 0.268799f, 0.303223f,
+ 0.337402f, 0.368652f, 0.399414f, 0.427734f, 0.455078f, 0.481201f, 0.506348f, 0.529785f, 0.552246f, 0.573242f, 0.593750f, 0.613281f,
+ 0.632324f, 0.650391f, 0.667480f, 0.683105f, 0.698730f, 0.713867f, 0.728516f, 0.741211f, 0.755371f, 0.767578f, 0.779785f, 0.791504f,
+ 0.803223f, 0.813477f, 0.823242f, 0.834473f, 0.843750f, 0.853027f, 0.861816f, 0.870605f, 0.878906f, 0.887695f, 0.895996f, 0.901855f,
+ 0.910645f, 0.917480f, 0.923828f, 0.930176f, 0.937012f, 0.943359f, 0.949707f, 0.955078f, 0.960938f, 0.966797f, 0.972656f, 0.977051f,
+ 0.982422f, 0.987305f, 0.989746f, 0.981445f, 0.973633f, 0.967773f, 0.961426f, 0.956055f, 0.019089f, 0.057007f, 0.095215f, 0.132202f,
+ 0.168823f, 0.204712f, 0.238281f, 0.272217f, 0.304688f, 0.334717f, 0.364502f, 0.392822f, 0.420898f, 0.446533f, 0.471924f, 0.495850f,
+ 0.518555f, 0.541992f, 0.562988f, 0.582520f, 0.602539f, 0.621094f, 0.639160f, 0.655762f, 0.672852f, 0.687988f, 0.703613f, 0.718262f,
+ 0.732422f, 0.746094f, 0.758789f, 0.771484f, 0.783203f, 0.795898f, 0.807129f, 0.817383f, 0.827637f, 0.837402f, 0.846680f, 0.856445f,
+ 0.865234f, 0.874023f, 0.882324f, 0.890137f, 0.898438f, 0.905273f, 0.913574f, 0.920410f, 0.927246f, 0.934082f, 0.940918f, 0.946777f,
+ 0.953125f, 0.958496f, 0.964844f, 0.969727f, 0.975586f, 0.980957f, 0.986816f, 0.979004f, 0.971680f, 0.965332f, 0.959961f, 0.954590f,
+ 0.016327f, 0.048676f, 0.081787f, 0.114807f, 0.147705f, 0.180176f, 0.211426f, 0.243652f, 0.273438f, 0.303223f, 0.332031f, 0.360107f,
+ 0.386963f, 0.412598f, 0.438477f, 0.462891f, 0.487305f, 0.510254f, 0.530762f, 0.552246f, 0.572754f, 0.590820f, 0.610352f, 0.629883f,
+ 0.647461f, 0.662598f, 0.679688f, 0.693848f, 0.709961f, 0.723633f, 0.737305f, 0.750977f, 0.763672f, 0.776367f, 0.788086f, 0.799316f,
+ 0.810059f, 0.820801f, 0.832031f, 0.841309f, 0.851074f, 0.860352f, 0.868652f, 0.877930f, 0.886230f, 0.894531f, 0.902832f, 0.910156f,
+ 0.916504f, 0.924316f, 0.930664f, 0.937500f, 0.943848f, 0.950684f, 0.957031f, 0.962891f, 0.968262f, 0.974121f, 0.983887f, 0.976074f,
+ 0.969727f, 0.963867f, 0.958496f, 0.953125f, 0.013573f, 0.041901f, 0.070801f, 0.100098f, 0.129517f, 0.159058f, 0.187866f, 0.217041f,
+ 0.246216f, 0.274414f, 0.302002f, 0.328857f, 0.354980f, 0.381592f, 0.406738f, 0.431641f, 0.455322f, 0.478271f, 0.500000f, 0.521484f,
+ 0.541992f, 0.563477f, 0.583008f, 0.600098f, 0.619141f, 0.636719f, 0.653320f, 0.671387f, 0.684570f, 0.699707f, 0.715332f, 0.729492f,
+ 0.743164f, 0.755371f, 0.768555f, 0.780762f, 0.792480f, 0.804199f, 0.814453f, 0.824707f, 0.835449f, 0.845215f, 0.854980f, 0.864746f,
+ 0.874023f, 0.882812f, 0.890137f, 0.898438f, 0.905762f, 0.914062f, 0.921387f, 0.928223f, 0.935059f, 0.941406f, 0.948242f, 0.955078f,
+ 0.961426f, 0.966797f, 0.980957f, 0.973633f, 0.967773f, 0.961914f, 0.956543f, 0.951660f, 0.011681f, 0.036316f, 0.061584f, 0.087524f,
+ 0.113342f, 0.140259f, 0.167358f, 0.194214f, 0.220947f, 0.247437f, 0.273926f, 0.300537f, 0.325684f, 0.351074f, 0.375732f, 0.400146f,
+ 0.423828f, 0.446533f, 0.469482f, 0.491943f, 0.512695f, 0.532715f, 0.553223f, 0.573242f, 0.592285f, 0.609863f, 0.627930f, 0.644531f,
+ 0.660156f, 0.676758f, 0.691406f, 0.706055f, 0.720215f, 0.734863f, 0.749023f, 0.762207f, 0.774414f, 0.786133f, 0.797852f, 0.809082f,
+ 0.820801f, 0.831055f, 0.840332f, 0.850098f, 0.859863f, 0.869629f, 0.878418f, 0.886719f, 0.895508f, 0.903809f, 0.910645f, 0.918945f,
+ 0.925781f, 0.932617f, 0.939453f, 0.947754f, 0.953613f, 0.958984f, 0.977539f, 0.970703f, 0.964844f, 0.959473f, 0.954102f, 0.949707f,
+ 0.010330f, 0.031525f, 0.053406f, 0.076538f, 0.100159f, 0.124084f, 0.148193f, 0.173096f, 0.197998f, 0.223267f, 0.247681f, 0.273193f,
+ 0.297607f, 0.322021f, 0.346924f, 0.370117f, 0.394043f, 0.417236f, 0.439697f, 0.462158f, 0.483887f, 0.504883f, 0.524902f, 0.545410f,
+ 0.563477f, 0.583008f, 0.602539f, 0.618652f, 0.636230f, 0.652344f, 0.669922f, 0.685059f, 0.699219f, 0.714355f, 0.729004f, 0.741211f,
+ 0.755371f, 0.767578f, 0.780762f, 0.792480f, 0.803711f, 0.815918f, 0.825195f, 0.836914f, 0.846191f, 0.855957f, 0.864746f, 0.874512f,
+ 0.883301f, 0.891602f, 0.900391f, 0.908203f, 0.916016f, 0.923828f, 0.931152f, 0.937988f, 0.945801f, 0.952148f, 0.974121f, 0.967773f,
+ 0.962891f, 0.957520f, 0.952637f, 0.947754f, 0.009186f, 0.027359f, 0.047302f, 0.067505f, 0.088806f, 0.109924f, 0.132202f, 0.154907f,
+ 0.177246f, 0.201050f, 0.224121f, 0.247925f, 0.271240f, 0.295410f, 0.318359f, 0.341797f, 0.365234f, 0.387939f, 0.410156f, 0.432861f,
+ 0.454590f, 0.475586f, 0.495850f, 0.517090f, 0.536621f, 0.556152f, 0.575195f, 0.592773f, 0.609863f, 0.628418f, 0.645020f, 0.661133f,
+ 0.677246f, 0.692383f, 0.707520f, 0.721191f, 0.735352f, 0.748047f, 0.762207f, 0.774414f, 0.786621f, 0.798828f, 0.810547f, 0.820801f,
+ 0.831543f, 0.842285f, 0.852539f, 0.862305f, 0.871094f, 0.880859f, 0.889648f, 0.898438f, 0.906738f, 0.914551f, 0.921875f, 0.929199f,
+ 0.936035f, 0.944824f, 0.971191f, 0.965332f, 0.959473f, 0.955078f, 0.950195f, 0.945801f, 0.008041f, 0.024384f, 0.041321f, 0.059631f,
+ 0.078003f, 0.097656f, 0.117554f, 0.138428f, 0.159912f, 0.181152f, 0.203003f, 0.224976f, 0.247070f, 0.269531f, 0.292480f, 0.314697f,
+ 0.337891f, 0.360352f, 0.382324f, 0.403809f, 0.426025f, 0.447998f, 0.468018f, 0.488770f, 0.508301f, 0.528320f, 0.547852f, 0.567383f,
+ 0.585449f, 0.603516f, 0.620605f, 0.637695f, 0.654297f, 0.670410f, 0.686523f, 0.700195f, 0.715820f, 0.729980f, 0.743164f, 0.756836f,
+ 0.769531f, 0.782715f, 0.794434f, 0.805664f, 0.816895f, 0.827637f, 0.838379f, 0.848633f, 0.859375f, 0.868164f, 0.877930f, 0.887695f,
+ 0.895996f, 0.905273f, 0.912598f, 0.920898f, 0.928711f, 0.936035f, 0.966797f, 0.962402f, 0.957031f, 0.952637f, 0.947754f, 0.943848f,
+ 0.007095f, 0.021515f, 0.036926f, 0.052704f, 0.069641f, 0.087463f, 0.105347f, 0.123413f, 0.143188f, 0.163452f, 0.183105f, 0.204102f,
+ 0.225220f, 0.246704f, 0.268066f, 0.290283f, 0.311768f, 0.333740f, 0.355225f, 0.376465f, 0.397949f, 0.419434f, 0.440430f, 0.461670f,
+ 0.481445f, 0.500977f, 0.520020f, 0.540527f, 0.559570f, 0.578125f, 0.595703f, 0.613770f, 0.630371f, 0.646973f, 0.663086f, 0.678223f,
+ 0.694336f, 0.709473f, 0.723145f, 0.736328f, 0.750000f, 0.764648f, 0.777344f, 0.790039f, 0.801270f, 0.812988f, 0.824707f, 0.834961f,
+ 0.846191f, 0.856934f, 0.865723f, 0.875977f, 0.884766f, 0.894531f, 0.903320f, 0.911621f, 0.919922f, 0.927734f, 0.962891f, 0.959473f,
+ 0.954102f, 0.949219f, 0.945312f, 0.941406f, 0.006138f, 0.019150f, 0.033051f, 0.047089f, 0.061829f, 0.077515f, 0.094299f, 0.111084f,
+ 0.128174f, 0.146729f, 0.165771f, 0.185059f, 0.205200f, 0.224731f, 0.245361f, 0.265625f, 0.286865f, 0.307861f, 0.328857f, 0.350098f,
+ 0.370605f, 0.392090f, 0.413086f, 0.433594f, 0.454346f, 0.474609f, 0.493896f, 0.513672f, 0.532227f, 0.552734f, 0.569824f, 0.588867f,
+ 0.605957f, 0.623047f, 0.640625f, 0.656738f, 0.672852f, 0.688477f, 0.703613f, 0.717773f, 0.732910f, 0.746582f, 0.759766f, 0.772461f,
+ 0.786621f, 0.798340f, 0.810059f, 0.820312f, 0.832520f, 0.842773f, 0.853516f, 0.863770f, 0.873535f, 0.883789f, 0.892578f, 0.901367f,
+ 0.910645f, 0.919434f, 0.958984f, 0.955566f, 0.951172f, 0.946777f, 0.942871f, 0.938965f, 0.005424f, 0.017059f, 0.029541f, 0.042023f,
+ 0.055389f, 0.069397f, 0.083984f, 0.099670f, 0.115601f, 0.132324f, 0.149292f, 0.167114f, 0.185547f, 0.204468f, 0.224121f, 0.243896f,
+ 0.262939f, 0.283691f, 0.304443f, 0.323486f, 0.345459f, 0.365479f, 0.386230f, 0.407471f, 0.426758f, 0.448486f, 0.467529f, 0.487061f,
+ 0.506348f, 0.526367f, 0.545410f, 0.563965f, 0.581543f, 0.600098f, 0.617676f, 0.634277f, 0.650391f, 0.666016f, 0.682617f, 0.697754f,
+ 0.712891f, 0.727539f, 0.741211f, 0.755859f, 0.769043f, 0.782227f, 0.793945f, 0.806152f, 0.818848f, 0.830566f, 0.840332f, 0.851074f,
+ 0.861328f, 0.872070f, 0.881836f, 0.892090f, 0.900879f, 0.910645f, 0.955566f, 0.952637f, 0.948730f, 0.943359f, 0.939941f, 0.935547f,
+ 0.004833f, 0.015442f, 0.026169f, 0.037689f, 0.049683f, 0.062164f, 0.075806f, 0.089539f, 0.103760f, 0.119263f, 0.134888f, 0.151978f,
+ 0.168335f, 0.186646f, 0.204102f, 0.223022f, 0.242065f, 0.260986f, 0.280518f, 0.300537f, 0.320801f, 0.340820f, 0.360107f, 0.381104f,
+ 0.401367f, 0.421387f, 0.441650f, 0.460449f, 0.480957f, 0.500000f, 0.519531f, 0.538574f, 0.557129f, 0.575684f, 0.593262f, 0.610840f,
+ 0.628906f, 0.645508f, 0.662109f, 0.677246f, 0.692871f, 0.708008f, 0.723145f, 0.738281f, 0.751465f, 0.766113f, 0.778320f, 0.791504f,
+ 0.802246f, 0.816406f, 0.827637f, 0.838867f, 0.850098f, 0.860352f, 0.871582f, 0.881348f, 0.890137f, 0.899902f, 0.951660f, 0.948730f,
+ 0.944824f, 0.940918f, 0.937012f, 0.933594f, 0.004269f, 0.013809f, 0.023911f, 0.033569f, 0.044342f, 0.056213f, 0.068054f, 0.080811f,
+ 0.093933f, 0.107910f, 0.122131f, 0.137451f, 0.152710f, 0.169434f, 0.185791f, 0.203979f, 0.221436f, 0.239990f, 0.257812f, 0.277344f,
+ 0.296631f, 0.316162f, 0.335693f, 0.355713f, 0.375244f, 0.395996f, 0.416016f, 0.436035f, 0.455078f, 0.474365f, 0.494629f, 0.513184f,
+ 0.532715f, 0.550781f, 0.569336f, 0.586914f, 0.604980f, 0.622559f, 0.639648f, 0.655762f, 0.672363f, 0.688477f, 0.704102f, 0.718750f,
+ 0.733887f, 0.747559f, 0.761230f, 0.775391f, 0.788574f, 0.800781f, 0.814453f, 0.825684f, 0.837402f, 0.848633f, 0.859375f, 0.870605f,
+ 0.880371f, 0.891113f, 0.947754f, 0.945312f, 0.941895f, 0.937988f, 0.934082f, 0.931152f, 0.004028f, 0.012581f, 0.021133f, 0.030396f,
+ 0.039948f, 0.050323f, 0.061523f, 0.072815f, 0.084961f, 0.096985f, 0.110535f, 0.124756f, 0.138916f, 0.153687f, 0.169800f, 0.185669f,
+ 0.202881f, 0.219116f, 0.237305f, 0.255615f, 0.273926f, 0.293213f, 0.311768f, 0.331055f, 0.351074f, 0.370605f, 0.390381f, 0.409668f,
+ 0.429688f, 0.449707f, 0.468994f, 0.487549f, 0.506836f, 0.526367f, 0.545898f, 0.562988f, 0.581543f, 0.599121f, 0.616699f, 0.634766f,
+ 0.651367f, 0.667480f, 0.683594f, 0.699707f, 0.714844f, 0.730957f, 0.744141f, 0.758789f, 0.772949f, 0.785645f, 0.799316f, 0.812500f,
+ 0.823730f, 0.836914f, 0.847168f, 0.859375f, 0.869629f, 0.880371f, 0.942383f, 0.941406f, 0.937500f, 0.934570f, 0.931152f, 0.927734f,
+ 0.003613f, 0.011391f, 0.018875f, 0.027679f, 0.036133f, 0.045624f, 0.055420f, 0.065491f, 0.076416f, 0.088135f, 0.099487f, 0.112427f,
+ 0.126099f, 0.139771f, 0.154419f, 0.169556f, 0.184814f, 0.201050f, 0.218262f, 0.234985f, 0.252441f, 0.271484f, 0.289062f, 0.308594f,
+ 0.326660f, 0.346924f, 0.365234f, 0.384521f, 0.404541f, 0.424072f, 0.443359f, 0.463135f, 0.482422f, 0.501953f, 0.521484f, 0.539551f,
+ 0.558594f, 0.576660f, 0.595215f, 0.612793f, 0.629883f, 0.647949f, 0.663574f, 0.679688f, 0.695801f, 0.711426f, 0.727539f, 0.741699f,
+ 0.757324f, 0.770996f, 0.785156f, 0.798828f, 0.811035f, 0.823730f, 0.835449f, 0.848145f, 0.858887f, 0.870605f, 0.937988f, 0.937988f,
+ 0.934570f, 0.931152f, 0.927734f, 0.924805f, 0.003248f, 0.010185f, 0.017395f, 0.025055f, 0.032928f, 0.041321f, 0.049957f, 0.059265f,
+ 0.069092f, 0.079407f, 0.090820f, 0.101746f, 0.113770f, 0.126953f, 0.140381f, 0.154053f, 0.168701f, 0.184082f, 0.199951f, 0.216431f,
+ 0.232788f, 0.250000f, 0.267578f, 0.285645f, 0.303955f, 0.322998f, 0.341553f, 0.361084f, 0.379150f, 0.399414f, 0.418701f, 0.437988f,
+ 0.457275f, 0.477051f, 0.496094f, 0.515137f, 0.534180f, 0.553223f, 0.571289f, 0.589844f, 0.606934f, 0.625488f, 0.643066f, 0.659668f,
+ 0.676758f, 0.692871f, 0.708984f, 0.725098f, 0.740234f, 0.753906f, 0.769043f, 0.782227f, 0.796387f, 0.810059f, 0.822266f, 0.834961f,
+ 0.847168f, 0.859375f, 0.933594f, 0.933594f, 0.931152f, 0.927246f, 0.923828f, 0.921387f, 0.002914f, 0.009361f, 0.015793f, 0.022659f,
+ 0.029938f, 0.037354f, 0.045593f, 0.053406f, 0.062988f, 0.072083f, 0.081665f, 0.092712f, 0.103943f, 0.114990f, 0.128174f, 0.140503f,
+ 0.153809f, 0.167725f, 0.182251f, 0.198242f, 0.213623f, 0.230225f, 0.246826f, 0.263672f, 0.281494f, 0.300049f, 0.318604f, 0.337158f,
+ 0.356201f, 0.374756f, 0.394531f, 0.413574f, 0.433105f, 0.451904f, 0.471680f, 0.491211f, 0.509766f, 0.529297f, 0.547852f, 0.566895f,
+ 0.584961f, 0.603516f, 0.621094f, 0.638672f, 0.656738f, 0.673340f, 0.689453f, 0.706543f, 0.722656f, 0.737793f, 0.752930f, 0.767578f,
+ 0.781250f, 0.796875f, 0.809082f, 0.823242f, 0.835449f, 0.847656f, 0.929199f, 0.929199f, 0.927246f, 0.923828f, 0.920898f, 0.917969f,
+ 0.002766f, 0.008736f, 0.014442f, 0.020691f, 0.027054f, 0.033905f, 0.040924f, 0.048645f, 0.056976f, 0.065674f, 0.074951f, 0.084229f,
+ 0.094116f, 0.105225f, 0.116333f, 0.127563f, 0.139771f, 0.153564f, 0.166626f, 0.181030f, 0.196411f, 0.211182f, 0.227417f, 0.243896f,
+ 0.260742f, 0.277588f, 0.295898f, 0.314209f, 0.332031f, 0.351562f, 0.370117f, 0.389404f, 0.408203f, 0.428223f, 0.447266f, 0.467041f,
+ 0.486084f, 0.505859f, 0.524414f, 0.543945f, 0.562012f, 0.581543f, 0.600098f, 0.617676f, 0.636230f, 0.654297f, 0.670898f, 0.687500f,
+ 0.704102f, 0.720703f, 0.736816f, 0.751465f, 0.766113f, 0.781738f, 0.796387f, 0.809082f, 0.823242f, 0.835938f, 0.923828f, 0.925781f,
+ 0.922852f, 0.920410f, 0.916992f, 0.914551f, 0.002483f, 0.007599f, 0.013161f, 0.018555f, 0.024551f, 0.030670f, 0.037476f, 0.044464f,
+ 0.051636f, 0.059174f, 0.067688f, 0.075928f, 0.085693f, 0.095093f, 0.105591f, 0.116394f, 0.127441f, 0.139648f, 0.152344f, 0.165527f,
+ 0.179565f, 0.193970f, 0.208862f, 0.224487f, 0.240356f, 0.256836f, 0.274658f, 0.291748f, 0.310059f, 0.328369f, 0.346680f, 0.365234f,
+ 0.384521f, 0.404297f, 0.423340f, 0.442139f, 0.462646f, 0.481445f, 0.500977f, 0.520020f, 0.540039f, 0.559082f, 0.577148f, 0.596191f,
+ 0.614746f, 0.632812f, 0.651367f, 0.669434f, 0.685059f, 0.702637f, 0.718750f, 0.734375f, 0.750488f, 0.766113f, 0.780762f, 0.795410f,
+ 0.811035f, 0.823730f, 0.919434f, 0.920898f, 0.918457f, 0.916016f, 0.913086f, 0.910645f, 0.002457f, 0.007114f, 0.011757f, 0.016708f,
+ 0.022125f, 0.027786f, 0.033752f, 0.040375f, 0.046661f, 0.053864f, 0.061584f, 0.069336f, 0.077515f, 0.086365f, 0.095947f, 0.105896f,
+ 0.116638f, 0.127075f, 0.138916f, 0.151245f, 0.164062f, 0.177490f, 0.191528f, 0.206177f, 0.221802f, 0.237427f, 0.253906f, 0.270508f,
+ 0.287842f, 0.305664f, 0.323730f, 0.342285f, 0.361572f, 0.379639f, 0.399170f, 0.418457f, 0.438965f, 0.458252f, 0.477295f, 0.497559f,
+ 0.516113f, 0.536133f, 0.554688f, 0.574707f, 0.593750f, 0.612305f, 0.630859f, 0.648926f, 0.666504f, 0.684082f, 0.701660f, 0.717773f,
+ 0.734863f, 0.751465f, 0.766602f, 0.781738f, 0.797852f, 0.812012f, 0.913086f, 0.916016f, 0.913574f, 0.911621f, 0.909180f, 0.906250f,
+ 0.002132f, 0.006493f, 0.010750f, 0.015717f, 0.020569f, 0.025604f, 0.030823f, 0.036682f, 0.043060f, 0.049286f, 0.055786f, 0.062988f,
+ 0.070557f, 0.078918f, 0.086914f, 0.096191f, 0.105530f, 0.116028f, 0.126953f, 0.138306f, 0.149902f, 0.162231f, 0.175537f, 0.189453f,
+ 0.203491f, 0.218628f, 0.234131f, 0.250000f, 0.266602f, 0.284180f, 0.301514f, 0.319580f, 0.338135f, 0.356689f, 0.375977f, 0.395020f,
+ 0.413818f, 0.434082f, 0.452881f, 0.473145f, 0.492920f, 0.512207f, 0.532227f, 0.552246f, 0.570801f, 0.591309f, 0.609375f, 0.629395f,
+ 0.646973f, 0.665527f, 0.683105f, 0.700684f, 0.717773f, 0.734863f, 0.751465f, 0.767578f, 0.782715f, 0.799316f, 0.908203f, 0.911133f,
+ 0.909180f, 0.907227f, 0.904785f, 0.902832f, 0.001891f, 0.006008f, 0.010025f, 0.014122f, 0.018616f, 0.023239f, 0.028442f, 0.033691f,
+ 0.038757f, 0.044556f, 0.050964f, 0.057465f, 0.064087f, 0.071167f, 0.079224f, 0.087463f, 0.096008f, 0.105591f, 0.115356f, 0.125488f,
+ 0.136597f, 0.148193f, 0.160278f, 0.173218f, 0.186768f, 0.200684f, 0.215332f, 0.231323f, 0.246338f, 0.262939f, 0.279785f, 0.297607f,
+ 0.314941f, 0.333984f, 0.353271f, 0.371094f, 0.391357f, 0.409668f, 0.430420f, 0.448975f, 0.469482f, 0.489746f, 0.509277f, 0.528809f,
+ 0.549316f, 0.568848f, 0.588379f, 0.607910f, 0.626953f, 0.645996f, 0.664062f, 0.683105f, 0.700684f, 0.718262f, 0.735840f, 0.751953f,
+ 0.768555f, 0.785645f, 0.902344f, 0.906250f, 0.904785f, 0.902832f, 0.900391f, 0.898438f, 0.001732f, 0.005573f, 0.009193f, 0.012932f,
+ 0.017075f, 0.021286f, 0.025406f, 0.030289f, 0.035675f, 0.040344f, 0.046326f, 0.052032f, 0.058411f, 0.064575f, 0.072205f, 0.079834f,
+ 0.087708f, 0.095947f, 0.104797f, 0.114380f, 0.124451f, 0.134888f, 0.146606f, 0.158691f, 0.170776f, 0.184082f, 0.197510f, 0.212524f,
+ 0.227417f, 0.243164f, 0.259521f, 0.276367f, 0.293457f, 0.311768f, 0.329590f, 0.348633f, 0.367188f, 0.386230f, 0.406006f, 0.425781f,
+ 0.446533f, 0.465332f, 0.486084f, 0.505859f, 0.526367f, 0.545898f, 0.567383f, 0.585938f, 0.605957f, 0.625977f, 0.645508f, 0.664551f,
+ 0.683105f, 0.701172f, 0.718750f, 0.736816f, 0.754395f, 0.770508f, 0.896484f, 0.900879f, 0.900391f, 0.897949f, 0.895996f, 0.894043f,
+ 0.001713f, 0.004684f, 0.008339f, 0.011818f, 0.015450f, 0.019409f, 0.023605f, 0.027832f, 0.032349f, 0.036865f, 0.041809f, 0.047302f,
+ 0.052673f, 0.058838f, 0.065613f, 0.072083f, 0.079407f, 0.087280f, 0.095337f, 0.104126f, 0.113037f, 0.122986f, 0.133667f, 0.144897f,
+ 0.156250f, 0.168579f, 0.181396f, 0.195068f, 0.208984f, 0.224243f, 0.239624f, 0.255859f, 0.272461f, 0.289551f, 0.307617f, 0.326172f,
+ 0.344482f, 0.363770f, 0.383301f, 0.402588f, 0.422607f, 0.443115f, 0.463135f, 0.483154f, 0.503418f, 0.523926f, 0.544434f, 0.564941f,
+ 0.584473f, 0.604980f, 0.624512f, 0.645508f, 0.664551f, 0.683594f, 0.701660f, 0.721191f, 0.738281f, 0.755859f, 0.889648f, 0.895996f,
+ 0.895020f, 0.893066f, 0.891602f, 0.889160f, 0.001545f, 0.004745f, 0.007710f, 0.010979f, 0.014450f, 0.017807f, 0.021469f, 0.025238f,
+ 0.029282f, 0.033661f, 0.038177f, 0.043182f, 0.048157f, 0.053436f, 0.059326f, 0.065674f, 0.072205f, 0.078857f, 0.086548f, 0.094604f,
+ 0.102905f, 0.111816f, 0.121521f, 0.131592f, 0.142334f, 0.153442f, 0.165894f, 0.178345f, 0.192139f, 0.205933f, 0.220703f, 0.236084f,
+ 0.251709f, 0.268555f, 0.285645f, 0.303467f, 0.321777f, 0.340332f, 0.359619f, 0.379150f, 0.398682f, 0.419189f, 0.440430f, 0.460449f,
+ 0.480957f, 0.501465f, 0.521973f, 0.543457f, 0.563477f, 0.584961f, 0.604492f, 0.625488f, 0.645508f, 0.665039f, 0.684082f, 0.704102f,
+ 0.723145f, 0.741211f, 0.885254f, 0.890137f, 0.889160f, 0.887695f, 0.886719f, 0.884277f, 0.001487f, 0.004356f, 0.006828f, 0.010162f,
+ 0.012993f, 0.016022f, 0.019333f, 0.023087f, 0.026886f, 0.030518f, 0.034668f, 0.039062f, 0.043671f, 0.048370f, 0.053741f, 0.059326f,
+ 0.065308f, 0.071655f, 0.078125f, 0.085693f, 0.093323f, 0.101807f, 0.110657f, 0.119507f, 0.129517f, 0.140137f, 0.151367f, 0.163330f,
+ 0.175781f, 0.188843f, 0.202759f, 0.217163f, 0.232666f, 0.248413f, 0.264893f, 0.282227f, 0.299805f, 0.318115f, 0.336914f, 0.356445f,
+ 0.375488f, 0.395996f, 0.416504f, 0.436279f, 0.457520f, 0.479004f, 0.499023f, 0.520508f, 0.541504f, 0.562988f, 0.583984f, 0.604492f,
+ 0.625488f, 0.646973f, 0.666504f, 0.687012f, 0.706055f, 0.725098f, 0.877441f, 0.885254f, 0.884766f, 0.882324f, 0.881836f, 0.880371f,
+ 0.001443f, 0.003807f, 0.006336f, 0.009171f, 0.011909f, 0.015007f, 0.018097f, 0.020905f, 0.024384f, 0.027893f, 0.031555f, 0.035370f,
+ 0.039581f, 0.044128f, 0.048889f, 0.053894f, 0.059174f, 0.065125f, 0.070984f, 0.077698f, 0.084656f, 0.091919f, 0.100037f, 0.108093f,
+ 0.117493f, 0.127563f, 0.137817f, 0.148438f, 0.159912f, 0.172485f, 0.185547f, 0.199585f, 0.213867f, 0.229248f, 0.244995f, 0.261230f,
+ 0.278564f, 0.296387f, 0.314697f, 0.333252f, 0.353271f, 0.372314f, 0.393311f, 0.413330f, 0.433594f, 0.455078f, 0.476318f, 0.497314f,
+ 0.519531f, 0.540527f, 0.562500f, 0.583496f, 0.605469f, 0.626953f, 0.648438f, 0.669434f, 0.689941f, 0.709961f, 0.870605f, 0.878906f,
+ 0.878418f, 0.877441f, 0.875488f, 0.873535f, 0.001302f, 0.003712f, 0.005859f, 0.008286f, 0.010910f, 0.013779f, 0.016235f, 0.019135f,
+ 0.021912f, 0.025345f, 0.029022f, 0.032166f, 0.036011f, 0.040131f, 0.044128f, 0.048492f, 0.053528f, 0.058533f, 0.064209f, 0.070129f,
+ 0.076355f, 0.083191f, 0.090149f, 0.098328f, 0.106628f, 0.115662f, 0.124817f, 0.134766f, 0.145630f, 0.157104f, 0.169678f, 0.182495f,
+ 0.195801f, 0.210205f, 0.225342f, 0.241455f, 0.257812f, 0.274902f, 0.292725f, 0.311035f, 0.330322f, 0.349365f, 0.369873f, 0.390137f,
+ 0.411133f, 0.432373f, 0.453369f, 0.474609f, 0.496826f, 0.519043f, 0.541504f, 0.563477f, 0.585449f, 0.606445f, 0.629395f, 0.650391f,
+ 0.672363f, 0.693848f, 0.863281f, 0.872070f, 0.872070f, 0.871582f, 0.869629f, 0.868164f, 0.001170f, 0.003151f, 0.005295f, 0.007812f,
+ 0.010132f, 0.012466f, 0.015076f, 0.017517f, 0.019943f, 0.023178f, 0.026443f, 0.029312f, 0.032471f, 0.036041f, 0.039978f, 0.044037f,
+ 0.048828f, 0.053070f, 0.057983f, 0.063232f, 0.068909f, 0.075378f, 0.081909f, 0.088745f, 0.096375f, 0.104309f, 0.113281f, 0.122437f,
+ 0.132202f, 0.142944f, 0.154419f, 0.166138f, 0.178955f, 0.192505f, 0.206421f, 0.221558f, 0.237183f, 0.253906f, 0.270996f, 0.289062f,
+ 0.308105f, 0.326904f, 0.346924f, 0.366455f, 0.387695f, 0.408936f, 0.430176f, 0.451416f, 0.474365f, 0.496582f, 0.518066f, 0.541016f,
+ 0.563965f, 0.585938f, 0.608887f, 0.630859f, 0.654297f, 0.675781f, 0.856934f, 0.865234f, 0.866211f, 0.864746f, 0.863281f, 0.862793f,
+ 0.001049f, 0.003254f, 0.005234f, 0.007263f, 0.009270f, 0.011307f, 0.013596f, 0.015869f, 0.018555f, 0.020844f, 0.023972f, 0.026566f,
+ 0.029739f, 0.033020f, 0.036316f, 0.039856f, 0.044159f, 0.048096f, 0.052277f, 0.057281f, 0.062439f, 0.067871f, 0.073792f, 0.079956f,
+ 0.087158f, 0.094055f, 0.102234f, 0.110535f, 0.119934f, 0.129517f, 0.140259f, 0.151245f, 0.162842f, 0.175537f, 0.189209f, 0.203369f,
+ 0.218262f, 0.233643f, 0.250488f, 0.268066f, 0.285645f, 0.304443f, 0.324219f, 0.343750f, 0.364014f, 0.385254f, 0.406494f, 0.428223f,
+ 0.450928f, 0.472656f, 0.495605f, 0.519043f, 0.541504f, 0.565918f, 0.588379f, 0.612305f, 0.635742f, 0.659180f, 0.850098f, 0.859863f,
+ 0.859863f, 0.858398f, 0.857910f, 0.856934f, 0.000914f, 0.002861f, 0.004742f, 0.006569f, 0.008415f, 0.010521f, 0.012596f, 0.014648f,
+ 0.016708f, 0.019089f, 0.021515f, 0.023865f, 0.026688f, 0.029572f, 0.032928f, 0.036377f, 0.039337f, 0.043365f, 0.047333f, 0.051544f,
+ 0.056305f, 0.061066f, 0.066406f, 0.071960f, 0.078247f, 0.084961f, 0.092163f, 0.099426f, 0.108215f, 0.116943f, 0.126831f, 0.136719f,
+ 0.148193f, 0.159302f, 0.171875f, 0.185669f, 0.199585f, 0.214478f, 0.230469f, 0.247070f, 0.264160f, 0.282471f, 0.301270f, 0.321045f,
+ 0.341553f, 0.362061f, 0.383545f, 0.404785f, 0.427734f, 0.449951f, 0.473389f, 0.496582f, 0.520020f, 0.543457f, 0.568359f, 0.592285f,
+ 0.615723f, 0.639648f, 0.840820f, 0.851074f, 0.853027f, 0.853027f, 0.852051f, 0.850586f, 0.000679f, 0.002518f, 0.004173f, 0.006149f,
+ 0.008064f, 0.009369f, 0.011551f, 0.013222f, 0.015175f, 0.017212f, 0.019592f, 0.021835f, 0.024048f, 0.026932f, 0.029846f, 0.032623f,
+ 0.035675f, 0.038940f, 0.042542f, 0.046295f, 0.050354f, 0.055054f, 0.059601f, 0.064880f, 0.070190f, 0.076233f, 0.082703f, 0.089661f,
+ 0.097229f, 0.105103f, 0.113831f, 0.123474f, 0.133423f, 0.144409f, 0.156006f, 0.168335f, 0.182495f, 0.196411f, 0.211304f, 0.227295f,
+ 0.243530f, 0.260986f, 0.279053f, 0.298828f, 0.318359f, 0.339111f, 0.360107f, 0.381348f, 0.403809f, 0.427490f, 0.449463f, 0.473633f,
+ 0.497803f, 0.521484f, 0.546875f, 0.570801f, 0.595703f, 0.620605f, 0.833008f, 0.845215f, 0.845703f, 0.845703f, 0.845215f, 0.843750f,
+ 0.000719f, 0.002470f, 0.003975f, 0.005337f, 0.007275f, 0.008713f, 0.010376f, 0.012032f, 0.013580f, 0.015793f, 0.017609f, 0.019501f,
+ 0.021530f, 0.024277f, 0.026657f, 0.029312f, 0.031982f, 0.035187f, 0.038086f, 0.041565f, 0.045288f, 0.049103f, 0.053436f, 0.058136f,
+ 0.062927f, 0.068054f, 0.073853f, 0.080383f, 0.087341f, 0.094666f, 0.102173f, 0.111084f, 0.120300f, 0.130859f, 0.141235f, 0.152954f,
+ 0.164429f, 0.178223f, 0.192749f, 0.207642f, 0.223145f, 0.239868f, 0.258301f, 0.276611f, 0.295654f, 0.316162f, 0.337402f, 0.358643f,
+ 0.380859f, 0.403320f, 0.427002f, 0.450684f, 0.474609f, 0.499756f, 0.523926f, 0.550781f, 0.575195f, 0.600586f, 0.824707f, 0.836914f,
+ 0.838379f, 0.838867f, 0.837402f, 0.837402f, 0.000683f, 0.002361f, 0.003649f, 0.005116f, 0.006416f, 0.008202f, 0.009460f, 0.010941f,
+ 0.012817f, 0.014099f, 0.015839f, 0.017593f, 0.019867f, 0.021988f, 0.023926f, 0.026276f, 0.028824f, 0.031311f, 0.034363f, 0.036957f,
+ 0.040375f, 0.043823f, 0.047546f, 0.051758f, 0.056183f, 0.061249f, 0.066162f, 0.071777f, 0.077942f, 0.084534f, 0.091553f, 0.099487f,
+ 0.107910f, 0.116882f, 0.127075f, 0.137451f, 0.148804f, 0.161499f, 0.174805f, 0.188721f, 0.203735f, 0.220093f, 0.237427f, 0.254639f,
+ 0.273926f, 0.293457f, 0.313965f, 0.334961f, 0.357666f, 0.379883f, 0.403076f, 0.427002f, 0.451660f, 0.476807f, 0.501953f, 0.527344f,
+ 0.553711f, 0.581055f, 0.815918f, 0.829102f, 0.831055f, 0.831055f, 0.831055f, 0.830566f, 0.000607f, 0.001863f, 0.003416f, 0.004528f,
+ 0.005943f, 0.007191f, 0.008781f, 0.009964f, 0.011337f, 0.012939f, 0.014458f, 0.015808f, 0.018051f, 0.019394f, 0.021332f, 0.023529f,
+ 0.025803f, 0.028168f, 0.030502f, 0.033020f, 0.036072f, 0.039032f, 0.042419f, 0.046082f, 0.049927f, 0.054321f, 0.058411f, 0.063538f,
+ 0.069336f, 0.075684f, 0.081787f, 0.088562f, 0.096436f, 0.104553f, 0.113281f, 0.123596f, 0.133667f, 0.145386f, 0.157471f, 0.171021f,
+ 0.185547f, 0.200562f, 0.216553f, 0.234619f, 0.251709f, 0.271240f, 0.291504f, 0.312012f, 0.333496f, 0.355957f, 0.379395f, 0.403076f,
+ 0.428223f, 0.453857f, 0.479492f, 0.506348f, 0.532715f, 0.560059f, 0.805664f, 0.820801f, 0.823730f, 0.822754f, 0.822754f, 0.822266f,
+ 0.000593f, 0.001862f, 0.002966f, 0.004341f, 0.005600f, 0.006516f, 0.007626f, 0.008995f, 0.010223f, 0.011292f, 0.012848f, 0.014427f,
+ 0.016098f, 0.017532f, 0.019165f, 0.021027f, 0.022842f, 0.024918f, 0.027115f, 0.029739f, 0.032013f, 0.034637f, 0.037506f, 0.040955f,
+ 0.044220f, 0.048065f, 0.051941f, 0.056305f, 0.061768f, 0.066528f, 0.072327f, 0.078979f, 0.085571f, 0.092834f, 0.101135f, 0.110229f,
+ 0.119690f, 0.130127f, 0.141602f, 0.153564f, 0.167114f, 0.181763f, 0.196899f, 0.213623f, 0.230957f, 0.249268f, 0.268555f, 0.289062f,
+ 0.310059f, 0.333252f, 0.355957f, 0.379883f, 0.404541f, 0.430176f, 0.456055f, 0.483887f, 0.510254f, 0.539062f, 0.797852f, 0.812988f,
+ 0.814941f, 0.815430f, 0.815918f, 0.814453f, 0.000556f, 0.001811f, 0.002998f, 0.003815f, 0.004658f, 0.005905f, 0.007099f, 0.008232f,
+ 0.009239f, 0.010483f, 0.011559f, 0.013016f, 0.014305f, 0.015671f, 0.017090f, 0.018646f, 0.020370f, 0.022369f, 0.024124f, 0.026062f,
+ 0.028458f, 0.030624f, 0.033264f, 0.036041f, 0.039307f, 0.042053f, 0.045807f, 0.049530f, 0.054016f, 0.058441f, 0.063904f, 0.069641f,
+ 0.075745f, 0.082520f, 0.089539f, 0.097717f, 0.106750f, 0.116150f, 0.126587f, 0.137817f, 0.150024f, 0.163452f, 0.177490f, 0.193359f,
+ 0.209717f, 0.227539f, 0.246704f, 0.266602f, 0.287598f, 0.309326f, 0.332520f, 0.355713f, 0.380371f, 0.406494f, 0.432861f, 0.459961f,
+ 0.488525f, 0.517090f, 0.787598f, 0.804199f, 0.806641f, 0.807617f, 0.807617f, 0.807129f, 0.000507f, 0.001697f, 0.002468f, 0.003351f,
+ 0.004425f, 0.005486f, 0.006325f, 0.007412f, 0.008156f, 0.009270f, 0.010239f, 0.011497f, 0.012520f, 0.013954f, 0.015182f, 0.016617f,
+ 0.018036f, 0.019714f, 0.021362f, 0.022934f, 0.024704f, 0.026886f, 0.029419f, 0.031525f, 0.034302f, 0.037292f, 0.040558f, 0.043701f,
+ 0.047577f, 0.051849f, 0.056183f, 0.061249f, 0.066467f, 0.072876f, 0.078918f, 0.086548f, 0.094116f, 0.102844f, 0.112427f, 0.122620f,
+ 0.133667f, 0.146362f, 0.159668f, 0.174438f, 0.190063f, 0.207153f, 0.225098f, 0.244263f, 0.264648f, 0.286377f, 0.308350f, 0.332275f,
+ 0.357178f, 0.382080f, 0.408936f, 0.436035f, 0.465820f, 0.495361f, 0.776855f, 0.794922f, 0.797852f, 0.799316f, 0.798828f, 0.798340f,
+ 0.000366f, 0.001644f, 0.002289f, 0.003046f, 0.004082f, 0.005032f, 0.005550f, 0.006599f, 0.007389f, 0.008369f, 0.009201f, 0.010315f,
+ 0.011276f, 0.012405f, 0.013466f, 0.014587f, 0.015991f, 0.017303f, 0.018692f, 0.020081f, 0.021851f, 0.023865f, 0.025726f, 0.027771f,
+ 0.030136f, 0.032532f, 0.035309f, 0.038422f, 0.041626f, 0.045044f, 0.048767f, 0.053375f, 0.057861f, 0.063477f, 0.069031f, 0.075684f,
+ 0.082336f, 0.090515f, 0.099182f, 0.107849f, 0.118958f, 0.130005f, 0.142212f, 0.156128f, 0.170898f, 0.186890f, 0.203857f, 0.222534f,
+ 0.241821f, 0.263428f, 0.285156f, 0.308105f, 0.332275f, 0.359131f, 0.385010f, 0.413086f, 0.441895f, 0.472168f, 0.767090f, 0.785645f,
+ 0.789062f, 0.789551f, 0.790527f, 0.789551f, 0.000340f, 0.001434f, 0.002129f, 0.002827f, 0.003696f, 0.004463f, 0.005112f, 0.005730f,
+ 0.006836f, 0.007465f, 0.008217f, 0.008972f, 0.009972f, 0.010887f, 0.011948f, 0.012794f, 0.013947f, 0.015030f, 0.016266f, 0.017670f,
+ 0.019165f, 0.020813f, 0.022415f, 0.024216f, 0.026047f, 0.028336f, 0.030594f, 0.033142f, 0.035858f, 0.039154f, 0.042328f, 0.046265f,
+ 0.050537f, 0.055237f, 0.059998f, 0.065918f, 0.072083f, 0.078918f, 0.086243f, 0.094788f, 0.104309f, 0.114807f, 0.125854f, 0.138672f,
+ 0.152222f, 0.166992f, 0.183716f, 0.200928f, 0.220459f, 0.240112f, 0.261719f, 0.284668f, 0.308838f, 0.333740f, 0.360840f, 0.388672f,
+ 0.418213f, 0.448730f, 0.756348f, 0.775391f, 0.779297f, 0.780273f, 0.781250f, 0.780273f, 0.000511f, 0.001174f, 0.002163f, 0.002554f,
+ 0.003391f, 0.003990f, 0.004547f, 0.005211f, 0.005993f, 0.006653f, 0.007462f, 0.007942f, 0.008781f, 0.009476f, 0.010323f, 0.011444f,
+ 0.012207f, 0.013062f, 0.014336f, 0.015427f, 0.016464f, 0.017929f, 0.019287f, 0.021164f, 0.022461f, 0.024567f, 0.026474f, 0.028885f,
+ 0.031067f, 0.033630f, 0.036835f, 0.040070f, 0.043488f, 0.047394f, 0.051910f, 0.056732f, 0.062378f, 0.068481f, 0.075073f, 0.082764f,
+ 0.090881f, 0.100403f, 0.110779f, 0.122009f, 0.134399f, 0.148560f, 0.163940f, 0.180298f, 0.198120f, 0.218140f, 0.239014f, 0.260986f,
+ 0.285645f, 0.310059f, 0.336182f, 0.364502f, 0.393311f, 0.424316f, 0.744629f, 0.765137f, 0.769531f, 0.770508f, 0.771484f, 0.771484f,
+ 0.000374f, 0.000983f, 0.001696f, 0.002279f, 0.002924f, 0.003571f, 0.004139f, 0.004742f, 0.005390f, 0.005817f, 0.006371f, 0.006981f,
+ 0.007648f, 0.008354f, 0.009041f, 0.009727f, 0.010536f, 0.011375f, 0.012398f, 0.013535f, 0.014389f, 0.015541f, 0.016602f, 0.018112f,
+ 0.019516f, 0.020996f, 0.022644f, 0.024582f, 0.026627f, 0.028748f, 0.031586f, 0.034210f, 0.037415f, 0.040588f, 0.044464f, 0.048676f,
+ 0.053192f, 0.058472f, 0.064880f, 0.070984f, 0.078674f, 0.086914f, 0.096191f, 0.106445f, 0.117859f, 0.130859f, 0.144775f, 0.160522f,
+ 0.177490f, 0.196411f, 0.215942f, 0.237793f, 0.261475f, 0.285645f, 0.312012f, 0.339111f, 0.368652f, 0.400391f, 0.733887f, 0.755371f,
+ 0.759766f, 0.760742f, 0.761719f, 0.761719f, 0.000298f, 0.000924f, 0.001542f, 0.002125f, 0.002439f, 0.003153f, 0.003502f, 0.004196f,
+ 0.004585f, 0.005039f, 0.005531f, 0.006054f, 0.006531f, 0.007217f, 0.007935f, 0.008362f, 0.009171f, 0.009773f, 0.010704f, 0.011505f,
+ 0.012207f, 0.013321f, 0.014381f, 0.015556f, 0.016586f, 0.017792f, 0.019608f, 0.020844f, 0.022583f, 0.024536f, 0.026566f, 0.028885f,
+ 0.031494f, 0.034332f, 0.037689f, 0.041260f, 0.045258f, 0.049927f, 0.054901f, 0.060699f, 0.067322f, 0.074768f, 0.082764f, 0.091675f,
+ 0.102173f, 0.113831f, 0.126831f, 0.141113f, 0.157104f, 0.175049f, 0.194580f, 0.215210f, 0.237305f, 0.261475f, 0.287598f, 0.314697f,
+ 0.344482f, 0.375977f, 0.721680f, 0.744629f, 0.749512f, 0.751465f, 0.751465f, 0.751465f, 0.000275f, 0.001002f, 0.001335f, 0.001704f,
+ 0.002264f, 0.002790f, 0.003202f, 0.003555f, 0.004017f, 0.004368f, 0.004894f, 0.005318f, 0.005592f, 0.006241f, 0.006611f, 0.007317f,
+ 0.007851f, 0.008560f, 0.009071f, 0.009758f, 0.010429f, 0.011375f, 0.011986f, 0.013130f, 0.013916f, 0.015205f, 0.016403f, 0.017624f,
+ 0.019119f, 0.020660f, 0.022278f, 0.024582f, 0.026474f, 0.029007f, 0.031738f, 0.034668f, 0.038025f, 0.041962f, 0.046417f, 0.051270f,
+ 0.056915f, 0.063110f, 0.070312f, 0.078369f, 0.087769f, 0.098145f, 0.109863f, 0.123352f, 0.137451f, 0.154785f, 0.172363f, 0.192261f,
+ 0.214233f, 0.237793f, 0.262939f, 0.289795f, 0.319336f, 0.351074f, 0.708984f, 0.733398f, 0.738281f, 0.740234f, 0.741211f, 0.740723f,
+ 0.000334f, 0.000805f, 0.001231f, 0.001640f, 0.002033f, 0.002277f, 0.002871f, 0.003115f, 0.003481f, 0.003895f, 0.004147f, 0.004379f,
+ 0.004841f, 0.005306f, 0.005653f, 0.006241f, 0.006630f, 0.007217f, 0.007721f, 0.008133f, 0.008842f, 0.009529f, 0.010010f, 0.011017f,
+ 0.011780f, 0.012733f, 0.013626f, 0.014824f, 0.015656f, 0.017212f, 0.018829f, 0.020248f, 0.021973f, 0.023926f, 0.026306f, 0.028900f,
+ 0.031616f, 0.034973f, 0.038605f, 0.042816f, 0.047424f, 0.052765f, 0.059021f, 0.066162f, 0.074219f, 0.083435f, 0.093994f, 0.105835f,
+ 0.119385f, 0.134277f, 0.151611f, 0.170532f, 0.191284f, 0.214233f, 0.239014f, 0.265381f, 0.293701f, 0.325684f, 0.696289f, 0.722168f,
+ 0.727051f, 0.729004f, 0.729980f, 0.729980f, 0.000215f, 0.000635f, 0.001184f, 0.001348f, 0.001758f, 0.002171f, 0.002249f, 0.002596f,
+ 0.003004f, 0.003325f, 0.003487f, 0.003906f, 0.004108f, 0.004494f, 0.004955f, 0.005241f, 0.005726f, 0.006134f, 0.006485f, 0.006916f,
+ 0.007496f, 0.008072f, 0.008629f, 0.009071f, 0.009857f, 0.010651f, 0.011375f, 0.012283f, 0.013283f, 0.014320f, 0.015350f, 0.016739f,
+ 0.017975f, 0.019852f, 0.021454f, 0.023712f, 0.025925f, 0.028717f, 0.031769f, 0.035217f, 0.038910f, 0.043396f, 0.048767f, 0.054901f,
+ 0.061707f, 0.069824f, 0.078613f, 0.089783f, 0.101685f, 0.115479f, 0.131104f, 0.149292f, 0.168823f, 0.190674f, 0.214844f, 0.241211f,
+ 0.269775f, 0.299561f, 0.683594f, 0.709961f, 0.715332f, 0.717773f, 0.718262f, 0.718750f, 0.000199f, 0.000826f, 0.001047f, 0.001288f,
+ 0.001600f, 0.001857f, 0.002014f, 0.002329f, 0.002535f, 0.002785f, 0.003027f, 0.003210f, 0.003580f, 0.003788f, 0.004025f, 0.004444f,
+ 0.004791f, 0.004974f, 0.005417f, 0.005909f, 0.006248f, 0.006672f, 0.007118f, 0.007664f, 0.008232f, 0.008759f, 0.009598f, 0.009964f,
+ 0.010956f, 0.011650f, 0.012665f, 0.013702f, 0.014832f, 0.016144f, 0.017654f, 0.019211f, 0.021118f, 0.023102f, 0.025681f, 0.028320f,
+ 0.031708f, 0.035370f, 0.039673f, 0.044739f, 0.050812f, 0.057800f, 0.065796f, 0.074768f, 0.085510f, 0.097961f, 0.112000f, 0.128662f,
+ 0.147217f, 0.168213f, 0.190796f, 0.216309f, 0.244751f, 0.274902f, 0.669922f, 0.698730f, 0.703613f, 0.705566f, 0.707031f, 0.707031f,
+ 0.000212f, 0.000458f, 0.000959f, 0.001192f, 0.001321f, 0.001500f, 0.001823f, 0.002064f, 0.002073f, 0.002293f, 0.002512f, 0.002768f,
+ 0.002981f, 0.003138f, 0.003431f, 0.003765f, 0.003918f, 0.004238f, 0.004482f, 0.004814f, 0.005245f, 0.005531f, 0.005871f, 0.006214f,
+ 0.006660f, 0.007236f, 0.007664f, 0.008331f, 0.008812f, 0.009628f, 0.010277f, 0.010979f, 0.012016f, 0.012978f, 0.014084f, 0.015495f,
+ 0.016937f, 0.018494f, 0.020386f, 0.022659f, 0.025208f, 0.028183f, 0.031860f, 0.036072f, 0.040894f, 0.046326f, 0.053009f, 0.061127f,
+ 0.070374f, 0.081238f, 0.094238f, 0.109314f, 0.126343f, 0.145874f, 0.167847f, 0.192505f, 0.219604f, 0.249634f, 0.656738f, 0.686035f,
+ 0.690430f, 0.694336f, 0.694336f, 0.696777f, 0.000151f, 0.000529f, 0.000692f, 0.000883f, 0.001153f, 0.001337f, 0.001380f, 0.001520f,
+ 0.001753f, 0.001886f, 0.002077f, 0.002243f, 0.002386f, 0.002556f, 0.002832f, 0.003029f, 0.003277f, 0.003447f, 0.003683f, 0.003952f,
+ 0.004135f, 0.004578f, 0.004833f, 0.005222f, 0.005417f, 0.005810f, 0.006355f, 0.006718f, 0.007076f, 0.007652f, 0.008293f, 0.008980f,
+ 0.009674f, 0.010422f, 0.011276f, 0.012283f, 0.013443f, 0.014664f, 0.016113f, 0.017853f, 0.019897f, 0.022156f, 0.024826f, 0.028275f,
+ 0.032135f, 0.036865f, 0.042389f, 0.049011f, 0.056732f, 0.066223f, 0.077576f, 0.090820f, 0.106384f, 0.124512f, 0.145264f, 0.169067f,
+ 0.195190f, 0.224976f, 0.642578f, 0.671387f, 0.679688f, 0.682617f, 0.682617f, 0.683594f, 0.000127f, 0.000376f, 0.000600f, 0.000721f,
+ 0.000901f, 0.001066f, 0.001180f, 0.001332f, 0.001455f, 0.001549f, 0.001709f, 0.001831f, 0.001947f, 0.002150f, 0.002245f, 0.002443f,
+ 0.002682f, 0.002844f, 0.002989f, 0.003201f, 0.003403f, 0.003683f, 0.003883f, 0.004097f, 0.004372f, 0.004665f, 0.004963f, 0.005348f,
+ 0.005711f, 0.006165f, 0.006672f, 0.007004f, 0.007610f, 0.008278f, 0.008873f, 0.009636f, 0.010475f, 0.011475f, 0.012634f, 0.014053f,
+ 0.015404f, 0.017242f, 0.019104f, 0.021774f, 0.024750f, 0.028458f, 0.032745f, 0.038391f, 0.044861f, 0.052795f, 0.062103f, 0.073914f,
+ 0.087830f, 0.104553f, 0.123718f, 0.145996f, 0.171509f, 0.200439f, 0.627930f, 0.658691f, 0.666504f, 0.668945f, 0.671387f, 0.671387f,
+ 0.000013f, 0.000374f, 0.000443f, 0.000688f, 0.000819f, 0.000844f, 0.001004f, 0.001132f, 0.001216f, 0.001259f, 0.001405f, 0.001523f,
+ 0.001566f, 0.001753f, 0.001842f, 0.001997f, 0.002022f, 0.002287f, 0.002377f, 0.002541f, 0.002787f, 0.002878f, 0.003096f, 0.003283f,
+ 0.003551f, 0.003651f, 0.003971f, 0.004272f, 0.004524f, 0.004887f, 0.005196f, 0.005527f, 0.005939f, 0.006386f, 0.006977f, 0.007526f,
+ 0.008148f, 0.008835f, 0.009689f, 0.010689f, 0.011810f, 0.013000f, 0.014641f, 0.016388f, 0.018799f, 0.021469f, 0.024734f, 0.029022f,
+ 0.034210f, 0.040588f, 0.048401f, 0.058319f, 0.070435f, 0.085205f, 0.102905f, 0.123901f, 0.147827f, 0.175903f, 0.612793f, 0.645508f,
+ 0.653320f, 0.656250f, 0.657227f, 0.657227f, 0.000113f, 0.000234f, 0.000465f, 0.000547f, 0.000646f, 0.000684f, 0.000711f, 0.000832f,
+ 0.000963f, 0.000999f, 0.001042f, 0.001183f, 0.001279f, 0.001402f, 0.001494f, 0.001513f, 0.001688f, 0.001716f, 0.001919f, 0.001993f,
+ 0.002081f, 0.002253f, 0.002441f, 0.002575f, 0.002714f, 0.002876f, 0.003050f, 0.003214f, 0.003531f, 0.003714f, 0.003956f, 0.004276f,
+ 0.004604f, 0.004967f, 0.005386f, 0.005718f, 0.006283f, 0.006790f, 0.007290f, 0.008133f, 0.008957f, 0.009987f, 0.010956f, 0.012375f,
+ 0.013916f, 0.015991f, 0.018311f, 0.021347f, 0.025253f, 0.030289f, 0.036560f, 0.044586f, 0.054779f, 0.067749f, 0.083252f, 0.102722f,
+ 0.125732f, 0.152100f, 0.597168f, 0.631836f, 0.639160f, 0.643555f, 0.643066f, 0.645508f, 0.000207f, 0.000175f, 0.000364f, 0.000507f,
+ 0.000496f, 0.000569f, 0.000683f, 0.000584f, 0.000737f, 0.000764f, 0.000885f, 0.000964f, 0.000999f, 0.001076f, 0.001085f, 0.001272f,
+ 0.001327f, 0.001354f, 0.001491f, 0.001494f, 0.001677f, 0.001781f, 0.001862f, 0.001976f, 0.002079f, 0.002190f, 0.002338f, 0.002481f,
+ 0.002691f, 0.002811f, 0.003117f, 0.003214f, 0.003422f, 0.003706f, 0.003990f, 0.004314f, 0.004608f, 0.004982f, 0.005379f, 0.006027f,
+ 0.006580f, 0.007351f, 0.008049f, 0.009041f, 0.010323f, 0.011551f, 0.013428f, 0.015419f, 0.018219f, 0.021713f, 0.026550f, 0.032715f,
+ 0.040833f, 0.051605f, 0.065552f, 0.082458f, 0.104004f, 0.129395f, 0.582031f, 0.618652f, 0.625488f, 0.627930f, 0.630859f, 0.631348f,
+ 0.000189f, 0.000160f, 0.000272f, 0.000387f, 0.000335f, 0.000486f, 0.000424f, 0.000469f, 0.000551f, 0.000589f, 0.000700f, 0.000727f,
+ 0.000772f, 0.000859f, 0.000891f, 0.000872f, 0.001000f, 0.001048f, 0.001076f, 0.001172f, 0.001224f, 0.001311f, 0.001376f, 0.001450f,
+ 0.001554f, 0.001591f, 0.001760f, 0.001838f, 0.001999f, 0.002180f, 0.002333f, 0.002388f, 0.002584f, 0.002777f, 0.002907f, 0.003162f,
+ 0.003368f, 0.003677f, 0.003979f, 0.004303f, 0.004715f, 0.005188f, 0.005787f, 0.006378f, 0.007313f, 0.008194f, 0.009407f, 0.010887f,
+ 0.012779f, 0.015198f, 0.018494f, 0.022888f, 0.029037f, 0.037659f, 0.048920f, 0.064270f, 0.083740f, 0.107300f, 0.565918f, 0.603516f,
+ 0.611328f, 0.614746f, 0.617188f, 0.618164f, 0.000000f, 0.000170f, 0.000207f, 0.000274f, 0.000292f, 0.000309f, 0.000381f, 0.000326f,
+ 0.000418f, 0.000439f, 0.000519f, 0.000519f, 0.000560f, 0.000574f, 0.000652f, 0.000678f, 0.000717f, 0.000756f, 0.000782f, 0.000820f,
+ 0.000893f, 0.000937f, 0.000991f, 0.001063f, 0.001112f, 0.001174f, 0.001284f, 0.001302f, 0.001408f, 0.001460f, 0.001586f, 0.001711f,
+ 0.001826f, 0.001959f, 0.002058f, 0.002207f, 0.002388f, 0.002565f, 0.002836f, 0.003046f, 0.003284f, 0.003567f, 0.004009f, 0.004463f,
+ 0.005001f, 0.005661f, 0.006451f, 0.007473f, 0.008751f, 0.010368f, 0.012611f, 0.015587f, 0.019730f, 0.025787f, 0.034729f, 0.047272f,
+ 0.064392f, 0.087097f, 0.550293f, 0.587891f, 0.596680f, 0.600586f, 0.602539f, 0.603516f, 0.000000f, 0.000057f, 0.000175f, 0.000210f,
+ 0.000221f, 0.000261f, 0.000224f, 0.000285f, 0.000296f, 0.000329f, 0.000374f, 0.000329f, 0.000344f, 0.000416f, 0.000421f, 0.000479f,
+ 0.000455f, 0.000530f, 0.000552f, 0.000598f, 0.000640f, 0.000670f, 0.000695f, 0.000740f, 0.000798f, 0.000806f, 0.000883f, 0.000908f,
+ 0.000983f, 0.001094f, 0.001083f, 0.001169f, 0.001242f, 0.001340f, 0.001440f, 0.001536f, 0.001601f, 0.001752f, 0.001893f, 0.002029f,
+ 0.002218f, 0.002424f, 0.002651f, 0.002934f, 0.003294f, 0.003681f, 0.004200f, 0.004833f, 0.005688f, 0.006863f, 0.008202f, 0.010178f,
+ 0.012955f, 0.016846f, 0.023163f, 0.032745f, 0.047150f, 0.067383f, 0.534180f, 0.574219f, 0.582031f, 0.584961f, 0.586914f, 0.589844f,
+ 0.000000f, 0.000105f, 0.000145f, 0.000101f, 0.000161f, 0.000163f, 0.000165f, 0.000193f, 0.000190f, 0.000202f, 0.000205f, 0.000260f,
+ 0.000251f, 0.000281f, 0.000305f, 0.000316f, 0.000323f, 0.000346f, 0.000364f, 0.000383f, 0.000413f, 0.000436f, 0.000461f, 0.000486f,
+ 0.000515f, 0.000564f, 0.000594f, 0.000616f, 0.000639f, 0.000677f, 0.000729f, 0.000748f, 0.000842f, 0.000861f, 0.000943f, 0.000970f,
+ 0.001054f, 0.001120f, 0.001219f, 0.001310f, 0.001398f, 0.001534f, 0.001709f, 0.001852f, 0.002096f, 0.002291f, 0.002594f, 0.002987f,
+ 0.003481f, 0.004128f, 0.004997f, 0.006218f, 0.007950f, 0.010445f, 0.014313f, 0.020874f, 0.032166f, 0.049866f, 0.517578f, 0.558105f,
+ 0.567383f, 0.570801f, 0.573730f, 0.574707f, 0.000000f, 0.000097f, 0.000089f, 0.000082f, 0.000092f, 0.000096f, 0.000092f, 0.000118f,
+ 0.000126f, 0.000130f, 0.000138f, 0.000138f, 0.000143f, 0.000163f, 0.000181f, 0.000187f, 0.000195f, 0.000228f, 0.000221f, 0.000261f,
+ 0.000243f, 0.000254f, 0.000274f, 0.000299f, 0.000334f, 0.000332f, 0.000345f, 0.000362f, 0.000394f, 0.000410f, 0.000433f, 0.000463f,
+ 0.000497f, 0.000510f, 0.000562f, 0.000594f, 0.000636f, 0.000670f, 0.000731f, 0.000777f, 0.000832f, 0.000927f, 0.000991f, 0.001101f,
+ 0.001210f, 0.001350f, 0.001513f, 0.001720f, 0.001999f, 0.002373f, 0.002815f, 0.003498f, 0.004478f, 0.006001f, 0.008347f, 0.012299f,
+ 0.019669f, 0.034210f, 0.501465f, 0.542969f, 0.552246f, 0.556641f, 0.559082f, 0.559570f, 0.000107f, 0.000087f, 0.000077f, 0.000070f,
+ 0.000065f, 0.000066f, 0.000059f, 0.000064f, 0.000065f, 0.000071f, 0.000070f, 0.000095f, 0.000081f, 0.000085f, 0.000110f, 0.000097f,
+ 0.000117f, 0.000126f, 0.000127f, 0.000133f, 0.000132f, 0.000141f, 0.000169f, 0.000173f, 0.000185f, 0.000183f, 0.000192f, 0.000215f,
+ 0.000216f, 0.000235f, 0.000236f, 0.000265f, 0.000278f, 0.000290f, 0.000313f, 0.000317f, 0.000347f, 0.000365f, 0.000400f, 0.000422f,
+ 0.000457f, 0.000494f, 0.000535f, 0.000586f, 0.000639f, 0.000700f, 0.000786f, 0.000888f, 0.001019f, 0.001207f, 0.001435f, 0.001746f,
+ 0.002258f, 0.003019f, 0.004299f, 0.006523f, 0.010612f, 0.020859f, 0.484619f, 0.527344f, 0.536621f, 0.541504f, 0.542969f, 0.544922f,
+ 0.000092f, 0.000070f, 0.000062f, 0.000056f, 0.000051f, 0.000048f, 0.000045f, 0.000044f, 0.000041f, 0.000039f, 0.000038f, 0.000037f,
+ 0.000047f, 0.000039f, 0.000041f, 0.000041f, 0.000058f, 0.000053f, 0.000062f, 0.000064f, 0.000068f, 0.000072f, 0.000076f, 0.000076f,
+ 0.000078f, 0.000092f, 0.000085f, 0.000101f, 0.000104f, 0.000110f, 0.000115f, 0.000118f, 0.000127f, 0.000133f, 0.000152f, 0.000150f,
+ 0.000163f, 0.000190f, 0.000190f, 0.000202f, 0.000213f, 0.000225f, 0.000249f, 0.000268f, 0.000296f, 0.000321f, 0.000354f, 0.000402f,
+ 0.000458f, 0.000520f, 0.000618f, 0.000744f, 0.000950f, 0.001263f, 0.001822f, 0.002865f, 0.005028f, 0.010544f, 0.468018f, 0.511230f,
+ 0.521484f, 0.524902f, 0.529297f, 0.529785f, 0.000067f, 0.000049f, 0.000041f, 0.000037f, 0.000034f, 0.000032f, 0.000031f, 0.000029f,
+ 0.000028f, 0.000027f, 0.000027f, 0.000026f, 0.000025f, 0.000023f, 0.000022f, 0.000021f, 0.000020f, 0.000020f, 0.000023f, 0.000024f,
+ 0.000021f, 0.000022f, 0.000025f, 0.000029f, 0.000030f, 0.000034f, 0.000036f, 0.000034f, 0.000039f, 0.000038f, 0.000045f, 0.000045f,
+ 0.000048f, 0.000051f, 0.000053f, 0.000055f, 0.000063f, 0.000070f, 0.000073f, 0.000073f, 0.000080f, 0.000084f, 0.000089f, 0.000102f,
+ 0.000107f, 0.000115f, 0.000128f, 0.000145f, 0.000156f, 0.000178f, 0.000213f, 0.000253f, 0.000311f, 0.000400f, 0.000572f, 0.000916f,
+ 0.001751f, 0.004158f, 0.450439f, 0.496338f, 0.505859f, 0.510742f, 0.513184f, 0.514648f, 0.000016f, 0.000013f, 0.000011f, 0.000010f,
+ 0.000012f, 0.000012f, 0.000011f, 0.000012f, 0.000011f, 0.000012f, 0.000011f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000011f,
+ 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000008f,
+ 0.000008f, 0.000009f, 0.000009f, 0.000009f, 0.000009f, 0.000011f, 0.000012f, 0.000012f, 0.000015f, 0.000014f, 0.000014f, 0.000017f,
+ 0.000018f, 0.000020f, 0.000020f, 0.000022f, 0.000026f, 0.000027f, 0.000028f, 0.000027f, 0.000033f, 0.000036f, 0.000044f, 0.000051f,
+ 0.000057f, 0.000078f, 0.000103f, 0.000159f, 0.000315f, 0.000997f, 0.433350f, 0.479980f, 0.490234f, 0.495605f, 0.498291f, 0.499512f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000004f, 0.000004f, 0.000007f, 0.000025f, 0.416016f, 0.464111f,
+ 0.474854f, 0.479248f, 0.481934f, 0.484375f,
+ },
+ {
+ 0.023209f, 0.069336f, 0.113037f, 0.154663f, 0.193726f, 0.231812f, 0.267578f, 0.301758f, 0.333740f, 0.364258f, 0.393555f, 0.421631f,
+ 0.447510f, 0.473145f, 0.497070f, 0.520020f, 0.541992f, 0.562988f, 0.583008f, 0.602539f, 0.620605f, 0.638184f, 0.655762f, 0.671387f,
+ 0.687500f, 0.702637f, 0.716309f, 0.729980f, 0.744141f, 0.757812f, 0.769531f, 0.782227f, 0.793945f, 0.804688f, 0.815918f, 0.826172f,
+ 0.836426f, 0.846191f, 0.855957f, 0.865234f, 0.874023f, 0.882812f, 0.891113f, 0.898926f, 0.907227f, 0.915039f, 0.922852f, 0.929688f,
+ 0.937012f, 0.943848f, 0.950684f, 0.956543f, 0.963379f, 0.969238f, 0.976074f, 0.981445f, 0.986816f, 0.992676f, 0.991211f, 0.978516f,
+ 0.968750f, 0.960449f, 0.952637f, 0.945312f, 0.019730f, 0.059631f, 0.098206f, 0.135864f, 0.172119f, 0.206421f, 0.239624f, 0.272461f,
+ 0.304932f, 0.333984f, 0.362549f, 0.389648f, 0.416016f, 0.441406f, 0.466309f, 0.489502f, 0.511230f, 0.533203f, 0.554199f, 0.573242f,
+ 0.593262f, 0.611816f, 0.629395f, 0.645508f, 0.662598f, 0.678711f, 0.693359f, 0.708496f, 0.722168f, 0.735840f, 0.750000f, 0.762207f,
+ 0.773926f, 0.786133f, 0.796875f, 0.808594f, 0.818848f, 0.829590f, 0.839355f, 0.850098f, 0.859863f, 0.868652f, 0.877441f, 0.886230f,
+ 0.895020f, 0.903809f, 0.911133f, 0.918457f, 0.925781f, 0.933105f, 0.940430f, 0.946777f, 0.954590f, 0.960938f, 0.966797f, 0.973145f,
+ 0.979004f, 0.984863f, 0.987793f, 0.976074f, 0.966797f, 0.958496f, 0.951172f, 0.943848f, 0.017151f, 0.051636f, 0.085510f, 0.119202f,
+ 0.152466f, 0.184814f, 0.216187f, 0.246582f, 0.276855f, 0.305664f, 0.332764f, 0.360107f, 0.385986f, 0.411621f, 0.435791f, 0.459473f,
+ 0.481445f, 0.502441f, 0.524414f, 0.546387f, 0.565430f, 0.583496f, 0.602051f, 0.619629f, 0.636719f, 0.653320f, 0.669434f, 0.684082f,
+ 0.699707f, 0.713867f, 0.728027f, 0.741211f, 0.754883f, 0.767090f, 0.779297f, 0.791016f, 0.802734f, 0.813965f, 0.824219f, 0.833984f,
+ 0.843750f, 0.854492f, 0.863281f, 0.873535f, 0.882324f, 0.890137f, 0.898926f, 0.906738f, 0.915039f, 0.922852f, 0.930176f, 0.937012f,
+ 0.944336f, 0.951172f, 0.958008f, 0.964844f, 0.970703f, 0.977051f, 0.983887f, 0.972656f, 0.964355f, 0.956543f, 0.949219f, 0.942383f,
+ 0.014885f, 0.044678f, 0.075195f, 0.104919f, 0.135254f, 0.165649f, 0.194702f, 0.223633f, 0.251221f, 0.279053f, 0.305420f, 0.331543f,
+ 0.357422f, 0.382568f, 0.406982f, 0.430420f, 0.453369f, 0.475586f, 0.496582f, 0.517090f, 0.536133f, 0.556641f, 0.575684f, 0.592773f,
+ 0.611328f, 0.628418f, 0.643555f, 0.661621f, 0.676270f, 0.691406f, 0.705566f, 0.720215f, 0.733887f, 0.746582f, 0.759766f, 0.772949f,
+ 0.784668f, 0.795898f, 0.807129f, 0.818359f, 0.828125f, 0.838867f, 0.848633f, 0.858887f, 0.867676f, 0.877441f, 0.886230f, 0.894531f,
+ 0.903320f, 0.911621f, 0.919434f, 0.927734f, 0.934570f, 0.940918f, 0.948730f, 0.956543f, 0.962402f, 0.969238f, 0.979980f, 0.970215f,
+ 0.961914f, 0.954102f, 0.947266f, 0.940918f, 0.013046f, 0.038940f, 0.066162f, 0.093323f, 0.120544f, 0.147583f, 0.174683f, 0.201538f,
+ 0.228516f, 0.254639f, 0.280518f, 0.304932f, 0.330566f, 0.354492f, 0.379395f, 0.402100f, 0.424561f, 0.446533f, 0.467529f, 0.488525f,
+ 0.509277f, 0.529297f, 0.547852f, 0.566895f, 0.585449f, 0.602539f, 0.620605f, 0.636230f, 0.653809f, 0.667480f, 0.684570f, 0.698242f,
+ 0.712891f, 0.726562f, 0.739746f, 0.753418f, 0.765625f, 0.777344f, 0.789551f, 0.801270f, 0.812500f, 0.823730f, 0.833984f, 0.844238f,
+ 0.854004f, 0.863770f, 0.874023f, 0.882324f, 0.891113f, 0.899902f, 0.908203f, 0.916504f, 0.924805f, 0.932129f, 0.939453f, 0.947266f,
+ 0.954102f, 0.960938f, 0.976562f, 0.967285f, 0.958984f, 0.951660f, 0.944824f, 0.938965f, 0.011696f, 0.034698f, 0.058807f, 0.083130f,
+ 0.107727f, 0.132324f, 0.156982f, 0.182251f, 0.207153f, 0.232178f, 0.256836f, 0.280762f, 0.304688f, 0.328369f, 0.352295f, 0.375244f,
+ 0.397461f, 0.419434f, 0.440430f, 0.461914f, 0.482178f, 0.501953f, 0.522461f, 0.540527f, 0.559570f, 0.577148f, 0.595703f, 0.613281f,
+ 0.628418f, 0.644531f, 0.661621f, 0.676270f, 0.691406f, 0.705078f, 0.719727f, 0.733887f, 0.746094f, 0.759766f, 0.771973f, 0.784180f,
+ 0.795898f, 0.807617f, 0.818359f, 0.829102f, 0.839844f, 0.850098f, 0.859375f, 0.869629f, 0.878906f, 0.887695f, 0.896484f, 0.905273f,
+ 0.914062f, 0.921875f, 0.929688f, 0.937988f, 0.944824f, 0.952637f, 0.973145f, 0.963379f, 0.956055f, 0.949219f, 0.942871f, 0.937012f,
+ 0.010094f, 0.030975f, 0.052063f, 0.073975f, 0.096069f, 0.118713f, 0.141479f, 0.164551f, 0.187866f, 0.211182f, 0.234985f, 0.258057f,
+ 0.280518f, 0.303467f, 0.326172f, 0.348145f, 0.370117f, 0.392822f, 0.413574f, 0.434814f, 0.455322f, 0.476074f, 0.495361f, 0.515137f,
+ 0.533203f, 0.551758f, 0.569824f, 0.586426f, 0.604492f, 0.621582f, 0.637695f, 0.654297f, 0.668945f, 0.683594f, 0.699219f, 0.712402f,
+ 0.728516f, 0.741699f, 0.753906f, 0.767090f, 0.778320f, 0.790527f, 0.802246f, 0.813965f, 0.824219f, 0.835449f, 0.846680f, 0.855957f,
+ 0.865723f, 0.875488f, 0.884766f, 0.894043f, 0.902832f, 0.911133f, 0.919434f, 0.927734f, 0.935547f, 0.943359f, 0.968750f, 0.960449f,
+ 0.953125f, 0.946289f, 0.940430f, 0.934570f, 0.008797f, 0.027466f, 0.045959f, 0.066223f, 0.086304f, 0.106506f, 0.127441f, 0.149170f,
+ 0.170532f, 0.192261f, 0.213867f, 0.236206f, 0.258057f, 0.280273f, 0.301758f, 0.323486f, 0.344727f, 0.367188f, 0.388184f, 0.408447f,
+ 0.429443f, 0.450439f, 0.469727f, 0.489014f, 0.508301f, 0.526855f, 0.545410f, 0.562500f, 0.581055f, 0.597656f, 0.613770f, 0.630859f,
+ 0.647461f, 0.663574f, 0.677734f, 0.693359f, 0.707031f, 0.720703f, 0.735352f, 0.748047f, 0.760254f, 0.772461f, 0.785156f, 0.797363f,
+ 0.810059f, 0.819824f, 0.831543f, 0.842285f, 0.852051f, 0.862793f, 0.873047f, 0.882324f, 0.891113f, 0.899902f, 0.909180f, 0.917969f,
+ 0.925781f, 0.934082f, 0.964355f, 0.957031f, 0.949707f, 0.943359f, 0.937988f, 0.932129f, 0.007927f, 0.024414f, 0.041077f, 0.059204f,
+ 0.077148f, 0.095581f, 0.115479f, 0.134644f, 0.154785f, 0.175293f, 0.196045f, 0.216553f, 0.236694f, 0.258057f, 0.278809f, 0.300049f,
+ 0.321289f, 0.342529f, 0.363281f, 0.383545f, 0.403564f, 0.424072f, 0.444092f, 0.463135f, 0.483154f, 0.501953f, 0.519531f, 0.539062f,
+ 0.555664f, 0.574707f, 0.591309f, 0.608398f, 0.624512f, 0.640137f, 0.655762f, 0.671875f, 0.686523f, 0.701172f, 0.715820f, 0.729004f,
+ 0.742676f, 0.755859f, 0.769043f, 0.781738f, 0.792969f, 0.805176f, 0.816895f, 0.827637f, 0.838867f, 0.849121f, 0.859375f, 0.870117f,
+ 0.879395f, 0.889160f, 0.898926f, 0.906738f, 0.916504f, 0.924805f, 0.960938f, 0.953125f, 0.947266f, 0.940430f, 0.935547f, 0.929688f,
+ 0.007080f, 0.022247f, 0.037445f, 0.053070f, 0.069336f, 0.086975f, 0.103577f, 0.121948f, 0.140503f, 0.158936f, 0.178833f, 0.198242f,
+ 0.217651f, 0.237793f, 0.257812f, 0.278076f, 0.297607f, 0.318604f, 0.338623f, 0.358643f, 0.378662f, 0.399170f, 0.418213f, 0.438721f,
+ 0.457520f, 0.477051f, 0.495361f, 0.513672f, 0.531250f, 0.549316f, 0.567383f, 0.583984f, 0.601562f, 0.617676f, 0.634277f, 0.650391f,
+ 0.666016f, 0.680176f, 0.695801f, 0.710449f, 0.723633f, 0.737305f, 0.750977f, 0.764648f, 0.776367f, 0.789551f, 0.802246f, 0.813477f,
+ 0.824219f, 0.835938f, 0.846680f, 0.857422f, 0.867188f, 0.876953f, 0.887207f, 0.895996f, 0.905762f, 0.915527f, 0.955566f, 0.949707f,
+ 0.943359f, 0.937988f, 0.932129f, 0.927246f, 0.006363f, 0.019516f, 0.033691f, 0.047577f, 0.062469f, 0.078186f, 0.093933f, 0.110657f,
+ 0.127563f, 0.144653f, 0.162598f, 0.181152f, 0.199707f, 0.218384f, 0.237427f, 0.257324f, 0.276367f, 0.295166f, 0.315674f, 0.335205f,
+ 0.355225f, 0.374756f, 0.393799f, 0.413574f, 0.432617f, 0.451904f, 0.470459f, 0.489258f, 0.508301f, 0.525879f, 0.543945f, 0.560059f,
+ 0.578613f, 0.595703f, 0.612793f, 0.628418f, 0.644531f, 0.659668f, 0.675293f, 0.689941f, 0.704590f, 0.719238f, 0.732910f, 0.747070f,
+ 0.759766f, 0.773438f, 0.785156f, 0.797852f, 0.809570f, 0.821289f, 0.833008f, 0.843750f, 0.854980f, 0.865723f, 0.875977f, 0.886230f,
+ 0.895508f, 0.904785f, 0.951660f, 0.945801f, 0.939941f, 0.934570f, 0.929199f, 0.924805f, 0.005985f, 0.017776f, 0.030212f, 0.043030f,
+ 0.056488f, 0.070190f, 0.085205f, 0.100342f, 0.115723f, 0.132446f, 0.148438f, 0.165771f, 0.183228f, 0.200684f, 0.218994f, 0.237183f,
+ 0.255859f, 0.274170f, 0.292725f, 0.313477f, 0.331299f, 0.351318f, 0.369873f, 0.389160f, 0.408936f, 0.426758f, 0.446533f, 0.464844f,
+ 0.483154f, 0.501465f, 0.519531f, 0.537598f, 0.555664f, 0.572754f, 0.589844f, 0.605957f, 0.622070f, 0.639648f, 0.654297f, 0.670898f,
+ 0.685059f, 0.700195f, 0.714844f, 0.728516f, 0.742188f, 0.754883f, 0.769043f, 0.781738f, 0.795410f, 0.808105f, 0.818359f, 0.830566f,
+ 0.841797f, 0.853027f, 0.863770f, 0.874023f, 0.884766f, 0.893555f, 0.947266f, 0.942383f, 0.936523f, 0.930664f, 0.926270f, 0.921387f,
+ 0.005173f, 0.016083f, 0.027359f, 0.038849f, 0.051056f, 0.063843f, 0.077026f, 0.091064f, 0.105591f, 0.120422f, 0.135498f, 0.150879f,
+ 0.167480f, 0.184326f, 0.201172f, 0.218384f, 0.236084f, 0.254395f, 0.272949f, 0.291260f, 0.309570f, 0.328125f, 0.346680f, 0.365967f,
+ 0.384766f, 0.403320f, 0.422119f, 0.440918f, 0.458984f, 0.477783f, 0.496094f, 0.513672f, 0.531738f, 0.548828f, 0.566406f, 0.583984f,
+ 0.600098f, 0.617188f, 0.632812f, 0.649902f, 0.665527f, 0.681152f, 0.694824f, 0.709473f, 0.724121f, 0.738770f, 0.752441f, 0.765137f,
+ 0.778809f, 0.791992f, 0.803711f, 0.815918f, 0.828125f, 0.839844f, 0.851562f, 0.862793f, 0.873535f, 0.883789f, 0.941895f, 0.938477f,
+ 0.933105f, 0.927246f, 0.922363f, 0.918457f, 0.004791f, 0.014610f, 0.024475f, 0.035126f, 0.046478f, 0.057922f, 0.069885f, 0.083008f,
+ 0.096069f, 0.109253f, 0.123840f, 0.137939f, 0.153076f, 0.168701f, 0.185059f, 0.200928f, 0.218262f, 0.234985f, 0.252686f, 0.270264f,
+ 0.288086f, 0.306396f, 0.324951f, 0.343018f, 0.362305f, 0.379883f, 0.398926f, 0.417236f, 0.435547f, 0.454346f, 0.472656f, 0.491211f,
+ 0.508301f, 0.526855f, 0.543457f, 0.561523f, 0.578125f, 0.595215f, 0.612305f, 0.628418f, 0.644043f, 0.660645f, 0.675781f, 0.691406f,
+ 0.706055f, 0.720215f, 0.735840f, 0.749023f, 0.762695f, 0.776855f, 0.789551f, 0.800781f, 0.814941f, 0.826172f, 0.838867f, 0.851074f,
+ 0.862305f, 0.872070f, 0.937500f, 0.933594f, 0.929199f, 0.923828f, 0.919434f, 0.915527f, 0.004387f, 0.013268f, 0.022385f, 0.031860f,
+ 0.041962f, 0.052612f, 0.063171f, 0.075073f, 0.086792f, 0.099854f, 0.113037f, 0.125977f, 0.140381f, 0.154663f, 0.169678f, 0.184814f,
+ 0.200562f, 0.217773f, 0.234131f, 0.250732f, 0.268066f, 0.284912f, 0.303223f, 0.321289f, 0.339355f, 0.357666f, 0.375488f, 0.394043f,
+ 0.411865f, 0.430664f, 0.448730f, 0.467041f, 0.485352f, 0.503418f, 0.520508f, 0.539062f, 0.556152f, 0.573242f, 0.590820f, 0.606934f,
+ 0.624512f, 0.640625f, 0.655762f, 0.672363f, 0.687500f, 0.702148f, 0.718750f, 0.731934f, 0.746582f, 0.759766f, 0.772949f, 0.787109f,
+ 0.800781f, 0.813477f, 0.825195f, 0.838379f, 0.850098f, 0.861816f, 0.932617f, 0.929688f, 0.925293f, 0.919922f, 0.915527f, 0.912109f,
+ 0.003941f, 0.011986f, 0.020630f, 0.029144f, 0.038544f, 0.048035f, 0.058075f, 0.068542f, 0.079590f, 0.090942f, 0.102661f, 0.115295f,
+ 0.128296f, 0.141602f, 0.155518f, 0.170654f, 0.185425f, 0.200684f, 0.216309f, 0.231812f, 0.249146f, 0.265137f, 0.282471f, 0.299072f,
+ 0.317139f, 0.334717f, 0.352783f, 0.371338f, 0.388916f, 0.406982f, 0.425537f, 0.443848f, 0.461914f, 0.479980f, 0.498291f, 0.515625f,
+ 0.533203f, 0.550293f, 0.568359f, 0.585449f, 0.603027f, 0.618652f, 0.635742f, 0.652344f, 0.668457f, 0.684082f, 0.699219f, 0.713867f,
+ 0.729004f, 0.743652f, 0.757812f, 0.771484f, 0.785645f, 0.798828f, 0.812012f, 0.824219f, 0.836914f, 0.850098f, 0.927246f, 0.925293f,
+ 0.920410f, 0.916504f, 0.912598f, 0.908203f, 0.003790f, 0.011009f, 0.018829f, 0.026779f, 0.035339f, 0.043762f, 0.053223f, 0.062408f,
+ 0.072693f, 0.082947f, 0.093689f, 0.105469f, 0.117554f, 0.130005f, 0.142822f, 0.156494f, 0.170166f, 0.184448f, 0.198975f, 0.213745f,
+ 0.230469f, 0.246460f, 0.262939f, 0.279541f, 0.296143f, 0.313721f, 0.331299f, 0.348633f, 0.367188f, 0.384521f, 0.402344f, 0.420410f,
+ 0.438965f, 0.457275f, 0.475830f, 0.493164f, 0.510742f, 0.528809f, 0.546387f, 0.564453f, 0.581055f, 0.598145f, 0.615234f, 0.631836f,
+ 0.647461f, 0.665527f, 0.680664f, 0.696289f, 0.711914f, 0.728027f, 0.741211f, 0.756836f, 0.770508f, 0.783691f, 0.798340f, 0.811523f,
+ 0.824219f, 0.837402f, 0.921387f, 0.920410f, 0.916504f, 0.913086f, 0.908691f, 0.904785f, 0.003479f, 0.009949f, 0.016937f, 0.024445f,
+ 0.031708f, 0.039948f, 0.048218f, 0.056793f, 0.066223f, 0.075928f, 0.085632f, 0.096313f, 0.107178f, 0.118958f, 0.130493f, 0.143311f,
+ 0.156494f, 0.170044f, 0.183960f, 0.197876f, 0.213501f, 0.228027f, 0.244019f, 0.260010f, 0.276611f, 0.293213f, 0.309814f, 0.327393f,
+ 0.344482f, 0.363037f, 0.379883f, 0.398438f, 0.416504f, 0.434082f, 0.451904f, 0.470215f, 0.488525f, 0.505859f, 0.523926f, 0.541504f,
+ 0.559570f, 0.577637f, 0.594238f, 0.611328f, 0.628418f, 0.645020f, 0.661133f, 0.677246f, 0.693848f, 0.709961f, 0.725586f, 0.739746f,
+ 0.755371f, 0.769531f, 0.783203f, 0.797852f, 0.810547f, 0.824707f, 0.916016f, 0.915527f, 0.912109f, 0.908691f, 0.904785f, 0.900879f,
+ 0.003014f, 0.008842f, 0.015640f, 0.022018f, 0.028885f, 0.036163f, 0.044250f, 0.051819f, 0.059967f, 0.069031f, 0.078247f, 0.088135f,
+ 0.098267f, 0.108337f, 0.119751f, 0.131470f, 0.143433f, 0.156006f, 0.169189f, 0.183105f, 0.196655f, 0.211304f, 0.226196f, 0.241211f,
+ 0.257080f, 0.273438f, 0.289307f, 0.306396f, 0.323975f, 0.340576f, 0.358398f, 0.375732f, 0.393799f, 0.411133f, 0.429688f, 0.447998f,
+ 0.466064f, 0.483887f, 0.501465f, 0.519531f, 0.537598f, 0.555664f, 0.573242f, 0.590820f, 0.607910f, 0.625000f, 0.642578f, 0.658203f,
+ 0.675293f, 0.691406f, 0.707520f, 0.724121f, 0.738770f, 0.753418f, 0.769531f, 0.783203f, 0.797363f, 0.811523f, 0.910156f, 0.910645f,
+ 0.907715f, 0.904785f, 0.900879f, 0.896973f, 0.002861f, 0.008591f, 0.014000f, 0.020203f, 0.026962f, 0.033203f, 0.040161f, 0.047485f,
+ 0.055237f, 0.062988f, 0.071594f, 0.080750f, 0.089905f, 0.099854f, 0.109741f, 0.120056f, 0.131592f, 0.143311f, 0.155640f, 0.167969f,
+ 0.181763f, 0.195190f, 0.209229f, 0.223877f, 0.238647f, 0.254150f, 0.269531f, 0.285889f, 0.302979f, 0.319824f, 0.336426f, 0.354004f,
+ 0.372070f, 0.389893f, 0.406982f, 0.424805f, 0.443359f, 0.461182f, 0.479492f, 0.498047f, 0.515625f, 0.533691f, 0.551270f, 0.569336f,
+ 0.587402f, 0.604492f, 0.622070f, 0.639160f, 0.656738f, 0.673828f, 0.689941f, 0.705566f, 0.722168f, 0.737793f, 0.753418f, 0.768066f,
+ 0.783203f, 0.798340f, 0.904297f, 0.905762f, 0.902832f, 0.899414f, 0.895996f, 0.893066f, 0.002535f, 0.007812f, 0.013252f, 0.018738f,
+ 0.024384f, 0.030548f, 0.036774f, 0.043427f, 0.050476f, 0.057556f, 0.065491f, 0.073425f, 0.082458f, 0.091370f, 0.100525f, 0.110413f,
+ 0.120605f, 0.131592f, 0.142822f, 0.154663f, 0.166870f, 0.180176f, 0.193237f, 0.207031f, 0.221191f, 0.236084f, 0.250732f, 0.266602f,
+ 0.282959f, 0.299072f, 0.315430f, 0.332520f, 0.350342f, 0.367676f, 0.385010f, 0.403076f, 0.421631f, 0.439209f, 0.457520f, 0.475342f,
+ 0.494141f, 0.512695f, 0.530273f, 0.547852f, 0.565918f, 0.584473f, 0.602051f, 0.619629f, 0.637207f, 0.655273f, 0.671387f, 0.688965f,
+ 0.706055f, 0.721191f, 0.737305f, 0.752930f, 0.769531f, 0.784668f, 0.898438f, 0.900879f, 0.897949f, 0.894531f, 0.891602f, 0.888672f,
+ 0.002411f, 0.007103f, 0.012161f, 0.017105f, 0.022385f, 0.027985f, 0.033203f, 0.039581f, 0.045532f, 0.052521f, 0.059814f, 0.067261f,
+ 0.074768f, 0.083313f, 0.092041f, 0.101013f, 0.110291f, 0.120361f, 0.130615f, 0.141724f, 0.153076f, 0.165283f, 0.177612f, 0.190918f,
+ 0.204346f, 0.218506f, 0.233154f, 0.247559f, 0.263428f, 0.279053f, 0.295166f, 0.312256f, 0.328857f, 0.345947f, 0.363281f, 0.381348f,
+ 0.398926f, 0.417236f, 0.435547f, 0.453369f, 0.471191f, 0.489502f, 0.508301f, 0.525879f, 0.545410f, 0.563477f, 0.581055f, 0.600098f,
+ 0.617676f, 0.635254f, 0.653809f, 0.670410f, 0.687500f, 0.705078f, 0.720703f, 0.736816f, 0.753418f, 0.769531f, 0.892090f, 0.895020f,
+ 0.892578f, 0.889648f, 0.887207f, 0.884277f, 0.002344f, 0.006565f, 0.011322f, 0.015686f, 0.020630f, 0.025574f, 0.030807f, 0.035980f,
+ 0.042084f, 0.048279f, 0.054352f, 0.061432f, 0.068848f, 0.076172f, 0.083618f, 0.092590f, 0.101135f, 0.109619f, 0.120178f, 0.130249f,
+ 0.140991f, 0.151978f, 0.163696f, 0.175781f, 0.188721f, 0.202026f, 0.215820f, 0.230103f, 0.244873f, 0.259766f, 0.275635f, 0.291504f,
+ 0.307617f, 0.324219f, 0.342041f, 0.358887f, 0.376709f, 0.394775f, 0.412354f, 0.431152f, 0.448975f, 0.468018f, 0.486328f, 0.504883f,
+ 0.523438f, 0.541992f, 0.560547f, 0.579102f, 0.597656f, 0.615234f, 0.633789f, 0.651855f, 0.669434f, 0.687500f, 0.704590f, 0.721680f,
+ 0.738770f, 0.755859f, 0.886719f, 0.889648f, 0.887695f, 0.884766f, 0.882812f, 0.879883f, 0.002003f, 0.006268f, 0.009987f, 0.014198f,
+ 0.018875f, 0.023605f, 0.028259f, 0.033203f, 0.038513f, 0.044495f, 0.049866f, 0.056152f, 0.062500f, 0.069458f, 0.076660f, 0.084473f,
+ 0.092163f, 0.100586f, 0.109741f, 0.119324f, 0.128662f, 0.139526f, 0.150146f, 0.161499f, 0.173706f, 0.185791f, 0.199341f, 0.212891f,
+ 0.227051f, 0.241455f, 0.256592f, 0.271729f, 0.288330f, 0.304199f, 0.321045f, 0.337891f, 0.355469f, 0.373291f, 0.391113f, 0.408936f,
+ 0.426758f, 0.446289f, 0.464600f, 0.483643f, 0.500977f, 0.520996f, 0.539551f, 0.558594f, 0.577148f, 0.595703f, 0.614746f, 0.632324f,
+ 0.650879f, 0.669434f, 0.687012f, 0.704590f, 0.722656f, 0.740234f, 0.880371f, 0.883301f, 0.881836f, 0.879883f, 0.877441f, 0.875000f,
+ 0.001739f, 0.005779f, 0.009598f, 0.013245f, 0.017334f, 0.021637f, 0.025955f, 0.030121f, 0.035217f, 0.040131f, 0.045990f, 0.051453f,
+ 0.056915f, 0.063354f, 0.070007f, 0.076965f, 0.084351f, 0.091980f, 0.100281f, 0.108826f, 0.117981f, 0.127441f, 0.137939f, 0.148315f,
+ 0.160034f, 0.171753f, 0.183594f, 0.196167f, 0.209961f, 0.223511f, 0.238037f, 0.252930f, 0.268066f, 0.284180f, 0.300537f, 0.317139f,
+ 0.333740f, 0.351074f, 0.368896f, 0.386719f, 0.405273f, 0.423584f, 0.442871f, 0.460938f, 0.479736f, 0.499512f, 0.517578f, 0.537109f,
+ 0.555664f, 0.575195f, 0.594238f, 0.613770f, 0.632324f, 0.650879f, 0.669922f, 0.687988f, 0.706055f, 0.724121f, 0.873047f, 0.876953f,
+ 0.875488f, 0.874023f, 0.872559f, 0.869141f, 0.001648f, 0.005039f, 0.008675f, 0.012161f, 0.015823f, 0.019760f, 0.023865f, 0.028015f,
+ 0.032318f, 0.036865f, 0.041504f, 0.046906f, 0.051758f, 0.057922f, 0.064087f, 0.070435f, 0.077209f, 0.084290f, 0.091736f, 0.099243f,
+ 0.108215f, 0.117004f, 0.126343f, 0.135620f, 0.146484f, 0.157349f, 0.168823f, 0.180908f, 0.193848f, 0.206909f, 0.220459f, 0.234619f,
+ 0.249634f, 0.264404f, 0.280273f, 0.296631f, 0.313232f, 0.329834f, 0.347412f, 0.365479f, 0.383545f, 0.401855f, 0.420166f, 0.438721f,
+ 0.458252f, 0.477783f, 0.496826f, 0.516602f, 0.535156f, 0.554199f, 0.574219f, 0.593750f, 0.612305f, 0.631836f, 0.651367f, 0.670410f,
+ 0.689453f, 0.708984f, 0.865234f, 0.872070f, 0.870605f, 0.868652f, 0.866699f, 0.863770f, 0.001492f, 0.004704f, 0.007973f, 0.011124f,
+ 0.014603f, 0.017792f, 0.021652f, 0.025314f, 0.029526f, 0.033722f, 0.038147f, 0.042694f, 0.047668f, 0.052673f, 0.057983f, 0.064209f,
+ 0.070068f, 0.076233f, 0.083313f, 0.090942f, 0.098572f, 0.106750f, 0.115295f, 0.124512f, 0.134277f, 0.144287f, 0.154663f, 0.166504f,
+ 0.178345f, 0.190063f, 0.203247f, 0.217041f, 0.231079f, 0.245850f, 0.260986f, 0.276611f, 0.293213f, 0.309570f, 0.326172f, 0.343994f,
+ 0.361816f, 0.379395f, 0.397949f, 0.417480f, 0.436523f, 0.455322f, 0.474854f, 0.493896f, 0.514160f, 0.533691f, 0.553711f, 0.573730f,
+ 0.593262f, 0.612793f, 0.632812f, 0.651855f, 0.672363f, 0.690918f, 0.857910f, 0.865723f, 0.864746f, 0.863281f, 0.860352f, 0.858887f,
+ 0.001657f, 0.004684f, 0.007290f, 0.010201f, 0.013657f, 0.016541f, 0.019989f, 0.023636f, 0.026932f, 0.030548f, 0.034576f, 0.039154f,
+ 0.043793f, 0.048126f, 0.053162f, 0.058319f, 0.063721f, 0.069885f, 0.076355f, 0.082947f, 0.089844f, 0.097046f, 0.105286f, 0.113281f,
+ 0.122559f, 0.131348f, 0.141357f, 0.152100f, 0.163330f, 0.175415f, 0.187256f, 0.199951f, 0.213501f, 0.227051f, 0.241943f, 0.257324f,
+ 0.273193f, 0.288818f, 0.305420f, 0.322754f, 0.340576f, 0.358643f, 0.375732f, 0.394775f, 0.414307f, 0.433105f, 0.453613f, 0.472168f,
+ 0.492188f, 0.512695f, 0.532715f, 0.552246f, 0.573242f, 0.593262f, 0.613770f, 0.632812f, 0.654785f, 0.673828f, 0.851074f, 0.859375f,
+ 0.858398f, 0.856934f, 0.855469f, 0.853027f, 0.001457f, 0.003944f, 0.006870f, 0.009392f, 0.012543f, 0.015190f, 0.018417f, 0.021576f,
+ 0.024811f, 0.028122f, 0.031708f, 0.035278f, 0.039398f, 0.043793f, 0.048218f, 0.052887f, 0.058044f, 0.063477f, 0.069397f, 0.075256f,
+ 0.081360f, 0.088318f, 0.095398f, 0.103210f, 0.111084f, 0.120361f, 0.129150f, 0.139038f, 0.149292f, 0.160645f, 0.172241f, 0.183716f,
+ 0.196533f, 0.209595f, 0.224121f, 0.238647f, 0.253174f, 0.268799f, 0.286133f, 0.302490f, 0.319092f, 0.337158f, 0.355225f, 0.373535f,
+ 0.392090f, 0.411133f, 0.430908f, 0.450928f, 0.470947f, 0.490967f, 0.511719f, 0.531250f, 0.551758f, 0.573730f, 0.594238f, 0.614746f,
+ 0.636230f, 0.656738f, 0.842773f, 0.852051f, 0.851562f, 0.851074f, 0.848633f, 0.846680f, 0.001404f, 0.003891f, 0.006233f, 0.008751f,
+ 0.011353f, 0.014175f, 0.017075f, 0.019592f, 0.022842f, 0.025772f, 0.028839f, 0.032410f, 0.036011f, 0.039764f, 0.043671f, 0.048126f,
+ 0.052704f, 0.057373f, 0.062561f, 0.067688f, 0.074158f, 0.080200f, 0.086853f, 0.093445f, 0.101379f, 0.109192f, 0.117432f, 0.126709f,
+ 0.136353f, 0.146484f, 0.157227f, 0.168823f, 0.180542f, 0.193115f, 0.206299f, 0.219727f, 0.234375f, 0.249756f, 0.265869f, 0.281738f,
+ 0.298096f, 0.315674f, 0.333252f, 0.352051f, 0.370850f, 0.389160f, 0.409180f, 0.428955f, 0.448730f, 0.469971f, 0.489502f, 0.510742f,
+ 0.531738f, 0.552246f, 0.574707f, 0.595215f, 0.617676f, 0.639160f, 0.835449f, 0.845215f, 0.845215f, 0.844238f, 0.843262f, 0.840332f,
+ 0.001275f, 0.003536f, 0.005600f, 0.007881f, 0.010628f, 0.012878f, 0.015610f, 0.018097f, 0.020996f, 0.023376f, 0.026443f, 0.029556f,
+ 0.032867f, 0.036163f, 0.039581f, 0.043915f, 0.047943f, 0.052216f, 0.056763f, 0.061981f, 0.067322f, 0.072449f, 0.078796f, 0.084717f,
+ 0.091919f, 0.098999f, 0.106995f, 0.115417f, 0.124084f, 0.133667f, 0.143433f, 0.154297f, 0.165161f, 0.177124f, 0.189697f, 0.202759f,
+ 0.216309f, 0.230713f, 0.245728f, 0.261719f, 0.278320f, 0.295410f, 0.312256f, 0.330566f, 0.349365f, 0.367676f, 0.386719f, 0.406494f,
+ 0.427246f, 0.447266f, 0.468506f, 0.489746f, 0.510742f, 0.532227f, 0.553711f, 0.575684f, 0.597656f, 0.619141f, 0.826172f, 0.837402f,
+ 0.837891f, 0.837402f, 0.835449f, 0.833984f, 0.001134f, 0.003105f, 0.005337f, 0.007462f, 0.009628f, 0.011833f, 0.014137f, 0.016113f,
+ 0.018875f, 0.021484f, 0.024063f, 0.026581f, 0.029709f, 0.032623f, 0.036194f, 0.039703f, 0.043335f, 0.047058f, 0.051422f, 0.055908f,
+ 0.060608f, 0.065491f, 0.071167f, 0.076843f, 0.083313f, 0.089661f, 0.097168f, 0.104492f, 0.112122f, 0.121155f, 0.130615f, 0.140137f,
+ 0.150757f, 0.161499f, 0.173462f, 0.185547f, 0.199341f, 0.212524f, 0.227051f, 0.242310f, 0.258057f, 0.274414f, 0.291016f, 0.309082f,
+ 0.327148f, 0.345459f, 0.364990f, 0.384521f, 0.404297f, 0.425781f, 0.445801f, 0.467285f, 0.489258f, 0.510254f, 0.533203f, 0.555664f,
+ 0.578125f, 0.601074f, 0.817871f, 0.830078f, 0.831055f, 0.830078f, 0.829102f, 0.828125f, 0.001101f, 0.003019f, 0.004818f, 0.006725f,
+ 0.008781f, 0.010864f, 0.013069f, 0.014801f, 0.017151f, 0.019531f, 0.021973f, 0.024429f, 0.026917f, 0.030121f, 0.033112f, 0.036041f,
+ 0.039337f, 0.042542f, 0.046509f, 0.050537f, 0.054596f, 0.058990f, 0.064209f, 0.069519f, 0.075134f, 0.080994f, 0.087158f, 0.094177f,
+ 0.102051f, 0.109741f, 0.117981f, 0.127319f, 0.136963f, 0.147095f, 0.158081f, 0.169434f, 0.182251f, 0.195557f, 0.208984f, 0.223267f,
+ 0.238281f, 0.254639f, 0.270996f, 0.288330f, 0.305908f, 0.324219f, 0.343018f, 0.362549f, 0.382324f, 0.402832f, 0.424805f, 0.445312f,
+ 0.467529f, 0.489258f, 0.511230f, 0.535645f, 0.558594f, 0.582031f, 0.809082f, 0.822266f, 0.824219f, 0.823242f, 0.821777f, 0.820801f,
+ 0.000987f, 0.002644f, 0.004562f, 0.006344f, 0.008133f, 0.009918f, 0.011696f, 0.013527f, 0.015572f, 0.017746f, 0.019714f, 0.021942f,
+ 0.024155f, 0.027069f, 0.029678f, 0.032288f, 0.035156f, 0.038574f, 0.041779f, 0.045319f, 0.049225f, 0.053284f, 0.057678f, 0.062225f,
+ 0.067505f, 0.072571f, 0.078613f, 0.084961f, 0.092041f, 0.098938f, 0.106506f, 0.115112f, 0.123779f, 0.133667f, 0.143311f, 0.154541f,
+ 0.165894f, 0.178345f, 0.191406f, 0.205200f, 0.219238f, 0.234985f, 0.250977f, 0.267578f, 0.284912f, 0.302734f, 0.321289f, 0.340332f,
+ 0.360352f, 0.380615f, 0.401611f, 0.423340f, 0.445312f, 0.467529f, 0.490967f, 0.514160f, 0.537598f, 0.561035f, 0.800293f, 0.814453f,
+ 0.815918f, 0.815918f, 0.814941f, 0.813965f, 0.000932f, 0.002567f, 0.004009f, 0.005722f, 0.007538f, 0.008812f, 0.010864f, 0.012413f,
+ 0.014290f, 0.015991f, 0.018051f, 0.019836f, 0.022247f, 0.024506f, 0.026520f, 0.029175f, 0.031769f, 0.034332f, 0.037689f, 0.040466f,
+ 0.043945f, 0.047607f, 0.051605f, 0.055817f, 0.060486f, 0.065125f, 0.070557f, 0.076111f, 0.081909f, 0.088806f, 0.095886f, 0.103210f,
+ 0.111755f, 0.120422f, 0.130249f, 0.140137f, 0.150513f, 0.162109f, 0.174561f, 0.187256f, 0.200928f, 0.215698f, 0.231323f, 0.246582f,
+ 0.264160f, 0.281982f, 0.299561f, 0.319092f, 0.338623f, 0.358643f, 0.379883f, 0.400879f, 0.423096f, 0.445557f, 0.468750f, 0.492188f,
+ 0.516113f, 0.541504f, 0.791016f, 0.805664f, 0.808105f, 0.808594f, 0.807129f, 0.806641f, 0.000871f, 0.002337f, 0.003727f, 0.005474f,
+ 0.006641f, 0.008377f, 0.009567f, 0.011154f, 0.012848f, 0.014610f, 0.016235f, 0.017960f, 0.019958f, 0.021729f, 0.023926f, 0.026154f,
+ 0.028351f, 0.030975f, 0.033722f, 0.036407f, 0.039459f, 0.042694f, 0.046082f, 0.049896f, 0.053833f, 0.058167f, 0.062744f, 0.067932f,
+ 0.073608f, 0.079468f, 0.085632f, 0.092651f, 0.100098f, 0.108521f, 0.116699f, 0.126099f, 0.136108f, 0.146606f, 0.157959f, 0.170410f,
+ 0.183594f, 0.197510f, 0.212280f, 0.227295f, 0.243652f, 0.260986f, 0.278564f, 0.297607f, 0.316406f, 0.336426f, 0.357178f, 0.378662f,
+ 0.400146f, 0.422852f, 0.446045f, 0.470215f, 0.494873f, 0.520020f, 0.781250f, 0.796875f, 0.800293f, 0.800781f, 0.799805f, 0.799316f,
+ 0.000782f, 0.002131f, 0.003649f, 0.004715f, 0.006054f, 0.007458f, 0.008759f, 0.010269f, 0.011711f, 0.012970f, 0.014664f, 0.016327f,
+ 0.017914f, 0.019699f, 0.021423f, 0.023499f, 0.025391f, 0.027374f, 0.029999f, 0.032501f, 0.035156f, 0.037872f, 0.040710f, 0.044403f,
+ 0.047791f, 0.051880f, 0.055969f, 0.060364f, 0.065247f, 0.070496f, 0.076172f, 0.082825f, 0.089294f, 0.096497f, 0.104431f, 0.112854f,
+ 0.122375f, 0.132202f, 0.142700f, 0.153931f, 0.166260f, 0.179565f, 0.193481f, 0.208008f, 0.223877f, 0.240479f, 0.257568f, 0.275879f,
+ 0.294922f, 0.314453f, 0.334961f, 0.355957f, 0.377686f, 0.400391f, 0.423828f, 0.448730f, 0.472900f, 0.498535f, 0.771484f, 0.789062f,
+ 0.791504f, 0.792480f, 0.791016f, 0.791016f, 0.000742f, 0.001822f, 0.003183f, 0.004444f, 0.005600f, 0.006550f, 0.008087f, 0.009247f,
+ 0.010559f, 0.011650f, 0.013184f, 0.014565f, 0.016083f, 0.017548f, 0.019119f, 0.020737f, 0.022644f, 0.024597f, 0.026627f, 0.028809f,
+ 0.031281f, 0.033539f, 0.036469f, 0.039429f, 0.042480f, 0.045654f, 0.049561f, 0.053406f, 0.057739f, 0.062469f, 0.067749f, 0.073364f,
+ 0.079773f, 0.086121f, 0.093262f, 0.100647f, 0.109253f, 0.118042f, 0.128174f, 0.138550f, 0.150024f, 0.162231f, 0.175171f, 0.189087f,
+ 0.204468f, 0.220215f, 0.236938f, 0.254639f, 0.273438f, 0.292236f, 0.312012f, 0.333252f, 0.355957f, 0.377686f, 0.401367f, 0.425781f,
+ 0.451416f, 0.476318f, 0.761230f, 0.779785f, 0.782227f, 0.782715f, 0.782715f, 0.782715f, 0.000632f, 0.001970f, 0.003042f, 0.004025f,
+ 0.005173f, 0.006435f, 0.007343f, 0.008522f, 0.009369f, 0.010475f, 0.011726f, 0.012962f, 0.014145f, 0.015411f, 0.016922f, 0.018478f,
+ 0.020111f, 0.021835f, 0.023682f, 0.025253f, 0.027466f, 0.029678f, 0.032196f, 0.034607f, 0.037415f, 0.040497f, 0.043610f, 0.047089f,
+ 0.051178f, 0.055573f, 0.059845f, 0.064758f, 0.070068f, 0.076111f, 0.082275f, 0.089417f, 0.096863f, 0.105286f, 0.114441f, 0.123535f,
+ 0.134399f, 0.145508f, 0.157959f, 0.171387f, 0.185425f, 0.200806f, 0.216919f, 0.233521f, 0.251953f, 0.270508f, 0.290527f, 0.310791f,
+ 0.332275f, 0.355469f, 0.378418f, 0.403564f, 0.428223f, 0.455322f, 0.750977f, 0.770996f, 0.774414f, 0.774414f, 0.774902f, 0.773926f,
+ 0.000517f, 0.001554f, 0.002741f, 0.003695f, 0.004669f, 0.005417f, 0.006466f, 0.007545f, 0.008453f, 0.009499f, 0.010468f, 0.011490f,
+ 0.012718f, 0.013985f, 0.014977f, 0.016235f, 0.017868f, 0.019211f, 0.020630f, 0.022263f, 0.024078f, 0.026291f, 0.028275f, 0.030380f,
+ 0.032928f, 0.035675f, 0.038513f, 0.041656f, 0.044769f, 0.048523f, 0.052216f, 0.057007f, 0.061493f, 0.066711f, 0.072510f, 0.078735f,
+ 0.085327f, 0.093201f, 0.101135f, 0.109619f, 0.119690f, 0.130371f, 0.141602f, 0.154053f, 0.167480f, 0.181396f, 0.197021f, 0.213623f,
+ 0.230835f, 0.248901f, 0.268066f, 0.289062f, 0.310303f, 0.332520f, 0.355225f, 0.379639f, 0.405273f, 0.432373f, 0.740234f, 0.760742f,
+ 0.763672f, 0.765625f, 0.765625f, 0.765625f, 0.000588f, 0.001405f, 0.002306f, 0.003370f, 0.004375f, 0.005116f, 0.005817f, 0.006630f,
+ 0.007797f, 0.008507f, 0.009216f, 0.010254f, 0.011246f, 0.012154f, 0.013191f, 0.014366f, 0.015503f, 0.016785f, 0.018127f, 0.019562f,
+ 0.021072f, 0.022919f, 0.024643f, 0.026749f, 0.028564f, 0.031006f, 0.033203f, 0.036072f, 0.039032f, 0.042114f, 0.045654f, 0.049561f,
+ 0.053650f, 0.058380f, 0.063049f, 0.068848f, 0.075256f, 0.081543f, 0.088562f, 0.096924f, 0.105652f, 0.115173f, 0.125977f, 0.137207f,
+ 0.149902f, 0.163208f, 0.177979f, 0.193726f, 0.210205f, 0.228027f, 0.247070f, 0.266602f, 0.287842f, 0.309326f, 0.333008f, 0.356934f,
+ 0.382568f, 0.408691f, 0.729004f, 0.751953f, 0.755371f, 0.756348f, 0.757324f, 0.756348f, 0.000431f, 0.001562f, 0.002253f, 0.003088f,
+ 0.003944f, 0.004536f, 0.005066f, 0.006020f, 0.006840f, 0.007542f, 0.008347f, 0.008949f, 0.009827f, 0.010719f, 0.011696f, 0.012756f,
+ 0.013649f, 0.014679f, 0.015808f, 0.017288f, 0.018356f, 0.019913f, 0.021332f, 0.023148f, 0.024719f, 0.026840f, 0.029007f, 0.031250f,
+ 0.033661f, 0.036469f, 0.039490f, 0.042969f, 0.046326f, 0.050293f, 0.054901f, 0.059845f, 0.064941f, 0.071289f, 0.077454f, 0.084656f,
+ 0.092529f, 0.101562f, 0.111145f, 0.121460f, 0.132935f, 0.145386f, 0.159302f, 0.174438f, 0.190186f, 0.206909f, 0.225098f, 0.244751f,
+ 0.265381f, 0.287109f, 0.310059f, 0.333984f, 0.359131f, 0.386230f, 0.716797f, 0.740723f, 0.744629f, 0.746582f, 0.747070f, 0.747070f,
+ 0.000576f, 0.001266f, 0.002028f, 0.002766f, 0.003317f, 0.004051f, 0.004742f, 0.005459f, 0.006054f, 0.006641f, 0.007240f, 0.007919f,
+ 0.008644f, 0.009300f, 0.010170f, 0.010925f, 0.011795f, 0.012733f, 0.013855f, 0.014885f, 0.015900f, 0.017212f, 0.018326f, 0.019684f,
+ 0.021469f, 0.023178f, 0.024734f, 0.026794f, 0.028946f, 0.031204f, 0.033844f, 0.036682f, 0.039948f, 0.043335f, 0.047150f, 0.051422f,
+ 0.055969f, 0.061066f, 0.067139f, 0.073242f, 0.080444f, 0.088440f, 0.096985f, 0.106445f, 0.116943f, 0.128906f, 0.141479f, 0.154907f,
+ 0.170410f, 0.186523f, 0.204102f, 0.222900f, 0.243774f, 0.264160f, 0.286865f, 0.310791f, 0.336182f, 0.362793f, 0.705078f, 0.730469f,
+ 0.735352f, 0.736816f, 0.737793f, 0.736816f, 0.000307f, 0.001126f, 0.001758f, 0.002436f, 0.002911f, 0.003540f, 0.004047f, 0.004711f,
+ 0.005245f, 0.005749f, 0.006302f, 0.006844f, 0.007355f, 0.008095f, 0.008835f, 0.009438f, 0.010139f, 0.010941f, 0.011963f, 0.012878f,
+ 0.013519f, 0.014847f, 0.015945f, 0.017029f, 0.018250f, 0.019669f, 0.021362f, 0.022675f, 0.024750f, 0.026657f, 0.028854f, 0.031219f,
+ 0.033844f, 0.036804f, 0.040222f, 0.043793f, 0.047791f, 0.052185f, 0.057251f, 0.062866f, 0.069275f, 0.075867f, 0.083923f, 0.092407f,
+ 0.102295f, 0.112366f, 0.124207f, 0.137085f, 0.151489f, 0.167114f, 0.183838f, 0.202148f, 0.221558f, 0.242065f, 0.263916f, 0.287842f,
+ 0.312256f, 0.339111f, 0.693848f, 0.719727f, 0.724609f, 0.726074f, 0.727539f, 0.727051f, 0.000428f, 0.000939f, 0.001581f, 0.002033f,
+ 0.002665f, 0.003222f, 0.003660f, 0.004059f, 0.004475f, 0.004997f, 0.005554f, 0.006031f, 0.006371f, 0.007080f, 0.007511f, 0.008263f,
+ 0.008820f, 0.009552f, 0.010124f, 0.010948f, 0.011665f, 0.012550f, 0.013397f, 0.014526f, 0.015388f, 0.016754f, 0.017960f, 0.019257f,
+ 0.020844f, 0.022583f, 0.024246f, 0.026642f, 0.028656f, 0.031128f, 0.033783f, 0.036865f, 0.040253f, 0.044312f, 0.048523f, 0.053314f,
+ 0.058655f, 0.064880f, 0.071594f, 0.079102f, 0.087891f, 0.097107f, 0.108276f, 0.119751f, 0.133179f, 0.148071f, 0.163818f, 0.180908f,
+ 0.199951f, 0.219849f, 0.241699f, 0.264160f, 0.288818f, 0.315918f, 0.680176f, 0.708496f, 0.713867f, 0.716309f, 0.716797f, 0.717285f,
+ 0.000467f, 0.001054f, 0.001476f, 0.001825f, 0.002386f, 0.002644f, 0.003218f, 0.003553f, 0.003866f, 0.004433f, 0.004700f, 0.004948f,
+ 0.005505f, 0.006023f, 0.006405f, 0.006920f, 0.007484f, 0.008057f, 0.008598f, 0.009178f, 0.009857f, 0.010551f, 0.011169f, 0.012199f,
+ 0.013092f, 0.014084f, 0.015091f, 0.016205f, 0.017303f, 0.018845f, 0.020538f, 0.021957f, 0.023773f, 0.025833f, 0.028152f, 0.030716f,
+ 0.033661f, 0.036896f, 0.040405f, 0.044708f, 0.049286f, 0.054321f, 0.060333f, 0.067322f, 0.074890f, 0.083435f, 0.092651f, 0.103516f,
+ 0.115784f, 0.129028f, 0.144287f, 0.160278f, 0.178345f, 0.197632f, 0.218994f, 0.241089f, 0.265869f, 0.292725f, 0.667969f, 0.697266f,
+ 0.702637f, 0.704590f, 0.706055f, 0.707031f, 0.000348f, 0.000841f, 0.001292f, 0.001580f, 0.001961f, 0.002508f, 0.002630f, 0.002993f,
+ 0.003458f, 0.003738f, 0.003952f, 0.004425f, 0.004639f, 0.005070f, 0.005547f, 0.005840f, 0.006462f, 0.006844f, 0.007214f, 0.007698f,
+ 0.008339f, 0.008980f, 0.009560f, 0.010094f, 0.010941f, 0.011711f, 0.012550f, 0.013565f, 0.014404f, 0.015579f, 0.016754f, 0.018082f,
+ 0.019592f, 0.021439f, 0.023209f, 0.025375f, 0.027863f, 0.030411f, 0.033478f, 0.037018f, 0.040680f, 0.045105f, 0.050476f, 0.056183f,
+ 0.062805f, 0.070251f, 0.078613f, 0.088196f, 0.099060f, 0.111450f, 0.125122f, 0.140869f, 0.158203f, 0.176880f, 0.197266f, 0.218506f,
+ 0.242798f, 0.268555f, 0.655273f, 0.686035f, 0.691406f, 0.694336f, 0.695312f, 0.695801f, 0.000170f, 0.000976f, 0.001161f, 0.001441f,
+ 0.001846f, 0.002144f, 0.002367f, 0.002632f, 0.002892f, 0.003178f, 0.003435f, 0.003618f, 0.004021f, 0.004292f, 0.004562f, 0.005028f,
+ 0.005405f, 0.005623f, 0.006069f, 0.006577f, 0.006973f, 0.007431f, 0.007904f, 0.008484f, 0.009018f, 0.009659f, 0.010559f, 0.010994f,
+ 0.012009f, 0.012840f, 0.013901f, 0.014915f, 0.016129f, 0.017502f, 0.019089f, 0.020676f, 0.022568f, 0.024673f, 0.027252f, 0.029984f,
+ 0.033234f, 0.037079f, 0.041016f, 0.045868f, 0.051758f, 0.058014f, 0.065613f, 0.073853f, 0.083801f, 0.094727f, 0.107483f, 0.121826f,
+ 0.137573f, 0.156006f, 0.175049f, 0.196167f, 0.219482f, 0.245850f, 0.641113f, 0.673340f, 0.679688f, 0.681641f, 0.683594f, 0.684082f,
+ 0.000293f, 0.000601f, 0.001049f, 0.001358f, 0.001532f, 0.001719f, 0.001882f, 0.002298f, 0.002317f, 0.002628f, 0.002750f, 0.003143f,
+ 0.003363f, 0.003559f, 0.003866f, 0.004204f, 0.004383f, 0.004753f, 0.005028f, 0.005348f, 0.005863f, 0.006176f, 0.006569f, 0.006954f,
+ 0.007401f, 0.008057f, 0.008537f, 0.009178f, 0.009735f, 0.010521f, 0.011208f, 0.011978f, 0.013130f, 0.014099f, 0.015289f, 0.016739f,
+ 0.018219f, 0.019821f, 0.021713f, 0.024200f, 0.026749f, 0.029785f, 0.033386f, 0.036987f, 0.041840f, 0.047089f, 0.053253f, 0.060760f,
+ 0.069214f, 0.079224f, 0.090515f, 0.103638f, 0.118652f, 0.135376f, 0.154175f, 0.174561f, 0.196777f, 0.222534f, 0.628906f, 0.660645f,
+ 0.668457f, 0.670410f, 0.672852f, 0.673340f, 0.000258f, 0.000656f, 0.000811f, 0.001049f, 0.001288f, 0.001462f, 0.001599f, 0.001740f,
+ 0.002012f, 0.002171f, 0.002367f, 0.002535f, 0.002705f, 0.002880f, 0.003115f, 0.003429f, 0.003666f, 0.003897f, 0.004116f, 0.004398f,
+ 0.004635f, 0.005066f, 0.005341f, 0.005779f, 0.006042f, 0.006454f, 0.006954f, 0.007450f, 0.007835f, 0.008400f, 0.009132f, 0.009819f,
+ 0.010536f, 0.011307f, 0.012245f, 0.013229f, 0.014580f, 0.015900f, 0.017303f, 0.019119f, 0.021103f, 0.023468f, 0.026123f, 0.029495f,
+ 0.033112f, 0.037628f, 0.042938f, 0.048859f, 0.056152f, 0.064941f, 0.074829f, 0.086548f, 0.100281f, 0.115967f, 0.133545f, 0.153198f,
+ 0.175171f, 0.199341f, 0.613770f, 0.648926f, 0.655273f, 0.658691f, 0.660645f, 0.662598f, 0.000176f, 0.000474f, 0.000602f, 0.000854f,
+ 0.001030f, 0.001240f, 0.001349f, 0.001505f, 0.001580f, 0.001738f, 0.001957f, 0.002068f, 0.002230f, 0.002420f, 0.002556f, 0.002705f,
+ 0.002998f, 0.003178f, 0.003345f, 0.003567f, 0.003811f, 0.004105f, 0.004284f, 0.004593f, 0.004848f, 0.005173f, 0.005527f, 0.005939f,
+ 0.006306f, 0.006817f, 0.007366f, 0.007729f, 0.008339f, 0.008995f, 0.009644f, 0.010551f, 0.011360f, 0.012344f, 0.013710f, 0.015030f,
+ 0.016510f, 0.018143f, 0.020279f, 0.022751f, 0.025650f, 0.029144f, 0.033508f, 0.038452f, 0.044556f, 0.052032f, 0.060364f, 0.070923f,
+ 0.082642f, 0.097290f, 0.113525f, 0.132446f, 0.153442f, 0.176880f, 0.600586f, 0.636719f, 0.644531f, 0.647461f, 0.648926f, 0.649414f,
+ 0.000121f, 0.000426f, 0.000509f, 0.000778f, 0.000931f, 0.000992f, 0.001135f, 0.001303f, 0.001359f, 0.001410f, 0.001519f, 0.001722f,
+ 0.001751f, 0.001951f, 0.002060f, 0.002218f, 0.002287f, 0.002487f, 0.002670f, 0.002848f, 0.003061f, 0.003233f, 0.003452f, 0.003664f,
+ 0.003883f, 0.004078f, 0.004379f, 0.004692f, 0.004982f, 0.005329f, 0.005756f, 0.006081f, 0.006504f, 0.007019f, 0.007599f, 0.008217f,
+ 0.008850f, 0.009628f, 0.010437f, 0.011597f, 0.012650f, 0.013931f, 0.015480f, 0.017380f, 0.019577f, 0.022247f, 0.025513f, 0.029617f,
+ 0.034363f, 0.040314f, 0.047241f, 0.056274f, 0.066711f, 0.079773f, 0.094482f, 0.112488f, 0.132446f, 0.154907f, 0.585449f, 0.624023f,
+ 0.630371f, 0.634277f, 0.636230f, 0.637207f, 0.000161f, 0.000263f, 0.000526f, 0.000627f, 0.000723f, 0.000775f, 0.000856f, 0.000960f,
+ 0.001079f, 0.001158f, 0.001208f, 0.001272f, 0.001441f, 0.001557f, 0.001657f, 0.001702f, 0.001897f, 0.001918f, 0.002151f, 0.002232f,
+ 0.002337f, 0.002522f, 0.002720f, 0.002865f, 0.003029f, 0.003193f, 0.003387f, 0.003601f, 0.003887f, 0.004124f, 0.004356f, 0.004639f,
+ 0.005070f, 0.005466f, 0.005863f, 0.006298f, 0.006874f, 0.007290f, 0.007965f, 0.008774f, 0.009560f, 0.010666f, 0.011719f, 0.013077f,
+ 0.014679f, 0.016693f, 0.019058f, 0.021881f, 0.025528f, 0.030121f, 0.036011f, 0.043396f, 0.052460f, 0.063477f, 0.076721f, 0.093079f,
+ 0.112305f, 0.133667f, 0.572266f, 0.609375f, 0.618164f, 0.622070f, 0.623535f, 0.625488f, 0.000109f, 0.000212f, 0.000404f, 0.000578f,
+ 0.000567f, 0.000655f, 0.000763f, 0.000676f, 0.000824f, 0.000869f, 0.000971f, 0.001064f, 0.001132f, 0.001210f, 0.001212f, 0.001398f,
+ 0.001486f, 0.001525f, 0.001653f, 0.001676f, 0.001867f, 0.001953f, 0.002062f, 0.002199f, 0.002295f, 0.002443f, 0.002586f, 0.002766f,
+ 0.002979f, 0.003128f, 0.003429f, 0.003551f, 0.003763f, 0.004074f, 0.004349f, 0.004688f, 0.005032f, 0.005470f, 0.005894f, 0.006519f,
+ 0.007092f, 0.007896f, 0.008629f, 0.009659f, 0.010910f, 0.012215f, 0.013962f, 0.015991f, 0.018646f, 0.021881f, 0.026428f, 0.032074f,
+ 0.039276f, 0.048645f, 0.060455f, 0.075256f, 0.092773f, 0.113220f, 0.554688f, 0.596191f, 0.605957f, 0.608887f, 0.610352f, 0.612305f,
+ 0.000202f, 0.000186f, 0.000312f, 0.000433f, 0.000382f, 0.000543f, 0.000482f, 0.000546f, 0.000621f, 0.000666f, 0.000789f, 0.000802f,
+ 0.000859f, 0.000950f, 0.000970f, 0.000975f, 0.001113f, 0.001162f, 0.001207f, 0.001312f, 0.001362f, 0.001433f, 0.001541f, 0.001618f,
+ 0.001720f, 0.001791f, 0.001966f, 0.002035f, 0.002199f, 0.002413f, 0.002546f, 0.002626f, 0.002855f, 0.003063f, 0.003204f, 0.003448f,
+ 0.003693f, 0.003986f, 0.004364f, 0.004684f, 0.005127f, 0.005619f, 0.006271f, 0.006870f, 0.007748f, 0.008713f, 0.009911f, 0.011368f,
+ 0.013191f, 0.015518f, 0.018646f, 0.022644f, 0.028107f, 0.035645f, 0.045471f, 0.058502f, 0.074646f, 0.093994f, 0.541016f, 0.583008f,
+ 0.591797f, 0.596191f, 0.599121f, 0.600098f, 0.000000f, 0.000179f, 0.000242f, 0.000318f, 0.000341f, 0.000345f, 0.000432f, 0.000364f,
+ 0.000475f, 0.000483f, 0.000572f, 0.000576f, 0.000619f, 0.000640f, 0.000716f, 0.000737f, 0.000791f, 0.000845f, 0.000871f, 0.000907f,
+ 0.000998f, 0.001025f, 0.001107f, 0.001181f, 0.001244f, 0.001303f, 0.001391f, 0.001462f, 0.001549f, 0.001631f, 0.001756f, 0.001906f,
+ 0.001984f, 0.002161f, 0.002264f, 0.002419f, 0.002613f, 0.002825f, 0.003103f, 0.003321f, 0.003584f, 0.003893f, 0.004349f, 0.004799f,
+ 0.005383f, 0.006020f, 0.006836f, 0.007858f, 0.009117f, 0.010674f, 0.012825f, 0.015533f, 0.019363f, 0.024780f, 0.032593f, 0.043274f,
+ 0.057770f, 0.076111f, 0.525879f, 0.569336f, 0.578613f, 0.583008f, 0.585449f, 0.586426f, 0.000000f, 0.000088f, 0.000192f, 0.000227f,
+ 0.000230f, 0.000286f, 0.000255f, 0.000317f, 0.000321f, 0.000371f, 0.000401f, 0.000373f, 0.000391f, 0.000457f, 0.000474f, 0.000530f,
+ 0.000509f, 0.000585f, 0.000625f, 0.000664f, 0.000707f, 0.000746f, 0.000772f, 0.000817f, 0.000877f, 0.000887f, 0.000978f, 0.001007f,
+ 0.001069f, 0.001202f, 0.001192f, 0.001290f, 0.001356f, 0.001464f, 0.001583f, 0.001678f, 0.001771f, 0.001929f, 0.002050f, 0.002230f,
+ 0.002424f, 0.002651f, 0.002888f, 0.003176f, 0.003534f, 0.003967f, 0.004475f, 0.005154f, 0.005993f, 0.007118f, 0.008469f, 0.010338f,
+ 0.012794f, 0.016403f, 0.021957f, 0.030090f, 0.042419f, 0.059052f, 0.510254f, 0.554199f, 0.564453f, 0.570312f, 0.572754f, 0.573242f,
+ 0.000000f, 0.000126f, 0.000180f, 0.000121f, 0.000178f, 0.000176f, 0.000177f, 0.000212f, 0.000210f, 0.000228f, 0.000238f, 0.000291f,
+ 0.000280f, 0.000298f, 0.000336f, 0.000350f, 0.000369f, 0.000387f, 0.000395f, 0.000427f, 0.000460f, 0.000476f, 0.000515f, 0.000536f,
+ 0.000573f, 0.000619f, 0.000650f, 0.000670f, 0.000703f, 0.000746f, 0.000798f, 0.000836f, 0.000902f, 0.000949f, 0.001031f, 0.001062f,
+ 0.001162f, 0.001227f, 0.001349f, 0.001442f, 0.001533f, 0.001690f, 0.001865f, 0.001995f, 0.002228f, 0.002495f, 0.002800f, 0.003191f,
+ 0.003653f, 0.004349f, 0.005203f, 0.006393f, 0.008026f, 0.010307f, 0.013710f, 0.019379f, 0.028854f, 0.043457f, 0.494873f, 0.541016f,
+ 0.550781f, 0.555664f, 0.558105f, 0.559570f, 0.000000f, 0.000095f, 0.000086f, 0.000079f, 0.000105f, 0.000124f, 0.000111f, 0.000137f,
+ 0.000141f, 0.000142f, 0.000147f, 0.000151f, 0.000160f, 0.000181f, 0.000202f, 0.000207f, 0.000214f, 0.000248f, 0.000244f, 0.000282f,
+ 0.000273f, 0.000283f, 0.000306f, 0.000334f, 0.000367f, 0.000378f, 0.000376f, 0.000399f, 0.000437f, 0.000459f, 0.000474f, 0.000516f,
+ 0.000552f, 0.000567f, 0.000616f, 0.000649f, 0.000693f, 0.000743f, 0.000805f, 0.000851f, 0.000918f, 0.000999f, 0.001085f, 0.001195f,
+ 0.001309f, 0.001466f, 0.001644f, 0.001850f, 0.002151f, 0.002487f, 0.002974f, 0.003654f, 0.004574f, 0.006001f, 0.008156f, 0.011452f,
+ 0.017853f, 0.029739f, 0.478271f, 0.526367f, 0.537109f, 0.541504f, 0.544434f, 0.545898f, 0.000106f, 0.000085f, 0.000074f, 0.000067f,
+ 0.000066f, 0.000070f, 0.000069f, 0.000073f, 0.000073f, 0.000080f, 0.000084f, 0.000109f, 0.000093f, 0.000098f, 0.000119f, 0.000108f,
+ 0.000128f, 0.000135f, 0.000137f, 0.000149f, 0.000150f, 0.000157f, 0.000182f, 0.000185f, 0.000207f, 0.000206f, 0.000214f, 0.000234f,
+ 0.000237f, 0.000253f, 0.000267f, 0.000289f, 0.000306f, 0.000313f, 0.000344f, 0.000352f, 0.000384f, 0.000406f, 0.000445f, 0.000467f,
+ 0.000503f, 0.000543f, 0.000593f, 0.000634f, 0.000697f, 0.000764f, 0.000850f, 0.000963f, 0.001105f, 0.001298f, 0.001536f, 0.001856f,
+ 0.002333f, 0.003069f, 0.004299f, 0.006271f, 0.009789f, 0.018234f, 0.462402f, 0.511719f, 0.522949f, 0.527344f, 0.530762f, 0.532715f,
+ 0.000091f, 0.000069f, 0.000060f, 0.000054f, 0.000049f, 0.000046f, 0.000043f, 0.000041f, 0.000040f, 0.000044f, 0.000040f, 0.000040f,
+ 0.000054f, 0.000044f, 0.000045f, 0.000044f, 0.000062f, 0.000062f, 0.000069f, 0.000071f, 0.000074f, 0.000079f, 0.000081f, 0.000081f,
+ 0.000085f, 0.000099f, 0.000098f, 0.000115f, 0.000115f, 0.000119f, 0.000125f, 0.000130f, 0.000140f, 0.000144f, 0.000165f, 0.000172f,
+ 0.000178f, 0.000191f, 0.000205f, 0.000222f, 0.000234f, 0.000251f, 0.000276f, 0.000293f, 0.000327f, 0.000354f, 0.000392f, 0.000437f,
+ 0.000494f, 0.000562f, 0.000662f, 0.000800f, 0.001005f, 0.001315f, 0.001852f, 0.002825f, 0.004723f, 0.009285f, 0.446533f, 0.497803f,
+ 0.508301f, 0.514160f, 0.516602f, 0.519043f, 0.000067f, 0.000048f, 0.000040f, 0.000036f, 0.000033f, 0.000031f, 0.000030f, 0.000028f,
+ 0.000027f, 0.000026f, 0.000025f, 0.000024f, 0.000023f, 0.000022f, 0.000021f, 0.000020f, 0.000019f, 0.000020f, 0.000024f, 0.000026f,
+ 0.000025f, 0.000027f, 0.000031f, 0.000032f, 0.000032f, 0.000037f, 0.000041f, 0.000038f, 0.000045f, 0.000042f, 0.000048f, 0.000049f,
+ 0.000053f, 0.000055f, 0.000059f, 0.000062f, 0.000071f, 0.000074f, 0.000077f, 0.000081f, 0.000086f, 0.000091f, 0.000098f, 0.000109f,
+ 0.000116f, 0.000125f, 0.000137f, 0.000158f, 0.000173f, 0.000193f, 0.000230f, 0.000273f, 0.000335f, 0.000425f, 0.000603f, 0.000935f,
+ 0.001694f, 0.003727f, 0.431396f, 0.481934f, 0.493652f, 0.499512f, 0.502930f, 0.504883f, 0.000021f, 0.000016f, 0.000013f, 0.000012f,
+ 0.000013f, 0.000012f, 0.000012f, 0.000012f, 0.000012f, 0.000012f, 0.000011f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000011f,
+ 0.000011f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000008f, 0.000008f, 0.000007f,
+ 0.000008f, 0.000009f, 0.000009f, 0.000010f, 0.000010f, 0.000013f, 0.000014f, 0.000013f, 0.000015f, 0.000016f, 0.000017f, 0.000019f,
+ 0.000019f, 0.000020f, 0.000023f, 0.000026f, 0.000027f, 0.000027f, 0.000032f, 0.000030f, 0.000036f, 0.000039f, 0.000050f, 0.000056f,
+ 0.000063f, 0.000082f, 0.000109f, 0.000168f, 0.000317f, 0.000922f, 0.415283f, 0.467773f, 0.479980f, 0.486328f, 0.489014f, 0.490723f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000004f, 0.000005f, 0.000008f, 0.000026f, 0.398926f, 0.452881f,
+ 0.465576f, 0.471436f, 0.474854f, 0.477051f,
+ },
+ {
+ 0.019653f, 0.058990f, 0.097473f, 0.134277f, 0.169189f, 0.203491f, 0.236450f, 0.267578f, 0.297852f, 0.326416f, 0.354004f, 0.380859f,
+ 0.406250f, 0.431641f, 0.455078f, 0.477539f, 0.500000f, 0.520996f, 0.541504f, 0.560547f, 0.580566f, 0.598633f, 0.615723f, 0.633301f,
+ 0.649902f, 0.666016f, 0.681641f, 0.695801f, 0.709961f, 0.724609f, 0.738770f, 0.751953f, 0.765137f, 0.775879f, 0.788574f, 0.799805f,
+ 0.812012f, 0.822754f, 0.833496f, 0.844238f, 0.854004f, 0.864258f, 0.874023f, 0.883301f, 0.891602f, 0.900391f, 0.909668f, 0.917969f,
+ 0.925781f, 0.934570f, 0.941895f, 0.949707f, 0.956543f, 0.963379f, 0.970703f, 0.977539f, 0.984863f, 0.991211f, 0.988770f, 0.972656f,
+ 0.960449f, 0.949707f, 0.940430f, 0.931641f, 0.017303f, 0.052399f, 0.086548f, 0.119446f, 0.153076f, 0.183594f, 0.214722f, 0.245117f,
+ 0.273193f, 0.301270f, 0.328613f, 0.354492f, 0.379883f, 0.404541f, 0.427979f, 0.450195f, 0.472656f, 0.494629f, 0.515137f, 0.534668f,
+ 0.554199f, 0.573242f, 0.591309f, 0.608887f, 0.625977f, 0.642578f, 0.658203f, 0.672852f, 0.688477f, 0.704102f, 0.717285f, 0.731445f,
+ 0.744629f, 0.756836f, 0.769531f, 0.782715f, 0.793945f, 0.805664f, 0.816406f, 0.828125f, 0.838379f, 0.849121f, 0.858887f, 0.868652f,
+ 0.877930f, 0.888184f, 0.896973f, 0.905762f, 0.915039f, 0.921875f, 0.930176f, 0.937988f, 0.946777f, 0.954102f, 0.960938f, 0.968750f,
+ 0.975586f, 0.982422f, 0.984375f, 0.969238f, 0.957520f, 0.947754f, 0.938477f, 0.930176f, 0.015221f, 0.045837f, 0.076843f, 0.107666f,
+ 0.136719f, 0.166504f, 0.196045f, 0.223999f, 0.250244f, 0.278320f, 0.303711f, 0.329346f, 0.353271f, 0.378906f, 0.401367f, 0.424316f,
+ 0.447266f, 0.468018f, 0.487793f, 0.508301f, 0.529297f, 0.547363f, 0.566406f, 0.583984f, 0.601562f, 0.618652f, 0.634766f, 0.650879f,
+ 0.666016f, 0.681641f, 0.695801f, 0.710449f, 0.724121f, 0.737305f, 0.750488f, 0.762695f, 0.775391f, 0.788086f, 0.799316f, 0.811035f,
+ 0.821777f, 0.833008f, 0.844238f, 0.854004f, 0.864258f, 0.874023f, 0.882812f, 0.892578f, 0.901367f, 0.910156f, 0.918457f, 0.926758f,
+ 0.936035f, 0.942871f, 0.950684f, 0.958496f, 0.965820f, 0.973145f, 0.980469f, 0.965820f, 0.955078f, 0.945312f, 0.936523f, 0.928223f,
+ 0.013420f, 0.041138f, 0.068359f, 0.096436f, 0.124023f, 0.150879f, 0.177246f, 0.204224f, 0.230103f, 0.255859f, 0.281494f, 0.305420f,
+ 0.329834f, 0.352783f, 0.376709f, 0.398682f, 0.420654f, 0.442627f, 0.462646f, 0.483887f, 0.502441f, 0.521484f, 0.540527f, 0.559082f,
+ 0.576172f, 0.595703f, 0.611328f, 0.627930f, 0.644043f, 0.659668f, 0.674316f, 0.688965f, 0.703613f, 0.717285f, 0.730957f, 0.744629f,
+ 0.756836f, 0.770020f, 0.781738f, 0.793945f, 0.805176f, 0.816895f, 0.828125f, 0.838379f, 0.849121f, 0.859375f, 0.869141f, 0.878418f,
+ 0.888184f, 0.897461f, 0.906738f, 0.915039f, 0.923828f, 0.932129f, 0.940430f, 0.947754f, 0.956543f, 0.963867f, 0.976074f, 0.962402f,
+ 0.951660f, 0.942383f, 0.934082f, 0.926758f, 0.012001f, 0.036591f, 0.061737f, 0.086670f, 0.112000f, 0.136719f, 0.161743f, 0.186768f,
+ 0.211792f, 0.235840f, 0.259521f, 0.283203f, 0.307129f, 0.329590f, 0.352295f, 0.374268f, 0.395996f, 0.416992f, 0.437744f, 0.457520f,
+ 0.477295f, 0.497314f, 0.515625f, 0.534180f, 0.553223f, 0.570312f, 0.588379f, 0.604492f, 0.621582f, 0.636719f, 0.653320f, 0.666992f,
+ 0.683105f, 0.697266f, 0.710449f, 0.724609f, 0.737793f, 0.750977f, 0.764160f, 0.775879f, 0.788086f, 0.799805f, 0.812012f, 0.823242f,
+ 0.833496f, 0.844238f, 0.854492f, 0.864746f, 0.875000f, 0.884277f, 0.894043f, 0.902832f, 0.911621f, 0.920898f, 0.929688f, 0.937500f,
+ 0.945801f, 0.953613f, 0.971191f, 0.958984f, 0.949219f, 0.939941f, 0.932129f, 0.924316f, 0.010612f, 0.032684f, 0.054810f, 0.077759f,
+ 0.100952f, 0.124023f, 0.146851f, 0.171021f, 0.193604f, 0.217163f, 0.239380f, 0.261963f, 0.284424f, 0.307129f, 0.328613f, 0.351318f,
+ 0.371826f, 0.392334f, 0.413574f, 0.432617f, 0.453613f, 0.472656f, 0.491943f, 0.510254f, 0.528320f, 0.546387f, 0.563965f, 0.580078f,
+ 0.598633f, 0.613770f, 0.629883f, 0.645996f, 0.661621f, 0.675293f, 0.688965f, 0.705078f, 0.718262f, 0.731934f, 0.745605f, 0.757812f,
+ 0.770996f, 0.782715f, 0.795410f, 0.807129f, 0.818359f, 0.829102f, 0.839844f, 0.851074f, 0.860840f, 0.871094f, 0.880859f, 0.891113f,
+ 0.900391f, 0.909668f, 0.917969f, 0.927246f, 0.935547f, 0.943848f, 0.966797f, 0.955566f, 0.945801f, 0.937012f, 0.929199f, 0.921875f,
+ 0.009483f, 0.029556f, 0.050140f, 0.070129f, 0.091797f, 0.112549f, 0.134155f, 0.156372f, 0.177368f, 0.198975f, 0.220825f, 0.243286f,
+ 0.263916f, 0.285645f, 0.306885f, 0.327393f, 0.348145f, 0.368896f, 0.389404f, 0.409424f, 0.429199f, 0.448730f, 0.467529f, 0.486572f,
+ 0.505371f, 0.522461f, 0.540039f, 0.558105f, 0.574219f, 0.591309f, 0.607422f, 0.623535f, 0.639648f, 0.654785f, 0.669922f, 0.685547f,
+ 0.698730f, 0.712891f, 0.726074f, 0.740234f, 0.752441f, 0.765625f, 0.778320f, 0.789551f, 0.802246f, 0.813477f, 0.825195f, 0.836426f,
+ 0.847168f, 0.856934f, 0.868164f, 0.877930f, 0.888184f, 0.897461f, 0.906738f, 0.915527f, 0.925293f, 0.935059f, 0.962402f, 0.951660f,
+ 0.942383f, 0.933594f, 0.926270f, 0.919434f, 0.008934f, 0.026581f, 0.044708f, 0.063354f, 0.082825f, 0.102844f, 0.122437f, 0.141968f,
+ 0.162720f, 0.183105f, 0.202515f, 0.224609f, 0.244995f, 0.265381f, 0.285645f, 0.306152f, 0.326416f, 0.346680f, 0.365967f, 0.385498f,
+ 0.406006f, 0.425293f, 0.444092f, 0.461914f, 0.480225f, 0.499268f, 0.517090f, 0.535156f, 0.552246f, 0.568359f, 0.585449f, 0.601562f,
+ 0.616699f, 0.633789f, 0.649414f, 0.663574f, 0.678711f, 0.693848f, 0.706543f, 0.721680f, 0.734375f, 0.746582f, 0.760742f, 0.773438f,
+ 0.786133f, 0.797852f, 0.809082f, 0.821777f, 0.832031f, 0.843262f, 0.854492f, 0.864746f, 0.875000f, 0.884766f, 0.895020f, 0.904785f,
+ 0.914062f, 0.922852f, 0.957520f, 0.947266f, 0.938965f, 0.930664f, 0.923340f, 0.916992f, 0.007668f, 0.024017f, 0.040405f, 0.057831f,
+ 0.075195f, 0.093079f, 0.111694f, 0.130127f, 0.148926f, 0.168213f, 0.187500f, 0.206543f, 0.226440f, 0.246460f, 0.265869f, 0.285400f,
+ 0.305176f, 0.324707f, 0.344238f, 0.363281f, 0.383057f, 0.401123f, 0.420166f, 0.439941f, 0.457764f, 0.475586f, 0.493164f, 0.511719f,
+ 0.528809f, 0.545898f, 0.562988f, 0.579590f, 0.596191f, 0.612305f, 0.627441f, 0.643555f, 0.658203f, 0.672363f, 0.687988f, 0.702637f,
+ 0.715332f, 0.728516f, 0.742676f, 0.756348f, 0.768555f, 0.781250f, 0.794434f, 0.806152f, 0.818359f, 0.828613f, 0.840332f, 0.851074f,
+ 0.861816f, 0.872559f, 0.882812f, 0.892578f, 0.903320f, 0.912598f, 0.952637f, 0.943848f, 0.935059f, 0.927246f, 0.920410f, 0.914062f,
+ 0.007263f, 0.021530f, 0.037048f, 0.052429f, 0.068909f, 0.084961f, 0.102112f, 0.119568f, 0.136475f, 0.154541f, 0.172852f, 0.191528f,
+ 0.209717f, 0.228638f, 0.246948f, 0.265869f, 0.284912f, 0.304199f, 0.322510f, 0.341309f, 0.360596f, 0.379639f, 0.397461f, 0.416504f,
+ 0.434570f, 0.452881f, 0.470947f, 0.489014f, 0.505859f, 0.523438f, 0.541016f, 0.557129f, 0.574219f, 0.590332f, 0.606445f, 0.622070f,
+ 0.637695f, 0.653809f, 0.667969f, 0.682129f, 0.697754f, 0.711426f, 0.724609f, 0.737793f, 0.750977f, 0.765625f, 0.777832f, 0.790039f,
+ 0.801270f, 0.813477f, 0.825684f, 0.837402f, 0.848145f, 0.859375f, 0.870117f, 0.880859f, 0.891602f, 0.900391f, 0.947754f, 0.938965f,
+ 0.931152f, 0.923828f, 0.917480f, 0.911133f, 0.006401f, 0.019730f, 0.033813f, 0.047729f, 0.062561f, 0.077515f, 0.093140f, 0.108948f,
+ 0.125366f, 0.141968f, 0.159058f, 0.175781f, 0.193726f, 0.212036f, 0.229980f, 0.247681f, 0.265869f, 0.284424f, 0.302734f, 0.320557f,
+ 0.339111f, 0.357910f, 0.376221f, 0.394287f, 0.412109f, 0.429688f, 0.448486f, 0.466064f, 0.483398f, 0.500977f, 0.517090f, 0.535156f,
+ 0.552246f, 0.568359f, 0.583984f, 0.600586f, 0.616699f, 0.632324f, 0.647949f, 0.662598f, 0.677246f, 0.692383f, 0.706543f, 0.719727f,
+ 0.734375f, 0.747070f, 0.761230f, 0.773926f, 0.786621f, 0.797852f, 0.811523f, 0.823242f, 0.834961f, 0.846680f, 0.857422f, 0.868652f,
+ 0.879395f, 0.890137f, 0.942383f, 0.934082f, 0.927246f, 0.919922f, 0.913574f, 0.908203f, 0.005836f, 0.018158f, 0.030746f, 0.043335f,
+ 0.057007f, 0.070801f, 0.085754f, 0.099548f, 0.115112f, 0.130127f, 0.146362f, 0.162354f, 0.178711f, 0.195801f, 0.212769f, 0.230103f,
+ 0.247925f, 0.264893f, 0.283203f, 0.300293f, 0.318604f, 0.336426f, 0.354492f, 0.372314f, 0.390137f, 0.408203f, 0.425537f, 0.443848f,
+ 0.461182f, 0.478271f, 0.496094f, 0.513184f, 0.529297f, 0.546387f, 0.563477f, 0.580566f, 0.595703f, 0.611816f, 0.626465f, 0.642090f,
+ 0.658691f, 0.671875f, 0.686523f, 0.702148f, 0.716797f, 0.729980f, 0.744629f, 0.757324f, 0.770020f, 0.783203f, 0.796875f, 0.808105f,
+ 0.820312f, 0.832520f, 0.844727f, 0.855957f, 0.867188f, 0.877930f, 0.937012f, 0.930176f, 0.922852f, 0.916504f, 0.910645f, 0.904785f,
+ 0.005486f, 0.016525f, 0.028030f, 0.039612f, 0.052185f, 0.064636f, 0.077576f, 0.091553f, 0.105347f, 0.119568f, 0.134521f, 0.149536f,
+ 0.164917f, 0.180664f, 0.197388f, 0.213623f, 0.230347f, 0.246826f, 0.264160f, 0.280518f, 0.298584f, 0.315674f, 0.334229f, 0.350830f,
+ 0.369141f, 0.386963f, 0.404053f, 0.422119f, 0.438477f, 0.456299f, 0.474121f, 0.491211f, 0.507812f, 0.524902f, 0.541504f, 0.557617f,
+ 0.574707f, 0.590820f, 0.606934f, 0.622559f, 0.637207f, 0.652832f, 0.668945f, 0.683105f, 0.698730f, 0.711914f, 0.726074f, 0.740723f,
+ 0.753906f, 0.766602f, 0.780273f, 0.792969f, 0.805664f, 0.818848f, 0.830566f, 0.842285f, 0.854492f, 0.866211f, 0.931641f, 0.925781f,
+ 0.918945f, 0.913086f, 0.907227f, 0.900879f, 0.004810f, 0.014847f, 0.025604f, 0.036621f, 0.047577f, 0.059174f, 0.071472f, 0.084106f,
+ 0.096985f, 0.109863f, 0.124146f, 0.137939f, 0.152954f, 0.167358f, 0.182495f, 0.197754f, 0.213745f, 0.230103f, 0.246216f, 0.262939f,
+ 0.279297f, 0.296387f, 0.313477f, 0.329834f, 0.348145f, 0.365479f, 0.382080f, 0.399658f, 0.417480f, 0.434082f, 0.452148f, 0.469238f,
+ 0.486084f, 0.502441f, 0.520020f, 0.536621f, 0.552734f, 0.569336f, 0.585938f, 0.601562f, 0.617676f, 0.632812f, 0.648438f, 0.664062f,
+ 0.679688f, 0.693848f, 0.708008f, 0.722656f, 0.735840f, 0.750488f, 0.765137f, 0.777832f, 0.791016f, 0.803711f, 0.816895f, 0.829102f,
+ 0.841309f, 0.853027f, 0.925781f, 0.921387f, 0.914551f, 0.908203f, 0.903320f, 0.897461f, 0.004494f, 0.013809f, 0.023331f, 0.033264f,
+ 0.043549f, 0.053833f, 0.065369f, 0.076660f, 0.088684f, 0.100708f, 0.113464f, 0.127075f, 0.140381f, 0.154419f, 0.169067f, 0.183472f,
+ 0.198975f, 0.213623f, 0.229370f, 0.245117f, 0.261475f, 0.277832f, 0.294678f, 0.311523f, 0.327148f, 0.344727f, 0.362061f, 0.378418f,
+ 0.395996f, 0.413086f, 0.430176f, 0.447021f, 0.464111f, 0.481689f, 0.498047f, 0.514648f, 0.531738f, 0.547363f, 0.565430f, 0.582031f,
+ 0.597656f, 0.612793f, 0.628418f, 0.644043f, 0.660645f, 0.674805f, 0.689941f, 0.705078f, 0.718750f, 0.734375f, 0.747559f, 0.761719f,
+ 0.775391f, 0.788086f, 0.803223f, 0.814453f, 0.828125f, 0.840332f, 0.919434f, 0.916504f, 0.909668f, 0.904785f, 0.898926f, 0.894043f,
+ 0.004120f, 0.012512f, 0.021423f, 0.030655f, 0.039673f, 0.049500f, 0.059845f, 0.070374f, 0.081543f, 0.093323f, 0.104614f, 0.116577f,
+ 0.129395f, 0.142456f, 0.156250f, 0.169434f, 0.183594f, 0.198364f, 0.213257f, 0.228638f, 0.244141f, 0.259766f, 0.275635f, 0.291748f,
+ 0.308105f, 0.324707f, 0.341309f, 0.359131f, 0.375244f, 0.391846f, 0.408447f, 0.426025f, 0.442871f, 0.459473f, 0.477051f, 0.494141f,
+ 0.510254f, 0.527344f, 0.543457f, 0.560059f, 0.577148f, 0.592773f, 0.608887f, 0.625977f, 0.640625f, 0.656738f, 0.671875f, 0.686523f,
+ 0.702637f, 0.716797f, 0.731445f, 0.746582f, 0.759277f, 0.773926f, 0.787598f, 0.800293f, 0.814453f, 0.827148f, 0.914062f, 0.911133f,
+ 0.905273f, 0.899902f, 0.895508f, 0.890625f, 0.004120f, 0.011566f, 0.019180f, 0.027969f, 0.036255f, 0.045746f, 0.054901f, 0.064941f,
+ 0.074707f, 0.085327f, 0.096436f, 0.107239f, 0.119324f, 0.131470f, 0.144165f, 0.157104f, 0.169922f, 0.183594f, 0.198242f, 0.212769f,
+ 0.227295f, 0.242188f, 0.257568f, 0.273193f, 0.289307f, 0.305420f, 0.321289f, 0.337891f, 0.354492f, 0.371094f, 0.387451f, 0.405029f,
+ 0.421143f, 0.438477f, 0.455322f, 0.472656f, 0.488525f, 0.505859f, 0.521973f, 0.539551f, 0.555664f, 0.572754f, 0.588867f, 0.605469f,
+ 0.621582f, 0.637207f, 0.653320f, 0.668945f, 0.684570f, 0.698242f, 0.714844f, 0.729492f, 0.745117f, 0.758301f, 0.771973f, 0.787109f,
+ 0.800781f, 0.813477f, 0.907715f, 0.905762f, 0.900879f, 0.895508f, 0.890625f, 0.886719f, 0.003464f, 0.010536f, 0.018143f, 0.025604f,
+ 0.033600f, 0.041992f, 0.050659f, 0.059631f, 0.068481f, 0.078552f, 0.088196f, 0.099060f, 0.110107f, 0.121033f, 0.133057f, 0.145020f,
+ 0.157349f, 0.170166f, 0.183838f, 0.197632f, 0.210938f, 0.225464f, 0.241089f, 0.255371f, 0.270508f, 0.286377f, 0.302246f, 0.317871f,
+ 0.334229f, 0.349854f, 0.367188f, 0.383789f, 0.399414f, 0.417236f, 0.433838f, 0.450928f, 0.468018f, 0.484131f, 0.501465f, 0.519043f,
+ 0.535156f, 0.551758f, 0.568359f, 0.585449f, 0.601074f, 0.617676f, 0.634277f, 0.649902f, 0.666016f, 0.681152f, 0.695801f, 0.711914f,
+ 0.727539f, 0.741699f, 0.756836f, 0.770508f, 0.785645f, 0.800293f, 0.901855f, 0.900391f, 0.895996f, 0.891113f, 0.886230f, 0.881836f,
+ 0.003197f, 0.009903f, 0.016525f, 0.023849f, 0.030853f, 0.038605f, 0.046265f, 0.054657f, 0.063232f, 0.072266f, 0.081543f, 0.090881f,
+ 0.100769f, 0.112061f, 0.123047f, 0.134155f, 0.145752f, 0.157471f, 0.170166f, 0.182861f, 0.196289f, 0.210327f, 0.223755f, 0.238525f,
+ 0.253418f, 0.268066f, 0.283203f, 0.299316f, 0.314697f, 0.330811f, 0.346680f, 0.363281f, 0.379639f, 0.396484f, 0.412842f, 0.429443f,
+ 0.446289f, 0.462891f, 0.480225f, 0.497559f, 0.514648f, 0.531250f, 0.547852f, 0.564453f, 0.581055f, 0.598145f, 0.615234f, 0.631836f,
+ 0.646484f, 0.663086f, 0.679199f, 0.694824f, 0.710449f, 0.726074f, 0.740234f, 0.755859f, 0.770508f, 0.784668f, 0.895020f, 0.894531f,
+ 0.890625f, 0.886719f, 0.881836f, 0.877441f, 0.003071f, 0.009163f, 0.015602f, 0.021729f, 0.028412f, 0.035522f, 0.042755f, 0.050598f,
+ 0.057983f, 0.066284f, 0.075317f, 0.083862f, 0.092773f, 0.102905f, 0.113342f, 0.123840f, 0.134399f, 0.145752f, 0.157593f, 0.169556f,
+ 0.182129f, 0.194702f, 0.207886f, 0.222046f, 0.235840f, 0.250977f, 0.265137f, 0.280273f, 0.295898f, 0.311279f, 0.326660f, 0.342773f,
+ 0.359375f, 0.375732f, 0.392090f, 0.409180f, 0.425049f, 0.441895f, 0.459473f, 0.476318f, 0.493652f, 0.510742f, 0.527344f, 0.544434f,
+ 0.561035f, 0.578125f, 0.595215f, 0.611328f, 0.628418f, 0.645020f, 0.661133f, 0.677246f, 0.693359f, 0.708496f, 0.724609f, 0.740723f,
+ 0.755859f, 0.771484f, 0.889160f, 0.889160f, 0.885254f, 0.881348f, 0.876953f, 0.873047f, 0.002748f, 0.008171f, 0.014084f, 0.019638f,
+ 0.026108f, 0.032318f, 0.039154f, 0.045990f, 0.053619f, 0.061066f, 0.068665f, 0.076477f, 0.085632f, 0.094727f, 0.104187f, 0.113831f,
+ 0.123535f, 0.134888f, 0.145508f, 0.157104f, 0.168701f, 0.181030f, 0.193481f, 0.206665f, 0.220093f, 0.233398f, 0.248169f, 0.262695f,
+ 0.277344f, 0.292236f, 0.307617f, 0.322998f, 0.339355f, 0.355469f, 0.371582f, 0.388184f, 0.404541f, 0.420410f, 0.438477f, 0.455322f,
+ 0.472656f, 0.489014f, 0.506348f, 0.523926f, 0.541016f, 0.557617f, 0.575195f, 0.591309f, 0.608887f, 0.625977f, 0.643555f, 0.659180f,
+ 0.674805f, 0.691406f, 0.707520f, 0.724121f, 0.739746f, 0.755371f, 0.882812f, 0.883789f, 0.879883f, 0.875977f, 0.872559f, 0.868652f,
+ 0.002491f, 0.007809f, 0.012764f, 0.018448f, 0.024094f, 0.029861f, 0.036102f, 0.042572f, 0.049500f, 0.056091f, 0.063293f, 0.070984f,
+ 0.079285f, 0.087036f, 0.095825f, 0.104858f, 0.114441f, 0.124084f, 0.133789f, 0.144653f, 0.156250f, 0.167480f, 0.179199f, 0.191650f,
+ 0.204102f, 0.217896f, 0.231445f, 0.245239f, 0.259521f, 0.274170f, 0.289307f, 0.304199f, 0.319580f, 0.334961f, 0.351074f, 0.367676f,
+ 0.384277f, 0.400635f, 0.417480f, 0.434570f, 0.451660f, 0.468994f, 0.485352f, 0.502441f, 0.520508f, 0.537109f, 0.554688f, 0.571777f,
+ 0.588867f, 0.605957f, 0.623047f, 0.639648f, 0.656738f, 0.673828f, 0.690430f, 0.708008f, 0.723633f, 0.739746f, 0.874023f, 0.876953f,
+ 0.874023f, 0.871582f, 0.867188f, 0.862793f, 0.002279f, 0.007130f, 0.012291f, 0.016922f, 0.022171f, 0.027847f, 0.033325f, 0.039185f,
+ 0.045349f, 0.051849f, 0.058411f, 0.064880f, 0.072144f, 0.080017f, 0.087891f, 0.096313f, 0.105103f, 0.114197f, 0.123779f, 0.134155f,
+ 0.144043f, 0.155151f, 0.166016f, 0.177246f, 0.189697f, 0.202271f, 0.214722f, 0.228271f, 0.242310f, 0.256592f, 0.270752f, 0.285400f,
+ 0.300537f, 0.315674f, 0.331543f, 0.347656f, 0.363525f, 0.379639f, 0.396729f, 0.414307f, 0.430908f, 0.447754f, 0.465088f, 0.482178f,
+ 0.499512f, 0.517090f, 0.533203f, 0.552246f, 0.568848f, 0.586426f, 0.603516f, 0.621582f, 0.639648f, 0.656250f, 0.673828f, 0.690918f,
+ 0.707520f, 0.724121f, 0.867676f, 0.870605f, 0.868164f, 0.865723f, 0.861328f, 0.857910f, 0.002220f, 0.006565f, 0.011238f, 0.015961f,
+ 0.020401f, 0.025558f, 0.030853f, 0.036133f, 0.041199f, 0.047180f, 0.053436f, 0.059723f, 0.066162f, 0.073853f, 0.080688f, 0.088440f,
+ 0.096436f, 0.105042f, 0.114319f, 0.123047f, 0.132446f, 0.142822f, 0.153198f, 0.164062f, 0.175659f, 0.187378f, 0.199463f, 0.212402f,
+ 0.225464f, 0.239014f, 0.252686f, 0.266846f, 0.281494f, 0.296631f, 0.312500f, 0.328369f, 0.343750f, 0.359863f, 0.376221f, 0.393066f,
+ 0.409668f, 0.426514f, 0.444336f, 0.461670f, 0.478760f, 0.496826f, 0.513672f, 0.532227f, 0.549316f, 0.567383f, 0.584961f, 0.602051f,
+ 0.620605f, 0.637207f, 0.655273f, 0.672363f, 0.689941f, 0.708008f, 0.860840f, 0.864746f, 0.862793f, 0.859375f, 0.855957f, 0.853027f,
+ 0.002190f, 0.005993f, 0.010117f, 0.014420f, 0.018738f, 0.023361f, 0.028015f, 0.033142f, 0.037781f, 0.043732f, 0.048920f, 0.054840f,
+ 0.061218f, 0.067810f, 0.074219f, 0.081299f, 0.088562f, 0.096130f, 0.104614f, 0.113098f, 0.122253f, 0.131714f, 0.141113f, 0.151245f,
+ 0.162109f, 0.173462f, 0.184692f, 0.196899f, 0.209473f, 0.222534f, 0.236206f, 0.249634f, 0.263672f, 0.277588f, 0.293213f, 0.308350f,
+ 0.323975f, 0.339844f, 0.355957f, 0.372070f, 0.389404f, 0.405762f, 0.422852f, 0.439941f, 0.458008f, 0.475098f, 0.492920f, 0.510742f,
+ 0.528320f, 0.546875f, 0.564453f, 0.583496f, 0.601074f, 0.619141f, 0.636719f, 0.654785f, 0.672852f, 0.691406f, 0.852539f, 0.858398f,
+ 0.856445f, 0.853516f, 0.850586f, 0.847656f, 0.001787f, 0.005753f, 0.009300f, 0.013611f, 0.017410f, 0.021576f, 0.025665f, 0.030533f,
+ 0.035126f, 0.040039f, 0.044952f, 0.050446f, 0.055817f, 0.061890f, 0.068054f, 0.074707f, 0.081482f, 0.088501f, 0.095764f, 0.103943f,
+ 0.112183f, 0.120850f, 0.130249f, 0.139526f, 0.149658f, 0.160400f, 0.171021f, 0.182007f, 0.194336f, 0.206421f, 0.219360f, 0.232666f,
+ 0.245850f, 0.260010f, 0.274170f, 0.289307f, 0.304443f, 0.319580f, 0.335693f, 0.352295f, 0.369141f, 0.385498f, 0.402344f, 0.419189f,
+ 0.437012f, 0.454346f, 0.472412f, 0.490234f, 0.507812f, 0.525879f, 0.545410f, 0.562500f, 0.581055f, 0.600098f, 0.618164f, 0.636719f,
+ 0.655273f, 0.674316f, 0.845703f, 0.852051f, 0.849609f, 0.847168f, 0.845215f, 0.841309f, 0.001766f, 0.005241f, 0.008881f, 0.012024f,
+ 0.016129f, 0.020233f, 0.024124f, 0.027664f, 0.032135f, 0.036835f, 0.041321f, 0.046173f, 0.051392f, 0.056946f, 0.062225f, 0.068604f,
+ 0.074524f, 0.080933f, 0.088135f, 0.095398f, 0.103210f, 0.110779f, 0.119263f, 0.128296f, 0.137695f, 0.147217f, 0.157349f, 0.168091f,
+ 0.179688f, 0.191284f, 0.203613f, 0.215942f, 0.228882f, 0.242554f, 0.255859f, 0.270508f, 0.285400f, 0.300537f, 0.316406f, 0.331787f,
+ 0.348877f, 0.364746f, 0.382080f, 0.398682f, 0.415771f, 0.434082f, 0.451416f, 0.469482f, 0.487793f, 0.505859f, 0.524414f, 0.542969f,
+ 0.562012f, 0.580566f, 0.598145f, 0.618652f, 0.637695f, 0.657227f, 0.837891f, 0.844727f, 0.843750f, 0.841309f, 0.838379f, 0.836426f,
+ 0.001598f, 0.004887f, 0.008217f, 0.011497f, 0.014786f, 0.018326f, 0.021652f, 0.025513f, 0.029541f, 0.033813f, 0.038086f, 0.042236f,
+ 0.046844f, 0.052032f, 0.057251f, 0.062622f, 0.068237f, 0.074280f, 0.080505f, 0.086975f, 0.094116f, 0.101074f, 0.109314f, 0.117554f,
+ 0.126587f, 0.135254f, 0.144775f, 0.155029f, 0.165405f, 0.176392f, 0.187744f, 0.199829f, 0.212646f, 0.224976f, 0.238647f, 0.252441f,
+ 0.267090f, 0.281738f, 0.296631f, 0.312256f, 0.328369f, 0.344971f, 0.361328f, 0.377686f, 0.395264f, 0.412842f, 0.430908f, 0.448730f,
+ 0.467041f, 0.485596f, 0.503906f, 0.522461f, 0.541504f, 0.561523f, 0.580078f, 0.599121f, 0.618164f, 0.639648f, 0.828613f, 0.837891f,
+ 0.836914f, 0.834473f, 0.833008f, 0.830566f, 0.001709f, 0.004494f, 0.007416f, 0.010628f, 0.013680f, 0.016785f, 0.020203f, 0.023712f,
+ 0.027435f, 0.031006f, 0.034424f, 0.038635f, 0.043182f, 0.047668f, 0.052307f, 0.057159f, 0.062042f, 0.067749f, 0.073730f, 0.079956f,
+ 0.086182f, 0.092773f, 0.100159f, 0.107727f, 0.115479f, 0.123962f, 0.132935f, 0.142578f, 0.151978f, 0.162476f, 0.173340f, 0.184570f,
+ 0.196411f, 0.208740f, 0.221436f, 0.235229f, 0.248779f, 0.262939f, 0.277832f, 0.293213f, 0.308105f, 0.324219f, 0.341309f, 0.357178f,
+ 0.374756f, 0.391846f, 0.409424f, 0.427490f, 0.446533f, 0.464844f, 0.483643f, 0.501953f, 0.521484f, 0.541504f, 0.561035f, 0.579590f,
+ 0.599609f, 0.620605f, 0.821289f, 0.830566f, 0.830078f, 0.828125f, 0.825684f, 0.823242f, 0.001367f, 0.004105f, 0.007023f, 0.009552f,
+ 0.012611f, 0.015289f, 0.018341f, 0.021652f, 0.024857f, 0.027878f, 0.031769f, 0.035614f, 0.039276f, 0.043610f, 0.047333f, 0.052155f,
+ 0.056549f, 0.061401f, 0.066895f, 0.072449f, 0.078613f, 0.084778f, 0.091309f, 0.098083f, 0.105774f, 0.113281f, 0.121399f, 0.130371f,
+ 0.139648f, 0.148926f, 0.159546f, 0.169922f, 0.180908f, 0.192749f, 0.204834f, 0.217651f, 0.231567f, 0.244385f, 0.259277f, 0.273926f,
+ 0.289307f, 0.304688f, 0.320557f, 0.336914f, 0.354248f, 0.371338f, 0.388184f, 0.406982f, 0.424316f, 0.443115f, 0.462646f, 0.481445f,
+ 0.501465f, 0.520508f, 0.541016f, 0.559570f, 0.580078f, 0.601074f, 0.812988f, 0.823242f, 0.823242f, 0.821289f, 0.819824f, 0.817383f,
+ 0.001398f, 0.003883f, 0.006351f, 0.008911f, 0.011559f, 0.014343f, 0.017212f, 0.020035f, 0.022797f, 0.026062f, 0.028793f, 0.031891f,
+ 0.035858f, 0.039368f, 0.043213f, 0.047607f, 0.051483f, 0.056030f, 0.060883f, 0.065979f, 0.071350f, 0.076843f, 0.083130f, 0.089172f,
+ 0.096069f, 0.103333f, 0.111023f, 0.119019f, 0.127319f, 0.136719f, 0.145996f, 0.156128f, 0.166138f, 0.177368f, 0.189453f, 0.201416f,
+ 0.213745f, 0.227295f, 0.240601f, 0.255371f, 0.269287f, 0.285400f, 0.301270f, 0.317139f, 0.333740f, 0.350586f, 0.367920f, 0.385986f,
+ 0.404297f, 0.422852f, 0.442383f, 0.460938f, 0.479980f, 0.500488f, 0.520508f, 0.541016f, 0.560547f, 0.582520f, 0.803711f, 0.814941f,
+ 0.815430f, 0.814453f, 0.812500f, 0.810547f, 0.001259f, 0.003464f, 0.006332f, 0.008286f, 0.010384f, 0.013000f, 0.015587f, 0.018234f,
+ 0.021027f, 0.023422f, 0.026566f, 0.029480f, 0.032379f, 0.035919f, 0.039215f, 0.043060f, 0.046997f, 0.050995f, 0.055267f, 0.059998f,
+ 0.065002f, 0.069946f, 0.075317f, 0.081299f, 0.087280f, 0.094116f, 0.101135f, 0.108276f, 0.116150f, 0.124695f, 0.133545f, 0.142700f,
+ 0.152222f, 0.162720f, 0.173950f, 0.185303f, 0.197754f, 0.210205f, 0.223022f, 0.237061f, 0.250732f, 0.265869f, 0.281250f, 0.297119f,
+ 0.313477f, 0.330322f, 0.347656f, 0.364746f, 0.383301f, 0.401367f, 0.420898f, 0.440186f, 0.459229f, 0.479736f, 0.499512f, 0.520996f,
+ 0.541016f, 0.562988f, 0.794434f, 0.807129f, 0.807617f, 0.807129f, 0.805176f, 0.803711f, 0.001070f, 0.003237f, 0.005432f, 0.007359f,
+ 0.009857f, 0.012337f, 0.014191f, 0.016586f, 0.019257f, 0.021561f, 0.024094f, 0.026901f, 0.029724f, 0.032745f, 0.035675f, 0.039368f,
+ 0.042572f, 0.045990f, 0.050354f, 0.054535f, 0.058746f, 0.063232f, 0.068420f, 0.073608f, 0.079529f, 0.085266f, 0.091370f, 0.098083f,
+ 0.105835f, 0.113159f, 0.121094f, 0.129639f, 0.139038f, 0.148926f, 0.159058f, 0.169678f, 0.181274f, 0.193481f, 0.205811f, 0.219482f,
+ 0.233032f, 0.247192f, 0.262207f, 0.277100f, 0.293213f, 0.309814f, 0.326660f, 0.344238f, 0.361816f, 0.380615f, 0.398926f, 0.418945f,
+ 0.438477f, 0.458008f, 0.479004f, 0.499512f, 0.520996f, 0.543945f, 0.784668f, 0.798828f, 0.800293f, 0.799805f, 0.797852f, 0.796875f,
+ 0.001074f, 0.002916f, 0.004955f, 0.007149f, 0.009033f, 0.011055f, 0.013268f, 0.015495f, 0.017365f, 0.019485f, 0.022095f, 0.024002f,
+ 0.026688f, 0.029633f, 0.032593f, 0.035370f, 0.038361f, 0.041870f, 0.045319f, 0.049225f, 0.052948f, 0.057068f, 0.061676f, 0.066345f,
+ 0.071167f, 0.076782f, 0.082581f, 0.088867f, 0.095886f, 0.102539f, 0.109802f, 0.118042f, 0.126709f, 0.135132f, 0.144897f, 0.155151f,
+ 0.165771f, 0.177368f, 0.189209f, 0.201904f, 0.215210f, 0.229370f, 0.242798f, 0.258057f, 0.274170f, 0.290039f, 0.306885f, 0.323242f,
+ 0.341309f, 0.359375f, 0.378418f, 0.397461f, 0.416260f, 0.437500f, 0.457031f, 0.479004f, 0.501465f, 0.522461f, 0.775391f, 0.790527f,
+ 0.791992f, 0.791504f, 0.791016f, 0.789551f, 0.000837f, 0.002916f, 0.004738f, 0.006477f, 0.008575f, 0.010170f, 0.012161f, 0.014023f,
+ 0.015808f, 0.017792f, 0.020111f, 0.022064f, 0.024414f, 0.026794f, 0.029251f, 0.032074f, 0.034698f, 0.037598f, 0.040741f, 0.043915f,
+ 0.047577f, 0.051361f, 0.055389f, 0.059692f, 0.064209f, 0.068787f, 0.074585f, 0.079712f, 0.085632f, 0.092346f, 0.099487f, 0.106323f,
+ 0.114929f, 0.122925f, 0.131958f, 0.141235f, 0.151123f, 0.161865f, 0.172974f, 0.184937f, 0.197632f, 0.210693f, 0.224854f, 0.239136f,
+ 0.254395f, 0.269531f, 0.285889f, 0.302979f, 0.320557f, 0.338623f, 0.356689f, 0.375977f, 0.395752f, 0.415527f, 0.436523f, 0.458252f,
+ 0.479248f, 0.501465f, 0.765137f, 0.781738f, 0.783691f, 0.784180f, 0.783203f, 0.781250f, 0.000854f, 0.002817f, 0.004089f, 0.005684f,
+ 0.007675f, 0.009277f, 0.010864f, 0.012413f, 0.014427f, 0.016235f, 0.017838f, 0.019913f, 0.021805f, 0.023987f, 0.026276f, 0.028915f,
+ 0.030960f, 0.033875f, 0.036652f, 0.039551f, 0.042816f, 0.045837f, 0.049591f, 0.053589f, 0.057526f, 0.061829f, 0.066650f, 0.071655f,
+ 0.077393f, 0.083008f, 0.088989f, 0.096008f, 0.103210f, 0.110657f, 0.119141f, 0.127930f, 0.137085f, 0.146973f, 0.157593f, 0.169312f,
+ 0.181274f, 0.193481f, 0.207031f, 0.220581f, 0.235229f, 0.250732f, 0.266357f, 0.282227f, 0.299805f, 0.317627f, 0.335449f, 0.354736f,
+ 0.374268f, 0.394531f, 0.415527f, 0.436279f, 0.458252f, 0.481689f, 0.754883f, 0.773438f, 0.775391f, 0.775879f, 0.774902f, 0.773926f,
+ 0.000852f, 0.002520f, 0.003937f, 0.005527f, 0.006836f, 0.008408f, 0.009773f, 0.011620f, 0.013039f, 0.014687f, 0.016327f, 0.017944f,
+ 0.019760f, 0.021774f, 0.023697f, 0.025894f, 0.027969f, 0.030121f, 0.032501f, 0.035370f, 0.038208f, 0.041046f, 0.044098f, 0.047791f,
+ 0.051453f, 0.055176f, 0.059570f, 0.064026f, 0.068787f, 0.074158f, 0.079834f, 0.085938f, 0.092590f, 0.099304f, 0.106873f, 0.114990f,
+ 0.124023f, 0.133301f, 0.143066f, 0.153687f, 0.164551f, 0.176392f, 0.189209f, 0.202637f, 0.216553f, 0.231323f, 0.246704f, 0.262451f,
+ 0.279297f, 0.296387f, 0.314697f, 0.333496f, 0.353516f, 0.373047f, 0.394775f, 0.415039f, 0.437500f, 0.460449f, 0.745117f, 0.763672f,
+ 0.766602f, 0.767090f, 0.767090f, 0.765625f, 0.000762f, 0.002342f, 0.003563f, 0.004787f, 0.006447f, 0.007648f, 0.009193f, 0.010353f,
+ 0.012016f, 0.013138f, 0.014557f, 0.016312f, 0.017929f, 0.019470f, 0.021103f, 0.023056f, 0.024918f, 0.026886f, 0.029099f, 0.031586f,
+ 0.034058f, 0.036499f, 0.039307f, 0.042450f, 0.045685f, 0.049072f, 0.052826f, 0.056915f, 0.061096f, 0.065918f, 0.070984f, 0.076538f,
+ 0.082520f, 0.088928f, 0.095520f, 0.102905f, 0.111206f, 0.119629f, 0.128662f, 0.138184f, 0.148682f, 0.160156f, 0.171997f, 0.184937f,
+ 0.198364f, 0.212524f, 0.227173f, 0.243042f, 0.259277f, 0.276611f, 0.294189f, 0.312500f, 0.331055f, 0.350830f, 0.372070f, 0.392334f,
+ 0.415771f, 0.438232f, 0.734375f, 0.754395f, 0.758789f, 0.758789f, 0.758789f, 0.757812f, 0.000848f, 0.002024f, 0.003553f, 0.004646f,
+ 0.005726f, 0.007050f, 0.008362f, 0.009438f, 0.010536f, 0.011810f, 0.013123f, 0.014481f, 0.015778f, 0.017242f, 0.018753f, 0.020447f,
+ 0.022278f, 0.023819f, 0.025940f, 0.027771f, 0.029999f, 0.032410f, 0.034851f, 0.037354f, 0.040375f, 0.043610f, 0.046631f, 0.050354f,
+ 0.054108f, 0.058563f, 0.062805f, 0.067871f, 0.073242f, 0.078796f, 0.085083f, 0.091797f, 0.098816f, 0.106689f, 0.115540f, 0.124207f,
+ 0.134155f, 0.144409f, 0.155762f, 0.167725f, 0.180664f, 0.193848f, 0.208618f, 0.223389f, 0.239746f, 0.256104f, 0.273438f, 0.291260f,
+ 0.310059f, 0.330078f, 0.349854f, 0.370850f, 0.393555f, 0.416992f, 0.724121f, 0.744629f, 0.748535f, 0.750000f, 0.749512f, 0.749512f,
+ 0.000736f, 0.001780f, 0.002937f, 0.004314f, 0.005211f, 0.006214f, 0.007423f, 0.008537f, 0.009392f, 0.010773f, 0.011726f, 0.012970f,
+ 0.014183f, 0.015373f, 0.016724f, 0.017990f, 0.019730f, 0.021194f, 0.022644f, 0.024368f, 0.026443f, 0.028610f, 0.030685f, 0.032898f,
+ 0.035583f, 0.038300f, 0.041351f, 0.044556f, 0.047638f, 0.051422f, 0.055359f, 0.059875f, 0.064392f, 0.069580f, 0.075195f, 0.080872f,
+ 0.087646f, 0.094849f, 0.102173f, 0.110596f, 0.119690f, 0.129761f, 0.139893f, 0.151367f, 0.163452f, 0.176147f, 0.190063f, 0.204590f,
+ 0.219238f, 0.235718f, 0.252441f, 0.270264f, 0.289062f, 0.307861f, 0.328613f, 0.350098f, 0.372314f, 0.395020f, 0.712402f, 0.734863f,
+ 0.739746f, 0.740723f, 0.740723f, 0.740234f, 0.000589f, 0.001616f, 0.002674f, 0.003841f, 0.004940f, 0.005676f, 0.006554f, 0.007442f,
+ 0.008812f, 0.009537f, 0.010277f, 0.011528f, 0.012634f, 0.013527f, 0.014671f, 0.016037f, 0.017136f, 0.018631f, 0.019943f, 0.021530f,
+ 0.023071f, 0.025146f, 0.026825f, 0.029037f, 0.030853f, 0.033447f, 0.035736f, 0.038849f, 0.041656f, 0.044922f, 0.048462f, 0.052277f,
+ 0.056519f, 0.061127f, 0.065796f, 0.071411f, 0.077148f, 0.083435f, 0.090393f, 0.097900f, 0.106079f, 0.115356f, 0.125122f, 0.135132f,
+ 0.146729f, 0.158936f, 0.171509f, 0.185059f, 0.200439f, 0.215576f, 0.232056f, 0.249756f, 0.267822f, 0.286621f, 0.306885f, 0.328125f,
+ 0.349854f, 0.373291f, 0.701172f, 0.725586f, 0.729980f, 0.730957f, 0.731934f, 0.730957f, 0.000547f, 0.001666f, 0.002367f, 0.003559f,
+ 0.004238f, 0.005028f, 0.005852f, 0.006859f, 0.007755f, 0.008530f, 0.009163f, 0.010056f, 0.010956f, 0.011978f, 0.013062f, 0.014076f,
+ 0.015053f, 0.016251f, 0.017471f, 0.018921f, 0.020233f, 0.021774f, 0.023315f, 0.025162f, 0.026871f, 0.029007f, 0.031204f, 0.033661f,
+ 0.036102f, 0.039062f, 0.042053f, 0.045380f, 0.048859f, 0.053040f, 0.057343f, 0.062225f, 0.067261f, 0.073120f, 0.079407f, 0.086243f,
+ 0.093567f, 0.101868f, 0.110596f, 0.120239f, 0.130859f, 0.141968f, 0.154053f, 0.167358f, 0.181274f, 0.196045f, 0.212158f, 0.229248f,
+ 0.247192f, 0.265381f, 0.285400f, 0.305664f, 0.327637f, 0.350586f, 0.689453f, 0.715820f, 0.720215f, 0.722168f, 0.722168f, 0.722168f,
+ 0.000492f, 0.001634f, 0.002342f, 0.003111f, 0.003866f, 0.004574f, 0.005417f, 0.005928f, 0.006588f, 0.007393f, 0.008041f, 0.008873f,
+ 0.009689f, 0.010391f, 0.011375f, 0.012146f, 0.013100f, 0.014183f, 0.015274f, 0.016479f, 0.017456f, 0.018768f, 0.020157f, 0.021606f,
+ 0.023300f, 0.024933f, 0.026855f, 0.028885f, 0.031143f, 0.033417f, 0.036133f, 0.039032f, 0.042236f, 0.045776f, 0.049713f, 0.053680f,
+ 0.058228f, 0.063232f, 0.069092f, 0.074829f, 0.081482f, 0.089050f, 0.096924f, 0.105591f, 0.115417f, 0.126221f, 0.137329f, 0.149658f,
+ 0.162964f, 0.176880f, 0.192505f, 0.208740f, 0.226318f, 0.244873f, 0.263428f, 0.283936f, 0.306396f, 0.329346f, 0.676270f, 0.705078f,
+ 0.709961f, 0.711914f, 0.712891f, 0.711914f, 0.000506f, 0.001342f, 0.002157f, 0.002813f, 0.003353f, 0.004105f, 0.004658f, 0.005344f,
+ 0.005871f, 0.006538f, 0.007050f, 0.007751f, 0.008247f, 0.009109f, 0.009865f, 0.010559f, 0.011269f, 0.012169f, 0.013290f, 0.014191f,
+ 0.015015f, 0.016312f, 0.017395f, 0.018570f, 0.019989f, 0.021439f, 0.023102f, 0.024536f, 0.026535f, 0.028702f, 0.030899f, 0.033356f,
+ 0.035980f, 0.039093f, 0.042328f, 0.046051f, 0.049927f, 0.054199f, 0.059052f, 0.064575f, 0.070496f, 0.076782f, 0.084412f, 0.092285f,
+ 0.100708f, 0.110779f, 0.121399f, 0.132690f, 0.145508f, 0.158813f, 0.173584f, 0.189453f, 0.205688f, 0.223755f, 0.242554f, 0.263184f,
+ 0.284180f, 0.306641f, 0.664551f, 0.693848f, 0.699707f, 0.702148f, 0.702637f, 0.703125f, 0.000500f, 0.001122f, 0.001810f, 0.002363f,
+ 0.002987f, 0.003576f, 0.004158f, 0.004620f, 0.005032f, 0.005627f, 0.006161f, 0.006721f, 0.007179f, 0.007790f, 0.008385f, 0.009163f,
+ 0.009758f, 0.010536f, 0.011284f, 0.011986f, 0.012878f, 0.013710f, 0.014725f, 0.015823f, 0.016937f, 0.018326f, 0.019547f, 0.020874f,
+ 0.022522f, 0.024399f, 0.026077f, 0.028427f, 0.030609f, 0.032990f, 0.035736f, 0.038788f, 0.042236f, 0.045990f, 0.050354f, 0.054901f,
+ 0.059967f, 0.065918f, 0.072205f, 0.079468f, 0.087219f, 0.096252f, 0.105713f, 0.116272f, 0.128174f, 0.140747f, 0.154419f, 0.169556f,
+ 0.186279f, 0.203125f, 0.221313f, 0.240601f, 0.261719f, 0.284424f, 0.652344f, 0.683105f, 0.688965f, 0.691406f, 0.692383f, 0.693359f,
+ 0.000482f, 0.001184f, 0.001604f, 0.002171f, 0.002562f, 0.003029f, 0.003656f, 0.003941f, 0.004410f, 0.004948f, 0.005325f, 0.005577f,
+ 0.006157f, 0.006702f, 0.007172f, 0.007751f, 0.008331f, 0.008904f, 0.009514f, 0.010063f, 0.010925f, 0.011719f, 0.012306f, 0.013321f,
+ 0.014275f, 0.015465f, 0.016510f, 0.017593f, 0.018845f, 0.020401f, 0.022095f, 0.023682f, 0.025513f, 0.027679f, 0.029968f, 0.032593f,
+ 0.035461f, 0.038757f, 0.042175f, 0.046326f, 0.050873f, 0.055939f, 0.061462f, 0.067444f, 0.074402f, 0.082520f, 0.091125f, 0.100830f,
+ 0.111572f, 0.123413f, 0.136719f, 0.150513f, 0.165894f, 0.182251f, 0.200684f, 0.219727f, 0.240234f, 0.261963f, 0.640137f, 0.671387f,
+ 0.679199f, 0.680664f, 0.682617f, 0.683105f, 0.000501f, 0.000919f, 0.001424f, 0.001853f, 0.002266f, 0.002789f, 0.002998f, 0.003397f,
+ 0.003902f, 0.004192f, 0.004417f, 0.004974f, 0.005207f, 0.005676f, 0.006134f, 0.006527f, 0.007179f, 0.007465f, 0.008018f, 0.008537f,
+ 0.009178f, 0.009888f, 0.010544f, 0.011093f, 0.011986f, 0.012794f, 0.013664f, 0.014717f, 0.015747f, 0.016983f, 0.018127f, 0.019470f,
+ 0.021103f, 0.022919f, 0.024826f, 0.026962f, 0.029358f, 0.031769f, 0.035065f, 0.038239f, 0.042297f, 0.046570f, 0.051422f, 0.056671f,
+ 0.062805f, 0.069763f, 0.077698f, 0.086182f, 0.095825f, 0.106812f, 0.119080f, 0.132568f, 0.147217f, 0.162598f, 0.180176f, 0.198730f,
+ 0.218628f, 0.241211f, 0.627441f, 0.660156f, 0.668457f, 0.669922f, 0.672363f, 0.671875f, 0.000235f, 0.001120f, 0.001356f, 0.001651f,
+ 0.002117f, 0.002441f, 0.002678f, 0.002993f, 0.003244f, 0.003519f, 0.003876f, 0.004086f, 0.004505f, 0.004787f, 0.005085f, 0.005604f,
+ 0.005985f, 0.006271f, 0.006783f, 0.007145f, 0.007679f, 0.008217f, 0.008728f, 0.009277f, 0.009956f, 0.010605f, 0.011490f, 0.012062f,
+ 0.013084f, 0.013962f, 0.014984f, 0.016113f, 0.017395f, 0.018829f, 0.020416f, 0.022125f, 0.023972f, 0.025955f, 0.028625f, 0.031616f,
+ 0.034515f, 0.038147f, 0.042114f, 0.046783f, 0.052094f, 0.058075f, 0.065002f, 0.072510f, 0.081604f, 0.091125f, 0.102539f, 0.114807f,
+ 0.128662f, 0.143921f, 0.160034f, 0.178467f, 0.198364f, 0.218750f, 0.613281f, 0.648926f, 0.657227f, 0.659668f, 0.661621f, 0.661621f,
+ 0.000382f, 0.000704f, 0.001099f, 0.001557f, 0.001774f, 0.001976f, 0.002132f, 0.002575f, 0.002634f, 0.002916f, 0.003103f, 0.003494f,
+ 0.003754f, 0.003956f, 0.004269f, 0.004684f, 0.004902f, 0.005234f, 0.005569f, 0.005890f, 0.006416f, 0.006786f, 0.007160f, 0.007645f,
+ 0.008118f, 0.008781f, 0.009346f, 0.010025f, 0.010658f, 0.011475f, 0.012230f, 0.013016f, 0.014122f, 0.015251f, 0.016342f, 0.017807f,
+ 0.019424f, 0.021103f, 0.023026f, 0.025436f, 0.027817f, 0.030914f, 0.034210f, 0.037750f, 0.042450f, 0.047455f, 0.053101f, 0.059998f,
+ 0.067688f, 0.076660f, 0.086670f, 0.097961f, 0.110779f, 0.125366f, 0.140747f, 0.158081f, 0.176880f, 0.197632f, 0.600098f, 0.637207f,
+ 0.644531f, 0.647949f, 0.649414f, 0.651855f, 0.000182f, 0.000738f, 0.000942f, 0.001220f, 0.001469f, 0.001634f, 0.001820f, 0.002005f,
+ 0.002291f, 0.002441f, 0.002636f, 0.002832f, 0.003019f, 0.003242f, 0.003502f, 0.003824f, 0.004017f, 0.004333f, 0.004570f, 0.004883f,
+ 0.005173f, 0.005615f, 0.005909f, 0.006317f, 0.006649f, 0.007160f, 0.007656f, 0.008156f, 0.008583f, 0.009209f, 0.009857f, 0.010696f,
+ 0.011322f, 0.012367f, 0.013229f, 0.014259f, 0.015686f, 0.016815f, 0.018402f, 0.020126f, 0.022095f, 0.024414f, 0.027176f, 0.030273f,
+ 0.033722f, 0.038086f, 0.042969f, 0.048645f, 0.055237f, 0.063171f, 0.071960f, 0.082031f, 0.093994f, 0.107300f, 0.122131f, 0.138550f,
+ 0.156494f, 0.177002f, 0.586426f, 0.625488f, 0.633789f, 0.637207f, 0.638672f, 0.639648f, 0.000199f, 0.000534f, 0.000745f, 0.000995f,
+ 0.001190f, 0.001387f, 0.001516f, 0.001691f, 0.001790f, 0.001941f, 0.002214f, 0.002346f, 0.002449f, 0.002686f, 0.002832f, 0.003042f,
+ 0.003304f, 0.003531f, 0.003662f, 0.003952f, 0.004181f, 0.004517f, 0.004704f, 0.005074f, 0.005352f, 0.005718f, 0.006096f, 0.006481f,
+ 0.006947f, 0.007454f, 0.007988f, 0.008484f, 0.009140f, 0.009804f, 0.010475f, 0.011307f, 0.012299f, 0.013268f, 0.014511f, 0.015823f,
+ 0.017410f, 0.018936f, 0.021225f, 0.023621f, 0.026367f, 0.029770f, 0.033661f, 0.038452f, 0.044067f, 0.050812f, 0.058411f, 0.067444f,
+ 0.077942f, 0.090149f, 0.104187f, 0.119812f, 0.137085f, 0.156372f, 0.572754f, 0.613770f, 0.621582f, 0.625977f, 0.627441f, 0.628906f,
+ 0.000165f, 0.000486f, 0.000618f, 0.000880f, 0.001063f, 0.001140f, 0.001258f, 0.001464f, 0.001498f, 0.001561f, 0.001707f, 0.001899f,
+ 0.001976f, 0.002171f, 0.002285f, 0.002474f, 0.002571f, 0.002764f, 0.002968f, 0.003170f, 0.003389f, 0.003580f, 0.003822f, 0.004036f,
+ 0.004269f, 0.004505f, 0.004738f, 0.005157f, 0.005474f, 0.005821f, 0.006279f, 0.006649f, 0.007107f, 0.007610f, 0.008240f, 0.008835f,
+ 0.009598f, 0.010361f, 0.011276f, 0.012299f, 0.013466f, 0.014740f, 0.016251f, 0.018021f, 0.020294f, 0.022797f, 0.025833f, 0.029739f,
+ 0.034058f, 0.039612f, 0.046021f, 0.053833f, 0.063110f, 0.074158f, 0.086914f, 0.101562f, 0.118164f, 0.136841f, 0.558594f, 0.601074f,
+ 0.608887f, 0.613281f, 0.615234f, 0.617188f, 0.000096f, 0.000348f, 0.000585f, 0.000707f, 0.000837f, 0.000866f, 0.000972f, 0.001095f,
+ 0.001198f, 0.001309f, 0.001355f, 0.001417f, 0.001615f, 0.001740f, 0.001863f, 0.001880f, 0.002048f, 0.002159f, 0.002380f, 0.002487f,
+ 0.002613f, 0.002777f, 0.003000f, 0.003143f, 0.003353f, 0.003521f, 0.003748f, 0.003963f, 0.004265f, 0.004490f, 0.004776f, 0.005093f,
+ 0.005577f, 0.005966f, 0.006321f, 0.006828f, 0.007320f, 0.007904f, 0.008575f, 0.009392f, 0.010231f, 0.011276f, 0.012321f, 0.013832f,
+ 0.015343f, 0.017242f, 0.019501f, 0.022247f, 0.025696f, 0.029922f, 0.035187f, 0.041779f, 0.049683f, 0.059387f, 0.070801f, 0.084106f,
+ 0.100037f, 0.117798f, 0.544434f, 0.588867f, 0.597656f, 0.602539f, 0.604492f, 0.605469f, 0.000123f, 0.000248f, 0.000443f, 0.000625f,
+ 0.000663f, 0.000733f, 0.000843f, 0.000780f, 0.000921f, 0.000986f, 0.001081f, 0.001178f, 0.001254f, 0.001348f, 0.001364f, 0.001515f,
+ 0.001565f, 0.001705f, 0.001824f, 0.001870f, 0.002066f, 0.002155f, 0.002274f, 0.002422f, 0.002525f, 0.002695f, 0.002863f, 0.003038f,
+ 0.003271f, 0.003441f, 0.003736f, 0.003901f, 0.004112f, 0.004478f, 0.004719f, 0.005093f, 0.005482f, 0.005913f, 0.006413f, 0.007019f,
+ 0.007626f, 0.008408f, 0.009201f, 0.010201f, 0.011436f, 0.012749f, 0.014389f, 0.016373f, 0.018906f, 0.022034f, 0.025909f, 0.031082f,
+ 0.037628f, 0.045715f, 0.055939f, 0.068176f, 0.082764f, 0.099365f, 0.529785f, 0.574707f, 0.584961f, 0.589844f, 0.591797f, 0.593750f,
+ 0.000210f, 0.000212f, 0.000365f, 0.000494f, 0.000438f, 0.000597f, 0.000538f, 0.000623f, 0.000638f, 0.000736f, 0.000866f, 0.000882f,
+ 0.000954f, 0.001040f, 0.001070f, 0.001086f, 0.001220f, 0.001274f, 0.001341f, 0.001457f, 0.001513f, 0.001598f, 0.001697f, 0.001781f,
+ 0.001898f, 0.001970f, 0.002131f, 0.002241f, 0.002401f, 0.002645f, 0.002783f, 0.002892f, 0.003120f, 0.003347f, 0.003508f, 0.003757f,
+ 0.004032f, 0.004314f, 0.004688f, 0.005066f, 0.005520f, 0.006012f, 0.006702f, 0.007332f, 0.008171f, 0.009140f, 0.010399f, 0.011787f,
+ 0.013496f, 0.015732f, 0.018509f, 0.022278f, 0.027267f, 0.033813f, 0.042328f, 0.053070f, 0.066406f, 0.082825f, 0.516602f, 0.562500f,
+ 0.573242f, 0.577637f, 0.580078f, 0.581543f, 0.000000f, 0.000216f, 0.000281f, 0.000346f, 0.000374f, 0.000388f, 0.000491f, 0.000416f,
+ 0.000516f, 0.000535f, 0.000635f, 0.000625f, 0.000681f, 0.000719f, 0.000790f, 0.000813f, 0.000879f, 0.000926f, 0.000968f, 0.001004f,
+ 0.001097f, 0.001135f, 0.001229f, 0.001300f, 0.001361f, 0.001431f, 0.001541f, 0.001610f, 0.001711f, 0.001802f, 0.001922f, 0.002094f,
+ 0.002169f, 0.002346f, 0.002468f, 0.002644f, 0.002844f, 0.003094f, 0.003368f, 0.003586f, 0.003883f, 0.004223f, 0.004662f, 0.005093f,
+ 0.005680f, 0.006348f, 0.007206f, 0.008202f, 0.009392f, 0.010895f, 0.012939f, 0.015465f, 0.018906f, 0.023682f, 0.030502f, 0.039825f,
+ 0.051331f, 0.066528f, 0.500977f, 0.548828f, 0.560059f, 0.564453f, 0.567871f, 0.569336f, 0.000000f, 0.000106f, 0.000201f, 0.000252f,
+ 0.000251f, 0.000322f, 0.000281f, 0.000340f, 0.000359f, 0.000428f, 0.000443f, 0.000419f, 0.000444f, 0.000500f, 0.000524f, 0.000590f,
+ 0.000574f, 0.000650f, 0.000693f, 0.000732f, 0.000778f, 0.000821f, 0.000848f, 0.000900f, 0.000965f, 0.000982f, 0.001072f, 0.001109f,
+ 0.001169f, 0.001307f, 0.001301f, 0.001409f, 0.001483f, 0.001610f, 0.001734f, 0.001835f, 0.001940f, 0.002098f, 0.002241f, 0.002426f,
+ 0.002634f, 0.002865f, 0.003136f, 0.003431f, 0.003763f, 0.004211f, 0.004742f, 0.005417f, 0.006229f, 0.007298f, 0.008621f, 0.010330f,
+ 0.012650f, 0.015808f, 0.020569f, 0.027908f, 0.037994f, 0.051514f, 0.485840f, 0.536133f, 0.547363f, 0.551758f, 0.554688f, 0.557617f,
+ 0.000026f, 0.000156f, 0.000201f, 0.000136f, 0.000188f, 0.000187f, 0.000192f, 0.000240f, 0.000245f, 0.000254f, 0.000262f, 0.000311f,
+ 0.000309f, 0.000331f, 0.000374f, 0.000385f, 0.000411f, 0.000431f, 0.000443f, 0.000461f, 0.000507f, 0.000522f, 0.000562f, 0.000596f,
+ 0.000634f, 0.000684f, 0.000718f, 0.000735f, 0.000776f, 0.000815f, 0.000875f, 0.000927f, 0.000982f, 0.001053f, 0.001123f, 0.001162f,
+ 0.001271f, 0.001346f, 0.001473f, 0.001577f, 0.001670f, 0.001838f, 0.002005f, 0.002161f, 0.002405f, 0.002670f, 0.002993f, 0.003399f,
+ 0.003860f, 0.004528f, 0.005386f, 0.006523f, 0.008003f, 0.010063f, 0.013206f, 0.017990f, 0.026031f, 0.038086f, 0.471191f, 0.522949f,
+ 0.534668f, 0.540039f, 0.543457f, 0.544922f, 0.000000f, 0.000093f, 0.000084f, 0.000085f, 0.000124f, 0.000145f, 0.000122f, 0.000149f,
+ 0.000152f, 0.000152f, 0.000158f, 0.000167f, 0.000186f, 0.000209f, 0.000217f, 0.000225f, 0.000231f, 0.000272f, 0.000273f, 0.000301f,
+ 0.000303f, 0.000310f, 0.000338f, 0.000361f, 0.000387f, 0.000423f, 0.000413f, 0.000436f, 0.000478f, 0.000503f, 0.000525f, 0.000570f,
+ 0.000608f, 0.000626f, 0.000677f, 0.000706f, 0.000753f, 0.000813f, 0.000884f, 0.000929f, 0.001000f, 0.001094f, 0.001183f, 0.001302f,
+ 0.001412f, 0.001563f, 0.001769f, 0.001974f, 0.002277f, 0.002626f, 0.003124f, 0.003761f, 0.004665f, 0.005993f, 0.007935f, 0.010818f,
+ 0.016205f, 0.026138f, 0.456299f, 0.509277f, 0.520996f, 0.527344f, 0.530762f, 0.532715f, 0.000105f, 0.000083f, 0.000072f, 0.000065f,
+ 0.000071f, 0.000072f, 0.000077f, 0.000084f, 0.000088f, 0.000093f, 0.000095f, 0.000120f, 0.000100f, 0.000108f, 0.000126f, 0.000118f,
+ 0.000139f, 0.000149f, 0.000153f, 0.000165f, 0.000169f, 0.000172f, 0.000194f, 0.000203f, 0.000233f, 0.000225f, 0.000233f, 0.000253f,
+ 0.000266f, 0.000275f, 0.000299f, 0.000319f, 0.000338f, 0.000345f, 0.000374f, 0.000384f, 0.000415f, 0.000448f, 0.000483f, 0.000511f,
+ 0.000543f, 0.000585f, 0.000647f, 0.000692f, 0.000755f, 0.000827f, 0.000924f, 0.001041f, 0.001186f, 0.001372f, 0.001608f, 0.001953f,
+ 0.002411f, 0.003098f, 0.004238f, 0.005989f, 0.009003f, 0.016006f, 0.441406f, 0.495361f, 0.508301f, 0.514160f, 0.518066f, 0.520508f,
+ 0.000090f, 0.000067f, 0.000058f, 0.000052f, 0.000047f, 0.000044f, 0.000044f, 0.000040f, 0.000042f, 0.000049f, 0.000042f, 0.000045f,
+ 0.000059f, 0.000047f, 0.000050f, 0.000054f, 0.000071f, 0.000073f, 0.000075f, 0.000078f, 0.000079f, 0.000084f, 0.000087f, 0.000090f,
+ 0.000097f, 0.000109f, 0.000108f, 0.000124f, 0.000124f, 0.000131f, 0.000138f, 0.000143f, 0.000155f, 0.000164f, 0.000178f, 0.000182f,
+ 0.000192f, 0.000209f, 0.000225f, 0.000244f, 0.000259f, 0.000274f, 0.000303f, 0.000321f, 0.000357f, 0.000385f, 0.000429f, 0.000470f,
+ 0.000537f, 0.000608f, 0.000710f, 0.000852f, 0.001052f, 0.001371f, 0.001877f, 0.002762f, 0.004406f, 0.008202f, 0.426270f, 0.483154f,
+ 0.495605f, 0.500977f, 0.505371f, 0.507324f, 0.000067f, 0.000047f, 0.000039f, 0.000035f, 0.000032f, 0.000030f, 0.000029f, 0.000027f,
+ 0.000026f, 0.000025f, 0.000024f, 0.000023f, 0.000021f, 0.000020f, 0.000019f, 0.000021f, 0.000020f, 0.000024f, 0.000028f, 0.000030f,
+ 0.000029f, 0.000032f, 0.000035f, 0.000034f, 0.000036f, 0.000044f, 0.000046f, 0.000040f, 0.000048f, 0.000047f, 0.000051f, 0.000053f,
+ 0.000059f, 0.000059f, 0.000064f, 0.000066f, 0.000077f, 0.000079f, 0.000081f, 0.000091f, 0.000094f, 0.000100f, 0.000108f, 0.000119f,
+ 0.000129f, 0.000137f, 0.000148f, 0.000173f, 0.000191f, 0.000210f, 0.000249f, 0.000292f, 0.000357f, 0.000448f, 0.000629f, 0.000943f,
+ 0.001630f, 0.003332f, 0.411377f, 0.468506f, 0.482910f, 0.488770f, 0.492188f, 0.495117f, 0.000025f, 0.000018f, 0.000015f, 0.000013f,
+ 0.000014f, 0.000013f, 0.000012f, 0.000012f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f,
+ 0.000011f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000008f, 0.000008f, 0.000008f, 0.000008f, 0.000007f,
+ 0.000008f, 0.000010f, 0.000010f, 0.000010f, 0.000012f, 0.000014f, 0.000014f, 0.000014f, 0.000016f, 0.000018f, 0.000019f, 0.000021f,
+ 0.000020f, 0.000023f, 0.000025f, 0.000027f, 0.000027f, 0.000029f, 0.000035f, 0.000033f, 0.000040f, 0.000044f, 0.000052f, 0.000061f,
+ 0.000069f, 0.000087f, 0.000117f, 0.000174f, 0.000319f, 0.000847f, 0.395996f, 0.454834f, 0.468750f, 0.475586f, 0.479004f, 0.481689f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000002f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000003f, 0.000004f, 0.000004f, 0.000005f, 0.000009f, 0.000027f, 0.381348f, 0.441406f,
+ 0.455566f, 0.462891f, 0.466309f, 0.468994f,
+ },
+ {
+ 0.016769f, 0.050629f, 0.083740f, 0.116638f, 0.148071f, 0.178955f, 0.208374f, 0.236938f, 0.265137f, 0.291992f, 0.317871f, 0.343994f,
+ 0.368164f, 0.391846f, 0.415527f, 0.437988f, 0.459717f, 0.480469f, 0.501465f, 0.520996f, 0.540527f, 0.559082f, 0.577637f, 0.594727f,
+ 0.612305f, 0.628418f, 0.644531f, 0.661133f, 0.676270f, 0.691406f, 0.705566f, 0.719727f, 0.734375f, 0.747070f, 0.760254f, 0.773438f,
+ 0.786133f, 0.798828f, 0.810059f, 0.821777f, 0.833008f, 0.843262f, 0.854492f, 0.865234f, 0.875488f, 0.885254f, 0.895508f, 0.904297f,
+ 0.913574f, 0.923340f, 0.932617f, 0.940918f, 0.949707f, 0.958008f, 0.966309f, 0.974609f, 0.981934f, 0.990234f, 0.985352f, 0.965332f,
+ 0.950195f, 0.937500f, 0.926270f, 0.915527f, 0.015083f, 0.045929f, 0.075806f, 0.105408f, 0.135254f, 0.163208f, 0.191772f, 0.219238f,
+ 0.245239f, 0.271973f, 0.297363f, 0.321045f, 0.345947f, 0.369141f, 0.391846f, 0.414062f, 0.435791f, 0.456787f, 0.477295f, 0.497314f,
+ 0.516113f, 0.535645f, 0.554199f, 0.571777f, 0.588867f, 0.606445f, 0.623047f, 0.639160f, 0.654785f, 0.669434f, 0.685059f, 0.699219f,
+ 0.713379f, 0.728027f, 0.741211f, 0.754883f, 0.767578f, 0.780273f, 0.792480f, 0.804688f, 0.815918f, 0.826660f, 0.838867f, 0.850098f,
+ 0.859863f, 0.871094f, 0.880859f, 0.891113f, 0.900879f, 0.909180f, 0.919434f, 0.929688f, 0.937500f, 0.946289f, 0.954590f, 0.963379f,
+ 0.971191f, 0.979004f, 0.980469f, 0.961426f, 0.947266f, 0.935059f, 0.924316f, 0.914062f, 0.013573f, 0.040955f, 0.068848f, 0.096313f,
+ 0.123169f, 0.150635f, 0.175537f, 0.202026f, 0.228271f, 0.251709f, 0.276367f, 0.300781f, 0.323730f, 0.347168f, 0.369385f, 0.390625f,
+ 0.412354f, 0.433594f, 0.454346f, 0.473145f, 0.491943f, 0.512207f, 0.529785f, 0.549316f, 0.566406f, 0.583008f, 0.600586f, 0.616211f,
+ 0.633301f, 0.648438f, 0.663574f, 0.679199f, 0.693359f, 0.708008f, 0.721680f, 0.735840f, 0.748535f, 0.762207f, 0.773926f, 0.786621f,
+ 0.798340f, 0.811035f, 0.822754f, 0.833984f, 0.845215f, 0.855957f, 0.865723f, 0.876465f, 0.886719f, 0.895508f, 0.906738f, 0.916016f,
+ 0.925293f, 0.934570f, 0.943848f, 0.952148f, 0.960449f, 0.969238f, 0.976074f, 0.958008f, 0.944336f, 0.932617f, 0.921875f, 0.912109f,
+ 0.012329f, 0.037201f, 0.062164f, 0.087646f, 0.112488f, 0.137451f, 0.161865f, 0.187134f, 0.210938f, 0.234253f, 0.258301f, 0.281006f,
+ 0.303467f, 0.325195f, 0.347656f, 0.368652f, 0.389648f, 0.410400f, 0.430664f, 0.450928f, 0.470215f, 0.488770f, 0.507812f, 0.525391f,
+ 0.543457f, 0.560059f, 0.579102f, 0.593750f, 0.611816f, 0.627441f, 0.643066f, 0.658203f, 0.672363f, 0.687500f, 0.702148f, 0.715820f,
+ 0.729004f, 0.742676f, 0.755371f, 0.768066f, 0.781738f, 0.792969f, 0.805176f, 0.816895f, 0.829102f, 0.839844f, 0.850586f, 0.861816f,
+ 0.872559f, 0.882812f, 0.893066f, 0.902832f, 0.912109f, 0.921875f, 0.930664f, 0.940430f, 0.948242f, 0.958008f, 0.970703f, 0.953613f,
+ 0.940430f, 0.929199f, 0.919434f, 0.910156f, 0.010979f, 0.033752f, 0.056763f, 0.080139f, 0.103516f, 0.126221f, 0.149414f, 0.172485f,
+ 0.195435f, 0.218262f, 0.240356f, 0.261719f, 0.284180f, 0.306396f, 0.326416f, 0.347900f, 0.368408f, 0.389160f, 0.408691f, 0.427979f,
+ 0.447754f, 0.467041f, 0.484863f, 0.502441f, 0.520996f, 0.538086f, 0.555664f, 0.573242f, 0.589355f, 0.604980f, 0.622559f, 0.637207f,
+ 0.652832f, 0.666992f, 0.680664f, 0.695801f, 0.710938f, 0.724121f, 0.737305f, 0.750977f, 0.763672f, 0.776855f, 0.789062f, 0.799805f,
+ 0.812012f, 0.824219f, 0.835449f, 0.846680f, 0.857910f, 0.868164f, 0.878418f, 0.889160f, 0.898926f, 0.909180f, 0.917969f, 0.928223f,
+ 0.937012f, 0.946777f, 0.965820f, 0.949707f, 0.937012f, 0.926270f, 0.916504f, 0.907715f, 0.009941f, 0.030746f, 0.051514f, 0.073181f,
+ 0.094116f, 0.116028f, 0.137817f, 0.158691f, 0.180664f, 0.202637f, 0.223511f, 0.244873f, 0.265869f, 0.285889f, 0.307129f, 0.327881f,
+ 0.347412f, 0.367188f, 0.387207f, 0.405762f, 0.425537f, 0.444092f, 0.462646f, 0.481201f, 0.499756f, 0.516602f, 0.533691f, 0.550781f,
+ 0.567383f, 0.583984f, 0.599609f, 0.616211f, 0.630859f, 0.647461f, 0.661621f, 0.676758f, 0.689453f, 0.704590f, 0.718750f, 0.731934f,
+ 0.745117f, 0.757812f, 0.770996f, 0.783691f, 0.796387f, 0.807617f, 0.819824f, 0.831543f, 0.842773f, 0.854004f, 0.864258f, 0.875488f,
+ 0.885742f, 0.895508f, 0.905762f, 0.915527f, 0.925781f, 0.934570f, 0.960449f, 0.945312f, 0.933594f, 0.922852f, 0.913574f, 0.905273f,
+ 0.009003f, 0.027756f, 0.046997f, 0.066711f, 0.085999f, 0.106506f, 0.127075f, 0.146973f, 0.166992f, 0.187500f, 0.207886f, 0.228149f,
+ 0.248169f, 0.268311f, 0.287842f, 0.307861f, 0.327393f, 0.347656f, 0.365967f, 0.385010f, 0.404541f, 0.422363f, 0.441162f, 0.458740f,
+ 0.477783f, 0.495117f, 0.512207f, 0.529297f, 0.546387f, 0.562012f, 0.578613f, 0.595215f, 0.610840f, 0.625977f, 0.641113f, 0.656738f,
+ 0.670410f, 0.685059f, 0.699707f, 0.714355f, 0.727051f, 0.741699f, 0.752441f, 0.767090f, 0.778809f, 0.791504f, 0.803711f, 0.815430f,
+ 0.827148f, 0.838867f, 0.850098f, 0.860840f, 0.872070f, 0.881836f, 0.893066f, 0.903809f, 0.913574f, 0.923828f, 0.955078f, 0.940918f,
+ 0.929199f, 0.919922f, 0.911133f, 0.902344f, 0.008469f, 0.025375f, 0.043121f, 0.060944f, 0.079468f, 0.097961f, 0.116394f, 0.135620f,
+ 0.154541f, 0.174072f, 0.193115f, 0.212280f, 0.231689f, 0.250732f, 0.270264f, 0.289307f, 0.307861f, 0.327148f, 0.345215f, 0.364990f,
+ 0.382812f, 0.401123f, 0.418945f, 0.437012f, 0.455811f, 0.472900f, 0.490234f, 0.507812f, 0.524414f, 0.541016f, 0.558105f, 0.573242f,
+ 0.590332f, 0.605469f, 0.620117f, 0.636230f, 0.651367f, 0.665039f, 0.679688f, 0.694336f, 0.708496f, 0.722168f, 0.735840f, 0.750000f,
+ 0.762695f, 0.774902f, 0.787598f, 0.798828f, 0.811523f, 0.823730f, 0.834473f, 0.846191f, 0.857910f, 0.868652f, 0.879883f, 0.891113f,
+ 0.900391f, 0.911133f, 0.949219f, 0.937012f, 0.925293f, 0.916016f, 0.907227f, 0.899414f, 0.007618f, 0.023178f, 0.039490f, 0.055542f,
+ 0.072937f, 0.090271f, 0.107605f, 0.125122f, 0.142944f, 0.160889f, 0.178955f, 0.197510f, 0.216553f, 0.234497f, 0.252686f, 0.271240f,
+ 0.289795f, 0.307861f, 0.326172f, 0.344238f, 0.362549f, 0.380859f, 0.398438f, 0.416504f, 0.433838f, 0.452393f, 0.468994f, 0.485840f,
+ 0.502930f, 0.519531f, 0.536133f, 0.553223f, 0.569336f, 0.584473f, 0.599609f, 0.615234f, 0.631348f, 0.646484f, 0.659668f, 0.675293f,
+ 0.689941f, 0.703125f, 0.716797f, 0.730957f, 0.744141f, 0.756836f, 0.771484f, 0.782227f, 0.795898f, 0.807617f, 0.819824f, 0.831543f,
+ 0.843750f, 0.854980f, 0.866211f, 0.877441f, 0.888672f, 0.898438f, 0.943359f, 0.931641f, 0.921387f, 0.912109f, 0.903809f, 0.896484f,
+ 0.007118f, 0.021255f, 0.035889f, 0.051514f, 0.066895f, 0.083191f, 0.098999f, 0.115540f, 0.132324f, 0.149292f, 0.166260f, 0.183716f,
+ 0.200928f, 0.218628f, 0.236084f, 0.253906f, 0.272217f, 0.289795f, 0.307617f, 0.325439f, 0.342529f, 0.360596f, 0.378906f, 0.395996f,
+ 0.413330f, 0.430908f, 0.447510f, 0.465332f, 0.481934f, 0.497803f, 0.514648f, 0.531738f, 0.547852f, 0.562988f, 0.579102f, 0.595215f,
+ 0.610840f, 0.625977f, 0.641113f, 0.655273f, 0.670410f, 0.685059f, 0.698730f, 0.712891f, 0.726074f, 0.739258f, 0.753418f, 0.766113f,
+ 0.779785f, 0.791992f, 0.803711f, 0.816406f, 0.829102f, 0.839844f, 0.852539f, 0.863770f, 0.874512f, 0.886719f, 0.937988f, 0.926758f,
+ 0.917480f, 0.908203f, 0.900391f, 0.893066f, 0.006481f, 0.019775f, 0.032928f, 0.047272f, 0.061371f, 0.076233f, 0.091064f, 0.107117f,
+ 0.122559f, 0.138062f, 0.154663f, 0.170532f, 0.187256f, 0.204346f, 0.220947f, 0.237915f, 0.254883f, 0.272217f, 0.289062f, 0.306641f,
+ 0.323730f, 0.341064f, 0.358643f, 0.375732f, 0.393555f, 0.410645f, 0.426758f, 0.444580f, 0.461182f, 0.477783f, 0.494141f, 0.510254f,
+ 0.526855f, 0.543457f, 0.559082f, 0.574219f, 0.590332f, 0.605957f, 0.621094f, 0.634766f, 0.650879f, 0.665039f, 0.679688f, 0.694824f,
+ 0.708008f, 0.722656f, 0.736816f, 0.749023f, 0.762695f, 0.775391f, 0.788086f, 0.801270f, 0.813965f, 0.826172f, 0.838379f, 0.849121f,
+ 0.861328f, 0.873535f, 0.932129f, 0.921875f, 0.912598f, 0.904297f, 0.896484f, 0.889160f, 0.005924f, 0.017899f, 0.030426f, 0.043427f,
+ 0.056824f, 0.070435f, 0.084106f, 0.098755f, 0.112976f, 0.128052f, 0.143311f, 0.158936f, 0.174072f, 0.189575f, 0.206421f, 0.222534f,
+ 0.238403f, 0.255615f, 0.271729f, 0.288818f, 0.305908f, 0.322021f, 0.339355f, 0.356445f, 0.373291f, 0.390137f, 0.407227f, 0.423584f,
+ 0.440430f, 0.457031f, 0.472900f, 0.489502f, 0.506836f, 0.521973f, 0.538574f, 0.554688f, 0.570312f, 0.585449f, 0.601074f, 0.616211f,
+ 0.631348f, 0.646484f, 0.661621f, 0.675781f, 0.690430f, 0.704590f, 0.717285f, 0.731934f, 0.746094f, 0.759277f, 0.771973f, 0.785156f,
+ 0.798340f, 0.810547f, 0.823242f, 0.835938f, 0.848145f, 0.860352f, 0.925781f, 0.916504f, 0.908203f, 0.900391f, 0.893066f, 0.886719f,
+ 0.005573f, 0.016693f, 0.028366f, 0.040192f, 0.052277f, 0.064880f, 0.078064f, 0.090698f, 0.105042f, 0.118591f, 0.133057f, 0.147461f,
+ 0.162231f, 0.177612f, 0.192383f, 0.207886f, 0.223633f, 0.239502f, 0.255615f, 0.272217f, 0.288330f, 0.304932f, 0.320312f, 0.337646f,
+ 0.354004f, 0.369873f, 0.386719f, 0.403320f, 0.419922f, 0.437012f, 0.453369f, 0.469482f, 0.485596f, 0.501465f, 0.517578f, 0.534180f,
+ 0.549316f, 0.565918f, 0.581055f, 0.595703f, 0.611328f, 0.626953f, 0.641602f, 0.657227f, 0.671387f, 0.686523f, 0.699707f, 0.714355f,
+ 0.729004f, 0.742676f, 0.756348f, 0.769043f, 0.782715f, 0.795410f, 0.809082f, 0.821289f, 0.833984f, 0.846680f, 0.919434f, 0.911133f,
+ 0.903320f, 0.895508f, 0.888672f, 0.882324f, 0.005016f, 0.015396f, 0.026169f, 0.037231f, 0.048126f, 0.059937f, 0.071716f, 0.084167f,
+ 0.096680f, 0.109558f, 0.123169f, 0.136719f, 0.150269f, 0.164917f, 0.179077f, 0.194580f, 0.208984f, 0.223877f, 0.239746f, 0.255127f,
+ 0.270996f, 0.286377f, 0.302490f, 0.319336f, 0.335205f, 0.351318f, 0.367432f, 0.383545f, 0.399902f, 0.415771f, 0.432373f, 0.448975f,
+ 0.465088f, 0.481934f, 0.497314f, 0.513672f, 0.529785f, 0.544434f, 0.561035f, 0.576660f, 0.592285f, 0.607422f, 0.622559f, 0.638184f,
+ 0.652344f, 0.667480f, 0.681641f, 0.696777f, 0.711426f, 0.725586f, 0.738770f, 0.753418f, 0.766602f, 0.779297f, 0.793945f, 0.807129f,
+ 0.819824f, 0.833008f, 0.913086f, 0.906738f, 0.898438f, 0.890625f, 0.884277f, 0.878418f, 0.004738f, 0.014053f, 0.024017f, 0.033752f,
+ 0.044495f, 0.055328f, 0.066467f, 0.078064f, 0.089661f, 0.102051f, 0.114258f, 0.126831f, 0.139771f, 0.153564f, 0.167114f, 0.181030f,
+ 0.195190f, 0.209839f, 0.224731f, 0.239136f, 0.253906f, 0.269531f, 0.285156f, 0.300293f, 0.317139f, 0.332520f, 0.348145f, 0.364990f,
+ 0.380859f, 0.396240f, 0.412109f, 0.428711f, 0.444336f, 0.460938f, 0.477295f, 0.492676f, 0.509277f, 0.524902f, 0.540527f, 0.556641f,
+ 0.572266f, 0.587402f, 0.604004f, 0.618164f, 0.633301f, 0.648438f, 0.664062f, 0.678223f, 0.693359f, 0.708008f, 0.722656f, 0.736328f,
+ 0.750000f, 0.764160f, 0.777832f, 0.791016f, 0.805176f, 0.817871f, 0.907227f, 0.900879f, 0.894043f, 0.886719f, 0.880371f, 0.874512f,
+ 0.004105f, 0.012741f, 0.022491f, 0.031769f, 0.041107f, 0.051208f, 0.061249f, 0.071777f, 0.083069f, 0.093811f, 0.105896f, 0.117554f,
+ 0.129761f, 0.142212f, 0.155273f, 0.168579f, 0.182251f, 0.196167f, 0.210449f, 0.223755f, 0.238525f, 0.253662f, 0.268799f, 0.283447f,
+ 0.298828f, 0.313965f, 0.329834f, 0.344971f, 0.361328f, 0.376953f, 0.393066f, 0.408691f, 0.424561f, 0.441406f, 0.457031f, 0.472656f,
+ 0.488770f, 0.504883f, 0.520996f, 0.536133f, 0.551758f, 0.567871f, 0.583496f, 0.599121f, 0.614258f, 0.629395f, 0.645996f, 0.660156f,
+ 0.675781f, 0.689453f, 0.704102f, 0.719727f, 0.733398f, 0.747559f, 0.761719f, 0.776367f, 0.789062f, 0.803223f, 0.899902f, 0.895020f,
+ 0.888184f, 0.881836f, 0.875488f, 0.870117f, 0.003925f, 0.011978f, 0.020538f, 0.028763f, 0.038269f, 0.047028f, 0.056732f, 0.066223f,
+ 0.076904f, 0.086731f, 0.097900f, 0.109314f, 0.120483f, 0.132324f, 0.144653f, 0.156982f, 0.169678f, 0.183228f, 0.196289f, 0.209961f,
+ 0.223633f, 0.237427f, 0.251953f, 0.266602f, 0.281982f, 0.296875f, 0.312012f, 0.326660f, 0.342041f, 0.357910f, 0.373779f, 0.389404f,
+ 0.404785f, 0.420166f, 0.436768f, 0.452637f, 0.468506f, 0.484863f, 0.500977f, 0.516602f, 0.531738f, 0.546875f, 0.563965f, 0.579102f,
+ 0.595215f, 0.610840f, 0.625977f, 0.641602f, 0.657227f, 0.671387f, 0.687500f, 0.702148f, 0.716309f, 0.731445f, 0.746094f, 0.760742f,
+ 0.774414f, 0.788086f, 0.893066f, 0.889648f, 0.882812f, 0.876953f, 0.870605f, 0.865723f, 0.003704f, 0.011169f, 0.019165f, 0.026550f,
+ 0.035339f, 0.043488f, 0.052277f, 0.061066f, 0.071045f, 0.080933f, 0.090576f, 0.101074f, 0.111877f, 0.122925f, 0.134277f, 0.146118f,
+ 0.157837f, 0.170288f, 0.183105f, 0.195557f, 0.209351f, 0.222900f, 0.236328f, 0.250732f, 0.264893f, 0.279297f, 0.294189f, 0.308838f,
+ 0.323975f, 0.339844f, 0.354736f, 0.370117f, 0.385986f, 0.401367f, 0.416504f, 0.432861f, 0.448486f, 0.463867f, 0.480469f, 0.497070f,
+ 0.511719f, 0.527832f, 0.544434f, 0.559570f, 0.575684f, 0.591797f, 0.606934f, 0.623047f, 0.638184f, 0.654297f, 0.668945f, 0.684570f,
+ 0.699219f, 0.714355f, 0.729492f, 0.744629f, 0.758789f, 0.773926f, 0.886230f, 0.883301f, 0.877441f, 0.871582f, 0.866211f, 0.860840f,
+ 0.003500f, 0.010292f, 0.017395f, 0.024963f, 0.032440f, 0.040344f, 0.048462f, 0.057098f, 0.065063f, 0.074646f, 0.083679f, 0.093445f,
+ 0.103882f, 0.114136f, 0.124451f, 0.135498f, 0.146606f, 0.158447f, 0.170410f, 0.182739f, 0.195435f, 0.208008f, 0.221558f, 0.234863f,
+ 0.248657f, 0.262695f, 0.276855f, 0.291748f, 0.306152f, 0.320801f, 0.335693f, 0.350830f, 0.365967f, 0.382080f, 0.396973f, 0.413330f,
+ 0.429199f, 0.444336f, 0.459473f, 0.476074f, 0.492188f, 0.507812f, 0.524414f, 0.540039f, 0.555664f, 0.571777f, 0.586914f, 0.604004f,
+ 0.619629f, 0.635742f, 0.650391f, 0.666504f, 0.682129f, 0.697754f, 0.712891f, 0.728027f, 0.743164f, 0.758301f, 0.878906f, 0.877441f,
+ 0.871582f, 0.866699f, 0.860840f, 0.856445f, 0.003084f, 0.009697f, 0.016403f, 0.022659f, 0.029892f, 0.037354f, 0.044281f, 0.052338f,
+ 0.060516f, 0.068970f, 0.077515f, 0.086243f, 0.096069f, 0.105713f, 0.115356f, 0.125610f, 0.136353f, 0.147339f, 0.158081f, 0.170410f,
+ 0.181396f, 0.194458f, 0.207275f, 0.219482f, 0.232910f, 0.246704f, 0.260010f, 0.274170f, 0.288330f, 0.302979f, 0.317383f, 0.332764f,
+ 0.347656f, 0.363037f, 0.378174f, 0.392578f, 0.408936f, 0.424316f, 0.440430f, 0.456299f, 0.472656f, 0.488525f, 0.503906f, 0.519531f,
+ 0.535645f, 0.552734f, 0.568359f, 0.584961f, 0.600586f, 0.616699f, 0.633301f, 0.648438f, 0.663574f, 0.679199f, 0.694824f, 0.710938f,
+ 0.726074f, 0.742188f, 0.872559f, 0.870605f, 0.865723f, 0.860840f, 0.855957f, 0.851074f, 0.002913f, 0.008781f, 0.014938f, 0.021759f,
+ 0.027878f, 0.034393f, 0.041412f, 0.048737f, 0.055969f, 0.063599f, 0.072021f, 0.080200f, 0.088928f, 0.097839f, 0.106934f, 0.116150f,
+ 0.126587f, 0.136353f, 0.147095f, 0.157715f, 0.169189f, 0.181519f, 0.193481f, 0.205933f, 0.217773f, 0.231323f, 0.244629f, 0.257812f,
+ 0.271240f, 0.285400f, 0.299561f, 0.314453f, 0.329590f, 0.343506f, 0.358887f, 0.373779f, 0.389648f, 0.405029f, 0.420410f, 0.437012f,
+ 0.452393f, 0.468262f, 0.484375f, 0.500000f, 0.516113f, 0.532227f, 0.548828f, 0.564941f, 0.581055f, 0.597168f, 0.612793f, 0.629883f,
+ 0.645508f, 0.662109f, 0.678223f, 0.694336f, 0.709473f, 0.726074f, 0.863770f, 0.864258f, 0.859863f, 0.854980f, 0.850586f, 0.846191f,
+ 0.002815f, 0.008194f, 0.013954f, 0.019653f, 0.025696f, 0.031982f, 0.038177f, 0.044830f, 0.051819f, 0.058502f, 0.066162f, 0.073792f,
+ 0.082031f, 0.090393f, 0.098999f, 0.107605f, 0.117493f, 0.126709f, 0.137207f, 0.146729f, 0.157593f, 0.168579f, 0.179810f, 0.191772f,
+ 0.203369f, 0.215820f, 0.228882f, 0.241455f, 0.254395f, 0.268311f, 0.282227f, 0.296631f, 0.310303f, 0.325439f, 0.339844f, 0.354736f,
+ 0.370361f, 0.385742f, 0.400879f, 0.416504f, 0.432617f, 0.448486f, 0.464355f, 0.479980f, 0.496094f, 0.513184f, 0.528809f, 0.545410f,
+ 0.561035f, 0.578613f, 0.594727f, 0.611328f, 0.626953f, 0.643555f, 0.660156f, 0.676270f, 0.693359f, 0.709473f, 0.856445f, 0.858398f,
+ 0.854492f, 0.849121f, 0.845215f, 0.841309f, 0.002583f, 0.007492f, 0.012878f, 0.018417f, 0.023941f, 0.029495f, 0.035339f, 0.041779f,
+ 0.047577f, 0.054047f, 0.061523f, 0.068787f, 0.075562f, 0.083313f, 0.091858f, 0.099792f, 0.108521f, 0.117615f, 0.126709f, 0.136108f,
+ 0.146851f, 0.156860f, 0.166992f, 0.178345f, 0.189819f, 0.202148f, 0.213623f, 0.225830f, 0.238892f, 0.252197f, 0.265137f, 0.278809f,
+ 0.292480f, 0.306885f, 0.321045f, 0.336914f, 0.350830f, 0.366943f, 0.381348f, 0.396240f, 0.412354f, 0.428223f, 0.444336f, 0.460449f,
+ 0.476318f, 0.493408f, 0.509277f, 0.525879f, 0.542480f, 0.559082f, 0.574707f, 0.591797f, 0.608398f, 0.625488f, 0.642090f, 0.659180f,
+ 0.675781f, 0.691406f, 0.848145f, 0.851562f, 0.848145f, 0.843750f, 0.838867f, 0.835449f, 0.002512f, 0.007374f, 0.012115f, 0.016983f,
+ 0.022064f, 0.027359f, 0.032715f, 0.038147f, 0.044373f, 0.050354f, 0.056641f, 0.063293f, 0.070190f, 0.077026f, 0.084717f, 0.092041f,
+ 0.100342f, 0.108398f, 0.117554f, 0.126221f, 0.135742f, 0.145142f, 0.155151f, 0.165771f, 0.176758f, 0.187988f, 0.199341f, 0.210815f,
+ 0.223389f, 0.236206f, 0.249023f, 0.261719f, 0.275879f, 0.289062f, 0.303467f, 0.317627f, 0.332520f, 0.347412f, 0.361816f, 0.377197f,
+ 0.393066f, 0.407959f, 0.424072f, 0.440186f, 0.457031f, 0.473145f, 0.489502f, 0.505859f, 0.522461f, 0.540039f, 0.555664f, 0.572754f,
+ 0.589844f, 0.606445f, 0.623535f, 0.640625f, 0.658203f, 0.675781f, 0.840820f, 0.843750f, 0.841309f, 0.836914f, 0.833984f, 0.830566f,
+ 0.002369f, 0.006668f, 0.011093f, 0.015778f, 0.020523f, 0.025223f, 0.030701f, 0.035339f, 0.040710f, 0.046600f, 0.051971f, 0.058075f,
+ 0.064819f, 0.071228f, 0.077942f, 0.085205f, 0.092224f, 0.100464f, 0.108398f, 0.116882f, 0.125610f, 0.134155f, 0.143555f, 0.153564f,
+ 0.164062f, 0.174316f, 0.185303f, 0.196899f, 0.208496f, 0.220093f, 0.232666f, 0.245239f, 0.258057f, 0.271729f, 0.285645f, 0.299561f,
+ 0.313721f, 0.328613f, 0.342773f, 0.358154f, 0.373535f, 0.388916f, 0.405518f, 0.419922f, 0.437012f, 0.453125f, 0.469238f, 0.486328f,
+ 0.502930f, 0.519531f, 0.536133f, 0.553223f, 0.571289f, 0.588379f, 0.605469f, 0.623047f, 0.640137f, 0.656250f, 0.833008f, 0.837402f,
+ 0.834473f, 0.831055f, 0.827637f, 0.824219f, 0.002188f, 0.006027f, 0.010582f, 0.014297f, 0.018921f, 0.023270f, 0.028183f, 0.032593f,
+ 0.037781f, 0.042999f, 0.048584f, 0.053650f, 0.059601f, 0.065369f, 0.071899f, 0.078369f, 0.085449f, 0.092407f, 0.099609f, 0.107788f,
+ 0.115601f, 0.124451f, 0.133301f, 0.142212f, 0.151978f, 0.161865f, 0.172363f, 0.182617f, 0.193970f, 0.205566f, 0.217407f, 0.229858f,
+ 0.241943f, 0.254639f, 0.268311f, 0.281494f, 0.295654f, 0.310059f, 0.324219f, 0.339600f, 0.353760f, 0.369629f, 0.385010f, 0.400879f,
+ 0.417725f, 0.433594f, 0.449219f, 0.465820f, 0.482910f, 0.499512f, 0.517090f, 0.534180f, 0.551270f, 0.568848f, 0.586426f, 0.604004f,
+ 0.622559f, 0.639160f, 0.824219f, 0.830078f, 0.827637f, 0.824707f, 0.821777f, 0.818359f, 0.002098f, 0.005634f, 0.009354f, 0.013557f,
+ 0.017685f, 0.021576f, 0.025604f, 0.030380f, 0.034943f, 0.039429f, 0.044281f, 0.049255f, 0.055023f, 0.060577f, 0.066101f, 0.072144f,
+ 0.078491f, 0.085083f, 0.091858f, 0.098999f, 0.106873f, 0.114502f, 0.122498f, 0.131592f, 0.140137f, 0.149536f, 0.159424f, 0.169556f,
+ 0.180054f, 0.191162f, 0.202026f, 0.213989f, 0.226318f, 0.239136f, 0.250977f, 0.264648f, 0.278320f, 0.291748f, 0.305908f, 0.320557f,
+ 0.334961f, 0.350342f, 0.365479f, 0.381592f, 0.397461f, 0.413818f, 0.429199f, 0.446289f, 0.462891f, 0.479736f, 0.496338f, 0.514160f,
+ 0.530762f, 0.548828f, 0.566406f, 0.584473f, 0.602539f, 0.621582f, 0.815918f, 0.823730f, 0.821289f, 0.817871f, 0.815430f, 0.812500f,
+ 0.001772f, 0.005249f, 0.008995f, 0.012260f, 0.016251f, 0.020020f, 0.024216f, 0.027603f, 0.032196f, 0.036377f, 0.041199f, 0.045410f,
+ 0.050110f, 0.055603f, 0.061005f, 0.066406f, 0.072327f, 0.077820f, 0.084290f, 0.090942f, 0.098083f, 0.105164f, 0.113037f, 0.120789f,
+ 0.129272f, 0.138062f, 0.147339f, 0.156982f, 0.166626f, 0.176758f, 0.187866f, 0.199097f, 0.210449f, 0.222412f, 0.234985f, 0.247559f,
+ 0.260742f, 0.273682f, 0.287598f, 0.302002f, 0.316650f, 0.331299f, 0.346191f, 0.362061f, 0.377686f, 0.393066f, 0.409668f, 0.426514f,
+ 0.443115f, 0.459717f, 0.476807f, 0.494629f, 0.511230f, 0.529785f, 0.547852f, 0.565430f, 0.583984f, 0.602539f, 0.806152f, 0.814453f,
+ 0.813965f, 0.811035f, 0.809082f, 0.806641f, 0.001631f, 0.005131f, 0.008186f, 0.011673f, 0.014938f, 0.018463f, 0.021957f, 0.025635f,
+ 0.029083f, 0.033325f, 0.037445f, 0.041840f, 0.046478f, 0.050751f, 0.055634f, 0.060760f, 0.065979f, 0.071472f, 0.077515f, 0.083801f,
+ 0.090027f, 0.096802f, 0.104065f, 0.110840f, 0.119080f, 0.127197f, 0.135498f, 0.144775f, 0.153931f, 0.163574f, 0.173462f, 0.184570f,
+ 0.195312f, 0.207153f, 0.218506f, 0.230591f, 0.243652f, 0.256348f, 0.270020f, 0.283691f, 0.297852f, 0.312744f, 0.326904f, 0.342529f,
+ 0.357910f, 0.373535f, 0.389404f, 0.406494f, 0.421875f, 0.439941f, 0.457275f, 0.474365f, 0.492432f, 0.509766f, 0.527832f, 0.546875f,
+ 0.564941f, 0.584473f, 0.797852f, 0.807129f, 0.807129f, 0.804199f, 0.801758f, 0.799316f, 0.001632f, 0.004704f, 0.007912f, 0.010788f,
+ 0.013870f, 0.017105f, 0.020187f, 0.023483f, 0.026932f, 0.030563f, 0.034332f, 0.038086f, 0.042694f, 0.046631f, 0.050995f, 0.055725f,
+ 0.060486f, 0.065674f, 0.070862f, 0.076721f, 0.082825f, 0.088623f, 0.094910f, 0.102112f, 0.109070f, 0.116516f, 0.124695f, 0.133057f,
+ 0.141968f, 0.151001f, 0.160522f, 0.170776f, 0.181030f, 0.191650f, 0.202881f, 0.214722f, 0.227417f, 0.239624f, 0.252686f, 0.265625f,
+ 0.279785f, 0.293213f, 0.308350f, 0.323242f, 0.338867f, 0.354248f, 0.370117f, 0.386475f, 0.403076f, 0.420410f, 0.437012f, 0.454102f,
+ 0.471924f, 0.490234f, 0.508789f, 0.526855f, 0.545410f, 0.564453f, 0.788086f, 0.799316f, 0.798828f, 0.797852f, 0.794434f, 0.791992f,
+ 0.001594f, 0.004177f, 0.007122f, 0.010201f, 0.012344f, 0.015839f, 0.018372f, 0.021683f, 0.024857f, 0.028534f, 0.031464f, 0.035034f,
+ 0.038879f, 0.042572f, 0.046295f, 0.051056f, 0.055389f, 0.059723f, 0.064697f, 0.069763f, 0.075073f, 0.080750f, 0.087219f, 0.093445f,
+ 0.099548f, 0.107056f, 0.114136f, 0.121887f, 0.130249f, 0.138794f, 0.147217f, 0.157104f, 0.166748f, 0.177124f, 0.187988f, 0.199097f,
+ 0.210693f, 0.222778f, 0.235352f, 0.248169f, 0.261719f, 0.275635f, 0.289062f, 0.303955f, 0.319336f, 0.334717f, 0.350098f, 0.365479f,
+ 0.382324f, 0.398926f, 0.416016f, 0.433594f, 0.451904f, 0.469238f, 0.487549f, 0.506348f, 0.525391f, 0.544922f, 0.779297f, 0.791504f,
+ 0.791504f, 0.789551f, 0.788086f, 0.786133f, 0.001365f, 0.004173f, 0.006222f, 0.008842f, 0.011703f, 0.014366f, 0.017242f, 0.020218f,
+ 0.022903f, 0.025787f, 0.028824f, 0.032227f, 0.035522f, 0.038818f, 0.042511f, 0.046326f, 0.050507f, 0.054657f, 0.058594f, 0.063660f,
+ 0.068359f, 0.073914f, 0.078918f, 0.085083f, 0.091125f, 0.097534f, 0.104126f, 0.111511f, 0.118896f, 0.126831f, 0.135742f, 0.144043f,
+ 0.153564f, 0.163330f, 0.173462f, 0.184082f, 0.195068f, 0.206787f, 0.218628f, 0.231079f, 0.243896f, 0.257080f, 0.270996f, 0.285645f,
+ 0.300049f, 0.314941f, 0.330322f, 0.346191f, 0.362305f, 0.379395f, 0.395508f, 0.412842f, 0.431641f, 0.448975f, 0.468262f, 0.487549f,
+ 0.505371f, 0.525391f, 0.769531f, 0.783691f, 0.783691f, 0.782715f, 0.781250f, 0.778809f, 0.001230f, 0.003925f, 0.006268f, 0.008659f,
+ 0.010796f, 0.013145f, 0.015617f, 0.018234f, 0.021133f, 0.023682f, 0.026215f, 0.029251f, 0.032349f, 0.035400f, 0.038696f, 0.042206f,
+ 0.045807f, 0.049377f, 0.053925f, 0.057953f, 0.062500f, 0.067078f, 0.071777f, 0.077271f, 0.082703f, 0.088806f, 0.094910f, 0.101379f,
+ 0.109192f, 0.115967f, 0.123779f, 0.131470f, 0.140259f, 0.149536f, 0.159302f, 0.169312f, 0.180054f, 0.190674f, 0.202515f, 0.214722f,
+ 0.226562f, 0.239624f, 0.253174f, 0.266602f, 0.281738f, 0.295898f, 0.311035f, 0.326904f, 0.342529f, 0.359131f, 0.375732f, 0.393066f,
+ 0.410400f, 0.428467f, 0.447510f, 0.466064f, 0.485596f, 0.504883f, 0.759277f, 0.774902f, 0.775879f, 0.774902f, 0.773438f, 0.771973f,
+ 0.001031f, 0.003601f, 0.005604f, 0.007858f, 0.009880f, 0.012146f, 0.014549f, 0.016998f, 0.019043f, 0.021362f, 0.024475f, 0.026566f,
+ 0.029358f, 0.032196f, 0.035248f, 0.038391f, 0.041656f, 0.045044f, 0.048553f, 0.052582f, 0.056213f, 0.060669f, 0.065186f, 0.070068f,
+ 0.074768f, 0.080322f, 0.086060f, 0.092102f, 0.098877f, 0.105408f, 0.112366f, 0.120239f, 0.128540f, 0.136597f, 0.145874f, 0.155396f,
+ 0.165283f, 0.175537f, 0.186401f, 0.198120f, 0.210083f, 0.222534f, 0.235229f, 0.248657f, 0.262451f, 0.277344f, 0.291504f, 0.307617f,
+ 0.322998f, 0.339111f, 0.354980f, 0.372559f, 0.390625f, 0.408936f, 0.426758f, 0.445312f, 0.466064f, 0.485840f, 0.749512f, 0.765137f,
+ 0.767578f, 0.767090f, 0.765137f, 0.764648f, 0.001161f, 0.003078f, 0.005310f, 0.007282f, 0.009201f, 0.011330f, 0.013214f, 0.015404f,
+ 0.017273f, 0.019409f, 0.021988f, 0.024078f, 0.026550f, 0.029358f, 0.032043f, 0.034454f, 0.037415f, 0.040710f, 0.043854f, 0.047272f,
+ 0.050659f, 0.054840f, 0.058777f, 0.063293f, 0.067566f, 0.072449f, 0.077759f, 0.083069f, 0.088928f, 0.095886f, 0.102478f, 0.109070f,
+ 0.116760f, 0.124390f, 0.132935f, 0.141479f, 0.151123f, 0.161011f, 0.171143f, 0.182007f, 0.193726f, 0.205688f, 0.218018f, 0.230835f,
+ 0.244507f, 0.258789f, 0.272949f, 0.287109f, 0.303467f, 0.319336f, 0.335449f, 0.352539f, 0.369873f, 0.387939f, 0.406250f, 0.425049f,
+ 0.444824f, 0.464844f, 0.739258f, 0.756348f, 0.758789f, 0.758789f, 0.757324f, 0.756836f, 0.001004f, 0.002939f, 0.005005f, 0.006779f,
+ 0.008453f, 0.010323f, 0.012177f, 0.013870f, 0.016052f, 0.018051f, 0.019638f, 0.022141f, 0.023956f, 0.026413f, 0.028870f, 0.031281f,
+ 0.033661f, 0.036591f, 0.039429f, 0.042542f, 0.045776f, 0.049011f, 0.053009f, 0.056885f, 0.061035f, 0.065186f, 0.069885f, 0.075134f,
+ 0.080505f, 0.085999f, 0.091858f, 0.098633f, 0.105591f, 0.112732f, 0.120667f, 0.128662f, 0.137573f, 0.146729f, 0.156372f, 0.166748f,
+ 0.177490f, 0.189331f, 0.201294f, 0.213501f, 0.226807f, 0.239746f, 0.254150f, 0.268555f, 0.283936f, 0.298828f, 0.316162f, 0.332275f,
+ 0.349609f, 0.367432f, 0.385498f, 0.404053f, 0.423828f, 0.443848f, 0.728516f, 0.747559f, 0.750488f, 0.750488f, 0.749512f, 0.748047f,
+ 0.000970f, 0.002523f, 0.004665f, 0.006203f, 0.007759f, 0.009491f, 0.011070f, 0.012802f, 0.014336f, 0.016266f, 0.017944f, 0.019852f,
+ 0.021805f, 0.023911f, 0.025818f, 0.028137f, 0.030579f, 0.032837f, 0.035248f, 0.038055f, 0.041046f, 0.044189f, 0.047333f, 0.050842f,
+ 0.054504f, 0.058502f, 0.062866f, 0.067383f, 0.071960f, 0.077393f, 0.082642f, 0.088928f, 0.095093f, 0.101685f, 0.108765f, 0.116272f,
+ 0.124451f, 0.133423f, 0.142212f, 0.152100f, 0.162354f, 0.172729f, 0.184692f, 0.196411f, 0.209106f, 0.221802f, 0.235718f, 0.250000f,
+ 0.265137f, 0.280029f, 0.296143f, 0.312012f, 0.329346f, 0.346924f, 0.364990f, 0.384277f, 0.403564f, 0.423340f, 0.718262f, 0.738770f,
+ 0.741211f, 0.742188f, 0.741211f, 0.740234f, 0.000785f, 0.002600f, 0.004028f, 0.005390f, 0.007275f, 0.008774f, 0.010124f, 0.011620f,
+ 0.013306f, 0.014427f, 0.015991f, 0.017838f, 0.019577f, 0.021469f, 0.023254f, 0.024902f, 0.027115f, 0.029190f, 0.031677f, 0.034088f,
+ 0.036682f, 0.039307f, 0.042175f, 0.045410f, 0.048553f, 0.052002f, 0.055908f, 0.060028f, 0.064270f, 0.068909f, 0.074097f, 0.079163f,
+ 0.085022f, 0.091309f, 0.097473f, 0.104797f, 0.112183f, 0.120239f, 0.128662f, 0.137451f, 0.146973f, 0.157471f, 0.168213f, 0.179810f,
+ 0.191650f, 0.204468f, 0.217529f, 0.231201f, 0.245605f, 0.260254f, 0.275879f, 0.292236f, 0.308838f, 0.326416f, 0.344238f, 0.363037f,
+ 0.382080f, 0.403076f, 0.707031f, 0.729980f, 0.732422f, 0.733398f, 0.733398f, 0.732910f, 0.000775f, 0.002190f, 0.003696f, 0.005081f,
+ 0.006397f, 0.007858f, 0.009239f, 0.010323f, 0.011803f, 0.012978f, 0.014328f, 0.015915f, 0.017349f, 0.019058f, 0.020630f, 0.022339f,
+ 0.024445f, 0.025909f, 0.028275f, 0.030151f, 0.032532f, 0.035065f, 0.037476f, 0.040283f, 0.042969f, 0.046448f, 0.049469f, 0.053314f,
+ 0.056976f, 0.061371f, 0.065613f, 0.070435f, 0.075623f, 0.081360f, 0.087341f, 0.093628f, 0.100220f, 0.107788f, 0.115845f, 0.123901f,
+ 0.133057f, 0.142456f, 0.152832f, 0.163574f, 0.174561f, 0.187012f, 0.199463f, 0.212646f, 0.226562f, 0.241455f, 0.256836f, 0.272705f,
+ 0.288818f, 0.305664f, 0.323486f, 0.341797f, 0.362305f, 0.382080f, 0.695312f, 0.719238f, 0.722656f, 0.724121f, 0.724121f, 0.723633f,
+ 0.000906f, 0.002022f, 0.003521f, 0.004963f, 0.005756f, 0.006847f, 0.008446f, 0.009392f, 0.010437f, 0.012039f, 0.012863f, 0.014343f,
+ 0.015457f, 0.016876f, 0.018295f, 0.019730f, 0.021484f, 0.023102f, 0.024689f, 0.026581f, 0.028717f, 0.030945f, 0.032928f, 0.035370f,
+ 0.037872f, 0.040894f, 0.043915f, 0.047028f, 0.050415f, 0.054169f, 0.058167f, 0.062286f, 0.067078f, 0.071960f, 0.077209f, 0.082947f,
+ 0.089417f, 0.096008f, 0.103271f, 0.110718f, 0.119324f, 0.128052f, 0.137817f, 0.147705f, 0.158691f, 0.169922f, 0.181519f, 0.195435f,
+ 0.208496f, 0.222534f, 0.237305f, 0.252441f, 0.268799f, 0.285645f, 0.302979f, 0.322266f, 0.340332f, 0.360840f, 0.683594f, 0.708984f,
+ 0.714355f, 0.715332f, 0.715820f, 0.715332f, 0.000700f, 0.002043f, 0.003139f, 0.004219f, 0.005417f, 0.006477f, 0.007442f, 0.008415f,
+ 0.009499f, 0.010475f, 0.011497f, 0.012619f, 0.013824f, 0.014969f, 0.016190f, 0.017639f, 0.018799f, 0.020386f, 0.021896f, 0.023560f,
+ 0.025131f, 0.027176f, 0.028900f, 0.031067f, 0.033295f, 0.035919f, 0.038239f, 0.041229f, 0.044373f, 0.047394f, 0.050934f, 0.054871f,
+ 0.058838f, 0.063293f, 0.068115f, 0.073303f, 0.078857f, 0.084839f, 0.091309f, 0.098328f, 0.106079f, 0.114136f, 0.123230f, 0.132690f,
+ 0.143066f, 0.153442f, 0.165161f, 0.177368f, 0.190186f, 0.203979f, 0.218262f, 0.232910f, 0.248901f, 0.265381f, 0.282227f, 0.301025f,
+ 0.319580f, 0.339355f, 0.672852f, 0.699707f, 0.704590f, 0.706055f, 0.706543f, 0.706055f, 0.000762f, 0.001804f, 0.002762f, 0.003914f,
+ 0.004791f, 0.005764f, 0.006542f, 0.007622f, 0.008606f, 0.009232f, 0.010178f, 0.011093f, 0.012108f, 0.013191f, 0.014412f, 0.015289f,
+ 0.016510f, 0.017731f, 0.019119f, 0.020615f, 0.022049f, 0.023483f, 0.025345f, 0.027100f, 0.028885f, 0.031067f, 0.033417f, 0.035797f,
+ 0.038422f, 0.041382f, 0.044495f, 0.047638f, 0.051178f, 0.055267f, 0.059387f, 0.064026f, 0.069092f, 0.074585f, 0.080566f, 0.087097f,
+ 0.093811f, 0.101624f, 0.109619f, 0.117798f, 0.127319f, 0.137817f, 0.148682f, 0.160278f, 0.172607f, 0.185669f, 0.199097f, 0.214233f,
+ 0.229492f, 0.245850f, 0.261963f, 0.280273f, 0.299316f, 0.319580f, 0.660645f, 0.689453f, 0.694824f, 0.696777f, 0.697266f, 0.697266f,
+ 0.000499f, 0.001527f, 0.002565f, 0.003622f, 0.004429f, 0.005138f, 0.005955f, 0.006691f, 0.007317f, 0.008156f, 0.008949f, 0.009903f,
+ 0.010635f, 0.011452f, 0.012512f, 0.013451f, 0.014503f, 0.015610f, 0.016632f, 0.017746f, 0.019073f, 0.020355f, 0.021957f, 0.023453f,
+ 0.025208f, 0.026932f, 0.028732f, 0.030945f, 0.033142f, 0.035614f, 0.038300f, 0.041199f, 0.044464f, 0.047760f, 0.051514f, 0.055573f,
+ 0.059998f, 0.064819f, 0.070312f, 0.075867f, 0.082275f, 0.088806f, 0.096436f, 0.104797f, 0.113342f, 0.122559f, 0.132568f, 0.143799f,
+ 0.155396f, 0.167725f, 0.181274f, 0.195068f, 0.209961f, 0.225708f, 0.242310f, 0.259766f, 0.277832f, 0.297363f, 0.648926f, 0.678711f,
+ 0.685059f, 0.687500f, 0.687500f, 0.687988f, 0.000653f, 0.001627f, 0.002562f, 0.003166f, 0.003872f, 0.004562f, 0.005287f, 0.005905f,
+ 0.006557f, 0.007309f, 0.007835f, 0.008621f, 0.009140f, 0.010109f, 0.010773f, 0.011627f, 0.012428f, 0.013351f, 0.014488f, 0.015472f,
+ 0.016479f, 0.017578f, 0.018845f, 0.020157f, 0.021591f, 0.023132f, 0.024765f, 0.026337f, 0.028473f, 0.030594f, 0.032867f, 0.035309f,
+ 0.037933f, 0.041107f, 0.044403f, 0.047852f, 0.051666f, 0.055756f, 0.060455f, 0.065552f, 0.070740f, 0.077454f, 0.083862f, 0.091125f,
+ 0.099304f, 0.107971f, 0.117859f, 0.127808f, 0.139038f, 0.150757f, 0.163574f, 0.176880f, 0.191162f, 0.206665f, 0.222656f, 0.239258f,
+ 0.257568f, 0.277100f, 0.636230f, 0.667969f, 0.675293f, 0.677734f, 0.678223f, 0.678711f, 0.000393f, 0.001375f, 0.002174f, 0.002773f,
+ 0.003334f, 0.004070f, 0.004692f, 0.005047f, 0.005672f, 0.006298f, 0.006893f, 0.007454f, 0.007957f, 0.008636f, 0.009171f, 0.010002f,
+ 0.010674f, 0.011574f, 0.012451f, 0.013145f, 0.014091f, 0.014893f, 0.016083f, 0.017151f, 0.018402f, 0.019714f, 0.021042f, 0.022415f,
+ 0.024155f, 0.026108f, 0.027786f, 0.030212f, 0.032379f, 0.034698f, 0.037415f, 0.040436f, 0.043793f, 0.047455f, 0.051727f, 0.056030f,
+ 0.061218f, 0.066284f, 0.072571f, 0.079041f, 0.086121f, 0.094299f, 0.102844f, 0.112305f, 0.122925f, 0.134033f, 0.145752f, 0.158569f,
+ 0.172729f, 0.187378f, 0.203003f, 0.219238f, 0.237671f, 0.255859f, 0.624023f, 0.657227f, 0.664062f, 0.666992f, 0.668457f, 0.668457f,
+ 0.000379f, 0.001404f, 0.001893f, 0.002403f, 0.002840f, 0.003458f, 0.004021f, 0.004459f, 0.004894f, 0.005527f, 0.005844f, 0.006256f,
+ 0.006866f, 0.007423f, 0.007957f, 0.008476f, 0.009155f, 0.009735f, 0.010422f, 0.011078f, 0.011925f, 0.012787f, 0.013458f, 0.014526f,
+ 0.015541f, 0.016632f, 0.017838f, 0.019028f, 0.020248f, 0.021851f, 0.023514f, 0.024979f, 0.027054f, 0.029236f, 0.031555f, 0.034180f,
+ 0.036713f, 0.040375f, 0.043854f, 0.047607f, 0.051727f, 0.056549f, 0.061768f, 0.067627f, 0.073792f, 0.081116f, 0.089111f, 0.097595f,
+ 0.107056f, 0.117371f, 0.128906f, 0.141113f, 0.154053f, 0.168579f, 0.183960f, 0.199585f, 0.216309f, 0.235352f, 0.612793f, 0.647949f,
+ 0.652832f, 0.656250f, 0.658691f, 0.658203f, 0.000506f, 0.001164f, 0.001575f, 0.002136f, 0.002600f, 0.003054f, 0.003405f, 0.003735f,
+ 0.004364f, 0.004681f, 0.004944f, 0.005569f, 0.005810f, 0.006187f, 0.006813f, 0.007233f, 0.007881f, 0.008217f, 0.008850f, 0.009293f,
+ 0.010109f, 0.010788f, 0.011543f, 0.012161f, 0.012993f, 0.013931f, 0.014809f, 0.015945f, 0.016983f, 0.018234f, 0.019440f, 0.020813f,
+ 0.022491f, 0.024261f, 0.026169f, 0.028458f, 0.030701f, 0.033295f, 0.036560f, 0.039520f, 0.043121f, 0.047333f, 0.052032f, 0.056885f,
+ 0.062561f, 0.068909f, 0.076111f, 0.083496f, 0.092407f, 0.101929f, 0.112671f, 0.124451f, 0.136719f, 0.150146f, 0.165039f, 0.180786f,
+ 0.197510f, 0.215210f, 0.597656f, 0.636230f, 0.642578f, 0.647461f, 0.647949f, 0.649902f, 0.000344f, 0.001057f, 0.001456f, 0.001907f,
+ 0.002377f, 0.002735f, 0.002983f, 0.003359f, 0.003651f, 0.003960f, 0.004311f, 0.004471f, 0.005009f, 0.005283f, 0.005653f, 0.006145f,
+ 0.006592f, 0.006889f, 0.007469f, 0.007889f, 0.008423f, 0.008911f, 0.009567f, 0.010124f, 0.010788f, 0.011574f, 0.012466f, 0.013123f,
+ 0.014053f, 0.015091f, 0.016159f, 0.017288f, 0.018539f, 0.020111f, 0.021698f, 0.023285f, 0.025024f, 0.027405f, 0.029800f, 0.032501f,
+ 0.035583f, 0.039001f, 0.042908f, 0.047302f, 0.052185f, 0.057465f, 0.063843f, 0.070984f, 0.078857f, 0.087463f, 0.097168f, 0.108215f,
+ 0.120117f, 0.132812f, 0.146851f, 0.161865f, 0.177856f, 0.195557f, 0.585449f, 0.624023f, 0.633301f, 0.636230f, 0.637695f, 0.638672f,
+ 0.000516f, 0.000847f, 0.001210f, 0.001663f, 0.002012f, 0.002218f, 0.002424f, 0.002861f, 0.002947f, 0.003275f, 0.003469f, 0.003819f,
+ 0.004169f, 0.004337f, 0.004658f, 0.005169f, 0.005424f, 0.005795f, 0.006138f, 0.006500f, 0.007057f, 0.007458f, 0.007874f, 0.008369f,
+ 0.008888f, 0.009583f, 0.010147f, 0.010864f, 0.011589f, 0.012428f, 0.013161f, 0.013931f, 0.015076f, 0.016266f, 0.017456f, 0.018845f,
+ 0.020432f, 0.022232f, 0.024094f, 0.026459f, 0.028809f, 0.031586f, 0.034973f, 0.038513f, 0.042755f, 0.047485f, 0.052643f, 0.058929f,
+ 0.065796f, 0.073792f, 0.082581f, 0.092407f, 0.103516f, 0.115723f, 0.128906f, 0.142944f, 0.158813f, 0.175781f, 0.572266f, 0.613770f,
+ 0.621094f, 0.625977f, 0.626953f, 0.628418f, 0.000262f, 0.000864f, 0.001096f, 0.001409f, 0.001576f, 0.001852f, 0.002047f, 0.002247f,
+ 0.002518f, 0.002741f, 0.002956f, 0.003157f, 0.003359f, 0.003597f, 0.003872f, 0.004230f, 0.004406f, 0.004772f, 0.005035f, 0.005379f,
+ 0.005695f, 0.006153f, 0.006485f, 0.006935f, 0.007275f, 0.007801f, 0.008301f, 0.008789f, 0.009300f, 0.009949f, 0.010727f, 0.011482f,
+ 0.012245f, 0.013145f, 0.014236f, 0.015236f, 0.016525f, 0.017838f, 0.019348f, 0.021088f, 0.023010f, 0.025253f, 0.027878f, 0.031128f,
+ 0.034149f, 0.038269f, 0.042694f, 0.047852f, 0.053833f, 0.060852f, 0.068665f, 0.077698f, 0.087891f, 0.099182f, 0.111633f, 0.125732f,
+ 0.140381f, 0.157227f, 0.558105f, 0.601562f, 0.610840f, 0.614746f, 0.617188f, 0.619141f, 0.000270f, 0.000683f, 0.000851f, 0.001138f,
+ 0.001346f, 0.001561f, 0.001701f, 0.001884f, 0.001984f, 0.002193f, 0.002455f, 0.002609f, 0.002743f, 0.002993f, 0.003159f, 0.003361f,
+ 0.003593f, 0.003883f, 0.004044f, 0.004360f, 0.004532f, 0.004971f, 0.005169f, 0.005573f, 0.005863f, 0.006252f, 0.006653f, 0.007095f,
+ 0.007572f, 0.008110f, 0.008713f, 0.009056f, 0.009827f, 0.010574f, 0.011307f, 0.012070f, 0.013069f, 0.014122f, 0.015297f, 0.016678f,
+ 0.018234f, 0.019775f, 0.021835f, 0.024216f, 0.026917f, 0.030151f, 0.033875f, 0.038147f, 0.043121f, 0.049408f, 0.056091f, 0.064026f,
+ 0.073059f, 0.083801f, 0.095276f, 0.108459f, 0.122803f, 0.138794f, 0.545410f, 0.590332f, 0.599609f, 0.603516f, 0.606445f, 0.607422f,
+ 0.000190f, 0.000607f, 0.000724f, 0.000989f, 0.001171f, 0.001265f, 0.001416f, 0.001602f, 0.001666f, 0.001761f, 0.001893f, 0.002102f,
+ 0.002199f, 0.002413f, 0.002537f, 0.002743f, 0.002850f, 0.003027f, 0.003258f, 0.003494f, 0.003729f, 0.003937f, 0.004204f, 0.004410f,
+ 0.004616f, 0.004921f, 0.005192f, 0.005604f, 0.005936f, 0.006298f, 0.006836f, 0.007233f, 0.007694f, 0.008224f, 0.008827f, 0.009506f,
+ 0.010262f, 0.011055f, 0.011978f, 0.012955f, 0.014099f, 0.015434f, 0.017029f, 0.018677f, 0.020813f, 0.023193f, 0.026169f, 0.029541f,
+ 0.033783f, 0.038513f, 0.044403f, 0.051208f, 0.059387f, 0.068665f, 0.079468f, 0.091858f, 0.105774f, 0.120728f, 0.530762f, 0.578125f,
+ 0.588379f, 0.592773f, 0.595215f, 0.597168f, 0.000151f, 0.000443f, 0.000673f, 0.000793f, 0.000937f, 0.000987f, 0.001092f, 0.001192f,
+ 0.001324f, 0.001460f, 0.001495f, 0.001565f, 0.001778f, 0.001944f, 0.002054f, 0.002096f, 0.002254f, 0.002338f, 0.002594f, 0.002737f,
+ 0.002886f, 0.003048f, 0.003294f, 0.003460f, 0.003679f, 0.003868f, 0.004086f, 0.004322f, 0.004642f, 0.004894f, 0.005199f, 0.005554f,
+ 0.006035f, 0.006451f, 0.006836f, 0.007359f, 0.007820f, 0.008461f, 0.009163f, 0.009956f, 0.010803f, 0.011871f, 0.012917f, 0.014343f,
+ 0.015900f, 0.017670f, 0.019791f, 0.022400f, 0.025589f, 0.029404f, 0.034210f, 0.039948f, 0.046936f, 0.055298f, 0.064941f, 0.076172f,
+ 0.089172f, 0.103821f, 0.517090f, 0.565918f, 0.576172f, 0.582031f, 0.584961f, 0.586426f, 0.000203f, 0.000287f, 0.000531f, 0.000688f,
+ 0.000738f, 0.000820f, 0.000915f, 0.000875f, 0.001036f, 0.001117f, 0.001215f, 0.001317f, 0.001374f, 0.001476f, 0.001524f, 0.001682f,
+ 0.001726f, 0.001867f, 0.002014f, 0.002056f, 0.002209f, 0.002365f, 0.002495f, 0.002663f, 0.002775f, 0.002953f, 0.003134f, 0.003325f,
+ 0.003567f, 0.003736f, 0.004070f, 0.004261f, 0.004494f, 0.004845f, 0.005116f, 0.005459f, 0.005928f, 0.006329f, 0.006863f, 0.007458f,
+ 0.008087f, 0.008873f, 0.009689f, 0.010651f, 0.011826f, 0.013130f, 0.014732f, 0.016617f, 0.018890f, 0.021912f, 0.025482f, 0.029938f,
+ 0.035736f, 0.042847f, 0.051453f, 0.061615f, 0.074158f, 0.087952f, 0.504395f, 0.554199f, 0.565918f, 0.569336f, 0.573242f, 0.574219f,
+ 0.000215f, 0.000259f, 0.000423f, 0.000534f, 0.000499f, 0.000649f, 0.000622f, 0.000690f, 0.000717f, 0.000817f, 0.000937f, 0.000984f,
+ 0.001045f, 0.001148f, 0.001182f, 0.001211f, 0.001339f, 0.001406f, 0.001463f, 0.001590f, 0.001666f, 0.001759f, 0.001867f, 0.001949f,
+ 0.002064f, 0.002176f, 0.002342f, 0.002453f, 0.002619f, 0.002871f, 0.003033f, 0.003101f, 0.003389f, 0.003620f, 0.003794f, 0.004059f,
+ 0.004368f, 0.004681f, 0.005035f, 0.005466f, 0.005917f, 0.006405f, 0.007092f, 0.007744f, 0.008591f, 0.009506f, 0.010567f, 0.011993f,
+ 0.013710f, 0.015762f, 0.018326f, 0.021759f, 0.026077f, 0.031891f, 0.039124f, 0.048462f, 0.059570f, 0.072571f, 0.489258f, 0.542480f,
+ 0.553223f, 0.558594f, 0.562012f, 0.563965f, 0.000067f, 0.000253f, 0.000305f, 0.000367f, 0.000422f, 0.000431f, 0.000530f, 0.000466f,
+ 0.000565f, 0.000590f, 0.000702f, 0.000690f, 0.000746f, 0.000795f, 0.000859f, 0.000897f, 0.000962f, 0.001021f, 0.001069f, 0.001105f,
+ 0.001207f, 0.001257f, 0.001354f, 0.001424f, 0.001483f, 0.001570f, 0.001687f, 0.001750f, 0.001857f, 0.001982f, 0.002071f, 0.002281f,
+ 0.002361f, 0.002527f, 0.002684f, 0.002846f, 0.003092f, 0.003342f, 0.003622f, 0.003866f, 0.004173f, 0.004520f, 0.004955f, 0.005428f,
+ 0.006023f, 0.006687f, 0.007481f, 0.008446f, 0.009628f, 0.011047f, 0.012840f, 0.015205f, 0.018326f, 0.022629f, 0.028442f, 0.036102f,
+ 0.046051f, 0.058197f, 0.476318f, 0.529785f, 0.541992f, 0.547852f, 0.550293f, 0.553223f, 0.000000f, 0.000118f, 0.000216f, 0.000288f,
+ 0.000272f, 0.000350f, 0.000312f, 0.000374f, 0.000395f, 0.000470f, 0.000488f, 0.000477f, 0.000495f, 0.000548f, 0.000573f, 0.000646f,
+ 0.000636f, 0.000714f, 0.000763f, 0.000803f, 0.000852f, 0.000897f, 0.000930f, 0.000985f, 0.001056f, 0.001089f, 0.001163f, 0.001210f,
+ 0.001281f, 0.001432f, 0.001431f, 0.001548f, 0.001622f, 0.001743f, 0.001869f, 0.001991f, 0.002104f, 0.002262f, 0.002428f, 0.002632f,
+ 0.002815f, 0.003077f, 0.003344f, 0.003656f, 0.004002f, 0.004478f, 0.004974f, 0.005627f, 0.006435f, 0.007481f, 0.008713f, 0.010307f,
+ 0.012291f, 0.015289f, 0.019409f, 0.025497f, 0.033966f, 0.045013f, 0.461914f, 0.517090f, 0.529297f, 0.536133f, 0.539551f, 0.541504f,
+ 0.000073f, 0.000175f, 0.000165f, 0.000149f, 0.000200f, 0.000208f, 0.000215f, 0.000260f, 0.000268f, 0.000277f, 0.000292f, 0.000341f,
+ 0.000334f, 0.000370f, 0.000413f, 0.000424f, 0.000449f, 0.000474f, 0.000488f, 0.000507f, 0.000555f, 0.000574f, 0.000616f, 0.000652f,
+ 0.000696f, 0.000746f, 0.000780f, 0.000804f, 0.000849f, 0.000888f, 0.000949f, 0.001011f, 0.001075f, 0.001151f, 0.001225f, 0.001266f,
+ 0.001385f, 0.001466f, 0.001596f, 0.001699f, 0.001808f, 0.001980f, 0.002157f, 0.002329f, 0.002544f, 0.002850f, 0.003178f, 0.003593f,
+ 0.004047f, 0.004658f, 0.005508f, 0.006565f, 0.007935f, 0.009819f, 0.012527f, 0.016647f, 0.023514f, 0.033173f, 0.447510f, 0.503906f,
+ 0.517578f, 0.523926f, 0.527344f, 0.529297f, 0.000000f, 0.000106f, 0.000097f, 0.000099f, 0.000136f, 0.000157f, 0.000129f, 0.000162f,
+ 0.000167f, 0.000172f, 0.000180f, 0.000186f, 0.000209f, 0.000227f, 0.000232f, 0.000248f, 0.000260f, 0.000291f, 0.000300f, 0.000327f,
+ 0.000335f, 0.000343f, 0.000363f, 0.000395f, 0.000428f, 0.000459f, 0.000458f, 0.000477f, 0.000515f, 0.000549f, 0.000578f, 0.000621f,
+ 0.000659f, 0.000683f, 0.000741f, 0.000767f, 0.000818f, 0.000877f, 0.000952f, 0.001010f, 0.001085f, 0.001177f, 0.001275f, 0.001406f,
+ 0.001516f, 0.001664f, 0.001884f, 0.002096f, 0.002415f, 0.002745f, 0.003231f, 0.003843f, 0.004715f, 0.005936f, 0.007629f, 0.010139f,
+ 0.014763f, 0.022812f, 0.433350f, 0.491455f, 0.506348f, 0.511719f, 0.515625f, 0.518066f, 0.000104f, 0.000080f, 0.000069f, 0.000062f,
+ 0.000074f, 0.000074f, 0.000089f, 0.000097f, 0.000099f, 0.000102f, 0.000105f, 0.000126f, 0.000106f, 0.000119f, 0.000139f, 0.000135f,
+ 0.000154f, 0.000164f, 0.000166f, 0.000175f, 0.000188f, 0.000194f, 0.000211f, 0.000220f, 0.000252f, 0.000248f, 0.000260f, 0.000272f,
+ 0.000293f, 0.000301f, 0.000328f, 0.000347f, 0.000365f, 0.000371f, 0.000401f, 0.000422f, 0.000447f, 0.000489f, 0.000524f, 0.000553f,
+ 0.000588f, 0.000635f, 0.000701f, 0.000751f, 0.000816f, 0.000897f, 0.000997f, 0.001109f, 0.001265f, 0.001460f, 0.001686f, 0.002035f,
+ 0.002457f, 0.003130f, 0.004124f, 0.005676f, 0.008263f, 0.014114f, 0.418945f, 0.479492f, 0.493652f, 0.500000f, 0.503418f, 0.506836f,
+ 0.000089f, 0.000065f, 0.000056f, 0.000050f, 0.000045f, 0.000042f, 0.000046f, 0.000042f, 0.000043f, 0.000055f, 0.000046f, 0.000049f,
+ 0.000065f, 0.000055f, 0.000057f, 0.000063f, 0.000075f, 0.000080f, 0.000078f, 0.000084f, 0.000085f, 0.000092f, 0.000097f, 0.000102f,
+ 0.000108f, 0.000117f, 0.000118f, 0.000138f, 0.000135f, 0.000142f, 0.000151f, 0.000160f, 0.000172f, 0.000180f, 0.000195f, 0.000197f,
+ 0.000210f, 0.000230f, 0.000244f, 0.000266f, 0.000279f, 0.000299f, 0.000324f, 0.000352f, 0.000383f, 0.000414f, 0.000457f, 0.000509f,
+ 0.000575f, 0.000650f, 0.000756f, 0.000904f, 0.001103f, 0.001410f, 0.001880f, 0.002668f, 0.004112f, 0.007290f, 0.404541f, 0.466309f,
+ 0.481201f, 0.488037f, 0.492432f, 0.495361f, 0.000066f, 0.000046f, 0.000038f, 0.000034f, 0.000031f, 0.000029f, 0.000027f, 0.000026f,
+ 0.000025f, 0.000023f, 0.000022f, 0.000024f, 0.000020f, 0.000021f, 0.000021f, 0.000026f, 0.000024f, 0.000028f, 0.000031f, 0.000032f,
+ 0.000032f, 0.000035f, 0.000040f, 0.000038f, 0.000041f, 0.000047f, 0.000049f, 0.000043f, 0.000050f, 0.000052f, 0.000056f, 0.000059f,
+ 0.000066f, 0.000062f, 0.000067f, 0.000071f, 0.000082f, 0.000083f, 0.000089f, 0.000098f, 0.000104f, 0.000107f, 0.000116f, 0.000125f,
+ 0.000141f, 0.000149f, 0.000160f, 0.000183f, 0.000207f, 0.000228f, 0.000264f, 0.000311f, 0.000376f, 0.000469f, 0.000646f, 0.000937f,
+ 0.001554f, 0.002983f, 0.390381f, 0.454346f, 0.469727f, 0.476318f, 0.480713f, 0.484131f, 0.000028f, 0.000019f, 0.000015f, 0.000014f,
+ 0.000014f, 0.000013f, 0.000012f, 0.000012f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000010f,
+ 0.000010f, 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000008f, 0.000008f, 0.000007f, 0.000008f, 0.000009f, 0.000009f, 0.000010f,
+ 0.000010f, 0.000011f, 0.000012f, 0.000011f, 0.000014f, 0.000015f, 0.000016f, 0.000016f, 0.000018f, 0.000019f, 0.000019f, 0.000022f,
+ 0.000023f, 0.000024f, 0.000026f, 0.000028f, 0.000029f, 0.000032f, 0.000037f, 0.000037f, 0.000042f, 0.000048f, 0.000056f, 0.000066f,
+ 0.000077f, 0.000091f, 0.000124f, 0.000183f, 0.000318f, 0.000779f, 0.376465f, 0.441406f, 0.457275f, 0.464600f, 0.468994f, 0.471924f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000003f, 0.000004f, 0.000004f, 0.000005f, 0.000010f, 0.000027f, 0.363037f, 0.428223f,
+ 0.444580f, 0.452881f, 0.457031f, 0.459961f,
+ },
+ {
+ 0.014420f, 0.043488f, 0.072388f, 0.100830f, 0.129150f, 0.156494f, 0.183350f, 0.210327f, 0.235352f, 0.260986f, 0.285645f, 0.309082f,
+ 0.332764f, 0.355713f, 0.377441f, 0.399658f, 0.420898f, 0.441650f, 0.461914f, 0.481445f, 0.500977f, 0.520508f, 0.538574f, 0.556641f,
+ 0.574707f, 0.591797f, 0.608398f, 0.624512f, 0.641602f, 0.657227f, 0.672363f, 0.687500f, 0.702148f, 0.717285f, 0.730957f, 0.745117f,
+ 0.758789f, 0.772461f, 0.783203f, 0.797363f, 0.810547f, 0.822266f, 0.833984f, 0.845703f, 0.857422f, 0.868652f, 0.879395f, 0.890625f,
+ 0.901367f, 0.911621f, 0.921875f, 0.932129f, 0.941895f, 0.951660f, 0.960938f, 0.970215f, 0.979492f, 0.987793f, 0.981934f, 0.957031f,
+ 0.938965f, 0.923340f, 0.909668f, 0.897461f, 0.013199f, 0.039978f, 0.066284f, 0.093445f, 0.119324f, 0.145386f, 0.170410f, 0.195801f,
+ 0.220581f, 0.244019f, 0.268066f, 0.291260f, 0.314453f, 0.335938f, 0.358154f, 0.379639f, 0.399902f, 0.420898f, 0.441406f, 0.460938f,
+ 0.480225f, 0.498291f, 0.516602f, 0.535156f, 0.553223f, 0.570312f, 0.587891f, 0.603516f, 0.620117f, 0.636719f, 0.652832f, 0.667480f,
+ 0.682617f, 0.696777f, 0.711914f, 0.726074f, 0.739746f, 0.753418f, 0.766602f, 0.779785f, 0.791992f, 0.804688f, 0.817871f, 0.829102f,
+ 0.841309f, 0.852539f, 0.864258f, 0.875488f, 0.886230f, 0.896973f, 0.907227f, 0.917969f, 0.928223f, 0.937500f, 0.947266f, 0.957520f,
+ 0.966797f, 0.975586f, 0.976562f, 0.952637f, 0.935547f, 0.920898f, 0.907715f, 0.895996f, 0.011932f, 0.036499f, 0.061554f, 0.085999f,
+ 0.110962f, 0.135010f, 0.158813f, 0.182373f, 0.206421f, 0.229004f, 0.251221f, 0.274170f, 0.295654f, 0.317871f, 0.339111f, 0.360107f,
+ 0.379395f, 0.399414f, 0.420654f, 0.440430f, 0.458252f, 0.477295f, 0.496094f, 0.513672f, 0.531738f, 0.549805f, 0.566406f, 0.583984f,
+ 0.599121f, 0.616211f, 0.631348f, 0.647461f, 0.662598f, 0.677734f, 0.692383f, 0.705566f, 0.720703f, 0.734863f, 0.748047f, 0.761230f,
+ 0.774414f, 0.787598f, 0.799805f, 0.812500f, 0.824707f, 0.837402f, 0.848633f, 0.859375f, 0.871094f, 0.882324f, 0.892578f, 0.904297f,
+ 0.913574f, 0.924316f, 0.934570f, 0.943848f, 0.954102f, 0.963867f, 0.970703f, 0.948242f, 0.931641f, 0.917480f, 0.905273f, 0.894043f,
+ 0.011070f, 0.033478f, 0.056396f, 0.079529f, 0.101990f, 0.125244f, 0.147705f, 0.170410f, 0.192139f, 0.214111f, 0.235596f, 0.257812f,
+ 0.279053f, 0.300293f, 0.320557f, 0.340576f, 0.360596f, 0.381104f, 0.400635f, 0.420166f, 0.438965f, 0.458008f, 0.476562f, 0.493652f,
+ 0.511230f, 0.527832f, 0.545898f, 0.562012f, 0.579102f, 0.595703f, 0.610840f, 0.627930f, 0.642578f, 0.657227f, 0.672363f, 0.686523f,
+ 0.701660f, 0.715332f, 0.729492f, 0.742676f, 0.756348f, 0.769531f, 0.782227f, 0.795898f, 0.807617f, 0.820312f, 0.832031f, 0.843262f,
+ 0.855469f, 0.866699f, 0.877441f, 0.889648f, 0.899414f, 0.910156f, 0.920410f, 0.930664f, 0.940430f, 0.950684f, 0.964844f, 0.943848f,
+ 0.927734f, 0.914551f, 0.902344f, 0.891602f, 0.010010f, 0.031067f, 0.051880f, 0.073303f, 0.094421f, 0.116577f, 0.136963f, 0.157959f,
+ 0.180542f, 0.200684f, 0.221436f, 0.242676f, 0.262939f, 0.283447f, 0.303467f, 0.323242f, 0.342529f, 0.362305f, 0.381348f, 0.399414f,
+ 0.418701f, 0.437256f, 0.455322f, 0.472412f, 0.490479f, 0.507812f, 0.524902f, 0.541992f, 0.558105f, 0.574219f, 0.591309f, 0.606445f,
+ 0.622070f, 0.637695f, 0.652344f, 0.666504f, 0.683594f, 0.695801f, 0.710449f, 0.724121f, 0.737305f, 0.751465f, 0.765137f, 0.777344f,
+ 0.790039f, 0.802734f, 0.814941f, 0.827637f, 0.839355f, 0.851074f, 0.862305f, 0.874512f, 0.885254f, 0.895996f, 0.906738f, 0.917480f,
+ 0.927246f, 0.937988f, 0.958984f, 0.939453f, 0.923828f, 0.911133f, 0.899414f, 0.889160f, 0.009491f, 0.028305f, 0.047699f, 0.067810f,
+ 0.087341f, 0.107849f, 0.127686f, 0.147827f, 0.167725f, 0.187744f, 0.207886f, 0.227051f, 0.247314f, 0.266846f, 0.286377f, 0.305908f,
+ 0.324463f, 0.343262f, 0.361572f, 0.380371f, 0.399658f, 0.416748f, 0.435547f, 0.452881f, 0.470703f, 0.488281f, 0.503906f, 0.522461f,
+ 0.538086f, 0.554199f, 0.571289f, 0.586914f, 0.602051f, 0.617676f, 0.633789f, 0.647949f, 0.663086f, 0.677246f, 0.692871f, 0.705078f,
+ 0.718750f, 0.732910f, 0.746582f, 0.759766f, 0.773438f, 0.785645f, 0.798340f, 0.811035f, 0.823242f, 0.834961f, 0.847168f, 0.859863f,
+ 0.870117f, 0.881348f, 0.893066f, 0.903320f, 0.914551f, 0.924316f, 0.953125f, 0.934082f, 0.919434f, 0.906738f, 0.896484f, 0.885742f,
+ 0.008598f, 0.026245f, 0.044495f, 0.062622f, 0.081177f, 0.100098f, 0.119019f, 0.137817f, 0.156616f, 0.175903f, 0.194946f, 0.213745f,
+ 0.232788f, 0.251221f, 0.269775f, 0.288330f, 0.307129f, 0.325928f, 0.344238f, 0.362305f, 0.380371f, 0.397705f, 0.415771f, 0.433105f,
+ 0.450928f, 0.468262f, 0.484863f, 0.501953f, 0.518555f, 0.534668f, 0.550293f, 0.566406f, 0.582520f, 0.598145f, 0.612305f, 0.627930f,
+ 0.643555f, 0.657715f, 0.672852f, 0.687500f, 0.700684f, 0.715332f, 0.728516f, 0.742188f, 0.755371f, 0.769531f, 0.781738f, 0.794434f,
+ 0.807129f, 0.818359f, 0.831543f, 0.843262f, 0.855469f, 0.865723f, 0.877930f, 0.889160f, 0.900391f, 0.911621f, 0.946777f, 0.929199f,
+ 0.915039f, 0.903320f, 0.892578f, 0.883301f, 0.007896f, 0.024490f, 0.041138f, 0.057892f, 0.075439f, 0.092712f, 0.110229f, 0.128296f,
+ 0.146118f, 0.164429f, 0.181885f, 0.200562f, 0.218628f, 0.236572f, 0.255127f, 0.272949f, 0.291016f, 0.308594f, 0.326172f, 0.343994f,
+ 0.361816f, 0.380127f, 0.396973f, 0.414551f, 0.430908f, 0.447998f, 0.465576f, 0.481445f, 0.497559f, 0.514160f, 0.529785f, 0.546387f,
+ 0.562988f, 0.578613f, 0.593262f, 0.609375f, 0.623047f, 0.638672f, 0.653809f, 0.667480f, 0.681641f, 0.697266f, 0.710938f, 0.724121f,
+ 0.737305f, 0.752441f, 0.765625f, 0.776367f, 0.790527f, 0.803223f, 0.815918f, 0.827637f, 0.839844f, 0.851562f, 0.863281f, 0.875000f,
+ 0.886719f, 0.898926f, 0.940430f, 0.923828f, 0.910645f, 0.899414f, 0.889160f, 0.879883f, 0.007320f, 0.022369f, 0.038055f, 0.053925f,
+ 0.070190f, 0.086609f, 0.103027f, 0.119568f, 0.136475f, 0.153320f, 0.170532f, 0.187988f, 0.204834f, 0.223022f, 0.240112f, 0.257324f,
+ 0.275391f, 0.291504f, 0.308838f, 0.326904f, 0.344727f, 0.361572f, 0.378662f, 0.395020f, 0.411865f, 0.428711f, 0.445068f, 0.462646f,
+ 0.478271f, 0.494141f, 0.510254f, 0.525879f, 0.542480f, 0.557129f, 0.573242f, 0.588867f, 0.603516f, 0.618164f, 0.633789f, 0.648438f,
+ 0.663086f, 0.678223f, 0.691895f, 0.706543f, 0.720215f, 0.733398f, 0.746582f, 0.759766f, 0.774414f, 0.786621f, 0.799805f, 0.811523f,
+ 0.823730f, 0.836914f, 0.848145f, 0.860840f, 0.872070f, 0.884277f, 0.933594f, 0.918945f, 0.906250f, 0.895020f, 0.885254f, 0.876953f,
+ 0.006760f, 0.021011f, 0.034973f, 0.050049f, 0.065369f, 0.080261f, 0.095337f, 0.111633f, 0.127319f, 0.142822f, 0.159668f, 0.176514f,
+ 0.192383f, 0.209106f, 0.225586f, 0.242554f, 0.259277f, 0.275635f, 0.292480f, 0.309326f, 0.326904f, 0.343750f, 0.359619f, 0.376465f,
+ 0.393066f, 0.409424f, 0.426514f, 0.442871f, 0.458252f, 0.475586f, 0.490967f, 0.505859f, 0.522461f, 0.539062f, 0.554199f, 0.569336f,
+ 0.583984f, 0.600586f, 0.614258f, 0.630371f, 0.643555f, 0.658691f, 0.673340f, 0.687500f, 0.702148f, 0.715332f, 0.729980f, 0.743652f,
+ 0.756348f, 0.770020f, 0.782715f, 0.796387f, 0.808105f, 0.820801f, 0.833008f, 0.846680f, 0.857910f, 0.870117f, 0.927246f, 0.913574f,
+ 0.901367f, 0.891113f, 0.881348f, 0.873047f, 0.006367f, 0.019165f, 0.032379f, 0.046295f, 0.060089f, 0.074463f, 0.088867f, 0.103821f,
+ 0.118835f, 0.133911f, 0.149048f, 0.164673f, 0.180298f, 0.196289f, 0.212524f, 0.228516f, 0.244385f, 0.260742f, 0.277344f, 0.293213f,
+ 0.309570f, 0.326416f, 0.342773f, 0.358887f, 0.374512f, 0.391113f, 0.406982f, 0.423340f, 0.439453f, 0.455078f, 0.470947f, 0.487793f,
+ 0.502441f, 0.519043f, 0.533691f, 0.550293f, 0.564941f, 0.580078f, 0.595703f, 0.610840f, 0.625488f, 0.640137f, 0.654785f, 0.669434f,
+ 0.683594f, 0.696777f, 0.710938f, 0.725586f, 0.738770f, 0.752441f, 0.766113f, 0.778320f, 0.791016f, 0.805176f, 0.818359f, 0.830566f,
+ 0.842773f, 0.854980f, 0.920410f, 0.908203f, 0.896484f, 0.886230f, 0.877441f, 0.868652f, 0.005981f, 0.017914f, 0.030350f, 0.042908f,
+ 0.056213f, 0.069092f, 0.083008f, 0.096619f, 0.111084f, 0.124634f, 0.139526f, 0.154297f, 0.169312f, 0.184570f, 0.199951f, 0.215454f,
+ 0.230713f, 0.245728f, 0.261963f, 0.277588f, 0.293213f, 0.309326f, 0.325195f, 0.340820f, 0.356934f, 0.373047f, 0.388916f, 0.404785f,
+ 0.420410f, 0.436279f, 0.452148f, 0.468506f, 0.483154f, 0.499756f, 0.515137f, 0.530762f, 0.545898f, 0.560059f, 0.576172f, 0.590820f,
+ 0.606445f, 0.621094f, 0.635254f, 0.649902f, 0.663574f, 0.678223f, 0.692383f, 0.706543f, 0.720703f, 0.733887f, 0.748535f, 0.762695f,
+ 0.775391f, 0.789551f, 0.801758f, 0.814941f, 0.828125f, 0.840332f, 0.913574f, 0.902344f, 0.890625f, 0.881836f, 0.872559f, 0.865234f,
+ 0.005402f, 0.016617f, 0.028061f, 0.039948f, 0.051758f, 0.064270f, 0.076782f, 0.089600f, 0.102600f, 0.116455f, 0.130371f, 0.144165f,
+ 0.158936f, 0.172607f, 0.187744f, 0.201904f, 0.216431f, 0.232422f, 0.247192f, 0.261719f, 0.277100f, 0.292480f, 0.308838f, 0.323975f,
+ 0.339355f, 0.355469f, 0.371338f, 0.386230f, 0.402344f, 0.417725f, 0.433350f, 0.448486f, 0.464600f, 0.480225f, 0.495361f, 0.510742f,
+ 0.525879f, 0.541992f, 0.557129f, 0.571777f, 0.586914f, 0.601562f, 0.616211f, 0.631836f, 0.645508f, 0.661621f, 0.674805f, 0.688965f,
+ 0.703125f, 0.717773f, 0.731934f, 0.745605f, 0.757812f, 0.772949f, 0.785156f, 0.799316f, 0.812012f, 0.826172f, 0.906738f, 0.896484f,
+ 0.886230f, 0.876465f, 0.868164f, 0.860840f, 0.005264f, 0.015457f, 0.026474f, 0.037170f, 0.048157f, 0.059845f, 0.071594f, 0.083984f,
+ 0.096191f, 0.109070f, 0.121887f, 0.134766f, 0.148193f, 0.161255f, 0.175781f, 0.189209f, 0.203369f, 0.218384f, 0.233032f, 0.247681f,
+ 0.261963f, 0.277100f, 0.292480f, 0.307129f, 0.322998f, 0.337891f, 0.352539f, 0.368652f, 0.384033f, 0.399170f, 0.414307f, 0.430420f,
+ 0.445801f, 0.460693f, 0.475342f, 0.491211f, 0.506836f, 0.521973f, 0.537598f, 0.551758f, 0.567383f, 0.582520f, 0.598145f, 0.612305f,
+ 0.627441f, 0.642090f, 0.656738f, 0.670898f, 0.685059f, 0.698730f, 0.713867f, 0.728516f, 0.742188f, 0.755371f, 0.770020f, 0.782715f,
+ 0.796387f, 0.810547f, 0.899414f, 0.889648f, 0.879883f, 0.872070f, 0.863770f, 0.856445f, 0.004719f, 0.014229f, 0.024384f, 0.034607f,
+ 0.044708f, 0.055756f, 0.066895f, 0.077942f, 0.089600f, 0.101624f, 0.113525f, 0.125854f, 0.138428f, 0.151245f, 0.164673f, 0.177734f,
+ 0.191650f, 0.205078f, 0.219360f, 0.233154f, 0.247925f, 0.261475f, 0.276367f, 0.291504f, 0.305908f, 0.320312f, 0.335449f, 0.350098f,
+ 0.365723f, 0.380615f, 0.395996f, 0.411133f, 0.427002f, 0.441895f, 0.456543f, 0.472656f, 0.487793f, 0.502441f, 0.518555f, 0.533203f,
+ 0.547852f, 0.562988f, 0.577637f, 0.593262f, 0.607910f, 0.623535f, 0.638184f, 0.652344f, 0.666992f, 0.681641f, 0.696777f, 0.711426f,
+ 0.725098f, 0.738281f, 0.753418f, 0.766113f, 0.782227f, 0.794922f, 0.892090f, 0.884277f, 0.875000f, 0.866699f, 0.858887f, 0.852539f,
+ 0.004280f, 0.013329f, 0.022476f, 0.031982f, 0.042114f, 0.051849f, 0.062225f, 0.072449f, 0.083679f, 0.095032f, 0.105530f, 0.117676f,
+ 0.129517f, 0.141357f, 0.154297f, 0.166748f, 0.178711f, 0.192505f, 0.205933f, 0.219727f, 0.233521f, 0.247070f, 0.260986f, 0.275391f,
+ 0.290039f, 0.303955f, 0.319580f, 0.333740f, 0.347412f, 0.363037f, 0.377686f, 0.392822f, 0.408203f, 0.422852f, 0.437988f, 0.453125f,
+ 0.468506f, 0.483398f, 0.498779f, 0.514160f, 0.527832f, 0.543945f, 0.559570f, 0.574707f, 0.588867f, 0.604492f, 0.619141f, 0.634277f,
+ 0.648438f, 0.663086f, 0.678223f, 0.692383f, 0.707520f, 0.721680f, 0.735352f, 0.749512f, 0.764648f, 0.778320f, 0.884277f, 0.877441f,
+ 0.868652f, 0.861328f, 0.854492f, 0.847656f, 0.004280f, 0.012138f, 0.021103f, 0.029999f, 0.038940f, 0.048279f, 0.057831f, 0.067566f,
+ 0.077454f, 0.087524f, 0.098816f, 0.109558f, 0.120728f, 0.131958f, 0.143799f, 0.155762f, 0.168091f, 0.180176f, 0.193359f, 0.206177f,
+ 0.219360f, 0.232910f, 0.246338f, 0.260254f, 0.273682f, 0.287598f, 0.302246f, 0.316650f, 0.331299f, 0.344971f, 0.359863f, 0.374268f,
+ 0.389648f, 0.404297f, 0.419434f, 0.434326f, 0.449463f, 0.464844f, 0.479492f, 0.494141f, 0.509766f, 0.524414f, 0.540039f, 0.555176f,
+ 0.569824f, 0.584961f, 0.600098f, 0.615723f, 0.629883f, 0.645508f, 0.659668f, 0.675293f, 0.689453f, 0.704590f, 0.719238f, 0.732422f,
+ 0.748535f, 0.762207f, 0.876953f, 0.871582f, 0.863281f, 0.855957f, 0.849609f, 0.842773f, 0.003744f, 0.011436f, 0.019348f, 0.027893f,
+ 0.036102f, 0.044739f, 0.053711f, 0.063110f, 0.072205f, 0.081970f, 0.091919f, 0.101746f, 0.112732f, 0.122864f, 0.134521f, 0.145996f,
+ 0.157715f, 0.169434f, 0.181519f, 0.193848f, 0.206665f, 0.219360f, 0.231445f, 0.245361f, 0.259033f, 0.272217f, 0.286621f, 0.299805f,
+ 0.314209f, 0.328125f, 0.342285f, 0.357178f, 0.371826f, 0.386475f, 0.400635f, 0.415527f, 0.430420f, 0.445068f, 0.459717f, 0.476074f,
+ 0.490234f, 0.505371f, 0.521484f, 0.536133f, 0.551758f, 0.565430f, 0.581543f, 0.595703f, 0.611816f, 0.626465f, 0.641602f, 0.656738f,
+ 0.671875f, 0.686523f, 0.701172f, 0.715820f, 0.731445f, 0.746582f, 0.868652f, 0.864746f, 0.856934f, 0.851074f, 0.844727f, 0.837891f,
+ 0.003595f, 0.011093f, 0.018265f, 0.025711f, 0.033600f, 0.041656f, 0.050140f, 0.058350f, 0.067505f, 0.076416f, 0.085632f, 0.095093f,
+ 0.104919f, 0.115295f, 0.125610f, 0.136108f, 0.147583f, 0.157959f, 0.169800f, 0.181519f, 0.193359f, 0.205933f, 0.218140f, 0.231323f,
+ 0.243652f, 0.257324f, 0.270508f, 0.283447f, 0.297363f, 0.311523f, 0.325928f, 0.339111f, 0.353516f, 0.367432f, 0.382812f, 0.396973f,
+ 0.412109f, 0.426758f, 0.441406f, 0.456055f, 0.471436f, 0.486328f, 0.501953f, 0.516113f, 0.531738f, 0.546875f, 0.562500f, 0.577637f,
+ 0.592773f, 0.607910f, 0.622559f, 0.638184f, 0.653809f, 0.669434f, 0.684082f, 0.699219f, 0.714355f, 0.729492f, 0.860840f, 0.857422f,
+ 0.852051f, 0.844727f, 0.839355f, 0.832520f, 0.003349f, 0.009933f, 0.016754f, 0.024063f, 0.031204f, 0.038849f, 0.046356f, 0.054413f,
+ 0.062744f, 0.070984f, 0.080017f, 0.088989f, 0.097778f, 0.107361f, 0.117004f, 0.127197f, 0.137451f, 0.148071f, 0.159180f, 0.169922f,
+ 0.181519f, 0.192993f, 0.204956f, 0.217407f, 0.229980f, 0.242188f, 0.254883f, 0.267578f, 0.281494f, 0.294434f, 0.307861f, 0.321533f,
+ 0.335693f, 0.350098f, 0.364258f, 0.379150f, 0.393066f, 0.407715f, 0.422607f, 0.437500f, 0.452148f, 0.467041f, 0.482422f, 0.497314f,
+ 0.512695f, 0.527832f, 0.542969f, 0.558594f, 0.573730f, 0.589844f, 0.604004f, 0.619629f, 0.635254f, 0.651367f, 0.665527f, 0.681152f,
+ 0.696289f, 0.711914f, 0.852539f, 0.851562f, 0.846191f, 0.838867f, 0.832520f, 0.827637f, 0.003290f, 0.009415f, 0.015976f, 0.022095f,
+ 0.028946f, 0.036255f, 0.043396f, 0.050598f, 0.058502f, 0.066284f, 0.074036f, 0.082275f, 0.091187f, 0.099731f, 0.108826f, 0.118652f,
+ 0.128296f, 0.137939f, 0.148193f, 0.159302f, 0.170166f, 0.180786f, 0.191895f, 0.203491f, 0.215210f, 0.227661f, 0.240112f, 0.252686f,
+ 0.265625f, 0.278564f, 0.291748f, 0.305176f, 0.318604f, 0.332764f, 0.346924f, 0.360352f, 0.375000f, 0.389160f, 0.404297f, 0.418213f,
+ 0.433105f, 0.448486f, 0.463135f, 0.477783f, 0.493408f, 0.508301f, 0.523438f, 0.540039f, 0.554199f, 0.570312f, 0.585938f, 0.601074f,
+ 0.617188f, 0.633301f, 0.648926f, 0.664062f, 0.679688f, 0.695312f, 0.844727f, 0.844238f, 0.838867f, 0.833008f, 0.827148f, 0.822266f,
+ 0.002913f, 0.008621f, 0.014595f, 0.020950f, 0.027496f, 0.033600f, 0.040558f, 0.047119f, 0.054260f, 0.061615f, 0.068970f, 0.076782f,
+ 0.084717f, 0.093140f, 0.101562f, 0.109985f, 0.118591f, 0.129150f, 0.138306f, 0.148682f, 0.158447f, 0.169189f, 0.180054f, 0.191162f,
+ 0.202148f, 0.213379f, 0.225586f, 0.237305f, 0.250488f, 0.262939f, 0.275391f, 0.288086f, 0.302490f, 0.315186f, 0.329346f, 0.342529f,
+ 0.356934f, 0.370117f, 0.385742f, 0.400146f, 0.414795f, 0.429199f, 0.444336f, 0.459473f, 0.473389f, 0.489258f, 0.503906f, 0.519531f,
+ 0.535645f, 0.551270f, 0.566895f, 0.582520f, 0.598145f, 0.614258f, 0.629395f, 0.645996f, 0.661621f, 0.677734f, 0.837402f, 0.836914f,
+ 0.832520f, 0.826660f, 0.821777f, 0.816406f, 0.002748f, 0.008018f, 0.014168f, 0.019196f, 0.025040f, 0.031250f, 0.037506f, 0.043732f,
+ 0.050415f, 0.057098f, 0.063721f, 0.071167f, 0.078979f, 0.086609f, 0.094299f, 0.102783f, 0.111145f, 0.119812f, 0.128296f, 0.138306f,
+ 0.147583f, 0.157593f, 0.168213f, 0.178711f, 0.188843f, 0.200317f, 0.211792f, 0.223511f, 0.235352f, 0.247192f, 0.259521f, 0.272461f,
+ 0.285156f, 0.298584f, 0.312012f, 0.324707f, 0.339111f, 0.352783f, 0.366943f, 0.381348f, 0.395996f, 0.410889f, 0.425537f, 0.439941f,
+ 0.454834f, 0.470459f, 0.485352f, 0.501953f, 0.516113f, 0.531738f, 0.547363f, 0.563477f, 0.579102f, 0.595703f, 0.611328f, 0.626953f,
+ 0.642578f, 0.659668f, 0.828125f, 0.830566f, 0.825684f, 0.820801f, 0.815430f, 0.811035f, 0.002630f, 0.007412f, 0.012978f, 0.018356f,
+ 0.023758f, 0.028931f, 0.034729f, 0.040894f, 0.046631f, 0.053101f, 0.059143f, 0.065979f, 0.073669f, 0.080200f, 0.087585f, 0.095276f,
+ 0.102844f, 0.111633f, 0.119812f, 0.128296f, 0.137573f, 0.146729f, 0.156128f, 0.166382f, 0.176880f, 0.187256f, 0.197998f, 0.209351f,
+ 0.220581f, 0.232422f, 0.244385f, 0.256592f, 0.268799f, 0.281982f, 0.294922f, 0.308105f, 0.321045f, 0.334717f, 0.348633f, 0.363525f,
+ 0.378174f, 0.391846f, 0.406006f, 0.420898f, 0.436279f, 0.451660f, 0.466064f, 0.481934f, 0.496826f, 0.513184f, 0.528320f, 0.543945f,
+ 0.560059f, 0.576660f, 0.592285f, 0.608887f, 0.625000f, 0.640625f, 0.819336f, 0.822266f, 0.818848f, 0.813965f, 0.810059f, 0.805664f,
+ 0.002201f, 0.007240f, 0.011803f, 0.016617f, 0.021622f, 0.027344f, 0.032288f, 0.037598f, 0.043427f, 0.049194f, 0.055267f, 0.061462f,
+ 0.067566f, 0.073853f, 0.080872f, 0.088013f, 0.095703f, 0.103821f, 0.111145f, 0.119446f, 0.127563f, 0.136597f, 0.145752f, 0.155273f,
+ 0.165039f, 0.174683f, 0.185181f, 0.195801f, 0.206543f, 0.218140f, 0.229370f, 0.241455f, 0.253174f, 0.265381f, 0.278564f, 0.291504f,
+ 0.304199f, 0.317383f, 0.331299f, 0.344971f, 0.358643f, 0.373291f, 0.386963f, 0.402100f, 0.416016f, 0.431641f, 0.447266f, 0.462646f,
+ 0.477295f, 0.493652f, 0.509277f, 0.524902f, 0.541504f, 0.557617f, 0.574219f, 0.589844f, 0.605957f, 0.623047f, 0.810059f, 0.814453f,
+ 0.811035f, 0.807129f, 0.803223f, 0.798828f, 0.002293f, 0.006927f, 0.010994f, 0.015617f, 0.020584f, 0.025131f, 0.029663f, 0.034760f,
+ 0.040192f, 0.045532f, 0.050964f, 0.056793f, 0.062805f, 0.068726f, 0.074890f, 0.081482f, 0.088806f, 0.096069f, 0.103333f, 0.110535f,
+ 0.118896f, 0.126709f, 0.135254f, 0.144165f, 0.153442f, 0.162720f, 0.172119f, 0.182495f, 0.192749f, 0.203735f, 0.214600f, 0.225952f,
+ 0.237793f, 0.250000f, 0.261719f, 0.274170f, 0.287354f, 0.300293f, 0.313477f, 0.326904f, 0.340820f, 0.354980f, 0.369385f, 0.383545f,
+ 0.396973f, 0.411865f, 0.427734f, 0.442871f, 0.458740f, 0.473633f, 0.489502f, 0.505859f, 0.522461f, 0.537598f, 0.553711f, 0.572754f,
+ 0.588379f, 0.604492f, 0.802246f, 0.807617f, 0.804199f, 0.800781f, 0.797363f, 0.792969f, 0.002081f, 0.006172f, 0.010460f, 0.014503f,
+ 0.019104f, 0.023163f, 0.027832f, 0.032410f, 0.037354f, 0.041992f, 0.047211f, 0.052490f, 0.057831f, 0.063232f, 0.069458f, 0.075317f,
+ 0.082153f, 0.088257f, 0.094910f, 0.102295f, 0.110107f, 0.117554f, 0.125122f, 0.133667f, 0.142456f, 0.151001f, 0.160767f, 0.169922f,
+ 0.179443f, 0.190430f, 0.200562f, 0.211914f, 0.222412f, 0.234009f, 0.245850f, 0.258545f, 0.270752f, 0.283203f, 0.296387f, 0.309082f,
+ 0.322998f, 0.336670f, 0.350098f, 0.364990f, 0.378906f, 0.393311f, 0.408936f, 0.423096f, 0.438965f, 0.454834f, 0.470703f, 0.486572f,
+ 0.502441f, 0.518555f, 0.534668f, 0.551270f, 0.569336f, 0.585938f, 0.792480f, 0.799316f, 0.797363f, 0.793457f, 0.790039f, 0.786621f,
+ 0.002028f, 0.005669f, 0.009705f, 0.013565f, 0.017532f, 0.021286f, 0.025574f, 0.030197f, 0.034180f, 0.038757f, 0.043488f, 0.048737f,
+ 0.053497f, 0.058594f, 0.064026f, 0.070007f, 0.075623f, 0.081360f, 0.088135f, 0.094238f, 0.101379f, 0.108643f, 0.116028f, 0.123718f,
+ 0.131592f, 0.140137f, 0.149048f, 0.157715f, 0.167114f, 0.176636f, 0.187012f, 0.197388f, 0.208130f, 0.219238f, 0.230347f, 0.241943f,
+ 0.254150f, 0.266113f, 0.279053f, 0.291504f, 0.304932f, 0.318848f, 0.332031f, 0.345947f, 0.360107f, 0.375000f, 0.389404f, 0.404541f,
+ 0.419922f, 0.434814f, 0.450684f, 0.466553f, 0.482910f, 0.499023f, 0.516113f, 0.533203f, 0.550293f, 0.567383f, 0.783203f, 0.790527f,
+ 0.789551f, 0.786621f, 0.783691f, 0.780762f, 0.001852f, 0.005554f, 0.008957f, 0.012642f, 0.016296f, 0.020172f, 0.024033f, 0.027878f,
+ 0.031677f, 0.035919f, 0.040253f, 0.044952f, 0.049255f, 0.053955f, 0.058960f, 0.063965f, 0.069336f, 0.074951f, 0.080933f, 0.087219f,
+ 0.093201f, 0.100159f, 0.106689f, 0.114197f, 0.121521f, 0.129517f, 0.137817f, 0.146118f, 0.155151f, 0.164307f, 0.173462f, 0.183472f,
+ 0.193970f, 0.204224f, 0.215210f, 0.226562f, 0.238037f, 0.250244f, 0.262451f, 0.274902f, 0.287598f, 0.301025f, 0.314209f, 0.327393f,
+ 0.342041f, 0.356445f, 0.370850f, 0.385254f, 0.400879f, 0.415771f, 0.431396f, 0.446777f, 0.463379f, 0.480469f, 0.497314f, 0.514160f,
+ 0.530273f, 0.547363f, 0.774414f, 0.783203f, 0.782715f, 0.779297f, 0.776367f, 0.773438f, 0.001690f, 0.005207f, 0.008278f, 0.011696f,
+ 0.015068f, 0.018784f, 0.022186f, 0.025909f, 0.029221f, 0.033508f, 0.037109f, 0.041321f, 0.045471f, 0.049774f, 0.054108f, 0.058838f,
+ 0.063843f, 0.069214f, 0.074280f, 0.080078f, 0.086243f, 0.091980f, 0.098083f, 0.105164f, 0.111877f, 0.119446f, 0.126953f, 0.134888f,
+ 0.143555f, 0.151978f, 0.161133f, 0.170532f, 0.180176f, 0.189697f, 0.200684f, 0.211182f, 0.222412f, 0.234009f, 0.245972f, 0.257568f,
+ 0.270508f, 0.282959f, 0.295898f, 0.309570f, 0.323486f, 0.337158f, 0.351562f, 0.366211f, 0.381104f, 0.396729f, 0.411865f, 0.427490f,
+ 0.443604f, 0.459961f, 0.477051f, 0.494385f, 0.510742f, 0.529297f, 0.763184f, 0.774902f, 0.773438f, 0.771973f, 0.769043f, 0.767578f,
+ 0.001528f, 0.004692f, 0.007587f, 0.010956f, 0.014221f, 0.016907f, 0.020218f, 0.023407f, 0.027283f, 0.030273f, 0.033997f, 0.038055f,
+ 0.041809f, 0.045959f, 0.049683f, 0.053955f, 0.058838f, 0.063171f, 0.068176f, 0.073120f, 0.078491f, 0.084473f, 0.090332f, 0.096619f,
+ 0.102905f, 0.109619f, 0.116699f, 0.124207f, 0.131958f, 0.140503f, 0.148438f, 0.157349f, 0.166626f, 0.176392f, 0.186157f, 0.196045f,
+ 0.207031f, 0.218018f, 0.229736f, 0.241699f, 0.253174f, 0.265381f, 0.278320f, 0.291748f, 0.305176f, 0.318848f, 0.333496f, 0.347412f,
+ 0.362305f, 0.376709f, 0.392822f, 0.407715f, 0.424072f, 0.440430f, 0.457031f, 0.473633f, 0.491211f, 0.508789f, 0.753906f, 0.766602f,
+ 0.767090f, 0.764160f, 0.761719f, 0.759766f, 0.001261f, 0.004250f, 0.007389f, 0.010185f, 0.013023f, 0.015976f, 0.018692f, 0.021713f,
+ 0.024734f, 0.028183f, 0.031464f, 0.034943f, 0.038452f, 0.041870f, 0.045410f, 0.049561f, 0.054047f, 0.058044f, 0.062164f, 0.067017f,
+ 0.071838f, 0.077332f, 0.082581f, 0.088318f, 0.094360f, 0.100525f, 0.107117f, 0.114258f, 0.121643f, 0.128540f, 0.136841f, 0.144897f,
+ 0.153931f, 0.162476f, 0.171875f, 0.182007f, 0.192139f, 0.202637f, 0.213623f, 0.224854f, 0.237183f, 0.248657f, 0.260986f, 0.274170f,
+ 0.287354f, 0.300781f, 0.314453f, 0.328613f, 0.343018f, 0.358643f, 0.373291f, 0.388916f, 0.404785f, 0.420654f, 0.437744f, 0.454590f,
+ 0.471924f, 0.489990f, 0.744629f, 0.757812f, 0.757812f, 0.756836f, 0.754395f, 0.752441f, 0.001527f, 0.004047f, 0.006680f, 0.009369f,
+ 0.012024f, 0.014618f, 0.017288f, 0.020248f, 0.022705f, 0.025803f, 0.028778f, 0.031769f, 0.034912f, 0.038330f, 0.041595f, 0.045166f,
+ 0.048737f, 0.052673f, 0.056885f, 0.061218f, 0.065552f, 0.070251f, 0.075012f, 0.080505f, 0.086060f, 0.091614f, 0.097656f, 0.104065f,
+ 0.110901f, 0.118225f, 0.125366f, 0.133179f, 0.141357f, 0.149902f, 0.158569f, 0.168213f, 0.177734f, 0.187866f, 0.198364f, 0.208984f,
+ 0.220581f, 0.232422f, 0.244019f, 0.256836f, 0.269287f, 0.282471f, 0.296143f, 0.309326f, 0.324463f, 0.338379f, 0.353760f, 0.368652f,
+ 0.385498f, 0.400635f, 0.417725f, 0.434570f, 0.451660f, 0.469482f, 0.733887f, 0.749023f, 0.750977f, 0.749023f, 0.747070f, 0.744629f,
+ 0.001313f, 0.003803f, 0.006126f, 0.008507f, 0.011185f, 0.013550f, 0.015839f, 0.018219f, 0.021027f, 0.023438f, 0.026520f, 0.029129f,
+ 0.031738f, 0.034821f, 0.037964f, 0.041138f, 0.044434f, 0.048035f, 0.051636f, 0.055420f, 0.059540f, 0.063782f, 0.068176f, 0.073181f,
+ 0.077881f, 0.083496f, 0.088989f, 0.094849f, 0.101440f, 0.107849f, 0.114441f, 0.121887f, 0.129395f, 0.137207f, 0.145874f, 0.154419f,
+ 0.163574f, 0.173462f, 0.183228f, 0.193726f, 0.204712f, 0.216064f, 0.227661f, 0.239624f, 0.251709f, 0.264648f, 0.277832f, 0.291504f,
+ 0.305664f, 0.320312f, 0.334473f, 0.349854f, 0.365479f, 0.380615f, 0.397217f, 0.414551f, 0.432129f, 0.449951f, 0.722656f, 0.740234f,
+ 0.741699f, 0.741211f, 0.739746f, 0.737793f, 0.001137f, 0.003654f, 0.005871f, 0.007881f, 0.010262f, 0.012268f, 0.014496f, 0.017059f,
+ 0.018890f, 0.021317f, 0.023605f, 0.026291f, 0.029007f, 0.031494f, 0.034515f, 0.036987f, 0.040375f, 0.043457f, 0.046936f, 0.050385f,
+ 0.053925f, 0.058044f, 0.061981f, 0.066650f, 0.070679f, 0.075562f, 0.080994f, 0.085938f, 0.091919f, 0.098450f, 0.104370f, 0.110840f,
+ 0.118164f, 0.125366f, 0.133301f, 0.141357f, 0.150024f, 0.159546f, 0.168457f, 0.178711f, 0.189453f, 0.199707f, 0.211060f, 0.222656f,
+ 0.234741f, 0.247314f, 0.260010f, 0.272705f, 0.287354f, 0.300781f, 0.315674f, 0.330322f, 0.345947f, 0.362061f, 0.377441f, 0.394775f,
+ 0.412109f, 0.429199f, 0.712891f, 0.730957f, 0.733398f, 0.733398f, 0.731445f, 0.729492f, 0.001163f, 0.003218f, 0.005329f, 0.007542f,
+ 0.009331f, 0.011330f, 0.013367f, 0.015434f, 0.017685f, 0.019714f, 0.021515f, 0.024139f, 0.026062f, 0.028763f, 0.031204f, 0.033722f,
+ 0.036163f, 0.039398f, 0.041992f, 0.045624f, 0.048553f, 0.051971f, 0.056000f, 0.059937f, 0.063904f, 0.068054f, 0.072876f, 0.077820f,
+ 0.083374f, 0.088623f, 0.094116f, 0.100830f, 0.107117f, 0.114197f, 0.121399f, 0.129272f, 0.136963f, 0.145630f, 0.154785f, 0.163696f,
+ 0.173828f, 0.184204f, 0.194946f, 0.205933f, 0.217529f, 0.229614f, 0.242676f, 0.255859f, 0.269043f, 0.282471f, 0.296387f, 0.311523f,
+ 0.326172f, 0.341553f, 0.357910f, 0.374756f, 0.391846f, 0.409180f, 0.701660f, 0.721680f, 0.723633f, 0.724609f, 0.723145f, 0.722656f,
+ 0.001008f, 0.003147f, 0.004818f, 0.006882f, 0.008530f, 0.010468f, 0.012390f, 0.013832f, 0.016006f, 0.017899f, 0.019608f, 0.021866f,
+ 0.023849f, 0.025940f, 0.027847f, 0.030350f, 0.032806f, 0.035187f, 0.037994f, 0.040619f, 0.043732f, 0.046875f, 0.050110f, 0.053833f,
+ 0.057617f, 0.061371f, 0.065613f, 0.070068f, 0.074768f, 0.079895f, 0.085144f, 0.090637f, 0.096863f, 0.103149f, 0.110107f, 0.116943f,
+ 0.124634f, 0.132568f, 0.140991f, 0.149536f, 0.159302f, 0.169189f, 0.179443f, 0.189575f, 0.201538f, 0.213013f, 0.225342f, 0.236938f,
+ 0.250244f, 0.264160f, 0.278320f, 0.292236f, 0.307617f, 0.322021f, 0.337891f, 0.354248f, 0.371582f, 0.389160f, 0.689941f, 0.712891f,
+ 0.715820f, 0.715820f, 0.715820f, 0.714355f, 0.001126f, 0.002708f, 0.004486f, 0.006313f, 0.007927f, 0.009659f, 0.011238f, 0.012833f,
+ 0.014435f, 0.015823f, 0.017670f, 0.019485f, 0.021347f, 0.023453f, 0.025101f, 0.027161f, 0.029160f, 0.031525f, 0.033752f, 0.036560f,
+ 0.039154f, 0.041687f, 0.044891f, 0.047943f, 0.051453f, 0.054871f, 0.058655f, 0.062622f, 0.067078f, 0.071411f, 0.076355f, 0.081665f,
+ 0.086792f, 0.092957f, 0.098877f, 0.105713f, 0.112549f, 0.119995f, 0.127563f, 0.135864f, 0.144897f, 0.154297f, 0.164185f, 0.173828f,
+ 0.185059f, 0.196045f, 0.208008f, 0.219849f, 0.232666f, 0.245483f, 0.259033f, 0.273438f, 0.287842f, 0.302734f, 0.318604f, 0.334473f,
+ 0.351318f, 0.369385f, 0.679688f, 0.702637f, 0.707031f, 0.707031f, 0.707031f, 0.705566f, 0.000980f, 0.002733f, 0.004021f, 0.005688f,
+ 0.007084f, 0.008553f, 0.010345f, 0.011513f, 0.012962f, 0.014297f, 0.015823f, 0.017609f, 0.019119f, 0.020721f, 0.022568f, 0.024200f,
+ 0.026291f, 0.028000f, 0.030457f, 0.032410f, 0.034912f, 0.037476f, 0.039734f, 0.042786f, 0.045563f, 0.048920f, 0.052185f, 0.055817f,
+ 0.059662f, 0.063660f, 0.067993f, 0.072632f, 0.077759f, 0.083191f, 0.088623f, 0.094971f, 0.101135f, 0.107849f, 0.115479f, 0.122864f,
+ 0.131592f, 0.139893f, 0.149414f, 0.158447f, 0.169067f, 0.179443f, 0.191040f, 0.202393f, 0.214478f, 0.227539f, 0.240723f, 0.255127f,
+ 0.268555f, 0.283447f, 0.298828f, 0.315186f, 0.331787f, 0.348389f, 0.667480f, 0.693359f, 0.697754f, 0.698730f, 0.698242f, 0.697754f,
+ 0.000870f, 0.002420f, 0.003994f, 0.005165f, 0.006584f, 0.007763f, 0.009209f, 0.010468f, 0.011604f, 0.013336f, 0.013977f, 0.015442f,
+ 0.016830f, 0.018509f, 0.020065f, 0.021606f, 0.023224f, 0.024933f, 0.026672f, 0.028656f, 0.030914f, 0.033112f, 0.035187f, 0.037689f,
+ 0.040344f, 0.043335f, 0.046234f, 0.049438f, 0.052948f, 0.056427f, 0.060394f, 0.064331f, 0.069031f, 0.073853f, 0.078735f, 0.084412f,
+ 0.090271f, 0.096436f, 0.103455f, 0.110229f, 0.118042f, 0.126099f, 0.134766f, 0.143921f, 0.153198f, 0.163696f, 0.174438f, 0.185913f,
+ 0.197754f, 0.210083f, 0.222778f, 0.235962f, 0.250000f, 0.264648f, 0.279053f, 0.294922f, 0.311279f, 0.328613f, 0.655273f, 0.684082f,
+ 0.688477f, 0.689941f, 0.689941f, 0.689941f, 0.000790f, 0.002153f, 0.003576f, 0.004726f, 0.005966f, 0.007172f, 0.008186f, 0.009453f,
+ 0.010521f, 0.011482f, 0.012772f, 0.013771f, 0.015144f, 0.016434f, 0.017792f, 0.019226f, 0.020355f, 0.022049f, 0.023666f, 0.025375f,
+ 0.027145f, 0.029297f, 0.030975f, 0.033142f, 0.035339f, 0.037964f, 0.040405f, 0.043365f, 0.046478f, 0.049744f, 0.053101f, 0.057068f,
+ 0.060944f, 0.065063f, 0.069763f, 0.074646f, 0.079956f, 0.085938f, 0.091675f, 0.098083f, 0.105164f, 0.112732f, 0.121033f, 0.129395f,
+ 0.138428f, 0.148560f, 0.158325f, 0.169067f, 0.180664f, 0.192139f, 0.205078f, 0.217529f, 0.231934f, 0.246094f, 0.260010f, 0.275391f,
+ 0.292236f, 0.309570f, 0.644043f, 0.673340f, 0.678711f, 0.680664f, 0.680664f, 0.680176f, 0.000538f, 0.002022f, 0.003185f, 0.004456f,
+ 0.005360f, 0.006321f, 0.007286f, 0.008484f, 0.009422f, 0.010185f, 0.011177f, 0.012283f, 0.013191f, 0.014435f, 0.015587f, 0.016769f,
+ 0.017914f, 0.019302f, 0.020584f, 0.022171f, 0.023819f, 0.025391f, 0.027222f, 0.028992f, 0.030914f, 0.033234f, 0.035461f, 0.037903f,
+ 0.040649f, 0.043396f, 0.046326f, 0.049561f, 0.053131f, 0.056946f, 0.061279f, 0.065613f, 0.070374f, 0.075439f, 0.080811f, 0.086731f,
+ 0.093140f, 0.100037f, 0.107544f, 0.115662f, 0.124023f, 0.132935f, 0.143066f, 0.153320f, 0.163696f, 0.175415f, 0.187012f, 0.200195f,
+ 0.213013f, 0.227173f, 0.241455f, 0.256592f, 0.272461f, 0.288330f, 0.632812f, 0.663574f, 0.669434f, 0.670898f, 0.671387f, 0.671875f,
+ 0.000686f, 0.001864f, 0.002884f, 0.003883f, 0.004829f, 0.005592f, 0.006504f, 0.007454f, 0.008064f, 0.008995f, 0.009850f, 0.010948f,
+ 0.011711f, 0.012581f, 0.013763f, 0.014618f, 0.015701f, 0.016953f, 0.018112f, 0.019180f, 0.020691f, 0.021973f, 0.023560f, 0.025192f,
+ 0.026962f, 0.028717f, 0.030624f, 0.032959f, 0.035004f, 0.037567f, 0.040314f, 0.043121f, 0.046204f, 0.049713f, 0.053284f, 0.057129f,
+ 0.061157f, 0.065796f, 0.071167f, 0.076477f, 0.082214f, 0.088379f, 0.095276f, 0.102600f, 0.110596f, 0.118652f, 0.127808f, 0.137817f,
+ 0.147705f, 0.158569f, 0.170166f, 0.182251f, 0.195068f, 0.208008f, 0.222656f, 0.237671f, 0.252686f, 0.269287f, 0.620605f, 0.653320f,
+ 0.659180f, 0.661621f, 0.663086f, 0.663574f, 0.000782f, 0.001828f, 0.002949f, 0.003487f, 0.004421f, 0.005032f, 0.005878f, 0.006557f,
+ 0.007332f, 0.008110f, 0.008591f, 0.009537f, 0.010094f, 0.011147f, 0.011864f, 0.012779f, 0.013573f, 0.014549f, 0.015625f, 0.016846f,
+ 0.017822f, 0.018936f, 0.020279f, 0.021729f, 0.023117f, 0.024704f, 0.026505f, 0.028183f, 0.030289f, 0.032349f, 0.034546f, 0.037109f,
+ 0.039703f, 0.042786f, 0.045837f, 0.049133f, 0.053009f, 0.056763f, 0.061584f, 0.066284f, 0.071411f, 0.076843f, 0.083191f, 0.089722f,
+ 0.097290f, 0.104919f, 0.113647f, 0.122498f, 0.132324f, 0.142578f, 0.153809f, 0.164917f, 0.177612f, 0.190430f, 0.203857f, 0.218506f,
+ 0.233887f, 0.249390f, 0.606934f, 0.642578f, 0.649414f, 0.653320f, 0.652832f, 0.654785f, 0.000604f, 0.001636f, 0.002550f, 0.003180f,
+ 0.003799f, 0.004498f, 0.005051f, 0.005573f, 0.006325f, 0.006836f, 0.007607f, 0.008087f, 0.008820f, 0.009483f, 0.010132f, 0.010918f,
+ 0.011665f, 0.012527f, 0.013535f, 0.014297f, 0.015251f, 0.016190f, 0.017288f, 0.018433f, 0.019791f, 0.021133f, 0.022400f, 0.023865f,
+ 0.025742f, 0.027664f, 0.029373f, 0.031677f, 0.034027f, 0.036255f, 0.039032f, 0.042023f, 0.045197f, 0.048798f, 0.052643f, 0.056824f,
+ 0.061493f, 0.066467f, 0.072327f, 0.078308f, 0.084473f, 0.091858f, 0.099609f, 0.108032f, 0.117249f, 0.126831f, 0.137451f, 0.148193f,
+ 0.160034f, 0.172729f, 0.186035f, 0.199829f, 0.214722f, 0.229980f, 0.596680f, 0.632812f, 0.638672f, 0.642578f, 0.644531f, 0.645020f,
+ 0.000447f, 0.001384f, 0.001986f, 0.002697f, 0.003225f, 0.003828f, 0.004501f, 0.005009f, 0.005459f, 0.006027f, 0.006474f, 0.006935f,
+ 0.007591f, 0.008217f, 0.008644f, 0.009308f, 0.010025f, 0.010498f, 0.011330f, 0.012100f, 0.012909f, 0.013924f, 0.014618f, 0.015610f,
+ 0.016739f, 0.017807f, 0.019043f, 0.020340f, 0.021622f, 0.023178f, 0.024979f, 0.026520f, 0.028366f, 0.030640f, 0.032959f, 0.035492f,
+ 0.038239f, 0.041260f, 0.044495f, 0.048340f, 0.052399f, 0.056732f, 0.061768f, 0.067017f, 0.072754f, 0.079224f, 0.086304f, 0.093994f,
+ 0.102478f, 0.111511f, 0.121521f, 0.132080f, 0.143311f, 0.155518f, 0.168213f, 0.181763f, 0.196411f, 0.211548f, 0.583008f, 0.621094f,
+ 0.629395f, 0.632324f, 0.634766f, 0.635742f, 0.000375f, 0.001324f, 0.001728f, 0.002466f, 0.002872f, 0.003384f, 0.003685f, 0.004185f,
+ 0.004845f, 0.005184f, 0.005444f, 0.006130f, 0.006401f, 0.006844f, 0.007446f, 0.007957f, 0.008636f, 0.008965f, 0.009659f, 0.010139f,
+ 0.010971f, 0.011742f, 0.012497f, 0.013138f, 0.014099f, 0.014992f, 0.015900f, 0.017166f, 0.018143f, 0.019485f, 0.020676f, 0.022156f,
+ 0.023697f, 0.025528f, 0.027374f, 0.029556f, 0.031921f, 0.034424f, 0.037445f, 0.040375f, 0.044067f, 0.047577f, 0.052155f, 0.056824f,
+ 0.062042f, 0.067688f, 0.074158f, 0.081055f, 0.088745f, 0.097351f, 0.106323f, 0.116455f, 0.127075f, 0.138672f, 0.151123f, 0.164062f,
+ 0.177856f, 0.192871f, 0.570801f, 0.610840f, 0.619629f, 0.623047f, 0.625488f, 0.625977f, 0.000432f, 0.000921f, 0.001664f, 0.002056f,
+ 0.002697f, 0.003061f, 0.003326f, 0.003757f, 0.004044f, 0.004379f, 0.004761f, 0.004948f, 0.005463f, 0.005791f, 0.006199f, 0.006752f,
+ 0.007229f, 0.007526f, 0.008156f, 0.008621f, 0.009193f, 0.009712f, 0.010330f, 0.010994f, 0.011688f, 0.012466f, 0.013374f, 0.014153f,
+ 0.015099f, 0.016083f, 0.017212f, 0.018250f, 0.019623f, 0.021210f, 0.022614f, 0.024445f, 0.026321f, 0.028351f, 0.030762f, 0.033325f,
+ 0.036377f, 0.039642f, 0.043304f, 0.047485f, 0.051880f, 0.056885f, 0.062469f, 0.068542f, 0.075623f, 0.083374f, 0.091919f, 0.101135f,
+ 0.111389f, 0.122559f, 0.134277f, 0.146606f, 0.160278f, 0.174683f, 0.557617f, 0.600098f, 0.609375f, 0.612793f, 0.615723f, 0.616699f,
+ 0.000255f, 0.000997f, 0.001393f, 0.001908f, 0.002239f, 0.002512f, 0.002720f, 0.003166f, 0.003283f, 0.003616f, 0.003866f, 0.004223f,
+ 0.004597f, 0.004795f, 0.005127f, 0.005573f, 0.005939f, 0.006359f, 0.006657f, 0.007133f, 0.007687f, 0.008041f, 0.008545f, 0.009087f,
+ 0.009636f, 0.010300f, 0.010910f, 0.011757f, 0.012489f, 0.013313f, 0.014153f, 0.014954f, 0.016037f, 0.017258f, 0.018555f, 0.019867f,
+ 0.021530f, 0.023239f, 0.025055f, 0.027252f, 0.029663f, 0.032379f, 0.035339f, 0.038666f, 0.042664f, 0.047058f, 0.051849f, 0.057465f,
+ 0.063416f, 0.070557f, 0.078369f, 0.086731f, 0.096313f, 0.106384f, 0.117798f, 0.129761f, 0.143311f, 0.156982f, 0.544922f, 0.588867f,
+ 0.599121f, 0.602539f, 0.605469f, 0.606445f, 0.000353f, 0.000879f, 0.001276f, 0.001613f, 0.001785f, 0.002075f, 0.002300f, 0.002501f,
+ 0.002808f, 0.003010f, 0.003283f, 0.003487f, 0.003714f, 0.003967f, 0.004269f, 0.004597f, 0.004837f, 0.005230f, 0.005512f, 0.005878f,
+ 0.006203f, 0.006626f, 0.007030f, 0.007519f, 0.007866f, 0.008354f, 0.009010f, 0.009468f, 0.010017f, 0.010765f, 0.011444f, 0.012291f,
+ 0.013100f, 0.014030f, 0.015030f, 0.016098f, 0.017441f, 0.018646f, 0.020157f, 0.021912f, 0.023804f, 0.026047f, 0.028488f, 0.031342f,
+ 0.034424f, 0.037994f, 0.042206f, 0.046997f, 0.052338f, 0.058533f, 0.065369f, 0.073364f, 0.081787f, 0.091492f, 0.102356f, 0.113647f,
+ 0.126343f, 0.139526f, 0.531250f, 0.579102f, 0.587891f, 0.592773f, 0.595703f, 0.596680f, 0.000295f, 0.000784f, 0.000912f, 0.001261f,
+ 0.001517f, 0.001761f, 0.001893f, 0.002113f, 0.002211f, 0.002432f, 0.002676f, 0.002861f, 0.002993f, 0.003294f, 0.003479f, 0.003700f,
+ 0.003933f, 0.004242f, 0.004452f, 0.004745f, 0.004974f, 0.005428f, 0.005642f, 0.006081f, 0.006401f, 0.006817f, 0.007240f, 0.007641f,
+ 0.008209f, 0.008667f, 0.009361f, 0.009720f, 0.010506f, 0.011261f, 0.012024f, 0.012794f, 0.013840f, 0.014893f, 0.016113f, 0.017395f,
+ 0.018860f, 0.020493f, 0.022446f, 0.024658f, 0.027283f, 0.030228f, 0.033691f, 0.037659f, 0.042145f, 0.047546f, 0.053467f, 0.060547f,
+ 0.068359f, 0.077332f, 0.087158f, 0.098145f, 0.109741f, 0.123230f, 0.517090f, 0.566895f, 0.576660f, 0.581543f, 0.584961f, 0.587402f,
+ 0.000247f, 0.000702f, 0.000849f, 0.001033f, 0.001304f, 0.001416f, 0.001576f, 0.001754f, 0.001860f, 0.001953f, 0.002104f, 0.002327f,
+ 0.002419f, 0.002651f, 0.002785f, 0.003014f, 0.003134f, 0.003315f, 0.003584f, 0.003813f, 0.004078f, 0.004295f, 0.004555f, 0.004784f,
+ 0.005013f, 0.005329f, 0.005669f, 0.006069f, 0.006439f, 0.006821f, 0.007381f, 0.007797f, 0.008301f, 0.008812f, 0.009430f, 0.010139f,
+ 0.010948f, 0.011642f, 0.012573f, 0.013664f, 0.014671f, 0.016052f, 0.017502f, 0.019135f, 0.021255f, 0.023438f, 0.026199f, 0.029312f,
+ 0.033203f, 0.037476f, 0.042725f, 0.048828f, 0.055695f, 0.063721f, 0.072937f, 0.082947f, 0.094666f, 0.107117f, 0.504883f, 0.555664f,
+ 0.566406f, 0.572754f, 0.574707f, 0.577148f, 0.000217f, 0.000516f, 0.000750f, 0.000898f, 0.001011f, 0.001117f, 0.001203f, 0.001307f,
+ 0.001470f, 0.001604f, 0.001659f, 0.001750f, 0.001945f, 0.002121f, 0.002249f, 0.002316f, 0.002478f, 0.002581f, 0.002832f, 0.003000f,
+ 0.003164f, 0.003334f, 0.003593f, 0.003784f, 0.003990f, 0.004196f, 0.004440f, 0.004673f, 0.005035f, 0.005329f, 0.005642f, 0.005981f,
+ 0.006462f, 0.006916f, 0.007313f, 0.007805f, 0.008377f, 0.008987f, 0.009727f, 0.010521f, 0.011314f, 0.012421f, 0.013466f, 0.014755f,
+ 0.016235f, 0.017914f, 0.019913f, 0.022461f, 0.025330f, 0.028778f, 0.033081f, 0.038239f, 0.044189f, 0.051422f, 0.059662f, 0.069336f,
+ 0.080200f, 0.091980f, 0.492676f, 0.543945f, 0.555664f, 0.561035f, 0.564453f, 0.566406f, 0.000131f, 0.000355f, 0.000605f, 0.000759f,
+ 0.000832f, 0.000904f, 0.001018f, 0.000975f, 0.001144f, 0.001235f, 0.001336f, 0.001447f, 0.001518f, 0.001620f, 0.001668f, 0.001835f,
+ 0.001901f, 0.002045f, 0.002188f, 0.002270f, 0.002424f, 0.002577f, 0.002707f, 0.002893f, 0.003002f, 0.003223f, 0.003407f, 0.003572f,
+ 0.003851f, 0.004017f, 0.004391f, 0.004608f, 0.004833f, 0.005203f, 0.005497f, 0.005886f, 0.006351f, 0.006771f, 0.007278f, 0.007858f,
+ 0.008560f, 0.009315f, 0.010086f, 0.011078f, 0.012222f, 0.013443f, 0.015022f, 0.016769f, 0.018967f, 0.021591f, 0.024780f, 0.028931f,
+ 0.033875f, 0.039734f, 0.047241f, 0.056122f, 0.066101f, 0.077637f, 0.477783f, 0.532715f, 0.544922f, 0.551270f, 0.553711f, 0.555664f,
+ 0.000245f, 0.000303f, 0.000473f, 0.000498f, 0.000544f, 0.000707f, 0.000700f, 0.000767f, 0.000802f, 0.000892f, 0.001021f, 0.001086f,
+ 0.001140f, 0.001260f, 0.001303f, 0.001325f, 0.001462f, 0.001553f, 0.001603f, 0.001746f, 0.001816f, 0.001904f, 0.002043f, 0.002127f,
+ 0.002254f, 0.002356f, 0.002548f, 0.002672f, 0.002851f, 0.003092f, 0.003265f, 0.003374f, 0.003647f, 0.003891f, 0.004097f, 0.004360f,
+ 0.004669f, 0.004997f, 0.005390f, 0.005810f, 0.006226f, 0.006756f, 0.007450f, 0.008095f, 0.008934f, 0.009827f, 0.010902f, 0.012268f,
+ 0.013840f, 0.015701f, 0.018036f, 0.021072f, 0.024948f, 0.029800f, 0.035980f, 0.043945f, 0.053345f, 0.063843f, 0.465576f, 0.520996f,
+ 0.535645f, 0.540039f, 0.543457f, 0.545898f, 0.000108f, 0.000275f, 0.000332f, 0.000402f, 0.000462f, 0.000468f, 0.000580f, 0.000522f,
+ 0.000616f, 0.000657f, 0.000758f, 0.000762f, 0.000812f, 0.000870f, 0.000945f, 0.000978f, 0.001054f, 0.001109f, 0.001179f, 0.001213f,
+ 0.001311f, 0.001371f, 0.001473f, 0.001558f, 0.001629f, 0.001718f, 0.001837f, 0.001903f, 0.002016f, 0.002159f, 0.002258f, 0.002478f,
+ 0.002548f, 0.002731f, 0.002909f, 0.003086f, 0.003317f, 0.003580f, 0.003885f, 0.004116f, 0.004421f, 0.004818f, 0.005264f, 0.005745f,
+ 0.006294f, 0.006966f, 0.007748f, 0.008667f, 0.009766f, 0.011086f, 0.012787f, 0.014908f, 0.017746f, 0.021271f, 0.026382f, 0.032990f,
+ 0.041199f, 0.051239f, 0.452393f, 0.509277f, 0.522461f, 0.529297f, 0.533203f, 0.535156f, 0.000016f, 0.000143f, 0.000244f, 0.000315f,
+ 0.000309f, 0.000391f, 0.000344f, 0.000402f, 0.000429f, 0.000517f, 0.000522f, 0.000526f, 0.000546f, 0.000606f, 0.000628f, 0.000705f,
+ 0.000692f, 0.000781f, 0.000837f, 0.000868f, 0.000923f, 0.000969f, 0.001013f, 0.001070f, 0.001142f, 0.001186f, 0.001273f, 0.001326f,
+ 0.001397f, 0.001534f, 0.001561f, 0.001685f, 0.001775f, 0.001873f, 0.002024f, 0.002153f, 0.002272f, 0.002443f, 0.002611f, 0.002800f,
+ 0.003014f, 0.003250f, 0.003529f, 0.003868f, 0.004227f, 0.004692f, 0.005192f, 0.005836f, 0.006603f, 0.007587f, 0.008751f, 0.010193f,
+ 0.012001f, 0.014610f, 0.018219f, 0.023392f, 0.030594f, 0.039795f, 0.437744f, 0.498291f, 0.512207f, 0.517578f, 0.521484f, 0.525391f,
+ 0.000102f, 0.000186f, 0.000171f, 0.000181f, 0.000227f, 0.000229f, 0.000231f, 0.000278f, 0.000293f, 0.000304f, 0.000314f, 0.000375f,
+ 0.000365f, 0.000411f, 0.000446f, 0.000457f, 0.000496f, 0.000513f, 0.000533f, 0.000554f, 0.000603f, 0.000622f, 0.000669f, 0.000708f,
+ 0.000757f, 0.000789f, 0.000843f, 0.000875f, 0.000925f, 0.000964f, 0.001037f, 0.001094f, 0.001172f, 0.001243f, 0.001324f, 0.001373f,
+ 0.001497f, 0.001570f, 0.001712f, 0.001829f, 0.001947f, 0.002123f, 0.002291f, 0.002472f, 0.002703f, 0.003008f, 0.003342f, 0.003757f,
+ 0.004204f, 0.004810f, 0.005539f, 0.006554f, 0.007828f, 0.009537f, 0.011894f, 0.015442f, 0.021072f, 0.029282f, 0.424561f, 0.486084f,
+ 0.500488f, 0.506836f, 0.512207f, 0.514648f, 0.000014f, 0.000127f, 0.000112f, 0.000109f, 0.000143f, 0.000165f, 0.000141f, 0.000180f,
+ 0.000185f, 0.000191f, 0.000196f, 0.000203f, 0.000233f, 0.000252f, 0.000260f, 0.000274f, 0.000288f, 0.000314f, 0.000328f, 0.000363f,
+ 0.000362f, 0.000374f, 0.000400f, 0.000436f, 0.000464f, 0.000501f, 0.000504f, 0.000521f, 0.000563f, 0.000593f, 0.000635f, 0.000671f,
+ 0.000712f, 0.000740f, 0.000800f, 0.000837f, 0.000892f, 0.000955f, 0.001030f, 0.001092f, 0.001167f, 0.001270f, 0.001369f, 0.001491f,
+ 0.001626f, 0.001769f, 0.001993f, 0.002209f, 0.002523f, 0.002863f, 0.003325f, 0.003880f, 0.004715f, 0.005764f, 0.007320f, 0.009468f,
+ 0.013344f, 0.020187f, 0.410645f, 0.473877f, 0.489258f, 0.496826f, 0.500488f, 0.503906f, 0.000103f, 0.000078f, 0.000067f, 0.000065f,
+ 0.000086f, 0.000085f, 0.000101f, 0.000106f, 0.000106f, 0.000107f, 0.000115f, 0.000133f, 0.000118f, 0.000133f, 0.000154f, 0.000150f,
+ 0.000167f, 0.000177f, 0.000180f, 0.000190f, 0.000207f, 0.000213f, 0.000228f, 0.000238f, 0.000267f, 0.000277f, 0.000287f, 0.000298f,
+ 0.000313f, 0.000325f, 0.000347f, 0.000375f, 0.000393f, 0.000405f, 0.000440f, 0.000463f, 0.000486f, 0.000527f, 0.000562f, 0.000599f,
+ 0.000639f, 0.000688f, 0.000757f, 0.000807f, 0.000879f, 0.000961f, 0.001059f, 0.001180f, 0.001342f, 0.001533f, 0.001762f, 0.002102f,
+ 0.002502f, 0.003128f, 0.004028f, 0.005379f, 0.007591f, 0.012505f, 0.397217f, 0.462891f, 0.478760f, 0.485840f, 0.490479f, 0.492676f,
+ 0.000087f, 0.000063f, 0.000054f, 0.000048f, 0.000047f, 0.000044f, 0.000046f, 0.000047f, 0.000047f, 0.000060f, 0.000053f, 0.000056f,
+ 0.000072f, 0.000060f, 0.000064f, 0.000069f, 0.000078f, 0.000085f, 0.000084f, 0.000090f, 0.000094f, 0.000102f, 0.000105f, 0.000111f,
+ 0.000116f, 0.000126f, 0.000132f, 0.000150f, 0.000147f, 0.000158f, 0.000167f, 0.000178f, 0.000185f, 0.000192f, 0.000211f, 0.000216f,
+ 0.000226f, 0.000246f, 0.000265f, 0.000284f, 0.000299f, 0.000325f, 0.000349f, 0.000381f, 0.000415f, 0.000448f, 0.000490f, 0.000544f,
+ 0.000612f, 0.000694f, 0.000798f, 0.000943f, 0.001139f, 0.001436f, 0.001870f, 0.002586f, 0.003817f, 0.006474f, 0.383545f, 0.450195f,
+ 0.467041f, 0.474365f, 0.478760f, 0.482422f, 0.000065f, 0.000045f, 0.000037f, 0.000033f, 0.000030f, 0.000028f, 0.000026f, 0.000025f,
+ 0.000024f, 0.000022f, 0.000021f, 0.000025f, 0.000020f, 0.000021f, 0.000025f, 0.000029f, 0.000028f, 0.000031f, 0.000033f, 0.000034f,
+ 0.000036f, 0.000041f, 0.000045f, 0.000040f, 0.000045f, 0.000049f, 0.000051f, 0.000048f, 0.000055f, 0.000057f, 0.000061f, 0.000066f,
+ 0.000072f, 0.000068f, 0.000073f, 0.000078f, 0.000087f, 0.000089f, 0.000097f, 0.000104f, 0.000113f, 0.000115f, 0.000128f, 0.000137f,
+ 0.000148f, 0.000160f, 0.000174f, 0.000194f, 0.000221f, 0.000248f, 0.000283f, 0.000324f, 0.000396f, 0.000496f, 0.000657f, 0.000928f,
+ 0.001479f, 0.002684f, 0.371094f, 0.438477f, 0.455078f, 0.463867f, 0.468750f, 0.471191f, 0.000029f, 0.000019f, 0.000016f, 0.000014f,
+ 0.000014f, 0.000013f, 0.000012f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000010f,
+ 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000008f, 0.000007f, 0.000008f, 0.000007f, 0.000008f, 0.000009f, 0.000010f, 0.000011f,
+ 0.000012f, 0.000011f, 0.000012f, 0.000013f, 0.000015f, 0.000017f, 0.000018f, 0.000018f, 0.000020f, 0.000019f, 0.000021f, 0.000024f,
+ 0.000024f, 0.000026f, 0.000028f, 0.000031f, 0.000031f, 0.000035f, 0.000040f, 0.000041f, 0.000045f, 0.000052f, 0.000059f, 0.000071f,
+ 0.000083f, 0.000099f, 0.000132f, 0.000188f, 0.000315f, 0.000712f, 0.356934f, 0.426514f, 0.444824f, 0.452637f, 0.457520f, 0.460938f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000001f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000003f, 0.000004f, 0.000004f, 0.000006f, 0.000010f, 0.000027f, 0.343750f, 0.414795f,
+ 0.433105f, 0.441895f, 0.446289f, 0.449951f,
+ },
+ {
+ 0.012436f, 0.037598f, 0.062805f, 0.087891f, 0.113037f, 0.137329f, 0.161621f, 0.185425f, 0.209717f, 0.232544f, 0.255371f, 0.278076f,
+ 0.300049f, 0.321289f, 0.343506f, 0.364014f, 0.385010f, 0.404785f, 0.424561f, 0.444824f, 0.463623f, 0.482422f, 0.501465f, 0.520020f,
+ 0.537598f, 0.554688f, 0.572266f, 0.589355f, 0.605957f, 0.622070f, 0.639648f, 0.655273f, 0.670410f, 0.685547f, 0.700684f, 0.715332f,
+ 0.730469f, 0.744629f, 0.758301f, 0.771973f, 0.785156f, 0.799316f, 0.812012f, 0.825684f, 0.837891f, 0.850586f, 0.863281f, 0.875000f,
+ 0.887207f, 0.898926f, 0.910156f, 0.921387f, 0.933105f, 0.944336f, 0.954102f, 0.964844f, 0.976074f, 0.985840f, 0.978027f, 0.947266f,
+ 0.925781f, 0.907715f, 0.892090f, 0.877930f, 0.011276f, 0.034546f, 0.058289f, 0.082031f, 0.105469f, 0.128662f, 0.152344f, 0.174805f,
+ 0.197876f, 0.219604f, 0.241455f, 0.263672f, 0.284912f, 0.306152f, 0.326416f, 0.347168f, 0.366699f, 0.387695f, 0.406494f, 0.426025f,
+ 0.444824f, 0.463379f, 0.481934f, 0.500000f, 0.518066f, 0.535645f, 0.552246f, 0.569824f, 0.586426f, 0.603027f, 0.619141f, 0.634766f,
+ 0.650391f, 0.666016f, 0.681152f, 0.695801f, 0.710938f, 0.725586f, 0.739258f, 0.753906f, 0.768066f, 0.781250f, 0.794922f, 0.807617f,
+ 0.821289f, 0.833496f, 0.846191f, 0.858398f, 0.870605f, 0.882812f, 0.894531f, 0.906250f, 0.917480f, 0.929199f, 0.939453f, 0.951660f,
+ 0.961426f, 0.972656f, 0.971680f, 0.942871f, 0.921875f, 0.904785f, 0.889160f, 0.875977f, 0.010628f, 0.032288f, 0.054932f, 0.076172f,
+ 0.099060f, 0.121216f, 0.142700f, 0.164795f, 0.186279f, 0.207642f, 0.229248f, 0.249756f, 0.269531f, 0.291016f, 0.310791f, 0.331543f,
+ 0.349609f, 0.369385f, 0.388916f, 0.409180f, 0.427246f, 0.444824f, 0.463135f, 0.480713f, 0.499512f, 0.516602f, 0.533203f, 0.550293f,
+ 0.567383f, 0.583496f, 0.599609f, 0.615723f, 0.630859f, 0.646973f, 0.661621f, 0.677246f, 0.691895f, 0.705566f, 0.720703f, 0.735352f,
+ 0.749512f, 0.763184f, 0.776367f, 0.790039f, 0.803223f, 0.816406f, 0.828613f, 0.842285f, 0.854492f, 0.867676f, 0.878418f, 0.890137f,
+ 0.902832f, 0.913086f, 0.925293f, 0.936035f, 0.947754f, 0.958008f, 0.964844f, 0.937500f, 0.917480f, 0.901367f, 0.886719f, 0.873535f,
+ 0.009926f, 0.030167f, 0.050995f, 0.071594f, 0.092346f, 0.113892f, 0.134399f, 0.154663f, 0.175537f, 0.195679f, 0.216309f, 0.235840f,
+ 0.256104f, 0.276611f, 0.295654f, 0.314453f, 0.333496f, 0.353027f, 0.370850f, 0.389404f, 0.408936f, 0.427490f, 0.445312f, 0.462891f,
+ 0.480225f, 0.497803f, 0.513672f, 0.531250f, 0.547363f, 0.563965f, 0.580078f, 0.597168f, 0.612305f, 0.627930f, 0.642578f, 0.658691f,
+ 0.673340f, 0.687500f, 0.702637f, 0.717285f, 0.731445f, 0.744629f, 0.758301f, 0.772461f, 0.786133f, 0.799316f, 0.811523f, 0.824707f,
+ 0.837891f, 0.849121f, 0.861816f, 0.874023f, 0.887207f, 0.898438f, 0.910156f, 0.920898f, 0.932617f, 0.943848f, 0.958008f, 0.932129f,
+ 0.913086f, 0.897461f, 0.883301f, 0.871094f, 0.009178f, 0.028107f, 0.047729f, 0.066895f, 0.086182f, 0.106384f, 0.125977f, 0.145386f,
+ 0.165527f, 0.184937f, 0.203857f, 0.224121f, 0.242676f, 0.261475f, 0.281006f, 0.300049f, 0.318604f, 0.336426f, 0.355469f, 0.372314f,
+ 0.391113f, 0.409424f, 0.426514f, 0.444092f, 0.461426f, 0.477783f, 0.495850f, 0.512207f, 0.528809f, 0.544434f, 0.561035f, 0.576660f,
+ 0.593262f, 0.608398f, 0.623047f, 0.638184f, 0.655273f, 0.668945f, 0.682617f, 0.697754f, 0.712402f, 0.726562f, 0.740234f, 0.753906f,
+ 0.768066f, 0.781250f, 0.794434f, 0.807617f, 0.820312f, 0.833496f, 0.845215f, 0.858398f, 0.870605f, 0.881836f, 0.894043f, 0.906738f,
+ 0.917480f, 0.928711f, 0.951172f, 0.926758f, 0.909180f, 0.893555f, 0.880859f, 0.868164f, 0.008667f, 0.025986f, 0.044922f, 0.062805f,
+ 0.081421f, 0.099854f, 0.118347f, 0.137085f, 0.155518f, 0.173828f, 0.193115f, 0.211304f, 0.229858f, 0.248413f, 0.266602f, 0.285400f,
+ 0.303223f, 0.321045f, 0.339111f, 0.357178f, 0.373779f, 0.391357f, 0.409424f, 0.426270f, 0.443115f, 0.460449f, 0.476807f, 0.494141f,
+ 0.510254f, 0.526855f, 0.541992f, 0.559082f, 0.574219f, 0.589355f, 0.605469f, 0.620117f, 0.636230f, 0.649902f, 0.664551f, 0.678711f,
+ 0.693848f, 0.707031f, 0.723145f, 0.736328f, 0.750977f, 0.762695f, 0.776855f, 0.790039f, 0.803223f, 0.816406f, 0.828613f, 0.842285f,
+ 0.853516f, 0.866211f, 0.878906f, 0.890625f, 0.902832f, 0.913574f, 0.944336f, 0.921875f, 0.903809f, 0.889160f, 0.876953f, 0.865234f,
+ 0.008057f, 0.024658f, 0.041321f, 0.058411f, 0.075989f, 0.093811f, 0.110535f, 0.128784f, 0.146729f, 0.164307f, 0.182007f, 0.200073f,
+ 0.217773f, 0.234619f, 0.252930f, 0.271240f, 0.288086f, 0.306152f, 0.322998f, 0.341064f, 0.357910f, 0.374756f, 0.391357f, 0.409180f,
+ 0.425293f, 0.442383f, 0.458496f, 0.475342f, 0.491455f, 0.507324f, 0.523438f, 0.539551f, 0.555176f, 0.570312f, 0.585938f, 0.601074f,
+ 0.616699f, 0.631836f, 0.646484f, 0.660645f, 0.676270f, 0.688477f, 0.704102f, 0.718262f, 0.731445f, 0.745117f, 0.760254f, 0.771484f,
+ 0.785156f, 0.799316f, 0.812500f, 0.824707f, 0.836914f, 0.850098f, 0.862793f, 0.874512f, 0.886719f, 0.898438f, 0.937500f, 0.915527f,
+ 0.899414f, 0.885254f, 0.872559f, 0.861816f, 0.007477f, 0.022919f, 0.038971f, 0.054901f, 0.070801f, 0.087646f, 0.104065f, 0.121155f,
+ 0.137573f, 0.155029f, 0.171875f, 0.188721f, 0.206177f, 0.222778f, 0.240112f, 0.257080f, 0.274170f, 0.290283f, 0.308350f, 0.324463f,
+ 0.342041f, 0.358154f, 0.375488f, 0.391113f, 0.407471f, 0.424561f, 0.440430f, 0.456787f, 0.474121f, 0.489746f, 0.505371f, 0.521484f,
+ 0.536133f, 0.552246f, 0.565918f, 0.582031f, 0.597168f, 0.613281f, 0.626953f, 0.642578f, 0.656738f, 0.670898f, 0.684570f, 0.699219f,
+ 0.712891f, 0.727539f, 0.741211f, 0.754395f, 0.768066f, 0.781738f, 0.794434f, 0.808105f, 0.820312f, 0.833984f, 0.846680f, 0.858887f,
+ 0.871582f, 0.883301f, 0.930176f, 0.910156f, 0.894043f, 0.880371f, 0.868652f, 0.858398f, 0.007023f, 0.021240f, 0.036224f, 0.051300f,
+ 0.066467f, 0.082092f, 0.097900f, 0.113892f, 0.129517f, 0.145752f, 0.161743f, 0.178223f, 0.194702f, 0.210327f, 0.227661f, 0.243408f,
+ 0.260986f, 0.276855f, 0.292725f, 0.309814f, 0.326172f, 0.342041f, 0.358398f, 0.375732f, 0.391113f, 0.406982f, 0.422852f, 0.438965f,
+ 0.454590f, 0.471191f, 0.486816f, 0.502441f, 0.517578f, 0.533203f, 0.548340f, 0.562988f, 0.578613f, 0.593750f, 0.609375f, 0.623535f,
+ 0.638184f, 0.652832f, 0.666992f, 0.680664f, 0.695312f, 0.708984f, 0.722656f, 0.736816f, 0.750000f, 0.764160f, 0.777344f, 0.789551f,
+ 0.803223f, 0.816895f, 0.830078f, 0.842773f, 0.854980f, 0.868652f, 0.922852f, 0.904297f, 0.889160f, 0.875977f, 0.864746f, 0.854492f,
+ 0.006458f, 0.019913f, 0.033691f, 0.048126f, 0.062744f, 0.077026f, 0.092224f, 0.106567f, 0.122192f, 0.137207f, 0.152222f, 0.167725f,
+ 0.183838f, 0.199951f, 0.215088f, 0.231323f, 0.246826f, 0.262695f, 0.279053f, 0.294678f, 0.310547f, 0.326172f, 0.342041f, 0.358887f,
+ 0.374268f, 0.389893f, 0.405518f, 0.421143f, 0.437012f, 0.452637f, 0.467773f, 0.483643f, 0.499512f, 0.513672f, 0.529785f, 0.545410f,
+ 0.560059f, 0.575195f, 0.590332f, 0.604980f, 0.618652f, 0.634277f, 0.648438f, 0.662598f, 0.676270f, 0.690918f, 0.704102f, 0.718750f,
+ 0.732422f, 0.745605f, 0.760254f, 0.773438f, 0.786621f, 0.801270f, 0.812988f, 0.826172f, 0.839844f, 0.851562f, 0.915527f, 0.897949f,
+ 0.883789f, 0.871094f, 0.860352f, 0.850586f, 0.006077f, 0.018921f, 0.031464f, 0.045258f, 0.058411f, 0.072144f, 0.085999f, 0.100220f,
+ 0.114258f, 0.129028f, 0.143677f, 0.158691f, 0.173584f, 0.188477f, 0.203247f, 0.219238f, 0.234497f, 0.249634f, 0.264893f, 0.280273f,
+ 0.295410f, 0.310791f, 0.326904f, 0.342285f, 0.357910f, 0.373535f, 0.388428f, 0.404053f, 0.420166f, 0.435303f, 0.450195f, 0.465332f,
+ 0.481201f, 0.496338f, 0.511230f, 0.525879f, 0.540527f, 0.556641f, 0.570312f, 0.585938f, 0.600098f, 0.614746f, 0.629883f, 0.644531f,
+ 0.657715f, 0.672363f, 0.687012f, 0.700684f, 0.714355f, 0.729004f, 0.742188f, 0.755371f, 0.769531f, 0.782227f, 0.796875f, 0.810059f,
+ 0.823242f, 0.836426f, 0.907715f, 0.891602f, 0.877930f, 0.866211f, 0.855957f, 0.846680f, 0.005596f, 0.017654f, 0.029587f, 0.041840f,
+ 0.055115f, 0.067871f, 0.080566f, 0.093994f, 0.107361f, 0.120911f, 0.134766f, 0.149414f, 0.163452f, 0.177979f, 0.192261f, 0.206787f,
+ 0.221191f, 0.236816f, 0.250732f, 0.266113f, 0.281250f, 0.295898f, 0.311279f, 0.326904f, 0.342041f, 0.356201f, 0.371826f, 0.387451f,
+ 0.402344f, 0.417236f, 0.432373f, 0.447266f, 0.462891f, 0.477539f, 0.492432f, 0.506836f, 0.522949f, 0.536621f, 0.551758f, 0.566895f,
+ 0.582031f, 0.596191f, 0.610352f, 0.625488f, 0.640625f, 0.653320f, 0.668457f, 0.682617f, 0.696777f, 0.710449f, 0.724609f, 0.739258f,
+ 0.751465f, 0.765625f, 0.780273f, 0.792480f, 0.806152f, 0.820801f, 0.899902f, 0.885742f, 0.872070f, 0.861328f, 0.851562f, 0.842285f,
+ 0.005451f, 0.016479f, 0.028259f, 0.039856f, 0.051331f, 0.063416f, 0.075867f, 0.088196f, 0.100952f, 0.113770f, 0.126953f, 0.140747f,
+ 0.153564f, 0.167847f, 0.181519f, 0.195679f, 0.210083f, 0.223633f, 0.237427f, 0.252197f, 0.267334f, 0.281738f, 0.296143f, 0.311035f,
+ 0.325928f, 0.340332f, 0.355469f, 0.370361f, 0.385010f, 0.400635f, 0.415039f, 0.429688f, 0.444092f, 0.459717f, 0.474121f, 0.489258f,
+ 0.503906f, 0.519043f, 0.533203f, 0.548828f, 0.562012f, 0.577637f, 0.591797f, 0.606445f, 0.621582f, 0.635742f, 0.650391f, 0.664551f,
+ 0.678223f, 0.692871f, 0.706055f, 0.721191f, 0.733887f, 0.747559f, 0.762207f, 0.775879f, 0.791016f, 0.804199f, 0.892090f, 0.878906f,
+ 0.866699f, 0.855957f, 0.846191f, 0.837891f, 0.004963f, 0.015343f, 0.026169f, 0.037079f, 0.047943f, 0.059570f, 0.070801f, 0.083008f,
+ 0.095093f, 0.106750f, 0.119507f, 0.132080f, 0.145142f, 0.158569f, 0.171143f, 0.184692f, 0.198730f, 0.211792f, 0.225830f, 0.239380f,
+ 0.253662f, 0.267578f, 0.281738f, 0.295898f, 0.309814f, 0.324219f, 0.340088f, 0.353760f, 0.368164f, 0.383057f, 0.397705f, 0.412842f,
+ 0.426758f, 0.441406f, 0.456787f, 0.470947f, 0.485352f, 0.500000f, 0.515137f, 0.529785f, 0.543945f, 0.559082f, 0.572754f, 0.588379f,
+ 0.602539f, 0.616699f, 0.631348f, 0.645996f, 0.659180f, 0.674805f, 0.689453f, 0.703125f, 0.716797f, 0.729980f, 0.744629f, 0.758789f,
+ 0.772461f, 0.786621f, 0.883789f, 0.872070f, 0.860840f, 0.850586f, 0.841309f, 0.833008f, 0.004726f, 0.014549f, 0.024109f, 0.034668f,
+ 0.044708f, 0.055573f, 0.066467f, 0.077820f, 0.088928f, 0.100342f, 0.112000f, 0.124390f, 0.136230f, 0.148804f, 0.161621f, 0.173950f,
+ 0.186768f, 0.200439f, 0.213623f, 0.226074f, 0.239868f, 0.253418f, 0.267090f, 0.281250f, 0.295410f, 0.309570f, 0.323486f, 0.337891f,
+ 0.352295f, 0.365967f, 0.381104f, 0.394775f, 0.409180f, 0.423828f, 0.438477f, 0.452881f, 0.467773f, 0.481689f, 0.496582f, 0.511230f,
+ 0.525391f, 0.539551f, 0.554199f, 0.568848f, 0.583984f, 0.599121f, 0.612305f, 0.627441f, 0.641113f, 0.656250f, 0.669922f, 0.684570f,
+ 0.699219f, 0.713379f, 0.727539f, 0.741699f, 0.755859f, 0.771484f, 0.875488f, 0.865723f, 0.854492f, 0.845215f, 0.836426f, 0.828613f,
+ 0.004452f, 0.013359f, 0.022690f, 0.032745f, 0.042297f, 0.051910f, 0.061920f, 0.072693f, 0.083496f, 0.094177f, 0.105408f, 0.116760f,
+ 0.128174f, 0.140137f, 0.151855f, 0.164185f, 0.176758f, 0.189087f, 0.201660f, 0.214478f, 0.227173f, 0.240356f, 0.253906f, 0.267578f,
+ 0.280273f, 0.294922f, 0.307373f, 0.321045f, 0.336670f, 0.350098f, 0.363770f, 0.378174f, 0.392334f, 0.406006f, 0.420410f, 0.434082f,
+ 0.448975f, 0.463623f, 0.478271f, 0.492676f, 0.506836f, 0.520996f, 0.536133f, 0.550781f, 0.565430f, 0.580078f, 0.593750f, 0.608887f,
+ 0.623047f, 0.638184f, 0.651367f, 0.666016f, 0.681152f, 0.695312f, 0.709473f, 0.723145f, 0.738281f, 0.752930f, 0.867676f, 0.858398f,
+ 0.848633f, 0.839355f, 0.831055f, 0.823730f, 0.004143f, 0.012794f, 0.021713f, 0.030396f, 0.039551f, 0.048645f, 0.058563f, 0.068176f,
+ 0.078308f, 0.088928f, 0.098328f, 0.109924f, 0.120728f, 0.131592f, 0.142944f, 0.154175f, 0.165771f, 0.178223f, 0.190186f, 0.202881f,
+ 0.214844f, 0.227417f, 0.240845f, 0.253906f, 0.265869f, 0.279541f, 0.293213f, 0.305908f, 0.320068f, 0.333496f, 0.347168f, 0.361816f,
+ 0.375000f, 0.389160f, 0.403320f, 0.417236f, 0.431396f, 0.444824f, 0.459473f, 0.473633f, 0.488525f, 0.503418f, 0.517578f, 0.532227f,
+ 0.545410f, 0.560547f, 0.575684f, 0.590332f, 0.604004f, 0.618652f, 0.632812f, 0.647949f, 0.663086f, 0.676758f, 0.691895f, 0.706543f,
+ 0.721191f, 0.735840f, 0.859375f, 0.852539f, 0.842773f, 0.833496f, 0.824707f, 0.818848f, 0.003839f, 0.012062f, 0.020126f, 0.028366f,
+ 0.036774f, 0.045593f, 0.054718f, 0.063416f, 0.073120f, 0.082825f, 0.092957f, 0.102966f, 0.113464f, 0.123535f, 0.134277f, 0.145020f,
+ 0.155762f, 0.167847f, 0.179199f, 0.190796f, 0.202393f, 0.214844f, 0.227417f, 0.239868f, 0.252197f, 0.264648f, 0.277588f, 0.291016f,
+ 0.304199f, 0.317383f, 0.330811f, 0.343750f, 0.357422f, 0.371826f, 0.385254f, 0.399902f, 0.413574f, 0.427246f, 0.441162f, 0.455566f,
+ 0.469971f, 0.484375f, 0.498535f, 0.514160f, 0.527344f, 0.541992f, 0.556152f, 0.570312f, 0.585449f, 0.600098f, 0.614746f, 0.629883f,
+ 0.645508f, 0.658203f, 0.673340f, 0.688477f, 0.703125f, 0.718262f, 0.851074f, 0.844727f, 0.835938f, 0.827637f, 0.820312f, 0.812988f,
+ 0.003786f, 0.011147f, 0.018921f, 0.026550f, 0.034729f, 0.042664f, 0.051117f, 0.060028f, 0.068298f, 0.077454f, 0.086914f, 0.096130f,
+ 0.105835f, 0.115662f, 0.126343f, 0.136475f, 0.146606f, 0.157715f, 0.168457f, 0.180176f, 0.191528f, 0.202759f, 0.215088f, 0.226929f,
+ 0.239014f, 0.251221f, 0.263428f, 0.275391f, 0.289062f, 0.301514f, 0.314941f, 0.328369f, 0.341797f, 0.354736f, 0.367676f, 0.382324f,
+ 0.395264f, 0.409912f, 0.423340f, 0.437012f, 0.451660f, 0.465576f, 0.480469f, 0.494629f, 0.508301f, 0.522949f, 0.538086f, 0.551758f,
+ 0.567383f, 0.582031f, 0.596191f, 0.610840f, 0.625977f, 0.639648f, 0.655273f, 0.670410f, 0.685547f, 0.700684f, 0.842285f, 0.837402f,
+ 0.829590f, 0.821289f, 0.813965f, 0.808105f, 0.003504f, 0.010445f, 0.017609f, 0.025131f, 0.032349f, 0.040314f, 0.047485f, 0.055756f,
+ 0.064026f, 0.072571f, 0.080872f, 0.089661f, 0.099426f, 0.108459f, 0.118286f, 0.127930f, 0.137817f, 0.147583f, 0.158203f, 0.169189f,
+ 0.180908f, 0.191040f, 0.203003f, 0.214111f, 0.225708f, 0.237549f, 0.249023f, 0.261475f, 0.273926f, 0.286865f, 0.299316f, 0.311768f,
+ 0.325684f, 0.338623f, 0.351562f, 0.364746f, 0.378418f, 0.392578f, 0.405518f, 0.419678f, 0.433105f, 0.447998f, 0.461670f, 0.475830f,
+ 0.490479f, 0.503906f, 0.519531f, 0.533203f, 0.547852f, 0.562988f, 0.576660f, 0.591797f, 0.606445f, 0.622070f, 0.636719f, 0.652344f,
+ 0.666504f, 0.682617f, 0.833496f, 0.830078f, 0.822754f, 0.815918f, 0.808594f, 0.802734f, 0.003447f, 0.009941f, 0.016373f, 0.023300f,
+ 0.030228f, 0.037689f, 0.044128f, 0.052551f, 0.059845f, 0.068115f, 0.076538f, 0.083862f, 0.092896f, 0.101440f, 0.110596f, 0.119995f,
+ 0.129028f, 0.138916f, 0.148926f, 0.158936f, 0.169189f, 0.180176f, 0.190308f, 0.201416f, 0.212769f, 0.224365f, 0.235962f, 0.247192f,
+ 0.259033f, 0.271973f, 0.283936f, 0.296631f, 0.309570f, 0.321777f, 0.334961f, 0.348389f, 0.361572f, 0.374756f, 0.388184f, 0.401611f,
+ 0.415771f, 0.429443f, 0.443359f, 0.457520f, 0.471436f, 0.486084f, 0.500977f, 0.514648f, 0.528809f, 0.543457f, 0.558594f, 0.573242f,
+ 0.588867f, 0.603516f, 0.617676f, 0.633301f, 0.648926f, 0.664551f, 0.824219f, 0.823242f, 0.815918f, 0.809082f, 0.802246f, 0.796387f,
+ 0.003141f, 0.009407f, 0.015251f, 0.021851f, 0.028107f, 0.034882f, 0.041779f, 0.048340f, 0.056244f, 0.062988f, 0.071106f, 0.078796f,
+ 0.087036f, 0.094910f, 0.103149f, 0.112305f, 0.121460f, 0.130371f, 0.139404f, 0.149048f, 0.159180f, 0.169189f, 0.179565f, 0.189087f,
+ 0.200317f, 0.211548f, 0.222412f, 0.233765f, 0.245117f, 0.257324f, 0.269043f, 0.281006f, 0.293213f, 0.305664f, 0.318848f, 0.331055f,
+ 0.343750f, 0.358398f, 0.369873f, 0.384033f, 0.397217f, 0.411865f, 0.424805f, 0.438965f, 0.453125f, 0.467529f, 0.481689f, 0.495850f,
+ 0.510254f, 0.524414f, 0.539551f, 0.554688f, 0.569824f, 0.584961f, 0.599121f, 0.614258f, 0.629883f, 0.645020f, 0.815430f, 0.814453f,
+ 0.809570f, 0.802734f, 0.796875f, 0.791504f, 0.002838f, 0.008461f, 0.014236f, 0.020676f, 0.026749f, 0.032593f, 0.039032f, 0.045715f,
+ 0.052216f, 0.059479f, 0.066467f, 0.073608f, 0.080933f, 0.088623f, 0.096619f, 0.104919f, 0.113098f, 0.121521f, 0.130493f, 0.139526f,
+ 0.148560f, 0.158203f, 0.167969f, 0.177979f, 0.187988f, 0.198730f, 0.208862f, 0.220093f, 0.231323f, 0.242798f, 0.253906f, 0.265869f,
+ 0.278320f, 0.289551f, 0.302246f, 0.314941f, 0.327393f, 0.340088f, 0.353516f, 0.365967f, 0.379883f, 0.392822f, 0.406738f, 0.420898f,
+ 0.434814f, 0.447998f, 0.462891f, 0.477539f, 0.491455f, 0.506836f, 0.520996f, 0.536133f, 0.550781f, 0.565918f, 0.581055f, 0.596680f,
+ 0.611816f, 0.627441f, 0.806152f, 0.807617f, 0.801270f, 0.796387f, 0.790039f, 0.784668f, 0.002689f, 0.008102f, 0.013618f, 0.019058f,
+ 0.024719f, 0.030548f, 0.036560f, 0.042725f, 0.048615f, 0.054779f, 0.061615f, 0.068604f, 0.075012f, 0.082703f, 0.090271f, 0.097900f,
+ 0.105530f, 0.113586f, 0.121826f, 0.130371f, 0.139282f, 0.147705f, 0.157349f, 0.166504f, 0.176147f, 0.186401f, 0.196289f, 0.207520f,
+ 0.217651f, 0.228394f, 0.239868f, 0.251465f, 0.262451f, 0.274414f, 0.286377f, 0.298828f, 0.311035f, 0.323730f, 0.336670f, 0.349121f,
+ 0.362549f, 0.375244f, 0.389160f, 0.402344f, 0.417236f, 0.429932f, 0.443848f, 0.458984f, 0.472168f, 0.487793f, 0.501953f, 0.517578f,
+ 0.531738f, 0.546875f, 0.561523f, 0.576660f, 0.593262f, 0.608398f, 0.797852f, 0.798828f, 0.794922f, 0.789551f, 0.784668f, 0.779297f,
+ 0.002666f, 0.007462f, 0.012596f, 0.018066f, 0.023026f, 0.028412f, 0.033813f, 0.039398f, 0.045166f, 0.051239f, 0.057587f, 0.063721f,
+ 0.070312f, 0.077148f, 0.084167f, 0.090820f, 0.098267f, 0.105591f, 0.113159f, 0.121460f, 0.129761f, 0.138428f, 0.147217f, 0.156128f,
+ 0.165283f, 0.174438f, 0.183960f, 0.194092f, 0.204834f, 0.214844f, 0.225830f, 0.236816f, 0.247925f, 0.259033f, 0.270752f, 0.282227f,
+ 0.294678f, 0.306641f, 0.319336f, 0.332031f, 0.344482f, 0.357910f, 0.371094f, 0.384033f, 0.398682f, 0.412109f, 0.425781f, 0.440186f,
+ 0.454102f, 0.468018f, 0.482910f, 0.497314f, 0.512207f, 0.528320f, 0.542969f, 0.558594f, 0.573242f, 0.589355f, 0.787598f, 0.791016f,
+ 0.787109f, 0.781738f, 0.777344f, 0.772461f, 0.002569f, 0.007069f, 0.012199f, 0.016739f, 0.021393f, 0.026672f, 0.031189f, 0.037109f,
+ 0.042480f, 0.047729f, 0.053345f, 0.059387f, 0.065430f, 0.071838f, 0.078186f, 0.084167f, 0.091492f, 0.098816f, 0.105774f, 0.112976f,
+ 0.121155f, 0.129028f, 0.136963f, 0.145508f, 0.153687f, 0.163086f, 0.172363f, 0.181885f, 0.191406f, 0.201782f, 0.211670f, 0.222412f,
+ 0.233032f, 0.244263f, 0.255371f, 0.266846f, 0.278809f, 0.290527f, 0.302734f, 0.314697f, 0.327393f, 0.340820f, 0.353027f, 0.366455f,
+ 0.380127f, 0.393799f, 0.406006f, 0.421143f, 0.435059f, 0.449707f, 0.463623f, 0.479248f, 0.494141f, 0.509277f, 0.523438f, 0.539551f,
+ 0.555176f, 0.570801f, 0.778320f, 0.783203f, 0.779785f, 0.775879f, 0.770996f, 0.767090f, 0.002398f, 0.006733f, 0.010918f, 0.015495f,
+ 0.020203f, 0.024963f, 0.029663f, 0.034485f, 0.039246f, 0.044678f, 0.049896f, 0.055267f, 0.060486f, 0.066345f, 0.072693f, 0.078857f,
+ 0.085083f, 0.091370f, 0.097961f, 0.105530f, 0.112244f, 0.119629f, 0.127563f, 0.135376f, 0.143799f, 0.152100f, 0.160889f, 0.169922f,
+ 0.178833f, 0.188843f, 0.198608f, 0.208496f, 0.218628f, 0.229492f, 0.240479f, 0.251953f, 0.262695f, 0.274902f, 0.286377f, 0.298340f,
+ 0.310547f, 0.323242f, 0.335693f, 0.349365f, 0.362061f, 0.375000f, 0.388916f, 0.402832f, 0.416748f, 0.430420f, 0.445068f, 0.459473f,
+ 0.474854f, 0.489258f, 0.504883f, 0.519531f, 0.535645f, 0.551758f, 0.769043f, 0.774902f, 0.771973f, 0.768555f, 0.764160f, 0.759766f,
+ 0.002062f, 0.006191f, 0.010384f, 0.014786f, 0.018402f, 0.023270f, 0.027435f, 0.031891f, 0.036163f, 0.041199f, 0.045685f, 0.051208f,
+ 0.056244f, 0.061371f, 0.066772f, 0.072510f, 0.078369f, 0.084656f, 0.091125f, 0.097290f, 0.104309f, 0.111145f, 0.118164f, 0.126221f,
+ 0.133301f, 0.141724f, 0.149658f, 0.157837f, 0.167236f, 0.176025f, 0.185547f, 0.195190f, 0.205444f, 0.215332f, 0.225830f, 0.236084f,
+ 0.247314f, 0.259033f, 0.270020f, 0.281982f, 0.293701f, 0.305908f, 0.318848f, 0.331787f, 0.344482f, 0.357178f, 0.370361f, 0.384521f,
+ 0.397461f, 0.411621f, 0.426025f, 0.440674f, 0.455322f, 0.470703f, 0.485596f, 0.500977f, 0.517578f, 0.532227f, 0.759277f, 0.766602f,
+ 0.764160f, 0.761230f, 0.757324f, 0.753418f, 0.002064f, 0.005859f, 0.009613f, 0.013626f, 0.017456f, 0.021606f, 0.025574f, 0.029526f,
+ 0.034302f, 0.038422f, 0.042938f, 0.047485f, 0.052155f, 0.056763f, 0.061951f, 0.067139f, 0.072754f, 0.078308f, 0.084167f, 0.090149f,
+ 0.096191f, 0.102722f, 0.109558f, 0.116699f, 0.123901f, 0.131104f, 0.139160f, 0.146729f, 0.155273f, 0.163940f, 0.173096f, 0.182129f,
+ 0.192017f, 0.201172f, 0.211060f, 0.221558f, 0.232544f, 0.243530f, 0.254150f, 0.266113f, 0.277588f, 0.289307f, 0.301758f, 0.313965f,
+ 0.326904f, 0.338867f, 0.352051f, 0.366211f, 0.379150f, 0.393066f, 0.407471f, 0.421875f, 0.436768f, 0.450439f, 0.466553f, 0.481201f,
+ 0.497314f, 0.513184f, 0.749512f, 0.758301f, 0.756348f, 0.753906f, 0.750000f, 0.746582f, 0.001851f, 0.005405f, 0.009109f, 0.012589f,
+ 0.016129f, 0.020020f, 0.023926f, 0.027481f, 0.031738f, 0.035492f, 0.039734f, 0.044128f, 0.048065f, 0.052765f, 0.057373f, 0.061859f,
+ 0.066711f, 0.072388f, 0.077393f, 0.083130f, 0.088745f, 0.094727f, 0.101135f, 0.107666f, 0.114380f, 0.121704f, 0.128540f, 0.136108f,
+ 0.144043f, 0.151733f, 0.160522f, 0.169678f, 0.178589f, 0.187622f, 0.197998f, 0.207397f, 0.217285f, 0.227905f, 0.238892f, 0.250000f,
+ 0.261230f, 0.272461f, 0.284180f, 0.296387f, 0.308838f, 0.321533f, 0.334473f, 0.347656f, 0.361328f, 0.375000f, 0.388672f, 0.402588f,
+ 0.417969f, 0.432617f, 0.447021f, 0.461914f, 0.478516f, 0.493652f, 0.739258f, 0.749512f, 0.749023f, 0.745605f, 0.742188f, 0.739746f,
+ 0.001666f, 0.005405f, 0.008575f, 0.011696f, 0.015327f, 0.018646f, 0.022293f, 0.025650f, 0.029327f, 0.032776f, 0.036530f, 0.040619f,
+ 0.044128f, 0.048828f, 0.052887f, 0.057098f, 0.061829f, 0.066467f, 0.071350f, 0.076355f, 0.081909f, 0.087341f, 0.092896f, 0.099304f,
+ 0.105469f, 0.112000f, 0.118835f, 0.125977f, 0.133545f, 0.140991f, 0.148438f, 0.156982f, 0.165771f, 0.174805f, 0.183960f, 0.193115f,
+ 0.203369f, 0.212891f, 0.223389f, 0.234497f, 0.244751f, 0.256348f, 0.268066f, 0.279541f, 0.291260f, 0.303955f, 0.316406f, 0.329590f,
+ 0.342529f, 0.355957f, 0.369385f, 0.384766f, 0.398926f, 0.413330f, 0.428467f, 0.442383f, 0.458740f, 0.474609f, 0.728516f, 0.740723f,
+ 0.740234f, 0.738281f, 0.735352f, 0.732910f, 0.001534f, 0.004936f, 0.007980f, 0.011223f, 0.013893f, 0.017212f, 0.020294f, 0.023361f,
+ 0.026688f, 0.030182f, 0.033600f, 0.037537f, 0.040924f, 0.044495f, 0.048340f, 0.052155f, 0.056732f, 0.061035f, 0.065430f, 0.069824f,
+ 0.075073f, 0.080078f, 0.085571f, 0.091003f, 0.096863f, 0.103271f, 0.109009f, 0.115723f, 0.123230f, 0.129639f, 0.137207f, 0.145264f,
+ 0.153320f, 0.161499f, 0.170410f, 0.179688f, 0.189087f, 0.198364f, 0.208740f, 0.218750f, 0.229126f, 0.240356f, 0.251465f, 0.263184f,
+ 0.274902f, 0.286621f, 0.299072f, 0.311768f, 0.324463f, 0.337402f, 0.351074f, 0.364746f, 0.378662f, 0.394287f, 0.408936f, 0.423096f,
+ 0.439453f, 0.455322f, 0.716797f, 0.731934f, 0.732422f, 0.729980f, 0.728027f, 0.725586f, 0.001639f, 0.004337f, 0.007439f, 0.009888f,
+ 0.013092f, 0.015717f, 0.018921f, 0.021805f, 0.024612f, 0.027542f, 0.030762f, 0.034088f, 0.037598f, 0.041107f, 0.044189f, 0.047699f,
+ 0.051666f, 0.055664f, 0.059723f, 0.064148f, 0.068542f, 0.073425f, 0.078003f, 0.083435f, 0.088806f, 0.094360f, 0.100159f, 0.106079f,
+ 0.112915f, 0.119690f, 0.125977f, 0.133667f, 0.141357f, 0.149414f, 0.157349f, 0.166260f, 0.175049f, 0.184326f, 0.193970f, 0.203735f,
+ 0.214355f, 0.224609f, 0.235352f, 0.246460f, 0.257568f, 0.269287f, 0.281738f, 0.294189f, 0.305908f, 0.319824f, 0.332520f, 0.346680f,
+ 0.360596f, 0.375244f, 0.389648f, 0.404297f, 0.419189f, 0.435791f, 0.707520f, 0.723145f, 0.723633f, 0.722656f, 0.720703f, 0.717773f,
+ 0.001469f, 0.004345f, 0.006844f, 0.009483f, 0.012428f, 0.014679f, 0.017166f, 0.019989f, 0.022949f, 0.025574f, 0.028320f, 0.031525f,
+ 0.034088f, 0.037323f, 0.040710f, 0.043762f, 0.047119f, 0.050873f, 0.054352f, 0.058441f, 0.062561f, 0.066711f, 0.071167f, 0.075989f,
+ 0.080627f, 0.086426f, 0.091553f, 0.097473f, 0.103210f, 0.109680f, 0.115723f, 0.122986f, 0.129761f, 0.137451f, 0.145142f, 0.153198f,
+ 0.161621f, 0.170654f, 0.179688f, 0.189087f, 0.198730f, 0.209229f, 0.219604f, 0.230225f, 0.241211f, 0.252197f, 0.264404f, 0.276367f,
+ 0.288574f, 0.301270f, 0.314453f, 0.328125f, 0.341309f, 0.354980f, 0.370117f, 0.385498f, 0.399902f, 0.415771f, 0.696289f, 0.714355f,
+ 0.715820f, 0.714355f, 0.712891f, 0.710449f, 0.001227f, 0.003862f, 0.006245f, 0.008644f, 0.010796f, 0.013344f, 0.015823f, 0.018448f,
+ 0.020645f, 0.023331f, 0.025681f, 0.028305f, 0.030975f, 0.033722f, 0.036987f, 0.039673f, 0.043121f, 0.046112f, 0.049774f, 0.053406f,
+ 0.056854f, 0.060760f, 0.064697f, 0.069397f, 0.073364f, 0.078369f, 0.083313f, 0.088257f, 0.094116f, 0.100098f, 0.105957f, 0.112122f,
+ 0.118774f, 0.125854f, 0.133057f, 0.140869f, 0.148682f, 0.157227f, 0.165405f, 0.174927f, 0.184082f, 0.193726f, 0.204102f, 0.214111f,
+ 0.225098f, 0.236328f, 0.247314f, 0.259277f, 0.270752f, 0.282959f, 0.296143f, 0.309082f, 0.322510f, 0.336426f, 0.350830f, 0.365479f,
+ 0.380371f, 0.396240f, 0.684570f, 0.705078f, 0.706543f, 0.706543f, 0.705078f, 0.703125f, 0.001069f, 0.003525f, 0.006062f, 0.008286f,
+ 0.010178f, 0.012589f, 0.014542f, 0.017075f, 0.019241f, 0.021179f, 0.023499f, 0.026047f, 0.028137f, 0.030762f, 0.033417f, 0.035889f,
+ 0.038757f, 0.041779f, 0.044586f, 0.048309f, 0.051056f, 0.054810f, 0.058777f, 0.062347f, 0.066528f, 0.070740f, 0.075256f, 0.080261f,
+ 0.085205f, 0.090393f, 0.095886f, 0.102478f, 0.108154f, 0.114441f, 0.121399f, 0.128784f, 0.135742f, 0.144165f, 0.151978f, 0.160767f,
+ 0.169434f, 0.178833f, 0.188721f, 0.198608f, 0.208984f, 0.220215f, 0.230957f, 0.241943f, 0.253906f, 0.265869f, 0.278564f, 0.291260f,
+ 0.304443f, 0.318359f, 0.332031f, 0.346680f, 0.361572f, 0.377197f, 0.673828f, 0.695801f, 0.698242f, 0.697754f, 0.697266f, 0.695312f,
+ 0.001211f, 0.003250f, 0.005112f, 0.007195f, 0.009651f, 0.011414f, 0.013641f, 0.015205f, 0.017334f, 0.019608f, 0.021164f, 0.023712f,
+ 0.025726f, 0.027863f, 0.029984f, 0.032410f, 0.035034f, 0.037689f, 0.040466f, 0.042938f, 0.046478f, 0.049591f, 0.052856f, 0.056274f,
+ 0.060089f, 0.063721f, 0.068115f, 0.072266f, 0.076904f, 0.081970f, 0.087036f, 0.092285f, 0.097961f, 0.104309f, 0.110535f, 0.117126f,
+ 0.124084f, 0.131226f, 0.139038f, 0.147095f, 0.155884f, 0.164429f, 0.174194f, 0.183228f, 0.192749f, 0.203491f, 0.214233f, 0.224976f,
+ 0.236206f, 0.247925f, 0.260498f, 0.272705f, 0.285889f, 0.299805f, 0.312988f, 0.327637f, 0.342529f, 0.356934f, 0.662598f, 0.686523f,
+ 0.689453f, 0.689453f, 0.688965f, 0.687500f, 0.001138f, 0.003206f, 0.005180f, 0.007309f, 0.008377f, 0.010635f, 0.012352f, 0.014153f,
+ 0.015640f, 0.017487f, 0.019272f, 0.021164f, 0.023026f, 0.025314f, 0.027222f, 0.029282f, 0.031433f, 0.033600f, 0.036041f, 0.038788f,
+ 0.041626f, 0.044281f, 0.047455f, 0.050507f, 0.054047f, 0.057556f, 0.061188f, 0.065063f, 0.069214f, 0.073486f, 0.078369f, 0.083191f,
+ 0.088196f, 0.093811f, 0.099609f, 0.106018f, 0.112305f, 0.119385f, 0.126343f, 0.134033f, 0.142090f, 0.150635f, 0.159546f, 0.168579f,
+ 0.177734f, 0.187500f, 0.198242f, 0.208618f, 0.219604f, 0.231812f, 0.242188f, 0.254883f, 0.267578f, 0.281494f, 0.294434f, 0.308350f,
+ 0.322998f, 0.338379f, 0.651367f, 0.676758f, 0.681152f, 0.680664f, 0.680664f, 0.679688f, 0.000977f, 0.002806f, 0.004559f, 0.006176f,
+ 0.008034f, 0.009476f, 0.011131f, 0.012741f, 0.014275f, 0.015732f, 0.017334f, 0.019104f, 0.020767f, 0.022293f, 0.024323f, 0.026016f,
+ 0.028198f, 0.030197f, 0.032257f, 0.034515f, 0.036957f, 0.039856f, 0.042084f, 0.044891f, 0.047791f, 0.051147f, 0.054535f, 0.058197f,
+ 0.061768f, 0.065674f, 0.069946f, 0.074585f, 0.079102f, 0.084412f, 0.089600f, 0.095398f, 0.101196f, 0.107544f, 0.114258f, 0.121094f,
+ 0.128662f, 0.137085f, 0.145020f, 0.153687f, 0.162720f, 0.172607f, 0.182129f, 0.192749f, 0.203125f, 0.214111f, 0.226074f, 0.237671f,
+ 0.249878f, 0.262207f, 0.275635f, 0.289551f, 0.304199f, 0.318848f, 0.639160f, 0.666992f, 0.671387f, 0.671875f, 0.671875f, 0.671387f,
+ 0.000968f, 0.002722f, 0.004318f, 0.005634f, 0.007393f, 0.008667f, 0.010139f, 0.011383f, 0.012856f, 0.014389f, 0.015427f, 0.016907f,
+ 0.018387f, 0.020081f, 0.021683f, 0.023315f, 0.025085f, 0.026840f, 0.028641f, 0.030624f, 0.032837f, 0.035065f, 0.037445f, 0.039948f,
+ 0.042542f, 0.045410f, 0.048340f, 0.051514f, 0.054840f, 0.058502f, 0.062408f, 0.066223f, 0.070679f, 0.075134f, 0.080078f, 0.085388f,
+ 0.090515f, 0.096436f, 0.102722f, 0.109314f, 0.116333f, 0.123352f, 0.131592f, 0.139526f, 0.147949f, 0.156860f, 0.166748f, 0.176758f,
+ 0.187134f, 0.197632f, 0.209106f, 0.220337f, 0.232666f, 0.244751f, 0.257568f, 0.270996f, 0.284912f, 0.300537f, 0.627441f, 0.657227f,
+ 0.662598f, 0.663574f, 0.663574f, 0.663086f, 0.001081f, 0.002466f, 0.003862f, 0.005348f, 0.006447f, 0.007927f, 0.009018f, 0.010490f,
+ 0.011436f, 0.012627f, 0.013916f, 0.015015f, 0.016449f, 0.017563f, 0.019165f, 0.020706f, 0.021973f, 0.023834f, 0.025467f, 0.027130f,
+ 0.029175f, 0.030991f, 0.033081f, 0.035156f, 0.037384f, 0.040039f, 0.042603f, 0.045502f, 0.048492f, 0.051636f, 0.054962f, 0.058716f,
+ 0.062439f, 0.066467f, 0.071045f, 0.075378f, 0.080811f, 0.085815f, 0.091492f, 0.098022f, 0.103943f, 0.111023f, 0.118164f, 0.125732f,
+ 0.133911f, 0.142456f, 0.151367f, 0.161011f, 0.170898f, 0.181396f, 0.192139f, 0.203247f, 0.214844f, 0.227173f, 0.239380f, 0.252441f,
+ 0.266602f, 0.281006f, 0.616699f, 0.647949f, 0.653320f, 0.655273f, 0.654785f, 0.655273f, 0.000735f, 0.002331f, 0.003601f, 0.005005f,
+ 0.005825f, 0.007061f, 0.008049f, 0.009148f, 0.010315f, 0.011131f, 0.012230f, 0.013367f, 0.014328f, 0.015541f, 0.016968f, 0.018234f,
+ 0.019257f, 0.020798f, 0.022202f, 0.023666f, 0.025452f, 0.027115f, 0.028885f, 0.030792f, 0.032715f, 0.035034f, 0.037323f, 0.039825f,
+ 0.042419f, 0.045258f, 0.048157f, 0.051422f, 0.054810f, 0.058411f, 0.062378f, 0.066528f, 0.071106f, 0.076233f, 0.081116f, 0.086853f,
+ 0.092407f, 0.098938f, 0.105469f, 0.112854f, 0.120361f, 0.128418f, 0.136841f, 0.145752f, 0.155273f, 0.165283f, 0.175537f, 0.186646f,
+ 0.197510f, 0.209473f, 0.221558f, 0.234619f, 0.248047f, 0.261719f, 0.603516f, 0.636719f, 0.644531f, 0.645020f, 0.645508f, 0.646484f,
+ 0.000837f, 0.002073f, 0.003357f, 0.004292f, 0.005409f, 0.006271f, 0.007271f, 0.007973f, 0.008873f, 0.009956f, 0.010811f, 0.012032f,
+ 0.012848f, 0.013664f, 0.014870f, 0.015839f, 0.017090f, 0.018280f, 0.019333f, 0.020691f, 0.022186f, 0.023453f, 0.025223f, 0.026779f,
+ 0.028595f, 0.030441f, 0.032410f, 0.034729f, 0.036743f, 0.039307f, 0.042023f, 0.044434f, 0.047791f, 0.050781f, 0.054413f, 0.058075f,
+ 0.061951f, 0.066711f, 0.071106f, 0.076355f, 0.081848f, 0.087341f, 0.093872f, 0.099854f, 0.107483f, 0.114441f, 0.122925f, 0.131104f,
+ 0.140381f, 0.149414f, 0.159180f, 0.170166f, 0.181152f, 0.192139f, 0.204468f, 0.216553f, 0.230103f, 0.244507f, 0.592773f, 0.626953f,
+ 0.635254f, 0.637207f, 0.636719f, 0.637695f, 0.000524f, 0.001863f, 0.003014f, 0.003777f, 0.004852f, 0.005516f, 0.006428f, 0.007111f,
+ 0.008095f, 0.008888f, 0.009476f, 0.010345f, 0.011063f, 0.012016f, 0.012810f, 0.013786f, 0.014648f, 0.015717f, 0.016891f, 0.017929f,
+ 0.019150f, 0.020401f, 0.021606f, 0.023193f, 0.024597f, 0.026276f, 0.027939f, 0.029770f, 0.031738f, 0.033936f, 0.036194f, 0.038574f,
+ 0.041107f, 0.043945f, 0.047180f, 0.050385f, 0.054291f, 0.057770f, 0.061981f, 0.066345f, 0.071167f, 0.076355f, 0.082153f, 0.088074f,
+ 0.094666f, 0.101685f, 0.109131f, 0.117249f, 0.125610f, 0.134399f, 0.143921f, 0.154175f, 0.164795f, 0.175659f, 0.187256f, 0.199341f,
+ 0.211670f, 0.225464f, 0.580078f, 0.617676f, 0.625000f, 0.627930f, 0.628906f, 0.628906f, 0.000657f, 0.001829f, 0.002909f, 0.003525f,
+ 0.004295f, 0.005051f, 0.005592f, 0.006123f, 0.006920f, 0.007553f, 0.008339f, 0.008888f, 0.009689f, 0.010262f, 0.011017f, 0.011848f,
+ 0.012634f, 0.013489f, 0.014572f, 0.015427f, 0.016449f, 0.017426f, 0.018539f, 0.019852f, 0.021133f, 0.022507f, 0.023834f, 0.025375f,
+ 0.027084f, 0.028976f, 0.030792f, 0.032959f, 0.035400f, 0.037720f, 0.040405f, 0.043243f, 0.046356f, 0.049530f, 0.053314f, 0.057190f,
+ 0.061554f, 0.066223f, 0.071472f, 0.076782f, 0.082825f, 0.089417f, 0.096191f, 0.103210f, 0.111633f, 0.119934f, 0.128662f, 0.138550f,
+ 0.148315f, 0.158813f, 0.170288f, 0.182373f, 0.194458f, 0.207642f, 0.567383f, 0.606445f, 0.615234f, 0.619141f, 0.620117f, 0.620117f,
+ 0.000584f, 0.001548f, 0.002333f, 0.003086f, 0.003660f, 0.004303f, 0.005020f, 0.005543f, 0.006042f, 0.006538f, 0.007118f, 0.007641f,
+ 0.008301f, 0.008919f, 0.009499f, 0.010147f, 0.010918f, 0.011414f, 0.012222f, 0.013084f, 0.013901f, 0.014954f, 0.015671f, 0.016724f,
+ 0.017914f, 0.019012f, 0.020325f, 0.021698f, 0.022949f, 0.024445f, 0.026215f, 0.027954f, 0.029755f, 0.032043f, 0.034210f, 0.036591f,
+ 0.039215f, 0.042297f, 0.045441f, 0.048676f, 0.052612f, 0.056580f, 0.061432f, 0.066040f, 0.071350f, 0.077332f, 0.083496f, 0.090393f,
+ 0.097717f, 0.105835f, 0.114380f, 0.123413f, 0.133301f, 0.143066f, 0.153931f, 0.165039f, 0.177124f, 0.190308f, 0.555176f, 0.597656f,
+ 0.604980f, 0.609375f, 0.609863f, 0.611328f, 0.000438f, 0.001456f, 0.001925f, 0.002811f, 0.003246f, 0.003731f, 0.004108f, 0.004669f,
+ 0.005344f, 0.005535f, 0.005913f, 0.006641f, 0.007038f, 0.007473f, 0.008049f, 0.008675f, 0.009361f, 0.009689f, 0.010513f, 0.011032f,
+ 0.011894f, 0.012695f, 0.013390f, 0.014183f, 0.015114f, 0.016037f, 0.016998f, 0.018280f, 0.019272f, 0.020645f, 0.022003f, 0.023361f,
+ 0.024796f, 0.026779f, 0.028656f, 0.030685f, 0.032928f, 0.035370f, 0.038147f, 0.040955f, 0.044403f, 0.047821f, 0.052032f, 0.056183f,
+ 0.060974f, 0.066162f, 0.071777f, 0.078125f, 0.084656f, 0.092102f, 0.100159f, 0.109009f, 0.117981f, 0.127563f, 0.138306f, 0.148804f,
+ 0.160645f, 0.173218f, 0.542969f, 0.586914f, 0.594727f, 0.599609f, 0.601074f, 0.601074f, 0.000520f, 0.001104f, 0.001921f, 0.002256f,
+ 0.002886f, 0.003389f, 0.003689f, 0.004063f, 0.004440f, 0.004829f, 0.005230f, 0.005466f, 0.005966f, 0.006332f, 0.006786f, 0.007347f,
+ 0.007835f, 0.008232f, 0.008812f, 0.009216f, 0.009865f, 0.010490f, 0.011124f, 0.011803f, 0.012573f, 0.013390f, 0.014275f, 0.015121f,
+ 0.016144f, 0.016953f, 0.018234f, 0.019257f, 0.020782f, 0.022064f, 0.023743f, 0.025360f, 0.027176f, 0.029327f, 0.031616f, 0.034058f,
+ 0.036957f, 0.039917f, 0.043182f, 0.047272f, 0.051025f, 0.055695f, 0.060913f, 0.066345f, 0.072693f, 0.079285f, 0.086548f, 0.094543f,
+ 0.103271f, 0.112793f, 0.122864f, 0.132812f, 0.144531f, 0.156616f, 0.530273f, 0.576660f, 0.585449f, 0.590332f, 0.592285f, 0.593262f,
+ 0.000366f, 0.001040f, 0.001583f, 0.002129f, 0.002522f, 0.002792f, 0.003012f, 0.003420f, 0.003630f, 0.003967f, 0.004246f, 0.004623f,
+ 0.005039f, 0.005253f, 0.005627f, 0.006096f, 0.006447f, 0.006939f, 0.007179f, 0.007710f, 0.008324f, 0.008698f, 0.009247f, 0.009796f,
+ 0.010414f, 0.011063f, 0.011627f, 0.012543f, 0.013191f, 0.014099f, 0.014938f, 0.015930f, 0.016983f, 0.018219f, 0.019440f, 0.020813f,
+ 0.022324f, 0.024002f, 0.025818f, 0.027969f, 0.030289f, 0.032898f, 0.035583f, 0.038727f, 0.042450f, 0.046234f, 0.050781f, 0.055695f,
+ 0.061157f, 0.067383f, 0.074158f, 0.081360f, 0.089478f, 0.098267f, 0.107788f, 0.117737f, 0.129028f, 0.140503f, 0.517578f, 0.566406f,
+ 0.575195f, 0.581055f, 0.582520f, 0.584473f, 0.000482f, 0.001008f, 0.001481f, 0.001818f, 0.002001f, 0.002296f, 0.002569f, 0.002781f,
+ 0.002998f, 0.003319f, 0.003620f, 0.003828f, 0.004082f, 0.004364f, 0.004658f, 0.004978f, 0.005257f, 0.005665f, 0.005993f, 0.006340f,
+ 0.006725f, 0.007160f, 0.007576f, 0.008095f, 0.008522f, 0.008980f, 0.009621f, 0.010170f, 0.010765f, 0.011543f, 0.012161f, 0.013023f,
+ 0.013840f, 0.014801f, 0.015869f, 0.016861f, 0.018127f, 0.019379f, 0.020859f, 0.022583f, 0.024261f, 0.026596f, 0.028839f, 0.031555f,
+ 0.034271f, 0.037628f, 0.041504f, 0.045837f, 0.050598f, 0.056000f, 0.062134f, 0.068726f, 0.076172f, 0.084656f, 0.093567f, 0.103088f,
+ 0.113586f, 0.125000f, 0.504883f, 0.554688f, 0.565918f, 0.570801f, 0.573242f, 0.574219f, 0.000400f, 0.000803f, 0.001046f, 0.001427f,
+ 0.001657f, 0.001952f, 0.002033f, 0.002337f, 0.002453f, 0.002678f, 0.002871f, 0.003120f, 0.003286f, 0.003605f, 0.003817f, 0.004036f,
+ 0.004299f, 0.004604f, 0.004848f, 0.005142f, 0.005428f, 0.005871f, 0.006107f, 0.006584f, 0.006908f, 0.007332f, 0.007736f, 0.008186f,
+ 0.008820f, 0.009308f, 0.009964f, 0.010422f, 0.011200f, 0.011993f, 0.012726f, 0.013512f, 0.014511f, 0.015610f, 0.016724f, 0.017914f,
+ 0.019440f, 0.021057f, 0.022827f, 0.024933f, 0.027466f, 0.030197f, 0.033295f, 0.036896f, 0.041077f, 0.045776f, 0.050995f, 0.056976f,
+ 0.063721f, 0.071167f, 0.079773f, 0.089172f, 0.098633f, 0.109314f, 0.491699f, 0.543457f, 0.555176f, 0.561035f, 0.563477f, 0.565430f,
+ 0.000279f, 0.000821f, 0.000974f, 0.001161f, 0.001382f, 0.001583f, 0.001670f, 0.001934f, 0.002064f, 0.002153f, 0.002306f, 0.002544f,
+ 0.002670f, 0.002909f, 0.003052f, 0.003288f, 0.003429f, 0.003624f, 0.003893f, 0.004082f, 0.004406f, 0.004635f, 0.004925f, 0.005196f,
+ 0.005444f, 0.005764f, 0.006134f, 0.006546f, 0.006947f, 0.007343f, 0.007858f, 0.008270f, 0.008858f, 0.009346f, 0.010010f, 0.010757f,
+ 0.011475f, 0.012260f, 0.013206f, 0.014214f, 0.015236f, 0.016479f, 0.017975f, 0.019623f, 0.021515f, 0.023590f, 0.026062f, 0.028976f,
+ 0.032471f, 0.036224f, 0.040833f, 0.046082f, 0.052094f, 0.059052f, 0.066650f, 0.075684f, 0.084778f, 0.094971f, 0.479492f, 0.532715f,
+ 0.545898f, 0.551270f, 0.553711f, 0.555664f, 0.000253f, 0.000612f, 0.000835f, 0.000998f, 0.001111f, 0.001228f, 0.001334f, 0.001452f,
+ 0.001619f, 0.001757f, 0.001837f, 0.001920f, 0.002140f, 0.002321f, 0.002453f, 0.002544f, 0.002670f, 0.002790f, 0.003086f, 0.003260f,
+ 0.003422f, 0.003620f, 0.003893f, 0.004101f, 0.004326f, 0.004528f, 0.004761f, 0.005051f, 0.005444f, 0.005756f, 0.006065f, 0.006435f,
+ 0.006882f, 0.007378f, 0.007763f, 0.008286f, 0.008865f, 0.009506f, 0.010162f, 0.011024f, 0.011826f, 0.012917f, 0.013916f, 0.015175f,
+ 0.016602f, 0.018204f, 0.020035f, 0.022293f, 0.024948f, 0.028076f, 0.031921f, 0.036377f, 0.041565f, 0.047577f, 0.054535f, 0.062622f,
+ 0.071777f, 0.081787f, 0.465576f, 0.522461f, 0.535645f, 0.541992f, 0.544922f, 0.546875f, 0.000155f, 0.000398f, 0.000680f, 0.000828f,
+ 0.000907f, 0.000989f, 0.001113f, 0.001081f, 0.001253f, 0.001350f, 0.001453f, 0.001573f, 0.001661f, 0.001777f, 0.001829f, 0.001978f,
+ 0.002062f, 0.002216f, 0.002346f, 0.002470f, 0.002644f, 0.002804f, 0.002930f, 0.003134f, 0.003265f, 0.003485f, 0.003674f, 0.003866f,
+ 0.004154f, 0.004333f, 0.004707f, 0.004910f, 0.005180f, 0.005581f, 0.005875f, 0.006283f, 0.006729f, 0.007164f, 0.007713f, 0.008270f,
+ 0.008934f, 0.009727f, 0.010513f, 0.011482f, 0.012520f, 0.013710f, 0.015152f, 0.016815f, 0.018799f, 0.021118f, 0.024048f, 0.027756f,
+ 0.032104f, 0.037201f, 0.043518f, 0.050903f, 0.059418f, 0.068420f, 0.453125f, 0.511719f, 0.525391f, 0.530762f, 0.535156f, 0.536621f,
+ 0.000303f, 0.000337f, 0.000498f, 0.000560f, 0.000603f, 0.000721f, 0.000782f, 0.000845f, 0.000880f, 0.000988f, 0.001119f, 0.001184f,
+ 0.001258f, 0.001377f, 0.001420f, 0.001446f, 0.001590f, 0.001666f, 0.001754f, 0.001889f, 0.001980f, 0.002073f, 0.002216f, 0.002308f,
+ 0.002447f, 0.002562f, 0.002758f, 0.002899f, 0.003084f, 0.003328f, 0.003506f, 0.003641f, 0.003922f, 0.004147f, 0.004391f, 0.004665f,
+ 0.004959f, 0.005322f, 0.005695f, 0.006119f, 0.006588f, 0.007072f, 0.007790f, 0.008392f, 0.009178f, 0.010056f, 0.011124f, 0.012383f,
+ 0.013832f, 0.015587f, 0.017685f, 0.020309f, 0.023926f, 0.028076f, 0.033447f, 0.039978f, 0.047638f, 0.056335f, 0.440186f, 0.500000f,
+ 0.514160f, 0.520996f, 0.524414f, 0.526855f, 0.000132f, 0.000296f, 0.000368f, 0.000444f, 0.000501f, 0.000519f, 0.000631f, 0.000580f,
+ 0.000675f, 0.000735f, 0.000820f, 0.000840f, 0.000882f, 0.000946f, 0.001029f, 0.001070f, 0.001164f, 0.001221f, 0.001286f, 0.001317f,
+ 0.001416f, 0.001494f, 0.001607f, 0.001681f, 0.001763f, 0.001863f, 0.001978f, 0.002069f, 0.002169f, 0.002348f, 0.002451f, 0.002661f,
+ 0.002754f, 0.002943f, 0.003130f, 0.003323f, 0.003553f, 0.003813f, 0.004124f, 0.004364f, 0.004669f, 0.005062f, 0.005493f, 0.005985f,
+ 0.006546f, 0.007172f, 0.007950f, 0.008850f, 0.009857f, 0.011116f, 0.012695f, 0.014603f, 0.016983f, 0.020157f, 0.024490f, 0.029968f,
+ 0.036957f, 0.045166f, 0.426025f, 0.488770f, 0.503906f, 0.511719f, 0.515137f, 0.517578f, 0.000063f, 0.000160f, 0.000267f, 0.000282f,
+ 0.000339f, 0.000417f, 0.000377f, 0.000433f, 0.000472f, 0.000570f, 0.000563f, 0.000578f, 0.000599f, 0.000663f, 0.000681f, 0.000759f,
+ 0.000760f, 0.000845f, 0.000910f, 0.000941f, 0.000997f, 0.001057f, 0.001110f, 0.001169f, 0.001238f, 0.001288f, 0.001381f, 0.001441f,
+ 0.001514f, 0.001655f, 0.001693f, 0.001815f, 0.001910f, 0.002028f, 0.002153f, 0.002308f, 0.002441f, 0.002607f, 0.002783f, 0.002962f,
+ 0.003214f, 0.003458f, 0.003744f, 0.004051f, 0.004444f, 0.004883f, 0.005402f, 0.006031f, 0.006699f, 0.007610f, 0.008766f, 0.009933f,
+ 0.011688f, 0.013931f, 0.017075f, 0.021454f, 0.027313f, 0.035004f, 0.414307f, 0.478271f, 0.493652f, 0.501465f, 0.505859f, 0.508301f,
+ 0.000120f, 0.000194f, 0.000194f, 0.000205f, 0.000245f, 0.000246f, 0.000251f, 0.000301f, 0.000322f, 0.000332f, 0.000343f, 0.000413f,
+ 0.000397f, 0.000448f, 0.000481f, 0.000494f, 0.000545f, 0.000556f, 0.000582f, 0.000601f, 0.000653f, 0.000676f, 0.000726f, 0.000767f,
+ 0.000821f, 0.000840f, 0.000919f, 0.000952f, 0.001011f, 0.001054f, 0.001116f, 0.001186f, 0.001263f, 0.001337f, 0.001418f, 0.001482f,
+ 0.001607f, 0.001685f, 0.001842f, 0.001965f, 0.002090f, 0.002235f, 0.002420f, 0.002613f, 0.002851f, 0.003159f, 0.003492f, 0.003887f,
+ 0.004345f, 0.004906f, 0.005600f, 0.006474f, 0.007645f, 0.009186f, 0.011230f, 0.014305f, 0.019135f, 0.025848f, 0.400635f, 0.466797f,
+ 0.483398f, 0.490967f, 0.495117f, 0.498047f, 0.000030f, 0.000140f, 0.000121f, 0.000114f, 0.000147f, 0.000178f, 0.000159f, 0.000195f,
+ 0.000199f, 0.000204f, 0.000216f, 0.000223f, 0.000255f, 0.000271f, 0.000288f, 0.000302f, 0.000314f, 0.000346f, 0.000357f, 0.000395f,
+ 0.000397f, 0.000408f, 0.000436f, 0.000470f, 0.000501f, 0.000542f, 0.000547f, 0.000566f, 0.000612f, 0.000641f, 0.000692f, 0.000722f,
+ 0.000767f, 0.000798f, 0.000861f, 0.000898f, 0.000963f, 0.001030f, 0.001107f, 0.001164f, 0.001255f, 0.001361f, 0.001464f, 0.001591f,
+ 0.001719f, 0.001871f, 0.002111f, 0.002312f, 0.002617f, 0.002964f, 0.003368f, 0.003902f, 0.004654f, 0.005653f, 0.006958f, 0.008888f,
+ 0.012161f, 0.017822f, 0.388672f, 0.456543f, 0.473389f, 0.481201f, 0.486328f, 0.489014f, 0.000102f, 0.000076f, 0.000076f, 0.000075f,
+ 0.000095f, 0.000092f, 0.000109f, 0.000111f, 0.000112f, 0.000113f, 0.000126f, 0.000147f, 0.000135f, 0.000144f, 0.000165f, 0.000161f,
+ 0.000179f, 0.000192f, 0.000198f, 0.000202f, 0.000224f, 0.000232f, 0.000248f, 0.000259f, 0.000278f, 0.000295f, 0.000308f, 0.000320f,
+ 0.000340f, 0.000353f, 0.000379f, 0.000402f, 0.000423f, 0.000440f, 0.000472f, 0.000503f, 0.000526f, 0.000564f, 0.000610f, 0.000644f,
+ 0.000690f, 0.000741f, 0.000810f, 0.000862f, 0.000946f, 0.001024f, 0.001121f, 0.001247f, 0.001407f, 0.001603f, 0.001822f, 0.002144f,
+ 0.002539f, 0.003098f, 0.003901f, 0.005096f, 0.006931f, 0.011024f, 0.375244f, 0.444092f, 0.462158f, 0.470215f, 0.475586f, 0.478760f,
+ 0.000085f, 0.000061f, 0.000052f, 0.000047f, 0.000049f, 0.000046f, 0.000047f, 0.000050f, 0.000055f, 0.000069f, 0.000060f, 0.000062f,
+ 0.000077f, 0.000066f, 0.000069f, 0.000075f, 0.000084f, 0.000093f, 0.000093f, 0.000098f, 0.000102f, 0.000108f, 0.000111f, 0.000121f,
+ 0.000129f, 0.000136f, 0.000142f, 0.000154f, 0.000162f, 0.000172f, 0.000182f, 0.000187f, 0.000197f, 0.000209f, 0.000225f, 0.000231f,
+ 0.000246f, 0.000262f, 0.000290f, 0.000306f, 0.000321f, 0.000349f, 0.000380f, 0.000402f, 0.000437f, 0.000480f, 0.000525f, 0.000579f,
+ 0.000649f, 0.000735f, 0.000842f, 0.000984f, 0.001173f, 0.001451f, 0.001855f, 0.002485f, 0.003542f, 0.005753f, 0.362305f, 0.434326f,
+ 0.451904f, 0.460693f, 0.465576f, 0.468506f, 0.000064f, 0.000044f, 0.000036f, 0.000032f, 0.000029f, 0.000027f, 0.000025f, 0.000024f,
+ 0.000022f, 0.000023f, 0.000021f, 0.000027f, 0.000023f, 0.000022f, 0.000028f, 0.000031f, 0.000030f, 0.000034f, 0.000036f, 0.000038f,
+ 0.000040f, 0.000045f, 0.000048f, 0.000042f, 0.000047f, 0.000053f, 0.000055f, 0.000054f, 0.000060f, 0.000062f, 0.000065f, 0.000072f,
+ 0.000078f, 0.000075f, 0.000079f, 0.000087f, 0.000093f, 0.000098f, 0.000106f, 0.000113f, 0.000121f, 0.000126f, 0.000136f, 0.000150f,
+ 0.000159f, 0.000173f, 0.000190f, 0.000209f, 0.000235f, 0.000265f, 0.000302f, 0.000343f, 0.000416f, 0.000515f, 0.000665f, 0.000917f,
+ 0.001396f, 0.002401f, 0.349854f, 0.421875f, 0.440918f, 0.449951f, 0.455811f, 0.458008f, 0.000030f, 0.000020f, 0.000016f, 0.000014f,
+ 0.000014f, 0.000013f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000009f, 0.000009f,
+ 0.000009f, 0.000008f, 0.000008f, 0.000008f, 0.000007f, 0.000007f, 0.000008f, 0.000008f, 0.000009f, 0.000011f, 0.000011f, 0.000013f,
+ 0.000013f, 0.000012f, 0.000013f, 0.000014f, 0.000016f, 0.000018f, 0.000018f, 0.000019f, 0.000021f, 0.000021f, 0.000023f, 0.000027f,
+ 0.000025f, 0.000028f, 0.000031f, 0.000032f, 0.000033f, 0.000038f, 0.000043f, 0.000046f, 0.000050f, 0.000055f, 0.000062f, 0.000074f,
+ 0.000088f, 0.000106f, 0.000138f, 0.000191f, 0.000312f, 0.000653f, 0.337402f, 0.410645f, 0.431152f, 0.438965f, 0.445068f, 0.448975f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000004f, 0.000004f, 0.000004f, 0.000006f, 0.000010f, 0.000026f, 0.324219f, 0.399902f,
+ 0.419922f, 0.429688f, 0.435059f, 0.438965f,
+ },
+ {
+ 0.010521f, 0.032043f, 0.054443f, 0.076843f, 0.098572f, 0.121216f, 0.142700f, 0.164062f, 0.185913f, 0.207275f, 0.229004f, 0.249268f,
+ 0.270508f, 0.290527f, 0.311035f, 0.331055f, 0.350586f, 0.370361f, 0.389648f, 0.408936f, 0.428223f, 0.446533f, 0.465088f, 0.482666f,
+ 0.500977f, 0.519043f, 0.536133f, 0.553223f, 0.570801f, 0.587891f, 0.604980f, 0.621582f, 0.637207f, 0.653320f, 0.668945f, 0.685547f,
+ 0.700684f, 0.716309f, 0.730957f, 0.745605f, 0.760254f, 0.774902f, 0.789551f, 0.803711f, 0.816895f, 0.831543f, 0.845703f, 0.858887f,
+ 0.871582f, 0.885254f, 0.897949f, 0.910645f, 0.923340f, 0.936035f, 0.948242f, 0.959961f, 0.972168f, 0.984375f, 0.972656f, 0.936035f,
+ 0.910645f, 0.890137f, 0.872070f, 0.855957f, 0.010048f, 0.030350f, 0.051392f, 0.072266f, 0.093506f, 0.114319f, 0.135620f, 0.155273f,
+ 0.177124f, 0.197144f, 0.217773f, 0.237915f, 0.257568f, 0.277588f, 0.298096f, 0.316895f, 0.336182f, 0.355225f, 0.374268f, 0.393311f,
+ 0.411865f, 0.430176f, 0.448486f, 0.466309f, 0.483398f, 0.501465f, 0.519043f, 0.535645f, 0.552734f, 0.570312f, 0.586426f, 0.602539f,
+ 0.618652f, 0.635254f, 0.650879f, 0.666016f, 0.682129f, 0.697266f, 0.712402f, 0.727539f, 0.741699f, 0.756836f, 0.770996f, 0.785645f,
+ 0.799805f, 0.812988f, 0.826660f, 0.840332f, 0.854004f, 0.867676f, 0.881348f, 0.893066f, 0.907715f, 0.919434f, 0.932617f, 0.943848f,
+ 0.955566f, 0.968262f, 0.965332f, 0.930664f, 0.906738f, 0.886719f, 0.869629f, 0.854004f, 0.009254f, 0.028961f, 0.048615f, 0.068054f,
+ 0.088562f, 0.108093f, 0.128540f, 0.147705f, 0.167236f, 0.188599f, 0.207886f, 0.227295f, 0.244873f, 0.265625f, 0.284668f, 0.303955f,
+ 0.322510f, 0.340820f, 0.358887f, 0.378662f, 0.396484f, 0.414307f, 0.431885f, 0.448975f, 0.466797f, 0.484619f, 0.500977f, 0.519043f,
+ 0.535645f, 0.551758f, 0.568359f, 0.584961f, 0.600586f, 0.616699f, 0.632324f, 0.647949f, 0.663086f, 0.678223f, 0.693848f, 0.708984f,
+ 0.723633f, 0.738281f, 0.752930f, 0.767578f, 0.780762f, 0.794922f, 0.809082f, 0.822754f, 0.835938f, 0.849609f, 0.863770f, 0.875488f,
+ 0.888672f, 0.902344f, 0.915527f, 0.927246f, 0.939453f, 0.952637f, 0.958008f, 0.925293f, 0.901855f, 0.882812f, 0.866211f, 0.851562f,
+ 0.008736f, 0.027039f, 0.045807f, 0.064514f, 0.083801f, 0.102844f, 0.121826f, 0.140869f, 0.159302f, 0.179077f, 0.197388f, 0.216064f,
+ 0.234741f, 0.253662f, 0.271729f, 0.290283f, 0.308350f, 0.327148f, 0.344238f, 0.362061f, 0.381836f, 0.398926f, 0.416016f, 0.432373f,
+ 0.450195f, 0.466797f, 0.484375f, 0.500977f, 0.517090f, 0.533691f, 0.550781f, 0.567871f, 0.582031f, 0.598145f, 0.613770f, 0.629395f,
+ 0.645020f, 0.659668f, 0.675781f, 0.689941f, 0.705566f, 0.719727f, 0.734375f, 0.749512f, 0.763184f, 0.776855f, 0.791016f, 0.804688f,
+ 0.818848f, 0.832031f, 0.845215f, 0.858398f, 0.872559f, 0.884766f, 0.897949f, 0.909668f, 0.922852f, 0.936035f, 0.950684f, 0.919434f,
+ 0.896973f, 0.878906f, 0.862793f, 0.848633f, 0.008339f, 0.025543f, 0.043427f, 0.060974f, 0.078979f, 0.097168f, 0.115051f, 0.133179f,
+ 0.151367f, 0.169678f, 0.187988f, 0.206055f, 0.223999f, 0.241821f, 0.260742f, 0.277832f, 0.295166f, 0.313232f, 0.331299f, 0.347412f,
+ 0.365479f, 0.383057f, 0.399902f, 0.416992f, 0.433350f, 0.450195f, 0.467773f, 0.484863f, 0.499756f, 0.515625f, 0.532715f, 0.548340f,
+ 0.564941f, 0.580566f, 0.596191f, 0.610840f, 0.626953f, 0.641602f, 0.656738f, 0.671875f, 0.686035f, 0.701660f, 0.714844f, 0.730469f,
+ 0.745117f, 0.759766f, 0.772461f, 0.786621f, 0.801270f, 0.814453f, 0.827637f, 0.841309f, 0.854004f, 0.867676f, 0.880859f, 0.893555f,
+ 0.907227f, 0.919434f, 0.943359f, 0.913086f, 0.891602f, 0.874512f, 0.858887f, 0.845703f, 0.008102f, 0.024002f, 0.040802f, 0.057098f,
+ 0.074768f, 0.091553f, 0.108826f, 0.126343f, 0.143921f, 0.161377f, 0.179077f, 0.195923f, 0.213745f, 0.230835f, 0.248047f, 0.265869f,
+ 0.282227f, 0.299561f, 0.316895f, 0.334473f, 0.350586f, 0.367920f, 0.384277f, 0.400391f, 0.417725f, 0.434326f, 0.450195f, 0.467285f,
+ 0.482910f, 0.498291f, 0.514648f, 0.530762f, 0.546387f, 0.561523f, 0.577637f, 0.593262f, 0.608398f, 0.623535f, 0.637695f, 0.654297f,
+ 0.668457f, 0.682617f, 0.698242f, 0.711914f, 0.727051f, 0.741211f, 0.754395f, 0.768066f, 0.782715f, 0.796387f, 0.810547f, 0.823730f,
+ 0.836426f, 0.849609f, 0.863770f, 0.876465f, 0.889648f, 0.902344f, 0.934570f, 0.907715f, 0.887207f, 0.870117f, 0.854980f, 0.842285f,
+ 0.007504f, 0.022812f, 0.038727f, 0.054871f, 0.070312f, 0.087097f, 0.103088f, 0.119446f, 0.136475f, 0.153442f, 0.169556f, 0.186523f,
+ 0.203369f, 0.219971f, 0.236450f, 0.253418f, 0.270264f, 0.287109f, 0.302979f, 0.319824f, 0.336182f, 0.353271f, 0.369141f, 0.386230f,
+ 0.402100f, 0.417725f, 0.433594f, 0.450684f, 0.466553f, 0.482178f, 0.498047f, 0.513184f, 0.528809f, 0.543945f, 0.559082f, 0.575195f,
+ 0.589844f, 0.605469f, 0.621094f, 0.634277f, 0.649414f, 0.665039f, 0.679688f, 0.694824f, 0.708496f, 0.722168f, 0.736816f, 0.750000f,
+ 0.763184f, 0.778809f, 0.791504f, 0.805664f, 0.819336f, 0.832520f, 0.845703f, 0.858887f, 0.872070f, 0.885742f, 0.927246f, 0.900879f,
+ 0.881836f, 0.864746f, 0.851074f, 0.838867f, 0.006836f, 0.021683f, 0.036224f, 0.051666f, 0.066772f, 0.081970f, 0.098022f, 0.113831f,
+ 0.129517f, 0.145264f, 0.161011f, 0.177856f, 0.193359f, 0.209106f, 0.226196f, 0.241821f, 0.257812f, 0.274414f, 0.290283f, 0.306641f,
+ 0.322754f, 0.338623f, 0.354492f, 0.370361f, 0.386230f, 0.402100f, 0.417725f, 0.433838f, 0.449463f, 0.465088f, 0.480469f, 0.495605f,
+ 0.511719f, 0.527344f, 0.541016f, 0.556641f, 0.571777f, 0.587402f, 0.601562f, 0.617676f, 0.631836f, 0.646484f, 0.660645f, 0.674805f,
+ 0.689941f, 0.704102f, 0.718262f, 0.731934f, 0.746582f, 0.760254f, 0.774414f, 0.786621f, 0.801758f, 0.815430f, 0.828125f, 0.842285f,
+ 0.854980f, 0.868652f, 0.918457f, 0.894531f, 0.875977f, 0.859863f, 0.846680f, 0.834961f, 0.006672f, 0.020401f, 0.034088f, 0.048462f,
+ 0.062927f, 0.077820f, 0.092529f, 0.107666f, 0.122803f, 0.137695f, 0.152954f, 0.169067f, 0.183716f, 0.199829f, 0.214722f, 0.230347f,
+ 0.246704f, 0.262207f, 0.277832f, 0.292969f, 0.308105f, 0.324219f, 0.339600f, 0.354492f, 0.371094f, 0.386963f, 0.401855f, 0.418457f,
+ 0.432861f, 0.449219f, 0.463379f, 0.478271f, 0.494385f, 0.508301f, 0.523438f, 0.539551f, 0.553711f, 0.568848f, 0.583984f, 0.598633f,
+ 0.612793f, 0.627441f, 0.642578f, 0.656250f, 0.670898f, 0.685547f, 0.698730f, 0.714355f, 0.728027f, 0.742188f, 0.755859f, 0.769531f,
+ 0.783691f, 0.795898f, 0.810059f, 0.824707f, 0.838379f, 0.850586f, 0.910645f, 0.887695f, 0.870117f, 0.854980f, 0.842285f, 0.831055f,
+ 0.006207f, 0.019211f, 0.032623f, 0.046112f, 0.059662f, 0.073181f, 0.087585f, 0.102051f, 0.116577f, 0.130249f, 0.145142f, 0.159790f,
+ 0.175171f, 0.189575f, 0.205322f, 0.219238f, 0.235474f, 0.249634f, 0.265137f, 0.280029f, 0.294678f, 0.310547f, 0.325928f, 0.340820f,
+ 0.356201f, 0.371094f, 0.386230f, 0.401367f, 0.416504f, 0.431885f, 0.446533f, 0.461670f, 0.476074f, 0.492188f, 0.507324f, 0.520996f,
+ 0.535645f, 0.550781f, 0.564941f, 0.580078f, 0.594727f, 0.609863f, 0.623535f, 0.637695f, 0.652832f, 0.667480f, 0.681152f, 0.695312f,
+ 0.709473f, 0.723633f, 0.737793f, 0.751953f, 0.765137f, 0.779297f, 0.793945f, 0.807129f, 0.819824f, 0.833496f, 0.901855f, 0.880859f,
+ 0.864258f, 0.850098f, 0.837891f, 0.826660f, 0.006020f, 0.018219f, 0.030579f, 0.043365f, 0.055908f, 0.069153f, 0.082336f, 0.096802f,
+ 0.109497f, 0.123535f, 0.137451f, 0.151855f, 0.165649f, 0.180054f, 0.194702f, 0.208252f, 0.223999f, 0.238037f, 0.252930f, 0.267334f,
+ 0.281982f, 0.296875f, 0.312012f, 0.326904f, 0.340820f, 0.355957f, 0.370850f, 0.385986f, 0.400391f, 0.415039f, 0.430176f, 0.445801f,
+ 0.459229f, 0.474365f, 0.489014f, 0.502441f, 0.518066f, 0.533203f, 0.547363f, 0.562012f, 0.576660f, 0.590820f, 0.605469f, 0.619629f,
+ 0.633789f, 0.647949f, 0.663574f, 0.676758f, 0.690918f, 0.705566f, 0.719238f, 0.733398f, 0.746582f, 0.760254f, 0.774414f, 0.788574f,
+ 0.802246f, 0.816406f, 0.894043f, 0.874023f, 0.858398f, 0.844238f, 0.832031f, 0.822266f, 0.005520f, 0.017059f, 0.028625f, 0.040649f,
+ 0.053131f, 0.065552f, 0.077698f, 0.091187f, 0.104065f, 0.117371f, 0.130859f, 0.143677f, 0.157349f, 0.171021f, 0.184814f, 0.198730f,
+ 0.213135f, 0.226807f, 0.241211f, 0.255127f, 0.269775f, 0.283691f, 0.298096f, 0.312744f, 0.326660f, 0.341553f, 0.355957f, 0.370117f,
+ 0.384766f, 0.399170f, 0.414307f, 0.427979f, 0.442627f, 0.457764f, 0.471924f, 0.486084f, 0.500488f, 0.515137f, 0.529785f, 0.543945f,
+ 0.558594f, 0.572754f, 0.587402f, 0.601074f, 0.615234f, 0.629395f, 0.644043f, 0.657715f, 0.672852f, 0.685547f, 0.700684f, 0.714844f,
+ 0.728027f, 0.743164f, 0.756348f, 0.770508f, 0.785645f, 0.798340f, 0.885254f, 0.867676f, 0.852051f, 0.839355f, 0.828125f, 0.817871f,
+ 0.005241f, 0.015854f, 0.027481f, 0.038605f, 0.050171f, 0.061859f, 0.073853f, 0.085693f, 0.098328f, 0.111206f, 0.123474f, 0.136475f,
+ 0.149658f, 0.162598f, 0.175293f, 0.188477f, 0.202148f, 0.216431f, 0.229858f, 0.242798f, 0.256104f, 0.270264f, 0.284668f, 0.298828f,
+ 0.312744f, 0.326904f, 0.341064f, 0.355469f, 0.369141f, 0.383057f, 0.396729f, 0.411621f, 0.426025f, 0.439697f, 0.454590f, 0.468506f,
+ 0.482666f, 0.497070f, 0.512207f, 0.525391f, 0.540527f, 0.555176f, 0.567871f, 0.582031f, 0.596191f, 0.610840f, 0.625488f, 0.639648f,
+ 0.653809f, 0.668457f, 0.681641f, 0.695801f, 0.710449f, 0.724121f, 0.738770f, 0.751953f, 0.766602f, 0.780273f, 0.876465f, 0.860352f,
+ 0.845703f, 0.833984f, 0.822754f, 0.812988f, 0.004982f, 0.015274f, 0.025681f, 0.036438f, 0.047119f, 0.058167f, 0.069397f, 0.081055f,
+ 0.092957f, 0.104492f, 0.116577f, 0.128418f, 0.141113f, 0.153442f, 0.166504f, 0.179321f, 0.192261f, 0.205200f, 0.218506f, 0.231934f,
+ 0.244629f, 0.258301f, 0.271729f, 0.284912f, 0.299072f, 0.312988f, 0.325684f, 0.340088f, 0.353271f, 0.367676f, 0.381836f, 0.395508f,
+ 0.408936f, 0.423584f, 0.438232f, 0.451416f, 0.466309f, 0.479736f, 0.493896f, 0.507812f, 0.521973f, 0.536133f, 0.550293f, 0.563965f,
+ 0.578613f, 0.592773f, 0.606934f, 0.620605f, 0.635254f, 0.649414f, 0.663086f, 0.677246f, 0.691406f, 0.706543f, 0.720703f, 0.734375f,
+ 0.748047f, 0.762695f, 0.868164f, 0.853027f, 0.839355f, 0.828125f, 0.817383f, 0.808105f, 0.004745f, 0.014290f, 0.024506f, 0.034393f,
+ 0.044617f, 0.054749f, 0.065308f, 0.076538f, 0.087646f, 0.098938f, 0.110535f, 0.121582f, 0.134155f, 0.145264f, 0.157837f, 0.170166f,
+ 0.182373f, 0.194824f, 0.207153f, 0.220337f, 0.233276f, 0.245728f, 0.259277f, 0.271973f, 0.285645f, 0.298584f, 0.311768f, 0.325684f,
+ 0.338623f, 0.352539f, 0.365967f, 0.379395f, 0.393066f, 0.406738f, 0.421143f, 0.434326f, 0.448730f, 0.462402f, 0.475586f, 0.490479f,
+ 0.503906f, 0.518066f, 0.532227f, 0.546387f, 0.560059f, 0.574219f, 0.588379f, 0.602539f, 0.616211f, 0.630371f, 0.644531f, 0.658691f,
+ 0.673340f, 0.686523f, 0.701660f, 0.715332f, 0.730469f, 0.745117f, 0.858887f, 0.845215f, 0.833008f, 0.821777f, 0.812012f, 0.802734f,
+ 0.004494f, 0.013550f, 0.022675f, 0.032227f, 0.042145f, 0.052002f, 0.061554f, 0.072205f, 0.082520f, 0.093323f, 0.104614f, 0.115112f,
+ 0.126099f, 0.137817f, 0.149536f, 0.160767f, 0.172607f, 0.184692f, 0.196167f, 0.208862f, 0.221924f, 0.233765f, 0.246216f, 0.258545f,
+ 0.272461f, 0.284424f, 0.297119f, 0.310547f, 0.323242f, 0.336914f, 0.350586f, 0.363281f, 0.376953f, 0.390869f, 0.403564f, 0.416992f,
+ 0.431152f, 0.444824f, 0.458496f, 0.472656f, 0.486084f, 0.500000f, 0.513672f, 0.527832f, 0.541504f, 0.555664f, 0.569824f, 0.583496f,
+ 0.598145f, 0.611816f, 0.626465f, 0.639648f, 0.654297f, 0.668457f, 0.683594f, 0.697754f, 0.711914f, 0.726562f, 0.849609f, 0.838867f,
+ 0.826172f, 0.815918f, 0.806641f, 0.796875f, 0.004288f, 0.012619f, 0.021713f, 0.030945f, 0.039368f, 0.048737f, 0.058533f, 0.067932f,
+ 0.077759f, 0.088013f, 0.098755f, 0.108398f, 0.119080f, 0.129639f, 0.141235f, 0.152466f, 0.163940f, 0.174927f, 0.186768f, 0.198608f,
+ 0.210205f, 0.222290f, 0.234131f, 0.246094f, 0.258789f, 0.270508f, 0.283203f, 0.296631f, 0.309326f, 0.321777f, 0.335449f, 0.348145f,
+ 0.361084f, 0.374023f, 0.386963f, 0.400391f, 0.414062f, 0.427734f, 0.441162f, 0.455078f, 0.467773f, 0.482422f, 0.495117f, 0.509277f,
+ 0.523926f, 0.536621f, 0.550781f, 0.564941f, 0.579102f, 0.593262f, 0.607422f, 0.621582f, 0.635742f, 0.649902f, 0.664551f, 0.678711f,
+ 0.693848f, 0.708008f, 0.840820f, 0.831055f, 0.819336f, 0.809570f, 0.801270f, 0.792969f, 0.004013f, 0.012070f, 0.019989f, 0.029190f,
+ 0.037415f, 0.045776f, 0.055023f, 0.064392f, 0.073669f, 0.083374f, 0.092224f, 0.102295f, 0.112610f, 0.122742f, 0.133057f, 0.143799f,
+ 0.155273f, 0.165527f, 0.176880f, 0.188110f, 0.199463f, 0.210815f, 0.222534f, 0.234619f, 0.245972f, 0.258301f, 0.270508f, 0.282715f,
+ 0.294678f, 0.307129f, 0.320557f, 0.333008f, 0.345947f, 0.358398f, 0.371826f, 0.384277f, 0.397461f, 0.410889f, 0.424561f, 0.437256f,
+ 0.451416f, 0.464600f, 0.477783f, 0.491455f, 0.504395f, 0.518555f, 0.532715f, 0.546875f, 0.560547f, 0.574219f, 0.588379f, 0.604004f,
+ 0.617188f, 0.631348f, 0.645020f, 0.660645f, 0.674316f, 0.689941f, 0.832031f, 0.823242f, 0.813477f, 0.803711f, 0.794922f, 0.787109f,
+ 0.003790f, 0.011559f, 0.019119f, 0.027069f, 0.035034f, 0.043762f, 0.052032f, 0.060059f, 0.069153f, 0.078369f, 0.087280f, 0.096741f,
+ 0.105957f, 0.115967f, 0.125732f, 0.135620f, 0.146118f, 0.156128f, 0.166992f, 0.177612f, 0.188965f, 0.199829f, 0.210815f, 0.222290f,
+ 0.233887f, 0.244873f, 0.257324f, 0.268799f, 0.281006f, 0.292969f, 0.305420f, 0.317627f, 0.329834f, 0.341797f, 0.355469f, 0.368164f,
+ 0.380859f, 0.393311f, 0.407227f, 0.419434f, 0.433350f, 0.446533f, 0.459961f, 0.473633f, 0.486328f, 0.500488f, 0.515625f, 0.528320f,
+ 0.541504f, 0.556152f, 0.570312f, 0.584473f, 0.598633f, 0.612305f, 0.626465f, 0.640625f, 0.655762f, 0.670410f, 0.822266f, 0.815918f,
+ 0.805664f, 0.796387f, 0.788574f, 0.782227f, 0.003599f, 0.010727f, 0.018219f, 0.025177f, 0.033203f, 0.041046f, 0.048981f, 0.057220f,
+ 0.065247f, 0.073792f, 0.082764f, 0.091064f, 0.100220f, 0.108826f, 0.118591f, 0.128052f, 0.137573f, 0.147705f, 0.158081f, 0.167603f,
+ 0.177979f, 0.188721f, 0.198975f, 0.210205f, 0.221924f, 0.232544f, 0.243774f, 0.255615f, 0.267090f, 0.278564f, 0.290039f, 0.302490f,
+ 0.314941f, 0.327393f, 0.338623f, 0.352295f, 0.364014f, 0.377441f, 0.390381f, 0.403564f, 0.415039f, 0.428955f, 0.441895f, 0.455078f,
+ 0.468994f, 0.482666f, 0.496094f, 0.509277f, 0.523926f, 0.537598f, 0.551270f, 0.565430f, 0.579590f, 0.594238f, 0.608887f, 0.622559f,
+ 0.637207f, 0.651855f, 0.813477f, 0.807617f, 0.798340f, 0.790527f, 0.782715f, 0.775391f, 0.003355f, 0.009918f, 0.017105f, 0.023911f,
+ 0.031281f, 0.038147f, 0.045990f, 0.053284f, 0.061493f, 0.069214f, 0.077026f, 0.085571f, 0.093567f, 0.102600f, 0.111755f, 0.120728f,
+ 0.129761f, 0.138916f, 0.148804f, 0.158447f, 0.167725f, 0.177979f, 0.188965f, 0.198608f, 0.209473f, 0.220215f, 0.231567f, 0.242554f,
+ 0.253906f, 0.264160f, 0.276123f, 0.287109f, 0.300049f, 0.312012f, 0.323975f, 0.336182f, 0.348145f, 0.360840f, 0.372803f, 0.385986f,
+ 0.398438f, 0.411621f, 0.424316f, 0.437256f, 0.450439f, 0.464844f, 0.478027f, 0.490723f, 0.504395f, 0.518066f, 0.532715f, 0.546387f,
+ 0.561523f, 0.575684f, 0.589355f, 0.604004f, 0.618164f, 0.632324f, 0.802246f, 0.800293f, 0.792480f, 0.783691f, 0.776367f, 0.769531f,
+ 0.003265f, 0.009575f, 0.016144f, 0.022415f, 0.029510f, 0.036316f, 0.042755f, 0.050812f, 0.057556f, 0.065002f, 0.072388f, 0.080200f,
+ 0.087952f, 0.096680f, 0.104858f, 0.113281f, 0.122070f, 0.130493f, 0.139771f, 0.148926f, 0.158447f, 0.168335f, 0.177612f, 0.187500f,
+ 0.198120f, 0.208130f, 0.218750f, 0.229492f, 0.240234f, 0.250732f, 0.262207f, 0.273682f, 0.285156f, 0.296143f, 0.308594f, 0.320068f,
+ 0.332520f, 0.344482f, 0.357178f, 0.368652f, 0.381836f, 0.394043f, 0.406494f, 0.420410f, 0.433105f, 0.445801f, 0.459717f, 0.473633f,
+ 0.486816f, 0.500000f, 0.513672f, 0.527832f, 0.541992f, 0.556152f, 0.570312f, 0.585449f, 0.598633f, 0.613770f, 0.794434f, 0.791504f,
+ 0.784180f, 0.776855f, 0.770020f, 0.764160f, 0.002954f, 0.008904f, 0.014961f, 0.021210f, 0.027420f, 0.033905f, 0.040619f, 0.047363f,
+ 0.053986f, 0.060883f, 0.068054f, 0.075378f, 0.082703f, 0.090515f, 0.098022f, 0.105896f, 0.114319f, 0.122742f, 0.131592f, 0.139771f,
+ 0.149170f, 0.157959f, 0.167480f, 0.177124f, 0.186768f, 0.196411f, 0.206543f, 0.216919f, 0.227539f, 0.237671f, 0.248413f, 0.259277f,
+ 0.270264f, 0.281738f, 0.292725f, 0.304443f, 0.315918f, 0.327637f, 0.340576f, 0.352539f, 0.364746f, 0.377930f, 0.390137f, 0.401855f,
+ 0.415039f, 0.428223f, 0.441406f, 0.454834f, 0.468506f, 0.481689f, 0.494873f, 0.509277f, 0.523438f, 0.537598f, 0.551758f, 0.565918f,
+ 0.580078f, 0.594727f, 0.783691f, 0.783203f, 0.776855f, 0.770508f, 0.763672f, 0.757324f, 0.002836f, 0.008659f, 0.014351f, 0.019913f,
+ 0.025772f, 0.032074f, 0.037933f, 0.044128f, 0.050903f, 0.057159f, 0.064026f, 0.070496f, 0.077698f, 0.085022f, 0.091919f, 0.099426f,
+ 0.107727f, 0.114990f, 0.123169f, 0.131226f, 0.140015f, 0.148682f, 0.157349f, 0.166260f, 0.175171f, 0.184692f, 0.194214f, 0.203979f,
+ 0.214355f, 0.224487f, 0.234985f, 0.245728f, 0.256104f, 0.267334f, 0.278320f, 0.288818f, 0.301025f, 0.312256f, 0.324219f, 0.335938f,
+ 0.347900f, 0.360596f, 0.372070f, 0.384521f, 0.397217f, 0.410400f, 0.423340f, 0.436279f, 0.449463f, 0.463135f, 0.476807f, 0.490723f,
+ 0.503906f, 0.517578f, 0.532227f, 0.546875f, 0.561035f, 0.575684f, 0.773926f, 0.775391f, 0.769043f, 0.763672f, 0.757812f, 0.751953f,
+ 0.002506f, 0.008080f, 0.013100f, 0.018738f, 0.024384f, 0.029953f, 0.035797f, 0.041473f, 0.047485f, 0.053558f, 0.059265f, 0.065918f,
+ 0.072693f, 0.079468f, 0.086426f, 0.093384f, 0.100708f, 0.108032f, 0.115417f, 0.122986f, 0.130615f, 0.139038f, 0.147827f, 0.156494f,
+ 0.165039f, 0.173828f, 0.182617f, 0.192139f, 0.201782f, 0.211426f, 0.221558f, 0.231323f, 0.242188f, 0.252686f, 0.263672f, 0.274414f,
+ 0.284912f, 0.296143f, 0.308105f, 0.319824f, 0.331543f, 0.343750f, 0.355225f, 0.367432f, 0.379883f, 0.393066f, 0.405273f, 0.418457f,
+ 0.431641f, 0.444580f, 0.457764f, 0.471924f, 0.485840f, 0.499268f, 0.512695f, 0.527344f, 0.542480f, 0.556641f, 0.764160f, 0.766602f,
+ 0.761719f, 0.756348f, 0.750488f, 0.745605f, 0.002640f, 0.007809f, 0.012497f, 0.017593f, 0.023102f, 0.028122f, 0.033569f, 0.038879f,
+ 0.044250f, 0.049988f, 0.055908f, 0.061615f, 0.067627f, 0.074036f, 0.080566f, 0.087524f, 0.093262f, 0.100769f, 0.107910f, 0.114929f,
+ 0.121948f, 0.130371f, 0.137939f, 0.146362f, 0.154297f, 0.163208f, 0.171509f, 0.180664f, 0.189697f, 0.199341f, 0.208618f, 0.218506f,
+ 0.228394f, 0.238892f, 0.248779f, 0.259277f, 0.270752f, 0.281250f, 0.292236f, 0.303467f, 0.315186f, 0.326660f, 0.338867f, 0.351074f,
+ 0.362305f, 0.374756f, 0.387939f, 0.400146f, 0.413330f, 0.426514f, 0.439209f, 0.452881f, 0.466553f, 0.480225f, 0.494141f, 0.508301f,
+ 0.522949f, 0.537109f, 0.753906f, 0.758301f, 0.754395f, 0.749023f, 0.743652f, 0.739258f, 0.002441f, 0.007088f, 0.011993f, 0.016266f,
+ 0.021255f, 0.026031f, 0.031189f, 0.036072f, 0.041260f, 0.046753f, 0.052155f, 0.057587f, 0.063232f, 0.068787f, 0.075623f, 0.081055f,
+ 0.087341f, 0.094177f, 0.100647f, 0.106689f, 0.113892f, 0.121399f, 0.129028f, 0.136841f, 0.144287f, 0.152222f, 0.160522f, 0.169312f,
+ 0.178101f, 0.186523f, 0.196045f, 0.205200f, 0.214966f, 0.224487f, 0.234863f, 0.244751f, 0.255371f, 0.265625f, 0.276367f, 0.287842f,
+ 0.298828f, 0.310303f, 0.321533f, 0.333984f, 0.345459f, 0.357666f, 0.370117f, 0.382568f, 0.394287f, 0.407959f, 0.421875f, 0.433838f,
+ 0.446777f, 0.461426f, 0.475098f, 0.488525f, 0.504395f, 0.517578f, 0.744141f, 0.749512f, 0.746094f, 0.741699f, 0.736816f, 0.732422f,
+ 0.002172f, 0.006695f, 0.011093f, 0.015266f, 0.020081f, 0.024521f, 0.029388f, 0.033966f, 0.038727f, 0.043427f, 0.048706f, 0.053772f,
+ 0.059418f, 0.064270f, 0.069580f, 0.075500f, 0.081421f, 0.087280f, 0.093262f, 0.099670f, 0.106567f, 0.113220f, 0.119995f, 0.127197f,
+ 0.134644f, 0.142212f, 0.150146f, 0.157959f, 0.166382f, 0.174927f, 0.184082f, 0.192505f, 0.201904f, 0.211792f, 0.220825f, 0.230713f,
+ 0.240601f, 0.251221f, 0.261719f, 0.272461f, 0.282715f, 0.294434f, 0.305420f, 0.316650f, 0.328369f, 0.340088f, 0.352783f, 0.364746f,
+ 0.377197f, 0.389648f, 0.402832f, 0.416016f, 0.429443f, 0.442627f, 0.456055f, 0.469971f, 0.484863f, 0.499268f, 0.733887f, 0.741211f,
+ 0.737793f, 0.734375f, 0.729980f, 0.725586f, 0.002045f, 0.006187f, 0.010406f, 0.014664f, 0.018570f, 0.022675f, 0.027176f, 0.031586f,
+ 0.035858f, 0.040253f, 0.045227f, 0.049774f, 0.054504f, 0.059692f, 0.065186f, 0.070374f, 0.075500f, 0.080627f, 0.086792f, 0.092285f,
+ 0.098999f, 0.104675f, 0.111816f, 0.118286f, 0.125610f, 0.132324f, 0.139771f, 0.147339f, 0.155029f, 0.163696f, 0.171631f, 0.180420f,
+ 0.189087f, 0.197754f, 0.207275f, 0.216309f, 0.226440f, 0.236694f, 0.246338f, 0.256836f, 0.267334f, 0.278320f, 0.289062f, 0.300537f,
+ 0.312012f, 0.323975f, 0.335449f, 0.347168f, 0.359375f, 0.372314f, 0.384521f, 0.396973f, 0.410400f, 0.423584f, 0.437500f, 0.450928f,
+ 0.465332f, 0.479736f, 0.723145f, 0.732422f, 0.729980f, 0.726562f, 0.722656f, 0.718750f, 0.002148f, 0.005802f, 0.009811f, 0.013565f,
+ 0.017578f, 0.021179f, 0.025040f, 0.029053f, 0.033417f, 0.037445f, 0.042114f, 0.046112f, 0.050720f, 0.055511f, 0.060028f, 0.065002f,
+ 0.069458f, 0.075134f, 0.080078f, 0.085693f, 0.091492f, 0.097290f, 0.103394f, 0.109802f, 0.116089f, 0.122925f, 0.129883f, 0.136963f,
+ 0.144165f, 0.151733f, 0.160156f, 0.167847f, 0.176392f, 0.184692f, 0.193848f, 0.203003f, 0.212402f, 0.221680f, 0.231689f, 0.242065f,
+ 0.251953f, 0.262207f, 0.273193f, 0.283936f, 0.295410f, 0.306152f, 0.318359f, 0.329590f, 0.342285f, 0.354248f, 0.366455f, 0.379150f,
+ 0.391846f, 0.405273f, 0.418701f, 0.432617f, 0.446289f, 0.460205f, 0.712891f, 0.723633f, 0.722168f, 0.718750f, 0.715332f, 0.712402f,
+ 0.001963f, 0.005642f, 0.009071f, 0.012756f, 0.016006f, 0.020020f, 0.023422f, 0.027679f, 0.030762f, 0.034943f, 0.038605f, 0.042969f,
+ 0.047028f, 0.051178f, 0.055542f, 0.060120f, 0.064575f, 0.069153f, 0.074280f, 0.079041f, 0.084595f, 0.089905f, 0.095276f, 0.101440f,
+ 0.107300f, 0.113586f, 0.119751f, 0.127075f, 0.134033f, 0.141357f, 0.148438f, 0.155884f, 0.164062f, 0.172729f, 0.180542f, 0.190063f,
+ 0.198364f, 0.207764f, 0.217163f, 0.226807f, 0.236938f, 0.247070f, 0.257324f, 0.268066f, 0.278320f, 0.289795f, 0.301025f, 0.312744f,
+ 0.324707f, 0.336182f, 0.347900f, 0.360840f, 0.372803f, 0.386230f, 0.399902f, 0.413574f, 0.427246f, 0.441162f, 0.702148f, 0.714355f,
+ 0.713867f, 0.711426f, 0.707520f, 0.704590f, 0.001995f, 0.005245f, 0.008553f, 0.011543f, 0.015015f, 0.018326f, 0.021881f, 0.025131f,
+ 0.028641f, 0.032349f, 0.035675f, 0.039520f, 0.043549f, 0.047089f, 0.051086f, 0.054962f, 0.059265f, 0.063782f, 0.068054f, 0.072571f,
+ 0.077759f, 0.082520f, 0.088013f, 0.093323f, 0.098755f, 0.104858f, 0.111145f, 0.117371f, 0.123840f, 0.130615f, 0.137207f, 0.144897f,
+ 0.152344f, 0.160278f, 0.167969f, 0.176514f, 0.185425f, 0.193848f, 0.202881f, 0.212524f, 0.221924f, 0.231323f, 0.241821f, 0.251953f,
+ 0.262451f, 0.272949f, 0.284424f, 0.295166f, 0.306396f, 0.319092f, 0.329590f, 0.343018f, 0.355225f, 0.368652f, 0.381348f, 0.393799f,
+ 0.408447f, 0.422852f, 0.691406f, 0.706055f, 0.706055f, 0.703125f, 0.700684f, 0.697754f, 0.001692f, 0.004898f, 0.007828f, 0.011070f,
+ 0.013992f, 0.017227f, 0.020187f, 0.023499f, 0.026520f, 0.029526f, 0.033081f, 0.036377f, 0.039459f, 0.043396f, 0.047028f, 0.050323f,
+ 0.054199f, 0.058350f, 0.062317f, 0.066711f, 0.071106f, 0.075928f, 0.080750f, 0.085510f, 0.090820f, 0.096497f, 0.102234f, 0.107727f,
+ 0.114075f, 0.120300f, 0.126587f, 0.133789f, 0.141113f, 0.148193f, 0.156006f, 0.163696f, 0.171753f, 0.180542f, 0.188965f, 0.198120f,
+ 0.207275f, 0.216797f, 0.226318f, 0.236206f, 0.246338f, 0.256836f, 0.267334f, 0.278809f, 0.289795f, 0.300781f, 0.313232f, 0.324707f,
+ 0.337402f, 0.349365f, 0.362305f, 0.376221f, 0.389404f, 0.403809f, 0.680176f, 0.696289f, 0.697266f, 0.695312f, 0.692871f, 0.689941f,
+ 0.001606f, 0.004543f, 0.007450f, 0.010269f, 0.012962f, 0.015900f, 0.018677f, 0.021591f, 0.024628f, 0.027618f, 0.030182f, 0.033783f,
+ 0.036194f, 0.039734f, 0.042725f, 0.046478f, 0.049652f, 0.053253f, 0.057251f, 0.060883f, 0.065186f, 0.069336f, 0.073730f, 0.078247f,
+ 0.083252f, 0.088501f, 0.093628f, 0.099182f, 0.104553f, 0.110718f, 0.116577f, 0.123108f, 0.129883f, 0.136719f, 0.143921f, 0.151367f,
+ 0.159302f, 0.167114f, 0.175415f, 0.183960f, 0.192871f, 0.202148f, 0.210938f, 0.221436f, 0.230713f, 0.240723f, 0.250977f, 0.261963f,
+ 0.272461f, 0.283691f, 0.295166f, 0.306885f, 0.319092f, 0.331055f, 0.343750f, 0.356689f, 0.370361f, 0.383545f, 0.669434f, 0.687500f,
+ 0.688965f, 0.687500f, 0.685547f, 0.682617f, 0.001701f, 0.004345f, 0.006802f, 0.009514f, 0.012283f, 0.014793f, 0.017288f, 0.019958f,
+ 0.022614f, 0.025177f, 0.027695f, 0.030487f, 0.033081f, 0.035858f, 0.039185f, 0.042236f, 0.045319f, 0.048523f, 0.051941f, 0.055847f,
+ 0.059326f, 0.063171f, 0.067139f, 0.071594f, 0.075928f, 0.080566f, 0.085571f, 0.090454f, 0.095520f, 0.101196f, 0.106567f, 0.112427f,
+ 0.119019f, 0.125610f, 0.132324f, 0.139282f, 0.146973f, 0.154419f, 0.161987f, 0.170532f, 0.178833f, 0.187134f, 0.196777f, 0.206177f,
+ 0.214966f, 0.225220f, 0.235352f, 0.246094f, 0.255615f, 0.266846f, 0.278320f, 0.290039f, 0.301270f, 0.313477f, 0.325195f, 0.338867f,
+ 0.352539f, 0.365234f, 0.657715f, 0.678711f, 0.679688f, 0.679199f, 0.677734f, 0.675293f, 0.001310f, 0.003979f, 0.006393f, 0.008522f,
+ 0.011223f, 0.013557f, 0.015976f, 0.018433f, 0.020737f, 0.022842f, 0.025421f, 0.027649f, 0.030289f, 0.032806f, 0.035645f, 0.038025f,
+ 0.041199f, 0.044220f, 0.047058f, 0.050720f, 0.053589f, 0.057281f, 0.061157f, 0.064941f, 0.068787f, 0.072998f, 0.077698f, 0.082153f,
+ 0.086975f, 0.092102f, 0.097229f, 0.103027f, 0.108826f, 0.114746f, 0.121094f, 0.127930f, 0.134521f, 0.141846f, 0.149292f, 0.157227f,
+ 0.164673f, 0.173218f, 0.182007f, 0.190552f, 0.199951f, 0.209717f, 0.219360f, 0.229004f, 0.239502f, 0.250244f, 0.260986f, 0.272461f,
+ 0.282959f, 0.295166f, 0.307373f, 0.320557f, 0.333252f, 0.346436f, 0.646973f, 0.668945f, 0.670898f, 0.671387f, 0.669922f, 0.668457f,
+ 0.001348f, 0.003523f, 0.005863f, 0.008133f, 0.010338f, 0.012520f, 0.014511f, 0.016464f, 0.018768f, 0.020920f, 0.022888f, 0.025665f,
+ 0.027588f, 0.029861f, 0.032135f, 0.034485f, 0.037140f, 0.040039f, 0.042725f, 0.045532f, 0.048859f, 0.051971f, 0.055237f, 0.058594f,
+ 0.062408f, 0.066101f, 0.070251f, 0.074280f, 0.078735f, 0.083435f, 0.088318f, 0.093567f, 0.098633f, 0.104431f, 0.110291f, 0.116455f,
+ 0.122986f, 0.129517f, 0.136963f, 0.143921f, 0.152222f, 0.159546f, 0.167358f, 0.176514f, 0.185181f, 0.194214f, 0.203857f, 0.213623f,
+ 0.223389f, 0.233521f, 0.244385f, 0.255127f, 0.266602f, 0.277832f, 0.289307f, 0.301758f, 0.314697f, 0.328613f, 0.635254f, 0.659668f,
+ 0.663086f, 0.663086f, 0.662109f, 0.660156f, 0.001084f, 0.003263f, 0.005554f, 0.007416f, 0.009445f, 0.011185f, 0.013161f, 0.015366f,
+ 0.017136f, 0.019058f, 0.020935f, 0.022781f, 0.024857f, 0.026886f, 0.029160f, 0.031097f, 0.033569f, 0.035858f, 0.038361f, 0.040924f,
+ 0.043427f, 0.046478f, 0.049500f, 0.052948f, 0.056122f, 0.059418f, 0.063293f, 0.067139f, 0.070923f, 0.075073f, 0.079712f, 0.084229f,
+ 0.089233f, 0.094604f, 0.100037f, 0.105774f, 0.111694f, 0.117798f, 0.124634f, 0.131226f, 0.139038f, 0.146484f, 0.154175f, 0.162231f,
+ 0.170654f, 0.179199f, 0.188599f, 0.197754f, 0.207153f, 0.217407f, 0.227295f, 0.238159f, 0.248657f, 0.260986f, 0.271973f, 0.284912f,
+ 0.296631f, 0.308838f, 0.623535f, 0.650391f, 0.653809f, 0.654297f, 0.653809f, 0.652832f, 0.001070f, 0.003069f, 0.005108f, 0.006855f,
+ 0.008522f, 0.010384f, 0.011993f, 0.013847f, 0.015549f, 0.016968f, 0.018677f, 0.020660f, 0.022079f, 0.024048f, 0.026077f, 0.027954f,
+ 0.030014f, 0.032135f, 0.034210f, 0.036560f, 0.038971f, 0.041840f, 0.044434f, 0.047089f, 0.049896f, 0.053284f, 0.056763f, 0.060120f,
+ 0.063477f, 0.067505f, 0.071533f, 0.075928f, 0.080261f, 0.085205f, 0.089905f, 0.095520f, 0.100830f, 0.106567f, 0.113159f, 0.119385f,
+ 0.126221f, 0.133301f, 0.140259f, 0.148560f, 0.156494f, 0.165039f, 0.173462f, 0.182861f, 0.192017f, 0.201172f, 0.211548f, 0.221802f,
+ 0.232666f, 0.243286f, 0.254639f, 0.265869f, 0.278809f, 0.291260f, 0.611816f, 0.640625f, 0.645508f, 0.645996f, 0.645508f, 0.645020f,
+ 0.001057f, 0.002815f, 0.004646f, 0.006187f, 0.007935f, 0.009583f, 0.011139f, 0.012428f, 0.013878f, 0.015404f, 0.016830f, 0.018433f,
+ 0.019836f, 0.021637f, 0.023300f, 0.024857f, 0.026855f, 0.028519f, 0.030533f, 0.032593f, 0.034790f, 0.037140f, 0.039520f, 0.041748f,
+ 0.044525f, 0.047302f, 0.050232f, 0.053497f, 0.056580f, 0.059998f, 0.063721f, 0.067627f, 0.071777f, 0.076111f, 0.080627f, 0.085571f,
+ 0.090698f, 0.096130f, 0.101624f, 0.107849f, 0.114258f, 0.120544f, 0.127686f, 0.135132f, 0.142700f, 0.150269f, 0.158813f, 0.167725f,
+ 0.176392f, 0.185791f, 0.195312f, 0.205444f, 0.216064f, 0.226562f, 0.237793f, 0.248657f, 0.260254f, 0.272949f, 0.600098f, 0.631348f,
+ 0.636230f, 0.637207f, 0.637695f, 0.636719f, 0.001022f, 0.002628f, 0.004486f, 0.005684f, 0.007179f, 0.008636f, 0.009911f, 0.011307f,
+ 0.012428f, 0.013771f, 0.015152f, 0.016342f, 0.017822f, 0.018997f, 0.020584f, 0.022263f, 0.023651f, 0.025482f, 0.027191f, 0.028793f,
+ 0.030960f, 0.032715f, 0.034912f, 0.036987f, 0.039368f, 0.041840f, 0.044495f, 0.047180f, 0.050110f, 0.053314f, 0.056580f, 0.060059f,
+ 0.063660f, 0.067383f, 0.071777f, 0.075928f, 0.081055f, 0.085938f, 0.091187f, 0.096619f, 0.102356f, 0.108826f, 0.115051f, 0.121948f,
+ 0.129150f, 0.136475f, 0.144653f, 0.152832f, 0.161621f, 0.170288f, 0.179932f, 0.189209f, 0.198730f, 0.209595f, 0.220459f, 0.231201f,
+ 0.242798f, 0.255615f, 0.588867f, 0.621094f, 0.626953f, 0.629883f, 0.629395f, 0.629883f, 0.001016f, 0.002304f, 0.003975f, 0.005024f,
+ 0.006584f, 0.007812f, 0.008926f, 0.009987f, 0.011024f, 0.012199f, 0.013321f, 0.014595f, 0.015617f, 0.016830f, 0.018326f, 0.019577f,
+ 0.020798f, 0.022293f, 0.023758f, 0.025253f, 0.027145f, 0.028656f, 0.030640f, 0.032501f, 0.034546f, 0.036682f, 0.039001f, 0.041412f,
+ 0.044037f, 0.046875f, 0.049622f, 0.052917f, 0.056030f, 0.059387f, 0.063354f, 0.067383f, 0.071655f, 0.075928f, 0.080750f, 0.085876f,
+ 0.091248f, 0.097168f, 0.102905f, 0.109497f, 0.116272f, 0.123413f, 0.130859f, 0.138550f, 0.147217f, 0.155518f, 0.164551f, 0.173828f,
+ 0.183350f, 0.193481f, 0.204102f, 0.214600f, 0.225342f, 0.237915f, 0.575684f, 0.611816f, 0.617188f, 0.621094f, 0.621582f, 0.620605f,
+ 0.000768f, 0.002398f, 0.003801f, 0.004875f, 0.005848f, 0.006889f, 0.008072f, 0.008820f, 0.009758f, 0.010910f, 0.011810f, 0.013023f,
+ 0.013878f, 0.014786f, 0.016083f, 0.017166f, 0.018402f, 0.019577f, 0.020691f, 0.022125f, 0.023743f, 0.025009f, 0.026779f, 0.028336f,
+ 0.030075f, 0.031921f, 0.033997f, 0.036255f, 0.038452f, 0.040833f, 0.043488f, 0.045959f, 0.049011f, 0.052216f, 0.055634f, 0.059052f,
+ 0.062744f, 0.066956f, 0.071289f, 0.075745f, 0.080566f, 0.086060f, 0.091614f, 0.097351f, 0.103821f, 0.110291f, 0.117432f, 0.124939f,
+ 0.132568f, 0.140869f, 0.149414f, 0.158325f, 0.168213f, 0.177368f, 0.187744f, 0.197876f, 0.208984f, 0.219849f, 0.563965f, 0.602051f,
+ 0.608887f, 0.610840f, 0.613770f, 0.612305f, 0.000764f, 0.002028f, 0.003302f, 0.004276f, 0.005325f, 0.006035f, 0.007034f, 0.007843f,
+ 0.008904f, 0.009628f, 0.010323f, 0.011192f, 0.012039f, 0.013092f, 0.013924f, 0.014854f, 0.015793f, 0.016953f, 0.018036f, 0.019211f,
+ 0.020355f, 0.021667f, 0.023010f, 0.024582f, 0.026016f, 0.027771f, 0.029434f, 0.031235f, 0.033264f, 0.035217f, 0.037628f, 0.039886f,
+ 0.042084f, 0.044952f, 0.048126f, 0.051392f, 0.054779f, 0.058197f, 0.062164f, 0.066223f, 0.070740f, 0.075439f, 0.080566f, 0.086182f,
+ 0.091919f, 0.098145f, 0.104431f, 0.111633f, 0.119080f, 0.126587f, 0.134888f, 0.143311f, 0.152710f, 0.162109f, 0.171631f, 0.182129f,
+ 0.192139f, 0.203491f, 0.552246f, 0.591309f, 0.599609f, 0.602539f, 0.604004f, 0.604980f, 0.000782f, 0.001970f, 0.003082f, 0.003859f,
+ 0.004635f, 0.005611f, 0.006123f, 0.006767f, 0.007595f, 0.008270f, 0.009140f, 0.009674f, 0.010490f, 0.011040f, 0.011902f, 0.012749f,
+ 0.013573f, 0.014526f, 0.015656f, 0.016541f, 0.017548f, 0.018631f, 0.019730f, 0.021103f, 0.022446f, 0.023758f, 0.025162f, 0.026611f,
+ 0.028458f, 0.030441f, 0.032074f, 0.034302f, 0.036316f, 0.038727f, 0.041138f, 0.044098f, 0.046997f, 0.050232f, 0.053711f, 0.057281f,
+ 0.061340f, 0.065491f, 0.070435f, 0.075256f, 0.080688f, 0.086426f, 0.092346f, 0.098694f, 0.105896f, 0.113098f, 0.120911f, 0.129028f,
+ 0.137695f, 0.146606f, 0.155884f, 0.165894f, 0.175903f, 0.186768f, 0.540527f, 0.582520f, 0.590332f, 0.593750f, 0.594727f, 0.596191f,
+ 0.000711f, 0.001649f, 0.002529f, 0.003332f, 0.004036f, 0.004799f, 0.005444f, 0.006050f, 0.006638f, 0.007160f, 0.007771f, 0.008331f,
+ 0.008980f, 0.009644f, 0.010307f, 0.010887f, 0.011787f, 0.012306f, 0.013176f, 0.014099f, 0.014915f, 0.015839f, 0.016708f, 0.017822f,
+ 0.019073f, 0.020233f, 0.021423f, 0.022690f, 0.024033f, 0.025589f, 0.027344f, 0.028976f, 0.030930f, 0.032990f, 0.035156f, 0.037445f,
+ 0.040131f, 0.042847f, 0.045776f, 0.049042f, 0.052551f, 0.056519f, 0.060486f, 0.064941f, 0.069458f, 0.074951f, 0.080444f, 0.086487f,
+ 0.092957f, 0.099915f, 0.107361f, 0.114929f, 0.123535f, 0.131714f, 0.140747f, 0.150513f, 0.160767f, 0.171265f, 0.527832f, 0.572754f,
+ 0.581543f, 0.583496f, 0.586426f, 0.587402f, 0.000504f, 0.001575f, 0.002235f, 0.003147f, 0.003641f, 0.004150f, 0.004570f, 0.005173f,
+ 0.005863f, 0.006016f, 0.006462f, 0.007111f, 0.007660f, 0.008156f, 0.008736f, 0.009354f, 0.010094f, 0.010475f, 0.011253f, 0.011879f,
+ 0.012657f, 0.013603f, 0.014267f, 0.015099f, 0.016144f, 0.017014f, 0.017990f, 0.019104f, 0.020416f, 0.021652f, 0.022919f, 0.024353f,
+ 0.025986f, 0.027710f, 0.029602f, 0.031494f, 0.033722f, 0.036102f, 0.038635f, 0.041412f, 0.044525f, 0.047729f, 0.051636f, 0.055511f,
+ 0.059540f, 0.064331f, 0.069580f, 0.075073f, 0.080750f, 0.087341f, 0.094116f, 0.101379f, 0.109558f, 0.117676f, 0.126221f, 0.135376f,
+ 0.145874f, 0.155518f, 0.516113f, 0.562012f, 0.571777f, 0.576172f, 0.578125f, 0.579102f, 0.000445f, 0.001304f, 0.002201f, 0.002535f,
+ 0.003126f, 0.003664f, 0.004047f, 0.004463f, 0.004887f, 0.005234f, 0.005711f, 0.005997f, 0.006500f, 0.006901f, 0.007389f, 0.007904f,
+ 0.008293f, 0.008919f, 0.009499f, 0.009941f, 0.010635f, 0.011269f, 0.011948f, 0.012589f, 0.013435f, 0.014252f, 0.015091f, 0.016052f,
+ 0.017059f, 0.017960f, 0.019241f, 0.020264f, 0.021667f, 0.022995f, 0.024628f, 0.026230f, 0.027985f, 0.029984f, 0.032288f, 0.034515f,
+ 0.037140f, 0.040009f, 0.043152f, 0.046722f, 0.050354f, 0.054504f, 0.059143f, 0.064026f, 0.069458f, 0.075256f, 0.081726f, 0.088562f,
+ 0.095825f, 0.103516f, 0.112000f, 0.120850f, 0.130005f, 0.140381f, 0.502441f, 0.551758f, 0.562012f, 0.566406f, 0.568848f, 0.571289f,
+ 0.000396f, 0.001226f, 0.001812f, 0.002357f, 0.002796f, 0.003094f, 0.003328f, 0.003763f, 0.003979f, 0.004364f, 0.004642f, 0.005051f,
+ 0.005489f, 0.005745f, 0.006126f, 0.006611f, 0.007004f, 0.007473f, 0.007771f, 0.008293f, 0.008919f, 0.009392f, 0.009941f, 0.010483f,
+ 0.011169f, 0.011765f, 0.012436f, 0.013344f, 0.014030f, 0.014908f, 0.015778f, 0.016769f, 0.017838f, 0.018997f, 0.020279f, 0.021622f,
+ 0.023056f, 0.024704f, 0.026474f, 0.028580f, 0.030579f, 0.033051f, 0.035706f, 0.038605f, 0.041840f, 0.045380f, 0.049500f, 0.053986f,
+ 0.058685f, 0.063843f, 0.069885f, 0.076050f, 0.083191f, 0.090576f, 0.098511f, 0.107056f, 0.115479f, 0.125122f, 0.491211f, 0.541504f,
+ 0.552734f, 0.557617f, 0.560547f, 0.562012f, 0.000559f, 0.001152f, 0.001668f, 0.001955f, 0.002234f, 0.002550f, 0.002821f, 0.003057f,
+ 0.003296f, 0.003635f, 0.003948f, 0.004189f, 0.004448f, 0.004761f, 0.005077f, 0.005417f, 0.005699f, 0.006142f, 0.006458f, 0.006844f,
+ 0.007271f, 0.007717f, 0.008156f, 0.008675f, 0.009132f, 0.009590f, 0.010277f, 0.010864f, 0.011482f, 0.012131f, 0.012901f, 0.013741f,
+ 0.014595f, 0.015549f, 0.016525f, 0.017563f, 0.018799f, 0.020111f, 0.021484f, 0.023087f, 0.024765f, 0.026840f, 0.028992f, 0.031403f,
+ 0.034119f, 0.037323f, 0.040680f, 0.044464f, 0.048584f, 0.053345f, 0.058838f, 0.064514f, 0.071045f, 0.078247f, 0.085571f, 0.093567f,
+ 0.101685f, 0.111023f, 0.477539f, 0.531738f, 0.542969f, 0.548340f, 0.552246f, 0.553711f, 0.000459f, 0.000939f, 0.001184f, 0.001600f,
+ 0.001761f, 0.002144f, 0.002258f, 0.002546f, 0.002708f, 0.002922f, 0.003157f, 0.003414f, 0.003588f, 0.003918f, 0.004154f, 0.004387f,
+ 0.004662f, 0.004993f, 0.005249f, 0.005566f, 0.005867f, 0.006252f, 0.006573f, 0.007061f, 0.007408f, 0.007858f, 0.008270f, 0.008713f,
+ 0.009361f, 0.009911f, 0.010513f, 0.011047f, 0.011841f, 0.012566f, 0.013252f, 0.014175f, 0.015182f, 0.016220f, 0.017258f, 0.018524f,
+ 0.019882f, 0.021454f, 0.023132f, 0.025146f, 0.027405f, 0.029877f, 0.032745f, 0.035919f, 0.039642f, 0.043823f, 0.048492f, 0.053619f,
+ 0.059235f, 0.065735f, 0.072693f, 0.080383f, 0.088867f, 0.097412f, 0.466309f, 0.520508f, 0.533691f, 0.539062f, 0.542480f, 0.543945f,
+ 0.000369f, 0.000915f, 0.001124f, 0.001297f, 0.001534f, 0.001741f, 0.001833f, 0.002111f, 0.002272f, 0.002369f, 0.002516f, 0.002766f,
+ 0.002920f, 0.003162f, 0.003317f, 0.003551f, 0.003723f, 0.003941f, 0.004211f, 0.004425f, 0.004757f, 0.004993f, 0.005306f, 0.005581f,
+ 0.005859f, 0.006203f, 0.006592f, 0.007015f, 0.007450f, 0.007828f, 0.008377f, 0.008797f, 0.009361f, 0.009895f, 0.010582f, 0.011322f,
+ 0.012016f, 0.012772f, 0.013687f, 0.014748f, 0.015778f, 0.016907f, 0.018326f, 0.019821f, 0.021622f, 0.023483f, 0.025742f, 0.028473f,
+ 0.031525f, 0.034943f, 0.038910f, 0.043457f, 0.048645f, 0.054749f, 0.061279f, 0.068420f, 0.076111f, 0.084778f, 0.453613f, 0.510742f,
+ 0.523926f, 0.529785f, 0.533203f, 0.536133f, 0.000186f, 0.000582f, 0.000925f, 0.001026f, 0.001228f, 0.001351f, 0.001470f, 0.001606f,
+ 0.001765f, 0.001908f, 0.001999f, 0.002104f, 0.002281f, 0.002476f, 0.002659f, 0.002766f, 0.002911f, 0.003040f, 0.003344f, 0.003475f,
+ 0.003683f, 0.003922f, 0.004185f, 0.004417f, 0.004673f, 0.004890f, 0.005123f, 0.005440f, 0.005817f, 0.006126f, 0.006481f, 0.006859f,
+ 0.007275f, 0.007740f, 0.008202f, 0.008728f, 0.009315f, 0.009972f, 0.010597f, 0.011391f, 0.012268f, 0.013252f, 0.014221f, 0.015388f,
+ 0.016724f, 0.018265f, 0.020004f, 0.022049f, 0.024445f, 0.027206f, 0.030762f, 0.034424f, 0.038971f, 0.044220f, 0.050262f, 0.056976f,
+ 0.064575f, 0.072083f, 0.441650f, 0.500488f, 0.514160f, 0.520020f, 0.524414f, 0.526855f, 0.000194f, 0.000467f, 0.000775f, 0.000911f,
+ 0.000994f, 0.001081f, 0.001221f, 0.001204f, 0.001368f, 0.001479f, 0.001582f, 0.001707f, 0.001801f, 0.001921f, 0.001993f, 0.002146f,
+ 0.002245f, 0.002398f, 0.002531f, 0.002674f, 0.002871f, 0.003033f, 0.003172f, 0.003374f, 0.003519f, 0.003742f, 0.003963f, 0.004158f,
+ 0.004448f, 0.004650f, 0.005032f, 0.005230f, 0.005550f, 0.005932f, 0.006241f, 0.006634f, 0.007088f, 0.007572f, 0.008110f, 0.008636f,
+ 0.009323f, 0.010071f, 0.010834f, 0.011757f, 0.012779f, 0.013863f, 0.015190f, 0.016769f, 0.018555f, 0.020706f, 0.023331f, 0.026352f,
+ 0.030182f, 0.034760f, 0.040039f, 0.046356f, 0.053406f, 0.060638f, 0.427979f, 0.489502f, 0.504883f, 0.511719f, 0.515137f, 0.518066f,
+ 0.000339f, 0.000388f, 0.000559f, 0.000617f, 0.000667f, 0.000795f, 0.000853f, 0.000938f, 0.000972f, 0.001079f, 0.001217f, 0.001274f,
+ 0.001369f, 0.001480f, 0.001536f, 0.001581f, 0.001711f, 0.001804f, 0.001900f, 0.002047f, 0.002129f, 0.002245f, 0.002394f, 0.002493f,
+ 0.002645f, 0.002773f, 0.002974f, 0.003124f, 0.003307f, 0.003559f, 0.003757f, 0.003893f, 0.004169f, 0.004353f, 0.004684f, 0.004963f,
+ 0.005272f, 0.005615f, 0.005981f, 0.006420f, 0.006878f, 0.007378f, 0.008080f, 0.008682f, 0.009438f, 0.010239f, 0.011299f, 0.012459f,
+ 0.013809f, 0.015305f, 0.017212f, 0.019501f, 0.022583f, 0.026245f, 0.030838f, 0.036255f, 0.042938f, 0.049988f, 0.416504f, 0.479492f,
+ 0.495361f, 0.501465f, 0.505859f, 0.508789f, 0.000148f, 0.000349f, 0.000414f, 0.000480f, 0.000554f, 0.000575f, 0.000675f, 0.000641f,
+ 0.000743f, 0.000809f, 0.000882f, 0.000919f, 0.000967f, 0.001019f, 0.001122f, 0.001156f, 0.001264f, 0.001322f, 0.001392f, 0.001431f,
+ 0.001529f, 0.001625f, 0.001735f, 0.001802f, 0.001912f, 0.002007f, 0.002131f, 0.002237f, 0.002338f, 0.002525f, 0.002638f, 0.002850f,
+ 0.002962f, 0.003130f, 0.003347f, 0.003536f, 0.003784f, 0.004063f, 0.004364f, 0.004623f, 0.004929f, 0.005314f, 0.005714f, 0.006191f,
+ 0.006760f, 0.007385f, 0.008080f, 0.008919f, 0.009933f, 0.011078f, 0.012390f, 0.014130f, 0.016251f, 0.019012f, 0.022720f, 0.027496f,
+ 0.033234f, 0.040192f, 0.403320f, 0.468994f, 0.485352f, 0.491943f, 0.497070f, 0.500000f, 0.000093f, 0.000191f, 0.000299f, 0.000284f,
+ 0.000367f, 0.000453f, 0.000420f, 0.000467f, 0.000519f, 0.000611f, 0.000607f, 0.000626f, 0.000647f, 0.000722f, 0.000741f, 0.000815f,
+ 0.000829f, 0.000910f, 0.000967f, 0.001023f, 0.001076f, 0.001138f, 0.001197f, 0.001260f, 0.001334f, 0.001393f, 0.001490f, 0.001562f,
+ 0.001633f, 0.001772f, 0.001831f, 0.001949f, 0.002056f, 0.002167f, 0.002312f, 0.002472f, 0.002607f, 0.002781f, 0.002972f, 0.003145f,
+ 0.003387f, 0.003647f, 0.003941f, 0.004253f, 0.004604f, 0.005051f, 0.005558f, 0.006165f, 0.006836f, 0.007660f, 0.008652f, 0.009796f,
+ 0.011284f, 0.013260f, 0.015945f, 0.019608f, 0.024734f, 0.031082f, 0.390625f, 0.459229f, 0.475586f, 0.482910f, 0.488037f, 0.490723f,
+ 0.000132f, 0.000208f, 0.000217f, 0.000221f, 0.000267f, 0.000272f, 0.000277f, 0.000320f, 0.000356f, 0.000372f, 0.000372f, 0.000446f,
+ 0.000436f, 0.000487f, 0.000514f, 0.000531f, 0.000587f, 0.000601f, 0.000629f, 0.000658f, 0.000707f, 0.000736f, 0.000784f, 0.000816f,
+ 0.000880f, 0.000909f, 0.000978f, 0.001035f, 0.001084f, 0.001135f, 0.001200f, 0.001278f, 0.001357f, 0.001429f, 0.001516f, 0.001588f,
+ 0.001724f, 0.001802f, 0.001949f, 0.002085f, 0.002230f, 0.002373f, 0.002554f, 0.002743f, 0.003000f, 0.003300f, 0.003611f, 0.003963f,
+ 0.004425f, 0.004967f, 0.005630f, 0.006424f, 0.007462f, 0.008812f, 0.010551f, 0.013184f, 0.017258f, 0.022980f, 0.377686f, 0.448242f,
+ 0.465820f, 0.474121f, 0.478760f, 0.481934f, 0.000041f, 0.000149f, 0.000126f, 0.000128f, 0.000158f, 0.000196f, 0.000174f, 0.000206f,
+ 0.000216f, 0.000223f, 0.000231f, 0.000244f, 0.000276f, 0.000291f, 0.000312f, 0.000326f, 0.000338f, 0.000374f, 0.000387f, 0.000423f,
+ 0.000430f, 0.000447f, 0.000471f, 0.000509f, 0.000538f, 0.000583f, 0.000591f, 0.000613f, 0.000659f, 0.000688f, 0.000743f, 0.000779f,
+ 0.000833f, 0.000865f, 0.000924f, 0.000966f, 0.001033f, 0.001106f, 0.001186f, 0.001245f, 0.001336f, 0.001453f, 0.001559f, 0.001685f,
+ 0.001807f, 0.001980f, 0.002207f, 0.002417f, 0.002689f, 0.003027f, 0.003418f, 0.003933f, 0.004604f, 0.005482f, 0.006641f, 0.008263f,
+ 0.011017f, 0.015778f, 0.364746f, 0.437256f, 0.456055f, 0.463623f, 0.469238f, 0.472656f, 0.000100f, 0.000089f, 0.000085f, 0.000081f,
+ 0.000101f, 0.000096f, 0.000116f, 0.000116f, 0.000119f, 0.000126f, 0.000141f, 0.000157f, 0.000149f, 0.000158f, 0.000179f, 0.000176f,
+ 0.000195f, 0.000206f, 0.000216f, 0.000222f, 0.000240f, 0.000246f, 0.000269f, 0.000279f, 0.000303f, 0.000320f, 0.000333f, 0.000345f,
+ 0.000365f, 0.000379f, 0.000409f, 0.000434f, 0.000453f, 0.000477f, 0.000511f, 0.000541f, 0.000569f, 0.000608f, 0.000656f, 0.000689f,
+ 0.000738f, 0.000795f, 0.000867f, 0.000918f, 0.001005f, 0.001087f, 0.001189f, 0.001312f, 0.001465f, 0.001656f, 0.001873f, 0.002171f,
+ 0.002546f, 0.003056f, 0.003767f, 0.004765f, 0.006390f, 0.009811f, 0.353516f, 0.426758f, 0.446045f, 0.455078f, 0.459717f, 0.464111f,
+ 0.000084f, 0.000059f, 0.000050f, 0.000049f, 0.000049f, 0.000047f, 0.000052f, 0.000058f, 0.000061f, 0.000075f, 0.000065f, 0.000066f,
+ 0.000080f, 0.000071f, 0.000076f, 0.000082f, 0.000092f, 0.000102f, 0.000100f, 0.000105f, 0.000110f, 0.000115f, 0.000121f, 0.000133f,
+ 0.000140f, 0.000146f, 0.000152f, 0.000164f, 0.000177f, 0.000185f, 0.000192f, 0.000202f, 0.000213f, 0.000224f, 0.000241f, 0.000252f,
+ 0.000268f, 0.000283f, 0.000310f, 0.000328f, 0.000348f, 0.000374f, 0.000406f, 0.000431f, 0.000470f, 0.000515f, 0.000560f, 0.000614f,
+ 0.000688f, 0.000771f, 0.000884f, 0.001019f, 0.001202f, 0.001466f, 0.001827f, 0.002369f, 0.003269f, 0.005184f, 0.341797f, 0.416016f,
+ 0.435791f, 0.445557f, 0.450928f, 0.455078f, 0.000062f, 0.000042f, 0.000035f, 0.000030f, 0.000028f, 0.000026f, 0.000024f, 0.000023f,
+ 0.000023f, 0.000023f, 0.000023f, 0.000030f, 0.000024f, 0.000024f, 0.000031f, 0.000034f, 0.000035f, 0.000037f, 0.000039f, 0.000040f,
+ 0.000043f, 0.000048f, 0.000050f, 0.000046f, 0.000051f, 0.000057f, 0.000059f, 0.000058f, 0.000063f, 0.000068f, 0.000070f, 0.000077f,
+ 0.000082f, 0.000082f, 0.000086f, 0.000093f, 0.000100f, 0.000106f, 0.000114f, 0.000120f, 0.000131f, 0.000136f, 0.000145f, 0.000161f,
+ 0.000171f, 0.000186f, 0.000204f, 0.000222f, 0.000251f, 0.000281f, 0.000318f, 0.000364f, 0.000430f, 0.000530f, 0.000672f, 0.000902f,
+ 0.001316f, 0.002153f, 0.329346f, 0.406006f, 0.426758f, 0.436035f, 0.441650f, 0.445801f, 0.000031f, 0.000020f, 0.000016f, 0.000014f,
+ 0.000014f, 0.000013f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000009f,
+ 0.000008f, 0.000008f, 0.000007f, 0.000007f, 0.000007f, 0.000008f, 0.000009f, 0.000010f, 0.000011f, 0.000012f, 0.000012f, 0.000014f,
+ 0.000014f, 0.000013f, 0.000015f, 0.000016f, 0.000018f, 0.000019f, 0.000019f, 0.000020f, 0.000023f, 0.000023f, 0.000025f, 0.000027f,
+ 0.000028f, 0.000031f, 0.000034f, 0.000034f, 0.000037f, 0.000041f, 0.000045f, 0.000049f, 0.000053f, 0.000059f, 0.000066f, 0.000079f,
+ 0.000093f, 0.000112f, 0.000144f, 0.000196f, 0.000307f, 0.000598f, 0.317383f, 0.394531f, 0.416504f, 0.425781f, 0.432129f, 0.436279f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000003f, 0.000003f, 0.000004f, 0.000004f, 0.000004f, 0.000007f, 0.000010f, 0.000026f, 0.305420f, 0.384277f,
+ 0.405762f, 0.416504f, 0.423340f, 0.427246f,
+ },
+ {
+ 0.009338f, 0.028412f, 0.047394f, 0.066895f, 0.086548f, 0.105774f, 0.125854f, 0.145142f, 0.165039f, 0.184570f, 0.204712f, 0.223389f,
+ 0.243164f, 0.261719f, 0.280762f, 0.299805f, 0.318848f, 0.338135f, 0.356445f, 0.374512f, 0.393066f, 0.412354f, 0.429932f, 0.447510f,
+ 0.465576f, 0.483887f, 0.501465f, 0.518555f, 0.536133f, 0.553711f, 0.570312f, 0.587402f, 0.604492f, 0.621094f, 0.637695f, 0.653809f,
+ 0.670898f, 0.687012f, 0.702637f, 0.719238f, 0.734863f, 0.750488f, 0.765137f, 0.780762f, 0.795898f, 0.811523f, 0.825684f, 0.840820f,
+ 0.855469f, 0.870605f, 0.884277f, 0.899414f, 0.913086f, 0.926758f, 0.940918f, 0.955078f, 0.967773f, 0.981934f, 0.966797f, 0.923828f,
+ 0.894531f, 0.870605f, 0.850586f, 0.832520f, 0.008652f, 0.026825f, 0.045380f, 0.063965f, 0.082703f, 0.101807f, 0.120544f, 0.139282f,
+ 0.158569f, 0.177246f, 0.196167f, 0.214722f, 0.233521f, 0.252197f, 0.270508f, 0.289062f, 0.307861f, 0.325928f, 0.343994f, 0.361328f,
+ 0.380615f, 0.397705f, 0.415771f, 0.433594f, 0.450928f, 0.469238f, 0.485596f, 0.502930f, 0.520020f, 0.537598f, 0.553223f, 0.570801f,
+ 0.586914f, 0.603516f, 0.620117f, 0.636719f, 0.652832f, 0.668945f, 0.683594f, 0.700684f, 0.716309f, 0.731934f, 0.746582f, 0.762695f,
+ 0.777344f, 0.792480f, 0.807617f, 0.821777f, 0.836914f, 0.850586f, 0.865723f, 0.880371f, 0.894043f, 0.908691f, 0.921875f, 0.937012f,
+ 0.950195f, 0.963867f, 0.958496f, 0.917969f, 0.889648f, 0.867188f, 0.847656f, 0.830566f, 0.008293f, 0.025620f, 0.042999f, 0.061035f,
+ 0.079163f, 0.097656f, 0.115112f, 0.132812f, 0.151367f, 0.170532f, 0.188599f, 0.206787f, 0.223999f, 0.242920f, 0.259766f, 0.278809f,
+ 0.296143f, 0.313232f, 0.331055f, 0.349609f, 0.367432f, 0.385010f, 0.401611f, 0.418945f, 0.435791f, 0.453369f, 0.469727f, 0.487061f,
+ 0.503906f, 0.520508f, 0.537598f, 0.553223f, 0.569824f, 0.586426f, 0.603027f, 0.619141f, 0.634277f, 0.650879f, 0.666504f, 0.682129f,
+ 0.697754f, 0.713379f, 0.729004f, 0.743164f, 0.758301f, 0.773926f, 0.789062f, 0.803711f, 0.818359f, 0.833008f, 0.847168f, 0.862305f,
+ 0.875488f, 0.890137f, 0.903809f, 0.917480f, 0.931152f, 0.945801f, 0.950195f, 0.911133f, 0.884766f, 0.862793f, 0.844238f, 0.828125f,
+ 0.008148f, 0.024506f, 0.041016f, 0.058289f, 0.075256f, 0.092712f, 0.109802f, 0.127319f, 0.145020f, 0.162964f, 0.180298f, 0.198120f,
+ 0.215454f, 0.232300f, 0.250244f, 0.267822f, 0.285400f, 0.302734f, 0.318848f, 0.335693f, 0.354004f, 0.371582f, 0.388672f, 0.405029f,
+ 0.421143f, 0.438965f, 0.455078f, 0.472168f, 0.487549f, 0.503906f, 0.521484f, 0.537598f, 0.551758f, 0.568359f, 0.584961f, 0.601562f,
+ 0.616211f, 0.633301f, 0.648926f, 0.664062f, 0.679199f, 0.694824f, 0.709473f, 0.725098f, 0.740234f, 0.755371f, 0.770020f, 0.785156f,
+ 0.799805f, 0.813965f, 0.828125f, 0.842773f, 0.856934f, 0.871582f, 0.884766f, 0.898926f, 0.912598f, 0.926270f, 0.941895f, 0.905273f,
+ 0.879883f, 0.858887f, 0.840332f, 0.824707f, 0.007523f, 0.023010f, 0.039246f, 0.055542f, 0.072021f, 0.088257f, 0.105347f, 0.122070f,
+ 0.138306f, 0.155273f, 0.172852f, 0.189575f, 0.206421f, 0.223145f, 0.240112f, 0.256592f, 0.274170f, 0.291260f, 0.307617f, 0.323730f,
+ 0.340576f, 0.358154f, 0.374023f, 0.390137f, 0.406738f, 0.422852f, 0.440430f, 0.456543f, 0.472656f, 0.489014f, 0.504395f, 0.520996f,
+ 0.537109f, 0.552734f, 0.568848f, 0.584473f, 0.599121f, 0.615234f, 0.630859f, 0.645020f, 0.660645f, 0.677246f, 0.690918f, 0.706055f,
+ 0.721680f, 0.736328f, 0.750977f, 0.766113f, 0.780273f, 0.794922f, 0.809570f, 0.823730f, 0.837891f, 0.852539f, 0.866211f, 0.880371f,
+ 0.894531f, 0.908691f, 0.933105f, 0.898438f, 0.874023f, 0.853516f, 0.836426f, 0.821289f, 0.007339f, 0.021912f, 0.037170f, 0.052948f,
+ 0.068665f, 0.084412f, 0.100281f, 0.116333f, 0.133057f, 0.149048f, 0.164795f, 0.181274f, 0.198242f, 0.214233f, 0.230835f, 0.247314f,
+ 0.262939f, 0.279053f, 0.295898f, 0.312500f, 0.328613f, 0.344971f, 0.360107f, 0.376953f, 0.392578f, 0.408691f, 0.425293f, 0.441406f,
+ 0.456787f, 0.472656f, 0.488525f, 0.504883f, 0.520020f, 0.535156f, 0.550781f, 0.567383f, 0.582520f, 0.597656f, 0.612793f, 0.628418f,
+ 0.642578f, 0.657715f, 0.673340f, 0.688477f, 0.702637f, 0.718750f, 0.731445f, 0.748047f, 0.762207f, 0.775879f, 0.791016f, 0.804199f,
+ 0.818848f, 0.833008f, 0.847656f, 0.861328f, 0.875000f, 0.890625f, 0.924316f, 0.891602f, 0.868164f, 0.849121f, 0.832520f, 0.817871f,
+ 0.006817f, 0.021133f, 0.035675f, 0.050018f, 0.065186f, 0.080505f, 0.096069f, 0.111389f, 0.126831f, 0.142456f, 0.158203f, 0.174194f,
+ 0.189819f, 0.205444f, 0.220703f, 0.237183f, 0.253174f, 0.268555f, 0.284668f, 0.300049f, 0.316406f, 0.332275f, 0.347656f, 0.363281f,
+ 0.379395f, 0.394775f, 0.409668f, 0.426270f, 0.442139f, 0.457275f, 0.472656f, 0.488037f, 0.503906f, 0.518555f, 0.534668f, 0.548828f,
+ 0.564941f, 0.579590f, 0.595215f, 0.610352f, 0.625000f, 0.640137f, 0.654785f, 0.669434f, 0.685059f, 0.699707f, 0.713379f, 0.728027f,
+ 0.742676f, 0.758301f, 0.770996f, 0.786621f, 0.799316f, 0.813965f, 0.828613f, 0.842285f, 0.856445f, 0.871094f, 0.915527f, 0.884766f,
+ 0.862305f, 0.843750f, 0.827637f, 0.813965f, 0.006611f, 0.020111f, 0.033752f, 0.047974f, 0.062378f, 0.076843f, 0.091431f, 0.106262f,
+ 0.120911f, 0.136230f, 0.151123f, 0.166382f, 0.181396f, 0.196899f, 0.211670f, 0.227295f, 0.242554f, 0.257812f, 0.272705f, 0.288086f,
+ 0.304199f, 0.318848f, 0.334473f, 0.349609f, 0.365967f, 0.379883f, 0.395996f, 0.410889f, 0.426270f, 0.441895f, 0.457764f, 0.472412f,
+ 0.487061f, 0.502930f, 0.517090f, 0.532227f, 0.547363f, 0.563477f, 0.577637f, 0.592285f, 0.606934f, 0.621582f, 0.636230f, 0.651367f,
+ 0.665039f, 0.679688f, 0.694336f, 0.709473f, 0.724121f, 0.738770f, 0.752930f, 0.767578f, 0.780762f, 0.795410f, 0.809082f, 0.823242f,
+ 0.837891f, 0.852539f, 0.906250f, 0.877441f, 0.855957f, 0.838379f, 0.823242f, 0.809570f, 0.006153f, 0.019150f, 0.031952f, 0.045624f,
+ 0.059326f, 0.073303f, 0.087158f, 0.101562f, 0.115540f, 0.129395f, 0.144653f, 0.159180f, 0.173584f, 0.187866f, 0.203613f, 0.217651f,
+ 0.232300f, 0.247559f, 0.262207f, 0.277344f, 0.292969f, 0.307617f, 0.322021f, 0.336914f, 0.352051f, 0.367188f, 0.381592f, 0.396729f,
+ 0.411377f, 0.427002f, 0.440918f, 0.456787f, 0.471436f, 0.486572f, 0.500977f, 0.514648f, 0.530273f, 0.545410f, 0.560059f, 0.574219f,
+ 0.589355f, 0.604004f, 0.618164f, 0.632324f, 0.647461f, 0.661133f, 0.676270f, 0.691406f, 0.705078f, 0.719727f, 0.733887f, 0.748047f,
+ 0.763184f, 0.777344f, 0.791016f, 0.805176f, 0.819336f, 0.833496f, 0.896973f, 0.870117f, 0.849609f, 0.833008f, 0.818359f, 0.805176f,
+ 0.005947f, 0.018311f, 0.030731f, 0.043243f, 0.056732f, 0.069580f, 0.083435f, 0.096558f, 0.110474f, 0.123962f, 0.137695f, 0.152100f,
+ 0.166016f, 0.180054f, 0.194092f, 0.208862f, 0.222656f, 0.236816f, 0.251465f, 0.266113f, 0.281250f, 0.294922f, 0.309814f, 0.324219f,
+ 0.338623f, 0.352783f, 0.368164f, 0.382568f, 0.397461f, 0.411377f, 0.426025f, 0.441162f, 0.455078f, 0.469971f, 0.484131f, 0.499268f,
+ 0.513672f, 0.528320f, 0.542969f, 0.557129f, 0.571289f, 0.585449f, 0.599609f, 0.614258f, 0.628418f, 0.643066f, 0.657227f, 0.671875f,
+ 0.686523f, 0.700195f, 0.714355f, 0.729004f, 0.743164f, 0.756836f, 0.770996f, 0.785645f, 0.800293f, 0.814453f, 0.888184f, 0.862305f,
+ 0.843262f, 0.827148f, 0.813477f, 0.800781f, 0.005646f, 0.017136f, 0.029388f, 0.041534f, 0.053802f, 0.066162f, 0.078979f, 0.092285f,
+ 0.104980f, 0.118408f, 0.130981f, 0.144897f, 0.158203f, 0.172363f, 0.185547f, 0.199951f, 0.213501f, 0.226440f, 0.240356f, 0.254883f,
+ 0.269287f, 0.283691f, 0.297607f, 0.311279f, 0.325439f, 0.339600f, 0.353760f, 0.368408f, 0.382812f, 0.396973f, 0.410645f, 0.425049f,
+ 0.439697f, 0.454102f, 0.468262f, 0.482178f, 0.496094f, 0.510742f, 0.524902f, 0.539551f, 0.554199f, 0.568359f, 0.582031f, 0.596191f,
+ 0.610352f, 0.624023f, 0.639160f, 0.652832f, 0.667969f, 0.681152f, 0.696289f, 0.709961f, 0.723633f, 0.738770f, 0.752441f, 0.765625f,
+ 0.780273f, 0.794922f, 0.878418f, 0.855469f, 0.836914f, 0.821289f, 0.808105f, 0.796387f, 0.005478f, 0.016174f, 0.027740f, 0.038849f,
+ 0.051270f, 0.063293f, 0.075317f, 0.087402f, 0.099854f, 0.112793f, 0.125366f, 0.138184f, 0.151001f, 0.164307f, 0.177734f, 0.190918f,
+ 0.204102f, 0.217529f, 0.231079f, 0.244141f, 0.257324f, 0.271240f, 0.284668f, 0.299072f, 0.312744f, 0.326660f, 0.339600f, 0.354004f,
+ 0.368408f, 0.382324f, 0.395264f, 0.410156f, 0.423096f, 0.437500f, 0.452148f, 0.465332f, 0.480469f, 0.493408f, 0.507812f, 0.521484f,
+ 0.535645f, 0.549316f, 0.563477f, 0.578125f, 0.592285f, 0.605957f, 0.620605f, 0.634766f, 0.647949f, 0.662109f, 0.676758f, 0.691406f,
+ 0.705078f, 0.718750f, 0.732910f, 0.747559f, 0.762207f, 0.777344f, 0.869141f, 0.847656f, 0.830078f, 0.815430f, 0.802734f, 0.791504f,
+ 0.005005f, 0.015762f, 0.026657f, 0.037384f, 0.048218f, 0.059998f, 0.071594f, 0.083618f, 0.095215f, 0.107666f, 0.119141f, 0.131958f,
+ 0.144043f, 0.156128f, 0.169800f, 0.182129f, 0.194824f, 0.207031f, 0.219849f, 0.233032f, 0.247559f, 0.260010f, 0.272949f, 0.286133f,
+ 0.300293f, 0.313477f, 0.326172f, 0.339844f, 0.353516f, 0.367188f, 0.381592f, 0.394531f, 0.407959f, 0.422363f, 0.436279f, 0.449463f,
+ 0.462891f, 0.477539f, 0.490723f, 0.504395f, 0.518066f, 0.532227f, 0.545898f, 0.560059f, 0.574219f, 0.586914f, 0.602051f, 0.616211f,
+ 0.629395f, 0.644531f, 0.657227f, 0.671875f, 0.685547f, 0.699707f, 0.713867f, 0.728516f, 0.742676f, 0.756836f, 0.859375f, 0.840332f,
+ 0.823730f, 0.809082f, 0.797363f, 0.786621f, 0.004894f, 0.014786f, 0.025269f, 0.035614f, 0.045990f, 0.057129f, 0.068420f, 0.079224f,
+ 0.090698f, 0.102112f, 0.113708f, 0.125610f, 0.137817f, 0.149536f, 0.161377f, 0.174316f, 0.185791f, 0.198486f, 0.211670f, 0.223389f,
+ 0.236816f, 0.249512f, 0.261230f, 0.274414f, 0.287598f, 0.300537f, 0.313232f, 0.326904f, 0.340576f, 0.353027f, 0.366211f, 0.379883f,
+ 0.393066f, 0.406006f, 0.419678f, 0.433350f, 0.446289f, 0.460205f, 0.473633f, 0.487305f, 0.500977f, 0.515137f, 0.528320f, 0.542480f,
+ 0.554688f, 0.569824f, 0.583008f, 0.597656f, 0.610840f, 0.625488f, 0.638672f, 0.652832f, 0.666504f, 0.681152f, 0.694824f, 0.708984f,
+ 0.723145f, 0.737793f, 0.850098f, 0.833008f, 0.817383f, 0.802734f, 0.791992f, 0.780762f, 0.004536f, 0.014160f, 0.023972f, 0.033630f,
+ 0.043823f, 0.053955f, 0.064697f, 0.075195f, 0.086365f, 0.096802f, 0.108276f, 0.119751f, 0.130493f, 0.142212f, 0.153687f, 0.165405f,
+ 0.177246f, 0.189331f, 0.201538f, 0.213501f, 0.225464f, 0.237915f, 0.250244f, 0.262939f, 0.274902f, 0.288086f, 0.300781f, 0.312988f,
+ 0.326172f, 0.339600f, 0.352051f, 0.365479f, 0.377930f, 0.390625f, 0.403564f, 0.417480f, 0.430420f, 0.444092f, 0.457520f, 0.470215f,
+ 0.483643f, 0.497559f, 0.510742f, 0.524414f, 0.537598f, 0.551270f, 0.564941f, 0.579102f, 0.592285f, 0.605957f, 0.619629f, 0.633789f,
+ 0.647949f, 0.661621f, 0.675293f, 0.689453f, 0.704102f, 0.718262f, 0.840332f, 0.825195f, 0.809570f, 0.797363f, 0.786133f, 0.776367f,
+ 0.004433f, 0.013138f, 0.022720f, 0.032013f, 0.041199f, 0.051147f, 0.061462f, 0.071716f, 0.082336f, 0.091919f, 0.102722f, 0.113586f,
+ 0.124390f, 0.135010f, 0.145996f, 0.157837f, 0.168823f, 0.180054f, 0.192383f, 0.203491f, 0.215332f, 0.227417f, 0.239502f, 0.251221f,
+ 0.263672f, 0.275635f, 0.287842f, 0.300537f, 0.312500f, 0.324707f, 0.338135f, 0.350342f, 0.363037f, 0.375977f, 0.388672f, 0.401611f,
+ 0.413818f, 0.427246f, 0.440186f, 0.453613f, 0.466064f, 0.479736f, 0.492920f, 0.506836f, 0.519531f, 0.533203f, 0.546875f, 0.560059f,
+ 0.573242f, 0.587402f, 0.600098f, 0.614746f, 0.628418f, 0.642578f, 0.657227f, 0.670898f, 0.685059f, 0.699707f, 0.830566f, 0.816406f,
+ 0.802734f, 0.791016f, 0.780273f, 0.770996f, 0.004372f, 0.012619f, 0.021393f, 0.030350f, 0.039276f, 0.048523f, 0.058289f, 0.067505f,
+ 0.077393f, 0.087585f, 0.097290f, 0.107727f, 0.118225f, 0.128296f, 0.138550f, 0.149414f, 0.160278f, 0.171631f, 0.182739f, 0.193359f,
+ 0.205200f, 0.216187f, 0.228027f, 0.240234f, 0.251465f, 0.263428f, 0.275146f, 0.287598f, 0.298828f, 0.311523f, 0.323242f, 0.336182f,
+ 0.348633f, 0.360107f, 0.372803f, 0.385986f, 0.398682f, 0.411621f, 0.424072f, 0.436523f, 0.449951f, 0.462891f, 0.475098f, 0.488525f,
+ 0.501953f, 0.514648f, 0.527344f, 0.541992f, 0.555176f, 0.569336f, 0.582031f, 0.596191f, 0.609863f, 0.623047f, 0.637695f, 0.651855f,
+ 0.665527f, 0.679688f, 0.821289f, 0.808105f, 0.795410f, 0.784180f, 0.774902f, 0.765137f, 0.003937f, 0.012169f, 0.020477f, 0.028641f,
+ 0.037781f, 0.046448f, 0.055481f, 0.064209f, 0.073181f, 0.082458f, 0.092651f, 0.101990f, 0.111572f, 0.121948f, 0.132202f, 0.142212f,
+ 0.151978f, 0.162720f, 0.173340f, 0.184326f, 0.195312f, 0.206055f, 0.217163f, 0.228516f, 0.239990f, 0.250977f, 0.262695f, 0.274658f,
+ 0.285889f, 0.297363f, 0.308838f, 0.321045f, 0.333496f, 0.345459f, 0.357422f, 0.370117f, 0.382324f, 0.395020f, 0.407227f, 0.419922f,
+ 0.432617f, 0.444336f, 0.458008f, 0.470703f, 0.483398f, 0.497559f, 0.510254f, 0.522949f, 0.536133f, 0.550293f, 0.562988f, 0.577637f,
+ 0.590820f, 0.603516f, 0.618164f, 0.632324f, 0.645508f, 0.660645f, 0.811035f, 0.800293f, 0.788086f, 0.777832f, 0.768555f, 0.760254f,
+ 0.003868f, 0.011368f, 0.019257f, 0.027512f, 0.035431f, 0.043274f, 0.051880f, 0.060852f, 0.069214f, 0.078003f, 0.087524f, 0.096924f,
+ 0.105896f, 0.115112f, 0.124817f, 0.134766f, 0.144409f, 0.154663f, 0.164673f, 0.175415f, 0.184814f, 0.196289f, 0.206299f, 0.216797f,
+ 0.228394f, 0.239380f, 0.250244f, 0.260986f, 0.273193f, 0.284424f, 0.295410f, 0.307373f, 0.319092f, 0.331299f, 0.342285f, 0.354248f,
+ 0.366455f, 0.378662f, 0.390869f, 0.403809f, 0.415771f, 0.427734f, 0.440430f, 0.453369f, 0.466309f, 0.479736f, 0.492188f, 0.504883f,
+ 0.518066f, 0.531250f, 0.544922f, 0.558105f, 0.571777f, 0.584473f, 0.598633f, 0.612305f, 0.626465f, 0.641602f, 0.801758f, 0.792480f,
+ 0.781738f, 0.770508f, 0.761230f, 0.753906f, 0.003616f, 0.010872f, 0.018387f, 0.026077f, 0.033875f, 0.041351f, 0.049591f, 0.057434f,
+ 0.065674f, 0.073669f, 0.082153f, 0.091064f, 0.100098f, 0.109009f, 0.117981f, 0.127563f, 0.137207f, 0.146362f, 0.156494f, 0.165894f,
+ 0.176025f, 0.186157f, 0.196655f, 0.206421f, 0.216919f, 0.227539f, 0.237915f, 0.249268f, 0.260254f, 0.270752f, 0.282471f, 0.293945f,
+ 0.305176f, 0.316406f, 0.328125f, 0.338867f, 0.350342f, 0.361816f, 0.375244f, 0.387207f, 0.398926f, 0.411133f, 0.423584f, 0.436523f,
+ 0.448730f, 0.461182f, 0.474121f, 0.485840f, 0.499756f, 0.513672f, 0.525391f, 0.539062f, 0.552734f, 0.565918f, 0.580566f, 0.593750f,
+ 0.608398f, 0.621094f, 0.790527f, 0.783691f, 0.773926f, 0.764160f, 0.755859f, 0.747559f, 0.003450f, 0.010429f, 0.017487f, 0.024445f,
+ 0.031860f, 0.039581f, 0.046631f, 0.054718f, 0.061951f, 0.070251f, 0.078003f, 0.086121f, 0.094910f, 0.102905f, 0.111572f, 0.120300f,
+ 0.129761f, 0.138428f, 0.147217f, 0.156982f, 0.166992f, 0.176147f, 0.186157f, 0.196045f, 0.206299f, 0.216187f, 0.226318f, 0.236938f,
+ 0.247437f, 0.258301f, 0.268311f, 0.279785f, 0.290527f, 0.301758f, 0.312744f, 0.324219f, 0.335449f, 0.346680f, 0.359131f, 0.370605f,
+ 0.382812f, 0.394531f, 0.406982f, 0.419189f, 0.430908f, 0.443604f, 0.456055f, 0.468506f, 0.481445f, 0.494873f, 0.506836f, 0.520996f,
+ 0.534180f, 0.547363f, 0.561035f, 0.573730f, 0.588379f, 0.601074f, 0.780762f, 0.775879f, 0.766602f, 0.757324f, 0.748535f, 0.741699f,
+ 0.003281f, 0.009811f, 0.016174f, 0.023438f, 0.030060f, 0.037109f, 0.044464f, 0.051239f, 0.058441f, 0.066345f, 0.073792f, 0.081238f,
+ 0.089539f, 0.097229f, 0.105286f, 0.113647f, 0.122498f, 0.130615f, 0.139526f, 0.148438f, 0.157837f, 0.166626f, 0.176636f, 0.185547f,
+ 0.195312f, 0.204956f, 0.215088f, 0.224976f, 0.234863f, 0.245239f, 0.255859f, 0.266113f, 0.276367f, 0.287354f, 0.298096f, 0.309326f,
+ 0.320801f, 0.331787f, 0.343018f, 0.355225f, 0.366211f, 0.378418f, 0.389893f, 0.401611f, 0.413574f, 0.425781f, 0.438721f, 0.451416f,
+ 0.463135f, 0.476074f, 0.489014f, 0.501465f, 0.514648f, 0.528809f, 0.541992f, 0.554688f, 0.568848f, 0.582520f, 0.770508f, 0.767090f,
+ 0.758789f, 0.750488f, 0.743164f, 0.735352f, 0.002901f, 0.009422f, 0.015488f, 0.021729f, 0.028290f, 0.035278f, 0.041321f, 0.048523f,
+ 0.055420f, 0.062195f, 0.069336f, 0.076477f, 0.084412f, 0.091858f, 0.099609f, 0.107361f, 0.115112f, 0.123535f, 0.131592f, 0.140137f,
+ 0.148438f, 0.157715f, 0.166382f, 0.174927f, 0.184692f, 0.193970f, 0.203369f, 0.212646f, 0.222656f, 0.232910f, 0.242920f, 0.252197f,
+ 0.263184f, 0.273438f, 0.284180f, 0.294922f, 0.305664f, 0.316895f, 0.327881f, 0.338867f, 0.349854f, 0.361328f, 0.373291f, 0.385254f,
+ 0.397461f, 0.408691f, 0.420898f, 0.433350f, 0.445801f, 0.458252f, 0.470703f, 0.483154f, 0.496826f, 0.510254f, 0.522461f, 0.535645f,
+ 0.549805f, 0.562988f, 0.760742f, 0.758789f, 0.750488f, 0.743652f, 0.736328f, 0.729492f, 0.002861f, 0.008606f, 0.014488f, 0.021057f,
+ 0.026810f, 0.032898f, 0.038879f, 0.045532f, 0.051666f, 0.058319f, 0.065125f, 0.072449f, 0.079224f, 0.086426f, 0.093689f, 0.100830f,
+ 0.108276f, 0.116089f, 0.123962f, 0.131958f, 0.140625f, 0.148560f, 0.156494f, 0.164795f, 0.174194f, 0.183228f, 0.192017f, 0.201294f,
+ 0.210815f, 0.220093f, 0.229858f, 0.239746f, 0.249390f, 0.260010f, 0.270508f, 0.280518f, 0.290771f, 0.301758f, 0.312744f, 0.323486f,
+ 0.334473f, 0.345215f, 0.356934f, 0.368408f, 0.379883f, 0.391846f, 0.403564f, 0.416016f, 0.427490f, 0.439453f, 0.452881f, 0.465332f,
+ 0.478271f, 0.490234f, 0.503906f, 0.517090f, 0.529785f, 0.543945f, 0.750000f, 0.750000f, 0.743164f, 0.736328f, 0.729492f, 0.723145f,
+ 0.002977f, 0.008492f, 0.013931f, 0.019745f, 0.024948f, 0.030991f, 0.036804f, 0.042755f, 0.048889f, 0.055267f, 0.061737f, 0.067932f,
+ 0.074829f, 0.081116f, 0.087646f, 0.095215f, 0.102356f, 0.109436f, 0.116760f, 0.124023f, 0.131714f, 0.139648f, 0.147461f, 0.155762f,
+ 0.164185f, 0.172485f, 0.181152f, 0.189697f, 0.198730f, 0.208130f, 0.217285f, 0.226685f, 0.236572f, 0.245850f, 0.255859f, 0.265869f,
+ 0.276367f, 0.286377f, 0.297607f, 0.307861f, 0.318359f, 0.329102f, 0.340576f, 0.351807f, 0.363281f, 0.374023f, 0.386230f, 0.397949f,
+ 0.409668f, 0.422119f, 0.434082f, 0.446777f, 0.459229f, 0.471924f, 0.484863f, 0.497803f, 0.511230f, 0.525391f, 0.739746f, 0.741211f,
+ 0.735352f, 0.729004f, 0.722656f, 0.717285f, 0.002441f, 0.007896f, 0.013443f, 0.018402f, 0.023911f, 0.029343f, 0.034454f, 0.040375f,
+ 0.045868f, 0.051453f, 0.057800f, 0.063721f, 0.070068f, 0.075928f, 0.082520f, 0.089233f, 0.095703f, 0.102478f, 0.109314f, 0.116638f,
+ 0.123596f, 0.131348f, 0.138550f, 0.145996f, 0.153809f, 0.162109f, 0.170044f, 0.179199f, 0.187866f, 0.196045f, 0.205078f, 0.213745f,
+ 0.223389f, 0.233032f, 0.242554f, 0.252197f, 0.261963f, 0.271973f, 0.281982f, 0.292236f, 0.303223f, 0.312988f, 0.324463f, 0.335693f,
+ 0.346191f, 0.357910f, 0.368652f, 0.380371f, 0.391846f, 0.404541f, 0.415527f, 0.428467f, 0.440674f, 0.453369f, 0.466553f, 0.479248f,
+ 0.491455f, 0.505371f, 0.729492f, 0.732422f, 0.727539f, 0.721191f, 0.716309f, 0.709961f, 0.002457f, 0.007553f, 0.012489f, 0.017548f,
+ 0.022217f, 0.027405f, 0.032471f, 0.037689f, 0.043060f, 0.048553f, 0.054230f, 0.059631f, 0.065369f, 0.071533f, 0.077393f, 0.083069f,
+ 0.089417f, 0.096069f, 0.102356f, 0.108398f, 0.115417f, 0.122925f, 0.130127f, 0.137451f, 0.144531f, 0.152100f, 0.160156f, 0.168091f,
+ 0.176514f, 0.184570f, 0.192871f, 0.201660f, 0.210571f, 0.219238f, 0.229126f, 0.238281f, 0.248413f, 0.257812f, 0.267578f, 0.277588f,
+ 0.287354f, 0.298096f, 0.308594f, 0.319336f, 0.329590f, 0.340820f, 0.351318f, 0.363770f, 0.375732f, 0.386963f, 0.397949f, 0.409912f,
+ 0.422363f, 0.434326f, 0.446533f, 0.459473f, 0.473145f, 0.486084f, 0.718750f, 0.723633f, 0.719727f, 0.713867f, 0.708984f, 0.703613f,
+ 0.002436f, 0.006939f, 0.011612f, 0.016113f, 0.021072f, 0.025497f, 0.030640f, 0.035339f, 0.040222f, 0.045441f, 0.050690f, 0.055725f,
+ 0.060669f, 0.066589f, 0.072144f, 0.077881f, 0.083740f, 0.089294f, 0.095215f, 0.101501f, 0.108032f, 0.114868f, 0.121643f, 0.128052f,
+ 0.135010f, 0.142334f, 0.150024f, 0.157349f, 0.164917f, 0.173340f, 0.181274f, 0.189697f, 0.198120f, 0.206909f, 0.215698f, 0.224365f,
+ 0.234497f, 0.243652f, 0.252930f, 0.262695f, 0.272461f, 0.282471f, 0.292480f, 0.302979f, 0.313721f, 0.324463f, 0.335205f, 0.346436f,
+ 0.357666f, 0.369141f, 0.380859f, 0.391602f, 0.404541f, 0.416016f, 0.428467f, 0.440918f, 0.454102f, 0.466553f, 0.708496f, 0.715820f,
+ 0.711426f, 0.706055f, 0.701660f, 0.696777f, 0.002188f, 0.006599f, 0.011032f, 0.015068f, 0.019897f, 0.024048f, 0.028656f, 0.033264f,
+ 0.037720f, 0.042236f, 0.047028f, 0.051941f, 0.056824f, 0.062012f, 0.067444f, 0.072449f, 0.077942f, 0.083374f, 0.088867f, 0.094727f,
+ 0.100769f, 0.106750f, 0.112732f, 0.119263f, 0.126099f, 0.133179f, 0.139648f, 0.146729f, 0.154175f, 0.161987f, 0.170044f, 0.177612f,
+ 0.185791f, 0.194214f, 0.203125f, 0.211670f, 0.220581f, 0.229370f, 0.238770f, 0.248047f, 0.257812f, 0.267822f, 0.277344f, 0.287109f,
+ 0.297363f, 0.307861f, 0.318848f, 0.329590f, 0.341064f, 0.351562f, 0.363037f, 0.374512f, 0.385498f, 0.397461f, 0.409668f, 0.422363f,
+ 0.434326f, 0.447021f, 0.697266f, 0.706543f, 0.703125f, 0.698730f, 0.694336f, 0.689941f, 0.002024f, 0.006165f, 0.010399f, 0.014481f,
+ 0.018555f, 0.022797f, 0.026627f, 0.030869f, 0.035187f, 0.039459f, 0.043732f, 0.047943f, 0.052917f, 0.057434f, 0.062622f, 0.067261f,
+ 0.071838f, 0.077454f, 0.082581f, 0.087891f, 0.093628f, 0.099182f, 0.105469f, 0.111206f, 0.117126f, 0.123779f, 0.130371f, 0.137085f,
+ 0.143921f, 0.151001f, 0.158691f, 0.166016f, 0.173950f, 0.181641f, 0.190063f, 0.198120f, 0.206909f, 0.215698f, 0.224976f, 0.233398f,
+ 0.242798f, 0.252197f, 0.262207f, 0.271973f, 0.281738f, 0.291992f, 0.302734f, 0.313477f, 0.323242f, 0.334229f, 0.345459f, 0.355957f,
+ 0.368652f, 0.380615f, 0.391602f, 0.403809f, 0.415771f, 0.428467f, 0.686523f, 0.696777f, 0.695312f, 0.691895f, 0.687500f, 0.683105f,
+ 0.001931f, 0.005970f, 0.009651f, 0.013557f, 0.017136f, 0.021088f, 0.024902f, 0.028748f, 0.032623f, 0.036743f, 0.040833f, 0.044983f,
+ 0.049591f, 0.053467f, 0.057800f, 0.062500f, 0.066833f, 0.071533f, 0.076538f, 0.081238f, 0.086670f, 0.092224f, 0.097290f, 0.103088f,
+ 0.108887f, 0.114990f, 0.120972f, 0.127197f, 0.134277f, 0.140503f, 0.147705f, 0.154663f, 0.162231f, 0.169922f, 0.177612f, 0.185303f,
+ 0.193604f, 0.201904f, 0.210815f, 0.219238f, 0.228516f, 0.237427f, 0.247070f, 0.256592f, 0.265869f, 0.275879f, 0.285645f, 0.295898f,
+ 0.306396f, 0.317139f, 0.328369f, 0.338623f, 0.350342f, 0.362305f, 0.374023f, 0.385010f, 0.397461f, 0.410156f, 0.675781f, 0.687988f,
+ 0.687012f, 0.683594f, 0.680664f, 0.676270f, 0.001725f, 0.005436f, 0.009171f, 0.012589f, 0.016190f, 0.019485f, 0.023132f, 0.026978f,
+ 0.030899f, 0.034180f, 0.037659f, 0.041565f, 0.045074f, 0.049438f, 0.053345f, 0.057739f, 0.061768f, 0.065918f, 0.070679f, 0.075073f,
+ 0.080078f, 0.084656f, 0.089966f, 0.095215f, 0.100464f, 0.106445f, 0.112000f, 0.117615f, 0.124207f, 0.130737f, 0.136719f, 0.144043f,
+ 0.151123f, 0.158081f, 0.165405f, 0.173096f, 0.181152f, 0.189087f, 0.197510f, 0.205688f, 0.214600f, 0.223145f, 0.232178f, 0.241699f,
+ 0.250732f, 0.260254f, 0.270264f, 0.279785f, 0.289795f, 0.300293f, 0.310791f, 0.322510f, 0.333496f, 0.344238f, 0.355713f, 0.367188f,
+ 0.379395f, 0.392090f, 0.664551f, 0.678711f, 0.678223f, 0.675781f, 0.672852f, 0.669922f, 0.001741f, 0.005077f, 0.008522f, 0.011810f,
+ 0.014946f, 0.018524f, 0.021332f, 0.024872f, 0.028519f, 0.031799f, 0.034973f, 0.038727f, 0.041992f, 0.045654f, 0.049072f, 0.052856f,
+ 0.056671f, 0.060638f, 0.064819f, 0.069092f, 0.073425f, 0.078125f, 0.082886f, 0.087280f, 0.092651f, 0.098206f, 0.103638f, 0.109192f,
+ 0.114563f, 0.120667f, 0.126709f, 0.133057f, 0.139771f, 0.146851f, 0.153931f, 0.160767f, 0.168457f, 0.175903f, 0.183838f, 0.192505f,
+ 0.200195f, 0.208618f, 0.217407f, 0.226562f, 0.236084f, 0.245239f, 0.254639f, 0.263672f, 0.273926f, 0.283447f, 0.294189f, 0.304932f,
+ 0.315674f, 0.326172f, 0.337402f, 0.348877f, 0.360107f, 0.373291f, 0.653809f, 0.670410f, 0.669922f, 0.667480f, 0.665527f, 0.662109f,
+ 0.001639f, 0.004951f, 0.007996f, 0.010857f, 0.013779f, 0.016968f, 0.019974f, 0.023392f, 0.026001f, 0.029373f, 0.032013f, 0.035370f,
+ 0.038513f, 0.041992f, 0.044586f, 0.048706f, 0.052124f, 0.055634f, 0.059723f, 0.063354f, 0.067444f, 0.071289f, 0.075745f, 0.080444f,
+ 0.085022f, 0.089722f, 0.095032f, 0.100220f, 0.105347f, 0.111206f, 0.117126f, 0.123108f, 0.129395f, 0.135620f, 0.142090f, 0.148682f,
+ 0.156372f, 0.163574f, 0.170898f, 0.178711f, 0.186890f, 0.194580f, 0.203613f, 0.211426f, 0.220459f, 0.229492f, 0.238281f, 0.248169f,
+ 0.257324f, 0.267578f, 0.277832f, 0.287354f, 0.298340f, 0.308350f, 0.319824f, 0.331543f, 0.342041f, 0.354248f, 0.641602f, 0.660645f,
+ 0.662109f, 0.660645f, 0.658203f, 0.654785f, 0.001569f, 0.004539f, 0.007538f, 0.010368f, 0.013359f, 0.016006f, 0.018539f, 0.021210f,
+ 0.024384f, 0.026855f, 0.029892f, 0.032471f, 0.035034f, 0.038177f, 0.041199f, 0.044434f, 0.047485f, 0.050781f, 0.054321f, 0.057953f,
+ 0.061523f, 0.065430f, 0.069275f, 0.073547f, 0.077820f, 0.082092f, 0.086731f, 0.091736f, 0.096985f, 0.101990f, 0.107361f, 0.112549f,
+ 0.118774f, 0.124878f, 0.131104f, 0.137573f, 0.144409f, 0.150635f, 0.157837f, 0.165283f, 0.173340f, 0.181274f, 0.188599f, 0.197510f,
+ 0.205933f, 0.214600f, 0.223633f, 0.232056f, 0.241577f, 0.251709f, 0.261230f, 0.270996f, 0.281250f, 0.291260f, 0.302246f, 0.313477f,
+ 0.323730f, 0.336182f, 0.630859f, 0.651855f, 0.652832f, 0.652344f, 0.650391f, 0.647461f, 0.001558f, 0.004139f, 0.007103f, 0.009560f,
+ 0.012077f, 0.014313f, 0.016983f, 0.019653f, 0.021988f, 0.024490f, 0.027023f, 0.029526f, 0.031891f, 0.034821f, 0.037903f, 0.040192f,
+ 0.043457f, 0.046417f, 0.049316f, 0.052795f, 0.055725f, 0.059357f, 0.063354f, 0.066895f, 0.070740f, 0.074890f, 0.078979f, 0.083801f,
+ 0.088440f, 0.093018f, 0.097961f, 0.103394f, 0.108704f, 0.114563f, 0.120239f, 0.126343f, 0.132690f, 0.139038f, 0.145874f, 0.152710f,
+ 0.159912f, 0.168091f, 0.175537f, 0.183228f, 0.191650f, 0.199707f, 0.208130f, 0.216797f, 0.226074f, 0.235352f, 0.244507f, 0.254395f,
+ 0.264404f, 0.274414f, 0.285156f, 0.296631f, 0.307373f, 0.318604f, 0.619141f, 0.643066f, 0.644531f, 0.644043f, 0.642578f, 0.639648f,
+ 0.001314f, 0.004002f, 0.006603f, 0.009056f, 0.011490f, 0.013184f, 0.015587f, 0.017883f, 0.020157f, 0.022415f, 0.024582f, 0.027206f,
+ 0.029160f, 0.031677f, 0.034088f, 0.036530f, 0.039337f, 0.042206f, 0.044891f, 0.047729f, 0.050751f, 0.053955f, 0.057312f, 0.060486f,
+ 0.064148f, 0.068054f, 0.071960f, 0.075867f, 0.079895f, 0.084595f, 0.089172f, 0.094238f, 0.098999f, 0.104492f, 0.109802f, 0.115173f,
+ 0.121338f, 0.127686f, 0.134033f, 0.140991f, 0.147095f, 0.154541f, 0.161865f, 0.169800f, 0.177368f, 0.185547f, 0.193848f, 0.201904f,
+ 0.211060f, 0.219116f, 0.229004f, 0.238525f, 0.248047f, 0.257812f, 0.267822f, 0.277832f, 0.289062f, 0.300537f, 0.607910f, 0.633301f,
+ 0.636230f, 0.635742f, 0.634766f, 0.633301f, 0.001217f, 0.003571f, 0.005947f, 0.008011f, 0.010391f, 0.012207f, 0.014313f, 0.016617f,
+ 0.018280f, 0.020523f, 0.022537f, 0.024475f, 0.026443f, 0.028778f, 0.030884f, 0.032867f, 0.035553f, 0.037872f, 0.040375f, 0.042938f,
+ 0.045593f, 0.048431f, 0.051605f, 0.054688f, 0.057953f, 0.061279f, 0.065002f, 0.068665f, 0.072266f, 0.076294f, 0.080872f, 0.085083f,
+ 0.089783f, 0.094482f, 0.099915f, 0.104736f, 0.110901f, 0.116272f, 0.122314f, 0.128784f, 0.134888f, 0.142090f, 0.148560f, 0.155884f,
+ 0.163574f, 0.171753f, 0.179077f, 0.187500f, 0.195679f, 0.204346f, 0.213745f, 0.222656f, 0.231812f, 0.241455f, 0.250977f, 0.261230f,
+ 0.272461f, 0.282959f, 0.596680f, 0.623535f, 0.627441f, 0.627930f, 0.627441f, 0.625000f, 0.001111f, 0.003542f, 0.005569f, 0.007504f,
+ 0.009338f, 0.011452f, 0.012939f, 0.015030f, 0.016678f, 0.018326f, 0.020203f, 0.022217f, 0.023788f, 0.025604f, 0.027771f, 0.029877f,
+ 0.031860f, 0.033813f, 0.036102f, 0.038605f, 0.040985f, 0.043579f, 0.046448f, 0.049042f, 0.051849f, 0.055054f, 0.058319f, 0.061615f,
+ 0.065125f, 0.068909f, 0.072815f, 0.076843f, 0.080872f, 0.085571f, 0.089905f, 0.095398f, 0.100159f, 0.105713f, 0.111206f, 0.116882f,
+ 0.122925f, 0.129517f, 0.135742f, 0.142822f, 0.149902f, 0.157349f, 0.165161f, 0.172852f, 0.181152f, 0.189331f, 0.198120f, 0.206909f,
+ 0.215820f, 0.225342f, 0.235474f, 0.245239f, 0.254883f, 0.266602f, 0.584473f, 0.614746f, 0.619141f, 0.619629f, 0.619141f, 0.618164f,
+ 0.001149f, 0.003147f, 0.004826f, 0.006886f, 0.008629f, 0.010452f, 0.012024f, 0.013359f, 0.015175f, 0.016647f, 0.018143f, 0.019882f,
+ 0.021332f, 0.023026f, 0.024902f, 0.026550f, 0.028397f, 0.030045f, 0.032318f, 0.034393f, 0.036682f, 0.038910f, 0.041107f, 0.043671f,
+ 0.046295f, 0.048950f, 0.051819f, 0.054993f, 0.058258f, 0.061523f, 0.065063f, 0.068481f, 0.072510f, 0.076965f, 0.081055f, 0.085510f,
+ 0.090393f, 0.095093f, 0.100342f, 0.105774f, 0.111694f, 0.117371f, 0.124084f, 0.130371f, 0.136963f, 0.143921f, 0.151245f, 0.159058f,
+ 0.166626f, 0.174927f, 0.182983f, 0.191650f, 0.200195f, 0.209473f, 0.218750f, 0.228149f, 0.238037f, 0.249146f, 0.572266f, 0.604980f,
+ 0.609863f, 0.611328f, 0.610352f, 0.611328f, 0.001009f, 0.003059f, 0.004620f, 0.006283f, 0.007881f, 0.009415f, 0.010864f, 0.011940f,
+ 0.013443f, 0.014847f, 0.016403f, 0.017700f, 0.019012f, 0.020493f, 0.021927f, 0.023697f, 0.025177f, 0.026947f, 0.028732f, 0.030472f,
+ 0.032654f, 0.034302f, 0.036591f, 0.038757f, 0.041046f, 0.043488f, 0.045837f, 0.048706f, 0.051544f, 0.054810f, 0.057770f, 0.061188f,
+ 0.064331f, 0.068237f, 0.072083f, 0.076416f, 0.080872f, 0.085388f, 0.090149f, 0.095276f, 0.100403f, 0.105896f, 0.111877f, 0.117798f,
+ 0.124329f, 0.130859f, 0.138062f, 0.145020f, 0.152710f, 0.160034f, 0.168335f, 0.176514f, 0.185059f, 0.193481f, 0.203125f, 0.212158f,
+ 0.221924f, 0.232178f, 0.562500f, 0.594727f, 0.601074f, 0.602539f, 0.603516f, 0.602539f, 0.000865f, 0.002674f, 0.004444f, 0.005615f,
+ 0.007233f, 0.008430f, 0.009827f, 0.010880f, 0.011917f, 0.013206f, 0.014412f, 0.015717f, 0.016876f, 0.018173f, 0.019501f, 0.020950f,
+ 0.022217f, 0.023773f, 0.025284f, 0.026749f, 0.028610f, 0.030151f, 0.032166f, 0.034149f, 0.036041f, 0.038330f, 0.040558f, 0.042877f,
+ 0.045532f, 0.048157f, 0.050934f, 0.053894f, 0.056946f, 0.060303f, 0.063843f, 0.067566f, 0.071472f, 0.075806f, 0.080261f, 0.084778f,
+ 0.089600f, 0.094971f, 0.100220f, 0.105896f, 0.111877f, 0.118103f, 0.125000f, 0.131348f, 0.138550f, 0.146362f, 0.153687f, 0.161987f,
+ 0.169678f, 0.178223f, 0.187134f, 0.196045f, 0.205811f, 0.215698f, 0.549805f, 0.584961f, 0.592773f, 0.594238f, 0.593750f, 0.595215f,
+ 0.000951f, 0.002476f, 0.003956f, 0.005062f, 0.006268f, 0.007637f, 0.008888f, 0.009666f, 0.010628f, 0.011810f, 0.012856f, 0.013878f,
+ 0.014946f, 0.015900f, 0.017227f, 0.018356f, 0.019592f, 0.020889f, 0.022003f, 0.023438f, 0.025101f, 0.026489f, 0.028122f, 0.029739f,
+ 0.031555f, 0.033295f, 0.035431f, 0.037537f, 0.039795f, 0.041962f, 0.044647f, 0.047302f, 0.049957f, 0.052979f, 0.056122f, 0.059387f,
+ 0.062927f, 0.066956f, 0.070679f, 0.074951f, 0.079468f, 0.084167f, 0.089294f, 0.094482f, 0.100098f, 0.106018f, 0.112061f, 0.118835f,
+ 0.125366f, 0.132446f, 0.139893f, 0.147827f, 0.155762f, 0.163574f, 0.172607f, 0.180786f, 0.190063f, 0.199951f, 0.536621f, 0.576172f,
+ 0.583496f, 0.586914f, 0.587402f, 0.586914f, 0.000788f, 0.002115f, 0.003592f, 0.004780f, 0.005939f, 0.006615f, 0.007740f, 0.008598f,
+ 0.009514f, 0.010376f, 0.011200f, 0.012138f, 0.013016f, 0.014069f, 0.014977f, 0.015961f, 0.016922f, 0.018036f, 0.019043f, 0.020447f,
+ 0.021606f, 0.022995f, 0.024323f, 0.025864f, 0.027344f, 0.028946f, 0.030731f, 0.032593f, 0.034515f, 0.036530f, 0.038910f, 0.041016f,
+ 0.043274f, 0.046021f, 0.048981f, 0.051819f, 0.055176f, 0.058472f, 0.062012f, 0.065857f, 0.069946f, 0.074219f, 0.078796f, 0.083801f,
+ 0.088806f, 0.094299f, 0.100281f, 0.106018f, 0.112793f, 0.119446f, 0.126343f, 0.133545f, 0.141357f, 0.149292f, 0.157104f, 0.165894f,
+ 0.174683f, 0.184326f, 0.524902f, 0.566895f, 0.575195f, 0.576660f, 0.579102f, 0.579590f, 0.000661f, 0.001961f, 0.003382f, 0.004311f,
+ 0.005161f, 0.006062f, 0.006737f, 0.007427f, 0.008286f, 0.008995f, 0.009857f, 0.010368f, 0.011230f, 0.011955f, 0.012833f, 0.013786f,
+ 0.014565f, 0.015480f, 0.016647f, 0.017578f, 0.018677f, 0.019806f, 0.020950f, 0.022263f, 0.023651f, 0.024994f, 0.026306f, 0.027863f,
+ 0.029724f, 0.031525f, 0.033325f, 0.035370f, 0.037292f, 0.039673f, 0.042114f, 0.044769f, 0.047546f, 0.050537f, 0.053680f, 0.057098f,
+ 0.060852f, 0.064514f, 0.069031f, 0.073303f, 0.078064f, 0.083069f, 0.088379f, 0.094238f, 0.100220f, 0.106689f, 0.113342f, 0.120300f,
+ 0.127563f, 0.135132f, 0.142700f, 0.151245f, 0.160034f, 0.168823f, 0.512695f, 0.557129f, 0.566406f, 0.569824f, 0.569824f, 0.571289f,
+ 0.000757f, 0.001709f, 0.002844f, 0.003582f, 0.004448f, 0.005192f, 0.005989f, 0.006519f, 0.007038f, 0.007801f, 0.008453f, 0.009071f,
+ 0.009727f, 0.010391f, 0.011009f, 0.011726f, 0.012650f, 0.013184f, 0.014107f, 0.014977f, 0.015900f, 0.016800f, 0.017776f, 0.018936f,
+ 0.020172f, 0.021271f, 0.022446f, 0.023697f, 0.025055f, 0.026703f, 0.028397f, 0.030014f, 0.031921f, 0.033905f, 0.035919f, 0.038177f,
+ 0.040680f, 0.043243f, 0.045898f, 0.049072f, 0.052216f, 0.055725f, 0.059784f, 0.063538f, 0.067688f, 0.072327f, 0.077271f, 0.082764f,
+ 0.088379f, 0.094299f, 0.100708f, 0.107239f, 0.114136f, 0.121582f, 0.128906f, 0.136963f, 0.145630f, 0.153564f, 0.500977f, 0.547852f,
+ 0.556641f, 0.561523f, 0.562500f, 0.563965f, 0.000704f, 0.001769f, 0.002542f, 0.003523f, 0.004036f, 0.004562f, 0.005032f, 0.005661f,
+ 0.006176f, 0.006542f, 0.007072f, 0.007698f, 0.008339f, 0.008827f, 0.009323f, 0.010094f, 0.010757f, 0.011276f, 0.012093f, 0.012733f,
+ 0.013489f, 0.014488f, 0.015244f, 0.016006f, 0.017151f, 0.017975f, 0.018967f, 0.020142f, 0.021255f, 0.022552f, 0.023880f, 0.025314f,
+ 0.026840f, 0.028503f, 0.030441f, 0.032166f, 0.034424f, 0.036438f, 0.039001f, 0.041656f, 0.044464f, 0.047455f, 0.050842f, 0.054443f,
+ 0.058167f, 0.062286f, 0.066956f, 0.071899f, 0.076904f, 0.082458f, 0.088501f, 0.094482f, 0.101196f, 0.108337f, 0.115662f, 0.123352f,
+ 0.130981f, 0.139282f, 0.489746f, 0.538574f, 0.547852f, 0.551270f, 0.554688f, 0.555176f, 0.000579f, 0.001450f, 0.002396f, 0.002857f,
+ 0.003454f, 0.004032f, 0.004356f, 0.004791f, 0.005333f, 0.005718f, 0.006130f, 0.006485f, 0.007042f, 0.007473f, 0.007988f, 0.008476f,
+ 0.008865f, 0.009613f, 0.010086f, 0.010651f, 0.011345f, 0.012047f, 0.012764f, 0.013435f, 0.014282f, 0.015144f, 0.015884f, 0.016846f,
+ 0.017868f, 0.018814f, 0.020050f, 0.021164f, 0.022507f, 0.023773f, 0.025192f, 0.026978f, 0.028564f, 0.030640f, 0.032623f, 0.034882f,
+ 0.037231f, 0.039886f, 0.042786f, 0.046143f, 0.049286f, 0.052979f, 0.057098f, 0.061279f, 0.066223f, 0.071167f, 0.076660f, 0.082581f,
+ 0.088989f, 0.095581f, 0.102661f, 0.109863f, 0.117737f, 0.125488f, 0.476807f, 0.528320f, 0.538574f, 0.543945f, 0.546875f, 0.546875f,
+ 0.000510f, 0.001428f, 0.002037f, 0.002613f, 0.003086f, 0.003290f, 0.003672f, 0.004108f, 0.004345f, 0.004768f, 0.005035f, 0.005470f,
+ 0.005959f, 0.006207f, 0.006599f, 0.007095f, 0.007568f, 0.008003f, 0.008377f, 0.008904f, 0.009575f, 0.010010f, 0.010643f, 0.011131f,
+ 0.011871f, 0.012535f, 0.013199f, 0.014038f, 0.014839f, 0.015640f, 0.016586f, 0.017502f, 0.018585f, 0.019745f, 0.021088f, 0.022354f,
+ 0.023727f, 0.025253f, 0.026962f, 0.028870f, 0.030762f, 0.033051f, 0.035492f, 0.038177f, 0.041229f, 0.044403f, 0.048004f, 0.051880f,
+ 0.056213f, 0.060516f, 0.065857f, 0.071045f, 0.077271f, 0.083374f, 0.090027f, 0.096863f, 0.104492f, 0.112183f, 0.463623f, 0.518066f,
+ 0.529785f, 0.535156f, 0.538086f, 0.540039f, 0.000473f, 0.001222f, 0.001771f, 0.002117f, 0.002323f, 0.002796f, 0.003096f, 0.003355f,
+ 0.003601f, 0.003975f, 0.004295f, 0.004543f, 0.004833f, 0.005142f, 0.005455f, 0.005848f, 0.006165f, 0.006535f, 0.006947f, 0.007370f,
+ 0.007809f, 0.008240f, 0.008690f, 0.009216f, 0.009758f, 0.010223f, 0.010925f, 0.011536f, 0.012146f, 0.012833f, 0.013573f, 0.014389f,
+ 0.015244f, 0.016220f, 0.017120f, 0.018219f, 0.019379f, 0.020599f, 0.021988f, 0.023514f, 0.025131f, 0.027054f, 0.029037f, 0.031311f,
+ 0.033752f, 0.036591f, 0.039520f, 0.042999f, 0.046661f, 0.050873f, 0.055603f, 0.060333f, 0.066101f, 0.071960f, 0.078491f, 0.084961f,
+ 0.091797f, 0.099426f, 0.452148f, 0.508301f, 0.520508f, 0.526367f, 0.528809f, 0.530273f, 0.000299f, 0.001057f, 0.001329f, 0.001771f,
+ 0.001957f, 0.002350f, 0.002483f, 0.002697f, 0.002964f, 0.003181f, 0.003441f, 0.003653f, 0.003904f, 0.004238f, 0.004501f, 0.004738f,
+ 0.005024f, 0.005390f, 0.005657f, 0.005985f, 0.006279f, 0.006714f, 0.007053f, 0.007507f, 0.007881f, 0.008369f, 0.008774f, 0.009300f,
+ 0.009888f, 0.010483f, 0.011093f, 0.011627f, 0.012398f, 0.013130f, 0.013855f, 0.014717f, 0.015686f, 0.016739f, 0.017761f, 0.018890f,
+ 0.020248f, 0.021698f, 0.023376f, 0.025131f, 0.027237f, 0.029556f, 0.032166f, 0.035004f, 0.038208f, 0.041962f, 0.045868f, 0.050507f,
+ 0.055359f, 0.060852f, 0.066772f, 0.073242f, 0.080017f, 0.087097f, 0.440674f, 0.498047f, 0.511719f, 0.517090f, 0.520508f, 0.522949f,
+ 0.000427f, 0.001020f, 0.001253f, 0.001431f, 0.001690f, 0.001900f, 0.002018f, 0.002304f, 0.002481f, 0.002569f, 0.002731f, 0.002998f,
+ 0.003157f, 0.003424f, 0.003592f, 0.003838f, 0.004017f, 0.004253f, 0.004551f, 0.004776f, 0.005100f, 0.005379f, 0.005699f, 0.005932f,
+ 0.006290f, 0.006630f, 0.007038f, 0.007465f, 0.007927f, 0.008286f, 0.008858f, 0.009293f, 0.009888f, 0.010429f, 0.011086f, 0.011765f,
+ 0.012482f, 0.013298f, 0.014168f, 0.015068f, 0.016129f, 0.017288f, 0.018585f, 0.019943f, 0.021622f, 0.023361f, 0.025436f, 0.027847f,
+ 0.030655f, 0.033447f, 0.037079f, 0.041229f, 0.045776f, 0.050568f, 0.056061f, 0.062317f, 0.068726f, 0.075684f, 0.427734f, 0.488525f,
+ 0.502441f, 0.508789f, 0.513184f, 0.513672f, 0.000255f, 0.000597f, 0.001032f, 0.001150f, 0.001353f, 0.001493f, 0.001608f, 0.001750f,
+ 0.001933f, 0.002062f, 0.002178f, 0.002302f, 0.002474f, 0.002670f, 0.002872f, 0.002995f, 0.003147f, 0.003298f, 0.003565f, 0.003729f,
+ 0.003941f, 0.004219f, 0.004436f, 0.004719f, 0.005005f, 0.005230f, 0.005489f, 0.005806f, 0.006191f, 0.006496f, 0.006897f, 0.007267f,
+ 0.007671f, 0.008179f, 0.008636f, 0.009163f, 0.009766f, 0.010368f, 0.011047f, 0.011810f, 0.012611f, 0.013527f, 0.014519f, 0.015640f,
+ 0.016800f, 0.018265f, 0.019897f, 0.021698f, 0.023895f, 0.026260f, 0.029175f, 0.032715f, 0.036682f, 0.041168f, 0.045929f, 0.051758f,
+ 0.057922f, 0.064575f, 0.415771f, 0.478271f, 0.493652f, 0.500000f, 0.503906f, 0.505859f, 0.000255f, 0.000544f, 0.000863f, 0.000994f,
+ 0.001086f, 0.001183f, 0.001317f, 0.001328f, 0.001491f, 0.001608f, 0.001716f, 0.001851f, 0.001943f, 0.002075f, 0.002161f, 0.002319f,
+ 0.002426f, 0.002596f, 0.002741f, 0.002884f, 0.003088f, 0.003265f, 0.003391f, 0.003620f, 0.003777f, 0.004005f, 0.004215f, 0.004452f,
+ 0.004734f, 0.004963f, 0.005341f, 0.005577f, 0.005875f, 0.006271f, 0.006603f, 0.006996f, 0.007450f, 0.007919f, 0.008446f, 0.009003f,
+ 0.009674f, 0.010338f, 0.011101f, 0.011909f, 0.012917f, 0.013977f, 0.015190f, 0.016495f, 0.018112f, 0.020325f, 0.022415f, 0.025146f,
+ 0.028473f, 0.032349f, 0.036804f, 0.041992f, 0.047913f, 0.054077f, 0.404541f, 0.468506f, 0.484131f, 0.490967f, 0.495361f, 0.498291f,
+ 0.000377f, 0.000440f, 0.000606f, 0.000685f, 0.000735f, 0.000876f, 0.000929f, 0.001035f, 0.001068f, 0.001157f, 0.001307f, 0.001381f,
+ 0.001473f, 0.001595f, 0.001664f, 0.001708f, 0.001850f, 0.001957f, 0.002043f, 0.002195f, 0.002291f, 0.002422f, 0.002571f, 0.002687f,
+ 0.002842f, 0.002979f, 0.003183f, 0.003345f, 0.003532f, 0.003794f, 0.004002f, 0.004154f, 0.004429f, 0.004635f, 0.004967f, 0.005253f,
+ 0.005573f, 0.005909f, 0.006275f, 0.006695f, 0.007183f, 0.007660f, 0.008316f, 0.008934f, 0.009644f, 0.010429f, 0.011360f, 0.012497f,
+ 0.013634f, 0.014977f, 0.016663f, 0.018875f, 0.021423f, 0.024643f, 0.028549f, 0.033020f, 0.038483f, 0.044525f, 0.391602f, 0.458984f,
+ 0.474854f, 0.482178f, 0.488037f, 0.489990f, 0.000159f, 0.000401f, 0.000450f, 0.000522f, 0.000605f, 0.000634f, 0.000728f, 0.000702f,
+ 0.000808f, 0.000882f, 0.000959f, 0.000991f, 0.001043f, 0.001112f, 0.001205f, 0.001245f, 0.001357f, 0.001419f, 0.001513f, 0.001546f,
+ 0.001648f, 0.001752f, 0.001863f, 0.001942f, 0.002056f, 0.002159f, 0.002289f, 0.002392f, 0.002506f, 0.002697f, 0.002827f, 0.003023f,
+ 0.003172f, 0.003330f, 0.003542f, 0.003750f, 0.004017f, 0.004292f, 0.004559f, 0.004871f, 0.005161f, 0.005539f, 0.005932f, 0.006416f,
+ 0.006973f, 0.007526f, 0.008232f, 0.008980f, 0.009918f, 0.010895f, 0.012085f, 0.013680f, 0.015472f, 0.017975f, 0.021103f, 0.025146f,
+ 0.029938f, 0.035645f, 0.379395f, 0.448486f, 0.465820f, 0.473633f, 0.478760f, 0.481689f, 0.000112f, 0.000220f, 0.000321f, 0.000322f,
+ 0.000401f, 0.000489f, 0.000469f, 0.000510f, 0.000568f, 0.000653f, 0.000659f, 0.000676f, 0.000703f, 0.000789f, 0.000811f, 0.000886f,
+ 0.000888f, 0.000994f, 0.001048f, 0.001096f, 0.001155f, 0.001220f, 0.001289f, 0.001357f, 0.001431f, 0.001496f, 0.001599f, 0.001675f,
+ 0.001759f, 0.001894f, 0.001965f, 0.002083f, 0.002193f, 0.002310f, 0.002464f, 0.002634f, 0.002758f, 0.002949f, 0.003134f, 0.003319f,
+ 0.003551f, 0.003830f, 0.004120f, 0.004440f, 0.004784f, 0.005188f, 0.005680f, 0.006222f, 0.006886f, 0.007614f, 0.008461f, 0.009529f,
+ 0.010864f, 0.012596f, 0.014961f, 0.018097f, 0.022263f, 0.027466f, 0.367920f, 0.438232f, 0.456543f, 0.465332f, 0.470215f, 0.472900f,
+ 0.000140f, 0.000219f, 0.000241f, 0.000245f, 0.000290f, 0.000291f, 0.000302f, 0.000342f, 0.000380f, 0.000409f, 0.000408f, 0.000485f,
+ 0.000473f, 0.000527f, 0.000556f, 0.000575f, 0.000630f, 0.000642f, 0.000673f, 0.000711f, 0.000762f, 0.000800f, 0.000852f, 0.000886f,
+ 0.000952f, 0.000982f, 0.001049f, 0.001108f, 0.001159f, 0.001220f, 0.001281f, 0.001369f, 0.001454f, 0.001522f, 0.001595f, 0.001695f,
+ 0.001839f, 0.001928f, 0.002068f, 0.002209f, 0.002337f, 0.002504f, 0.002686f, 0.002876f, 0.003139f, 0.003437f, 0.003723f, 0.004078f,
+ 0.004509f, 0.005009f, 0.005615f, 0.006332f, 0.007317f, 0.008461f, 0.009926f, 0.012154f, 0.015640f, 0.020325f, 0.356445f, 0.429199f,
+ 0.447266f, 0.456299f, 0.462158f, 0.464844f, 0.000048f, 0.000154f, 0.000141f, 0.000147f, 0.000174f, 0.000207f, 0.000188f, 0.000221f,
+ 0.000233f, 0.000242f, 0.000248f, 0.000271f, 0.000299f, 0.000312f, 0.000337f, 0.000350f, 0.000367f, 0.000403f, 0.000416f, 0.000458f,
+ 0.000465f, 0.000483f, 0.000507f, 0.000546f, 0.000576f, 0.000625f, 0.000637f, 0.000659f, 0.000705f, 0.000742f, 0.000797f, 0.000837f,
+ 0.000890f, 0.000925f, 0.000978f, 0.001036f, 0.001103f, 0.001181f, 0.001253f, 0.001329f, 0.001421f, 0.001529f, 0.001647f, 0.001782f,
+ 0.001906f, 0.002075f, 0.002291f, 0.002483f, 0.002758f, 0.003059f, 0.003450f, 0.003906f, 0.004536f, 0.005306f, 0.006325f, 0.007713f,
+ 0.010101f, 0.014084f, 0.343262f, 0.418457f, 0.437744f, 0.447510f, 0.452881f, 0.456543f, 0.000099f, 0.000100f, 0.000091f, 0.000085f,
+ 0.000105f, 0.000099f, 0.000127f, 0.000127f, 0.000130f, 0.000137f, 0.000152f, 0.000164f, 0.000164f, 0.000172f, 0.000195f, 0.000186f,
+ 0.000209f, 0.000222f, 0.000231f, 0.000241f, 0.000258f, 0.000266f, 0.000290f, 0.000301f, 0.000324f, 0.000343f, 0.000357f, 0.000369f,
+ 0.000392f, 0.000409f, 0.000440f, 0.000463f, 0.000484f, 0.000513f, 0.000544f, 0.000578f, 0.000607f, 0.000650f, 0.000702f, 0.000737f,
+ 0.000787f, 0.000846f, 0.000918f, 0.000977f, 0.001062f, 0.001146f, 0.001259f, 0.001379f, 0.001524f, 0.001701f, 0.001924f, 0.002207f,
+ 0.002542f, 0.003006f, 0.003628f, 0.004494f, 0.005821f, 0.008774f, 0.332031f, 0.409180f, 0.428467f, 0.438965f, 0.444336f, 0.447998f,
+ 0.000082f, 0.000057f, 0.000048f, 0.000051f, 0.000055f, 0.000054f, 0.000057f, 0.000064f, 0.000066f, 0.000079f, 0.000070f, 0.000070f,
+ 0.000084f, 0.000078f, 0.000084f, 0.000091f, 0.000099f, 0.000108f, 0.000108f, 0.000114f, 0.000119f, 0.000124f, 0.000129f, 0.000144f,
+ 0.000151f, 0.000158f, 0.000163f, 0.000176f, 0.000188f, 0.000196f, 0.000208f, 0.000220f, 0.000227f, 0.000239f, 0.000259f, 0.000273f,
+ 0.000290f, 0.000303f, 0.000331f, 0.000351f, 0.000376f, 0.000402f, 0.000432f, 0.000460f, 0.000500f, 0.000547f, 0.000593f, 0.000648f,
+ 0.000720f, 0.000805f, 0.000918f, 0.001045f, 0.001225f, 0.001462f, 0.001788f, 0.002264f, 0.003029f, 0.004623f, 0.320801f, 0.398682f,
+ 0.419922f, 0.430420f, 0.436279f, 0.440674f, 0.000061f, 0.000041f, 0.000033f, 0.000029f, 0.000026f, 0.000025f, 0.000024f, 0.000024f,
+ 0.000023f, 0.000023f, 0.000025f, 0.000032f, 0.000026f, 0.000027f, 0.000035f, 0.000037f, 0.000039f, 0.000041f, 0.000041f, 0.000041f,
+ 0.000044f, 0.000050f, 0.000054f, 0.000051f, 0.000055f, 0.000060f, 0.000061f, 0.000062f, 0.000069f, 0.000074f, 0.000075f, 0.000081f,
+ 0.000087f, 0.000090f, 0.000093f, 0.000098f, 0.000108f, 0.000114f, 0.000123f, 0.000130f, 0.000142f, 0.000144f, 0.000156f, 0.000173f,
+ 0.000179f, 0.000200f, 0.000218f, 0.000237f, 0.000267f, 0.000299f, 0.000335f, 0.000382f, 0.000448f, 0.000544f, 0.000677f, 0.000883f,
+ 0.001233f, 0.001933f, 0.309570f, 0.388672f, 0.410889f, 0.421143f, 0.427246f, 0.431885f, 0.000031f, 0.000020f, 0.000016f, 0.000014f,
+ 0.000013f, 0.000012f, 0.000012f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000008f, 0.000009f,
+ 0.000009f, 0.000007f, 0.000007f, 0.000007f, 0.000008f, 0.000009f, 0.000011f, 0.000012f, 0.000012f, 0.000012f, 0.000013f, 0.000015f,
+ 0.000015f, 0.000014f, 0.000016f, 0.000017f, 0.000019f, 0.000020f, 0.000020f, 0.000022f, 0.000025f, 0.000023f, 0.000026f, 0.000029f,
+ 0.000031f, 0.000034f, 0.000036f, 0.000037f, 0.000040f, 0.000044f, 0.000048f, 0.000052f, 0.000056f, 0.000063f, 0.000068f, 0.000083f,
+ 0.000098f, 0.000117f, 0.000149f, 0.000201f, 0.000301f, 0.000544f, 0.297607f, 0.379150f, 0.400879f, 0.411865f, 0.419189f, 0.423340f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,
+ 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000002f, 0.000003f, 0.000004f, 0.000004f, 0.000004f, 0.000005f, 0.000007f, 0.000011f, 0.000026f, 0.286621f, 0.368896f,
+ 0.391846f, 0.402588f, 0.409912f, 0.414551f,
+ },
+ {
+ 0.007935f, 0.024429f, 0.041290f, 0.058838f, 0.076355f, 0.093933f, 0.111145f, 0.128174f, 0.146606f, 0.164429f, 0.182617f, 0.200562f,
+ 0.218750f, 0.236206f, 0.254150f, 0.271729f, 0.289551f, 0.308105f, 0.325684f, 0.342773f, 0.360596f, 0.379150f, 0.396240f, 0.414795f,
+ 0.431641f, 0.450439f, 0.468018f, 0.484619f, 0.502441f, 0.520020f, 0.536621f, 0.554688f, 0.571777f, 0.588379f, 0.605469f, 0.622559f,
+ 0.640137f, 0.657227f, 0.672852f, 0.689941f, 0.707031f, 0.723633f, 0.740234f, 0.756836f, 0.773926f, 0.789551f, 0.805664f, 0.821777f,
+ 0.838379f, 0.854980f, 0.870117f, 0.885742f, 0.901855f, 0.917480f, 0.932617f, 0.948730f, 0.963379f, 0.979492f, 0.960449f, 0.909668f,
+ 0.876465f, 0.850098f, 0.827637f, 0.807617f, 0.007530f, 0.023422f, 0.039764f, 0.056610f, 0.073303f, 0.090149f, 0.107300f, 0.124084f,
+ 0.141968f, 0.158569f, 0.176392f, 0.193604f, 0.210815f, 0.228760f, 0.246094f, 0.262695f, 0.280518f, 0.298340f, 0.315430f, 0.333252f,
+ 0.350586f, 0.367432f, 0.384766f, 0.402344f, 0.419678f, 0.436768f, 0.453613f, 0.471436f, 0.488037f, 0.504883f, 0.521973f, 0.538574f,
+ 0.556641f, 0.573242f, 0.589844f, 0.605957f, 0.623535f, 0.639160f, 0.656250f, 0.673340f, 0.688477f, 0.706055f, 0.721680f, 0.738770f,
+ 0.754883f, 0.770508f, 0.786133f, 0.803711f, 0.817871f, 0.834473f, 0.850586f, 0.866211f, 0.881348f, 0.896973f, 0.913086f, 0.928223f,
+ 0.942871f, 0.958984f, 0.951172f, 0.903320f, 0.871094f, 0.845703f, 0.824219f, 0.805664f, 0.007320f, 0.022552f, 0.038391f, 0.054260f,
+ 0.070312f, 0.086792f, 0.103271f, 0.120178f, 0.136841f, 0.153564f, 0.170410f, 0.187256f, 0.203735f, 0.220825f, 0.237793f, 0.255127f,
+ 0.271240f, 0.288086f, 0.305420f, 0.322021f, 0.339844f, 0.356689f, 0.373047f, 0.390137f, 0.406738f, 0.423340f, 0.440186f, 0.456787f,
+ 0.474121f, 0.490967f, 0.507324f, 0.523926f, 0.540527f, 0.557129f, 0.573242f, 0.590332f, 0.606445f, 0.623047f, 0.638672f, 0.655273f,
+ 0.671875f, 0.687500f, 0.703613f, 0.720215f, 0.735840f, 0.751953f, 0.767578f, 0.783203f, 0.799316f, 0.814941f, 0.830078f, 0.845703f,
+ 0.861328f, 0.877441f, 0.892090f, 0.908203f, 0.922852f, 0.938477f, 0.941895f, 0.895996f, 0.865723f, 0.841309f, 0.820801f, 0.802734f,
+ 0.007008f, 0.021667f, 0.036865f, 0.052216f, 0.067871f, 0.083862f, 0.099426f, 0.115479f, 0.131470f, 0.148315f, 0.164551f, 0.180298f,
+ 0.196899f, 0.213379f, 0.229370f, 0.246460f, 0.262695f, 0.279541f, 0.295410f, 0.311523f, 0.329102f, 0.345215f, 0.360840f, 0.378174f,
+ 0.394043f, 0.410156f, 0.427246f, 0.443115f, 0.459717f, 0.476318f, 0.493652f, 0.508789f, 0.524902f, 0.541016f, 0.557129f, 0.573242f,
+ 0.589844f, 0.605469f, 0.621582f, 0.638672f, 0.652832f, 0.669434f, 0.685547f, 0.701660f, 0.717285f, 0.731934f, 0.749023f, 0.764160f,
+ 0.779785f, 0.794922f, 0.810059f, 0.826172f, 0.841309f, 0.856445f, 0.872070f, 0.886719f, 0.902344f, 0.917480f, 0.932129f, 0.889648f,
+ 0.859863f, 0.835938f, 0.816895f, 0.799316f, 0.006817f, 0.020645f, 0.035156f, 0.050110f, 0.065247f, 0.080383f, 0.096313f, 0.111450f,
+ 0.126587f, 0.142456f, 0.158447f, 0.174316f, 0.189819f, 0.205566f, 0.221802f, 0.237427f, 0.253662f, 0.269775f, 0.285889f, 0.301514f,
+ 0.317627f, 0.333740f, 0.349609f, 0.366211f, 0.381348f, 0.397705f, 0.414307f, 0.429932f, 0.447266f, 0.462646f, 0.477539f, 0.494385f,
+ 0.509766f, 0.525879f, 0.541992f, 0.557617f, 0.571777f, 0.588379f, 0.605469f, 0.619629f, 0.636230f, 0.651855f, 0.666992f, 0.681152f,
+ 0.698242f, 0.714355f, 0.729980f, 0.745117f, 0.759766f, 0.775391f, 0.790527f, 0.806152f, 0.821289f, 0.835938f, 0.850586f, 0.866211f,
+ 0.882324f, 0.896484f, 0.922363f, 0.882324f, 0.854004f, 0.831543f, 0.812500f, 0.795898f, 0.006378f, 0.019989f, 0.034027f, 0.048004f,
+ 0.062744f, 0.077148f, 0.091980f, 0.107178f, 0.122192f, 0.137207f, 0.152466f, 0.167603f, 0.183960f, 0.199097f, 0.214111f, 0.229736f,
+ 0.244995f, 0.260254f, 0.276367f, 0.291504f, 0.306641f, 0.322998f, 0.338623f, 0.354248f, 0.369629f, 0.385254f, 0.400879f, 0.416504f,
+ 0.432617f, 0.447510f, 0.464111f, 0.479492f, 0.494141f, 0.511230f, 0.525879f, 0.541016f, 0.556641f, 0.572754f, 0.586914f, 0.602051f,
+ 0.617676f, 0.633789f, 0.648926f, 0.665039f, 0.679688f, 0.695312f, 0.710449f, 0.726074f, 0.739746f, 0.755859f, 0.771484f, 0.785645f,
+ 0.800781f, 0.815918f, 0.831055f, 0.846680f, 0.860840f, 0.875977f, 0.912598f, 0.874512f, 0.847656f, 0.826172f, 0.807617f, 0.791504f,
+ 0.006603f, 0.019287f, 0.032776f, 0.046356f, 0.060272f, 0.073914f, 0.088135f, 0.102905f, 0.117554f, 0.132690f, 0.147095f, 0.161377f,
+ 0.176636f, 0.191162f, 0.205444f, 0.221680f, 0.236572f, 0.251465f, 0.267090f, 0.281250f, 0.296875f, 0.312256f, 0.327393f, 0.342285f,
+ 0.357666f, 0.373291f, 0.388184f, 0.403076f, 0.418457f, 0.433838f, 0.448975f, 0.465088f, 0.479980f, 0.494385f, 0.509277f, 0.525879f,
+ 0.540039f, 0.555176f, 0.570801f, 0.586426f, 0.601074f, 0.616211f, 0.631348f, 0.646484f, 0.661133f, 0.676270f, 0.692383f, 0.705078f,
+ 0.720215f, 0.735352f, 0.751953f, 0.766602f, 0.781250f, 0.796387f, 0.810059f, 0.825684f, 0.840820f, 0.855469f, 0.902344f, 0.866699f,
+ 0.841797f, 0.820312f, 0.803223f, 0.787598f, 0.006111f, 0.018433f, 0.031097f, 0.044739f, 0.057892f, 0.071472f, 0.085205f, 0.099304f,
+ 0.113037f, 0.127319f, 0.141357f, 0.156128f, 0.169678f, 0.183838f, 0.198608f, 0.213745f, 0.227661f, 0.243652f, 0.257324f, 0.272705f,
+ 0.286865f, 0.301025f, 0.316406f, 0.331543f, 0.345703f, 0.360107f, 0.375000f, 0.390625f, 0.405762f, 0.420410f, 0.435303f, 0.449951f,
+ 0.465088f, 0.479492f, 0.494141f, 0.509277f, 0.523926f, 0.538574f, 0.553711f, 0.569336f, 0.583496f, 0.598145f, 0.612793f, 0.628418f,
+ 0.642578f, 0.657227f, 0.671387f, 0.687012f, 0.702637f, 0.716797f, 0.731934f, 0.745605f, 0.761230f, 0.775391f, 0.790527f, 0.805176f,
+ 0.819824f, 0.834961f, 0.892578f, 0.858887f, 0.834473f, 0.814941f, 0.798340f, 0.783203f, 0.005756f, 0.017761f, 0.029907f, 0.042572f,
+ 0.055481f, 0.068420f, 0.081482f, 0.095276f, 0.108826f, 0.122070f, 0.135620f, 0.149902f, 0.163330f, 0.177368f, 0.191284f, 0.206421f,
+ 0.219482f, 0.233521f, 0.247925f, 0.262451f, 0.277100f, 0.290771f, 0.304688f, 0.319580f, 0.334229f, 0.348389f, 0.362549f, 0.377441f,
+ 0.391602f, 0.406250f, 0.421143f, 0.435791f, 0.450439f, 0.463867f, 0.478760f, 0.493164f, 0.507812f, 0.521973f, 0.537109f, 0.551270f,
+ 0.565430f, 0.580078f, 0.594727f, 0.609863f, 0.624023f, 0.638672f, 0.653320f, 0.668457f, 0.682129f, 0.697266f, 0.711914f, 0.726562f,
+ 0.740723f, 0.755859f, 0.770996f, 0.785156f, 0.799805f, 0.814453f, 0.882812f, 0.851562f, 0.827148f, 0.808594f, 0.792969f, 0.778809f,
+ 0.005741f, 0.017166f, 0.029053f, 0.041138f, 0.053345f, 0.065796f, 0.078674f, 0.091248f, 0.104614f, 0.117004f, 0.130737f, 0.143921f,
+ 0.156860f, 0.170288f, 0.183960f, 0.197754f, 0.211304f, 0.224976f, 0.238892f, 0.251953f, 0.266357f, 0.280273f, 0.294922f, 0.308594f,
+ 0.322021f, 0.336914f, 0.350098f, 0.364502f, 0.378174f, 0.393066f, 0.407471f, 0.420166f, 0.435059f, 0.449219f, 0.463135f, 0.477295f,
+ 0.491699f, 0.506348f, 0.520996f, 0.534668f, 0.549316f, 0.563477f, 0.577148f, 0.591309f, 0.605469f, 0.620605f, 0.634766f, 0.648438f,
+ 0.663086f, 0.677734f, 0.691895f, 0.706543f, 0.720215f, 0.734863f, 0.750488f, 0.765137f, 0.779297f, 0.793945f, 0.872559f, 0.843262f,
+ 0.820801f, 0.803223f, 0.787598f, 0.773926f, 0.005283f, 0.016052f, 0.028030f, 0.039246f, 0.050751f, 0.063232f, 0.074829f, 0.087341f,
+ 0.099976f, 0.112732f, 0.125122f, 0.138062f, 0.150757f, 0.163696f, 0.176758f, 0.189697f, 0.203125f, 0.216553f, 0.229614f, 0.243286f,
+ 0.256592f, 0.269775f, 0.283203f, 0.297119f, 0.310547f, 0.324463f, 0.337891f, 0.351807f, 0.365234f, 0.378662f, 0.392822f, 0.406738f,
+ 0.419922f, 0.434814f, 0.448730f, 0.461182f, 0.476562f, 0.489746f, 0.502930f, 0.517578f, 0.531738f, 0.545410f, 0.559082f, 0.573730f,
+ 0.587402f, 0.602051f, 0.615723f, 0.629395f, 0.644043f, 0.658203f, 0.672363f, 0.686523f, 0.701660f, 0.714844f, 0.729980f, 0.743652f,
+ 0.758301f, 0.774414f, 0.862305f, 0.835449f, 0.813965f, 0.796875f, 0.782227f, 0.769043f, 0.005272f, 0.015427f, 0.026230f, 0.037506f,
+ 0.049164f, 0.060516f, 0.072021f, 0.083740f, 0.095825f, 0.108521f, 0.120361f, 0.132324f, 0.144897f, 0.156738f, 0.169922f, 0.182373f,
+ 0.195068f, 0.208008f, 0.220459f, 0.233887f, 0.246948f, 0.260254f, 0.272461f, 0.285889f, 0.299561f, 0.312500f, 0.325684f, 0.338867f,
+ 0.352783f, 0.365479f, 0.378906f, 0.392334f, 0.406006f, 0.419189f, 0.432861f, 0.446777f, 0.460693f, 0.473877f, 0.486572f, 0.500977f,
+ 0.515137f, 0.528809f, 0.542480f, 0.555176f, 0.569824f, 0.583984f, 0.597656f, 0.611328f, 0.625000f, 0.639648f, 0.653320f, 0.667480f,
+ 0.681641f, 0.695801f, 0.709961f, 0.723633f, 0.738281f, 0.752930f, 0.852539f, 0.827148f, 0.807129f, 0.790527f, 0.776367f, 0.764160f,
+ 0.004822f, 0.014885f, 0.025360f, 0.035767f, 0.046570f, 0.057587f, 0.068726f, 0.080139f, 0.091736f, 0.103577f, 0.115479f, 0.126709f,
+ 0.138672f, 0.150879f, 0.162231f, 0.174805f, 0.187622f, 0.199951f, 0.212524f, 0.224854f, 0.236694f, 0.249878f, 0.262207f, 0.275391f,
+ 0.287842f, 0.300293f, 0.313477f, 0.326904f, 0.340088f, 0.353027f, 0.365479f, 0.378174f, 0.391602f, 0.404541f, 0.417236f, 0.431641f,
+ 0.444336f, 0.457764f, 0.470703f, 0.484375f, 0.497803f, 0.510742f, 0.524902f, 0.537598f, 0.552246f, 0.564941f, 0.579590f, 0.592285f,
+ 0.606445f, 0.621094f, 0.634277f, 0.646973f, 0.662109f, 0.675781f, 0.689453f, 0.704102f, 0.718262f, 0.733398f, 0.842285f, 0.818848f,
+ 0.799805f, 0.784180f, 0.770996f, 0.758301f, 0.004745f, 0.014427f, 0.024277f, 0.034546f, 0.044800f, 0.055176f, 0.066040f, 0.076477f,
+ 0.087341f, 0.099060f, 0.110474f, 0.121216f, 0.132690f, 0.144165f, 0.156006f, 0.167358f, 0.179688f, 0.191284f, 0.203247f, 0.216187f,
+ 0.227905f, 0.239868f, 0.252441f, 0.264648f, 0.277100f, 0.289307f, 0.301270f, 0.314453f, 0.326660f, 0.338867f, 0.352539f, 0.364990f,
+ 0.377686f, 0.390137f, 0.403076f, 0.416016f, 0.428467f, 0.441406f, 0.453857f, 0.468262f, 0.480957f, 0.494385f, 0.507324f, 0.520020f,
+ 0.534180f, 0.547363f, 0.560059f, 0.573730f, 0.586914f, 0.601074f, 0.615234f, 0.628418f, 0.641602f, 0.656250f, 0.669434f, 0.683594f,
+ 0.697754f, 0.712402f, 0.832520f, 0.809570f, 0.792480f, 0.778320f, 0.764160f, 0.753906f, 0.004612f, 0.013840f, 0.023483f, 0.033081f,
+ 0.042999f, 0.052490f, 0.063049f, 0.073303f, 0.083801f, 0.094238f, 0.105042f, 0.115967f, 0.127319f, 0.138062f, 0.149048f, 0.160645f,
+ 0.171875f, 0.183228f, 0.194946f, 0.206665f, 0.218384f, 0.230347f, 0.241699f, 0.253906f, 0.265869f, 0.277832f, 0.290039f, 0.301758f,
+ 0.314209f, 0.326660f, 0.339111f, 0.351074f, 0.363281f, 0.375977f, 0.388428f, 0.401123f, 0.413330f, 0.426270f, 0.439453f, 0.451904f,
+ 0.464111f, 0.478027f, 0.489746f, 0.503418f, 0.515625f, 0.529297f, 0.542480f, 0.556152f, 0.569336f, 0.582031f, 0.595215f, 0.608887f,
+ 0.622559f, 0.636230f, 0.649902f, 0.663574f, 0.677246f, 0.691895f, 0.821289f, 0.802246f, 0.785645f, 0.771484f, 0.758789f, 0.748047f,
+ 0.004345f, 0.012985f, 0.022156f, 0.030884f, 0.040802f, 0.050568f, 0.060303f, 0.069946f, 0.079956f, 0.090393f, 0.100403f, 0.111084f,
+ 0.120667f, 0.131714f, 0.142700f, 0.153198f, 0.164429f, 0.175659f, 0.186523f, 0.197876f, 0.208496f, 0.220337f, 0.231567f, 0.243286f,
+ 0.254639f, 0.266113f, 0.277832f, 0.289795f, 0.301758f, 0.313477f, 0.325439f, 0.337402f, 0.349609f, 0.361328f, 0.373779f, 0.385986f,
+ 0.398193f, 0.410889f, 0.423340f, 0.435059f, 0.447998f, 0.460205f, 0.473389f, 0.486084f, 0.499023f, 0.511230f, 0.524414f, 0.537109f,
+ 0.549805f, 0.563477f, 0.576172f, 0.589355f, 0.603027f, 0.616699f, 0.629883f, 0.644531f, 0.658691f, 0.670898f, 0.811035f, 0.792969f,
+ 0.777832f, 0.764648f, 0.752441f, 0.742676f, 0.004002f, 0.012718f, 0.021210f, 0.029877f, 0.039246f, 0.048431f, 0.057281f, 0.067078f,
+ 0.076538f, 0.086121f, 0.096008f, 0.105957f, 0.115540f, 0.125732f, 0.136475f, 0.146729f, 0.157227f, 0.167236f, 0.177979f, 0.189819f,
+ 0.200195f, 0.210693f, 0.221802f, 0.232788f, 0.243896f, 0.255127f, 0.266602f, 0.278320f, 0.289062f, 0.300293f, 0.312012f, 0.323975f,
+ 0.335449f, 0.347168f, 0.359131f, 0.371094f, 0.382812f, 0.394775f, 0.406982f, 0.419434f, 0.431152f, 0.443604f, 0.455566f, 0.468506f,
+ 0.481445f, 0.493408f, 0.506348f, 0.519043f, 0.531738f, 0.544922f, 0.558105f, 0.570801f, 0.583984f, 0.597168f, 0.610352f, 0.624512f,
+ 0.637695f, 0.651855f, 0.800293f, 0.785156f, 0.770508f, 0.757812f, 0.747070f, 0.737305f, 0.003967f, 0.011940f, 0.020203f, 0.028931f,
+ 0.037109f, 0.045898f, 0.054840f, 0.063477f, 0.073059f, 0.082214f, 0.090942f, 0.100647f, 0.110535f, 0.120178f, 0.129639f, 0.139648f,
+ 0.149902f, 0.160156f, 0.170044f, 0.180786f, 0.190674f, 0.201416f, 0.211792f, 0.222412f, 0.233521f, 0.244751f, 0.255615f, 0.266113f,
+ 0.276855f, 0.288574f, 0.299561f, 0.311279f, 0.322266f, 0.333984f, 0.344727f, 0.356934f, 0.368164f, 0.379395f, 0.390869f, 0.403076f,
+ 0.415283f, 0.427246f, 0.439453f, 0.451172f, 0.464111f, 0.476807f, 0.488281f, 0.500977f, 0.513672f, 0.526367f, 0.538574f, 0.551758f,
+ 0.564453f, 0.577637f, 0.590820f, 0.604492f, 0.618164f, 0.631836f, 0.790039f, 0.775879f, 0.763184f, 0.750977f, 0.740723f, 0.731445f,
+ 0.003679f, 0.011749f, 0.019135f, 0.027237f, 0.035431f, 0.043884f, 0.052399f, 0.060577f, 0.069153f, 0.077881f, 0.086731f, 0.095947f,
+ 0.104797f, 0.114380f, 0.123535f, 0.133057f, 0.142700f, 0.152588f, 0.162231f, 0.171753f, 0.182129f, 0.192261f, 0.202026f, 0.212524f,
+ 0.222900f, 0.233643f, 0.243896f, 0.254395f, 0.264893f, 0.276123f, 0.286621f, 0.297119f, 0.308105f, 0.319336f, 0.331299f, 0.341553f,
+ 0.353027f, 0.364258f, 0.375977f, 0.387451f, 0.399414f, 0.410645f, 0.422607f, 0.434814f, 0.445801f, 0.458984f, 0.470703f, 0.482910f,
+ 0.495361f, 0.508301f, 0.520020f, 0.532227f, 0.545410f, 0.558594f, 0.570801f, 0.584961f, 0.597656f, 0.611816f, 0.778809f, 0.768066f,
+ 0.754883f, 0.743652f, 0.733887f, 0.725098f, 0.003525f, 0.010956f, 0.018433f, 0.026260f, 0.033295f, 0.041870f, 0.049377f, 0.057709f,
+ 0.065735f, 0.074463f, 0.082764f, 0.091736f, 0.099976f, 0.108582f, 0.118103f, 0.126465f, 0.135742f, 0.144775f, 0.154175f, 0.164307f,
+ 0.173218f, 0.182983f, 0.192505f, 0.202759f, 0.212646f, 0.221924f, 0.232910f, 0.242188f, 0.252930f, 0.262939f, 0.273926f, 0.284180f,
+ 0.294922f, 0.305420f, 0.316162f, 0.327637f, 0.338867f, 0.349609f, 0.361084f, 0.371826f, 0.382812f, 0.395020f, 0.406494f, 0.417725f,
+ 0.429688f, 0.441406f, 0.452637f, 0.465088f, 0.477783f, 0.489258f, 0.501953f, 0.514160f, 0.527344f, 0.539062f, 0.551758f, 0.564941f,
+ 0.578125f, 0.591797f, 0.768555f, 0.759277f, 0.748047f, 0.736816f, 0.728027f, 0.718750f, 0.003363f, 0.010353f, 0.017548f, 0.024765f,
+ 0.032196f, 0.039673f, 0.046936f, 0.054565f, 0.062561f, 0.070496f, 0.078308f, 0.086731f, 0.094910f, 0.103333f, 0.111633f, 0.120422f,
+ 0.129150f, 0.137695f, 0.146973f, 0.155762f, 0.164673f, 0.173950f, 0.183228f, 0.193359f, 0.201782f, 0.212036f, 0.221436f, 0.231323f,
+ 0.241699f, 0.251221f, 0.261719f, 0.271729f, 0.281494f, 0.291992f, 0.302734f, 0.312988f, 0.323730f, 0.334961f, 0.345459f, 0.357666f,
+ 0.367432f, 0.378662f, 0.389893f, 0.401855f, 0.412842f, 0.424316f, 0.435791f, 0.447266f, 0.459473f, 0.471436f, 0.482910f, 0.495605f,
+ 0.507324f, 0.520508f, 0.533203f, 0.545898f, 0.558594f, 0.570801f, 0.757812f, 0.750488f, 0.740234f, 0.729980f, 0.720703f, 0.712402f,
+ 0.003254f, 0.010048f, 0.016815f, 0.023453f, 0.030609f, 0.037537f, 0.044617f, 0.051971f, 0.059265f, 0.066833f, 0.074280f, 0.082153f,
+ 0.089905f, 0.097717f, 0.106018f, 0.113770f, 0.122131f, 0.131104f, 0.139282f, 0.147705f, 0.155762f, 0.165161f, 0.173950f, 0.183228f,
+ 0.192139f, 0.200928f, 0.210693f, 0.220093f, 0.229736f, 0.239258f, 0.248657f, 0.259277f, 0.268799f, 0.279053f, 0.288574f, 0.299561f,
+ 0.309814f, 0.319580f, 0.330322f, 0.340820f, 0.352783f, 0.362549f, 0.374023f, 0.385010f, 0.395752f, 0.407471f, 0.418701f, 0.429688f,
+ 0.441650f, 0.453125f, 0.465088f, 0.477539f, 0.489014f, 0.500977f, 0.513184f, 0.526855f, 0.539062f, 0.552246f, 0.747559f, 0.741699f,
+ 0.731934f, 0.722656f, 0.714355f, 0.707031f, 0.003345f, 0.009262f, 0.015900f, 0.022614f, 0.029282f, 0.035522f, 0.042633f, 0.048981f,
+ 0.056000f, 0.063110f, 0.070801f, 0.077454f, 0.084839f, 0.092590f, 0.100281f, 0.107849f, 0.116089f, 0.123169f, 0.131348f, 0.139648f,
+ 0.148193f, 0.156616f, 0.164795f, 0.173584f, 0.182617f, 0.191284f, 0.200073f, 0.208740f, 0.218140f, 0.227417f, 0.236694f, 0.246338f,
+ 0.255859f, 0.265381f, 0.275146f, 0.285889f, 0.294922f, 0.305420f, 0.315918f, 0.325928f, 0.336670f, 0.347412f, 0.358154f, 0.368652f,
+ 0.378662f, 0.390381f, 0.402100f, 0.412842f, 0.424316f, 0.435059f, 0.447021f, 0.458984f, 0.470459f, 0.482422f, 0.494873f, 0.508301f,
+ 0.520020f, 0.532227f, 0.737305f, 0.732910f, 0.723633f, 0.715820f, 0.708008f, 0.700195f, 0.003195f, 0.009010f, 0.015137f, 0.021225f,
+ 0.027466f, 0.033844f, 0.040161f, 0.046417f, 0.053497f, 0.059875f, 0.066711f, 0.073425f, 0.080505f, 0.087280f, 0.094788f, 0.102173f,
+ 0.109070f, 0.117004f, 0.124634f, 0.132446f, 0.139893f, 0.147705f, 0.155884f, 0.163940f, 0.172729f, 0.180908f, 0.189697f, 0.198242f,
+ 0.206665f, 0.215820f, 0.225220f, 0.233765f, 0.243408f, 0.251953f, 0.262207f, 0.271484f, 0.281494f, 0.291260f, 0.300537f, 0.311035f,
+ 0.320801f, 0.332520f, 0.341797f, 0.352051f, 0.362305f, 0.373535f, 0.384521f, 0.395264f, 0.406494f, 0.417480f, 0.429443f, 0.440430f,
+ 0.451904f, 0.463867f, 0.476074f, 0.487793f, 0.499268f, 0.513184f, 0.726562f, 0.723633f, 0.716309f, 0.708496f, 0.700684f, 0.694336f,
+ 0.002859f, 0.008507f, 0.014366f, 0.020203f, 0.026123f, 0.031891f, 0.038025f, 0.044281f, 0.050354f, 0.056519f, 0.062683f, 0.069275f,
+ 0.075195f, 0.082458f, 0.088806f, 0.095947f, 0.102783f, 0.110046f, 0.117065f, 0.124878f, 0.132080f, 0.139282f, 0.146851f, 0.154907f,
+ 0.162598f, 0.171265f, 0.178833f, 0.187500f, 0.195435f, 0.204590f, 0.213013f, 0.221680f, 0.231079f, 0.239502f, 0.248047f, 0.258301f,
+ 0.267334f, 0.277100f, 0.286133f, 0.296387f, 0.306641f, 0.316162f, 0.326416f, 0.336426f, 0.346924f, 0.357422f, 0.367188f, 0.378418f,
+ 0.389160f, 0.400391f, 0.411865f, 0.422852f, 0.433594f, 0.445557f, 0.457520f, 0.468994f, 0.481445f, 0.493408f, 0.715332f, 0.715332f,
+ 0.708984f, 0.700684f, 0.693848f, 0.687988f, 0.002701f, 0.008080f, 0.013718f, 0.019058f, 0.024582f, 0.030197f, 0.035675f, 0.041748f,
+ 0.047302f, 0.053589f, 0.059082f, 0.065308f, 0.071777f, 0.077576f, 0.084106f, 0.090332f, 0.097107f, 0.103577f, 0.110046f, 0.117493f,
+ 0.124146f, 0.131470f, 0.138550f, 0.145508f, 0.153564f, 0.161377f, 0.169067f, 0.176880f, 0.184814f, 0.192627f, 0.201294f, 0.209717f,
+ 0.218140f, 0.226929f, 0.235229f, 0.245117f, 0.253418f, 0.262939f, 0.272705f, 0.281738f, 0.290771f, 0.300781f, 0.310791f, 0.321289f,
+ 0.330566f, 0.341064f, 0.351562f, 0.361572f, 0.372559f, 0.382568f, 0.393066f, 0.405273f, 0.415771f, 0.426758f, 0.438721f, 0.450439f,
+ 0.461670f, 0.474121f, 0.704102f, 0.706543f, 0.700195f, 0.693359f, 0.687012f, 0.681152f, 0.002546f, 0.007771f, 0.012985f, 0.017975f,
+ 0.023392f, 0.028976f, 0.034180f, 0.039368f, 0.044556f, 0.050110f, 0.055847f, 0.061218f, 0.066895f, 0.072815f, 0.078674f, 0.085083f,
+ 0.091309f, 0.097168f, 0.103516f, 0.110107f, 0.116821f, 0.123413f, 0.130371f, 0.137329f, 0.144165f, 0.151733f, 0.158813f, 0.166382f,
+ 0.174438f, 0.182129f, 0.190063f, 0.197510f, 0.206055f, 0.214355f, 0.222778f, 0.231812f, 0.240723f, 0.249023f, 0.258789f, 0.267578f,
+ 0.276855f, 0.285889f, 0.295654f, 0.305420f, 0.315430f, 0.324463f, 0.334961f, 0.345215f, 0.354492f, 0.365234f, 0.376221f, 0.387451f,
+ 0.398926f, 0.409424f, 0.419678f, 0.432129f, 0.443848f, 0.455566f, 0.693848f, 0.697266f, 0.691895f, 0.686523f, 0.680176f, 0.674805f,
+ 0.002542f, 0.007271f, 0.012337f, 0.017181f, 0.021744f, 0.026840f, 0.031555f, 0.037231f, 0.042236f, 0.046906f, 0.051941f, 0.057709f,
+ 0.063049f, 0.068542f, 0.073853f, 0.079712f, 0.085266f, 0.091064f, 0.096985f, 0.103027f, 0.109009f, 0.115417f, 0.122192f, 0.128540f,
+ 0.135132f, 0.141846f, 0.148926f, 0.156250f, 0.163696f, 0.171387f, 0.178223f, 0.186035f, 0.194580f, 0.202271f, 0.210327f, 0.218994f,
+ 0.227173f, 0.235596f, 0.244385f, 0.252930f, 0.262451f, 0.271240f, 0.280762f, 0.290771f, 0.299805f, 0.309082f, 0.318359f, 0.329102f,
+ 0.338623f, 0.348633f, 0.358643f, 0.370117f, 0.379639f, 0.390869f, 0.401611f, 0.413330f, 0.425293f, 0.436523f, 0.682129f, 0.688477f,
+ 0.684082f, 0.678711f, 0.673340f, 0.667969f, 0.002300f, 0.007076f, 0.011505f, 0.016251f, 0.020401f, 0.025665f, 0.029816f, 0.034790f,
+ 0.039368f, 0.044159f, 0.048798f, 0.053955f, 0.059174f, 0.064148f, 0.069153f, 0.074463f, 0.079346f, 0.085266f, 0.090759f, 0.096191f,
+ 0.102112f, 0.108032f, 0.114075f, 0.120117f, 0.126587f, 0.133057f, 0.139648f, 0.146240f, 0.153442f, 0.160400f, 0.167725f, 0.174683f,
+ 0.182739f, 0.190308f, 0.198120f, 0.206177f, 0.214355f, 0.222656f, 0.230713f, 0.239258f, 0.248413f, 0.257080f, 0.265869f, 0.274658f,
+ 0.284424f, 0.292725f, 0.302490f, 0.313232f, 0.321777f, 0.331787f, 0.341797f, 0.352295f, 0.363281f, 0.373535f, 0.383545f, 0.395264f,
+ 0.405762f, 0.416992f, 0.671387f, 0.679688f, 0.675293f, 0.670898f, 0.666016f, 0.661133f, 0.002104f, 0.006474f, 0.010506f, 0.015099f,
+ 0.018875f, 0.023911f, 0.028534f, 0.032715f, 0.036652f, 0.041290f, 0.046021f, 0.050171f, 0.054535f, 0.059570f, 0.064575f, 0.069458f,
+ 0.074341f, 0.079346f, 0.084351f, 0.089844f, 0.095032f, 0.100830f, 0.106628f, 0.112122f, 0.117859f, 0.124084f, 0.130249f, 0.136841f,
+ 0.143188f, 0.149780f, 0.157349f, 0.163940f, 0.171021f, 0.178345f, 0.186279f, 0.193848f, 0.201172f, 0.209717f, 0.217529f, 0.225464f,
+ 0.233765f, 0.242676f, 0.251221f, 0.260254f, 0.268311f, 0.278076f, 0.287109f, 0.296143f, 0.305908f, 0.315674f, 0.325195f, 0.335449f,
+ 0.344971f, 0.355469f, 0.365967f, 0.377441f, 0.387939f, 0.398193f, 0.660645f, 0.670410f, 0.667969f, 0.663086f, 0.659180f, 0.654785f,
+ 0.002085f, 0.006306f, 0.010506f, 0.014107f, 0.018448f, 0.022293f, 0.026215f, 0.029953f, 0.034515f, 0.038391f, 0.042786f, 0.046844f,
+ 0.051361f, 0.055573f, 0.059784f, 0.064331f, 0.068970f, 0.073425f, 0.078430f, 0.083313f, 0.088318f, 0.093567f, 0.098816f, 0.104126f,
+ 0.109924f, 0.115662f, 0.121521f, 0.127197f, 0.133545f, 0.139771f, 0.146729f, 0.153076f, 0.160278f, 0.166992f, 0.174316f, 0.181274f,
+ 0.188965f, 0.196045f, 0.204468f, 0.212036f, 0.220459f, 0.228638f, 0.237183f, 0.245483f, 0.254150f, 0.262451f, 0.271484f, 0.281250f,
+ 0.290283f, 0.299561f, 0.308350f, 0.318115f, 0.328369f, 0.337158f, 0.349121f, 0.358887f, 0.370117f, 0.380615f, 0.649414f, 0.661133f,
+ 0.659668f, 0.655762f, 0.651855f, 0.647949f, 0.001922f, 0.005867f, 0.009399f, 0.013565f, 0.017380f, 0.020859f, 0.024551f, 0.028442f,
+ 0.032318f, 0.035980f, 0.039551f, 0.043488f, 0.047333f, 0.051239f, 0.055573f, 0.059875f, 0.063660f, 0.067810f, 0.072876f, 0.077087f,
+ 0.081726f, 0.086304f, 0.091370f, 0.096863f, 0.101746f, 0.107483f, 0.112732f, 0.117920f, 0.124329f, 0.130005f, 0.136108f, 0.142822f,
+ 0.149170f, 0.155396f, 0.162598f, 0.169434f, 0.176636f, 0.183838f, 0.191772f, 0.198975f, 0.206665f, 0.214478f, 0.222290f, 0.230835f,
+ 0.239258f, 0.247803f, 0.256836f, 0.264893f, 0.274414f, 0.283203f, 0.292725f, 0.301758f, 0.311035f, 0.321289f, 0.332275f, 0.340820f,
+ 0.351562f, 0.363037f, 0.637695f, 0.652832f, 0.651367f, 0.647949f, 0.644531f, 0.641602f, 0.002052f, 0.005253f, 0.009117f, 0.012482f,
+ 0.016113f, 0.019302f, 0.022842f, 0.026230f, 0.029831f, 0.033447f, 0.036682f, 0.040588f, 0.044189f, 0.047333f, 0.051178f, 0.055267f,
+ 0.058807f, 0.062683f, 0.067200f, 0.070984f, 0.075195f, 0.079895f, 0.084534f, 0.088806f, 0.093933f, 0.098999f, 0.104309f, 0.109619f,
+ 0.114807f, 0.120422f, 0.126587f, 0.132080f, 0.138550f, 0.144775f, 0.151245f, 0.157837f, 0.164551f, 0.171387f, 0.178467f, 0.186157f,
+ 0.193359f, 0.201294f, 0.208740f, 0.216797f, 0.224854f, 0.233398f, 0.241211f, 0.250000f, 0.258545f, 0.267822f, 0.276855f, 0.286133f,
+ 0.295410f, 0.304932f, 0.314697f, 0.324463f, 0.334229f, 0.344238f, 0.626953f, 0.642578f, 0.643066f, 0.641113f, 0.637695f, 0.634277f,
+ 0.001711f, 0.005424f, 0.008347f, 0.012024f, 0.014977f, 0.018066f, 0.021500f, 0.024399f, 0.027756f, 0.030869f, 0.034058f, 0.037048f,
+ 0.040558f, 0.044006f, 0.046906f, 0.050690f, 0.054169f, 0.057983f, 0.061584f, 0.065247f, 0.069336f, 0.073425f, 0.077576f, 0.082092f,
+ 0.086670f, 0.091064f, 0.095886f, 0.101196f, 0.105957f, 0.111267f, 0.116943f, 0.122559f, 0.128174f, 0.133789f, 0.140259f, 0.146118f,
+ 0.153076f, 0.159424f, 0.166016f, 0.173462f, 0.180542f, 0.187744f, 0.195435f, 0.203003f, 0.209961f, 0.218994f, 0.226562f, 0.234619f,
+ 0.243286f, 0.251709f, 0.260742f, 0.269531f, 0.277832f, 0.287354f, 0.297363f, 0.306885f, 0.316406f, 0.326660f, 0.615234f, 0.633789f,
+ 0.634277f, 0.632812f, 0.630371f, 0.626953f, 0.001721f, 0.004829f, 0.008034f, 0.010857f, 0.013893f, 0.016953f, 0.019806f, 0.022705f,
+ 0.025589f, 0.028793f, 0.031616f, 0.034180f, 0.036926f, 0.039978f, 0.043213f, 0.046356f, 0.049744f, 0.052887f, 0.056305f, 0.059906f,
+ 0.063416f, 0.067322f, 0.070862f, 0.075134f, 0.079285f, 0.083435f, 0.088074f, 0.092712f, 0.097534f, 0.102173f, 0.107544f, 0.112305f,
+ 0.118225f, 0.123657f, 0.129272f, 0.135376f, 0.141602f, 0.147705f, 0.153931f, 0.160889f, 0.167847f, 0.174683f, 0.181885f, 0.189209f,
+ 0.196533f, 0.204224f, 0.212524f, 0.219727f, 0.228271f, 0.236572f, 0.245483f, 0.253418f, 0.261719f, 0.270996f, 0.280029f, 0.289307f,
+ 0.300537f, 0.309326f, 0.604004f, 0.625000f, 0.626953f, 0.625000f, 0.622559f, 0.620117f, 0.001624f, 0.004730f, 0.007412f, 0.010300f,
+ 0.013199f, 0.015717f, 0.018448f, 0.020935f, 0.023163f, 0.026138f, 0.028687f, 0.031204f, 0.033875f, 0.036743f, 0.039825f, 0.042389f,
+ 0.045166f, 0.048523f, 0.051422f, 0.054535f, 0.057953f, 0.061249f, 0.064880f, 0.068542f, 0.072388f, 0.076355f, 0.080505f, 0.084534f,
+ 0.089294f, 0.093750f, 0.098389f, 0.103210f, 0.108337f, 0.113647f, 0.118896f, 0.124817f, 0.130737f, 0.135986f, 0.142212f, 0.148560f,
+ 0.155151f, 0.162109f, 0.168579f, 0.175415f, 0.183105f, 0.190552f, 0.197998f, 0.205322f, 0.213623f, 0.221436f, 0.229370f, 0.237915f,
+ 0.246216f, 0.254883f, 0.264160f, 0.273438f, 0.282471f, 0.292236f, 0.593262f, 0.615723f, 0.618164f, 0.617188f, 0.615234f, 0.612793f,
+ 0.001355f, 0.004463f, 0.007061f, 0.009506f, 0.011612f, 0.014381f, 0.016830f, 0.019394f, 0.021576f, 0.023697f, 0.026428f, 0.028778f,
+ 0.030975f, 0.033386f, 0.035950f, 0.038513f, 0.041260f, 0.044067f, 0.046967f, 0.049622f, 0.052612f, 0.055847f, 0.059052f, 0.062164f,
+ 0.065918f, 0.069397f, 0.073242f, 0.077271f, 0.081055f, 0.085327f, 0.089661f, 0.094177f, 0.098877f, 0.103455f, 0.108582f, 0.113647f,
+ 0.119812f, 0.125000f, 0.130981f, 0.137085f, 0.142944f, 0.149414f, 0.156006f, 0.162354f, 0.169434f, 0.176514f, 0.183716f, 0.191284f,
+ 0.198975f, 0.206421f, 0.214844f, 0.222412f, 0.231323f, 0.238647f, 0.247437f, 0.256592f, 0.265625f, 0.276367f, 0.581055f, 0.606445f,
+ 0.609863f, 0.608887f, 0.607910f, 0.606445f, 0.001413f, 0.004128f, 0.006180f, 0.008781f, 0.010994f, 0.013496f, 0.015427f, 0.017654f,
+ 0.019684f, 0.021881f, 0.024139f, 0.025879f, 0.028137f, 0.030334f, 0.032471f, 0.034821f, 0.037354f, 0.039642f, 0.042236f, 0.044708f,
+ 0.047394f, 0.050079f, 0.053223f, 0.056244f, 0.059479f, 0.062622f, 0.066223f, 0.069946f, 0.073608f, 0.077209f, 0.081604f, 0.085632f,
+ 0.089722f, 0.094360f, 0.098999f, 0.103943f, 0.108826f, 0.114319f, 0.119568f, 0.125122f, 0.131104f, 0.137085f, 0.143433f, 0.150024f,
+ 0.156494f, 0.163330f, 0.170044f, 0.177490f, 0.184326f, 0.191895f, 0.199707f, 0.207764f, 0.215698f, 0.223755f, 0.231812f, 0.240845f,
+ 0.249756f, 0.258789f, 0.568848f, 0.598145f, 0.601562f, 0.600586f, 0.600586f, 0.599121f, 0.001182f, 0.003773f, 0.005970f, 0.008293f,
+ 0.010277f, 0.012512f, 0.014030f, 0.016129f, 0.017929f, 0.019791f, 0.021683f, 0.023590f, 0.025452f, 0.027328f, 0.029404f, 0.031677f,
+ 0.033539f, 0.035583f, 0.037903f, 0.040314f, 0.042877f, 0.045319f, 0.048126f, 0.050690f, 0.053436f, 0.056519f, 0.059723f, 0.062744f,
+ 0.066284f, 0.069702f, 0.073608f, 0.077209f, 0.081055f, 0.085754f, 0.089783f, 0.094421f, 0.099060f, 0.103821f, 0.109192f, 0.114563f,
+ 0.119934f, 0.125488f, 0.131104f, 0.137695f, 0.144043f, 0.149780f, 0.156738f, 0.163940f, 0.170654f, 0.177856f, 0.185181f, 0.192871f,
+ 0.200439f, 0.208740f, 0.216675f, 0.225342f, 0.233521f, 0.242554f, 0.557617f, 0.587891f, 0.592285f, 0.592773f, 0.592285f, 0.592285f,
+ 0.001198f, 0.003677f, 0.005547f, 0.007561f, 0.009468f, 0.011253f, 0.012833f, 0.014465f, 0.016205f, 0.017792f, 0.019394f, 0.021240f,
+ 0.022751f, 0.024475f, 0.026260f, 0.028015f, 0.030136f, 0.031708f, 0.034088f, 0.036102f, 0.038361f, 0.040497f, 0.042816f, 0.045288f,
+ 0.047882f, 0.050476f, 0.053284f, 0.056183f, 0.059174f, 0.062500f, 0.065796f, 0.069153f, 0.072998f, 0.076904f, 0.080994f, 0.085083f,
+ 0.089478f, 0.094116f, 0.098633f, 0.103394f, 0.108704f, 0.113953f, 0.119934f, 0.125366f, 0.131348f, 0.137329f, 0.143555f, 0.150391f,
+ 0.157227f, 0.163818f, 0.170776f, 0.178467f, 0.185791f, 0.193359f, 0.201538f, 0.209717f, 0.218018f, 0.226807f, 0.544922f, 0.578613f,
+ 0.583984f, 0.584961f, 0.585449f, 0.584473f, 0.001067f, 0.003101f, 0.004974f, 0.006855f, 0.008522f, 0.009949f, 0.011635f, 0.012985f,
+ 0.014595f, 0.016052f, 0.017685f, 0.019012f, 0.020264f, 0.021851f, 0.023346f, 0.025146f, 0.026688f, 0.028336f, 0.030304f, 0.031860f,
+ 0.034119f, 0.035889f, 0.038025f, 0.040283f, 0.042450f, 0.044952f, 0.047302f, 0.050049f, 0.052765f, 0.055908f, 0.058594f, 0.061859f,
+ 0.064880f, 0.068481f, 0.072327f, 0.076172f, 0.080200f, 0.084290f, 0.088684f, 0.093262f, 0.098145f, 0.102905f, 0.108337f, 0.113708f,
+ 0.119080f, 0.125000f, 0.131348f, 0.137329f, 0.143921f, 0.150391f, 0.157593f, 0.164551f, 0.171753f, 0.179077f, 0.186768f, 0.194702f,
+ 0.203003f, 0.210815f, 0.534180f, 0.569336f, 0.575684f, 0.577637f, 0.577637f, 0.577148f, 0.001196f, 0.003178f, 0.004601f, 0.006241f,
+ 0.007782f, 0.009262f, 0.010391f, 0.011795f, 0.012955f, 0.014198f, 0.015518f, 0.016785f, 0.018097f, 0.019409f, 0.020782f, 0.022247f,
+ 0.023544f, 0.025269f, 0.026749f, 0.028152f, 0.030045f, 0.031555f, 0.033630f, 0.035645f, 0.037567f, 0.039642f, 0.041992f, 0.044281f,
+ 0.046692f, 0.049042f, 0.052094f, 0.054779f, 0.057831f, 0.060760f, 0.064209f, 0.067627f, 0.071228f, 0.075256f, 0.079224f, 0.083557f,
+ 0.087891f, 0.092468f, 0.097168f, 0.102356f, 0.107605f, 0.113098f, 0.119019f, 0.124878f, 0.130859f, 0.137451f, 0.144287f, 0.150635f,
+ 0.157471f, 0.164917f, 0.171997f, 0.179932f, 0.187378f, 0.196899f, 0.521973f, 0.560547f, 0.566895f, 0.569824f, 0.570312f, 0.568848f,
+ 0.001242f, 0.002674f, 0.004421f, 0.005573f, 0.006882f, 0.008354f, 0.009491f, 0.010559f, 0.011406f, 0.012695f, 0.013893f, 0.014908f,
+ 0.015854f, 0.017044f, 0.018234f, 0.019501f, 0.020752f, 0.022003f, 0.023254f, 0.024689f, 0.026154f, 0.027802f, 0.029434f, 0.031113f,
+ 0.032898f, 0.034668f, 0.036774f, 0.038910f, 0.040802f, 0.043030f, 0.045593f, 0.048065f, 0.050873f, 0.053680f, 0.056458f, 0.059692f,
+ 0.062866f, 0.066467f, 0.069946f, 0.074036f, 0.077942f, 0.082275f, 0.086731f, 0.091614f, 0.096313f, 0.101562f, 0.106934f, 0.112671f,
+ 0.118591f, 0.124634f, 0.130859f, 0.137207f, 0.144043f, 0.151123f, 0.157593f, 0.165283f, 0.173218f, 0.180664f, 0.510254f, 0.550781f,
+ 0.558105f, 0.561035f, 0.562012f, 0.562012f, 0.000842f, 0.002552f, 0.003769f, 0.005333f, 0.006149f, 0.007298f, 0.008362f, 0.009224f,
+ 0.010254f, 0.011230f, 0.012108f, 0.013092f, 0.014000f, 0.014992f, 0.016006f, 0.016953f, 0.017990f, 0.019196f, 0.020142f, 0.021622f,
+ 0.022827f, 0.024216f, 0.025513f, 0.026993f, 0.028564f, 0.030212f, 0.032013f, 0.033813f, 0.035706f, 0.037598f, 0.039703f, 0.041840f,
+ 0.044159f, 0.046539f, 0.049347f, 0.052155f, 0.055084f, 0.058228f, 0.061554f, 0.065002f, 0.068909f, 0.072693f, 0.076599f, 0.081238f,
+ 0.085388f, 0.090515f, 0.095764f, 0.100891f, 0.106689f, 0.112366f, 0.118103f, 0.124634f, 0.130859f, 0.137573f, 0.144287f, 0.151855f,
+ 0.158447f, 0.166260f, 0.498535f, 0.541992f, 0.549805f, 0.553711f, 0.554199f, 0.554688f, 0.000874f, 0.002186f, 0.003445f, 0.004807f,
+ 0.005562f, 0.006607f, 0.007378f, 0.008102f, 0.008919f, 0.009666f, 0.010513f, 0.011131f, 0.012039f, 0.012848f, 0.013779f, 0.014671f,
+ 0.015465f, 0.016464f, 0.017517f, 0.018585f, 0.019730f, 0.020798f, 0.022018f, 0.023300f, 0.024612f, 0.026093f, 0.027374f, 0.029022f,
+ 0.030624f, 0.032440f, 0.034180f, 0.036285f, 0.038116f, 0.040344f, 0.042725f, 0.045349f, 0.047913f, 0.050476f, 0.053406f, 0.056488f,
+ 0.059998f, 0.063354f, 0.067383f, 0.071289f, 0.075562f, 0.079834f, 0.084656f, 0.089478f, 0.094849f, 0.100342f, 0.106140f, 0.111877f,
+ 0.118042f, 0.124573f, 0.130981f, 0.137451f, 0.144653f, 0.152588f, 0.486816f, 0.531738f, 0.541016f, 0.545410f, 0.547363f, 0.546875f,
+ 0.000667f, 0.002001f, 0.003244f, 0.003895f, 0.004936f, 0.005608f, 0.006477f, 0.006901f, 0.007648f, 0.008354f, 0.009132f, 0.009766f,
+ 0.010490f, 0.011177f, 0.011780f, 0.012543f, 0.013420f, 0.014084f, 0.015045f, 0.015961f, 0.016876f, 0.017822f, 0.018768f, 0.019958f,
+ 0.021255f, 0.022232f, 0.023560f, 0.024780f, 0.026108f, 0.027634f, 0.029221f, 0.030762f, 0.032684f, 0.034576f, 0.036621f, 0.038605f,
+ 0.040985f, 0.043488f, 0.046021f, 0.049042f, 0.051727f, 0.054901f, 0.058441f, 0.061981f, 0.065552f, 0.069885f, 0.074097f, 0.078857f,
+ 0.083923f, 0.088623f, 0.094360f, 0.099854f, 0.105957f, 0.111694f, 0.118164f, 0.124817f, 0.131836f, 0.138794f, 0.474365f, 0.522949f,
+ 0.532227f, 0.536621f, 0.538574f, 0.539062f, 0.000876f, 0.002020f, 0.002857f, 0.003855f, 0.004436f, 0.005009f, 0.005482f, 0.006130f,
+ 0.006588f, 0.007084f, 0.007656f, 0.008286f, 0.008949f, 0.009506f, 0.010025f, 0.010803f, 0.011444f, 0.012047f, 0.012802f, 0.013512f,
+ 0.014305f, 0.015282f, 0.016052f, 0.016846f, 0.017914f, 0.018829f, 0.019882f, 0.021027f, 0.022232f, 0.023453f, 0.024689f, 0.026169f,
+ 0.027573f, 0.029327f, 0.031036f, 0.032806f, 0.034882f, 0.036743f, 0.039032f, 0.041626f, 0.044312f, 0.046936f, 0.050018f, 0.053253f,
+ 0.056610f, 0.060272f, 0.064392f, 0.068542f, 0.072937f, 0.078003f, 0.082886f, 0.088318f, 0.093933f, 0.099670f, 0.106140f, 0.112000f,
+ 0.118713f, 0.125732f, 0.463135f, 0.513672f, 0.524414f, 0.528809f, 0.530762f, 0.532227f, 0.000573f, 0.001698f, 0.002670f, 0.003082f,
+ 0.003735f, 0.004318f, 0.004673f, 0.005161f, 0.005779f, 0.006203f, 0.006565f, 0.007015f, 0.007591f, 0.007965f, 0.008583f, 0.009094f,
+ 0.009491f, 0.010239f, 0.010780f, 0.011353f, 0.012047f, 0.012787f, 0.013504f, 0.014206f, 0.015060f, 0.015915f, 0.016708f, 0.017685f,
+ 0.018677f, 0.019653f, 0.020828f, 0.021866f, 0.023224f, 0.024445f, 0.025818f, 0.027557f, 0.029114f, 0.030991f, 0.032928f, 0.035034f,
+ 0.037201f, 0.039581f, 0.042328f, 0.045166f, 0.048157f, 0.051392f, 0.054962f, 0.058685f, 0.062988f, 0.067444f, 0.072021f, 0.077148f,
+ 0.082520f, 0.088196f, 0.093750f, 0.100403f, 0.106201f, 0.112976f, 0.450928f, 0.503906f, 0.515137f, 0.520020f, 0.522949f, 0.524414f,
+ 0.000643f, 0.001637f, 0.002197f, 0.002800f, 0.003376f, 0.003613f, 0.003914f, 0.004391f, 0.004742f, 0.005150f, 0.005466f, 0.005924f,
+ 0.006344f, 0.006645f, 0.007046f, 0.007591f, 0.008118f, 0.008560f, 0.008934f, 0.009529f, 0.010147f, 0.010651f, 0.011276f, 0.011787f,
+ 0.012543f, 0.013229f, 0.013916f, 0.014740f, 0.015564f, 0.016388f, 0.017258f, 0.018188f, 0.019257f, 0.020355f, 0.021729f, 0.022766f,
+ 0.024277f, 0.025696f, 0.027237f, 0.029022f, 0.030945f, 0.033020f, 0.035248f, 0.037689f, 0.040405f, 0.043182f, 0.046295f, 0.049866f,
+ 0.053528f, 0.057526f, 0.061920f, 0.066284f, 0.071716f, 0.077209f, 0.082703f, 0.088196f, 0.094177f, 0.101074f, 0.438965f, 0.494629f,
+ 0.507324f, 0.512207f, 0.515137f, 0.516113f, 0.000484f, 0.001272f, 0.001968f, 0.002327f, 0.002573f, 0.003054f, 0.003338f, 0.003660f,
+ 0.003906f, 0.004303f, 0.004658f, 0.004921f, 0.005222f, 0.005547f, 0.005878f, 0.006290f, 0.006542f, 0.007015f, 0.007442f, 0.007851f,
+ 0.008339f, 0.008713f, 0.009247f, 0.009811f, 0.010345f, 0.010849f, 0.011490f, 0.012123f, 0.012733f, 0.013428f, 0.014183f, 0.014961f,
+ 0.015839f, 0.016815f, 0.017731f, 0.018768f, 0.019821f, 0.021072f, 0.022385f, 0.023727f, 0.025345f, 0.027084f, 0.028946f, 0.030914f,
+ 0.033295f, 0.035614f, 0.038513f, 0.041473f, 0.044678f, 0.048462f, 0.052338f, 0.056671f, 0.061310f, 0.066101f, 0.071533f, 0.077148f,
+ 0.083069f, 0.089172f, 0.427246f, 0.485352f, 0.498535f, 0.503906f, 0.508301f, 0.509766f, 0.000416f, 0.001121f, 0.001410f, 0.001959f,
+ 0.002159f, 0.002558f, 0.002724f, 0.002939f, 0.003220f, 0.003447f, 0.003733f, 0.003944f, 0.004219f, 0.004578f, 0.004810f, 0.005100f,
+ 0.005402f, 0.005783f, 0.006077f, 0.006382f, 0.006729f, 0.007141f, 0.007526f, 0.007965f, 0.008354f, 0.008858f, 0.009300f, 0.009789f,
+ 0.010452f, 0.010986f, 0.011658f, 0.012131f, 0.012833f, 0.013702f, 0.014435f, 0.015266f, 0.016113f, 0.017136f, 0.018143f, 0.019241f,
+ 0.020493f, 0.021820f, 0.023346f, 0.025085f, 0.027023f, 0.028976f, 0.031174f, 0.033966f, 0.036743f, 0.039856f, 0.043396f, 0.047180f,
+ 0.051605f, 0.056152f, 0.061127f, 0.066284f, 0.072021f, 0.078247f, 0.415283f, 0.475586f, 0.490234f, 0.496338f, 0.499756f, 0.501953f,
+ 0.000493f, 0.001126f, 0.001391f, 0.001574f, 0.001786f, 0.002073f, 0.002188f, 0.002417f, 0.002657f, 0.002785f, 0.002964f, 0.003189f,
+ 0.003384f, 0.003687f, 0.003859f, 0.004124f, 0.004330f, 0.004555f, 0.004890f, 0.005119f, 0.005451f, 0.005749f, 0.006054f, 0.006348f,
+ 0.006683f, 0.007050f, 0.007458f, 0.007889f, 0.008339f, 0.008751f, 0.009323f, 0.009766f, 0.010353f, 0.010887f, 0.011520f, 0.012192f,
+ 0.012932f, 0.013748f, 0.014542f, 0.015434f, 0.016434f, 0.017471f, 0.018723f, 0.019989f, 0.021500f, 0.023117f, 0.024948f, 0.027100f,
+ 0.029770f, 0.032166f, 0.035248f, 0.038696f, 0.042633f, 0.046875f, 0.051605f, 0.056427f, 0.061859f, 0.067688f, 0.403320f, 0.467041f,
+ 0.480957f, 0.487793f, 0.491699f, 0.494385f, 0.000336f, 0.000673f, 0.001150f, 0.001274f, 0.001482f, 0.001630f, 0.001748f, 0.001904f,
+ 0.002087f, 0.002232f, 0.002306f, 0.002497f, 0.002672f, 0.002872f, 0.003092f, 0.003225f, 0.003387f, 0.003553f, 0.003819f, 0.003979f,
+ 0.004230f, 0.004517f, 0.004738f, 0.005016f, 0.005322f, 0.005569f, 0.005848f, 0.006184f, 0.006573f, 0.006851f, 0.007271f, 0.007660f,
+ 0.008064f, 0.008568f, 0.009048f, 0.009567f, 0.010139f, 0.010788f, 0.011391f, 0.012161f, 0.012939f, 0.013763f, 0.014694f, 0.015717f,
+ 0.016815f, 0.018097f, 0.019714f, 0.021149f, 0.023270f, 0.025421f, 0.028015f, 0.030991f, 0.034271f, 0.038116f, 0.042328f, 0.046997f,
+ 0.052094f, 0.057770f, 0.391113f, 0.457031f, 0.472412f, 0.479736f, 0.484375f, 0.486816f, 0.000309f, 0.000612f, 0.000953f, 0.001086f,
+ 0.001191f, 0.001281f, 0.001351f, 0.001442f, 0.001610f, 0.001733f, 0.001783f, 0.001991f, 0.002087f, 0.002232f, 0.002337f, 0.002495f,
+ 0.002611f, 0.002775f, 0.002935f, 0.003101f, 0.003302f, 0.003496f, 0.003622f, 0.003839f, 0.004047f, 0.004265f, 0.004494f, 0.004738f,
+ 0.005039f, 0.005272f, 0.005650f, 0.005898f, 0.006210f, 0.006588f, 0.006950f, 0.007332f, 0.007782f, 0.008240f, 0.008766f, 0.009331f,
+ 0.009964f, 0.010612f, 0.011314f, 0.012062f, 0.013023f, 0.014038f, 0.015007f, 0.016251f, 0.017761f, 0.019501f, 0.021530f, 0.023926f,
+ 0.026718f, 0.030106f, 0.033905f, 0.038361f, 0.043060f, 0.048370f, 0.379395f, 0.446777f, 0.464111f, 0.471191f, 0.475586f, 0.479492f,
+ 0.000439f, 0.000476f, 0.000672f, 0.000752f, 0.000810f, 0.000949f, 0.001011f, 0.001121f, 0.001160f, 0.001249f, 0.001408f, 0.001493f,
+ 0.001591f, 0.001719f, 0.001788f, 0.001845f, 0.001982f, 0.002106f, 0.002201f, 0.002357f, 0.002460f, 0.002598f, 0.002724f, 0.002869f,
+ 0.003036f, 0.003187f, 0.003397f, 0.003569f, 0.003763f, 0.004017f, 0.004211f, 0.004414f, 0.004704f, 0.004890f, 0.005234f, 0.005524f,
+ 0.005825f, 0.006187f, 0.006535f, 0.006977f, 0.007423f, 0.007874f, 0.008553f, 0.009079f, 0.009857f, 0.010567f, 0.011360f, 0.012306f,
+ 0.013390f, 0.014702f, 0.016220f, 0.017960f, 0.020157f, 0.022995f, 0.026352f, 0.030212f, 0.034790f, 0.039459f, 0.368408f, 0.437744f,
+ 0.455322f, 0.463379f, 0.468018f, 0.471436f, 0.000202f, 0.000437f, 0.000488f, 0.000579f, 0.000664f, 0.000692f, 0.000792f, 0.000762f,
+ 0.000875f, 0.000949f, 0.001038f, 0.001068f, 0.001116f, 0.001196f, 0.001300f, 0.001352f, 0.001458f, 0.001529f, 0.001623f, 0.001667f,
+ 0.001770f, 0.001884f, 0.001989f, 0.002071f, 0.002203f, 0.002310f, 0.002445f, 0.002556f, 0.002680f, 0.002876f, 0.002991f, 0.003206f,
+ 0.003365f, 0.003531f, 0.003759f, 0.003956f, 0.004227f, 0.004513f, 0.004768f, 0.005074f, 0.005402f, 0.005756f, 0.006142f, 0.006603f,
+ 0.007160f, 0.007645f, 0.008339f, 0.008987f, 0.009819f, 0.010780f, 0.011803f, 0.013153f, 0.014763f, 0.016876f, 0.019623f, 0.022995f,
+ 0.026978f, 0.031708f, 0.356445f, 0.428223f, 0.446533f, 0.455078f, 0.460449f, 0.463379f, 0.000126f, 0.000241f, 0.000344f, 0.000353f,
+ 0.000437f, 0.000522f, 0.000513f, 0.000552f, 0.000613f, 0.000699f, 0.000717f, 0.000727f, 0.000763f, 0.000848f, 0.000877f, 0.000956f,
+ 0.000963f, 0.001068f, 0.001128f, 0.001170f, 0.001238f, 0.001311f, 0.001385f, 0.001454f, 0.001534f, 0.001603f, 0.001714f, 0.001779f,
+ 0.001885f, 0.002016f, 0.002092f, 0.002214f, 0.002331f, 0.002460f, 0.002613f, 0.002777f, 0.002924f, 0.003120f, 0.003298f, 0.003496f,
+ 0.003708f, 0.004009f, 0.004292f, 0.004601f, 0.004951f, 0.005341f, 0.005772f, 0.006260f, 0.006901f, 0.007572f, 0.008324f, 0.009300f,
+ 0.010445f, 0.011848f, 0.013870f, 0.016678f, 0.020218f, 0.024536f, 0.345703f, 0.419189f, 0.437500f, 0.447021f, 0.452393f, 0.455811f,
+ 0.000146f, 0.000240f, 0.000268f, 0.000268f, 0.000310f, 0.000311f, 0.000331f, 0.000366f, 0.000410f, 0.000447f, 0.000446f, 0.000517f,
+ 0.000511f, 0.000571f, 0.000596f, 0.000618f, 0.000674f, 0.000691f, 0.000723f, 0.000762f, 0.000822f, 0.000856f, 0.000912f, 0.000950f,
+ 0.001014f, 0.001049f, 0.001128f, 0.001188f, 0.001237f, 0.001303f, 0.001371f, 0.001466f, 0.001532f, 0.001623f, 0.001701f, 0.001805f,
+ 0.001945f, 0.002035f, 0.002186f, 0.002329f, 0.002460f, 0.002632f, 0.002819f, 0.003012f, 0.003271f, 0.003550f, 0.003819f, 0.004162f,
+ 0.004539f, 0.005024f, 0.005585f, 0.006233f, 0.007050f, 0.008072f, 0.009331f, 0.011269f, 0.014160f, 0.018112f, 0.333740f, 0.408447f,
+ 0.428711f, 0.438232f, 0.443359f, 0.447510f, 0.000053f, 0.000163f, 0.000155f, 0.000160f, 0.000191f, 0.000228f, 0.000206f, 0.000233f,
+ 0.000248f, 0.000263f, 0.000267f, 0.000294f, 0.000324f, 0.000335f, 0.000364f, 0.000378f, 0.000396f, 0.000435f, 0.000445f, 0.000490f,
+ 0.000502f, 0.000522f, 0.000543f, 0.000582f, 0.000619f, 0.000665f, 0.000679f, 0.000705f, 0.000755f, 0.000797f, 0.000856f, 0.000887f,
+ 0.000953f, 0.000988f, 0.001043f, 0.001103f, 0.001177f, 0.001256f, 0.001331f, 0.001410f, 0.001508f, 0.001612f, 0.001734f, 0.001873f,
+ 0.001999f, 0.002163f, 0.002378f, 0.002565f, 0.002827f, 0.003119f, 0.003479f, 0.003899f, 0.004463f, 0.005116f, 0.005951f, 0.007153f,
+ 0.009163f, 0.012535f, 0.322510f, 0.400146f, 0.420654f, 0.430176f, 0.436523f, 0.440430f, 0.000097f, 0.000107f, 0.000095f, 0.000087f,
+ 0.000107f, 0.000110f, 0.000137f, 0.000139f, 0.000140f, 0.000147f, 0.000168f, 0.000175f, 0.000177f, 0.000184f, 0.000210f, 0.000200f,
+ 0.000224f, 0.000239f, 0.000246f, 0.000258f, 0.000278f, 0.000288f, 0.000312f, 0.000324f, 0.000347f, 0.000368f, 0.000382f, 0.000395f,
+ 0.000418f, 0.000440f, 0.000471f, 0.000495f, 0.000521f, 0.000547f, 0.000577f, 0.000620f, 0.000649f, 0.000695f, 0.000749f, 0.000785f,
+ 0.000838f, 0.000897f, 0.000972f, 0.001028f, 0.001118f, 0.001204f, 0.001316f, 0.001432f, 0.001580f, 0.001748f, 0.001961f, 0.002207f,
+ 0.002533f, 0.002941f, 0.003487f, 0.004223f, 0.005371f, 0.007809f, 0.311523f, 0.390381f, 0.411377f, 0.421875f, 0.428467f, 0.432617f,
+ 0.000000f, 0.000055f, 0.000046f, 0.000054f, 0.000060f, 0.000058f, 0.000060f, 0.000068f, 0.000068f, 0.000082f, 0.000076f, 0.000078f,
+ 0.000092f, 0.000087f, 0.000091f, 0.000097f, 0.000105f, 0.000115f, 0.000118f, 0.000124f, 0.000128f, 0.000133f, 0.000139f, 0.000154f,
+ 0.000160f, 0.000172f, 0.000175f, 0.000191f, 0.000201f, 0.000211f, 0.000221f, 0.000238f, 0.000242f, 0.000257f, 0.000277f, 0.000295f,
+ 0.000309f, 0.000326f, 0.000351f, 0.000375f, 0.000400f, 0.000428f, 0.000459f, 0.000490f, 0.000535f, 0.000579f, 0.000626f, 0.000683f,
+ 0.000754f, 0.000836f, 0.000952f, 0.001064f, 0.001237f, 0.001460f, 0.001751f, 0.002157f, 0.002800f, 0.004189f, 0.299561f, 0.380127f,
+ 0.403076f, 0.413574f, 0.419922f, 0.424072f, 0.000059f, 0.000039f, 0.000032f, 0.000028f, 0.000025f, 0.000025f, 0.000025f, 0.000024f,
+ 0.000023f, 0.000024f, 0.000026f, 0.000034f, 0.000029f, 0.000031f, 0.000038f, 0.000040f, 0.000042f, 0.000043f, 0.000042f, 0.000043f,
+ 0.000048f, 0.000054f, 0.000058f, 0.000056f, 0.000060f, 0.000062f, 0.000066f, 0.000069f, 0.000072f, 0.000078f, 0.000082f, 0.000085f,
+ 0.000093f, 0.000096f, 0.000099f, 0.000106f, 0.000116f, 0.000123f, 0.000132f, 0.000140f, 0.000150f, 0.000154f, 0.000167f, 0.000184f,
+ 0.000192f, 0.000212f, 0.000231f, 0.000251f, 0.000282f, 0.000314f, 0.000350f, 0.000401f, 0.000463f, 0.000554f, 0.000679f, 0.000861f,
+ 0.001157f, 0.001750f, 0.289307f, 0.371582f, 0.394043f, 0.406006f, 0.412109f, 0.417236f, 0.000031f, 0.000020f, 0.000016f, 0.000014f,
+ 0.000013f, 0.000012f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000008f, 0.000008f, 0.000009f,
+ 0.000009f, 0.000007f, 0.000008f, 0.000008f, 0.000010f, 0.000011f, 0.000012f, 0.000013f, 0.000013f, 0.000013f, 0.000014f, 0.000017f,
+ 0.000017f, 0.000016f, 0.000018f, 0.000019f, 0.000021f, 0.000021f, 0.000022f, 0.000025f, 0.000027f, 0.000025f, 0.000028f, 0.000030f,
+ 0.000033f, 0.000036f, 0.000038f, 0.000040f, 0.000042f, 0.000047f, 0.000052f, 0.000057f, 0.000060f, 0.000068f, 0.000073f, 0.000089f,
+ 0.000104f, 0.000124f, 0.000153f, 0.000204f, 0.000293f, 0.000497f, 0.278076f, 0.362793f, 0.385498f, 0.397705f, 0.405029f, 0.409912f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000003f, 0.000003f, 0.000004f, 0.000004f, 0.000005f, 0.000005f, 0.000008f, 0.000012f, 0.000026f, 0.267822f, 0.353027f,
+ 0.376953f, 0.388916f, 0.395996f, 0.401367f,
+ },
+ {
+ 0.006824f, 0.021286f, 0.036285f, 0.051208f, 0.066467f, 0.082825f, 0.098694f, 0.114563f, 0.130737f, 0.146973f, 0.162720f, 0.179932f,
+ 0.196411f, 0.212646f, 0.229370f, 0.246338f, 0.263184f, 0.279785f, 0.297363f, 0.314209f, 0.331055f, 0.348389f, 0.365479f, 0.383301f,
+ 0.400146f, 0.417725f, 0.435303f, 0.451904f, 0.469971f, 0.486816f, 0.503906f, 0.521484f, 0.539551f, 0.556641f, 0.573730f, 0.592285f,
+ 0.609375f, 0.627441f, 0.644531f, 0.662598f, 0.679688f, 0.696777f, 0.714355f, 0.731934f, 0.749512f, 0.768066f, 0.784180f, 0.802246f,
+ 0.820312f, 0.837891f, 0.854980f, 0.871582f, 0.889648f, 0.906738f, 0.924805f, 0.941406f, 0.959473f, 0.976074f, 0.953125f, 0.895020f,
+ 0.857422f, 0.827637f, 0.803223f, 0.781738f, 0.006741f, 0.020706f, 0.035187f, 0.049866f, 0.065125f, 0.079895f, 0.095581f, 0.111206f,
+ 0.126953f, 0.142822f, 0.158569f, 0.174561f, 0.190796f, 0.207031f, 0.223511f, 0.239380f, 0.256104f, 0.272705f, 0.289307f, 0.305664f,
+ 0.322754f, 0.338867f, 0.356201f, 0.372314f, 0.389404f, 0.406494f, 0.423828f, 0.440430f, 0.457520f, 0.474854f, 0.491211f, 0.508789f,
+ 0.525391f, 0.541992f, 0.559082f, 0.576660f, 0.594238f, 0.610840f, 0.627930f, 0.645508f, 0.662598f, 0.679199f, 0.696289f, 0.713379f,
+ 0.731445f, 0.747559f, 0.765137f, 0.782715f, 0.799805f, 0.816895f, 0.834473f, 0.851074f, 0.868164f, 0.884766f, 0.902344f, 0.919434f,
+ 0.936523f, 0.953613f, 0.942871f, 0.887695f, 0.851562f, 0.823730f, 0.799805f, 0.779297f, 0.006504f, 0.020004f, 0.033875f, 0.048676f,
+ 0.063110f, 0.077759f, 0.092712f, 0.108032f, 0.123230f, 0.138672f, 0.153931f, 0.170044f, 0.185791f, 0.200806f, 0.217041f, 0.233276f,
+ 0.248901f, 0.265137f, 0.280762f, 0.297363f, 0.313721f, 0.329834f, 0.346680f, 0.363037f, 0.378418f, 0.395752f, 0.411621f, 0.428467f,
+ 0.445312f, 0.461670f, 0.479004f, 0.494873f, 0.511230f, 0.527832f, 0.544434f, 0.561523f, 0.578613f, 0.594727f, 0.611328f, 0.628906f,
+ 0.645508f, 0.662109f, 0.679199f, 0.695312f, 0.712402f, 0.729004f, 0.746094f, 0.762695f, 0.779297f, 0.796387f, 0.812500f, 0.829590f,
+ 0.846191f, 0.863281f, 0.879395f, 0.896973f, 0.914062f, 0.930176f, 0.932129f, 0.879395f, 0.845703f, 0.818848f, 0.795898f, 0.776367f,
+ 0.006226f, 0.019318f, 0.032959f, 0.046631f, 0.060699f, 0.075745f, 0.089966f, 0.104553f, 0.119385f, 0.134277f, 0.149292f, 0.164917f,
+ 0.179932f, 0.195190f, 0.210693f, 0.226562f, 0.242188f, 0.257568f, 0.273438f, 0.289062f, 0.304932f, 0.320557f, 0.336426f, 0.352539f,
+ 0.368652f, 0.384766f, 0.400391f, 0.417236f, 0.433105f, 0.448730f, 0.465088f, 0.481689f, 0.497559f, 0.513672f, 0.528809f, 0.546875f,
+ 0.562500f, 0.578613f, 0.595215f, 0.612793f, 0.627930f, 0.645508f, 0.661621f, 0.677246f, 0.693848f, 0.709961f, 0.726562f, 0.743164f,
+ 0.759766f, 0.774902f, 0.791992f, 0.808594f, 0.825195f, 0.841309f, 0.856934f, 0.874023f, 0.890625f, 0.907715f, 0.921387f, 0.872070f,
+ 0.839355f, 0.813477f, 0.791504f, 0.772461f, 0.005928f, 0.018997f, 0.031830f, 0.045380f, 0.059235f, 0.072754f, 0.087463f, 0.101562f,
+ 0.115723f, 0.130371f, 0.145264f, 0.159668f, 0.175049f, 0.189453f, 0.204468f, 0.219482f, 0.234497f, 0.250000f, 0.266113f, 0.280273f,
+ 0.295410f, 0.311768f, 0.327393f, 0.343018f, 0.357422f, 0.373779f, 0.389404f, 0.404785f, 0.421143f, 0.437012f, 0.452881f, 0.468262f,
+ 0.484375f, 0.499512f, 0.515137f, 0.531738f, 0.546875f, 0.562500f, 0.579102f, 0.595215f, 0.610840f, 0.627441f, 0.643555f, 0.659180f,
+ 0.674805f, 0.691406f, 0.708008f, 0.723145f, 0.738770f, 0.755371f, 0.771484f, 0.787598f, 0.803711f, 0.819824f, 0.835449f, 0.851562f,
+ 0.867676f, 0.884277f, 0.910156f, 0.864258f, 0.832520f, 0.808105f, 0.787109f, 0.769043f, 0.005939f, 0.018066f, 0.030991f, 0.043488f,
+ 0.057312f, 0.070557f, 0.084473f, 0.098328f, 0.112610f, 0.126587f, 0.140259f, 0.154907f, 0.169678f, 0.184326f, 0.198608f, 0.213379f,
+ 0.227783f, 0.242065f, 0.257568f, 0.272705f, 0.287109f, 0.302246f, 0.318115f, 0.333252f, 0.347656f, 0.362549f, 0.378418f, 0.393555f,
+ 0.408936f, 0.423828f, 0.439697f, 0.455078f, 0.471191f, 0.484863f, 0.500488f, 0.517578f, 0.532227f, 0.547363f, 0.562500f, 0.579102f,
+ 0.594727f, 0.610352f, 0.625488f, 0.641602f, 0.657227f, 0.671875f, 0.687500f, 0.704102f, 0.719238f, 0.733887f, 0.750488f, 0.767090f,
+ 0.782715f, 0.798340f, 0.813965f, 0.830566f, 0.845215f, 0.862305f, 0.899902f, 0.855469f, 0.825684f, 0.801758f, 0.782227f, 0.764648f,
+ 0.005684f, 0.017639f, 0.030334f, 0.042572f, 0.055298f, 0.068054f, 0.081787f, 0.095276f, 0.108765f, 0.122192f, 0.136353f, 0.150513f,
+ 0.164307f, 0.178467f, 0.192627f, 0.206665f, 0.221436f, 0.234985f, 0.249634f, 0.264404f, 0.278564f, 0.293213f, 0.308350f, 0.321533f,
+ 0.337646f, 0.353027f, 0.367432f, 0.381592f, 0.395996f, 0.411865f, 0.426758f, 0.441895f, 0.456543f, 0.471680f, 0.485840f, 0.501465f,
+ 0.517090f, 0.531738f, 0.546387f, 0.562012f, 0.576660f, 0.592773f, 0.608398f, 0.623047f, 0.638672f, 0.654297f, 0.668457f, 0.684082f,
+ 0.699707f, 0.714844f, 0.730469f, 0.745605f, 0.761230f, 0.777832f, 0.791504f, 0.807617f, 0.823242f, 0.839355f, 0.889160f, 0.847656f,
+ 0.818848f, 0.796387f, 0.776855f, 0.760254f, 0.005417f, 0.017136f, 0.028778f, 0.041016f, 0.054047f, 0.066528f, 0.079590f, 0.092102f,
+ 0.105225f, 0.118652f, 0.131714f, 0.145630f, 0.158813f, 0.172607f, 0.186523f, 0.200317f, 0.213745f, 0.227905f, 0.242188f, 0.256104f,
+ 0.270020f, 0.283936f, 0.299072f, 0.312744f, 0.327148f, 0.341797f, 0.355957f, 0.369629f, 0.384766f, 0.399414f, 0.413574f, 0.427490f,
+ 0.443115f, 0.457764f, 0.472656f, 0.487061f, 0.501465f, 0.516602f, 0.530762f, 0.545898f, 0.560547f, 0.574707f, 0.589844f, 0.605469f,
+ 0.619629f, 0.633301f, 0.648926f, 0.665527f, 0.679688f, 0.694824f, 0.709961f, 0.725586f, 0.739746f, 0.755371f, 0.770020f, 0.786133f,
+ 0.802246f, 0.817383f, 0.877930f, 0.838867f, 0.812012f, 0.790039f, 0.771973f, 0.755371f, 0.005520f, 0.016464f, 0.027695f, 0.039948f,
+ 0.051575f, 0.063965f, 0.076660f, 0.089111f, 0.101807f, 0.114319f, 0.126953f, 0.140381f, 0.153564f, 0.166992f, 0.180298f, 0.193970f,
+ 0.207153f, 0.220337f, 0.234131f, 0.248169f, 0.261475f, 0.275146f, 0.288818f, 0.302734f, 0.316162f, 0.330566f, 0.345459f, 0.358887f,
+ 0.372803f, 0.386719f, 0.401367f, 0.415527f, 0.429199f, 0.443848f, 0.458008f, 0.472412f, 0.486572f, 0.500977f, 0.515137f, 0.529785f,
+ 0.544434f, 0.558105f, 0.572754f, 0.587891f, 0.601074f, 0.617188f, 0.631836f, 0.645020f, 0.660645f, 0.674805f, 0.689453f, 0.704590f,
+ 0.719727f, 0.734375f, 0.750000f, 0.764160f, 0.780273f, 0.794922f, 0.866699f, 0.830566f, 0.804688f, 0.784180f, 0.766113f, 0.750977f,
+ 0.005222f, 0.016022f, 0.026962f, 0.038086f, 0.050049f, 0.061798f, 0.074158f, 0.085876f, 0.098145f, 0.110718f, 0.122986f, 0.135864f,
+ 0.148438f, 0.161133f, 0.173584f, 0.187378f, 0.199707f, 0.213501f, 0.226440f, 0.240112f, 0.252441f, 0.266113f, 0.279785f, 0.292725f,
+ 0.306152f, 0.320068f, 0.333984f, 0.347900f, 0.361572f, 0.374512f, 0.387695f, 0.402344f, 0.416504f, 0.429688f, 0.443604f, 0.458008f,
+ 0.471680f, 0.485596f, 0.499023f, 0.513184f, 0.527832f, 0.541016f, 0.555664f, 0.569336f, 0.583984f, 0.598633f, 0.612793f, 0.626465f,
+ 0.641602f, 0.656250f, 0.669922f, 0.684570f, 0.698730f, 0.713867f, 0.728516f, 0.742188f, 0.757812f, 0.771484f, 0.855957f, 0.822266f,
+ 0.797852f, 0.777832f, 0.760742f, 0.746094f, 0.004944f, 0.015327f, 0.026230f, 0.037201f, 0.048187f, 0.059448f, 0.071167f, 0.082642f,
+ 0.094727f, 0.106506f, 0.119019f, 0.130371f, 0.143555f, 0.155640f, 0.167725f, 0.180908f, 0.193604f, 0.206177f, 0.218506f, 0.231812f,
+ 0.244873f, 0.257568f, 0.270996f, 0.283203f, 0.296387f, 0.309814f, 0.322754f, 0.336670f, 0.348877f, 0.362061f, 0.376465f, 0.389893f,
+ 0.402588f, 0.415283f, 0.429443f, 0.443115f, 0.457031f, 0.470459f, 0.483887f, 0.497314f, 0.511230f, 0.524414f, 0.538574f, 0.551758f,
+ 0.565918f, 0.579590f, 0.593750f, 0.606934f, 0.621094f, 0.635254f, 0.649902f, 0.664062f, 0.678223f, 0.692871f, 0.707031f, 0.721191f,
+ 0.735840f, 0.750488f, 0.846191f, 0.813477f, 0.790527f, 0.770996f, 0.754883f, 0.740723f, 0.004951f, 0.014656f, 0.025253f, 0.035309f,
+ 0.046417f, 0.057465f, 0.068665f, 0.079773f, 0.091370f, 0.102844f, 0.114441f, 0.126099f, 0.138062f, 0.150391f, 0.161987f, 0.174561f,
+ 0.186523f, 0.198730f, 0.211060f, 0.223267f, 0.235352f, 0.248779f, 0.260986f, 0.274414f, 0.286621f, 0.298584f, 0.312256f, 0.324463f,
+ 0.337158f, 0.350342f, 0.363281f, 0.376953f, 0.389404f, 0.402344f, 0.415283f, 0.428955f, 0.441162f, 0.455322f, 0.467285f, 0.481201f,
+ 0.493896f, 0.507324f, 0.520996f, 0.534668f, 0.547852f, 0.561035f, 0.575195f, 0.588867f, 0.603027f, 0.616211f, 0.630371f, 0.643555f,
+ 0.658203f, 0.671875f, 0.686035f, 0.699707f, 0.714844f, 0.729492f, 0.833984f, 0.804688f, 0.782227f, 0.764160f, 0.749512f, 0.735352f,
+ 0.004700f, 0.014343f, 0.024200f, 0.034515f, 0.044586f, 0.055176f, 0.066162f, 0.077209f, 0.087830f, 0.098816f, 0.110413f, 0.121826f,
+ 0.132690f, 0.144897f, 0.156372f, 0.168213f, 0.179443f, 0.191650f, 0.203369f, 0.215088f, 0.227661f, 0.239990f, 0.251709f, 0.263916f,
+ 0.276611f, 0.289551f, 0.301270f, 0.313965f, 0.325928f, 0.338135f, 0.350586f, 0.363037f, 0.376465f, 0.388428f, 0.401123f, 0.414062f,
+ 0.426514f, 0.439209f, 0.452393f, 0.465088f, 0.478271f, 0.491455f, 0.503906f, 0.517090f, 0.530273f, 0.543457f, 0.556641f, 0.570312f,
+ 0.583008f, 0.597168f, 0.610352f, 0.624512f, 0.638184f, 0.651367f, 0.665527f, 0.679199f, 0.692871f, 0.708496f, 0.823242f, 0.796387f,
+ 0.774902f, 0.757812f, 0.742676f, 0.729980f, 0.004395f, 0.013802f, 0.023499f, 0.033173f, 0.043121f, 0.053345f, 0.063538f, 0.073730f,
+ 0.085083f, 0.095581f, 0.106140f, 0.116760f, 0.127930f, 0.139160f, 0.150757f, 0.161621f, 0.173096f, 0.184814f, 0.196289f, 0.207520f,
+ 0.219971f, 0.231201f, 0.242920f, 0.254150f, 0.266602f, 0.278320f, 0.290527f, 0.302490f, 0.314209f, 0.326904f, 0.338867f, 0.349854f,
+ 0.362305f, 0.375488f, 0.387451f, 0.400146f, 0.412354f, 0.424805f, 0.436768f, 0.449219f, 0.461914f, 0.475098f, 0.487061f, 0.500000f,
+ 0.512695f, 0.525391f, 0.538574f, 0.551758f, 0.564453f, 0.577148f, 0.590820f, 0.604004f, 0.618164f, 0.631348f, 0.644531f, 0.658203f,
+ 0.672363f, 0.686523f, 0.812500f, 0.786621f, 0.767090f, 0.750977f, 0.736816f, 0.724609f, 0.004425f, 0.013405f, 0.022385f, 0.032043f,
+ 0.041565f, 0.051605f, 0.061340f, 0.071106f, 0.081116f, 0.091125f, 0.101868f, 0.112671f, 0.123169f, 0.133667f, 0.144897f, 0.155029f,
+ 0.166748f, 0.177246f, 0.188599f, 0.199585f, 0.211182f, 0.222046f, 0.233643f, 0.245361f, 0.255615f, 0.268066f, 0.279053f, 0.291260f,
+ 0.303223f, 0.314209f, 0.325684f, 0.338379f, 0.349854f, 0.361572f, 0.374023f, 0.385254f, 0.397949f, 0.409912f, 0.421143f, 0.434082f,
+ 0.445801f, 0.457764f, 0.470215f, 0.482910f, 0.495361f, 0.508301f, 0.520996f, 0.534180f, 0.546387f, 0.560059f, 0.572266f, 0.584961f,
+ 0.597168f, 0.610840f, 0.624023f, 0.638184f, 0.650879f, 0.666016f, 0.801270f, 0.778320f, 0.760254f, 0.744141f, 0.730469f, 0.719238f,
+ 0.004261f, 0.012543f, 0.021591f, 0.031052f, 0.039734f, 0.049164f, 0.058838f, 0.068420f, 0.077881f, 0.087402f, 0.098145f, 0.108276f,
+ 0.118225f, 0.128784f, 0.138550f, 0.149292f, 0.159790f, 0.170654f, 0.181519f, 0.191772f, 0.203003f, 0.213623f, 0.225098f, 0.235107f,
+ 0.247070f, 0.257324f, 0.269287f, 0.280273f, 0.291260f, 0.302246f, 0.313721f, 0.325439f, 0.336670f, 0.348145f, 0.359619f, 0.371338f,
+ 0.382812f, 0.395020f, 0.406738f, 0.418213f, 0.429932f, 0.442139f, 0.454102f, 0.466309f, 0.479004f, 0.490723f, 0.502930f, 0.515625f,
+ 0.526855f, 0.540527f, 0.552246f, 0.565918f, 0.578613f, 0.591309f, 0.604492f, 0.617188f, 0.630859f, 0.644043f, 0.790039f, 0.769531f,
+ 0.751953f, 0.737305f, 0.724121f, 0.713379f, 0.003983f, 0.012329f, 0.020538f, 0.029312f, 0.038452f, 0.047241f, 0.056244f, 0.065552f,
+ 0.075195f, 0.084290f, 0.094238f, 0.103638f, 0.113403f, 0.123413f, 0.133057f, 0.143066f, 0.153076f, 0.163696f, 0.173584f, 0.184204f,
+ 0.194580f, 0.204834f, 0.215332f, 0.225952f, 0.237305f, 0.247803f, 0.258545f, 0.269531f, 0.280518f, 0.291260f, 0.301758f, 0.312988f,
+ 0.324219f, 0.335205f, 0.346191f, 0.357178f, 0.368896f, 0.380127f, 0.391113f, 0.403076f, 0.414551f, 0.426270f, 0.437500f, 0.449951f,
+ 0.460938f, 0.473389f, 0.485596f, 0.497314f, 0.509277f, 0.522461f, 0.533691f, 0.546875f, 0.558594f, 0.571289f, 0.583496f, 0.596680f,
+ 0.608887f, 0.623047f, 0.778809f, 0.761230f, 0.744141f, 0.730957f, 0.718262f, 0.707031f, 0.003717f, 0.012016f, 0.020142f, 0.028137f,
+ 0.036682f, 0.045441f, 0.053711f, 0.062927f, 0.071777f, 0.080627f, 0.090210f, 0.099060f, 0.108643f, 0.118164f, 0.127808f, 0.137329f,
+ 0.147095f, 0.156128f, 0.166748f, 0.175903f, 0.186157f, 0.196655f, 0.206909f, 0.216797f, 0.227417f, 0.236816f, 0.247559f, 0.258301f,
+ 0.268799f, 0.278809f, 0.289795f, 0.299805f, 0.310547f, 0.321777f, 0.333008f, 0.343262f, 0.354492f, 0.365234f, 0.376953f, 0.387939f,
+ 0.398438f, 0.410400f, 0.421387f, 0.433105f, 0.444824f, 0.455811f, 0.467529f, 0.479736f, 0.491943f, 0.502930f, 0.515625f, 0.527344f,
+ 0.540039f, 0.551758f, 0.563965f, 0.576660f, 0.589844f, 0.602539f, 0.767578f, 0.751465f, 0.736328f, 0.723633f, 0.711914f, 0.701660f,
+ 0.003813f, 0.011337f, 0.019028f, 0.027252f, 0.035583f, 0.043396f, 0.051849f, 0.060028f, 0.068481f, 0.077026f, 0.086121f, 0.095093f,
+ 0.103821f, 0.112610f, 0.121765f, 0.131470f, 0.140503f, 0.149780f, 0.159058f, 0.168701f, 0.178711f, 0.187744f, 0.197998f, 0.207397f,
+ 0.217651f, 0.227661f, 0.236694f, 0.246704f, 0.257080f, 0.267334f, 0.277832f, 0.288330f, 0.298584f, 0.308838f, 0.319336f, 0.329590f,
+ 0.340332f, 0.351318f, 0.361816f, 0.372559f, 0.383301f, 0.395020f, 0.405273f, 0.416260f, 0.427734f, 0.439209f, 0.450195f, 0.462158f,
+ 0.473389f, 0.485107f, 0.497314f, 0.508301f, 0.520996f, 0.533203f, 0.544922f, 0.557617f, 0.568848f, 0.582031f, 0.757324f, 0.742676f,
+ 0.729004f, 0.716309f, 0.705566f, 0.695801f, 0.003633f, 0.011040f, 0.018280f, 0.026062f, 0.033569f, 0.041229f, 0.049591f, 0.057373f,
+ 0.065308f, 0.073975f, 0.082214f, 0.090393f, 0.099243f, 0.107544f, 0.116028f, 0.125854f, 0.134155f, 0.143311f, 0.151978f, 0.160767f,
+ 0.170410f, 0.179321f, 0.188477f, 0.198242f, 0.207764f, 0.217896f, 0.227051f, 0.236328f, 0.246338f, 0.256104f, 0.265869f, 0.276123f,
+ 0.285645f, 0.295898f, 0.306152f, 0.316162f, 0.326172f, 0.336914f, 0.347412f, 0.358154f, 0.368164f, 0.378906f, 0.389648f, 0.400146f,
+ 0.410889f, 0.421631f, 0.432861f, 0.444824f, 0.456055f, 0.466797f, 0.479004f, 0.490234f, 0.501465f, 0.514160f, 0.525879f, 0.537598f,
+ 0.549316f, 0.561523f, 0.745605f, 0.733887f, 0.721191f, 0.708496f, 0.699219f, 0.689453f, 0.003469f, 0.010429f, 0.017609f, 0.024612f,
+ 0.032135f, 0.039520f, 0.047516f, 0.055206f, 0.062347f, 0.070618f, 0.078308f, 0.085938f, 0.094727f, 0.102417f, 0.111511f, 0.119446f,
+ 0.127441f, 0.136475f, 0.144897f, 0.154175f, 0.162476f, 0.171509f, 0.180054f, 0.189697f, 0.198486f, 0.207886f, 0.216553f, 0.225830f,
+ 0.235229f, 0.244873f, 0.254395f, 0.263428f, 0.273193f, 0.283203f, 0.292969f, 0.302734f, 0.312744f, 0.322510f, 0.333008f, 0.342773f,
+ 0.353027f, 0.363037f, 0.374023f, 0.384521f, 0.395264f, 0.405762f, 0.416260f, 0.427002f, 0.438232f, 0.449219f, 0.460449f, 0.471924f,
+ 0.482910f, 0.494629f, 0.506348f, 0.517578f, 0.529785f, 0.541504f, 0.734375f, 0.725098f, 0.712891f, 0.701660f, 0.692383f, 0.683594f,
+ 0.003328f, 0.009804f, 0.016373f, 0.023727f, 0.030746f, 0.037994f, 0.044952f, 0.052032f, 0.059998f, 0.067383f, 0.074707f, 0.082214f,
+ 0.089783f, 0.097961f, 0.105774f, 0.114197f, 0.122131f, 0.129517f, 0.137695f, 0.146118f, 0.154419f, 0.163330f, 0.171997f, 0.180664f,
+ 0.188477f, 0.197388f, 0.206055f, 0.215332f, 0.224365f, 0.233765f, 0.242798f, 0.251709f, 0.260986f, 0.270020f, 0.279785f, 0.289062f,
+ 0.299561f, 0.308594f, 0.318115f, 0.328613f, 0.338135f, 0.348877f, 0.358154f, 0.368408f, 0.378174f, 0.388916f, 0.399658f, 0.410156f,
+ 0.420898f, 0.431885f, 0.442871f, 0.453369f, 0.463867f, 0.475342f, 0.486572f, 0.498535f, 0.510742f, 0.521973f, 0.723633f, 0.715820f,
+ 0.705078f, 0.694336f, 0.686035f, 0.677246f, 0.003090f, 0.009628f, 0.016129f, 0.022644f, 0.029068f, 0.036407f, 0.042633f, 0.049866f,
+ 0.056946f, 0.063904f, 0.071167f, 0.078186f, 0.085327f, 0.092896f, 0.100098f, 0.107788f, 0.115662f, 0.123230f, 0.131104f, 0.139160f,
+ 0.146973f, 0.154907f, 0.162964f, 0.171265f, 0.179565f, 0.188110f, 0.196777f, 0.204834f, 0.213745f, 0.222168f, 0.231079f, 0.239868f,
+ 0.248779f, 0.258057f, 0.267090f, 0.276611f, 0.285645f, 0.294434f, 0.304688f, 0.314209f, 0.323242f, 0.332520f, 0.342773f, 0.353027f,
+ 0.362549f, 0.373047f, 0.383057f, 0.393311f, 0.404053f, 0.414307f, 0.424561f, 0.435059f, 0.445801f, 0.456787f, 0.467773f, 0.479004f,
+ 0.490479f, 0.501953f, 0.712891f, 0.707031f, 0.696777f, 0.687500f, 0.679199f, 0.671387f, 0.003096f, 0.009026f, 0.015450f, 0.021606f,
+ 0.027695f, 0.034302f, 0.040833f, 0.047455f, 0.054077f, 0.060669f, 0.067444f, 0.074097f, 0.081604f, 0.088501f, 0.095337f, 0.102295f,
+ 0.109375f, 0.116821f, 0.124146f, 0.131592f, 0.139404f, 0.147217f, 0.155029f, 0.162231f, 0.170288f, 0.177979f, 0.186646f, 0.194092f,
+ 0.203247f, 0.211670f, 0.219604f, 0.228149f, 0.236816f, 0.245605f, 0.254639f, 0.263184f, 0.272217f, 0.281250f, 0.290527f, 0.299805f,
+ 0.308838f, 0.318604f, 0.327637f, 0.337646f, 0.347900f, 0.356934f, 0.367432f, 0.376953f, 0.387451f, 0.397217f, 0.407227f, 0.417480f,
+ 0.427979f, 0.439209f, 0.449463f, 0.459717f, 0.470947f, 0.482666f, 0.701172f, 0.698242f, 0.688477f, 0.680176f, 0.671875f, 0.665039f,
+ 0.002831f, 0.008789f, 0.014702f, 0.020523f, 0.026642f, 0.032684f, 0.038757f, 0.044708f, 0.051666f, 0.057312f, 0.063660f, 0.070190f,
+ 0.076904f, 0.083435f, 0.090454f, 0.097046f, 0.103821f, 0.110535f, 0.117981f, 0.124817f, 0.131714f, 0.138916f, 0.146606f, 0.153687f,
+ 0.161011f, 0.168823f, 0.176270f, 0.184570f, 0.192139f, 0.200317f, 0.208008f, 0.216309f, 0.224609f, 0.233032f, 0.241821f, 0.250244f,
+ 0.258789f, 0.268066f, 0.276611f, 0.285400f, 0.294678f, 0.303223f, 0.312500f, 0.322021f, 0.331787f, 0.340088f, 0.350830f, 0.360596f,
+ 0.369385f, 0.380371f, 0.389893f, 0.399658f, 0.410645f, 0.420654f, 0.430908f, 0.442383f, 0.452148f, 0.464111f, 0.690430f, 0.688965f,
+ 0.681152f, 0.672852f, 0.665039f, 0.658691f, 0.002712f, 0.008553f, 0.013878f, 0.019638f, 0.025360f, 0.030716f, 0.037231f, 0.042633f,
+ 0.048615f, 0.054810f, 0.060638f, 0.066650f, 0.072205f, 0.078796f, 0.085083f, 0.091492f, 0.097961f, 0.104065f, 0.110718f, 0.117859f,
+ 0.124207f, 0.130981f, 0.138550f, 0.145142f, 0.152588f, 0.160156f, 0.166992f, 0.174561f, 0.181885f, 0.189453f, 0.197754f, 0.205444f,
+ 0.213013f, 0.220825f, 0.229004f, 0.237061f, 0.246094f, 0.254639f, 0.262939f, 0.271484f, 0.280273f, 0.288818f, 0.298584f, 0.307129f,
+ 0.316162f, 0.325195f, 0.334229f, 0.344482f, 0.353516f, 0.363525f, 0.372803f, 0.382812f, 0.392822f, 0.402344f, 0.412842f, 0.423096f,
+ 0.433350f, 0.444092f, 0.679199f, 0.679688f, 0.672852f, 0.665039f, 0.658203f, 0.651855f, 0.002674f, 0.007828f, 0.013290f, 0.018723f,
+ 0.023743f, 0.029160f, 0.034790f, 0.040100f, 0.045929f, 0.051544f, 0.057068f, 0.063110f, 0.068359f, 0.074280f, 0.080078f, 0.086243f,
+ 0.092346f, 0.098206f, 0.104919f, 0.110779f, 0.117493f, 0.123291f, 0.130005f, 0.136963f, 0.143677f, 0.150635f, 0.157471f, 0.164307f,
+ 0.171631f, 0.179199f, 0.186279f, 0.193604f, 0.201904f, 0.209229f, 0.217163f, 0.224976f, 0.233154f, 0.240967f, 0.249634f, 0.258301f,
+ 0.266113f, 0.274414f, 0.283691f, 0.291748f, 0.301025f, 0.310059f, 0.319336f, 0.327148f, 0.337402f, 0.347168f, 0.355957f, 0.364746f,
+ 0.375488f, 0.385498f, 0.394043f, 0.405273f, 0.415283f, 0.426025f, 0.667969f, 0.670410f, 0.664551f, 0.657227f, 0.651367f, 0.645508f,
+ 0.002731f, 0.007622f, 0.012627f, 0.017868f, 0.022781f, 0.028107f, 0.032959f, 0.037811f, 0.043121f, 0.048615f, 0.053925f, 0.059235f,
+ 0.064514f, 0.070007f, 0.075562f, 0.080688f, 0.086914f, 0.092102f, 0.098083f, 0.104309f, 0.110107f, 0.115906f, 0.122314f, 0.128540f,
+ 0.135010f, 0.141479f, 0.147949f, 0.154663f, 0.161865f, 0.168579f, 0.175415f, 0.182739f, 0.191040f, 0.197510f, 0.205200f, 0.212891f,
+ 0.219971f, 0.228638f, 0.236328f, 0.244263f, 0.252686f, 0.260498f, 0.268799f, 0.278076f, 0.286133f, 0.294434f, 0.303223f, 0.312500f,
+ 0.320801f, 0.329834f, 0.339844f, 0.347656f, 0.357910f, 0.367676f, 0.376709f, 0.386963f, 0.396729f, 0.406982f, 0.656738f, 0.662598f,
+ 0.656738f, 0.649902f, 0.644531f, 0.638672f, 0.002411f, 0.007168f, 0.012238f, 0.016739f, 0.021957f, 0.026184f, 0.031311f, 0.035583f,
+ 0.041016f, 0.045685f, 0.050568f, 0.055573f, 0.060791f, 0.065735f, 0.070557f, 0.076111f, 0.081238f, 0.086792f, 0.092163f, 0.097534f,
+ 0.103271f, 0.108887f, 0.114563f, 0.120605f, 0.126587f, 0.132446f, 0.139038f, 0.145508f, 0.152100f, 0.158447f, 0.165527f, 0.171997f,
+ 0.178833f, 0.186035f, 0.193481f, 0.200928f, 0.207886f, 0.215820f, 0.222900f, 0.230713f, 0.238770f, 0.246948f, 0.255127f, 0.262695f,
+ 0.271484f, 0.280029f, 0.287842f, 0.296631f, 0.305420f, 0.313965f, 0.322754f, 0.331787f, 0.340576f, 0.350342f, 0.359375f, 0.369385f,
+ 0.379150f, 0.388184f, 0.645508f, 0.652832f, 0.648438f, 0.643066f, 0.637695f, 0.632324f, 0.002480f, 0.006691f, 0.011452f, 0.015900f,
+ 0.020828f, 0.024734f, 0.029327f, 0.033752f, 0.038513f, 0.042999f, 0.047638f, 0.052429f, 0.056671f, 0.061859f, 0.066040f, 0.071289f,
+ 0.075684f, 0.080688f, 0.086243f, 0.091248f, 0.096436f, 0.101562f, 0.107300f, 0.112366f, 0.118347f, 0.124146f, 0.130249f, 0.135864f,
+ 0.141968f, 0.148438f, 0.155029f, 0.161377f, 0.167969f, 0.174683f, 0.181641f, 0.188599f, 0.195679f, 0.203247f, 0.210449f, 0.217529f,
+ 0.225342f, 0.233398f, 0.241577f, 0.249023f, 0.256592f, 0.264893f, 0.273193f, 0.281494f, 0.289795f, 0.297607f, 0.306885f, 0.315430f,
+ 0.323730f, 0.333496f, 0.342529f, 0.351318f, 0.360840f, 0.370605f, 0.634766f, 0.643555f, 0.640625f, 0.635742f, 0.630859f, 0.625488f,
+ 0.002230f, 0.006477f, 0.010582f, 0.014870f, 0.019073f, 0.023270f, 0.027893f, 0.031860f, 0.036072f, 0.040253f, 0.044373f, 0.048706f,
+ 0.052856f, 0.057312f, 0.061859f, 0.066406f, 0.070984f, 0.075317f, 0.080139f, 0.084839f, 0.089661f, 0.094910f, 0.099792f, 0.104858f,
+ 0.110718f, 0.115356f, 0.121399f, 0.126831f, 0.132690f, 0.138672f, 0.145142f, 0.151001f, 0.157471f, 0.164185f, 0.170532f, 0.177002f,
+ 0.184082f, 0.191040f, 0.197876f, 0.205200f, 0.212402f, 0.219604f, 0.227295f, 0.234985f, 0.242188f, 0.250244f, 0.257812f, 0.266113f,
+ 0.274170f, 0.282471f, 0.290771f, 0.299072f, 0.307373f, 0.316162f, 0.326416f, 0.333984f, 0.343750f, 0.353271f, 0.622070f, 0.634277f,
+ 0.631836f, 0.627930f, 0.623535f, 0.619141f, 0.002220f, 0.006039f, 0.010353f, 0.014328f, 0.017838f, 0.022141f, 0.025742f, 0.029510f,
+ 0.033600f, 0.037781f, 0.041443f, 0.045502f, 0.049469f, 0.053436f, 0.057190f, 0.061462f, 0.065735f, 0.069946f, 0.074524f, 0.078674f,
+ 0.083069f, 0.087830f, 0.092468f, 0.097412f, 0.102783f, 0.107910f, 0.112793f, 0.118164f, 0.123901f, 0.129395f, 0.135132f, 0.140991f,
+ 0.147339f, 0.152954f, 0.159302f, 0.165527f, 0.172363f, 0.178589f, 0.185425f, 0.191895f, 0.199219f, 0.206665f, 0.213989f, 0.221069f,
+ 0.228516f, 0.236206f, 0.243042f, 0.251709f, 0.258789f, 0.266846f, 0.275146f, 0.283203f, 0.291260f, 0.300537f, 0.308350f, 0.317627f,
+ 0.326904f, 0.335938f, 0.611816f, 0.625000f, 0.624023f, 0.620117f, 0.616211f, 0.612793f, 0.001965f, 0.005882f, 0.009613f, 0.013184f,
+ 0.016785f, 0.020370f, 0.024384f, 0.027664f, 0.031311f, 0.035126f, 0.038727f, 0.042572f, 0.046112f, 0.049347f, 0.053253f, 0.056915f,
+ 0.060883f, 0.064697f, 0.068909f, 0.072693f, 0.076843f, 0.081055f, 0.085754f, 0.090088f, 0.094849f, 0.099609f, 0.104614f, 0.109741f,
+ 0.114746f, 0.119995f, 0.125488f, 0.130981f, 0.136719f, 0.142700f, 0.148315f, 0.154541f, 0.160522f, 0.166870f, 0.173828f, 0.179932f,
+ 0.186768f, 0.193604f, 0.200439f, 0.207764f, 0.214844f, 0.221802f, 0.228882f, 0.236328f, 0.244385f, 0.252197f, 0.259277f, 0.268066f,
+ 0.275635f, 0.283447f, 0.292236f, 0.301270f, 0.309570f, 0.318848f, 0.600098f, 0.616211f, 0.615234f, 0.612793f, 0.609375f, 0.605469f,
+ 0.001966f, 0.005653f, 0.009109f, 0.012428f, 0.015945f, 0.018967f, 0.022537f, 0.025894f, 0.029175f, 0.032440f, 0.035797f, 0.038818f,
+ 0.042389f, 0.046051f, 0.049072f, 0.052521f, 0.056335f, 0.059906f, 0.063293f, 0.067017f, 0.070923f, 0.075134f, 0.078979f, 0.083496f,
+ 0.087646f, 0.091980f, 0.096619f, 0.101196f, 0.105957f, 0.111145f, 0.116028f, 0.121277f, 0.126831f, 0.132080f, 0.137817f, 0.143311f,
+ 0.149780f, 0.155029f, 0.161621f, 0.167847f, 0.173950f, 0.180786f, 0.187622f, 0.194214f, 0.201050f, 0.207764f, 0.215210f, 0.222046f,
+ 0.229370f, 0.236816f, 0.244751f, 0.251953f, 0.260010f, 0.268311f, 0.276123f, 0.284180f, 0.293213f, 0.301514f, 0.588379f, 0.606934f,
+ 0.607422f, 0.604980f, 0.602051f, 0.599609f, 0.001963f, 0.005333f, 0.008377f, 0.011589f, 0.014450f, 0.017593f, 0.021133f, 0.023972f,
+ 0.027145f, 0.030075f, 0.033295f, 0.035858f, 0.038818f, 0.041992f, 0.045288f, 0.048279f, 0.051849f, 0.054840f, 0.058289f, 0.061737f,
+ 0.065186f, 0.068848f, 0.072632f, 0.076721f, 0.080505f, 0.084717f, 0.088806f, 0.093079f, 0.097717f, 0.102356f, 0.106934f, 0.111755f,
+ 0.116882f, 0.121887f, 0.127319f, 0.132935f, 0.138306f, 0.144287f, 0.149902f, 0.156250f, 0.162109f, 0.168579f, 0.174316f, 0.180908f,
+ 0.187500f, 0.194458f, 0.201538f, 0.208252f, 0.215210f, 0.222656f, 0.229980f, 0.237061f, 0.244629f, 0.252441f, 0.260254f, 0.267334f,
+ 0.276123f, 0.284180f, 0.576660f, 0.597656f, 0.599609f, 0.598145f, 0.595215f, 0.591797f, 0.001631f, 0.004906f, 0.007805f, 0.010826f,
+ 0.013802f, 0.016983f, 0.019485f, 0.022079f, 0.024750f, 0.027939f, 0.030136f, 0.033112f, 0.035797f, 0.038727f, 0.041443f, 0.044281f,
+ 0.047058f, 0.050018f, 0.053253f, 0.056396f, 0.059662f, 0.063049f, 0.066406f, 0.069946f, 0.073730f, 0.077454f, 0.081360f, 0.085388f,
+ 0.089417f, 0.093750f, 0.098267f, 0.102844f, 0.107727f, 0.112244f, 0.117615f, 0.122253f, 0.127441f, 0.133057f, 0.138550f, 0.144287f,
+ 0.150024f, 0.156250f, 0.161987f, 0.167969f, 0.174805f, 0.181274f, 0.187744f, 0.194580f, 0.201294f, 0.208374f, 0.215210f, 0.222412f,
+ 0.229736f, 0.237183f, 0.244629f, 0.252197f, 0.260010f, 0.269287f, 0.566406f, 0.588867f, 0.590820f, 0.590332f, 0.587891f, 0.585938f,
+ 0.001858f, 0.004318f, 0.007465f, 0.010246f, 0.012550f, 0.015793f, 0.018143f, 0.020782f, 0.022980f, 0.025116f, 0.027924f, 0.030106f,
+ 0.032623f, 0.035126f, 0.037720f, 0.040283f, 0.042847f, 0.045380f, 0.048492f, 0.051300f, 0.054321f, 0.057373f, 0.060516f, 0.063599f,
+ 0.067139f, 0.070496f, 0.074219f, 0.078003f, 0.081848f, 0.085754f, 0.089783f, 0.093994f, 0.098267f, 0.102783f, 0.107239f, 0.112366f,
+ 0.117371f, 0.122498f, 0.127686f, 0.132935f, 0.138428f, 0.144043f, 0.150024f, 0.155884f, 0.161865f, 0.168091f, 0.174316f, 0.180664f,
+ 0.187622f, 0.194214f, 0.200928f, 0.207520f, 0.214966f, 0.221680f, 0.229370f, 0.236816f, 0.244751f, 0.252441f, 0.553223f, 0.579102f,
+ 0.583496f, 0.582031f, 0.581055f, 0.579590f, 0.001425f, 0.004284f, 0.007019f, 0.009521f, 0.011894f, 0.014191f, 0.016632f, 0.018723f,
+ 0.021210f, 0.023209f, 0.025482f, 0.027344f, 0.029617f, 0.032043f, 0.034210f, 0.036407f, 0.039001f, 0.041077f, 0.043976f, 0.046448f,
+ 0.049133f, 0.051819f, 0.054932f, 0.057770f, 0.060730f, 0.063965f, 0.067322f, 0.070862f, 0.074280f, 0.077698f, 0.082031f, 0.085571f,
+ 0.089844f, 0.093994f, 0.098022f, 0.102722f, 0.107178f, 0.111877f, 0.116821f, 0.121887f, 0.127075f, 0.132446f, 0.138062f, 0.143799f,
+ 0.149414f, 0.155518f, 0.161377f, 0.167480f, 0.173950f, 0.180176f, 0.186890f, 0.193481f, 0.200562f, 0.207397f, 0.214355f, 0.221313f,
+ 0.229492f, 0.237427f, 0.541504f, 0.570801f, 0.575195f, 0.575195f, 0.573730f, 0.572266f, 0.001613f, 0.004181f, 0.006252f, 0.008774f,
+ 0.011108f, 0.013054f, 0.015152f, 0.016937f, 0.019150f, 0.021011f, 0.023163f, 0.024826f, 0.026993f, 0.028793f, 0.030823f, 0.033081f,
+ 0.035156f, 0.037201f, 0.039612f, 0.041748f, 0.044464f, 0.046814f, 0.049438f, 0.052155f, 0.054840f, 0.057831f, 0.060699f, 0.063599f,
+ 0.067078f, 0.070374f, 0.073853f, 0.077087f, 0.081177f, 0.085083f, 0.089111f, 0.093262f, 0.097473f, 0.101929f, 0.106689f, 0.111023f,
+ 0.116455f, 0.121277f, 0.126343f, 0.132080f, 0.137573f, 0.142700f, 0.148682f, 0.154907f, 0.161133f, 0.167236f, 0.173340f, 0.179688f,
+ 0.186768f, 0.193115f, 0.200684f, 0.207275f, 0.214233f, 0.221924f, 0.530273f, 0.561523f, 0.565430f, 0.567383f, 0.564941f, 0.564941f,
+ 0.001237f, 0.003775f, 0.006348f, 0.008141f, 0.010117f, 0.012184f, 0.013763f, 0.015656f, 0.017319f, 0.018967f, 0.020645f, 0.022507f,
+ 0.023926f, 0.025757f, 0.027573f, 0.029449f, 0.031677f, 0.033325f, 0.035645f, 0.037659f, 0.039734f, 0.041809f, 0.044189f, 0.046692f,
+ 0.049133f, 0.051697f, 0.054504f, 0.057251f, 0.060059f, 0.063110f, 0.066467f, 0.069763f, 0.072937f, 0.076477f, 0.080505f, 0.084290f,
+ 0.088013f, 0.092407f, 0.096436f, 0.101013f, 0.105713f, 0.110352f, 0.115356f, 0.120605f, 0.125488f, 0.130981f, 0.136353f, 0.142090f,
+ 0.148438f, 0.153931f, 0.159912f, 0.166260f, 0.172485f, 0.179321f, 0.185791f, 0.193115f, 0.199463f, 0.206665f, 0.520020f, 0.552246f,
+ 0.558105f, 0.559570f, 0.559082f, 0.557617f, 0.001151f, 0.003399f, 0.005611f, 0.007439f, 0.009354f, 0.010925f, 0.012489f, 0.014061f,
+ 0.015610f, 0.017258f, 0.018845f, 0.020248f, 0.021484f, 0.023193f, 0.024796f, 0.026459f, 0.028183f, 0.029785f, 0.031738f, 0.033386f,
+ 0.035309f, 0.037384f, 0.039368f, 0.041626f, 0.043701f, 0.046204f, 0.048553f, 0.051178f, 0.053955f, 0.056488f, 0.059418f, 0.062256f,
+ 0.065308f, 0.068542f, 0.071899f, 0.075623f, 0.079224f, 0.082947f, 0.087097f, 0.091064f, 0.095520f, 0.099854f, 0.104736f, 0.109314f,
+ 0.114136f, 0.119324f, 0.124756f, 0.130127f, 0.135498f, 0.141113f, 0.146973f, 0.153198f, 0.159180f, 0.165527f, 0.172241f, 0.178711f,
+ 0.185425f, 0.192749f, 0.507324f, 0.543945f, 0.549316f, 0.552246f, 0.551270f, 0.551270f, 0.001070f, 0.002996f, 0.004986f, 0.006851f,
+ 0.008514f, 0.009850f, 0.011330f, 0.012596f, 0.014015f, 0.015259f, 0.016586f, 0.017731f, 0.019287f, 0.020676f, 0.022079f, 0.023468f,
+ 0.024765f, 0.026489f, 0.028030f, 0.029465f, 0.031311f, 0.032898f, 0.034851f, 0.036743f, 0.038940f, 0.040833f, 0.043091f, 0.045074f,
+ 0.047729f, 0.050079f, 0.052673f, 0.055389f, 0.058136f, 0.061188f, 0.064087f, 0.067261f, 0.070618f, 0.074158f, 0.077942f, 0.081726f,
+ 0.085815f, 0.089783f, 0.094055f, 0.098572f, 0.103088f, 0.107971f, 0.113037f, 0.118164f, 0.123413f, 0.128784f, 0.134521f, 0.140137f,
+ 0.146118f, 0.152100f, 0.158325f, 0.164307f, 0.171387f, 0.177368f, 0.496094f, 0.534668f, 0.541992f, 0.543945f, 0.544434f, 0.544434f,
+ 0.001086f, 0.003069f, 0.004463f, 0.006256f, 0.007393f, 0.009026f, 0.010178f, 0.011276f, 0.012260f, 0.013542f, 0.014648f, 0.015808f,
+ 0.016861f, 0.017899f, 0.019333f, 0.020599f, 0.021942f, 0.023117f, 0.024384f, 0.025833f, 0.027344f, 0.028992f, 0.030579f, 0.032318f,
+ 0.034149f, 0.035828f, 0.037842f, 0.039764f, 0.041901f, 0.044037f, 0.046539f, 0.048645f, 0.051147f, 0.053894f, 0.056641f, 0.059631f,
+ 0.062500f, 0.065735f, 0.069031f, 0.072754f, 0.076294f, 0.080139f, 0.083984f, 0.088379f, 0.092712f, 0.097229f, 0.101929f, 0.106873f,
+ 0.111694f, 0.117004f, 0.122314f, 0.127930f, 0.133789f, 0.139282f, 0.145142f, 0.151367f, 0.157349f, 0.163818f, 0.484619f, 0.525391f,
+ 0.534180f, 0.536621f, 0.536133f, 0.536621f, 0.001125f, 0.002892f, 0.003883f, 0.005867f, 0.006603f, 0.007935f, 0.009026f, 0.009911f,
+ 0.010956f, 0.012077f, 0.012909f, 0.013901f, 0.014977f, 0.015671f, 0.016983f, 0.018021f, 0.019058f, 0.020279f, 0.021225f, 0.022598f,
+ 0.023941f, 0.025299f, 0.026535f, 0.028107f, 0.029755f, 0.031113f, 0.033020f, 0.034668f, 0.036682f, 0.038483f, 0.040527f, 0.042511f,
+ 0.044708f, 0.046936f, 0.049744f, 0.052216f, 0.054840f, 0.057800f, 0.060791f, 0.064087f, 0.067505f, 0.071045f, 0.074463f, 0.078491f,
+ 0.082397f, 0.086609f, 0.091248f, 0.095581f, 0.100342f, 0.105530f, 0.110474f, 0.116272f, 0.120972f, 0.126953f, 0.132812f, 0.138672f,
+ 0.144287f, 0.150513f, 0.472412f, 0.516113f, 0.524902f, 0.528809f, 0.529785f, 0.529785f, 0.000859f, 0.002470f, 0.003815f, 0.005226f,
+ 0.005913f, 0.007206f, 0.007942f, 0.008652f, 0.009583f, 0.010406f, 0.011223f, 0.011971f, 0.012856f, 0.013664f, 0.014664f, 0.015549f,
+ 0.016464f, 0.017487f, 0.018478f, 0.019592f, 0.020767f, 0.021774f, 0.023117f, 0.024338f, 0.025604f, 0.027008f, 0.028519f, 0.029953f,
+ 0.031525f, 0.033173f, 0.034943f, 0.036865f, 0.038696f, 0.040863f, 0.042969f, 0.045471f, 0.048004f, 0.050293f, 0.052979f, 0.055847f,
+ 0.058960f, 0.062042f, 0.065491f, 0.069153f, 0.072937f, 0.076660f, 0.080750f, 0.085144f, 0.089539f, 0.094177f, 0.099304f, 0.104187f,
+ 0.109741f, 0.114807f, 0.120483f, 0.125977f, 0.131836f, 0.138306f, 0.460449f, 0.507812f, 0.516602f, 0.520020f, 0.522461f, 0.522949f,
+ 0.000906f, 0.002359f, 0.003643f, 0.004356f, 0.005310f, 0.005989f, 0.007030f, 0.007507f, 0.008255f, 0.009010f, 0.009834f, 0.010483f,
+ 0.011230f, 0.011887f, 0.012573f, 0.013367f, 0.014252f, 0.014954f, 0.015900f, 0.016785f, 0.017776f, 0.018631f, 0.019775f, 0.020874f,
+ 0.022110f, 0.023117f, 0.024368f, 0.025589f, 0.026932f, 0.028549f, 0.029938f, 0.031525f, 0.033325f, 0.035187f, 0.037109f, 0.038971f,
+ 0.041138f, 0.043396f, 0.045715f, 0.048370f, 0.051025f, 0.053772f, 0.057129f, 0.060089f, 0.063416f, 0.067261f, 0.070679f, 0.075012f,
+ 0.079285f, 0.083618f, 0.088379f, 0.093018f, 0.098083f, 0.102478f, 0.108093f, 0.114380f, 0.119507f, 0.125488f, 0.448975f, 0.498291f,
+ 0.508789f, 0.513672f, 0.514648f, 0.516113f, 0.000728f, 0.001932f, 0.003067f, 0.003990f, 0.004784f, 0.005295f, 0.005974f, 0.006584f,
+ 0.007099f, 0.007652f, 0.008255f, 0.008904f, 0.009491f, 0.010109f, 0.010658f, 0.011497f, 0.012131f, 0.012718f, 0.013535f, 0.014336f,
+ 0.015083f, 0.016083f, 0.016785f, 0.017761f, 0.018738f, 0.019669f, 0.020691f, 0.021805f, 0.023010f, 0.024170f, 0.025467f, 0.026794f,
+ 0.028336f, 0.029922f, 0.031555f, 0.033203f, 0.035034f, 0.036987f, 0.039062f, 0.041290f, 0.043671f, 0.046143f, 0.048920f, 0.051880f,
+ 0.054901f, 0.058228f, 0.061615f, 0.065369f, 0.069214f, 0.073425f, 0.077637f, 0.082214f, 0.087097f, 0.091797f, 0.096497f, 0.102356f,
+ 0.107483f, 0.113464f, 0.437256f, 0.489746f, 0.500977f, 0.504883f, 0.507812f, 0.509277f, 0.000724f, 0.001842f, 0.002728f, 0.003332f,
+ 0.004101f, 0.004707f, 0.005020f, 0.005497f, 0.006245f, 0.006603f, 0.007027f, 0.007515f, 0.008156f, 0.008537f, 0.009125f, 0.009659f,
+ 0.010101f, 0.010864f, 0.011482f, 0.012070f, 0.012756f, 0.013496f, 0.014236f, 0.014931f, 0.015808f, 0.016632f, 0.017487f, 0.018433f,
+ 0.019379f, 0.020416f, 0.021530f, 0.022583f, 0.023804f, 0.024979f, 0.026443f, 0.027939f, 0.029526f, 0.031235f, 0.033020f, 0.035004f,
+ 0.037018f, 0.039185f, 0.041595f, 0.044159f, 0.046783f, 0.049866f, 0.052856f, 0.056274f, 0.059906f, 0.063721f, 0.067749f, 0.072327f,
+ 0.076172f, 0.081299f, 0.085938f, 0.091309f, 0.096558f, 0.101807f, 0.426270f, 0.480469f, 0.492676f, 0.498047f, 0.500488f, 0.501953f,
+ 0.000673f, 0.001715f, 0.002426f, 0.002953f, 0.003588f, 0.003944f, 0.004200f, 0.004776f, 0.005131f, 0.005527f, 0.005886f, 0.006371f,
+ 0.006790f, 0.007076f, 0.007538f, 0.008133f, 0.008644f, 0.009140f, 0.009483f, 0.010071f, 0.010689f, 0.011230f, 0.011879f, 0.012474f,
+ 0.013222f, 0.013916f, 0.014587f, 0.015411f, 0.016190f, 0.016983f, 0.017883f, 0.018845f, 0.019867f, 0.020935f, 0.022141f, 0.023270f,
+ 0.024567f, 0.026001f, 0.027481f, 0.029114f, 0.030777f, 0.032684f, 0.034698f, 0.036865f, 0.039337f, 0.041748f, 0.044647f, 0.047882f,
+ 0.050964f, 0.054260f, 0.058258f, 0.062195f, 0.066528f, 0.070679f, 0.075623f, 0.080505f, 0.085510f, 0.090515f, 0.414307f, 0.472168f,
+ 0.484131f, 0.490234f, 0.492920f, 0.495850f, 0.000484f, 0.001445f, 0.002169f, 0.002569f, 0.002836f, 0.003317f, 0.003569f, 0.003952f,
+ 0.004215f, 0.004623f, 0.004959f, 0.005306f, 0.005592f, 0.005951f, 0.006306f, 0.006737f, 0.007004f, 0.007492f, 0.007942f, 0.008331f,
+ 0.008865f, 0.009270f, 0.009781f, 0.010338f, 0.010887f, 0.011429f, 0.012047f, 0.012726f, 0.013336f, 0.014030f, 0.014771f, 0.015572f,
+ 0.016418f, 0.017258f, 0.018234f, 0.019196f, 0.020279f, 0.021423f, 0.022675f, 0.023987f, 0.025375f, 0.027039f, 0.028702f, 0.030563f,
+ 0.032623f, 0.034698f, 0.037262f, 0.040039f, 0.042664f, 0.046051f, 0.049194f, 0.052948f, 0.057129f, 0.061371f, 0.065613f, 0.070007f,
+ 0.075317f, 0.080200f, 0.402588f, 0.462402f, 0.476807f, 0.482666f, 0.485107f, 0.487061f, 0.000459f, 0.001265f, 0.001572f, 0.002138f,
+ 0.002365f, 0.002775f, 0.002920f, 0.003189f, 0.003454f, 0.003723f, 0.003986f, 0.004250f, 0.004536f, 0.004906f, 0.005150f, 0.005463f,
+ 0.005787f, 0.006172f, 0.006481f, 0.006794f, 0.007156f, 0.007542f, 0.007980f, 0.008430f, 0.008827f, 0.009361f, 0.009796f, 0.010300f,
+ 0.010910f, 0.011497f, 0.012161f, 0.012672f, 0.013336f, 0.014183f, 0.014893f, 0.015640f, 0.016541f, 0.017517f, 0.018448f, 0.019485f,
+ 0.020676f, 0.021912f, 0.023392f, 0.024979f, 0.026627f, 0.028351f, 0.030457f, 0.032806f, 0.035034f, 0.037933f, 0.041229f, 0.044373f,
+ 0.047821f, 0.052002f, 0.056244f, 0.060547f, 0.065247f, 0.069885f, 0.390869f, 0.453857f, 0.468018f, 0.475098f, 0.478027f, 0.480469f,
+ 0.000332f, 0.001075f, 0.001464f, 0.001721f, 0.001911f, 0.002235f, 0.002375f, 0.002558f, 0.002834f, 0.002998f, 0.003185f, 0.003441f,
+ 0.003647f, 0.003952f, 0.004139f, 0.004421f, 0.004631f, 0.004879f, 0.005180f, 0.005447f, 0.005795f, 0.006115f, 0.006416f, 0.006718f,
+ 0.007099f, 0.007462f, 0.007881f, 0.008331f, 0.008797f, 0.009140f, 0.009735f, 0.010223f, 0.010803f, 0.011337f, 0.011986f, 0.012611f,
+ 0.013283f, 0.014076f, 0.014847f, 0.015732f, 0.016693f, 0.017700f, 0.018784f, 0.019897f, 0.021317f, 0.022873f, 0.024429f, 0.026306f,
+ 0.028473f, 0.030960f, 0.033600f, 0.036407f, 0.039856f, 0.043549f, 0.047119f, 0.051392f, 0.055969f, 0.060394f, 0.379639f, 0.444580f,
+ 0.458984f, 0.467529f, 0.470947f, 0.472900f, 0.000408f, 0.000770f, 0.001271f, 0.001390f, 0.001601f, 0.001762f, 0.001848f, 0.002052f,
+ 0.002247f, 0.002401f, 0.002491f, 0.002684f, 0.002878f, 0.003086f, 0.003304f, 0.003452f, 0.003626f, 0.003805f, 0.004074f, 0.004257f,
+ 0.004513f, 0.004807f, 0.005039f, 0.005299f, 0.005638f, 0.005905f, 0.006191f, 0.006516f, 0.006927f, 0.007206f, 0.007645f, 0.008034f,
+ 0.008415f, 0.008911f, 0.009384f, 0.009941f, 0.010483f, 0.011116f, 0.011711f, 0.012428f, 0.013191f, 0.013969f, 0.014862f, 0.015854f,
+ 0.016785f, 0.017975f, 0.019348f, 0.020721f, 0.022461f, 0.024445f, 0.026733f, 0.029175f, 0.032227f, 0.035248f, 0.038788f, 0.042755f,
+ 0.046967f, 0.051636f, 0.367920f, 0.435059f, 0.452148f, 0.459229f, 0.463623f, 0.466797f, 0.000382f, 0.000669f, 0.001037f, 0.001185f,
+ 0.001293f, 0.001379f, 0.001470f, 0.001565f, 0.001729f, 0.001864f, 0.001928f, 0.002138f, 0.002237f, 0.002398f, 0.002510f, 0.002672f,
+ 0.002802f, 0.002966f, 0.003134f, 0.003319f, 0.003517f, 0.003723f, 0.003870f, 0.004089f, 0.004311f, 0.004532f, 0.004772f, 0.005013f,
+ 0.005314f, 0.005573f, 0.005924f, 0.006203f, 0.006523f, 0.006897f, 0.007240f, 0.007660f, 0.008041f, 0.008530f, 0.009048f, 0.009621f,
+ 0.010201f, 0.010841f, 0.011467f, 0.012192f, 0.013138f, 0.013969f, 0.014931f, 0.016113f, 0.017380f, 0.018936f, 0.020630f, 0.022751f,
+ 0.025208f, 0.027924f, 0.031311f, 0.034851f, 0.038879f, 0.043274f, 0.356689f, 0.426270f, 0.443848f, 0.451660f, 0.456055f, 0.459473f,
+ 0.000482f, 0.000542f, 0.000723f, 0.000822f, 0.000881f, 0.001025f, 0.001100f, 0.001209f, 0.001249f, 0.001355f, 0.001522f, 0.001599f,
+ 0.001708f, 0.001836f, 0.001918f, 0.001970f, 0.002129f, 0.002251f, 0.002357f, 0.002522f, 0.002636f, 0.002768f, 0.002911f, 0.003056f,
+ 0.003237f, 0.003393f, 0.003605f, 0.003771f, 0.003994f, 0.004234f, 0.004444f, 0.004635f, 0.004932f, 0.005150f, 0.005486f, 0.005779f,
+ 0.006081f, 0.006458f, 0.006775f, 0.007179f, 0.007668f, 0.008110f, 0.008690f, 0.009209f, 0.009926f, 0.010551f, 0.011330f, 0.012184f,
+ 0.013184f, 0.014297f, 0.015610f, 0.017181f, 0.019165f, 0.021500f, 0.024384f, 0.027618f, 0.031372f, 0.035614f, 0.345459f, 0.417236f,
+ 0.435303f, 0.443604f, 0.448730f, 0.451904f, 0.000240f, 0.000479f, 0.000533f, 0.000625f, 0.000716f, 0.000746f, 0.000857f, 0.000835f,
+ 0.000941f, 0.001024f, 0.001104f, 0.001155f, 0.001204f, 0.001282f, 0.001396f, 0.001453f, 0.001554f, 0.001627f, 0.001737f, 0.001787f,
+ 0.001894f, 0.002012f, 0.002119f, 0.002218f, 0.002335f, 0.002453f, 0.002611f, 0.002714f, 0.002848f, 0.003050f, 0.003168f, 0.003395f,
+ 0.003529f, 0.003740f, 0.003963f, 0.004158f, 0.004429f, 0.004688f, 0.004982f, 0.005280f, 0.005600f, 0.005959f, 0.006340f, 0.006775f,
+ 0.007252f, 0.007748f, 0.008369f, 0.008980f, 0.009705f, 0.010513f, 0.011513f, 0.012665f, 0.014069f, 0.015869f, 0.018158f, 0.020950f,
+ 0.024338f, 0.028366f, 0.335205f, 0.408203f, 0.427002f, 0.435547f, 0.441162f, 0.445312f, 0.000138f, 0.000265f, 0.000381f, 0.000386f,
+ 0.000465f, 0.000556f, 0.000558f, 0.000597f, 0.000659f, 0.000748f, 0.000770f, 0.000786f, 0.000829f, 0.000904f, 0.000940f, 0.001021f,
+ 0.001043f, 0.001139f, 0.001201f, 0.001253f, 0.001327f, 0.001396f, 0.001481f, 0.001555f, 0.001637f, 0.001712f, 0.001813f, 0.001899f,
+ 0.002005f, 0.002140f, 0.002220f, 0.002348f, 0.002462f, 0.002600f, 0.002733f, 0.002932f, 0.003075f, 0.003279f, 0.003452f, 0.003630f,
+ 0.003872f, 0.004166f, 0.004436f, 0.004742f, 0.005077f, 0.005459f, 0.005848f, 0.006310f, 0.006874f, 0.007492f, 0.008171f, 0.009026f,
+ 0.009995f, 0.011307f, 0.013008f, 0.015343f, 0.018265f, 0.021881f, 0.323486f, 0.399170f, 0.418945f, 0.428467f, 0.434326f, 0.437988f,
+ 0.000165f, 0.000260f, 0.000287f, 0.000296f, 0.000331f, 0.000339f, 0.000360f, 0.000395f, 0.000442f, 0.000482f, 0.000487f, 0.000551f,
+ 0.000546f, 0.000611f, 0.000640f, 0.000667f, 0.000711f, 0.000742f, 0.000775f, 0.000816f, 0.000876f, 0.000916f, 0.000974f, 0.001015f,
+ 0.001081f, 0.001123f, 0.001195f, 0.001267f, 0.001317f, 0.001388f, 0.001459f, 0.001558f, 0.001630f, 0.001718f, 0.001804f, 0.001916f,
+ 0.002033f, 0.002148f, 0.002295f, 0.002455f, 0.002583f, 0.002754f, 0.002941f, 0.003134f, 0.003386f, 0.003639f, 0.003910f, 0.004215f,
+ 0.004597f, 0.005013f, 0.005520f, 0.006130f, 0.006821f, 0.007690f, 0.008789f, 0.010452f, 0.012909f, 0.016174f, 0.312012f, 0.390381f,
+ 0.410645f, 0.420654f, 0.426270f, 0.430664f, 0.000057f, 0.000171f, 0.000164f, 0.000170f, 0.000211f, 0.000213f, 0.000229f, 0.000247f,
+ 0.000267f, 0.000279f, 0.000289f, 0.000317f, 0.000349f, 0.000364f, 0.000390f, 0.000407f, 0.000427f, 0.000467f, 0.000476f, 0.000521f,
+ 0.000537f, 0.000561f, 0.000578f, 0.000626f, 0.000667f, 0.000714f, 0.000729f, 0.000753f, 0.000806f, 0.000855f, 0.000911f, 0.000945f,
+ 0.001004f, 0.001054f, 0.001112f, 0.001172f, 0.001251f, 0.001333f, 0.001406f, 0.001489f, 0.001595f, 0.001694f, 0.001811f, 0.001952f,
+ 0.002090f, 0.002243f, 0.002453f, 0.002638f, 0.002888f, 0.003143f, 0.003489f, 0.003870f, 0.004353f, 0.004921f, 0.005672f, 0.006664f,
+ 0.008423f, 0.011230f, 0.301758f, 0.381104f, 0.402832f, 0.413330f, 0.418457f, 0.423828f, 0.000096f, 0.000112f, 0.000097f, 0.000090f,
+ 0.000113f, 0.000119f, 0.000144f, 0.000149f, 0.000151f, 0.000158f, 0.000181f, 0.000184f, 0.000179f, 0.000201f, 0.000224f, 0.000216f,
+ 0.000237f, 0.000255f, 0.000263f, 0.000276f, 0.000297f, 0.000308f, 0.000332f, 0.000347f, 0.000369f, 0.000395f, 0.000408f, 0.000422f,
+ 0.000447f, 0.000471f, 0.000500f, 0.000531f, 0.000554f, 0.000583f, 0.000617f, 0.000660f, 0.000690f, 0.000739f, 0.000795f, 0.000833f,
+ 0.000885f, 0.000948f, 0.001022f, 0.001085f, 0.001175f, 0.001262f, 0.001371f, 0.001487f, 0.001633f, 0.001778f, 0.001986f, 0.002218f,
+ 0.002502f, 0.002865f, 0.003330f, 0.003979f, 0.004932f, 0.007000f, 0.291260f, 0.372070f, 0.394043f, 0.404541f, 0.412109f, 0.416260f,
+ 0.000000f, 0.000056f, 0.000049f, 0.000061f, 0.000064f, 0.000061f, 0.000062f, 0.000071f, 0.000072f, 0.000088f, 0.000083f, 0.000086f,
+ 0.000097f, 0.000094f, 0.000098f, 0.000105f, 0.000116f, 0.000122f, 0.000126f, 0.000134f, 0.000137f, 0.000143f, 0.000150f, 0.000164f,
+ 0.000171f, 0.000183f, 0.000188f, 0.000204f, 0.000214f, 0.000224f, 0.000236f, 0.000255f, 0.000258f, 0.000277f, 0.000293f, 0.000315f,
+ 0.000328f, 0.000349f, 0.000376f, 0.000396f, 0.000426f, 0.000454f, 0.000486f, 0.000521f, 0.000563f, 0.000605f, 0.000657f, 0.000714f,
+ 0.000791f, 0.000866f, 0.000977f, 0.001085f, 0.001243f, 0.001441f, 0.001703f, 0.002058f, 0.002573f, 0.003740f, 0.280029f, 0.362793f,
+ 0.385742f, 0.397217f, 0.404297f, 0.408936f, 0.000058f, 0.000038f, 0.000031f, 0.000027f, 0.000025f, 0.000026f, 0.000025f, 0.000024f,
+ 0.000024f, 0.000027f, 0.000030f, 0.000038f, 0.000032f, 0.000035f, 0.000040f, 0.000041f, 0.000044f, 0.000045f, 0.000045f, 0.000047f,
+ 0.000052f, 0.000058f, 0.000061f, 0.000059f, 0.000065f, 0.000067f, 0.000069f, 0.000073f, 0.000078f, 0.000083f, 0.000089f, 0.000091f,
+ 0.000099f, 0.000103f, 0.000106f, 0.000114f, 0.000124f, 0.000132f, 0.000141f, 0.000150f, 0.000158f, 0.000164f, 0.000180f, 0.000193f,
+ 0.000205f, 0.000225f, 0.000245f, 0.000267f, 0.000297f, 0.000329f, 0.000365f, 0.000416f, 0.000479f, 0.000563f, 0.000676f, 0.000839f,
+ 0.001088f, 0.001589f, 0.270264f, 0.353760f, 0.377197f, 0.390137f, 0.396973f, 0.402100f, 0.000030f, 0.000019f, 0.000016f, 0.000014f,
+ 0.000013f, 0.000012f, 0.000011f, 0.000011f, 0.000010f, 0.000010f, 0.000009f, 0.000009f, 0.000009f, 0.000008f, 0.000007f, 0.000009f,
+ 0.000009f, 0.000008f, 0.000009f, 0.000010f, 0.000011f, 0.000012f, 0.000012f, 0.000014f, 0.000014f, 0.000014f, 0.000015f, 0.000018f,
+ 0.000017f, 0.000017f, 0.000019f, 0.000020f, 0.000022f, 0.000022f, 0.000023f, 0.000026f, 0.000028f, 0.000027f, 0.000030f, 0.000032f,
+ 0.000035f, 0.000038f, 0.000040f, 0.000042f, 0.000045f, 0.000049f, 0.000055f, 0.000060f, 0.000065f, 0.000074f, 0.000078f, 0.000095f,
+ 0.000109f, 0.000129f, 0.000160f, 0.000205f, 0.000284f, 0.000452f, 0.259766f, 0.345703f, 0.369629f, 0.382812f, 0.390625f, 0.395264f,
+ 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f,
+ 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000001f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f, 0.000002f,
+ 0.000002f, 0.000003f, 0.000003f, 0.000004f, 0.000004f, 0.000005f, 0.000006f, 0.000009f, 0.000012f, 0.000026f, 0.249878f, 0.336182f,
+ 0.362061f, 0.374512f, 0.382080f, 0.387695f,
+ }
+};
+
+/* 4 different blue noise, one per channel */
+static float blue_noise[64 * 64][4] = {
+ {0.367188f, 0.855469f, 0.523438f, 0.375000f}, {0.242188f, 0.699219f, 0.164062f, 0.292969f},
+ {0.828125f, 0.257812f, 0.449219f, 0.679688f}, {0.128906f, 0.523438f, 0.058594f, 0.164062f},
+ {0.214844f, 0.648438f, 0.750000f, 0.492188f}, {0.535156f, 0.226562f, 0.492188f, 0.429688f},
+ {0.050781f, 0.425781f, 0.886719f, 0.019531f}, {0.199219f, 0.785156f, 0.378906f, 0.984375f},
+ {0.390625f, 0.039062f, 0.222656f, 0.777344f}, {0.574219f, 0.460938f, 0.687500f, 0.085938f},
+ {0.757812f, 0.117188f, 0.968750f, 0.343750f}, {0.109375f, 0.398438f, 0.500000f, 0.871094f},
+ {0.871094f, 0.796875f, 0.628906f, 0.132812f}, {0.289062f, 0.480469f, 0.851562f, 0.484375f},
+ {0.519531f, 0.035156f, 0.234375f, 0.832031f}, {0.390625f, 0.558594f, 0.738281f, 0.636719f},
+ {0.015625f, 0.648438f, 0.910156f, 0.507812f}, {0.199219f, 0.257812f, 0.640625f, 0.578125f},
+ {0.359375f, 0.976562f, 0.855469f, 0.726562f}, {0.523438f, 0.445312f, 0.335938f, 0.304688f},
+ {0.046875f, 0.296875f, 0.921875f, 0.687500f}, {0.476562f, 0.929688f, 0.777344f, 0.164062f},
+ {0.726562f, 0.515625f, 0.398438f, 0.781250f}, {0.652344f, 0.156250f, 0.191406f, 0.015625f},
+ {0.300781f, 0.695312f, 0.011719f, 0.417969f}, {0.433594f, 0.882812f, 0.738281f, 0.843750f},
+ {0.890625f, 0.308594f, 0.523438f, 0.496094f}, {0.589844f, 0.730469f, 0.050781f, 0.886719f},
+ {0.738281f, 0.539062f, 0.683594f, 0.640625f}, {0.421875f, 0.191406f, 0.265625f, 0.996094f},
+ {0.609375f, 0.339844f, 0.617188f, 0.066406f}, {0.371094f, 0.398438f, 0.378906f, 0.898438f},
+ {0.937500f, 0.578125f, 0.136719f, 0.136719f}, {0.453125f, 0.820312f, 0.664062f, 0.968750f},
+ {0.828125f, 0.070312f, 0.316406f, 0.328125f}, {0.558594f, 0.714844f, 0.593750f, 0.714844f},
+ {0.351562f, 0.781250f, 0.355469f, 0.804688f}, {0.203125f, 0.398438f, 0.214844f, 0.519531f},
+ {0.785156f, 0.207031f, 0.398438f, 0.453125f}, {0.617188f, 0.289062f, 0.281250f, 0.257812f},
+ {0.171875f, 0.609375f, 0.792969f, 0.027344f}, {0.539062f, 0.871094f, 0.007812f, 0.886719f},
+ {0.019531f, 0.246094f, 0.226562f, 0.363281f}, {0.988281f, 0.582031f, 0.777344f, 0.054688f},
+ {0.468750f, 0.933594f, 0.312500f, 0.246094f}, {0.218750f, 0.015625f, 0.851562f, 0.167969f},
+ {0.566406f, 0.699219f, 0.519531f, 0.902344f}, {0.125000f, 0.507812f, 0.136719f, 0.386719f},
+ {0.296875f, 0.812500f, 0.558594f, 0.203125f}, {0.402344f, 0.199219f, 0.058594f, 0.875000f},
+ {0.898438f, 0.386719f, 0.664062f, 0.660156f}, {0.027344f, 0.078125f, 0.296875f, 0.453125f},
+ {0.667969f, 0.828125f, 0.808594f, 0.171875f}, {0.257812f, 0.535156f, 0.464844f, 0.914062f},
+ {0.597656f, 0.363281f, 0.886719f, 0.718750f}, {0.332031f, 0.042969f, 0.683594f, 0.003906f},
+ {0.632812f, 0.480469f, 0.429688f, 0.425781f}, {0.226562f, 0.910156f, 0.566406f, 0.558594f},
+ {0.496094f, 0.062500f, 0.863281f, 0.226562f}, {0.105469f, 0.976562f, 0.707031f, 0.941406f},
+ {0.394531f, 0.203125f, 0.285156f, 0.277344f}, {0.003906f, 0.804688f, 0.781250f, 0.050781f},
+ {0.210938f, 0.289062f, 0.117188f, 0.601562f}, {0.972656f, 0.179688f, 0.589844f, 0.144531f},
+ {0.152344f, 0.359375f, 0.730469f, 0.449219f}, {0.765625f, 0.105469f, 0.292969f, 0.101562f},
+ {0.519531f, 0.812500f, 0.617188f, 0.976562f}, {0.988281f, 0.960938f, 0.902344f, 0.054688f},
+ {0.457031f, 0.738281f, 0.335938f, 0.875000f}, {0.871094f, 0.121094f, 0.195312f, 0.210938f},
+ {0.781250f, 0.296875f, 0.539062f, 0.585938f}, {0.636719f, 0.667969f, 0.621094f, 0.328125f},
+ {0.324219f, 0.929688f, 0.855469f, 0.148438f}, {0.984375f, 0.718750f, 0.421875f, 0.824219f},
+ {0.500000f, 0.308594f, 0.757812f, 0.699219f}, {0.664062f, 0.214844f, 0.269531f, 0.558594f},
+ {0.414062f, 0.984375f, 0.074219f, 0.757812f}, {0.589844f, 0.339844f, 0.925781f, 0.273438f},
+ {0.089844f, 0.847656f, 0.316406f, 0.398438f}, {0.695312f, 0.921875f, 0.460938f, 0.890625f},
+ {0.894531f, 0.093750f, 0.113281f, 0.347656f}, {0.562500f, 0.386719f, 0.289062f, 0.964844f},
+ {0.121094f, 0.820312f, 0.003906f, 0.214844f}, {0.765625f, 0.187500f, 0.710938f, 0.914062f},
+ {0.878906f, 0.773438f, 0.445312f, 0.078125f}, {0.218750f, 0.117188f, 0.613281f, 0.617188f},
+ {0.085938f, 0.652344f, 0.996094f, 0.339844f}, {0.863281f, 0.359375f, 0.496094f, 0.531250f},
+ {0.148438f, 0.437500f, 0.320312f, 0.695312f}, {0.503906f, 0.613281f, 0.792969f, 0.082031f},
+ {0.097656f, 0.109375f, 0.960938f, 0.238281f}, {0.246094f, 0.914062f, 0.414062f, 0.328125f},
+ {0.011719f, 0.648438f, 0.828125f, 0.738281f}, {0.980469f, 0.457031f, 0.343750f, 0.117188f},
+ {0.140625f, 0.937500f, 0.976562f, 0.601562f}, {0.234375f, 0.867188f, 0.574219f, 0.230469f},
+ {0.542969f, 0.519531f, 0.902344f, 0.402344f}, {0.027344f, 0.300781f, 0.253906f, 0.503906f},
+ {0.757812f, 0.964844f, 0.949219f, 0.058594f}, {0.152344f, 0.234375f, 0.039062f, 0.925781f},
+ {0.687500f, 0.628906f, 0.492188f, 0.386719f}, {0.929688f, 0.546875f, 0.667969f, 0.109375f},
+ {0.269531f, 0.136719f, 0.964844f, 0.617188f}, {0.320312f, 0.464844f, 0.542969f, 0.972656f},
+ {0.960938f, 0.960938f, 0.171875f, 0.093750f}, {0.355469f, 0.523438f, 0.429688f, 0.765625f},
+ {0.246094f, 0.328125f, 0.992188f, 0.496094f}, {0.648438f, 0.074219f, 0.097656f, 0.605469f},
+ {0.144531f, 0.648438f, 0.476562f, 0.808594f}, {0.855469f, 0.832031f, 0.195312f, 0.546875f},
+ {0.925781f, 0.414062f, 0.960938f, 0.675781f}, {0.000000f, 0.113281f, 0.746094f, 0.835938f},
+ {0.828125f, 0.324219f, 0.613281f, 0.500000f}, {0.699219f, 0.738281f, 0.332031f, 0.125000f},
+ {0.542969f, 0.906250f, 0.898438f, 0.250000f}, {0.105469f, 0.632812f, 0.511719f, 0.062500f},
+ {0.433594f, 0.273438f, 0.097656f, 0.816406f}, {0.511719f, 0.707031f, 0.593750f, 0.632812f},
+ {0.179688f, 0.980469f, 0.367188f, 0.335938f}, {0.882812f, 0.113281f, 0.031250f, 0.980469f},
+ {0.410156f, 0.656250f, 0.253906f, 0.675781f}, {0.039062f, 0.300781f, 0.785156f, 0.800781f},
+ {0.695312f, 0.382812f, 0.386719f, 0.156250f}, {0.847656f, 0.457031f, 0.000000f, 0.847656f},
+ {0.945312f, 0.542969f, 0.664062f, 0.683594f}, {0.730469f, 0.707031f, 0.238281f, 0.535156f},
+ {0.472656f, 0.921875f, 0.871094f, 0.910156f}, {0.867188f, 0.601562f, 0.031250f, 0.812500f},
+ {0.632812f, 0.769531f, 0.925781f, 0.625000f}, {0.433594f, 0.558594f, 0.078125f, 0.851562f},
+ {0.015625f, 0.187500f, 0.792969f, 0.515625f}, {0.343750f, 0.386719f, 0.562500f, 0.773438f},
+ {0.679688f, 0.035156f, 0.121094f, 0.347656f}, {0.300781f, 0.582031f, 0.703125f, 0.660156f},
+ {0.152344f, 0.878906f, 0.929688f, 0.902344f}, {0.433594f, 0.507812f, 0.093750f, 0.460938f},
+ {0.714844f, 0.171875f, 0.042969f, 0.531250f}, {0.828125f, 0.550781f, 0.312500f, 0.945312f},
+ {0.011719f, 0.894531f, 0.136719f, 0.417969f}, {0.257812f, 0.046875f, 0.562500f, 0.226562f},
+ {0.187500f, 0.601562f, 0.800781f, 0.929688f}, {0.949219f, 0.128906f, 0.437500f, 0.613281f},
+ {0.816406f, 0.277344f, 0.054688f, 0.035156f}, {0.226562f, 0.425781f, 0.542969f, 0.183594f},
+ {0.628906f, 0.750000f, 0.984375f, 0.113281f}, {0.839844f, 0.003906f, 0.792969f, 0.796875f},
+ {0.269531f, 0.324219f, 0.496094f, 0.003906f}, {0.683594f, 0.601562f, 0.574219f, 0.546875f},
+ {0.957031f, 0.703125f, 0.164062f, 0.378906f}, {0.605469f, 0.398438f, 0.078125f, 0.855469f},
+ {0.449219f, 0.250000f, 0.257812f, 0.988281f}, {0.367188f, 0.964844f, 0.859375f, 0.195312f},
+ {0.820312f, 0.007812f, 0.125000f, 0.753906f}, {0.625000f, 0.832031f, 0.453125f, 0.609375f},
+ {0.929688f, 0.230469f, 0.246094f, 0.925781f}, {0.394531f, 0.375000f, 0.097656f, 0.550781f},
+ {0.558594f, 0.148438f, 0.183594f, 0.191406f}, {0.480469f, 0.796875f, 0.488281f, 0.785156f},
+ {0.714844f, 0.250000f, 0.011719f, 0.296875f}, {0.660156f, 0.085938f, 0.804688f, 0.691406f},
+ {0.890625f, 0.695312f, 0.101562f, 0.855469f}, {0.320312f, 0.195312f, 0.441406f, 0.761719f},
+ {0.265625f, 0.375000f, 0.765625f, 0.191406f}, {0.996094f, 0.113281f, 0.832031f, 0.585938f},
+ {0.101562f, 0.882812f, 0.152344f, 0.285156f}, {0.468750f, 0.332031f, 0.722656f, 0.882812f},
+ {0.656250f, 0.816406f, 0.105469f, 0.339844f}, {0.035156f, 0.703125f, 0.855469f, 0.687500f},
+ {0.738281f, 0.003906f, 0.601562f, 0.566406f}, {0.441406f, 0.664062f, 0.703125f, 0.843750f},
+ {0.875000f, 0.789062f, 0.839844f, 0.187500f}, {0.781250f, 0.457031f, 0.640625f, 0.996094f},
+ {0.050781f, 0.210938f, 0.355469f, 0.332031f}, {0.363281f, 0.351562f, 0.039062f, 0.421875f},
+ {0.429688f, 0.550781f, 0.699219f, 0.089844f}, {0.753906f, 0.917969f, 0.269531f, 0.285156f},
+ {0.496094f, 0.058594f, 0.929688f, 0.980469f}, {0.343750f, 0.445312f, 0.445312f, 0.566406f},
+ {0.152344f, 0.160156f, 0.003906f, 0.750000f}, {0.738281f, 0.570312f, 0.847656f, 0.941406f},
+ {0.808594f, 0.027344f, 0.167969f, 0.292969f}, {0.992188f, 0.867188f, 0.921875f, 0.519531f},
+ {0.074219f, 0.187500f, 0.761719f, 0.199219f}, {0.750000f, 0.597656f, 0.312500f, 0.472656f},
+ {0.277344f, 0.753906f, 0.945312f, 0.089844f}, {0.796875f, 0.820312f, 0.511719f, 0.375000f},
+ {0.542969f, 0.878906f, 0.191406f, 0.503906f}, {0.175781f, 0.632812f, 0.597656f, 0.109375f},
+ {0.257812f, 0.335938f, 0.980469f, 0.339844f}, {0.664062f, 0.000000f, 0.542969f, 0.417969f},
+ {0.324219f, 0.144531f, 0.410156f, 0.078125f}, {0.062500f, 0.437500f, 0.472656f, 0.250000f},
+ {0.925781f, 0.058594f, 0.636719f, 0.332031f}, {0.269531f, 0.671875f, 0.234375f, 0.175781f},
+ {0.714844f, 0.285156f, 0.382812f, 0.574219f}, {0.570312f, 0.906250f, 0.988281f, 0.414062f},
+ {0.097656f, 0.460938f, 0.425781f, 0.257812f}, {0.953125f, 0.796875f, 0.265625f, 0.117188f},
+ {0.589844f, 0.367188f, 0.777344f, 0.746094f}, {0.035156f, 0.082031f, 0.457031f, 0.062500f},
+ {0.226562f, 0.253906f, 0.953125f, 0.628906f}, {0.527344f, 0.417969f, 0.519531f, 0.261719f},
+ {0.132812f, 0.812500f, 0.828125f, 0.000000f}, {0.906250f, 0.660156f, 0.386719f, 0.367188f},
+ {0.742188f, 0.500000f, 0.207031f, 0.093750f}, {0.359375f, 0.769531f, 0.609375f, 0.718750f},
+ {0.480469f, 0.695312f, 0.679688f, 0.539062f}, {0.144531f, 0.179688f, 0.757812f, 0.765625f},
+ {0.332031f, 0.625000f, 0.179688f, 0.679688f}, {0.445312f, 0.492188f, 0.378906f, 0.425781f},
+ {0.035156f, 0.550781f, 0.230469f, 0.476562f}, {0.402344f, 0.898438f, 0.898438f, 0.652344f},
+ {0.156250f, 0.046875f, 0.820312f, 0.132812f}, {0.328125f, 0.484375f, 0.679688f, 0.246094f},
+ {0.746094f, 0.750000f, 0.363281f, 0.453125f}, {0.238281f, 0.863281f, 0.558594f, 0.105469f},
+ {0.023438f, 0.289062f, 0.648438f, 0.292969f}, {0.683594f, 0.566406f, 0.906250f, 0.804688f},
+ {0.335938f, 0.773438f, 0.601562f, 0.375000f}, {0.781250f, 0.496094f, 0.710938f, 0.023438f},
+ {0.847656f, 0.996094f, 0.929688f, 0.425781f}, {0.308594f, 0.027344f, 0.656250f, 0.871094f},
+ {0.183594f, 0.625000f, 0.292969f, 0.480469f}, {0.089844f, 0.753906f, 0.164062f, 0.363281f},
+ {0.804688f, 0.476562f, 0.687500f, 0.011719f}, {0.503906f, 0.910156f, 0.523438f, 0.644531f},
+ {0.605469f, 0.609375f, 0.203125f, 0.441406f}, {0.417969f, 0.742188f, 0.621094f, 0.085938f},
+ {0.839844f, 0.441406f, 0.296875f, 0.679688f}, {0.531250f, 0.042969f, 0.929688f, 0.781250f},
+ {0.378906f, 0.929688f, 0.460938f, 0.148438f}, {0.902344f, 0.238281f, 0.050781f, 0.222656f},
+ {0.570312f, 0.378906f, 0.328125f, 0.390625f}, {0.105469f, 0.121094f, 0.253906f, 0.460938f},
+ {0.500000f, 0.906250f, 0.515625f, 0.281250f}, {0.296875f, 0.160156f, 0.148438f, 0.664062f},
+ {0.699219f, 0.722656f, 0.757812f, 0.007812f}, {0.539062f, 0.968750f, 0.589844f, 0.914062f},
+ {0.253906f, 0.246094f, 0.406250f, 0.769531f}, {0.609375f, 0.613281f, 0.105469f, 0.707031f},
+ {0.195312f, 0.687500f, 0.179688f, 0.031250f}, {0.949219f, 0.523438f, 0.785156f, 0.339844f},
+ {0.863281f, 0.804688f, 0.234375f, 0.433594f}, {0.230469f, 0.355469f, 0.648438f, 0.687500f},
+ {0.304688f, 0.757812f, 0.421875f, 0.378906f}, {0.375000f, 0.464844f, 0.539062f, 0.046875f},
+ {0.558594f, 0.324219f, 0.214844f, 0.761719f}, {0.679688f, 0.410156f, 0.074219f, 0.839844f},
+ {0.464844f, 0.519531f, 0.710938f, 0.281250f}, {0.968750f, 0.152344f, 0.140625f, 0.925781f},
+ {0.359375f, 0.230469f, 0.902344f, 0.609375f}, {0.593750f, 0.097656f, 0.457031f, 0.761719f},
+ {0.441406f, 0.785156f, 0.058594f, 0.960938f}, {0.125000f, 0.890625f, 0.312500f, 0.203125f},
+ {0.812500f, 0.488281f, 0.804688f, 0.878906f}, {0.558594f, 0.992188f, 0.175781f, 0.742188f},
+ {0.179688f, 0.222656f, 0.343750f, 0.039062f}, {0.789062f, 0.871094f, 0.843750f, 0.949219f},
+ {0.902344f, 0.503906f, 0.507812f, 0.718750f}, {0.402344f, 0.625000f, 0.027344f, 0.011719f},
+ {0.195312f, 0.152344f, 0.605469f, 0.929688f}, {0.753906f, 0.214844f, 0.160156f, 0.839844f},
+ {0.488281f, 0.687500f, 0.671875f, 0.390625f}, {0.851562f, 0.992188f, 0.363281f, 0.191406f},
+ {0.933594f, 0.617188f, 0.230469f, 0.308594f}, {0.375000f, 0.746094f, 0.656250f, 0.867188f},
+ {0.613281f, 0.105469f, 0.898438f, 0.671875f}, {0.316406f, 0.371094f, 0.714844f, 0.503906f},
+ {0.687500f, 0.234375f, 0.031250f, 0.808594f}, {0.550781f, 0.957031f, 0.957031f, 0.433594f},
+ {0.023438f, 0.539062f, 0.351562f, 0.308594f}, {0.964844f, 0.359375f, 0.261719f, 0.980469f},
+ {0.750000f, 0.941406f, 0.863281f, 0.234375f}, {0.906250f, 0.863281f, 0.605469f, 0.863281f},
+ {0.503906f, 0.109375f, 0.093750f, 0.289062f}, {0.582031f, 0.238281f, 0.414062f, 0.949219f},
+ {0.792969f, 0.992188f, 0.308594f, 0.757812f}, {0.062500f, 0.164062f, 0.039062f, 0.816406f},
+ {0.902344f, 0.542969f, 0.933594f, 0.675781f}, {0.554688f, 0.085938f, 0.726562f, 0.507812f},
+ {0.984375f, 0.460938f, 0.175781f, 0.890625f}, {0.468750f, 0.179688f, 0.027344f, 0.140625f},
+ {0.125000f, 0.679688f, 0.304688f, 0.468750f}, {0.203125f, 0.058594f, 0.531250f, 0.953125f},
+ {0.070312f, 0.328125f, 0.375000f, 0.667969f}, {0.746094f, 0.554688f, 0.785156f, 0.578125f},
+ {0.917969f, 0.421875f, 0.558594f, 0.089844f}, {0.445312f, 0.289062f, 0.855469f, 0.937500f},
+ {0.378906f, 0.156250f, 0.398438f, 0.539062f}, {0.066406f, 0.015625f, 0.335938f, 0.265625f},
+ {0.730469f, 0.812500f, 0.878906f, 0.820312f}, {0.191406f, 0.535156f, 0.015625f, 0.988281f},
+ {0.046875f, 0.171875f, 0.554688f, 0.484375f}, {0.777344f, 0.656250f, 0.375000f, 0.015625f},
+ {0.230469f, 0.488281f, 0.238281f, 0.535156f}, {0.144531f, 0.578125f, 0.750000f, 0.910156f},
+ {0.812500f, 0.757812f, 0.910156f, 0.714844f}, {0.207031f, 0.429688f, 0.386719f, 0.042969f},
+ {0.945312f, 0.292969f, 0.023438f, 0.136719f}, {0.597656f, 0.859375f, 0.941406f, 0.742188f},
+ {0.171875f, 0.593750f, 0.289062f, 0.519531f}, {0.914062f, 0.031250f, 0.886719f, 0.234375f},
+ {0.808594f, 0.773438f, 0.824219f, 0.160156f}, {0.082031f, 0.132812f, 0.496094f, 0.464844f},
+ {0.664062f, 0.871094f, 0.675781f, 0.597656f}, {0.042969f, 0.289062f, 0.546875f, 0.195312f},
+ {0.453125f, 0.996094f, 0.363281f, 0.859375f}, {0.585938f, 0.226562f, 0.718750f, 0.140625f},
+ {0.648438f, 0.093750f, 0.277344f, 0.609375f}, {0.035156f, 0.933594f, 0.980469f, 0.898438f},
+ {0.910156f, 0.671875f, 0.625000f, 0.410156f}, {0.210938f, 0.246094f, 0.472656f, 0.578125f},
+ {0.136719f, 0.960938f, 0.832031f, 0.031250f}, {0.066406f, 0.054688f, 0.656250f, 0.660156f},
+ {0.898438f, 0.714844f, 0.347656f, 0.218750f}, {0.765625f, 0.589844f, 0.820312f, 0.449219f},
+ {0.023438f, 0.398438f, 0.734375f, 0.011719f}, {0.960938f, 0.253906f, 0.132812f, 0.582031f},
+ {0.378906f, 0.644531f, 0.945312f, 0.480469f}, {0.496094f, 0.320312f, 0.683594f, 0.656250f},
+ {0.085938f, 0.722656f, 0.105469f, 0.386719f}, {0.316406f, 0.414062f, 0.753906f, 0.226562f},
+ {0.046875f, 0.011719f, 0.199219f, 0.464844f}, {0.621094f, 0.968750f, 0.714844f, 0.300781f},
+ {0.878906f, 0.726562f, 0.863281f, 0.593750f}, {0.257812f, 0.312500f, 0.324219f, 0.523438f},
+ {0.347656f, 0.835938f, 0.816406f, 0.687500f}, {0.074219f, 0.480469f, 0.000000f, 0.972656f},
+ {0.656250f, 0.007812f, 0.578125f, 0.785156f}, {0.792969f, 0.914062f, 0.152344f, 0.570312f},
+ {0.464844f, 0.292969f, 0.292969f, 0.152344f}, {0.863281f, 0.843750f, 0.101562f, 0.957031f},
+ {0.066406f, 0.449219f, 0.484375f, 0.199219f}, {0.437500f, 0.019531f, 0.878906f, 0.886719f},
+ {0.800781f, 0.074219f, 0.132812f, 0.136719f}, {0.296875f, 0.800781f, 0.511719f, 0.488281f},
+ {0.656250f, 0.253906f, 0.019531f, 0.371094f}, {0.101562f, 0.148438f, 0.726562f, 0.609375f},
+ {0.203125f, 0.664062f, 0.660156f, 0.089844f}, {0.976562f, 0.437500f, 0.972656f, 0.175781f},
+ {0.289062f, 0.781250f, 0.765625f, 0.578125f}, {0.660156f, 0.343750f, 0.519531f, 0.312500f},
+ {0.507812f, 0.625000f, 0.441406f, 0.019531f}, {0.175781f, 0.933594f, 0.230469f, 0.394531f},
+ {0.796875f, 0.722656f, 0.824219f, 0.570312f}, {0.277344f, 0.410156f, 0.406250f, 0.226562f},
+ {0.597656f, 0.949219f, 0.761719f, 0.707031f}, {0.949219f, 0.609375f, 0.882812f, 0.070312f},
+ {0.519531f, 0.859375f, 0.128906f, 0.273438f}, {0.632812f, 0.203125f, 0.042969f, 0.156250f},
+ {0.265625f, 0.890625f, 0.449219f, 0.812500f}, {0.585938f, 0.664062f, 0.230469f, 0.210938f},
+ {0.968750f, 0.960938f, 0.742188f, 0.726562f}, {0.226562f, 0.339844f, 0.992188f, 0.117188f},
+ {0.875000f, 0.410156f, 0.093750f, 0.894531f}, {0.640625f, 0.261719f, 0.710938f, 0.324219f},
+ {0.917969f, 0.980469f, 0.425781f, 0.234375f}, {0.308594f, 0.300781f, 0.804688f, 0.628906f},
+ {0.589844f, 0.105469f, 0.648438f, 0.421875f}, {0.714844f, 0.847656f, 0.125000f, 0.808594f},
+ {0.406250f, 0.187500f, 0.480469f, 0.300781f}, {0.667969f, 0.992188f, 0.679688f, 0.960938f},
+ {0.070312f, 0.542969f, 0.800781f, 0.859375f}, {0.835938f, 0.082031f, 0.554688f, 0.578125f},
+ {0.398438f, 0.496094f, 0.449219f, 0.402344f}, {0.113281f, 0.398438f, 0.222656f, 0.828125f},
+ {0.460938f, 0.308594f, 0.054688f, 0.625000f}, {0.976562f, 0.472656f, 0.984375f, 0.375000f},
+ {0.281250f, 0.203125f, 0.312500f, 0.937500f}, {0.386719f, 0.000000f, 0.875000f, 0.785156f},
+ {0.785156f, 0.402344f, 0.078125f, 0.527344f}, {0.117188f, 0.644531f, 0.812500f, 0.082031f},
+ {0.941406f, 0.503906f, 0.132812f, 0.972656f}, {0.488281f, 0.140625f, 0.023438f, 0.238281f},
+ {0.832031f, 0.843750f, 0.859375f, 0.167969f}, {0.335938f, 0.011719f, 0.382812f, 0.730469f},
+ {0.628906f, 0.777344f, 0.570312f, 0.875000f}, {0.527344f, 0.355469f, 0.285156f, 0.132812f},
+ {0.234375f, 0.472656f, 0.093750f, 0.312500f}, {0.308594f, 0.941406f, 0.214844f, 0.820312f},
+ {0.640625f, 0.164062f, 0.628906f, 0.714844f}, {0.871094f, 0.832031f, 0.390625f, 0.156250f},
+ {0.218750f, 0.531250f, 0.265625f, 0.289062f}, {0.699219f, 0.117188f, 0.550781f, 0.796875f},
+ {0.980469f, 0.578125f, 0.890625f, 0.125000f}, {0.523438f, 0.824219f, 0.460938f, 0.890625f},
+ {0.445312f, 0.347656f, 0.285156f, 0.675781f}, {0.816406f, 0.097656f, 0.949219f, 0.781250f},
+ {0.140625f, 0.550781f, 0.089844f, 0.160156f}, {0.675781f, 0.421875f, 0.484375f, 0.074219f},
+ {0.542969f, 0.062500f, 0.535156f, 0.230469f}, {0.421875f, 0.570312f, 0.886719f, 0.484375f},
+ {0.167969f, 0.339844f, 0.734375f, 0.035156f}, {0.277344f, 0.199219f, 0.425781f, 0.441406f},
+ {0.093750f, 0.527344f, 0.996094f, 0.714844f}, {0.214844f, 0.148438f, 0.632812f, 0.335938f},
+ {0.941406f, 0.585938f, 0.242188f, 0.593750f}, {0.160156f, 0.886719f, 0.410156f, 0.652344f},
+ {0.597656f, 0.679688f, 0.812500f, 0.019531f}, {0.242188f, 0.312500f, 0.585938f, 0.562500f},
+ {0.531250f, 0.460938f, 0.937500f, 0.921875f}, {0.375000f, 0.734375f, 0.328125f, 0.054688f},
+ {0.703125f, 0.382812f, 0.472656f, 0.734375f}, {0.824219f, 0.835938f, 0.140625f, 0.519531f},
+ {0.441406f, 0.289062f, 0.203125f, 0.414062f}, {0.121094f, 0.691406f, 0.628906f, 0.925781f},
+ {0.378906f, 0.019531f, 0.105469f, 0.082031f}, {0.714844f, 0.222656f, 0.347656f, 0.734375f},
+ {0.046875f, 0.816406f, 0.968750f, 0.976562f}, {0.421875f, 0.320312f, 0.078125f, 0.628906f},
+ {0.871094f, 0.097656f, 0.484375f, 0.835938f}, {0.695312f, 0.265625f, 0.207031f, 0.332031f},
+ {0.351562f, 0.718750f, 0.273438f, 0.761719f}, {0.406250f, 0.382812f, 0.957031f, 0.511719f},
+ {0.042969f, 0.785156f, 0.628906f, 0.980469f}, {0.832031f, 0.117188f, 0.910156f, 0.343750f},
+ {0.144531f, 0.500000f, 0.058594f, 0.421875f}, {0.699219f, 0.843750f, 0.589844f, 0.601562f},
+ {0.546875f, 0.574219f, 0.488281f, 0.164062f}, {0.363281f, 0.054688f, 0.265625f, 0.390625f},
+ {0.128906f, 0.785156f, 0.949219f, 0.746094f}, {0.492188f, 0.691406f, 0.175781f, 0.949219f},
+ {0.972656f, 0.902344f, 0.894531f, 0.183594f}, {0.027344f, 0.359375f, 0.570312f, 0.070312f},
+ {0.273438f, 0.062500f, 0.207031f, 0.500000f}, {0.472656f, 0.730469f, 0.972656f, 0.613281f},
+ {0.351562f, 0.640625f, 0.089844f, 0.363281f}, {0.742188f, 0.226562f, 0.187500f, 0.195312f},
+ {0.234375f, 0.699219f, 0.730469f, 0.945312f}, {0.625000f, 0.945312f, 0.636719f, 0.082031f},
+ {0.328125f, 0.839844f, 0.378906f, 0.312500f}, {0.707031f, 0.652344f, 0.574219f, 0.875000f},
+ {0.566406f, 0.742188f, 0.148438f, 0.050781f}, {0.882812f, 0.921875f, 0.460938f, 0.246094f},
+ {0.519531f, 0.585938f, 0.917969f, 0.656250f}, {0.730469f, 0.718750f, 0.597656f, 0.316406f},
+ {0.261719f, 0.808594f, 0.500000f, 0.460938f}, {0.171875f, 0.285156f, 0.324219f, 0.796875f},
+ {0.773438f, 0.562500f, 0.746094f, 0.546875f}, {0.433594f, 0.429688f, 0.183594f, 0.343750f},
+ {0.726562f, 0.628906f, 0.050781f, 0.488281f}, {0.859375f, 0.898438f, 0.972656f, 0.996094f},
+ {0.402344f, 0.542969f, 0.429688f, 0.402344f}, {0.101562f, 0.304688f, 0.535156f, 0.542969f},
+ {0.476562f, 0.675781f, 0.863281f, 0.902344f}, {0.734375f, 0.035156f, 0.488281f, 0.359375f},
+ {0.289062f, 0.761719f, 0.773438f, 0.976562f}, {0.589844f, 0.949219f, 0.007812f, 0.519531f},
+ {0.843750f, 0.269531f, 0.417969f, 0.835938f}, {0.664062f, 0.183594f, 0.144531f, 0.554688f},
+ {0.226562f, 0.652344f, 0.656250f, 0.085938f}, {0.367188f, 0.789062f, 0.562500f, 0.957031f},
+ {0.972656f, 0.238281f, 0.394531f, 0.433594f}, {0.000000f, 0.894531f, 0.207031f, 0.644531f},
+ {0.777344f, 0.136719f, 0.968750f, 0.820312f}, {0.910156f, 0.949219f, 0.261719f, 0.355469f},
+ {0.722656f, 0.785156f, 0.070312f, 0.917969f}, {0.996094f, 0.707031f, 0.792969f, 0.105469f},
+ {0.562500f, 0.644531f, 0.511719f, 0.246094f}, {0.648438f, 0.937500f, 0.335938f, 0.851562f},
+ {0.398438f, 0.738281f, 0.777344f, 0.078125f}, {0.832031f, 0.410156f, 0.695312f, 0.285156f},
+ {0.722656f, 0.210938f, 0.167969f, 0.785156f}, {0.042969f, 0.609375f, 0.296875f, 0.214844f},
+ {0.863281f, 0.976562f, 0.441406f, 0.824219f}, {0.167969f, 0.027344f, 0.066406f, 0.664062f},
+ {0.609375f, 0.562500f, 0.828125f, 0.347656f}, {0.000000f, 0.191406f, 0.562500f, 0.839844f},
+ {0.250000f, 0.070312f, 0.281250f, 0.207031f}, {0.875000f, 0.875000f, 0.917969f, 0.644531f},
+ {0.941406f, 0.523438f, 0.781250f, 0.867188f}, {0.617188f, 0.378906f, 0.687500f, 0.343750f},
+ {0.316406f, 0.132812f, 0.546875f, 0.171875f}, {0.542969f, 0.574219f, 0.609375f, 0.101562f},
+ {0.230469f, 0.484375f, 0.851562f, 0.433594f}, {0.007812f, 0.828125f, 0.671875f, 0.910156f},
+ {0.160156f, 0.160156f, 0.734375f, 0.605469f}, {0.890625f, 0.527344f, 0.351562f, 0.394531f},
+ {0.757812f, 0.042969f, 0.511719f, 0.039062f}, {0.507812f, 0.593750f, 0.144531f, 0.640625f},
+ {0.335938f, 0.238281f, 0.316406f, 0.781250f}, {0.464844f, 0.726562f, 0.191406f, 0.500000f},
+ {0.000000f, 0.093750f, 0.667969f, 0.707031f}, {0.273438f, 0.636719f, 0.843750f, 0.031250f},
+ {0.746094f, 0.210938f, 0.101562f, 0.570312f}, {0.437500f, 0.421875f, 0.343750f, 0.832031f},
+ {0.625000f, 0.519531f, 0.027344f, 0.355469f}, {0.824219f, 0.613281f, 0.777344f, 0.667969f},
+ {0.886719f, 0.261719f, 0.296875f, 0.121094f}, {0.554688f, 0.476562f, 0.609375f, 0.777344f},
+ {0.992188f, 0.328125f, 0.417969f, 0.253906f}, {0.007812f, 0.812500f, 0.339844f, 0.050781f},
+ {0.519531f, 0.371094f, 0.921875f, 0.476562f}, {0.867188f, 0.167969f, 0.121094f, 0.660156f},
+ {0.773438f, 0.054688f, 0.789062f, 0.718750f}, {0.066406f, 0.535156f, 0.253906f, 0.128906f},
+ {0.156250f, 0.343750f, 0.753906f, 0.503906f}, {0.218750f, 0.437500f, 0.027344f, 0.410156f},
+ {0.347656f, 0.070312f, 0.398438f, 0.839844f}, {0.019531f, 0.175781f, 0.222656f, 0.714844f},
+ {0.410156f, 0.375000f, 0.953125f, 0.011719f}, {0.605469f, 0.886719f, 0.652344f, 0.640625f},
+ {0.093750f, 0.082031f, 0.414062f, 0.097656f}, {0.289062f, 0.707031f, 0.886719f, 0.269531f},
+ {0.003906f, 0.195312f, 0.242188f, 0.691406f}, {0.980469f, 0.261719f, 0.781250f, 0.070312f},
+ {0.671875f, 0.070312f, 0.722656f, 0.621094f}, {0.820312f, 0.851562f, 0.914062f, 0.250000f},
+ {0.550781f, 0.429688f, 0.164062f, 0.097656f}, {0.140625f, 0.210938f, 0.082031f, 0.671875f},
+ {0.042969f, 0.367188f, 0.996094f, 0.054688f}, {0.394531f, 0.457031f, 0.605469f, 0.613281f},
+ {0.164062f, 0.695312f, 0.312500f, 0.417969f}, {0.109375f, 0.132812f, 0.929688f, 0.320312f},
+ {0.734375f, 0.937500f, 0.800781f, 0.207031f}, {0.578125f, 0.476562f, 0.039062f, 0.367188f},
+ {0.500000f, 0.382812f, 0.761719f, 0.859375f}, {0.304688f, 0.750000f, 0.628906f, 0.273438f},
+ {0.207031f, 0.617188f, 0.121094f, 0.730469f}, {0.597656f, 0.269531f, 0.683594f, 0.140625f},
+ {0.324219f, 0.445312f, 0.371094f, 0.613281f}, {0.027344f, 0.386719f, 0.187500f, 0.761719f},
+ {0.507812f, 0.093750f, 0.597656f, 0.546875f}, {0.769531f, 0.250000f, 0.015625f, 0.386719f},
+ {0.265625f, 0.335938f, 0.914062f, 0.472656f}, {0.335938f, 0.113281f, 0.539062f, 0.972656f},
+ {0.496094f, 0.828125f, 0.078125f, 0.730469f}, {0.980469f, 0.507812f, 0.656250f, 0.410156f},
+ {0.410156f, 0.093750f, 0.871094f, 0.148438f}, {0.777344f, 0.910156f, 0.238281f, 0.464844f},
+ {0.929688f, 0.644531f, 0.746094f, 0.253906f}, {0.343750f, 0.488281f, 0.394531f, 0.992188f},
+ {0.566406f, 0.949219f, 0.011719f, 0.117188f}, {0.476562f, 0.597656f, 0.859375f, 0.476562f},
+ {0.210938f, 0.449219f, 0.476562f, 0.273438f}, {0.816406f, 0.902344f, 0.156250f, 0.542969f},
+ {0.093750f, 0.738281f, 0.253906f, 0.773438f}, {0.964844f, 0.640625f, 0.316406f, 0.500000f},
+ {0.738281f, 0.925781f, 0.007812f, 0.257812f}, {0.828125f, 0.066406f, 0.433594f, 0.000000f},
+ {0.457031f, 0.437500f, 0.578125f, 0.187500f}, {0.667969f, 0.980469f, 0.089844f, 0.699219f},
+ {0.207031f, 0.351562f, 0.824219f, 0.886719f}, {0.105469f, 0.902344f, 0.703125f, 0.246094f},
+ {0.933594f, 0.183594f, 0.796875f, 0.070312f}, {0.796875f, 0.449219f, 0.457031f, 0.925781f},
+ {0.656250f, 0.945312f, 0.378906f, 0.289062f}, {0.957031f, 0.878906f, 0.769531f, 0.875000f},
+ {0.847656f, 0.335938f, 0.531250f, 0.097656f}, {0.089844f, 0.128906f, 0.628906f, 0.464844f},
+ {0.199219f, 0.824219f, 0.437500f, 0.273438f}, {0.335938f, 0.035156f, 0.507812f, 0.925781f},
+ {0.113281f, 0.773438f, 0.839844f, 0.554688f}, {0.160156f, 0.925781f, 0.042969f, 0.437500f},
+ {0.695312f, 0.132812f, 0.875000f, 0.687500f}, {0.300781f, 0.007812f, 0.519531f, 0.878906f},
+ {0.921875f, 0.898438f, 0.671875f, 0.800781f}, {0.187500f, 0.582031f, 0.000000f, 0.539062f},
+ {0.421875f, 0.253906f, 0.484375f, 0.265625f}, {0.503906f, 0.800781f, 0.945312f, 0.988281f},
+ {0.917969f, 0.117188f, 0.625000f, 0.753906f}, {0.812500f, 0.859375f, 0.707031f, 0.578125f},
+ {0.671875f, 0.269531f, 0.296875f, 0.171875f}, {0.984375f, 0.949219f, 0.769531f, 0.367188f},
+ {0.847656f, 0.476562f, 0.156250f, 0.957031f}, {0.703125f, 0.613281f, 0.554688f, 0.867188f},
+ {0.890625f, 0.328125f, 0.101562f, 0.421875f}, {0.503906f, 0.976562f, 0.687500f, 0.910156f},
+ {0.570312f, 0.511719f, 0.503906f, 0.777344f}, {0.156250f, 0.808594f, 0.597656f, 0.179688f},
+ {0.355469f, 0.125000f, 0.019531f, 0.839844f}, {0.199219f, 0.730469f, 0.308594f, 0.738281f},
+ {0.949219f, 0.984375f, 0.671875f, 0.496094f}, {0.429688f, 0.613281f, 0.246094f, 0.199219f},
+ {0.910156f, 0.085938f, 0.363281f, 0.765625f}, {0.769531f, 0.878906f, 0.707031f, 0.261719f},
+ {0.472656f, 0.519531f, 0.187500f, 0.000000f}, {0.894531f, 0.328125f, 0.519531f, 0.750000f},
+ {0.277344f, 0.593750f, 0.238281f, 0.632812f}, {0.058594f, 0.855469f, 0.359375f, 0.500000f},
+ {0.855469f, 0.023438f, 0.910156f, 0.027344f}, {0.699219f, 0.523438f, 0.449219f, 0.562500f},
+ {0.457031f, 0.667969f, 0.308594f, 0.980469f}, {0.125000f, 0.175781f, 0.824219f, 0.312500f},
+ {0.867188f, 0.867188f, 0.476562f, 0.414062f}, {0.375000f, 0.027344f, 0.929688f, 0.882812f},
+ {0.683594f, 0.812500f, 0.851562f, 0.175781f}, {0.117188f, 0.480469f, 0.125000f, 0.804688f},
+ {0.878906f, 0.980469f, 0.210938f, 0.679688f}, {0.058594f, 0.554688f, 0.378906f, 0.042969f},
+ {0.628906f, 0.167969f, 0.976562f, 0.527344f}, {0.132812f, 0.757812f, 0.769531f, 0.621094f},
+ {0.308594f, 0.371094f, 0.191406f, 0.312500f}, {0.464844f, 0.273438f, 0.527344f, 0.898438f},
+ {0.085938f, 0.808594f, 0.960938f, 0.007812f}, {0.734375f, 0.324219f, 0.691406f, 0.757812f},
+ {0.671875f, 0.105469f, 0.339844f, 0.593750f}, {0.058594f, 0.765625f, 0.585938f, 0.703125f},
+ {0.761719f, 0.246094f, 0.062500f, 0.031250f}, {0.156250f, 0.167969f, 0.417969f, 0.917969f},
+ {0.355469f, 0.035156f, 0.800781f, 0.382812f}, {0.644531f, 0.281250f, 0.925781f, 0.683594f},
+ {0.496094f, 0.773438f, 0.136719f, 0.957031f}, {0.121094f, 0.226562f, 0.890625f, 0.562500f},
+ {0.304688f, 0.699219f, 0.187500f, 0.824219f}, {0.992188f, 0.628906f, 0.980469f, 0.457031f},
+ {0.550781f, 0.300781f, 0.410156f, 0.308594f}, {0.621094f, 0.761719f, 0.242188f, 0.148438f},
+ {0.292969f, 0.671875f, 0.609375f, 0.816406f}, {0.414062f, 0.386719f, 0.000000f, 0.445312f},
+ {0.167969f, 0.289062f, 0.890625f, 0.207031f}, {0.238281f, 0.542969f, 0.140625f, 0.523438f},
+ {0.566406f, 0.710938f, 0.218750f, 0.625000f}, {0.382812f, 0.464844f, 0.980469f, 0.156250f},
+ {0.785156f, 0.972656f, 0.695312f, 0.730469f}, {0.535156f, 0.199219f, 0.246094f, 0.863281f},
+ {0.648438f, 0.390625f, 0.371094f, 0.210938f}, {0.425781f, 0.550781f, 0.722656f, 0.000000f},
+ {0.773438f, 0.671875f, 0.140625f, 0.980469f}, {0.585938f, 0.425781f, 0.234375f, 0.304688f},
+ {0.105469f, 0.734375f, 0.812500f, 0.164062f}, {0.656250f, 0.460938f, 0.281250f, 0.421875f},
+ {0.277344f, 0.632812f, 0.863281f, 0.351562f}, {0.031250f, 0.968750f, 0.347656f, 0.015625f},
+ {0.613281f, 0.195312f, 0.195312f, 0.214844f}, {0.445312f, 0.507812f, 0.527344f, 0.906250f},
+ {0.296875f, 0.777344f, 0.855469f, 0.093750f}, {0.132812f, 0.660156f, 0.062500f, 0.285156f},
+ {0.546875f, 0.031250f, 0.457031f, 0.496094f}, {0.195312f, 0.230469f, 0.808594f, 0.144531f},
+ {0.375000f, 0.750000f, 0.273438f, 0.210938f}, {0.933594f, 0.156250f, 0.941406f, 0.601562f},
+ {0.230469f, 0.402344f, 0.355469f, 0.367188f}, {0.753906f, 0.656250f, 0.128906f, 0.449219f},
+ {0.058594f, 0.351562f, 0.464844f, 0.015625f}, {0.597656f, 0.570312f, 0.398438f, 0.957031f},
+ {0.789062f, 0.289062f, 0.824219f, 0.386719f}, {0.246094f, 0.492188f, 0.578125f, 0.863281f},
+ {0.636719f, 0.792969f, 0.046875f, 0.457031f}, {0.332031f, 0.019531f, 0.839844f, 0.929688f},
+ {0.207031f, 0.410156f, 0.109375f, 0.707031f}, {0.617188f, 0.765625f, 0.621094f, 0.992188f},
+ {0.960938f, 0.066406f, 0.691406f, 0.132812f}, {0.417969f, 0.289062f, 0.074219f, 0.906250f},
+ {0.789062f, 0.207031f, 0.851562f, 0.769531f}, {0.093750f, 0.972656f, 0.171875f, 0.183594f},
+ {0.937500f, 0.101562f, 0.726562f, 0.066406f}, {0.253906f, 0.324219f, 0.554688f, 0.527344f},
+ {0.820312f, 0.503906f, 0.062500f, 0.656250f}, {0.476562f, 0.593750f, 0.648438f, 0.007812f},
+ {0.179688f, 0.910156f, 0.281250f, 0.289062f}, {0.957031f, 0.062500f, 0.445312f, 0.921875f},
+ {0.441406f, 0.632812f, 0.726562f, 0.128906f}, {0.574219f, 0.292969f, 0.621094f, 0.234375f},
+ {0.203125f, 0.875000f, 0.476562f, 0.363281f}, {0.679688f, 0.667969f, 0.031250f, 0.945312f},
+ {0.914062f, 0.441406f, 0.347656f, 0.097656f}, {0.546875f, 0.214844f, 0.609375f, 0.687500f},
+ {0.191406f, 0.718750f, 0.113281f, 0.550781f}, {0.269531f, 0.148438f, 0.164062f, 0.375000f},
+ {0.992188f, 0.414062f, 0.898438f, 0.164062f}, {0.398438f, 0.652344f, 0.652344f, 0.429688f},
+ {0.523438f, 0.351562f, 0.210938f, 0.800781f}, {0.863281f, 0.820312f, 0.992188f, 0.218750f},
+ {0.437500f, 0.988281f, 0.707031f, 0.066406f}, {0.261719f, 0.421875f, 0.382812f, 0.859375f},
+ {0.921875f, 0.339844f, 0.644531f, 0.132812f}, {0.585938f, 0.539062f, 0.746094f, 0.359375f},
+ {0.386719f, 0.855469f, 0.488281f, 0.738281f}, {0.804688f, 0.019531f, 0.289062f, 0.105469f},
+ {0.253906f, 0.480469f, 0.050781f, 0.539062f}, {0.027344f, 0.109375f, 0.867188f, 0.945312f},
+ {0.898438f, 0.828125f, 0.523438f, 0.582031f}, {0.718750f, 0.046875f, 0.964844f, 0.339844f},
+ {0.519531f, 0.152344f, 0.281250f, 0.675781f}, {0.062500f, 0.765625f, 0.570312f, 0.984375f},
+ {0.886719f, 0.003906f, 0.738281f, 0.792969f}, {0.687500f, 0.257812f, 0.316406f, 0.410156f},
+ {0.019531f, 0.585938f, 0.078125f, 0.039062f}, {0.964844f, 0.660156f, 0.164062f, 0.320312f},
+ {0.257812f, 0.863281f, 0.941406f, 0.597656f}, {0.906250f, 0.292969f, 0.640625f, 0.386719f},
+ {0.214844f, 0.960938f, 0.472656f, 0.746094f}, {0.464844f, 0.214844f, 0.996094f, 0.628906f},
+ {0.378906f, 0.851562f, 0.558594f, 0.097656f}, {0.820312f, 0.300781f, 0.394531f, 0.898438f},
+ {0.718750f, 0.066406f, 0.597656f, 0.566406f}, {0.968750f, 0.406250f, 0.085938f, 0.843750f},
+ {0.363281f, 0.687500f, 0.433594f, 0.683594f}, {0.750000f, 0.574219f, 0.125000f, 0.437500f},
+ {0.078125f, 0.316406f, 0.980469f, 0.617188f}, {0.636719f, 0.136719f, 0.675781f, 0.812500f},
+ {0.468750f, 0.910156f, 0.367188f, 0.757812f}, {0.324219f, 0.546875f, 0.910156f, 0.554688f},
+ {0.050781f, 0.832031f, 0.003906f, 0.671875f}, {0.808594f, 0.054688f, 0.203125f, 0.042969f},
+ {0.625000f, 0.929688f, 0.632812f, 0.937500f}, {0.460938f, 0.468750f, 0.796875f, 0.523438f},
+ {0.882812f, 0.003906f, 0.964844f, 0.292969f}, {0.304688f, 0.902344f, 0.195312f, 0.589844f},
+ {0.503906f, 0.160156f, 0.515625f, 0.128906f}, {0.011719f, 0.671875f, 0.933594f, 0.328125f},
+ {0.714844f, 0.250000f, 0.765625f, 0.570312f}, {0.539062f, 0.921875f, 0.472656f, 0.167969f},
+ {0.820312f, 0.187500f, 0.871094f, 0.355469f}, {0.031250f, 0.996094f, 0.953125f, 0.476562f},
+ {0.355469f, 0.628906f, 0.425781f, 0.289062f}, {0.554688f, 0.449219f, 0.578125f, 0.593750f},
+ {0.183594f, 0.710938f, 0.273438f, 0.398438f}, {0.644531f, 0.359375f, 0.511719f, 0.695312f},
+ {0.398438f, 0.820312f, 0.015625f, 0.464844f}, {0.535156f, 0.925781f, 0.941406f, 0.933594f},
+ {0.628906f, 0.691406f, 0.238281f, 0.222656f}, {0.074219f, 0.222656f, 0.402344f, 0.707031f},
+ {0.785156f, 0.757812f, 0.761719f, 0.496094f}, {0.242188f, 0.367188f, 0.570312f, 0.589844f},
+ {0.726562f, 0.718750f, 0.320312f, 0.445312f}, {0.925781f, 0.417969f, 0.890625f, 0.863281f},
+ {0.382812f, 0.000000f, 0.261719f, 0.753906f}, {0.753906f, 0.953125f, 0.839844f, 0.179688f},
+ {0.023438f, 0.078125f, 0.414062f, 0.832031f}, {0.843750f, 0.597656f, 0.906250f, 0.496094f},
+ {0.617188f, 0.894531f, 0.492188f, 0.792969f}, {0.886719f, 0.542969f, 0.261719f, 0.289062f},
+ {0.140625f, 0.968750f, 0.437500f, 0.960938f}, {0.296875f, 0.046875f, 0.757812f, 0.851562f},
+ {0.601562f, 0.710938f, 0.300781f, 0.324219f}, {0.699219f, 0.500000f, 0.496094f, 0.574219f},
+ {0.019531f, 0.558594f, 0.035156f, 0.648438f}, {0.785156f, 0.675781f, 0.535156f, 0.449219f},
+ {0.078125f, 0.089844f, 0.234375f, 0.300781f}, {0.191406f, 0.175781f, 0.339844f, 0.617188f},
+ {0.714844f, 0.398438f, 0.785156f, 0.222656f}, {0.054688f, 0.921875f, 0.562500f, 0.875000f},
+ {0.488281f, 0.257812f, 0.683594f, 0.652344f}, {0.765625f, 0.566406f, 0.335938f, 0.386719f},
+ {0.371094f, 0.957031f, 0.121094f, 0.750000f}, {0.117188f, 0.511719f, 0.718750f, 0.007812f},
+ {0.820312f, 0.871094f, 0.421875f, 0.125000f}, {0.453125f, 0.617188f, 0.062500f, 0.371094f},
+ {0.613281f, 0.937500f, 0.914062f, 0.246094f}, {0.300781f, 0.371094f, 0.460938f, 0.703125f},
+ {0.480469f, 0.078125f, 0.863281f, 0.957031f}, {0.730469f, 0.746094f, 0.785156f, 0.488281f},
+ {0.363281f, 0.164062f, 0.566406f, 0.812500f}, {0.074219f, 0.093750f, 0.093750f, 0.140625f},
+ {0.859375f, 0.503906f, 0.320312f, 0.527344f}, {0.039062f, 0.050781f, 0.765625f, 0.464844f},
+ {0.953125f, 0.566406f, 0.058594f, 0.222656f}, {0.531250f, 0.156250f, 0.156250f, 0.773438f},
+ {0.230469f, 0.914062f, 0.738281f, 0.644531f}, {0.117188f, 0.750000f, 0.898438f, 0.152344f},
+ {0.574219f, 0.363281f, 0.656250f, 0.484375f}, {0.179688f, 0.011719f, 0.808594f, 0.312500f},
+ {0.894531f, 0.980469f, 0.328125f, 0.941406f}, {0.246094f, 0.730469f, 0.242188f, 0.066406f},
+ {0.949219f, 0.386719f, 0.609375f, 0.398438f}, {0.781250f, 0.445312f, 0.511719f, 0.257812f},
+ {0.675781f, 0.679688f, 0.730469f, 0.843750f}, {0.121094f, 0.273438f, 0.433594f, 0.324219f},
+ {0.273438f, 0.582031f, 0.855469f, 0.726562f}, {0.390625f, 0.863281f, 0.289062f, 0.816406f},
+ {0.699219f, 0.226562f, 0.707031f, 0.218750f}, {0.925781f, 0.757812f, 0.078125f, 0.687500f},
+ {0.128906f, 0.382812f, 0.640625f, 0.906250f}, {0.382812f, 0.101562f, 0.140625f, 0.789062f},
+ {0.988281f, 0.843750f, 0.273438f, 0.074219f}, {0.093750f, 0.562500f, 0.386719f, 0.660156f},
+ {0.441406f, 0.726562f, 0.230469f, 0.218750f}, {0.746094f, 0.238281f, 0.023438f, 0.875000f},
+ {0.683594f, 0.109375f, 0.750000f, 0.042969f}, {0.238281f, 0.898438f, 0.328125f, 0.812500f},
+ {0.902344f, 0.796875f, 0.988281f, 0.230469f}, {0.335938f, 0.574219f, 0.792969f, 0.335938f},
+ {0.015625f, 0.035156f, 0.613281f, 0.835938f}, {0.738281f, 0.414062f, 0.343750f, 0.101562f},
+ {0.976562f, 0.128906f, 0.867188f, 0.789062f}, {0.308594f, 0.285156f, 0.148438f, 0.371094f},
+ {0.554688f, 0.535156f, 0.980469f, 0.964844f}, {0.351562f, 0.191406f, 0.046875f, 0.074219f},
+ {0.003906f, 0.140625f, 0.812500f, 0.324219f}, {0.515625f, 0.804688f, 0.101562f, 0.644531f},
+ {0.292969f, 0.242188f, 0.152344f, 0.546875f}, {0.816406f, 0.527344f, 0.554688f, 0.277344f},
+ {0.246094f, 0.343750f, 0.664062f, 0.050781f}, {0.425781f, 0.839844f, 0.058594f, 0.425781f},
+ {0.347656f, 0.031250f, 0.714844f, 0.207031f}, {0.496094f, 0.460938f, 0.804688f, 0.652344f},
+ {0.800781f, 0.226562f, 0.078125f, 0.058594f}, {0.039062f, 0.859375f, 0.546875f, 0.484375f},
+ {0.945312f, 0.300781f, 0.847656f, 0.109375f}, {0.226562f, 0.121094f, 0.121094f, 0.933594f},
+ {0.906250f, 0.210938f, 0.878906f, 0.746094f}, {0.546875f, 0.875000f, 0.601562f, 0.187500f},
+ {0.675781f, 0.953125f, 0.085938f, 0.804688f}, {0.339844f, 0.601562f, 0.933594f, 0.507812f},
+ {0.859375f, 0.792969f, 0.023438f, 0.996094f}, {0.429688f, 0.128906f, 0.156250f, 0.031250f},
+ {0.929688f, 0.742188f, 0.906250f, 0.269531f}, {0.179688f, 0.203125f, 0.453125f, 0.484375f},
+ {0.671875f, 0.640625f, 0.644531f, 0.195312f}, {0.582031f, 0.328125f, 0.191406f, 0.847656f},
+ {0.976562f, 0.425781f, 0.832031f, 0.601562f}, {0.343750f, 0.191406f, 0.347656f, 0.906250f},
+ {0.210938f, 0.488281f, 0.605469f, 0.062500f}, {0.941406f, 0.804688f, 0.023438f, 0.546875f},
+ {0.101562f, 0.910156f, 0.527344f, 0.191406f}, {0.175781f, 0.437500f, 0.402344f, 0.648438f},
+ {0.820312f, 0.332031f, 0.265625f, 0.914062f}, {0.515625f, 0.636719f, 0.882812f, 0.062500f},
+ {0.621094f, 0.785156f, 0.429688f, 0.253906f}, {0.746094f, 0.707031f, 0.199219f, 0.937500f},
+ {0.152344f, 0.355469f, 0.683594f, 0.332031f}, {0.332031f, 0.804688f, 0.457031f, 0.074219f},
+ {0.878906f, 0.492188f, 0.964844f, 0.968750f}, {0.480469f, 0.109375f, 0.226562f, 0.382812f},
+ {0.792969f, 0.867188f, 0.035156f, 0.042969f}, {0.417969f, 0.234375f, 0.480469f, 0.734375f},
+ {0.843750f, 0.464844f, 0.566406f, 0.539062f}, {0.511719f, 0.609375f, 0.171875f, 0.187500f},
+ {0.011719f, 0.062500f, 0.046875f, 0.703125f}, {0.582031f, 0.191406f, 0.871094f, 0.968750f},
+ {0.429688f, 0.347656f, 0.308594f, 0.121094f}, {0.988281f, 0.777344f, 0.578125f, 0.484375f},
+ {0.527344f, 0.109375f, 0.152344f, 0.078125f}, {0.085938f, 0.320312f, 0.050781f, 0.160156f},
+ {0.835938f, 0.699219f, 0.539062f, 0.640625f}, {0.558594f, 0.531250f, 0.890625f, 0.433594f},
+ {0.183594f, 0.968750f, 0.332031f, 0.031250f}, {0.660156f, 0.449219f, 0.433594f, 0.269531f},
+ {0.851562f, 0.640625f, 0.722656f, 0.503906f}, {0.289062f, 0.347656f, 0.558594f, 0.835938f},
+ {0.156250f, 0.488281f, 0.171875f, 0.101562f}, {0.878906f, 0.828125f, 0.804688f, 0.550781f},
+ {0.511719f, 0.386719f, 0.492188f, 0.437500f}, {0.132812f, 0.531250f, 0.148438f, 0.671875f},
+ {0.765625f, 0.144531f, 0.101562f, 0.117188f}, {0.484375f, 0.257812f, 0.210938f, 0.910156f},
+ {0.835938f, 0.480469f, 0.433594f, 0.574219f}, {0.152344f, 0.628906f, 0.699219f, 0.269531f},
+ {0.214844f, 0.773438f, 0.089844f, 0.441406f}, {0.417969f, 0.992188f, 0.535156f, 0.152344f},
+ {0.898438f, 0.453125f, 0.667969f, 0.746094f}, {0.640625f, 0.867188f, 0.195312f, 0.207031f},
+ {0.148438f, 0.578125f, 0.507812f, 0.796875f}, {0.855469f, 0.921875f, 0.699219f, 0.027344f},
+ {0.097656f, 0.468750f, 0.960938f, 0.988281f}, {0.585938f, 0.625000f, 0.757812f, 0.382812f},
+ {0.160156f, 0.773438f, 0.300781f, 0.613281f}, {0.714844f, 0.183594f, 0.214844f, 0.875000f},
+ {0.070312f, 0.691406f, 0.980469f, 0.937500f}, {0.656250f, 0.375000f, 0.332031f, 0.125000f},
+ {0.746094f, 0.789062f, 0.621094f, 0.738281f}, {0.457031f, 0.585938f, 0.949219f, 0.605469f},
+ {0.335938f, 0.933594f, 0.179688f, 0.253906f}, {0.171875f, 0.625000f, 0.359375f, 0.523438f},
+ {0.386719f, 0.457031f, 0.730469f, 0.394531f}, {0.472656f, 0.003906f, 0.273438f, 0.039062f},
+ {0.281250f, 0.726562f, 0.457031f, 0.902344f}, {0.972656f, 0.488281f, 0.832031f, 0.093750f},
+ {0.617188f, 0.312500f, 0.406250f, 0.414062f}, {0.136719f, 0.660156f, 0.613281f, 0.687500f},
+ {0.562500f, 0.441406f, 0.226562f, 0.781250f}, {0.324219f, 0.375000f, 0.800781f, 0.074219f},
+ {0.871094f, 0.808594f, 0.082031f, 0.964844f}, {0.269531f, 0.089844f, 0.941406f, 0.699219f},
+ {0.011719f, 0.250000f, 0.503906f, 0.503906f}, {0.148438f, 0.671875f, 0.242188f, 0.300781f},
+ {0.707031f, 0.125000f, 0.679688f, 0.453125f}, {0.843750f, 0.296875f, 0.812500f, 0.835938f},
+ {0.417969f, 0.566406f, 0.187500f, 0.113281f}, {0.578125f, 0.226562f, 0.652344f, 0.285156f},
+ {0.675781f, 0.523438f, 0.718750f, 0.363281f}, {0.312500f, 0.894531f, 0.039062f, 0.691406f},
+ {0.406250f, 0.398438f, 0.605469f, 0.781250f}, {0.265625f, 0.246094f, 0.917969f, 0.851562f},
+ {0.570312f, 0.992188f, 0.843750f, 0.589844f}, {0.644531f, 0.605469f, 0.339844f, 0.714844f},
+ {0.003906f, 0.269531f, 0.531250f, 0.511719f}, {0.699219f, 0.652344f, 0.296875f, 0.277344f},
+ {0.312500f, 0.546875f, 0.710938f, 0.824219f}, {0.054688f, 0.152344f, 0.402344f, 0.238281f},
+ {0.667969f, 0.796875f, 0.914062f, 0.875000f}, {0.351562f, 0.281250f, 0.769531f, 0.351562f},
+ {0.730469f, 0.839844f, 0.691406f, 0.000000f}, {0.289062f, 0.894531f, 0.394531f, 0.632812f},
+ {0.152344f, 0.519531f, 0.113281f, 0.429688f}, {0.867188f, 0.988281f, 0.992188f, 0.582031f},
+ {0.210938f, 0.636719f, 0.480469f, 0.878906f}, {0.640625f, 0.171875f, 0.753906f, 0.984375f},
+ {0.023438f, 0.425781f, 0.371094f, 0.343750f}, {0.437500f, 0.039062f, 0.222656f, 0.539062f},
+ {0.257812f, 0.800781f, 0.835938f, 0.718750f}, {0.777344f, 0.300781f, 0.007812f, 0.964844f},
+ {0.484375f, 0.054688f, 0.984375f, 0.406250f}, {0.582031f, 0.140625f, 0.664062f, 0.617188f},
+ {0.398438f, 0.597656f, 0.906250f, 0.933594f}, {0.933594f, 0.019531f, 0.367188f, 0.726562f},
+ {0.312500f, 0.691406f, 0.601562f, 0.164062f}, {0.074219f, 0.320312f, 0.882812f, 0.964844f},
+ {0.589844f, 0.644531f, 0.679688f, 0.515625f}, {0.949219f, 0.964844f, 0.375000f, 0.742188f},
+ {0.281250f, 0.187500f, 0.910156f, 0.023438f}, {0.687500f, 0.886719f, 0.773438f, 0.640625f},
+ {0.597656f, 0.343750f, 0.292969f, 0.871094f}, {0.054688f, 0.089844f, 0.464844f, 0.535156f},
+ {0.808594f, 0.015625f, 0.839844f, 0.613281f}, {0.710938f, 0.675781f, 0.339844f, 0.902344f},
+ {0.484375f, 0.320312f, 0.429688f, 0.406250f}, {0.988281f, 0.062500f, 0.242188f, 0.687500f},
+ {0.664062f, 0.707031f, 0.375000f, 0.140625f}, {0.460938f, 0.128906f, 0.019531f, 0.480469f},
+ {0.960938f, 0.296875f, 0.453125f, 0.707031f}, {0.535156f, 0.980469f, 0.828125f, 0.246094f},
+ {0.894531f, 0.101562f, 0.578125f, 0.570312f}, {0.218750f, 0.273438f, 0.398438f, 0.335938f},
+ {0.113281f, 0.507812f, 0.000000f, 0.406250f}, {0.554688f, 0.160156f, 0.242188f, 0.890625f},
+ {0.828125f, 0.066406f, 0.671875f, 0.695312f}, {0.632812f, 0.398438f, 0.425781f, 0.148438f},
+ {0.730469f, 0.781250f, 0.785156f, 0.968750f}, {0.125000f, 0.273438f, 0.964844f, 0.281250f},
+ {0.820312f, 0.371094f, 0.191406f, 0.707031f}, {0.031250f, 0.218750f, 0.695312f, 0.585938f},
+ {0.507812f, 0.054688f, 0.511719f, 0.343750f}, {0.242188f, 0.890625f, 0.988281f, 0.167969f},
+ {0.734375f, 0.972656f, 0.730469f, 0.531250f}, {0.070312f, 0.011719f, 0.285156f, 0.316406f},
+ {0.460938f, 0.707031f, 0.394531f, 0.417969f}, {0.781250f, 0.546875f, 0.585938f, 0.234375f},
+ {0.402344f, 0.992188f, 0.769531f, 0.152344f}, {0.644531f, 0.738281f, 0.148438f, 0.773438f},
+ {0.757812f, 0.855469f, 0.976562f, 0.636719f}, {0.539062f, 0.050781f, 0.382812f, 0.390625f},
+ {0.246094f, 0.714844f, 0.296875f, 0.742188f}, {0.910156f, 0.972656f, 0.125000f, 0.886719f},
+ {0.128906f, 0.011719f, 0.960938f, 0.445312f}, {0.984375f, 0.828125f, 0.351562f, 0.554688f},
+ {0.054688f, 0.132812f, 0.511719f, 0.175781f}, {0.800781f, 0.464844f, 0.117188f, 0.398438f},
+ {0.921875f, 0.027344f, 0.257812f, 0.019531f}, {0.437500f, 0.191406f, 0.015625f, 0.441406f},
+ {0.203125f, 0.433594f, 0.785156f, 0.195312f}, {0.996094f, 0.953125f, 0.632812f, 0.917969f},
+ {0.257812f, 0.335938f, 0.144531f, 0.652344f}, {0.617188f, 0.703125f, 0.835938f, 0.101562f},
+ {0.941406f, 0.929688f, 0.265625f, 0.597656f}, {0.109375f, 0.503906f, 0.097656f, 0.468750f},
+ {0.195312f, 0.093750f, 0.957031f, 0.785156f}, {0.917969f, 0.714844f, 0.218750f, 0.906250f},
+ {0.761719f, 0.242188f, 0.648438f, 0.281250f}, {0.367188f, 0.019531f, 0.789062f, 0.195312f},
+ {0.707031f, 0.480469f, 0.253906f, 0.386719f}, {0.328125f, 0.828125f, 0.917969f, 0.757812f},
+ {0.960938f, 0.941406f, 0.667969f, 0.242188f}, {0.742188f, 0.601562f, 0.601562f, 0.105469f},
+ {0.347656f, 0.203125f, 0.496094f, 0.871094f}, {0.886719f, 0.687500f, 0.777344f, 0.152344f},
+ {0.046875f, 0.886719f, 0.089844f, 0.316406f}, {0.222656f, 0.957031f, 0.316406f, 0.773438f},
+ {0.625000f, 0.750000f, 0.527344f, 0.253906f}, {0.003906f, 0.277344f, 0.050781f, 0.382812f},
+ {0.660156f, 0.937500f, 0.250000f, 0.328125f}, {0.808594f, 0.078125f, 0.734375f, 0.625000f},
+ {0.437500f, 0.425781f, 0.460938f, 0.281250f}, {0.386719f, 0.738281f, 0.566406f, 0.394531f},
+ {0.039062f, 0.050781f, 0.035156f, 0.175781f}, {0.523438f, 0.546875f, 0.175781f, 0.996094f},
+ {0.925781f, 0.714844f, 0.957031f, 0.347656f}, {0.453125f, 0.843750f, 0.585938f, 0.039062f},
+ {0.109375f, 0.617188f, 0.003906f, 0.296875f}, {0.269531f, 0.406250f, 0.750000f, 0.109375f},
+ {0.390625f, 0.949219f, 0.933594f, 0.519531f}, {0.207031f, 0.222656f, 0.597656f, 0.238281f},
+ {0.332031f, 0.378906f, 0.640625f, 0.820312f}, {0.785156f, 0.898438f, 0.914062f, 0.906250f},
+ {0.054688f, 0.496094f, 0.523438f, 0.085938f}, {0.386719f, 0.417969f, 0.089844f, 0.777344f},
+ {0.304688f, 0.562500f, 0.148438f, 0.031250f}, {0.929688f, 0.925781f, 0.773438f, 0.519531f},
+ {0.414062f, 0.667969f, 0.468750f, 0.195312f}, {0.257812f, 0.738281f, 0.835938f, 0.800781f},
+ {0.972656f, 0.332031f, 0.519531f, 0.003906f}, {0.078125f, 0.847656f, 0.062500f, 0.359375f},
+ {0.882812f, 0.691406f, 0.566406f, 0.625000f}, {0.585938f, 0.148438f, 0.140625f, 0.777344f},
+ {0.214844f, 0.941406f, 0.652344f, 0.476562f}, {0.757812f, 0.824219f, 0.308594f, 0.238281f},
+ {0.402344f, 0.527344f, 0.113281f, 0.867188f}, {0.945312f, 0.585938f, 0.359375f, 0.937500f},
+ {0.839844f, 0.277344f, 0.062500f, 0.621094f}, {0.632812f, 0.167969f, 0.550781f, 0.804688f},
+ {0.222656f, 0.464844f, 0.894531f, 0.914062f}, {0.535156f, 0.882812f, 0.011719f, 0.566406f},
+ {0.886719f, 0.039062f, 0.312500f, 0.085938f}, {0.496094f, 0.394531f, 0.449219f, 0.875000f},
+ {0.085938f, 0.593750f, 0.097656f, 0.972656f}, {0.289062f, 0.343750f, 0.742188f, 0.011719f},
+ {0.031250f, 0.460938f, 0.894531f, 0.589844f}, {0.777344f, 0.156250f, 0.488281f, 0.222656f},
+ {0.468750f, 0.679688f, 0.835938f, 0.042969f}, {0.195312f, 0.281250f, 0.230469f, 0.992188f},
+ {0.718750f, 0.589844f, 0.796875f, 0.109375f}, {0.492188f, 0.921875f, 0.667969f, 0.667969f},
+ {0.097656f, 0.667969f, 0.390625f, 0.292969f}, {0.835938f, 0.871094f, 0.582031f, 0.871094f},
+ {0.378906f, 0.097656f, 0.878906f, 0.128906f}, {0.753906f, 0.765625f, 0.078125f, 0.558594f},
+ {0.503906f, 0.039062f, 0.937500f, 0.761719f}, {0.148438f, 0.207031f, 0.515625f, 0.425781f},
+ {0.816406f, 0.421875f, 0.593750f, 0.996094f}, {0.390625f, 0.367188f, 0.335938f, 0.136719f},
+ {0.550781f, 0.656250f, 0.441406f, 0.226562f}, {0.488281f, 0.144531f, 0.828125f, 0.523438f},
+ {0.605469f, 0.593750f, 0.531250f, 0.734375f}, {0.035156f, 0.390625f, 0.347656f, 0.671875f},
+ {0.464844f, 0.742188f, 0.019531f, 0.023438f}, {0.812500f, 0.265625f, 0.421875f, 0.492188f},
+ {0.164062f, 0.359375f, 0.101562f, 0.605469f}, {0.507812f, 0.121094f, 0.171875f, 0.800781f},
+ {0.605469f, 0.503906f, 0.933594f, 0.453125f}, {0.082031f, 0.250000f, 0.261719f, 0.203125f},
+ {0.968750f, 0.550781f, 0.460938f, 0.570312f}, {0.718750f, 0.410156f, 0.628906f, 0.054688f},
+ {0.835938f, 0.105469f, 0.710938f, 0.468750f}, {0.359375f, 0.457031f, 0.421875f, 0.894531f},
+ {0.250000f, 0.875000f, 0.968750f, 0.015625f}, {0.996094f, 0.210938f, 0.074219f, 0.855469f},
+ {0.179688f, 0.785156f, 0.304688f, 0.074219f}, {0.714844f, 0.855469f, 0.832031f, 0.804688f},
+ {0.230469f, 0.296875f, 0.500000f, 0.488281f}, {0.859375f, 0.394531f, 0.253906f, 0.222656f},
+ {0.324219f, 0.230469f, 0.640625f, 0.679688f}, {0.765625f, 0.511719f, 0.390625f, 0.820312f},
+ {0.179688f, 0.269531f, 0.222656f, 0.726562f}, {0.843750f, 0.121094f, 0.128906f, 0.468750f},
+ {0.609375f, 0.781250f, 0.859375f, 0.960938f}, {0.035156f, 0.531250f, 0.066406f, 0.335938f},
+ {0.734375f, 0.855469f, 0.167969f, 0.578125f}, {0.261719f, 0.023438f, 0.324219f, 0.175781f},
+ {0.867188f, 0.652344f, 0.875000f, 0.304688f}, {0.632812f, 0.746094f, 0.683594f, 0.371094f},
+ {0.183594f, 0.214844f, 0.273438f, 0.851562f}, {0.773438f, 0.832031f, 0.921875f, 0.667969f},
+ {0.589844f, 0.011719f, 0.703125f, 0.992188f}, {0.691406f, 0.433594f, 0.113281f, 0.300781f},
+ {0.003906f, 0.246094f, 0.933594f, 0.457031f}, {0.511719f, 0.984375f, 0.320312f, 0.843750f},
+ {0.300781f, 0.496094f, 0.886719f, 0.203125f}, {0.433594f, 0.578125f, 0.390625f, 0.539062f},
+ {0.914062f, 0.648438f, 0.007812f, 0.121094f}, {0.085938f, 0.421875f, 0.867188f, 0.824219f},
+ {0.683594f, 0.117188f, 0.753906f, 0.015625f}, {0.304688f, 0.750000f, 0.210938f, 0.460938f},
+ {0.113281f, 0.355469f, 0.828125f, 0.113281f}, {0.367188f, 0.843750f, 0.472656f, 0.718750f},
+ {0.988281f, 0.621094f, 0.167969f, 0.035156f}, {0.050781f, 0.308594f, 0.710938f, 0.363281f},
+ {0.171875f, 0.144531f, 0.871094f, 0.667969f}, {0.929688f, 0.515625f, 0.648438f, 0.265625f},
+ {0.363281f, 0.781250f, 0.542969f, 0.183594f}, {0.859375f, 0.203125f, 0.226562f, 0.335938f},
+ {0.609375f, 0.878906f, 0.574219f, 0.496094f}, {0.386719f, 0.621094f, 0.003906f, 0.800781f},
+ {0.644531f, 0.378906f, 0.628906f, 0.625000f}, {0.871094f, 0.757812f, 0.437500f, 0.324219f},
+ {0.238281f, 0.082031f, 0.160156f, 0.750000f}, {0.355469f, 0.535156f, 0.984375f, 0.519531f},
+ {0.691406f, 0.308594f, 0.734375f, 0.960938f}, {0.167969f, 0.722656f, 0.480469f, 0.628906f},
+ {0.550781f, 0.390625f, 0.179688f, 0.792969f}, {0.070312f, 0.511719f, 0.441406f, 0.347656f},
+ {0.906250f, 0.843750f, 0.363281f, 0.023438f}, {0.589844f, 0.636719f, 0.203125f, 0.289062f},
+ {0.449219f, 0.070312f, 0.007812f, 0.695312f}, {0.238281f, 0.566406f, 0.746094f, 0.382812f},
+ {0.683594f, 0.953125f, 0.492188f, 0.832031f}, {0.855469f, 0.324219f, 0.062500f, 0.328125f},
+ {0.093750f, 0.812500f, 0.156250f, 0.093750f}, {0.253906f, 0.917969f, 0.609375f, 0.929688f},
+ {0.925781f, 0.550781f, 0.710938f, 0.812500f}, {0.574219f, 0.082031f, 0.843750f, 0.304688f},
+ {0.109375f, 0.894531f, 0.308594f, 0.066406f}, {0.234375f, 0.718750f, 0.550781f, 0.941406f},
+ {0.683594f, 0.851562f, 0.699219f, 0.371094f}, {0.410156f, 0.773438f, 0.402344f, 0.636719f},
+ {0.308594f, 0.335938f, 0.136719f, 0.843750f}, {0.519531f, 0.175781f, 0.820312f, 0.687500f},
+ {0.109375f, 0.820312f, 0.292969f, 0.527344f}, {0.457031f, 0.539062f, 0.183594f, 0.191406f},
+ {0.742188f, 0.617188f, 0.847656f, 0.750000f}, {0.539062f, 0.363281f, 0.617188f, 0.566406f},
+ {0.085938f, 0.500000f, 0.140625f, 0.449219f}, {0.890625f, 0.578125f, 0.937500f, 0.699219f},
+ {0.632812f, 0.113281f, 0.664062f, 0.917969f}, {0.128906f, 0.660156f, 0.105469f, 0.582031f},
+ {0.375000f, 0.933594f, 0.812500f, 0.410156f}, {0.652344f, 0.160156f, 0.882812f, 0.132812f},
+ {0.503906f, 0.820312f, 0.691406f, 0.253906f}, {0.941406f, 0.457031f, 0.300781f, 0.851562f},
+ {0.550781f, 0.734375f, 0.546875f, 0.656250f}, {0.902344f, 0.175781f, 0.488281f, 0.000000f},
+ {0.437500f, 0.593750f, 0.730469f, 0.753906f}, {0.125000f, 0.261719f, 0.785156f, 0.437500f},
+ {0.570312f, 0.816406f, 0.203125f, 0.632812f}, {0.500000f, 0.074219f, 0.417969f, 0.949219f},
+ {0.031250f, 0.351562f, 0.632812f, 0.472656f}, {0.839844f, 0.601562f, 0.343750f, 0.152344f},
+ {0.136719f, 0.128906f, 0.187500f, 0.753906f}, {0.476562f, 0.886719f, 0.597656f, 0.101562f},
+ {0.371094f, 0.550781f, 0.265625f, 0.578125f}, {0.792969f, 0.187500f, 0.722656f, 0.925781f},
+ {0.164062f, 0.089844f, 0.203125f, 0.070312f}, {0.660156f, 0.035156f, 0.617188f, 0.417969f},
+ {0.359375f, 0.324219f, 0.476562f, 0.671875f}, {0.539062f, 0.871094f, 0.542969f, 0.300781f},
+ {0.812500f, 0.195312f, 0.925781f, 0.750000f}, {0.171875f, 0.675781f, 0.433594f, 0.394531f},
+ {0.492188f, 0.066406f, 0.597656f, 0.210938f}, {0.710938f, 0.507812f, 0.675781f, 0.281250f},
+ {0.574219f, 0.765625f, 0.964844f, 0.851562f}, {0.808594f, 0.226562f, 0.250000f, 0.468750f},
+ {0.316406f, 0.925781f, 0.367188f, 0.757812f}, {0.675781f, 0.656250f, 0.816406f, 0.429688f},
+ {0.214844f, 0.265625f, 0.062500f, 0.539062f}, {0.457031f, 0.953125f, 0.937500f, 0.722656f},
+ {0.972656f, 0.101562f, 0.410156f, 0.132812f}, {0.070312f, 0.800781f, 0.320312f, 0.929688f},
+ {0.320312f, 0.500000f, 0.769531f, 0.261719f}, {0.527344f, 0.218750f, 0.085938f, 0.472656f},
+ {0.015625f, 0.851562f, 0.550781f, 0.820312f}, {0.960938f, 0.359375f, 0.285156f, 0.210938f},
+ {0.609375f, 0.144531f, 0.062500f, 0.371094f}, {0.292969f, 0.812500f, 0.925781f, 0.058594f},
+ {0.664062f, 0.226562f, 0.308594f, 0.242188f}, {0.863281f, 0.582031f, 0.671875f, 0.488281f},
+ {0.332031f, 0.292969f, 0.765625f, 0.945312f}, {0.023438f, 0.910156f, 0.988281f, 0.183594f},
+ {0.726562f, 0.734375f, 0.621094f, 0.531250f}, {0.968750f, 0.261719f, 0.898438f, 0.902344f},
+ {0.058594f, 0.851562f, 0.675781f, 0.046875f}, {0.320312f, 0.187500f, 0.292969f, 0.609375f},
+ {0.781250f, 0.449219f, 0.949219f, 0.167969f}, {0.410156f, 0.054688f, 0.882812f, 0.441406f},
+ {0.667969f, 0.210938f, 0.207031f, 0.542969f}, {0.296875f, 0.667969f, 0.468750f, 0.855469f},
+ {0.871094f, 0.417969f, 0.980469f, 0.148438f}, {0.761719f, 0.164062f, 0.765625f, 0.699219f},
+ {0.914062f, 0.460938f, 0.035156f, 0.511719f}, {0.148438f, 0.027344f, 0.871094f, 0.007812f},
+ {0.800781f, 0.929688f, 0.210938f, 0.988281f}, {0.199219f, 0.675781f, 0.945312f, 0.128906f},
+ {0.574219f, 0.230469f, 0.027344f, 0.796875f}, {0.875000f, 0.980469f, 0.781250f, 0.648438f},
+ {0.140625f, 0.144531f, 0.542969f, 0.968750f}, {0.609375f, 0.003906f, 0.359375f, 0.238281f},
+ {0.335938f, 0.683594f, 0.222656f, 0.148438f}, {0.476562f, 0.171875f, 0.761719f, 0.308594f},
+ {0.757812f, 0.902344f, 0.402344f, 0.105469f}, {0.562500f, 0.445312f, 0.324219f, 0.757812f},
+ {0.972656f, 0.039062f, 0.527344f, 0.050781f}, {0.019531f, 0.570312f, 0.054688f, 0.933594f},
+ {0.296875f, 0.964844f, 0.457031f, 0.562500f}, {0.695312f, 0.351562f, 0.984375f, 0.183594f},
+ {0.078125f, 0.636719f, 0.800781f, 0.382812f}, {0.347656f, 0.082031f, 0.402344f, 0.093750f},
+ {0.804688f, 0.988281f, 0.257812f, 0.921875f}, {0.191406f, 0.316406f, 0.101562f, 0.535156f},
+ {0.707031f, 0.453125f, 0.570312f, 0.722656f}, {0.937500f, 0.160156f, 0.996094f, 0.050781f},
+ {0.363281f, 0.960938f, 0.023438f, 0.230469f}, {0.671875f, 0.480469f, 0.496094f, 0.414062f},
+ {0.320312f, 0.296875f, 0.859375f, 0.554688f}, {0.949219f, 0.644531f, 0.386719f, 0.261719f},
+ {0.867188f, 0.757812f, 0.035156f, 0.648438f}, {0.226562f, 0.359375f, 0.460938f, 0.726562f},
+ {0.714844f, 0.804688f, 0.816406f, 0.328125f}, {0.996094f, 0.914062f, 0.980469f, 0.886719f},
+ {0.023438f, 0.257812f, 0.250000f, 0.976562f}, {0.265625f, 0.773438f, 0.789062f, 0.171875f},
+ {0.605469f, 0.472656f, 0.046875f, 0.636719f}, {0.449219f, 0.945312f, 0.273438f, 0.957031f},
+ {0.902344f, 0.250000f, 0.128906f, 0.582031f}, {0.000000f, 0.906250f, 0.332031f, 0.519531f},
+ {0.273438f, 0.101562f, 0.042969f, 0.175781f}, {0.421875f, 0.386719f, 0.515625f, 0.988281f},
+ {0.742188f, 0.820312f, 0.605469f, 0.605469f}, {0.589844f, 0.453125f, 0.132812f, 0.066406f},
+ {0.128906f, 0.066406f, 0.285156f, 0.910156f}, {0.800781f, 0.550781f, 0.714844f, 0.835938f},
+ {0.699219f, 0.421875f, 0.855469f, 0.398438f}, {0.175781f, 0.304688f, 0.175781f, 0.664062f},
+ {0.738281f, 0.039062f, 0.683594f, 0.074219f}, {0.832031f, 0.984375f, 0.898438f, 0.867188f},
+ {0.574219f, 0.437500f, 0.363281f, 0.144531f}, {0.421875f, 0.640625f, 0.859375f, 0.597656f},
+ {0.898438f, 0.937500f, 0.640625f, 0.906250f}, {0.125000f, 0.484375f, 0.214844f, 0.449219f},
+ {0.472656f, 0.000000f, 0.808594f, 0.675781f}, {0.218750f, 0.960938f, 0.109375f, 0.847656f},
+ {0.425781f, 0.167969f, 0.539062f, 0.585938f}, {0.800781f, 0.460938f, 0.257812f, 0.734375f},
+ {0.289062f, 0.125000f, 0.402344f, 0.070312f}, {0.179688f, 0.777344f, 0.125000f, 0.648438f},
+ {0.890625f, 0.011719f, 0.187500f, 0.480469f}, {0.628906f, 0.492188f, 0.558594f, 0.761719f},
+ {0.144531f, 0.691406f, 0.769531f, 0.957031f}, {0.957031f, 0.765625f, 0.378906f, 0.351562f},
+ {0.187500f, 0.292969f, 0.074219f, 0.222656f}, {0.496094f, 0.957031f, 0.589844f, 0.652344f},
+ {0.378906f, 0.597656f, 0.128906f, 0.410156f}, {0.007812f, 0.316406f, 0.269531f, 0.273438f},
+ {0.449219f, 0.644531f, 0.367188f, 0.777344f}, {0.542969f, 0.093750f, 0.648438f, 0.234375f},
+ {0.660156f, 0.582031f, 0.503906f, 0.335938f}, {0.941406f, 0.382812f, 0.585938f, 0.421875f},
+ {0.031250f, 0.042969f, 0.117188f, 0.285156f}, {0.414062f, 0.304688f, 0.679688f, 0.082031f},
+ {0.781250f, 0.722656f, 0.484375f, 0.351562f}, {0.277344f, 0.800781f, 0.875000f, 0.496094f},
+ {0.914062f, 0.265625f, 0.007812f, 0.816406f}, {0.406250f, 0.968750f, 0.445312f, 0.628906f},
+ {0.066406f, 0.339844f, 0.710938f, 0.375000f}, {0.261719f, 0.746094f, 0.968750f, 0.878906f},
+ {0.203125f, 0.800781f, 0.160156f, 0.511719f}, {0.812500f, 0.312500f, 0.613281f, 0.328125f},
+ {0.414062f, 0.691406f, 0.359375f, 0.445312f}, {0.148438f, 0.007812f, 0.179688f, 0.625000f},
+ {0.238281f, 0.226562f, 0.027344f, 0.785156f}, {0.476562f, 0.507812f, 0.664062f, 0.875000f},
+ {0.648438f, 0.390625f, 0.945312f, 0.210938f}, {0.972656f, 0.710938f, 0.367188f, 0.269531f},
+ {0.285156f, 0.558594f, 0.464844f, 0.128906f}, {0.082031f, 0.679688f, 0.816406f, 0.832031f},
+ {0.457031f, 0.769531f, 0.078125f, 0.601562f}, {0.242188f, 0.867188f, 0.738281f, 0.898438f},
+ {0.750000f, 0.394531f, 0.554688f, 0.019531f}, {0.101562f, 0.042969f, 0.968750f, 0.367188f},
+ {0.621094f, 0.957031f, 0.769531f, 0.820312f}, {0.046875f, 0.449219f, 0.660156f, 0.492188f},
+ {0.562500f, 0.613281f, 0.089844f, 0.234375f}, {0.480469f, 0.710938f, 0.335938f, 0.027344f},
+ {0.851562f, 0.402344f, 0.156250f, 0.566406f}, {0.144531f, 0.554688f, 0.691406f, 0.507812f},
+ {0.957031f, 0.023438f, 0.378906f, 0.355469f}, {0.750000f, 0.605469f, 0.640625f, 0.054688f},
+ {0.207031f, 0.722656f, 0.941406f, 0.878906f}, {0.644531f, 0.429688f, 0.847656f, 0.660156f},
+ {0.847656f, 0.558594f, 0.773438f, 0.328125f}, {0.089844f, 0.691406f, 0.425781f, 0.125000f},
+ {0.480469f, 0.000000f, 0.195312f, 0.816406f}, {0.960938f, 0.332031f, 0.992188f, 0.226562f},
+ {0.019531f, 0.750000f, 0.457031f, 0.304688f}, {0.546875f, 0.175781f, 0.503906f, 0.027344f},
+ {0.253906f, 0.703125f, 0.046875f, 0.566406f}, {0.433594f, 0.898438f, 0.601562f, 0.199219f},
+ {0.925781f, 0.582031f, 0.972656f, 0.359375f}, {0.136719f, 0.687500f, 0.250000f, 0.699219f},
+ {0.269531f, 0.183594f, 0.468750f, 0.417969f}, {0.792969f, 0.066406f, 0.031250f, 0.003906f},
+ {0.050781f, 0.566406f, 0.578125f, 0.718750f}, {0.710938f, 0.273438f, 0.414062f, 0.093750f},
+ {0.769531f, 0.695312f, 0.500000f, 0.300781f}, {0.976562f, 0.792969f, 0.867188f, 0.152344f},
+ {0.093750f, 0.613281f, 0.054688f, 0.410156f}, {0.652344f, 0.339844f, 0.722656f, 0.808594f},
+ {0.570312f, 0.527344f, 0.804688f, 0.214844f}, {0.480469f, 0.398438f, 0.324219f, 0.312500f},
+ {0.371094f, 0.996094f, 0.851562f, 0.867188f}, {0.531250f, 0.621094f, 0.429688f, 0.250000f},
+ {0.441406f, 0.117188f, 0.039062f, 0.574219f}, {0.718750f, 0.355469f, 0.250000f, 0.703125f},
+ {0.843750f, 0.867188f, 0.515625f, 0.050781f}, {0.078125f, 0.511719f, 0.816406f, 0.976562f},
+ {0.621094f, 0.000000f, 0.667969f, 0.589844f}, {0.992188f, 0.800781f, 0.441406f, 0.882812f},
+ {0.277344f, 0.988281f, 0.898438f, 0.093750f}, {0.058594f, 0.277344f, 0.070312f, 0.722656f},
+ {0.351562f, 0.867188f, 0.746094f, 0.914062f}, {0.246094f, 0.507812f, 0.343750f, 0.601562f},
+ {0.707031f, 0.433594f, 0.996094f, 0.875000f}, {0.972656f, 0.640625f, 0.394531f, 0.406250f},
+ {0.664062f, 0.894531f, 0.253906f, 0.710938f}, {0.195312f, 0.406250f, 0.640625f, 0.906250f},
+ {0.015625f, 0.480469f, 0.921875f, 0.035156f}, {0.800781f, 0.070312f, 0.582031f, 0.953125f},
+ {0.679688f, 0.628906f, 0.062500f, 0.199219f}, {0.855469f, 0.218750f, 0.273438f, 0.265625f},
+ {0.449219f, 0.492188f, 0.792969f, 0.664062f}, {0.714844f, 0.101562f, 0.906250f, 0.808594f},
+ {0.578125f, 0.894531f, 0.714844f, 0.980469f}, {0.957031f, 0.421875f, 0.246094f, 0.058594f},
+ {0.757812f, 0.851562f, 0.578125f, 0.304688f}, {0.886719f, 0.789062f, 0.839844f, 0.488281f},
+ {0.000000f, 0.925781f, 0.140625f, 0.679688f}, {0.523438f, 0.121094f, 0.617188f, 0.355469f},
+ {0.406250f, 0.886719f, 0.710938f, 0.984375f}, {0.769531f, 0.035156f, 0.285156f, 0.503906f},
+ {0.890625f, 0.242188f, 0.906250f, 0.292969f}, {0.574219f, 0.531250f, 0.242188f, 0.703125f},
+ {0.171875f, 0.179688f, 0.121094f, 0.769531f}, {0.527344f, 0.718750f, 0.308594f, 0.968750f},
+ {0.433594f, 0.226562f, 0.171875f, 0.171875f}, {0.281250f, 0.105469f, 0.523438f, 0.125000f},
+ {0.761719f, 0.285156f, 0.417969f, 0.402344f}, {0.328125f, 0.515625f, 0.574219f, 0.691406f},
+ {0.406250f, 0.164062f, 0.910156f, 0.792969f}, {0.652344f, 0.996094f, 0.101562f, 0.109375f},
+ {0.062500f, 0.121094f, 0.507812f, 0.832031f}, {0.320312f, 0.378906f, 0.742188f, 0.242188f},
+ {0.390625f, 0.316406f, 0.175781f, 0.703125f}, {0.527344f, 0.156250f, 0.558594f, 0.417969f},
+ {0.933594f, 0.972656f, 0.085938f, 0.000000f}, {0.160156f, 0.199219f, 0.722656f, 0.734375f},
+ {0.242188f, 0.589844f, 0.898438f, 0.378906f}, {0.386719f, 0.941406f, 0.664062f, 0.503906f},
+ {0.652344f, 0.851562f, 0.339844f, 0.695312f}, {0.910156f, 0.628906f, 0.765625f, 0.953125f},
+ {0.343750f, 0.367188f, 0.218750f, 0.460938f}, {0.503906f, 0.136719f, 0.386719f, 0.769531f},
+ {0.078125f, 0.816406f, 0.117188f, 0.976562f}, {0.632812f, 0.257812f, 0.523438f, 0.511719f},
+ {0.378906f, 0.335938f, 0.722656f, 0.281250f}, {0.203125f, 0.769531f, 0.789062f, 0.558594f},
+ {0.511719f, 0.882812f, 0.144531f, 0.953125f}, {0.347656f, 0.117188f, 0.695312f, 0.769531f},
+ {0.253906f, 0.371094f, 0.964844f, 0.523438f}, {0.542969f, 0.425781f, 0.355469f, 0.878906f},
+ {0.382812f, 0.082031f, 0.167969f, 0.109375f}, {0.910156f, 0.894531f, 0.582031f, 0.363281f},
+ {0.132812f, 0.707031f, 0.472656f, 0.980469f}, {0.765625f, 0.210938f, 0.023438f, 0.445312f},
+ {0.000000f, 0.304688f, 0.976562f, 0.148438f}, {0.820312f, 0.542969f, 0.695312f, 0.023438f},
+ {0.230469f, 0.925781f, 0.625000f, 0.398438f}, {0.042969f, 0.429688f, 0.902344f, 0.792969f},
+ {0.554688f, 0.152344f, 0.738281f, 0.117188f}, {0.339844f, 0.730469f, 0.320312f, 0.480469f},
+ {0.804688f, 0.234375f, 0.960938f, 0.187500f}, {0.714844f, 0.375000f, 0.183594f, 0.347656f},
+ {0.578125f, 0.492188f, 0.539062f, 0.457031f}, {0.859375f, 0.203125f, 0.230469f, 0.550781f},
+ {0.769531f, 0.730469f, 0.832031f, 0.175781f}, {0.484375f, 0.789062f, 0.453125f, 0.031250f},
+ {0.308594f, 0.953125f, 0.718750f, 0.746094f}, {0.066406f, 0.554688f, 0.890625f, 0.214844f},
+ {0.378906f, 0.105469f, 0.085938f, 0.121094f}, {0.503906f, 0.195312f, 0.316406f, 0.605469f},
+ {0.949219f, 0.867188f, 0.167969f, 0.429688f}, {0.546875f, 0.531250f, 0.824219f, 0.542969f},
+ {0.316406f, 0.832031f, 0.207031f, 0.718750f}, {0.117188f, 0.390625f, 0.554688f, 0.460938f},
+ {0.515625f, 0.152344f, 0.492188f, 0.011719f}, {0.906250f, 0.597656f, 0.117188f, 0.156250f},
+ {0.046875f, 0.261719f, 0.417969f, 0.234375f}, {0.625000f, 0.542969f, 0.773438f, 0.707031f},
+ {0.386719f, 0.667969f, 0.476562f, 0.121094f}, {0.308594f, 0.062500f, 0.320312f, 0.593750f},
+ {0.167969f, 0.285156f, 0.886719f, 0.417969f}, {0.601562f, 0.199219f, 0.042969f, 0.777344f},
+ {0.835938f, 0.425781f, 0.187500f, 0.082031f}, {0.214844f, 0.343750f, 0.539062f, 0.648438f},
+ {0.023438f, 0.632812f, 0.398438f, 0.390625f}, {0.640625f, 0.093750f, 0.671875f, 0.195312f},
+ {0.984375f, 0.820312f, 0.445312f, 0.074219f}, {0.382812f, 0.921875f, 0.617188f, 0.449219f},
+ {0.910156f, 0.492188f, 0.828125f, 0.531250f}, {0.832031f, 0.683594f, 0.941406f, 0.859375f},
+ {0.125000f, 0.859375f, 0.046875f, 0.941406f}, {0.929688f, 0.058594f, 0.750000f, 0.617188f},
+ {0.218750f, 0.816406f, 0.835938f, 0.273438f}, {0.730469f, 0.222656f, 0.296875f, 0.441406f},
+ {0.574219f, 0.652344f, 0.441406f, 0.921875f}, {0.832031f, 0.886719f, 0.878906f, 0.484375f},
+ {0.117188f, 0.835938f, 0.226562f, 0.085938f}, {0.773438f, 0.050781f, 0.476562f, 0.781250f},
+ {0.343750f, 0.789062f, 0.292969f, 0.929688f}, {0.695312f, 0.468750f, 0.382812f, 0.535156f},
+ {0.882812f, 0.281250f, 0.019531f, 0.898438f}, {0.785156f, 0.125000f, 0.804688f, 0.160156f},
+ {0.304688f, 0.507812f, 0.101562f, 0.640625f}, {0.093750f, 0.230469f, 0.546875f, 0.105469f},
+ {0.839844f, 0.968750f, 0.929688f, 0.253906f}, {0.593750f, 0.476562f, 0.652344f, 0.605469f},
+ {0.773438f, 0.011719f, 0.816406f, 0.046875f}, {0.976562f, 0.527344f, 0.304688f, 0.890625f},
+ {0.464844f, 0.941406f, 0.187500f, 0.183594f}, {0.660156f, 0.460938f, 0.921875f, 0.804688f},
+ {0.875000f, 0.718750f, 0.328125f, 0.335938f}, {0.933594f, 0.175781f, 0.246094f, 0.214844f},
+ {0.011719f, 0.636719f, 0.000000f, 0.640625f}, {0.628906f, 0.980469f, 0.632812f, 0.925781f},
+ {0.187500f, 0.246094f, 0.281250f, 0.261719f}, {0.835938f, 0.046875f, 0.921875f, 0.617188f},
+ {0.273438f, 0.832031f, 0.660156f, 0.542969f}, {0.691406f, 0.648438f, 0.226562f, 0.726562f},
+ {0.988281f, 0.882812f, 0.527344f, 0.675781f}, {0.597656f, 0.039062f, 0.351562f, 0.921875f},
+ {0.304688f, 0.253906f, 0.152344f, 0.515625f}, {0.902344f, 0.804688f, 0.484375f, 0.277344f},
+ {0.656250f, 0.632812f, 0.113281f, 0.898438f}, {0.257812f, 0.078125f, 0.410156f, 0.742188f},
+ {0.132812f, 0.566406f, 0.000000f, 0.828125f}, {0.210938f, 0.914062f, 0.781250f, 0.042969f},
+ {0.394531f, 0.675781f, 0.613281f, 0.949219f}, {0.171875f, 0.117188f, 0.929688f, 0.664062f},
+ {0.910156f, 0.351562f, 0.300781f, 0.808594f}, {0.605469f, 0.160156f, 0.160156f, 0.503906f},
+ {0.214844f, 0.695312f, 0.597656f, 0.980469f}, {0.550781f, 0.246094f, 0.207031f, 0.562500f},
+ {0.847656f, 0.335938f, 0.789062f, 0.851562f}, {0.152344f, 0.601562f, 0.519531f, 0.277344f},
+ {0.722656f, 0.738281f, 0.742188f, 0.171875f}, {0.226562f, 0.296875f, 0.375000f, 0.777344f},
+ {0.625000f, 0.031250f, 0.683594f, 0.078125f}, {0.984375f, 0.917969f, 0.867188f, 0.851562f},
+ {0.171875f, 0.710938f, 0.339844f, 0.585938f}, {0.351562f, 0.996094f, 0.011719f, 0.746094f},
+ {0.277344f, 0.765625f, 0.636719f, 0.406250f}, {0.101562f, 0.183594f, 0.964844f, 0.890625f},
+ {0.539062f, 0.332031f, 0.089844f, 0.542969f}, {0.847656f, 0.472656f, 0.218750f, 0.960938f},
+ {0.722656f, 0.621094f, 0.515625f, 0.015625f}, {0.109375f, 0.750000f, 0.750000f, 0.859375f},
+ {0.355469f, 0.835938f, 0.347656f, 0.167969f}, {0.679688f, 0.976562f, 0.949219f, 0.562500f},
+ {0.496094f, 0.468750f, 0.148438f, 0.812500f}, {0.292969f, 0.281250f, 0.789062f, 0.945312f},
+ {0.789062f, 0.585938f, 0.882812f, 0.335938f}, {0.062500f, 0.324219f, 0.007812f, 0.679688f},
+ {0.695312f, 0.410156f, 0.214844f, 0.597656f}, {0.191406f, 0.140625f, 0.371094f, 0.292969f},
+ {0.636719f, 0.933594f, 0.261719f, 0.054688f}, {0.078125f, 0.351562f, 0.675781f, 0.753906f},
+ {0.515625f, 0.585938f, 0.191406f, 0.195312f}, {0.886719f, 0.742188f, 0.625000f, 0.332031f},
+ {0.441406f, 0.457031f, 0.988281f, 0.726562f}, {0.253906f, 0.265625f, 0.015625f, 0.156250f},
+ {0.980469f, 0.511719f, 0.355469f, 0.570312f}, {0.031250f, 0.628906f, 0.824219f, 0.296875f},
+ {0.617188f, 0.347656f, 0.949219f, 0.203125f}, {0.566406f, 0.875000f, 0.636719f, 0.621094f},
+ {0.058594f, 0.664062f, 0.246094f, 0.257812f}, {0.515625f, 0.734375f, 0.574219f, 0.437500f},
+ {0.183594f, 0.406250f, 0.167969f, 0.796875f}, {0.414062f, 0.062500f, 0.273438f, 0.343750f},
+ {0.703125f, 0.292969f, 0.843750f, 0.855469f}, {0.222656f, 0.781250f, 0.011719f, 0.152344f},
+ {0.023438f, 0.648438f, 0.437500f, 0.312500f}, {0.292969f, 0.382812f, 0.582031f, 0.738281f},
+ {0.726562f, 0.851562f, 0.074219f, 0.628906f}, {0.066406f, 0.050781f, 0.406250f, 0.121094f},
+ {0.171875f, 0.300781f, 0.843750f, 0.464844f}, {0.585938f, 0.542969f, 0.539062f, 0.386719f},
+ {0.804688f, 0.839844f, 0.750000f, 0.039062f}, {0.453125f, 0.500000f, 0.882812f, 0.707031f},
+ {0.722656f, 0.757812f, 0.445312f, 0.484375f}, {0.066406f, 0.578125f, 0.382812f, 0.007812f},
+ {0.429688f, 0.449219f, 0.835938f, 0.789062f}, {0.347656f, 0.109375f, 0.085938f, 0.089844f},
+ {0.203125f, 0.378906f, 0.781250f, 0.343750f}, {0.085938f, 0.742188f, 0.269531f, 0.835938f},
+ {0.742188f, 0.585938f, 0.929688f, 0.179688f}, {0.394531f, 0.191406f, 0.839844f, 0.632812f},
+ {0.964844f, 0.960938f, 0.210938f, 0.328125f}, {0.515625f, 0.464844f, 0.570312f, 0.539062f},
+ {0.460938f, 0.828125f, 0.710938f, 0.226562f}, {0.941406f, 0.042969f, 0.351562f, 0.613281f},
+ {0.671875f, 0.425781f, 0.085938f, 0.386719f}, {0.085938f, 0.882812f, 0.484375f, 0.128906f},
+ {0.437500f, 0.617188f, 0.660156f, 0.253906f}, {0.125000f, 0.058594f, 0.015625f, 0.324219f},
+ {0.929688f, 0.468750f, 0.550781f, 0.632812f}, {0.792969f, 0.824219f, 0.425781f, 0.468750f},
+ {0.636719f, 0.023438f, 0.949219f, 0.007812f}, {0.335938f, 0.937500f, 0.046875f, 0.667969f},
+ {0.882812f, 0.437500f, 0.468750f, 0.339844f}, {0.437500f, 0.125000f, 0.976562f, 0.976562f},
+ {0.085938f, 0.671875f, 0.082031f, 0.394531f}, {0.398438f, 0.562500f, 0.433594f, 0.308594f},
+ {0.773438f, 0.351562f, 0.937500f, 0.925781f}, {0.664062f, 0.453125f, 0.742188f, 0.523438f},
+ {0.871094f, 0.046875f, 0.289062f, 0.351562f}, {0.792969f, 0.871094f, 0.847656f, 0.832031f},
+ {0.195312f, 0.132812f, 0.378906f, 0.261719f}, {0.425781f, 0.964844f, 0.687500f, 0.187500f},
+ {0.996094f, 0.570312f, 0.933594f, 0.734375f}, {0.253906f, 0.011719f, 0.429688f, 0.316406f},
+ {0.906250f, 0.519531f, 0.820312f, 0.457031f}, {0.140625f, 0.132812f, 0.644531f, 0.250000f},
+ {0.820312f, 0.667969f, 0.074219f, 0.035156f}, {0.089844f, 0.902344f, 0.500000f, 0.488281f},
+ {0.449219f, 0.781250f, 0.324219f, 0.871094f}, {0.339844f, 0.000000f, 0.562500f, 0.230469f},
+ {0.246094f, 0.546875f, 0.695312f, 0.101562f}, {0.578125f, 0.644531f, 0.898438f, 0.804688f},
+ {0.460938f, 0.757812f, 0.496094f, 0.367188f}, {0.796875f, 0.437500f, 0.117188f, 0.476562f},
+ {0.359375f, 0.304688f, 0.347656f, 0.984375f}, {0.015625f, 0.906250f, 0.542969f, 0.015625f},
+ {0.175781f, 0.007812f, 0.074219f, 0.605469f}, {0.660156f, 0.703125f, 0.718750f, 0.882812f},
+ {0.496094f, 0.183594f, 0.582031f, 0.382812f}, {0.410156f, 0.761719f, 0.687500f, 0.968750f},
+ {0.199219f, 0.093750f, 0.117188f, 0.460938f}, {0.285156f, 0.222656f, 0.519531f, 0.070312f},
+ {0.445312f, 0.539062f, 0.855469f, 0.859375f}, {0.746094f, 0.023438f, 0.445312f, 0.039062f},
+ {0.996094f, 0.828125f, 0.957031f, 0.558594f}, {0.625000f, 0.914062f, 0.714844f, 0.707031f},
+ {0.890625f, 0.574219f, 0.484375f, 0.917969f}, {0.144531f, 0.089844f, 0.355469f, 0.527344f},
+ {0.367188f, 0.710938f, 0.894531f, 0.390625f}, {0.906250f, 0.160156f, 0.746094f, 0.441406f},
+ {0.531250f, 0.218750f, 0.671875f, 0.062500f}, {0.828125f, 0.605469f, 0.957031f, 0.851562f},
+ {0.324219f, 0.414062f, 0.617188f, 0.992188f}, {0.406250f, 0.917969f, 0.113281f, 0.601562f},
+ {0.125000f, 0.023438f, 0.480469f, 0.160156f}, {0.296875f, 0.328125f, 0.199219f, 0.828125f},
+ {0.953125f, 0.191406f, 0.070312f, 0.429688f}, {0.527344f, 0.941406f, 0.730469f, 0.199219f},
+ {0.609375f, 0.289062f, 0.140625f, 0.894531f}, {0.929688f, 0.160156f, 0.949219f, 0.285156f},
+ {0.503906f, 0.812500f, 0.601562f, 0.582031f}, {0.863281f, 0.484375f, 0.421875f, 0.464844f},
+ {0.457031f, 0.082031f, 0.058594f, 0.078125f}, {0.164062f, 0.398438f, 0.644531f, 0.968750f},
+ {0.097656f, 0.281250f, 0.300781f, 0.425781f}, {0.781250f, 0.695312f, 0.945312f, 0.003906f},
+ {0.015625f, 0.328125f, 0.871094f, 0.695312f}, {0.851562f, 0.179688f, 0.257812f, 0.292969f},
+ {0.531250f, 0.777344f, 0.144531f, 0.765625f}, {0.328125f, 0.527344f, 0.859375f, 0.863281f},
+ {0.824219f, 0.296875f, 0.375000f, 0.437500f}, {0.726562f, 0.917969f, 0.808594f, 0.062500f},
+ {0.273438f, 0.394531f, 0.109375f, 0.164062f}, {0.417969f, 0.515625f, 0.332031f, 0.378906f},
+ {0.097656f, 0.761719f, 0.695312f, 0.792969f}, {0.472656f, 0.652344f, 0.609375f, 0.898438f},
+ {0.039062f, 0.171875f, 0.277344f, 0.511719f}, {0.261719f, 0.976562f, 0.136719f, 0.695312f},
+ {0.828125f, 0.238281f, 0.648438f, 0.140625f}, {0.585938f, 0.792969f, 0.234375f, 0.632812f},
+ {0.007812f, 0.082031f, 0.593750f, 0.218750f}, {0.492188f, 0.281250f, 0.152344f, 0.097656f},
+ {0.234375f, 0.636719f, 0.199219f, 0.652344f}, {0.457031f, 0.402344f, 0.542969f, 0.035156f},
+ {0.691406f, 0.714844f, 0.050781f, 0.476562f}, {0.054688f, 0.808594f, 0.625000f, 0.382812f},
+ {0.628906f, 0.371094f, 0.125000f, 0.617188f}, {0.480469f, 0.253906f, 0.261719f, 0.933594f},
+ {0.558594f, 0.699219f, 0.015625f, 0.667969f}, {0.414062f, 0.394531f, 0.585938f, 0.902344f},
+ {0.964844f, 0.214844f, 0.230469f, 0.746094f}, {0.726562f, 0.070312f, 0.968750f, 0.136719f},
+ {0.609375f, 0.714844f, 0.742188f, 0.628906f}, {0.871094f, 0.171875f, 0.109375f, 0.425781f},
+ {0.035156f, 0.988281f, 0.421875f, 0.917969f}, {0.742188f, 0.253906f, 0.781250f, 0.710938f},
+ {0.972656f, 0.039062f, 0.605469f, 0.554688f}, {0.285156f, 0.191406f, 0.968750f, 0.140625f},
+ {0.554688f, 0.531250f, 0.851562f, 0.656250f}, {0.949219f, 0.101562f, 0.406250f, 0.828125f},
+ {0.710938f, 0.394531f, 0.242188f, 0.507812f}, {0.312500f, 0.953125f, 0.796875f, 0.265625f},
+ {0.816406f, 0.566406f, 0.156250f, 0.683594f}, {0.902344f, 0.433594f, 0.425781f, 0.121094f},
+ {0.726562f, 0.921875f, 0.210938f, 0.820312f}, {0.953125f, 0.386719f, 0.054688f, 0.726562f},
+ {0.132812f, 0.988281f, 0.761719f, 0.320312f}, {0.847656f, 0.167969f, 0.320312f, 0.996094f},
+ {0.007812f, 0.445312f, 0.398438f, 0.406250f}, {0.261719f, 0.621094f, 0.632812f, 0.210938f},
+ {0.472656f, 0.343750f, 0.082031f, 0.011719f}, {0.804688f, 0.882812f, 0.207031f, 0.656250f},
+ {0.574219f, 0.429688f, 0.140625f, 0.816406f}, {0.429688f, 0.988281f, 0.265625f, 0.937500f},
+ {0.246094f, 0.757812f, 0.488281f, 0.242188f}, {0.109375f, 0.109375f, 0.042969f, 0.675781f},
+ {0.691406f, 0.675781f, 0.367188f, 0.507812f}, {0.992188f, 0.234375f, 0.292969f, 0.269531f},
+ {0.500000f, 0.730469f, 0.808594f, 0.753906f}, {0.761719f, 0.128906f, 0.984375f, 0.312500f},
+ {0.234375f, 0.667969f, 0.648438f, 0.964844f}, {0.851562f, 0.398438f, 0.550781f, 0.664062f},
+ {0.039062f, 0.523438f, 0.312500f, 0.136719f}, {0.152344f, 0.699219f, 0.492188f, 0.406250f},
+ {0.644531f, 0.976562f, 0.187500f, 0.945312f}, {0.253906f, 0.320312f, 0.710938f, 0.210938f},
+ {0.687500f, 0.667969f, 0.546875f, 0.761719f}, {0.570312f, 0.898438f, 0.757812f, 0.667969f},
+ {0.882812f, 0.769531f, 0.097656f, 0.144531f}, {0.359375f, 0.519531f, 0.460938f, 0.878906f},
+ {0.597656f, 0.105469f, 0.675781f, 0.472656f}, {0.285156f, 0.976562f, 0.523438f, 0.996094f},
+ {0.750000f, 0.250000f, 0.421875f, 0.082031f}, {0.050781f, 0.578125f, 0.980469f, 0.523438f},
+ {0.625000f, 0.738281f, 0.742188f, 0.683594f}, {0.500000f, 0.214844f, 0.269531f, 0.937500f},
+ {0.000000f, 0.992188f, 0.917969f, 0.296875f}, {0.187500f, 0.144531f, 0.832031f, 0.726562f},
+ {0.988281f, 0.277344f, 0.156250f, 0.226562f}, {0.769531f, 0.363281f, 0.398438f, 0.097656f},
+ {0.562500f, 0.570312f, 0.898438f, 0.437500f}, {0.687500f, 0.851562f, 0.531250f, 0.246094f},
+ {0.941406f, 0.410156f, 0.839844f, 0.027344f}, {0.730469f, 0.511719f, 0.308594f, 0.867188f},
+ {0.300781f, 0.199219f, 0.796875f, 0.492188f}, {0.914062f, 0.828125f, 0.496094f, 0.781250f},
+ {0.132812f, 0.949219f, 0.703125f, 0.171875f}, {0.953125f, 0.527344f, 0.445312f, 0.941406f},
+ {0.582031f, 0.230469f, 0.878906f, 0.691406f}, {0.339844f, 0.085938f, 0.781250f, 0.816406f},
+ {0.804688f, 0.890625f, 0.570312f, 0.062500f}, {0.082031f, 0.164062f, 0.312500f, 0.523438f},
+ {0.765625f, 0.785156f, 0.859375f, 0.101562f}, {0.312500f, 0.925781f, 0.453125f, 0.359375f},
+ {0.230469f, 0.558594f, 0.691406f, 0.578125f}, {0.535156f, 0.335938f, 0.378906f, 0.277344f},
+ {0.167969f, 0.441406f, 0.273438f, 0.777344f}, {0.941406f, 0.875000f, 0.855469f, 0.000000f},
+ {0.507812f, 0.371094f, 0.160156f, 0.507812f}, {0.394531f, 0.800781f, 0.050781f, 0.191406f},
+ {0.148438f, 0.597656f, 0.304688f, 0.261719f}, {0.679688f, 0.960938f, 0.457031f, 0.894531f},
+ {0.226562f, 0.855469f, 0.027344f, 0.410156f}, {0.843750f, 0.675781f, 0.765625f, 0.093750f},
+ {0.601562f, 0.796875f, 0.937500f, 0.222656f}, {0.097656f, 0.148438f, 0.488281f, 0.785156f},
+ {0.148438f, 0.300781f, 0.320312f, 0.035156f}, {0.539062f, 0.039062f, 0.906250f, 0.632812f},
+ {0.070312f, 0.609375f, 0.609375f, 0.363281f}, {0.671875f, 0.816406f, 0.972656f, 0.500000f},
+ {0.371094f, 0.312500f, 0.699219f, 0.585938f}, {0.589844f, 0.699219f, 0.136719f, 0.148438f},
+ {0.328125f, 0.261719f, 0.031250f, 0.773438f}, {0.546875f, 0.746094f, 0.910156f, 0.277344f},
+ {0.105469f, 0.195312f, 0.589844f, 0.472656f}, {0.679688f, 0.519531f, 0.773438f, 0.109375f},
+ {0.937500f, 0.246094f, 0.996094f, 0.722656f}, {0.179688f, 0.324219f, 0.558594f, 0.195312f},
+ {0.753906f, 0.562500f, 0.878906f, 0.562500f}, {0.601562f, 0.488281f, 0.222656f, 0.355469f},
+ {0.867188f, 0.949219f, 0.773438f, 0.105469f}, {0.210938f, 0.808594f, 0.167969f, 0.867188f},
+ {0.648438f, 0.363281f, 0.574219f, 0.058594f}, {0.078125f, 0.468750f, 0.410156f, 0.574219f},
+ {0.375000f, 0.878906f, 0.035156f, 0.515625f}, {0.679688f, 0.796875f, 0.234375f, 0.351562f},
+ {0.316406f, 0.007812f, 0.765625f, 0.742188f}, {0.792969f, 0.609375f, 0.375000f, 0.625000f},
+ {0.402344f, 0.234375f, 0.890625f, 0.808594f}, {0.019531f, 0.871094f, 0.007812f, 0.054688f},
+ {0.824219f, 0.546875f, 0.332031f, 0.546875f}, {0.320312f, 0.015625f, 0.812500f, 0.363281f},
+ {0.222656f, 0.144531f, 0.390625f, 0.246094f}, {0.722656f, 0.363281f, 0.167969f, 0.597656f},
+ {0.417969f, 0.859375f, 0.031250f, 0.792969f}, {0.179688f, 0.648438f, 0.800781f, 0.167969f},
+ {0.917969f, 0.402344f, 0.632812f, 0.351562f}, {0.246094f, 0.007812f, 0.058594f, 0.207031f},
+ {0.964844f, 0.839844f, 0.191406f, 0.585938f}, {0.367188f, 0.097656f, 0.503906f, 0.820312f},
+ {0.878906f, 0.609375f, 0.039062f, 0.117188f}, {0.589844f, 0.871094f, 0.640625f, 0.914062f},
+ {0.675781f, 0.058594f, 0.230469f, 0.542969f}, {0.296875f, 0.796875f, 0.773438f, 0.613281f},
+ {0.898438f, 0.484375f, 0.019531f, 0.828125f}, {0.140625f, 0.007812f, 0.730469f, 0.937500f},
+ {0.355469f, 0.304688f, 0.363281f, 0.578125f}, {0.191406f, 0.753906f, 0.070312f, 0.722656f},
+ {0.535156f, 0.906250f, 0.902344f, 0.433594f}, {0.636719f, 0.578125f, 0.031250f, 0.992188f},
+ {0.367188f, 0.019531f, 0.992188f, 0.332031f}, {0.738281f, 0.683594f, 0.343750f, 0.554688f},
+ {0.027344f, 0.320312f, 0.250000f, 0.128906f}, {0.285156f, 0.441406f, 0.167969f, 0.296875f},
+ {0.933594f, 0.605469f, 0.488281f, 0.234375f}, {0.179688f, 0.500000f, 0.980469f, 0.785156f},
+ {0.660156f, 0.304688f, 0.734375f, 0.433594f}, {0.011719f, 0.035156f, 0.183594f, 0.207031f},
+ {0.855469f, 0.843750f, 0.906250f, 0.703125f}, {0.371094f, 0.617188f, 0.042969f, 0.988281f},
+ {0.105469f, 0.269531f, 0.480469f, 0.398438f}, {0.656250f, 0.519531f, 0.640625f, 0.328125f},
+ {0.773438f, 0.097656f, 0.941406f, 0.843750f}, {0.312500f, 0.472656f, 0.539062f, 0.964844f},
+ {0.894531f, 0.703125f, 0.238281f, 0.046875f}, {0.109375f, 0.132812f, 0.703125f, 0.769531f},
+ {0.429688f, 0.273438f, 0.175781f, 0.585938f}, {0.046875f, 0.492188f, 0.574219f, 0.347656f},
+ {0.382812f, 0.355469f, 0.285156f, 0.953125f}, {0.472656f, 0.636719f, 0.660156f, 0.437500f},
+ {0.769531f, 0.847656f, 0.093750f, 0.542969f}, {0.347656f, 0.246094f, 0.832031f, 0.910156f},
+ {0.250000f, 0.726562f, 0.371094f, 0.175781f}, {0.875000f, 0.136719f, 0.273438f, 0.238281f},
+ {0.492188f, 0.484375f, 0.500000f, 0.671875f}, {0.210938f, 0.562500f, 0.871094f, 0.089844f},
+ {0.820312f, 0.078125f, 0.234375f, 0.890625f}, {0.718750f, 0.957031f, 0.812500f, 0.621094f},
+ {0.398438f, 0.121094f, 0.515625f, 0.949219f}, {0.035156f, 0.804688f, 0.300781f, 0.367188f},
+ {0.308594f, 0.015625f, 0.386719f, 0.589844f}, {0.640625f, 0.636719f, 0.707031f, 0.296875f},
+ {0.054688f, 0.898438f, 0.101562f, 0.023438f}, {0.468750f, 0.042969f, 0.445312f, 0.789062f},
+ {0.359375f, 0.285156f, 0.652344f, 0.714844f}, {0.027344f, 0.167969f, 0.925781f, 0.421875f},
+ {0.554688f, 0.539062f, 0.710938f, 0.929688f}, {0.890625f, 0.621094f, 0.332031f, 0.226562f},
+ {0.164062f, 0.093750f, 0.906250f, 0.109375f}, {0.578125f, 0.265625f, 0.855469f, 0.882812f},
+ {0.460938f, 0.910156f, 0.671875f, 0.042969f}, {0.914062f, 0.367188f, 0.105469f, 0.250000f},
+ {0.734375f, 0.070312f, 0.621094f, 0.492188f}, {0.542969f, 0.183594f, 0.996094f, 0.308594f},
+ {0.980469f, 0.421875f, 0.238281f, 0.703125f}, {0.128906f, 0.621094f, 0.503906f, 0.933594f},
+ {0.632812f, 0.925781f, 0.906250f, 0.839844f}, {0.953125f, 0.218750f, 0.597656f, 0.109375f},
+ {0.039062f, 0.589844f, 0.960938f, 0.402344f}, {0.667969f, 0.714844f, 0.218750f, 0.550781f},
+ {0.472656f, 0.484375f, 0.312500f, 0.718750f}, {0.558594f, 0.152344f, 0.582031f, 0.894531f},
+ {0.152344f, 0.355469f, 0.691406f, 0.023438f}, {0.691406f, 0.671875f, 0.445312f, 0.410156f},
+ {0.753906f, 0.316406f, 0.867188f, 0.496094f}, {0.527344f, 0.546875f, 0.562500f, 0.656250f},
+ {0.125000f, 0.714844f, 0.304688f, 0.042969f}, {0.390625f, 0.218750f, 0.988281f, 0.320312f},
+ {0.218750f, 0.894531f, 0.585938f, 0.183594f}, {0.511719f, 0.691406f, 0.187500f, 0.761719f},
+ {0.457031f, 0.101562f, 0.457031f, 0.296875f}, {0.050781f, 0.628906f, 0.671875f, 0.371094f},
+ {0.816406f, 0.148438f, 0.554688f, 0.054688f}, {0.082031f, 0.371094f, 0.386719f, 0.269531f},
+ {0.417969f, 0.472656f, 0.753906f, 0.617188f}, {0.839844f, 0.175781f, 0.109375f, 0.750000f},
+ {0.218750f, 0.933594f, 0.656250f, 0.421875f}, {0.527344f, 0.742188f, 0.910156f, 0.910156f},
+ {0.875000f, 0.050781f, 0.402344f, 0.589844f}, {0.390625f, 0.988281f, 0.082031f, 0.972656f},
+ {0.460938f, 0.652344f, 0.355469f, 0.148438f}, {0.921875f, 0.464844f, 0.546875f, 0.847656f},
+ {0.601562f, 0.113281f, 0.132812f, 0.484375f}, {0.710938f, 0.964844f, 0.773438f, 0.089844f},
+ {0.273438f, 0.761719f, 0.593750f, 0.550781f}, {0.433594f, 0.664062f, 0.199219f, 0.156250f},
+ {0.203125f, 0.222656f, 0.355469f, 0.664062f}, {0.000000f, 0.835938f, 0.812500f, 0.609375f},
+ {0.625000f, 0.320312f, 0.738281f, 0.445312f}, {0.804688f, 0.410156f, 0.914062f, 0.304688f},
+ {0.523438f, 0.617188f, 0.644531f, 0.695312f}, {0.738281f, 0.070312f, 0.121094f, 0.179688f},
+ {0.886719f, 0.210938f, 0.890625f, 0.859375f}, {0.210938f, 0.984375f, 0.531250f, 0.730469f},
+ {0.988281f, 0.464844f, 0.000000f, 0.312500f}, {0.628906f, 0.527344f, 0.726562f, 0.078125f},
+ {0.433594f, 0.902344f, 0.472656f, 0.765625f}, {0.789062f, 0.058594f, 0.171875f, 0.957031f},
+ {0.042969f, 0.656250f, 0.570312f, 0.441406f}, {0.652344f, 0.796875f, 0.656250f, 0.832031f},
+ {0.914062f, 0.371094f, 0.339844f, 0.332031f}, {0.164062f, 0.875000f, 0.453125f, 0.515625f},
+ {0.968750f, 0.476562f, 0.167969f, 0.750000f}, {0.777344f, 0.683594f, 0.683594f, 0.160156f},
+ {0.492188f, 0.851562f, 0.019531f, 0.843750f}, {0.855469f, 0.144531f, 0.808594f, 0.972656f},
+ {0.960938f, 0.449219f, 0.332031f, 0.453125f}, {0.265625f, 0.781250f, 0.531250f, 0.898438f},
+ {0.781250f, 0.394531f, 0.851562f, 0.183594f}, {0.921875f, 0.855469f, 0.015625f, 0.628906f},
+ {0.285156f, 0.066406f, 0.132812f, 0.378906f}, {0.421875f, 0.992188f, 0.507812f, 0.796875f},
+ {0.816406f, 0.753906f, 0.269531f, 0.695312f}, {0.972656f, 0.570312f, 0.468750f, 0.449219f},
+ {0.113281f, 0.148438f, 0.160156f, 0.554688f}, {0.199219f, 0.726562f, 0.796875f, 0.992188f},
+ {0.285156f, 0.464844f, 0.289062f, 0.164062f}, {0.070312f, 0.785156f, 0.453125f, 0.875000f},
+ {0.375000f, 0.832031f, 0.843750f, 0.437500f}, {0.500000f, 0.269531f, 0.125000f, 0.023438f},
+ {0.445312f, 0.726562f, 0.687500f, 0.507812f}, {0.089844f, 0.457031f, 0.277344f, 0.289062f},
+ {0.839844f, 0.046875f, 0.359375f, 0.917969f}, {0.773438f, 0.300781f, 0.761719f, 0.050781f},
+ {0.347656f, 0.945312f, 0.882812f, 0.640625f}, {0.101562f, 0.902344f, 0.117188f, 0.460938f},
+ {0.816406f, 0.785156f, 0.937500f, 0.265625f}, {0.445312f, 0.453125f, 0.351562f, 0.765625f},
+ {0.226562f, 0.171875f, 0.726562f, 0.351562f}, {0.324219f, 0.921875f, 0.082031f, 0.839844f},
+ {0.808594f, 0.402344f, 0.421875f, 0.988281f}, {0.027344f, 0.113281f, 0.492188f, 0.398438f},
+ {0.855469f, 0.589844f, 0.109375f, 0.480469f}, {0.648438f, 0.339844f, 0.878906f, 0.066406f},
+ {0.976562f, 0.945312f, 0.257812f, 0.539062f}, {0.765625f, 0.433594f, 0.953125f, 0.160156f},
+ {0.250000f, 0.726562f, 0.140625f, 0.820312f}, {0.570312f, 0.261719f, 0.210938f, 0.894531f},
+ {0.964844f, 0.789062f, 0.613281f, 0.097656f}, {0.160156f, 0.117188f, 0.300781f, 0.210938f},
+ {0.488281f, 0.839844f, 0.820312f, 0.859375f}, {0.707031f, 0.542969f, 0.019531f, 0.496094f},
+ {0.605469f, 0.273438f, 0.714844f, 0.007812f}, {0.125000f, 0.820312f, 0.222656f, 0.718750f},
+ {0.750000f, 0.363281f, 0.652344f, 0.339844f}, {0.207031f, 0.195312f, 0.804688f, 0.636719f},
+ {0.050781f, 0.718750f, 0.300781f, 0.039062f}, {0.492188f, 0.406250f, 0.406250f, 0.906250f},
+ {0.910156f, 0.152344f, 0.992188f, 0.796875f}, {0.832031f, 0.015625f, 0.683594f, 0.214844f},
+ {0.570312f, 0.937500f, 0.085938f, 0.738281f}, {0.984375f, 0.570312f, 0.472656f, 0.371094f},
+ {0.468750f, 0.050781f, 0.394531f, 0.121094f}, {0.253906f, 0.886719f, 0.066406f, 0.820312f},
+ {0.328125f, 0.769531f, 0.332031f, 0.535156f}, {0.937500f, 0.921875f, 0.441406f, 0.011719f},
+ {0.640625f, 0.718750f, 0.199219f, 0.488281f}, {0.289062f, 0.031250f, 0.390625f, 0.136719f},
+ {0.007812f, 0.773438f, 0.992188f, 0.601562f}, {0.566406f, 0.398438f, 0.230469f, 0.406250f},
+ {0.171875f, 0.191406f, 0.785156f, 0.855469f}, {0.933594f, 0.343750f, 0.046875f, 0.285156f},
+ {0.121094f, 0.949219f, 0.921875f, 0.003906f}, {0.292969f, 0.218750f, 0.097656f, 0.558594f},
+ {0.441406f, 0.027344f, 0.734375f, 0.199219f}, {0.515625f, 0.597656f, 0.976562f, 0.050781f},
+ {0.250000f, 0.402344f, 0.066406f, 0.425781f}, {0.363281f, 0.300781f, 0.859375f, 0.250000f},
+ {0.203125f, 0.546875f, 0.433594f, 0.066406f}, {0.117188f, 0.363281f, 0.613281f, 0.644531f},
+ {0.542969f, 0.726562f, 0.191406f, 0.535156f}, {0.410156f, 0.199219f, 0.964844f, 0.125000f},
+ {0.140625f, 0.578125f, 0.261719f, 0.316406f}, {0.667969f, 0.660156f, 0.394531f, 0.496094f},
+ {0.488281f, 0.441406f, 0.625000f, 0.003906f}, {0.734375f, 0.304688f, 0.820312f, 0.601562f},
+ {0.007812f, 0.203125f, 0.082031f, 0.292969f}, {0.250000f, 0.417969f, 0.593750f, 0.191406f},
+ {0.511719f, 0.503906f, 0.953125f, 0.832031f}, {0.703125f, 0.960938f, 0.417969f, 0.656250f},
+ {0.605469f, 0.656250f, 0.566406f, 0.386719f}, {0.886719f, 0.312500f, 0.070312f, 0.097656f},
+ {0.753906f, 0.511719f, 0.640625f, 0.777344f}, {0.191406f, 0.109375f, 0.203125f, 0.621094f},
+ {0.917969f, 0.992188f, 0.738281f, 0.175781f}, {0.300781f, 0.390625f, 0.437500f, 0.664062f},
+ {0.515625f, 0.816406f, 0.078125f, 0.742188f}, {0.230469f, 0.085938f, 0.488281f, 0.226562f},
+ {0.589844f, 0.203125f, 0.546875f, 0.324219f}, {0.894531f, 0.558594f, 0.406250f, 0.832031f},
+ {0.292969f, 0.261719f, 0.250000f, 0.964844f}, {0.058594f, 0.027344f, 0.789062f, 0.179688f},
+ {0.968750f, 0.812500f, 0.515625f, 0.554688f}, {0.484375f, 0.496094f, 0.207031f, 0.242188f},
+ {0.914062f, 0.253906f, 0.921875f, 0.144531f}, {0.605469f, 0.968750f, 0.816406f, 0.714844f},
+ {0.734375f, 0.457031f, 0.699219f, 0.648438f}, {0.097656f, 0.183594f, 0.332031f, 0.882812f},
+ {0.410156f, 0.832031f, 0.605469f, 0.957031f}, {0.292969f, 0.542969f, 0.761719f, 0.679688f},
+ {0.691406f, 0.039062f, 0.421875f, 0.597656f}, {0.878906f, 0.984375f, 0.859375f, 0.468750f},
+ {0.324219f, 0.601562f, 0.507812f, 0.710938f}, {0.664062f, 0.343750f, 0.925781f, 0.363281f},
+ {0.785156f, 0.640625f, 0.453125f, 0.070312f}, {0.093750f, 0.214844f, 0.582031f, 0.652344f},
+ {0.347656f, 0.417969f, 0.519531f, 0.390625f}, {0.949219f, 0.140625f, 0.843750f, 0.277344f},
+ {0.261719f, 0.769531f, 0.937500f, 0.546875f}, {0.566406f, 0.535156f, 0.066406f, 0.757812f},
+ {0.328125f, 0.250000f, 0.503906f, 0.253906f}, {0.796875f, 0.589844f, 0.871094f, 0.445312f},
+ {0.144531f, 0.898438f, 0.003906f, 0.304688f}, {0.074219f, 0.308594f, 0.261719f, 0.953125f},
+ {0.355469f, 0.390625f, 0.839844f, 0.492188f}, {0.691406f, 0.742188f, 0.144531f, 0.062500f},
+ {0.863281f, 0.183594f, 0.589844f, 0.917969f}, {0.175781f, 0.527344f, 0.976562f, 0.230469f},
+ {0.582031f, 0.238281f, 0.511719f, 0.992188f}, {0.074219f, 0.441406f, 0.855469f, 0.644531f},
+ {0.140625f, 0.554688f, 0.750000f, 0.277344f}, {0.488281f, 0.328125f, 0.687500f, 0.941406f},
+ {0.824219f, 0.121094f, 0.582031f, 0.210938f}, {0.703125f, 0.687500f, 0.332031f, 0.699219f},
+ {0.324219f, 0.593750f, 0.625000f, 0.519531f}, {0.734375f, 0.859375f, 0.429688f, 0.644531f},
+ {0.390625f, 0.433594f, 0.839844f, 0.378906f}, {0.609375f, 0.515625f, 0.390625f, 0.738281f},
+ {0.761719f, 0.714844f, 0.539062f, 0.976562f}, {0.074219f, 0.269531f, 0.277344f, 0.679688f},
+ {0.882812f, 0.167969f, 0.636719f, 0.796875f}, {0.667969f, 0.769531f, 0.226562f, 0.886719f},
+ {0.593750f, 0.925781f, 0.941406f, 0.492188f}, {0.734375f, 0.078125f, 0.128906f, 0.386719f},
+ {0.332031f, 0.980469f, 0.722656f, 0.765625f}, {0.699219f, 0.269531f, 0.058594f, 0.265625f},
+ {0.835938f, 0.105469f, 0.476562f, 0.699219f}, {0.058594f, 0.917969f, 0.753906f, 0.984375f},
+ {0.191406f, 0.710938f, 0.214844f, 0.847656f}, {0.609375f, 0.023438f, 0.976562f, 0.144531f},
+ {0.332031f, 0.894531f, 0.683594f, 0.953125f}, {0.640625f, 0.339844f, 0.355469f, 0.761719f},
+ {0.867188f, 0.839844f, 0.023438f, 0.027344f}, {0.359375f, 0.117188f, 0.222656f, 0.328125f},
+ {0.441406f, 0.242188f, 0.718750f, 0.726562f}, {0.136719f, 0.933594f, 0.878906f, 0.585938f},
+ {0.656250f, 0.027344f, 0.382812f, 0.218750f}, {0.796875f, 0.566406f, 0.531250f, 0.976562f},
+ {0.582031f, 0.160156f, 0.023438f, 0.339844f}, {0.703125f, 0.664062f, 0.921875f, 0.425781f},
+ {0.390625f, 0.765625f, 0.851562f, 0.812500f}, {0.132812f, 0.515625f, 0.156250f, 0.945312f},
+ {0.996094f, 0.871094f, 0.718750f, 0.140625f}, {0.718750f, 0.417969f, 0.003906f, 0.593750f},
+ {0.406250f, 0.632812f, 0.621094f, 0.066406f}, {0.652344f, 0.738281f, 0.148438f, 0.679688f},
+ {0.167969f, 0.363281f, 0.285156f, 0.929688f}, {0.082031f, 0.078125f, 0.667969f, 0.000000f},
+ {0.429688f, 0.675781f, 0.027344f, 0.453125f}, {0.261719f, 0.617188f, 0.382812f, 0.796875f},
+ {0.339844f, 0.785156f, 0.234375f, 0.265625f}, {0.546875f, 0.050781f, 0.523438f, 0.105469f},
+ {0.164062f, 0.273438f, 0.007812f, 0.222656f}, {0.910156f, 0.667969f, 0.804688f, 0.390625f},
+ {0.492188f, 0.203125f, 0.082031f, 0.011719f}, {0.121094f, 0.863281f, 0.269531f, 0.242188f},
+ {0.011719f, 0.414062f, 0.695312f, 0.519531f}, {0.449219f, 0.496094f, 0.058594f, 0.972656f},
+ {0.238281f, 0.914062f, 0.191406f, 0.765625f}, {0.855469f, 0.078125f, 0.367188f, 0.179688f},
+ {0.046875f, 0.882812f, 0.281250f, 0.828125f}, {0.437500f, 0.687500f, 0.148438f, 0.113281f},
+ {0.816406f, 0.015625f, 0.613281f, 0.949219f}, {0.683594f, 0.937500f, 0.437500f, 0.187500f},
+ {0.988281f, 0.859375f, 0.238281f, 0.867188f}, {0.398438f, 0.085938f, 0.574219f, 0.597656f},
+ {0.636719f, 0.496094f, 0.722656f, 0.683594f}, {0.742188f, 0.808594f, 0.339844f, 0.019531f},
+ {0.234375f, 0.625000f, 0.531250f, 0.574219f}, {0.535156f, 0.460938f, 0.890625f, 0.269531f},
+ {0.050781f, 0.976562f, 0.289062f, 0.781250f}, {0.730469f, 0.109375f, 0.214844f, 0.460938f},
+ {0.371094f, 0.363281f, 0.789062f, 0.390625f}, {0.789062f, 0.656250f, 0.042969f, 0.074219f},
+ {0.679688f, 0.164062f, 0.269531f, 0.757812f}, {0.402344f, 0.839844f, 0.105469f, 0.359375f},
+ {0.875000f, 0.261719f, 0.875000f, 0.808594f}, {0.234375f, 0.933594f, 0.144531f, 0.046875f},
+ {0.062500f, 0.082031f, 0.945312f, 0.125000f}, {0.523438f, 0.285156f, 0.289062f, 0.937500f},
+ {0.855469f, 0.753906f, 0.691406f, 0.164062f}, {0.984375f, 0.148438f, 0.207031f, 0.464844f},
+ {0.027344f, 0.894531f, 0.132812f, 0.265625f}, {0.562500f, 0.976562f, 0.785156f, 0.593750f},
+ {0.144531f, 0.625000f, 0.476562f, 0.136719f}, {0.824219f, 0.046875f, 0.355469f, 0.320312f},
+ {0.445312f, 0.226562f, 0.558594f, 0.710938f}, {0.000000f, 0.664062f, 0.289062f, 0.207031f},
+ {0.910156f, 0.468750f, 0.835938f, 0.921875f}, {0.222656f, 0.609375f, 0.589844f, 0.039062f},
+ {0.582031f, 0.820312f, 0.898438f, 0.812500f}, {0.984375f, 0.347656f, 0.308594f, 0.445312f},
+ {0.378906f, 0.238281f, 0.550781f, 0.238281f}, {0.796875f, 0.523438f, 0.437500f, 0.542969f},
+ {0.937500f, 0.792969f, 0.179688f, 0.355469f}, {0.097656f, 0.687500f, 0.742188f, 0.429688f},
+ {0.761719f, 0.597656f, 0.523438f, 0.511719f}, {0.035156f, 0.050781f, 0.929688f, 0.132812f},
+ {0.957031f, 0.406250f, 0.328125f, 0.921875f}, {0.230469f, 0.609375f, 0.148438f, 0.472656f},
+ {0.335938f, 0.707031f, 0.777344f, 0.285156f}, {0.019531f, 0.351562f, 0.976562f, 0.824219f},
+ {0.261719f, 0.859375f, 0.316406f, 0.058594f}, {0.058594f, 0.230469f, 0.570312f, 0.570312f},
+ {0.882812f, 0.324219f, 0.652344f, 0.484375f}, {0.628906f, 0.601562f, 0.210938f, 0.015625f},
+ {0.195312f, 0.132812f, 0.988281f, 0.371094f}, {0.015625f, 0.699219f, 0.832031f, 0.527344f},
+ {0.535156f, 0.066406f, 0.335938f, 0.433594f}, {0.851562f, 0.976562f, 0.953125f, 0.742188f},
+ {0.574219f, 0.578125f, 0.468750f, 0.621094f}, {0.773438f, 0.855469f, 0.843750f, 0.316406f},
+ {0.703125f, 0.148438f, 0.750000f, 0.898438f}, {0.187500f, 0.300781f, 0.136719f, 0.582031f},
+ {0.960938f, 0.742188f, 0.644531f, 0.359375f}, {0.796875f, 0.378906f, 0.972656f, 0.523438f},
+ {0.031250f, 0.917969f, 0.171875f, 0.847656f}, {0.593750f, 0.507812f, 0.468750f, 0.445312f},
+ {0.207031f, 0.332031f, 0.359375f, 0.785156f}, {0.753906f, 0.105469f, 0.566406f, 0.914062f},
+ {0.386719f, 0.695312f, 0.960938f, 0.128906f}, {0.613281f, 0.000000f, 0.128906f, 0.308594f},
+ {0.914062f, 0.296875f, 0.792969f, 0.570312f}, {0.300781f, 0.730469f, 0.734375f, 0.457031f},
+ {0.550781f, 0.574219f, 0.972656f, 0.890625f}, {0.644531f, 0.480469f, 0.046875f, 0.687500f},
+ {0.160156f, 0.312500f, 0.335938f, 0.500000f}, {0.507812f, 0.625000f, 0.765625f, 0.417969f},
+ {0.093750f, 0.433594f, 0.164062f, 0.082031f}, {0.195312f, 0.347656f, 0.953125f, 0.355469f},
+ {0.468750f, 0.699219f, 0.109375f, 0.140625f}, {0.941406f, 0.210938f, 0.449219f, 0.832031f},
+ {0.296875f, 0.039062f, 0.656250f, 0.410156f}, {0.417969f, 0.277344f, 0.761719f, 0.878906f},
+ {0.121094f, 0.679688f, 0.027344f, 0.625000f}, {0.910156f, 0.792969f, 0.699219f, 0.156250f},
+ {0.449219f, 0.863281f, 0.625000f, 0.710938f}, {0.968750f, 0.011719f, 0.367188f, 0.871094f},
+ {0.199219f, 0.964844f, 0.554688f, 0.546875f}, {0.531250f, 0.605469f, 0.816406f, 0.441406f},
+ {0.105469f, 0.496094f, 0.460938f, 0.906250f}, {0.960938f, 0.804688f, 0.062500f, 0.484375f},
+ {0.457031f, 0.546875f, 0.515625f, 0.324219f}, {0.660156f, 0.003906f, 0.753906f, 0.578125f},
+ {0.199219f, 0.636719f, 0.035156f, 0.804688f}, {0.265625f, 0.320312f, 0.593750f, 0.093750f},
+ {0.347656f, 0.101562f, 0.957031f, 0.906250f}, {0.710938f, 0.453125f, 0.875000f, 0.363281f},
+ {0.402344f, 0.824219f, 0.027344f, 0.019531f}, {0.292969f, 0.531250f, 0.750000f, 0.554688f},
+ {0.976562f, 0.414062f, 0.910156f, 0.949219f}, {0.078125f, 0.863281f, 0.507812f, 0.089844f},
+ {0.792969f, 0.312500f, 0.390625f, 0.609375f}, {0.500000f, 0.000000f, 0.664062f, 0.347656f},
+ {0.304688f, 0.507812f, 0.160156f, 0.570312f}, {0.089844f, 0.152344f, 0.109375f, 0.097656f},
+ {0.457031f, 0.957031f, 0.800781f, 0.664062f}, {0.539062f, 0.636719f, 0.066406f, 0.738281f},
+ {0.144531f, 0.085938f, 0.878906f, 0.082031f}, {0.414062f, 0.175781f, 0.277344f, 0.886719f},
+ {0.292969f, 0.285156f, 0.835938f, 0.636719f}, {0.570312f, 0.750000f, 0.617188f, 0.257812f},
+ {0.812500f, 0.886719f, 0.058594f, 0.851562f}, {0.527344f, 0.199219f, 0.464844f, 0.082031f},
+ {0.851562f, 0.773438f, 0.664062f, 0.535156f}, {0.414062f, 0.441406f, 0.257812f, 0.679688f},
+ {0.976562f, 0.914062f, 0.109375f, 0.148438f}, {0.539062f, 0.488281f, 0.812500f, 0.886719f},
+ {0.816406f, 0.000000f, 0.371094f, 0.257812f}, {0.316406f, 0.960938f, 0.285156f, 0.703125f},
+ {0.484375f, 0.382812f, 0.457031f, 0.785156f}, {0.785156f, 0.277344f, 0.675781f, 0.875000f},
+ {0.265625f, 0.476562f, 0.070312f, 0.289062f}, {0.355469f, 0.207031f, 0.585938f, 0.109375f},
+ {0.636719f, 0.917969f, 0.179688f, 0.851562f}, {0.929688f, 0.519531f, 0.347656f, 0.515625f},
+ {0.007812f, 0.425781f, 0.554688f, 0.199219f}, {0.507812f, 0.011719f, 0.445312f, 0.085938f},
+ {0.667969f, 0.886719f, 0.859375f, 0.976562f}, {0.382812f, 0.476562f, 0.300781f, 0.738281f},
+ {0.843750f, 0.128906f, 0.726562f, 0.613281f}, {0.437500f, 0.808594f, 0.898438f, 0.183594f},
+ {0.652344f, 0.582031f, 0.667969f, 0.332031f}, {0.984375f, 0.753906f, 0.835938f, 0.699219f},
+ {0.812500f, 0.242188f, 0.320312f, 0.636719f}, {0.511719f, 0.945312f, 0.625000f, 0.816406f},
+ {0.183594f, 0.796875f, 0.421875f, 0.027344f}, {0.742188f, 0.179688f, 0.882812f, 0.253906f},
+ {0.972656f, 0.375000f, 0.660156f, 0.613281f}, {0.378906f, 0.964844f, 0.480469f, 0.324219f},
+ {0.015625f, 0.222656f, 0.863281f, 0.046875f}, {0.871094f, 0.058594f, 0.695312f, 0.800781f},
+ {0.289062f, 0.792969f, 0.382812f, 0.644531f}, {0.765625f, 0.171875f, 0.636719f, 0.929688f},
+ {0.554688f, 0.988281f, 0.808594f, 0.531250f}, {0.023438f, 0.546875f, 0.218750f, 0.730469f},
+ {0.882812f, 0.886719f, 0.929688f, 0.191406f}, {0.605469f, 0.136719f, 0.167969f, 0.332031f},
+ {0.812500f, 0.335938f, 0.414062f, 0.519531f}, {0.652344f, 0.585938f, 0.953125f, 0.093750f},
+ {0.269531f, 0.488281f, 0.132812f, 0.312500f}, {0.019531f, 0.292969f, 0.472656f, 0.589844f},
+ {0.316406f, 0.410156f, 0.914062f, 0.195312f}, {0.613281f, 0.742188f, 0.175781f, 0.023438f},
+ {0.761719f, 0.207031f, 0.398438f, 0.660156f}, {0.363281f, 0.363281f, 0.664062f, 0.253906f},
+ {0.585938f, 0.449219f, 0.246094f, 0.746094f}, {0.796875f, 0.996094f, 0.902344f, 0.882812f},
+ {0.136719f, 0.835938f, 0.367188f, 0.230469f}, {0.492188f, 0.390625f, 0.492188f, 0.707031f},
+ {0.812500f, 0.562500f, 0.316406f, 0.515625f}, {0.636719f, 0.687500f, 0.421875f, 0.839844f},
+ {0.898438f, 0.343750f, 0.164062f, 0.664062f}, {0.179688f, 0.125000f, 0.695312f, 0.453125f},
+ {0.527344f, 0.746094f, 0.097656f, 0.816406f}, {0.625000f, 0.183594f, 0.207031f, 0.156250f},
+ {0.371094f, 0.906250f, 0.003906f, 0.421875f}, {0.160156f, 0.707031f, 0.781250f, 0.683594f},
+ {0.656250f, 0.773438f, 0.343750f, 0.894531f}, {0.875000f, 0.406250f, 0.945312f, 0.171875f},
+ {0.242188f, 0.859375f, 0.699219f, 0.394531f}, {0.703125f, 0.460938f, 0.375000f, 0.281250f},
+ {0.902344f, 0.371094f, 0.636719f, 0.937500f}, {0.207031f, 0.558594f, 0.476562f, 0.574219f},
+ {0.679688f, 0.980469f, 0.121094f, 0.203125f}, {0.476562f, 0.484375f, 0.402344f, 0.773438f},
+ {0.171875f, 0.332031f, 0.808594f, 0.699219f}, {0.718750f, 0.144531f, 0.906250f, 0.417969f},
+ {0.113281f, 0.527344f, 0.195312f, 0.351562f}, {0.617188f, 0.066406f, 0.507812f, 0.933594f},
+ {0.460938f, 0.277344f, 0.417969f, 0.734375f}, {0.160156f, 0.640625f, 0.613281f, 0.394531f},
+ {0.730469f, 0.738281f, 0.039062f, 0.105469f}, {0.078125f, 0.187500f, 0.777344f, 0.617188f},
+ {0.425781f, 0.824219f, 0.527344f, 0.171875f}, {0.679688f, 0.898438f, 0.128906f, 0.984375f},
+ {0.949219f, 0.769531f, 0.414062f, 0.230469f}, {0.128906f, 0.320312f, 0.886719f, 0.402344f},
+ {0.234375f, 0.648438f, 0.046875f, 0.160156f}, {0.394531f, 0.242188f, 0.964844f, 0.691406f},
+ {0.312500f, 0.800781f, 0.265625f, 0.769531f}, {0.875000f, 0.695312f, 0.785156f, 0.414062f},
+ {0.132812f, 0.562500f, 0.085938f, 0.046875f}, {0.238281f, 0.218750f, 0.574219f, 0.292969f},
+ {0.722656f, 0.640625f, 0.394531f, 0.136719f}, {0.304688f, 0.062500f, 0.222656f, 0.941406f},
+ {0.074219f, 0.972656f, 0.039062f, 0.078125f}, {0.351562f, 0.445312f, 0.152344f, 0.542969f},
+ {0.265625f, 0.148438f, 0.500000f, 0.417969f}, {0.054688f, 0.531250f, 0.246094f, 0.203125f},
+ {0.687500f, 0.621094f, 0.007812f, 0.937500f}, {0.113281f, 0.457031f, 0.535156f, 0.378906f},
+ {0.472656f, 0.105469f, 0.210938f, 0.144531f}, {0.218750f, 0.664062f, 0.113281f, 0.996094f},
+ {0.703125f, 0.843750f, 0.261719f, 0.218750f}, {0.925781f, 0.523438f, 0.550781f, 0.722656f},
+ {0.613281f, 0.730469f, 0.019531f, 0.289062f}, {0.367188f, 0.269531f, 0.886719f, 0.472656f},
+ {0.843750f, 0.074219f, 0.304688f, 0.238281f}, {0.703125f, 0.648438f, 0.054688f, 0.984375f},
+ {0.171875f, 0.425781f, 0.371094f, 0.078125f}, {0.335938f, 0.734375f, 0.566406f, 0.660156f},
+ {0.496094f, 0.949219f, 0.500000f, 0.906250f}, {0.214844f, 0.058594f, 0.312500f, 0.750000f},
+ {0.554688f, 0.203125f, 0.867188f, 0.964844f}, {0.839844f, 0.707031f, 0.238281f, 0.257812f},
+ {0.707031f, 0.113281f, 0.679688f, 0.828125f}, {0.890625f, 0.890625f, 0.296875f, 0.144531f},
+ {0.164062f, 0.042969f, 0.968750f, 0.972656f}, {0.273438f, 0.671875f, 0.796875f, 0.609375f},
+ {0.019531f, 0.156250f, 0.562500f, 0.078125f}, {0.910156f, 0.246094f, 0.183594f, 0.371094f},
+ {0.414062f, 0.707031f, 0.824219f, 0.437500f}, {0.085938f, 0.195312f, 0.082031f, 0.046875f},
+ {0.945312f, 0.781250f, 0.683594f, 0.308594f}, {0.218750f, 0.023438f, 0.621094f, 0.175781f},
+ {0.464844f, 0.234375f, 0.261719f, 0.964844f}, {0.105469f, 0.957031f, 0.582031f, 0.234375f},
+ {0.750000f, 0.488281f, 0.808594f, 0.738281f}, {0.253906f, 0.582031f, 0.457031f, 0.285156f},
+ {0.855469f, 0.367188f, 0.984375f, 0.859375f}, {0.425781f, 0.121094f, 0.250000f, 0.492188f},
+ {0.945312f, 0.550781f, 0.433594f, 0.222656f}, {0.738281f, 0.214844f, 0.503906f, 0.953125f},
+ {0.019531f, 0.046875f, 0.226562f, 0.515625f}, {0.324219f, 0.734375f, 0.574219f, 0.785156f},
+ {0.589844f, 0.257812f, 0.011719f, 0.015625f}, {0.843750f, 0.812500f, 0.988281f, 0.468750f},
+ {0.992188f, 0.007812f, 0.238281f, 0.312500f}, {0.082031f, 0.425781f, 0.699219f, 0.054688f},
+ {0.382812f, 0.843750f, 0.304688f, 0.972656f}, {0.890625f, 0.667969f, 0.558594f, 0.183594f},
+ {0.281250f, 0.968750f, 0.000000f, 0.003906f}, {0.687500f, 0.812500f, 0.742188f, 0.632812f},
+ {0.910156f, 0.121094f, 0.867188f, 0.207031f}, {0.347656f, 0.574219f, 0.957031f, 0.511719f},
+ {0.238281f, 0.421875f, 0.183594f, 0.957031f}, {0.960938f, 0.097656f, 0.707031f, 0.316406f},
+ {0.585938f, 0.667969f, 0.921875f, 0.445312f}, {0.835938f, 0.535156f, 0.238281f, 0.660156f},
+ {0.039062f, 0.031250f, 0.800781f, 0.074219f}, {0.464844f, 0.125000f, 0.734375f, 0.808594f},
+ {0.742188f, 0.390625f, 0.503906f, 0.367188f}, {0.828125f, 0.054688f, 0.113281f, 0.953125f},
+ {0.550781f, 0.996094f, 0.621094f, 0.472656f}, {0.625000f, 0.175781f, 0.203125f, 0.636719f},
+ {0.472656f, 0.347656f, 0.941406f, 0.871094f}, {0.046875f, 0.945312f, 0.050781f, 0.675781f},
+ {0.937500f, 0.414062f, 0.503906f, 0.492188f}, {0.500000f, 0.265625f, 0.632812f, 0.832031f},
+ {0.894531f, 0.683594f, 0.992188f, 0.753906f}, {0.148438f, 0.367188f, 0.437500f, 0.277344f},
+ {0.550781f, 0.890625f, 0.777344f, 0.050781f}, {0.945312f, 0.316406f, 0.710938f, 0.871094f},
+ {0.410156f, 0.046875f, 0.343750f, 0.484375f}, {0.597656f, 0.855469f, 0.949219f, 0.671875f},
+ {0.843750f, 0.261719f, 0.398438f, 0.781250f}, {0.781250f, 0.769531f, 0.597656f, 0.515625f},
+ {0.320312f, 0.140625f, 0.796875f, 0.578125f}, {0.425781f, 0.406250f, 0.988281f, 0.894531f},
+ {0.062500f, 0.593750f, 0.191406f, 0.160156f}, {0.246094f, 0.875000f, 0.515625f, 0.824219f},
+ {0.132812f, 0.484375f, 0.468750f, 0.031250f}, {0.437500f, 0.367188f, 0.605469f, 0.375000f},
+ {0.976562f, 0.835938f, 0.859375f, 0.785156f}, {0.046875f, 0.242188f, 0.726562f, 0.433594f},
+ {0.765625f, 0.519531f, 0.089844f, 0.226562f}, {0.921875f, 0.394531f, 0.824219f, 0.003906f},
+ {0.105469f, 0.921875f, 0.585938f, 0.382812f}, {0.390625f, 0.824219f, 0.007812f, 0.476562f},
+ {0.484375f, 0.558594f, 0.738281f, 0.683594f}, {0.070312f, 0.441406f, 0.082031f, 0.347656f},
+ {0.433594f, 0.332031f, 0.605469f, 0.417969f}, {0.949219f, 0.765625f, 0.339844f, 0.789062f},
+ {0.738281f, 0.906250f, 0.015625f, 0.183594f}, {0.312500f, 0.601562f, 0.441406f, 0.527344f},
+ {0.695312f, 0.089844f, 0.722656f, 0.992188f}, {0.605469f, 0.867188f, 0.925781f, 0.644531f},
+ {0.539062f, 0.500000f, 0.218750f, 0.769531f}, {0.011719f, 0.929688f, 0.847656f, 0.414062f},
+ {0.777344f, 0.296875f, 0.972656f, 0.613281f}, {0.332031f, 0.644531f, 0.398438f, 0.058594f},
+ {0.937500f, 0.835938f, 0.328125f, 0.378906f}, {0.691406f, 0.042969f, 0.867188f, 0.542969f},
+ {0.039062f, 0.257812f, 0.625000f, 0.011719f}, {0.546875f, 0.964844f, 0.562500f, 0.753906f},
+ {0.117188f, 0.632812f, 0.738281f, 0.320312f}, {0.605469f, 0.296875f, 0.054688f, 0.050781f},
+ {0.824219f, 0.902344f, 0.820312f, 0.621094f}, {0.507812f, 0.589844f, 0.906250f, 0.863281f},
+ {0.058594f, 0.136719f, 0.324219f, 0.152344f}, {0.445312f, 0.929688f, 0.753906f, 0.671875f},
+ {0.253906f, 0.703125f, 0.167969f, 0.828125f}, {0.644531f, 0.218750f, 0.593750f, 0.375000f},
+ {0.781250f, 0.574219f, 0.085938f, 0.609375f}, {0.000000f, 0.042969f, 0.964844f, 0.550781f},
+ {0.500000f, 0.296875f, 0.359375f, 0.871094f}, {0.207031f, 0.394531f, 0.683594f, 0.457031f},
+ {0.062500f, 0.214844f, 0.136719f, 0.277344f}, {0.777344f, 0.933594f, 0.480469f, 0.847656f},
+ {0.648438f, 0.863281f, 0.332031f, 0.765625f}, {0.121094f, 0.351562f, 0.089844f, 0.042969f},
+ {0.367188f, 0.250000f, 0.390625f, 0.554688f}, {0.183594f, 0.433594f, 0.566406f, 0.730469f},
+ {0.300781f, 0.593750f, 0.300781f, 0.500000f}, {0.894531f, 0.726562f, 0.636719f, 0.589844f},
+ {0.105469f, 0.839844f, 0.375000f, 0.296875f}, {0.199219f, 0.468750f, 0.710938f, 0.125000f},
+ {0.062500f, 0.289062f, 0.902344f, 0.027344f}, {0.992188f, 0.609375f, 0.410156f, 0.250000f},
+ {0.281250f, 0.101562f, 0.687500f, 0.343750f}, {0.789062f, 0.718750f, 0.343750f, 0.558594f},
+ {0.578125f, 0.832031f, 0.878906f, 0.214844f}, {0.187500f, 0.539062f, 0.746094f, 0.378906f},
+ {0.691406f, 0.187500f, 0.277344f, 0.457031f}, {0.621094f, 0.031250f, 0.105469f, 0.984375f},
+ {0.859375f, 0.812500f, 0.917969f, 0.597656f}, {0.757812f, 0.656250f, 0.558594f, 0.343750f},
+ {0.332031f, 0.402344f, 0.179688f, 0.726562f}, {0.027344f, 0.996094f, 0.812500f, 0.085938f},
+ {0.261719f, 0.554688f, 0.074219f, 0.851562f}, {0.144531f, 0.351562f, 0.742188f, 0.003906f},
+ {0.519531f, 0.925781f, 0.449219f, 0.406250f}, {0.585938f, 0.027344f, 0.324219f, 0.347656f},
+ {0.824219f, 0.320312f, 0.097656f, 0.109375f}, {0.953125f, 0.953125f, 0.707031f, 0.558594f},
+ {0.671875f, 0.121094f, 0.773438f, 0.695312f}, {0.523438f, 0.773438f, 0.128906f, 0.609375f},
+ {0.273438f, 0.003906f, 0.964844f, 0.496094f}, {0.621094f, 0.617188f, 0.265625f, 0.132812f},
+ {0.367188f, 0.167969f, 0.199219f, 0.847656f}, {0.722656f, 0.761719f, 0.652344f, 0.539062f},
+ {0.156250f, 0.652344f, 0.437500f, 0.621094f}, {0.996094f, 0.253906f, 0.359375f, 0.777344f},
+ {0.648438f, 0.148438f, 0.937500f, 0.109375f}, {0.242188f, 0.632812f, 0.496094f, 0.902344f},
+ {0.828125f, 0.957031f, 0.769531f, 0.562500f}, {0.558594f, 0.074219f, 0.136719f, 0.289062f},
+ {0.503906f, 0.531250f, 0.878906f, 0.703125f}, {0.175781f, 0.476562f, 0.636719f, 0.843750f},
+ {0.878906f, 0.277344f, 0.292969f, 0.132812f}, {0.367188f, 0.417969f, 0.125000f, 0.574219f},
+ {0.281250f, 0.062500f, 0.550781f, 0.910156f}, {0.847656f, 0.589844f, 0.054688f, 0.273438f},
+ {0.664062f, 0.730469f, 0.511719f, 0.121094f}, {0.394531f, 0.402344f, 0.140625f, 0.503906f},
+ {0.578125f, 0.089844f, 0.039062f, 0.914062f}, {0.480469f, 0.777344f, 0.714844f, 0.652344f},
+ {0.195312f, 0.445312f, 0.179688f, 0.976562f}, {0.785156f, 0.675781f, 0.113281f, 0.132812f},
+ {0.351562f, 0.816406f, 0.886719f, 0.835938f}, {0.265625f, 0.488281f, 0.296875f, 0.453125f},
+ {0.175781f, 0.093750f, 0.144531f, 0.722656f}, {0.386719f, 0.335938f, 0.656250f, 0.339844f},
+ {0.753906f, 0.656250f, 0.531250f, 0.234375f}, {0.132812f, 0.398438f, 0.421875f, 0.421875f},
+ {0.351562f, 0.515625f, 0.929688f, 0.925781f}, {0.917969f, 0.105469f, 0.500000f, 0.492188f},
+ {0.601562f, 0.914062f, 0.773438f, 0.136719f}, {0.324219f, 0.613281f, 0.441406f, 0.750000f},
+ {0.949219f, 0.730469f, 0.222656f, 0.324219f}, {0.578125f, 0.480469f, 0.824219f, 0.808594f},
+ {0.402344f, 0.660156f, 0.289062f, 0.062500f}, {0.863281f, 0.761719f, 0.585938f, 0.578125f},
+ {0.488281f, 0.515625f, 0.898438f, 0.132812f}, {0.550781f, 0.050781f, 0.644531f, 0.355469f},
+ {0.921875f, 0.968750f, 0.832031f, 0.882812f}, {0.710938f, 0.796875f, 0.011719f, 0.261719f},
+ {0.511719f, 0.160156f, 0.980469f, 0.019531f}, {0.605469f, 0.945312f, 0.199219f, 0.921875f},
+ {0.343750f, 0.214844f, 0.789062f, 0.218750f}, {0.675781f, 0.550781f, 0.019531f, 0.570312f},
+ {0.437500f, 0.746094f, 0.468750f, 0.734375f}, {0.707031f, 0.875000f, 0.542969f, 0.804688f},
+ {0.144531f, 0.503906f, 0.285156f, 0.910156f}, {0.406250f, 0.019531f, 0.121094f, 0.101562f},
+ {0.742188f, 0.312500f, 0.816406f, 0.714844f}, {0.097656f, 0.933594f, 0.183594f, 0.007812f},
+ {0.371094f, 0.761719f, 0.589844f, 0.648438f}, {0.453125f, 0.492188f, 0.378906f, 0.167969f},
+ {0.222656f, 0.585938f, 0.847656f, 0.796875f}, {0.121094f, 0.214844f, 0.058594f, 0.128906f},
+ {0.484375f, 0.730469f, 0.632812f, 0.546875f}, {0.914062f, 0.078125f, 0.871094f, 0.296875f},
+ {0.640625f, 0.191406f, 0.304688f, 0.441406f}, {0.886719f, 0.714844f, 0.148438f, 0.242188f},
+ {0.082031f, 0.464844f, 0.933594f, 0.750000f}, {0.742188f, 0.632812f, 0.640625f, 0.667969f},
+ {0.183594f, 0.230469f, 0.386719f, 0.953125f}, {0.484375f, 0.687500f, 0.917969f, 0.445312f},
+ {0.007812f, 0.187500f, 0.226562f, 0.308594f}, {0.804688f, 0.570312f, 0.417969f, 0.914062f},
+ {0.195312f, 0.304688f, 0.671875f, 0.253906f}, {0.878906f, 0.902344f, 0.351562f, 0.960938f},
+ {0.078125f, 0.082031f, 0.042969f, 0.710938f}, {0.460938f, 0.449219f, 0.988281f, 0.292969f},
+ {0.300781f, 0.320312f, 0.781250f, 0.058594f}, {0.593750f, 0.023438f, 0.171875f, 0.949219f},
+ {0.796875f, 0.500000f, 0.539062f, 0.207031f}, {0.339844f, 0.839844f, 0.218750f, 0.503906f},
+ {0.132812f, 0.289062f, 0.417969f, 0.070312f}, {0.675781f, 0.218750f, 0.269531f, 0.871094f},
+ {0.042969f, 0.378906f, 0.996094f, 0.035156f}, {0.230469f, 0.816406f, 0.515625f, 0.472656f},
+ {0.453125f, 0.964844f, 0.375000f, 0.332031f}, {0.746094f, 0.664062f, 0.792969f, 0.214844f},
+ {0.058594f, 0.351562f, 0.457031f, 0.000000f}, {0.968750f, 0.882812f, 0.343750f, 0.718750f},
+ {0.160156f, 0.140625f, 0.765625f, 0.878906f}, {0.238281f, 0.207031f, 0.675781f, 0.789062f},
+ {0.070312f, 0.535156f, 0.945312f, 0.335938f}, {0.894531f, 0.917969f, 0.277344f, 0.179688f},
+ {0.296875f, 0.332031f, 0.535156f, 0.597656f}, {0.988281f, 0.167969f, 0.359375f, 0.398438f},
+ {0.718750f, 0.015625f, 0.671875f, 0.257812f}, {0.472656f, 0.414062f, 0.960938f, 0.554688f},
+ {0.890625f, 0.996094f, 0.460938f, 0.109375f}, {0.964844f, 0.789062f, 0.199219f, 0.996094f},
+ {0.667969f, 0.875000f, 0.089844f, 0.585938f}, {0.804688f, 0.183594f, 0.859375f, 0.703125f},
+ {0.546875f, 0.312500f, 0.261719f, 0.089844f}, {0.050781f, 0.769531f, 0.046875f, 0.273438f},
+ {0.187500f, 0.253906f, 0.843750f, 0.894531f}, {0.441406f, 0.367188f, 0.644531f, 0.230469f},
+ {0.742188f, 0.171875f, 0.105469f, 0.097656f}, {0.824219f, 0.890625f, 0.535156f, 0.984375f},
+ {0.144531f, 0.015625f, 0.394531f, 0.656250f}, {0.296875f, 0.316406f, 0.058594f, 0.402344f},
+ {0.019531f, 0.144531f, 0.210938f, 0.691406f}, {0.753906f, 0.621094f, 0.730469f, 0.929688f},
+ {0.250000f, 0.703125f, 0.492188f, 0.191406f}, {0.054688f, 0.292969f, 0.152344f, 0.414062f},
+ {0.410156f, 0.492188f, 0.445312f, 0.777344f}, {0.796875f, 0.339844f, 0.871094f, 0.855469f},
+ {0.902344f, 0.085938f, 0.250000f, 0.632812f}, {0.531250f, 0.906250f, 0.324219f, 0.394531f},
+ {0.250000f, 0.132812f, 0.839844f, 0.976562f}, {0.917969f, 0.375000f, 0.160156f, 0.523438f},
+ {0.859375f, 0.792969f, 0.601562f, 0.160156f}, {0.335938f, 0.453125f, 0.714844f, 0.425781f},
+ {0.523438f, 0.152344f, 0.464844f, 0.949219f}, {0.957031f, 0.625000f, 0.000000f, 0.863281f},
+ {0.800781f, 0.089844f, 0.531250f, 0.257812f}, {0.000000f, 0.863281f, 0.316406f, 0.511719f},
+ {0.308594f, 0.285156f, 0.679688f, 0.906250f}, {0.824219f, 0.132812f, 0.472656f, 0.230469f},
+ {0.535156f, 0.917969f, 0.265625f, 0.656250f}, {0.683594f, 0.503906f, 0.429688f, 0.960938f},
+ {0.363281f, 0.609375f, 0.515625f, 0.171875f}, {0.445312f, 0.289062f, 0.683594f, 0.917969f},
+ {0.964844f, 0.808594f, 0.238281f, 0.617188f}, {0.277344f, 0.085938f, 0.042969f, 0.062500f},
+ {0.394531f, 0.511719f, 0.839844f, 0.203125f}, {0.636719f, 0.753906f, 0.585938f, 0.843750f},
+ {0.343750f, 0.417969f, 0.289062f, 0.761719f}, {0.746094f, 0.933594f, 0.011719f, 0.171875f},
+ {0.566406f, 0.472656f, 0.816406f, 0.066406f}, {0.398438f, 0.671875f, 0.550781f, 0.566406f},
+ {0.675781f, 0.855469f, 0.750000f, 0.351562f}, {0.832031f, 0.546875f, 0.488281f, 0.179688f},
+ {0.222656f, 0.992188f, 0.285156f, 0.449219f}, {0.531250f, 0.792969f, 0.117188f, 0.839844f},
+ {0.003906f, 0.382812f, 0.875000f, 0.320312f}, {0.718750f, 0.722656f, 0.625000f, 0.718750f},
+ {0.925781f, 0.574219f, 0.843750f, 0.636719f}, {0.382812f, 0.878906f, 0.070312f, 0.238281f},
+ {0.621094f, 0.015625f, 0.707031f, 0.398438f}, {0.988281f, 0.738281f, 0.195312f, 0.925781f},
+ {0.796875f, 0.125000f, 0.039062f, 0.667969f}, {0.136719f, 0.179688f, 0.953125f, 0.796875f},
+ {0.632812f, 0.542969f, 0.648438f, 0.382812f}, {0.496094f, 0.804688f, 0.253906f, 0.550781f},
+ {0.433594f, 0.449219f, 0.894531f, 0.457031f}, {0.730469f, 0.988281f, 0.203125f, 0.675781f},
+ {0.800781f, 0.273438f, 0.484375f, 0.222656f}, {0.136719f, 0.710938f, 0.414062f, 0.074219f},
+ {0.617188f, 0.597656f, 0.789062f, 0.472656f}, {0.417969f, 0.851562f, 0.843750f, 0.800781f},
+ {0.027344f, 0.242188f, 0.031250f, 0.695312f}, {0.566406f, 0.699219f, 0.398438f, 0.898438f},
+ {0.089844f, 0.195312f, 0.593750f, 0.187500f}, {0.617188f, 0.531250f, 0.792969f, 0.382812f},
+ {0.199219f, 0.445312f, 0.351562f, 0.769531f}, {0.289062f, 0.074219f, 0.675781f, 0.035156f},
+ {0.492188f, 0.632812f, 0.730469f, 0.535156f}, {0.699219f, 0.976562f, 0.382812f, 0.800781f},
+ {0.875000f, 0.464844f, 0.308594f, 0.640625f}, {0.121094f, 0.800781f, 0.171875f, 0.437500f},
+ {0.257812f, 0.078125f, 0.925781f, 0.714844f}, {0.523438f, 0.550781f, 0.718750f, 0.507812f},
+ {0.625000f, 0.992188f, 0.996094f, 0.171875f}, {0.968750f, 0.238281f, 0.781250f, 0.246094f},
+ {0.191406f, 0.453125f, 0.433594f, 0.468750f}, {0.441406f, 0.839844f, 0.269531f, 0.812500f},
+ {0.855469f, 0.203125f, 0.941406f, 0.621094f}, {0.652344f, 0.890625f, 0.347656f, 0.113281f},
+ {0.972656f, 0.007812f, 0.687500f, 0.480469f}, {0.156250f, 0.679688f, 0.585938f, 0.683594f},
+ {0.015625f, 0.617188f, 0.519531f, 0.078125f}, {0.761719f, 0.437500f, 0.945312f, 0.453125f},
+ {0.371094f, 0.261719f, 0.078125f, 0.320312f}, {0.585938f, 0.652344f, 0.757812f, 0.054688f},
+ {0.031250f, 0.207031f, 0.972656f, 0.609375f}, {0.644531f, 0.585938f, 0.375000f, 0.292969f},
+ {0.210938f, 0.894531f, 0.242188f, 0.769531f}, {0.269531f, 0.246094f, 0.902344f, 0.574219f},
+ {0.882812f, 0.390625f, 0.957031f, 0.355469f}, {0.570312f, 0.457031f, 0.769531f, 0.062500f},
+ {0.726562f, 0.953125f, 0.214844f, 0.406250f}, {0.988281f, 0.347656f, 0.136719f, 0.742188f},
+ {0.066406f, 0.785156f, 0.972656f, 0.035156f}, {0.156250f, 0.425781f, 0.726562f, 0.375000f},
+ {0.207031f, 0.015625f, 0.015625f, 0.589844f}, {0.710938f, 0.898438f, 0.894531f, 0.480469f},
+ {0.031250f, 0.160156f, 0.562500f, 0.792969f}, {0.546875f, 0.980469f, 0.480469f, 0.273438f},
+ {0.863281f, 0.859375f, 0.738281f, 0.535156f}, {0.101562f, 0.355469f, 0.171875f, 0.371094f},
+ {0.910156f, 0.054688f, 0.523438f, 0.011719f}, {0.296875f, 0.808594f, 0.894531f, 0.640625f},
+ {0.937500f, 0.257812f, 0.457031f, 0.414062f}, {0.125000f, 0.113281f, 0.152344f, 0.804688f},
+ {0.507812f, 0.363281f, 0.617188f, 0.882812f}, {0.957031f, 0.195312f, 0.394531f, 0.656250f},
+ {0.054688f, 0.695312f, 0.906250f, 0.750000f}, {0.902344f, 0.070312f, 0.703125f, 0.582031f},
+ {0.421875f, 0.929688f, 0.031250f, 0.140625f}, {0.187500f, 0.167969f, 0.671875f, 0.433594f},
+ {0.476562f, 0.101562f, 0.363281f, 0.980469f}, {0.281250f, 0.683594f, 0.570312f, 0.765625f},
+ {0.847656f, 0.437500f, 0.472656f, 0.167969f}, {0.078125f, 0.628906f, 0.832031f, 0.605469f},
+ {0.570312f, 0.328125f, 0.593750f, 0.101562f}, {0.261719f, 0.765625f, 0.738281f, 0.503906f},
+ {0.906250f, 0.242188f, 0.164062f, 0.960938f}, {0.324219f, 0.007812f, 0.824219f, 0.164062f},
+ {0.593750f, 0.683594f, 0.570312f, 0.089844f}, {0.921875f, 0.617188f, 0.105469f, 0.296875f},
+ {0.527344f, 0.050781f, 0.632812f, 0.851562f}, {0.359375f, 0.375000f, 0.910156f, 0.726562f},
+ {0.835938f, 0.128906f, 0.070312f, 0.937500f}, {0.664062f, 0.515625f, 0.226562f, 0.027344f},
+ {0.226562f, 0.890625f, 0.500000f, 0.300781f}, {0.851562f, 0.574219f, 0.757812f, 0.648438f},
+ {0.316406f, 0.753906f, 0.257812f, 0.058594f}, {0.429688f, 0.277344f, 0.937500f, 0.507812f},
+ {0.007812f, 0.031250f, 0.019531f, 0.878906f}, {0.933594f, 0.714844f, 0.550781f, 0.308594f},
+ {0.835938f, 0.847656f, 0.136719f, 0.164062f}, {0.234375f, 0.546875f, 0.617188f, 0.968750f},
+ {0.394531f, 0.132812f, 0.902344f, 0.355469f}, {0.980469f, 0.679688f, 0.566406f, 0.019531f},
+ {0.671875f, 0.839844f, 0.468750f, 0.585938f}, {0.046875f, 0.417969f, 0.250000f, 0.378906f},
+ {0.375000f, 0.597656f, 0.023438f, 0.898438f}, {0.695312f, 0.789062f, 0.625000f, 0.753906f},
+ {0.898438f, 0.375000f, 0.875000f, 0.007812f}, {0.328125f, 0.542969f, 0.113281f, 0.531250f},
+ {0.578125f, 0.109375f, 0.542969f, 0.300781f}, {0.085938f, 0.406250f, 0.765625f, 0.988281f},
+ {0.285156f, 0.566406f, 0.062500f, 0.339844f}, {0.472656f, 0.777344f, 0.128906f, 0.164062f},
+ {0.636719f, 0.363281f, 0.628906f, 0.750000f}, {0.832031f, 0.035156f, 0.394531f, 0.835938f},
+ {0.109375f, 0.972656f, 0.667969f, 0.195312f}, {0.183594f, 0.710938f, 0.222656f, 0.890625f},
+ {0.808594f, 0.066406f, 0.046875f, 0.707031f}, {0.460938f, 0.953125f, 0.855469f, 0.476562f},
+ {0.082031f, 0.335938f, 0.652344f, 0.203125f}, {0.667969f, 0.738281f, 0.093750f, 0.121094f},
+ {0.425781f, 0.664062f, 0.417969f, 0.683594f}, {0.164062f, 0.007812f, 0.613281f, 0.964844f},
+ {0.632812f, 0.703125f, 0.042969f, 0.617188f}, {0.250000f, 0.554688f, 0.804688f, 0.464844f},
+ {0.394531f, 0.242188f, 0.371094f, 0.878906f}, {0.937500f, 0.847656f, 0.601562f, 0.816406f},
+ {0.804688f, 0.679688f, 0.195312f, 0.113281f}, {0.601562f, 0.378906f, 0.335938f, 0.320312f},
+ {0.339844f, 0.562500f, 0.812500f, 0.867188f}, {0.785156f, 0.437500f, 0.125000f, 0.140625f},
+ {0.230469f, 0.273438f, 0.355469f, 0.980469f}, {0.687500f, 0.656250f, 0.957031f, 0.468750f},
+ {0.156250f, 0.148438f, 0.082031f, 0.726562f}, {0.464844f, 0.535156f, 0.703125f, 0.898438f},
+ {0.039062f, 0.722656f, 0.324219f, 0.285156f}, {0.250000f, 0.945312f, 0.945312f, 0.117188f},
+ {0.777344f, 0.589844f, 0.093750f, 0.484375f}, {0.328125f, 0.285156f, 0.222656f, 0.023438f},
+ {0.609375f, 0.421875f, 0.828125f, 0.390625f}, {0.746094f, 0.617188f, 0.335938f, 0.929688f},
+ {0.261719f, 0.238281f, 0.449219f, 0.265625f}, {0.863281f, 0.472656f, 0.953125f, 0.031250f},
+ {0.105469f, 0.316406f, 0.292969f, 0.355469f}, {0.765625f, 0.976562f, 0.152344f, 0.531250f},
+ {0.523438f, 0.195312f, 0.933594f, 0.828125f}, {0.343750f, 0.554688f, 0.242188f, 0.304688f},
+ {0.414062f, 0.890625f, 0.414062f, 0.742188f}, {0.695312f, 0.496094f, 0.085938f, 0.250000f},
+ {0.824219f, 0.933594f, 0.316406f, 0.832031f}, {0.109375f, 0.386719f, 0.433594f, 0.347656f},
+ {0.199219f, 0.304688f, 0.000000f, 0.632812f}, {0.023438f, 0.843750f, 0.378906f, 0.988281f},
+ {0.679688f, 0.480469f, 0.746094f, 0.429688f}, {0.265625f, 0.769531f, 0.312500f, 0.574219f},
+ {0.058594f, 0.941406f, 0.593750f, 0.359375f}, {0.507812f, 0.074219f, 0.992188f, 0.527344f},
+ {0.160156f, 0.308594f, 0.167969f, 0.214844f}, {0.945312f, 0.382812f, 0.644531f, 0.964844f},
+ {0.789062f, 0.105469f, 0.117188f, 0.441406f}, {0.523438f, 0.613281f, 0.875000f, 0.812500f},
+ {0.722656f, 0.953125f, 0.492188f, 0.226562f}, {0.371094f, 0.347656f, 0.226562f, 0.617188f},
+ {0.101562f, 0.214844f, 0.984375f, 0.464844f}, {0.628906f, 0.406250f, 0.433594f, 0.742188f},
+ {0.777344f, 0.011719f, 0.035156f, 0.199219f}, {0.480469f, 0.277344f, 0.753906f, 0.855469f},
+ {0.339844f, 0.332031f, 0.347656f, 0.281250f}, {0.093750f, 0.207031f, 0.671875f, 0.792969f},
+ {0.808594f, 0.699219f, 0.156250f, 0.121094f}, {0.226562f, 0.097656f, 0.507812f, 0.335938f},
+ {0.476562f, 0.941406f, 0.367188f, 0.945312f}, {0.109375f, 0.660156f, 0.187500f, 0.210938f},
+ {0.800781f, 0.750000f, 0.609375f, 0.066406f}, {0.382812f, 0.984375f, 0.824219f, 0.714844f},
+ {0.738281f, 0.242188f, 0.296875f, 0.554688f}, {0.222656f, 0.832031f, 0.917969f, 0.906250f},
+ {0.320312f, 0.929688f, 0.464844f, 0.503906f}, {0.980469f, 0.519531f, 0.175781f, 0.277344f},
+ {0.500000f, 0.312500f, 0.808594f, 0.664062f}, {0.285156f, 0.816406f, 0.562500f, 0.789062f},
+ {0.929688f, 0.542969f, 0.437500f, 0.382812f}, {0.542969f, 0.414062f, 0.507812f, 0.023438f},
+ {0.777344f, 0.847656f, 0.308594f, 0.843750f}, {0.976562f, 0.121094f, 0.738281f, 0.527344f},
+ {0.042969f, 0.511719f, 0.164062f, 0.316406f}, {0.507812f, 0.812500f, 0.492188f, 0.824219f},
+ {0.339844f, 0.183594f, 0.875000f, 0.089844f}, {0.773438f, 0.074219f, 0.546875f, 0.281250f},
+ {0.460938f, 0.640625f, 0.929688f, 0.195312f}, {0.558594f, 0.121094f, 0.105469f, 0.695312f},
+ {0.285156f, 0.316406f, 0.781250f, 0.523438f}, {0.875000f, 0.769531f, 0.414062f, 0.019531f},
+ {0.121094f, 0.222656f, 0.984375f, 0.710938f}, {0.488281f, 0.710938f, 0.269531f, 0.398438f},
+ {0.992188f, 0.031250f, 0.625000f, 0.656250f}, {0.421875f, 0.597656f, 0.437500f, 0.101562f},
+ {0.593750f, 0.890625f, 0.777344f, 0.226562f}, {0.839844f, 0.214844f, 0.601562f, 0.589844f},
+ {0.718750f, 0.402344f, 0.253906f, 0.523438f}, {0.644531f, 0.019531f, 0.855469f, 0.687500f},
+ {0.433594f, 0.820312f, 0.667969f, 0.992188f}, {0.167969f, 0.746094f, 0.050781f, 0.238281f},
+ {0.109375f, 0.128906f, 0.582031f, 0.105469f}, {0.363281f, 0.847656f, 0.527344f, 0.527344f},
+ {0.687500f, 0.531250f, 0.191406f, 0.804688f}, {0.562500f, 0.777344f, 0.101562f, 0.683594f},
+ {0.636719f, 0.597656f, 0.796875f, 0.890625f}, {0.953125f, 0.402344f, 0.726562f, 0.113281f},
+ {0.164062f, 0.832031f, 0.011719f, 0.453125f}, {0.734375f, 0.265625f, 0.343750f, 0.019531f},
+ {0.210938f, 0.046875f, 0.675781f, 0.941406f}, {0.003906f, 0.089844f, 0.910156f, 0.421875f},
+ {0.535156f, 0.703125f, 0.523438f, 0.058594f}, {0.382812f, 0.578125f, 0.980469f, 0.582031f},
+ {0.984375f, 0.113281f, 0.699219f, 0.761719f}, {0.304688f, 0.906250f, 0.851562f, 0.023438f},
+ {0.859375f, 0.167969f, 0.250000f, 0.261719f}, {0.453125f, 0.230469f, 0.144531f, 0.113281f},
+ {0.960938f, 0.429688f, 0.453125f, 0.828125f}, {0.757812f, 0.628906f, 0.695312f, 0.156250f},
+ {0.375000f, 0.792969f, 0.343750f, 0.757812f}, {0.691406f, 0.476562f, 0.558594f, 0.593750f},
+ {0.250000f, 0.906250f, 0.300781f, 0.332031f}, {0.140625f, 0.152344f, 0.707031f, 0.136719f},
+ {0.871094f, 0.824219f, 0.394531f, 0.667969f}, {0.582031f, 0.496094f, 0.828125f, 0.941406f},
+ {0.453125f, 0.589844f, 0.769531f, 0.394531f}, {0.167969f, 0.910156f, 0.285156f, 0.058594f},
+ {0.027344f, 0.750000f, 0.195312f, 0.675781f}, {0.570312f, 0.949219f, 0.867188f, 0.515625f},
+ {0.843750f, 0.519531f, 0.078125f, 0.933594f}, {0.937500f, 0.878906f, 0.835938f, 0.070312f},
+ {0.539062f, 0.039062f, 0.292969f, 0.625000f}, {0.761719f, 0.492188f, 0.796875f, 0.558594f},
+ {0.597656f, 0.285156f, 0.703125f, 0.828125f}, {0.160156f, 0.171875f, 0.957031f, 0.656250f},
+ {0.671875f, 0.058594f, 0.035156f, 0.433594f}, {0.503906f, 0.324219f, 0.417969f, 0.863281f},
+ {0.925781f, 0.453125f, 0.230469f, 0.250000f}, {0.566406f, 0.136719f, 0.742188f, 0.031250f},
+ {0.066406f, 0.195312f, 0.097656f, 0.968750f}, {0.417969f, 0.753906f, 0.988281f, 0.097656f},
+ {0.675781f, 0.113281f, 0.273438f, 0.546875f}, {0.726562f, 0.468750f, 0.339844f, 0.136719f},
+ {0.394531f, 0.171875f, 0.914062f, 0.253906f}, {0.144531f, 0.277344f, 0.128906f, 0.996094f},
+ {0.316406f, 0.039062f, 0.578125f, 0.644531f}, {0.714844f, 0.574219f, 0.820312f, 0.910156f},
+ {0.378906f, 0.222656f, 0.269531f, 0.437500f}, {0.906250f, 0.984375f, 0.707031f, 0.175781f},
+ {0.113281f, 0.371094f, 0.339844f, 0.765625f}, {0.851562f, 0.882812f, 0.242188f, 0.570312f},
+ {0.015625f, 0.472656f, 0.453125f, 0.343750f}, {0.664062f, 0.972656f, 0.292969f, 0.984375f},
+ {0.097656f, 0.523438f, 0.660156f, 0.421875f}, {0.429688f, 0.058594f, 0.527344f, 0.234375f},
+ {0.187500f, 0.933594f, 0.070312f, 0.925781f}, {0.628906f, 0.132812f, 0.679688f, 0.558594f},
+ {0.753906f, 0.796875f, 0.203125f, 0.773438f}, {0.070312f, 0.484375f, 0.847656f, 0.328125f},
+ {0.355469f, 0.964844f, 0.035156f, 0.855469f}, {0.527344f, 0.335938f, 0.390625f, 0.933594f},
+ {0.210938f, 0.625000f, 0.191406f, 0.367188f}, {0.976562f, 0.460938f, 0.507812f, 0.191406f},
+ {0.582031f, 0.171875f, 0.425781f, 0.765625f}, {0.882812f, 0.507812f, 0.761719f, 0.332031f},
+ {0.812500f, 0.914062f, 0.265625f, 0.636719f}, {0.496094f, 0.050781f, 0.976562f, 0.875000f},
+ {0.980469f, 0.355469f, 0.738281f, 0.187500f}, {0.031250f, 0.898438f, 0.605469f, 0.476562f},
+ {0.320312f, 0.027344f, 0.410156f, 0.597656f}, {0.441406f, 0.734375f, 0.507812f, 0.218750f},
+ {0.066406f, 0.140625f, 0.894531f, 0.714844f}, {0.894531f, 0.468750f, 0.550781f, 0.562500f},
+ {0.652344f, 0.789062f, 0.785156f, 0.648438f}, {0.863281f, 0.972656f, 0.132812f, 0.191406f},
+ {0.457031f, 0.425781f, 0.277344f, 0.894531f}, {0.738281f, 0.203125f, 0.605469f, 0.683594f},
+ {0.640625f, 0.808594f, 0.480469f, 0.472656f}, {0.777344f, 0.515625f, 0.183594f, 0.199219f},
+ {0.125000f, 0.339844f, 0.953125f, 0.921875f}, {0.570312f, 0.671875f, 0.539062f, 0.500000f},
+ {0.210938f, 0.730469f, 0.781250f, 0.671875f}, {0.097656f, 0.019531f, 0.019531f, 0.890625f},
+ {0.597656f, 0.968750f, 0.835938f, 0.406250f}, {0.468750f, 0.191406f, 0.914062f, 0.082031f},
+ {0.042969f, 0.667969f, 0.445312f, 0.847656f}, {0.648438f, 0.421875f, 0.050781f, 0.722656f},
+ {0.335938f, 0.773438f, 0.179688f, 0.000000f}, {0.992188f, 0.300781f, 0.636719f, 0.257812f},
+ {0.273438f, 0.066406f, 0.093750f, 0.562500f}, {0.750000f, 0.171875f, 0.476562f, 0.902344f},
+ {0.902344f, 0.660156f, 0.691406f, 0.320312f}, {0.300781f, 0.445312f, 0.527344f, 0.144531f},
+ {0.195312f, 0.621094f, 0.406250f, 0.457031f}, {0.429688f, 0.152344f, 0.968750f, 0.707031f},
+ {0.273438f, 0.734375f, 0.453125f, 0.414062f}, {0.003906f, 0.914062f, 0.578125f, 0.265625f},
+ {0.410156f, 0.355469f, 0.093750f, 0.484375f}, {0.996094f, 0.847656f, 0.316406f, 0.148438f},
+ {0.839844f, 0.605469f, 0.484375f, 0.359375f}, {0.031250f, 0.511719f, 0.898438f, 0.773438f},
+ {0.187500f, 0.726562f, 0.679688f, 0.589844f}, {0.867188f, 0.644531f, 0.355469f, 0.390625f},
+ {0.136719f, 0.878906f, 0.843750f, 0.640625f}, {0.597656f, 0.589844f, 0.597656f, 0.441406f},
+ {0.222656f, 0.394531f, 0.714844f, 0.355469f}, {0.003906f, 0.863281f, 0.031250f, 0.925781f},
+ {0.871094f, 0.691406f, 0.761719f, 0.597656f}, {0.621094f, 0.628906f, 0.195312f, 0.414062f},
+ {0.230469f, 0.769531f, 0.941406f, 0.074219f}, {0.582031f, 0.929688f, 0.023438f, 0.230469f},
+ {0.812500f, 0.433594f, 0.398438f, 0.722656f}, {0.195312f, 0.304688f, 0.996094f, 0.000000f},
+ {0.679688f, 0.761719f, 0.089844f, 0.496094f}, {0.593750f, 0.605469f, 0.636719f, 0.925781f},
+ {0.222656f, 0.277344f, 0.750000f, 0.136719f}, {0.902344f, 0.730469f, 0.164062f, 0.644531f},
+ {0.515625f, 0.191406f, 0.863281f, 0.785156f}, {0.722656f, 0.585938f, 0.031250f, 0.601562f},
+ {0.949219f, 0.457031f, 0.921875f, 0.183594f}, {0.312500f, 0.851562f, 0.468750f, 0.066406f},
+ {0.003906f, 0.390625f, 0.750000f, 0.257812f}, {0.265625f, 0.304688f, 0.308594f, 0.496094f},
+ {0.808594f, 0.097656f, 0.542969f, 0.035156f}, {0.894531f, 0.761719f, 0.136719f, 0.152344f},
+ {0.089844f, 0.691406f, 0.992188f, 0.445312f}, {0.382812f, 0.070312f, 0.792969f, 0.070312f},
+ {0.011719f, 0.984375f, 0.355469f, 0.843750f}, {0.281250f, 0.308594f, 0.910156f, 0.593750f},
+ {0.660156f, 0.648438f, 0.152344f, 0.429688f}, {0.210938f, 0.210938f, 0.468750f, 0.722656f},
+ {0.406250f, 0.703125f, 0.019531f, 0.304688f}, {0.148438f, 0.273438f, 0.882812f, 0.078125f},
+ {0.832031f, 0.089844f, 0.250000f, 0.968750f}, {0.242188f, 0.863281f, 0.652344f, 0.335938f},
+ {0.601562f, 0.371094f, 0.199219f, 0.847656f}, {0.484375f, 0.679688f, 0.062500f, 0.277344f},
+ {0.289062f, 0.617188f, 0.453125f, 0.378906f}, {0.941406f, 0.343750f, 0.863281f, 0.515625f},
+ {0.152344f, 0.281250f, 0.218750f, 0.128906f}, {0.238281f, 0.746094f, 0.039062f, 0.316406f},
+ {0.046875f, 0.636719f, 0.792969f, 0.871094f}, {0.496094f, 0.031250f, 0.351562f, 0.390625f},
+ {0.406250f, 0.980469f, 0.660156f, 0.789062f}, {0.707031f, 0.558594f, 0.054688f, 0.609375f},
+ {0.886719f, 0.859375f, 0.890625f, 0.320312f}, {0.312500f, 0.132812f, 0.394531f, 0.039062f},
+ {0.816406f, 0.265625f, 0.250000f, 0.242188f}, {0.906250f, 0.355469f, 0.097656f, 0.488281f},
+ {0.410156f, 0.539062f, 0.746094f, 0.921875f}, {0.769531f, 0.093750f, 0.972656f, 0.539062f},
+ {0.203125f, 0.246094f, 0.527344f, 0.425781f}, {0.070312f, 0.695312f, 0.324219f, 0.800781f},
+ {0.820312f, 0.878906f, 0.906250f, 0.117188f}, {0.515625f, 0.375000f, 0.574219f, 0.761719f},
+ {0.660156f, 0.238281f, 0.941406f, 0.605469f}, {0.113281f, 0.105469f, 0.132812f, 0.835938f},
+ {0.710938f, 0.820312f, 0.652344f, 0.238281f}, {0.621094f, 0.394531f, 0.214844f, 0.992188f},
+ {0.136719f, 0.253906f, 0.011719f, 0.187500f}, {0.921875f, 0.578125f, 0.902344f, 0.046875f},
+ {0.730469f, 0.441406f, 0.246094f, 0.886719f}, {0.300781f, 0.800781f, 0.847656f, 0.957031f},
+ {0.238281f, 0.222656f, 0.648438f, 0.687500f}, {0.355469f, 0.894531f, 0.136719f, 0.109375f},
+ {0.707031f, 0.027344f, 0.554688f, 0.199219f}, {0.453125f, 0.285156f, 0.003906f, 0.800781f},
+ {0.953125f, 0.074219f, 0.511719f, 0.156250f}, {0.750000f, 0.671875f, 0.152344f, 0.863281f},
+ {0.824219f, 0.238281f, 0.402344f, 0.699219f}, {0.339844f, 0.003906f, 0.492188f, 0.042969f},
+ {0.964844f, 0.980469f, 0.867188f, 0.753906f}, {0.101562f, 0.367188f, 0.617188f, 0.511719f},
+ {0.492188f, 0.488281f, 0.363281f, 0.300781f}, {0.062500f, 0.156250f, 0.667969f, 0.800781f},
+ {0.277344f, 0.652344f, 0.550781f, 0.355469f}, {0.441406f, 0.062500f, 0.847656f, 0.601562f},
+ {0.953125f, 0.535156f, 0.199219f, 0.847656f}, {0.316406f, 0.140625f, 0.011719f, 0.250000f},
+ {0.757812f, 0.019531f, 0.910156f, 0.390625f}, {0.359375f, 0.390625f, 0.570312f, 0.042969f},
+ {0.054688f, 0.902344f, 0.386719f, 0.863281f}, {0.824219f, 0.339844f, 0.714844f, 0.304688f},
+ {0.390625f, 0.632812f, 0.242188f, 0.457031f}, {0.562500f, 0.238281f, 0.589844f, 0.734375f},
+ {0.921875f, 0.683594f, 0.097656f, 0.953125f}, {0.507812f, 0.550781f, 0.949219f, 0.816406f},
+ {0.671875f, 0.191406f, 0.878906f, 0.617188f}, {0.175781f, 0.835938f, 0.644531f, 0.703125f},
+ {0.316406f, 0.273438f, 0.718750f, 0.789062f}, {0.757812f, 0.871094f, 0.000000f, 0.550781f},
+ {0.546875f, 0.566406f, 0.113281f, 0.265625f}, {0.472656f, 0.382812f, 0.621094f, 0.941406f},
+ {0.925781f, 0.796875f, 0.699219f, 0.156250f}, {0.058594f, 0.437500f, 0.386719f, 0.050781f},
+ {0.777344f, 0.945312f, 0.308594f, 0.781250f}, {0.535156f, 0.496094f, 0.820312f, 0.394531f},
+ {0.906250f, 0.644531f, 0.125000f, 0.656250f}, {0.703125f, 0.542969f, 0.371094f, 0.144531f},
+ {0.804688f, 0.226562f, 0.988281f, 0.914062f}, {0.378906f, 0.906250f, 0.300781f, 0.046875f},
+ {0.035156f, 0.175781f, 0.753906f, 0.785156f}, {0.570312f, 0.566406f, 0.628906f, 0.976562f},
+ {0.343750f, 0.125000f, 0.390625f, 0.730469f}, {0.804688f, 0.878906f, 0.722656f, 0.238281f},
+ {0.605469f, 0.453125f, 0.921875f, 0.539062f}, {0.953125f, 0.257812f, 0.089844f, 0.093750f},
+ {0.179688f, 0.085938f, 0.429688f, 0.714844f}, {0.347656f, 0.402344f, 0.281250f, 0.167969f},
+ {0.628906f, 0.300781f, 0.613281f, 0.449219f}, {0.007812f, 0.503906f, 0.507812f, 0.984375f},
+ {0.539062f, 0.601562f, 0.187500f, 0.710938f}, {0.281250f, 0.835938f, 0.660156f, 0.632812f},
+ {0.113281f, 0.738281f, 0.363281f, 0.285156f}, {0.953125f, 0.933594f, 0.593750f, 0.191406f},
+ {0.554688f, 0.007812f, 0.238281f, 0.355469f}, {0.683594f, 0.625000f, 0.800781f, 0.980469f},
+ {0.417969f, 0.472656f, 0.000000f, 0.500000f}, {0.222656f, 0.984375f, 0.371094f, 0.218750f},
+ {0.382812f, 0.777344f, 0.253906f, 0.070312f}, {0.972656f, 0.566406f, 0.808594f, 0.378906f},
+ {0.472656f, 0.308594f, 0.316406f, 0.542969f}, {0.789062f, 0.058594f, 0.609375f, 0.781250f},
+ {0.855469f, 0.972656f, 0.726562f, 0.648438f}, {0.359375f, 0.652344f, 0.519531f, 0.746094f},
+ {0.511719f, 0.000000f, 0.425781f, 0.582031f}, {0.074219f, 0.125000f, 0.750000f, 0.296875f},
+ {0.625000f, 0.683594f, 0.382812f, 0.027344f}, {0.546875f, 0.960938f, 0.199219f, 0.523438f},
+ {0.792969f, 0.414062f, 0.964844f, 0.917969f}, {0.269531f, 0.488281f, 0.773438f, 0.308594f},
+ {0.375000f, 0.332031f, 0.312500f, 0.007812f}, {0.519531f, 0.941406f, 0.894531f, 0.570312f},
+ {0.175781f, 0.777344f, 0.226562f, 0.210938f}, {0.558594f, 0.558594f, 0.687500f, 0.324219f},
+ {0.449219f, 0.316406f, 0.078125f, 0.828125f}, {0.656250f, 0.101562f, 0.449219f, 0.164062f},
+ {0.839844f, 0.832031f, 0.250000f, 0.683594f}, {0.914062f, 0.253906f, 0.777344f, 0.554688f},
+ {0.738281f, 0.906250f, 0.144531f, 0.125000f}, {0.550781f, 0.714844f, 0.472656f, 0.945312f},
+ {0.039062f, 0.863281f, 0.695312f, 0.660156f}, {0.140625f, 0.445312f, 0.421875f, 0.453125f},
+ {0.476562f, 0.832031f, 0.796875f, 0.738281f}, {0.980469f, 0.679688f, 0.496094f, 0.101562f},
+ {0.269531f, 0.792969f, 0.121094f, 0.500000f}, {0.160156f, 0.101562f, 0.324219f, 0.152344f},
+ {0.656250f, 0.960938f, 0.820312f, 0.894531f}, {0.226562f, 0.000000f, 0.406250f, 0.640625f},
+ {0.851562f, 0.742188f, 0.156250f, 0.343750f}, {0.136719f, 0.917969f, 0.359375f, 0.425781f},
+ {0.414062f, 0.054688f, 0.492188f, 0.210938f}, {0.613281f, 0.441406f, 0.257812f, 0.300781f},
+ {0.941406f, 0.511719f, 0.449219f, 0.972656f}, {0.699219f, 0.128906f, 0.570312f, 0.652344f},
+ {0.847656f, 0.226562f, 0.281250f, 0.003906f}, {0.128906f, 0.734375f, 0.871094f, 0.375000f},
+ {0.339844f, 0.007812f, 0.535156f, 0.507812f}, {0.726562f, 0.117188f, 0.074219f, 0.894531f},
+ {0.257812f, 0.582031f, 0.933594f, 0.570312f}, {0.593750f, 0.171875f, 0.566406f, 0.250000f},
+ {0.351562f, 0.410156f, 0.484375f, 0.488281f}, {0.117188f, 0.996094f, 0.703125f, 0.761719f},
+ {0.191406f, 0.308594f, 0.843750f, 0.425781f}, {0.992188f, 0.003906f, 0.578125f, 0.609375f},
+ {0.769531f, 0.503906f, 0.164062f, 0.097656f}, {0.105469f, 0.816406f, 0.945312f, 0.460938f},
+ {0.699219f, 0.046875f, 0.109375f, 0.824219f}, {0.421875f, 0.957031f, 0.535156f, 0.007812f},
+ {0.898438f, 0.359375f, 0.312500f, 0.636719f}, {0.281250f, 0.718750f, 0.582031f, 0.964844f},
+ {0.082031f, 0.605469f, 0.863281f, 0.285156f}, {0.847656f, 0.800781f, 0.757812f, 0.070312f},
+ {0.445312f, 0.203125f, 0.125000f, 0.820312f}, {0.980469f, 0.902344f, 0.714844f, 0.562500f},
+ {0.164062f, 0.691406f, 0.921875f, 0.359375f}, {0.734375f, 0.046875f, 0.812500f, 0.144531f},
+ {0.613281f, 0.457031f, 0.480469f, 0.777344f}, {0.359375f, 0.320312f, 0.140625f, 0.089844f},
+ {0.488281f, 0.574219f, 0.886719f, 0.863281f}, {0.152344f, 0.855469f, 0.703125f, 0.636719f},
+ {0.921875f, 0.136719f, 0.421875f, 0.296875f}, {0.011719f, 0.527344f, 0.167969f, 0.710938f},
+ {0.601562f, 0.027344f, 0.742188f, 0.441406f}, {0.328125f, 0.707031f, 0.066406f, 0.882812f},
+ {0.050781f, 0.906250f, 0.875000f, 0.015625f}, {0.246094f, 0.500000f, 0.378906f, 0.339844f},
+ {0.566406f, 0.769531f, 0.117188f, 0.121094f}, {0.179688f, 0.195312f, 0.175781f, 0.386719f},
+ {0.656250f, 0.527344f, 0.988281f, 0.816406f}, {0.882812f, 0.304688f, 0.042969f, 0.449219f},
+ {0.425781f, 0.375000f, 0.601562f, 0.242188f}, {0.929688f, 0.562500f, 0.812500f, 0.617188f},
+ {0.101562f, 0.164062f, 0.261719f, 0.468750f}, {0.644531f, 0.820312f, 0.441406f, 0.718750f},
+ {0.023438f, 0.523438f, 0.632812f, 0.261719f}, {0.898438f, 0.437500f, 0.945312f, 0.953125f},
+ {0.066406f, 0.140625f, 0.109375f, 0.492188f}, {0.281250f, 0.882812f, 0.832031f, 0.902344f},
+ {0.781250f, 0.207031f, 0.292969f, 0.445312f}, {0.148438f, 0.722656f, 0.976562f, 0.089844f},
+ {0.402344f, 0.593750f, 0.523438f, 0.960938f}, {0.351562f, 0.046875f, 0.066406f, 0.871094f},
+ {0.175781f, 0.402344f, 0.316406f, 0.402344f}, {0.640625f, 0.339844f, 0.937500f, 0.046875f},
+ {0.871094f, 0.199219f, 0.589844f, 0.203125f}, {0.414062f, 0.945312f, 0.355469f, 0.316406f},
+ {0.691406f, 0.246094f, 0.277344f, 0.902344f}, {0.539062f, 0.507812f, 0.980469f, 0.566406f},
+ {0.609375f, 0.167969f, 0.214844f, 0.679688f}, {0.781250f, 0.429688f, 0.617188f, 0.820312f},
+ {0.464844f, 0.285156f, 0.875000f, 0.375000f}, {0.101562f, 0.488281f, 0.511719f, 0.019531f},
+ {0.710938f, 0.156250f, 0.691406f, 0.121094f}, {0.363281f, 0.359375f, 0.792969f, 0.578125f},
+ {0.792969f, 0.593750f, 0.046875f, 0.906250f}, {0.476562f, 0.972656f, 0.199219f, 0.089844f},
+ {0.031250f, 0.667969f, 0.824219f, 0.390625f}, {0.242188f, 0.343750f, 0.933594f, 0.480469f},
+ {0.421875f, 0.937500f, 0.339844f, 0.132812f}, {0.191406f, 0.613281f, 0.183594f, 0.750000f},
+ {0.617188f, 0.472656f, 0.800781f, 0.675781f}, {0.867188f, 0.855469f, 0.230469f, 0.203125f},
+ {0.449219f, 0.328125f, 0.660156f, 0.953125f}, {0.964844f, 0.746094f, 0.769531f, 0.828125f},
+ {0.007812f, 0.824219f, 0.179688f, 0.011719f}, {0.503906f, 0.125000f, 0.085938f, 0.531250f},
+ {0.421875f, 0.777344f, 0.433594f, 0.199219f}, {0.660156f, 0.710938f, 0.027344f, 0.679688f},
+ {0.261719f, 0.941406f, 0.347656f, 0.257812f}, {0.527344f, 0.386719f, 0.492188f, 0.351562f},
+ {0.843750f, 0.660156f, 0.671875f, 0.179688f}, {0.195312f, 0.195312f, 0.246094f, 0.578125f},
+ {0.062500f, 0.539062f, 0.828125f, 0.429688f}, {0.519531f, 0.847656f, 0.156250f, 0.363281f},
+ {0.730469f, 0.156250f, 0.472656f, 0.855469f}, {0.789062f, 0.941406f, 0.210938f, 0.527344f},
+ {0.250000f, 0.445312f, 0.960938f, 0.218750f}, {0.671875f, 0.078125f, 0.320312f, 0.753906f},
+ {0.500000f, 0.378906f, 0.417969f, 0.015625f}, {0.222656f, 0.988281f, 0.066406f, 0.949219f},
+ {0.828125f, 0.164062f, 0.285156f, 0.453125f}, {0.031250f, 0.222656f, 0.761719f, 0.589844f},
+ {0.878906f, 0.800781f, 0.042969f, 0.691406f}, {0.308594f, 0.351562f, 0.460938f, 0.027344f},
+ {0.789062f, 0.417969f, 0.656250f, 0.160156f}, {0.726562f, 0.285156f, 0.972656f, 0.941406f},
+ {0.859375f, 0.207031f, 0.597656f, 0.796875f}, {0.535156f, 0.839844f, 0.496094f, 0.621094f},
+ {0.941406f, 0.343750f, 0.445312f, 0.285156f}, {0.097656f, 0.164062f, 0.949219f, 0.914062f},
+ {0.687500f, 0.421875f, 0.789062f, 0.492188f}, {0.453125f, 0.871094f, 0.675781f, 0.214844f},
+ {0.035156f, 0.710938f, 0.289062f, 0.078125f}, {0.781250f, 0.941406f, 0.542969f, 0.703125f},
+ {0.207031f, 0.777344f, 0.101562f, 0.867188f}, {0.152344f, 0.089844f, 0.339844f, 0.984375f},
+ {0.480469f, 0.257812f, 0.707031f, 0.371094f}, {0.843750f, 0.722656f, 0.070312f, 0.835938f},
+ {0.230469f, 0.199219f, 0.750000f, 0.417969f}, {0.417969f, 0.054688f, 0.542969f, 0.773438f},
+ {0.617188f, 0.632812f, 0.375000f, 0.070312f}, {0.710938f, 0.386719f, 0.578125f, 0.613281f},
+ {0.921875f, 0.500000f, 0.652344f, 0.281250f}, {0.246094f, 0.921875f, 0.164062f, 0.644531f},
+ {0.687500f, 0.445312f, 0.890625f, 0.218750f}, {0.023438f, 0.789062f, 0.718750f, 0.476562f},
+ {0.996094f, 0.523438f, 0.820312f, 0.269531f}, {0.507812f, 0.117188f, 0.234375f, 0.710938f},
+ {0.253906f, 0.628906f, 0.105469f, 0.531250f}, {0.824219f, 0.574219f, 0.886719f, 0.800781f},
+ {0.070312f, 0.316406f, 0.050781f, 0.164062f}, {0.199219f, 0.039062f, 0.664062f, 0.964844f},
+ {0.867188f, 0.652344f, 0.769531f, 0.277344f}, {0.023438f, 0.867188f, 0.078125f, 0.222656f},
+ {0.335938f, 0.769531f, 0.960938f, 0.535156f}, {0.898438f, 0.535156f, 0.015625f, 0.996094f},
+ {0.585938f, 0.890625f, 0.269531f, 0.691406f}, {0.054688f, 0.644531f, 0.925781f, 0.175781f},
+ {0.980469f, 0.261719f, 0.585938f, 0.511719f}, {0.285156f, 0.789062f, 0.667969f, 0.742188f},
+ {0.113281f, 0.023438f, 0.402344f, 0.859375f}, {0.578125f, 0.417969f, 0.066406f, 0.230469f},
+ {0.800781f, 0.816406f, 0.753906f, 0.921875f}, {0.992188f, 0.164062f, 0.492188f, 0.816406f},
+ {0.519531f, 0.281250f, 0.414062f, 0.289062f}, {0.085938f, 0.675781f, 0.968750f, 0.449219f},
+ {0.167969f, 0.964844f, 0.046875f, 0.347656f}, {0.671875f, 0.035156f, 0.347656f, 0.113281f},
+ {0.761719f, 0.257812f, 0.277344f, 0.714844f}, {0.300781f, 0.457031f, 0.925781f, 0.316406f},
+ {0.578125f, 0.605469f, 0.617188f, 0.984375f}, {0.875000f, 0.082031f, 0.789062f, 0.851562f},
+ {0.156250f, 0.437500f, 0.265625f, 0.558594f}, {0.453125f, 0.253906f, 0.738281f, 0.898438f},
+ {0.968750f, 0.761719f, 0.882812f, 0.703125f}, {0.312500f, 0.480469f, 0.406250f, 0.949219f},
+ {0.679688f, 0.097656f, 0.031250f, 0.773438f}, {0.589844f, 0.308594f, 0.996094f, 0.125000f},
+ {0.375000f, 0.679688f, 0.691406f, 0.675781f}, {0.128906f, 0.000000f, 0.375000f, 0.929688f},
+ {0.562500f, 0.753906f, 0.570312f, 0.421875f}, {0.050781f, 0.562500f, 0.003906f, 0.304688f},
+ {0.386719f, 0.250000f, 0.531250f, 0.648438f}, {0.937500f, 0.781250f, 0.621094f, 0.843750f},
+ {0.437500f, 0.636719f, 0.953125f, 0.515625f}, {0.695312f, 0.515625f, 0.214844f, 0.242188f},
+ {0.253906f, 0.949219f, 0.562500f, 0.910156f}, {0.636719f, 0.097656f, 0.296875f, 0.406250f},
+ {0.453125f, 0.746094f, 0.109375f, 0.566406f}, {0.121094f, 0.917969f, 0.832031f, 0.480469f},
+ {0.269531f, 0.632812f, 0.207031f, 0.105469f}, {0.183594f, 0.449219f, 0.281250f, 0.179688f},
+ {0.746094f, 0.675781f, 0.031250f, 0.691406f}, {0.402344f, 0.113281f, 0.558594f, 0.574219f},
+ {0.894531f, 0.613281f, 0.238281f, 0.839844f}, {0.277344f, 0.277344f, 0.351562f, 0.964844f},
+ {0.976562f, 0.074219f, 0.832031f, 0.535156f}, {0.332031f, 0.472656f, 0.464844f, 0.335938f},
+ {0.738281f, 0.597656f, 0.882812f, 0.171875f}, {0.601562f, 0.855469f, 0.937500f, 0.125000f},
+ {0.292969f, 0.648438f, 0.500000f, 0.058594f}, {0.687500f, 0.996094f, 0.175781f, 0.660156f},
+ {0.984375f, 0.582031f, 0.820312f, 0.527344f}, {0.757812f, 0.761719f, 0.253906f, 0.339844f},
+ {0.488281f, 0.843750f, 0.472656f, 0.128906f}, {0.324219f, 0.265625f, 0.007812f, 0.726562f},
+ {0.085938f, 0.023438f, 0.792969f, 0.386719f}, {0.519531f, 0.664062f, 0.414062f, 0.789062f},
+ {0.578125f, 0.175781f, 0.351562f, 0.015625f}, {0.792969f, 0.292969f, 0.035156f, 0.585938f},
+ {0.308594f, 0.992188f, 0.441406f, 0.769531f}, {0.105469f, 0.683594f, 0.648438f, 0.988281f},
+ {0.765625f, 0.804688f, 0.519531f, 0.093750f}, {0.371094f, 0.074219f, 0.734375f, 0.621094f},
+ {0.929688f, 0.746094f, 0.156250f, 0.359375f}, {0.296875f, 0.964844f, 0.546875f, 0.011719f},
+ {0.722656f, 0.554688f, 0.453125f, 0.414062f}, {0.402344f, 0.347656f, 0.371094f, 0.761719f},
+ {0.964844f, 0.207031f, 0.187500f, 0.078125f}, {0.511719f, 0.074219f, 0.558594f, 0.476562f},
+ {0.257812f, 0.808594f, 0.433594f, 0.781250f}, {0.191406f, 0.410156f, 0.746094f, 0.839844f},
+ {0.750000f, 0.109375f, 0.117188f, 0.281250f}, {0.531250f, 0.195312f, 0.312500f, 0.031250f},
+ {0.859375f, 0.562500f, 0.976562f, 0.570312f}, {0.664062f, 0.703125f, 0.148438f, 0.320312f},
+ {0.363281f, 0.078125f, 0.687500f, 0.613281f}, {0.062500f, 0.531250f, 0.593750f, 0.082031f},
+ {0.703125f, 0.886719f, 0.105469f, 0.539062f}, {0.316406f, 0.382812f, 0.632812f, 0.035156f},
+ {0.390625f, 0.218750f, 0.453125f, 0.644531f}, {0.835938f, 0.562500f, 0.718750f, 0.582031f},
+ {0.214844f, 0.660156f, 0.546875f, 0.886719f}, {0.933594f, 0.359375f, 0.875000f, 0.160156f},
+ {0.089844f, 0.890625f, 0.218750f, 0.378906f}, {0.730469f, 0.210938f, 0.519531f, 0.062500f},
+ {0.359375f, 0.558594f, 0.972656f, 0.480469f}, {0.621094f, 0.324219f, 0.074219f, 0.136719f},
+ {0.042969f, 0.871094f, 0.191406f, 0.304688f}, {0.761719f, 0.589844f, 0.449219f, 0.050781f},
+ {0.476562f, 0.914062f, 0.750000f, 0.253906f}, {0.929688f, 0.414062f, 0.621094f, 0.476562f},
+ {0.218750f, 0.234375f, 0.269531f, 0.195312f}, {0.867188f, 0.519531f, 0.082031f, 0.042969f},
+ {0.320312f, 0.648438f, 0.773438f, 0.613281f}, {0.898438f, 0.328125f, 0.882812f, 0.882812f},
+ {0.769531f, 0.882812f, 0.175781f, 0.113281f}, {0.093750f, 0.109375f, 0.828125f, 0.183594f},
+ {0.566406f, 0.406250f, 0.687500f, 0.378906f}, {0.179688f, 0.714844f, 0.394531f, 0.054688f},
+ {0.984375f, 0.042969f, 0.863281f, 0.316406f}, {0.066406f, 0.671875f, 0.937500f, 0.824219f},
+ {0.574219f, 0.183594f, 0.351562f, 0.757812f}, {0.371094f, 0.570312f, 0.531250f, 0.347656f},
+ {0.675781f, 0.070312f, 0.718750f, 0.261719f}, {0.480469f, 0.949219f, 0.902344f, 0.976562f},
+ {0.808594f, 0.250000f, 0.648438f, 0.398438f}, {0.343750f, 0.539062f, 0.761719f, 0.054688f},
+ {0.601562f, 0.984375f, 0.082031f, 0.152344f}, {0.828125f, 0.828125f, 0.917969f, 0.730469f},
+ {0.121094f, 0.355469f, 0.625000f, 0.636719f}, {0.554688f, 0.226562f, 0.148438f, 0.406250f},
+ {0.398438f, 0.148438f, 0.222656f, 0.792969f}, {0.945312f, 0.429688f, 0.664062f, 0.562500f},
+ {0.082031f, 0.015625f, 0.410156f, 0.753906f}, {0.351562f, 0.367188f, 0.039062f, 0.187500f},
+ {0.562500f, 0.121094f, 0.359375f, 0.238281f}, {0.191406f, 0.308594f, 0.992188f, 0.886719f},
+ {0.128906f, 0.703125f, 0.144531f, 0.988281f}, {0.812500f, 0.539062f, 0.707031f, 0.558594f},
+ {0.968750f, 0.968750f, 0.933594f, 0.179688f}, {0.429688f, 0.335938f, 0.214844f, 0.929688f},
+ {0.195312f, 0.753906f, 0.554688f, 0.859375f}, {0.902344f, 0.867188f, 0.613281f, 0.363281f},
+ {0.468750f, 0.031250f, 0.960938f, 0.152344f}, {0.613281f, 0.234375f, 0.183594f, 0.304688f},
+ {0.210938f, 0.417969f, 0.292969f, 0.429688f}, {0.570312f, 0.476562f, 0.855469f, 0.882812f},
+ {0.652344f, 0.828125f, 0.406250f, 0.480469f}, {0.453125f, 0.386719f, 0.941406f, 0.722656f},
+ {0.085938f, 0.117188f, 0.246094f, 0.585938f}, {0.558594f, 0.710938f, 0.730469f, 0.933594f},
+ {0.140625f, 0.609375f, 0.804688f, 0.632812f}, {0.828125f, 0.996094f, 0.652344f, 0.320312f},
+ {0.687500f, 0.312500f, 0.335938f, 0.234375f}, {0.441406f, 0.472656f, 0.222656f, 0.402344f},
+ {0.632812f, 0.730469f, 0.890625f, 0.937500f}, {0.332031f, 0.871094f, 0.531250f, 0.675781f},
+ {0.164062f, 0.304688f, 0.464844f, 0.445312f}, {0.906250f, 0.914062f, 0.851562f, 0.160156f},
+ {0.460938f, 0.238281f, 0.246094f, 0.722656f}, {0.273438f, 0.753906f, 0.917969f, 0.398438f},
+ {0.777344f, 0.046875f, 0.304688f, 0.992188f}, {0.941406f, 0.496094f, 0.863281f, 0.847656f},
+ {0.554688f, 0.781250f, 0.144531f, 0.179688f}, {0.050781f, 0.097656f, 0.816406f, 0.406250f},
+ {0.621094f, 0.925781f, 0.003906f, 0.789062f}, {0.468750f, 0.515625f, 0.406250f, 0.273438f},
+ {0.820312f, 0.156250f, 0.679688f, 0.621094f}, {0.027344f, 0.691406f, 0.140625f, 0.734375f},
+ {0.234375f, 0.828125f, 0.382812f, 0.808594f}, {0.890625f, 0.054688f, 0.640625f, 0.410156f},
+ {0.398438f, 0.144531f, 0.582031f, 0.652344f}, {0.117188f, 0.722656f, 0.804688f, 0.519531f},
+ {0.265625f, 0.035156f, 0.132812f, 0.835938f}, {0.824219f, 0.781250f, 0.335938f, 0.589844f},
+ {0.015625f, 0.972656f, 0.503906f, 0.324219f}, {0.644531f, 0.367188f, 0.843750f, 0.792969f},
+ {0.460938f, 0.839844f, 0.656250f, 0.375000f}, {0.707031f, 0.179688f, 0.445312f, 0.496094f},
+ {0.148438f, 0.484375f, 0.253906f, 0.269531f}, {0.292969f, 0.585938f, 0.347656f, 0.710938f},
+ {0.800781f, 0.292969f, 0.101562f, 0.792969f}, {0.343750f, 0.847656f, 0.503906f, 0.992188f},
+ {0.511719f, 0.453125f, 0.160156f, 0.542969f}, {0.843750f, 0.261719f, 0.628906f, 0.207031f},
+ {0.214844f, 0.878906f, 0.777344f, 0.082031f}, {0.957031f, 0.492188f, 0.054688f, 0.855469f},
+ {0.890625f, 0.382812f, 0.136719f, 0.656250f}, {0.019531f, 0.804688f, 0.328125f, 0.519531f},
+ {0.636719f, 0.042969f, 0.402344f, 0.753906f}, {0.148438f, 0.753906f, 0.179688f, 0.449219f},
+ {0.046875f, 0.398438f, 0.507812f, 0.320312f}, {0.511719f, 0.019531f, 0.429688f, 0.253906f},
+ {0.222656f, 0.660156f, 0.003906f, 0.003906f}, {0.707031f, 0.910156f, 0.726562f, 0.933594f},
+ {0.011719f, 0.742188f, 0.781250f, 0.281250f}, {0.863281f, 0.316406f, 0.281250f, 0.445312f},
+ {0.515625f, 0.496094f, 0.570312f, 0.910156f}, {0.785156f, 0.875000f, 0.867188f, 0.605469f},
+ {0.042969f, 0.230469f, 0.207031f, 0.824219f}, {0.667969f, 0.468750f, 0.605469f, 0.472656f},
+ {0.878906f, 0.906250f, 0.316406f, 0.046875f}, {0.382812f, 0.164062f, 0.765625f, 0.671875f},
+ {0.015625f, 0.093750f, 0.070312f, 0.312500f}, {0.640625f, 0.425781f, 0.277344f, 0.457031f},
+ {0.847656f, 0.613281f, 0.859375f, 0.113281f}, {0.062500f, 0.128906f, 0.128906f, 0.691406f},
+ {0.726562f, 0.558594f, 0.761719f, 0.503906f}, {0.398438f, 0.355469f, 0.382812f, 0.917969f},
+ {0.886719f, 0.925781f, 0.000000f, 0.667969f}, {0.000000f, 0.148438f, 0.792969f, 0.062500f},
+ {0.156250f, 0.277344f, 0.597656f, 0.242188f}, {0.808594f, 0.191406f, 0.316406f, 0.855469f},
+ {0.945312f, 0.910156f, 0.042969f, 0.117188f}, {0.226562f, 0.453125f, 0.914062f, 0.191406f},
+ {0.761719f, 0.250000f, 0.109375f, 0.441406f}, {0.308594f, 0.015625f, 0.480469f, 0.882812f},
+ {0.015625f, 0.671875f, 0.847656f, 0.132812f}, {0.878906f, 0.144531f, 0.074219f, 0.605469f},
+ {0.933594f, 0.945312f, 0.613281f, 0.074219f}, {0.074219f, 0.503906f, 0.777344f, 0.359375f},
+ {0.406250f, 0.378906f, 0.050781f, 0.796875f}, {0.718750f, 0.605469f, 0.367188f, 0.886719f},
+ {0.003906f, 0.449219f, 0.554688f, 0.500000f}, {0.218750f, 0.988281f, 0.015625f, 0.218750f},
+ {0.640625f, 0.636719f, 0.730469f, 0.769531f}, {0.117188f, 0.144531f, 0.375000f, 0.269531f},
+ {0.429688f, 0.429688f, 0.250000f, 0.691406f}, {0.902344f, 0.839844f, 0.488281f, 0.957031f},
+ {0.261719f, 0.316406f, 0.949219f, 0.460938f}, {0.339844f, 0.738281f, 0.304688f, 0.085938f},
+ {0.531250f, 0.015625f, 0.101562f, 0.507812f}, {0.691406f, 0.984375f, 0.832031f, 0.941406f},
+ {0.945312f, 0.378906f, 0.890625f, 0.015625f}, {0.562500f, 0.628906f, 0.324219f, 0.203125f},
+ {0.796875f, 0.953125f, 0.011719f, 0.921875f}, {0.656250f, 0.285156f, 0.953125f, 0.730469f},
+ {0.167969f, 0.183594f, 0.542969f, 0.085938f}, {0.542969f, 0.468750f, 0.906250f, 0.890625f},
+ {0.410156f, 0.617188f, 0.046875f, 0.695312f}, {0.996094f, 0.128906f, 0.199219f, 0.972656f},
+ {0.191406f, 0.050781f, 0.945312f, 0.148438f}, {0.511719f, 0.937500f, 0.117188f, 0.738281f},
+ {0.613281f, 0.734375f, 0.722656f, 0.910156f}, {0.921875f, 0.019531f, 0.988281f, 0.429688f},
+ {0.652344f, 0.972656f, 0.601562f, 0.601562f}, {0.003906f, 0.136719f, 0.746094f, 0.664062f},
+ {0.722656f, 0.359375f, 0.011719f, 0.148438f}, {0.402344f, 0.609375f, 0.257812f, 0.718750f},
+ {0.765625f, 0.785156f, 0.414062f, 0.437500f}, {0.082031f, 0.296875f, 0.480469f, 0.605469f},
+ {0.542969f, 0.144531f, 0.996094f, 0.011719f}, {0.312500f, 0.699219f, 0.589844f, 0.882812f},
+ {0.242188f, 0.328125f, 0.859375f, 0.222656f}, {0.968750f, 0.593750f, 0.699219f, 0.804688f},
+ {0.425781f, 0.156250f, 0.964844f, 0.902344f}, {0.753906f, 0.492188f, 0.296875f, 0.605469f},
+ {0.917969f, 0.792969f, 0.582031f, 0.472656f}, {0.468750f, 0.546875f, 0.382812f, 0.847656f},
+ {0.632812f, 0.058594f, 0.074219f, 0.066406f}, {0.261719f, 0.937500f, 0.968750f, 0.683594f},
+ {0.160156f, 0.687500f, 0.125000f, 0.320312f}, {0.441406f, 0.781250f, 0.648438f, 0.019531f},
+ {0.320312f, 0.972656f, 0.023438f, 0.710938f}, {0.937500f, 0.070312f, 0.429688f, 0.164062f},
+ {0.273438f, 0.406250f, 0.886719f, 0.414062f}, {0.585938f, 0.789062f, 0.511719f, 0.804688f},
+ {0.234375f, 0.574219f, 0.636719f, 0.230469f}, {0.750000f, 0.832031f, 0.460938f, 0.531250f},
+ {0.355469f, 0.250000f, 0.695312f, 0.750000f}, {0.281250f, 0.480469f, 0.328125f, 0.250000f},
+ {0.132812f, 0.726562f, 0.500000f, 0.035156f}, {0.671875f, 0.886719f, 0.917969f, 0.601562f},
+ {0.972656f, 0.621094f, 0.664062f, 0.199219f}, {0.328125f, 0.699219f, 0.472656f, 0.789062f},
+ {0.511719f, 0.519531f, 0.121094f, 0.519531f}, {0.695312f, 0.593750f, 0.699219f, 0.300781f},
+ {0.351562f, 0.054688f, 0.503906f, 0.683594f}, {0.621094f, 0.757812f, 0.628906f, 0.351562f},
+ {0.484375f, 0.882812f, 0.285156f, 0.808594f}, {0.660156f, 0.394531f, 0.152344f, 0.046875f},
+ {0.386719f, 0.574219f, 0.992188f, 0.660156f}, {0.121094f, 0.824219f, 0.691406f, 0.738281f},
+ {0.242188f, 0.234375f, 0.410156f, 0.531250f}, {0.601562f, 0.031250f, 0.171875f, 0.191406f},
+ {0.773438f, 0.085938f, 0.277344f, 0.960938f}, {0.507812f, 0.839844f, 0.656250f, 0.113281f},
+ {0.968750f, 0.179688f, 0.812500f, 0.023438f}, {0.566406f, 0.351562f, 0.203125f, 0.632812f},
+ {0.878906f, 0.289062f, 0.515625f, 0.343750f}, {0.484375f, 0.710938f, 0.996094f, 0.121094f},
+ {0.183594f, 0.957031f, 0.589844f, 0.519531f}, {0.734375f, 0.191406f, 0.187500f, 0.042969f},
+ {0.804688f, 0.621094f, 0.644531f, 0.222656f}, {0.148438f, 0.269531f, 0.757812f, 0.898438f},
+ {0.406250f, 0.480469f, 0.574219f, 0.664062f}, {0.109375f, 0.789062f, 0.457031f, 0.328125f},
+ {0.296875f, 0.234375f, 0.718750f, 0.246094f}, {0.191406f, 0.523438f, 0.500000f, 0.570312f},
+ {0.500000f, 0.449219f, 0.281250f, 0.351562f}, {0.324219f, 0.347656f, 0.218750f, 0.160156f},
+ {0.953125f, 0.683594f, 0.378906f, 0.441406f}, {0.710938f, 0.539062f, 0.703125f, 0.382812f},
+ {0.097656f, 0.886719f, 0.425781f, 0.003906f}, {0.347656f, 0.281250f, 0.296875f, 0.546875f},
+ {0.761719f, 0.695312f, 0.554688f, 0.246094f}, {0.039062f, 0.433594f, 0.386719f, 0.078125f},
+ {0.253906f, 0.230469f, 0.496094f, 0.566406f}, {0.378906f, 0.804688f, 0.058594f, 0.023438f},
+ {0.449219f, 0.648438f, 0.304688f, 0.335938f}, {0.875000f, 0.199219f, 0.437500f, 0.101562f},
+ {0.136719f, 0.917969f, 0.917969f, 0.476562f}, {0.285156f, 0.539062f, 0.847656f, 0.902344f},
+ {0.617188f, 0.003906f, 0.703125f, 0.250000f}, {0.167969f, 0.996094f, 0.210938f, 0.953125f},
+ {0.429688f, 0.437500f, 0.800781f, 0.308594f}, {0.738281f, 0.847656f, 0.265625f, 0.140625f},
+ {0.847656f, 0.210938f, 0.019531f, 0.566406f}, {0.558594f, 0.929688f, 0.125000f, 0.085938f},
+ {0.660156f, 0.878906f, 0.808594f, 0.363281f}, {0.179688f, 0.289062f, 0.203125f, 0.671875f},
+ {0.308594f, 0.203125f, 0.851562f, 0.117188f}, {0.367188f, 0.414062f, 0.902344f, 0.746094f},
+ {0.101562f, 0.621094f, 0.527344f, 0.210938f}, {0.804688f, 0.265625f, 0.332031f, 0.500000f},
+ {0.914062f, 0.175781f, 0.464844f, 0.960938f}, {0.726562f, 0.535156f, 0.734375f, 0.378906f},
+ {0.628906f, 0.656250f, 0.539062f, 0.628906f}, {0.074219f, 0.601562f, 0.804688f, 0.273438f},
+ {0.453125f, 0.347656f, 0.109375f, 0.578125f}, {0.531250f, 0.210938f, 0.378906f, 0.867188f},
+ {0.699219f, 0.683594f, 0.175781f, 0.085938f}, {0.156250f, 0.050781f, 0.832031f, 0.972656f},
+ {0.492188f, 0.945312f, 0.972656f, 0.625000f}, {0.953125f, 0.382812f, 0.085938f, 0.820312f},
+ {0.550781f, 0.199219f, 0.253906f, 0.417969f}, {0.246094f, 0.082031f, 0.566406f, 0.847656f},
+ {0.449219f, 0.308594f, 0.070312f, 0.371094f}, {0.785156f, 0.003906f, 0.234375f, 0.132812f},
+ {0.097656f, 0.984375f, 0.984375f, 0.746094f}, {0.269531f, 0.847656f, 0.187500f, 0.980469f},
+ {0.871094f, 0.656250f, 0.824219f, 0.031250f}, {0.039062f, 0.296875f, 0.398438f, 0.550781f},
+ {0.187500f, 0.503906f, 0.882812f, 0.917969f}, {0.992188f, 0.179688f, 0.589844f, 0.500000f},
+ {0.789062f, 0.718750f, 0.363281f, 0.289062f}, {0.558594f, 0.332031f, 0.007812f, 0.980469f},
+ {0.464844f, 0.531250f, 0.507812f, 0.460938f}, {0.824219f, 0.640625f, 0.902344f, 0.253906f},
+ {0.203125f, 0.781250f, 0.722656f, 0.593750f}, {0.304688f, 0.687500f, 0.960938f, 0.308594f},
+ {0.136719f, 0.117188f, 0.125000f, 0.707031f}, {0.839844f, 0.550781f, 0.410156f, 0.917969f},
+ {0.351562f, 0.808594f, 0.769531f, 0.468750f}, {0.289062f, 0.000000f, 0.074219f, 0.863281f},
+ {0.667969f, 0.582031f, 0.691406f, 0.597656f}, {0.015625f, 0.375000f, 0.117188f, 0.371094f},
+ {0.578125f, 0.054688f, 0.902344f, 0.765625f}, {0.957031f, 0.882812f, 0.351562f, 0.558594f},
+ {0.644531f, 0.417969f, 0.058594f, 0.128906f}, {0.847656f, 0.664062f, 0.238281f, 0.429688f},
+ {0.464844f, 0.070312f, 0.171875f, 0.773438f}, {0.746094f, 0.917969f, 0.929688f, 0.855469f},
+ {0.000000f, 0.109375f, 0.777344f, 0.613281f}, {0.867188f, 0.851562f, 0.660156f, 0.996094f},
+ {0.609375f, 0.796875f, 0.851562f, 0.273438f}, {0.445312f, 0.222656f, 0.160156f, 0.777344f},
+ {0.808594f, 0.078125f, 0.597656f, 0.199219f}, {0.277344f, 0.394531f, 0.800781f, 0.636719f},
+ {0.582031f, 0.824219f, 0.753906f, 0.464844f}, {0.945312f, 0.511719f, 0.632812f, 0.851562f},
+ {0.835938f, 0.316406f, 0.226562f, 0.941406f}, {0.082031f, 0.554688f, 0.863281f, 0.210938f},
+ {0.546875f, 0.378906f, 0.785156f, 0.812500f}, {0.222656f, 0.468750f, 0.191406f, 0.289062f},
+ {0.953125f, 0.753906f, 0.535156f, 0.843750f}, {0.484375f, 0.089844f, 0.652344f, 0.367188f},
+ {0.828125f, 0.226562f, 0.089844f, 0.042969f}, {0.687500f, 0.722656f, 0.566406f, 0.746094f},
+ {0.937500f, 0.640625f, 0.375000f, 0.488281f}, {0.496094f, 0.105469f, 0.675781f, 0.386719f},
+ {0.113281f, 0.527344f, 0.460938f, 0.699219f}, {0.375000f, 0.453125f, 0.546875f, 0.945312f},
+ {0.878906f, 0.679688f, 0.343750f, 0.511719f}, {0.070312f, 0.085938f, 0.644531f, 0.179688f},
+ {0.820312f, 0.718750f, 0.480469f, 0.996094f}, {0.992188f, 0.957031f, 0.160156f, 0.390625f},
+ {0.683594f, 0.121094f, 0.695312f, 0.582031f}, {0.582031f, 0.824219f, 0.242188f, 0.148438f},
+ {0.203125f, 0.382812f, 0.835938f, 0.867188f}, {0.386719f, 0.042969f, 0.925781f, 0.105469f},
+ {0.832031f, 0.285156f, 0.296875f, 0.792969f}, {0.152344f, 0.738281f, 0.671875f, 0.945312f},
+ {0.765625f, 0.855469f, 0.234375f, 0.347656f}, {0.855469f, 0.511719f, 0.914062f, 0.734375f},
+ {0.101562f, 0.917969f, 0.582031f, 0.000000f}, {0.917969f, 0.316406f, 0.019531f, 0.394531f},
+ {0.804688f, 0.636719f, 0.410156f, 0.328125f}, {0.601562f, 0.765625f, 0.199219f, 0.171875f},
+ {0.027344f, 0.515625f, 0.800781f, 0.949219f}, {0.761719f, 0.835938f, 0.890625f, 0.285156f},
+ {0.183594f, 0.429688f, 0.734375f, 0.554688f}, {0.855469f, 0.773438f, 0.433594f, 0.925781f},
+ {0.593750f, 0.222656f, 0.871094f, 0.457031f}, {0.402344f, 0.351562f, 0.351562f, 0.625000f},
+ {0.917969f, 0.414062f, 0.554688f, 0.402344f}, {0.539062f, 0.136719f, 0.023438f, 0.257812f},
+ {0.433594f, 0.792969f, 0.718750f, 0.757812f}, {0.082031f, 0.960938f, 0.210938f, 0.160156f},
+ {0.281250f, 0.097656f, 0.789062f, 0.378906f}, {0.714844f, 0.863281f, 0.304688f, 0.859375f},
+ {0.343750f, 0.433594f, 0.828125f, 0.000000f}, {0.953125f, 0.976562f, 0.226562f, 0.769531f},
+ {0.042969f, 0.273438f, 0.566406f, 0.843750f}, {0.691406f, 0.402344f, 0.335938f, 0.425781f},
+ {0.394531f, 0.937500f, 0.476562f, 0.550781f}, {0.613281f, 0.476562f, 0.636719f, 0.808594f},
+ {0.093750f, 0.878906f, 0.890625f, 0.167969f}, {0.789062f, 0.234375f, 0.324219f, 0.066406f},
+ {0.980469f, 0.511719f, 0.441406f, 0.933594f}, {0.382812f, 0.675781f, 0.796875f, 0.710938f},
+ {0.500000f, 0.765625f, 0.273438f, 0.312500f}, {0.078125f, 0.125000f, 0.527344f, 0.839844f},
+ {0.757812f, 0.554688f, 0.980469f, 0.187500f}, {0.246094f, 0.332031f, 0.816406f, 0.960938f},
+ {0.589844f, 0.167969f, 0.421875f, 0.687500f}, {0.984375f, 0.582031f, 0.609375f, 0.074219f},
+ {0.089844f, 0.746094f, 0.097656f, 0.472656f}, {0.375000f, 0.406250f, 0.046875f, 0.117188f},
+ {0.238281f, 0.023438f, 0.468750f, 0.664062f}, {0.042969f, 0.570312f, 0.984375f, 0.527344f},
+ {0.894531f, 0.988281f, 0.097656f, 0.917969f}, {0.679688f, 0.750000f, 0.882812f, 0.824219f},
+ {0.121094f, 0.156250f, 0.015625f, 0.296875f}, {0.417969f, 0.601562f, 0.152344f, 0.675781f},
+ {0.714844f, 0.062500f, 0.925781f, 0.367188f}, {0.187500f, 0.878906f, 0.679688f, 0.515625f},
+ {0.789062f, 0.097656f, 0.574219f, 0.632812f}, {0.671875f, 0.683594f, 0.132812f, 0.968750f},
+ {0.593750f, 0.828125f, 0.363281f, 0.695312f}, {0.332031f, 0.324219f, 0.281250f, 0.535156f},
+ {0.058594f, 0.406250f, 0.957031f, 0.585938f}, {0.250000f, 0.871094f, 0.164062f, 0.800781f},
+ {0.355469f, 0.574219f, 0.894531f, 0.187500f}, {0.042969f, 0.359375f, 0.070312f, 0.625000f},
+ {0.207031f, 0.265625f, 0.949219f, 0.839844f}, {0.703125f, 0.031250f, 0.746094f, 0.039062f},
+ {0.273438f, 0.609375f, 0.242188f, 0.246094f}, {0.601562f, 0.371094f, 0.093750f, 0.781250f},
+ {0.535156f, 0.859375f, 0.765625f, 0.542969f}, {0.140625f, 0.324219f, 0.035156f, 0.292969f},
+ {0.425781f, 0.476562f, 0.605469f, 0.812500f}, {0.292969f, 0.585938f, 0.417969f, 0.660156f},
+ {0.023438f, 0.890625f, 0.066406f, 0.246094f}, {0.542969f, 0.445312f, 0.183594f, 0.539062f},
+ {0.484375f, 0.152344f, 0.976562f, 0.027344f}, {0.226562f, 0.953125f, 0.480469f, 0.488281f},
+ {0.988281f, 0.003906f, 0.054688f, 0.128906f}, {0.339844f, 0.125000f, 0.703125f, 0.648438f},
+ {0.406250f, 0.265625f, 0.281250f, 0.511719f}, {0.203125f, 0.453125f, 0.746094f, 0.890625f},
+ {0.308594f, 0.164062f, 0.535156f, 0.105469f}, {0.425781f, 0.023438f, 0.679688f, 0.574219f},
+ {0.871094f, 0.976562f, 0.609375f, 0.718750f}, {0.371094f, 0.664062f, 0.367188f, 0.078125f},
+ {0.531250f, 0.140625f, 0.160156f, 0.660156f}, {0.050781f, 0.570312f, 0.289062f, 0.007812f},
+ {0.710938f, 0.488281f, 0.636719f, 0.332031f}, {0.214844f, 0.089844f, 0.773438f, 0.207031f},
+ {0.132812f, 0.937500f, 0.097656f, 0.871094f}, {0.746094f, 0.554688f, 0.257812f, 0.097656f},
+ {0.832031f, 0.039062f, 0.964844f, 0.601562f}, {0.597656f, 0.625000f, 0.464844f, 0.703125f},
+ {0.898438f, 0.371094f, 0.539062f, 0.218750f}, {0.160156f, 0.207031f, 0.132812f, 0.574219f},
+ {0.515625f, 0.050781f, 0.937500f, 0.121094f}, {0.089844f, 0.734375f, 0.449219f, 0.343750f},
+ {0.640625f, 0.156250f, 0.093750f, 0.671875f}, {0.894531f, 0.578125f, 0.039062f, 0.058594f},
+ {0.449219f, 0.218750f, 0.847656f, 0.226562f}, {0.753906f, 0.726562f, 0.175781f, 0.382812f},
+ {0.035156f, 0.082031f, 0.261719f, 0.281250f}, {0.542969f, 0.328125f, 0.023438f, 0.652344f},
+ {0.234375f, 0.910156f, 0.562500f, 0.433594f}, {0.707031f, 0.449219f, 0.855469f, 0.242188f},
+ {0.312500f, 0.941406f, 0.394531f, 0.003906f}, {0.203125f, 0.218750f, 0.035156f, 0.625000f},
+ {0.917969f, 0.835938f, 0.628906f, 0.492188f}, {0.363281f, 0.972656f, 0.699219f, 0.382812f},
+ {0.156250f, 0.710938f, 0.125000f, 0.035156f}, {0.425781f, 0.265625f, 0.367188f, 0.535156f},
+ {0.667969f, 0.875000f, 0.535156f, 0.300781f}, {0.527344f, 0.640625f, 0.742188f, 0.753906f},
+ {0.769531f, 0.148438f, 0.328125f, 0.871094f}, {0.152344f, 0.484375f, 0.230469f, 0.046875f},
+ {0.488281f, 0.332031f, 0.511719f, 0.339844f}, {0.214844f, 0.656250f, 0.265625f, 0.105469f},
+ {0.539062f, 0.906250f, 0.363281f, 0.417969f}, {0.878906f, 0.207031f, 0.464844f, 0.167969f},
+ {0.304688f, 0.957031f, 0.324219f, 0.769531f}, {0.496094f, 0.726562f, 0.039062f, 0.117188f},
+ {0.980469f, 0.273438f, 0.406250f, 0.453125f}, {0.031250f, 0.167969f, 0.976562f, 0.058594f},
+ {0.414062f, 0.585938f, 0.804688f, 0.156250f}, {0.117188f, 0.960938f, 0.023438f, 0.222656f},
+ {0.882812f, 0.507812f, 0.449219f, 0.414062f}, {0.554688f, 0.066406f, 0.757812f, 0.113281f},
+ {0.808594f, 0.175781f, 0.515625f, 0.984375f}, {0.621094f, 0.937500f, 0.304688f, 0.269531f},
+ {0.769531f, 0.824219f, 0.609375f, 0.449219f}, {0.906250f, 0.750000f, 0.386719f, 0.738281f},
+ {0.464844f, 0.980469f, 0.878906f, 0.335938f}, {0.000000f, 0.542969f, 0.441406f, 0.429688f},
+ {0.781250f, 0.179688f, 0.984375f, 0.027344f}, {0.238281f, 0.765625f, 0.304688f, 0.914062f},
+ {0.500000f, 0.011719f, 0.914062f, 0.082031f}, {0.871094f, 0.238281f, 0.792969f, 0.355469f},
+ {0.750000f, 0.707031f, 0.632812f, 0.742188f}, {0.945312f, 0.796875f, 0.382812f, 0.433594f},
+ {0.109375f, 0.207031f, 0.570312f, 0.316406f}, {0.707031f, 0.492188f, 0.761719f, 0.203125f},
+ {0.597656f, 0.390625f, 0.328125f, 0.917969f}, {0.003906f, 0.554688f, 0.941406f, 0.261719f},
+ {0.519531f, 0.777344f, 0.453125f, 0.445312f}, {0.628906f, 0.699219f, 0.144531f, 0.679688f},
+ {0.066406f, 0.867188f, 0.878906f, 0.226562f}, {0.683594f, 0.589844f, 0.308594f, 0.777344f},
+ {0.117188f, 0.246094f, 0.464844f, 0.437500f}, {0.933594f, 0.339844f, 0.027344f, 0.488281f},
+ {0.632812f, 0.917969f, 0.925781f, 0.234375f}, {0.320312f, 0.273438f, 0.535156f, 0.886719f},
+ {0.980469f, 0.816406f, 0.050781f, 0.734375f}, {0.476562f, 0.734375f, 0.488281f, 0.152344f},
+ {0.648438f, 0.187500f, 0.687500f, 0.824219f}, {0.308594f, 0.875000f, 0.847656f, 0.460938f},
+ {0.367188f, 0.695312f, 0.417969f, 0.949219f}, {0.234375f, 0.281250f, 0.097656f, 0.035156f},
+ {0.007812f, 0.468750f, 0.667969f, 0.421875f}, {0.664062f, 0.921875f, 0.753906f, 0.914062f},
+ {0.863281f, 0.597656f, 0.605469f, 0.718750f}, {0.378906f, 0.320312f, 0.386719f, 0.476562f},
+ {0.273438f, 0.492188f, 0.683594f, 0.953125f}, {0.550781f, 0.851562f, 0.781250f, 0.144531f},
+ {0.167969f, 0.027344f, 0.593750f, 0.613281f}, {0.250000f, 0.367188f, 0.925781f, 0.976562f},
+ {0.941406f, 0.656250f, 0.511719f, 0.746094f}, {0.468750f, 0.757812f, 0.675781f, 0.531250f},
+ {0.156250f, 0.140625f, 0.953125f, 0.132812f}, {0.890625f, 0.269531f, 0.164062f, 0.792969f},
+ {0.820312f, 0.074219f, 0.734375f, 0.988281f}, {0.449219f, 0.605469f, 0.476562f, 0.105469f},
+ {0.546875f, 0.503906f, 0.210938f, 0.738281f}, {0.058594f, 0.019531f, 0.320312f, 0.277344f},
+ {0.875000f, 0.390625f, 0.867188f, 0.914062f}, {0.718750f, 0.468750f, 0.261719f, 0.808594f},
+ {0.281250f, 0.207031f, 0.953125f, 0.175781f}, {0.832031f, 0.312500f, 0.835938f, 0.402344f},
+ {0.914062f, 0.945312f, 0.640625f, 0.230469f}, {0.316406f, 0.816406f, 0.402344f, 0.457031f},
+ {0.648438f, 0.257812f, 0.730469f, 0.593750f}, {0.976562f, 0.441406f, 0.667969f, 0.730469f},
+ {0.363281f, 0.011719f, 0.957031f, 0.984375f}, {0.015625f, 0.363281f, 0.820312f, 0.019531f},
+ {0.636719f, 0.476562f, 0.531250f, 0.574219f}, {0.144531f, 0.632812f, 0.734375f, 0.878906f},
+ {0.355469f, 0.421875f, 0.253906f, 0.269531f}, {0.269531f, 0.929688f, 0.484375f, 0.730469f},
+ {0.773438f, 0.027344f, 0.621094f, 0.339844f}, {0.921875f, 0.253906f, 0.707031f, 0.925781f},
+ {0.722656f, 0.660156f, 0.328125f, 0.867188f}, {0.453125f, 0.777344f, 0.839844f, 0.679688f},
+ {0.156250f, 0.292969f, 0.234375f, 0.324219f}, {0.988281f, 0.699219f, 0.128906f, 0.062500f},
+ {0.523438f, 0.402344f, 0.820312f, 0.898438f}, {0.128906f, 0.140625f, 0.183594f, 0.160156f},
+ {0.394531f, 0.238281f, 0.050781f, 0.597656f}, {0.964844f, 0.062500f, 0.660156f, 0.855469f},
+ {0.339844f, 0.429688f, 0.558594f, 0.707031f}, {0.722656f, 0.648438f, 0.363281f, 0.628906f},
+ {0.921875f, 0.515625f, 0.207031f, 0.460938f}, {0.054688f, 0.988281f, 0.503906f, 0.878906f},
+ {0.652344f, 0.089844f, 0.718750f, 0.179688f}, {0.351562f, 0.339844f, 0.140625f, 0.980469f},
+ {0.800781f, 0.902344f, 0.085938f, 0.679688f}, {0.429688f, 0.679688f, 0.859375f, 0.765625f},
+ {0.296875f, 0.820312f, 0.195312f, 0.546875f}, {0.675781f, 0.613281f, 0.621094f, 0.839844f},
+ {0.882812f, 0.933594f, 0.816406f, 0.167969f}, {0.769531f, 0.070312f, 0.363281f, 0.812500f},
+ {0.964844f, 0.367188f, 0.062500f, 0.937500f}, {0.480469f, 0.421875f, 0.988281f, 0.351562f},
+ {0.226562f, 0.113281f, 0.121094f, 0.144531f}, {0.277344f, 0.726562f, 0.828125f, 0.992188f},
+ {0.742188f, 0.464844f, 0.695312f, 0.804688f}, {0.152344f, 0.058594f, 0.398438f, 0.382812f},
+ {0.421875f, 0.675781f, 0.960938f, 0.574219f}, {0.792969f, 0.601562f, 0.144531f, 0.511719f},
+ {0.031250f, 0.320312f, 0.332031f, 0.648438f}, {0.933594f, 0.441406f, 0.578125f, 0.292969f},
+ {0.703125f, 0.230469f, 0.179688f, 0.789062f}, {0.492188f, 0.773438f, 0.925781f, 0.527344f},
+ {0.960938f, 0.535156f, 0.339844f, 0.324219f}, {0.425781f, 0.671875f, 0.035156f, 0.820312f},
+ {0.734375f, 0.804688f, 0.257812f, 0.628906f}, {0.207031f, 0.113281f, 0.164062f, 0.187500f},
+ {0.808594f, 0.902344f, 0.984375f, 0.289062f}, {0.988281f, 0.636719f, 0.300781f, 0.886719f},
+ {0.707031f, 0.441406f, 0.214844f, 0.507812f}, {0.328125f, 0.968750f, 0.371094f, 0.015625f},
+ {0.859375f, 0.183594f, 0.742188f, 0.839844f}, {0.656250f, 0.570312f, 0.121094f, 0.332031f},
+ {0.398438f, 0.414062f, 0.343750f, 0.882812f}, {0.113281f, 0.816406f, 0.234375f, 0.476562f},
+ {0.613281f, 0.703125f, 0.656250f, 0.398438f}, {0.027344f, 0.359375f, 0.093750f, 0.550781f},
+ {0.683594f, 0.292969f, 0.789062f, 0.855469f}, {0.785156f, 0.804688f, 0.917969f, 0.214844f},
+ {0.328125f, 0.910156f, 0.574219f, 0.617188f}, {0.621094f, 0.085938f, 0.007812f, 0.359375f},
+ {0.199219f, 0.687500f, 0.445312f, 0.964844f}, {0.117188f, 0.519531f, 0.183594f, 0.699219f},
+ {0.574219f, 0.066406f, 0.121094f, 0.628906f}, {0.394531f, 0.605469f, 0.914062f, 0.945312f},
+ {0.730469f, 0.718750f, 0.574219f, 0.144531f}, {0.078125f, 0.105469f, 0.066406f, 0.265625f},
+ {0.800781f, 0.546875f, 0.191406f, 0.523438f}, {0.460938f, 0.792969f, 0.609375f, 0.703125f},
+ {0.746094f, 0.847656f, 0.101562f, 0.218750f}, {0.582031f, 0.125000f, 0.914062f, 0.945312f},
+ {0.859375f, 0.335938f, 0.851562f, 0.402344f}, {0.695312f, 0.535156f, 0.070312f, 0.785156f},
+ {0.523438f, 0.792969f, 0.207031f, 0.593750f}, {0.210938f, 0.445312f, 0.886719f, 0.464844f},
+ {0.628906f, 0.132812f, 0.582031f, 0.000000f}, {0.285156f, 0.902344f, 0.054688f, 0.515625f},
+ {0.019531f, 0.472656f, 0.648438f, 0.773438f}, {0.410156f, 0.011719f, 0.414062f, 0.558594f},
+ {0.312500f, 0.632812f, 0.699219f, 0.652344f}, {0.230469f, 0.500000f, 0.527344f, 0.500000f},
+ {0.656250f, 0.789062f, 0.921875f, 0.109375f}, {0.843750f, 0.308594f, 0.265625f, 0.960938f},
+ {0.183594f, 0.835938f, 0.734375f, 0.218750f}, {0.632812f, 0.925781f, 0.109375f, 0.140625f},
+ {0.093750f, 0.136719f, 0.847656f, 0.269531f}, {0.394531f, 0.371094f, 0.011719f, 0.523438f},
+ {0.191406f, 0.625000f, 0.273438f, 0.046875f}, {0.269531f, 0.566406f, 0.894531f, 0.593750f},
+ {0.574219f, 0.035156f, 0.359375f, 0.906250f}, {0.164062f, 0.300781f, 0.523438f, 0.085938f},
+ {0.925781f, 0.101562f, 0.425781f, 0.359375f}, {0.089844f, 0.230469f, 0.003906f, 0.054688f},
+ {0.257812f, 0.332031f, 0.550781f, 0.589844f}, {0.378906f, 0.187500f, 0.242188f, 0.300781f},
+ {0.167969f, 0.531250f, 0.785156f, 0.023438f}, {0.722656f, 0.824219f, 0.640625f, 0.628906f},
+ {0.578125f, 0.898438f, 0.519531f, 0.546875f}, {0.835938f, 0.621094f, 0.257812f, 0.054688f},
+ {0.503906f, 0.175781f, 0.195312f, 0.691406f}, {0.074219f, 0.394531f, 0.601562f, 0.304688f},
+ {0.882812f, 0.953125f, 0.796875f, 0.085938f}, {0.574219f, 0.015625f, 0.230469f, 0.968750f},
+ {0.273438f, 0.515625f, 0.886719f, 0.050781f}, {0.113281f, 0.828125f, 0.742188f, 0.367188f},
+ {0.816406f, 0.101562f, 0.281250f, 0.183594f}, {0.187500f, 0.968750f, 0.625000f, 0.671875f},
+ {0.562500f, 0.003906f, 0.796875f, 0.113281f}, {0.320312f, 0.164062f, 0.898438f, 0.257812f},
+ {0.128906f, 0.257812f, 0.503906f, 0.062500f}, {0.593750f, 0.390625f, 0.843750f, 0.542969f},
+ {0.472656f, 0.757812f, 0.726562f, 0.402344f}, {0.023438f, 0.062500f, 0.539062f, 0.792969f},
+ {0.113281f, 0.296875f, 0.425781f, 0.722656f}, {0.523438f, 0.808594f, 0.054688f, 0.449219f},
+ {0.800781f, 0.515625f, 0.816406f, 0.093750f}, {0.054688f, 0.867188f, 0.460938f, 0.207031f},
+ {0.566406f, 0.019531f, 0.605469f, 0.582031f}, {0.742188f, 0.992188f, 0.882812f, 0.671875f},
+ {0.265625f, 0.472656f, 0.546875f, 0.171875f}, {0.992188f, 0.171875f, 0.964844f, 0.316406f},
+ {0.406250f, 0.746094f, 0.429688f, 0.695312f}, {0.132812f, 0.628906f, 0.160156f, 0.453125f},
+ {0.488281f, 0.140625f, 0.507812f, 0.136719f}, {0.937500f, 0.562500f, 0.679688f, 0.566406f},
+ {0.019531f, 0.789062f, 0.769531f, 0.085938f}, {0.464844f, 0.898438f, 0.597656f, 0.492188f},
+ {0.957031f, 0.378906f, 0.304688f, 0.011719f}, {0.050781f, 0.179688f, 0.027344f, 0.765625f},
+ {0.261719f, 0.859375f, 0.875000f, 0.375000f}, {0.609375f, 0.964844f, 0.437500f, 0.812500f},
+ {0.175781f, 0.296875f, 0.781250f, 0.894531f}, {0.929688f, 0.691406f, 0.289062f, 0.468750f},
+ {0.238281f, 0.234375f, 0.382812f, 0.347656f}, {0.093750f, 0.054688f, 0.160156f, 0.652344f},
+ {0.914062f, 0.750000f, 0.656250f, 0.035156f}, {0.445312f, 0.863281f, 0.320312f, 0.187500f},
+ {0.167969f, 0.199219f, 0.519531f, 0.828125f}, {0.070312f, 0.703125f, 0.117188f, 0.644531f},
+ {0.371094f, 0.382812f, 0.386719f, 0.289062f}, {0.949219f, 0.601562f, 0.917969f, 0.144531f},
+ {0.675781f, 0.218750f, 0.476562f, 0.394531f}, {0.867188f, 0.550781f, 0.988281f, 0.933594f},
+ {0.585938f, 0.960938f, 0.003906f, 0.199219f}, {0.753906f, 0.339844f, 0.328125f, 0.371094f},
+ {0.078125f, 0.914062f, 0.773438f, 0.796875f}, {0.542969f, 0.593750f, 0.488281f, 0.308594f},
+ {0.449219f, 0.683594f, 0.148438f, 0.558594f}, {0.289062f, 0.218750f, 0.406250f, 0.402344f},
+ {0.582031f, 0.281250f, 0.589844f, 0.929688f}, {0.828125f, 0.734375f, 0.941406f, 0.714844f},
+ {0.460938f, 0.867188f, 0.449219f, 0.832031f}, {0.960938f, 0.453125f, 0.660156f, 0.398438f},
+ {0.027344f, 0.757812f, 0.234375f, 0.230469f}, {0.742188f, 0.972656f, 0.730469f, 0.468750f},
+ {0.488281f, 0.429688f, 0.128906f, 0.640625f}, {0.839844f, 0.722656f, 0.968750f, 0.960938f},
+ {0.558594f, 0.484375f, 0.664062f, 0.742188f}, {0.039062f, 0.964844f, 0.894531f, 0.390625f},
+ {0.812500f, 0.753906f, 0.183594f, 0.503906f}, {0.335938f, 0.281250f, 0.417969f, 0.757812f},
+ {0.441406f, 0.035156f, 0.726562f, 0.878906f}, {0.019531f, 0.496094f, 0.347656f, 0.269531f},
+ {0.921875f, 0.777344f, 0.867188f, 0.175781f}, {0.679688f, 0.859375f, 0.074219f, 0.605469f},
+ {0.355469f, 0.242188f, 0.449219f, 0.433594f}, {0.175781f, 0.363281f, 0.656250f, 0.765625f},
+ {0.515625f, 0.898438f, 0.003906f, 0.246094f}, {0.613281f, 0.152344f, 0.468750f, 0.894531f},
+ {0.386719f, 0.402344f, 0.523438f, 0.566406f}, {0.066406f, 0.613281f, 0.062500f, 0.988281f},
+ {0.765625f, 0.347656f, 0.390625f, 0.449219f}, {0.851562f, 0.843750f, 0.203125f, 0.875000f},
+ {0.054688f, 0.445312f, 0.441406f, 0.750000f}, {0.929688f, 0.992188f, 0.644531f, 0.937500f},
+ {0.769531f, 0.554688f, 0.000000f, 0.597656f}, {0.632812f, 0.234375f, 0.132812f, 0.101562f},
+ {0.367188f, 0.691406f, 0.867188f, 0.347656f}, {0.425781f, 0.125000f, 0.632812f, 0.261719f},
+ {0.183594f, 0.613281f, 0.968750f, 0.691406f}, {0.285156f, 0.250000f, 0.078125f, 0.929688f},
+ {0.917969f, 0.320312f, 0.292969f, 0.039062f}, {0.347656f, 0.644531f, 0.800781f, 0.269531f},
+ {0.851562f, 0.539062f, 0.019531f, 0.945312f}, {0.515625f, 0.882812f, 0.359375f, 0.070312f},
+ {0.218750f, 0.050781f, 0.277344f, 0.886719f}, {0.898438f, 0.242188f, 0.714844f, 0.019531f},
+ {0.558594f, 0.441406f, 0.062500f, 0.773438f}, {0.250000f, 0.964844f, 0.390625f, 0.902344f},
+ {0.820312f, 0.343750f, 0.226562f, 0.265625f}, {0.343750f, 0.003906f, 0.972656f, 0.832031f},
+ {0.757812f, 0.753906f, 0.484375f, 0.316406f}, {0.507812f, 0.234375f, 0.808594f, 0.554688f},
+ {0.859375f, 0.410156f, 0.347656f, 0.203125f}, {0.425781f, 0.503906f, 0.140625f, 0.062500f},
+ {0.687500f, 0.140625f, 0.496094f, 0.601562f}, {0.292969f, 0.582031f, 0.996094f, 0.093750f},
+ {0.828125f, 0.386719f, 0.707031f, 0.300781f}, {0.398438f, 0.980469f, 0.578125f, 0.859375f},
+ {0.042969f, 0.496094f, 0.441406f, 0.500000f}, {0.320312f, 0.609375f, 0.777344f, 0.550781f},
+ {0.601562f, 0.304688f, 0.945312f, 0.089844f}, {0.851562f, 0.093750f, 0.269531f, 0.234375f},
+ {0.492188f, 0.988281f, 0.753906f, 0.953125f}, {0.792969f, 0.332031f, 0.175781f, 0.847656f},
+ {0.089844f, 0.843750f, 0.726562f, 0.710938f}, {0.183594f, 0.082031f, 0.277344f, 0.246094f},
+ {0.476562f, 0.714844f, 0.566406f, 0.039062f}, {0.925781f, 0.187500f, 0.835938f, 0.878906f},
+ {0.035156f, 0.109375f, 0.214844f, 0.691406f}, {0.695312f, 0.464844f, 0.621094f, 0.007812f},
+ {0.949219f, 0.023438f, 0.968750f, 0.472656f}, {0.136719f, 0.558594f, 0.800781f, 0.769531f},
+ {0.773438f, 0.410156f, 0.679688f, 0.066406f}, {0.519531f, 0.816406f, 0.320312f, 0.644531f},
+ {0.683594f, 0.066406f, 0.171875f, 0.296875f}, {0.867188f, 0.253906f, 0.820312f, 0.125000f},
+ {0.386719f, 0.523438f, 0.054688f, 0.562500f}, {0.332031f, 0.156250f, 0.601562f, 0.863281f},
+ {0.648438f, 0.851562f, 0.796875f, 0.281250f}, {0.214844f, 0.644531f, 0.269531f, 0.425781f},
+ {0.417969f, 0.023438f, 0.390625f, 0.140625f}, {0.917969f, 0.132812f, 0.082031f, 0.902344f},
+ {0.617188f, 0.664062f, 0.496094f, 0.093750f}, {0.101562f, 0.578125f, 0.589844f, 0.207031f},
+ {0.996094f, 0.222656f, 0.015625f, 0.414062f}, {0.199219f, 0.996094f, 0.949219f, 0.824219f},
+ {0.398438f, 0.316406f, 0.757812f, 0.480469f}, {0.605469f, 0.550781f, 0.562500f, 0.929688f},
+ {0.246094f, 0.085938f, 0.300781f, 0.855469f}, {0.832031f, 0.648438f, 0.363281f, 0.128906f},
+ {0.914062f, 0.757812f, 0.914062f, 0.699219f}, {0.691406f, 0.566406f, 0.828125f, 0.410156f},
+ {0.980469f, 0.292969f, 0.121094f, 0.007812f}, {0.457031f, 0.742188f, 0.949219f, 0.730469f},
+ {0.648438f, 0.914062f, 0.714844f, 0.148438f}, {0.257812f, 0.511719f, 0.566406f, 0.503906f},
+ {0.527344f, 0.082031f, 0.105469f, 0.375000f}, {0.398438f, 0.707031f, 0.285156f, 0.019531f},
+ {0.300781f, 0.183594f, 0.359375f, 0.230469f}, {0.222656f, 0.355469f, 0.933594f, 0.867188f},
+ {0.867188f, 0.500000f, 0.476562f, 0.167969f}, {0.964844f, 0.945312f, 0.257812f, 0.636719f},
+ {0.683594f, 0.386719f, 0.171875f, 0.535156f}, {0.601562f, 0.074219f, 0.710938f, 0.781250f},
+ {0.484375f, 0.785156f, 0.414062f, 0.359375f}, {0.074219f, 0.214844f, 0.503906f, 0.742188f},
+ {0.167969f, 0.113281f, 0.144531f, 0.609375f}, {0.640625f, 0.378906f, 0.746094f, 0.800781f},
+ {0.304688f, 0.949219f, 0.851562f, 0.507812f}, {0.750000f, 0.507812f, 0.613281f, 0.339844f},
+ {0.082031f, 0.671875f, 0.894531f, 0.656250f}, {0.660156f, 0.195312f, 0.324219f, 0.410156f},
+ {0.414062f, 0.281250f, 0.824219f, 0.722656f}, {0.703125f, 0.640625f, 0.085938f, 0.167969f},
+ {0.597656f, 0.464844f, 0.718750f, 0.437500f}, {0.140625f, 0.578125f, 0.253906f, 0.863281f},
+ {0.207031f, 0.667969f, 0.546875f, 0.921875f}, {0.968750f, 0.042969f, 0.679688f, 0.667969f},
+ {0.531250f, 0.875000f, 0.218750f, 0.410156f}, {0.117188f, 0.761719f, 0.000000f, 0.164062f},
+ {0.488281f, 0.179688f, 0.894531f, 0.800781f}, {0.562500f, 0.660156f, 0.238281f, 0.722656f},
+ {0.789062f, 0.265625f, 0.050781f, 0.125000f}, {0.664062f, 0.007812f, 0.835938f, 0.992188f},
+ {0.996094f, 0.894531f, 0.410156f, 0.375000f}, {0.753906f, 0.566406f, 0.636719f, 0.757812f},
+ {0.234375f, 0.804688f, 0.550781f, 0.437500f}, {0.562500f, 0.046875f, 0.082031f, 0.074219f},
+ {0.343750f, 0.757812f, 0.359375f, 0.597656f}, {0.726562f, 0.429688f, 0.863281f, 0.480469f},
+ {0.257812f, 0.875000f, 0.136719f, 0.753906f}, {0.816406f, 0.261719f, 0.437500f, 0.429688f},
+ {0.332031f, 0.390625f, 0.089844f, 0.273438f}, {0.382812f, 0.742188f, 0.351562f, 0.621094f},
+ {0.222656f, 0.890625f, 0.027344f, 0.839844f}, {0.890625f, 0.093750f, 0.246094f, 0.988281f},
+ {0.011719f, 0.968750f, 0.539062f, 0.203125f}, {0.316406f, 0.484375f, 0.074219f, 0.363281f},
+ {0.238281f, 0.187500f, 0.500000f, 0.496094f}, {0.105469f, 0.660156f, 0.996094f, 0.796875f},
+ {0.777344f, 0.386719f, 0.414062f, 0.167969f}, {0.531250f, 0.589844f, 0.308594f, 0.730469f},
+ {0.976562f, 0.347656f, 0.871094f, 0.027344f}, {0.125000f, 0.261719f, 0.468750f, 0.691406f},
+ {0.710938f, 0.910156f, 0.703125f, 0.531250f}, {0.468750f, 0.812500f, 0.328125f, 0.250000f},
+ {0.277344f, 0.441406f, 0.765625f, 0.667969f}, {0.535156f, 0.375000f, 0.917969f, 0.972656f},
+ {0.648438f, 0.074219f, 0.292969f, 0.324219f}, {0.785156f, 0.687500f, 0.156250f, 0.710938f},
+ {0.304688f, 0.136719f, 0.484375f, 0.011719f}, {0.089844f, 0.714844f, 0.113281f, 0.652344f},
+ {0.769531f, 0.453125f, 0.992188f, 0.214844f}, {0.437500f, 0.199219f, 0.703125f, 0.328125f},
+ {0.003906f, 0.980469f, 0.171875f, 0.488281f}, {0.300781f, 0.476562f, 0.410156f, 0.621094f},
+ {0.218750f, 0.695312f, 0.218750f, 0.843750f}, {0.140625f, 0.058594f, 0.652344f, 0.222656f},
+ {0.347656f, 0.199219f, 0.320312f, 0.335938f}, {0.945312f, 0.652344f, 0.863281f, 0.652344f},
+ {0.703125f, 0.312500f, 0.976562f, 0.808594f}, {0.171875f, 0.585938f, 0.753906f, 0.292969f},
+ {0.906250f, 0.863281f, 0.808594f, 0.683594f}, {0.082031f, 0.781250f, 0.582031f, 0.488281f},
+ {0.562500f, 0.007812f, 0.691406f, 0.988281f}, {0.734375f, 0.886719f, 0.332031f, 0.406250f},
+ {0.000000f, 0.730469f, 0.550781f, 0.894531f}, {0.234375f, 0.460938f, 0.894531f, 0.117188f},
+ {0.761719f, 0.929688f, 0.207031f, 0.492188f}, {0.957031f, 0.683594f, 0.933594f, 0.441406f},
+ {0.386719f, 0.828125f, 0.644531f, 0.152344f}, {0.718750f, 0.593750f, 0.246094f, 0.394531f},
+ {0.011719f, 0.308594f, 0.484375f, 0.242188f}, {0.839844f, 0.851562f, 0.113281f, 0.972656f},
+ {0.359375f, 0.765625f, 0.195312f, 0.199219f}, {0.957031f, 0.406250f, 0.933594f, 0.531250f},
+ {0.175781f, 0.117188f, 0.535156f, 0.054688f}, {0.039062f, 0.863281f, 0.648438f, 0.992188f},
+ {0.285156f, 0.996094f, 0.152344f, 0.648438f}, {0.898438f, 0.074219f, 0.410156f, 0.117188f},
+ {0.375000f, 0.808594f, 0.929688f, 0.507812f}, {0.777344f, 0.347656f, 0.761719f, 0.277344f},
+ {0.007812f, 0.937500f, 0.617188f, 0.757812f}, {0.339844f, 0.433594f, 0.816406f, 0.972656f},
+ {0.718750f, 0.085938f, 0.328125f, 0.621094f}, {0.957031f, 0.921875f, 0.542969f, 0.250000f},
+ {0.214844f, 0.460938f, 0.132812f, 0.421875f}, {0.128906f, 0.734375f, 0.691406f, 0.882812f},
+ {0.277344f, 0.398438f, 0.195312f, 0.312500f}, {0.011719f, 0.179688f, 0.011719f, 0.667969f},
+ {0.406250f, 0.476562f, 0.960938f, 0.566406f}, {0.140625f, 0.644531f, 0.796875f, 0.175781f},
+ {0.898438f, 0.277344f, 0.222656f, 0.343750f}, {0.433594f, 0.156250f, 0.675781f, 0.980469f},
+ {0.613281f, 0.664062f, 0.601562f, 0.125000f}, {0.117188f, 0.539062f, 0.953125f, 0.546875f},
+ {0.511719f, 0.820312f, 0.722656f, 0.914062f}, {0.859375f, 0.625000f, 0.902344f, 0.156250f},
+ {0.593750f, 0.355469f, 0.464844f, 0.332031f}, {0.421875f, 0.167969f, 0.871094f, 0.101562f},
+ {0.730469f, 0.707031f, 0.714844f, 0.582031f}, {0.996094f, 0.613281f, 0.375000f, 0.746094f},
+ {0.156250f, 0.328125f, 0.769531f, 0.039062f}, {0.625000f, 0.929688f, 0.628906f, 0.949219f},
+ {0.449219f, 0.113281f, 0.910156f, 0.625000f}, {0.257812f, 0.800781f, 0.562500f, 0.339844f},
+ {0.046875f, 0.054688f, 0.031250f, 0.996094f}, {0.792969f, 0.496094f, 0.160156f, 0.195312f},
+ {0.324219f, 0.562500f, 0.929688f, 0.847656f}, {0.175781f, 0.203125f, 0.210938f, 0.789062f},
+ {0.863281f, 0.304688f, 0.847656f, 0.468750f}, {0.746094f, 0.925781f, 0.070312f, 0.609375f},
+ {0.136719f, 0.843750f, 0.675781f, 0.156250f}, {0.886719f, 0.605469f, 0.390625f, 0.562500f},
+ {0.519531f, 0.414062f, 0.636719f, 0.113281f}, {0.710938f, 0.910156f, 0.214844f, 0.375000f},
+ {0.964844f, 0.808594f, 0.785156f, 0.531250f}, {0.128906f, 0.281250f, 0.066406f, 0.957031f},
+ {0.488281f, 0.031250f, 0.609375f, 0.816406f}, {0.750000f, 0.128906f, 0.542969f, 0.101562f},
+ {0.550781f, 0.878906f, 0.757812f, 0.281250f}, {0.886719f, 0.250000f, 0.261719f, 0.917969f},
+ {0.808594f, 0.417969f, 0.476562f, 0.585938f}, {0.585938f, 0.812500f, 0.156250f, 0.085938f},
+ {0.011719f, 0.027344f, 0.042969f, 0.968750f}, {0.445312f, 0.941406f, 0.515625f, 0.429688f},
+ {0.671875f, 0.136719f, 0.179688f, 0.136719f}, {0.812500f, 0.640625f, 0.230469f, 0.832031f},
+ {0.480469f, 0.433594f, 0.070312f, 0.562500f}, {0.144531f, 0.281250f, 0.789062f, 0.031250f},
+ {0.320312f, 0.179688f, 0.023438f, 0.304688f}, {0.886719f, 0.558594f, 0.757812f, 0.234375f},
+ {0.445312f, 0.347656f, 0.371094f, 0.968750f}, {0.121094f, 0.039062f, 0.585938f, 0.863281f},
+ {0.816406f, 0.421875f, 0.054688f, 0.648438f}, {0.578125f, 0.160156f, 0.992188f, 0.089844f},
+ {0.429688f, 0.722656f, 0.402344f, 0.574219f}, {0.148438f, 0.097656f, 0.562500f, 0.835938f},
+ {0.613281f, 0.035156f, 0.785156f, 0.117188f}, {0.468750f, 0.605469f, 0.449219f, 0.296875f},
+ {0.851562f, 0.800781f, 0.035156f, 0.609375f}, {0.535156f, 0.523438f, 0.367188f, 0.789062f},
+ {0.796875f, 0.152344f, 0.863281f, 0.238281f}, {0.667969f, 0.300781f, 0.585938f, 0.343750f},
+ {0.074219f, 0.722656f, 0.042969f, 0.714844f}, {0.574219f, 0.199219f, 0.300781f, 0.039062f},
+ {0.648438f, 0.269531f, 0.089844f, 0.464844f}, {0.847656f, 0.621094f, 0.402344f, 0.367188f},
+ {0.164062f, 0.527344f, 0.457031f, 0.003906f}, {0.617188f, 0.328125f, 0.742188f, 0.566406f},
+ {0.367188f, 0.835938f, 0.972656f, 0.195312f}, {0.468750f, 0.136719f, 0.351562f, 0.695312f},
+ {0.542969f, 0.679688f, 0.496094f, 0.480469f}, {0.695312f, 0.941406f, 0.855469f, 0.046875f},
+ {0.933594f, 0.234375f, 0.312500f, 0.902344f}, {0.640625f, 0.527344f, 0.429688f, 0.804688f},
+ {0.832031f, 0.375000f, 0.500000f, 0.640625f}, {0.046875f, 0.949219f, 0.066406f, 0.292969f},
+ {0.984375f, 0.460938f, 0.390625f, 0.824219f}, {0.675781f, 0.066406f, 0.179688f, 0.058594f},
+ {0.175781f, 0.992188f, 0.531250f, 0.664062f}, {0.785156f, 0.230469f, 0.660156f, 0.511719f},
+ {0.089844f, 0.792969f, 0.300781f, 0.242188f}, {0.652344f, 0.292969f, 0.121094f, 0.699219f},
+ {0.480469f, 0.535156f, 0.195312f, 0.433594f}, {0.363281f, 0.777344f, 0.933594f, 0.894531f},
+ {0.550781f, 0.011719f, 0.273438f, 0.265625f}, {0.886719f, 0.871094f, 0.144531f, 0.410156f},
+ {0.937500f, 0.679688f, 0.699219f, 0.515625f}, {0.183594f, 0.214844f, 0.218750f, 0.097656f},
+ {0.855469f, 0.988281f, 0.777344f, 0.457031f}, {0.566406f, 0.761719f, 0.519531f, 0.593750f},
+ {0.664062f, 0.394531f, 0.593750f, 0.308594f}, {0.960938f, 0.695312f, 0.113281f, 0.070312f},
+ {0.007812f, 0.101562f, 0.425781f, 0.359375f}, {0.242188f, 0.742188f, 0.546875f, 0.042969f},
+ {0.355469f, 0.480469f, 0.250000f, 0.921875f}, {0.433594f, 0.187500f, 0.828125f, 0.859375f},
+ {0.035156f, 0.000000f, 0.894531f, 0.789062f}, {0.218750f, 0.343750f, 0.535156f, 0.285156f},
+ {0.558594f, 0.523438f, 0.433594f, 0.734375f}, {0.371094f, 0.625000f, 0.273438f, 0.031250f},
+ {0.652344f, 0.835938f, 0.875000f, 0.171875f}, {0.851562f, 0.375000f, 0.332031f, 0.550781f},
+ {0.062500f, 0.605469f, 0.968750f, 0.371094f}, {0.417969f, 0.539062f, 0.031250f, 0.460938f},
+ {0.097656f, 0.957031f, 0.820312f, 0.761719f}, {0.500000f, 0.750000f, 0.601562f, 0.191406f},
+ {0.242188f, 0.472656f, 0.371094f, 0.535156f}, {0.757812f, 0.269531f, 0.660156f, 0.625000f},
+ {0.343750f, 0.394531f, 0.453125f, 0.730469f}, {0.613281f, 0.535156f, 0.914062f, 0.332031f},
+ {0.265625f, 0.085938f, 0.410156f, 0.097656f}, {0.410156f, 0.835938f, 0.980469f, 0.757812f},
+ {0.832031f, 0.664062f, 0.484375f, 0.812500f}, {0.644531f, 0.128906f, 0.664062f, 0.593750f},
+ {0.546875f, 0.761719f, 0.109375f, 0.191406f}, {0.207031f, 0.503906f, 0.304688f, 0.007812f},
+ {0.667969f, 0.898438f, 0.812500f, 0.300781f}, {0.253906f, 0.230469f, 0.687500f, 0.921875f},
+ {0.976562f, 0.468750f, 0.339844f, 0.687500f}, {0.519531f, 0.554688f, 0.003906f, 0.468750f},
+ {0.769531f, 0.359375f, 0.632812f, 0.746094f}, {0.230469f, 0.929688f, 0.289062f, 0.933594f},
+ {0.109375f, 0.695312f, 0.691406f, 0.367188f}, {0.328125f, 0.242188f, 0.246094f, 0.484375f},
+ {0.984375f, 0.429688f, 0.984375f, 0.082031f}, {0.242188f, 0.910156f, 0.464844f, 0.582031f},
+ {0.480469f, 0.488281f, 0.199219f, 0.957031f}, {0.300781f, 0.558594f, 0.835938f, 0.816406f},
+ {0.437500f, 0.023438f, 0.957031f, 0.214844f}, {0.933594f, 0.687500f, 0.527344f, 0.859375f},
+ {0.269531f, 0.800781f, 0.179688f, 0.511719f}, {0.039062f, 0.222656f, 0.871094f, 0.921875f},
+ {0.894531f, 0.062500f, 0.628906f, 0.074219f}, {0.746094f, 0.546875f, 0.277344f, 0.820312f},
+ {0.863281f, 0.343750f, 0.589844f, 0.265625f}, {0.335938f, 0.855469f, 0.105469f, 0.140625f},
+ {0.078125f, 0.109375f, 0.707031f, 0.515625f}, {0.515625f, 0.722656f, 0.617188f, 0.226562f},
+ {0.292969f, 0.886719f, 0.878906f, 0.027344f}, {0.214844f, 0.003906f, 0.937500f, 0.699219f},
+ {0.554688f, 0.601562f, 0.757812f, 0.402344f}, {0.390625f, 0.324219f, 0.281250f, 0.207031f},
+ {0.304688f, 0.128906f, 0.039062f, 0.957031f}, {0.960938f, 0.500000f, 0.808594f, 0.367188f},
+ {0.265625f, 0.031250f, 0.406250f, 0.808594f}, {0.054688f, 0.925781f, 0.613281f, 0.871094f},
+ {0.195312f, 0.429688f, 0.558594f, 0.539062f}, {0.835938f, 0.136719f, 0.828125f, 0.121094f},
+ {0.699219f, 0.242188f, 0.015625f, 0.660156f}, {0.035156f, 0.464844f, 0.480469f, 0.835938f},
+ {0.312500f, 0.554688f, 0.320312f, 0.003906f}, {0.738281f, 0.308594f, 0.093750f, 0.785156f},
+ {0.484375f, 0.621094f, 0.406250f, 0.890625f}, {0.375000f, 0.160156f, 0.957031f, 0.386719f},
+ {0.093750f, 0.882812f, 0.355469f, 0.125000f}, {0.410156f, 0.015625f, 0.644531f, 0.941406f},
+ {0.593750f, 0.597656f, 0.722656f, 0.542969f}, {0.492188f, 0.531250f, 0.984375f, 0.734375f},
+ {0.683594f, 0.265625f, 0.464844f, 0.398438f}, {0.835938f, 0.968750f, 0.035156f, 0.242188f},
+ {0.945312f, 0.761719f, 0.328125f, 0.453125f}, {0.625000f, 0.246094f, 0.730469f, 0.910156f},
+ {0.328125f, 0.078125f, 0.937500f, 0.593750f}, {0.902344f, 0.945312f, 0.015625f, 0.425781f},
+ {0.171875f, 0.433594f, 0.488281f, 0.687500f}, {0.250000f, 0.312500f, 0.804688f, 0.781250f},
+ {0.609375f, 0.781250f, 0.093750f, 0.941406f}, {0.312500f, 0.097656f, 0.687500f, 0.667969f},
+ {0.710938f, 0.160156f, 0.425781f, 0.031250f}, {0.164062f, 0.355469f, 0.945312f, 0.878906f},
+ {0.968750f, 0.628906f, 0.738281f, 0.261719f}, {0.839844f, 0.218750f, 0.296875f, 0.058594f},
+ {0.128906f, 0.902344f, 0.875000f, 0.933594f}, {0.035156f, 0.726562f, 0.113281f, 0.207031f},
+ {0.996094f, 0.335938f, 0.625000f, 0.464844f}, {0.531250f, 0.984375f, 0.277344f, 0.660156f},
+ {0.066406f, 0.589844f, 0.148438f, 0.367188f}, {0.363281f, 0.242188f, 0.867188f, 0.707031f},
+ {0.945312f, 0.953125f, 0.437500f, 0.527344f}, {0.042969f, 0.292969f, 0.535156f, 0.828125f},
+ {0.492188f, 0.617188f, 0.175781f, 0.730469f}, {0.332031f, 0.785156f, 0.886719f, 0.351562f},
+ {0.875000f, 0.984375f, 0.226562f, 0.179688f}, {0.062500f, 0.269531f, 0.839844f, 0.039062f},
+ {0.292969f, 0.875000f, 0.960938f, 0.421875f}, {0.917969f, 0.175781f, 0.167969f, 0.867188f},
+ {0.714844f, 0.324219f, 0.753906f, 0.000000f}, {0.593750f, 0.582031f, 0.523438f, 0.671875f},
+ {0.421875f, 0.089844f, 0.117188f, 0.910156f}, {0.136719f, 0.652344f, 0.730469f, 0.402344f},
+ {0.750000f, 0.363281f, 0.335938f, 0.179688f}, {0.906250f, 0.824219f, 0.660156f, 0.550781f},
+ {0.199219f, 0.976562f, 0.128906f, 0.128906f}, {0.101562f, 0.125000f, 0.714844f, 0.664062f},
+ {0.800781f, 0.378906f, 0.257812f, 0.296875f}, {0.515625f, 0.890625f, 0.027344f, 0.773438f},
+ {0.414062f, 0.605469f, 0.082031f, 0.351562f}, {0.070312f, 0.765625f, 0.804688f, 0.585938f},
+ {0.187500f, 0.433594f, 0.910156f, 0.968750f}, {0.796875f, 0.031250f, 0.468750f, 0.726562f},
+ {0.457031f, 0.589844f, 0.156250f, 0.410156f}, {0.160156f, 0.312500f, 0.257812f, 0.949219f},
+ {0.718750f, 0.785156f, 0.027344f, 0.363281f}, {0.773438f, 0.210938f, 0.554688f, 0.863281f},
+ {0.476562f, 0.683594f, 0.335938f, 0.488281f}, {0.007812f, 0.765625f, 0.839844f, 0.769531f},
+ {0.707031f, 0.859375f, 0.488281f, 0.605469f}, {0.445312f, 0.406250f, 0.230469f, 0.082031f},
+ {0.566406f, 0.675781f, 0.746094f, 0.464844f}, {0.757812f, 0.582031f, 0.957031f, 0.023438f},
+ {0.925781f, 0.843750f, 0.066406f, 0.183594f}, {0.281250f, 0.367188f, 0.429688f, 0.976562f},
+ {0.125000f, 0.957031f, 0.644531f, 0.324219f}, {0.421875f, 0.746094f, 0.757812f, 0.214844f},
+ {0.675781f, 0.410156f, 0.976562f, 0.933594f}, {0.074219f, 0.914062f, 0.851562f, 0.558594f},
+ {0.617188f, 0.070312f, 0.667969f, 0.238281f}, {0.910156f, 0.457031f, 0.246094f, 0.742188f},
+ {0.285156f, 0.335938f, 0.824219f, 0.636719f}, {0.722656f, 0.832031f, 0.007812f, 0.828125f},
+ {0.816406f, 0.949219f, 0.289062f, 0.273438f}, {0.925781f, 0.152344f, 0.148438f, 0.675781f},
+ {0.085938f, 0.359375f, 0.789062f, 0.187500f}, {0.277344f, 0.640625f, 0.585938f, 0.507812f},
+ {0.164062f, 0.867188f, 0.105469f, 0.640625f}, {0.457031f, 0.570312f, 0.183594f, 0.050781f},
+ {0.789062f, 0.675781f, 0.371094f, 0.203125f}, {0.050781f, 0.164062f, 0.675781f, 0.996094f},
+ {0.726562f, 0.718750f, 0.152344f, 0.316406f}, {0.992188f, 0.210938f, 0.578125f, 0.066406f},
+ {0.464844f, 0.894531f, 0.386719f, 0.242188f}, {0.792969f, 0.500000f, 0.203125f, 0.140625f},
+ {0.925781f, 0.687500f, 0.527344f, 0.414062f}, {0.644531f, 0.062500f, 0.132812f, 0.824219f},
+ {0.289062f, 0.847656f, 0.234375f, 0.492188f}, {0.390625f, 0.570312f, 0.054688f, 0.394531f},
+ {0.554688f, 0.042969f, 0.546875f, 0.890625f}, {0.917969f, 0.796875f, 0.695312f, 0.589844f},
+ {0.203125f, 0.207031f, 0.839844f, 0.273438f}, {0.773438f, 0.484375f, 0.355469f, 0.960938f},
+ {0.699219f, 0.035156f, 0.593750f, 0.152344f}, {0.171875f, 0.410156f, 0.218750f, 0.050781f},
+ {0.289062f, 0.824219f, 0.921875f, 0.406250f}, {0.851562f, 0.078125f, 0.765625f, 0.261719f},
+ {0.781250f, 0.703125f, 0.066406f, 0.457031f}, {0.105469f, 0.000000f, 0.460938f, 0.546875f},
+ {0.695312f, 0.140625f, 0.734375f, 0.792969f}, {0.187500f, 0.660156f, 0.515625f, 0.632812f},
+ {0.636719f, 0.433594f, 0.085938f, 0.257812f}, {0.402344f, 0.500000f, 0.425781f, 0.562500f},
+ {0.003906f, 0.019531f, 0.890625f, 0.214844f}, {0.878906f, 0.953125f, 0.816406f, 0.156250f},
+ {0.503906f, 0.847656f, 0.058594f, 0.835938f}, {0.062500f, 0.746094f, 0.617188f, 0.738281f},
+ {0.839844f, 0.058594f, 0.902344f, 0.312500f}, {0.691406f, 0.171875f, 0.496094f, 0.640625f},
+ {0.390625f, 0.417969f, 0.378906f, 0.433594f}, {0.593750f, 0.742188f, 0.578125f, 0.945312f},
+ {0.734375f, 0.484375f, 0.917969f, 0.722656f}, {0.316406f, 0.289062f, 0.667969f, 0.113281f},
+ {0.675781f, 0.164062f, 0.429688f, 0.460938f}, {0.972656f, 0.984375f, 0.371094f, 0.628906f},
+ {0.628906f, 0.257812f, 0.218750f, 0.015625f}, {0.242188f, 0.656250f, 0.773438f, 0.320312f},
+ {0.589844f, 0.957031f, 0.984375f, 0.777344f}, {0.957031f, 0.492188f, 0.402344f, 0.550781f},
+ {0.359375f, 0.144531f, 0.726562f, 0.105469f}, {0.859375f, 0.425781f, 0.203125f, 0.582031f},
+ {0.113281f, 0.921875f, 0.128906f, 0.261719f}, {0.933594f, 0.253906f, 0.628906f, 0.144531f},
+ {0.812500f, 0.570312f, 0.992188f, 0.890625f}, {0.148438f, 0.179688f, 0.093750f, 0.308594f},
+ {0.894531f, 0.734375f, 0.160156f, 0.734375f}, {0.339844f, 0.269531f, 0.343750f, 0.628906f},
+ {0.621094f, 0.089844f, 0.500000f, 0.394531f}, {0.523438f, 0.644531f, 0.906250f, 0.773438f},
+ {0.796875f, 0.507812f, 0.203125f, 0.480469f}, {0.582031f, 0.042969f, 0.367188f, 0.710938f},
+};
+
+#endif /* __EEVEE_LUT_H__ */
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
new file mode 100644
index 00000000000..6736d4c4110
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -0,0 +1,1811 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_materials.c
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_alloca.h"
+#include "BLI_rand.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_particle.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_studiolight.h"
+
+#include "DNA_world_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_view3d_types.h"
+
+#include "GPU_material.h"
+
+#include "eevee_engine.h"
+#include "eevee_lut.h"
+#include "eevee_private.h"
+
+/* *********** STATIC *********** */
+static struct {
+ char *frag_shader_lib;
+ char *vert_shader_str;
+ char *volume_shader_lib;
+
+ struct GPUShader *default_prepass_sh;
+ struct GPUShader *default_prepass_clip_sh;
+ struct GPUShader *default_hair_prepass_sh;
+ struct GPUShader *default_hair_prepass_clip_sh;
+ struct GPUShader *default_lit[VAR_MAT_MAX];
+ struct GPUShader *default_background;
+ struct GPUShader *update_noise_sh;
+
+ /* 64*64 array texture containing all LUTs and other utilitarian arrays.
+ * Packing enables us to same precious textures slots. */
+ struct GPUTexture *util_tex;
+ struct GPUTexture *noise_tex;
+
+ struct GPUUniformBuffer *dummy_sss_profile;
+
+ uint sss_count;
+
+ float alpha_hash_offset;
+ float alpha_hash_scale;
+ float noise_offsets[3];
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_lamps_lib_glsl[];
+extern char datatoc_lightprobe_lib_glsl[];
+extern char datatoc_ambient_occlusion_lib_glsl[];
+extern char datatoc_prepass_frag_glsl[];
+extern char datatoc_prepass_vert_glsl[];
+extern char datatoc_default_frag_glsl[];
+extern char datatoc_default_world_frag_glsl[];
+extern char datatoc_ltc_lib_glsl[];
+extern char datatoc_bsdf_lut_frag_glsl[];
+extern char datatoc_btdf_lut_frag_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_common_hair_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_irradiance_lib_glsl[];
+extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_lit_surface_frag_glsl[];
+extern char datatoc_lit_surface_vert_glsl[];
+extern char datatoc_raytrace_lib_glsl[];
+extern char datatoc_ssr_lib_glsl[];
+extern char datatoc_shadow_vert_glsl[];
+extern char datatoc_lightprobe_geom_glsl[];
+extern char datatoc_lightprobe_vert_glsl[];
+extern char datatoc_background_vert_glsl[];
+extern char datatoc_update_noise_frag_glsl[];
+extern char datatoc_volumetric_vert_glsl[];
+extern char datatoc_volumetric_geom_glsl[];
+extern char datatoc_volumetric_frag_glsl[];
+extern char datatoc_volumetric_lib_glsl[];
+
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+
+extern Material defmaterial;
+extern GlobalsUboStorage ts;
+
+/* *********** FUNCTIONS *********** */
+
+#if 0 /* Used only to generate the LUT values */
+static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h))
+{
+ struct GPUTexture *tex;
+ struct GPUFrameBuffer *fb = NULL;
+ static float samples_len = 8192.0f;
+ static float inv_samples_len = 1.0f / 8192.0f;
+
+ char *lib_str = BLI_string_joinN(
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl);
+
+ struct GPUShader *sh = DRW_shader_create_with_lib(
+ datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, datatoc_bsdf_lut_frag_glsl, lib_str,
+ "#define HAMMERSLEY_SIZE 8192\n"
+ "#define BRDF_LUT_SIZE 64\n"
+ "#define NOISE_SIZE 64\n");
+
+ DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+ DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+
+ float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut");
+
+ tex = DRW_texture_create_2D(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels);
+
+ DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER};
+ GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
+
+ GPU_framebuffer_bind(fb);
+ DRW_draw_pass(pass);
+
+ float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut");
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, data);
+
+ printf("{");
+ for (int i = 0; i < w*h * 3; i+=3) {
+ printf("%ff, %ff, ", data[i], data[i+1]); i+=3;
+ printf("%ff, %ff, ", data[i], data[i+1]); i+=3;
+ printf("%ff, %ff, ", data[i], data[i+1]); i+=3;
+ printf("%ff, %ff, \n", data[i], data[i+1]);
+ }
+ printf("}");
+
+ MEM_freeN(texels);
+ MEM_freeN(data);
+
+ return tex;
+}
+
+static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h)
+{
+ struct GPUTexture *tex;
+ struct GPUTexture *hammersley = create_hammersley_sample_texture(8192);
+ struct GPUFrameBuffer *fb = NULL;
+ static float samples_len = 8192.0f;
+ static float a2 = 0.0f;
+ static float inv_samples_len = 1.0f / 8192.0f;
+
+ char *frag_str = BLI_string_joinN(
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_btdf_lut_frag_glsl);
+
+ struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str,
+ "#define HAMMERSLEY_SIZE 8192\n"
+ "#define BRDF_LUT_SIZE 64\n"
+ "#define NOISE_SIZE 64\n"
+ "#define LUT_SIZE 64\n");
+
+ MEM_freeN(frag_str);
+
+ DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_float(grp, "a2", &a2, 1);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley);
+ DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+
+ float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut");
+
+ tex = DRW_texture_create_2D(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels);
+
+ DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER};
+ GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
+
+ GPU_framebuffer_bind(fb);
+
+ float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut");
+
+ float inc = 1.0f / 31.0f;
+ float roughness = 1e-8f - inc;
+ FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w");
+ fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n");
+ do {
+ roughness += inc;
+ CLAMP(roughness, 1e-4f, 1.0f);
+ a2 = powf(roughness, 4.0f);
+ DRW_draw_pass(pass);
+
+ GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data);
+
+#if 1
+ fprintf(f, "\t{\n\t\t");
+ for (int i = 0; i < w*h * 3; i+=3) {
+ fprintf(f, "%ff,", data[i]);
+ if (((i/3)+1) % 12 == 0) fprintf(f, "\n\t\t");
+ else fprintf(f, " ");
+ }
+ fprintf(f, "\n\t},\n");
+#else
+ for (int i = 0; i < w*h * 3; i+=3) {
+ if (data[i] < 0.01) printf(" ");
+ else if (data[i] < 0.3) printf(".");
+ else if (data[i] < 0.6) printf("+");
+ else if (data[i] < 0.9) printf("%%");
+ else printf("#");
+ if ((i/3+1) % 64 == 0) printf("\n");
+ }
+#endif
+
+ } while (roughness < 1.0f);
+ fprintf(f, "\n};\n");
+
+ fclose(f);
+
+ MEM_freeN(texels);
+ MEM_freeN(data);
+
+ return tex;
+}
+#endif
+/* XXX TODO define all shared resources in a shared place without duplication */
+struct GPUTexture *EEVEE_materials_get_util_tex(void)
+{
+ return e_data.util_tex;
+}
+
+static int eevee_material_shadow_option(int shadow_method)
+{
+ switch (shadow_method) {
+ case SHADOW_ESM: return VAR_MAT_ESM;
+ case SHADOW_VSM: return VAR_MAT_VSM;
+ default:
+ BLI_assert(!"Incorrect Shadow Method");
+ break;
+ }
+
+ return 0;
+}
+
+static char *eevee_get_defines(int options)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_appendf(ds, SHADER_DEFINES);
+
+ if ((options & VAR_MAT_MESH) != 0) {
+ BLI_dynstr_appendf(ds, "#define MESH_SHADER\n");
+ }
+ if ((options & VAR_MAT_HAIR) != 0) {
+ BLI_dynstr_appendf(ds, "#define HAIR_SHADER\n");
+ }
+ if ((options & VAR_MAT_PROBE) != 0) {
+ BLI_dynstr_appendf(ds, "#define PROBE_CAPTURE\n");
+ }
+ if ((options & VAR_MAT_FLAT) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_FLAT_NORMAL\n");
+ }
+ if ((options & VAR_MAT_CLIP) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_ALPHA_CLIP\n");
+ }
+ if ((options & VAR_MAT_SHADOW) != 0) {
+ BLI_dynstr_appendf(ds, "#define SHADOW_SHADER\n");
+ }
+ if ((options & VAR_MAT_HASH) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_ALPHA_HASH\n");
+ }
+ if ((options & VAR_MAT_BLEND) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_ALPHA_BLEND\n");
+ }
+ if ((options & VAR_MAT_MULT) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_MULTIPLY\n");
+ }
+ if ((options & VAR_MAT_REFRACT) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_REFRACTION\n");
+ }
+ if ((options & VAR_MAT_SSS) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_SSS\n");
+ }
+ if ((options & VAR_MAT_SSSALBED) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_SSS_ALBEDO\n");
+ }
+ if ((options & VAR_MAT_TRANSLUC) != 0) {
+ BLI_dynstr_appendf(ds, "#define USE_TRANSLUCENCY\n");
+ }
+ if ((options & VAR_MAT_VSM) != 0) {
+ BLI_dynstr_appendf(ds, "#define SHADOW_VSM\n");
+ }
+ if ((options & VAR_MAT_ESM) != 0) {
+ BLI_dynstr_appendf(ds, "#define SHADOW_ESM\n");
+ }
+ if (((options & VAR_MAT_VOLUME) != 0) && ((options & VAR_MAT_BLEND) != 0)) {
+ BLI_dynstr_appendf(ds, "#define USE_ALPHA_BLEND_VOLUMETRICS\n");
+ }
+ if ((options & VAR_MAT_LOOKDEV) != 0) {
+ BLI_dynstr_appendf(ds, "#define LOOKDEV\n");
+ }
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return str;
+}
+
+static char *eevee_get_volume_defines(int options)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_appendf(ds, SHADER_DEFINES);
+ BLI_dynstr_appendf(ds, "#define VOLUMETRICS\n");
+
+ if ((options & VAR_MAT_VOLUME) != 0) {
+ BLI_dynstr_appendf(ds, "#define MESH_SHADER\n");
+ }
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return str;
+}
+
+/**
+ * ssr_id can be null to disable ssr contribution.
+ **/
+static void add_standard_uniforms(
+ DRWShadingGroup *shgrp, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ int *ssr_id, float *refract_depth,
+ bool use_diffuse, bool use_glossy, bool use_refract,
+ bool use_ssrefraction, bool use_alpha_blend)
+{
+ LightCache *lcache = vedata->stl->g_data->light_cache;
+
+ if (ssr_id == NULL) {
+ static int no_ssr = -1.0f;
+ ssr_id = &no_ssr;
+ }
+
+ DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo);
+
+ if (use_diffuse || use_glossy || use_refract) {
+ DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
+ DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool);
+ DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
+ DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer);
+ }
+ if ((use_diffuse || use_glossy) && !use_ssrefraction) {
+ if ((vedata->stl->effects->enabled_effects & EFFECT_GTAO) != 0) {
+ DRW_shgroup_uniform_texture_ref(shgrp, "horizonBuffer", &vedata->stl->effects->gtao_horizons);
+ }
+ else {
+ /* Use maxzbuffer as fallback to avoid sampling problem on certain platform, see: T52593 */
+ DRW_shgroup_uniform_texture_ref(shgrp, "horizonBuffer", &vedata->txl->maxzbuffer);
+ }
+ }
+ if (use_diffuse) {
+ DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex);
+ }
+ if (use_glossy || use_refract) {
+ DRW_shgroup_uniform_texture_ref(shgrp, "probeCubes", &lcache->cube_tx.tex);
+ }
+ if (use_glossy) {
+ DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &vedata->txl->planar_pool);
+ DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
+ }
+ if (use_refract) {
+ DRW_shgroup_uniform_float_copy(shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0 );
+ if (use_ssrefraction) {
+ DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color);
+ }
+ }
+
+ if ((vedata->stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0 &&
+ use_alpha_blend)
+ {
+ /* Do not use history buffers as they already have been swapped */
+ DRW_shgroup_uniform_texture_ref(shgrp, "inScattering", &vedata->txl->volume_scatter);
+ DRW_shgroup_uniform_texture_ref(shgrp, "inTransmittance", &vedata->txl->volume_transmittance);
+ }
+}
+
+static void create_default_shader(int options)
+{
+ char *frag_str = BLI_string_joinN(
+ e_data.frag_shader_lib,
+ datatoc_default_frag_glsl);
+
+ char *defines = eevee_get_defines(options);
+
+ e_data.default_lit[options] = DRW_shader_create(e_data.vert_shader_str, NULL, frag_str, defines);
+
+ MEM_freeN(defines);
+ MEM_freeN(frag_str);
+}
+
+static void eevee_init_dummys(void)
+{
+ e_data.dummy_sss_profile = GPU_material_create_sss_profile_ubo();
+}
+
+static void eevee_init_noise_texture(void)
+{
+ e_data.noise_tex = DRW_texture_create_2D(64, 64, GPU_RGBA16F, 0, (float *)blue_noise);
+}
+
+static void eevee_init_util_texture(void)
+{
+ const int layers = 3 + 16;
+ float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * 64 * 64 * layers, "utils texels");
+ float (*texels_layer)[4] = texels;
+
+ /* Copy ltc_mat_ggx into 1st layer */
+ memcpy(texels_layer, ltc_mat_ggx, sizeof(float[4]) * 64 * 64);
+ texels_layer += 64 * 64;
+
+ /* Copy bsdf_split_sum_ggx into 2nd layer red and green channels.
+ Copy ltc_mag_ggx into 2nd layer blue channel. */
+ for (int i = 0; i < 64 * 64; i++) {
+ texels_layer[i][0] = bsdf_split_sum_ggx[i * 2 + 0];
+ texels_layer[i][1] = bsdf_split_sum_ggx[i * 2 + 1];
+ texels_layer[i][2] = ltc_mag_ggx[i];
+ texels_layer[i][3] = ltc_disk_integral[i];
+ }
+ texels_layer += 64 * 64;
+
+ /* Copy blue noise in 3rd layer */
+ for (int i = 0; i < 64 * 64; i++) {
+ texels_layer[i][0] = blue_noise[i][0];
+ texels_layer[i][1] = blue_noise[i][2];
+ texels_layer[i][2] = cosf(blue_noise[i][1] * 2.0f * M_PI);
+ texels_layer[i][3] = sinf(blue_noise[i][1] * 2.0f * M_PI);
+ }
+ texels_layer += 64 * 64;
+
+ /* Copy Refraction GGX LUT in layer 4 - 20 */
+ for (int j = 0; j < 16; ++j) {
+ for (int i = 0; i < 64 * 64; i++) {
+ texels_layer[i][0] = btdf_split_sum_ggx[j * 2][i];
+ texels_layer[i][1] = btdf_split_sum_ggx[j * 2][i];
+ texels_layer[i][2] = btdf_split_sum_ggx[j * 2][i];
+ texels_layer[i][3] = btdf_split_sum_ggx[j * 2][i];
+ }
+ texels_layer += 64 * 64;
+ }
+
+ e_data.util_tex = DRW_texture_create_2D_array(
+ 64, 64, layers, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_WRAP, (float *)texels);
+
+ MEM_freeN(texels);
+}
+
+void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3])
+{
+ e_data.noise_offsets[0] = offsets[0];
+ e_data.noise_offsets[1] = offsets[1];
+ e_data.noise_offsets[2] = offsets[2];
+
+ /* Attach & detach because we don't currently support multiple FB per texture,
+ * and this would be the case for multiple viewport. */
+ GPU_framebuffer_bind(fbl->update_noise_fb);
+ DRW_draw_pass(psl->update_noise_pass);
+}
+
+static void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4])
+{
+ /* view vectors for the corners of the view frustum.
+ * Can be used to recreate the world space position easily */
+ float view_vecs[4][4] = {
+ {-1.0f, -1.0f, -1.0f, 1.0f},
+ { 1.0f, -1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f, 1.0f},
+ {-1.0f, -1.0f, 1.0f, 1.0f}
+ };
+
+ /* convert the view vectors to view space */
+ const bool is_persp = (winmat[3][3] == 0.0f);
+ for (int i = 0; i < 4; i++) {
+ mul_project_m4_v3(invproj, view_vecs[i]);
+ /* normalized trick see:
+ * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ if (is_persp) {
+ /* Divide XY by Z. */
+ mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]);
+ }
+ }
+
+ /**
+ * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and
+ * view_vecs[1] is the vector going from the near-bottom-left corner to
+ * the far-top-right corner.
+ * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner
+ * when Z = 1, and top-left corner if Z = 1.
+ * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed)
+ * distance from the near plane to the far clip plane.
+ **/
+ copy_v4_v4(r_viewvecs[0], view_vecs[0]);
+
+ /* we need to store the differences */
+ r_viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0];
+ r_viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1];
+ r_viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
+}
+
+void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl)
+{
+ if (!e_data.frag_shader_lib) {
+ /* Shaders */
+ e_data.frag_shader_lib = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_raytrace_lib_glsl,
+ datatoc_ssr_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_ltc_lib_glsl,
+ datatoc_lamps_lib_glsl,
+ /* Add one for each Closure */
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_volumetric_lib_glsl);
+
+ e_data.volume_shader_lib = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_ltc_lib_glsl,
+ datatoc_lamps_lib_glsl,
+ datatoc_volumetric_lib_glsl,
+ datatoc_volumetric_frag_glsl);
+
+ e_data.vert_shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_hair_lib_glsl,
+ datatoc_lit_surface_vert_glsl);
+
+ e_data.default_background = DRW_shader_create(
+ datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl,
+ NULL);
+
+ e_data.default_prepass_sh = DRW_shader_create(
+ datatoc_prepass_vert_glsl, NULL, datatoc_prepass_frag_glsl,
+ NULL);
+
+ e_data.default_prepass_clip_sh = DRW_shader_create(
+ datatoc_prepass_vert_glsl, NULL, datatoc_prepass_frag_glsl,
+ "#define CLIP_PLANES\n");
+
+ char *vert_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_hair_lib_glsl,
+ datatoc_prepass_vert_glsl);
+
+ e_data.default_hair_prepass_sh = DRW_shader_create(
+ vert_str, NULL, datatoc_prepass_frag_glsl,
+ "#define HAIR_SHADER\n");
+
+ e_data.default_hair_prepass_clip_sh = DRW_shader_create(
+ vert_str, NULL, datatoc_prepass_frag_glsl,
+ "#define HAIR_SHADER\n"
+ "#define CLIP_PLANES\n");
+
+ MEM_freeN(vert_str);
+
+ e_data.update_noise_sh = DRW_shader_create_fullscreen(
+ datatoc_update_noise_frag_glsl, NULL);
+
+ eevee_init_util_texture();
+ eevee_init_noise_texture();
+ eevee_init_dummys();
+ }
+
+ if (!DRW_state_is_image_render() &&
+ ((stl->effects->enabled_effects & EFFECT_TAA) == 0))
+ {
+ e_data.alpha_hash_offset = 0.0f;
+ e_data.alpha_hash_scale = 1.0f;
+ }
+ else {
+ double r;
+ BLI_halton_1D(5, 0.0, stl->effects->taa_current_sample - 1, &r);
+ e_data.alpha_hash_offset = (float)r;
+ e_data.alpha_hash_scale = 0.01f;
+ }
+
+ {
+ /* Update view_vecs */
+ float invproj[4][4], winmat[4][4];
+ DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_get(invproj, DRW_MAT_WININV);
+
+ EEVEE_update_viewvecs(invproj, winmat, sldata->common_data.view_vecs);
+ }
+
+ {
+ /* Update noise Framebuffer. */
+ GPU_framebuffer_ensure_config(&fbl->update_noise_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE_LAYER(e_data.util_tex, 2)
+ });
+ }
+}
+
+struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, World *wo)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ const int options = VAR_WORLD_PROBE;
+
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, false);
+ if (mat != NULL) {
+ return mat;
+ }
+ return DRW_shader_create_from_world(
+ scene, wo, engine, options,
+ datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib,
+ SHADER_DEFINES "#define PROBE_CAPTURE\n", false);
+}
+
+struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, World *wo)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_WORLD_BACKGROUND;
+
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true);
+ if (mat != NULL) {
+ return mat;
+ }
+ return DRW_shader_create_from_world(
+ scene, wo, engine, options,
+ datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib,
+ SHADER_DEFINES "#define WORLD_BACKGROUND\n", true);
+}
+
+struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *wo)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_WORLD_VOLUME;
+
+ GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true);
+ if (mat != NULL) {
+ return mat;
+ }
+
+ char *defines = eevee_get_volume_defines(options);
+
+ mat = DRW_shader_create_from_world(
+ scene, wo, engine, options,
+ datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib,
+ defines, true);
+
+ MEM_freeN(defines);
+
+ return mat;
+}
+
+struct GPUMaterial *EEVEE_material_mesh_get(
+ struct Scene *scene, Material *ma, EEVEE_Data *vedata,
+ bool use_blend, bool use_multiply, bool use_refract, bool use_sss, bool use_translucency, int shadow_method)
+{
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_MAT_MESH;
+
+ if (use_blend) options |= VAR_MAT_BLEND;
+ if (use_multiply) options |= VAR_MAT_MULT;
+ if (use_refract) options |= VAR_MAT_REFRACT;
+ if (use_sss) options |= VAR_MAT_SSS;
+ if (use_sss && effects->sss_separate_albedo) options |= VAR_MAT_SSSALBED;
+ if (use_translucency) options |= VAR_MAT_TRANSLUC;
+ if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME;
+
+ options |= eevee_material_shadow_option(shadow_method);
+
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
+ if (mat) {
+ return mat;
+ }
+
+ char *defines = eevee_get_defines(options);
+
+ mat = DRW_shader_create_from_material(
+ scene, ma, engine, options,
+ e_data.vert_shader_str, NULL, e_data.frag_shader_lib,
+ defines, true);
+
+ MEM_freeN(defines);
+
+ return mat;
+}
+
+struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_MAT_VOLUME;
+
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
+ if (mat != NULL) {
+ return mat;
+ }
+
+ char *defines = eevee_get_volume_defines(options);
+
+ mat = DRW_shader_create_from_material(
+ scene, ma, engine, options,
+ datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib,
+ defines, true);
+
+ MEM_freeN(defines);
+
+ return mat;
+}
+
+struct GPUMaterial *EEVEE_material_mesh_depth_get(
+ struct Scene *scene, Material *ma,
+ bool use_hashed_alpha, bool is_shadow)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_MAT_MESH;
+
+ if (use_hashed_alpha) {
+ options |= VAR_MAT_HASH;
+ }
+ else {
+ options |= VAR_MAT_CLIP;
+ }
+
+ if (is_shadow)
+ options |= VAR_MAT_SHADOW;
+
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
+ if (mat) {
+ return mat;
+ }
+
+ char *defines = eevee_get_defines(options);
+
+ char *frag_str = BLI_string_joinN(
+ e_data.frag_shader_lib,
+ datatoc_prepass_frag_glsl);
+
+ mat = DRW_shader_create_from_material(
+ scene, ma, engine, options,
+ (is_shadow) ? datatoc_shadow_vert_glsl : e_data.vert_shader_str,
+ NULL,
+ frag_str,
+ defines,
+ true);
+
+ MEM_freeN(frag_str);
+ MEM_freeN(defines);
+
+ return mat;
+}
+
+struct GPUMaterial *EEVEE_material_hair_get(
+ struct Scene *scene, Material *ma, int shadow_method)
+{
+ const void *engine = &DRW_engine_viewport_eevee_type;
+ int options = VAR_MAT_MESH | VAR_MAT_HAIR;
+
+ options |= eevee_material_shadow_option(shadow_method);
+
+ GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
+ if (mat) {
+ return mat;
+ }
+
+ char *defines = eevee_get_defines(options);
+
+ mat = DRW_shader_create_from_material(
+ scene, ma, engine, options,
+ e_data.vert_shader_str, NULL, e_data.frag_shader_lib,
+ defines, true);
+
+ MEM_freeN(defines);
+
+ return mat;
+}
+
+/**
+ * Create a default shading group inside the given pass.
+ **/
+static struct DRWShadingGroup *EEVEE_default_shading_group_create(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass,
+ bool is_hair, bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method)
+{
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
+ static int ssr_id;
+ ssr_id = (use_ssr) ? 1 : -1;
+ int options = VAR_MAT_MESH;
+
+ if (is_hair) options |= VAR_MAT_HAIR;
+ if (is_flat_normal) options |= VAR_MAT_FLAT;
+ if (use_blend) options |= VAR_MAT_BLEND;
+ if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME;
+
+ options |= eevee_material_shadow_option(shadow_method);
+
+ if (e_data.default_lit[options] == NULL) {
+ create_default_shader(options);
+ }
+
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass);
+ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, use_blend);
+
+ return shgrp;
+}
+
+/**
+ * Create a default shading group inside the default pass without standard uniforms.
+ **/
+static struct DRWShadingGroup *EEVEE_default_shading_group_get(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ Object *ob, ParticleSystem *psys, ModifierData *md,
+ bool is_hair, bool is_flat_normal, bool use_ssr, int shadow_method)
+{
+ static int ssr_id;
+ ssr_id = (use_ssr) ? 1 : -1;
+ int options = VAR_MAT_MESH;
+
+ BLI_assert(!is_hair || (ob && psys && md));
+
+ if (is_hair) options |= VAR_MAT_HAIR;
+ if (is_flat_normal) options |= VAR_MAT_FLAT;
+
+ options |= eevee_material_shadow_option(shadow_method);
+
+ if (e_data.default_lit[options] == NULL) {
+ create_default_shader(options);
+ }
+
+ if (vedata->psl->default_pass[options] == NULL) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
+ vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state);
+
+ /* XXX / WATCH: This creates non persistent binds for the ubos and textures.
+ * But it's currently OK because the following shgroups does not add any bind.
+ * EDIT: THIS IS NOT THE CASE FOR HAIRS !!! DUMMY!!! */
+ if (!is_hair) {
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
+ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false);
+ }
+ }
+
+ if (is_hair) {
+ DRWShadingGroup *shgrp = DRW_shgroup_hair_create(ob, psys, md,
+ vedata->psl->default_pass[options],
+ e_data.default_lit[options]);
+ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false);
+ return shgrp;
+ }
+ else {
+ return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
+ }
+}
+
+/**
+ * Create a default shading group inside the lookdev pass without standard uniforms.
+ **/
+static struct DRWShadingGroup *EEVEE_lookdev_shading_group_get(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ bool use_ssr, int shadow_method)
+{
+ static int ssr_id;
+ ssr_id = (use_ssr) ? 1 : -1;
+ int options = VAR_MAT_MESH | VAR_MAT_LOOKDEV;
+
+ options |= eevee_material_shadow_option(shadow_method);
+
+ if (e_data.default_lit[options] == NULL) {
+ create_default_shader(options);
+ }
+
+ if (vedata->psl->lookdev_pass == NULL) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_CULL_BACK;
+ vedata->psl->lookdev_pass = DRW_pass_create("LookDev Pass", state);
+
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->lookdev_pass);
+ /* XXX / WATCH: This creates non persistent binds for the ubos and textures.
+ * But it's currently OK because the following shgroups does not add any bind. */
+ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false);
+ }
+
+ return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->lookdev_pass);
+}
+void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+
+ /* Create Material Ghash */
+ {
+ stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash");
+ }
+
+ {
+ psl->background_pass = DRW_pass_create("Background Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRWShadingGroup *grp = NULL;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ World *wo = scene->world;
+
+ float *col = ts.colorBackground;
+
+ /* LookDev */
+ EEVEE_lookdev_cache_init(vedata, &grp, psl->background_pass, wo, NULL);
+ /* END */
+
+ if (!grp && wo) {
+ col = &wo->horr;
+
+ if (wo->use_nodes && wo->nodetree) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ static float compile_col[3] = {0.5f, 0.5f, 0.5f};
+ struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo);
+
+ switch (GPU_material_status(gpumat)) {
+ case GPU_MAT_SUCCESS:
+ grp = DRW_shgroup_material_create(gpumat, psl->background_pass);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ /* TODO (fclem): remove those (need to clean the GLSL files). */
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ break;
+ case GPU_MAT_QUEUED:
+ /* TODO Bypass probe compilation. */
+ col = compile_col;
+ break;
+ case GPU_MAT_FAILED:
+ default:
+ col = error_col;
+ break;
+ }
+ }
+ }
+
+ /* Fallback if shader fails or if not using nodetree. */
+ if (grp == NULL) {
+ grp = DRW_shgroup_create(e_data.default_background, psl->background_pass);
+ DRW_shgroup_uniform_vec3(grp, "color", col, 1);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE;
+ psl->depth_pass = DRW_pass_create("Depth Pass", state);
+ stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass);
+
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull", state);
+ stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass_cull);
+
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
+ psl->depth_pass_clip = DRW_pass_create("Depth Pass Clip", state);
+ stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip);
+ DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip, "clip_block", sldata->clip_ubo);
+
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK;
+ psl->depth_pass_clip_cull = DRW_pass_create("Depth Pass Cull Clip", state);
+ stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(
+ e_data.default_prepass_clip_sh, psl->depth_pass_clip_cull);
+ DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
+ psl->material_pass = DRW_pass_create("Material Shader Pass", state);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE;
+ psl->refract_depth_pass = DRW_pass_create("Refract Depth Pass", state);
+ stl->g_data->refract_depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->refract_depth_pass);
+
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ psl->refract_depth_pass_cull = DRW_pass_create("Refract Depth Pass Cull", state);
+ stl->g_data->refract_depth_shgrp_cull = DRW_shgroup_create(
+ e_data.default_prepass_sh, psl->refract_depth_pass_cull);
+
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
+ psl->refract_depth_pass_clip = DRW_pass_create("Refract Depth Pass Clip", state);
+ stl->g_data->refract_depth_shgrp_clip = DRW_shgroup_create(
+ e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip);
+ DRW_shgroup_uniform_block(stl->g_data->refract_depth_shgrp_clip, "clip_block", sldata->clip_ubo);
+
+ state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK;
+ psl->refract_depth_pass_clip_cull = DRW_pass_create("Refract Depth Pass Cull Clip", state);
+ stl->g_data->refract_depth_shgrp_clip_cull = DRW_shgroup_create(
+ e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip_cull);
+ DRW_shgroup_uniform_block(stl->g_data->refract_depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo);
+ }
+
+ {
+ DRWState state = (
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES |
+ DRW_STATE_WIRE);
+ psl->refract_pass = DRW_pass_create("Opaque Refraction Pass", state);
+ }
+
+ {
+ DRWState state = (
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES |
+ DRW_STATE_WIRE | DRW_STATE_WRITE_STENCIL);
+ psl->sss_pass = DRW_pass_create("Subsurface Pass", state);
+ e_data.sss_count = 0;
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE;
+ psl->transparent_pass = DRW_pass_create("Material Transparent Pass", state);
+ }
+
+ {
+ psl->update_noise_pass = DRW_pass_create("Update Noise Pass", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.update_noise_sh, psl->update_noise_pass);
+ DRW_shgroup_uniform_texture(grp, "blueNoise", e_data.noise_tex);
+ DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+}
+
+#define ADD_SHGROUP_CALL(shgrp, ob, ma, geom, oedata) do { \
+ if (is_sculpt_mode_draw) { \
+ DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat); \
+ } \
+ else { \
+ if (oedata) { \
+ DRW_shgroup_call_object_add_with_callback(shgrp, geom, ob, ma, EEVEE_lightprobes_obj_visibility_cb, oedata); \
+ } \
+ else { \
+ DRW_shgroup_call_object_add_ex(shgrp, geom, ob, ma, false); \
+ } \
+ } \
+} while (0)
+
+#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, ma, geom, oedata) do { \
+ if (shgrp) { \
+ ADD_SHGROUP_CALL(shgrp, ob, ma, geom, oedata); \
+ } \
+} while (0)
+
+typedef struct EeveeMaterialShadingGroups {
+ struct DRWShadingGroup *shading_grp;
+ struct DRWShadingGroup *depth_grp;
+ struct DRWShadingGroup *depth_clip_grp;
+} EeveeMaterialShadingGroups;
+
+static void material_opaque(
+ Material *ma, GHash *material_hash, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ bool do_cull, bool use_flat_nor, struct GPUMaterial **gpumat, struct GPUMaterial **gpumat_depth,
+ struct DRWShadingGroup **shgrp, struct DRWShadingGroup **shgrp_depth, struct DRWShadingGroup **shgrp_depth_clip)
+{
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ bool use_diffuse, use_glossy, use_refract;
+
+ float *color_p = &ma->r;
+ float *metal_p = &ma->metallic;
+ float *spec_p = &ma->spec;
+ float *rough_p = &ma->roughness;
+
+ const bool use_gpumat = (ma->use_nodes && ma->nodetree);
+ const bool use_ssrefract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
+ ((effects->enabled_effects & EFFECT_REFRACT) != 0);
+ bool use_sss = ((effects->enabled_effects & EFFECT_SSS) != 0);
+ const bool use_translucency = use_sss && ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0);
+
+ EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma);
+
+ if (emsg) {
+ *shgrp = emsg->shading_grp;
+ *shgrp_depth = emsg->depth_grp;
+ *shgrp_depth_clip = emsg->depth_clip_grp;
+
+ /* This will have been created already, just perform a lookup. */
+ *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(
+ scene, ma, vedata, false, false, use_ssrefract, use_sss, use_translucency, linfo->shadow_method) : NULL;
+ *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
+ scene, ma, (ma->blend_method == MA_BM_HASHED), false) : NULL;
+ return;
+ }
+
+ if (use_gpumat) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ static float compile_col[3] = {0.5f, 0.5f, 0.5f};
+ static float half = 0.5f;
+
+ /* Shading */
+ *gpumat = EEVEE_material_mesh_get(
+ scene, ma, vedata, false, false, use_ssrefract,
+ use_sss, use_translucency, linfo->shadow_method);
+
+ GPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
+
+ /* Alpha CLipped : Discard pixel from depth pass, then
+ * fail the depth test for shading. */
+ if (ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED)) {
+ *gpumat_depth = EEVEE_material_mesh_depth_get(scene, ma, (ma->blend_method == MA_BM_HASHED), false);
+
+ GPUMaterialStatus status_mat_depth = GPU_material_status(*gpumat_depth);
+ if (status_mat_depth != GPU_MAT_SUCCESS) {
+ /* Mixing both flags. If depth shader fails, show it to the user by not using
+ * the surface shader. */
+ status_mat_surface = status_mat_depth;
+ }
+ else if (use_ssrefract) {
+ *shgrp_depth = DRW_shgroup_material_create(
+ *gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass);
+ *shgrp_depth_clip = DRW_shgroup_material_create(
+ *gpumat_depth, (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip);
+ }
+ else {
+ *shgrp_depth = DRW_shgroup_material_create(
+ *gpumat_depth, (do_cull) ? psl->depth_pass_cull : psl->depth_pass);
+ *shgrp_depth_clip = DRW_shgroup_material_create(
+ *gpumat_depth, (do_cull) ? psl->depth_pass_clip_cull : psl->depth_pass_clip);
+ }
+
+ if (*shgrp_depth != NULL) {
+ use_diffuse = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_DIFFUSE);
+ use_glossy = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_GLOSSY);
+ use_refract = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_REFRACT);
+
+ add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL,
+ use_diffuse, use_glossy, use_refract, false, false);
+ add_standard_uniforms(*shgrp_depth_clip, sldata, vedata, NULL, NULL,
+ use_diffuse, use_glossy, use_refract, false, false);
+
+ if (ma->blend_method == MA_BM_CLIP) {
+ DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1);
+ DRW_shgroup_uniform_float(*shgrp_depth_clip, "alphaThreshold", &ma->alpha_threshold, 1);
+ }
+ else if (ma->blend_method == MA_BM_HASHED) {
+ DRW_shgroup_uniform_float(*shgrp_depth, "hashAlphaOffset", &e_data.alpha_hash_offset, 1);
+ DRW_shgroup_uniform_float(*shgrp_depth_clip, "hashAlphaOffset", &e_data.alpha_hash_offset, 1);
+ DRW_shgroup_uniform_float_copy(*shgrp_depth, "hashAlphaScale", e_data.alpha_hash_scale);
+ DRW_shgroup_uniform_float_copy(*shgrp_depth_clip, "hashAlphaScale", e_data.alpha_hash_scale);
+ }
+ }
+ }
+
+ switch (status_mat_surface) {
+ case GPU_MAT_SUCCESS:
+ {
+ static int no_ssr = -1;
+ static int first_ssr = 1;
+ int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? &first_ssr : &no_ssr;
+ use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE);
+ use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY);
+ use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT);
+ use_sss = use_sss && GPU_material_flag_get(*gpumat, GPU_MATFLAG_SSS);
+
+ *shgrp = DRW_shgroup_material_create(
+ *gpumat,
+ (use_ssrefract) ? psl->refract_pass :
+ (use_sss) ? psl->sss_pass : psl->material_pass);
+
+ add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth,
+ use_diffuse, use_glossy, use_refract, use_ssrefract, false);
+
+ if (use_sss) {
+ struct GPUTexture *sss_tex_profile = NULL;
+ struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get(
+ *gpumat,
+ stl->effects->sss_sample_count,
+ &sss_tex_profile);
+
+ if (sss_profile) {
+ if (use_translucency) {
+ DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile);
+ }
+
+ /* Limit of 8 bit stencil buffer. ID 255 is refraction. */
+ if (e_data.sss_count < 254) {
+ DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1);
+ EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile);
+ e_data.sss_count++;
+ }
+ else {
+ /* TODO : display message. */
+ printf("Error: Too many different Subsurface shader in the scene.\n");
+ }
+ }
+ else {
+ if (use_translucency) {
+ /* NOTE: This is a nasty workaround, because the sss profile might not have been generated
+ * but the UBO is still declared in this case even if not used. But rendering without a
+ * bound UBO might result in crashes on certain platform. */
+ DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile);
+ }
+ }
+ }
+ else {
+ if (use_translucency) {
+ DRW_shgroup_uniform_block(*shgrp, "sssProfile", e_data.dummy_sss_profile);
+ }
+ }
+ break;
+ }
+ case GPU_MAT_QUEUED:
+ {
+ color_p = compile_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
+ case GPU_MAT_FAILED:
+ default:
+ color_p = error_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
+ }
+
+ /* Fallback to default shader */
+ if (*shgrp == NULL) {
+ bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0);
+ *shgrp = EEVEE_default_shading_group_get(sldata, vedata,
+ NULL, NULL, NULL,
+ false, use_flat_nor, use_ssr, linfo->shadow_method);
+ DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
+ DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
+ DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
+ DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1);
+ }
+
+ /* Fallback default depth prepass */
+ if (*shgrp_depth == NULL) {
+ if (use_ssrefract) {
+ *shgrp_depth = (do_cull) ? stl->g_data->refract_depth_shgrp_cull : stl->g_data->refract_depth_shgrp;
+ *shgrp_depth_clip = (do_cull) ? stl->g_data->refract_depth_shgrp_clip_cull : stl->g_data->refract_depth_shgrp_clip;
+ }
+ else {
+ *shgrp_depth = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
+ *shgrp_depth_clip = (do_cull) ? stl->g_data->depth_shgrp_clip_cull : stl->g_data->depth_shgrp_clip;
+ }
+ }
+
+ emsg = MEM_mallocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups");
+ emsg->shading_grp = *shgrp;
+ emsg->depth_grp = *shgrp_depth;
+ emsg->depth_clip_grp = *shgrp_depth_clip;
+ BLI_ghash_insert(material_hash, ma, emsg);
+}
+
+static void material_transparent(
+ Material *ma, EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
+ bool do_cull, bool use_flat_nor,
+ struct GPUMaterial **gpumat, struct DRWShadingGroup **shgrp, struct DRWShadingGroup **shgrp_depth)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+
+ const bool use_ssrefract = (
+ ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
+ ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0)
+ );
+ float *color_p = &ma->r;
+ float *metal_p = &ma->metallic;
+ float *spec_p = &ma->spec;
+ float *rough_p = &ma->roughness;
+
+ if (ma->use_nodes && ma->nodetree) {
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ static float compile_col[3] = {0.5f, 0.5f, 0.5f};
+ static float half = 0.5f;
+
+ /* Shading */
+ *gpumat = EEVEE_material_mesh_get(
+ scene, ma, vedata, true, (ma->blend_method == MA_BM_MULTIPLY), use_ssrefract,
+ false, false, linfo->shadow_method);
+
+ switch (GPU_material_status(*gpumat)) {
+ case GPU_MAT_SUCCESS:
+ {
+ static int ssr_id = -1; /* TODO transparent SSR */
+ bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0;
+
+ *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
+
+ bool use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE);
+ bool use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY);
+ bool use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT);
+
+ add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth,
+ use_diffuse, use_glossy, use_refract, use_ssrefract, use_blend);
+ break;
+ }
+ case GPU_MAT_QUEUED:
+ {
+ /* TODO Bypass probe compilation. */
+ color_p = compile_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
+ case GPU_MAT_FAILED:
+ default:
+ color_p = error_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
+ }
+
+ /* Fallback to default shader */
+ if (*shgrp == NULL) {
+ *shgrp = EEVEE_default_shading_group_create(
+ sldata, vedata, psl->transparent_pass,
+ false, use_flat_nor, true, false, linfo->shadow_method);
+ DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
+ DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
+ DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
+ DRW_shgroup_uniform_float(*shgrp, "roughness", rough_p, 1);
+ }
+
+ const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKSIDE) != 0);
+
+ DRWState all_state = (
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_CULL_BACK |
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
+ DRW_STATE_BLEND | DRW_STATE_ADDITIVE | DRW_STATE_MULTIPLY
+ );
+
+ DRWState cur_state = DRW_STATE_WRITE_COLOR;
+ cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
+ cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
+
+ switch (ma->blend_method) {
+ case MA_BM_ADD:
+ cur_state |= DRW_STATE_ADDITIVE;
+ break;
+ case MA_BM_MULTIPLY:
+ cur_state |= DRW_STATE_MULTIPLY;
+ break;
+ case MA_BM_BLEND:
+ cur_state |= DRW_STATE_BLEND;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ /* Disable other blend modes and use the one we want. */
+ DRW_shgroup_state_disable(*shgrp, all_state);
+ DRW_shgroup_state_enable(*shgrp, cur_state);
+
+ /* Depth prepass */
+ if (use_prepass) {
+ *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
+ DRW_shgroup_uniform_block(*shgrp_depth, "clip_block", sldata->clip_ubo);
+
+ cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
+
+ DRW_shgroup_state_disable(*shgrp_depth, all_state);
+ DRW_shgroup_state_enable(*shgrp_depth, cur_state);
+ }
+}
+
+void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ GHash *material_hash = stl->g_data->material_hash;
+
+ const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->flag2 & V3D_BACKFACE_CULLING));
+ const bool is_active = (ob == draw_ctx->obact);
+ const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0;
+#if 0
+ const bool is_sculpt_mode_draw = is_sculpt_mode && (draw_ctx->v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE) == 0;
+#else
+ /* For now just force fully shaded with eevee when supported. */
+ const bool is_sculpt_mode_draw =
+ is_sculpt_mode &&
+ ((ob->sculpt && ob->sculpt->pbvh) && (BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES));
+#endif
+ const bool use_hide = is_active && DRW_object_use_hide_faces(ob);
+ const bool is_default_mode_shader = is_sculpt_mode;
+
+ /* First get materials for this mesh. */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
+ const int materials_len = MAX2(1, (is_sculpt_mode_draw ? 1 : ob->totcol));
+
+ struct DRWShadingGroup **shgrp_array = BLI_array_alloca(shgrp_array, materials_len);
+ struct DRWShadingGroup **shgrp_depth_array = BLI_array_alloca(shgrp_depth_array, materials_len);
+ struct DRWShadingGroup **shgrp_depth_clip_array = BLI_array_alloca(shgrp_depth_clip_array, materials_len);
+
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len);
+
+ bool use_flat_nor = false;
+
+ if (is_default_mode_shader) {
+ if (is_sculpt_mode_draw) {
+ use_flat_nor = DRW_object_is_flat_normal(ob);
+ }
+ }
+
+ for (int i = 0; i < materials_len; ++i) {
+ Material *ma;
+
+ if (is_sculpt_mode_draw) {
+ ma = NULL;
+ }
+ else {
+ ma = give_current_material(ob, i + 1);
+ }
+
+ gpumat_array[i] = NULL;
+ gpumat_depth_array[i] = NULL;
+ shgrp_array[i] = NULL;
+ shgrp_depth_array[i] = NULL;
+ shgrp_depth_clip_array[i] = NULL;
+
+ if (ma == NULL)
+ ma = &defmaterial;
+
+ switch (ma->blend_method) {
+ case MA_BM_SOLID:
+ case MA_BM_CLIP:
+ case MA_BM_HASHED:
+ material_opaque(ma, material_hash, sldata, vedata, do_cull, use_flat_nor,
+ &gpumat_array[i], &gpumat_depth_array[i],
+ &shgrp_array[i], &shgrp_depth_array[i], &shgrp_depth_clip_array[i]);
+ break;
+ case MA_BM_ADD:
+ case MA_BM_MULTIPLY:
+ case MA_BM_BLEND:
+ material_transparent(ma, sldata, vedata, do_cull, use_flat_nor,
+ &gpumat_array[i], &shgrp_array[i], &shgrp_depth_array[i]);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+
+ if (is_sculpt_mode && is_sculpt_mode_draw == false) {
+ DRW_cache_mesh_sculpt_coords_ensure(ob);
+ }
+
+ /* Only support single volume material for now. */
+ /* XXX We rely on the previously compiled surface shader
+ * to know if the material has a "volume nodetree".
+ */
+ bool use_volume_material = (gpumat_array[0] && GPU_material_use_domain_volume(gpumat_array[0]));
+
+ if (ob->dt >= OB_SOLID) {
+ /* Get per-material split surface */
+ char *auto_layer_names;
+ int *auto_layer_is_srgb;
+ int auto_layer_count;
+ struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
+ ob, gpumat_array, materials_len, use_hide,
+ &auto_layer_names,
+ &auto_layer_is_srgb,
+ &auto_layer_count);
+ if (mat_geom) {
+ for (int i = 0; i < materials_len; ++i) {
+ if (mat_geom[i] == NULL) {
+ continue;
+ }
+ EEVEE_ObjectEngineData *oedata = NULL;
+ Material *ma = give_current_material(ob, i + 1);
+
+ if (ma == NULL)
+ ma = &defmaterial;
+
+ /* Do not render surface if we are rendering a volume object
+ * and do not have a surface closure. */
+ if (use_volume_material &&
+ (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i])))
+ {
+ continue;
+ }
+
+ /* XXX TODO rewrite this to include the dupli objects.
+ * This means we cannot exclude dupli objects from reflections!!! */
+ if ((ob->base_flag & BASE_FROMDUPLI) == 0) {
+ oedata = EEVEE_object_data_ensure(ob);
+ oedata->ob = ob;
+ oedata->test_data = &sldata->probes->vis_data;
+ }
+
+ /* Shading pass */
+ ADD_SHGROUP_CALL(shgrp_array[i], ob, ma, mat_geom[i], oedata);
+
+ /* Depth Prepass */
+ ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, ma, mat_geom[i], oedata);
+ ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, ma, mat_geom[i], oedata);
+
+ char *name = auto_layer_names;
+ for (int j = 0; j < auto_layer_count; ++j) {
+ /* TODO don't add these uniform when not needed (default pass shaders). */
+ if (shgrp_array[i]) {
+ DRW_shgroup_uniform_bool(shgrp_array[i], name, &auto_layer_is_srgb[j], 1);
+ }
+ if (shgrp_depth_array[i]) {
+ DRW_shgroup_uniform_bool(shgrp_depth_array[i], name, &auto_layer_is_srgb[j], 1);
+ }
+ if (shgrp_depth_clip_array[i]) {
+ DRW_shgroup_uniform_bool(shgrp_depth_clip_array[i], name, &auto_layer_is_srgb[j], 1);
+ }
+ /* Go to next layer name. */
+ while (*name != '\0') { name++; }
+ name += 1;
+ }
+
+ /* Shadow Pass */
+ if (ma->use_nodes && ma->nodetree && (ma->blend_method != MA_BM_SOLID)) {
+ struct GPUMaterial *gpumat;
+ switch (ma->blend_shadow) {
+ case MA_BS_SOLID:
+ EEVEE_lights_cache_shcaster_add(
+ sldata, stl, mat_geom[i], ob);
+ *cast_shadow = true;
+ break;
+ case MA_BS_CLIP:
+ gpumat = EEVEE_material_mesh_depth_get(scene, ma, false, true);
+ EEVEE_lights_cache_shcaster_material_add(
+ sldata, psl, gpumat, mat_geom[i], ob, &ma->alpha_threshold);
+ *cast_shadow = true;
+ break;
+ case MA_BS_HASHED:
+ gpumat = EEVEE_material_mesh_depth_get(scene, ma, true, true);
+ EEVEE_lights_cache_shcaster_material_add(
+ sldata, psl, gpumat, mat_geom[i], ob, NULL);
+ *cast_shadow = true;
+ break;
+ case MA_BS_NONE:
+ default:
+ break;
+ }
+ }
+ else {
+ EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob);
+ *cast_shadow = true;
+ }
+ }
+ }
+ }
+
+ /* Volumetrics */
+ if (((stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_volume_material) {
+ EEVEE_volumes_cache_object_add(sldata, vedata, scene, ob);
+ }
+ }
+}
+
+void EEVEE_hair_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+
+ bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0);
+
+ if (ob->type == OB_MESH) {
+ if (ob != draw_ctx->object_edit) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ if (!psys_check_enabled(ob, psys, false)) {
+ continue;
+ }
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+ if (draw_as != PART_DRAW_PATH) {
+ continue;
+ }
+
+ DRWShadingGroup *shgrp = NULL;
+ Material *ma = give_current_material(ob, part->omat);
+
+ if (ma == NULL) {
+ ma = &defmaterial;
+ }
+
+ float *color_p = &ma->r;
+ float *metal_p = &ma->metallic;
+ float *spec_p = &ma->spec;
+ float *rough_p = &ma->roughness;
+
+ shgrp = DRW_shgroup_hair_create(
+ ob, psys, md,
+ psl->depth_pass,
+ e_data.default_hair_prepass_sh);
+
+ shgrp = DRW_shgroup_hair_create(
+ ob, psys, md,
+ psl->depth_pass_clip,
+ e_data.default_hair_prepass_clip_sh);
+ DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo);
+
+ shgrp = NULL;
+ if (ma->use_nodes && ma->nodetree) {
+ static int ssr_id;
+ ssr_id = (use_ssr) ? 1 : -1;
+ static float half = 0.5f;
+ static float error_col[3] = {1.0f, 0.0f, 1.0f};
+ static float compile_col[3] = {0.5f, 0.5f, 0.5f};
+ struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, sldata->lamps->shadow_method);
+
+ switch (GPU_material_status(gpumat)) {
+ case GPU_MAT_SUCCESS:
+ {
+ bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE);
+ bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY);
+ bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT);
+
+ shgrp = DRW_shgroup_material_hair_create(
+ ob, psys, md,
+ psl->material_pass,
+ gpumat);
+
+ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL,
+ use_diffuse, use_glossy, use_refract, false, false);
+ break;
+ }
+ case GPU_MAT_QUEUED:
+ {
+ color_p = compile_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
+ case GPU_MAT_FAILED:
+ default:
+ color_p = error_col;
+ metal_p = spec_p = rough_p = &half;
+ break;
+ }
+ }
+
+ /* Fallback to default shader */
+ if (shgrp == NULL) {
+ shgrp = EEVEE_default_shading_group_get(sldata, vedata,
+ ob, psys, md,
+ true, false, use_ssr,
+ sldata->lamps->shadow_method);
+ DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
+ DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
+ DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
+ DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
+ }
+
+ /* Shadows */
+ DRW_shgroup_hair_create(
+ ob, psys, md,
+ psl->shadow_pass,
+ e_data.default_hair_prepass_sh);
+ *cast_shadow = true;
+ }
+ }
+ }
+}
+
+void EEVEE_materials_cache_finish(EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+
+ /* Look-Dev */
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+ if (LOOK_DEV_OVERLAY_ENABLED(v3d)) {
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ struct GPUBatch *sphere = DRW_cache_sphere_get();
+ static float mat1[4][4];
+ static float color[3] = {0.8f, 0.8f, 0.8f};
+ static float metallic_on = 1.0f;
+ static float metallic_off = 0.00f;
+ static float specular_off = 0.5f;
+ static float specular_on = 1.0f;
+ static float roughness_off = 0.05f;
+ static float roughness_on = 1.00f;
+
+ float view_mat[4][4];
+ DRW_viewport_matrix_get(view_mat, DRW_MAT_VIEWINV);
+
+ DRWShadingGroup *shgrp = EEVEE_lookdev_shading_group_get(sldata, vedata, false, linfo->shadow_method);
+ DRW_shgroup_uniform_vec3(shgrp, "basecol", color, 1);
+ DRW_shgroup_uniform_float(shgrp, "metallic", &metallic_on, 1);
+ DRW_shgroup_uniform_float(shgrp, "specular", &specular_on, 1);
+ DRW_shgroup_uniform_float(shgrp, "roughness", &roughness_off, 1);
+ unit_m4(mat1);
+ mul_m4_m4m4(mat1, mat1, view_mat);
+ translate_m4(mat1, -1.5f, 0.0f, -5.0f);
+ DRW_shgroup_call_add(shgrp, sphere, mat1);
+
+ shgrp = EEVEE_lookdev_shading_group_get(sldata, vedata, false, linfo->shadow_method);
+ DRW_shgroup_uniform_vec3(shgrp, "basecol", color, 1);
+ DRW_shgroup_uniform_float(shgrp, "metallic", &metallic_off, 1);
+ DRW_shgroup_uniform_float(shgrp, "specular", &specular_off, 1);
+ DRW_shgroup_uniform_float(shgrp, "roughness", &roughness_on, 1);
+ translate_m4(mat1, 3.0f, 0.0f, 0.0f);
+ DRW_shgroup_call_add(shgrp, sphere, mat1);
+ }
+ /* END */
+
+ BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN);
+}
+
+void EEVEE_materials_free(void)
+{
+ for (int i = 0; i < VAR_MAT_MAX; ++i) {
+ DRW_SHADER_FREE_SAFE(e_data.default_lit[i]);
+ }
+ MEM_SAFE_FREE(e_data.frag_shader_lib);
+ MEM_SAFE_FREE(e_data.vert_shader_str);
+ MEM_SAFE_FREE(e_data.volume_shader_lib);
+ DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh);
+ DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh);
+ DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh);
+ DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh);
+ DRW_SHADER_FREE_SAFE(e_data.default_background);
+ DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
+ DRW_TEXTURE_FREE_SAFE(e_data.util_tex);
+ DRW_TEXTURE_FREE_SAFE(e_data.noise_tex);
+ DRW_UBO_FREE_SAFE(e_data.dummy_sss_profile);
+}
+
+void EEVEE_draw_default_passes(EEVEE_PassList *psl)
+{
+ for (int i = 0; i < VAR_MAT_MAX; ++i) {
+ if (psl->default_pass[i]) {
+ DRW_draw_pass(psl->default_pass[i]);
+ }
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c
new file mode 100644
index 00000000000..de9582611ec
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_mist.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_mist.c
+ * \ingroup draw_engine
+ *
+ * Implementation of Blender Mist pass.
+ * IMPORTANT: This is a "post process" of the Z depth so it will lack any transparent objects.
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_world_types.h"
+
+#include "BLI_string_utils.h"
+
+#include "eevee_private.h"
+
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_effect_mist_frag_glsl[];
+
+static struct {
+ struct GPUShader *mist_sh;
+} e_data = {NULL}; /* Engine data */
+
+void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+ Scene *scene = draw_ctx->scene;
+
+ float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ if (e_data.mist_sh == NULL) {
+ char *frag_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_effect_mist_frag_glsl);
+
+ e_data.mist_sh = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n");
+
+ MEM_freeN(frag_str);
+ }
+
+ /* Create FrameBuffer. */
+ DRW_texture_ensure_fullscreen_2D(&txl->mist_accum, GPU_R32F, 0); /* Should be enough precision for many samples. */
+
+ GPU_framebuffer_ensure_config(&fbl->mist_accum_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->mist_accum)
+ });
+
+ /* Clear texture. */
+ GPU_framebuffer_bind(fbl->mist_accum_fb);
+ GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear);
+
+ /* Mist settings. */
+ if (scene && scene->world) {
+ g_data->mist_start = scene->world->miststa;
+ g_data->mist_inv_dist = (scene->world->mistdist > 0.0f) ? 1.0f / scene->world->mistdist : 0.0f;
+
+ switch (scene->world->mistype) {
+ case WO_MIST_QUADRATIC:
+ g_data->mist_falloff = 2.0f;
+ break;
+ case WO_MIST_LINEAR:
+ g_data->mist_falloff = 1.0f;
+ break;
+ case WO_MIST_INVERSE_QUADRATIC:
+ g_data->mist_falloff = 0.5f;
+ break;
+ }
+ }
+ else {
+ float near = -sldata->common_data.view_vecs[0][2];
+ float range = sldata->common_data.view_vecs[1][2];
+ /* Fallback */
+ g_data->mist_start = near;
+ g_data->mist_inv_dist = 1.0f / fabsf(range);
+ g_data->mist_falloff = 1.0f;
+ }
+
+ /* XXX ??!! WHY? If not it does not match cycles. */
+ g_data->mist_falloff *= 0.5f;
+
+ /* Create Pass and shgroup. */
+ psl->mist_accum_ps = DRW_pass_create("Mist Accum", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.mist_sh, psl->mist_accum_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_vec3(grp, "mistSettings", &g_data->mist_start, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+}
+
+void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_PassList *psl = vedata->psl;
+
+ if (fbl->mist_accum_fb != NULL) {
+ GPU_framebuffer_bind(fbl->mist_accum_fb);
+ DRW_draw_pass(psl->mist_accum_ps);
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+ }
+}
+
+void EEVEE_mist_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.mist_sh);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
new file mode 100644
index 00000000000..d2309d20abb
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_motion_blur.c
+ * \ingroup draw_engine
+ *
+ * Gather all screen space effects technique such as Bloom, Motion Blur, DoF, SSAO, SSR, ...
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_global.h" /* for G.debug_value */
+#include "BKE_camera.h"
+#include "BKE_object.h"
+#include "BKE_animsys.h"
+#include "BKE_screen.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_screen_types.h"
+
+#include "ED_screen.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+#include "GPU_texture.h"
+
+static struct {
+ /* Motion Blur */
+ struct GPUShader *motion_blur_sh;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_effect_motion_blur_frag_glsl[];
+
+static void eevee_motion_blur_camera_get_matrix_at_time(
+ Scene *scene,
+ ARegion *ar, RegionView3D *rv3d, View3D *v3d,
+ Object *camera,
+ float time,
+ float r_mat[4][4])
+{
+ float obmat[4][4];
+
+ /* HACK */
+ Object cam_cpy; Camera camdata_cpy;
+ memcpy(&cam_cpy, camera, sizeof(cam_cpy));
+ memcpy(&camdata_cpy, camera->data, sizeof(camdata_cpy));
+ cam_cpy.data = &camdata_cpy;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ /* Past matrix */
+ /* FIXME : This is a temporal solution that does not take care of parent animations */
+ /* Recalc Anim manually */
+ BKE_animsys_evaluate_animdata(draw_ctx->depsgraph, scene, &cam_cpy.id, cam_cpy.adt, time, ADT_RECALC_ALL);
+ BKE_animsys_evaluate_animdata(draw_ctx->depsgraph, scene, &camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL);
+ BKE_object_where_is_calc_time(draw_ctx->depsgraph, scene, &cam_cpy, time);
+
+ /* Compute winmat */
+ CameraParams params;
+ BKE_camera_params_init(&params);
+
+ if (v3d != NULL) {
+ BKE_camera_params_from_view3d(&params, draw_ctx->depsgraph, v3d, rv3d);
+ BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
+ }
+ else {
+ BKE_camera_params_from_object(&params, &cam_cpy);
+ BKE_camera_params_compute_viewplane(&params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
+ }
+
+ BKE_camera_params_compute_matrix(&params);
+
+ /* FIXME Should be done per view (MULTIVIEW) */
+ normalize_m4_m4(obmat, cam_cpy.obmat);
+ invert_m4(obmat);
+ mul_m4_m4m4(r_mat, params.winmat, obmat);
+}
+
+static void eevee_create_shader_motion_blur(void)
+{
+ e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL);
+}
+
+int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ Scene *scene = draw_ctx->scene;
+
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ARegion *ar = draw_ctx->ar;
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) {
+ /* Update Motion Blur Matrices */
+ if (camera) {
+ float persmat[4][4];
+ float ctime = DEG_get_ctime(draw_ctx->depsgraph);
+ float delta = scene_eval->eevee.motion_blur_shutter;
+ Object *ob_camera_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, camera);
+
+ /* Current matrix */
+ eevee_motion_blur_camera_get_matrix_at_time(
+ scene,
+ ar, rv3d, v3d,
+ ob_camera_eval,
+ ctime,
+ effects->current_ndc_to_world);
+
+ /* Viewport Matrix */
+ DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
+
+ /* Only continue if camera is not being keyed */
+ if (DRW_state_is_image_render() ||
+ compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f))
+ {
+ /* Past matrix */
+ eevee_motion_blur_camera_get_matrix_at_time(
+ scene,
+ ar, rv3d, v3d,
+ ob_camera_eval,
+ ctime - delta,
+ effects->past_world_to_ndc);
+
+#if 0 /* for future high quality blur */
+ /* Future matrix */
+ eevee_motion_blur_camera_get_matrix_at_time(
+ scene,
+ ar, rv3d, v3d,
+ ob_camera_eval,
+ ctime + delta,
+ effects->future_world_to_ndc);
+#endif
+ invert_m4(effects->current_ndc_to_world);
+
+ effects->motion_blur_samples = scene_eval->eevee.motion_blur_samples;
+
+ if (!e_data.motion_blur_sh) {
+ eevee_create_shader_motion_blur();
+ }
+
+ return EFFECT_MOTION_BLUR | EFFECT_POST_BUFFER;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) {
+ psl->motion_blur = DRW_pass_create("Motion Blur", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur);
+ DRW_shgroup_uniform_int(grp, "samples", &effects->motion_blur_samples, 1);
+ DRW_shgroup_uniform_mat4(grp, "currInvViewProjMatrix", effects->current_ndc_to_world);
+ DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", effects->past_world_to_ndc);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+}
+
+void EEVEE_motion_blur_draw(EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ /* Motion Blur */
+ if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) {
+ GPU_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->motion_blur);
+ SWAP_BUFFERS();
+ }
+}
+
+void EEVEE_motion_blur_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
new file mode 100644
index 00000000000..03aee102136
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_occlusion.c
+ * \ingroup draw_engine
+ *
+ * Implementation of the screen space Ground Truth Ambient Occlusion.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_string_utils.h"
+
+#include "DNA_anim_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "BKE_global.h" /* for G.debug_value */
+
+#include "eevee_private.h"
+
+#include "GPU_extensions.h"
+#include "GPU_state.h"
+
+static struct {
+ /* Ground Truth Ambient Occlusion */
+ struct GPUShader *gtao_sh;
+ struct GPUShader *gtao_layer_sh;
+ struct GPUShader *gtao_debug_sh;
+ struct GPUTexture *src_depth;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_ambient_occlusion_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_effect_gtao_frag_glsl[];
+
+static void eevee_create_shader_occlusion(void)
+{
+ char *frag_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_effect_gtao_frag_glsl);
+
+ e_data.gtao_sh = DRW_shader_create_fullscreen(frag_str, NULL);
+ e_data.gtao_layer_sh = DRW_shader_create_fullscreen(frag_str, "#define LAYERED_DEPTH\n");
+ e_data.gtao_debug_sh = DRW_shader_create_fullscreen(frag_str, "#define DEBUG_AO\n");
+
+ MEM_freeN(frag_str);
+}
+
+int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) {
+ const float *viewport_size = DRW_viewport_size_get();
+ const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ /* Shaders */
+ if (!e_data.gtao_sh) {
+ eevee_create_shader_occlusion();
+ }
+
+ common_data->ao_dist = scene_eval->eevee.gtao_distance;
+ common_data->ao_factor = scene_eval->eevee.gtao_factor;
+ common_data->ao_quality = 1.0f - scene_eval->eevee.gtao_quality;
+
+ common_data->ao_settings = 1.0f; /* USE_AO */
+ if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_BENT_NORMALS) {
+ common_data->ao_settings += 2.0f; /* USE_BENT_NORMAL */
+ }
+ if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_BOUNCE) {
+ common_data->ao_settings += 4.0f; /* USE_DENOISE */
+ }
+
+ common_data->ao_bounce_fac = (scene_eval->eevee.flag & SCE_EEVEE_GTAO_BOUNCE) ? 1.0f : 0.0f;
+
+ effects->gtao_horizons = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], GPU_RGBA8,
+ &draw_engine_eevee_type);
+ GPU_framebuffer_ensure_config(&fbl->gtao_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->gtao_horizons)
+ });
+
+ if (G.debug_value == 6) {
+ effects->gtao_horizons_debug = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], GPU_RGBA8,
+ &draw_engine_eevee_type);
+ GPU_framebuffer_ensure_config(&fbl->gtao_debug_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->gtao_horizons_debug)
+ });
+ }
+ else {
+ effects->gtao_horizons_debug = NULL;
+ }
+
+ return EFFECT_GTAO | EFFECT_NORMAL_BUFFER;
+ }
+
+ /* Cleanup */
+ effects->gtao_horizons = NULL;
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb);
+ common_data->ao_settings = 0.0f;
+
+ return 0;
+}
+
+void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) {
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ DRW_texture_ensure_fullscreen_2D(&txl->ao_accum, GPU_R32F, 0); /* Should be enough precision for many samples. */
+
+ GPU_framebuffer_ensure_config(&fbl->ao_accum_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->ao_accum)
+ });
+
+ /* Clear texture. */
+ GPU_framebuffer_bind(fbl->ao_accum_fb);
+ GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear);
+
+ /* Accumulation pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE;
+ psl->ao_accum_ps = DRW_pass_create("AO Accum", state);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_accum_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
+ DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+ else {
+ /* Cleanup to release memory */
+ DRW_TEXTURE_FREE_SAFE(txl->ao_accum);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->ao_accum_fb);
+ }
+}
+
+void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
+ /** Occlusion algorithm overview
+ *
+ * We separate the computation into 2 steps.
+ *
+ * - First we scan the neighborhood pixels to find the maximum horizon angle.
+ * We save this angle in a RG8 array texture.
+ *
+ * - Then we use this angle to compute occlusion with the shading normal at
+ * the shading stage. This let us do correct shadowing for each diffuse / specular
+ * lobe present in the shader using the correct normal.
+ **/
+ psl->ao_horizon_search = DRW_pass_create("GTAO Horizon Search", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_sh, psl->ao_horizon_search);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &effects->ao_src_depth);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->ao_horizon_search_layer = DRW_pass_create("GTAO Horizon Search Layer", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(e_data.gtao_layer_sh, psl->ao_horizon_search_layer);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBufferLayered", &effects->ao_src_depth);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ if (G.debug_value == 6) {
+ psl->ao_horizon_debug = DRW_pass_create("GTAO Horizon Debug", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_horizon_debug);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
+ DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ }
+}
+
+void EEVEE_occlusion_compute(
+ EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
+ DRW_stats_group_start("GTAO Horizon Scan");
+ effects->ao_src_depth = depth_src;
+ effects->ao_depth_layer = layer;
+
+ GPU_framebuffer_bind(fbl->gtao_fb);
+
+ if (layer >= 0) {
+ DRW_draw_pass(psl->ao_horizon_search_layer);
+ }
+ else {
+ DRW_draw_pass(psl->ao_horizon_search);
+ }
+
+ if (GPU_mip_render_workaround()) {
+ /* Fix dot corruption on intel HD5XX/HD6XX series.
+ * It seems affected drivers are the same that needs
+ * GPU_mip_render_workaround. */
+ GPU_flush();
+ }
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+
+ DRW_stats_group_end();
+ }
+}
+
+void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if (((effects->enabled_effects & EFFECT_GTAO) != 0) && (G.debug_value == 6)) {
+ DRW_stats_group_start("GTAO Debug");
+
+ GPU_framebuffer_bind(fbl->gtao_debug_fb);
+ DRW_draw_pass(psl->ao_horizon_debug);
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+
+ DRW_stats_group_end();
+ }
+}
+
+void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_PassList *psl = vedata->psl;
+
+ if (fbl->ao_accum_fb != NULL) {
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ /* Update the min_max/horizon buffers so the refracion materials appear in it. */
+ EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
+ EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
+
+ GPU_framebuffer_bind(fbl->ao_accum_fb);
+ DRW_draw_pass(psl->ao_accum_ps);
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+ }
+}
+
+void EEVEE_occlusion_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.gtao_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gtao_layer_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
new file mode 100644
index 00000000000..451b1013103
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -0,0 +1,1054 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_private.h
+ * \ingroup DNA
+ */
+
+#ifndef __EEVEE_PRIVATE_H__
+#define __EEVEE_PRIVATE_H__
+
+#include "DNA_lightprobe_types.h"
+
+struct Object;
+struct EEVEE_BoundSphere;
+struct EEVEE_ShadowCasterBuffer;
+struct RenderLayer;
+struct RenderResult;
+struct GPUFrameBuffer;
+
+extern struct DrawEngineType draw_engine_eevee_type;
+
+/* Minimum UBO is 16384 bytes */
+#define MAX_PROBE 128 /* TODO : find size by dividing UBO max size by probe data size */
+#define MAX_GRID 64 /* TODO : find size by dividing UBO max size by grid data size */
+#define MAX_PLANAR 16 /* TODO : find size by dividing UBO max size by grid data size */
+#define MAX_LIGHT 128 /* TODO : find size by dividing UBO max size by light data size */
+#define MAX_CASCADE_NUM 4
+#define MAX_SHADOW 256 /* TODO : Make this depends on GL_MAX_ARRAY_TEXTURE_LAYERS */
+#define MAX_SHADOW_CASCADE 8
+#define MAX_SHADOW_CUBE (MAX_SHADOW - MAX_CASCADE_NUM * MAX_SHADOW_CASCADE)
+#define MAX_BLOOM_STEP 16
+
+/* Only define one of these. */
+// #define IRRADIANCE_SH_L2
+// #define IRRADIANCE_CUBEMAP
+#define IRRADIANCE_HL2
+#define HAMMERSLEY_SIZE 1024
+
+#if defined(IRRADIANCE_SH_L2)
+# define SHADER_IRRADIANCE "#define IRRADIANCE_SH_L2\n"
+#elif defined(IRRADIANCE_CUBEMAP)
+# define SHADER_IRRADIANCE "#define IRRADIANCE_CUBEMAP\n"
+#elif defined(IRRADIANCE_HL2)
+# define SHADER_IRRADIANCE "#define IRRADIANCE_HL2\n"
+#endif
+
+#define SHADER_DEFINES \
+ "#define EEVEE_ENGINE\n" \
+ "#define MAX_PROBE " STRINGIFY(MAX_PROBE) "\n" \
+ "#define MAX_GRID " STRINGIFY(MAX_GRID) "\n" \
+ "#define MAX_PLANAR " STRINGIFY(MAX_PLANAR) "\n" \
+ "#define MAX_LIGHT " STRINGIFY(MAX_LIGHT) "\n" \
+ "#define MAX_SHADOW " STRINGIFY(MAX_SHADOW) "\n" \
+ "#define MAX_SHADOW_CUBE " STRINGIFY(MAX_SHADOW_CUBE) "\n" \
+ "#define MAX_SHADOW_CASCADE " STRINGIFY(MAX_SHADOW_CASCADE) "\n" \
+ "#define MAX_CASCADE_NUM " STRINGIFY(MAX_CASCADE_NUM) "\n" \
+ SHADER_IRRADIANCE
+
+#define SWAP_DOUBLE_BUFFERS() { \
+ if (effects->swap_double_buffer) { \
+ SWAP(struct GPUFrameBuffer *, fbl->main_fb, fbl->double_buffer_fb); \
+ SWAP(struct GPUFrameBuffer *, fbl->main_color_fb, fbl->double_buffer_color_fb); \
+ SWAP(GPUTexture *, txl->color, txl->color_double_buffer); \
+ effects->swap_double_buffer = false; \
+ } \
+} ((void)0)
+
+#define SWAP_BUFFERS() { \
+ if (effects->target_buffer == fbl->effect_color_fb) { \
+ SWAP_DOUBLE_BUFFERS(); \
+ effects->source_buffer = txl->color_post; \
+ effects->target_buffer = fbl->main_color_fb; \
+ } \
+ else { \
+ SWAP_DOUBLE_BUFFERS(); \
+ effects->source_buffer = txl->color; \
+ effects->target_buffer = fbl->effect_color_fb; \
+ } \
+} ((void)0)
+
+#define SWAP_BUFFERS_TAA() { \
+ if (effects->target_buffer == fbl->effect_color_fb) { \
+ SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->taa_history_fb); \
+ SWAP(struct GPUFrameBuffer *, fbl->effect_color_fb, fbl->taa_history_color_fb); \
+ SWAP(GPUTexture *, txl->color_post, txl->taa_history); \
+ effects->source_buffer = txl->taa_history; \
+ effects->target_buffer = fbl->effect_color_fb; \
+ } \
+ else { \
+ SWAP(struct GPUFrameBuffer *, fbl->main_fb, fbl->taa_history_fb); \
+ SWAP(struct GPUFrameBuffer *, fbl->main_color_fb, fbl->taa_history_color_fb); \
+ SWAP(GPUTexture *, txl->color, txl->taa_history); \
+ effects->source_buffer = txl->taa_history; \
+ effects->target_buffer = fbl->main_color_fb; \
+ } \
+} ((void)0)
+
+#define OVERLAY_ENABLED(v3d) ((v3d) && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0)
+#define LOOK_DEV_MODE_ENABLED(v3d) ((v3d) && (v3d->shading.type == OB_MATERIAL))
+#define LOOK_DEV_OVERLAY_ENABLED(v3d) (LOOK_DEV_MODE_ENABLED(v3d) && OVERLAY_ENABLED(v3d) && (v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV))
+#define USE_SCENE_LIGHT(v3d) ((!v3d) || (!LOOK_DEV_MODE_ENABLED(v3d)) || ((LOOK_DEV_MODE_ENABLED(v3d) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS))))
+#define LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d) (LOOK_DEV_MODE_ENABLED(v3d) && !(v3d->shading.flag & V3D_SHADING_SCENE_WORLD))
+
+#define OCTAHEDRAL_SIZE_FROM_CUBESIZE(cube_size) ((int)ceilf(sqrtf((cube_size * cube_size) * 6.0f)))
+#define MIN_CUBE_LOD_LEVEL 3
+#define MAX_PLANAR_LOD_LEVEL 9
+
+/* World shader variations */
+enum {
+ VAR_WORLD_BACKGROUND = 0,
+ VAR_WORLD_PROBE = 1,
+ VAR_WORLD_VOLUME = 2,
+};
+
+/* Material shader variations */
+enum {
+ VAR_MAT_MESH = (1 << 0),
+ VAR_MAT_PROBE = (1 << 1),
+ VAR_MAT_HAIR = (1 << 2),
+ VAR_MAT_FLAT = (1 << 3),
+ VAR_MAT_BLEND = (1 << 4),
+ VAR_MAT_VSM = (1 << 5),
+ VAR_MAT_ESM = (1 << 6),
+ VAR_MAT_VOLUME = (1 << 7),
+ VAR_MAT_LOOKDEV = (1 << 8),
+ /* Max number of variation */
+ /* IMPORTANT : Leave it last and set
+ * it's value accordingly. */
+ VAR_MAT_MAX = (1 << 9),
+ /* These are options that are not counted in VAR_MAT_MAX
+ * because they are not cumulative with the others above. */
+ VAR_MAT_CLIP = (1 << 10),
+ VAR_MAT_HASH = (1 << 11),
+ VAR_MAT_MULT = (1 << 12),
+ VAR_MAT_SHADOW = (1 << 13),
+ VAR_MAT_REFRACT = (1 << 14),
+ VAR_MAT_SSS = (1 << 15),
+ VAR_MAT_TRANSLUC = (1 << 16),
+ VAR_MAT_SSSALBED = (1 << 17),
+};
+
+/* ************ PROBE UBO ************* */
+
+/* They are the same struct as their Cache siblings.
+ * typedef'ing just to keep the naming consistent with
+ * other eevee types. */
+typedef LightProbeCache EEVEE_LightProbe;
+typedef LightGridCache EEVEE_LightGrid;
+
+typedef struct EEVEE_PlanarReflection {
+ float plane_equation[4];
+ float clip_vec_x[3], attenuation_scale;
+ float clip_vec_y[3], attenuation_bias;
+ float clip_edge_x_pos, clip_edge_x_neg;
+ float clip_edge_y_pos, clip_edge_y_neg;
+ float facing_scale, facing_bias, clipsta, pad;
+ float reflectionmat[4][4]; /* Used for sampling the texture. */
+ float mtx[4][4]; /* Not used in shader. TODO move elsewhere. */
+} EEVEE_PlanarReflection;
+
+/* --------------------------------------- */
+
+typedef struct EEVEE_BoundSphere {
+ float center[3], radius;
+} EEVEE_BoundSphere;
+
+typedef struct EEVEE_BoundBox {
+ float center[3], halfdim[3];
+} EEVEE_BoundBox;
+
+typedef struct EEVEE_PassList {
+ /* Shadows */
+ struct DRWPass *shadow_pass;
+ struct DRWPass *shadow_cube_copy_pass;
+ struct DRWPass *shadow_cube_store_pass;
+ struct DRWPass *shadow_cube_store_high_pass;
+ struct DRWPass *shadow_cascade_copy_pass;
+ struct DRWPass *shadow_cascade_store_pass;
+ struct DRWPass *shadow_cascade_store_high_pass;
+
+ /* Probes */
+ struct DRWPass *probe_background;
+ struct DRWPass *probe_glossy_compute;
+ struct DRWPass *probe_diffuse_compute;
+ struct DRWPass *probe_visibility_compute;
+ struct DRWPass *probe_grid_fill;
+ struct DRWPass *probe_display;
+ struct DRWPass *probe_planar_downsample_ps;
+
+ /* Effects */
+ struct DRWPass *ao_horizon_search;
+ struct DRWPass *ao_horizon_search_layer;
+ struct DRWPass *ao_horizon_debug;
+ struct DRWPass *ao_accum_ps;
+ struct DRWPass *mist_accum_ps;
+ struct DRWPass *motion_blur;
+ struct DRWPass *bloom_blit;
+ struct DRWPass *bloom_downsample_first;
+ struct DRWPass *bloom_downsample;
+ struct DRWPass *bloom_upsample;
+ struct DRWPass *bloom_resolve;
+ struct DRWPass *dof_down;
+ struct DRWPass *dof_scatter;
+ struct DRWPass *dof_resolve;
+ struct DRWPass *volumetric_world_ps;
+ struct DRWPass *volumetric_objects_ps;
+ struct DRWPass *volumetric_scatter_ps;
+ struct DRWPass *volumetric_integration_ps;
+ struct DRWPass *volumetric_resolve_ps;
+ struct DRWPass *ssr_raytrace;
+ struct DRWPass *ssr_resolve;
+ struct DRWPass *sss_blur_ps;
+ struct DRWPass *sss_resolve_ps;
+ struct DRWPass *sss_accum_ps;
+ struct DRWPass *color_downsample_ps;
+ struct DRWPass *color_downsample_cube_ps;
+ struct DRWPass *velocity_resolve;
+ struct DRWPass *taa_resolve;
+
+ /* HiZ */
+ struct DRWPass *minz_downlevel_ps;
+ struct DRWPass *maxz_downlevel_ps;
+ struct DRWPass *minz_downdepth_ps;
+ struct DRWPass *maxz_downdepth_ps;
+ struct DRWPass *minz_downdepth_layer_ps;
+ struct DRWPass *maxz_downdepth_layer_ps;
+ struct DRWPass *minz_copydepth_ps;
+ struct DRWPass *maxz_copydepth_ps;
+ struct DRWPass *maxz_copydepth_layer_ps;
+
+ struct DRWPass *depth_pass;
+ struct DRWPass *depth_pass_cull;
+ struct DRWPass *depth_pass_clip;
+ struct DRWPass *depth_pass_clip_cull;
+ struct DRWPass *refract_depth_pass;
+ struct DRWPass *refract_depth_pass_cull;
+ struct DRWPass *refract_depth_pass_clip;
+ struct DRWPass *refract_depth_pass_clip_cull;
+ struct DRWPass *default_pass[VAR_MAT_MAX];
+ struct DRWPass *sss_pass;
+ struct DRWPass *material_pass;
+ struct DRWPass *refract_pass;
+ struct DRWPass *transparent_pass;
+ struct DRWPass *background_pass;
+ struct DRWPass *update_noise_pass;
+ struct DRWPass *lookdev_pass;
+} EEVEE_PassList;
+
+typedef struct EEVEE_FramebufferList {
+ /* Effects */
+ struct GPUFrameBuffer *gtao_fb;
+ struct GPUFrameBuffer *gtao_debug_fb;
+ struct GPUFrameBuffer *downsample_fb;
+ struct GPUFrameBuffer *bloom_blit_fb;
+ struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP];
+ struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1];
+ struct GPUFrameBuffer *sss_blur_fb;
+ struct GPUFrameBuffer *sss_blit_fb;
+ struct GPUFrameBuffer *sss_resolve_fb;
+ struct GPUFrameBuffer *sss_clear_fb;
+ struct GPUFrameBuffer *sss_accum_fb;
+ struct GPUFrameBuffer *dof_down_fb;
+ struct GPUFrameBuffer *dof_scatter_fb;
+ struct GPUFrameBuffer *volumetric_fb;
+ struct GPUFrameBuffer *volumetric_scat_fb;
+ struct GPUFrameBuffer *volumetric_integ_fb;
+ struct GPUFrameBuffer *screen_tracing_fb;
+ struct GPUFrameBuffer *refract_fb;
+ struct GPUFrameBuffer *mist_accum_fb;
+ struct GPUFrameBuffer *ao_accum_fb;
+ struct GPUFrameBuffer *velocity_resolve_fb;
+
+ struct GPUFrameBuffer *update_noise_fb;
+
+ struct GPUFrameBuffer *planarref_fb;
+ struct GPUFrameBuffer *planar_downsample_fb;
+
+ struct GPUFrameBuffer *main_fb;
+ struct GPUFrameBuffer *main_color_fb;
+ struct GPUFrameBuffer *effect_fb;
+ struct GPUFrameBuffer *effect_color_fb;
+ struct GPUFrameBuffer *double_buffer_fb;
+ struct GPUFrameBuffer *double_buffer_color_fb;
+ struct GPUFrameBuffer *double_buffer_depth_fb;
+ struct GPUFrameBuffer *taa_history_fb;
+ struct GPUFrameBuffer *taa_history_color_fb;
+} EEVEE_FramebufferList;
+
+typedef struct EEVEE_TextureList {
+ /* Effects */
+ struct GPUTexture *color_post; /* R16_G16_B16 */
+ struct GPUTexture *mist_accum;
+ struct GPUTexture *ao_accum;
+ struct GPUTexture *sss_dir_accum;
+ struct GPUTexture *sss_col_accum;
+ struct GPUTexture *refract_color;
+ struct GPUTexture *taa_history;
+
+ struct GPUTexture *volume_prop_scattering;
+ struct GPUTexture *volume_prop_extinction;
+ struct GPUTexture *volume_prop_emission;
+ struct GPUTexture *volume_prop_phase;
+ struct GPUTexture *volume_scatter;
+ struct GPUTexture *volume_transmittance;
+ struct GPUTexture *volume_scatter_history;
+ struct GPUTexture *volume_transmittance_history;
+
+ struct GPUTexture *lookdev_grid_tx;
+ struct GPUTexture *lookdev_cube_tx;
+
+ struct GPUTexture *planar_pool;
+ struct GPUTexture *planar_depth;
+
+ struct GPUTexture *maxzbuffer;
+
+ struct GPUTexture *color; /* R16_G16_B16 */
+ struct GPUTexture *color_double_buffer;
+ struct GPUTexture *depth_double_buffer;
+} EEVEE_TextureList;
+
+typedef struct EEVEE_StorageList {
+ /* Effects */
+ struct EEVEE_EffectsInfo *effects;
+
+ struct EEVEE_PrivateData *g_data;
+
+ struct LightCache *lookdev_lightcache;
+ EEVEE_LightProbe *lookdev_cube_data;
+ EEVEE_LightGrid *lookdev_grid_data;
+ LightCacheTexture *lookdev_cube_mips;
+} EEVEE_StorageList;
+
+/* ************ LIGHT UBO ************* */
+typedef struct EEVEE_Light {
+ float position[3], invsqrdist;
+ float color[3], spec;
+ float spotsize, spotblend, radius, shadowid;
+ float rightvec[3], sizex;
+ float upvec[3], sizey;
+ float forwardvec[3], lamptype;
+} EEVEE_Light;
+
+/* Special type for elliptic area lamps, matches lamps_lib.glsl */
+#define LAMPTYPE_AREA_ELLIPSE 100.0f
+
+typedef struct EEVEE_Shadow {
+ float near, far, bias, exp;
+ float shadow_start, data_start, multi_shadow_count, shadow_blur;
+ float contact_dist, contact_bias, contact_spread, contact_thickness;
+} EEVEE_Shadow;
+
+typedef struct EEVEE_ShadowCube {
+ float position[3], pad;
+} EEVEE_ShadowCube;
+
+typedef struct EEVEE_ShadowCascade {
+ float shadowmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC->Tex : used for sampling the shadow map. */
+ float split_start[4];
+ float split_end[4];
+} EEVEE_ShadowCascade;
+
+typedef struct EEVEE_ShadowRender {
+ float position[3], pad;
+ float cube_texel_size;
+ float stored_texel_size;
+ float clip_near;
+ float clip_far;
+ int shadow_samples_len;
+ float shadow_samples_len_inv;
+ float exponent;
+} EEVEE_ShadowRender;
+
+/* This is just a really long bitflag with special function to access it. */
+#define MAX_LIGHTBITS_FIELDS (MAX_LIGHT / 8)
+typedef struct EEVEE_LightBits {
+ uchar fields[MAX_LIGHTBITS_FIELDS];
+} EEVEE_LightBits;
+
+typedef struct EEVEE_ShadowCaster {
+ struct EEVEE_LightBits bits;
+ struct EEVEE_BoundBox bbox;
+} EEVEE_ShadowCaster;
+
+typedef struct EEVEE_ShadowCasterBuffer {
+ struct EEVEE_ShadowCaster *shadow_casters;
+ char *flags;
+ uint alloc_count;
+ uint count;
+} EEVEE_ShadowCasterBuffer;
+
+/* ************ LIGHT DATA ************* */
+typedef struct EEVEE_LampsInfo {
+ int num_light, cache_num_light;
+ int num_cube_layer, cache_num_cube_layer;
+ int num_cascade_layer, cache_num_cascade_layer;
+ int gpu_cube_len, gpu_cascade_len, gpu_shadow_len;
+ int cpu_cube_len, cpu_cascade_len;
+ int update_flag;
+ int shadow_cube_size, shadow_cascade_size, shadow_method;
+ bool shadow_high_bitdepth, soft_shadows;
+ int shadow_cube_store_size;
+ int current_shadow_cascade;
+ int current_shadow_face;
+ uint shadow_instance_count;
+ float filter_size;
+ /* List of lights in the scene. */
+ /* XXX This is fragile, can get out of sync quickly. */
+ struct Object *light_ref[MAX_LIGHT];
+ struct Object *shadow_cube_ref[MAX_SHADOW_CUBE];
+ struct Object *shadow_cascade_ref[MAX_SHADOW_CASCADE];
+ /* UBO Storage : data used by UBO */
+ struct EEVEE_Light light_data[MAX_LIGHT];
+ struct EEVEE_ShadowRender shadow_render_data;
+ struct EEVEE_Shadow shadow_data[MAX_SHADOW];
+ struct EEVEE_ShadowCube shadow_cube_data[MAX_SHADOW_CUBE];
+ struct EEVEE_ShadowCascade shadow_cascade_data[MAX_SHADOW_CASCADE];
+ /* Lights tracking */
+ int new_shadow_id[MAX_LIGHT]; /* To be able to convert old bitfield to new bitfield */
+ struct EEVEE_BoundSphere shadow_bounds[MAX_LIGHT]; /* Tightly packed light bounds */
+ /* Pointers only. */
+ struct EEVEE_ShadowCasterBuffer *shcaster_frontbuffer;
+ struct EEVEE_ShadowCasterBuffer *shcaster_backbuffer;
+} EEVEE_LampsInfo;
+
+/* EEVEE_LampsInfo->shadow_casters_flag */
+enum {
+ SHADOW_CASTER_PRUNED = (1 << 0),
+ SHADOW_CASTER_UPDATED = (1 << 1),
+};
+
+/* EEVEE_LampsInfo->update_flag */
+enum {
+ LIGHT_UPDATE_SHADOW_CUBE = (1 << 0),
+};
+
+/* ************ PROBE DATA ************* */
+typedef struct EEVEE_LightProbeVisTest {
+ struct Collection *collection; /* Skip test if NULL */
+ bool invert;
+ bool cached; /* Reuse last test results */
+} EEVEE_LightProbeVisTest;
+
+typedef struct EEVEE_LightProbesInfo {
+ int num_cube, cache_num_cube;
+ int num_grid, cache_num_grid;
+ int num_planar, cache_num_planar;
+ int total_irradiance_samples; /* Total for all grids */
+ int cache_irradiance_size[3];
+ int update_flag;
+ int updated_bounce;
+ int num_bounce;
+ int cubemap_res;
+ /* Update */
+ bool do_cube_update;
+ bool do_grid_update;
+ /* For rendering probes */
+ float probemat[6][4][4];
+ int layer;
+ float texel_size;
+ float padding_size;
+ float samples_len;
+ float samples_len_inv;
+ float near_clip;
+ float far_clip;
+ float roughness;
+ float firefly_fac;
+ float lodfactor;
+ float lod_rt_max, lod_cube_max, lod_planar_max;
+ float visibility_range;
+ float visibility_blur;
+ float intensity_fac;
+ int shres;
+ int studiolight_index;
+ float studiolight_rot_z;
+ EEVEE_LightProbeVisTest planar_vis_tests[MAX_PLANAR];
+ /* UBO Storage : data used by UBO */
+ EEVEE_LightProbe probe_data[MAX_PROBE];
+ EEVEE_LightGrid grid_data[MAX_GRID];
+ EEVEE_PlanarReflection planar_data[MAX_PLANAR];
+ /* Probe Visibility Collection */
+ EEVEE_LightProbeVisTest vis_data;
+} EEVEE_LightProbesInfo;
+
+/* EEVEE_LightProbesInfo->update_flag */
+enum {
+ PROBE_UPDATE_CUBE = (1 << 0),
+ PROBE_UPDATE_GRID = (1 << 1),
+ PROBE_UPDATE_ALL = 0xFFFFFF,
+};
+
+/* ************ EFFECTS DATA ************* */
+
+typedef enum EEVEE_EffectsFlag {
+ EFFECT_MOTION_BLUR = (1 << 0),
+ EFFECT_BLOOM = (1 << 1),
+ EFFECT_DOF = (1 << 2),
+ EFFECT_VOLUMETRIC = (1 << 3),
+ EFFECT_SSR = (1 << 4),
+ EFFECT_DOUBLE_BUFFER = (1 << 5), /* Not really an effect but a feature */
+ EFFECT_REFRACT = (1 << 6),
+ EFFECT_GTAO = (1 << 7),
+ EFFECT_TAA = (1 << 8),
+ EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */
+ EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */
+ EFFECT_SSS = (1 << 11),
+ EFFECT_VELOCITY_BUFFER = (1 << 12), /* Not really an effect but a feature */
+ EFFECT_TAA_REPROJECT = (1 << 13), /* should be mutually exclusive with EFFECT_TAA */
+ EFFECT_DEPTH_DOUBLE_BUFFER = (1 << 14), /* Not really an effect but a feature */
+} EEVEE_EffectsFlag;
+
+typedef struct EEVEE_EffectsInfo {
+ EEVEE_EffectsFlag enabled_effects;
+ bool swap_double_buffer;
+ /* SSSS */
+ int sss_sample_count;
+ bool sss_separate_albedo;
+ struct GPUTexture *sss_data; /* Textures from pool */
+ struct GPUTexture *sss_albedo;
+ struct GPUTexture *sss_blur;
+ struct GPUTexture *sss_stencil;
+ /* Volumetrics */
+ int volume_current_sample;
+ /* SSR */
+ bool reflection_trace_full;
+ bool ssr_was_persp;
+ int ssr_neighbor_ofs;
+ int ssr_halfres_ofs[2];
+ struct GPUTexture *ssr_normal_input; /* Textures from pool */
+ struct GPUTexture *ssr_specrough_input;
+ struct GPUTexture *ssr_hit_output;
+ struct GPUTexture *ssr_pdf_output;
+ /* Temporal Anti Aliasing */
+ int taa_reproject_sample;
+ int taa_current_sample;
+ int taa_render_sample;
+ int taa_total_sample;
+ float taa_alpha;
+ bool prev_drw_support;
+ float prev_drw_persmat[4][4];
+ float overide_persmat[4][4];
+ float overide_persinv[4][4];
+ float overide_winmat[4][4];
+ float overide_wininv[4][4];
+ /* Ambient Occlusion */
+ int ao_depth_layer;
+ struct GPUTexture *ao_src_depth; /* pointer copy */
+ struct GPUTexture *gtao_horizons; /* Textures from pool */
+ struct GPUTexture *gtao_horizons_debug;
+ /* Motion Blur */
+ float current_ndc_to_world[4][4];
+ float past_world_to_ndc[4][4];
+ int motion_blur_samples;
+ /* Velocity Pass */
+ float velocity_curr_persinv[4][4];
+ float velocity_past_persmat[4][4];
+ struct GPUTexture *velocity_tx; /* Texture from pool */
+ /* Depth Of Field */
+ float dof_near_far[2];
+ float dof_params[3];
+ float dof_bokeh[4];
+ float dof_bokeh_sides[4];
+ int dof_target_size[2];
+ struct GPUTexture *dof_down_near; /* Textures from pool */
+ struct GPUTexture *dof_down_far;
+ struct GPUTexture *dof_coc;
+ struct GPUTexture *dof_blur;
+ struct GPUTexture *dof_blur_alpha;
+ /* Other */
+ float prev_persmat[4][4];
+ /* Bloom */
+ int bloom_iteration_len;
+ float source_texel_size[2];
+ float blit_texel_size[2];
+ float downsamp_texel_size[MAX_BLOOM_STEP][2];
+ float bloom_color[3];
+ float bloom_clamp;
+ float bloom_sample_scale;
+ float bloom_curve_threshold[4];
+ float unf_source_texel_size[2];
+ struct GPUTexture *bloom_blit; /* Textures from pool */
+ struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP];
+ struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP - 1];
+ struct GPUTexture *unf_source_buffer; /* pointer copy */
+ struct GPUTexture *unf_base_buffer; /* pointer copy */
+ /* Not alloced, just a copy of a *GPUtexture in EEVEE_TextureList. */
+ struct GPUTexture *source_buffer; /* latest updated texture */
+ struct GPUFrameBuffer *target_buffer; /* next target to render to */
+ struct GPUTexture *final_tx; /* Final color to transform to display color space. */
+ struct GPUFrameBuffer *final_fb; /* Framebuffer with final_tx as attachement. */
+} EEVEE_EffectsInfo;
+
+/* ***************** COMMON DATA **************** */
+
+/* Common uniform buffer containing all "constant" data over the whole drawing pipeline. */
+/* !! CAUTION !!
+ * - [i]vec3 need to be padded to [i]vec4 (even in ubo declaration).
+ * - Make sure that [i]vec4 start at a multiple of 16 bytes.
+ * - Arrays of vec2/vec3 are padded as arrays of vec4.
+ * - sizeof(bool) == sizeof(int) in GLSL so use int in C */
+typedef struct EEVEE_CommonUniformBuffer {
+ float prev_persmat[4][4]; /* mat4 */
+ float view_vecs[2][4]; /* vec4[2] */
+ float mip_ratio[10][4]; /* vec2[10] */
+ /* Ambient Occlusion */
+ /* -- 16 byte aligned -- */
+ float ao_dist, pad1, ao_factor, pad2; /* vec4 */
+ float ao_offset, ao_bounce_fac, ao_quality, ao_settings; /* vec4 */
+ /* Volumetric */
+ /* -- 16 byte aligned -- */
+ int vol_tex_size[3], pad3; /* ivec3 */
+ float vol_depth_param[3], pad4; /* vec3 */
+ float vol_inv_tex_size[3], pad5; /* vec3 */
+ float vol_jitter[3], pad6; /* vec3 */
+ float vol_coord_scale[2], pad7[2]; /* vec2 */
+ /* -- 16 byte aligned -- */
+ float vol_history_alpha; /* float */
+ float vol_light_clamp; /* float */
+ float vol_shadow_steps; /* float */
+ int vol_use_lights; /* bool */
+ /* Screen Space Reflections */
+ /* -- 16 byte aligned -- */
+ float ssr_quality, ssr_thickness, ssr_pixelsize[2]; /* vec4 */
+ float ssr_border_fac; /* float */
+ float ssr_max_roughness; /* float */
+ float ssr_firefly_fac; /* float */
+ float ssr_brdf_bias; /* float */
+ int ssr_toggle; /* bool */
+ /* SubSurface Scattering */
+ float sss_jitter_threshold; /* float */
+ int sss_toggle; /* bool */
+ /* Specular */
+ int spec_toggle; /* bool */
+ /* Lamps */
+ int la_num_light; /* int */
+ /* Probes */
+ int prb_num_planar; /* int */
+ int prb_num_render_cube; /* int */
+ int prb_num_render_grid; /* int */
+ int prb_irradiance_vis_size; /* int */
+ float prb_irradiance_smooth; /* float */
+ float prb_lod_cube_max; /* float */
+ float prb_lod_planar_max; /* float */
+ /* Misc */
+ int hiz_mip_offset; /* int */
+ int ray_type; /* int */
+ float ray_depth; /* float */
+} EEVEE_CommonUniformBuffer;
+
+/* ray_type (keep in sync with rayType) */
+#define EEVEE_RAY_CAMERA 0
+#define EEVEE_RAY_SHADOW 1
+#define EEVEE_RAY_DIFFUSE 2
+#define EEVEE_RAY_GLOSSY 3
+
+/* ***************** CLIP PLANES DATA **************** */
+
+typedef struct EEVEE_ClipPlanesUniformBuffer {
+ float clip_planes[1][4]; /* must be less than MAX_CLIP_PLANES */
+} EEVEE_ClipPlanesUniformBuffer;
+
+/* ************** SCENE LAYER DATA ************** */
+typedef struct EEVEE_ViewLayerData {
+ /* Lamps */
+ struct EEVEE_LampsInfo *lamps;
+
+ struct GPUUniformBuffer *light_ubo;
+ struct GPUUniformBuffer *shadow_ubo;
+ struct GPUUniformBuffer *shadow_render_ubo;
+ struct GPUUniformBuffer *shadow_samples_ubo;
+
+ struct GPUFrameBuffer *shadow_cube_target_fb;
+ struct GPUFrameBuffer *shadow_cube_store_fb;
+ struct GPUFrameBuffer *shadow_cascade_target_fb;
+ struct GPUFrameBuffer *shadow_cascade_store_fb;
+
+ struct GPUTexture *shadow_cube_target;
+ struct GPUTexture *shadow_cube_blur;
+ struct GPUTexture *shadow_cascade_target;
+ struct GPUTexture *shadow_cascade_blur;
+ struct GPUTexture *shadow_cube_pool;
+ struct GPUTexture *shadow_cascade_pool;
+
+ struct EEVEE_ShadowCasterBuffer shcasters_buffers[2];
+
+ /* Probes */
+ struct EEVEE_LightProbesInfo *probes;
+
+ struct GPUUniformBuffer *probe_ubo;
+ struct GPUUniformBuffer *grid_ubo;
+ struct GPUUniformBuffer *planar_ubo;
+
+ /* Common Uniform Buffer */
+ struct EEVEE_CommonUniformBuffer common_data;
+ struct GPUUniformBuffer *common_ubo;
+
+ struct EEVEE_ClipPlanesUniformBuffer clip_data;
+ struct GPUUniformBuffer *clip_ubo;
+
+ struct LightCache *fallback_lightcache;
+} EEVEE_ViewLayerData;
+
+/* ************ OBJECT DATA ************ */
+
+typedef struct EEVEE_LightData {
+ short light_id, shadow_id;
+} EEVEE_LightData;
+
+typedef struct EEVEE_ShadowCubeData {
+ short light_id, shadow_id, cube_id, layer_id;
+} EEVEE_ShadowCubeData;
+
+typedef struct EEVEE_ShadowCascadeData {
+ short light_id, shadow_id, cascade_id, layer_id;
+ float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */
+ float projmat[MAX_CASCADE_NUM][4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float radius[MAX_CASCADE_NUM];
+} EEVEE_ShadowCascadeData;
+
+/* Theses are the structs stored inside Objects.
+ * It works with even if the object is in multiple layers
+ * because we don't get the same "Object *" for each layer. */
+typedef struct EEVEE_LampEngineData {
+ DrawData dd;
+
+ bool need_update;
+ /* This needs to be out of the union to avoid undefined behaviour. */
+ short prev_cube_shadow_id;
+ union {
+ struct EEVEE_LightData ld;
+ struct EEVEE_ShadowCubeData scd;
+ struct EEVEE_ShadowCascadeData scad;
+ } data;
+} EEVEE_LampEngineData;
+
+typedef struct EEVEE_LightProbeEngineData {
+ DrawData dd;
+
+ bool need_update;
+} EEVEE_LightProbeEngineData;
+
+typedef struct EEVEE_ObjectEngineData {
+ DrawData dd;
+
+ Object *ob; /* self reference */
+ EEVEE_LightProbeVisTest *test_data;
+ bool ob_vis, ob_vis_dirty;
+
+ bool need_update;
+ uint shadow_caster_id;
+} EEVEE_ObjectEngineData;
+
+typedef struct EEVEE_WorldEngineData {
+ DrawData dd;
+} EEVEE_WorldEngineData;
+
+/* *********************************** */
+
+typedef struct EEVEE_Data {
+ void *engine_type;
+ EEVEE_FramebufferList *fbl;
+ EEVEE_TextureList *txl;
+ EEVEE_PassList *psl;
+ EEVEE_StorageList *stl;
+} EEVEE_Data;
+
+typedef struct EEVEE_PrivateData {
+ struct DRWShadingGroup *shadow_shgrp;
+ struct DRWShadingGroup *depth_shgrp;
+ struct DRWShadingGroup *depth_shgrp_cull;
+ struct DRWShadingGroup *depth_shgrp_clip;
+ struct DRWShadingGroup *depth_shgrp_clip_cull;
+ struct DRWShadingGroup *refract_depth_shgrp;
+ struct DRWShadingGroup *refract_depth_shgrp_cull;
+ struct DRWShadingGroup *refract_depth_shgrp_clip;
+ struct DRWShadingGroup *refract_depth_shgrp_clip_cull;
+ struct DRWShadingGroup *cube_display_shgrp;
+ struct DRWShadingGroup *planar_display_shgrp;
+ struct GHash *material_hash;
+ float background_alpha; /* TODO find a better place for this. */
+ /* Chosen lightcache: can come from Lookdev or the viewlayer. */
+ struct LightCache *light_cache;
+ /* For planar probes */
+ float planar_texel_size[2];
+ /* For double buffering */
+ bool view_updated;
+ bool valid_double_buffer;
+ bool valid_taa_history;
+ /* Render Matrices */
+ float persmat[4][4], persinv[4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float winmat[4][4], wininv[4][4];
+ float studiolight_matrix[3][3];
+ float overscan, overscan_pixels;
+ float size_orig[2];
+
+ /* Mist Settings */
+ float mist_start, mist_inv_dist, mist_falloff;
+
+ /* Color Management */
+ bool use_color_view_settings;
+} EEVEE_PrivateData; /* Transient data */
+
+/* eevee_data.c */
+void EEVEE_view_layer_data_free(void *sldata);
+EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void);
+EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer);
+EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void);
+EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob);
+EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob);
+EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob);
+EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob);
+EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob);
+EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob);
+EEVEE_WorldEngineData *EEVEE_world_data_get(World *wo);
+EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo);
+
+/* eevee_materials.c */
+struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
+void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl);
+void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow);
+void EEVEE_hair_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow);
+void EEVEE_materials_cache_finish(EEVEE_Data *vedata);
+struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);
+struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo);
+struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo);
+struct GPUMaterial *EEVEE_material_mesh_get(
+ struct Scene *scene, Material *ma, EEVEE_Data *vedata,
+ bool use_blend, bool use_multiply, bool use_refract, bool use_sss, bool use_translucency, int shadow_method);
+struct GPUMaterial *EEVEE_material_mesh_volume_get(
+ struct Scene *scene, Material *ma);
+struct GPUMaterial *EEVEE_material_mesh_depth_get(
+ struct Scene *scene, Material *ma, bool use_hashed_alpha, bool is_shadow);
+struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method);
+void EEVEE_materials_free(void);
+void EEVEE_draw_default_passes(EEVEE_PassList *psl);
+void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]);
+
+/* eevee_lights.c */
+void EEVEE_lights_init(EEVEE_ViewLayerData *sldata);
+void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
+void EEVEE_lights_cache_shcaster_add(
+ EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, struct GPUBatch *geom, Object *ob);
+void EEVEE_lights_cache_shcaster_material_add(
+ EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl,
+ struct GPUMaterial *gpumat, struct GPUBatch *geom, struct Object *ob,
+ float *alpha_threshold);
+void EEVEE_lights_cache_shcaster_object_add(EEVEE_ViewLayerData *sldata, struct Object *ob);
+void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lights_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lights_free(void);
+
+
+/* eevee_shaders.c */
+void EEVEE_shaders_lightprobe_shaders_init(void);
+struct GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void);
+struct GPUShader *EEVEE_shaders_probe_default_sh_get(void);
+struct GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void);
+struct GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void);
+struct GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void);
+struct GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void);
+struct GPUShader *EEVEE_shaders_default_studiolight_sh_get(void);
+struct GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void);
+struct GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void);
+struct GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void);
+struct GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void);
+struct GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects);
+void EEVEE_shaders_free(void);
+
+/* eevee_lightprobes.c */
+bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data);
+void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *ob);
+void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_lightprobes_free(void);
+
+void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPUTexture *rt_color, GPUTexture *rt_depth);
+void EEVEE_lightbake_render_world(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6]);
+void EEVEE_lightbake_render_scene(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUFrameBuffer *face_fb[6],
+ const float pos[3], float near_clip, float far_clip);
+void EEVEE_lightbake_filter_glossy(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *rt_color, struct GPUFrameBuffer *fb,
+ int probe_idx, float intensity, int maxlevel, float filter_quality, float firefly_fac);
+void EEVEE_lightbake_filter_diffuse(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *rt_color, struct GPUFrameBuffer *fb,
+ int grid_offset, float intensity);
+void EEVEE_lightbake_filter_visibility(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *rt_depth, struct GPUFrameBuffer *fb,
+ int grid_offset, float clipsta, float clipend, float vis_range, float vis_blur, int vis_size);
+
+void EEVEE_lightprobes_grid_data_from_object(Object *ob, EEVEE_LightGrid *prb_data, int *offset);
+void EEVEE_lightprobes_cube_data_from_object(Object *ob, EEVEE_LightProbe *prb_data);
+void EEVEE_lightprobes_planar_data_from_object(Object *ob, EEVEE_PlanarReflection *eplanar, EEVEE_LightProbeVisTest *vis_test);
+
+/* eevee_depth_of_field.c */
+int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
+void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_depth_of_field_draw(EEVEE_Data *vedata);
+void EEVEE_depth_of_field_free(void);
+
+/* eevee_bloom.c */
+int EEVEE_bloom_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_bloom_draw(EEVEE_Data *vedata);
+void EEVEE_bloom_free(void);
+
+/* eevee_occlusion.c */
+int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
+void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_occlusion_free(void);
+
+/* eevee_screen_raytrace.c */
+int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_refraction_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_reflection_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_screen_raytrace_free(void);
+
+/* eevee_subsurface.c */
+int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_subsurface_add_pass(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint sss_id, struct GPUUniformBuffer *sss_profile);
+void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_subsurface_free(void);
+
+/* eevee_motion_blur.c */
+int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
+void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_motion_blur_draw(EEVEE_Data *vedata);
+void EEVEE_motion_blur_free(void);
+
+/* eevee_mist.c */
+void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_mist_free(void);
+
+/* eevee_temporal_sampling.c */
+void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
+int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_temporal_sampling_matrices_calc(
+ EEVEE_EffectsInfo *effects, float viewmat[4][4], float persmat[4][4], const double ht_point[2]);
+void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata);
+
+/* eevee_volumes.c */
+int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample);
+void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct Scene *scene, Object *ob);
+void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_volumes_resolve(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_volumes_free_smoke_textures(void);
+void EEVEE_volumes_free(void);
+
+/* eevee_effects.c */
+void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera, const bool minimal);
+void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer);
+void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level);
+void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level);
+void EEVEE_effects_do_gtao(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
+void EEVEE_effects_free(void);
+
+/* eevee_render.c */
+void EEVEE_render_init(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void EEVEE_render_cache(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect);
+void EEVEE_render_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer);
+
+/** eevee_lookdev.c */
+void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, DRWShadingGroup **grp, DRWPass *pass, struct World *world, EEVEE_LightProbesInfo *pinfo);
+void EEVEE_lookdev_draw_background(EEVEE_Data *vedata);
+
+/** eevee_engine.c */
+void EEVEE_cache_populate(void *vedata, Object *ob);
+
+/* Shadow Matrix */
+static const float texcomat[4][4] = { /* From NDC to TexCo */
+ {0.5f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.5f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.5f, 0.0f},
+ {0.5f, 0.5f, 0.5f, 1.0f}
+};
+
+/* Cubemap Matrices */
+static const float cubefacemat[6][4][4] = {
+ /* Pos X */
+ {{0.0f, 0.0f, -1.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f, 0.0f},
+ {-1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}},
+ /* Neg X */
+ {{0.0f, 0.0f, 1.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f, 0.0f},
+ {1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}},
+ /* Pos Y */
+ {{1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, -1.0f, 0.0f},
+ {0.0f, 1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}},
+ /* Neg Y */
+ {{1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}},
+ /* Pos Z */
+ {{1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, -1.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}},
+ /* Neg Z */
+ {{-1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}},
+};
+
+#endif /* __EEVEE_PRIVATE_H__ */
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
new file mode 100644
index 00000000000..8d196ee07eb
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_render.c
+ * \ingroup draw_engine
+ */
+
+/**
+ * Render functions for final render outputs.
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_camera.h"
+
+#include "BLI_rand.h"
+#include "BLI_rect.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_glew.h"
+#include "GPU_state.h"
+
+#include "RE_pipeline.h"
+
+#include "eevee_private.h"
+
+void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph)
+{
+ EEVEE_Data *vedata = (EEVEE_Data *)ved;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ const float *size_orig = DRW_viewport_size_get();
+
+ /* Init default FB and render targets:
+ * In render mode the default framebuffer is not generated
+ * because there is no viewport. So we need to manually create it or
+ * not use it. For code clarity we just allocate it make use of it. */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ /* Alloc transient data. */
+ if (!stl->g_data) {
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+ EEVEE_PrivateData *g_data = stl->g_data;
+ g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f;
+ g_data->valid_double_buffer = 0;
+ copy_v2_v2(g_data->size_orig, size_orig);
+
+ if (scene->eevee.flag & SCE_EEVEE_OVERSCAN) {
+ g_data->overscan = scene->eevee.overscan / 100.0f;
+ g_data->overscan_pixels = roundf(max_ff(size_orig[0], size_orig[1]) * g_data->overscan);
+ }
+ else {
+ g_data->overscan = 0.0f;
+ g_data->overscan_pixels = 0.0f;
+ }
+
+ /* XXX overiding viewport size. Simplify things but is not really 100% safe. */
+ DRW_render_viewport_size_set((int[2]){size_orig[0] + g_data->overscan_pixels * 2.0f,
+ size_orig[1] + g_data->overscan_pixels * 2.0f});
+
+ /* TODO 32 bit depth */
+ DRW_texture_ensure_fullscreen_2D(&dtxl->depth, GPU_DEPTH24_STENCIL8, 0);
+ DRW_texture_ensure_fullscreen_2D(&txl->color, GPU_RGBA32F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
+
+ GPU_framebuffer_ensure_config(&dfbl->default_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(txl->color)
+ });
+ GPU_framebuffer_ensure_config(&fbl->main_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(txl->color)
+ });
+ GPU_framebuffer_ensure_config(&fbl->main_color_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->color)
+ });
+
+ /* Alloc common ubo data. */
+ if (sldata->common_ubo == NULL) {
+ sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data);
+ }
+ if (sldata->clip_ubo == NULL) {
+ sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data);
+ }
+
+ /* Set the pers & view matrix. */
+ /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */
+ struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
+ float frame = BKE_scene_frame_get(scene);
+ RE_GetCameraWindow(engine->re, ob_camera_eval, frame, g_data->winmat);
+ RE_GetCameraModelMatrix(engine->re, ob_camera_eval, g_data->viewinv);
+
+ RE_GetCameraWindowWithOverscan(engine->re, g_data->winmat, g_data->overscan);
+
+ invert_m4_m4(g_data->viewmat, g_data->viewinv);
+ mul_m4_m4m4(g_data->persmat, g_data->winmat, g_data->viewmat);
+ invert_m4_m4(g_data->persinv, g_data->persmat);
+ invert_m4_m4(g_data->wininv, g_data->winmat);
+
+ DRW_viewport_matrix_override_set(g_data->persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(g_data->persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(g_data->winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(g_data->wininv, DRW_MAT_WININV);
+ DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV);
+
+ /* EEVEE_effects_init needs to go first for TAA */
+ EEVEE_effects_init(sldata, vedata, ob_camera_eval, false);
+ EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_lights_init(sldata);
+ EEVEE_lightprobes_init(sldata, vedata);
+
+ /* INIT CACHE */
+ EEVEE_bloom_cache_init(sldata, vedata);
+ EEVEE_depth_of_field_cache_init(sldata, vedata);
+ EEVEE_effects_cache_init(sldata, vedata);
+ EEVEE_lightprobes_cache_init(sldata, vedata);
+ EEVEE_lights_cache_init(sldata, vedata);
+ EEVEE_materials_cache_init(sldata, vedata);
+ EEVEE_motion_blur_cache_init(sldata, vedata);
+ EEVEE_occlusion_cache_init(sldata, vedata);
+ EEVEE_screen_raytrace_cache_init(sldata, vedata);
+ EEVEE_subsurface_cache_init(sldata, vedata);
+ EEVEE_temporal_sampling_cache_init(sldata, vedata);
+ EEVEE_volumes_cache_init(sldata, vedata);
+}
+
+/* Used by light cache. in this case engine is NULL. */
+void EEVEE_render_cache(
+ void *vedata, struct Object *ob,
+ struct RenderEngine *engine, struct Depsgraph *UNUSED(depsgraph))
+{
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ bool cast_shadow = false;
+
+ if (pinfo->vis_data.collection) {
+ /* Used for rendering probe with visibility groups. */
+ bool ob_vis = BKE_collection_has_object_recursive(pinfo->vis_data.collection, ob);
+ ob_vis = (pinfo->vis_data.invert) ? !ob_vis : ob_vis;
+
+ if (!ob_vis) {
+ return;
+ }
+ }
+
+ if (engine) {
+ char info[42];
+ BLI_snprintf(info, sizeof(info), "Syncing %s", ob->id.name + 2);
+ RE_engine_update_stats(engine, NULL, info);
+ }
+
+ if (ob->base_flag & BASE_VISIBLE) {
+ EEVEE_hair_cache_populate(vedata, sldata, ob, &cast_shadow);
+ }
+
+ if (DRW_object_is_visible_in_active_context(ob)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
+ EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
+ }
+ else if (ob->type == OB_LIGHTPROBE) {
+ EEVEE_lightprobes_cache_add(sldata, vedata, ob);
+ }
+ else if (ob->type == OB_LAMP) {
+ EEVEE_lights_cache_add(sldata, ob);
+ }
+ }
+
+ if (cast_shadow) {
+ EEVEE_lights_cache_shcaster_object_add(sldata, ob);
+ }
+}
+
+static void eevee_render_result_combined(
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata))
+{
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
+
+ GPU_framebuffer_bind(vedata->stl->effects->final_fb);
+ GPU_framebuffer_read_color(vedata->stl->effects->final_fb,
+ vedata->stl->g_data->overscan_pixels + rect->xmin,
+ vedata->stl->g_data->overscan_pixels + rect->ymin,
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
+ 4, 0, rp->rect);
+
+ /* Premult alpha */
+ int pixels_len = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+ for (int i = 0; i < pixels_len * 4; i += 4) {
+ mul_v3_fl(rp->rect + i, rp->rect[i + 3]);
+ }
+}
+
+static void eevee_render_result_subsurface(
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ if (vedata->fbl->sss_accum_fb == NULL) {
+ /* SSS is not enabled. */
+ return;
+ }
+
+ if ((view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_COLOR, viewname);
+
+ GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
+ GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
+ vedata->stl->g_data->overscan_pixels + rect->xmin,
+ vedata->stl->g_data->overscan_pixels + rect->ymin,
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
+ 3, 1, rp->rect);
+
+ /* This is the accumulated color. Divide by the number of samples. */
+ for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
+ rp->rect[i] /= (float)render_samples;
+ }
+ }
+
+ if ((view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_DIRECT, viewname);
+
+ GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
+ GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
+ vedata->stl->g_data->overscan_pixels + rect->xmin,
+ vedata->stl->g_data->overscan_pixels + rect->ymin,
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
+ 3, 0, rp->rect);
+
+ /* This is the accumulated color. Divide by the number of samples. */
+ for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
+ rp->rect[i] /= (float)render_samples;
+ }
+ }
+
+ if ((view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) != 0) {
+ /* Do nothing as all the lighting is in the direct pass.
+ * TODO : Separate Direct from indirect lighting. */
+ }
+}
+
+static void eevee_render_result_normal(
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata))
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+
+ /* Only read the center texel. */
+ if (stl->effects->taa_current_sample > 1)
+ return;
+
+ if ((view_layer->passflag & SCE_PASS_NORMAL) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_NORMAL, viewname);
+
+ GPU_framebuffer_bind(vedata->fbl->main_fb);
+ GPU_framebuffer_read_color(vedata->fbl->main_fb,
+ g_data->overscan_pixels + rect->xmin,
+ g_data->overscan_pixels + rect->ymin,
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
+ 3, 1, rp->rect);
+
+ /* Convert Eevee encoded normals to Blender normals. */
+ for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
+ if (rp->rect[i] == 0.0f && rp->rect[i + 1] == 0.0f) {
+ /* If normal is not correct then do not produce NANs. */
+ continue;
+ }
+
+ float fenc[2];
+ fenc[0] = rp->rect[i + 0] * 4.0f - 2.0f;
+ fenc[1] = rp->rect[i + 1] * 4.0f - 2.0f;
+
+ float f = dot_v2v2(fenc, fenc);
+ float g = sqrtf(1.0f - f / 4.0f);
+
+ rp->rect[i + 0] = fenc[0] * g;
+ rp->rect[i + 1] = fenc[1] * g;
+ rp->rect[i + 2] = 1.0f - f / 2.0f;
+
+ mul_mat3_m4_v3(g_data->viewinv, &rp->rect[i]);
+ }
+ }
+}
+
+static void eevee_render_result_z(
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *g_data = stl->g_data;
+
+ /* Only read the center texel. */
+ if (stl->effects->taa_current_sample > 1)
+ return;
+
+ if ((view_layer->passflag & SCE_PASS_Z) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
+
+ GPU_framebuffer_bind(vedata->fbl->main_fb);
+ GPU_framebuffer_read_depth(vedata->fbl->main_fb,
+ g_data->overscan_pixels + rect->xmin,
+ g_data->overscan_pixels + rect->ymin,
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
+ rp->rect);
+
+ bool is_persp = DRW_viewport_is_persp_get();
+
+ /* Convert ogl depth [0..1] to view Z [near..far] */
+ for (int i = 0; i < rp->rectx * rp->recty; ++i) {
+ if (rp->rect[i] == 1.0f ) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
+ if (is_persp) {
+ rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
+ rp->rect[i] = g_data->winmat[3][2] / (rp->rect[i] + g_data->winmat[2][2]);
+ }
+ else {
+ rp->rect[i] = -common_data->view_vecs[0][2] + rp->rect[i] * -common_data->view_vecs[1][2];
+ }
+ }
+ }
+ }
+}
+
+static void eevee_render_result_mist(
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_MIST, viewname);
+
+ GPU_framebuffer_bind(vedata->fbl->mist_accum_fb);
+ GPU_framebuffer_read_color(vedata->fbl->mist_accum_fb,
+ vedata->stl->g_data->overscan_pixels + rect->xmin,
+ vedata->stl->g_data->overscan_pixels + rect->ymin,
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
+ 1, 0, rp->rect);
+
+ /* This is the accumulated color. Divide by the number of samples. */
+ for (int i = 0; i < rp->rectx * rp->recty; i++) {
+ rp->rect[i] /= (float)render_samples;
+ }
+ }
+}
+
+static void eevee_render_result_occlusion(
+ RenderLayer *rl, const char *viewname, const rcti *rect,
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ if (vedata->fbl->ao_accum_fb == NULL) {
+ /* AO is not enabled. */
+ return;
+ }
+
+ if ((view_layer->passflag & SCE_PASS_AO) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_AO, viewname);
+
+ GPU_framebuffer_bind(vedata->fbl->ao_accum_fb);
+ GPU_framebuffer_read_color(vedata->fbl->ao_accum_fb,
+ vedata->stl->g_data->overscan_pixels + rect->xmin,
+ vedata->stl->g_data->overscan_pixels + rect->ymin,
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
+ 3, 0, rp->rect);
+
+ /* This is the accumulated color. Divide by the number of samples. */
+ for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
+ rp->rect[i] = rp->rect[i + 1] = rp->rect[i + 2] = min_ff(1.0f, rp->rect[i] / (float)render_samples);
+ }
+ }
+}
+
+static void eevee_render_draw_background(EEVEE_Data *vedata)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PassList *psl = vedata->psl;
+
+ /* Prevent background to write to data buffers.
+ * NOTE : This also make sure the textures are bound
+ * to the right double buffer. */
+ GPU_framebuffer_ensure_config(&fbl->main_fb, {
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE
+ });
+ GPU_framebuffer_bind(fbl->main_fb);
+
+ DRW_draw_pass(psl->background_pass);
+
+ GPU_framebuffer_ensure_config(&fbl->main_fb, {
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_normal_input),
+ GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_specrough_input),
+ GPU_ATTACHMENT_TEXTURE(stl->effects->sss_data),
+ GPU_ATTACHMENT_TEXTURE(stl->effects->sss_albedo)
+ });
+ GPU_framebuffer_bind(fbl->main_fb);
+}
+
+void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl, const rcti *rect)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ const char *viewname = RE_GetActiveRenderView(engine->re);
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
+ EEVEE_PrivateData *g_data = stl->g_data;
+
+ /* FINISH CACHE */
+ EEVEE_materials_cache_finish(vedata);
+ EEVEE_lights_cache_finish(sldata, vedata);
+ EEVEE_lightprobes_cache_finish(sldata, vedata);
+
+ /* Sort transparents before the loop. */
+ DRW_pass_sort_shgroup_z(psl->transparent_pass);
+
+ /* Push instances attribs to the GPU. */
+ DRW_render_instance_buffer_finish();
+
+ /* Need to be called after DRW_render_instance_buffer_finish() */
+ /* Also we weed to have a correct fbo bound for DRW_hair_update */
+ GPU_framebuffer_bind(fbl->main_fb);
+ DRW_hair_update();
+
+ if ((view_layer->passflag & (SCE_PASS_SUBSURFACE_COLOR |
+ SCE_PASS_SUBSURFACE_DIRECT |
+ SCE_PASS_SUBSURFACE_INDIRECT)) != 0)
+ {
+ EEVEE_subsurface_output_init(sldata, vedata);
+ }
+
+ if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
+ EEVEE_mist_output_init(sldata, vedata);
+ }
+
+ if ((view_layer->passflag & SCE_PASS_AO) != 0) {
+ EEVEE_occlusion_output_init(sldata, vedata);
+ }
+
+ uint tot_sample = scene_eval->eevee.taa_render_samples;
+ uint render_samples = 0;
+
+ if (RE_engine_test_break(engine)) {
+ return;
+ }
+
+ while (render_samples < tot_sample && !RE_engine_test_break(engine)) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float clear_depth = 1.0f;
+ uint clear_stencil = 0x00;
+ uint primes[3] = {2, 3, 7};
+ double offset[3] = {0.0, 0.0, 0.0};
+ double r[3];
+
+ /* Restore winmat before jittering again. */
+ copy_m4_m4(stl->effects->overide_winmat, g_data->winmat);
+ /* Copy previous persmat to UBO data */
+ copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat);
+
+ BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r);
+ EEVEE_update_noise(psl, fbl, r);
+ EEVEE_temporal_sampling_matrices_calc(stl->effects, g_data->viewmat, g_data->persmat, r);
+ EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1);
+ EEVEE_materials_init(sldata, stl, fbl);
+
+ /* Set matrices. */
+ DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV);
+ DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV);
+
+ /* Refresh Probes */
+ RE_engine_update_stats(engine, NULL, "Updating Probes");
+ EEVEE_lightprobes_refresh(sldata, vedata);
+ EEVEE_lightprobes_refresh_planar(sldata, vedata);
+
+ char info[42];
+ BLI_snprintf(info, sizeof(info), "Rendering %u / %u samples", render_samples + 1, tot_sample);
+ RE_engine_update_stats(engine, NULL, info);
+
+ /* Refresh Shadows */
+ EEVEE_lights_update(sldata, vedata);
+ EEVEE_draw_shadows(sldata, vedata);
+
+ /* Set ray type. */
+ sldata->common_data.ray_type = EEVEE_RAY_CAMERA;
+ sldata->common_data.ray_depth = 0.0f;
+ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
+
+ GPU_framebuffer_bind(fbl->main_fb);
+ GPU_framebuffer_clear_color_depth_stencil(fbl->main_fb, clear_col, clear_depth, clear_stencil);
+ /* Depth prepass */
+ DRW_draw_pass(psl->depth_pass);
+ DRW_draw_pass(psl->depth_pass_cull);
+ /* Create minmax texture */
+ EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
+ EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
+ EEVEE_volumes_compute(sldata, vedata);
+ /* Shading pass */
+ eevee_render_draw_background(vedata);
+ GPU_framebuffer_bind(fbl->main_fb);
+ EEVEE_draw_default_passes(psl);
+ DRW_draw_pass(psl->material_pass);
+ EEVEE_subsurface_data_render(sldata, vedata);
+ /* Effects pre-transparency */
+ EEVEE_subsurface_compute(sldata, vedata);
+ EEVEE_reflection_compute(sldata, vedata);
+ EEVEE_refraction_compute(sldata, vedata);
+ /* Opaque refraction */
+ DRW_draw_pass(psl->refract_depth_pass);
+ DRW_draw_pass(psl->refract_depth_pass_cull);
+ DRW_draw_pass(psl->refract_pass);
+ /* Subsurface output */
+ EEVEE_subsurface_output_accumulate(sldata, vedata);
+ /* Occlusion output */
+ EEVEE_occlusion_output_accumulate(sldata, vedata);
+ /* Result NORMAL */
+ eevee_render_result_normal(rl, viewname, rect, vedata, sldata);
+ /* Volumetrics Resolve Opaque */
+ EEVEE_volumes_resolve(sldata, vedata);
+ /* Mist output */
+ EEVEE_mist_output_accumulate(sldata, vedata);
+ /* Transparent */
+ DRW_draw_pass(psl->transparent_pass);
+ /* Result Z */
+ eevee_render_result_z(rl, viewname, rect, vedata, sldata);
+ /* Post Process */
+ EEVEE_draw_effects(sldata, vedata);
+
+ /* XXX Seems to fix TDR issue with NVidia drivers on linux. */
+ GPU_finish();
+
+ RE_engine_update_progress(engine, (float)(render_samples++) / (float)tot_sample);
+ }
+
+ eevee_render_result_combined(rl, viewname, rect, vedata, sldata);
+ eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata, render_samples);
+ eevee_render_result_mist(rl, viewname, rect, vedata, sldata, render_samples);
+ eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata, render_samples);
+
+ /* Restore original viewport size. */
+ DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]});
+}
+
+void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
+{
+ int type;
+
+ RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
+
+#define CHECK_PASS(name, channels, chanid) \
+ if (view_layer->passflag & (SCE_PASS_ ## name)) { \
+ if (channels == 4) type = SOCK_RGBA; \
+ else if (channels == 3) type = SOCK_VECTOR; \
+ else type = SOCK_FLOAT; \
+ RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_ ## name, channels, chanid, type); \
+ }
+
+ CHECK_PASS(Z, 1, "Z");
+ CHECK_PASS(MIST, 1, "Z");
+ CHECK_PASS(NORMAL, 3, "XYZ");
+ CHECK_PASS(AO, 3, "RGB");
+ CHECK_PASS(SUBSURFACE_COLOR, 3, "RGB");
+ CHECK_PASS(SUBSURFACE_DIRECT, 3, "RGB");
+
+#undef CHECK_PASS
+}
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
new file mode 100644
index 00000000000..13bedc34e05
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_screen_raytrace.c
+ * \ingroup draw_engine
+ *
+ * Screen space reflections and refractions techniques.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+#include "GPU_texture.h"
+
+/* SSR shader variations */
+enum {
+ SSR_RESOLVE = (1 << 0),
+ SSR_FULL_TRACE = (1 << 1),
+ SSR_AO = (1 << 3),
+ SSR_MAX_SHADER = (1 << 4),
+};
+
+static struct {
+ /* Screen Space Reflection */
+ struct GPUShader *ssr_sh[SSR_MAX_SHADER];
+
+ /* Theses are just references, not actually allocated */
+ struct GPUTexture *depth_src;
+ struct GPUTexture *color_src;
+} e_data = {{NULL}}; /* Engine data */
+
+extern char datatoc_ambient_occlusion_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_effect_ssr_frag_glsl[];
+extern char datatoc_lightprobe_lib_glsl[];
+extern char datatoc_raytrace_lib_glsl[];
+
+static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
+{
+ if (e_data.ssr_sh[options] == NULL) {
+ char *ssr_shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_raytrace_lib_glsl,
+ datatoc_effect_ssr_frag_glsl);
+
+ DynStr *ds_defines = BLI_dynstr_new();
+ BLI_dynstr_appendf(ds_defines, SHADER_DEFINES);
+ if (options & SSR_RESOLVE) {
+ BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n");
+ }
+ else {
+ BLI_dynstr_appendf(ds_defines, "#define STEP_RAYTRACE\n");
+ BLI_dynstr_appendf(ds_defines, "#define PLANAR_PROBE_RAYTRACE\n");
+ }
+ if (options & SSR_FULL_TRACE) {
+ BLI_dynstr_appendf(ds_defines, "#define FULLRES\n");
+ }
+ if (options & SSR_AO) {
+ BLI_dynstr_appendf(ds_defines, "#define SSR_AO\n");
+ }
+ char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines);
+ BLI_dynstr_free(ds_defines);
+
+ e_data.ssr_sh[options] = DRW_shader_create_fullscreen(ssr_shader_str, ssr_define_str);
+
+ MEM_freeN(ssr_shader_str);
+ MEM_freeN(ssr_define_str);
+ }
+
+ return e_data.ssr_sh[options];
+}
+
+int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ const float *viewport_size = DRW_viewport_size_get();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ /* Compute pixel size, (shared with contact shadows) */
+ copy_v2_v2(common_data->ssr_pixelsize, viewport_size);
+ invert_v2(common_data->ssr_pixelsize);
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_SSR_ENABLED) {
+ const bool use_refraction = (scene_eval->eevee.flag & SCE_EEVEE_SSR_REFRACTION) != 0;
+
+ if (use_refraction) {
+ /* TODO: Opti: Could be shared. */
+ DRW_texture_ensure_fullscreen_2D(&txl->refract_color, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
+
+ GPU_framebuffer_ensure_config(&fbl->refract_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->refract_color)
+ });
+ }
+
+ const bool is_persp = DRW_viewport_is_persp_get();
+ if (effects->ssr_was_persp != is_persp) {
+ effects->ssr_was_persp = is_persp;
+ DRW_viewport_request_redraw();
+ EEVEE_temporal_sampling_reset(vedata);
+ stl->g_data->valid_double_buffer = false;
+ }
+
+ effects->reflection_trace_full = (scene_eval->eevee.flag & SCE_EEVEE_SSR_HALF_RESOLUTION) == 0;
+ common_data->ssr_thickness = scene_eval->eevee.ssr_thickness;
+ common_data->ssr_border_fac = scene_eval->eevee.ssr_border_fade;
+ common_data->ssr_firefly_fac = scene_eval->eevee.ssr_firefly_fac;
+ common_data->ssr_max_roughness = scene_eval->eevee.ssr_max_roughness;
+ common_data->ssr_quality = 1.0f - 0.95f * scene_eval->eevee.ssr_quality;
+ common_data->ssr_brdf_bias = 0.1f + common_data->ssr_quality * 0.6f; /* Range [0.1, 0.7]. */
+
+ if (common_data->ssr_firefly_fac < 1e-8f) {
+ common_data->ssr_firefly_fac = FLT_MAX;
+ }
+
+ const int divisor = (effects->reflection_trace_full) ? 1 : 2;
+ int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor};
+ int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+ const bool high_qual_input = true; /* TODO dither low quality input */
+ const GPUTextureFormat format = (high_qual_input) ? GPU_RGBA16F : GPU_RGBA8;
+
+ /* MRT for the shading pass in order to output needed data for the SSR pass. */
+ effects->ssr_specrough_input = DRW_texture_pool_query_2D(size_fs[0], size_fs[1], format,
+ &draw_engine_eevee_type);
+
+ GPU_framebuffer_texture_attach(fbl->main_fb, effects->ssr_specrough_input, 2, 0);
+
+ /* Raytracing output */
+ effects->ssr_hit_output = DRW_texture_pool_query_2D(tracing_res[0], tracing_res[1], GPU_RG16I,
+ &draw_engine_eevee_type);
+ effects->ssr_pdf_output = DRW_texture_pool_query_2D(tracing_res[0], tracing_res[1], GPU_R16F,
+ &draw_engine_eevee_type);
+
+ GPU_framebuffer_ensure_config(&fbl->screen_tracing_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output),
+ GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output)
+ });
+
+ /* Enable double buffering to be able to read previous frame color */
+ return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0);
+ }
+
+ /* Cleanup to release memory */
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb);
+ effects->ssr_specrough_input = NULL;
+ effects->ssr_hit_output = NULL;
+ effects->ssr_pdf_output = NULL;
+
+ return 0;
+}
+
+void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ LightCache *lcache = stl->g_data->light_cache;
+
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ if ((effects->enabled_effects & EFFECT_SSR) != 0) {
+ int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0;
+ options |= ((effects->enabled_effects & EFFECT_GTAO) != 0) ? SSR_AO : 0;
+
+ struct GPUShader *trace_shader = eevee_effects_screen_raytrace_shader_get(options);
+ struct GPUShader *resolve_shader = eevee_effects_screen_raytrace_shader_get(SSR_RESOLVE | options);
+
+ /** Screen space raytracing overview
+ *
+ * Following Frostbite stochastic SSR.
+ *
+ * - First pass Trace rays across the depth buffer. The hit position and pdf are
+ * recorded in a RGBA16F render target for each ray (sample).
+ *
+ * - We downsample the previous frame color buffer.
+ *
+ * - For each final pixel, we gather neighbors rays and choose a color buffer
+ * mipmap for each ray using its pdf. (filtered importance sampling)
+ * We then evaluate the lighting from the probes and mix the results together.
+ */
+ psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
+ DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input);
+ DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
+ DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ if (!effects->reflection_trace_full) {
+ DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1);
+ }
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
+ grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
+ DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input);
+ DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
+ DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth);
+ DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output);
+ DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output);
+ DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
+ if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
+ }
+
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+}
+
+void EEVEE_refraction_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & EFFECT_REFRACT) != 0) {
+ GPU_framebuffer_blit(fbl->main_fb, 0, fbl->refract_fb, 0, GPU_COLOR_BIT);
+ EEVEE_downsample_buffer(vedata, txl->refract_color, 9);
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+ }
+}
+
+void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if (((effects->enabled_effects & EFFECT_SSR) != 0) && stl->g_data->valid_double_buffer) {
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ e_data.depth_src = dtxl->depth;
+
+ DRW_stats_group_start("SSR");
+
+ /* Raytrace. */
+ GPU_framebuffer_bind(fbl->screen_tracing_fb);
+ DRW_draw_pass(psl->ssr_raytrace);
+
+ EEVEE_downsample_buffer(vedata, txl->color_double_buffer, 9);
+
+ /* Resolve at fullres */
+ int sample = (DRW_state_is_image_render()) ? effects->taa_render_sample : effects->taa_current_sample;
+ /* Doing a neighbor shift only after a few iteration. We wait for a prime number of cycles to avoid
+ * noise correlation. This reduces variance faster. */
+ effects->ssr_neighbor_ofs = ((sample / 5) % 8) * 4;
+ switch ((sample / 11) % 4) {
+ case 0:
+ effects->ssr_halfres_ofs[0] = 0;
+ effects->ssr_halfres_ofs[1] = 0;
+ break;
+ case 1:
+ effects->ssr_halfres_ofs[0] = 0;
+ effects->ssr_halfres_ofs[1] = 1;
+ break;
+ case 2:
+ effects->ssr_halfres_ofs[0] = 1;
+ effects->ssr_halfres_ofs[1] = 0;
+ break;
+ case 4:
+ effects->ssr_halfres_ofs[0] = 1;
+ effects->ssr_halfres_ofs[1] = 1;
+ break;
+ }
+ GPU_framebuffer_bind(fbl->main_color_fb);
+ DRW_draw_pass(psl->ssr_resolve);
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+ DRW_stats_group_end();
+ }
+}
+
+void EEVEE_screen_raytrace_free(void)
+{
+ for (int i = 0; i < SSR_MAX_SHADER; ++i) {
+ DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
new file mode 100644
index 00000000000..6fbd0ae5173
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_shaders.c
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_string_utils.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_shader.h"
+
+#include "eevee_private.h"
+
+const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n"
+#if defined(IRRADIANCE_SH_L2)
+ "#define IRRADIANCE_SH_L2\n"
+#elif defined(IRRADIANCE_CUBEMAP)
+ "#define IRRADIANCE_CUBEMAP\n"
+#elif defined(IRRADIANCE_HL2)
+ "#define IRRADIANCE_HL2\n"
+#endif
+ "#define NOISE_SIZE 64\n";
+
+static struct {
+ /* Probes */
+ struct GPUShader *probe_default_sh;
+ struct GPUShader *probe_default_studiolight_sh;
+ struct GPUShader *probe_grid_display_sh;
+ struct GPUShader *probe_cube_display_sh;
+ struct GPUShader *probe_planar_display_sh;
+ struct GPUShader *probe_filter_glossy_sh;
+ struct GPUShader *probe_filter_diffuse_sh;
+ struct GPUShader *probe_filter_visibility_sh;
+ struct GPUShader *probe_grid_fill_sh;
+ struct GPUShader *probe_planar_downsample_sh;
+
+ /* Velocity Resolve */
+ struct GPUShader *velocity_resolve_sh;
+
+ /* Temporal Anti Aliasing */
+ struct GPUShader *taa_resolve_sh;
+ struct GPUShader *taa_resolve_reproject_sh;
+
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
+extern char datatoc_background_vert_glsl[];
+extern char datatoc_default_world_frag_glsl[];
+extern char datatoc_lightprobe_geom_glsl[];
+extern char datatoc_lightprobe_vert_glsl[];
+extern char datatoc_lightprobe_cube_display_frag_glsl[];
+extern char datatoc_lightprobe_cube_display_vert_glsl[];
+extern char datatoc_lightprobe_filter_diffuse_frag_glsl[];
+extern char datatoc_lightprobe_filter_glossy_frag_glsl[];
+extern char datatoc_lightprobe_filter_visibility_frag_glsl[];
+extern char datatoc_lightprobe_grid_display_frag_glsl[];
+extern char datatoc_lightprobe_grid_display_vert_glsl[];
+extern char datatoc_lightprobe_grid_fill_frag_glsl[];
+extern char datatoc_lightprobe_planar_display_frag_glsl[];
+extern char datatoc_lightprobe_planar_display_vert_glsl[];
+extern char datatoc_lightprobe_planar_downsample_frag_glsl[];
+extern char datatoc_lightprobe_planar_downsample_geom_glsl[];
+extern char datatoc_lightprobe_planar_downsample_vert_glsl[];
+extern char datatoc_irradiance_lib_glsl[];
+extern char datatoc_lightprobe_lib_glsl[];
+extern char datatoc_octahedron_lib_glsl[];
+
+/* Velocity Resolve */
+extern char datatoc_effect_velocity_resolve_frag_glsl[];
+
+/* Temporal Sampling */
+extern char datatoc_effect_temporal_aa_glsl[];
+
+extern GlobalsUboStorage ts;
+
+/* *********** FUNCTIONS *********** */
+
+void EEVEE_shaders_lightprobe_shaders_init(void)
+{
+ BLI_assert(e_data.probe_filter_glossy_sh == NULL);
+ char *shader_str = NULL;
+
+ shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_lightprobe_filter_glossy_frag_glsl);
+
+ e_data.probe_filter_glossy_sh = DRW_shader_create(
+ datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, filter_defines);
+
+ e_data.probe_default_sh = DRW_shader_create(
+ datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL);
+
+ MEM_freeN(shader_str);
+
+ shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_lightprobe_filter_diffuse_frag_glsl);
+
+ e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(shader_str, filter_defines);
+
+ MEM_freeN(shader_str);
+
+ shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_lightprobe_filter_visibility_frag_glsl);
+
+ e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen(shader_str, filter_defines);
+
+ MEM_freeN(shader_str);
+
+ e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen(
+ datatoc_lightprobe_grid_fill_frag_glsl, filter_defines);
+
+ e_data.probe_planar_downsample_sh = DRW_shader_create(
+ datatoc_lightprobe_planar_downsample_vert_glsl,
+ datatoc_lightprobe_planar_downsample_geom_glsl,
+ datatoc_lightprobe_planar_downsample_frag_glsl,
+ NULL);
+}
+
+GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void)
+{
+ return e_data.probe_filter_glossy_sh;
+}
+
+GPUShader *EEVEE_shaders_probe_default_sh_get(void)
+{
+ return e_data.probe_default_sh;
+}
+
+GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void)
+{
+ return e_data.probe_filter_diffuse_sh;
+}
+
+GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void)
+{
+ return e_data.probe_filter_visibility_sh;
+}
+
+GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void)
+{
+ return e_data.probe_grid_fill_sh;
+}
+
+GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void)
+{
+ return e_data.probe_planar_downsample_sh;
+}
+
+GPUShader *EEVEE_shaders_default_studiolight_sh_get(void)
+{
+ if (e_data.probe_default_studiolight_sh == NULL) {
+ e_data.probe_default_studiolight_sh = DRW_shader_create(
+ datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, "#define LOOKDEV\n");
+ }
+ return e_data.probe_default_studiolight_sh;
+}
+
+GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void)
+{
+ if (e_data.probe_cube_display_sh == NULL) {
+ char *shader_str = BLI_string_joinN(
+ datatoc_octahedron_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_lightprobe_cube_display_frag_glsl);
+
+ char *vert_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_lightprobe_cube_display_vert_glsl);
+
+ e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, SHADER_DEFINES);
+
+ MEM_freeN(vert_str);
+ MEM_freeN(shader_str);
+ }
+ return e_data.probe_cube_display_sh;
+}
+
+ GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void)
+{
+ if (e_data.probe_grid_display_sh == NULL ) {
+ char *shader_str = BLI_string_joinN(
+ datatoc_octahedron_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_lightprobe_grid_display_frag_glsl);
+
+ char *vert_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_lightprobe_grid_display_vert_glsl);
+
+ e_data.probe_grid_display_sh = DRW_shader_create(vert_str, NULL, shader_str, filter_defines);
+
+ MEM_freeN(vert_str);
+ MEM_freeN(shader_str);
+ }
+ return e_data.probe_grid_display_sh;
+}
+
+ GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void)
+{
+ if (e_data.probe_planar_display_sh == NULL) {
+ char *vert_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_lightprobe_planar_display_vert_glsl);
+
+ char *shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_lightprobe_planar_display_frag_glsl);
+
+ e_data.probe_planar_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL);
+
+ MEM_freeN(vert_str);
+ MEM_freeN(shader_str);
+ }
+ return e_data.probe_planar_display_sh;
+}
+
+GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void)
+{
+ if (e_data.velocity_resolve_sh == NULL) {
+ char *frag_str = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_effect_velocity_resolve_frag_glsl);
+
+ e_data.velocity_resolve_sh = DRW_shader_create_fullscreen(frag_str, NULL);
+
+ MEM_freeN(frag_str);
+ }
+ return e_data.velocity_resolve_sh;
+}
+
+GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects)
+{
+ GPUShader **sh;
+ const char *define = NULL;
+ if (enabled_effects & EFFECT_TAA_REPROJECT) {
+ sh = &e_data.taa_resolve_reproject_sh;
+ define = "#define USE_REPROJECTION\n";
+
+
+
+ }
+ else {
+ sh = &e_data.taa_resolve_sh;
+ }
+ if (*sh == NULL) {
+ char *frag_str = BLI_string_joinN(
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_effect_temporal_aa_glsl);
+
+ *sh = DRW_shader_create_fullscreen(frag_str, define);
+ MEM_freeN(frag_str);
+ }
+
+ return *sh;
+}
+
+void EEVEE_shaders_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.probe_default_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_grid_fill_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_planar_downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_default_studiolight_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_cube_display_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh);
+ DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
new file mode 100644
index 00000000000..9ecc1fb1b2b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_subsurface.c
+ * \ingroup draw_engine
+ *
+ * Screen space subsurface scattering technique.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_string_utils.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+#include "GPU_texture.h"
+#include "GPU_extensions.h"
+
+static struct {
+ struct GPUShader *sss_sh[4];
+} e_data = {{NULL}}; /* Engine data */
+
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_effect_subsurface_frag_glsl[];
+
+static void eevee_create_shader_subsurface(void)
+{
+ char *frag_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_effect_subsurface_frag_glsl);
+
+ e_data.sss_sh[0] = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n");
+ e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n");
+ e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"
+ "#define USE_SEP_ALBEDO\n");
+ e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"
+ "#define USE_SEP_ALBEDO\n"
+ "#define RESULT_ACCUM\n");
+
+ MEM_freeN(frag_str);
+}
+
+int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const float *viewport_size = DRW_viewport_size_get();
+ const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_SSS_ENABLED) {
+ effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2;
+ effects->sss_separate_albedo = (scene_eval->eevee.flag & SCE_EEVEE_SSS_SEPARATE_ALBEDO) != 0;
+ common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold;
+
+ /* Force separate albedo for final render */
+ if (DRW_state_is_image_render()) {
+ effects->sss_separate_albedo = true;
+ }
+
+ /* Shaders */
+ if (!e_data.sss_sh[0]) {
+ eevee_create_shader_subsurface();
+ }
+
+ /* NOTE : we need another stencil because the stencil buffer is on the same texture
+ * as the depth buffer we are sampling from. This could be avoided if the stencil is
+ * a separate texture but that needs OpenGL 4.4 or ARB_texture_stencil8.
+ * OR OpenGL 4.3 / ARB_ES3_compatibility if using a renderbuffer instead */
+ effects->sss_stencil = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_eevee_type);
+ effects->sss_blur = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], GPU_RGBA16F,
+ &draw_engine_eevee_type);
+ effects->sss_data = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], GPU_RGBA16F,
+ &draw_engine_eevee_type);
+
+ GPUTexture *stencil_tex = effects->sss_stencil;
+
+ if (GPU_depth_blitting_workaround()) {
+ /* Blitting stencil buffer does not work on macOS + Radeon Pro.
+ * Blit depth instead and use sss_stencil's depth as depth texture,
+ * and dtxl->depth as stencil mask. */
+ GPU_framebuffer_ensure_config(&fbl->sss_blit_fb, {
+ GPU_ATTACHMENT_TEXTURE(effects->sss_stencil),
+ GPU_ATTACHMENT_NONE
+ });
+
+ stencil_tex = dtxl->depth;
+ }
+
+ GPU_framebuffer_ensure_config(&fbl->sss_blur_fb, {
+ GPU_ATTACHMENT_TEXTURE(stencil_tex),
+ GPU_ATTACHMENT_TEXTURE(effects->sss_blur)
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->sss_resolve_fb, {
+ GPU_ATTACHMENT_TEXTURE(stencil_tex),
+ GPU_ATTACHMENT_TEXTURE(txl->color)
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->sss_clear_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(effects->sss_data)
+ });
+
+ if (effects->sss_separate_albedo) {
+ effects->sss_albedo = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], GPU_R11F_G11F_B10F,
+ &draw_engine_eevee_type);
+ }
+ else {
+ effects->sss_albedo = NULL;
+ }
+ return EFFECT_SSS;
+ }
+
+ /* Cleanup to release memory */
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_blur_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_resolve_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb);
+ effects->sss_stencil = NULL;
+ effects->sss_blur = NULL;
+ effects->sss_data = NULL;
+
+ return 0;
+}
+
+static void set_shgrp_stencil(void *UNUSED(userData), DRWShadingGroup *shgrp)
+{
+ DRW_shgroup_stencil_mask(shgrp, 255);
+}
+
+void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_SSS_ENABLED) {
+ DRW_texture_ensure_fullscreen_2D(&txl->sss_dir_accum, GPU_RGBA16F, 0);
+ DRW_texture_ensure_fullscreen_2D(&txl->sss_col_accum, GPU_RGBA16F, 0);
+
+ GPUTexture *stencil_tex = effects->sss_stencil;
+
+ if (GPU_depth_blitting_workaround()) {
+ /* Blitting stencil buffer does not work on macOS + Radeon Pro.
+ * Blit depth instead and use sss_stencil's depth as depth texture,
+ * and dtxl->depth as stencil mask. */
+ stencil_tex = dtxl->depth;
+ }
+
+ GPU_framebuffer_ensure_config(&fbl->sss_accum_fb, {
+ GPU_ATTACHMENT_TEXTURE(stencil_tex),
+ GPU_ATTACHMENT_TEXTURE(txl->sss_dir_accum),
+ GPU_ATTACHMENT_TEXTURE(txl->sss_col_accum)
+ });
+
+ /* Clear texture. */
+ float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_framebuffer_bind(fbl->sss_accum_fb);
+ GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear);
+
+ /* Make the opaque refraction pass mask the sss. */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES |
+ DRW_STATE_WIRE | DRW_STATE_WRITE_STENCIL;
+ DRW_pass_state_set(vedata->psl->refract_pass, state);
+ DRW_pass_foreach_shgroup(vedata->psl->refract_pass, &set_shgrp_stencil, NULL);
+ }
+ else {
+ /* Cleanup to release memory */
+ DRW_TEXTURE_FREE_SAFE(txl->sss_dir_accum);
+ DRW_TEXTURE_FREE_SAFE(txl->sss_col_accum);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb);
+ }
+}
+
+void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & EFFECT_SSS) != 0) {
+ /** Screen Space SubSurface Scattering overview
+ * TODO
+ */
+ psl->sss_blur_ps = DRW_pass_create("Blur Horiz", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL);
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE | DRW_STATE_STENCIL_EQUAL;
+ psl->sss_resolve_ps = DRW_pass_create("Blur Vert", state);
+ psl->sss_accum_ps = DRW_pass_create("Resolve Accum", state);
+ }
+}
+
+void EEVEE_subsurface_add_pass(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint sss_id, struct GPUUniformBuffer *sss_profile)
+{
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth;
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_data);
+ DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_stencil_mask(grp, sss_id);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1];
+ grp = DRW_shgroup_create(sh, psl->sss_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur);
+ DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_stencil_mask(grp, sss_id);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ if (effects->sss_separate_albedo) {
+ DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
+ }
+
+ if (DRW_state_is_image_render()) {
+ grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_accum_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur);
+ DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
+ DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_stencil_mask(grp, sss_id);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+}
+
+void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & EFFECT_SSS) != 0) {
+ float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ /* Clear sss_data texture only... can this be done in a more clever way? */
+ GPU_framebuffer_bind(fbl->sss_clear_fb);
+ GPU_framebuffer_clear_color(fbl->sss_clear_fb, clear);
+
+ GPU_framebuffer_ensure_config(&fbl->main_fb, {
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_TEXTURE(effects->sss_data),
+ GPU_ATTACHMENT_TEXTURE(effects->sss_albedo)
+ });
+
+ GPU_framebuffer_bind(fbl->main_fb);
+ DRW_draw_pass(psl->sss_pass);
+
+ /* Restore */
+ GPU_framebuffer_ensure_config(&fbl->main_fb, {
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_LEAVE,
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_NONE
+ });
+ }
+}
+
+void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & EFFECT_SSS) != 0) {
+ float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ DRW_stats_group_start("SSS");
+
+ if (GPU_depth_blitting_workaround()) {
+ /* Copy depth channel */
+ GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blit_fb, 0, GPU_DEPTH_BIT);
+ }
+ else {
+ /* Copy stencil channel, could be avoided (see EEVEE_subsurface_init) */
+ GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT);
+ }
+
+ /* 1. horizontal pass */
+ GPU_framebuffer_bind(fbl->sss_blur_fb);
+ GPU_framebuffer_clear_color(fbl->sss_blur_fb, clear);
+ DRW_draw_pass(psl->sss_blur_ps);
+
+ /* 2. vertical pass + Resolve */
+ GPU_framebuffer_texture_attach(fbl->sss_resolve_fb, txl->color, 0, 0);
+ GPU_framebuffer_bind(fbl->sss_resolve_fb);
+ DRW_draw_pass(psl->sss_resolve_ps);
+
+ GPU_framebuffer_bind(fbl->main_fb);
+ DRW_stats_group_end();
+ }
+}
+
+void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if (((effects->enabled_effects & EFFECT_SSS) != 0) && (fbl->sss_accum_fb != NULL)) {
+ /* Copy stencil channel, could be avoided (see EEVEE_subsurface_init) */
+ GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT);
+
+ /* Only do vertical pass + Resolve */
+ GPU_framebuffer_bind(fbl->sss_accum_fb);
+ DRW_draw_pass(psl->sss_accum_ps);
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+ }
+}
+
+void EEVEE_subsurface_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.sss_sh[0]);
+ DRW_SHADER_FREE_SAFE(e_data.sss_sh[1]);
+ DRW_SHADER_FREE_SAFE(e_data.sss_sh[2]);
+ DRW_SHADER_FREE_SAFE(e_data.sss_sh[3]);
+}
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
new file mode 100644
index 00000000000..deac0b89b10
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_temporal_sampling.c
+ * \ingroup draw_engine
+ *
+ * Temporal super sampling technique
+ */
+
+#include "DRW_render.h"
+
+#include "ED_screen.h"
+
+#include "BLI_rand.h"
+#include "BLI_string_utils.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+#include "GPU_texture.h"
+
+#define FILTER_CDF_TABLE_SIZE 512
+
+static struct {
+ /* Pixel filter table: Only blackman-harris for now. */
+ bool inited;
+ float inverted_cdf[FILTER_CDF_TABLE_SIZE];
+} e_data = {false}; /* Engine data */
+
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+
+static float UNUSED_FUNCTION(filter_box)(float UNUSED(x))
+{
+ return 1.0f;
+}
+
+static float filter_blackman_harris(float x)
+{
+ /* Hardcoded 1px footprint [-0.5..0.5]. We resize later. */
+ const float width = 1.0f;
+ x = 2.0f * M_PI * (x / width + 0.5f);
+ return 0.35875f - 0.48829f * cosf(x) + 0.14128f * cosf(2.0f * x) - 0.01168f * cosf(3.0f * x);
+}
+
+/* Compute cumulative distribution function of a discrete function. */
+static void compute_cdf(float (*func)(float x), float cdf[FILTER_CDF_TABLE_SIZE])
+{
+ cdf[0] = 0.0f;
+ /* Actual CDF evaluation. */
+ for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; ++u) {
+ float x = (float)(u + 1) / (float)(FILTER_CDF_TABLE_SIZE - 1);
+ cdf[u + 1] = cdf[u] + func(x - 0.5f); /* [-0.5..0.5]. We resize later. */
+ }
+ /* Normalize the CDF. */
+ for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; u++) {
+ cdf[u] /= cdf[FILTER_CDF_TABLE_SIZE - 1];
+ }
+ /* Just to make sure. */
+ cdf[FILTER_CDF_TABLE_SIZE - 1] = 1.0f;
+}
+
+static void invert_cdf(const float cdf[FILTER_CDF_TABLE_SIZE], float invert_cdf[FILTER_CDF_TABLE_SIZE])
+{
+ for (int u = 0; u < FILTER_CDF_TABLE_SIZE; u++) {
+ float x = (float)u / (float)(FILTER_CDF_TABLE_SIZE - 1);
+ for (int i = 0; i < FILTER_CDF_TABLE_SIZE; ++i) {
+ if (cdf[i] >= x) {
+ if (i == FILTER_CDF_TABLE_SIZE - 1) {
+ invert_cdf[u] = 1.0f;
+ }
+ else {
+ float t = (x - cdf[i]) / (cdf[i + 1] - cdf[i]);
+ invert_cdf[u] = ((float)i + t) / (float)(FILTER_CDF_TABLE_SIZE - 1);
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* Evaluate a discrete function table with linear interpolation. */
+static float eval_table(float *table, float x)
+{
+ CLAMP(x, 0.0f, 1.0f);
+ x = x * (FILTER_CDF_TABLE_SIZE - 1);
+
+ int index = min_ii((int)(x), FILTER_CDF_TABLE_SIZE - 1);
+ int nindex = min_ii(index + 1, FILTER_CDF_TABLE_SIZE - 1);
+ float t = x - index;
+
+ return (1.0f - t) * table[index] + t * table[nindex];
+}
+
+static void eevee_create_cdf_table_temporal_sampling(void)
+{
+ float *cdf_table = MEM_mallocN(sizeof(float) * FILTER_CDF_TABLE_SIZE, "Eevee Filter CDF table");
+
+ float filter_width = 2.0f; /* Use a 2 pixel footprint by default. */
+
+ {
+ /* Use blackman-harris filter. */
+ filter_width *= 2.0f;
+ compute_cdf(filter_blackman_harris, cdf_table);
+ }
+
+ invert_cdf(cdf_table, e_data.inverted_cdf);
+
+ /* Scale and offset table. */
+ for (int i = 0; i < FILTER_CDF_TABLE_SIZE; ++i) {
+ e_data.inverted_cdf[i] = (e_data.inverted_cdf[i] - 0.5f) * filter_width;
+ }
+
+ MEM_freeN(cdf_table);
+ e_data.inited = true;
+}
+
+void EEVEE_temporal_sampling_matrices_calc(
+ EEVEE_EffectsInfo *effects, float viewmat[4][4], float persmat[4][4], const double ht_point[2])
+{
+ const float *viewport_size = DRW_viewport_size_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ RenderData *rd = &scene->r;
+
+ float filter_size = rd->gauss; /* Sigh.. Stupid legacy naming. */
+
+ float ofs_x = eval_table(e_data.inverted_cdf, (float)(ht_point[0])) * filter_size;
+ float ofs_y = eval_table(e_data.inverted_cdf, (float)(ht_point[1])) * filter_size;
+
+ window_translate_m4(
+ effects->overide_winmat, persmat,
+ ofs_x / viewport_size[0],
+ ofs_y / viewport_size[1]);
+
+ mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat);
+ invert_m4_m4(effects->overide_persinv, effects->overide_persmat);
+ invert_m4_m4(effects->overide_wininv, effects->overide_winmat);
+}
+
+void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata)
+{
+ vedata->stl->effects->taa_render_sample = 1;
+}
+
+int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ // EEVEE_FramebufferList *fbl = vedata->fbl;
+ // EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ int repro_flag = 0;
+
+ if (!e_data.inited) {
+ eevee_create_cdf_table_temporal_sampling();
+ }
+
+ /* Reset for each "redraw". When rendering using ogl render,
+ * we accumulate the redraw inside the drawing loop in eevee_draw_background().
+ * But we do NOT accumulate between "redraw" (as in full draw manager drawloop)
+ * because the opengl render already does that. */
+ effects->taa_render_sample = 1;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ if (((scene_eval->eevee.taa_samples != 1) &&
+ /* FIXME the motion blur camera evaluation is tagging view_updated
+ * thus making the TAA always reset and never stopping rendering. */
+ (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) ||
+ DRW_state_is_image_render())
+ {
+ float persmat[4][4], viewmat[4][4];
+
+ if (!DRW_state_is_image_render() &&
+ (scene_eval->eevee.flag & SCE_EEVEE_TAA_REPROJECTION))
+ {
+ repro_flag = EFFECT_TAA_REPROJECT | EFFECT_VELOCITY_BUFFER | EFFECT_DEPTH_DOUBLE_BUFFER | EFFECT_DOUBLE_BUFFER | EFFECT_POST_BUFFER;
+ effects->taa_reproject_sample = ((effects->taa_reproject_sample + 1) % 16);
+ }
+
+ /* Until we support reprojection, we need to make sure
+ * that the history buffer contains correct information. */
+ bool view_is_valid = stl->g_data->valid_double_buffer;
+
+ view_is_valid = view_is_valid && (stl->g_data->view_updated == false);
+
+ if (draw_ctx->evil_C != NULL) {
+ struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
+ view_is_valid = view_is_valid && (ED_screen_animation_no_scrub(wm) == NULL);
+ }
+
+ effects->taa_total_sample = scene_eval->eevee.taa_samples;
+ MAX2(effects->taa_total_sample, 0);
+
+ DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_get(effects->overide_winmat, DRW_MAT_WIN);
+ /* The view is jittered by the oglrenderer. So avoid testing in this case. */
+ if (!DRW_state_is_image_render()) {
+ view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN);
+ copy_m4_m4(effects->prev_drw_persmat, persmat);
+ }
+
+ /* Prevent ghosting from probe data. */
+ view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support());
+ effects->prev_drw_support = DRW_state_draw_support();
+
+ if (((effects->taa_total_sample == 0) || (effects->taa_current_sample < effects->taa_total_sample)) ||
+ DRW_state_is_image_render())
+ {
+ if (view_is_valid) {
+ /* OGL render already jitter the camera. */
+ if (!DRW_state_is_image_render()) {
+ effects->taa_current_sample += 1;
+ repro_flag = 0;
+
+ double ht_point[2];
+ double ht_offset[2] = {0.0, 0.0};
+ uint ht_primes[2] = {2, 3};
+
+ BLI_halton_2D(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point);
+
+ EEVEE_temporal_sampling_matrices_calc(effects, viewmat, persmat, ht_point);
+
+ DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV);
+ }
+ }
+ else {
+ effects->taa_current_sample = 1;
+ }
+ }
+ else {
+ effects->taa_current_sample = 1;
+ }
+
+ return repro_flag | EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_DEPTH_DOUBLE_BUFFER | EFFECT_POST_BUFFER;
+ }
+
+ effects->taa_current_sample = 1;
+
+ return repro_flag;
+}
+
+void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) {
+ struct GPUShader *sh = EEVEE_shaders_taa_resolve_sh_get(effects->enabled_effects);
+
+ psl->taa_resolve = DRW_pass_create("Temporal AA Resolve", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->taa_resolve);
+
+ DRW_shgroup_uniform_texture_ref(grp, "colorHistoryBuffer", &txl->taa_history);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ if (effects->enabled_effects & EFFECT_TAA_REPROJECT) {
+ // DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRW_shgroup_uniform_texture_ref(grp, "velocityBuffer", &effects->velocity_tx);
+ }
+ else {
+ DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1);
+ }
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+}
+
+void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) {
+ if ((effects->enabled_effects & EFFECT_TAA) != 0 && effects->taa_current_sample != 1) {
+ if (DRW_state_is_image_render()) {
+ /* See EEVEE_temporal_sampling_init() for more details. */
+ effects->taa_alpha = 1.0f / (float)(effects->taa_render_sample);
+ }
+ else {
+ effects->taa_alpha = 1.0f / (float)(effects->taa_current_sample);
+ }
+
+ GPU_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->taa_resolve);
+
+ /* Restore the depth from sample 1. */
+ if (!DRW_state_is_image_render()) {
+ GPU_framebuffer_blit(fbl->double_buffer_depth_fb, 0, fbl->main_fb, 0, GPU_DEPTH_BIT);
+ }
+
+ SWAP_BUFFERS_TAA();
+ }
+ else {
+ if (!DRW_state_is_image_render()) {
+ /* Save the depth buffer for the next frame.
+ * This saves us from doing anything special
+ * in the other mode engines. */
+ GPU_framebuffer_blit(fbl->main_fb, 0, fbl->double_buffer_depth_fb, 0, GPU_DEPTH_BIT);
+ }
+
+ /* Do reprojection for noise reduction */
+ /* TODO : do AA jitter if in only render view. */
+ if (!DRW_state_is_image_render() &&
+ (effects->enabled_effects & EFFECT_TAA_REPROJECT) != 0 &&
+ stl->g_data->valid_taa_history)
+ {
+ GPU_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->taa_resolve);
+ SWAP_BUFFERS_TAA();
+ }
+ else {
+ struct GPUFrameBuffer *source_fb = (effects->target_buffer == fbl->main_color_fb) ? fbl->effect_color_fb : fbl->main_color_fb;
+ GPU_framebuffer_blit(source_fb, 0, fbl->taa_history_color_fb, 0, GPU_COLOR_BIT);
+ }
+ }
+
+ /* Make each loop count when doing a render. */
+ if (DRW_state_is_image_render()) {
+ effects->taa_render_sample += 1;
+ effects->taa_current_sample += 1;
+ }
+ else {
+ if ((effects->taa_total_sample == 0) ||
+ (effects->taa_current_sample < effects->taa_total_sample))
+ {
+ DRW_viewport_request_redraw();
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
new file mode 100644
index 00000000000..4fffa3f285c
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file eevee_volumes.c
+ * \ingroup draw_engine
+ *
+ * Volumetric effects rendering using frostbite approach.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_rand.h"
+#include "BLI_string_utils.h"
+
+#include "DNA_object_force_types.h"
+#include "DNA_smoke_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_global.h" /* for G.debug_value */
+#include "BKE_modifier.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+
+#include "ED_screen.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "eevee_private.h"
+#include "GPU_draw.h"
+#include "GPU_texture.h"
+#include "GPU_material.h"
+
+static struct {
+ char *volumetric_common_lib;
+ char *volumetric_common_lamps_lib;
+
+ struct GPUShader *volumetric_clear_sh;
+ struct GPUShader *volumetric_scatter_sh;
+ struct GPUShader *volumetric_scatter_with_lamps_sh;
+ struct GPUShader *volumetric_integration_sh;
+ struct GPUShader *volumetric_resolve_sh;
+
+ GPUTexture *color_src;
+ GPUTexture *depth_src;
+
+ /* List of all smoke domains rendered within this frame. */
+ ListBase smoke_domains;
+} e_data = {NULL}; /* Engine data */
+
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_octahedron_lib_glsl[];
+extern char datatoc_irradiance_lib_glsl[];
+extern char datatoc_lamps_lib_glsl[];
+extern char datatoc_volumetric_frag_glsl[];
+extern char datatoc_volumetric_geom_glsl[];
+extern char datatoc_volumetric_vert_glsl[];
+extern char datatoc_volumetric_resolve_frag_glsl[];
+extern char datatoc_volumetric_scatter_frag_glsl[];
+extern char datatoc_volumetric_integration_frag_glsl[];
+extern char datatoc_volumetric_lib_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+
+static void eevee_create_shader_volumes(void)
+{
+ e_data.volumetric_common_lib = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_volumetric_lib_glsl);
+
+ e_data.volumetric_common_lamps_lib = BLI_string_joinN(
+ datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lamps_lib_glsl,
+ datatoc_volumetric_lib_glsl);
+
+ e_data.volumetric_clear_sh = DRW_shader_create_with_lib(
+ datatoc_volumetric_vert_glsl,
+ datatoc_volumetric_geom_glsl,
+ datatoc_volumetric_frag_glsl,
+ e_data.volumetric_common_lib,
+ "#define VOLUMETRICS\n"
+ "#define CLEAR\n");
+ e_data.volumetric_scatter_sh = DRW_shader_create_with_lib(
+ datatoc_volumetric_vert_glsl,
+ datatoc_volumetric_geom_glsl,
+ datatoc_volumetric_scatter_frag_glsl,
+ e_data.volumetric_common_lamps_lib,
+ SHADER_DEFINES
+ "#define VOLUMETRICS\n"
+ "#define VOLUME_SHADOW\n");
+ e_data.volumetric_scatter_with_lamps_sh = DRW_shader_create_with_lib(
+ datatoc_volumetric_vert_glsl,
+ datatoc_volumetric_geom_glsl,
+ datatoc_volumetric_scatter_frag_glsl,
+ e_data.volumetric_common_lamps_lib,
+ SHADER_DEFINES
+ "#define VOLUMETRICS\n"
+ "#define VOLUME_LIGHTING\n"
+ "#define VOLUME_SHADOW\n");
+ e_data.volumetric_integration_sh = DRW_shader_create_with_lib(
+ datatoc_volumetric_vert_glsl,
+ datatoc_volumetric_geom_glsl,
+ datatoc_volumetric_integration_frag_glsl,
+ e_data.volumetric_common_lib, NULL);
+ e_data.volumetric_resolve_sh = DRW_shader_create_with_lib(
+ datatoc_common_fullscreen_vert_glsl, NULL,
+ datatoc_volumetric_resolve_frag_glsl,
+ e_data.volumetric_common_lib, NULL);
+}
+
+void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, uint current_sample)
+{
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+
+ double ht_point[3];
+ double ht_offset[3] = {0.0, 0.0};
+ uint ht_primes[3] = {3, 7, 2};
+
+ BLI_halton_3D(ht_primes, ht_offset, current_sample, ht_point);
+
+ common_data->vol_jitter[0] = (float)ht_point[0];
+ common_data->vol_jitter[1] = (float)ht_point[1];
+ common_data->vol_jitter[2] = (float)ht_point[2];
+}
+
+int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+
+ const float *viewport_size = DRW_viewport_size_get();
+
+ BLI_listbase_clear(&e_data.smoke_domains);
+
+ if (scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_ENABLED) {
+
+ /* Shaders */
+ if (!e_data.volumetric_scatter_sh) {
+ eevee_create_shader_volumes();
+ }
+
+ const int tile_size = scene_eval->eevee.volumetric_tile_size;
+
+ /* Find Froxel Texture resolution. */
+ int tex_size[3];
+
+ tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size));
+ tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size));
+ tex_size[2] = max_ii(scene_eval->eevee.volumetric_samples, 1);
+
+ common_data->vol_coord_scale[0] = viewport_size[0] / (float)(tile_size * tex_size[0]);
+ common_data->vol_coord_scale[1] = viewport_size[1] / (float)(tile_size * tex_size[1]);
+
+ /* TODO compute snap to maxZBuffer for clustered rendering */
+
+ if ((common_data->vol_tex_size[0] != tex_size[0]) ||
+ (common_data->vol_tex_size[1] != tex_size[1]) ||
+ (common_data->vol_tex_size[2] != tex_size[2]))
+ {
+ DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_scatter);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb);
+ common_data->vol_tex_size[0] = tex_size[0];
+ common_data->vol_tex_size[1] = tex_size[1];
+ common_data->vol_tex_size[2] = tex_size[2];
+
+ common_data->vol_inv_tex_size[0] = 1.0f / (float)(tex_size[0]);
+ common_data->vol_inv_tex_size[1] = 1.0f / (float)(tex_size[1]);
+ common_data->vol_inv_tex_size[2] = 1.0f / (float)(tex_size[2]);
+ }
+
+ /* Like frostbite's paper, 5% blend of the new frame. */
+ common_data->vol_history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f;
+
+ if (txl->volume_prop_scattering == NULL) {
+ /* Volume properties: We evaluate all volumetric objects
+ * and store their final properties into each froxel */
+ txl->volume_prop_scattering = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
+ txl->volume_prop_extinction = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
+ txl->volume_prop_emission = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
+ txl->volume_prop_phase = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ GPU_RG16F, DRW_TEX_FILTER, NULL);
+
+ /* Volume scattering: We compute for each froxel the
+ * Scattered light towards the view. We also resolve temporal
+ * super sampling during this stage. */
+ txl->volume_scatter = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
+ txl->volume_transmittance = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
+
+ /* Final integration: We compute for each froxel the
+ * amount of scattered light and extinction coef at this
+ * given depth. We use theses textures as double buffer
+ * for the volumetric history. */
+ txl->volume_scatter_history = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
+ txl->volume_transmittance_history = DRW_texture_create_3D(tex_size[0], tex_size[1], tex_size[2],
+ GPU_R11F_G11F_B10F, DRW_TEX_FILTER, NULL);
+ }
+
+ /* Temporal Super sampling jitter */
+ uint ht_primes[3] = {3, 7, 2};
+ uint current_sample = 0;
+
+ /* If TAA is in use do not use the history buffer. */
+ bool do_taa = ((effects->enabled_effects & EFFECT_TAA) != 0);
+
+ if (draw_ctx->evil_C != NULL) {
+ struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
+ do_taa = do_taa && (ED_screen_animation_no_scrub(wm) == NULL);
+ }
+
+ if (do_taa) {
+ common_data->vol_history_alpha = 0.0f;
+ current_sample = effects->taa_current_sample - 1;
+ effects->volume_current_sample = -1;
+ }
+ else {
+ const uint max_sample = (ht_primes[0] * ht_primes[1] * ht_primes[2]);
+ current_sample = effects->volume_current_sample = (effects->volume_current_sample + 1) % max_sample;
+ if (current_sample != max_sample - 1) {
+ DRW_viewport_request_redraw();
+ }
+ }
+
+ EEVEE_volumes_set_jitter(sldata, current_sample);
+
+ /* Framebuffer setup */
+ GPU_framebuffer_ensure_config(&fbl->volumetric_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->volume_prop_scattering),
+ GPU_ATTACHMENT_TEXTURE(txl->volume_prop_extinction),
+ GPU_ATTACHMENT_TEXTURE(txl->volume_prop_emission),
+ GPU_ATTACHMENT_TEXTURE(txl->volume_prop_phase)
+ });
+ GPU_framebuffer_ensure_config(&fbl->volumetric_scat_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->volume_scatter),
+ GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance)
+ });
+ GPU_framebuffer_ensure_config(&fbl->volumetric_integ_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_history),
+ GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_history)
+ });
+
+ float integration_start = scene_eval->eevee.volumetric_start;
+ float integration_end = scene_eval->eevee.volumetric_end;
+ common_data->vol_light_clamp = scene_eval->eevee.volumetric_light_clamp;
+ common_data->vol_shadow_steps = (float)scene_eval->eevee.volumetric_shadow_samples;
+ if ((scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_SHADOWS) == 0) {
+ common_data->vol_shadow_steps = 0;
+ }
+
+ if (DRW_viewport_is_persp_get()) {
+ float sample_distribution = scene_eval->eevee.volumetric_sample_distribution;
+ sample_distribution = 4.0f * (1.00001f - sample_distribution);
+
+ const float clip_start = common_data->view_vecs[0][2];
+ /* Negate */
+ float near = integration_start = min_ff(-integration_start, clip_start - 1e-4f);
+ float far = integration_end = min_ff(-integration_end, near - 1e-4f);
+
+ common_data->vol_depth_param[0] = (far - near * exp2(1.0f / sample_distribution)) / (far - near);
+ common_data->vol_depth_param[1] = (1.0f - common_data->vol_depth_param[0]) / near;
+ common_data->vol_depth_param[2] = sample_distribution;
+ }
+ else {
+ const float clip_start = common_data->view_vecs[0][2];
+ const float clip_end = clip_start + common_data->view_vecs[1][2];
+ integration_start = min_ff(integration_end, clip_start);
+ integration_end = max_ff(-integration_end, clip_end);
+
+ common_data->vol_depth_param[0] = integration_start;
+ common_data->vol_depth_param[1] = integration_end;
+ common_data->vol_depth_param[2] = 1.0f / (integration_end - integration_start);
+ }
+
+ /* Disable clamp if equal to 0. */
+ if (common_data->vol_light_clamp == 0.0) {
+ common_data->vol_light_clamp = FLT_MAX;
+ }
+
+ common_data->vol_use_lights = (scene_eval->eevee.flag & SCE_EEVEE_VOLUMETRIC_LIGHTS) != 0;
+
+ return EFFECT_VOLUMETRIC | EFFECT_POST_BUFFER;
+ }
+
+ /* Cleanup to release memory */
+ DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_scatter);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history);
+ DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb);
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb);
+
+ return 0;
+}
+
+void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ LightCache *lcache = stl->g_data->light_cache;
+ EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
+
+ if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ DRWShadingGroup *grp = NULL;
+
+ /* Quick breakdown of the Volumetric rendering:
+ *
+ * The rendering is separated in 4 stages:
+ *
+ * - Material Parameters : we collect volume properties of
+ * all participating media in the scene and store them in
+ * a 3D texture aligned with the 3D frustum.
+ * This is done in 2 passes, one that clear the texture
+ * and/or evaluate the world volumes, and the 2nd one that
+ * additively render object volumes.
+ *
+ * - Light Scattering : the volume properties then are sampled
+ * and light scattering is evaluated for each cell of the
+ * volume texture. Temporal super-sampling (if enabled) occurs here.
+ *
+ * - Volume Integration : the scattered light and extinction is
+ * integrated (accumulated) along the view-rays. The result is stored
+ * for every cell in another texture.
+ *
+ * - Full-screen Resolve : From the previous stage, we get two
+ * 3D textures that contains integrated scattered light and extinction
+ * for "every" positions in the frustum. We only need to sample
+ * them and blend the scene color with those factors. This also
+ * work for alpha blended materials.
+ **/
+
+ /* World pass is not additive as it also clear the buffer. */
+ psl->volumetric_world_ps = DRW_pass_create("Volumetric World", DRW_STATE_WRITE_COLOR);
+
+ /* World Volumetric */
+ struct World *wo = scene->world;
+ if (wo != NULL && wo->use_nodes && wo->nodetree) {
+ struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo);
+
+ grp = DRW_shgroup_material_empty_tri_batch_create(mat,
+ psl->volumetric_world_ps,
+ common_data->vol_tex_size[2]);
+
+ if (grp) {
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ /* TODO (fclem): remove those (need to clean the GLSL files). */
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ }
+ }
+
+ if (grp == NULL) {
+ /* If no world or volume material is present just clear the buffer with this drawcall */
+ grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh,
+ psl->volumetric_world_ps,
+ common_data->vol_tex_size[2]);
+
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ }
+
+ /* Volumetric Objects */
+ psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR |
+ DRW_STATE_ADDITIVE);
+
+ struct GPUShader *scatter_sh = (common_data->vol_use_lights) ? e_data.volumetric_scatter_with_lamps_sh
+ : e_data.volumetric_scatter_sh;
+ psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_empty_tri_batch_create(scatter_sh, psl->volumetric_scatter_ps,
+ common_data->vol_tex_size[2]);
+ DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &lcache->grid_tx.tex);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_prop_scattering);
+ DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_prop_extinction);
+ DRW_shgroup_uniform_texture_ref(grp, "volumeEmission", &txl->volume_prop_emission);
+ DRW_shgroup_uniform_texture_ref(grp, "volumePhase", &txl->volume_prop_phase);
+ DRW_shgroup_uniform_texture_ref(grp, "historyScattering", &txl->volume_scatter_history);
+ DRW_shgroup_uniform_texture_ref(grp, "historyTransmittance", &txl->volume_transmittance_history);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ psl->volumetric_integration_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh,
+ psl->volumetric_integration_ps,
+ common_data->vol_tex_size[2]);
+ DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter);
+ DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmittance);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+
+ psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter);
+ DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmittance);
+ DRW_shgroup_uniform_texture_ref(grp, "inSceneColor", &e_data.color_src);
+ DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+}
+
+void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Scene *scene, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ float *texcoloc = NULL;
+ float *texcosize = NULL;
+ struct ModifierData *md = NULL;
+ Material *ma = give_current_material(ob, 1);
+
+ if (ma == NULL) {
+ return;
+ }
+
+ struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma);
+
+ /* If shader failed to compile or is currently compiling. */
+ if (GPU_material_status(mat) != GPU_MAT_SUCCESS) {
+ return;
+ }
+
+ DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, sldata->common_data.vol_tex_size[2]);
+
+ /* Making sure it's updated. */
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize);
+
+ /* TODO(fclem) remove those "unnecessary" UBOs */
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", ob->imat);
+ DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1);
+ DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1);
+
+ /* Smoke Simulation */
+ if (((ob->base_flag & BASE_FROMDUPLI) == 0) &&
+ (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (modifier_isEnabled(scene, md, eModifierMode_Realtime)))
+ {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ SmokeDomainSettings *sds = smd->domain;
+
+ if (sds == NULL) {
+ return;
+ }
+
+ /* Don't show smoke before simulation starts, this could be made an option in the future. */
+ const bool show_smoke = ((int)DEG_get_ctime(draw_ctx->depsgraph) >= sds->point_cache[0]->startframe);
+
+ if (sds->fluid && show_smoke) {
+ if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
+ GPU_create_smoke(smd, 0);
+ }
+ else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
+ GPU_create_smoke(smd, 1);
+ }
+ BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd));
+ }
+
+ if (sds->tex != NULL) {
+ DRW_shgroup_uniform_texture_ref(grp, "sampdensity", &sds->tex);
+ }
+ if (sds->tex_flame != NULL) {
+ DRW_shgroup_uniform_texture_ref(grp, "sampflame", &sds->tex_flame);
+ }
+
+ /* Output is such that 0..1 maps to 0..1000K */
+ DRW_shgroup_uniform_vec2(grp, "unftemperature", &sds->flame_ignition, 1);
+ }
+}
+
+void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+ if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
+ DRW_stats_group_start("Volumetrics");
+
+ /* Step 1: Participating Media Properties */
+ GPU_framebuffer_bind(fbl->volumetric_fb);
+ DRW_draw_pass(psl->volumetric_world_ps);
+ DRW_draw_pass(psl->volumetric_objects_ps);
+
+ /* Step 2: Scatter Light */
+ GPU_framebuffer_bind(fbl->volumetric_scat_fb);
+ DRW_draw_pass(psl->volumetric_scatter_ps);
+
+ /* Step 3: Integration */
+ GPU_framebuffer_bind(fbl->volumetric_integ_fb);
+ DRW_draw_pass(psl->volumetric_integration_ps);
+
+ /* Swap volume history buffers */
+ SWAP(struct GPUFrameBuffer *, fbl->volumetric_scat_fb, fbl->volumetric_integ_fb);
+ SWAP(GPUTexture *, txl->volume_scatter, txl->volume_scatter_history);
+ SWAP(GPUTexture *, txl->volume_transmittance, txl->volume_transmittance_history);
+
+ /* Restore */
+ GPU_framebuffer_bind(fbl->main_fb);
+
+ DRW_stats_group_end();
+ }
+}
+
+void EEVEE_volumes_resolve(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_FramebufferList *fbl = vedata->fbl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_EffectsInfo *effects = stl->effects;
+
+ if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) {
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ e_data.color_src = txl->color;
+ e_data.depth_src = dtxl->depth;
+
+ /* Step 4: Apply for opaque */
+ GPU_framebuffer_bind(fbl->effect_color_fb);
+ DRW_draw_pass(psl->volumetric_resolve_ps);
+
+ /* Swap the buffers and rebind depth to the current buffer */
+ SWAP(GPUFrameBuffer *, fbl->main_fb, fbl->effect_fb);
+ SWAP(GPUFrameBuffer *, fbl->main_color_fb, fbl->effect_color_fb);
+ SWAP(GPUTexture *, txl->color, txl->color_post);
+
+ /* Restore */
+ GPU_framebuffer_texture_detach(fbl->effect_fb, dtxl->depth);
+ GPU_framebuffer_texture_attach(fbl->main_fb, dtxl->depth, 0, 0);
+ GPU_framebuffer_bind(fbl->main_fb);
+ }
+}
+
+void EEVEE_volumes_free_smoke_textures(void)
+{
+ /* Free Smoke Textures after rendering */
+ for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) {
+ SmokeModifierData *smd = (SmokeModifierData *)link->data;
+ GPU_free_smoke(smd);
+ }
+ BLI_freelistN(&e_data.smoke_domains);
+}
+
+void EEVEE_volumes_free(void)
+{
+ MEM_SAFE_FREE(e_data.volumetric_common_lib);
+ MEM_SAFE_FREE(e_data.volumetric_common_lamps_lib);
+
+ DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh);
+ DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_sh);
+ DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_with_lamps_sh);
+ DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh);
+ DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
new file mode 100644
index 00000000000..40c6bb1f1e0
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -0,0 +1,282 @@
+
+/* Based on Practical Realtime Strategies for Accurate Indirect Occlusion
+ * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf
+ * http://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pptx */
+
+#if defined(MESH_SHADER)
+# if !defined(USE_ALPHA_HASH)
+# if !defined(USE_ALPHA_CLIP)
+# if !defined(SHADOW_SHADER)
+# if !defined(USE_MULTIPLY)
+# if !defined(USE_ALPHA_BLEND)
+# define ENABLE_DEFERED_AO
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifndef ENABLE_DEFERED_AO
+# if defined(STEP_RESOLVE)
+# define ENABLE_DEFERED_AO
+# endif
+#endif
+
+#define MAX_PHI_STEP 32
+#define MAX_SEARCH_ITER 32
+#define MAX_LOD 6.0
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
+uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
+
+uniform sampler2D horizonBuffer;
+
+/* aoSettings flags */
+#define USE_AO 1
+#define USE_BENT_NORMAL 2
+#define USE_DENOISE 4
+
+vec4 pack_horizons(vec4 v) { return v * 0.5 + 0.5; }
+vec4 unpack_horizons(vec4 v) { return v * 2.0 - 1.0; }
+
+/* Returns maximum screen distance an AO ray can travel for a given view depth */
+vec2 get_max_dir(float view_depth)
+{
+ float homcco = ProjectionMatrix[2][3] * view_depth + ProjectionMatrix[3][3];
+ float max_dist = aoDistance / homcco;
+ return vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * max_dist;
+}
+
+vec2 get_ao_dir(float jitter)
+{
+ /* Only half a turn because we integrate in slices. */
+ jitter *= M_PI;
+ return vec2(cos(jitter), sin(jitter));
+}
+
+void get_max_horizon_grouped(vec4 co1, vec4 co2, vec3 x, float lod, inout float h)
+{
+ int mip = int(lod) + hizMipOffset;
+ co1 *= mipRatio[mip].xyxy;
+ co2 *= mipRatio[mip].xyxy;
+
+ float depth1 = textureLod(maxzBuffer, co1.xy, floor(lod)).r;
+ float depth2 = textureLod(maxzBuffer, co1.zw, floor(lod)).r;
+ float depth3 = textureLod(maxzBuffer, co2.xy, floor(lod)).r;
+ float depth4 = textureLod(maxzBuffer, co2.zw, floor(lod)).r;
+
+ vec4 len, s_h;
+
+ vec3 s1 = get_view_space_from_depth(co1.xy, depth1); /* s View coordinate */
+ vec3 omega_s1 = s1 - x;
+ len.x = length(omega_s1);
+ s_h.x = omega_s1.z / len.x;
+
+ vec3 s2 = get_view_space_from_depth(co1.zw, depth2); /* s View coordinate */
+ vec3 omega_s2 = s2 - x;
+ len.y = length(omega_s2);
+ s_h.y = omega_s2.z / len.y;
+
+ vec3 s3 = get_view_space_from_depth(co2.xy, depth3); /* s View coordinate */
+ vec3 omega_s3 = s3 - x;
+ len.z = length(omega_s3);
+ s_h.z = omega_s3.z / len.z;
+
+ vec3 s4 = get_view_space_from_depth(co2.zw, depth4); /* s View coordinate */
+ vec3 omega_s4 = s4 - x;
+ len.w = length(omega_s4);
+ s_h.w = omega_s4.z / len.w;
+
+ /* Blend weight after half the aoDistance to fade artifacts */
+ vec4 blend = saturate((1.0 - len / aoDistance) * 2.0);
+
+ h = mix(h, max(h, s_h.x), blend.x);
+ h = mix(h, max(h, s_h.y), blend.y);
+ h = mix(h, max(h, s_h.z), blend.z);
+ h = mix(h, max(h, s_h.w), blend.w);
+}
+
+vec2 search_horizon_sweep(vec2 t_phi, vec3 pos, vec2 uvs, float jitter, vec2 max_dir)
+{
+ max_dir *= max_v2(abs(t_phi));
+
+ /* Convert to pixel space. */
+ t_phi /= vec2(textureSize(maxzBuffer, 0));
+
+ /* Avoid division by 0 */
+ t_phi += vec2(1e-5);
+
+ jitter *= 0.25;
+
+ /* Compute end points */
+ vec2 corner1 = min(vec2(1.0) - uvs, max_dir); /* Top right */
+ vec2 corner2 = max(vec2(0.0) - uvs, -max_dir); /* Bottom left */
+ vec2 iter1 = corner1 / t_phi;
+ vec2 iter2 = corner2 / t_phi;
+
+ vec2 min_iter = max(-iter1, -iter2);
+ vec2 max_iter = max( iter1, iter2);
+
+ vec2 times = vec2(-min_v2(min_iter), min_v2(max_iter));
+
+ vec2 h = vec2(-1.0); /* init at cos(pi) */
+
+ /* This is freaking sexy optimized. */
+ for (float i = 0.0, ofs = 4.0, time = -1.0;
+ i < MAX_SEARCH_ITER && time > times.x;
+ i++, time -= ofs, ofs = min(exp2(MAX_LOD) * 4.0, ofs + ofs * aoQuality))
+ {
+ vec4 t = max(times.xxxx, vec4(time) - (vec4(0.25, 0.5, 0.75, 1.0) - jitter) * ofs);
+ vec4 cos1 = uvs.xyxy + t_phi.xyxy * t.xxyy;
+ vec4 cos2 = uvs.xyxy + t_phi.xyxy * t.zzww;
+ float lod = min(MAX_LOD, max(i - jitter * 4.0, 0.0) * aoQuality);
+ get_max_horizon_grouped(cos1, cos2, pos, lod, h.y);
+ }
+
+ for (float i = 0.0, ofs = 4.0, time = 1.0;
+ i < MAX_SEARCH_ITER && time < times.y;
+ i++, time += ofs, ofs = min(exp2(MAX_LOD) * 4.0, ofs + ofs * aoQuality))
+ {
+ vec4 t = min(times.yyyy, vec4(time) + (vec4(0.25, 0.5, 0.75, 1.0) - jitter) * ofs);
+ vec4 cos1 = uvs.xyxy + t_phi.xyxy * t.xxyy;
+ vec4 cos2 = uvs.xyxy + t_phi.xyxy * t.zzww;
+ float lod = min(MAX_LOD, max(i - jitter * 4.0, 0.0) * aoQuality);
+ get_max_horizon_grouped(cos1, cos2, pos, lod, h.x);
+ }
+
+ return h;
+}
+
+void integrate_slice(vec3 normal, vec2 t_phi, vec2 horizons, inout float visibility, inout vec3 bent_normal)
+{
+ /* Projecting Normal to Plane P defined by t_phi and omega_o */
+ vec3 np = vec3(t_phi.y, -t_phi.x, 0.0); /* Normal vector to Integration plane */
+ vec3 t = vec3(-t_phi, 0.0);
+ vec3 n_proj = normal - np * dot(np, normal);
+ float n_proj_len = max(1e-16, length(n_proj));
+
+ float cos_n = clamp(n_proj.z / n_proj_len, -1.0, 1.0);
+ float n = sign(dot(n_proj, t)) * fast_acos(cos_n); /* Angle between view vec and normal */
+
+ /* (Slide 54) */
+ vec2 h = fast_acos(horizons);
+ h.x = -h.x;
+
+ /* Clamping thetas (slide 58) */
+ h.x = n + max(h.x - n, -M_PI_2);
+ h.y = n + min(h.y - n, M_PI_2);
+
+ /* Solving inner integral */
+ vec2 h_2 = 2.0 * h;
+ vec2 vd = -cos(h_2 - n) + cos_n + h_2 * sin(n);
+ float vis = (vd.x + vd.y) * 0.25 * n_proj_len;
+
+ visibility += vis;
+
+ /* Finding Bent normal */
+ float b_angle = (h.x + h.y) * 0.5;
+ /* The 0.5 factor below is here to equilibrate the accumulated vectors.
+ * (sin(b_angle) * -t_phi) will accumulate to (phi_step * result_nor.xy * 0.5).
+ * (cos(b_angle) * 0.5) will accumulate to (phi_step * result_nor.z * 0.5). */
+ bent_normal += vec3(sin(b_angle) * -t_phi, cos(b_angle) * 0.5);
+}
+
+void gtao_deferred(
+ vec3 normal, vec4 noise, float frag_depth, out float visibility, out vec3 bent_normal)
+{
+ /* Fetch early, hide latency! */
+ vec4 horizons = texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0);
+
+ vec4 dirs;
+ dirs.xy = get_ao_dir(noise.x * 0.5);
+ dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
+
+ bent_normal = vec3(0.0);
+ visibility = 0.0;
+
+ horizons = unpack_horizons(horizons);
+
+ integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal);
+ integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal);
+
+ visibility *= 0.5; /* We integrated 2 slices. */
+
+ bent_normal = normalize(bent_normal);
+}
+
+void gtao(vec3 normal, vec3 position, vec4 noise, out float visibility, out vec3 bent_normal)
+{
+ vec2 uvs = get_uvs_from_view(position);
+ vec2 max_dir = get_max_dir(position.z);
+ vec2 dir = get_ao_dir(noise.x);
+
+ bent_normal = vec3(0.0);
+ visibility = 0.0;
+
+ /* Only trace in 2 directions. May lead to a darker result but since it's mostly for
+ * alpha blended objects that will have overdraw, we limit the performance impact. */
+ vec2 horizons = search_horizon_sweep(dir, position, uvs, noise.y, max_dir);
+ integrate_slice(normal, dir, horizons, visibility, bent_normal);
+
+ bent_normal = normalize(bent_normal);
+}
+
+/* Multibounce approximation base on surface albedo.
+ * Page 78 in the .pdf version. */
+float gtao_multibounce(float visibility, vec3 albedo)
+{
+ if (aoBounceFac == 0.0) return visibility;
+
+ /* Median luminance. Because Colored multibounce looks bad. */
+ float lum = dot(albedo, vec3(0.3333));
+
+ float a = 2.0404 * lum - 0.3324;
+ float b = -4.7951 * lum + 0.6417;
+ float c = 2.7552 * lum + 0.6903;
+
+ float x = visibility;
+ return max(x, ((x * a + b) * x + c) * x);
+}
+
+/* Use the right occlusion */
+float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal)
+{
+#ifndef USE_REFRACTION
+ if ((int(aoSettings) & USE_AO) != 0) {
+ float visibility;
+ vec3 vnor = mat3(ViewMatrix) * N;
+
+#ifdef ENABLE_DEFERED_AO
+ gtao_deferred(vnor, rand, gl_FragCoord.z, visibility, bent_normal);
+#else
+ gtao(vnor, vpos, rand, visibility, bent_normal);
+#endif
+
+ /* Prevent some problems down the road. */
+ visibility = max(1e-3, visibility);
+
+ if ((int(aoSettings) & USE_BENT_NORMAL) != 0) {
+ /* The bent normal will show the facet look of the mesh. Try to minimize this. */
+ float mix_fac = visibility * visibility;
+ bent_normal = normalize(mix(bent_normal, vnor, mix_fac));
+
+ bent_normal = transform_direction(ViewMatrixInverse, bent_normal);
+ }
+ else {
+ bent_normal = N;
+ }
+
+ /* Scale by user factor */
+ visibility = pow(visibility, aoFactor);
+
+ return min(visibility, user_occlusion);
+ }
+#endif
+
+ bent_normal = N;
+ return user_occlusion;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/background_vert.glsl b/source/blender/draw/engines/eevee/shaders/background_vert.glsl
new file mode 100644
index 00000000000..380d6d96491
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/background_vert.glsl
@@ -0,0 +1,27 @@
+
+in vec2 pos;
+
+out vec3 viewPosition;
+
+#ifndef VOLUMETRICS
+/* necessary for compilation*/
+out vec3 worldPosition;
+out vec3 worldNormal;
+out vec3 viewNormal;
+#endif
+
+void main()
+{
+ gl_Position = vec4(pos, 1.0, 1.0);
+ viewPosition = vec3(pos, -1.0);
+
+#ifndef VOLUMETRICS
+ /* Not used in practice but needed to avoid compilation errors. */
+ worldPosition = viewPosition;
+ worldNormal = viewNormal = normalize(-viewPosition);
+#endif
+
+#ifdef ATTRIB
+ pass_attrib(viewPosition);
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
new file mode 100644
index 00000000000..a54cefc5b85
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -0,0 +1,862 @@
+
+#define M_PI 3.14159265358979323846 /* pi */
+#define M_2PI 6.28318530717958647692 /* 2*pi */
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#define M_1_PI 0.318309886183790671538 /* 1/pi */
+#define M_1_2PI 0.159154943091895335768 /* 1/(2*pi) */
+#define M_1_PI2 0.101321183642337771443 /* 1/(pi^2) */
+
+#define LUT_SIZE 64
+
+/* Buffers */
+uniform sampler2D colorBuffer;
+uniform sampler2D depthBuffer;
+uniform sampler2D maxzBuffer;
+uniform sampler2D minzBuffer;
+uniform sampler2DArray planarDepth;
+
+#define cameraForward normalize(ViewMatrixInverse[2].xyz)
+#define cameraPos ViewMatrixInverse[3].xyz
+#define cameraVec ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward)
+#define viewCameraVec ((ProjectionMatrix[3][3] == 0.0) ? normalize(-viewPosition) : vec3(0.0, 0.0, 1.0))
+
+/* ------- Structures -------- */
+
+/* ------ Lights ----- */
+struct LightData {
+ vec4 position_influence; /* w : InfluenceRadius (inversed and squared) */
+ vec4 color_spec; /* w : Spec Intensity */
+ vec4 spotdata_radius_shadow; /* x : spot size, y : spot blend, z : radius, w: shadow id */
+ vec4 rightvec_sizex; /* xyz: Normalized up vector, w: area size X or spot scale X */
+ vec4 upvec_sizey; /* xyz: Normalized right vector, w: area size Y or spot scale Y */
+ vec4 forwardvec_type; /* xyz: Normalized forward vector, w: Lamp Type */
+};
+
+/* convenience aliases */
+#define l_color color_spec.rgb
+#define l_spec color_spec.a
+#define l_position position_influence.xyz
+#define l_influence position_influence.w
+#define l_sizex rightvec_sizex.w
+#define l_sizey upvec_sizey.w
+#define l_right rightvec_sizex.xyz
+#define l_up upvec_sizey.xyz
+#define l_forward forwardvec_type.xyz
+#define l_type forwardvec_type.w
+#define l_spot_size spotdata_radius_shadow.x
+#define l_spot_blend spotdata_radius_shadow.y
+#define l_radius spotdata_radius_shadow.z
+#define l_shadowid spotdata_radius_shadow.w
+
+/* ------ Shadows ----- */
+#ifndef MAX_CASCADE_NUM
+#define MAX_CASCADE_NUM 4
+#endif
+
+struct ShadowData {
+ vec4 near_far_bias_exp;
+ vec4 shadow_data_start_end;
+ vec4 contact_shadow_data;
+};
+
+struct ShadowCubeData {
+ vec4 position;
+};
+
+struct ShadowCascadeData {
+ mat4 shadowmat[MAX_CASCADE_NUM];
+ vec4 split_start_distances;
+ vec4 split_end_distances;
+};
+
+/* convenience aliases */
+#define sh_near near_far_bias_exp.x
+#define sh_far near_far_bias_exp.y
+#define sh_bias near_far_bias_exp.z
+#define sh_exp near_far_bias_exp.w
+#define sh_bleed near_far_bias_exp.w
+#define sh_tex_start shadow_data_start_end.x
+#define sh_data_start shadow_data_start_end.y
+#define sh_multi_nbr shadow_data_start_end.z
+#define sh_blur shadow_data_start_end.w
+#define sh_contact_dist contact_shadow_data.x
+#define sh_contact_offset contact_shadow_data.y
+#define sh_contact_spread contact_shadow_data.z
+#define sh_contact_thickness contact_shadow_data.w
+
+/* ------- Convenience functions --------- */
+
+vec3 mul(mat3 m, vec3 v) { return m * v; }
+mat3 mul(mat3 m1, mat3 m2) { return m1 * m2; }
+vec3 transform_direction(mat4 m, vec3 v) { return mat3(m) * v; }
+vec3 transform_point(mat4 m, vec3 v) { return (m * vec4(v, 1.0)).xyz; }
+vec3 project_point(mat4 m, vec3 v) {
+ vec4 tmp = m * vec4(v, 1.0);
+ return tmp.xyz / tmp.w;
+}
+
+#define min3(a, b, c) min(a, min(b, c))
+#define min4(a, b, c, d) min(a, min3(b, c, d))
+#define min5(a, b, c, d, e) min(a, min4(b, c, d, e))
+#define min6(a, b, c, d, e, f) min(a, min5(b, c, d, e, f))
+#define min7(a, b, c, d, e, f, g) min(a, min6(b, c, d, e, f, g))
+#define min8(a, b, c, d, e, f, g, h) min(a, min7(b, c, d, e, f, g, h))
+#define min9(a, b, c, d, e, f, g, h, i) min(a, min8(b, c, d, e, f, g, h, i))
+
+#define max3(a, b, c) max(a, max(b, c))
+#define max4(a, b, c, d) max(a, max3(b, c, d))
+#define max5(a, b, c, d, e) max(a, max4(b, c, d, e))
+#define max6(a, b, c, d, e, f) max(a, max5(b, c, d, e, f))
+#define max7(a, b, c, d, e, f, g) max(a, max6(b, c, d, e, f, g))
+#define max8(a, b, c, d, e, f, g, h) max(a, max7(b, c, d, e, f, g, h))
+#define max9(a, b, c, d, e, f, g, h, i) max(a, max8(b, c, d, e, f, g, h, i))
+
+#define avg3(a, b, c) (a + b + c) * (1.0 / 3.0)
+#define avg4(a, b, c, d) (a + b + c + d) * (1.0 / 4.0)
+#define avg5(a, b, c, d, e) (a + b + c + d + e) * (1.0 / 5.0)
+#define avg6(a, b, c, d, e, f) (a + b + c + d + e + f) * (1.0 / 6.0)
+#define avg7(a, b, c, d, e, f, g) (a + b + c + d + e + f + g) * (1.0 / 7.0)
+#define avg8(a, b, c, d, e, f, g, h) (a + b + c + d + e + f + g + h) * (1.0 / 8.0)
+#define avg9(a, b, c, d, e, f, g, h, i) (a + b + c + d + e + f + g + h + i) * (1.0 / 9.0)
+
+float min_v2(vec2 v) { return min(v.x, v.y); }
+float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
+float max_v2(vec2 v) { return max(v.x, v.y); }
+float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
+
+float sum(vec2 v) { return dot(vec2(1.0), v); }
+float sum(vec3 v) { return dot(vec3(1.0), v); }
+float sum(vec4 v) { return dot(vec4(1.0), v); }
+
+float saturate(float a) { return clamp(a, 0.0, 1.0); }
+vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }
+vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); }
+vec4 saturate(vec4 a) { return clamp(a, 0.0, 1.0); }
+
+float distance_squared(vec2 a, vec2 b) { a -= b; return dot(a, a); }
+float distance_squared(vec3 a, vec3 b) { a -= b; return dot(a, a); }
+float len_squared(vec3 a) { return dot(a, a); }
+
+float inverse_distance(vec3 V) { return max( 1 / length(V), 1e-8); }
+
+vec2 mip_ratio_interp(float mip) {
+ float low_mip = floor(mip);
+ return mix(mipRatio[int(low_mip)], mipRatio[int(low_mip + 1.0)], mip - low_mip);
+}
+
+/* ------- RNG ------- */
+
+float wang_hash_noise(uint s)
+{
+ s = (s ^ 61u) ^ (s >> 16u);
+ s *= 9u;
+ s = s ^ (s >> 4u);
+ s *= 0x27d4eb2du;
+ s = s ^ (s >> 15u);
+
+ return fract(float(s) / 4294967296.0);
+}
+
+/* ------- Fast Math ------- */
+
+/* [Drobot2014a] Low Level Optimizations for GCN */
+float fast_sqrt(float v)
+{
+ return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(v) >> 1));
+}
+
+vec2 fast_sqrt(vec2 v)
+{
+ return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(v) >> 1));
+}
+
+/* [Eberly2014] GPGPU Programming for Games and Science */
+float fast_acos(float v)
+{
+ float res = -0.156583 * abs(v) + M_PI_2;
+ res *= fast_sqrt(1.0 - abs(v));
+ return (v >= 0) ? res : M_PI - res;
+}
+
+vec2 fast_acos(vec2 v)
+{
+ vec2 res = -0.156583 * abs(v) + M_PI_2;
+ res *= fast_sqrt(1.0 - abs(v));
+ v.x = (v.x >= 0) ? res.x : M_PI - res.x;
+ v.y = (v.y >= 0) ? res.y : M_PI - res.y;
+ return v;
+}
+
+float point_plane_projection_dist(vec3 lineorigin, vec3 planeorigin, vec3 planenormal)
+{
+ return dot(planenormal, planeorigin - lineorigin);
+}
+
+float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
+{
+ return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection);
+}
+
+float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec4 plane)
+{
+ vec3 plane_co = plane.xyz * (-plane.w / len_squared(plane.xyz));
+ vec3 h = lineorigin - plane_co;
+ return -dot(plane.xyz, h) / dot(plane.xyz, linedirection);
+}
+
+vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
+{
+ float dist = line_plane_intersect_dist(lineorigin, linedirection, planeorigin, planenormal);
+ return lineorigin + linedirection * dist;
+}
+
+vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec4 plane)
+{
+ float dist = line_plane_intersect_dist(lineorigin, linedirection, plane);
+ return lineorigin + linedirection * dist;
+}
+
+float line_aligned_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin)
+{
+ /* aligned plane normal */
+ vec3 L = planeorigin - lineorigin;
+ float diskdist = length(L);
+ vec3 planenormal = -normalize(L);
+ return -diskdist / dot(planenormal, linedirection);
+}
+
+vec3 line_aligned_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin)
+{
+ float dist = line_aligned_plane_intersect_dist(lineorigin, linedirection, planeorigin);
+ if (dist < 0) {
+ /* if intersection is behind we fake the intersection to be
+ * really far and (hopefully) not inside the radius of interest */
+ dist = 1e16;
+ }
+ return lineorigin + linedirection * dist;
+}
+
+float line_unit_sphere_intersect_dist(vec3 lineorigin, vec3 linedirection)
+{
+ float a = dot(linedirection, linedirection);
+ float b = dot(linedirection, lineorigin);
+ float c = dot(lineorigin, lineorigin) - 1;
+
+ float dist = 1e15;
+ float determinant = b * b - a * c;
+ if (determinant >= 0)
+ dist = (sqrt(determinant) - b) / a;
+
+ return dist;
+}
+
+float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
+{
+ /* https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ */
+ vec3 firstplane = (vec3( 1.0) - lineorigin) / linedirection;
+ vec3 secondplane = (vec3(-1.0) - lineorigin) / linedirection;
+ vec3 furthestplane = max(firstplane, secondplane);
+
+ return min_v3(furthestplane);
+}
+
+
+/* Return texture coordinates to sample Surface LUT */
+vec2 lut_coords(float cosTheta, float roughness)
+{
+ float theta = acos(cosTheta);
+ vec2 coords = vec2(roughness, theta / M_PI_2);
+
+ /* scale and bias coordinates, for correct filtered lookup */
+ return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
+}
+
+/* -- Tangent Space conversion -- */
+vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B)
+{
+ return T * vector.x + B * vector.y + N * vector.z;
+}
+
+vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B)
+{
+ return vec3( dot(T, vector), dot(B, vector), dot(N, vector));
+}
+
+void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B)
+{
+ vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0,0.0,1.0) : vec3(1.0,0.0,0.0);
+ T = normalize( cross(UpVector, N) );
+ B = cross(N, T);
+}
+
+/* ---- Opengl Depth conversion ---- */
+
+float linear_depth(bool is_persp, float z, float zf, float zn)
+{
+ if (is_persp) {
+ return (zn * zf) / (z * (zn - zf) + zf);
+ }
+ else {
+ return (z * 2.0 - 1.0) * zf;
+ }
+}
+
+float buffer_depth(bool is_persp, float z, float zf, float zn)
+{
+ if (is_persp) {
+ return (zf * (zn - z)) / (z * (zn - zf));
+ }
+ else {
+ return (z / (zf * 2.0)) + 0.5;
+ }
+}
+
+float get_view_z_from_depth(float depth)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ float d = 2.0 * depth - 1.0;
+ return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
+ }
+ else {
+ return viewVecs[0].z + depth * viewVecs[1].z;
+ }
+}
+
+float get_depth_from_view_z(float z)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ float d = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
+ return d * 0.5 + 0.5;
+ }
+ else {
+ return (z - viewVecs[0].z) / viewVecs[1].z;
+ }
+}
+
+vec2 get_uvs_from_view(vec3 view)
+{
+ vec3 ndc = project_point(ProjectionMatrix, view);
+ return ndc.xy * 0.5 + 0.5;
+}
+
+vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ return vec3(viewVecs[0].xy + uvcoords * viewVecs[1].xy, 1.0) * get_view_z_from_depth(depth);
+ }
+ else {
+ return viewVecs[0].xyz + vec3(uvcoords, depth) * viewVecs[1].xyz;
+ }
+}
+
+vec3 get_world_space_from_depth(vec2 uvcoords, float depth)
+{
+ return (ViewMatrixInverse * vec4(get_view_space_from_depth(uvcoords, depth), 1.0)).xyz;
+}
+
+vec3 get_specular_reflection_dominant_dir(vec3 N, vec3 V, float roughness)
+{
+ vec3 R = -reflect(V, N);
+ float smoothness = 1.0 - roughness;
+ float fac = smoothness * (sqrt(smoothness) + roughness);
+ return normalize(mix(N, R, fac));
+}
+
+float specular_occlusion(float NV, float AO, float roughness)
+{
+ return saturate(pow(NV + AO, roughness) - 1.0 + AO);
+}
+
+/* --- Refraction utils --- */
+
+float ior_from_f0(float f0)
+{
+ float f = sqrt(f0);
+ return (-f - 1.0) / (f - 1.0);
+}
+
+float f0_from_ior(float eta)
+{
+ float A = (eta - 1.0) / (eta + 1.0);
+ return A * A;
+}
+
+vec3 get_specular_refraction_dominant_dir(vec3 N, vec3 V, float roughness, float ior)
+{
+ /* TODO: This a bad approximation. Better approximation should fit
+ * the refracted vector and roughness into the best prefiltered reflection
+ * lobe. */
+ /* Correct the IOR for ior < 1.0 to not see the abrupt delimitation or the TIR */
+ ior = (ior < 1.0) ? mix(ior, 1.0, roughness) : ior;
+ float eta = 1.0 / ior;
+
+ float NV = dot(N, -V);
+
+ /* Custom Refraction. */
+ float k = 1.0 - eta * eta * (1.0 - NV * NV);
+ k = max(0.0, k); /* Only this changes. */
+ vec3 R = eta * -V - (eta * NV + sqrt(k)) * N;
+
+ return R;
+}
+
+float get_btdf_lut(sampler2DArray btdf_lut_tex, float NV, float roughness, float ior)
+{
+ const vec3 lut_scale_bias_texel_size = vec3((LUT_SIZE - 1.0), 0.5, 1.5) / LUT_SIZE;
+
+ vec3 coords;
+ /* Try to compensate for the low resolution and interpolation error. */
+ coords.x = (ior > 1.0)
+ ? (0.9 + lut_scale_bias_texel_size.z) + (0.1 - lut_scale_bias_texel_size.z) * f0_from_ior(ior)
+ : (0.9 + lut_scale_bias_texel_size.z) * ior * ior;
+ coords.y = 1.0 - saturate(NV);
+ coords.xy *= lut_scale_bias_texel_size.x;
+ coords.xy += lut_scale_bias_texel_size.y;
+
+ const float lut_lvl_ofs = 4.0; /* First texture lvl of roughness. */
+ const float lut_lvl_scale = 16.0; /* How many lvl of roughness in the lut. */
+
+ float mip = roughness * lut_lvl_scale;
+ float mip_floor = floor(mip);
+
+ coords.z = lut_lvl_ofs + mip_floor + 1.0;
+ float btdf_high = textureLod(btdf_lut_tex, coords, 0.0).r;
+
+ coords.z -= 1.0;
+ float btdf_low = textureLod(btdf_lut_tex, coords, 0.0).r;
+
+ float btdf = (ior == 1.0) ? 1.0 : mix(btdf_low, btdf_high, mip - coords.z);
+
+ return btdf;
+}
+
+/* ---- Encode / Decode Normal buffer data ---- */
+/* From http://aras-p.info/texts/CompactNormalStorage.html
+ * Using Method #4: Spheremap Transform */
+vec2 normal_encode(vec3 n, vec3 view)
+{
+ float p = sqrt(n.z * 8.0 + 8.0);
+ return n.xy / p + 0.5;
+}
+
+vec3 normal_decode(vec2 enc, vec3 view)
+{
+ vec2 fenc = enc * 4.0 - 2.0;
+ float f = dot(fenc, fenc);
+ float g = sqrt(1.0 - f / 4.0);
+ vec3 n;
+ n.xy = fenc*g;
+ n.z = 1 - f / 2;
+ return n;
+}
+
+/* ---- RGBM (shared multiplier) encoding ---- */
+/* From http://iwasbeingirony.blogspot.fr/2010/06/difference-between-rgbm-and-rgbd.html */
+
+/* Higher RGBM_MAX_RANGE gives imprecision issues in low intensity. */
+#define RGBM_MAX_RANGE 512.0
+
+vec4 rgbm_encode(vec3 rgb)
+{
+ float maxRGB = max_v3(rgb);
+ float M = maxRGB / RGBM_MAX_RANGE;
+ M = ceil(M * 255.0) / 255.0;
+ return vec4(rgb / (M * RGBM_MAX_RANGE), M);
+}
+
+vec3 rgbm_decode(vec4 data)
+{
+ return data.rgb * (data.a * RGBM_MAX_RANGE);
+}
+
+/* ---- RGBE (shared exponent) encoding ---- */
+vec4 rgbe_encode(vec3 rgb)
+{
+ float maxRGB = max_v3(rgb);
+ float fexp = ceil(log2(maxRGB));
+ return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0);
+}
+
+vec3 rgbe_decode(vec4 data)
+{
+ float fexp = data.a * 255.0 - 128.0;
+ return data.rgb * exp2(fexp);
+}
+
+#if 1
+#define irradiance_encode rgbe_encode
+#define irradiance_decode rgbe_decode
+#else /* No ecoding (when using floating point format) */
+#define irradiance_encode(X) (X).rgbb
+#define irradiance_decode(X) (X).rgb
+#endif
+
+/* Irradiance Visibility Encoding */
+#if 1
+vec4 visibility_encode(vec2 accum, float range)
+{
+ accum /= range;
+
+ vec4 data;
+ data.x = fract(accum.x);
+ data.y = floor(accum.x) / 255.0;
+ data.z = fract(accum.y);
+ data.w = floor(accum.y) / 255.0;
+
+ return data;
+}
+
+vec2 visibility_decode(vec4 data, float range)
+{
+ return (data.xz + data.yw * 255.0) * range;
+}
+#else /* No ecoding (when using floating point format) */
+vec4 visibility_encode(vec2 accum, float range)
+{
+ return accum.xyxy;
+}
+
+vec2 visibility_decode(vec4 data, float range)
+{
+ return data.xy;
+}
+#endif
+
+/* Fresnel monochromatic, perfect mirror */
+float F_eta(float eta, float cos_theta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ float c = abs(cos_theta);
+ float g = eta * eta - 1.0 + c * c;
+ float result;
+
+ if (g > 0.0) {
+ g = sqrt(g);
+ vec2 g_c = vec2(g) + vec2(c, -c);
+ float A = g_c.y / g_c.x;
+ A *= A;
+ g_c *= c;
+ float B = (g_c.y - 1.0) / (g_c.x + 1.0);
+ B *= B;
+ result = 0.5 * A * (1.0 + B);
+ }
+ else {
+ result = 1.0; /* TIR (no refracted component) */
+ }
+
+ return result;
+}
+
+/* Fresnel color blend base on fresnel factor */
+vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
+{
+ float f0 = F_eta(eta, 1.0);
+ float fac = saturate((fresnel - f0) / max(1e-8, 1.0 - f0));
+ return mix(f0_color, vec3(1.0), fac);
+}
+
+/* Fresnel */
+vec3 F_schlick(vec3 f0, float cos_theta)
+{
+ float fac = 1.0 - cos_theta;
+ float fac2 = fac * fac;
+ fac = fac2 * fac2 * fac;
+
+ /* Unreal specular matching : if specular color is below 2% intensity,
+ * (using green channel for intensity) treat as shadowning */
+ return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * fac + (1.0 - fac) * f0;
+}
+
+/* Fresnel approximation for LTC area lights (not MRP) */
+vec3 F_area(vec3 f0, vec2 lut)
+{
+ vec2 fac = normalize(lut.xy); /* XXX FIXME this does not work!!! */
+
+ /* Unreal specular matching : if specular color is below 2% intensity,
+ * treat as shadowning */
+ return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * fac.y + fac.x * f0;
+}
+
+/* Fresnel approximation for IBL */
+vec3 F_ibl(vec3 f0, vec2 lut)
+{
+ /* Unreal specular matching : if specular color is below 2% intensity,
+ * treat as shadowning */
+ return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y + lut.x * f0;
+}
+
+/* GGX */
+float D_ggx_opti(float NH, float a2)
+{
+ float tmp = (NH * a2 - NH) * NH + 1.0;
+ return M_PI * tmp*tmp; /* Doing RCP and mul a2 at the end */
+}
+
+float G1_Smith_GGX(float NX, float a2)
+{
+ /* Using Brian Karis approach and refactoring by NX/NX
+ * this way the (2*NL)*(2*NV) in G = G1(V) * G1(L) gets canceled by the brdf denominator 4*NL*NV
+ * Rcp is done on the whole G later
+ * Note that this is not convenient for the transmission formula */
+ return NX + sqrt(NX * (NX - NX * a2) + a2);
+ /* return 2 / (1 + sqrt(1 + a2 * (1 - NX*NX) / (NX*NX) ) ); /* Reference function */
+}
+
+float bsdf_ggx(vec3 N, vec3 L, vec3 V, float roughness)
+{
+ float a = roughness;
+ float a2 = a * a;
+
+ vec3 H = normalize(L + V);
+ float NH = max(dot(N, H), 1e-8);
+ float NL = max(dot(N, L), 1e-8);
+ float NV = max(dot(N, V), 1e-8);
+
+ float G = G1_Smith_GGX(NV, a2) * G1_Smith_GGX(NL, a2); /* Doing RCP at the end */
+ float D = D_ggx_opti(NH, a2);
+
+ /* Denominator is canceled by G1_Smith */
+ /* bsdf = D * G / (4.0 * NL * NV); /* Reference function */
+ return NL * a2 / (D * G); /* NL to Fit cycles Equation : line. 345 in bsdf_microfacet.h */
+}
+
+void accumulate_light(vec3 light, float fac, inout vec4 accum)
+{
+ accum += vec4(light, 1.0) * min(fac, (1.0 - accum.a));
+}
+
+/* ----------- Cone Aperture Approximation --------- */
+
+/* Return a fitted cone angle given the input roughness */
+float cone_cosine(float r)
+{
+ /* Using phong gloss
+ * roughness = sqrt(2/(gloss+2)) */
+ float gloss = -2 + 2 / (r * r);
+ /* Drobot 2014 in GPUPro5 */
+ // return cos(2.0 * sqrt(2.0 / (gloss + 2)));
+ /* Uludag 2014 in GPUPro5 */
+ // return pow(0.244, 1 / (gloss + 1));
+ /* Jimenez 2016 in Practical Realtime Strategies for Accurate Indirect Occlusion*/
+ return exp2(-3.32193 * r * r);
+}
+
+/* --------- Closure ---------- */
+#ifdef VOLUMETRICS
+
+struct Closure {
+ vec3 absorption;
+ vec3 scatter;
+ vec3 emission;
+ float anisotropy;
+};
+
+#define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0)
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ Closure cl;
+ cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
+ cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
+ cl.emission = mix(cl1.emission, cl2.emission, fac);
+ cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
+ return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ Closure cl;
+ cl.absorption = cl1.absorption + cl2.absorption;
+ cl.scatter = cl1.scatter + cl2.scatter;
+ cl.emission = cl1.emission + cl2.emission;
+ cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
+ return cl;
+}
+
+Closure closure_emission(vec3 rgb)
+{
+ Closure cl = CLOSURE_DEFAULT;
+ cl.emission = rgb;
+ return cl;
+}
+
+#else /* VOLUMETRICS */
+
+struct Closure {
+ vec3 radiance;
+ float opacity;
+# ifdef USE_SSS
+ vec4 sss_data;
+# ifdef USE_SSS_ALBEDO
+ vec3 sss_albedo;
+# endif
+# endif
+ vec4 ssr_data;
+ vec2 ssr_normal;
+ int ssr_id;
+};
+
+/* This is hacking ssr_id to tag transparent bsdf */
+#define TRANSPARENT_CLOSURE_FLAG -2
+#define REFRACT_CLOSURE_FLAG -3
+#define NO_SSR -999
+
+# ifdef USE_SSS
+# ifdef USE_SSS_ALBEDO
+#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), -1)
+# else
+#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec4(0.0), vec2(0.0), -1)
+# endif
+# else
+#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec2(0.0), -1)
+# endif
+
+uniform int outputSsrId;
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ Closure cl;
+
+ if (cl1.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
+ cl1.ssr_normal = cl2.ssr_normal;
+ cl1.ssr_data = cl2.ssr_data;
+ cl1.ssr_id = cl2.ssr_id;
+# ifdef USE_SSS
+ cl1.sss_data = cl2.sss_data;
+# ifdef USE_SSS_ALBEDO
+ cl1.sss_albedo = cl2.sss_albedo;
+# endif
+# endif
+ }
+ if (cl2.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
+ cl2.ssr_normal = cl1.ssr_normal;
+ cl2.ssr_data = cl1.ssr_data;
+ cl2.ssr_id = cl1.ssr_id;
+# ifdef USE_SSS
+ cl2.sss_data = cl1.sss_data;
+# ifdef USE_SSS_ALBEDO
+ cl2.sss_albedo = cl1.sss_albedo;
+# endif
+# endif
+ }
+ if (cl1.ssr_id == outputSsrId) {
+ cl.ssr_data = mix(cl1.ssr_data.xyzw, vec4(vec3(0.0), cl1.ssr_data.w), fac); /* do not blend roughness */
+ cl.ssr_normal = cl1.ssr_normal;
+ cl.ssr_id = cl1.ssr_id;
+ }
+ else {
+ cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */
+ cl.ssr_normal = cl2.ssr_normal;
+ cl.ssr_id = cl2.ssr_id;
+ }
+ cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
+ cl.radiance = mix(cl1.radiance * cl1.opacity, cl2.radiance * cl2.opacity, fac);
+ cl.radiance /= max(1e-8, cl.opacity);
+
+# ifdef USE_SSS
+ cl.sss_data.rgb = mix(cl1.sss_data.rgb, cl2.sss_data.rgb, fac);
+ cl.sss_data.a = (cl1.sss_data.a > 0.0) ? cl1.sss_data.a : cl2.sss_data.a;
+# ifdef USE_SSS_ALBEDO
+ /* TODO Find a solution to this. Dither? */
+ cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
+# endif
+# endif
+
+ return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ Closure cl = (cl1.ssr_id == outputSsrId) ? cl1 : cl2;
+# ifdef USE_SSS
+ cl.sss_data = (cl1.sss_data.a > 0.0) ? cl1.sss_data : cl2.sss_data;
+# ifdef USE_SSS_ALBEDO
+ /* TODO Find a solution to this. Dither? */
+ cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
+# endif
+# endif
+ cl.radiance = cl1.radiance + cl2.radiance;
+ cl.opacity = saturate(cl1.opacity + cl2.opacity);
+ return cl;
+}
+
+Closure closure_emission(vec3 rgb)
+{
+ Closure cl = CLOSURE_DEFAULT;
+ cl.radiance = rgb;
+ return cl;
+}
+
+# if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY)
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 ssrNormals;
+layout(location = 2) out vec4 ssrData;
+# ifdef USE_SSS
+layout(location = 3) out vec4 sssData;
+# ifdef USE_SSS_ALBEDO
+layout(location = 4) out vec4 sssAlbedo;
+# endif /* USE_SSS_ALBEDO */
+# endif /* USE_SSS */
+
+Closure nodetree_exec(void); /* Prototype */
+
+# if defined(USE_ALPHA_BLEND_VOLUMETRICS)
+/* Prototype because this file is included before volumetric_lib.glsl */
+vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth);
+# endif
+
+#define NODETREE_EXEC
+void main()
+{
+ Closure cl = nodetree_exec();
+# ifndef USE_ALPHA_BLEND
+ /* Prevent alpha hash material writing into alpha channel. */
+ cl.opacity = 1.0;
+# endif
+
+# if defined(USE_ALPHA_BLEND_VOLUMETRICS)
+ /* XXX fragile, better use real viewport resolution */
+ vec2 uvs = gl_FragCoord.xy / vec2(2 * textureSize(maxzBuffer, 0).xy);
+ fragColor = volumetric_resolve(vec4(cl.radiance, cl.opacity), uvs, gl_FragCoord.z);
+# else
+ fragColor = vec4(cl.radiance, cl.opacity);
+# endif
+
+ ssrNormals = cl.ssr_normal.xyyy;
+ ssrData = cl.ssr_data;
+# ifdef USE_SSS
+ sssData = cl.sss_data;
+# ifdef USE_SSS_ALBEDO
+ sssAlbedo = cl.sss_albedo.rgbb;
+# endif
+# endif
+
+ /* For Probe capture */
+# ifdef USE_SSS
+# ifdef USE_SSS_ALBEDO
+ fragColor.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * float(!sssToggle);
+# else
+ fragColor.rgb += cl.sss_data.rgb * float(!sssToggle);
+# endif
+# endif
+}
+
+# endif /* MESH_SHADER && !SHADOW_SHADER */
+
+#endif /* VOLUMETRICS */
+
+Closure nodetree_exec(void); /* Prototype */
+
+/* TODO find a better place */
+#ifdef USE_MULTIPLY
+
+out vec4 fragColor;
+
+#define NODETREE_EXEC
+void main()
+{
+ Closure cl = nodetree_exec();
+ fragColor = vec4(mix(vec3(1.0), cl.radiance, cl.opacity), 1.0);
+}
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl
new file mode 100644
index 00000000000..7fb4ee51a96
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl
@@ -0,0 +1,46 @@
+
+out vec4 FragColor;
+
+void main() {
+ vec3 N, T, B, V;
+
+ float NV = ( 1.0 - (clamp(gl_FragCoord.y / BRDF_LUT_SIZE, 1e-4, 0.9999)));
+ float sqrtRoughness = clamp(gl_FragCoord.x / BRDF_LUT_SIZE, 1e-4, 0.9999);
+ float a = sqrtRoughness * sqrtRoughness;
+ float a2 = a * a;
+
+ N = vec3(0.0, 0.0, 1.0);
+ T = vec3(1.0, 0.0, 0.0);
+ B = vec3(0.0, 1.0, 0.0);
+ V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
+
+ setup_noise();
+
+ /* Integrating BRDF */
+ float brdf_accum = 0.0;
+ float fresnel_accum = 0.0;
+ for (float i = 0; i < sampleCount; i++) {
+ vec3 H = sample_ggx(i, a2, N, T, B); /* Microfacet normal */
+ vec3 L = -reflect(V, H);
+ float NL = L.z;
+
+ if (NL > 0.0) {
+ float NH = max(H.z, 0.0);
+ float VH = max(dot(V, H), 0.0);
+
+ float G1_v = G1_Smith_GGX(NV, a2);
+ float G1_l = G1_Smith_GGX(NL, a2);
+ float G_smith = 4.0 * NV * NL / (G1_v * G1_l); /* See G1_Smith_GGX for explanations. */
+
+ float brdf = (G_smith * VH) / (NH * NV);
+ float Fc = pow(1.0 - VH, 5.0);
+
+ brdf_accum += (1.0 - Fc) * brdf;
+ fresnel_accum += Fc * brdf;
+ }
+ }
+ brdf_accum /= sampleCount;
+ fresnel_accum /= sampleCount;
+
+ FragColor = vec4(brdf_accum, fresnel_accum, 0.0, 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
new file mode 100644
index 00000000000..cce9d59dc12
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
@@ -0,0 +1,107 @@
+
+uniform sampler1D texHammersley;
+uniform sampler2D texJitter;
+uniform float sampleCount;
+uniform float invSampleCount;
+
+vec2 jitternoise = vec2(0.0);
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
+uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
+
+void setup_noise(void)
+{
+ jitternoise = texelfetch_noise_tex(gl_FragCoord.xy).rg; /* Global variable */
+}
+
+#ifdef HAMMERSLEY_SIZE
+vec3 hammersley_3d(float i, float invsamplenbr)
+{
+ vec3 Xi; /* Theta, cos(Phi), sin(Phi) */
+
+ Xi.x = i * invsamplenbr; /* i/samples */
+ Xi.x = fract(Xi.x + jitternoise.x);
+
+ int u = int(mod(i + jitternoise.y * HAMMERSLEY_SIZE, HAMMERSLEY_SIZE));
+
+ Xi.yz = texelFetch(texHammersley, u, 0).rg;
+
+ return Xi;
+}
+
+vec3 hammersley_3d(float i)
+{
+ return hammersley_3d(i, invSampleCount);
+}
+#endif
+
+/* -------------- BSDFS -------------- */
+
+float pdf_ggx_reflect(float NH, float a2)
+{
+ return NH * a2 / D_ggx_opti(NH, a2);
+}
+
+float pdf_hemisphere()
+{
+ return 0.5 * M_1_PI;
+}
+
+vec3 sample_ggx(vec3 rand, float a2)
+{
+ /* Theta is the aperture angle of the cone */
+ float z = sqrt( (1.0 - rand.x) / ( 1.0 + a2 * rand.x - rand.x ) ); /* cos theta */
+ float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */
+ float x = r * rand.y;
+ float y = r * rand.z;
+
+ /* Microfacet Normal */
+ return vec3(x, y, z);
+}
+
+vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH)
+{
+ vec3 Ht = sample_ggx(rand, a2);
+ NH = Ht.z;
+ return tangent_to_world(Ht, N, T, B);
+}
+
+#ifdef HAMMERSLEY_SIZE
+vec3 sample_ggx(float nsample, float a2, vec3 N, vec3 T, vec3 B)
+{
+ vec3 Xi = hammersley_3d(nsample);
+ vec3 Ht = sample_ggx(Xi, a2);
+ return tangent_to_world(Ht, N, T, B);
+}
+
+vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B)
+{
+ vec3 Xi = hammersley_3d(nsample);
+
+ float z = Xi.x; /* cos theta */
+ float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */
+ float x = r * Xi.y;
+ float y = r * Xi.z;
+
+ vec3 Ht = vec3(x, y, z);
+
+ return tangent_to_world(Ht, N, T, B);
+}
+
+vec3 sample_cone(float nsample, float angle, vec3 N, vec3 T, vec3 B)
+{
+ vec3 Xi = hammersley_3d(nsample);
+
+ float z = cos(angle * Xi.x); /* cos theta */
+ float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */
+ float x = r * Xi.y;
+ float y = r * Xi.z;
+
+ vec3 Ht = vec3(x, y, z);
+
+ return tangent_to_world(Ht, N, T, B);
+}
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
new file mode 100644
index 00000000000..5f0af6a6f5b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
@@ -0,0 +1,59 @@
+
+uniform float a2;
+
+out vec4 FragColor;
+
+void main() {
+ vec3 N, T, B, V;
+
+ float x = gl_FragCoord.x / BRDF_LUT_SIZE;
+ float y = gl_FragCoord.y / BRDF_LUT_SIZE;
+ /* There is little variation if ior > 1.0 so we
+ * maximize LUT precision for ior < 1.0 */
+ x = x * 1.1;
+ float ior = (x > 1.0) ? ior_from_f0((x-1.0) * 10.0) : sqrt(x);
+ float NV = (1.0 - (clamp(y, 1e-4, 0.9999)));
+
+ N = vec3(0.0, 0.0, 1.0);
+ T = vec3(1.0, 0.0, 0.0);
+ B = vec3(0.0, 1.0, 0.0);
+ V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
+
+ setup_noise();
+
+ /* Integrating BTDF */
+ float btdf_accum = 0.0;
+ for (float i = 0.0; i < sampleCount; i++) {
+ vec3 H = sample_ggx(i, a2, N, T, B); /* Microfacet normal */
+
+ float VH = dot(V, H);
+
+ /* Check if there is total internal reflections. */
+ float c = abs(VH);
+ float g = ior * ior - 1.0 + c * c;
+
+ float eta = 1.0/ior;
+ if (dot(H, V) < 0.0) {
+ H = -H;
+ eta = ior;
+ }
+
+ vec3 L = refract(-V, H, eta);
+ float NL = -dot(N, L);
+
+ if ((NL > 0.0) && (g > 0.0)) {
+ float LH = dot(L, H);
+
+ float G1_l = NL * 2.0 / G1_Smith_GGX(NL, a2); /* Balancing the adjustments made in G1_Smith */
+
+ /* btdf = abs(VH*LH) * (ior*ior) * D * G(V) * G(L) / (Ht2 * NV)
+ * pdf = (VH * abs(LH)) * (ior*ior) * D * G(V) / (Ht2 * NV) */
+ float btdf = G1_l * abs(VH*LH) / (VH * abs(LH));
+
+ btdf_accum += btdf;
+ }
+ }
+ btdf_accum /= sampleCount;
+
+ FragColor = vec4(btdf_accum, 0.0, 0.0, 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
new file mode 100644
index 00000000000..9c5a212aead
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
@@ -0,0 +1,66 @@
+
+layout(std140) uniform common_block {
+ mat4 pastViewProjectionMatrix;
+ vec4 viewVecs[2];
+ vec2 mipRatio[10]; /* To correct mip level texel mis-alignement */
+ /* Ambient Occlusion */
+ vec4 aoParameters[2];
+ /* Volumetric */
+ ivec4 volTexSize;
+ vec4 volDepthParameters; /* Parameters to the volume Z equation */
+ vec4 volInvTexSize;
+ vec4 volJitter;
+ vec4 volCoordScale; /* To convert volume uvs to screen uvs */
+ float volHistoryAlpha;
+ float volLightClamp;
+ float volShadowSteps;
+ bool volUseLights;
+ /* Screen Space Reflections */
+ vec4 ssrParameters;
+ float ssrBorderFac;
+ float ssrMaxRoughness;
+ float ssrFireflyFac;
+ float ssrBrdfBias;
+ bool ssrToggle;
+ /* SubSurface Scattering */
+ float sssJitterThreshold;
+ bool sssToggle;
+ /* Specular */
+ bool specToggle;
+ /* Lamps */
+ int laNumLight;
+ /* Probes */
+ int prbNumPlanar;
+ int prbNumRenderCube;
+ int prbNumRenderGrid;
+ int prbIrradianceVisSize;
+ float prbIrradianceSmooth;
+ float prbLodCubeMax;
+ float prbLodPlanarMax;
+ /* Misc*/
+ int hizMipOffset;
+ int rayType;
+ float rayDepth;
+};
+
+/* rayType (keep in sync with ray_type) */
+#define EEVEE_RAY_CAMERA 0
+#define EEVEE_RAY_SHADOW 1
+#define EEVEE_RAY_DIFFUSE 2
+#define EEVEE_RAY_GLOSSY 3
+
+/* aoParameters */
+#define aoDistance aoParameters[0].x
+#define aoSamples aoParameters[0].y /* UNUSED */
+#define aoFactor aoParameters[0].z
+#define aoInvSamples aoParameters[0].w /* UNUSED */
+
+#define aoOffset aoParameters[1].x /* UNUSED */
+#define aoBounceFac aoParameters[1].y
+#define aoQuality aoParameters[1].z
+#define aoSettings aoParameters[1].w
+
+/* ssrParameters */
+#define ssrQuality ssrParameters.x
+#define ssrThickness ssrParameters.y
+#define ssrPixelSize ssrParameters.zw
diff --git a/source/blender/draw/engines/eevee/shaders/concentric_samples_lib.glsl b/source/blender/draw/engines/eevee/shaders/concentric_samples_lib.glsl
new file mode 100644
index 00000000000..7de27a9fda9
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/concentric_samples_lib.glsl
@@ -0,0 +1,267 @@
+/* Precomputed table of concentric samples.
+ * Generated using this algorithm http://l2program.co.uk/900/concentric-disk-sampling
+ * Sorted by radius then by rotation angle.
+ * This way it's better for cache usage and for
+ * easily restricting to a certain number of
+ * sample while still having a circular kernel. */
+
+#define CONCENTRIC_SAMPLE_NUM 256
+const vec2 concentric[CONCENTRIC_SAMPLE_NUM] =
+vec2[CONCENTRIC_SAMPLE_NUM](
+ vec2(0.0441941738242, 0.0441941738242),
+ vec2(-0.0441941738242, -0.0441941738242),
+ vec2(-0.0441941738242, 0.0441941738242),
+ vec2(0.0441941738242, -0.0441941738242),
+ vec2(0.181111092429, 0.0485285709567),
+ vec2(0.132582521472, 0.132582521472),
+ vec2(-0.181111092429, 0.0485285709567),
+ vec2(0.0485285709567, 0.181111092429),
+ vec2(-0.181111092429, -0.0485285709567),
+ vec2(-0.0485285709567, 0.181111092429),
+ vec2(-0.132582521472, -0.132582521472),
+ vec2(-0.132582521472, 0.132582521472),
+ vec2(-0.0485285709567, -0.181111092429),
+ vec2(0.0485285709567, -0.181111092429),
+ vec2(0.132582521472, -0.132582521472),
+ vec2(0.181111092429, -0.0485285709567),
+ vec2(0.308652606436, 0.0488857703251),
+ vec2(0.278439538809, 0.141872031169),
+ vec2(0.220970869121, 0.220970869121),
+ vec2(-0.278439538809, 0.141872031169),
+ vec2(0.141872031169, 0.278439538809),
+ vec2(-0.308652606436, 0.0488857703251),
+ vec2(0.0488857703251, 0.308652606436),
+ vec2(-0.308652606436, -0.0488857703251),
+ vec2(-0.0488857703251, 0.308652606436),
+ vec2(-0.278439538809, -0.141872031169),
+ vec2(-0.141872031169, 0.278439538809),
+ vec2(-0.220970869121, -0.220970869121),
+ vec2(-0.220970869121, 0.220970869121),
+ vec2(-0.141872031169, -0.278439538809),
+ vec2(-0.0488857703251, -0.308652606436),
+ vec2(0.0488857703251, -0.308652606436),
+ vec2(0.141872031169, -0.278439538809),
+ vec2(0.220970869121, -0.220970869121),
+ vec2(0.278439538809, -0.141872031169),
+ vec2(0.308652606436, -0.0488857703251),
+ vec2(0.434749091828, 0.0489844582952),
+ vec2(0.41294895701, 0.144497089605),
+ vec2(0.370441837162, 0.232764033475),
+ vec2(0.309359216769, 0.309359216769),
+ vec2(-0.370441837162, 0.232764033475),
+ vec2(0.232764033475, 0.370441837162),
+ vec2(-0.41294895701, 0.144497089605),
+ vec2(0.144497089605, 0.41294895701),
+ vec2(-0.434749091828, 0.0489844582952),
+ vec2(0.0489844582952, 0.434749091828),
+ vec2(-0.434749091828, -0.0489844582952),
+ vec2(-0.0489844582952, 0.434749091828),
+ vec2(-0.41294895701, -0.144497089605),
+ vec2(-0.144497089605, 0.41294895701),
+ vec2(-0.370441837162, -0.232764033475),
+ vec2(-0.232764033475, 0.370441837162),
+ vec2(-0.309359216769, -0.309359216769),
+ vec2(-0.309359216769, 0.309359216769),
+ vec2(-0.232764033475, -0.370441837162),
+ vec2(-0.144497089605, -0.41294895701),
+ vec2(-0.0489844582952, -0.434749091828),
+ vec2(0.0489844582952, -0.434749091828),
+ vec2(0.144497089605, -0.41294895701),
+ vec2(0.232764033475, -0.370441837162),
+ vec2(0.309359216769, -0.309359216769),
+ vec2(0.370441837162, -0.232764033475),
+ vec2(0.41294895701, -0.144497089605),
+ vec2(0.434749091828, -0.0489844582952),
+ vec2(0.560359517677, 0.0490251052956),
+ vec2(0.543333277288, 0.14558571287),
+ vec2(0.509798130208, 0.237722772229),
+ vec2(0.460773024913, 0.322636745447),
+ vec2(0.397747564417, 0.397747564417),
+ vec2(-0.460773024913, 0.322636745447),
+ vec2(0.322636745447, 0.460773024913),
+ vec2(-0.509798130208, 0.237722772229),
+ vec2(0.237722772229, 0.509798130208),
+ vec2(-0.543333277288, 0.14558571287),
+ vec2(0.14558571287, 0.543333277288),
+ vec2(-0.560359517677, 0.0490251052956),
+ vec2(0.0490251052956, 0.560359517677),
+ vec2(-0.560359517677, -0.0490251052956),
+ vec2(-0.0490251052956, 0.560359517677),
+ vec2(-0.543333277288, -0.14558571287),
+ vec2(-0.14558571287, 0.543333277288),
+ vec2(-0.509798130208, -0.237722772229),
+ vec2(-0.237722772229, 0.509798130208),
+ vec2(-0.460773024913, -0.322636745447),
+ vec2(-0.322636745447, 0.460773024913),
+ vec2(-0.397747564417, -0.397747564417),
+ vec2(-0.397747564417, 0.397747564417),
+ vec2(-0.322636745447, -0.460773024913),
+ vec2(-0.237722772229, -0.509798130208),
+ vec2(-0.14558571287, -0.543333277288),
+ vec2(-0.0490251052956, -0.560359517677),
+ vec2(0.0490251052956, -0.560359517677),
+ vec2(0.14558571287, -0.543333277288),
+ vec2(0.237722772229, -0.509798130208),
+ vec2(0.322636745447, -0.460773024913),
+ vec2(0.397747564417, -0.397747564417),
+ vec2(0.460773024913, -0.322636745447),
+ vec2(0.509798130208, -0.237722772229),
+ vec2(0.543333277288, -0.14558571287),
+ vec2(0.560359517677, -0.0490251052956),
+ vec2(0.685748328795, 0.0490456884495),
+ vec2(0.671788470355, 0.146138636568),
+ vec2(0.644152935937, 0.240256623474),
+ vec2(0.603404305327, 0.32948367837),
+ vec2(0.550372103135, 0.412003395727),
+ vec2(0.486135912066, 0.486135912066),
+ vec2(-0.550372103135, 0.412003395727),
+ vec2(0.412003395727, 0.550372103135),
+ vec2(-0.603404305327, 0.32948367837),
+ vec2(0.32948367837, 0.603404305327),
+ vec2(-0.644152935937, 0.240256623474),
+ vec2(0.240256623474, 0.644152935937),
+ vec2(-0.671788470355, 0.146138636568),
+ vec2(0.146138636568, 0.671788470355),
+ vec2(-0.685748328795, 0.0490456884495),
+ vec2(0.0490456884495, 0.685748328795),
+ vec2(-0.685748328795, -0.0490456884495),
+ vec2(-0.0490456884495, 0.685748328795),
+ vec2(-0.671788470355, -0.146138636568),
+ vec2(-0.146138636568, 0.671788470355),
+ vec2(-0.644152935937, -0.240256623474),
+ vec2(-0.240256623474, 0.644152935937),
+ vec2(-0.603404305327, -0.32948367837),
+ vec2(-0.32948367837, 0.603404305327),
+ vec2(-0.550372103135, -0.412003395727),
+ vec2(-0.412003395727, 0.550372103135),
+ vec2(-0.486135912066, -0.486135912066),
+ vec2(-0.486135912066, 0.486135912066),
+ vec2(-0.412003395727, -0.550372103135),
+ vec2(-0.32948367837, -0.603404305327),
+ vec2(-0.240256623474, -0.644152935937),
+ vec2(-0.146138636568, -0.671788470355),
+ vec2(-0.0490456884495, -0.685748328795),
+ vec2(0.0490456884495, -0.685748328795),
+ vec2(0.146138636568, -0.671788470355),
+ vec2(0.240256623474, -0.644152935937),
+ vec2(0.32948367837, -0.603404305327),
+ vec2(0.412003395727, -0.550372103135),
+ vec2(0.486135912066, -0.486135912066),
+ vec2(0.550372103135, -0.412003395727),
+ vec2(0.603404305327, -0.32948367837),
+ vec2(0.644152935937, -0.240256623474),
+ vec2(0.671788470355, -0.146138636568),
+ vec2(0.685748328795, -0.0490456884495),
+ vec2(0.811017637806, 0.0490575291556),
+ vec2(0.799191174395, 0.146457218224),
+ vec2(0.775710704038, 0.241721231257),
+ vec2(0.740918624869, 0.33346040443),
+ vec2(0.695322283745, 0.420336974019),
+ vec2(0.639586577995, 0.501084084011),
+ vec2(0.574524259714, 0.574524259714),
+ vec2(-0.639586577995, 0.501084084011),
+ vec2(0.501084084011, 0.639586577995),
+ vec2(-0.695322283745, 0.420336974019),
+ vec2(0.420336974019, 0.695322283745),
+ vec2(-0.740918624869, 0.33346040443),
+ vec2(0.33346040443, 0.740918624869),
+ vec2(-0.775710704038, 0.241721231257),
+ vec2(0.241721231257, 0.775710704038),
+ vec2(-0.799191174395, 0.146457218224),
+ vec2(0.146457218224, 0.799191174395),
+ vec2(-0.811017637806, 0.0490575291556),
+ vec2(0.0490575291556, 0.811017637806),
+ vec2(-0.811017637806, -0.0490575291556),
+ vec2(-0.0490575291556, 0.811017637806),
+ vec2(-0.799191174395, -0.146457218224),
+ vec2(-0.146457218224, 0.799191174395),
+ vec2(-0.775710704038, -0.241721231257),
+ vec2(-0.241721231257, 0.775710704038),
+ vec2(-0.740918624869, -0.33346040443),
+ vec2(-0.33346040443, 0.740918624869),
+ vec2(-0.695322283745, -0.420336974019),
+ vec2(-0.420336974019, 0.695322283745),
+ vec2(-0.639586577995, -0.501084084011),
+ vec2(-0.501084084011, 0.639586577995),
+ vec2(-0.574524259714, -0.574524259714),
+ vec2(-0.574524259714, 0.574524259714),
+ vec2(-0.501084084011, -0.639586577995),
+ vec2(-0.420336974019, -0.695322283745),
+ vec2(-0.33346040443, -0.740918624869),
+ vec2(-0.241721231257, -0.775710704038),
+ vec2(-0.146457218224, -0.799191174395),
+ vec2(-0.0490575291556, -0.811017637806),
+ vec2(0.0490575291556, -0.811017637806),
+ vec2(0.146457218224, -0.799191174395),
+ vec2(0.241721231257, -0.775710704038),
+ vec2(0.33346040443, -0.740918624869),
+ vec2(0.420336974019, -0.695322283745),
+ vec2(0.501084084011, -0.639586577995),
+ vec2(0.574524259714, -0.574524259714),
+ vec2(0.639586577995, -0.501084084011),
+ vec2(0.695322283745, -0.420336974019),
+ vec2(0.740918624869, -0.33346040443),
+ vec2(0.775710704038, -0.241721231257),
+ vec2(0.799191174395, -0.146457218224),
+ vec2(0.811017637806, -0.0490575291556),
+ vec2(0.936215188832, 0.0490649589778),
+ vec2(0.925957819308, 0.146657310975),
+ vec2(0.905555462146, 0.242642854784),
+ vec2(0.875231649841, 0.335969952699),
+ vec2(0.835318616427, 0.425616093506),
+ vec2(0.786253657449, 0.510599095327),
+ vec2(0.728574338866, 0.589987866609),
+ vec2(0.662912607362, 0.662912607362),
+ vec2(-0.728574338866, 0.589987866609),
+ vec2(0.589987866609, 0.728574338866),
+ vec2(-0.786253657449, 0.510599095327),
+ vec2(0.510599095327, 0.786253657449),
+ vec2(-0.835318616427, 0.425616093506),
+ vec2(0.425616093506, 0.835318616427),
+ vec2(-0.875231649841, 0.335969952699),
+ vec2(0.335969952699, 0.875231649841),
+ vec2(-0.905555462146, 0.242642854784),
+ vec2(0.242642854784, 0.905555462146),
+ vec2(-0.925957819308, 0.146657310975),
+ vec2(0.146657310975, 0.925957819308),
+ vec2(-0.936215188832, 0.0490649589778),
+ vec2(0.0490649589778, 0.936215188832),
+ vec2(-0.936215188832, -0.0490649589778),
+ vec2(-0.0490649589778, 0.936215188832),
+ vec2(-0.925957819308, -0.146657310975),
+ vec2(-0.146657310975, 0.925957819308),
+ vec2(-0.905555462146, -0.242642854784),
+ vec2(-0.242642854784, 0.905555462146),
+ vec2(-0.875231649841, -0.335969952699),
+ vec2(-0.335969952699, 0.875231649841),
+ vec2(-0.835318616427, -0.425616093506),
+ vec2(-0.425616093506, 0.835318616427),
+ vec2(-0.786253657449, -0.510599095327),
+ vec2(-0.510599095327, 0.786253657449),
+ vec2(-0.728574338866, -0.589987866609),
+ vec2(-0.589987866609, 0.728574338866),
+ vec2(-0.662912607362, -0.662912607362),
+ vec2(-0.662912607362, 0.662912607362),
+ vec2(-0.589987866609, -0.728574338866),
+ vec2(-0.510599095327, -0.786253657449),
+ vec2(-0.425616093506, -0.835318616427),
+ vec2(-0.335969952699, -0.875231649841),
+ vec2(-0.242642854784, -0.905555462146),
+ vec2(-0.146657310975, -0.925957819308),
+ vec2(-0.0490649589778, -0.936215188832),
+ vec2(0.0490649589778, -0.936215188832),
+ vec2(0.146657310975, -0.925957819308),
+ vec2(0.242642854784, -0.905555462146),
+ vec2(0.335969952699, -0.875231649841),
+ vec2(0.425616093506, -0.835318616427),
+ vec2(0.510599095327, -0.786253657449),
+ vec2(0.589987866609, -0.728574338866),
+ vec2(0.662912607362, -0.662912607362),
+ vec2(0.728574338866, -0.589987866609),
+ vec2(0.786253657449, -0.510599095327),
+ vec2(0.835318616427, -0.425616093506),
+ vec2(0.875231649841, -0.335969952699),
+ vec2(0.905555462146, -0.242642854784),
+ vec2(0.925957819308, -0.146657310975),
+ vec2(0.936215188832, -0.0490649589778)
+);
diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
new file mode 100644
index 00000000000..3a5f6171a16
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
@@ -0,0 +1,47 @@
+
+uniform vec3 basecol;
+uniform float metallic;
+uniform float specular;
+uniform float roughness;
+
+Closure nodetree_exec(void)
+{
+#ifdef HAIR_SHADER
+ vec3 B = normalize(cross(worldNormal, hairTangent));
+ float cos_theta;
+ if (hairThicknessRes == 1) {
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ /* Random cosine normal distribution on the hair surface. */
+ cos_theta = rand.x * 2.0 - 1.0;
+ }
+ else {
+ /* Shade as a cylinder. */
+ cos_theta = hairThickTime / hairThickness;
+ }
+ float sin_theta = sqrt(max(0.0, 1.0f - cos_theta*cos_theta));
+ vec3 N = normalize(worldNormal * sin_theta + B * cos_theta);
+ vec3 vN = mat3(ViewMatrix) * N;
+#else
+ vec3 N = normalize(gl_FrontFacing ? worldNormal : -worldNormal);
+ vec3 vN = normalize(gl_FrontFacing ? viewNormal : -viewNormal);
+#endif
+
+ vec3 dielectric = vec3(0.034) * specular * 2.0;
+ vec3 albedo = mix(basecol, vec3(0.0), metallic);
+ vec3 f0 = mix(dielectric, basecol, metallic);
+ vec3 out_diff, out_spec, ssr_spec;
+ eevee_closure_default(N, albedo, f0, 1, roughness, 1.0, out_diff, out_spec, ssr_spec);
+
+ Closure result = Closure(
+ out_spec + out_diff * albedo,
+ 1.0,
+ vec4(ssr_spec, roughness),
+ normal_encode(vN, viewCameraVec),
+ 0);
+
+#ifdef LOOKDEV
+ gl_FragDepth = 0.0;
+#endif
+
+ return result;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
new file mode 100644
index 00000000000..126f2d9610a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/default_world_frag.glsl
@@ -0,0 +1,62 @@
+
+uniform float backgroundAlpha;
+uniform vec3 color;
+
+out vec4 FragColor;
+
+#ifdef LOOKDEV
+uniform mat4 ProjectionMatrix;
+uniform mat4 ProjectionMatrixInverse;
+uniform mat4 ViewMatrixInverse;
+uniform mat3 StudioLightMatrix;
+uniform sampler2D image;
+uniform float studioLightBackground = 1.0;
+in vec3 viewPosition;
+
+#define M_PI 3.14159265358979323846
+
+vec3 background_transform_to_world(vec3 viewvec)
+{
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
+
+ vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
+ return (ViewMatrixInverse * co).xyz;
+}
+
+float hypot(float x, float y)
+{
+ return sqrt(x * x + y * y);
+}
+
+vec4 node_tex_environment_equirectangular(vec3 co, sampler2D ima)
+{
+ vec3 nco = normalize(co);
+ float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
+ float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
+
+ /* Fix pole bleeding */
+ float width = float(textureSize(ima, 0).x);
+ float texel_width = 1.0 / width;
+ v = clamp(v, texel_width, 1.0 - texel_width);
+
+ /* Fix u = 0 seam */
+ /* This is caused by texture filtering, since uv don't have smooth derivatives
+ * at u = 0 or 2PI, hardware filtering is using the smallest mipmap for certain
+ * texels. So we force the highest mipmap and don't do anisotropic filtering. */
+ return textureLod(ima, vec2(u, v), 0.0);
+}
+#endif
+
+void main() {
+ vec3 background_color;
+#ifdef LOOKDEV
+ vec3 worldvec = background_transform_to_world(viewPosition);
+ background_color = node_tex_environment_equirectangular(StudioLightMatrix * worldvec, image).rgb;
+ background_color = mix(color, background_color, studioLightBackground);
+#else
+ background_color = color;
+#endif
+
+ FragColor = vec4(clamp(background_color, vec3(0.0), vec3(1e10)), backgroundAlpha);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
new file mode 100644
index 00000000000..c3674c8f74c
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
@@ -0,0 +1,218 @@
+/* Original implementation by Keijiro Takahashi
+ * Blender integration by Clément Foucault
+ *
+ * Original License :
+ *
+ * Kino/Bloom v2 - Bloom filter for Unity
+ *
+ * Copyright (C) 2015, 2016 Keijiro Takahashi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ **/
+
+uniform sampler2D sourceBuffer; /* Buffer to filter */
+uniform vec2 sourceBufferTexelSize;
+
+/* Step Blit */
+uniform vec4 curveThreshold;
+uniform float clampIntensity;
+
+/* Step Upsample */
+uniform sampler2D baseBuffer; /* Previous accumulation buffer */
+uniform vec2 baseBufferTexelSize;
+uniform float sampleScale;
+
+/* Step Resolve */
+uniform vec3 bloomColor;
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+/* -------------- Utils ------------- */
+
+vec3 safe_color(vec3 c)
+{
+ /* Clamp to avoid black square artifacts if a pixel goes NaN. */
+ return clamp(c, vec3(0.0), vec3(1e20)); /* 1e20 arbitrary. */
+}
+
+float brightness(vec3 c)
+{
+ return max(max(c.r, c.g), c.b);
+}
+
+/* 3-tap median filter */
+vec3 median(vec3 a, vec3 b, vec3 c)
+{
+ return a + b + c - min(min(a, b), c) - max(max(a, b), c);
+}
+
+/* ------------- Filters ------------ */
+
+vec3 downsample_filter_high(sampler2D tex, vec2 uv, vec2 texelSize)
+{
+ /* Downsample with a 4x4 box filter + anti-flicker filter */
+ vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1);
+
+ vec3 s1 = textureLod(tex, uv + d.xy, 0.0).rgb;
+ vec3 s2 = textureLod(tex, uv + d.zy, 0.0).rgb;
+ vec3 s3 = textureLod(tex, uv + d.xw, 0.0).rgb;
+ vec3 s4 = textureLod(tex, uv + d.zw, 0.0).rgb;
+
+ /* Karis's luma weighted average (using brightness instead of luma) */
+ float s1w = 1.0 / (brightness(s1) + 1.0);
+ float s2w = 1.0 / (brightness(s2) + 1.0);
+ float s3w = 1.0 / (brightness(s3) + 1.0);
+ float s4w = 1.0 / (brightness(s4) + 1.0);
+ float one_div_wsum = 1.0 / (s1w + s2w + s3w + s4w);
+
+ return (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * one_div_wsum;
+}
+
+vec3 downsample_filter(sampler2D tex, vec2 uv, vec2 texelSize)
+{
+ /* Downsample with a 4x4 box filter */
+ vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1);
+
+ vec3 s;
+ s = textureLod(tex, uv + d.xy, 0.0).rgb;
+ s += textureLod(tex, uv + d.zy, 0.0).rgb;
+ s += textureLod(tex, uv + d.xw, 0.0).rgb;
+ s += textureLod(tex, uv + d.zw, 0.0).rgb;
+
+ return s * (1.0 / 4);
+}
+
+vec3 upsample_filter_high(sampler2D tex, vec2 uv, vec2 texelSize)
+{
+ /* 9-tap bilinear upsampler (tent filter) */
+ vec4 d = texelSize.xyxy * vec4(1, 1, -1, 0) * sampleScale;
+
+ vec3 s;
+ s = textureLod(tex, uv - d.xy, 0.0).rgb;
+ s += textureLod(tex, uv - d.wy, 0.0).rgb * 2;
+ s += textureLod(tex, uv - d.zy, 0.0).rgb;
+
+ s += textureLod(tex, uv + d.zw, 0.0).rgb * 2;
+ s += textureLod(tex, uv , 0.0).rgb * 4;
+ s += textureLod(tex, uv + d.xw, 0.0).rgb * 2;
+
+ s += textureLod(tex, uv + d.zy, 0.0).rgb;
+ s += textureLod(tex, uv + d.wy, 0.0).rgb * 2;
+ s += textureLod(tex, uv + d.xy, 0.0).rgb;
+
+ return s * (1.0 / 16.0);
+}
+
+vec3 upsample_filter(sampler2D tex, vec2 uv, vec2 texelSize)
+{
+ /* 4-tap bilinear upsampler */
+ vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1) * (sampleScale * 0.5);
+
+ vec3 s;
+ s = textureLod(tex, uv + d.xy, 0.0).rgb;
+ s += textureLod(tex, uv + d.zy, 0.0).rgb;
+ s += textureLod(tex, uv + d.xw, 0.0).rgb;
+ s += textureLod(tex, uv + d.zw, 0.0).rgb;
+
+ return s * (1.0 / 4.0);
+}
+
+/* ----------- Steps ----------- */
+
+vec4 step_blit(void)
+{
+ vec2 uv = uvcoordsvar.xy + sourceBufferTexelSize.xy * 0.5;
+
+#ifdef HIGH_QUALITY /* Anti flicker */
+ vec3 d = sourceBufferTexelSize.xyx * vec3(1, 1, 0);
+ vec3 s0 = safe_color(textureLod(sourceBuffer, uvcoordsvar.xy, 0.0).rgb);
+ vec3 s1 = safe_color(textureLod(sourceBuffer, uvcoordsvar.xy - d.xz, 0.0).rgb);
+ vec3 s2 = safe_color(textureLod(sourceBuffer, uvcoordsvar.xy + d.xz, 0.0).rgb);
+ vec3 s3 = safe_color(textureLod(sourceBuffer, uvcoordsvar.xy - d.zy, 0.0).rgb);
+ vec3 s4 = safe_color(textureLod(sourceBuffer, uvcoordsvar.xy + d.zy, 0.0).rgb);
+ vec3 m = median(median(s0.rgb, s1, s2), s3, s4);
+#else
+ vec3 s0 = safe_color(textureLod(sourceBuffer, uvcoordsvar.xy, 0.0).rgb);
+ vec3 m = s0.rgb;
+#endif
+
+ /* Pixel brightness */
+ float br = brightness(m);
+
+ /* Under-threshold part: quadratic curve */
+ float rq = clamp(br - curveThreshold.x, 0, curveThreshold.y);
+ rq = curveThreshold.z * rq * rq;
+
+ /* Combine and apply the brightness response curve. */
+ m *= max(rq, br - curveThreshold.w) / max(1e-5, br);
+
+ /* Clamp pixel intensity */
+ br = max(1e-5, brightness(m));
+ m *= 1.0 - max(0.0, br - clampIntensity) / br;
+
+ return vec4(m, 1.0);
+}
+
+vec4 step_downsample(void)
+{
+#ifdef HIGH_QUALITY /* Anti flicker */
+ vec3 sample = downsample_filter_high(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize);
+#else
+ vec3 sample = downsample_filter(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize);
+#endif
+ return vec4(sample, 1.0);
+}
+
+vec4 step_upsample(void)
+{
+#ifdef HIGH_QUALITY
+ vec3 blur = upsample_filter_high(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize);
+#else
+ vec3 blur = upsample_filter(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize);
+#endif
+ vec3 base = textureLod(baseBuffer, uvcoordsvar.xy, 0.0).rgb;
+ return vec4(base + blur, 1.0);
+}
+
+vec4 step_resolve(void)
+{
+#ifdef HIGH_QUALITY
+ vec3 blur = upsample_filter_high(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize);
+#else
+ vec3 blur = upsample_filter(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize);
+#endif
+ vec4 base = textureLod(baseBuffer, uvcoordsvar.xy, 0.0);
+ vec3 cout = base.rgb + blur * bloomColor;
+ return vec4(cout, base.a);
+}
+
+void main(void)
+{
+#if defined(STEP_BLIT)
+ FragColor = step_blit();
+#elif defined(STEP_DOWNSAMPLE)
+ FragColor = step_downsample();
+#elif defined(STEP_UPSAMPLE)
+ FragColor = step_upsample();
+#elif defined(STEP_RESOLVE)
+ FragColor = step_resolve();
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
new file mode 100644
index 00000000000..27517ebd86e
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
@@ -0,0 +1,241 @@
+
+uniform mat4 ProjectionMatrix;
+
+uniform sampler2D colorBuffer;
+uniform sampler2D depthBuffer;
+
+uniform vec3 dofParams;
+
+#define dof_aperturesize dofParams.x
+#define dof_distance dofParams.y
+#define dof_invsensorsize dofParams.z
+
+uniform vec4 bokehParams[2];
+
+#define bokeh_rotation bokehParams[0].x
+#define bokeh_ratio bokehParams[0].y
+#define bokeh_maxsize bokehParams[0].z
+#define bokeh_sides bokehParams[1] /* Polygon Bokeh shape number of sides (with precomputed vars) */
+
+uniform vec2 nearFar; /* Near & far view depths values */
+
+#define M_PI 3.1415926535897932384626433832795
+#define M_2PI 6.2831853071795864769252868
+
+/* -------------- Utils ------------- */
+
+/* divide by sensor size to get the normalized size */
+#define calculate_coc(zdepth) (dof_aperturesize * (dof_distance / zdepth - 1.0) * dof_invsensorsize)
+
+#define linear_depth(z) ((ProjectionMatrix[3][3] == 0.0) \
+ ? (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) \
+ : (z * 2.0 - 1.0) * nearFar.y)
+
+#define weighted_sum(a, b, c, d, e) (a * e.x + b * e.y + c * e.z + d * e.w) / max(1e-6, dot(e, vec4(1.0)));
+
+float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); }
+
+#define THRESHOLD 1.0
+
+#ifdef STEP_DOWNSAMPLE
+
+layout(location = 0) out vec4 nearColor;
+layout(location = 1) out vec4 farColor;
+layout(location = 2) out vec2 cocData;
+
+/* Downsample the color buffer to half resolution.
+ * Weight color samples by
+ * Compute maximum CoC for near and far blur. */
+void main(void)
+{
+ ivec4 uvs = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
+
+ /* custom downsampling */
+ vec4 color1 = texelFetch(colorBuffer, uvs.xy, 0);
+ vec4 color2 = texelFetch(colorBuffer, uvs.zw, 0);
+ vec4 color3 = texelFetch(colorBuffer, uvs.zy, 0);
+ vec4 color4 = texelFetch(colorBuffer, uvs.xw, 0);
+
+ /* Leverage SIMD by combining 4 depth samples into a vec4 */
+ vec4 depth;
+ depth.r = texelFetch(depthBuffer, uvs.xy, 0).r;
+ depth.g = texelFetch(depthBuffer, uvs.zw, 0).r;
+ depth.b = texelFetch(depthBuffer, uvs.zy, 0).r;
+ depth.a = texelFetch(depthBuffer, uvs.xw, 0).r;
+
+ vec4 zdepth = linear_depth(depth);
+
+ /* Compute signed CoC for each depth samples */
+ vec4 coc_near = calculate_coc(zdepth);
+ vec4 coc_far = -coc_near;
+
+ cocData.x = max(max_v4(coc_near), 0.0);
+ cocData.y = max(max_v4(coc_far), 0.0);
+
+ /* now we need to write the near-far fields premultiplied by the coc
+ * also use bilateral weighting by each coc values to avoid bleeding. */
+ vec4 near_weights = step(THRESHOLD, coc_near) * clamp(1.0 - abs(cocData.x - coc_near), 0.0, 1.0);
+ vec4 far_weights = step(THRESHOLD, coc_far) * clamp(1.0 - abs(cocData.y - coc_far), 0.0, 1.0);
+
+# ifdef USE_ALPHA_DOF
+ /* Premult */
+ color1.rgb *= color1.a;
+ color2.rgb *= color2.a;
+ color3.rgb *= color3.a;
+ color4.rgb *= color4.a;
+# endif
+
+ /* now write output to weighted buffers. */
+ nearColor = weighted_sum(color1, color2, color3, color4, near_weights);
+ farColor = weighted_sum(color1, color2, color3, color4, far_weights);
+}
+
+#elif defined(STEP_SCATTER)
+
+flat in vec4 color;
+flat in float weight;
+flat in float smoothFac;
+flat in ivec2 edge;
+/* coordinate used for calculating radius */
+in vec2 particlecoord;
+
+layout(location = 0) out vec4 fragColor;
+# ifdef USE_ALPHA_DOF
+layout(location = 1) out float fragAlpha;
+# endif
+
+/* accumulate color in the near/far blur buffers */
+void main(void)
+{
+ /* Discard to avoid bleeding onto the next layer */
+ if (int(gl_FragCoord.x) * edge.x + edge.y > 0)
+ discard;
+
+ /* Circle Dof */
+ float dist = length(particlecoord);
+
+ /* Ouside of bokeh shape */
+ if (dist > 1.0)
+ discard;
+
+ /* Regular Polygon Dof */
+ if (bokeh_sides.x > 0.0) {
+ /* Circle parametrization */
+ float theta = atan(particlecoord.y, particlecoord.x) + bokeh_rotation;
+
+ /* Optimized version of :
+ * float denom = theta - (M_2PI / bokeh_sides) * floor((bokeh_sides * theta + M_PI) / M_2PI);
+ * float r = cos(M_PI / bokeh_sides) / cos(denom); */
+ float denom = theta - bokeh_sides.y * floor(bokeh_sides.z * theta + 0.5);
+ float r = bokeh_sides.w / cos(denom);
+
+ /* Divide circle radial coord by the shape radius for angle theta.
+ * Giving us the new linear radius to the shape edge. */
+ dist /= r;
+
+ /* Ouside of bokeh shape */
+ if (dist > 1.0)
+ discard;
+ }
+
+ fragColor = color;
+
+ /* Smooth the edges a bit. This effectively reduce the bokeh shape
+ * but does fade out the undersampling artifacts. */
+ float shape = smoothstep(1.0, min(0.999, smoothFac), dist);
+
+ fragColor *= shape;
+
+# ifdef USE_ALPHA_DOF
+ fragAlpha = fragColor.a;
+ fragColor.a = weight * shape;
+# endif
+}
+
+#elif defined(STEP_RESOLVE)
+
+#define MERGE_THRESHOLD 4.0
+
+uniform sampler2D scatterBuffer;
+uniform sampler2D scatterAlphaBuffer;
+
+in vec4 uvcoordsvar;
+out vec4 fragColor;
+
+vec4 upsample_filter(sampler2D tex, vec2 uv, vec2 texelSize)
+{
+ /* TODO FIXME: Clamp the sample position
+ * depending on the layer to avoid bleeding.
+ * This is not really noticeable so leaving it as is for now. */
+
+#if 1 /* 9-tap bilinear upsampler (tent filter) */
+ vec4 d = texelSize.xyxy * vec4(1, 1, -1, 0);
+
+ vec4 s;
+ s = textureLod(tex, uv - d.xy, 0.0);
+ s += textureLod(tex, uv - d.wy, 0.0) * 2;
+ s += textureLod(tex, uv - d.zy, 0.0);
+
+ s += textureLod(tex, uv + d.zw, 0.0) * 2;
+ s += textureLod(tex, uv , 0.0) * 4;
+ s += textureLod(tex, uv + d.xw, 0.0) * 2;
+
+ s += textureLod(tex, uv + d.zy, 0.0);
+ s += textureLod(tex, uv + d.wy, 0.0) * 2;
+ s += textureLod(tex, uv + d.xy, 0.0);
+
+ return s * (1.0 / 16.0);
+#else
+ /* 4-tap bilinear upsampler */
+ vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1) * 0.5;
+
+ vec4 s;
+ s = textureLod(tex, uv + d.xy, 0.0);
+ s += textureLod(tex, uv + d.zy, 0.0);
+ s += textureLod(tex, uv + d.xw, 0.0);
+ s += textureLod(tex, uv + d.zw, 0.0);
+
+ return s * (1.0 / 4.0);
+#endif
+}
+
+/* Combine the Far and Near color buffers */
+void main(void)
+{
+ vec2 uv = uvcoordsvar.xy;
+ /* Recompute Near / Far CoC per pixel */
+ float depth = textureLod(depthBuffer, uv, 0.0).r;
+ float zdepth = linear_depth(depth);
+ float coc_signed = calculate_coc(zdepth);
+ float coc_far = max(-coc_signed, 0.0);
+ float coc_near = max(coc_signed, 0.0);
+
+ vec4 focus_col = textureLod(colorBuffer, uv, 0.0);
+
+ vec2 texelSize = vec2(0.5, 1.0) / vec2(textureSize(scatterBuffer, 0));
+ vec2 near_uv = uv * vec2(0.5, 1.0);
+ vec2 far_uv = near_uv + vec2(0.5, 0.0);
+ vec4 near_col = upsample_filter(scatterBuffer, near_uv, texelSize);
+ vec4 far_col = upsample_filter(scatterBuffer, far_uv, texelSize);
+
+ float far_w = far_col.a;
+ float near_w = near_col.a;
+ float focus_w = 1.0 - smoothstep(1.0, MERGE_THRESHOLD, abs(coc_signed));
+ float inv_weight_sum = 1.0 / (near_w + focus_w + far_w);
+
+ focus_col *= focus_w; /* Premul */
+
+# ifdef USE_ALPHA_DOF
+ near_col.a = upsample_filter(scatterAlphaBuffer, near_uv, texelSize).r;
+ far_col.a = upsample_filter(scatterAlphaBuffer, far_uv, texelSize).r;
+# endif
+
+ fragColor = (far_col + near_col + focus_col) * inv_weight_sum;
+
+# ifdef USE_ALPHA_DOF
+ /* Unpremult */
+ fragColor.rgb /= (fragColor.a > 0.0) ? fragColor.a : 1.0;
+# endif
+}
+
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl
new file mode 100644
index 00000000000..92fd36f684a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl
@@ -0,0 +1,109 @@
+
+uniform vec4 bokehParams[2];
+
+#define bokeh_rotation bokehParams[0].x
+#define bokeh_ratio bokehParams[0].y
+#define bokeh_maxsize bokehParams[0].z
+
+uniform sampler2D nearBuffer;
+uniform sampler2D farBuffer;
+uniform sampler2D cocBuffer;
+
+flat out vec4 color;
+flat out float weight;
+flat out float smoothFac;
+flat out ivec2 edge;
+out vec2 particlecoord;
+
+#define M_PI 3.1415926535897932384626433832795
+
+/* Scatter pass, calculate a triangle covering the CoC. */
+void main()
+{
+ ivec2 tex_size = textureSize(cocBuffer, 0);
+ /* We render to a double width texture so compute
+ * the target texel size accordingly */
+ vec2 texel_size = vec2(0.5, 1.0) / vec2(tex_size);
+
+ int t_id = gl_VertexID / 3; /* Triangle Id */
+
+ ivec2 texelco = ivec2(0);
+ /* some math to get the target pixel */
+ texelco.x = t_id % tex_size.x;
+ texelco.y = t_id / tex_size.x;
+
+ vec2 cocs = texelFetch(cocBuffer, texelco, 0).rg;
+
+ bool is_near = (cocs.x > cocs.y);
+ float coc = (is_near) ? cocs.x : cocs.y;
+
+ /* Clamp to max size for performance */
+ coc = min(coc, bokeh_maxsize);
+
+ if (coc >= 1.0) {
+ if (is_near) {
+ color = texelFetch(nearBuffer, texelco, 0);
+ }
+ else {
+ color = texelFetch(farBuffer, texelco, 0);
+ }
+ /* find the area the pixel will cover and divide the color by it */
+ /* HACK: 4.0 out of nowhere (I suppose it's 4 pixels footprint for coc 0?)
+ * Makes near in focus more closer to 1.0 alpha. */
+ weight = 4.0 / (coc * coc * M_PI);
+ color *= weight;
+
+ /* Compute edge to discard fragment that does not belong to the other layer. */
+ edge.x = (is_near) ? 1 : -1;
+ edge.y = (is_near) ? -tex_size.x + 1 : tex_size.x;
+ }
+ else {
+ /* Don't produce any fragments */
+ color = vec4(0.0);
+ gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+ return;
+ }
+
+ /* Generate Triangle : less memory fetches from a VBO */
+ int v_id = gl_VertexID % 3; /* Vertex Id */
+
+ /* Extend to cover at least the unit circle */
+ const float extend = (cos(M_PI / 4.0) + 1.0) * 2.0;
+ /* Crappy diagram
+ * ex 1
+ * | \
+ * | \
+ * 1 | \
+ * | \
+ * | \
+ * 0 | x \
+ * | Circle \
+ * | Origin \
+ * -1 0 --------------- 2
+ * -1 0 1 ex
+ **/
+ gl_Position.x = float(v_id / 2) * extend - 1.0; /* int divisor round down */
+ gl_Position.y = float(v_id % 2) * extend - 1.0;
+ gl_Position.z = 0.0;
+ gl_Position.w = 1.0;
+
+ /* Generate Triangle */
+ particlecoord = gl_Position.xy;
+
+ gl_Position.xy *= coc * texel_size * vec2(bokeh_ratio, 1.0);
+ gl_Position.xy -= 1.0 - 0.5 * texel_size; /* NDC Bottom left */
+ gl_Position.xy += (0.5 + vec2(texelco) * 2.0) * texel_size;
+
+ /* Push far plane to left side. */
+ if (!is_near) {
+ gl_Position.x += 2.0 / 2.0;
+ }
+
+ /* don't do smoothing for small sprites */
+ if (coc > 3.0) {
+ smoothFac = 1.0 - 1.5 / coc;
+ }
+ else {
+ smoothFac = 1.0;
+ }
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl
new file mode 100644
index 00000000000..79f86cfae58
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_downsample_cube_frag.glsl
@@ -0,0 +1,30 @@
+/**
+ * Simple downsample shader. Takes the average of the 4 texels of lower mip.
+ **/
+
+uniform samplerCube source;
+uniform float texelSize;
+
+flat in int fFace;
+
+out vec4 FragColor;
+
+const vec3 maj_axes[6] = vec3[6](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3( 0.0, 0.0, 1.0), vec3( 0.0, 0.0, -1.0));
+const vec3 x_axis[6] = vec3[6](vec3(0.0, 0.0, -1.0), vec3( 0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3( 1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0));
+const vec3 y_axis[6] = vec3[6](vec3(0.0, -1.0, 0.0), vec3( 0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0), vec3( 0.0, -1.0, 0.0), vec3( 0.0, -1.0, 0.0));
+
+float brightness(vec3 c)
+{
+ return max(max(c.r, c.g), c.b);
+}
+
+void main()
+{
+ vec2 uvs = gl_FragCoord.xy * texelSize;
+
+ uvs = 2.0 * uvs - 1.0;
+
+ vec3 cubevec = x_axis[fFace] * uvs.x + y_axis[fFace] * uvs.y + maj_axes[fFace];
+
+ FragColor = textureLod(source, cubevec, 0.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
new file mode 100644
index 00000000000..8f06e161a20
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl
@@ -0,0 +1,37 @@
+/**
+ * Simple downsample shader. Takes the average of the 4 texels of lower mip.
+ **/
+
+uniform sampler2D source;
+uniform float fireflyFactor;
+
+out vec4 FragColor;
+
+float brightness(vec3 c)
+{
+ return max(max(c.r, c.g), c.b);
+}
+
+void main()
+{
+#if 0
+ /* Reconstructing Target uvs like this avoid missing pixels if NPO2 */
+ vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0));
+
+ FragColor = textureLod(source, uvs, 0.0);
+#else
+ vec2 texel_size = 1.0 / vec2(textureSize(source, 0));
+ vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size;
+ vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75);
+
+ FragColor = textureLod(source, uvs + ofs.xy, 0.0);
+ FragColor += textureLod(source, uvs + ofs.xw, 0.0);
+ FragColor += textureLod(source, uvs + ofs.zy, 0.0);
+ FragColor += textureLod(source, uvs + ofs.zw, 0.0);
+ FragColor *= 0.25;
+
+ /* Clamped brightness. */
+ float luma = max(1e-8, brightness(FragColor.rgb));
+ FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
new file mode 100644
index 00000000000..ccef05ef985
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl
@@ -0,0 +1,77 @@
+/**
+ * This shader only compute maximum horizon angles for each directions.
+ * The final integration is done at the resolve stage with the shading normal.
+ **/
+
+uniform float rotationOffset;
+
+out vec4 FragColor;
+
+#ifdef DEBUG_AO
+uniform sampler2D normalBuffer;
+
+void main()
+{
+ vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xy;
+ vec2 uvs = saturate(gl_FragCoord.xy * texel_size);
+
+ float depth = textureLod(depthBuffer, uvs, 0.0).r;
+
+ vec3 viewPosition = get_view_space_from_depth(uvs, depth);
+ vec3 V = viewCameraVec;
+ vec3 normal = normal_decode(texture(normalBuffer, uvs).rg, V);
+
+ vec3 bent_normal;
+ float visibility;
+
+ vec4 noise = texelfetch_noise_tex(gl_FragCoord.xy);
+
+ gtao_deferred(normal, noise, depth, visibility, bent_normal);
+
+ /* Handle Background case. Prevent artifact due to uncleared Horizon Render Target. */
+ FragColor = vec4((depth == 1.0) ? 0.0 : visibility);
+}
+
+#else
+
+#ifdef LAYERED_DEPTH
+uniform sampler2DArray depthBufferLayered;
+uniform int layer;
+# define gtao_depthBuffer depthBufferLayered
+# define gtao_textureLod(a, b, c) textureLod(a, vec3(b, layer), c)
+
+#else
+# define gtao_depthBuffer depthBuffer
+# define gtao_textureLod(a, b, c) textureLod(a, b, c)
+
+#endif
+
+void main()
+{
+ vec2 uvs = saturate(gl_FragCoord.xy / vec2(textureSize(gtao_depthBuffer, 0).xy));
+ float depth = gtao_textureLod(gtao_depthBuffer, uvs, 0.0).r;
+
+ if (depth == 1.0) {
+ /* Do not trace for background */
+ FragColor = vec4(0.0);
+ return;
+ }
+
+ /* Avoid self shadowing. */
+ depth = saturate(depth - 3e-6); /* Tweaked for 24bit depth buffer. */
+
+ vec3 viewPosition = get_view_space_from_depth(uvs, depth);
+ vec4 noise = texelfetch_noise_tex(gl_FragCoord.xy);
+ vec2 max_dir = get_max_dir(viewPosition.z);
+ vec4 dirs;
+ dirs.xy = get_ao_dir(noise.x * 0.5);
+ dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5);
+
+ /* Search in 4 directions. */
+ FragColor.xy = search_horizon_sweep(dirs.xy, viewPosition, uvs, noise.y, max_dir);
+ FragColor.zw = search_horizon_sweep(dirs.zw, viewPosition, uvs, noise.y, max_dir);
+
+ /* Resize output for integer texture. */
+ FragColor = pack_horizons(FragColor);
+}
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
new file mode 100644
index 00000000000..edfd0f307e9
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
@@ -0,0 +1,95 @@
+/**
+ * Shader that downsample depth buffer,
+ * saving min and max value of each texel in the above mipmaps.
+ * Adapted from http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/
+ **/
+
+#ifdef LAYERED
+uniform sampler2DArray depthBuffer;
+uniform int depthLayer;
+#else
+uniform sampler2D depthBuffer;
+#endif
+
+#ifdef LAYERED
+# define sampleLowerMip(t) texelFetch(depthBuffer, ivec3(t, depthLayer), 0).r
+# define gatherLowerMip(t) textureGather(depthBuffer, vec3(t, depthLayer))
+#else
+# define sampleLowerMip(t) texelFetch(depthBuffer, t, 0).r
+# define gatherLowerMip(t) textureGather(depthBuffer, t)
+#endif
+
+#ifdef MIN_PASS
+#define minmax2(a, b) min(a, b)
+#define minmax3(a, b, c) min(min(a, b), c)
+#define minmax4(a, b, c, d) min(min(min(a, b), c), d)
+#else /* MAX_PASS */
+#define minmax2(a, b) max(a, b)
+#define minmax3(a, b, c) max(max(a, b), c)
+#define minmax4(a, b, c, d) max(max(max(a, b), c), d)
+#endif
+
+/* On some AMD card / driver combination, it is needed otherwise,
+ * the shader does not write anything. */
+#if defined(GPU_INTEL) || defined(GPU_ATI)
+out vec4 fragColor;
+#endif
+
+void main()
+{
+ ivec2 texelPos = ivec2(gl_FragCoord.xy);
+ ivec2 mipsize = textureSize(depthBuffer, 0).xy;
+
+#ifndef COPY_DEPTH
+ texelPos *= 2;
+#endif
+
+#ifdef COPY_DEPTH
+ float val = sampleLowerMip(texelPos);
+#else
+ vec4 samp;
+# ifdef GPU_ARB_texture_gather
+ /* + 1.0 to gather at the center of target 4 texels. */
+ samp = gatherLowerMip((vec2(texelPos) + 1.0) / vec2(mipsize));
+# else
+ samp.x = sampleLowerMip(texelPos);
+ samp.y = sampleLowerMip(texelPos + ivec2(1, 0));
+ samp.z = sampleLowerMip(texelPos + ivec2(1, 1));
+ samp.w = sampleLowerMip(texelPos + ivec2(0, 1));
+# endif
+
+ float val = minmax4(samp.x, samp.y, samp.z, samp.w);
+
+ /* if we are reducing an odd-width texture then fetch the edge texels */
+ if (((mipsize.x & 1) != 0) && (texelPos.x == mipsize.x - 3)) {
+ /* if both edges are odd, fetch the top-left corner texel */
+ if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) {
+ samp.x = sampleLowerMip(texelPos + ivec2(2, 2));
+ val = minmax2(val, samp.x);
+ }
+# ifdef GPU_ARB_texture_gather
+ samp = gatherLowerMip((vec2(texelPos) + vec2(2.0, 1.0)) / vec2(mipsize));
+# else
+ samp.y = sampleLowerMip(texelPos + ivec2(2, 0));
+ samp.z = sampleLowerMip(texelPos + ivec2(2, 1));
+# endif
+ val = minmax3(val, samp.y, samp.z);
+ }
+ /* if we are reducing an odd-height texture then fetch the edge texels */
+ if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) {
+# ifdef GPU_ARB_texture_gather
+ samp = gatherLowerMip((vec2(texelPos) + vec2(1.0, 2.0)) / vec2(mipsize));
+# else
+ samp.x = sampleLowerMip(texelPos + ivec2(0, 2));
+ samp.y = sampleLowerMip(texelPos + ivec2(1, 2));
+# endif
+ val = minmax3(val, samp.x, samp.y);
+ }
+#endif
+
+#if defined(GPU_INTEL) || defined(GPU_ATI)
+ /* Use color format instead of 24bit depth texture */
+ fragColor = vec4(val);
+#endif
+ gl_FragDepth = val;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl
new file mode 100644
index 00000000000..fe38b2e9aac
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl
@@ -0,0 +1,31 @@
+/* Convert depth to Mist factor */
+uniform vec3 mistSettings;
+
+#define mistStart mistSettings.x
+#define mistInvDistance mistSettings.y
+#define mistFalloff mistSettings.z
+
+out vec4 fragColor;
+
+void main()
+{
+ vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xy;
+ vec2 uvs = gl_FragCoord.xy * texel_size;
+
+ float depth = textureLod(depthBuffer, uvs, 0.0).r;
+ vec3 co = get_view_space_from_depth(uvs, depth);
+
+ float zcor = (ProjectionMatrix[3][3] == 0.0) ? length(co) : -co.z;
+
+ /* bring depth into 0..1 range */
+ float mist = saturate((zcor - mistStart) * mistInvDistance);
+
+ /* falloff */
+ mist = pow(mist, mistFalloff);
+
+ fragColor = vec4(mist);
+
+ // if (mist > 0.999) fragColor = vec4(1.0);
+ // else if (mist > 0.0001) fragColor = vec4(0.5);
+ // else fragColor = vec4(0.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
new file mode 100644
index 00000000000..73e284570cd
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl
@@ -0,0 +1,65 @@
+
+uniform sampler2D colorBuffer;
+uniform sampler2D depthBuffer;
+
+
+/* current frame */
+uniform mat4 currInvViewProjMatrix;
+
+/* past frame frame */
+uniform mat4 pastViewProjMatrix;
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+#define MAX_SAMPLE 64
+
+uniform int samples;
+
+float wang_hash_noise(uint s)
+{
+ uint seed = (uint(gl_FragCoord.x) * 1664525u + uint(gl_FragCoord.y)) + s;
+
+ seed = (seed ^ 61u) ^ (seed >> 16u);
+ seed *= 9u;
+ seed = seed ^ (seed >> 4u);
+ seed *= 0x27d4eb2du;
+ seed = seed ^ (seed >> 15u);
+
+ float value = float(seed);
+ value *= 1.0 / 4294967296.0;
+ return fract(value);
+}
+
+void main()
+{
+ vec3 ndc_pos;
+ ndc_pos.xy = uvcoordsvar.xy;
+ ndc_pos.z = texture(depthBuffer, uvcoordsvar.xy).x;
+
+ float inv_samples = 1.0 / float(samples);
+ float noise = 2.0 * wang_hash_noise(0u) * inv_samples;
+
+ /* Normalize Device Coordinates are [-1, +1]. */
+ ndc_pos = ndc_pos * 2.0 - 1.0;
+
+ vec4 p = currInvViewProjMatrix * vec4(ndc_pos, 1.0);
+ vec3 world_pos = p.xyz / p.w; /* Perspective divide */
+
+ /* Now find where was this pixel position
+ * inside the past camera viewport */
+ vec4 old_ndc = pastViewProjMatrix * vec4(world_pos, 1.0);
+ old_ndc.xyz /= old_ndc.w; /* Perspective divide */
+
+ vec2 motion = (ndc_pos.xy - old_ndc.xy) * 0.25; /* 0.25 fit cycles ref */
+
+ float inc = 2.0 * inv_samples;
+ float i = -1.0 + noise;
+
+ FragColor = vec4(0.0);
+ for (int j = 0; j < samples && j < MAX_SAMPLE; j++) {
+ FragColor += textureLod(colorBuffer, uvcoordsvar.xy + motion * i, 0.0) * inv_samples;
+ i += inc;
+ }
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
new file mode 100644
index 00000000000..b8a86f8d742
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -0,0 +1,476 @@
+
+/* Based on Stochastic Screen Space Reflections
+ * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections */
+
+#define MAX_MIP 9.0
+
+uniform ivec2 halfresOffset;
+
+ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar)
+{
+ ivec2 hit_data = ivec2(saturate(hit_pos) * 32767.0); /* 16bit signed int limit */
+ hit_data.x *= (is_planar) ? -1 : 1;
+ hit_data.y *= (has_hit) ? 1 : -1;
+ return hit_data;
+}
+
+vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar)
+{
+ is_planar = (hit_data.x < 0);
+ has_hit = (hit_data.y > 0);
+ return vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */
+}
+
+#ifdef STEP_RAYTRACE
+
+uniform sampler2D normalBuffer;
+uniform sampler2D specroughBuffer;
+
+layout(location = 0) out ivec2 hitData;
+layout(location = 1) out float pdfData;
+
+void do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec4 rand)
+{
+ float NH;
+ vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
+ float pdf = pdf_ggx_reflect(NH, a2);
+
+ vec3 R = reflect(-V, H);
+ R = reflect(R, planeNormal);
+
+ /* If ray is bad (i.e. going below the plane) regenerate. */
+ if (dot(R, planeNormal) > 0.0) {
+ vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
+ pdf = pdf_ggx_reflect(NH, a2);
+
+ R = reflect(-V, H);
+ R = reflect(R, planeNormal);
+ }
+
+ pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
+
+ /* Since viewspace hit position can land behind the camera in this case,
+ * we save the reflected view position (visualize it as the hit position
+ * below the reflection plane). This way it's garanted that the hit will
+ * be in front of the camera. That let us tag the bad rays with a negative
+ * sign in the Z component. */
+ vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, rand.y, ssrQuality, a2, false);
+
+ hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true);
+}
+
+void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec4 rand)
+{
+ float NH;
+ vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
+ float pdf = pdf_ggx_reflect(NH, a2);
+
+ vec3 R = reflect(-V, H);
+ pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
+
+ vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true);
+
+ hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false);
+}
+
+void main()
+{
+#ifdef FULLRES
+ ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
+ ivec2 halfres_texel = fullres_texel;
+#else
+ ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2 + halfresOffset;
+ ivec2 halfres_texel = ivec2(gl_FragCoord.xy);
+#endif
+
+ float depth = texelFetch(depthBuffer, fullres_texel, 0).r;
+
+ /* Default: not hits. */
+ hitData = encode_hit_data(vec2(0.5), false, false);
+ pdfData = 0.0;
+
+ /* Early out */
+ /* We can't do discard because we don't clear the render target. */
+ if (depth == 1.0)
+ return;
+
+ vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0));
+
+ /* Using view space */
+ vec3 viewPosition = get_view_space_from_depth(uvs, depth);
+ vec3 V = viewCameraVec;
+ vec3 N = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, V);
+
+ /* Retrieve pixel data */
+ vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
+
+ /* Early out */
+ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0)
+ return;
+
+ float roughness = speccol_roughness.a;
+ float roughnessSquared = max(1e-3, roughness * roughness);
+ float a2 = roughnessSquared * roughnessSquared;
+
+ /* Early out */
+ if (roughness > ssrMaxRoughness + 0.2)
+ return;
+
+ vec4 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0);
+
+ /* Gives *perfect* reflection for very small roughness */
+ if (roughness < 0.04) {
+ rand.xzw *= 0.0;
+ }
+ /* Importance sampling bias */
+ rand.x = mix(rand.x, 0.0, ssrBrdfBias);
+
+ vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
+ vec3 wN = transform_direction(ViewMatrixInverse, N);
+
+ vec3 T, B;
+ make_orthonormal_basis(N, T, B); /* Generate tangent space */
+
+ /* Planar Reflections */
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) {
+ PlanarData pd = planars_data[i];
+
+ float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0);
+
+ if (fade > 0.5) {
+ /* Find view vector / reflection plane intersection. */
+ /* TODO optimize, use view space for all. */
+ vec3 tracePosition = line_plane_intersect(worldPosition, cameraVec, pd.pl_plane_eq);
+ tracePosition = transform_point(ViewMatrix, tracePosition);
+ vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
+
+ do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand);
+ return;
+ }
+ }
+
+ do_ssr(V, N, T, B, viewPosition, a2, rand);
+}
+
+#else /* STEP_RESOLVE */
+
+uniform sampler2D prevColorBuffer; /* previous frame */
+uniform sampler2D normalBuffer;
+uniform sampler2D specroughBuffer;
+
+uniform isampler2D hitBuffer;
+uniform sampler2D pdfBuffer;
+
+uniform int neighborOffset;
+
+const ivec2 neighbors[32] = ivec2[32](
+ ivec2( 0, 0), ivec2( 1, 1), ivec2(-2, 0), ivec2( 0, -2),
+ ivec2( 0, 0), ivec2( 1, -1), ivec2(-2, 0), ivec2( 0, 2),
+ ivec2( 0, 0), ivec2(-1, -1), ivec2( 2, 0), ivec2( 0, 2),
+ ivec2( 0, 0), ivec2(-1, 1), ivec2( 2, 0), ivec2( 0, -2),
+
+ ivec2( 0, 0), ivec2( 2, 2), ivec2(-2, 2), ivec2( 0, -1),
+ ivec2( 0, 0), ivec2( 2, -2), ivec2(-2, -2), ivec2( 0, 1),
+ ivec2( 0, 0), ivec2(-2, -2), ivec2(-2, 2), ivec2( 1, 0),
+ ivec2( 0, 0), ivec2( 2, 2), ivec2( 2, -2), ivec2(-1, 0)
+);
+
+out vec4 fragColor;
+
+#if 0 /* Finish reprojection with motion vectors */
+vec3 get_motion_vector(vec3 pos)
+{
+}
+
+/* http://bitsquid.blogspot.fr/2017/06/reprojecting-reflections_22.html */
+vec3 find_reflection_incident_point(vec3 cam, vec3 hit, vec3 pos, vec3 N)
+{
+ float d_cam = point_plane_projection_dist(cam, pos, N);
+ float d_hit = point_plane_projection_dist(hit, pos, N);
+
+ if (d_hit < d_cam) {
+ /* Swap */
+ float tmp = d_cam;
+ d_cam = d_hit;
+ d_hit = tmp;
+ }
+
+ vec3 proj_cam = cam - (N * d_cam);
+ vec3 proj_hit = hit - (N * d_hit);
+
+ return (proj_hit - proj_cam) * d_cam / (d_cam + d_hit) + proj_cam;
+}
+#endif
+
+float brightness(vec3 c)
+{
+ return max(max(c.r, c.g), c.b);
+}
+
+vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N)
+{
+ /* TODO real reprojection with motion vectors, etc... */
+ return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5;
+}
+
+float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index)
+{
+ if (is_planar) {
+ return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r;
+ }
+ else {
+ return textureLod(depthBuffer, hit_co, 0.0).r;
+ }
+}
+
+vec3 get_hit_vector(
+ vec3 hit_pos, PlanarData pd, vec3 worldPosition, vec3 N, vec3 V, bool is_planar,
+ inout vec2 hit_co, inout float mask)
+{
+ vec3 hit_vec;
+
+ if (is_planar) {
+ /* Reflect back the hit position to have it in non-reflected world space */
+ vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq);
+ hit_vec = hit_pos - trace_pos;
+ hit_vec = reflect(hit_vec, pd.pl_normal);
+ }
+ else {
+ /* Find hit position in previous frame. */
+ hit_co = get_reprojected_reflection(hit_pos, worldPosition, N);
+ hit_vec = hit_pos - worldPosition;
+ }
+
+ mask = screen_border_mask(hit_co);
+ return hit_vec;
+}
+
+vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar)
+{
+ if (is_planar) {
+ return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb;
+ }
+ else {
+ return textureLod(prevColorBuffer, ref_uvs, mip).rgb;
+ }
+}
+
+vec4 get_ssr_samples(
+ vec4 hit_pdf, ivec4 hit_data[2],
+ PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V,
+ float roughnessSquared, float cone_tan, vec2 source_uvs,
+ inout float weight_acc)
+{
+ bvec4 is_planar, has_hit;
+ vec4 hit_co[2];
+ hit_co[0].xy = decode_hit_data(hit_data[0].xy, has_hit.x, is_planar.x);
+ hit_co[0].zw = decode_hit_data(hit_data[0].zw, has_hit.y, is_planar.y);
+ hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z);
+ hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w);
+
+ vec4 hit_depth;
+ hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index);
+ hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index);
+ hit_depth.z = get_sample_depth(hit_co[1].xy, is_planar.z, planar_index);
+ hit_depth.w = get_sample_depth(hit_co[1].zw, is_planar.w, planar_index);
+
+ /* Hit position in view space. */
+ vec3 hit_view[4];
+ hit_view[0] = get_view_space_from_depth(hit_co[0].xy, hit_depth.x);
+ hit_view[1] = get_view_space_from_depth(hit_co[0].zw, hit_depth.y);
+ hit_view[2] = get_view_space_from_depth(hit_co[1].xy, hit_depth.z);
+ hit_view[3] = get_view_space_from_depth(hit_co[1].zw, hit_depth.w);
+
+ vec4 homcoord = vec4(hit_view[0].z, hit_view[1].z, hit_view[2].z, hit_view[3].z);
+ homcoord = ProjectionMatrix[2][3] * homcoord + ProjectionMatrix[3][3];
+
+ /* Hit position in world space. */
+ vec3 hit_pos[4];
+ hit_pos[0] = transform_point(ViewMatrixInverse, hit_view[0]);
+ hit_pos[1] = transform_point(ViewMatrixInverse, hit_view[1]);
+ hit_pos[2] = transform_point(ViewMatrixInverse, hit_view[2]);
+ hit_pos[3] = transform_point(ViewMatrixInverse, hit_view[3]);
+
+ /* Get actual hit vector and hit coordinate (from last frame). */
+ vec4 mask = vec4(1.0);
+ hit_pos[0] = get_hit_vector(hit_pos[0], pd, worldPosition, N, V, is_planar.x, hit_co[0].xy, mask.x);
+ hit_pos[1] = get_hit_vector(hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y);
+ hit_pos[2] = get_hit_vector(hit_pos[2], pd, worldPosition, N, V, is_planar.z, hit_co[1].xy, mask.z);
+ hit_pos[3] = get_hit_vector(hit_pos[3], pd, worldPosition, N, V, is_planar.w, hit_co[1].zw, mask.w);
+
+ vec4 hit_dist;
+ hit_dist.x = length(hit_pos[0]);
+ hit_dist.y = length(hit_pos[1]);
+ hit_dist.z = length(hit_pos[2]);
+ hit_dist.w = length(hit_pos[3]);
+ hit_dist = max(vec4(1e-8), hit_dist);
+
+ /* Normalize */
+ hit_pos[0] /= hit_dist.x;
+ hit_pos[1] /= hit_dist.y;
+ hit_pos[2] /= hit_dist.z;
+ hit_pos[3] /= hit_dist.w;
+
+ /* Compute cone footprint in screen space. */
+ vec4 cone_footprint = hit_dist * cone_tan;
+ cone_footprint = ssrBrdfBias * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord;
+
+ /* Estimate a cone footprint to sample a corresponding mipmap level. */
+ vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0))));
+ mip = clamp(mip, 0.0, MAX_MIP);
+
+ /* Correct UVs for mipmaping mis-alignment */
+ hit_co[0].xy *= mip_ratio_interp(mip.x);
+ hit_co[0].zw *= mip_ratio_interp(mip.y);
+ hit_co[1].xy *= mip_ratio_interp(mip.z);
+ hit_co[1].zw *= mip_ratio_interp(mip.w);
+
+ /* Slide 54 */
+ vec4 bsdf;
+ bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared);
+ bsdf.y = bsdf_ggx(N, hit_pos[1], V, roughnessSquared);
+ bsdf.z = bsdf_ggx(N, hit_pos[2], V, roughnessSquared);
+ bsdf.w = bsdf_ggx(N, hit_pos[3], V, roughnessSquared);
+
+ vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf);
+
+ vec3 sample[4];
+ sample[0] = get_scene_color(hit_co[0].xy, mip.x, planar_index, is_planar.x);
+ sample[1] = get_scene_color(hit_co[0].zw, mip.y, planar_index, is_planar.y);
+ sample[2] = get_scene_color(hit_co[1].xy, mip.z, planar_index, is_planar.z);
+ sample[3] = get_scene_color(hit_co[1].zw, mip.w, planar_index, is_planar.w);
+
+ /* Clamped brightness. */
+ vec4 luma;
+ luma.x = brightness(sample[0]);
+ luma.y = brightness(sample[1]);
+ luma.z = brightness(sample[2]);
+ luma.w = brightness(sample[3]);
+ luma = max(vec4(1e-8), luma);
+ luma = 1.0 - max(vec4(0.0), luma - ssrFireflyFac) / luma;
+
+ sample[0] *= luma.x;
+ sample[1] *= luma.y;
+ sample[2] *= luma.z;
+ sample[3] *= luma.w;
+
+ /* Protection against NaNs in the history buffer.
+ * This could be removed if some previous pass has already
+ * sanitized the input. */
+ if (any(isnan(sample[0]))) {
+ sample[0] = vec3(0.0); weight.x = 0.0;
+ }
+ if (any(isnan(sample[1]))) {
+ sample[1] = vec3(0.0); weight.y = 0.0;
+ }
+ if (any(isnan(sample[2]))) {
+ sample[2] = vec3(0.0); weight.z = 0.0;
+ }
+ if (any(isnan(sample[3]))) {
+ sample[3] = vec3(0.0); weight.w = 0.0;
+ }
+
+ weight_acc += sum(weight);
+
+ /* Do not add light if ray has failed. */
+ vec4 accum;
+ accum = vec4(sample[0], mask.x) * weight.x * float(has_hit.x);
+ accum += vec4(sample[1], mask.y) * weight.y * float(has_hit.y);
+ accum += vec4(sample[2], mask.z) * weight.z * float(has_hit.z);
+ accum += vec4(sample[3], mask.w) * weight.w * float(has_hit.w);
+ return accum;
+}
+
+void main()
+{
+ ivec2 fullres_texel = ivec2(gl_FragCoord.xy);
+#ifdef FULLRES
+ ivec2 halfres_texel = fullres_texel;
+#else
+ ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0);
+#endif
+ vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0));
+
+ float depth = textureLod(depthBuffer, uvs, 0.0).r;
+
+ /* Early out */
+ if (depth == 1.0)
+ discard;
+
+ /* Using world space */
+ vec3 viewPosition = get_view_space_from_depth(uvs, depth); /* Needed for viewCameraVec */
+ vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
+ vec3 V = cameraVec;
+ vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec);
+ vec3 N = transform_direction(ViewMatrixInverse, vN);
+ vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba;
+
+ /* Early out */
+ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0)
+ discard;
+
+ float roughness = speccol_roughness.a;
+ float roughnessSquared = max(1e-3, roughness * roughness);
+
+ vec4 spec_accum = vec4(0.0);
+
+ /* Resolve SSR */
+ float cone_cos = cone_cosine(roughnessSquared);
+ float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
+ cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */
+
+ vec2 source_uvs = project_point(pastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5;
+
+ vec4 ssr_accum = vec4(0.0);
+ float weight_acc = 0.0;
+
+ if (roughness < ssrMaxRoughness + 0.2) {
+ /* TODO optimize with textureGather */
+ /* Doing these fetches early to hide latency. */
+ vec4 hit_pdf;
+ hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r;
+ hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r;
+ hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r;
+ hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r;
+
+ ivec4 hit_data[2];
+ hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg;
+ hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg;
+ hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg;
+ hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg;
+
+ /* Find Planar Reflections affecting this pixel */
+ PlanarData pd;
+ float planar_index;
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; ++i) {
+ pd = planars_data[i];
+
+ float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0);
+
+ if (fade > 0.5) {
+ planar_index = float(i);
+ break;
+ }
+ }
+
+ ssr_accum += get_ssr_samples(hit_pdf, hit_data, pd, planar_index, worldPosition, N, V,
+ roughnessSquared, cone_tan, source_uvs, weight_acc);
+ }
+
+ /* Compute SSR contribution */
+ if (weight_acc > 0.0) {
+ ssr_accum /= weight_acc;
+ /* fade between 0.5 and 1.0 roughness */
+ ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
+ accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum);
+ }
+
+ /* If SSR contribution is not 1.0, blend with cubemaps */
+ if (spec_accum.a < 1.0) {
+ fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
+ }
+
+ fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0);
+}
+
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
new file mode 100644
index 00000000000..5ecf6323255
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
@@ -0,0 +1,99 @@
+
+/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
+
+#define MAX_SSS_SAMPLES 65
+layout(std140) uniform sssProfile {
+ vec4 kernel[MAX_SSS_SAMPLES];
+ vec4 radii_max_radius;
+ int sss_samples;
+};
+
+uniform sampler2D depthBuffer;
+uniform sampler2D sssData;
+uniform sampler2D sssAlbedo;
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
+uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
+
+layout(location = 0) out vec4 FragColor;
+#ifdef RESULT_ACCUM
+layout(location = 1) out vec4 sssColor;
+#endif
+
+float get_view_z_from_depth(float depth)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ float d = 2.0 * depth - 1.0;
+ return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
+ }
+ else {
+ return viewVecs[0].z + depth * viewVecs[1].z;
+ }
+}
+
+#define LUT_SIZE 64
+#define M_PI_2 1.5707963267948966 /* pi/2 */
+#define M_2PI 6.2831853071795865 /* 2*pi */
+
+void main(void)
+{
+ vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */
+ vec2 uvs = gl_FragCoord.xy * pixel_size;
+ vec4 sss_data = texture(sssData, uvs).rgba;
+ float depth_view = get_view_z_from_depth(texture(depthBuffer, uvs).r);
+
+ float rand = texelfetch_noise_tex(gl_FragCoord.xy).r;
+#ifdef FIRST_PASS
+ float angle = M_2PI * rand + M_PI_2;
+ vec2 dir = vec2(1.0, 0.0);
+#else /* SECOND_PASS */
+ float angle = M_2PI * rand;
+ vec2 dir = vec2(0.0, 1.0);
+#endif
+ vec2 dir_rand = vec2(cos(angle), sin(angle));
+
+ /* Compute kernel bounds in 2D. */
+ float homcoord = ProjectionMatrix[2][3] * depth_view + ProjectionMatrix[3][3];
+ vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_data.aa / homcoord;
+ vec2 finalStep = scale * radii_max_radius.w;
+ finalStep *= 0.5; /* samples range -1..1 */
+
+ /* Center sample */
+ vec3 accum = sss_data.rgb * kernel[0].rgb;
+
+ for (int i = 1; i < sss_samples && i < MAX_SSS_SAMPLES; i++) {
+ vec2 sample_uv = uvs + kernel[i].a * finalStep * ((abs(kernel[i].a) > sssJitterThreshold) ? dir : dir_rand);
+ vec3 color = texture(sssData, sample_uv).rgb;
+ float sample_depth = texture(depthBuffer, sample_uv).r;
+ sample_depth = get_view_z_from_depth(sample_depth);
+
+ /* Depth correction factor. */
+ float depth_delta = depth_view - sample_depth;
+ float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_data.a)), 0.0, 1.0);
+
+ /* Out of view samples. */
+ if (any(lessThan(sample_uv, vec2(0.0))) || any(greaterThan(sample_uv, vec2(1.0)))) {
+ s = 1.0;
+ }
+
+ accum += kernel[i].rgb * mix(color, sss_data.rgb, s);
+ }
+
+#ifdef FIRST_PASS
+ FragColor = vec4(accum, sss_data.a);
+#else /* SECOND_PASS */
+# ifdef USE_SEP_ALBEDO
+# ifdef RESULT_ACCUM
+ FragColor = vec4(accum, 1.0);
+ sssColor = texture(sssAlbedo, uvs);
+# else
+ FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0);
+# endif
+# else
+ FragColor = vec4(accum, 1.0);
+# endif
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
new file mode 100644
index 00000000000..e118777f6c8
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
@@ -0,0 +1,111 @@
+
+uniform sampler2D colorHistoryBuffer;
+uniform sampler2D velocityBuffer;
+
+out vec4 FragColor;
+
+vec4 safe_color(vec4 c)
+{
+ /* Clamp to avoid black square artifacts if a pixel goes NaN. */
+ return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
+}
+
+#ifdef USE_REPROJECTION
+
+/**
+ * Adapted from https://casual-effects.com/g3d/G3D10/data-files/shader/Film/Film_temporalAA.pix
+ * which is adapted from https://github.com/gokselgoktas/temporal-anti-aliasing/blob/master/Assets/Resources/Shaders/TemporalAntiAliasing.cginc
+ * which is adapted from https://github.com/playdeadgames/temporal
+ * Optimization by Stubbesaurus and epsilon adjustment to avoid division by zero.
+ *
+ * This can cause 3x3 blocks of color when there is a thin edge of a similar color that
+ * is varying in intensity.
+ */
+vec3 clip_to_aabb(vec3 color, vec3 minimum, vec3 maximum, vec3 average)
+{
+ /* note: only clips towards aabb center (but fast!) */
+ vec3 center = 0.5 * (maximum + minimum);
+ vec3 extents = 0.5 * (maximum - minimum);
+ vec3 dist = color - center;
+ vec3 ts = abs(extents) / max(abs(dist), vec3(0.0001));
+ float t = saturate(min_v3(ts));
+ return center + dist * t;
+}
+
+/**
+ * Vastly based on https://github.com/playdeadgames/temporal
+ */
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+ float depth = texelFetch(depthBuffer, texel, 0).r;
+ vec2 motion = texelFetch(velocityBuffer, texel, 0).rg;
+
+ /* Decode from unsigned normalized 16bit texture. */
+ motion = motion * 2.0 - 1.0;
+
+ /* Compute pixel position in previous frame. */
+ vec2 screen_res = vec2(textureSize(colorBuffer, 0).xy);
+ vec2 uv = gl_FragCoord.xy / screen_res;
+ vec2 uv_history = uv - motion;
+
+ ivec2 texel_history = ivec2(uv_history * screen_res);
+ vec4 color_history = textureLod(colorHistoryBuffer, uv_history, 0.0);
+
+ /* Color bounding box clamping. 3x3 neighborhood. */
+ vec4 c02 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, 1));
+ vec4 c12 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 0, 1));
+ vec4 c22 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 1, 1));
+ vec4 c01 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, 0));
+ vec4 c11 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 0, 0));
+ vec4 c21 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 1, 0));
+ vec4 c00 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, -1));
+ vec4 c10 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 0, -1));
+ vec4 c20 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 1, -1));
+
+ vec4 color = c11;
+
+ /* AABB minmax */
+ vec4 min_col = min9(c02, c12, c22, c01, c11, c21, c00, c10, c20);
+ vec4 max_col = max9(c02, c12, c22, c01, c11, c21, c00, c10, c20);
+ vec4 avg_col = avg9(c02, c12, c22, c01, c11, c21, c00, c10, c20);
+
+ /* bias the color aabb toward the center (rounding the shape) */
+ vec4 min_center = min5(c12, c01, c11, c21, c10);
+ vec4 max_center = max5(c12, c01, c11, c21, c10);
+ vec4 avg_center = avg5(c12, c01, c11, c21, c10);
+ min_col = (min_col + min_center) * 0.5;
+ max_col = (max_col + max_center) * 0.5;
+ avg_col = (avg_col + avg_center) * 0.5;
+
+ /* Clip color toward the center of the neighborhood colors AABB box. */
+ color_history.rgb = clip_to_aabb(color_history.rgb, min_col.rgb, max_col.rgb, avg_col.rgb);
+
+ /* Luminance weighting. */
+ /* TODO correct luminance */
+ float lum0 = dot(color.rgb, vec3(0.333));
+ float lum1 = dot(color_history.rgb, vec3(0.333));
+ float diff = abs(lum0 - lum1) / max(lum0, max(lum1, 0.2));
+ float weight = 1.0 - diff;
+ float alpha = mix(0.04, 0.12, weight * weight);
+
+ color_history = mix(color_history, color, alpha);
+
+ bool out_of_view = any(greaterThanEqual(abs(uv_history - 0.5), vec2(0.5)));
+ color_history = (out_of_view) ? color : color_history;
+
+ FragColor = safe_color(color_history);
+}
+
+#else
+
+uniform float alpha;
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+ vec4 color = texelFetch(colorBuffer, texel, 0);
+ vec4 color_history = texelFetch(colorHistoryBuffer, texel, 0);
+ FragColor = safe_color(mix(color_history, color, alpha));
+}
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl
new file mode 100644
index 00000000000..8324c25225c
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl
@@ -0,0 +1,22 @@
+
+uniform mat4 currPersinv;
+uniform mat4 pastPersmat;
+
+out vec2 outData;
+
+void main()
+{
+ /* Extract pixel motion vector from camera movement. */
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+ vec2 uv = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0).xy);
+
+ float depth = texelFetch(depthBuffer, texel, 0).r;
+
+ vec3 world_position = project_point(currPersinv, vec3(uv, depth) * 2.0 - 1.0);
+ vec2 uv_history = project_point(pastPersmat, world_position).xy * 0.5 + 0.5;
+
+ outData = uv - uv_history;
+
+ /* Encode to unsigned normalized 16bit texture. */
+ outData = outData * 0.5 + 0.5;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
new file mode 100644
index 00000000000..132cc16fcbd
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
@@ -0,0 +1,177 @@
+
+uniform sampler2DArray irradianceGrid;
+
+#define IRRADIANCE_LIB
+
+#ifdef IRRADIANCE_CUBEMAP
+struct IrradianceData {
+ vec3 color;
+};
+#elif defined(IRRADIANCE_SH_L2)
+struct IrradianceData {
+ vec3 shcoefs[9];
+};
+#else /* defined(IRRADIANCE_HL2) */
+struct IrradianceData {
+ vec3 cubesides[3];
+};
+#endif
+
+IrradianceData load_irradiance_cell(int cell, vec3 N)
+{
+ /* Keep in sync with diffuse_filter_probe() */
+
+#if defined(IRRADIANCE_CUBEMAP)
+
+ #define AMBIANT_CUBESIZE 8
+ ivec2 cell_co = ivec2(AMBIANT_CUBESIZE);
+ int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
+ cell_co.x *= cell % cell_per_row;
+ cell_co.y *= cell / cell_per_row;
+
+ vec2 texelSize = 1.0 / vec2(AMBIANT_CUBESIZE);
+
+ vec2 uvs = mapping_octahedron(N, texelSize);
+ uvs *= vec2(AMBIANT_CUBESIZE) / vec2(textureSize(irradianceGrid, 0));
+ uvs += vec2(cell_co) / vec2(textureSize(irradianceGrid, 0));
+
+ IrradianceData ir;
+ ir.color = texture(irradianceGrid, vec3(uvs, 0.0)).rgb;
+
+#elif defined(IRRADIANCE_SH_L2)
+
+ ivec2 cell_co = ivec2(3, 3);
+ int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
+ cell_co.x *= cell % cell_per_row;
+ cell_co.y *= cell / cell_per_row;
+
+ ivec3 ofs = ivec3(0, 1, 2);
+
+ IrradianceData ir;
+ ir.shcoefs[0] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xx, 0), 0).rgb;
+ ir.shcoefs[1] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yx, 0), 0).rgb;
+ ir.shcoefs[2] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zx, 0), 0).rgb;
+ ir.shcoefs[3] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xy, 0), 0).rgb;
+ ir.shcoefs[4] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yy, 0), 0).rgb;
+ ir.shcoefs[5] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zy, 0), 0).rgb;
+ ir.shcoefs[6] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xz, 0), 0).rgb;
+ ir.shcoefs[7] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yz, 0), 0).rgb;
+ ir.shcoefs[8] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zz, 0), 0).rgb;
+
+#else /* defined(IRRADIANCE_HL2) */
+
+ ivec2 cell_co = ivec2(3, 2);
+ int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
+ cell_co.x *= cell % cell_per_row;
+ cell_co.y *= cell / cell_per_row;
+
+ ivec3 is_negative = ivec3(step(0.0, -N));
+
+ IrradianceData ir;
+ ir.cubesides[0] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(0, is_negative.x), 0), 0));
+ ir.cubesides[1] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(1, is_negative.y), 0), 0));
+ ir.cubesides[2] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(2, is_negative.z), 0), 0));
+
+#endif
+
+ return ir;
+}
+
+float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range)
+{
+ /* Keep in sync with diffuse_filter_probe() */
+ ivec2 cell_co = ivec2(prbIrradianceVisSize);
+ ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / prbIrradianceVisSize;
+ cell_co.x *= (cell % cell_per_row_col.x);
+ cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y;
+ float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y);
+
+ vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy);
+ vec2 co = vec2(cell_co) * texel_size;
+
+ vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(prbIrradianceVisSize)));
+ uv *= vec2(prbIrradianceVisSize) * texel_size;
+
+ vec4 data = texture(irradianceGrid, vec3(co + uv, layer));
+
+ /* Decoding compressed data */
+ vec2 moments = visibility_decode(data, range);
+
+ /* Doing chebishev test */
+ float variance = abs(moments.x * moments.x - moments.y);
+ variance = max(variance, bias / 10.0);
+
+ float d = dist - moments.x;
+ float p_max = variance / (variance + d * d);
+
+ /* Increase contrast in the weight by squaring it */
+ p_max *= p_max;
+
+ /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
+ p_max = clamp((p_max - bleed_bias) / (1.0 - bleed_bias), 0.0, 1.0);
+
+ return (dist <= moments.x) ? 1.0 : p_max;
+}
+
+/* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */
+vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[4])
+{
+ vec3 sh = vec3(0.0);
+
+ sh += 0.282095 * shcoefs[0];
+
+ sh += -0.488603 * N.z * shcoefs[1];
+ sh += 0.488603 * N.y * shcoefs[2];
+ sh += -0.488603 * N.x * shcoefs[3];
+
+ return sh;
+}
+
+vec3 spherical_harmonics_L2(vec3 N, vec3 shcoefs[9])
+{
+ vec3 sh = vec3(0.0);
+
+ sh += 0.282095 * shcoefs[0];
+
+ sh += -0.488603 * N.z * shcoefs[1];
+ sh += 0.488603 * N.y * shcoefs[2];
+ sh += -0.488603 * N.x * shcoefs[3];
+
+ sh += 1.092548 * N.x * N.z * shcoefs[4];
+ sh += -1.092548 * N.z * N.y * shcoefs[5];
+ sh += 0.315392 * (3.0 * N.y * N.y - 1.0) * shcoefs[6];
+ sh += -1.092548 * N.x * N.y * shcoefs[7];
+ sh += 0.546274 * (N.x * N.x - N.z * N.z) * shcoefs[8];
+
+ return sh;
+}
+
+vec3 hl2_basis(vec3 N, vec3 cubesides[3])
+{
+ vec3 irradiance = vec3(0.0);
+
+ vec3 n_squared = N * N;
+
+ irradiance += n_squared.x * cubesides[0];
+ irradiance += n_squared.y * cubesides[1];
+ irradiance += n_squared.z * cubesides[2];
+
+ return irradiance;
+}
+
+vec3 compute_irradiance(vec3 N, IrradianceData ird)
+{
+#if defined(IRRADIANCE_CUBEMAP)
+ return ird.color;
+#elif defined(IRRADIANCE_SH_L2)
+ return spherical_harmonics_L2(N, ird.shcoefs);
+#else /* defined(IRRADIANCE_HL2) */
+ return hl2_basis(N, ird.cubesides);
+#endif
+}
+
+vec3 irradiance_from_cell_get(int cell, vec3 ir_dir)
+{
+ IrradianceData ir_data = load_irradiance_cell(cell, ir_dir);
+ return compute_irradiance(ir_dir, ir_data);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
new file mode 100644
index 00000000000..fb18af494b4
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
@@ -0,0 +1,450 @@
+
+uniform sampler2DArray shadowCubeTexture;
+uniform sampler2DArray shadowCascadeTexture;
+
+#define LAMPS_LIB
+
+layout(std140) uniform shadow_block {
+ ShadowData shadows_data[MAX_SHADOW];
+ ShadowCubeData shadows_cube_data[MAX_SHADOW_CUBE];
+ ShadowCascadeData shadows_cascade_data[MAX_SHADOW_CASCADE];
+};
+
+layout(std140) uniform light_block {
+ LightData lights_data[MAX_LIGHT];
+};
+
+/* type */
+#define POINT 0.0
+#define SUN 1.0
+#define SPOT 2.0
+#define AREA_RECT 4.0
+/* Used to define the area lamp shape, doesn't directly correspond to a Blender lamp type. */
+#define AREA_ELLIPSE 100.0
+
+#if defined(SHADOW_VSM)
+#define ShadowSample vec2
+#define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).rg
+#define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).rg
+#elif defined(SHADOW_ESM)
+#define ShadowSample float
+#define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
+#define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
+#else
+#define ShadowSample float
+#define sample_cube(vec, id) texture_octahedron(shadowCubeTexture, vec4(vec, id)).r
+#define sample_cascade(vec, id) texture(shadowCascadeTexture, vec3(vec, id)).r
+#endif
+
+#if defined(SHADOW_VSM)
+#define get_depth_delta(dist, s) (dist - s.x)
+#else
+#define get_depth_delta(dist, s) (dist - s)
+#endif
+
+/* ----------------------------------------------------------- */
+/* ----------------------- Shadow tests ---------------------- */
+/* ----------------------------------------------------------- */
+
+#if defined(SHADOW_VSM)
+
+float shadow_test(ShadowSample moments, float dist, ShadowData sd)
+{
+ float p = 0.0;
+
+ if (dist <= moments.x)
+ p = 1.0;
+
+ float variance = moments.y - (moments.x * moments.x);
+ variance = max(variance, sd.sh_bias / 10.0);
+
+ float d = moments.x - dist;
+ float p_max = variance / (variance + d * d);
+
+ /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
+ p_max = clamp((p_max - sd.sh_bleed) / (1.0 - sd.sh_bleed), 0.0, 1.0);
+
+ return max(p, p_max);
+}
+
+#elif defined(SHADOW_ESM)
+
+float shadow_test(ShadowSample z, float dist, ShadowData sd)
+{
+ return saturate(exp(sd.sh_exp * (z - dist + sd.sh_bias)));
+}
+
+#else
+
+float shadow_test(ShadowSample z, float dist, ShadowData sd)
+{
+ return step(0, z - dist + sd.sh_bias);
+}
+
+#endif
+
+/* ----------------------------------------------------------- */
+/* ----------------------- Shadow types ---------------------- */
+/* ----------------------------------------------------------- */
+
+float shadow_cubemap(ShadowData sd, ShadowCubeData scd, float texid, vec3 W)
+{
+ vec3 cubevec = W - scd.position.xyz;
+ float dist = length(cubevec);
+
+ cubevec /= dist;
+
+ ShadowSample s = sample_cube(cubevec, texid);
+ return shadow_test(s, dist, sd);
+}
+
+float evaluate_cascade(ShadowData sd, mat4 shadowmat, vec3 W, float range, float texid)
+{
+ vec4 shpos = shadowmat * vec4(W, 1.0);
+ float dist = shpos.z * range;
+
+ ShadowSample s = sample_cascade(shpos.xy, texid);
+ float vis = shadow_test(s, dist, sd);
+
+ /* If fragment is out of shadowmap range, do not occlude */
+ if (shpos.z < 1.0 && shpos.z > 0.0) {
+ return vis;
+ }
+ else {
+ return 1.0;
+ }
+}
+
+float shadow_cascade(ShadowData sd, int scd_id, float texid, vec3 W)
+{
+ vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
+ vec4 weights = smoothstep(
+ shadows_cascade_data[scd_id].split_end_distances,
+ shadows_cascade_data[scd_id].split_start_distances.yzwx,
+ view_z);
+
+ weights.yzw -= weights.xyz;
+
+ vec4 vis = vec4(1.0);
+ float range = abs(sd.sh_far - sd.sh_near); /* Same factor as in get_cascade_world_distance(). */
+
+ /* Branching using (weights > 0.0) is reaally slooow on intel so avoid it for now. */
+ /* TODO OPTI: Only do 2 samples and blend. */
+ vis.x = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[0], W, range, texid + 0);
+ vis.y = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[1], W, range, texid + 1);
+ vis.z = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[2], W, range, texid + 2);
+ vis.w = evaluate_cascade(sd, shadows_cascade_data[scd_id].shadowmat[3], W, range, texid + 3);
+
+ float weight_sum = dot(vec4(1.0), weights);
+ if (weight_sum > 0.9999) {
+ float vis_sum = dot(vec4(1.0), vis * weights);
+ return vis_sum / weight_sum;
+ }
+ else {
+ float vis_sum = dot(vec4(1.0), vis * step(0.001, weights));
+ return mix(1.0, vis_sum, weight_sum);
+ }
+}
+
+/* ----------------------------------------------------------- */
+/* --------------------- Light Functions --------------------- */
+/* ----------------------------------------------------------- */
+
+/* From Frostbite PBR Course
+ * Distance based attenuation
+ * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */
+float distance_attenuation(float dist_sqr, float inv_sqr_influence)
+{
+ float factor = dist_sqr * inv_sqr_influence;
+ float fac = saturate(1.0 - factor * factor);
+ return fac * fac;
+}
+
+float spot_attenuation(LightData ld, vec3 l_vector)
+{
+ float z = dot(ld.l_forward, l_vector.xyz);
+ vec3 lL = l_vector.xyz / z;
+ float x = dot(ld.l_right, lL) / ld.l_sizex;
+ float y = dot(ld.l_up, lL) / ld.l_sizey;
+ float ellipse = inversesqrt(1.0 + x * x + y * y);
+ float spotmask = smoothstep(0.0, 1.0, (ellipse - ld.l_spot_size) / ld.l_spot_blend);
+ return spotmask;
+}
+
+float light_visibility(LightData ld, vec3 W,
+#ifndef VOLUMETRICS
+ vec3 viewPosition,
+ vec3 viewNormal,
+#endif
+ vec4 l_vector)
+{
+ float vis = 1.0;
+
+ if (ld.l_type == SPOT) {
+ vis *= spot_attenuation(ld, l_vector.xyz);
+ }
+ if (ld.l_type >= SPOT) {
+ vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
+ }
+ if (ld.l_type != SUN) {
+ vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
+ }
+
+#if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW)
+ /* shadowing */
+ if (ld.l_shadowid >= 0.0 && vis > 0.001) {
+ ShadowData data = shadows_data[int(ld.l_shadowid)];
+
+ if (ld.l_type == SUN) {
+ vis *= shadow_cascade(
+ data, int(data.sh_data_start),
+ data.sh_tex_start, W);
+ }
+ else {
+ vis *= shadow_cubemap(
+ data, shadows_cube_data[int(data.sh_data_start)],
+ data.sh_tex_start, W);
+ }
+
+#ifndef VOLUMETRICS
+ /* Only compute if not already in shadow. */
+ if (data.sh_contact_dist > 0.0) {
+ vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
+ float trace_distance = (ld.l_type != SUN) ? min(data.sh_contact_dist, l_vector.w) : data.sh_contact_dist;
+
+ vec3 T, B;
+ make_orthonormal_basis(L.xyz / L.w, T, B);
+
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ rand.zw *= fast_sqrt(rand.y) * data.sh_contact_spread;
+
+ /* We use the full l_vector.xyz so that the spread is minimize
+ * if the shading point is further away from the light source */
+ vec3 ray_dir = L.xyz + T * rand.z + B * rand.w;
+ ray_dir = transform_direction(ViewMatrix, ray_dir);
+ ray_dir = normalize(ray_dir);
+
+ vec3 ray_ori = viewPosition;
+
+ if (dot(viewNormal, ray_dir) <= 0.0) {
+ return vis;
+ }
+
+ float bias = 0.5; /* Constant Bias */
+ bias += 1.0 - abs(dot(viewNormal, ray_dir)); /* Angle dependent bias */
+ bias *= gl_FrontFacing ? data.sh_contact_offset : -data.sh_contact_offset;
+
+ vec3 nor_bias = viewNormal * bias;
+ ray_ori += nor_bias;
+
+ ray_dir *= trace_distance;
+ ray_dir -= nor_bias;
+
+ vec3 hit_pos = raycast(-1, ray_ori, ray_dir, data.sh_contact_thickness, rand.x,
+ 0.1, 0.001, false);
+
+ if (hit_pos.z > 0.0) {
+ hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
+ float hit_dist = distance(viewPosition, hit_pos);
+ float dist_ratio = hit_dist / trace_distance;
+ return vis * saturate(dist_ratio * dist_ratio * dist_ratio);
+ }
+ }
+#endif
+ }
+#endif
+
+ return vis;
+}
+
+#ifdef USE_LTC
+float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
+{
+ if (ld.l_type == AREA_RECT) {
+ vec3 corners[4];
+ corners[0] = normalize((l_vector.xyz + ld.l_right * -ld.l_sizex) + ld.l_up * ld.l_sizey);
+ corners[1] = normalize((l_vector.xyz + ld.l_right * -ld.l_sizex) + ld.l_up * -ld.l_sizey);
+ corners[2] = normalize((l_vector.xyz + ld.l_right * ld.l_sizex) + ld.l_up * -ld.l_sizey);
+ corners[3] = normalize((l_vector.xyz + ld.l_right * ld.l_sizex) + ld.l_up * ld.l_sizey);
+
+ return ltc_evaluate_quad(corners, N);
+ }
+ else if (ld.l_type == AREA_ELLIPSE) {
+ vec3 points[3];
+ points[0] = (l_vector.xyz + ld.l_right * -ld.l_sizex) + ld.l_up * -ld.l_sizey;
+ points[1] = (l_vector.xyz + ld.l_right * ld.l_sizex) + ld.l_up * -ld.l_sizey;
+ points[2] = (l_vector.xyz + ld.l_right * ld.l_sizex) + ld.l_up * ld.l_sizey;
+
+ return ltc_evaluate_disk(N, V, mat3(1.0), points);
+ }
+ else {
+ float radius = ld.l_radius;
+ radius /= (ld.l_type == SUN) ? 1.0 : l_vector.w;
+ vec3 L = (ld.l_type == SUN) ? -ld.l_forward : (l_vector.xyz / l_vector.w);
+
+ return ltc_evaluate_disk_simple(radius, dot(N, L));
+ }
+}
+
+float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector)
+{
+ if (ld.l_type == AREA_RECT) {
+ vec3 corners[4];
+ corners[0] = (l_vector.xyz + ld.l_right * -ld.l_sizex) + ld.l_up * ld.l_sizey;
+ corners[1] = (l_vector.xyz + ld.l_right * -ld.l_sizex) + ld.l_up * -ld.l_sizey;
+ corners[2] = (l_vector.xyz + ld.l_right * ld.l_sizex) + ld.l_up * -ld.l_sizey;
+ corners[3] = (l_vector.xyz + ld.l_right * ld.l_sizex) + ld.l_up * ld.l_sizey;
+
+ ltc_transform_quad(N, V, ltc_matrix(ltc_mat), corners);
+
+ return ltc_evaluate_quad(corners, vec3(0.0, 0.0, 1.0));
+ }
+ else {
+ bool is_ellipse = (ld.l_type == AREA_ELLIPSE);
+ float radius_x = is_ellipse ? ld.l_sizex : ld.l_radius;
+ float radius_y = is_ellipse ? ld.l_sizey : ld.l_radius;
+
+ vec3 L = (ld.l_type == SUN) ? -ld.l_forward : l_vector.xyz;
+ vec3 Px = ld.l_right;
+ vec3 Py = ld.l_up;
+
+ if (ld.l_type == SPOT || ld.l_type == POINT) {
+ make_orthonormal_basis(l_vector.xyz / l_vector.w, Px, Py);
+ }
+
+ vec3 points[3];
+ points[0] = (L + Px * -radius_x) + Py * -radius_y;
+ points[1] = (L + Px * radius_x) + Py * -radius_y;
+ points[2] = (L + Px * radius_x) + Py * radius_y;
+
+ return ltc_evaluate_disk(N, V, ltc_matrix(ltc_mat), points);
+ }
+}
+#endif
+
+#define MAX_SSS_SAMPLES 65
+#define SSS_LUT_SIZE 64.0
+#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE))
+#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE))
+
+#ifdef USE_TRANSLUCENCY
+layout(std140) uniform sssProfile {
+ vec4 kernel[MAX_SSS_SAMPLES];
+ vec4 radii_max_radius;
+ int sss_samples;
+};
+
+uniform sampler1D sssTexProfile;
+
+vec3 sss_profile(float s) {
+ s /= radii_max_radius.w;
+ return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
+}
+#endif
+
+vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, float scale)
+{
+#if !defined(USE_TRANSLUCENCY) || defined(VOLUMETRICS)
+ return vec3(0.0);
+#else
+ vec3 vis = vec3(1.0);
+
+ if (ld.l_type == SPOT) {
+ vis *= spot_attenuation(ld, l_vector.xyz);
+ }
+ if (ld.l_type >= SPOT) {
+ vis *= step(0.0, -dot(l_vector.xyz, ld.l_forward));
+ }
+ if (ld.l_type != SUN) {
+ vis *= distance_attenuation(l_vector.w * l_vector.w, ld.l_influence);
+ }
+
+ /* Only shadowed light can produce translucency */
+ if (ld.l_shadowid >= 0.0 && vis.x > 0.001) {
+ ShadowData data = shadows_data[int(ld.l_shadowid)];
+ float delta;
+
+ vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
+
+ vec3 T, B;
+ make_orthonormal_basis(L.xyz / L.w, T, B);
+
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ rand.zw *= fast_sqrt(rand.y) * data.sh_blur;
+
+ /* We use the full l_vector.xyz so that the spread is minimize
+ * if the shading point is further away from the light source */
+ W = W + T * rand.z + B * rand.w;
+
+ if (ld.l_type == SUN) {
+ int scd_id = int(data.sh_data_start);
+ vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
+
+ vec4 weights = step(shadows_cascade_data[scd_id].split_end_distances, view_z);
+ float id = abs(4.0 - dot(weights, weights));
+
+ if (id > 3.0) {
+ return vec3(0.0);
+ }
+
+ float range = abs(data.sh_far - data.sh_near); /* Same factor as in get_cascade_world_distance(). */
+
+ vec4 shpos = shadows_cascade_data[scd_id].shadowmat[int(id)] * vec4(W, 1.0);
+ float dist = shpos.z * range;
+
+ if (shpos.z > 1.0 || shpos.z < 0.0) {
+ return vec3(0.0);
+ }
+
+ ShadowSample s = sample_cascade(shpos.xy, data.sh_tex_start + id);
+ delta = get_depth_delta(dist, s);
+ }
+ else {
+ vec3 cubevec = W - shadows_cube_data[int(data.sh_data_start)].position.xyz;
+ float dist = length(cubevec);
+ cubevec /= dist;
+
+ ShadowSample s = sample_cube(cubevec, data.sh_tex_start);
+ delta = get_depth_delta(dist, s);
+ }
+
+ /* XXX : Removing Area Power. */
+ /* TODO : put this out of the shader. */
+ float falloff;
+ if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
+ vis *= (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
+ if (ld.l_type == AREA_ELLIPSE) {
+ vis *= M_PI * 0.25;
+ }
+ vis *= 0.3 * 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
+ vis /= (l_vector.w * l_vector.w);
+ falloff = dot(N, l_vector.xyz / l_vector.w);
+ }
+ else if (ld.l_type == SUN) {
+ vis /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f);
+ vis *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
+ vis *= M_2PI * 0.78; /* Matching cycles with point light. */
+ vis *= 0.082; /* XXX ad hoc, empirical */
+ falloff = dot(N, -ld.l_forward);
+ }
+ else {
+ vis *= (4.0 * ld.l_radius * ld.l_radius) * (1.0 /10.0);
+ vis *= 1.5; /* XXX ad hoc, empirical */
+ vis /= (l_vector.w * l_vector.w);
+ falloff = dot(N, l_vector.xyz / l_vector.w);
+ }
+ // vis *= M_1_PI; /* Normalize */
+
+ /* Applying profile */
+ vis *= sss_profile(abs(delta) / scale);
+
+ /* No transmittance at grazing angle (hide artifacts) */
+ vis *= saturate(falloff * 2.0);
+ }
+ else {
+ vis = vec3(0.0);
+ }
+
+ return vis;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
new file mode 100644
index 00000000000..5a72244cfbe
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl
@@ -0,0 +1,18 @@
+
+flat in int pid;
+in vec2 quadCoord;
+
+out vec4 FragColor;
+
+void main()
+{
+ float dist_sqr = dot(quadCoord, quadCoord);
+
+ /* Discard outside the circle. */
+ if (dist_sqr > 1.0)
+ discard;
+
+ vec3 view_nor = vec3(quadCoord, sqrt(max(0.0, 1.0 - dist_sqr)));
+ vec3 world_ref = mat3(ViewMatrixInverse) * reflect(vec3(0.0, 0.0, -1.0), view_nor);
+ FragColor = vec4(textureLod_octahedron(probeCubes, vec4(world_ref, pid), 0.0, prbLodCubeMax).rgb, 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
new file mode 100644
index 00000000000..b327878b63d
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl
@@ -0,0 +1,43 @@
+
+/* XXX TODO fix code duplication */
+struct CubeData {
+ vec4 position_type;
+ vec4 attenuation_fac_type;
+ mat4 influencemat;
+ mat4 parallaxmat;
+};
+
+layout(std140) uniform probe_block {
+ CubeData probes_data[MAX_PROBE];
+};
+
+uniform float sphere_size;
+uniform vec3 screen_vecs[2];
+
+flat out int pid;
+out vec2 quadCoord;
+
+const vec2 pos[6] = vec2[6](
+ vec2(-1.0, -1.0),
+ vec2( 1.0, -1.0),
+ vec2(-1.0, 1.0),
+
+ vec2( 1.0, -1.0),
+ vec2( 1.0, 1.0),
+ vec2(-1.0, 1.0)
+);
+
+void main()
+{
+ pid = 1 + (gl_VertexID / 6); /* +1 for the world */
+ int vert_id = gl_VertexID % 6;
+
+ quadCoord = pos[vert_id];
+
+ vec3 ws_location = probes_data[pid].position_type.xyz;
+ vec3 screen_pos = screen_vecs[0] * quadCoord.x + screen_vecs[1] * quadCoord.y;
+ ws_location += screen_pos * sphere_size;
+
+ gl_Position = ViewProjectionMatrix * vec4(ws_location, 1.0);
+ gl_Position.z += 0.0001; /* Small bias to let the icon draw without zfighting */
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
new file mode 100644
index 00000000000..7cf4259a938
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
@@ -0,0 +1,197 @@
+
+uniform samplerCube probeHdr;
+uniform int probeSize;
+uniform float lodFactor;
+uniform float lodMax;
+uniform float intensityFac;
+
+in vec3 worldPosition;
+
+out vec4 FragColor;
+
+#define M_4PI 12.5663706143591729
+
+const mat3 CUBE_ROTATIONS[6] = mat3[](
+ mat3(vec3( 0.0, 0.0, -1.0),
+ vec3( 0.0, -1.0, 0.0),
+ vec3(-1.0, 0.0, 0.0)),
+ mat3(vec3( 0.0, 0.0, 1.0),
+ vec3( 0.0, -1.0, 0.0),
+ vec3( 1.0, 0.0, 0.0)),
+ mat3(vec3( 1.0, 0.0, 0.0),
+ vec3( 0.0, 0.0, 1.0),
+ vec3( 0.0, -1.0, 0.0)),
+ mat3(vec3( 1.0, 0.0, 0.0),
+ vec3( 0.0, 0.0, -1.0),
+ vec3( 0.0, 1.0, 0.0)),
+ mat3(vec3( 1.0, 0.0, 0.0),
+ vec3( 0.0, -1.0, 0.0),
+ vec3( 0.0, 0.0, -1.0)),
+ mat3(vec3(-1.0, 0.0, 0.0),
+ vec3( 0.0, -1.0, 0.0),
+ vec3( 0.0, 0.0, 1.0)));
+
+vec3 get_cubemap_vector(vec2 co, int face)
+{
+ return normalize(CUBE_ROTATIONS[face] * vec3(co * 2.0 - 1.0, 1.0));
+}
+
+float area_element(float x, float y)
+{
+ return atan(x * y, sqrt(x * x + y * y + 1));
+}
+
+float texel_solid_angle(vec2 co, float halfpix)
+{
+ vec2 v1 = (co - vec2(halfpix)) * 2.0 - 1.0;
+ vec2 v2 = (co + vec2(halfpix)) * 2.0 - 1.0;
+
+ return area_element(v1.x, v1.y) - area_element(v1.x, v2.y) - area_element(v2.x, v1.y) + area_element(v2.x, v2.y);
+}
+
+vec3 octahedral_to_cubemap_proj(vec2 co)
+{
+ co = co * 2.0 - 1.0;
+
+ vec2 abs_co = abs(co);
+ vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
+
+ if ( abs_co.x + abs_co.y > 1.0 ) {
+ v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
+ }
+
+ return v;
+}
+
+void main()
+{
+#if defined(IRRADIANCE_SH_L2)
+ float pixstep = 1.0 / probeSize;
+ float halfpix = pixstep / 2.0;
+
+ /* Downside: leaks negative values, very bandwidth consuming */
+ int comp = int(gl_FragCoord.x) % 3 + (int(gl_FragCoord.y) % 3) * 3;
+
+ float weight_accum = 0.0;
+ vec3 sh = vec3(0.0);
+
+ for (int face = 0; face < 6; ++face) {
+ for (float x = halfpix; x < 1.0; x += pixstep) {
+ for (float y = halfpix; y < 1.0; y += pixstep) {
+ float weight, coef;
+ vec2 facecoord = vec2(x,y);
+ vec3 cubevec = get_cubemap_vector(facecoord, face);
+
+ if (comp == 0) {
+ coef = 0.282095;
+ }
+ else if (comp == 1) {
+ coef = -0.488603 * cubevec.z * 2.0 / 3.0;
+ }
+ else if (comp == 2) {
+ coef = 0.488603 * cubevec.y * 2.0 / 3.0;
+ }
+ else if (comp == 3) {
+ coef = -0.488603 * cubevec.x * 2.0 / 3.0;
+ }
+ else if (comp == 4) {
+ coef = 1.092548 * cubevec.x * cubevec.z * 1.0 / 4.0;
+ }
+ else if (comp == 5) {
+ coef = -1.092548 * cubevec.z * cubevec.y * 1.0 / 4.0;
+ }
+ else if (comp == 6) {
+ coef = 0.315392 * (3.0 * cubevec.y * cubevec.y - 1.0) * 1.0 / 4.0;
+ }
+ else if (comp == 7) {
+ coef = 1.092548 * cubevec.x * cubevec.y * 1.0 / 4.0;
+ }
+ else { /* (comp == 8) */
+ coef = 0.546274 * (cubevec.x * cubevec.x - cubevec.z * cubevec.z) * 1.0 / 4.0;
+ }
+
+ weight = texel_solid_angle(facecoord, halfpix);
+
+ vec4 sample = textureLod(probeHdr, cubevec, lodMax);
+ sh += sample.rgb * coef * weight;
+ weight_accum += weight;
+ }
+ }
+ }
+ sh *= M_4PI / weight_accum;
+
+ FragColor = vec4(sh, 1.0);
+#else
+#if defined(IRRADIANCE_CUBEMAP)
+ /* Downside: Need lots of memory for storage, distortion due to octahedral mapping */
+ const vec2 map_size = vec2(16.0);
+ const vec2 texelSize = 1.0 / map_size;
+ vec2 uvs = mod(gl_FragCoord.xy, map_size) * texelSize;
+ const float paddingSize = 1.0;
+
+ /* Add a N pixel border to ensure filtering is correct
+ * for N mipmap levels. */
+ uvs = (uvs - texelSize * paddingSize) / (1.0 - 2.0 * texelSize * paddingSize);
+
+ /* edge mirroring : only mirror if directly adjacent
+ * (not diagonally adjacent) */
+ vec2 m = abs(uvs - 0.5) + 0.5;
+ vec2 f = floor(m);
+ if (f.x - f.y != 0.0) {
+ uvs = 1.0 - uvs;
+ }
+
+ /* clamp to [0-1] */
+ uvs = fract(uvs);
+
+ /* get cubemap vector */
+ vec3 cubevec = octahedral_to_cubemap_proj(uvs);
+
+#elif defined(IRRADIANCE_HL2)
+ /* Downside: very very low resolution (6 texels), bleed lighting because of interpolation */
+ int x = int(gl_FragCoord.x) % 3;
+ int y = int(gl_FragCoord.y) % 2;
+
+ vec3 cubevec = vec3(1.0, 0.0, 0.0);
+
+ if (x == 1) {
+ cubevec = cubevec.yxy;
+ }
+ else if (x == 2) {
+ cubevec = cubevec.yyx;
+ }
+
+ if (y == 1) {
+ cubevec = -cubevec;
+ }
+#endif
+
+ vec3 N, T, B, V;
+
+ N = normalize(cubevec);
+
+ make_orthonormal_basis(N, T, B); /* Generate tangent space */
+
+ /* Integrating Envmap */
+ float weight = 0.0;
+ vec3 out_radiance = vec3(0.0);
+ for (float i = 0; i < sampleCount; i++) {
+ vec3 L = sample_hemisphere(i, N, T, B); /* Microfacet normal */
+ float NL = dot(N, L);
+
+ if (NL > 0.0) {
+ /* Coarse Approximation of the mapping distortion
+ * Unit Sphere -> Cubemap Face */
+ const float dist = 4.0 * M_PI / 6.0;
+ float pdf = pdf_hemisphere();
+ /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */
+ float lod = clamp(lodFactor - 0.5 * log2(pdf * dist), 0.0, lodMax) ;
+
+ out_radiance += textureLod(probeHdr, L, lod).rgb * NL;
+ weight += NL;
+ }
+ }
+
+ FragColor = irradiance_encode(intensityFac * out_radiance / weight);
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
new file mode 100644
index 00000000000..fdfee54f368
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
@@ -0,0 +1,98 @@
+
+uniform samplerCube probeHdr;
+uniform float roughnessSquared;
+uniform float texelSize;
+uniform float lodFactor;
+uniform float lodMax;
+uniform float paddingSize;
+uniform float intensityFac;
+uniform float fireflyFactor;
+
+in vec3 worldPosition;
+
+out vec4 FragColor;
+
+float brightness(vec3 c)
+{
+ return max(max(c.r, c.g), c.b);
+}
+
+vec3 octahedral_to_cubemap_proj(vec2 co)
+{
+ co = co * 2.0 - 1.0;
+
+ vec2 abs_co = abs(co);
+ vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
+
+ if ( abs_co.x + abs_co.y > 1.0 ) {
+ v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
+ }
+
+ return v;
+}
+
+void main() {
+ vec2 uvs = gl_FragCoord.xy * texelSize;
+
+ /* Add a N pixel border to ensure filtering is correct
+ * for N mipmap levels. */
+ uvs = (uvs - paddingSize) / (1.0 - 2.0 * paddingSize);
+
+ /* edge mirroring : only mirror if directly adjacent
+ * (not diagonally adjacent) */
+ vec2 m = abs(uvs - 0.5) + 0.5;
+ vec2 f = floor(m);
+ if (f.x - f.y != 0.0) {
+ uvs = 1.0 - uvs;
+ }
+
+ /* clamp to [0-1] */
+ uvs = fract(uvs);
+
+ /* get cubemap vector */
+ vec3 cubevec = octahedral_to_cubemap_proj(uvs);
+
+ vec3 N, T, B, V;
+
+ vec3 R = normalize(cubevec);
+
+ /* Isotropic assumption */
+ N = V = R;
+
+ make_orthonormal_basis(N, T, B); /* Generate tangent space */
+
+ /* Noise to dither the samples */
+ /* Note : ghosting is better looking than noise. */
+ // setup_noise();
+
+ /* Integrating Envmap */
+ float weight = 0.0;
+ vec3 out_radiance = vec3(0.0);
+ for (float i = 0; i < sampleCount; i++) {
+ vec3 H = sample_ggx(i, roughnessSquared, N, T, B); /* Microfacet normal */
+ vec3 L = -reflect(V, H);
+ float NL = dot(N, L);
+
+ if (NL > 0.0) {
+ float NH = max(1e-8, dot(N, H)); /* cosTheta */
+
+ /* Coarse Approximation of the mapping distortion
+ * Unit Sphere -> Cubemap Face */
+ const float dist = 4.0 * M_PI / 6.0;
+ float pdf = pdf_ggx_reflect(NH, roughnessSquared);
+ /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */
+ float lod = clamp(lodFactor - 0.5 * log2(pdf * dist), 0.0, lodMax) ;
+
+ vec3 l_col = textureLod(probeHdr, L, lod).rgb;
+
+ /* Clamped brightness. */
+ float luma = max(1e-8, brightness(l_col));
+ l_col *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
+
+ out_radiance += l_col * NL;
+ weight += NL;
+ }
+ }
+
+ FragColor = vec4(intensityFac * out_radiance / weight, 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
new file mode 100644
index 00000000000..083d2313337
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
@@ -0,0 +1,87 @@
+
+uniform samplerCube probeDepth;
+uniform int outputSize;
+uniform float lodFactor;
+uniform float storedTexelSize;
+uniform float lodMax;
+uniform float nearClip;
+uniform float farClip;
+uniform float visibilityRange;
+uniform float visibilityBlur;
+
+out vec4 FragColor;
+
+vec3 octahedral_to_cubemap_proj(vec2 co)
+{
+ co = co * 2.0 - 1.0;
+
+ vec2 abs_co = abs(co);
+ vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
+
+ if ( abs_co.x + abs_co.y > 1.0 ) {
+ v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
+ }
+
+ return v;
+}
+
+float linear_depth(float z)
+{
+ return (nearClip * farClip) / (z * (nearClip - farClip) + farClip);
+}
+
+float get_world_distance(float depth, vec3 cos)
+{
+ float is_background = step(1.0, depth);
+ depth = linear_depth(depth);
+ depth += 1e1 * is_background;
+ cos = normalize(abs(cos));
+ float cos_vec = max(cos.x, max(cos.y, cos.z));
+ return depth / cos_vec;
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy) % ivec2(outputSize);
+
+ vec3 cos;
+
+ cos.xy = (vec2(texel) + 0.5) * storedTexelSize;
+
+ /* add a 2 pixel border to ensure filtering is correct */
+ cos.xy = (cos.xy - storedTexelSize) / (1.0 - 2.0 * storedTexelSize);
+
+ float pattern = 1.0;
+
+ /* edge mirroring : only mirror if directly adjacent
+ * (not diagonally adjacent) */
+ vec2 m = abs(cos.xy - 0.5) + 0.5;
+ vec2 f = floor(m);
+ if (f.x - f.y != 0.0) {
+ cos.xy = 1.0 - cos.xy;
+ }
+
+ /* clamp to [0-1] */
+ cos.xy = fract(cos.xy);
+
+ /* get cubemap vector */
+ cos = normalize(octahedral_to_cubemap_proj(cos.xy));
+
+ vec3 T, B;
+ make_orthonormal_basis(cos, T, B); /* Generate tangent space */
+
+ vec2 accum = vec2(0.0);
+
+ for (float i = 0; i < sampleCount; i++) {
+ vec3 sample = sample_cone(i, M_PI_2 * visibilityBlur, cos, T, B);
+ float depth = texture(probeDepth, sample).r;
+ depth = get_world_distance(depth, sample);
+ accum += vec2(depth, depth * depth);
+ }
+
+ accum *= invSampleCount;
+ accum = abs(accum);
+
+ /* Encode to normalized RGBA 8 */
+ FragColor = visibility_encode(accum, visibilityRange);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
new file mode 100644
index 00000000000..2ce37d867b7
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_geom.glsl
@@ -0,0 +1,34 @@
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+uniform int Layer;
+
+in vec4 vPos[];
+flat in int face[];
+flat out int fFace;
+
+out vec3 worldPosition;
+out vec3 viewPosition; /* Required. otherwise generate linking error. */
+out vec3 worldNormal; /* Required. otherwise generate linking error. */
+out vec3 viewNormal; /* Required. otherwise generate linking error. */
+
+const vec3 maj_axes[6] = vec3[6](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3( 0.0, 0.0, 1.0), vec3( 0.0, 0.0, -1.0));
+const vec3 x_axis[6] = vec3[6](vec3(0.0, 0.0, -1.0), vec3( 0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3( 1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0));
+const vec3 y_axis[6] = vec3[6](vec3(0.0, -1.0, 0.0), vec3( 0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0), vec3( 0.0, -1.0, 0.0), vec3( 0.0, -1.0, 0.0));
+
+void main() {
+ fFace = face[0];
+ gl_Layer = Layer + fFace;
+
+ for (int v = 0; v < 3; ++v) {
+ gl_Position = vPos[v];
+ worldPosition = x_axis[fFace] * vPos[v].x + y_axis[fFace] * vPos[v].y + maj_axes[fFace];
+#ifdef ATTRIB
+ pass_attrib(v);
+#endif
+ EmitVertex();
+ }
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl
new file mode 100644
index 00000000000..fd8eb157aa5
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_frag.glsl
@@ -0,0 +1,19 @@
+
+flat in int cellOffset;
+in vec2 quadCoord;
+
+out vec4 FragColor;
+
+void main()
+{
+ float dist_sqr = dot(quadCoord, quadCoord);
+
+ /* Discard outside the circle. */
+ if (dist_sqr > 1.0)
+ discard;
+
+ vec3 view_nor = vec3(quadCoord, sqrt(max(0.0, 1.0 - dist_sqr)));
+ vec3 world_nor = mat3(ViewMatrixInverse) * view_nor;
+ IrradianceData ir_data = load_irradiance_cell(cellOffset, world_nor);
+ FragColor = vec4(compute_irradiance(world_nor, ir_data), 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
new file mode 100644
index 00000000000..7a92b55e530
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl
@@ -0,0 +1,49 @@
+
+uniform float sphere_size;
+uniform int offset;
+uniform ivec3 grid_resolution;
+uniform vec3 corner;
+uniform vec3 increment_x;
+uniform vec3 increment_y;
+uniform vec3 increment_z;
+uniform vec3 screen_vecs[2];
+
+flat out int cellOffset;
+out vec2 quadCoord;
+
+const vec2 pos[6] = vec2[6](
+ vec2(-1.0, -1.0),
+ vec2( 1.0, -1.0),
+ vec2(-1.0, 1.0),
+
+ vec2( 1.0, -1.0),
+ vec2( 1.0, 1.0),
+ vec2(-1.0, 1.0)
+);
+
+void main()
+{
+ int cell_id = gl_VertexID / 6;
+ int vert_id = gl_VertexID % 6;
+
+ vec3 ls_cell_location;
+ /* Keep in sync with update_irradiance_probe */
+ ls_cell_location.z = float(cell_id % grid_resolution.z);
+ ls_cell_location.y = float((cell_id / grid_resolution.z) % grid_resolution.y);
+ ls_cell_location.x = float(cell_id / (grid_resolution.z * grid_resolution.y));
+
+ cellOffset = offset + cell_id;
+
+ vec3 ws_cell_location = corner +
+ (increment_x * ls_cell_location.x +
+ increment_y * ls_cell_location.y +
+ increment_z * ls_cell_location.z);
+
+
+ quadCoord = pos[vert_id];
+ vec3 screen_pos = screen_vecs[0] * quadCoord.x + screen_vecs[1] * quadCoord.y;
+ ws_cell_location += screen_pos * sphere_size;
+
+ gl_Position = ViewProjectionMatrix * vec4(ws_cell_location , 1.0);
+ gl_Position.z += 0.0001; /* Small bias to let the icon draw without zfighting */
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl
new file mode 100644
index 00000000000..ced8e7f4f01
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl
@@ -0,0 +1,20 @@
+uniform sampler2DArray irradianceGrid;
+
+out vec4 FragColor;
+
+void main()
+{
+#if defined(IRRADIANCE_SH_L2)
+ const ivec2 data_size = ivec2(3, 3);
+#elif defined(IRRADIANCE_CUBEMAP)
+ const ivec2 data_size = ivec2(8, 8);
+#elif defined(IRRADIANCE_HL2)
+ const ivec2 data_size = ivec2(3, 2);
+#endif
+ ivec2 coord = ivec2(gl_FragCoord.xy) % data_size;
+ FragColor = texelFetch(irradianceGrid, ivec3(coord, 0), 0);
+
+ if (any(greaterThanEqual(ivec2(gl_FragCoord.xy), data_size))) {
+ FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
new file mode 100644
index 00000000000..a991e640a79
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -0,0 +1,304 @@
+/* ----------- Uniforms --------- */
+
+uniform sampler2DArray probePlanars;
+uniform sampler2DArray probeCubes;
+
+/* ----------- Structures --------- */
+
+struct CubeData {
+ vec4 position_type;
+ vec4 attenuation_fac_type;
+ mat4 influencemat;
+ mat4 parallaxmat;
+};
+
+#define PROBE_PARALLAX_BOX 1.0
+#define PROBE_ATTENUATION_BOX 1.0
+
+#define p_position position_type.xyz
+#define p_parallax_type position_type.w
+#define p_atten_fac attenuation_fac_type.x
+#define p_atten_type attenuation_fac_type.y
+
+struct PlanarData {
+ vec4 plane_equation;
+ vec4 clip_vec_x_fade_scale;
+ vec4 clip_vec_y_fade_bias;
+ vec4 clip_edges;
+ vec4 facing_scale_bias;
+ mat4 reflectionmat; /* transform world space into reflection texture space */
+ mat4 unused;
+};
+
+#define pl_plane_eq plane_equation
+#define pl_normal plane_equation.xyz
+#define pl_facing_scale facing_scale_bias.x
+#define pl_facing_bias facing_scale_bias.y
+#define pl_fade_scale clip_vec_x_fade_scale.w
+#define pl_fade_bias clip_vec_y_fade_bias.w
+#define pl_clip_pos_x clip_vec_x_fade_scale.xyz
+#define pl_clip_pos_y clip_vec_y_fade_bias.xyz
+#define pl_clip_edges clip_edges
+
+struct GridData {
+ mat4 localmat;
+ ivec4 resolution_offset;
+ vec4 ws_corner_atten_scale; /* world space corner position */
+ vec4 ws_increment_x_atten_bias; /* world space vector between 2 opposite cells */
+ vec4 ws_increment_y_lvl_bias;
+ vec4 ws_increment_z;
+ vec4 vis_bias_bleed_range;
+};
+
+#define g_corner ws_corner_atten_scale.xyz
+#define g_atten_scale ws_corner_atten_scale.w
+#define g_atten_bias ws_increment_x_atten_bias.w
+#define g_level_bias ws_increment_y_lvl_bias.w
+#define g_increment_x ws_increment_x_atten_bias.xyz
+#define g_increment_y ws_increment_y_lvl_bias.xyz
+#define g_increment_z ws_increment_z.xyz
+#define g_resolution resolution_offset.xyz
+#define g_offset resolution_offset.w
+#define g_vis_bias vis_bias_bleed_range.x
+#define g_vis_bleed vis_bias_bleed_range.y
+#define g_vis_range vis_bias_bleed_range.z
+
+#ifndef MAX_PROBE
+#define MAX_PROBE 1
+#endif
+#ifndef MAX_GRID
+#define MAX_GRID 1
+#endif
+#ifndef MAX_PLANAR
+#define MAX_PLANAR 1
+#endif
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
+uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
+
+layout(std140) uniform probe_block {
+ CubeData probes_data[MAX_PROBE];
+};
+
+layout(std140) uniform grid_block {
+ GridData grids_data[MAX_GRID];
+};
+
+layout(std140) uniform planar_block {
+ PlanarData planars_data[MAX_PLANAR];
+};
+
+/* ----------- Functions --------- */
+
+float probe_attenuation_cube(int pd_id, vec3 W)
+{
+ vec3 localpos = transform_point(probes_data[pd_id].influencemat, W);
+
+ float probe_atten_fac = probes_data[pd_id].p_atten_fac;
+ float fac;
+ if (probes_data[pd_id].p_atten_type == PROBE_ATTENUATION_BOX) {
+ vec3 axes_fac = saturate(probe_atten_fac - probe_atten_fac * abs(localpos));
+ fac = min_v3(axes_fac);
+ }
+ else {
+ fac = saturate(probe_atten_fac - probe_atten_fac * length(localpos));
+ }
+
+ return fac;
+}
+
+float probe_attenuation_planar(PlanarData pd, vec3 W, vec3 N, float roughness)
+{
+ /* Normal Facing */
+ float fac = saturate(dot(pd.pl_normal, N) * pd.pl_facing_scale + pd.pl_facing_bias);
+
+ /* Distance from plane */
+ fac *= saturate(abs(dot(pd.pl_plane_eq, vec4(W, 1.0))) * pd.pl_fade_scale + pd.pl_fade_bias);
+
+ /* Fancy fast clipping calculation */
+ vec2 dist_to_clip;
+ dist_to_clip.x = dot(pd.pl_clip_pos_x, W);
+ dist_to_clip.y = dot(pd.pl_clip_pos_y, W);
+ /* compare and add all tests */
+ fac *= step(2.0, dot(step(pd.pl_clip_edges, dist_to_clip.xxyy), vec2(-1.0, 1.0).xyxy));
+
+ /* Decrease influence for high roughness */
+ fac *= saturate(1.0 - roughness * 10.0);
+
+ return fac;
+}
+
+float probe_attenuation_grid(GridData gd, mat4 localmat, vec3 W, out vec3 localpos)
+{
+ localpos = transform_point(localmat, W);
+ vec3 pos_to_edge = max(vec3(0.0), abs(localpos) - 1.0);
+ float fade = length(pos_to_edge);
+ return saturate(-fade * gd.g_atten_scale + gd.g_atten_bias);
+}
+
+vec3 probe_evaluate_cube(int pd_id, vec3 W, vec3 R, float roughness)
+{
+ /* Correct reflection ray using parallax volume intersection. */
+ vec3 localpos = transform_point(probes_data[pd_id].parallaxmat, W);
+ vec3 localray = transform_direction(probes_data[pd_id].parallaxmat, R);
+
+ float dist;
+ if (probes_data[pd_id].p_parallax_type == PROBE_PARALLAX_BOX) {
+ dist = line_unit_box_intersect_dist(localpos, localray);
+ }
+ else {
+ dist = line_unit_sphere_intersect_dist(localpos, localray);
+ }
+
+ /* Use Distance in WS directly to recover intersection */
+ vec3 intersection = W + R * dist - probes_data[pd_id].p_position;
+
+ /* From Frostbite PBR Course
+ * Distance based roughness
+ * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */
+ float original_roughness = roughness;
+ float linear_roughness = sqrt(roughness);
+ float distance_roughness = saturate(dist * linear_roughness / length(intersection));
+ linear_roughness = mix(distance_roughness, linear_roughness, linear_roughness);
+ roughness = linear_roughness * linear_roughness;
+
+ float fac = saturate(original_roughness * 2.0 - 1.0);
+ R = mix(intersection, R, fac * fac);
+
+ return textureLod_octahedron(probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax, prbLodCubeMax).rgb;
+}
+
+vec3 probe_evaluate_world_spec(vec3 R, float roughness)
+{
+ return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax).rgb;
+}
+
+vec3 probe_evaluate_planar(
+ float id, PlanarData pd, vec3 W, vec3 N, vec3 V,
+ float roughness, inout float fade)
+{
+ /* Find view vector / reflection plane intersection. */
+ vec3 point_on_plane = line_plane_intersect(W, V, pd.pl_plane_eq);
+
+ /* How far the pixel is from the plane. */
+ float ref_depth = 1.0; /* TODO parameter */
+
+ /* Compute distorded reflection vector based on the distance to the reflected object.
+ * In other words find intersection between reflection vector and the sphere center
+ * around point_on_plane. */
+ vec3 proj_ref = reflect(reflect(-V, N) * ref_depth, pd.pl_normal);
+
+ /* Final point in world space. */
+ vec3 ref_pos = point_on_plane + proj_ref;
+
+ /* Reproject to find texture coords. */
+ vec4 refco = ViewProjectionMatrix * vec4(ref_pos, 1.0);
+ refco.xy /= refco.w;
+
+ /* TODO: If we support non-ssr planar reflection, we should blur them with gaussian
+ * and chose the right mip depending on the cone footprint after projection */
+ vec3 sample = textureLod(probePlanars, vec3(refco.xy * 0.5 + 0.5, id), 0.0).rgb;
+
+ return sample;
+}
+
+void fallback_cubemap(
+ vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum)
+{
+ /* Specular probes */
+ vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared);
+
+#ifdef SSR_AO
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ vec3 bent_normal;
+ float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal);
+ final_ao = specular_occlusion(dot(N, V), final_ao, roughness);
+#else
+ const float final_ao = 1.0;
+#endif
+
+ /* Starts at 1 because 0 is world probe */
+ for (int i = 1; i < MAX_PROBE && i < prbNumRenderCube && spec_accum.a < 0.999; ++i) {
+ float fade = probe_attenuation_cube(i, W);
+
+ if (fade > 0.0) {
+ vec3 spec = final_ao * probe_evaluate_cube(i, W, spec_dir, roughness);
+ accumulate_light(spec, fade, spec_accum);
+ }
+ }
+
+ /* World Specular */
+ if (spec_accum.a < 0.999) {
+ vec3 spec = final_ao * probe_evaluate_world_spec(spec_dir, roughness);
+ accumulate_light(spec, 1.0, spec_accum);
+ }
+}
+
+#ifdef IRRADIANCE_LIB
+vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos)
+{
+ localpos = localpos * 0.5 + 0.5;
+ localpos = localpos * vec3(gd.g_resolution) - 0.5;
+
+ vec3 localpos_floored = floor(localpos);
+ vec3 trilinear_weight = fract(localpos);
+
+ float weight_accum = 0.0;
+ vec3 irradiance_accum = vec3(0.0);
+
+ /* For each neighboor cells */
+ for (int i = 0; i < 8; ++i) {
+ ivec3 offset = ivec3(i, i >> 1, i >> 2) & ivec3(1);
+ vec3 cell_cos = clamp(localpos_floored + vec3(offset), vec3(0.0), vec3(gd.g_resolution) - 1.0);
+
+ /* Keep in sync with update_irradiance_probe */
+ ivec3 icell_cos = ivec3(gd.g_level_bias * floor(cell_cos / gd.g_level_bias));
+ int cell = gd.g_offset + icell_cos.z
+ + icell_cos.y * gd.g_resolution.z
+ + icell_cos.x * gd.g_resolution.z * gd.g_resolution.y;
+
+ vec3 color = irradiance_from_cell_get(cell, N);
+
+ /* We need this because we render probes in world space (so we need light vector in WS).
+ * And rendering them in local probe space is too much problem. */
+ vec3 ws_cell_location = gd.g_corner +
+ (gd.g_increment_x * cell_cos.x +
+ gd.g_increment_y * cell_cos.y +
+ gd.g_increment_z * cell_cos.z);
+
+ vec3 ws_point_to_cell = ws_cell_location - W;
+ float ws_dist_point_to_cell = length(ws_point_to_cell);
+ vec3 ws_light = ws_point_to_cell / ws_dist_point_to_cell;
+
+ /* Smooth backface test */
+ float weight = saturate(dot(ws_light, N));
+
+ /* Precomputed visibility */
+ weight *= load_visibility_cell(cell, ws_light, ws_dist_point_to_cell, gd.g_vis_bias, gd.g_vis_bleed, gd.g_vis_range);
+
+ /* Smoother transition */
+ weight += prbIrradianceSmooth;
+
+ /* Trilinear weights */
+ vec3 trilinear = mix(1.0 - trilinear_weight, trilinear_weight, offset);
+ weight *= trilinear.x * trilinear.y * trilinear.z;
+
+ /* Avoid zero weight */
+ weight = max(0.00001, weight);
+
+ weight_accum += weight;
+ irradiance_accum += color * weight;
+ }
+
+ return irradiance_accum / weight_accum;
+}
+
+vec3 probe_evaluate_world_diff(vec3 N)
+{
+ return irradiance_from_cell_get(0, N);
+}
+
+#endif /* IRRADIANCE_LIB */
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
new file mode 100644
index 00000000000..3808b59761f
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl
@@ -0,0 +1,14 @@
+
+uniform sampler2DArray probePlanars;
+
+in vec3 worldPosition;
+flat in int probeIdx;
+
+out vec4 FragColor;
+
+void main()
+{
+ vec4 refco = ViewProjectionMatrix * vec4(worldPosition, 1.0);
+ refco.xy /= refco.w;
+ FragColor = vec4(textureLod(probePlanars, vec3(refco.xy * 0.5 + 0.5, float(probeIdx)), 0.0).rgb, 1.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
new file mode 100644
index 00000000000..a71a3bef1e1
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl
@@ -0,0 +1,15 @@
+
+in vec3 pos;
+
+in int probe_id;
+in mat4 probe_mat;
+
+out vec3 worldPosition;
+flat out int probeIdx;
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * probe_mat * vec4(pos, 1.0);
+ worldPosition = (probe_mat * vec4(pos, 1.0)).xyz;
+ probeIdx = probe_id;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
new file mode 100644
index 00000000000..d629195b815
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
@@ -0,0 +1,40 @@
+/**
+ * Simple downsample shader. Takes the average of the 4 texels of lower mip.
+ **/
+
+uniform sampler2DArray source;
+uniform float fireflyFactor;
+
+in vec2 uvs;
+flat in float layer;
+
+out vec4 FragColor;
+
+float brightness(vec3 c)
+{
+ return max(max(c.r, c.g), c.b);
+}
+
+void main()
+{
+#if 0
+ /* Reconstructing Target uvs like this avoid missing pixels if NPO2 */
+ vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0));
+
+ FragColor = textureLod(source, vec3(uvs, layer), 0.0);
+#else
+ vec2 texel_size = 1.0 / vec2(textureSize(source, 0));
+ vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size;
+ vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75);
+
+ FragColor = textureLod(source, vec3(uvs + ofs.xy, layer), 0.0);
+ FragColor += textureLod(source, vec3(uvs + ofs.xw, layer), 0.0);
+ FragColor += textureLod(source, vec3(uvs + ofs.zy, layer), 0.0);
+ FragColor += textureLod(source, vec3(uvs + ofs.zw, layer), 0.0);
+ FragColor *= 0.25;
+
+ /* Clamped brightness. */
+ float luma = max(1e-8, brightness(FragColor.rgb));
+ FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl
new file mode 100644
index 00000000000..721cc8789a0
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl
@@ -0,0 +1,24 @@
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+in int instance[];
+in vec2 vPos[];
+
+flat out float layer;
+
+void main() {
+ gl_Layer = instance[0];
+ layer = float(instance[0]);
+
+ gl_Position = vec4(vPos[0], 0.0, 1.0);
+ EmitVertex();
+
+ gl_Position = vec4(vPos[1], 0.0, 1.0);
+ EmitVertex();
+
+ gl_Position = vec4(vPos[2], 0.0, 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl
new file mode 100644
index 00000000000..d682e39d8ad
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl
@@ -0,0 +1,10 @@
+
+in vec2 pos;
+
+out int instance;
+out vec2 vPos;
+
+void main() {
+ instance = gl_InstanceID;
+ vPos = pos;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_vert.glsl
new file mode 100644
index 00000000000..bbb77af673a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_vert.glsl
@@ -0,0 +1,10 @@
+
+in vec3 pos;
+
+out vec4 vPos;
+flat out int face;
+
+void main() {
+ vPos = vec4(pos, 1.0);
+ face = gl_InstanceID;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
new file mode 100644
index 00000000000..5631957ca31
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -0,0 +1,523 @@
+
+#ifndef LIT_SURFACE_UNIFORM
+#define LIT_SURFACE_UNIFORM
+
+uniform float refractionDepth;
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
+uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
+
+in vec3 worldPosition;
+in vec3 viewPosition;
+
+#ifdef USE_FLAT_NORMAL
+flat in vec3 worldNormal;
+flat in vec3 viewNormal;
+#else
+in vec3 worldNormal;
+in vec3 viewNormal;
+#endif
+
+#ifdef HAIR_SHADER
+in vec3 hairTangent; /* world space */
+in float hairThickTime;
+in float hairThickness;
+in float hairTime;
+flat in int hairStrandID;
+
+uniform int hairThicknessRes = 1;
+#endif
+
+#endif /* LIT_SURFACE_UNIFORM */
+
+/** AUTO CONFIG
+ * We include the file multiple times each time with a different configuration.
+ * This leads to a lot of deadcode. Better idea would be to only generate the one needed.
+ */
+#if !defined(SURFACE_DEFAULT)
+ #define SURFACE_DEFAULT
+ #define CLOSURE_NAME eevee_closure_default
+ #define CLOSURE_DIFFUSE
+ #define CLOSURE_GLOSSY
+#endif /* SURFACE_DEFAULT */
+
+#if !defined(SURFACE_PRINCIPLED) && !defined(CLOSURE_NAME)
+ #define SURFACE_PRINCIPLED
+ #define CLOSURE_NAME eevee_closure_principled
+ #define CLOSURE_DIFFUSE
+ #define CLOSURE_GLOSSY
+ #define CLOSURE_CLEARCOAT
+ #define CLOSURE_REFRACTION
+ #define CLOSURE_SUBSURFACE
+#endif /* SURFACE_PRINCIPLED */
+
+#if !defined(SURFACE_CLEARCOAT) && !defined(CLOSURE_NAME)
+ #define SURFACE_CLEARCOAT
+ #define CLOSURE_NAME eevee_closure_clearcoat
+ #define CLOSURE_GLOSSY
+ #define CLOSURE_CLEARCOAT
+#endif /* SURFACE_CLEARCOAT */
+
+#if !defined(SURFACE_DIFFUSE) && !defined(CLOSURE_NAME)
+ #define SURFACE_DIFFUSE
+ #define CLOSURE_NAME eevee_closure_diffuse
+ #define CLOSURE_DIFFUSE
+#endif /* SURFACE_DIFFUSE */
+
+#if !defined(SURFACE_SUBSURFACE) && !defined(CLOSURE_NAME)
+ #define SURFACE_SUBSURFACE
+ #define CLOSURE_NAME eevee_closure_subsurface
+ #define CLOSURE_DIFFUSE
+ #define CLOSURE_SUBSURFACE
+#endif /* SURFACE_SUBSURFACE */
+
+#if !defined(SURFACE_SKIN) && !defined(CLOSURE_NAME)
+ #define SURFACE_SKIN
+ #define CLOSURE_NAME eevee_closure_skin
+ #define CLOSURE_DIFFUSE
+ #define CLOSURE_SUBSURFACE
+ #define CLOSURE_GLOSSY
+#endif /* SURFACE_SKIN */
+
+#if !defined(SURFACE_GLOSSY) && !defined(CLOSURE_NAME)
+ #define SURFACE_GLOSSY
+ #define CLOSURE_NAME eevee_closure_glossy
+ #define CLOSURE_GLOSSY
+#endif /* SURFACE_GLOSSY */
+
+#if !defined(SURFACE_REFRACT) && !defined(CLOSURE_NAME)
+ #define SURFACE_REFRACT
+ #define CLOSURE_NAME eevee_closure_refraction
+ #define CLOSURE_REFRACTION
+#endif /* SURFACE_REFRACT */
+
+#if !defined(SURFACE_GLASS) && !defined(CLOSURE_NAME)
+ #define SURFACE_GLASS
+ #define CLOSURE_NAME eevee_closure_glass
+ #define CLOSURE_GLOSSY
+ #define CLOSURE_REFRACTION
+#endif /* SURFACE_GLASS */
+
+/* Safety : CLOSURE_CLEARCOAT implies CLOSURE_GLOSSY */
+#ifdef CLOSURE_CLEARCOAT
+ #ifndef CLOSURE_GLOSSY
+ #define CLOSURE_GLOSSY
+ #endif
+#endif /* CLOSURE_CLEARCOAT */
+
+void CLOSURE_NAME(
+ vec3 N
+#ifdef CLOSURE_DIFFUSE
+ , vec3 albedo
+#endif
+#ifdef CLOSURE_GLOSSY
+ , vec3 f0, int ssr_id
+#endif
+#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
+ , float roughness
+#endif
+#ifdef CLOSURE_CLEARCOAT
+ , vec3 C_N, float C_intensity, float C_roughness
+#endif
+#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
+ , float ao
+#endif
+#ifdef CLOSURE_SUBSURFACE
+ , float sss_scale
+#endif
+#ifdef CLOSURE_REFRACTION
+ , float ior
+#endif
+#ifdef CLOSURE_DIFFUSE
+ , out vec3 out_diff
+#endif
+#ifdef CLOSURE_SUBSURFACE
+ , out vec3 out_trans
+#endif
+#ifdef CLOSURE_GLOSSY
+ , out vec3 out_spec
+#endif
+#ifdef CLOSURE_REFRACTION
+ , out vec3 out_refr
+#endif
+#ifdef CLOSURE_GLOSSY
+ , out vec3 ssr_spec
+#endif
+ )
+{
+#ifdef CLOSURE_DIFFUSE
+ out_diff = vec3(0.0);
+#endif
+
+#ifdef CLOSURE_SUBSURFACE
+ out_trans = vec3(0.0);
+#endif
+
+#ifdef CLOSURE_GLOSSY
+ out_spec = vec3(0.0);
+#endif
+
+#ifdef CLOSURE_REFRACTION
+ out_refr = vec3(0.0);
+#endif
+
+ /* Zero length vectors cause issues, see: T51979. */
+ float len = length(N);
+ if (isnan(len)) {
+ return;
+ }
+ N /= len;
+
+#ifdef CLOSURE_CLEARCOAT
+ len = length(C_N);
+ if (isnan(len)) {
+ return;
+ }
+ C_N /= len;
+#endif
+
+#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
+ roughness = clamp(roughness, 1e-8, 0.9999);
+ float roughnessSquared = roughness * roughness;
+#endif
+
+#ifdef CLOSURE_CLEARCOAT
+ C_roughness = clamp(C_roughness, 1e-8, 0.9999);
+ float C_roughnessSquared = C_roughness * C_roughness;
+#endif
+
+ vec3 V = cameraVec;
+
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+
+ /* ---------------------------------------------------------------- */
+ /* -------------------- SCENE LAMPS LIGHTING ---------------------- */
+ /* ---------------------------------------------------------------- */
+
+#ifdef CLOSURE_GLOSSY
+ vec2 lut_uv = lut_coords(dot(N, V), roughness);
+ vec4 ltc_mat = texture(utilTex, vec3(lut_uv, 0.0)).rgba;
+#endif
+
+#ifdef CLOSURE_CLEARCOAT
+ vec2 lut_uv_clear = lut_coords(dot(C_N, V), C_roughness);
+ vec4 ltc_mat_clear = texture(utilTex, vec3(lut_uv_clear, 0.0)).rgba;
+ vec3 out_spec_clear = vec3(0.0);
+#endif
+
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
+ LightData ld = lights_data[i];
+
+ vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
+ l_vector.xyz = ld.l_position - worldPosition;
+ l_vector.w = length(l_vector.xyz);
+
+ float l_vis = light_visibility(ld, worldPosition, viewPosition, viewNormal, l_vector);
+
+ if (l_vis < 1e-8)
+ continue;
+
+ vec3 l_color_vis = ld.l_color * l_vis;
+
+ #ifdef CLOSURE_DIFFUSE
+ out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector);
+ #endif
+
+ #ifdef CLOSURE_SUBSURFACE
+ out_trans += ld.l_color * light_translucent(ld, worldPosition, -N, l_vector, sss_scale);
+ #endif
+
+ #ifdef CLOSURE_GLOSSY
+ out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec;
+ #endif
+
+ #ifdef CLOSURE_CLEARCOAT
+ out_spec_clear += l_color_vis * light_specular(ld, ltc_mat_clear, C_N, V, l_vector) * ld.l_spec;
+ #endif
+ }
+
+#ifdef CLOSURE_GLOSSY
+ vec3 brdf_lut_lamps = texture(utilTex, vec3(lut_uv, 1.0)).rgb;
+ out_spec *= F_area(f0, brdf_lut_lamps.xy) * brdf_lut_lamps.z;
+#endif
+
+#ifdef CLOSURE_CLEARCOAT
+ vec3 brdf_lut_lamps_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).rgb;
+ out_spec_clear *= F_area(vec3(0.04), brdf_lut_lamps_clear.xy) * brdf_lut_lamps_clear.z;
+ out_spec += out_spec_clear * C_intensity;
+#endif
+
+ /* ---------------------------------------------------------------- */
+ /* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */
+ /* ---------------------------------------------------------------- */
+
+ /* Accumulate incoming light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
+#ifdef CLOSURE_GLOSSY
+ vec4 spec_accum = vec4(0.0);
+#endif
+
+#ifdef CLOSURE_CLEARCOAT
+ vec4 C_spec_accum = vec4(0.0);
+#endif
+
+#ifdef CLOSURE_REFRACTION
+ vec4 refr_accum = vec4(0.0);
+#endif
+
+#ifdef CLOSURE_GLOSSY
+ /* ---------------------------- */
+ /* Planar Reflections */
+ /* ---------------------------- */
+
+ for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; ++i) {
+ PlanarData pd = planars_data[i];
+
+ /* Fade on geometric normal. */
+ float fade = probe_attenuation_planar(pd, worldPosition, (gl_FrontFacing) ? worldNormal : -worldNormal, roughness);
+
+ if (fade > 0.0) {
+ if (!(ssrToggle && ssr_id == outputSsrId)) {
+ vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, roughness, fade);
+ accumulate_light(spec, fade, spec_accum);
+ }
+
+ #ifdef CLOSURE_CLEARCOAT
+ vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, C_roughness, fade);
+ accumulate_light(C_spec, fade, C_spec_accum);
+ #endif
+
+ }
+ }
+#endif
+
+
+#ifdef CLOSURE_GLOSSY
+ vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared);
+#endif
+
+#ifdef CLOSURE_CLEARCOAT
+ vec3 C_spec_dir = get_specular_reflection_dominant_dir(C_N, V, C_roughnessSquared);
+#endif
+
+#ifdef CLOSURE_REFRACTION
+ /* Refract the view vector using the depth heuristic.
+ * Then later Refract a second time the already refracted
+ * ray using the inverse ior. */
+ float final_ior = (refractionDepth > 0.0) ? 1.0 / ior : ior;
+ vec3 refr_V = (refractionDepth > 0.0) ? -refract(-V, N, final_ior) : V;
+ vec3 refr_pos = (refractionDepth > 0.0) ? line_plane_intersect(worldPosition, refr_V, worldPosition - N * refractionDepth, N) : worldPosition;
+ vec3 refr_dir = get_specular_refraction_dominant_dir(N, refr_V, roughness, final_ior);
+#endif
+
+
+#ifdef CLOSURE_REFRACTION
+ /* ---------------------------- */
+ /* Screen Space Refraction */
+ /* ---------------------------- */
+ #ifdef USE_REFRACTION
+ if (ssrToggle && roughness < ssrMaxRoughness + 0.2) {
+ /* Find approximated position of the 2nd refraction event. */
+ vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition;
+ vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand);
+ trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness);
+ accumulate_light(trans.rgb, trans.a, refr_accum);
+ }
+ #endif
+
+#endif
+
+
+ /* ---------------------------- */
+ /* Specular probes */
+ /* ---------------------------- */
+#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION)
+
+ #if defined(CLOSURE_GLOSSY) && defined(CLOSURE_REFRACTION)
+ #define GLASS_ACCUM 1
+ #define ACCUM min(refr_accum.a, spec_accum.a)
+ #elif defined(CLOSURE_REFRACTION)
+ #define GLASS_ACCUM 0
+ #define ACCUM refr_accum.a
+ #else
+ #define GLASS_ACCUM 0
+ #define ACCUM spec_accum.a
+ #endif
+
+ /* Starts at 1 because 0 is world probe */
+ for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; ++i) {
+ float fade = probe_attenuation_cube(i, worldPosition);
+
+ if (fade > 0.0) {
+
+ #if GLASS_ACCUM
+ if (spec_accum.a < 0.999) {
+ #endif
+ #ifdef CLOSURE_GLOSSY
+ if (!(ssrToggle && ssr_id == outputSsrId)) {
+ vec3 spec = probe_evaluate_cube(i, worldPosition, spec_dir, roughness);
+ accumulate_light(spec, fade, spec_accum);
+ }
+ #endif
+
+ #ifdef CLOSURE_CLEARCOAT
+ vec3 C_spec = probe_evaluate_cube(i, worldPosition, C_spec_dir, C_roughness);
+ accumulate_light(C_spec, fade, C_spec_accum);
+ #endif
+ #if GLASS_ACCUM
+ }
+ #endif
+
+ #if GLASS_ACCUM
+ if (refr_accum.a < 0.999) {
+ #endif
+ #ifdef CLOSURE_REFRACTION
+ vec3 trans = probe_evaluate_cube(i, refr_pos, refr_dir, roughnessSquared);
+ accumulate_light(trans, fade, refr_accum);
+ #endif
+ #if GLASS_ACCUM
+ }
+ #endif
+ }
+ }
+
+ #undef GLASS_ACCUM
+ #undef ACCUM
+
+ /* ---------------------------- */
+ /* World Probe */
+ /* ---------------------------- */
+ #ifdef CLOSURE_GLOSSY
+ if (spec_accum.a < 0.999) {
+ if (!(ssrToggle && ssr_id == outputSsrId)) {
+ vec3 spec = probe_evaluate_world_spec(spec_dir, roughness);
+ accumulate_light(spec, 1.0, spec_accum);
+ }
+
+ #ifdef CLOSURE_CLEARCOAT
+ vec3 C_spec = probe_evaluate_world_spec(C_spec_dir, C_roughness);
+ accumulate_light(C_spec, 1.0, C_spec_accum);
+ #endif
+
+ }
+ #endif
+
+ #ifdef CLOSURE_REFRACTION
+ if (refr_accum.a < 0.999) {
+ vec3 trans = probe_evaluate_world_spec(refr_dir, roughnessSquared);
+ accumulate_light(trans, 1.0, refr_accum);
+ }
+ #endif
+#endif /* Specular probes */
+
+
+ /* ---------------------------- */
+ /* Ambient Occlusion */
+ /* ---------------------------- */
+#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE)
+ vec3 bent_normal;
+ float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal);
+#endif
+
+
+ /* ---------------------------- */
+ /* Specular Output */
+ /* ---------------------------- */
+ float NV = dot(N, V);
+#ifdef CLOSURE_GLOSSY
+ vec2 uv = lut_coords(NV, roughness);
+ vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg;
+
+ /* This factor is outputted to be used by SSR in order
+ * to match the intensity of the regular reflections. */
+ ssr_spec = F_ibl(f0, brdf_lut);
+ float spec_occlu = specular_occlusion(NV, final_ao, roughness);
+
+ /* The SSR pass recompute the occlusion to not apply it to the SSR */
+ if (ssrToggle && ssr_id == outputSsrId) {
+ spec_occlu = 1.0;
+ }
+
+ out_spec += spec_accum.rgb * ssr_spec * spec_occlu;
+#endif
+
+#ifdef CLOSURE_REFRACTION
+ float btdf = get_btdf_lut(utilTex, NV, roughness, ior);
+
+ out_refr += refr_accum.rgb * btdf;
+#endif
+
+#ifdef CLOSURE_CLEARCOAT
+ NV = dot(C_N, V);
+ vec2 C_uv = lut_coords(NV, C_roughness);
+ vec2 C_brdf_lut = texture(utilTex, vec3(C_uv, 1.0)).rg;
+ vec3 C_fresnel = F_ibl(vec3(0.04), C_brdf_lut) * specular_occlusion(NV, final_ao, C_roughness);
+
+ out_spec += C_spec_accum.rgb * C_fresnel * C_intensity;
+#endif
+
+#ifdef CLOSURE_GLOSSY
+ /* Global toggle for lightprobe baking. */
+ out_spec *= float(specToggle);
+#endif
+
+ /* ---------------------------------------------------------------- */
+ /* ---------------- DIFFUSE ENVIRONMENT LIGHTING ------------------ */
+ /* ---------------------------------------------------------------- */
+
+ /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */
+#ifdef CLOSURE_DIFFUSE
+ vec4 diff_accum = vec4(0.0);
+
+ /* ---------------------------- */
+ /* Irradiance Grids */
+ /* ---------------------------- */
+ /* Start at 1 because 0 is world irradiance */
+ for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; ++i) {
+ GridData gd = grids_data[i];
+
+ vec3 localpos;
+ float fade = probe_attenuation_grid(gd, grids_data[i].localmat, worldPosition, localpos);
+
+ if (fade > 0.0) {
+ vec3 diff = probe_evaluate_grid(gd, worldPosition, bent_normal, localpos);
+ accumulate_light(diff, fade, diff_accum);
+ }
+ }
+
+ /* ---------------------------- */
+ /* World Diffuse */
+ /* ---------------------------- */
+ if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) {
+ vec3 diff = probe_evaluate_world_diff(bent_normal);
+ accumulate_light(diff, 1.0, diff_accum);
+ }
+
+ out_diff += diff_accum.rgb * gtao_multibounce(final_ao, albedo);
+#endif
+}
+
+/* Cleanup for next configuration */
+#undef CLOSURE_NAME
+
+#ifdef CLOSURE_DIFFUSE
+ #undef CLOSURE_DIFFUSE
+#endif
+
+#ifdef CLOSURE_GLOSSY
+ #undef CLOSURE_GLOSSY
+#endif
+
+#ifdef CLOSURE_CLEARCOAT
+ #undef CLOSURE_CLEARCOAT
+#endif
+
+#ifdef CLOSURE_REFRACTION
+ #undef CLOSURE_REFRACTION
+#endif
+
+#ifdef CLOSURE_SUBSURFACE
+ #undef CLOSURE_SUBSURFACE
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
new file mode 100644
index 00000000000..a6e6f1fac42
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
@@ -0,0 +1,79 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat3 WorldNormalMatrix;
+#ifndef ATTRIB
+uniform mat4 ModelMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 ModelMatrixInverse;
+#endif
+
+#ifndef HAIR_SHADER
+in vec3 pos;
+in vec3 nor;
+#endif
+
+out vec3 worldPosition;
+out vec3 viewPosition;
+
+/* Used for planar reflections */
+/* keep in sync with EEVEE_ClipPlanesUniformBuffer */
+layout(std140) uniform clip_block {
+ vec4 ClipPlanes[1];
+};
+
+#ifdef USE_FLAT_NORMAL
+flat out vec3 worldNormal;
+flat out vec3 viewNormal;
+#else
+out vec3 worldNormal;
+out vec3 viewNormal;
+#endif
+
+#ifdef HAIR_SHADER
+out vec3 hairTangent;
+out float hairThickTime;
+out float hairThickness;
+out float hairTime;
+flat out int hairStrandID;
+#endif
+
+void main()
+{
+#ifdef GPU_INTEL
+ /* Due to some shader compiler bug, we somewhat
+ * need to access gl_VertexID to make it work. even
+ * if it's actually dead code. */
+ gl_Position.x = float(gl_VertexID);
+#endif
+
+#ifdef HAIR_SHADER
+ hairStrandID = hair_get_strand_id();
+ vec3 pos, binor;
+ hair_get_pos_tan_binor_time(
+ (ProjectionMatrix[3][3] == 0.0),
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz,
+ pos, hairTangent, binor, hairTime, hairThickness, hairThickTime);
+
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+ viewPosition = (ViewMatrix * vec4(pos, 1.0)).xyz;
+ worldPosition = pos;
+ hairTangent = normalize(hairTangent);
+ worldNormal = cross(binor, hairTangent);
+ viewNormal = normalize(mat3(ViewMatrix) * worldNormal);
+#else
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
+ worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz;
+ worldNormal = normalize(WorldNormalMatrix * nor);
+ viewNormal = normalize(NormalMatrix * nor);
+#endif
+
+ /* Used for planar reflections */
+ gl_ClipDistance[0] = dot(vec4(worldPosition, 1.0), ClipPlanes[0]);
+
+#ifdef ATTRIB
+ pass_attrib(pos);
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
new file mode 100644
index 00000000000..11c223a45d6
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
@@ -0,0 +1,321 @@
+/**
+ * Adapted from :
+ * Real-Time Polygonal-Light Shading with Linearly Transformed Cosines.
+ * Eric Heitz, Jonathan Dupuy, Stephen Hill and David Neubelt.
+ * ACM Transactions on Graphics (Proceedings of ACM SIGGRAPH 2016) 35(4), 2016.
+ * Project page: https://eheitzresearch.wordpress.com/415-2/
+ **/
+
+#define USE_LTC
+
+#ifndef UTIL_TEX
+#define UTIL_TEX
+uniform sampler2DArray utilTex;
+#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0)
+#endif /* UTIL_TEX */
+
+/* Diffuse *clipped* sphere integral. */
+float diffuse_sphere_integral_lut(float avg_dir_z, float form_factor)
+{
+ vec2 uv = vec2(avg_dir_z * 0.5 + 0.5, form_factor);
+ uv = uv * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
+
+ return texture(utilTex, vec3(uv, 1.0)).w;
+}
+
+float diffuse_sphere_integral_cheap(float avg_dir_z, float form_factor)
+{
+ return max((form_factor * form_factor + avg_dir_z) / (form_factor + 1.0), 0.0);
+}
+
+/**
+ * An extended version of the implementation from
+ * "How to solve a cubic equation, revisited"
+ * http://momentsingraphics.de/?p=105
+ **/
+vec3 solve_cubic(vec4 coefs)
+{
+ /* Normalize the polynomial */
+ coefs.xyz /= coefs.w;
+ /* Divide middle coefficients by three */
+ coefs.yz /= 3.0;
+
+ float A = coefs.w;
+ float B = coefs.z;
+ float C = coefs.y;
+ float D = coefs.x;
+
+ /* Compute the Hessian and the discriminant */
+ vec3 delta = vec3(
+ -coefs.z*coefs.z + coefs.y,
+ -coefs.y*coefs.z + coefs.x,
+ dot(vec2(coefs.z, -coefs.y), coefs.xy)
+ );
+
+ /* Discriminant */
+ float discr = dot(vec2(4.0 * delta.x, -delta.y), delta.zy);
+
+ vec2 xlc, xsc;
+
+ /* Algorithm A */
+ {
+ float A_a = 1.0;
+ float C_a = delta.x;
+ float D_a = -2.0 * B * delta.x + delta.y;
+
+ /* Take the cubic root of a normalized complex number */
+ float theta = atan(sqrt(discr), -D_a) / 3.0;
+
+ float x_1a = 2.0 * sqrt(-C_a) * cos(theta);
+ float x_3a = 2.0 * sqrt(-C_a) * cos(theta + (2.0 / 3.0) * M_PI);
+
+ float xl;
+ if ((x_1a + x_3a) > 2.0 * B) {
+ xl = x_1a;
+ }
+ else {
+ xl = x_3a;
+ }
+
+ xlc = vec2(xl - B, A);
+ }
+
+ /* Algorithm D */
+ {
+ float A_d = D;
+ float C_d = delta.z;
+ float D_d = -D * delta.y + 2.0 * C * delta.z;
+
+ /* Take the cubic root of a normalized complex number */
+ float theta = atan(D * sqrt(discr), -D_d) / 3.0;
+
+ float x_1d = 2.0 * sqrt(-C_d) * cos(theta);
+ float x_3d = 2.0 * sqrt(-C_d) * cos(theta + (2.0 / 3.0) * M_PI);
+
+ float xs;
+ if (x_1d + x_3d < 2.0 * C)
+ xs = x_1d;
+ else
+ xs = x_3d;
+
+ xsc = vec2(-D, xs + C);
+ }
+
+ float E = xlc.y * xsc.y;
+ float F = -xlc.x * xsc.y - xlc.y * xsc.x;
+ float G = xlc.x * xsc.x;
+
+ vec2 xmc = vec2(C * F - B * G, -B * F + C * E);
+
+ vec3 root = vec3(xsc.x / xsc.y,
+ xmc.x / xmc.y,
+ xlc.x / xlc.y);
+
+ if (root.x < root.y && root.x < root.z) {
+ root.xyz = root.yxz;
+ }
+ else if (root.z < root.x && root.z < root.y) {
+ root.xyz = root.xzy;
+ }
+
+ return root;
+}
+
+/* from Real-Time Area Lighting: a Journey from Research to Production
+ * Stephen Hill and Eric Heitz */
+vec3 edge_integral_vec(vec3 v1, vec3 v2)
+{
+ float x = dot(v1, v2);
+ float y = abs(x);
+
+ float a = 0.8543985 + (0.4965155 + 0.0145206 * y) * y;
+ float b = 3.4175940 + (4.1616724 + y) * y;
+ float v = a / b;
+
+ float theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt(max(1.0 - x * x, 1e-7)) - v;
+
+ return cross(v1, v2) * theta_sintheta;
+}
+
+mat3 ltc_matrix(vec4 lut)
+{
+ /* load inverse matrix */
+ mat3 Minv = mat3(
+ vec3( 1, 0, lut.y),
+ vec3( 0, lut.z, 0),
+ vec3(lut.w, 0, lut.x)
+ );
+
+ return Minv;
+}
+
+void ltc_transform_quad(vec3 N, vec3 V, mat3 Minv, inout vec3 corners[4])
+{
+ /* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */
+ V = normalize(V + 1e-8);
+
+ /* construct orthonormal basis around N */
+ vec3 T1, T2;
+ T1 = normalize(V - N * dot(N, V));
+ T2 = cross(N, T1);
+
+ /* rotate area light in (T1, T2, R) basis */
+ Minv = Minv * transpose(mat3(T1, T2, N));
+
+ /* Apply LTC inverse matrix. */
+ corners[0] = normalize(Minv * corners[0]);
+ corners[1] = normalize(Minv * corners[1]);
+ corners[2] = normalize(Minv * corners[2]);
+ corners[3] = normalize(Minv * corners[3]);
+}
+
+/* If corners have already pass through ltc_transform_quad(), then N **MUST** be vec3(0.0, 0.0, 1.0),
+ * corresponding to the Up axis of the shading basis. */
+float ltc_evaluate_quad(vec3 corners[4], vec3 N)
+{
+ /* Approximation using a sphere of the same solid angle than the quad.
+ * Finding the clipped sphere diffuse integral is easier than clipping the quad. */
+ vec3 avg_dir;
+ avg_dir = edge_integral_vec(corners[0], corners[1]);
+ avg_dir += edge_integral_vec(corners[1], corners[2]);
+ avg_dir += edge_integral_vec(corners[2], corners[3]);
+ avg_dir += edge_integral_vec(corners[3], corners[0]);
+
+ float form_factor = length(avg_dir);
+ float avg_dir_z = dot(N, avg_dir / form_factor);
+
+#if 1 /* use tabulated horizon-clipped sphere */
+ return form_factor * diffuse_sphere_integral_lut(avg_dir_z, form_factor);
+#else /* Less accurate version, a bit cheaper. */
+ return form_factor * diffuse_sphere_integral_cheap(avg_dir_z, form_factor);
+#endif
+}
+
+/* If disk does not need to be transformed and is already front facing. */
+float ltc_evaluate_disk_simple(float disk_radius, float NL)
+{
+ float r_sqr = disk_radius * disk_radius;
+ float one_r_sqr = 1.0 + r_sqr;
+ float form_factor = r_sqr * inversesqrt(one_r_sqr * one_r_sqr);
+
+#if 1 /* use tabulated horizon-clipped sphere */
+ return form_factor * diffuse_sphere_integral_lut(NL, form_factor);
+#else /* Less accurate version, a bit cheaper. */
+ return form_factor * diffuse_sphere_integral_cheap(NL, form_factor);
+#endif
+}
+
+/* disk_points are WS vectors from the shading point to the disk "bounding domain" */
+float ltc_evaluate_disk(vec3 N, vec3 V, mat3 Minv, vec3 disk_points[3])
+{
+ /* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */
+ V = normalize(V + 1e-8);
+
+ /* construct orthonormal basis around N */
+ vec3 T1, T2;
+ T1 = normalize(V - N * dot(V, N));
+ T2 = cross(N, T1);
+
+ /* rotate area light in (T1, T2, R) basis */
+ mat3 R = transpose(mat3(T1, T2, N));
+
+ /* Intermediate step: init ellipse. */
+ vec3 L_[3];
+ L_[0] = mul(R, disk_points[0]);
+ L_[1] = mul(R, disk_points[1]);
+ L_[2] = mul(R, disk_points[2]);
+
+ vec3 C = 0.5 * (L_[0] + L_[2]);
+ vec3 V1 = 0.5 * (L_[1] - L_[2]);
+ vec3 V2 = 0.5 * (L_[1] - L_[0]);
+
+ /* Transform ellipse by Minv. */
+ C = Minv * C;
+ V1 = Minv * V1;
+ V2 = Minv * V2;
+
+ /* Compute eigenvectors of new ellipse. */
+
+ float d11 = dot(V1, V1);
+ float d22 = dot(V2, V2);
+ float d12 = dot(V1, V2);
+ float a, b; /* Eigenvalues */
+ const float threshold = 0.0007; /* Can be adjusted. Fix artifacts. */
+ if (abs(d12) / sqrt(d11 * d22) > threshold) {
+ float tr = d11 + d22;
+ float det = -d12 * d12 + d11 * d22;
+
+ /* use sqrt matrix to solve for eigenvalues */
+ det = sqrt(det);
+ float u = 0.5 * sqrt(tr - 2.0 * det);
+ float v = 0.5 * sqrt(tr + 2.0 * det);
+ float e_max = (u + v);
+ float e_min = (u - v);
+ e_max *= e_max;
+ e_min *= e_min;
+
+ vec3 V1_, V2_;
+ if (d11 > d22) {
+ V1_ = d12 * V1 + (e_max - d11) * V2;
+ V2_ = d12 * V1 + (e_min - d11) * V2;
+ }
+ else {
+ V1_ = d12 * V2 + (e_max - d22) * V1;
+ V2_ = d12 * V2 + (e_min - d22) * V1;
+ }
+
+ a = 1.0 / e_max;
+ b = 1.0 / e_min;
+ V1 = normalize(V1_);
+ V2 = normalize(V2_);
+ }
+ else {
+ a = 1.0 / d11;
+ b = 1.0 / d22;
+ V1 *= sqrt(a);
+ V2 *= sqrt(b);
+ }
+
+ /* Now find front facing ellipse with same solid angle. */
+
+ vec3 V3 = normalize(cross(V1, V2));
+ if (dot(C, V3) < 0.0)
+ V3 *= -1.0;
+
+ float L = dot(V3, C);
+ float x0 = dot(V1, C) / L;
+ float y0 = dot(V2, C) / L;
+
+ a *= L*L;
+ b *= L*L;
+
+ float c0 = a * b;
+ float c1 = a * b * (1.0 + x0 * x0 + y0 * y0) - a - b;
+ float c2 = 1.0 - a * (1.0 + x0 * x0) - b * (1.0 + y0 * y0);
+ float c3 = 1.0;
+
+ vec3 roots = solve_cubic(vec4(c0, c1, c2, c3));
+ float e1 = roots.x;
+ float e2 = roots.y;
+ float e3 = roots.z;
+
+ vec3 avg_dir = vec3(a * x0 / (a - e2), b * y0 / (b - e2), 1.0);
+
+ mat3 rotate = mat3(V1, V2, V3);
+
+ avg_dir = rotate * avg_dir;
+ avg_dir = normalize(avg_dir);
+
+ /* L1, L2 are the extends of the front facing ellipse. */
+ float L1 = sqrt(-e2/e3);
+ float L2 = sqrt(-e2/e1);
+
+ /* Find the sphere and compute lighting. */
+ float form_factor = max(0.0, L1 * L2 * inversesqrt((1.0 + L1 * L1) * (1.0 + L2 * L2)));
+
+#if 1 /* use tabulated horizon-clipped sphere */
+ return form_factor * diffuse_sphere_integral_lut(avg_dir.z, form_factor);
+#else /* Less accurate version, a bit cheaper. */
+ return form_factor * diffuse_sphere_integral_cheap(avg_dir.z, form_factor);
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl
new file mode 100644
index 00000000000..ec13c885bbb
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl
@@ -0,0 +1,37 @@
+
+vec2 mapping_octahedron(vec3 cubevec, vec2 texel_size)
+{
+ /* projection onto octahedron */
+ cubevec /= dot( vec3(1), abs(cubevec) );
+
+ /* out-folding of the downward faces */
+ if ( cubevec.z < 0.0 ) {
+ cubevec.xy = (1.0 - abs(cubevec.yx)) * sign(cubevec.xy);
+ }
+
+ /* mapping to [0;1]ˆ2 texture space */
+ vec2 uvs = cubevec.xy * (0.5) + 0.5;
+
+ /* edge filtering fix */
+ uvs = (1.0 - 2.0 * texel_size) * uvs + texel_size;
+
+ return uvs;
+}
+
+vec4 textureLod_octahedron(sampler2DArray tex, vec4 cubevec, float lod, float lod_max)
+{
+ vec2 texelSize = 1.0 / vec2(textureSize(tex, int(lod_max)));
+
+ vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize);
+
+ return textureLod(tex, vec3(uvs, cubevec.w), lod);
+}
+
+vec4 texture_octahedron(sampler2DArray tex, vec4 cubevec)
+{
+ vec2 texelSize = 1.0 / vec2(textureSize(tex, 0));
+
+ vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize);
+
+ return texture(tex, vec3(uvs, cubevec.w));
+}
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
new file mode 100644
index 00000000000..6b6ab0c0bcc
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -0,0 +1,86 @@
+
+#ifdef USE_ALPHA_HASH
+
+/* From the paper "Hashed Alpha Testing" by Chris Wyman and Morgan McGuire */
+float hash(vec2 a) {
+ return fract(1e4 * sin(17.0 * a.x + 0.1 * a.y) * (0.1 + abs(sin(13.0 * a.y + a.x))));
+}
+
+float hash3d(vec3 a) {
+ return hash(vec2(hash(a.xy), a.z));
+}
+
+uniform float hashAlphaOffset;
+uniform float hashAlphaScale = 1.0; /* Roughly in pixel */
+
+float hashed_alpha_threshold(vec3 co)
+{
+ /* Find the discretized derivatives of our coordinates. */
+ float max_deriv = max(length(dFdx(co)), length(dFdy(co)));
+ float pix_scale = 1.0 / (hashAlphaScale * max_deriv);
+
+ /* Find two nearest log-discretized noise scales. */
+ float pix_scale_log = log2(pix_scale);
+ vec2 pix_scales;
+ pix_scales.x = exp2(floor(pix_scale_log));
+ pix_scales.y = exp2(ceil(pix_scale_log));
+
+ /* Compute alpha thresholds at our two noise scales. */
+ vec2 alpha;
+ alpha.x = hash3d(floor(pix_scales.x * co));
+ alpha.y = hash3d(floor(pix_scales.y * co));
+
+ /* Factor to interpolate lerp with. */
+ float fac = fract(log2(pix_scale));
+
+ /* Interpolate alpha threshold from noise at two scales. */
+ float x = mix(alpha.x, alpha.y, fac);
+
+ /* Pass into CDF to compute uniformly distrib threshold. */
+ float a = min(fac, 1.0 - fac);
+ float one_a = 1.0 - a;
+ float denom = 1.0 / (2 * a * one_a);
+ float one_x = (1 - x);
+ vec3 cases = vec3(
+ (x * x) * denom,
+ (x - 0.5 * a) / one_a,
+ 1.0 - (one_x * one_x * denom)
+ );
+
+ /* Find our final, uniformly distributed alpha threshold. */
+ float threshold = (x < one_a) ? ((x < a) ? cases.x : cases.y) : cases.z;
+
+ /* Avoids threshold == 0. */
+ threshold = clamp(threshold, 1.0e-6, 1.0);
+
+ /* Jitter the threshold for TAA accumulation. */
+ return fract(threshold + hashAlphaOffset);
+}
+
+#endif
+
+#ifdef USE_ALPHA_CLIP
+uniform float alphaThreshold;
+#endif
+
+void main()
+{
+ /* For now do nothing.
+ * In the future, output object motion blur. */
+
+#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP)
+#define NODETREE_EXEC
+
+ Closure cl = nodetree_exec();
+
+#if defined(USE_ALPHA_HASH)
+ /* Hashed Alpha Testing */
+ if (cl.opacity < hashed_alpha_threshold(worldPosition))
+ discard;
+#elif defined(USE_ALPHA_CLIP)
+ /* Alpha clip */
+ if (cl.opacity <= alphaThreshold)
+ discard;
+#endif
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
new file mode 100644
index 00000000000..1a8dbc97317
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
@@ -0,0 +1,39 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelMatrix;
+uniform mat4 ModelMatrixInverse;
+
+#ifdef CLIP_PLANES
+/* keep in sync with DRWManager.view_data */
+layout(std140) uniform clip_block {
+ vec4 ClipPlanes[1];
+};
+#endif
+
+#ifndef HAIR_SHADER
+in vec3 pos;
+#endif
+
+void main()
+{
+#ifdef HAIR_SHADER
+ float time, thick_time, thickness;
+ vec3 pos, tan, binor;
+ hair_get_pos_tan_binor_time(
+ (ProjectionMatrix[3][3] == 0.0),
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz,
+ pos, tan, binor, time, thickness, thick_time);
+
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+ vec4 worldPosition = vec4(pos, 1.0);
+#else
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ vec4 worldPosition = (ModelMatrix * vec4(pos, 1.0));
+#endif
+
+#ifdef CLIP_PLANES
+ gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), ClipPlanes[0]);
+#endif
+ /* TODO motion vectors */
+}
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
new file mode 100644
index 00000000000..c9f2d64f30b
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -0,0 +1,237 @@
+#define MAX_STEP 256
+
+float sample_depth(vec2 uv, int index, float lod)
+{
+#ifdef PLANAR_PROBE_RAYTRACE
+ if (index > -1) {
+ return textureLod(planarDepth, vec3(uv, index), 0.0).r;
+ }
+ else {
+#endif
+ /* Correct UVs for mipmaping mis-alignment */
+ uv *= mipRatio[int(lod) + hizMipOffset];
+ return textureLod(maxzBuffer, uv, lod).r;
+#ifdef PLANAR_PROBE_RAYTRACE
+ }
+#endif
+}
+
+vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod)
+{
+ vec4 depths;
+#ifdef PLANAR_PROBE_RAYTRACE
+ if (index > -1) {
+ depths.x = textureLod(planarDepth, vec3(uv1.xy, index), 0.0).r;
+ depths.y = textureLod(planarDepth, vec3(uv1.zw, index), 0.0).r;
+ depths.z = textureLod(planarDepth, vec3(uv2.xy, index), 0.0).r;
+ depths.w = textureLod(planarDepth, vec3(uv2.zw, index), 0.0).r;
+ }
+ else {
+#endif
+ depths.x = textureLod(maxzBuffer, uv1.xy, lod).r;
+ depths.y = textureLod(maxzBuffer, uv1.zw, lod).r;
+ depths.z = textureLod(maxzBuffer, uv2.xy, lod).r;
+ depths.w = textureLod(maxzBuffer, uv2.zw, lod).r;
+#ifdef PLANAR_PROBE_RAYTRACE
+ }
+#endif
+ return depths;
+}
+
+float refine_isect(float prev_delta, float curr_delta)
+{
+ /**
+ * Simplification of 2D intersection :
+ * r0 = (0.0, prev_ss_ray.z);
+ * r1 = (1.0, curr_ss_ray.z);
+ * d0 = (0.0, prev_hit_depth_sample);
+ * d1 = (1.0, curr_hit_depth_sample);
+ * vec2 r = r1 - r0;
+ * vec2 d = d1 - d0;
+ * vec2 isect = ((d * cross(r1, r0)) - (r * cross(d1, d0))) / cross(r,d);
+ *
+ * We only want isect.x to know how much stride we need. So it simplifies :
+ *
+ * isect_x = (cross(r1, r0) - cross(d1, d0)) / cross(r,d);
+ * isect_x = (prev_ss_ray.z - prev_hit_depth_sample.z) / cross(r,d);
+ */
+ return saturate(prev_delta / (prev_delta - curr_delta));
+}
+
+void prepare_raycast(
+ vec3 ray_origin, vec3 ray_dir, float thickness, out vec4 ss_step, out vec4 ss_ray, out float max_time)
+{
+ /* Negate the ray direction if it goes towards the camera.
+ * This way we don't need to care if the projected point
+ * is behind the near plane. */
+ float z_sign = -sign(ray_dir.z);
+ vec3 ray_end = ray_origin + z_sign * ray_dir;
+
+ /* Project into screen space. */
+ vec4 ss_start, ss_end;
+ ss_start.xyz = project_point(ProjectionMatrix, ray_origin);
+ ss_end.xyz = project_point(ProjectionMatrix, ray_end);
+
+ /* We interpolate the ray Z + thickness values to check if depth is within threshold. */
+ ray_origin.z -= thickness;
+ ray_end.z -= thickness;
+ ss_start.w = project_point(ProjectionMatrix, ray_origin).z;
+ ss_end.w = project_point(ProjectionMatrix, ray_end).z;
+
+ /* XXX This is a hack a better method is welcome ! */
+ /* We take the delta between the offseted depth and the depth and substract it from the ray depth.
+ * This will change the world space thickness appearance a bit but we can have negative
+ * values without worries. We cannot do this in viewspace because of the perspective division. */
+ ss_start.w = 2.0 * ss_start.z - ss_start.w;
+ ss_end.w = 2.0 * ss_end.z - ss_end.w;
+
+ ss_step = ss_end - ss_start;
+ max_time = length(ss_step.xyz);
+ ss_step = z_sign * ss_step / length(ss_step.xyz);
+
+ /* If the line is degenerate, make it cover at least one pixel
+ * to not have to handle zero-pixel extent as a special case later */
+ ss_step.xy += vec2((dot(ss_step.xy, ss_step.xy) < 0.000001) ? 0.001 : 0.0);
+
+ /* Make ss_step cover one pixel. */
+ ss_step /= max(abs(ss_step.x), abs(ss_step.y));
+ ss_step *= (abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y;
+
+ /* Clip to segment's end. */
+ max_time /= length(ss_step.xyz);
+
+ /* Clipping to frustum sides. */
+ max_time = min(max_time, line_unit_box_intersect_dist(ss_start.xyz, ss_step.xyz));
+
+ /* Convert to texture coords. Z component included
+ * since this is how it's stored in the depth buffer.
+ * 4th component how far we are on the ray */
+ ss_ray = ss_start * 0.5 + 0.5;
+ ss_step *= 0.5;
+
+ ss_ray.xy += 0.5 * ssrPixelSize * 2.0; /* take the center of the texel. * 2 because halfres. */
+}
+
+/* See times_and_deltas. */
+#define curr_time times_and_deltas.x
+#define prev_time times_and_deltas.y
+#define curr_delta times_and_deltas.z
+#define prev_delta times_and_deltas.w
+
+// #define GROUPED_FETCHES /* is still slower, need to see where is the bottleneck. */
+/* Return the hit position, and negate the z component (making it positive) if not hit occurred. */
+/* __ray_dir__ is the ray direction premultiplied by it's maximum length */
+vec3 raycast(
+ int index, vec3 ray_origin, vec3 ray_dir, float thickness, float ray_jitter,
+ float trace_quality, float roughness, const bool discard_backface)
+{
+ vec4 ss_step, ss_start;
+ float max_time;
+ prepare_raycast(ray_origin, ray_dir, thickness, ss_step, ss_start, max_time);
+
+ float max_trace_time = max(0.001, max_time - 0.01);
+
+#ifdef GROUPED_FETCHES
+ ray_jitter *= 0.25;
+#endif
+
+ /* x : current_time, y: previous_time, z: current_delta, w: previous_delta */
+ vec4 times_and_deltas = vec4(0.0);
+
+ float ray_time = 0.0;
+ float depth_sample = sample_depth(ss_start.xy, index, 0.0);
+ curr_delta = depth_sample - ss_start.z;
+
+ float lod_fac = saturate(fast_sqrt(roughness) * 2.0 - 0.4);
+ bool hit = false;
+ float iter;
+ for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) {
+ /* Minimum stride of 2 because we are using half res minmax zbuffer. */
+ float stride = max(1.0, iter * trace_quality) * 2.0;
+ float lod = log2(stride * 0.5 * trace_quality) * lod_fac;
+ ray_time += stride;
+
+ /* Save previous values. */
+ times_and_deltas.xyzw = times_and_deltas.yxwz;
+
+#ifdef GROUPED_FETCHES
+ stride *= 4.0;
+ vec4 jit_stride = mix(vec4(2.0), vec4(stride), vec4(0.0, 0.25, 0.5, 0.75) + ray_jitter);
+
+ vec4 times = min(vec4(ray_time) + jit_stride, vec4(max_trace_time));
+
+ vec4 uv1 = ss_start.xyxy + ss_step.xyxy * times.xxyy;
+ vec4 uv2 = ss_start.xyxy + ss_step.xyxy * times.zzww;
+
+ vec4 depth_samples = sample_depth_grouped(uv1, uv2, index, lod);
+
+ vec4 ray_z = ss_start.zzzz + ss_step.zzzz * times.xyzw;
+ vec4 ray_w = ss_start.wwww + ss_step.wwww * vec4(prev_time, times.xyz);
+
+ vec4 deltas = depth_samples - ray_z;
+ /* Same as component wise (curr_delta <= 0.0) && (prev_w <= depth_sample). */
+ bvec4 test = equal(step(deltas, vec4(0.0)) * step(ray_w, depth_samples), vec4(1.0));
+ hit = any(test);
+
+ if (hit) {
+ vec2 m = vec2(1.0, 0.0); /* Mask */
+
+ vec4 ret_times_and_deltas = times.wzzz * m.xxyy + deltas.wwwz * m.yyxx;
+ ret_times_and_deltas = (test.z) ? times.zyyy * m.xxyy + deltas.zzzy * m.yyxx : ret_times_and_deltas;
+ ret_times_and_deltas = (test.y) ? times.yxxx * m.xxyy + deltas.yyyx * m.yyxx : ret_times_and_deltas;
+ times_and_deltas = (test.x) ? times.xxxx * m.xyyy + deltas.xxxx * m.yyxy + times_and_deltas.yyww * m.yxyx : ret_times_and_deltas;
+
+ depth_sample = depth_samples.w;
+ depth_sample = (test.z) ? depth_samples.z : depth_sample;
+ depth_sample = (test.y) ? depth_samples.y : depth_sample;
+ depth_sample = (test.x) ? depth_samples.x : depth_sample;
+ }
+ else {
+ curr_time = times.w;
+ curr_delta = deltas.w;
+ }
+#else
+ float jit_stride = mix(2.0, stride, ray_jitter);
+
+ curr_time = min(ray_time + jit_stride, max_trace_time);
+ vec4 ss_ray = ss_start + ss_step * curr_time;
+
+ depth_sample = sample_depth(ss_ray.xy, index, lod);
+
+ float prev_w = ss_start.w + ss_step.w * prev_time;
+ curr_delta = depth_sample - ss_ray.z;
+ hit = (curr_delta <= 0.0) && (prev_w <= depth_sample);
+#endif
+ }
+
+ if (discard_backface) {
+ /* Discard backface hits */
+ hit = hit && (prev_delta > 0.0);
+ }
+
+ /* Reject hit if background. */
+ hit = hit && (depth_sample != 1.0);
+
+ curr_time = (hit) ? mix(prev_time, curr_time, refine_isect(prev_delta, curr_delta)) : curr_time;
+ ray_time = (hit) ? curr_time : ray_time;
+
+ /* Clip to frustum. */
+ ray_time = max(0.001, min(ray_time, max_time - 1.5));
+
+ vec4 ss_ray = ss_start + ss_step * ray_time;
+
+ /* Tag Z if ray failed. */
+ ss_ray.z *= (hit) ? 1.0 : -1.0;
+ return ss_ray.xyz;
+}
+
+float screen_border_mask(vec2 hit_co)
+{
+ const float margin = 0.003;
+ float atten = ssrBorderFac + margin; /* Screen percentage */
+ hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co));
+
+ float screenfade = hit_co.x * hit_co.y;
+
+ return screenfade;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl
new file mode 100644
index 00000000000..3ac214bfde2
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl
@@ -0,0 +1,196 @@
+/* Copy the depth only shadowmap into another texture while converting
+ * to linear depth (or other storage method) and doing a 3x3 box filter. */
+
+layout(std140) uniform shadow_render_block {
+ vec4 lampPosition;
+ float cubeTexelSize;
+ float storedTexelSize;
+ float nearClip;
+ float farClip;
+ int shadowSampleCount;
+ float shadowInvSampleCount;
+ float exponent;
+};
+
+#ifdef CSM
+uniform sampler2DArray shadowTexture;
+uniform int cascadeId;
+#else
+uniform samplerCube shadowTexture;
+uniform int faceId;
+#endif
+uniform float shadowFilterSize;
+
+out vec4 FragColor;
+
+#define linear_depth(z) ((nearClip * farClip) / (clamp(z, 0.0, 0.999999) * (nearClip - farClip) + farClip))
+
+/* add bias so background filtering does not bleed into shadow map */
+#define BACKGROUND_BIAS 0.05
+
+#ifdef CSM
+vec4 get_world_distance(vec4 depths, vec3 cos[4])
+{
+ depths += step(vec4(0.9999), depths) * BACKGROUND_BIAS;
+ return clamp(depths * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
+}
+
+float get_world_distance(float depth, vec3 cos)
+{
+ depth += step(0.9999, depth) * BACKGROUND_BIAS;
+ return clamp(depth * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
+}
+
+#else /* CUBEMAP */
+vec4 get_world_distance(vec4 depths, vec3 cos[4])
+{
+ depths = linear_depth(depths);
+ cos[0] = normalize(abs(cos[0]));
+ cos[1] = normalize(abs(cos[1]));
+ cos[2] = normalize(abs(cos[2]));
+ cos[3] = normalize(abs(cos[3]));
+ vec4 cos_vec;
+ cos_vec.x = max(cos[0].x, max(cos[0].y, cos[0].z));
+ cos_vec.y = max(cos[1].x, max(cos[1].y, cos[1].z));
+ cos_vec.z = max(cos[2].x, max(cos[2].y, cos[2].z));
+ cos_vec.w = max(cos[3].x, max(cos[3].y, cos[3].z));
+ return depths / cos_vec;
+}
+
+float get_world_distance(float depth, vec3 cos)
+{
+ depth = linear_depth(depth);
+ cos = normalize(abs(cos));
+ float cos_vec = max(cos.x, max(cos.y, cos.z));
+ return depth / cos_vec;
+}
+#endif
+
+/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
+#define ln_space_prefilter_step(ref, sample) exp(sample - ref)
+#define ln_space_prefilter_finalize(ref, sum) (ref + log(SAMPLE_WEIGHT * sum))
+
+#define SAMPLE_WEIGHT 0.11111
+
+#ifdef ESM
+void prefilter(vec4 depths, float ref, inout float accum)
+{
+ accum += dot(ln_space_prefilter_step(ref, depths), vec4(1.0));
+}
+#else /* VSM */
+void prefilter(vec4 depths, float ref, inout vec2 accum)
+{
+ vec4 depths_sqr = depths * depths;
+ accum += vec2(dot(vec4(1.0), depths), dot(vec4(1.0), depths_sqr)) * SAMPLE_WEIGHT;
+}
+#endif
+
+#ifdef CSM
+vec3 get_texco(vec2 uvs, vec2 ofs)
+{
+ return vec3(uvs + ofs, float(cascadeId));
+}
+#else /* CUBEMAP */
+const vec3 minorAxisX[6] = vec3[6](
+ vec3(0.0f, 0.0f, -1.0f),
+ vec3(0.0f, 0.0f, 1.0f),
+ vec3(1.0f, 0.0f, 0.0f),
+ vec3(1.0f, 0.0f, 0.0f),
+ vec3(1.0f, 0.0f, 0.0f),
+ vec3(-1.0f, 0.0f, 0.0f)
+);
+
+const vec3 minorAxisY[6] = vec3[6](
+ vec3(0.0f, -1.0f, 0.0f),
+ vec3(0.0f, -1.0f, 0.0f),
+ vec3(0.0f, 0.0f, 1.0f),
+ vec3(0.0f, 0.0f, -1.0f),
+ vec3(0.0f, -1.0f, 0.0f),
+ vec3(0.0f, -1.0f, 0.0f)
+);
+
+const vec3 majorAxis[6] = vec3[6](
+ vec3(1.0f, 0.0f, 0.0f),
+ vec3(-1.0f, 0.0f, 0.0f),
+ vec3(0.0f, 1.0f, 0.0f),
+ vec3(0.0f, -1.0f, 0.0f),
+ vec3(0.0f, 0.0f, 1.0f),
+ vec3(0.0f, 0.0f, -1.0f)
+);
+
+vec3 get_texco(vec2 uvs, vec2 ofs)
+{
+ uvs += ofs;
+ return majorAxis[faceId] + uvs.x * minorAxisX[faceId] + uvs.y * minorAxisY[faceId];
+}
+#endif
+
+void main() {
+ /* Copy the depth only shadowmap into another texture while converting
+ * to linear depth and do a 3x3 box blur. */
+
+#ifdef CSM
+ vec2 uvs = gl_FragCoord.xy * storedTexelSize;
+#else /* CUBEMAP */
+ vec2 uvs = gl_FragCoord.xy * cubeTexelSize * 2.0 - 1.0;
+#endif
+
+ /* Center texel */
+ vec3 co = get_texco(uvs, vec2(0.0));
+ float depth = texture(shadowTexture, co).r;
+ depth = get_world_distance(depth, co);
+
+ if (shadowFilterSize == 0.0) {
+#ifdef ESM
+ FragColor = vec4(depth);
+#else /* VSM */
+ FragColor = vec2(depth, depth * depth).xyxy;
+#endif
+ return;
+ }
+
+#ifdef ESM
+ float accum = 1.0;
+ float ref = depth;
+#else /* VSM */
+ float ref = 0.0; /* UNUSED */
+ vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT;
+#endif
+
+#ifdef CSM
+ vec3 ofs = vec3(1.0, 0.0, -1.0) * shadowFilterSize;
+#else /* CUBEMAP */
+ vec3 ofs = vec3(1.0, 0.0, -1.0) * shadowFilterSize;
+#endif
+
+ vec3 cos[4];
+ cos[0] = get_texco(uvs, ofs.zz);
+ cos[1] = get_texco(uvs, ofs.yz);
+ cos[2] = get_texco(uvs, ofs.xz);
+ cos[3] = get_texco(uvs, ofs.zy);
+
+ vec4 depths;
+ depths.x = texture(shadowTexture, cos[0]).r;
+ depths.y = texture(shadowTexture, cos[1]).r;
+ depths.z = texture(shadowTexture, cos[2]).r;
+ depths.w = texture(shadowTexture, cos[3]).r;
+ depths = get_world_distance(depths, cos);
+ prefilter(depths, ref, accum);
+
+ cos[0] = get_texco(uvs, ofs.xy);
+ cos[1] = get_texco(uvs, ofs.zx);
+ cos[2] = get_texco(uvs, ofs.yx);
+ cos[3] = get_texco(uvs, ofs.xx);
+ depths.x = texture(shadowTexture, cos[0]).r;
+ depths.y = texture(shadowTexture, cos[1]).r;
+ depths.z = texture(shadowTexture, cos[2]).r;
+ depths.w = texture(shadowTexture, cos[3]).r;
+ depths = get_world_distance(depths, cos);
+ prefilter(depths, ref, accum);
+
+#ifdef ESM
+ accum = ln_space_prefilter_finalize(ref, accum);
+#endif
+
+ FragColor = vec2(accum).xyxy;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_frag.glsl
new file mode 100644
index 00000000000..160fcee4c73
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_frag.glsl
@@ -0,0 +1,4 @@
+
+void main() {
+ /* Do nothing */
+}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
new file mode 100644
index 00000000000..cb7b2b0312a
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
@@ -0,0 +1,242 @@
+
+layout(std140) uniform shadow_render_block {
+ vec4 lampPosition;
+ float cubeTexelSize;
+ float storedTexelSize;
+ float nearClip;
+ float farClip;
+ int shadowSampleCount;
+ float shadowInvSampleCount;
+ float exponent;
+};
+
+#ifdef CSM
+uniform sampler2DArray shadowTexture;
+uniform int cascadeId;
+#else
+uniform samplerCube shadowTexture;
+#endif
+uniform float shadowFilterSize;
+
+out vec4 FragColor;
+
+vec3 octahedral_to_cubemap_proj(vec2 co)
+{
+ co = co * 2.0 - 1.0;
+
+ vec2 abs_co = abs(co);
+ vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
+
+ if ( abs_co.x + abs_co.y > 1.0 ) {
+ v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
+ }
+
+ return v;
+}
+
+/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
+/* http://advances.realtimerendering.com/s2009/SIGGRAPH%202009%20-%20Lighting%20Research%20at%20Bungie.pdf Slide 55*/
+#define ln_space_prefilter_step(ref, sample) exp(sample - ref)
+#define ln_space_prefilter_finalize(ref, sum) (ref + log(shadowInvSampleCount * sum))
+
+#ifdef CSM
+vec3 get_texco(vec3 cos, const vec2 ofs)
+{
+ cos.xy += ofs * shadowFilterSize;
+ return cos;
+}
+#else /* CUBEMAP */
+/* global vars */
+vec3 T = vec3(0.0);
+vec3 B = vec3(0.0);
+
+void make_orthonormal_basis(vec3 N)
+{
+ vec3 UpVector = (abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+ T = normalize(cross(UpVector, N));
+ B = cross(N, T);
+}
+
+vec3 get_texco(vec3 cos, const vec2 ofs)
+{
+ return cos + ofs.x * T + ofs.y * B;
+}
+
+#endif
+
+#ifdef ESM
+void grouped_samples_accum(
+ vec3 cos,
+ const vec2 co1, const vec2 co2, const vec2 co3, const vec2 co4,
+ float ref,
+ inout vec4 accum)
+{
+ vec4 depths;
+ depths.x = texture(shadowTexture, get_texco(cos, co1)).r;
+ depths.y = texture(shadowTexture, get_texco(cos, co2)).r;
+ depths.z = texture(shadowTexture, get_texco(cos, co3)).r;
+ depths.w = texture(shadowTexture, get_texco(cos, co4)).r;
+
+ accum += ln_space_prefilter_step(ref, depths);
+}
+#else /* VSM */
+void grouped_samples_accum(
+ vec3 cos,
+ const vec2 co1, const vec2 co2, const vec2 co3, const vec2 co4,
+ float ref,
+ inout vec2 accum)
+{
+ vec4 depths1, depths2;
+ depths1.xy = texture(shadowTexture, get_texco(cos, co1)).rg;
+ depths1.zw = texture(shadowTexture, get_texco(cos, co2)).rg;
+ depths2.xy = texture(shadowTexture, get_texco(cos, co3)).rg;
+ depths2.zw = texture(shadowTexture, get_texco(cos, co4)).rg;
+
+ accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw;
+}
+#endif
+
+void main() {
+ vec3 cos;
+
+ cos.xy = gl_FragCoord.xy * storedTexelSize;
+
+#ifdef CSM
+ cos.z = float(cascadeId);
+#else /* CUBEMAP */
+ /* add a 2 pixel border to ensure filtering is correct */
+ cos.xy *= 1.0 + storedTexelSize * 2.0;
+ cos.xy -= storedTexelSize;
+
+ float pattern = 1.0;
+
+ /* edge mirroring : only mirror if directly adjacent
+ * (not diagonally adjacent) */
+ vec2 m = abs(cos.xy - 0.5) + 0.5;
+ vec2 f = floor(m);
+ if (f.x - f.y != 0.0) {
+ cos.xy = 1.0 - cos.xy;
+ }
+
+ /* clamp to [0-1] */
+ cos.xy = fract(cos.xy);
+
+ /* get cubemap vector */
+ cos = normalize(octahedral_to_cubemap_proj(cos.xy));
+ make_orthonormal_basis(cos);
+
+ T *= shadowFilterSize;
+ B *= shadowFilterSize;
+#endif
+
+#ifdef ESM
+ /* disc blur in log space. */
+ vec4 depths;
+ depths.x = texture(shadowTexture, get_texco(cos, concentric[0])).r;
+ depths.y = texture(shadowTexture, get_texco(cos, concentric[1])).r;
+ depths.z = texture(shadowTexture, get_texco(cos, concentric[2])).r;
+ depths.w = texture(shadowTexture, get_texco(cos, concentric[3])).r;
+ float ref = depths.x;
+ vec4 accum = ln_space_prefilter_step(ref, depths);
+
+#else /* VSM */
+ float ref = 0.0; /* UNUSED */
+ vec2 accum = vec2(0.0);
+ grouped_samples_accum(cos, concentric[0], concentric[1], concentric[2], concentric[3], ref, accum);
+#endif
+
+ /**
+ * Making the `grouped_samples_accum` be called within a loop would be
+ * the most conventional solution, however in some older gpus, transverse the huge
+ * `const vec2 concentric[]` array with variable indices is extremely slow.
+ * The solution is to use constant indices to access the array.
+ */
+ if (shadowSampleCount > 4) {
+ grouped_samples_accum(cos, concentric[4], concentric[5], concentric[6], concentric[7], ref, accum);
+ grouped_samples_accum(cos, concentric[8], concentric[9], concentric[10], concentric[11], ref, accum);
+ grouped_samples_accum(cos, concentric[12], concentric[13], concentric[14], concentric[15], ref, accum);
+ }
+ if (shadowSampleCount > 16) {
+ grouped_samples_accum(cos, concentric[16], concentric[17], concentric[18], concentric[19], ref, accum);
+ grouped_samples_accum(cos, concentric[20], concentric[21], concentric[22], concentric[23], ref, accum);
+ grouped_samples_accum(cos, concentric[24], concentric[25], concentric[26], concentric[27], ref, accum);
+ grouped_samples_accum(cos, concentric[28], concentric[29], concentric[30], concentric[31], ref, accum);
+ grouped_samples_accum(cos, concentric[32], concentric[33], concentric[34], concentric[35], ref, accum);
+ }
+#ifdef HIGH_BLUR
+ if (shadowSampleCount > 36) {
+ grouped_samples_accum(cos, concentric[36], concentric[37], concentric[38], concentric[39], ref, accum);
+ grouped_samples_accum(cos, concentric[40], concentric[41], concentric[42], concentric[43], ref, accum);
+ grouped_samples_accum(cos, concentric[44], concentric[45], concentric[46], concentric[47], ref, accum);
+ grouped_samples_accum(cos, concentric[48], concentric[49], concentric[50], concentric[51], ref, accum);
+ grouped_samples_accum(cos, concentric[52], concentric[53], concentric[54], concentric[55], ref, accum);
+ grouped_samples_accum(cos, concentric[56], concentric[57], concentric[58], concentric[59], ref, accum);
+ grouped_samples_accum(cos, concentric[60], concentric[61], concentric[62], concentric[63], ref, accum);
+ }
+ if (shadowSampleCount > 64) {
+ grouped_samples_accum(cos, concentric[64], concentric[65], concentric[66], concentric[67], ref, accum);
+ grouped_samples_accum(cos, concentric[68], concentric[69], concentric[70], concentric[71], ref, accum);
+ grouped_samples_accum(cos, concentric[72], concentric[73], concentric[74], concentric[75], ref, accum);
+ grouped_samples_accum(cos, concentric[76], concentric[77], concentric[78], concentric[79], ref, accum);
+ grouped_samples_accum(cos, concentric[80], concentric[81], concentric[82], concentric[83], ref, accum);
+ grouped_samples_accum(cos, concentric[84], concentric[85], concentric[86], concentric[87], ref, accum);
+ grouped_samples_accum(cos, concentric[88], concentric[89], concentric[90], concentric[91], ref, accum);
+ grouped_samples_accum(cos, concentric[92], concentric[93], concentric[94], concentric[95], ref, accum);
+ grouped_samples_accum(cos, concentric[96], concentric[97], concentric[98], concentric[99], ref, accum);
+ }
+ if (shadowSampleCount > 100) {
+ grouped_samples_accum(cos, concentric[100], concentric[101], concentric[102], concentric[103], ref, accum);
+ grouped_samples_accum(cos, concentric[104], concentric[105], concentric[106], concentric[107], ref, accum);
+ grouped_samples_accum(cos, concentric[108], concentric[109], concentric[110], concentric[111], ref, accum);
+ grouped_samples_accum(cos, concentric[112], concentric[113], concentric[114], concentric[115], ref, accum);
+ grouped_samples_accum(cos, concentric[116], concentric[117], concentric[118], concentric[119], ref, accum);
+ grouped_samples_accum(cos, concentric[120], concentric[121], concentric[122], concentric[123], ref, accum);
+ grouped_samples_accum(cos, concentric[124], concentric[125], concentric[126], concentric[127], ref, accum);
+ grouped_samples_accum(cos, concentric[128], concentric[129], concentric[130], concentric[131], ref, accum);
+ grouped_samples_accum(cos, concentric[132], concentric[133], concentric[134], concentric[135], ref, accum);
+ grouped_samples_accum(cos, concentric[136], concentric[137], concentric[138], concentric[139], ref, accum);
+ grouped_samples_accum(cos, concentric[140], concentric[141], concentric[142], concentric[143], ref, accum);
+ }
+ if (shadowSampleCount > 144) {
+ grouped_samples_accum(cos, concentric[144], concentric[145], concentric[146], concentric[147], ref, accum);
+ grouped_samples_accum(cos, concentric[148], concentric[149], concentric[150], concentric[151], ref, accum);
+ grouped_samples_accum(cos, concentric[152], concentric[153], concentric[154], concentric[155], ref, accum);
+ grouped_samples_accum(cos, concentric[156], concentric[157], concentric[158], concentric[159], ref, accum);
+ grouped_samples_accum(cos, concentric[160], concentric[161], concentric[162], concentric[163], ref, accum);
+ grouped_samples_accum(cos, concentric[164], concentric[165], concentric[166], concentric[167], ref, accum);
+ grouped_samples_accum(cos, concentric[168], concentric[169], concentric[170], concentric[171], ref, accum);
+ grouped_samples_accum(cos, concentric[172], concentric[173], concentric[174], concentric[175], ref, accum);
+ grouped_samples_accum(cos, concentric[176], concentric[177], concentric[178], concentric[179], ref, accum);
+ grouped_samples_accum(cos, concentric[180], concentric[181], concentric[182], concentric[183], ref, accum);
+ grouped_samples_accum(cos, concentric[184], concentric[185], concentric[186], concentric[187], ref, accum);
+ grouped_samples_accum(cos, concentric[188], concentric[189], concentric[190], concentric[191], ref, accum);
+ grouped_samples_accum(cos, concentric[192], concentric[193], concentric[194], concentric[195], ref, accum);
+ }
+ if (shadowSampleCount > 196) {
+ grouped_samples_accum(cos, concentric[196], concentric[197], concentric[198], concentric[199], ref, accum);
+ grouped_samples_accum(cos, concentric[200], concentric[201], concentric[202], concentric[203], ref, accum);
+ grouped_samples_accum(cos, concentric[204], concentric[205], concentric[206], concentric[207], ref, accum);
+ grouped_samples_accum(cos, concentric[208], concentric[209], concentric[210], concentric[211], ref, accum);
+ grouped_samples_accum(cos, concentric[212], concentric[213], concentric[114], concentric[215], ref, accum);
+ grouped_samples_accum(cos, concentric[216], concentric[217], concentric[218], concentric[219], ref, accum);
+ grouped_samples_accum(cos, concentric[220], concentric[221], concentric[222], concentric[223], ref, accum);
+ grouped_samples_accum(cos, concentric[224], concentric[225], concentric[226], concentric[227], ref, accum);
+ grouped_samples_accum(cos, concentric[228], concentric[229], concentric[230], concentric[231], ref, accum);
+ grouped_samples_accum(cos, concentric[232], concentric[233], concentric[234], concentric[235], ref, accum);
+ grouped_samples_accum(cos, concentric[236], concentric[237], concentric[238], concentric[239], ref, accum);
+ grouped_samples_accum(cos, concentric[240], concentric[241], concentric[242], concentric[243], ref, accum);
+ grouped_samples_accum(cos, concentric[244], concentric[245], concentric[246], concentric[247], ref, accum);
+ grouped_samples_accum(cos, concentric[248], concentric[249], concentric[250], concentric[251], ref, accum);
+ grouped_samples_accum(cos, concentric[252], concentric[253], concentric[254], concentric[255], ref, accum);
+ }
+#endif
+
+#ifdef ESM
+ accum.x = dot(vec4(1.0), accum);
+ accum.x = ln_space_prefilter_finalize(ref, accum.x);
+ FragColor = accum.xxxx;
+
+#else /* VSM */
+ FragColor = accum.xyxy * shadowInvSampleCount;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
new file mode 100644
index 00000000000..cfd24ae8d65
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -0,0 +1,33 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+#ifdef MESH_SHADER
+uniform mat4 ModelViewMatrix;
+uniform mat3 WorldNormalMatrix;
+# ifndef ATTRIB
+uniform mat4 ModelMatrix;
+uniform mat3 NormalMatrix;
+# endif
+#endif
+
+in vec3 pos;
+in vec3 nor;
+
+#ifdef MESH_SHADER
+out vec3 worldPosition;
+out vec3 viewPosition;
+out vec3 worldNormal;
+out vec3 viewNormal;
+#endif
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+#ifdef MESH_SHADER
+ viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
+ worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz;
+ viewNormal = normalize(NormalMatrix * nor);
+ worldNormal = normalize(WorldNormalMatrix * nor);
+#ifdef ATTRIB
+ pass_attrib(pos);
+#endif
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
new file mode 100644
index 00000000000..6c7bfeb6b82
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl
@@ -0,0 +1,72 @@
+/* ------------ Refraction ------------ */
+
+#define BTDF_BIAS 0.85
+
+vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec4 rand)
+{
+ float a2 = max(5e-6, roughnessSquared * roughnessSquared);
+
+ /* Importance sampling bias */
+ rand.x = mix(rand.x, 0.0, BTDF_BIAS);
+
+ vec3 T, B;
+ float NH;
+ make_orthonormal_basis(N, T, B);
+ vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
+ float pdf = pdf_ggx_reflect(NH, a2);
+
+ /* If ray is bad (i.e. going below the plane) regenerate. */
+ if (F_eta(ior, dot(H, V)) < 1.0) {
+ H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
+ pdf = pdf_ggx_reflect(NH, a2);
+ }
+
+ vec3 vV = viewCameraVec;
+ float eta = 1.0/ior;
+ if (dot(H, V) < 0.0) {
+ H = -H;
+ eta = ior;
+ }
+
+ vec3 R = refract(-V, H, 1.0 / ior);
+
+ R = transform_direction(ViewMatrix, R);
+
+ vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, roughnessSquared, false);
+
+ if ((hit_pos.z > 0.0) && (F_eta(ior, dot(H, V)) < 1.0)) {
+ hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z);
+ float hit_dist = distance(hit_pos, viewPosition);
+
+ float cone_cos = cone_cosine(roughnessSquared);
+ float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos;
+
+ /* Empirical fit for refraction. */
+ /* TODO find a better fit or precompute inside the LUT. */
+ cone_tan *= 0.5 * fast_sqrt(f0_from_ior((ior < 1.0) ? 1.0 / ior : ior));
+
+ float cone_footprint = hit_dist * cone_tan;
+
+ /* find the offset in screen space by multiplying a point
+ * in camera space at the depth of the point by the projection matrix. */
+ float homcoord = ProjectionMatrix[2][3] * hit_pos.z + ProjectionMatrix[3][3];
+ /* UV space footprint */
+ cone_footprint = BTDF_BIAS * 0.5 * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * cone_footprint / homcoord;
+
+ vec2 hit_uvs = project_point(ProjectionMatrix, hit_pos).xy * 0.5 + 0.5;
+
+ /* Texel footprint */
+ vec2 texture_size = vec2(textureSize(colorBuffer, 0).xy);
+ float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, 9.0);
+
+ /* Correct UVs for mipmaping mis-alignment */
+ hit_uvs *= mip_ratio_interp(mip);
+
+ vec3 spec = textureLod(colorBuffer, hit_uvs, mip).xyz;
+ float mask = screen_border_mask(hit_uvs);
+
+ return vec4(spec, mask);
+ }
+
+ return vec4(0.0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl
new file mode 100644
index 00000000000..2907f25782f
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/update_noise_frag.glsl
@@ -0,0 +1,18 @@
+
+uniform sampler2D blueNoise;
+uniform vec3 offsets;
+
+out vec4 FragColor;
+
+#define M_2PI 6.28318530717958647692
+
+void main(void)
+{
+ vec3 blue_noise = texelFetch(blueNoise, ivec2(gl_FragCoord.xy), 0).xyz;
+
+ float noise = fract(blue_noise.y + offsets.z);
+ FragColor.x = fract(blue_noise.x + offsets.x);
+ FragColor.y = fract(blue_noise.z + offsets.y);
+ FragColor.z = cos(noise * M_2PI);
+ FragColor.w = sin(noise * M_2PI);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
new file mode 100644
index 00000000000..3a293647f84
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -0,0 +1,63 @@
+
+/* Based on Frosbite Unified Volumetric.
+ * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
+
+#define NODETREE_EXEC
+
+#ifdef MESH_SHADER
+uniform mat4 volumeObjectMatrix;
+uniform vec3 volumeOrcoLoc;
+uniform vec3 volumeOrcoSize;
+#endif
+
+flat in int slice;
+
+/* Warning: theses are not attributes, theses are global vars. */
+vec3 worldPosition = vec3(0.0);
+vec3 viewPosition = vec3(0.0);
+vec3 viewNormal = vec3(0.0);
+#ifdef MESH_SHADER
+vec3 volumeObjectLocalCoord = vec3(0.0);
+#endif
+
+layout(location = 0) out vec4 volumeScattering;
+layout(location = 1) out vec4 volumeExtinction;
+layout(location = 2) out vec4 volumeEmissive;
+layout(location = 3) out vec4 volumePhase;
+
+/* Store volumetric properties into the froxel textures. */
+
+void main()
+{
+ ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice);
+ vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz);
+
+ viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z);
+ worldPosition = transform_point(ViewMatrixInverse, viewPosition);
+#ifdef MESH_SHADER
+ volumeObjectLocalCoord = transform_point(volumeObjectMatrix, worldPosition);
+ volumeObjectLocalCoord = (volumeObjectLocalCoord - volumeOrcoLoc + volumeOrcoSize) / (volumeOrcoSize * 2.0);
+
+ if (any(lessThan(volumeObjectLocalCoord, vec3(0.0))) ||
+ any(greaterThan(volumeObjectLocalCoord, vec3(1.0))))
+ discard;
+#endif
+
+#ifdef CLEAR
+ Closure cl = CLOSURE_DEFAULT;
+#else
+ Closure cl = nodetree_exec();
+#endif
+
+ volumeScattering = vec4(cl.scatter, 1.0);
+ volumeExtinction = vec4(max(vec3(1e-4), cl.absorption + cl.scatter), 1.0);
+ volumeEmissive = vec4(cl.emission, 1.0);
+
+ /* Do not add phase weight if no scattering. */
+ if (all(equal(cl.scatter, vec3(0.0)))) {
+ volumePhase = vec4(0.0);
+ }
+ else {
+ volumePhase = vec4(cl.anisotropy, vec3(1.0));
+ }
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl
new file mode 100644
index 00000000000..d435bda4f60
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl
@@ -0,0 +1,70 @@
+
+#ifdef MESH_SHADER
+/* TODO tight slices */
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+#else /* World */
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+#endif
+
+in vec4 vPos[];
+
+flat out int slice;
+
+#ifdef MESH_SHADER
+/* TODO tight slices */
+void main() {
+ gl_Layer = slice = int(vPos[0].z);
+
+#ifdef ATTRIB
+ pass_attrib(0);
+#endif
+ gl_Position = vPos[0].xyww;
+ EmitVertex();
+
+#ifdef ATTRIB
+ pass_attrib(1);
+#endif
+ gl_Position = vPos[1].xyww;
+ EmitVertex();
+
+#ifdef ATTRIB
+ pass_attrib(2);
+#endif
+ gl_Position = vPos[2].xyww;
+ EmitVertex();
+
+ EndPrimitive();
+}
+
+#else /* World */
+
+/* This is just a pass-through geometry shader that send the geometry
+ * to the layer corresponding to it's depth. */
+
+void main() {
+ gl_Layer = slice = int(vPos[0].z);
+
+#ifdef ATTRIB
+ pass_attrib(0);
+#endif
+ gl_Position = vPos[0].xyww;
+ EmitVertex();
+
+#ifdef ATTRIB
+ pass_attrib(1);
+#endif
+ gl_Position = vPos[1].xyww;
+ EmitVertex();
+
+#ifdef ATTRIB
+ pass_attrib(2);
+#endif
+ gl_Position = vPos[2].xyww;
+ EmitVertex();
+
+ EndPrimitive();
+}
+
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
new file mode 100644
index 00000000000..827d774b290
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -0,0 +1,63 @@
+
+/* Based on Frosbite Unified Volumetric.
+ * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
+
+/* Step 3 : Integrate for each froxel the final amount of light
+ * scattered back to the viewer and the amount of transmittance. */
+
+uniform sampler3D volumeScattering; /* Result of the scatter step */
+uniform sampler3D volumeExtinction;
+
+flat in int slice;
+
+layout(location = 0) out vec4 finalScattering;
+layout(location = 1) out vec4 finalTransmittance;
+
+void main()
+{
+ /* Start with full transmittance and no scattered light. */
+ finalScattering = vec4(0.0);
+ finalTransmittance = vec4(1.0);
+
+ vec3 tex_size = vec3(textureSize(volumeScattering, 0).xyz);
+
+ /* Compute view ray. */
+ vec2 uvs = gl_FragCoord.xy / tex_size.xy;
+ vec3 ndc_cell = volume_to_ndc(vec3(uvs, 1e-5));
+ vec3 view_cell = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z);
+
+ /* Ortho */
+ float prev_ray_len = view_cell.z;
+ float orig_ray_len = 1.0;
+
+ /* Persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ prev_ray_len = length(view_cell);
+ orig_ray_len = prev_ray_len / view_cell.z;
+ }
+
+ /* Without compute shader and arbitrary write we need to
+ * accumulate from the beginning of the ray for each cell. */
+ float integration_end = float(slice);
+ for (int i = 0; i < slice; ++i) {
+ ivec3 volume_cell = ivec3(gl_FragCoord.xy, i);
+
+ vec4 Lscat = texelFetch(volumeScattering, volume_cell, 0);
+ vec4 s_extinction = texelFetch(volumeExtinction, volume_cell, 0);
+
+ float cell_depth = volume_z_to_view_z((float(i) + 1.0) / tex_size.z);
+ float ray_len = orig_ray_len * cell_depth;
+
+ /* Evaluate Scattering */
+ float s_len = abs(ray_len - prev_ray_len);
+ prev_ray_len = ray_len;
+ vec4 Tr = exp(-s_extinction * s_len);
+
+ /* integrate along the current step segment */
+ Lscat = (Lscat - Lscat * Tr) / s_extinction;
+ /* accumulate and also take into account the transmittance from previous steps */
+ finalScattering += finalTransmittance * Lscat;
+
+ finalTransmittance *= Tr;
+ }
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
new file mode 100644
index 00000000000..ae36252153f
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
@@ -0,0 +1,155 @@
+
+/* Based on Frosbite Unified Volumetric.
+ * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
+
+/* Volume slice to view space depth. */
+float volume_z_to_view_z(float z)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ /* Exponential distribution */
+ return (exp2(z / volDepthParameters.z) - volDepthParameters.x) / volDepthParameters.y;
+ }
+ else {
+ /* Linear distribution */
+ return mix(volDepthParameters.x, volDepthParameters.y, z);
+ }
+}
+
+float view_z_to_volume_z(float depth)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ /* Exponential distribution */
+ return volDepthParameters.z * log2(depth * volDepthParameters.y + volDepthParameters.x);
+ }
+ else {
+ /* Linear distribution */
+ return (depth - volDepthParameters.x) * volDepthParameters.z;
+ }
+}
+
+/* Volume texture normalized coordinates to NDC (special range [0, 1]). */
+vec3 volume_to_ndc(vec3 cos)
+{
+ cos.z = volume_z_to_view_z(cos.z);
+ cos.z = get_depth_from_view_z(cos.z);
+ cos.xy /= volCoordScale.xy;
+ return cos;
+}
+
+vec3 ndc_to_volume(vec3 cos)
+{
+ cos.z = get_view_z_from_depth(cos.z);
+ cos.z = view_z_to_volume_z(cos.z);
+ cos.xy *= volCoordScale.xy;
+ return cos;
+}
+
+float phase_function_isotropic()
+{
+ return 1.0 / (4.0 * M_PI);
+}
+
+float phase_function(vec3 v, vec3 l, float g)
+{
+ /* Henyey-Greenstein */
+ float cos_theta = dot(v, l);
+ g = clamp(g, -1.0 + 1e-3, 1.0 - 1e-3);
+ float sqr_g = g * g;
+ return (1- sqr_g) / max(1e-8, 4.0 * M_PI * pow(1 + sqr_g - 2 * g * cos_theta, 3.0 / 2.0));
+}
+
+#ifdef LAMPS_LIB
+vec3 light_volume(LightData ld, vec4 l_vector)
+{
+ float power;
+ /* TODO : Area lighting ? */
+ /* XXX : Removing Area Power. */
+ /* TODO : put this out of the shader. */
+ /* See eevee_light_setup(). */
+ if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
+ power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
+ if (ld.l_type == AREA_ELLIPSE) {
+ power *= M_PI * 0.25;
+ }
+ power *= 20.0 * max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
+ }
+ else if (ld.l_type == SUN) {
+ power = ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
+ power /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f);
+ power *= M_PI * 0.5; /* Matching cycles. */
+ }
+ else {
+ power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 /10.0);
+ power *= M_2PI; /* Matching cycles with point light. */
+ }
+
+ power /= (l_vector.w * l_vector.w);
+
+ /* OPTI: find a better way than calculating this on the fly */
+ float lum = dot(ld.l_color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
+ vec3 tint = (lum > 0.0) ? ld.l_color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
+
+ lum = min(lum * power, volLightClamp);
+
+ return tint * lum;
+}
+
+#define VOLUMETRIC_SHADOW_MAX_STEP 32.0
+
+vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction)
+{
+ /* Waiting for proper volume shadowmaps and out of frustum shadow map. */
+ vec3 ndc = project_point(ViewProjectionMatrix, wpos);
+ vec3 volume_co = ndc_to_volume(ndc * 0.5 + 0.5);
+
+ /* Let the texture be clamped to edge. This reduce visual glitches. */
+ return texture(volume_extinction, volume_co).rgb;
+}
+
+vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D volume_extinction)
+{
+#if defined(VOLUME_SHADOW)
+ /* Heterogeneous volume shadows */
+ float dd = l_vector.w / volShadowSteps;
+ vec3 L = l_vector.xyz * l_vector.w;
+ vec3 shadow = vec3(1.0);
+ for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volShadowSteps - 0.1); s += 1.0) {
+ vec3 pos = ray_wpos + L * (s / volShadowSteps);
+ vec3 s_extinction = participating_media_extinction(pos, volume_extinction);
+ shadow *= exp(-s_extinction * dd);
+ }
+ return shadow;
+#else
+ return vec3(1.0);
+#endif /* VOLUME_SHADOW */
+}
+#endif
+
+#ifdef IRRADIANCE_LIB
+vec3 irradiance_volumetric(vec3 wpos)
+{
+#ifdef IRRADIANCE_HL2
+ IrradianceData ir_data = load_irradiance_cell(0, vec3(1.0));
+ vec3 irradiance = ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
+ ir_data = load_irradiance_cell(0, vec3(-1.0));
+ irradiance += ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
+ irradiance *= 0.16666666; /* 1/6 */
+ return irradiance;
+#else
+ return vec3(0.0);
+#endif
+}
+#endif
+
+uniform sampler3D inScattering;
+uniform sampler3D inTransmittance;
+
+vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth)
+{
+ vec3 volume_cos = ndc_to_volume(vec3(frag_uvs, frag_depth));
+
+ vec3 scattering = texture(inScattering, volume_cos).rgb;
+ vec3 transmittance = texture(inTransmittance, volume_cos).rgb;
+
+ return vec4(scene_color.rgb * transmittance + scattering, scene_color.a);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl
new file mode 100644
index 00000000000..0115b2cb99e
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_resolve_frag.glsl
@@ -0,0 +1,21 @@
+
+/* Based on Frosbite Unified Volumetric.
+ * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
+
+/* Step 4 : Apply final integration on top of the scene color.
+ * Note that we do the blending ourself instead of relying
+ * on hardware blending which would require 2 pass. */
+
+uniform sampler2D inSceneColor;
+uniform sampler2D inSceneDepth;
+
+out vec4 FragColor;
+
+void main()
+{
+ vec2 uvs = gl_FragCoord.xy / vec2(textureSize(inSceneDepth, 0));
+ vec4 scene_color = texture(inSceneColor, uvs);
+ float scene_depth = texture(inSceneDepth, uvs).r;
+
+ FragColor = volumetric_resolve(scene_color, uvs, scene_depth);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
new file mode 100644
index 00000000000..fcbb6661b14
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
@@ -0,0 +1,75 @@
+
+/* Based on Frosbite Unified Volumetric.
+ * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
+
+/* Step 2 : Evaluate all light scattering for each froxels.
+ * Also do the temporal reprojection to fight aliasing artifacts. */
+
+uniform sampler3D volumeScattering;
+uniform sampler3D volumeExtinction;
+uniform sampler3D volumeEmission;
+uniform sampler3D volumePhase;
+
+uniform sampler3D historyScattering;
+uniform sampler3D historyTransmittance;
+
+flat in int slice;
+
+layout(location = 0) out vec4 outScattering;
+layout(location = 1) out vec4 outTransmittance;
+
+void main()
+{
+ ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice);
+
+ /* Emission */
+ outScattering = texelFetch(volumeEmission, volume_cell, 0);
+ outTransmittance = texelFetch(volumeExtinction, volume_cell, 0);
+ vec3 s_scattering = texelFetch(volumeScattering, volume_cell, 0).rgb;
+ vec3 volume_ndc = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz);
+ vec3 worldPosition = get_world_space_from_depth(volume_ndc.xy, volume_ndc.z);
+ vec3 wdir = cameraVec;
+
+ vec2 phase = texelFetch(volumePhase, volume_cell, 0).rg;
+ float s_anisotropy = phase.x / max(1.0, phase.y);
+
+ /* Environment : Average color. */
+ outScattering.rgb += irradiance_volumetric(worldPosition) * s_scattering * phase_function_isotropic();
+
+#ifdef VOLUME_LIGHTING /* Lights */
+ for (int i = 0; i < MAX_LIGHT && i < laNumLight; ++i) {
+
+ LightData ld = lights_data[i];
+
+ vec4 l_vector;
+ l_vector.xyz = (ld.l_type == SUN) ? -ld.l_forward : ld.l_position - worldPosition;
+ l_vector.w = length(l_vector.xyz);
+
+ float Vis = light_visibility(ld, worldPosition, l_vector);
+
+ vec3 Li = light_volume(ld, l_vector) * light_volume_shadow(ld, worldPosition, l_vector, volumeExtinction);
+
+ outScattering.rgb += Li * Vis * s_scattering * phase_function(-wdir, l_vector.xyz / l_vector.w, s_anisotropy);
+ }
+#endif
+
+ /* Temporal supersampling */
+ /* Note : this uses the cell non-jittered position (texel center). */
+ vec3 curr_ndc = volume_to_ndc(vec3(gl_FragCoord.xy, float(slice) + 0.5) * volInvTexSize.xyz);
+ vec3 wpos = get_world_space_from_depth(curr_ndc.xy, curr_ndc.z);
+ vec3 prev_ndc = project_point(pastViewProjectionMatrix, wpos);
+ vec3 prev_volume = ndc_to_volume(prev_ndc * 0.5 + 0.5);
+
+ if ((volHistoryAlpha > 0.0) && all(greaterThan(prev_volume, vec3(0.0))) && all(lessThan(prev_volume, vec3(1.0)))) {
+ vec4 h_Scattering = texture(historyScattering, prev_volume);
+ vec4 h_Transmittance = texture(historyTransmittance, prev_volume);
+ outScattering = mix(outScattering, h_Scattering, volHistoryAlpha);
+ outTransmittance = mix(outTransmittance, h_Transmittance, volHistoryAlpha);
+ }
+
+ /* Catch NaNs */
+ if (any(isnan(outScattering)) || any(isnan(outTransmittance))) {
+ outScattering = vec4(0.0);
+ outTransmittance = vec4(1.0);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
new file mode 100644
index 00000000000..a99acd41fbd
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -0,0 +1,27 @@
+
+out vec4 vPos;
+
+void main()
+{
+ /* Generate Triangle : less memory fetches from a VBO */
+ int v_id = gl_VertexID % 3; /* Vertex Id */
+ int t_id = gl_VertexID / 3; /* Triangle Id */
+
+ /* Crappy diagram
+ * ex 1
+ * | \
+ * | \
+ * 1 | \
+ * | \
+ * | \
+ * 0 | \
+ * | \
+ * | \
+ * -1 0 --------------- 2
+ * -1 0 1 ex
+ **/
+ vPos.x = float(v_id / 2) * 4.0 - 1.0; /* int divisor round down */
+ vPos.y = float(v_id % 2) * 4.0 - 1.0;
+ vPos.z = float(t_id);
+ vPos.w = 1.0;
+}
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
new file mode 100644
index 00000000000..b2c30ba723c
--- /dev/null
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file external_engine.c
+ * \ingroup draw_engine
+ *
+ * Base engine for external render engines.
+ * We use it for depth and non-mesh objects.
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_icons.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+
+#include "ED_view3d.h"
+#include "ED_screen.h"
+
+#include "GPU_glew.h"
+#include "GPU_matrix.h"
+#include "GPU_shader.h"
+#include "GPU_viewport.h"
+
+#include "external_engine.h"
+/* Shaders */
+
+#define EXTERNAL_ENGINE "BLENDER_EXTERNAL"
+
+/* *********** LISTS *********** */
+
+/* GPUViewport.storage
+ * Is freed everytime the viewport engine changes */
+typedef struct EXTERNAL_Storage {
+ int dummy;
+} EXTERNAL_Storage;
+
+typedef struct EXTERNAL_StorageList {
+ struct EXTERNAL_Storage *storage;
+ struct EXTERNAL_PrivateData *g_data;
+} EXTERNAL_StorageList;
+
+typedef struct EXTERNAL_FramebufferList {
+ struct GPUFrameBuffer *default_fb;
+} EXTERNAL_FramebufferList;
+
+typedef struct EXTERNAL_TextureList {
+ /* default */
+ struct GPUTexture *depth;
+} EXTERNAL_TextureList;
+
+typedef struct EXTERNAL_PassList {
+ struct DRWPass *depth_pass;
+} EXTERNAL_PassList;
+
+typedef struct EXTERNAL_Data {
+ void *engine_type;
+ EXTERNAL_FramebufferList *fbl;
+ EXTERNAL_TextureList *txl;
+ EXTERNAL_PassList *psl;
+ EXTERNAL_StorageList *stl;
+ char info[GPU_INFO_SIZE];
+} EXTERNAL_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Depth Pre Pass */
+ struct GPUShader *depth_sh;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EXTERNAL_PrivateData {
+ DRWShadingGroup *depth_shgrp;
+} EXTERNAL_PrivateData; /* Transient data */
+
+/* Functions */
+
+static void external_engine_init(void *UNUSED(vedata))
+{
+ /* Depth prepass */
+ if (!e_data.depth_sh) {
+ e_data.depth_sh = DRW_shader_create_3D_depth_only();
+ }
+}
+
+static void external_cache_init(void *vedata)
+{
+ EXTERNAL_PassList *psl = ((EXTERNAL_Data *)vedata)->psl;
+ EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ /* Depth Pass */
+ {
+ psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+ stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass);
+ }
+}
+
+static void external_cache_populate(void *vedata, Object *ob)
+{
+ EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
+
+ if (!DRW_object_is_renderable(ob))
+ return;
+
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ /* Depth Prepass */
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp, geom, ob->obmat);
+ }
+}
+
+static void external_cache_finish(void *UNUSED(vedata))
+{
+}
+
+static void external_draw_scene_do(void *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ARegion *ar = draw_ctx->ar;
+ RenderEngineType *type;
+
+ DRW_state_reset_ex(DRW_STATE_DEFAULT & ~DRW_STATE_DEPTH_LESS_EQUAL);
+
+ /* Create render engine. */
+ if (!rv3d->render_engine) {
+ RenderEngineType *engine_type = draw_ctx->engine_type;
+
+ if (!(engine_type->view_update && engine_type->view_draw)) {
+ return;
+ }
+
+ RenderEngine *engine = RE_engine_create_ex(engine_type, true);
+ engine->tile_x = scene->r.tilex;
+ engine->tile_y = scene->r.tiley;
+ engine_type->view_update(engine, draw_ctx->evil_C);
+ rv3d->render_engine = engine;
+ }
+
+ /* Rendered draw. */
+ GPU_matrix_push_projection();
+ ED_region_pixelspace(ar);
+
+ /* Render result draw. */
+ type = rv3d->render_engine->type;
+ type->view_draw(rv3d->render_engine, draw_ctx->evil_C);
+
+ GPU_matrix_pop_projection();
+
+ /* Set render info. */
+ EXTERNAL_Data *data = vedata;
+ if (rv3d->render_engine->text[0] != '\0') {
+ BLI_strncpy(data->info, rv3d->render_engine->text, sizeof(data->info));
+ }
+ else {
+ data->info[0] = '\0';
+ }
+}
+
+static void external_draw_scene(void *vedata)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ EXTERNAL_PassList *psl = ((EXTERNAL_Data *)vedata)->psl;
+
+ /* Will be NULL during OpenGL render.
+ * OpenGL render is used for quick preview (thumbnails or sequencer preview)
+ * where using the rendering engine to preview doesn't make so much sense. */
+ if (draw_ctx->evil_C) {
+ external_draw_scene_do(vedata);
+ }
+ DRW_draw_pass(psl->depth_pass);
+}
+
+static void external_engine_free(void)
+{
+ /* All shaders are builtin. */
+}
+
+static const DrawEngineDataSize external_data_size = DRW_VIEWPORT_DATA_SIZE(EXTERNAL_Data);
+
+DrawEngineType draw_engine_external_type = {
+ NULL, NULL,
+ N_("External"),
+ &external_data_size,
+ &external_engine_init,
+ &external_engine_free,
+ &external_cache_init,
+ &external_cache_populate,
+ &external_cache_finish,
+ NULL,
+ &external_draw_scene,
+ NULL,
+ NULL,
+ NULL,
+};
+
+/* Note: currently unused, we should not register unless we want to see this when debugging the view. */
+
+RenderEngineType DRW_engine_viewport_external_type = {
+ NULL, NULL,
+ EXTERNAL_ENGINE, N_("External"), RE_INTERNAL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &draw_engine_external_type,
+ {NULL, NULL, NULL}
+};
+
+#undef EXTERNAL_ENGINE
diff --git a/source/blender/draw/engines/external/external_engine.h b/source/blender/draw/engines/external/external_engine.h
new file mode 100644
index 00000000000..1789fb67efe
--- /dev/null
+++ b/source/blender/draw/engines/external/external_engine.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file external_engine.h
+ * \ingroup draw_engine
+ */
+
+#ifndef __EXTERNAL_ENGINE_H__
+#define __EXTERNAL_ENGINE_H__
+
+extern RenderEngineType DRW_engine_viewport_external_type;
+
+#endif /* __EXTERNAL_ENGINE_H__ */
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
new file mode 100644
index 00000000000..5478c4a60b9
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_cache_utils.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_gpencil.h"
+
+#include "gpencil_engine.h"
+
+#include "draw_cache_impl.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+ /* add a gpencil object to cache to defer drawing */
+tGPencilObjectCache *gpencil_object_cache_add(
+ tGPencilObjectCache *cache_array, Object *ob,
+ int *gp_cache_size, int *gp_cache_used)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ tGPencilObjectCache *cache_elem = NULL;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ tGPencilObjectCache *p = NULL;
+
+ /* By default a cache is created with one block with a predefined number of free slots,
+ if the size is not enough, the cache is reallocated adding a new block of free slots.
+ This is done in order to keep cache small */
+ if (*gp_cache_used + 1 > *gp_cache_size) {
+ if ((*gp_cache_size == 0) || (cache_array == NULL)) {
+ p = MEM_callocN(sizeof(struct tGPencilObjectCache) * GP_CACHE_BLOCK_SIZE, "tGPencilObjectCache");
+ *gp_cache_size = GP_CACHE_BLOCK_SIZE;
+ }
+ else {
+ *gp_cache_size += GP_CACHE_BLOCK_SIZE;
+ p = MEM_recallocN(cache_array, sizeof(struct tGPencilObjectCache) * *gp_cache_size);
+ }
+ cache_array = p;
+ }
+ /* zero out all pointers */
+ cache_elem = &cache_array[*gp_cache_used];
+ memset(cache_elem, 0, sizeof(*cache_elem));
+
+ Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
+ cache_elem->ob = ob_orig;
+ cache_elem->gpd = (bGPdata *)ob_orig->data;
+ copy_v3_v3(cache_elem->loc, ob->loc);
+ copy_m4_m4(cache_elem->obmat, ob->obmat);
+ cache_elem->idx = *gp_cache_used;
+
+ /* object is duplicated (particle) */
+ cache_elem->is_dup_ob = ob->base_flag & BASE_FROMDUPLI;
+
+ /* save FXs */
+ cache_elem->pixfactor = cache_elem->gpd->pixfactor;
+ cache_elem->shader_fx = ob_orig->shader_fx;
+
+ /* shgrp array */
+ cache_elem->tot_layers = 0;
+ int totgpl = BLI_listbase_count(&cache_elem->gpd->layers);
+ if (totgpl > 0) {
+ cache_elem->shgrp_array = MEM_callocN(sizeof(tGPencilObjectCache_shgrp) * totgpl, __func__);
+ }
+
+ /* calculate zdepth from point of view */
+ float zdepth = 0.0;
+ if (rv3d) {
+ if (rv3d->is_persp) {
+ zdepth = ED_view3d_calc_zfac(rv3d, ob->loc, NULL);
+ }
+ else {
+ zdepth = -dot_v3v3(rv3d->viewinv[2], ob->loc);
+ }
+ }
+ else {
+ /* In render mode, rv3d is not available, so use the distance to camera.
+ * The real distance is not important, but the relative distance to the camera plane
+ * in order to sort by z_depth of the objects
+ */
+ float vn[3] = { 0.0f, 0.0f, -1.0f }; /* always face down */
+ float plane_cam[4];
+ struct Object *camera = draw_ctx->scene->camera;
+ if (camera) {
+ mul_m4_v3(camera->obmat, vn);
+ normalize_v3(vn);
+ plane_from_point_normal_v3(plane_cam, camera->loc, vn);
+ zdepth = dist_squared_to_plane_v3(ob->loc, plane_cam);
+ }
+ }
+ cache_elem->zdepth = zdepth;
+ /* increase slots used in cache */
+ (*gp_cache_used)++;
+
+ return cache_array;
+}
+
+/* add a shading group to the cache to create later */
+GpencilBatchGroup *gpencil_group_cache_add(
+ GpencilBatchGroup *cache_array,
+ bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
+ const short type, const bool onion,
+ const int vertex_idx,
+ int *grp_size, int *grp_used)
+{
+ GpencilBatchGroup *cache_elem = NULL;
+ GpencilBatchGroup *p = NULL;
+
+ /* By default a cache is created with one block with a predefined number of free slots,
+ if the size is not enough, the cache is reallocated adding a new block of free slots.
+ This is done in order to keep cache small */
+ if (*grp_used + 1 > *grp_size) {
+ if ((*grp_size == 0) || (cache_array == NULL)) {
+ p = MEM_callocN(sizeof(struct GpencilBatchGroup) * GPENCIL_GROUPS_BLOCK_SIZE, "GpencilBatchGroup");
+ *grp_size = GPENCIL_GROUPS_BLOCK_SIZE;
+ }
+ else {
+ *grp_size += GPENCIL_GROUPS_BLOCK_SIZE;
+ p = MEM_recallocN(cache_array, sizeof(struct GpencilBatchGroup) * *grp_size);
+ }
+ cache_array = p;
+ }
+ /* zero out all data */
+ cache_elem = &cache_array[*grp_used];
+ memset(cache_elem, 0, sizeof(*cache_elem));
+
+ cache_elem->gpl = gpl;
+ cache_elem->gpf = gpf;
+ cache_elem->gps = gps;
+ cache_elem->type = type;
+ cache_elem->onion = onion;
+ cache_elem->vertex_idx = vertex_idx;
+
+ /* increase slots used in cache */
+ (*grp_used)++;
+
+ return cache_array;
+}
+
+/* get current cache data */
+static GpencilBatchCache *gpencil_batch_get_element(Object *ob)
+{
+ Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
+ return ob_orig->runtime.gpencil_cache;
+}
+
+/* verify if cache is valid */
+static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
+{
+ bool valid = true;
+ if (cache == NULL) {
+ return false;
+ }
+
+ cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
+ if (cfra != cache->cache_frame) {
+ valid = false;
+ }
+ else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
+ valid = false;
+ }
+ else if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) {
+ /* if onion, set as dirty always
+ * This reduces performance, but avoid any crash in the multiple
+ * overlay and multiwindow options and keep all windows working
+ */
+ valid = false;
+ }
+ else if (cache->is_editmode) {
+ valid = false;
+ }
+ else if (cache->is_dirty) {
+ valid = false;
+ }
+
+ return valid;
+}
+
+/* cache init */
+static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
+{
+ Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
+ bGPdata *gpd = (bGPdata *)ob_orig->data;
+
+ GpencilBatchCache *cache = gpencil_batch_get_element(ob);
+
+ if (!cache) {
+ cache = MEM_callocN(sizeof(*cache), __func__);
+ ob_orig->runtime.gpencil_cache = cache;
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+ cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ cache->is_dirty = true;
+
+ cache->cache_frame = cfra;
+
+ /* create array of derived frames equal to number of layers */
+ cache->tot_layers = BLI_listbase_count(&gpd->layers);
+ CLAMP_MIN(cache->tot_layers, 1);
+ cache->derived_array = MEM_callocN(sizeof(struct bGPDframe) * cache->tot_layers, "Derived GPF");
+
+ return cache;
+}
+
+/* clear cache */
+static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
+{
+ if (!cache) {
+ return;
+ }
+
+ GPU_BATCH_DISCARD_SAFE(cache->b_stroke.batch);
+ GPU_BATCH_DISCARD_SAFE(cache->b_point.batch);
+ GPU_BATCH_DISCARD_SAFE(cache->b_fill.batch);
+ GPU_BATCH_DISCARD_SAFE(cache->b_edit.batch);
+ GPU_BATCH_DISCARD_SAFE(cache->b_edlin.batch);
+
+ MEM_SAFE_FREE(cache->b_stroke.batch);
+ MEM_SAFE_FREE(cache->b_point.batch);
+ MEM_SAFE_FREE(cache->b_fill.batch);
+ MEM_SAFE_FREE(cache->b_edit.batch);
+ MEM_SAFE_FREE(cache->b_edlin.batch);
+
+ MEM_SAFE_FREE(cache->grp_cache);
+ cache->grp_size = 0;
+ cache->grp_used = 0;
+
+ /* clear all frames derived data */
+ for (int i = 0; i < cache->tot_layers; i++) {
+ bGPDframe *derived_gpf = &cache->derived_array[i];
+ BKE_gpencil_free_frame_runtime_data(derived_gpf);
+ derived_gpf = NULL;
+ }
+ cache->tot_layers = 0;
+ MEM_SAFE_FREE(cache->derived_array);
+}
+
+/* get cache */
+GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
+{
+ Object *ob_orig = (Object *)DEG_get_original_id(&ob->id);
+ bGPdata *gpd = (bGPdata *)ob_orig->data;
+
+ GpencilBatchCache *cache = gpencil_batch_get_element(ob);
+ if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
+ if (cache) {
+ gpencil_batch_cache_clear(cache);
+ }
+ return gpencil_batch_cache_init(ob, cfra);
+ }
+ else {
+ return cache;
+ }
+}
+
+/* set cache as dirty */
+void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
+{
+ bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
+ gpd_orig->flag |= GP_DATA_CACHE_IS_DIRTY;
+}
+
+/* free batch cache */
+void DRW_gpencil_batch_cache_free(bGPdata *UNUSED(gpd))
+{
+ return;
+}
+
+/* wrapper to clear cache */
+void DRW_gpencil_freecache(struct Object *ob)
+{
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpencil_batch_cache_clear(ob->runtime.gpencil_cache);
+ MEM_SAFE_FREE(ob->runtime.gpencil_cache);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (gpd) {
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
new file mode 100644
index 00000000000..1afb5daa912
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
@@ -0,0 +1,727 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw/engines/gpencil/gpencil_draw_cache_impl.c
+ * \ingroup draw
+ */
+
+#include "BLI_polyfill_2d.h"
+#include "BLI_math_color.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_action.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+
+#include "DRW_render.h"
+
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "gpencil_engine.h"
+
+/* Helper to add stroke point to vbo */
+static void gpencil_set_stroke_point(
+ GPUVertBuf *vbo, const bGPDspoint *pt, int idx,
+ uint pos_id, uint color_id,
+ uint thickness_id, uint uvdata_id, short thickness,
+ const float ink[4])
+{
+
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ float col[4];
+ ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
+
+ GPU_vertbuf_attr_set(vbo, color_id, idx, col);
+
+ /* transfer both values using the same shader variable */
+ float uvdata[2] = { pt->uv_fac, pt->uv_rot };
+ GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata);
+
+ /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */
+ float thick = max_ff(pt->pressure * thickness, 1.0f);
+ GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick);
+
+ GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
+}
+
+/* Helper to add a new fill point and texture coordinates to vertex buffer */
+static void gpencil_set_fill_point(
+ GPUVertBuf *vbo, int idx, bGPDspoint *pt, const float fcolor[4], float uv[2],
+ uint pos_id, uint color_id, uint text_id)
+{
+ GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
+ GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor);
+ GPU_vertbuf_attr_set(vbo, text_id, idx, uv);
+}
+
+static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex)
+{
+ if (be->vbo->vertex_alloc <= be->vbo_len + totvertex) {
+ uint newsize = be->vbo->vertex_alloc + (((totvertex / GPENCIL_VBO_BLOCK_SIZE) + 1) * GPENCIL_VBO_BLOCK_SIZE);
+ GPU_vertbuf_data_resize(be->vbo, newsize);
+ }
+}
+
+/* create batch geometry data for points stroke shader */
+void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be, bGPDstroke *gps, short thickness, const float ink[4])
+{
+ int totvertex = gps->totpoints;
+ if (be->vbo == NULL) {
+ be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ be->thickness_id = GPU_vertformat_attr_add(&be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ be->uvdata_id = GPU_vertformat_attr_add(&be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ be->vbo = GPU_vertbuf_create_with_format(&be->format);
+ GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
+ be->vbo_len = 0;
+ }
+ gpencil_vbo_ensure_size(be, totvertex);
+
+ /* draw stroke curve */
+ const bGPDspoint *pt = gps->points;
+ float alpha;
+ float col[4];
+
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
+ /* set point */
+ alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
+
+ float thick = max_ff(pt->pressure * thickness, 1.0f);
+
+ GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, col);
+ GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &thick);
+
+ /* transfer both values using the same shader variable */
+ float uvdata[2] = { pt->uv_fac, pt->uv_rot };
+ GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata);
+
+ GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
+ be->vbo_len++;
+ }
+}
+
+/* create batch geometry data for stroke shader */
+void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, short thickness, const float ink[4])
+{
+ bGPDspoint *points = gps->points;
+ int totpoints = gps->totpoints;
+ /* if cyclic needs more vertex */
+ int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0;
+ int totvertex = totpoints + cyclic_add + 2;
+
+ if (be->vbo == NULL) {
+ be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ be->thickness_id = GPU_vertformat_attr_add(&be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ be->uvdata_id = GPU_vertformat_attr_add(&be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ be->vbo = GPU_vertbuf_create_with_format(&be->format);
+ GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
+ be->vbo_len = 0;
+ }
+ gpencil_vbo_ensure_size(be, totvertex);
+
+ /* draw stroke curve */
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* first point for adjacency (not drawn) */
+ if (i == 0) {
+ if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
+ gpencil_set_stroke_point(
+ be->vbo, &points[totpoints - 1], be->vbo_len,
+ be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+ be->vbo_len++;
+ }
+ else {
+ gpencil_set_stroke_point(
+ be->vbo, &points[1], be->vbo_len,
+ be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+ be->vbo_len++;
+ }
+ }
+ /* set point */
+ gpencil_set_stroke_point(
+ be->vbo, pt, be->vbo_len,
+ be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+ be->vbo_len++;
+ }
+
+ if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
+ /* draw line to first point to complete the cycle */
+ gpencil_set_stroke_point(
+ be->vbo, &points[0], be->vbo_len,
+ be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+ be->vbo_len++;
+ /* now add adjacency point (not drawn) */
+ gpencil_set_stroke_point(
+ be->vbo, &points[1], be->vbo_len,
+ be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+ be->vbo_len++;
+ }
+ /* last adjacency point (not drawn) */
+ else {
+ gpencil_set_stroke_point(
+ be->vbo, &points[totpoints - 2], be->vbo_len,
+ be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
+ be->vbo_len++;
+ }
+}
+
+/* create batch geometry data for stroke shader */
+void DRW_gpencil_get_fill_geom(struct GpencilBatchCacheElem *be, Object *ob, bGPDstroke *gps, const float color[4])
+{
+ BLI_assert(gps->totpoints >= 3);
+
+ /* Calculate triangles cache for filling area (must be done only after changes) */
+ if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
+ DRW_gpencil_triangulate_stroke_fill(ob, gps);
+ ED_gpencil_calc_stroke_uv(ob, gps);
+ }
+
+ BLI_assert(gps->tot_triangles >= 1);
+ int totvertex = gps->tot_triangles * 3;
+
+ if (be->vbo == NULL) {
+ be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ be->uvdata_id = GPU_vertformat_attr_add(&be->format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ be->vbo = GPU_vertbuf_create_with_format(&be->format);
+ GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
+ be->vbo_len = 0;
+ }
+ gpencil_vbo_ensure_size(be, totvertex);
+
+ /* Draw all triangles for filling the polygon (cache must be calculated before) */
+ bGPDtriangle *stroke_triangle = gps->triangles;
+ for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
+ for (int j = 0; j < 3; j++) {
+ gpencil_set_fill_point(
+ be->vbo, be->vbo_len, &gps->points[stroke_triangle->verts[j]], color, stroke_triangle->uv[j],
+ be->pos_id, be->color_id, be->uvdata_id);
+ be->vbo_len++;
+ }
+ }
+}
+
+/* create batch geometry data for current buffer stroke shader */
+GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ ARegion *ar = draw_ctx->ar;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ToolSettings *ts = scene->toolsettings;
+ Object *ob = draw_ctx->obact;
+
+ tGPspoint *points = gpd->runtime.sbuffer;
+ int totpoints = gpd->runtime.sbuffer_size;
+
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, color_id, thickness_id, uvdata_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, totpoints + 2);
+
+ /* draw stroke curve */
+ const tGPspoint *tpt = points;
+ bGPDspoint pt, pt2;
+ int idx = 0;
+
+ /* get origin to reproject point */
+ float origin[3];
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+
+ for (int i = 0; i < totpoints; i++, tpt++) {
+ ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
+ ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
+
+ /* first point for adjacency (not drawn) */
+ if (i == 0) {
+ if (totpoints > 1) {
+ ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2);
+ gpencil_set_stroke_point(
+ vbo, &pt2, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ }
+ else {
+ gpencil_set_stroke_point(
+ vbo, &pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ }
+ idx++;
+ }
+ /* set point */
+ gpencil_set_stroke_point(
+ vbo, &pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ idx++;
+ }
+
+ /* last adjacency point (not drawn) */
+ if (totpoints > 2) {
+ ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2);
+ gpencil_set_stroke_point(
+ vbo, &pt2, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ }
+ else {
+ gpencil_set_stroke_point(
+ vbo, &pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+/* create batch geometry data for current buffer point shader */
+GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ ARegion *ar = draw_ctx->ar;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ToolSettings *ts = scene->toolsettings;
+ Object *ob = draw_ctx->obact;
+
+ tGPspoint *points = gpd->runtime.sbuffer;
+ int totpoints = gpd->runtime.sbuffer_size;
+
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, color_id, thickness_id, uvdata_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, totpoints);
+
+ /* draw stroke curve */
+ const tGPspoint *tpt = points;
+ bGPDspoint pt;
+ int idx = 0;
+
+ /* get origin to reproject point */
+ float origin[3];
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+
+ for (int i = 0; i < totpoints; i++, tpt++) {
+ ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
+ ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
+
+ /* set point */
+ gpencil_set_stroke_point(
+ vbo, &pt, idx,
+ pos_id, color_id, thickness_id, uvdata_id,
+ thickness, gpd->runtime.scolor);
+ idx++;
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+/* create batch geometry data for current buffer fill shader */
+GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd)
+{
+ if (gpd == NULL) {
+ return NULL;
+ }
+
+ const tGPspoint *points = gpd->runtime.sbuffer;
+ int totpoints = gpd->runtime.sbuffer_size;
+ if (totpoints < 3) {
+ return NULL;
+ }
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ ARegion *ar = draw_ctx->ar;
+ ToolSettings *ts = scene->toolsettings;
+ Object *ob = draw_ctx->obact;
+
+ /* get origin to reproject point */
+ float origin[3];
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+
+ int tot_triangles = totpoints - 2;
+ /* allocate memory for temporary areas */
+ uint (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, __func__);
+ float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, __func__);
+
+ /* Convert points to array and triangulate
+ * Here a cache is not used because while drawing the information changes all the time, so the cache
+ * would be recalculated constantly, so it is better to do direct calculation for each function call
+ */
+ for (int i = 0; i < totpoints; i++) {
+ const tGPspoint *pt = &points[i];
+ points2d[i][0] = pt->x;
+ points2d[i][1] = pt->y;
+ }
+ BLI_polyfill_calc(points2d, (uint)totpoints, 0, tmp_triangles);
+
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, color_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ /* draw triangulation data */
+ if (tot_triangles > 0) {
+ GPU_vertbuf_data_alloc(vbo, tot_triangles * 3);
+
+ const tGPspoint *tpt;
+ bGPDspoint pt;
+
+ int idx = 0;
+ for (int i = 0; i < tot_triangles; i++) {
+ for (int j = 0; j < 3; j++) {
+ tpt = &points[tmp_triangles[i][j]];
+ ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
+ GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt.x);
+ GPU_vertbuf_attr_set(vbo, color_id, idx, gpd->runtime.sfill);
+ idx++;
+ }
+ }
+ }
+
+ /* clear memory */
+ if (tmp_triangles) {
+ MEM_freeN(tmp_triangles);
+ }
+ if (points2d) {
+ MEM_freeN(points2d);
+ }
+
+ return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+/* Draw selected verts for strokes being edited */
+void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, float alpha, short dflag)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Object *ob = draw_ctx->obact;
+ bGPdata *gpd = ob->data;
+ bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
+
+ int vgindex = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, vgindex)) {
+ vgindex = -1;
+ }
+
+ /* Get size of verts:
+ * - The selected state needs to be larger than the unselected state so that
+ * they stand out more.
+ * - We use the theme setting for size of the unselected verts
+ */
+ float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
+ float vsize;
+ if ((int)bsize > 8) {
+ vsize = 10.0f;
+ bsize = 8.0f;
+ }
+ else {
+ vsize = bsize + 2;
+ }
+
+ /* for now, we assume that the base color of the points is not too close to the real color */
+ float selectColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
+ selectColor[3] = alpha;
+
+ float unselectColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor);
+ unselectColor[3] = alpha;
+
+ if (be->vbo == NULL) {
+ be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ be->thickness_id = GPU_vertformat_attr_add(&be->format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+
+ be->vbo = GPU_vertbuf_create_with_format(&be->format);
+ GPU_vertbuf_data_alloc(be->vbo, gps->totpoints);
+ be->vbo_len = 0;
+ }
+ gpencil_vbo_ensure_size(be, gps->totpoints);
+
+ /* Draw start and end point differently if enabled stroke direction hint */
+ bool show_direction_hint = (dflag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
+
+ /* Draw all the stroke points (selected or not) */
+ bGPDspoint *pt = gps->points;
+ MDeformVert *dvert = gps->dvert;
+
+ float fcolor[4];
+ float fsize = 0;
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
+ /* weight paint */
+ if (is_weight_paint) {
+ float weight = (dvert && dvert->dw) ? defvert_find_weight(dvert, vgindex) : 0.0f;
+ float hue = 2.0f * (1.0f - weight) / 3.0f;
+ hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
+ selectColor[3] = 1.0f;
+ copy_v4_v4(fcolor, selectColor);
+ fsize = vsize;
+ }
+ else {
+ if (show_direction_hint && i == 0) {
+ /* start point in green bigger */
+ ARRAY_SET_ITEMS(fcolor, 0.0f, 1.0f, 0.0f, 1.0f);
+ fsize = vsize + 4;
+ }
+ else if (show_direction_hint && (i == gps->totpoints - 1)) {
+ /* end point in red smaller */
+ ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f);
+ fsize = vsize + 1;
+ }
+ else if (pt->flag & GP_SPOINT_SELECT) {
+ copy_v4_v4(fcolor, selectColor);
+ fsize = vsize;
+ }
+ else {
+ copy_v4_v4(fcolor, unselectColor);
+ fsize = bsize;
+ }
+ }
+
+ GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
+ GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &fsize);
+ GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
+ be->vbo_len++;
+ if (gps->dvert != NULL) {
+ dvert++;
+ }
+ }
+}
+
+/* Draw lines for strokes being edited */
+void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, float alpha, short UNUSED(dflag))
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Object *ob = draw_ctx->obact;
+ bGPdata *gpd = ob->data;
+ bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
+
+ int vgindex = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, vgindex)) {
+ vgindex = -1;
+ }
+
+ float selectColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
+ selectColor[3] = alpha;
+ float linecolor[4];
+ copy_v4_v4(linecolor, gpd->line_color);
+
+ if (be->vbo == NULL) {
+ be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ be->vbo = GPU_vertbuf_create_with_format(&be->format);
+ GPU_vertbuf_data_alloc(be->vbo, gps->totpoints);
+ be->vbo_len = 0;
+ }
+ gpencil_vbo_ensure_size(be, gps->totpoints);
+
+ /* Draw all the stroke lines (selected or not) */
+ bGPDspoint *pt = gps->points;
+ MDeformVert *dvert = gps->dvert;
+
+ float fcolor[4];
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
+ /* weight paint */
+ if (is_weight_paint) {
+ float weight = (dvert && dvert->dw) ? defvert_find_weight(dvert, vgindex) : 0.0f;
+ float hue = 2.0f * (1.0f - weight) / 3.0f;
+ hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
+ selectColor[3] = 1.0f;
+ copy_v4_v4(fcolor, selectColor);
+ }
+ else {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ copy_v4_v4(fcolor, selectColor);
+ }
+ else {
+ copy_v4_v4(fcolor, linecolor);
+ }
+ }
+
+ GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
+ GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
+ be->vbo_len++;
+
+ if (gps->dvert != NULL) {
+ dvert++;
+ }
+ }
+}
+
+static void set_grid_point(
+ GPUVertBuf *vbo, int idx, float col_grid[4],
+ uint pos_id, uint color_id,
+ float v1, float v2, const int axis)
+{
+ GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid);
+
+ float pos[3];
+ /* Set the grid in the selected axis */
+ switch (axis) {
+ case GP_LOCKAXIS_X:
+ {
+ ARRAY_SET_ITEMS(pos, 0.0f, v1, v2);
+ break;
+ }
+ case GP_LOCKAXIS_Y:
+ {
+ ARRAY_SET_ITEMS(pos, v1, 0.0f, v2);
+ break;
+ }
+ case GP_LOCKAXIS_Z:
+ default: /* view aligned */
+ {
+ ARRAY_SET_ITEMS(pos, v1, v2, 0.0f);
+ break;
+ }
+ }
+
+ GPU_vertbuf_attr_set(vbo, pos_id, idx, pos);
+}
+
+/* Draw grid lines */
+GPUBatch *DRW_gpencil_get_grid(Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *ts = scene->toolsettings;
+ View3D *v3d = draw_ctx->v3d;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool do_center = (gpd->grid.lines <= 0) ? false : true;
+
+ float col_grid[4];
+
+ /* verify we have something to draw and valid values */
+ if (gpd->grid.scale[0] == 0.0f) {
+ gpd->grid.scale[0] = 1.0f;
+ }
+ if (gpd->grid.scale[1] == 0.0f) {
+ gpd->grid.scale[1] = 1.0f;
+ }
+
+ if (v3d->overlay.gpencil_grid_opacity < 0.1f) {
+ v3d->overlay.gpencil_grid_opacity = 0.1f;
+ }
+
+ /* set color */
+ copy_v3_v3(col_grid, gpd->grid.color);
+ col_grid[3] = v3d->overlay.gpencil_grid_opacity;
+
+ const int axis = ts->gp_sculpt.lock_axis;
+
+ const char *grid_unit = NULL;
+ const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
+ const float grid_w = gpd->grid.scale[0] * ED_scene_grid_scale(scene, &grid_unit);
+ const float grid_h = gpd->grid.scale[1] * ED_scene_grid_scale(scene, &grid_unit);
+ const float space_w = (grid_w / gridlines);
+ const float space_h = (grid_h / gridlines);
+ const float offset[2] = { gpd->grid.offset[0], gpd->grid.offset[1] };
+
+ const uint vertex_len = 2 * (gridlines * 4 + 2);
+
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, color_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vertex_len);
+
+ int idx = 0;
+
+ for (int a = 1; a <= gridlines; a++) {
+ const float line_w = a * space_w;
+ const float line_h = a * space_h;
+
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], -line_h + offset[1], axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], -line_h + offset[1], axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], +line_h + offset[1], axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], +line_h + offset[1], axis);
+ idx++;
+
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], -grid_h + offset[1], axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], +grid_h + offset[1], axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], -grid_h + offset[1], axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], +grid_h + offset[1], axis);
+ idx++;
+ }
+ /* center lines */
+ if (do_center) {
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], 0.0f + offset[1], axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], 0.0f + offset[1], axis);
+ idx++;
+
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], -grid_h + offset[1], axis);
+ idx++;
+ set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], +grid_h + offset[1], axis);
+ idx++;
+ }
+ return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
new file mode 100644
index 00000000000..932a6cc3df0
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -0,0 +1,1631 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_draw_utils.c
+ * \ingroup draw
+ */
+
+#include "BLI_polyfill_2d.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_brush.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_image.h"
+#include "BKE_material.h"
+#include "BKE_paint.h"
+
+#include "ED_gpencil.h"
+#include "ED_view3d.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+/* For EvaluationContext... */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "gpencil_engine.h"
+
+/* fill type to communicate to shader */
+#define SOLID 0
+#define GRADIENT 1
+#define RADIAL 2
+#define CHESS 3
+#define TEXTURE 4
+#define PATTERN 5
+
+#define GP_SET_SRC_GPS(src_gps) if (src_gps) src_gps = src_gps->next
+
+/* Get number of vertex for using in GPU VBOs */
+static void gpencil_calc_vertex(
+ GPENCIL_StorageList *stl, tGPencilObjectCache *cache_ob,
+ GpencilBatchCache *cache, bGPdata *gpd,
+ int cfra_eval)
+{
+ Object *ob = cache_ob->ob;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ bGPDframe *gpf = NULL;
+
+ const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
+
+ cache_ob->tot_vertex = 0;
+ cache_ob->tot_triangles = 0;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_HIDE) {
+ continue;
+ }
+
+ /* verify time modifiers */
+ if ((time_remap) && (!stl->storage->simplify_modif)) {
+ int remap_cfra = BKE_gpencil_time_modifier(
+ draw_ctx->depsgraph, draw_ctx->scene, ob, gpl, cfra_eval,
+ stl->storage->is_render);
+ gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
+ }
+ else {
+ gpf = gpl->actframe;
+ }
+
+ if (gpf == NULL) {
+ continue;
+ }
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ cache_ob->tot_vertex += gps->totpoints + 3;
+ cache_ob->tot_triangles += gps->totpoints - 1;
+ }
+ }
+
+ cache->b_fill.tot_vertex = cache_ob->tot_triangles * 3;
+ cache->b_stroke.tot_vertex = cache_ob->tot_vertex;
+ cache->b_point.tot_vertex = cache_ob->tot_vertex;
+
+ /* some modifiers can change the number of points */
+ int factor = 0;
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ /* only modifiers that change size */
+ if (mti && mti->getDuplicationFactor) {
+ factor = mti->getDuplicationFactor(md);
+
+ cache->b_fill.tot_vertex *= factor;
+ cache->b_stroke.tot_vertex *= factor;
+ cache->b_point.tot_vertex *= factor;
+ }
+ }
+}
+
+/* Helper for doing all the checks on whether a stroke can be drawn */
+static bool gpencil_can_draw_stroke(
+ struct MaterialGPencilStyle *gp_style, const bGPDstroke *gps,
+ const bool onion, const bool is_mat_preview)
+{
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL))
+ return false;
+
+ /* if mat preview render always visible */
+ if (is_mat_preview) {
+ return true;
+ }
+
+ /* check if the color is visible */
+ if ((gp_style == NULL) ||
+ (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
+ (onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN)))
+ {
+ return false;
+ }
+
+ /* stroke can be drawn */
+ return true;
+}
+
+/* calc bounding box in 2d using flat projection data */
+static void gpencil_calc_2d_bounding_box(
+ const float(*points2d)[2], int totpoints, float minv[2], float maxv[2])
+{
+ minv[0] = points2d[0][0];
+ minv[1] = points2d[0][1];
+ maxv[0] = points2d[0][0];
+ maxv[1] = points2d[0][1];
+
+ for (int i = 1; i < totpoints; i++) {
+ /* min */
+ if (points2d[i][0] < minv[0]) {
+ minv[0] = points2d[i][0];
+ }
+ if (points2d[i][1] < minv[1]) {
+ minv[1] = points2d[i][1];
+ }
+ /* max */
+ if (points2d[i][0] > maxv[0]) {
+ maxv[0] = points2d[i][0];
+ }
+ if (points2d[i][1] > maxv[1]) {
+ maxv[1] = points2d[i][1];
+ }
+ }
+ /* use a perfect square */
+ if (maxv[0] > maxv[1]) {
+ maxv[1] = maxv[0];
+ }
+ else {
+ maxv[0] = maxv[1];
+ }
+}
+
+/* calc texture coordinates using flat projected points */
+static void gpencil_calc_stroke_fill_uv(
+ const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], float(*r_uv)[2])
+{
+ float d[2];
+ d[0] = maxv[0] - minv[0];
+ d[1] = maxv[1] - minv[1];
+ for (int i = 0; i < totpoints; i++) {
+ r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
+ r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
+ }
+}
+
+/* Get points of stroke always flat to view not affected by camera view or view position */
+static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
+{
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
+
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
+
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
+
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
+
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
+
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+ points2d[i][0] = dot_v3v3(loc, locx);
+ points2d[i][1] = dot_v3v3(loc, locy);
+ }
+
+ /* Concave (-1), Convex (1), or Autodetect (0)? */
+ *r_direction = (int)locy[2];
+}
+
+/* recalc the internal geometry caches for fill and uvs */
+static void DRW_gpencil_recalc_geometry_caches(
+ Object *ob, bGPDlayer *gpl, MaterialGPencilStyle *gp_style, bGPDstroke *gps)
+{
+ if (gps->flag & GP_STROKE_RECALC_CACHES) {
+ /* Calculate triangles cache for filling area (must be done only after changes) */
+ if ((gps->tot_triangles == 0) || (gps->triangles == NULL)) {
+ if ((gps->totpoints > 2) &&
+ ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
+ (gp_style->fill_style > 0) || (gpl->blend_mode != eGplBlendMode_Normal)))
+ {
+ DRW_gpencil_triangulate_stroke_fill(ob, gps);
+ }
+ }
+
+ /* calc uv data along the stroke */
+ ED_gpencil_calc_stroke_uv(ob, gps);
+
+ /* clear flag */
+ gps->flag &= ~GP_STROKE_RECALC_CACHES;
+ }
+}
+
+/* create shading group for filling */
+static DRWShadingGroup *DRW_gpencil_shgroup_fill_create(
+ GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass,
+ GPUShader *shader, bGPdata *gpd, bGPDlayer *gpl,
+ MaterialGPencilStyle *gp_style, int id)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+
+ /* e_data.gpencil_fill_sh */
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+
+ DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1);
+
+ /* set style type */
+ switch (gp_style->fill_style) {
+ case GP_STYLE_FILL_STYLE_SOLID:
+ stl->shgroups[id].fill_style = SOLID;
+ break;
+ case GP_STYLE_FILL_STYLE_GRADIENT:
+ if (gp_style->gradient_type == GP_STYLE_GRADIENT_LINEAR) {
+ stl->shgroups[id].fill_style = GRADIENT;
+ }
+ else {
+ stl->shgroups[id].fill_style = RADIAL;
+ }
+ break;
+ case GP_STYLE_FILL_STYLE_CHESSBOARD:
+ stl->shgroups[id].fill_style = CHESS;
+ break;
+ case GP_STYLE_FILL_STYLE_TEXTURE:
+ if (gp_style->flag & GP_STYLE_FILL_PATTERN) {
+ stl->shgroups[id].fill_style = PATTERN;
+ }
+ else {
+ stl->shgroups[id].fill_style = TEXTURE;
+ }
+ break;
+ default:
+ stl->shgroups[id].fill_style = GP_STYLE_FILL_STYLE_SOLID;
+ break;
+ }
+ DRW_shgroup_uniform_int(grp, "fill_type", &stl->shgroups[id].fill_style, 1);
+
+ DRW_shgroup_uniform_float(grp, "mix_factor", &gp_style->mix_factor, 1);
+
+ DRW_shgroup_uniform_float(grp, "gradient_angle", &gp_style->gradient_angle, 1);
+ DRW_shgroup_uniform_float(grp, "gradient_radius", &gp_style->gradient_radius, 1);
+ DRW_shgroup_uniform_float(grp, "pattern_gridsize", &gp_style->pattern_gridsize, 1);
+ DRW_shgroup_uniform_vec2(grp, "gradient_scale", gp_style->gradient_scale, 1);
+ DRW_shgroup_uniform_vec2(grp, "gradient_shift", gp_style->gradient_shift, 1);
+
+ DRW_shgroup_uniform_float(grp, "texture_angle", &gp_style->texture_angle, 1);
+ DRW_shgroup_uniform_vec2(grp, "texture_scale", gp_style->texture_scale, 1);
+ DRW_shgroup_uniform_vec2(grp, "texture_offset", gp_style->texture_offset, 1);
+ DRW_shgroup_uniform_float(grp, "texture_opacity", &gp_style->texture_opacity, 1);
+ DRW_shgroup_uniform_float(grp, "layer_opacity", &gpl->opacity, 1);
+
+ stl->shgroups[id].texture_mix = gp_style->flag & GP_STYLE_COLOR_TEX_MIX ? 1 : 0;
+ DRW_shgroup_uniform_int(grp, "texture_mix", &stl->shgroups[id].texture_mix, 1);
+
+ stl->shgroups[id].texture_flip = gp_style->flag & GP_STYLE_COLOR_FLIP_FILL ? 1 : 0;
+ DRW_shgroup_uniform_int(grp, "texture_flip", &stl->shgroups[id].texture_flip, 1);
+
+ DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1);
+ /* image texture */
+ if ((gp_style->flag & GP_STYLE_COLOR_TEX_MIX) ||
+ (gp_style->fill_style & GP_STYLE_FILL_STYLE_TEXTURE))
+ {
+ ImBuf *ibuf;
+ Image *image = gp_style->ima;
+ ImageUser iuser = { NULL };
+ void *lock;
+
+ iuser.ok = true;
+
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ else {
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, GL_TEXTURE_2D, true, 0.0);
+ DRW_shgroup_uniform_texture(grp, "myTexture", texture);
+
+ stl->shgroups[id].texture_clamp = gp_style->flag & GP_STYLE_COLOR_TEX_CLAMP ? 1 : 0;
+ DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+ else {
+ /* if no texture defined, need a blank texture to avoid errors in draw manager */
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
+ stl->shgroups[id].texture_clamp = 0;
+ DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
+ }
+
+ return grp;
+}
+
+/* create shading group for strokes */
+DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
+ GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob,
+ bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* e_data.gpencil_stroke_sh */
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+
+ DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
+
+ DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+
+ /* avoid wrong values */
+ if ((gpd) && (gpd->pixfactor == 0)) {
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ }
+
+ /* object scale and depth */
+ if ((ob) && (id > -1)) {
+ stl->shgroups[id].obj_scale = mat4_to_scale(ob->obmat);
+ DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1);
+ stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
+ DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1);
+
+ stl->shgroups[id].stroke_style = gp_style->stroke_style;
+ stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID;
+ if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
+ stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE;
+ if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
+ stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN;
+ }
+ }
+ DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1);
+ DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
+ }
+ else {
+ stl->storage->obj_scale = 1.0f;
+ stl->storage->keep_size = 0;
+ stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1);
+ DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1);
+ DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1);
+ if (gpd) {
+ DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
+ }
+ else {
+ DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
+ }
+ }
+
+ if ((gpd) && (id > -1)) {
+ DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1);
+ }
+ else {
+ /* for drawing always on front */
+ DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
+ }
+
+ /* image texture for pattern */
+ if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
+ ImBuf *ibuf;
+ Image *image = gp_style->sima;
+ ImageUser iuser = { NULL };
+ void *lock;
+
+ iuser.ok = true;
+
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ else {
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true, 0.0f);
+ DRW_shgroup_uniform_texture(grp, "myTexture", texture);
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+ else {
+ /* if no texture defined, need a blank texture to avoid errors in draw manager */
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
+ }
+
+ return grp;
+}
+
+/* create shading group for points */
+static DRWShadingGroup *DRW_gpencil_shgroup_point_create(
+ GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob,
+ bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const float *viewport_size = DRW_viewport_size_get();
+
+ /* e_data.gpencil_stroke_sh */
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
+
+ DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
+ DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
+
+ /* avoid wrong values */
+ if ((gpd) && (gpd->pixfactor == 0)) {
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ }
+
+ /* object scale and depth */
+ if ((ob) && (id > -1)) {
+ stl->shgroups[id].obj_scale = mat4_to_scale(ob->obmat);
+ DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1);
+ stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
+ DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1);
+
+ stl->shgroups[id].mode = gp_style->mode;
+ stl->shgroups[id].stroke_style = gp_style->stroke_style;
+ stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID;
+ if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
+ stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE;
+ if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
+ stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN;
+ }
+ }
+ DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1);
+ DRW_shgroup_uniform_int(grp, "mode", &stl->shgroups[id].mode, 1);
+ DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
+ }
+ else {
+ stl->storage->obj_scale = 1.0f;
+ stl->storage->keep_size = 0;
+ stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR;
+ stl->storage->mode = gp_style->mode;
+ DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1);
+ DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1);
+ DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1);
+ DRW_shgroup_uniform_int(grp, "mode", &stl->storage->mode, 1);
+ if (gpd) {
+ DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
+ }
+ else {
+ DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
+ }
+ }
+
+ if (gpd) {
+ DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&gpd->xray_mode, 1);
+ }
+ else {
+ /* for drawing always on front */
+ DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
+ }
+
+ /* image texture */
+ if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
+ ImBuf *ibuf;
+ Image *image = gp_style->sima;
+ ImageUser iuser = { NULL };
+ void *lock;
+
+ iuser.ok = true;
+
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ else {
+ GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true, 0.0f);
+ DRW_shgroup_uniform_texture(grp, "myTexture", texture);
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+ else {
+ /* if no texture defined, need a blank texture to avoid errors in draw manager */
+ DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
+ }
+
+ return grp;
+}
+
+/* add fill vertex info */
+static void gpencil_add_fill_vertexdata(
+ GpencilBatchCache *cache,
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
+ float opacity, const float tintcolor[4], const bool onion, const bool custonion)
+{
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ if (gps->totpoints >= 3) {
+ float tfill[4];
+ /* set color using material, tint color and opacity */
+ interp_v3_v3v3(tfill, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
+ tfill[3] = gps->runtime.tmp_fill_rgba[3] * opacity;
+ if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
+ (gp_style->fill_style > 0) ||
+ (gpl->blend_mode != eGplBlendMode_Normal))
+ {
+ if (cache->is_dirty) {
+ const float *color;
+ if (!onion) {
+ color = tfill;
+ }
+ else {
+ if (custonion) {
+ color = tintcolor;
+ }
+ else {
+ ARRAY_SET_ITEMS(tfill, UNPACK3(gps->runtime.tmp_fill_rgba), tintcolor[3]);
+ color = tfill;
+ }
+ }
+ /* create vertex data */
+ const int old_len = cache->b_fill.vbo_len;
+ DRW_gpencil_get_fill_geom(&cache->b_fill, ob, gps, color);
+
+ /* add to list of groups */
+ if (old_len < cache->b_fill.vbo_len) {
+ cache->grp_cache = gpencil_group_cache_add(
+ cache->grp_cache, gpl, gpf, gps,
+ eGpencilBatchGroupType_Fill, onion,
+ cache->b_fill.vbo_len,
+ &cache->grp_size, &cache->grp_used);
+ }
+ }
+ }
+ }
+}
+
+/* add stroke vertex info */
+static void gpencil_add_stroke_vertexdata(
+ GpencilBatchCache *cache,
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
+ const float opacity, const float tintcolor[4], const bool onion,
+ const bool custonion)
+{
+ float tcolor[4];
+ float ink[4];
+ short sthickness;
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* set color using base color, tint color and opacity */
+ if (cache->is_dirty) {
+ if (!onion) {
+ /* if special stroke, use fill color as stroke color */
+ if (gps->flag & GP_STROKE_NOFILL) {
+ interp_v3_v3v3(tcolor, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
+ tcolor[3] = gps->runtime.tmp_fill_rgba[3] * opacity;
+ }
+ else {
+ interp_v3_v3v3(tcolor, gps->runtime.tmp_stroke_rgba, tintcolor, tintcolor[3]);
+ tcolor[3] = gps->runtime.tmp_stroke_rgba[3] * opacity;
+ }
+ copy_v4_v4(ink, tcolor);
+ }
+ else {
+ if (custonion) {
+ copy_v4_v4(ink, tintcolor);
+ }
+ else {
+ ARRAY_SET_ITEMS(tcolor, UNPACK3(gps->runtime.tmp_stroke_rgba), opacity);
+ copy_v4_v4(ink, tcolor);
+ }
+ }
+
+ sthickness = gps->thickness + gpl->line_change;
+ CLAMP_MIN(sthickness, 1);
+
+ if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
+ /* create vertex data */
+ const int old_len = cache->b_stroke.vbo_len;
+ DRW_gpencil_get_stroke_geom(&cache->b_stroke, gps, sthickness, ink);
+
+ /* add to list of groups */
+ if (old_len < cache->b_stroke.vbo_len) {
+ cache->grp_cache = gpencil_group_cache_add(
+ cache->grp_cache, gpl, gpf, gps,
+ eGpencilBatchGroupType_Stroke, onion,
+ cache->b_stroke.vbo_len,
+ &cache->grp_size, &cache->grp_used);
+ }
+ }
+ else {
+ /* create vertex data */
+ const int old_len = cache->b_point.vbo_len;
+ DRW_gpencil_get_point_geom(&cache->b_point, gps, sthickness, ink);
+
+ /* add to list of groups */
+ if (old_len < cache->b_point.vbo_len) {
+ cache->grp_cache = gpencil_group_cache_add(
+ cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Point, onion,
+ cache->b_point.vbo_len,
+ &cache->grp_size, &cache->grp_used);
+ }
+ }
+ }
+}
+
+/* add edit points vertex info */
+static void gpencil_add_editpoints_vertexdata(
+ GPENCIL_StorageList *UNUSED(stl), GpencilBatchCache *cache, ToolSettings *UNUSED(ts), Object *ob,
+ bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* alpha factor for edit points/line to make them more subtle */
+ float edit_alpha = v3d->vertex_opacity;
+
+ if (GPENCIL_ANY_EDIT_MODE(gpd)) {
+ Object *obact = DRW_context_state_get()->obact;
+ if ((!obact) || (obact->type != OB_GPENCIL)) {
+ return;
+ }
+ const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
+
+ if (cache->is_dirty) {
+ if ((obact == ob) &&
+ ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES))
+ {
+ /* line of the original stroke */
+ DRW_gpencil_get_edlin_geom(&cache->b_edlin, gps, edit_alpha, gpd->flag);
+
+ /* add to list of groups */
+ cache->grp_cache = gpencil_group_cache_add(
+ cache->grp_cache, gpl, gpf, gps,
+ eGpencilBatchGroupType_Edlin, false,
+ cache->b_edlin.vbo_len,
+ &cache->grp_size, &cache->grp_used);
+ }
+ /* edit points */
+ if ((gps->flag & GP_STROKE_SELECT) || (is_weight_paint)) {
+ if ((gpl->flag & GP_LAYER_UNLOCK_COLOR) || ((gp_style->flag & GP_STYLE_COLOR_LOCKED) == 0)) {
+ if (obact == ob) {
+ DRW_gpencil_get_edit_geom(&cache->b_edit, gps, edit_alpha, gpd->flag);
+
+ /* add to list of groups */
+ cache->grp_cache = gpencil_group_cache_add(
+ cache->grp_cache, gpl, gpf, gps,
+ eGpencilBatchGroupType_Edit, false,
+ cache->b_edit.vbo_len,
+ &cache->grp_size, &cache->grp_used);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* main function to draw strokes */
+static void gpencil_draw_strokes(
+ GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob,
+ bGPdata *gpd, bGPDlayer *gpl, bGPDframe *src_gpf, bGPDframe *derived_gpf,
+ const float opacity, const float tintcolor[4],
+ const bool custonion, tGPencilObjectCache *cache_ob)
+{
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+ bGPDstroke *gps, *src_gps;
+ float viewmatrix[4][4];
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool playing = stl->storage->is_playing;
+ const bool is_render = (bool)stl->storage->is_render;
+ const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
+ const bool overlay_multiedit = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) : true;
+
+ /* Get evaluation context */
+ /* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files
+ * (i.e. the thumbnail offscreen rendering fails)
+ */
+ Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
+
+ /* get parent matrix and save as static data */
+ ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
+ copy_m4_m4(derived_gpf->runtime.viewmatrix, viewmatrix);
+
+ if ((cache_ob != NULL) && (cache_ob->is_dup_ob)) {
+ copy_m4_m4(derived_gpf->runtime.viewmatrix, cache_ob->obmat);
+ }
+
+ /* apply geometry modifiers */
+ if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) {
+ if (!stl->storage->simplify_modif) {
+ if (BKE_gpencil_has_geometry_modifiers(ob)) {
+ BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, derived_gpf, stl->storage->is_render);
+ }
+ }
+ }
+
+ if (src_gpf) {
+ src_gps = src_gpf->strokes.first;
+ }
+ else {
+ src_gps = NULL;
+ }
+
+ for (gps = derived_gpf->strokes.first; gps; gps = gps->next) {
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* check if stroke can be drawn */
+ if (gpencil_can_draw_stroke(gp_style, gps, false, is_mat_preview) == false) {
+ GP_SET_SRC_GPS(src_gps);
+ continue;
+ }
+
+ /* be sure recalc all cache in source stroke to avoid recalculation when frame change
+ * and improve fps */
+ if (src_gps) {
+ DRW_gpencil_recalc_geometry_caches(ob, gpl, gp_style, src_gps);
+ }
+
+ /* if the fill has any value, it's considered a fill and is not drawn if simplify fill is enabled */
+ if ((stl->storage->simplify_fill) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_REMOVE_FILL_LINE)) {
+ if ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
+ (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID) ||
+ (gpl->blend_mode != eGplBlendMode_Normal))
+ {
+ GP_SET_SRC_GPS(src_gps);
+ continue;
+ }
+ }
+
+ if ((gpl->actframe->framenum == derived_gpf->framenum) ||
+ (!is_multiedit) || (overlay_multiedit))
+ {
+ /* copy color to temp fields to apply temporal changes in the stroke */
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ /* apply modifiers (only modify geometry, but not create ) */
+ if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) {
+ if (!stl->storage->simplify_modif) {
+ BKE_gpencil_stroke_modifiers(depsgraph, ob, gpl, derived_gpf, gps, stl->storage->is_render);
+ }
+ }
+
+ /* hide any blend layer */
+ if ((!stl->storage->simplify_blend) ||
+ (gpl->blend_mode == eGplBlendMode_Normal))
+ {
+ /* fill */
+ if ((gp_style->flag & GP_STYLE_FILL_SHOW) &&
+ (!stl->storage->simplify_fill) &&
+ ((gps->flag & GP_STROKE_NOFILL) == 0))
+ {
+ gpencil_add_fill_vertexdata(
+ cache, ob, gpl, derived_gpf, gps,
+ opacity, tintcolor, false, custonion);
+ }
+ /* stroke */
+ if ((gp_style->flag & GP_STYLE_STROKE_SHOW) &&
+ ((gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
+ (gpl->blend_mode == eGplBlendMode_Normal)))
+ {
+ gpencil_add_stroke_vertexdata(
+ cache, ob, gpl, derived_gpf, gps,
+ opacity, tintcolor, false, custonion);
+ }
+ }
+ }
+
+ /* edit points (only in edit mode and not play animation not render) */
+ if ((draw_ctx->obact == ob) && (src_gps) &&
+ (!playing) && (!is_render) && (!cache_ob->is_dup_ob))
+ {
+ if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
+ if (!stl->g_data->shgrps_edit_line) {
+ stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh, psl->edit_pass);
+ }
+ if (!stl->g_data->shgrps_edit_point) {
+ stl->g_data->shgrps_edit_point = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->edit_pass);
+ const float *viewport_size = DRW_viewport_size_get();
+ DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1);
+ }
+
+ gpencil_add_editpoints_vertexdata(stl, cache, ts, ob, gpd, gpl, derived_gpf, src_gps);
+ }
+ }
+
+ GP_SET_SRC_GPS(src_gps);
+ }
+}
+
+/* get alpha factor for onion strokes */
+static void gpencil_get_onion_alpha(float color[4], bGPdata *gpd)
+{
+#define MIN_ALPHA_VALUE 0.01f
+
+ /* if fade is disabled, opacity is equal in all frames */
+ if ((gpd->onion_flag & GP_ONION_FADE) == 0) {
+ color[3] = gpd->onion_factor;
+ }
+ else {
+ /* add override opacity factor */
+ color[3] += gpd->onion_factor - 0.5f;
+ }
+
+ CLAMP(color[3], MIN_ALPHA_VALUE, 1.0f);
+}
+
+/* function to draw strokes for onion only */
+static void gpencil_draw_onion_strokes(
+ GpencilBatchCache *cache, GPENCIL_e_data *UNUSED(e_data), void *vedata, Object *ob,
+ bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf,
+ const float opacity, const float tintcolor[4], const bool custonion)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
+
+ float viewmatrix[4][4];
+
+ /* get parent matrix and save as static data */
+ ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
+ copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ int id = stl->storage->shgroup_id;
+ /* check if stroke can be drawn */
+ if (gpencil_can_draw_stroke(gp_style, gps, true, false) == false) {
+ continue;
+ }
+ /* limit the number of shading groups */
+ if (id >= GPENCIL_MAX_SHGROUPS) {
+ continue;
+ }
+
+ /* stroke */
+ gpencil_add_stroke_vertexdata(
+ cache, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion);
+
+ stl->storage->shgroup_id++;
+ }
+}
+
+/* draw onion-skinning for a layer */
+static void gpencil_draw_onionskins(
+ GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata,
+ Object *ob, bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf)
+{
+
+ const float default_color[3] = { UNPACK3(U.gpencil_new_layer_col) };
+ const float alpha = 1.0f;
+ float color[4];
+ int idx;
+ float fac = 1.0f;
+ int step = 0;
+ int mode = 0;
+ bool colflag = false;
+ bGPDframe *gpf_loop = NULL;
+ int last = gpf->framenum;
+
+ colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL;
+
+ /* -------------------------------
+ * 1) Draw Previous Frames First
+ * ------------------------------- */
+ step = gpd->gstep;
+ mode = gpd->onion_mode;
+
+ if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) {
+ copy_v3_v3(color, gpd->gcolor_prev);
+ }
+ else {
+ copy_v3_v3(color, default_color);
+ }
+
+ idx = 0;
+ for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) {
+ /* only selected frames */
+ if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) {
+ continue;
+ }
+ /* absolute range */
+ if (mode == GP_ONION_MODE_ABSOLUTE) {
+ if ((gpf->framenum - gf->framenum) > step) {
+ break;
+ }
+ }
+ /* relative range */
+ if (mode == GP_ONION_MODE_RELATIVE) {
+ idx++;
+ if (idx > step) {
+ break;
+ }
+
+ }
+ /* alpha decreases with distance from curframe index */
+ if (mode != GP_ONION_MODE_SELECTED) {
+ if (mode == GP_ONION_MODE_ABSOLUTE) {
+ fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(step + 1));
+ }
+ else {
+ fac = 1.0f - ((float)idx / (float)(step + 1));
+ }
+ color[3] = alpha * fac * 0.66f;
+ }
+ else {
+ idx++;
+ fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f);
+ color[3] = fac;
+ }
+
+ /* if loop option, save the frame to use later */
+ if ((mode != GP_ONION_MODE_ABSOLUTE) && (gpd->onion_flag & GP_ONION_LOOP)) {
+ gpf_loop = gf;
+ }
+
+ gpencil_get_onion_alpha(color, gpd);
+ gpencil_draw_onion_strokes(cache, e_data, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
+ }
+ /* -------------------------------
+ * 2) Now draw next frames
+ * ------------------------------- */
+ step = gpd->gstep_next;
+ mode = gpd->onion_mode;
+
+ if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) {
+ copy_v3_v3(color, gpd->gcolor_next);
+ }
+ else {
+ copy_v3_v3(color, default_color);
+ }
+
+ idx = 0;
+ for (bGPDframe *gf = gpf->next; gf; gf = gf->next) {
+ /* only selected frames */
+ if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) {
+ continue;
+ }
+ /* absolute range */
+ if (mode == GP_ONION_MODE_ABSOLUTE) {
+ if ((gf->framenum - gpf->framenum) > step) {
+ break;
+ }
+ }
+ /* relative range */
+ if (mode == GP_ONION_MODE_RELATIVE) {
+ idx++;
+ if (idx > step) {
+ break;
+ }
+
+ }
+ /* alpha decreases with distance from curframe index */
+ if (mode != GP_ONION_MODE_SELECTED) {
+ if (mode == GP_ONION_MODE_ABSOLUTE) {
+ fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(step + 1));
+ }
+ else {
+ fac = 1.0f - ((float)idx / (float)(step + 1));
+ }
+ color[3] = alpha * fac * 0.66f;
+ }
+ else {
+ idx++;
+ fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f);
+ color[3] = fac;
+ }
+
+ gpencil_get_onion_alpha(color, gpd);
+ gpencil_draw_onion_strokes(cache, e_data, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
+ if (last < gf->framenum) {
+ last = gf->framenum;
+ }
+ }
+
+ /* Draw first frame in blue for loop mode */
+ if ((gpd->onion_flag & GP_ONION_LOOP) && (gpf_loop != NULL)) {
+ if ((last == gpf->framenum) || (gpf->next == NULL)) {
+ gpencil_get_onion_alpha(color, gpd);
+ gpencil_draw_onion_strokes(
+ cache, e_data, vedata, ob, gpd, gpl,
+ gpf_loop, color[3], color, colflag);
+ }
+ }
+}
+
+static void gpencil_copy_frame(bGPDframe *gpf, bGPDframe *derived_gpf)
+{
+ derived_gpf->prev = gpf->prev;
+ derived_gpf->next = gpf->next;
+ derived_gpf->framenum = gpf->framenum;
+ derived_gpf->flag = gpf->flag;
+ derived_gpf->key_type = gpf->key_type;
+ derived_gpf->runtime = gpf->runtime;
+ copy_m4_m4(derived_gpf->runtime.viewmatrix, gpf->runtime.viewmatrix);
+
+ /* copy strokes */
+ BLI_listbase_clear(&derived_gpf->strokes);
+ for (bGPDstroke *gps_src = gpf->strokes.first; gps_src; gps_src = gps_src->next) {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+ BLI_addtail(&derived_gpf->strokes, gps_dst);
+ }
+}
+
+/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
+void DRW_gpencil_triangulate_stroke_fill(Object *ob, bGPDstroke *gps)
+{
+ BLI_assert(gps->totpoints >= 3);
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ /* allocate memory for temporary areas */
+ gps->tot_triangles = gps->totpoints - 2;
+ uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
+ float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
+ float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
+
+ int direction = 0;
+
+ /* convert to 2d and triangulate */
+ gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
+ BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
+
+ /* calc texture coordinates automatically */
+ float minv[2];
+ float maxv[2];
+ /* first needs bounding box data */
+ if (gpd->flag & GP_DATA_UV_ADAPTATIVE) {
+ gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv);
+ }
+ else {
+ ARRAY_SET_ITEMS(minv, -1.0f, -1.0f);
+ ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f);
+ }
+
+ /* calc uv data */
+ gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv);
+
+ /* Number of triangles */
+ gps->tot_triangles = gps->totpoints - 2;
+ /* save triangulation data in stroke cache */
+ if (gps->tot_triangles > 0) {
+ if (gps->triangles == NULL) {
+ gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation");
+ }
+ else {
+ gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
+ }
+
+ for (int i = 0; i < gps->tot_triangles; i++) {
+ bGPDtriangle *stroke_triangle = &gps->triangles[i];
+ memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
+ /* copy texture coordinates */
+ copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
+ copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
+ copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
+ }
+ }
+ else {
+ /* No triangles needed - Free anything allocated previously */
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+
+ gps->triangles = NULL;
+ }
+
+ /* disable recalculation flag */
+ if (gps->flag & GP_STROKE_RECALC_CACHES) {
+ gps->flag &= ~GP_STROKE_RECALC_CACHES;
+ }
+
+ /* clear memory */
+ MEM_SAFE_FREE(tmp_triangles);
+ MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(uv);
+}
+
+/* draw stroke in drawing buffer */
+void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob)
+{
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ bGPdata *gpd_eval = ob->data;
+ /* need the original to avoid cow overhead while drawing */
+ bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
+
+ MaterialGPencilStyle *gp_style = NULL;
+
+ float obscale = mat4_to_scale(ob->obmat);
+
+ /* use the brush material */
+ Material *ma = BKE_gpencil_get_material_from_brush(brush);
+ if (ma != NULL) {
+ gp_style = ma->gp_style;
+ }
+ /* this is not common, but avoid any special situations when brush could be without material */
+ if (gp_style == NULL) {
+ gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
+ }
+
+ /* drawing strokes */
+ /* Check if may need to draw the active stroke cache, only if this layer is the active layer
+ * that is being edited. (Stroke buffer is currently stored in gp-data)
+ */
+ if (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 0)) {
+ if ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ /* It should also be noted that sbuffer contains temporary point types
+ * i.e. tGPspoints NOT bGPDspoints
+ */
+ short lthick = brush->size * obscale;
+ /* if only one point, don't need to draw buffer because the user has no time to see it */
+ if (gpd->runtime.sbuffer_size > 1) {
+ if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
+ stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create(
+ e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false);
+ }
+ else {
+ stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create(
+ e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false);
+ }
+
+ /* clean previous version of the batch */
+ if (stl->storage->buffer_stroke) {
+ GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_stroke);
+ MEM_SAFE_FREE(e_data->batch_buffer_stroke);
+ stl->storage->buffer_stroke = false;
+ }
+
+ /* use unit matrix because the buffer is in screen space and does not need conversion */
+ if (gpd->runtime.mode == GP_STYLE_MODE_LINE) {
+ e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_stroke_geom(
+ gpd, lthick);
+ }
+ else {
+ e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom(
+ gpd, lthick);
+ }
+
+ if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
+ DRW_shgroup_call_add(
+ stl->g_data->shgrps_drawing_stroke,
+ e_data->batch_buffer_stroke,
+ stl->storage->unit_matrix);
+ }
+
+ if ((gpd->runtime.sbuffer_size >= 3) &&
+ (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) &&
+ ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_DISSABLE_LASSO) == 0) &&
+ (gp_style->flag & GP_STYLE_FILL_SHOW))
+ {
+ /* if not solid, fill is simulated with solid color */
+ if (gpd->runtime.bfill_style > 0) {
+ gpd->runtime.sfill[3] = 0.5f;
+ }
+ stl->g_data->shgrps_drawing_fill = DRW_shgroup_create(
+ e_data->gpencil_drawing_fill_sh, psl->drawing_pass);
+
+ /* clean previous version of the batch */
+ if (stl->storage->buffer_fill) {
+ GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_fill);
+ MEM_SAFE_FREE(e_data->batch_buffer_fill);
+ stl->storage->buffer_fill = false;
+ }
+
+ e_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd);
+ DRW_shgroup_call_add(
+ stl->g_data->shgrps_drawing_fill,
+ e_data->batch_buffer_fill,
+ stl->storage->unit_matrix);
+ stl->storage->buffer_fill = true;
+ }
+ stl->storage->buffer_stroke = true;
+ }
+ }
+ }
+}
+
+/* create all missing batches */
+static void DRW_gpencil_create_batches(GpencilBatchCache *cache)
+{
+ if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) {
+ cache->b_point.batch = GPU_batch_create_ex(GPU_PRIM_POINTS, cache->b_point.vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ if ((cache->b_stroke.vbo) && (cache->b_stroke.batch == NULL)) {
+ cache->b_stroke.batch = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, cache->b_stroke.vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ if ((cache->b_fill.vbo) && (cache->b_fill.batch == NULL)) {
+ cache->b_fill.batch = GPU_batch_create_ex(GPU_PRIM_TRIS, cache->b_fill.vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ if ((cache->b_edit.vbo) && (cache->b_edit.batch == NULL)) {
+ cache->b_edit.batch = GPU_batch_create_ex(GPU_PRIM_POINTS, cache->b_edit.vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ if ((cache->b_edlin.vbo) && (cache->b_edlin.batch == NULL)) {
+ cache->b_edlin.batch = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, cache->b_edlin.vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+}
+
+/* create all shading groups */
+static void DRW_gpencil_shgroups_create(
+ GPENCIL_e_data *e_data, void *vedata,
+ Object *ob,
+ GpencilBatchCache *cache, tGPencilObjectCache *cache_ob)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ GpencilBatchGroup *elm = NULL;
+ DRWShadingGroup *shgrp = NULL;
+ tGPencilObjectCache_shgrp *array_elm = NULL;
+
+ bGPDlayer *gpl = NULL;
+ bGPDlayer *gpl_prev = NULL;
+ int idx = 0;
+ bool tag_first = false;
+
+ int start_stroke = 0;
+ int start_point = 0;
+ int start_fill = 0;
+ int start_edit = 0;
+ int start_edlin = 0;
+
+ for (int i = 0; i < cache->grp_used; i++) {
+ elm = &cache->grp_cache[i];
+ array_elm = &cache_ob->shgrp_array[idx];
+
+ /* save last group when change */
+ if (gpl_prev == NULL) {
+ gpl_prev = elm->gpl;
+ tag_first = true;
+ }
+ else {
+ if (elm->gpl != gpl_prev) {
+ /* first layer is always blend Normal */
+ array_elm->mode = idx == 0 ? eGplBlendMode_Normal: gpl->blend_mode;
+ array_elm->end_shgrp = shgrp;
+ gpl_prev = elm->gpl;
+ tag_first = true;
+ idx++;
+ }
+ }
+
+ gpl = elm->gpl;
+ bGPDframe *gpf = elm->gpf;
+ bGPDstroke *gps = elm->gps;
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* limit the number of shading groups */
+ if (i >= GPENCIL_MAX_SHGROUPS) {
+ break;
+ }
+
+ switch (elm->type) {
+ case eGpencilBatchGroupType_Stroke:
+ {
+ const int len = elm->vertex_idx - start_stroke;
+
+ shgrp = DRW_gpencil_shgroup_stroke_create(
+ e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh,
+ ob, gpd, gp_style, stl->storage->shgroup_id, elm->onion);
+
+ DRW_shgroup_call_range_add(
+ shgrp, cache->b_stroke.batch,
+ (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+ start_stroke, len);
+
+ stl->storage->shgroup_id++;
+ start_stroke = elm->vertex_idx;
+ break;
+ }
+ case eGpencilBatchGroupType_Point:
+ {
+ const int len = elm->vertex_idx - start_point;
+
+ shgrp = DRW_gpencil_shgroup_point_create(
+ e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh,
+ ob, gpd, gp_style, stl->storage->shgroup_id, elm->onion);
+
+ DRW_shgroup_call_range_add(
+ shgrp, cache->b_point.batch,
+ (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+ start_point, len);
+
+ stl->storage->shgroup_id++;
+ start_point = elm->vertex_idx;
+ break;
+ }
+ case eGpencilBatchGroupType_Fill:
+ {
+ const int len = elm->vertex_idx - start_fill;
+
+ shgrp = DRW_gpencil_shgroup_fill_create(
+ e_data, vedata, psl->stroke_pass, e_data->gpencil_fill_sh,
+ gpd, gpl, gp_style, stl->storage->shgroup_id);
+
+ DRW_shgroup_call_range_add(
+ shgrp, cache->b_fill.batch,
+ (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+ start_fill, len);
+
+ stl->storage->shgroup_id++;
+ start_fill = elm->vertex_idx;
+ break;
+ }
+ case eGpencilBatchGroupType_Edit:
+ {
+ const int len = elm->vertex_idx - start_edit;
+ /* use always the same group */
+ DRW_shgroup_call_range_add(
+ stl->g_data->shgrps_edit_point,
+ cache->b_edit.batch,
+ (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+ start_edit, len);
+
+ start_edit = elm->vertex_idx;
+ break;
+ }
+ case eGpencilBatchGroupType_Edlin:
+ {
+ const int len = elm->vertex_idx - start_edlin;
+ /* use always the same group */
+ DRW_shgroup_call_range_add(
+ stl->g_data->shgrps_edit_line,
+ cache->b_edlin.batch,
+ (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat,
+ start_edlin, len);
+
+ start_edlin = elm->vertex_idx;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ /* save first group */
+ if ((shgrp != NULL) && (tag_first)) {
+ array_elm = &cache_ob->shgrp_array[idx];
+ array_elm->mode = idx == 0 ? eGplBlendMode_Normal: gpl->blend_mode;
+ array_elm->clamp_layer = gpl->flag & GP_LAYER_USE_MASK;
+ array_elm->blend_opacity = gpl->opacity;
+ array_elm->init_shgrp = shgrp;
+ cache_ob->tot_layers++;
+
+ tag_first = false;
+ }
+ }
+
+ /* save last group */
+ if (shgrp != NULL) {
+ array_elm->mode = idx == 0 ? eGplBlendMode_Normal : gpl->blend_mode;
+ array_elm->end_shgrp = shgrp;
+ }
+}
+/* populate a datablock for multiedit (no onions, no modifiers) */
+void DRW_gpencil_populate_multiedit(
+ GPENCIL_e_data *e_data, void *vedata, Object *ob,
+ tGPencilObjectCache *cache_ob)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDframe *gpf = NULL;
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *ts = scene->toolsettings;
+
+ /* check if playing animation */
+ bool playing = stl->storage->is_playing;
+
+ /* calc max size of VBOs */
+ gpencil_calc_vertex(stl, cache_ob, cache, gpd, cfra_eval);
+
+ /* draw strokes */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* don't draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* list of frames to draw */
+ if (!playing) {
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ts, ob, gpd, gpl, gpf, gpf,
+ gpl->opacity, gpl->tintcolor, false, cache_ob);
+ }
+ }
+ }
+ else {
+ gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+ if (gpf) {
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ts, ob, gpd, gpl, gpf, gpf,
+ gpl->opacity, gpl->tintcolor, false, cache_ob);
+ }
+ }
+
+ }
+
+ /* create batchs and shading groups */
+ DRW_gpencil_create_batches(cache);
+ DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
+
+ cache->is_dirty = false;
+}
+
+/* helper for populate a complete grease pencil datablock */
+void DRW_gpencil_populate_datablock(
+ GPENCIL_e_data *e_data, void *vedata,
+ Object *ob,
+ tGPencilObjectCache *cache_ob)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const ViewLayer *view_layer = DEG_get_evaluated_view_layer(draw_ctx->depsgraph);
+ Scene *scene = draw_ctx->scene;
+
+ bGPdata *gpd_eval = (bGPdata *)ob->data;
+ bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
+
+ View3D *v3d = draw_ctx->v3d;
+ int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ ToolSettings *ts = scene->toolsettings;
+
+ bGPDframe *derived_gpf = NULL;
+ const bool main_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true;
+ const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion;
+ const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) : true;
+ const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
+
+ float opacity;
+ bGPDframe *gpf = NULL;
+ bGPDlayer *gpl_active = BKE_gpencil_layer_getactive(gpd);
+
+ /* check if playing animation */
+ bool playing = stl->storage->is_playing;
+
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
+
+ /* if object is duplicate, only create shading groups */
+ if (cache_ob->is_dup_ob) {
+ DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
+ return;
+ }
+
+ /* calc max size of VBOs */
+ gpencil_calc_vertex(stl, cache_ob, cache, gpd, cfra_eval);
+
+ /* init general modifiers data */
+ if (!stl->storage->simplify_modif) {
+ if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) {
+ BKE_gpencil_lattice_init(ob);
+ }
+ }
+ /* draw normal strokes */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* don't draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE) {
+ continue;
+ }
+
+ /* filter view layer to gp layers in the same view layer (for compo) */
+ if ((stl->storage->is_render) && (gpl->viewlayername[0] != '\0')) {
+ if (!STREQ(view_layer->name, gpl->viewlayername)) {
+ continue;
+ }
+ }
+
+ /* remap time */
+ int remap_cfra = cfra_eval;
+ if ((time_remap) && (!stl->storage->simplify_modif)) {
+ remap_cfra = BKE_gpencil_time_modifier(
+ draw_ctx->depsgraph, scene, ob, gpl, cfra_eval,
+ stl->storage->is_render);
+ }
+
+ gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
+ if (gpf == NULL)
+ continue;
+
+ opacity = gpl->opacity;
+ /* if pose mode, maybe the overlay to fade geometry is enabled */
+ if ((draw_ctx->obact) && (draw_ctx->object_mode == OB_MODE_POSE) &&
+ (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT))
+ {
+ opacity = opacity * v3d->overlay.xray_alpha_bone;
+ }
+ /* fade no active layers */
+ if ((overlay) && (draw_ctx->object_mode == OB_MODE_GPENCIL_PAINT) &&
+ (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) &&
+ (draw_ctx->obact) && (draw_ctx->obact == ob) &&
+ (gpl != gpl_active))
+ {
+ opacity = opacity * v3d->overlay.gpencil_fade_layer;
+ }
+
+ /* create derived frames array data or expand */
+ int derived_idx = BLI_findindex(&gpd->layers, gpl);
+ derived_gpf = &cache->derived_array[derived_idx];
+
+ /* if no derived frame or dirty cache, create a new one */
+ if ((derived_gpf == NULL) || (cache->is_dirty)) {
+ if (derived_gpf != NULL) {
+ /* first clear temp data */
+ BKE_gpencil_free_frame_runtime_data(derived_gpf);
+ }
+ /* create new data (do not assign new memory)*/
+ gpencil_copy_frame(gpf, derived_gpf);
+ }
+
+ /* draw onion skins */
+ if (!ID_IS_LINKED(&gpd->id)) {
+ if ((gpd->flag & GP_DATA_SHOW_ONIONSKINS) &&
+ (do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
+ ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)) &&
+ (!cache_ob->is_dup_ob) && (gpd->id.us <= 1))
+ {
+ if (((!stl->storage->is_render) && (overlay)) ||
+ ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)))
+ {
+ gpencil_draw_onionskins(cache, e_data, vedata, ob, gpd, gpl, gpf);
+ }
+ }
+ }
+ /* draw normal strokes */
+ gpencil_draw_strokes(
+ cache, e_data, vedata, ts, ob, gpd, gpl, gpf, derived_gpf,
+ opacity, gpl->tintcolor, false, cache_ob);
+ }
+
+ /* clear any lattice data */
+ if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) {
+ BKE_gpencil_lattice_clear(ob);
+ }
+
+ /* create batchs and shading groups */
+ DRW_gpencil_create_batches(cache);
+ DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
+
+ cache->is_dirty = false;
+}
+
+void DRW_gpencil_populate_particles(GPENCIL_e_data *e_data, void *vedata)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+
+ /* add particles */
+ for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
+ tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
+ Object *ob = cache_ob->ob;
+ if (cache_ob->is_dup_ob) {
+ GpencilBatchCache *cache = ob->runtime.gpencil_cache;
+ DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
+ }
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
new file mode 100644
index 00000000000..483d6a80991
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -0,0 +1,924 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_engine.c
+ * \ingroup draw
+ */
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_gpencil.h"
+#include "BKE_shader_fx.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_view3d_types.h"
+
+#include "draw_mode_engines.h"
+
+#include "UI_resources.h"
+
+#include "GPU_texture.h"
+
+#include "gpencil_engine.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_screen.h"
+#include "ED_gpencil.h"
+
+#include "WM_api.h"
+
+extern char datatoc_gpencil_fill_vert_glsl[];
+extern char datatoc_gpencil_fill_frag_glsl[];
+extern char datatoc_gpencil_stroke_vert_glsl[];
+extern char datatoc_gpencil_stroke_geom_glsl[];
+extern char datatoc_gpencil_stroke_frag_glsl[];
+extern char datatoc_gpencil_zdepth_mix_frag_glsl[];
+extern char datatoc_gpencil_simple_mix_frag_glsl[];
+extern char datatoc_gpencil_point_vert_glsl[];
+extern char datatoc_gpencil_point_geom_glsl[];
+extern char datatoc_gpencil_point_frag_glsl[];
+extern char datatoc_gpencil_background_frag_glsl[];
+extern char datatoc_gpencil_paper_frag_glsl[];
+extern char datatoc_gpencil_edit_point_vert_glsl[];
+extern char datatoc_gpencil_edit_point_geom_glsl[];
+extern char datatoc_gpencil_edit_point_frag_glsl[];
+extern char datatoc_gpencil_blend_frag_glsl[];
+
+/* *********** STATIC *********** */
+static GPENCIL_e_data e_data = {NULL}; /* Engine data */
+
+/* *********** FUNCTIONS *********** */
+
+/* create a multisample buffer if not present */
+void DRW_gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h)
+{
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
+
+ short samples = stl->storage->multisamples;
+
+ if (samples > 0) {
+ if (!fbl->multisample_fb) {
+ fbl->multisample_fb = GPU_framebuffer_create();
+ if (fbl->multisample_fb) {
+ if (txl->multisample_color == NULL) {
+ txl->multisample_color = GPU_texture_create_2D_multisample(
+ rect_w, rect_h, GPU_RGBA16F, NULL, samples, NULL);
+ }
+ if (txl->multisample_depth == NULL) {
+ txl->multisample_depth = GPU_texture_create_2D_multisample(
+ rect_w, rect_h, GPU_DEPTH24_STENCIL8, NULL, samples, NULL);
+ }
+ GPU_framebuffer_ensure_config(
+ &fbl->multisample_fb, {
+ GPU_ATTACHMENT_TEXTURE(txl->multisample_depth),
+ GPU_ATTACHMENT_TEXTURE(txl->multisample_color)
+ });
+ }
+ }
+ }
+}
+
+static void GPENCIL_create_framebuffers(void *vedata)
+{
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+
+ /* Go full 32bits for rendering */
+ GPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F;
+
+ if (DRW_state_is_fbo()) {
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = { (int)viewport_size[0], (int)viewport_size[1] };
+
+ /* create multiframe framebuffer for AA */
+ if (stl->storage->multisamples > 0) {
+ DRW_gpencil_multisample_ensure(vedata, size[0], size[1]);
+ }
+
+ /* temp textures */
+ e_data.temp_depth_tx_a = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ e_data.temp_color_tx_a = DRW_texture_pool_query_2D(size[0], size[1], fb_format,
+ &draw_engine_gpencil_type);
+ GPU_framebuffer_ensure_config(
+ &fbl->temp_fb_a, {
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_a),
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_a)
+ });
+
+ e_data.temp_depth_tx_b = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ e_data.temp_color_tx_b = DRW_texture_pool_query_2D(
+ size[0], size[1], fb_format,
+ &draw_engine_gpencil_type);
+ GPU_framebuffer_ensure_config(
+ &fbl->temp_fb_b, {
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_b),
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_b)
+ });
+
+ /* used for rim and shadow FX effects */
+ e_data.temp_depth_tx_fx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ e_data.temp_color_tx_fx = DRW_texture_pool_query_2D(
+ size[0], size[1], fb_format,
+ &draw_engine_gpencil_type);
+ GPU_framebuffer_ensure_config(
+ &fbl->temp_fb_fx, {
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_fx),
+ GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_fx),
+ });
+
+ /* background framebuffer to speed up drawing process (always 16 bits) */
+ e_data.background_depth_tx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ e_data.background_color_tx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_RGBA32F,
+ &draw_engine_gpencil_type);
+ GPU_framebuffer_ensure_config(
+ &fbl->background_fb, {
+ GPU_ATTACHMENT_TEXTURE(e_data.background_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.background_color_tx)
+ });
+ }
+}
+
+static void GPENCIL_create_shaders(void)
+{
+ /* normal fill shader */
+ if (!e_data.gpencil_fill_sh) {
+ e_data.gpencil_fill_sh = DRW_shader_create(
+ datatoc_gpencil_fill_vert_glsl, NULL,
+ datatoc_gpencil_fill_frag_glsl, NULL);
+ }
+
+ /* normal stroke shader using geometry to display lines (line mode) */
+ if (!e_data.gpencil_stroke_sh) {
+ e_data.gpencil_stroke_sh = DRW_shader_create(
+ datatoc_gpencil_stroke_vert_glsl,
+ datatoc_gpencil_stroke_geom_glsl,
+ datatoc_gpencil_stroke_frag_glsl,
+ NULL);
+ }
+
+ /* dot/rectangle mode for normal strokes using geometry */
+ if (!e_data.gpencil_point_sh) {
+ e_data.gpencil_point_sh = DRW_shader_create(
+ datatoc_gpencil_point_vert_glsl,
+ datatoc_gpencil_point_geom_glsl,
+ datatoc_gpencil_point_frag_glsl,
+ NULL);
+ }
+ /* used for edit points or strokes with one point only */
+ if (!e_data.gpencil_edit_point_sh) {
+ e_data.gpencil_edit_point_sh = DRW_shader_create(
+ datatoc_gpencil_edit_point_vert_glsl,
+ datatoc_gpencil_edit_point_geom_glsl,
+ datatoc_gpencil_edit_point_frag_glsl, NULL);
+ }
+
+ /* used for edit lines for edit modes */
+ if (!e_data.gpencil_line_sh) {
+ e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ }
+
+ /* used to filling during drawing */
+ if (!e_data.gpencil_drawing_fill_sh) {
+ e_data.gpencil_drawing_fill_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
+ }
+
+ /* full screen for mix zdepth*/
+ if (!e_data.gpencil_fullscreen_sh) {
+ e_data.gpencil_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_zdepth_mix_frag_glsl, NULL);
+ }
+ if (!e_data.gpencil_simple_fullscreen_sh) {
+ e_data.gpencil_simple_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_simple_mix_frag_glsl, NULL);
+ }
+
+ /* blend */
+ if (!e_data.gpencil_blend_fullscreen_sh) {
+ e_data.gpencil_blend_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_blend_frag_glsl, NULL);
+ }
+
+ /* shaders for use when drawing */
+ if (!e_data.gpencil_background_sh) {
+ e_data.gpencil_background_sh = DRW_shader_create_fullscreen(datatoc_gpencil_background_frag_glsl, NULL);
+ }
+ if (!e_data.gpencil_paper_sh) {
+ e_data.gpencil_paper_sh = DRW_shader_create_fullscreen(datatoc_gpencil_paper_frag_glsl, NULL);
+ }
+}
+
+void GPENCIL_engine_init(void *vedata)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ /* init storage */
+ if (!stl->storage) {
+ stl->storage = MEM_callocN(sizeof(GPENCIL_Storage), "GPENCIL_Storage");
+
+ /* unit matrix */
+ unit_m4(stl->storage->unit_matrix);
+ }
+
+ stl->storage->multisamples = U.gpencil_multisamples;
+
+ /* create framebuffers */
+ GPENCIL_create_framebuffers(vedata);
+
+ /* create shaders */
+ GPENCIL_create_shaders();
+ GPENCIL_create_fx_shaders(&e_data);
+
+ /* blank texture used if no texture defined for fill shader */
+ if (!e_data.gpencil_blank_texture) {
+ float rect[16][16][4] = {{{0.0f}}};
+ e_data.gpencil_blank_texture = DRW_texture_create_2D(16, 16, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
+ }
+}
+
+static void GPENCIL_engine_free(void)
+{
+ /* only free custom shaders, builtin shaders are freed in blender close */
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_fill_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh);
+ DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh);
+
+ DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
+
+ GPU_BATCH_DISCARD_SAFE(e_data.batch_buffer_stroke);
+ MEM_SAFE_FREE(e_data.batch_buffer_stroke);
+
+ GPU_BATCH_DISCARD_SAFE(e_data.batch_buffer_fill);
+ MEM_SAFE_FREE(e_data.batch_buffer_fill);
+
+ GPU_BATCH_DISCARD_SAFE(e_data.batch_grid);
+ MEM_SAFE_FREE(e_data.batch_grid);
+
+ /* effects */
+ GPENCIL_delete_fx_shaders(&e_data);
+}
+
+void GPENCIL_cache_init(void *vedata)
+{
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+
+ /* Special handling for when active object is GP object (e.g. for draw mode) */
+ Object *obact = draw_ctx->obact;
+ bGPdata *obact_gpd = NULL;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ if (obact && (obact->type == OB_GPENCIL) && (obact->data)) {
+ obact_gpd = (bGPdata *)obact->data;
+ gp_style = BKE_material_gpencil_settings_get(obact, obact->actcol);
+ }
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(g_data), "g_data");
+ stl->storage->xray = GP_XRAY_FRONT; /* used for drawing */
+ stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID; /* used for drawing */
+ }
+ stl->storage->tonemapping = 0;
+
+ stl->g_data->shgrps_edit_line = NULL;
+ stl->g_data->shgrps_edit_point = NULL;
+
+ if (!stl->shgroups) {
+ /* Alloc maximum size because count strokes is very slow and can be very complex due onion skinning.
+ */
+ stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup");
+ }
+
+ /* init gp objects cache */
+ stl->g_data->gp_cache_used = 0;
+ stl->g_data->gp_cache_size = 0;
+ stl->g_data->gp_object_cache = NULL;
+
+ {
+ /* Stroke pass */
+ psl->stroke_pass = DRW_pass_create(
+ "GPencil Stroke Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND);
+ stl->storage->shgroup_id = 0;
+
+ /* edit pass */
+ psl->edit_pass = DRW_pass_create(
+ "GPencil Edit Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
+
+ /* detect if playing animation */
+ if (draw_ctx->evil_C) {
+
+ bool playing = ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != NULL;
+ if (playing != stl->storage->is_playing) {
+ stl->storage->reset_cache = true;
+ }
+ stl->storage->is_playing = playing;
+ }
+ else {
+ stl->storage->is_playing = false;
+ stl->storage->reset_cache = false;
+ }
+ /* save render state */
+ stl->storage->is_render = DRW_state_is_image_render();
+ stl->storage->is_mat_preview = (bool)stl->storage->is_render && STREQ(scene->id.name + 2, "preview");
+
+ if (obact_gpd) {
+ /* for some reason, when press play there is a delay in the animation flag check
+ * and this produces errors. To be sure, we set cache as dirty because the frame
+ * is changing.
+ */
+ if (stl->storage->is_playing == true) {
+ obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+ /* if render, set as dirty to update all data */
+ else if (stl->storage->is_render == true) {
+ obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+ }
+
+ /* save simplify flags (can change while drawing, so it's better to save) */
+ stl->storage->simplify_fill = GP_SIMPLIFY_FILL(scene, stl->storage->is_playing);
+ stl->storage->simplify_modif = GP_SIMPLIFY_MODIF(scene, stl->storage->is_playing);
+ stl->storage->simplify_fx = GP_SIMPLIFY_FX(scene, stl->storage->is_playing);
+ stl->storage->simplify_blend = GP_SIMPLIFY_BLEND(scene, stl->storage->is_playing);
+
+ /* save pixsize */
+ stl->storage->pixsize = DRW_viewport_pixelsize_get();
+ if ((!DRW_state_is_opengl_render()) && (stl->storage->is_render)) {
+ stl->storage->pixsize = &stl->storage->render_pixsize;
+ }
+
+ /* detect if painting session */
+ if ((obact_gpd) &&
+ (obact_gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
+ (stl->storage->is_playing == false))
+ {
+ /* need the original to avoid cow overhead while drawing */
+ bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&obact_gpd->id);
+ if (((gpd_orig->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) &&
+ (gpd_orig->runtime.sbuffer_size > 0) &&
+ ((gpd_orig->flag & GP_DATA_STROKE_POLYGON) == 0))
+ {
+ stl->g_data->session_flag |= GP_DRW_PAINT_PAINTING;
+ }
+ else {
+ stl->g_data->session_flag = GP_DRW_PAINT_IDLE;
+ }
+ }
+ else {
+ /* if not drawing mode */
+ stl->g_data->session_flag = GP_DRW_PAINT_HOLD;
+ }
+
+ if (gp_style) {
+ stl->storage->stroke_style = gp_style->stroke_style;
+ stl->storage->color_type = GPENCIL_COLOR_SOLID;
+ if (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) {
+ stl->storage->color_type = GPENCIL_COLOR_TEXTURE;
+ if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
+ stl->storage->color_type = GPENCIL_COLOR_PATTERN;
+ }
+ }
+ }
+ else {
+ stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID;
+ stl->storage->color_type = GPENCIL_COLOR_SOLID;
+ }
+
+ /* drawing buffer pass for drawing the stroke that is being drawing by the user. The data
+ * is stored in sbuffer
+ */
+ psl->drawing_pass = DRW_pass_create(
+ "GPencil Drawing Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+
+ /* full screen pass to combine the result with default framebuffer */
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ psl->mix_pass = DRW_pass_create(
+ "GPencil Mix Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass);
+ DRW_shgroup_call_add(mix_shgrp, quad, NULL);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeColor", &e_data.input_color_tx);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeDepth", &e_data.input_depth_tx);
+ DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
+
+ /* mix pass no blend used to copy between passes. A separated pass is required
+ * because if mix_pass is used, the acumulation of blend degrade the colors.
+ *
+ * This pass is used too to take the snapshot used for background_pass. This image
+ * will be used as the background while the user is drawing.
+ */
+ psl->mix_pass_noblend = DRW_pass_create(
+ "GPencil Mix Pass no blend",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ DRWShadingGroup *mix_shgrp_noblend = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass_noblend);
+ DRW_shgroup_call_add(mix_shgrp_noblend, quad, NULL);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeColor", &e_data.input_color_tx);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeDepth", &e_data.input_depth_tx);
+ DRW_shgroup_uniform_int(mix_shgrp_noblend, "tonemapping", &stl->storage->tonemapping, 1);
+
+ /* Painting session pass (used only to speedup while the user is drawing )
+ * This pass is used to show the snapshot of the current grease pencil strokes captured
+ * when the user starts to draw (see comments above).
+ * In this way, the previous strokes don't need to be redraw and the drawing process
+ * is far to agile.
+ */
+ psl->background_pass = DRW_pass_create(
+ "GPencil Background Painting Session Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ DRWShadingGroup *background_shgrp = DRW_shgroup_create(e_data.gpencil_background_sh, psl->background_pass);
+ DRW_shgroup_call_add(background_shgrp, quad, NULL);
+ DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeColor", &e_data.background_color_tx);
+ DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeDepth", &e_data.background_depth_tx);
+
+ /* pass for drawing paper (only if viewport)
+ * In render, the v3d is null so the paper is disabled
+ * The paper is way to isolate the drawing in complex scene and to have a cleaner
+ * drawing area.
+ */
+ if (v3d) {
+ psl->paper_pass = DRW_pass_create(
+ "GPencil Paper Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
+ DRWShadingGroup *paper_shgrp = DRW_shgroup_create(e_data.gpencil_paper_sh, psl->paper_pass);
+ DRW_shgroup_call_add(paper_shgrp, quad, NULL);
+ DRW_shgroup_uniform_vec3(paper_shgrp, "color", v3d->shading.background_color, 1);
+ DRW_shgroup_uniform_float(paper_shgrp, "opacity", &v3d->overlay.gpencil_paper_opacity, 1);
+ }
+
+ /* grid pass */
+ if (v3d) {
+ psl->grid_pass = DRW_pass_create(
+ "GPencil Grid Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass);
+ }
+
+ /* blend layers pass */
+ psl->blend_pass = DRW_pass_create(
+ "GPencil Blend Layers Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ DRWShadingGroup *blend_shgrp = DRW_shgroup_create(e_data.gpencil_blend_fullscreen_sh, psl->blend_pass);
+ DRW_shgroup_call_add(blend_shgrp, quad, NULL);
+ DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeColor", &e_data.temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeDepth", &e_data.temp_depth_tx_a);
+ DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &e_data.temp_color_tx_fx);
+ DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendDepth", &e_data.temp_depth_tx_fx);
+ DRW_shgroup_uniform_int(blend_shgrp, "mode", &stl->storage->blend_mode, 1);
+ DRW_shgroup_uniform_int(blend_shgrp, "clamp_layer", &stl->storage->clamp_layer, 1);
+ DRW_shgroup_uniform_float(blend_shgrp, "blend_opacity", &stl->storage->blend_opacity, 1);
+ DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
+
+ /* create effects passes */
+ if (!stl->storage->simplify_fx) {
+ GPENCIL_create_fx_passes(psl);
+ }
+ }
+}
+
+static void gpencil_add_draw_data(void *vedata, Object *ob)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ int i = stl->g_data->gp_cache_used - 1;
+ tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
+
+ if (!cache_ob->is_dup_ob) {
+ /* fill shading groups */
+ if (!is_multiedit) {
+ DRW_gpencil_populate_datablock(&e_data, vedata, ob, cache_ob);
+ }
+ else {
+ DRW_gpencil_populate_multiedit(&e_data, vedata, ob, cache_ob);
+ }
+ }
+
+ /* FX passses */
+ cache_ob->has_fx = false;
+ if ((!stl->storage->simplify_fx) &&
+ (BKE_shaderfx_has_gpencil(ob)))
+ {
+ cache_ob->has_fx = true;
+ if ((!stl->storage->simplify_fx) && (!is_multiedit)) {
+ DRW_gpencil_fx_prepare(&e_data, vedata, cache_ob);
+ }
+ }
+
+}
+
+void GPENCIL_cache_populate(void *vedata, Object *ob)
+{
+ /* object must be visible */
+ if (!DRW_object_is_visible_in_active_context(ob)) {
+ return;
+ }
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *ts = scene->toolsettings;
+ View3D *v3d = draw_ctx->v3d;
+
+ if (ob->type == OB_GPENCIL && ob->data) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ /* when start/stop animation the cache must be set as dirty to reset all data */
+ if (stl->storage->reset_cache) {
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ stl->storage->reset_cache = false;
+ }
+
+ if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) {
+
+ /* save gp objects for drawing later */
+ stl->g_data->gp_object_cache = gpencil_object_cache_add(
+ stl->g_data->gp_object_cache, ob,
+ &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used);
+
+ /* load drawing data */
+ gpencil_add_draw_data(vedata, ob);
+ }
+
+ /* draw current painting strokes
+ * (only if region is equal to originated paint region)
+ */
+ if ((draw_ctx->obact == ob) &&
+ ((gpd->runtime.ar == NULL) || (gpd->runtime.ar == draw_ctx->ar)))
+ {
+ DRW_gpencil_populate_buffer_strokes(&e_data, vedata, ts, ob);
+ }
+
+ /* grid */
+ if ((v3d) &&
+ ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->gp_flag & V3D_GP_SHOW_GRID) &&
+ (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact))
+ {
+ GPU_BATCH_DISCARD_SAFE(e_data.batch_grid);
+ MEM_SAFE_FREE(e_data.batch_grid);
+
+ e_data.batch_grid = DRW_gpencil_get_grid(ob);
+
+ /* define grid orientation */
+ if (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_VIEW) {
+ copy_m4_m4(stl->storage->grid_matrix, ob->obmat);
+ }
+ else {
+ /* align always to view */
+ invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat);
+ /* copy ob location */
+ copy_v3_v3(stl->storage->grid_matrix[3], ob->obmat[3]);
+ }
+
+ DRW_shgroup_call_add(
+ stl->g_data->shgrps_grid,
+ e_data.batch_grid,
+ stl->storage->grid_matrix);
+ }
+ }
+}
+
+void GPENCIL_cache_finish(void *vedata)
+{
+ DRW_gpencil_populate_particles(&e_data, vedata);
+}
+
+/* helper function to sort inverse gpencil objects using qsort */
+static int gpencil_object_cache_compare_zdepth(const void *a1, const void *a2)
+{
+ const tGPencilObjectCache *ps1 = a1, *ps2 = a2;
+
+ if (ps1->zdepth < ps2->zdepth) return 1;
+ else if (ps1->zdepth > ps2->zdepth) return -1;
+
+ return 0;
+}
+
+/* prepare a texture with full viewport screenshot for fast drawing */
+static void gpencil_prepare_fast_drawing(
+ GPENCIL_StorageList *stl, DefaultFramebufferList *dfbl,
+ GPENCIL_FramebufferList *fbl, DRWPass *pass,
+ const float clearcol[4])
+{
+ if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) {
+ GPU_framebuffer_bind(fbl->background_fb);
+ /* clean only in first loop cycle */
+ if (stl->g_data->session_flag & GP_DRW_PAINT_IDLE) {
+ GPU_framebuffer_clear_color_depth(fbl->background_fb, clearcol, 1.0f);
+ stl->g_data->session_flag = GP_DRW_PAINT_FILLING;
+ }
+ /* repeat pass to fill temp texture */
+ DRW_draw_pass(pass);
+ /* set default framebuffer again */
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+}
+
+static void gpencil_free_obj_runtime(GPENCIL_StorageList *stl)
+{
+ /* reset all cache flags */
+ for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
+ tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
+ bGPdata *gpd = cache_ob->gpd;
+ gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
+
+ /* free shgrp array */
+ cache_ob->tot_layers = 0;
+ MEM_SAFE_FREE(cache_ob->shgrp_array);
+ }
+
+ /* free the cache itself */
+ MEM_SAFE_FREE(stl->g_data->gp_object_cache);
+}
+
+static void gpencil_draw_pass_range(
+ GPENCIL_FramebufferList *fbl, GPENCIL_StorageList *stl,
+ GPENCIL_PassList *psl, GPENCIL_TextureList *txl,
+ GPUFrameBuffer *fb,
+ DRWShadingGroup *init_shgrp, DRWShadingGroup *end_shgrp, bool multi)
+{
+ if (init_shgrp == NULL) {
+ return;
+ }
+
+ /* previews don't use AA */
+ if ((!stl->storage->is_mat_preview) && (multi)) {
+ MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+ }
+
+ DRW_draw_pass_subset(
+ psl->stroke_pass, init_shgrp, end_shgrp);
+
+ if ((!stl->storage->is_mat_preview) && (multi)) {
+ MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
+ }
+
+}
+
+/* draw scene */
+void GPENCIL_draw_scene(void *ved)
+{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
+
+ tGPencilObjectCache *cache_ob;
+ tGPencilObjectCache_shgrp *array_elm = NULL;
+ DRWShadingGroup *init_shgrp = NULL;
+ DRWShadingGroup *end_shgrp = NULL;
+
+ const float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Object *obact = draw_ctx->obact;
+ const bool playing = stl->storage->is_playing;
+ const bool is_render = stl->storage->is_render;
+
+ /* paper pass to display a comfortable area to draw over complex scenes with geometry */
+ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->gp_flag & V3D_GP_SHOW_PAPER))
+ {
+ DRW_draw_pass(psl->paper_pass);
+ }
+ }
+
+ /* if we have a painting session, we use fast viewport drawing method */
+ if ((!is_render) && (stl->g_data->session_flag & GP_DRW_PAINT_PAINTING)) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+
+ MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+
+ DRW_draw_pass(psl->background_pass);
+ DRW_draw_pass(psl->drawing_pass);
+
+ MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, dfbl->default_fb, txl);
+
+ /* free memory */
+ gpencil_free_obj_runtime(stl);
+
+ /* grid pass */
+ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->gp_flag & V3D_GP_SHOW_GRID))
+ {
+ DRW_draw_pass(psl->grid_pass);
+ }
+ }
+
+ return;
+ }
+
+ if (DRW_state_is_fbo()) {
+
+ /* Draw all pending objects */
+ if (stl->g_data->gp_cache_used > 0) {
+
+ /* sort by zdepth */
+ qsort(stl->g_data->gp_object_cache, stl->g_data->gp_cache_used,
+ sizeof(tGPencilObjectCache), gpencil_object_cache_compare_zdepth);
+
+ for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
+ cache_ob = &stl->g_data->gp_object_cache[i];
+ bGPdata *gpd = cache_ob->gpd;
+ init_shgrp = NULL;
+ /* Render stroke in separated framebuffer */
+ GPU_framebuffer_bind(fbl->temp_fb_a);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
+
+ /* Stroke Pass:
+ * draw only a subset that usually starts with a fill and ends with stroke
+ */
+ bool use_blend = false;
+ if (cache_ob->tot_layers > 0) {
+ for (int e = 0; e < cache_ob->tot_layers; e++) {
+ bool is_last = e == cache_ob->tot_layers - 1 ? true : false;
+ array_elm = &cache_ob->shgrp_array[e];
+
+ if (((array_elm->mode == eGplBlendMode_Normal) &&
+ (!use_blend) && (!array_elm->clamp_layer)) ||
+ (e == 0))
+ {
+ if (init_shgrp == NULL) {
+ init_shgrp = array_elm->init_shgrp;
+ }
+ end_shgrp = array_elm->end_shgrp;
+ }
+ else {
+ use_blend = true;
+ /* draw pending groups */
+ gpencil_draw_pass_range(
+ fbl, stl, psl, txl, fbl->temp_fb_a,
+ init_shgrp, end_shgrp, is_last);
+
+ /* draw current group in separated texture */
+ init_shgrp = array_elm->init_shgrp;
+ end_shgrp = array_elm->end_shgrp;
+
+ GPU_framebuffer_bind(fbl->temp_fb_fx);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
+ gpencil_draw_pass_range(
+ fbl, stl, psl, txl, fbl->temp_fb_fx,
+ init_shgrp, end_shgrp,
+ is_last);
+
+ /* Blend A texture and FX texture */
+ GPU_framebuffer_bind(fbl->temp_fb_b);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
+ stl->storage->blend_mode = array_elm->mode;
+ stl->storage->clamp_layer = (int)array_elm->clamp_layer;
+ stl->storage->blend_opacity = array_elm->blend_opacity;
+ stl->storage->tonemapping = stl->storage->is_render ? 1 : 0;
+ DRW_draw_pass(psl->blend_pass);
+ stl->storage->tonemapping = 0;
+
+ /* Copy B texture to A texture to follow loop */
+ e_data.input_depth_tx = e_data.temp_depth_tx_b;
+ e_data.input_color_tx = e_data.temp_color_tx_b;
+
+ GPU_framebuffer_bind(fbl->temp_fb_a);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
+ DRW_draw_pass(psl->mix_pass_noblend);
+
+ /* prepare next group */
+ init_shgrp = NULL;
+ }
+
+ }
+ /* last group */
+ gpencil_draw_pass_range(
+ fbl, stl, psl, txl, fbl->temp_fb_a,
+ init_shgrp, end_shgrp,
+ true);
+ }
+
+ /* Current buffer drawing */
+ if ((!is_render) && (cache_ob->is_dup_ob == false)) {
+ DRW_draw_pass(psl->drawing_pass);
+ }
+ /* fx passes */
+ if (cache_ob->has_fx == true) {
+ stl->storage->tonemapping = 0;
+ DRW_gpencil_fx_draw(&e_data, vedata, cache_ob);
+ }
+
+ e_data.input_depth_tx = e_data.temp_depth_tx_a;
+ e_data.input_color_tx = e_data.temp_color_tx_a;
+
+ /* Combine with scene buffer */
+ if ((!is_render) || (fbl->main == NULL)) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+ else {
+ GPU_framebuffer_bind(fbl->main);
+ }
+ /* tonemapping */
+ stl->storage->tonemapping = stl->storage->is_render ? 1 : 0;
+
+ DRW_draw_pass(psl->mix_pass);
+
+ /* prepare for fast drawing */
+ if (!is_render) {
+ if (!playing) {
+ gpencil_prepare_fast_drawing(stl, dfbl, fbl, psl->mix_pass_noblend, clearcol);
+ }
+ }
+ else {
+ /* if render, the cache must be dirty for next loop */
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+ }
+ /* edit points */
+ if ((!is_render) && (!playing)) {
+ DRW_draw_pass(psl->edit_pass);
+ }
+ }
+ /* grid pass */
+ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (v3d->gp_flag & V3D_GP_SHOW_GRID))
+ {
+ DRW_draw_pass(psl->grid_pass);
+ }
+ }
+ }
+ /* free memory */
+ gpencil_free_obj_runtime(stl);
+
+ /* reset */
+ if (DRW_state_is_fbo()) {
+ /* attach again default framebuffer */
+ if (!is_render) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+
+ /* the temp texture is ready. Now we can use fast screen drawing */
+ if (stl->g_data->session_flag & GP_DRW_PAINT_FILLING) {
+ stl->g_data->session_flag = GP_DRW_PAINT_READY;
+ }
+ }
+}
+
+static const DrawEngineDataSize GPENCIL_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_Data);
+
+DrawEngineType draw_engine_gpencil_type = {
+ NULL, NULL,
+ N_("GpencilMode"),
+ &GPENCIL_data_size,
+ &GPENCIL_engine_init,
+ &GPENCIL_engine_free,
+ &GPENCIL_cache_init,
+ &GPENCIL_cache_populate,
+ &GPENCIL_cache_finish,
+ NULL,
+ &GPENCIL_draw_scene,
+ NULL,
+ NULL,
+ &GPENCIL_render_to_image,
+};
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
new file mode 100644
index 00000000000..b8b526cb873
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -0,0 +1,441 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_engine.h
+ * \ingroup draw
+ */
+
+#ifndef __GPENCIL_ENGINE_H__
+#define __GPENCIL_ENGINE_H__
+
+#include "GPU_batch.h"
+
+struct tGPspoint;
+struct bGPDstroke;
+struct ModifierData;
+struct GPENCIL_Data;
+struct GPENCIL_StorageList;
+struct Object;
+struct MaterialGPencilStyle;
+struct RenderEngine;
+struct RenderLayer;
+
+#define GPENCIL_CACHE_BLOCK_SIZE 8
+#define GPENCIL_MAX_SHGROUPS 65536
+#define GPENCIL_GROUPS_BLOCK_SIZE 1024
+
+/* used to expand VBOs. Size has a big impact in the speed */
+#define GPENCIL_VBO_BLOCK_SIZE 128
+
+#define GPENCIL_COLOR_SOLID 0
+#define GPENCIL_COLOR_TEXTURE 1
+#define GPENCIL_COLOR_PATTERN 2
+
+#define GP_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))
+#define GP_SIMPLIFY_ONPLAY(playing) (((playing == true) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY)) || ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY) == 0))
+#define GP_SIMPLIFY_FILL(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL)))
+#define GP_SIMPLIFY_MODIF(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER)))
+#define GP_SIMPLIFY_FX(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX)))
+#define GP_SIMPLIFY_BLEND(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND)))
+
+#define GP_IS_CAMERAVIEW ((rv3d != NULL) && (rv3d->persp == RV3D_CAMOB && v3d->camera))
+
+ /* *********** OBJECTS CACHE *********** */
+typedef struct tGPencilObjectCache_shgrp {
+ int mode;
+ bool clamp_layer;
+ float blend_opacity;
+ DRWShadingGroup *init_shgrp;
+ DRWShadingGroup *end_shgrp;
+} tGPencilObjectCache_shgrp;
+
+ /* used to save gpencil object data for drawing */
+typedef struct tGPencilObjectCache {
+ struct Object *ob;
+ struct bGPdata *gpd;
+ int idx; /*original index, can change after sort */
+
+ /* effects */
+ bool has_fx;
+ ListBase shader_fx;
+ float pixfactor;
+ DRWShadingGroup *fx_wave_sh;
+ DRWShadingGroup *fx_blur_sh;
+ DRWShadingGroup *fx_colorize_sh;
+ DRWShadingGroup *fx_pixel_sh;
+ DRWShadingGroup *fx_rim_sh;
+ DRWShadingGroup *fx_shadow_sh;
+ DRWShadingGroup *fx_glow_sh;
+ DRWShadingGroup *fx_swirl_sh;
+ DRWShadingGroup *fx_flip_sh;
+ DRWShadingGroup *fx_light_sh;
+
+ float loc[3];
+ float obmat[4][4];
+ float zdepth; /* z-depth value to sort gp object */
+ bool is_dup_ob; /* flag to tag duplicate objects */
+
+ /* GPU data size */
+ int tot_vertex;
+ int tot_triangles;
+
+ /* Save shader groups by layer */
+ int tot_layers;
+ tGPencilObjectCache_shgrp *shgrp_array;
+
+} tGPencilObjectCache;
+
+ /* *********** LISTS *********** */
+typedef struct GPENCIL_shgroup {
+ int s_clamp;
+ int stroke_style;
+ int color_type;
+ int mode;
+ int texture_mix;
+ int texture_flip;
+ int texture_clamp;
+ int fill_style;
+ int keep_size;
+ float obj_scale;
+} GPENCIL_shgroup;
+
+typedef struct GPENCIL_Storage {
+ int shgroup_id; /* total elements */
+ float unit_matrix[4][4];
+ int stroke_style;
+ int color_type;
+ int mode;
+ int xray;
+ int keep_size;
+ float obj_scale;
+ float pixfactor;
+ bool is_playing;
+ bool is_render;
+ bool is_mat_preview;
+ bool reset_cache;
+ bool buffer_stroke;
+ bool buffer_fill;
+ const float *pixsize;
+ float render_pixsize;
+ int tonemapping;
+ short multisamples;
+
+ int blend_mode;
+ int clamp_layer;
+ float blend_opacity;
+
+ /* simplify settings*/
+ bool simplify_fill;
+ bool simplify_modif;
+ bool simplify_fx;
+ bool simplify_blend;
+
+ /* Render Matrices and data */
+ float persmat[4][4], persinv[4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float winmat[4][4], wininv[4][4];
+ float view_vecs[2][4]; /* vec4[2] */
+
+ float grid_matrix[4][4];
+
+ Object *camera; /* camera pointer for render mode */
+} GPENCIL_Storage;
+
+typedef struct GPENCIL_StorageList {
+ struct GPENCIL_Storage *storage;
+ struct g_data *g_data;
+ struct GPENCIL_shgroup *shgroups;
+} GPENCIL_StorageList;
+
+typedef struct GPENCIL_PassList {
+ struct DRWPass *stroke_pass;
+ struct DRWPass *edit_pass;
+ struct DRWPass *drawing_pass;
+ struct DRWPass *mix_pass;
+ struct DRWPass *mix_pass_noblend;
+ struct DRWPass *background_pass;
+ struct DRWPass *paper_pass;
+ struct DRWPass *grid_pass;
+ struct DRWPass *blend_pass;
+
+ /* effects */
+ struct DRWPass *fx_shader_pass;
+ struct DRWPass *fx_shader_pass_blend;
+
+} GPENCIL_PassList;
+
+typedef struct GPENCIL_FramebufferList {
+ struct GPUFrameBuffer *main;
+ struct GPUFrameBuffer *temp_fb_a;
+ struct GPUFrameBuffer *temp_fb_b;
+ struct GPUFrameBuffer *temp_fb_fx;
+ struct GPUFrameBuffer *background_fb;
+
+ struct GPUFrameBuffer *multisample_fb;
+} GPENCIL_FramebufferList;
+
+typedef struct GPENCIL_TextureList {
+ struct GPUTexture *texture;
+
+ /* multisample textures */
+ struct GPUTexture *multisample_color;
+ struct GPUTexture *multisample_depth;
+
+} GPENCIL_TextureList;
+
+typedef struct GPENCIL_Data {
+ void *engine_type; /* Required */
+ struct GPENCIL_FramebufferList *fbl;
+ struct GPENCIL_TextureList *txl;
+ struct GPENCIL_PassList *psl;
+ struct GPENCIL_StorageList *stl;
+
+ /* render textures */
+ struct GPUTexture *render_depth_tx;
+ struct GPUTexture *render_color_tx;
+
+} GPENCIL_Data;
+
+/* *********** STATIC *********** */
+typedef struct g_data {
+ struct DRWShadingGroup *shgrps_edit_point;
+ struct DRWShadingGroup *shgrps_edit_line;
+ struct DRWShadingGroup *shgrps_drawing_stroke;
+ struct DRWShadingGroup *shgrps_drawing_fill;
+ struct DRWShadingGroup *shgrps_grid;
+
+ int gp_cache_used; /* total objects in cache */
+ int gp_cache_size; /* size of the cache */
+ struct tGPencilObjectCache *gp_object_cache;
+
+ int session_flag;
+
+} g_data; /* Transient data */
+
+/* flags for fast drawing support */
+typedef enum eGPsession_Flag {
+ GP_DRW_PAINT_HOLD = (1 << 0),
+ GP_DRW_PAINT_IDLE = (1 << 1),
+ GP_DRW_PAINT_FILLING = (1 << 2),
+ GP_DRW_PAINT_READY = (1 << 3),
+ GP_DRW_PAINT_PAINTING = (1 << 4),
+} eGPsession_Flag;
+
+typedef struct GPENCIL_e_data {
+ /* general drawing shaders */
+ struct GPUShader *gpencil_fill_sh;
+ struct GPUShader *gpencil_stroke_sh;
+ struct GPUShader *gpencil_point_sh;
+ struct GPUShader *gpencil_edit_point_sh;
+ struct GPUShader *gpencil_line_sh;
+ struct GPUShader *gpencil_drawing_fill_sh;
+ struct GPUShader *gpencil_fullscreen_sh;
+ struct GPUShader *gpencil_simple_fullscreen_sh;
+ struct GPUShader *gpencil_blend_fullscreen_sh;
+ struct GPUShader *gpencil_background_sh;
+ struct GPUShader *gpencil_paper_sh;
+
+ /* effects */
+ struct GPUShader *gpencil_fx_blur_sh;
+ struct GPUShader *gpencil_fx_colorize_sh;
+ struct GPUShader *gpencil_fx_flip_sh;
+ struct GPUShader *gpencil_fx_glow_prepare_sh;
+ struct GPUShader *gpencil_fx_glow_resolve_sh;
+ struct GPUShader *gpencil_fx_light_sh;
+ struct GPUShader *gpencil_fx_pixel_sh;
+ struct GPUShader *gpencil_fx_rim_prepare_sh;
+ struct GPUShader *gpencil_fx_rim_resolve_sh;
+ struct GPUShader *gpencil_fx_shadow_prepare_sh;
+ struct GPUShader *gpencil_fx_shadow_resolve_sh;
+ struct GPUShader *gpencil_fx_swirl_sh;
+ struct GPUShader *gpencil_fx_wave_sh;
+
+ /* textures */
+ struct GPUTexture *background_depth_tx;
+ struct GPUTexture *background_color_tx;
+
+ struct GPUTexture *gpencil_blank_texture;
+
+ /* runtime pointers texture */
+ struct GPUTexture *input_depth_tx;
+ struct GPUTexture *input_color_tx;
+
+ /* working textures */
+ struct GPUTexture *temp_color_tx_a;
+ struct GPUTexture *temp_depth_tx_a;
+
+ struct GPUTexture *temp_color_tx_b;
+ struct GPUTexture *temp_depth_tx_b;
+
+ struct GPUTexture *temp_color_tx_fx;
+ struct GPUTexture *temp_depth_tx_fx;
+
+ /* for buffer only one batch is nedeed because the drawing is only of one stroke */
+ GPUBatch *batch_buffer_stroke;
+ GPUBatch *batch_buffer_fill;
+
+ /* grid geometry */
+ GPUBatch *batch_grid;
+
+} GPENCIL_e_data; /* Engine data */
+
+/* GPUBatch Cache */
+typedef struct GpencilBatchCacheElem {
+ GPUBatch *batch;
+ GPUVertBuf *vbo;
+ int vbo_len;
+ /* attr ids */
+ GPUVertFormat format;
+ uint pos_id;
+ uint color_id;
+ uint thickness_id;
+ uint uvdata_id;
+
+ /* size for VBO alloc */
+ int tot_vertex;
+} GpencilBatchCacheElem;
+
+typedef struct GpencilBatchGroup {
+ bGPDlayer *gpl; /* reference to original layer */
+ bGPDframe *gpf; /* reference to original frame */
+ bGPDstroke *gps; /* reference to original stroke */
+ short type; /* type of element */
+ bool onion; /* the group is part of onion skin */
+ int vertex_idx; /* index of vertex data */
+} GpencilBatchGroup;
+
+typedef enum GpencilBatchGroup_Type {
+ eGpencilBatchGroupType_Stroke = 1,
+ eGpencilBatchGroupType_Point = 2,
+ eGpencilBatchGroupType_Fill = 3,
+ eGpencilBatchGroupType_Edit = 4,
+ eGpencilBatchGroupType_Edlin = 5,
+} GpencilBatchGroup_Type;
+
+typedef struct GpencilBatchCache {
+ GpencilBatchCacheElem b_stroke;
+ GpencilBatchCacheElem b_point;
+ GpencilBatchCacheElem b_fill;
+ GpencilBatchCacheElem b_edit;
+ GpencilBatchCacheElem b_edlin;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+ bool is_editmode;
+ int cache_frame;
+
+ /* data with the shading groups */
+ int grp_used; /* total groups in arrays */
+ int grp_size; /* max size of the array */
+ struct GpencilBatchGroup *grp_cache; /* array of elements */
+
+ int tot_layers;
+ struct bGPDframe *derived_array; /* runtime data created by modifiers */
+} GpencilBatchCache;
+
+/* general drawing functions */
+struct DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(
+ struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, struct DRWPass *pass, struct GPUShader *shader,
+ struct Object *ob, struct bGPdata *gpd, struct MaterialGPencilStyle *gp_style, int id, bool onion);
+void DRW_gpencil_populate_datablock(
+ struct GPENCIL_e_data *e_data, void *vedata,
+ struct Object *ob, struct tGPencilObjectCache *cache_ob);
+void DRW_gpencil_populate_buffer_strokes(
+ struct GPENCIL_e_data *e_data, void *vedata, struct ToolSettings *ts, struct Object *ob);
+void DRW_gpencil_populate_multiedit(
+ struct GPENCIL_e_data *e_data, void *vedata,
+ struct Object *ob, struct tGPencilObjectCache *cache_ob);
+void DRW_gpencil_triangulate_stroke_fill(struct Object *ob, struct bGPDstroke *gps);
+void DRW_gpencil_populate_particles(struct GPENCIL_e_data *e_data, void *vedata);
+
+void DRW_gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int rect_h);
+
+/* create geometry functions */
+void DRW_gpencil_get_point_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, short thickness, const float ink[4]);
+void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, short thickness, const float ink[4]);
+void DRW_gpencil_get_fill_geom(struct GpencilBatchCacheElem *be, struct Object *ob, struct bGPDstroke *gps, const float color[4]);
+void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, float alpha, short dflag);
+void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, float alpha, short dflag);
+
+struct GPUBatch *DRW_gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, short thickness);
+struct GPUBatch *DRW_gpencil_get_buffer_fill_geom(struct bGPdata *gpd);
+struct GPUBatch *DRW_gpencil_get_buffer_point_geom(struct bGPdata *gpd, short thickness);
+struct GPUBatch *DRW_gpencil_get_grid(Object *ob);
+
+/* object cache functions */
+struct tGPencilObjectCache *gpencil_object_cache_add(
+ struct tGPencilObjectCache *cache_array, struct Object *ob,
+ int *gp_cache_size, int *gp_cache_used);
+
+/* shading groups cache functions */
+struct GpencilBatchGroup *gpencil_group_cache_add(
+ struct GpencilBatchGroup *cache_array,
+ struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps,
+ const short type, const bool onion,
+ const int vertex_idx,
+ int *grp_size, int *grp_used);
+
+/* geometry batch cache functions */
+struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra);
+
+/* effects */
+void GPENCIL_create_fx_shaders(struct GPENCIL_e_data *e_data);
+void GPENCIL_delete_fx_shaders(struct GPENCIL_e_data *e_data);
+void GPENCIL_create_fx_passes(struct GPENCIL_PassList *psl);
+
+void DRW_gpencil_fx_prepare(
+ struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata,
+ struct tGPencilObjectCache *cache);
+void DRW_gpencil_fx_draw(
+ struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata,
+ struct tGPencilObjectCache *cache);
+
+/* main functions */
+void GPENCIL_engine_init(void *vedata);
+void GPENCIL_cache_init(void *vedata);
+void GPENCIL_cache_populate(void *vedata, struct Object *ob);
+void GPENCIL_cache_finish(void *vedata);
+void GPENCIL_draw_scene(void *vedata);
+
+/* render */
+void GPENCIL_render_init(struct GPENCIL_Data *ved, struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void GPENCIL_render_to_image(void *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect);
+
+/* Use of multisample framebuffers. */
+#define MULTISAMPLE_GP_SYNC_ENABLE(lvl, fbl) { \
+ if ((lvl > 0) && (fbl->multisample_fb != NULL)) { \
+ DRW_stats_query_start("GP Multisample Blit"); \
+ GPU_framebuffer_bind(fbl->multisample_fb); \
+ GPU_framebuffer_clear_color_depth(fbl->multisample_fb, (const float[4]){0.0f}, 1.0f); \
+ DRW_stats_query_end(); \
+ } \
+}
+
+#define MULTISAMPLE_GP_SYNC_DISABLE(lvl, fbl, fb, txl) { \
+ if ((lvl > 0) && (fbl->multisample_fb != NULL)) { \
+ DRW_stats_query_start("GP Multisample Resolve"); \
+ GPU_framebuffer_bind(fb); \
+ DRW_multisamples_resolve(txl->multisample_depth, txl->multisample_color, true); \
+ DRW_stats_query_end(); \
+ } \
+}
+
+#endif /* __GPENCIL_ENGINE_H__ */
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
new file mode 100644
index 00000000000..8dc15472a20
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_render.c
+ * \ingroup draw
+ */
+#include "BLI_rect.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "draw_mode_engines.h"
+
+#include "RE_pipeline.h"
+
+#include "gpencil_engine.h"
+
+/* Get pixel size for render
+ * This function uses the same calculation used for viewport, because if use
+ * camera pixelsize, the result is not correct.
+ */
+static float get_render_pixelsize(float persmat[4][4], int winx, int winy)
+{
+ float v1[3], v2[3];
+ float len_px, len_sc;
+
+ v1[0] = persmat[0][0];
+ v1[1] = persmat[1][0];
+ v1[2] = persmat[2][0];
+
+ v2[0] = persmat[0][1];
+ v2[1] = persmat[1][1];
+ v2[2] = persmat[2][1];
+
+ len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
+ len_sc = (float)MAX2(winx, winy);
+
+ return len_px / len_sc;
+}
+
+/* init render data */
+void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph)
+{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_StorageList *stl = vedata->stl;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = { (int)viewport_size[0], (int)viewport_size[1] };
+
+ /* In render mode the default framebuffer is not generated
+ * because there is no viewport. So we need to manually create one
+ * NOTE : use 32 bit format for precision in render mode.
+ */
+ /* create multiframe framebuffer for AA */
+ if (U.gpencil_multisamples > 0) {
+ int rect_w = (int)viewport_size[0];
+ int rect_h = (int)viewport_size[1];
+ DRW_gpencil_multisample_ensure(vedata, rect_w, rect_h);
+ }
+
+ vedata->render_depth_tx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_DEPTH24_STENCIL8,
+ &draw_engine_gpencil_type);
+ vedata->render_color_tx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_RGBA32F,
+ &draw_engine_gpencil_type);
+ GPU_framebuffer_ensure_config(
+ &fbl->main, {
+ GPU_ATTACHMENT_TEXTURE(vedata->render_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(vedata->render_color_tx)
+ });
+
+ /* Alloc transient data. */
+ if (!stl->g_data) {
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+
+ /* Set the pers & view matrix. */
+ struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
+ float frame = BKE_scene_frame_get(scene);
+ RE_GetCameraWindow(engine->re, camera, frame, stl->storage->winmat);
+ RE_GetCameraModelMatrix(engine->re, camera, stl->storage->viewinv);
+
+ invert_m4_m4(stl->storage->viewmat, stl->storage->viewinv);
+ mul_m4_m4m4(stl->storage->persmat, stl->storage->winmat, stl->storage->viewmat);
+ invert_m4_m4(stl->storage->persinv, stl->storage->persmat);
+ invert_m4_m4(stl->storage->wininv, stl->storage->winmat);
+
+ DRW_viewport_matrix_override_set(stl->storage->persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(stl->storage->persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(stl->storage->winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(stl->storage->wininv, DRW_MAT_WININV);
+ DRW_viewport_matrix_override_set(stl->storage->viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(stl->storage->viewinv, DRW_MAT_VIEWINV);
+
+ /* calculate pixel size for render */
+ stl->storage->render_pixsize = get_render_pixelsize(stl->storage->persmat, viewport_size[0], viewport_size[1]);
+ /* INIT CACHE */
+ GPENCIL_cache_init(vedata);
+}
+
+/* render all objects and select only grease pencil */
+static void GPENCIL_render_cache(
+ void *vedata, struct Object *ob,
+ struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph))
+{
+ if ((ob == NULL) || (DRW_object_is_visible_in_active_context(ob) == false)) {
+ return;
+ }
+
+ if (ob->type == OB_GPENCIL) {
+ GPENCIL_cache_populate(vedata, ob);
+ }
+}
+
+/* TODO: Reuse Eevee code in shared module instead to duplicate here */
+static void GPENCIL_render_update_viewvecs(float invproj[4][4], float winmat[4][4], float(*r_viewvecs)[4])
+{
+ /* view vectors for the corners of the view frustum.
+ * Can be used to recreate the world space position easily */
+ float view_vecs[4][4] = {
+ {-1.0f, -1.0f, -1.0f, 1.0f},
+ {1.0f, -1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f, 1.0f},
+ {-1.0f, -1.0f, 1.0f, 1.0f}
+ };
+
+ /* convert the view vectors to view space */
+ const bool is_persp = (winmat[3][3] == 0.0f);
+ for (int i = 0; i < 4; i++) {
+ mul_project_m4_v3(invproj, view_vecs[i]);
+ /* normalized trick see:
+ * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ if (is_persp) {
+ /* Divide XY by Z. */
+ mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]);
+ }
+ }
+
+ /**
+ * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and
+ * view_vecs[1] is the vector going from the near-bottom-left corner to
+ * the far-top-right corner.
+ * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner
+ * when Z = 1, and top-left corner if Z = 1.
+ * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed)
+ * distance from the near plane to the far clip plane.
+ */
+ copy_v4_v4(r_viewvecs[0], view_vecs[0]);
+
+ /* we need to store the differences */
+ r_viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0];
+ r_viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1];
+ r_viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
+}
+
+/* Update view_vecs */
+static void GPENCIL_render_update_vecs(GPENCIL_Data *vedata)
+{
+ GPENCIL_StorageList *stl = vedata->stl;
+
+ float invproj[4][4], winmat[4][4];
+ DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_get(invproj, DRW_MAT_WININV);
+
+ /* this is separated to keep function equal to Eevee for future reuse of same code */
+ GPENCIL_render_update_viewvecs(invproj, winmat, stl->storage->view_vecs);
+}
+
+/* read z-depth render result */
+static void GPENCIL_render_result_z(struct RenderLayer *rl, const char *viewname, GPENCIL_Data *vedata, const rcti *rect)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ GPENCIL_StorageList *stl = vedata->stl;
+
+ if ((view_layer->passflag & SCE_PASS_Z) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
+
+ GPU_framebuffer_read_depth(vedata->fbl->main, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), rp->rect);
+
+ bool is_persp = DRW_viewport_is_persp_get();
+
+ GPENCIL_render_update_vecs(vedata);
+
+ /* Convert ogl depth [0..1] to view Z [near..far] */
+ for (int i = 0; i < BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
+ if (is_persp) {
+ rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
+ rp->rect[i] = stl->storage->winmat[3][2] / (rp->rect[i] + stl->storage->winmat[2][2]);
+ }
+ else {
+ rp->rect[i] = -stl->storage->view_vecs[0][2] + rp->rect[i] * -stl->storage->view_vecs[1][2];
+ }
+ }
+ }
+ }
+}
+
+/* read combined render result */
+static void GPENCIL_render_result_combined(struct RenderLayer *rl, const char *viewname, GPENCIL_Data *vedata, const rcti *rect)
+{
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+
+ GPU_framebuffer_bind(fbl->main);
+ GPU_framebuffer_read_color(vedata->fbl->main, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 4, 0, rp->rect);
+}
+
+/* helper to blend pixels */
+static void blend_pixel(float src[4], float dst[4])
+{
+ float alpha = src[3];
+
+ /* use blend: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA */
+ dst[0] = (src[0] * alpha) + (dst[0] * (1.0f - alpha));
+ dst[1] = (src[1] * alpha) + (dst[1] * (1.0f - alpha));
+ dst[2] = (src[2] * alpha) + (dst[2] * (1.0f - alpha));
+}
+
+/* render grease pencil to image */
+void GPENCIL_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect)
+{
+ const char *viewname = RE_GetActiveRenderView(engine->re);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ int imgsize = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+
+ /* save previous render data */
+ RenderPass *rpass_color_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
+ RenderPass *rpass_depth_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
+ float *src_rect_color_data = NULL;
+ float *src_rect_depth_data = NULL;
+ if ((rpass_color_src) && (rpass_depth_src) && (rpass_color_src->rect) && (rpass_depth_src->rect)) {
+ src_rect_color_data = MEM_dupallocN(rpass_color_src->rect);
+ src_rect_depth_data = MEM_dupallocN(rpass_depth_src->rect);
+ }
+ else {
+ /* TODO: put this message in a better place */
+ printf("Warning: To render grease pencil, enable Combined and Z passes.\n");
+ }
+
+ GPENCIL_engine_init(vedata);
+ GPENCIL_render_init(vedata, engine, draw_ctx->depsgraph);
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ Object *camera = DEG_get_evaluated_object(draw_ctx->depsgraph, RE_GetCamera(engine->re));
+ stl->storage->camera = camera; /* save current camera */
+
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ if (fbl->main) {
+ GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx, 0, 0);
+ GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx, 0, 0);
+ /* clean first time the buffer */
+ float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ GPU_framebuffer_bind(fbl->main);
+ GPU_framebuffer_clear_color_depth(fbl->main, clearcol, 1.0f);
+ }
+
+ /* loop all objects and draw */
+ DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache);
+
+ GPENCIL_cache_finish(vedata);
+ GPENCIL_draw_scene(vedata);
+
+ /* combined data */
+ GPENCIL_render_result_combined(render_layer, viewname, vedata, rect);
+ /* z-depth data */
+ GPENCIL_render_result_z(render_layer, viewname, vedata, rect);
+
+ /* detach textures */
+ if (fbl->main) {
+ GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx);
+ GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx);
+ }
+
+ /* merge previous render image with new GP image */
+ if (src_rect_color_data) {
+ RenderPass *rpass_color_gp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
+ RenderPass *rpass_depth_gp = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
+ float *gp_rect_color_data = rpass_color_gp->rect;
+ float *gp_rect_depth_data = rpass_depth_gp->rect;
+ float *gp_pixel_rgba;
+ float *gp_pixel_depth;
+ float *src_pixel_rgba;
+ float *src_pixel_depth;
+ float tmp[4];
+
+ for (int i = 0; i < imgsize; i++) {
+ gp_pixel_rgba = &gp_rect_color_data[i * 4];
+ gp_pixel_depth = &gp_rect_depth_data[i];
+
+ src_pixel_rgba = &src_rect_color_data[i * 4];
+ src_pixel_depth = &src_rect_depth_data[i];
+
+ /* check grease pencil render transparency */
+ if (gp_pixel_rgba[3] > 0.0f) {
+ copy_v4_v4(tmp, gp_pixel_rgba);
+ if (src_pixel_rgba[3] > 0.0f) {
+ /* copy source color on back */
+ copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
+ /* check z-depth */
+ if (gp_pixel_depth[0] > src_pixel_depth[0]) {
+ /* copy source z-depth */
+ gp_pixel_depth[0] = src_pixel_depth[0];
+ /* blend gp render */
+ blend_pixel(tmp, gp_pixel_rgba);
+ /* blend object on top */
+ blend_pixel(src_pixel_rgba, gp_pixel_rgba);
+ }
+ else {
+ /* blend gp render */
+ blend_pixel(tmp, gp_pixel_rgba);
+ }
+ }
+ }
+ else {
+ copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
+ gp_pixel_depth[0] = src_pixel_depth[0];
+ }
+ }
+
+ /* free memory */
+ MEM_SAFE_FREE(src_rect_color_data);
+ MEM_SAFE_FREE(src_rect_depth_data);
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
new file mode 100644
index 00000000000..fcadf296253
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -0,0 +1,1129 @@
+/*
+ * Copyright 2017, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ */
+
+/** \file blender/draw/engines/gpencil/gpencil_shader_fx.c
+ * \ingroup draw
+ */
+#include "DNA_gpencil_types.h"
+#include "DNA_shader_fx_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_camera_types.h"
+
+#include "BKE_gpencil.h"
+#include "BKE_shader_fx.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+
+#include "ED_view3d.h"
+#include "ED_gpencil.h"
+
+#include "gpencil_engine.h"
+
+extern char datatoc_gpencil_fx_blur_frag_glsl[];
+extern char datatoc_gpencil_fx_colorize_frag_glsl[];
+extern char datatoc_gpencil_fx_flip_frag_glsl[];
+extern char datatoc_gpencil_fx_light_frag_glsl[];
+extern char datatoc_gpencil_fx_pixel_frag_glsl[];
+extern char datatoc_gpencil_fx_rim_prepare_frag_glsl[];
+extern char datatoc_gpencil_fx_rim_resolve_frag_glsl[];
+extern char datatoc_gpencil_fx_shadow_prepare_frag_glsl[];
+extern char datatoc_gpencil_fx_shadow_resolve_frag_glsl[];
+extern char datatoc_gpencil_fx_glow_prepare_frag_glsl[];
+extern char datatoc_gpencil_fx_glow_resolve_frag_glsl[];
+extern char datatoc_gpencil_fx_swirl_frag_glsl[];
+extern char datatoc_gpencil_fx_wave_frag_glsl[];
+
+/* verify if this fx is active */
+static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_render)
+{
+ if (fx == NULL) {
+ return false;
+ }
+
+ if (gpd == NULL) {
+ return false;
+ }
+
+ bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+ if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit)) {
+ return false;
+ }
+
+ if (((fx->mode & eShaderFxMode_Realtime) && (is_render == false)) ||
+ ((fx->mode & eShaderFxMode_Render) && (is_render == true)))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Get normal of draw using one stroke of visible layer
+ * \param gpd GP datablock
+ * \param r_point Point on plane
+ * \param r_normal Normal vector
+ */
+static bool get_normal_vector(bGPdata *gpd, float r_point[3], float r_normal[3])
+{
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* get frame */
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->totpoints >= 3) {
+ bGPDspoint *pt = &gps->points[0];
+ BKE_gpencil_stroke_normal(gps, r_normal);
+ /* in some weird situations, the normal cannot be calculated, so try next stroke */
+ if ((r_normal[0] != 0.0f) || (r_normal[1] != 0.0f) || (r_normal[2] != 0.0f)) {
+ copy_v3_v3(r_point, &pt->x);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/* helper to get near and far depth of field values */
+static void GPENCIL_dof_nearfar(Object *camera, float coc, float nearfar[2])
+{
+ if (camera == NULL) {
+ return;
+ }
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ Camera *cam = (Camera *)camera->data;
+
+ float fstop = cam->gpu_dof.fstop;
+ float focus_dist = BKE_camera_object_dof_distance(camera);
+ float focal_len = cam->lens;
+
+ /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
+ * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though
+ * because the shader reads coordinates in world space, which is in blender units.
+ * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */
+ float scale = (scene->unit.system) ? scene->unit.scale_length : 1.0f;
+ float scale_camera = 0.001f / scale;
+ /* we want radius here for the aperture number */
+ float aperture_scaled = 0.5f * scale_camera * focal_len / fstop;
+ float focal_len_scaled = scale_camera * focal_len;
+
+ float hyperfocal = (focal_len_scaled * focal_len_scaled) / (aperture_scaled * coc);
+ nearfar[0] = (hyperfocal * focus_dist) / (hyperfocal + focal_len);
+ nearfar[1] = (hyperfocal * focus_dist) / (hyperfocal - focal_len);
+}
+
+/* **************** Shader Effects ***************************** */
+
+/* Gaussian Blur FX
+ * The effect is done using two shading groups because is faster to apply horizontal
+ * and vertical in different operations.
+ */
+static void DRW_gpencil_fx_blur(
+ ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata, tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+
+ BlurShaderFxData *fxd = (BlurShaderFxData *)fx;
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ DRWShadingGroup *fx_shgrp;
+
+ fxd->blur[0] = fxd->radius[0];
+ fxd->blur[1] = fxd->radius[1];
+
+ /* init weight */
+ if (fxd->flag & FX_BLUR_DOF_MODE) {
+ /* viewport and opengl render */
+ Object *camera = NULL;
+ if (rv3d) {
+ if (rv3d->persp == RV3D_CAMOB) {
+ camera = v3d->camera;
+ }
+ }
+ else {
+ camera = stl->storage->camera;
+ }
+
+ if (camera) {
+ float nearfar[2];
+ GPENCIL_dof_nearfar(camera, fxd->coc, nearfar);
+ float zdepth = stl->g_data->gp_object_cache[ob_idx].zdepth;
+ /* the object is on focus area */
+ if ((zdepth >= nearfar[0]) && (zdepth <= nearfar[1])) {
+ fxd->blur[0] = 0;
+ fxd->blur[1] = 0;
+ }
+ else {
+ float f;
+ if (zdepth < nearfar[0]) {
+ f = nearfar[0] - zdepth;
+ }
+ else {
+ f = zdepth - nearfar[1];
+ }
+ fxd->blur[0] = f;
+ fxd->blur[1] = f;
+ CLAMP2(&fxd->blur[0], 0, fxd->radius[0]);
+ }
+ }
+ else {
+ /* if not camera view, the blur is disabled */
+ fxd->blur[0] = 0;
+ fxd->blur[1] = 0;
+ }
+ }
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_blur_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &cache->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &cache->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Colorize FX */
+static void DRW_gpencil_fx_colorize(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+{
+ if (fx == NULL) {
+ return;
+ }
+ ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_colorize_sh, psl->fx_shader_pass);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_vec4(fx_shgrp, "low_color", &fxd->low_color[0], 1);
+ DRW_shgroup_uniform_vec4(fx_shgrp, "high_color", &fxd->high_color[0], 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "factor", &fxd->factor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Flip FX */
+static void DRW_gpencil_fx_flip(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+{
+ if (fx == NULL) {
+ return;
+ }
+ FlipShaderFxData *fxd = (FlipShaderFxData *)fx;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+
+ fxd->flipmode = 100;
+ /* the number works as bit flag */
+ if (fxd->flag & FX_FLIP_HORIZONTAL) {
+ fxd->flipmode += 10;
+ }
+ if (fxd->flag & FX_FLIP_VERTICAL) {
+ fxd->flipmode += 1;
+ }
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_flip_sh, psl->fx_shader_pass);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_int(fx_shgrp, "flipmode", &fxd->flipmode, 1);
+
+ DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Light FX */
+static void DRW_gpencil_fx_light(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ LightShaderFxData *fxd = (LightShaderFxData *)fx;
+
+ if (fxd->object == NULL) {
+ return;
+ }
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_light_sh, psl->fx_shader_pass);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+
+ /* location of the light using obj location as origin */
+ copy_v3_v3(fxd->loc, &fxd->object->loc[0]);
+
+ /* Calc distance to strokes plane
+ * The w component of location is used to transfer the distance to drawing plane
+ */
+ float r_point[3], r_normal[3];
+ float r_plane[4];
+ bGPdata *gpd = cache->gpd;
+ if (!get_normal_vector(gpd, r_point, r_normal)) {
+ return;
+ }
+ mul_mat3_m4_v3(cache->obmat, r_normal); /* only rotation component */
+ plane_from_point_normal_v3(r_plane, r_point, r_normal);
+ float dt = dist_to_plane_v3(fxd->object->loc, r_plane);
+ fxd->loc[3] = dt; /* use last element to save it */
+
+ DRW_shgroup_uniform_vec4(fx_shgrp, "loc", &fxd->loc[0], 1);
+
+ DRW_shgroup_uniform_float(fx_shgrp, "energy", &fxd->energy, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "ambient", &fxd->ambient, 1);
+
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &cache->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Pixelate FX */
+static void DRW_gpencil_fx_pixel(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ PixelShaderFxData *fxd = (PixelShaderFxData *)fx;
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+ bGPdata *gpd = cache->gpd;
+
+ fxd->size[2] = (int)fxd->flag & FX_PIXEL_USE_LINES;
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_pixel_sh, psl->fx_shader_pass);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_int(fx_shgrp, "size", &fxd->size[0], 3);
+ DRW_shgroup_uniform_vec4(fx_shgrp, "color", &fxd->rgba[0], 1);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &cache->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Rim FX */
+static void DRW_gpencil_fx_rim(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ RimShaderFxData *fxd = (RimShaderFxData *)fx;
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ /* prepare pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_rim_prepare_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+
+ DRW_shgroup_uniform_int(fx_shgrp, "offset", &fxd->offset[0], 2);
+ DRW_shgroup_uniform_vec3(fx_shgrp, "rim_color", &fxd->rim_rgb[0], 1);
+ DRW_shgroup_uniform_vec3(fx_shgrp, "mask_color", &fxd->mask_rgb[0], 1);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &cache->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &cache->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+
+ /* blur pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_blur_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_fx);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_fx);
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &cache->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &cache->pixfactor, 1);
+
+ fxd->runtime.fx_sh_b = fx_shgrp;
+
+ /* resolve pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_rim_resolve_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeRim", &e_data->temp_color_tx_fx);
+ DRW_shgroup_uniform_vec3(fx_shgrp, "mask_color", &fxd->mask_rgb[0], 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
+
+ fxd->runtime.fx_sh_c = fx_shgrp;
+}
+
+/* Shadow FX */
+static void DRW_gpencil_fx_shadow(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
+ if ((!fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) {
+ return;
+ }
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ /* prepare pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_shadow_prepare_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+
+ DRW_shgroup_uniform_int(fx_shgrp, "offset", &fxd->offset[0], 2);
+ DRW_shgroup_uniform_float(fx_shgrp, "scale", &fxd->scale[0], 2);
+ DRW_shgroup_uniform_float(fx_shgrp, "rotation", &fxd->rotation, 1);
+ DRW_shgroup_uniform_vec4(fx_shgrp, "shadow_color", &fxd->shadow_rgba[0], 1);
+
+ if ((fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) {
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &fxd->object->loc[0], 1);
+ }
+ else {
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &cache->loc[0], 1);
+ }
+
+ const int nowave = -1;
+ if (fxd->flag & FX_SHADOW_USE_WAVE) {
+ DRW_shgroup_uniform_int(fx_shgrp, "orientation", &fxd->orientation, 1);
+ }
+ else {
+ DRW_shgroup_uniform_int(fx_shgrp, "orientation", &nowave, 1);
+ }
+ DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &fxd->amplitude, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "period", &fxd->period, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "phase", &fxd->phase, 1);
+
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &cache->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+
+ /* blur pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_blur_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_fx);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_fx);
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &cache->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &cache->pixfactor, 1);
+
+ fxd->runtime.fx_sh_b = fx_shgrp;
+
+ /* resolve pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_shadow_resolve_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowColor", &e_data->temp_color_tx_fx);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowDepth", &e_data->temp_depth_tx_fx);
+
+ fxd->runtime.fx_sh_c = fx_shgrp;
+}
+
+/* Glow FX */
+static void DRW_gpencil_fx_glow(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ GlowShaderFxData *fxd = (GlowShaderFxData *)fx;
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ /* prepare pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_glow_prepare_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "glow_color", &fxd->glow_color[0], 1);
+ DRW_shgroup_uniform_vec3(fx_shgrp, "select_color", &fxd->select_color[0], 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "threshold", &fxd->threshold, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+
+ /* blur pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_blur_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_fx);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_fx);
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &cache->loc[0], 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &cache->pixfactor, 1);
+
+ fxd->runtime.fx_sh_b = fx_shgrp;
+
+ /* resolve pass */
+ fx_shgrp = DRW_shgroup_create(
+ e_data->gpencil_fx_glow_resolve_sh,
+ psl->fx_shader_pass_blend);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowColor", &e_data->temp_color_tx_fx);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowDepth", &e_data->temp_depth_tx_fx);
+
+ /* reuse field */
+ DRW_shgroup_uniform_int(fx_shgrp, "alpha_mode", &fxd->blur[1], 1);
+
+ fxd->runtime.fx_sh_c = fx_shgrp;
+}
+
+/* Swirl FX */
+static void DRW_gpencil_fx_swirl(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ if (fx == NULL) {
+ return;
+ }
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+ if (fxd->object == NULL) {
+ return;
+ }
+
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ DRWShadingGroup *fx_shgrp;
+
+ fxd->transparent = (int)fxd->flag & FX_SWIRL_MAKE_TRANSPARENT;
+
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_swirl_sh, psl->fx_shader_pass);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+
+ DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+
+ DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &fxd->object->loc[0], 1);
+
+ DRW_shgroup_uniform_int(fx_shgrp, "radius", &fxd->radius, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "angle", &fxd->angle, 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "transparent", &fxd->transparent, 1);
+
+ DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &cache->pixfactor, 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* Wave Distorsion FX */
+static void DRW_gpencil_fx_wave(
+ ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+{
+ if (fx == NULL) {
+ return;
+ }
+
+ WaveShaderFxData *fxd = (WaveShaderFxData *)fx;
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+
+ DRWShadingGroup *fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_wave_sh, psl->fx_shader_pass);
+ DRW_shgroup_call_add(fx_shgrp, fxquad, NULL);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a);
+ DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a);
+ DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &fxd->amplitude, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "period", &fxd->period, 1);
+ DRW_shgroup_uniform_float(fx_shgrp, "phase", &fxd->phase, 1);
+ DRW_shgroup_uniform_int(fx_shgrp, "orientation", &fxd->orientation, 1);
+ DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1);
+
+ fxd->runtime.fx_sh = fx_shgrp;
+}
+
+/* ************************************************************** */
+
+/* create all FX shaders */
+void GPENCIL_create_fx_shaders(GPENCIL_e_data *e_data)
+{
+ /* fx shaders (all in screen space) */
+ if (!e_data->gpencil_fx_blur_sh) {
+ e_data->gpencil_fx_blur_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_blur_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_colorize_sh) {
+ e_data->gpencil_fx_colorize_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_colorize_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_flip_sh) {
+ e_data->gpencil_fx_flip_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_flip_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_light_sh) {
+ e_data->gpencil_fx_light_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_light_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_pixel_sh) {
+ e_data->gpencil_fx_pixel_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_pixel_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_rim_prepare_sh) {
+ e_data->gpencil_fx_rim_prepare_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_rim_prepare_frag_glsl, NULL);
+
+ e_data->gpencil_fx_rim_resolve_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_rim_resolve_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_shadow_prepare_sh) {
+ e_data->gpencil_fx_shadow_prepare_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_shadow_prepare_frag_glsl, NULL);
+
+ e_data->gpencil_fx_shadow_resolve_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_shadow_resolve_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_glow_prepare_sh) {
+ e_data->gpencil_fx_glow_prepare_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_glow_prepare_frag_glsl, NULL);
+
+ e_data->gpencil_fx_glow_resolve_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_glow_resolve_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_swirl_sh) {
+ e_data->gpencil_fx_swirl_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_swirl_frag_glsl, NULL);
+ }
+ if (!e_data->gpencil_fx_wave_sh) {
+ e_data->gpencil_fx_wave_sh = DRW_shader_create_fullscreen(
+ datatoc_gpencil_fx_wave_frag_glsl, NULL);
+ }
+}
+
+/* free FX shaders */
+void GPENCIL_delete_fx_shaders(GPENCIL_e_data *e_data)
+{
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_blur_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_colorize_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_flip_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_light_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_pixel_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_rim_prepare_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_rim_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_shadow_prepare_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_shadow_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_glow_prepare_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_glow_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_swirl_sh);
+ DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_wave_sh);
+}
+
+/* create all passes used by FX */
+void GPENCIL_create_fx_passes(GPENCIL_PassList *psl)
+{
+ psl->fx_shader_pass = DRW_pass_create(
+ "GPencil Shader FX Pass",
+ DRW_STATE_WRITE_COLOR |
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ psl->fx_shader_pass_blend = DRW_pass_create(
+ "GPencil Shader FX Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND |
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+}
+
+
+/* prepare fx shading groups */
+void DRW_gpencil_fx_prepare(
+ GPENCIL_e_data *e_data, GPENCIL_Data *vedata,
+ tGPencilObjectCache *cache)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ int ob_idx = cache->idx;
+
+ if (cache->shader_fx.first == NULL) {
+ return;
+ }
+ /* loop FX */
+ for (ShaderFxData *fx = cache->shader_fx.first; fx; fx = fx->next) {
+ if (effect_is_active(cache->gpd, fx, stl->storage->is_render)) {
+ switch (fx->type) {
+ case eShaderFxType_Blur:
+ DRW_gpencil_fx_blur(fx, ob_idx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Colorize:
+ DRW_gpencil_fx_colorize(fx, e_data, vedata);
+ break;
+ case eShaderFxType_Flip:
+ DRW_gpencil_fx_flip(fx, e_data, vedata);
+ break;
+ case eShaderFxType_Light:
+ DRW_gpencil_fx_light(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Pixel:
+ DRW_gpencil_fx_pixel(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Rim:
+ DRW_gpencil_fx_rim(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Shadow:
+ DRW_gpencil_fx_shadow(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Glow:
+ DRW_gpencil_fx_glow(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Swirl:
+ DRW_gpencil_fx_swirl(fx, e_data, vedata, cache);
+ break;
+ case eShaderFxType_Wave:
+ DRW_gpencil_fx_wave(fx, e_data, vedata);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+}
+
+/* helper to draw one FX pass and do ping-pong copy */
+static void gpencil_draw_fx_pass(
+ GPENCIL_e_data *e_data,
+ GPENCIL_PassList *psl,
+ GPENCIL_FramebufferList *fbl,
+ DRWShadingGroup *shgrp, bool blend)
+{
+ if (shgrp == NULL) {
+ return;
+ }
+
+ const float clearcol[4] = {0.0f};
+ GPU_framebuffer_bind(fbl->temp_fb_b);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
+
+ /* draw effect pass in temp texture (B) using as source the previous image
+ * existing in the other temp texture (A) */
+ if (!blend) {
+ DRW_draw_pass_subset(psl->fx_shader_pass, shgrp, shgrp);
+ }
+ else {
+ DRW_draw_pass_subset(psl->fx_shader_pass_blend, shgrp, shgrp);
+ }
+
+ /* copy pass from b to a for ping-pong frame buffers */
+ e_data->input_depth_tx = e_data->temp_depth_tx_b;
+ e_data->input_color_tx = e_data->temp_color_tx_b;
+
+ GPU_framebuffer_bind(fbl->temp_fb_a);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
+ DRW_draw_pass(psl->mix_pass_noblend);
+}
+
+/* helper to manage gaussian blur passes */
+static void draw_gpencil_blur_passes(
+ GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
+ BlurShaderFxData *fxd)
+{
+ if (fxd->runtime.fx_sh == NULL) {
+ return;
+ }
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ DRWShadingGroup *shgrp = fxd->runtime.fx_sh;
+ int samples = fxd->samples;
+
+ float bx = fxd->blur[0];
+ float by = fxd->blur[1];
+
+ /* the blur is done in two steps (Hor/Ver) because is faster and
+ * gets better result
+ *
+ * samples could be 0 and disable de blur effects because sometimes
+ * is easier animate the number of samples only, instead to animate the
+ * hide/unhide and the number of samples to make some effects.
+ */
+ for (int b = 0; b < samples; b++) {
+ /* horizontal */
+ if (bx > 0) {
+ fxd->blur[0] = bx;
+ fxd->blur[1] = 0;
+ gpencil_draw_fx_pass(e_data, psl, fbl, shgrp, true);
+ }
+ /* vertical */
+ if (by > 0) {
+ fxd->blur[0] = 0;
+ fxd->blur[1] = by;
+ gpencil_draw_fx_pass(e_data, psl, fbl, shgrp, true);
+ }
+ }
+}
+
+/* blur intermediate pass */
+static void draw_gpencil_midpass_blur(
+ GPENCIL_Data *vedata,
+ ShaderFxData_Runtime *runtime)
+{
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ const float clearcol[4] = {0.0f};
+
+ GPU_framebuffer_bind(fbl->temp_fb_b);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
+ DRW_draw_pass_subset(psl->fx_shader_pass_blend,
+ runtime->fx_sh_b, runtime->fx_sh_b);
+
+ /* copy pass from b for ping-pong frame buffers */
+ GPU_framebuffer_bind(fbl->temp_fb_fx);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
+ DRW_draw_pass(psl->mix_pass_noblend);
+}
+
+/* do blur of mid passes */
+static void draw_gpencil_do_blur(
+ GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
+ ShaderFxData_Runtime *runtime,
+ int samples, int bx, int by, int blur[2])
+{
+ e_data->input_depth_tx = e_data->temp_depth_tx_b;
+ e_data->input_color_tx = e_data->temp_color_tx_b;
+
+ if ((samples > 0) && ((bx > 0) || (by > 0))) {
+ for (int x = 0; x < samples; x++) {
+
+ /* horizontal */
+ blur[0] = bx;
+ blur[1] = 0;
+ draw_gpencil_midpass_blur(vedata, runtime);
+
+ /* Vertical */
+ blur[0] = 0;
+ blur[1] = by;
+ draw_gpencil_midpass_blur(vedata, runtime);
+
+ blur[0] = bx;
+ blur[1] = by;
+ }
+ }
+}
+
+/* helper to draw RIM passes */
+static void draw_gpencil_rim_passes(
+ GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
+ RimShaderFxData *fxd)
+{
+ if (fxd->runtime.fx_sh_b == NULL) {
+ return;
+ }
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+
+ const float clearcol[4] = {0.0f};
+
+ /* prepare mask */
+ GPU_framebuffer_bind(fbl->temp_fb_fx);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
+ DRW_draw_pass_subset(
+ psl->fx_shader_pass_blend,
+ fxd->runtime.fx_sh, fxd->runtime.fx_sh);
+
+ /* blur rim */
+ draw_gpencil_do_blur(
+ e_data, vedata, &fxd->runtime,
+ fxd->samples,
+ fxd->blur[0], fxd->blur[1],
+ &fxd->blur[0]);
+
+ /* resolve */
+ GPU_framebuffer_bind(fbl->temp_fb_b);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
+ DRW_draw_pass_subset(
+ psl->fx_shader_pass_blend,
+ fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
+
+ /* copy pass from b to a for ping-pong frame buffers */
+ e_data->input_depth_tx = e_data->temp_depth_tx_b;
+ e_data->input_color_tx = e_data->temp_color_tx_b;
+
+ GPU_framebuffer_bind(fbl->temp_fb_a);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
+ DRW_draw_pass(psl->mix_pass_noblend);
+}
+
+/* helper to draw SHADOW passes */
+static void draw_gpencil_shadow_passes(
+ GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
+ ShadowShaderFxData *fxd)
+{
+ if (fxd->runtime.fx_sh_b == NULL) {
+ return;
+ }
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ const float clearcol[4] = {0.0f};
+
+ /* prepare shadow */
+ GPU_framebuffer_bind(fbl->temp_fb_fx);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
+ DRW_draw_pass_subset(
+ psl->fx_shader_pass_blend,
+ fxd->runtime.fx_sh, fxd->runtime.fx_sh);
+
+ /* blur shadow */
+ draw_gpencil_do_blur(
+ e_data, vedata, &fxd->runtime,
+ fxd->samples,
+ fxd->blur[0], fxd->blur[1],
+ &fxd->blur[0]);
+
+ /* resolve */
+ GPU_framebuffer_bind(fbl->temp_fb_b);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
+ DRW_draw_pass_subset(
+ psl->fx_shader_pass_blend,
+ fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
+
+ /* copy pass from b to a for ping-pong frame buffers */
+ e_data->input_depth_tx = e_data->temp_depth_tx_b;
+ e_data->input_color_tx = e_data->temp_color_tx_b;
+
+ GPU_framebuffer_bind(fbl->temp_fb_a);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
+ DRW_draw_pass(psl->mix_pass_noblend);
+}
+
+/* helper to draw GLOW passes */
+static void draw_gpencil_glow_passes(
+ GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata,
+ GlowShaderFxData *fxd)
+{
+ if (fxd->runtime.fx_sh_b == NULL) {
+ return;
+ }
+
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+
+ const float clearcol[4] = {0.0f};
+
+ /* prepare glow */
+ GPU_framebuffer_bind(fbl->temp_fb_fx);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
+ DRW_draw_pass_subset(
+ psl->fx_shader_pass_blend,
+ fxd->runtime.fx_sh, fxd->runtime.fx_sh);
+
+ /* blur glow */
+ draw_gpencil_do_blur(
+ e_data, vedata, &fxd->runtime,
+ fxd->samples,
+ fxd->blur[0], fxd->blur[0],
+ &fxd->blur[0]);
+
+ /* resolve */
+ GPU_framebuffer_bind(fbl->temp_fb_b);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
+
+ /* reuses blur field to keep alpha mode */
+ fxd->blur[1] = (fxd->flag & FX_GLOW_USE_ALPHA) ? 1 : 0;
+
+ DRW_draw_pass_subset(
+ psl->fx_shader_pass_blend,
+ fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
+
+ /* copy pass from b to a for ping-pong frame buffers */
+ e_data->input_depth_tx = e_data->temp_depth_tx_b;
+ e_data->input_color_tx = e_data->temp_color_tx_b;
+
+ GPU_framebuffer_bind(fbl->temp_fb_a);
+ GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
+ DRW_draw_pass(psl->mix_pass_noblend);
+}
+
+/* apply all object fx effects */
+void DRW_gpencil_fx_draw(
+ GPENCIL_e_data *e_data,
+ GPENCIL_Data *vedata, tGPencilObjectCache *cache)
+{
+ GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+ GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+
+ /* loop FX modifiers */
+ for (ShaderFxData *fx = cache->shader_fx.first; fx; fx = fx->next) {
+ if (effect_is_active(cache->gpd, fx, stl->storage->is_render)) {
+ switch (fx->type) {
+
+ case eShaderFxType_Blur:
+ {
+ BlurShaderFxData *fxd = (BlurShaderFxData *)fx;
+ draw_gpencil_blur_passes(e_data, vedata, fxd);
+ break;
+ }
+ case eShaderFxType_Colorize:
+ {
+ ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Flip:
+ {
+ FlipShaderFxData *fxd = (FlipShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Light:
+ {
+ LightShaderFxData *fxd = (LightShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Pixel:
+ {
+ PixelShaderFxData *fxd = (PixelShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Rim:
+ {
+ RimShaderFxData *fxd = (RimShaderFxData *)fx;
+ draw_gpencil_rim_passes(e_data, vedata, fxd);
+ break;
+ }
+ case eShaderFxType_Shadow:
+ {
+ ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
+ draw_gpencil_shadow_passes(e_data, vedata, fxd);
+ break;
+ }
+ case eShaderFxType_Glow:
+ {
+ GlowShaderFxData *fxd = (GlowShaderFxData *)fx;
+ draw_gpencil_glow_passes(e_data, vedata, fxd);
+ break;
+ }
+ case eShaderFxType_Swirl:
+ {
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ case eShaderFxType_Wave:
+ {
+ WaveShaderFxData *fxd = (WaveShaderFxData *)fx;
+ gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl
new file mode 100644
index 00000000000..e59cbef3e5d
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl
@@ -0,0 +1,87 @@
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrix;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform vec2 Viewport;
+
+uniform int blur[2];
+
+uniform vec3 loc;
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixfactor;
+
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+vec2 noffset = vec2(blur[0], blur[1]);
+
+out vec4 FragColor;
+
+float get_zdepth(ivec2 poxy)
+{
+ /* if outside viewport set as infinite depth */
+ if ((poxy.x < 0) || (poxy.x > Viewport.x)) {
+ return 1.0f;
+ }
+ if ((poxy.y < 0) || (poxy.y > Viewport.y)) {
+ return 1.0f;
+ }
+
+ float zdepth = texelFetch(strokeDepth, poxy, 0).r;
+ return zdepth;
+}
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+
+ vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
+
+ float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) : (noffset[0] / defaultpixsize);
+ float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) : (noffset[1] / defaultpixsize);
+
+ /* round to avoid shift when add more samples */
+ dx = floor(dx) + 1.0;
+ dy = floor(dy) + 1.0;
+
+ /* apply blurring, using a 9-tap filter with predefined gaussian weights */
+ /* depth (get the value of the surrounding pixels) */
+ float outdepth = 0.0;
+
+ outdepth += get_zdepth(ivec2(uv.x - 1.0 * dx, uv.y + 1.0 * dy)) * 0.0947416;
+ outdepth += get_zdepth(ivec2(uv.x - 0.0 * dx, uv.y + 1.0 * dy)) * 0.118318;
+ outdepth += get_zdepth(ivec2(uv.x + 1.0 * dx, uv.y + 1.0 * dy)) * 0.0947416;
+ outdepth += get_zdepth(ivec2(uv.x - 1.0 * dx, uv.y + 0.0 * dy)) * 0.118318;
+
+ outdepth += get_zdepth(ivec2(uv.x, uv.y)) * 0.147761;
+
+ outdepth += get_zdepth(ivec2(uv.x + 1.0 * dx, uv.y + 0.0 * dy)) * 0.118318;
+ outdepth += get_zdepth(ivec2(uv.x - 1.0 * dx, uv.y - 1.0 * dy)) * 0.0947416;
+ outdepth += get_zdepth(ivec2(uv.x + 0.0 * dx, uv.y - 1.0 * dy)) * 0.118318;
+ outdepth += get_zdepth(ivec2(uv.x + 1.0 * dx, uv.y - 1.0 * dy)) * 0.0947416;
+
+ gl_FragDepth = outdepth;
+
+ /* color */
+ vec4 outcolor = vec4(0.0);
+ outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416;
+ outcolor += texelFetch(strokeColor, ivec2(uv.x - 0.0 * dx, uv.y + 1.0 * dy), 0) * 0.118318;
+ outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416;
+ outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 0.0 * dy), 0) * 0.118318;
+
+ outcolor += texelFetch(strokeColor, ivec2(uv.x, uv.y), 0) * 0.147761;
+
+ outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y + 0.0 * dy), 0) * 0.118318;
+ outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y - 1.0 * dy), 0) * 0.0947416;
+ outcolor += texelFetch(strokeColor, ivec2(uv.x + 0.0 * dx, uv.y - 1.0 * dy), 0) * 0.118318;
+ outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y - 1.0 * dy), 0) * 0.0947416;
+
+ FragColor = clamp(outcolor, 0, 1.0);
+
+ /* discar extreme values */
+ if (outcolor.a < 0.02f) {
+ discard;
+ }
+ if ((outdepth <= 0.000001) || (outdepth >= 0.999999)){
+ discard;
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl
new file mode 100644
index 00000000000..33b249ac09b
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl
@@ -0,0 +1,86 @@
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+
+uniform vec4 low_color;
+uniform vec4 high_color;
+uniform int mode;
+uniform float factor;
+
+out vec4 FragColor;
+
+#define MODE_GRAYSCALE 0
+#define MODE_SEPIA 1
+#define MODE_BITONE 2
+#define MODE_CUSTOM 3
+#define MODE_TRANSPARENT 4
+
+float get_luminance(vec4 color)
+{
+ float lum = (color.r * 0.2126) + (color.g * 0.7152) + (color.b * 0.723);
+ return lum;
+}
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+
+ float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
+ vec4 src_pixel= texelFetch(strokeColor, uv.xy, 0);
+ float luminance = get_luminance(src_pixel);
+ vec4 outcolor;
+
+ /* is transparent */
+ if (src_pixel.a == 0.0f) {
+ discard;
+ }
+
+ switch(mode) {
+ case MODE_GRAYSCALE:
+ {
+ outcolor = vec4(luminance, luminance, luminance, src_pixel.a);
+ break;
+ }
+ case MODE_SEPIA:
+ {
+ float Red = (src_pixel.r * 0.393) + (src_pixel.g * 0.769) + (src_pixel.b * 0.189);
+ float Green = (src_pixel.r * 0.349) + (src_pixel.g * 0.686) + (src_pixel.b * 0.168);
+ float Blue = (src_pixel.r * 0.272) + (src_pixel.g * 0.534) + (src_pixel.b * 0.131);
+ outcolor = vec4(Red, Green, Blue, src_pixel.a);
+ break;
+ }
+ case MODE_BITONE:
+ {
+ if (luminance <= factor) {
+ outcolor = low_color;
+ }
+ else {
+ outcolor = high_color;
+ }
+ break;
+ }
+ case MODE_CUSTOM:
+ {
+ /* if below umbral, force custom color */
+ if (luminance <= factor) {
+ outcolor = low_color;
+ }
+ else {
+ outcolor = vec4(luminance * low_color.r, luminance * low_color.b, luminance * low_color.b, src_pixel.a);
+ }
+ break;
+ }
+ case MODE_TRANSPARENT:
+ {
+ outcolor = vec4(src_pixel.rgb, src_pixel.a * factor);
+ break;
+ }
+ default:
+ {
+ outcolor = src_pixel;
+ }
+
+ }
+
+ gl_FragDepth = stroke_depth;
+ FragColor = outcolor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl
new file mode 100644
index 00000000000..43589461cd1
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl
@@ -0,0 +1,37 @@
+out vec4 FragColor;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform vec2 wsize;
+uniform int flipmode;
+
+void main()
+{
+ vec2 mode = vec2(0,0);
+ /* horz. */
+ if (flipmode >= 110) {
+ mode[0] = 1;
+ }
+ /* vert. */
+ if ((flipmode == 101) || (flipmode == 111)) {
+ mode[1] = 1;
+ }
+
+ vec2 uv = vec2(gl_FragCoord.xy);
+ float stroke_depth;
+ vec4 outcolor;
+
+ if (mode[0] > 0) {
+ uv.x = wsize.x - uv.x;
+ }
+ if (mode[1] > 0) {
+ uv.y = wsize.y - uv.y;
+ }
+
+ ivec2 iuv = ivec2(uv.x, uv.y);
+ stroke_depth = texelFetch(strokeDepth, iuv, 0).r;
+ outcolor = texelFetch(strokeColor, iuv, 0);
+
+ gl_FragDepth = stroke_depth;
+ FragColor = outcolor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl
new file mode 100644
index 00000000000..9cdcad3e486
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl
@@ -0,0 +1,68 @@
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrix;
+
+/* ******************************************************************* */
+/* create glow mask */
+/* ******************************************************************* */
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+
+uniform vec3 glow_color;
+uniform vec3 select_color;
+uniform float threshold;
+uniform int mode;
+
+out vec4 FragColor;
+
+#define MODE_LUMINANCE 0
+#define MODE_COLOR 1
+
+/* calc luminance */
+float luma( vec3 color ) {
+ /* the color is linear, so do not apply tonemapping */
+ return (color.r + color.g + color.b) / 3.0;
+}
+
+bool check_color(vec3 color_a, vec3 color_b)
+{
+ /* need round the number to avoid precision errors */
+ if ((floor(color_a.r * 100) == floor(color_b.r * 100)) &&
+ (floor(color_a.g * 100) == floor(color_b.g * 100)) &&
+ (floor(color_a.b * 100) == floor(color_b.b * 100)))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void main()
+{
+ vec2 uv = vec2(gl_FragCoord.xy);
+
+ float stroke_depth = texelFetch(strokeDepth, ivec2(uv.xy), 0).r;
+ vec4 src_pixel= texelFetch(strokeColor, ivec2(uv.xy), 0);
+ vec4 outcolor;
+
+ /* is transparent */
+ if (src_pixel.a == 0.0f) {
+ discard;
+ }
+
+ if (mode == MODE_LUMINANCE) {
+ if (luma(src_pixel.rgb) < threshold) {
+ discard;
+ }
+ }
+ else if (mode == MODE_COLOR) {
+ if (!check_color(src_pixel.rgb, select_color.rgb)) {
+ discard;
+ }
+ }
+ else {
+ discard;
+ }
+
+ gl_FragDepth = stroke_depth;
+ FragColor = vec4(glow_color.rgb, 1.0);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl
new file mode 100644
index 00000000000..5bff7a20523
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl
@@ -0,0 +1,46 @@
+/* ******************************************************************* */
+/* Resolve GLOW pass */
+/* ******************************************************************* */
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform sampler2D glowColor;
+uniform sampler2D glowDepth;
+uniform int alpha_mode;
+
+out vec4 FragColor;
+
+void main()
+{
+ vec4 outcolor;
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+
+ float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
+ vec4 src_pixel= texelFetch(strokeColor, uv.xy, 0);
+ vec4 glow_pixel= texelFetch(glowColor, uv.xy, 0);
+ float glow_depth = texelFetch(glowDepth, uv.xy, 0).r;
+
+ if (alpha_mode == 0) {
+ outcolor = src_pixel + glow_pixel;
+ }
+ else {
+ if ((src_pixel.a < 0.1) || (glow_pixel.a < 0.1)) {
+ outcolor = src_pixel + glow_pixel;
+ }
+ else {
+ outcolor = src_pixel;
+ }
+ }
+
+ if (src_pixel.a < glow_pixel.a) {
+ gl_FragDepth = glow_depth;
+ }
+ else {
+ gl_FragDepth = stroke_depth;
+ }
+
+ if (outcolor.a < 0.001) {
+ discard;
+ }
+
+ FragColor = outcolor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl
new file mode 100644
index 00000000000..c12dd223ebe
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl
@@ -0,0 +1,69 @@
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrix;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform vec2 Viewport;
+uniform vec4 loc;
+uniform float energy;
+uniform float ambient;
+
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixfactor;
+
+out vec4 FragColor;
+
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+
+#define height loc.w
+
+/* project 3d point to 2d on screen space */
+vec2 toScreenSpace(vec4 vertex)
+{
+ /* need to calculate ndc because this is not done by vertex shader */
+ vec3 ndc = vec3(vertex).xyz / vertex.w;
+
+ vec2 sc;
+ sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
+ sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
+
+ return sc;
+}
+
+void main()
+{
+ float stroke_depth;
+ vec4 objcolor;
+
+ vec4 light_loc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
+ vec2 light2d = toScreenSpace(light_loc);
+
+ /* calc pixel scale */
+ float pxscale = (ProjectionMatrix[3][3] == 0.0) ? (10.0 / (light_loc.z * defaultpixsize)) : (10.0 / defaultpixsize);
+ pxscale = max(pxscale, 0.000001);
+
+ /* the height over plane is received in the w component of the loc
+ * and needs a factor to adapt to pixels
+ */
+ float peak = height * 10.0 * pxscale;
+ vec3 light3d = vec3(light2d.x, light2d.y, peak);
+
+ vec2 uv = vec2(gl_FragCoord.xy);
+ vec3 frag_loc = vec3(uv.x, uv.y, 0);
+ vec3 norm = vec3(0, 0, 1.0); /* always z-up */
+
+ ivec2 iuv = ivec2(uv.x, uv.y);
+ stroke_depth = texelFetch(strokeDepth, iuv, 0).r;
+ objcolor = texelFetch(strokeColor, iuv, 0);
+
+ /* diffuse light */
+ vec3 lightdir = normalize(light3d - frag_loc);
+ float diff = max(dot(norm, lightdir), 0.0);
+ float dist = length(light3d - frag_loc) / pxscale;
+ float factor = diff * ((energy * 100.0) / (dist * dist));
+
+ vec3 result = factor * max(ambient, 0.1) * vec3(objcolor);
+
+ gl_FragDepth = stroke_depth;
+ FragColor = vec4(result.r, result.g, result.b, objcolor.a);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl
new file mode 100644
index 00000000000..eb5596c639a
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl
@@ -0,0 +1,49 @@
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrix;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+
+uniform int size[3];
+uniform vec4 color;
+
+uniform vec3 loc;
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixfactor;
+
+out vec4 FragColor;
+
+int uselines = size[2];
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+vec2 nsize = max(vec2(size[0], size[1]), 3.0);
+
+/* This pixelation shader is a modified version of original Geeks3d.com code */
+void main()
+{
+ vec2 uv = vec2(gl_FragCoord.xy);
+ vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
+
+ float dx = (ProjectionMatrix[3][3] == 0.0) ? (nsize[0] / (nloc.z * defaultpixsize)) : (nsize[0] / defaultpixsize);
+ float dy = (ProjectionMatrix[3][3] == 0.0) ? (nsize[1] / (nloc.z * defaultpixsize)) : (nsize[1] / defaultpixsize);
+
+ dx = max(abs(dx), 3.0);
+ dy = max(abs(dy), 3.0);
+
+ vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));
+
+ float stroke_depth = texelFetch(strokeDepth, ivec2(coord), 0).r;
+ vec4 outcolor = texelFetch(strokeColor, ivec2(coord), 0);
+
+ if (uselines == 1) {
+ float difx = uv.x - (floor(uv.x / nsize[0]) * nsize[0]);
+ if ((difx == 0.5) && (outcolor.a > 0)) {
+ outcolor = color;
+ }
+ float dify = uv.y - (floor(uv.y / nsize[1]) * nsize[1]);
+ if ((dify == 0.5) && (outcolor.a > 0)) {
+ outcolor = color;
+ }
+ }
+ gl_FragDepth = stroke_depth;
+ FragColor = outcolor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl
new file mode 100644
index 00000000000..2321429fbf1
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl
@@ -0,0 +1,63 @@
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrix;
+
+/* ******************************************************************* */
+/* create rim and mask */
+/* ******************************************************************* */
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform vec2 Viewport;
+
+uniform int offset[2];
+uniform vec3 rim_color;
+uniform vec3 mask_color;
+
+uniform vec3 loc;
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixfactor;
+
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+vec2 noffset = vec2(offset[0], offset[1]);
+
+out vec4 FragColor;
+
+void main()
+{
+ vec2 uv = vec2(gl_FragCoord.xy);
+ vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
+
+ float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) : (noffset[0] / defaultpixsize);
+ float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) : (noffset[1] / defaultpixsize);
+
+ float stroke_depth = texelFetch(strokeDepth, ivec2(uv.xy), 0).r;
+ vec4 src_pixel= texelFetch(strokeColor, ivec2(uv.xy), 0);
+ vec4 offset_pixel= texelFetch(strokeColor, ivec2(uv.x - dx, uv.y - dy), 0);
+ vec4 outcolor;
+
+ /* is transparent */
+ if (src_pixel.a == 0.0f) {
+ discard;
+ }
+ /* check inside viewport */
+ else if ((uv.x - dx < 0) || (uv.x - dx > Viewport[0])) {
+ discard;
+ }
+ else if ((uv.y - dy < 0) || (uv.y - dy > Viewport[1])) {
+ discard;
+ }
+ /* pixel is equal to mask color, keep */
+ else if (src_pixel.rgb == mask_color.rgb) {
+ discard;
+ }
+ else {
+ if ((src_pixel.a > 0) && (offset_pixel.a > 0)) {
+ discard;
+ }
+ else {
+ outcolor = vec4(rim_color, 1.0);
+ }
+ }
+
+ gl_FragDepth = stroke_depth;
+ FragColor = outcolor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl
new file mode 100644
index 00000000000..0a7eb65d564
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl
@@ -0,0 +1,98 @@
+/* ******************************************************************* */
+/* Resolve RIM pass and add blur if needed */
+/* ******************************************************************* */
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform sampler2D strokeRim;
+
+uniform vec3 mask_color;
+uniform int mode;
+
+out vec4 FragColor;
+
+#define MODE_NORMAL 0
+#define MODE_OVERLAY 1
+#define MODE_ADD 2
+#define MODE_SUB 3
+#define MODE_MULTIPLY 4
+#define MODE_DIVIDE 5
+
+float overlay_color(float a, float b)
+{
+ float rtn;
+ if (a < 0.5) {
+ rtn = 2.0 * a * b;
+ }
+ else {
+ rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);
+ }
+
+ return rtn;
+}
+
+vec4 get_blend_color(int mode, vec4 src_color, vec4 mix_color)
+{
+ vec4 outcolor;
+ if (mode == MODE_NORMAL) {
+ outcolor = mix_color;
+ }
+ else if (mode == MODE_OVERLAY) {
+ outcolor.r = overlay_color(src_color.r, mix_color.r);
+ outcolor.g = overlay_color(src_color.g, mix_color.g);
+ outcolor.b = overlay_color(src_color.b, mix_color.b);
+ }
+ else if (mode == MODE_ADD){
+ outcolor = src_color + mix_color;
+ }
+ else if (mode == MODE_SUB){
+ outcolor = src_color - mix_color;
+ }
+ else if (mode == MODE_MULTIPLY) {
+ outcolor = src_color * mix_color;
+ }
+ else if (mode == MODE_DIVIDE) {
+ outcolor = src_color / mix_color;
+ }
+ else {
+ outcolor = mix_color;
+ }
+
+ /* use always the alpha of source color */
+
+ outcolor.a = src_color.a;
+ /* use alpha to calculate the weight of the mixed color */
+ outcolor = mix(src_color, outcolor, mix_color.a);
+
+ return outcolor;
+}
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+
+ float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
+ vec4 src_pixel= texelFetch(strokeColor, uv.xy, 0);
+ vec4 rim_pixel= texelFetch(strokeRim, uv.xy, 0);
+
+ vec4 outcolor = src_pixel;
+
+ /* is transparent */
+ if (src_pixel.a == 0.0f) {
+ discard;
+ }
+ /* pixel is equal to mask color, keep */
+ else if (src_pixel.rgb == mask_color.rgb) {
+ outcolor = src_pixel;
+ }
+ else {
+ if (rim_pixel.a == 0.0f) {
+ outcolor = src_pixel;
+ }
+ else {
+ outcolor = get_blend_color(mode, src_pixel, rim_pixel);
+ }
+ }
+
+ gl_FragDepth = stroke_depth;
+ FragColor = outcolor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl
new file mode 100644
index 00000000000..8bb92f69723
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl
@@ -0,0 +1,97 @@
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrix;
+
+/* ******************************************************************* */
+/* create shadow */
+/* ******************************************************************* */
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform vec2 Viewport;
+
+uniform int offset[2];
+uniform float scale[2];
+uniform float rotation;
+uniform vec4 shadow_color;
+
+uniform float amplitude;
+uniform float period;
+uniform float phase;
+uniform int orientation;
+
+uniform vec3 loc;
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixfactor;
+
+#define M_PI 3.1415926535897932384626433832795
+
+#define HORIZONTAL 0
+#define VERTICAL 1
+
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+vec2 noffset = vec2(offset[0], offset[1]);
+float cosv = cos(rotation);
+float sinv = sin(rotation);
+
+out vec4 FragColor;
+
+/* project 3d point to 2d on screen space */
+vec2 toScreenSpace(vec4 vertex)
+{
+ /* need to calculate ndc because this is not done by vertex shader */
+ vec3 ndc = vec3(vertex).xyz / vertex.w;
+
+ vec2 sc;
+ sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
+ sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
+
+ return sc;
+}
+
+void main()
+{
+ vec2 uv = vec2(gl_FragCoord.xy);
+ vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
+ vec2 loc2d = toScreenSpace(nloc);
+
+ float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) : (noffset[0] / defaultpixsize);
+ float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) : (noffset[1] / defaultpixsize);
+
+
+ /* move point to new coords system */
+ vec2 tpos = vec2(uv.x, uv.y) - loc2d;
+
+ /* rotation */
+ if (rotation != 0) {
+ vec2 rotpoint = vec2((tpos.x * cosv) - (tpos.y * sinv), (tpos.x * sinv) + (tpos.y * cosv));
+ tpos = rotpoint;
+ }
+
+ /* apply offset */
+ tpos = vec2(tpos.x - dx, tpos.y - dy);
+
+ /* apply scale */
+ tpos.x *= 1.0 / scale[0];
+ tpos.y *= 1.0 / scale[1];
+
+ /* back to original coords system */
+ vec2 texpos = tpos + loc2d;
+
+ /* wave */
+ if (orientation == HORIZONTAL) {
+ float pval = (uv.x * M_PI) / Viewport[0];
+ texpos.y += amplitude * sin((period * pval) + phase);
+ }
+ else if (orientation == VERTICAL){
+ float pval = (uv.y * M_PI) / Viewport[1];
+ texpos.x += amplitude * sin((period * pval) + phase);
+ }
+
+ vec4 src_pixel = texelFetch(strokeColor, ivec2(texpos.x, texpos.y), 0);
+ /* is transparent */
+ if (src_pixel.a == 0.0f) {
+ discard;
+ }
+
+ gl_FragDepth = texelFetch(strokeDepth, ivec2(texpos.x, texpos.y), 0).r;
+ FragColor = shadow_color;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl
new file mode 100644
index 00000000000..0343d0d42fc
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl
@@ -0,0 +1,32 @@
+/* ******************************************************************* */
+/* Resolve Shadow pass */
+/* ******************************************************************* */
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform sampler2D shadowColor;
+uniform sampler2D shadowDepth;
+
+out vec4 FragColor;
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+
+ float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
+ float shadow_depth = texelFetch(shadowDepth, uv.xy, 0).r;
+ vec4 stroke_pixel= texelFetch(strokeColor, uv.xy, 0);
+ vec4 shadow_pixel= texelFetch(shadowColor, uv.xy, 0);
+
+ /* copy original pixel */
+ vec4 outcolor = stroke_pixel;
+ float outdepth = stroke_depth;
+
+ /* if stroke is not on top, copy shadow */
+ if ((stroke_pixel.a <= 0.2) && (shadow_pixel.a > 0.0)) {
+ outcolor = shadow_pixel;
+ outdepth = shadow_depth;
+ }
+
+ gl_FragDepth = outdepth;
+ FragColor = outcolor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl
new file mode 100644
index 00000000000..92485987c93
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl
@@ -0,0 +1,69 @@
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrix;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+
+uniform vec2 Viewport;
+uniform vec3 loc;
+uniform int radius;
+uniform float angle;
+uniform int transparent;
+
+uniform float pixsize; /* rv3d->pixsize */
+uniform float pixfactor;
+
+out vec4 FragColor;
+
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+
+/* project 3d point to 2d on screen space */
+vec2 toScreenSpace(vec4 vertex)
+{
+ /* need to calculate ndc because this is not done by vertex shader */
+ vec3 ndc = vec3(vertex).xyz / vertex.w;
+
+ vec2 sc;
+ sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
+ sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
+
+ return sc;
+}
+
+/* This swirl shader is a modified version of original Geeks3d.com code */
+void main()
+{
+ vec2 uv = vec2(gl_FragCoord.xy);
+ float stroke_depth;
+ vec4 outcolor;
+
+ vec4 center3d = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
+ vec2 center = toScreenSpace(center3d);
+ vec2 tc = uv - center;
+
+ float dist = length(tc);
+ float pxradius = (ProjectionMatrix[3][3] == 0.0) ? (radius / (loc.z * defaultpixsize)) : (radius / defaultpixsize);
+ pxradius = max(pxradius, 1);
+
+ if (dist <= pxradius) {
+ float percent = (pxradius - dist) / pxradius;
+ float theta = percent * percent * angle * 8.0;
+ float s = sin(theta);
+ float c = cos(theta);
+ tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));
+ tc += center;
+
+ stroke_depth = texelFetch(strokeDepth, ivec2(tc), 0).r;
+ outcolor = texelFetch(strokeColor, ivec2(tc), 0);
+ }
+ else {
+ if (transparent == 1) {
+ discard;
+ }
+ stroke_depth = texelFetch(strokeDepth, ivec2(uv), 0).r;
+ outcolor = texelFetch(strokeColor, ivec2(uv), 0);
+ }
+
+ gl_FragDepth = stroke_depth;
+ FragColor = outcolor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl
new file mode 100644
index 00000000000..3dbab0297c4
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl
@@ -0,0 +1,43 @@
+
+out vec4 FragColor;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+
+uniform float amplitude;
+uniform float period;
+uniform float phase;
+uniform int orientation;
+uniform vec2 wsize;
+
+#define M_PI 3.1415926535897932384626433832795
+
+#define HORIZONTAL 0
+#define VERTICAL 1
+
+void main()
+{
+ vec4 outcolor;
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ float stroke_depth;
+
+ float value;
+ if (orientation == HORIZONTAL) {
+ float pval = (uv.x * M_PI) / wsize[0];
+ value = amplitude * sin((period * pval) + phase);
+ outcolor = texelFetch(strokeColor, ivec2(uv.x, uv.y + value), 0);
+ stroke_depth = texelFetch(strokeDepth, ivec2(uv.x, uv.y + value), 0).r;
+ }
+ else {
+ float pval = (uv.y * M_PI) / wsize[1];
+ value = amplitude * sin((period * pval) + phase);
+ outcolor = texelFetch(strokeColor, ivec2(uv.x + value, uv.y), 0);
+ stroke_depth = texelFetch(strokeDepth, ivec2(uv.x + value, uv.y), 0).r;
+ }
+
+ FragColor = outcolor;
+ gl_FragDepth = stroke_depth;
+
+ if (outcolor.a < 0.02f)
+ discard;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl
new file mode 100644
index 00000000000..cbd7a461dd3
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl
@@ -0,0 +1,12 @@
+out vec4 FragColor;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+
+ gl_FragDepth = texelFetch(strokeDepth, uv, 0).r;
+ FragColor = texelFetch(strokeColor, uv, 0);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
new file mode 100644
index 00000000000..f5696116eea
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
@@ -0,0 +1,155 @@
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform sampler2D blendColor;
+uniform sampler2D blendDepth;
+uniform int mode;
+uniform int clamp_layer;
+uniform float blend_opacity;
+uniform int tonemapping;
+
+#define ON 1
+#define OFF 0
+
+#define MODE_NORMAL 0
+#define MODE_OVERLAY 1
+#define MODE_ADD 2
+#define MODE_SUB 3
+#define MODE_MULTIPLY 4
+#define MODE_DIVIDE 5
+
+float overlay_color(float a, float b)
+{
+ float rtn;
+ if (a < 0.5) {
+ rtn = 2.0 * a * b;
+ }
+ else {
+ rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);
+ }
+
+ return rtn;
+}
+
+vec4 get_blend_color(int mode, vec4 src_color, vec4 blend_color)
+{
+ vec4 mix_color = blend_color;
+ vec4 outcolor;
+
+ if (mix_color.a == 0) {
+ outcolor = src_color;
+ }
+ else if (mode == MODE_OVERLAY) {
+ mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
+ outcolor.r = overlay_color(src_color.r, mix_color.r);
+ outcolor.g = overlay_color(src_color.g, mix_color.g);
+ outcolor.b = overlay_color(src_color.b, mix_color.b);
+ outcolor.a = src_color.a;
+ }
+ else if (mode == MODE_ADD){
+ mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
+ outcolor = src_color + mix_color;
+ outcolor.a = src_color.a;
+ }
+ else if (mode == MODE_SUB){
+ outcolor = src_color - mix_color;
+ outcolor.a = clamp(src_color.a - (mix_color.a * blend_opacity), 0.0, 1.0);
+ }
+ else if (mode == MODE_MULTIPLY) {
+ /* interpolate between 1 and color using opacity */
+ mix_color.rgb = mix(vec3(1,1,1), mix_color.rgb * mix_color.a, blend_opacity);
+ outcolor = src_color * mix_color;
+ outcolor.a = src_color.a;
+ }
+ else if (mode == MODE_DIVIDE) {
+ mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
+ outcolor = src_color / mix_color;
+ outcolor.a = src_color.a;
+ }
+ else {
+ outcolor = mix_color * blend_opacity;;
+ outcolor.a = src_color.a;
+ }
+
+ return outcolor;
+}
+
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308)
+ return (c < 0.0) ? 0.0 : c * 12.92;
+ else
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+}
+
+vec4 tone(vec4 stroke_color)
+{
+ if (tonemapping == 1) {
+ vec4 color = vec4(0, 0, 0, stroke_color.a);
+ color.r = linearrgb_to_srgb(stroke_color.r);
+ color.g = linearrgb_to_srgb(stroke_color.g);
+ color.b = linearrgb_to_srgb(stroke_color.b);
+ return color;
+ }
+ else {
+ return stroke_color;
+ }
+}
+
+void main()
+{
+ vec4 outcolor;
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
+ float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
+
+ vec4 mix_color = texelFetch(blendColor, uv, 0).rgba;
+ float mix_depth = texelFetch(blendDepth, uv, 0).r;
+
+ /* premult alpha factor to remove double blend effects */
+ if (stroke_color.a > 0) {
+ stroke_color = vec4(vec3(stroke_color.rgb / stroke_color.a), stroke_color.a);
+ }
+ if (mix_color.a > 0) {
+ mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
+ }
+
+ /* Normal mode */
+ if (mode == MODE_NORMAL) {
+ if (stroke_color.a > 0) {
+ if (mix_color.a > 0) {
+ FragColor = vec4(mix(stroke_color.rgb, mix_color.rgb, mix_color.a), stroke_color.a);
+ gl_FragDepth = mix_depth;
+ }
+ else {
+ FragColor = stroke_color;
+ gl_FragDepth = stroke_depth;
+ }
+ }
+ else {
+ if (clamp_layer == ON) {
+ discard;
+ }
+ else {
+ FragColor = mix_color;
+ gl_FragDepth = mix_depth;
+ }
+ }
+ FragColor = tone(FragColor);
+ return;
+ }
+
+ /* if not using mask, return mix color */
+ if ((stroke_color.a == 0) && (clamp_layer == OFF)) {
+ FragColor = tone(mix_color);
+ gl_FragDepth = mix_depth;
+ return;
+ }
+
+ /* apply blend mode */
+ FragColor = tone(get_blend_color(mode, stroke_color, mix_color));
+ gl_FragDepth = stroke_depth;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl
new file mode 100644
index 00000000000..b3bd8e488f2
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl
@@ -0,0 +1,17 @@
+in vec4 mColor;
+in vec2 mTexCoord;
+out vec4 fragColor;
+
+void main()
+{
+ vec2 centered = mTexCoord - vec2(0.5);
+ float dist_squared = dot(centered, centered);
+ const float rad_squared = 0.25;
+
+ // round point with jaggy edges
+ if (dist_squared > rad_squared) {
+ discard;
+ }
+
+ fragColor = mColor;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl
new file mode 100644
index 00000000000..0d2da00db66
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl
@@ -0,0 +1,48 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 Viewport;
+
+layout(points) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+in vec4 finalColor[1];
+in float finalThickness[1];
+
+out vec4 mColor;
+out vec2 mTexCoord;
+
+/* project 3d point to 2d on screen space */
+vec2 toScreenSpace(vec4 vertex)
+{
+ return vec2(vertex.xy / vertex.w) * Viewport;
+}
+
+void main(void)
+{
+ vec4 P0 = gl_in[0].gl_Position;
+ vec2 sp0 = toScreenSpace(P0);
+
+ float size = finalThickness[0];
+
+ /* generate the triangle strip */
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x - size, sp0.y + size) / Viewport, 0, 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x - size, sp0.y - size) / Viewport, 0, 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(1, 1);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x + size, sp0.y + size) / Viewport, 0, 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(1, 0);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x + size, sp0.y - size) / Viewport, 0, 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
new file mode 100644
index 00000000000..77fdf58bea0
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
@@ -0,0 +1,15 @@
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 color;
+in float size;
+
+out vec4 finalColor;
+out float finalThickness;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ finalColor = color;
+ finalThickness = size;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
new file mode 100644
index 00000000000..1d57cdc4bcf
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
@@ -0,0 +1,147 @@
+uniform vec4 color2;
+uniform int fill_type;
+uniform float mix_factor;
+
+uniform float gradient_angle;
+uniform float gradient_radius;
+uniform float pattern_gridsize;
+uniform vec2 gradient_scale;
+uniform vec2 gradient_shift;
+
+uniform float texture_angle;
+uniform vec2 texture_scale;
+uniform vec2 texture_offset;
+uniform int texture_mix;
+uniform int texture_flip;
+uniform float texture_opacity;
+uniform int xraymode;
+uniform float layer_opacity;
+
+uniform sampler2D myTexture;
+uniform int texture_clamp;
+
+/* keep this list synchronized with list in gpencil_draw_utils.c */
+#define SOLID 0
+#define GRADIENT 1
+#define RADIAL 2
+#define CHESS 3
+#define TEXTURE 4
+#define PATTERN 5
+
+#define GP_XRAY_FRONT 0
+#define GP_XRAY_3DSPACE 1
+#define GP_XRAY_BACK 2
+
+in vec4 finalColor;
+in vec2 texCoord_interp;
+out vec4 fragColor;
+#define texture2D texture
+
+void set_color(in vec4 color, in vec4 color2, in vec4 tcolor, in float mixv, in float factor,
+ in int tmix, in int flip, out vec4 ocolor)
+{
+ /* full color A */
+ if (mixv == 1.0) {
+ if (tmix == 1) {
+ ocolor = (flip == 0) ? color : tcolor;
+ }
+ else {
+ ocolor = (flip == 0) ? color : color2;
+ }
+ }
+ /* full color B */
+ else if (mixv == 0.0) {
+ if (tmix == 1) {
+ ocolor = (flip == 0) ? tcolor : color;
+ }
+ else {
+ ocolor = (flip == 0) ? color2 : color;
+ }
+ }
+ /* mix of colors */
+ else {
+ if (tmix == 1) {
+ ocolor = (flip == 0) ? mix(color, tcolor, factor) : mix(tcolor, color, factor);
+ }
+ else {
+ ocolor = (flip == 0) ? mix(color, color2, factor) : mix(color2, color, factor);
+ }
+ }
+ ocolor.a *= layer_opacity;
+}
+
+void main()
+{
+ vec2 t_center = vec2(0.5, 0.5);
+ mat2 matrot_tex = mat2(cos(texture_angle), -sin(texture_angle), sin(texture_angle), cos(texture_angle));
+ vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + texture_offset;
+ vec4 tmp_color;
+ tmp_color = (texture_clamp == 0) ? texture2D(myTexture, rot_tex * texture_scale) : texture2D(myTexture, clamp(rot_tex * texture_scale, 0.0, 1.0));
+ vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * texture_opacity);
+ vec4 chesscolor;
+
+ /* solid fill */
+ if (fill_type == SOLID) {
+ fragColor = finalColor;
+ }
+ else {
+ vec2 center = vec2(0.5, 0.5) + gradient_shift;
+ mat2 matrot = mat2(cos(gradient_angle), -sin(gradient_angle), sin(gradient_angle), cos(gradient_angle));
+ vec2 rot = (((matrot * (texCoord_interp - center)) + center) * gradient_scale) + gradient_shift;
+ /* gradient */
+ if (fill_type == GRADIENT) {
+ set_color(finalColor, color2, text_color, mix_factor, rot.x - mix_factor + 0.5, texture_mix, texture_flip, fragColor);
+ }
+ /* radial gradient */
+ if (fill_type == RADIAL) {
+ float in_rad = gradient_radius * mix_factor;
+ float ex_rad = gradient_radius - in_rad;
+ float intensity = 0;
+ float distance = length((center - texCoord_interp) * gradient_scale);
+ if (distance > gradient_radius) {
+ discard;
+ }
+ if (distance > in_rad) {
+ intensity = clamp(((distance - in_rad) / ex_rad), 0.0, 1.0);
+ }
+ set_color(finalColor, color2, text_color, mix_factor, intensity, texture_mix, texture_flip, fragColor);
+ }
+ /* chessboard */
+ if (fill_type == CHESS) {
+ vec2 pos = rot / pattern_gridsize;
+ if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) || (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) {
+ chesscolor = (texture_flip == 0) ? finalColor : color2;
+ }
+ else {
+ chesscolor = (texture_flip == 0) ? color2 : finalColor;
+ }
+ /* mix with texture */
+ fragColor = (texture_mix == 1) ? mix(chesscolor, text_color, mix_factor) : chesscolor;
+ fragColor.a *= layer_opacity;
+ }
+ /* texture */
+ if (fill_type == TEXTURE) {
+ fragColor = (texture_mix == 1) ? mix(text_color, finalColor, mix_factor) : text_color;
+ fragColor.a *= layer_opacity;
+ }
+ /* pattern */
+ if (fill_type == PATTERN) {
+ fragColor = finalColor;
+ fragColor.a = min(text_color.a, finalColor.a) * layer_opacity;
+ }
+ }
+
+ /* set zdepth */
+ if (xraymode == GP_XRAY_FRONT) {
+ gl_FragDepth = 0.000001;
+ }
+ else if (xraymode == GP_XRAY_3DSPACE) {
+ gl_FragDepth = gl_FragCoord.z;
+ }
+ else if (xraymode == GP_XRAY_BACK) {
+ gl_FragDepth = 0.999999;
+ }
+ else {
+ gl_FragDepth = 0.000001;
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
new file mode 100644
index 00000000000..52da354a562
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
@@ -0,0 +1,14 @@
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 color;
+in vec2 texCoord;
+out vec4 finalColor;
+out vec2 texCoord_interp;
+
+void main(void)
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ finalColor = color;
+ texCoord_interp = texCoord;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl
new file mode 100644
index 00000000000..c2e3f787bec
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl
@@ -0,0 +1,9 @@
+uniform vec3 color;
+uniform float opacity;
+
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = vec4(color, opacity);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
new file mode 100644
index 00000000000..db973056110
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
@@ -0,0 +1,51 @@
+uniform int color_type;
+uniform int mode;
+uniform sampler2D myTexture;
+
+in vec4 mColor;
+in vec2 mTexCoord;
+out vec4 fragColor;
+
+#define texture2D texture
+
+#define GPENCIL_MODE_LINE 0
+#define GPENCIL_MODE_DOTS 1
+#define GPENCIL_MODE_BOX 2
+
+/* keep this list synchronized with list in gpencil_engine.h */
+#define GPENCIL_COLOR_SOLID 0
+#define GPENCIL_COLOR_TEXTURE 1
+#define GPENCIL_COLOR_PATTERN 2
+
+void main()
+{
+ vec2 centered = mTexCoord - vec2(0.5);
+ float dist_squared = dot(centered, centered);
+ const float rad_squared = 0.25;
+
+ // round point with jaggy edges
+ if ((mode != GPENCIL_MODE_BOX) && (dist_squared > rad_squared))
+ discard;
+
+ vec4 tmp_color = texture2D(myTexture, mTexCoord);
+
+ /* Solid */
+ if (color_type == GPENCIL_COLOR_SOLID) {
+ fragColor = mColor;
+ }
+ /* texture */
+ if (color_type == GPENCIL_COLOR_TEXTURE) {
+ fragColor = texture2D(myTexture, mTexCoord);
+ /* mult both alpha factor to use strength factor with texture */
+ fragColor.a = min(fragColor.a * mColor.a, fragColor.a);
+ }
+ /* pattern */
+ if (color_type == GPENCIL_COLOR_PATTERN) {
+ vec4 text_color = texture2D(myTexture, mTexCoord);
+ fragColor = mColor;
+ /* mult both alpha factor to use strength factor with color alpha limit */
+ fragColor.a = min(text_color.a * mColor.a, mColor.a);
+ }
+ if(fragColor.a < 0.0035)
+ discard;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
new file mode 100644
index 00000000000..63f22e0f812
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
@@ -0,0 +1,82 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 Viewport;
+uniform int xraymode;
+
+layout(points) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+in vec4 finalColor[1];
+in float finalThickness[1];
+in vec2 finaluvdata[1];
+
+out vec4 mColor;
+out vec2 mTexCoord;
+
+#define GP_XRAY_FRONT 0
+#define GP_XRAY_3DSPACE 1
+#define GP_XRAY_BACK 2
+
+/* project 3d point to 2d on screen space */
+vec2 toScreenSpace(vec4 vertex)
+{
+ return vec2(vertex.xy / vertex.w) * Viewport;
+}
+
+/* get zdepth value */
+float getZdepth(vec4 point)
+{
+ if (xraymode == GP_XRAY_FRONT) {
+ return 0.000001;
+ }
+ if (xraymode == GP_XRAY_3DSPACE) {
+ return (point.z / point.w);
+ }
+ if (xraymode == GP_XRAY_BACK) {
+ return 0.999999;
+ }
+
+ /* in front by default */
+ return 0.000001;
+}
+
+vec2 rotateUV(vec2 uv, float angle)
+{
+ /* translate center of rotation to the center of texture */
+ vec2 new_uv = uv - vec2(0.5f, 0.5f);
+ vec2 rot_uv;
+ rot_uv.x = new_uv.x * cos(angle) - new_uv.y * sin(angle);
+ rot_uv.y = new_uv.y * cos(angle) + new_uv.x * sin(angle);
+ return rot_uv + vec2(0.5f, 0.5f);
+}
+
+void main(void)
+{
+ /* receive 4 points */
+ vec4 P0 = gl_in[0].gl_Position;
+ vec2 sp0 = toScreenSpace(P0);
+
+ float size = finalThickness[0];
+ float aspect = 1.0;
+ /* generate the triangle strip */
+ mTexCoord = rotateUV(vec2(0, 1), finaluvdata[0].y);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x - size, sp0.y + size * aspect) / Viewport, getZdepth(P0), 1.0);
+ EmitVertex();
+
+ mTexCoord = rotateUV(vec2(0, 0), finaluvdata[0].y);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x - size, sp0.y - size * aspect) / Viewport, getZdepth(P0), 1.0);
+ EmitVertex();
+
+ mTexCoord = rotateUV(vec2(1, 1), finaluvdata[0].y);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x + size, sp0.y + size * aspect) / Viewport, getZdepth(P0), 1.0);
+ EmitVertex();
+
+ mTexCoord = rotateUV(vec2(1, 0), finaluvdata[0].y);
+ mColor = finalColor[0];
+ gl_Position = vec4(vec2(sp0.x + size, sp0.y - size * aspect) / Viewport, getZdepth(P0), 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
new file mode 100644
index 00000000000..f870bfbb48d
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
@@ -0,0 +1,36 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform float pixsize; /* rv3d->pixsize */
+uniform int keep_size;
+uniform float objscale;
+uniform float pixfactor;
+
+in vec3 pos;
+in vec4 color;
+in float thickness;
+in vec2 uvdata;
+
+out vec4 finalColor;
+out float finalThickness;
+out vec2 finaluvdata;
+
+#define TRUE 1
+
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ finalColor = color;
+
+ if (keep_size == TRUE) {
+ finalThickness = thickness;
+ }
+ else {
+ float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) : (thickness / defaultpixsize);
+ finalThickness = max(size * objscale, 4.0); /* minimum 4 pixels */
+ }
+
+ finaluvdata = uvdata;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl
new file mode 100644
index 00000000000..dd54e38c3d0
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl
@@ -0,0 +1,15 @@
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
+ vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
+
+ FragColor = stroke_color;
+ gl_FragDepth = stroke_depth;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
new file mode 100644
index 00000000000..9a82e871f56
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
@@ -0,0 +1,49 @@
+uniform int color_type;
+uniform sampler2D myTexture;
+
+in vec4 mColor;
+in vec2 mTexCoord;
+in float uvfac;
+
+out vec4 fragColor;
+
+#define texture2D texture
+
+/* keep this list synchronized with list in gpencil_engine.h */
+#define GPENCIL_COLOR_SOLID 0
+#define GPENCIL_COLOR_TEXTURE 1
+#define GPENCIL_COLOR_PATTERN 2
+
+void main()
+{
+ vec4 tColor = vec4(mColor);
+ /* if alpha < 0, then encap (only solid mode ) */
+ if ((mColor.a < 0) && (color_type == GPENCIL_COLOR_SOLID)) {
+ vec2 center = vec2(uvfac, 1.0);
+ tColor.a = tColor.a * -1.0;
+ float dist = length(mTexCoord - center);
+ if (dist > 0.50) {
+ discard;
+ }
+ }
+ /* Solid */
+ if (color_type == GPENCIL_COLOR_SOLID) {
+ fragColor = tColor;
+ }
+ /* texture */
+ if (color_type == GPENCIL_COLOR_TEXTURE) {
+ fragColor = texture2D(myTexture, mTexCoord);
+ /* mult both alpha factor to use strength factor */
+ fragColor.a = min(fragColor.a * tColor.a, fragColor.a);
+ }
+ /* pattern */
+ if (color_type == GPENCIL_COLOR_PATTERN) {
+ vec4 text_color = texture2D(myTexture, mTexCoord);
+ fragColor = tColor;
+ /* mult both alpha factor to use strength factor with color alpha limit */
+ fragColor.a = min(text_color.a * tColor.a, tColor.a);
+ }
+
+ if(fragColor.a < 0.0035)
+ discard;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl
new file mode 100644
index 00000000000..f9054b44996
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl
@@ -0,0 +1,208 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 Viewport;
+uniform int xraymode;
+uniform int color_type;
+
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 13) out;
+
+in vec4 finalColor[4];
+in float finalThickness[4];
+in vec2 finaluvdata[4];
+
+out vec4 mColor;
+out vec2 mTexCoord;
+out float uvfac;
+
+#define GP_XRAY_FRONT 0
+#define GP_XRAY_3DSPACE 1
+#define GP_XRAY_BACK 2
+
+/* keep this list synchronized with list in gpencil_engine.h */
+#define GPENCIL_COLOR_SOLID 0
+#define GPENCIL_COLOR_TEXTURE 1
+#define GPENCIL_COLOR_PATTERN 2
+
+/* project 3d point to 2d on screen space */
+vec2 toScreenSpace(vec4 vertex)
+{
+ return vec2(vertex.xy / vertex.w) * Viewport;
+}
+
+/* get zdepth value */
+float getZdepth(vec4 point)
+{
+ if (xraymode == GP_XRAY_FRONT) {
+ return 0.000001;
+ }
+ if (xraymode == GP_XRAY_3DSPACE) {
+ return (point.z / point.w);
+ }
+ if (xraymode == GP_XRAY_BACK) {
+ return 0.999999;
+ }
+
+ /* in front by default */
+ return 0.000001;
+}
+void main(void)
+{
+ float MiterLimit = 0.75;
+ uvfac = 0;
+
+ /* receive 4 points */
+ vec4 P0 = gl_in[0].gl_Position;
+ vec4 P1 = gl_in[1].gl_Position;
+ vec4 P2 = gl_in[2].gl_Position;
+ vec4 P3 = gl_in[3].gl_Position;
+
+ /* get the four vertices passed to the shader */
+ vec2 sp0 = toScreenSpace(P0); // start of previous segment
+ vec2 sp1 = toScreenSpace(P1); // end of previous segment, start of current segment
+ vec2 sp2 = toScreenSpace(P2); // end of current segment, start of next segment
+ vec2 sp3 = toScreenSpace(P3); // end of next segment
+
+ /* culling outside viewport */
+ vec2 area = Viewport * 4.0;
+ if (sp1.x < -area.x || sp1.x > area.x) return;
+ if (sp1.y < -area.y || sp1.y > area.y) return;
+ if (sp2.x < -area.x || sp2.x > area.x) return;
+ if (sp2.y < -area.y || sp2.y > area.y) return;
+
+ /* determine the direction of each of the 3 segments (previous, current, next) */
+ vec2 v0 = normalize(sp1 - sp0);
+ vec2 v1 = normalize(sp2 - sp1);
+ vec2 v2 = normalize(sp3 - sp2);
+
+ /* determine the normal of each of the 3 segments (previous, current, next) */
+ vec2 n0 = vec2(-v0.y, v0.x);
+ vec2 n1 = vec2(-v1.y, v1.x);
+ vec2 n2 = vec2(-v2.y, v2.x);
+
+ /* determine miter lines by averaging the normals of the 2 segments */
+ vec2 miter_a = normalize(n0 + n1); // miter at start of current segment
+ vec2 miter_b = normalize(n1 + n2); // miter at end of current segment
+
+ /* determine the length of the miter by projecting it onto normal and then inverse it */
+ float an1 = dot(miter_a, n1);
+ float bn1 = dot(miter_b, n2);
+ if (an1 == 0) an1 = 1;
+ if (bn1 == 0) bn1 = 1;
+ float length_a = finalThickness[1] / an1;
+ float length_b = finalThickness[2] / bn1;
+ if (length_a <= 0.0) length_a = 0.01;
+ if (length_b <= 0.0) length_b = 0.01;
+
+ /* prevent excessively long miters at sharp corners */
+ if (dot(v0, v1) < -MiterLimit) {
+ miter_a = n1;
+ length_a = finalThickness[1];
+
+ /* close the gap */
+ if (dot(v0, n1) > 0) {
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0.5);
+ mColor = finalColor[1];
+ gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+ }
+ else {
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0.5);
+ mColor = finalColor[1];
+ gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+ }
+ }
+
+ if (dot(v1, v2) < -MiterLimit) {
+ miter_b = n1;
+ length_b = finalThickness[2];
+ }
+
+ /* generate the start endcap (alpha < 0 used as endcap flag)*/
+ if ((P0 == P2) && (color_type == GPENCIL_COLOR_SOLID)){
+ mTexCoord = vec2(2, 1);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0;
+ gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 2);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+ }
+
+ /* generate the triangle strip */
+ mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 0) : vec2(finaluvdata[1].x, 0);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 1) : vec2(finaluvdata[1].x, 1);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(1, 0) : vec2(finaluvdata[2].x, 0);
+ mColor = finalColor[2];
+ gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(1, 1) : vec2(finaluvdata[2].x, 1);
+ mColor = finalColor[2];
+ gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ /* generate the end endcap (alpha < 0 used as endcap flag)*/
+ if ((P1 == P3) && (color_type == GPENCIL_COLOR_SOLID)){
+ mTexCoord = vec2(finaluvdata[2].x, 2);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ uvfac = finaluvdata[2].x;
+ gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(finaluvdata[2].x, 0);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ uvfac = finaluvdata[2].x;
+ gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(finaluvdata[2].x + 2, 1);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ uvfac = finaluvdata[2].x;
+ vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0;
+ gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+ }
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
new file mode 100644
index 00000000000..121e244ac8a
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
@@ -0,0 +1,36 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform float pixsize; /* rv3d->pixsize */
+uniform int keep_size;
+uniform float objscale;
+uniform float pixfactor;
+
+in vec3 pos;
+in vec4 color;
+in float thickness;
+in vec2 uvdata;
+
+out vec4 finalColor;
+out float finalThickness;
+out vec2 finaluvdata;
+
+#define TRUE 1
+
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+
+void main(void)
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ finalColor = color;
+
+ if (keep_size == TRUE) {
+ finalThickness = thickness;
+ }
+ else {
+ float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) : (thickness / defaultpixsize);
+ finalThickness = max(size * objscale, 1.0);
+ }
+
+ finaluvdata = uvdata;
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl
new file mode 100644
index 00000000000..0983e6c4d87
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl
@@ -0,0 +1,45 @@
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform int tonemapping;
+
+float srgb_to_linearrgb(float c)
+{
+ if (c < 0.04045)
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
+ else
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
+}
+
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308)
+ return (c < 0.0) ? 0.0 : c * 12.92;
+ else
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+}
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
+ vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
+
+ /* premult alpha factor to remove double blend effects */
+ if (stroke_color.a > 0) {
+ stroke_color = vec4(vec3(stroke_color.rgb / stroke_color.a), stroke_color.a);
+ }
+
+ /* apply color correction for render only */
+ if (tonemapping == 1) {
+ stroke_color.r = srgb_to_linearrgb(stroke_color.r);
+ stroke_color.g = srgb_to_linearrgb(stroke_color.g);
+ stroke_color.b = srgb_to_linearrgb(stroke_color.b);
+ }
+
+ FragColor = stroke_color;
+ gl_FragDepth = stroke_depth;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl
new file mode 100644
index 00000000000..fda2fc85460
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_background_lib.glsl
@@ -0,0 +1,3 @@
+vec3 background_color(WorldData world_data, float y) {
+ return mix(world_data.background_color_low, world_data.background_color_high, y).xyz + bayer_dither_noise();
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
new file mode 100644
index 00000000000..b52d7d31e61
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
@@ -0,0 +1,83 @@
+out vec4 fragColor;
+
+uniform sampler2D depthBuffer;
+uniform sampler2D colorBuffer;
+uniform sampler2D normalBuffer;
+uniform usampler2D objectId;
+
+uniform vec2 invertedViewportSize;
+uniform mat4 WinMatrix; /* inverse WinMatrix */
+
+uniform vec4 viewvecs[3];
+uniform vec4 ssao_params;
+uniform vec4 ssao_settings;
+uniform vec2 curvature_settings;
+uniform sampler2D ssao_jitter;
+
+layout(std140) uniform samples_block {
+ vec4 ssao_samples[500];
+};
+
+#define ssao_samples_num ssao_params.x
+#define jitter_tilling ssao_params.yz
+#define ssao_iteration ssao_params.w
+
+#define ssao_distance ssao_settings.x
+#define ssao_factor_cavity ssao_settings.y
+#define ssao_factor_edge ssao_settings.z
+#define ssao_attenuation ssao_settings.w
+
+vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth)
+{
+ if (WinMatrix[3][3] == 0.0) {
+ /* Perspective */
+ float d = 2.0 * depth - 1.0;
+
+ float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]);
+
+ return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
+ }
+ else {
+ /* Orthographic */
+ vec3 offset = vec3(uvcoords, depth);
+
+ return viewvecs[0].xyz + offset * viewvecs[1].xyz;
+ }
+}
+
+/* forward declartion */
+void ssao_factors(
+ in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
+ out float cavities, out float edges);
+
+
+void main()
+{
+ vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize;
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+
+ float cavity = 0.0, edges = 0.0, curvature = 0.0;
+
+#ifdef USE_CAVITY
+ float depth = texelFetch(depthBuffer, texel, 0).x;
+ vec3 position = get_view_space_from_depth(screenco, depth);
+
+ vec4 diffuse_color = texelFetch(colorBuffer, texel, 0);
+ vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg);
+ if (diffuse_color.a == 0.0) {
+ normal_viewport = -normal_viewport;
+ }
+
+
+ ssao_factors(depth, normal_viewport, position, screenco, cavity, edges);
+#endif
+
+#ifdef USE_CURVATURE
+ curvature = calculate_curvature(objectId, normalBuffer, texel, curvature_settings.x, curvature_settings.y);
+#endif
+
+ float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
+
+ /* Using UNORM render target so compress the range. */
+ fragColor = vec4(final_cavity_factor / CAVITY_BUFFER_RANGE);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
new file mode 100644
index 00000000000..7b77139fb6c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
@@ -0,0 +1,84 @@
+
+
+/* from The Alchemy screen-space ambient obscurance algorithm
+ * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
+
+void ssao_factors(
+ in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
+ out float cavities, out float edges)
+{
+ cavities = edges = 0.0;
+ /* early out if there is no need for SSAO */
+ if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0)
+ return;
+
+ /* take the normalized ray direction here */
+ vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb;
+
+ /* find the offset in screen space by multiplying a point
+ * in camera space at the depth of the point by the projection matrix. */
+ vec2 offset;
+ float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3];
+ offset.x = WinMatrix[0][0] * ssao_distance / homcoord;
+ offset.y = WinMatrix[1][1] * ssao_distance / homcoord;
+ /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
+ offset *= 0.5;
+
+
+ int num_samples = int(ssao_samples_num);
+
+ /* Note. Putting noise usage here to put some ALU after texture fetch. */
+ vec2 rotX = noise.rg;
+ vec2 rotY = vec2(-rotX.y, rotX.x);
+
+ for (int x = 0; x < num_samples; x++) {
+ int sample_index = x + (int(ssao_iteration) * num_samples);
+ if (sample_index > 500) {
+ continue;
+ }
+ /* ssao_samples[x].xy is sample direction (normalized).
+ * ssao_samples[x].z is sample distance from disk center. */
+
+ /* Rotate with random direction to get jittered result. */
+ vec2 dir_jittered = vec2(dot(ssao_samples[sample_index].xy, rotX), dot(ssao_samples[sample_index].xy, rotY));
+ dir_jittered.xy *= ssao_samples[sample_index].z + noise.b;
+
+ vec2 uvcoords = screenco.xy + dir_jittered * offset;
+
+ if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0)
+ continue;
+
+ float depth_new = texture(depthBuffer, uvcoords).r;
+
+ /* Handle Background case */
+ bool is_background = (depth_new == 1.0);
+
+ /* This trick provide good edge effect even if no neighboor is found. */
+ vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new);
+
+ if (is_background)
+ pos_new.z -= ssao_distance;
+
+ vec3 dir = pos_new - position;
+ float len = length(dir);
+ float f_cavities = dot(dir, normal);
+ float f_edge = -f_cavities;
+ float f_bias = 0.05 * len + 0.0001;
+
+ float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation));
+
+ /* use minor bias here to avoid self shadowing */
+ if (f_cavities > -f_bias)
+ cavities += f_cavities * attenuation;
+
+ if (f_edge > f_bias)
+ edges += f_edge * attenuation;
+ }
+
+ cavities /= ssao_samples_num;
+ edges /= ssao_samples_num;
+
+ /* don't let cavity wash out the surface appearance */
+ cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0);
+ edges = edges * ssao_factor_edge;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_checkerboard_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_checkerboard_depth_frag.glsl
new file mode 100644
index 00000000000..94fa5d51229
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_checkerboard_depth_frag.glsl
@@ -0,0 +1,38 @@
+
+/* 4x4 bayer matrix. */
+#define P(x) ((x + 0.5) * (1.0 / 16.0))
+const vec4 dither_mat[4] = vec4[4](
+ vec4( P(0.0), P(8.0), P(2.0), P(10.0)),
+ vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
+ vec4( P(3.0), P(11.0), P(1.0), P(9.0)),
+ vec4(P(15.0), P(7.0), P(13.0), P(5.0))
+);
+
+uniform float threshold = 0.5;
+uniform float offset = 0.0;
+
+/* Noise dithering pattern
+ * 0 - Bayer matrix
+ * 1 - Interlieved gradient noise
+ */
+#define NOISE 1
+
+void main()
+{
+#if NOISE == 0
+ ivec2 tx = ivec2(gl_FragCoord.xy) % 4;
+ float noise = dither_mat[tx.x][tx.y];
+#elif NOISE == 1
+ /* Interlieved gradient noise by Jorge Jimenez
+ * http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare */
+ float noise = fract(offset + 52.9829189 * fract(0.06711056 * gl_FragCoord.x + 0.00583715 * gl_FragCoord.y));
+#else
+#error
+#endif
+
+ if (noise > threshold) {
+ discard;
+ } else {
+ gl_FragDepth = 1.0;
+ }
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
new file mode 100644
index 00000000000..982c3821030
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -0,0 +1,123 @@
+#define NO_OBJECT_ID uint(0)
+#define EPSILON 0.00001
+#define M_PI 3.14159265358979323846
+
+#define CAVITY_BUFFER_RANGE 4.0
+
+/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */
+#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0))
+const vec4 dither_mat4x4[4] = vec4[4](
+ vec4( P(0.0), P(8.0), P(2.0), P(10.0)),
+ vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
+ vec4( P(3.0), P(11.0), P(1.0), P(9.0)),
+ vec4(P(15.0), P(7.0), P(13.0), P(5.0))
+);
+
+float bayer_dither_noise() {
+ ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4;
+ ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2;
+ return dither_mat4x4[tx1.x][tx1.y];
+}
+
+/* From http://aras-p.info/texts/CompactNormalStorage.html
+ * Using Method #4: Spheremap Transform */
+vec3 normal_decode(vec2 enc)
+{
+ vec2 fenc = enc.xy * 4.0 - 2.0;
+ float f = dot(fenc, fenc);
+ float g = sqrt(1.0 - f / 4.0);
+ vec3 n;
+ n.xy = fenc*g;
+ n.z = 1 - f / 2;
+ return n;
+}
+
+/* From http://aras-p.info/texts/CompactNormalStorage.html
+ * Using Method #4: Spheremap Transform */
+vec2 normal_encode(vec3 n)
+{
+ float p = sqrt(n.z * 8.0 + 8.0);
+ return vec2(n.xy / p + 0.5);
+}
+
+void fresnel(vec3 I, vec3 N, float ior, out float kr)
+{
+ float cosi = clamp(dot(I, N), -1.0, 1.0);
+ float etai = 1.0;
+ float etat = ior;
+ if (cosi > 0) {
+ etat = 1.0;
+ etai = ior;
+ }
+
+ // Compute sini using Snell's law
+ float sint = etai / etat * sqrt(max(0.0, 1.0 - cosi * cosi));
+ // Total internal reflection
+ if (sint >= 1) {
+ kr = 1;
+ }
+ else {
+ float cost = sqrt(max(0.0, 1.0 - sint * sint));
+ cosi = abs(cosi);
+ float Rs = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost));
+ float Rp = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost));
+ kr = (Rs * Rs + Rp * Rp) / 2;
+ }
+ // As a consequence of the conservation of energy, transmittance is given by:
+ // kt = 1 - kr;
+}
+
+float calculate_transparent_weight(float z, float alpha)
+{
+#if 0
+ /* Eq 10 : Good for surfaces with varying opacity (like particles) */
+ float a = min(1.0, alpha * 10.0) + 0.01;
+ float b = -gl_FragCoord.z * 0.95 + 1.0;
+ float w = a * a * a * 3e2 * b * b * b;
+#else
+ /* Eq 7 put more emphasis on surfaces closer to the view. */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */
+ // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */
+ /* Same as eq 7, but optimized. */
+ float a = abs(z) / 5.0;
+ float b = abs(z) / 200.0;
+ b *= b;
+ float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */
+#endif
+ return alpha * clamp(w, 1e-2, 3e2);
+}
+
+/* Special function only to be used with calculate_transparent_weight(). */
+float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat)
+{
+ if (proj_mat[3][3] == 0.0) {
+ float d = 2.0 * depth - 1.0;
+ return -proj_mat[3][2] / (d + proj_mat[2][2]);
+ }
+ else {
+ /* Return depth from near plane. */
+ return depth * viewvecs[1].z;
+ }
+}
+
+vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat)
+{
+ return (proj_mat[3][3] == 0.0)
+ ? normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz)
+ : vec3(0.0, 0.0, 1.0);
+}
+
+vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
+{
+ /* Quick creation of an orthonormal basis */
+ float a = 1.0 / (1.0 + I.z);
+ float b = -I.x * I.y * a;
+ vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x);
+ vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y);
+ vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N));
+ if (flipped) {
+ matcap_uv.x = -matcap_uv.x;
+ }
+ return matcap_uv * 0.496 + 0.5;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
new file mode 100644
index 00000000000..53315b8c132
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
@@ -0,0 +1,43 @@
+#ifndef CURVATURE_OFFSET
+# define CURVATURE_OFFSET 1
+#endif
+
+float curvature_soft_clamp(float curvature, float control)
+{
+ if (curvature < 0.5 / control) {
+ return curvature * (1.0 - curvature * control);
+ }
+ return 0.25 / control;
+}
+
+float calculate_curvature(usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley)
+{
+ uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r;
+ uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r;
+ uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r;
+ uint object_right = texelFetchOffset(objectId, texel, 0, ivec2( CURVATURE_OFFSET, 0)).r;
+
+ if((object_up != object_down) || (object_right != object_left)) {
+ return 0.0;
+ }
+
+ vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg;
+ vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg;
+ vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg;
+ vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2( CURVATURE_OFFSET, 0)).rg;
+
+#ifdef WORKBENCH_ENCODE_NORMALS
+ normal_up = normal_decode(normal_up ).rg;
+ normal_down = normal_decode(normal_down ).rg;
+ normal_left = normal_decode(normal_left ).rg;
+ normal_right = normal_decode(normal_right).rg;
+#endif
+
+ float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r));
+
+ if (normal_diff < 0) {
+ return -2.0 * curvature_soft_clamp(-normal_diff, valley);
+ }
+
+ return 2.0 * curvature_soft_clamp(normal_diff, ridge);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
new file mode 100644
index 00000000000..fd058d45cf6
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
@@ -0,0 +1,21 @@
+struct LightData {
+ vec4 direction;
+ vec4 specular_color;
+ vec4 diffuse_color_wrap; /* rgb: diffuse col a: wrapped lighting factor */
+};
+
+struct WorldData {
+ vec3 spherical_harmonics_coefs[STUDIOLIGHT_SH_MAX_COMPONENTS];
+ vec4 background_color_low;
+ vec4 background_color_high;
+ vec4 object_outline_color;
+ vec4 shadow_direction_vs;
+ LightData lights[4];
+ vec4 ambient_color;
+ int num_lights;
+ int matcap_orientation;
+ float background_alpha;
+ float curvature_ridge;
+ float curvature_valley;
+ int pad[3];
+};
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
new file mode 100644
index 00000000000..310169bdf5d
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
@@ -0,0 +1,111 @@
+out vec4 fragColor;
+
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrixInverse;
+
+uniform usampler2D objectId;
+uniform sampler2D colorBuffer;
+uniform sampler2D specularBuffer;
+uniform sampler2D normalBuffer;
+/* normalBuffer contains viewport normals */
+uniform sampler2D cavityBuffer;
+uniform sampler2D matcapImage;
+
+uniform vec2 invertedViewportSize;
+uniform vec4 viewvecs[3];
+uniform float shadowMultiplier;
+uniform float lightMultiplier;
+uniform float shadowShift = 0.1;
+
+layout(std140) uniform world_block {
+ WorldData world_data;
+};
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+ vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
+ uint object_id = texelFetch(objectId, texel, 0).r;
+
+#ifndef V3D_SHADING_OBJECT_OUTLINE
+ if (object_id == NO_OBJECT_ID) {
+ fragColor = vec4(background_color(world_data, uv_viewport.y), world_data.background_alpha);
+ return;
+ }
+#else /* !V3D_SHADING_OBJECT_OUTLINE */
+ float object_outline = calculate_object_outline(objectId, texel, object_id);
+
+ if (object_id == NO_OBJECT_ID) {
+ vec3 background = background_color(world_data, uv_viewport.y);
+ if (object_outline == 0.0) {
+ fragColor = vec4(background, world_data.background_alpha);
+ }
+ else {
+ /* Do correct alpha blending. */
+ vec4 background_color = vec4(background, 1.0) * world_data.background_alpha;
+ vec4 outline_color = vec4(world_data.object_outline_color.rgb, 1.0);
+ fragColor = mix(outline_color, background_color, object_outline);
+ fragColor = vec4(fragColor.rgb / max(1e-8, fragColor.a), fragColor.a);
+ }
+ return;
+ }
+#endif /* !V3D_SHADING_OBJECT_OUTLINE */
+
+ vec4 diffuse_color = texelFetch(colorBuffer, texel, 0);
+
+/* Do we need normals */
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+# ifdef WORKBENCH_ENCODE_NORMALS
+ vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg);
+ if (diffuse_color.a == 0.0) {
+ normal_viewport = -normal_viewport;
+ }
+# else /* WORKBENCH_ENCODE_NORMALS */
+ vec3 normal_viewport = texelFetch(normalBuffer, texel, 0).rgb;
+# endif /* WORKBENCH_ENCODE_NORMALS */
+#endif
+
+ vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix);
+
+ /* -------- SHADING --------- */
+#ifdef V3D_LIGHTING_FLAT
+ vec3 shaded_color = diffuse_color.rgb;
+
+#elif defined(V3D_LIGHTING_MATCAP)
+ bool flipped = world_data.matcap_orientation != 0;
+ vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped);
+ vec3 matcap = textureLod(matcapImage, matcap_uv, 0.0).rgb;
+ vec3 shaded_color = matcap * diffuse_color.rgb;
+
+#elif defined(V3D_LIGHTING_STUDIO)
+
+# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ vec4 specular_data = texelFetch(specularBuffer, texel, 0);
+# else
+ vec4 specular_data = vec4(0.0);
+# endif
+ vec3 shaded_color = get_world_lighting(world_data,
+ diffuse_color.rgb, specular_data.rgb, specular_data.a,
+ normal_viewport, I_vs);
+#endif
+
+ /* -------- POST EFFECTS --------- */
+#ifdef WB_CAVITY
+ /* Using UNORM texture so decompress the range */
+ shaded_color *= texelFetch(cavityBuffer, texel, 0).r * CAVITY_BUFFER_RANGE;
+#endif
+
+#ifdef V3D_SHADING_SHADOW
+ float light_factor = -dot(normal_viewport, world_data.shadow_direction_vs.xyz);
+ /* The step function might be ok for meshes but it's
+ * clearly not the case for hairs. Do smoothstep in this case. */
+ float shadow_mix = smoothstep(1.0, shadowShift, light_factor);
+ shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix);
+#endif
+
+#ifdef V3D_SHADING_OBJECT_OUTLINE
+ shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline);
+#endif
+
+ fragColor = vec4(shaded_color, 1.0);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
new file mode 100644
index 00000000000..4ffd20c2839
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
@@ -0,0 +1,19 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D colorBuffer;
+uniform vec2 invertedViewportSize;
+
+void main()
+{
+ FragColor = FxaaPixelShader(
+ uvcoordsvar.st,
+ colorBuffer,
+ invertedViewportSize,
+ 1.0,
+ 0.166,
+ 0.0833
+ );
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
new file mode 100644
index 00000000000..1da1b2ad13c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
@@ -0,0 +1,14 @@
+uniform sampler2D historyBuffer;
+uniform sampler2D colorBuffer;
+
+out vec4 colorOutput;
+
+uniform float mixFactor;
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+ vec4 color_buffer = texelFetch(colorBuffer, texel, 0);
+ vec4 history_buffer = texelFetch(historyBuffer, texel, 0);
+ colorOutput = mix(history_buffer, color_buffer, mixFactor);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl
new file mode 100644
index 00000000000..1d9f37274bd
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl
@@ -0,0 +1,37 @@
+out vec4 fragColor;
+
+uniform usampler2D objectId;
+uniform sampler2D transparentAccum;
+uniform sampler2D transparentRevealage;
+uniform vec2 invertedViewportSize;
+
+layout(std140) uniform world_block {
+ WorldData world_data;
+};
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+ vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
+ uint object_id = texelFetch(objectId, texel, 0).r;
+
+ /* Listing 4 */
+ vec4 trans_accum = texelFetch(transparentAccum, texel, 0);
+ float trans_revealage = trans_accum.a;
+ trans_accum.a = texelFetch(transparentRevealage, texel, 0).r;
+
+#ifdef V3D_SHADING_OBJECT_OUTLINE
+ float outline = calculate_object_outline(objectId, texel, object_id);
+#else /* V3D_SHADING_OBJECT_OUTLINE */
+ float outline = 1.0;
+#endif /* V3D_SHADING_OBJECT_OUTLINE */
+ vec3 bg_color = background_color(world_data, uv_viewport.y);
+
+ /* TODO: Bypass the whole shader if there is no xray pass and no outline pass. */
+ vec3 trans_color = trans_accum.rgb / clamp(trans_accum.a, 1e-4, 5e4);
+ vec3 color = mix(trans_color, bg_color, trans_revealage);
+
+ color = mix(world_data.object_outline_color.rgb, color, outline);
+
+ fragColor = vec4(color, 1.0);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
new file mode 100644
index 00000000000..9380044f2b9
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl
@@ -0,0 +1,20 @@
+uniform int object_id = 0;
+layout(location=0) out uint objectId;
+uniform float ImageTransparencyCutoff = 0.1;
+#ifdef V3D_SHADING_TEXTURE_COLOR
+uniform sampler2D image;
+
+in vec2 uv_interp;
+#endif
+
+void main()
+{
+#ifdef V3D_SHADING_TEXTURE_COLOR
+ vec4 diffuse_color = texture(image, uv_interp);
+ if (diffuse_color.a < ImageTransparencyCutoff) {
+ discard;
+ }
+#endif
+
+ objectId = uint(object_id);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
new file mode 100644
index 00000000000..c00edb06100
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
@@ -0,0 +1,78 @@
+#ifdef V3D_SHADING_TEXTURE_COLOR
+uniform sampler2D image;
+uniform float ImageTransparencyCutoff = 0.1;
+
+#endif
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform float alpha = 0.5;
+uniform vec2 invertedViewportSize;
+uniform vec4 viewvecs[3];
+
+uniform vec4 materialDiffuseColor;
+uniform vec4 materialSpecularColor;
+uniform float materialRoughness;
+
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+in vec3 normal_viewport;
+#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
+#ifdef V3D_SHADING_TEXTURE_COLOR
+in vec2 uv_interp;
+#endif
+#ifdef V3D_LIGHTING_MATCAP
+uniform sampler2D matcapImage;
+#endif
+
+layout(std140) uniform world_block {
+ WorldData world_data;
+};
+
+layout(location=0) out vec4 transparentAccum;
+layout(location=1) out float revealageAccum; /* revealage actually stored in transparentAccum.a */
+
+void main()
+{
+ vec4 diffuse_color;
+
+#ifdef V3D_SHADING_TEXTURE_COLOR
+ diffuse_color = texture(image, uv_interp);
+ if (diffuse_color.a < ImageTransparencyCutoff) {
+ discard;
+ }
+#else
+ diffuse_color = materialDiffuseColor;
+#endif /* V3D_SHADING_TEXTURE_COLOR */
+
+ vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize;
+ vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix);
+
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+ vec3 nor = normalize(normal_viewport);
+#endif
+
+ /* -------- SHADING --------- */
+#ifdef V3D_LIGHTING_FLAT
+ vec3 shaded_color = diffuse_color.rgb;
+
+#elif defined(V3D_LIGHTING_MATCAP)
+ bool flipped = world_data.matcap_orientation != 0;
+ vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped);
+ vec3 matcap = textureLod(matcapImage, matcap_uv, 0.0).rgb;
+ vec3 shaded_color = matcap * diffuse_color.rgb;
+
+#elif defined(V3D_LIGHTING_STUDIO)
+ vec3 shaded_color = get_world_lighting(world_data,
+ diffuse_color.rgb, materialSpecularColor.rgb, materialRoughness,
+ nor, I_vs);
+#endif
+
+ /* Based on :
+ * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
+ * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
+ */
+ /* Listing 4 */
+ float z = linear_zdepth(gl_FragCoord.z, viewvecs, ProjectionMatrix);
+ float weight = calculate_transparent_weight(z, alpha);
+ transparentAccum = vec4(shaded_color * weight, alpha);
+ revealageAccum = weight;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl
new file mode 100644
index 00000000000..59f2df11086
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl
@@ -0,0 +1,13 @@
+uniform sampler2D depthBuffer;
+
+void main(void)
+{
+ float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
+
+ /* background, discard */
+ if (depth >= 1.0) {
+ discard;
+ }
+
+ gl_FragDepth = depth;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl
new file mode 100644
index 00000000000..3e925ba023f
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl
@@ -0,0 +1,12 @@
+#define OBJECT_OUTLINE_OFFSET 1
+
+float calculate_object_outline(usampler2D objectId, ivec2 texel, uint object_id)
+{
+ uvec4 oid_offset = uvec4(
+ texelFetchOffset(objectId, texel, 0, ivec2(0, OBJECT_OUTLINE_OFFSET)).r,
+ texelFetchOffset(objectId, texel, 0, ivec2(0, -OBJECT_OUTLINE_OFFSET)).r,
+ texelFetchOffset(objectId, texel, 0, ivec2(-OBJECT_OUTLINE_OFFSET, 0)).r,
+ texelFetchOffset(objectId, texel, 0, ivec2( OBJECT_OUTLINE_OFFSET, 0)).r);
+
+ return dot(vec4(equal(uvec4(object_id), oid_offset)), vec4(0.25));
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
new file mode 100644
index 00000000000..5f622b00bca
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -0,0 +1,79 @@
+uniform int object_id = 0;
+
+uniform vec4 materialDiffuseColor;
+uniform vec4 materialSpecularColor;
+uniform float materialRoughness;
+
+#ifdef V3D_SHADING_TEXTURE_COLOR
+uniform sampler2D image;
+uniform float ImageTransparencyCutoff = 0.1;
+
+#endif
+
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+in vec3 normal_viewport;
+#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
+
+#ifdef V3D_SHADING_TEXTURE_COLOR
+in vec2 uv_interp;
+#endif /* V3D_SHADING_TEXTURE_COLOR */
+
+#ifdef HAIR_SHADER
+flat in float hair_rand;
+#endif
+
+layout(location=0) out uint objectId;
+layout(location=1) out vec4 diffuseColor;
+#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+layout(location=2) out vec4 specularColor;
+#endif
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+# ifdef WORKBENCH_ENCODE_NORMALS
+layout(location=3) out vec2 normalViewport;
+# else /* WORKBENCH_ENCODE_NORMALS */
+layout(location=3) out vec3 normalViewport;
+# endif /* WORKBENCH_ENCODE_NORMALS */
+#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
+
+void main()
+{
+ objectId = uint(object_id);
+
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+ vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport;
+ n = normalize(n);
+#endif
+
+#ifdef V3D_SHADING_TEXTURE_COLOR
+ diffuseColor = texture(image, uv_interp);
+ if (diffuseColor.a < ImageTransparencyCutoff) {
+ discard;
+ }
+#else
+ diffuseColor = vec4(materialDiffuseColor.rgb, 0.0);
+#endif /* V3D_SHADING_TEXTURE_COLOR */
+
+#ifdef HAIR_SHADER
+ float hair_color_variation = hair_rand * 0.1;
+ diffuseColor.rgb = clamp(diffuseColor.rgb - hair_color_variation, 0.0, 1.0);
+#endif
+
+#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ specularColor = vec4(materialSpecularColor.rgb, materialRoughness);
+# ifdef HAIR_SHADER
+ specularColor.rgb = clamp(specularColor.rgb - hair_color_variation, 0.0, 1.0);
+# endif
+#endif
+
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+# ifdef WORKBENCH_ENCODE_NORMALS
+ diffuseColor.a = float(gl_FrontFacing);
+ normalViewport = normal_encode(n);
+# else /* WORKBENCH_ENCODE_NORMALS */
+ normalViewport = n;
+# endif /* WORKBENCH_ENCODE_NORMALS */
+# ifdef HAIR_SHADER
+ diffuseColor.a = 0.5;
+# endif
+#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
new file mode 100644
index 00000000000..62040da8524
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -0,0 +1,70 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelMatrixInverse;
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat3 NormalMatrix;
+
+#ifndef HAIR_SHADER
+in vec3 pos;
+in vec3 nor;
+in vec2 uv;
+#else /* HAIR_SHADER */
+# ifdef V3D_SHADING_TEXTURE_COLOR
+uniform samplerBuffer u; /* active texture layer */
+# endif
+flat out float hair_rand;
+#endif /* HAIR_SHADER */
+
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+out vec3 normal_viewport;
+#endif
+
+#ifdef V3D_SHADING_TEXTURE_COLOR
+out vec2 uv_interp;
+#endif
+
+/* From http://libnoise.sourceforge.net/noisegen/index.html */
+float integer_noise(int n)
+{
+ n = (n >> 13) ^ n;
+ int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ return (float(nn) / 1073741824.0);
+}
+
+void main()
+{
+#ifdef HAIR_SHADER
+# ifdef V3D_SHADING_TEXTURE_COLOR
+ vec2 uv = hair_get_customdata_vec2(u);
+# endif
+ float time, thick_time, thickness;
+ vec3 pos, tan, binor;
+ hair_get_pos_tan_binor_time(
+ (ProjectionMatrix[3][3] == 0.0),
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz,
+ pos, tan, binor, time, thickness, thick_time);
+ /* To "simulate" anisotropic shading, randomize hair normal per strand. */
+ hair_rand = integer_noise(hair_get_strand_id());
+ tan = normalize(tan);
+ vec3 nor = normalize(cross(binor, tan));
+ nor = normalize(mix(nor, -tan, hair_rand * 0.10));
+ float cos_theta = (hair_rand*2.0 - 1.0) * 0.20;
+ float sin_theta = sqrt(max(0.0, 1.0f - cos_theta*cos_theta));
+ nor = nor * sin_theta + binor * cos_theta;
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+#else
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+#endif
+#ifdef V3D_SHADING_TEXTURE_COLOR
+ uv_interp = uv;
+#endif
+
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+ normal_viewport = NormalMatrix * nor;
+# ifndef HAIR_SHADER
+ normal_viewport = normalize(normal_viewport);
+# endif
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl
new file mode 100644
index 00000000000..d8c8f22ed1c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl
@@ -0,0 +1,85 @@
+#extension GL_ARB_gpu_shader5 : enable
+
+#ifdef GL_ARB_gpu_shader5
+#define USE_INVOC_EXT
+#endif
+
+#ifdef DOUBLE_MANIFOLD
+# ifdef USE_INVOC_EXT
+# define invoc_len 2
+# else
+# define vert_len 6
+# endif
+#else
+# ifdef USE_INVOC_EXT
+# define invoc_len 2
+# else
+# define vert_len 6
+# endif
+#endif
+
+#ifdef USE_INVOC_EXT
+layout(triangles, invocations = invoc_len) in;
+layout(triangle_strip, max_vertices = 3) out;
+#else
+layout(triangles) in;
+layout(triangle_strip, max_vertices = vert_len) out;
+#endif
+
+uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
+
+in VertexData {
+ vec3 pos; /* local position */
+ vec4 frontPosition; /* final ndc position */
+ vec4 backPosition;
+} vData[];
+
+vec4 get_pos(int v, bool backface)
+{
+ return (backface) ? vData[v].backPosition : vData[v].frontPosition;
+}
+
+void emit_cap(const bool front, bool reversed)
+{
+ if (front) {
+ gl_Position = vData[0].frontPosition; EmitVertex();
+ gl_Position = vData[reversed ? 2 : 1].frontPosition; EmitVertex();
+ gl_Position = vData[reversed ? 1 : 2].frontPosition; EmitVertex();
+ }
+ else {
+ gl_Position = vData[0].backPosition; EmitVertex();
+ gl_Position = vData[reversed ? 1 : 2].backPosition; EmitVertex();
+ gl_Position = vData[reversed ? 2 : 1].backPosition; EmitVertex();
+ }
+ EndPrimitive();
+}
+
+void main()
+{
+ vec3 v10 = vData[0].pos - vData[1].pos;
+ vec3 v12 = vData[2].pos - vData[1].pos;
+
+ vec3 n = cross(v12, v10);
+ float facing = dot(n, lightDirection);
+
+ bool backface = facing > 0.0;
+
+#ifdef DOUBLE_MANIFOLD
+ /* In case of non manifold geom, we only increase/decrease
+ * the stencil buffer by one but do every faces as they were facing the light. */
+ bool invert = backface;
+#else
+ const bool invert = false;
+ if (!backface) {
+#endif
+#ifdef USE_INVOC_EXT
+ bool do_front = (gl_InvocationID & 1) == 0;
+ emit_cap(do_front, invert);
+#else
+ emit_cap(true, invert);
+ emit_cap(false, invert);
+#endif
+#ifndef DOUBLE_MANIFOLD
+ }
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
new file mode 100644
index 00000000000..ceb33e77f2b
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
@@ -0,0 +1,14 @@
+
+out vec4 fragColor;
+
+void main()
+{
+ const float intensity = 0.25;
+#ifdef SHADOW_PASS
+ fragColor = vec4((gl_FrontFacing) ? vec3(intensity, -intensity, 0.0)
+ : vec3(-intensity, intensity, 0.0), 1.0);
+#else
+ fragColor = vec4((gl_FrontFacing) ? vec3(intensity, intensity, -intensity)
+ : vec3(-intensity, -intensity, intensity), 1.0);
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl
new file mode 100644
index 00000000000..7418f86a58e
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl
@@ -0,0 +1,118 @@
+#extension GL_ARB_gpu_shader5 : enable
+
+#ifdef GL_ARB_gpu_shader5
+#define USE_INVOC_EXT
+#endif
+
+#ifdef DOUBLE_MANIFOLD
+# ifdef USE_INVOC_EXT
+# define invoc_len 2
+# else
+# define vert_len 8
+# endif
+#else
+# ifdef USE_INVOC_EXT
+# define invoc_len 1
+# else
+# define vert_len 4
+# endif
+#endif
+
+#ifdef USE_INVOC_EXT
+layout(lines_adjacency, invocations = invoc_len) in;
+layout(triangle_strip, max_vertices = 4) out;
+#else
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = vert_len) out;
+#endif
+
+uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
+
+in VertexData {
+ vec3 pos; /* local position */
+ vec4 frontPosition; /* final ndc position */
+ vec4 backPosition;
+} vData[];
+
+#define DEGENERATE_THRESHOLD 1e-12
+
+#define len_sqr(a) dot(a, a)
+
+void extrude_edge(bool invert)
+{
+ /* Reverse order if backfacing the light. */
+ ivec2 idx = (invert) ? ivec2(1, 2) : ivec2(2, 1);
+ gl_Position = vData[idx.x].frontPosition; EmitVertex();
+ gl_Position = vData[idx.y].frontPosition; EmitVertex();
+ gl_Position = vData[idx.x].backPosition; EmitVertex();
+ gl_Position = vData[idx.y].backPosition; EmitVertex();
+ EndPrimitive();
+}
+
+void main()
+{
+ vec3 v10 = vData[0].pos - vData[1].pos;
+ vec3 v12 = vData[2].pos - vData[1].pos;
+ vec3 v13 = vData[3].pos - vData[1].pos;
+
+#ifdef DEGENERATE_THRESHOLD
+ vec3 v20 = vData[0].pos - vData[2].pos;
+ vec3 v23 = vData[3].pos - vData[2].pos;
+
+ vec4 edges_lensqr = vec4(len_sqr(v10), len_sqr(v13), len_sqr(v20), len_sqr(v23));
+ bvec4 degen_edges = lessThan(edges_lensqr, vec4(DEGENERATE_THRESHOLD));
+
+ /* Both triangles are degenerate, abort. */
+ if (any(degen_edges.xz) && any(degen_edges.yw))
+ return;
+#endif
+
+ vec3 n1 = cross(v12, v10);
+ vec3 n2 = cross(v13, v12);
+ vec2 facing = vec2(dot(n1, lightDirection),
+ dot(n2, lightDirection));
+
+ /* WATCH: maybe unpredictable in some cases. */
+ bool is_manifold = any(notEqual(vData[0].pos, vData[3].pos));
+
+ bvec2 backface = greaterThan(facing, vec2(0.0));
+
+#ifdef DEGENERATE_THRESHOLD
+# ifndef DOUBLE_MANIFOLD
+ /* If the mesh is known to be manifold and we don't use double count,
+ * only create an quad if the we encounter a facing geom. */
+ if ((any(degen_edges.xz) && backface.y) ||
+ (any(degen_edges.yw) && backface.x))
+ return;
+# endif
+
+ /* If one of the 2 triangles is degenerate, replace edge by a non-manifold one. */
+ backface.x = (any(degen_edges.xz)) ? !backface.y : backface.x;
+ backface.y = (any(degen_edges.yw)) ? !backface.x : backface.y;
+ is_manifold = (any(degen_edges)) ? false : is_manifold;
+#endif
+
+ /* If both faces face the same direction it's not an outline edge. */
+ if (backface.x == backface.y)
+ return;
+
+#ifdef USE_INVOC_EXT
+ if (gl_InvocationID == 0) {
+ extrude_edge(backface.x);
+ }
+ else if (is_manifold) {
+# ifdef DOUBLE_MANIFOLD
+ /* Increment/Decrement twice for manifold edges. */
+ extrude_edge(backface.x);
+# endif
+ }
+#else
+ extrude_edge(backface.x);
+ if (is_manifold) {
+# ifdef DOUBLE_MANIFOLD
+ /* Increment/Decrement twice for manifold edges. */
+ extrude_edge(backface.x);
+# endif
+ }
+#endif
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl
new file mode 100644
index 00000000000..50a721f948f
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl
@@ -0,0 +1,21 @@
+#define INFINITE 1000.0
+
+uniform mat4 ModelViewProjectionMatrix;
+
+uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
+uniform float lightDistance = 1e4;
+
+in vec3 pos;
+
+out VertexData {
+ vec3 pos; /* local position */
+ vec4 frontPosition; /* final ndc position */
+ vec4 backPosition;
+} vData;
+
+void main()
+{
+ vData.pos = pos;
+ vData.frontPosition = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ vData.backPosition = ModelViewProjectionMatrix * vec4(pos + lightDirection * lightDistance, 1.0);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
new file mode 100644
index 00000000000..0d2d2187a85
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -0,0 +1,248 @@
+
+uniform mat4 ProjectionMatrix;
+uniform mat4 ModelMatrixInverse;
+uniform mat4 ModelViewMatrixInverse;
+uniform mat4 ModelMatrix;
+uniform vec3 OrcoTexCoFactors[2];
+
+uniform sampler2D depthBuffer;
+
+uniform sampler3D densityTexture;
+uniform sampler3D shadowTexture;
+uniform sampler3D flameTexture;
+uniform sampler1D flameColorTexture;
+uniform sampler1D transferTexture;
+
+uniform int samplesLen = 256;
+uniform float noiseOfs = 0.0f;
+uniform float stepLength; /* Step length in local space. */
+uniform float densityScale; /* Simple Opacity multiplicator. */
+uniform vec4 viewvecs[3];
+
+uniform float slicePosition;
+uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
+
+#ifdef VOLUME_SLICE
+in vec3 localPos;
+#endif
+
+out vec4 fragColor;
+
+#define M_PI 3.1415926535897932 /* pi */
+
+float phase_function_isotropic()
+{
+ return 1.0 / (4.0 * M_PI);
+}
+
+float get_view_z_from_depth(float depth)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ float d = 2.0 * depth - 1.0;
+ return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
+ }
+ else {
+ return viewvecs[0].z + depth * viewvecs[1].z;
+ }
+}
+
+vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ return vec3(viewvecs[0].xy + uvcoords * viewvecs[1].xy, 1.0) * get_view_z_from_depth(depth);
+ }
+ else {
+ return viewvecs[0].xyz + vec3(uvcoords, depth) * viewvecs[1].xyz;
+ }
+}
+
+float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
+
+float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
+{
+ /* https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ */
+ vec3 firstplane = (vec3( 1.0) - lineorigin) / linedirection;
+ vec3 secondplane = (vec3(-1.0) - lineorigin) / linedirection;
+ vec3 furthestplane = min(firstplane, secondplane);
+ return max_v3(furthestplane);
+}
+
+#define sample_trilinear(ima, co) texture(ima, co)
+
+vec4 sample_tricubic(sampler3D ima, vec3 co)
+{
+ vec3 tex_size = vec3(textureSize(ima, 0).xyz);
+
+ co *= tex_size;
+ /* texel center */
+ vec3 tc = floor(co - 0.5) + 0.5;
+ vec3 f = co - tc;
+ vec3 f2 = f * f;
+ vec3 f3 = f2 * f;
+ /* Bspline coefs (optimized) */
+ vec3 w3 = f3 / 6.0;
+ vec3 w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0;
+ vec3 w1 = f3 * 0.5 - f2 + 2.0 / 3.0;
+ vec3 w2 = 1.0 - w0 - w1 - w3;
+
+ vec3 s0 = w0 + w1;
+ vec3 s1 = w2 + w3;
+
+ vec3 f0 = w1 / (w0 + w1);
+ vec3 f1 = w3 / (w2 + w3);
+
+ vec2 final_z;
+ vec4 final_co;
+ final_co.xy = tc.xy - 1.0 + f0.xy;
+ final_co.zw = tc.xy + 1.0 + f1.xy;
+ final_z = tc.zz + vec2(-1.0, 1.0) + vec2(f0.z, f1.z);
+
+ final_co /= tex_size.xyxy;
+ final_z /= tex_size.zz;
+
+ vec4 color;
+ color = texture(ima, vec3(final_co.xy, final_z.x)) * s0.x * s0.y * s0.z;
+ color += texture(ima, vec3(final_co.zy, final_z.x)) * s1.x * s0.y * s0.z;
+ color += texture(ima, vec3(final_co.xw, final_z.x)) * s0.x * s1.y * s0.z;
+ color += texture(ima, vec3(final_co.zw, final_z.x)) * s1.x * s1.y * s0.z;
+
+ color += texture(ima, vec3(final_co.xy, final_z.y)) * s0.x * s0.y * s1.z;
+ color += texture(ima, vec3(final_co.zy, final_z.y)) * s1.x * s0.y * s1.z;
+ color += texture(ima, vec3(final_co.xw, final_z.y)) * s0.x * s1.y * s1.z;
+ color += texture(ima, vec3(final_co.zw, final_z.y)) * s1.x * s1.y * s1.z;
+
+ return color;
+}
+
+#ifdef USE_TRICUBIC
+# define sample_volume_texture sample_tricubic
+#else
+# define sample_volume_texture sample_trilinear
+#endif
+
+void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction)
+{
+ vec3 co = ls_pos * 0.5 + 0.5;
+#ifdef USE_COBA
+ float val = sample_volume_texture(densityTexture, co).r;
+ vec4 tval = texture(transferTexture, val) * densityScale;
+ tval.rgb = pow(tval.rgb, vec3(2.2));
+ scattering = tval.rgb * 1500.0;
+ extinction = max(1e-4, tval.a * 50.0);
+#else
+ float flame = sample_volume_texture(flameTexture, co).r;
+ vec4 emission = texture(flameColorTexture, flame);
+ float shadows = sample_volume_texture(shadowTexture, co).r;
+ vec4 density = sample_volume_texture(densityTexture, co); /* rgb: color, a: density */
+
+ scattering = density.rgb * (density.a * densityScale);
+ extinction = max(1e-4, dot(scattering, vec3(0.33333)));
+
+ /* Scale shadows in log space and clamp them to avoid completely black shadows. */
+ scattering *= exp(clamp(log(shadows) * densityScale * 0.1, -2.5, 0.0)) * M_PI;
+
+ /* 800 is arbitrary and here to mimic old viewport. TODO make it a parameter */
+ scattering += pow(emission.rgb, vec3(2.2)) * emission.a * 800.0;
+#endif
+}
+
+void eval_volume_step(inout vec3 Lscat, float extinction, float step_len, out float Tr)
+{
+ Lscat *= phase_function_isotropic();
+ /* Evaluate Scattering */
+ Tr = exp(-extinction * step_len);
+ /* integrate along the current step segment */
+ Lscat = (Lscat - Lscat * Tr) / extinction;
+}
+
+#define P(x) ((x + 0.5) * (1.0 / 16.0))
+const vec4 dither_mat[4] = vec4[4](
+ vec4( P(0.0), P(8.0), P(2.0), P(10.0)),
+ vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
+ vec4( P(3.0), P(11.0), P(1.0), P(9.0)),
+ vec4(P(15.0), P(7.0), P(13.0), P(5.0))
+);
+
+vec4 volume_integration(
+ vec3 ray_ori, vec3 ray_dir, float ray_inc, float ray_max, float step_len)
+{
+ /* Start with full transmittance and no scattered light. */
+ vec3 final_scattering = vec3(0.0);
+ float final_transmittance = 1.0;
+
+ ivec2 tx = ivec2(gl_FragCoord.xy) % 4;
+ float noise = fract(dither_mat[tx.x][tx.y] + noiseOfs);
+
+ float ray_len = noise * ray_inc;
+ for (int i = 0; i < samplesLen && ray_len < ray_max; ++i, ray_len += ray_inc) {
+ vec3 ls_pos = ray_ori + ray_dir * ray_len;
+
+ vec3 Lscat;
+ float s_extinction, Tr;
+ volume_properties(ls_pos, Lscat, s_extinction);
+ eval_volume_step(Lscat, s_extinction, step_len, Tr);
+ /* accumulate and also take into account the transmittance from previous steps */
+ final_scattering += final_transmittance * Lscat;
+ final_transmittance *= Tr;
+ }
+
+ return vec4(final_scattering, final_transmittance);
+}
+
+void main()
+{
+#ifdef VOLUME_SLICE
+ /* Manual depth test. TODO remove. */
+ float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
+ if (gl_FragCoord.z >= depth) {
+ discard;
+ }
+
+ vec3 Lscat;
+ float s_extinction, Tr;
+ volume_properties(localPos, Lscat, s_extinction);
+ eval_volume_step(Lscat, s_extinction, stepLength, Tr);
+
+ fragColor = vec4(Lscat, Tr);
+#else
+ vec2 screen_uv = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0).xy);
+ bool is_persp = ProjectionMatrix[3][3] == 0.0;
+
+ vec3 volume_center = ModelMatrix[3].xyz;
+
+ float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
+ float depth_end = min(depth, gl_FragCoord.z);
+ vec3 vs_ray_end = get_view_space_from_depth(screen_uv, depth_end);
+ vec3 vs_ray_ori = get_view_space_from_depth(screen_uv, 0.0);
+ vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0);
+ vs_ray_dir /= abs(vs_ray_dir.z);
+
+ vec3 ls_ray_dir = mat3(ModelViewMatrixInverse) * vs_ray_dir * OrcoTexCoFactors[1] * 2.0;
+ vec3 ls_ray_ori = (ModelViewMatrixInverse * vec4(vs_ray_ori, 1.0)).xyz;
+ vec3 ls_ray_end = (ModelViewMatrixInverse * vec4(vs_ray_end, 1.0)).xyz;
+
+ ls_ray_ori = (OrcoTexCoFactors[0] + ls_ray_ori * OrcoTexCoFactors[1]) * 2.0 - 1.0;
+ ls_ray_end = (OrcoTexCoFactors[0] + ls_ray_end * OrcoTexCoFactors[1]) * 2.0 - 1.0;
+
+ /* TODO: Align rays to volume center so that it mimics old behaviour of slicing the volume. */
+
+ float dist = line_unit_box_intersect_dist(ls_ray_ori, ls_ray_dir);
+ if (dist > 0.0) {
+ ls_ray_ori = ls_ray_dir * dist + ls_ray_ori;
+ }
+
+ vec3 ls_vol_isect = ls_ray_end - ls_ray_ori;
+ if (dot(ls_ray_dir, ls_vol_isect) < 0.0) {
+ /* Start is further away than the end.
+ * That means no volume is intersected. */
+ discard;
+ }
+
+ fragColor = volume_integration(ls_ray_ori, ls_ray_dir, stepLength,
+ length(ls_vol_isect) / length(ls_ray_dir),
+ length(vs_ray_dir) * stepLength);
+#endif
+
+ /* Convert transmitance to alpha so we can use premul blending. */
+ fragColor.a = 1.0 - fragColor.a;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
new file mode 100644
index 00000000000..7ce21c3d5ca
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -0,0 +1,33 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec3 OrcoTexCoFactors[2];
+uniform float slicePosition;
+uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
+
+in vec3 pos;
+
+#ifdef VOLUME_SLICE
+in vec3 uvs;
+
+out vec3 localPos;
+#endif
+
+void main()
+{
+#ifdef VOLUME_SLICE
+ if (sliceAxis == 0) {
+ localPos = vec3(slicePosition * 2.0 - 1.0, pos.xy);
+ }
+ else if (sliceAxis == 1) {
+ localPos = vec3(pos.x, slicePosition * 2.0 - 1.0, pos.y);
+ }
+ else {
+ localPos = vec3(pos.xy, slicePosition * 2.0 - 1.0);
+ }
+ vec3 final_pos = localPos;
+#else
+ vec3 final_pos = pos;
+#endif
+ final_pos = ((final_pos * 0.5 + 0.5) - OrcoTexCoFactors[0]) / OrcoTexCoFactors[1];
+ gl_Position = ModelViewProjectionMatrix * vec4(final_pos, 1.0);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
new file mode 100644
index 00000000000..e25be733d44
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
@@ -0,0 +1,191 @@
+#define BLINN
+
+#if STUDIOLIGHT_SH_BANDS == 2
+vec3 spherical_harmonics(vec3 N, vec3 sh_coefs[STUDIOLIGHT_SH_MAX_COMPONENTS])
+{
+ /* http://www.geomerics.com/wp-content/uploads/2015/08/CEDEC_Geomerics_ReconstructingDiffuseLighting1.pdf */
+ /* Highly optimized form, precompute as much as we can. */
+ /**
+ * R1 = 0.5 * vec3(L3.r, L2.r, L1.r);
+ * sh_coefs[0..2] = R1 / length(R1);
+ **/
+ vec3 q;
+ q.x = dot(sh_coefs[1], N);
+ q.y = dot(sh_coefs[2], N);
+ q.z = dot(sh_coefs[3], N);
+ q = 0.5 * q + 0.5;
+
+ /**
+ * R0 = L0.r;
+ * lr1_r0 = lenR1 / R0;
+ * p = 1.0 + 2.0 * lr1_r0;
+ * a = (1.0 - lr1_r0) / (1.0 + lr1_r0);
+ * return R0 * (a + (1.0 - a) * (p + 1.0) * pow(q, p));
+ *
+ * sh_coefs[4] = p;
+ * sh_coefs[5] = R0 * a;
+ * sh_coefs[0] = R0 * (1.0 - a) * (p + 1.0);
+ **/
+ q = pow(q, sh_coefs[4]);
+ return sh_coefs[0] * q + sh_coefs[5];
+}
+
+#else
+
+vec3 spherical_harmonics(vec3 N, vec3 sh_coefs[STUDIOLIGHT_SH_MAX_COMPONENTS])
+{
+ vec3 sh = 0.282095 * sh_coefs[0];
+
+# if STUDIOLIGHT_SH_BANDS > 1
+ float nx = N.x;
+ float ny = N.y;
+ float nz = N.z;
+ sh += -0.488603 * nz * sh_coefs[1];
+ sh += 0.488603 * ny * sh_coefs[2];
+ sh += -0.488603 * nx * sh_coefs[3];
+# endif
+# if STUDIOLIGHT_SH_BANDS > 2
+ float nx2 = nx * nx;
+ float ny2 = ny * ny;
+ float nz2 = nz * nz;
+ sh += 1.092548 * nx * nz * sh_coefs[4];
+ sh += -1.092548 * nz * ny * sh_coefs[5];
+ sh += 0.315392 * (3.0 * ny2 - 1.0) * sh_coefs[6];
+ sh += -1.092548 * nx * ny * sh_coefs[7];
+ sh += 0.546274 * (nx2 - nz2) * sh_coefs[8];
+# endif
+# if STUDIOLIGHT_SH_BANDS > 4
+ float nx4 = nx2 * nx2;
+ float ny4 = ny2 * ny2;
+ float nz4 = nz2 * nz2;
+ sh += (2.5033429417967046 * nx * nz * (nx2 - nz2)) * sh_coefs[9];
+ sh += (-1.7701307697799304 * nz * ny * (3.0 * nx2 - nz2)) * sh_coefs[10];
+ sh += (0.9461746957575601 * nz * nx * (-1.0 +7.0*ny2)) * sh_coefs[11];
+ sh += (-0.6690465435572892 * nz * ny * (-3.0 + 7.0 * ny2)) * sh_coefs[12];
+ sh += ((105.0*ny4-90.0*ny2+9.0)/28.359261614) * sh_coefs[13];
+ sh += (-0.6690465435572892 * nx * ny * (-3.0 + 7.0 * ny2)) * sh_coefs[14];
+ sh += (0.9461746957575601 * (nx2 - nz2) * (-1.0 + 7.0 * ny2)) * sh_coefs[15];
+ sh += (-1.7701307697799304 * nx * ny * (nx2 - 3.0 * nz2)) * sh_coefs[16];
+ sh += (0.6258357354491761 * (nx4 - 6.0 * nz2 * nx2 + nz4)) * sh_coefs[17];
+# endif
+ return sh;
+}
+#endif
+
+/* [Drobot2014a] Low Level Optimizations for GCN */
+vec4 fast_rcp(vec4 v)
+{
+ return intBitsToFloat(0x7eef370b - floatBitsToInt(v));
+}
+
+vec3 brdf_approx(vec3 spec_color, float roughness, float NV)
+{
+ /* Treat anything below 2% as shadowing.
+ * (in other words, makes it possible to completely disable
+ * specular on a material by setting specular color to black). */
+ float shadowing = clamp(50.0 * spec_color.g, 0.0, 1.0);
+ /* Very rough own approx. We don't need it to be correct, just fast.
+ * Just simulate fresnel effect with roughness attenuation. */
+ float fresnel = exp2(-8.35 * NV) * (1.0 - roughness);
+ return mix(spec_color, vec3(1.0), fresnel) * shadowing;
+}
+
+void prep_specular(
+ vec3 L, vec3 I, vec3 N, vec3 R,
+ out float NL, out float wrapped_NL, out float spec_angle)
+{
+ wrapped_NL = dot(L, R);
+ vec3 half_dir = normalize(L + I);
+ spec_angle = clamp(dot(half_dir, N), 0.0, 1.0);
+ NL = clamp(dot(L, N), 0.0, 1.0);
+}
+
+/* Normalized Blinn shading */
+vec4 blinn_specular(vec4 shininess, vec4 spec_angle, vec4 NL)
+{
+ /* Pi is already divided in the lamp power.
+ * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */
+ vec4 normalization_factor = shininess * 0.125 + 1.0;
+ vec4 spec_light = pow(spec_angle, shininess) * NL * normalization_factor;
+
+ return spec_light;
+}
+
+/* NL need to be unclamped. w in [0..1] range. */
+vec4 wrapped_lighting(vec4 NL, vec4 w)
+{
+ vec4 w_1 = w + 1.0;
+ vec4 denom = fast_rcp(w_1 * w_1);
+ return clamp((NL + w) * denom, 0.0, 1.0);
+}
+
+vec3 get_world_lighting(
+ WorldData world_data,
+ vec3 diffuse_color, vec3 specular_color, float roughness,
+ vec3 N, vec3 I)
+{
+ vec3 specular_light = world_data.ambient_color.rgb;
+ vec3 diffuse_light = world_data.ambient_color.rgb;
+ vec4 wrap = vec4(
+ world_data.lights[0].diffuse_color_wrap.a,
+ world_data.lights[1].diffuse_color_wrap.a,
+ world_data.lights[2].diffuse_color_wrap.a,
+ world_data.lights[3].diffuse_color_wrap.a
+ );
+
+#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
+ /* Prepare Specular computation. Eval 4 lights at once. */
+ vec3 R = -reflect(I, N);
+ vec4 spec_angle, spec_NL, wrap_NL;
+ prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
+ prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
+ prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
+ prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);
+
+ vec4 gloss = vec4(1.0 - roughness);
+ /* Reduce gloss for smooth light. (simulate bigger light) */
+ gloss *= 1.0 - wrap;
+ vec4 shininess = exp2(10.0 * gloss + 1.0);
+
+ vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);
+
+ /* Simulate Env. light. */
+ vec4 w = mix(wrap, vec4(1.0), roughness);
+ vec4 spec_env = wrapped_lighting(wrap_NL, w);
+
+ spec_light = mix(spec_light, spec_env, wrap * wrap);
+
+ /* Multiply result by lights specular colors. */
+ specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
+ specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
+ specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
+ specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;
+
+ float NV = clamp(dot(N, I), 0.0, 1.0);
+ specular_color = brdf_approx(specular_color, roughness, NV);
+#endif
+ specular_light *= specular_color;
+
+ /* Prepare diffuse computation. Eval 4 lights at once. */
+ vec4 diff_NL;
+ diff_NL.x = dot(world_data.lights[0].direction.xyz, N);
+ diff_NL.y = dot(world_data.lights[1].direction.xyz, N);
+ diff_NL.z = dot(world_data.lights[2].direction.xyz, N);
+ diff_NL.w = dot(world_data.lights[3].direction.xyz, N);
+
+ vec4 diff_light = wrapped_lighting(diff_NL, wrap);
+
+ /* Multiply result by lights diffuse colors. */
+ diffuse_light += diff_light.x * world_data.lights[0].diffuse_color_wrap.rgb;
+ diffuse_light += diff_light.y * world_data.lights[1].diffuse_color_wrap.rgb;
+ diffuse_light += diff_light.z * world_data.lights[2].diffuse_color_wrap.rgb;
+ diffuse_light += diff_light.w * world_data.lights[3].diffuse_color_wrap.rgb;
+
+ /* Energy conservation with colored specular look strange.
+ * Limit this strangeness by using mono-chromatic specular intensity. */
+ float spec_energy = dot(specular_color, vec3(0.33333));
+
+ diffuse_light *= diffuse_color * (1.0 - spec_energy);
+
+ return diffuse_light + specular_light;
+}
diff --git a/source/blender/draw/engines/workbench/solid_mode.c b/source/blender/draw/engines/workbench/solid_mode.c
new file mode 100644
index 00000000000..19c8b4f18d1
--- /dev/null
+++ b/source/blender/draw/engines/workbench/solid_mode.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file solid_mode.c
+ * \ingroup draw_engine
+ *
+ * Simple engine for drawing color and/or depth.
+ * When we only need simple studio shaders.
+ */
+
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+
+#include "RE_pipeline.h"
+
+#include "workbench_private.h"
+
+/* Functions */
+
+static void workbench_solid_engine_init(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_deferred_engine_init(data);
+}
+
+static void workbench_solid_cache_init(void *vedata)
+{
+
+ WORKBENCH_Data *data = vedata;
+ workbench_deferred_cache_init(data);
+}
+
+static void workbench_solid_cache_populate(void *vedata, Object *ob)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_deferred_solid_cache_populate(data, ob);
+}
+
+static void workbench_solid_cache_finish(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_deferred_cache_finish(data);
+}
+
+static void workbench_solid_draw_background(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_deferred_draw_background(data);
+ workbench_deferred_draw_scene(data);
+ workbench_deferred_draw_finish(data);
+}
+
+static void workbench_solid_engine_free(void)
+{
+ workbench_deferred_engine_free();
+}
+
+static void workbench_solid_view_update(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_taa_view_updated(data);
+}
+
+static void workbench_solid_id_update(void *UNUSED(vedata), struct ID *id)
+{
+ if (GS(id->name) == ID_OB) {
+ WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get(id, &draw_engine_workbench_solid);
+ if (oed != NULL && oed->dd.recalc != 0) {
+ oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0;
+ oed->dd.recalc = 0;
+ }
+ }
+}
+
+static void workbench_render_to_image(void *vedata, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect)
+{
+ workbench_render(vedata, engine, render_layer, rect);
+}
+
+static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
+
+DrawEngineType draw_engine_workbench_solid = {
+ NULL, NULL,
+ N_("Workbench"),
+ &workbench_data_size,
+ &workbench_solid_engine_init,
+ &workbench_solid_engine_free,
+ &workbench_solid_cache_init,
+ &workbench_solid_cache_populate,
+ &workbench_solid_cache_finish,
+ &workbench_solid_draw_background,
+ NULL,
+ &workbench_solid_view_update,
+ &workbench_solid_id_update,
+ &workbench_render_to_image,
+};
diff --git a/source/blender/draw/engines/workbench/transparent_mode.c b/source/blender/draw/engines/workbench/transparent_mode.c
new file mode 100644
index 00000000000..1d451a96419
--- /dev/null
+++ b/source/blender/draw/engines/workbench/transparent_mode.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file transparent_mode.c
+ * \ingroup draw_engine
+ *
+ * Simple engine for drawing color and/or depth.
+ * When we only need simple studio shaders.
+ */
+
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+
+#include "workbench_private.h"
+
+/* Functions */
+
+static void workbench_transparent_engine_init(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_forward_engine_init(data);
+}
+
+static void workbench_transparent_cache_init(void *vedata)
+{
+
+ WORKBENCH_Data *data = vedata;
+ workbench_forward_cache_init(data);
+}
+
+static void workbench_transparent_cache_populate(void *vedata, Object *ob)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_forward_cache_populate(data, ob);
+}
+
+static void workbench_transparent_cache_finish(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_forward_cache_finish(data);
+}
+
+static void workbench_transparent_draw_background(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_forward_draw_background(data);
+ workbench_forward_draw_scene(data);
+ workbench_forward_draw_finish(data);
+}
+
+static void workbench_transparent_engine_free(void)
+{
+ workbench_forward_engine_free();
+}
+
+static void workbench_transparent_view_update(void *vedata)
+{
+ WORKBENCH_Data *data = vedata;
+ workbench_taa_view_updated(data);
+}
+
+static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data);
+
+DrawEngineType draw_engine_workbench_transparent = {
+ NULL, NULL,
+ N_("Workbench"),
+ &workbench_data_size,
+ &workbench_transparent_engine_init,
+ &workbench_transparent_engine_free,
+ &workbench_transparent_cache_init,
+ &workbench_transparent_cache_populate,
+ &workbench_transparent_cache_finish,
+ &workbench_transparent_draw_background,
+ NULL,
+ &workbench_transparent_view_update,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
new file mode 100644
index 00000000000..1cdf4c2b443
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -0,0 +1,176 @@
+#include "workbench_private.h"
+
+#include "DNA_userdef_types.h"
+
+#include "UI_resources.h"
+
+
+void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info)
+{
+ effect_info->jitter_index = 0;
+ effect_info->view_updated = true;
+}
+
+void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ wpd->material_hash = BLI_ghash_ptr_new(__func__);
+ wpd->user_preferences = &U;
+
+ View3D *v3d = draw_ctx->v3d;
+ if (!v3d) {
+ wpd->shading = scene->display.shading;
+ wpd->use_color_view_settings = true;
+ }
+ else if (v3d->shading.type == OB_RENDER &&
+ BKE_scene_uses_blender_workbench(scene))
+ {
+ wpd->shading = scene->display.shading;
+ wpd->use_color_view_settings = true;
+ }
+ else {
+ wpd->shading = v3d->shading;
+ wpd->use_color_view_settings = false;
+ }
+
+ if (wpd->shading.light == V3D_LIGHTING_MATCAP) {
+ wpd->studio_light = BKE_studiolight_find(
+ wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP);
+ }
+ else {
+ wpd->studio_light = BKE_studiolight_find(
+ wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO);
+ }
+
+ /* If matcaps are missing, use this as fallback. */
+ if (UNLIKELY(wpd->studio_light == NULL)) {
+ wpd->studio_light = BKE_studiolight_find(
+ wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO);
+ }
+
+ wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity;
+
+ WORKBENCH_UBO_World *wd = &wpd->world_data;
+ wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0;
+ wd->background_alpha = (DRW_state_is_image_render() && scene->r.alphamode == R_ALPHAPREMUL) ? 0.0f : 1.0f;
+
+ if (!v3d || ((v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) &&
+ (scene->world != NULL)))
+ {
+ copy_v3_v3(wd->background_color_low, &scene->world->horr);
+ copy_v3_v3(wd->background_color_high, &scene->world->horr);
+ }
+ else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_VIEWPORT) {
+ copy_v3_v3(wd->background_color_low, v3d->shading.background_color);
+ copy_v3_v3(wd->background_color_high, v3d->shading.background_color);
+ }
+ else if (v3d) {
+ UI_GetThemeColor3fv(UI_GetThemeValue(TH_SHOW_BACK_GRAD) ? TH_LOW_GRAD : TH_HIGH_GRAD, wd->background_color_low);
+ UI_GetThemeColor3fv(TH_HIGH_GRAD, wd->background_color_high);
+
+ /* XXX: Really quick conversion to avoid washed out background.
+ * Needs to be addressed properly (color managed using ocio). */
+ srgb_to_linearrgb_v3_v3(wd->background_color_high, wd->background_color_high);
+ srgb_to_linearrgb_v3_v3(wd->background_color_low, wd->background_color_low);
+ }
+ else {
+ zero_v3(wd->background_color_low);
+ zero_v3(wd->background_color_high);
+ }
+
+ studiolight_update_world(wpd, wpd->studio_light, wd);
+
+ copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color);
+ wd->object_outline_color[3] = 1.0f;
+
+ wd->curvature_ridge = 0.5f / max_ff(SQUARE(wpd->shading.curvature_ridge_factor), 1e-4f);
+ wd->curvature_valley = 0.7f / max_ff(SQUARE(wpd->shading.curvature_valley_factor), 1e-4f);
+
+ wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data);
+
+ /* Cavity settings */
+ {
+ const int ssao_samples = scene->display.matcap_ssao_samples;
+
+ float invproj[4][4];
+ const bool is_persp = DRW_viewport_is_persp_get();
+ /* view vectors for the corners of the view frustum.
+ * Can be used to recreate the world space position easily */
+ float viewvecs[3][4] = {
+ {-1.0f, -1.0f, -1.0f, 1.0f},
+ {1.0f, -1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f, 1.0f}
+ };
+ int i;
+ const float *size = DRW_viewport_size_get();
+
+ wpd->ssao_params[0] = ssao_samples;
+ wpd->ssao_params[1] = size[0] / 64.0;
+ wpd->ssao_params[2] = size[1] / 64.0;
+ wpd->ssao_params[3] = 0;
+
+ /* distance, factor, factor, attenuation */
+ copy_v4_fl4(
+ wpd->ssao_settings,
+ scene->display.matcap_ssao_distance,
+ wpd->shading.cavity_valley_factor,
+ wpd->shading.cavity_ridge_factor,
+ scene->display.matcap_ssao_attenuation);
+
+ /* invert the view matrix */
+ DRW_viewport_matrix_get(wpd->winmat, DRW_MAT_WIN);
+ invert_m4_m4(invproj, wpd->winmat);
+
+ /* convert the view vectors to view space */
+ for (i = 0; i < 3; i++) {
+ mul_m4_v4(invproj, viewvecs[i]);
+ /* normalized trick see:
+ * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
+ if (is_persp)
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
+ viewvecs[i][3] = 1.0;
+
+ copy_v4_v4(wpd->viewvecs[i], viewvecs[i]);
+ }
+
+ /* we need to store the differences */
+ wpd->viewvecs[1][0] -= wpd->viewvecs[0][0];
+ wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->viewvecs[0][1];
+
+ /* calculate a depth offset as well */
+ if (!is_persp) {
+ float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
+ mul_m4_v4(invproj, vec_far);
+ mul_v3_fl(vec_far, 1.0f / vec_far[3]);
+ wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2];
+ }
+ }
+
+ wpd->volumes_do = false;
+ BLI_listbase_clear(&wpd->smoke_domains);
+}
+
+void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, float r_light_direction[3])
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ WORKBENCH_UBO_World *wd = &wpd->world_data;
+ float view_matrix[4][4];
+ DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW);
+
+ copy_v3_v3(r_light_direction, scene->display.light_direction);
+ negate_v3(r_light_direction);
+
+ /* Shadow direction. */
+ mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, r_light_direction);
+
+ DRW_uniformbuffer_update(wpd->world_ubo, wd);
+}
+
+void workbench_private_data_free(WORKBENCH_PrivateData *wpd)
+{
+ BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN);
+ DRW_UBO_FREE_SAFE(wpd->world_ubo);
+}
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
new file mode 100644
index 00000000000..1ca76da672a
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -0,0 +1,1003 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_deferred.c
+ * \ingroup draw_engine
+ */
+
+#include "workbench_private.h"
+
+#include "BIF_gl.h"
+
+#include "BLI_alloca.h"
+#include "BLI_dynstr.h"
+#include "BLI_utildefines.h"
+#include "BLI_rand.h"
+
+#include "BKE_node.h"
+#include "BKE_modifier.h"
+#include "BKE_particle.h"
+
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
+#include "ED_uvedit.h"
+
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
+
+/* *********** STATIC *********** */
+
+/* #define DEBUG_SHADOW_VOLUME */
+
+#ifdef DEBUG_SHADOW_VOLUME
+# include "draw_debug.h"
+#endif
+
+static struct {
+ struct GPUShader *prepass_sh_cache[MAX_SHADERS];
+ struct GPUShader *composite_sh_cache[MAX_SHADERS];
+ struct GPUShader *cavity_sh[MAX_CAVITY_SHADERS];
+ struct GPUShader *ghost_resolve_sh;
+ struct GPUShader *shadow_fail_sh;
+ struct GPUShader *shadow_fail_manifold_sh;
+ struct GPUShader *shadow_pass_sh;
+ struct GPUShader *shadow_pass_manifold_sh;
+ struct GPUShader *shadow_caps_sh;
+ struct GPUShader *shadow_caps_manifold_sh;
+
+ struct GPUTexture *ghost_depth_tx; /* ref only, not alloced */
+ struct GPUTexture *object_id_tx; /* ref only, not alloced */
+ struct GPUTexture *color_buffer_tx; /* ref only, not alloced */
+ struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */
+ struct GPUTexture *specular_buffer_tx; /* ref only, not alloced */
+ struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */
+ struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
+
+ SceneDisplay display; /* world light direction for shadows */
+ int next_object_id;
+
+ struct GPUUniformBuffer *sampling_ubo;
+ struct GPUTexture *jitter_tx;
+ int cached_sample_num;
+} e_data = {{NULL}};
+
+/* Shaders */
+extern char datatoc_common_hair_lib_glsl[];
+
+extern char datatoc_workbench_prepass_vert_glsl[];
+extern char datatoc_workbench_prepass_frag_glsl[];
+extern char datatoc_workbench_cavity_frag_glsl[];
+extern char datatoc_workbench_deferred_composite_frag_glsl[];
+extern char datatoc_workbench_ghost_resolve_frag_glsl[];
+
+extern char datatoc_workbench_shadow_vert_glsl[];
+extern char datatoc_workbench_shadow_geom_glsl[];
+extern char datatoc_workbench_shadow_caps_geom_glsl[];
+extern char datatoc_workbench_shadow_debug_frag_glsl[];
+
+extern char datatoc_workbench_background_lib_glsl[];
+extern char datatoc_workbench_cavity_lib_glsl[];
+extern char datatoc_workbench_common_lib_glsl[];
+extern char datatoc_workbench_data_lib_glsl[];
+extern char datatoc_workbench_object_outline_lib_glsl[];
+extern char datatoc_workbench_curvature_lib_glsl[];
+extern char datatoc_workbench_world_light_lib_glsl[];
+
+extern char datatoc_gpu_shader_depth_only_frag_glsl[];
+
+static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_background_lib_glsl);
+
+ if ((wpd->shading.light & V3D_LIGHTING_MATCAP) || (wpd->shading.light & V3D_LIGHTING_STUDIO) || (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT)) {
+ BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl);
+ }
+ if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) {
+ BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl);
+ }
+ if (CURVATURE_ENABLED(wpd)) {
+ BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
+ }
+
+ BLI_dynstr_append(ds, datatoc_workbench_deferred_composite_frag_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static char *workbench_build_prepass_frag(void)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static char *workbench_build_prepass_vert(bool is_hair)
+{
+ char *str = NULL;
+ if (!is_hair) {
+ return BLI_strdup(datatoc_workbench_prepass_vert_glsl);
+ }
+
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static char *workbench_build_cavity_frag(bool cavity, bool curvature, bool high_dpi)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ if (cavity) {
+ BLI_dynstr_append(ds, "#define USE_CAVITY\n");
+ }
+ if (curvature) {
+ BLI_dynstr_append(ds, "#define USE_CURVATURE\n");
+ }
+ if (high_dpi) {
+ BLI_dynstr_append(ds, "#define CURVATURE_OFFSET 2\n");
+ }
+ BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature)
+{
+ const bool high_dpi = (U.pixelsize > 1.5f);
+ int index = 0;
+ SET_FLAG_FROM_TEST(index, cavity, 1 << 0);
+ SET_FLAG_FROM_TEST(index, curvature, 1 << 1);
+ SET_FLAG_FROM_TEST(index, high_dpi, 1 << 2);
+
+ GPUShader **sh = &e_data.cavity_sh[index];
+ if (*sh == NULL) {
+ char *cavity_frag = workbench_build_cavity_frag(cavity, curvature, high_dpi);
+ *sh = DRW_shader_create_fullscreen(cavity_frag, NULL);
+ MEM_freeN(cavity_frag);
+ }
+ return *sh;
+}
+
+static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, bool use_textures, bool is_hair)
+{
+ if (e_data.prepass_sh_cache[index] == NULL) {
+ char *defines = workbench_material_build_defines(wpd, use_textures, is_hair);
+ char *composite_frag = workbench_build_composite_frag(wpd);
+ char *prepass_vert = workbench_build_prepass_vert(is_hair);
+ char *prepass_frag = workbench_build_prepass_frag();
+ e_data.prepass_sh_cache[index] = DRW_shader_create(
+ prepass_vert, NULL,
+ prepass_frag, defines);
+ if (!use_textures && !is_hair) {
+ e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
+ }
+ MEM_freeN(prepass_vert);
+ MEM_freeN(prepass_frag);
+ MEM_freeN(composite_frag);
+ MEM_freeN(defines);
+ }
+}
+
+static void select_deferred_shaders(WORKBENCH_PrivateData *wpd)
+{
+ int index_solid = workbench_material_get_shader_index(wpd, false, false);
+ int index_solid_hair = workbench_material_get_shader_index(wpd, false, true);
+ int index_texture = workbench_material_get_shader_index(wpd, true, false);
+ int index_texture_hair = workbench_material_get_shader_index(wpd, true, true);
+
+ ensure_deferred_shaders(wpd, index_solid, false, false);
+ ensure_deferred_shaders(wpd, index_solid_hair, false, true);
+ ensure_deferred_shaders(wpd, index_texture, true, false);
+ ensure_deferred_shaders(wpd, index_texture_hair, true, true);
+
+ wpd->prepass_solid_sh = e_data.prepass_sh_cache[index_solid];
+ wpd->prepass_solid_hair_sh = e_data.prepass_sh_cache[index_solid_hair];
+ wpd->prepass_texture_sh = e_data.prepass_sh_cache[index_texture];
+ wpd->prepass_texture_hair_sh = e_data.prepass_sh_cache[index_texture_hair];
+ wpd->composite_sh = e_data.composite_sh_cache[index_solid];
+}
+
+
+/* Using Hammersley distribution */
+static float *create_disk_samples(int num_samples, int num_iterations)
+{
+ /* vec4 to ensure memory alignment. */
+ const int total_samples = num_samples * num_iterations;
+ float(*texels)[4] = MEM_mallocN(sizeof(float[4]) * total_samples, __func__);
+ const float num_samples_inv = 1.0f / num_samples;
+
+ for (int i = 0; i < total_samples; i++) {
+ float it_add = (i / num_samples) * 0.499f;
+ float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f);
+ double dphi;
+ BLI_hammersley_1D(i, &dphi);
+
+ float phi = (float)dphi * 2.0f * M_PI + it_add;
+ texels[i][0] = cosf(phi);
+ texels[i][1] = sinf(phi);
+ /* This deliberately distribute more samples
+ * at the center of the disk (and thus the shadow). */
+ texels[i][2] = r;
+ }
+
+ return (float *)texels;
+}
+
+static struct GPUTexture *create_jitter_texture(int num_samples)
+{
+ float jitter[64 * 64][3];
+ const float num_samples_inv = 1.0f / num_samples;
+
+ for (int i = 0; i < 64 * 64; i++) {
+ float phi = blue_noise[i][0] * 2.0f * M_PI;
+ /* This rotate the sample per pixels */
+ jitter[i][0] = cosf(phi);
+ jitter[i][1] = sinf(phi);
+ /* This offset the sample along it's direction axis (reduce banding) */
+ float bn = blue_noise[i][1] - 0.5f;
+ CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
+ jitter[i][2] = bn * num_samples_inv;
+ }
+
+ UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
+
+ return DRW_texture_create_2D(64, 64, GPU_RGB16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
+}
+/* Functions */
+
+
+static void workbench_init_object_data(DrawData *dd)
+{
+ WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
+ data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
+ data->shadow_bbox_dirty = true;
+}
+
+void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+ if (!stl->effects) {
+ stl->effects = MEM_callocN(sizeof(*stl->effects), __func__);
+ workbench_effect_info_init(stl->effects);
+ }
+
+ if (!e_data.next_object_id) {
+ memset(e_data.prepass_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS);
+ memset(e_data.composite_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS);
+ e_data.next_object_id = 1;
+#ifdef DEBUG_SHADOW_VOLUME
+ const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
+#else
+ const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl;
+#endif
+ /* TODO only compile on demand */
+ e_data.shadow_pass_sh = DRW_shader_create(
+ datatoc_workbench_shadow_vert_glsl,
+ datatoc_workbench_shadow_geom_glsl,
+ shadow_frag,
+ "#define SHADOW_PASS\n"
+ "#define DOUBLE_MANIFOLD\n");
+ e_data.shadow_pass_manifold_sh = DRW_shader_create(
+ datatoc_workbench_shadow_vert_glsl,
+ datatoc_workbench_shadow_geom_glsl,
+ shadow_frag,
+ "#define SHADOW_PASS\n");
+ e_data.shadow_fail_sh = DRW_shader_create(
+ datatoc_workbench_shadow_vert_glsl,
+ datatoc_workbench_shadow_geom_glsl,
+ shadow_frag,
+ "#define SHADOW_FAIL\n"
+ "#define DOUBLE_MANIFOLD\n");
+ e_data.shadow_fail_manifold_sh = DRW_shader_create(
+ datatoc_workbench_shadow_vert_glsl,
+ datatoc_workbench_shadow_geom_glsl,
+ shadow_frag,
+ "#define SHADOW_FAIL\n");
+ e_data.shadow_caps_sh = DRW_shader_create(
+ datatoc_workbench_shadow_vert_glsl,
+ datatoc_workbench_shadow_caps_geom_glsl,
+ shadow_frag,
+ "#define SHADOW_FAIL\n"
+ "#define DOUBLE_MANIFOLD\n");
+ e_data.shadow_caps_manifold_sh = DRW_shader_create(
+ datatoc_workbench_shadow_vert_glsl,
+ datatoc_workbench_shadow_caps_geom_glsl,
+ shadow_frag,
+ "#define SHADOW_FAIL\n");
+
+ e_data.ghost_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_ghost_resolve_frag_glsl, NULL);
+ }
+ workbench_volume_engine_init();
+ workbench_fxaa_engine_init();
+ workbench_taa_engine_init(vedata);
+
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ workbench_private_data_init(wpd);
+
+ {
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+ const GPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16 : GPU_RGBA32F;
+ e_data.object_id_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R32UI, &draw_engine_workbench_solid);
+ e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid);
+ e_data.normal_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], nor_tex_format, &draw_engine_workbench_solid);
+ e_data.cavity_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R16, &draw_engine_workbench_solid);
+ e_data.specular_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid);
+ e_data.composite_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid);
+
+ GPU_framebuffer_ensure_config(&fbl->prepass_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.specular_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->cavity_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.cavity_buffer_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->composite_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->volume_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->effect_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
+ });
+ }
+
+ {
+ Scene *scene = draw_ctx->scene;
+ /* AO Samples Tex */
+ int num_iterations = workbench_taa_calculate_num_iterations(vedata);
+
+ const int ssao_samples_single_iteration = scene->display.matcap_ssao_samples;
+ const int ssao_samples = MIN2(num_iterations * ssao_samples_single_iteration, 500);
+
+ if (e_data.sampling_ubo && (e_data.cached_sample_num != ssao_samples)) {
+ DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
+ DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
+ }
+
+ if (e_data.sampling_ubo == NULL) {
+ float *samples = create_disk_samples(ssao_samples_single_iteration, num_iterations);
+ e_data.jitter_tx = create_jitter_texture(ssao_samples);
+ e_data.sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples);
+ e_data.cached_sample_num = ssao_samples;
+ MEM_freeN(samples);
+ }
+ }
+
+ /* Prepass */
+ {
+ DRWShadingGroup *grp;
+ const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->flag2 & V3D_BACKFACE_CULLING));
+
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ psl->prepass_pass = DRW_pass_create("Prepass", (do_cull) ? state | DRW_STATE_CULL_BACK : state);
+ psl->prepass_hair_pass = DRW_pass_create("Prepass", state);
+
+ psl->ghost_prepass_pass = DRW_pass_create("Prepass Ghost", (do_cull) ? state | DRW_STATE_CULL_BACK : state);
+ psl->ghost_prepass_hair_pass = DRW_pass_create("Prepass Ghost", state);
+
+ psl->ghost_resolve_pass = DRW_pass_create("Resolve Ghost Depth", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
+ grp = DRW_shgroup_create(e_data.ghost_resolve_sh, psl->ghost_resolve_pass);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.ghost_depth_tx);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+
+ {
+ workbench_aa_create_pass(vedata, &e_data.color_buffer_tx);
+ }
+
+ if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
+ int state = DRW_STATE_WRITE_COLOR;
+ GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
+ psl->cavity_pass = DRW_pass_create("Cavity", state);
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass);
+ DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
+ DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo);
+
+ if (SSAO_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx);
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+ DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1);
+ DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1);
+ DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat);
+ DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx);
+ }
+
+ if (CURVATURE_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
+ DRW_shgroup_uniform_vec2(grp, "curvature_settings", &wpd->world_data.curvature_ridge, 1);
+ }
+
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+}
+
+static void workbench_setup_ghost_framebuffer(WORKBENCH_FramebufferList *fbl)
+{
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ e_data.ghost_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_workbench_solid);
+ GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb, {
+ GPU_ATTACHMENT_TEXTURE(e_data.ghost_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.specular_buffer_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
+ });
+}
+
+void workbench_deferred_engine_free(void)
+{
+ for (int index = 0; index < MAX_SHADERS; index++) {
+ DRW_SHADER_FREE_SAFE(e_data.prepass_sh_cache[index]);
+ DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
+ }
+ for (int index = 0; index < MAX_CAVITY_SHADERS; ++index) {
+ DRW_SHADER_FREE_SAFE(e_data.cavity_sh[index]);
+ }
+ DRW_SHADER_FREE_SAFE(e_data.ghost_resolve_sh);
+ DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
+ DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
+
+ DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_fail_manifold_sh);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_caps_manifold_sh);
+
+ workbench_volume_engine_free();
+ workbench_fxaa_engine_free();
+ workbench_taa_engine_free();
+}
+
+static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp)
+{
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
+ if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
+ }
+ if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx);
+ }
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture_ref(grp, "specularBuffer", &e_data.specular_buffer_tx);
+ }
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+ }
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+
+ if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture);
+ }
+}
+
+void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ DRWShadingGroup *grp;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ Scene *scene = draw_ctx->scene;
+
+ workbench_volume_cache_init(vedata);
+
+ select_deferred_shaders(wpd);
+
+ /* Deferred Mix Pass */
+ {
+ workbench_private_data_get_light_direction(wpd, e_data.display.light_direction);
+ studiolight_update_light(wpd, e_data.display.light_direction);
+
+ e_data.display.shadow_shift = scene->display.shadow_shift;
+
+ if (SHADOW_ENABLED(wpd)) {
+ psl->composite_pass = DRW_pass_create(
+ "Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL);
+ grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
+ workbench_composite_uniforms(wpd, grp);
+ DRW_shgroup_stencil_mask(grp, 0x00);
+ DRW_shgroup_uniform_float_copy(grp, "lightMultiplier", 1.0f);
+ DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1);
+ DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+
+ /* Stencil Shadow passes. */
+#ifdef DEBUG_SHADOW_VOLUME
+ DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE;
+ DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE;
+#else
+ DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_PASS;
+ DRWState depth_fail_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL;
+#endif
+ psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Pass", depth_pass_state);
+ psl->shadow_depth_pass_mani_pass = DRW_pass_create("Shadow Pass Mani", depth_pass_state);
+ psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Fail", depth_fail_state);
+ psl->shadow_depth_fail_mani_pass = DRW_pass_create("Shadow Fail Mani", depth_fail_state);
+ psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Fail Caps", depth_fail_state);
+ psl->shadow_depth_fail_caps_mani_pass = DRW_pass_create("Shadow Fail Caps Mani", depth_fail_state);
+
+#ifndef DEBUG_SHADOW_VOLUME
+ grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+ grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, psl->shadow_depth_pass_mani_pass);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+ grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+ grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, psl->shadow_depth_fail_mani_pass);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+ grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+ grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, psl->shadow_depth_fail_caps_mani_pass);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+
+ psl->composite_shadow_pass = DRW_pass_create("Composite Shadow", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL);
+ grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_shadow_pass);
+ DRW_shgroup_stencil_mask(grp, 0x00);
+ workbench_composite_uniforms(wpd, grp);
+ DRW_shgroup_uniform_float(grp, "lightMultiplier", &wpd->shadow_multiplier, 1);
+ DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1);
+ DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+#endif
+
+ }
+ else {
+ psl->composite_pass = DRW_pass_create(
+ "Composite", DRW_STATE_WRITE_COLOR);
+ grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
+ workbench_composite_uniforms(wpd, grp);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+ }
+}
+
+static WORKBENCH_MaterialData *get_or_create_material_data(
+ WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_MaterialData *material;
+ WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
+ &ob->id, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
+ WORKBENCH_MaterialData material_template;
+ const bool is_ghost = (ob->dtx & OB_DRAWXRAY);
+
+ /* Solid */
+ workbench_material_update_data(wpd, ob, mat, &material_template);
+ material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
+ material_template.color_type = color_type;
+ material_template.ima = ima;
+ uint hash = workbench_material_get_hash(&material_template, is_ghost);
+
+ material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash));
+ if (material == NULL) {
+ material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__);
+ material->shgrp = DRW_shgroup_create(
+ (color_type == V3D_SHADING_TEXTURE_COLOR) ? wpd->prepass_texture_sh: wpd->prepass_solid_sh,
+ (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass);
+ workbench_material_copy(material, &material_template);
+ DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
+ DRW_shgroup_uniform_int(material->shgrp, "object_id", &material->object_id, 1);
+ workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob);
+
+ BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
+ }
+ return material;
+}
+
+static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ if (!psys_check_enabled(ob, psys, false)) {
+ continue;
+ }
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH) {
+ Image *image = NULL;
+ Material *mat = give_current_material(ob, part->omat);
+ ED_object_get_active_image(ob, part->omat, &image, NULL, NULL, NULL);
+ int color_type = workbench_material_determine_color_type(wpd, image, ob);
+ WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type);
+
+ struct GPUShader *shader = (color_type != V3D_SHADING_TEXTURE_COLOR) ?
+ wpd->prepass_solid_hair_sh :
+ wpd->prepass_texture_hair_sh;
+ DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
+ ob, psys, md,
+ (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass,
+ shader);
+ DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF);
+ DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob);
+ }
+ }
+}
+
+void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+
+ if (!DRW_object_is_renderable(ob))
+ return;
+
+ if (ob->type == OB_MESH) {
+ workbench_cache_populate_particles(vedata, ob);
+ }
+
+ ModifierData *md;
+ if (((ob->base_flag & BASE_FROMDUPLI) == 0) &&
+ (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
+ (((SmokeModifierData *)md)->domain != NULL))
+ {
+ workbench_volume_cache_populate(vedata, scene, ob, md);
+ return; /* Do not draw solid in this case. */
+ }
+
+ if (!DRW_object_is_visible_in_active_context(ob) || (ob->dt < OB_SOLID)) {
+ return;
+ }
+
+ WORKBENCH_MaterialData *material;
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
+ const bool is_active = (ob == draw_ctx->obact);
+ const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0;
+ const bool use_hide = is_active && DRW_object_use_hide_faces(ob);
+ bool is_drawn = false;
+ if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && ELEM(ob->type, OB_MESH)) {
+ const Mesh *me = ob->data;
+ if (me->mloopuv) {
+ const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob, use_hide) : NULL;
+ if (materials_len > 0 && geom_array) {
+ for (int i = 0; i < materials_len; i++) {
+ if (geom_array[i] == NULL) {
+ continue;
+ }
+
+ Material *mat = give_current_material(ob, i + 1);
+ Image *image;
+ ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
+ int color_type = workbench_material_determine_color_type(wpd, image, ob);
+ material = get_or_create_material_data(vedata, ob, mat, image, color_type);
+ DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob);
+ }
+ is_drawn = true;
+ }
+ }
+ }
+
+ /* Fallback from not drawn OB_TEXTURE mode or just OB_SOLID mode */
+ if (!is_drawn) {
+ if (ELEM(wpd->shading.color_type, V3D_SHADING_SINGLE_COLOR, V3D_SHADING_RANDOM_COLOR)) {
+ /* No material split needed */
+ struct GPUBatch *geom = DRW_cache_object_surface_get_ex(ob, use_hide);
+ if (geom) {
+ material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type);
+ if (is_sculpt_mode) {
+ DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_object_add(material->shgrp, geom, ob);
+ }
+ }
+ }
+ else { /* MATERIAL colors */
+ const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ for (int i = 0; i < materials_len; i++) {
+ gpumat_array[i] = NULL;
+ }
+
+ struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
+ ob, gpumat_array, materials_len, use_hide, NULL, NULL, NULL);
+ if (mat_geom) {
+ for (int i = 0; i < materials_len; ++i) {
+ if (mat_geom[i] == NULL) {
+ continue;
+ }
+
+ Material *mat = give_current_material(ob, i + 1);
+ material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR);
+ if (is_sculpt_mode) {
+ DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob);
+ }
+ }
+ }
+ }
+ }
+
+ if (SHADOW_ENABLED(wpd) && (ob->display.flag & OB_SHOW_SHADOW)) {
+ bool is_manifold;
+ struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold);
+ if (geom_shadow) {
+ if (is_sculpt_mode || use_hide) {
+ /* Currently unsupported in sculpt mode. We could revert to the slow
+ * method in this case but I'm not sure if it's a good idea given that
+ * sculpted meshes are heavy to begin with. */
+ // DRW_shgroup_call_sculpt_add(wpd->shadow_shgrp, ob, ob->obmat);
+ }
+ else {
+ WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
+ &ob->id, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
+
+ if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
+
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction);
+
+ DRWShadingGroup *grp;
+ bool use_shadow_pass_technique = !studiolight_camera_in_object_shadow(wpd, ob, engine_object_data);
+
+ if (use_shadow_pass_technique) {
+ if (is_manifold) {
+ grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, psl->shadow_depth_pass_mani_pass);
+ }
+ else {
+ grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass);
+ }
+ DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f);
+ DRW_shgroup_call_add(grp, geom_shadow, ob->obmat);
+#ifdef DEBUG_SHADOW_VOLUME
+ DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f});
+#endif
+ }
+ else {
+ float extrude_distance = studiolight_object_shadow_distance(wpd, ob, engine_object_data);
+
+ /* TODO(fclem): only use caps if they are in the view frustum. */
+ const bool need_caps = true;
+ if (need_caps) {
+ if (is_manifold) {
+ grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, psl->shadow_depth_fail_caps_mani_pass);
+ }
+ else {
+ grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass);
+ }
+ DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance);
+ DRW_shgroup_call_add(grp, DRW_cache_object_surface_get(ob), ob->obmat);
+ }
+
+ if (is_manifold) {
+ grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, psl->shadow_depth_fail_mani_pass);
+ }
+ else {
+ grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass);
+ }
+ DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance);
+ DRW_shgroup_call_add(grp, geom_shadow, ob->obmat);
+#ifdef DEBUG_SHADOW_VOLUME
+ DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
+#endif
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void workbench_deferred_cache_finish(WORKBENCH_Data *UNUSED(vedata))
+{
+}
+
+void workbench_deferred_draw_background(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ const float clear_depth = 1.0f;
+ const float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ uint clear_stencil = 0x00;
+
+ DRW_stats_group_start("Clear Background");
+ GPU_framebuffer_bind(fbl->prepass_fb);
+ int clear_bits = GPU_DEPTH_BIT | GPU_COLOR_BIT;
+ SET_FLAG_FROM_TEST(clear_bits, SHADOW_ENABLED(wpd), GPU_STENCIL_BIT);
+ GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_color, clear_depth, clear_stencil);
+ DRW_stats_group_end();
+}
+
+void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (TAA_ENABLED(wpd)) {
+ workbench_taa_draw_scene_start(vedata);
+ }
+
+ /* clear in background */
+ GPU_framebuffer_bind(fbl->prepass_fb);
+ DRW_draw_pass(psl->prepass_pass);
+ DRW_draw_pass(psl->prepass_hair_pass);
+
+ if (GHOST_ENABLED(psl)) {
+ /* meh, late init to not request a depth buffer we won't use. */
+ workbench_setup_ghost_framebuffer(fbl);
+
+ GPU_framebuffer_bind(fbl->ghost_prepass_fb);
+ GPU_framebuffer_clear_depth(fbl->ghost_prepass_fb, 1.0f);
+ DRW_draw_pass(psl->ghost_prepass_pass);
+ DRW_draw_pass(psl->ghost_prepass_hair_pass);
+
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
+ DRW_draw_pass(psl->ghost_resolve_pass);
+ }
+
+ if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
+ GPU_framebuffer_bind(fbl->cavity_fb);
+ DRW_draw_pass(psl->cavity_pass);
+ }
+
+ if (SHADOW_ENABLED(wpd)) {
+#ifdef DEBUG_SHADOW_VOLUME
+ GPU_framebuffer_bind(fbl->composite_fb);
+ DRW_draw_pass(psl->composite_pass);
+#else
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
+#endif
+ DRW_draw_pass(psl->shadow_depth_pass_pass);
+ DRW_draw_pass(psl->shadow_depth_pass_mani_pass);
+ DRW_draw_pass(psl->shadow_depth_fail_pass);
+ DRW_draw_pass(psl->shadow_depth_fail_mani_pass);
+ DRW_draw_pass(psl->shadow_depth_fail_caps_pass);
+ DRW_draw_pass(psl->shadow_depth_fail_caps_mani_pass);
+
+ if (GHOST_ENABLED(psl)) {
+ /* We need to set the stencil buffer to 0 where Ghost objects
+ * else they will get shadow and even badly shadowed. */
+ DRW_pass_state_set(psl->ghost_prepass_pass, DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL);
+ DRW_pass_state_set(psl->ghost_prepass_hair_pass, DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL);
+
+ DRW_draw_pass(psl->ghost_prepass_pass);
+ DRW_draw_pass(psl->ghost_prepass_hair_pass);
+ }
+#ifndef DEBUG_SHADOW_VOLUME
+ GPU_framebuffer_bind(fbl->composite_fb);
+ DRW_draw_pass(psl->composite_pass);
+ DRW_draw_pass(psl->composite_shadow_pass);
+#endif
+ }
+ else {
+ GPU_framebuffer_bind(fbl->composite_fb);
+ DRW_draw_pass(psl->composite_pass);
+ }
+
+ /* TODO(fclem): only enable when needed (when there is overlays). */
+ if (GHOST_ENABLED(psl)) {
+ /* In order to not draw on top of ghost objects, we clear the stencil
+ * to 0xFF and the ghost object to 0x00 and only draw overlays on top if
+ * stencil is not 0. */
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
+ GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF);
+
+ DRW_pass_state_set(psl->ghost_prepass_pass, DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL);
+ DRW_pass_state_set(psl->ghost_prepass_hair_pass, DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL);
+
+ DRW_draw_pass(psl->ghost_prepass_pass);
+ DRW_draw_pass(psl->ghost_prepass_hair_pass);
+ }
+
+ if (wpd->volumes_do) {
+ GPU_framebuffer_bind(fbl->volume_fb);
+ DRW_draw_pass(psl->volume_pass);
+ }
+
+ workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
+}
+
+void workbench_deferred_draw_finish(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+
+ workbench_private_data_free(wpd);
+ workbench_volume_smoke_textures_free(wpd);
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c
new file mode 100644
index 00000000000..deb9a517f96
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_aa.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_effect_aa.c
+ * \ingroup draw_engine
+ */
+
+#include "ED_screen.h"
+
+#include "workbench_private.h"
+
+
+void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_EffectInfo *effect_info = stl->effects;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (draw_ctx->evil_C != NULL) {
+ struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
+ wpd->is_playback = ED_screen_animation_playing(wm) != NULL;
+ }
+ else {
+ wpd->is_playback = false;
+ }
+
+ if (TAA_ENABLED(wpd)) {
+ psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx);
+ }
+ else if (FXAA_ENABLED(wpd)) {
+ psl->effect_aa_pass = workbench_fxaa_create_pass(tx);
+ effect_info->jitter_index = 0;
+ }
+ else {
+ psl->effect_aa_pass = NULL;
+ }
+}
+
+static void workspace_aa_draw_transform(GPUTexture *tx, WORKBENCH_PrivateData *wpd)
+{
+ if (DRW_state_is_image_render()) {
+ /* Linear result for render. */
+ DRW_transform_none(tx);
+ }
+ else {
+ /* Display space result for viewport. */
+ DRW_transform_to_display(tx, wpd->use_color_view_settings);
+ }
+}
+
+void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_EffectInfo *effect_info = stl->effects;
+
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ if (FXAA_ENABLED(wpd)) {
+ GPU_framebuffer_bind(fbl->effect_fb);
+ workspace_aa_draw_transform(tx, wpd);
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->effect_aa_pass);
+ }
+ else if (TAA_ENABLED(wpd)) {
+ /*
+ * when drawing the first TAA frame, we transform directly to the
+ * color_only_fb as the TAA shader is just performing a direct copy.
+ * the workbench_taa_draw_screen_end will fill the history buffer
+ * for the other iterations.
+ */
+ if (effect_info->jitter_index == 1) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ workspace_aa_draw_transform(tx, wpd);
+ }
+ else {
+ GPU_framebuffer_bind(fbl->effect_fb);
+ workspace_aa_draw_transform(tx, wpd);
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->effect_aa_pass);
+ }
+ workbench_taa_draw_scene_end(vedata);
+ }
+ else {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ workspace_aa_draw_transform(tx, wpd);
+ }
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c b/source/blender/draw/engines/workbench/workbench_effect_fxaa.c
new file mode 100644
index 00000000000..1beb35e6440
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_fxaa.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_effect_fxaa.c
+ * \ingroup draw_engine
+ */
+#include "workbench_private.h"
+
+/* *********** STATIC *********** */
+static struct {
+ struct GPUShader *effect_fxaa_sh;
+} e_data = {NULL};
+
+/* Shaders */
+extern char datatoc_common_fxaa_lib_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+extern char datatoc_workbench_effect_fxaa_frag_glsl[];
+
+/* *********** Functions *********** */
+void workbench_fxaa_engine_init(void)
+{
+ if (e_data.effect_fxaa_sh == NULL) {
+ e_data.effect_fxaa_sh = DRW_shader_create_with_lib(
+ datatoc_common_fullscreen_vert_glsl, NULL,
+ datatoc_workbench_effect_fxaa_frag_glsl,
+ datatoc_common_fxaa_lib_glsl,
+ NULL);
+ }
+}
+
+DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx)
+{
+ DRWPass *pass = DRW_pass_create("Effect FXAA", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_fxaa_sh, pass);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ return pass;
+}
+
+void workbench_fxaa_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.effect_fxaa_sh);
+}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c
new file mode 100644
index 00000000000..403338d55c4
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_taa.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_effect_taa.c
+ * \ingroup draw_engine
+ */
+
+
+#include "workbench_private.h"
+#include "BLI_jitter_2d.h"
+
+static struct {
+ struct GPUShader *effect_taa_sh;
+ float jitter_8[8][2];
+ float jitter_16[16][2];
+ float jitter_32[32][2];
+} e_data = {NULL};
+
+extern char datatoc_workbench_effect_taa_frag_glsl[];
+
+
+static void workbench_taa_jitter_init_order(float (*table)[2], int num)
+{
+ BLI_jitter_init(table, num);
+
+ /* find closest element to center */
+ int closest_index = 0;
+ float closest_squared_distance = 1.0f;
+
+ for (int index = 0; index < num; index++) {
+ const float squared_dist = SQUARE(table[index][0]) + SQUARE(table[index][1]);
+ if (squared_dist < closest_squared_distance) {
+ closest_squared_distance = squared_dist;
+ closest_index = index;
+ }
+ }
+
+ /* move jitter table so that closest sample is in center */
+ for (int index = 0; index < num; index++) {
+ sub_v2_v2(table[index], table[closest_index]);
+ mul_v2_fl(table[index], 2.0f);
+ }
+
+ /* swap center sample to the start of the table */
+ if (closest_index != 0) {
+ swap_v2_v2(table[0], table[closest_index]);
+ }
+
+ /* sort list based on furtest distance with previous */
+ for (int i = 0; i < num - 2; i++) {
+ float f_squared_dist = 0.0;
+ int f_index = i;
+ for (int j = i + 1; j < num; j++) {
+ const float squared_dist = SQUARE(table[i][0] - table[j][0]) + SQUARE(table[i][1] - table[j][1]);
+ if (squared_dist > f_squared_dist) {
+ f_squared_dist = squared_dist;
+ f_index = j;
+ }
+ }
+ swap_v2_v2(table[i + 1], table[f_index]);
+ }
+}
+
+
+static void workbench_taa_jitter_init(void)
+{
+ workbench_taa_jitter_init_order(e_data.jitter_8, 8);
+ workbench_taa_jitter_init_order(e_data.jitter_16, 16);
+ workbench_taa_jitter_init_order(e_data.jitter_32, 32);
+}
+
+int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ int result = 1;
+ if (TAA_ENABLED(wpd)) {
+ if (DRW_state_is_image_render()) {
+ const Scene *scene = DRW_context_state_get()->scene;
+ result = (scene->r.mode & R_OSA) ? scene->r.osa : 1;
+ }
+ else if (IN_RANGE_INCL(
+ wpd->user_preferences->gpu_viewport_quality,
+ GPU_VIEWPORT_QUALITY_TAA8, GPU_VIEWPORT_QUALITY_TAA16))
+ {
+ result = 8;
+ }
+ else if (IN_RANGE_INCL(
+ wpd->user_preferences->gpu_viewport_quality,
+ GPU_VIEWPORT_QUALITY_TAA16, GPU_VIEWPORT_QUALITY_TAA32))
+ {
+ result = 16;
+ }
+ else {
+ result = 32;
+ }
+ }
+ return result;
+}
+
+void workbench_taa_engine_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ if (e_data.effect_taa_sh == NULL) {
+ e_data.effect_taa_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_taa_frag_glsl, NULL);
+ workbench_taa_jitter_init();
+ }
+
+ /* reset complete drawing when navigating. */
+ if (effect_info->jitter_index != 0) {
+ if (rv3d && rv3d->rflag & RV3D_NAVIGATING) {
+ effect_info->jitter_index = 0;
+ }
+ }
+
+ if (effect_info->view_updated) {
+ effect_info->jitter_index = 0;
+ effect_info->view_updated = false;
+ }
+
+ {
+ float view[4][4];
+ float win[4][4];
+ DRW_viewport_matrix_get(view, DRW_MAT_VIEW);
+ DRW_viewport_matrix_get(win, DRW_MAT_WIN);
+ mul_m4_m4m4(effect_info->curr_mat, view, win);
+ if (!equals_m4m4(effect_info->curr_mat, effect_info->last_mat)) {
+ effect_info->jitter_index = 0;
+ }
+ }
+}
+
+void workbench_taa_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.effect_taa_sh);
+}
+
+
+DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_TextureList *txl = vedata->txl;
+ WORKBENCH_EffectInfo *effect_info = stl->effects;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ /*
+ * jitter_index is not updated yet. This will be done in during draw phase.
+ * so for now it is inversed.
+ */
+ int previous_jitter_index = effect_info->jitter_index;
+
+ {
+ DRW_texture_ensure_fullscreen_2D(&txl->history_buffer_tx, GPU_RGBA16F, 0);
+ DRW_texture_ensure_fullscreen_2D(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0);
+ }
+
+ {
+ GPU_framebuffer_ensure_config(&fbl->effect_taa_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->depth_buffer_fb, {
+ GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
+ });
+ }
+
+
+ DRWPass *pass = DRW_pass_create("Effect TAA", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_taa_sh, pass);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->history_buffer_tx);
+ DRW_shgroup_uniform_float(grp, "mixFactor", &effect_info->taa_mix_factor, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+
+ /*
+ * Set the offset for the cavity shader so every iteration different
+ * samples will be selected
+ */
+ wpd->ssao_params[3] = previous_jitter_index;
+
+ return pass;
+}
+
+void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_EffectInfo *effect_info = stl->effects;
+ const float *viewport_size = DRW_viewport_size_get();
+ int num_samples = 8;
+ float (*samples)[2];
+ float mix_factor;
+
+ num_samples = workbench_taa_calculate_num_iterations(vedata);
+ switch (num_samples) {
+ default:
+ case 8:
+ samples = e_data.jitter_8;
+ break;
+ case 16:
+ samples = e_data.jitter_16;
+ break;
+ case 32:
+ samples = e_data.jitter_32;
+ break;
+ }
+
+ mix_factor = 1.0f / (effect_info->jitter_index + 1);
+
+ const int bitmask = num_samples - 1;
+ const int jitter_index = effect_info->jitter_index;
+ const float *transform_offset = samples[jitter_index];
+ effect_info->jitter_index = (jitter_index + 1) & bitmask;
+
+ /* construct new matrices from transform delta */
+ float viewmat[4][4];
+ float persmat[4][4];
+ DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_get(persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_get(effect_info->override_winmat, DRW_MAT_WIN);
+
+ window_translate_m4(
+ effect_info->override_winmat, persmat,
+ transform_offset[0] / viewport_size[0],
+ transform_offset[1] / viewport_size[1]);
+
+ mul_m4_m4m4(effect_info->override_persmat, effect_info->override_winmat, viewmat);
+ invert_m4_m4(effect_info->override_persinv, effect_info->override_persmat);
+ invert_m4_m4(effect_info->override_wininv, effect_info->override_winmat);
+
+ DRW_viewport_matrix_override_set(effect_info->override_persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(effect_info->override_persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(effect_info->override_winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(effect_info->override_wininv, DRW_MAT_WININV);
+
+ /* weight the mix factor by the jitter index */
+ effect_info->taa_mix_factor = mix_factor;
+}
+
+void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata)
+{
+ /*
+ * If first frame than the offset is 0.0 and its depth is the depth buffer to use
+ * for the rest of the draw engines. We store it in a persistent buffer.
+ *
+ * If it is not the first frame we copy the persistent buffer back to the
+ * default depth buffer
+ */
+ const WORKBENCH_StorageList *stl = vedata->stl;
+ const WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ WORKBENCH_EffectInfo *effect_info = stl->effects;
+
+ if (effect_info->jitter_index == 1) {
+ GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->depth_buffer_fb, 0, GPU_DEPTH_BIT);
+ }
+ else {
+ GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT);
+ }
+
+ GPU_framebuffer_blit(dfbl->color_only_fb, 0, fbl->effect_taa_fb, 0, GPU_COLOR_BIT);
+
+ if (!DRW_state_is_image_render()) {
+ DRW_viewport_matrix_override_unset_all();
+ }
+
+ copy_m4_m4(effect_info->last_mat, effect_info->curr_mat);
+ if (effect_info->jitter_index != 0 && !DRW_state_is_image_render()) {
+ DRW_viewport_request_redraw();
+ }
+}
+
+void workbench_taa_view_updated(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ if (stl) {
+ WORKBENCH_EffectInfo *effect_info = stl->effects;
+ if (effect_info) {
+ effect_info->view_updated = true;
+ }
+ }
+}
diff --git a/source/blender/render/intern/include/voxeldata.h b/source/blender/draw/engines/workbench/workbench_engine.c
index 041ca78a799..180932b9b64 100644
--- a/source/blender/render/intern/include/voxeldata.h
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -1,5 +1,5 @@
/*
- * ***** BEGIN GPL LICENSE BLOCK *****
+ * Copyright 2016, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -15,33 +15,33 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
+ * Contributor(s): Blender Institute
*
- * The Original Code is: all of this file.
- *
- * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
- *
- * ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/render/intern/include/voxeldata.h
- * \ingroup render
+/** \file workbench_engine.c
+ * \ingroup draw_engine
+ *
+ * Simple engine for drawing color and/or depth.
+ * When we only need simple flat shaders.
*/
-#ifndef __VOXELDATA_H__
-#define __VOXELDATA_H__
+#include "DRW_render.h"
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
-struct Render;
-struct TexResult;
+#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
-typedef struct VoxelDataHeader {
- int resolX, resolY, resolZ;
- int frames;
-} VoxelDataHeader;
+/* Note: currently unused, we may want to register so we can see this when debugging the view. */
+RenderEngineType DRW_engine_viewport_workbench_type = {
+ NULL, NULL,
+ WORKBENCH_ENGINE, N_("Workbench"), RE_INTERNAL,
+ NULL, &DRW_render_to_image, NULL, NULL, NULL, NULL,
+ &workbench_render_update_passes,
+ &draw_engine_workbench_solid,
+ {NULL, NULL, NULL}
+};
-void cache_voxeldata(Tex *tex, int scene_frame);
-void make_voxeldata(struct Render *re);
-int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
-#endif /* __VOXELDATA_H__ */
+#undef WORKBENCH_ENGINE
diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h
new file mode 100644
index 00000000000..a7f168db093
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_engine.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_engine.h
+ * \ingroup draw_engine
+ */
+
+#ifndef __WORKBENCH_ENGINE_H__
+#define __WORKBENCH_ENGINE_H__
+
+extern DrawEngineType draw_engine_workbench_solid;
+extern DrawEngineType draw_engine_workbench_transparent;
+extern RenderEngineType DRW_engine_viewport_workbench_type;
+
+#endif /* __WORKBENCH_ENGINE_H__ */
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
new file mode 100644
index 00000000000..3a5e592fa69
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_forward.c
+ * \ingroup draw_engine
+ */
+
+#include "workbench_private.h"
+
+#include "BIF_gl.h"
+
+#include "BLI_alloca.h"
+#include "BLI_dynstr.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_node.h"
+#include "BKE_particle.h"
+#include "BKE_modifier.h"
+
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
+#include "ED_uvedit.h"
+
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "UI_resources.h"
+
+/* *********** STATIC *********** */
+static struct {
+ struct GPUShader *composite_sh_cache[MAX_SHADERS];
+ struct GPUShader *transparent_accum_sh_cache[MAX_SHADERS];
+ struct GPUShader *object_outline_sh;
+ struct GPUShader *object_outline_texture_sh;
+ struct GPUShader *object_outline_hair_sh;
+ struct GPUShader *checker_depth_sh;
+
+ struct GPUTexture *object_id_tx; /* ref only, not alloced */
+ struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */
+ struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */
+ struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
+
+ int next_object_id;
+} e_data = {{NULL}};
+
+/* Shaders */
+extern char datatoc_common_hair_lib_glsl[];
+
+extern char datatoc_workbench_forward_composite_frag_glsl[];
+extern char datatoc_workbench_forward_depth_frag_glsl[];
+extern char datatoc_workbench_forward_transparent_accum_frag_glsl[];
+extern char datatoc_workbench_data_lib_glsl[];
+extern char datatoc_workbench_background_lib_glsl[];
+extern char datatoc_workbench_checkerboard_depth_frag_glsl[];
+extern char datatoc_workbench_object_outline_lib_glsl[];
+extern char datatoc_workbench_curvature_lib_glsl[];
+extern char datatoc_workbench_prepass_vert_glsl[];
+extern char datatoc_workbench_common_lib_glsl[];
+extern char datatoc_workbench_world_light_lib_glsl[];
+
+/* static functions */
+static char *workbench_build_forward_vert(bool is_hair)
+{
+ char *str = NULL;
+ if (!is_hair) {
+ return BLI_strdup(datatoc_workbench_prepass_vert_glsl);
+ }
+
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static char *workbench_build_forward_transparent_accum_frag(void)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_forward_transparent_accum_frag_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static char *workbench_build_forward_composite_frag(void)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_background_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_forward_composite_frag_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static void workbench_init_object_data(DrawData *dd)
+{
+ WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd;
+ data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
+}
+
+static WORKBENCH_MaterialData *get_or_create_material_data(
+ WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_MaterialData *material;
+ WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure(
+ &ob->id, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
+ WORKBENCH_MaterialData material_template;
+ DRWShadingGroup *grp;
+
+ /* Solid */
+ workbench_material_update_data(wpd, ob, mat, &material_template);
+ material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
+ material_template.color_type = color_type;
+ material_template.ima = ima;
+ uint hash = workbench_material_get_hash(&material_template, false);
+
+ material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash));
+ if (material == NULL) {
+ material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__);
+
+ /* transparent accum */
+ grp = DRW_shgroup_create(
+ color_type == V3D_SHADING_TEXTURE_COLOR ? wpd->transparent_accum_texture_sh: wpd->transparent_accum_sh,
+ psl->transparent_accum_pass);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_float(grp, "alpha", &wpd->shading.xray_alpha, 1);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+ workbench_material_copy(material, &material_template);
+ if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture );
+ }
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ }
+
+ workbench_material_shgroup_uniform(wpd, grp, material, ob);
+ material->shgrp = grp;
+
+ /* Depth */
+ if (workbench_material_determine_color_type(wpd, material->ima, ob) == V3D_SHADING_TEXTURE_COLOR) {
+ material->shgrp_object_outline = DRW_shgroup_create(
+ e_data.object_outline_texture_sh, psl->object_outline_pass);
+ GPUTexture *tex = GPU_texture_from_blender(material->ima, NULL, GL_TEXTURE_2D, false, 0.0f);
+ DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex);
+ }
+ else {
+ material->shgrp_object_outline = DRW_shgroup_create(
+ e_data.object_outline_sh, psl->object_outline_pass);
+ }
+ material->object_id = engine_object_data->object_id;
+ DRW_shgroup_uniform_int(material->shgrp_object_outline, "object_id", &material->object_id, 1);
+ BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material);
+ }
+ return material;
+}
+
+static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, bool use_textures, bool is_hair)
+{
+ if (e_data.composite_sh_cache[index] == NULL && !use_textures && !is_hair) {
+ char *defines = workbench_material_build_defines(wpd, use_textures, is_hair);
+ char *composite_frag = workbench_build_forward_composite_frag();
+ e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines);
+ MEM_freeN(composite_frag);
+ MEM_freeN(defines);
+ }
+
+ if (e_data.transparent_accum_sh_cache[index] == NULL) {
+ char *defines = workbench_material_build_defines(wpd, use_textures, is_hair);
+ char *transparent_accum_vert = workbench_build_forward_vert(is_hair);
+ char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag();
+ e_data.transparent_accum_sh_cache[index] = DRW_shader_create(
+ transparent_accum_vert, NULL,
+ transparent_accum_frag, defines);
+ MEM_freeN(transparent_accum_vert);
+ MEM_freeN(transparent_accum_frag);
+ MEM_freeN(defines);
+ }
+}
+
+static void select_forward_shaders(WORKBENCH_PrivateData *wpd)
+{
+ int index_solid = workbench_material_get_shader_index(wpd, false, false);
+ int index_solid_hair = workbench_material_get_shader_index(wpd, false, true);
+ int index_texture = workbench_material_get_shader_index(wpd, true, false);
+ int index_texture_hair = workbench_material_get_shader_index(wpd, true, true);
+
+ ensure_forward_shaders(wpd, index_solid, false, false);
+ ensure_forward_shaders(wpd, index_solid_hair, false, true);
+ ensure_forward_shaders(wpd, index_texture, true, false);
+ ensure_forward_shaders(wpd, index_texture_hair, true, true);
+
+ wpd->composite_sh = e_data.composite_sh_cache[index_solid];
+ wpd->transparent_accum_sh = e_data.transparent_accum_sh_cache[index_solid];
+ wpd->transparent_accum_hair_sh = e_data.transparent_accum_sh_cache[index_solid_hair];
+ wpd->transparent_accum_texture_sh = e_data.transparent_accum_sh_cache[index_texture];
+ wpd->transparent_accum_texture_hair_sh = e_data.transparent_accum_sh_cache[index_texture_hair];
+}
+
+/* public functions */
+void workbench_forward_engine_init(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DRWShadingGroup *grp;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+ if (!stl->effects) {
+ stl->effects = MEM_callocN(sizeof(*stl->effects), __func__);
+ workbench_effect_info_init(stl->effects);
+ }
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ workbench_private_data_init(wpd);
+ float light_direction[3];
+ workbench_private_data_get_light_direction(wpd, light_direction);
+
+ if (!e_data.next_object_id) {
+ e_data.next_object_id = 1;
+ memset(e_data.composite_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS);
+ memset(e_data.transparent_accum_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS);
+
+ char *defines = workbench_material_build_defines(wpd, false, false);
+ char *defines_texture = workbench_material_build_defines(wpd, true, false);
+ char *defines_hair = workbench_material_build_defines(wpd, false, true);
+ char *forward_vert = workbench_build_forward_vert(false);
+ char *forward_hair_vert = workbench_build_forward_vert(true);
+ e_data.object_outline_sh = DRW_shader_create(
+ forward_vert, NULL,
+ datatoc_workbench_forward_depth_frag_glsl, defines);
+ e_data.object_outline_texture_sh = DRW_shader_create(
+ forward_vert, NULL,
+ datatoc_workbench_forward_depth_frag_glsl, defines_texture);
+ e_data.object_outline_hair_sh = DRW_shader_create(
+ forward_hair_vert, NULL,
+ datatoc_workbench_forward_depth_frag_glsl, defines_hair);
+
+
+ e_data.checker_depth_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_checkerboard_depth_frag_glsl, NULL);
+ MEM_freeN(forward_hair_vert);
+ MEM_freeN(forward_vert);
+ MEM_freeN(defines);
+ MEM_freeN(defines_texture);
+ MEM_freeN(defines_hair);
+ }
+ workbench_volume_engine_init();
+ workbench_fxaa_engine_init();
+ workbench_taa_engine_init(vedata);
+
+ select_forward_shaders(wpd);
+
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ e_data.object_id_tx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_R32UI, &draw_engine_workbench_transparent);
+ e_data.transparent_accum_tx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_transparent);
+ e_data.transparent_revealage_tx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_R16F, &draw_engine_workbench_transparent);
+ e_data.composite_buffer_tx = DRW_texture_pool_query_2D(
+ size[0], size[1], GPU_R11F_G11F_B10F, &draw_engine_workbench_transparent);
+
+ GPU_framebuffer_ensure_config(&fbl->object_outline_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.transparent_revealage_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->composite_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->effect_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx),
+ });
+
+ workbench_volume_cache_init(vedata);
+ const bool do_cull = (draw_ctx->v3d && (draw_ctx->v3d->flag2 & V3D_BACKFACE_CULLING));
+ const int cull_state = (do_cull) ? DRW_STATE_CULL_BACK : 0;
+
+ /* Transparency Accum */
+ {
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | cull_state;
+ psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state);
+ }
+ /* Depth */
+ {
+ int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state;
+ psl->object_outline_pass = DRW_pass_create("Object Outline Pass", state);
+ }
+ /* Composite */
+ {
+ int state = DRW_STATE_WRITE_COLOR;
+ psl->composite_pass = DRW_pass_create("Composite", state);
+
+ grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass);
+ if (OBJECT_ID_PASS_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
+ }
+ DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.transparent_accum_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.transparent_revealage_tx);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+
+ {
+ workbench_aa_create_pass(vedata, &e_data.transparent_accum_tx);
+ }
+
+ /* Checker Depth */
+ {
+ static float noise_offset = 0.0f;
+ float blend_threshold = 0.0f;
+
+ if (DRW_state_is_image_render()) {
+ /* TODO: Should be based on the number of samples used for render. */
+ noise_offset = fmodf(noise_offset + 1.0f / 8.0f, 1.0f);
+ }
+
+ if (wpd->shading.flag & XRAY_FLAG(wpd)) {
+ blend_threshold = 1.0f - XRAY_ALPHA(wpd) * 0.9f;
+ }
+
+ if (wpd->shading.type == OB_WIRE) {
+ wpd->shading.xray_alpha = 0.0f;
+ wpd->shading.xray_alpha_wire = 0.0f;
+ }
+
+ int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS;
+ psl->checker_depth_pass = DRW_pass_create("Checker Depth", state);
+ grp = DRW_shgroup_create(e_data.checker_depth_sh, psl->checker_depth_pass);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ DRW_shgroup_uniform_float_copy(grp, "threshold", blend_threshold);
+ DRW_shgroup_uniform_float_copy(grp, "offset", noise_offset);
+ }
+}
+
+void workbench_forward_engine_free()
+{
+ for (int index = 0; index < MAX_SHADERS; index++) {
+ DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
+ DRW_SHADER_FREE_SAFE(e_data.transparent_accum_sh_cache[index]);
+ }
+ DRW_SHADER_FREE_SAFE(e_data.object_outline_sh);
+ DRW_SHADER_FREE_SAFE(e_data.object_outline_texture_sh);
+ DRW_SHADER_FREE_SAFE(e_data.object_outline_hair_sh);
+ DRW_SHADER_FREE_SAFE(e_data.checker_depth_sh);
+
+ workbench_volume_engine_free();
+ workbench_fxaa_engine_free();
+ workbench_taa_engine_free();
+}
+
+void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata))
+{
+}
+
+static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ if (!psys_check_enabled(ob, psys, false)) {
+ continue;
+ }
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH) {
+ Image *image = NULL;
+ Material *mat = give_current_material(ob, part->omat);
+ ED_object_get_active_image(ob, part->omat, &image, NULL, NULL, NULL);
+ int color_type = workbench_material_determine_color_type(wpd, image, ob);
+ WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type);
+
+ struct GPUShader *shader = (color_type != V3D_SHADING_TEXTURE_COLOR)
+ ? wpd->transparent_accum_hair_sh
+ : wpd->transparent_accum_texture_hair_sh;
+ DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
+ ob, psys, md,
+ psl->transparent_accum_pass,
+ shader);
+ DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo);
+ workbench_material_shgroup_uniform(wpd, shgrp, material, ob);
+ DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+ /* Hairs have lots of layer and can rapidly become the most prominent surface.
+ * So lower their alpha artificially. */
+ float hair_alpha = XRAY_ALPHA(wpd) * 0.33f;
+ DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha);
+ if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
+ BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
+ DRW_shgroup_uniform_texture(shgrp, "matcapImage", wpd->studio_light->equirect_radiance_gputexture );
+ }
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
+ DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ }
+ shgrp = DRW_shgroup_hair_create(ob, psys, md,
+ vedata->psl->object_outline_pass,
+ e_data.object_outline_hair_sh);
+ DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1);
+ }
+ }
+}
+
+void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ const bool is_wire = (ob->dt == OB_WIRE);
+
+ if (!DRW_object_is_renderable(ob))
+ return;
+
+ if (ob->type == OB_MESH) {
+ workbench_forward_cache_populate_particles(vedata, ob);
+ }
+
+ ModifierData *md;
+ if (((ob->base_flag & BASE_FROMDUPLI) == 0) &&
+ (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
+ (((SmokeModifierData *)md)->domain != NULL))
+ {
+ workbench_volume_cache_populate(vedata, scene, ob, md);
+ return; /* Do not draw solid in this case. */
+ }
+
+ if (!DRW_object_is_visible_in_active_context(ob) || (ob->dt < OB_WIRE)) {
+ return;
+ }
+
+ WORKBENCH_MaterialData *material;
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
+ const bool is_active = (ob == draw_ctx->obact);
+ const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0;
+ const bool use_hide = is_active && DRW_object_use_hide_faces(ob);
+ bool is_drawn = false;
+
+ if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && ELEM(ob->type, OB_MESH)) {
+ const Mesh *me = ob->data;
+ if (me->mloopuv) {
+ const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob, use_hide) : NULL;
+ if (materials_len > 0 && geom_array) {
+ for (int i = 0; i < materials_len; i++) {
+ if (geom_array[i] == NULL) {
+ continue;
+ }
+
+ Material *mat = give_current_material(ob, i + 1);
+ Image *image;
+ ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
+ /* use OB_SOLID when no texture could be determined */
+
+ int color_type = wpd->shading.color_type;
+ if (color_type == V3D_SHADING_TEXTURE_COLOR) {
+ /* use OB_SOLID when no texture could be determined */
+ if (image == NULL) {
+ color_type = V3D_SHADING_MATERIAL_COLOR;
+ }
+ }
+
+ material = get_or_create_material_data(vedata, ob, mat, image, color_type);
+ DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_array[i], ob);
+ DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob);
+ }
+ is_drawn = true;
+ }
+ }
+ }
+
+ /* Fallback from not drawn OB_TEXTURE mode or just OB_SOLID mode */
+ if (!is_drawn) {
+ if (ELEM(wpd->shading.color_type, V3D_SHADING_SINGLE_COLOR, V3D_SHADING_RANDOM_COLOR)) {
+ /* No material split needed */
+ struct GPUBatch *geom = DRW_cache_object_surface_get_ex(ob, use_hide);
+ if (geom) {
+ material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type);
+ if (is_sculpt_mode) {
+ DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat);
+ if (!is_wire) {
+ DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
+ }
+ }
+ else {
+ DRW_shgroup_call_object_add(material->shgrp_object_outline, geom, ob);
+ if (!is_wire) {
+ DRW_shgroup_call_object_add(material->shgrp, geom, ob);
+ }
+ }
+ }
+ }
+ else {
+ const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ for (int i = 0; i < materials_len; i++) {
+ gpumat_array[i] = NULL;
+ }
+
+ struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
+ ob, gpumat_array, materials_len, use_hide, NULL, NULL, NULL);
+ if (mat_geom) {
+ for (int i = 0; i < materials_len; ++i) {
+ if (mat_geom[i] == NULL) {
+ continue;
+ }
+
+ Material *mat = give_current_material(ob, i + 1);
+ material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR);
+ if (is_sculpt_mode) {
+ DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat);
+ if (!is_wire) {
+ DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
+ }
+ }
+ else {
+ DRW_shgroup_call_object_add(material->shgrp_object_outline, mat_geom[i], ob);
+ if (!is_wire) {
+ DRW_shgroup_call_object_add(material->shgrp, mat_geom[i], ob);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void workbench_forward_cache_finish(WORKBENCH_Data *UNUSED(vedata))
+{
+}
+
+void workbench_forward_draw_background(WORKBENCH_Data *UNUSED(vedata))
+{
+ const float clear_depth = 1.0f;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DRW_stats_group_start("Clear depth");
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear_depth(dfbl->default_fb, clear_depth);
+ DRW_stats_group_end();
+}
+
+void workbench_forward_draw_scene(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (TAA_ENABLED(wpd)) {
+ workbench_taa_draw_scene_start(vedata);
+ }
+
+ /* Write Depth + Object ID */
+ const float clear_outline[4] = {0.0f};
+ GPU_framebuffer_bind(fbl->object_outline_fb);
+ GPU_framebuffer_clear_color(fbl->object_outline_fb, clear_outline);
+ DRW_draw_pass(psl->object_outline_pass);
+
+ if (XRAY_ALPHA(wpd) > 0.0) {
+ const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ GPU_framebuffer_bind(fbl->transparent_accum_fb);
+ GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
+ DRW_draw_pass(psl->transparent_accum_pass);
+ }
+ else {
+ /* TODO(fclem): this is unnecessary and takes up perf.
+ * Better change the composite frag shader to not use the tx. */
+ const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ GPU_framebuffer_bind(fbl->transparent_accum_fb);
+ GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color);
+ }
+
+ /* Composite */
+ GPU_framebuffer_bind(fbl->composite_fb);
+ DRW_draw_pass(psl->composite_pass);
+ DRW_draw_pass(psl->volume_pass);
+
+ /* Color correct and Anti aliasing */
+ workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
+
+ /* Apply checker pattern */
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
+ DRW_draw_pass(psl->checker_depth_pass);
+}
+
+void workbench_forward_draw_finish(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+
+ workbench_private_data_free(wpd);
+ workbench_volume_smoke_textures_free(wpd);
+}
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
new file mode 100644
index 00000000000..19fb8efb812
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -0,0 +1,177 @@
+
+
+#include "workbench_private.h"
+
+#include "BIF_gl.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_hash.h"
+
+#define HSV_SATURATION 0.5
+#define HSV_VALUE 0.8
+
+void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, WORKBENCH_MaterialData *data)
+{
+ /* When V3D_SHADING_TEXTURE_COLOR is active, use V3D_SHADING_MATERIAL_COLOR as fallback when no texture could be determined */
+ int color_type = wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR ? V3D_SHADING_MATERIAL_COLOR : wpd->shading.color_type;
+ copy_v4_fl4(data->diffuse_color, 0.8f, 0.8f, 0.8f, 1.0f);
+ copy_v4_fl4(data->specular_color, 0.05f, 0.05f, 0.05f, 1.0f); /* Dielectric: 5% reflective. */
+ data->roughness = 0.5; /* sqrtf(0.25f); */
+
+ if (color_type == V3D_SHADING_SINGLE_COLOR) {
+ copy_v3_v3(data->diffuse_color, wpd->shading.single_color);
+ }
+ else if (color_type == V3D_SHADING_RANDOM_COLOR) {
+ uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
+ if (ob->id.lib) {
+ hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
+ }
+
+ float hue = BLI_hash_int_01(hash);
+ float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
+ hsv_to_rgb_v(hsv, data->diffuse_color);
+ }
+ else {
+ /* V3D_SHADING_MATERIAL_COLOR */
+ if (mat) {
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
+ mul_v3_v3fl(data->diffuse_color, &mat->r, 1.0f - mat->metallic);
+ mul_v3_v3fl(data->specular_color, &mat->r, mat->metallic);
+ add_v3_fl(data->specular_color, 0.05f * (1.0f - mat->metallic));
+ data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */
+ }
+ else {
+ copy_v3_v3(data->diffuse_color, &mat->r);
+ }
+ }
+ }
+}
+
+char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) {
+ BLI_dynstr_appendf(ds, "#define V3D_SHADING_OBJECT_OUTLINE\n");
+ }
+ if (wpd->shading.flag & V3D_SHADING_SHADOW) {
+ BLI_dynstr_appendf(ds, "#define V3D_SHADING_SHADOW\n");
+ }
+ if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define WB_CAVITY\n");
+ }
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n");
+ }
+ if (STUDIOLIGHT_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_STUDIO\n");
+ }
+ if (FLAT_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_FLAT\n");
+ }
+ if (MATCAP_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_MATCAP\n");
+ }
+ if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n");
+ }
+ if (use_textures) {
+ BLI_dynstr_appendf(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
+ }
+ if (NORMAL_ENCODING_ENABLED()) {
+ BLI_dynstr_appendf(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
+ }
+ if (is_hair) {
+ BLI_dynstr_appendf(ds, "#define HAIR_SHADER\n");
+ }
+
+ BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_SH_BANDS %d\n", STUDIOLIGHT_SH_BANDS);
+ BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_SH_MAX_COMPONENTS %d\n", WORKBENCH_SH_DATA_LEN);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost)
+{
+ uint input[4];
+ uint result;
+ float *color = material_template->diffuse_color;
+ input[0] = (uint)(color[0] * 512);
+ input[1] = (uint)(color[1] * 512);
+ input[2] = (uint)(color[2] * 512);
+ input[3] = material_template->object_id;
+ result = BLI_ghashutil_uinthash_v4_murmur(input);
+
+ color = material_template->specular_color;
+ input[0] = (uint)(color[0] * 512);
+ input[1] = (uint)(color[1] * 512);
+ input[2] = (uint)(color[2] * 512);
+ input[3] = (uint)(material_template->roughness * 512);
+ result += BLI_ghashutil_uinthash_v4_murmur(input);
+
+ result += BLI_ghashutil_uinthash((uint)is_ghost);
+
+ /* add texture reference */
+ if (material_template->ima) {
+ result += BLI_ghashutil_inthash_p_murmur(material_template->ima);
+ }
+
+ return result;
+}
+
+int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair)
+{
+ /* NOTE: change MAX_SHADERS accordingly when modifying this function. */
+ int index = 0;
+ /* 1 bit V3D_SHADING_TEXTURE_COLOR */
+ SET_FLAG_FROM_TEST(index, use_textures, 1 << 0);
+ /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */
+ int ligh_flag = SPECULAR_HIGHLIGHT_ENABLED(wpd) ? 3 : wpd->shading.light;
+ SET_FLAG_FROM_TEST(index, wpd->shading.light, ligh_flag << 1);
+ /* 3 bits for flags */
+ SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 3);
+ SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 4);
+ SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 5);
+ /* 1 bit for hair */
+ SET_FLAG_FROM_TEST(index, is_hair, 1 << 6);
+ return index;
+}
+
+int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *ima, Object *ob)
+{
+ int color_type = wpd->shading.color_type;
+ if ((color_type == V3D_SHADING_TEXTURE_COLOR && ima == NULL) || (ob->dt < OB_TEXTURE)) {
+ color_type = V3D_SHADING_MATERIAL_COLOR;
+ }
+ return color_type;
+}
+
+void workbench_material_shgroup_uniform(
+ WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob)
+{
+ if (workbench_material_determine_color_type(wpd, material->ima, ob) == V3D_SHADING_TEXTURE_COLOR) {
+ GPUTexture *tex = GPU_texture_from_blender(material->ima, NULL, GL_TEXTURE_2D, false, 0.0f);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ }
+ else {
+ DRW_shgroup_uniform_vec4(grp, "materialDiffuseColor", material->diffuse_color, 1);
+ }
+
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
+ DRW_shgroup_uniform_vec4(grp, "materialSpecularColor", material->specular_color, 1);
+ DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1);
+ }
+}
+
+void workbench_material_copy(WORKBENCH_MaterialData *dest_material, const WORKBENCH_MaterialData *source_material)
+{
+ dest_material->object_id = source_material->object_id;
+ copy_v4_v4(dest_material->diffuse_color, source_material->diffuse_color);
+ copy_v4_v4(dest_material->specular_color, source_material->specular_color);
+ dest_material->roughness = source_material->roughness;
+ dest_material->ima = source_material->ima;
+}
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
new file mode 100644
index 00000000000..0e27ed2ed53
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_private.h
+ * \ingroup draw_engine
+ */
+
+#ifndef __WORKBENCH_PRIVATE_H__
+#define __WORKBENCH_PRIVATE_H__
+
+
+#include "BKE_studiolight.h"
+
+#include "DNA_image_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_userdef_types.h"
+
+#include "DRW_render.h"
+
+#include "workbench_engine.h"
+
+#define WORKBENCH_ENGINE "BLENDER_WORKBENCH"
+#define M_GOLDEN_RATION_CONJUGATE 0.618033988749895
+#define MAX_SHADERS (1 << 7)
+#define MAX_CAVITY_SHADERS (1 << 3)
+
+#define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type & V3D_SHADING_TEXTURE_COLOR)
+#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT)
+#define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO)
+#define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP)
+#define USE_WORLD_ORIENTATION(wpd) ((wpd->shading.flag & V3D_SHADING_WORLD_ORIENTATION) != 0)
+#define STUDIOLIGHT_TYPE_WORLD_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_TYPE_WORLD))
+#define STUDIOLIGHT_TYPE_STUDIO_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_TYPE_STUDIO))
+#define STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd) (MATCAP_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_TYPE_MATCAP))
+#define SSAO_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_CAVITY) && ((wpd->shading.cavity_type == V3D_SHADING_CAVITY_SSAO) || (wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH)))
+#define CURVATURE_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_CAVITY) && ((wpd->shading.cavity_type == V3D_SHADING_CAVITY_CURVATURE) || (wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH)))
+#define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW)
+#define GHOST_ENABLED(psl) (!DRW_pass_is_empty(psl->ghost_prepass_pass) || !DRW_pass_is_empty(psl->ghost_prepass_hair_pass))
+
+#define IS_NAVIGATING(wpd) ((DRW_context_state_get()->rv3d) && (DRW_context_state_get()->rv3d->rflag & RV3D_NAVIGATING))
+#define FXAA_ENABLED(wpd) ((!DRW_state_is_opengl_render()) && \
+ (IN_RANGE(wpd->user_preferences->gpu_viewport_quality, GPU_VIEWPORT_QUALITY_FXAA, GPU_VIEWPORT_QUALITY_TAA8) || \
+ ((IS_NAVIGATING(wpd) || wpd->is_playback) && (wpd->user_preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8))))
+#define TAA_ENABLED(wpd) (DRW_state_is_image_render() || (wpd->user_preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8 && !IS_NAVIGATING(wpd) && !wpd->is_playback))
+#define SPECULAR_HIGHLIGHT_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && (!STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)))
+#define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
+#define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
+#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd))
+#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd))
+#define NORMAL_ENCODING_ENABLED() (true)
+
+
+struct RenderEngine;
+struct RenderLayer;
+struct rcti;
+
+
+typedef struct WORKBENCH_FramebufferList {
+ /* Deferred render buffers */
+ struct GPUFrameBuffer *prepass_fb;
+ struct GPUFrameBuffer *ghost_prepass_fb;
+ struct GPUFrameBuffer *cavity_fb;
+ struct GPUFrameBuffer *composite_fb;
+
+ struct GPUFrameBuffer *effect_fb;
+ struct GPUFrameBuffer *effect_taa_fb;
+ struct GPUFrameBuffer *depth_buffer_fb;
+ struct GPUFrameBuffer *volume_fb;
+
+ /* Forward render buffers */
+ struct GPUFrameBuffer *object_outline_fb;
+ struct GPUFrameBuffer *transparent_accum_fb;
+ struct GPUFrameBuffer *transparent_revealage_fb;
+} WORKBENCH_FramebufferList;
+
+typedef struct WORKBENCH_TextureList {
+ struct GPUTexture *history_buffer_tx;
+ struct GPUTexture *depth_buffer_tx;
+} WORKBENCH_TextureList;
+
+typedef struct WORKBENCH_StorageList {
+ struct WORKBENCH_PrivateData *g_data;
+ struct WORKBENCH_EffectInfo *effects;
+} WORKBENCH_StorageList;
+
+typedef struct WORKBENCH_PassList {
+ /* deferred rendering */
+ struct DRWPass *prepass_pass;
+ struct DRWPass *prepass_hair_pass;
+ struct DRWPass *ghost_prepass_pass;
+ struct DRWPass *ghost_prepass_hair_pass;
+ struct DRWPass *cavity_pass;
+ struct DRWPass *shadow_depth_pass_pass;
+ struct DRWPass *shadow_depth_pass_mani_pass;
+ struct DRWPass *shadow_depth_fail_pass;
+ struct DRWPass *shadow_depth_fail_mani_pass;
+ struct DRWPass *shadow_depth_fail_caps_pass;
+ struct DRWPass *shadow_depth_fail_caps_mani_pass;
+ struct DRWPass *composite_pass;
+ struct DRWPass *composite_shadow_pass;
+ struct DRWPass *ghost_resolve_pass;
+ struct DRWPass *effect_aa_pass;
+ struct DRWPass *volume_pass;
+
+ /* forward rendering */
+ struct DRWPass *transparent_accum_pass;
+ struct DRWPass *object_outline_pass;
+ struct DRWPass *depth_pass;
+ struct DRWPass *checker_depth_pass;
+} WORKBENCH_PassList;
+
+typedef struct WORKBENCH_Data {
+ void *engine_type;
+ WORKBENCH_FramebufferList *fbl;
+ WORKBENCH_TextureList *txl;
+ WORKBENCH_PassList *psl;
+ WORKBENCH_StorageList *stl;
+} WORKBENCH_Data;
+
+typedef struct WORKBENCH_UBO_Light {
+ float light_direction[4];
+ float specular_color[3], pad;
+ float diffuse_color[3], wrapped;
+} WORKBENCH_UBO_Light;
+
+#define WORKBENCH_SH_DATA_LEN ((STUDIOLIGHT_SH_BANDS == 2) ? 6 : STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN)
+
+typedef struct WORKBENCH_UBO_World {
+ float spherical_harmonics_coefs[WORKBENCH_SH_DATA_LEN][4];
+ float background_color_low[4];
+ float background_color_high[4];
+ float object_outline_color[4];
+ float shadow_direction_vs[4];
+ WORKBENCH_UBO_Light lights[4];
+ float ambient_color[4];
+ int num_lights;
+ int matcap_orientation;
+ float background_alpha;
+ float curvature_ridge;
+ float curvature_valley;
+ int pad[3];
+} WORKBENCH_UBO_World;
+BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16)
+
+
+typedef struct WORKBENCH_PrivateData {
+ struct GHash *material_hash;
+ struct GPUShader *prepass_solid_sh;
+ struct GPUShader *prepass_solid_hair_sh;
+ struct GPUShader *prepass_texture_sh;
+ struct GPUShader *prepass_texture_hair_sh;
+ struct GPUShader *composite_sh;
+ struct GPUShader *transparent_accum_sh;
+ struct GPUShader *transparent_accum_hair_sh;
+ struct GPUShader *transparent_accum_texture_sh;
+ struct GPUShader *transparent_accum_texture_hair_sh;
+ View3DShading shading;
+ StudioLight *studio_light;
+ UserDef *user_preferences;
+ struct GPUUniformBuffer *world_ubo;
+ struct DRWShadingGroup *shadow_shgrp;
+ struct DRWShadingGroup *depth_shgrp;
+ WORKBENCH_UBO_World world_data;
+ float shadow_multiplier;
+ float cached_shadow_direction[3];
+ float shadow_mat[4][4];
+ float shadow_inv[4][4];
+ float shadow_far_plane[4]; /* Far plane of the view frustum. */
+ float shadow_near_corners[4][3]; /* Near plane corners in shadow space. */
+ float shadow_near_min[3]; /* min and max of shadow_near_corners. allow fast test */
+ float shadow_near_max[3];
+ float shadow_near_sides[2][4]; /* This is a parallelogram, so only 2 normal and distance to the edges. */
+ bool shadow_changed;
+ bool is_playback;
+
+ /* Volumes */
+ bool volumes_do;
+ ListBase smoke_domains;
+
+ /* Ssao */
+ float winmat[4][4];
+ float viewvecs[3][4];
+ float ssao_params[4];
+ float ssao_settings[4];
+
+ /* Color Management */
+ bool use_color_view_settings;
+} WORKBENCH_PrivateData; /* Transient data */
+
+typedef struct WORKBENCH_EffectInfo {
+ float override_persmat[4][4];
+ float override_persinv[4][4];
+ float override_winmat[4][4];
+ float override_wininv[4][4];
+ float last_mat[4][4];
+ float curr_mat[4][4];
+ int jitter_index;
+ float taa_mix_factor;
+ bool view_updated;
+} WORKBENCH_EffectInfo;
+
+typedef struct WORKBENCH_MaterialData {
+ float diffuse_color[4];
+ float specular_color[4];
+ float roughness;
+ int object_id;
+ int color_type;
+ Image *ima;
+
+ /* Linked shgroup for drawing */
+ DRWShadingGroup *shgrp;
+ /* forward rendering */
+ DRWShadingGroup *shgrp_object_outline;
+} WORKBENCH_MaterialData;
+
+typedef struct WORKBENCH_ObjectData {
+ DrawData dd;
+
+ /* Shadow direction in local object space. */
+ float shadow_dir[3], shadow_depth;
+ float shadow_min[3], shadow_max[3]; /* Min, max in shadow space */
+ BoundBox shadow_bbox;
+ bool shadow_bbox_dirty;
+
+ int object_id;
+} WORKBENCH_ObjectData;
+
+/* workbench_engine.c */
+void workbench_solid_materials_init(WORKBENCH_Data *vedata);
+void workbench_solid_materials_cache_init(WORKBENCH_Data *vedata);
+void workbench_solid_materials_cache_populate(WORKBENCH_Data *vedata, Object *ob);
+void workbench_solid_materials_cache_finish(WORKBENCH_Data *vedata);
+void workbench_solid_materials_draw_scene(WORKBENCH_Data *vedata);
+void workbench_solid_materials_free(void);
+
+/* workbench_deferred.c */
+void workbench_deferred_engine_init(WORKBENCH_Data *vedata);
+void workbench_deferred_engine_free(void);
+void workbench_deferred_draw_background(WORKBENCH_Data *vedata);
+void workbench_deferred_draw_scene(WORKBENCH_Data *vedata);
+void workbench_deferred_draw_finish(WORKBENCH_Data *vedata);
+void workbench_deferred_cache_init(WORKBENCH_Data *vedata);
+void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob);
+void workbench_deferred_cache_finish(WORKBENCH_Data *vedata);
+
+/* workbench_forward.c */
+void workbench_forward_engine_init(WORKBENCH_Data *vedata);
+void workbench_forward_engine_free(void);
+void workbench_forward_draw_background(WORKBENCH_Data *vedata);
+void workbench_forward_draw_scene(WORKBENCH_Data *vedata);
+void workbench_forward_draw_finish(WORKBENCH_Data *vedata);
+void workbench_forward_cache_init(WORKBENCH_Data *vedata);
+void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob);
+void workbench_forward_cache_finish(WORKBENCH_Data *vedata);
+
+/* workbench_effect_aa.c */
+void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx);
+void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx);
+
+/* workbench_effect_fxaa.c */
+void workbench_fxaa_engine_init(void);
+void workbench_fxaa_engine_free(void);
+DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx);
+
+/* workbench_effect_taa.c */
+void workbench_taa_engine_init(WORKBENCH_Data *vedata);
+void workbench_taa_engine_free(void);
+DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx);
+void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata);
+void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata);
+void workbench_taa_view_updated(WORKBENCH_Data *vedata);
+int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata);
+
+/* workbench_materials.c */
+int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *ima, Object *ob);
+char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair);
+void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, WORKBENCH_MaterialData *data);
+uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost);
+int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair);
+void workbench_material_shgroup_uniform(
+ WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material, Object *ob);
+void workbench_material_copy(WORKBENCH_MaterialData *dest_material, const WORKBENCH_MaterialData *source_material);
+
+/* workbench_studiolight.c */
+void studiolight_update_world(WORKBENCH_PrivateData *wpd, StudioLight *sl, WORKBENCH_UBO_World *wd);
+void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]);
+bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed);
+float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed);
+bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed);
+
+/* workbench_data.c */
+void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info);
+void workbench_private_data_init(WORKBENCH_PrivateData *wpd);
+void workbench_private_data_free(WORKBENCH_PrivateData *wpd);
+void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, float r_light_direction[3]);
+
+/* workbench_volume.c */
+void workbench_volume_engine_init(void);
+void workbench_volume_engine_free(void);
+void workbench_volume_cache_init(WORKBENCH_Data *vedata);
+void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Object *ob, struct ModifierData *md);
+void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd);
+
+/* workbench_render.c */
+void workbench_render(WORKBENCH_Data *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect);
+void workbench_render_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer);
+
+#endif
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
new file mode 100644
index 00000000000..e8d525585f4
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_render.c
+ * \ingroup draw_engine
+ *
+ * Render functions for final render output.
+ */
+
+#include "BLI_rect.h"
+
+#include "BKE_report.h"
+
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RE_pipeline.h"
+
+#include "workbench_private.h"
+
+static void workbench_render_deferred_cache(
+ void *vedata, struct Object *ob,
+ struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph))
+{
+ workbench_deferred_solid_cache_populate(vedata, ob);
+}
+
+static void workbench_render_forward_cache(
+ void *vedata, struct Object *ob,
+ struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph))
+{
+ workbench_forward_cache_populate(vedata, ob);
+}
+
+static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph)
+{
+ /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
+ float frame = BKE_scene_frame_get(scene);
+
+ /* Set the persective, view and window matrix. */
+ float winmat[4][4], wininv[4][4];
+ float viewmat[4][4], viewinv[4][4];
+ float persmat[4][4], persinv[4][4];
+
+ RE_GetCameraWindow(engine->re, ob_camera_eval, frame, winmat);
+ RE_GetCameraModelMatrix(engine->re, ob_camera_eval, viewinv);
+
+ invert_m4_m4(viewmat, viewinv);
+ mul_m4_m4m4(persmat, winmat, viewmat);
+ invert_m4_m4(persinv, persmat);
+ invert_m4_m4(wininv, winmat);
+
+ DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS);
+ DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV);
+ DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV);
+ DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV);
+}
+
+static bool workbench_render_framebuffers_init(void)
+{
+ /* For image render, allocate own buffers because we don't have a viewport. */
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ dtxl->color = GPU_texture_create_2D(size[0], size[1], GPU_RGBA8, NULL, NULL);
+ dtxl->depth = GPU_texture_create_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, NULL, NULL);
+
+ if (!(dtxl->depth && dtxl->color)) {
+ return false;
+ }
+
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ GPU_framebuffer_ensure_config(&dfbl->default_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color)
+ });
+
+ GPU_framebuffer_ensure_config(&dfbl->depth_only_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_NONE
+ });
+
+ GPU_framebuffer_ensure_config(&dfbl->color_only_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(dtxl->color)
+ });
+
+ bool ok = true;
+ ok = ok && GPU_framebuffer_check_valid(dfbl->default_fb, NULL);
+ ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL);
+ ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL);
+
+ return ok;
+}
+
+static void workbench_render_framebuffers_finish(void)
+{
+}
+
+void workbench_render(WORKBENCH_Data *data, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ Depsgraph *depsgraph = draw_ctx->depsgraph;
+ workbench_render_matrices_init(engine, depsgraph);
+
+ if (!workbench_render_framebuffers_init()) {
+ RE_engine_report(engine, RPT_ERROR, "Failed to allocate OpenGL buffers");
+ return;
+ }
+
+ const bool deferred = (scene->display.shading.flag & XRAY_FLAG(&scene->display)) == 0;
+
+ if (deferred) {
+ /* Init engine. */
+ workbench_deferred_engine_init(data);
+
+ /* Init objects. */
+ workbench_deferred_cache_init(data);
+ DRW_render_object_iter(data, engine, depsgraph, workbench_render_deferred_cache);
+ workbench_deferred_cache_finish(data);
+ DRW_render_instance_buffer_finish();
+
+ /* Draw. */
+ int num_samples = workbench_taa_calculate_num_iterations(data);
+ for (int sample = 0; sample < num_samples; sample++) {
+ if (RE_engine_test_break(engine)) {
+ break;
+ }
+ /* TODO: Save matrices instead of recomputing them for each samples. */
+ workbench_render_matrices_init(engine, depsgraph);
+
+ workbench_deferred_draw_background(data);
+ workbench_deferred_draw_scene(data);
+ }
+
+ workbench_deferred_draw_finish(data);
+ }
+ else {
+ /* Init engine. */
+ workbench_forward_engine_init(data);
+
+ /* Init objects. */
+ workbench_forward_cache_init(data);
+ DRW_render_object_iter(data, engine, depsgraph, workbench_render_forward_cache);
+ workbench_forward_cache_finish(data);
+ DRW_render_instance_buffer_finish();
+
+ /* Draw. */
+ int num_samples = workbench_taa_calculate_num_iterations(data);
+ for (int sample = 0; sample < num_samples; sample++) {
+ if (RE_engine_test_break(engine)) {
+ break;
+ }
+
+ workbench_forward_draw_background(data);
+ workbench_forward_draw_scene(data);
+ }
+
+ workbench_forward_draw_finish(data);
+ }
+
+ /* Write render output. */
+ const char *viewname = RE_GetActiveRenderView(engine->re);
+ RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
+
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ GPU_framebuffer_read_color(dfbl->color_only_fb,
+ rect->xmin, rect->ymin,
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect),
+ 4, 0, rp->rect);
+
+ workbench_render_framebuffers_finish();
+}
+
+void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
+{
+ RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
+}
diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c
new file mode 100644
index 00000000000..7b348cfd8ec
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_studiolight.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_studiolight.c
+ * \ingroup draw_engine
+ */
+#include "BKE_studiolight.h"
+
+#include "DRW_engine.h"
+#include "workbench_private.h"
+
+#include "BKE_object.h"
+
+#include "BLI_math.h"
+#include "BKE_global.h"
+
+void studiolight_update_world(WORKBENCH_PrivateData *wpd, StudioLight *studiolight, WORKBENCH_UBO_World *wd)
+{
+ float view_matrix[4][4], rot_matrix[4][4];
+ DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW);
+
+ if (USE_WORLD_ORIENTATION(wpd)) {
+ axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z);
+ mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix);
+ swap_v3_v3(rot_matrix[2], rot_matrix[1]);
+ negate_v3(rot_matrix[2]);
+ }
+ else {
+ unit_m4(rot_matrix);
+ }
+
+ if (U.edit_solid_light) {
+ studiolight = BKE_studiolight_studio_edit_get();
+ }
+
+ /* Studio Lights. */
+ for (int i = 0; i < 4; i++) {
+ WORKBENCH_UBO_Light *light = &wd->lights[i];
+ /* TODO use 4 lights in studiolights prefs. */
+ if (i > 2) {
+ copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
+ copy_v3_fl(light->specular_color, 0.0f);
+ copy_v3_fl(light->diffuse_color, 0.0f);
+ continue;
+ }
+
+ SolidLight *sl = &studiolight->light[i];
+ if (sl->flag) {
+ copy_v3_v3(light->light_direction, sl->vec);
+ mul_mat3_m4_v3(rot_matrix, light->light_direction);
+ /* We should predivide the power by PI but that makes the lights really dim. */
+ copy_v3_v3(light->specular_color, sl->spec);
+ copy_v3_v3(light->diffuse_color, sl->col);
+ light->wrapped = sl->smooth;
+ }
+ else {
+ copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
+ copy_v3_fl(light->specular_color, 0.0f);
+ copy_v3_fl(light->diffuse_color, 0.0f);
+ }
+ }
+
+ copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
+
+#if 0
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
+
+#if STUDIOLIGHT_SH_BANDS == 2
+ /* Use Geomerics non-linear SH. */
+ mul_v3_v3fl(wd->spherical_harmonics_coefs[0], sl->spherical_harmonics_coefs[0], M_1_PI);
+ /* Swizzle to make shader code simpler. */
+ for (int i = 0; i < 3; ++i) {
+ copy_v3_fl3(
+ wd->spherical_harmonics_coefs[i + 1],
+ -sl->spherical_harmonics_coefs[3][i],
+ sl->spherical_harmonics_coefs[2][i],
+ -sl->spherical_harmonics_coefs[1][i]);
+ mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], M_1_PI * 1.5f); /* 1.5f is to improve the contrast a bit. */
+ }
+
+ /* Precompute as much as we can. See shader code for derivation. */
+ float len_r1[3], lr1_r0[3], p[3], a[3];
+ for (int i = 0; i < 3; ++i) {
+ mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], 0.5f);
+ len_r1[i] = len_v3(wd->spherical_harmonics_coefs[i + 1]);
+ mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], 1.0f / len_r1[i]);
+ }
+ /* lr1_r0 = lenR1 / R0; */
+ copy_v3_v3(lr1_r0, wd->spherical_harmonics_coefs[0]);
+ invert_v3(lr1_r0);
+ mul_v3_v3(lr1_r0, len_r1);
+ /* p = 1.0 + 2.0 * lr1_r0; */
+ copy_v3_v3(p, lr1_r0);
+ mul_v3_fl(p, 2.0f);
+ add_v3_fl(p, 1.0f);
+ /* a = (1.0 - lr1_r0) / (1.0 + lr1_r0); */
+ copy_v3_v3(a, lr1_r0);
+ add_v3_fl(a, 1.0f);
+ invert_v3(a);
+ negate_v3(lr1_r0);
+ add_v3_fl(lr1_r0, 1.0f);
+ mul_v3_v3(a, lr1_r0);
+ /* sh_coefs[4] = p; */
+ copy_v3_v3(wd->spherical_harmonics_coefs[4], p);
+ /* sh_coefs[5] = R0 * a; */
+ mul_v3_v3v3(wd->spherical_harmonics_coefs[5], wd->spherical_harmonics_coefs[0], a);
+ /* sh_coefs[0] = R0 * (1.0 - a) * (p + 1.0); */
+ negate_v3(a);
+ add_v3_fl(a, 1.0f);
+ add_v3_fl(p, 1.0f);
+ mul_v3_v3(a, p);
+ mul_v3_v3(wd->spherical_harmonics_coefs[0], a);
+#else
+ for (int i = 0; i < STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN; i++) {
+ /* Can't memcpy because of alignment */
+ copy_v3_v3(wd->spherical_harmonics_coefs[i], sl->spherical_harmonics_coefs[i]);
+ }
+#endif
+#endif
+}
+
+static void compute_parallel_lines_nor_and_dist(const float v1[2], const float v2[2], const float v3[2], float r_line[2])
+{
+ sub_v2_v2v2(r_line, v2, v1);
+ /* Find orthogonal vector. */
+ SWAP(float, r_line[0], r_line[1]);
+ r_line[0] = -r_line[0];
+ /* Edge distances. */
+ r_line[2] = dot_v2v2(r_line, v1);
+ r_line[3] = dot_v2v2(r_line, v3);
+ /* Make sure r_line[2] is the minimum. */
+ if (r_line[2] > r_line[3]) {
+ SWAP(float, r_line[2], r_line[3]);
+ }
+}
+
+void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3])
+{
+ wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f);
+
+ if (wpd->shadow_changed) {
+ float up[3] = {0.0f, 0.0f, 1.0f};
+ unit_m4(wpd->shadow_mat);
+
+ /* TODO fix singularity. */
+ copy_v3_v3(wpd->shadow_mat[2], light_direction);
+ cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up);
+ normalize_v3(wpd->shadow_mat[0]);
+ cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]);
+
+ invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat);
+
+ copy_v3_v3(wpd->cached_shadow_direction, light_direction);
+ }
+
+ float planes[6][4];
+ DRW_culling_frustum_planes_get(planes);
+ /* we only need the far plane. */
+ copy_v4_v4(wpd->shadow_far_plane, planes[2]);
+
+ BoundBox frustum_corners;
+ DRW_culling_frustum_corners_get(&frustum_corners);
+
+ mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
+ mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
+ mul_v3_mat3_m4v3(wpd->shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
+ mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
+
+ INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
+ for (int i = 0; i < 4; ++i) {
+ minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]);
+ }
+
+ compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[0], wpd->shadow_near_corners[1], wpd->shadow_near_corners[2], wpd->shadow_near_sides[0]);
+ compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[1], wpd->shadow_near_corners[2], wpd->shadow_near_corners[0], wpd->shadow_near_sides[1]);
+}
+
+static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed)
+{
+ if ((oed->shadow_bbox_dirty) || (wpd->shadow_changed)) {
+ float tmp_mat[4][4];
+ mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat);
+
+ /* Get AABB in shadow space. */
+ INIT_MINMAX(oed->shadow_min, oed->shadow_max);
+
+ /* From object space to shadow space */
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ for (int i = 0; i < 8; ++i) {
+ float corner[3];
+ mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
+ minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
+ }
+ oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2];
+ /* Extend towards infinity. */
+ oed->shadow_max[2] += 1e4f;
+
+ /* Get extended AABB in world space. */
+ BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
+ for (int i = 0; i < 8; ++i) {
+ mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
+ }
+ oed->shadow_bbox_dirty = false;
+ }
+
+ return &oed->shadow_bbox;
+}
+
+bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed)
+{
+ BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
+ return DRW_culling_box_test(shadow_bbox);
+}
+
+float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed)
+{
+ BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
+
+ int corners[4] = {0, 3, 4, 7};
+ float dist = 1e4f, dist_isect;
+ for (int i = 0; i < 4; ++i) {
+ if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
+ wpd->cached_shadow_direction,
+ wpd->shadow_far_plane,
+ &dist_isect, true))
+ {
+ if (dist_isect < dist) {
+ dist = dist_isect;
+ }
+ }
+ else {
+ /* All rays are parallels. If one fails, the other will too. */
+ break;
+ }
+ }
+ return max_ii(dist - oed->shadow_depth, 0);
+}
+
+bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed)
+{
+ /* Just to be sure the min, max are updated. */
+ studiolight_object_shadow_bbox_get(wpd, ob, oed);
+
+ /* Test if near plane is in front of the shadow. */
+ if (oed->shadow_min[2] > wpd->shadow_near_max[2]) {
+ return false;
+ }
+
+ /* Separation Axis Theorem test */
+
+ /* Test bbox sides first (faster) */
+ if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) ||
+ (oed->shadow_max[0] < wpd->shadow_near_min[0]) ||
+ (oed->shadow_min[1] > wpd->shadow_near_max[1]) ||
+ (oed->shadow_max[1] < wpd->shadow_near_min[1]))
+ {
+ return false;
+ }
+
+ /* Test projected near rectangle sides */
+ float pts[4][2] = {
+ {oed->shadow_min[0], oed->shadow_min[1]},
+ {oed->shadow_min[0], oed->shadow_max[1]},
+ {oed->shadow_max[0], oed->shadow_min[1]},
+ {oed->shadow_max[0], oed->shadow_max[1]}
+ };
+
+ for (int i = 0; i < 2; ++i) {
+ float min_dst = FLT_MAX, max_dst = -FLT_MAX;
+ for (int j = 0; j < 4; ++j) {
+ float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
+ /* Do min max */
+ if (min_dst > dst) min_dst = dst;
+ if (max_dst < dst) max_dst = dst;
+ }
+
+ if ((wpd->shadow_near_sides[i][2] > max_dst) ||
+ (wpd->shadow_near_sides[i][3] < min_dst))
+ {
+ return false;
+ }
+ }
+
+ /* No separation axis found. Both shape intersect. */
+ return true;
+}
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
new file mode 100644
index 00000000000..a4cd81e7fd2
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_volume.c
+ * \ingroup draw_engine
+ */
+
+#include "workbench_private.h"
+
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BLI_rand.h"
+#include "BLI_dynstr.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_smoke_types.h"
+
+#include "GPU_draw.h"
+
+enum {
+ VOLUME_SH_SLICE = 0,
+ VOLUME_SH_COBA,
+ VOLUME_SH_CUBIC,
+};
+
+#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
+
+static struct {
+ struct GPUShader *volume_sh[VOLUME_SH_MAX];
+ struct GPUShader *volume_coba_sh;
+ struct GPUShader *volume_slice_sh;
+ struct GPUShader *volume_slice_coba_sh;
+ struct GPUTexture *dummy_tex;
+ struct GPUTexture *dummy_coba_tex;
+} e_data = {NULL};
+
+extern char datatoc_workbench_volume_vert_glsl[];
+extern char datatoc_workbench_volume_frag_glsl[];
+
+static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic)
+{
+ int id = 0;
+ id += (slice) ? (1 << VOLUME_SH_SLICE) : 0;
+ id += (coba) ? (1 << VOLUME_SH_COBA) : 0;
+ id += (cubic) ? (1 << VOLUME_SH_CUBIC) : 0;
+
+ if (!e_data.volume_sh[id]) {
+ DynStr *ds = BLI_dynstr_new();
+
+ if (slice) {
+ BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
+ }
+ if (coba) {
+ BLI_dynstr_append(ds, "#define USE_COBA\n");
+ }
+ if (cubic) {
+ BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
+ }
+
+ char *defines = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ e_data.volume_sh[id] = DRW_shader_create(
+ datatoc_workbench_volume_vert_glsl, NULL,
+ datatoc_workbench_volume_frag_glsl,
+ defines);
+
+ MEM_freeN(defines);
+ }
+
+ return e_data.volume_sh[id];
+}
+
+void workbench_volume_engine_init(void)
+{
+ if (!e_data.dummy_tex) {
+ float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ e_data.dummy_tex = GPU_texture_create_3D(1, 1, 1, GPU_RGBA8, pixel, NULL);
+ e_data.dummy_coba_tex = GPU_texture_create_1D(1, GPU_RGBA8, pixel, NULL);
+ }
+}
+
+void workbench_volume_engine_free(void)
+{
+ for (int i = 0; i < VOLUME_SH_MAX; ++i) {
+ DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]);
+ }
+ DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex);
+ DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex);
+}
+
+void workbench_volume_cache_init(WORKBENCH_Data *vedata)
+{
+ vedata->psl->volume_pass = DRW_pass_create("Volumes", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_PREMUL | DRW_STATE_CULL_FRONT);
+}
+
+void workbench_volume_cache_populate(WORKBENCH_Data *vedata, Scene *scene, Object *ob, ModifierData *md)
+{
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ SmokeDomainSettings *sds = smd->domain;
+ WORKBENCH_PrivateData *wpd = vedata->stl->g_data;
+ WORKBENCH_EffectInfo *effect_info = vedata->stl->effects;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRWShadingGroup *grp = NULL;
+
+ /* Don't show smoke before simulation starts, this could be made an option in the future. */
+ if (!sds->fluid || CFRA < sds->point_cache[0]->startframe) {
+ return;
+ }
+
+ wpd->volumes_do = true;
+ if (sds->use_coba) {
+ GPU_create_smoke_coba_field(smd);
+ }
+ else if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
+ GPU_create_smoke(smd, 0);
+ }
+ else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
+ GPU_create_smoke(smd, 1);
+ }
+
+ if ((!sds->use_coba && sds->tex == NULL) ||
+ (sds->use_coba && sds->tex_field == NULL))
+ {
+ return;
+ }
+
+ const bool use_slice = (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
+ sds->axis_slice_method == AXIS_SLICE_SINGLE);
+ const bool cubic_interp = (sds->interp_method == VOLUME_INTERP_CUBIC);
+ GPUShader *sh = volume_shader_get(use_slice, sds->use_coba, cubic_interp);
+
+ if (use_slice) {
+ float invviewmat[4][4];
+ DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV);
+
+ const int axis = (sds->slice_axis == SLICE_AXIS_AUTO)
+ ? axis_dominant_v3_single(invviewmat[2])
+ : sds->slice_axis - 1;
+ float dim[3];
+ BKE_object_dimensions_get(ob, dim);
+ /* 0.05f to acheive somewhat the same opacity as the full view. */
+ float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
+
+ grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
+ DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
+ DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
+ DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
+ DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT);
+ }
+ else {
+ double noise_ofs;
+ BLI_halton_1D(3, 0.0, effect_info->jitter_index, &noise_ofs);
+ float dim[3], step_length, max_slice;
+ float slice_ct[3] = {sds->res[0], sds->res[1], sds->res[2]};
+ mul_v3_fl(slice_ct, max_ff(0.001f, sds->slice_per_voxel));
+ max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]);
+ BKE_object_dimensions_get(ob, dim);
+ invert_v3(slice_ct);
+ mul_v3_v3(dim, slice_ct);
+ step_length = len_v3(dim);
+
+ grp = DRW_shgroup_create(sh, vedata->psl->volume_pass);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+ DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
+ DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
+ DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
+ DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
+ }
+
+ if (sds->use_coba) {
+ DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex_field);
+ DRW_shgroup_uniform_texture(grp, "transferTexture", sds->tex_coba);
+ }
+ else {
+ DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex);
+ DRW_shgroup_uniform_texture(grp, "shadowTexture", sds->tex_shadow);
+ DRW_shgroup_uniform_texture(grp, "flameTexture", (sds->tex_flame) ? sds->tex_flame : e_data.dummy_tex);
+ DRW_shgroup_uniform_texture(grp, "flameColorTexture", (sds->tex_flame) ? sds->tex_flame_coba : e_data.dummy_coba_tex);
+ }
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * sds->display_thickness);
+
+ if (use_slice) {
+ DRW_shgroup_call_object_add(grp, DRW_cache_quad_get(), ob);
+ }
+ else {
+ DRW_shgroup_call_object_add(grp, DRW_cache_cube_get(), ob);
+ }
+
+ BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(smd));
+}
+
+void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd)
+{
+ /* Free Smoke Textures after rendering */
+ /* XXX This is a waste of processing and GPU bandwidth if nothing
+ * is updated. But the problem is since Textures are stored in the
+ * modifier we don't want them to take precious VRAM if the
+ * modifier is not used for display. We should share them for
+ * all viewport in a redraw at least. */
+ for (LinkData *link = wpd->smoke_domains.first; link; link = link->next) {
+ SmokeModifierData *smd = (SmokeModifierData *)link->data;
+ GPU_free_smoke(smd);
+ }
+ BLI_freelistN(&wpd->smoke_domains);
+}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
new file mode 100644
index 00000000000..1d11774d48f
--- /dev/null
+++ b/source/blender/draw/intern/DRW_render.h
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file DRW_render.h
+ * \ingroup draw
+ */
+
+/* This is the Render Functions used by Realtime engines to draw with OpenGL */
+
+#ifndef __DRW_RENDER_H__
+#define __DRW_RENDER_H__
+
+#include "BLI_listbase.h"
+#include "BLI_math_matrix.h"
+#include "BLI_math_vector.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_material.h"
+#include "BKE_scene.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+#include "draw_cache.h"
+#include "draw_view.h"
+
+#include "draw_manager_profiling.h"
+#include "draw_debug.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RE_engine.h"
+
+#include "DEG_depsgraph.h"
+
+struct rcti;
+struct bContext;
+struct GPUFrameBuffer;
+struct GPUShader;
+struct GPUMaterial;
+struct GPUTexture;
+struct GPUUniformBuffer;
+struct Object;
+struct GPUBatch;
+struct DefaultFramebufferList;
+struct DefaultTextureList;
+struct DRWTextStore;
+struct LampEngineData;
+struct ParticleSystem;
+struct RenderEngineType;
+struct ViewportEngineData;
+struct ViewportEngineData_Info;
+
+typedef struct DRWUniform DRWUniform;
+typedef struct DRWInterface DRWInterface;
+typedef struct DRWPass DRWPass;
+typedef struct DRWShadingGroup DRWShadingGroup;
+
+/* TODO Put it somewhere else? */
+typedef struct BoundSphere {
+ float center[3], radius;
+} BoundSphere;
+
+/* declare members as empty (unused) */
+typedef char DRWViewportEmptyList;
+
+#define DRW_VIEWPORT_LIST_SIZE(list) \
+ (sizeof(list) == sizeof(DRWViewportEmptyList) ? 0 : ((sizeof(list)) / sizeof(void *)))
+
+/* Unused members must be either pass list or 'char *' when not usd. */
+#define DRW_VIEWPORT_DATA_SIZE(ty) { \
+ DRW_VIEWPORT_LIST_SIZE(*(((ty *)NULL)->fbl)), \
+ DRW_VIEWPORT_LIST_SIZE(*(((ty *)NULL)->txl)), \
+ DRW_VIEWPORT_LIST_SIZE(*(((ty *)NULL)->psl)), \
+ DRW_VIEWPORT_LIST_SIZE(*(((ty *)NULL)->stl)) \
+}
+
+/* Use of multisample framebuffers. */
+#define MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl) { \
+ if (dfbl->multisample_fb != NULL) { \
+ DRW_stats_query_start("Multisample Blit"); \
+ GPU_framebuffer_bind(dfbl->multisample_fb); \
+ /* TODO clear only depth but need to do alpha to coverage for transparencies. */ \
+ GPU_framebuffer_clear_color_depth(dfbl->multisample_fb, (const float[4]){0.0f}, 1.0f); \
+ DRW_stats_query_end(); \
+ } \
+} ((void)0)
+
+#define MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl) { \
+ if (dfbl->multisample_fb != NULL) { \
+ DRW_stats_query_start("Multisample Resolve"); \
+ GPU_framebuffer_bind(dfbl->default_fb); \
+ DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color, true); \
+ DRW_stats_query_end(); \
+ } \
+}
+
+#define MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl) { \
+ if (dfbl->multisample_fb != NULL) { \
+ DRW_stats_query_start("Multisample Resolve"); \
+ GPU_framebuffer_bind(dfbl->default_fb); \
+ DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color, false); \
+ DRW_stats_query_end(); \
+ } \
+}
+
+
+
+
+typedef struct DrawEngineDataSize {
+ int fbl_len;
+ int txl_len;
+ int psl_len;
+ int stl_len;
+} DrawEngineDataSize;
+
+typedef struct DrawEngineType {
+ struct DrawEngineType *next, *prev;
+
+ char idname[32];
+
+ const DrawEngineDataSize *vedata_size;
+
+ void (*engine_init)(void *vedata);
+ void (*engine_free)(void);
+
+ void (*cache_init)(void *vedata);
+ void (*cache_populate)(void *vedata, struct Object *ob);
+ void (*cache_finish)(void *vedata);
+
+ void (*draw_background)(void *vedata);
+ void (*draw_scene)(void *vedata);
+
+ void (*view_update)(void *vedata);
+ void (*id_update)(void *vedata, struct ID *id);
+
+ void (*render_to_image)(
+ void *vedata, struct RenderEngine *engine,
+ struct RenderLayer *layer, const struct rcti *rect);
+} DrawEngineType;
+
+#ifndef __DRW_ENGINE_H__
+/* Buffer and textures used by the viewport by default */
+typedef struct DefaultFramebufferList {
+ struct GPUFrameBuffer *default_fb;
+ struct GPUFrameBuffer *color_only_fb;
+ struct GPUFrameBuffer *depth_only_fb;
+ struct GPUFrameBuffer *multisample_fb;
+} DefaultFramebufferList;
+
+typedef struct DefaultTextureList {
+ struct GPUTexture *color;
+ struct GPUTexture *depth;
+ struct GPUTexture *multisample_color;
+ struct GPUTexture *multisample_depth;
+} DefaultTextureList;
+#endif
+
+/* Textures */
+typedef enum {
+ DRW_TEX_FILTER = (1 << 0),
+ DRW_TEX_WRAP = (1 << 1),
+ DRW_TEX_COMPARE = (1 << 2),
+ DRW_TEX_MIPMAP = (1 << 3),
+} DRWTextureFlag;
+
+/* Textures from DRW_texture_pool_query_* have the options
+ * DRW_TEX_FILTER for color float textures, and no options
+ * for depth textures and integer textures. */
+struct GPUTexture *DRW_texture_pool_query_2D(int w, int h, GPUTextureFormat format, DrawEngineType *engine_type);
+
+struct GPUTexture *DRW_texture_create_1D(
+ int w, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_2D(
+ int w, int h, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_2D_array(
+ int w, int h, int d, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_3D(
+ int w, int h, int d, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+struct GPUTexture *DRW_texture_create_cube(
+ int w, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels);
+
+void DRW_texture_ensure_fullscreen_2D(
+ struct GPUTexture **tex, GPUTextureFormat format, DRWTextureFlag flags);
+void DRW_texture_ensure_2D(
+ struct GPUTexture **tex, int w, int h, GPUTextureFormat format, DRWTextureFlag flags);
+
+void DRW_texture_generate_mipmaps(struct GPUTexture *tex);
+void DRW_texture_free(struct GPUTexture *tex);
+#define DRW_TEXTURE_FREE_SAFE(tex) do { \
+ if (tex != NULL) { \
+ DRW_texture_free(tex); \
+ tex = NULL; \
+ } \
+} while (0)
+
+/* UBOs */
+struct GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data);
+void DRW_uniformbuffer_update(struct GPUUniformBuffer *ubo, const void *data);
+void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo);
+#define DRW_UBO_FREE_SAFE(ubo) do { \
+ if (ubo != NULL) { \
+ DRW_uniformbuffer_free(ubo); \
+ ubo = NULL; \
+ } \
+} while (0)
+
+void DRW_transform_to_display(struct GPUTexture *tex, bool use_view_settings);
+void DRW_transform_none(struct GPUTexture *tex);
+void DRW_multisamples_resolve(
+ struct GPUTexture *src_depth, struct GPUTexture *src_color, bool use_depth);
+
+/* Shaders */
+struct GPUShader *DRW_shader_create(
+ const char *vert, const char *geom, const char *frag, const char *defines);
+struct GPUShader *DRW_shader_create_with_lib(
+ const char *vert, const char *geom, const char *frag, const char *lib, const char *defines);
+struct GPUShader *DRW_shader_create_with_transform_feedback(
+ const char *vert, const char *geom, const char *defines,
+ const GPUShaderTFBType prim_type, const char **varying_names, const int varying_count);
+struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines);
+struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines);
+struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines);
+struct GPUShader *DRW_shader_create_3D_depth_only(void);
+struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, int options, bool deferred);
+struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, int options, bool deferred);
+struct GPUMaterial *DRW_shader_create_from_world(
+ struct Scene *scene, struct World *wo, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines, bool deferred);
+struct GPUMaterial *DRW_shader_create_from_material(
+ struct Scene *scene, struct Material *ma, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines, bool deferred);
+void DRW_shader_free(struct GPUShader *shader);
+#define DRW_SHADER_FREE_SAFE(shader) do { \
+ if (shader != NULL) { \
+ DRW_shader_free(shader); \
+ shader = NULL; \
+ } \
+} while (0)
+
+/* Batches */
+
+typedef enum {
+ DRW_STATE_WRITE_DEPTH = (1 << 0),
+ DRW_STATE_WRITE_COLOR = (1 << 1),
+ DRW_STATE_DEPTH_ALWAYS = (1 << 2),
+ DRW_STATE_DEPTH_LESS = (1 << 3),
+ DRW_STATE_DEPTH_LESS_EQUAL = (1 << 4),
+ DRW_STATE_DEPTH_EQUAL = (1 << 5),
+ DRW_STATE_DEPTH_GREATER = (1 << 6),
+ DRW_STATE_DEPTH_GREATER_EQUAL = (1 << 7),
+ DRW_STATE_CULL_BACK = (1 << 8),
+ DRW_STATE_CULL_FRONT = (1 << 9),
+ DRW_STATE_WIRE = (1 << 10),
+ DRW_STATE_POINT = (1 << 11),
+ DRW_STATE_STIPPLE_2 = (1 << 12),
+ DRW_STATE_STIPPLE_3 = (1 << 13),
+ DRW_STATE_STIPPLE_4 = (1 << 14),
+ DRW_STATE_BLEND = (1 << 15),
+ DRW_STATE_ADDITIVE = (1 << 16),
+ DRW_STATE_MULTIPLY = (1 << 17),
+ /* DRW_STATE_TRANSMISSION = (1 << 18), */ /* Not used */
+ DRW_STATE_CLIP_PLANES = (1 << 19),
+ DRW_STATE_ADDITIVE_FULL = (1 << 20), /* Same as DRW_STATE_ADDITIVE but let alpha accumulate without premult. */
+ DRW_STATE_BLEND_PREMUL = (1 << 21), /* Use that if color is already premult by alpha. */
+ DRW_STATE_WIRE_SMOOTH = (1 << 22),
+ DRW_STATE_TRANS_FEEDBACK = (1 << 23),
+ DRW_STATE_BLEND_OIT = (1 << 24),
+
+ DRW_STATE_WRITE_STENCIL = (1 << 27),
+ DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (1 << 28),
+ DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (1 << 29),
+ DRW_STATE_STENCIL_EQUAL = (1 << 30),
+ DRW_STATE_STENCIL_NEQUAL = (1 << 31),
+} DRWState;
+#define DRW_STATE_DEFAULT (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL)
+
+typedef enum {
+ DRW_ATTRIB_INT,
+ DRW_ATTRIB_FLOAT,
+} DRWAttribType;
+
+typedef struct DRWInstanceAttribFormat {
+ char name[32];
+ DRWAttribType type;
+ int components;
+} DRWInstanceAttribFormat;
+
+struct GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttribFormat attribs[], int arraysize);
+#define DRW_shgroup_instance_format(format, ...) do { \
+ if (format == NULL) { \
+ DRWInstanceAttribFormat drw_format[] = __VA_ARGS__;\
+ format = DRW_shgroup_instance_format_array(drw_format, (sizeof(drw_format) / sizeof(DRWInstanceAttribFormat))); \
+ } \
+} while (0)
+
+DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass);
+DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup);
+DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass);
+DRWShadingGroup *DRW_shgroup_material_instance_create(
+ struct GPUMaterial *material, DRWPass *pass, struct GPUBatch *geom, struct Object *ob,
+ struct GPUVertFormat *format);
+DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(struct GPUMaterial *material, DRWPass *pass, int size);
+DRWShadingGroup *DRW_shgroup_instance_create(
+ struct GPUShader *shader, DRWPass *pass, struct GPUBatch *geom, struct GPUVertFormat *format);
+DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass);
+DRWShadingGroup *DRW_shgroup_line_batch_create_with_format(
+ struct GPUShader *shader, DRWPass *pass, struct GPUVertFormat *format);
+DRWShadingGroup *DRW_shgroup_line_batch_create(
+ struct GPUShader *shader, DRWPass *pass);
+DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(
+ struct GPUShader *shader, DRWPass *pass, int size);
+DRWShadingGroup *DRW_shgroup_transform_feedback_create(
+ struct GPUShader *shader, DRWPass *pass, struct GPUVertBuf *tf_target);
+
+
+typedef void (DRWCallGenerateFn)(
+ DRWShadingGroup *shgroup,
+ void (*draw_fn)(DRWShadingGroup *shgroup, struct GPUBatch *geom),
+ void *user_data);
+
+/* return final visibility */
+typedef bool (DRWCallVisibilityFn)(
+ bool vis_in,
+ void *user_data);
+
+void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct GPUBatch *batch);
+
+void DRW_shgroup_free(struct DRWShadingGroup *shgroup);
+void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct GPUBatch *geom, float (*obmat)[4]);
+void DRW_shgroup_call_range_add(
+ DRWShadingGroup *shgroup, struct GPUBatch *geom, float (*obmat)[4], uint v_sta, uint v_count);
+void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, uint point_len, float (*obmat)[4]);
+void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, uint line_count, float (*obmat)[4]);
+void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, uint tria_count, float (*obmat)[4]);
+void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, uint tria_count, struct Object *ob);
+void DRW_shgroup_call_object_add_ex(
+ DRWShadingGroup *shgroup, struct GPUBatch *geom, struct Object *ob, struct Material *ma, bool bypass_culling);
+#define DRW_shgroup_call_object_add(shgroup, geom, ob) DRW_shgroup_call_object_add_ex(shgroup, geom, ob, NULL, false)
+#define DRW_shgroup_call_object_add_no_cull(shgroup, geom, ob) DRW_shgroup_call_object_add_ex(shgroup, geom, ob, NULL, true)
+void DRW_shgroup_call_object_add_with_callback(
+ DRWShadingGroup *shgroup, struct GPUBatch *geom, struct Object *ob, struct Material *ma,
+ DRWCallVisibilityFn *callback, void *user_data);
+/* Used for drawing a batch with instancing without instance attribs. */
+void DRW_shgroup_call_instances_add(
+ DRWShadingGroup *shgroup, struct GPUBatch *geom, float (*obmat)[4], uint *count);
+void DRW_shgroup_call_object_instances_add(
+ DRWShadingGroup *shgroup, struct GPUBatch *geom, struct Object *ob, uint *count);
+void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, struct Object *ob, float (*obmat)[4]);
+void DRW_shgroup_call_generate_add(
+ DRWShadingGroup *shgroup, DRWCallGenerateFn *geometry_fn, void *user_data, float (*obmat)[4]);
+void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], uint attr_len);
+#define DRW_shgroup_call_dynamic_add(shgroup, ...) do { \
+ const void *array[] = {__VA_ARGS__}; \
+ DRW_shgroup_call_dynamic_add_array(shgroup, array, (sizeof(array) / sizeof(*array))); \
+} while (0)
+
+uint DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup);
+
+void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
+void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
+void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
+
+void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex);
+void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex);
+void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo);
+void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo);
+void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex);
+void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
+void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
+void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
+void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize);
+void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize);
+void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize);
+/* Boolean are expected to be 4bytes longs for opengl! */
+void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
+void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
+void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
+void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
+void DRW_shgroup_uniform_ivec4(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize);
+void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float (*value)[3]);
+void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4]);
+/* Store value instead of referencing it. */
+void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
+void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value);
+void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value);
+
+bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
+
+/* Passes */
+DRWPass *DRW_pass_create(const char *name, DRWState state);
+void DRW_pass_state_set(DRWPass *pass, DRWState state);
+void DRW_pass_state_add(DRWPass *pass, DRWState state);
+void DRW_pass_state_remove(DRWPass *pass, DRWState state);
+void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData);
+void DRW_pass_sort_shgroup_z(DRWPass *pass);
+
+bool DRW_pass_is_empty(DRWPass *pass);
+
+/* Viewport */
+typedef enum {
+ /* keep in sync with the union struct DRWMatrixState. */
+ DRW_MAT_PERS = 0,
+ DRW_MAT_PERSINV,
+ DRW_MAT_VIEW,
+ DRW_MAT_VIEWINV,
+ DRW_MAT_WIN,
+ DRW_MAT_WININV,
+
+ DRW_MAT_COUNT, // Don't use this.
+} DRWViewportMatrixType;
+
+typedef struct DRWMatrixState {
+ union {
+ float mat[DRW_MAT_COUNT][4][4];
+ struct {
+ /* keep in sync with the enum DRWViewportMatrixType. */
+ float persmat[4][4];
+ float persinv[4][4];
+ float viewmat[4][4];
+ float viewinv[4][4];
+ float winmat[4][4];
+ float wininv[4][4];
+ };
+ };
+} DRWMatrixState;
+
+void DRW_viewport_init(const bContext *C);
+void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type);
+void DRW_viewport_matrix_get_all(DRWMatrixState *state);
+void DRW_viewport_matrix_override_set(const float mat[4][4], DRWViewportMatrixType type);
+void DRW_viewport_matrix_override_set_all(DRWMatrixState *state);
+void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type);
+void DRW_viewport_matrix_override_unset_all(void);
+
+/* These are in view-space so negative if in perspective.
+ * Extract near and far clip distance from the projection matrix. */
+float DRW_viewport_near_distance_get(void);
+float DRW_viewport_far_distance_get(void);
+
+const float *DRW_viewport_size_get(void);
+const float *DRW_viewport_invert_size_get(void);
+const float *DRW_viewport_screenvecs_get(void);
+const float *DRW_viewport_pixelsize_get(void);
+bool DRW_viewport_is_persp_get(void);
+
+struct DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void);
+struct DefaultTextureList *DRW_viewport_texture_list_get(void);
+
+void DRW_viewport_request_redraw(void);
+
+void DRW_render_to_image(struct RenderEngine *engine, struct Depsgraph *depsgraph);
+void DRW_render_object_iter(
+ void *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph,
+ void (*callback)(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *depsgraph));
+void DRW_render_instance_buffer_finish(void);
+void DRW_render_viewport_size_set(int size[2]);
+
+void DRW_custom_pipeline(
+ DrawEngineType *draw_engine_type,
+ struct Depsgraph *depsgraph,
+ void (*callback)(void *vedata, void *user_data),
+ void *user_data);
+
+/* ViewLayers */
+void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type);
+void **DRW_view_layer_engine_data_ensure_ex(
+ struct ViewLayer *view_layer, DrawEngineType *engine_type, void (*callback)(void *storage));
+void **DRW_view_layer_engine_data_ensure(
+ DrawEngineType *engine_type, void (*callback)(void *storage));
+
+/* DrawData */
+DrawData *DRW_drawdata_get(ID *ib, DrawEngineType *engine_type);
+DrawData *DRW_drawdata_ensure(
+ ID *id,
+ DrawEngineType *engine_type,
+ size_t size,
+ DrawDataInitCb init_cb,
+ DrawDataFreeCb free_cb);
+
+/* Settings */
+bool DRW_object_is_renderable(const struct Object *ob);
+bool DRW_object_is_visible_in_active_context(const struct Object *ob);
+bool DRW_object_is_flat_normal(const struct Object *ob);
+bool DRW_object_use_hide_faces(const struct Object *ob);
+
+bool DRW_object_is_visible_psys_in_active_context(const struct Object *object, const struct ParticleSystem *psys);
+
+struct Object *DRW_object_get_dupli_parent(const struct Object *ob);
+struct DupliObject *DRW_object_get_dupli(const struct Object *ob);
+
+/* Draw commands */
+void DRW_draw_pass(DRWPass *pass);
+void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group);
+
+void DRW_draw_text_cache_queue(struct DRWTextStore *dt);
+
+void DRW_draw_callbacks_pre_scene(void);
+void DRW_draw_callbacks_post_scene(void);
+
+void DRW_state_reset_ex(DRWState state);
+void DRW_state_reset(void);
+void DRW_state_lock(DRWState state);
+
+void DRW_state_invert_facing(void);
+
+void DRW_state_clip_planes_count_set(uint plane_len);
+void DRW_state_clip_planes_reset(void);
+
+/* Culling, return true if object is inside view frustum. */
+bool DRW_culling_sphere_test(BoundSphere *bsphere);
+bool DRW_culling_box_test(BoundBox *bbox);
+bool DRW_culling_plane_test(float plane[4]);
+
+void DRW_culling_frustum_corners_get(BoundBox *corners);
+void DRW_culling_frustum_planes_get(float planes[6][4]);
+
+/* Selection */
+void DRW_select_load_id(uint id);
+
+/* Draw State */
+void DRW_state_dfdy_factors_get(float dfdyfac[2]);
+bool DRW_state_is_fbo(void);
+bool DRW_state_is_select(void);
+bool DRW_state_is_depth(void);
+bool DRW_state_is_image_render(void);
+bool DRW_state_is_scene_render(void);
+bool DRW_state_is_opengl_render(void);
+bool DRW_state_show_text(void);
+bool DRW_state_draw_support(void);
+bool DRW_state_draw_background(void);
+
+struct DRWTextStore *DRW_state_text_cache_get(void);
+
+/* Avoid too many lookups while drawing */
+typedef struct DRWContextState {
+
+ struct ARegion *ar; /* 'CTX_wm_region(C)' */
+ struct RegionView3D *rv3d; /* 'CTX_wm_region_view3d(C)' */
+ struct View3D *v3d; /* 'CTX_wm_view3d(C)' */
+
+ struct Scene *scene; /* 'CTX_data_scene(C)' */
+ struct ViewLayer *view_layer; /* 'CTX_data_view_layer(C)' */
+
+ /* Use 'object_edit' for edit-mode */
+ struct Object *obact; /* 'OBACT' */
+
+ struct RenderEngineType *engine_type;
+
+ struct Depsgraph *depsgraph;
+
+ eObjectMode object_mode;
+
+ /* Last resort (some functions take this as an arg so we can't easily avoid).
+ * May be NULL when used for selection or depth buffer. */
+ const struct bContext *evil_C;
+
+ /* ---- */
+
+ /* Cache: initialized by 'drw_context_state_init'. */
+ struct Object *object_pose;
+ struct Object *object_edit;
+
+} DRWContextState;
+
+const DRWContextState *DRW_context_state_get(void);
+
+#define XRAY_ALPHA(v3d) (((v3d)->shading.type == OB_WIRE) ? (v3d)->shading.xray_alpha_wire : (v3d)->shading.xray_alpha)
+#define XRAY_FLAG(v3d) (((v3d)->shading.type == OB_WIRE) ? V3D_SHADING_XRAY_BONE : V3D_SHADING_XRAY)
+#define XRAY_ENABLED(v3d) ((((v3d)->shading.flag & XRAY_FLAG(v3d)) != 0) && (XRAY_ALPHA(v3d) < 1.0f))
+
+#endif /* __DRW_RENDER_H__ */
diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c
new file mode 100644
index 00000000000..4ec1f761d04
--- /dev/null
+++ b/source/blender/draw/intern/draw_anim_viz.c
@@ -0,0 +1,359 @@
+/*
+ * ***** 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) 2009/2018 by the Blender Foundation.
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/draw/intern/draw_anim_viz.c
+ * \ingroup draw
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "BLI_sys_types.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+#include "BLI_dlrbTree.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+
+#include "ED_keyframes_draw.h"
+
+#include "UI_resources.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+#include "draw_mode_engines.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+
+/* ********************************* Lists ************************************** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself.
+ */
+
+/* XXX: How to show frame numbers, etc.? Currently only doing the dots and lines */
+typedef struct MPATH_PassList {
+ struct DRWPass *lines;
+ struct DRWPass *points;
+} MPATH_PassList;
+
+typedef struct MPATH_StorageList {
+ struct MPATH_PrivateData *g_data;
+} MPATH_StorageList;
+
+typedef struct MPATH_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ MPATH_PassList *psl;
+ MPATH_StorageList *stl;
+} MPATH_Data;
+
+#if 0
+static struct {
+ GPUShader *mpath_line_sh;
+ GPUShader *mpath_points_sh;
+} e_data = {0};
+#endif
+
+/* *************************** Path Cache *********************************** */
+
+/* Just convert the CPU cache to GPU cache. */
+static GPUVertBuf *mpath_vbo_get(bMotionPath *mpath)
+{
+ if (!mpath->points_vbo) {
+ GPUVertFormat format = {0};
+ /* Match structure of bMotionPathVert. */
+ uint pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "flag", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ mpath->points_vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(mpath->points_vbo, mpath->length);
+
+ /* meh... a useless memcpy. */
+ GPUVertBufRaw raw_data;
+ GPU_vertbuf_attr_get_raw_data(mpath->points_vbo, pos, &raw_data);
+ memcpy(GPU_vertbuf_raw_step(&raw_data), mpath->points, sizeof(bMotionPathVert) * mpath->length);
+ }
+ return mpath->points_vbo;
+}
+
+static GPUBatch *mpath_batch_line_get(bMotionPath *mpath)
+{
+ if (!mpath->batch_line) {
+ mpath->batch_line = GPU_batch_create(GPU_PRIM_LINE_STRIP, mpath_vbo_get(mpath), NULL);
+ }
+ return mpath->batch_line;
+}
+
+static GPUBatch *mpath_batch_points_get(bMotionPath *mpath)
+{
+ if (!mpath->batch_points) {
+ mpath->batch_points = GPU_batch_create(GPU_PRIM_POINTS, mpath_vbo_get(mpath), NULL);
+ }
+ return mpath->batch_points;
+}
+
+/* *************************** Draw Engine Entrypoints ************************** */
+
+static void MPATH_engine_init(void *UNUSED(vedata))
+{
+}
+
+static void MPATH_engine_free(void)
+{
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void MPATH_cache_init(void *vedata)
+{
+ MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ psl->lines = DRW_pass_create("Motionpath Line Pass", state);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_POINT;
+ psl->points = DRW_pass_create("Motionpath Point Pass", state);
+ }
+}
+
+static void MPATH_cache_motion_path(MPATH_PassList *psl,
+ Object *ob, bPoseChannel *pchan,
+ bAnimVizSettings *avs, bMotionPath *mpath)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ int txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_ASCII;
+ int stepsize = avs->path_step;
+ int sfra, efra, sind, len;
+ int cfra = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ bool sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT);
+ bool show_keyframes = (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) != 0;
+ bMotionPathVert *mpv, *mpv_start;
+
+ /* get frame ranges */
+ if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
+ /* With "Around Current", we only choose frames from around
+ * the current frame to draw.
+ */
+ sfra = cfra - avs->path_bc;
+ efra = cfra + avs->path_ac + 1;
+ }
+ else {
+ /* Use the current display range */
+ sfra = avs->path_sf;
+ efra = avs->path_ef;
+ }
+
+ /* no matter what, we can only show what is in the cache and no more
+ * - abort if whole range is past ends of path
+ * - otherwise clamp endpoints to extents of path
+ */
+ if (sfra < mpath->start_frame) {
+ /* start clamp */
+ sfra = mpath->start_frame;
+ }
+ if (efra > mpath->end_frame) {
+ /* end clamp */
+ efra = mpath->end_frame;
+ }
+
+ if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) {
+ /* whole path is out of bounds */
+ return;
+ }
+
+ len = efra - sfra;
+
+ if ((len <= 0) || (mpath->points == NULL)) {
+ return;
+ }
+
+ sind = sfra - mpath->start_frame;
+ mpv_start = (mpath->points + sind);
+
+ bool use_custom_col = (mpath->flag & MOTIONPATH_FLAG_CUSTOM) != 0;
+
+ /* draw curve-line of path */
+ /* Draw lines only if line drawing option is enabled */
+ if (mpath->flag & MOTIONPATH_FLAG_LINES) {
+ DRWShadingGroup *shgrp = DRW_shgroup_create(mpath_line_shader_get(), psl->lines);
+ DRW_shgroup_uniform_int_copy(shgrp, "frameCurrent", cfra);
+ DRW_shgroup_uniform_int_copy(shgrp, "frameStart", sfra);
+ DRW_shgroup_uniform_int_copy(shgrp, "frameEnd", efra);
+ DRW_shgroup_uniform_int_copy(shgrp, "cacheStart", mpath->start_frame);
+ DRW_shgroup_uniform_int_copy(shgrp, "lineThickness", mpath->line_thickness);
+ DRW_shgroup_uniform_bool_copy(shgrp, "selected", sel);
+ DRW_shgroup_uniform_bool_copy(shgrp, "useCustomColor", use_custom_col);
+ DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_block(shgrp, "globalsBlock", globals_ubo);
+ if (use_custom_col) {
+ DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
+ }
+ /* Only draw the required range. */
+ DRW_shgroup_call_range_add(shgrp, mpath_batch_line_get(mpath), NULL, sind, len);
+ }
+
+ /* Draw points. */
+ DRWShadingGroup *shgrp = DRW_shgroup_create(mpath_points_shader_get(), psl->points);
+ DRW_shgroup_uniform_int_copy(shgrp, "frameCurrent", cfra);
+ DRW_shgroup_uniform_int_copy(shgrp, "cacheStart", mpath->start_frame);
+ DRW_shgroup_uniform_int_copy(shgrp, "pointSize", mpath->line_thickness);
+ DRW_shgroup_uniform_int_copy(shgrp, "stepSize", stepsize);
+ DRW_shgroup_uniform_bool_copy(shgrp, "selected", sel);
+ DRW_shgroup_uniform_bool_copy(shgrp, "showKeyFrames", show_keyframes);
+ DRW_shgroup_uniform_bool_copy(shgrp, "useCustomColor", use_custom_col);
+ DRW_shgroup_uniform_block(shgrp, "globalsBlock", globals_ubo);
+ if (use_custom_col) {
+ DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
+ }
+ /* Only draw the required range. */
+ DRW_shgroup_call_range_add(shgrp, mpath_batch_points_get(mpath), NULL, sind, len);
+
+ /* Draw frame numbers at each framestep value */
+ bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
+ if ((avs->path_viewflag & (MOTIONPATH_VIEW_FNUMS)) || (show_kf_no && show_keyframes)) {
+ int i;
+ uchar col[4], col_kf[4];
+ UI_GetThemeColor3ubv(TH_TEXT_HI, col);
+ UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col_kf);
+ col[3] = col_kf[3] = 255;
+
+ for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) {
+ int frame = sfra + i;
+ char numstr[32];
+ size_t numstr_len;
+ float co[3];
+ bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0;
+
+ if ((show_keyframes && show_kf_no && is_keyframe) ||
+ ((avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) && (i == 0)))
+ {
+ numstr_len = sprintf(numstr, " %d", frame);
+ mul_v3_m4v3(co, ob->imat, mpv->co);
+ DRW_text_cache_add(dt, co, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col);
+ }
+ else if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) {
+ bMotionPathVert *mpvP = (mpv - stepsize);
+ bMotionPathVert *mpvN = (mpv + stepsize);
+ /* only draw framenum if several consecutive highlighted points don't occur on same point */
+ if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
+ numstr_len = sprintf(numstr, " %d", frame);
+ mul_v3_m4v3(co, ob->imat, mpv->co);
+ DRW_text_cache_add(dt, co, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+}
+
+/* Add geometry to shading groups. Execute for each objects */
+static void MPATH_cache_populate(void *vedata, Object *ob)
+{
+ MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (draw_ctx->v3d->overlay.flag & V3D_OVERLAY_HIDE_MOTION_PATHS) {
+ return;
+ }
+
+ if (ob->type == OB_ARMATURE) {
+ if (DRW_pose_mode_armature(ob, draw_ctx->obact)) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->mpath) {
+ MPATH_cache_motion_path(psl, ob, pchan, &ob->pose->avs, pchan->mpath);
+ }
+ }
+ }
+ }
+ else {
+ if (ob->mpath) {
+ MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
+ }
+ }
+}
+
+/* Draw time! Control rendering pipeline from here */
+static void MPATH_draw_scene(void *vedata)
+{
+ MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ if (DRW_pass_is_empty(psl->lines) &&
+ DRW_pass_is_empty(psl->points))
+ {
+ /* Nothing to draw. */
+ return;
+ }
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
+
+ DRW_draw_pass(psl->lines);
+ DRW_draw_pass(psl->points);
+
+ MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl)
+}
+
+/* *************************** Draw Engine Defines ****************************** */
+
+static const DrawEngineDataSize MPATH_data_size = DRW_VIEWPORT_DATA_SIZE(MPATH_Data);
+
+DrawEngineType draw_engine_motion_path_type = {
+ NULL, NULL,
+ N_("MotionPath"),
+ &MPATH_data_size,
+ &MPATH_engine_init,
+ &MPATH_engine_free,
+ &MPATH_cache_init,
+ &MPATH_cache_populate,
+ NULL,
+ NULL,
+ &MPATH_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
new file mode 100644
index 00000000000..aec25274ab1
--- /dev/null
+++ b/source/blender/draw/intern/draw_armature.c
@@ -0,0 +1,1915 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_armature.c
+ * \ingroup draw
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "DRW_render.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_dlrbTree.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_global.h"
+#include "BKE_modifier.h"
+#include "BKE_nla.h"
+#include "BKE_curve.h"
+
+#include "BIF_gl.h"
+
+#include "ED_armature.h"
+#include "ED_keyframes_draw.h"
+
+#include "GPU_select.h"
+
+#include "UI_resources.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var))
+#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag))
+
+#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
+
+/* For now just match 2.7x where possible. */
+// #define USE_SOLID_COLOR
+
+/* Reset for drawing each armature object */
+static struct {
+ /* Current armature object */
+ Object *ob;
+ /* Reset when changing current_armature */
+ DRWShadingGroup *bone_octahedral_solid;
+ DRWShadingGroup *bone_octahedral_wire;
+ DRWShadingGroup *bone_octahedral_outline;
+ DRWShadingGroup *bone_box_solid;
+ DRWShadingGroup *bone_box_wire;
+ DRWShadingGroup *bone_box_outline;
+ DRWShadingGroup *bone_wire;
+ DRWShadingGroup *bone_stick;
+ DRWShadingGroup *bone_dof_sphere;
+ DRWShadingGroup *bone_dof_lines;
+ DRWShadingGroup *bone_envelope_solid;
+ DRWShadingGroup *bone_envelope_distance;
+ DRWShadingGroup *bone_envelope_wire;
+ DRWShadingGroup *bone_point_solid;
+ DRWShadingGroup *bone_point_wire;
+ DRWShadingGroup *bone_axes;
+ DRWShadingGroup *lines_relationship;
+ DRWShadingGroup *lines_ik;
+ DRWShadingGroup *lines_ik_no_target;
+ DRWShadingGroup *lines_ik_spline;
+
+ DRWArmaturePasses passes;
+
+ bool transparent;
+} g_data = {NULL};
+
+
+/**
+ * Follow `TH_*` naming except for mixed colors.
+ */
+static struct {
+ float select_color[4];
+ float edge_select_color[4];
+ float bone_select_color[4]; /* tint */
+ float wire_color[4];
+ float wire_edit_color[4];
+ float bone_solid_color[4];
+ float bone_active_unselect_color[4]; /* mix */
+ float bone_pose_color[4];
+ float bone_pose_active_color[4];
+ float bone_pose_active_unselect_color[4]; /* mix */
+ float text_hi_color[4];
+ float text_color[4];
+ float vertex_select_color[4];
+ float vertex_color[4];
+
+ /* not a theme, this is an override */
+ const float *const_color;
+ float const_wire;
+} g_theme;
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Shader Groups (DRW_shgroup)
+ * \{ */
+
+/* Octahedral */
+static void drw_shgroup_bone_octahedral(
+ const float (*bone_mat)[4],
+ const float bone_color[4], const float hint_color[4], const float outline_color[4])
+{
+ if (g_data.bone_octahedral_outline == NULL) {
+ struct GPUBatch *geom = DRW_cache_bone_octahedral_wire_get();
+ g_data.bone_octahedral_outline = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, geom);
+ }
+ if (g_data.bone_octahedral_solid == NULL) {
+ struct GPUBatch *geom = DRW_cache_bone_octahedral_get();
+ g_data.bone_octahedral_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, geom,
+ g_data.transparent);
+ }
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_solid, final_bonemat, bone_color, hint_color);
+ if (outline_color[3] > 0.0f) {
+ DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_outline, final_bonemat, outline_color);
+ }
+}
+
+/* Box / B-Bone */
+static void drw_shgroup_bone_box(
+ const float (*bone_mat)[4],
+ const float bone_color[4], const float hint_color[4], const float outline_color[4])
+{
+ if (g_data.bone_box_wire == NULL) {
+ struct GPUBatch *geom = DRW_cache_bone_box_wire_get();
+ g_data.bone_box_outline = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, geom);
+ }
+ if (g_data.bone_box_solid == NULL) {
+ struct GPUBatch *geom = DRW_cache_bone_box_get();
+ g_data.bone_box_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, geom, g_data.transparent);
+ }
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, final_bonemat, bone_color, hint_color);
+ if (outline_color[3] > 0.0f) {
+ DRW_shgroup_call_dynamic_add(g_data.bone_box_outline, final_bonemat, outline_color);
+ }
+}
+
+/* Wire */
+static void drw_shgroup_bone_wire(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_wire == NULL) {
+ g_data.bone_wire = shgroup_dynlines_flat_color(g_data.passes.bone_wire);
+ }
+ float head[3], tail[3];
+ mul_v3_m4v3(head, g_data.ob->obmat, bone_mat[3]);
+ DRW_shgroup_call_dynamic_add(g_data.bone_wire, head, color);
+
+ add_v3_v3v3(tail, bone_mat[3], bone_mat[1]);
+ mul_m4_v3(g_data.ob->obmat, tail);
+ DRW_shgroup_call_dynamic_add(g_data.bone_wire, tail, color);
+}
+
+/* Stick */
+static void drw_shgroup_bone_stick(
+ const float (*bone_mat)[4],
+ const float col_wire[4], const float col_bone[4], const float col_head[4], const float col_tail[4])
+{
+ if (g_data.bone_stick == NULL) {
+ g_data.bone_stick = shgroup_instance_bone_stick(g_data.passes.bone_wire);
+ }
+ float final_bonemat[4][4], tail[4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ add_v3_v3v3(tail, final_bonemat[3], final_bonemat[1]);
+ DRW_shgroup_call_dynamic_add(g_data.bone_stick, final_bonemat[3], tail, col_wire, col_bone, col_head, col_tail);
+}
+
+
+/* Envelope */
+static void drw_shgroup_bone_envelope_distance(
+ const float (*bone_mat)[4],
+ const float *radius_head, const float *radius_tail, const float *distance)
+{
+ if (g_data.passes.bone_envelope != NULL) {
+ if (g_data.bone_envelope_distance == NULL) {
+ g_data.bone_envelope_distance = shgroup_instance_bone_envelope_distance(g_data.passes.bone_envelope);
+ /* passes.bone_envelope should have the DRW_STATE_CULL_FRONT state enabled. */
+ }
+ float head_sphere[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sphere[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ /* We need matrix mul because we need shear applied. */
+ /* NOTE: could be done in shader if that becomes a bottleneck. */
+ mul_m4_v4(final_bonemat, head_sphere);
+ mul_m4_v4(final_bonemat, tail_sphere);
+ head_sphere[3] = *radius_head;
+ head_sphere[3] += *distance;
+ tail_sphere[3] = *radius_tail;
+ tail_sphere[3] += *distance;
+ DRW_shgroup_call_dynamic_add(g_data.bone_envelope_distance, head_sphere, tail_sphere, final_bonemat[0]);
+ }
+}
+
+static void drw_shgroup_bone_envelope(
+ const float (*bone_mat)[4],
+ const float bone_color[4], const float hint_color[4], const float outline_color[4],
+ const float *radius_head, const float *radius_tail)
+{
+ if (g_data.bone_point_wire == NULL) {
+ g_data.bone_point_wire = shgroup_instance_bone_sphere_outline(g_data.passes.bone_wire);
+ }
+ if (g_data.bone_point_solid == NULL) {
+ g_data.bone_point_solid = shgroup_instance_bone_sphere_solid(g_data.passes.bone_solid, g_data.transparent);
+ }
+ if (g_data.bone_envelope_wire == NULL) {
+ g_data.bone_envelope_wire = shgroup_instance_bone_envelope_outline(g_data.passes.bone_wire);
+ }
+ if (g_data.bone_envelope_solid == NULL) {
+ g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.passes.bone_solid, g_data.transparent);
+ /* We can have a lot of overdraw if we don't do this. Also envelope are not subject to
+ * inverted matrix. */
+ DRW_shgroup_state_enable(g_data.bone_envelope_solid, DRW_STATE_CULL_BACK);
+ }
+
+ float head_sphere[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sphere[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ mul_m4_v4(final_bonemat, head_sphere);
+ mul_m4_v4(final_bonemat, tail_sphere);
+ head_sphere[3] = *radius_head;
+ tail_sphere[3] = *radius_tail;
+
+ if (head_sphere[3] < 0.0f) {
+ /* Draw Tail only */
+ float tmp[4][4] = {{0.0f}};
+ tmp[0][0] = tmp[1][1] = tmp[2][2] = tail_sphere[3] / PT_DEFAULT_RAD;
+ tmp[3][3] = 1.0f;
+ copy_v3_v3(tmp[3], tail_sphere);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, bone_color, hint_color);
+ if (outline_color[3] > 0.0f) {
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, tmp, outline_color);
+ }
+ }
+ else if (tail_sphere[3] < 0.0f) {
+ /* Draw Head only */
+ float tmp[4][4] = {{0.0f}};
+ tmp[0][0] = tmp[1][1] = tmp[2][2] = head_sphere[3] / PT_DEFAULT_RAD;
+ tmp[3][3] = 1.0f;
+ copy_v3_v3(tmp[3], head_sphere);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, bone_color, hint_color);
+ if (outline_color[3] > 0.0f) {
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, tmp, outline_color);
+ }
+ }
+ else {
+ /* Draw Body */
+ float tmp_sphere[4];
+ float len = len_v3v3(tail_sphere, head_sphere);
+ float fac_head = (len - head_sphere[3]) / len;
+ float fac_tail = (len - tail_sphere[3]) / len;
+
+ /* Small epsilon to avoid problem with float precision in shader. */
+ if (len > (tail_sphere[3] + head_sphere[3]) + 1e-8f) {
+
+ copy_v4_v4(tmp_sphere, head_sphere);
+ interp_v4_v4v4(head_sphere, tail_sphere, head_sphere, fac_head);
+ interp_v4_v4v4(tail_sphere, tmp_sphere, tail_sphere, fac_tail);
+ DRW_shgroup_call_dynamic_add(
+ g_data.bone_envelope_solid, head_sphere, tail_sphere, bone_color, hint_color, final_bonemat[0]);
+ if (outline_color[3] > 0.0f) {
+ DRW_shgroup_call_dynamic_add(
+ g_data.bone_envelope_wire, head_sphere, tail_sphere, outline_color, final_bonemat[0]);
+ }
+ }
+ else {
+ float tmp[4][4] = {{0.0f}};
+ float fac = max_ff(fac_head, 1.0f - fac_tail);
+ interp_v4_v4v4(tmp_sphere, tail_sphere, head_sphere, clamp_f(fac, 0.0f, 1.0f));
+ tmp[0][0] = tmp[1][1] = tmp[2][2] = tmp_sphere[3] / PT_DEFAULT_RAD;
+ tmp[3][3] = 1.0f;
+ copy_v3_v3(tmp[3], tmp_sphere);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, tmp, bone_color, hint_color);
+ if (outline_color[3] > 0.0f) {
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, tmp, outline_color);
+ }
+ }
+ }
+}
+
+/* Custom (geometry) */
+
+static void drw_shgroup_bone_custom_solid(
+ const float (*bone_mat)[4],
+ const float bone_color[4], const float hint_color[4], const float outline_color[4],
+ Object *custom)
+{
+ /* grr, not re-using instances! */
+ struct GPUBatch *surf = DRW_cache_object_surface_get(custom);
+ struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
+ struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom);
+ float final_bonemat[4][4];
+
+ if (surf || edges || ledges) {
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ }
+
+ if (surf) {
+ DRWShadingGroup *shgrp_geom_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, surf,
+ g_data.transparent);
+ DRW_shgroup_call_dynamic_add(shgrp_geom_solid, final_bonemat, bone_color, hint_color);
+ }
+
+ if (edges && outline_color[3] > 0.0f) {
+ DRWShadingGroup *shgrp_geom_wire = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, edges);
+ DRW_shgroup_call_dynamic_add(shgrp_geom_wire, final_bonemat, outline_color);
+ }
+
+ if (ledges) {
+ DRWShadingGroup *shgrp_geom_ledges = shgroup_instance_wire(g_data.passes.bone_wire, ledges);
+ float final_color[4];
+ copy_v3_v3(final_color, outline_color);
+ final_color[3] = 1.0f; /* hack */
+ DRW_shgroup_call_dynamic_add(shgrp_geom_ledges, final_bonemat, final_color);
+ }
+}
+
+static void drw_shgroup_bone_custom_wire(
+ const float (*bone_mat)[4],
+ const float color[4], Object *custom)
+{
+ /* grr, not re-using instances! */
+ struct GPUBatch *geom = DRW_cache_object_wire_outline_get(custom);
+ if (geom) {
+ DRWShadingGroup *shgrp_geom_wire = shgroup_instance_wire(g_data.passes.bone_wire, geom);
+ float final_bonemat[4][4], final_color[4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ copy_v3_v3(final_color, color);
+ final_color[3] = 1.0f; /* hack */
+ DRW_shgroup_call_dynamic_add(shgrp_geom_wire, final_bonemat, final_color);
+ }
+}
+
+/* Head and tail sphere */
+static void drw_shgroup_bone_point(
+ const float (*bone_mat)[4],
+ const float bone_color[4], const float hint_color[4], const float outline_color[4])
+{
+ if (g_data.bone_point_wire == NULL) {
+ g_data.bone_point_wire = shgroup_instance_bone_sphere_outline(g_data.passes.bone_wire);
+ }
+ if (g_data.bone_point_solid == NULL) {
+ g_data.bone_point_solid = shgroup_instance_bone_sphere_solid(g_data.passes.bone_solid, g_data.transparent);
+ }
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, final_bonemat, bone_color, hint_color);
+ if (outline_color[3] > 0.0f) {
+ DRW_shgroup_call_dynamic_add(g_data.bone_point_wire, final_bonemat, outline_color);
+ }
+}
+
+/* Axes */
+static void drw_shgroup_bone_axes(const float (*bone_mat)[4], const float color[4])
+{
+ if (g_data.bone_axes == NULL) {
+ g_data.bone_axes = shgroup_instance_bone_axes(g_data.passes.bone_axes);
+ }
+ float final_bonemat[4][4];
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ DRW_shgroup_call_dynamic_add(g_data.bone_axes, final_bonemat, color);
+}
+
+/* Relationship lines */
+static void drw_shgroup_bone_relationship_lines(const float start[3], const float end[3])
+{
+ if (g_data.lines_relationship == NULL) {
+ g_data.lines_relationship = shgroup_dynlines_dashed_uniform_color(
+ g_data.passes.relationship_lines, g_theme.wire_color);
+ }
+ /* reverse order to have less stipple overlap */
+ float v[3];
+ mul_v3_m4v3(v, g_data.ob->obmat, end);
+ DRW_shgroup_call_dynamic_add(g_data.lines_relationship, v);
+ mul_v3_m4v3(v, g_data.ob->obmat, start);
+ DRW_shgroup_call_dynamic_add(g_data.lines_relationship, v);
+}
+
+static void drw_shgroup_bone_ik_lines(const float start[3], const float end[3])
+{
+ if (g_data.lines_ik == NULL) {
+ static float fcolor[4] = {0.8f, 0.5f, 0.0f, 1.0f}; /* add theme! */
+ g_data.lines_ik = shgroup_dynlines_dashed_uniform_color(g_data.passes.relationship_lines, fcolor);
+ }
+ /* reverse order to have less stipple overlap */
+ float v[3];
+ mul_v3_m4v3(v, g_data.ob->obmat, end);
+ DRW_shgroup_call_dynamic_add(g_data.lines_ik, v);
+ mul_v3_m4v3(v, g_data.ob->obmat, start);
+ DRW_shgroup_call_dynamic_add(g_data.lines_ik, v);
+}
+
+static void drw_shgroup_bone_ik_no_target_lines(const float start[3], const float end[3])
+{
+ if (g_data.lines_ik_no_target == NULL) {
+ static float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
+ g_data.lines_ik_no_target = shgroup_dynlines_dashed_uniform_color(g_data.passes.relationship_lines, fcolor);
+ }
+ /* reverse order to have less stipple overlap */
+ float v[3];
+ mul_v3_m4v3(v, g_data.ob->obmat, end);
+ DRW_shgroup_call_dynamic_add(g_data.lines_ik_no_target, v);
+ mul_v3_m4v3(v, g_data.ob->obmat, start);
+ DRW_shgroup_call_dynamic_add(g_data.lines_ik_no_target, v);
+}
+
+static void drw_shgroup_bone_ik_spline_lines(const float start[3], const float end[3])
+{
+ if (g_data.lines_ik_spline == NULL) {
+ static float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
+ g_data.lines_ik_spline = shgroup_dynlines_dashed_uniform_color(g_data.passes.relationship_lines, fcolor);
+ }
+ /* reverse order to have less stipple overlap */
+ float v[3];
+ mul_v3_m4v3(v, g_data.ob->obmat, end);
+ DRW_shgroup_call_dynamic_add(g_data.lines_ik_spline, v);
+ mul_v3_m4v3(v, g_data.ob->obmat, start);
+ DRW_shgroup_call_dynamic_add(g_data.lines_ik_spline, v);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Drawing Theme Helpers
+ *
+ * Note, this section is duplicate of code in 'drawarmature.c'.
+ *
+ * \{ */
+
+/* global here is reset before drawing each bone */
+static struct {
+ const ThemeWireColor *bcolor;
+} g_color;
+
+/* values of colCode for set_pchan_color */
+enum {
+ PCHAN_COLOR_NORMAL = 0, /* normal drawing */
+ PCHAN_COLOR_SOLID, /* specific case where "solid" color is needed */
+ PCHAN_COLOR_CONSTS, /* "constraint" colors (which may/may-not be suppressed) */
+
+ PCHAN_COLOR_SPHEREBONE_BASE, /* for the 'stick' of sphere (envelope) bones */
+ PCHAN_COLOR_SPHEREBONE_END, /* for the ends of sphere (envelope) bones */
+ PCHAN_COLOR_LINEBONE /* for the middle of line-bones */
+};
+
+/* This function sets the color-set for coloring a certain bone */
+static void set_pchan_colorset(Object *ob, bPoseChannel *pchan)
+{
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bActionGroup *grp = NULL;
+ short color_index = 0;
+
+ /* sanity check */
+ if (ELEM(NULL, ob, arm, pose, pchan)) {
+ g_color.bcolor = NULL;
+ return;
+ }
+
+ /* only try to set custom color if enabled for armature */
+ if (arm->flag & ARM_COL_CUSTOM) {
+ /* currently, a bone can only use a custom color set if it's group (if it has one),
+ * has been set to use one
+ */
+ if (pchan->agrp_index) {
+ grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
+ if (grp)
+ color_index = grp->customCol;
+ }
+ }
+
+ /* bcolor is a pointer to the color set to use. If NULL, then the default
+ * color set (based on the theme colors for 3d-view) is used.
+ */
+ if (color_index > 0) {
+ bTheme *btheme = UI_GetTheme();
+ g_color.bcolor = &btheme->tarm[(color_index - 1)];
+ }
+ else if (color_index == -1) {
+ /* use the group's own custom color set (grp is always != NULL here) */
+ g_color.bcolor = &grp->cs;
+ }
+ else {
+ g_color.bcolor = NULL;
+ }
+}
+
+/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
+static void cp_shade_color3ub(uchar cp[3], const int offset)
+{
+ int r, g, b;
+
+ r = offset + (int) cp[0];
+ CLAMP(r, 0, 255);
+ g = offset + (int) cp[1];
+ CLAMP(g, 0, 255);
+ b = offset + (int) cp[2];
+ CLAMP(b, 0, 255);
+
+ cp[0] = r;
+ cp[1] = g;
+ cp[2] = b;
+}
+
+static void cp_shade_color3f(float cp[3], const float offset)
+{
+ add_v3_fl(cp, offset);
+ CLAMP(cp[0], 0, 255);
+ CLAMP(cp[1], 0, 255);
+ CLAMP(cp[2], 0, 255);
+}
+
+
+/* This function sets the gl-color for coloring a certain bone (based on bcolor) */
+static bool set_pchan_color(short colCode, const int boneflag, const short constflag, float r_color[4])
+{
+ float *fcolor = r_color;
+ const ThemeWireColor *bcolor = g_color.bcolor;
+
+ switch (colCode) {
+ case PCHAN_COLOR_NORMAL:
+ {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_char((char *)cp, bcolor->active);
+ if (!(boneflag & BONE_SELECTED)) {
+ cp_shade_color3ub(cp, -80);
+ }
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_char((char *)cp, bcolor->select);
+ }
+ else {
+ /* a bit darker than solid */
+ copy_v3_v3_char((char *)cp, bcolor->solid);
+ cp_shade_color3ub(cp, -50);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
+ UI_GetThemeColor4fv(TH_BONE_POSE_ACTIVE, fcolor);
+ }
+ else if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorBlendShade4fv(TH_WIRE, TH_BONE_POSE, 0.15f, 0, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_WIRE, fcolor);
+ }
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_SOLID:
+ {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+
+ if (bcolor) {
+ float solid_bcolor[3];
+ rgb_uchar_to_float(solid_bcolor, (uchar *)bcolor->solid);
+ interp_v3_v3v3(fcolor, fcolor, solid_bcolor, 1.0f);
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_CONSTS:
+ {
+ if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) {
+ uchar cp[4];
+ if (constflag & PCHAN_HAS_TARGET) rgba_char_args_set((char *)cp, 255, 150, 0, 80);
+ else if (constflag & PCHAN_HAS_IK) rgba_char_args_set((char *)cp, 255, 255, 0, 80);
+ else if (constflag & PCHAN_HAS_SPLINEIK) rgba_char_args_set((char *)cp, 200, 255, 0, 80);
+ else if (constflag & PCHAN_HAS_CONST) rgba_char_args_set((char *)cp, 0, 255, 120, 80);
+ else {
+ return false;
+ }
+
+ rgba_uchar_to_float(fcolor, cp);
+
+ return true;
+ }
+ return false;
+ }
+ case PCHAN_COLOR_SPHEREBONE_BASE:
+ {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_char((char *)cp, bcolor->active);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_char((char *)cp, bcolor->select);
+ }
+ else {
+ copy_v3_v3_char((char *)cp, bcolor->solid);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, 40, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+ }
+ }
+
+ return true;
+ }
+ case PCHAN_COLOR_SPHEREBONE_END:
+ {
+ if (bcolor) {
+ uchar cp[4] = {255};
+
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3_char((char *)cp, bcolor->active);
+ cp_shade_color3ub(cp, 10);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ copy_v3_v3_char((char *)cp, bcolor->select);
+ cp_shade_color3ub(cp, -30);
+ }
+ else {
+ copy_v3_v3_char((char *)cp, bcolor->solid);
+ cp_shade_color3ub(cp, -30);
+ }
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, 10, fcolor);
+ }
+ else if (boneflag & BONE_SELECTED) {
+ UI_GetThemeColorShade4fv(TH_BONE_POSE, -30, fcolor);
+ }
+ else {
+ UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor);
+ }
+ }
+ break;
+ }
+ case PCHAN_COLOR_LINEBONE:
+ {
+ /* inner part in background color or constraint */
+ if ((constflag) && ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS))) {
+ uchar cp[4];
+ if (constflag & PCHAN_HAS_TARGET) rgba_char_args_set((char *)cp, 255, 150, 0, 255);
+ else if (constflag & PCHAN_HAS_IK) rgba_char_args_set((char *)cp, 255, 255, 0, 255);
+ else if (constflag & PCHAN_HAS_SPLINEIK) rgba_char_args_set((char *)cp, 200, 255, 0, 255);
+ else if (constflag & PCHAN_HAS_CONST) rgba_char_args_set((char *)cp, 0, 255, 120, 255);
+ else if (constflag) UI_GetThemeColor4ubv(TH_BONE_POSE, cp); /* PCHAN_HAS_ACTION */
+
+ rgb_uchar_to_float(fcolor, cp);
+ }
+ else {
+ if (bcolor) {
+ const char *cp = bcolor->solid;
+ rgb_uchar_to_float(fcolor, (uchar *)cp);
+ fcolor[3] = 204.f / 255.f;
+ }
+ else {
+ UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor);
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Drawing Color Helpers
+ * \{ */
+
+/** See: 'set_pchan_color'*/
+static void update_color(const Object *ob, const float const_color[4])
+{
+ g_theme.const_color = const_color;
+ g_theme.const_wire = ((ob->base_flag & BASE_SELECTED) != 0) ? 1.5f : 0.0f;
+
+#define NO_ALPHA(c) (((c)[3] = 1.0f), (c))
+
+ UI_GetThemeColor3fv(TH_SELECT, NO_ALPHA(g_theme.select_color));
+ UI_GetThemeColor3fv(TH_EDGE_SELECT, NO_ALPHA(g_theme.edge_select_color));
+ UI_GetThemeColorShade3fv(TH_EDGE_SELECT, -20, NO_ALPHA(g_theme.bone_select_color));
+ UI_GetThemeColor3fv(TH_WIRE, NO_ALPHA(g_theme.wire_color));
+ UI_GetThemeColor3fv(TH_WIRE_EDIT, NO_ALPHA(g_theme.wire_edit_color));
+ UI_GetThemeColor3fv(TH_BONE_SOLID, NO_ALPHA(g_theme.bone_solid_color));
+ UI_GetThemeColorBlendShade3fv(TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f, 0, NO_ALPHA(g_theme.bone_active_unselect_color));
+ UI_GetThemeColor3fv(TH_BONE_POSE, NO_ALPHA(g_theme.bone_pose_color));
+ UI_GetThemeColor3fv(TH_BONE_POSE_ACTIVE, NO_ALPHA(g_theme.bone_pose_active_color));
+ UI_GetThemeColorBlendShade3fv(TH_WIRE, TH_BONE_POSE, 0.15f, 0, NO_ALPHA(g_theme.bone_pose_active_unselect_color));
+ UI_GetThemeColor3fv(TH_TEXT_HI, NO_ALPHA(g_theme.text_hi_color));
+ UI_GetThemeColor3fv(TH_TEXT, NO_ALPHA(g_theme.text_color));
+ UI_GetThemeColor3fv(TH_VERTEX_SELECT, NO_ALPHA(g_theme.vertex_select_color));
+ UI_GetThemeColor3fv(TH_VERTEX, NO_ALPHA(g_theme.vertex_color));
+
+#undef NO_ALPHA
+}
+
+static const float *get_bone_solid_color(
+ const EditBone *UNUSED(eBone), const bPoseChannel *pchan, const bArmature *arm,
+ const int boneflag, const short constflag)
+{
+ if (g_theme.const_color)
+ return g_theme.bone_solid_color;
+
+ if (arm->flag & ARM_POSEMODE) {
+ static float disp_color[4];
+ copy_v4_v4(disp_color, pchan->draw_data->solid_color);
+ set_pchan_color(PCHAN_COLOR_SOLID, boneflag, constflag, disp_color);
+ return disp_color;
+ }
+
+ return g_theme.bone_solid_color;
+}
+
+static const float *get_bone_solid_with_consts_color(
+ const EditBone *eBone, const bPoseChannel *pchan, const bArmature *arm,
+ const int boneflag, const short constflag)
+{
+ if (g_theme.const_color)
+ return g_theme.bone_solid_color;
+
+ const float *col = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
+
+ static float consts_color[4];
+ if (set_pchan_color(PCHAN_COLOR_CONSTS, boneflag, constflag, consts_color)) {
+ interp_v3_v3v3(consts_color, col, consts_color, 0.5f);
+ }
+ else {
+ copy_v4_v4(consts_color, col);
+ }
+ return consts_color;
+}
+
+static float get_bone_wire_thickness(int boneflag)
+{
+ if (g_theme.const_color)
+ return g_theme.const_wire;
+ else if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED))
+ return 2.0f;
+ else
+ return 1.0f;
+}
+
+static const float *get_bone_wire_color(
+ const EditBone *eBone, const bPoseChannel *pchan, const bArmature *arm,
+ const int boneflag, const short constflag)
+{
+ static float disp_color[4];
+
+ if (g_theme.const_color) {
+ copy_v3_v3(disp_color, g_theme.const_color);
+ }
+ else if (eBone) {
+ if (boneflag & BONE_SELECTED) {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3(disp_color, g_theme.edge_select_color);
+ }
+ else {
+ copy_v3_v3(disp_color, g_theme.bone_select_color);
+ }
+ }
+ else {
+ if (boneflag & BONE_DRAW_ACTIVE) {
+ copy_v3_v3(disp_color, g_theme.bone_active_unselect_color);
+ }
+ else {
+ copy_v3_v3(disp_color, g_theme.wire_edit_color);
+ }
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ copy_v4_v4(disp_color, pchan->draw_data->wire_color);
+ set_pchan_color(PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color);
+ }
+ else {
+ copy_v3_v3(disp_color, g_theme.vertex_color);
+ }
+
+ disp_color[3] = get_bone_wire_thickness(boneflag);
+
+ return disp_color;
+}
+
+#define HINT_MUL 0.5f
+#define HINT_SHADE 0.2f
+
+static void bone_hint_color_shade(float hint_color[4], const float color[4])
+{
+ mul_v3_v3fl(hint_color, color, HINT_MUL);
+ cp_shade_color3f(hint_color, -HINT_SHADE);
+ hint_color[3] = 1.0f;
+}
+
+static const float *get_bone_hint_color(
+ const EditBone *eBone, const bPoseChannel *pchan, const bArmature *arm,
+ const int boneflag, const short constflag)
+{
+ static float hint_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ if (g_theme.const_color) {
+ bone_hint_color_shade(hint_color, g_theme.bone_solid_color);
+ }
+ else {
+ const float *wire_color = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+ bone_hint_color_shade(hint_color, wire_color);
+ }
+
+ return hint_color;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Helper Utils
+ * \{ */
+
+static void pchan_draw_data_init(bPoseChannel *pchan)
+{
+ if (pchan->draw_data != NULL) {
+ if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) {
+ MEM_SAFE_FREE(pchan->draw_data);
+ }
+ }
+
+ if (pchan->draw_data == NULL) {
+ pchan->draw_data = MEM_mallocN(sizeof(*pchan->draw_data) + sizeof(Mat4) * pchan->bone->segments, __func__);
+ pchan->draw_data->bbone_matrix_len = pchan->bone->segments;
+ }
+}
+
+static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *pchan)
+{
+ float s[4][4], ebmat[4][4];
+ float length;
+ float (*bone_mat)[4];
+ float (*disp_mat)[4];
+ float (*disp_tail_mat)[4];
+
+ /* TODO : This should be moved to depsgraph or armature refresh
+ * and not be tight to the draw pass creation.
+ * This would refresh armature without invalidating the draw cache */
+ if (pchan) {
+ length = pchan->bone->length;
+ bone_mat = pchan->pose_mat;
+ disp_mat = pchan->disp_mat;
+ disp_tail_mat = pchan->disp_tail_mat;
+ }
+ else {
+ eBone->length = len_v3v3(eBone->tail, eBone->head);
+ ED_armature_ebone_to_mat4(eBone, ebmat);
+
+ length = eBone->length;
+ bone_mat = ebmat;
+ disp_mat = eBone->disp_mat;
+ disp_tail_mat = eBone->disp_tail_mat;
+ }
+
+ scale_m4_fl(s, length);
+ mul_m4_m4m4(disp_mat, bone_mat, s);
+ copy_m4_m4(disp_tail_mat, disp_mat);
+ translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
+}
+
+/* compute connected child pointer for B-Bone drawing */
+static void edbo_compute_bbone_child(bArmature *arm)
+{
+ EditBone *eBone;
+
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ eBone->bbone_child = NULL;
+ }
+
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ eBone->parent->bbone_child = eBone;
+ }
+ }
+}
+
+/* A version of b_bone_spline_setup() for previewing editmode curve settings. */
+static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_SUBDIV][4][4])
+{
+ BBoneSplineParameters param;
+ EditBone *prev, *next;
+ float imat[4][4], bonemat[4][4];
+ float tmp[3];
+
+ memset(&param, 0, sizeof(param));
+
+ param.segments = ebone->segments;
+ param.length = ebone->length;
+
+ /* Get "next" and "prev" bones - these are used for handle calculations. */
+ if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
+ /* Use connected parent. */
+ if (ebone->flag & BONE_CONNECTED) {
+ prev = ebone->parent;
+ }
+ else {
+ prev = NULL;
+ }
+ }
+ else {
+ prev = ebone->bbone_prev;
+ }
+
+ if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
+ /* Use connected child. */
+ next = ebone->bbone_child;
+ }
+ else {
+ next = ebone->bbone_next;
+ }
+
+ /* compute handles from connected bones */
+ if (prev || next) {
+ ED_armature_ebone_to_mat4(ebone, imat);
+ invert_m4(imat);
+
+ if (prev) {
+ param.use_prev = true;
+
+ if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+ zero_v3(param.prev_h);
+ }
+ else if (ebone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
+ sub_v3_v3v3(tmp, prev->tail, prev->head);
+ sub_v3_v3v3(tmp, ebone->head, tmp);
+ mul_v3_m4v3(param.prev_h, imat, tmp);
+ }
+ else {
+ param.prev_bbone = (prev->segments > 1);
+
+ mul_v3_m4v3(param.prev_h, imat, prev->head);
+ }
+
+ if (!param.prev_bbone) {
+ ED_armature_ebone_to_mat4(prev, bonemat);
+ mul_m4_m4m4(param.prev_mat, imat, bonemat);
+ }
+ }
+
+ if (next) {
+ param.use_next = true;
+
+ if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+ copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
+ }
+ else if (ebone->bbone_next_type == BBONE_HANDLE_TANGENT) {
+ sub_v3_v3v3(tmp, next->tail, next->head);
+ add_v3_v3v3(tmp, ebone->tail, tmp);
+ mul_v3_m4v3(param.next_h, imat, tmp);
+ }
+ else {
+ param.next_bbone = (next->segments > 1);
+
+ mul_v3_m4v3(param.next_h, imat, next->tail);
+ }
+
+ ED_armature_ebone_to_mat4(next, bonemat);
+ mul_m4_m4m4(param.next_mat, imat, bonemat);
+ }
+ }
+
+ param.ease1 = ebone->ease1;
+ param.ease2 = ebone->ease2;
+ param.roll1 = ebone->roll1;
+ param.roll2 = ebone->roll2;
+
+ if (prev && (ebone->flag & BONE_ADD_PARENT_END_ROLL)) {
+ param.roll1 += prev->roll2;
+ }
+
+ param.scaleIn = ebone->scaleIn;
+ param.scaleOut = ebone->scaleOut;
+
+ param.curveInX = ebone->curveInX;
+ param.curveInY = ebone->curveInY;
+
+ param.curveOutX = ebone->curveOutX;
+ param.curveOutY = ebone->curveOutY;
+
+ ebone->segments = BKE_compute_b_bone_spline(&param, (Mat4 *)result_array);
+}
+
+static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pchan)
+{
+ float s[4][4], ebmat[4][4];
+ float length, xwidth, zwidth;
+ float (*bone_mat)[4];
+ short bbone_segments;
+
+ /* TODO : This should be moved to depsgraph or armature refresh
+ * and not be tight to the draw pass creation.
+ * This would refresh armature without invalidating the draw cache */
+ if (pchan) {
+ length = pchan->bone->length;
+ xwidth = pchan->bone->xwidth;
+ zwidth = pchan->bone->zwidth;
+ bone_mat = pchan->pose_mat;
+ bbone_segments = pchan->bone->segments;
+ }
+ else {
+ eBone->length = len_v3v3(eBone->tail, eBone->head);
+ ED_armature_ebone_to_mat4(eBone, ebmat);
+
+ length = eBone->length;
+ xwidth = eBone->xwidth;
+ zwidth = eBone->zwidth;
+ bone_mat = ebmat;
+ bbone_segments = eBone->segments;
+ }
+
+ size_to_mat4(s, (const float[3]){xwidth, length / bbone_segments, zwidth});
+
+ /* Compute BBones segment matrices... */
+ /* Note that we need this even for one-segment bones, because box drawing need specific weirdo matrix for the box,
+ * that we cannot use to draw end points & co. */
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ if (bbone_segments > 1) {
+ if (bbone_segments == pchan->runtime.bbone_segments) {
+ memcpy(bbones_mat, pchan->runtime.bbone_pose_mats, sizeof(Mat4) * bbone_segments);
+ }
+ else {
+ b_bone_spline_setup(pchan, false, bbones_mat);
+ }
+
+ for (int i = bbone_segments; i--; bbones_mat++) {
+ mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s);
+ mul_m4_m4m4(bbones_mat->mat, bone_mat, bbones_mat->mat);
+ }
+ }
+ else {
+ mul_m4_m4m4(bbones_mat->mat, bone_mat, s);
+ }
+ }
+ else {
+ float (*bbones_mat)[4][4] = eBone->disp_bbone_mat;
+
+ if (bbone_segments > 1) {
+ ebone_spline_preview(eBone, bbones_mat);
+
+ for (int i = bbone_segments; i--; bbones_mat++) {
+ mul_m4_m4m4(*bbones_mat, *bbones_mat, s);
+ mul_m4_m4m4(*bbones_mat, bone_mat, *bbones_mat);
+ }
+ }
+ else {
+ mul_m4_m4m4(*bbones_mat, bone_mat, s);
+ }
+ }
+
+ /* Grrr... We need default display matrix to draw end points, axes, etc. :( */
+ draw_bone_update_disp_matrix_default(eBone, pchan);
+}
+
+static void draw_bone_update_disp_matrix_custom(bPoseChannel *pchan)
+{
+ float s[4][4];
+ float length;
+ float (*bone_mat)[4];
+ float (*disp_mat)[4];
+ float (*disp_tail_mat)[4];
+
+ /* See TODO above */
+ length = PCHAN_CUSTOM_DRAW_SIZE(pchan);
+ bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
+ disp_mat = pchan->disp_mat;
+ disp_tail_mat = pchan->disp_tail_mat;
+
+ scale_m4_fl(s, length);
+ mul_m4_m4m4(disp_mat, bone_mat, s);
+ copy_m4_m4(disp_tail_mat, disp_mat);
+ translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
+}
+
+static void draw_axes(EditBone *eBone, bPoseChannel *pchan)
+{
+ float final_col[4];
+ const float *col = (g_theme.const_color) ? g_theme.const_color :
+ (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? g_theme.text_hi_color : g_theme.text_color;
+ copy_v4_v4(final_col, col);
+ /* Mix with axes color. */
+ final_col[3] = (g_theme.const_color) ? 1.0 : (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? 0.3 : 0.8;
+ drw_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_mat), final_col);
+}
+
+static void draw_points(
+ const EditBone *eBone, const bPoseChannel *pchan, const bArmature *arm,
+ const int boneflag, const short constflag,
+ const int select_id)
+{
+ float col_solid_root[4], col_solid_tail[4], col_wire_root[4], col_wire_tail[4];
+ float col_hint_root[4], col_hint_tail[4];
+
+ copy_v4_v4(col_solid_root, g_theme.bone_solid_color);
+ copy_v4_v4(col_solid_tail, g_theme.bone_solid_color);
+ copy_v4_v4(col_wire_root, (g_theme.const_color) ? g_theme.const_color : g_theme.vertex_color);
+ copy_v4_v4(col_wire_tail, (g_theme.const_color) ? g_theme.const_color : g_theme.vertex_color);
+
+ const bool is_envelope_draw = (arm->drawtype == ARM_ENVELOPE);
+ static const float envelope_ignore = -1.0f;
+
+ col_wire_tail[3] = col_wire_root[3] = get_bone_wire_thickness(boneflag);
+
+ /* Edit bone points can be selected */
+ if (eBone) {
+ if (eBone->flag & BONE_ROOTSEL) {
+ copy_v3_v3(col_wire_root, g_theme.vertex_select_color);
+ }
+ if (eBone->flag & BONE_TIPSEL) {
+ copy_v3_v3(col_wire_tail, g_theme.vertex_select_color);
+ }
+ }
+ else if (arm->flag & ARM_POSEMODE) {
+ const float *solid_color = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
+ const float *wire_color = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+ copy_v4_v4(col_wire_tail, wire_color);
+ copy_v4_v4(col_wire_root, wire_color);
+ copy_v4_v4(col_solid_tail, solid_color);
+ copy_v4_v4(col_solid_root, solid_color);
+ }
+
+ bone_hint_color_shade(col_hint_root, (g_theme.const_color) ? col_solid_root : col_wire_root);
+ bone_hint_color_shade(col_hint_tail, (g_theme.const_color) ? col_solid_tail : col_wire_tail);
+
+ /* Draw root point if we are not connected and parent are not hidden */
+ if ((BONE_FLAG(eBone, pchan) & BONE_CONNECTED) == 0) {
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_ROOT);
+ }
+
+ if (eBone) {
+ if (!((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent))) {
+ if (is_envelope_draw) {
+ drw_shgroup_bone_envelope(
+ eBone->disp_mat, col_solid_root, col_hint_root, col_wire_root,
+ &eBone->rad_head, &envelope_ignore);
+ }
+ else {
+ drw_shgroup_bone_point(eBone->disp_mat, col_solid_root, col_hint_root, col_wire_root);
+ }
+ }
+ }
+ else {
+ Bone *bone = pchan->bone;
+ if (!((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))) {
+ if (is_envelope_draw) {
+ drw_shgroup_bone_envelope(
+ pchan->disp_mat, col_solid_root, col_hint_root, col_wire_root,
+ &bone->rad_head, &envelope_ignore);
+ }
+ else {
+ drw_shgroup_bone_point(pchan->disp_mat, col_solid_root, col_hint_root, col_wire_root);
+ }
+ }
+ }
+ }
+
+ /* Draw tip point */
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_TIP);
+ }
+
+ if (is_envelope_draw) {
+ const float *rad_tail = eBone ? &eBone->rad_tail : &pchan->bone->rad_tail;
+ drw_shgroup_bone_envelope(
+ BONE_VAR(eBone, pchan, disp_mat), col_solid_tail, col_hint_tail, col_wire_tail,
+ &envelope_ignore, rad_tail);
+ }
+ else {
+ drw_shgroup_bone_point(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail, col_hint_tail, col_wire_tail);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw Bones
+ * \{ */
+
+static void draw_bone_custom_shape(
+ EditBone *eBone, bPoseChannel *pchan, bArmature *arm,
+ const int boneflag, const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(eBone, pchan, arm, boneflag, constflag);
+ const float (*disp_mat)[4] = pchan->disp_mat;
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if ((boneflag & BONE_DRAWWIRE) == 0) {
+ drw_shgroup_bone_custom_solid(disp_mat, col_solid, col_hint, col_wire, pchan->custom);
+ }
+ else {
+ drw_shgroup_bone_custom_wire(disp_mat, col_wire, pchan->custom);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+}
+
+static void draw_bone_envelope(
+ EditBone *eBone, bPoseChannel *pchan, bArmature *arm,
+ const int boneflag, const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(eBone, pchan, arm, boneflag, constflag);
+
+ float *rad_head, *rad_tail, *distance;
+ if (eBone) {
+ rad_tail = &eBone->rad_tail;
+ distance = &eBone->dist;
+ rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail : &eBone->rad_head;
+ }
+ else {
+ rad_tail = &pchan->bone->rad_tail;
+ distance = &pchan->bone->dist;
+ rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail : &pchan->bone->rad_head;
+ }
+
+ if ((select_id == -1) &&
+ (boneflag & BONE_NO_DEFORM) == 0 &&
+ ((boneflag & BONE_SELECTED) || (eBone && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL)))))
+ {
+ drw_shgroup_bone_envelope_distance(BONE_VAR(eBone, pchan, disp_mat), rad_head, rad_tail, distance);
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ drw_shgroup_bone_envelope(
+ BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire,
+ rad_head, rad_tail);
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ draw_points(eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+static void draw_bone_line(
+ EditBone *eBone, bPoseChannel *pchan, bArmature *arm,
+ const int boneflag, const short constflag, const int select_id)
+{
+ const float *col_bone = get_bone_solid_with_consts_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+ const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float *col_head = no_display;
+ const float *col_tail = col_bone;
+
+ if (eBone) {
+ if (eBone->flag & BONE_TIPSEL) {
+ col_tail = g_theme.vertex_select_color;
+ }
+ if (boneflag & BONE_SELECTED) {
+ col_bone = g_theme.edge_select_color;
+ }
+ col_wire = g_theme.wire_color;
+ }
+
+ /* Draw root point if we are not connected and parent are not hidden */
+ if ((BONE_FLAG(eBone, pchan) & BONE_CONNECTED) == 0) {
+ if (eBone && !(eBone->parent && !EBONE_VISIBLE(arm, eBone->parent))) {
+ col_head = (eBone->flag & BONE_ROOTSEL) ? g_theme.vertex_select_color : col_bone;
+ }
+ else if (pchan) {
+ Bone *bone = pchan->bone;
+ if (!(bone->parent && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))) {
+ col_head = col_bone;
+ }
+ }
+ }
+
+ if (g_theme.const_color != NULL) {
+ col_wire = no_display; /* actually shrink the display. */
+ col_bone = col_head = col_tail = g_theme.const_color;
+ }
+
+ if (select_id == -1) {
+ /* Not in selection mode, draw everything at once. */
+ drw_shgroup_bone_stick(BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, col_head, col_tail);
+ }
+ else {
+ /* In selection mode, draw bone, root and tip separately. */
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ drw_shgroup_bone_stick(BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, no_display, no_display);
+
+ if (col_head[3] > 0.0f) {
+ DRW_select_load_id(select_id | BONESEL_ROOT);
+ drw_shgroup_bone_stick(BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, col_head, no_display);
+ }
+
+ DRW_select_load_id(select_id | BONESEL_TIP);
+ drw_shgroup_bone_stick(BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, no_display, col_tail);
+
+ DRW_select_load_id(-1);
+ }
+}
+
+static void draw_bone_wire(
+ EditBone *eBone, bPoseChannel *pchan, bArmature *arm,
+ const int boneflag, const short constflag,
+ const int select_id)
+{
+ const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ BLI_assert(bbones_mat != NULL);
+
+ for (int i = pchan->bone->segments; i--; bbones_mat++) {
+ drw_shgroup_bone_wire(bbones_mat->mat, col_wire);
+ }
+ }
+ else if (eBone) {
+ for (int i = 0; i < eBone->segments; i++) {
+ drw_shgroup_bone_wire(eBone->disp_bbone_mat[i], col_wire);
+ }
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ if (eBone) {
+ draw_points(eBone, pchan, arm, boneflag, constflag, select_id);
+ }
+}
+
+static void draw_bone_box(
+ EditBone *eBone, bPoseChannel *pchan, bArmature *arm,
+ const int boneflag, const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ if (pchan) {
+ Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+ BLI_assert(bbones_mat != NULL);
+
+ for (int i = pchan->bone->segments; i--; bbones_mat++) {
+ drw_shgroup_bone_box(bbones_mat->mat, col_solid, col_hint, col_wire);
+ }
+ }
+ else if (eBone) {
+ for (int i = 0; i < eBone->segments; i++) {
+ drw_shgroup_bone_box(eBone->disp_bbone_mat[i], col_solid, col_hint, col_wire);
+ }
+ }
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ if (eBone) {
+ draw_points(eBone, pchan, arm, boneflag, constflag, select_id);
+ }
+}
+
+static void draw_bone_octahedral(
+ EditBone *eBone, bPoseChannel *pchan, bArmature *arm,
+ const int boneflag, const short constflag,
+ const int select_id)
+{
+ const float *col_solid = get_bone_solid_with_consts_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_wire = get_bone_wire_color(eBone, pchan, arm, boneflag, constflag);
+ const float *col_hint = get_bone_hint_color(eBone, pchan, arm, boneflag, constflag);
+
+ if (select_id != -1) {
+ DRW_select_load_id(select_id | BONESEL_BONE);
+ }
+
+ drw_shgroup_bone_octahedral(BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire);
+
+ if (select_id != -1) {
+ DRW_select_load_id(-1);
+ }
+
+ draw_points(eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw Degrees of Freedom
+ * \{ */
+
+static void draw_bone_dofs(bPoseChannel *pchan)
+{
+ float final_bonemat[4][4], posetrans[4][4], mat[4][4];
+ float amin[2], amax[2], xminmax[2], zminmax[2];
+ float col_sphere[4] = {0.25f, 0.25f, 0.25f, 0.25f};
+ float col_lines[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ float col_xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ float col_zaxis[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+
+ if (g_data.passes.bone_envelope == NULL) {
+ return;
+ }
+
+ if (g_data.bone_dof_sphere == NULL) {
+ g_data.bone_dof_lines = shgroup_instance_bone_dof(g_data.passes.bone_wire, DRW_cache_bone_dof_lines_get());
+ g_data.bone_dof_sphere = shgroup_instance_bone_dof(g_data.passes.bone_envelope, DRW_cache_bone_dof_sphere_get());
+ DRW_shgroup_state_enable(g_data.bone_dof_sphere, DRW_STATE_BLEND);
+ DRW_shgroup_state_disable(g_data.bone_dof_sphere, DRW_STATE_CULL_FRONT);
+ }
+
+ /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
+ xminmax[0] = sinf(pchan->limitmin[0] * 0.5f);
+ xminmax[1] = sinf(pchan->limitmax[0] * 0.5f);
+ zminmax[0] = sinf(pchan->limitmin[2] * 0.5f);
+ zminmax[1] = sinf(pchan->limitmax[2] * 0.5f);
+
+ unit_m4(posetrans);
+ translate_m4(posetrans, pchan->pose_mat[3][0], pchan->pose_mat[3][1], pchan->pose_mat[3][2]);
+ /* in parent-bone pose space... */
+ if (pchan->parent) {
+ copy_m4_m4(mat, pchan->parent->pose_mat);
+ mat[3][0] = mat[3][1] = mat[3][2] = 0.0f;
+ mul_m4_m4m4(posetrans, posetrans, mat);
+ }
+ /* ... but own restspace */
+ mul_m4_m4m3(posetrans, posetrans, pchan->bone->bone_mat);
+
+ float scale = pchan->bone->length * pchan->size[1];
+ scale_m4_fl(mat, scale);
+ mat[1][1] = -mat[1][1];
+ mul_m4_m4m4(posetrans, posetrans, mat);
+
+ /* into world space. */
+ mul_m4_m4m4(final_bonemat, g_data.ob->obmat, posetrans);
+
+ if ((pchan->ikflag & BONE_IK_XLIMIT) &&
+ (pchan->ikflag & BONE_IK_ZLIMIT))
+ {
+ amin[0] = xminmax[0];
+ amax[0] = xminmax[1];
+ amin[1] = zminmax[0];
+ amax[1] = zminmax[1];
+ DRW_shgroup_call_dynamic_add(g_data.bone_dof_sphere, final_bonemat, col_sphere, amin, amax);
+ DRW_shgroup_call_dynamic_add(g_data.bone_dof_lines, final_bonemat, col_lines, amin, amax);
+ }
+ if (pchan->ikflag & BONE_IK_XLIMIT) {
+ amin[0] = xminmax[0];
+ amax[0] = xminmax[1];
+ amin[1] = amax[1] = 0.0f;
+ DRW_shgroup_call_dynamic_add(g_data.bone_dof_lines, final_bonemat, col_xaxis, amin, amax);
+ }
+ if (pchan->ikflag & BONE_IK_ZLIMIT) {
+ amin[1] = zminmax[0];
+ amax[1] = zminmax[1];
+ amin[0] = amax[0] = 0.0f;
+ DRW_shgroup_call_dynamic_add(g_data.bone_dof_lines, final_bonemat, col_zaxis, amin, amax);
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw Relationships
+ * \{ */
+
+static void pchan_draw_ik_lines(bPoseChannel *pchan, const bool only_temp, const int constflag)
+{
+ bConstraint *con;
+ bPoseChannel *parchan;
+ float *line_start = NULL, *line_end = NULL;
+
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->enforce == 0.0f)
+ continue;
+
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+ int segcount = 0;
+
+ /* if only_temp, only draw if it is a temporary ik-chain */
+ if (only_temp && !(data->flag & CONSTRAINT_IK_TEMP))
+ continue;
+
+ /* exclude tip from chain? */
+ parchan = ((data->flag & CONSTRAINT_IK_TIP) == 0) ? pchan->parent : pchan;
+ line_start = parchan->pose_tail;
+
+ /* Find the chain's root */
+ while (parchan->parent) {
+ segcount++;
+ if (segcount == data->rootbone || segcount > 255) {
+ break; /* 255 is weak */
+ }
+ parchan = parchan->parent;
+ }
+
+ if (parchan) {
+ line_end = parchan->pose_head;
+
+ if (constflag & PCHAN_HAS_TARGET)
+ drw_shgroup_bone_ik_lines(line_start, line_end);
+ else
+ drw_shgroup_bone_ik_no_target_lines(line_start, line_end);
+ }
+ break;
+ }
+ case CONSTRAINT_TYPE_SPLINEIK:
+ {
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+ int segcount = 0;
+
+ /* don't draw if only_temp, as Spline IK chains cannot be temporary */
+ if (only_temp)
+ continue;
+
+ parchan = pchan;
+ line_start = parchan->pose_tail;
+
+ /* Find the chain's root */
+ while (parchan->parent) {
+ segcount++;
+ /* FIXME: revise the breaking conditions */
+ if (segcount == data->chainlen || segcount > 255) break; /* 255 is weak */
+ parchan = parchan->parent;
+ }
+ /* Only draw line in case our chain is more than one bone long! */
+ if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
+ line_end = parchan->pose_head;
+ drw_shgroup_bone_ik_spline_lines(line_start, line_end);
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void draw_bone_relations(
+ EditBone *ebone, bPoseChannel *pchan, bArmature *arm,
+ const int boneflag, const short constflag, const bool do_relations)
+{
+ if (g_data.passes.relationship_lines) {
+ if (ebone && ebone->parent) {
+ if (do_relations) {
+ /* Always draw for unconnected bones, regardless of selection,
+ * since riggers will want to know about the links between bones
+ */
+ if ((boneflag & BONE_CONNECTED) == 0) {
+ drw_shgroup_bone_relationship_lines(ebone->head, ebone->parent->tail);
+ }
+ }
+ }
+ else if (pchan && pchan->parent) {
+ if (do_relations) {
+ /* Only draw if bone or its parent is selected - reduces viewport complexity with complex rigs */
+ if ((boneflag & BONE_SELECTED) ||
+ (pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED)))
+ {
+ if ((boneflag & BONE_CONNECTED) == 0) {
+ drw_shgroup_bone_relationship_lines(pchan->pose_head, pchan->parent->pose_tail);
+ }
+ }
+ }
+
+ /* Draw a line to IK root bone if bone is selected. */
+ if (arm->flag & ARM_POSEMODE) {
+ if (constflag & (PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK)) {
+ if (boneflag & BONE_SELECTED) {
+ pchan_draw_ik_lines(pchan, !do_relations, constflag);
+ }
+ }
+ }
+ }
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Main Draw Loops
+ * \{ */
+
+static void draw_armature_edit(Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ EditBone *eBone;
+ bArmature *arm = ob->data;
+ int index;
+ const bool is_select = DRW_state_is_select();
+
+ update_color(ob, NULL);
+ edbo_compute_bbone_child(arm);
+
+ const bool show_text = DRW_state_show_text();
+ const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
+
+ for (eBone = arm->edbo->first, index = ob->select_color; eBone; eBone = eBone->next, index += 0x10000) {
+ if (eBone->layer & arm->layer) {
+ if ((eBone->flag & BONE_HIDDEN_A) == 0) {
+ const int select_id = is_select ? index : (uint)-1;
+
+ const short constflag = 0;
+
+ /* catch exception for bone with hidden parent */
+ int boneflag = eBone->flag;
+ if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) {
+ boneflag &= ~BONE_CONNECTED;
+ }
+
+ /* set temporary flag for drawing bone as active, but only if selected */
+ if (eBone == arm->act_edbone) {
+ boneflag |= BONE_DRAW_ACTIVE;
+ }
+
+ draw_bone_relations(eBone, NULL, arm, boneflag, constflag, show_relations);
+
+ if (arm->drawtype == ARM_ENVELOPE) {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_envelope(eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_LINE) {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_line(eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_WIRE) {
+ draw_bone_update_disp_matrix_bbone(eBone, NULL);
+ draw_bone_wire(eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_B_BONE) {
+ draw_bone_update_disp_matrix_bbone(eBone, NULL);
+ draw_bone_box(eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+ else {
+ draw_bone_update_disp_matrix_default(eBone, NULL);
+ draw_bone_octahedral(eBone, NULL, arm, boneflag, constflag, select_id);
+ }
+
+ /* Draw names of bone */
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ uchar color[4];
+ UI_GetThemeColor4ubv((eBone->flag & BONE_SELECTED) ? TH_TEXT_HI : TH_TEXT, color);
+
+ float vec[3];
+ mid_v3_v3v3(vec, eBone->head, eBone->tail);
+ mul_m4_v3(ob->obmat, vec);
+
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ DRW_text_cache_add(
+ dt, vec, eBone->name, strlen(eBone->name),
+ 10, 0, DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, color);
+ }
+
+ /* Draw additional axes */
+ if (arm->flag & ARM_DRAWAXES) {
+ draw_axes(eBone, NULL);
+ }
+ }
+ }
+ }
+}
+
+/* if const_color is NULL do pose mode coloring */
+static void draw_armature_pose(Object *ob, const float const_color[4])
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ int index = -1;
+ Bone *bone;
+
+ update_color(ob, const_color);
+
+ /* We can't safely draw non-updated pose, might contain NULL bone pointers... */
+ if (ob->pose->flag & POSE_RECALC) {
+ return;
+ }
+
+ // if (!(base->flag & OB_FROMDUPLI)) // TODO
+ {
+ if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) {
+ arm->flag |= ARM_POSEMODE;
+ }
+
+ if (arm->flag & ARM_POSEMODE) {
+ index = ob->select_color;
+ }
+ }
+
+ const bool is_pose_select = (arm->flag & ARM_POSEMODE) && DRW_state_is_select();
+ const bool show_text = DRW_state_show_text();
+ const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
+
+ /* being set below */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bone = pchan->bone;
+
+ /* bone must be visible */
+ if ((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) {
+ if (bone->layer & arm->layer) {
+ const int select_id = is_pose_select ? index : (uint)-1;
+
+ const short constflag = pchan->constflag;
+
+ pchan_draw_data_init(pchan);
+
+ if (const_color) {
+ /* keep color */
+ }
+ else {
+ /* set color-set to use */
+ set_pchan_colorset(ob, pchan);
+ }
+
+ int boneflag = bone->flag;
+ /* catch exception for bone with hidden parent */
+ boneflag = bone->flag;
+ if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
+ boneflag &= ~BONE_CONNECTED;
+ }
+
+ /* set temporary flag for drawing bone as active, but only if selected */
+ if (bone == arm->act_bone)
+ boneflag |= BONE_DRAW_ACTIVE;
+
+ draw_bone_relations(NULL, pchan, arm, boneflag, constflag, show_relations);
+
+ if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
+ draw_bone_update_disp_matrix_custom(pchan);
+ draw_bone_custom_shape(NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_ENVELOPE) {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_envelope(NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_LINE) {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_line(NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_WIRE) {
+ draw_bone_update_disp_matrix_bbone(NULL, pchan);
+ draw_bone_wire(NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else if (arm->drawtype == ARM_B_BONE) {
+ draw_bone_update_disp_matrix_bbone(NULL, pchan);
+ draw_bone_box(NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+ else {
+ draw_bone_update_disp_matrix_default(NULL, pchan);
+ draw_bone_octahedral(NULL, pchan, arm, boneflag, constflag, select_id);
+ }
+
+ if (!is_pose_select && show_relations &&
+ (arm->flag & ARM_POSEMODE) &&
+ (bone->flag & BONE_SELECTED) &&
+ ((ob->base_flag & BASE_FROMDUPLI) == 0) &&
+ (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT)))
+ {
+ draw_bone_dofs(pchan);
+ }
+
+ /* Draw names of bone */
+ if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+ uchar color[4];
+ UI_GetThemeColor4ubv((arm->flag & ARM_POSEMODE) &&
+ (bone->flag & BONE_SELECTED) ? TH_TEXT_HI : TH_TEXT, color);
+ float vec[3];
+ mid_v3_v3v3(vec, pchan->pose_head, pchan->pose_tail);
+ mul_m4_v3(ob->obmat, vec);
+
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ DRW_text_cache_add(
+ dt, vec, pchan->name, strlen(pchan->name),
+ 10, 0, DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, color);
+ }
+
+ /* Draw additional axes */
+ if (arm->flag & ARM_DRAWAXES) {
+ draw_axes(NULL, pchan);
+ }
+ }
+ }
+ if (is_pose_select) {
+ index += 0x10000;
+ }
+ }
+
+ arm->flag &= ~ARM_POSEMODE;
+}
+
+/**
+ * This function set the object space to use for all subsequent `DRW_shgroup_bone_*` calls.
+ */
+static void drw_shgroup_armature(Object *ob, DRWArmaturePasses passes, bool transp)
+{
+ memset(&g_data, 0x0, sizeof(g_data));
+ g_data.ob = ob;
+ g_data.passes = passes;
+ g_data.transparent = transp;
+ memset(&g_color, 0x0, sizeof(g_color));
+}
+
+void DRW_shgroup_armature_object(Object *ob, ViewLayer *view_layer, DRWArmaturePasses passes)
+{
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+ passes.bone_envelope = NULL; /* Don't do envelope distance in object mode. */
+ drw_shgroup_armature(ob, passes, false);
+ draw_armature_pose(ob, color);
+}
+
+void DRW_shgroup_armature_pose(Object *ob, DRWArmaturePasses passes, bool transp)
+{
+ drw_shgroup_armature(ob, passes, transp);
+ draw_armature_pose(ob, NULL);
+}
+
+void DRW_shgroup_armature_edit(Object *ob, DRWArmaturePasses passes, bool transp)
+{
+ drw_shgroup_armature(ob, passes, transp);
+ draw_armature_edit(ob);
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
new file mode 100644
index 00000000000..ccb33b7b0fd
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache.c
@@ -0,0 +1,3717 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_cache.c
+ * \ingroup draw
+ */
+
+
+#include "DNA_scene_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_lattice_types.h"
+
+#include "UI_resources.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "BKE_object_deform.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_batch_utils.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "draw_cache.h"
+#include "draw_cache_impl.h"
+
+/* Batch's only (free'd as an array) */
+static struct DRWShapeCache {
+ GPUBatch *drw_single_vertice;
+ GPUBatch *drw_cursor;
+ GPUBatch *drw_cursor_only_circle;
+ GPUBatch *drw_fullscreen_quad;
+ GPUBatch *drw_fullscreen_quad_texcoord;
+ GPUBatch *drw_quad;
+ GPUBatch *drw_grid;
+ GPUBatch *drw_sphere;
+ GPUBatch *drw_screenspace_circle;
+ GPUBatch *drw_plain_axes;
+ GPUBatch *drw_single_arrow;
+ GPUBatch *drw_cube;
+ GPUBatch *drw_circle;
+ GPUBatch *drw_square;
+ GPUBatch *drw_line;
+ GPUBatch *drw_line_endpoints;
+ GPUBatch *drw_empty_cube;
+ GPUBatch *drw_empty_sphere;
+ GPUBatch *drw_empty_cylinder;
+ GPUBatch *drw_empty_capsule_body;
+ GPUBatch *drw_empty_capsule_cap;
+ GPUBatch *drw_empty_cone;
+ GPUBatch *drw_arrows;
+ GPUBatch *drw_axis_names;
+ GPUBatch *drw_image_plane;
+ GPUBatch *drw_image_plane_wire;
+ GPUBatch *drw_field_wind;
+ GPUBatch *drw_field_force;
+ GPUBatch *drw_field_vortex;
+ GPUBatch *drw_field_tube_limit;
+ GPUBatch *drw_field_cone_limit;
+ GPUBatch *drw_lamp;
+ GPUBatch *drw_lamp_shadows;
+ GPUBatch *drw_lamp_sunrays;
+ GPUBatch *drw_lamp_area_square;
+ GPUBatch *drw_lamp_area_disk;
+ GPUBatch *drw_lamp_hemi;
+ GPUBatch *drw_lamp_spot;
+ GPUBatch *drw_lamp_spot_volume;
+ GPUBatch *drw_lamp_spot_square;
+ GPUBatch *drw_lamp_spot_square_volume;
+ GPUBatch *drw_speaker;
+ GPUBatch *drw_lightprobe_cube;
+ GPUBatch *drw_lightprobe_planar;
+ GPUBatch *drw_lightprobe_grid;
+ GPUBatch *drw_bone_octahedral;
+ GPUBatch *drw_bone_octahedral_wire;
+ GPUBatch *drw_bone_box;
+ GPUBatch *drw_bone_box_wire;
+ GPUBatch *drw_bone_wire_wire;
+ GPUBatch *drw_bone_envelope;
+ GPUBatch *drw_bone_envelope_outline;
+ GPUBatch *drw_bone_point;
+ GPUBatch *drw_bone_point_wire;
+ GPUBatch *drw_bone_stick;
+ GPUBatch *drw_bone_arrows;
+ GPUBatch *drw_bone_dof_sphere;
+ GPUBatch *drw_bone_dof_lines;
+ GPUBatch *drw_camera;
+ GPUBatch *drw_camera_frame;
+ GPUBatch *drw_camera_tria;
+ GPUBatch *drw_camera_focus;
+ GPUBatch *drw_particle_cross;
+ GPUBatch *drw_particle_circle;
+ GPUBatch *drw_particle_axis;
+ GPUBatch *drw_gpencil_axes;
+} SHC = {NULL};
+
+void DRW_shape_cache_free(void)
+{
+ uint i = sizeof(SHC) / sizeof(GPUBatch *);
+ GPUBatch **batch = (GPUBatch **)&SHC;
+ while (i--) {
+ GPU_BATCH_DISCARD_SAFE(*batch);
+ batch++;
+ }
+}
+
+void DRW_shape_cache_reset(void)
+{
+ uint i = sizeof(SHC) / sizeof(GPUBatch *);
+ GPUBatch **batch = (GPUBatch **)&SHC;
+ while (i--) {
+ if (*batch) {
+ GPU_batch_vao_cache_clear(*batch);
+ }
+ batch++;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Helper functions
+ * \{ */
+
+static void UNUSED_FUNCTION(add_fancy_edge)(
+ GPUVertBuf *vbo, uint pos_id, uint n1_id, uint n2_id,
+ uint *v_idx, const float co1[3], const float co2[3],
+ const float n1[3], const float n2[3])
+{
+ GPU_vertbuf_attr_set(vbo, n1_id, *v_idx, n1);
+ GPU_vertbuf_attr_set(vbo, n2_id, *v_idx, n2);
+ GPU_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, co1);
+
+ GPU_vertbuf_attr_set(vbo, n1_id, *v_idx, n1);
+ GPU_vertbuf_attr_set(vbo, n2_id, *v_idx, n2);
+ GPU_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, co2);
+}
+
+#if 0 /* UNUSED */
+static void add_lat_lon_vert(
+ GPUVertBuf *vbo, uint pos_id, uint nor_id,
+ uint *v_idx, const float rad, const float lat, const float lon)
+{
+ float pos[3], nor[3];
+ nor[0] = sinf(lat) * cosf(lon);
+ nor[1] = cosf(lat);
+ nor[2] = sinf(lat) * sinf(lon);
+ mul_v3_v3fl(pos, nor, rad);
+
+ GPU_vertbuf_attr_set(vbo, nor_id, *v_idx, nor);
+ GPU_vertbuf_attr_set(vbo, pos_id, (*v_idx)++, pos);
+}
+
+static GPUVertBuf *fill_arrows_vbo(const float scale)
+{
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ /* Line */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 6 * 3);
+
+ float v1[3] = {0.0, 0.0, 0.0};
+ float v2[3] = {0.0, 0.0, 0.0};
+ float vtmp1[3], vtmp2[3];
+
+ for (int axis = 0; axis < 3; axis++) {
+ const int arrow_axis = (axis == 0) ? 1 : 0;
+
+ v2[axis] = 1.0f;
+ mul_v3_v3fl(vtmp1, v1, scale);
+ mul_v3_v3fl(vtmp2, v2, scale);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 0, vtmp1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 1, vtmp2);
+
+ v1[axis] = 0.85f;
+ v1[arrow_axis] = -0.08f;
+ mul_v3_v3fl(vtmp1, v1, scale);
+ mul_v3_v3fl(vtmp2, v2, scale);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 2, vtmp1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 3, vtmp2);
+
+ v1[arrow_axis] = 0.08f;
+ mul_v3_v3fl(vtmp1, v1, scale);
+ mul_v3_v3fl(vtmp2, v2, scale);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 4, vtmp1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 6 + 5, vtmp2);
+
+ /* reset v1 & v2 to zero */
+ v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
+ }
+
+ return vbo;
+}
+#endif /* UNUSED */
+
+static GPUVertBuf *sphere_wire_vbo(const float rad)
+{
+#define NSEGMENTS 32
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2 * 3);
+
+ /* a single ring of vertices */
+ float p[NSEGMENTS][2];
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
+ p[i][0] = rad * cosf(angle);
+ p[i][1] = rad * sinf(angle);
+ }
+
+ for (int axis = 0; axis < 3; ++axis) {
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ float cv[2], v[3];
+
+ cv[0] = p[(i + j) % NSEGMENTS][0];
+ cv[1] = p[(i + j) % NSEGMENTS][1];
+
+ if (axis == 0) {
+ ARRAY_SET_ITEMS(v, cv[0], cv[1], 0.0f);
+ }
+ else if (axis == 1) {
+ ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
+ }
+ else {
+ ARRAY_SET_ITEMS(v, 0.0f, cv[0], cv[1]);
+ }
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + j + (NSEGMENTS * 2 * axis), v);
+ }
+ }
+ }
+
+ return vbo;
+#undef NSEGMENTS
+}
+
+/* Quads */
+/* Use this one for rendering fullscreen passes. For 3D objects use DRW_cache_quad_get(). */
+GPUBatch *DRW_cache_fullscreen_quad_get(void)
+{
+ if (!SHC.drw_fullscreen_quad) {
+ /* Use a triangle instead of a real quad */
+ /* https://www.slideshare.net/DevCentralAMD/vertex-shader-tricks-bill-bilodeau - slide 14 */
+ float pos[3][2] = {{-1.0f, -1.0f}, { 3.0f, -1.0f}, {-1.0f, 3.0f}};
+ float uvs[3][2] = {{ 0.0f, 0.0f}, { 2.0f, 0.0f}, { 0.0f, 2.0f}};
+
+ /* Position Only 2D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, uvs; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "texCoord");
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 3);
+
+ for (int i = 0; i < 3; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
+ GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
+ }
+
+ SHC.drw_fullscreen_quad = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_fullscreen_quad;
+}
+
+/* Just a regular quad with 4 vertices. */
+GPUBatch *DRW_cache_quad_get(void)
+{
+ if (!SHC.drw_quad) {
+ float pos[4][2] = {{-1.0f, -1.0f}, { 1.0f, -1.0f}, {1.0f, 1.0f}, {-1.0f, 1.0f}};
+ float uvs[4][2] = {{ 0.0f, 0.0f}, { 1.0f, 0.0f}, {1.0f, 1.0f}, { 0.0f, 1.0f}};
+
+ /* Position Only 2D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, uvs; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.uvs = GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 4);
+
+ for (int i = 0; i < 4; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, pos[i]);
+ GPU_vertbuf_attr_set(vbo, attr_id.uvs, i, uvs[i]);
+ }
+
+ SHC.drw_quad = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_quad;
+}
+
+/* Grid */
+GPUBatch *DRW_cache_grid_get(void)
+{
+ if (!SHC.drw_grid) {
+ /* Position Only 2D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 8 * 8 * 2 * 3);
+
+ uint v_idx = 0;
+ for (int i = 0; i < 8; ++i) {
+ for (int j = 0; j < 8; ++j) {
+ float pos0[2] = {(float)i / 8.0f, (float)j / 8.0f};
+ float pos1[2] = {(float)(i + 1) / 8.0f, (float)j / 8.0f};
+ float pos2[2] = {(float)i / 8.0f, (float)(j + 1) / 8.0f};
+ float pos3[2] = {(float)(i + 1) / 8.0f, (float)(j + 1) / 8.0f};
+
+ madd_v2_v2v2fl(pos0, (float[2]){-1.0f, -1.0f}, pos0, 2.0f);
+ madd_v2_v2v2fl(pos1, (float[2]){-1.0f, -1.0f}, pos1, 2.0f);
+ madd_v2_v2v2fl(pos2, (float[2]){-1.0f, -1.0f}, pos2, 2.0f);
+ madd_v2_v2v2fl(pos3, (float[2]){-1.0f, -1.0f}, pos3, 2.0f);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos2);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos2);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, pos3);
+ }
+ }
+
+ SHC.drw_grid = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_grid;
+}
+
+/* Sphere */
+GPUBatch *DRW_cache_sphere_get(void)
+{
+ if (!SHC.drw_sphere) {
+ SHC.drw_sphere = gpu_batch_sphere(32, 24);
+ }
+ return SHC.drw_sphere;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Common
+ * \{ */
+
+GPUBatch *DRW_cache_cube_get(void)
+{
+ if (!SHC.drw_cube) {
+ const GLfloat verts[8][3] = {
+ {-1.0f, -1.0f, -1.0f},
+ {-1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f},
+ {-1.0f, 1.0f, 1.0f},
+ { 1.0f, -1.0f, -1.0f},
+ { 1.0f, -1.0f, 1.0f},
+ { 1.0f, 1.0f, -1.0f},
+ { 1.0f, 1.0f, 1.0f}
+ };
+
+ const uint indices[36] = {
+ 0, 1, 2,
+ 1, 3, 2,
+ 0, 4, 1,
+ 4, 5, 1,
+ 6, 5, 4,
+ 6, 7, 5,
+ 2, 7, 6,
+ 2, 3, 7,
+ 3, 1, 7,
+ 1, 5, 7,
+ 0, 2, 4,
+ 2, 6, 4,
+ };
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 36);
+
+ for (int i = 0; i < 36; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
+ }
+
+ SHC.drw_cube = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_cube;
+}
+
+GPUBatch *DRW_cache_empty_cube_get(void)
+{
+ if (!SHC.drw_empty_cube) {
+ const GLfloat verts[8][3] = {
+ {-1.0f, -1.0f, -1.0f},
+ {-1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f},
+ {-1.0f, 1.0f, 1.0f},
+ { 1.0f, -1.0f, -1.0f},
+ { 1.0f, -1.0f, 1.0f},
+ { 1.0f, 1.0f, -1.0f},
+ { 1.0f, 1.0f, 1.0f}
+ };
+
+ const GLubyte indices[24] = {0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 24);
+
+ for (int i = 0; i < 24; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, verts[indices[i]]);
+ }
+
+ SHC.drw_empty_cube = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_empty_cube;
+}
+
+GPUBatch *DRW_cache_circle_get(void)
+{
+#define CIRCLE_RESOL 64
+ if (!SHC.drw_circle) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
+
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = 0.0f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+ }
+
+ SHC.drw_circle = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_circle;
+#undef CIRCLE_RESOL
+}
+
+GPUBatch *DRW_cache_square_get(void)
+{
+ if (!SHC.drw_square) {
+ float p[4][3] = {{ 1.0f, 0.0f, 1.0f},
+ { 1.0f, 0.0f, -1.0f},
+ {-1.0f, 0.0f, -1.0f},
+ {-1.0f, 0.0f, 1.0f}};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 8);
+
+ for (int i = 0; i < 4; i++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2, p[i % 4]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + 1, p[(i + 1) % 4]);
+ }
+
+ SHC.drw_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_square;
+}
+
+GPUBatch *DRW_cache_single_line_get(void)
+{
+ /* Z axis line */
+ if (!SHC.drw_line) {
+ float v1[3] = {0.0f, 0.0f, 0.0f};
+ float v2[3] = {0.0f, 0.0f, 1.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 2);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
+
+ SHC.drw_line = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_line;
+}
+
+GPUBatch *DRW_cache_single_line_endpoints_get(void)
+{
+ /* Z axis line */
+ if (!SHC.drw_line_endpoints) {
+ float v1[3] = {0.0f, 0.0f, 0.0f};
+ float v2[3] = {0.0f, 0.0f, 1.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 2);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v2);
+
+ SHC.drw_line_endpoints = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_line_endpoints;
+}
+
+GPUBatch *DRW_cache_screenspace_circle_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_screenspace_circle) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL + 1);
+
+ for (int a = 0; a <= CIRCLE_RESOL; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+ }
+
+ SHC.drw_screenspace_circle = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_screenspace_circle;
+#undef CIRCLE_RESOL
+}
+
+/* Grease Pencil object */
+GPUBatch *DRW_cache_gpencil_axes_get(void)
+{
+ if (!SHC.drw_gpencil_axes) {
+ int axis;
+ float v1[3] = { 0.0f, 0.0f, 0.0f };
+ float v2[3] = { 0.0f, 0.0f, 0.0f };
+
+ /* cube data */
+ const GLfloat verts[8][3] = {
+ { -0.25f, -0.25f, -0.25f },
+ { -0.25f, -0.25f, 0.25f },
+ { -0.25f, 0.25f, -0.25f },
+ { -0.25f, 0.25f, 0.25f },
+ { 0.25f, -0.25f, -0.25f },
+ { 0.25f, -0.25f, 0.25f },
+ { 0.25f, 0.25f, -0.25f },
+ { 0.25f, 0.25f, 0.25f }
+ };
+
+ const GLubyte indices[24] = { 0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6 };
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static uint pos_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ /* alloc 30 elements for cube and 3 axis */
+ GPU_vertbuf_data_alloc(vbo, ARRAY_SIZE(indices) + 6);
+
+ /* draw axis */
+ for (axis = 0; axis < 3; axis++) {
+ v1[axis] = 1.0f;
+ v2[axis] = -1.0f;
+
+ GPU_vertbuf_attr_set(vbo, pos_id, axis * 2, v1);
+ GPU_vertbuf_attr_set(vbo, pos_id, axis * 2 + 1, v2);
+
+ /* reset v1 & v2 to zero for next axis */
+ v1[axis] = v2[axis] = 0.0f;
+ }
+
+ /* draw cube */
+ for (int i = 0; i < 24; ++i) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i + 6, verts[indices[i]]);
+ }
+
+ SHC.drw_gpencil_axes = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_gpencil_axes;
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Common Object API
+* \{ */
+
+GPUBatch *DRW_cache_object_wire_outline_get(Object *ob)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ return DRW_cache_mesh_wire_outline_get(ob);
+
+ /* TODO, should match 'DRW_cache_object_surface_get' */
+ default:
+ return NULL;
+ }
+}
+
+GPUBatch *DRW_cache_object_edge_detection_get(Object *ob, bool *r_is_manifold)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ return DRW_cache_mesh_edge_detection_get(ob, r_is_manifold);
+
+ /* TODO, should match 'DRW_cache_object_surface_get' */
+ default:
+ return NULL;
+ }
+}
+
+/* Returns a buffer texture. */
+void DRW_cache_object_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ DRW_cache_mesh_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count);
+ break;
+ case OB_CURVE:
+ DRW_cache_curve_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count);
+ break;
+ case OB_SURF:
+ DRW_cache_surf_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count);
+ break;
+ case OB_FONT:
+ DRW_cache_text_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count);
+ break;
+ case OB_MBALL:
+ DRW_cache_mball_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count);
+ break;
+ }
+}
+
+GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ return DRW_cache_mesh_loose_edges_get(ob);
+
+ /* TODO, should match 'DRW_cache_object_surface_get' */
+ default:
+ return NULL;
+ }
+}
+
+GPUBatch *DRW_cache_object_surface_get(Object *ob)
+{
+ return DRW_cache_object_surface_get_ex(ob, false);
+}
+
+GPUBatch *DRW_cache_object_surface_get_ex(Object *ob, bool use_hide)
+{
+ switch (ob->type) {
+ case OB_MESH:
+ return DRW_cache_mesh_surface_get(ob, use_hide);
+ case OB_CURVE:
+ return DRW_cache_curve_surface_get(ob);
+ case OB_SURF:
+ return DRW_cache_surf_surface_get(ob);
+ case OB_FONT:
+ return DRW_cache_text_surface_get(ob);
+ case OB_MBALL:
+ return DRW_cache_mball_surface_get(ob);
+ default:
+ return NULL;
+ }
+}
+
+GPUBatch **DRW_cache_object_surface_material_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, bool use_hide,
+ char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count)
+{
+ if (auto_layer_names != NULL) {
+ *auto_layer_names = NULL;
+ *auto_layer_is_srgb = NULL;
+ *auto_layer_count = 0;
+ }
+
+ switch (ob->type) {
+ case OB_MESH:
+ return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len, use_hide,
+ auto_layer_names, auto_layer_is_srgb, auto_layer_count);
+ case OB_CURVE:
+ return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
+ case OB_SURF:
+ return DRW_cache_surf_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
+ case OB_FONT:
+ return DRW_cache_text_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
+ case OB_MBALL:
+ return DRW_cache_mball_surface_shaded_get(ob, gpumat_array, gpumat_array_len);
+ default:
+ return NULL;
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Empties
+ * \{ */
+
+GPUBatch *DRW_cache_plain_axes_get(void)
+{
+ if (!SHC.drw_plain_axes) {
+ int axis;
+ float v1[3] = {0.0f, 0.0f, 0.0f};
+ float v2[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 6);
+
+ for (axis = 0; axis < 3; axis++) {
+ v1[axis] = 1.0f;
+ v2[axis] = -1.0f;
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 2, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, axis * 2 + 1, v2);
+
+ /* reset v1 & v2 to zero for next axis */
+ v1[axis] = v2[axis] = 0.0f;
+ }
+
+ SHC.drw_plain_axes = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_plain_axes;
+}
+
+GPUBatch *DRW_cache_single_arrow_get(void)
+{
+ if (!SHC.drw_single_arrow) {
+ float v1[3] = {0.0f, 0.0f, 1.0f}, v2[3], v3[3];
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ /* Square Pyramid */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 12);
+
+ v2[0] = 0.035f; v2[1] = 0.035f;
+ v3[0] = -0.035f; v3[1] = 0.035f;
+ v2[2] = v3[2] = 0.75f;
+
+ for (int sides = 0; sides < 4; sides++) {
+ if (sides % 2 == 1) {
+ v2[0] = -v2[0];
+ v3[1] = -v3[1];
+ }
+ else {
+ v2[1] = -v2[1];
+ v3[0] = -v3[0];
+ }
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 0, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 1, v2);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, sides * 3 + 2, v3);
+ }
+
+ SHC.drw_single_arrow = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_single_arrow;
+}
+
+GPUBatch *DRW_cache_empty_sphere_get(void)
+{
+ if (!SHC.drw_empty_sphere) {
+ GPUVertBuf *vbo = sphere_wire_vbo(1.0f);
+ SHC.drw_empty_sphere = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_empty_sphere;
+}
+
+GPUBatch *DRW_cache_empty_cone_get(void)
+{
+#define NSEGMENTS 8
+ if (!SHC.drw_empty_cone) {
+ /* a single ring of vertices */
+ float p[NSEGMENTS][2];
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
+ p[i][0] = cosf(angle);
+ p[i][1] = sinf(angle);
+ }
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
+
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float cv[2], v[3];
+ cv[0] = p[(i) % NSEGMENTS][0];
+ cv[1] = p[(i) % NSEGMENTS][1];
+
+ /* cone sides */
+ ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
+ ARRAY_SET_ITEMS(v, 0.0f, 2.0f, 0.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
+
+ /* end ring */
+ ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v);
+ cv[0] = p[(i + 1) % NSEGMENTS][0];
+ cv[1] = p[(i + 1) % NSEGMENTS][1];
+ ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
+ }
+
+ SHC.drw_empty_cone = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_empty_cone;
+#undef NSEGMENTS
+}
+
+GPUBatch *DRW_cache_empty_cylinder_get(void)
+{
+#define NSEGMENTS 12
+ if (!SHC.drw_empty_cylinder) {
+ /* a single ring of vertices */
+ float p[NSEGMENTS][2];
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
+ p[i][0] = cosf(angle);
+ p[i][1] = sinf(angle);
+ }
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 6);
+
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float cv[2], pv[2], v[3];
+ cv[0] = p[(i) % NSEGMENTS][0];
+ cv[1] = p[(i) % NSEGMENTS][1];
+ pv[0] = p[(i + 1) % NSEGMENTS][0];
+ pv[1] = p[(i + 1) % NSEGMENTS][1];
+
+ /* cylinder sides */
+ copy_v3_fl3(v, cv[0], cv[1], -1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6, v);
+ copy_v3_fl3(v, cv[0], cv[1], 1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 1, v);
+
+ /* top ring */
+ copy_v3_fl3(v, cv[0], cv[1], 1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 2, v);
+ copy_v3_fl3(v, pv[0], pv[1], 1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 3, v);
+
+ /* bottom ring */
+ copy_v3_fl3(v, cv[0], cv[1], -1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 4, v);
+ copy_v3_fl3(v, pv[0], pv[1], -1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 6 + 5, v);
+ }
+
+ SHC.drw_empty_cylinder = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_empty_cylinder;
+#undef NSEGMENTS
+}
+
+GPUBatch *DRW_cache_empty_capsule_body_get(void)
+{
+ if (!SHC.drw_empty_capsule_body) {
+ const float pos[8][3] = {
+ { 1.0f, 0.0f, 1.0f},
+ { 1.0f, 0.0f, 0.0f},
+ { 0.0f, 1.0f, 1.0f},
+ { 0.0f, 1.0f, 0.0f},
+ {-1.0f, 0.0f, 1.0f},
+ {-1.0f, 0.0f, 0.0f},
+ { 0.0f, -1.0f, 1.0f},
+ { 0.0f, -1.0f, 0.0f}
+ };
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 8);
+ GPU_vertbuf_attr_fill(vbo, attr_id.pos, pos);
+
+ SHC.drw_empty_capsule_body = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_empty_capsule_body;
+}
+
+GPUBatch *DRW_cache_empty_capsule_cap_get(void)
+{
+#define NSEGMENTS 24 /* Must be multiple of 2. */
+ if (!SHC.drw_empty_capsule_cap) {
+ /* a single ring of vertices */
+ float p[NSEGMENTS][2];
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
+ p[i][0] = cosf(angle);
+ p[i][1] = sinf(angle);
+ }
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, (NSEGMENTS * 2) * 2);
+
+ /* Base circle */
+ int vidx = 0;
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ copy_v2_v2(v, p[(i) % NSEGMENTS]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ copy_v2_v2(v, p[(i + 1) % NSEGMENTS]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+
+ for (int i = 0; i < NSEGMENTS / 2; ++i) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ int ci = i % NSEGMENTS;
+ int pi = (i + 1) % NSEGMENTS;
+ /* Y half circle */
+ copy_v3_fl3(v, p[ci][0], 0.0f, p[ci][1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ copy_v3_fl3(v, p[pi][0], 0.0f, p[pi][1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ /* X half circle */
+ copy_v3_fl3(v, 0.0f, p[ci][0], p[ci][1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ copy_v3_fl3(v, 0.0f, p[pi][0], p[pi][1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+
+ SHC.drw_empty_capsule_cap = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_empty_capsule_cap;
+#undef NSEGMENTS
+}
+
+GPUBatch *DRW_cache_image_plane_get(void)
+{
+ if (!SHC.drw_image_plane) {
+ const float quad[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, texCoords; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.texCoords = GPU_vertformat_attr_add(&format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 4);
+ for (uint j = 0; j < 4; j++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
+ GPU_vertbuf_attr_set(vbo, attr_id.texCoords, j, quad[j]);
+ }
+ SHC.drw_image_plane = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_image_plane;
+}
+
+GPUBatch *DRW_cache_image_plane_wire_get(void)
+{
+ if (!SHC.drw_image_plane_wire) {
+ const float quad[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 4);
+ for (uint j = 0; j < 4; j++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, j, quad[j]);
+ }
+ SHC.drw_image_plane_wire = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_image_plane_wire;
+}
+
+/* Force Field */
+GPUBatch *DRW_cache_field_wind_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_field_wind) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 4);
+
+ for (int i = 0; i < 4; i++) {
+ float z = 0.05f * (float)i;
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[2] = z;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[2] = z;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
+ }
+ }
+
+ SHC.drw_field_wind = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_field_wind;
+#undef CIRCLE_RESOL
+}
+
+GPUBatch *DRW_cache_field_force_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_field_force) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 3);
+
+ for (int i = 0; i < 3; i++) {
+ float radius = 1.0f + 0.5f * (float)i;
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[2] = 0.0f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2, v);
+
+ v[0] = radius * sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[1] = radius * cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[2] = 0.0f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * CIRCLE_RESOL * 2 + a * 2 + 1, v);
+ }
+ }
+
+ SHC.drw_field_force = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_field_force;
+#undef CIRCLE_RESOL
+}
+
+GPUBatch *DRW_cache_field_vortex_get(void)
+{
+#define SPIRAL_RESOL 32
+ if (!SHC.drw_field_vortex) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ uint v_idx = 0;
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, SPIRAL_RESOL * 2 + 1);
+
+ for (int a = SPIRAL_RESOL; a > -1; a--) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
+ v[1] = cosf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+
+ for (int a = 1; a <= SPIRAL_RESOL; a++) {
+ v[0] = -sinf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
+ v[1] = -cosf((2.0f * M_PI * a) / ((float)SPIRAL_RESOL)) * (a / (float)SPIRAL_RESOL);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+
+ SHC.drw_field_vortex = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_field_vortex;
+#undef SPIRAL_RESOL
+}
+
+GPUBatch *DRW_cache_field_tube_limit_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_field_tube_limit) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ uint v_idx = 0;
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 + 8);
+
+ /* Caps */
+ for (int i = 0; i < 2; i++) {
+ float z = (float)i * 2.0f - 1.0f;
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[2] = z;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[2] = z;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+ }
+ /* Side Edges */
+ for (int a = 0; a < 4; a++) {
+ for (int i = 0; i < 2; i++) {
+ float z = (float)i * 2.0f - 1.0f;
+ v[0] = sinf((2.0f * M_PI * a) / 4.0f);
+ v[1] = cosf((2.0f * M_PI * a) / 4.0f);
+ v[2] = z;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+ }
+
+ SHC.drw_field_tube_limit = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_field_tube_limit;
+#undef CIRCLE_RESOL
+}
+
+GPUBatch *DRW_cache_field_cone_limit_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_field_cone_limit) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ uint v_idx = 0;
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 + 8);
+
+ /* Caps */
+ for (int i = 0; i < 2; i++) {
+ float z = (float)i * 2.0f - 1.0f;
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[2] = z;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[2] = z;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+ }
+ /* Side Edges */
+ for (int a = 0; a < 4; a++) {
+ for (int i = 0; i < 2; i++) {
+ float z = (float)i * 2.0f - 1.0f;
+ v[0] = z * sinf((2.0f * M_PI * a) / 4.0f);
+ v[1] = z * cosf((2.0f * M_PI * a) / 4.0f);
+ v[2] = z;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+ }
+
+ SHC.drw_field_cone_limit = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_field_cone_limit;
+#undef CIRCLE_RESOL
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Lamps
+ * \{ */
+
+GPUBatch *DRW_cache_lamp_get(void)
+{
+#define NSEGMENTS 8
+ if (!SHC.drw_lamp) {
+ float v[2];
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
+
+ for (int a = 0; a < NSEGMENTS * 2; a += 2) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
+ }
+
+ SHC.drw_lamp = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp;
+#undef NSEGMENTS
+}
+
+GPUBatch *DRW_cache_lamp_shadows_get(void)
+{
+#define NSEGMENTS 10
+ if (!SHC.drw_lamp_shadows) {
+ float v[2];
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 2);
+
+ for (int a = 0; a < NSEGMENTS * 2; a += 2) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)NSEGMENTS * 2));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)NSEGMENTS * 2));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a + 1, v);
+ }
+
+ SHC.drw_lamp_shadows = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_shadows;
+#undef NSEGMENTS
+}
+
+GPUBatch *DRW_cache_lamp_sunrays_get(void)
+{
+ if (!SHC.drw_lamp_sunrays) {
+ float v[2], v1[2], v2[2];
+
+ /* Position Only 2D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 32);
+
+ for (int a = 0; a < 8; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / 8.0f);
+ v[1] = cosf((2.0f * M_PI * a) / 8.0f);
+
+ mul_v2_v2fl(v1, v, 1.6f);
+ mul_v2_v2fl(v2, v, 1.9f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 1, v2);
+
+ mul_v2_v2fl(v1, v, 2.2f);
+ mul_v2_v2fl(v2, v, 2.5f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 2, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 3, v2);
+ }
+
+ SHC.drw_lamp_sunrays = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_sunrays;
+}
+
+GPUBatch *DRW_cache_lamp_area_square_get(void)
+{
+ if (!SHC.drw_lamp_area_square) {
+ float v1[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 8);
+
+ v1[0] = v1[1] = 0.5f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+ v1[0] = -0.5f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 1, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 2, v1);
+ v1[1] = -0.5f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 3, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 4, v1);
+ v1[0] = 0.5f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 5, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 6, v1);
+ v1[1] = 0.5f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 7, v1);
+
+ SHC.drw_lamp_area_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_area_square;
+}
+
+GPUBatch *DRW_cache_lamp_area_disk_get(void)
+{
+#define NSEGMENTS 32
+ if (!SHC.drw_lamp_area_disk) {
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 2 * NSEGMENTS);
+
+ float v[3] = {0.0f, 0.5f, 0.0f};
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v);
+ for (int a = 1; a < NSEGMENTS; a++) {
+ v[0] = 0.5f * sinf(2.0f * (float)M_PI * a / NSEGMENTS);
+ v[1] = 0.5f * cosf(2.0f * (float)M_PI * a / NSEGMENTS);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 2 * a - 1, v);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 2 * a, v);
+ }
+ copy_v3_fl3(v, 0.0f, 0.5f, 0.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, (2 * NSEGMENTS) - 1, v);
+
+ SHC.drw_lamp_area_disk = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_area_disk;
+#undef NSEGMENTS
+}
+
+GPUBatch *DRW_cache_lamp_hemi_get(void)
+{
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_lamp_hemi) {
+ float v[3];
+ int vidx = 0;
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL * 2 * 2 - 6 * 2 * 2);
+
+ /* XZ plane */
+ for (int a = 3; a < CIRCLE_RESOL / 2 - 3; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL) - M_PI / 2);
+ v[2] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL) - M_PI / 2) - 1.0f;
+ v[1] = 0.0f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+
+ v[0] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL) - M_PI / 2);
+ v[2] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL) - M_PI / 2) - 1.0f;
+ v[1] = 0.0f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+
+ /* XY plane */
+ for (int a = 3; a < CIRCLE_RESOL / 2 - 3; a++) {
+ v[2] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL)) - 1.0f;
+ v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[0] = 0.0f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+
+ v[2] = sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL)) - 1.0f;
+ v[1] = cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[0] = 0.0f;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+
+ /* YZ plane full circle */
+ /* lease v[2] as it is */
+ const float rad = cosf((2.0f * M_PI * 3) / ((float)CIRCLE_RESOL));
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[1] = rad * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[0] = rad * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+
+ v[1] = rad * sinf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ v[0] = rad * cosf((2.0f * M_PI * (a + 1)) / ((float)CIRCLE_RESOL));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+
+
+ SHC.drw_lamp_hemi = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_hemi;
+#undef CIRCLE_RESOL
+}
+
+
+GPUBatch *DRW_cache_lamp_spot_get(void)
+{
+#define NSEGMENTS 32
+ if (!SHC.drw_lamp_spot) {
+ /* a single ring of vertices */
+ float p[NSEGMENTS][2];
+ float n[NSEGMENTS][3];
+ float neg[NSEGMENTS][3];
+ float half_angle = 2 * M_PI / ((float)NSEGMENTS * 2);
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
+ p[i][0] = cosf(angle);
+ p[i][1] = sinf(angle);
+
+ n[i][0] = cosf(angle - half_angle);
+ n[i][1] = sinf(angle - half_angle);
+ n[i][2] = cosf(M_PI / 16.0f); /* slope of the cone */
+ normalize_v3(n[i]); /* necessary ? */
+ negate_v3_v3(neg[i], n[i]);
+ }
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, n1, n2; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.n1 = GPU_vertformat_attr_add(&format, "N1", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.n2 = GPU_vertformat_attr_add(&format, "N2", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 4);
+
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float cv[2], v[3];
+ cv[0] = p[i % NSEGMENTS][0];
+ cv[1] = p[i % NSEGMENTS][1];
+
+ /* cone sides */
+ ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v);
+ ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4, n[(i) % NSEGMENTS]);
+ GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 1, n[(i) % NSEGMENTS]);
+ GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4, n[(i + 1) % NSEGMENTS]);
+ GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 1, n[(i + 1) % NSEGMENTS]);
+
+ /* end ring */
+ ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v);
+ cv[0] = p[(i + 1) % NSEGMENTS][0];
+ cv[1] = p[(i + 1) % NSEGMENTS][1];
+ ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 2, n[(i) % NSEGMENTS]);
+ GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 3, n[(i) % NSEGMENTS]);
+ GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 2, neg[(i) % NSEGMENTS]);
+ GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 3, neg[(i) % NSEGMENTS]);
+ }
+
+ SHC.drw_lamp_spot = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_spot;
+#undef NSEGMENTS
+}
+
+GPUBatch *DRW_cache_lamp_spot_volume_get(void)
+{
+#define NSEGMENTS 32
+ if (!SHC.drw_lamp_spot_volume) {
+ /* a single ring of vertices */
+ float p[NSEGMENTS][2];
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float angle = 2 * M_PI * ((float)i / (float)NSEGMENTS);
+ p[i][0] = cosf(angle);
+ p[i][1] = sinf(angle);
+ }
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, NSEGMENTS * 3);
+
+ uint v_idx = 0;
+ for (int i = 0; i < NSEGMENTS; ++i) {
+ float cv[2], v[3];
+
+ ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+
+ cv[0] = p[i % NSEGMENTS][0];
+ cv[1] = p[i % NSEGMENTS][1];
+ ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+
+ cv[0] = p[(i + 1) % NSEGMENTS][0];
+ cv[1] = p[(i + 1) % NSEGMENTS][1];
+ ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v);
+ }
+
+ SHC.drw_lamp_spot_volume = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_spot_volume;
+#undef NSEGMENTS
+}
+
+GPUBatch *DRW_cache_lamp_spot_square_get(void)
+{
+ if (!SHC.drw_lamp_spot_square) {
+ float p[5][3] = {{ 0.0f, 0.0f, 0.0f},
+ { 1.0f, 1.0f, -1.0f},
+ { 1.0f, -1.0f, -1.0f},
+ {-1.0f, -1.0f, -1.0f},
+ {-1.0f, 1.0f, -1.0f}};
+
+ uint v_idx = 0;
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 16);
+
+ /* piramid sides */
+ for (int i = 1; i <= 4; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[i]);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
+ }
+
+ SHC.drw_lamp_spot_square = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_spot_square;
+}
+
+GPUBatch *DRW_cache_lamp_spot_square_volume_get(void)
+{
+ if (!SHC.drw_lamp_spot_square_volume) {
+ float p[5][3] = {{ 0.0f, 0.0f, 0.0f},
+ { 1.0f, 1.0f, -1.0f},
+ { 1.0f, -1.0f, -1.0f},
+ {-1.0f, -1.0f, -1.0f},
+ {-1.0f, 1.0f, -1.0f}};
+
+ uint v_idx = 0;
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 12);
+
+ /* piramid sides */
+ for (int i = 1; i <= 4; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[0]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[((i + 1) % 4) + 1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, p[(i % 4) + 1]);
+ }
+
+ SHC.drw_lamp_spot_square_volume = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lamp_spot_square_volume;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Speaker
+ * \{ */
+
+GPUBatch *DRW_cache_speaker_get(void)
+{
+ if (!SHC.drw_speaker) {
+ float v[3];
+ const int segments = 16;
+ int vidx = 0;
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 3 * segments * 2 + 4 * 4);
+
+ for (int j = 0; j < 3; j++) {
+ float z = 0.25f * j - 0.125f;
+ float r = (j == 0 ? 0.5f : 0.25f);
+
+ copy_v3_fl3(v, r, 0.0f, z);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ for (int i = 1; i < segments; i++) {
+ float x = cosf(2.f * (float)M_PI * i / segments) * r;
+ float y = sinf(2.f * (float)M_PI * i / segments) * r;
+ copy_v3_fl3(v, x, y, z);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+ copy_v3_fl3(v, r, 0.0f, z);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+
+ for (int j = 0; j < 4; j++) {
+ float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
+ float y = ((j % 2) * (j - 2)) * 0.5f;
+ for (int i = 0; i < 3; i++) {
+ if (i == 1) {
+ x *= 0.5f;
+ y *= 0.5f;
+ }
+
+ float z = 0.25f * i - 0.125f;
+ copy_v3_fl3(v, x, y, z);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ if (i == 1) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, v);
+ }
+ }
+ }
+
+ SHC.drw_speaker = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_speaker;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Probe
+ * \{ */
+
+GPUBatch *DRW_cache_lightprobe_cube_get(void)
+{
+ if (!SHC.drw_lightprobe_cube) {
+ int v_idx = 0;
+ const float sin_pi_3 = 0.86602540378f;
+ const float cos_pi_3 = 0.5f;
+ float v[7][3] = {
+ {0.0f, 1.0f, 0.0f},
+ {sin_pi_3, cos_pi_3, 0.0f},
+ {sin_pi_3, -cos_pi_3, 0.0f},
+ {0.0f, -1.0f, 0.0f},
+ {-sin_pi_3, -cos_pi_3, 0.0f},
+ {-sin_pi_3, cos_pi_3, 0.0f},
+ {0.0f, 0.0f, 0.0f},
+ };
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, (6 + 3) * 2);
+
+ for (int i = 0; i < 6; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 6]);
+ }
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ SHC.drw_lightprobe_cube = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lightprobe_cube;
+}
+
+GPUBatch *DRW_cache_lightprobe_grid_get(void)
+{
+ if (!SHC.drw_lightprobe_grid) {
+ int v_idx = 0;
+ const float sin_pi_3 = 0.86602540378f;
+ const float cos_pi_3 = 0.5f;
+ const float v[7][3] = {
+ {0.0f, 1.0f, 0.0f},
+ {sin_pi_3, cos_pi_3, 0.0f},
+ {sin_pi_3, -cos_pi_3, 0.0f},
+ {0.0f, -1.0f, 0.0f},
+ {-sin_pi_3, -cos_pi_3, 0.0f},
+ {-sin_pi_3, cos_pi_3, 0.0f},
+ {0.0f, 0.0f, 0.0f},
+ };
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, (6 * 2 + 3) * 2);
+
+ for (int i = 0; i < 6; ++i) {
+ float tmp_v1[3], tmp_v2[3], tmp_tr[3];
+ copy_v3_v3(tmp_v1, v[i]);
+ copy_v3_v3(tmp_v2, v[(i + 1) % 6]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
+
+ /* Internal wires. */
+ for (int j = 1; j < 2; ++j) {
+ mul_v3_v3fl(tmp_tr, v[(i / 2) * 2 + 1], -0.5f * j);
+ add_v3_v3v3(tmp_v1, v[i], tmp_tr);
+ add_v3_v3v3(tmp_v2, v[(i + 1) % 6], tmp_tr);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, tmp_v2);
+ }
+ }
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[5]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[3]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[6]);
+
+ SHC.drw_lightprobe_grid = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lightprobe_grid;
+}
+
+GPUBatch *DRW_cache_lightprobe_planar_get(void)
+{
+ if (!SHC.drw_lightprobe_planar) {
+ int v_idx = 0;
+ const float sin_pi_3 = 0.86602540378f;
+ float v[4][3] = {
+ {0.0f, 0.5f, 0.0f},
+ {sin_pi_3, 0.0f, 0.0f},
+ {0.0f, -0.5f, 0.0f},
+ {-sin_pi_3, 0.0f, 0.0f},
+ };
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 4 * 2);
+
+ for (int i = 0; i < 4; ++i) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[i]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, v[(i + 1) % 4]);
+ }
+
+ SHC.drw_lightprobe_planar = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_lightprobe_planar;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Armature Bones
+ * \{ */
+
+static const float bone_octahedral_verts[6][3] = {
+ { 0.0f, 0.0f, 0.0f},
+ { 0.1f, 0.1f, 0.1f},
+ { 0.1f, 0.1f, -0.1f},
+ {-0.1f, 0.1f, -0.1f},
+ {-0.1f, 0.1f, 0.1f},
+ { 0.0f, 1.0f, 0.0f}
+};
+
+static const float bone_octahedral_smooth_normals[6][3] = {
+ { 0.0f, -1.0f, 0.0f},
+#if 0 /* creates problems for outlines when scaled */
+ { 0.943608f * M_SQRT1_2, -0.331048f, 0.943608f * M_SQRT1_2},
+ { 0.943608f * M_SQRT1_2, -0.331048f, -0.943608f * M_SQRT1_2},
+ {-0.943608f * M_SQRT1_2, -0.331048f, -0.943608f * M_SQRT1_2},
+ {-0.943608f * M_SQRT1_2, -0.331048f, 0.943608f * M_SQRT1_2},
+#else
+ { M_SQRT1_2, 0.0f, M_SQRT1_2},
+ { M_SQRT1_2, 0.0f, -M_SQRT1_2},
+ {-M_SQRT1_2, 0.0f, -M_SQRT1_2},
+ {-M_SQRT1_2, 0.0f, M_SQRT1_2},
+#endif
+ { 0.0f, 1.0f, 0.0f}
+};
+
+#if 0 /* UNUSED */
+
+static const uint bone_octahedral_wire[24] = {
+ 0, 1, 1, 5, 5, 3, 3, 0,
+ 0, 4, 4, 5, 5, 2, 2, 0,
+ 1, 2, 2, 3, 3, 4, 4, 1,
+};
+
+/* aligned with bone_octahedral_wire
+ * Contains adjacent normal index */
+static const uint bone_octahedral_wire_adjacent_face[24] = {
+ 0, 3, 4, 7, 5, 6, 1, 2,
+ 2, 3, 6, 7, 4, 5, 0, 1,
+ 0, 4, 1, 5, 2, 6, 3, 7,
+};
+#endif
+
+static const uint bone_octahedral_solid_tris[8][3] = {
+ {2, 1, 0}, /* bottom */
+ {3, 2, 0},
+ {4, 3, 0},
+ {1, 4, 0},
+
+ {5, 1, 2}, /* top */
+ {5, 2, 3},
+ {5, 3, 4},
+ {5, 4, 1}
+};
+
+/**
+ * Store indices of generated verts from bone_octahedral_solid_tris to define adjacency infos.
+ * Example: triangle {2, 1, 0} is adjacent to {3, 2, 0}, {1, 4, 0} and {5, 1, 2}.
+ * {2, 1, 0} becomes {0, 1, 2}
+ * {3, 2, 0} becomes {3, 4, 5}
+ * {1, 4, 0} becomes {9, 10, 11}
+ * {5, 1, 2} becomes {12, 13, 14}
+ * According to opengl specification it becomes (starting from
+ * the first vertex of the first face aka. vertex 2):
+ * {0, 12, 1, 10, 2, 3}
+ **/
+static const uint bone_octahedral_wire_lines_adjacency[12][4] = {
+ { 0, 1, 2, 6}, { 0, 12, 1, 6}, { 0, 3, 12, 6}, { 0, 2, 3, 6},
+ { 1, 6, 2, 3}, { 1, 12, 6, 3}, { 1, 0, 12, 3}, { 1, 2, 0, 3},
+ { 2, 0, 1, 12}, { 2, 3, 0, 12}, { 2, 6, 3, 12}, { 2, 1, 6, 12},
+};
+
+#if 0 /* UNUSED */
+static const uint bone_octahedral_solid_tris_adjacency[8][6] = {
+ { 0, 12, 1, 10, 2, 3},
+ { 3, 15, 4, 1, 5, 6},
+ { 6, 18, 7, 4, 8, 9},
+ { 9, 21, 10, 7, 11, 0},
+
+ {12, 22, 13, 2, 14, 17},
+ {15, 13, 16, 5, 17, 20},
+ {18, 16, 19, 8, 20, 23},
+ {21, 19, 22, 11, 23, 14},
+};
+#endif
+
+/* aligned with bone_octahedral_solid_tris */
+static const float bone_octahedral_solid_normals[8][3] = {
+ { M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
+ {-0.00000000f, -M_SQRT1_2, -M_SQRT1_2},
+ {-M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
+ { 0.00000000f, -M_SQRT1_2, M_SQRT1_2},
+ { 0.99388373f, 0.11043154f, -0.00000000f},
+ { 0.00000000f, 0.11043154f, -0.99388373f},
+ {-0.99388373f, 0.11043154f, 0.00000000f},
+ { 0.00000000f, 0.11043154f, 0.99388373f}
+};
+
+GPUBatch *DRW_cache_bone_octahedral_get(void)
+{
+ if (!SHC.drw_bone_octahedral) {
+ uint v_idx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, nor, snor; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.snor = GPU_vertformat_attr_add(&format, "snor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 24);
+
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 3; ++j) {
+ GPU_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_octahedral_solid_normals[i]);
+ GPU_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_octahedral_smooth_normals[bone_octahedral_solid_tris[i][j]]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_octahedral_verts[bone_octahedral_solid_tris[i][j]]);
+ }
+ }
+
+ SHC.drw_bone_octahedral = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL,
+ GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_bone_octahedral;
+}
+
+GPUBatch *DRW_cache_bone_octahedral_wire_get(void)
+{
+ if (!SHC.drw_bone_octahedral_wire) {
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, 12, 24);
+
+ for (int i = 0; i < 12; i++) {
+ GPU_indexbuf_add_line_adj_verts(&elb,
+ bone_octahedral_wire_lines_adjacency[i][0],
+ bone_octahedral_wire_lines_adjacency[i][1],
+ bone_octahedral_wire_lines_adjacency[i][2],
+ bone_octahedral_wire_lines_adjacency[i][3]);
+ }
+
+ /* HACK Reuse vertex buffer. */
+ GPUBatch *pos_nor_batch = DRW_cache_bone_octahedral_get();
+
+ SHC.drw_bone_octahedral_wire = GPU_batch_create_ex(GPU_PRIM_LINES_ADJ, pos_nor_batch->verts[0], GPU_indexbuf_build(&elb),
+ GPU_BATCH_OWNS_INDEX);
+ }
+ return SHC.drw_bone_octahedral_wire;
+}
+
+/* XXX TODO move that 1 unit cube to more common/generic place? */
+static const float bone_box_verts[8][3] = {
+ { 1.0f, 0.0f, 1.0f},
+ { 1.0f, 0.0f, -1.0f},
+ {-1.0f, 0.0f, -1.0f},
+ {-1.0f, 0.0f, 1.0f},
+ { 1.0f, 1.0f, 1.0f},
+ { 1.0f, 1.0f, -1.0f},
+ {-1.0f, 1.0f, -1.0f},
+ {-1.0f, 1.0f, 1.0f}
+};
+
+static const float bone_box_smooth_normals[8][3] = {
+ { M_SQRT3, -M_SQRT3, M_SQRT3},
+ { M_SQRT3, -M_SQRT3, -M_SQRT3},
+ {-M_SQRT3, -M_SQRT3, -M_SQRT3},
+ {-M_SQRT3, -M_SQRT3, M_SQRT3},
+ { M_SQRT3, M_SQRT3, M_SQRT3},
+ { M_SQRT3, M_SQRT3, -M_SQRT3},
+ {-M_SQRT3, M_SQRT3, -M_SQRT3},
+ {-M_SQRT3, M_SQRT3, M_SQRT3},
+};
+
+#if 0 /* UNUSED */
+static const uint bone_box_wire[24] = {
+ 0, 1, 1, 2, 2, 3, 3, 0,
+ 4, 5, 5, 6, 6, 7, 7, 4,
+ 0, 4, 1, 5, 2, 6, 3, 7,
+};
+
+/* aligned with bone_octahedral_wire
+ * Contains adjacent normal index */
+static const uint bone_box_wire_adjacent_face[24] = {
+ 0, 2, 0, 4, 1, 6, 1, 8,
+ 3, 10, 5, 10, 7, 11, 9, 11,
+ 3, 8, 2, 5, 4, 7, 6, 9,
+};
+#endif
+
+static const uint bone_box_solid_tris[12][3] = {
+ {0, 2, 1}, /* bottom */
+ {0, 3, 2},
+
+ {0, 1, 5}, /* sides */
+ {0, 5, 4},
+
+ {1, 2, 6},
+ {1, 6, 5},
+
+ {2, 3, 7},
+ {2, 7, 6},
+
+ {3, 0, 4},
+ {3, 4, 7},
+
+ {4, 5, 6}, /* top */
+ {4, 6, 7},
+};
+
+/**
+ * Store indices of generated verts from bone_box_solid_tris to define adjacency infos.
+ * See bone_octahedral_solid_tris for more infos.
+ **/
+static const uint bone_box_wire_lines_adjacency[12][4] = {
+ { 4, 2, 0, 11}, { 0, 1, 2, 8}, { 2, 4, 1, 14}, { 1, 0, 4, 20}, /* bottom */
+ { 0, 8, 11, 14}, { 2, 14, 8, 20}, { 1, 20, 14, 11}, { 4, 11, 20, 8}, /* top */
+ { 20, 0, 11, 2}, { 11, 2, 8, 1}, { 8, 1, 14, 4}, { 14, 4, 20, 0}, /* sides */
+};
+
+#if 0 /* UNUSED */
+static const uint bone_box_solid_tris_adjacency[12][6] = {
+ { 0, 5, 1, 14, 2, 8},
+ { 3, 26, 4, 20, 5, 1},
+
+ { 6, 2, 7, 16, 8, 11},
+ { 9, 7, 10, 32, 11, 24},
+
+ {12, 0, 13, 22, 14, 17},
+ {15, 13, 16, 30, 17, 6},
+
+ {18, 3, 19, 28, 20, 23},
+ {21, 19, 22, 33, 23, 12},
+
+ {24, 4, 25, 10, 26, 29},
+ {27, 25, 28, 34, 29, 18},
+
+ {30, 9, 31, 15, 32, 35},
+ {33, 31, 34, 21, 35, 27},
+};
+#endif
+
+/* aligned with bone_box_solid_tris */
+static const float bone_box_solid_normals[12][3] = {
+ { 0.0f, -1.0f, 0.0f},
+ { 0.0f, -1.0f, 0.0f},
+
+ { 1.0f, 0.0f, 0.0f},
+ { 1.0f, 0.0f, 0.0f},
+
+ { 0.0f, 0.0f, -1.0f},
+ { 0.0f, 0.0f, -1.0f},
+
+ {-1.0f, 0.0f, 0.0f},
+ {-1.0f, 0.0f, 0.0f},
+
+ { 0.0f, 0.0f, 1.0f},
+ { 0.0f, 0.0f, 1.0f},
+
+ { 0.0f, 1.0f, 0.0f},
+ { 0.0f, 1.0f, 0.0f},
+};
+
+GPUBatch *DRW_cache_bone_box_get(void)
+{
+ if (!SHC.drw_bone_box) {
+ uint v_idx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, nor, snor; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.snor = GPU_vertformat_attr_add(&format, "snor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 36);
+
+ for (int i = 0; i < 12; i++) {
+ for (int j = 0; j < 3; j++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.nor, v_idx, bone_box_solid_normals[i]);
+ GPU_vertbuf_attr_set(vbo, attr_id.snor, v_idx, bone_box_smooth_normals[bone_box_solid_tris[i][j]]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, bone_box_verts[bone_box_solid_tris[i][j]]);
+ }
+ }
+
+ SHC.drw_bone_box = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL,
+ GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_bone_box;
+}
+
+GPUBatch *DRW_cache_bone_box_wire_get(void)
+{
+ if (!SHC.drw_bone_box_wire) {
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, 12, 36);
+
+ for (int i = 0; i < 12; i++) {
+ GPU_indexbuf_add_line_adj_verts(&elb,
+ bone_box_wire_lines_adjacency[i][0],
+ bone_box_wire_lines_adjacency[i][1],
+ bone_box_wire_lines_adjacency[i][2],
+ bone_box_wire_lines_adjacency[i][3]);
+ }
+
+ /* HACK Reuse vertex buffer. */
+ GPUBatch *pos_nor_batch = DRW_cache_bone_box_get();
+
+ SHC.drw_bone_box_wire = GPU_batch_create_ex(GPU_PRIM_LINES_ADJ, pos_nor_batch->verts[0], GPU_indexbuf_build(&elb),
+ GPU_BATCH_OWNS_INDEX);
+ }
+ return SHC.drw_bone_box_wire;
+}
+
+/* Helpers for envelope bone's solid sphere-with-hidden-equatorial-cylinder.
+ * Note that here we only encode head/tail in forth component of the vector. */
+static void benv_lat_lon_to_co(const float lat, const float lon, float r_nor[3])
+{
+ r_nor[0] = sinf(lat) * cosf(lon);
+ r_nor[1] = sinf(lat) * sinf(lon);
+ r_nor[2] = cosf(lat);
+}
+
+GPUBatch *DRW_cache_bone_envelope_solid_get(void)
+{
+ if (!SHC.drw_bone_envelope) {
+ const int lon_res = 24;
+ const int lat_res = 24;
+ const float lon_inc = 2.0f * M_PI / lon_res;
+ const float lat_inc = M_PI / lat_res;
+ uint v_idx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, ((lat_res + 1) * 2) * lon_res * 1);
+
+ float lon = 0.0f;
+ for (int i = 0; i < lon_res; i++, lon += lon_inc) {
+ float lat = 0.0f;
+ float co1[3], co2[3];
+
+ /* Note: the poles are duplicated on purpose, to restart the strip. */
+
+ /* 1st sphere */
+ for (int j = 0; j < lat_res; j++, lat += lat_inc) {
+ benv_lat_lon_to_co(lat, lon, co1);
+ benv_lat_lon_to_co(lat, lon + lon_inc, co2);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
+ }
+
+ /* Closing the loop */
+ benv_lat_lon_to_co(M_PI, lon, co1);
+ benv_lat_lon_to_co(M_PI, lon + lon_inc, co2);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v_idx++, co2);
+ }
+
+ SHC.drw_bone_envelope = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_bone_envelope;
+}
+
+GPUBatch *DRW_cache_bone_envelope_outline_get(void)
+{
+ if (!SHC.drw_bone_envelope_outline) {
+# define CIRCLE_RESOL 64
+ float v0[2], v1[2], v2[2];
+ const float radius = 1.0f;
+
+ /* Position Only 2D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos0, pos1, pos2; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos0 = GPU_vertformat_attr_add(&format, "pos0", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.pos1 = GPU_vertformat_attr_add(&format, "pos1", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.pos2 = GPU_vertformat_attr_add(&format, "pos2", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
+
+ v0[0] = radius * sinf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
+ v0[1] = radius * cosf((2.0f * M_PI * -2) / ((float)CIRCLE_RESOL));
+ v1[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
+ v1[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
+
+ /* Output 4 verts for each position. See shader for explanation. */
+ uint v = 0;
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v2[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v2[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
+ copy_v2_v2(v0, v1);
+ copy_v2_v2(v1, v2);
+ }
+ v2[0] = 0.0f;
+ v2[1] = radius;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos1, v, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos2, v++, v2);
+
+ SHC.drw_bone_envelope_outline = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+# undef CIRCLE_RESOL
+ }
+ return SHC.drw_bone_envelope_outline;
+}
+
+GPUBatch *DRW_cache_bone_point_get(void)
+{
+ if (!SHC.drw_bone_point) {
+#if 0 /* old style geometry sphere */
+ const int lon_res = 16;
+ const int lat_res = 8;
+ const float rad = 0.05f;
+ const float lon_inc = 2 * M_PI / lon_res;
+ const float lat_inc = M_PI / lat_res;
+ uint v_idx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, (lat_res - 1) * lon_res * 6);
+
+ float lon = 0.0f;
+ for (int i = 0; i < lon_res; i++, lon += lon_inc) {
+ float lat = 0.0f;
+ for (int j = 0; j < lat_res; j++, lat += lat_inc) {
+ if (j != lat_res - 1) { /* Pole */
+ add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon + lon_inc);
+ add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon);
+ add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat, lon);
+ }
+
+ if (j != 0) { /* Pole */
+ add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat, lon + lon_inc);
+ add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat + lat_inc, lon + lon_inc);
+ add_lat_lon_vert(vbo, attr_id.pos, attr_id.nor, &v_idx, rad, lat, lon);
+ }
+ }
+ }
+
+ SHC.drw_bone_point = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+#else
+# define CIRCLE_RESOL 64
+ float v[2];
+ const float radius = 0.05f;
+
+ /* Position Only 2D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
+
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a, v);
+ }
+
+ SHC.drw_bone_point = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
+# undef CIRCLE_RESOL
+#endif
+ }
+ return SHC.drw_bone_point;
+}
+
+GPUBatch *DRW_cache_bone_point_wire_outline_get(void)
+{
+ if (!SHC.drw_bone_point_wire) {
+#if 0 /* old style geometry sphere */
+ GPUVertBuf *vbo = sphere_wire_vbo(0.05f);
+ SHC.drw_bone_point_wire = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+#else
+# define CIRCLE_RESOL 64
+ float v0[2], v1[2];
+ const float radius = 0.05f;
+
+ /* Position Only 2D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos0, pos1; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos0 = GPU_vertformat_attr_add(&format, "pos0", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.pos1 = GPU_vertformat_attr_add(&format, "pos1", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, (CIRCLE_RESOL + 1) * 2);
+
+ v0[0] = radius * sinf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
+ v0[1] = radius * cosf((2.0f * M_PI * -1) / ((float)CIRCLE_RESOL));
+
+ uint v = 0;
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v1[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v1[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
+ copy_v2_v2(v0, v1);
+ }
+ v1[0] = 0.0f;
+ v1[1] = radius;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos0, v, v0);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos1, v++, v1);
+
+ SHC.drw_bone_point_wire = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+# undef CIRCLE_RESOL
+#endif
+ }
+ return SHC.drw_bone_point_wire;
+}
+
+/* keep in sync with armature_stick_vert.glsl */
+#define COL_WIRE (1 << 0)
+#define COL_HEAD (1 << 1)
+#define COL_TAIL (1 << 2)
+#define COL_BONE (1 << 3)
+
+#define POS_HEAD (1 << 4)
+#define POS_TAIL (1 << 5)
+#define POS_BONE (1 << 6)
+
+GPUBatch *DRW_cache_bone_stick_get(void)
+{
+ if (!SHC.drw_bone_stick) {
+#define CIRCLE_RESOL 12
+ uint v = 0;
+ uint flag;
+ const float radius = 2.0f; /* head/tail radius */
+ float pos[2];
+
+ /* Position Only 2D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, flag; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.flag = GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+
+ const uint vcount = (CIRCLE_RESOL + 1) * 2 + 6;
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vcount);
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init_ex(&elb, GPU_PRIM_TRI_FAN, (CIRCLE_RESOL + 2) * 2 + 6 + 2, vcount, true);
+
+ /* head/tail points */
+ for (int i = 0; i < 2; ++i) {
+ /* center vertex */
+ copy_v2_fl(pos, 0.0f);
+ flag = (i == 0) ? POS_HEAD : POS_TAIL;
+ flag |= (i == 0) ? COL_HEAD : COL_TAIL;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, pos);
+ GPU_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ /* circle vertices */
+ flag |= COL_WIRE;
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ pos[0] = radius * sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ pos[1] = radius * cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, pos);
+ GPU_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ }
+ /* Close the circle */
+ GPU_indexbuf_add_generic_vert(&elb, v - CIRCLE_RESOL);
+
+ GPU_indexbuf_add_primitive_restart(&elb);
+ }
+
+ /* Bone rectangle */
+ pos[0] = 0.0f;
+ for (int i = 0; i < 6; ++i) {
+ pos[1] = (i == 0 || i == 3) ? 0.0f : ((i < 3) ? 1.0f : -1.0f);
+ flag = ((i < 2 || i > 4) ? POS_HEAD : POS_TAIL) |
+ ((i == 0 || i == 3) ? 0 : COL_WIRE) | COL_BONE | POS_BONE;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, pos);
+ GPU_vertbuf_attr_set(vbo, attr_id.flag, v, &flag);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ }
+
+ SHC.drw_bone_stick = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, GPU_indexbuf_build(&elb),
+ GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+#undef CIRCLE_RESOL
+ }
+ return SHC.drw_bone_stick;
+}
+
+static void set_bone_axis_vert(
+ GPUVertBuf *vbo, uint axis, uint pos, uint col,
+ uint *v, const float *a, const float *p, const float *c)
+{
+ GPU_vertbuf_attr_set(vbo, axis, *v, a);
+ GPU_vertbuf_attr_set(vbo, pos, *v, p);
+ GPU_vertbuf_attr_set(vbo, col, *v, c);
+ *v += 1;
+}
+
+#define S_X 0.0215f
+#define S_Y 0.025f
+static float x_axis_name[4][2] = {
+ { 0.9f * S_X, 1.0f * S_Y}, {-1.0f * S_X, -1.0f * S_Y},
+ {-0.9f * S_X, 1.0f * S_Y}, { 1.0f * S_X, -1.0f * S_Y}
+};
+#define X_LEN (sizeof(x_axis_name) / (sizeof(float) * 2))
+#undef S_X
+#undef S_Y
+
+#define S_X 0.0175f
+#define S_Y 0.025f
+static float y_axis_name[6][2] = {
+ {-1.0f * S_X, 1.0f * S_Y}, { 0.0f * S_X, -0.1f * S_Y},
+ { 1.0f * S_X, 1.0f * S_Y}, { 0.0f * S_X, -0.1f * S_Y},
+ { 0.0f * S_X, -0.1f * S_Y}, { 0.0f * S_X, -1.0f * S_Y}
+};
+#define Y_LEN (sizeof(y_axis_name) / (sizeof(float) * 2))
+#undef S_X
+#undef S_Y
+
+#define S_X 0.02f
+#define S_Y 0.025f
+static float z_axis_name[10][2] = {
+ {-0.95f * S_X, 1.00f * S_Y}, { 0.95f * S_X, 1.00f * S_Y},
+ { 0.95f * S_X, 1.00f * S_Y}, { 0.95f * S_X, 0.90f * S_Y},
+ { 0.95f * S_X, 0.90f * S_Y}, {-1.00f * S_X, -0.90f * S_Y},
+ {-1.00f * S_X, -0.90f * S_Y}, {-1.00f * S_X, -1.00f * S_Y},
+ {-1.00f * S_X, -1.00f * S_Y}, { 1.00f * S_X, -1.00f * S_Y}
+};
+#define Z_LEN (sizeof(z_axis_name) / (sizeof(float) * 2))
+#undef S_X
+#undef S_Y
+
+#define S_X 0.007f
+#define S_Y 0.007f
+static float axis_marker[8][2] = {
+#if 0 /* square */
+ {-1.0f * S_X, 1.0f * S_Y}, { 1.0f * S_X, 1.0f * S_Y},
+ { 1.0f * S_X, 1.0f * S_Y}, { 1.0f * S_X, -1.0f * S_Y},
+ { 1.0f * S_X, -1.0f * S_Y}, {-1.0f * S_X, -1.0f * S_Y},
+ {-1.0f * S_X, -1.0f * S_Y}, {-1.0f * S_X, 1.0f * S_Y}
+#else /* diamond */
+ {-S_X, 0.f}, { 0.f, S_Y},
+ { 0.f, S_Y}, { S_X, 0.f},
+ { S_X, 0.f}, { 0.f, -S_Y},
+ { 0.f, -S_Y}, {-S_X, 0.f}
+#endif
+};
+#define MARKER_LEN (sizeof(axis_marker) / (sizeof(float) * 2))
+#define MARKER_FILL_LAYER 6
+#undef S_X
+#undef S_Y
+
+#define S_X 0.0007f
+#define S_Y 0.0007f
+#define O_X 0.001f
+#define O_Y -0.001f
+static float axis_name_shadow[8][2] = {
+ {-S_X + O_X, S_Y + O_Y}, { S_X + O_X, S_Y + O_Y},
+ { S_X + O_X, S_Y + O_Y}, { S_X + O_X, -S_Y + O_Y},
+ { S_X + O_X, -S_Y + O_Y}, {-S_X + O_X, -S_Y + O_Y},
+ {-S_X + O_X, -S_Y + O_Y}, {-S_X + O_X, S_Y + O_Y}
+};
+// #define SHADOW_RES (sizeof(axis_name_shadow) / (sizeof(float) * 2))
+#define SHADOW_RES 0
+#undef O_X
+#undef O_Y
+#undef S_X
+#undef S_Y
+
+GPUBatch *DRW_cache_bone_arrows_get(void)
+{
+ if (!SHC.drw_bone_arrows) {
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint axis, pos, col; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.axis = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ attr_id.pos = GPU_vertformat_attr_add(&format, "screenPos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.col = GPU_vertformat_attr_add(&format, "colorAxis", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ /* Line */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, (2 + MARKER_LEN * MARKER_FILL_LAYER) * 3 +
+ (X_LEN + Y_LEN + Z_LEN) * (1 + SHADOW_RES));
+
+ uint v = 0;
+
+ for (int axis = 0; axis < 3; axis++) {
+ float pos[2] = {0.0f, 0.0f};
+ float c[3] = {0.0f, 0.0f, 0.0f};
+ float a = 0.0f;
+ /* center to axis line */
+ set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
+ c[axis] = 0.5f;
+ a = axis + 0.25f;
+ set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col, &v, &a, pos, c);
+
+ /* Axis end marker */
+ for (int j = 1; j < MARKER_FILL_LAYER + 1; ++j) {
+ for (int i = 0; i < MARKER_LEN; ++i) {
+ float tmp[2];
+ mul_v2_v2fl(tmp, axis_marker[i], j / (float)MARKER_FILL_LAYER);
+ set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col,
+ &v, &a, tmp, c);
+ }
+ }
+
+ a = axis + 0.31f;
+ /* Axis name */
+ int axis_v_len;
+ float (*axis_verts)[2];
+ if (axis == 0) {
+ axis_verts = x_axis_name;
+ axis_v_len = X_LEN;
+ }
+ else if (axis == 1) {
+ axis_verts = y_axis_name;
+ axis_v_len = Y_LEN;
+ }
+ else {
+ axis_verts = z_axis_name;
+ axis_v_len = Z_LEN;
+ }
+
+ /* Axis name shadows */
+ copy_v3_fl(c, 0.0f);
+ c[axis] = 0.3f;
+ for (int j = 0; j < SHADOW_RES; ++j) {
+ for (int i = 0; i < axis_v_len; ++i) {
+ float tmp[2];
+ add_v2_v2v2(tmp, axis_verts[i], axis_name_shadow[j]);
+ set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col,
+ &v, &a, tmp, c);
+ }
+ }
+
+ /* Axis name */
+ copy_v3_fl(c, 0.1f);
+ c[axis] = 1.0f;
+ for (int i = 0; i < axis_v_len; ++i) {
+ set_bone_axis_vert(vbo, attr_id.axis, attr_id.pos, attr_id.col,
+ &v, &a, axis_verts[i], c);
+ }
+ }
+
+ SHC.drw_bone_arrows = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_bone_arrows;
+}
+
+const float staticSine[16] = {
+ 0.0f, 0.104528463268f, 0.207911690818f, 0.309016994375f,
+ 0.406736643076f, 0.5f, 0.587785252292f, 0.669130606359f,
+ 0.743144825477f, 0.809016994375f, 0.866025403784f,
+ 0.913545457643f, 0.951056516295f, 0.978147600734f,
+ 0.994521895368f, 1.0f
+};
+
+#define set_vert(a, b, quarter) \
+ copy_v2_fl2(pos, (quarter % 2 == 0) ? -(a) : (a), (quarter < 2) ? -(b) : (b)); \
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v++, pos);
+
+GPUBatch *DRW_cache_bone_dof_sphere_get(void)
+{
+ if (!SHC.drw_bone_dof_sphere) {
+ int i, j, q, n = ARRAY_SIZE(staticSine);
+ float x, z, px, pz, pos[2];
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, n * n * 6 * 4);
+
+ uint v = 0;
+ for (q = 0; q < 4; ++q) {
+ pz = 0.0f;
+ for (i = 1; i < n; ++i) {
+ z = staticSine[i];
+ px = 0.0f;
+ for (j = 1; j <= (n - i); ++j) {
+ x = staticSine[j];
+ if (j == n - i) {
+ set_vert(px, z, q);
+ set_vert(px, pz, q);
+ set_vert(x, pz, q);
+ }
+ else {
+ set_vert(x, z, q);
+ set_vert(x, pz, q);
+ set_vert(px, z, q);
+
+ set_vert(x, pz, q);
+ set_vert(px, pz, q);
+ set_vert(px, z, q);
+ }
+ px = x;
+ }
+ pz = z;
+ }
+ }
+ /* TODO alloc right count from the begining. */
+ GPU_vertbuf_data_resize(vbo, v);
+
+ SHC.drw_bone_dof_sphere = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_bone_dof_sphere;
+}
+
+GPUBatch *DRW_cache_bone_dof_lines_get(void)
+{
+ if (!SHC.drw_bone_dof_lines) {
+ int i, n = ARRAY_SIZE(staticSine);
+ float pos[2];
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, n * 4);
+
+ uint v = 0;
+ for (i = 0; i < n * 4; i++) {
+ float a = (1.0f - (i / (float)(n * 4))) * 2.0f * M_PI;
+ float x = cosf(a);
+ float y = sinf(a);
+ set_vert(x, y, 0);
+ }
+
+ SHC.drw_bone_dof_lines = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_bone_dof_lines;
+}
+
+#undef set_vert
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Camera
+ * \{ */
+
+/**
+ * We could make these more generic functions.
+ * although filling 1d lines is not common.
+ *
+ * \note Use x coordinate to identify the vertex the vertex shader take care to place it appropriately.
+ */
+
+static const float camera_coords_frame_bounds[5] = {
+ 0.0f, /* center point */
+ 1.0f, /* + X + Y */
+ 2.0f, /* + X - Y */
+ 3.0f, /* - X - Y */
+ 4.0f, /* - X + Y */
+};
+
+static const float camera_coords_frame_tri[3] = {
+ 5.0f, /* tria + X */
+ 6.0f, /* tria - X */
+ 7.0f, /* tria + Y */
+};
+
+/** Draw a loop of lines. */
+static void camera_fill_lines_loop_fl_v1(
+ GPUVertBufRaw *pos_step,
+ const float *coords, const uint coords_len)
+{
+ for (uint i = 0, i_prev = coords_len - 1; i < coords_len; i_prev = i++) {
+ *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i_prev];
+ *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
+ }
+}
+
+/** Fan lines out from the first vertex. */
+static void camera_fill_lines_fan_fl_v1(
+ GPUVertBufRaw *pos_step,
+ const float *coords, const uint coords_len)
+{
+ for (uint i = 1; i < coords_len; i++) {
+ *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[0];
+ *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
+ }
+}
+
+/** Simply fill the array. */
+static void camera_fill_array_fl_v1(
+ GPUVertBufRaw *pos_step,
+ const float *coords, const uint coords_len)
+{
+ for (uint i = 0; i < coords_len; i++) {
+ *((float *)GPU_vertbuf_raw_step(pos_step)) = coords[i];
+ }
+}
+
+
+GPUBatch *DRW_cache_camera_get(void)
+{
+ if (!SHC.drw_camera) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = 22;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ GPUVertBufRaw pos_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+
+ /* camera cone (from center to frame) */
+ camera_fill_lines_fan_fl_v1(&pos_step, camera_coords_frame_bounds, ARRAY_SIZE(camera_coords_frame_bounds));
+
+ /* camera frame (skip center) */
+ camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
+
+ /* camera triangle (above the frame) */
+ camera_fill_lines_loop_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
+
+ BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
+
+ SHC.drw_camera = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_camera;
+}
+
+GPUBatch *DRW_cache_camera_frame_get(void)
+{
+ if (!SHC.drw_camera_frame) {
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = 8;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ GPUVertBufRaw pos_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+
+ /* camera frame (skip center) */
+ camera_fill_lines_loop_fl_v1(&pos_step, &camera_coords_frame_bounds[1], ARRAY_SIZE(camera_coords_frame_bounds) - 1);
+
+ BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
+
+ SHC.drw_camera_frame = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_camera_frame;
+}
+
+GPUBatch *DRW_cache_camera_tria_get(void)
+{
+ if (!SHC.drw_camera_tria) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ /* Vertices */
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = 3;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ GPUVertBufRaw pos_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+
+ /* camera triangle (above the frame) */
+ camera_fill_array_fl_v1(&pos_step, camera_coords_frame_tri, ARRAY_SIZE(camera_coords_frame_tri));
+
+ BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
+
+ SHC.drw_camera_tria = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_camera_tria;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Object Mode Helpers
+ * \{ */
+
+/* Object Center */
+GPUBatch *DRW_cache_single_vert_get(void)
+{
+ if (!SHC.drw_single_vertice) {
+ float v1[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Position Only 3D format */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 1);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 0, v1);
+
+ SHC.drw_single_vertice = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_single_vertice;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Meshes
+ * \{ */
+
+GPUBatch *DRW_cache_mesh_surface_overlay_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_all_triangles(me);
+}
+
+void DRW_cache_mesh_wire_overlay_get(
+ Object *ob,
+ GPUBatch **r_tris, GPUBatch **r_ledges, GPUBatch **r_lverts,
+ struct GPUTexture **r_data_tex)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+
+ *r_tris = DRW_mesh_batch_cache_get_overlay_triangles(me);
+ *r_ledges = DRW_mesh_batch_cache_get_overlay_loose_edges(me);
+ *r_lverts = DRW_mesh_batch_cache_get_overlay_loose_verts(me);
+ *r_data_tex = DRW_mesh_batch_cache_get_overlay_data_tex(me);
+}
+
+void DRW_cache_mesh_normals_overlay_get(
+ Object *ob,
+ GPUBatch **r_tris, GPUBatch **r_tris_lnor, GPUBatch **r_ledges, GPUBatch **r_lverts)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+
+ *r_tris = DRW_mesh_batch_cache_get_overlay_triangles_nor(me);
+ *r_tris_lnor = DRW_mesh_batch_cache_get_overlay_triangles_lnor(me);
+ *r_ledges = DRW_mesh_batch_cache_get_overlay_loose_edges_nor(me);
+ *r_lverts = DRW_mesh_batch_cache_get_overlay_loose_verts(me);
+}
+
+GPUBatch *DRW_cache_face_centers_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+
+ return DRW_mesh_batch_cache_get_overlay_facedots(me);
+}
+
+GPUBatch *DRW_cache_mesh_wire_outline_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_fancy_edges(me);
+}
+
+GPUBatch *DRW_cache_mesh_edge_detection_get(Object *ob, bool *r_is_manifold)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_edge_detection(me, r_is_manifold);
+}
+
+GPUBatch *DRW_cache_mesh_surface_get(Object *ob, bool use_hide)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_triangles_with_normals(me, use_hide);
+}
+
+void DRW_cache_mesh_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ DRW_mesh_batch_cache_get_wireframes_face_texbuf(me, r_vert_tx, r_faceid_tx, r_tri_count);
+}
+
+GPUBatch *DRW_cache_mesh_loose_edges_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_loose_edges_with_normals(me);
+}
+
+GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob, ToolSettings *ts, bool paint_mode)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+
+ /* Extract complete vertex weight group selection state and mode flags. */
+ struct DRW_MeshWeightState wstate;
+ memset(&wstate, 0, sizeof(wstate));
+
+ wstate.defgroup_active = ob->actdef - 1;
+ wstate.defgroup_len = BLI_listbase_count(&ob->defbase);
+
+ wstate.alert_mode = ts->weightuser;
+
+ if (paint_mode && ts->multipaint) {
+ /* Multipaint needs to know all selected bones, not just the active group.
+ * This is actually a relatively expensive operation, but caching would be difficult. */
+ wstate.defgroup_sel = BKE_object_defgroup_selected_get(ob, wstate.defgroup_len, &wstate.defgroup_sel_count);
+
+ if (wstate.defgroup_sel_count > 1) {
+ wstate.flags |= DRW_MESH_WEIGHT_STATE_MULTIPAINT | (ts->auto_normalize ? DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE : 0);
+
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ BKE_object_defgroup_mirror_selection(
+ ob, wstate.defgroup_len, wstate.defgroup_sel, wstate.defgroup_sel, &wstate.defgroup_sel_count);
+ }
+ }
+ /* With only one selected bone Multipaint reverts to regular mode. */
+ else {
+ wstate.defgroup_sel_count = 0;
+ MEM_SAFE_FREE(wstate.defgroup_sel);
+ }
+ }
+
+ /* Generate the weight data using the selection. */
+ GPUBatch *batch = DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(me, &wstate);
+
+ DRW_mesh_weight_state_clear(&wstate);
+
+ return batch;
+}
+
+GPUBatch *DRW_cache_mesh_surface_vert_colors_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(me);
+}
+
+/* Return list of batches */
+GPUBatch **DRW_cache_mesh_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, bool use_hide,
+ char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_surface_shaded(me, gpumat_array, gpumat_array_len, use_hide,
+ auto_layer_names, auto_layer_is_srgb, auto_layer_count);
+}
+
+/* Return list of batches */
+GPUBatch **DRW_cache_mesh_surface_texpaint_get(Object *ob, bool use_hide)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_surface_texpaint(me, use_hide);
+}
+
+GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_surface_texpaint_single(me);
+}
+
+GPUBatch *DRW_cache_mesh_surface_verts_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_points_with_normals(me);
+}
+
+GPUBatch *DRW_cache_mesh_edges_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_all_edges(me);
+}
+
+GPUBatch *DRW_cache_mesh_verts_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_all_verts(me);
+}
+
+GPUBatch *DRW_cache_mesh_edges_paint_overlay_get(Object *ob, bool use_wire, bool use_sel)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_weight_overlay_edges(me, use_wire, use_sel, use_sel);
+}
+
+GPUBatch *DRW_cache_mesh_faces_weight_overlay_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_weight_overlay_faces(me);
+}
+
+GPUBatch *DRW_cache_mesh_verts_weight_overlay_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ return DRW_mesh_batch_cache_get_weight_overlay_verts(me);
+}
+
+void DRW_cache_mesh_sculpt_coords_ensure(Object *ob)
+{
+ BLI_assert(ob->type == OB_MESH);
+
+ Mesh *me = ob->data;
+ DRW_mesh_cache_sculpt_coords_ensure(me);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Curve
+ * \{ */
+
+GPUBatch *DRW_cache_curve_edge_wire_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_CURVE);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_wire_edge(cu, ob->runtime.curve_cache);
+}
+
+GPUBatch *DRW_cache_curve_edge_normal_get(Object *ob, float normal_size)
+{
+ BLI_assert(ob->type == OB_CURVE);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_normal_edge(cu, ob->runtime.curve_cache, normal_size);
+}
+
+GPUBatch *DRW_cache_curve_edge_overlay_get(Object *ob)
+{
+ BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF));
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_overlay_edges(cu);
+}
+
+GPUBatch *DRW_cache_curve_vert_overlay_get(Object *ob, bool handles)
+{
+ BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF));
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_overlay_verts(cu, handles);
+}
+
+GPUBatch *DRW_cache_curve_surface_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_CURVE);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache);
+}
+
+void DRW_cache_curve_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count)
+{
+ BLI_assert(ob->type == OB_CURVE);
+
+ struct Curve *cu = ob->data;
+ DRW_curve_batch_cache_get_wireframes_face_texbuf(cu, ob->runtime.curve_cache, r_vert_tx, r_faceid_tx, r_tri_count);
+}
+
+/* Return list of batches */
+GPUBatch **DRW_cache_curve_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ BLI_assert(ob->type == OB_CURVE);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name MetaBall
+ * \{ */
+
+GPUBatch *DRW_cache_mball_surface_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MBALL);
+ return DRW_metaball_batch_cache_get_triangles_with_normals(ob);
+}
+
+void DRW_cache_mball_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count)
+{
+ BLI_assert(ob->type == OB_MBALL);
+ DRW_metaball_batch_cache_get_wireframes_face_texbuf(ob, r_vert_tx, r_faceid_tx, r_tri_count);
+}
+
+GPUBatch **DRW_cache_mball_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ BLI_assert(ob->type == OB_MBALL);
+ MetaBall *mb = ob->data;
+ return DRW_metaball_batch_cache_get_surface_shaded(ob, mb, gpumat_array, gpumat_array_len);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Font
+ * \{ */
+
+GPUBatch *DRW_cache_text_edge_wire_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_FONT);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_wire_edge(cu, ob->runtime.curve_cache);
+}
+
+GPUBatch *DRW_cache_text_surface_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_FONT);
+ struct Curve *cu = ob->data;
+ if (cu->editfont && (cu->flag & CU_FAST)) {
+ return NULL;
+ }
+ return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache);
+}
+
+void DRW_cache_text_face_wireframe_get(
+ Object *ob,
+ struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count)
+{
+ BLI_assert(ob->type == OB_FONT);
+ struct Curve *cu = ob->data;
+ if (cu->editfont && (cu->flag & CU_FAST)) {
+ *r_vert_tx = NULL;
+ *r_faceid_tx = NULL;
+ *r_tri_count = 0;
+ return;
+ }
+ DRW_curve_batch_cache_get_wireframes_face_texbuf(cu, ob->runtime.curve_cache, r_vert_tx, r_faceid_tx, r_tri_count);
+}
+
+GPUBatch **DRW_cache_text_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ BLI_assert(ob->type == OB_FONT);
+ struct Curve *cu = ob->data;
+ if (cu->editfont && (cu->flag & CU_FAST)) {
+ return NULL;
+ }
+ return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len);
+}
+
+GPUBatch *DRW_cache_text_cursor_overlay_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_FONT);
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_overlay_cursor(cu);
+}
+
+GPUBatch *DRW_cache_text_select_overlay_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_FONT);
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_overlay_select(cu);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Surface
+ * \{ */
+
+GPUBatch *DRW_cache_surf_surface_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_SURF);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache);
+}
+
+void DRW_cache_surf_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count)
+{
+ BLI_assert(ob->type == OB_SURF);
+
+ struct Curve *cu = ob->data;
+ DRW_curve_batch_cache_get_wireframes_face_texbuf(cu, ob->runtime.curve_cache, r_vert_tx, r_faceid_tx, r_tri_count);
+}
+
+/* Return list of batches */
+GPUBatch **DRW_cache_surf_surface_shaded_get(
+ Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ BLI_assert(ob->type == OB_SURF);
+
+ struct Curve *cu = ob->data;
+ return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Lattice
+ * \{ */
+
+GPUBatch *DRW_cache_lattice_verts_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_LATTICE);
+
+ struct Lattice *lt = ob->data;
+ return DRW_lattice_batch_cache_get_all_verts(lt);
+}
+
+GPUBatch *DRW_cache_lattice_wire_get(Object *ob, bool use_weight)
+{
+ BLI_assert(ob->type == OB_LATTICE);
+
+ Lattice *lt = ob->data;
+ int actdef = -1;
+
+ if (use_weight && ob->defbase.first && lt->editlatt->latt->dvert) {
+ actdef = ob->actdef - 1;
+ }
+
+ return DRW_lattice_batch_cache_get_all_edges(lt, use_weight, actdef);
+}
+
+GPUBatch *DRW_cache_lattice_vert_overlay_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_LATTICE);
+
+ struct Lattice *lt = ob->data;
+ return DRW_lattice_batch_cache_get_overlay_verts(lt);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Particles
+ * \{ */
+
+GPUBatch *DRW_cache_particles_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
+{
+ return DRW_particles_batch_cache_get_hair(object, psys, md);
+}
+
+GPUBatch *DRW_cache_particles_get_dots(Object *object, ParticleSystem *psys)
+{
+ return DRW_particles_batch_cache_get_dots(object, psys);
+}
+
+GPUBatch *DRW_cache_particles_get_edit_strands(
+ Object *object,
+ ParticleSystem *psys,
+ struct PTCacheEdit *edit,
+ bool use_weight)
+{
+ return DRW_particles_batch_cache_get_edit_strands(object, psys, edit, use_weight);
+}
+
+GPUBatch *DRW_cache_particles_get_edit_inner_points(
+ Object *object,
+ ParticleSystem *psys,
+ struct PTCacheEdit *edit)
+{
+ return DRW_particles_batch_cache_get_edit_inner_points(object, psys, edit);
+}
+
+GPUBatch *DRW_cache_particles_get_edit_tip_points(
+ Object *object,
+ ParticleSystem *psys,
+ struct PTCacheEdit *edit)
+{
+ return DRW_particles_batch_cache_get_edit_tip_points(object, psys, edit);
+}
+
+GPUBatch *DRW_cache_particles_get_prim(int type)
+{
+ switch (type) {
+ case PART_DRAW_CROSS:
+ if (!SHC.drw_particle_cross) {
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, axis_id;
+
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "inst_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ axis_id = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 6);
+
+ /* X axis */
+ float co[3] = {-1.0f, 0.0f, 0.0f};
+ int axis = -1;
+ GPU_vertbuf_attr_set(vbo, pos_id, 0, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 0, &axis);
+
+ co[0] = 1.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, 1, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 1, &axis);
+
+ /* Y axis */
+ co[0] = 0.0f;
+ co[1] = -1.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, 2, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 2, &axis);
+
+ co[1] = 1.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, 3, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 3, &axis);
+
+ /* Z axis */
+ co[1] = 0.0f;
+ co[2] = -1.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, 4, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 4, &axis);
+
+ co[2] = 1.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, 5, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 5, &axis);
+
+ SHC.drw_particle_cross = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+
+ return SHC.drw_particle_cross;
+ case PART_DRAW_AXIS:
+ if (!SHC.drw_particle_axis) {
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, axis_id;
+
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "inst_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ axis_id = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 6);
+
+ /* X axis */
+ float co[3] = {0.0f, 0.0f, 0.0f};
+ int axis = 0;
+ GPU_vertbuf_attr_set(vbo, pos_id, 0, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 0, &axis);
+
+ co[0] = 1.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, 1, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 1, &axis);
+
+ /* Y axis */
+ co[0] = 0.0f;
+ axis = 1;
+ GPU_vertbuf_attr_set(vbo, pos_id, 2, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 2, &axis);
+
+ co[1] = 1.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, 3, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 3, &axis);
+
+ /* Z axis */
+ co[1] = 0.0f;
+ axis = 2;
+ GPU_vertbuf_attr_set(vbo, pos_id, 4, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 4, &axis);
+
+ co[2] = 1.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, 5, co);
+ GPU_vertbuf_attr_set(vbo, axis_id, 5, &axis);
+
+ SHC.drw_particle_axis = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+
+ return SHC.drw_particle_axis;
+ case PART_DRAW_CIRC:
+#define CIRCLE_RESOL 32
+ if (!SHC.drw_particle_circle) {
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ int axis = -1;
+
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, axis_id;
+
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "inst_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ axis_id = GPU_vertformat_attr_add(&format, "axis", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CIRCLE_RESOL);
+
+ for (int a = 0; a < CIRCLE_RESOL; a++) {
+ v[0] = sinf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[1] = cosf((2.0f * M_PI * a) / ((float)CIRCLE_RESOL));
+ v[2] = 0.0f;
+ GPU_vertbuf_attr_set(vbo, pos_id, a, v);
+ GPU_vertbuf_attr_set(vbo, axis_id, a, &axis);
+ }
+
+ SHC.drw_particle_circle = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+
+ return SHC.drw_particle_circle;
+#undef CIRCLE_RESOL
+ default:
+ BLI_assert(false);
+ break;
+ }
+
+ return NULL;
+}
+
+/* 3D cursor */
+GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
+{
+ GPUBatch **drw_cursor = crosshair_lines ? &SHC.drw_cursor : &SHC.drw_cursor_only_circle;
+
+ if (*drw_cursor == NULL) {
+ const float f5 = 0.25f;
+ const float f10 = 0.5f;
+ const float f20 = 1.0f;
+
+ const int segments = 16;
+ const int vert_len = segments + 8;
+ const int index_len = vert_len + 5;
+
+ uchar red[3] = {255, 0, 0};
+ uchar white[3] = {255, 255, 255};
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, color; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ attr_id.color = GPU_vertformat_attr_add(&format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len, true);
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vert_len);
+
+ int v = 0;
+ for (int i = 0; i < segments; ++i) {
+ float angle = (float)(2 * M_PI) * ((float)i / (float)segments);
+ float x = f10 * cosf(angle);
+ float y = f10 * sinf(angle);
+
+ if (i % 2 == 0)
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, red);
+ else
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, white);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){x, y});
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ }
+ GPU_indexbuf_add_generic_vert(&elb, 0);
+
+ if (crosshair_lines) {
+ uchar crosshair_color[3];
+ UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color);
+
+ GPU_indexbuf_add_primitive_restart(&elb);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){-f20, 0});
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){-f5, 0});
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+
+ GPU_indexbuf_add_primitive_restart(&elb);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){+f5, 0});
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){+f20, 0});
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+
+ GPU_indexbuf_add_primitive_restart(&elb);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, -f20});
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, -f5});
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+
+ GPU_indexbuf_add_primitive_restart(&elb);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, +f5});
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, +f20});
+ GPU_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color);
+ GPU_indexbuf_add_generic_vert(&elb, v++);
+ }
+
+ GPUIndexBuf *ibo = GPU_indexbuf_build(&elb);
+
+ *drw_cursor = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, ibo, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+ }
+ return *drw_cursor;
+}
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
new file mode 100644
index 00000000000..1eeef83c81e
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_cache.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_CACHE_H__
+#define __DRAW_CACHE_H__
+
+struct GPUBatch;
+struct GPUMaterial;
+struct ModifierData;
+struct Object;
+struct PTCacheEdit;
+
+void DRW_shape_cache_free(void);
+void DRW_shape_cache_reset(void);
+
+/* 3D cursor */
+struct GPUBatch *DRW_cache_cursor_get(bool crosshair_lines);
+
+/* Common Shapes */
+struct GPUBatch *DRW_cache_grid_get(void);
+struct GPUBatch *DRW_cache_fullscreen_quad_get(void);
+struct GPUBatch *DRW_cache_quad_get(void);
+struct GPUBatch *DRW_cache_cube_get(void);
+struct GPUBatch *DRW_cache_sphere_get(void);
+struct GPUBatch *DRW_cache_single_vert_get(void);
+struct GPUBatch *DRW_cache_single_line_get(void);
+struct GPUBatch *DRW_cache_single_line_endpoints_get(void);
+struct GPUBatch *DRW_cache_screenspace_circle_get(void);
+
+/* Common Object */
+struct GPUBatch *DRW_cache_object_wire_outline_get(struct Object *ob);
+struct GPUBatch *DRW_cache_object_edge_detection_get(struct Object *ob, bool *r_is_manifold);
+struct GPUBatch *DRW_cache_object_surface_get(struct Object *ob);
+struct GPUBatch *DRW_cache_object_surface_get_ex(struct Object *ob, bool use_hide);
+struct GPUBatch *DRW_cache_object_loose_edges_get(struct Object *ob);
+struct GPUBatch **DRW_cache_object_surface_material_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, bool use_hide,
+ char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count);
+void DRW_cache_object_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count);
+
+/* Empties */
+struct GPUBatch *DRW_cache_plain_axes_get(void);
+struct GPUBatch *DRW_cache_single_arrow_get(void);
+struct GPUBatch *DRW_cache_empty_cube_get(void);
+struct GPUBatch *DRW_cache_circle_get(void);
+struct GPUBatch *DRW_cache_square_get(void);
+struct GPUBatch *DRW_cache_empty_sphere_get(void);
+struct GPUBatch *DRW_cache_empty_cylinder_get(void);
+struct GPUBatch *DRW_cache_empty_cone_get(void);
+struct GPUBatch *DRW_cache_empty_capsule_cap_get(void);
+struct GPUBatch *DRW_cache_empty_capsule_body_get(void);
+struct GPUBatch *DRW_cache_image_plane_get(void);
+struct GPUBatch *DRW_cache_image_plane_wire_get(void);
+
+/* Force Field */
+struct GPUBatch *DRW_cache_field_wind_get(void);
+struct GPUBatch *DRW_cache_field_force_get(void);
+struct GPUBatch *DRW_cache_field_vortex_get(void);
+struct GPUBatch *DRW_cache_field_tube_limit_get(void);
+struct GPUBatch *DRW_cache_field_cone_limit_get(void);
+
+/* Grease Pencil */
+struct GPUBatch *DRW_cache_gpencil_axes_get(void);
+
+/* Lamps */
+struct GPUBatch *DRW_cache_lamp_get(void);
+struct GPUBatch *DRW_cache_lamp_shadows_get(void);
+struct GPUBatch *DRW_cache_lamp_sunrays_get(void);
+struct GPUBatch *DRW_cache_lamp_area_square_get(void);
+struct GPUBatch *DRW_cache_lamp_area_disk_get(void);
+struct GPUBatch *DRW_cache_lamp_hemi_get(void);
+struct GPUBatch *DRW_cache_lamp_spot_get(void);
+struct GPUBatch *DRW_cache_lamp_spot_volume_get(void);
+struct GPUBatch *DRW_cache_lamp_spot_square_get(void);
+struct GPUBatch *DRW_cache_lamp_spot_square_volume_get(void);
+
+/* Camera */
+struct GPUBatch *DRW_cache_camera_get(void);
+struct GPUBatch *DRW_cache_camera_frame_get(void);
+struct GPUBatch *DRW_cache_camera_tria_get(void);
+
+/* Speaker */
+struct GPUBatch *DRW_cache_speaker_get(void);
+
+/* Probe */
+struct GPUBatch *DRW_cache_lightprobe_cube_get(void);
+struct GPUBatch *DRW_cache_lightprobe_grid_get(void);
+struct GPUBatch *DRW_cache_lightprobe_planar_get(void);
+
+/* Bones */
+struct GPUBatch *DRW_cache_bone_octahedral_get(void);
+struct GPUBatch *DRW_cache_bone_octahedral_wire_get(void);
+struct GPUBatch *DRW_cache_bone_box_get(void);
+struct GPUBatch *DRW_cache_bone_box_wire_get(void);
+struct GPUBatch *DRW_cache_bone_envelope_solid_get(void);
+struct GPUBatch *DRW_cache_bone_envelope_outline_get(void);
+struct GPUBatch *DRW_cache_bone_envelope_head_wire_outline_get(void);
+struct GPUBatch *DRW_cache_bone_point_get(void);
+struct GPUBatch *DRW_cache_bone_point_wire_outline_get(void);
+struct GPUBatch *DRW_cache_bone_stick_get(void);
+struct GPUBatch *DRW_cache_bone_arrows_get(void);
+struct GPUBatch *DRW_cache_bone_dof_sphere_get(void);
+struct GPUBatch *DRW_cache_bone_dof_lines_get(void);
+
+/* Meshes */
+struct GPUBatch *DRW_cache_mesh_surface_overlay_get(struct Object *ob);
+void DRW_cache_mesh_wire_overlay_get(
+ struct Object *ob,
+ struct GPUBatch **r_tris, struct GPUBatch **r_ledges, struct GPUBatch **r_lverts,
+ struct GPUTexture **r_data_tex);
+void DRW_cache_mesh_normals_overlay_get(
+ struct Object *ob,
+ struct GPUBatch **r_tris, struct GPUBatch **r_tris_lnor,
+ struct GPUBatch **r_ledges, struct GPUBatch **r_lverts);
+struct GPUBatch *DRW_cache_face_centers_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_wire_outline_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_edge_detection_get(struct Object *ob, bool *r_is_manifold);
+struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob, bool use_hide);
+struct GPUBatch *DRW_cache_mesh_loose_edges_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob, struct ToolSettings *ts, bool paint_mode);
+struct GPUBatch *DRW_cache_mesh_surface_vert_colors_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_surface_verts_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_edges_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_verts_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_edges_paint_overlay_get(struct Object *ob, bool use_wire, bool use_sel);
+struct GPUBatch *DRW_cache_mesh_faces_weight_overlay_get(struct Object *ob);
+struct GPUBatch *DRW_cache_mesh_verts_weight_overlay_get(struct Object *ob);
+struct GPUBatch **DRW_cache_mesh_surface_shaded_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, bool use_hide,
+ char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count);
+struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob, bool use_hide);
+struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob);
+void DRW_cache_mesh_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count);
+
+void DRW_cache_mesh_sculpt_coords_ensure(struct Object *ob);
+
+/* Curve */
+struct GPUBatch *DRW_cache_curve_surface_get(struct Object *ob);
+struct GPUBatch **DRW_cache_curve_surface_shaded_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+struct GPUBatch *DRW_cache_curve_surface_verts_get(struct Object *ob);
+struct GPUBatch *DRW_cache_curve_edge_wire_get(struct Object *ob);
+void DRW_cache_curve_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count);
+/* edit-mode */
+struct GPUBatch *DRW_cache_curve_edge_normal_get(struct Object *ob, float normal_size);
+struct GPUBatch *DRW_cache_curve_edge_overlay_get(struct Object *ob);
+struct GPUBatch *DRW_cache_curve_vert_overlay_get(struct Object *ob, bool handles);
+
+/* Font */
+struct GPUBatch *DRW_cache_text_edge_wire_get(struct Object *ob);
+struct GPUBatch *DRW_cache_text_surface_get(struct Object *ob);
+struct GPUBatch **DRW_cache_text_surface_shaded_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+void DRW_cache_text_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count);
+/* edit-mode */
+struct GPUBatch *DRW_cache_text_cursor_overlay_get(struct Object *ob);
+struct GPUBatch *DRW_cache_text_select_overlay_get(struct Object *ob);
+
+/* Surface */
+struct GPUBatch *DRW_cache_surf_surface_get(struct Object *ob);
+struct GPUBatch **DRW_cache_surf_surface_shaded_get(
+ struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+void DRW_cache_surf_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count);
+
+/* Lattice */
+struct GPUBatch *DRW_cache_lattice_verts_get(struct Object *ob);
+struct GPUBatch *DRW_cache_lattice_wire_get(struct Object *ob, bool use_weight);
+struct GPUBatch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
+
+/* Particles */
+struct GPUBatch *DRW_cache_particles_get_hair(
+ struct Object *object, struct ParticleSystem *psys, struct ModifierData *md);
+struct GPUBatch *DRW_cache_particles_get_dots(
+ struct Object *object, struct ParticleSystem *psys);
+struct GPUBatch *DRW_cache_particles_get_edit_strands(
+ struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit, bool use_weight);
+struct GPUBatch *DRW_cache_particles_get_edit_inner_points(
+ struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
+struct GPUBatch *DRW_cache_particles_get_edit_tip_points(
+ struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
+struct GPUBatch *DRW_cache_particles_get_prim(int type);
+
+/* Metaball */
+struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob);
+struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+void DRW_cache_mball_face_wireframe_get(
+ Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count);
+
+#endif /* __DRAW_CACHE_H__ */
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
new file mode 100644
index 00000000000..720d54ad011
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_cache_impl.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_CACHE_IMPL_H__
+#define __DRAW_CACHE_IMPL_H__
+
+struct CurveCache;
+struct GPUMaterial;
+struct GPUTexture;
+struct GPUBatch;
+struct GPUIndexBuf;
+struct GPUVertBuf;
+struct ListBase;
+struct ModifierData;
+struct ParticleSystem;
+struct PTCacheEdit;
+struct SpaceImage;
+
+struct Curve;
+struct Lattice;
+struct Mesh;
+struct MetaBall;
+struct bGPdata;
+
+/* Expose via BKE callbacks */
+void DRW_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode);
+void DRW_mball_batch_cache_free(struct MetaBall *mb);
+
+void DRW_curve_batch_cache_dirty_tag(struct Curve *cu, int mode);
+void DRW_curve_batch_cache_free(struct Curve *cu);
+
+void DRW_mesh_batch_cache_dirty_tag(struct Mesh *me, int mode);
+void DRW_mesh_batch_cache_free(struct Mesh *me);
+
+void DRW_lattice_batch_cache_dirty_tag(struct Lattice *lt, int mode);
+void DRW_lattice_batch_cache_free(struct Lattice *lt);
+
+void DRW_particle_batch_cache_dirty_tag(struct ParticleSystem *psys, int mode);
+void DRW_particle_batch_cache_free(struct ParticleSystem *psys);
+
+void DRW_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
+void DRW_gpencil_batch_cache_free(struct bGPdata *gpd);
+
+/* Curve */
+struct GPUBatch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu, struct CurveCache *ob_curve_cache);
+struct GPUBatch *DRW_curve_batch_cache_get_normal_edge(
+ struct Curve *cu, struct CurveCache *ob_curve_cache, float normal_size);
+struct GPUBatch *DRW_curve_batch_cache_get_overlay_edges(struct Curve *cu);
+struct GPUBatch *DRW_curve_batch_cache_get_overlay_verts(struct Curve *cu, bool handles);
+
+struct GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(
+ struct Curve *cu, struct CurveCache *ob_curve_cache);
+struct GPUBatch **DRW_curve_batch_cache_get_surface_shaded(
+ struct Curve *cu, struct CurveCache *ob_curve_cache,
+ struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+void DRW_curve_batch_cache_get_wireframes_face_texbuf(
+ struct Curve *cu, struct CurveCache *ob_curve_cache,
+ struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count);
+
+/* Metaball */
+struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob);
+struct GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(struct Object *ob, struct MetaBall *mb, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+void DRW_metaball_batch_cache_get_wireframes_face_texbuf(
+ struct Object *ob, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count);
+
+/* Curve (Font) */
+struct GPUBatch *DRW_curve_batch_cache_get_overlay_cursor(struct Curve *cu);
+struct GPUBatch *DRW_curve_batch_cache_get_overlay_select(struct Curve *cu);
+
+/* DispList */
+struct GPUVertBuf *DRW_displist_vertbuf_calc_pos_with_normals(struct ListBase *lb);
+struct GPUIndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(struct ListBase *lb);
+struct GPUIndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(
+ struct ListBase *lb, uint gpumat_array_len);
+struct GPUBatch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(
+ struct ListBase *lb, uint gpumat_array_len);
+struct GPUVertBuf *DRW_displist_create_edges_overlay_texture_buf(ListBase *lb);
+
+/* Lattice */
+struct GPUBatch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt, bool use_weight, const int actdef);
+struct GPUBatch *DRW_lattice_batch_cache_get_all_verts(struct Lattice *lt);
+struct GPUBatch *DRW_lattice_batch_cache_get_overlay_verts(struct Lattice *lt);
+
+/* Vertex Group Selection and display options */
+struct DRW_MeshWeightState {
+ int defgroup_active;
+ int defgroup_len;
+
+ short flags;
+ char alert_mode;
+
+ /* Set of all selected bones for Multipaint. */
+ bool *defgroup_sel; /* [defgroup_len] */
+ int defgroup_sel_count;
+};
+
+/* DRW_MeshWeightState.flags */
+enum {
+ DRW_MESH_WEIGHT_STATE_MULTIPAINT = (1 << 0),
+ DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE = (1 << 1),
+};
+
+void DRW_mesh_weight_state_clear(struct DRW_MeshWeightState *wstate);
+void DRW_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst, const struct DRW_MeshWeightState *wstate_src);
+bool DRW_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, const struct DRW_MeshWeightState *b);
+
+/* Mesh */
+struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(
+ struct Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len, bool use_hide,
+ char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count);
+struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me, bool use_hide);
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_edges(struct Mesh *me, bool use_wire, bool use_sel, bool use_hide);
+struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_faces(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_verts(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_all_edges(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_all_triangles(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals(struct Mesh *me, bool use_hide);
+struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(struct Mesh *me, const struct DRW_MeshWeightState *wstate);
+struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me, bool use_hide, uint select_id_offset);
+struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_mask(struct Mesh *me, bool use_hide);
+struct GPUBatch *DRW_mesh_batch_cache_get_loose_edges_with_normals(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_points_with_normals(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_all_verts(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_fancy_edges(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edge_detection(struct Mesh *me, bool *r_is_manifold);
+struct GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles_nor(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles_lnor(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_overlay_verts(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_edges(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_edges_nor(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_verts(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_overlay_facedots(struct Mesh *me);
+struct GPUTexture *DRW_mesh_batch_cache_get_overlay_data_tex(struct Mesh *me);
+/* edit-mesh selection (use generic function for faces) */
+struct GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(struct Mesh *me, uint select_id_offset);
+struct GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(struct Mesh *me, uint select_id_offset);
+struct GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(struct Mesh *me, uint select_id_offset);
+/* Object mode Wireframe overlays */
+void DRW_mesh_batch_cache_get_wireframes_face_texbuf(
+ struct Mesh *me, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count);
+
+void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me);
+
+enum {
+ UVEDIT_EDGES = (1 << 0),
+ UVEDIT_DATA = (1 << 1),
+ UVEDIT_FACEDOTS = (1 << 2),
+ UVEDIT_FACES = (1 << 3),
+ UVEDIT_STRETCH_ANGLE = (1 << 4),
+ UVEDIT_STRETCH_AREA = (1 << 5),
+ UVEDIT_SYNC_SEL = (1 << 6),
+};
+
+/* For Image UV editor. */
+struct GPUBatch *DRW_mesh_batch_cache_get_texpaint_loop_wire(struct Mesh *me);
+void DRW_mesh_cache_uvedit(
+ struct Object *me, struct SpaceImage *sima, struct Scene *scene, uchar state,
+ struct GPUBatch **faces, struct GPUBatch **edges, struct GPUBatch **verts, struct GPUBatch **facedots);
+
+/* Edit mesh bitflags (is this the right place?) */
+
+enum {
+ VFLAG_VERTEX_ACTIVE = 1 << 0,
+ VFLAG_VERTEX_SELECTED = 1 << 1,
+ VFLAG_VERTEX_EXISTS = 1 << 2,
+ VFLAG_FACE_ACTIVE = 1 << 3,
+ VFLAG_FACE_SELECTED = 1 << 4,
+ VFLAG_FACE_FREESTYLE = 1 << 5,
+ /* Beware to not go over 1 << 7 (it's a byte flag)
+ * (see gpu_shader_edit_mesh_overlay_geom.glsl) */
+};
+
+enum {
+ VFLAG_EDGE_EXISTS = 1 << 0,
+ VFLAG_EDGE_ACTIVE = 1 << 1,
+ VFLAG_EDGE_SELECTED = 1 << 2,
+ VFLAG_EDGE_SEAM = 1 << 3,
+ VFLAG_EDGE_SHARP = 1 << 4,
+ VFLAG_EDGE_FREESTYLE = 1 << 5,
+ /* Beware to not go over 1 << 7 (it's a byte flag)
+ * (see gpu_shader_edit_mesh_overlay_geom.glsl) */
+};
+
+/* Particles */
+struct GPUBatch *DRW_particles_batch_cache_get_hair(
+ struct Object *object, struct ParticleSystem *psys, struct ModifierData *md);
+struct GPUBatch *DRW_particles_batch_cache_get_dots(
+ struct Object *object, struct ParticleSystem *psys);
+struct GPUBatch *DRW_particles_batch_cache_get_edit_strands(
+ struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit, bool use_weight);
+struct GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(
+ struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
+struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(
+ struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
+
+#endif /* __DRAW_CACHE_IMPL_H__ */
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c
new file mode 100644
index 00000000000..f214f722c0b
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_curve.c
@@ -0,0 +1,1132 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_cache_impl_curve.c
+ * \ingroup draw
+ *
+ * \brief Curve API for render engines
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "DNA_curve_types.h"
+
+#include "BKE_curve.h"
+
+#include "BKE_font.h"
+
+#include "GPU_batch.h"
+#include "GPU_texture.h"
+
+#include "UI_resources.h"
+
+#include "DRW_render.h"
+
+#include "draw_cache_impl.h" /* own include */
+
+#define SELECT 1
+#define ACTIVE_NURB 1 << 2
+#define EVEN_U_BIT 1 << 3 /* Alternate this bit for every U vert. */
+
+/* Used as values of `color_id` in `edit_curve_overlay_handle_geom.glsl` */
+enum {
+ COLOR_NURB_ULINE_ID = TH_HANDLE_AUTOCLAMP - TH_HANDLE_FREE + 2,
+
+ TOT_HANDLE_COL,
+};
+
+/**
+ * TODO
+ * - Ensure `CurveCache`, `SEQUENCER_DAG_WORKAROUND`.
+ * - Check number of verts/edges to see if cache is valid.
+ * - Check if 'overlay.edges' can use single attribute per edge, not 2 (for selection drawing).
+ */
+
+static void curve_batch_cache_clear(Curve *cu);
+
+/* ---------------------------------------------------------------------- */
+/* Curve Interface, direct access to basic data. */
+
+static void curve_render_overlay_verts_edges_len_get(
+ ListBase *lb, int *r_vert_len, int *r_edge_len)
+{
+ BLI_assert(r_vert_len || r_edge_len);
+ int vert_len = 0;
+ int edge_len = 0;
+ for (Nurb *nu = lb->first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ vert_len += nu->pntsu * 3;
+ /* 2x handles per point*/
+ edge_len += 2 * nu->pntsu;
+ }
+ else if (nu->bp) {
+ vert_len += nu->pntsu * nu->pntsv;
+ /* segments between points */
+ edge_len += (nu->pntsu - 1) * nu->pntsv;
+ edge_len += (nu->pntsv - 1) * nu->pntsu;
+ }
+ }
+ if (r_vert_len) {
+ *r_vert_len = vert_len;
+ }
+ if (r_edge_len) {
+ *r_edge_len = edge_len;
+ }
+}
+
+static void curve_render_wire_verts_edges_len_get(
+ const CurveCache *ob_curve_cache,
+ int *r_vert_len, int *r_edge_len)
+{
+ BLI_assert(r_vert_len || r_edge_len);
+ int vert_len = 0;
+ int edge_len = 0;
+ for (const BevList *bl = ob_curve_cache->bev.first; bl; bl = bl->next) {
+ if (bl->nr > 0) {
+ const bool is_cyclic = bl->poly != -1;
+
+ /* verts */
+ vert_len += bl->nr;
+
+ /* edges */
+ edge_len += bl->nr;
+ if (!is_cyclic) {
+ edge_len -= 1;
+ }
+ }
+ }
+ if (r_vert_len) {
+ *r_vert_len = vert_len;
+ }
+ if (r_edge_len) {
+ *r_edge_len = edge_len;
+ }
+}
+
+static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache)
+{
+ int normal_len = 0;
+ const BevList *bl;
+ const Nurb *nu;
+ for (bl = ob_curve_cache->bev.first, nu = lb->first; nu && bl; bl = bl->next, nu = nu->next) {
+ int nr = bl->nr;
+ int skip = nu->resolu / 16;
+#if 0
+ while (nr-- > 0) { /* accounts for empty bevel lists */
+ normal_len += 1;
+ nr -= skip;
+ }
+#else
+ /* Same as loop above */
+ normal_len += (nr / (skip + 1)) + ((nr % (skip + 1)) != 0);
+#endif
+ }
+ return normal_len;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Curve Interface, indirect, partially cached access to complex data. */
+
+typedef struct CurveRenderData {
+ int types;
+
+ struct {
+ int vert_len;
+ int edge_len;
+ } overlay;
+
+ struct {
+ int vert_len;
+ int edge_len;
+ } wire;
+
+ /* edit mode normal's */
+ struct {
+ /* 'edge_len == len * 2'
+ * 'vert_len == len * 3' */
+ int len;
+ } normal;
+
+ struct {
+ EditFont *edit_font;
+ } text;
+
+ /* borrow from 'Object' */
+ CurveCache *ob_curve_cache;
+
+ /* borrow from 'Curve' */
+ ListBase *nurbs;
+
+ /* edit, index in nurb list */
+ int actnu;
+ /* edit, index in active nurb (BPoint or BezTriple) */
+ int actvert;
+} CurveRenderData;
+
+enum {
+ /* Wire center-line */
+ CU_DATATYPE_WIRE = 1 << 0,
+ /* Edit-mode verts and optionally handles */
+ CU_DATATYPE_OVERLAY = 1 << 1,
+ /* Edit-mode normals */
+ CU_DATATYPE_NORMAL = 1 << 2,
+ /* Geometry */
+ CU_DATATYPE_SURFACE = 1 << 3,
+ /* Text */
+ CU_DATATYPE_TEXT_SELECT = 1 << 4,
+};
+
+/*
+ * ob_curve_cache can be NULL, only needed for CU_DATATYPE_WIRE
+ */
+static CurveRenderData *curve_render_data_create(Curve *cu, CurveCache *ob_curve_cache, const int types)
+{
+ CurveRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
+ rdata->types = types;
+ ListBase *nurbs;
+
+ rdata->actnu = cu->actnu;
+ rdata->actvert = cu->actvert;
+
+ rdata->ob_curve_cache = ob_curve_cache;
+
+ if (types & CU_DATATYPE_WIRE) {
+ curve_render_wire_verts_edges_len_get(
+ rdata->ob_curve_cache,
+ &rdata->wire.vert_len, &rdata->wire.edge_len);
+ }
+
+ if (cu->editnurb) {
+ EditNurb *editnurb = cu->editnurb;
+ nurbs = &editnurb->nurbs;
+
+ if (types & CU_DATATYPE_OVERLAY) {
+ curve_render_overlay_verts_edges_len_get(
+ nurbs,
+ &rdata->overlay.vert_len,
+ &rdata->overlay.edge_len);
+
+ rdata->actnu = cu->actnu;
+ rdata->actvert = cu->actvert;
+ }
+ if (types & CU_DATATYPE_NORMAL) {
+ rdata->normal.len = curve_render_normal_len_get(nurbs, rdata->ob_curve_cache);
+ }
+ }
+ else {
+ nurbs = &cu->nurb;
+ }
+
+ rdata->nurbs = nurbs;
+
+ rdata->text.edit_font = cu->editfont;
+
+ return rdata;
+}
+
+static void curve_render_data_free(CurveRenderData *rdata)
+{
+#if 0
+ if (rdata->loose_verts) {
+ MEM_freeN(rdata->loose_verts);
+ }
+#endif
+ MEM_freeN(rdata);
+}
+
+static int curve_render_data_overlay_verts_len_get(const CurveRenderData *rdata)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_OVERLAY);
+ return rdata->overlay.vert_len;
+}
+
+static int curve_render_data_overlay_edges_len_get(const CurveRenderData *rdata)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_OVERLAY);
+ return rdata->overlay.edge_len;
+}
+
+static int curve_render_data_wire_verts_len_get(const CurveRenderData *rdata)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_WIRE);
+ return rdata->wire.vert_len;
+}
+
+static int curve_render_data_wire_edges_len_get(const CurveRenderData *rdata)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_WIRE);
+ return rdata->wire.edge_len;
+}
+
+static int curve_render_data_normal_len_get(const CurveRenderData *rdata)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
+ return rdata->normal.len;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* Curve GPUBatch Cache */
+
+typedef struct CurveBatchCache {
+ /* center-line */
+ struct {
+ GPUVertBuf *verts;
+ GPUVertBuf *edges;
+ GPUBatch *batch;
+ GPUIndexBuf *elem;
+ } wire;
+
+ /* normals */
+ struct {
+ GPUVertBuf *verts;
+ GPUVertBuf *edges;
+ GPUBatch *batch;
+ GPUIndexBuf *elem;
+ } normal;
+
+ /* control handles and vertices */
+ struct {
+ GPUBatch *edges;
+ GPUBatch *verts;
+ GPUBatch *verts_no_handles;
+ } overlay;
+
+ struct {
+ GPUVertBuf *verts;
+ GPUIndexBuf *triangles_in_order;
+ GPUBatch **shaded_triangles;
+ GPUBatch *batch;
+ int mat_len;
+ } surface;
+
+ /* Wireframes */
+ struct {
+ GPUVertBuf *elem_vbo;
+ GPUTexture *elem_tx;
+ GPUTexture *verts_tx;
+ uint tri_count;
+ } face_wire;
+
+ /* 3d text */
+ struct {
+ GPUBatch *select;
+ GPUBatch *cursor;
+ } text;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+
+ float normal_size;
+
+ bool is_editmode;
+} CurveBatchCache;
+
+/* GPUBatch cache management. */
+
+static bool curve_batch_cache_valid(Curve *cu)
+{
+ CurveBatchCache *cache = cu->batch_cache;
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ if (cache->is_dirty) {
+ return false;
+ }
+
+ if (cache->is_editmode != ((cu->editnurb != NULL) || (cu->editfont != NULL))) {
+ return false;
+ }
+
+ if (cache->is_editmode) {
+ if (cu->editfont) {
+ /* TODO */
+ }
+ }
+
+ return true;
+}
+
+static void curve_batch_cache_init(Curve *cu)
+{
+ CurveBatchCache *cache = cu->batch_cache;
+
+ if (!cache) {
+ cache = cu->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+#if 0
+ ListBase *nurbs;
+ if (cu->editnurb) {
+ EditNurb *editnurb = cu->editnurb;
+ nurbs = &editnurb->nurbs;
+ }
+ else {
+ nurbs = &cu->nurb;
+ }
+#endif
+
+ cache->is_editmode = (cu->editnurb != NULL) || (cu->editfont != NULL);
+
+ cache->is_dirty = false;
+}
+
+static CurveBatchCache *curve_batch_cache_get(Curve *cu)
+{
+ if (!curve_batch_cache_valid(cu)) {
+ curve_batch_cache_clear(cu);
+ curve_batch_cache_init(cu);
+ }
+ return cu->batch_cache;
+}
+
+void DRW_curve_batch_cache_dirty_tag(Curve *cu, int mode)
+{
+ CurveBatchCache *cache = cu->batch_cache;
+ if (cache == NULL) {
+ return;
+ }
+ switch (mode) {
+ case BKE_CURVE_BATCH_DIRTY_ALL:
+ cache->is_dirty = true;
+ break;
+ case BKE_CURVE_BATCH_DIRTY_SELECT:
+ /* editnurb */
+ GPU_BATCH_DISCARD_SAFE(cache->overlay.verts_no_handles);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay.verts);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay.edges);
+
+ /* editfont */
+ GPU_BATCH_DISCARD_SAFE(cache->text.select);
+ GPU_BATCH_DISCARD_SAFE(cache->text.cursor);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void curve_batch_cache_clear(Curve *cu)
+{
+ CurveBatchCache *cache = cu->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ GPU_BATCH_DISCARD_SAFE(cache->overlay.verts_no_handles);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay.verts);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay.edges);
+
+ GPU_VERTBUF_DISCARD_SAFE(cache->surface.verts);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->surface.triangles_in_order);
+
+ GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len);
+ GPU_BATCH_DISCARD_SAFE(cache->surface.batch);
+
+ GPU_VERTBUF_DISCARD_SAFE(cache->face_wire.elem_vbo);
+ DRW_TEXTURE_FREE_SAFE(cache->face_wire.elem_tx);
+ DRW_TEXTURE_FREE_SAFE(cache->face_wire.verts_tx);
+ cache->face_wire.tri_count = 0;
+
+ /* don't own vbo & elems */
+ GPU_BATCH_DISCARD_SAFE(cache->wire.batch);
+ GPU_VERTBUF_DISCARD_SAFE(cache->wire.verts);
+ GPU_VERTBUF_DISCARD_SAFE(cache->wire.edges);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->wire.elem);
+
+ /* don't own vbo & elems */
+ GPU_BATCH_DISCARD_SAFE(cache->normal.batch);
+ GPU_VERTBUF_DISCARD_SAFE(cache->normal.verts);
+ GPU_VERTBUF_DISCARD_SAFE(cache->normal.edges);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->normal.elem);
+
+ /* 3d text */
+ GPU_BATCH_DISCARD_SAFE(cache->text.cursor);
+ GPU_BATCH_DISCARD_SAFE(cache->text.select);
+}
+
+void DRW_curve_batch_cache_free(Curve *cu)
+{
+ curve_batch_cache_clear(cu);
+ MEM_SAFE_FREE(cu->batch_cache);
+}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Private Curve Cache API
+ * \{ */
+
+/* GPUBatch cache usage. */
+static GPUVertBuf *curve_batch_cache_get_wire_verts(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_WIRE);
+ BLI_assert(rdata->ob_curve_cache != NULL);
+
+ if (cache->wire.verts == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ const int vert_len = curve_render_data_wire_verts_len_get(rdata);
+
+ GPUVertBuf *vbo = cache->wire.verts = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vert_len);
+ int vbo_len_used = 0;
+ for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
+ if (bl->nr > 0) {
+ const int i_end = vbo_len_used + bl->nr;
+ for (const BevPoint *bevp = bl->bevpoints; vbo_len_used < i_end; vbo_len_used++, bevp++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bevp->vec);
+ }
+ }
+ }
+ BLI_assert(vbo_len_used == vert_len);
+ }
+
+ return cache->wire.verts;
+}
+
+static GPUIndexBuf *curve_batch_cache_get_wire_edges(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_WIRE);
+ BLI_assert(rdata->ob_curve_cache != NULL);
+
+ if (cache->wire.edges == NULL) {
+ const int vert_len = curve_render_data_wire_verts_len_get(rdata);
+ const int edge_len = curve_render_data_wire_edges_len_get(rdata);
+ int edge_len_used = 0;
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
+
+ int i = 0;
+ for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
+ if (bl->nr > 0) {
+ const bool is_cyclic = bl->poly != -1;
+ const int i_end = i + (bl->nr);
+ int i_prev;
+ if (is_cyclic) {
+ i_prev = i + (bl->nr - 1);
+ }
+ else {
+ i_prev = i;
+ i += 1;
+ }
+ for (; i < i_end; i_prev = i++) {
+ GPU_indexbuf_add_line_verts(&elb, i_prev, i);
+ edge_len_used += 1;
+ }
+ }
+ }
+ cache->wire.elem = GPU_indexbuf_build(&elb);
+ }
+
+ return cache->wire.elem;
+}
+
+static GPUVertBuf *curve_batch_cache_get_normal_verts(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
+ BLI_assert(rdata->ob_curve_cache != NULL);
+
+ if (cache->normal.verts == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ const int normal_len = curve_render_data_normal_len_get(rdata);
+ const int vert_len = normal_len * 3;
+
+ GPUVertBuf *vbo = cache->normal.verts = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vert_len);
+ int vbo_len_used = 0;
+
+ const BevList *bl;
+ const Nurb *nu;
+
+ for (bl = rdata->ob_curve_cache->bev.first, nu = rdata->nurbs->first;
+ nu && bl;
+ bl = bl->next, nu = nu->next)
+ {
+ const BevPoint *bevp = bl->bevpoints;
+ int nr = bl->nr;
+ int skip = nu->resolu / 16;
+
+ while (nr-- > 0) { /* accounts for empty bevel lists */
+ const float fac = bevp->radius * cache->normal_size;
+ float vec_a[3]; /* Offset perpendicular to the curve */
+ float vec_b[3]; /* Delta along the curve */
+
+ vec_a[0] = fac;
+ vec_a[1] = 0.0f;
+ vec_a[2] = 0.0f;
+
+ mul_qt_v3(bevp->quat, vec_a);
+ madd_v3_v3fl(vec_a, bevp->dir, -fac);
+
+ reflect_v3_v3v3(vec_b, vec_a, bevp->dir);
+ negate_v3(vec_b);
+
+ add_v3_v3(vec_a, bevp->vec);
+ add_v3_v3(vec_b, bevp->vec);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_a);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, bevp->vec);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_b);
+
+ bevp += skip + 1;
+ nr -= skip;
+ }
+ }
+ BLI_assert(vbo_len_used == vert_len);
+ }
+
+ return cache->normal.verts;
+}
+
+static GPUIndexBuf *curve_batch_cache_get_normal_edges(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
+ BLI_assert(rdata->ob_curve_cache != NULL);
+
+ if (cache->normal.edges == NULL) {
+ const int normal_len = curve_render_data_normal_len_get(rdata);
+ const int vert_len = normal_len * 3;
+ const int edge_len = normal_len * 2;
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
+
+ int vbo_len_used = 0;
+ for (int i = 0; i < normal_len; i++) {
+ GPU_indexbuf_add_line_verts(&elb, vbo_len_used + 0, vbo_len_used + 1);
+ GPU_indexbuf_add_line_verts(&elb, vbo_len_used + 1, vbo_len_used + 2);
+ vbo_len_used += 3;
+ }
+
+ BLI_assert(vbo_len_used == vert_len);
+
+ cache->normal.elem = GPU_indexbuf_build(&elb);
+ }
+
+ return cache->normal.elem;
+}
+
+static void curve_batch_cache_create_overlay_batches(Curve *cu)
+{
+ /* Since CU_DATATYPE_OVERLAY is slow to generate, generate them all at once */
+ int options = CU_DATATYPE_OVERLAY;
+
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+ CurveRenderData *rdata = curve_render_data_create(cu, NULL, options);
+
+ if (cache->overlay.verts == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attr_len == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = curve_render_data_overlay_verts_len_get(rdata);
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_POINTS, vbo_len_capacity, vbo_len_capacity);
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ int i = 0, nu_id = 0;
+ for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, nu_id++) {
+ const bool is_active_nurb = (nu_id == cu->actnu);
+ if (nu->bezt) {
+ int a = 0;
+ for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
+ if (bezt->hide == false) {
+ const bool is_active = (i == rdata->actvert);
+ GPU_indexbuf_add_point_vert(&elb, vbo_len_used + 1);
+ for (int j = 0; j < 3; j++) {
+ char vflag = ((&bezt->f1)[j] & SELECT) ? VFLAG_VERTEX_SELECTED : 0;
+ vflag |= (is_active) ? VFLAG_VERTEX_ACTIVE : 0;
+ vflag |= (is_active_nurb) ? ACTIVE_NURB : 0;
+ /* handle color id */
+ char col_id = (&bezt->h1)[j / 2];
+ vflag |= col_id << 4; /* << 4 because of EVEN_U_BIT */
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j]);
+ GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+ }
+ }
+ i += 1;
+ }
+ }
+ else if (nu->bp) {
+ int a = 0;
+ int pt_len = nu->pntsu * nu->pntsv;
+ for (const BPoint *bp = nu->bp; a < pt_len; a++, bp++) {
+ if (bp->hide == false) {
+ const bool is_active = (i == rdata->actvert);
+ char vflag = (bp->f1 & SELECT) ? VFLAG_VERTEX_SELECTED : 0;
+ vflag |= (is_active) ? VFLAG_VERTEX_ACTIVE : 0;
+ vflag |= (is_active_nurb) ? ACTIVE_NURB : 0;
+ vflag |= (((a % nu->pntsu) % 2) == 0) ? EVEN_U_BIT : 0;
+ vflag |= COLOR_NURB_ULINE_ID << 4; /* << 4 because of EVEN_U_BIT */
+ GPU_indexbuf_add_point_vert(&elb, vbo_len_used);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp->vec);
+ GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
+ vbo_len_used += 1;
+ }
+ i += 1;
+ }
+ }
+ i += nu->pntsu;
+ }
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+
+ GPUIndexBuf *ibo = GPU_indexbuf_build(&elb);
+
+ cache->overlay.verts = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ cache->overlay.verts_no_handles = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, ibo, GPU_BATCH_OWNS_INDEX);
+ }
+
+ if (cache->overlay.edges == NULL) {
+ GPUVertBuf *vbo = cache->overlay.verts->verts[0];
+
+ const int edge_len = curve_render_data_overlay_edges_len_get(rdata);
+ const int vbo_len_capacity = edge_len * 2;
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES, vbo_len_capacity, vbo->vertex_len);
+
+ int curr_index = 0;
+ int i = 0;
+ for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, i++) {
+ if (nu->bezt) {
+ int a = 0;
+ for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
+ if (bezt->hide == false) {
+ GPU_indexbuf_add_line_verts(&elb, curr_index + 1, curr_index + 0);
+ GPU_indexbuf_add_line_verts(&elb, curr_index + 1, curr_index + 2);
+ curr_index += 3;
+ }
+ }
+ }
+ else if (nu->bp) {
+ int a = 0;
+ int next_v_index = curr_index;
+ for (const BPoint *bp = nu->bp; a < nu->pntsu; a++, bp++) {
+ if (bp->hide == false) {
+ next_v_index += 1;
+ }
+ }
+
+ int pt_len = nu->pntsu * nu->pntsv;
+ for (a = 0; a < pt_len; a++) {
+ const BPoint *bp_curr = &nu->bp[a];
+ const BPoint *bp_next_u = ((a % nu->pntsu) < (nu->pntsu - 1)) ? &nu->bp[a + 1] : NULL;
+ const BPoint *bp_next_v = (a < (pt_len - nu->pntsu)) ? &nu->bp[a + nu->pntsu] : NULL;
+ if (bp_curr->hide == false) {
+ if (bp_next_u && (bp_next_u->hide == false)) {
+ GPU_indexbuf_add_line_verts(&elb, curr_index, curr_index + 1);
+ }
+ if (bp_next_v && (bp_next_v->hide == false)) {
+ GPU_indexbuf_add_line_verts(&elb, curr_index, next_v_index);
+ }
+ curr_index += 1;
+ }
+ if (bp_next_v && (bp_next_v->hide == false)) {
+ next_v_index += 1;
+ }
+ }
+ }
+ }
+
+ GPUIndexBuf *ibo = GPU_indexbuf_build(&elb);
+ cache->overlay.edges = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, ibo, GPU_BATCH_OWNS_INDEX);
+ }
+
+ curve_render_data_free(rdata);
+}
+
+static GPUBatch *curve_batch_cache_get_pos_and_normals(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_SURFACE);
+ if (cache->surface.batch == NULL) {
+ ListBase *lb = &rdata->ob_curve_cache->disp;
+
+ if (cache->surface.verts == NULL) {
+ cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
+ }
+ if (cache->surface.triangles_in_order == NULL) {
+ cache->surface.triangles_in_order = DRW_displist_indexbuf_calc_triangles_in_order(lb);
+ }
+ cache->surface.batch = GPU_batch_create(
+ GPU_PRIM_TRIS, cache->surface.verts, cache->surface.triangles_in_order);
+ }
+
+ return cache->surface.batch;
+}
+
+static GPUTexture *curve_batch_cache_get_edges_overlay_texture_buf(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_SURFACE);
+
+ if (cache->face_wire.elem_tx != NULL) {
+ return cache->face_wire.elem_tx;
+ }
+
+ ListBase *lb = &rdata->ob_curve_cache->disp;
+
+ /* We need a special index buffer. */
+ GPUVertBuf *vbo = cache->face_wire.elem_vbo = DRW_displist_create_edges_overlay_texture_buf(lb);
+
+ /* Upload data early because we need to create the texture for it. */
+ GPU_vertbuf_use(vbo);
+ cache->face_wire.elem_tx = GPU_texture_create_from_vertbuf(vbo);
+ cache->face_wire.tri_count = vbo->vertex_alloc / 3;
+
+ return cache->face_wire.elem_tx;
+}
+
+static GPUTexture *curve_batch_cache_get_vert_pos_and_nor_in_order_buf(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_SURFACE);
+
+ if (cache->face_wire.verts_tx == NULL) {
+ curve_batch_cache_get_pos_and_normals(rdata, cache);
+ GPU_vertbuf_use(cache->surface.verts); /* Upload early for buffer texture creation. */
+ cache->face_wire.verts_tx = GPU_texture_create_buffer(GPU_R32F, cache->surface.verts->vbo_id);
+ }
+
+ return cache->face_wire.verts_tx;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Private Object/Font Cache API
+ * \{ */
+
+
+static GPUBatch *curve_batch_cache_get_overlay_select(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT);
+ if (cache->text.select == NULL) {
+ EditFont *ef = rdata->text.edit_font;
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = ef->selboxes_len * 6;
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ float box[4][3];
+
+ /* fill in xy below */
+ box[0][2] = box[1][2] = box[2][2] = box[3][2] = 0.001;
+
+ for (int i = 0; i < ef->selboxes_len; i++) {
+ EditFontSelBox *sb = &ef->selboxes[i];
+
+ float selboxw;
+ if (i + 1 != ef->selboxes_len) {
+ if (ef->selboxes[i + 1].y == sb->y)
+ selboxw = ef->selboxes[i + 1].x - sb->x;
+ else
+ selboxw = sb->w;
+ }
+ else {
+ selboxw = sb->w;
+ }
+
+ if (sb->rot == 0.0f) {
+ copy_v2_fl2(box[0], sb->x, sb->y);
+ copy_v2_fl2(box[1], sb->x + selboxw, sb->y);
+ copy_v2_fl2(box[2], sb->x + selboxw, sb->y + sb->h);
+ copy_v2_fl2(box[3], sb->x, sb->y + sb->h);
+ }
+ else {
+ float mat[2][2];
+
+ angle_to_mat2(mat, sb->rot);
+
+ copy_v2_fl2(box[0], sb->x, sb->y);
+
+ copy_v2_fl2(box[1], selboxw, 0.0f);
+ mul_m2v2(mat, box[1]);
+ add_v2_v2(box[1], &sb->x);
+
+ copy_v2_fl2(box[2], selboxw, sb->h);
+ mul_m2v2(mat, box[2]);
+ add_v2_v2(box[2], &sb->x);
+
+ copy_v2_fl2(box[3], 0.0f, sb->h);
+ mul_m2v2(mat, box[3]);
+ add_v2_v2(box[3], &sb->x);
+ }
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[1]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[3]);
+ }
+ BLI_assert(vbo_len_used == vbo_len_capacity);
+ cache->text.select = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return cache->text.select;
+}
+
+static GPUBatch *curve_batch_cache_get_overlay_cursor(CurveRenderData *rdata, CurveBatchCache *cache)
+{
+ BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT);
+ if (cache->text.cursor == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = 4;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ for (int i = 0; i < 4; i++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->text.edit_font->textcurs[i]);
+ }
+ cache->text.cursor = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return cache->text.cursor;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public Object/Curve API
+ * \{ */
+
+GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu, CurveCache *ob_curve_cache)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->wire.batch == NULL) {
+ /* create batch from Curve */
+ CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_WIRE);
+
+ cache->wire.batch = GPU_batch_create(
+ GPU_PRIM_LINES,
+ curve_batch_cache_get_wire_verts(rdata, cache),
+ curve_batch_cache_get_wire_edges(rdata, cache));
+
+ curve_render_data_free(rdata);
+ }
+ return cache->wire.batch;
+}
+
+GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu, CurveCache *ob_curve_cache, float normal_size)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->normal.batch != NULL) {
+ cache->normal_size = normal_size;
+ if (cache->normal_size != normal_size) {
+ GPU_BATCH_DISCARD_SAFE(cache->normal.batch);
+ GPU_VERTBUF_DISCARD_SAFE(cache->normal.edges);
+ }
+ }
+ cache->normal_size = normal_size;
+
+ if (cache->normal.batch == NULL) {
+ /* create batch from Curve */
+ CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_NORMAL);
+
+ cache->normal.batch = GPU_batch_create(
+ GPU_PRIM_LINES,
+ curve_batch_cache_get_normal_verts(rdata, cache),
+ curve_batch_cache_get_normal_edges(rdata, cache));
+
+ curve_render_data_free(rdata);
+ cache->normal_size = normal_size;
+ }
+ return cache->normal.batch;
+}
+
+GPUBatch *DRW_curve_batch_cache_get_overlay_edges(Curve *cu)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->overlay.edges == NULL) {
+ curve_batch_cache_create_overlay_batches(cu);
+ }
+
+ return cache->overlay.edges;
+}
+
+GPUBatch *DRW_curve_batch_cache_get_overlay_verts(Curve *cu, bool handles)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->overlay.verts == NULL || cache->overlay.verts_no_handles == NULL) {
+ curve_batch_cache_create_overlay_batches(cu);
+ }
+
+ return (handles) ? cache->overlay.verts : cache->overlay.verts_no_handles;
+}
+
+GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(
+ struct Curve *cu, struct CurveCache *ob_curve_cache)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->surface.batch == NULL) {
+ CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
+
+ curve_batch_cache_get_pos_and_normals(rdata, cache);
+
+ curve_render_data_free(rdata);
+ }
+
+ return cache->surface.batch;
+}
+
+GPUBatch **DRW_curve_batch_cache_get_surface_shaded(
+ struct Curve *cu, struct CurveCache *ob_curve_cache,
+ struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->surface.mat_len != gpumat_array_len) {
+ GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len);
+ }
+
+ if (cache->surface.shaded_triangles == NULL) {
+ CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
+ ListBase *lb = &rdata->ob_curve_cache->disp;
+
+ cache->surface.mat_len = gpumat_array_len;
+ if (cu->flag & CU_UV_ORCO) {
+ cache->surface.shaded_triangles = DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(
+ lb, gpumat_array_len);
+ }
+ else {
+ cache->surface.shaded_triangles = MEM_mallocN(
+ sizeof(*cache->surface.shaded_triangles) * gpumat_array_len, __func__);
+ GPUIndexBuf **el = DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(
+ lb, gpumat_array_len);
+
+ if (cache->surface.verts == NULL) {
+ cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
+ }
+
+ for (int i = 0; i < gpumat_array_len; ++i) {
+ cache->surface.shaded_triangles[i] = GPU_batch_create_ex(
+ GPU_PRIM_TRIS, cache->surface.verts, el[i], GPU_BATCH_OWNS_INDEX);
+ }
+
+ MEM_freeN(el); /* Save `el` in cache? */
+ }
+
+ curve_render_data_free(rdata);
+ }
+
+ return cache->surface.shaded_triangles;
+}
+
+void DRW_curve_batch_cache_get_wireframes_face_texbuf(
+ Curve *cu, CurveCache *ob_curve_cache,
+ GPUTexture **verts_data, GPUTexture **face_indices, int *tri_count)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->face_wire.elem_tx == NULL || cache->face_wire.verts_tx == NULL) {
+ CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
+
+ curve_batch_cache_get_edges_overlay_texture_buf(rdata, cache);
+ curve_batch_cache_get_vert_pos_and_nor_in_order_buf(rdata, cache);
+
+ curve_render_data_free(rdata);
+ }
+
+ *tri_count = cache->face_wire.tri_count;
+ *face_indices = cache->face_wire.elem_tx;
+ *verts_data = cache->face_wire.verts_tx;
+}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public Object/Font API
+ * \{ */
+
+GPUBatch *DRW_curve_batch_cache_get_overlay_select(Curve *cu)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->text.select == NULL) {
+ CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT);
+
+ curve_batch_cache_get_overlay_select(rdata, cache);
+
+ curve_render_data_free(rdata);
+ }
+
+ return cache->text.select;
+}
+
+GPUBatch *DRW_curve_batch_cache_get_overlay_cursor(Curve *cu)
+{
+ CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+ if (cache->text.cursor == NULL) {
+ CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT);
+
+ curve_batch_cache_get_overlay_cursor(rdata, cache);
+
+ curve_render_data_free(rdata);
+ }
+
+ return cache->text.cursor;
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c
new file mode 100644
index 00000000000..d6a57676a8d
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_displist.c
@@ -0,0 +1,465 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_cache_impl_displist.c
+ * \ingroup draw
+ *
+ * \brief DispList API for render engines
+ *
+ * \note DispList may be removed soon! This is a utility for object types that use render.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_alloca.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "DNA_curve_types.h"
+
+#include "BKE_displist.h"
+
+#include "GPU_batch.h"
+
+#include "draw_cache_impl.h" /* own include */
+
+static int dl_vert_len(const DispList *dl)
+{
+ switch (dl->type) {
+ case DL_INDEX3:
+ case DL_INDEX4:
+ return dl->nr;
+ case DL_SURF:
+ return dl->parts * dl->nr;
+ }
+ return 0;
+}
+
+static int dl_tri_len(const DispList *dl)
+{
+ switch (dl->type) {
+ case DL_INDEX3:
+ return dl->parts;
+ case DL_INDEX4:
+ return dl->parts * 2;
+ case DL_SURF:
+ return dl->totindex * 2;
+ }
+ return 0;
+}
+
+/* see: displist_get_allverts */
+static int curve_render_surface_vert_len_get(const ListBase *lb)
+{
+ int vert_len = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ vert_len += dl_vert_len(dl);
+ }
+ return vert_len;
+}
+
+static int curve_render_surface_tri_len_get(const ListBase *lb)
+{
+ int tri_len = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ tri_len += dl_tri_len(dl);
+ }
+ return tri_len;
+}
+
+typedef void (setTriIndicesFn)(void *thunk, uint v1, uint v2, uint v3);
+
+static void displist_indexbufbuilder_set(
+ setTriIndicesFn *set_tri_indices,
+ setTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */
+ void *thunk, const DispList *dl, const int ofs)
+{
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ const int *idx = dl->index;
+ if (dl->type == DL_INDEX3) {
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++, idx += 3) {
+ set_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
+ }
+ }
+ else if (dl->type == DL_SURF) {
+ const int i_end = dl->totindex;
+ for (int i = 0; i < i_end; i++, idx += 4) {
+ set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
+ set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[3] + ofs);
+ }
+ }
+ else {
+ BLI_assert(dl->type == DL_INDEX4);
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++, idx += 4) {
+ if (idx[2] != idx[3]) {
+ set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
+ set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
+ }
+ else {
+ set_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
+ }
+ }
+ }
+ }
+}
+
+GPUVertBuf *DRW_displist_vertbuf_calc_pos_with_normals(ListBase *lb)
+{
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attr_len == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb));
+
+ BKE_displist_normals_add(lb);
+
+ int vbo_len_used = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ const bool ndata_is_single = dl->type == DL_INDEX3;
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ const float *fp_co = dl->verts;
+ const float *fp_no = dl->nors;
+ const int vbo_end = vbo_len_used + dl_vert_len(dl);
+ while (vbo_len_used < vbo_end) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co);
+ if (fp_no) {
+ static short short_no[4];
+ normal_float_to_short_v3(short_no, fp_no);
+ GPU_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, short_no);
+ if (ndata_is_single == false) {
+ fp_no += 3;
+ }
+ }
+ fp_co += 3;
+ vbo_len_used += 1;
+ }
+ }
+ }
+
+ return vbo;
+}
+
+GPUIndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(ListBase *lb)
+{
+ const int tri_len = curve_render_surface_tri_len_get(lb);
+ const int vert_len = curve_render_surface_vert_len_get(lb);
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len);
+
+ int ofs = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ displist_indexbufbuilder_set((setTriIndicesFn *)GPU_indexbuf_add_tri_verts,
+ (setTriIndicesFn *)GPU_indexbuf_add_tri_verts,
+ &elb, dl, ofs);
+ ofs += dl_vert_len(dl);
+ }
+
+ return GPU_indexbuf_build(&elb);
+}
+
+GPUIndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(ListBase *lb, uint gpumat_array_len)
+{
+ GPUIndexBuf **shaded_triangles_in_order = MEM_callocN(
+ sizeof(*shaded_triangles_in_order) * gpumat_array_len, __func__);
+ GPUIndexBufBuilder *elb = BLI_array_alloca(elb, gpumat_array_len);
+
+ const int tri_len = curve_render_surface_tri_len_get(lb);
+ const int vert_len = curve_render_surface_vert_len_get(lb);
+ int i;
+
+ /* Init each index buffer builder */
+ for (i = 0; i < gpumat_array_len; i++) {
+ GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, tri_len, vert_len);
+ }
+
+ /* calc each index buffer builder */
+ int ofs = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ displist_indexbufbuilder_set((setTriIndicesFn *)GPU_indexbuf_add_tri_verts,
+ (setTriIndicesFn *)GPU_indexbuf_add_tri_verts,
+ &elb[dl->col], dl, ofs);
+ ofs += dl_vert_len(dl);
+ }
+
+ /* build each indexbuf */
+ for (i = 0; i < gpumat_array_len; i++) {
+ shaded_triangles_in_order[i] = GPU_indexbuf_build(&elb[i]);
+ }
+
+ return shaded_triangles_in_order;
+}
+
+typedef struct DRWDisplistWireThunk {
+ uint index_id, vidx;
+ short dl_type;
+ GPUVertBuf *vbo;
+} DRWDisplistWireThunk;
+
+static void set_overlay_wires_tri_indices(void *thunk, uint v1, uint v2, uint v3)
+{
+ DRWDisplistWireThunk *dwt = (DRWDisplistWireThunk *)thunk;
+ /* Tag real edges. */
+ v1 |= (1 << 30);
+ v2 |= (1 << 30);
+ v3 |= (1 << 30);
+ GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v1);
+ GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v2);
+ GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v3);
+}
+
+static void set_overlay_wires_quad_tri_indices(void *thunk, uint v1, uint v2, uint v3)
+{
+ DRWDisplistWireThunk *dwt = (DRWDisplistWireThunk *)thunk;
+ /* Tag real edges. */
+ v2 |= (1 << 30);
+ v3 |= (1 << 30);
+ GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v1);
+ GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v2);
+ GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v3);
+}
+
+GPUVertBuf *DRW_displist_create_edges_overlay_texture_buf(ListBase *lb)
+{
+ GPUVertFormat format = {0};
+ uint index_id = GPU_vertformat_attr_add(&format, "index", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ GPU_vertbuf_data_alloc(vbo, curve_render_surface_tri_len_get(lb) * 3);
+
+ DRWDisplistWireThunk thunk = {.index_id = index_id, .vbo = vbo, .vidx = 0};
+
+ int ofs = 0;
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ thunk.dl_type = dl->type;
+ /* TODO consider non-manifold edges correctly. */
+ displist_indexbufbuilder_set(set_overlay_wires_tri_indices,
+ set_overlay_wires_quad_tri_indices,
+ &thunk, dl, ofs);
+ ofs += dl_vert_len(dl);
+ }
+
+ return vbo;
+}
+
+
+static void displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ GPUVertBufRaw *pos_step, GPUVertBufRaw *nor_step, GPUVertBufRaw *uv_step,
+ const float v1[3], const float v2[3], const float v3[3],
+ const float n1[3], const float n2[3], const float n3[3],
+ const float uv1[2], const float uv2[2], const float uv3[2])
+{
+ copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v1);
+ copy_v3_v3(GPU_vertbuf_raw_step(nor_step), n1);
+ copy_v2_v2(GPU_vertbuf_raw_step(uv_step), uv1);
+
+ copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v2);
+ copy_v3_v3(GPU_vertbuf_raw_step(nor_step), n2);
+ copy_v2_v2(GPU_vertbuf_raw_step(uv_step), uv2);
+
+ copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v3);
+ copy_v3_v3(GPU_vertbuf_raw_step(nor_step), n3);
+ copy_v2_v2(GPU_vertbuf_raw_step(uv_step), uv3);
+}
+
+GPUBatch **DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(ListBase *lb, uint gpumat_array_len)
+{
+ static GPUVertFormat shaded_triangles_format = { 0 };
+ static struct { uint pos, nor, uv; } attr_id;
+
+ if (shaded_triangles_format.attr_len == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GPU_vertformat_attr_add(&shaded_triangles_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.nor = GPU_vertformat_attr_add(&shaded_triangles_format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.uv = GPU_vertformat_attr_add(&shaded_triangles_format, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUBatch **shaded_triangles = MEM_mallocN(sizeof(*shaded_triangles) * gpumat_array_len, __func__);
+
+ GPUVertBuf **vbo = BLI_array_alloca(vbo, gpumat_array_len);
+ uint *vbo_len_capacity = BLI_array_alloca(vbo_len_capacity, gpumat_array_len);
+
+ GPUVertBufRaw *pos_step, *nor_step, *uv_step;
+ pos_step = BLI_array_alloca(pos_step, gpumat_array_len);
+ nor_step = BLI_array_alloca(nor_step, gpumat_array_len);
+ uv_step = BLI_array_alloca(uv_step, gpumat_array_len);
+
+ /* Create each vertex buffer */
+ for (int i = 0; i < gpumat_array_len; i++) {
+ vbo[i] = GPU_vertbuf_create_with_format(&shaded_triangles_format);
+ vbo_len_capacity[i] = 0;
+ }
+
+ /* Calc `vbo_len_capacity` */
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ vbo_len_capacity[dl->col] += dl_tri_len(dl) * 3;
+ }
+
+ /* Alloc each vertex buffer and get each raw data */
+ for (int i = 0; i < gpumat_array_len; i++) {
+ GPU_vertbuf_data_alloc(vbo[i], vbo_len_capacity[i]);
+ GPU_vertbuf_attr_get_raw_data(vbo[i], attr_id.pos, &pos_step[i]);
+ GPU_vertbuf_attr_get_raw_data(vbo[i], attr_id.nor, &nor_step[i]);
+ GPU_vertbuf_attr_get_raw_data(vbo[i], attr_id.uv, &uv_step[i]);
+ }
+
+ BKE_displist_normals_add(lb);
+
+ for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ const int col = dl->col;
+ const float(*verts)[3] = (float(*)[3])dl->verts;
+ const float(*nors)[3] = (float(*)[3])dl->nors;
+ const int *idx = dl->index;
+ float uv[4][2];
+
+ if (dl->type == DL_INDEX3) {
+ const float x_max = (float)(dl->nr - 1);
+ uv[0][1] = uv[1][1] = uv[2][1] = 0.0f;
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++, idx += 3) {
+ uv[0][0] = idx[0] / x_max;
+ uv[1][0] = idx[2] / x_max;
+ uv[2][0] = idx[1] / x_max;
+
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[idx[0]], verts[idx[2]], verts[idx[1]],
+ dl->nors, dl->nors, dl->nors,
+ uv[0], uv[1], uv[2]);
+ }
+ }
+ else if (dl->type == DL_SURF) {
+ uint quad[4];
+ for (int a = 0; a < dl->parts; a++) {
+ if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
+ break;
+ }
+
+ int b;
+ if (dl->flag & DL_CYCL_U) {
+ quad[0] = dl->nr * a;
+ quad[3] = quad[0] + dl->nr - 1;
+ quad[1] = quad[0] + dl->nr;
+ quad[2] = quad[3] + dl->nr;
+ b = 0;
+ }
+ else {
+ quad[3] = dl->nr * a;
+ quad[0] = quad[3] + 1;
+ quad[2] = quad[3] + dl->nr;
+ quad[1] = quad[0] + dl->nr;
+ b = 1;
+ }
+ if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
+ quad[1] -= dl->parts * dl->nr;
+ quad[2] -= dl->parts * dl->nr;
+ }
+
+ for (; b < dl->nr; b++) {
+ int orco_sizeu = dl->nr - 1;
+ int orco_sizev = dl->parts - 1;
+
+ /* exception as handled in convertblender.c too */
+ if (dl->flag & DL_CYCL_U) {
+ orco_sizeu++;
+ }
+ if (dl->flag & DL_CYCL_V) {
+ orco_sizev++;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ /* find uv based on vertex index into grid array */
+ uv[i][0] = (quad[i] / dl->nr) / (float)orco_sizev;
+ uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu;
+
+ /* cyclic correction */
+ if ((i == 1 || i == 2) && uv[i][0] == 0.0f) {
+ uv[i][0] = 1.0f;
+ }
+ if ((i == 0 || i == 1) && uv[i][1] == 0.0f) {
+ uv[i][1] = 1.0f;
+ }
+ }
+
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[quad[0]], verts[quad[1]], verts[quad[2]],
+ nors[quad[0]], nors[quad[1]], nors[quad[2]],
+ uv[0], uv[1], uv[2]);
+
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[quad[0]], verts[quad[2]], verts[quad[3]],
+ nors[quad[0]], nors[quad[2]], nors[quad[3]],
+ uv[0], uv[2], uv[3]);
+
+ quad[2] = quad[1];
+ quad[1]++;
+ quad[3] = quad[0];
+ quad[0]++;
+ }
+ }
+ }
+ else {
+ BLI_assert(dl->type == DL_INDEX4);
+ uv[0][0] = uv[0][1] = uv[1][0] = uv[3][1] = 0.0f;
+ uv[1][1] = uv[2][0] = uv[2][1] = uv[3][0] = 1.0f;
+
+ const int i_end = dl->parts;
+ for (int i = 0; i < i_end; i++, idx += 4) {
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[idx[0]], verts[idx[1]], verts[idx[2]],
+ nors[idx[0]], nors[idx[1]], nors[idx[2]],
+ uv[0], uv[1], uv[2]);
+
+ if (idx[2] != idx[3]) {
+ displist_vertbuf_attr_set_tri_pos_normals_and_uv(
+ &pos_step[col], &nor_step[col], &uv_step[col],
+ verts[idx[0]], verts[idx[2]], verts[idx[3]],
+ nors[idx[0]], nors[idx[2]], nors[idx[3]],
+ uv[0], uv[2], uv[3]);
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < gpumat_array_len; i++) {
+ uint vbo_len_used = GPU_vertbuf_raw_used(&pos_step[i]);
+ if (vbo_len_capacity[i] != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo[i], vbo_len_used);
+ }
+ shaded_triangles[i] = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo[i], NULL, GPU_BATCH_OWNS_VBO);
+ }
+
+ return shaded_triangles;
+}
diff --git a/source/blender/draw/intern/draw_cache_impl_lattice.c b/source/blender/draw/intern/draw_cache_impl_lattice.c
new file mode 100644
index 00000000000..b077162b41d
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_lattice.c
@@ -0,0 +1,579 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_cache_impl_lattice.c
+ * \ingroup draw
+ *
+ * \brief Lattice API for render engines
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_lattice.h"
+#include "BKE_deform.h"
+#include "BKE_colorband.h"
+
+#include "GPU_batch.h"
+
+#include "draw_cache_impl.h" /* own include */
+
+#define SELECT 1
+
+/**
+ * TODO
+ * - 'DispList' is currently not used
+ * (we could avoid using since it will be removed)
+ */
+
+static void lattice_batch_cache_clear(Lattice *lt);
+
+/* ---------------------------------------------------------------------- */
+/* Lattice Interface, direct access to basic data. */
+
+static int vert_len_calc(int u, int v, int w)
+{
+ if (u <= 0 || v <= 0 || w <= 0) {
+ return 0;
+ }
+ return u * v * w;
+}
+
+static int edge_len_calc(int u, int v, int w)
+{
+ if (u <= 0 || v <= 0 || w <= 0) {
+ return 0;
+ }
+ return (((((u - 1) * v) +
+ ((v - 1) * u)) * w) +
+ ((w - 1) * (u * v)));
+}
+
+static int lattice_render_verts_len_get(Lattice *lt)
+{
+ if (lt->editlatt) {
+ lt = lt->editlatt->latt;
+ }
+
+ const int u = lt->pntsu;
+ const int v = lt->pntsv;
+ const int w = lt->pntsw;
+
+ if ((lt->flag & LT_OUTSIDE) == 0) {
+ return vert_len_calc(u, v, w);
+ }
+ else {
+ /* TODO remove internal coords */
+ return vert_len_calc(u, v, w);
+ }
+}
+
+static int lattice_render_edges_len_get(Lattice *lt)
+{
+ if (lt->editlatt) {
+ lt = lt->editlatt->latt;
+ }
+
+ const int u = lt->pntsu;
+ const int v = lt->pntsv;
+ const int w = lt->pntsw;
+
+ if ((lt->flag & LT_OUTSIDE) == 0) {
+ return edge_len_calc(u, v, w);
+ }
+ else {
+ /* TODO remove internal coords */
+ return edge_len_calc(u, v, w);
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* Lattice Interface, indirect, partially cached access to complex data. */
+
+typedef struct LatticeRenderData {
+ int types;
+
+ int vert_len;
+ int edge_len;
+
+ struct {
+ int u_len, v_len, w_len;
+ } dims;
+ bool show_only_outside;
+
+ struct EditLatt *edit_latt;
+ BPoint *bp;
+
+ int actbp;
+
+ struct MDeformVert *dvert;
+} LatticeRenderData;
+
+enum {
+ LR_DATATYPE_VERT = 1 << 0,
+ LR_DATATYPE_EDGE = 1 << 1,
+ LR_DATATYPE_OVERLAY = 1 << 2,
+};
+
+static LatticeRenderData *lattice_render_data_create(Lattice *lt, const int types)
+{
+ LatticeRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
+ rdata->types = types;
+
+ if (lt->editlatt) {
+ EditLatt *editlatt = lt->editlatt;
+ lt = editlatt->latt;
+
+ rdata->edit_latt = editlatt;
+
+ rdata->dvert = lt->dvert;
+
+ if (types & (LR_DATATYPE_VERT)) {
+ rdata->vert_len = lattice_render_verts_len_get(lt);
+ }
+ if (types & (LR_DATATYPE_EDGE)) {
+ rdata->edge_len = lattice_render_edges_len_get(lt);
+ }
+ if (types & LR_DATATYPE_OVERLAY) {
+ rdata->actbp = lt->actbp;
+ }
+ }
+ else {
+ rdata->dvert = NULL;
+
+ if (types & (LR_DATATYPE_VERT)) {
+ rdata->vert_len = lattice_render_verts_len_get(lt);
+ }
+ if (types & (LR_DATATYPE_EDGE)) {
+ rdata->edge_len = lattice_render_edges_len_get(lt);
+ /*no edge data */
+ }
+ }
+
+ rdata->bp = lt->def;
+
+ rdata->dims.u_len = lt->pntsu;
+ rdata->dims.v_len = lt->pntsv;
+ rdata->dims.w_len = lt->pntsw;
+
+ rdata->show_only_outside = (lt->flag & LT_OUTSIDE) != 0;
+ rdata->actbp = lt->actbp;
+
+ return rdata;
+}
+
+static void lattice_render_data_free(LatticeRenderData *rdata)
+{
+#if 0
+ if (rdata->loose_verts) {
+ MEM_freeN(rdata->loose_verts);
+ }
+#endif
+ MEM_freeN(rdata);
+}
+
+static int lattice_render_data_verts_len_get(const LatticeRenderData *rdata)
+{
+ BLI_assert(rdata->types & LR_DATATYPE_VERT);
+ return rdata->vert_len;
+}
+
+static int lattice_render_data_edges_len_get(const LatticeRenderData *rdata)
+{
+ BLI_assert(rdata->types & LR_DATATYPE_EDGE);
+ return rdata->edge_len;
+}
+
+static const BPoint *lattice_render_data_vert_bpoint(const LatticeRenderData *rdata, const int vert_idx)
+{
+ BLI_assert(rdata->types & LR_DATATYPE_VERT);
+ return &rdata->bp[vert_idx];
+}
+
+/* TODO, move into shader? */
+static void rgb_from_weight(float r_rgb[3], const float weight)
+{
+ const float blend = ((weight / 2.0f) + 0.5f);
+
+ if (weight <= 0.25f) { /* blue->cyan */
+ r_rgb[0] = 0.0f;
+ r_rgb[1] = blend * weight * 4.0f;
+ r_rgb[2] = blend;
+ }
+ else if (weight <= 0.50f) { /* cyan->green */
+ r_rgb[0] = 0.0f;
+ r_rgb[1] = blend;
+ r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
+ }
+ else if (weight <= 0.75f) { /* green->yellow */
+ r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
+ r_rgb[1] = blend;
+ r_rgb[2] = 0.0f;
+ }
+ else if (weight <= 1.0f) { /* yellow->red */
+ r_rgb[0] = blend;
+ r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
+ r_rgb[2] = 0.0f;
+ }
+ else {
+ /* exceptional value, unclamped or nan,
+ * avoid uninitialized memory use */
+ r_rgb[0] = 1.0f;
+ r_rgb[1] = 0.0f;
+ r_rgb[2] = 1.0f;
+ }
+}
+
+static void lattice_render_data_weight_col_get(const LatticeRenderData *rdata, const int vert_idx,
+ const int actdef, float r_col[4])
+{
+ if (actdef > -1) {
+ float weight = defvert_find_weight(rdata->dvert + vert_idx, actdef);
+
+ if (U.flag & USER_CUSTOM_RANGE) {
+ BKE_colorband_evaluate(&U.coba_weight, weight, r_col);
+ }
+ else {
+ rgb_from_weight(r_col, weight);
+ }
+
+ r_col[3] = 1.0f;
+ }
+ else {
+ zero_v4(r_col);
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+/* Lattice GPUBatch Cache */
+
+typedef struct LatticeBatchCache {
+ GPUVertBuf *pos;
+ GPUIndexBuf *edges;
+
+ GPUBatch *all_verts;
+ GPUBatch *all_edges;
+
+ GPUBatch *overlay_verts;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+
+ struct {
+ int u_len, v_len, w_len;
+ } dims;
+ bool show_only_outside;
+
+ bool is_editmode;
+} LatticeBatchCache;
+
+/* GPUBatch cache management. */
+
+static bool lattice_batch_cache_valid(Lattice *lt)
+{
+ LatticeBatchCache *cache = lt->batch_cache;
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ if (cache->is_editmode != (lt->editlatt != NULL)) {
+ return false;
+ }
+
+ if (cache->is_dirty) {
+ return false;
+ }
+ else {
+ if ((cache->dims.u_len != lt->pntsu) ||
+ (cache->dims.v_len != lt->pntsv) ||
+ (cache->dims.w_len != lt->pntsw) ||
+ ((cache->show_only_outside != ((lt->flag & LT_OUTSIDE) != 0))))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void lattice_batch_cache_init(Lattice *lt)
+{
+ LatticeBatchCache *cache = lt->batch_cache;
+
+ if (!cache) {
+ cache = lt->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+ cache->dims.u_len = lt->pntsu;
+ cache->dims.v_len = lt->pntsv;
+ cache->dims.w_len = lt->pntsw;
+ cache->show_only_outside = (lt->flag & LT_OUTSIDE) != 0;
+
+ cache->is_editmode = lt->editlatt != NULL;
+
+ cache->is_dirty = false;
+}
+
+static LatticeBatchCache *lattice_batch_cache_get(Lattice *lt)
+{
+ if (!lattice_batch_cache_valid(lt)) {
+ lattice_batch_cache_clear(lt);
+ lattice_batch_cache_init(lt);
+ }
+ return lt->batch_cache;
+}
+
+void DRW_lattice_batch_cache_dirty_tag(Lattice *lt, int mode)
+{
+ LatticeBatchCache *cache = lt->batch_cache;
+ if (cache == NULL) {
+ return;
+ }
+ switch (mode) {
+ case BKE_LATTICE_BATCH_DIRTY_ALL:
+ cache->is_dirty = true;
+ break;
+ case BKE_LATTICE_BATCH_DIRTY_SELECT:
+ /* TODO Separate Flag vbo */
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_verts);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void lattice_batch_cache_clear(Lattice *lt)
+{
+ LatticeBatchCache *cache = lt->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ GPU_BATCH_DISCARD_SAFE(cache->all_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->all_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_verts);
+
+ GPU_VERTBUF_DISCARD_SAFE(cache->pos);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->edges);
+}
+
+void DRW_lattice_batch_cache_free(Lattice *lt)
+{
+ lattice_batch_cache_clear(lt);
+ MEM_SAFE_FREE(lt->batch_cache);
+}
+
+/* GPUBatch cache usage. */
+static GPUVertBuf *lattice_batch_cache_get_pos(LatticeRenderData *rdata, LatticeBatchCache *cache,
+ bool use_weight, const int actdef)
+{
+ BLI_assert(rdata->types & LR_DATATYPE_VERT);
+
+ if (cache->pos == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, col; } attr_id;
+
+ GPU_vertformat_clear(&format);
+
+ /* initialize vertex format */
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ if (use_weight) {
+ attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+
+ const int vert_len = lattice_render_data_verts_len_get(rdata);
+
+ cache->pos = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(cache->pos, vert_len);
+ for (int i = 0; i < vert_len; ++i) {
+ const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i);
+ GPU_vertbuf_attr_set(cache->pos, attr_id.pos, i, bp->vec);
+
+ if (use_weight) {
+ float w_col[4];
+ lattice_render_data_weight_col_get(rdata, i, actdef, w_col);
+
+ GPU_vertbuf_attr_set(cache->pos, attr_id.col, i, w_col);
+ }
+ }
+ }
+
+ return cache->pos;
+}
+
+static GPUIndexBuf *lattice_batch_cache_get_edges(LatticeRenderData *rdata, LatticeBatchCache *cache)
+{
+ BLI_assert(rdata->types & (LR_DATATYPE_VERT | LR_DATATYPE_EDGE));
+
+ if (cache->edges == NULL) {
+ const int vert_len = lattice_render_data_verts_len_get(rdata);
+ const int edge_len = lattice_render_data_edges_len_get(rdata);
+ int edge_len_real = 0;
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
+
+#define LATT_INDEX(u, v, w) \
+ ((((w) * rdata->dims.v_len + (v)) * rdata->dims.u_len) + (u))
+
+ for (int w = 0; w < rdata->dims.w_len; w++) {
+ int wxt = (w == 0 || w == rdata->dims.w_len - 1);
+ for (int v = 0; v < rdata->dims.v_len; v++) {
+ int vxt = (v == 0 || v == rdata->dims.v_len - 1);
+ for (int u = 0; u < rdata->dims.u_len; u++) {
+ int uxt = (u == 0 || u == rdata->dims.u_len - 1);
+
+ if (w && ((uxt || vxt) || !rdata->show_only_outside)) {
+ GPU_indexbuf_add_line_verts(&elb, LATT_INDEX(u, v, w - 1), LATT_INDEX(u, v, w));
+ BLI_assert(edge_len_real <= edge_len);
+ edge_len_real++;
+ }
+ if (v && ((uxt || wxt) || !rdata->show_only_outside)) {
+ GPU_indexbuf_add_line_verts(&elb, LATT_INDEX(u, v - 1, w), LATT_INDEX(u, v, w));
+ BLI_assert(edge_len_real <= edge_len);
+ edge_len_real++;
+ }
+ if (u && ((vxt || wxt) || !rdata->show_only_outside)) {
+ GPU_indexbuf_add_line_verts(&elb, LATT_INDEX(u - 1, v, w), LATT_INDEX(u, v, w));
+ BLI_assert(edge_len_real <= edge_len);
+ edge_len_real++;
+ }
+ }
+ }
+ }
+
+#undef LATT_INDEX
+
+ if (rdata->show_only_outside) {
+ BLI_assert(edge_len_real <= edge_len);
+ }
+ else {
+ BLI_assert(edge_len_real == edge_len);
+ }
+
+ cache->edges = GPU_indexbuf_build(&elb);
+ }
+
+ return cache->edges;
+}
+
+static void lattice_batch_cache_create_overlay_batches(Lattice *lt)
+{
+ /* Since LR_DATATYPE_OVERLAY is slow to generate, generate them all at once */
+ int options = LR_DATATYPE_VERT | LR_DATATYPE_OVERLAY;
+
+ LatticeBatchCache *cache = lattice_batch_cache_get(lt);
+ LatticeRenderData *rdata = lattice_render_data_create(lt, options);
+
+ if (cache->overlay_verts == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attr_len == 0) {
+ /* initialize vertex format */
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
+ }
+
+ const int vert_len = lattice_render_data_verts_len_get(rdata);
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vert_len);
+ for (int i = 0; i < vert_len; ++i) {
+ const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i);
+
+ char vflag = 0;
+ if (bp->f1 & SELECT) {
+ if (i == rdata->actbp) {
+ vflag |= VFLAG_VERTEX_ACTIVE;
+ }
+ else {
+ vflag |= VFLAG_VERTEX_SELECTED;
+ }
+ }
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, bp->vec);
+ GPU_vertbuf_attr_set(vbo, attr_id.data, i, &vflag);
+ }
+
+ cache->overlay_verts = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+
+ lattice_render_data_free(rdata);
+}
+
+GPUBatch *DRW_lattice_batch_cache_get_all_edges(Lattice *lt, bool use_weight, const int actdef)
+{
+ LatticeBatchCache *cache = lattice_batch_cache_get(lt);
+
+ if (cache->all_edges == NULL) {
+ /* create batch from Lattice */
+ LatticeRenderData *rdata = lattice_render_data_create(lt, LR_DATATYPE_VERT | LR_DATATYPE_EDGE);
+
+ cache->all_edges = GPU_batch_create(GPU_PRIM_LINES, lattice_batch_cache_get_pos(rdata, cache, use_weight, actdef),
+ lattice_batch_cache_get_edges(rdata, cache));
+
+ lattice_render_data_free(rdata);
+ }
+
+ return cache->all_edges;
+}
+
+GPUBatch *DRW_lattice_batch_cache_get_all_verts(Lattice *lt)
+{
+ LatticeBatchCache *cache = lattice_batch_cache_get(lt);
+
+ if (cache->all_verts == NULL) {
+ LatticeRenderData *rdata = lattice_render_data_create(lt, LR_DATATYPE_VERT);
+
+ cache->all_verts = GPU_batch_create(GPU_PRIM_POINTS, lattice_batch_cache_get_pos(rdata, cache, false, -1), NULL);
+
+ lattice_render_data_free(rdata);
+ }
+
+ return cache->all_verts;
+}
+
+GPUBatch *DRW_lattice_batch_cache_get_overlay_verts(Lattice *lt)
+{
+ LatticeBatchCache *cache = lattice_batch_cache_get(lt);
+
+ if (cache->overlay_verts == NULL) {
+ lattice_batch_cache_create_overlay_batches(lt);
+ }
+
+ return cache->overlay_verts;
+}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
new file mode 100644
index 00000000000..fbd2420b7a4
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -0,0 +1,5912 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_cache_impl_mesh.c
+ * \ingroup draw
+ *
+ * \brief Mesh API for render engines
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_buffer.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_math_bits.h"
+#include "BLI_math_color.h"
+#include "BLI_string.h"
+#include "BLI_alloca.h"
+#include "BLI_edgehash.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_editmesh_tangent.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_colorband.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "bmesh.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_draw.h"
+#include "GPU_material.h"
+#include "GPU_texture.h"
+
+#include "DRW_render.h"
+
+#include "ED_image.h"
+#include "ED_mesh.h"
+#include "ED_uvedit.h"
+
+#include "draw_cache_impl.h" /* own include */
+
+static void mesh_batch_cache_clear(Mesh *me);
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Mesh/BMesh Interface (direct access to basic data).
+ * \{ */
+
+static int mesh_render_verts_len_get(Mesh *me)
+{
+ return me->edit_btmesh ? me->edit_btmesh->bm->totvert : me->totvert;
+}
+
+static int mesh_render_edges_len_get(Mesh *me)
+{
+ return me->edit_btmesh ? me->edit_btmesh->bm->totedge : me->totedge;
+}
+
+static int mesh_render_looptri_len_get(Mesh *me)
+{
+ return me->edit_btmesh ? me->edit_btmesh->tottri : poly_to_tri_count(me->totpoly, me->totloop);
+}
+
+static int mesh_render_polys_len_get(Mesh *me)
+{
+ return me->edit_btmesh ? me->edit_btmesh->bm->totface : me->totpoly;
+}
+
+static int mesh_render_mat_len_get(Mesh *me)
+{
+ return MAX2(1, me->totcol);
+}
+
+static int UNUSED_FUNCTION(mesh_render_loops_len_get)(Mesh *me)
+{
+ return me->edit_btmesh ? me->edit_btmesh->bm->totloop : me->totloop;
+}
+
+/** \} */
+
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
+ * \{ */
+
+typedef struct EdgeAdjacentPolys {
+ int count;
+ int face_index[2];
+} EdgeAdjacentPolys;
+
+typedef struct EdgeAdjacentVerts {
+ int vert_index[2]; /* -1 if none */
+} EdgeAdjacentVerts;
+
+typedef struct EdgeDrawAttr {
+ uchar v_flag;
+ uchar e_flag;
+ uchar crease;
+ uchar bweight;
+} EdgeDrawAttr;
+
+typedef struct MeshRenderData {
+ int types;
+
+ int vert_len;
+ int edge_len;
+ int tri_len;
+ int loop_len;
+ int poly_len;
+ int mat_len;
+ int loose_vert_len;
+ int loose_edge_len;
+
+ /* Support for mapped mesh data. */
+ struct {
+ /* Must be set if we want to get mapped data. */
+ bool use;
+ bool supported;
+
+ Mesh *me_cage;
+
+ int vert_len;
+ int edge_len;
+ int tri_len;
+ int loop_len;
+ int poly_len;
+
+ int *loose_verts;
+ int loose_vert_len;
+
+ int *loose_edges;
+ int loose_edge_len;
+
+ /* origindex layers */
+ int *v_origindex;
+ int *e_origindex;
+ int *l_origindex;
+ int *p_origindex;
+ } mapped;
+
+ BMEditMesh *edit_bmesh;
+ struct EditMeshData *edit_data;
+
+ MVert *mvert;
+ const MEdge *medge;
+ const MLoop *mloop;
+ const MPoly *mpoly;
+ float (*orco)[3]; /* vertex coordinates normalized to bounding box */
+ bool is_orco_allocated;
+ MDeformVert *dvert;
+ MLoopUV *mloopuv;
+ MLoopCol *mloopcol;
+ float (*loop_normals)[3];
+
+ /* CustomData 'cd' cache for efficient access. */
+ struct {
+ struct {
+ MLoopUV **uv;
+ int uv_len;
+ int uv_active;
+
+ MLoopCol **vcol;
+ int vcol_len;
+ int vcol_active;
+
+ float (**tangent)[4];
+ int tangent_len;
+ int tangent_active;
+
+ bool *auto_vcol;
+ } layers;
+
+ /* Custom-data offsets (only needed for BMesh access) */
+ struct {
+ int crease;
+ int bweight;
+ int *uv;
+ int *vcol;
+#ifdef WITH_FREESTYLE
+ int freestyle_edge;
+ int freestyle_face;
+#endif
+ } offset;
+
+ struct {
+ char (*auto_mix)[32];
+ char (*uv)[32];
+ char (*vcol)[32];
+ char (*tangent)[32];
+ } uuid;
+
+ /* for certain cases we need an output loop-data storage (bmesh tangents) */
+ struct {
+ CustomData ldata;
+ /* grr, special case variable (use in place of 'dm->tangent_mask') */
+ short tangent_mask;
+ } output;
+ } cd;
+
+ BMVert *eve_act;
+ BMEdge *eed_act;
+ BMFace *efa_act;
+
+ /* Data created on-demand (usually not for bmesh-based data). */
+ EdgeAdjacentPolys *edges_adjacent_polys;
+ MLoopTri *mlooptri;
+ int *loose_edges;
+ int *loose_verts;
+
+ float (*poly_normals)[3];
+ float (*vert_weight);
+ char (*vert_color)[3];
+ GPUPackedNormal *poly_normals_pack;
+ GPUPackedNormal *vert_normals_pack;
+ bool *edge_select_bool;
+ bool *edge_visible_bool;
+} MeshRenderData;
+
+enum {
+ MR_DATATYPE_VERT = 1 << 0,
+ MR_DATATYPE_EDGE = 1 << 1,
+ MR_DATATYPE_LOOPTRI = 1 << 2,
+ MR_DATATYPE_LOOP = 1 << 3,
+ MR_DATATYPE_POLY = 1 << 4,
+ MR_DATATYPE_OVERLAY = 1 << 5,
+ MR_DATATYPE_SHADING = 1 << 6,
+ MR_DATATYPE_DVERT = 1 << 7,
+ MR_DATATYPE_LOOPCOL = 1 << 8,
+ MR_DATATYPE_LOOPUV = 1 << 9,
+};
+
+/**
+ * These functions look like they would be slow but they will typically return true on the first iteration.
+ * Only false when all attached elements are hidden.
+ */
+static bool bm_vert_has_visible_edge(const BMVert *v)
+{
+ const BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v->e;
+ do {
+ if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
+ return true;
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first);
+ return false;
+}
+
+static bool bm_edge_has_visible_face(const BMEdge *e)
+{
+ const BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ return false;
+}
+
+
+static void mesh_cd_calc_used_gpu_layers(
+ CustomData *UNUSED(cd_vdata), uchar cd_vused[CD_NUMTYPES],
+ CustomData *cd_ldata, ushort cd_lused[CD_NUMTYPES],
+ struct GPUMaterial **gpumat_array, int gpumat_array_len)
+{
+ /* See: DM_vertex_attributes_from_gpu for similar logic */
+ GPUVertexAttribs gattribs = {{{0}}};
+
+ for (int i = 0; i < gpumat_array_len; i++) {
+ GPUMaterial *gpumat = gpumat_array[i];
+ if (gpumat) {
+ GPU_material_vertex_attributes(gpumat, &gattribs);
+ for (int j = 0; j < gattribs.totlayer; j++) {
+ const char *name = gattribs.layer[j].name;
+ int type = gattribs.layer[j].type;
+ int layer = -1;
+
+ if (type == CD_AUTO_FROM_NAME) {
+ /* We need to deduct what exact layer is used.
+ *
+ * We do it based on the specified name.
+ */
+ if (name[0] != '\0') {
+ layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name);
+ type = CD_MTFACE;
+
+ if (layer == -1) {
+ layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name);
+ type = CD_MCOL;
+ }
+#if 0 /* Tangents are always from UV's - this will never happen. */
+ if (layer == -1) {
+ layer = CustomData_get_named_layer(cd_ldata, CD_TANGENT, name);
+ type = CD_TANGENT;
+ }
+#endif
+ if (layer == -1) {
+ continue;
+ }
+ }
+ else {
+ /* Fall back to the UV layer, which matches old behavior. */
+ type = CD_MTFACE;
+ }
+ }
+
+ switch (type) {
+ case CD_MTFACE:
+ {
+ if (layer == -1) {
+ layer = (name[0] != '\0') ?
+ CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) :
+ CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
+ }
+ if (layer != -1) {
+ cd_lused[CD_MLOOPUV] |= (1 << layer);
+ }
+ break;
+ }
+ case CD_TANGENT:
+ {
+ if (layer == -1) {
+ layer = (name[0] != '\0') ?
+ CustomData_get_named_layer(cd_ldata, CD_MLOOPUV, name) :
+ CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
+ }
+ if (layer != -1) {
+ cd_lused[CD_TANGENT] |= (1 << layer);
+ }
+ else {
+ /* no UV layers at all => requesting orco */
+ cd_lused[CD_TANGENT] |= DM_TANGENT_MASK_ORCO;
+ cd_vused[CD_ORCO] |= 1;
+ }
+ break;
+ }
+ case CD_MCOL:
+ {
+ if (layer == -1) {
+ layer = (name[0] != '\0') ?
+ CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name) :
+ CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
+ }
+ if (layer != -1) {
+ cd_lused[CD_MLOOPCOL] |= (1 << layer);
+ }
+ break;
+ }
+ case CD_ORCO:
+ {
+ cd_vused[CD_ORCO] |= 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static void mesh_render_calc_normals_loop_and_poly(const Mesh *me, const float split_angle, MeshRenderData *rdata)
+{
+ BLI_assert((me->flag & ME_AUTOSMOOTH) != 0);
+
+ int totloop = me->totloop;
+ int totpoly = me->totpoly;
+ float (*loop_normals)[3] = MEM_mallocN(sizeof(*loop_normals) * totloop, __func__);
+ float (*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
+ short (*clnors)[2] = CustomData_get_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BKE_mesh_calc_normals_poly(
+ me->mvert, NULL, me->totvert,
+ me->mloop, me->mpoly, totloop, totpoly, poly_normals, false);
+
+ BKE_mesh_normals_loop_split(
+ me->mvert, me->totvert, me->medge, me->totedge,
+ me->mloop, loop_normals, totloop, me->mpoly, poly_normals, totpoly,
+ true, split_angle, NULL, clnors, NULL);
+
+ rdata->loop_len = totloop;
+ rdata->poly_len = totpoly;
+ rdata->loop_normals = loop_normals;
+ rdata->poly_normals = poly_normals;
+}
+
+
+/**
+ * TODO(campbell): 'gpumat_array' may include materials linked to the object.
+ * While not default, object materials should be supported.
+ * Although this only impacts the data that's generated, not the materials that display.
+ */
+static MeshRenderData *mesh_render_data_create_ex(
+ Mesh *me, const int types,
+ struct GPUMaterial **gpumat_array, uint gpumat_array_len)
+{
+ MeshRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
+ rdata->types = types;
+ rdata->mat_len = mesh_render_mat_len_get(me);
+
+ CustomData_reset(&rdata->cd.output.ldata);
+
+ const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
+ const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
+
+ if (me->edit_btmesh) {
+ BMEditMesh *embm = me->edit_btmesh;
+ BMesh *bm = embm->bm;
+
+ rdata->edit_bmesh = embm;
+ rdata->edit_data = me->runtime.edit_data;
+
+ if (embm->mesh_eval_cage && (embm->mesh_eval_cage->runtime.is_original == false)) {
+ Mesh *me_cage = embm->mesh_eval_cage;
+
+ rdata->mapped.me_cage = me_cage;
+ if (types & MR_DATATYPE_VERT) {
+ rdata->mapped.vert_len = me_cage->totvert;
+ }
+ if (types & MR_DATATYPE_EDGE) {
+ rdata->mapped.edge_len = me_cage->totedge;
+ }
+ if (types & MR_DATATYPE_LOOP) {
+ rdata->mapped.loop_len = me_cage->totloop;
+ }
+ if (types & MR_DATATYPE_POLY) {
+ rdata->mapped.poly_len = me_cage->totpoly;
+ }
+ if (types & MR_DATATYPE_LOOPTRI) {
+ rdata->mapped.tri_len = poly_to_tri_count(me_cage->totpoly, me_cage->totloop);
+ }
+
+ rdata->mapped.v_origindex = CustomData_get_layer(&me_cage->vdata, CD_ORIGINDEX);
+ rdata->mapped.e_origindex = CustomData_get_layer(&me_cage->edata, CD_ORIGINDEX);
+ rdata->mapped.l_origindex = CustomData_get_layer(&me_cage->ldata, CD_ORIGINDEX);
+ rdata->mapped.p_origindex = CustomData_get_layer(&me_cage->pdata, CD_ORIGINDEX);
+ rdata->mapped.supported = (
+ rdata->mapped.v_origindex &&
+ rdata->mapped.e_origindex &&
+ rdata->mapped.p_origindex);
+ }
+
+ int bm_ensure_types = 0;
+ if (types & MR_DATATYPE_VERT) {
+ rdata->vert_len = bm->totvert;
+ bm_ensure_types |= BM_VERT;
+ }
+ if (types & MR_DATATYPE_EDGE) {
+ rdata->edge_len = bm->totedge;
+ bm_ensure_types |= BM_EDGE;
+ }
+ if (types & MR_DATATYPE_LOOPTRI) {
+ bm_ensure_types |= BM_LOOP;
+ }
+ if (types & MR_DATATYPE_LOOP) {
+ int totloop = bm->totloop;
+ if (is_auto_smooth) {
+ rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * totloop, __func__);
+ int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ BM_loops_calc_normal_vcos(
+ bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL,
+ cd_loop_clnors_offset, false);
+ }
+ rdata->loop_len = totloop;
+ bm_ensure_types |= BM_LOOP;
+ }
+ if (types & MR_DATATYPE_POLY) {
+ rdata->poly_len = bm->totface;
+ bm_ensure_types |= BM_FACE;
+ }
+ if (types & MR_DATATYPE_OVERLAY) {
+ rdata->efa_act = BM_mesh_active_face_get(bm, false, true);
+ rdata->eed_act = BM_mesh_active_edge_get(bm);
+ rdata->eve_act = BM_mesh_active_vert_get(bm);
+ rdata->cd.offset.crease = CustomData_get_offset(&bm->edata, CD_CREASE);
+ rdata->cd.offset.bweight = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+
+#ifdef WITH_FREESTYLE
+ rdata->cd.offset.freestyle_edge = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE);
+ rdata->cd.offset.freestyle_face = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE);
+#endif
+ }
+ if (types & (MR_DATATYPE_DVERT)) {
+ bm_ensure_types |= BM_VERT;
+ }
+ if (rdata->edit_data != NULL) {
+ bm_ensure_types |= BM_VERT;
+ }
+
+ BM_mesh_elem_index_ensure(bm, bm_ensure_types);
+ BM_mesh_elem_table_ensure(bm, bm_ensure_types & ~BM_LOOP);
+
+ if (types & MR_DATATYPE_LOOPTRI) {
+ /* Edit mode ensures this is valid, no need to calculate. */
+ BLI_assert((bm->totloop == 0) || (embm->looptris != NULL));
+ int tottri = embm->tottri;
+ MLoopTri *mlooptri = MEM_mallocN(sizeof(*rdata->mlooptri) * embm->tottri, __func__);
+ for (int index = 0; index < tottri ; index ++ ) {
+ BMLoop **bmtri = embm->looptris[index];
+ MLoopTri *mtri = &mlooptri[index];
+ mtri->tri[0] = BM_elem_index_get(bmtri[0]);
+ mtri->tri[1] = BM_elem_index_get(bmtri[1]);
+ mtri->tri[2] = BM_elem_index_get(bmtri[2]);
+ }
+ rdata->mlooptri = mlooptri;
+ rdata->tri_len = tottri;
+ }
+
+ if (types & MR_DATATYPE_OVERLAY) {
+ rdata->loose_vert_len = rdata->loose_edge_len = 0;
+
+ {
+ int *lverts = MEM_mallocN(rdata->vert_len * sizeof(int), __func__);
+ BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
+ for (int i = 0; i < bm->totvert; i++) {
+ const BMVert *eve = BM_vert_at_index(bm, i);
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ /* Loose vert */
+ if (eve->e == NULL || !bm_vert_has_visible_edge(eve)) {
+ lverts[rdata->loose_vert_len++] = i;
+ }
+ }
+ }
+ rdata->loose_verts = MEM_reallocN(lverts, rdata->loose_vert_len * sizeof(int));
+ }
+
+ {
+ int *ledges = MEM_mallocN(rdata->edge_len * sizeof(int), __func__);
+ BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0);
+ for (int i = 0; i < bm->totedge; i++) {
+ const BMEdge *eed = BM_edge_at_index(bm, i);
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ /* Loose edge */
+ if (eed->l == NULL || !bm_edge_has_visible_face(eed)) {
+ ledges[rdata->loose_edge_len++] = i;
+ }
+ }
+ }
+ rdata->loose_edges = MEM_reallocN(ledges, rdata->loose_edge_len * sizeof(int));
+ }
+
+ if (rdata->mapped.supported) {
+ Mesh *me_cage = embm->mesh_eval_cage;
+ rdata->mapped.loose_vert_len = rdata->mapped.loose_edge_len = 0;
+
+ if (rdata->loose_vert_len) {
+ int *lverts = MEM_mallocN(me_cage->totvert * sizeof(int), __func__);
+ const int *v_origindex = rdata->mapped.v_origindex;
+ for (int i = 0; i < me_cage->totvert; i++) {
+ const int v_orig = v_origindex[i];
+ if (v_orig != ORIGINDEX_NONE) {
+ BMVert *eve = BM_vert_at_index(bm, v_orig);
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ /* Loose vert */
+ if (eve->e == NULL || !bm_vert_has_visible_edge(eve)) {
+ lverts[rdata->mapped.loose_vert_len++] = i;
+ }
+ }
+ }
+ }
+ rdata->mapped.loose_verts = MEM_reallocN(lverts, rdata->mapped.loose_vert_len * sizeof(int));
+ }
+
+ if (rdata->loose_edge_len) {
+ int *ledges = MEM_mallocN(me_cage->totedge * sizeof(int), __func__);
+ const int *e_origindex = rdata->mapped.e_origindex;
+ for (int i = 0; i < me_cage->totedge; i++) {
+ const int e_orig = e_origindex[i];
+ if (e_orig != ORIGINDEX_NONE) {
+ BMEdge *eed = BM_edge_at_index(bm, e_orig);
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ /* Loose edge */
+ if (eed->l == NULL || !bm_edge_has_visible_face(eed)) {
+ ledges[rdata->mapped.loose_edge_len++] = i;
+ }
+ }
+ }
+ }
+ rdata->mapped.loose_edges = MEM_reallocN(ledges, rdata->mapped.loose_edge_len * sizeof(int));
+ }
+ }
+ }
+ }
+ else {
+ if (types & (MR_DATATYPE_VERT)) {
+ rdata->vert_len = me->totvert;
+ rdata->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
+ }
+ if (types & (MR_DATATYPE_EDGE)) {
+ rdata->edge_len = me->totedge;
+ rdata->medge = CustomData_get_layer(&me->edata, CD_MEDGE);
+ }
+ if (types & MR_DATATYPE_LOOPTRI) {
+ const int tri_len = rdata->tri_len = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *mlooptri = MEM_mallocN(sizeof(*mlooptri) * tri_len, __func__);
+ BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mlooptri);
+ rdata->mlooptri = mlooptri;
+ }
+ if (types & MR_DATATYPE_LOOP) {
+ rdata->loop_len = me->totloop;
+ rdata->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
+
+ if (is_auto_smooth) {
+ mesh_render_calc_normals_loop_and_poly(me, split_angle, rdata);
+ }
+ }
+ if (types & MR_DATATYPE_POLY) {
+ rdata->poly_len = me->totpoly;
+ rdata->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
+ }
+ if (types & MR_DATATYPE_DVERT) {
+ rdata->vert_len = me->totvert;
+ rdata->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ }
+ if (types & MR_DATATYPE_LOOPCOL) {
+ rdata->loop_len = me->totloop;
+ rdata->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
+ }
+ if (types & MR_DATATYPE_LOOPUV) {
+ rdata->loop_len = me->totloop;
+ rdata->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
+ }
+ }
+
+ if (types & MR_DATATYPE_SHADING) {
+ CustomData *cd_vdata, *cd_ldata;
+
+ if (me->edit_btmesh) {
+ BMesh *bm = me->edit_btmesh->bm;
+ cd_vdata = &bm->vdata;
+ cd_ldata = &bm->ldata;
+ }
+ else {
+ cd_vdata = &me->vdata;
+ cd_ldata = &me->ldata;
+ }
+
+ /* Add edge/poly if we need them */
+ uchar cd_vused[CD_NUMTYPES] = {0};
+ ushort cd_lused[CD_NUMTYPES] = {0};
+
+ mesh_cd_calc_used_gpu_layers(
+ cd_vdata, cd_vused,
+ cd_ldata, cd_lused,
+ gpumat_array, gpumat_array_len);
+
+
+ rdata->cd.layers.uv_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
+ rdata->cd.layers.vcol_active = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
+ rdata->cd.layers.tangent_active = rdata->cd.layers.uv_active;
+
+#define CD_VALIDATE_ACTIVE_LAYER(active_index, used) \
+ if ((active_index != -1) && (used & (1 << active_index)) == 0) { \
+ active_index = -1; \
+ } ((void)0)
+
+ CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.uv_active, cd_lused[CD_MLOOPUV]);
+ CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.tangent_active, cd_lused[CD_TANGENT]);
+ CD_VALIDATE_ACTIVE_LAYER(rdata->cd.layers.vcol_active, cd_lused[CD_MLOOPCOL]);
+
+#undef CD_VALIDATE_ACTIVE_LAYER
+
+ rdata->is_orco_allocated = false;
+ if (cd_vused[CD_ORCO] & 1) {
+ rdata->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
+ /* If orco is not available compute it ourselves */
+ if (!rdata->orco) {
+ rdata->is_orco_allocated = true;
+ if (me->edit_btmesh) {
+ BMesh *bm = me->edit_btmesh->bm;
+ rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
+ BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
+ for (int i = 0; i < bm->totvert; i++) {
+ copy_v3_v3(rdata->orco[i], BM_vert_at_index(bm, i)->co);
+ }
+ BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
+ }
+ else {
+ rdata->orco = MEM_mallocN(sizeof(*rdata->orco) * rdata->vert_len, "orco mesh");
+ MVert *mvert = rdata->mvert;
+ for (int a = 0; a < rdata->vert_len; a++, mvert++) {
+ copy_v3_v3(rdata->orco[a], mvert->co);
+ }
+ BKE_mesh_orco_verts_transform(me, rdata->orco, rdata->vert_len, 0);
+ }
+ }
+ }
+ else {
+ rdata->orco = NULL;
+ }
+
+ /* don't access mesh directly, instead use vars taken from BMesh or Mesh */
+#define me DONT_USE_THIS
+#ifdef me /* quiet warning */
+#endif
+ struct {
+ uint uv_len;
+ uint vcol_len;
+ } cd_layers_src = {
+ .uv_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPUV),
+ .vcol_len = CustomData_number_of_layers(cd_ldata, CD_MLOOPCOL),
+ };
+
+ rdata->cd.layers.uv_len = count_bits_i(cd_lused[CD_MLOOPUV]);
+ rdata->cd.layers.tangent_len = count_bits_i(cd_lused[CD_TANGENT]);
+ rdata->cd.layers.vcol_len = count_bits_i(cd_lused[CD_MLOOPCOL]);
+
+ rdata->cd.layers.uv = MEM_mallocN(sizeof(*rdata->cd.layers.uv) * rdata->cd.layers.uv_len, __func__);
+ rdata->cd.layers.vcol = MEM_mallocN(sizeof(*rdata->cd.layers.vcol) * rdata->cd.layers.vcol_len, __func__);
+ rdata->cd.layers.tangent = MEM_mallocN(sizeof(*rdata->cd.layers.tangent) * rdata->cd.layers.tangent_len, __func__);
+
+ rdata->cd.uuid.uv = MEM_mallocN(sizeof(*rdata->cd.uuid.uv) * rdata->cd.layers.uv_len, __func__);
+ rdata->cd.uuid.vcol = MEM_mallocN(sizeof(*rdata->cd.uuid.vcol) * rdata->cd.layers.vcol_len, __func__);
+ rdata->cd.uuid.tangent = MEM_mallocN(sizeof(*rdata->cd.uuid.tangent) * rdata->cd.layers.tangent_len, __func__);
+
+ rdata->cd.offset.uv = MEM_mallocN(sizeof(*rdata->cd.offset.uv) * rdata->cd.layers.uv_len, __func__);
+ rdata->cd.offset.vcol = MEM_mallocN(sizeof(*rdata->cd.offset.vcol) * rdata->cd.layers.vcol_len, __func__);
+
+ /* Allocate max */
+ rdata->cd.layers.auto_vcol = MEM_callocN(
+ sizeof(*rdata->cd.layers.auto_vcol) * rdata->cd.layers.vcol_len, __func__);
+ rdata->cd.uuid.auto_mix = MEM_mallocN(
+ sizeof(*rdata->cd.uuid.auto_mix) * (rdata->cd.layers.vcol_len + rdata->cd.layers.uv_len), __func__);
+
+ /* XXX FIXME XXX */
+ /* We use a hash to identify each data layer based on its name.
+ * Gawain then search for this name in the current shader and bind if it exists.
+ * NOTE : This is prone to hash collision.
+ * One solution to hash collision would be to format the cd layer name
+ * to a safe glsl var name, but without name clash.
+ * NOTE 2 : Replicate changes to code_generate_vertex_new() in gpu_codegen.c */
+ if (rdata->cd.layers.vcol_len != 0) {
+ for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.vcol_len; i_src++, i_dst++) {
+ if ((cd_lused[CD_MLOOPCOL] & (1 << i_src)) == 0) {
+ i_dst--;
+ if (rdata->cd.layers.vcol_active >= i_src) {
+ rdata->cd.layers.vcol_active--;
+ }
+ }
+ else {
+ const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i_src);
+ uint hash = BLI_ghashutil_strhash_p(name);
+ BLI_snprintf(rdata->cd.uuid.vcol[i_dst], sizeof(*rdata->cd.uuid.vcol), "c%u", hash);
+ rdata->cd.layers.vcol[i_dst] = CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i_src);
+ if (rdata->edit_bmesh) {
+ rdata->cd.offset.vcol[i_dst] = CustomData_get_n_offset(
+ &rdata->edit_bmesh->bm->ldata, CD_MLOOPCOL, i_src);
+ }
+
+ /* Gather number of auto layers. */
+ /* We only do vcols that are not overridden by uvs */
+ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, name) == -1) {
+ BLI_snprintf(
+ rdata->cd.uuid.auto_mix[rdata->cd.layers.uv_len + i_dst],
+ sizeof(*rdata->cd.uuid.auto_mix), "a%u", hash);
+ rdata->cd.layers.auto_vcol[i_dst] = true;
+ }
+ }
+ }
+ }
+
+ /* Start Fresh */
+ CustomData_free_layers(cd_ldata, CD_TANGENT, rdata->loop_len);
+ CustomData_free_layers(cd_ldata, CD_MLOOPTANGENT, rdata->loop_len);
+
+ if (rdata->cd.layers.uv_len != 0) {
+ for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
+ if ((cd_lused[CD_MLOOPUV] & (1 << i_src)) == 0) {
+ i_dst--;
+ if (rdata->cd.layers.uv_active >= i_src) {
+ rdata->cd.layers.uv_active--;
+ }
+ }
+ else {
+ const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src);
+ uint hash = BLI_ghashutil_strhash_p(name);
+
+ BLI_snprintf(rdata->cd.uuid.uv[i_dst], sizeof(*rdata->cd.uuid.uv), "u%u", hash);
+ rdata->cd.layers.uv[i_dst] = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i_src);
+ if (rdata->edit_bmesh) {
+ rdata->cd.offset.uv[i_dst] = CustomData_get_n_offset(
+ &rdata->edit_bmesh->bm->ldata, CD_MLOOPUV, i_src);
+ }
+ BLI_snprintf(rdata->cd.uuid.auto_mix[i_dst], sizeof(*rdata->cd.uuid.auto_mix), "a%u", hash);
+ }
+ }
+ }
+
+ if (rdata->cd.layers.tangent_len != 0) {
+
+ /* -------------------------------------------------------------------- */
+ /* Pre-calculate tangents into 'rdata->cd.output.ldata' */
+
+ BLI_assert(!CustomData_has_layer(&rdata->cd.output.ldata, CD_TANGENT));
+
+ /* Tangent Names */
+ char tangent_names[MAX_MTFACE][MAX_NAME];
+ for (int i_src = 0, i_dst = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
+ if ((cd_lused[CD_TANGENT] & (1 << i_src)) == 0) {
+ i_dst--;
+ }
+ else {
+ BLI_strncpy(
+ tangent_names[i_dst],
+ CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src), MAX_NAME);
+ }
+ }
+
+ /* If tangent from orco is requested, decrement tangent_len */
+ int actual_tangent_len = (cd_lused[CD_TANGENT] & DM_TANGENT_MASK_ORCO) ?
+ rdata->cd.layers.tangent_len - 1 : rdata->cd.layers.tangent_len;
+ if (rdata->edit_bmesh) {
+ BMEditMesh *em = rdata->edit_bmesh;
+ BMesh *bm = em->bm;
+
+ if (is_auto_smooth && rdata->loop_normals == NULL) {
+ /* Should we store the previous array of `loop_normals` in somewhere? */
+ rdata->loop_len = bm->totloop;
+ rdata->loop_normals = MEM_mallocN(sizeof(*rdata->loop_normals) * rdata->loop_len, __func__);
+ BM_loops_calc_normal_vcos(bm, NULL, NULL, NULL, true, split_angle, rdata->loop_normals, NULL, NULL, -1, false);
+ }
+
+ bool calc_active_tangent = false;
+
+ BKE_editmesh_loop_tangent_calc(
+ em, calc_active_tangent,
+ tangent_names, actual_tangent_len,
+ rdata->poly_normals, rdata->loop_normals,
+ rdata->orco,
+ &rdata->cd.output.ldata, bm->totloop,
+ &rdata->cd.output.tangent_mask);
+ }
+ else {
+#undef me
+
+ if (is_auto_smooth && rdata->loop_normals == NULL) {
+ /* Should we store the previous array of `loop_normals` in CustomData? */
+ mesh_render_calc_normals_loop_and_poly(me, split_angle, rdata);
+ }
+
+ bool calc_active_tangent = false;
+
+ BKE_mesh_calc_loop_tangent_ex(
+ me->mvert,
+ me->mpoly, me->totpoly,
+ me->mloop,
+ rdata->mlooptri, rdata->tri_len,
+ cd_ldata,
+ calc_active_tangent,
+ tangent_names, actual_tangent_len,
+ rdata->poly_normals, rdata->loop_normals,
+ rdata->orco,
+ &rdata->cd.output.ldata, me->totloop,
+ &rdata->cd.output.tangent_mask);
+
+ /* If we store tangents in the mesh, set temporary. */
+#if 0
+ CustomData_set_layer_flag(cd_ldata, CD_TANGENT, CD_FLAG_TEMPORARY);
+#endif
+
+#define me DONT_USE_THIS
+#ifdef me /* quiet warning */
+#endif
+ }
+
+ /* End tangent calculation */
+ /* -------------------------------------------------------------------- */
+
+ BLI_assert(CustomData_number_of_layers(&rdata->cd.output.ldata, CD_TANGENT) == rdata->cd.layers.tangent_len);
+
+ int i_dst = 0;
+ for (int i_src = 0; i_src < cd_layers_src.uv_len; i_src++, i_dst++) {
+ if ((cd_lused[CD_TANGENT] & (1 << i_src)) == 0) {
+ i_dst--;
+ if (rdata->cd.layers.tangent_active >= i_src) {
+ rdata->cd.layers.tangent_active--;
+ }
+ }
+ else {
+ const char *name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i_src);
+ uint hash = BLI_ghashutil_strhash_p(name);
+
+ BLI_snprintf(rdata->cd.uuid.tangent[i_dst], sizeof(*rdata->cd.uuid.tangent), "t%u", hash);
+
+ /* Done adding tangents. */
+
+ /* note: BKE_editmesh_loop_tangent_calc calculates 'CD_TANGENT',
+ * not 'CD_MLOOPTANGENT' (as done below). It's OK, they're compatible. */
+
+ /* note: normally we'd use 'i_src' here, but 'i_dst' is in sync with 'rdata->cd.output' */
+ rdata->cd.layers.tangent[i_dst] = CustomData_get_layer_n(&rdata->cd.output.ldata, CD_TANGENT, i_dst);
+ if (rdata->tri_len != 0) {
+ BLI_assert(rdata->cd.layers.tangent[i_dst] != NULL);
+ }
+ }
+ }
+ if (cd_lused[CD_TANGENT] & DM_TANGENT_MASK_ORCO) {
+ const char *name = CustomData_get_layer_name(&rdata->cd.output.ldata, CD_TANGENT, i_dst);
+ uint hash = BLI_ghashutil_strhash_p(name);
+ BLI_snprintf(rdata->cd.uuid.tangent[i_dst], sizeof(*rdata->cd.uuid.tangent), "t%u", hash);
+
+ rdata->cd.layers.tangent[i_dst] = CustomData_get_layer_n(&rdata->cd.output.ldata, CD_TANGENT, i_dst);
+ }
+ }
+
+#undef me
+ }
+
+ return rdata;
+}
+
+static void mesh_render_data_free(MeshRenderData *rdata)
+{
+ if (rdata->is_orco_allocated) {
+ MEM_SAFE_FREE(rdata->orco);
+ }
+ MEM_SAFE_FREE(rdata->cd.offset.uv);
+ MEM_SAFE_FREE(rdata->cd.offset.vcol);
+ MEM_SAFE_FREE(rdata->cd.uuid.auto_mix);
+ MEM_SAFE_FREE(rdata->cd.uuid.uv);
+ MEM_SAFE_FREE(rdata->cd.uuid.vcol);
+ MEM_SAFE_FREE(rdata->cd.uuid.tangent);
+ MEM_SAFE_FREE(rdata->cd.layers.uv);
+ MEM_SAFE_FREE(rdata->cd.layers.vcol);
+ MEM_SAFE_FREE(rdata->cd.layers.tangent);
+ MEM_SAFE_FREE(rdata->cd.layers.auto_vcol);
+ MEM_SAFE_FREE(rdata->loose_verts);
+ MEM_SAFE_FREE(rdata->loose_edges);
+ MEM_SAFE_FREE(rdata->edges_adjacent_polys);
+ MEM_SAFE_FREE(rdata->mlooptri);
+ MEM_SAFE_FREE(rdata->loop_normals);
+ MEM_SAFE_FREE(rdata->poly_normals);
+ MEM_SAFE_FREE(rdata->poly_normals_pack);
+ MEM_SAFE_FREE(rdata->vert_normals_pack);
+ MEM_SAFE_FREE(rdata->vert_weight);
+ MEM_SAFE_FREE(rdata->edge_select_bool);
+ MEM_SAFE_FREE(rdata->edge_visible_bool);
+ MEM_SAFE_FREE(rdata->vert_color);
+
+ MEM_SAFE_FREE(rdata->mapped.loose_verts);
+ MEM_SAFE_FREE(rdata->mapped.loose_edges);
+
+ CustomData_free(&rdata->cd.output.ldata, rdata->loop_len);
+
+ MEM_freeN(rdata);
+}
+
+static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
+{
+ return mesh_render_data_create_ex(me, types, NULL, 0);
+}
+
+/** \} */
+
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Accessor Functions
+ * \{ */
+
+static const char *mesh_render_data_uv_auto_layer_uuid_get(const MeshRenderData *rdata, int layer)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_SHADING);
+ return rdata->cd.uuid.auto_mix[layer];
+}
+
+static const char *mesh_render_data_vcol_auto_layer_uuid_get(const MeshRenderData *rdata, int layer)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_SHADING);
+ return rdata->cd.uuid.auto_mix[rdata->cd.layers.uv_len + layer];
+}
+
+static const char *mesh_render_data_uv_layer_uuid_get(const MeshRenderData *rdata, int layer)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_SHADING);
+ return rdata->cd.uuid.uv[layer];
+}
+
+static const char *mesh_render_data_vcol_layer_uuid_get(const MeshRenderData *rdata, int layer)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_SHADING);
+ return rdata->cd.uuid.vcol[layer];
+}
+
+static const char *mesh_render_data_tangent_layer_uuid_get(const MeshRenderData *rdata, int layer)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_SHADING);
+ return rdata->cd.uuid.tangent[layer];
+}
+
+static int mesh_render_data_verts_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+ return rdata->vert_len;
+}
+static int mesh_render_data_verts_len_get_maybe_mapped(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+ return ((rdata->mapped.use == false) ? rdata->vert_len : rdata->mapped.vert_len);
+}
+
+static int UNUSED_FUNCTION(mesh_render_data_loose_verts_len_get)(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_OVERLAY);
+ return rdata->loose_vert_len;
+}
+static int mesh_render_data_loose_verts_len_get_maybe_mapped(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_OVERLAY);
+ return ((rdata->mapped.use == false) ? rdata->loose_vert_len : rdata->mapped.loose_vert_len);
+}
+
+static int mesh_render_data_edges_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_EDGE);
+ return rdata->edge_len;
+}
+static int mesh_render_data_edges_len_get_maybe_mapped(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_EDGE);
+ return ((rdata->mapped.use == false) ? rdata->edge_len : rdata->mapped.edge_len);
+}
+
+static int UNUSED_FUNCTION(mesh_render_data_loose_edges_len_get)(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_OVERLAY);
+ return rdata->loose_edge_len;
+}
+static int mesh_render_data_loose_edges_len_get_maybe_mapped(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_OVERLAY);
+ return ((rdata->mapped.use == false) ? rdata->loose_edge_len : rdata->mapped.loose_edge_len);
+}
+
+static int mesh_render_data_looptri_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_LOOPTRI);
+ return rdata->tri_len;
+}
+static int mesh_render_data_looptri_len_get_maybe_mapped(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_LOOPTRI);
+ return ((rdata->mapped.use == false) ? rdata->tri_len : rdata->mapped.tri_len);
+}
+
+static int mesh_render_data_mat_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_POLY);
+ return rdata->mat_len;
+}
+
+static int mesh_render_data_loops_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_LOOP);
+ return rdata->loop_len;
+}
+
+static int mesh_render_data_polys_len_get(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_POLY);
+ return rdata->poly_len;
+}
+static int mesh_render_data_polys_len_get_maybe_mapped(const MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_POLY);
+ return ((rdata->mapped.use == false) ? rdata->poly_len : rdata->mapped.poly_len);
+}
+
+/** \} */
+
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Internal Cache (Lazy Initialization)
+ * \{ */
+
+/** Ensure #MeshRenderData.poly_normals_pack */
+static void mesh_render_data_ensure_poly_normals_pack(MeshRenderData *rdata)
+{
+ GPUPackedNormal *pnors_pack = rdata->poly_normals_pack;
+ if (pnors_pack == NULL) {
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter fiter;
+ BMFace *efa;
+ int i;
+
+ pnors_pack = rdata->poly_normals_pack = MEM_mallocN(sizeof(*pnors_pack) * rdata->poly_len, __func__);
+ if (rdata->edit_data && rdata->edit_data->vertexCos != NULL) {
+ BKE_editmesh_cache_ensure_poly_normals(rdata->edit_bmesh, rdata->edit_data);
+ const float (*pnors)[3] = rdata->edit_data->polyNos;
+ for (i = 0; i < bm->totface; i++) {
+ pnors_pack[i] = GPU_normal_convert_i10_v3(pnors[i]);
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX(efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ pnors_pack[i] = GPU_normal_convert_i10_v3(efa->no);
+ }
+ }
+ }
+ else {
+ float (*pnors)[3] = rdata->poly_normals;
+
+ if (!pnors) {
+ pnors = rdata->poly_normals = MEM_mallocN(sizeof(*pnors) * rdata->poly_len, __func__);
+ BKE_mesh_calc_normals_poly(
+ rdata->mvert, NULL, rdata->vert_len,
+ rdata->mloop, rdata->mpoly, rdata->loop_len, rdata->poly_len, pnors, true);
+ }
+
+ pnors_pack = rdata->poly_normals_pack = MEM_mallocN(sizeof(*pnors_pack) * rdata->poly_len, __func__);
+ for (int i = 0; i < rdata->poly_len; i++) {
+ pnors_pack[i] = GPU_normal_convert_i10_v3(pnors[i]);
+ }
+ }
+ }
+}
+
+/** Ensure #MeshRenderData.vert_normals_pack */
+static void mesh_render_data_ensure_vert_normals_pack(MeshRenderData *rdata)
+{
+ GPUPackedNormal *vnors_pack = rdata->vert_normals_pack;
+ if (vnors_pack == NULL) {
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter viter;
+ BMVert *eve;
+ int i;
+
+ vnors_pack = rdata->vert_normals_pack = MEM_mallocN(sizeof(*vnors_pack) * rdata->vert_len, __func__);
+ BM_ITER_MESH_INDEX(eve, &viter, bm, BM_VERT, i) {
+ vnors_pack[i] = GPU_normal_convert_i10_v3(eve->no);
+ }
+ }
+ else {
+ /* data from mesh used directly */
+ BLI_assert(0);
+ }
+ }
+}
+
+
+/** Ensure #MeshRenderData.vert_color */
+static void mesh_render_data_ensure_vert_color(MeshRenderData *rdata)
+{
+ char (*vcol)[3] = rdata->vert_color;
+ if (vcol == NULL) {
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
+ if (cd_loop_color_offset == -1) {
+ goto fallback;
+ }
+
+ vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
+
+ BMIter fiter;
+ BMFace *efa;
+ int i = 0;
+
+ BM_ITER_MESH(efa, &fiter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_color_offset);
+ vcol[i][0] = lcol->r;
+ vcol[i][1] = lcol->g;
+ vcol[i][2] = lcol->b;
+ i += 1;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ BLI_assert(i == rdata->loop_len);
+ }
+ else {
+ if (rdata->mloopcol == NULL) {
+ goto fallback;
+ }
+
+ vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
+
+ for (int i = 0; i < rdata->loop_len; i++) {
+ vcol[i][0] = rdata->mloopcol[i].r;
+ vcol[i][1] = rdata->mloopcol[i].g;
+ vcol[i][2] = rdata->mloopcol[i].b;
+ }
+ }
+ }
+ return;
+
+fallback:
+ vcol = rdata->vert_color = MEM_mallocN(sizeof(*vcol) * rdata->loop_len, __func__);
+
+ for (int i = 0; i < rdata->loop_len; i++) {
+ vcol[i][0] = 255;
+ vcol[i][1] = 255;
+ vcol[i][2] = 255;
+ }
+}
+
+static float evaluate_vertex_weight(const MDeformVert *dvert, const struct DRW_MeshWeightState *wstate)
+{
+ float input = 0.0f;
+ bool show_alert_color = false;
+
+ if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) {
+ /* Multi-Paint feature */
+ input = BKE_defvert_multipaint_collective_weight(
+ dvert, wstate->defgroup_len, wstate->defgroup_sel, wstate->defgroup_sel_count,
+ (wstate->flags & DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE) != 0);
+
+ /* make it black if the selected groups have no weight on a vertex */
+ if (input == 0.0f) {
+ show_alert_color = true;
+ }
+ }
+ else {
+ /* default, non tricky behavior */
+ input = defvert_find_weight(dvert, wstate->defgroup_active);
+
+ if (input == 0.0f) {
+ switch (wstate->alert_mode) {
+ case OB_DRAW_GROUPUSER_ACTIVE:
+ show_alert_color = true;
+ break;
+
+ case OB_DRAW_GROUPUSER_ALL:
+ show_alert_color = defvert_is_weight_zero(dvert, wstate->defgroup_len);
+ break;
+ }
+ }
+ }
+
+ if (show_alert_color) {
+ return -1.0f;
+ }
+ else {
+ CLAMP(input, 0.0f, 1.0f);
+ return input;
+ }
+}
+
+/** Ensure #MeshRenderData.vert_weight */
+static void mesh_render_data_ensure_vert_weight(MeshRenderData *rdata, const struct DRW_MeshWeightState *wstate)
+{
+ float (*vweight) = rdata->vert_weight;
+ if (vweight == NULL) {
+ if (wstate->defgroup_active == -1) {
+ goto fallback;
+ }
+
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
+ if (cd_dvert_offset == -1) {
+ goto fallback;
+ }
+
+ BMIter viter;
+ BMVert *eve;
+ int i;
+
+ vweight = rdata->vert_weight = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__);
+ BM_ITER_MESH_INDEX(eve, &viter, bm, BM_VERT, i) {
+ const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ vweight[i] = evaluate_vertex_weight(dvert, wstate);
+ }
+ }
+ else {
+ if (rdata->dvert == NULL) {
+ goto fallback;
+ }
+
+ vweight = rdata->vert_weight = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__);
+ for (int i = 0; i < rdata->vert_len; i++) {
+ vweight[i] = evaluate_vertex_weight(&rdata->dvert[i], wstate);
+ }
+ }
+ }
+ return;
+
+fallback:
+ vweight = rdata->vert_weight = MEM_callocN(sizeof(*vweight) * rdata->vert_len, __func__);
+
+ if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) {
+ copy_vn_fl(vweight, rdata->vert_len, -2.0f);
+ }
+ else if (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) {
+ copy_vn_fl(vweight, rdata->vert_len, -1.0f);
+ }
+}
+
+
+/** Ensure #MeshRenderData.edge_select_bool */
+static void mesh_render_data_ensure_edge_select_bool(MeshRenderData *rdata, bool use_wire)
+{
+ bool *edge_select_bool = rdata->edge_select_bool;
+ if (edge_select_bool == NULL) {
+ edge_select_bool = rdata->edge_select_bool =
+ MEM_callocN(sizeof(*edge_select_bool) * rdata->edge_len, __func__);
+
+ for (int i = 0; i < rdata->poly_len; i++) {
+ const MPoly *poly = &rdata->mpoly[i];
+
+ if (poly->flag & ME_FACE_SEL) {
+ for (int j = 0; j < poly->totloop; j++) {
+ const MLoop *loop = &rdata->mloop[poly->loopstart + j];
+ if (use_wire) {
+ edge_select_bool[loop->e] = true;
+ }
+ else {
+ /* Not totally correct, will cause problems for edges with 3x faces. */
+ edge_select_bool[loop->e] = !edge_select_bool[loop->e];
+ }
+ }
+ }
+ }
+ }
+}
+
+/** Ensure #MeshRenderData.edge_visible_bool */
+static void mesh_render_data_ensure_edge_visible_bool(MeshRenderData *rdata)
+{
+ bool *edge_visible_bool = rdata->edge_visible_bool;
+ if (edge_visible_bool == NULL) {
+ edge_visible_bool = rdata->edge_visible_bool =
+ MEM_callocN(sizeof(*edge_visible_bool) * rdata->edge_len, __func__);
+
+ for (int i = 0; i < rdata->poly_len; i++) {
+ const MPoly *poly = &rdata->mpoly[i];
+
+ if (!(poly->flag & ME_HIDE)) {
+ for (int j = 0; j < poly->totloop; j++) {
+ const MLoop *loop = &rdata->mloop[poly->loopstart + j];
+ edge_visible_bool[loop->e] = true;
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Internal Cache Generation
+ * \{ */
+
+static bool mesh_render_data_pnors_pcenter_select_get(
+ MeshRenderData *rdata, const int poly,
+ float r_pnors[3], float r_center[3], bool *r_selected)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (rdata->edit_bmesh) {
+ const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, poly);
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ return false;
+ }
+ if (rdata->edit_data && rdata->edit_data->vertexCos) {
+ copy_v3_v3(r_center, rdata->edit_data->polyCos[poly]);
+ copy_v3_v3(r_pnors, rdata->edit_data->polyNos[poly]);
+ }
+ else {
+ BM_face_calc_center_mean(efa, r_center);
+ copy_v3_v3(r_pnors, efa->no);
+ }
+ *r_selected = (BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0) ? true : false;
+ }
+ else {
+ MVert *mvert = rdata->mvert;
+ const MPoly *mpoly = rdata->mpoly + poly;
+ const MLoop *mloop = rdata->mloop + mpoly->loopstart;
+
+ BKE_mesh_calc_poly_center(mpoly, mloop, mvert, r_center);
+ BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, r_pnors);
+
+ *r_selected = false; /* No selection if not in edit mode */
+ }
+
+ return true;
+}
+static bool mesh_render_data_pnors_pcenter_select_get_mapped(
+ MeshRenderData *rdata, const int poly,
+ float r_pnors[3], float r_center[3], bool *r_selected)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+ const int *p_origindex = rdata->mapped.p_origindex;
+ const int p_orig = p_origindex[poly];
+ if (p_orig == ORIGINDEX_NONE) {
+ return false;
+ }
+ BMEditMesh *em = rdata->edit_bmesh;
+ const BMFace *efa = BM_face_at_index(rdata->edit_bmesh->bm, p_orig);
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ return false;
+ }
+
+ Mesh *me_cage = em->mesh_eval_cage;
+ const MVert *mvert = me_cage->mvert;
+#if 0
+ const MEdge *medge = me_cage->medge;
+#endif
+ const MLoop *mloop = me_cage->mloop;
+ const MPoly *mpoly = me_cage->mpoly;
+
+ const MPoly *mp = mpoly + poly;
+ const MLoop *ml = mloop + mp->loopstart;
+
+ BKE_mesh_calc_poly_center(mp, ml, mvert, r_center);
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, r_pnors);
+
+ *r_selected = (BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0) ? true : false;
+
+ return true;
+}
+
+static bool mesh_render_data_edge_vcos_manifold_pnors(
+ MeshRenderData *rdata, const int edge_index,
+ float **r_vco1, float **r_vco2, float **r_pnor1, float **r_pnor2, bool *r_is_manifold)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMEdge *eed = BM_edge_at_index(bm, edge_index);
+ if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ return false;
+ }
+ *r_vco1 = eed->v1->co;
+ *r_vco2 = eed->v2->co;
+ if (BM_edge_is_manifold(eed)) {
+ *r_pnor1 = eed->l->f->no;
+ *r_pnor2 = eed->l->radial_next->f->no;
+ *r_is_manifold = true;
+ }
+ else if (eed->l != NULL) {
+ *r_pnor1 = eed->l->f->no;
+ *r_pnor2 = eed->l->f->no;
+ *r_is_manifold = false;
+ }
+ else {
+ *r_pnor1 = eed->v1->no;
+ *r_pnor2 = eed->v1->no;
+ *r_is_manifold = false;
+ }
+ }
+ else {
+ MVert *mvert = rdata->mvert;
+ const MEdge *medge = rdata->medge;
+ EdgeAdjacentPolys *eap = rdata->edges_adjacent_polys;
+ float (*pnors)[3] = rdata->poly_normals;
+
+ if (!eap) {
+ const MLoop *mloop = rdata->mloop;
+ const MPoly *mpoly = rdata->mpoly;
+ const int poly_len = rdata->poly_len;
+ const bool do_pnors = (poly_len != 0 && pnors == NULL);
+
+ eap = rdata->edges_adjacent_polys = MEM_mallocN(sizeof(*eap) * rdata->edge_len, __func__);
+ for (int i = 0; i < rdata->edge_len; i++) {
+ eap[i].count = 0;
+ eap[i].face_index[0] = -1;
+ eap[i].face_index[1] = -1;
+ }
+ if (do_pnors) {
+ pnors = rdata->poly_normals = MEM_mallocN(sizeof(*pnors) * poly_len, __func__);
+ }
+
+ for (int i = 0; i < poly_len; i++, mpoly++) {
+ if (do_pnors) {
+ BKE_mesh_calc_poly_normal(mpoly, mloop + mpoly->loopstart, mvert, pnors[i]);
+ }
+
+ const int loopend = mpoly->loopstart + mpoly->totloop;
+ for (int j = mpoly->loopstart; j < loopend; j++) {
+ const int edge_idx = mloop[j].e;
+ if (eap[edge_idx].count < 2) {
+ eap[edge_idx].face_index[eap[edge_idx].count] = i;
+ }
+ eap[edge_idx].count++;
+ }
+ }
+ }
+ BLI_assert(eap && (rdata->poly_len == 0 || pnors != NULL));
+
+ *r_vco1 = mvert[medge[edge_index].v1].co;
+ *r_vco2 = mvert[medge[edge_index].v2].co;
+ if (eap[edge_index].face_index[0] == -1) {
+ /* Edge has no poly... */
+ *r_pnor1 = *r_pnor2 = mvert[medge[edge_index].v1].co; /* XXX mvert.no are shorts... :( */
+ *r_is_manifold = false;
+ }
+ else {
+ *r_pnor1 = pnors[eap[edge_index].face_index[0]];
+
+ float nor[3], v1[3], v2[3], r_center[3];
+ const MPoly *mpoly = rdata->mpoly + eap[edge_index].face_index[0];
+ const MLoop *mloop = rdata->mloop + mpoly->loopstart;
+
+ BKE_mesh_calc_poly_center(mpoly, mloop, mvert, r_center);
+ sub_v3_v3v3(v1, *r_vco2, *r_vco1);
+ sub_v3_v3v3(v2, r_center, *r_vco1);
+ cross_v3_v3v3(nor, v1, v2);
+
+ if (dot_v3v3(nor, *r_pnor1) < 0.0) {
+ SWAP(float *, *r_vco1, *r_vco2);
+ }
+
+ if (eap[edge_index].count == 2) {
+ BLI_assert(eap[edge_index].face_index[1] >= 0);
+ *r_pnor2 = pnors[eap[edge_index].face_index[1]];
+ *r_is_manifold = true;
+ }
+ else {
+ *r_pnor2 = pnors[eap[edge_index].face_index[0]];
+ *r_is_manifold = false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static uchar mesh_render_data_looptri_flag(MeshRenderData *rdata, const BMFace *efa)
+{
+ uchar fflag = 0;
+
+ if (efa == rdata->efa_act)
+ fflag |= VFLAG_FACE_ACTIVE;
+
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ fflag |= VFLAG_FACE_SELECTED;
+
+#ifdef WITH_FREESTYLE
+ if (rdata->cd.offset.freestyle_face != -1) {
+ const FreestyleFace *ffa = BM_ELEM_CD_GET_VOID_P(efa, rdata->cd.offset.freestyle_face);
+ if (ffa->flag & FREESTYLE_FACE_MARK) {
+ fflag |= VFLAG_FACE_FREESTYLE;
+ }
+ }
+#endif
+
+ return fflag;
+}
+
+static void mesh_render_data_edge_flag(
+ const MeshRenderData *rdata, const BMEdge *eed,
+ EdgeDrawAttr *eattr)
+{
+ eattr->e_flag |= VFLAG_EDGE_EXISTS;
+
+ if (eed == rdata->eed_act)
+ eattr->e_flag |= VFLAG_EDGE_ACTIVE;
+
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT))
+ eattr->e_flag |= VFLAG_EDGE_SELECTED;
+
+ if (BM_elem_flag_test(eed, BM_ELEM_SEAM))
+ eattr->e_flag |= VFLAG_EDGE_SEAM;
+
+ if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
+ eattr->e_flag |= VFLAG_EDGE_SHARP;
+
+ /* Use a byte for value range */
+ if (rdata->cd.offset.crease != -1) {
+ float crease = BM_ELEM_CD_GET_FLOAT(eed, rdata->cd.offset.crease);
+ if (crease > 0) {
+ eattr->crease = (uchar)(crease * 255.0f);
+ }
+ }
+
+ /* Use a byte for value range */
+ if (rdata->cd.offset.bweight != -1) {
+ float bweight = BM_ELEM_CD_GET_FLOAT(eed, rdata->cd.offset.bweight);
+ if (bweight > 0) {
+ eattr->bweight = (uchar)(bweight * 255.0f);
+ }
+ }
+
+#ifdef WITH_FREESTYLE
+ if (rdata->cd.offset.freestyle_edge != -1) {
+ const FreestyleEdge *fed = BM_ELEM_CD_GET_VOID_P(eed, rdata->cd.offset.freestyle_edge);
+ if (fed->flag & FREESTYLE_EDGE_MARK) {
+ eattr->e_flag |= VFLAG_EDGE_FREESTYLE;
+ }
+ }
+#endif
+}
+
+static uchar mesh_render_data_vertex_flag(MeshRenderData *rdata, const BMVert *eve)
+{
+ uchar vflag = VFLAG_VERTEX_EXISTS;
+
+ /* Current vertex */
+ if (eve == rdata->eve_act)
+ vflag |= VFLAG_VERTEX_ACTIVE;
+
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
+ vflag |= VFLAG_VERTEX_SELECTED;
+
+ return vflag;
+}
+
+static void add_overlay_tri(
+ MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data, GPUIndexBufBuilder *elb,
+ const uint pos_id, const uint vnor_id, const uint lnor_id, const uint data_id,
+ const BMLoop **bm_looptri, const int base_vert_idx)
+{
+ uchar fflag;
+ uchar vflag;
+
+ for (int i = 0; i < 3; ++i) {
+ if (!BM_elem_flag_test(bm_looptri[i]->v, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(bm_looptri[i]->v, BM_ELEM_TAG);
+ GPU_indexbuf_add_generic_vert(elb, base_vert_idx + i);
+ }
+ }
+
+ if (vbo_pos) {
+ /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */
+ if (rdata->edit_data && rdata->edit_data->vertexCos) {
+ for (uint i = 0; i < 3; i++) {
+ int vidx = BM_elem_index_get(bm_looptri[i]->v);
+ const float *pos = rdata->edit_data->vertexCos[vidx];
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos);
+ }
+ }
+ else {
+ for (uint i = 0; i < 3; i++) {
+ const float *pos = bm_looptri[i]->v->co;
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos);
+ }
+ }
+ }
+
+ if (vbo_nor) {
+ float (*lnors)[3] = rdata->loop_normals;
+ for (uint i = 0; i < 3; i++) {
+ const float *nor = (lnors) ? lnors[BM_elem_index_get(bm_looptri[i])] : bm_looptri[0]->f->no;
+ GPUPackedNormal lnor = GPU_normal_convert_i10_v3(nor);
+ GPU_vertbuf_attr_set(vbo_nor, lnor_id, base_vert_idx + i, &lnor);
+ GPUPackedNormal vnor = GPU_normal_convert_i10_v3(bm_looptri[i]->v->no);
+ GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor);
+ }
+ }
+
+ if (vbo_data) {
+ fflag = mesh_render_data_looptri_flag(rdata, bm_looptri[0]->f);
+ for (uint i = 0; i < 3; i++) {
+ const int i_next = (i + 1) % 3;
+ const int i_prev = (i + 2) % 3;
+ vflag = mesh_render_data_vertex_flag(rdata, bm_looptri[i]->v);
+ /* Opposite edge to the vertex at 'i'. */
+ EdgeDrawAttr eattr = {0};
+ const bool is_edge_real = (bm_looptri[i_next] == bm_looptri[i_prev]->prev);
+ if (is_edge_real) {
+ mesh_render_data_edge_flag(rdata, bm_looptri[i_next]->e, &eattr);
+ }
+ eattr.v_flag = fflag | vflag;
+ GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx + i, &eattr);
+ }
+ }
+}
+static void add_overlay_tri_mapped(
+ MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data, GPUIndexBufBuilder *elb,
+ const uint pos_id, const uint vnor_id, const uint lnor_id, const uint data_id,
+ BMFace *efa, const MLoopTri *mlt, const float poly_normal[3], const int base_vert_idx)
+{
+ BMEditMesh *embm = rdata->edit_bmesh;
+ BMesh *bm = embm->bm;
+ Mesh *me_cage = embm->mesh_eval_cage;
+
+ const MVert *mvert = me_cage->mvert;
+ const MEdge *medge = me_cage->medge;
+ const MLoop *mloop = me_cage->mloop;
+#if 0
+ const MPoly *mpoly = me_cage->mpoly;
+#endif
+
+ const int *v_origindex = rdata->mapped.v_origindex;
+ const int *e_origindex = rdata->mapped.e_origindex;
+#if 0
+ const int *l_origindex = rdata->mapped.l_origindex;
+ const int *p_origindex = rdata->mapped.p_origindex;
+#endif
+
+ uchar fflag;
+ uchar vflag;
+
+ if (elb) {
+ for (int i = 0; i < 3; ++i) {
+ const int v_orig = v_origindex[mloop[mlt->tri[i]].v];
+ if (v_orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ BMVert *v = BM_vert_at_index(bm, v_orig);
+ if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ GPU_indexbuf_add_generic_vert(elb, base_vert_idx + i);
+ }
+ }
+ }
+
+ if (vbo_pos) {
+ for (uint i = 0; i < 3; i++) {
+ const float *pos = mvert[mloop[mlt->tri[i]].v].co;
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos);
+ }
+ }
+
+ if (vbo_nor) {
+ float (*lnors)[3] = rdata->loop_normals;
+ for (uint i = 0; i < 3; i++) {
+ const float *nor = (lnors) ? lnors[mlt->tri[i]] : poly_normal;
+ GPUPackedNormal lnor = GPU_normal_convert_i10_v3(nor);
+ GPU_vertbuf_attr_set(vbo_nor, lnor_id, base_vert_idx + i, &lnor);
+ GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[mloop[mlt->tri[i]].v].no);
+ GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor);
+ }
+ }
+
+ if (vbo_data) {
+ fflag = mesh_render_data_looptri_flag(rdata, efa);
+ for (uint i = 0; i < 3; i++) {
+ const int i_next = (i + 1) % 3;
+ const int i_prev = (i + 2) % 3;
+ const int v_orig = v_origindex[mloop[mlt->tri[i]].v];
+ if (v_orig != ORIGINDEX_NONE) {
+ BMVert *v = BM_vert_at_index(bm, v_orig);
+ vflag = mesh_render_data_vertex_flag(rdata, v);
+ }
+ else {
+ /* Importantly VFLAG_VERTEX_EXISTS is not set. */
+ vflag = 0;
+ }
+ /* Opposite edge to the vertex at 'i'. */
+ EdgeDrawAttr eattr = {0};
+ const int e_idx = mloop[mlt->tri[i_next]].e;
+ const int e_orig = e_origindex[e_idx];
+ if (e_orig != ORIGINDEX_NONE) {
+ const MEdge *ed = &medge[e_idx];
+ const uint tri_edge[2] = {mloop[mlt->tri[i_prev]].v, mloop[mlt->tri[i_next]].v};
+ const bool is_edge_real = (
+ ((ed->v1 == tri_edge[0]) && (ed->v2 == tri_edge[1])) ||
+ ((ed->v1 == tri_edge[1]) && (ed->v2 == tri_edge[0])));
+ if (is_edge_real) {
+ BMEdge *eed = BM_edge_at_index(bm, e_orig);
+ mesh_render_data_edge_flag(rdata, eed, &eattr);
+ }
+ }
+ eattr.v_flag = fflag | vflag;
+ GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx + i, &eattr);
+ }
+ }
+}
+
+static void add_overlay_loose_edge(
+ MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data,
+ const uint pos_id, const uint vnor_id, const uint data_id,
+ const BMEdge *eed, const int base_vert_idx)
+{
+ if (vbo_pos) {
+ /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */
+ if (rdata->edit_data && rdata->edit_data->vertexCos) {
+ for (uint i = 0; i < 2; i++) {
+ int vidx = BM_elem_index_get((&eed->v1)[i]);
+ const float *pos = rdata->edit_data->vertexCos[vidx];
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos);
+ }
+ }
+ else {
+ for (int i = 0; i < 2; i++) {
+ const float *pos = (&eed->v1)[i]->co;
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos);
+ }
+ }
+ }
+
+ if (vbo_nor) {
+ for (int i = 0; i < 2; i++) {
+ GPUPackedNormal vnor = GPU_normal_convert_i10_v3((&eed->v1)[i]->no);
+ GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor);
+ }
+ }
+
+ if (vbo_data) {
+ EdgeDrawAttr eattr = {0};
+ mesh_render_data_edge_flag(rdata, eed, &eattr);
+ for (int i = 0; i < 2; i++) {
+ eattr.v_flag = mesh_render_data_vertex_flag(rdata, (&eed->v1)[i]);
+ GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx + i, &eattr);
+ }
+ }
+}
+static void add_overlay_loose_edge_mapped(
+ MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data,
+ const uint pos_id, const uint vnor_id, const uint data_id,
+ BMEdge *eed, const MVert *mvert, const MEdge *ed, const int base_vert_idx)
+{
+ if (vbo_pos) {
+ /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */
+ for (int i = 0; i < 2; i++) {
+ const float *pos = mvert[*(&ed->v1 + i)].co;
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx + i, pos);
+ }
+ }
+
+ if (vbo_nor) {
+ for (int i = 0; i < 2; i++) {
+ GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mvert[*(&ed->v1 + i)].no);
+ GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx + i, &vnor);
+ }
+ }
+
+ if (vbo_data) {
+ EdgeDrawAttr eattr = {0};
+ mesh_render_data_edge_flag(rdata, eed, &eattr);
+ for (int i = 0; i < 2; i++) {
+ const int v_orig = rdata->mapped.v_origindex[*(&ed->v1 + i)];
+ eattr.v_flag = (v_orig != ORIGINDEX_NONE) ? mesh_render_data_vertex_flag(rdata, (&eed->v1)[i]) : 0;
+ GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx + i, &eattr);
+ }
+ }
+}
+
+static void add_overlay_loose_vert(
+ MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data,
+ const uint pos_id, const uint vnor_id, const uint data_id,
+ const BMVert *eve, const int base_vert_idx)
+{
+ if (vbo_pos) {
+ /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */
+ if (rdata->edit_data && rdata->edit_data->vertexCos) {
+ int vidx = BM_elem_index_get(eve);
+ const float *pos = rdata->edit_data->vertexCos[vidx];
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx, pos);
+ }
+ else {
+ const float *pos = eve->co;
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx, pos);
+ }
+ }
+
+ if (vbo_nor) {
+ GPUPackedNormal vnor = GPU_normal_convert_i10_v3(eve->no);
+ GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx, &vnor);
+ }
+
+ if (vbo_data) {
+ uchar vflag[4] = {0, 0, 0, 0};
+ vflag[0] = mesh_render_data_vertex_flag(rdata, eve);
+ GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx, vflag);
+ }
+}
+static void add_overlay_loose_vert_mapped(
+ MeshRenderData *rdata, GPUVertBuf *vbo_pos, GPUVertBuf *vbo_nor, GPUVertBuf *vbo_data,
+ const uint pos_id, const uint vnor_id, const uint data_id,
+ const BMVert *eve, const MVert *mv, const int base_vert_idx)
+{
+ if (vbo_pos) {
+ const float *pos = mv->co;
+ GPU_vertbuf_attr_set(vbo_pos, pos_id, base_vert_idx, pos);
+ }
+
+ if (vbo_nor) {
+ GPUPackedNormal vnor = GPU_normal_convert_i10_s3(mv->no);
+ GPU_vertbuf_attr_set(vbo_nor, vnor_id, base_vert_idx, &vnor);
+ }
+
+ if (vbo_data) {
+ uchar vflag[4] = {0, 0, 0, 0};
+ vflag[0] = mesh_render_data_vertex_flag(rdata, eve);
+ GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx, vflag);
+ }
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Vertex Group Selection
+ * \{ */
+
+/** Reset the selection structure, deallocating heap memory as appropriate. */
+void DRW_mesh_weight_state_clear(struct DRW_MeshWeightState *wstate)
+{
+ MEM_SAFE_FREE(wstate->defgroup_sel);
+
+ memset(wstate, 0, sizeof(*wstate));
+
+ wstate->defgroup_active = -1;
+}
+
+/** Copy selection data from one structure to another, including heap memory. */
+void DRW_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst, const struct DRW_MeshWeightState *wstate_src)
+{
+ MEM_SAFE_FREE(wstate_dst->defgroup_sel);
+
+ memcpy(wstate_dst, wstate_src, sizeof(*wstate_dst));
+
+ if (wstate_src->defgroup_sel) {
+ wstate_dst->defgroup_sel = MEM_dupallocN(wstate_src->defgroup_sel);
+ }
+}
+
+/** Compare two selection structures. */
+bool DRW_mesh_weight_state_compare(const struct DRW_MeshWeightState *a, const struct DRW_MeshWeightState *b)
+{
+ return a->defgroup_active == b->defgroup_active &&
+ a->defgroup_len == b->defgroup_len &&
+ a->flags == b->flags &&
+ a->alert_mode == b->alert_mode &&
+ a->defgroup_sel_count == b->defgroup_sel_count &&
+ ((!a->defgroup_sel && !b->defgroup_sel) ||
+ (a->defgroup_sel && b->defgroup_sel &&
+ memcmp(a->defgroup_sel, b->defgroup_sel, a->defgroup_len * sizeof(bool)) == 0));
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Mesh GPUBatch Cache
+ * \{ */
+
+typedef struct MeshBatchCache {
+ GPUVertBuf *pos_in_order;
+ GPUIndexBuf *edges_in_order;
+ GPUIndexBuf *edges_adjacency; /* Store edges with adjacent vertices. */
+ GPUIndexBuf *triangles_in_order;
+ GPUIndexBuf *ledges_in_order;
+
+ GPUTexture *pos_in_order_tx; /* Depending on pos_in_order */
+
+ GPUBatch *all_verts;
+ GPUBatch *all_edges;
+ GPUBatch *all_triangles;
+
+ GPUVertBuf *pos_with_normals;
+ GPUVertBuf *pos_with_normals_visible_only;
+ GPUVertBuf *tri_aligned_uv; /* Active UV layer (mloopuv) */
+
+ /**
+ * Other uses are all positions or loose elements.
+ * This stores all visible elements, needed for selection.
+ */
+ GPUVertBuf *ed_fcenter_pos_with_nor_and_sel;
+ GPUVertBuf *ed_edge_pos;
+ GPUVertBuf *ed_vert_pos;
+
+ GPUBatch *triangles_with_normals;
+ GPUBatch *ledges_with_normals;
+
+ /* Skip hidden (depending on paint select mode) */
+ GPUBatch *triangles_with_weights;
+ GPUBatch *triangles_with_vert_colors;
+ /* Always skip hidden */
+ GPUBatch *triangles_with_select_mask;
+ GPUBatch *triangles_with_select_id;
+ uint triangles_with_select_id_offset;
+
+ GPUBatch *facedot_with_select_id; /* shares vbo with 'overlay_facedots' */
+ GPUBatch *edges_with_select_id;
+ GPUBatch *verts_with_select_id;
+
+ uint facedot_with_select_id_offset;
+ uint edges_with_select_id_offset;
+ uint verts_with_select_id_offset;
+
+ GPUBatch *points_with_normals;
+ GPUBatch *fancy_edges; /* owns its vertex buffer (not shared) */
+
+ GPUBatch *edge_detection;
+
+ GPUVertBuf *edges_face_overlay;
+ GPUTexture *edges_face_overlay_tx;
+ int edges_face_overlay_tri_count; /* Number of tri in edges_face_overlay(_adj)_tx */
+
+ /* Maybe have shaded_triangles_data split into pos_nor and uv_tangent
+ * to minimize data transfer for skinned mesh. */
+ GPUVertFormat shaded_triangles_format;
+ GPUVertBuf *shaded_triangles_data;
+ GPUIndexBuf **shaded_triangles_in_order;
+ GPUBatch **shaded_triangles;
+
+ /* Texture Paint.*/
+ /* per-texture batch */
+ GPUBatch **texpaint_triangles;
+ GPUBatch *texpaint_triangles_single;
+
+ /* Edit Cage Mesh buffers */
+ GPUVertBuf *ed_tri_pos;
+ GPUVertBuf *ed_tri_nor; /* LoopNor, VertNor */
+ GPUVertBuf *ed_tri_data;
+ GPUTexture *ed_tri_data_tx;
+ GPUIndexBuf *ed_tri_verts;
+
+ GPUVertBuf *ed_ledge_pos;
+ GPUVertBuf *ed_ledge_nor; /* VertNor */
+ GPUVertBuf *ed_ledge_data;
+
+ GPUVertBuf *ed_lvert_pos;
+ GPUVertBuf *ed_lvert_nor; /* VertNor */
+ GPUVertBuf *ed_lvert_data;
+
+ GPUBatch *overlay_triangles;
+ GPUBatch *overlay_triangles_nor; /* GPU_PRIM_POINTS */
+ GPUBatch *overlay_triangles_lnor; /* GPU_PRIM_POINTS */
+ GPUBatch *overlay_loose_edges;
+ GPUBatch *overlay_loose_edges_nor; /* GPU_PRIM_POINTS */
+ GPUBatch *overlay_loose_verts;
+ GPUBatch *overlay_facedots;
+
+ GPUBatch *overlay_weight_faces;
+ GPUBatch *overlay_weight_verts;
+ GPUBatch *overlay_paint_edges;
+
+ /* 2D/UV edit */
+ GPUVertBuf *edituv_pos;
+ GPUVertBuf *edituv_area;
+ GPUVertBuf *edituv_angle;
+ GPUVertBuf *edituv_data;
+
+ GPUIndexBuf *edituv_visible_faces;
+ GPUIndexBuf *edituv_visible_edges;
+
+ GPUBatch *texpaint_uv_loops;
+
+ GPUBatch *edituv_faces_strech_area;
+ GPUBatch *edituv_faces_strech_angle;
+ GPUBatch *edituv_faces;
+ GPUBatch *edituv_edges;
+ GPUBatch *edituv_verts;
+ GPUBatch *edituv_facedots;
+
+ char edituv_state;
+
+ /* arrays of bool uniform names (and value) that will be use to
+ * set srgb conversion for auto attribs.*/
+ char *auto_layer_names;
+ int *auto_layer_is_srgb;
+ int auto_layer_len;
+
+ /* settings to determine if cache is invalid */
+ bool is_maybe_dirty;
+ bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
+ int edge_len;
+ int tri_len;
+ int poly_len;
+ int vert_len;
+ int mat_len;
+ bool is_editmode;
+
+ struct DRW_MeshWeightState weight_state;
+
+ /* XXX, only keep for as long as sculpt mode uses shaded drawing. */
+ bool is_sculpt_points_tag;
+
+ /* Valid only if edges_adjacency is up to date. */
+ bool is_manifold;
+} MeshBatchCache;
+
+/* GPUBatch cache management. */
+
+static bool mesh_batch_cache_valid(Mesh *me)
+{
+ MeshBatchCache *cache = me->runtime.batch_cache;
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ /* XXX find another place for this */
+ if (cache->mat_len != mesh_render_mat_len_get(me)) {
+ cache->is_maybe_dirty = true;
+ }
+
+ if (cache->is_editmode != (me->edit_btmesh != NULL)) {
+ return false;
+ }
+
+ if (cache->is_dirty) {
+ return false;
+ }
+
+ if (cache->is_maybe_dirty == false) {
+ return true;
+ }
+ else {
+ if (cache->is_editmode) {
+ return false;
+ }
+ else if ((cache->vert_len != mesh_render_verts_len_get(me)) ||
+ (cache->edge_len != mesh_render_edges_len_get(me)) ||
+ (cache->tri_len != mesh_render_looptri_len_get(me)) ||
+ (cache->poly_len != mesh_render_polys_len_get(me)) ||
+ (cache->mat_len != mesh_render_mat_len_get(me)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void mesh_batch_cache_init(Mesh *me)
+{
+ MeshBatchCache *cache = me->runtime.batch_cache;
+
+ if (!cache) {
+ cache = me->runtime.batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+ cache->is_editmode = me->edit_btmesh != NULL;
+
+ if (cache->is_editmode == false) {
+ cache->edge_len = mesh_render_edges_len_get(me);
+ cache->tri_len = mesh_render_looptri_len_get(me);
+ cache->poly_len = mesh_render_polys_len_get(me);
+ cache->vert_len = mesh_render_verts_len_get(me);
+ }
+
+ cache->mat_len = mesh_render_mat_len_get(me);
+
+ cache->is_maybe_dirty = false;
+ cache->is_dirty = false;
+
+ DRW_mesh_weight_state_clear(&cache->weight_state);
+}
+
+static MeshBatchCache *mesh_batch_cache_get(Mesh *me)
+{
+ if (!mesh_batch_cache_valid(me)) {
+ mesh_batch_cache_clear(me);
+ mesh_batch_cache_init(me);
+ }
+ return me->runtime.batch_cache;
+}
+
+static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, const struct DRW_MeshWeightState *wstate)
+{
+ if (!DRW_mesh_weight_state_compare(&cache->weight_state, wstate)) {
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights);
+
+ DRW_mesh_weight_state_clear(&cache->weight_state);
+ }
+}
+
+static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->shaded_triangles_data);
+ if (cache->shaded_triangles_in_order) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_INDEXBUF_DISCARD_SAFE(cache->shaded_triangles_in_order[i]);
+ }
+ }
+ if (cache->shaded_triangles) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]);
+ }
+ }
+ if (cache->texpaint_triangles) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ /* They use shaded_triangles_in_order */
+ GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->shaded_triangles_in_order);
+ MEM_SAFE_FREE(cache->shaded_triangles);
+ MEM_SAFE_FREE(cache->texpaint_triangles);
+
+ MEM_SAFE_FREE(cache->auto_layer_names);
+ MEM_SAFE_FREE(cache->auto_layer_is_srgb);
+}
+
+static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->edituv_pos);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edituv_area);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edituv_angle);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edituv_data);
+
+ GPU_INDEXBUF_DISCARD_SAFE(cache->edituv_visible_faces);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->edituv_visible_edges);
+
+ if (cache->edituv_faces_strech_area) {
+ gpu_batch_presets_unregister(cache->edituv_faces_strech_area);
+ }
+ if (cache->edituv_faces_strech_angle) {
+ gpu_batch_presets_unregister(cache->edituv_faces_strech_angle);
+ }
+ if (cache->edituv_faces) {
+ gpu_batch_presets_unregister(cache->edituv_faces);
+ }
+ if (cache->edituv_edges) {
+ gpu_batch_presets_unregister(cache->edituv_edges);
+ }
+ if (cache->edituv_verts) {
+ gpu_batch_presets_unregister(cache->edituv_verts);
+ }
+ if (cache->edituv_facedots) {
+ gpu_batch_presets_unregister(cache->edituv_facedots);
+ }
+
+ GPU_BATCH_DISCARD_SAFE(cache->edituv_faces_strech_area);
+ GPU_BATCH_DISCARD_SAFE(cache->edituv_faces_strech_angle);
+ GPU_BATCH_DISCARD_SAFE(cache->edituv_faces);
+ GPU_BATCH_DISCARD_SAFE(cache->edituv_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->edituv_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->edituv_facedots);
+
+ gpu_batch_presets_unregister(cache->texpaint_uv_loops);
+
+ GPU_BATCH_DISCARD_SAFE(cache->texpaint_uv_loops);
+
+ cache->edituv_state = 0;
+}
+
+void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
+{
+ MeshBatchCache *cache = me->runtime.batch_cache;
+ if (cache == NULL) {
+ return;
+ }
+ switch (mode) {
+ case BKE_MESH_BATCH_DIRTY_MAYBE_ALL:
+ cache->is_maybe_dirty = true;
+ break;
+ case BKE_MESH_BATCH_DIRTY_SELECT:
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_tri_data);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_ledge_data);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_lvert_data);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_fcenter_pos_with_nor_and_sel); /* Contains select flag */
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_edge_pos);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_vert_pos);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->ed_tri_verts);
+ DRW_TEXTURE_FREE_SAFE(cache->ed_tri_data_tx);
+
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_facedots);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles_nor);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles_lnor);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_edges_nor);
+ /* Edit mode selection. */
+ GPU_BATCH_DISCARD_SAFE(cache->facedot_with_select_id);
+ GPU_BATCH_DISCARD_SAFE(cache->edges_with_select_id);
+ GPU_BATCH_DISCARD_SAFE(cache->verts_with_select_id);
+ /* Because visible UVs depends on edit mode selection, discard everything. */
+ mesh_batch_cache_discard_uvedit(cache);
+ break;
+ case BKE_MESH_BATCH_DIRTY_ALL:
+ cache->is_dirty = true;
+ break;
+ case BKE_MESH_BATCH_DIRTY_SHADING:
+ mesh_batch_cache_discard_shaded_tri(cache);
+ mesh_batch_cache_discard_uvedit(cache);
+ break;
+ case BKE_MESH_BATCH_DIRTY_SCULPT_COORDS:
+ cache->is_sculpt_points_tag = true;
+ break;
+ case BKE_MESH_BATCH_DIRTY_UVEDIT_ALL:
+ mesh_batch_cache_discard_uvedit(cache);
+ break;
+ case BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT:
+ /* For now same as above. */
+ mesh_batch_cache_discard_uvedit(cache);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+/**
+ * This only clear the batches associated to the given vertex buffer.
+ **/
+static void mesh_batch_cache_clear_selective(Mesh *me, GPUVertBuf *vert)
+{
+ MeshBatchCache *cache = me->runtime.batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ BLI_assert(vert != NULL);
+
+ if (ELEM(vert, cache->pos_with_normals, cache->pos_with_normals_visible_only)) {
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_normals);
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights);
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors);
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_select_id);
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_select_mask);
+ GPU_BATCH_DISCARD_SAFE(cache->points_with_normals);
+ GPU_BATCH_DISCARD_SAFE(cache->ledges_with_normals);
+ if (cache->shaded_triangles) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->shaded_triangles);
+ if (cache->texpaint_triangles) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->texpaint_triangles);
+ GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single);
+ }
+ /* TODO: add the other ones if needed. */
+ else {
+ /* Does not match any vertbuf in the batch cache! */
+ BLI_assert(0);
+ }
+}
+
+static void mesh_batch_cache_clear(Mesh *me)
+{
+ MeshBatchCache *cache = me->runtime.batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ GPU_BATCH_DISCARD_SAFE(cache->all_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->all_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->all_triangles);
+
+ GPU_VERTBUF_DISCARD_SAFE(cache->pos_in_order);
+ DRW_TEXTURE_FREE_SAFE(cache->pos_in_order_tx);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->edges_in_order);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->triangles_in_order);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->ledges_in_order);
+
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_tri_pos);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_tri_nor);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_tri_data);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_ledge_pos);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_ledge_nor);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_ledge_data);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_lvert_pos);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_lvert_nor);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_lvert_data);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->ed_tri_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles_nor);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_triangles_lnor);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_loose_edges_nor);
+ DRW_TEXTURE_FREE_SAFE(cache->ed_tri_data_tx);
+
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_weight_faces);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_weight_verts);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_paint_edges);
+ GPU_BATCH_DISCARD_SAFE(cache->overlay_facedots);
+
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_normals);
+ GPU_BATCH_DISCARD_SAFE(cache->points_with_normals);
+ GPU_BATCH_DISCARD_SAFE(cache->ledges_with_normals);
+ GPU_VERTBUF_DISCARD_SAFE(cache->pos_with_normals);
+ GPU_VERTBUF_DISCARD_SAFE(cache->pos_with_normals_visible_only);
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights);
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors);
+ GPU_VERTBUF_DISCARD_SAFE(cache->tri_aligned_uv);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_fcenter_pos_with_nor_and_sel);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_edge_pos);
+ GPU_VERTBUF_DISCARD_SAFE(cache->ed_vert_pos);
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_select_mask);
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_select_id);
+ GPU_BATCH_DISCARD_SAFE(cache->facedot_with_select_id);
+ GPU_BATCH_DISCARD_SAFE(cache->edges_with_select_id);
+ GPU_BATCH_DISCARD_SAFE(cache->verts_with_select_id);
+
+ GPU_BATCH_DISCARD_SAFE(cache->fancy_edges);
+
+ GPU_INDEXBUF_DISCARD_SAFE(cache->edges_adjacency);
+ GPU_BATCH_DISCARD_SAFE(cache->edge_detection);
+
+ GPU_VERTBUF_DISCARD_SAFE(cache->edges_face_overlay);
+ DRW_TEXTURE_FREE_SAFE(cache->edges_face_overlay_tx);
+
+ mesh_batch_cache_discard_shaded_tri(cache);
+
+ mesh_batch_cache_discard_uvedit(cache);
+
+ if (cache->texpaint_triangles) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]);
+ }
+ }
+ MEM_SAFE_FREE(cache->texpaint_triangles);
+
+ GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single);
+
+ DRW_mesh_weight_state_clear(&cache->weight_state);
+}
+
+void DRW_mesh_batch_cache_free(Mesh *me)
+{
+ mesh_batch_cache_clear(me);
+ MEM_SAFE_FREE(me->runtime.batch_cache);
+}
+
+/* GPUBatch cache usage. */
+
+static GPUVertBuf *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (cache->shaded_triangles_data == NULL) {
+ const uint uv_len = rdata->cd.layers.uv_len;
+ const uint tangent_len = rdata->cd.layers.tangent_len;
+ const uint vcol_len = rdata->cd.layers.vcol_len;
+ const uint layers_combined_len = uv_len + vcol_len + tangent_len;
+ cache->auto_layer_len = 0;
+
+ if (layers_combined_len == 0) {
+ return NULL;
+ }
+
+ GPUVertFormat *format = &cache->shaded_triangles_format;
+
+ GPU_vertformat_clear(format);
+
+ /* initialize vertex format */
+ uint *layers_combined_id = BLI_array_alloca(layers_combined_id, layers_combined_len);
+ uint *uv_id = layers_combined_id;
+ uint *tangent_id = uv_id + uv_len;
+ uint *vcol_id = tangent_id + tangent_len;
+
+ /* Not needed, just for sanity. */
+ if (uv_len == 0) { uv_id = NULL; }
+ if (tangent_len == 0) { tangent_id = NULL; }
+ if (vcol_len == 0) { vcol_id = NULL; }
+
+ /* Count number of auto layer and allocate big enough name buffer. */
+ uint auto_names_len = 0;
+ uint auto_ofs = 0;
+ uint auto_id = 0;
+ for (uint i = 0; i < uv_len; i++) {
+ const char *attrib_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i);
+ auto_names_len += strlen(attrib_name) + 2; /* include null terminator and b prefix. */
+ cache->auto_layer_len++;
+ }
+ for (uint i = 0; i < vcol_len; i++) {
+ if (rdata->cd.layers.auto_vcol[i]) {
+ const char *attrib_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i);
+ auto_names_len += strlen(attrib_name) + 2; /* include null terminator and b prefix. */
+ cache->auto_layer_len++;
+ }
+ }
+ auto_names_len += 1; /* add an ultimate '\0' terminator */
+ cache->auto_layer_names = MEM_callocN(auto_names_len * sizeof(char), "Auto layer name buf");
+ cache->auto_layer_is_srgb = MEM_mallocN(cache->auto_layer_len * sizeof(int), "Auto layer value buf");
+
+#define USE_COMP_MESH_DATA
+
+ for (uint i = 0; i < uv_len; i++) {
+ /* UV */
+ const char *attrib_name = mesh_render_data_uv_layer_uuid_get(rdata, i);
+#if defined(USE_COMP_MESH_DATA) && 0 /* these are clamped. Maybe use them as an option in the future */
+ uv_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
+#else
+ uv_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+#endif
+
+ /* Auto Name */
+ attrib_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i);
+ GPU_vertformat_alias_add(format, attrib_name);
+
+ /* +1 include null terminator. */
+ auto_ofs += 1 + BLI_snprintf_rlen(
+ cache->auto_layer_names + auto_ofs, auto_names_len - auto_ofs, "b%s", attrib_name);
+ cache->auto_layer_is_srgb[auto_id++] = 0; /* tag as not srgb */
+
+ if (i == rdata->cd.layers.uv_active) {
+ GPU_vertformat_alias_add(format, "u");
+ }
+ }
+
+ for (uint i = 0; i < tangent_len; i++) {
+ const char *attrib_name = mesh_render_data_tangent_layer_uuid_get(rdata, i);
+#ifdef USE_COMP_MESH_DATA
+ /* Tangents need more precision than 10_10_10 */
+ tangent_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+#else
+ tangent_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+#endif
+
+ if (i == rdata->cd.layers.tangent_active) {
+ GPU_vertformat_alias_add(format, "t");
+ }
+ }
+
+ for (uint i = 0; i < vcol_len; i++) {
+ const char *attrib_name = mesh_render_data_vcol_layer_uuid_get(rdata, i);
+ vcol_id[i] = GPU_vertformat_attr_add(format, attrib_name, GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ /* Auto layer */
+ if (rdata->cd.layers.auto_vcol[i]) {
+ attrib_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i);
+
+ GPU_vertformat_alias_add(format, attrib_name);
+
+ /* +1 include null terminator. */
+ auto_ofs += 1 + BLI_snprintf_rlen(
+ cache->auto_layer_names + auto_ofs, auto_names_len - auto_ofs, "b%s", attrib_name);
+ cache->auto_layer_is_srgb[auto_id++] = 1; /* tag as srgb */
+ }
+
+ if (i == rdata->cd.layers.vcol_active) {
+ GPU_vertformat_alias_add(format, "c");
+ }
+ }
+
+ const uint tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ GPUVertBuf *vbo = cache->shaded_triangles_data = GPU_vertbuf_create_with_format(format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ GPUVertBufRaw *layers_combined_step = BLI_array_alloca(layers_combined_step, layers_combined_len);
+
+ GPUVertBufRaw *uv_step = layers_combined_step;
+ GPUVertBufRaw *tangent_step = uv_step + uv_len;
+ GPUVertBufRaw *vcol_step = tangent_step + tangent_len;
+
+ /* Not needed, just for sanity. */
+ if (uv_len == 0) { uv_step = NULL; }
+ if (tangent_len == 0) { tangent_step = NULL; }
+ if (vcol_len == 0) { vcol_step = NULL; }
+
+ for (uint i = 0; i < uv_len; i++) {
+ GPU_vertbuf_attr_get_raw_data(vbo, uv_id[i], &uv_step[i]);
+ }
+ for (uint i = 0; i < tangent_len; i++) {
+ GPU_vertbuf_attr_get_raw_data(vbo, tangent_id[i], &tangent_step[i]);
+ }
+ for (uint i = 0; i < vcol_len; i++) {
+ GPU_vertbuf_attr_get_raw_data(vbo, vcol_id[i], &vcol_step[i]);
+ }
+
+ /* TODO deduplicate all verts and make use of GPUIndexBuf in
+ * mesh_batch_cache_get_triangles_in_order_split_by_material. */
+ if (rdata->edit_bmesh) {
+ for (uint i = 0; i < tri_len; i++) {
+ const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ /* UVs */
+ for (uint j = 0; j < uv_len; j++) {
+ const uint layer_offset = rdata->cd.offset.uv[j];
+ for (uint t = 0; t < 3; t++) {
+ const float *elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(bm_looptri[t], layer_offset))->uv;
+ copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem);
+ }
+ }
+ /* TANGENTs */
+ for (uint j = 0; j < tangent_len; j++) {
+ float (*layer_data)[4] = rdata->cd.layers.tangent[j];
+ for (uint t = 0; t < 3; t++) {
+ const float *elem = layer_data[BM_elem_index_get(bm_looptri[t])];
+#ifdef USE_COMP_MESH_DATA
+ normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
+#else
+ copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
+#endif
+ }
+ }
+ /* VCOLs */
+ for (uint j = 0; j < vcol_len; j++) {
+ const uint layer_offset = rdata->cd.offset.vcol[j];
+ for (uint t = 0; t < 3; t++) {
+ const uchar *elem = &((MLoopCol *)BM_ELEM_CD_GET_VOID_P(bm_looptri[t], layer_offset))->r;
+ copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
+ }
+ }
+ }
+ }
+ else {
+ for (uint i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+
+ /* UVs */
+ for (uint j = 0; j < uv_len; j++) {
+ const MLoopUV *layer_data = rdata->cd.layers.uv[j];
+ for (uint t = 0; t < 3; t++) {
+ const float *elem = layer_data[mlt->tri[t]].uv;
+ copy_v2_v2(GPU_vertbuf_raw_step(&uv_step[j]), elem);
+ }
+ }
+ /* TANGENTs */
+ for (uint j = 0; j < tangent_len; j++) {
+ float (*layer_data)[4] = rdata->cd.layers.tangent[j];
+ for (uint t = 0; t < 3; t++) {
+ const float *elem = layer_data[mlt->tri[t]];
+#ifdef USE_COMP_MESH_DATA
+ normal_float_to_short_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
+#else
+ copy_v4_v4(GPU_vertbuf_raw_step(&tangent_step[j]), elem);
+#endif
+ }
+ }
+ /* VCOLs */
+ for (uint j = 0; j < vcol_len; j++) {
+ const MLoopCol *layer_data = rdata->cd.layers.vcol[j];
+ for (uint t = 0; t < 3; t++) {
+ const uchar *elem = &layer_data[mlt->tri[t]].r;
+ copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
+ }
+ }
+ }
+ }
+
+ vbo_len_used = GPU_vertbuf_raw_used(&layers_combined_step[0]);
+
+#ifndef NDEBUG
+ /* Check all layers are write aligned. */
+ if (layers_combined_len > 1) {
+ for (uint i = 1; i < layers_combined_len; i++) {
+ BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&layers_combined_step[i]));
+ }
+ }
+#endif
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+#undef USE_COMP_MESH_DATA
+
+ return cache->shaded_triangles_data;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_tri_uv_active(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPUV));
+
+
+ if (cache->tri_aligned_uv == NULL) {
+ const MLoopUV *mloopuv = rdata->mloopuv;
+ if (mloopuv == NULL) {
+ return NULL;
+ }
+
+ uint vidx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint uv; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.uv = GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ GPUVertBuf *vbo = cache->tri_aligned_uv = GPU_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+
+ BMEditMesh *embm = rdata->edit_bmesh;
+ /* get uv's from active UVMap */
+ if (rdata->edit_bmesh) {
+ /* edit mode */
+ BMesh *bm = embm->bm;
+
+ const int layer_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ for (uint i = 0; i < tri_len; i++) {
+ const BMLoop **bm_looptri = (const BMLoop **)embm->looptris[i];
+ if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ for (uint t = 0; t < 3; t++) {
+ const BMLoop *loop = bm_looptri[t];
+ const int index = BM_elem_index_get(loop);
+ if (index != -1) {
+ const float *elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->uv;
+ GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, elem);
+ }
+ }
+ }
+ }
+ else {
+ /* object mode */
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+ GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[0]].uv);
+ GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[1]].uv);
+ GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[2]].uv);
+ }
+ }
+
+ vbo_len_used = vidx;
+
+ BLI_assert(vbo_len_capacity == vbo_len_used);
+ UNUSED_VARS_NDEBUG(vbo_len_used);
+ }
+
+ return cache->tri_aligned_uv;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_tri_pos_and_normals_ex(
+ MeshRenderData *rdata, const bool use_hide,
+ GPUVertBuf **r_vbo)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (*r_vbo == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata);
+
+ GPUVertBuf *vbo = *r_vbo = GPU_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ GPUVertBufRaw pos_step, nor_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(vbo, attr_id.nor, &nor_step);
+
+ if (rdata->mapped.use == false) {
+ float (*lnors)[3] = rdata->loop_normals;
+ if (rdata->edit_bmesh) {
+ GPUPackedNormal *pnors_pack, *vnors_pack;
+
+ if (lnors == NULL) {
+ mesh_render_data_ensure_poly_normals_pack(rdata);
+ mesh_render_data_ensure_vert_normals_pack(rdata);
+
+ pnors_pack = rdata->poly_normals_pack;
+ vnors_pack = rdata->vert_normals_pack;
+ }
+
+ for (int i = 0; i < tri_len; i++) {
+ const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ const BMFace *bm_face = bm_looptri[0]->f;
+
+ /* use_hide always for edit-mode */
+ if (BM_elem_flag_test(bm_face, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+
+ if (lnors) {
+ for (uint t = 0; t < 3; t++) {
+ const float *nor = lnors[BM_elem_index_get(bm_looptri[t])];
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_v3(nor);
+ }
+ }
+ else if (BM_elem_flag_test(bm_face, BM_ELEM_SMOOTH)) {
+ for (uint t = 0; t < 3; t++) {
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = vnors_pack[BM_elem_index_get(bm_looptri[t]->v)];
+ }
+ }
+ else {
+ const GPUPackedNormal *snor_pack = &pnors_pack[BM_elem_index_get(bm_face)];
+ for (uint t = 0; t < 3; t++) {
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = *snor_pack;
+ }
+ }
+
+ /* TODO(sybren): deduplicate this and all the other places it's pasted to in this file. */
+ if (rdata->edit_data && rdata->edit_data->vertexCos) {
+ for (uint t = 0; t < 3; t++) {
+ int vidx = BM_elem_index_get(bm_looptri[t]->v);
+ const float *pos = rdata->edit_data->vertexCos[vidx];
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), pos);
+ }
+ }
+ else {
+ for (uint t = 0; t < 3; t++) {
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), bm_looptri[t]->v->co);
+ }
+ }
+ }
+ }
+ else {
+ if (lnors == NULL) {
+ /* Use normals from vertex. */
+ mesh_render_data_ensure_poly_normals_pack(rdata);
+ }
+
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+ const MPoly *mp = &rdata->mpoly[mlt->poly];
+
+ if (use_hide && (mp->flag & ME_HIDE)) {
+ continue;
+ }
+
+ const uint vtri[3] = {
+ rdata->mloop[mlt->tri[0]].v,
+ rdata->mloop[mlt->tri[1]].v,
+ rdata->mloop[mlt->tri[2]].v,
+ };
+
+ if (lnors) {
+ for (uint t = 0; t < 3; t++) {
+ const float *nor = lnors[mlt->tri[t]];
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_v3(nor);
+ }
+ }
+ else if (mp->flag & ME_SMOOTH) {
+ for (uint t = 0; t < 3; t++) {
+ const MVert *mv = &rdata->mvert[vtri[t]];
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_s3(mv->no);
+ }
+ }
+ else {
+ const GPUPackedNormal *pnors_pack = &rdata->poly_normals_pack[mlt->poly];
+ for (uint t = 0; t < 3; t++) {
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = *pnors_pack;
+ }
+ }
+
+ for (uint t = 0; t < 3; t++) {
+ const MVert *mv = &rdata->mvert[vtri[t]];
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mv->co);
+ }
+ }
+ }
+ }
+ else {
+ /* Note: mapped doesn't support lnors yet. */
+ BMesh *bm = rdata->edit_bmesh->bm;
+ Mesh *me_cage = rdata->mapped.me_cage;
+
+ /* TODO(campbell): unlike non-mapped modes we don't generate these on demand, just use if they exist.
+ * this seems like a low priority TODO since mapped meshes typically
+ * use the final mesh evaluated mesh for showing faces. */
+ const float (*lnors)[3] = CustomData_get_layer(&me_cage->ldata, CD_NORMAL);
+
+ /* TODO(campbell): this is quite an expensive operation for something
+ * that's not used unless 'normal' display option is enabled. */
+ if (!CustomData_has_layer(&me_cage->pdata, CD_NORMAL)) {
+ /* TODO(campbell): this is quite an expensive operation for something
+ * that's not used unless 'normal' display option is enabled. */
+ BKE_mesh_ensure_normals_for_display(me_cage);
+ }
+ const float (*polynors)[3] = CustomData_get_layer(&me_cage->pdata, CD_NORMAL);
+
+ const MVert *mvert = rdata->mapped.me_cage->mvert;
+ const MLoop *mloop = rdata->mapped.me_cage->mloop;
+ const MPoly *mpoly = rdata->mapped.me_cage->mpoly;
+
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &mlooptri[i];
+ const int p_orig = rdata->mapped.p_origindex[mlt->poly];
+ if (p_orig != ORIGINDEX_NONE) {
+ /* Assume 'use_hide' */
+ BMFace *efa = BM_face_at_index(bm, p_orig);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ const MPoly *mp = &mpoly[mlt->poly];
+ const uint vtri[3] = {
+ mloop[mlt->tri[0]].v,
+ mloop[mlt->tri[1]].v,
+ mloop[mlt->tri[2]].v,
+ };
+
+ if (lnors) {
+ for (uint t = 0; t < 3; t++) {
+ const float *nor = lnors[mlt->tri[t]];
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_v3(nor);
+ }
+ }
+ else if (mp->flag & ME_SMOOTH) {
+ for (uint t = 0; t < 3; t++) {
+ const MVert *mv = &mvert[vtri[t]];
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = GPU_normal_convert_i10_s3(mv->no);
+ }
+ }
+ else {
+ /* we don't have cached 'rdata->poly_normals_pack'. */
+ const GPUPackedNormal pnor = GPU_normal_convert_i10_v3(polynors[mlt->poly]);
+ for (uint t = 0; t < 3; t++) {
+ *((GPUPackedNormal *)GPU_vertbuf_raw_step(&nor_step)) = pnor;
+ }
+ }
+
+ for (uint t = 0; t < 3; t++) {
+ const MVert *mv = &mvert[vtri[t]];
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mv->co);
+ }
+ }
+ }
+ }
+ }
+
+ vbo_len_used = GPU_vertbuf_raw_used(&pos_step);
+ BLI_assert(vbo_len_used == GPU_vertbuf_raw_used(&nor_step));
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+ return *r_vbo;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_tri_pos_and_normals(
+ MeshRenderData *rdata, MeshBatchCache *cache, bool use_hide)
+{
+ return mesh_batch_cache_get_tri_pos_and_normals_ex(
+ rdata, use_hide,
+ use_hide ? &cache->pos_with_normals_visible_only : &cache->pos_with_normals);
+}
+
+static GPUVertBuf *mesh_batch_cache_get_facedot_pos_with_normals_and_flag(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ if (cache->ed_fcenter_pos_with_nor_and_sel == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.data = GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ const int vbo_len_capacity = mesh_render_data_polys_len_get_maybe_mapped(rdata);
+ int vidx = 0;
+
+ GPUVertBuf *vbo = cache->ed_fcenter_pos_with_nor_and_sel = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ if (rdata->edit_bmesh) {
+ if (rdata->edit_data && rdata->edit_data->vertexCos != NULL) {
+ BKE_editmesh_cache_ensure_poly_normals(rdata->edit_bmesh, rdata->edit_data);
+ BKE_editmesh_cache_ensure_poly_centers(rdata->edit_bmesh, rdata->edit_data);
+ }
+ }
+
+ if (rdata->mapped.use == false) {
+ for (int i = 0; i < vbo_len_capacity; i++) {
+ float pcenter[3], pnor[3];
+ bool selected = false;
+ if (mesh_render_data_pnors_pcenter_select_get(rdata, i, pnor, pcenter, &selected)) {
+ GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor);
+ nor.w = selected ? 1 : 0;
+ GPU_vertbuf_attr_set(vbo, attr_id.data, vidx, &nor);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, pcenter);
+ vidx += 1;
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < vbo_len_capacity; i++) {
+ float pcenter[3], pnor[3];
+ bool selected = false;
+ if (mesh_render_data_pnors_pcenter_select_get_mapped(rdata, i, pnor, pcenter, &selected)) {
+ GPUPackedNormal nor = GPU_normal_convert_i10_v3(pnor);
+ nor.w = selected ? 1 : 0;
+ GPU_vertbuf_attr_set(vbo, attr_id.data, vidx, &nor);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, pcenter);
+ vidx += 1;
+ }
+ }
+ }
+ const int vbo_len_used = vidx;
+ BLI_assert(vbo_len_used <= vbo_len_capacity);
+ if (vbo_len_used != vbo_len_capacity) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return cache->ed_fcenter_pos_with_nor_and_sel;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_edges_visible(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE));
+
+ if (cache->ed_edge_pos == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ const int vbo_len_capacity = mesh_render_data_edges_len_get_maybe_mapped(rdata) * 2;
+ int vidx = 0;
+
+ GPUVertBuf *vbo = cache->ed_edge_pos = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ if (rdata->mapped.use == false) {
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter iter;
+ BMEdge *eed;
+
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, eed->v1->co);
+ vidx += 1;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, eed->v2->co);
+ vidx += 1;
+ }
+ }
+ }
+ else {
+ /* not yet done! */
+ BLI_assert(0);
+ }
+ }
+ else {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ const MVert *mvert = rdata->mapped.me_cage->mvert;
+ const MEdge *medge = rdata->mapped.me_cage->medge;
+ const int *e_origindex = rdata->mapped.e_origindex;
+ for (int i = 0; i < rdata->mapped.edge_len; i++) {
+ const int e_orig = e_origindex[i];
+ if (e_orig != ORIGINDEX_NONE) {
+ BMEdge *eed = BM_edge_at_index(bm, e_orig);
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ const MEdge *ed = &medge[i];
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, mvert[ed->v1].co);
+ vidx += 1;
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, mvert[ed->v2].co);
+ vidx += 1;
+ }
+ }
+ }
+ }
+ const int vbo_len_used = vidx;
+ if (vbo_len_used != vbo_len_capacity) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ UNUSED_VARS_NDEBUG(vbo_len_used);
+ }
+
+ return cache->ed_edge_pos;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_verts_visible(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_vert_pos == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, data; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+
+ const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata);
+ uint vidx = 0;
+
+ GPUVertBuf *vbo = cache->ed_vert_pos = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ if (rdata->mapped.use == false) {
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter iter;
+ BMVert *eve;
+
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, eve->co);
+ vidx += 1;
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < vbo_len_capacity; i++) {
+ const MVert *mv = &rdata->mvert[i];
+ if (!(mv->flag & ME_HIDE)) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, mv->co);
+ vidx += 1;
+ }
+ }
+ }
+ }
+ else {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ const MVert *mvert = rdata->mapped.me_cage->mvert;
+ const int *v_origindex = rdata->mapped.v_origindex;
+ for (int i = 0; i < vbo_len_capacity; i++) {
+ const int v_orig = v_origindex[i];
+ if (v_orig != ORIGINDEX_NONE) {
+ BMVert *eve = BM_vert_at_index(bm, v_orig);
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ const MVert *mv = &mvert[i];
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx, mv->co);
+ vidx += 1;
+ }
+ }
+ }
+ }
+ const uint vbo_len_used = vidx;
+ if (vbo_len_used != vbo_len_capacity) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+
+ UNUSED_VARS_NDEBUG(vbo_len_used);
+ }
+
+ return cache->ed_vert_pos;
+}
+
+static GPUVertBuf *mesh_create_facedot_select_id(
+ MeshRenderData *rdata, uint select_id_offset)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ GPUVertBuf *vbo;
+ {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, col; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+
+ const int vbo_len_capacity = mesh_render_data_polys_len_get(rdata);
+ int vidx = 0;
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ uint select_index = select_id_offset;
+
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter iter;
+ BMEdge *efa;
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ int select_id;
+ GPU_select_index_get(select_index, &select_id);
+ GPU_vertbuf_attr_set(vbo, attr_id.col, vidx, &select_id);
+ vidx += 1;
+ }
+ select_index += 1;
+ }
+ }
+ else {
+ /* not yet done! */
+ BLI_assert(0);
+ }
+ const int vbo_len_used = vidx;
+ if (vbo_len_used != vbo_len_capacity) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return vbo;
+}
+
+static GPUVertBuf *mesh_create_edges_select_id(
+ MeshRenderData *rdata, uint select_id_offset)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE));
+
+ GPUVertBuf *vbo;
+ {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, col; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+
+ const int vbo_len_capacity = mesh_render_data_edges_len_get_maybe_mapped(rdata) * 2;
+ int vidx = 0;
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ if (rdata->mapped.use == false) {
+ uint select_index = select_id_offset;
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter iter;
+ BMEdge *eed;
+
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ int select_id;
+ GPU_select_index_get(select_index, &select_id);
+ GPU_vertbuf_attr_set(vbo, attr_id.col, vidx, &select_id);
+ vidx += 1;
+ GPU_vertbuf_attr_set(vbo, attr_id.col, vidx, &select_id);
+ vidx += 1;
+ }
+ select_index += 1;
+ }
+ }
+ else {
+ /* not yet done! */
+ BLI_assert(0);
+ }
+ }
+ else {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ const int *e_origindex = rdata->mapped.e_origindex;
+ for (int i = 0; i < rdata->mapped.edge_len; i++) {
+ const int e_orig = e_origindex[i];
+ if (e_orig != ORIGINDEX_NONE) {
+ BMEdge *eed = BM_edge_at_index(bm, e_orig);
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ uint select_index = select_id_offset + e_orig;
+ int select_id;
+ GPU_select_index_get(select_index, &select_id);
+ GPU_vertbuf_attr_set(vbo, attr_id.col, vidx, &select_id);
+ vidx += 1;
+ GPU_vertbuf_attr_set(vbo, attr_id.col, vidx, &select_id);
+ vidx += 1;
+ }
+ }
+ }
+ }
+ const int vbo_len_used = vidx;
+ if (vbo_len_used != vbo_len_capacity) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return vbo;
+}
+
+static GPUVertBuf *mesh_create_verts_select_id(
+ MeshRenderData *rdata, uint select_id_offset)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ GPUVertBuf *vbo;
+ {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, col; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+
+ const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata);
+ int vidx = 0;
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ if (rdata->mapped.use == false) {
+ uint select_index = select_id_offset;
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter iter;
+ BMVert *eve;
+
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ int select_id;
+ GPU_select_index_get(select_index, &select_id);
+ GPU_vertbuf_attr_set(vbo, attr_id.col, vidx, &select_id);
+ vidx += 1;
+ }
+ select_index += 1;
+ }
+ }
+ else {
+ for (int i = 0; i < vbo_len_capacity; i++) {
+ const MVert *mv = &rdata->mvert[i];
+ if (!(mv->flag & ME_HIDE)) {
+ int select_id;
+ GPU_select_index_get(select_index, &select_id);
+ GPU_vertbuf_attr_set(vbo, attr_id.col, vidx, &select_id);
+ vidx += 1;
+ }
+ select_index += 1;
+ }
+ }
+ }
+ else {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ const int *v_origindex = rdata->mapped.v_origindex;
+ for (int i = 0; i < vbo_len_capacity; i++) {
+ const int v_orig = v_origindex[i];
+ if (v_orig != ORIGINDEX_NONE) {
+ BMVert *eve = BM_vert_at_index(bm, v_orig);
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ uint select_index = select_id_offset + v_orig;
+ int select_id;
+ GPU_select_index_get(select_index, &select_id);
+ GPU_vertbuf_attr_set(vbo, attr_id.col, vidx, &select_id);
+ vidx += 1;
+ }
+ }
+ }
+ }
+ const int vbo_len_used = vidx;
+ if (vbo_len_used != vbo_len_capacity) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return vbo;
+}
+
+static GPUVertBuf *mesh_create_tri_weights(
+ MeshRenderData *rdata, bool use_hide, const struct DRW_MeshWeightState *wstate)
+{
+ BLI_assert(
+ rdata->types &
+ (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT));
+
+ GPUVertBuf *vbo;
+ {
+ uint cidx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint weight; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.weight = GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ mesh_render_data_ensure_vert_weight(rdata, wstate);
+ const float (*vert_weight) = rdata->vert_weight;
+
+ if (rdata->edit_bmesh) {
+ for (int i = 0; i < tri_len; i++) {
+ const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ /* Assume 'use_hide' */
+ if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) {
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ const int v_index = BM_elem_index_get(ltri[tri_corner]->v);
+ GPU_vertbuf_attr_set(vbo, attr_id.weight, cidx++, &vert_weight[v_index]);
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+ if (!(use_hide && (rdata->mpoly[mlt->poly].flag & ME_HIDE))) {
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ const uint v_index = rdata->mloop[mlt->tri[tri_corner]].v;
+ GPU_vertbuf_attr_set(vbo, attr_id.weight, cidx++, &vert_weight[v_index]);
+ }
+ }
+ }
+ }
+ vbo_len_used = cidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return vbo;
+}
+
+static GPUVertBuf *mesh_create_tri_vert_colors(
+ MeshRenderData *rdata, bool use_hide)
+{
+ BLI_assert(
+ rdata->types &
+ (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPCOL));
+
+ GPUVertBuf *vbo;
+ {
+ uint cidx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint col; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+
+ const uint vbo_len_capacity = tri_len * 3;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ mesh_render_data_ensure_vert_color(rdata);
+ const char (*vert_color)[3] = rdata->vert_color;
+
+ if (rdata->edit_bmesh) {
+ for (int i = 0; i < tri_len; i++) {
+ const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ /* Assume 'use_hide' */
+ if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) {
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ const int l_index = BM_elem_index_get(ltri[tri_corner]);
+ GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, vert_color[l_index]);
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+ if (!(use_hide && (rdata->mpoly[mlt->poly].flag & ME_HIDE))) {
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ const uint l_index = mlt->tri[tri_corner];
+ GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, vert_color[l_index]);
+ }
+ }
+ }
+ }
+ const uint vbo_len_used = cidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return vbo;
+}
+
+static GPUVertBuf *mesh_create_tri_select_id(
+ MeshRenderData *rdata, bool use_hide, uint select_id_offset)
+{
+ BLI_assert(
+ rdata->types &
+ (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY));
+
+ GPUVertBuf *vbo;
+ {
+ uint cidx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint col; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+
+ const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata);
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+
+ if (rdata->mapped.use == false) {
+ if (rdata->edit_bmesh) {
+ for (int i = 0; i < tri_len; i++) {
+ const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ /* Assume 'use_hide' */
+ if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) {
+ const int poly_index = BM_elem_index_get(ltri[0]->f);
+ int select_id;
+ GPU_select_index_get(poly_index + select_id_offset, &select_id);
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, &select_id);
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+ const int poly_index = mlt->poly;
+ if (!(use_hide && (rdata->mpoly[poly_index].flag & ME_HIDE))) {
+ int select_id;
+ GPU_select_index_get(poly_index + select_id_offset, &select_id);
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, &select_id);
+ }
+ }
+ }
+ }
+ }
+ else {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ Mesh *me_cage = rdata->mapped.me_cage;
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &mlooptri[i];
+ const int p_orig = rdata->mapped.p_origindex[mlt->poly];
+ if (p_orig != ORIGINDEX_NONE) {
+ /* Assume 'use_hide' */
+ BMFace *efa = BM_face_at_index(bm, p_orig);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ int select_id;
+ GPU_select_index_get(select_id_offset + p_orig, &select_id);
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.col, cidx++, &select_id);
+ }
+ }
+ }
+ }
+ }
+ vbo_len_used = cidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+ return vbo;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_vert_pos_and_nor_in_order(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->pos_in_order == NULL) {
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, nor; } attr_id;
+ if (format.attr_len == 0) {
+ /* Normal is padded so that the vbo can be used as a buffer texture */
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+
+ GPUVertBuf *vbo = cache->pos_in_order = GPU_vertbuf_create_with_format(&format);
+ const int vbo_len_capacity = mesh_render_data_verts_len_get_maybe_mapped(rdata);
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ if (rdata->mapped.use == false) {
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter iter;
+ BMVert *eve;
+ uint i;
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ static short no_short[4];
+ normal_float_to_short_v3(no_short, eve->no);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, eve->co);
+ GPU_vertbuf_attr_set(vbo, attr_id.nor, i, no_short);
+ }
+ BLI_assert(i == vbo_len_capacity);
+ }
+ else {
+ for (int i = 0; i < vbo_len_capacity; i++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->mvert[i].co);
+ GPU_vertbuf_attr_set(vbo, attr_id.nor, i, rdata->mvert[i].no); /* XXX actually reading 4 shorts */
+ }
+ }
+ }
+ else {
+ const MVert *mvert = rdata->mapped.me_cage->mvert;
+ const int *v_origindex = rdata->mapped.v_origindex;
+ for (int i = 0; i < vbo_len_capacity; i++) {
+ const int v_orig = v_origindex[i];
+ if (v_orig != ORIGINDEX_NONE) {
+ const MVert *mv = &mvert[i];
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, i, mv->co);
+ GPU_vertbuf_attr_set(vbo, attr_id.nor, i, mv->no); /* XXX actually reading 4 shorts */
+ }
+ }
+ }
+ }
+
+ return cache->pos_in_order;
+}
+
+static GPUVertFormat *edit_mesh_overlay_pos_format(uint *r_pos_id)
+{
+ static GPUVertFormat format_pos = { 0 };
+ static uint pos_id;
+ if (format_pos.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ *r_pos_id = pos_id;
+ return &format_pos;
+}
+
+static GPUVertFormat *edit_mesh_overlay_nor_format(uint *r_vnor_id, uint *r_lnor_id)
+{
+ static GPUVertFormat format_nor = { 0 };
+ static GPUVertFormat format_nor_loop = { 0 };
+ static uint vnor_id, vnor_loop_id, lnor_id;
+ if (format_nor.attr_len == 0) {
+ vnor_id = GPU_vertformat_attr_add(&format_nor, "vnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ vnor_loop_id = GPU_vertformat_attr_add(&format_nor_loop, "vnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ lnor_id = GPU_vertformat_attr_add(&format_nor_loop, "lnor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ if (r_lnor_id) {
+ *r_vnor_id = vnor_loop_id;
+ *r_lnor_id = lnor_id;
+ return &format_nor_loop;
+ }
+ else {
+ *r_vnor_id = vnor_id;
+ return &format_nor;
+ }
+}
+
+static GPUVertFormat *edit_mesh_overlay_data_format(uint *r_data_id)
+{
+ static GPUVertFormat format_flag = { 0 };
+ static uint data_id;
+ if (format_flag.attr_len == 0) {
+ data_id = GPU_vertformat_attr_add(&format_flag, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ }
+ *r_data_id = data_id;
+ return &format_flag;
+}
+
+static void mesh_batch_cache_create_overlay_tri_buffers(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter iter;
+ BMVert *ev;
+ const int tri_len = mesh_render_data_looptri_len_get_maybe_mapped(rdata);
+
+ const int vbo_len_capacity = tri_len * 3;
+ int vbo_len_used = 0;
+ int points_len = bm->totvert;
+
+ /* Positions */
+ GPUVertBuf *vbo_pos = NULL;
+ static struct { uint pos, vnor, lnor, data; } attr_id;
+ if (cache->ed_tri_pos == NULL) {
+ vbo_pos = cache->ed_tri_pos =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos));
+ GPU_vertbuf_data_alloc(vbo_pos, vbo_len_capacity);
+ }
+
+ /* Normals */
+ GPUVertBuf *vbo_nor = NULL;
+ if (cache->ed_tri_nor == NULL) {
+ vbo_nor = cache->ed_tri_nor =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, &attr_id.lnor));
+ GPU_vertbuf_data_alloc(vbo_nor, vbo_len_capacity);
+ }
+
+ /* Data */
+ GPUVertBuf *vbo_data = NULL;
+ if (cache->ed_tri_data == NULL) {
+ vbo_data = cache->ed_tri_data =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data));
+ GPU_vertbuf_data_alloc(vbo_data, vbo_len_capacity);
+ }
+
+ /* Verts IBO */
+ GPUIndexBufBuilder elb, *elbp = NULL;
+ if (cache->ed_tri_verts == NULL) {
+ elbp = &elb;
+ GPU_indexbuf_init(elbp, GPU_PRIM_POINTS, points_len, vbo_len_capacity);
+ }
+
+ /* Clear tag */
+ BM_ITER_MESH(ev, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_disable(ev, BM_ELEM_TAG);
+ }
+
+ if (rdata->mapped.use == false) {
+ for (int i = 0; i < tri_len; i++) {
+ const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ if (!BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
+ add_overlay_tri(
+ rdata, vbo_pos, vbo_nor, vbo_data, elbp,
+ attr_id.pos, attr_id.vnor, attr_id.lnor, attr_id.data,
+ bm_looptri, vbo_len_used);
+ vbo_len_used += 3;
+ }
+ }
+ }
+ else {
+ Mesh *me_cage = rdata->mapped.me_cage;
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me_cage);
+ if (!CustomData_has_layer(&me_cage->pdata, CD_NORMAL)) {
+ /* TODO(campbell): this is quite an expensive operation for something
+ * that's not used unless 'normal' display option is enabled. */
+ BKE_mesh_ensure_normals_for_display(me_cage);
+ }
+ const float (*polynors)[3] = CustomData_get_layer(&me_cage->pdata, CD_NORMAL);
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &mlooptri[i];
+ const int p_orig = rdata->mapped.p_origindex[mlt->poly];
+ if (p_orig != ORIGINDEX_NONE) {
+ BMFace *efa = BM_face_at_index(bm, p_orig);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ add_overlay_tri_mapped(
+ rdata, vbo_pos, vbo_nor, vbo_data, elbp,
+ attr_id.pos, attr_id.vnor, attr_id.lnor, attr_id.data,
+ efa, mlt, polynors[mlt->poly], vbo_len_used);
+ vbo_len_used += 3;
+ }
+ }
+ }
+ }
+
+ if (elbp != NULL) {
+ cache->ed_tri_verts = GPU_indexbuf_build(elbp);
+ }
+
+ /* Finish */
+ if (vbo_len_used != vbo_len_capacity) {
+ if (vbo_pos != NULL) {
+ GPU_vertbuf_data_resize(vbo_pos, vbo_len_used);
+ }
+ if (vbo_nor != NULL) {
+ GPU_vertbuf_data_resize(vbo_nor, vbo_len_used);
+ }
+ if (vbo_data != NULL) {
+ GPU_vertbuf_data_resize(vbo_data, vbo_len_used);
+ }
+ }
+
+ /* Upload data early because we need to create the texture for it. */
+ GPU_vertbuf_use(vbo_data);
+ cache->ed_tri_data_tx = GPU_texture_create_from_vertbuf(vbo_data);
+}
+
+static void mesh_batch_cache_create_overlay_ledge_buffers(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
+
+ const int ledge_len = mesh_render_data_loose_edges_len_get_maybe_mapped(rdata);
+
+ const int vbo_len_capacity = ledge_len * 2;
+ int vbo_len_used = 0;
+
+ /* Positions */
+ GPUVertBuf *vbo_pos = NULL;
+ static struct { uint pos, vnor, data; } attr_id;
+ if (cache->ed_ledge_pos == NULL) {
+ vbo_pos = cache->ed_ledge_pos =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos));
+ GPU_vertbuf_data_alloc(vbo_pos, vbo_len_capacity);
+ }
+
+ /* Normals */
+ GPUVertBuf *vbo_nor = NULL;
+ if (cache->ed_ledge_nor == NULL) {
+ vbo_nor = cache->ed_ledge_nor =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, NULL));
+ GPU_vertbuf_data_alloc(vbo_nor, vbo_len_capacity);
+ }
+
+ /* Data */
+ GPUVertBuf *vbo_data = NULL;
+ if (cache->ed_ledge_data == NULL) {
+ vbo_data = cache->ed_ledge_data =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data));
+ GPU_vertbuf_data_alloc(vbo_data, vbo_len_capacity);
+ }
+
+ if (rdata->mapped.use == false) {
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ for (uint i = 0; i < ledge_len; i++) {
+ const BMEdge *eed = BM_edge_at_index(bm, rdata->loose_edges[i]);
+ add_overlay_loose_edge(
+ rdata, vbo_pos, vbo_nor, vbo_data,
+ attr_id.pos, attr_id.vnor, attr_id.data,
+ eed, vbo_len_used);
+ vbo_len_used += 2;
+ }
+ }
+ }
+ else {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ Mesh *me_cage = rdata->mapped.me_cage;
+ const MVert *mvert = me_cage->mvert;
+ const MEdge *medge = me_cage->medge;
+ const int *e_origindex = rdata->mapped.e_origindex;
+ for (uint i_iter = 0; i_iter < ledge_len; i_iter++) {
+ const int i = rdata->mapped.loose_edges[i_iter];
+ const int e_orig = e_origindex[i];
+ const MEdge *ed = &medge[i];
+ BMEdge *eed = BM_edge_at_index(bm, e_orig);
+ add_overlay_loose_edge_mapped(
+ rdata, vbo_pos, vbo_nor, vbo_data,
+ attr_id.pos, attr_id.vnor, attr_id.data,
+ eed, mvert, ed, vbo_len_used);
+ vbo_len_used += 2;
+ }
+ }
+
+ /* Finish */
+ if (vbo_len_used != vbo_len_capacity) {
+ if (vbo_pos != NULL) {
+ GPU_vertbuf_data_resize(vbo_pos, vbo_len_used);
+ }
+ if (vbo_nor != NULL) {
+ GPU_vertbuf_data_resize(vbo_nor, vbo_len_used);
+ }
+ if (vbo_data != NULL) {
+ GPU_vertbuf_data_resize(vbo_data, vbo_len_used);
+ }
+ }
+}
+
+static void mesh_batch_cache_create_overlay_lvert_buffers(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
+
+ BMesh *bm = rdata->edit_bmesh->bm;
+ const int lvert_len = mesh_render_data_loose_verts_len_get_maybe_mapped(rdata);
+
+ const int vbo_len_capacity = lvert_len;
+ int vbo_len_used = 0;
+
+ static struct { uint pos, vnor, data; } attr_id;
+
+ /* Positions */
+ GPUVertBuf *vbo_pos = NULL;
+ if (cache->ed_lvert_pos == NULL) {
+ vbo_pos = cache->ed_lvert_pos =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_pos_format(&attr_id.pos));
+ GPU_vertbuf_data_alloc(vbo_pos, vbo_len_capacity);
+ }
+
+ /* Normals */
+ GPUVertBuf *vbo_nor = NULL;
+ if (cache->ed_lvert_nor == NULL) {
+ vbo_nor = cache->ed_lvert_nor =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_nor_format(&attr_id.vnor, NULL));
+ GPU_vertbuf_data_alloc(vbo_nor, vbo_len_capacity);
+ }
+
+ /* Data */
+ GPUVertBuf *vbo_data = NULL;
+ if (cache->ed_lvert_data == NULL) {
+ vbo_data = cache->ed_lvert_data =
+ GPU_vertbuf_create_with_format(edit_mesh_overlay_data_format(&attr_id.data));
+ GPU_vertbuf_data_alloc(vbo_data, vbo_len_capacity);
+ }
+
+ if (rdata->mapped.use == false) {
+ for (uint i = 0; i < lvert_len; i++) {
+ BMVert *eve = BM_vert_at_index(bm, rdata->loose_verts[i]);
+ add_overlay_loose_vert(
+ rdata, vbo_pos, vbo_nor, vbo_data,
+ attr_id.pos, attr_id.vnor, attr_id.data,
+ eve, vbo_len_used);
+ vbo_len_used += 1;
+ }
+ }
+ else {
+ Mesh *me_cage = rdata->mapped.me_cage;
+ const MVert *mvert = me_cage->mvert;
+ const int *v_origindex = rdata->mapped.v_origindex;
+ for (uint i_iter = 0; i_iter < lvert_len; i_iter++) {
+ const int i = rdata->mapped.loose_verts[i_iter];
+ const int v_orig = v_origindex[i];
+ const MVert *mv = &mvert[i];
+ BMVert *eve = BM_vert_at_index(bm, v_orig);
+ add_overlay_loose_vert_mapped(
+ rdata, vbo_pos, vbo_nor, vbo_data,
+ attr_id.pos, attr_id.vnor, attr_id.data,
+ eve, mv, vbo_len_used);
+ vbo_len_used += 1;
+ }
+ }
+
+ /* Finish */
+ if (vbo_len_used != vbo_len_capacity) {
+ if (vbo_pos != NULL) {
+ GPU_vertbuf_data_resize(vbo_pos, vbo_len_used);
+ }
+ if (vbo_nor != NULL) {
+ GPU_vertbuf_data_resize(vbo_nor, vbo_len_used);
+ }
+ if (vbo_data != NULL) {
+ GPU_vertbuf_data_resize(vbo_data, vbo_len_used);
+ }
+ }
+}
+
+/* Position */
+static GPUVertBuf *mesh_batch_cache_get_edit_tri_pos(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_tri_pos == NULL) {
+ mesh_batch_cache_create_overlay_tri_buffers(rdata, cache);
+ }
+
+ return cache->ed_tri_pos;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_edit_ledge_pos(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_ledge_pos == NULL) {
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+ mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache);
+ }
+
+ return cache->ed_ledge_pos;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_edit_lvert_pos(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_lvert_pos == NULL) {
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+ mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache);
+ }
+
+ return cache->ed_lvert_pos;
+}
+
+/* Indices */
+static GPUIndexBuf *mesh_batch_cache_get_edit_tri_indices(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_tri_verts == NULL) {
+ mesh_batch_cache_create_overlay_tri_buffers(rdata, cache);
+ }
+
+ return cache->ed_tri_verts;
+}
+
+/* Normal */
+static GPUVertBuf *mesh_batch_cache_get_edit_tri_nor(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_tri_nor == NULL) {
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+ mesh_batch_cache_create_overlay_tri_buffers(rdata, cache);
+ }
+
+ return cache->ed_tri_nor;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_edit_ledge_nor(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_ledge_nor == NULL) {
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+ mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache);
+ }
+
+ return cache->ed_ledge_nor;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_edit_lvert_nor(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_lvert_nor == NULL) {
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+ mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache);
+ }
+
+ return cache->ed_lvert_nor;
+}
+
+/* Data */
+static GPUVertBuf *mesh_batch_cache_get_edit_tri_data(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_tri_data == NULL) {
+ mesh_batch_cache_create_overlay_tri_buffers(rdata, cache);
+ }
+
+ return cache->ed_tri_data;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_edit_ledge_data(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_ledge_data == NULL) {
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+ mesh_batch_cache_create_overlay_ledge_buffers(rdata, cache);
+ }
+
+ return cache->ed_ledge_data;
+}
+
+static GPUVertBuf *mesh_batch_cache_get_edit_lvert_data(
+ MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & MR_DATATYPE_VERT);
+
+ if (cache->ed_lvert_data == NULL) {
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+ mesh_batch_cache_create_overlay_lvert_buffers(rdata, cache);
+ }
+
+ return cache->ed_lvert_data;
+}
+
+static GPUIndexBuf *mesh_batch_cache_get_edges_in_order(MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE));
+
+ if (cache->edges_in_order == NULL) {
+ const int vert_len = mesh_render_data_verts_len_get(rdata);
+ const int edge_len = mesh_render_data_edges_len_get(rdata);
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
+
+ BLI_assert(rdata->types & MR_DATATYPE_EDGE);
+
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter eiter;
+ BMEdge *eed;
+ BM_ITER_MESH(eed, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ GPU_indexbuf_add_line_verts(&elb, BM_elem_index_get(eed->v1), BM_elem_index_get(eed->v2));
+ }
+ }
+ }
+ else {
+ const MEdge *ed = rdata->medge;
+ for (int i = 0; i < edge_len; i++, ed++) {
+ GPU_indexbuf_add_line_verts(&elb, ed->v1, ed->v2);
+ }
+ }
+ cache->edges_in_order = GPU_indexbuf_build(&elb);
+ }
+
+ return cache->edges_in_order;
+}
+
+#define NO_EDGE INT_MAX
+static GPUIndexBuf *mesh_batch_cache_get_edges_adjacency(MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI));
+
+ if (cache->edges_adjacency == NULL) {
+ const int vert_len = mesh_render_data_verts_len_get(rdata);
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ cache->is_manifold = true;
+
+ /* Allocate max but only used indices are sent to GPU. */
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, tri_len * 3, vert_len);
+
+ EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3);
+ /* Create edges for each pair of triangles sharing an edge. */
+ for (int i = 0; i < tri_len; i++) {
+ for (int e = 0; e < 3; e++) {
+ uint v0, v1, v2;
+ if (rdata->edit_bmesh) {
+ const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
+ break;
+ }
+ v0 = BM_elem_index_get(bm_looptri[e]->v);
+ v1 = BM_elem_index_get(bm_looptri[(e + 1) % 3]->v);
+ v2 = BM_elem_index_get(bm_looptri[(e + 2) % 3]->v);
+ }
+ else {
+ const MLoop *mloop = rdata->mloop;
+ const MLoopTri *mlt = rdata->mlooptri + i;
+ v0 = mloop[mlt->tri[e]].v;
+ v1 = mloop[mlt->tri[(e + 1) % 3]].v;
+ v2 = mloop[mlt->tri[(e + 2) % 3]].v;
+ }
+ bool inv_indices = (v1 > v2);
+ void **pval;
+ bool value_is_init = BLI_edgehash_ensure_p(eh, v1, v2, &pval);
+ int v_data = POINTER_AS_INT(*pval);
+ if (!value_is_init || v_data == NO_EDGE) {
+ /* Save the winding order inside the sign bit. Because the
+ * edgehash sort the keys and we need to compare winding later. */
+ int value = (int)v0 + 1; /* Int 0 cannot be signed */
+ *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
+ }
+ else {
+ /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
+ *pval = POINTER_FROM_INT(NO_EDGE);
+ bool inv_opposite = (v_data < 0);
+ uint v_opposite = (uint)abs(v_data) - 1;
+
+ if (inv_opposite == inv_indices) {
+ /* Don't share edge if triangles have non matching winding. */
+ GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0);
+ GPU_indexbuf_add_line_adj_verts(&elb, v_opposite, v1, v2, v_opposite);
+ cache->is_manifold = false;
+ }
+ else {
+ GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v_opposite);
+ }
+ }
+ }
+ }
+ /* Create edges for remaning non manifold edges. */
+ EdgeHashIterator *ehi;
+ for (ehi = BLI_edgehashIterator_new(eh);
+ BLI_edgehashIterator_isDone(ehi) == false;
+ BLI_edgehashIterator_step(ehi))
+ {
+ uint v1, v2;
+ int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
+ if (v_data == NO_EDGE) {
+ continue;
+ }
+ BLI_edgehashIterator_getKey(ehi, &v1, &v2);
+ uint v0 = (uint)abs(v_data) - 1;
+ if (v_data < 0) { /* inv_opposite */
+ SWAP(uint, v1, v2);
+ }
+ GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0);
+ cache->is_manifold = false;
+ }
+ BLI_edgehashIterator_free(ehi);
+ BLI_edgehash_free(eh, NULL);
+
+ cache->edges_adjacency = GPU_indexbuf_build(&elb);
+ }
+
+ return cache->edges_adjacency;
+}
+#undef NO_EDGE
+
+static EdgeHash *create_looptri_edge_adjacency_hash(MeshRenderData *rdata)
+{
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+ /* Create adjacency info in looptri */
+ EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3);
+ /* Create edges for each pair of triangles sharing an edge. */
+ for (int i = 0; i < tri_len; i++) {
+ for (int e = 0; e < 3; e++) {
+ uint v0, v1, v2;
+ if (rdata->edit_bmesh) {
+ const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
+ break;
+ }
+ v0 = BM_elem_index_get(bm_looptri[e]->v);
+ v1 = BM_elem_index_get(bm_looptri[(e + 1) % 3]->v);
+ v2 = BM_elem_index_get(bm_looptri[(e + 2) % 3]->v);
+ }
+ else {
+ const MLoop *mloop = rdata->mloop;
+ const MLoopTri *mlt = rdata->mlooptri + i;
+ v0 = mloop[mlt->tri[e]].v;
+ v1 = mloop[mlt->tri[(e + 1) % 3]].v;
+ v2 = mloop[mlt->tri[(e + 2) % 3]].v;
+ }
+
+ EdgeAdjacentVerts **eav;
+ bool value_is_init = BLI_edgehash_ensure_p(eh, v1, v2, (void ***)&eav);
+ if (!value_is_init) {
+ *eav = MEM_mallocN(sizeof(**eav), "EdgeAdjacentVerts");
+ (*eav)->vert_index[0] = v0;
+ (*eav)->vert_index[1] = -1;
+ }
+ else {
+ if ((*eav)->vert_index[1] == -1) {
+ (*eav)->vert_index[1] = v0;
+ }
+ else {
+ /* Not a manifold edge. */
+ }
+ }
+ }
+ }
+ return eh;
+}
+
+static GPUVertBuf *mesh_batch_cache_create_edges_overlay_texture_buf(MeshRenderData *rdata)
+{
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ GPUVertFormat format = {0};
+ uint index_id = GPU_vertformat_attr_add(&format, "index", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ int vbo_len_capacity = tri_len * 3;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ int vidx = 0;
+ EdgeHash *eh = NULL;
+ eh = create_looptri_edge_adjacency_hash(rdata);
+
+ for (int i = 0; i < tri_len; i++) {
+ bool edge_is_real[3];
+
+ const MEdge *medge = rdata->medge;
+ const MLoop *mloop = rdata->mloop;
+ const MLoopTri *mlt = rdata->mlooptri + i;
+
+ int j, j_next;
+ for (j = 2, j_next = 0; j_next < 3; j = j_next++) {
+ const MEdge *ed = &medge[mloop[mlt->tri[j]].e];
+ const uint tri_edge[2] = {mloop[mlt->tri[j]].v, mloop[mlt->tri[j_next]].v};
+ const bool is_edge_real = (
+ ((ed->v1 == tri_edge[0]) && (ed->v2 == tri_edge[1])) ||
+ ((ed->v1 == tri_edge[1]) && (ed->v2 == tri_edge[0])));
+ edge_is_real[j] = is_edge_real;
+ }
+
+ for (int e = 0; e < 3; e++) {
+ int v0 = mloop[mlt->tri[e]].v;
+ int v1 = mloop[mlt->tri[(e + 1) % 3]].v;
+ EdgeAdjacentVerts *eav = BLI_edgehash_lookup(eh, v0, v1);
+ uint value = (uint)v0;
+ /* Real edge */
+ if (edge_is_real[e]) {
+ value |= (1 << 30);
+ }
+ /* Non-manifold edge */
+ if (eav->vert_index[1] == -1) {
+ value |= (1u << 31);
+ }
+ GPU_vertbuf_attr_set(vbo, index_id, vidx++, &value);
+ }
+ }
+
+ BLI_edgehash_free(eh, MEM_freeN);
+
+ int vbo_len_used = vidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+
+ return vbo;
+}
+
+static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI));
+
+ BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */
+
+ if (cache->edges_face_overlay_tx != NULL) {
+ return cache->edges_face_overlay_tx;
+ }
+
+ GPUVertBuf *vbo = cache->edges_face_overlay = mesh_batch_cache_create_edges_overlay_texture_buf(rdata);
+
+ /* Upload data early because we need to create the texture for it. */
+ GPU_vertbuf_use(vbo);
+ cache->edges_face_overlay_tx = GPU_texture_create_from_vertbuf(vbo);
+ cache->edges_face_overlay_tri_count = vbo->vertex_alloc / 3;
+
+ return cache->edges_face_overlay_tx;
+}
+
+static GPUTexture *mesh_batch_cache_get_vert_pos_and_nor_in_order_buf(MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI));
+
+ if (cache->pos_in_order_tx == NULL) {
+ GPUVertBuf *pos_in_order = mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache);
+ GPU_vertbuf_use(pos_in_order); /* Upload early for buffer texture creation. */
+ cache->pos_in_order_tx = GPU_texture_create_buffer(GPU_R32F, pos_in_order->vbo_id);
+ }
+
+ return cache->pos_in_order_tx;
+}
+
+static GPUIndexBuf *mesh_batch_cache_get_triangles_in_order(MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
+
+ if (cache->triangles_in_order == NULL) {
+ const int vert_len = mesh_render_data_verts_len_get(rdata);
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len);
+
+ if (rdata->edit_bmesh) {
+ for (int i = 0; i < tri_len; i++) {
+ const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) {
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ GPU_indexbuf_add_generic_vert(&elb, BM_elem_index_get(ltri[tri_corner]->v));
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ GPU_indexbuf_add_generic_vert(&elb, mlt->tri[tri_corner]);
+ }
+ }
+ }
+ cache->triangles_in_order = GPU_indexbuf_build(&elb);
+ }
+
+ return cache->triangles_in_order;
+}
+
+
+static GPUIndexBuf *mesh_batch_cache_get_loose_edges(MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
+
+ if (cache->ledges_in_order == NULL) {
+ const int vert_len = mesh_render_data_verts_len_get_maybe_mapped(rdata);
+ const int edge_len = mesh_render_data_edges_len_get_maybe_mapped(rdata);
+
+ /* Alloc max (edge_len) and upload only needed range. */
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
+
+ if (rdata->mapped.use == false) {
+ if (rdata->edit_bmesh) {
+ /* No need to support since edit mesh already draw them.
+ * But some engines may want them ... */
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter eiter;
+ BMEdge *eed;
+ BM_ITER_MESH(eed, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
+ (eed->l == NULL || !bm_edge_has_visible_face(eed)))
+ {
+ GPU_indexbuf_add_line_verts(&elb, BM_elem_index_get(eed->v1), BM_elem_index_get(eed->v2));
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < edge_len; i++) {
+ const MEdge *medge = &rdata->medge[i];
+ if (medge->flag & ME_LOOSEEDGE) {
+ GPU_indexbuf_add_line_verts(&elb, medge->v1, medge->v2);
+ }
+ }
+ }
+ }
+ else {
+ /* Hidden checks are already done when creating the loose edge list. */
+ Mesh *me_cage = rdata->mapped.me_cage;
+ for (int i_iter = 0; i_iter < rdata->mapped.loose_edge_len; i_iter++) {
+ const int i = rdata->mapped.loose_edges[i_iter];
+ const MEdge *medge = &me_cage->medge[i];
+ GPU_indexbuf_add_line_verts(&elb, medge->v1, medge->v2);
+ }
+ }
+ cache->ledges_in_order = GPU_indexbuf_build(&elb);
+ }
+
+ return cache->ledges_in_order;
+}
+
+static GPUIndexBuf **mesh_batch_cache_get_triangles_in_order_split_by_material(
+ MeshRenderData *rdata, MeshBatchCache *cache,
+ /* Special case when drawing final evaluated mesh in editmode, so hidden faces are ignored. */
+ BMesh *bm_mapped, const int *p_origindex_mapped, bool use_hide)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_POLY));
+
+ if (cache->shaded_triangles_in_order == NULL) {
+ const int poly_len = mesh_render_data_polys_len_get(rdata);
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+ const int mat_len = mesh_render_data_mat_len_get(rdata);
+
+ int *mat_tri_len = MEM_callocN(sizeof(*mat_tri_len) * mat_len, __func__);
+ cache->shaded_triangles_in_order = MEM_callocN(sizeof(*cache->shaded_triangles) * mat_len, __func__);
+ GPUIndexBufBuilder *elb = MEM_callocN(sizeof(*elb) * mat_len, __func__);
+
+ /* Note that polygons (not triangles) are used here.
+ * This OK because result is _guaranteed_ to be the same. */
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter fiter;
+ BMFace *efa;
+
+ BM_ITER_MESH(efa, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ const short ma_id = efa->mat_nr < mat_len ? efa->mat_nr : 0;
+ mat_tri_len[ma_id] += (efa->len - 2);
+ }
+ }
+ }
+ else if (bm_mapped == NULL) {
+ for (uint i = 0; i < poly_len; i++) {
+ const MPoly *mp = &rdata->mpoly[i];
+ if (!use_hide || !(mp->flag & ME_HIDE)) {
+ const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0;
+ mat_tri_len[ma_id] += (mp->totloop - 2);
+ }
+ }
+ }
+ else {
+ BM_mesh_elem_table_ensure(bm_mapped, BM_FACE);
+ for (uint i = 0; i < poly_len; i++) {
+ const int p_orig = p_origindex_mapped[i];
+ if ((p_orig == ORIGINDEX_NONE) ||
+ !BM_elem_flag_test(BM_face_at_index(bm_mapped, p_orig), BM_ELEM_HIDDEN))
+ {
+ const MPoly *mp = &rdata->mpoly[i]; ;
+ const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0;
+ mat_tri_len[ma_id] += (mp->totloop - 2);
+ }
+ }
+
+ }
+
+ /* Init ELBs. */
+ for (int i = 0; i < mat_len; i++) {
+ GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, mat_tri_len[i], tri_len * 3);
+ }
+
+ /* Populate ELBs. */
+ uint nidx = 0;
+ if (rdata->edit_bmesh) {
+ BMesh *bm = rdata->edit_bmesh->bm;
+ BMIter fiter;
+ BMFace *efa;
+
+ BM_ITER_MESH(efa, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ const short ma_id = efa->mat_nr < mat_len ? efa->mat_nr : 0;
+ for (int j = 2; j < efa->len; j++) {
+ GPU_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2);
+ nidx += 3;
+ }
+ }
+ }
+ }
+ else if (bm_mapped == NULL) {
+ for (uint i = 0; i < poly_len; i++) {
+ const MPoly *mp = &rdata->mpoly[i];
+ if (!use_hide || !(mp->flag & ME_HIDE)) {
+ const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0;
+ for (int j = 2; j < mp->totloop; j++) {
+ GPU_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2);
+ nidx += 3;
+ }
+ }
+ else {
+ nidx += 3 * (mp->totloop - 2);
+ }
+ }
+ }
+ else {
+ for (uint i = 0; i < poly_len; i++) {
+ const int p_orig = p_origindex_mapped[i];
+ const MPoly *mp = &rdata->mpoly[i];
+ if ((p_orig == ORIGINDEX_NONE) ||
+ !BM_elem_flag_test(BM_face_at_index(bm_mapped, p_orig), BM_ELEM_HIDDEN))
+ {
+ const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0;
+ for (int j = 2; j < mp->totloop; j++) {
+ GPU_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2);
+ nidx += 3;
+ }
+ }
+ else {
+ nidx += (mp->totloop - 2) * 3;
+ }
+ }
+ }
+
+ /* Build ELBs. */
+ for (int i = 0; i < mat_len; i++) {
+ cache->shaded_triangles_in_order[i] = GPU_indexbuf_build(&elb[i]);
+ }
+
+ MEM_freeN(mat_tri_len);
+ MEM_freeN(elb);
+ }
+
+ return cache->shaded_triangles_in_order;
+}
+
+static GPUVertBuf *mesh_create_edge_pos_with_sel(
+ MeshRenderData *rdata, bool use_wire, bool use_select_bool, bool use_visible_bool)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_POLY | MR_DATATYPE_LOOP));
+ BLI_assert(rdata->edit_bmesh == NULL);
+
+ GPUVertBuf *vbo;
+ {
+ uint vidx = 0, cidx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, sel; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.sel = GPU_vertformat_attr_add(&format, "select", GPU_COMP_U8, 1, GPU_FETCH_INT);
+ }
+
+ const int edge_len = mesh_render_data_edges_len_get(rdata);
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = edge_len * 2;
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ if (use_select_bool) {
+ mesh_render_data_ensure_edge_select_bool(rdata, use_wire);
+ }
+ bool *edge_select_bool = use_select_bool ? rdata->edge_select_bool : NULL;
+ if (use_visible_bool) {
+ mesh_render_data_ensure_edge_visible_bool(rdata);
+ }
+ bool *edge_visible_bool = use_visible_bool ? rdata->edge_visible_bool : NULL;
+
+ for (int i = 0; i < edge_len; i++) {
+ const MEdge *ed = &rdata->medge[i];
+
+ if (use_visible_bool && !edge_visible_bool[i]) {
+ continue;
+ }
+
+ uchar edge_vert_sel;
+ if (use_select_bool && edge_select_bool[i]) {
+ edge_vert_sel = true;
+ }
+ else if (use_wire) {
+ edge_vert_sel = false;
+ }
+ else {
+ continue;
+ }
+
+ GPU_vertbuf_attr_set(vbo, attr_id.sel, cidx++, &edge_vert_sel);
+ GPU_vertbuf_attr_set(vbo, attr_id.sel, cidx++, &edge_vert_sel);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, rdata->mvert[ed->v1].co);
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, vidx++, rdata->mvert[ed->v2].co);
+ }
+ vbo_len_used = vidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+
+ return vbo;
+}
+
+static GPUIndexBuf *mesh_create_tri_overlay_weight_faces(
+ MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
+
+ {
+ const int vert_len = mesh_render_data_verts_len_get(rdata);
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len);
+
+ for (int i = 0; i < tri_len; i++) {
+ const MLoopTri *mlt = &rdata->mlooptri[i];
+ if (!(rdata->mpoly[mlt->poly].flag & (ME_FACE_SEL | ME_HIDE))) {
+ for (uint tri_corner = 0; tri_corner < 3; tri_corner++) {
+ GPU_indexbuf_add_generic_vert(&elb, rdata->mloop[mlt->tri[tri_corner]].v);
+ }
+ }
+ }
+ return GPU_indexbuf_build(&elb);
+ }
+}
+
+/**
+ * Non-edit mode vertices (only used for weight-paint mode).
+ */
+static GPUVertBuf *mesh_create_vert_pos_with_overlay_data(
+ MeshRenderData *rdata)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT));
+ BLI_assert(rdata->edit_bmesh == NULL);
+
+ GPUVertBuf *vbo;
+ {
+ uint cidx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint data; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_I8, 1, GPU_FETCH_INT);
+ }
+
+ const int vert_len = mesh_render_data_verts_len_get(rdata);
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+
+ const int vbo_len_capacity = vert_len;
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ for (int i = 0; i < vert_len; i++) {
+ const MVert *mv = &rdata->mvert[i];
+ const char data = mv->flag & (SELECT | ME_HIDE);
+ GPU_vertbuf_attr_set(vbo, attr_id.data, cidx++, &data);
+ }
+ vbo_len_used = cidx;
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+ }
+ return vbo;
+}
+
+/** \} */
+
+
+/* ---------------------------------------------------------------------- */
+
+/** \name Public API
+ * \{ */
+
+GPUBatch *DRW_mesh_batch_cache_get_all_edges(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->all_edges == NULL) {
+ /* create batch from Mesh */
+ const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_EDGE;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ cache->all_edges = GPU_batch_create(
+ GPU_PRIM_LINES, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache),
+ mesh_batch_cache_get_edges_in_order(rdata, cache));
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->all_edges;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_all_triangles(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->all_triangles == NULL) {
+ /* create batch from DM */
+ const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ cache->all_triangles = GPU_batch_create(
+ GPU_PRIM_TRIS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache),
+ mesh_batch_cache_get_triangles_in_order(rdata, cache));
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->all_triangles;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals(Mesh *me, bool use_hide)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->triangles_with_normals == NULL) {
+ const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ cache->triangles_with_normals = GPU_batch_create(
+ GPU_PRIM_TRIS, mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, use_hide), NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_normals;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_loose_edges_with_normals(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->ledges_with_normals == NULL) {
+ const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+
+ cache->ledges_with_normals = GPU_batch_create(
+ GPU_PRIM_LINES, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache),
+ mesh_batch_cache_get_loose_edges(rdata, cache));
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->ledges_with_normals;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(
+ Mesh *me, const struct DRW_MeshWeightState *wstate)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ mesh_batch_cache_check_vertex_group(cache, wstate);
+
+ if (cache->triangles_with_weights == NULL) {
+ const bool use_hide = (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) != 0;
+ const int datatype =
+ MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ cache->triangles_with_weights = GPU_batch_create_ex(
+ GPU_PRIM_TRIS, mesh_create_tri_weights(rdata, use_hide, wstate), NULL, GPU_BATCH_OWNS_VBO);
+
+ DRW_mesh_weight_state_copy(&cache->weight_state, wstate);
+
+ GPUVertBuf *vbo_tris = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, use_hide);
+
+ GPU_batch_vertbuf_add(cache->triangles_with_weights, vbo_tris);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_weights;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->triangles_with_vert_colors == NULL) {
+ const bool use_hide = (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) != 0;
+ const int datatype =
+ MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPCOL;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ cache->triangles_with_vert_colors = GPU_batch_create_ex(
+ GPU_PRIM_TRIS, mesh_create_tri_vert_colors(rdata, use_hide), NULL, GPU_BATCH_OWNS_VBO);
+
+ GPUVertBuf *vbo_tris = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, use_hide);
+ GPU_batch_vertbuf_add(cache->triangles_with_vert_colors, vbo_tris);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_vert_colors;
+}
+
+
+struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(
+ struct Mesh *me, bool use_hide, uint select_id_offset)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->triangles_with_select_id_offset != select_id_offset) {
+ cache->triangles_with_select_id_offset = select_id_offset;
+ GPU_BATCH_DISCARD_SAFE(cache->triangles_with_select_id);
+ }
+
+ if (cache->triangles_with_select_id == NULL) {
+ const int datatype =
+ MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+
+ cache->triangles_with_select_id = GPU_batch_create_ex(
+ GPU_PRIM_TRIS, mesh_create_tri_select_id(rdata, use_hide, select_id_offset), NULL, GPU_BATCH_OWNS_VBO);
+
+ GPUVertBuf *vbo_tris = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, use_hide);
+ GPU_batch_vertbuf_add(cache->triangles_with_select_id, vbo_tris);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_select_id;
+}
+
+/**
+ * Same as #DRW_mesh_batch_cache_get_triangles_with_select_id
+ * without the ID's, use to mask out geometry, eg - dont select face-dots behind other faces.
+ */
+struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_mask(struct Mesh *me, bool use_hide)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+ if (cache->triangles_with_select_mask == NULL) {
+ const int datatype =
+ MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+
+ GPUVertBuf *vbo_tris = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, use_hide);
+
+ cache->triangles_with_select_mask = GPU_batch_create(
+ GPU_PRIM_TRIS, vbo_tris, NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->triangles_with_select_mask;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_points_with_normals(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->points_with_normals == NULL) {
+ const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ cache->points_with_normals = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, false), NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->points_with_normals;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_all_verts(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->all_verts == NULL) {
+ /* create batch from DM */
+ MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT);
+
+ cache->all_verts = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache), NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->all_verts;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_fancy_edges(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->fancy_edges == NULL) {
+ /* create batch from DM */
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos, n1, n2; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ attr_id.n1 = GPU_vertformat_attr_add(&format, "N1", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ attr_id.n2 = GPU_vertformat_attr_add(&format, "N2", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ MeshRenderData *rdata = mesh_render_data_create(
+ me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
+
+ const int edge_len = mesh_render_data_edges_len_get(rdata);
+
+ const int vbo_len_capacity = edge_len * 2; /* these are PRIM_LINE verts, not mesh verts */
+ int vbo_len_used = 0;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+ for (int i = 0; i < edge_len; i++) {
+ float *vcos1, *vcos2;
+ float *pnor1 = NULL, *pnor2 = NULL;
+ bool is_manifold;
+
+ if (mesh_render_data_edge_vcos_manifold_pnors(rdata, i, &vcos1, &vcos2, &pnor1, &pnor2, &is_manifold)) {
+
+ GPUPackedNormal n1value = { .x = 0, .y = 0, .z = +511 };
+ GPUPackedNormal n2value = { .x = 0, .y = 0, .z = -511 };
+
+ if (is_manifold) {
+ n1value = GPU_normal_convert_i10_v3(pnor1);
+ n2value = GPU_normal_convert_i10_v3(pnor2);
+ }
+
+ const GPUPackedNormal *n1 = &n1value;
+ const GPUPackedNormal *n2 = &n2value;
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 2 * i, vcos1);
+ GPU_vertbuf_attr_set(vbo, attr_id.n1, 2 * i, n1);
+ GPU_vertbuf_attr_set(vbo, attr_id.n2, 2 * i, n2);
+
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, 2 * i + 1, vcos2);
+ GPU_vertbuf_attr_set(vbo, attr_id.n1, 2 * i + 1, n1);
+ GPU_vertbuf_attr_set(vbo, attr_id.n2, 2 * i + 1, n2);
+
+ vbo_len_used += 2;
+ }
+ }
+ if (vbo_len_used != vbo_len_capacity) {
+ GPU_vertbuf_data_resize(vbo, vbo_len_used);
+ }
+
+ cache->fancy_edges = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->fancy_edges;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_edge_detection(Mesh *me, bool *r_is_manifold)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->edge_detection == NULL) {
+ const int options = MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI;
+
+ MeshRenderData *rdata = mesh_render_data_create(me, options);
+
+ cache->edge_detection = GPU_batch_create_ex(
+ GPU_PRIM_LINES_ADJ, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache),
+ mesh_batch_cache_get_edges_adjacency(rdata, cache), 0);
+
+ mesh_render_data_free(rdata);
+ }
+
+ if (r_is_manifold) {
+ *r_is_manifold = cache->is_manifold;
+ }
+
+ return cache->edge_detection;
+}
+
+void DRW_mesh_batch_cache_get_wireframes_face_texbuf(
+ Mesh *me, GPUTexture **verts_data, GPUTexture **face_indices, int *tri_count)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->edges_face_overlay_tx == NULL || cache->pos_in_order_tx == NULL) {
+ const int options = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI;
+
+ MeshRenderData *rdata = mesh_render_data_create(me, options);
+
+ mesh_batch_cache_get_edges_overlay_texture_buf(rdata, cache);
+ mesh_batch_cache_get_vert_pos_and_nor_in_order_buf(rdata, cache);
+
+ mesh_render_data_free(rdata);
+ }
+
+ *tri_count = cache->edges_face_overlay_tri_count;
+ *face_indices = cache->edges_face_overlay_tx;
+ *verts_data = cache->pos_in_order_tx;
+}
+
+static void mesh_batch_cache_create_overlay_batches(Mesh *me)
+{
+ BLI_assert(me->edit_btmesh != NULL);
+
+ /* Since MR_DATATYPE_OVERLAY is slow to generate, generate them all at once */
+ const int options =
+ MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY |
+ MR_DATATYPE_LOOPTRI | MR_DATATYPE_OVERLAY;
+
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+ MeshRenderData *rdata = mesh_render_data_create(me, options);
+
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+
+ if (cache->overlay_triangles == NULL) {
+ cache->overlay_triangles = GPU_batch_create(
+ GPU_PRIM_TRIS, mesh_batch_cache_get_edit_tri_pos(rdata, cache), NULL);
+ GPU_batch_vertbuf_add(cache->overlay_triangles, mesh_batch_cache_get_edit_tri_nor(rdata, cache));
+ GPU_batch_vertbuf_add(cache->overlay_triangles, mesh_batch_cache_get_edit_tri_data(rdata, cache));
+ }
+
+ if (cache->overlay_loose_edges == NULL) {
+ cache->overlay_loose_edges = GPU_batch_create(
+ GPU_PRIM_LINES, mesh_batch_cache_get_edit_ledge_pos(rdata, cache), NULL);
+ GPU_batch_vertbuf_add(cache->overlay_loose_edges, mesh_batch_cache_get_edit_ledge_nor(rdata, cache));
+ GPU_batch_vertbuf_add(cache->overlay_loose_edges, mesh_batch_cache_get_edit_ledge_data(rdata, cache));
+ }
+
+ if (cache->overlay_loose_verts == NULL) {
+ cache->overlay_loose_verts = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_edit_lvert_pos(rdata, cache), NULL);
+ GPU_batch_vertbuf_add(cache->overlay_loose_verts, mesh_batch_cache_get_edit_lvert_nor(rdata, cache));
+ GPU_batch_vertbuf_add(cache->overlay_loose_verts, mesh_batch_cache_get_edit_lvert_data(rdata, cache));
+ }
+
+ /* Also used for vertices display */
+ if (cache->overlay_triangles_nor == NULL) {
+ cache->overlay_triangles_nor = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_edit_tri_pos(rdata, cache),
+ mesh_batch_cache_get_edit_tri_indices(rdata, cache));
+ GPU_batch_vertbuf_add(cache->overlay_triangles_nor, mesh_batch_cache_get_edit_tri_nor(rdata, cache));
+ GPU_batch_vertbuf_add(cache->overlay_triangles_nor, mesh_batch_cache_get_edit_tri_data(rdata, cache));
+ }
+
+ if (cache->overlay_triangles_lnor == NULL) {
+ cache->overlay_triangles_lnor = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_edit_tri_pos(rdata, cache), NULL);
+ GPU_batch_vertbuf_add(cache->overlay_triangles_lnor, mesh_batch_cache_get_edit_tri_nor(rdata, cache));
+ GPU_batch_vertbuf_add(cache->overlay_triangles_lnor, mesh_batch_cache_get_edit_tri_data(rdata, cache));
+ }
+
+ if (cache->overlay_loose_edges_nor == NULL) {
+ cache->overlay_loose_edges_nor = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_edit_ledge_pos(rdata, cache), NULL);
+ GPU_batch_vertbuf_add(cache->overlay_loose_edges_nor, mesh_batch_cache_get_edit_ledge_nor(rdata, cache));
+ GPU_batch_vertbuf_add(cache->overlay_loose_edges_nor, mesh_batch_cache_get_edit_ledge_data(rdata, cache));
+ }
+
+ mesh_render_data_free(rdata);
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_triangles == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+
+ return cache->overlay_triangles;
+}
+
+GPUTexture *DRW_mesh_batch_cache_get_overlay_data_tex(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->ed_tri_data_tx == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+
+ return cache->ed_tri_data_tx;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_edges(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_loose_edges == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+
+ return cache->overlay_loose_edges;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_verts(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_loose_verts == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+
+ return cache->overlay_loose_verts;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles_nor(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_triangles_nor == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+
+ return cache->overlay_triangles_nor;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_overlay_triangles_lnor(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_triangles_lnor == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+
+ return cache->overlay_triangles_lnor;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_overlay_loose_edges_nor(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_loose_edges_nor == NULL) {
+ mesh_batch_cache_create_overlay_batches(me);
+ }
+
+ return cache->overlay_loose_edges_nor;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_overlay_facedots(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_facedots == NULL) {
+ MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
+
+ cache->overlay_facedots = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_facedot_pos_with_normals_and_flag(rdata, cache), NULL);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->overlay_facedots;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_facedots_with_select_id(Mesh *me, uint select_id_offset)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->facedot_with_select_id_offset != select_id_offset) {
+ cache->facedot_with_select_id_offset = select_id_offset;
+ GPU_BATCH_DISCARD_SAFE(cache->edges_with_select_id);
+ }
+
+ if (cache->facedot_with_select_id == NULL) {
+ MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
+
+ /* We only want the 'pos', not the normals or flag.
+ * Use since this is almost certainly already created. */
+ cache->facedot_with_select_id = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_facedot_pos_with_normals_and_flag(rdata, cache), NULL);
+
+ GPU_batch_vertbuf_add_ex(
+ cache->facedot_with_select_id,
+ mesh_create_facedot_select_id(rdata, select_id_offset), true);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->facedot_with_select_id;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_edges_with_select_id(Mesh *me, uint select_id_offset)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->edges_with_select_id_offset != select_id_offset) {
+ cache->edges_with_select_id_offset = select_id_offset;
+ GPU_BATCH_DISCARD_SAFE(cache->edges_with_select_id);
+ }
+
+ if (cache->edges_with_select_id == NULL) {
+ MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE);
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+
+ cache->edges_with_select_id = GPU_batch_create(
+ GPU_PRIM_LINES, mesh_batch_cache_get_edges_visible(rdata, cache), NULL);
+
+ GPU_batch_vertbuf_add_ex(
+ cache->edges_with_select_id,
+ mesh_create_edges_select_id(rdata, select_id_offset), true);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->edges_with_select_id;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me, uint select_id_offset)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->verts_with_select_id_offset != select_id_offset) {
+ cache->verts_with_select_id_offset = select_id_offset;
+ GPU_BATCH_DISCARD_SAFE(cache->verts_with_select_id);
+ }
+
+ if (cache->verts_with_select_id == NULL) {
+ MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT);
+ if (rdata->mapped.supported) {
+ rdata->mapped.use = true;
+ }
+
+ cache->verts_with_select_id = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_verts_visible(rdata, cache), NULL);
+
+ GPU_batch_vertbuf_add_ex(
+ cache->verts_with_select_id,
+ mesh_create_verts_select_id(rdata, select_id_offset), true);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->verts_with_select_id;
+}
+
+GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(
+ Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len, bool use_hide,
+ char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->shaded_triangles == NULL) {
+
+ /* Hack to show the final result. */
+ BMesh *bm_mapped = NULL;
+ const int *p_origindex = NULL;
+ const bool use_em_final = (
+ me->edit_btmesh &&
+ me->edit_btmesh->mesh_eval_final &&
+ (me->edit_btmesh->mesh_eval_final->runtime.is_original == false));
+ Mesh me_fake;
+ if (use_em_final) {
+ /* Pass in mapped args. */
+ bm_mapped = me->edit_btmesh->bm;
+ p_origindex = CustomData_get_layer(&me->edit_btmesh->mesh_eval_final->pdata, CD_ORIGINDEX);
+ if (p_origindex == NULL) {
+ bm_mapped = NULL;
+ }
+
+ me_fake = *me->edit_btmesh->mesh_eval_final;
+ me_fake.mat = me->mat;
+ me_fake.totcol = me->totcol;
+ me = &me_fake;
+ }
+
+ /* create batch from DM */
+ const int datatype =
+ MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI |
+ MR_DATATYPE_POLY | MR_DATATYPE_SHADING;
+ MeshRenderData *rdata = mesh_render_data_create_ex(me, datatype, gpumat_array, gpumat_array_len);
+
+ const int mat_len = mesh_render_data_mat_len_get(rdata);
+
+ cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * mat_len, __func__);
+
+ GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material(
+ rdata, cache,
+ bm_mapped, p_origindex, use_hide);
+
+ GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, false);
+ GPUVertBuf *vbo_shading = mesh_batch_cache_get_tri_shading_data(rdata, cache);
+
+ for (int i = 0; i < mat_len; i++) {
+ cache->shaded_triangles[i] = GPU_batch_create(
+ GPU_PRIM_TRIS, vbo, el[i]);
+ if (vbo_shading) {
+ GPU_batch_vertbuf_add(cache->shaded_triangles[i], vbo_shading);
+ }
+ }
+
+ mesh_render_data_free(rdata);
+ }
+
+ if (auto_layer_names) {
+ *auto_layer_names = cache->auto_layer_names;
+ *auto_layer_is_srgb = cache->auto_layer_is_srgb;
+ *auto_layer_count = cache->auto_layer_len;
+ }
+
+ return cache->shaded_triangles;
+}
+
+GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me, bool use_hide)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->texpaint_triangles == NULL) {
+ /* create batch from DM */
+ const int datatype =
+ MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOPUV;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ const int mat_len = mesh_render_data_mat_len_get(rdata);
+
+ cache->texpaint_triangles = MEM_callocN(sizeof(*cache->texpaint_triangles) * mat_len, __func__);
+
+ GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material(rdata, cache, NULL, NULL, use_hide);
+
+ GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, false);
+
+ for (int i = 0; i < mat_len; i++) {
+ cache->texpaint_triangles[i] = GPU_batch_create(
+ GPU_PRIM_TRIS, vbo, el[i]);
+ GPUVertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache);
+ if (vbo_uv) {
+ GPU_batch_vertbuf_add(cache->texpaint_triangles[i], vbo_uv);
+ }
+ }
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->texpaint_triangles;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->texpaint_triangles_single == NULL) {
+ /* create batch from DM */
+ const int datatype =
+ MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOPUV;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache, false);
+
+ cache->texpaint_triangles_single = GPU_batch_create(
+ GPU_PRIM_TRIS, vbo, NULL);
+ GPUVertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache);
+ if (vbo_uv) {
+ GPU_batch_vertbuf_add(cache->texpaint_triangles_single, vbo_uv);
+ }
+ mesh_render_data_free(rdata);
+ }
+ return cache->texpaint_triangles_single;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_texpaint_loop_wire(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->texpaint_uv_loops == NULL) {
+ /* create batch from DM */
+ const int datatype = MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPUV;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ const MLoopUV *mloopuv_base = rdata->mloopuv;
+ if (mloopuv_base == NULL) {
+ return NULL;
+ }
+
+ uint vidx = 0;
+
+ static GPUVertFormat format = { 0 };
+ static struct { uint uv; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.uv = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ const uint vert_len = mesh_render_data_loops_len_get(rdata);
+ const uint poly_len = mesh_render_data_polys_len_get(rdata);
+ const uint idx_len = vert_len + poly_len;
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_LOOP, idx_len, vert_len, true);
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, vert_len);
+
+ const MPoly *mpoly = rdata->mpoly;
+ for (int a = 0; a < poly_len; a++, mpoly++) {
+ const MLoopUV *mloopuv = mloopuv_base + mpoly->loopstart;
+ for (int b = 0; b < mpoly->totloop; b++, mloopuv++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx, mloopuv->uv);
+ GPU_indexbuf_add_generic_vert(&elb, vidx++);
+ }
+ GPU_indexbuf_add_primitive_restart(&elb);
+ }
+
+ cache->texpaint_uv_loops = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP,
+ vbo, GPU_indexbuf_build(&elb),
+ GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+ gpu_batch_presets_register(cache->texpaint_uv_loops);
+ mesh_render_data_free(rdata);
+ }
+ return cache->texpaint_uv_loops;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_edges(Mesh *me, bool use_wire, bool use_sel, bool use_hide)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_paint_edges == NULL) {
+ /* create batch from Mesh */
+ const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_POLY | MR_DATATYPE_LOOP;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ cache->overlay_paint_edges = GPU_batch_create_ex(
+ GPU_PRIM_LINES, mesh_create_edge_pos_with_sel(rdata, use_wire, use_sel, use_hide), NULL, GPU_BATCH_OWNS_VBO);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->overlay_paint_edges;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_faces(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_weight_faces == NULL) {
+ /* create batch from Mesh */
+ const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_POLY | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI;
+ MeshRenderData *rdata = mesh_render_data_create(me, datatype);
+
+ cache->overlay_weight_faces = GPU_batch_create_ex(
+ GPU_PRIM_TRIS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache),
+ mesh_create_tri_overlay_weight_faces(rdata), GPU_BATCH_OWNS_INDEX);
+
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->overlay_weight_faces;
+}
+
+GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_verts(Mesh *me)
+{
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ if (cache->overlay_weight_verts == NULL) {
+ /* create batch from Mesh */
+ MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT);
+
+ cache->overlay_weight_verts = GPU_batch_create(
+ GPU_PRIM_POINTS, mesh_batch_cache_get_vert_pos_and_nor_in_order(rdata, cache), NULL);
+
+ GPU_batch_vertbuf_add_ex(
+ cache->overlay_weight_verts,
+ mesh_create_vert_pos_with_overlay_data(rdata), true);
+ mesh_render_data_free(rdata);
+ }
+
+ return cache->overlay_weight_verts;
+}
+
+/**
+ * Needed for when we draw with shaded data.
+ */
+void DRW_mesh_cache_sculpt_coords_ensure(Mesh *me)
+{
+ if (me->runtime.batch_cache) {
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+ if (cache && cache->pos_with_normals && cache->is_sculpt_points_tag) {
+ /* XXX Force update of all the batches that contains the pos_with_normals buffer.
+ * TODO(fclem): Ideally, Gawain should provide a way to update a buffer without destroying it. */
+ mesh_batch_cache_clear_selective(me, cache->pos_with_normals);
+ GPU_VERTBUF_DISCARD_SAFE(cache->pos_with_normals);
+ }
+ cache->is_sculpt_points_tag = false;
+ }
+}
+
+static uchar mesh_batch_cache_validate_edituvs(MeshBatchCache *cache, uchar state)
+{
+ if ((cache->edituv_state & UVEDIT_SYNC_SEL) != (state & UVEDIT_SYNC_SEL)) {
+ mesh_batch_cache_discard_uvedit(cache);
+ return state;
+ }
+ else {
+ return ((cache->edituv_state & state) ^ state);
+ }
+}
+
+/* Compute 3D & 2D areas and their sum. */
+BLI_INLINE void edit_uv_preprocess_stretch_area(
+ float (*tf_uv)[2], BMFace *efa, const float asp[2], const int cd_loop_uv_offset, uint fidx,
+ float *totarea, float *totuvarea, float (*faces_areas)[2])
+{
+ BMLoop *l;
+ BMIter liter;
+ int i;
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ mul_v2_v2v2(tf_uv[i], luv->uv, asp);
+ }
+ faces_areas[fidx][0] = BM_face_calc_area(efa);
+ faces_areas[fidx][1] = area_poly_v2(tf_uv, efa->len);
+
+ *totarea += faces_areas[fidx][0];
+ *totuvarea += faces_areas[fidx][1];
+}
+
+BLI_INLINE float edit_uv_get_stretch_area(float area, float uvarea)
+{
+ if (area < FLT_EPSILON || uvarea < FLT_EPSILON) {
+ return 1.0f;
+ }
+ else if (area > uvarea) {
+ return 1.0f - (uvarea / area);
+ }
+ else {
+ return 1.0f - (area / uvarea);
+ }
+}
+
+/* Compute face's normalized contour vectors. */
+BLI_INLINE void edit_uv_preprocess_stretch_angle(
+ float (*auv)[2], float (*av)[3], const int cd_loop_uv_offset, BMFace *efa, float asp[2])
+{
+ BMLoop *l;
+ BMIter liter;
+ int i;
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset);
+
+ sub_v2_v2v2(auv[i], luv_prev->uv, luv->uv);
+ mul_v2_v2(auv[i], asp);
+ normalize_v2(auv[i]);
+
+ sub_v3_v3v3(av[i], l->prev->v->co, l->v->co);
+ normalize_v3(av[i]);
+ }
+}
+
+BLI_INLINE float edit_uv_get_loop_stretch_angle(
+ const float auv0[2], const float auv1[2], const float av0[3], const float av1[3])
+{
+ float uvang = angle_normalized_v2v2(auv0, auv1);
+ float ang = angle_normalized_v3v3(av0, av1);
+ float stretch = fabsf(uvang - ang) / (float)M_PI;
+ return 1.0f - pow2f(1.0f - stretch);
+}
+
+#define VERTEX_SELECT (1 << 0)
+#define VERTEX_PINNED (1 << 1)
+#define FACE_SELECT (1 << 2)
+#define FACE_ACTIVE (1 << 3)
+#define EDGE_SELECT (1 << 4)
+
+BLI_INLINE uchar edit_uv_get_face_flag(BMFace *efa, BMFace *efa_act, const int cd_loop_uv_offset, Scene *scene)
+{
+ uchar flag = 0;
+ flag |= uvedit_face_select_test(scene, efa, cd_loop_uv_offset) ? FACE_SELECT : 0;
+ flag |= (efa == efa_act) ? FACE_ACTIVE : 0;
+ return flag;
+}
+
+BLI_INLINE uchar edit_uv_get_loop_flag(BMLoop *l, const int cd_loop_uv_offset, Scene *scene)
+{
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ uchar flag = 0;
+ flag |= uvedit_uv_select_test(scene, l, cd_loop_uv_offset) ? VERTEX_SELECT : 0;
+ flag |= uvedit_edge_select_test(scene, l, cd_loop_uv_offset) ? EDGE_SELECT : 0;
+ flag |= (luv->flag & MLOOPUV_PINNED) ? VERTEX_PINNED : 0;
+ return flag;
+}
+
+static struct EditUVFormatIndex {
+ uint uvs, area, angle, flag, fdots_uvs, fdots_flag;
+} uv_attr_id = {0};
+
+static void uvedit_fill_buffer_data(
+ Object *ob, struct SpaceImage *sima, Scene *scene, uchar state, MeshBatchCache *cache,
+ GPUIndexBufBuilder *elb_faces, GPUIndexBufBuilder *elb_edges, GPUVertBuf **facedots_vbo)
+{
+ Mesh *me = ob->data;
+ BMEditMesh *embm = me->edit_btmesh;
+ BMesh *bm = embm->bm;
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+ MLoopUV *luv;
+ uint vidx, fidx, i;
+ float (*faces_areas)[2] = NULL;
+ float asp[2];
+ float totarea = 0.0f, totuvarea = 0.0f;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ Image *ima = sima->image;
+ BMFace *efa_act = EDBM_uv_active_face_get(embm, false, false); /* will be set to NULL if hidden */
+
+ if (state & (UVEDIT_STRETCH_AREA | UVEDIT_STRETCH_ANGLE)) {
+ ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]);
+ }
+
+ BLI_buffer_declare_static(vec3f, vec3_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_buffer_declare_static(vec2f, vec2_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
+
+ if (state & UVEDIT_STRETCH_AREA) {
+ faces_areas = MEM_mallocN(sizeof(float) * 2 * bm->totface, "EDITUV faces areas");
+ }
+
+ /* Preprocess */
+ fidx = 0;
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ /* Tag hidden faces */
+ BM_elem_flag_set(efa, BM_ELEM_TAG, uvedit_face_visible_test(scene, ob, ima, efa));
+
+ if ((state & UVEDIT_STRETCH_AREA) &&
+ BM_elem_flag_test(efa, BM_ELEM_TAG))
+ {
+ const int efa_len = efa->len;
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&vec2_buf, vec2f, efa_len);
+ edit_uv_preprocess_stretch_area(tf_uv, efa, asp, cd_loop_uv_offset, fidx++,
+ &totarea, &totuvarea, faces_areas);
+ }
+ }
+
+ vidx = 0;
+ fidx = 0;
+ BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
+ const int efa_len = efa->len;
+ float fdot[2] = {0.0f, 0.0f};
+ float (*av)[3], (*auv)[2];
+ ushort area_stretch;
+ /* Skip hidden faces. */
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
+
+ uchar face_flag = edit_uv_get_face_flag(efa, efa_act, cd_loop_uv_offset, scene);
+ /* Face preprocess */
+ if (state & UVEDIT_STRETCH_AREA) {
+ area_stretch = edit_uv_get_stretch_area(faces_areas[fidx][0] / totarea,
+ faces_areas[fidx][1] / totuvarea) * 65534.0f;
+ }
+ if (state & UVEDIT_STRETCH_ANGLE) {
+ av = (float (*)[3])BLI_buffer_reinit_data(&vec3_buf, vec3f, efa_len);
+ auv = (float (*)[2])BLI_buffer_reinit_data(&vec2_buf, vec2f, efa_len);
+ edit_uv_preprocess_stretch_angle(auv, av, cd_loop_uv_offset, efa, asp);
+ }
+
+ BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ uchar flag = face_flag | edit_uv_get_loop_flag(l, cd_loop_uv_offset, scene);
+
+ if (state & UVEDIT_STRETCH_AREA) {
+ GPU_vertbuf_attr_set(cache->edituv_area, uv_attr_id.area, vidx, &area_stretch);
+ }
+ if (state & UVEDIT_STRETCH_ANGLE) {
+ ushort angle = 65534.0f * edit_uv_get_loop_stretch_angle(auv[i], auv[(i + 1) % efa_len],
+ av[i], av[(i + 1) % efa_len]);
+ GPU_vertbuf_attr_set(cache->edituv_angle, uv_attr_id.angle, vidx, &angle);
+ }
+ if (state & UVEDIT_EDGES) {
+ GPU_vertbuf_attr_set(cache->edituv_pos, uv_attr_id.uvs, vidx, luv->uv);
+ }
+ if (state & UVEDIT_DATA) {
+ GPU_vertbuf_attr_set(cache->edituv_data, uv_attr_id.flag, vidx, &flag);
+ }
+ if (state & UVEDIT_FACES) {
+ GPU_indexbuf_add_generic_vert(elb_faces, vidx);
+ }
+ if (state & UVEDIT_EDGES) {
+ GPU_indexbuf_add_generic_vert(elb_edges, vidx);
+ }
+
+ if (state & UVEDIT_FACEDOTS) {
+ add_v2_v2(fdot, luv->uv);
+ }
+ vidx++;
+ }
+
+ if (state & UVEDIT_FACES) {
+ GPU_indexbuf_add_primitive_restart(elb_faces);
+ }
+ if (state & UVEDIT_EDGES) {
+ GPU_indexbuf_add_primitive_restart(elb_edges);
+ }
+
+ if (state & UVEDIT_FACEDOTS) {
+ mul_v2_fl(fdot, 1.0f / (float)efa->len);
+ GPU_vertbuf_attr_set(*facedots_vbo, uv_attr_id.fdots_uvs, fidx, fdot);
+ GPU_vertbuf_attr_set(*facedots_vbo, uv_attr_id.fdots_flag, fidx, &face_flag);
+ }
+ fidx++;
+ }
+
+ if (faces_areas) {
+ MEM_freeN(faces_areas);
+ }
+
+ BLI_buffer_free(&vec3_buf);
+ BLI_buffer_free(&vec2_buf);
+
+ if (vidx == 0) {
+ GPU_VERTBUF_DISCARD_SAFE(cache->edituv_area);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edituv_angle);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edituv_pos);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edituv_data);
+ GPU_VERTBUF_DISCARD_SAFE(*facedots_vbo);
+ }
+
+ if (vidx < bm->totloop) {
+ if (cache->edituv_area && (state & UVEDIT_STRETCH_AREA)) {
+ GPU_vertbuf_data_resize(cache->edituv_area, vidx);
+ }
+ if (cache->edituv_angle && (state & UVEDIT_STRETCH_ANGLE)) {
+ GPU_vertbuf_data_resize(cache->edituv_angle, vidx);
+ }
+ if (cache->edituv_pos && (state & UVEDIT_EDGES)) {
+ GPU_vertbuf_data_resize(cache->edituv_pos, vidx);
+ }
+ if (cache->edituv_data && (state & UVEDIT_DATA)) {
+ GPU_vertbuf_data_resize(cache->edituv_data, vidx);
+ }
+ }
+ if (fidx < bm->totface) {
+ if (*facedots_vbo) {
+ GPU_vertbuf_data_resize(*facedots_vbo, fidx);
+ }
+ }
+}
+
+static void mesh_batch_cache_create_uvedit_buffers(
+ Object *ob, struct SpaceImage *sima, Scene *scene, MeshBatchCache *cache, uchar state)
+{
+ GPUVertBuf *facedots_vbo = NULL;
+
+ if (state == 0) {
+ return;
+ }
+
+ Mesh *me = ob->data;
+ BMEditMesh *embm = me->edit_btmesh;
+ BMesh *bm = embm->bm;
+
+ static GPUVertFormat format_pos = { 0 };
+ static GPUVertFormat format_area = { 0 };
+ static GPUVertFormat format_angle = { 0 };
+ static GPUVertFormat format_flag = { 0 };
+ static GPUVertFormat format_facedots = { 0 };
+
+ if (format_pos.attr_len == 0) {
+ uv_attr_id.uvs = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uv_attr_id.area = GPU_vertformat_attr_add(&format_area, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uv_attr_id.angle = GPU_vertformat_attr_add(&format_angle, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uv_attr_id.flag = GPU_vertformat_attr_add(&format_flag, "flag", GPU_COMP_U8, 1, GPU_FETCH_INT);
+
+ uv_attr_id.fdots_uvs = GPU_vertformat_attr_add(&format_facedots, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uv_attr_id.fdots_flag = GPU_vertformat_attr_add(&format_facedots, "flag", GPU_COMP_U8, 1, GPU_FETCH_INT);
+ }
+
+ const uint vert_len = bm->totloop;
+ const uint idx_len = bm->totloop + bm->totface;
+ const uint face_len = bm->totface;
+
+ if (state & UVEDIT_EDGES) {
+ cache->edituv_pos = GPU_vertbuf_create_with_format(&format_pos);
+ GPU_vertbuf_data_alloc(cache->edituv_pos, vert_len);
+ }
+ if (state & UVEDIT_DATA) {
+ cache->edituv_data = GPU_vertbuf_create_with_format(&format_flag);
+ GPU_vertbuf_data_alloc(cache->edituv_data, vert_len);
+ }
+ if (state & UVEDIT_STRETCH_AREA) {
+ cache->edituv_area = GPU_vertbuf_create_with_format(&format_area);
+ GPU_vertbuf_data_alloc(cache->edituv_area, vert_len);
+ }
+ if (state & UVEDIT_STRETCH_ANGLE) {
+ cache->edituv_angle = GPU_vertbuf_create_with_format(&format_angle);
+ GPU_vertbuf_data_alloc(cache->edituv_angle, vert_len);
+ }
+ if (state & UVEDIT_FACEDOTS) {
+ facedots_vbo = GPU_vertbuf_create_with_format(&format_facedots);
+ GPU_vertbuf_data_alloc(facedots_vbo, face_len);
+ }
+
+ /* NOTE: we could use the same index buffer for both primitive type (it's the same indices)
+ * but since GPU_PRIM_LINE_LOOP does not exist in vulkan, make it future proof. */
+ GPUIndexBufBuilder elb_faces, elb_edges;
+ if (state & UVEDIT_EDGES) {
+ GPU_indexbuf_init_ex(&elb_edges, GPU_PRIM_LINE_LOOP, idx_len, vert_len, true);
+ }
+ if (state & UVEDIT_FACES) {
+ GPU_indexbuf_init_ex(&elb_faces, GPU_PRIM_TRI_FAN, idx_len, vert_len, true);
+ }
+
+ uvedit_fill_buffer_data(ob, sima, scene, state, cache, &elb_faces, &elb_edges, &facedots_vbo);
+
+ if (state & UVEDIT_EDGES) {
+ cache->edituv_visible_edges = GPU_indexbuf_build(&elb_edges);
+ }
+ if (state & UVEDIT_FACES) {
+ cache->edituv_visible_faces = GPU_indexbuf_build(&elb_faces);
+ }
+ if ((state & UVEDIT_FACEDOTS) && facedots_vbo) {
+ cache->edituv_facedots = GPU_batch_create_ex(GPU_PRIM_POINTS, facedots_vbo, NULL, GPU_BATCH_OWNS_VBO);
+ gpu_batch_presets_register(cache->edituv_facedots);
+ }
+
+ cache->edituv_state |= state;
+}
+
+void DRW_mesh_cache_uvedit(
+ Object *ob, struct SpaceImage *sima, Scene *scene, uchar state,
+ GPUBatch **faces, GPUBatch **edges, GPUBatch **verts, GPUBatch **facedots)
+{
+ Mesh *me = ob->data;
+ MeshBatchCache *cache = mesh_batch_cache_get(me);
+
+ uchar missing_state = mesh_batch_cache_validate_edituvs(cache, state);
+
+ mesh_batch_cache_create_uvedit_buffers(ob, sima, scene, cache, missing_state);
+
+ /* Bail out if there is nothing to draw. */
+ if (cache->edituv_data == NULL) {
+ *faces = *edges = *verts = *facedots = NULL;
+ return;
+ }
+
+ /* Faces */
+ if (state & UVEDIT_STRETCH_AREA) {
+ if (cache->edituv_faces_strech_area == NULL) {
+ cache->edituv_faces_strech_area = GPU_batch_create(GPU_PRIM_TRI_FAN,
+ cache->edituv_pos,
+ cache->edituv_visible_faces);
+ GPU_batch_vertbuf_add_ex(cache->edituv_faces_strech_area,
+ cache->edituv_area, false);
+ gpu_batch_presets_register(cache->edituv_faces_strech_area);
+ }
+ *faces = cache->edituv_faces_strech_area;
+ }
+ else if (state & UVEDIT_STRETCH_ANGLE) {
+ if (cache->edituv_faces_strech_angle == NULL) {
+ cache->edituv_faces_strech_angle = GPU_batch_create(GPU_PRIM_TRI_FAN,
+ cache->edituv_pos,
+ cache->edituv_visible_faces);
+ GPU_batch_vertbuf_add_ex(cache->edituv_faces_strech_angle,
+ cache->edituv_angle, false);
+ gpu_batch_presets_register(cache->edituv_faces_strech_angle);
+ }
+ *faces = cache->edituv_faces_strech_angle;
+ }
+ else if (state & UVEDIT_FACES) {
+ if (cache->edituv_faces == NULL) {
+ cache->edituv_faces = GPU_batch_create(GPU_PRIM_TRI_FAN,
+ cache->edituv_pos,
+ cache->edituv_visible_faces);
+ GPU_batch_vertbuf_add_ex(cache->edituv_faces,
+ cache->edituv_data, false);
+ gpu_batch_presets_register(cache->edituv_faces);
+ }
+ *faces = cache->edituv_faces;
+ }
+ else {
+ *faces = NULL;
+ }
+
+ {
+ if (cache->edituv_edges == NULL) {
+ cache->edituv_edges = GPU_batch_create(GPU_PRIM_LINE_LOOP,
+ cache->edituv_pos,
+ cache->edituv_visible_edges);
+ GPU_batch_vertbuf_add_ex(cache->edituv_edges,
+ cache->edituv_data, false);
+ gpu_batch_presets_register(cache->edituv_edges);
+ }
+ *edges = cache->edituv_edges;
+ }
+
+ {
+ if (cache->edituv_verts == NULL) {
+ cache->edituv_verts = GPU_batch_create(GPU_PRIM_POINTS,
+ cache->edituv_pos,
+ NULL);
+ GPU_batch_vertbuf_add_ex(cache->edituv_verts,
+ cache->edituv_data, false);
+ gpu_batch_presets_register(cache->edituv_verts);
+ }
+ *verts = cache->edituv_verts;
+ }
+
+ if (state & UVEDIT_FACEDOTS) {
+ *facedots = cache->edituv_facedots;
+ }
+ else {
+ *facedots = NULL;
+ }
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
new file mode 100644
index 00000000000..841cb73d9c7
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -0,0 +1,257 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_cache_impl_metaball.c
+ * \ingroup draw
+ *
+ * \brief MetaBall API for render engines
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_curve.h"
+#include "BKE_mball.h"
+
+#include "GPU_batch.h"
+
+#include "DRW_render.h"
+
+#include "draw_cache_impl.h" /* own include */
+
+
+static void metaball_batch_cache_clear(MetaBall *mb);
+
+/* ---------------------------------------------------------------------- */
+/* MetaBall GPUBatch Cache */
+
+typedef struct MetaBallBatchCache {
+ GPUBatch *batch;
+ GPUBatch **shaded_triangles;
+ int mat_len;
+
+ /* Shared */
+ GPUVertBuf *pos_nor_in_order;
+
+ /* Wireframe */
+ struct {
+ GPUVertBuf *elem_vbo;
+ GPUTexture *elem_tx;
+ GPUTexture *verts_tx;
+ int tri_count;
+ } face_wire;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+} MetaBallBatchCache;
+
+/* GPUBatch cache management. */
+
+static bool metaball_batch_cache_valid(MetaBall *mb)
+{
+ MetaBallBatchCache *cache = mb->batch_cache;
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ return cache->is_dirty == false;
+}
+
+static void metaball_batch_cache_init(MetaBall *mb)
+{
+ MetaBallBatchCache *cache = mb->batch_cache;
+
+ if (!cache) {
+ cache = mb->batch_cache = MEM_mallocN(sizeof(*cache), __func__);
+ }
+ cache->batch = NULL;
+ cache->mat_len = 0;
+ cache->shaded_triangles = NULL;
+ cache->is_dirty = false;
+ cache->pos_nor_in_order = NULL;
+ cache->face_wire.elem_vbo = NULL;
+ cache->face_wire.elem_tx = NULL;
+ cache->face_wire.verts_tx = NULL;
+ cache->face_wire.tri_count = 0;
+}
+
+static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb)
+{
+ if (!metaball_batch_cache_valid(mb)) {
+ metaball_batch_cache_clear(mb);
+ metaball_batch_cache_init(mb);
+ }
+ return mb->batch_cache;
+}
+
+void DRW_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
+{
+ MetaBallBatchCache *cache = mb->batch_cache;
+ if (cache == NULL) {
+ return;
+ }
+ switch (mode) {
+ case BKE_MBALL_BATCH_DIRTY_ALL:
+ cache->is_dirty = true;
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void metaball_batch_cache_clear(MetaBall *mb)
+{
+ MetaBallBatchCache *cache = mb->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ GPU_VERTBUF_DISCARD_SAFE(cache->face_wire.elem_vbo);
+ DRW_TEXTURE_FREE_SAFE(cache->face_wire.elem_tx);
+ DRW_TEXTURE_FREE_SAFE(cache->face_wire.verts_tx);
+
+ GPU_BATCH_DISCARD_SAFE(cache->batch);
+ GPU_VERTBUF_DISCARD_SAFE(cache->pos_nor_in_order);
+ /* Note: shaded_triangles[0] is already freed by cache->batch */
+ MEM_SAFE_FREE(cache->shaded_triangles);
+ cache->mat_len = 0;
+}
+
+void DRW_mball_batch_cache_free(MetaBall *mb)
+{
+ metaball_batch_cache_clear(mb);
+ MEM_SAFE_FREE(mb->batch_cache);
+}
+
+static GPUVertBuf *mball_batch_cache_get_pos_and_normals(Object *ob, MetaBallBatchCache *cache)
+{
+ if (cache->pos_nor_in_order == NULL) {
+ ListBase *lb = &ob->runtime.curve_cache->disp;
+ cache->pos_nor_in_order = DRW_displist_vertbuf_calc_pos_with_normals(lb);
+ }
+ return cache->pos_nor_in_order;
+}
+
+static GPUTexture *mball_batch_cache_get_edges_overlay_texture_buf(Object *ob, MetaBallBatchCache *cache)
+{
+ if (cache->face_wire.elem_tx != NULL) {
+ return cache->face_wire.elem_tx;
+ }
+
+ ListBase *lb = &ob->runtime.curve_cache->disp;
+
+ /* We need a special index buffer. */
+ GPUVertBuf *vbo = cache->face_wire.elem_vbo = DRW_displist_create_edges_overlay_texture_buf(lb);
+
+ /* Upload data early because we need to create the texture for it. */
+ GPU_vertbuf_use(vbo);
+ cache->face_wire.elem_tx = GPU_texture_create_from_vertbuf(vbo);
+ cache->face_wire.tri_count = vbo->vertex_alloc / 3;
+
+ return cache->face_wire.elem_tx;
+}
+
+static GPUTexture *mball_batch_cache_get_vert_pos_and_nor_in_order_buf(Object *ob, MetaBallBatchCache *cache)
+{
+ if (cache->face_wire.verts_tx == NULL) {
+ GPUVertBuf *vbo = mball_batch_cache_get_pos_and_normals(ob, cache);
+ GPU_vertbuf_use(vbo); /* Upload early for buffer texture creation. */
+ cache->face_wire.verts_tx = GPU_texture_create_buffer(GPU_R32F, vbo->vbo_id);
+ }
+
+ return cache->face_wire.verts_tx;
+}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public Object/MetaBall API
+ * \{ */
+
+GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob)
+{
+ if (!BKE_mball_is_basis(ob)) {
+ return NULL;
+ }
+
+ MetaBall *mb = ob->data;
+ MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
+
+ if (cache->batch == NULL) {
+ ListBase *lb = &ob->runtime.curve_cache->disp;
+ cache->batch = GPU_batch_create_ex(
+ GPU_PRIM_TRIS,
+ mball_batch_cache_get_pos_and_normals(ob, cache),
+ DRW_displist_indexbuf_calc_triangles_in_order(lb),
+ GPU_BATCH_OWNS_INDEX);
+ }
+
+ return cache->batch;
+}
+
+GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob, MetaBall *mb, struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len)
+{
+ if (!BKE_mball_is_basis(ob)) {
+ return NULL;
+ }
+
+ MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
+ if (cache->shaded_triangles == NULL) {
+ cache->mat_len = gpumat_array_len;
+ cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * cache->mat_len, __func__);
+ cache->shaded_triangles[0] = DRW_metaball_batch_cache_get_triangles_with_normals(ob);
+ for (int i = 1; i < cache->mat_len; ++i) {
+ cache->shaded_triangles[i] = NULL;
+ }
+ }
+ return cache->shaded_triangles;
+
+}
+
+void DRW_metaball_batch_cache_get_wireframes_face_texbuf(
+ Object *ob, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count)
+{
+ if (!BKE_mball_is_basis(ob)) {
+ *verts_data = NULL;
+ *face_indices = NULL;
+ *tri_count = 0;
+ return;
+ }
+
+ MetaBall *mb = ob->data;
+ MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
+
+ if (cache->face_wire.verts_tx == NULL) {
+ *verts_data = mball_batch_cache_get_vert_pos_and_nor_in_order_buf(ob, cache);
+ *face_indices = mball_batch_cache_get_edges_overlay_texture_buf(ob, cache);
+ }
+ else {
+ *verts_data = cache->face_wire.verts_tx;
+ *face_indices = cache->face_wire.elem_tx;
+ }
+ *tri_count = cache->face_wire.tri_count;
+}
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
new file mode 100644
index 00000000000..d83f8fb660b
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -0,0 +1,1689 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_cache_impl_particles.c
+ * \ingroup draw
+ *
+ * \brief Particle API for render engines
+ */
+
+#include "DRW_render.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_customdata_types.h"
+
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+
+#include "ED_particle.h"
+
+#include "GPU_batch.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "draw_cache_impl.h" /* own include */
+#include "draw_hair_private.h"
+
+static void particle_batch_cache_clear(ParticleSystem *psys);
+
+/* ---------------------------------------------------------------------- */
+/* Particle GPUBatch Cache */
+
+typedef struct ParticlePointCache {
+ GPUVertBuf *pos;
+ GPUBatch *points;
+ int elems_len;
+ int point_len;
+} ParticlePointCache;
+
+typedef struct ParticleBatchCache {
+ /* Object mode strands for hair and points for particle,
+ * strands for paths when in edit mode.
+ */
+ ParticleHairCache hair; /* Used for hair strands */
+ ParticlePointCache point; /* Used for particle points. */
+
+ /* Control points when in edit mode. */
+ ParticleHairCache edit_hair;
+
+ GPUVertBuf *edit_pos;
+ GPUBatch *edit_strands;
+
+ GPUVertBuf *edit_inner_pos;
+ GPUBatch *edit_inner_points;
+ int edit_inner_point_len;
+
+ GPUVertBuf *edit_tip_pos;
+ GPUBatch *edit_tip_points;
+ int edit_tip_point_len;
+
+ /* Settings to determine if cache is invalid. */
+ bool is_dirty;
+ bool edit_is_weight;
+} ParticleBatchCache;
+
+/* GPUBatch cache management. */
+
+typedef struct HairAttributeID {
+ uint pos;
+ uint tan;
+ uint ind;
+} HairAttributeID;
+
+typedef struct EditStrandData {
+ float pos[3];
+ uchar color;
+} EditStrandData;
+
+static GPUVertFormat *edit_points_vert_format_get(uint *r_pos_id, uint *r_color_id)
+{
+ static GPUVertFormat edit_point_format = { 0 };
+ static uint pos_id, color_id;
+ if (edit_point_format.attr_len == 0) {
+ /* Keep in sync with EditStrandData */
+ pos_id = GPU_vertformat_attr_add(&edit_point_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ color_id = GPU_vertformat_attr_add(&edit_point_format, "color", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ *r_pos_id = pos_id;
+ *r_color_id = color_id;
+ return &edit_point_format;
+}
+
+static bool particle_batch_cache_valid(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ if (cache->is_dirty == false) {
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ return true;
+}
+
+static void particle_batch_cache_init(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+
+ if (!cache) {
+ cache = psys->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+ cache->is_dirty = false;
+}
+
+static ParticleBatchCache *particle_batch_cache_get(ParticleSystem *psys)
+{
+ if (!particle_batch_cache_valid(psys)) {
+ particle_batch_cache_clear(psys);
+ particle_batch_cache_init(psys);
+ }
+ return psys->batch_cache;
+}
+
+void DRW_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+ if (cache == NULL) {
+ return;
+ }
+ switch (mode) {
+ case BKE_PARTICLE_BATCH_DIRTY_ALL:
+ cache->is_dirty = true;
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void particle_batch_cache_clear_point(ParticlePointCache *point_cache)
+{
+ GPU_BATCH_DISCARD_SAFE(point_cache->points);
+ GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
+}
+
+static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
+{
+ /* TODO more granular update tagging. */
+ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf);
+ DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex);
+
+ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf);
+ DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex);
+
+ for (int i = 0; i < MAX_MTFACE; ++i) {
+ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]);
+ }
+ for (int i = 0; i < MAX_MCOL; ++i) {
+ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]);
+ }
+ for (int i = 0; i < MAX_HAIR_SUBDIV; ++i) {
+ GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf);
+ DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex);
+ for (int j = 0; j < MAX_THICKRES; ++j) {
+ GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]);
+ }
+ }
+
+ /* "Normal" legacy hairs */
+ GPU_BATCH_DISCARD_SAFE(hair_cache->hairs);
+ GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
+ GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
+}
+
+static void particle_batch_cache_clear(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ particle_batch_cache_clear_point(&cache->point);
+ particle_batch_cache_clear_hair(&cache->hair);
+
+ particle_batch_cache_clear_hair(&cache->edit_hair);
+
+ GPU_BATCH_DISCARD_SAFE(cache->edit_inner_points);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edit_inner_pos);
+ GPU_BATCH_DISCARD_SAFE(cache->edit_tip_points);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edit_tip_pos);
+}
+
+void DRW_particle_batch_cache_free(ParticleSystem *psys)
+{
+ particle_batch_cache_clear(psys);
+ MEM_SAFE_FREE(psys->batch_cache);
+}
+
+static void count_cache_segment_keys(
+ ParticleCacheKey **pathcache,
+ const int num_path_cache_keys,
+ ParticleHairCache *hair_cache)
+{
+ for (int i = 0; i < num_path_cache_keys; i++) {
+ ParticleCacheKey *path = pathcache[i];
+ if (path->segments > 0) {
+ hair_cache->strands_len++;
+ hair_cache->elems_len += path->segments + 2;
+ hair_cache->point_len += path->segments + 1;
+ }
+ }
+}
+
+static void ensure_seg_pt_count(
+ PTCacheEdit *edit,
+ ParticleSystem *psys,
+ ParticleHairCache *hair_cache)
+{
+ if ((hair_cache->pos != NULL && hair_cache->indices != NULL) ||
+ (hair_cache->proc_point_buf != NULL))
+ {
+ return;
+ }
+
+ hair_cache->strands_len = 0;
+ hair_cache->elems_len = 0;
+ hair_cache->point_len = 0;
+
+ if (edit != NULL && edit->pathcache != NULL) {
+ count_cache_segment_keys(edit->pathcache, edit->totcached, hair_cache);
+ }
+ else {
+ if (psys->pathcache &&
+ (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
+ {
+ count_cache_segment_keys(psys->pathcache, psys->totpart, hair_cache);
+ }
+ if (psys->childcache) {
+ const int child_count = psys->totchild * psys->part->disp / 100;
+ count_cache_segment_keys(psys->childcache, child_count, hair_cache);
+ }
+ }
+}
+
+static void particle_pack_mcol(MCol *mcol, ushort r_scol[3])
+{
+ /* Convert to linear ushort and swizzle */
+ r_scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
+ r_scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
+ r_scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
+}
+
+/* Used by parent particles and simple children. */
+static void particle_calculate_parent_uvs(
+ ParticleSystem *psys,
+ ParticleSystemModifierData *psmd,
+ const int num_uv_layers,
+ const int parent_index,
+ /*const*/ MTFace **mtfaces,
+ float (*r_uv)[2])
+{
+ if (psmd == NULL) {
+ return;
+ }
+ const int emit_from = psmd->psys->part->from;
+ if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ return;
+ }
+ ParticleData *particle = &psys->particles[parent_index];
+ int num = particle->num_dmcache;
+ if (num == DMCACHE_NOTFOUND || num == DMCACHE_ISCHILD) {
+ if (particle->num < psmd->mesh_final->totface) {
+ num = particle->num;
+ }
+ }
+ if (num != DMCACHE_NOTFOUND && num != DMCACHE_ISCHILD) {
+ MFace *mface = &psmd->mesh_final->mface[num];
+ for (int j = 0; j < num_uv_layers; j++) {
+ psys_interpolate_uvs(
+ mtfaces[j] + num,
+ mface->v4,
+ particle->fuv,
+ r_uv[j]);
+ }
+ }
+}
+
+static void particle_calculate_parent_mcol(
+ ParticleSystem *psys,
+ ParticleSystemModifierData *psmd,
+ const int num_uv_layers,
+ const int parent_index,
+ /*const*/ MCol **mcols,
+ MCol *r_mcol)
+{
+ if (psmd == NULL) {
+ return;
+ }
+ const int emit_from = psmd->psys->part->from;
+ if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ return;
+ }
+ ParticleData *particle = &psys->particles[parent_index];
+ int num = particle->num_dmcache;
+ if (num == DMCACHE_NOTFOUND || num == DMCACHE_ISCHILD) {
+ if (particle->num < psmd->mesh_final->totface) {
+ num = particle->num;
+ }
+ }
+ if (num != DMCACHE_NOTFOUND && num != DMCACHE_ISCHILD) {
+ MFace *mface = &psmd->mesh_final->mface[num];
+ for (int j = 0; j < num_uv_layers; j++) {
+ psys_interpolate_mcol(
+ mcols[j] + num,
+ mface->v4,
+ particle->fuv,
+ &r_mcol[j]);
+ }
+ }
+}
+
+/* Used by interpolated children. */
+static void particle_interpolate_children_uvs(
+ ParticleSystem *psys,
+ ParticleSystemModifierData *psmd,
+ const int num_uv_layers,
+ const int child_index,
+ /*const*/ MTFace **mtfaces,
+ float (*r_uv)[2])
+{
+ if (psmd == NULL) {
+ return;
+ }
+ const int emit_from = psmd->psys->part->from;
+ if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ return;
+ }
+ ChildParticle *particle = &psys->child[child_index];
+ int num = particle->num;
+ if (num != DMCACHE_NOTFOUND) {
+ MFace *mface = &psmd->mesh_final->mface[num];
+ for (int j = 0; j < num_uv_layers; j++) {
+ psys_interpolate_uvs(
+ mtfaces[j] + num,
+ mface->v4,
+ particle->fuv,
+ r_uv[j]);
+ }
+ }
+}
+
+static void particle_interpolate_children_mcol(
+ ParticleSystem *psys,
+ ParticleSystemModifierData *psmd,
+ const int num_col_layers,
+ const int child_index,
+ /*const*/ MCol **mcols,
+ MCol *r_mcol)
+{
+ if (psmd == NULL) {
+ return;
+ }
+ const int emit_from = psmd->psys->part->from;
+ if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ return;
+ }
+ ChildParticle *particle = &psys->child[child_index];
+ int num = particle->num;
+ if (num != DMCACHE_NOTFOUND) {
+ MFace *mface = &psmd->mesh_final->mface[num];
+ for (int j = 0; j < num_col_layers; j++) {
+ psys_interpolate_mcol(
+ mcols[j] + num,
+ mface->v4,
+ particle->fuv,
+ &r_mcol[j]);
+ }
+ }
+}
+
+static void particle_calculate_uvs(
+ ParticleSystem *psys,
+ ParticleSystemModifierData *psmd,
+ const bool is_simple,
+ const int num_uv_layers,
+ const int parent_index,
+ const int child_index,
+ /*const*/ MTFace **mtfaces,
+ float (**r_parent_uvs)[2],
+ float (**r_uv)[2])
+{
+ if (psmd == NULL) {
+ return;
+ }
+ if (is_simple) {
+ if (r_parent_uvs[parent_index] != NULL) {
+ *r_uv = r_parent_uvs[parent_index];
+ }
+ else {
+ *r_uv = MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs");
+ }
+ }
+ else {
+ *r_uv = MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs");
+ }
+ if (child_index == -1) {
+ /* Calculate UVs for parent particles. */
+ if (is_simple) {
+ r_parent_uvs[parent_index] = *r_uv;
+ }
+ particle_calculate_parent_uvs(
+ psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
+ }
+ else {
+ /* Calculate UVs for child particles. */
+ if (!is_simple) {
+ particle_interpolate_children_uvs(
+ psys, psmd, num_uv_layers, child_index, mtfaces, *r_uv);
+ }
+ else if (!r_parent_uvs[psys->child[child_index].parent]) {
+ r_parent_uvs[psys->child[child_index].parent] = *r_uv;
+ particle_calculate_parent_uvs(
+ psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
+ }
+ }
+}
+
+static void particle_calculate_mcol(
+ ParticleSystem *psys,
+ ParticleSystemModifierData *psmd,
+ const bool is_simple,
+ const int num_col_layers,
+ const int parent_index,
+ const int child_index,
+ /*const*/ MCol **mcols,
+ MCol **r_parent_mcol,
+ MCol **r_mcol)
+{
+ if (psmd == NULL) {
+ return;
+ }
+ if (is_simple) {
+ if (r_parent_mcol[parent_index] != NULL) {
+ *r_mcol = r_parent_mcol[parent_index];
+ }
+ else {
+ *r_mcol = MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol");
+ }
+ }
+ else {
+ *r_mcol = MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol");
+ }
+ if (child_index == -1) {
+ /* Calculate MCols for parent particles. */
+ if (is_simple) {
+ r_parent_mcol[parent_index] = *r_mcol;
+ }
+ particle_calculate_parent_mcol(
+ psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
+ }
+ else {
+ /* Calculate MCols for child particles. */
+ if (!is_simple) {
+ particle_interpolate_children_mcol(
+ psys, psmd, num_col_layers, child_index, mcols, *r_mcol);
+ }
+ else if (!r_parent_mcol[psys->child[child_index].parent]) {
+ r_parent_mcol[psys->child[child_index].parent] = *r_mcol;
+ particle_calculate_parent_mcol(
+ psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
+ }
+ }
+}
+
+/* Will return last filled index. */
+typedef enum ParticleSource {
+ PARTICLE_SOURCE_PARENT,
+ PARTICLE_SOURCE_CHILDREN,
+} ParticleSource;
+static int particle_batch_cache_fill_segments(
+ ParticleSystem *psys,
+ ParticleSystemModifierData *psmd,
+ ParticleCacheKey **path_cache,
+ const ParticleSource particle_source,
+ const int global_offset,
+ const int start_index,
+ const int num_path_keys,
+ const int num_uv_layers,
+ const int num_col_layers,
+ /*const*/ MTFace **mtfaces,
+ /*const*/ MCol **mcols,
+ uint *uv_id,
+ uint *col_id,
+ float (***r_parent_uvs)[2],
+ MCol ***r_parent_mcol,
+ GPUIndexBufBuilder *elb,
+ HairAttributeID *attr_id,
+ ParticleHairCache *hair_cache)
+{
+ const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
+ const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
+ if (is_simple && *r_parent_uvs == NULL) {
+ /* TODO(sergey): For edit mode it should be edit->totcached. */
+ *r_parent_uvs = MEM_callocN(
+ sizeof(*r_parent_uvs) * psys->totpart,
+ "Parent particle UVs");
+ }
+ if (is_simple && *r_parent_mcol == NULL) {
+ *r_parent_mcol = MEM_callocN(
+ sizeof(*r_parent_mcol) * psys->totpart,
+ "Parent particle MCol");
+ }
+ int curr_point = start_index;
+ for (int i = 0; i < num_path_keys; i++) {
+ ParticleCacheKey *path = path_cache[i];
+ if (path->segments <= 0) {
+ continue;
+ }
+ float tangent[3];
+ float (*uv)[2] = NULL;
+ MCol *mcol = NULL;
+ particle_calculate_mcol(
+ psys, psmd,
+ is_simple, num_col_layers,
+ is_child ? psys->child[i].parent : i,
+ is_child ? i : -1,
+ mcols,
+ *r_parent_mcol, &mcol);
+ particle_calculate_uvs(
+ psys, psmd,
+ is_simple, num_uv_layers,
+ is_child ? psys->child[i].parent : i,
+ is_child ? i : -1,
+ mtfaces,
+ *r_parent_uvs, &uv);
+ for (int j = 0; j < path->segments; j++) {
+ if (j == 0) {
+ sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
+ }
+ else {
+ sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
+ }
+ GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[j].co);
+ GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
+ GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &i);
+ if (psmd != NULL) {
+ for (int k = 0; k < num_uv_layers; k++) {
+ GPU_vertbuf_attr_set(
+ hair_cache->pos, uv_id[k], curr_point,
+ (is_simple && is_child) ?
+ (*r_parent_uvs)[psys->child[i].parent][k] : uv[k]);
+ }
+ for (int k = 0; k < num_col_layers; k++) {
+ /* TODO Put the conversion outside the loop */
+ ushort scol[4];
+ particle_pack_mcol(
+ (is_simple && is_child) ?
+ &(*r_parent_mcol)[psys->child[i].parent][k] : &mcol[k],
+ scol);
+ GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
+ }
+ }
+ GPU_indexbuf_add_generic_vert(elb, curr_point);
+ curr_point++;
+ }
+ sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
+
+ int global_index = i + global_offset;
+ GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[path->segments].co);
+ GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
+ GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &global_index);
+
+ if (psmd != NULL) {
+ for (int k = 0; k < num_uv_layers; k++) {
+ GPU_vertbuf_attr_set(
+ hair_cache->pos, uv_id[k], curr_point,
+ (is_simple && is_child) ?
+ (*r_parent_uvs)[psys->child[i].parent][k] : uv[k]);
+ }
+ for (int k = 0; k < num_col_layers; k++) {
+ /* TODO Put the conversion outside the loop */
+ ushort scol[4];
+ particle_pack_mcol(
+ (is_simple && is_child) ?
+ &(*r_parent_mcol)[psys->child[i].parent][k] : &mcol[k],
+ scol);
+ GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
+ }
+ if (!is_simple) {
+ MEM_freeN(uv);
+ MEM_freeN(mcol);
+ }
+ }
+ /* Finish the segment and add restart primitive. */
+ GPU_indexbuf_add_generic_vert(elb, curr_point);
+ GPU_indexbuf_add_primitive_restart(elb);
+ curr_point++;
+ }
+ return curr_point;
+}
+
+static void particle_batch_cache_fill_segments_proc_pos(
+ ParticleCacheKey **path_cache,
+ const int num_path_keys,
+ GPUVertBufRaw *attr_step)
+{
+ for (int i = 0; i < num_path_keys; i++) {
+ ParticleCacheKey *path = path_cache[i];
+ if (path->segments <= 0) {
+ continue;
+ }
+ float total_len = 0.0f;
+ float *co_prev = NULL, *seg_data_first;
+ for (int j = 0; j <= path->segments; j++) {
+ float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
+ copy_v3_v3(seg_data, path[j].co);
+ if (co_prev) {
+ total_len += len_v3v3(co_prev, path[j].co);
+ }
+ else {
+ seg_data_first = seg_data;
+ }
+ seg_data[3] = total_len;
+ co_prev = path[j].co;
+ }
+ if (total_len > 0.0f) {
+ /* Divide by total length to have a [0-1] number. */
+ for (int j = 0; j <= path->segments; j++, seg_data_first += 4) {
+ seg_data_first[3] /= total_len;
+ }
+ }
+ }
+}
+
+static float particle_key_select_ratio(const PTCacheEdit *edit, int strand, float t)
+{
+ const PTCacheEditPoint *point = &edit->points[strand];
+ float edit_key_seg_t = 1.0f / (point->totkey - 1);
+ if (t == 1.0) {
+ return (point->keys[point->totkey - 1].flag & PEK_SELECT) ? 1.0f : 0.0;
+ }
+ else {
+ float interp = t / edit_key_seg_t;
+ int index = (int)interp;
+ interp -= floorf(interp); /* Time between 2 edit key */
+ float s1 = (point->keys[index].flag & PEK_SELECT) ? 1.0f : 0.0;
+ float s2 = (point->keys[index + 1].flag & PEK_SELECT) ? 1.0f : 0.0;
+ return s1 + interp * (s2 - s1);
+ }
+}
+
+static float particle_key_weight(const ParticleData *particle, int strand, float t)
+{
+ const ParticleData *part = particle + strand;
+ const HairKey *hkeys = part->hair;
+ float edit_key_seg_t = 1.0f / (part->totkey - 1);
+ if (t == 1.0) {
+ return hkeys[part->totkey - 1].weight;
+ }
+ else {
+ float interp = t / edit_key_seg_t;
+ int index = (int)interp;
+ interp -= floorf(interp); /* Time between 2 edit key */
+ float s1 = hkeys[index].weight;
+ float s2 = hkeys[index + 1].weight;
+ return s1 + interp * (s2 - s1);
+ }
+}
+
+static int particle_batch_cache_fill_segments_edit(
+ const PTCacheEdit *edit, /* NULL for weight data */
+ const ParticleData *particle, /* NULL for select data */
+ ParticleCacheKey **path_cache,
+ const int start_index,
+ const int num_path_keys,
+ GPUIndexBufBuilder *elb,
+ GPUVertBufRaw *attr_step)
+{
+ int curr_point = start_index;
+ for (int i = 0; i < num_path_keys; i++) {
+ ParticleCacheKey *path = path_cache[i];
+ if (path->segments <= 0) {
+ continue;
+ }
+ for (int j = 0; j <= path->segments; j++) {
+ EditStrandData *seg_data = (EditStrandData *)GPU_vertbuf_raw_step(attr_step);
+ copy_v3_v3(seg_data->pos, path[j].co);
+ float strand_t = (float)(j) / path->segments;
+ if (particle) {
+ float weight = particle_key_weight(particle, i, strand_t);
+ /* NaN or unclamped become 0xFF */
+ seg_data->color = (uchar)((weight <= 1.0f) ? 0xFE * weight : 0xFF);
+ }
+ else {
+ float selected = particle_key_select_ratio(edit, i, strand_t);
+ seg_data->color = (uchar)(0xFF * selected);
+ }
+ GPU_indexbuf_add_generic_vert(elb, curr_point);
+ curr_point++;
+ }
+ /* Finish the segment and add restart primitive. */
+ GPU_indexbuf_add_primitive_restart(elb);
+ }
+ return curr_point;
+}
+
+static int particle_batch_cache_fill_segments_indices(
+ ParticleCacheKey **path_cache,
+ const int start_index,
+ const int num_path_keys,
+ const int res,
+ GPUIndexBufBuilder *elb)
+{
+ int curr_point = start_index;
+ for (int i = 0; i < num_path_keys; i++) {
+ ParticleCacheKey *path = path_cache[i];
+ if (path->segments <= 0) {
+ continue;
+ }
+ for (int k = 0; k < res; k++) {
+ GPU_indexbuf_add_generic_vert(elb, curr_point++);
+ }
+ GPU_indexbuf_add_primitive_restart(elb);
+ }
+ return curr_point;
+}
+
+static int particle_batch_cache_fill_strands_data(
+ ParticleSystem *psys,
+ ParticleSystemModifierData *psmd,
+ ParticleCacheKey **path_cache,
+ const ParticleSource particle_source,
+ const int start_index,
+ const int num_path_keys,
+ GPUVertBufRaw *data_step,
+ float (***r_parent_uvs)[2], GPUVertBufRaw *uv_step, MTFace **mtfaces, int num_uv_layers,
+ MCol ***r_parent_mcol, GPUVertBufRaw *col_step, MCol **mcols, int num_col_layers)
+{
+ const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
+ const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
+ if (is_simple && *r_parent_uvs == NULL) {
+ /* TODO(sergey): For edit mode it should be edit->totcached. */
+ *r_parent_uvs = MEM_callocN(
+ sizeof(*r_parent_uvs) * psys->totpart,
+ "Parent particle UVs");
+ }
+ if (is_simple && *r_parent_mcol == NULL) {
+ *r_parent_mcol = MEM_callocN(
+ sizeof(*r_parent_mcol) * psys->totpart,
+ "Parent particle MCol");
+ }
+ int curr_point = start_index;
+ for (int i = 0; i < num_path_keys; i++) {
+ ParticleCacheKey *path = path_cache[i];
+ if (path->segments <= 0) {
+ continue;
+ }
+
+ uint *seg_data = (uint *)GPU_vertbuf_raw_step(data_step);
+ *seg_data = (curr_point & 0xFFFFFF) | (path->segments << 24);
+ curr_point += path->segments + 1;
+
+ if (psmd != NULL) {
+ float (*uv)[2] = NULL;
+ MCol *mcol = NULL;
+
+ particle_calculate_uvs(
+ psys, psmd,
+ is_simple, num_uv_layers,
+ is_child ? psys->child[i].parent : i,
+ is_child ? i : -1,
+ mtfaces,
+ *r_parent_uvs, &uv);
+
+ particle_calculate_mcol(
+ psys, psmd,
+ is_simple, num_col_layers,
+ is_child ? psys->child[i].parent : i,
+ is_child ? i : -1,
+ mcols,
+ *r_parent_mcol, &mcol);
+
+ for (int k = 0; k < num_uv_layers; k++) {
+ float *t_uv = (float *)GPU_vertbuf_raw_step(uv_step + k);
+ copy_v2_v2(t_uv, uv[k]);
+ }
+ for (int k = 0; k < num_col_layers; k++) {
+ ushort *scol = (ushort *)GPU_vertbuf_raw_step(col_step + k);
+ particle_pack_mcol(
+ (is_simple && is_child) ?
+ &(*r_parent_mcol)[psys->child[i].parent][k] : &mcol[k],
+ scol);
+ }
+ if (!is_simple) {
+ MEM_freeN(uv);
+ MEM_freeN(mcol);
+ }
+ }
+ }
+ return curr_point;
+}
+
+static void particle_batch_cache_ensure_procedural_final_points(
+ ParticleHairCache *cache,
+ int subdiv)
+{
+ /* Same format as point_tex. */
+ GPUVertFormat format = { 0 };
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format(&format);
+
+ /* Create a destination buffer for the transform feedback. Sized appropriately */
+ /* Those are points! not line segments. */
+ GPU_vertbuf_data_alloc(cache->final[subdiv].proc_buf, cache->final[subdiv].strands_res * cache->strands_len);
+
+ /* Create vbo immediately to bind to texture buffer. */
+ GPU_vertbuf_use(cache->final[subdiv].proc_buf);
+
+ cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf(cache->final[subdiv].proc_buf);
+}
+
+static void particle_batch_cache_ensure_procedural_strand_data(
+ PTCacheEdit *edit,
+ ParticleSystem *psys,
+ ModifierData *md,
+ ParticleHairCache *cache)
+{
+ int active_uv = 0;
+ int active_col = 0;
+
+ ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
+
+ if (psmd != NULL && psmd->mesh_final != NULL) {
+ if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) {
+ cache->num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV);
+ active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
+ }
+ if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) {
+ cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL);
+ active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL);
+ }
+ }
+
+ GPUVertBufRaw data_step;
+ GPUVertBufRaw uv_step[MAX_MTFACE];
+ GPUVertBufRaw col_step[MAX_MCOL];
+
+ MTFace *mtfaces[MAX_MTFACE] = {NULL};
+ MCol *mcols[MAX_MCOL] = {NULL};
+ float (**parent_uvs)[2] = NULL;
+ MCol **parent_mcol = NULL;
+
+ GPUVertFormat format_data = {0};
+ uint data_id = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
+
+ GPUVertFormat format_uv = {0};
+ uint uv_id = GPU_vertformat_attr_add(&format_uv, "uv", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPUVertFormat format_col = {0};
+ uint col_id = GPU_vertformat_attr_add(&format_col, "col", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ memset(cache->uv_layer_names, 0, sizeof(cache->uv_layer_names));
+ memset(cache->col_layer_names, 0, sizeof(cache->col_layer_names));
+
+ /* Strand Data */
+ cache->proc_strand_buf = GPU_vertbuf_create_with_format(&format_data);
+ GPU_vertbuf_data_alloc(cache->proc_strand_buf, cache->strands_len);
+ GPU_vertbuf_attr_get_raw_data(cache->proc_strand_buf, data_id, &data_step);
+
+ /* UV layers */
+ for (int i = 0; i < cache->num_uv_layers; i++) {
+ cache->proc_uv_buf[i] = GPU_vertbuf_create_with_format(&format_uv);
+ GPU_vertbuf_data_alloc(cache->proc_uv_buf[i], cache->strands_len);
+ GPU_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]);
+
+ const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
+ uint hash = BLI_ghashutil_strhash_p(name);
+ int n = 0;
+ BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "u%u", hash);
+ BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash);
+
+ if (i == active_uv) {
+ BLI_snprintf(cache->uv_layer_names[i][n], MAX_LAYER_NAME_LEN, "u");
+ }
+ }
+ /* Vertex colors */
+ for (int i = 0; i < cache->num_col_layers; i++) {
+ cache->proc_col_buf[i] = GPU_vertbuf_create_with_format(&format_col);
+ GPU_vertbuf_data_alloc(cache->proc_col_buf[i], cache->strands_len);
+ GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]);
+
+ const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i);
+ uint hash = BLI_ghashutil_strhash_p(name);
+ int n = 0;
+ BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "c%u", hash);
+
+ /* We only do vcols auto name that are not overridden by uvs */
+ if (CustomData_get_named_layer_index(&psmd->mesh_final->ldata, CD_MLOOPUV, name) == -1) {
+ BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash);
+ }
+
+ if (i == active_col) {
+ BLI_snprintf(cache->col_layer_names[i][n], MAX_LAYER_NAME_LEN, "c");
+ }
+ }
+
+ if (cache->num_uv_layers || cache->num_col_layers) {
+ BKE_mesh_tessface_ensure(psmd->mesh_final);
+ if (cache->num_uv_layers) {
+ for (int j = 0; j < cache->num_uv_layers; j++) {
+ mtfaces[j] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, j);
+ }
+ }
+ if (cache->num_col_layers) {
+ for (int j = 0; j < cache->num_col_layers; j++) {
+ mcols[j] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j);
+ }
+ }
+ }
+
+ if (edit != NULL && edit->pathcache != NULL) {
+ particle_batch_cache_fill_strands_data(
+ psys, psmd, edit->pathcache, PARTICLE_SOURCE_PARENT,
+ 0, edit->totcached,
+ &data_step,
+ &parent_uvs, uv_step, (MTFace **)mtfaces, cache->num_uv_layers,
+ &parent_mcol, col_step, (MCol **)mcols, cache->num_col_layers);
+ }
+ else {
+ int curr_point = 0;
+ if ((psys->pathcache != NULL) &&
+ (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
+ {
+ curr_point = particle_batch_cache_fill_strands_data(
+ psys, psmd, psys->pathcache, PARTICLE_SOURCE_PARENT,
+ 0, psys->totpart,
+ &data_step,
+ &parent_uvs, uv_step, (MTFace **)mtfaces, cache->num_uv_layers,
+ &parent_mcol, col_step, (MCol **)mcols, cache->num_col_layers);
+ }
+ if (psys->childcache) {
+ const int child_count = psys->totchild * psys->part->disp / 100;
+ curr_point = particle_batch_cache_fill_strands_data(
+ psys, psmd, psys->childcache, PARTICLE_SOURCE_CHILDREN,
+ curr_point, child_count,
+ &data_step,
+ &parent_uvs, uv_step, (MTFace **)mtfaces, cache->num_uv_layers,
+ &parent_mcol, col_step, (MCol **)mcols, cache->num_col_layers);
+ }
+ }
+ /* Cleanup. */
+ if (parent_uvs != NULL) {
+ /* TODO(sergey): For edit mode it should be edit->totcached. */
+ for (int i = 0; i < psys->totpart; i++) {
+ MEM_SAFE_FREE(parent_uvs[i]);
+ }
+ MEM_freeN(parent_uvs);
+ }
+ if (parent_mcol != NULL) {
+ for (int i = 0; i < psys->totpart; i++) {
+ MEM_SAFE_FREE(parent_mcol[i]);
+ }
+ MEM_freeN(parent_mcol);
+ }
+
+ /* Create vbo immediately to bind to texture buffer. */
+ GPU_vertbuf_use(cache->proc_strand_buf);
+ cache->strand_tex = GPU_texture_create_from_vertbuf(cache->proc_strand_buf);
+
+ for (int i = 0; i < cache->num_uv_layers; i++) {
+ GPU_vertbuf_use(cache->proc_uv_buf[i]);
+ cache->uv_tex[i] = GPU_texture_create_from_vertbuf(cache->proc_uv_buf[i]);
+ }
+ for (int i = 0; i < cache->num_col_layers; i++) {
+ GPU_vertbuf_use(cache->proc_col_buf[i]);
+ cache->col_tex[i] = GPU_texture_create_from_vertbuf(cache->proc_col_buf[i]);
+ }
+}
+
+static void particle_batch_cache_ensure_procedural_indices(
+ PTCacheEdit *edit,
+ ParticleSystem *psys,
+ ParticleHairCache *cache,
+ int thickness_res,
+ int subdiv)
+{
+ BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
+
+ if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) {
+ return;
+ }
+
+ int verts_per_hair = cache->final[subdiv].strands_res * thickness_res;
+ /* +1 for primitive restart */
+ int element_count = (verts_per_hair + 1) * cache->strands_len;
+ GPUPrimType prim_type = (thickness_res == 1) ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP;
+
+ static GPUVertFormat format = { 0 };
+ GPU_vertformat_clear(&format);
+
+ /* initialize vertex format */
+ GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 1);
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init_ex(&elb, prim_type, element_count, element_count, true);
+
+ if (edit != NULL && edit->pathcache != NULL) {
+ particle_batch_cache_fill_segments_indices(
+ edit->pathcache, 0, edit->totcached, verts_per_hair, &elb);
+ }
+ else {
+ int curr_point = 0;
+ if ((psys->pathcache != NULL) &&
+ (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
+ {
+ curr_point = particle_batch_cache_fill_segments_indices(
+ psys->pathcache, 0, psys->totpart, verts_per_hair, &elb);
+ }
+ if (psys->childcache) {
+ const int child_count = psys->totchild * psys->part->disp / 100;
+ curr_point = particle_batch_cache_fill_segments_indices(
+ psys->childcache, curr_point, child_count, verts_per_hair, &elb);
+ }
+ }
+
+ cache->final[subdiv].proc_hairs[thickness_res - 1] = GPU_batch_create_ex(
+ prim_type,
+ vbo,
+ GPU_indexbuf_build(&elb),
+ GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+}
+
+static void particle_batch_cache_ensure_procedural_pos(
+ PTCacheEdit *edit,
+ ParticleSystem *psys,
+ ParticleHairCache *cache)
+{
+ if (cache->proc_point_buf != NULL) {
+ return;
+ }
+
+ /* initialize vertex format */
+ GPUVertFormat format = {0};
+ uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ cache->proc_point_buf = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(cache->proc_point_buf, cache->point_len);
+
+ GPUVertBufRaw pos_step;
+ GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step);
+
+ if (edit != NULL && edit->pathcache != NULL) {
+ particle_batch_cache_fill_segments_proc_pos(
+ edit->pathcache,
+ edit->totcached,
+ &pos_step);
+ }
+ else {
+ if ((psys->pathcache != NULL) &&
+ (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
+ {
+ particle_batch_cache_fill_segments_proc_pos(
+ psys->pathcache,
+ psys->totpart,
+ &pos_step);
+ }
+ if (psys->childcache) {
+ const int child_count = psys->totchild * psys->part->disp / 100;
+ particle_batch_cache_fill_segments_proc_pos(
+ psys->childcache,
+ child_count,
+ &pos_step);
+ }
+ }
+
+ /* Create vbo immediately to bind to texture buffer. */
+ GPU_vertbuf_use(cache->proc_point_buf);
+
+ cache->point_tex = GPU_texture_create_from_vertbuf(cache->proc_point_buf);
+}
+
+static void particle_batch_cache_ensure_pos_and_seg(
+ PTCacheEdit *edit,
+ ParticleSystem *psys,
+ ModifierData *md,
+ ParticleHairCache *hair_cache)
+{
+ if (hair_cache->pos != NULL && hair_cache->indices != NULL) {
+ return;
+ }
+
+ int curr_point = 0;
+ ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
+
+ GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
+ GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
+
+ static GPUVertFormat format = { 0 };
+ HairAttributeID attr_id;
+ uint *uv_id = NULL;
+ uint *col_id = NULL;
+ int num_uv_layers = 0;
+ int num_col_layers = 0;
+ int active_uv = 0;
+ int active_col = 0;
+ MTFace **mtfaces = NULL;
+ MCol **mcols = NULL;
+ float (**parent_uvs)[2] = NULL;
+ MCol **parent_mcol = NULL;
+
+ if (psmd != NULL) {
+ if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) {
+ num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV);
+ active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
+ }
+ if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) {
+ num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL);
+ active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL);
+ }
+ }
+
+ GPU_vertformat_clear(&format);
+
+ /* initialize vertex format */
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.tan = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ attr_id.ind = GPU_vertformat_attr_add(&format, "ind", GPU_COMP_I32, 1, GPU_FETCH_INT);
+
+ if (psmd) {
+ uv_id = MEM_mallocN(sizeof(*uv_id) * num_uv_layers, "UV attrib format");
+ col_id = MEM_mallocN(sizeof(*col_id) * num_col_layers, "Col attrib format");
+
+ for (int i = 0; i < num_uv_layers; i++) {
+ const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
+ char uuid[32];
+
+ BLI_snprintf(uuid, sizeof(uuid), "u%u", BLI_ghashutil_strhash_p(name));
+ uv_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ if (i == active_uv) {
+ GPU_vertformat_alias_add(&format, "u");
+ }
+ }
+
+ for (int i = 0; i < num_uv_layers; i++) {
+ const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
+ char uuid[32];
+
+ BLI_snprintf(uuid, sizeof(uuid), "c%u", BLI_ghashutil_strhash_p(name));
+ col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ if (i == active_col) {
+ GPU_vertformat_alias_add(&format, "c");
+ }
+ }
+ }
+
+ hair_cache->pos = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len);
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init_ex(
+ &elb,
+ GPU_PRIM_LINE_STRIP,
+ hair_cache->elems_len, hair_cache->point_len,
+ true);
+
+ if (num_uv_layers || num_col_layers) {
+ BKE_mesh_tessface_ensure(psmd->mesh_final);
+ if (num_uv_layers) {
+ mtfaces = MEM_mallocN(sizeof(*mtfaces) * num_uv_layers, "Faces UV layers");
+ for (int i = 0; i < num_uv_layers; i++) {
+ mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, i);
+ }
+ }
+ if (num_col_layers) {
+ mcols = MEM_mallocN(sizeof(*mcols) * num_col_layers, "Color layers");
+ for (int i = 0; i < num_col_layers; i++) {
+ mcols[i] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, i);
+ }
+ }
+ }
+
+ if (edit != NULL && edit->pathcache != NULL) {
+ curr_point = particle_batch_cache_fill_segments(
+ psys, psmd, edit->pathcache, PARTICLE_SOURCE_PARENT,
+ 0, 0, edit->totcached,
+ num_uv_layers, num_col_layers, mtfaces, mcols, uv_id, col_id, &parent_uvs, &parent_mcol,
+ &elb, &attr_id, hair_cache);
+ }
+ else {
+ if ((psys->pathcache != NULL) &&
+ (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
+ {
+ curr_point = particle_batch_cache_fill_segments(
+ psys, psmd, psys->pathcache, PARTICLE_SOURCE_PARENT,
+ 0, 0, psys->totpart,
+ num_uv_layers, num_col_layers, mtfaces, mcols, uv_id, col_id, &parent_uvs, &parent_mcol,
+ &elb, &attr_id, hair_cache);
+ }
+ if (psys->childcache != NULL) {
+ const int child_count = psys->totchild * psys->part->disp / 100;
+ curr_point = particle_batch_cache_fill_segments(
+ psys, psmd, psys->childcache, PARTICLE_SOURCE_CHILDREN,
+ psys->totpart, curr_point, child_count,
+ num_uv_layers, num_col_layers, mtfaces, mcols, uv_id, col_id, &parent_uvs, &parent_mcol,
+ &elb, &attr_id, hair_cache);
+ }
+ }
+ /* Cleanup. */
+ if (parent_uvs != NULL) {
+ /* TODO(sergey): For edit mode it should be edit->totcached. */
+ for (int i = 0; i < psys->totpart; i++) {
+ MEM_SAFE_FREE(parent_uvs[i]);
+ }
+ MEM_freeN(parent_uvs);
+ }
+ if (parent_mcol != NULL) {
+ for (int i = 0; i < psys->totpart; i++) {
+ MEM_SAFE_FREE(parent_mcol[i]);
+ }
+ MEM_freeN(parent_mcol);
+ }
+ if (num_uv_layers) {
+ MEM_freeN(mtfaces);
+ }
+ if (num_col_layers) {
+ MEM_freeN(mcols);
+ }
+ if (psmd != NULL) {
+ MEM_freeN(uv_id);
+ }
+ hair_cache->indices = GPU_indexbuf_build(&elb);
+}
+
+static void particle_batch_cache_ensure_pos(
+ Object *object,
+ ParticleSystem *psys,
+ ParticlePointCache *point_cache)
+{
+ if (point_cache->pos != NULL) {
+ return;
+ }
+
+ static GPUVertFormat format = { 0 };
+ static uint pos_id, rot_id, val_id;
+ int i, curr_point;
+ ParticleData *pa;
+ ParticleKey state;
+ ParticleSimulationData sim = {NULL};
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ sim.depsgraph = draw_ctx->depsgraph;
+ sim.scene = draw_ctx->scene;
+ sim.ob = object;
+ sim.psys = psys;
+ sim.psmd = psys_get_modifier(object, psys);
+
+ if (psys->part->phystype == PART_PHYS_KEYED) {
+ if (psys->flag & PSYS_KEYED) {
+ psys_count_keyed_targets(&sim);
+ if (psys->totkeyed == 0)
+ return;
+ }
+ }
+
+ GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
+
+ if (format.attr_len == 0) {
+ /* initialize vertex format */
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ rot_id = GPU_vertformat_attr_add(&format, "rot", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ val_id = GPU_vertformat_attr_add(&format, "val", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ point_cache->pos = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(point_cache->pos, psys->totpart);
+
+ for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
+ state.time = DEG_get_ctime(draw_ctx->depsgraph);
+ if (!psys_get_particle_state(&sim, i, &state, 0)) {
+ continue;
+ }
+
+ float val;
+
+ GPU_vertbuf_attr_set(point_cache->pos, pos_id, curr_point, pa->state.co);
+ GPU_vertbuf_attr_set(point_cache->pos, rot_id, curr_point, pa->state.rot);
+
+ switch (psys->part->draw_col) {
+ case PART_DRAW_COL_VEL:
+ val = len_v3(pa->state.vel) / psys->part->color_vec_max;
+ break;
+ case PART_DRAW_COL_ACC:
+ val = len_v3v3(
+ pa->state.vel,
+ pa->prev_state.vel) / ((pa->state.time - pa->prev_state.time) * psys->part->color_vec_max);
+ break;
+ default:
+ val = -1.0f;
+ break;
+ }
+
+ GPU_vertbuf_attr_set(point_cache->pos, val_id, curr_point, &val);
+
+ curr_point++;
+ }
+
+ if (curr_point != psys->totpart) {
+ GPU_vertbuf_data_resize(point_cache->pos, curr_point);
+ }
+}
+
+static void drw_particle_update_ptcache_edit(
+ Object *object_eval,
+ ParticleSystem *psys,
+ PTCacheEdit *edit)
+{
+ if (edit->psys == NULL) {
+ return;
+ }
+ /* NOTE: Get flag from particle system coming from drawing object.
+ * this is where depsgraph will be setting flags to.
+ */
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
+ Object *object_orig = DEG_get_original_object(object_eval);
+ if (psys->flag & PSYS_HAIR_UPDATED) {
+ PE_update_object(draw_ctx->depsgraph, scene_orig, object_orig, 0);
+ psys->flag &= ~PSYS_HAIR_UPDATED;
+ }
+ if (edit->pathcache == NULL) {
+ Depsgraph *depsgraph = draw_ctx->depsgraph;
+ psys_cache_edit_paths(
+ depsgraph,
+ scene_orig, object_orig,
+ edit,
+ DEG_get_ctime(depsgraph),
+ DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ }
+}
+
+static void drw_particle_update_ptcache(
+ Object *object_eval,
+ ParticleSystem *psys)
+{
+ if ((object_eval->mode & OB_MODE_PARTICLE_EDIT) == 0) {
+ return;
+ }
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
+ Object *object_orig = DEG_get_original_object(object_eval);
+ PTCacheEdit *edit = PE_create_current(
+ draw_ctx->depsgraph, scene_orig, object_orig);
+ if (edit != NULL) {
+ drw_particle_update_ptcache_edit(object_eval, psys, edit);
+ }
+}
+
+typedef struct ParticleDrawSource {
+ Object *object;
+ ParticleSystem *psys;
+ ModifierData *md;
+ PTCacheEdit *edit;
+} ParticleDrawSource;
+
+static void drw_particle_get_hair_source(
+ Object *object,
+ ParticleSystem *psys,
+ ModifierData *md,
+ PTCacheEdit *edit,
+ ParticleDrawSource *r_draw_source)
+{
+ r_draw_source->object = object;
+ r_draw_source->psys = psys;
+ r_draw_source->md = md;
+ r_draw_source->edit = edit;
+ if ((object->mode & OB_MODE_PARTICLE_EDIT) != 0) {
+ r_draw_source->object = DEG_get_original_object(object);
+ r_draw_source->psys = psys_orig_get(psys);
+ }
+}
+
+GPUBatch *DRW_particles_batch_cache_get_hair(
+ Object *object,
+ ParticleSystem *psys,
+ ModifierData *md)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+ if (cache->hair.hairs == NULL) {
+ drw_particle_update_ptcache(object, psys);
+ ParticleDrawSource source;
+ drw_particle_get_hair_source(object, psys, md, NULL, &source);
+ ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
+ particle_batch_cache_ensure_pos_and_seg(source.edit, source.psys, source.md, &cache->hair);
+ cache->hair.hairs = GPU_batch_create(
+ GPU_PRIM_LINE_STRIP,
+ cache->hair.pos,
+ cache->hair.indices);
+ }
+ return cache->hair.hairs;
+}
+
+GPUBatch *DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+
+ if (cache->point.points == NULL) {
+ particle_batch_cache_ensure_pos(object, psys, &cache->point);
+ cache->point.points = GPU_batch_create(GPU_PRIM_POINTS, cache->point.pos, NULL);
+ }
+
+ return cache->point.points;
+}
+
+static void particle_batch_cache_ensure_edit_pos_and_seg(
+ PTCacheEdit *edit,
+ ParticleSystem *psys,
+ ModifierData *UNUSED(md),
+ ParticleHairCache *hair_cache,
+ bool use_weight)
+{
+ if (hair_cache->pos != NULL && hair_cache->indices != NULL) {
+ return;
+ }
+
+ ParticleData *particle = (use_weight) ? psys->particles : NULL;
+
+ GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
+ GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
+
+ GPUVertBufRaw data_step;
+ GPUIndexBufBuilder elb;
+ uint pos_id, color_id;
+ GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
+
+ hair_cache->pos = GPU_vertbuf_create_with_format(edit_point_format);
+ GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len);
+ GPU_vertbuf_attr_get_raw_data(hair_cache->pos, pos_id, &data_step);
+
+ GPU_indexbuf_init_ex(
+ &elb,
+ GPU_PRIM_LINE_STRIP,
+ hair_cache->elems_len, hair_cache->point_len,
+ true);
+
+ if (edit != NULL && edit->pathcache != NULL) {
+ particle_batch_cache_fill_segments_edit(
+ edit, particle, edit->pathcache,
+ 0, edit->totcached,
+ &elb, &data_step);
+ }
+ else {
+ BLI_assert(!"Hairs are not in edit mode!");
+ }
+ hair_cache->indices = GPU_indexbuf_build(&elb);
+}
+
+GPUBatch *DRW_particles_batch_cache_get_edit_strands(
+ Object *object,
+ ParticleSystem *psys,
+ PTCacheEdit *edit,
+ bool use_weight)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+ if (cache->edit_is_weight != use_weight) {
+ GPU_VERTBUF_DISCARD_SAFE(cache->edit_hair.pos);
+ GPU_BATCH_DISCARD_SAFE(cache->edit_hair.hairs);
+ }
+ if (cache->edit_hair.hairs != NULL) {
+ return cache->edit_hair.hairs;
+ }
+ drw_particle_update_ptcache_edit(object, psys, edit);
+ ensure_seg_pt_count(edit, psys, &cache->edit_hair);
+ particle_batch_cache_ensure_edit_pos_and_seg(edit, psys, NULL, &cache->edit_hair, use_weight);
+ cache->edit_hair.hairs = GPU_batch_create(
+ GPU_PRIM_LINE_STRIP,
+ cache->edit_hair.pos,
+ cache->edit_hair.indices);
+ cache->edit_is_weight = use_weight;
+ return cache->edit_hair.hairs;
+}
+
+static void ensure_edit_inner_points_count(
+ const PTCacheEdit *edit,
+ ParticleBatchCache *cache)
+{
+ if (cache->edit_inner_pos != NULL) {
+ return;
+ }
+ cache->edit_inner_point_len = 0;
+ for (int point_index = 0; point_index < edit->totpoint; point_index++) {
+ const PTCacheEditPoint *point = &edit->points[point_index];
+ BLI_assert(point->totkey >= 1);
+ cache->edit_inner_point_len += (point->totkey - 1);
+ }
+}
+
+static void particle_batch_cache_ensure_edit_inner_pos(
+ PTCacheEdit *edit,
+ ParticleBatchCache *cache)
+{
+ if (cache->edit_inner_pos != NULL) {
+ return;
+ }
+
+ uint pos_id, color_id;
+ GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
+
+ cache->edit_inner_pos = GPU_vertbuf_create_with_format(edit_point_format);
+ GPU_vertbuf_data_alloc(cache->edit_inner_pos, cache->edit_inner_point_len);
+
+ int global_key_index = 0;
+ for (int point_index = 0; point_index < edit->totpoint; point_index++) {
+ const PTCacheEditPoint *point = &edit->points[point_index];
+ for (int key_index = 0; key_index < point->totkey - 1; key_index++) {
+ PTCacheEditKey *key = &point->keys[key_index];
+ uchar color = (key->flag & PEK_SELECT) ? 0xFF : 0x00;
+ GPU_vertbuf_attr_set(cache->edit_inner_pos, pos_id, global_key_index, key->world_co);
+ GPU_vertbuf_attr_set(cache->edit_inner_pos, color_id, global_key_index, &color);
+ global_key_index++;
+ }
+ }
+}
+
+GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(
+ Object *object,
+ ParticleSystem *psys,
+ PTCacheEdit *edit)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+ if (cache->edit_inner_points != NULL) {
+ return cache->edit_inner_points;
+ }
+ drw_particle_update_ptcache_edit(object, psys, edit);
+ ensure_edit_inner_points_count(edit, cache);
+ particle_batch_cache_ensure_edit_inner_pos(edit, cache);
+ cache->edit_inner_points = GPU_batch_create(
+ GPU_PRIM_POINTS,
+ cache->edit_inner_pos,
+ NULL);
+ return cache->edit_inner_points;
+}
+
+static void ensure_edit_tip_points_count(
+ const PTCacheEdit *edit,
+ ParticleBatchCache *cache)
+{
+ if (cache->edit_tip_pos != NULL) {
+ return;
+ }
+ cache->edit_tip_point_len = edit->totpoint;
+}
+
+static void particle_batch_cache_ensure_edit_tip_pos(
+ PTCacheEdit *edit,
+ ParticleBatchCache *cache)
+{
+ if (cache->edit_tip_pos != NULL) {
+ return;
+ }
+
+ uint pos_id, color_id;
+ GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
+
+ cache->edit_tip_pos = GPU_vertbuf_create_with_format(edit_point_format);
+ GPU_vertbuf_data_alloc(cache->edit_tip_pos, cache->edit_tip_point_len);
+
+ for (int point_index = 0; point_index < edit->totpoint; point_index++) {
+ const PTCacheEditPoint *point = &edit->points[point_index];
+ PTCacheEditKey *key = &point->keys[point->totkey - 1];
+ uchar color = (key->flag & PEK_SELECT) ? 0xFF : 0x00;
+ GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, point_index, key->world_co);
+ GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, point_index, &color);
+ }
+}
+
+GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(
+ Object *object,
+ ParticleSystem *psys,
+ PTCacheEdit *edit)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+ if (cache->edit_tip_points != NULL) {
+ return cache->edit_tip_points;
+ }
+ drw_particle_update_ptcache_edit(object, psys, edit);
+ ensure_edit_tip_points_count(edit, cache);
+ particle_batch_cache_ensure_edit_tip_pos(edit, cache);
+ cache->edit_tip_points = GPU_batch_create(
+ GPU_PRIM_POINTS,
+ cache->edit_tip_pos,
+ NULL);
+ return cache->edit_tip_points;
+}
+
+/* Ensure all textures and buffers needed for GPU accelerated drawing. */
+bool particles_ensure_procedural_data(
+ Object *object,
+ ParticleSystem *psys,
+ ModifierData *md,
+ ParticleHairCache **r_hair_cache,
+ int subdiv,
+ int thickness_res)
+{
+ bool need_ft_update = false;
+
+ drw_particle_update_ptcache(object, psys);
+
+ ParticleDrawSource source;
+ drw_particle_get_hair_source(object, psys, md, NULL, &source);
+
+ ParticleSettings *part = source.psys->part;
+ ParticleBatchCache *cache = particle_batch_cache_get(source.psys);
+ *r_hair_cache = &cache->hair;
+
+ (*r_hair_cache)->final[subdiv].strands_res = 1 << (part->draw_step + subdiv);
+
+ /* Refreshed on combing and simulation. */
+ if ((*r_hair_cache)->proc_point_buf == NULL) {
+ ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
+ particle_batch_cache_ensure_procedural_pos(source.edit, source.psys, &cache->hair);
+ need_ft_update = true;
+ }
+
+ /* Refreshed if active layer or custom data changes. */
+ if ((*r_hair_cache)->strand_tex == NULL) {
+ particle_batch_cache_ensure_procedural_strand_data(source.edit, source.psys, source.md, &cache->hair);
+ }
+
+ /* Refreshed only on subdiv count change. */
+ if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) {
+ particle_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv);
+ need_ft_update = true;
+ }
+ if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) {
+ particle_batch_cache_ensure_procedural_indices(source.edit, source.psys, &cache->hair, thickness_res, subdiv);
+ }
+
+ return need_ft_update;
+}
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
new file mode 100644
index 00000000000..4d33e6ed802
--- /dev/null
+++ b/source/blender/draw/intern/draw_common.c
@@ -0,0 +1,1009 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_common.c
+ * \ingroup draw
+ */
+
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "UI_resources.h"
+
+#include "BKE_object.h"
+#include "BKE_global.h"
+#include "BKE_colorband.h"
+
+#include "draw_common.h"
+
+#if 0
+#define UI_COLOR_RGB_FROM_U8(r, g, b, v4) \
+ ARRAY_SET_ITEMS(v4, (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, 1.0)
+#endif
+#define UI_COLOR_RGBA_FROM_U8(r, g, b, a, v4) \
+ ARRAY_SET_ITEMS(v4, (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f)
+
+/* Colors & Constant */
+GlobalsUboStorage ts;
+struct GPUUniformBuffer *globals_ubo = NULL;
+struct GPUTexture *globals_ramp = NULL;
+struct GPUTexture *globals_weight_ramp = NULL;
+
+static bool weight_ramp_custom = false;
+static ColorBand weight_ramp_copy;
+
+static struct GPUTexture *DRW_create_weight_colorramp_texture(void);
+
+void DRW_globals_update(void)
+{
+ UI_GetThemeColor4fv(TH_WIRE, ts.colorWire);
+ UI_GetThemeColor4fv(TH_WIRE_EDIT, ts.colorWireEdit);
+ UI_GetThemeColor4fv(TH_ACTIVE, ts.colorActive);
+ UI_GetThemeColor4fv(TH_SELECT, ts.colorSelect);
+ UI_GetThemeColor4fv(TH_TRANSFORM, ts.colorTransform);
+ UI_COLOR_RGBA_FROM_U8(0x88, 0xFF, 0xFF, 155, ts.colorLibrarySelect);
+ UI_COLOR_RGBA_FROM_U8(0x55, 0xCC, 0xCC, 155, ts.colorLibrary);
+ UI_GetThemeColor4fv(TH_LAMP, ts.colorLamp);
+ UI_GetThemeColor4fv(TH_SPEAKER, ts.colorSpeaker);
+ UI_GetThemeColor4fv(TH_CAMERA, ts.colorCamera);
+ UI_GetThemeColor4fv(TH_EMPTY, ts.colorEmpty);
+ UI_GetThemeColor4fv(TH_VERTEX, ts.colorVertex);
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, ts.colorVertexSelect);
+ UI_GetThemeColor4fv(TH_VERTEX_UNREFERENCED, ts.colorVertexUnreferenced);
+ UI_COLOR_RGBA_FROM_U8(0xB0, 0x00, 0xB0, 0xFF, ts.colorVertexMissingData);
+ UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, ts.colorEditMeshActive);
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, ts.colorEdgeSelect);
+
+ UI_GetThemeColor4fv(TH_EDGE_SEAM, ts.colorEdgeSeam);
+ UI_GetThemeColor4fv(TH_EDGE_SHARP, ts.colorEdgeSharp);
+ UI_GetThemeColor4fv(TH_EDGE_CREASE, ts.colorEdgeCrease);
+ UI_GetThemeColor4fv(TH_EDGE_BEVEL, ts.colorEdgeBWeight);
+ UI_GetThemeColor4fv(TH_EDGE_FACESEL, ts.colorEdgeFaceSelect);
+ UI_GetThemeColor4fv(TH_FACE, ts.colorFace);
+ UI_GetThemeColor4fv(TH_FACE_SELECT, ts.colorFaceSelect);
+ UI_GetThemeColor4fv(TH_NORMAL, ts.colorNormal);
+ UI_GetThemeColor4fv(TH_VNORMAL, ts.colorVNormal);
+ UI_GetThemeColor4fv(TH_LNORMAL, ts.colorLNormal);
+ UI_GetThemeColor4fv(TH_FACE_DOT, ts.colorFaceDot);
+ UI_GetThemeColor4fv(TH_BACK, ts.colorBackground);
+
+#ifdef WITH_FREESTYLE
+ UI_GetThemeColor4fv(TH_FREESTYLE_EDGE_MARK, ts.colorEdgeFreestyle);
+ UI_GetThemeColor4fv(TH_FREESTYLE_FACE_MARK, ts.colorFaceFreestyle);
+#else
+ zero_v4(ts.colorEdgeFreestyle);
+ zero_v4(ts.colorFaceFreestyle);
+#endif
+
+ /* Curve */
+ UI_GetThemeColor4fv(TH_HANDLE_FREE, ts.colorHandleFree);
+ UI_GetThemeColor4fv(TH_HANDLE_AUTO, ts.colorHandleAuto);
+ UI_GetThemeColor4fv(TH_HANDLE_VECT, ts.colorHandleVect);
+ UI_GetThemeColor4fv(TH_HANDLE_ALIGN, ts.colorHandleAlign);
+ UI_GetThemeColor4fv(TH_HANDLE_AUTOCLAMP, ts.colorHandleAutoclamp);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_FREE, ts.colorHandleSelFree);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_AUTO, ts.colorHandleSelAuto);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_VECT, ts.colorHandleSelVect);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_ALIGN, ts.colorHandleSelAlign);
+ UI_GetThemeColor4fv(TH_HANDLE_SEL_AUTOCLAMP, ts.colorHandleSelAutoclamp);
+ UI_GetThemeColor4fv(TH_NURB_ULINE, ts.colorNurbUline);
+ UI_GetThemeColor4fv(TH_NURB_VLINE, ts.colorNurbVline);
+ UI_GetThemeColor4fv(TH_NURB_SEL_ULINE, ts.colorNurbSelUline);
+ UI_GetThemeColor4fv(TH_NURB_SEL_VLINE, ts.colorNurbSelVline);
+ UI_GetThemeColor4fv(TH_ACTIVE_SPLINE, ts.colorActiveSpline);
+
+ UI_GetThemeColor4fv(TH_BONE_POSE, ts.colorBonePose);
+
+ UI_GetThemeColor4fv(TH_CFRAME, ts.colorCurrentFrame);
+
+ /* Grid */
+ UI_GetThemeColorShade4fv(TH_GRID, 10, ts.colorGrid);
+ /* emphasise division lines lighter instead of darker, if background is darker than grid */
+ UI_GetThemeColorShade4fv(
+ TH_GRID,
+ (ts.colorGrid[0] + ts.colorGrid[1] + ts.colorGrid[2] + 0.12f >
+ ts.colorBackground[0] + ts.colorBackground[1] + ts.colorBackground[2]) ?
+ 20 : -10, ts.colorGridEmphasise);
+ /* Grid Axis */
+ UI_GetThemeColorBlendShade4fv(TH_GRID, TH_AXIS_X, 0.5f, -10, ts.colorGridAxisX);
+ UI_GetThemeColorBlendShade4fv(TH_GRID, TH_AXIS_Y, 0.5f, -10, ts.colorGridAxisY);
+ UI_GetThemeColorBlendShade4fv(TH_GRID, TH_AXIS_Z, 0.5f, -10, ts.colorGridAxisZ);
+
+ UI_GetThemeColorShadeAlpha4fv(TH_TRANSFORM, 0, -80, ts.colorDeselect);
+ UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, ts.colorOutline);
+ UI_GetThemeColorShadeAlpha4fv(TH_LAMP, 0, 255, ts.colorLampNoAlpha);
+
+ ts.sizeLampCenter = (U.obcenter_dia + 1.5f) * U.pixelsize;
+ ts.sizeLampCircle = U.pixelsize * 9.0f;
+ ts.sizeLampCircleShadow = ts.sizeLampCircle + U.pixelsize * 3.0f;
+
+ /* M_SQRT2 to be at least the same size of the old square */
+ ts.sizeVertex = U.pixelsize * (max_ff(1.0f, UI_GetThemeValuef(TH_VERTEX_SIZE) * (float)M_SQRT2 / 2.0f));
+ ts.sizeFaceDot = U.pixelsize * UI_GetThemeValuef(TH_FACEDOT_SIZE);
+ ts.sizeEdge = U.pixelsize * (1.0f / 2.0f); /* TODO Theme */
+ ts.sizeEdgeFix = U.pixelsize * (0.5f + 2.0f * (2.0f * (MAX2(ts.sizeVertex, ts.sizeEdge)) * (float)M_SQRT1_2));
+
+ /* Color management. */
+ if (DRW_state_is_image_render()) {
+ float *color = ts.UBO_FIRST_COLOR;
+ do {
+ /* TODO more accurate transform. */
+ srgb_to_linearrgb_v4(color, color);
+ color += 4;
+ } while (color != ts.UBO_LAST_COLOR);
+ }
+
+ if (globals_ubo == NULL) {
+ globals_ubo = DRW_uniformbuffer_create(sizeof(GlobalsUboStorage), &ts);
+ }
+
+ DRW_uniformbuffer_update(globals_ubo, &ts);
+
+ ColorBand ramp = {0};
+ float *colors;
+ int col_size;
+
+ ramp.tot = 3;
+ ramp.data[0].a = 1.0f;
+ ramp.data[0].b = 1.0f;
+ ramp.data[0].pos = 0.0f;
+ ramp.data[1].a = 1.0f;
+ ramp.data[1].g = 1.0f;
+ ramp.data[1].pos = 0.5f;
+ ramp.data[2].a = 1.0f;
+ ramp.data[2].r = 1.0f;
+ ramp.data[2].pos = 1.0f;
+
+ BKE_colorband_evaluate_table_rgba(&ramp, &colors, &col_size);
+
+ if (globals_ramp) {
+ GPU_texture_free(globals_ramp);
+ }
+ globals_ramp = GPU_texture_create_1D(col_size, GPU_RGBA8, colors, NULL);
+
+ MEM_freeN(colors);
+
+ /* Weight Painting color ramp texture */
+ bool user_weight_ramp = (U.flag & USER_CUSTOM_RANGE) != 0;
+
+ if (weight_ramp_custom != user_weight_ramp ||
+ (user_weight_ramp && memcmp(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)) != 0))
+ {
+ DRW_TEXTURE_FREE_SAFE(globals_weight_ramp);
+ }
+
+ if (globals_weight_ramp == NULL) {
+ weight_ramp_custom = user_weight_ramp;
+ memcpy(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand));
+
+ globals_weight_ramp = DRW_create_weight_colorramp_texture();
+ }
+}
+
+/* ********************************* SHGROUP ************************************* */
+
+extern char datatoc_animviz_mpath_lines_vert_glsl[];
+extern char datatoc_animviz_mpath_lines_geom_glsl[];
+extern char datatoc_animviz_mpath_points_vert_glsl[];
+
+extern char datatoc_volume_velocity_vert_glsl[];
+
+extern char datatoc_armature_axes_vert_glsl[];
+extern char datatoc_armature_sphere_solid_vert_glsl[];
+extern char datatoc_armature_sphere_solid_frag_glsl[];
+extern char datatoc_armature_sphere_outline_vert_glsl[];
+extern char datatoc_armature_envelope_solid_vert_glsl[];
+extern char datatoc_armature_envelope_solid_frag_glsl[];
+extern char datatoc_armature_envelope_outline_vert_glsl[];
+extern char datatoc_armature_envelope_distance_frag_glsl[];
+extern char datatoc_armature_shape_solid_vert_glsl[];
+extern char datatoc_armature_shape_solid_frag_glsl[];
+extern char datatoc_armature_shape_outline_vert_glsl[];
+extern char datatoc_armature_shape_outline_geom_glsl[];
+extern char datatoc_armature_stick_vert_glsl[];
+extern char datatoc_armature_stick_frag_glsl[];
+extern char datatoc_armature_dof_vert_glsl[];
+
+extern char datatoc_common_globals_lib_glsl[];
+
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
+
+extern char datatoc_object_mball_handles_vert_glsl[];
+extern char datatoc_object_empty_axes_vert_glsl[];
+
+static struct {
+ struct GPUShader *shape_outline;
+ struct GPUShader *shape_solid;
+ struct GPUShader *bone_axes;
+ struct GPUShader *bone_envelope;
+ struct GPUShader *bone_envelope_distance;
+ struct GPUShader *bone_envelope_outline;
+ struct GPUShader *bone_sphere;
+ struct GPUShader *bone_sphere_outline;
+ struct GPUShader *bone_stick;
+ struct GPUShader *bone_dofs;
+
+ struct GPUShader *mpath_line_sh;
+ struct GPUShader *mpath_points_sh;
+
+ struct GPUShader *volume_velocity_needle_sh;
+ struct GPUShader *volume_velocity_sh;
+ struct GPUShader *empty_axes_sh;
+
+ struct GPUShader *mball_handles;
+} g_shaders = {NULL};
+
+static struct {
+ struct GPUVertFormat *instance_screenspace;
+ struct GPUVertFormat *instance_color;
+ struct GPUVertFormat *instance_screen_aligned;
+ struct GPUVertFormat *instance_scaled;
+ struct GPUVertFormat *instance_sized;
+ struct GPUVertFormat *instance_outline;
+ struct GPUVertFormat *instance;
+ struct GPUVertFormat *instance_camera;
+ struct GPUVertFormat *instance_distance_lines;
+ struct GPUVertFormat *instance_spot;
+ struct GPUVertFormat *instance_bone;
+ struct GPUVertFormat *instance_bone_dof;
+ struct GPUVertFormat *instance_bone_stick;
+ struct GPUVertFormat *instance_bone_outline;
+ struct GPUVertFormat *instance_bone_envelope;
+ struct GPUVertFormat *instance_bone_envelope_distance;
+ struct GPUVertFormat *instance_bone_envelope_outline;
+ struct GPUVertFormat *instance_mball_handles;
+ struct GPUVertFormat *dynlines_color;
+} g_formats = {NULL};
+
+void DRW_globals_free(void)
+{
+ struct GPUVertFormat **format = &g_formats.instance_screenspace;
+ for (int i = 0; i < sizeof(g_formats) / sizeof(void *); ++i, ++format) {
+ MEM_SAFE_FREE(*format);
+ }
+
+ struct GPUShader **shader = &g_shaders.shape_outline;
+ for (int i = 0; i < sizeof(g_shaders) / sizeof(void *); ++i, ++shader) {
+ DRW_SHADER_FREE_SAFE(*shader);
+ }
+}
+
+DRWShadingGroup *shgroup_dynlines_flat_color(DRWPass *pass)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+
+ DRW_shgroup_instance_format(g_formats.dynlines_color, {
+ {"pos", DRW_ATTRIB_FLOAT, 3},
+ {"color", DRW_ATTRIB_FLOAT, 4}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_line_batch_create_with_format(sh, pass, g_formats.dynlines_color);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_dynlines_dashed_uniform_color(DRWPass *pass, float color[4])
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ static float dash_width = 6.0f;
+ static float dash_factor = 0.5f;
+ DRWShadingGroup *grp = DRW_shgroup_line_batch_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", color, 1);
+ DRW_shgroup_uniform_vec2(grp, "viewport_size", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_float(grp, "dash_width", &dash_width, 1);
+ DRW_shgroup_uniform_float(grp, "dash_factor", &dash_factor, 1);
+ DRW_shgroup_uniform_int_copy(grp, "colors_len", 0); /* "simple" mode */
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_dynpoints_uniform_color(DRWPass *pass, float color[4], float *size)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+
+ DRWShadingGroup *grp = DRW_shgroup_point_batch_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", color, 1);
+ DRW_shgroup_uniform_float(grp, "size", size, 1);
+ DRW_shgroup_state_enable(grp, DRW_STATE_POINT);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_groundlines_uniform_color(DRWPass *pass, float color[4])
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_GROUNDLINE);
+
+ DRWShadingGroup *grp = DRW_shgroup_point_batch_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", color, 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_groundpoints_uniform_color(DRWPass *pass, float color[4])
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_GROUNDPOINT);
+
+ DRWShadingGroup *grp = DRW_shgroup_point_batch_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", color, 1);
+ DRW_shgroup_state_enable(grp, DRW_STATE_POINT);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, struct GPUBatch *geom, float *size)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR);
+
+ DRW_shgroup_instance_format(g_formats.instance_screenspace, {
+ {"world_pos", DRW_ATTRIB_FLOAT, 3},
+ {"color", DRW_ATTRIB_FLOAT, 3}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_screenspace);
+ DRW_shgroup_uniform_float(grp, "size", size, 1);
+ DRW_shgroup_uniform_float(grp, "pixel_size", DRW_viewport_pixelsize_get(), 1);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+ DRW_shgroup_state_enable(grp, DRW_STATE_STIPPLE_3);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_solid(DRWPass *pass, struct GPUBatch *geom)
+{
+ static float light[3] = {0.0f, 0.0f, 1.0f};
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR);
+
+ DRW_shgroup_instance_format(g_formats.instance_color, {
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ {"color", DRW_ATTRIB_FLOAT, 4}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_color);
+ DRW_shgroup_uniform_vec3(grp, "light", light, 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_wire(DRWPass *pass, struct GPUBatch *geom)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR);
+
+ DRW_shgroup_instance_format(g_formats.instance_color, {
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ {"color", DRW_ATTRIB_FLOAT, 4}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_color);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_screen_aligned(DRWPass *pass, struct GPUBatch *geom)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED);
+
+ DRW_shgroup_instance_format(g_formats.instance_screen_aligned, {
+ {"color", DRW_ATTRIB_FLOAT, 3},
+ {"size", DRW_ATTRIB_FLOAT, 1},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_screen_aligned);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_scaled(DRWPass *pass, struct GPUBatch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE);
+
+ DRW_shgroup_instance_format(g_formats.instance_scaled, {
+ {"color", DRW_ATTRIB_FLOAT, 3},
+ {"size", DRW_ATTRIB_FLOAT, 3},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_scaled);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance(DRWPass *pass, struct GPUBatch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
+
+ DRW_shgroup_instance_format(g_formats.instance_sized, {
+ {"color", DRW_ATTRIB_FLOAT, 3},
+ {"size", DRW_ATTRIB_FLOAT, 1},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_sized);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_alpha(DRWPass *pass, struct GPUBatch *geom, float alpha)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
+
+ DRW_shgroup_instance_format(g_formats.instance_sized, {
+ {"color", DRW_ATTRIB_FLOAT, 4},
+ {"size", DRW_ATTRIB_FLOAT, 1},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_sized);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", alpha);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_empty_axes(DRWPass *pass, struct GPUBatch *geom)
+{
+ if (g_shaders.empty_axes_sh == NULL) {
+ g_shaders.empty_axes_sh = DRW_shader_create(
+ datatoc_object_empty_axes_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_sized, {
+ {"color", DRW_ATTRIB_FLOAT, 3},
+ {"size", DRW_ATTRIB_FLOAT, 1},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(g_shaders.empty_axes_sh, pass, geom, g_formats.instance_sized);
+ DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_outline(DRWPass *pass, struct GPUBatch *geom, int *baseid)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE);
+
+ DRW_shgroup_instance_format(g_formats.instance_outline, {
+ {"callId", DRW_ATTRIB_INT, 1},
+ {"size", DRW_ATTRIB_FLOAT, 1},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_outline);
+ DRW_shgroup_uniform_int(grp, "baseId", baseid, 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_camera_instance(DRWPass *pass, struct GPUBatch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_CAMERA);
+
+ DRW_shgroup_instance_format(g_formats.instance_camera, {
+ {"color", DRW_ATTRIB_FLOAT, 3},
+ {"corners", DRW_ATTRIB_FLOAT, 8},
+ {"depth", DRW_ATTRIB_FLOAT, 1},
+ {"tria", DRW_ATTRIB_FLOAT, 4},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_camera);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_distance_lines_instance(DRWPass *pass, struct GPUBatch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_DISTANCE_LINES);
+ static float point_size = 4.0f;
+
+ DRW_shgroup_instance_format(g_formats.instance_distance_lines, {
+ {"color", DRW_ATTRIB_FLOAT, 3},
+ {"start", DRW_ATTRIB_FLOAT, 1},
+ {"end", DRW_ATTRIB_FLOAT, 1},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_distance_lines);
+ DRW_shgroup_uniform_float(grp, "size", &point_size, 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, struct GPUBatch *geom)
+{
+ GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR);
+ static const int True = true;
+ static const int False = false;
+
+ DRW_shgroup_instance_format(g_formats.instance_spot, {
+ {"color", DRW_ATTRIB_FLOAT, 3},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_spot);
+ DRW_shgroup_uniform_bool(grp, "drawFront", &False, 1);
+ DRW_shgroup_uniform_bool(grp, "drawBack", &False, 1);
+ DRW_shgroup_uniform_bool(grp, "drawSilhouette", &True, 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_axes(DRWPass *pass)
+{
+ if (g_shaders.bone_axes == NULL) {
+ g_shaders.bone_axes = DRW_shader_create(
+ datatoc_armature_axes_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_color, {
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ {"color", DRW_ATTRIB_FLOAT, 4}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.bone_axes,
+ pass, DRW_cache_bone_arrows_get(),
+ g_formats.instance_color);
+ DRW_shgroup_uniform_vec3(grp, "screenVecs[0]", DRW_viewport_screenvecs_get(), 2);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_envelope_outline(DRWPass *pass)
+{
+ if (g_shaders.bone_envelope_outline == NULL) {
+ g_shaders.bone_envelope_outline = DRW_shader_create(
+ datatoc_armature_envelope_outline_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope_outline, {
+ {"headSphere", DRW_ATTRIB_FLOAT, 4},
+ {"tailSphere", DRW_ATTRIB_FLOAT, 4},
+ {"outlineColorSize", DRW_ATTRIB_FLOAT, 4},
+ {"xAxis", DRW_ATTRIB_FLOAT, 3}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.bone_envelope_outline,
+ pass, DRW_cache_bone_envelope_outline_get(),
+ g_formats.instance_bone_envelope_outline);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_envelope_distance(DRWPass *pass)
+{
+ if (g_shaders.bone_envelope_distance == NULL) {
+ g_shaders.bone_envelope_distance = DRW_shader_create(
+ datatoc_armature_envelope_solid_vert_glsl, NULL,
+ datatoc_armature_envelope_distance_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope_distance, {
+ {"headSphere", DRW_ATTRIB_FLOAT, 4},
+ {"tailSphere", DRW_ATTRIB_FLOAT, 4},
+ {"xAxis", DRW_ATTRIB_FLOAT, 3}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.bone_envelope_distance,
+ pass, DRW_cache_bone_envelope_solid_get(),
+ g_formats.instance_bone_envelope_distance);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, bool transp)
+{
+ if (g_shaders.bone_envelope == NULL) {
+ g_shaders.bone_envelope = DRW_shader_create(
+ datatoc_armature_envelope_solid_vert_glsl, NULL,
+ datatoc_armature_envelope_solid_frag_glsl, "#define SMOOTH_ENVELOPE\n");
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone_envelope, {
+ {"headSphere", DRW_ATTRIB_FLOAT, 4},
+ {"tailSphere", DRW_ATTRIB_FLOAT, 4},
+ {"boneColor", DRW_ATTRIB_FLOAT, 3},
+ {"stateColor", DRW_ATTRIB_FLOAT, 3},
+ {"xAxis", DRW_ATTRIB_FLOAT, 3}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.bone_envelope,
+ pass, DRW_cache_bone_envelope_solid_get(),
+ g_formats.instance_bone_envelope);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.6f : 1.0f);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_mball_handles(DRWPass *pass)
+{
+ if (g_shaders.mball_handles == NULL) {
+ g_shaders.mball_handles = DRW_shader_create(
+ datatoc_object_mball_handles_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_mball_handles, {
+ {"ScaleTranslationMatrix", DRW_ATTRIB_FLOAT, 12},
+ {"radius", DRW_ATTRIB_FLOAT, 1},
+ {"color", DRW_ATTRIB_FLOAT, 3}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.mball_handles, pass,
+ DRW_cache_screenspace_circle_get(),
+ g_formats.instance_mball_handles);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+
+ return grp;
+}
+
+/* Only works with batches with adjacency infos. */
+DRWShadingGroup *shgroup_instance_bone_shape_outline(DRWPass *pass, struct GPUBatch *geom)
+{
+ if (g_shaders.shape_outline == NULL) {
+ g_shaders.shape_outline = DRW_shader_create(
+ datatoc_armature_shape_outline_vert_glsl,
+ datatoc_armature_shape_outline_geom_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone_outline, {
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ {"outlineColorSize", DRW_ATTRIB_FLOAT, 4}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.shape_outline,
+ pass, geom, g_formats.instance_bone_outline);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_shape_solid(DRWPass *pass, struct GPUBatch *geom, bool transp)
+{
+ if (g_shaders.shape_solid == NULL) {
+ g_shaders.shape_solid = DRW_shader_create(
+ datatoc_armature_shape_solid_vert_glsl, NULL,
+ datatoc_armature_shape_solid_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone, {
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ {"boneColor", DRW_ATTRIB_FLOAT, 3},
+ {"stateColor", DRW_ATTRIB_FLOAT, 3}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.shape_solid,
+ pass, geom, g_formats.instance_bone);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.6f : 1.0f);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_sphere_solid(DRWPass *pass, bool transp)
+{
+ if (g_shaders.bone_sphere == NULL) {
+ g_shaders.bone_sphere = DRW_shader_create(
+ datatoc_armature_sphere_solid_vert_glsl, NULL,
+ datatoc_armature_sphere_solid_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone, {
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ {"boneColor", DRW_ATTRIB_FLOAT, 3},
+ {"stateColor", DRW_ATTRIB_FLOAT, 3}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.bone_sphere,
+ pass, DRW_cache_bone_point_get(), g_formats.instance_bone);
+ /* More transparent than the shape to be less distractive. */
+ DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.4f : 1.0f);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_sphere_outline(DRWPass *pass)
+{
+ if (g_shaders.bone_sphere_outline == NULL) {
+ g_shaders.bone_sphere_outline = DRW_shader_create(
+ datatoc_armature_sphere_outline_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone_outline, {
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ {"outlineColorSize", DRW_ATTRIB_FLOAT, 4}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.bone_sphere_outline,
+ pass, DRW_cache_bone_point_wire_outline_get(),
+ g_formats.instance_bone_outline);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+
+ return grp;
+}
+
+DRWShadingGroup *shgroup_instance_bone_stick(DRWPass *pass)
+{
+ if (g_shaders.bone_stick == NULL) {
+ g_shaders.bone_stick = DRW_shader_create(
+ datatoc_armature_stick_vert_glsl, NULL,
+ datatoc_armature_stick_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone_stick, {
+ {"boneStart", DRW_ATTRIB_FLOAT, 3},
+ {"boneEnd", DRW_ATTRIB_FLOAT, 3},
+ {"wireColor", DRW_ATTRIB_FLOAT, 4}, /* TODO port theses to uchar color */
+ {"boneColor", DRW_ATTRIB_FLOAT, 4},
+ {"headColor", DRW_ATTRIB_FLOAT, 4},
+ {"tailColor", DRW_ATTRIB_FLOAT, 4}
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.bone_stick,
+ pass, DRW_cache_bone_stick_get(),
+ g_formats.instance_bone_stick);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_float_copy(grp, "stickSize", 5.0f * U.pixelsize);
+
+ return grp;
+}
+
+struct DRWShadingGroup *shgroup_instance_bone_dof(struct DRWPass *pass, struct GPUBatch *geom)
+{
+ if (g_shaders.bone_dofs == NULL) {
+ g_shaders.bone_dofs = DRW_shader_create(
+ datatoc_armature_dof_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+ }
+
+ DRW_shgroup_instance_format(g_formats.instance_bone_dof, {
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ {"color", DRW_ATTRIB_FLOAT, 4},
+ {"amin", DRW_ATTRIB_FLOAT, 2},
+ {"amax", DRW_ATTRIB_FLOAT, 2},
+ });
+
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ g_shaders.bone_dofs,
+ pass, geom,
+ g_formats.instance_bone_dof);
+
+ return grp;
+}
+
+struct GPUShader *mpath_line_shader_get(void)
+{
+ if (g_shaders.mpath_line_sh == NULL) {
+ g_shaders.mpath_line_sh = DRW_shader_create_with_lib(
+ datatoc_animviz_mpath_lines_vert_glsl,
+ datatoc_animviz_mpath_lines_geom_glsl,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ NULL);
+ }
+ return g_shaders.mpath_line_sh;
+}
+
+
+struct GPUShader *mpath_points_shader_get(void)
+{
+ if (g_shaders.mpath_points_sh == NULL) {
+ g_shaders.mpath_points_sh = DRW_shader_create_with_lib(
+ datatoc_animviz_mpath_points_vert_glsl,
+ NULL,
+ datatoc_gpu_shader_point_varying_color_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ NULL);
+ }
+ return g_shaders.mpath_points_sh;
+}
+
+struct GPUShader *volume_velocity_shader_get(bool use_needle)
+{
+ if (use_needle) {
+ if (g_shaders.volume_velocity_needle_sh == NULL) {
+ g_shaders.volume_velocity_needle_sh = DRW_shader_create(
+ datatoc_volume_velocity_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl, "#define USE_NEEDLE");
+ }
+ return g_shaders.volume_velocity_needle_sh;
+ }
+ else {
+ if (g_shaders.volume_velocity_sh == NULL) {
+ g_shaders.volume_velocity_sh = DRW_shader_create(
+ datatoc_volume_velocity_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+ }
+ return g_shaders.volume_velocity_sh;
+ }
+}
+
+/* ******************************************** COLOR UTILS *********************************************** */
+
+/* TODO FINISH */
+/**
+ * Get the wire color theme_id of an object based on it's state
+ * \a r_color is a way to get a pointer to the static color var associated
+ */
+int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool is_edit = (draw_ctx->object_mode & OB_MODE_EDIT) != 0;
+ const bool active = (view_layer->basact && view_layer->basact->object == ob);
+ /* confusing logic here, there are 2 methods of setting the color
+ * 'colortab[colindex]' and 'theme_id', colindex overrides theme_id.
+ *
+ * note: no theme yet for 'colindex' */
+ int theme_id = is_edit ? TH_WIRE_EDIT : TH_WIRE;
+
+ if (//(scene->obedit == NULL) &&
+ ((G.moving & G_TRANSFORM_OBJ) != 0) &&
+ ((ob->base_flag & BASE_SELECTED) != 0))
+ {
+ theme_id = TH_TRANSFORM;
+ }
+ else {
+ /* Sets the 'theme_id' or fallback to wire */
+ if ((ob->base_flag & BASE_SELECTED) != 0) {
+ theme_id = (active) ? TH_ACTIVE : TH_SELECT;
+ }
+ else {
+ if (ob->type == OB_LAMP) theme_id = TH_LAMP;
+ else if (ob->type == OB_SPEAKER) theme_id = TH_SPEAKER;
+ else if (ob->type == OB_CAMERA) theme_id = TH_CAMERA;
+ else if (ob->type == OB_EMPTY) theme_id = TH_EMPTY;
+ else if (ob->type == OB_LIGHTPROBE) theme_id = TH_EMPTY; /* TODO add lightprobe color */
+ /* fallback to TH_WIRE */
+ }
+ }
+
+ if (r_color != NULL) {
+ switch (theme_id) {
+ case TH_WIRE_EDIT: *r_color = ts.colorWireEdit; break;
+ case TH_ACTIVE: *r_color = ts.colorActive; break;
+ case TH_SELECT: *r_color = ts.colorSelect; break;
+ case TH_TRANSFORM: *r_color = ts.colorTransform; break;
+ case TH_SPEAKER: *r_color = ts.colorSpeaker; break;
+ case TH_CAMERA: *r_color = ts.colorCamera; break;
+ case TH_EMPTY: *r_color = ts.colorEmpty; break;
+ case TH_LAMP: *r_color = ts.colorLamp; break;
+ default: *r_color = ts.colorWire; break;
+ }
+ }
+
+ return theme_id;
+}
+
+/* XXX This is very stupid, better find something more general. */
+float *DRW_color_background_blend_get(int theme_id)
+{
+ static float colors[11][4];
+ float *ret;
+
+ switch (theme_id) {
+ case TH_WIRE_EDIT: ret = colors[0]; break;
+ case TH_ACTIVE: ret = colors[1]; break;
+ case TH_SELECT: ret = colors[2]; break;
+ case TH_TRANSFORM: ret = colors[5]; break;
+ case TH_SPEAKER: ret = colors[6]; break;
+ case TH_CAMERA: ret = colors[7]; break;
+ case TH_EMPTY: ret = colors[8]; break;
+ case TH_LAMP: ret = colors[9]; break;
+ default: ret = colors[10]; break;
+ }
+
+ UI_GetThemeColorBlendShade4fv(theme_id, TH_BACK, 0.5, 0, ret);
+
+ return ret;
+}
+
+
+bool DRW_object_is_flat(Object *ob, int *axis)
+{
+ float dim[3];
+
+ if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
+ /* Non-meshes object cannot be considered as flat. */
+ return false;
+ }
+
+ BKE_object_dimensions_get(ob, dim);
+ if (dim[0] == 0.0f) {
+ *axis = 0;
+ return true;
+ }
+ else if (dim[1] == 0.0f) {
+ *axis = 1;
+ return true;
+ }
+ else if (dim[2] == 0.0f) {
+ *axis = 2;
+ return true;
+ }
+ return false;
+}
+
+bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis)
+{
+ float ob_rot[3][3], invviewmat[4][4];
+ DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV);
+ BKE_object_rot_to_mat3(ob, ob_rot, true);
+ float dot = dot_v3v3(ob_rot[axis], invviewmat[2]);
+ if (fabsf(dot) < 1e-3) {
+ return true;
+ }
+
+ return false;
+}
+
+static void DRW_evaluate_weight_to_color(const float weight, float result[4])
+{
+ if (U.flag & USER_CUSTOM_RANGE) {
+ BKE_colorband_evaluate(&U.coba_weight, weight, result);
+ }
+ else {
+ /* Use gamma correction to even out the color bands:
+ * increasing widens yellow/cyan vs red/green/blue.
+ * Gamma 1.0 produces the original 2.79 color ramp. */
+ const float gamma = 1.5f;
+ float hsv[3] = {(2.0f / 3.0f) * (1.0f - weight), 1.0f, pow(0.5f + 0.5f * weight, gamma)};
+
+ hsv_to_rgb_v(hsv, result);
+
+ for (int i = 0; i < 3; i++) {
+ result[i] = pow(result[i], 1.0f / gamma);
+ }
+ }
+}
+
+static GPUTexture *DRW_create_weight_colorramp_texture(void)
+{
+ char error[256];
+ float pixels[256][4];
+ for (int i = 0 ; i < 256 ; i ++) {
+ DRW_evaluate_weight_to_color(i / 255.0f, pixels[i]);
+ pixels[i][3] = 1.0f;
+ }
+
+ return GPU_texture_create_1D(256, GPU_RGBA8, pixels[0], error);
+}
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
new file mode 100644
index 00000000000..f9e9d2adba3
--- /dev/null
+++ b/source/blender/draw/intern/draw_common.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_common.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_COMMON_H__
+#define __DRAW_COMMON_H__
+
+struct DRWPass;
+struct DRWShadingGroup;
+struct GPUBatch;
+struct GPUMaterial;
+struct Object;
+struct ViewLayer;
+struct ModifierData;
+struct ParticleSystem;
+struct PTCacheEdit;
+
+#define UBO_FIRST_COLOR colorWire
+#define UBO_LAST_COLOR colorGridAxisZ
+
+/* Used as ubo but colors can be directly referenced as well */
+/* Keep in sync with: common_globals_lib.glsl (globalsBlock) */
+/* NOTE! Also keep all color as vec4 and between UBO_FIRST_COLOR and UBO_LAST_COLOR */
+typedef struct GlobalsUboStorage {
+ /* UBOs data needs to be 16 byte aligned (size of vec4) */
+ float colorWire[4];
+ float colorWireEdit[4];
+ float colorActive[4];
+ float colorSelect[4];
+ float colorTransform[4];
+ float colorLibrarySelect[4];
+ float colorLibrary[4];
+ float colorLamp[4];
+ float colorSpeaker[4];
+ float colorCamera[4];
+ float colorEmpty[4];
+ float colorVertex[4];
+ float colorVertexSelect[4];
+ float colorVertexUnreferenced[4];
+ float colorVertexMissingData[4];
+ float colorEditMeshActive[4];
+ float colorEdgeSelect[4];
+ float colorEdgeSeam[4];
+ float colorEdgeSharp[4];
+ float colorEdgeCrease[4];
+ float colorEdgeBWeight[4];
+ float colorEdgeFaceSelect[4];
+ float colorEdgeFreestyle[4];
+ float colorFace[4];
+ float colorFaceSelect[4];
+ float colorFaceFreestyle[4];
+ float colorNormal[4];
+ float colorVNormal[4];
+ float colorLNormal[4];
+ float colorFaceDot[4];
+
+ float colorDeselect[4];
+ float colorOutline[4];
+ float colorLampNoAlpha[4];
+
+ float colorBackground[4];
+
+ float colorHandleFree[4];
+ float colorHandleAuto[4];
+ float colorHandleVect[4];
+ float colorHandleAlign[4];
+ float colorHandleAutoclamp[4];
+ float colorHandleSelFree[4];
+ float colorHandleSelAuto[4];
+ float colorHandleSelVect[4];
+ float colorHandleSelAlign[4];
+ float colorHandleSelAutoclamp[4];
+ float colorNurbUline[4];
+ float colorNurbVline[4];
+ float colorNurbSelUline[4];
+ float colorNurbSelVline[4];
+ float colorActiveSpline[4];
+
+ float colorBonePose[4];
+
+ float colorCurrentFrame[4];
+
+ float colorGrid[4];
+ float colorGridEmphasise[4];
+ float colorGridAxisX[4];
+ float colorGridAxisY[4];
+ float colorGridAxisZ[4];
+
+ /* NOTE! Put all color before UBO_LAST_COLOR */
+
+ /* Pack individual float at the end of the buffer to avoid alignment errors */
+ float sizeLampCenter, sizeLampCircle, sizeLampCircleShadow;
+ float sizeVertex, sizeEdge, sizeEdgeFix, sizeFaceDot;
+ float gridDistance, gridResolution, gridSubdivisions, gridScale;
+
+ float pad_globalsBlock;
+} GlobalsUboStorage;
+/* Keep in sync with globalsBlock in shaders */
+BLI_STATIC_ASSERT_ALIGN(GlobalsUboStorage, 16)
+
+void DRW_globals_update(void);
+void DRW_globals_free(void);
+
+struct DRWShadingGroup *shgroup_dynlines_flat_color(struct DRWPass *pass);
+struct DRWShadingGroup *shgroup_dynlines_dashed_uniform_color(struct DRWPass *pass, float color[4]);
+struct DRWShadingGroup *shgroup_dynpoints_uniform_color(struct DRWPass *pass, float color[4], float *size);
+struct DRWShadingGroup *shgroup_groundlines_uniform_color(struct DRWPass *pass, float color[4]);
+struct DRWShadingGroup *shgroup_groundpoints_uniform_color(struct DRWPass *pass, float color[4]);
+struct DRWShadingGroup *shgroup_instance_screenspace(struct DRWPass *pass, struct GPUBatch *geom, float *size);
+struct DRWShadingGroup *shgroup_instance_solid(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance_wire(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance_screen_aligned(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance_empty_axes(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance_image_plane(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance_scaled(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance_alpha(struct DRWPass *pass, struct GPUBatch *geom, float alpha);
+struct DRWShadingGroup *shgroup_instance_outline(struct DRWPass *pass, struct GPUBatch *geom, int *baseid);
+struct DRWShadingGroup *shgroup_camera_instance(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance_mball_handles(struct DRWPass *pass);
+struct DRWShadingGroup *shgroup_instance_bone_axes(struct DRWPass *pass);
+struct DRWShadingGroup *shgroup_instance_bone_envelope_distance(struct DRWPass *pass);
+struct DRWShadingGroup *shgroup_instance_bone_envelope_outline(struct DRWPass *pass);
+struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, bool transp);
+struct DRWShadingGroup *shgroup_instance_bone_shape_outline(struct DRWPass *pass, struct GPUBatch *geom);
+struct DRWShadingGroup *shgroup_instance_bone_shape_solid(struct DRWPass *pass, struct GPUBatch *geom, bool transp);
+struct DRWShadingGroup *shgroup_instance_bone_sphere_outline(struct DRWPass *pass);
+struct DRWShadingGroup *shgroup_instance_bone_sphere_solid(struct DRWPass *pass, bool transp);
+struct DRWShadingGroup *shgroup_instance_bone_stick(struct DRWPass *pass);
+struct DRWShadingGroup *shgroup_instance_bone_dof(struct DRWPass *pass, struct GPUBatch *geom);
+
+struct GPUShader *mpath_line_shader_get(void);
+struct GPUShader *mpath_points_shader_get(void);
+
+struct GPUShader *volume_velocity_shader_get(bool use_needle);
+
+int DRW_object_wire_theme_get(
+ struct Object *ob, struct ViewLayer *view_layer, float **r_color);
+float *DRW_color_background_blend_get(int theme_id);
+
+bool DRW_object_is_flat(Object *ob, int *axis);
+bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis);
+
+/* draw_armature.c */
+typedef struct DRWArmaturePasses {
+ struct DRWPass *bone_solid;
+ struct DRWPass *bone_outline;
+ struct DRWPass *bone_wire;
+ struct DRWPass *bone_envelope;
+ struct DRWPass *bone_axes;
+ struct DRWPass *relationship_lines;
+} DRWArmaturePasses;
+
+void DRW_shgroup_armature_object(struct Object *ob, struct ViewLayer *view_layer, struct DRWArmaturePasses passes);
+void DRW_shgroup_armature_pose(struct Object *ob, struct DRWArmaturePasses passes, bool transp);
+void DRW_shgroup_armature_edit(struct Object *ob, struct DRWArmaturePasses passes, bool transp);
+
+/* draw_hair.c */
+
+/* This creates a shading group with display hairs.
+ * The draw call is already added by this function, just add additional uniforms. */
+struct DRWShadingGroup *DRW_shgroup_hair_create(
+ struct Object *object, struct ParticleSystem *psys, struct ModifierData *md,
+ struct DRWPass *hair_pass,
+ struct GPUShader *shader);
+
+struct DRWShadingGroup *DRW_shgroup_material_hair_create(
+ struct Object *object, struct ParticleSystem *psys, struct ModifierData *md,
+ struct DRWPass *hair_pass,
+ struct GPUMaterial *material);
+
+void DRW_hair_init(void);
+void DRW_hair_update(void);
+void DRW_hair_free(void);
+
+/* pose_mode.c */
+bool DRW_pose_mode_armature(
+ struct Object *ob, struct Object *active_ob);
+
+#endif /* __DRAW_COMMON_H__ */
diff --git a/source/blender/draw/intern/draw_debug.c b/source/blender/draw/intern/draw_debug.c
new file mode 100644
index 00000000000..366da92cf50
--- /dev/null
+++ b/source/blender/draw/intern/draw_debug.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_debug.c
+ * \ingroup draw
+ *
+ * \brief Simple API to draw debug shapes in the viewport.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+
+#include "BKE_object.h"
+
+#include "BLI_link_utils.h"
+
+#include "GPU_immediate.h"
+
+#include "draw_debug.h"
+#include "draw_manager.h"
+
+/* --------- Register --------- */
+
+/* Matrix applied to all points before drawing. Could be a stack if needed. */
+static float g_modelmat[4][4];
+
+void DRW_debug_modelmat_reset(void)
+{
+ unit_m4(g_modelmat);
+}
+
+void DRW_debug_modelmat(const float modelmat[4][4])
+{
+ copy_m4_m4(g_modelmat, modelmat);
+}
+
+void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4])
+{
+ DRWDebugLine *line = MEM_mallocN(sizeof(DRWDebugLine), "DRWDebugLine");
+ mul_v3_m4v3(line->pos[0], g_modelmat, v1);
+ mul_v3_m4v3(line->pos[1], g_modelmat, v2);
+ copy_v4_v4(line->color, color);
+ BLI_LINKS_PREPEND(DST.debug.lines, line);
+}
+
+void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float color[4])
+{
+ BLI_assert(vert_len > 1);
+
+ for (int i = 0; i < vert_len; ++i) {
+ DRW_debug_line_v3v3(v[i], v[(i + 1) % vert_len], color);
+ }
+}
+
+/* NOTE: g_modelmat is still applied on top. */
+void DRW_debug_m4(const float m[4][4])
+{
+ float v0[3] = {0.0f, 0.0f, 0.0f};
+ float v1[3] = {1.0f, 0.0f, 0.0f};
+ float v2[3] = {0.0f, 1.0f, 0.0f};
+ float v3[3] = {0.0f, 0.0f, 1.0f};
+
+ mul_m4_v3(m, v0);
+ mul_m4_v3(m, v1);
+ mul_m4_v3(m, v2);
+ mul_m4_v3(m, v3);
+
+ DRW_debug_line_v3v3(v0, v1, (float[4]){1.0f, 0.0f, 0.0f, 1.0f});
+ DRW_debug_line_v3v3(v0, v2, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
+ DRW_debug_line_v3v3(v0, v3, (float[4]){0.0f, 0.0f, 1.0f, 1.0f});
+}
+
+void DRW_debug_bbox(const BoundBox *bbox, const float color[4])
+{
+ DRW_debug_line_v3v3(bbox->vec[0], bbox->vec[1], color);
+ DRW_debug_line_v3v3(bbox->vec[1], bbox->vec[2], color);
+ DRW_debug_line_v3v3(bbox->vec[2], bbox->vec[3], color);
+ DRW_debug_line_v3v3(bbox->vec[3], bbox->vec[0], color);
+
+ DRW_debug_line_v3v3(bbox->vec[4], bbox->vec[5], color);
+ DRW_debug_line_v3v3(bbox->vec[5], bbox->vec[6], color);
+ DRW_debug_line_v3v3(bbox->vec[6], bbox->vec[7], color);
+ DRW_debug_line_v3v3(bbox->vec[7], bbox->vec[4], color);
+
+ DRW_debug_line_v3v3(bbox->vec[0], bbox->vec[4], color);
+ DRW_debug_line_v3v3(bbox->vec[1], bbox->vec[5], color);
+ DRW_debug_line_v3v3(bbox->vec[2], bbox->vec[6], color);
+ DRW_debug_line_v3v3(bbox->vec[3], bbox->vec[7], color);
+}
+
+void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool invert)
+{
+ BoundBox bb;
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
+ float project_matrix[4][4];
+ if (invert) {
+ invert_m4_m4(project_matrix, m);
+ }
+ else {
+ copy_m4_m4(project_matrix, m);
+ }
+
+ BKE_boundbox_init_from_minmax(&bb, min, max);
+ for (int i = 0; i < 8; ++i) {
+ mul_project_m4_v3(project_matrix, bb.vec[i]);
+ }
+ DRW_debug_bbox(&bb, color);
+}
+
+void DRW_debug_sphere(const float center[3], const float radius, const float color[4])
+{
+ float size_mat[4][4];
+ DRWDebugSphere *sphere = MEM_mallocN(sizeof(DRWDebugSphere), "DRWDebugSphere");
+ /* Bake all transform into a Matrix4 */
+ scale_m4_fl(size_mat, radius);
+ copy_m4_m4(sphere->mat, g_modelmat);
+ translate_m4(sphere->mat, center[0], center[1], center[2]);
+ mul_m4_m4m4(sphere->mat, sphere->mat, size_mat);
+
+ copy_v4_v4(sphere->color, color);
+ BLI_LINKS_PREPEND(DST.debug.spheres, sphere);
+}
+
+/* --------- Render --------- */
+
+static void drw_debug_draw_lines(void)
+{
+ int count = BLI_linklist_count((LinkNode *)DST.debug.lines);
+
+ if (count == 0) {
+ return;
+ }
+
+ GPUVertFormat *vert_format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(vert_format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ immBegin(GPU_PRIM_LINES, count * 2);
+
+ while (DST.debug.lines) {
+ void *next = DST.debug.lines->next;
+
+ immAttr4fv(col, DST.debug.lines->color);
+ immVertex3fv(pos, DST.debug.lines->pos[0]);
+
+ immAttr4fv(col, DST.debug.lines->color);
+ immVertex3fv(pos, DST.debug.lines->pos[1]);
+
+ MEM_freeN(DST.debug.lines);
+ DST.debug.lines = next;
+ }
+ immEnd();
+
+ immUnbindProgram();
+}
+
+static void drw_debug_draw_spheres(void)
+{
+ int count = BLI_linklist_count((LinkNode *)DST.debug.spheres);
+
+ if (count == 0) {
+ return;
+ }
+
+ float one = 1.0f;
+ GPUVertFormat vert_format = {0};
+ uint mat = GPU_vertformat_attr_add(&vert_format, "InstanceModelMatrix", GPU_COMP_F32, 16, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(&vert_format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint siz = GPU_vertformat_attr_add(&vert_format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *inst_vbo = GPU_vertbuf_create_with_format(&vert_format);
+
+ GPU_vertbuf_data_alloc(inst_vbo, count);
+
+ int v = 0;
+ while (DST.debug.spheres) {
+ void *next = DST.debug.spheres->next;
+
+ GPU_vertbuf_attr_set(inst_vbo, mat, v, DST.debug.spheres->mat[0]);
+ GPU_vertbuf_attr_set(inst_vbo, col, v, DST.debug.spheres->color);
+ GPU_vertbuf_attr_set(inst_vbo, siz, v, &one);
+ v++;
+
+ MEM_freeN(DST.debug.spheres);
+ DST.debug.spheres = next;
+ }
+
+ GPUBatch *empty_sphere = DRW_cache_empty_sphere_get();
+
+ GPUBatch *draw_batch = GPU_batch_create(GPU_PRIM_LINES, empty_sphere->verts[0], NULL);
+ GPU_batch_instbuf_set(draw_batch, inst_vbo, true);
+ GPU_batch_program_set_builtin(draw_batch, GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
+ GPU_batch_uniform_1f(draw_batch, "alpha", 1.0f);
+
+ GPU_batch_draw(draw_batch);
+ GPU_batch_discard(draw_batch);
+}
+
+void drw_debug_draw(void)
+{
+ drw_debug_draw_lines();
+ drw_debug_draw_spheres();
+}
+
+void drw_debug_init(void)
+{
+ DRW_debug_modelmat_reset();
+}
diff --git a/source/blender/draw/intern/draw_debug.h b/source/blender/draw/intern/draw_debug.h
new file mode 100644
index 00000000000..319d2674279
--- /dev/null
+++ b/source/blender/draw/intern/draw_debug.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_debug.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_DEBUG_H__
+#define __DRAW_DEBUG_H__
+
+struct BoundBox;
+
+void DRW_debug_modelmat_reset(void);
+void DRW_debug_modelmat(const float modelmat[4][4]);
+
+void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]);
+void DRW_debug_polygon_v3(const float (*v)[3], const int vert_len, const float color[4]);
+void DRW_debug_m4(const float m[4][4]);
+void DRW_debug_m4_as_bbox(const float m[4][4], const float color[4], const bool invert);
+void DRW_debug_bbox(const BoundBox *bbox, const float color[4]);
+void DRW_debug_sphere(const float center[3], const float radius, const float color[4]);
+
+#endif /* __DRAW_DEBUG_H__ */
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
new file mode 100644
index 00000000000..f6891563dbb
--- /dev/null
+++ b/source/blender/draw/intern/draw_hair.c
@@ -0,0 +1,214 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_hair.c
+ * \ingroup draw
+ *
+ * \brief Contains procedural GPU hair drawing methods.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_customdata_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_mesh.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+
+#include "ED_particle.h"
+
+#include "GPU_batch.h"
+#include "GPU_shader.h"
+
+#include "draw_hair_private.h"
+
+typedef enum ParticleRefineShader {
+ PART_REFINE_CATMULL_ROM = 0,
+ PART_REFINE_MAX_SHADER,
+} ParticleRefineShader;
+
+static GPUShader *g_refine_shaders[PART_REFINE_MAX_SHADER] = {NULL};
+static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
+
+extern char datatoc_common_hair_lib_glsl[];
+extern char datatoc_common_hair_refine_vert_glsl[];
+
+static GPUShader *hair_refine_shader_get(ParticleRefineShader sh)
+{
+ if (g_refine_shaders[sh]) {
+ return g_refine_shaders[sh];
+ }
+
+ char *vert_with_lib = BLI_string_joinN(datatoc_common_hair_lib_glsl, datatoc_common_hair_refine_vert_glsl);
+
+ const char *var_names[1] = {"outData"};
+
+ g_refine_shaders[sh] = DRW_shader_create_with_transform_feedback(vert_with_lib, NULL, "#define HAIR_PHASE_SUBDIV\n",
+ GPU_SHADER_TFB_POINTS, var_names, 1);
+
+ MEM_freeN(vert_with_lib);
+
+ return g_refine_shaders[sh];
+}
+
+void DRW_hair_init(void)
+{
+ g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_TRANS_FEEDBACK);
+}
+
+typedef struct DRWHairInstanceData {
+ DrawData dd;
+
+ float mat[4][4];
+} DRWHairInstanceData;
+
+static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(
+ Object *object, ParticleSystem *psys, ModifierData *md,
+ DRWPass *hair_pass,
+ struct GPUMaterial *gpu_mat, GPUShader *gpu_shader)
+{
+ /* TODO(fclem): Pass the scene as parameter */
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ static float unit_mat[4][4] = {
+ {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1},
+ };
+ float (*dupli_mat)[4];
+ Object *dupli_parent = DRW_object_get_dupli_parent(object);
+ DupliObject *dupli_object = DRW_object_get_dupli(object);
+
+ int subdiv = scene->r.hair_subdiv;
+ int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
+
+ ParticleHairCache *hair_cache;
+ ParticleSettings *part = psys->part;
+ bool need_ft_update = particles_ensure_procedural_data(object, psys, md, &hair_cache, subdiv, thickness_res);
+
+ DRWShadingGroup *shgrp;
+ if (gpu_mat) {
+ shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass);
+ }
+ else if (gpu_shader) {
+ shgrp = DRW_shgroup_create(gpu_shader, hair_pass);
+ }
+ else {
+ shgrp = NULL;
+ BLI_assert(0);
+ }
+
+ /* TODO optimize this. Only bind the ones GPUMaterial needs. */
+ for (int i = 0; i < hair_cache->num_uv_layers; ++i) {
+ for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->uv_layer_names[i][n][0] != '\0'; ++n) {
+ DRW_shgroup_uniform_texture(shgrp, hair_cache->uv_layer_names[i][n], hair_cache->uv_tex[i]);
+ }
+ }
+ for (int i = 0; i < hair_cache->num_col_layers; ++i) {
+ for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->col_layer_names[i][n][0] != '\0'; ++n) {
+ DRW_shgroup_uniform_texture(shgrp, hair_cache->col_layer_names[i][n], hair_cache->col_tex[i]);
+ }
+ }
+
+ if (dupli_parent) {
+ DRWHairInstanceData *hair_inst_data = (DRWHairInstanceData *)DRW_drawdata_ensure(
+ &object->id, (DrawEngineType *)&drw_shgroup_create_hair_procedural_ex,
+ sizeof(DRWHairInstanceData), NULL, NULL);
+ dupli_mat = hair_inst_data->mat;
+ if (dupli_object->type & OB_DUPLICOLLECTION) {
+ copy_m4_m4(dupli_mat, dupli_parent->obmat);
+ }
+ else {
+ copy_m4_m4(dupli_mat, dupli_object->ob->obmat);
+ invert_m4(dupli_mat);
+ mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat);
+ }
+ }
+ else {
+ dupli_mat = unit_mat;
+ }
+
+ DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex);
+ DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
+ DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
+ DRW_shgroup_uniform_float(shgrp, "hairRadShape", &part->shape, 1);
+ DRW_shgroup_uniform_mat4(shgrp, "hairDupliMatrix", dupli_mat);
+ DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", part->rad_root * part->rad_scale * 0.5f);
+ DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", part->rad_tip * part->rad_scale * 0.5f);
+ DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", (part->shape_flag & PART_SHAPE_CLOSE_TIP) != 0);
+ /* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass culling test. */
+ DRW_shgroup_call_object_add_no_cull(shgrp, hair_cache->final[subdiv].proc_hairs[thickness_res - 1], object);
+
+ /* Transform Feedback subdiv. */
+ if (need_ft_update) {
+ int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len;
+ GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass,
+ hair_cache->final[subdiv].proc_buf);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex);
+ DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex);
+ DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
+ DRW_shgroup_call_procedural_points_add(tf_shgrp, final_points_len, NULL);
+ }
+
+ return shgrp;
+}
+
+DRWShadingGroup *DRW_shgroup_hair_create(
+ Object *object, ParticleSystem *psys, ModifierData *md,
+ DRWPass *hair_pass,
+ GPUShader *shader)
+{
+ return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, shader);
+}
+
+DRWShadingGroup *DRW_shgroup_material_hair_create(
+ Object *object, ParticleSystem *psys, ModifierData *md,
+ DRWPass *hair_pass,
+ struct GPUMaterial *material)
+{
+ return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, material, NULL);
+}
+
+void DRW_hair_update(void)
+{
+ DRW_draw_pass(g_tf_pass);
+}
+
+void DRW_hair_free(void)
+{
+ for (int i = 0; i < PART_REFINE_MAX_SHADER; ++i) {
+ DRW_SHADER_FREE_SAFE(g_refine_shaders[i]);
+ }
+}
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
new file mode 100644
index 00000000000..41f91e02459
--- /dev/null
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -0,0 +1,92 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_hair_private.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_HAIR_PRIVATE_H__
+#define __DRAW_HAIR_PRIVATE_H__
+
+#define MAX_LAYER_NAME_CT 3 /* u0123456789, u, a0123456789 */
+#define MAX_LAYER_NAME_LEN DECIMAL_DIGITS_BOUND(uint) + 2
+#define MAX_THICKRES 2 /* see eHairType */
+#define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */
+
+struct Object;
+struct ParticleSystem;
+struct ModifierData;
+struct ParticleHairCache;
+
+typedef struct ParticleHairFinalCache {
+ /* Output of the subdivision stage: vertex buff sized to subdiv level. */
+ GPUVertBuf *proc_buf;
+ GPUTexture *proc_tex;
+
+ /* Just contains a huge index buffer used to draw the final hair. */
+ GPUBatch *proc_hairs[MAX_THICKRES];
+
+ int strands_res; /* points per hair, at least 2 */
+} ParticleHairFinalCache;
+
+typedef struct ParticleHairCache {
+ GPUVertBuf *pos;
+ GPUIndexBuf *indices;
+ GPUBatch *hairs;
+
+ /* Hair Procedural display: Interpolation is done on the GPU. */
+ GPUVertBuf *proc_point_buf; /* Input control points */
+ GPUTexture *point_tex;
+
+ GPUVertBuf *proc_strand_buf; /* Infos of control points strands (segment count and base index) */
+ GPUTexture *strand_tex;
+
+ GPUVertBuf *proc_uv_buf[MAX_MTFACE];
+ GPUTexture *uv_tex[MAX_MTFACE];
+ char uv_layer_names[MAX_MTFACE][MAX_LAYER_NAME_CT][MAX_LAYER_NAME_LEN];
+
+ GPUVertBuf *proc_col_buf[MAX_MCOL];
+ GPUTexture *col_tex[MAX_MCOL];
+ char col_layer_names[MAX_MCOL][MAX_LAYER_NAME_CT][MAX_LAYER_NAME_LEN];
+
+ int num_uv_layers;
+ int num_col_layers;
+
+ ParticleHairFinalCache final[MAX_HAIR_SUBDIV];
+
+ int strands_len;
+ int elems_len;
+ int point_len;
+} ParticleHairCache;
+
+bool particles_ensure_procedural_data(
+ struct Object *object,
+ struct ParticleSystem *psys,
+ struct ModifierData *md,
+ struct ParticleHairCache **r_hair_cache,
+ int subdiv,
+ int thickness_res);
+
+#endif /* __DRAW_HAIR_PRIVATE_H__ */
diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c
new file mode 100644
index 00000000000..9695643d707
--- /dev/null
+++ b/source/blender/draw/intern/draw_instance_data.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_instance_data.c
+ * \ingroup draw
+ */
+
+/**
+ * DRW Instance Data Manager
+ * This is a special memory manager that keeps memory blocks ready to send as vbo data in one continuous allocation.
+ * This way we avoid feeding gawain each instance data one by one and unnecessary memcpy.
+ * Since we loose which memory block was used each DRWShadingGroup we need to redistribute them in the same order/size
+ * to avoid to realloc each frame.
+ * This is why DRWInstanceDatas are sorted in a list for each different data size.
+ **/
+
+#include "draw_instance_data.h"
+#include "DRW_engine.h"
+#include "DRW_render.h" /* For DRW_shgroup_get_instance_count() */
+
+#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+#include "BLI_mempool.h"
+
+#define BUFFER_CHUNK_SIZE 32
+#define BUFFER_VERTS_CHUNK 32
+
+typedef struct DRWBatchingBuffer {
+ struct DRWShadingGroup *shgroup; /* Link back to the owning shGroup. Also tells if it's used */
+ GPUVertFormat *format; /* Identifier. */
+ GPUVertBuf *vert; /* GPUVertBuf contained in the GPUBatch. */
+ GPUBatch *batch; /* GPUBatch containing the GPUVertBuf. */
+} DRWBatchingBuffer;
+
+typedef struct DRWInstancingBuffer {
+ struct DRWShadingGroup *shgroup; /* Link back to the owning shGroup. Also tells if it's used */
+ GPUVertFormat *format; /* Identifier. */
+ GPUBatch *instance; /* Identifier. */
+ GPUVertBuf *vert; /* GPUVertBuf contained in the GPUBatch. */
+ GPUBatch *batch; /* GPUBatch containing the GPUVertBuf. */
+} DRWInstancingBuffer;
+
+typedef struct DRWInstanceChunk {
+ size_t cursor; /* Offset to the next instance data. */
+ size_t alloc_size; /* Number of DRWBatchingBuffer/Batches alloc'd in ibufs/btchs. */
+ union {
+ DRWBatchingBuffer *bbufs;
+ DRWInstancingBuffer *ibufs;
+ };
+} DRWInstanceChunk;
+
+struct DRWInstanceData {
+ struct DRWInstanceData *next;
+ bool used; /* If this data is used or not. */
+ size_t data_size; /* Size of one instance data. */
+ BLI_mempool *mempool;
+};
+
+struct DRWInstanceDataList {
+ struct DRWInstanceDataList *next, *prev;
+ /* Linked lists for all possible data pool size */
+ DRWInstanceData *idata_head[MAX_INSTANCE_DATA_SIZE];
+ DRWInstanceData *idata_tail[MAX_INSTANCE_DATA_SIZE];
+
+ DRWInstanceChunk instancing;
+ DRWInstanceChunk batching;
+};
+
+static ListBase g_idatalists = {NULL, NULL};
+
+/* -------------------------------------------------------------------- */
+
+/** \name Instance Buffer Management
+ * \{ */
+
+/**
+ * This manager allows to distribute existing batches for instancing
+ * attributes. This reduce the number of batches creation.
+ * Querying a batch is done with a vertex format. This format should
+ * be static so that it's pointer never changes (because we are using
+ * this pointer as identifier [we don't want to check the full format
+ * that would be too slow]).
+ **/
+
+static void instance_batch_free(GPUBatch *batch, void *UNUSED(user_data))
+{
+ /* Free all batches that have the same key before they are reused. */
+ /* TODO: Make it thread safe! Batch freeing can happen from another thread. */
+ /* XXX we need to iterate over all idatalists unless we make some smart
+ * data structure to store the locations to update. */
+ for (DRWInstanceDataList *idatalist = g_idatalists.first; idatalist; idatalist = idatalist->next) {
+ DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs;
+ for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) {
+ if (ibuf->instance == batch) {
+ BLI_assert(ibuf->shgroup == NULL); /* Make sure it has no other users. */
+ GPU_VERTBUF_DISCARD_SAFE(ibuf->vert);
+ GPU_BATCH_DISCARD_SAFE(ibuf->batch);
+ /* Tag as non alloced. */
+ ibuf->format = NULL;
+ }
+ }
+ }
+}
+
+void DRW_batching_buffer_request(
+ DRWInstanceDataList *idatalist, GPUVertFormat *format, GPUPrimType type, struct DRWShadingGroup *shgroup,
+ GPUBatch **r_batch, GPUVertBuf **r_vert)
+{
+ DRWInstanceChunk *chunk = &idatalist->batching;
+ DRWBatchingBuffer *bbuf = idatalist->batching.bbufs;
+ BLI_assert(format);
+ /* Search for an unused batch. */
+ for (int i = 0; i < idatalist->batching.alloc_size; i++, bbuf++) {
+ if (bbuf->shgroup == NULL) {
+ if (bbuf->format == format) {
+ bbuf->shgroup = shgroup;
+ *r_batch = bbuf->batch;
+ *r_vert = bbuf->vert;
+ return;
+ }
+ }
+ }
+ int new_id = 0; /* Find insertion point. */
+ for (; new_id < chunk->alloc_size; ++new_id) {
+ if (chunk->bbufs[new_id].format == NULL)
+ break;
+ }
+ /* If there is no batch left. Allocate more. */
+ if (new_id == chunk->alloc_size) {
+ new_id = chunk->alloc_size;
+ chunk->alloc_size += BUFFER_CHUNK_SIZE;
+ chunk->bbufs = MEM_reallocN(chunk->bbufs, chunk->alloc_size * sizeof(DRWBatchingBuffer));
+ memset(chunk->bbufs + new_id, 0, sizeof(DRWBatchingBuffer) * BUFFER_CHUNK_SIZE);
+ }
+ /* Create the batch. */
+ bbuf = chunk->bbufs + new_id;
+ bbuf->vert = *r_vert = GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_DYNAMIC);
+ bbuf->batch = *r_batch = GPU_batch_create_ex(type, bbuf->vert, NULL, 0);
+ bbuf->format = format;
+ bbuf->shgroup = shgroup;
+ GPU_vertbuf_data_alloc(*r_vert, BUFFER_VERTS_CHUNK);
+}
+
+void DRW_instancing_buffer_request(
+ DRWInstanceDataList *idatalist, GPUVertFormat *format, GPUBatch *instance, struct DRWShadingGroup *shgroup,
+ GPUBatch **r_batch, GPUVertBuf **r_vert)
+{
+ DRWInstanceChunk *chunk = &idatalist->instancing;
+ DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs;
+ BLI_assert(format);
+ /* Search for an unused batch. */
+ for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) {
+ if (ibuf->shgroup == NULL) {
+ if (ibuf->format == format) {
+ if (ibuf->instance == instance) {
+ ibuf->shgroup = shgroup;
+ *r_batch = ibuf->batch;
+ *r_vert = ibuf->vert;
+ return;
+ }
+ }
+ }
+ }
+ int new_id = 0; /* Find insertion point. */
+ for (; new_id < chunk->alloc_size; ++new_id) {
+ if (chunk->ibufs[new_id].format == NULL)
+ break;
+ }
+ /* If there is no batch left. Allocate more. */
+ if (new_id == chunk->alloc_size) {
+ new_id = chunk->alloc_size;
+ chunk->alloc_size += BUFFER_CHUNK_SIZE;
+ chunk->ibufs = MEM_reallocN(chunk->ibufs, chunk->alloc_size * sizeof(DRWInstancingBuffer));
+ memset(chunk->ibufs + new_id, 0, sizeof(DRWInstancingBuffer) * BUFFER_CHUNK_SIZE);
+ }
+ /* Create the batch. */
+ ibuf = chunk->ibufs + new_id;
+ ibuf->vert = *r_vert = GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_DYNAMIC);
+ ibuf->batch = *r_batch = GPU_batch_duplicate(instance);
+ ibuf->format = format;
+ ibuf->shgroup = shgroup;
+ ibuf->instance = instance;
+ GPU_vertbuf_data_alloc(*r_vert, BUFFER_VERTS_CHUNK);
+ GPU_batch_instbuf_set(ibuf->batch, ibuf->vert, false);
+ /* Make sure to free this ibuf if the instance batch gets free. */
+ GPU_batch_callback_free_set(instance, &instance_batch_free, NULL);
+}
+
+void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist)
+{
+ size_t realloc_size = 1; /* Avoid 0 size realloc. */
+ /* Resize down buffers in use and send data to GPU & free unused buffers. */
+ DRWInstanceChunk *batching = &idatalist->batching;
+ DRWBatchingBuffer *bbuf = batching->bbufs;
+ for (int i = 0; i < batching->alloc_size; i++, bbuf++) {
+ if (bbuf->shgroup != NULL) {
+ realloc_size = i + 1;
+ uint vert_len = DRW_shgroup_get_instance_count(bbuf->shgroup);
+ vert_len += (vert_len == 0) ? 1 : 0; /* Do not realloc to 0 size buffer */
+ if (vert_len + BUFFER_VERTS_CHUNK <= bbuf->vert->vertex_len) {
+ uint size = vert_len + BUFFER_VERTS_CHUNK - 1;
+ size = size - size % BUFFER_VERTS_CHUNK;
+ GPU_vertbuf_data_resize(bbuf->vert, size);
+ }
+ GPU_vertbuf_use(bbuf->vert); /* Send data. */
+ bbuf->shgroup = NULL; /* Set as non used for the next round. */
+ }
+ else {
+ GPU_VERTBUF_DISCARD_SAFE(bbuf->vert);
+ GPU_BATCH_DISCARD_SAFE(bbuf->batch);
+ bbuf->format = NULL; /* Tag as non alloced. */
+ }
+ }
+ /* Rounding up to nearest chunk size. */
+ realloc_size += BUFFER_CHUNK_SIZE - 1;
+ realloc_size -= realloc_size % BUFFER_CHUNK_SIZE;
+ /* Resize down if necessary. */
+ if (realloc_size < batching->alloc_size) {
+ batching->alloc_size = realloc_size;
+ batching->ibufs = MEM_reallocN(batching->ibufs, realloc_size * sizeof(DRWBatchingBuffer));
+ }
+
+ realloc_size = 1;
+ /* Resize down buffers in use and send data to GPU & free unused buffers. */
+ DRWInstanceChunk *instancing = &idatalist->instancing;
+ DRWInstancingBuffer *ibuf = instancing->ibufs;
+ for (int i = 0; i < instancing->alloc_size; i++, ibuf++) {
+ if (ibuf->shgroup != NULL) {
+ realloc_size = i + 1;
+ uint vert_len = DRW_shgroup_get_instance_count(ibuf->shgroup);
+ vert_len += (vert_len == 0) ? 1 : 0; /* Do not realloc to 0 size buffer */
+ if (vert_len + BUFFER_VERTS_CHUNK <= ibuf->vert->vertex_len) {
+ uint size = vert_len + BUFFER_VERTS_CHUNK - 1;
+ size = size - size % BUFFER_VERTS_CHUNK;
+ GPU_vertbuf_data_resize(ibuf->vert, size);
+ }
+ GPU_vertbuf_use(ibuf->vert); /* Send data. */
+ ibuf->shgroup = NULL; /* Set as non used for the next round. */
+ }
+ else {
+ GPU_VERTBUF_DISCARD_SAFE(ibuf->vert);
+ GPU_BATCH_DISCARD_SAFE(ibuf->batch);
+ ibuf->format = NULL; /* Tag as non alloced. */
+ }
+ }
+ /* Rounding up to nearest chunk size. */
+ realloc_size += BUFFER_CHUNK_SIZE - 1;
+ realloc_size -= realloc_size % BUFFER_CHUNK_SIZE;
+ /* Resize down if necessary. */
+ if (realloc_size < instancing->alloc_size) {
+ instancing->alloc_size = realloc_size;
+ instancing->ibufs = MEM_reallocN(instancing->ibufs, realloc_size * sizeof(DRWInstancingBuffer));
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Instance Data (DRWInstanceData)
+ * \{ */
+
+static DRWInstanceData *drw_instance_data_create(DRWInstanceDataList *idatalist, uint attrib_size)
+{
+ DRWInstanceData *idata = MEM_callocN(sizeof(DRWInstanceData), "DRWInstanceData");
+ idata->next = NULL;
+ idata->used = true;
+ idata->data_size = attrib_size;
+ idata->mempool = BLI_mempool_create(sizeof(float) * idata->data_size, 0, 16, 0);
+
+ BLI_assert(attrib_size > 0);
+
+ /* Push to linked list. */
+ if (idatalist->idata_head[attrib_size - 1] == NULL) {
+ idatalist->idata_head[attrib_size - 1] = idata;
+ }
+ else {
+ idatalist->idata_tail[attrib_size - 1]->next = idata;
+ }
+ idatalist->idata_tail[attrib_size - 1] = idata;
+
+ return idata;
+}
+
+static void DRW_instance_data_free(DRWInstanceData *idata)
+{
+ BLI_mempool_destroy(idata->mempool);
+}
+
+/**
+ * Return a pointer to the next instance data space.
+ **/
+void *DRW_instance_data_next(DRWInstanceData *idata)
+{
+ return BLI_mempool_alloc(idata->mempool);
+}
+
+DRWInstanceData *DRW_instance_data_request(DRWInstanceDataList *idatalist, uint attrib_size)
+{
+ BLI_assert(attrib_size > 0 && attrib_size <= MAX_INSTANCE_DATA_SIZE);
+
+ DRWInstanceData *idata = idatalist->idata_head[attrib_size - 1];
+
+ /* Search for an unused data chunk. */
+ for (; idata; idata = idata->next) {
+ if (idata->used == false) {
+ idata->used = true;
+ return idata;
+ }
+ }
+
+ return drw_instance_data_create(idatalist, attrib_size);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Instance Data List (DRWInstanceDataList)
+ * \{ */
+
+DRWInstanceDataList *DRW_instance_data_list_create(void)
+{
+ DRWInstanceDataList *idatalist = MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList");
+ idatalist->batching.bbufs = MEM_callocN(sizeof(DRWBatchingBuffer) * BUFFER_CHUNK_SIZE, "DRWBatchingBuffers");
+ idatalist->batching.alloc_size = BUFFER_CHUNK_SIZE;
+ idatalist->instancing.ibufs = MEM_callocN(sizeof(DRWInstancingBuffer) * BUFFER_CHUNK_SIZE, "DRWInstancingBuffers");
+ idatalist->instancing.alloc_size = BUFFER_CHUNK_SIZE;
+
+ BLI_addtail(&g_idatalists, idatalist);
+
+ return idatalist;
+}
+
+void DRW_instance_data_list_free(DRWInstanceDataList *idatalist)
+{
+ DRWInstanceData *idata, *next_idata;
+
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
+ next_idata = idata->next;
+ DRW_instance_data_free(idata);
+ MEM_freeN(idata);
+ }
+ idatalist->idata_head[i] = NULL;
+ idatalist->idata_tail[i] = NULL;
+ }
+
+ DRWBatchingBuffer *bbuf = idatalist->batching.bbufs;
+ for (int i = 0; i < idatalist->batching.alloc_size; i++, bbuf++) {
+ GPU_VERTBUF_DISCARD_SAFE(bbuf->vert);
+ GPU_BATCH_DISCARD_SAFE(bbuf->batch);
+ }
+ MEM_freeN(idatalist->batching.bbufs);
+
+ DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs;
+ for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) {
+ GPU_VERTBUF_DISCARD_SAFE(ibuf->vert);
+ GPU_BATCH_DISCARD_SAFE(ibuf->batch);
+ }
+ MEM_freeN(idatalist->instancing.ibufs);
+
+ BLI_remlink(&g_idatalists, idatalist);
+}
+
+void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist)
+{
+ DRWInstanceData *idata;
+
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
+ idata->used = false;
+ }
+ }
+}
+
+void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist)
+{
+ DRWInstanceData *idata, *next_idata;
+
+ /* Remove unused data blocks and sanitize each list. */
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ idatalist->idata_tail[i] = NULL;
+ for (idata = idatalist->idata_head[i]; idata; idata = next_idata) {
+ next_idata = idata->next;
+ if (idata->used == false) {
+ if (idatalist->idata_head[i] == idata) {
+ idatalist->idata_head[i] = next_idata;
+ }
+ else {
+ /* idatalist->idata_tail[i] is guaranteed not to be null in this case. */
+ idatalist->idata_tail[i]->next = next_idata;
+ }
+ DRW_instance_data_free(idata);
+ MEM_freeN(idata);
+ }
+ else {
+ if (idatalist->idata_tail[i] != NULL) {
+ idatalist->idata_tail[i]->next = idata;
+ }
+ idatalist->idata_tail[i] = idata;
+ }
+ }
+ }
+}
+
+void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist)
+{
+ DRWInstanceData *idata;
+
+ for (int i = 0; i < MAX_INSTANCE_DATA_SIZE; ++i) {
+ for (idata = idatalist->idata_head[i]; idata; idata = idata->next) {
+ BLI_mempool_clear_ex(idata->mempool, BLI_mempool_len(idata->mempool));
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
new file mode 100644
index 00000000000..174f03e3bc7
--- /dev/null
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_instance_data.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_INSTANCE_DATA_H__
+#define __DRAW_INSTANCE_DATA_H__
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
+
+#include "GPU_batch.h"
+
+#define MAX_INSTANCE_DATA_SIZE 64 /* Can be adjusted for more */
+
+typedef struct DRWInstanceData DRWInstanceData;
+typedef struct DRWInstanceDataList DRWInstanceDataList;
+
+struct DRWShadingGroup;
+
+void *DRW_instance_data_next(DRWInstanceData *idata);
+DRWInstanceData *DRW_instance_data_request(
+ DRWInstanceDataList *idatalist, uint attrib_size);
+
+void DRW_batching_buffer_request(
+ DRWInstanceDataList *idatalist, GPUVertFormat *format, GPUPrimType type, struct DRWShadingGroup *shgroup,
+ GPUBatch **r_batch, GPUVertBuf **r_vert);
+void DRW_instancing_buffer_request(
+ DRWInstanceDataList *idatalist, GPUVertFormat *format, GPUBatch *instance, struct DRWShadingGroup *shgroup,
+ GPUBatch **r_batch, GPUVertBuf **r_vert);
+
+/* Upload all instance data to the GPU as soon as possible. */
+void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist);
+
+void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist);
+void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist);
+void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist);
+
+#endif /* __DRAW_INSTANCE_DATA_H__ */
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
new file mode 100644
index 00000000000..9d0fb690b5a
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager.c
@@ -0,0 +1,2716 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_manager.c
+ * \ingroup draw
+ */
+
+#include <stdio.h>
+
+#include "BLI_listbase.h"
+#include "BLI_mempool.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_threads.h"
+
+#include "BLF_api.h"
+
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_workspace.h"
+
+#include "draw_manager.h"
+#include "DNA_camera_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_world_types.h"
+
+#include "ED_space_api.h"
+#include "ED_screen.h"
+#include "ED_gpencil.h"
+#include "ED_particle.h"
+#include "ED_view3d.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+#include "GPU_matrix.h"
+
+#include "IMB_colormanagement.h"
+
+#include "RE_engine.h"
+#include "RE_pipeline.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "wm_window.h"
+
+#include "draw_manager_text.h"
+#include "draw_manager_profiling.h"
+
+/* only for callbacks */
+#include "draw_cache_impl.h"
+
+#include "draw_mode_engines.h"
+#include "engines/eevee/eevee_engine.h"
+#include "engines/basic/basic_engine.h"
+#include "engines/workbench/workbench_engine.h"
+#include "engines/external/external_engine.h"
+
+#include "GPU_context.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#ifdef USE_GPU_SELECT
+# include "GPU_select.h"
+#endif
+
+/** Render State: No persistent data between draw calls. */
+DRWManager DST = {NULL};
+
+static ListBase DRW_engines = {NULL, NULL};
+
+extern struct GPUUniformBuffer *view_ubo; /* draw_manager_exec.c */
+
+static void drw_state_prepare_clean_for_draw(DRWManager *dst)
+{
+ memset(dst, 0x0, offsetof(DRWManager, gl_context));
+}
+
+/* This function is used to reset draw manager to a state
+ * where we don't re-use data by accident across different
+ * draw calls.
+ */
+#ifdef DEBUG
+static void drw_state_ensure_not_reused(DRWManager *dst)
+{
+ memset(dst, 0xff, offsetof(DRWManager, gl_context));
+}
+#endif
+
+/* -------------------------------------------------------------------- */
+
+void DRW_draw_callbacks_pre_scene(void)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+}
+
+void DRW_draw_callbacks_post_scene(void)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+}
+
+struct DRWTextStore *DRW_text_cache_ensure(void)
+{
+ BLI_assert(DST.text_store_p);
+ if (*DST.text_store_p == NULL) {
+ *DST.text_store_p = DRW_text_cache_create();
+ }
+ return *DST.text_store_p;
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Settings
+ * \{ */
+
+bool DRW_object_is_renderable(const Object *ob)
+{
+ BLI_assert(BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE));
+
+ if (ob->type == OB_MESH) {
+ if ((ob == DST.draw_ctx.object_edit) || BKE_object_is_in_editmode(ob)) {
+ View3D *v3d = DST.draw_ctx.v3d;
+ const int mask = (V3D_OVERLAY_EDIT_OCCLUDE_WIRE | V3D_OVERLAY_EDIT_WEIGHT);
+
+ if (v3d && v3d->overlay.edit_flag & mask) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Return whether this object is visible depending if
+ * we are rendering or drawing in the viewport.
+ */
+bool DRW_object_is_visible_in_active_context(const Object *ob)
+{
+ const eObjectVisibilityCheck mode = DRW_state_is_scene_render() ?
+ OB_VISIBILITY_CHECK_FOR_RENDER :
+ OB_VISIBILITY_CHECK_FOR_VIEWPORT;
+ return BKE_object_is_visible(ob, mode);
+}
+
+bool DRW_object_is_flat_normal(const Object *ob)
+{
+ if (ob->type == OB_MESH) {
+ const Mesh *me = ob->data;
+ if (me->mpoly && me->mpoly[0].flag & ME_SMOOTH) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool DRW_object_use_hide_faces(const struct Object *ob)
+{
+ if (ob->type == OB_MESH) {
+ const Mesh *me = ob->data;
+
+ switch (ob->mode) {
+ case OB_MODE_TEXTURE_PAINT:
+ case OB_MODE_VERTEX_PAINT:
+ return (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+ case OB_MODE_WEIGHT_PAINT:
+ return (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ }
+ }
+
+ return false;
+}
+
+bool DRW_object_is_visible_psys_in_active_context(
+ const Object *object,
+ const ParticleSystem *psys)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ if (object == draw_ctx->object_edit) {
+ return false;
+ }
+ const ParticleSettings *part = psys->part;
+ const ParticleEditSettings *pset = &scene->toolsettings->particle;
+ if (object->mode == OB_MODE_PARTICLE_EDIT) {
+ if (psys_in_edit_mode(draw_ctx->depsgraph, psys)) {
+ if ((pset->flag & PE_DRAW_PART) == 0) {
+ return false;
+ }
+ if ((part->childtype == 0) &&
+ (psys->flag & PSYS_HAIR_DYNAMICS &&
+ psys->pointcache->flag & PTCACHE_BAKED) == 0)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+struct Object *DRW_object_get_dupli_parent(const Object *UNUSED(ob))
+{
+ return DST.dupli_parent;
+}
+
+struct DupliObject *DRW_object_get_dupli(const Object *UNUSED(ob))
+{
+ return DST.dupli_source;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Color Management
+ * \{ */
+
+/* Use color management profile to draw texture to framebuffer */
+void DRW_transform_to_display(GPUTexture *tex, bool use_view_settings)
+{
+ drw_state_set(DRW_STATE_WRITE_COLOR);
+
+ GPUVertFormat *vert_format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint texco = GPU_vertformat_attr_add(vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ const float dither = 1.0f;
+
+ bool use_ocio = false;
+
+ /* View transform is already applied for offscreen, don't apply again, see: T52046 */
+ if (!(DST.options.is_image_render && !DST.options.is_scene_render)) {
+ Scene *scene = DST.draw_ctx.scene;
+ ColorManagedDisplaySettings *display_settings = &scene->display_settings;
+ ColorManagedViewSettings *view_settings = (use_view_settings) ? &scene->view_settings : NULL;
+
+ use_ocio = IMB_colormanagement_setup_glsl_draw_from_space(
+ view_settings, display_settings, NULL, dither, false);
+ }
+
+ if (!use_ocio) {
+ /* View transform is already applied for offscreen, don't apply again, see: T52046 */
+ if (DST.options.is_image_render && !DST.options.is_scene_render) {
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB);
+ }
+ immUniform1i("image", 0);
+ }
+
+ GPU_texture_bind(tex, 0); /* OCIO texture bind point is 0 */
+
+ float mat[4][4];
+ unit_m4(mat);
+ immUniformMatrix4fv("ModelViewProjectionMatrix", mat);
+
+ /* Full screen triangle */
+ immBegin(GPU_PRIM_TRIS, 3);
+ immAttr2f(texco, 0.0f, 0.0f);
+ immVertex2f(pos, -1.0f, -1.0f);
+
+ immAttr2f(texco, 2.0f, 0.0f);
+ immVertex2f(pos, 3.0f, -1.0f);
+
+ immAttr2f(texco, 0.0f, 2.0f);
+ immVertex2f(pos, -1.0f, 3.0f);
+ immEnd();
+
+ GPU_texture_unbind(tex);
+
+ if (use_ocio) {
+ IMB_colormanagement_finish_glsl_draw();
+ }
+ else {
+ immUnbindProgram();
+ }
+}
+
+/* Draw texture to framebuffer without any color transforms */
+void DRW_transform_none(GPUTexture *tex)
+{
+ /* Draw as texture for final render (without immediate mode). */
+ GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_IMAGE_COLOR);
+
+ GPU_texture_bind(tex, 0);
+
+ const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ GPU_batch_uniform_4fv(geom, "color", white);
+
+ float mat[4][4];
+ unit_m4(mat);
+ GPU_batch_uniform_mat4(geom, "ModelViewProjectionMatrix", mat);
+
+ GPU_batch_program_use_begin(geom);
+ GPU_batch_draw_range_ex(geom, 0, 0, false);
+ GPU_batch_program_use_end(geom);
+
+ GPU_texture_unbind(tex);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Multisample Resolve
+ * \{ */
+
+/* Use manual multisample resolve pass.
+ * Much quicker than blitting back and forth.
+ * Assume destination fb is bound*/
+void DRW_multisamples_resolve(GPUTexture *src_depth, GPUTexture *src_color, bool use_depth)
+{
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_PREMUL;
+
+ if (use_depth) {
+ state |= DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ }
+ drw_state_set(state);
+
+ int samples = GPU_texture_samples(src_depth);
+
+ BLI_assert(samples > 0);
+ BLI_assert(GPU_texture_samples(src_color) == samples);
+
+ GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+
+ int builtin;
+ if (use_depth) {
+ switch (samples) {
+ case 2: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST; break;
+ case 4: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST; break;
+ case 8: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST; break;
+ case 16: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST; break;
+ default:
+ BLI_assert("Mulisample count unsupported by blit shader.");
+ builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST;
+ break;
+ }
+ }
+ else {
+ switch (samples) {
+ case 2: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2; break;
+ case 4: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_4; break;
+ case 8: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_8; break;
+ case 16: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_16; break;
+ default:
+ BLI_assert("Mulisample count unsupported by blit shader.");
+ builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2;
+ break;
+ }
+ }
+
+ GPU_batch_program_set_builtin(geom, builtin);
+
+ if (use_depth) {
+ GPU_texture_bind(src_depth, 0);
+ GPU_batch_uniform_1i(geom, "depthMulti", 0);
+ }
+
+ GPU_texture_bind(src_color, 1);
+ GPU_batch_uniform_1i(geom, "colorMulti", 1);
+
+ float mat[4][4];
+ unit_m4(mat);
+ GPU_batch_uniform_mat4(geom, "ModelViewProjectionMatrix", mat);
+
+ /* avoid gpuMatrix calls */
+ GPU_batch_program_use_begin(geom);
+ GPU_batch_draw_range_ex(geom, 0, 0, false);
+ GPU_batch_program_use_end(geom);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Viewport (DRW_viewport)
+ * \{ */
+
+void *drw_viewport_engine_data_ensure(void *engine_type)
+{
+ void *data = GPU_viewport_engine_data_get(DST.viewport, engine_type);
+
+ if (data == NULL) {
+ data = GPU_viewport_engine_data_create(DST.viewport, engine_type);
+ }
+ return data;
+}
+
+void DRW_engine_viewport_data_size_get(
+ const void *engine_type_v,
+ int *r_fbl_len, int *r_txl_len, int *r_psl_len, int *r_stl_len)
+{
+ const DrawEngineType *engine_type = engine_type_v;
+
+ if (r_fbl_len) {
+ *r_fbl_len = engine_type->vedata_size->fbl_len;
+ }
+ if (r_txl_len) {
+ *r_txl_len = engine_type->vedata_size->txl_len;
+ }
+ if (r_psl_len) {
+ *r_psl_len = engine_type->vedata_size->psl_len;
+ }
+ if (r_stl_len) {
+ *r_stl_len = engine_type->vedata_size->stl_len;
+ }
+}
+
+/* WARNING: only use for custom pipeline. 99% of the time, you don't want to use this. */
+void DRW_render_viewport_size_set(int size[2])
+{
+ DST.size[0] = size[0];
+ DST.size[1] = size[1];
+}
+
+const float *DRW_viewport_size_get(void)
+{
+ return DST.size;
+}
+
+const float *DRW_viewport_invert_size_get(void)
+{
+ return DST.inv_size;
+}
+
+const float *DRW_viewport_screenvecs_get(void)
+{
+ return &DST.screenvecs[0][0];
+}
+
+const float *DRW_viewport_pixelsize_get(void)
+{
+ return &DST.pixsize;
+}
+
+static void drw_viewport_cache_resize(void)
+{
+ /* Release the memiter before clearing the mempools that references them */
+ GPU_viewport_cache_release(DST.viewport);
+
+ if (DST.vmempool != NULL) {
+ BLI_mempool_clear_ex(DST.vmempool->calls, BLI_mempool_len(DST.vmempool->calls));
+ BLI_mempool_clear_ex(DST.vmempool->states, BLI_mempool_len(DST.vmempool->states));
+ BLI_mempool_clear_ex(DST.vmempool->shgroups, BLI_mempool_len(DST.vmempool->shgroups));
+ BLI_mempool_clear_ex(DST.vmempool->uniforms, BLI_mempool_len(DST.vmempool->uniforms));
+ BLI_mempool_clear_ex(DST.vmempool->passes, BLI_mempool_len(DST.vmempool->passes));
+ }
+
+ DRW_instance_data_list_free_unused(DST.idatalist);
+ DRW_instance_data_list_resize(DST.idatalist);
+}
+
+/* Not a viewport variable, we could split this out. */
+static void drw_context_state_init(void)
+{
+ if (DST.draw_ctx.obact) {
+ DST.draw_ctx.object_mode = DST.draw_ctx.obact->mode;
+ }
+ else {
+ DST.draw_ctx.object_mode = OB_MODE_OBJECT;
+ }
+
+ /* Edit object. */
+ if (DST.draw_ctx.object_mode & OB_MODE_EDIT) {
+ DST.draw_ctx.object_edit = DST.draw_ctx.obact;
+ }
+ else {
+ DST.draw_ctx.object_edit = NULL;
+ }
+
+ /* Pose object. */
+ if (DST.draw_ctx.object_mode & OB_MODE_POSE) {
+ DST.draw_ctx.object_pose = DST.draw_ctx.obact;
+ }
+ else if (DST.draw_ctx.object_mode & OB_MODE_WEIGHT_PAINT) {
+ DST.draw_ctx.object_pose = BKE_object_pose_armature_get(DST.draw_ctx.obact);
+ }
+ else {
+ DST.draw_ctx.object_pose = NULL;
+ }
+}
+
+/* It also stores viewport variable to an immutable place: DST
+ * This is because a cache uniform only store reference
+ * to its value. And we don't want to invalidate the cache
+ * if this value change per viewport */
+static void drw_viewport_var_init(void)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+ /* Refresh DST.size */
+ if (DST.viewport) {
+ int size[2];
+ GPU_viewport_size_get(DST.viewport, size);
+ DST.size[0] = size[0];
+ DST.size[1] = size[1];
+ DST.inv_size[0] = 1.0f / size[0];
+ DST.inv_size[1] = 1.0f / size[1];
+
+ DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(DST.viewport);
+ DST.default_framebuffer = fbl->default_fb;
+
+ DST.vmempool = GPU_viewport_mempool_get(DST.viewport);
+
+ if (DST.vmempool->calls == NULL) {
+ DST.vmempool->calls = BLI_mempool_create(sizeof(DRWCall), 0, 512, 0);
+ }
+ if (DST.vmempool->states == NULL) {
+ DST.vmempool->states = BLI_mempool_create(sizeof(DRWCallState), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+ }
+ if (DST.vmempool->shgroups == NULL) {
+ DST.vmempool->shgroups = BLI_mempool_create(sizeof(DRWShadingGroup), 0, 256, 0);
+ }
+ if (DST.vmempool->uniforms == NULL) {
+ DST.vmempool->uniforms = BLI_mempool_create(sizeof(DRWUniform), 0, 512, 0);
+ }
+ if (DST.vmempool->passes == NULL) {
+ DST.vmempool->passes = BLI_mempool_create(sizeof(DRWPass), 0, 64, 0);
+ }
+
+ DST.idatalist = GPU_viewport_instance_data_list_get(DST.viewport);
+ DRW_instance_data_list_reset(DST.idatalist);
+ }
+ else {
+ DST.size[0] = 0;
+ DST.size[1] = 0;
+
+ DST.inv_size[0] = 0;
+ DST.inv_size[1] = 0;
+
+ DST.default_framebuffer = NULL;
+ DST.vmempool = NULL;
+ }
+
+ if (rv3d != NULL) {
+ /* Refresh DST.screenvecs */
+ copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]);
+ copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]);
+ normalize_v3(DST.screenvecs[0]);
+ normalize_v3(DST.screenvecs[1]);
+
+ /* Refresh DST.pixelsize */
+ DST.pixsize = rv3d->pixsize;
+
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERS], rv3d->persmat);
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERSINV], rv3d->persinv);
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEW], rv3d->viewmat);
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEWINV], rv3d->viewinv);
+ copy_m4_m4(DST.original_mat.mat[DRW_MAT_WIN], rv3d->winmat);
+ invert_m4_m4(DST.original_mat.mat[DRW_MAT_WININV], rv3d->winmat);
+
+ memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DST.original_mat.mat));
+
+ copy_v4_v4(DST.view_data.viewcamtexcofac, rv3d->viewcamtexcofac);
+ }
+ else {
+ copy_v4_fl4(DST.view_data.viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f);
+ }
+
+ /* Reset facing */
+ DST.frontface = GL_CCW;
+ DST.backface = GL_CW;
+ glFrontFace(DST.frontface);
+
+ if (DST.draw_ctx.object_edit) {
+ ED_view3d_init_mats_rv3d(DST.draw_ctx.object_edit, rv3d);
+ }
+
+ /* Alloc array of texture reference. */
+ if (DST.RST.bound_texs == NULL) {
+ DST.RST.bound_texs = MEM_callocN(sizeof(GPUTexture *) * GPU_max_textures(), "Bound GPUTexture refs");
+ }
+ if (DST.RST.bound_tex_slots == NULL) {
+ DST.RST.bound_tex_slots = MEM_callocN(sizeof(char) * GPU_max_textures(), "Bound Texture Slots");
+ }
+ if (DST.RST.bound_ubos == NULL) {
+ DST.RST.bound_ubos = MEM_callocN(sizeof(GPUUniformBuffer *) * GPU_max_ubo_binds(), "Bound GPUUniformBuffer refs");
+ }
+ if (DST.RST.bound_ubo_slots == NULL) {
+ DST.RST.bound_ubo_slots = MEM_callocN(sizeof(char) * GPU_max_ubo_binds(), "Bound Ubo Slots");
+ }
+
+ if (view_ubo == NULL) {
+ view_ubo = DRW_uniformbuffer_create(sizeof(ViewUboStorage), NULL);
+ }
+
+ DST.override_mat = 0;
+ DST.dirty_mat = true;
+ DST.state_cache_id = 1;
+
+ DST.clipping.updated = false;
+
+ memset(DST.object_instance_data, 0x0, sizeof(DST.object_instance_data));
+}
+
+void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type)
+{
+ BLI_assert(type >= 0 && type < DRW_MAT_COUNT);
+ /* Can't use this in render mode. */
+ BLI_assert(((DST.override_mat & (1 << type)) != 0) || DST.draw_ctx.rv3d != NULL);
+
+ copy_m4_m4(mat, DST.view_data.matstate.mat[type]);
+}
+
+void DRW_viewport_matrix_get_all(DRWMatrixState *state)
+{
+ memcpy(state, DST.view_data.matstate.mat, sizeof(DRWMatrixState));
+}
+
+void DRW_viewport_matrix_override_set(const float mat[4][4], DRWViewportMatrixType type)
+{
+ BLI_assert(type < DRW_MAT_COUNT);
+ copy_m4_m4(DST.view_data.matstate.mat[type], mat);
+ DST.override_mat |= (1 << type);
+ DST.dirty_mat = true;
+ DST.clipping.updated = false;
+}
+
+void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type)
+{
+ BLI_assert(type < DRW_MAT_COUNT);
+ copy_m4_m4(DST.view_data.matstate.mat[type], DST.original_mat.mat[type]);
+ DST.override_mat &= ~(1 << type);
+ DST.dirty_mat = true;
+ DST.clipping.updated = false;
+}
+
+void DRW_viewport_matrix_override_set_all(DRWMatrixState *state)
+{
+ memcpy(DST.view_data.matstate.mat, state, sizeof(DRWMatrixState));
+ DST.override_mat = 0xFFFFFF;
+ DST.dirty_mat = true;
+ DST.clipping.updated = false;
+}
+
+void DRW_viewport_matrix_override_unset_all(void)
+{
+ memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DRWMatrixState));
+ DST.override_mat = 0;
+ DST.dirty_mat = true;
+ DST.clipping.updated = false;
+}
+
+bool DRW_viewport_is_persp_get(void)
+{
+ RegionView3D *rv3d = DST.draw_ctx.rv3d;
+ if (rv3d) {
+ return rv3d->is_persp;
+ }
+ else {
+ return DST.view_data.matstate.mat[DRW_MAT_WIN][3][3] == 0.0f;
+ }
+}
+
+float DRW_viewport_near_distance_get(void)
+{
+ float projmat[4][4];
+ DRW_viewport_matrix_get(projmat, DRW_MAT_WIN);
+
+ if (DRW_viewport_is_persp_get()) {
+ return -projmat[3][2] / (projmat[2][2] - 1.0f);
+ }
+ else {
+ return -(projmat[3][2] + 1.0f) / projmat[2][2];
+ }
+}
+
+float DRW_viewport_far_distance_get(void)
+{
+ float projmat[4][4];
+ DRW_viewport_matrix_get(projmat, DRW_MAT_WIN);
+
+ if (DRW_viewport_is_persp_get()) {
+ return -projmat[3][2] / (projmat[2][2] + 1.0f);
+ }
+ else {
+ return -(projmat[3][2] - 1.0f) / projmat[2][2];
+ }
+}
+
+DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void)
+{
+ return GPU_viewport_framebuffer_list_get(DST.viewport);
+}
+
+DefaultTextureList *DRW_viewport_texture_list_get(void)
+{
+ return GPU_viewport_texture_list_get(DST.viewport);
+}
+
+void DRW_viewport_request_redraw(void)
+{
+ GPU_viewport_tag_update(DST.viewport);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name ViewLayers (DRW_scenelayer)
+ * \{ */
+
+void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type)
+{
+ for (ViewLayerEngineData *sled = DST.draw_ctx.view_layer->drawdata.first; sled; sled = sled->next) {
+ if (sled->engine_type == engine_type) {
+ return sled->storage;
+ }
+ }
+ return NULL;
+}
+
+void **DRW_view_layer_engine_data_ensure_ex(
+ ViewLayer *view_layer, DrawEngineType *engine_type, void (*callback)(void *storage))
+{
+ ViewLayerEngineData *sled;
+
+ for (sled = view_layer->drawdata.first; sled; sled = sled->next) {
+ if (sled->engine_type == engine_type) {
+ return &sled->storage;
+ }
+ }
+
+ sled = MEM_callocN(sizeof(ViewLayerEngineData), "ViewLayerEngineData");
+ sled->engine_type = engine_type;
+ sled->free = callback;
+ BLI_addtail(&view_layer->drawdata, sled);
+
+ return &sled->storage;
+}
+
+void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage))
+{
+ return DRW_view_layer_engine_data_ensure_ex(DST.draw_ctx.view_layer, engine_type, callback);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw Data (DRW_drawdata)
+ * \{ */
+
+/* Used for DRW_drawdata_from_id()
+ * All ID-datablocks which have their own 'local' DrawData
+ * should have the same arrangement in their structs.
+ */
+typedef struct IdDdtTemplate {
+ ID id;
+ struct AnimData *adt;
+ DrawDataList drawdata;
+} IdDdtTemplate;
+
+/* Check if ID can have AnimData */
+static bool id_type_can_have_drawdata(const short id_type)
+{
+ /* Only some ID-blocks have this info for now */
+ /* TODO: finish adding this for the other blocktypes */
+ switch (id_type) {
+ /* has DrawData */
+ case ID_OB:
+ case ID_WO:
+ return true;
+
+ /* no DrawData */
+ default:
+ return false;
+ }
+}
+
+static bool id_can_have_drawdata(const ID *id)
+{
+ /* sanity check */
+ if (id == NULL)
+ return false;
+
+ return id_type_can_have_drawdata(GS(id->name));
+}
+
+/* Get DrawData from the given ID-block. In order for this to work, we assume that
+ * the DrawData pointer is stored in the struct in the same fashion as in IdDdtTemplate.
+ */
+DrawDataList *DRW_drawdatalist_from_id(ID *id)
+{
+ /* only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdDdtTemplate, and extract the
+ * DrawData that way
+ */
+ if (id_can_have_drawdata(id)) {
+ IdDdtTemplate *idt = (IdDdtTemplate *)id;
+ return &idt->drawdata;
+ }
+ else
+ return NULL;
+}
+
+DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type)
+{
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+
+ if (drawdata == NULL)
+ return NULL;
+
+ LISTBASE_FOREACH(DrawData *, dd, drawdata) {
+ if (dd->engine_type == engine_type) {
+ return dd;
+ }
+ }
+ return NULL;
+}
+
+DrawData *DRW_drawdata_ensure(
+ ID *id,
+ DrawEngineType *engine_type,
+ size_t size,
+ DrawDataInitCb init_cb,
+ DrawDataFreeCb free_cb)
+{
+ BLI_assert(size >= sizeof(DrawData));
+ BLI_assert(id_can_have_drawdata(id));
+ /* Try to re-use existing data. */
+ DrawData *dd = DRW_drawdata_get(id, engine_type);
+ if (dd != NULL) {
+ return dd;
+ }
+
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+
+ /* Allocate new data. */
+ if ((GS(id->name) == ID_OB) && (((Object *)id)->base_flag & BASE_FROMDUPLI) != 0) {
+ /* NOTE: data is not persistent in this case. It is reset each redraw. */
+ BLI_assert(free_cb == NULL); /* No callback allowed. */
+ /* Round to sizeof(float) for DRW_instance_data_request(). */
+ const size_t t = sizeof(float) - 1;
+ size = (size + t) & ~t;
+ size_t fsize = size / sizeof(float);
+ BLI_assert(fsize < MAX_INSTANCE_DATA_SIZE);
+ if (DST.object_instance_data[fsize] == NULL) {
+ DST.object_instance_data[fsize] = DRW_instance_data_request(DST.idatalist, fsize);
+ }
+ dd = (DrawData *)DRW_instance_data_next(DST.object_instance_data[fsize]);
+ memset(dd, 0, size);
+ }
+ else {
+ dd = MEM_callocN(size, "DrawData");
+ }
+ dd->engine_type = engine_type;
+ dd->free = free_cb;
+ /* Perform user-side initialization, if needed. */
+ if (init_cb != NULL) {
+ init_cb(dd);
+ }
+ /* Register in the list. */
+ BLI_addtail((ListBase *)drawdata, dd);
+ return dd;
+}
+
+void DRW_drawdata_free(ID *id)
+{
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+
+ if (drawdata == NULL)
+ return;
+
+ LISTBASE_FOREACH(DrawData *, dd, drawdata) {
+ if (dd->free != NULL) {
+ dd->free(dd);
+ }
+ }
+
+ BLI_freelistN((ListBase *)drawdata);
+}
+
+/* Unlink (but don't free) the drawdata from the DrawDataList if the ID is an OB from dupli. */
+static void drw_drawdata_unlink_dupli(ID *id)
+{
+ if ((GS(id->name) == ID_OB) && (((Object *)id)->base_flag & BASE_FROMDUPLI) != 0) {
+ DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
+
+ if (drawdata == NULL)
+ return;
+
+ BLI_listbase_clear((ListBase *)drawdata);
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Rendering (DRW_engines)
+ * \{ */
+
+static void drw_engines_init(void)
+{
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+ PROFILE_START(stime);
+
+ if (engine->engine_init) {
+ engine->engine_init(data);
+ }
+
+ PROFILE_END_UPDATE(data->init_time, stime);
+ }
+}
+
+static void drw_engines_cache_init(void)
+{
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ if (data->text_draw_cache) {
+ DRW_text_cache_destroy(data->text_draw_cache);
+ data->text_draw_cache = NULL;
+ }
+ if (DST.text_store_p == NULL) {
+ DST.text_store_p = &data->text_draw_cache;
+ }
+
+ if (engine->cache_init) {
+ engine->cache_init(data);
+ }
+ }
+}
+
+static void drw_engines_world_update(Scene *scene)
+{
+ if (scene->world == NULL) {
+ return;
+ }
+
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ if (engine->id_update) {
+ engine->id_update(data, &scene->world->id);
+ }
+ }
+}
+
+static void drw_engines_cache_populate(Object *ob)
+{
+ DST.ob_state = NULL;
+
+ /* HACK: DrawData is copied by COW from the duplicated object.
+ * This is valid for IDs that cannot be instantiated but this
+ * is not what we want in this case so we clear the pointer
+ * ourselves here. */
+ drw_drawdata_unlink_dupli((ID *)ob);
+
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ if (engine->id_update) {
+ engine->id_update(data, &ob->id);
+ }
+
+ if (engine->cache_populate) {
+ engine->cache_populate(data, ob);
+ }
+ }
+
+ /* ... and clearing it here too because theses draw data are
+ * from a mempool and must not be free individually by depsgraph. */
+ drw_drawdata_unlink_dupli((ID *)ob);
+}
+
+static void drw_engines_cache_finish(void)
+{
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ if (engine->cache_finish) {
+ engine->cache_finish(data);
+ }
+ }
+}
+
+static void drw_engines_draw_background(void)
+{
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ if (engine->draw_background) {
+ PROFILE_START(stime);
+
+ DRW_stats_group_start(engine->idname);
+ engine->draw_background(data);
+ DRW_stats_group_end();
+
+ PROFILE_END_UPDATE(data->background_time, stime);
+ return;
+ }
+ }
+
+ /* No draw_background found, doing default background */
+ if (DRW_state_draw_background()) {
+ DRW_draw_background();
+ }
+}
+
+static void drw_engines_draw_scene(void)
+{
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+ PROFILE_START(stime);
+
+ if (engine->draw_scene) {
+ DRW_stats_group_start(engine->idname);
+ engine->draw_scene(data);
+ /* Restore for next engine */
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(DST.default_framebuffer);
+ }
+ DRW_stats_group_end();
+ }
+
+ PROFILE_END_UPDATE(data->render_time, stime);
+ }
+}
+
+static void drw_engines_draw_text(void)
+{
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+ PROFILE_START(stime);
+
+ if (data->text_draw_cache) {
+ DRW_text_cache_draw(data->text_draw_cache, DST.draw_ctx.ar);
+ }
+
+ PROFILE_END_UPDATE(data->render_time, stime);
+ }
+}
+
+/* Draw render engine info. */
+void DRW_draw_region_engine_info(int xoffset, int yoffset)
+{
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ if (data->info[0] != '\0') {
+ char *chr_current = data->info;
+ char *chr_start = chr_current;
+ int line_len = 0;
+
+ const int font_id = BLF_default();
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
+
+ BLF_enable(font_id, BLF_SHADOW);
+ BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ BLF_shadow_offset(font_id, 1, -1);
+
+ while (*chr_current++ != '\0') {
+ line_len++;
+ if (*chr_current == '\n') {
+ char info[GPU_INFO_SIZE];
+ BLI_strncpy(info, chr_start, line_len + 1);
+ yoffset -= U.widget_unit;
+ BLF_draw_default(xoffset, yoffset, 0.0f, info, sizeof(info));
+
+ /* Re-start counting. */
+ chr_start = chr_current + 1;
+ line_len = -1;
+ }
+ }
+
+ char info[GPU_INFO_SIZE];
+ BLI_strncpy(info, chr_start, line_len + 1);
+ yoffset -= U.widget_unit;
+ BLF_draw_default(xoffset, yoffset, 0.0f, info, sizeof(info));
+
+ BLF_disable(font_id, BLF_SHADOW);
+ }
+ }
+}
+
+static void use_drw_engine(DrawEngineType *engine)
+{
+ LinkData *ld = MEM_callocN(sizeof(LinkData), "enabled engine link data");
+ ld->data = engine;
+ BLI_addtail(&DST.enabled_engines, ld);
+}
+
+/**
+ * Use for external render engines.
+ */
+static void drw_engines_enable_external(void)
+{
+ use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
+}
+
+/* TODO revisit this when proper layering is implemented */
+/* Gather all draw engines needed and store them in DST.enabled_engines
+ * That also define the rendering order of engines */
+static void drw_engines_enable_from_engine(RenderEngineType *engine_type, int drawtype, bool use_xray)
+{
+ switch (drawtype) {
+ case OB_WIRE:
+ use_drw_engine(&draw_engine_workbench_transparent);
+ break;
+
+ case OB_SOLID:
+ if (use_xray) {
+ use_drw_engine(&draw_engine_workbench_transparent);
+ }
+ else {
+ use_drw_engine(&draw_engine_workbench_solid);
+ }
+ break;
+
+ case OB_MATERIAL:
+ case OB_RENDER:
+ default:
+ /* TODO layers */
+ if (engine_type->draw_engine != NULL) {
+ use_drw_engine(engine_type->draw_engine);
+ }
+
+ if ((engine_type->flag & RE_INTERNAL) == 0) {
+ drw_engines_enable_external();
+ }
+ break;
+ }
+}
+
+static void drw_engines_enable_from_object_mode(void)
+{
+ use_drw_engine(&draw_engine_object_type);
+ /* TODO(fclem) remove this, it does not belong to it's own engine. */
+ use_drw_engine(&draw_engine_motion_path_type);
+}
+
+static void drw_engines_enable_from_paint_mode(int mode)
+{
+ switch (mode) {
+ case CTX_MODE_SCULPT:
+ use_drw_engine(&draw_engine_sculpt_type);
+ break;
+ case CTX_MODE_PAINT_WEIGHT:
+ use_drw_engine(&draw_engine_paint_weight_type);
+ break;
+ case CTX_MODE_PAINT_VERTEX:
+ use_drw_engine(&draw_engine_paint_vertex_type);
+ break;
+ case CTX_MODE_PAINT_TEXTURE:
+ use_drw_engine(&draw_engine_paint_texture_type);
+ break;
+ default:
+ break;
+ }
+}
+
+static void drw_engines_enable_from_mode(int mode)
+{
+ switch (mode) {
+ case CTX_MODE_EDIT_MESH:
+ use_drw_engine(&draw_engine_edit_mesh_type);
+ break;
+ case CTX_MODE_EDIT_SURFACE:
+ case CTX_MODE_EDIT_CURVE:
+ use_drw_engine(&draw_engine_edit_curve_type);
+ break;
+ case CTX_MODE_EDIT_TEXT:
+ use_drw_engine(&draw_engine_edit_text_type);
+ break;
+ case CTX_MODE_EDIT_ARMATURE:
+ use_drw_engine(&draw_engine_edit_armature_type);
+ break;
+ case CTX_MODE_EDIT_METABALL:
+ use_drw_engine(&draw_engine_edit_metaball_type);
+ break;
+ case CTX_MODE_EDIT_LATTICE:
+ use_drw_engine(&draw_engine_edit_lattice_type);
+ break;
+ case CTX_MODE_PARTICLE:
+ use_drw_engine(&draw_engine_particle_type);
+ break;
+ case CTX_MODE_POSE:
+ case CTX_MODE_PAINT_WEIGHT:
+ /* The pose engine clears the depth of the default framebuffer
+ * to draw an object with `OB_DRAWXRAY`.
+ * (different of workbench that has its own framebuffer).
+ * So make sure you call its `draw_scene` after all the other engines. */
+ use_drw_engine(&draw_engine_pose_type);
+ break;
+ case CTX_MODE_SCULPT:
+ case CTX_MODE_PAINT_VERTEX:
+ case CTX_MODE_PAINT_TEXTURE:
+ case CTX_MODE_OBJECT:
+ case CTX_MODE_GPENCIL_PAINT:
+ case CTX_MODE_GPENCIL_EDIT:
+ case CTX_MODE_GPENCIL_SCULPT:
+ case CTX_MODE_GPENCIL_WEIGHT:
+ break;
+ default:
+ BLI_assert(!"Draw mode invalid");
+ break;
+ }
+ /* grease pencil */
+ use_drw_engine(&draw_engine_gpencil_type);
+}
+
+static void drw_engines_enable_from_overlays(int UNUSED(overlay_flag))
+{
+ use_drw_engine(&draw_engine_overlay_type);
+}
+/**
+ * Use for select and depth-drawing.
+ */
+static void drw_engines_enable_basic(void)
+{
+ use_drw_engine(DRW_engine_viewport_basic_type.draw_engine);
+}
+
+static void drw_engines_enable(ViewLayer *view_layer, RenderEngineType *engine_type)
+{
+ Object *obact = OBACT(view_layer);
+ const int mode = CTX_data_mode_enum_ex(DST.draw_ctx.object_edit, obact, DST.draw_ctx.object_mode);
+ View3D *v3d = DST.draw_ctx.v3d;
+ const int drawtype = v3d->shading.type;
+ const bool use_xray = XRAY_ENABLED(v3d);
+
+ drw_engines_enable_from_engine(engine_type, drawtype, use_xray);
+
+ if (DRW_state_draw_support()) {
+ /* Draw paint modes first so that they are drawn below the wireframes. */
+ drw_engines_enable_from_paint_mode(mode);
+ drw_engines_enable_from_overlays(v3d->overlay.flag);
+ drw_engines_enable_from_object_mode();
+ drw_engines_enable_from_mode(mode);
+ }
+ else {
+ /* Force enable overlays engine for wireframe mode */
+ if (v3d->shading.type == OB_WIRE) {
+ drw_engines_enable_from_overlays(v3d->overlay.flag);
+ }
+ /* if gpencil must draw the strokes, but not the object */
+ drw_engines_enable_from_mode(mode);
+ }
+}
+
+static void drw_engines_disable(void)
+{
+ BLI_freelistN(&DST.enabled_engines);
+}
+
+static uint DRW_engines_get_hash(void)
+{
+ uint hash = 0;
+ /* The cache depends on enabled engines */
+ /* FIXME : if collision occurs ... segfault */
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *engine = link->data;
+ hash += BLI_ghashutil_strhash_p(engine->idname);
+ }
+
+ return hash;
+}
+
+/* -------------------------------------------------------------------- */
+
+/** \name View Update
+ * \{ */
+
+void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
+{
+ RenderEngineType *engine_type = update_ctx->engine_type;
+ ARegion *ar = update_ctx->ar;
+ View3D *v3d = update_ctx->v3d;
+ RegionView3D *rv3d = ar->regiondata;
+ Depsgraph *depsgraph = update_ctx->depsgraph;
+ Scene *scene = update_ctx->scene;
+ ViewLayer *view_layer = update_ctx->view_layer;
+
+ /* Separate update for each stereo view. */
+ for (int view = 0; view < 2; view++) {
+ GPUViewport *viewport = WM_draw_region_get_viewport(ar, view);
+ if (!viewport) {
+ continue;
+ }
+
+ /* XXX Really nasty locking. But else this could
+ * be executed by the material previews thread
+ * while rendering a viewport. */
+ BLI_ticket_mutex_lock(DST.gl_context_mutex);
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+
+ DST.viewport = viewport;
+ DST.draw_ctx = (DRWContextState){
+ .ar = ar, .rv3d = rv3d, .v3d = v3d,
+ .scene = scene, .view_layer = view_layer, .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph, .object_mode = OB_MODE_OBJECT,
+ };
+
+ drw_engines_enable(view_layer, engine_type);
+
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *draw_engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine);
+
+ if (draw_engine->view_update) {
+ draw_engine->view_update(data);
+ }
+ }
+
+ DST.viewport = NULL;
+
+ drw_engines_disable();
+
+ BLI_ticket_mutex_unlock(DST.gl_context_mutex);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Main Draw Loops (DRW_draw)
+ * \{ */
+
+/* Everything starts here.
+ * This function takes care of calling all cache and rendering functions
+ * for each relevant engine / mode engine. */
+void DRW_draw_view(const bContext *C)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+ GPUViewport *viewport = WM_draw_region_get_bound_viewport(ar);
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+ DST.options.draw_text = (
+ (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0 &&
+ (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) != 0);
+ DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C);
+}
+
+/**
+ * Used for both regular and off-screen drawing.
+ * Need to reset DST before calling this function
+ */
+void DRW_draw_render_loop_ex(
+ struct Depsgraph *depsgraph,
+ RenderEngineType *engine_type,
+ ARegion *ar, View3D *v3d,
+ GPUViewport *viewport,
+ const bContext *evil_C)
+{
+
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RegionView3D *rv3d = ar->regiondata;
+ bool do_annotations = (((v3d->flag2 & V3D_SHOW_ANNOTATION) != 0) && ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0));
+
+ DST.draw_ctx.evil_C = evil_C;
+ DST.viewport = viewport;
+
+ /* Setup viewport */
+ GPU_viewport_engines_data_validate(DST.viewport, DRW_engines_get_hash());
+
+ DST.draw_ctx = (DRWContextState){
+ .ar = ar, .rv3d = rv3d, .v3d = v3d,
+ .scene = scene, .view_layer = view_layer, .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+
+ /* reuse if caller sets */
+ .evil_C = DST.draw_ctx.evil_C,
+ };
+ drw_context_state_init();
+ drw_viewport_var_init();
+
+ /* Get list of enabled engines */
+ drw_engines_enable(view_layer, engine_type);
+
+ /* Update ubos */
+ DRW_globals_update();
+
+ drw_debug_init();
+ DRW_hair_init();
+
+ /* No framebuffer allowed before drawing. */
+ BLI_assert(GPU_framebuffer_active_get() == NULL);
+
+ /* Init engines */
+ drw_engines_init();
+
+ /* Cache filling */
+ {
+ PROFILE_START(stime);
+ drw_engines_cache_init();
+ drw_engines_world_update(scene);
+
+ const int object_type_exclude_viewport = v3d->object_type_exclude_viewport;
+ DEG_OBJECT_ITER_BEGIN(depsgraph, ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+ {
+ if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
+ continue;
+ }
+ if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ continue;
+ }
+ DST.dupli_parent = data_.dupli_parent;
+ DST.dupli_source = data_.dupli_object_current;
+ drw_engines_cache_populate(ob);
+ }
+ DEG_OBJECT_ITER_END;
+
+ drw_engines_cache_finish();
+
+ DRW_render_instance_buffer_finish();
+
+#ifdef USE_PROFILE
+ double *cache_time = GPU_viewport_cache_time_get(DST.viewport);
+ PROFILE_END_UPDATE(*cache_time, stime);
+#endif
+ }
+
+ DRW_stats_begin();
+
+ GPU_framebuffer_bind(DST.default_framebuffer);
+
+ /* Start Drawing */
+ DRW_state_reset();
+
+ DRW_hair_update();
+
+ drw_engines_draw_background();
+
+ /* WIP, single image drawn over the camera view (replace) */
+ bool do_bg_image = false;
+ if (rv3d->persp == RV3D_CAMOB) {
+ Object *cam_ob = v3d->camera;
+ if (cam_ob && cam_ob->type == OB_CAMERA) {
+ Camera *cam = cam_ob->data;
+ if (!BLI_listbase_is_empty(&cam->bg_images)) {
+ do_bg_image = true;
+ }
+ }
+ }
+
+ GPU_framebuffer_bind(DST.default_framebuffer);
+
+ if (do_bg_image) {
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, false, true);
+ }
+
+ DRW_draw_callbacks_pre_scene();
+ if (DST.draw_ctx.evil_C) {
+ ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_PRE_VIEW);
+ }
+
+ drw_engines_draw_scene();
+
+ /* annotations - temporary drawing buffer (3d space) */
+ /* XXX: Or should we use a proper draw/overlay engine for this case? */
+ if (do_annotations) {
+ glDisable(GL_DEPTH_TEST);
+ /* XXX: as scene->gpd is not copied for COW yet */
+ ED_gpencil_draw_view3d_annotations(DEG_get_input_scene(depsgraph), depsgraph, v3d, ar, true);
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ DRW_draw_callbacks_post_scene();
+ if (DST.draw_ctx.evil_C) {
+ ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_POST_VIEW);
+ }
+
+ DRW_state_reset();
+
+ drw_debug_draw();
+
+ glDisable(GL_DEPTH_TEST);
+ drw_engines_draw_text();
+ glEnable(GL_DEPTH_TEST);
+
+ if (DST.draw_ctx.evil_C) {
+ /* needed so gizmo isn't obscured */
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0))
+ {
+ glDisable(GL_DEPTH_TEST);
+ DRW_draw_gizmo_3d();
+ }
+
+ DRW_draw_region_info();
+
+ /* annotations - temporary drawing buffer (screenspace) */
+ /* XXX: Or should we use a proper draw/overlay engine for this case? */
+ if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
+ (do_annotations))
+ {
+ glDisable(GL_DEPTH_TEST);
+ /* XXX: as scene->gpd is not copied for COW yet */
+ ED_gpencil_draw_view3d_annotations(DEG_get_input_scene(depsgraph), depsgraph, v3d, ar, false);
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
+ /* Draw 2D after region info so we can draw on top of the camera passepartout overlay.
+ * 'DRW_draw_region_info' sets the projection in pixel-space. */
+ glDisable(GL_DEPTH_TEST);
+ DRW_draw_gizmo_2d();
+ glEnable(GL_DEPTH_TEST);
+ }
+ }
+
+ DRW_stats_reset();
+
+ if (do_bg_image) {
+ ED_view3d_draw_bgpic_test(scene, depsgraph, ar, v3d, true, true);
+ }
+
+ if (G.debug_value > 20 && G.debug_value < 30) {
+ glDisable(GL_DEPTH_TEST);
+ rcti rect; /* local coordinate visible rect inside region, to accommodate overlapping ui */
+ ED_region_visible_rect(DST.draw_ctx.ar, &rect);
+ DRW_stats_draw(&rect);
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ if (WM_draw_region_get_bound_viewport(ar)) {
+ /* Don't unbind the framebuffer yet in this case and let
+ * GPU_viewport_unbind do it, so that we can still do further
+ * drawing of action zones on top. */
+ }
+ else {
+ GPU_framebuffer_restore();
+ }
+
+ DRW_state_reset();
+ drw_engines_disable();
+
+ drw_viewport_cache_resize();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+}
+
+void DRW_draw_render_loop(
+ struct Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d,
+ GPUViewport *viewport)
+{
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+
+ DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, NULL);
+}
+
+/* @viewport CAN be NULL, in this case we create one. */
+void DRW_draw_render_loop_offscreen(
+ struct Depsgraph *depsgraph, RenderEngineType *engine_type,
+ ARegion *ar, View3D *v3d,
+ const bool draw_background, GPUOffScreen *ofs,
+ GPUViewport *viewport)
+{
+ /* Create temporary viewport if needed. */
+ GPUViewport *render_viewport = viewport;
+ if (viewport == NULL) {
+ render_viewport = GPU_viewport_create_from_offscreen(ofs);
+ }
+
+ GPU_framebuffer_restore();
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+ DST.options.is_image_render = true;
+ DST.options.draw_background = draw_background;
+ DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, render_viewport, NULL);
+
+ /* Free temporary viewport. */
+ if (viewport == NULL) {
+ /* don't free data owned by 'ofs' */
+ GPU_viewport_clear_from_offscreen(render_viewport);
+ GPU_viewport_free(render_viewport);
+ }
+
+ /* we need to re-bind (annoying!) */
+ GPU_offscreen_bind(ofs, false);
+}
+
+/* Helper to check if exit object type to render. */
+bool DRW_render_check_grease_pencil(Depsgraph *depsgraph)
+{
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
+ {
+ if ((ob->type == OB_GPENCIL) && (DRW_object_is_visible_in_active_context(ob))) {
+ return true;
+ }
+ }
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
+
+ return false;
+}
+
+static void DRW_render_gpencil_to_image(RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect)
+{
+ if (draw_engine_gpencil_type.render_to_image) {
+ ViewportEngineData *gpdata = drw_viewport_engine_data_ensure(&draw_engine_gpencil_type);
+ draw_engine_gpencil_type.render_to_image(gpdata, engine, render_layer, rect);
+ }
+}
+
+void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph)
+{
+ /* This function is only valid for Cycles
+ * Eevee done all work in the Eevee render directly.
+ * Maybe it can be done equal for both engines?
+ */
+ if (STREQ(engine->type->name, "Eevee")) {
+ return;
+ }
+
+ /* Early out if there are no grease pencil objects, especially important
+ * to avoid failing in in background renders without OpenGL context. */
+ if (!DRW_render_check_grease_pencil(depsgraph)) {
+ return;
+ }
+
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RenderEngineType *engine_type = engine->type;
+ RenderData *r = &scene->r;
+ Render *render = engine->re;
+ /* Changing Context */
+ if (G.background && DST.gl_context == NULL) {
+ WM_init_opengl(G_MAIN);
+ }
+
+ void *re_gl_context = RE_gl_context_get(render);
+ void *re_gpu_context = NULL;
+
+ /* Changing Context */
+ if (re_gl_context != NULL) {
+ DRW_opengl_render_context_enable(re_gl_context);
+ /* We need to query gpu context after a gl context has been bound. */
+ re_gpu_context = RE_gpu_context_get(render);
+ DRW_gawain_render_context_enable(re_gpu_context);
+ }
+ else {
+ DRW_opengl_context_enable();
+ }
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+ DST.options.is_image_render = true;
+ DST.options.is_scene_render = true;
+ DST.options.draw_background = scene->r.alphamode == R_ADDSKY;
+ DST.buffer_finish_called = true;
+
+ DST.draw_ctx = (DRWContextState) {
+ .scene = scene, .view_layer = view_layer,
+ .engine_type = engine_type,
+ .depsgraph = depsgraph, .object_mode = OB_MODE_OBJECT,
+ };
+ drw_context_state_init();
+
+ DST.viewport = GPU_viewport_create();
+ const int size[2] = { (r->size * r->xsch) / 100, (r->size * r->ysch) / 100 };
+ GPU_viewport_size_set(DST.viewport, size);
+
+ drw_viewport_var_init();
+
+ /* set default viewport */
+ gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
+ glDisable(GL_SCISSOR_TEST);
+ glViewport(0, 0, size[0], size[1]);
+
+ /* Main rendering. */
+ rctf view_rect;
+ rcti render_rect;
+ RE_GetViewPlane(render, &view_rect, &render_rect);
+ if (BLI_rcti_is_empty(&render_rect)) {
+ BLI_rcti_init(&render_rect, 0, size[0], 0, size[1]);
+ }
+
+ RenderResult *render_result = RE_engine_get_result(engine);
+ RenderLayer *render_layer = render_result->layers.first;
+
+ DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
+
+ /* Force cache to reset. */
+ drw_viewport_cache_resize();
+ GPU_viewport_free(DST.viewport);
+ DRW_state_reset();
+
+ glDisable(GL_DEPTH_TEST);
+
+ /* Restore Drawing area. */
+ gpuPopAttrib();
+ glEnable(GL_SCISSOR_TEST);
+ GPU_framebuffer_restore();
+
+ /* Changing Context */
+ /* GPXX Review this context */
+ DRW_opengl_context_disable();
+
+ DST.buffer_finish_called = false;
+}
+
+void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RenderEngineType *engine_type = engine->type;
+ DrawEngineType *draw_engine_type = engine_type->draw_engine;
+ RenderData *r = &scene->r;
+ Render *render = engine->re;
+
+ if (G.background && DST.gl_context == NULL) {
+ WM_init_opengl(G_MAIN);
+ }
+
+ void *re_gl_context = RE_gl_context_get(render);
+ void *re_gpu_context = NULL;
+
+ /* Changing Context */
+ if (re_gl_context != NULL) {
+ DRW_opengl_render_context_enable(re_gl_context);
+ /* We need to query gpu context after a gl context has been bound. */
+ re_gpu_context = RE_gpu_context_get(render);
+ DRW_gawain_render_context_enable(re_gpu_context);
+ }
+ else {
+ DRW_opengl_context_enable();
+ }
+
+ /* IMPORTANT: We dont support immediate mode in render mode!
+ * This shall remain in effect until immediate mode supports
+ * multiple threads. */
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+ DST.options.is_image_render = true;
+ DST.options.is_scene_render = true;
+ DST.options.draw_background = scene->r.alphamode == R_ADDSKY;
+
+ DST.draw_ctx = (DRWContextState){
+ .scene = scene, .view_layer = view_layer,
+ .engine_type = engine_type,
+ .depsgraph = depsgraph, .object_mode = OB_MODE_OBJECT,
+ };
+ drw_context_state_init();
+
+ DST.viewport = GPU_viewport_create();
+ const int size[2] = {(r->size * r->xsch) / 100, (r->size * r->ysch) / 100};
+ GPU_viewport_size_set(DST.viewport, size);
+
+ drw_viewport_var_init();
+
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine_type);
+
+ /* set default viewport */
+ glViewport(0, 0, size[0], size[1]);
+
+ /* Main rendering. */
+ rctf view_rect;
+ rcti render_rect;
+ RE_GetViewPlane(render, &view_rect, &render_rect);
+ if (BLI_rcti_is_empty(&render_rect)) {
+ BLI_rcti_init(&render_rect, 0, size[0], 0, size[1]);
+ }
+
+ /* Init render result. */
+ RenderResult *render_result = RE_engine_begin_result(
+ engine,
+ 0,
+ 0,
+ (int)size[0],
+ (int)size[1],
+ view_layer->name,
+ /* RR_ALL_VIEWS */ NULL);
+
+ RenderLayer *render_layer = render_result->layers.first;
+ for (RenderView *render_view = render_result->views.first;
+ render_view != NULL;
+ render_view = render_view->next)
+ {
+ RE_SetActiveRenderView(render, render_view->name);
+ engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
+ /* grease pencil: render result is merged in the previous render result. */
+ if (DRW_render_check_grease_pencil(depsgraph)) {
+ DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
+ }
+ DST.buffer_finish_called = false;
+ }
+
+ RE_engine_end_result(engine, render_result, false, false, false);
+
+ /* Force cache to reset. */
+ drw_viewport_cache_resize();
+
+ GPU_viewport_free(DST.viewport);
+ GPU_framebuffer_restore();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+
+ /* Changing Context */
+ if (re_gl_context != NULL) {
+ DRW_gawain_render_context_disable(re_gpu_context);
+ DRW_opengl_render_context_disable(re_gl_context);
+ }
+ else {
+ DRW_opengl_context_disable();
+ }
+}
+
+void DRW_render_object_iter(
+ void *vedata, RenderEngine *engine, struct Depsgraph *depsgraph,
+ void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph))
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ DRW_hair_init();
+
+ const int object_type_exclude_viewport = draw_ctx->v3d ? draw_ctx->v3d->object_type_exclude_viewport : 0;
+ DEG_OBJECT_ITER_BEGIN(depsgraph, ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+ {
+ if ((object_type_exclude_viewport & (1 << ob->type)) == 0) {
+ DST.dupli_parent = data_.dupli_parent;
+ DST.dupli_source = data_.dupli_object_current;
+ DST.ob_state = NULL;
+ callback(vedata, ob, engine, depsgraph);
+ }
+ }
+ DEG_OBJECT_ITER_END
+}
+
+/* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired).
+ * This function only setup DST and execute the given function.
+ * Warning: similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl). */
+void DRW_custom_pipeline(
+ DrawEngineType *draw_engine_type,
+ struct Depsgraph *depsgraph,
+ void (*callback)(void *vedata, void *user_data),
+ void *user_data)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+ DST.options.is_image_render = true;
+ DST.options.is_scene_render = true;
+ DST.options.draw_background = false;
+
+ DST.draw_ctx = (DRWContextState){
+ .scene = scene,
+ .view_layer = view_layer,
+ .engine_type = NULL,
+ .depsgraph = depsgraph,
+ .object_mode = OB_MODE_OBJECT,
+ };
+ drw_context_state_init();
+
+ DST.viewport = GPU_viewport_create();
+ const int size[2] = {1, 1};
+ GPU_viewport_size_set(DST.viewport, size);
+
+ drw_viewport_var_init();
+
+ DRW_hair_init();
+
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine_type);
+
+ /* Execute the callback */
+ callback(data, user_data);
+ DST.buffer_finish_called = false;
+
+ GPU_viewport_free(DST.viewport);
+ GPU_framebuffer_restore();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+}
+
+static struct DRWSelectBuffer {
+ struct GPUFrameBuffer *framebuffer;
+ struct GPUTexture *texture_depth;
+} g_select_buffer = {NULL};
+
+static void draw_select_framebuffer_setup(const rcti *rect)
+{
+ if (g_select_buffer.framebuffer == NULL) {
+ g_select_buffer.framebuffer = GPU_framebuffer_create();
+ }
+
+ /* If size mismatch recreate the texture. */
+ if ((g_select_buffer.texture_depth != NULL) &&
+ ((GPU_texture_width(g_select_buffer.texture_depth) != BLI_rcti_size_x(rect)) ||
+ (GPU_texture_height(g_select_buffer.texture_depth) != BLI_rcti_size_y(rect))))
+ {
+ GPU_texture_free(g_select_buffer.texture_depth);
+ g_select_buffer.texture_depth = NULL;
+ }
+
+ if (g_select_buffer.texture_depth == NULL) {
+ g_select_buffer.texture_depth = GPU_texture_create_2D(
+ BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), GPU_DEPTH_COMPONENT24, NULL, NULL);
+
+ GPU_framebuffer_texture_attach(g_select_buffer.framebuffer, g_select_buffer.texture_depth, 0, 0);
+
+ if (!GPU_framebuffer_check_valid(g_select_buffer.framebuffer, NULL)) {
+ printf("Error invalid selection framebuffer\n");
+ }
+ }
+}
+
+/* Must run after all instance datas have been added. */
+void DRW_render_instance_buffer_finish(void)
+{
+ BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!");
+ DST.buffer_finish_called = true;
+ DRW_instance_buffer_finish(DST.idatalist);
+}
+
+/**
+ * object mode select-loop, see: ED_view3d_draw_select_loop (legacy drawing).
+ */
+void DRW_draw_select_loop(
+ struct Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d,
+ bool UNUSED(use_obedit_skip), bool draw_surface, bool UNUSED(use_nearest), const rcti *rect,
+ DRW_SelectPassFn select_pass_fn, void *select_pass_user_data,
+ DRW_ObjectFilterFn object_filter_fn, void *object_filter_user_data)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ Object *obact = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(obact);
+#ifndef USE_GPU_SELECT
+ UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect);
+#else
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+
+ bool use_obedit = false;
+ int obedit_mode = 0;
+ if (obedit != NULL) {
+ if (obedit->type == OB_MBALL) {
+ use_obedit = true;
+ obedit_mode = CTX_MODE_EDIT_METABALL;
+ }
+ else if (obedit->type == OB_ARMATURE) {
+ use_obedit = true;
+ obedit_mode = CTX_MODE_EDIT_ARMATURE;
+ }
+ }
+ if (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT) {
+ if (!(v3d->flag2 & V3D_RENDER_OVERRIDE)) {
+ /* Note: don't use "BKE_object_pose_armature_get" here, it breaks selection. */
+ Object *obpose = OBPOSE_FROM_OBACT(obact);
+ if (obpose) {
+ use_obedit = true;
+ obedit_mode = CTX_MODE_POSE;
+ }
+ }
+ }
+
+ struct GPUViewport *viewport = GPU_viewport_create();
+ GPU_viewport_size_set(viewport, (const int[2]){BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)});
+
+ DST.viewport = viewport;
+ DST.options.is_select = true;
+
+ /* Get list of enabled engines */
+ if (use_obedit) {
+ drw_engines_enable_from_paint_mode(obedit_mode);
+ drw_engines_enable_from_mode(obedit_mode);
+ }
+ else if (!draw_surface) {
+ drw_engines_enable_from_overlays(v3d->overlay.flag);
+ drw_engines_enable_from_object_mode();
+ }
+ else {
+ drw_engines_enable_basic();
+ drw_engines_enable_from_overlays(v3d->overlay.flag);
+ drw_engines_enable_from_object_mode();
+ }
+
+ /* Setup viewport */
+
+ /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
+ DST.draw_ctx = (DRWContextState){
+ .ar = ar, .rv3d = rv3d, .v3d = v3d,
+ .scene = scene, .view_layer = view_layer, .obact = obact,
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+ };
+ drw_context_state_init();
+ drw_viewport_var_init();
+
+ /* Update ubos */
+ DRW_globals_update();
+
+ /* Init engines */
+ drw_engines_init();
+ DRW_hair_init();
+
+ {
+ drw_engines_cache_init();
+ drw_engines_world_update(scene);
+
+ if (use_obedit) {
+#if 0
+ drw_engines_cache_populate(obact);
+#else
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->mode, ob_iter) {
+ drw_engines_cache_populate(ob_iter);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+#endif
+ }
+ else {
+ const int object_type_exclude_select = (
+ v3d->object_type_exclude_viewport | v3d->object_type_exclude_select
+ );
+ bool filter_exclude = false;
+ DEG_OBJECT_ITER_BEGIN(depsgraph, ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+ {
+ if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ continue;
+ }
+
+ if ((ob->base_flag & BASE_SELECTABLE) &&
+ (object_type_exclude_select & (1 << ob->type)) == 0)
+ {
+ if (object_filter_fn != NULL) {
+ if (ob->base_flag & BASE_FROMDUPLI) {
+ /* pass (use previous filter_exclude value) */
+ }
+ else {
+ filter_exclude = (object_filter_fn(ob, object_filter_user_data) == false);
+ }
+ if (filter_exclude) {
+ continue;
+ }
+ }
+
+ /* This relies on dupli instances being after their instancing object. */
+ if ((ob->base_flag & BASE_FROMDUPLI) == 0) {
+ Object *ob_orig = DEG_get_original_object(ob);
+ DRW_select_load_id(ob_orig->select_color);
+ }
+ DST.dupli_parent = data_.dupli_parent;
+ DST.dupli_source = data_.dupli_object_current;
+ drw_engines_cache_populate(ob);
+ }
+ }
+ DEG_OBJECT_ITER_END;
+ }
+
+ drw_engines_cache_finish();
+
+ DRW_render_instance_buffer_finish();
+ }
+
+ /* Setup framebuffer */
+ draw_select_framebuffer_setup(rect);
+ GPU_framebuffer_bind(g_select_buffer.framebuffer);
+ GPU_framebuffer_clear_depth(g_select_buffer.framebuffer, 1.0f);
+
+ /* Start Drawing */
+ DRW_state_reset();
+ DRW_draw_callbacks_pre_scene();
+
+ DRW_hair_update();
+
+ DRW_state_lock(
+ DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_ALWAYS |
+ DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_DEPTH_EQUAL |
+ DRW_STATE_DEPTH_GREATER |
+ DRW_STATE_DEPTH_ALWAYS);
+
+ /* Only 1-2 passes. */
+ while (true) {
+ if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) {
+ break;
+ }
+
+ drw_engines_draw_scene();
+
+ if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) {
+ break;
+ }
+ }
+
+ DRW_state_lock(0);
+
+ DRW_draw_callbacks_post_scene();
+
+ DRW_state_reset();
+ drw_engines_disable();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+ GPU_framebuffer_restore();
+
+ /* Cleanup for selection state */
+ GPU_viewport_free(viewport);
+#endif /* USE_GPU_SELECT */
+}
+
+static void draw_depth_texture_to_screen(GPUTexture *texture)
+{
+ const float w = (float)GPU_texture_width(texture);
+ const float h = (float)GPU_texture_height(texture);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_DEPTH_COPY);
+
+ GPU_texture_bind(texture, 0);
+
+ immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
+
+ immBegin(GPU_PRIM_TRI_STRIP, 4);
+
+ immAttr2f(texcoord, 0.0f, 0.0f);
+ immVertex2f(pos, 0.0f, 0.0f);
+
+ immAttr2f(texcoord, 1.0f, 0.0f);
+ immVertex2f(pos, w, 0.0f);
+
+ immAttr2f(texcoord, 0.0f, 1.0f);
+ immVertex2f(pos, 0.0f, h);
+
+ immAttr2f(texcoord, 1.0f, 1.0f);
+ immVertex2f(pos, w, h);
+
+ immEnd();
+
+ GPU_texture_unbind(texture);
+
+ immUnbindProgram();
+}
+
+/**
+ * object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing).
+ */
+void DRW_draw_depth_loop(
+ Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ RegionView3D *rv3d = ar->regiondata;
+
+ DRW_opengl_context_enable();
+
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
+
+ struct GPUViewport *viewport = GPU_viewport_create();
+ GPU_viewport_size_set(viewport, (const int[2]){ar->winx, ar->winy});
+
+ /* Setup framebuffer */
+ draw_select_framebuffer_setup(&ar->winrct);
+ GPU_framebuffer_bind(g_select_buffer.framebuffer);
+ GPU_framebuffer_clear_depth(g_select_buffer.framebuffer, 1.0f);
+
+ DST.viewport = viewport;
+ DST.options.is_depth = true;
+
+ /* Get list of enabled engines */
+ {
+ drw_engines_enable_basic();
+ drw_engines_enable_from_object_mode();
+ }
+
+ /* Setup viewport */
+
+ /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
+ DST.draw_ctx = (DRWContextState){
+ .ar = ar, .rv3d = rv3d, .v3d = v3d,
+ .scene = scene, .view_layer = view_layer, .obact = OBACT(view_layer),
+ .engine_type = engine_type,
+ .depsgraph = depsgraph,
+ };
+ drw_context_state_init();
+ drw_viewport_var_init();
+
+ /* Update ubos */
+ DRW_globals_update();
+
+ /* Init engines */
+ drw_engines_init();
+ DRW_hair_init();
+
+ {
+ drw_engines_cache_init();
+ drw_engines_world_update(scene);
+
+ const int object_type_exclude_viewport = v3d->object_type_exclude_viewport;
+ DEG_OBJECT_ITER_BEGIN(depsgraph, ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+ {
+ if ((object_type_exclude_viewport & (1 << ob->type)) != 0) {
+ continue;
+ }
+
+ if (v3d->localvd && ((v3d->local_view_uuid & ob->base_local_view_bits) == 0)) {
+ continue;
+ }
+
+ DST.dupli_parent = data_.dupli_parent;
+ DST.dupli_source = data_.dupli_object_current;
+ drw_engines_cache_populate(ob);
+ }
+ DEG_OBJECT_ITER_END;
+
+ drw_engines_cache_finish();
+
+ DRW_render_instance_buffer_finish();
+ }
+
+ /* Start Drawing */
+ DRW_state_reset();
+
+ DRW_hair_update();
+
+ DRW_draw_callbacks_pre_scene();
+ drw_engines_draw_scene();
+ DRW_draw_callbacks_post_scene();
+
+ DRW_state_reset();
+ drw_engines_disable();
+
+#ifdef DEBUG
+ /* Avoid accidental reuse. */
+ drw_state_ensure_not_reused(&DST);
+#endif
+
+ /* TODO: Reading depth for operators should be done here. */
+
+ GPU_framebuffer_restore();
+
+ /* Cleanup for selection state */
+ GPU_viewport_free(viewport);
+
+ /* Changin context */
+ DRW_opengl_context_disable();
+
+ /* XXX Drawing the resulting buffer to the BACK_BUFFER */
+ GPU_matrix_push();
+ GPU_matrix_push_projection();
+ wmOrtho2_region_pixelspace(ar);
+ GPU_matrix_identity_set();
+
+ glEnable(GL_DEPTH_TEST); /* Cannot write to depth buffer without testing */
+ glDepthFunc(GL_ALWAYS);
+ draw_depth_texture_to_screen(g_select_buffer.texture_depth);
+ glDepthFunc(GL_LEQUAL);
+
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw Manager State (DRW_state)
+ * \{ */
+
+void DRW_state_dfdy_factors_get(float dfdyfac[2])
+{
+ GPU_get_dfdy_factors(dfdyfac);
+}
+
+/**
+ * When false, drawing doesn't output to a pixel buffer
+ * eg: Occlusion queries, or when we have setup a context to draw in already.
+ */
+bool DRW_state_is_fbo(void)
+{
+ return ((DST.default_framebuffer != NULL) || DST.options.is_image_render);
+}
+
+/**
+ * For when engines need to know if this is drawing for selection or not.
+ */
+bool DRW_state_is_select(void)
+{
+ return DST.options.is_select;
+}
+
+bool DRW_state_is_depth(void)
+{
+ return DST.options.is_depth;
+}
+
+/**
+ * Whether we are rendering for an image
+ */
+bool DRW_state_is_image_render(void)
+{
+ return DST.options.is_image_render;
+}
+
+/**
+ * Whether we are rendering only the render engine,
+ * or if we should also render the mode engines.
+ */
+bool DRW_state_is_scene_render(void)
+{
+ BLI_assert(DST.options.is_scene_render ?
+ DST.options.is_image_render : true);
+ return DST.options.is_scene_render;
+}
+
+/**
+ * Whether we are rendering simple opengl render
+ */
+bool DRW_state_is_opengl_render(void)
+{
+ return DST.options.is_image_render && !DST.options.is_scene_render;
+}
+
+/**
+ * Should text draw in this mode?
+ */
+bool DRW_state_show_text(void)
+{
+ return (DST.options.is_select) == 0 &&
+ (DST.options.is_depth) == 0 &&
+ (DST.options.is_scene_render) == 0 &&
+ (DST.options.draw_text) == 0;
+}
+
+/**
+ * Should draw support elements
+ * Objects center, selection outline, probe data, ...
+ */
+bool DRW_state_draw_support(void)
+{
+ View3D *v3d = DST.draw_ctx.v3d;
+ return (DRW_state_is_scene_render() == false) &&
+ (v3d != NULL) &&
+ ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0);
+}
+
+/**
+ * Whether we should render the background
+ */
+bool DRW_state_draw_background(void)
+{
+ if (DRW_state_is_image_render() == false) {
+ return true;
+ }
+ return DST.options.draw_background;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Context State (DRW_context_state)
+ * \{ */
+
+const DRWContextState *DRW_context_state_get(void)
+{
+ return &DST.draw_ctx;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Init/Exit (DRW_engines)
+ * \{ */
+
+bool DRW_engine_render_support(DrawEngineType *draw_engine_type)
+{
+ return draw_engine_type->render_to_image;
+}
+
+void DRW_engine_register(DrawEngineType *draw_engine_type)
+{
+ BLI_addtail(&DRW_engines, draw_engine_type);
+}
+
+void DRW_engines_register(void)
+{
+ RE_engines_register(&DRW_engine_viewport_eevee_type);
+ RE_engines_register(&DRW_engine_viewport_workbench_type);
+
+ DRW_engine_register(&draw_engine_workbench_solid);
+ DRW_engine_register(&draw_engine_workbench_transparent);
+
+ DRW_engine_register(&draw_engine_object_type);
+ DRW_engine_register(&draw_engine_edit_armature_type);
+ DRW_engine_register(&draw_engine_edit_curve_type);
+ DRW_engine_register(&draw_engine_edit_lattice_type);
+ DRW_engine_register(&draw_engine_edit_mesh_type);
+ DRW_engine_register(&draw_engine_edit_metaball_type);
+ DRW_engine_register(&draw_engine_edit_text_type);
+ DRW_engine_register(&draw_engine_motion_path_type);
+ DRW_engine_register(&draw_engine_overlay_type);
+ DRW_engine_register(&draw_engine_paint_texture_type);
+ DRW_engine_register(&draw_engine_paint_vertex_type);
+ DRW_engine_register(&draw_engine_paint_weight_type);
+ DRW_engine_register(&draw_engine_particle_type);
+ DRW_engine_register(&draw_engine_pose_type);
+ DRW_engine_register(&draw_engine_sculpt_type);
+ DRW_engine_register(&draw_engine_gpencil_type);
+
+ /* setup callbacks */
+ {
+ /* BKE: mball.c */
+ extern void *BKE_mball_batch_cache_dirty_tag_cb;
+ extern void *BKE_mball_batch_cache_free_cb;
+ /* BKE: curve.c */
+ extern void *BKE_curve_batch_cache_dirty_tag_cb;
+ extern void *BKE_curve_batch_cache_free_cb;
+ /* BKE: mesh.c */
+ extern void *BKE_mesh_batch_cache_dirty_tag_cb;
+ extern void *BKE_mesh_batch_cache_free_cb;
+ /* BKE: lattice.c */
+ extern void *BKE_lattice_batch_cache_dirty_tag_cb;
+ extern void *BKE_lattice_batch_cache_free_cb;
+ /* BKE: particle.c */
+ extern void *BKE_particle_batch_cache_dirty_tag_cb;
+ extern void *BKE_particle_batch_cache_free_cb;
+ /* BKE: gpencil.c */
+ extern void *BKE_gpencil_batch_cache_dirty_tag_cb;
+ extern void *BKE_gpencil_batch_cache_free_cb;
+
+ BKE_mball_batch_cache_dirty_tag_cb = DRW_mball_batch_cache_dirty_tag;
+ BKE_mball_batch_cache_free_cb = DRW_mball_batch_cache_free;
+
+ BKE_curve_batch_cache_dirty_tag_cb = DRW_curve_batch_cache_dirty_tag;
+ BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free;
+
+ BKE_mesh_batch_cache_dirty_tag_cb = DRW_mesh_batch_cache_dirty_tag;
+ BKE_mesh_batch_cache_free_cb = DRW_mesh_batch_cache_free;
+
+ BKE_lattice_batch_cache_dirty_tag_cb = DRW_lattice_batch_cache_dirty_tag;
+ BKE_lattice_batch_cache_free_cb = DRW_lattice_batch_cache_free;
+
+ BKE_particle_batch_cache_dirty_tag_cb = DRW_particle_batch_cache_dirty_tag;
+ BKE_particle_batch_cache_free_cb = DRW_particle_batch_cache_free;
+
+ BKE_gpencil_batch_cache_dirty_tag_cb = DRW_gpencil_batch_cache_dirty_tag;
+ BKE_gpencil_batch_cache_free_cb = DRW_gpencil_batch_cache_free;
+ }
+}
+
+extern struct GPUVertFormat *g_pos_format; /* draw_shgroup.c */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GPUTexture *globals_ramp; /* draw_common.c */
+extern struct GPUTexture *globals_weight_ramp; /* draw_common.c */
+void DRW_engines_free(void)
+{
+ DRW_opengl_context_enable();
+
+ DRW_TEXTURE_FREE_SAFE(g_select_buffer.texture_depth);
+ GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer);
+
+ DRW_hair_free();
+ DRW_shape_cache_free();
+ DRW_stats_free();
+ DRW_globals_free();
+
+ DrawEngineType *next;
+ for (DrawEngineType *type = DRW_engines.first; type; type = next) {
+ next = type->next;
+ BLI_remlink(&R_engines, type);
+
+ if (type->engine_free) {
+ type->engine_free();
+ }
+ }
+
+ DRW_UBO_FREE_SAFE(globals_ubo);
+ DRW_UBO_FREE_SAFE(view_ubo);
+ DRW_TEXTURE_FREE_SAFE(globals_ramp);
+ DRW_TEXTURE_FREE_SAFE(globals_weight_ramp);
+ MEM_SAFE_FREE(g_pos_format);
+
+ MEM_SAFE_FREE(DST.RST.bound_texs);
+ MEM_SAFE_FREE(DST.RST.bound_tex_slots);
+ MEM_SAFE_FREE(DST.RST.bound_ubos);
+ MEM_SAFE_FREE(DST.RST.bound_ubo_slots);
+
+ DRW_opengl_context_disable();
+}
+
+/** \} */
+
+/** \name Init/Exit (DRW_opengl_ctx)
+ * \{ */
+
+void DRW_opengl_context_create(void)
+{
+ BLI_assert(DST.gl_context == NULL); /* Ensure it's called once */
+
+ DST.gl_context_mutex = BLI_ticket_mutex_alloc();
+ if (!G.background) {
+ immDeactivate();
+ }
+ /* This changes the active context. */
+ DST.gl_context = WM_opengl_context_create();
+ WM_opengl_context_activate(DST.gl_context);
+ /* Be sure to create gawain.context too. */
+ DST.gpu_context = GPU_context_create();
+ if (!G.background) {
+ immActivate();
+ }
+ /* Set default Blender OpenGL state */
+ GPU_state_init();
+ /* So we activate the window's one afterwards. */
+ wm_window_reset_drawable();
+}
+
+void DRW_opengl_context_destroy(void)
+{
+ BLI_assert(BLI_thread_is_main());
+ if (DST.gl_context != NULL) {
+ WM_opengl_context_activate(DST.gl_context);
+ GPU_context_active_set(DST.gpu_context);
+ GPU_context_discard(DST.gpu_context);
+ WM_opengl_context_dispose(DST.gl_context);
+ BLI_ticket_mutex_free(DST.gl_context_mutex);
+ }
+}
+
+void DRW_opengl_context_enable_ex(bool restore)
+{
+ if (DST.gl_context != NULL) {
+ /* IMPORTANT: We dont support immediate mode in render mode!
+ * This shall remain in effect until immediate mode supports
+ * multiple threads. */
+ BLI_ticket_mutex_lock(DST.gl_context_mutex);
+ if (BLI_thread_is_main() && restore) {
+ if (!G.background) {
+ immDeactivate();
+ }
+ }
+ WM_opengl_context_activate(DST.gl_context);
+ GPU_context_active_set(DST.gpu_context);
+ if (BLI_thread_is_main() && restore) {
+ if (!G.background) {
+ immActivate();
+ }
+ BLF_batch_reset();
+ }
+ }
+}
+
+void DRW_opengl_context_disable_ex(bool restore)
+{
+ if (DST.gl_context != NULL) {
+#ifdef __APPLE__
+ /* Need to flush before disabling draw context, otherwise it does not
+ * always finish drawing and viewport can be empty or partially drawn */
+ glFlush();
+#endif
+
+ if (BLI_thread_is_main() && restore) {
+ wm_window_reset_drawable();
+ }
+ else {
+ WM_opengl_context_release(DST.gl_context);
+ GPU_context_active_set(NULL);
+ }
+
+ BLI_ticket_mutex_unlock(DST.gl_context_mutex);
+ }
+}
+
+void DRW_opengl_context_enable(void)
+{
+ DRW_opengl_context_enable_ex(true);
+}
+
+void DRW_opengl_context_disable(void)
+{
+ DRW_opengl_context_disable_ex(true);
+}
+
+void DRW_opengl_render_context_enable(void *re_gl_context)
+{
+ /* If thread is main you should use DRW_opengl_context_enable(). */
+ BLI_assert(!BLI_thread_is_main());
+
+ /* TODO get rid of the blocking. Only here because of the static global DST. */
+ BLI_ticket_mutex_lock(DST.gl_context_mutex);
+ WM_opengl_context_activate(re_gl_context);
+}
+
+void DRW_opengl_render_context_disable(void *re_gl_context)
+{
+ glFlush();
+ WM_opengl_context_release(re_gl_context);
+ /* TODO get rid of the blocking. */
+ BLI_ticket_mutex_unlock(DST.gl_context_mutex);
+}
+
+/* Needs to be called AFTER DRW_opengl_render_context_enable() */
+void DRW_gawain_render_context_enable(void *re_gpu_context)
+{
+ /* If thread is main you should use DRW_opengl_context_enable(). */
+ BLI_assert(!BLI_thread_is_main());
+
+ GPU_context_active_set(re_gpu_context);
+ DRW_shape_cache_reset(); /* XXX fix that too. */
+}
+
+/* Needs to be called BEFORE DRW_opengl_render_context_disable() */
+void DRW_gawain_render_context_disable(void *UNUSED(re_gpu_context))
+{
+ DRW_shape_cache_reset(); /* XXX fix that too. */
+ GPU_context_active_set(NULL);
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
new file mode 100644
index 00000000000..07a8f5647a7
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager.h
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_manager.h
+ * \ingroup draw
+ */
+
+/* Private functions / structs of the draw manager */
+
+#ifndef __DRAW_MANAGER_H__
+#define __DRAW_MANAGER_H__
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BLI_linklist.h"
+#include "BLI_threads.h"
+
+#include "GPU_batch.h"
+#include "GPU_context.h"
+#include "GPU_framebuffer.h"
+#include "GPU_shader.h"
+#include "GPU_uniformbuffer.h"
+#include "GPU_viewport.h"
+
+#include "draw_instance_data.h"
+
+/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */
+#define USE_GPU_SELECT
+
+/* ------------ Profiling --------------- */
+
+#define USE_PROFILE
+
+#ifdef USE_PROFILE
+# include "PIL_time.h"
+
+# define PROFILE_TIMER_FALLOFF 0.04
+
+# define PROFILE_START(time_start) \
+ double time_start = PIL_check_seconds_timer();
+
+# define PROFILE_END_ACCUM(time_accum, time_start) { \
+ time_accum += (PIL_check_seconds_timer() - time_start) * 1e3; \
+} ((void)0)
+
+/* exp average */
+# define PROFILE_END_UPDATE(time_update, time_start) { \
+ double _time_delta = (PIL_check_seconds_timer() - time_start) * 1e3; \
+ time_update = (time_update * (1.0 - PROFILE_TIMER_FALLOFF)) + \
+ (_time_delta * PROFILE_TIMER_FALLOFF); \
+} ((void)0)
+
+#else /* USE_PROFILE */
+
+# define PROFILE_START(time_start) ((void)0)
+# define PROFILE_END_ACCUM(time_accum, time_start) ((void)0)
+# define PROFILE_END_UPDATE(time_update, time_start) ((void)0)
+
+#endif /* USE_PROFILE */
+
+/* ------------ Data Structure --------------- */
+/**
+ * Data structure containing all drawcalls organized by passes and materials.
+ * DRWPass > DRWShadingGroup > DRWCall > DRWCallState
+ * > DRWUniform
+ **/
+
+/* Used by DRWCallState.flag */
+enum {
+ DRW_CALL_CULLED = (1 << 0),
+ DRW_CALL_NEGSCALE = (1 << 1),
+ DRW_CALL_BYPASS_CULLING = (1 << 2),
+};
+
+/* Used by DRWCallState.matflag */
+enum {
+ DRW_CALL_MODELINVERSE = (1 << 0),
+ DRW_CALL_MODELVIEW = (1 << 1),
+ DRW_CALL_MODELVIEWINVERSE = (1 << 2),
+ DRW_CALL_MODELVIEWPROJECTION = (1 << 3),
+ DRW_CALL_NORMALVIEW = (1 << 4),
+ DRW_CALL_NORMALWORLD = (1 << 5),
+ DRW_CALL_ORCOTEXFAC = (1 << 6),
+ DRW_CALL_EYEVEC = (1 << 7),
+ DRW_CALL_OBJECTINFO = (1 << 8),
+};
+
+typedef struct DRWCallState {
+ DRWCallVisibilityFn *visibility_cb;
+ void *user_data;
+
+ uchar flag;
+ uchar cache_id; /* Compared with DST.state_cache_id to see if matrices are still valid. */
+ uint16_t matflag; /* Which matrices to compute. */
+ /* Culling: Using Bounding Sphere for now for faster culling.
+ * Not ideal for planes. */
+ BoundSphere bsphere;
+ /* Matrices */
+ float model[4][4];
+ float modelinverse[4][4];
+ float modelview[4][4];
+ float modelviewinverse[4][4];
+ float modelviewprojection[4][4];
+ float normalview[3][3];
+ float normalworld[3][3]; /* Not view dependent */
+ float orcotexfac[2][3]; /* Not view dependent */
+ float objectinfo[2];
+ float eyevec[3];
+} DRWCallState;
+
+typedef enum {
+ DRW_CALL_SINGLE, /* A single batch */
+ DRW_CALL_RANGE, /* Like single but only draw a range of vertices/indices. */
+ DRW_CALL_INSTANCES, /* Draw instances without any instancing attribs. */
+ DRW_CALL_GENERATE, /* Uses a callback to draw with any number of batches. */
+ DRW_CALL_PROCEDURAL, /* Generate a drawcall without any GPUBatch. */
+} DRWCallType;
+
+typedef struct DRWCall {
+ struct DRWCall *next;
+ DRWCallState *state;
+
+ union {
+ struct { /* type == DRW_CALL_SINGLE */
+ GPUBatch *geometry;
+ short ma_index;
+ } single;
+ struct { /* type == DRW_CALL_RANGE */
+ GPUBatch *geometry;
+ uint start, count;
+ } range;
+ struct { /* type == DRW_CALL_INSTANCES */
+ GPUBatch *geometry;
+ /* Count can be adjusted between redraw. If needed, we can add fixed count. */
+ uint *count;
+ } instances;
+ struct { /* type == DRW_CALL_GENERATE */
+ DRWCallGenerateFn *geometry_fn;
+ void *user_data;
+ } generate;
+ struct { /* type == DRW_CALL_PROCEDURAL */
+ uint vert_count;
+ GPUPrimType prim_type;
+ } procedural;
+ };
+
+ DRWCallType type;
+#ifdef USE_GPU_SELECT
+ int select_id;
+#endif
+} DRWCall;
+
+/* Used by DRWUniform.type */
+typedef enum {
+ DRW_UNIFORM_BOOL,
+ DRW_UNIFORM_BOOL_COPY,
+ DRW_UNIFORM_SHORT_TO_INT,
+ DRW_UNIFORM_SHORT_TO_FLOAT,
+ DRW_UNIFORM_INT,
+ DRW_UNIFORM_INT_COPY,
+ DRW_UNIFORM_FLOAT,
+ DRW_UNIFORM_FLOAT_COPY,
+ DRW_UNIFORM_TEXTURE,
+ DRW_UNIFORM_TEXTURE_PERSIST,
+ DRW_UNIFORM_TEXTURE_REF,
+ DRW_UNIFORM_BLOCK,
+ DRW_UNIFORM_BLOCK_PERSIST
+} DRWUniformType;
+
+#define MAX_UNIFORM_NAME 13
+
+struct DRWUniform {
+ DRWUniform *next; /* single-linked list */
+ union {
+ /* For reference or array/vector types. */
+ const void *pvalue;
+ /* Single values. */
+ float fvalue;
+ int ivalue;
+ };
+ int location;
+ char type; /* DRWUniformType */
+ char length; /* cannot be more than 16 */
+ char arraysize; /* cannot be more than 16 too */
+#ifndef NDEBUG
+ char name[MAX_UNIFORM_NAME];
+#endif
+};
+
+typedef enum {
+ DRW_SHG_NORMAL,
+ DRW_SHG_POINT_BATCH,
+ DRW_SHG_LINE_BATCH,
+ DRW_SHG_TRIANGLE_BATCH,
+ DRW_SHG_INSTANCE,
+ DRW_SHG_INSTANCE_EXTERNAL,
+ DRW_SHG_FEEDBACK_TRANSFORM,
+} DRWShadingGroupType;
+
+struct DRWShadingGroup {
+ DRWShadingGroup *next;
+
+ GPUShader *shader; /* Shader to bind */
+ DRWUniform *uniforms; /* Uniforms pointers */
+
+ /* Watch this! Can be nasty for debugging. */
+ union {
+ struct { /* DRW_SHG_NORMAL */
+ DRWCall *first, *last; /* Linked list of DRWCall or DRWCallDynamic depending of type */
+ } calls;
+ struct { /* DRW_SHG_FEEDBACK_TRANSFORM */
+ DRWCall *first, *last; /* Linked list of DRWCall or DRWCallDynamic depending of type */
+ struct GPUVertBuf *tfeedback_target; /* Transform Feedback target. */
+ };
+ struct { /* DRW_SHG_***_BATCH */
+ struct GPUBatch *batch_geom; /* Result of call batching */
+ struct GPUVertBuf *batch_vbo;
+ uint primitive_count;
+ };
+ struct { /* DRW_SHG_INSTANCE[_EXTERNAL] */
+ struct GPUBatch *instance_geom;
+ struct GPUVertBuf *instance_vbo;
+ uint instance_count;
+ float instance_orcofac[2][3]; /* TODO find a better place. */
+ };
+ };
+
+ DRWState state_extra; /* State changes for this batch only (or'd with the pass's state) */
+ DRWState state_extra_disable; /* State changes for this batch only (and'd with the pass's state) */
+ uint stencil_mask; /* Stencil mask to use for stencil test / write operations */
+ DRWShadingGroupType type;
+
+ /* Builtin matrices locations */
+ int model;
+ int modelinverse;
+ int modelview;
+ int modelviewinverse;
+ int modelviewprojection;
+ int normalview;
+ int normalworld;
+ int orcotexfac;
+ int eye;
+ int callid;
+ int objectinfo;
+ uint16_t matflag; /* Matrices needed, same as DRWCall.flag */
+
+ DRWPass *pass_parent; /* backlink to pass we're in */
+#ifndef NDEBUG
+ char attribs_count;
+#endif
+#ifdef USE_GPU_SELECT
+ GPUVertBuf *inst_selectid;
+ int override_selectid; /* Override for single object instances. */
+#endif
+};
+
+#define MAX_PASS_NAME 32
+
+struct DRWPass {
+ /* Linked list */
+ struct {
+ DRWShadingGroup *first;
+ DRWShadingGroup *last;
+ } shgroups;
+
+ DRWState state;
+ char name[MAX_PASS_NAME];
+};
+
+typedef struct ViewUboStorage {
+ DRWMatrixState matstate;
+ float viewcamtexcofac[4];
+ float clipplanes[2][4];
+} ViewUboStorage;
+
+/* ------------- DRAW DEBUG ------------ */
+
+typedef struct DRWDebugLine {
+ struct DRWDebugLine *next; /* linked list */
+ float pos[2][3];
+ float color[4];
+} DRWDebugLine;
+
+typedef struct DRWDebugSphere {
+ struct DRWDebugSphere *next; /* linked list */
+ float mat[4][4];
+ float color[4];
+} DRWDebugSphere;
+
+/* ------------- DRAW MANAGER ------------ */
+
+#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */
+#define STENCIL_UNDEFINED 256
+typedef struct DRWManager {
+ /* TODO clean up this struct a bit */
+ /* Cache generation */
+ ViewportMemoryPool *vmempool;
+ DRWInstanceDataList *idatalist;
+ DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
+ /* State of the object being evaluated if already allocated. */
+ DRWCallState *ob_state;
+ uchar state_cache_id; /* Could be larger but 254 view changes is already a lot! */
+ struct DupliObject *dupli_source;
+ struct Object *dupli_parent;
+
+ /* Rendering state */
+ GPUShader *shader;
+
+ /* Managed by `DRW_state_set`, `DRW_state_reset` */
+ DRWState state;
+ DRWState state_lock;
+ uint stencil_mask;
+
+ /* Per viewport */
+ GPUViewport *viewport;
+ struct GPUFrameBuffer *default_framebuffer;
+ float size[2];
+ float inv_size[2];
+ float screenvecs[2][3];
+ float pixsize;
+
+ GLenum backface, frontface;
+
+ struct {
+ uint is_select : 1;
+ uint is_depth : 1;
+ uint is_image_render : 1;
+ uint is_scene_render : 1;
+ uint draw_background : 1;
+ uint draw_text : 1;
+ } options;
+
+ /* Current rendering context */
+ DRWContextState draw_ctx;
+
+ /* Convenience pointer to text_store owned by the viewport */
+ struct DRWTextStore **text_store_p;
+
+ ListBase enabled_engines; /* RenderEngineType */
+
+ bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */
+
+ /* View dependent uniforms. */
+ DRWMatrixState original_mat; /* Original rv3d matrices. */
+ int override_mat; /* Bitflag of which matrices are overridden. */
+ int num_clip_planes; /* Number of active clipplanes. */
+ bool dirty_mat;
+
+ /* keep in sync with viewBlock */
+ ViewUboStorage view_data;
+
+ struct {
+ float frustum_planes[6][4];
+ BoundBox frustum_corners;
+ BoundSphere frustum_bsphere;
+ bool updated;
+ } clipping;
+
+#ifdef USE_GPU_SELECT
+ uint select_id;
+#endif
+
+ /* ---------- Nothing after this point is cleared after use ----------- */
+
+ /* gl_context serves as the offset for clearing only
+ * the top portion of the struct so DO NOT MOVE IT! */
+ void *gl_context; /* Unique ghost context used by the draw manager. */
+ GPUContext *gpu_context;
+ TicketMutex *gl_context_mutex; /* Mutex to lock the drw manager and avoid concurrent context usage. */
+
+ /** GPU Resource State: Memory storage between drawing. */
+ struct {
+ GPUTexture **bound_texs;
+ char *bound_tex_slots;
+ int bind_tex_inc;
+ GPUUniformBuffer **bound_ubos;
+ char *bound_ubo_slots;
+ int bind_ubo_inc;
+ } RST;
+
+ struct {
+ /* TODO(fclem) optimize: use chunks. */
+ DRWDebugLine *lines;
+ DRWDebugSphere *spheres;
+ } debug;
+} DRWManager;
+
+extern DRWManager DST; /* TODO : get rid of this and allow multithreaded rendering */
+
+/* --------------- FUNCTIONS ------------- */
+
+void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags);
+void drw_texture_get_format(
+ GPUTextureFormat format, bool is_framebuffer,
+ GPUTextureFormat *r_data_type, int *r_channels, bool *r_is_depth);
+
+void *drw_viewport_engine_data_ensure(void *engine_type);
+
+void drw_state_set(DRWState state);
+
+void drw_debug_draw(void);
+void drw_debug_init(void);
+
+#endif /* __DRAW_MANAGER_H__ */
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
new file mode 100644
index 00000000000..e9d874bd1ee
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -0,0 +1,1185 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_manager_data.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+
+#include "BLI_hash.h"
+#include "BLI_link_utils.h"
+#include "BLI_mempool.h"
+
+#include "intern/gpu_codegen.h"
+
+struct GPUVertFormat *g_pos_format = NULL;
+
+extern struct GPUUniformBuffer *view_ubo; /* draw_manager_exec.c */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Uniform Buffer Object (DRW_uniformbuffer)
+ * \{ */
+
+GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data)
+{
+ return GPU_uniformbuffer_create(size, data, NULL);
+}
+
+void DRW_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
+{
+ GPU_uniformbuffer_update(ubo, data);
+}
+
+void DRW_uniformbuffer_free(GPUUniformBuffer *ubo)
+{
+ GPU_uniformbuffer_free(ubo);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Uniforms (DRW_shgroup_uniform)
+ * \{ */
+
+static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, int loc,
+ DRWUniformType type, const void *value, int length, int arraysize)
+{
+ DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms);
+ uni->location = loc;
+ uni->type = type;
+ uni->length = length;
+ uni->arraysize = arraysize;
+
+ switch (type) {
+ case DRW_UNIFORM_INT_COPY:
+ uni->ivalue = *((int *)value);
+ break;
+ case DRW_UNIFORM_BOOL_COPY:
+ uni->ivalue = (int)*((bool *)value);
+ break;
+ case DRW_UNIFORM_FLOAT_COPY:
+ uni->fvalue = *((float *)value);
+ break;
+ default:
+ uni->pvalue = value;
+ break;
+ }
+
+ BLI_LINKS_PREPEND(shgroup->uniforms, uni);
+}
+
+static void drw_shgroup_builtin_uniform(
+ DRWShadingGroup *shgroup, int builtin, const void *value, int length, int arraysize)
+{
+ int loc = GPU_shader_get_builtin_uniform(shgroup->shader, builtin);
+
+ if (loc != -1) {
+ drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_FLOAT, value, length, arraysize);
+ }
+}
+
+static void drw_shgroup_uniform(DRWShadingGroup *shgroup, const char *name,
+ DRWUniformType type, const void *value, int length, int arraysize)
+{
+ int location;
+ if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) {
+ location = GPU_shader_get_uniform_block(shgroup->shader, name);
+ }
+ else {
+ location = GPU_shader_get_uniform(shgroup->shader, name);
+ }
+
+ if (location == -1) {
+ if (G.debug & G_DEBUG)
+ fprintf(stderr, "Pass : %s, Uniform '%s' not found!\n", shgroup->pass_parent->name, name);
+ /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */
+ // BLI_assert(0);
+ return;
+ }
+
+ BLI_assert(arraysize > 0 && arraysize <= 16);
+ BLI_assert(length >= 0 && length <= 16);
+
+ drw_shgroup_uniform_create_ex(shgroup, location, type, value, length, arraysize);
+
+#ifndef NDEBUG
+ /* Save uniform name to easily identify it when debugging. */
+ BLI_strncpy(shgroup->uniforms->name, name, MAX_UNIFORM_NAME);
+#endif
+}
+
+void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
+{
+ BLI_assert(tex != NULL);
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1);
+}
+
+/* Same as DRW_shgroup_uniform_texture but is guaranteed to be bound if shader does not change between shgrp. */
+void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
+{
+ BLI_assert(tex != NULL);
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1);
+}
+
+void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
+{
+ BLI_assert(ubo != NULL);
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1);
+}
+
+/* Same as DRW_shgroup_uniform_block but is guaranteed to be bound if shader does not change between shgrp. */
+void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
+{
+ BLI_assert(ubo != NULL);
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1);
+}
+
+void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_REF, tex, 0, 1);
+}
+
+void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize);
+}
+
+void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize);
+}
+
+void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize);
+}
+
+void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
+}
+
+void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize);
+}
+
+void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize);
+}
+
+void DRW_shgroup_uniform_ivec4(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 4, arraysize);
+}
+
+void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float (*value)[3])
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, (float *)value, 9, 1);
+}
+
+void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4])
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, (float *)value, 16, 1);
+}
+
+/* Stores the int instead of a pointer. */
+void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
+}
+
+void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BOOL_COPY, &value, 1, 1);
+}
+
+void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value)
+{
+ drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, &value, 1, 1);
+}
+
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw Call (DRW_calls)
+ * \{ */
+
+static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
+{
+ ID *ob_data = (ob) ? ob->data : NULL;
+ float *texcoloc = NULL;
+ float *texcosize = NULL;
+ if (ob_data != NULL) {
+ switch (GS(ob_data->name)) {
+ case ID_ME:
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ break;
+ case ID_CU:
+ {
+ Curve *cu = (Curve *)ob_data;
+ if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(cu);
+ }
+ texcoloc = cu->loc;
+ texcosize = cu->size;
+ break;
+ }
+ case ID_MB:
+ {
+ MetaBall *mb = (MetaBall *)ob_data;
+ texcoloc = mb->loc;
+ texcosize = mb->size;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if ((texcoloc != NULL) && (texcosize != NULL)) {
+ mul_v3_v3fl(r_orcofacs[1], texcosize, 2.0f);
+ invert_v3(r_orcofacs[1]);
+ sub_v3_v3v3(r_orcofacs[0], texcoloc, texcosize);
+ negate_v3(r_orcofacs[0]);
+ mul_v3_v3(r_orcofacs[0], r_orcofacs[1]); /* result in a nice MADD in the shader */
+ }
+ else {
+ copy_v3_fl(r_orcofacs[0], 0.0f);
+ copy_v3_fl(r_orcofacs[1], 1.0f);
+ }
+}
+
+static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+{
+ DRWCallState *state = BLI_mempool_alloc(DST.vmempool->states);
+ state->flag = 0;
+ state->cache_id = 0;
+ state->visibility_cb = NULL;
+ state->matflag = shgroup->matflag;
+
+ /* Matrices */
+ if (obmat != NULL) {
+ copy_m4_m4(state->model, obmat);
+
+ if (is_negative_m4(state->model)) {
+ state->flag |= DRW_CALL_NEGSCALE;
+ }
+ }
+ else {
+ unit_m4(state->model);
+ }
+
+ if (ob != NULL) {
+ float corner[3];
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ /* Get BoundSphere center and radius from the BoundBox. */
+ mid_v3_v3v3(state->bsphere.center, bbox->vec[0], bbox->vec[6]);
+ mul_v3_m4v3(corner, obmat, bbox->vec[0]);
+ mul_m4_v3(obmat, state->bsphere.center);
+ state->bsphere.radius = len_v3v3(state->bsphere.center, corner);
+ }
+ else {
+ /* Bypass test. */
+ state->bsphere.radius = -1.0f;
+ }
+
+ /* Orco factors: We compute this at creation to not have to save the *ob_data */
+ if ((state->matflag & DRW_CALL_ORCOTEXFAC) != 0) {
+ drw_call_calc_orco(ob, state->orcotexfac);
+ state->matflag &= ~DRW_CALL_ORCOTEXFAC;
+ }
+
+ if ((state->matflag & DRW_CALL_OBJECTINFO) != 0) {
+ state->objectinfo[0] = ob ? ob->index : 0;
+ unsigned int random;
+#if 0 /* TODO(fclem) handle dupli objects */
+ if (GMS.dob) {
+ random = GMS.dob->random_id;
+ }
+ else
+#endif
+ {
+ random = BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
+ }
+ state->objectinfo[1] = random * (1.0f / (float)0xFFFFFFFF);
+ state->matflag &= ~DRW_CALL_OBJECTINFO;
+ }
+
+ return state;
+}
+
+static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
+{
+ if (DST.ob_state == NULL) {
+ DST.ob_state = drw_call_state_create(shgroup, obmat, ob);
+ }
+ else {
+ /* If the DRWCallState is reused, add necessary matrices. */
+ DST.ob_state->matflag |= shgroup->matflag;
+ }
+
+ return DST.ob_state;
+}
+
+void DRW_shgroup_call_add(DRWShadingGroup *shgroup, GPUBatch *geom, float (*obmat)[4])
+{
+ BLI_assert(geom != NULL);
+ BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ call->type = DRW_CALL_SINGLE;
+ call->single.geometry = geom;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+void DRW_shgroup_call_range_add(DRWShadingGroup *shgroup, GPUBatch *geom, float (*obmat)[4], uint v_sta, uint v_count)
+{
+ BLI_assert(geom != NULL);
+ BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
+ BLI_assert(v_count);
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ call->type = DRW_CALL_RANGE;
+ call->range.geometry = geom;
+ call->range.start = v_sta;
+ call->range.count = v_count;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+static void drw_shgroup_call_procedural_add_ex(
+ DRWShadingGroup *shgroup, GPUPrimType prim_type, uint vert_count, float (*obmat)[4], Object *ob)
+{
+ BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ if (ob) {
+ call->state = drw_call_state_object(shgroup, ob->obmat, ob);
+ }
+ else {
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ }
+ call->type = DRW_CALL_PROCEDURAL;
+ call->procedural.prim_type = prim_type;
+ call->procedural.vert_count = vert_count;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, uint point_len, float (*obmat)[4])
+{
+ drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_POINTS, point_len, obmat, NULL);
+}
+
+void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, uint line_count, float (*obmat)[4])
+{
+ drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_LINES, line_count * 2, obmat, NULL);
+}
+
+void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, uint tria_count, float (*obmat)[4])
+{
+ drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_TRIS, tria_count * 3, obmat, NULL);
+}
+
+/* TODO (fclem): this is a sign that the api is starting to be limiting.
+ * Maybe add special function that general purpose for special cases. */
+void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, uint tria_count, Object *ob)
+{
+ drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_TRIS, tria_count * 3, NULL, ob);
+}
+
+/* These calls can be culled and are optimized for redraw */
+void DRW_shgroup_call_object_add_ex(DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, Material *ma, bool bypass_culling)
+{
+ BLI_assert(geom != NULL);
+ BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_object(shgroup, ob->obmat, ob);
+ call->type = DRW_CALL_SINGLE;
+ call->single.geometry = geom;
+ call->single.ma_index = ma ? ma->index : 0;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ /* NOTE this will disable culling for the whole object. */
+ call->state->flag |= (bypass_culling) ? DRW_CALL_BYPASS_CULLING : 0;
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+void DRW_shgroup_call_object_add_with_callback(
+ DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, Material *ma,
+ DRWCallVisibilityFn *callback, void *user_data)
+{
+ BLI_assert(geom != NULL);
+ BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_object(shgroup, ob->obmat, ob);
+ call->state->visibility_cb = callback;
+ call->state->user_data = user_data;
+ call->type = DRW_CALL_SINGLE;
+ call->single.geometry = geom;
+ call->single.ma_index = ma ? ma->index : 0;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup, GPUBatch *geom, float (*obmat)[4], uint *count)
+{
+ BLI_assert(geom != NULL);
+ BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ call->type = DRW_CALL_INSTANCES;
+ call->instances.geometry = geom;
+ call->instances.count = count;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+/* These calls can be culled and are optimized for redraw */
+void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, uint *count)
+{
+ BLI_assert(geom != NULL);
+ BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_object(shgroup, ob->obmat, ob);
+ call->type = DRW_CALL_INSTANCES;
+ call->instances.geometry = geom;
+ call->instances.count = count;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+void DRW_shgroup_call_generate_add(
+ DRWShadingGroup *shgroup,
+ DRWCallGenerateFn *geometry_fn, void *user_data,
+ float (*obmat)[4])
+{
+ BLI_assert(geometry_fn != NULL);
+ BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
+
+ DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ call->type = DRW_CALL_GENERATE;
+ call->generate.geometry_fn = geometry_fn;
+ call->generate.user_data = user_data;
+#ifdef USE_GPU_SELECT
+ call->select_id = DST.select_id;
+#endif
+
+ BLI_LINKS_APPEND(&shgroup->calls, call);
+}
+
+static void sculpt_draw_cb(
+ DRWShadingGroup *shgroup,
+ void (*draw_fn)(DRWShadingGroup *shgroup, GPUBatch *geom),
+ void *user_data)
+{
+ Object *ob = user_data;
+
+ /* XXX should be ensured before but sometime it's not... go figure (see T57040). */
+ PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(DST.draw_ctx.depsgraph, ob);
+
+ const DRWContextState *drwctx = DRW_context_state_get();
+ int fast_mode = 0;
+
+ if (drwctx->evil_C != NULL) {
+ Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C);
+ if (p && (p->flags & PAINT_FAST_NAVIGATE)) {
+ fast_mode = drwctx->rv3d->rflag & RV3D_NAVIGATING;
+ }
+ }
+
+ if (pbvh) {
+ BKE_pbvh_draw_cb(
+ pbvh, NULL, NULL, fast_mode, false,
+ (void (*)(void *, GPUBatch *))draw_fn, shgroup);
+ }
+}
+
+void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4])
+{
+ DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat);
+}
+
+void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], uint attr_len)
+{
+#ifdef USE_GPU_SELECT
+ if (G.f & G_PICKSEL) {
+ if (shgroup->instance_count == shgroup->inst_selectid->vertex_len) {
+ GPU_vertbuf_data_resize(shgroup->inst_selectid, shgroup->instance_count + 32);
+ }
+ GPU_vertbuf_attr_set(shgroup->inst_selectid, 0, shgroup->instance_count, &DST.select_id);
+ }
+#endif
+
+ BLI_assert(attr_len == shgroup->attribs_count);
+ UNUSED_VARS_NDEBUG(attr_len);
+
+ for (int i = 0; i < attr_len; ++i) {
+ if (shgroup->instance_count == shgroup->instance_vbo->vertex_len) {
+ GPU_vertbuf_data_resize(shgroup->instance_vbo, shgroup->instance_count + 32);
+ }
+ GPU_vertbuf_attr_set(shgroup->instance_vbo, i, shgroup->instance_count, attr[i]);
+ }
+
+ shgroup->instance_count += 1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Shading Groups (DRW_shgroup)
+ * \{ */
+
+static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
+{
+ shgroup->instance_geom = NULL;
+ shgroup->instance_vbo = NULL;
+ shgroup->instance_count = 0;
+ shgroup->uniforms = NULL;
+#ifdef USE_GPU_SELECT
+ shgroup->inst_selectid = NULL;
+ shgroup->override_selectid = -1;
+#endif
+#ifndef NDEBUG
+ shgroup->attribs_count = 0;
+#endif
+
+ int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
+
+ if (view_ubo_location != -1) {
+ drw_shgroup_uniform_create_ex(shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, view_ubo, 0, 1);
+ }
+ else {
+ /* Only here to support builtin shaders. This should not be used by engines. */
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW, DST.view_data.matstate.mat[DRW_MAT_VIEW], 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW_INV, DST.view_data.matstate.mat[DRW_MAT_VIEWINV], 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION, DST.view_data.matstate.mat[DRW_MAT_PERS], 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_PERSINV], 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION, DST.view_data.matstate.mat[DRW_MAT_WIN], 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_WININV], 16, 1);
+ drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_CAMERATEXCO, DST.view_data.viewcamtexcofac, 3, 2);
+ }
+
+ shgroup->model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
+ shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
+ shgroup->modelview = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW);
+ shgroup->modelviewinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV);
+ shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
+ shgroup->normalview = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL);
+ shgroup->normalworld = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_WORLDNORMAL);
+ shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO);
+ shgroup->objectinfo = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_INFO);
+ shgroup->eye = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_EYE);
+ shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID);
+
+ shgroup->matflag = 0;
+ if (shgroup->modelinverse > -1)
+ shgroup->matflag |= DRW_CALL_MODELINVERSE;
+ if (shgroup->modelview > -1)
+ shgroup->matflag |= DRW_CALL_MODELVIEW;
+ if (shgroup->modelviewinverse > -1)
+ shgroup->matflag |= DRW_CALL_MODELVIEWINVERSE;
+ if (shgroup->modelviewprojection > -1)
+ shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION;
+ if (shgroup->normalview > -1)
+ shgroup->matflag |= DRW_CALL_NORMALVIEW;
+ if (shgroup->normalworld > -1)
+ shgroup->matflag |= DRW_CALL_NORMALWORLD;
+ if (shgroup->orcotexfac > -1)
+ shgroup->matflag |= DRW_CALL_ORCOTEXFAC;
+ if (shgroup->objectinfo > -1)
+ shgroup->matflag |= DRW_CALL_OBJECTINFO;
+ if (shgroup->eye > -1)
+ shgroup->matflag |= DRW_CALL_EYEVEC;
+}
+
+static void drw_shgroup_instance_init(
+ DRWShadingGroup *shgroup, GPUShader *shader, GPUBatch *batch, GPUVertFormat *format)
+{
+ BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
+ BLI_assert(batch != NULL);
+ BLI_assert(format != NULL);
+
+ drw_shgroup_init(shgroup, shader);
+
+ shgroup->instance_geom = batch;
+#ifndef NDEBUG
+ shgroup->attribs_count = format->attr_len;
+#endif
+
+ DRW_instancing_buffer_request(DST.idatalist, format, batch, shgroup,
+ &shgroup->instance_geom, &shgroup->instance_vbo);
+
+#ifdef USE_GPU_SELECT
+ if (G.f & G_PICKSEL) {
+ /* Not actually used for rendering but alloced in one chunk.
+ * Plus we don't have to care about ownership. */
+ static GPUVertFormat inst_select_format = {0};
+ if (inst_select_format.attr_len == 0) {
+ GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ GPUBatch *batch_dummy; /* Not used */
+ DRW_batching_buffer_request(DST.idatalist, &inst_select_format,
+ GPU_PRIM_POINTS, shgroup,
+ &batch_dummy, &shgroup->inst_selectid);
+ }
+#endif
+}
+
+static void drw_shgroup_batching_init(
+ DRWShadingGroup *shgroup, GPUShader *shader, GPUVertFormat *format)
+{
+ drw_shgroup_init(shgroup, shader);
+
+#ifndef NDEBUG
+ shgroup->attribs_count = (format != NULL) ? format->attr_len : 0;
+#endif
+ BLI_assert(format != NULL);
+
+ GPUPrimType type;
+ switch (shgroup->type) {
+ case DRW_SHG_POINT_BATCH: type = GPU_PRIM_POINTS; break;
+ case DRW_SHG_LINE_BATCH: type = GPU_PRIM_LINES; break;
+ case DRW_SHG_TRIANGLE_BATCH: type = GPU_PRIM_TRIS; break;
+ default: type = GPU_PRIM_NONE; BLI_assert(0); break;
+ }
+
+ DRW_batching_buffer_request(DST.idatalist, format, type, shgroup,
+ &shgroup->batch_geom, &shgroup->batch_vbo);
+
+#ifdef USE_GPU_SELECT
+ if (G.f & G_PICKSEL) {
+ /* Not actually used for rendering but alloced in one chunk. */
+ static GPUVertFormat inst_select_format = {0};
+ if (inst_select_format.attr_len == 0) {
+ GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ GPUBatch *batch; /* Not used */
+ DRW_batching_buffer_request(DST.idatalist, &inst_select_format,
+ GPU_PRIM_POINTS, shgroup,
+ &batch, &shgroup->inst_selectid);
+ }
+#endif
+}
+
+static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
+{
+ DRWShadingGroup *shgroup = BLI_mempool_alloc(DST.vmempool->shgroups);
+
+ BLI_LINKS_APPEND(&pass->shgroups, shgroup);
+
+ shgroup->type = DRW_SHG_NORMAL;
+ shgroup->shader = shader;
+ shgroup->state_extra = 0;
+ shgroup->state_extra_disable = ~0x0;
+ shgroup->stencil_mask = 0;
+ shgroup->calls.first = NULL;
+ shgroup->calls.last = NULL;
+#if 0 /* All the same in the union! */
+ shgroup->batch_geom = NULL;
+ shgroup->batch_vbo = NULL;
+
+ shgroup->instance_geom = NULL;
+ shgroup->instance_vbo = NULL;
+#endif
+ shgroup->pass_parent = pass;
+
+ return shgroup;
+}
+
+static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass *pass)
+{
+ if (!gpupass) {
+ /* Shader compilation error */
+ return NULL;
+ }
+
+ GPUShader *sh = GPU_pass_shader_get(gpupass);
+
+ if (!sh) {
+ /* Shader not yet compiled */
+ return NULL;
+ }
+
+ DRWShadingGroup *grp = drw_shgroup_create_ex(sh, pass);
+ return grp;
+}
+
+static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, struct GPUMaterial *material)
+{
+ ListBase *inputs = GPU_material_get_inputs(material);
+
+ /* Converting dynamic GPUInput to DRWUniform */
+ for (GPUInput *input = inputs->first; input; input = input->next) {
+ /* Textures */
+ if (input->source == GPU_SOURCE_TEX) {
+ GPUTexture *tex = NULL;
+
+ if (input->ima) {
+ double time = 0.0; /* TODO make time variable */
+ tex = GPU_texture_from_blender(input->ima, input->iuser, GL_TEXTURE_2D, input->image_isdata, time);
+ }
+ else {
+ /* Color Ramps */
+ tex = *input->coba;
+ }
+
+ if (input->bindtex) {
+ drw_shgroup_uniform_create_ex(grp, input->shaderloc, DRW_UNIFORM_TEXTURE, tex, 0, 1);
+ }
+ }
+ }
+
+ GPUUniformBuffer *ubo = GPU_material_uniform_buffer_get(material);
+ if (ubo != NULL) {
+ DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo);
+ }
+
+ return grp;
+}
+
+GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttribFormat attribs[], int arraysize)
+{
+ GPUVertFormat *format = MEM_callocN(sizeof(GPUVertFormat), "GPUVertFormat");
+
+ for (int i = 0; i < arraysize; ++i) {
+ GPU_vertformat_attr_add(format, attribs[i].name,
+ (attribs[i].type == DRW_ATTRIB_INT) ? GPU_COMP_I32 : GPU_COMP_F32,
+ attribs[i].components,
+ (attribs[i].type == DRW_ATTRIB_INT) ? GPU_FETCH_INT : GPU_FETCH_FLOAT);
+ }
+ return format;
+}
+
+DRWShadingGroup *DRW_shgroup_material_create(
+ struct GPUMaterial *material, DRWPass *pass)
+{
+ GPUPass *gpupass = GPU_material_get_pass(material);
+ DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
+
+ if (shgroup) {
+ drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass));
+ drw_shgroup_material_inputs(shgroup, material);
+ }
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_material_instance_create(
+ struct GPUMaterial *material, DRWPass *pass, GPUBatch *geom, Object *ob, GPUVertFormat *format)
+{
+ GPUPass *gpupass = GPU_material_get_pass(material);
+ DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
+
+ if (shgroup) {
+ shgroup->type = DRW_SHG_INSTANCE;
+ shgroup->instance_geom = geom;
+ drw_call_calc_orco(ob, shgroup->instance_orcofac);
+ drw_shgroup_instance_init(shgroup, GPU_pass_shader_get(gpupass), geom, format);
+ drw_shgroup_material_inputs(shgroup, material);
+ }
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(
+ struct GPUMaterial *material, DRWPass *pass, int tri_count)
+{
+#ifdef USE_GPU_SELECT
+ BLI_assert((G.f & G_PICKSEL) == 0);
+#endif
+ GPUPass *gpupass = GPU_material_get_pass(material);
+ DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
+
+ if (shgroup) {
+ /* Calling drw_shgroup_init will cause it to call GPU_draw_primitive(). */
+ drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass));
+ shgroup->type = DRW_SHG_TRIANGLE_BATCH;
+ shgroup->instance_count = tri_count * 3;
+ drw_shgroup_material_inputs(shgroup, material);
+ }
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ drw_shgroup_init(shgroup, shader);
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_instance_create(
+ struct GPUShader *shader, DRWPass *pass, GPUBatch *geom, GPUVertFormat *format)
+{
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ shgroup->type = DRW_SHG_INSTANCE;
+ shgroup->instance_geom = geom;
+ drw_call_calc_orco(NULL, shgroup->instance_orcofac);
+ drw_shgroup_instance_init(shgroup, shader, geom, format);
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}});
+
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ shgroup->type = DRW_SHG_POINT_BATCH;
+
+ drw_shgroup_batching_init(shgroup, shader, g_pos_format);
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_line_batch_create_with_format(
+ struct GPUShader *shader, DRWPass *pass, GPUVertFormat *format)
+{
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ shgroup->type = DRW_SHG_LINE_BATCH;
+
+ drw_shgroup_batching_init(shgroup, shader, format);
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass)
+{
+ DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}});
+
+ return DRW_shgroup_line_batch_create_with_format(shader, pass, g_pos_format);
+}
+
+/* Very special batch. Use this if you position
+ * your vertices with the vertex shader
+ * and dont need any VBO attrib */
+DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int tri_count)
+{
+#ifdef USE_GPU_SELECT
+ BLI_assert((G.f & G_PICKSEL) == 0);
+#endif
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+
+ /* Calling drw_shgroup_init will cause it to call GPU_draw_primitive(). */
+ drw_shgroup_init(shgroup, shader);
+
+ shgroup->type = DRW_SHG_TRIANGLE_BATCH;
+ shgroup->instance_count = tri_count * 3;
+
+ return shgroup;
+}
+
+DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, GPUVertBuf *tf_target)
+{
+ BLI_assert(tf_target != NULL);
+ DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
+ shgroup->type = DRW_SHG_FEEDBACK_TRANSFORM;
+
+ drw_shgroup_init(shgroup, shader);
+
+ shgroup->tfeedback_target = tf_target;
+
+ return shgroup;
+}
+
+/* Specify an external batch instead of adding each attrib one by one. */
+void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct GPUBatch *batch)
+{
+ BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
+ BLI_assert(shgroup->instance_count == 0);
+ /* You cannot use external instancing batch without a dummy format. */
+ BLI_assert(shgroup->attribs_count != 0);
+
+ shgroup->type = DRW_SHG_INSTANCE_EXTERNAL;
+ drw_call_calc_orco(NULL, shgroup->instance_orcofac);
+ /* PERF : This destroys the vaos cache so better check if it's necessary. */
+ /* Note: This WILL break if batch->verts[0] is destroyed and reallocated
+ * at the same address. Bindings/VAOs would remain obsolete. */
+ //if (shgroup->instancing_geom->inst != batch->verts[0])
+ GPU_batch_instbuf_set(shgroup->instance_geom, batch->verts[0], false);
+
+#ifdef USE_GPU_SELECT
+ shgroup->override_selectid = DST.select_id;
+#endif
+}
+
+uint DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup)
+{
+ return shgroup->instance_count;
+}
+
+/**
+ * State is added to #Pass.state while drawing.
+ * Use to temporarily enable draw options.
+ */
+void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
+{
+ shgroup->state_extra |= state;
+}
+
+void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
+{
+ shgroup->state_extra_disable &= ~state;
+}
+
+void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
+{
+ BLI_assert(mask <= 255);
+ shgroup->stencil_mask = mask;
+}
+
+bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
+{
+ switch (shgroup->type) {
+ case DRW_SHG_NORMAL:
+ case DRW_SHG_FEEDBACK_TRANSFORM:
+ return shgroup->calls.first == NULL;
+ case DRW_SHG_POINT_BATCH:
+ case DRW_SHG_LINE_BATCH:
+ case DRW_SHG_TRIANGLE_BATCH:
+ case DRW_SHG_INSTANCE:
+ case DRW_SHG_INSTANCE_EXTERNAL:
+ return shgroup->instance_count == 0;
+ }
+ BLI_assert(!"Shading Group type not supported");
+ return true;
+}
+
+DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup)
+{
+ /* Remove this assertion if needed but implement the other cases first! */
+ BLI_assert(shgroup->type == DRW_SHG_NORMAL);
+
+ DRWShadingGroup *shgroup_new = BLI_mempool_alloc(DST.vmempool->shgroups);
+
+ *shgroup_new = *shgroup;
+ shgroup_new->uniforms = NULL; /* Not sure about that.. Should we copy them instead? */
+ shgroup_new->calls.first = NULL;
+ shgroup_new->calls.last = NULL;
+
+ BLI_LINKS_INSERT_AFTER(&shgroup->pass_parent->shgroups, shgroup, shgroup_new);
+
+ return shgroup_new;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Passes (DRW_pass)
+ * \{ */
+
+DRWPass *DRW_pass_create(const char *name, DRWState state)
+{
+ DRWPass *pass = BLI_mempool_alloc(DST.vmempool->passes);
+ pass->state = state;
+ if (((G.debug_value > 20) && (G.debug_value < 30)) ||
+ (G.debug & G_DEBUG))
+ {
+ BLI_strncpy(pass->name, name, MAX_PASS_NAME);
+ }
+
+ pass->shgroups.first = NULL;
+ pass->shgroups.last = NULL;
+
+ return pass;
+}
+
+bool DRW_pass_is_empty(DRWPass *pass)
+{
+ for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) {
+ if (!DRW_shgroup_is_empty(shgroup)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void DRW_pass_state_set(DRWPass *pass, DRWState state)
+{
+ pass->state = state;
+}
+
+void DRW_pass_state_add(DRWPass *pass, DRWState state)
+{
+ pass->state |= state;
+}
+
+void DRW_pass_state_remove(DRWPass *pass, DRWState state)
+{
+ pass->state &= ~state;
+}
+
+void DRW_pass_free(DRWPass *pass)
+{
+ pass->shgroups.first = NULL;
+ pass->shgroups.last = NULL;
+}
+
+void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData)
+{
+ for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) {
+ callback(userData, shgroup);
+ }
+}
+
+typedef struct ZSortData {
+ float *axis;
+ float *origin;
+} ZSortData;
+
+static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
+{
+ const ZSortData *zsortdata = (ZSortData *)thunk;
+ const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a;
+ const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b;
+
+ const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first;
+ const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first;
+
+ if (call_a == NULL) return -1;
+ if (call_b == NULL) return -1;
+
+ float tmp[3];
+ sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]);
+ const float a_sq = dot_v3v3(zsortdata->axis, tmp);
+ sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]);
+ const float b_sq = dot_v3v3(zsortdata->axis, tmp);
+
+ if (a_sq < b_sq) return 1;
+ else if (a_sq > b_sq) return -1;
+ else {
+ /* If there is a depth prepass put it before */
+ if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
+ return -1;
+ }
+ else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
+ return 1;
+ }
+ else return 0;
+ }
+}
+
+/* ------------------ Shading group sorting --------------------- */
+
+#define SORT_IMPL_LINKTYPE DRWShadingGroup
+
+#define SORT_IMPL_USE_THUNK
+#define SORT_IMPL_FUNC shgroup_sort_fn_r
+#include "../../blenlib/intern/list_sort_impl.h"
+#undef SORT_IMPL_FUNC
+#undef SORT_IMPL_USE_THUNK
+
+#undef SORT_IMPL_LINKTYPE
+
+/**
+ * Sort Shading groups by decreasing Z of their first draw call.
+ * This is useful for order dependent effect such as transparency.
+ **/
+void DRW_pass_sort_shgroup_z(DRWPass *pass)
+{
+ float (*viewinv)[4];
+ viewinv = DST.view_data.matstate.mat[DRW_MAT_VIEWINV];
+
+ ZSortData zsortdata = {viewinv[2], viewinv[3]};
+
+ if (pass->shgroups.first && pass->shgroups.first->next) {
+ pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata);
+
+ /* Find the next last */
+ DRWShadingGroup *last = pass->shgroups.first;
+ while ((last = last->next)) {
+ /* Do nothing */
+ }
+ pass->shgroups.last = last;
+ }
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
new file mode 100644
index 00000000000..2d56c7e0cfe
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -0,0 +1,1332 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_manager_exec.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+#include "BLI_mempool.h"
+
+#include "BIF_glutil.h"
+
+#include "BKE_global.h"
+#include "BKE_object.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "intern/gpu_shader_private.h"
+
+#ifdef USE_GPU_SELECT
+# include "ED_view3d.h"
+# include "ED_armature.h"
+# include "GPU_select.h"
+#endif
+
+#ifdef USE_GPU_SELECT
+void DRW_select_load_id(uint id)
+{
+ BLI_assert(G.f & G_PICKSEL);
+ DST.select_id = id;
+}
+#endif
+
+#define DEBUG_UBO_BINDING
+
+struct GPUUniformBuffer *view_ubo;
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw State (DRW_state)
+ * \{ */
+
+void drw_state_set(DRWState state)
+{
+ if (DST.state == state) {
+ return;
+ }
+
+#define CHANGED_TO(f) \
+ ((DST.state_lock & (f)) ? 0 : \
+ (((DST.state & (f)) ? \
+ ((state & (f)) ? 0 : -1) : \
+ ((state & (f)) ? 1 : 0))))
+
+#define CHANGED_ANY(f) \
+ (((DST.state & (f)) != (state & (f))) && \
+ ((DST.state_lock & (f)) == 0))
+
+#define CHANGED_ANY_STORE_VAR(f, enabled) \
+ (((DST.state & (f)) != (enabled = (state & (f)))) && \
+ (((DST.state_lock & (f)) == 0)))
+
+ /* Depth Write */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_WRITE_DEPTH))) {
+ if (test == 1) {
+ glDepthMask(GL_TRUE);
+ }
+ else {
+ glDepthMask(GL_FALSE);
+ }
+ }
+ }
+
+ /* Color Write */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_WRITE_COLOR))) {
+ if (test == 1) {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+ else {
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ }
+ }
+ }
+
+ /* Raster Discard */
+ {
+ if (CHANGED_ANY(DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR |
+ DRW_STATE_WRITE_STENCIL |
+ DRW_STATE_WRITE_STENCIL_SHADOW_PASS |
+ DRW_STATE_WRITE_STENCIL_SHADOW_FAIL))
+ {
+ if ((state & (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR |
+ DRW_STATE_WRITE_STENCIL | DRW_STATE_WRITE_STENCIL_SHADOW_PASS |
+ DRW_STATE_WRITE_STENCIL_SHADOW_FAIL)) != 0)
+ {
+ glDisable(GL_RASTERIZER_DISCARD);
+ }
+ else {
+ glEnable(GL_RASTERIZER_DISCARD);
+ }
+ }
+ }
+
+ /* Cull */
+ {
+ DRWState test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_CULL_BACK | DRW_STATE_CULL_FRONT,
+ test))
+ {
+ if (test) {
+ glEnable(GL_CULL_FACE);
+
+ if ((state & DRW_STATE_CULL_BACK) != 0) {
+ glCullFace(GL_BACK);
+ }
+ else if ((state & DRW_STATE_CULL_FRONT) != 0) {
+ glCullFace(GL_FRONT);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ glDisable(GL_CULL_FACE);
+ }
+ }
+ }
+
+ /* Depth Test */
+ {
+ DRWState test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
+ DRW_STATE_DEPTH_GREATER | DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_DEPTH_ALWAYS,
+ test))
+ {
+ if (test) {
+ glEnable(GL_DEPTH_TEST);
+
+ if (state & DRW_STATE_DEPTH_LESS) {
+ glDepthFunc(GL_LESS);
+ }
+ else if (state & DRW_STATE_DEPTH_LESS_EQUAL) {
+ glDepthFunc(GL_LEQUAL);
+ }
+ else if (state & DRW_STATE_DEPTH_EQUAL) {
+ glDepthFunc(GL_EQUAL);
+ }
+ else if (state & DRW_STATE_DEPTH_GREATER) {
+ glDepthFunc(GL_GREATER);
+ }
+ else if (state & DRW_STATE_DEPTH_GREATER_EQUAL) {
+ glDepthFunc(GL_GEQUAL);
+ }
+ else if (state & DRW_STATE_DEPTH_ALWAYS) {
+ glDepthFunc(GL_ALWAYS);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ glDisable(GL_DEPTH_TEST);
+ }
+ }
+ }
+
+ /* Wire Width */
+ {
+ if (CHANGED_ANY(DRW_STATE_WIRE | DRW_STATE_WIRE_SMOOTH)) {
+ if ((state & DRW_STATE_WIRE_SMOOTH) != 0) {
+ GPU_line_width(2.0f);
+ GPU_line_smooth(true);
+ }
+ else if ((state & DRW_STATE_WIRE) != 0) {
+ GPU_line_width(1.0f);
+ }
+ else {
+ GPU_line_smooth(false);
+ }
+ }
+ }
+
+ /* Points Size */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_POINT))) {
+ if (test == 1) {
+ GPU_enable_program_point_size();
+ glPointSize(5.0f);
+ }
+ else {
+ GPU_disable_program_point_size();
+ }
+ }
+ }
+
+ /* Blending (all buffer) */
+ {
+ int test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_BLEND | DRW_STATE_BLEND_PREMUL | DRW_STATE_ADDITIVE |
+ DRW_STATE_MULTIPLY | DRW_STATE_ADDITIVE_FULL |
+ DRW_STATE_BLEND_OIT,
+ test))
+ {
+ if (test) {
+ glEnable(GL_BLEND);
+
+ if ((state & DRW_STATE_BLEND) != 0) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, /* RGB */
+ GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* Alpha */
+ }
+ else if ((state & DRW_STATE_BLEND_PREMUL) != 0) {
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else if ((state & DRW_STATE_MULTIPLY) != 0) {
+ glBlendFunc(GL_DST_COLOR, GL_ZERO);
+ }
+ else if ((state & DRW_STATE_BLEND_OIT) != 0) {
+ glBlendFuncSeparate(GL_ONE, GL_ONE, /* RGB */
+ GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); /* Alpha */
+ }
+ else if ((state & DRW_STATE_ADDITIVE) != 0) {
+ /* Do not let alpha accumulate but premult the source RGB by it. */
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, /* RGB */
+ GL_ZERO, GL_ONE); /* Alpha */
+ }
+ else if ((state & DRW_STATE_ADDITIVE_FULL) != 0) {
+ /* Let alpha accumulate. */
+ glBlendFunc(GL_ONE, GL_ONE);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ glDisable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE); /* Don't multiply incoming color by alpha. */
+ }
+ }
+ }
+
+ /* Clip Planes */
+ {
+ int test;
+ if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) {
+ if (test == 1) {
+ for (int i = 0; i < DST.num_clip_planes; ++i) {
+ glEnable(GL_CLIP_DISTANCE0 + i);
+ }
+ }
+ else {
+ for (int i = 0; i < MAX_CLIP_PLANES; ++i) {
+ glDisable(GL_CLIP_DISTANCE0 + i);
+ }
+ }
+ }
+ }
+
+ /* Line Stipple */
+ {
+ int test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_STIPPLE_2 | DRW_STATE_STIPPLE_3 | DRW_STATE_STIPPLE_4,
+ test))
+ {
+ if (test) {
+ if ((state & DRW_STATE_STIPPLE_2) != 0) {
+ setlinestyle(2);
+ }
+ else if ((state & DRW_STATE_STIPPLE_3) != 0) {
+ setlinestyle(3);
+ }
+ else if ((state & DRW_STATE_STIPPLE_4) != 0) {
+ setlinestyle(4);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ setlinestyle(0);
+ }
+ }
+ }
+
+ /* Stencil */
+ {
+ DRWState test;
+ if (CHANGED_ANY_STORE_VAR(
+ DRW_STATE_WRITE_STENCIL |
+ DRW_STATE_WRITE_STENCIL_SHADOW_PASS |
+ DRW_STATE_WRITE_STENCIL_SHADOW_FAIL |
+ DRW_STATE_STENCIL_EQUAL |
+ DRW_STATE_STENCIL_NEQUAL,
+ test))
+ {
+ if (test) {
+ glEnable(GL_STENCIL_TEST);
+ /* Stencil Write */
+ if ((state & DRW_STATE_WRITE_STENCIL) != 0) {
+ glStencilMask(0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ }
+ else if ((state & DRW_STATE_WRITE_STENCIL_SHADOW_PASS) != 0) {
+ glStencilMask(0xFF);
+ glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
+ glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
+ }
+ else if ((state & DRW_STATE_WRITE_STENCIL_SHADOW_FAIL) != 0) {
+ glStencilMask(0xFF);
+ glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
+ glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP);
+ }
+ /* Stencil Test */
+ else if ((state & (DRW_STATE_STENCIL_EQUAL | DRW_STATE_STENCIL_NEQUAL)) != 0) {
+ glStencilMask(0x00); /* disable write */
+ DST.stencil_mask = STENCIL_UNDEFINED;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ /* disable write & test */
+ DST.stencil_mask = 0;
+ glStencilMask(0x00);
+ glStencilFunc(GL_ALWAYS, 0, 0xFF);
+ glDisable(GL_STENCIL_TEST);
+ }
+ }
+ }
+
+#undef CHANGED_TO
+#undef CHANGED_ANY
+#undef CHANGED_ANY_STORE_VAR
+
+ DST.state = state;
+}
+
+static void drw_stencil_set(uint mask)
+{
+ if (DST.stencil_mask != mask) {
+ DST.stencil_mask = mask;
+ /* Stencil Write */
+ if ((DST.state & DRW_STATE_WRITE_STENCIL) != 0) {
+ glStencilFunc(GL_ALWAYS, mask, 0xFF);
+ }
+ /* Stencil Test */
+ else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) {
+ glStencilFunc(GL_EQUAL, mask, 0xFF);
+ }
+ else if ((DST.state & DRW_STATE_STENCIL_NEQUAL) != 0) {
+ glStencilFunc(GL_NOTEQUAL, mask, 0xFF);
+ }
+ }
+}
+
+/* Reset state to not interfer with other UI drawcall */
+void DRW_state_reset_ex(DRWState state)
+{
+ DST.state = ~state;
+ drw_state_set(state);
+}
+
+/**
+ * Use with care, intended so selection code can override passes depth settings,
+ * which is important for selection to work properly.
+ *
+ * Should be set in main draw loop, cleared afterwards
+ */
+void DRW_state_lock(DRWState state)
+{
+ DST.state_lock = state;
+}
+
+void DRW_state_reset(void)
+{
+ DRW_state_reset_ex(DRW_STATE_DEFAULT);
+
+ /* Reset blending function */
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+/* NOTE : Make sure to reset after use! */
+void DRW_state_invert_facing(void)
+{
+ SWAP(GLenum, DST.backface, DST.frontface);
+ glFrontFace(DST.frontface);
+}
+
+/**
+ * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES,
+ * and if the shaders have support for it (see usage of gl_ClipDistance).
+ * Be sure to call DRW_state_clip_planes_reset() after you finish drawing.
+ **/
+void DRW_state_clip_planes_count_set(uint plane_len)
+{
+ BLI_assert(plane_len <= MAX_CLIP_PLANES);
+ DST.num_clip_planes = plane_len;
+}
+
+void DRW_state_clip_planes_reset(void)
+{
+ DST.num_clip_planes = 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Clipping (DRW_clipping)
+ * \{ */
+
+/* Extract the 8 corners from a Projection Matrix.
+ * Although less accurate, this solution can be simplified as follows:
+ * BKE_boundbox_init_from_minmax(&bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const float[3]){1.0f, 1.0f, 1.0f});
+ * for (int i = 0; i < 8; i++) {mul_project_m4_v3(projinv, bbox.vec[i]);}
+ */
+static void draw_frustum_boundbox_calc(const float(*projmat)[4], BoundBox *r_bbox)
+{
+ float near, far, left, right, bottom, top;
+ bool is_persp = projmat[3][3] == 0.0f;
+
+ if (is_persp) {
+ near = projmat[3][2] / (projmat[2][2] - 1.0f);
+ far = projmat[3][2] / (projmat[2][2] + 1.0f);
+ left = near * (projmat[2][0] - 1.0f) / projmat[0][0];
+ right = near * (projmat[2][0] + 1.0f) / projmat[0][0];
+ bottom = near * (projmat[2][1] - 1.0f) / projmat[1][1];
+ top = near * (projmat[2][1] + 1.0f) / projmat[1][1];
+ }
+ else {
+ near = ( projmat[3][2] + 1.0f) / projmat[2][2];
+ far = ( projmat[3][2] - 1.0f) / projmat[2][2];
+ left = (-projmat[3][0] - 1.0f) / projmat[0][0];
+ right = (-projmat[3][0] + 1.0f) / projmat[0][0];
+ bottom = (-projmat[3][1] - 1.0f) / projmat[1][1];
+ top = (-projmat[3][1] + 1.0f) / projmat[1][1];
+ }
+
+ r_bbox->vec[0][2] = r_bbox->vec[3][2] = r_bbox->vec[7][2] = r_bbox->vec[4][2] = -near;
+ r_bbox->vec[0][0] = r_bbox->vec[3][0] = left;
+ r_bbox->vec[4][0] = r_bbox->vec[7][0] = right;
+ r_bbox->vec[0][1] = r_bbox->vec[4][1] = bottom;
+ r_bbox->vec[7][1] = r_bbox->vec[3][1] = top;
+
+ /* Get the coordinates of the far plane. */
+ if (is_persp) {
+ float sca_far = far / near;
+ left *= sca_far;
+ bottom *= sca_far;
+ right *= sca_far;
+ top *= sca_far;
+ }
+
+ r_bbox->vec[1][2] = r_bbox->vec[2][2] = r_bbox->vec[6][2] = r_bbox->vec[5][2] = -far;
+ r_bbox->vec[1][0] = r_bbox->vec[2][0] = left;
+ r_bbox->vec[6][0] = r_bbox->vec[5][0] = right;
+ r_bbox->vec[1][1] = r_bbox->vec[5][1] = bottom;
+ r_bbox->vec[2][1] = r_bbox->vec[6][1] = top;
+}
+
+static void draw_clipping_setup_from_view(void)
+{
+ if (DST.clipping.updated)
+ return;
+
+ float (*viewinv)[4] = DST.view_data.matstate.mat[DRW_MAT_VIEWINV];
+ float (*projmat)[4] = DST.view_data.matstate.mat[DRW_MAT_WIN];
+ float (*projinv)[4] = DST.view_data.matstate.mat[DRW_MAT_WININV];
+ BoundSphere *bsphere = &DST.clipping.frustum_bsphere;
+
+ /* Extract Clipping Planes */
+ BoundBox bbox;
+#if 0 /* It has accuracy problems. */
+ BKE_boundbox_init_from_minmax(&bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const float[3]){1.0f, 1.0f, 1.0f});
+ for (int i = 0; i < 8; i++) {
+ mul_project_m4_v3(projinv, bbox.vec[i]);
+ }
+#else
+ draw_frustum_boundbox_calc(projmat, &bbox);
+#endif
+ /* Transform into world space. */
+ for (int i = 0; i < 8; i++) {
+ mul_m4_v3(viewinv, bbox.vec[i]);
+ }
+
+ memcpy(&DST.clipping.frustum_corners, &bbox, sizeof(BoundBox));
+
+ /* Compute clip planes using the world space frustum corners. */
+ for (int p = 0; p < 6; p++) {
+ int q, r;
+ switch (p) {
+ case 0: q = 1; r = 2; break; /* -X */
+ case 1: q = 0; r = 5; break; /* -Y */
+ case 2: q = 1; r = 5; break; /* +Z (far) */
+ case 3: q = 2; r = 6; break; /* +Y */
+ case 4: q = 0; r = 3; break; /* -Z (near) */
+ default: q = 4; r = 7; break; /* +X */
+ }
+ if (DST.frontface == GL_CW) {
+ SWAP(int, q, r);
+ }
+
+ normal_tri_v3(DST.clipping.frustum_planes[p], bbox.vec[p], bbox.vec[q], bbox.vec[r]);
+ DST.clipping.frustum_planes[p][3] = -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[p]);
+ }
+
+ /* Extract Bounding Sphere */
+ if (projmat[3][3] != 0.0f) {
+ /* Orthographic */
+ /* The most extreme points on the near and far plane. (normalized device coords). */
+ float *nearpoint = bbox.vec[0];
+ float *farpoint = bbox.vec[6];
+
+ /* just use median point */
+ mid_v3_v3v3(bsphere->center, farpoint, nearpoint);
+ bsphere->radius = len_v3v3(bsphere->center, farpoint);
+ }
+ else if (projmat[2][0] == 0.0f && projmat[2][1] == 0.0f) {
+ /* Perspective with symmetrical frustum. */
+
+ /* We obtain the center and radius of the circumscribed circle of the
+ * isosceles trapezoid composed by the diagonals of the near and far clipping plane */
+
+ /* center of each clipping plane */
+ float mid_min[3], mid_max[3];
+ mid_v3_v3v3(mid_min, bbox.vec[3], bbox.vec[4]);
+ mid_v3_v3v3(mid_max, bbox.vec[2], bbox.vec[5]);
+
+ /* square length of the diagonals of each clipping plane */
+ float a_sq = len_squared_v3v3(bbox.vec[3], bbox.vec[4]);
+ float b_sq = len_squared_v3v3(bbox.vec[2], bbox.vec[5]);
+
+ /* distance squared between clipping planes */
+ float h_sq = len_squared_v3v3(mid_min, mid_max);
+
+ float fac = (4 * h_sq + b_sq - a_sq) / (8 * h_sq);
+
+ /* The goal is to get the smallest sphere,
+ * not the sphere that passes through each corner */
+ CLAMP(fac, 0.0f, 1.0f);
+
+ interp_v3_v3v3(bsphere->center, mid_min, mid_max, fac);
+
+ /* distance from the center to one of the points of the far plane (1, 2, 5, 6) */
+ bsphere->radius = len_v3v3(bsphere->center, bbox.vec[1]);
+ }
+ else {
+ /* Perspective with asymmetrical frustum. */
+
+ /* We put the sphere center on the line that goes from origin
+ * to the center of the far clipping plane. */
+
+ /* Detect which of the corner of the far clipping plane is the farthest to the origin */
+ float nfar[4]; /* most extreme far point in NDC space */
+ float farxy[2]; /* farpoint projection onto the near plane */
+ float farpoint[3] = {0.0f}; /* most extreme far point in camera coordinate */
+ float nearpoint[3]; /* most extreme near point in camera coordinate */
+ float farcenter[3] = {0.0f}; /* center of far cliping plane in camera coordinate */
+ float F = -1.0f, N; /* square distance of far and near point to origin */
+ float f, n; /* distance of far and near point to z axis. f is always > 0 but n can be < 0 */
+ float e, s; /* far and near clipping distance (<0) */
+ float c; /* slope of center line = distance of far clipping center to z axis / far clipping distance */
+ float z; /* projection of sphere center on z axis (<0) */
+
+ /* Find farthest corner and center of far clip plane. */
+ float corner[3] = {1.0f, 1.0f, 1.0f}; /* in clip space */
+ for (int i = 0; i < 4; i++) {
+ float point[3];
+ mul_v3_project_m4_v3(point, projinv, corner);
+ float len = len_squared_v3(point);
+ if (len > F) {
+ copy_v3_v3(nfar, corner);
+ copy_v3_v3(farpoint, point);
+ F = len;
+ }
+ add_v3_v3(farcenter, point);
+ /* rotate by 90 degree to walk through the 4 points of the far clip plane */
+ float tmp = corner[0];
+ corner[0] = -corner[1];
+ corner[1] = tmp;
+ }
+
+ /* the far center is the average of the far clipping points */
+ mul_v3_fl(farcenter, 0.25f);
+ /* the extreme near point is the opposite point on the near clipping plane */
+ copy_v3_fl3(nfar, -nfar[0], -nfar[1], -1.0f);
+ mul_v3_project_m4_v3(nearpoint, projinv, nfar);
+ /* this is a frustum projection */
+ N = len_squared_v3(nearpoint);
+ e = farpoint[2];
+ s = nearpoint[2];
+ /* distance to view Z axis */
+ f = len_v2(farpoint);
+ /* get corresponding point on the near plane */
+ mul_v2_v2fl(farxy, farpoint, s / e);
+ /* this formula preserve the sign of n */
+ sub_v2_v2(nearpoint, farxy);
+ n = f * s / e - len_v2(nearpoint);
+ c = len_v2(farcenter) / e;
+ /* the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case */
+ z = (F - N) / (2.0f * (e - s + c * (f - n)));
+
+ bsphere->center[0] = farcenter[0] * z / e;
+ bsphere->center[1] = farcenter[1] * z / e;
+ bsphere->center[2] = z;
+ bsphere->radius = len_v3v3(bsphere->center, farpoint);
+
+ /* Transform to world space. */
+ mul_m4_v3(viewinv, bsphere->center);
+ }
+
+ DST.clipping.updated = true;
+}
+
+/* Return True if the given BoundSphere intersect the current view frustum */
+bool DRW_culling_sphere_test(BoundSphere *bsphere)
+{
+ draw_clipping_setup_from_view();
+
+ /* Bypass test if radius is negative. */
+ if (bsphere->radius < 0.0f)
+ return true;
+
+ /* Do a rough test first: Sphere VS Sphere intersect. */
+ BoundSphere *frustum_bsphere = &DST.clipping.frustum_bsphere;
+ float center_dist = len_squared_v3v3(bsphere->center, frustum_bsphere->center);
+ if (center_dist > SQUARE(bsphere->radius + frustum_bsphere->radius))
+ return false;
+
+ /* Test against the 6 frustum planes. */
+ for (int p = 0; p < 6; p++) {
+ float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bsphere->center);
+ if (dist < -bsphere->radius) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Return True if the given BoundBox intersect the current view frustum.
+ * bbox must be in world space. */
+bool DRW_culling_box_test(BoundBox *bbox)
+{
+ draw_clipping_setup_from_view();
+
+ /* 6 view frustum planes */
+ for (int p = 0; p < 6; p++) {
+ /* 8 box vertices. */
+ for (int v = 0; v < 8 ; v++) {
+ float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bbox->vec[v]);
+ if (dist > 0.0f) {
+ /* At least one point in front of this plane.
+ * Go to next plane. */
+ break;
+ }
+ else if (v == 7) {
+ /* 8 points behind this plane. */
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Return True if the current view frustum is inside or intersect the given plane */
+bool DRW_culling_plane_test(float plane[4])
+{
+ draw_clipping_setup_from_view();
+
+ /* Test against the 8 frustum corners. */
+ for (int c = 0; c < 8; c++) {
+ float dist = plane_point_side_v3(plane, DST.clipping.frustum_corners.vec[c]);
+ if (dist < 0.0f) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void DRW_culling_frustum_corners_get(BoundBox *corners)
+{
+ draw_clipping_setup_from_view();
+ memcpy(corners, &DST.clipping.frustum_corners, sizeof(BoundBox));
+}
+
+/* See draw_clipping_setup_from_view() for the plane order. */
+void DRW_culling_frustum_planes_get(float planes[6][4])
+{
+ draw_clipping_setup_from_view();
+ memcpy(planes, &DST.clipping.frustum_planes, sizeof(DST.clipping.frustum_planes));
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Draw (DRW_draw)
+ * \{ */
+
+static void draw_visibility_eval(DRWCallState *st)
+{
+ bool culled = st->flag & DRW_CALL_CULLED;
+
+ if (st->cache_id != DST.state_cache_id) {
+ /* Update culling result for this view. */
+ culled = !DRW_culling_sphere_test(&st->bsphere);
+ }
+
+ if (st->visibility_cb) {
+ culled = !st->visibility_cb(!culled, st->user_data);
+ }
+
+ SET_FLAG_FROM_TEST(st->flag, culled, DRW_CALL_CULLED);
+}
+
+static void draw_matrices_model_prepare(DRWCallState *st)
+{
+ if (st->cache_id == DST.state_cache_id) {
+ /* Values are already updated for this view. */
+ return;
+ }
+ else {
+ st->cache_id = DST.state_cache_id;
+ }
+
+ /* No need to go further the call will not be used. */
+ if ((st->flag & DRW_CALL_CULLED) != 0 &&
+ (st->flag & DRW_CALL_BYPASS_CULLING) == 0)
+ {
+ return;
+ }
+ /* Order matters */
+ if (st->matflag & (DRW_CALL_MODELVIEW | DRW_CALL_MODELVIEWINVERSE |
+ DRW_CALL_NORMALVIEW | DRW_CALL_EYEVEC))
+ {
+ mul_m4_m4m4(st->modelview, DST.view_data.matstate.mat[DRW_MAT_VIEW], st->model);
+ }
+ if (st->matflag & DRW_CALL_MODELVIEWINVERSE) {
+ invert_m4_m4(st->modelviewinverse, st->modelview);
+ }
+ if (st->matflag & DRW_CALL_MODELVIEWPROJECTION) {
+ mul_m4_m4m4(st->modelviewprojection, DST.view_data.matstate.mat[DRW_MAT_PERS], st->model);
+ }
+ if (st->matflag & (DRW_CALL_NORMALVIEW | DRW_CALL_EYEVEC)) {
+ copy_m3_m4(st->normalview, st->modelview);
+ invert_m3(st->normalview);
+ transpose_m3(st->normalview);
+ }
+ if (st->matflag & DRW_CALL_EYEVEC) {
+ /* Used by orthographic wires */
+ float tmp[3][3];
+ copy_v3_fl3(st->eyevec, 0.0f, 0.0f, 1.0f);
+ invert_m3_m3(tmp, st->normalview);
+ /* set eye vector, transformed to object coords */
+ mul_m3_v3(tmp, st->eyevec);
+ }
+ /* Non view dependent */
+ if (st->matflag & DRW_CALL_MODELINVERSE) {
+ invert_m4_m4(st->modelinverse, st->model);
+ st->matflag &= ~DRW_CALL_MODELINVERSE;
+ }
+ if (st->matflag & DRW_CALL_NORMALWORLD) {
+ copy_m3_m4(st->normalworld, st->model);
+ invert_m3(st->normalworld);
+ transpose_m3(st->normalworld);
+ st->matflag &= ~DRW_CALL_NORMALWORLD;
+ }
+}
+
+static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call)
+{
+ /* step 1 : bind object dependent matrices */
+ if (call != NULL) {
+ DRWCallState *state = call->state;
+ float objectinfo[3];
+ objectinfo[0] = state->objectinfo[0];
+ objectinfo[1] = call->single.ma_index; /* WATCH this is only valid for single drawcalls. */
+ objectinfo[2] = state->objectinfo[1];
+
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelview, 16, 1, (float *)state->modelview);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewinverse, 16, 1, (float *)state->modelviewinverse);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)state->modelviewprojection);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->normalview, 9, 1, (float *)state->normalview);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->normalworld, 9, 1, (float *)state->normalworld);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 3, 1, (float *)objectinfo);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->eye, 3, 1, (float *)state->eyevec);
+ }
+ else {
+ BLI_assert((shgroup->normalview == -1) && (shgroup->normalworld == -1) && (shgroup->eye == -1));
+ /* For instancing and batching. */
+ float unitmat[4][4];
+ unit_m4(unitmat);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)unitmat);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelinverse, 16, 1, (float *)unitmat);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelview, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_VIEW]);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewinverse, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_VIEWINV]);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_PERS]);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 3, 1, (float *)unitmat);
+ GPU_shader_uniform_vector(shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)shgroup->instance_orcofac);
+ }
+}
+
+static void draw_geometry_execute_ex(
+ DRWShadingGroup *shgroup, GPUBatch *geom, uint start, uint count, bool draw_instance)
+{
+ /* Special case: empty drawcall, placement is done via shader, don't bind anything. */
+ /* TODO use DRW_CALL_PROCEDURAL instead */
+ if (geom == NULL) {
+ BLI_assert(shgroup->type == DRW_SHG_TRIANGLE_BATCH); /* Add other type if needed. */
+ /* Shader is already bound. */
+ GPU_draw_primitive(GPU_PRIM_TRIS, count);
+ return;
+ }
+
+ /* step 2 : bind vertex array & draw */
+ GPU_batch_program_set_no_use(
+ geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+ /* XXX hacking gawain. we don't want to call glUseProgram! (huge performance loss) */
+ geom->program_in_use = true;
+
+ GPU_batch_draw_range_ex(geom, start, count, draw_instance);
+
+ geom->program_in_use = false; /* XXX hacking gawain */
+}
+
+static void draw_geometry_execute(DRWShadingGroup *shgroup, GPUBatch *geom)
+{
+ draw_geometry_execute_ex(shgroup, geom, 0, 0, false);
+}
+
+enum {
+ BIND_NONE = 0,
+ BIND_TEMP = 1, /* Release slot after this shading group. */
+ BIND_PERSIST = 2, /* Release slot only after the next shader change. */
+};
+
+static void bind_texture(GPUTexture *tex, char bind_type)
+{
+ int index;
+ char *slot_flags = DST.RST.bound_tex_slots;
+ int bind_num = GPU_texture_bound_number(tex);
+ if (bind_num == -1) {
+ for (int i = 0; i < GPU_max_textures(); ++i) {
+ index = DST.RST.bind_tex_inc = (DST.RST.bind_tex_inc + 1) % GPU_max_textures();
+ if (slot_flags[index] == BIND_NONE) {
+ if (DST.RST.bound_texs[index] != NULL) {
+ GPU_texture_unbind(DST.RST.bound_texs[index]);
+ }
+ GPU_texture_bind(tex, index);
+ DST.RST.bound_texs[index] = tex;
+ slot_flags[index] = bind_type;
+ // printf("Binds Texture %d %p\n", DST.RST.bind_tex_inc, tex);
+ return;
+ }
+ }
+ printf("Not enough texture slots! Reduce number of textures used by your shader.\n");
+ }
+ slot_flags[bind_num] = bind_type;
+}
+
+static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
+{
+ int index;
+ char *slot_flags = DST.RST.bound_ubo_slots;
+ int bind_num = GPU_uniformbuffer_bindpoint(ubo);
+ if (bind_num == -1) {
+ for (int i = 0; i < GPU_max_ubo_binds(); ++i) {
+ index = DST.RST.bind_ubo_inc = (DST.RST.bind_ubo_inc + 1) % GPU_max_ubo_binds();
+ if (slot_flags[index] == BIND_NONE) {
+ if (DST.RST.bound_ubos[index] != NULL) {
+ GPU_uniformbuffer_unbind(DST.RST.bound_ubos[index]);
+ }
+ GPU_uniformbuffer_bind(ubo, index);
+ DST.RST.bound_ubos[index] = ubo;
+ slot_flags[index] = bind_type;
+ return;
+ }
+ }
+ /* printf so user can report bad behaviour */
+ printf("Not enough ubo slots! This should not happen!\n");
+ /* This is not depending on user input.
+ * It is our responsibility to make sure there is enough slots. */
+ BLI_assert(0);
+ }
+ slot_flags[bind_num] = bind_type;
+}
+
+#ifndef NDEBUG
+/**
+ * Opengl specification is strict on buffer binding.
+ *
+ * " If any active uniform block is not backed by a
+ * sufficiently large buffer object, the results of shader
+ * execution are undefined, and may result in GL interruption or
+ * termination. " - Opengl 3.3 Core Specification
+ *
+ * For now we only check if the binding is correct. Not the size of
+ * the bound ubo.
+ *
+ * See T55475.
+ * */
+static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
+{
+ bool valid = true;
+# ifdef DEBUG_UBO_BINDING
+ /* Check that all active uniform blocks have a non-zero buffer bound. */
+ GLint program = 0;
+ GLint active_blocks = 0;
+
+ glGetIntegerv(GL_CURRENT_PROGRAM, &program);
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &active_blocks);
+
+ for (uint i = 0; i < active_blocks; ++i) {
+ int binding = 0;
+ int buffer = 0;
+
+ glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_BINDING, &binding);
+ glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, binding, &buffer);
+
+ if (buffer == 0) {
+ char blockname[64];
+ glGetActiveUniformBlockName(program, i, sizeof(blockname), NULL, blockname);
+
+ if (valid) {
+ printf("Trying to draw with missing UBO binding.\n");
+ valid = false;
+ }
+ printf("Pass : %s, Shader : %s, Block : %s\n", shgroup->pass_parent->name, shgroup->shader->name, blockname);
+ }
+ }
+# endif
+ return valid;
+}
+#endif
+
+static void release_texture_slots(bool with_persist)
+{
+ if (with_persist) {
+ memset(DST.RST.bound_tex_slots, 0x0, sizeof(*DST.RST.bound_tex_slots) * GPU_max_textures());
+ }
+ else {
+ for (int i = 0; i < GPU_max_textures(); ++i) {
+ if (DST.RST.bound_tex_slots[i] != BIND_PERSIST)
+ DST.RST.bound_tex_slots[i] = BIND_NONE;
+ }
+ }
+
+ /* Reset so that slots are consistently assigned for different shader
+ * draw calls, to avoid shader specialization/patching by the driver. */
+ DST.RST.bind_tex_inc = 0;
+}
+
+static void release_ubo_slots(bool with_persist)
+{
+ if (with_persist) {
+ memset(DST.RST.bound_ubo_slots, 0x0, sizeof(*DST.RST.bound_ubo_slots) * GPU_max_ubo_binds());
+ }
+ else {
+ for (int i = 0; i < GPU_max_ubo_binds(); ++i) {
+ if (DST.RST.bound_ubo_slots[i] != BIND_PERSIST)
+ DST.RST.bound_ubo_slots[i] = BIND_NONE;
+ }
+ }
+
+ /* Reset so that slots are consistently assigned for different shader
+ * draw calls, to avoid shader specialization/patching by the driver. */
+ DST.RST.bind_ubo_inc = 0;
+}
+
+static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
+{
+ BLI_assert(shgroup->shader);
+
+ GPUTexture *tex;
+ GPUUniformBuffer *ubo;
+ int val;
+ float fval;
+ const bool shader_changed = (DST.shader != shgroup->shader);
+ bool use_tfeedback = false;
+
+ if (shader_changed) {
+ if (DST.shader) GPU_shader_unbind();
+ GPU_shader_bind(shgroup->shader);
+ DST.shader = shgroup->shader;
+ }
+
+ if ((pass_state & DRW_STATE_TRANS_FEEDBACK) != 0 &&
+ (shgroup->type == DRW_SHG_FEEDBACK_TRANSFORM))
+ {
+ use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
+ shgroup->tfeedback_target->vbo_id);
+ }
+
+ release_ubo_slots(shader_changed);
+ release_texture_slots(shader_changed);
+
+ drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
+ drw_stencil_set(shgroup->stencil_mask);
+
+ /* Binding Uniform */
+ for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) {
+ switch (uni->type) {
+ case DRW_UNIFORM_SHORT_TO_INT:
+ val = (int)*((short *)uni->pvalue);
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, &val);
+ break;
+ case DRW_UNIFORM_SHORT_TO_FLOAT:
+ fval = (float)*((short *)uni->pvalue);
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)&fval);
+ break;
+ case DRW_UNIFORM_BOOL_COPY:
+ case DRW_UNIFORM_INT_COPY:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, &uni->ivalue);
+ break;
+ case DRW_UNIFORM_BOOL:
+ case DRW_UNIFORM_INT:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->pvalue);
+ break;
+ case DRW_UNIFORM_FLOAT_COPY:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, &uni->fvalue);
+ break;
+ case DRW_UNIFORM_FLOAT:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->pvalue);
+ break;
+ case DRW_UNIFORM_TEXTURE:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_PERSIST:
+ tex = (GPUTexture *)uni->pvalue;
+ BLI_assert(tex);
+ bind_texture(tex, BIND_PERSIST);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_TEXTURE_REF:
+ tex = *((GPUTexture **)uni->pvalue);
+ BLI_assert(tex);
+ bind_texture(tex, BIND_TEMP);
+ GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ break;
+ case DRW_UNIFORM_BLOCK:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_TEMP);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ case DRW_UNIFORM_BLOCK_PERSIST:
+ ubo = (GPUUniformBuffer *)uni->pvalue;
+ bind_ubo(ubo, BIND_PERSIST);
+ GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ break;
+ }
+ }
+
+#ifdef USE_GPU_SELECT
+# define GPU_SELECT_LOAD_IF_PICKSEL(_select_id) \
+ if (G.f & G_PICKSEL) { \
+ GPU_select_load_id(_select_id); \
+ } ((void)0)
+
+# define GPU_SELECT_LOAD_IF_PICKSEL_CALL(_call) \
+ if ((G.f & G_PICKSEL) && (_call)) { \
+ GPU_select_load_id((_call)->select_id); \
+ } ((void)0)
+
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \
+ _start = 0; \
+ _count = _shgroup->instance_count; \
+ int *select_id = NULL; \
+ if (G.f & G_PICKSEL) { \
+ if (_shgroup->override_selectid == -1) { \
+ /* Hack : get vbo data without actually drawing. */ \
+ GPUVertBufRaw raw; \
+ GPU_vertbuf_attr_get_raw_data(_shgroup->inst_selectid, 0, &raw); \
+ select_id = GPU_vertbuf_raw_step(&raw); \
+ switch (_shgroup->type) { \
+ case DRW_SHG_TRIANGLE_BATCH: _count = 3; break; \
+ case DRW_SHG_LINE_BATCH: _count = 2; break; \
+ default: _count = 1; break; \
+ } \
+ } \
+ else { \
+ GPU_select_load_id(_shgroup->override_selectid); \
+ } \
+ } \
+ while (_start < _shgroup->instance_count) { \
+ if (select_id) { \
+ GPU_select_load_id(select_id[_start]); \
+ }
+
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(_start, _count) \
+ _start += _count; \
+ }
+
+#else
+# define GPU_SELECT_LOAD_IF_PICKSEL(select_id)
+# define GPU_SELECT_LOAD_IF_PICKSEL_CALL(call)
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count)
+# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \
+ _start = 0; \
+ _count = _shgroup->instance_count;
+
+#endif
+
+ BLI_assert(ubo_bindings_validate(shgroup));
+
+ /* Rendering Calls */
+ if (!ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM)) {
+ /* Replacing multiple calls with only one */
+ if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) {
+ if (shgroup->type == DRW_SHG_INSTANCE_EXTERNAL) {
+ if (shgroup->instance_geom != NULL) {
+ GPU_SELECT_LOAD_IF_PICKSEL(shgroup->override_selectid);
+ draw_geometry_prepare(shgroup, NULL);
+ draw_geometry_execute_ex(shgroup, shgroup->instance_geom, 0, 0, true);
+ }
+ }
+ else {
+ if (shgroup->instance_count > 0) {
+ uint count, start;
+ draw_geometry_prepare(shgroup, NULL);
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count)
+ {
+ draw_geometry_execute_ex(shgroup, shgroup->instance_geom, start, count, true);
+ }
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count)
+ }
+ }
+ }
+ else { /* DRW_SHG_***_BATCH */
+ /* Some dynamic batch can have no geom (no call to aggregate) */
+ if (shgroup->instance_count > 0) {
+ uint count, start;
+ draw_geometry_prepare(shgroup, NULL);
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count)
+ {
+ draw_geometry_execute_ex(shgroup, shgroup->batch_geom, start, count, false);
+ }
+ GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count)
+ }
+ }
+ }
+ else {
+ bool prev_neg_scale = false;
+ int callid = 0;
+ for (DRWCall *call = shgroup->calls.first; call; call = call->next) {
+
+ /* OPTI/IDEA(clem): Do this preparation in another thread. */
+ draw_visibility_eval(call->state);
+ draw_matrices_model_prepare(call->state);
+
+ if ((call->state->flag & DRW_CALL_CULLED) != 0 &&
+ (call->state->flag & DRW_CALL_BYPASS_CULLING) == 0)
+ {
+ continue;
+ }
+
+ /* XXX small exception/optimisation for outline rendering. */
+ if (shgroup->callid != -1) {
+ GPU_shader_uniform_vector_int(shgroup->shader, shgroup->callid, 1, 1, &callid);
+ callid += 1;
+ }
+
+ /* Negative scale objects */
+ bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE;
+ if (neg_scale != prev_neg_scale) {
+ glFrontFace((neg_scale) ? DST.backface : DST.frontface);
+ prev_neg_scale = neg_scale;
+ }
+
+ GPU_SELECT_LOAD_IF_PICKSEL_CALL(call);
+ draw_geometry_prepare(shgroup, call);
+
+ switch (call->type) {
+ case DRW_CALL_SINGLE:
+ draw_geometry_execute(shgroup, call->single.geometry);
+ break;
+ case DRW_CALL_RANGE:
+ draw_geometry_execute_ex(shgroup, call->range.geometry, call->range.start, call->range.count, false);
+ break;
+ case DRW_CALL_INSTANCES:
+ draw_geometry_execute_ex(shgroup, call->instances.geometry, 0, *call->instances.count, true);
+ break;
+ case DRW_CALL_GENERATE:
+ call->generate.geometry_fn(shgroup, draw_geometry_execute, call->generate.user_data);
+ break;
+ case DRW_CALL_PROCEDURAL:
+ GPU_draw_primitive(call->procedural.prim_type, call->procedural.vert_count);
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ /* Reset state */
+ glFrontFace(DST.frontface);
+ }
+
+ if (use_tfeedback) {
+ GPU_shader_transform_feedback_disable(shgroup->shader);
+ }
+
+ /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */
+ DRW_state_reset();
+}
+
+static void drw_update_view(void)
+{
+ if (DST.dirty_mat) {
+ DST.state_cache_id++;
+ DST.dirty_mat = false;
+
+ DRW_uniformbuffer_update(view_ubo, &DST.view_data);
+
+ /* Catch integer wrap around. */
+ if (UNLIKELY(DST.state_cache_id == 0)) {
+ DST.state_cache_id = 1;
+ /* We must reset all CallStates to ensure that not
+ * a single one stayed with cache_id equal to 1. */
+ BLI_mempool_iter iter;
+ DRWCallState *state;
+ BLI_mempool_iternew(DST.vmempool->states, &iter);
+ while ((state = BLI_mempool_iterstep(&iter))) {
+ state->cache_id = 0;
+ }
+ }
+
+ /* TODO dispatch threads to compute matrices/culling */
+ }
+
+ draw_clipping_setup_from_view();
+}
+
+static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
+{
+ if (start_group == NULL)
+ return;
+
+ DST.shader = NULL;
+
+ BLI_assert(DST.buffer_finish_called && "DRW_render_instance_buffer_finish had not been called before drawing");
+
+ drw_update_view();
+
+ drw_state_set(pass->state);
+
+ DRW_stats_query_start(pass->name);
+
+ for (DRWShadingGroup *shgroup = start_group; shgroup; shgroup = shgroup->next) {
+ draw_shgroup(shgroup, pass->state);
+ /* break if upper limit */
+ if (shgroup == end_group) {
+ break;
+ }
+ }
+
+ /* Clear Bound textures */
+ for (int i = 0; i < GPU_max_textures(); i++) {
+ if (DST.RST.bound_texs[i] != NULL) {
+ GPU_texture_unbind(DST.RST.bound_texs[i]);
+ DST.RST.bound_texs[i] = NULL;
+ }
+ }
+
+ /* Clear Bound Ubos */
+ for (int i = 0; i < GPU_max_ubo_binds(); i++) {
+ if (DST.RST.bound_ubos[i] != NULL) {
+ GPU_uniformbuffer_unbind(DST.RST.bound_ubos[i]);
+ DST.RST.bound_ubos[i] = NULL;
+ }
+ }
+
+ if (DST.shader) {
+ GPU_shader_unbind();
+ DST.shader = NULL;
+ }
+
+ DRW_stats_query_end();
+}
+
+void DRW_draw_pass(DRWPass *pass)
+{
+ drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last);
+}
+
+/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
+void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
+{
+ drw_draw_pass_ex(pass, start_group, end_group);
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
new file mode 100644
index 00000000000..7b5ea4445ce
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_manager_profiling.c
+ * \ingroup draw
+ */
+
+#include "BLI_rect.h"
+#include "BLI_string.h"
+
+#include "BKE_global.h"
+
+#include "BLF_api.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "draw_manager.h"
+
+#include "GPU_glew.h"
+#include "GPU_texture.h"
+
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "draw_manager_profiling.h"
+
+#define MAX_TIMER_NAME 32
+#define MAX_NESTED_TIMER 8
+#define CHUNK_SIZE 8
+#define GPU_TIMER_FALLOFF 0.1
+
+typedef struct DRWTimer {
+ GLuint query[2];
+ GLuint64 time_average;
+ char name[MAX_TIMER_NAME];
+ int lvl; /* Hierarchy level for nested timer. */
+ bool is_query; /* Does this timer actually perform queries or is it just a group. */
+} DRWTimer;
+
+static struct DRWTimerPool {
+ DRWTimer *timers;
+ int chunk_count; /* Number of chunk allocated. */
+ int timer_count; /* chunk_count * CHUNK_SIZE */
+ int timer_increment; /* Keep track of where we are in the stack. */
+ int end_increment; /* Keep track of bad usage. */
+ bool is_recording; /* Are we in the render loop? */
+ bool is_querying; /* Keep track of bad usage. */
+} DTP = {NULL};
+
+void DRW_stats_free(void)
+{
+ if (DTP.timers != NULL) {
+ for (int i = 0; i < DTP.timer_count; ++i) {
+ DRWTimer *timer = &DTP.timers[i];
+ glDeleteQueries(2, timer->query);
+ }
+ MEM_freeN(DTP.timers);
+ DTP.timers = NULL;
+ }
+}
+
+void DRW_stats_begin(void)
+{
+ if (G.debug_value > 20 && G.debug_value < 30) {
+ DTP.is_recording = true;
+ }
+
+ if (DTP.is_recording && DTP.timers == NULL) {
+ DTP.chunk_count = 1;
+ DTP.timer_count = DTP.chunk_count * CHUNK_SIZE;
+ DTP.timers = MEM_callocN(sizeof(DRWTimer) * DTP.timer_count, "DRWTimer stack");
+ }
+ else if (!DTP.is_recording && DTP.timers != NULL) {
+ DRW_stats_free();
+ }
+
+ DTP.is_querying = false;
+ DTP.timer_increment = 0;
+ DTP.end_increment = 0;
+}
+
+static DRWTimer *drw_stats_timer_get(void)
+{
+ if (UNLIKELY(DTP.timer_increment >= DTP.timer_count)) {
+ /* Resize the stack. */
+ DTP.chunk_count++;
+ DTP.timer_count = DTP.chunk_count * CHUNK_SIZE;
+ DTP.timers = MEM_recallocN(DTP.timers, sizeof(DRWTimer) * DTP.timer_count);
+ }
+
+ return &DTP.timers[DTP.timer_increment++];
+}
+
+static void drw_stats_timer_start_ex(const char *name, const bool is_query)
+{
+ if (DTP.is_recording) {
+ DRWTimer *timer = drw_stats_timer_get();
+ BLI_strncpy(timer->name, name, MAX_TIMER_NAME);
+ timer->lvl = DTP.timer_increment - DTP.end_increment - 1;
+ timer->is_query = is_query;
+
+ /* Queries cannot be nested or interleaved. */
+ BLI_assert(!DTP.is_querying);
+ if (timer->is_query) {
+ if (timer->query[0] == 0) {
+ glGenQueries(1, timer->query);
+ }
+
+ glFinish();
+ /* Issue query for the next frame */
+ glBeginQuery(GL_TIME_ELAPSED, timer->query[0]);
+ DTP.is_querying = true;
+ }
+ }
+}
+
+/* Use this to group the queries. It does NOT keep track
+ * of the time, it only sum what the queries inside it. */
+void DRW_stats_group_start(const char *name)
+{
+ drw_stats_timer_start_ex(name, false);
+}
+
+void DRW_stats_group_end(void)
+{
+ if (DTP.is_recording) {
+ BLI_assert(!DTP.is_querying);
+ DTP.end_increment++;
+ }
+}
+
+/* NOTE: Only call this when no sub timer will be called. */
+void DRW_stats_query_start(const char *name)
+{
+ drw_stats_timer_start_ex(name, true);
+}
+
+void DRW_stats_query_end(void)
+{
+ if (DTP.is_recording) {
+ DTP.end_increment++;
+ BLI_assert(DTP.is_querying);
+ glEndQuery(GL_TIME_ELAPSED);
+ DTP.is_querying = false;
+ }
+}
+
+void DRW_stats_reset(void)
+{
+ BLI_assert((DTP.timer_increment - DTP.end_increment) <= 0 && "You forgot a DRW_stats_group/query_end somewhere!");
+ BLI_assert((DTP.timer_increment - DTP.end_increment) >= 0 && "You forgot a DRW_stats_group/query_start somewhere!");
+
+ if (DTP.is_recording) {
+ GLuint64 lvl_time[MAX_NESTED_TIMER] = {0};
+
+ /* Swap queries for the next frame and sum up each lvl time. */
+ for (int i = DTP.timer_increment - 1; i >= 0; --i) {
+ DRWTimer *timer = &DTP.timers[i];
+ SWAP(GLuint, timer->query[0], timer->query[1]);
+
+ BLI_assert(timer->lvl < MAX_NESTED_TIMER);
+
+ if (timer->is_query) {
+ GLuint64 time;
+ if (timer->query[0] != 0) {
+ glGetQueryObjectui64v(timer->query[0], GL_QUERY_RESULT, &time);
+ }
+ else {
+ time = 1000000000; /* 1ms default */
+ }
+
+ timer->time_average = timer->time_average * (1.0 - GPU_TIMER_FALLOFF) + time * GPU_TIMER_FALLOFF;
+ timer->time_average = MIN2(timer->time_average, 1000000000);
+ }
+ else {
+ timer->time_average = lvl_time[timer->lvl + 1];
+ lvl_time[timer->lvl + 1] = 0;
+ }
+
+ lvl_time[timer->lvl] += timer->time_average;
+ }
+
+ DTP.is_recording = false;
+ }
+}
+
+static void draw_stat_5row(rcti *rect, int u, int v, const char *txt, const int size)
+{
+ BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit,
+ rect->ymax - (3 + v) * U.widget_unit, 0.0f,
+ txt, size);
+}
+
+static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size)
+{
+ BLF_draw_default_ascii(rect->xmin + (1 + u) * U.widget_unit,
+ rect->ymax - (3 + v) * U.widget_unit, 0.0f,
+ txt, size);
+}
+
+void DRW_stats_draw(rcti *rect)
+{
+ char stat_string[64];
+ int lvl_index[MAX_NESTED_TIMER];
+ int v = 0, u = 0;
+
+ double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0;
+
+ int fontid = BLF_default();
+ UI_FontThemeColor(fontid, TH_TEXT_HI);
+ BLF_enable(fontid, BLF_SHADOW);
+ BLF_shadow(fontid, 5, (const float[4]){0.0f, 0.0f, 0.0f, 0.75f});
+ BLF_shadow_offset(fontid, 0, -1);
+
+ BLF_batch_draw_begin();
+
+ /* ------------------------------------------ */
+ /* ---------------- CPU stats --------------- */
+ /* ------------------------------------------ */
+ /* Label row */
+ char col_label[32];
+ sprintf(col_label, "Engine");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Init");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Background");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Render");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(col_label, "Total (w/o cache)");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ v++;
+
+ /* Engines rows */
+ char time_to_txt[16];
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ u = 0;
+ DrawEngineType *engine = link->data;
+ ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
+
+ draw_stat_5row(rect, u++, v, engine->idname, sizeof(engine->idname));
+
+ init_tot_time += data->init_time;
+ sprintf(time_to_txt, "%.2fms", data->init_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+
+ background_tot_time += data->background_time;
+ sprintf(time_to_txt, "%.2fms", data->background_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+
+ render_tot_time += data->render_time;
+ sprintf(time_to_txt, "%.2fms", data->render_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+
+ tot_time += data->init_time + data->background_time + data->render_time;
+ sprintf(time_to_txt, "%.2fms", data->init_time + data->background_time + data->render_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ v++;
+ }
+
+ /* Totals row */
+ u = 0;
+ sprintf(col_label, "Sub Total");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(time_to_txt, "%.2fms", init_tot_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", background_tot_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", render_tot_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ sprintf(time_to_txt, "%.2fms", tot_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ v += 2;
+
+ u = 0;
+ double *cache_time = GPU_viewport_cache_time_get(DST.viewport);
+ sprintf(col_label, "Cache Time");
+ draw_stat_5row(rect, u++, v, col_label, sizeof(col_label));
+ sprintf(time_to_txt, "%.2fms", *cache_time);
+ draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt));
+ v += 2;
+
+ /* ------------------------------------------ */
+ /* ---------------- GPU stats --------------- */
+ /* ------------------------------------------ */
+
+ /* Memory Stats */
+ uint tex_mem = GPU_texture_memory_usage_get();
+ uint vbo_mem = GPU_vertbuf_get_memory_usage();
+
+ sprintf(stat_string, "GPU Memory");
+ draw_stat(rect, 0, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (double)(tex_mem + vbo_mem) / 1000000.0);
+ draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "Textures");
+ draw_stat(rect, 1, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (double)tex_mem / 1000000.0);
+ draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "Meshes");
+ draw_stat(rect, 1, v, stat_string, sizeof(stat_string));
+ sprintf(stat_string, "%.2fMB", (double)vbo_mem / 1000000.0);
+ draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string));
+ v += 1;
+
+ /* GPU Timings */
+ BLI_snprintf(stat_string, sizeof(stat_string), "GPU Render Timings");
+ draw_stat(rect, 0, v++, stat_string, sizeof(stat_string));
+
+ for (int i = 0; i < DTP.timer_increment; ++i) {
+ double time_ms, time_percent;
+ DRWTimer *timer = &DTP.timers[i];
+ DRWTimer *timer_parent = (timer->lvl > 0) ? &DTP.timers[lvl_index[timer->lvl - 1]] : NULL;
+
+ /* Only display a number of lvl at a time */
+ if ((G.debug_value - 21) < timer->lvl) continue;
+
+ BLI_assert(timer->lvl < MAX_NESTED_TIMER);
+ lvl_index[timer->lvl] = i;
+
+ time_ms = timer->time_average / 1000000.0;
+
+ if (timer_parent != NULL) {
+ time_percent = ((double)timer->time_average / (double)timer_parent->time_average) * 100.0;
+ }
+ else {
+ time_percent = 100.0;
+ }
+
+ /* avoid very long number */
+ time_ms = MIN2(time_ms, 999.0);
+ time_percent = MIN2(time_percent, 100.0);
+
+ BLI_snprintf(stat_string, sizeof(stat_string), "%s", timer->name);
+ draw_stat(rect, 0 + timer->lvl, v, stat_string, sizeof(stat_string));
+ BLI_snprintf(stat_string, sizeof(stat_string), "%.2fms", time_ms);
+ draw_stat(rect, 12 + timer->lvl, v, stat_string, sizeof(stat_string));
+ BLI_snprintf(stat_string, sizeof(stat_string), "%.0f", time_percent);
+ draw_stat(rect, 16 + timer->lvl, v, stat_string, sizeof(stat_string));
+ v++;
+ }
+
+ BLF_batch_draw_end();
+ BLF_disable(fontid, BLF_SHADOW);
+}
diff --git a/source/blender/draw/intern/draw_manager_profiling.h b/source/blender/draw/intern/draw_manager_profiling.h
new file mode 100644
index 00000000000..233cd3878d2
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_profiling.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_manager_profiling.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_MANAGER_PROFILING_H__
+#define __DRAW_MANAGER_PROFILING_H__
+
+struct rcti;
+
+void DRW_stats_free(void);
+void DRW_stats_begin(void);
+void DRW_stats_reset(void);
+
+void DRW_stats_group_start(const char *name);
+void DRW_stats_group_end(void);
+
+void DRW_stats_query_start(const char *name);
+void DRW_stats_query_end(void);
+
+void DRW_stats_draw(rcti *rect);
+
+#endif /* __DRAW_MANAGER_PROFILING_H__ */
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
new file mode 100644
index 00000000000..bb580695865
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_manager_shader.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+#include "DNA_world_types.h"
+#include "DNA_material_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_threads.h"
+#include "BLI_task.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "GPU_shader.h"
+#include "GPU_material.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+extern char datatoc_gpu_shader_2D_vert_glsl[];
+extern char datatoc_gpu_shader_3D_vert_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+
+#define USE_DEFERRED_COMPILATION 1
+
+/* -------------------------------------------------------------------- */
+
+/** \name Deferred Compilation (DRW_deferred)
+ *
+ * Since compiling shader can take a long time, we do it in a non blocking
+ * manner in another thread.
+ *
+ * \{ */
+
+typedef struct DRWDeferredShader {
+ struct DRWDeferredShader *prev, *next;
+
+ GPUMaterial *mat;
+} DRWDeferredShader;
+
+typedef struct DRWShaderCompiler {
+ ListBase queue; /* DRWDeferredShader */
+ SpinLock list_lock;
+
+ DRWDeferredShader *mat_compiling;
+ ThreadMutex compilation_lock;
+
+ void *gl_context;
+ bool own_context;
+
+ int shaders_done; /* To compute progress. */
+} DRWShaderCompiler;
+
+static void drw_deferred_shader_free(DRWDeferredShader *dsh)
+{
+ /* Make sure it is not queued before freeing. */
+ MEM_freeN(dsh);
+}
+
+static void drw_deferred_shader_queue_free(ListBase *queue)
+{
+ DRWDeferredShader *dsh;
+ while ((dsh = BLI_pophead(queue))) {
+ drw_deferred_shader_free(dsh);
+ }
+}
+
+static void drw_deferred_shader_compilation_exec(void *custom_data, short *stop, short *do_update, float *progress)
+{
+ DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
+ void *gl_context = comp->gl_context;
+
+ WM_opengl_context_activate(gl_context);
+
+ while (true) {
+ BLI_spin_lock(&comp->list_lock);
+
+ if (*stop != 0) {
+ /* We don't want user to be able to cancel the compilation
+ * but wm can kill the task if we are closing blender. */
+ BLI_spin_unlock(&comp->list_lock);
+ break;
+ }
+
+ /* Pop tail because it will be less likely to lock the main thread
+ * if all GPUMaterials are to be freed (see DRW_deferred_shader_remove()). */
+ comp->mat_compiling = BLI_poptail(&comp->queue);
+ if (comp->mat_compiling == NULL) {
+ /* No more Shader to compile. */
+ BLI_spin_unlock(&comp->list_lock);
+ break;
+ }
+
+ comp->shaders_done++;
+ int total = BLI_listbase_count(&comp->queue) + comp->shaders_done;
+
+ BLI_mutex_lock(&comp->compilation_lock);
+ BLI_spin_unlock(&comp->list_lock);
+
+ /* Do the compilation. */
+ GPU_material_compile(comp->mat_compiling->mat);
+
+ *progress = (float)comp->shaders_done / (float)total;
+ *do_update = true;
+
+ glFlush();
+ BLI_mutex_unlock(&comp->compilation_lock);
+
+ BLI_spin_lock(&comp->list_lock);
+ drw_deferred_shader_free(comp->mat_compiling);
+ comp->mat_compiling = NULL;
+ BLI_spin_unlock(&comp->list_lock);
+ }
+
+ WM_opengl_context_release(gl_context);
+}
+
+static void drw_deferred_shader_compilation_free(void *custom_data)
+{
+ DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
+
+ drw_deferred_shader_queue_free(&comp->queue);
+
+ BLI_spin_end(&comp->list_lock);
+ BLI_mutex_end(&comp->compilation_lock);
+
+ if (comp->own_context) {
+ /* Only destroy if the job owns the context. */
+ WM_opengl_context_dispose(comp->gl_context);
+ }
+
+ MEM_freeN(comp);
+}
+
+static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred)
+{
+ /* Do not deferre the compilation if we are rendering for image. */
+ if (DRW_state_is_image_render() || !USE_DEFERRED_COMPILATION || !deferred) {
+ /* Double checking that this GPUMaterial is not going to be
+ * compiled by another thread. */
+ DRW_deferred_shader_remove(mat);
+ GPU_material_compile(mat);
+ return;
+ }
+
+ DRWDeferredShader *dsh = MEM_callocN(sizeof(DRWDeferredShader), "Deferred Shader");
+
+ dsh->mat = mat;
+
+ BLI_assert(DST.draw_ctx.evil_C);
+ wmWindowManager *wm = CTX_wm_manager(DST.draw_ctx.evil_C);
+ wmWindow *win = CTX_wm_window(DST.draw_ctx.evil_C);
+
+ /* Use original scene ID since this is what the jobs template tests for. */
+ Scene *scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
+
+ /* Get the running job or a new one if none is running. Can only have one job per type & owner. */
+ wmJob *wm_job = WM_jobs_get(wm, win, scene, "Shaders Compilation",
+ WM_JOB_PROGRESS | WM_JOB_SUSPEND, WM_JOB_TYPE_SHADER_COMPILATION);
+
+ DRWShaderCompiler *old_comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job);
+
+ DRWShaderCompiler *comp = MEM_callocN(sizeof(DRWShaderCompiler), "DRWShaderCompiler");
+ BLI_spin_init(&comp->list_lock);
+ BLI_mutex_init(&comp->compilation_lock);
+
+ if (old_comp) {
+ BLI_spin_lock(&old_comp->list_lock);
+ BLI_movelisttolist(&comp->queue, &old_comp->queue);
+ BLI_spin_unlock(&old_comp->list_lock);
+ /* Do not recreate context, just pass ownership. */
+ if (old_comp->gl_context) {
+ comp->gl_context = old_comp->gl_context;
+ old_comp->own_context = false;
+ comp->own_context = true;
+ }
+ }
+
+ BLI_addtail(&comp->queue, dsh);
+
+ /* Create only one context. */
+ if (comp->gl_context == NULL) {
+ comp->gl_context = WM_opengl_context_create();
+ WM_opengl_context_activate(DST.gl_context);
+ comp->own_context = true;
+ }
+
+ WM_jobs_customdata_set(wm_job, comp, drw_deferred_shader_compilation_free);
+ WM_jobs_timer(wm_job, 0.1, NC_MATERIAL | ND_SHADING_DRAW, 0);
+ WM_jobs_callbacks(wm_job, drw_deferred_shader_compilation_exec, NULL, NULL, NULL);
+ WM_jobs_start(wm, wm_job);
+}
+
+void DRW_deferred_shader_remove(GPUMaterial *mat)
+{
+ Scene *scene = GPU_material_scene(mat);
+
+ for (wmWindowManager *wm = G_MAIN->wm.first; wm; wm = wm->id.next) {
+ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_SHADER_COMPILATION) == false) {
+ /* No job running, do not create a new one by calling WM_jobs_get. */
+ continue;
+ }
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ wmJob *wm_job = WM_jobs_get(wm, win, scene, "Shaders Compilation",
+ WM_JOB_PROGRESS | WM_JOB_SUSPEND, WM_JOB_TYPE_SHADER_COMPILATION);
+
+ DRWShaderCompiler *comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job);
+ if (comp != NULL) {
+ BLI_spin_lock(&comp->list_lock);
+ DRWDeferredShader *dsh;
+ dsh = (DRWDeferredShader *)BLI_findptr(&comp->queue, mat, offsetof(DRWDeferredShader, mat));
+ if (dsh) {
+ BLI_remlink(&comp->queue, dsh);
+ }
+
+ /* Wait for compilation to finish */
+ if ((comp->mat_compiling != NULL) && (comp->mat_compiling->mat == mat)) {
+ BLI_mutex_lock(&comp->compilation_lock);
+ BLI_mutex_unlock(&comp->compilation_lock);
+ }
+
+ BLI_spin_unlock(&comp->list_lock);
+
+ if (dsh) {
+ drw_deferred_shader_free(dsh);
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines)
+{
+ return GPU_shader_create(vert, frag, geom, NULL, defines, __func__);
+}
+
+GPUShader *DRW_shader_create_with_lib(
+ const char *vert, const char *geom, const char *frag, const char *lib, const char *defines)
+{
+ GPUShader *sh;
+ char *vert_with_lib = NULL;
+ char *frag_with_lib = NULL;
+ char *geom_with_lib = NULL;
+
+ vert_with_lib = BLI_string_joinN(lib, vert);
+ frag_with_lib = BLI_string_joinN(lib, frag);
+ if (geom) {
+ geom_with_lib = BLI_string_joinN(lib, geom);
+ }
+
+ sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines, __func__);
+
+ MEM_freeN(vert_with_lib);
+ MEM_freeN(frag_with_lib);
+ if (geom) {
+ MEM_freeN(geom_with_lib);
+ }
+
+ return sh;
+}
+
+GPUShader *DRW_shader_create_with_transform_feedback(
+ const char *vert, const char *geom, const char *defines,
+ const GPUShaderTFBType prim_type, const char **varying_names, const int varying_count)
+{
+ return GPU_shader_create_ex(vert, NULL, geom, NULL, defines,
+ prim_type, varying_names, varying_count, __func__);
+}
+
+GPUShader *DRW_shader_create_2D(const char *frag, const char *defines)
+{
+ return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines, __func__);
+}
+
+GPUShader *DRW_shader_create_3D(const char *frag, const char *defines)
+{
+ return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines, __func__);
+}
+
+GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines)
+{
+ return GPU_shader_create(datatoc_common_fullscreen_vert_glsl, frag, NULL, NULL, defines, __func__);
+}
+
+GPUShader *DRW_shader_create_3D_depth_only(void)
+{
+ return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY);
+}
+
+GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int options, bool deferred)
+{
+ GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
+ if (DRW_state_is_image_render() || !deferred) {
+ if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX
+ * with the shader code and we will resume the compilation from there. */
+ return NULL;
+ }
+ }
+ return mat;
+}
+
+GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, int options, bool deferred)
+{
+ GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
+ if (DRW_state_is_image_render() || !deferred) {
+ if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX
+ * with the shader code and we will resume the compilation from there. */
+ return NULL;
+ }
+ }
+ return mat;
+}
+
+GPUMaterial *DRW_shader_create_from_world(
+ struct Scene *scene, World *wo, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines, bool deferred)
+{
+ GPUMaterial *mat = NULL;
+ if (DRW_state_is_image_render()) {
+ mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
+ }
+
+ if (mat == NULL) {
+ scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
+ mat = GPU_material_from_nodetree(
+ scene, wo->nodetree, &wo->gpumaterial, engine_type, options,
+ vert, geom, frag_lib, defines, wo->id.name);
+ }
+
+ if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ drw_deferred_shader_add(mat, deferred);
+ }
+
+ return mat;
+}
+
+GPUMaterial *DRW_shader_create_from_material(
+ struct Scene *scene, Material *ma, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines, bool deferred)
+{
+ GPUMaterial *mat = NULL;
+ if (DRW_state_is_image_render()) {
+ mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
+ }
+
+ if (mat == NULL) {
+ scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
+ mat = GPU_material_from_nodetree(
+ scene, ma->nodetree, &ma->gpumaterial, engine_type, options,
+ vert, geom, frag_lib, defines, ma->id.name);
+ }
+
+ if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ drw_deferred_shader_add(mat, deferred);
+ }
+
+ return mat;
+}
+
+void DRW_shader_free(GPUShader *shader)
+{
+ GPU_shader_free(shader);
+}
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
new file mode 100644
index 00000000000..1a183e14d60
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/** \file blender/draw/intern/draw_manager_text.c
+ * \ingroup draw
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_math.h"
+
+#include "BIF_gl.h"
+
+#include "GPU_matrix.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "BLF_api.h"
+
+#include "draw_manager_text.h"
+
+typedef struct ViewCachedString {
+ struct ViewCachedString *next, *prev;
+ float vec[3];
+ union {
+ uchar ub[4];
+ int pack;
+ } col;
+ short sco[2];
+ short xoffs, yoffs;
+ short flag;
+ int str_len;
+
+ /* str is allocated past the end */
+ char str[0];
+} ViewCachedString;
+
+typedef struct DRWTextStore {
+ ListBase list;
+} DRWTextStore;
+
+DRWTextStore *DRW_text_cache_create(void)
+{
+ DRWTextStore *dt = MEM_callocN(sizeof(*dt), __func__);
+ return dt;
+}
+
+void DRW_text_cache_destroy(struct DRWTextStore *dt)
+{
+ BLI_freelistN(&dt->list);
+ MEM_freeN(dt);
+}
+
+void DRW_text_cache_add(
+ DRWTextStore *dt,
+ const float co[3],
+ const char *str, const int str_len,
+ short xoffs, short yoffs, short flag,
+ const uchar col[4])
+{
+ int alloc_len;
+ ViewCachedString *vos;
+
+ if (flag & DRW_TEXT_CACHE_STRING_PTR) {
+ BLI_assert(str_len == strlen(str));
+ alloc_len = sizeof(void *);
+ }
+ else {
+ alloc_len = str_len + 1;
+ }
+
+ vos = MEM_mallocN(sizeof(ViewCachedString) + alloc_len, __func__);
+
+ BLI_addtail(&dt->list, vos);
+
+ copy_v3_v3(vos->vec, co);
+ copy_v4_v4_uchar(vos->col.ub, col);
+ vos->xoffs = xoffs;
+ vos->yoffs = yoffs;
+ vos->flag = flag;
+ vos->str_len = str_len;
+
+ /* allocate past the end */
+ if (flag & DRW_TEXT_CACHE_STRING_PTR) {
+ memcpy(vos->str, &str, alloc_len);
+ }
+ else {
+ memcpy(vos->str, str, alloc_len);
+ }
+}
+
+void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ ViewCachedString *vos;
+ int tot = 0;
+
+ /* project first and test */
+ for (vos = dt->list.first; vos; vos = vos->next) {
+ if (ED_view3d_project_short_ex(
+ ar,
+ (vos->flag & DRW_TEXT_CACHE_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
+ (vos->flag & DRW_TEXT_CACHE_LOCALCLIP) != 0,
+ vos->vec, vos->sco,
+ V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ {
+ tot++;
+ }
+ else {
+ vos->sco[0] = IS_CLIPPED;
+ }
+ }
+
+ if (tot) {
+ int col_pack_prev = 0;
+
+ if (rv3d->rflag & RV3D_CLIPPING) {
+ ED_view3d_clipping_disable();
+ }
+
+ float original_proj[4][4];
+ GPU_matrix_projection_get(original_proj);
+ wmOrtho2_region_pixelspace(ar);
+
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+
+ const int font_id = BLF_default();
+
+ const uiStyle *style = UI_style_get();
+
+ BLF_size(font_id, style->widget.points * U.pixelsize, U.dpi);
+
+ for (vos = dt->list.first; vos; vos = vos->next) {
+ if (vos->sco[0] != IS_CLIPPED) {
+ if (col_pack_prev != vos->col.pack) {
+ BLF_color4ubv(font_id, vos->col.ub);
+ col_pack_prev = vos->col.pack;
+ }
+
+ BLF_position(
+ font_id,
+ (float)(vos->sco[0] + vos->xoffs), (float)(vos->sco[1] + vos->yoffs), 2.0f);
+
+ ((vos->flag & DRW_TEXT_CACHE_ASCII) ?
+ BLF_draw_ascii :
+ BLF_draw
+ )(font_id,
+ (vos->flag & DRW_TEXT_CACHE_STRING_PTR) ? *((const char **)vos->str) : vos->str,
+ vos->str_len);
+ }
+ }
+
+ GPU_matrix_pop();
+ GPU_matrix_projection_set(original_proj);
+
+ if (rv3d->rflag & RV3D_CLIPPING) {
+ ED_view3d_clipping_enable();
+ }
+ }
+}
diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h
new file mode 100644
index 00000000000..6798f36e7f4
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_text.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/** \file blender/draw/intern/draw_manager_text.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_MANAGER_TEXT_H__
+#define __DRAW_MANAGER_TEXT_H__
+
+struct DRWTextStore;
+
+struct DRWTextStore *DRW_text_cache_create(void);
+void DRW_text_cache_destroy(struct DRWTextStore *dt);
+
+void DRW_text_cache_add(
+ struct DRWTextStore *dt,
+ const float co[3],
+ const char *str, const int str_len,
+ short xoffs, short yoffs, short flag,
+ const uchar col[4]);
+
+void DRW_text_cache_draw(struct DRWTextStore *dt, struct ARegion *ar);
+
+enum {
+ DRW_TEXT_CACHE_ASCII = (1 << 0),
+ DRW_TEXT_CACHE_GLOBALSPACE = (1 << 1),
+ DRW_TEXT_CACHE_LOCALCLIP = (1 << 2),
+ /* reference the string by pointer */
+ DRW_TEXT_CACHE_STRING_PTR = (1 << 3),
+};
+
+/* draw_manager.c */
+struct DRWTextStore *DRW_text_cache_ensure(void);
+
+#endif /* __DRAW_MANAGER_TEXT_H__ */
diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c
new file mode 100644
index 00000000000..36882a87408
--- /dev/null
+++ b/source/blender/draw/intern/draw_manager_texture.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_manager_texture.c
+ * \ingroup draw
+ */
+
+#include "draw_manager.h"
+
+#ifndef NDEBUG
+/* Maybe gpu_texture.c is a better place for this. */
+static bool drw_texture_format_supports_framebuffer(GPUTextureFormat format)
+{
+ /* Some formats do not work with framebuffers. */
+ switch (format) {
+ /* Only add formats that are COMPATIBLE with FB.
+ * Generally they are multiple of 16bit. */
+ case GPU_R16F:
+ case GPU_R16I:
+ case GPU_R16UI:
+ case GPU_R16:
+ case GPU_R32F:
+ case GPU_R32UI:
+ case GPU_RG8:
+ case GPU_RG16:
+ case GPU_RG16F:
+ case GPU_RG16I:
+ case GPU_RG32F:
+ case GPU_R11F_G11F_B10F:
+ case GPU_RGBA8:
+ case GPU_RGBA16F:
+ case GPU_RGBA32F:
+ case GPU_DEPTH_COMPONENT16:
+ case GPU_DEPTH_COMPONENT24:
+ case GPU_DEPTH24_STENCIL8:
+ case GPU_DEPTH_COMPONENT32F:
+ return true;
+ default:
+ return false;
+ }
+}
+#endif
+
+void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags)
+{
+ GPU_texture_bind(tex, 0);
+ if (flags & DRW_TEX_MIPMAP) {
+ GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER);
+ GPU_texture_generate_mipmap(tex);
+ }
+ else {
+ GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER);
+ }
+ GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP);
+ GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE);
+ GPU_texture_unbind(tex);
+}
+
+GPUTexture *DRW_texture_create_1D(int w, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex = GPU_texture_create_1D(w, format, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_2D(int w, int h, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex = GPU_texture_create_2D(w, h, format, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_2D_array(
+ int w, int h, int d, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex = GPU_texture_create_2D_array(w, h, d, format, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_3D(
+ int w, int h, int d, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex = GPU_texture_create_3D(w, h, d, format, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_create_cube(int w, GPUTextureFormat format, DRWTextureFlag flags, const float *fpixels)
+{
+ GPUTexture *tex = GPU_texture_create_cube(w, format, fpixels, NULL);
+ drw_texture_set_parameters(tex, flags);
+
+ return tex;
+}
+
+GPUTexture *DRW_texture_pool_query_2D(int w, int h, GPUTextureFormat format, DrawEngineType *engine_type)
+{
+ BLI_assert(drw_texture_format_supports_framebuffer(format));
+ GPUTexture *tex = GPU_viewport_texture_pool_query(DST.viewport, engine_type, w, h, format);
+
+ return tex;
+}
+
+void DRW_texture_ensure_fullscreen_2D(GPUTexture **tex, GPUTextureFormat format, DRWTextureFlag flags)
+{
+ if (*(tex) == NULL) {
+ const float *size = DRW_viewport_size_get();
+ *(tex) = DRW_texture_create_2D((int)size[0], (int)size[1], format, flags, NULL);
+ }
+}
+
+void DRW_texture_ensure_2D(GPUTexture **tex, int w, int h, GPUTextureFormat format, DRWTextureFlag flags)
+{
+ if (*(tex) == NULL) {
+ *(tex) = DRW_texture_create_2D(w, h, format, flags, NULL);
+ }
+}
+
+void DRW_texture_generate_mipmaps(GPUTexture *tex)
+{
+ GPU_texture_bind(tex, 0);
+ GPU_texture_generate_mipmap(tex);
+ GPU_texture_unbind(tex);
+}
+
+void DRW_texture_free(GPUTexture *tex)
+{
+ GPU_texture_free(tex);
+}
diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c
new file mode 100644
index 00000000000..8867c85ac2f
--- /dev/null
+++ b/source/blender/draw/intern/draw_view.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/intern/draw_view.c
+ * \ingroup draw
+ *
+ * Contains dynamic drawing using immediate mode
+ */
+
+#include "DNA_brush_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_world_types.h"
+#include "DNA_view3d_types.h"
+
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_view3d.h"
+
+#include "GPU_draw.h"
+#include "GPU_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_unit.h"
+
+#include "DRW_render.h"
+
+#include "view3d_intern.h"
+
+#include "draw_view.h"
+
+/* ******************** region info ***************** */
+
+void DRW_draw_region_info(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ARegion *ar = draw_ctx->ar;
+
+ DRW_draw_cursor();
+
+ view3d_draw_region_info(draw_ctx->evil_C, ar);
+}
+
+/* ************************* Background ************************** */
+
+void DRW_draw_background(void)
+{
+ /* Just to make sure */
+ glDepthMask(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glStencilMask(0xFF);
+
+ if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) {
+ float m[4][4];
+ unit_m4(m);
+
+ /* Gradient background Color */
+ glDisable(GL_DEPTH_TEST);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uchar col_hi[3], col_lo[3];
+
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+ GPU_matrix_projection_set(m);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR_DITHER);
+
+ UI_GetThemeColor3ubv(TH_LOW_GRAD, col_lo);
+ UI_GetThemeColor3ubv(TH_HIGH_GRAD, col_hi);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr3ubv(color, col_lo);
+ immVertex2f(pos, -1.0f, -1.0f);
+ immVertex2f(pos, 1.0f, -1.0f);
+
+ immAttr3ubv(color, col_hi);
+ immVertex2f(pos, 1.0f, 1.0f);
+ immVertex2f(pos, -1.0f, 1.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ glEnable(GL_DEPTH_TEST);
+ }
+ else {
+ /* Solid background Color */
+ UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ }
+}
+
+/* **************************** 3D Cursor ******************************** */
+
+static bool is_cursor_visible(const DRWContextState *draw_ctx, Scene *scene, ViewLayer *view_layer)
+{
+ View3D *v3d = draw_ctx->v3d;
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_CURSOR)) {
+ return false;
+ }
+
+ /* don't draw cursor in paint modes, but with a few exceptions */
+ if (draw_ctx->object_mode & OB_MODE_ALL_PAINT) {
+ /* exception: object is in weight paint and has deforming armature in pose mode */
+ if (draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) {
+ if (BKE_object_pose_armature_get(draw_ctx->obact) != NULL) {
+ return true;
+ }
+ }
+ /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */
+ else if (draw_ctx->object_mode & OB_MODE_TEXTURE_PAINT) {
+ const Paint *p = BKE_paint_get_active(scene, view_layer);
+
+ if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) {
+ if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
+ return true;
+ }
+ }
+ }
+
+ /* no exception met? then don't draw cursor! */
+ return false;
+ }
+ else if (draw_ctx->object_mode & OB_MODE_GPENCIL_WEIGHT) {
+ /* grease pencil hide always in some modes */
+ return false;
+ }
+
+ return true;
+}
+
+void DRW_draw_cursor(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ARegion *ar = draw_ctx->ar;
+ Scene *scene = draw_ctx->scene;
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+
+ if (is_cursor_visible(draw_ctx, scene, view_layer)) {
+ int co[2];
+ const View3DCursor *cursor = &scene->cursor;
+ if (ED_view3d_project_int_global(
+ ar, cursor->location, co, V3D_PROJ_TEST_NOP | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ {
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* Draw nice Anti Aliased cursor. */
+ glLineWidth(1.0f);
+ glEnable(GL_BLEND);
+ glEnable(GL_LINE_SMOOTH);
+
+ float eps = 1e-5f;
+ rv3d->viewquat[0] = -rv3d->viewquat[0];
+ const bool is_aligned = compare_v4v4(cursor->rotation, rv3d->viewquat, eps);
+ rv3d->viewquat[0] = -rv3d->viewquat[0];
+
+ /* Draw lines */
+ if (is_aligned == false) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor3(TH_VIEW_OVERLAY);
+ immBegin(GPU_PRIM_LINES, 12);
+
+ const float scale = ED_view3d_pixel_size_no_ui_scale(rv3d, cursor->location) * U.widget_unit;
+
+#define CURSOR_VERT(axis_vec, axis, fac) \
+ immVertex3f( \
+ pos, \
+ cursor->location[0] + axis_vec[0] * (fac), \
+ cursor->location[1] + axis_vec[1] * (fac), \
+ cursor->location[2] + axis_vec[2] * (fac))
+
+#define CURSOR_EDGE(axis_vec, axis, sign) { \
+ CURSOR_VERT(axis_vec, axis, sign 1.0f); \
+ CURSOR_VERT(axis_vec, axis, sign 0.25f); \
+ }
+
+ for (int axis = 0; axis < 3; axis++) {
+ float axis_vec[3] = {0};
+ axis_vec[axis] = scale;
+ mul_qt_v3(cursor->rotation, axis_vec);
+ CURSOR_EDGE(axis_vec, axis, +);
+ CURSOR_EDGE(axis_vec, axis, -);
+ }
+
+#undef CURSOR_VERT
+#undef CURSOR_EDGE
+
+ immEnd();
+ immUnbindProgram();
+ }
+
+ ED_region_pixelspace(ar);
+ GPU_matrix_translate_2f(co[0] + 0.5f, co[1] + 0.5f);
+ GPU_matrix_scale_2f(U.widget_unit, U.widget_unit);
+
+ GPUBatch *cursor_batch = DRW_cache_cursor_get(is_aligned);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_FLAT_COLOR);
+ GPU_batch_program_set(cursor_batch, GPU_shader_get_program(shader), GPU_shader_get_interface(shader));
+
+ GPU_batch_draw(cursor_batch);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
+ }
+}
+
+/* **************************** 3D Gizmo ******************************** */
+
+void DRW_draw_gizmo_3d(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ARegion *ar = draw_ctx->ar;
+
+ /* draw depth culled gizmos - gizmos need to be updated *after* view matrix was set up */
+ /* TODO depth culling gizmos is not yet supported, just drawing _3D here, should
+ * later become _IN_SCENE (and draw _3D separate) */
+ WM_gizmomap_draw(
+ ar->gizmo_map, draw_ctx->evil_C,
+ WM_GIZMOMAP_DRAWSTEP_3D);
+
+}
+
+void DRW_draw_gizmo_2d(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ARegion *ar = draw_ctx->ar;
+
+ WM_gizmomap_draw(
+ ar->gizmo_map, draw_ctx->evil_C,
+ WM_GIZMOMAP_DRAWSTEP_2D);
+
+ glDepthMask(GL_TRUE);
+}
diff --git a/source/blender/draw/intern/draw_view.h b/source/blender/draw/intern/draw_view.h
new file mode 100644
index 00000000000..01a342f0ae4
--- /dev/null
+++ b/source/blender/draw/intern/draw_view.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file draw_view.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_VIEW_H__
+#define __DRAW_VIEW_H__
+
+void DRW_draw_region_info(void);
+void DRW_draw_background(void);
+void DRW_draw_cursor(void);
+void DRW_draw_gizmo_3d(void);
+void DRW_draw_gizmo_2d(void);
+
+#endif /* __DRAW_VIEW_H__ */
diff --git a/source/blender/draw/modes/draw_mode_engines.h b/source/blender/draw/modes/draw_mode_engines.h
new file mode 100644
index 00000000000..059724384ea
--- /dev/null
+++ b/source/blender/draw/modes/draw_mode_engines.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/draw_mode_engines.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_MODE_ENGINES_H__
+#define __DRAW_MODE_ENGINES_H__
+
+extern DrawEngineType draw_engine_object_type;
+extern DrawEngineType draw_engine_edit_armature_type;
+extern DrawEngineType draw_engine_edit_curve_type;
+extern DrawEngineType draw_engine_edit_lattice_type;
+extern DrawEngineType draw_engine_edit_mesh_type;
+extern DrawEngineType draw_engine_edit_metaball_type;
+extern DrawEngineType draw_engine_edit_text_type;
+extern DrawEngineType draw_engine_motion_path_type;
+extern DrawEngineType draw_engine_paint_texture_type;
+extern DrawEngineType draw_engine_paint_vertex_type;
+extern DrawEngineType draw_engine_paint_weight_type;
+extern DrawEngineType draw_engine_particle_type;
+extern DrawEngineType draw_engine_pose_type;
+extern DrawEngineType draw_engine_sculpt_type;
+extern DrawEngineType draw_engine_overlay_type;
+extern DrawEngineType draw_engine_gpencil_type;
+
+#endif /* __DRAW_MODE_ENGINES_H__ */
diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c
new file mode 100644
index 00000000000..02f208900e4
--- /dev/null
+++ b/source/blender/draw/modes/edit_armature_mode.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_armature_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_view3d_types.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+extern GlobalsUboStorage ts;
+
+/* *********** LISTS *********** */
+typedef struct EDIT_ARMATURE_PassList {
+ struct DRWPass *bone_solid[2];
+ struct DRWPass *bone_wire[2];
+ struct DRWPass *bone_outline[2];
+ struct DRWPass *bone_envelope[2];
+ struct DRWPass *bone_axes;
+ struct DRWPass *relationship[2];
+} EDIT_ARMATURE_PassList;
+
+typedef struct EDIT_ARMATURE_StorageList {
+ struct EDIT_ARMATURE_PrivateData *g_data;
+} EDIT_ARMATURE_StorageList;
+
+typedef struct EDIT_ARMATURE_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ EDIT_ARMATURE_PassList *psl;
+ EDIT_ARMATURE_StorageList *stl;
+} EDIT_ARMATURE_Data;
+
+/* *********** STATIC *********** */
+
+typedef struct EDIT_ARMATURE_PrivateData {
+ bool transparent_bones;
+} EDIT_ARMATURE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+static void EDIT_ARMATURE_cache_init(void *vedata)
+{
+ EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
+ EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+ stl->g_data->transparent_bones = (draw_ctx->v3d->overlay.arm_flag & V3D_OVERLAY_ARM_TRANSP_BONES) != 0;
+
+ for (int i = 0; i < 2; ++i) {
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ state |= (stl->g_data->transparent_bones) ? DRW_STATE_BLEND : DRW_STATE_WRITE_DEPTH;
+ psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state);
+
+ /* Bones Outline */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ psl->bone_outline[i] = DRW_pass_create("Bone Outline Pass", state);
+
+ /* Wire bones */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
+ psl->bone_wire[i] = DRW_pass_create("Bone Wire Pass", state);
+
+ /* distance outline around envelope bones */
+ state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_FRONT;
+ psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass", state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND | DRW_STATE_WIRE;
+ psl->relationship[i] = DRW_pass_create("Bone Relationship Pass", state);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WIRE_SMOOTH | DRW_STATE_BLEND;
+ psl->bone_axes = DRW_pass_create("Bone Axes Pass", state);
+ }
+}
+
+static void EDIT_ARMATURE_cache_populate(void *vedata, Object *ob)
+{
+ bArmature *arm = ob->data;
+
+ if (ob->type == OB_ARMATURE) {
+ if (arm->edbo) {
+ EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
+ EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl;
+
+ int ghost = (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
+
+ DRWArmaturePasses passes = {
+ .bone_solid = psl->bone_solid[ghost],
+ .bone_outline = psl->bone_outline[ghost],
+ .bone_wire = psl->bone_wire[ghost],
+ .bone_envelope = psl->bone_envelope[ghost],
+ .bone_axes = psl->bone_axes,
+ .relationship_lines = psl->relationship[ghost],
+ };
+ DRW_shgroup_armature_edit(ob, passes, stl->g_data->transparent_bones);
+ }
+ }
+}
+
+static void EDIT_ARMATURE_draw_scene(void *vedata)
+{
+ EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
+ EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_draw_pass(psl->bone_envelope[0]);
+
+ if (stl->g_data->transparent_bones) {
+ /* For performance reason, avoid blending on MS target. */
+ DRW_draw_pass(psl->bone_solid[0]);
+ }
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
+
+ if (!stl->g_data->transparent_bones) {
+ DRW_draw_pass(psl->bone_solid[0]);
+ }
+
+ DRW_draw_pass(psl->bone_outline[0]);
+ DRW_draw_pass(psl->bone_wire[0]);
+ DRW_draw_pass(psl->relationship[0]);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
+
+ if (!DRW_pass_is_empty(psl->bone_envelope[1]) ||
+ !DRW_pass_is_empty(psl->bone_solid[1]) ||
+ !DRW_pass_is_empty(psl->bone_outline[1]) ||
+ !DRW_pass_is_empty(psl->bone_wire[1]) ||
+ !DRW_pass_is_empty(psl->relationship[1]))
+ {
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
+ }
+
+ DRW_draw_pass(psl->bone_envelope[1]);
+ DRW_draw_pass(psl->bone_solid[1]);
+ DRW_draw_pass(psl->bone_outline[1]);
+ DRW_draw_pass(psl->bone_wire[1]);
+ DRW_draw_pass(psl->relationship[1]);
+ }
+
+ /* Draw axes with linesmooth and outside of multisample buffer. */
+ DRW_draw_pass(psl->bone_axes);
+}
+
+static const DrawEngineDataSize EDIT_ARMATURE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_ARMATURE_Data);
+
+DrawEngineType draw_engine_edit_armature_type = {
+ NULL, NULL,
+ N_("EditArmatureMode"),
+ &EDIT_ARMATURE_data_size,
+ NULL,
+ NULL,
+ &EDIT_ARMATURE_cache_init,
+ &EDIT_ARMATURE_cache_populate,
+ NULL,
+ NULL,
+ &EDIT_ARMATURE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
new file mode 100644
index 00000000000..3d716d77405
--- /dev/null
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_curve_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_object.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_batch.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[];
+extern char datatoc_edit_curve_overlay_handle_vert_glsl[];
+extern char datatoc_edit_curve_overlay_handle_geom_glsl[];
+
+extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_CURVE_engine_init() to
+ * initialize most of them and EDIT_CURVE_cache_init()
+ * for EDIT_CURVE_PassList */
+
+typedef struct EDIT_CURVE_PassList {
+ struct DRWPass *wire_pass;
+ struct DRWPass *overlay_edge_pass;
+ struct DRWPass *overlay_vert_pass;
+} EDIT_CURVE_PassList;
+
+typedef struct EDIT_CURVE_StorageList {
+ struct CustomStruct *block;
+ struct EDIT_CURVE_PrivateData *g_data;
+} EDIT_CURVE_StorageList;
+
+typedef struct EDIT_CURVE_Data {
+ void *engine_type; /* Required */
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ EDIT_CURVE_PassList *psl;
+ EDIT_CURVE_StorageList *stl;
+} EDIT_CURVE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ GPUShader *wire_sh;
+ GPUShader *overlay_edge_sh; /* handles and nurbs control cage */
+ GPUShader *overlay_vert_sh;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_CURVE_PrivateData {
+ /* resulting curve as 'wire' for curves (and optionally normals) */
+ DRWShadingGroup *wire_shgrp;
+
+ DRWShadingGroup *overlay_edge_shgrp;
+ DRWShadingGroup *overlay_vert_shgrp;
+
+ int show_handles;
+} EDIT_CURVE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_CURVE_engine_init(void *UNUSED(vedata))
+{
+ if (!e_data.wire_sh) {
+ e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!e_data.overlay_edge_sh) {
+ e_data.overlay_edge_sh = DRW_shader_create_with_lib(
+ datatoc_edit_curve_overlay_handle_vert_glsl,
+ datatoc_edit_curve_overlay_handle_geom_glsl,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+
+ if (!e_data.overlay_vert_sh) {
+ e_data.overlay_vert_sh = DRW_shader_create_with_lib(
+ datatoc_edit_curve_overlay_loosevert_vert_glsl, NULL,
+ datatoc_gpu_shader_point_varying_color_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_CURVE_cache_init(void *vedata)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+
+ stl->g_data->show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+
+ {
+ DRWShadingGroup *grp;
+
+ /* Center-Line (wire) */
+ psl->wire_pass = DRW_pass_create(
+ "Curve Wire",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE);
+
+ grp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorWireEdit, 1);
+ stl->g_data->wire_shgrp = grp;
+
+ psl->overlay_edge_pass = DRW_pass_create(
+ "Curve Handle Overlay",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
+
+ grp = DRW_shgroup_create(e_data.overlay_edge_sh, psl->overlay_edge_pass);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_bool(grp, "showCurveHandles", &stl->g_data->show_handles, 1);
+ stl->g_data->overlay_edge_shgrp = grp;
+
+
+ psl->overlay_vert_pass = DRW_pass_create(
+ "Curve Vert Overlay",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_POINT);
+
+ grp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ stl->g_data->overlay_vert_shgrp = grp;
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ if (ob->type == OB_CURVE) {
+ if (BKE_object_is_in_editmode(ob)) {
+ Curve *cu = ob->data;
+ /* Get geometry cache */
+ struct GPUBatch *geom;
+
+ geom = DRW_cache_curve_edge_wire_get(ob);
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+
+ if ((cu->flag & CU_3D) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0) {
+ geom = DRW_cache_curve_edge_normal_get(ob, v3d->overlay.normals_length);
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+ }
+
+ geom = DRW_cache_curve_edge_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(stl->g_data->overlay_edge_shgrp, geom, ob->obmat);
+ }
+
+ geom = DRW_cache_curve_vert_overlay_get(ob, stl->g_data->show_handles);
+ DRW_shgroup_call_add(stl->g_data->overlay_vert_shgrp, geom, ob->obmat);
+ }
+ }
+
+ if (ob->type == OB_SURF) {
+ if (BKE_object_is_in_editmode(ob)) {
+ struct GPUBatch *geom = DRW_cache_curve_edge_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->overlay_edge_shgrp, geom, ob->obmat);
+
+ geom = DRW_cache_curve_vert_overlay_get(ob, false);
+ DRW_shgroup_call_add(stl->g_data->overlay_vert_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_CURVE_draw_scene(void *vedata)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ if (!DRW_pass_is_empty(psl->wire_pass)) {
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
+
+ DRW_draw_pass(psl->wire_pass);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl)
+ }
+
+ /* Thoses passes don't write to depth and are AA'ed using other tricks. */
+ DRW_draw_pass(psl->overlay_edge_pass);
+ DRW_draw_pass(psl->overlay_vert_pass);
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_CURVE_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.overlay_edge_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh);
+}
+
+static const DrawEngineDataSize EDIT_CURVE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_CURVE_Data);
+
+DrawEngineType draw_engine_edit_curve_type = {
+ NULL, NULL,
+ N_("EditCurveMode"),
+ &EDIT_CURVE_data_size,
+ &EDIT_CURVE_engine_init,
+ &EDIT_CURVE_engine_free,
+ &EDIT_CURVE_cache_init,
+ &EDIT_CURVE_cache_populate,
+ NULL,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_CURVE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c
new file mode 100644
index 00000000000..1d4d4cd8362
--- /dev/null
+++ b/source/blender/draw/modes/edit_lattice_mode.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_lattice_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_object.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_edit_lattice_overlay_loosevert_vert_glsl[];
+extern char datatoc_edit_lattice_overlay_frag_glsl[];
+
+extern char datatoc_gpu_shader_3D_vert_glsl[];
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_LATTICE_engine_init() to
+ * initialize most of them and EDIT_LATTICE_cache_init()
+ * for EDIT_LATTICE_PassList */
+
+typedef struct EDIT_LATTICE_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_LATTICE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *wire_pass;
+ struct DRWPass *vert_pass;
+} EDIT_LATTICE_PassList;
+
+typedef struct EDIT_LATTICE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_LATTICE_FramebufferList;
+
+typedef struct EDIT_LATTICE_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} EDIT_LATTICE_TextureList;
+
+typedef struct EDIT_LATTICE_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct EDIT_LATTICE_PrivateData *g_data;
+} EDIT_LATTICE_StorageList;
+
+typedef struct EDIT_LATTICE_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_LATTICE_FramebufferList *fbl;
+ EDIT_LATTICE_TextureList *txl;
+ EDIT_LATTICE_PassList *psl;
+ EDIT_LATTICE_StorageList *stl;
+} EDIT_LATTICE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_LATTICE_engine_init();
+ * free in EDIT_LATTICE_engine_free(); */
+ GPUShader *wire_sh;
+
+ GPUShader *overlay_vert_sh;
+
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_LATTICE_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in EDIT_LATTICE_cache_populate() */
+ DRWShadingGroup *wire_shgrp;
+ DRWShadingGroup *vert_shgrp;
+} EDIT_LATTICE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_LATTICE_engine_init(void *vedata)
+{
+ EDIT_LATTICE_TextureList *txl = ((EDIT_LATTICE_Data *)vedata)->txl;
+ EDIT_LATTICE_FramebufferList *fbl = ((EDIT_LATTICE_Data *)vedata)->fbl;
+ EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.wire_sh) {
+ e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
+ }
+
+ if (!e_data.overlay_vert_sh) {
+ e_data.overlay_vert_sh = DRW_shader_create_with_lib(
+ datatoc_edit_lattice_overlay_loosevert_vert_glsl, NULL,
+ datatoc_edit_lattice_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_LATTICE_cache_init(void *vedata)
+{
+ EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
+ EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ psl->wire_pass = DRW_pass_create(
+ "Lattice Wire",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE);
+ stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+
+ psl->vert_pass = DRW_pass_create(
+ "Lattice Verts",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_POINT);
+ stl->g_data->vert_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->vert_pass);
+
+ DRW_shgroup_uniform_block(stl->g_data->vert_shgrp, "globalsBlock", globals_ubo);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_LATTICE_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
+ EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ UNUSED_VARS(psl);
+
+ if (ob->type == OB_LATTICE) {
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
+ /* Get geometry cache */
+ struct GPUBatch *geom;
+
+ geom = DRW_cache_lattice_wire_get(ob, true);
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+
+ geom = DRW_cache_lattice_vert_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->vert_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_LATTICE_cache_finish(void *vedata)
+{
+ EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
+ EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
+
+ /* Do something here! dependent on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_LATTICE_draw_scene(void *vedata)
+{
+ EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
+ EDIT_LATTICE_FramebufferList *fbl = ((EDIT_LATTICE_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl);
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
+
+ /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
+ /*
+ * DRW_framebuffer_texture_detach(dtxl->depth);
+ * DRW_framebuffer_bind(fbl->custom_fb);
+ * DRW_draw_pass(psl->pass);
+ * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ * DRW_framebuffer_bind(dfbl->default_fb);
+ */
+
+ /* ... or just render passes on default framebuffer. */
+ DRW_draw_pass(psl->wire_pass);
+ DRW_draw_pass(psl->vert_pass);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl)
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_LATTICE_engine_free(void)
+{
+ // Currently built-in, dont free
+ DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh);
+}
+
+static const DrawEngineDataSize EDIT_LATTICE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_LATTICE_Data);
+
+DrawEngineType draw_engine_edit_lattice_type = {
+ NULL, NULL,
+ N_("EditLatticeMode"),
+ &EDIT_LATTICE_data_size,
+ &EDIT_LATTICE_engine_init,
+ &EDIT_LATTICE_engine_free,
+ &EDIT_LATTICE_cache_init,
+ &EDIT_LATTICE_cache_populate,
+ &EDIT_LATTICE_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_LATTICE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
new file mode 100644
index 00000000000..834a0c0be0b
--- /dev/null
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -0,0 +1,804 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_mesh_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
+
+#include "draw_common.h"
+
+#include "draw_cache_impl.h"
+#include "draw_mode_engines.h"
+
+#include "edit_mesh_mode_intern.h" /* own include */
+
+#include "BKE_object.h"
+
+#include "BLI_dynstr.h"
+
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern struct GPUTexture *globals_weight_ramp; /* draw_common.c */
+
+extern char datatoc_paint_weight_vert_glsl[];
+extern char datatoc_paint_weight_frag_glsl[];
+
+extern char datatoc_edit_mesh_overlay_common_lib_glsl[];
+extern char datatoc_edit_mesh_overlay_frag_glsl[];
+extern char datatoc_edit_mesh_overlay_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_geom_tri_glsl[];
+extern char datatoc_edit_mesh_overlay_geom_edge_glsl[];
+extern char datatoc_edit_mesh_overlay_points_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_facedot_frag_glsl[];
+extern char datatoc_edit_mesh_overlay_facedot_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_ghost_clear_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_mix_frag_glsl[];
+extern char datatoc_edit_mesh_overlay_facefill_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_facefill_frag_glsl[];
+extern char datatoc_edit_normals_vert_glsl[];
+extern char datatoc_edit_normals_geom_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+typedef struct EDIT_MESH_PassList {
+ struct DRWPass *weight_faces;
+ struct DRWPass *depth_hidden_wire;
+ struct DRWPass *ghost_clear_depth;
+ struct DRWPass *edit_face_overlay;
+ struct DRWPass *edit_face_occluded;
+ struct DRWPass *mix_occlude;
+ struct DRWPass *facefill_occlude;
+ struct DRWPass *normals;
+} EDIT_MESH_PassList;
+
+typedef struct EDIT_MESH_FramebufferList {
+ struct GPUFrameBuffer *occlude_wire_fb;
+ struct GPUFrameBuffer *ghost_wire_fb;
+} EDIT_MESH_FramebufferList;
+
+typedef struct EDIT_MESH_StorageList {
+ struct EDIT_MESH_PrivateData *g_data;
+} EDIT_MESH_StorageList;
+
+typedef struct EDIT_MESH_Data {
+ void *engine_type;
+ EDIT_MESH_FramebufferList *fbl;
+ DRWViewportEmptyList *txl;
+ EDIT_MESH_PassList *psl;
+ EDIT_MESH_StorageList *stl;
+} EDIT_MESH_Data;
+
+/* *********** STATIC *********** */
+#define MAX_SHADERS 16
+
+static struct {
+ /* weight */
+ GPUShader *weight_face_shader;
+
+ /* Geometry */
+ GPUShader *overlay_tri_sh_cache[MAX_SHADERS];
+ GPUShader *overlay_loose_edge_sh_cache[MAX_SHADERS];
+
+ GPUShader *overlay_vert_sh;
+ GPUShader *overlay_lvert_sh;
+ GPUShader *overlay_facedot_sh;
+ GPUShader *overlay_mix_sh;
+ GPUShader *overlay_facefill_sh;
+ GPUShader *normals_face_sh;
+ GPUShader *normals_loop_sh;
+ GPUShader *normals_sh;
+ GPUShader *depth_sh;
+ GPUShader *ghost_clear_depth_sh;
+ /* temp buffer texture */
+ struct GPUTexture *occlude_wire_depth_tx;
+ struct GPUTexture *occlude_wire_color_tx;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_MESH_PrivateData {
+ /* weight */
+ DRWShadingGroup *fweights_shgrp;
+ DRWShadingGroup *depth_shgrp_hidden_wire;
+
+ DRWShadingGroup *fnormals_shgrp;
+ DRWShadingGroup *vnormals_shgrp;
+ DRWShadingGroup *lnormals_shgrp;
+
+ DRWShadingGroup *face_overlay_shgrp;
+ DRWShadingGroup *verts_overlay_shgrp;
+ DRWShadingGroup *ledges_overlay_shgrp;
+ DRWShadingGroup *lverts_overlay_shgrp;
+ DRWShadingGroup *facedot_overlay_shgrp;
+
+ DRWShadingGroup *face_occluded_shgrp;
+ DRWShadingGroup *verts_occluded_shgrp;
+ DRWShadingGroup *ledges_occluded_shgrp;
+ DRWShadingGroup *lverts_occluded_shgrp;
+ DRWShadingGroup *facedot_occluded_shgrp;
+ DRWShadingGroup *facefill_occluded_shgrp;
+
+ int data_mask[4];
+ int ghost_ob;
+ int edit_ob;
+ bool do_zbufclip;
+ bool do_faces;
+ bool do_edges;
+ float edge_width_scale;
+} EDIT_MESH_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+static int EDIT_MESH_sh_index(ToolSettings *tsettings, RegionView3D *rv3d, bool supports_fast_mode)
+{
+ int result = tsettings->selectmode << 1;
+ if (supports_fast_mode) {
+ SET_FLAG_FROM_TEST(result, (rv3d->rflag & RV3D_NAVIGATING), 1 << 0);
+ }
+ return result;
+}
+
+static char *EDIT_MESH_sh_defines(ToolSettings *tsettings, RegionView3D *rv3d, bool anti_alias, bool looseedge)
+{
+ const int selectmode = tsettings->selectmode;
+ const int fast_mode = rv3d->rflag & RV3D_NAVIGATING;
+
+ char *str = NULL;
+ DynStr *ds = BLI_dynstr_new();
+
+ if (selectmode & SCE_SELECT_VERTEX) {
+ BLI_dynstr_append(ds, "#define VERTEX_SELECTION\n");
+ }
+
+ if (selectmode & SCE_SELECT_EDGE) {
+ BLI_dynstr_append(ds, "#define EDGE_SELECTION\n");
+ }
+
+ if (selectmode & SCE_SELECT_FACE) {
+ BLI_dynstr_append(ds, "#define FACE_SELECTION\n");
+ }
+
+ if (!fast_mode || looseedge) {
+ BLI_dynstr_append(ds, "#define EDGE_FIX\n");
+ }
+
+ if (anti_alias) {
+ BLI_dynstr_append(ds, "#define ANTI_ALIASING\n");
+ }
+
+ if (!looseedge) {
+ BLI_dynstr_append(ds, "#define VERTEX_FACING\n");
+ }
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+static char *EDIT_MESH_sh_lib(void)
+{
+ char *str = NULL;
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_common_globals_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_edit_mesh_overlay_common_lib_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static GPUShader *EDIT_MESH_ensure_shader(
+ ToolSettings *tsettings, RegionView3D *rv3d, bool supports_fast_mode, bool looseedge)
+{
+ const int index = EDIT_MESH_sh_index(tsettings, rv3d, supports_fast_mode);
+ const int fast_mode = rv3d->rflag & RV3D_NAVIGATING;
+ if (looseedge) {
+ if (!e_data.overlay_loose_edge_sh_cache[index]) {
+ char *defines = EDIT_MESH_sh_defines(tsettings, rv3d, true, true);
+ char *lib = EDIT_MESH_sh_lib();
+ e_data.overlay_loose_edge_sh_cache[index] = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_edge_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ lib,
+ defines);
+ MEM_freeN(lib);
+ MEM_freeN(defines);
+ }
+ return e_data.overlay_loose_edge_sh_cache[index];
+ }
+ else {
+ if (!e_data.overlay_tri_sh_cache[index]) {
+ char *defines = EDIT_MESH_sh_defines(tsettings, rv3d, true, false);
+ char *lib = EDIT_MESH_sh_lib();
+ e_data.overlay_tri_sh_cache[index] = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ fast_mode ? NULL : datatoc_edit_mesh_overlay_geom_tri_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ lib,
+ defines);
+ MEM_freeN(lib);
+ MEM_freeN(defines);
+ }
+ return e_data.overlay_tri_sh_cache[index];
+ }
+}
+
+static void EDIT_MESH_engine_init(void *vedata)
+{
+ EDIT_MESH_FramebufferList *fbl = ((EDIT_MESH_Data *)vedata)->fbl;
+
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ e_data.occlude_wire_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH_COMPONENT24,
+ &draw_engine_edit_mesh_type);
+ e_data.occlude_wire_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8,
+ &draw_engine_edit_mesh_type);
+
+ GPU_framebuffer_ensure_config(&fbl->occlude_wire_fb, {
+ GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_color_tx)
+ });
+
+ if (!e_data.weight_face_shader) {
+ e_data.weight_face_shader = DRW_shader_create_with_lib(
+ datatoc_paint_weight_vert_glsl, NULL,
+ datatoc_paint_weight_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+
+ if (!e_data.overlay_vert_sh) {
+ char *lib = EDIT_MESH_sh_lib();
+ e_data.overlay_vert_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_points_vert_glsl, NULL,
+ datatoc_gpu_shader_point_varying_color_frag_glsl, lib,
+ "#define VERTEX_FACING\n");
+ e_data.overlay_lvert_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_points_vert_glsl, NULL,
+ datatoc_gpu_shader_point_varying_color_frag_glsl, lib,
+ NULL);
+ MEM_freeN(lib);
+ }
+ if (!e_data.overlay_facedot_sh) {
+ e_data.overlay_facedot_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_facedot_vert_glsl, NULL,
+ datatoc_edit_mesh_overlay_facedot_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define VERTEX_FACING\n");
+ }
+ if (!e_data.overlay_mix_sh) {
+ e_data.overlay_mix_sh = DRW_shader_create_fullscreen(datatoc_edit_mesh_overlay_mix_frag_glsl, NULL);
+ }
+ if (!e_data.overlay_facefill_sh) {
+ e_data.overlay_facefill_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_facefill_vert_glsl, NULL,
+ datatoc_edit_mesh_overlay_facefill_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+ if (!e_data.normals_face_sh) {
+ e_data.normals_face_sh = DRW_shader_create(
+ datatoc_edit_normals_vert_glsl,
+ datatoc_edit_normals_geom_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl,
+ "#define FACE_NORMALS\n");
+ }
+ if (!e_data.normals_loop_sh) {
+ e_data.normals_loop_sh = DRW_shader_create(
+ datatoc_edit_normals_vert_glsl,
+ datatoc_edit_normals_geom_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl,
+ "#define LOOP_NORMALS\n");
+ }
+ if (!e_data.normals_sh) {
+ e_data.normals_sh = DRW_shader_create(
+ datatoc_edit_normals_vert_glsl,
+ datatoc_edit_normals_geom_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl, NULL);
+ }
+ if (!e_data.depth_sh) {
+ e_data.depth_sh = DRW_shader_create_3D_depth_only();
+ }
+ if (!e_data.ghost_clear_depth_sh) {
+ e_data.ghost_clear_depth_sh = DRW_shader_create(datatoc_edit_mesh_overlay_ghost_clear_vert_glsl,
+ NULL, NULL, NULL);
+ }
+
+}
+
+static DRWPass *edit_mesh_create_overlay_pass(
+ float *face_alpha, float *edge_width_scale, int *data_mask, bool do_edges, bool xray,
+ DRWState statemod,
+ DRWShadingGroup **r_face_shgrp, DRWShadingGroup **r_verts_shgrp, DRWShadingGroup **r_ledges_shgrp,
+ DRWShadingGroup **r_lverts_shgrp, DRWShadingGroup **r_facedot_shgrp)
+{
+ GPUShader *tri_sh, *ledge_sh;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *tsettings = scene->toolsettings;
+ const int fast_mode = rv3d->rflag & RV3D_NAVIGATING;
+
+ ledge_sh = EDIT_MESH_ensure_shader(tsettings, rv3d, false, true);
+ tri_sh = EDIT_MESH_ensure_shader(tsettings, rv3d, true, false);
+
+ DRWPass *pass = DRW_pass_create(
+ "Edit Mesh Face Overlay Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_POINT | statemod);
+
+ if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) {
+ *r_lverts_shgrp = DRW_shgroup_create(e_data.overlay_lvert_sh, pass);
+ DRW_shgroup_uniform_block(*r_lverts_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(*r_lverts_shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_float(*r_lverts_shgrp, "edgeScale", edge_width_scale, 1);
+ DRW_shgroup_state_enable(*r_lverts_shgrp, DRW_STATE_WRITE_DEPTH);
+
+ *r_verts_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, pass);
+ DRW_shgroup_uniform_block(*r_verts_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(*r_verts_shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_float(*r_verts_shgrp, "edgeScale", edge_width_scale, 1);
+ DRW_shgroup_state_enable(*r_verts_shgrp, DRW_STATE_WRITE_DEPTH);
+ }
+
+ if ((tsettings->selectmode & SCE_SELECT_FACE) != 0) {
+ *r_facedot_shgrp = DRW_shgroup_create(e_data.overlay_facedot_sh, pass);
+ DRW_shgroup_uniform_block(*r_facedot_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_float(*r_facedot_shgrp, "edgeScale", edge_width_scale, 1);
+ DRW_shgroup_state_enable(*r_facedot_shgrp, DRW_STATE_WRITE_DEPTH);
+ }
+
+ *r_face_shgrp = DRW_shgroup_create(tri_sh, pass);
+ DRW_shgroup_uniform_block(*r_face_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(*r_face_shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_float(*r_face_shgrp, "faceAlphaMod", face_alpha, 1);
+ DRW_shgroup_uniform_float(*r_face_shgrp, "edgeScale", edge_width_scale, 1);
+ DRW_shgroup_uniform_ivec4(*r_face_shgrp, "dataMask", data_mask, 1);
+ DRW_shgroup_uniform_bool_copy(*r_face_shgrp, "doEdges", do_edges);
+ if (!fast_mode) {
+ DRW_shgroup_uniform_bool_copy(*r_face_shgrp, "isXray", xray);
+ }
+
+ *r_ledges_shgrp = DRW_shgroup_create(ledge_sh, pass);
+ DRW_shgroup_uniform_block(*r_ledges_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(*r_ledges_shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_float(*r_ledges_shgrp, "edgeScale", edge_width_scale, 1);
+ DRW_shgroup_uniform_ivec4(*r_ledges_shgrp, "dataMask", data_mask, 1);
+ DRW_shgroup_uniform_bool_copy(*r_ledges_shgrp, "doEdges", do_edges);
+
+ return pass;
+}
+
+static float backwire_opacity;
+static float face_mod;
+static float size_normal;
+
+static void EDIT_MESH_cache_init(void *vedata)
+{
+ EDIT_MESH_PassList *psl = ((EDIT_MESH_Data *)vedata)->psl;
+ EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *tsettings = scene->toolsettings;
+
+ static float zero = 0.0f;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+ stl->g_data->ghost_ob = 0;
+ stl->g_data->edit_ob = 0;
+ stl->g_data->do_faces = true;
+ stl->g_data->do_edges = true;
+
+ stl->g_data->do_zbufclip = ((v3d)->shading.flag & XRAY_FLAG(v3d)) != 0;
+
+ /* Applies on top of the theme edge width, so edge-mode can have thick edges. */
+ stl->g_data->edge_width_scale = (tsettings->selectmode & (SCE_SELECT_EDGE)) ? 1.75f : 1.0f;
+
+ stl->g_data->data_mask[0] = 0xFF; /* Face Flag */
+ stl->g_data->data_mask[1] = 0xFF; /* Edge Flag */
+ stl->g_data->data_mask[2] = 0xFF; /* Crease */
+ stl->g_data->data_mask[3] = 0xFF; /* BWeight */
+
+ if (draw_ctx->object_edit->type == OB_MESH) {
+ if (BKE_object_is_in_editmode(draw_ctx->object_edit)) {
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FREESTYLE_FACE) == 0) {
+ stl->g_data->data_mask[0] &= ~VFLAG_FACE_FREESTYLE;
+ }
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACES) == 0) {
+ stl->g_data->data_mask[0] &= ~(VFLAG_FACE_SELECTED & VFLAG_FACE_FREESTYLE);
+ stl->g_data->do_faces = false;
+ }
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_SEAMS) == 0) {
+ stl->g_data->data_mask[1] &= ~VFLAG_EDGE_SEAM;
+ }
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_SHARP) == 0) {
+ stl->g_data->data_mask[1] &= ~VFLAG_EDGE_SHARP;
+ }
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FREESTYLE_EDGE) == 0) {
+ stl->g_data->data_mask[1] &= ~VFLAG_EDGE_FREESTYLE;
+ }
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGES) == 0) {
+ if ((tsettings->selectmode & SCE_SELECT_EDGE) == 0) {
+ stl->g_data->data_mask[1] &= ~(VFLAG_EDGE_ACTIVE & VFLAG_EDGE_SELECTED);
+ stl->g_data->do_edges = false;
+ }
+ }
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CREASES) == 0) {
+ stl->g_data->data_mask[2] = 0x0;
+ }
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_BWEIGHTS) == 0) {
+ stl->g_data->data_mask[3] = 0x0;
+ }
+ }
+ }
+
+ {
+ psl->weight_faces = DRW_pass_create(
+ "Weight Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->fweights_shgrp = DRW_shgroup_create(e_data.weight_face_shader, psl->weight_faces);
+
+ static float alpha = 1.0f;
+ DRW_shgroup_uniform_float(stl->g_data->fweights_shgrp, "opacity", &alpha, 1);
+ DRW_shgroup_uniform_texture(stl->g_data->fweights_shgrp, "colorramp", globals_weight_ramp);
+ DRW_shgroup_uniform_block(stl->g_data->fweights_shgrp, "globalsBlock", globals_ubo);
+ }
+
+ {
+ /* Complementary Depth Pass */
+ psl->depth_hidden_wire = DRW_pass_create(
+ "Depth Pass Hidden Wire",
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK);
+ stl->g_data->depth_shgrp_hidden_wire = DRW_shgroup_create(e_data.depth_sh, psl->depth_hidden_wire);
+ }
+
+ {
+ /* Depth clearing for ghosting. */
+ psl->ghost_clear_depth = DRW_pass_create(
+ "Ghost Depth Clear",
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_STENCIL_NEQUAL);
+
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.ghost_clear_depth_sh, psl->ghost_clear_depth);
+ DRW_shgroup_stencil_mask(shgrp, 0x00);
+ DRW_shgroup_call_add(shgrp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+
+ {
+ /* Normals */
+ psl->normals = DRW_pass_create(
+ "Edit Mesh Normals Pass",
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->fnormals_shgrp = DRW_shgroup_create(e_data.normals_face_sh, psl->normals);
+ DRW_shgroup_uniform_float(stl->g_data->fnormals_shgrp, "normalSize", &size_normal, 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->fnormals_shgrp, "color", ts.colorNormal, 1);
+
+ stl->g_data->vnormals_shgrp = DRW_shgroup_create(e_data.normals_sh, psl->normals);
+ DRW_shgroup_uniform_float(stl->g_data->vnormals_shgrp, "normalSize", &size_normal, 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->vnormals_shgrp, "color", ts.colorVNormal, 1);
+
+ stl->g_data->lnormals_shgrp = DRW_shgroup_create(e_data.normals_loop_sh, psl->normals);
+ DRW_shgroup_uniform_float(stl->g_data->lnormals_shgrp, "normalSize", &size_normal, 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->lnormals_shgrp, "color", ts.colorLNormal, 1);
+ }
+
+ if (!stl->g_data->do_zbufclip) {
+ psl->edit_face_overlay = edit_mesh_create_overlay_pass(
+ &face_mod, &stl->g_data->edge_width_scale, stl->g_data->data_mask, stl->g_data->do_edges, false,
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND,
+ &stl->g_data->face_overlay_shgrp,
+ &stl->g_data->verts_overlay_shgrp,
+ &stl->g_data->ledges_overlay_shgrp,
+ &stl->g_data->lverts_overlay_shgrp,
+ &stl->g_data->facedot_overlay_shgrp);
+ }
+ else {
+ /* We render all wires with depth and opaque to a new fbo and blend the result based on depth values */
+ psl->edit_face_occluded = edit_mesh_create_overlay_pass(
+ &zero, &stl->g_data->edge_width_scale, stl->g_data->data_mask, stl->g_data->do_edges, true,
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH,
+ &stl->g_data->face_occluded_shgrp,
+ &stl->g_data->verts_occluded_shgrp,
+ &stl->g_data->ledges_occluded_shgrp,
+ &stl->g_data->lverts_occluded_shgrp,
+ &stl->g_data->facedot_occluded_shgrp);
+
+ /* however we loose the front faces value (because we need the depth of occluded wires and
+ * faces are alpha blended ) so we recover them in a new pass. */
+ psl->facefill_occlude = DRW_pass_create(
+ "Front Face Color",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+ stl->g_data->facefill_occluded_shgrp = DRW_shgroup_create(e_data.overlay_facefill_sh, psl->facefill_occlude);
+ DRW_shgroup_uniform_block(stl->g_data->facefill_occluded_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_ivec4(stl->g_data->facefill_occluded_shgrp, "dataMask", stl->g_data->data_mask, 1);
+
+ /* we need a full screen pass to combine the result */
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ psl->mix_occlude = DRW_pass_create(
+ "Mix Occluded Wires",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
+ DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.overlay_mix_sh, psl->mix_occlude);
+ DRW_shgroup_call_add(mix_shgrp, quad, NULL);
+ DRW_shgroup_uniform_float(mix_shgrp, "alpha", &backwire_opacity, 1);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireColor", &e_data.occlude_wire_color_tx);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireDepth", &e_data.occlude_wire_depth_tx);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "sceneDepth", &dtxl->depth);
+ }
+}
+
+static void edit_mesh_add_ob_to_pass(
+ Scene *scene, Object *ob,
+ DRWShadingGroup *face_shgrp,
+ DRWShadingGroup *verts_shgrp,
+ DRWShadingGroup *ledges_shgrp,
+ DRWShadingGroup *lverts_shgrp,
+ DRWShadingGroup *facedot_shgrp,
+ DRWShadingGroup *facefill_shgrp)
+{
+ struct GPUBatch *geo_ovl_tris, *geo_ovl_verts, *geo_ovl_lnor, *geo_ovl_ledges, *geo_ovl_lverts, *geo_ovl_fcenter;
+ struct GPUTexture *data_texture;
+ ToolSettings *tsettings = scene->toolsettings;
+
+ DRW_cache_mesh_wire_overlay_get(ob, &geo_ovl_tris, &geo_ovl_ledges, &geo_ovl_lverts, &data_texture);
+
+ face_shgrp = DRW_shgroup_create_sub(face_shgrp);
+ DRW_shgroup_uniform_texture(face_shgrp, "dataBuffer", data_texture);
+ DRW_shgroup_call_add(face_shgrp, geo_ovl_tris, ob->obmat);
+
+ DRW_shgroup_call_add(ledges_shgrp, geo_ovl_ledges, ob->obmat);
+
+ if (facefill_shgrp) {
+ DRW_shgroup_call_add(facefill_shgrp, geo_ovl_tris, ob->obmat);
+ }
+
+ if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) {
+ /* Thoses are point batches. */
+ DRW_cache_mesh_normals_overlay_get(ob, &geo_ovl_verts, &geo_ovl_lnor, &geo_ovl_ledges, &geo_ovl_lverts);
+ DRW_shgroup_call_add(verts_shgrp, geo_ovl_verts, ob->obmat);
+ DRW_shgroup_call_add(lverts_shgrp, geo_ovl_ledges, ob->obmat);
+ DRW_shgroup_call_add(lverts_shgrp, geo_ovl_lverts, ob->obmat);
+ }
+
+ if (facedot_shgrp && (tsettings->selectmode & SCE_SELECT_FACE) != 0 ) {
+ geo_ovl_fcenter = DRW_cache_face_centers_get(ob);
+ DRW_shgroup_call_add(facedot_shgrp, geo_ovl_fcenter, ob->obmat);
+ }
+}
+
+static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *tsettings = scene->toolsettings;
+ struct GPUBatch *geom;
+
+ if (ob->type == OB_MESH) {
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
+ bool do_occlude_wire = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
+ bool do_show_weight = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT) != 0;
+ bool fnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_NORMALS) != 0;
+ bool vnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_VERT_NORMALS) != 0;
+ bool lnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_LOOP_NORMALS) != 0;
+
+ bool show_face_dots = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) != 0;
+
+ if (stl->g_data->do_faces == false &&
+ stl->g_data->do_edges == false &&
+ (tsettings->selectmode & SCE_SELECT_FACE))
+ {
+ /* Force display of face centers in this case because that's
+ * the only way to see if a face is selected. */
+ show_face_dots = true;
+ }
+
+ /* Updating uniform */
+ backwire_opacity = v3d->overlay.backwire_opacity;
+ size_normal = v3d->overlay.normals_length;
+
+ face_mod = (do_occlude_wire) ? 0.0f : 1.0f;
+
+ if (!stl->g_data->do_faces) {
+ face_mod = 0.0f;
+ }
+
+ if (do_show_weight) {
+ geom = DRW_cache_mesh_surface_weights_get(ob, tsettings, false);
+ DRW_shgroup_call_add(stl->g_data->fweights_shgrp, geom, ob->obmat);
+ }
+
+ if (do_occlude_wire) {
+ geom = DRW_cache_mesh_surface_get(ob, false);
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp_hidden_wire, geom, ob->obmat);
+ }
+
+ if (fnormals_do) {
+ geom = DRW_cache_face_centers_get(ob);
+ DRW_shgroup_call_add(stl->g_data->fnormals_shgrp, geom, ob->obmat);
+ }
+
+ if (vnormals_do || lnormals_do) {
+ struct GPUBatch *geo_ovl_tris, *geo_ovl_lnor, *geo_ovl_ledges, *geo_ovl_lverts;
+ DRW_cache_mesh_normals_overlay_get(ob, &geo_ovl_tris, &geo_ovl_lnor, &geo_ovl_ledges, &geo_ovl_lverts);
+
+ if (vnormals_do) {
+ DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_tris, ob->obmat);
+ DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_ledges, ob->obmat);
+ DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_lverts, ob->obmat);
+ }
+
+ if (lnormals_do) {
+ DRW_shgroup_call_add(stl->g_data->lnormals_shgrp, geo_ovl_lnor, ob->obmat);
+ }
+ }
+
+ if (stl->g_data->do_zbufclip) {
+ edit_mesh_add_ob_to_pass(
+ scene, ob,
+ stl->g_data->face_occluded_shgrp,
+ stl->g_data->verts_occluded_shgrp,
+ stl->g_data->ledges_occluded_shgrp,
+ stl->g_data->lverts_occluded_shgrp,
+ stl->g_data->facedot_occluded_shgrp,
+ (stl->g_data->do_faces) ? stl->g_data->facefill_occluded_shgrp : NULL);
+ }
+ else {
+ edit_mesh_add_ob_to_pass(
+ scene, ob,
+ stl->g_data->face_overlay_shgrp,
+ stl->g_data->verts_overlay_shgrp,
+ stl->g_data->ledges_overlay_shgrp,
+ stl->g_data->lverts_overlay_shgrp,
+ (show_face_dots) ? stl->g_data->facedot_overlay_shgrp : NULL,
+ NULL);
+ }
+
+ stl->g_data->ghost_ob += (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
+ stl->g_data->edit_ob += 1;
+
+ /* 3D text overlay */
+ if (v3d->overlay.edit_flag & (V3D_OVERLAY_EDIT_EDGE_LEN |
+ V3D_OVERLAY_EDIT_FACE_AREA |
+ V3D_OVERLAY_EDIT_FACE_ANG |
+ V3D_OVERLAY_EDIT_EDGE_ANG |
+ V3D_OVERLAY_EDIT_INDICES))
+ {
+ if (DRW_state_show_text()) {
+ DRW_edit_mesh_mode_text_measure_stats(
+ draw_ctx->ar, v3d, ob, &scene->unit);
+ }
+ }
+ }
+ }
+}
+
+static void EDIT_MESH_draw_scene(void *vedata)
+{
+ EDIT_MESH_PassList *psl = ((EDIT_MESH_Data *)vedata)->psl;
+ EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
+ EDIT_MESH_FramebufferList *fbl = ((EDIT_MESH_Data *)vedata)->fbl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ DRW_draw_pass(psl->weight_faces);
+
+ DRW_draw_pass(psl->depth_hidden_wire);
+
+ if (stl->g_data->do_zbufclip) {
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ /* render facefill */
+ DRW_draw_pass(psl->facefill_occlude);
+
+ /* Render wires on a separate framebuffer */
+ GPU_framebuffer_bind(fbl->occlude_wire_fb);
+ GPU_framebuffer_clear_color_depth(fbl->occlude_wire_fb, clearcol, 1.0f);
+ DRW_draw_pass(psl->normals);
+ DRW_draw_pass(psl->edit_face_occluded);
+
+ /* Combine with scene buffer */
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->mix_occlude);
+ }
+ else {
+ DRW_draw_pass(psl->normals);
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ if (v3d->shading.type == OB_SOLID && (v3d->shading.flag & XRAY_FLAG(v3d)) == 0) {
+ if (stl->g_data->ghost_ob == 1 && stl->g_data->edit_ob == 1) {
+ /* In the case of single ghost object edit (common case for retopology):
+ * we duplicate the depht+stencil buffer and clear all depth to 1.0f where
+ * the stencil buffer is no 0x00. */
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+ struct GPUTexture *ghost_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_edit_mesh_type);
+ GPU_framebuffer_ensure_config(&fbl->ghost_wire_fb, {
+ GPU_ATTACHMENT_TEXTURE(ghost_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color),
+ });
+
+ GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->ghost_wire_fb, 0, GPU_DEPTH_BIT | GPU_STENCIL_BIT);
+ GPU_framebuffer_bind(fbl->ghost_wire_fb);
+
+ DRW_draw_pass(psl->ghost_clear_depth);
+ }
+ }
+
+ DRW_draw_pass(psl->edit_face_overlay);
+ }
+}
+
+static void EDIT_MESH_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.weight_face_shader);
+
+ DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_lvert_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_facedot_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_mix_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_facefill_sh);
+ DRW_SHADER_FREE_SAFE(e_data.normals_loop_sh);
+ DRW_SHADER_FREE_SAFE(e_data.normals_face_sh);
+ DRW_SHADER_FREE_SAFE(e_data.normals_sh);
+ DRW_SHADER_FREE_SAFE(e_data.ghost_clear_depth_sh);
+
+ for (int i = 0; i < MAX_SHADERS; i++) {
+ DRW_SHADER_FREE_SAFE(e_data.overlay_tri_sh_cache[i]);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_loose_edge_sh_cache[i]);
+ }
+}
+
+static const DrawEngineDataSize EDIT_MESH_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_MESH_Data);
+
+DrawEngineType draw_engine_edit_mesh_type = {
+ NULL, NULL,
+ N_("EditMeshMode"),
+ &EDIT_MESH_data_size,
+ &EDIT_MESH_engine_init,
+ &EDIT_MESH_engine_free,
+ &EDIT_MESH_cache_init,
+ &EDIT_MESH_cache_populate,
+ NULL,
+ NULL,
+ &EDIT_MESH_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_mesh_mode_intern.h b/source/blender/draw/modes/edit_mesh_mode_intern.h
new file mode 100644
index 00000000000..99298bd41f4
--- /dev/null
+++ b/source/blender/draw/modes/edit_mesh_mode_intern.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/draw/modes/edit_mesh_mode_intern.h
+ * \ingroup draw
+ */
+
+#ifndef __EDIT_MESH_MODE_INTERN_H__
+#define __EDIT_MESH_MODE_INTERN_H__
+
+struct ARegion;
+struct Object;
+struct UnitSettings;
+struct View3D;
+
+/* edit_mesh_mode_text.c */
+void DRW_edit_mesh_mode_text_measure_stats(
+ struct ARegion *ar, struct View3D *v3d,
+ struct Object *ob, const UnitSettings *unit);
+
+#endif /* __EDIT_MESH_MODE_INTERN_H__ */
diff --git a/source/blender/draw/modes/edit_mesh_mode_text.c b/source/blender/draw/modes/edit_mesh_mode_text.c
new file mode 100644
index 00000000000..d2bfc75a2bf
--- /dev/null
+++ b/source/blender/draw/modes/edit_mesh_mode_text.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_mesh_mode_text.c
+ * \ingroup draw
+ */
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_global.h"
+#include "BKE_unit.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_shader.h"
+#include "GPU_viewport.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "UI_resources.h"
+
+#include "draw_manager_text.h"
+
+#include "edit_mesh_mode_intern.h" /* own include */
+
+/* Copied from drawobject.c */
+void DRW_edit_mesh_mode_text_measure_stats(
+ ARegion *ar, View3D *v3d,
+ Object *ob, const UnitSettings *unit)
+{
+ /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square, etc.).
+ * See bug #36090.
+ */
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ const short txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | (unit->system ? 0 : DRW_TEXT_CACHE_ASCII);
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ float v1[3], v2[3], v3[3], vmid[3], fvec[3];
+ char numstr[32]; /* Stores the measurement display text here */
+ size_t numstr_len;
+ const char *conv_float; /* Use a float conversion matching the grid size */
+ uchar col[4] = {0, 0, 0, 255}; /* color of the text to draw */
+ float area; /* area of the face */
+ float grid = unit->system ? unit->scale_length : v3d->grid;
+ const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0;
+ const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0;
+ /* when 2 edge-info options are enabled, space apart */
+ const bool do_edge_textpair = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) && (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG);
+ const short edge_texpair_sep = (short)(5.0f * U.ui_scale);
+ float clip_planes[4][4];
+ /* allow for displaying shape keys and deform mods */
+ BMIter iter;
+
+ /* make the precision of the display value proportionate to the gridsize */
+
+ if (grid <= 0.01f) conv_float = "%.6g";
+ else if (grid <= 0.1f) conv_float = "%.5g";
+ else if (grid <= 1.0f) conv_float = "%.4g";
+ else if (grid <= 10.0f) conv_float = "%.3g";
+ else conv_float = "%.2g";
+
+ if (v3d->overlay.edit_flag & (V3D_OVERLAY_EDIT_EDGE_LEN | V3D_OVERLAY_EDIT_EDGE_ANG | V3D_OVERLAY_EDIT_INDICES)) {
+ BoundBox bb;
+ const rcti rect = {0, ar->winx, 0, ar->winy};
+
+ ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
+ }
+
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) {
+ BMEdge *eed;
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ /* draw selected edges, or edges next to selected verts while dragging */
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
+ (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
+ {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ mul_m4_v3(ob->obmat, vmid);
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ }
+
+ if (unit->system) {
+ numstr_len = bUnit_AsString2(
+ numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
+ B_UNIT_LENGTH, unit, false);
+ }
+ else {
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
+ }
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0,
+ (do_edge_textpair) ? edge_texpair_sep : 0,
+ txt_flag, col);
+ }
+ }
+ }
+ }
+
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG) {
+ const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
+ BMEdge *eed;
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
+ /* draw selected edges, or edges next to selected verts while dragging */
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
+ (do_moving &&
+ (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
+ /* special case, this is useful to show when verts connected to
+ * this edge via a face are being transformed */
+ BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)
+ )))
+ {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+ float no_a[3], no_b[3];
+ float angle;
+
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ mul_m4_v3(ob->obmat, vmid);
+
+ copy_v3_v3(no_a, l_a->f->no);
+ copy_v3_v3(no_b, l_b->f->no);
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->imat, no_a);
+ mul_mat3_m4_v3(ob->imat, no_b);
+ normalize_v3(no_a);
+ normalize_v3(no_b);
+ }
+
+ angle = angle_normalized_v3v3(no_a, no_b);
+
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%.3f%s", (is_rad) ? angle : RAD2DEGF(angle),
+ (is_rad) ? "r" : "°");
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0,
+ (do_edge_textpair) ? -edge_texpair_sep : 0,
+ txt_flag, col);
+ }
+ }
+ }
+ }
+ }
+
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_AREA) {
+ /* would be nice to use BM_face_calc_area, but that is for 2d faces
+ * so instead add up tessellation triangle areas */
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
+
+ int i, n, numtri;
+ BMFace *f = NULL;
+ BM_ITER_MESH_INDEX(f, &iter, em->bm, BM_FACES_OF_MESH, i) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ n = 0;
+ numtri = f->len - 2;
+ area = 0;
+ zero_v3(vmid);
+ BMLoop *(*l)[3] = &em->looptris[poly_to_tri_count(i, BM_elem_index_get(f->l_first))];
+ for (int j = 0; j < numtri; j++) {
+ copy_v3_v3(v1, l[j][0]->v->co);
+ copy_v3_v3(v2, l[j][1]->v->co);
+ copy_v3_v3(v3, l[j][2]->v->co);
+
+ add_v3_v3(vmid, v1);
+ add_v3_v3(vmid, v2);
+ add_v3_v3(vmid, v3);
+ n += 3;
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ mul_mat3_m4_v3(ob->obmat, v3);
+ }
+
+ area += area_tri_v3(v1, v2, v3);
+ }
+
+ mul_v3_fl(vmid, 1.0f / (float)n);
+ mul_m4_v3(ob->obmat, vmid);
+
+ if (unit->system) {
+ numstr_len = bUnit_AsString2(
+ numstr, sizeof(numstr),
+ (double)(area * unit->scale_length * unit->scale_length),
+ 3, B_UNIT_AREA, unit, false);
+ }
+ else {
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area);
+ }
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_ANG) {
+ BMFace *efa;
+ const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT);
+
+ if (is_face_sel || do_moving) {
+ BMIter liter;
+ BMLoop *loop;
+ bool is_first = true;
+
+ BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (is_face_sel ||
+ (do_moving &&
+ (BM_elem_flag_test(loop->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT))))
+ {
+ float v2_local[3];
+
+ /* lazy init center calc */
+ if (is_first) {
+ BM_face_calc_center_bounds(efa, vmid);
+ is_first = false;
+ }
+ copy_v3_v3(v1, loop->prev->v->co);
+ copy_v3_v3(v2, loop->v->co);
+ copy_v3_v3(v3, loop->next->v->co);
+
+ copy_v3_v3(v2_local, v2);
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ mul_mat3_m4_v3(ob->obmat, v3);
+ }
+
+ float angle = angle_v3v3v3(v1, v2, v3);
+
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%.3f%s", (is_rad) ? angle : RAD2DEGF(angle),
+ (is_rad) ? "r" : "°");
+ interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
+ mul_m4_v3(ob->obmat, fvec);
+ DRW_text_cache_add(dt, fvec, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+ }
+
+ /* This option is for mesh ops and addons debugging; only available in UI if Blender starts with --debug */
+ if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_INDICES) {
+ int i;
+
+ /* For now, reuse an appropriate theme color */
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
+
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *v;
+
+ BM_ITER_MESH_INDEX(v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ float vec[3];
+ mul_v3_m4v3(vec, ob->obmat, v->co);
+
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(dt, vec, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+
+ if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *e;
+
+ BM_ITER_MESH_INDEX(e, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, e->v1->co);
+ copy_v3_v3(v2, e->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ mul_m4_v3(ob->obmat, vmid);
+
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+
+ if (em->selectmode & SCE_SELECT_FACE) {
+ BMFace *f;
+
+ BM_ITER_MESH_INDEX(f, &iter, em->bm, BM_FACES_OF_MESH, i) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_face_calc_center_mean(f, v1);
+ mul_m4_v3(ob->obmat, v1);
+
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c
new file mode 100644
index 00000000000..912c30c1482
--- /dev/null
+++ b/source/blender/draw/modes/edit_metaball_mode.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_metaball_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_meta_types.h"
+
+#include "BKE_object.h"
+#include "BKE_mball.h"
+
+#include "ED_mball.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_select.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_METABALL_engine_init() to
+ * initialize most of them and EDIT_METABALL_cache_init()
+ * for EDIT_METABALL_PassList */
+
+typedef struct EDIT_METABALL_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_METABALL_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *pass;
+} EDIT_METABALL_PassList;
+
+typedef struct EDIT_METABALL_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_METABALL_FramebufferList;
+
+typedef struct EDIT_METABALL_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} EDIT_METABALL_TextureList;
+
+typedef struct EDIT_METABALL_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ // struct CustomStruct *block;
+ struct EDIT_METABALL_PrivateData *g_data;
+} EDIT_METABALL_StorageList;
+
+typedef struct EDIT_METABALL_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_METABALL_FramebufferList *fbl;
+ EDIT_METABALL_TextureList *txl;
+ EDIT_METABALL_PassList *psl;
+ EDIT_METABALL_StorageList *stl;
+} EDIT_METABALL_Data;
+
+/* *********** STATIC *********** */
+
+typedef struct EDIT_METABALL_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in EDIT_METABALL_cache_populate() */
+ DRWShadingGroup *group;
+} EDIT_METABALL_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_METABALL_cache_init(void *vedata)
+{
+ EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
+ EDIT_METABALL_StorageList *stl = ((EDIT_METABALL_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ DRWState state = (
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND | DRW_STATE_WIRE);
+ psl->pass = DRW_pass_create("My Pass", state);
+
+ /* Create a shadingGroup using a function in draw_common.c or custom one */
+ stl->g_data->group = shgroup_instance_mball_handles(psl->pass);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_METABALL_cache_populate(void *vedata, Object *ob)
+{
+ //EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
+ EDIT_METABALL_StorageList *stl = ((EDIT_METABALL_Data *)vedata)->stl;
+
+ if (ob->type == OB_MBALL) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DRWShadingGroup *group = stl->g_data->group;
+
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
+ MetaBall *mb = ob->data;
+
+ const float *color;
+ const float col_radius[3] = {0.63, 0.19, 0.19}; /* 0x3030A0 */
+ const float col_radius_select[3] = {0.94, 0.63, 0.63}; /* 0xA0A0F0 */
+ const float col_stiffness[3] = {0.19, 0.63, 0.19}; /* 0x30A030 */
+ const float col_stiffness_select[3] = {0.63, 0.94, 0.63}; /* 0xA0F0A0 */
+
+ const bool is_select = DRW_state_is_select();
+
+ float draw_scale_xform[3][4]; /* Matrix of Scale and Translation */
+ {
+ float scamat[3][3];
+ copy_m3_m4(scamat, ob->obmat);
+ /* Get the normalized inverse matrix to extract only
+ * the scale of Scamat */
+ float iscamat[3][3];
+ invert_m3_m3(iscamat, scamat);
+ normalize_m3(iscamat);
+ mul_m3_m3_post(scamat, iscamat);
+
+ copy_v3_v3(draw_scale_xform[0], scamat[0]);
+ copy_v3_v3(draw_scale_xform[1], scamat[1]);
+ copy_v3_v3(draw_scale_xform[2], scamat[2]);
+ }
+
+ int selection_id = ob->select_color;
+ for (MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next, selection_id += 0x10000) {
+ float world_pos[3];
+ mul_v3_m4v3(world_pos, ob->obmat, &ml->x);
+ draw_scale_xform[0][3] = world_pos[0];
+ draw_scale_xform[1][3] = world_pos[1];
+ draw_scale_xform[2][3] = world_pos[2];
+
+ float draw_stiffness_radius = ml->rad * atanf(ml->s) / (float)M_PI_2;
+
+ if ((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) color = col_radius_select;
+ else color = col_radius;
+
+ if (is_select) {
+ DRW_select_load_id(selection_id | MBALLSEL_RADIUS);
+ }
+
+ DRW_shgroup_call_dynamic_add(group, draw_scale_xform, &ml->rad, color);
+
+ if ((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) color = col_stiffness_select;
+ else color = col_stiffness;
+
+ if (is_select) {
+ DRW_select_load_id(selection_id | MBALLSEL_STIFF);
+ }
+
+ DRW_shgroup_call_dynamic_add(group, draw_scale_xform, &draw_stiffness_radius, color);
+ }
+ }
+ }
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_METABALL_draw_scene(void *vedata)
+{
+ EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
+ /* render passes on default framebuffer. */
+ DRW_draw_pass(psl->pass);
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_METABALL_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+static const DrawEngineDataSize EDIT_METABALL_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_METABALL_Data);
+
+DrawEngineType draw_engine_edit_metaball_type = {
+ NULL, NULL,
+ N_("EditMetaballMode"),
+ &EDIT_METABALL_data_size,
+ NULL,
+ &EDIT_METABALL_engine_free,
+ &EDIT_METABALL_cache_init,
+ &EDIT_METABALL_cache_populate,
+ NULL,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_METABALL_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c
new file mode 100644
index 00000000000..7d6aa5b560c
--- /dev/null
+++ b/source/blender/draw/modes/edit_text_mode.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_text_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_curve_types.h"
+
+#include "BIF_glutil.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_batch.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_TEXT_engine_init() to
+ * initialize most of them and EDIT_TEXT_cache_init()
+ * for EDIT_TEXT_PassList */
+
+typedef struct EDIT_TEXT_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_TEXT_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *wire_pass;
+ struct DRWPass *overlay_select_pass;
+ struct DRWPass *overlay_cursor_pass;
+ struct DRWPass *text_box_pass;
+} EDIT_TEXT_PassList;
+
+typedef struct EDIT_TEXT_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_TEXT_FramebufferList;
+
+typedef struct EDIT_TEXT_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} EDIT_TEXT_TextureList;
+
+typedef struct EDIT_TEXT_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct EDIT_TEXT_PrivateData *g_data;
+} EDIT_TEXT_StorageList;
+
+typedef struct EDIT_TEXT_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_TEXT_FramebufferList *fbl;
+ EDIT_TEXT_TextureList *txl;
+ EDIT_TEXT_PassList *psl;
+ EDIT_TEXT_StorageList *stl;
+} EDIT_TEXT_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_TEXT_engine_init();
+ * free in EDIT_TEXT_engine_free(); */
+ GPUShader *wire_sh;
+ GPUShader *overlay_select_sh;
+ GPUShader *overlay_cursor_sh;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_TEXT_PrivateData {
+ /* resulting curve as 'wire' for fast editmode drawing */
+ DRWShadingGroup *wire_shgrp;
+ DRWShadingGroup *overlay_select_shgrp;
+ DRWShadingGroup *overlay_cursor_shgrp;
+ DRWShadingGroup *box_shgrp;
+ DRWShadingGroup *box_active_shgrp;
+} EDIT_TEXT_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_TEXT_engine_init(void *vedata)
+{
+ EDIT_TEXT_TextureList *txl = ((EDIT_TEXT_Data *)vedata)->txl;
+ EDIT_TEXT_FramebufferList *fbl = ((EDIT_TEXT_Data *)vedata)->fbl;
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.wire_sh) {
+ e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!e_data.overlay_select_sh) {
+ e_data.overlay_select_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!e_data.overlay_cursor_sh) {
+ e_data.overlay_cursor_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_TEXT_cache_init(void *vedata)
+{
+ EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Text outline (fast drawing!) */
+ psl->wire_pass = DRW_pass_create(
+ "Font Wire",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE);
+ stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+
+ psl->overlay_select_pass = DRW_pass_create(
+ "Font Select",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH);
+ stl->g_data->overlay_select_shgrp = DRW_shgroup_create(e_data.overlay_select_sh, psl->overlay_select_pass);
+
+ psl->overlay_cursor_pass = DRW_pass_create(
+ "Font Cursor",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH);
+ stl->g_data->overlay_cursor_shgrp = DRW_shgroup_create(e_data.overlay_cursor_sh, psl->overlay_cursor_pass);
+
+ psl->text_box_pass = DRW_pass_create(
+ "Font Text Boxes",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH);
+ stl->g_data->box_shgrp = shgroup_dynlines_dashed_uniform_color(psl->text_box_pass, ts.colorWire);
+ stl->g_data->box_active_shgrp = shgroup_dynlines_dashed_uniform_color(psl->text_box_pass, ts.colorActive);
+ }
+}
+
+static void edit_text_cache_populate_boxes(void *vedata, Object *ob)
+{
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+ const Curve *cu = ob->data;
+
+ DRWShadingGroup *shading_groups[] = {
+ stl->g_data->box_active_shgrp,
+ stl->g_data->box_shgrp,
+ };
+
+ float vec[3], vec1[3], vec2[3];
+ for (int i = 0; i < cu->totbox; i++) {
+ TextBox *tb = &cu->tb[i];
+
+ if ((tb->w == 0.0f) && (tb->h == 0.0f)) {
+ continue;
+ }
+
+ const bool is_active = i == (cu->actbox - 1);
+ DRWShadingGroup *shading_group = shading_groups[is_active ? 0 : 1];
+
+ vec[0] = cu->xof + tb->x;
+ vec[1] = cu->yof + tb->y + cu->fsize_realtime;
+ vec[2] = 0.001;
+
+ mul_v3_m4v3(vec1, ob->obmat, vec);
+ vec[0] += tb->w;
+ mul_v3_m4v3(vec2, ob->obmat, vec);
+
+ DRW_shgroup_call_dynamic_add(shading_group, vec1);
+ DRW_shgroup_call_dynamic_add(shading_group, vec2);
+
+ vec[1] -= tb->h;
+ copy_v3_v3(vec1, vec2);
+ mul_v3_m4v3(vec2, ob->obmat, vec);
+
+ DRW_shgroup_call_dynamic_add(shading_group, vec1);
+ DRW_shgroup_call_dynamic_add(shading_group, vec2);
+
+ vec[0] -= tb->w;
+ copy_v3_v3(vec1, vec2);
+ mul_v3_m4v3(vec2, ob->obmat, vec);
+
+ DRW_shgroup_call_dynamic_add(shading_group, vec1);
+ DRW_shgroup_call_dynamic_add(shading_group, vec2);
+
+ vec[1] += tb->h;
+ copy_v3_v3(vec1, vec2);
+ mul_v3_m4v3(vec2, ob->obmat, vec);
+
+ DRW_shgroup_call_dynamic_add(shading_group, vec1);
+ DRW_shgroup_call_dynamic_add(shading_group, vec2);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_TEXT_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_FONT) {
+ if (ob == draw_ctx->object_edit) {
+ const Curve *cu = ob->data;
+ /* Get geometry cache */
+ struct GPUBatch *geom;
+
+ if (cu->flag & CU_FAST) {
+ geom = DRW_cache_text_edge_wire_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+ }
+ }
+ else {
+ /* object mode draws */
+ }
+
+ geom = DRW_cache_text_select_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(stl->g_data->overlay_select_shgrp, geom, ob->obmat);
+ }
+
+ geom = DRW_cache_text_cursor_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(stl->g_data->overlay_cursor_shgrp, geom, ob->obmat);
+ }
+
+ edit_text_cache_populate_boxes(vedata, ob);
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_TEXT_cache_finish(void *vedata)
+{
+ EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+
+ /* Do something here! dependent on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_TEXT_draw_scene(void *vedata)
+{
+ EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
+ EDIT_TEXT_FramebufferList *fbl = ((EDIT_TEXT_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl, dfbl, dtxl);
+
+ /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
+ /*
+ * DRW_framebuffer_texture_detach(dtxl->depth);
+ * DRW_framebuffer_bind(fbl->custom_fb);
+ * DRW_draw_pass(psl->pass);
+ * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ * DRW_framebuffer_bind(dfbl->default_fb);
+ */
+
+ DRW_draw_pass(psl->wire_pass);
+
+ if (!DRW_pass_is_empty(psl->text_box_pass)) {
+ DRW_draw_pass(psl->text_box_pass);
+ }
+
+ set_inverted_drawing(1);
+ DRW_draw_pass(psl->overlay_select_pass);
+ DRW_draw_pass(psl->overlay_cursor_pass);
+ set_inverted_drawing(0);
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_TEXT_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+static const DrawEngineDataSize EDIT_TEXT_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_TEXT_Data);
+
+DrawEngineType draw_engine_edit_text_type = {
+ NULL, NULL,
+ N_("EditTextMode"),
+ &EDIT_TEXT_data_size,
+ &EDIT_TEXT_engine_init,
+ &EDIT_TEXT_engine_free,
+ &EDIT_TEXT_cache_init,
+ &EDIT_TEXT_cache_populate,
+ &EDIT_TEXT_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_TEXT_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
new file mode 100644
index 00000000000..e9455a843f5
--- /dev/null
+++ b/source/blender/draw/modes/object_mode.c
@@ -0,0 +1,2992 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/object_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_userdef_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_smoke_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BIF_gl.h"
+
+#include "BLI_string_utils.h"
+
+#include "BKE_anim.h"
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_movieclip.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_image.h"
+#include "BKE_texture.h"
+#include "BKE_tracking.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "UI_resources.h"
+
+#include "draw_mode_engines.h"
+#include "draw_manager_text.h"
+#include "draw_common.h"
+
+#include "DEG_depsgraph_query.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GPUTexture *globals_ramp; /* draw_common.c */
+extern GlobalsUboStorage ts;
+
+extern char datatoc_object_outline_prepass_vert_glsl[];
+extern char datatoc_object_outline_prepass_geom_glsl[];
+extern char datatoc_object_outline_prepass_frag_glsl[];
+extern char datatoc_object_outline_resolve_frag_glsl[];
+extern char datatoc_object_outline_detect_frag_glsl[];
+extern char datatoc_object_outline_expand_frag_glsl[];
+extern char datatoc_object_grid_frag_glsl[];
+extern char datatoc_object_grid_vert_glsl[];
+extern char datatoc_object_empty_image_frag_glsl[];
+extern char datatoc_object_empty_image_vert_glsl[];
+extern char datatoc_object_lightprobe_grid_vert_glsl[];
+extern char datatoc_object_particle_prim_vert_glsl[];
+extern char datatoc_object_particle_dot_vert_glsl[];
+extern char datatoc_object_particle_dot_frag_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_common_fxaa_lib_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_flat_id_frag_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+typedef struct OBJECT_PassList {
+ struct DRWPass *non_meshes[2];
+ struct DRWPass *image_empties[2];
+ struct DRWPass *spot_shapes[2];
+ struct DRWPass *ob_center;
+ struct DRWPass *outlines;
+ struct DRWPass *outlines_search;
+ struct DRWPass *outlines_expand;
+ struct DRWPass *outlines_bleed;
+ struct DRWPass *outlines_resolve;
+ struct DRWPass *grid;
+ struct DRWPass *bone_solid[2];
+ struct DRWPass *bone_outline[2];
+ struct DRWPass *bone_wire[2];
+ struct DRWPass *bone_envelope[2];
+ struct DRWPass *bone_axes[2];
+ struct DRWPass *particle;
+ struct DRWPass *lightprobes;
+} OBJECT_PassList;
+
+typedef struct OBJECT_FramebufferList {
+ struct GPUFrameBuffer *outlines_fb;
+ struct GPUFrameBuffer *blur_fb;
+ struct GPUFrameBuffer *expand_fb;
+ struct GPUFrameBuffer *ghost_fb;
+} OBJECT_FramebufferList;
+
+typedef struct OBJECT_StorageList {
+ struct OBJECT_PrivateData *g_data;
+} OBJECT_StorageList;
+
+typedef struct OBJECT_Data {
+ void *engine_type;
+ OBJECT_FramebufferList *fbl;
+ DRWViewportEmptyList *txl;
+ OBJECT_PassList *psl;
+ OBJECT_StorageList *stl;
+} OBJECT_Data;
+
+/* *********** STATIC *********** */
+
+typedef struct OBJECT_ShadingGroupList {
+ /* Reference only */
+ struct DRWPass *non_meshes;
+ struct DRWPass *image_empties;
+ struct DRWPass *spot_shapes;
+ struct DRWPass *bone_solid;
+ struct DRWPass *bone_outline;
+ struct DRWPass *bone_wire;
+ struct DRWPass *bone_envelope;
+ struct DRWPass *bone_axes;
+
+ /* Empties */
+ DRWShadingGroup *plain_axes;
+ DRWShadingGroup *cube;
+ DRWShadingGroup *circle;
+ DRWShadingGroup *sphere;
+ DRWShadingGroup *sphere_solid;
+ DRWShadingGroup *cylinder;
+ DRWShadingGroup *capsule_cap;
+ DRWShadingGroup *capsule_body;
+ DRWShadingGroup *cone;
+ DRWShadingGroup *single_arrow;
+ DRWShadingGroup *single_arrow_line;
+ DRWShadingGroup *empty_axes;
+
+ /* Force Field */
+ DRWShadingGroup *field_wind;
+ DRWShadingGroup *field_force;
+ DRWShadingGroup *field_vortex;
+ DRWShadingGroup *field_curve_sta;
+ DRWShadingGroup *field_curve_end;
+ DRWShadingGroup *field_tube_limit;
+ DRWShadingGroup *field_cone_limit;
+
+ /* Grease Pencil */
+ DRWShadingGroup *gpencil_axes;
+
+ /* Speaker */
+ DRWShadingGroup *speaker;
+
+ /* Probe */
+ DRWShadingGroup *probe_cube;
+ DRWShadingGroup *probe_planar;
+ DRWShadingGroup *probe_grid;
+
+ /* MetaBalls */
+ DRWShadingGroup *mball_handle;
+
+ /* Lamps */
+ DRWShadingGroup *lamp_center;
+ DRWShadingGroup *lamp_groundpoint;
+ DRWShadingGroup *lamp_groundline;
+ DRWShadingGroup *lamp_circle;
+ DRWShadingGroup *lamp_circle_shadow;
+ DRWShadingGroup *lamp_sunrays;
+ DRWShadingGroup *lamp_distance;
+ DRWShadingGroup *lamp_buflimit;
+ DRWShadingGroup *lamp_buflimit_points;
+ DRWShadingGroup *lamp_area_sphere;
+ DRWShadingGroup *lamp_area_square;
+ DRWShadingGroup *lamp_area_disk;
+ DRWShadingGroup *lamp_hemi;
+ DRWShadingGroup *lamp_spot_cone;
+ DRWShadingGroup *lamp_spot_blend;
+ DRWShadingGroup *lamp_spot_pyramid;
+ DRWShadingGroup *lamp_spot_blend_rect;
+ DRWShadingGroup *lamp_spot_volume;
+ DRWShadingGroup *lamp_spot_volume_rect;
+ DRWShadingGroup *lamp_spot_volume_outside;
+ DRWShadingGroup *lamp_spot_volume_rect_outside;
+
+ /* Helpers */
+ DRWShadingGroup *relationship_lines;
+ DRWShadingGroup *constraint_lines;
+
+ /* Camera */
+ DRWShadingGroup *camera;
+ DRWShadingGroup *camera_frame;
+ DRWShadingGroup *camera_tria;
+ DRWShadingGroup *camera_focus;
+ DRWShadingGroup *camera_clip;
+ DRWShadingGroup *camera_clip_points;
+ DRWShadingGroup *camera_mist;
+ DRWShadingGroup *camera_mist_points;
+ ListBase camera_path;
+
+ /* Wire */
+ DRWShadingGroup *wire;
+ DRWShadingGroup *wire_active;
+ DRWShadingGroup *wire_select;
+ DRWShadingGroup *wire_transform;
+
+ /* Points */
+ DRWShadingGroup *points;
+ DRWShadingGroup *points_active;
+ DRWShadingGroup *points_select;
+ DRWShadingGroup *points_transform;
+
+ /* Texture Space */
+ DRWShadingGroup *texspace;
+} OBJECT_ShadingGroupList;
+
+typedef struct OBJECT_PrivateData {
+ OBJECT_ShadingGroupList sgl;
+ OBJECT_ShadingGroupList sgl_ghost;
+
+ /* Outlines */
+ DRWShadingGroup *outlines_active;
+ DRWShadingGroup *outlines_select;
+ DRWShadingGroup *outlines_transform;
+
+ /* Lightprobes */
+ DRWShadingGroup *lightprobes_cube_select;
+ DRWShadingGroup *lightprobes_cube_active;
+ DRWShadingGroup *lightprobes_cube_transform;
+
+ DRWShadingGroup *lightprobes_planar_select;
+ DRWShadingGroup *lightprobes_planar_active;
+ DRWShadingGroup *lightprobes_planar_transform;
+
+ /* Objects Centers */
+ DRWShadingGroup *center_active;
+ DRWShadingGroup *center_selected;
+ DRWShadingGroup *center_deselected;
+ DRWShadingGroup *center_selected_lib;
+ DRWShadingGroup *center_deselected_lib;
+
+ /* Outlines id offset */
+ int id_ofs_active;
+ int id_ofs_select;
+ int id_ofs_transform;
+ int id_ofs_prb_active;
+ int id_ofs_prb_select;
+ int id_ofs_prb_transform;
+
+ bool xray_enabled;
+} OBJECT_PrivateData; /* Transient data */
+
+static struct {
+ /* Instance Data format */
+ struct GPUVertFormat *particle_format;
+ struct GPUVertFormat *empty_image_format;
+ struct GPUVertFormat *empty_image_wire_format;
+
+ /* fullscreen shaders */
+ GPUShader *outline_prepass_sh;
+ GPUShader *outline_prepass_wire_sh;
+ GPUShader *outline_resolve_sh;
+ GPUShader *outline_resolve_aa_sh;
+ GPUShader *outline_detect_sh;
+ GPUShader *outline_detect_wire_sh;
+ GPUShader *outline_fade_sh;
+
+ /* regular shaders */
+ GPUShader *object_empty_image_sh;
+ GPUShader *object_empty_image_wire_sh;
+ GPUShader *grid_sh;
+ GPUShader *part_dot_sh;
+ GPUShader *part_prim_sh;
+ GPUShader *part_axis_sh;
+ GPUShader *lightprobe_grid_sh;
+ float camera_pos[3];
+ float screenvecs[3][4];
+ float grid_settings[5];
+ int grid_flag;
+ float grid_normal[3];
+ float grid_axes[3];
+ int zpos_flag;
+ int zneg_flag;
+ float zplane_normal[3];
+ float zplane_axes[3];
+ float inv_viewport_size[2];
+ bool draw_grid;
+ /* Temp buffer textures */
+ struct GPUTexture *outlines_depth_tx;
+ struct GPUTexture *outlines_id_tx;
+ struct GPUTexture *outlines_color_tx;
+ struct GPUTexture *outlines_blur_tx;
+
+ ListBase smoke_domains;
+} e_data = {NULL}; /* Engine data */
+
+
+enum {
+ SHOW_AXIS_X = (1 << 0),
+ SHOW_AXIS_Y = (1 << 1),
+ SHOW_AXIS_Z = (1 << 2),
+ SHOW_GRID = (1 << 3),
+ PLANE_XY = (1 << 4),
+ PLANE_XZ = (1 << 5),
+ PLANE_YZ = (1 << 6),
+ CLIP_ZPOS = (1 << 7),
+ CLIP_ZNEG = (1 << 8),
+ GRID_BACK = (1 << 9),
+};
+
+/* Prototypes. */
+static void DRW_shgroup_empty_ex(OBJECT_ShadingGroupList *sgl, float mat[4][4], float *draw_size, char draw_type, float *color);
+
+/* *********** FUNCTIONS *********** */
+
+static void OBJECT_engine_init(void *vedata)
+{
+ OBJECT_FramebufferList *fbl = ((OBJECT_Data *)vedata)->fbl;
+
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ if (DRW_state_is_fbo()) {
+ e_data.outlines_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH_COMPONENT24,
+ &draw_engine_object_type);
+ /* XXX TODO GPU_R16UI can overflow, it would cause no harm
+ * (only bad colored or missing outlines) but we should
+ * use 32bits only if the scene have that many objects */
+ e_data.outlines_id_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R16UI,
+ &draw_engine_object_type);
+
+ GPU_framebuffer_ensure_config(&fbl->outlines_fb, {
+ GPU_ATTACHMENT_TEXTURE(e_data.outlines_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.outlines_id_tx)
+ });
+
+ e_data.outlines_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8,
+ &draw_engine_object_type);
+
+ GPU_framebuffer_ensure_config(&fbl->expand_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.outlines_color_tx)
+ });
+
+ e_data.outlines_blur_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8,
+ &draw_engine_object_type);
+
+ GPU_framebuffer_ensure_config(&fbl->blur_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.outlines_blur_tx)
+ });
+ }
+
+ /* Shaders */
+ if (!e_data.outline_resolve_sh) {
+ /* Outline */
+ e_data.outline_prepass_sh = DRW_shader_create_3D(datatoc_object_outline_prepass_frag_glsl, NULL);
+
+ e_data.outline_prepass_wire_sh = DRW_shader_create(
+ datatoc_object_outline_prepass_vert_glsl,
+ datatoc_object_outline_prepass_geom_glsl,
+ datatoc_object_outline_prepass_frag_glsl, NULL);
+
+ e_data.outline_resolve_sh = DRW_shader_create_fullscreen(datatoc_object_outline_resolve_frag_glsl, NULL);
+
+ e_data.outline_resolve_aa_sh = DRW_shader_create_with_lib(
+ datatoc_common_fullscreen_vert_glsl, NULL,
+ datatoc_object_outline_resolve_frag_glsl,
+ datatoc_common_fxaa_lib_glsl,
+ "#define FXAA_ALPHA\n"
+ "#define USE_FXAA\n");
+
+ e_data.outline_detect_sh = DRW_shader_create_with_lib(
+ datatoc_common_fullscreen_vert_glsl, NULL,
+ datatoc_object_outline_detect_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ NULL);
+
+ e_data.outline_detect_wire_sh = DRW_shader_create_with_lib(
+ datatoc_common_fullscreen_vert_glsl, NULL,
+ datatoc_object_outline_detect_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define WIRE\n");
+
+
+ e_data.outline_fade_sh = DRW_shader_create_fullscreen(datatoc_object_outline_expand_frag_glsl, NULL);
+
+ /* Empty images */
+# define EMPTY_IMAGE_SHADER_DEFINES \
+ "#define DEPTH_UNCHANGED " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_DEFAULT) "\n" \
+ "#define DEPTH_FRONT " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_FRONT) "\n" \
+ "#define DEPTH_BACK " STRINGIFY(OB_EMPTY_IMAGE_DEPTH_BACK) "\n"
+
+ e_data.object_empty_image_sh = DRW_shader_create(
+ datatoc_object_empty_image_vert_glsl, NULL,
+ datatoc_object_empty_image_frag_glsl,
+ EMPTY_IMAGE_SHADER_DEFINES);
+
+ e_data.object_empty_image_wire_sh = DRW_shader_create(
+ datatoc_object_empty_image_vert_glsl, NULL,
+ datatoc_object_empty_image_frag_glsl,
+ EMPTY_IMAGE_SHADER_DEFINES
+ "#define USE_WIRE\n");
+
+# undef EMPTY_IMAGE_SHADER_DEFINES
+
+ /* Grid */
+ e_data.grid_sh = DRW_shader_create_with_lib(
+ datatoc_object_grid_vert_glsl, NULL,
+ datatoc_object_grid_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+
+ /* Particles */
+ e_data.part_prim_sh = DRW_shader_create(
+ datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+
+ e_data.part_axis_sh = DRW_shader_create(
+ datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl,
+ "#define USE_AXIS\n");
+
+ e_data.part_dot_sh = DRW_shader_create(
+ datatoc_object_particle_dot_vert_glsl, NULL, datatoc_object_particle_dot_frag_glsl, NULL);
+
+ /* Lightprobes */
+ e_data.lightprobe_grid_sh = DRW_shader_create(
+ datatoc_object_lightprobe_grid_vert_glsl, NULL, datatoc_gpu_shader_flat_id_frag_glsl, NULL);
+ }
+
+ {
+ /* Grid precompute */
+ float invviewmat[4][4], invwinmat[4][4];
+ float viewmat[4][4], winmat[4][4];
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ float grid_scale = ED_view3d_grid_scale(scene, v3d, NULL);
+ float grid_res;
+
+ const bool show_axis_x = (v3d->gridflag & V3D_SHOW_X) != 0;
+ const bool show_axis_y = (v3d->gridflag & V3D_SHOW_Y) != 0;
+ const bool show_axis_z = (v3d->gridflag & V3D_SHOW_Z) != 0;
+ const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) != 0;
+ e_data.draw_grid = show_axis_x || show_axis_y || show_axis_z || show_floor;
+
+ DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_get(invwinmat, DRW_MAT_WININV);
+ DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV);
+
+ /* Setup camera pos */
+ copy_v3_v3(e_data.camera_pos, invviewmat[3]);
+
+ /* if perps */
+ if (winmat[3][3] == 0.0f) {
+ float fov;
+ float viewvecs[2][4] = {
+ {1.0f, -1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f, 1.0f}
+ };
+
+ /* convert the view vectors to view space */
+ for (int i = 0; i < 2; i++) {
+ mul_m4_v4(invwinmat, viewvecs[i]);
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); /* perspective divide */
+ }
+
+ fov = angle_v3v3(viewvecs[0], viewvecs[1]) / 2.0f;
+ grid_res = fabsf(tanf(fov)) / grid_scale;
+
+ e_data.grid_flag = (1 << 4); /* XY plane */
+ if (show_axis_x)
+ e_data.grid_flag |= SHOW_AXIS_X;
+ if (show_axis_y)
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ if (show_floor)
+ e_data.grid_flag |= SHOW_GRID;
+
+ }
+ else {
+ if (rv3d->view != RV3D_VIEW_USER) {
+ /* Allow 3 more subdivisions. */
+ grid_scale /= powf(v3d->gridsubdiv, 3);
+ }
+
+ float viewdist = 1.0f / max_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
+ grid_res = viewdist / grid_scale;
+
+ if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
+ e_data.grid_flag = PLANE_YZ;
+ if (show_axis_y) {
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ }
+ {
+ e_data.grid_flag |= SHOW_AXIS_Z;
+ }
+ if (show_floor) {
+ e_data.grid_flag |= SHOW_GRID;
+ e_data.grid_flag |= GRID_BACK;
+ }
+ }
+ else if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
+ e_data.grid_flag = PLANE_XY;
+ if (show_axis_x) {
+ e_data.grid_flag |= SHOW_AXIS_X;
+ }
+ if (show_axis_y) {
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ }
+ if (show_floor) {
+ e_data.grid_flag |= SHOW_GRID;
+ e_data.grid_flag |= GRID_BACK;
+ }
+ }
+ else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
+ e_data.grid_flag = PLANE_XZ;
+ if (show_axis_x) {
+ e_data.grid_flag |= SHOW_AXIS_X;
+ }
+ {
+ e_data.grid_flag |= SHOW_AXIS_Z;
+ }
+ if (show_floor) {
+ e_data.grid_flag |= SHOW_GRID;
+ e_data.grid_flag |= GRID_BACK;
+ }
+ }
+ else { /* RV3D_VIEW_USER */
+ e_data.grid_flag = PLANE_XY;
+ if (show_axis_x) {
+ e_data.grid_flag |= SHOW_AXIS_X;
+ }
+ if (show_axis_y) {
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ }
+ if (show_floor) {
+ e_data.grid_flag |= SHOW_GRID;
+ }
+ }
+ }
+
+ e_data.grid_normal[0] = (float)((e_data.grid_flag & PLANE_YZ) != 0);
+ e_data.grid_normal[1] = (float)((e_data.grid_flag & PLANE_XZ) != 0);
+ e_data.grid_normal[2] = (float)((e_data.grid_flag & PLANE_XY) != 0);
+
+ e_data.grid_axes[0] = (float)((e_data.grid_flag & (PLANE_XZ | PLANE_XY)) != 0);
+ e_data.grid_axes[1] = (float)((e_data.grid_flag & (PLANE_YZ | PLANE_XY)) != 0);
+ e_data.grid_axes[2] = (float)((e_data.grid_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+
+ /* Vectors to recover pixel world position. Fix grid precision issue. */
+ /* Using pixel at z = 0.0f in ndc space : gives average precision between
+ * near and far plane. Note that it might not be the best choice. */
+ copy_v4_fl4(e_data.screenvecs[0], 1.0f, -1.0f, 0.0f, 1.0f);
+ copy_v4_fl4(e_data.screenvecs[1], -1.0f, 1.0f, 0.0f, 1.0f);
+ copy_v4_fl4(e_data.screenvecs[2], -1.0f, -1.0f, 0.0f, 1.0f);
+
+ for (int i = 0; i < 3; i++) {
+ /* Doing 2 steps to recover world position of the corners of the frustum.
+ * Using the inverse perspective matrix is giving very low precision output. */
+ mul_m4_v4(invwinmat, e_data.screenvecs[i]);
+ e_data.screenvecs[i][0] /= e_data.screenvecs[i][3]; /* perspective divide */
+ e_data.screenvecs[i][1] /= e_data.screenvecs[i][3]; /* perspective divide */
+ e_data.screenvecs[i][2] /= e_data.screenvecs[i][3]; /* perspective divide */
+ e_data.screenvecs[i][3] = 1.0f;
+ /* main instability come from this one */
+ /* TODO : to make things even more stable, don't use
+ * invviewmat and derive vectors from camera properties */
+ mul_m4_v4(invviewmat, e_data.screenvecs[i]);
+ }
+
+ sub_v3_v3(e_data.screenvecs[0], e_data.screenvecs[2]);
+ sub_v3_v3(e_data.screenvecs[1], e_data.screenvecs[2]);
+
+ /* Z axis if needed */
+ if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) {
+ e_data.zpos_flag = SHOW_AXIS_Z;
+
+ float zvec[4] = {0.0f, 0.0f, -1.0f, 0.0f};
+ mul_m4_v4(invviewmat, zvec);
+
+ /* z axis : chose the most facing plane */
+ if (fabsf(zvec[0]) < fabsf(zvec[1])) {
+ e_data.zpos_flag |= PLANE_XZ;
+ }
+ else {
+ e_data.zpos_flag |= PLANE_YZ;
+ }
+
+ e_data.zneg_flag = e_data.zpos_flag;
+
+ /* Persp : If camera is below floor plane, we switch clipping
+ * Ortho : If eye vector is looking up, we switch clipping */
+ if (((winmat[3][3] == 0.0f) && (e_data.camera_pos[2] > 0.0f)) ||
+ ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f)))
+ {
+ e_data.zpos_flag |= CLIP_ZPOS;
+ e_data.zneg_flag |= CLIP_ZNEG;
+ }
+ else {
+ e_data.zpos_flag |= CLIP_ZNEG;
+ e_data.zneg_flag |= CLIP_ZPOS;
+ }
+
+ e_data.zplane_normal[0] = (float)((e_data.zpos_flag & PLANE_YZ) != 0);
+ e_data.zplane_normal[1] = (float)((e_data.zpos_flag & PLANE_XZ) != 0);
+ e_data.zplane_normal[2] = (float)((e_data.zpos_flag & PLANE_XY) != 0);
+
+ e_data.zplane_axes[0] = (float)((e_data.zpos_flag & (PLANE_XZ | PLANE_XY)) != 0);
+ e_data.zplane_axes[1] = (float)((e_data.zpos_flag & (PLANE_YZ | PLANE_XY)) != 0);
+ e_data.zplane_axes[2] = (float)((e_data.zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+
+ }
+ else {
+ e_data.zneg_flag = e_data.zpos_flag = CLIP_ZNEG | CLIP_ZPOS;
+ }
+
+ float dist;
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) {
+ Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ dist = ((Camera *)(camera_object->data))->clipend;
+ }
+ else {
+ dist = v3d->far;
+ }
+
+ e_data.grid_settings[0] = dist / 2.0f; /* gridDistance */
+ e_data.grid_settings[1] = grid_res; /* gridResolution */
+ e_data.grid_settings[2] = grid_scale; /* gridScale */
+ e_data.grid_settings[3] = v3d->gridsubdiv; /* gridSubdiv */
+ e_data.grid_settings[4] = (v3d->gridsubdiv > 1) ? 1.0f / logf(v3d->gridsubdiv) : 0.0f; /* 1/log(gridSubdiv) */
+ }
+
+ copy_v2_v2(e_data.inv_viewport_size, DRW_viewport_size_get());
+ invert_v2(e_data.inv_viewport_size);
+}
+
+static void OBJECT_engine_free(void)
+{
+ MEM_SAFE_FREE(e_data.particle_format);
+ MEM_SAFE_FREE(e_data.empty_image_format);
+ MEM_SAFE_FREE(e_data.empty_image_wire_format);
+ DRW_SHADER_FREE_SAFE(e_data.outline_prepass_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_prepass_wire_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_resolve_aa_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_detect_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_detect_wire_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_fade_sh);
+ DRW_SHADER_FREE_SAFE(e_data.object_empty_image_sh);
+ DRW_SHADER_FREE_SAFE(e_data.object_empty_image_wire_sh);
+ DRW_SHADER_FREE_SAFE(e_data.grid_sh);
+ DRW_SHADER_FREE_SAFE(e_data.part_prim_sh);
+ DRW_SHADER_FREE_SAFE(e_data.part_axis_sh);
+ DRW_SHADER_FREE_SAFE(e_data.part_dot_sh);
+ DRW_SHADER_FREE_SAFE(e_data.lightprobe_grid_sh);
+}
+
+static DRWShadingGroup *shgroup_outline(DRWPass *pass, const int *ofs, GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_int(grp, "baseId", ofs, 1);
+
+ return grp;
+}
+
+/* currently same as 'shgroup_outline', new function to avoid confustion */
+static DRWShadingGroup *shgroup_wire(DRWPass *pass, const float col[4], GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", col, 1);
+
+ return grp;
+}
+
+/* currently same as 'shgroup_outline', new function to avoid confustion */
+static DRWShadingGroup *shgroup_points(DRWPass *pass, const float col[4], GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", col, 1);
+
+ return grp;
+}
+
+static int *shgroup_theme_id_to_probe_outline_counter(
+ OBJECT_StorageList *stl, int theme_id)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return &stl->g_data->id_ofs_prb_active;
+ case TH_SELECT:
+ return &stl->g_data->id_ofs_prb_select;
+ case TH_TRANSFORM:
+ default:
+ return &stl->g_data->id_ofs_prb_transform;
+ }
+}
+
+static int *shgroup_theme_id_to_outline_counter(
+ OBJECT_StorageList *stl, int theme_id)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return &stl->g_data->id_ofs_active;
+ case TH_SELECT:
+ return &stl->g_data->id_ofs_select;
+ case TH_TRANSFORM:
+ default:
+ return &stl->g_data->id_ofs_transform;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_probe_planar_outline_shgrp(
+ OBJECT_StorageList *stl, int theme_id)
+{
+ /* does not increment counter */
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->lightprobes_planar_active;
+ case TH_SELECT:
+ return stl->g_data->lightprobes_planar_select;
+ case TH_TRANSFORM:
+ default:
+ return stl->g_data->lightprobes_planar_transform;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_probe_cube_outline_shgrp(
+ OBJECT_StorageList *stl, int theme_id)
+{
+ /* does not increment counter */
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->lightprobes_cube_active;
+ case TH_SELECT:
+ return stl->g_data->lightprobes_cube_select;
+ case TH_TRANSFORM:
+ default:
+ return stl->g_data->lightprobes_cube_transform;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_outline_or(
+ OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback)
+{
+ int *counter = shgroup_theme_id_to_outline_counter(stl, theme_id);
+ *counter += 1;
+
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->outlines_active;
+ case TH_SELECT:
+ return stl->g_data->outlines_select;
+ case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
+ default:
+ return fallback;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_wire_or(
+ OBJECT_ShadingGroupList *sgl, int theme_id, DRWShadingGroup *fallback)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return sgl->wire_active;
+ case TH_SELECT:
+ return sgl->wire_select;
+ case TH_TRANSFORM:
+ return sgl->wire_transform;
+ default:
+ return fallback;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_point_or(
+ OBJECT_ShadingGroupList *sgl, int theme_id, DRWShadingGroup *fallback)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return sgl->points_active;
+ case TH_SELECT:
+ return sgl->points_select;
+ case TH_TRANSFORM:
+ return sgl->points_transform;
+ default:
+ return fallback;
+ }
+}
+
+static void image_calc_aspect(Image *ima, ImageUser *iuser, float r_image_aspect[2])
+{
+ float ima_x, ima_y;
+ if (ima) {
+ int w, h;
+ BKE_image_get_size(ima, iuser, &w, &h);
+ ima_x = w;
+ ima_y = h;
+ }
+ else {
+ /* if no image, make it a 1x1 empty square, honor scale & offset */
+ ima_x = ima_y = 1.0f;
+ }
+ /* Get the image aspect even if the buffer is invalid */
+ float sca_x = 1.0f, sca_y = 1.0f;
+ if (ima) {
+ if (ima->aspx > ima->aspy) {
+ sca_y = ima->aspy / ima->aspx;
+ }
+ else if (ima->aspx < ima->aspy) {
+ sca_x = ima->aspx / ima->aspy;
+ }
+ }
+
+ const float scale_x_inv = ima_x * sca_x;
+ const float scale_y_inv = ima_y * sca_y;
+ if (scale_x_inv > scale_y_inv) {
+ r_image_aspect[0] = 1.0f;
+ r_image_aspect[1] = scale_y_inv / scale_x_inv;
+ }
+ else {
+ r_image_aspect[0] = scale_x_inv / scale_y_inv;
+ r_image_aspect[1] = 1.0f;
+ }
+}
+
+static void DRW_shgroup_empty_image(
+ OBJECT_ShadingGroupList *sgl, Object *ob, const float color[3], RegionView3D *rv3d)
+{
+ /* TODO: 'StereoViews', see draw_empty_image. */
+
+ if (!BKE_image_empty_visible_in_view3d(ob, rv3d))
+ return;
+
+ GPUTexture *tex = ob->data ?
+ GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D, false, 0.0f) :
+ NULL;
+
+ float image_aspect[2];
+ image_calc_aspect(ob->data, ob->iuser, image_aspect);
+
+ /* OPTI(fclem) We need sorting only for transparent images. If an image as no alpha channel and
+ * ob->col[3] == 1.0f, we could remove it from the sorting pass. */
+
+ if (tex && (ob->col[3] > 0.0f)) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.object_empty_image_sh, sgl->image_empties);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ /* TODO(fclem) implement DRW_shgroup_uniform_vec2_copy */
+ DRW_shgroup_uniform_float_copy(grp, "aspectX", image_aspect[0]);
+ DRW_shgroup_uniform_float_copy(grp, "aspectY", image_aspect[1]);
+ DRW_shgroup_uniform_int_copy(grp, "depthMode", ob->empty_image_depth);
+ DRW_shgroup_uniform_float(grp, "size", &ob->empty_drawsize, 1);
+ DRW_shgroup_uniform_vec2(grp, "offset", ob->ima_ofs, 1);
+ DRW_shgroup_uniform_vec4(grp, "objectColor", ob->col, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_image_plane_get(), ob->obmat);
+ }
+
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.object_empty_image_wire_sh, sgl->non_meshes);
+ /* TODO(fclem) implement DRW_shgroup_uniform_vec2_copy */
+ DRW_shgroup_uniform_float_copy(grp, "aspectX", image_aspect[0]);
+ DRW_shgroup_uniform_float_copy(grp, "aspectY", image_aspect[1]);
+ DRW_shgroup_uniform_int_copy(grp, "depthMode", ob->empty_image_depth);
+ DRW_shgroup_uniform_float(grp, "size", &ob->empty_drawsize, 1);
+ DRW_shgroup_uniform_vec2(grp, "offset", ob->ima_ofs, 1);
+ DRW_shgroup_uniform_vec4(grp, "color", color, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_image_plane_wire_get(), ob->obmat);
+ }
+}
+
+static void OBJECT_cache_init(void *vedata)
+{
+ OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
+ OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ OBJECT_PrivateData *g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ /* TODO : use dpi setting for enabling the second pass */
+ const bool do_outline_expand = false;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ g_data = stl->g_data;
+ g_data->xray_enabled = XRAY_ENABLED(draw_ctx->v3d) && (draw_ctx->v3d->shading.type < OB_MATERIAL);
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE;
+ psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+
+ GPUShader *sh = e_data.outline_prepass_sh;
+
+ if (g_data->xray_enabled) {
+ sh = e_data.outline_prepass_wire_sh;
+ }
+
+ g_data->outlines_select = shgroup_outline(psl->outlines, &g_data->id_ofs_select, sh);
+ g_data->outlines_transform = shgroup_outline(psl->outlines, &g_data->id_ofs_transform, sh);
+ g_data->outlines_active = shgroup_outline(psl->outlines, &g_data->id_ofs_active, sh);
+
+ g_data->id_ofs_select = 0;
+ g_data->id_ofs_active = 0;
+ g_data->id_ofs_transform = 0;
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_POINT;
+ DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state);
+ struct GPUBatch *sphere = DRW_cache_sphere_get();
+ struct GPUBatch *quad = DRW_cache_quad_get();
+
+ /* Cubemap */
+ g_data->lightprobes_cube_select = shgroup_instance_outline(pass, sphere, &g_data->id_ofs_prb_select);
+ g_data->lightprobes_cube_active = shgroup_instance_outline(pass, sphere, &g_data->id_ofs_prb_active);
+ g_data->lightprobes_cube_transform = shgroup_instance_outline(pass, sphere, &g_data->id_ofs_prb_transform);
+
+ /* Planar */
+ g_data->lightprobes_planar_select = shgroup_instance_outline(pass, quad, &g_data->id_ofs_prb_select);
+ g_data->lightprobes_planar_active = shgroup_instance_outline(pass, quad, &g_data->id_ofs_prb_active);
+ g_data->lightprobes_planar_transform = shgroup_instance_outline(pass, quad, &g_data->id_ofs_prb_transform);
+
+ g_data->id_ofs_prb_select = 0;
+ g_data->id_ofs_prb_active = 0;
+ g_data->id_ofs_prb_transform = 0;
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
+ float alphaOcclu = (g_data->xray_enabled) ? 1.0f : 0.35f;
+ /* Reminder : bool uniforms need to be 4 bytes. */
+ static const int bTrue = true;
+ static const int bFalse = false;
+
+ psl->outlines_search = DRW_pass_create("Outlines Detect Pass", state);
+
+ GPUShader *sh = (g_data->xray_enabled) ? e_data.outline_detect_wire_sh : e_data.outline_detect_sh;
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->outlines_search);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineId", &e_data.outlines_id_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu);
+ DRW_shgroup_uniform_int(grp, "idOffsets", &stl->g_data->id_ofs_active, 3);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_expand = DRW_pass_create("Outlines Expand Pass", state);
+
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_expand);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_blur_tx);
+ DRW_shgroup_uniform_bool(grp, "doExpand", (do_outline_expand) ? &bTrue : &bFalse, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_bleed = DRW_pass_create("Outlines Bleed Pass", state);
+
+ if (do_outline_expand) {
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_bleed);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_color_tx);
+ DRW_shgroup_uniform_bool(grp, "doExpand", &bFalse, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND;
+ psl->outlines_resolve = DRW_pass_create("Outlines Resolve Pass", state);
+
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ GPUTexture **outline_tx = (do_outline_expand) ? &e_data.outlines_blur_tx : &e_data.outlines_color_tx;
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.outline_resolve_aa_sh, psl->outlines_resolve);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx);
+ DRW_shgroup_uniform_vec2(grp, "rcpDimensions", e_data.inv_viewport_size, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
+ /* Grid pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND;
+ psl->grid = DRW_pass_create("Infinite Grid Pass", state);
+
+ struct GPUBatch *geom = DRW_cache_grid_get();
+ float grid_line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f;
+ static float mat[4][4];
+ unit_m4(mat);
+
+ /* Create 3 quads to render ordered transparency Z axis */
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zneg_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.zplane_normal, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1);
+ DRW_shgroup_uniform_vec3(grp, "cameraPos", e_data.camera_pos, 1);
+ DRW_shgroup_uniform_vec4(grp, "screenvecs[0]", e_data.screenvecs[0], 3);
+ DRW_shgroup_uniform_vec4(grp, "gridSettings", e_data.grid_settings, 1);
+ DRW_shgroup_uniform_float_copy(grp, "lineKernel", grid_line_size);
+ DRW_shgroup_uniform_float(grp, "gridOneOverLogSubdiv", &e_data.grid_settings[4], 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call_add(grp, geom, mat);
+
+ grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.grid_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.grid_normal, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.grid_axes, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call_add(grp, geom, mat);
+
+ grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zpos_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.zplane_normal, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call_add(grp, geom, mat);
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
+
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ sgl->bone_solid = psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state);
+ sgl->bone_outline = psl->bone_outline[i] = DRW_pass_create("Bone Outline Pass", state);
+
+ /* Wire bones */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
+ sgl->bone_wire = psl->bone_wire[i] = DRW_pass_create("Bone Wire Pass", state);
+
+ /* distance outline around envelope bones */
+ state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_FRONT;
+ sgl->bone_envelope = psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass", state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE;
+ sgl->bone_axes = psl->bone_axes[i] = DRW_pass_create("Bone Axes Pass", state);
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ OBJECT_ShadingGroupList *sgl = (i == 1) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
+
+ /* Non Meshes Pass (Camera, empties, lamps ...) */
+ struct GPUBatch *geom;
+ struct GPUShader *sh;
+
+ DRWState state =
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND | DRW_STATE_POINT | DRW_STATE_WIRE;
+ sgl->non_meshes = psl->non_meshes[i] = DRW_pass_create("Non Meshes Pass", state);
+
+ state = DRW_STATE_WRITE_COLOR |
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND | DRW_STATE_WIRE;
+ sgl->image_empties = psl->image_empties[i] = DRW_pass_create("Image Empties", state);
+
+ /* Empties */
+ geom = DRW_cache_plain_axes_get();
+ sgl->plain_axes = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_empty_cube_get();
+ sgl->cube = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_circle_get();
+ sgl->circle = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_empty_sphere_get();
+ sgl->sphere = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_sphere_get();
+ sgl->sphere_solid = shgroup_instance_solid(sgl->non_meshes, geom);
+
+ geom = DRW_cache_empty_cylinder_get();
+ sgl->cylinder = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_empty_capsule_cap_get();
+ sgl->capsule_cap = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_empty_capsule_body_get();
+ sgl->capsule_body = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_empty_cone_get();
+ sgl->cone = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_single_arrow_get();
+ sgl->single_arrow = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ sgl->single_arrow_line = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_bone_arrows_get();
+ sgl->empty_axes = shgroup_instance_empty_axes(sgl->non_meshes, geom);
+
+ /* Force Field */
+ geom = DRW_cache_field_wind_get();
+ sgl->field_wind = shgroup_instance_scaled(sgl->non_meshes, geom);
+
+ geom = DRW_cache_field_force_get();
+ sgl->field_force = shgroup_instance_screen_aligned(sgl->non_meshes, geom);
+
+ geom = DRW_cache_field_vortex_get();
+ sgl->field_vortex = shgroup_instance_scaled(sgl->non_meshes, geom);
+
+ geom = DRW_cache_screenspace_circle_get();
+ sgl->field_curve_sta = shgroup_instance_screen_aligned(sgl->non_meshes, geom);
+
+ /* Grease Pencil */
+ geom = DRW_cache_gpencil_axes_get();
+ sgl->gpencil_axes = shgroup_instance(sgl->non_meshes, geom);
+
+ /* Speaker */
+ geom = DRW_cache_speaker_get();
+ sgl->speaker = shgroup_instance(sgl->non_meshes, geom);
+
+ /* Probe */
+ static float probeSize = 14.0f;
+ geom = DRW_cache_lightprobe_cube_get();
+ sgl->probe_cube = shgroup_instance_screenspace(sgl->non_meshes, geom, &probeSize);
+
+ geom = DRW_cache_lightprobe_grid_get();
+ sgl->probe_grid = shgroup_instance_screenspace(sgl->non_meshes, geom, &probeSize);
+
+ static float probePlanarSize = 20.0f;
+ geom = DRW_cache_lightprobe_planar_get();
+ sgl->probe_planar = shgroup_instance_screenspace(sgl->non_meshes, geom, &probePlanarSize);
+
+ /* Camera */
+ geom = DRW_cache_camera_get();
+ sgl->camera = shgroup_camera_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_camera_frame_get();
+ sgl->camera_frame = shgroup_camera_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_camera_tria_get();
+ sgl->camera_tria = shgroup_camera_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_plain_axes_get();
+ sgl->camera_focus = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ sgl->camera_clip = shgroup_distance_lines_instance(sgl->non_meshes, geom);
+ sgl->camera_mist = shgroup_distance_lines_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_endpoints_get();
+ sgl->camera_clip_points = shgroup_distance_lines_instance(sgl->non_meshes, geom);
+ sgl->camera_mist_points = shgroup_distance_lines_instance(sgl->non_meshes, geom);
+
+ BLI_listbase_clear(&sgl->camera_path);
+
+ /* Texture Space */
+ geom = DRW_cache_empty_cube_get();
+ sgl->texspace = shgroup_instance(sgl->non_meshes, geom);
+
+ /* Wires (for loose edges) */
+ sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ sgl->wire = shgroup_wire(sgl->non_meshes, ts.colorWire, sh);
+ sgl->wire_select = shgroup_wire(sgl->non_meshes, ts.colorSelect, sh);
+ sgl->wire_transform = shgroup_wire(sgl->non_meshes, ts.colorTransform, sh);
+ sgl->wire_active = shgroup_wire(sgl->non_meshes, ts.colorActive, sh);
+
+ /* Points (loose points) */
+ sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
+ sgl->points = shgroup_points(sgl->non_meshes, ts.colorWire, sh);
+ sgl->points_select = shgroup_points(sgl->non_meshes, ts.colorSelect, sh);
+ sgl->points_transform = shgroup_points(sgl->non_meshes, ts.colorTransform, sh);
+ sgl->points_active = shgroup_points(sgl->non_meshes, ts.colorActive, sh);
+
+ /* Metaballs Handles */
+ sgl->mball_handle = shgroup_instance_mball_handles(sgl->non_meshes);
+
+ /* Lamps */
+ /* TODO
+ * for now we create multiple times the same VBO with only lamp center coordinates
+ * but ideally we would only create it once */
+
+ /* start with buflimit because we don't want stipples */
+ geom = DRW_cache_single_line_get();
+ sgl->lamp_buflimit = shgroup_distance_lines_instance(sgl->non_meshes, geom);
+
+ sgl->lamp_center = shgroup_dynpoints_uniform_color(sgl->non_meshes, ts.colorLampNoAlpha, &ts.sizeLampCenter);
+
+ geom = DRW_cache_lamp_get();
+ sgl->lamp_circle = shgroup_instance_screenspace(sgl->non_meshes, geom, &ts.sizeLampCircle);
+ geom = DRW_cache_lamp_shadows_get();
+ sgl->lamp_circle_shadow = shgroup_instance_screenspace(sgl->non_meshes, geom, &ts.sizeLampCircleShadow);
+
+ geom = DRW_cache_lamp_sunrays_get();
+ sgl->lamp_sunrays = shgroup_instance_screenspace(sgl->non_meshes, geom, &ts.sizeLampCircle);
+
+ sgl->lamp_groundline = shgroup_groundlines_uniform_color(sgl->non_meshes, ts.colorLamp);
+ sgl->lamp_groundpoint = shgroup_groundpoints_uniform_color(sgl->non_meshes, ts.colorLamp);
+
+ geom = DRW_cache_screenspace_circle_get();
+ sgl->lamp_area_sphere = shgroup_instance_screen_aligned(sgl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_area_square_get();
+ sgl->lamp_area_square = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_area_disk_get();
+ sgl->lamp_area_disk = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_hemi_get();
+ sgl->lamp_hemi = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ sgl->lamp_distance = shgroup_distance_lines_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_endpoints_get();
+ sgl->lamp_buflimit_points = shgroup_distance_lines_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_spot_get();
+ sgl->lamp_spot_cone = shgroup_spot_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_circle_get();
+ sgl->lamp_spot_blend = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_spot_square_get();
+ sgl->lamp_spot_pyramid = shgroup_instance(sgl->non_meshes, geom);
+
+ geom = DRW_cache_square_get();
+ sgl->lamp_spot_blend_rect = shgroup_instance(sgl->non_meshes, geom);
+
+ /* -------- STIPPLES ------- */
+
+ /* Relationship Lines */
+ sgl->relationship_lines = shgroup_dynlines_dashed_uniform_color(sgl->non_meshes, ts.colorWire);
+ sgl->constraint_lines = shgroup_dynlines_dashed_uniform_color(sgl->non_meshes, ts.colorGridAxisZ);
+
+ /* Force Field Curve Guide End (here because of stipple) */
+ /* TODO port to shader stipple */
+ geom = DRW_cache_screenspace_circle_get();
+ sgl->field_curve_end = shgroup_instance_screen_aligned(sgl->non_meshes, geom);
+
+ /* Force Field Limits */
+ /* TODO port to shader stipple */
+ geom = DRW_cache_field_tube_limit_get();
+ sgl->field_tube_limit = shgroup_instance_scaled(sgl->non_meshes, geom);
+
+ /* TODO port to shader stipple */
+ geom = DRW_cache_field_cone_limit_get();
+ sgl->field_cone_limit = shgroup_instance_scaled(sgl->non_meshes, geom);
+
+ /* Spot shapes */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND | DRW_STATE_CULL_FRONT;
+ sgl->spot_shapes = psl->spot_shapes[i] = DRW_pass_create("Spot Shape Pass", state);
+ float cone_spot_alpha = 0.5f;
+
+ geom = DRW_cache_lamp_spot_volume_get();
+ sgl->lamp_spot_volume = shgroup_instance_alpha(sgl->spot_shapes, geom, cone_spot_alpha);
+
+ geom = DRW_cache_lamp_spot_square_volume_get();
+ sgl->lamp_spot_volume_rect = shgroup_instance_alpha(sgl->spot_shapes, geom, cone_spot_alpha);
+
+ cone_spot_alpha = 0.3f;
+ geom = DRW_cache_lamp_spot_volume_get();
+ sgl->lamp_spot_volume_outside = shgroup_instance_alpha(sgl->spot_shapes, geom, cone_spot_alpha);
+ DRW_shgroup_state_disable(sgl->lamp_spot_volume_outside, DRW_STATE_CULL_FRONT);
+ DRW_shgroup_state_enable(sgl->lamp_spot_volume_outside, DRW_STATE_CULL_BACK);
+
+ geom = DRW_cache_lamp_spot_square_volume_get();
+ sgl->lamp_spot_volume_rect_outside = shgroup_instance_alpha(sgl->spot_shapes, geom, cone_spot_alpha);
+ DRW_shgroup_state_disable(sgl->lamp_spot_volume_rect_outside, DRW_STATE_CULL_FRONT);
+ DRW_shgroup_state_enable(sgl->lamp_spot_volume_rect_outside, DRW_STATE_CULL_BACK);
+ }
+
+ {
+ /* Object Center pass grouped by State */
+ DRWShadingGroup *grp;
+ static float outlineWidth, size;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_POINT;
+ psl->ob_center = DRW_pass_create("Obj Center Pass", state);
+
+ outlineWidth = 1.0f * U.pixelsize;
+ size = U.obcenter_dia * U.pixelsize + outlineWidth;
+
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+
+ /* Active */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_float(grp, "size", &size, 1);
+ DRW_shgroup_uniform_float(grp, "outlineWidth", &outlineWidth, 1);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorActive, 1);
+ DRW_shgroup_uniform_vec4(grp, "outlineColor", ts.colorOutline, 1);
+ stl->g_data->center_active = grp;
+
+ /* Select */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorSelect, 1);
+ stl->g_data->center_selected = grp;
+
+ /* Deselect */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorDeselect, 1);
+ stl->g_data->center_deselected = grp;
+
+ /* Select (library) */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorLibrarySelect, 1);
+ stl->g_data->center_selected_lib = grp;
+
+ /* Deselect (library) */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorLibrary, 1);
+ stl->g_data->center_deselected_lib = grp;
+ }
+
+ {
+ /* Particle Pass */
+ psl->particle = DRW_pass_create(
+ "Particle Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_POINT | DRW_STATE_BLEND);
+ }
+}
+
+static void DRW_shgroup_mball_handles(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
+{
+ MetaBall *mb = ob->data;
+
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ float draw_scale_xform[3][4]; /* Matrix of Scale and Translation */
+ {
+ float scamat[3][3];
+ copy_m3_m4(scamat, ob->obmat);
+ /* Get the normalized inverse matrix to extract only
+ * the scale of Scamat */
+ float iscamat[3][3];
+ invert_m3_m3(iscamat, scamat);
+ normalize_m3(iscamat);
+ mul_m3_m3_post(scamat, iscamat);
+
+ copy_v3_v3(draw_scale_xform[0], scamat[0]);
+ copy_v3_v3(draw_scale_xform[1], scamat[1]);
+ copy_v3_v3(draw_scale_xform[2], scamat[2]);
+ }
+
+ for (MetaElem *ml = mb->elems.first; ml != NULL; ml = ml->next) {
+ /* draw radius */
+ float world_pos[3];
+ mul_v3_m4v3(world_pos, ob->obmat, &ml->x);
+ draw_scale_xform[0][3] = world_pos[0];
+ draw_scale_xform[1][3] = world_pos[1];
+ draw_scale_xform[2][3] = world_pos[2];
+
+ DRW_shgroup_call_dynamic_add(sgl->mball_handle, draw_scale_xform, &ml->rad, color);
+ }
+}
+
+static void DRW_shgroup_lamp(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
+{
+ Lamp *la = ob->data;
+ float *color;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
+ static float zero = 0.0f;
+
+ typedef struct LampEngineData {
+ DrawData dd;
+ float shape_mat[4][4];
+ float spot_blend_mat[4][4];
+ } LampEngineData;
+
+ LampEngineData *lamp_engine_data =
+ (LampEngineData *)DRW_drawdata_ensure(
+ &ob->id,
+ &draw_engine_object_type,
+ sizeof(LampEngineData),
+ NULL,
+ NULL);
+
+ float (*shapemat)[4] = lamp_engine_data->shape_mat;
+ float (*spotblendmat)[4] = lamp_engine_data->spot_blend_mat;
+
+ /* Don't draw the center if it's selected or active */
+ if (theme_id == TH_LAMP)
+ DRW_shgroup_call_dynamic_add(sgl->lamp_center, ob->obmat[3]);
+
+ /* First circle */
+ DRW_shgroup_call_dynamic_add(sgl->lamp_circle, ob->obmat[3], color);
+
+ /* draw dashed outer circle for shadow */
+ DRW_shgroup_call_dynamic_add(sgl->lamp_circle_shadow, ob->obmat[3], color);
+
+ /* Distance */
+ if (ELEM(la->type, LA_SUN, LA_AREA)) {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_distance, color, &zero, &la->dist, ob->obmat);
+ }
+
+ copy_m4_m4(shapemat, ob->obmat);
+
+ if (la->type == LA_SUN) {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_sunrays, ob->obmat[3], color);
+ }
+ else if (la->type == LA_SPOT) {
+ float size[3], sizemat[4][4];
+ static float one = 1.0f;
+ float cone_inside[3] = {0.0f, 0.0f, 0.0f};
+ float cone_outside[3] = {1.0f, 1.0f, 1.0f};
+ float blend = 1.0f - pow2f(la->spotblend);
+ size[0] = size[1] = sinf(la->spotsize * 0.5f) * la->dist;
+ size[2] = cosf(la->spotsize * 0.5f) * la->dist;
+
+ size_to_mat4(sizemat, size);
+ mul_m4_m4m4(shapemat, ob->obmat, sizemat);
+
+ size[0] = size[1] = blend; size[2] = 1.0f;
+ size_to_mat4(sizemat, size);
+ translate_m4(sizemat, 0.0f, 0.0f, -1.0f);
+ rotate_m4(sizemat, 'X', (float)(M_PI / 2));
+ mul_m4_m4m4(spotblendmat, shapemat, sizemat);
+
+ if (la->mode & LA_SQUARE) {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_spot_pyramid, color, &one, shapemat);
+
+ /* hide line if it is zero size or overlaps with outer border,
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
+ if (blend != 0.0f && blend != 1.0f) {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_spot_blend_rect, color, &one, spotblendmat);
+ }
+
+ if (la->mode & LA_SHOW_CONE) {
+
+ DRW_shgroup_call_dynamic_add(sgl->lamp_spot_volume_rect, cone_inside, &one, shapemat);
+ DRW_shgroup_call_dynamic_add(sgl->lamp_spot_volume_rect_outside, cone_outside, &one, shapemat);
+ }
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_spot_cone, color, shapemat);
+
+ /* hide line if it is zero size or overlaps with outer border,
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
+ if (blend != 0.0f && blend != 1.0f) {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_spot_blend, color, &one, spotblendmat);
+ }
+
+ if (la->mode & LA_SHOW_CONE) {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_spot_volume, cone_inside, &one, shapemat);
+ DRW_shgroup_call_dynamic_add(sgl->lamp_spot_volume_outside, cone_outside, &one, shapemat);
+ }
+ }
+
+ DRW_shgroup_call_dynamic_add(sgl->lamp_buflimit, color, &la->clipsta, &la->clipend, ob->obmat);
+ DRW_shgroup_call_dynamic_add(sgl->lamp_buflimit_points, color, &la->clipsta, &la->clipend, ob->obmat);
+ }
+ else if (la->type == LA_AREA) {
+ float size[3] = {1.0f, 1.0f, 1.0f}, sizemat[4][4];
+
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
+ size[1] = la->area_sizey / la->area_size;
+ size_to_mat4(sizemat, size);
+ mul_m4_m4m4(shapemat, shapemat, sizemat);
+ }
+
+ if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_area_disk, color, &la->area_size, shapemat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_area_square, color, &la->area_size, shapemat);
+ }
+ }
+
+ if (ELEM(la->type, LA_LOCAL, LA_SPOT)) {
+ /* We only want position not scale. */
+ shapemat[0][0] = shapemat[1][1] = shapemat[2][2] = 1.0f;
+ shapemat[0][1] = shapemat[0][2] = 0.0f;
+ shapemat[1][0] = shapemat[1][2] = 0.0f;
+ shapemat[2][0] = shapemat[2][1] = 0.0f;
+ DRW_shgroup_call_dynamic_add(sgl->lamp_area_sphere, color, &la->area_size, shapemat);
+ }
+
+ /* Line and point going to the ground */
+ DRW_shgroup_call_dynamic_add(sgl->lamp_groundline, ob->obmat[3]);
+ DRW_shgroup_call_dynamic_add(sgl->lamp_groundpoint, ob->obmat[3]);
+}
+
+static GPUBatch *batch_camera_path_get(
+ ListBase *camera_paths, const MovieTrackingReconstruction *reconstruction)
+{
+ GPUBatch *geom;
+ static GPUVertFormat format = { 0 };
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, reconstruction->camnr);
+
+ MovieReconstructedCamera *camera = reconstruction->cameras;
+ for (int a = 0; a < reconstruction->camnr; a++, camera++) {
+ GPU_vertbuf_attr_set(vbo, attr_id.pos, a, camera->mat[3]);
+ }
+
+ geom = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+
+ /* Store the batch to do cleanup after drawing. */
+ BLI_addtail(camera_paths, BLI_genericNodeN(geom));
+ return geom;
+}
+
+static void batch_camera_path_free(ListBase *camera_paths)
+{
+ LinkData *link;
+ while ((link = BLI_pophead(camera_paths))) {
+ GPUBatch *camera_path = link->data;
+ GPU_batch_discard(camera_path);
+ MEM_freeN(link);
+ }
+}
+
+static void DRW_shgroup_camera(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ Camera *cam = ob->data;
+ const Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ const bool is_active = (ob == camera_object);
+ const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ float vec[4][3], asp[2], shift[2], scale[3], drawsize;
+
+ scale[0] = 1.0f / len_v3(ob->obmat[0]);
+ scale[1] = 1.0f / len_v3(ob->obmat[1]);
+ scale[2] = 1.0f / len_v3(ob->obmat[2]);
+
+ BKE_camera_view_frame_ex(scene, cam, cam->drawsize, false, scale,
+ asp, shift, &drawsize, vec);
+
+ /* Frame coords */
+ copy_v2_v2(cam->drwcorners[0], vec[0]);
+ copy_v2_v2(cam->drwcorners[1], vec[1]);
+ copy_v2_v2(cam->drwcorners[2], vec[2]);
+ copy_v2_v2(cam->drwcorners[3], vec[3]);
+
+ /* depth */
+ cam->drwdepth = vec[0][2];
+
+ /* tria */
+ cam->drwtria[0][0] = shift[0] + ((0.7f * drawsize) * scale[0]);
+ cam->drwtria[0][1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
+ cam->drwtria[1][0] = shift[0];
+ cam->drwtria[1][1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
+
+ if (look_through) {
+ /* Only draw the frame. */
+ DRW_shgroup_call_dynamic_add(
+ sgl->camera_frame, color, cam->drwcorners,
+ &cam->drwdepth, cam->drwtria, ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(
+ sgl->camera, color, cam->drwcorners,
+ &cam->drwdepth, cam->drwtria, ob->obmat);
+
+ /* Active cam */
+ if (is_active) {
+ DRW_shgroup_call_dynamic_add(
+ sgl->camera_tria, color,
+ cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat);
+ }
+ }
+
+ /* draw the rest in normalize object space */
+ normalize_m4_m4(cam->drwnormalmat, ob->obmat);
+
+ if (cam->flag & CAM_SHOWLIMITS) {
+ static float col[3] = {0.5f, 0.5f, 0.25f}, col_hi[3] = {1.0f, 1.0f, 0.5f};
+ float sizemat[4][4], size[3] = {1.0f, 1.0f, 0.0f};
+ float focusdist = BKE_camera_object_dof_distance(ob);
+
+ copy_m4_m4(cam->drwfocusmat, cam->drwnormalmat);
+ translate_m4(cam->drwfocusmat, 0.0f, 0.0f, -focusdist);
+ size_to_mat4(sizemat, size);
+ mul_m4_m4m4(cam->drwfocusmat, cam->drwfocusmat, sizemat);
+
+ DRW_shgroup_call_dynamic_add(
+ sgl->camera_focus, (is_active ? col_hi : col),
+ &cam->drawsize, cam->drwfocusmat);
+
+ DRW_shgroup_call_dynamic_add(
+ sgl->camera_clip, color,
+ &cam->clipsta, &cam->clipend, cam->drwnormalmat);
+ DRW_shgroup_call_dynamic_add(
+ sgl->camera_clip_points, (is_active ? col_hi : col),
+ &cam->clipsta, &cam->clipend, cam->drwnormalmat);
+ }
+
+ if (cam->flag & CAM_SHOWMIST) {
+ World *world = scene->world;
+
+ if (world) {
+ static float col[3] = {0.5f, 0.5f, 0.5f}, col_hi[3] = {1.0f, 1.0f, 1.0f};
+ world->mistend = world->miststa + world->mistdist;
+ DRW_shgroup_call_dynamic_add(
+ sgl->camera_mist, color,
+ &world->miststa, &world->mistend, cam->drwnormalmat);
+ DRW_shgroup_call_dynamic_add(
+ sgl->camera_mist_points, (is_active ? col_hi : col),
+ &world->miststa, &world->mistend, cam->drwnormalmat);
+ }
+ }
+
+ /* Motion Tracking. */
+ MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
+ if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) && (clip != NULL)) {
+ BLI_assert(BLI_listbase_is_empty(&sgl->camera_path));
+ const bool is_select = DRW_state_is_select();
+ const bool is_solid_bundle = (v3d->bundle_drawtype == OB_EMPTY_SPHERE) &&
+ ((v3d->shading.type != OB_SOLID) ||
+ ((v3d->shading.flag & XRAY_FLAG(v3d)) == 0));
+
+ MovieTracking *tracking = &clip->tracking;
+ /* Index must start in 1, to mimic BKE_tracking_track_get_indexed. */
+ int track_index = 1;
+
+ uchar text_color_selected[4], text_color_unselected[4];
+ float bundle_color_unselected[4], bundle_color_solid[4];
+
+ UI_GetThemeColor4ubv(TH_SELECT, text_color_selected);
+ UI_GetThemeColor4ubv(TH_TEXT, text_color_unselected);
+ UI_GetThemeColor4fv(TH_WIRE, bundle_color_unselected);
+ UI_GetThemeColor4fv(TH_BUNDLE_SOLID, bundle_color_solid);
+
+ float camera_mat[4][4];
+ BKE_tracking_get_camera_object_matrix(draw_ctx->depsgraph, scene, ob, camera_mat);
+
+ float bundle_scale_mat[4][4];
+ if (is_solid_bundle) {
+ scale_m4_fl(bundle_scale_mat, v3d->bundle_size);
+ }
+
+ for (MovieTrackingObject *tracking_object = tracking->objects.first;
+ tracking_object != NULL;
+ tracking_object = tracking_object->next)
+ {
+ float tracking_object_mat[4][4];
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ copy_m4_m4(tracking_object_mat, camera_mat);
+ }
+ else {
+ const int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, DEG_get_ctime(draw_ctx->depsgraph));
+ float object_mat[4][4];
+ BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, object_mat);
+
+ invert_m4(object_mat);
+ mul_m4_m4m4(tracking_object_mat, cam->drwnormalmat, object_mat);
+ }
+
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ for (MovieTrackingTrack *track = tracksbase->first; track; track = track->next) {
+
+ if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+ continue;
+ }
+
+ bool is_selected = TRACK_SELECTED(track);
+
+ float bundle_mat[4][4];
+ copy_m4_m4(bundle_mat, tracking_object_mat);
+ translate_m4(bundle_mat, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+
+ float *bundle_color;
+ if (track->flag & TRACK_CUSTOMCOLOR) {
+ bundle_color = track->color;
+ }
+ else if (is_solid_bundle) {
+ bundle_color = bundle_color_solid;
+ }
+ else if (is_selected) {
+ bundle_color = color;
+ }
+ else {
+ bundle_color = bundle_color_unselected;
+ }
+
+ if (is_select) {
+ DRW_select_load_id(camera_object->select_color | (track_index << 16));
+ track_index++;
+ }
+
+ if (is_solid_bundle) {
+
+ if (is_selected) {
+ DRW_shgroup_empty_ex(sgl,
+ bundle_mat,
+ &v3d->bundle_size,
+ v3d->bundle_drawtype,
+ color);
+ }
+
+ float bundle_color_v4[4] = {
+ bundle_color[0],
+ bundle_color[1],
+ bundle_color[2],
+ 1.0f,
+ };
+
+ mul_m4_m4m4(bundle_mat, bundle_mat, bundle_scale_mat);
+ DRW_shgroup_call_dynamic_add(sgl->sphere_solid,
+ bundle_mat,
+ bundle_color_v4);
+ }
+ else {
+ DRW_shgroup_empty_ex(sgl,
+ bundle_mat,
+ &v3d->bundle_size,
+ v3d->bundle_drawtype,
+ bundle_color);
+ }
+
+ if ((v3d->flag2 & V3D_SHOW_BUNDLENAME) && !is_select) {
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+ DRW_text_cache_add(dt,
+ bundle_mat[3],
+ track->name,
+ strlen(track->name),
+ 10, 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ is_selected ? text_color_selected : text_color_unselected);
+ }
+ }
+
+ if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA) && !is_select) {
+ MovieTrackingReconstruction *reconstruction;
+ reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
+
+ if (reconstruction->camnr) {
+ static float camera_path_color[4];
+ UI_GetThemeColor4fv(TH_CAMERA_PATH, camera_path_color);
+
+ GPUBatch *geom = batch_camera_path_get(&sgl->camera_path, reconstruction);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ DRWShadingGroup *shading_group = DRW_shgroup_create(shader, sgl->non_meshes);
+ DRW_shgroup_uniform_vec4(shading_group, "color", camera_path_color, 1);
+ DRW_shgroup_call_add(shading_group, geom, camera_mat);
+ }
+ }
+ }
+ }
+}
+
+static void DRW_shgroup_empty_ex(
+ OBJECT_ShadingGroupList *sgl, float mat[4][4], float *draw_size, char draw_type, float *color)
+{
+ switch (draw_type) {
+ case OB_PLAINAXES:
+ DRW_shgroup_call_dynamic_add(sgl->plain_axes, color, draw_size, mat);
+ break;
+ case OB_SINGLE_ARROW:
+ DRW_shgroup_call_dynamic_add(sgl->single_arrow, color, draw_size, mat);
+ DRW_shgroup_call_dynamic_add(sgl->single_arrow_line, color, draw_size, mat);
+ break;
+ case OB_CUBE:
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, draw_size, mat);
+ break;
+ case OB_CIRCLE:
+ DRW_shgroup_call_dynamic_add(sgl->circle, color, draw_size, mat);
+ break;
+ case OB_EMPTY_SPHERE:
+ DRW_shgroup_call_dynamic_add(sgl->sphere, color, draw_size, mat);
+ break;
+ case OB_EMPTY_CONE:
+ DRW_shgroup_call_dynamic_add(sgl->cone, color, draw_size, mat);
+ break;
+ case OB_ARROWS:
+ DRW_shgroup_call_dynamic_add(sgl->empty_axes, color, draw_size, mat);
+ break;
+ case OB_EMPTY_IMAGE:
+ BLI_assert(!"Should never happen, use DRW_shgroup_empty instead.");
+ break;
+ }
+}
+
+static void DRW_shgroup_empty(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer, RegionView3D *rv3d)
+{
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ switch (ob->empty_drawtype) {
+ case OB_PLAINAXES:
+ case OB_SINGLE_ARROW:
+ case OB_CUBE:
+ case OB_CIRCLE:
+ case OB_EMPTY_SPHERE:
+ case OB_EMPTY_CONE:
+ case OB_ARROWS:
+ DRW_shgroup_empty_ex(sgl, ob->obmat, &ob->empty_drawsize, ob->empty_drawtype, color);
+ break;
+ case OB_EMPTY_IMAGE:
+ DRW_shgroup_empty_image(sgl, ob, color, rv3d);
+ break;
+ }
+}
+
+static void DRW_shgroup_forcefield(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
+{
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ float *color = DRW_color_background_blend_get(theme_id);
+ PartDeflect *pd = ob->pd;
+ Curve *cu = (ob->type == OB_CURVE) ? ob->data : NULL;
+
+ /* TODO Move this to depsgraph */
+ float tmp[3];
+ copy_v3_fl(pd->drawvec1, ob->empty_drawsize);
+
+ switch (pd->forcefield) {
+ case PFIELD_WIND:
+ pd->drawvec1[2] = pd->f_strength;
+ break;
+ case PFIELD_VORTEX:
+ if (pd->f_strength < 0.0f) {
+ pd->drawvec1[1] = -pd->drawvec1[1];
+ }
+ break;
+ case PFIELD_GUIDE:
+ if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path && ob->runtime.curve_cache->path->data) {
+ where_on_path(ob, 0.0f, pd->drawvec1, tmp, NULL, NULL, NULL);
+ where_on_path(ob, 1.0f, pd->drawvec2, tmp, NULL, NULL, NULL);
+ }
+ break;
+ }
+
+ if (pd->falloff == PFIELD_FALL_TUBE) {
+ pd->drawvec_falloff_max[0] = pd->drawvec_falloff_max[1] = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f;
+ pd->drawvec_falloff_max[2] = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+
+ pd->drawvec_falloff_min[0] = pd->drawvec_falloff_min[1] = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f;
+ pd->drawvec_falloff_min[2] = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+ }
+ else if (pd->falloff == PFIELD_FALL_CONE) {
+ float radius, distance;
+
+ radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
+ distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+ pd->drawvec_falloff_max[0] = pd->drawvec_falloff_max[1] = distance * sinf(radius);
+ pd->drawvec_falloff_max[2] = distance * cosf(radius);
+
+ radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
+ distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+
+ pd->drawvec_falloff_min[0] = pd->drawvec_falloff_min[1] = distance * sinf(radius);
+ pd->drawvec_falloff_min[2] = distance * cosf(radius);
+ }
+ /* End of things that should go to depthgraph */
+
+ switch (pd->forcefield) {
+ case PFIELD_WIND:
+ DRW_shgroup_call_dynamic_add(sgl->field_wind, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_FORCE:
+ DRW_shgroup_call_dynamic_add(sgl->field_force, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_VORTEX:
+ DRW_shgroup_call_dynamic_add(sgl->field_vortex, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_GUIDE:
+ if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path && ob->runtime.curve_cache->path->data) {
+ DRW_shgroup_call_dynamic_add(sgl->field_curve_sta, color, &pd->f_strength, ob->obmat);
+ DRW_shgroup_call_dynamic_add(sgl->field_curve_end, color, &pd->f_strength, ob->obmat);
+ }
+ break;
+ }
+
+ if (pd->falloff == PFIELD_FALL_SPHERE) {
+ /* as last, guide curve alters it */
+ if ((pd->flag & PFIELD_USEMAX) != 0) {
+ DRW_shgroup_call_dynamic_add(sgl->field_curve_end, color, &pd->maxdist, ob->obmat);
+ }
+
+ if ((pd->flag & PFIELD_USEMIN) != 0) {
+ DRW_shgroup_call_dynamic_add(sgl->field_curve_end, color, &pd->mindist, ob->obmat);
+ }
+ }
+ else if (pd->falloff == PFIELD_FALL_TUBE) {
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ DRW_shgroup_call_dynamic_add(sgl->field_tube_limit, color, &pd->drawvec_falloff_max, ob->obmat);
+ }
+
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ DRW_shgroup_call_dynamic_add(sgl->field_tube_limit, color, &pd->drawvec_falloff_min, ob->obmat);
+ }
+ }
+ else if (pd->falloff == PFIELD_FALL_CONE) {
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ DRW_shgroup_call_dynamic_add(sgl->field_cone_limit, color, &pd->drawvec_falloff_max, ob->obmat);
+ }
+
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ DRW_shgroup_call_dynamic_add(sgl->field_cone_limit, color, &pd->drawvec_falloff_min, ob->obmat);
+ }
+ }
+}
+
+static void DRW_shgroup_volume_extra(
+ OBJECT_ShadingGroupList *sgl,
+ Object *ob, ViewLayer *view_layer, Scene *scene, ModifierData *md)
+{
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ SmokeDomainSettings *sds = smd->domain;
+ float *color;
+ float one = 1.0f;
+
+ if (sds == NULL) {
+ return;
+ }
+
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ /* Small cube showing voxel size. */
+ float voxel_cubemat[4][4] = {{0.0f}};
+ voxel_cubemat[0][0] = 1.0f / (float)sds->res[0];
+ voxel_cubemat[1][1] = 1.0f / (float)sds->res[1];
+ voxel_cubemat[2][2] = 1.0f / (float)sds->res[2];
+ voxel_cubemat[3][0] = voxel_cubemat[3][1] = voxel_cubemat[3][2] = -1.0f;
+ voxel_cubemat[3][3] = 1.0f;
+ translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f);
+ mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat);
+
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, voxel_cubemat);
+
+ /* Don't show smoke before simulation starts, this could be made an option in the future. */
+ if (!sds->draw_velocity || !sds->fluid || CFRA < sds->point_cache[0]->startframe) {
+ return;
+ }
+
+ const bool use_needle = (sds->vector_draw_type == VECTOR_DRAW_NEEDLE);
+ int line_count = (use_needle) ? 6 : 1;
+ int slice_axis = -1;
+ line_count *= sds->res[0] * sds->res[1] * sds->res[2];
+
+ if (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
+ sds->axis_slice_method == AXIS_SLICE_SINGLE)
+ {
+ float invviewmat[4][4];
+ DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV);
+
+ const int axis = (sds->slice_axis == SLICE_AXIS_AUTO)
+ ? axis_dominant_v3_single(invviewmat[2])
+ : sds->slice_axis - 1;
+ slice_axis = axis;
+ line_count /= sds->res[axis];
+ }
+
+ GPU_create_smoke_velocity(smd);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(volume_velocity_shader_get(use_needle), sgl->non_meshes);
+ DRW_shgroup_uniform_texture(grp, "velocityX", sds->tex_velocity_x);
+ DRW_shgroup_uniform_texture(grp, "velocityY", sds->tex_velocity_y);
+ DRW_shgroup_uniform_texture(grp, "velocityZ", sds->tex_velocity_z);
+ DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale);
+ DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
+ DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis);
+ DRW_shgroup_call_procedural_lines_add(grp, line_count, ob->obmat);
+
+ BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd));
+}
+
+static void volumes_free_smoke_textures(void)
+{
+ /* Free Smoke Textures after rendering */
+ /* XXX This is a waste of processing and GPU bandwidth if nothing
+ * is updated. But the problem is since Textures are stored in the
+ * modifier we don't want them to take precious VRAM if the
+ * modifier is not used for display. We should share them for
+ * all viewport in a redraw at least. */
+ for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) {
+ SmokeModifierData *smd = (SmokeModifierData *)link->data;
+ GPU_free_smoke_velocity(smd);
+ }
+ BLI_freelistN(&e_data.smoke_domains);
+}
+
+static void DRW_shgroup_gpencil(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
+{
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ DRW_shgroup_call_dynamic_add(sgl->gpencil_axes, color, &ob->empty_drawsize, ob->obmat);
+}
+
+static void DRW_shgroup_speaker(OBJECT_ShadingGroupList *sgl, Object *ob, ViewLayer *view_layer)
+{
+ float *color;
+ static float one = 1.0f;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ DRW_shgroup_call_dynamic_add(sgl->speaker, color, &one, ob->obmat);
+}
+
+typedef struct OBJECT_LightProbeEngineData {
+ DrawData dd;
+
+ float increment_x[3];
+ float increment_y[3];
+ float increment_z[3];
+ float corner[3];
+} OBJECT_LightProbeEngineData;
+
+static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl, Object *ob, ViewLayer *view_layer)
+{
+ float *color;
+ static float one = 1.0f;
+ LightProbe *prb = (LightProbe *)ob->data;
+ bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0);
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
+
+ OBJECT_LightProbeEngineData *prb_data =
+ (OBJECT_LightProbeEngineData *)DRW_drawdata_ensure(
+ &ob->id,
+ &draw_engine_object_type,
+ sizeof(OBJECT_LightProbeEngineData),
+ NULL,
+ NULL);
+
+ if ((DRW_state_is_select() || do_outlines) && ((prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) != 0)) {
+ int *call_id = shgroup_theme_id_to_probe_outline_counter(stl, theme_id);
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ /* Update transforms */
+ float cell_dim[3], half_cell_dim[3];
+ cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
+ cell_dim[1] = 2.0f / (float)(prb->grid_resolution_y);
+ cell_dim[2] = 2.0f / (float)(prb->grid_resolution_z);
+
+ mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
+
+ /* First cell. */
+ copy_v3_fl(prb_data->corner, -1.0f);
+ add_v3_v3(prb_data->corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, prb_data->corner);
+
+ /* Opposite neighbor cell. */
+ copy_v3_fl3(prb_data->increment_x, cell_dim[0], 0.0f, 0.0f);
+ add_v3_v3(prb_data->increment_x, half_cell_dim);
+ add_v3_fl(prb_data->increment_x, -1.0f);
+ mul_m4_v3(ob->obmat, prb_data->increment_x);
+ sub_v3_v3(prb_data->increment_x, prb_data->corner);
+
+ copy_v3_fl3(prb_data->increment_y, 0.0f, cell_dim[1], 0.0f);
+ add_v3_v3(prb_data->increment_y, half_cell_dim);
+ add_v3_fl(prb_data->increment_y, -1.0f);
+ mul_m4_v3(ob->obmat, prb_data->increment_y);
+ sub_v3_v3(prb_data->increment_y, prb_data->corner);
+
+ copy_v3_fl3(prb_data->increment_z, 0.0f, 0.0f, cell_dim[2]);
+ add_v3_v3(prb_data->increment_z, half_cell_dim);
+ add_v3_fl(prb_data->increment_z, -1.0f);
+ mul_m4_v3(ob->obmat, prb_data->increment_z);
+ sub_v3_v3(prb_data->increment_z, prb_data->corner);
+
+ uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.lightprobe_grid_sh, psl->lightprobes);
+ DRW_shgroup_uniform_int_copy(grp, "call_id", *call_id);
+ DRW_shgroup_uniform_int(grp, "baseId", call_id, 1); /* that's correct */
+ DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1);
+ DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1);
+ DRW_shgroup_call_procedural_points_add(grp, cell_count, NULL);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ float draw_size = 1.0f;
+ float probe_cube_mat[4][4];
+ // prb_data->draw_size = prb->data_draw_size * 0.1f;
+ // unit_m4(prb_data->probe_cube_mat);
+ // copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]);
+
+ DRWShadingGroup *grp = shgroup_theme_id_to_probe_cube_outline_shgrp(stl, theme_id);
+ /* TODO remove or change the drawing of the cube probes. Theses line draws nothing on purpose
+ * to keep the call ids correct. */
+ zero_m4(probe_cube_mat);
+ DRW_shgroup_call_dynamic_add(grp, call_id, &draw_size, probe_cube_mat);
+ }
+ else {
+ float draw_size = 1.0f;
+ DRWShadingGroup *grp = shgroup_theme_id_to_probe_planar_outline_shgrp(stl, theme_id);
+ DRW_shgroup_call_dynamic_add(grp, call_id, &draw_size, ob->obmat);
+ }
+
+ *call_id += 1;
+ }
+
+ switch (prb->type) {
+ case LIGHTPROBE_TYPE_PLANAR:
+ DRW_shgroup_call_dynamic_add(sgl->probe_planar, ob->obmat[3], color);
+ break;
+ case LIGHTPROBE_TYPE_GRID:
+ DRW_shgroup_call_dynamic_add(sgl->probe_grid, ob->obmat[3], color);
+ break;
+ case LIGHTPROBE_TYPE_CUBE:
+ default:
+ DRW_shgroup_call_dynamic_add(sgl->probe_cube, ob->obmat[3], color);
+ break;
+ }
+
+
+
+ if (prb->type == LIGHTPROBE_TYPE_PLANAR) {
+ float mat[4][4];
+ copy_m4_m4(mat, ob->obmat);
+ normalize_m4(mat);
+
+ DRW_shgroup_call_dynamic_add(sgl->single_arrow, color, &ob->empty_drawsize, mat);
+ DRW_shgroup_call_dynamic_add(sgl->single_arrow_line, color, &ob->empty_drawsize, mat);
+
+ copy_m4_m4(mat, ob->obmat);
+ zero_v3(mat[2]);
+
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, mat);
+ }
+
+ if ((prb->flag & LIGHTPROBE_FLAG_SHOW_INFLUENCE) != 0) {
+
+ prb->distfalloff = (1.0f - prb->falloff) * prb->distinf;
+ prb->distgridinf = prb->distinf;
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ prb->distfalloff += 1.0f;
+ prb->distgridinf += 1.0f;
+ }
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID ||
+ prb->attenuation_type == LIGHTPROBE_SHAPE_BOX)
+ {
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, &prb->distgridinf, ob->obmat);
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, &prb->distfalloff, ob->obmat);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR) {
+ float rangemat[4][4];
+ copy_m4_m4(rangemat, ob->obmat);
+ normalize_v3(rangemat[2]);
+ mul_v3_fl(rangemat[2], prb->distinf);
+
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, rangemat);
+
+ copy_m4_m4(rangemat, ob->obmat);
+ normalize_v3(rangemat[2]);
+ mul_v3_fl(rangemat[2], prb->distfalloff);
+
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, rangemat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(sgl->sphere, color, &prb->distgridinf, ob->obmat);
+ DRW_shgroup_call_dynamic_add(sgl->sphere, color, &prb->distfalloff, ob->obmat);
+ }
+ }
+
+ if ((prb->flag & LIGHTPROBE_FLAG_SHOW_PARALLAX) != 0) {
+ if (prb->type != LIGHTPROBE_TYPE_PLANAR) {
+ float (*obmat)[4], *dist;
+
+ if ((prb->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) {
+ dist = &prb->distpar;
+ /* TODO object parallax */
+ obmat = ob->obmat;
+ }
+ else {
+ dist = &prb->distinf;
+ obmat = ob->obmat;
+ }
+
+ if (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) {
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, dist, obmat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(sgl->sphere, color, dist, obmat);
+ }
+ }
+ }
+
+ if ((prb->flag & LIGHTPROBE_FLAG_SHOW_CLIP_DIST) != 0) {
+ if (prb->type != LIGHTPROBE_TYPE_PLANAR) {
+ static const float cubefacemat[6][4][4] = {
+ {{0.0, 0.0, -1.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{0.0, 0.0, 1.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {1.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{1.0, 0.0, 0.0, 0.0}, {0.0, 0.0, -1.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{1.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{1.0, 0.0, 0.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {0.0, 0.0, -1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{-1.0, 0.0, 0.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ };
+
+ for (int i = 0; i < 6; ++i) {
+ float clipmat[4][4];
+ normalize_m4_m4(clipmat, ob->obmat);
+ mul_m4_m4m4(clipmat, clipmat, cubefacemat[i]);
+
+ DRW_shgroup_call_dynamic_add(sgl->lamp_buflimit, color, &prb->clipsta, &prb->clipend, clipmat);
+ DRW_shgroup_call_dynamic_add(sgl->lamp_buflimit_points, color, &prb->clipsta, &prb->clipend, clipmat);
+ }
+ }
+ }
+
+ /* Line and point going to the ground */
+ if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ DRW_shgroup_call_dynamic_add(sgl->lamp_groundline, ob->obmat[3]);
+ DRW_shgroup_call_dynamic_add(sgl->lamp_groundpoint, ob->obmat[3]);
+ }
+}
+
+static void DRW_shgroup_relationship_lines(
+ OBJECT_ShadingGroupList *sgl,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
+{
+ if (ob->parent && DRW_object_is_visible_in_active_context(ob->parent)) {
+ DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->parent->obmat[3]);
+ DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->obmat[3]);
+ }
+
+ if (ob->rigidbody_constraint) {
+ Object *rbc_ob1 = ob->rigidbody_constraint->ob1;
+ Object *rbc_ob2 = ob->rigidbody_constraint->ob2;
+ if (rbc_ob1 && DRW_object_is_visible_in_active_context(rbc_ob1)) {
+ DRW_shgroup_call_dynamic_add(sgl->relationship_lines, rbc_ob1->obmat[3]);
+ DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->obmat[3]);
+ }
+ if (rbc_ob2 && DRW_object_is_visible_in_active_context(rbc_ob2)) {
+ DRW_shgroup_call_dynamic_add(sgl->relationship_lines, rbc_ob2->obmat[3]);
+ DRW_shgroup_call_dynamic_add(sgl->relationship_lines, ob->obmat[3]);
+ }
+ }
+
+ /* Drawing the constraint lines */
+ if (!BLI_listbase_is_empty(&ob->constraints)) {
+ bConstraint *curcon;
+ bConstraintOb *cob;
+ ListBase *list = &ob->constraints;
+
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+
+ for (curcon = list->first; curcon; curcon = curcon->next) {
+ if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ /* special case for object solver and follow track constraints because they don't fill
+ * constraint targets properly (design limitation -- scene is needed for their target
+ * but it can't be accessed from get_targets callback) */
+
+ Object *camob = NULL;
+
+ if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+ bFollowTrackConstraint *data = (bFollowTrackConstraint *)curcon->data;
+
+ camob = data->camera ? data->camera : scene->camera;
+ }
+ else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = (bObjectSolverConstraint *)curcon->data;
+
+ camob = data->camera ? data->camera : scene->camera;
+ }
+
+ if (camob) {
+ DRW_shgroup_call_dynamic_add(sgl->constraint_lines, camob->obmat[3]);
+ DRW_shgroup_call_dynamic_add(sgl->constraint_lines, ob->obmat[3]);
+ }
+ }
+ else {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+
+ if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* calculate target's matrix */
+ if (cti->get_target_matrix) {
+ cti->get_target_matrix(depsgraph,
+ curcon,
+ cob,
+ ct,
+ DEG_get_ctime(depsgraph));
+ }
+ else {
+ unit_m4(ct->matrix);
+ }
+
+ DRW_shgroup_call_dynamic_add(sgl->constraint_lines, ct->matrix[3]);
+ DRW_shgroup_call_dynamic_add(sgl->constraint_lines, ob->obmat[3]);
+ }
+
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(curcon, &targets, 1);
+ }
+ }
+ }
+ }
+
+ BKE_constraints_clear_evalob(cob);
+ }
+}
+
+static void DRW_shgroup_object_center(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer, View3D *v3d)
+{
+ if (v3d->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_ORIGINS) {
+ return;
+ }
+ const bool is_library = ob->id.us > 1 || ID_IS_LINKED(ob);
+ DRWShadingGroup *shgroup;
+
+ if (ob == OBACT(view_layer)) {
+ shgroup = stl->g_data->center_active;
+ }
+ else if (ob->base_flag & BASE_SELECTED) {
+ if (is_library) {
+ shgroup = stl->g_data->center_selected_lib;
+ }
+ else {
+ shgroup = stl->g_data->center_selected;
+ }
+ }
+ else if (v3d->flag & V3D_DRAW_CENTERS) {
+ if (is_library) {
+ shgroup = stl->g_data->center_deselected_lib;
+ }
+ else {
+ shgroup = stl->g_data->center_deselected;
+ }
+ }
+ else {
+ return;
+ }
+
+ DRW_shgroup_call_dynamic_add(shgroup, ob->obmat[3]);
+}
+
+static void DRW_shgroup_texture_space(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id)
+{
+ if (ob->data == NULL) {
+ return;
+ }
+
+ ID *ob_data = ob->data;
+ float *texcoloc = NULL;
+ float *texcosize = NULL;
+
+ switch (GS(ob_data->name)) {
+ case ID_ME:
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ break;
+ case ID_CU:
+ {
+ Curve *cu = (Curve *)ob_data;
+ if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(cu);
+ }
+ texcoloc = cu->loc;
+ texcosize = cu->size;
+ break;
+ }
+ case ID_MB:
+ {
+ MetaBall *mb = (MetaBall *)ob_data;
+ texcoloc = mb->loc;
+ texcosize = mb->size;
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+
+ float tmp[4][4] = {{0.0f}}, one = 1.0f;
+ tmp[0][0] = texcosize[0];
+ tmp[1][1] = texcosize[1];
+ tmp[2][2] = texcosize[2];
+ tmp[3][0] = texcoloc[0];
+ tmp[3][1] = texcoloc[1];
+ tmp[3][2] = texcoloc[2];
+ tmp[3][3] = 1.0f;
+
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+
+ float color[4];
+ UI_GetThemeColor4fv(theme_id, color);
+
+ DRW_shgroup_call_dynamic_add(sgl->texspace, color, &one, tmp);
+}
+
+static void DRW_shgroup_bounds(OBJECT_ShadingGroupList *sgl, Object *ob, int theme_id)
+{
+ float color[4], center[3], size[3], tmp[4][4], final_mat[4][4], one = 1.0f;
+ BoundBox bb_local;
+
+ if (ob->type == OB_MBALL && !BKE_mball_is_basis(ob)) {
+ return;
+ }
+
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+
+ if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT,
+ OB_MBALL, OB_ARMATURE, OB_LATTICE))
+ {
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
+ bb = &bb_local;
+ BKE_boundbox_init_from_minmax(bb, min, max);
+ }
+
+ UI_GetThemeColor4fv(theme_id, color);
+ BKE_boundbox_calc_center_aabb(bb, center);
+ BKE_boundbox_calc_size_aabb(bb, size);
+
+ switch (ob->boundtype) {
+ case OB_BOUND_BOX:
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_shgroup_call_dynamic_add(sgl->cube, color, &one, tmp);
+ break;
+ case OB_BOUND_SPHERE:
+ size[0] = max_fff(size[0], size[1], size[2]);
+ size[1] = size[2] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_shgroup_call_dynamic_add(sgl->sphere, color, &one, tmp);
+ break;
+ case OB_BOUND_CYLINDER:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_shgroup_call_dynamic_add(sgl->cylinder, color, &one, tmp);
+ break;
+ case OB_BOUND_CONE:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ size_to_mat4(tmp, size);
+ copy_v3_v3(tmp[3], center);
+ /* Cone batch has base at 0 and is pointing towards +Y. */
+ swap_v3_v3(tmp[1], tmp[2]);
+ tmp[3][2] -= size[2];
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+ DRW_shgroup_call_dynamic_add(sgl->cone, color, &one, tmp);
+ break;
+ case OB_BOUND_CAPSULE:
+ size[0] = max_ff(size[0], size[1]);
+ size[1] = size[0];
+ scale_m4_fl(tmp, size[0]);
+ copy_v2_v2(tmp[3], center);
+ tmp[3][2] = center[2] + max_ff(0.0f, size[2] - size[0]);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_shgroup_call_dynamic_add(sgl->capsule_cap, color, &one, final_mat);
+ negate_v3(tmp[2]);
+ tmp[3][2] = center[2] - max_ff(0.0f, size[2] - size[0]);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_shgroup_call_dynamic_add(sgl->capsule_cap, color, &one, final_mat);
+ tmp[2][2] = max_ff(0.0f, size[2] * 2.0f - size[0] * 2.0f);
+ mul_m4_m4m4(final_mat, ob->obmat, tmp);
+ DRW_shgroup_call_dynamic_add(sgl->capsule_body, color, &one, final_mat);
+ break;
+ }
+}
+
+static void OBJECT_cache_populate_particles(Object *ob,
+ OBJECT_PassList *psl)
+{
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (!psys_check_enabled(ob, psys, false)) {
+ continue;
+ }
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+
+ ParticleSettings *part = psys->part;
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ static float mat[4][4];
+ unit_m4(mat);
+
+ if (draw_as != PART_DRAW_PATH) {
+ struct GPUBatch *geom = DRW_cache_particles_get_dots(ob, psys);
+ DRWShadingGroup *shgrp = NULL;
+ static int screen_space[2] = {0, 1};
+ static float def_prim_col[3] = {0.5f, 0.5f, 0.5f};
+ static float def_sec_col[3] = {1.0f, 1.0f, 1.0f};
+
+ /* Dummy particle format for instancing to work. */
+ DRW_shgroup_instance_format(e_data.particle_format, {{"dummy", DRW_ATTRIB_FLOAT, 1}});
+
+ Material *ma = give_current_material(ob, part->omat);
+
+ switch (draw_as) {
+ case PART_DRAW_DOT:
+ shgrp = DRW_shgroup_create(e_data.part_dot_sh, psl->particle);
+ DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "outlineColor", ma ? &ma->specr : def_sec_col, 1);
+ DRW_shgroup_uniform_float(shgrp, "pixel_size", DRW_viewport_pixelsize_get(), 1);
+ DRW_shgroup_uniform_float(shgrp, "size", &part->draw_size, 1);
+ DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp);
+ DRW_shgroup_call_add(shgrp, geom, mat);
+ break;
+ case PART_DRAW_CROSS:
+ shgrp = DRW_shgroup_instance_create(
+ e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CROSS),
+ e_data.particle_format);
+ DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp);
+ DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
+ DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1);
+ break;
+ case PART_DRAW_CIRC:
+ shgrp = DRW_shgroup_instance_create(
+ e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CIRC),
+ e_data.particle_format);
+ DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp);
+ DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
+ DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[1], 1);
+ break;
+ case PART_DRAW_AXIS:
+ shgrp = DRW_shgroup_instance_create(
+ e_data.part_axis_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_AXIS),
+ e_data.particle_format);
+ DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1);
+ break;
+ default:
+ break;
+ }
+
+ if (shgrp) {
+ if (draw_as != PART_DRAW_DOT) {
+ DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1);
+ DRW_shgroup_instance_batch(shgrp, geom);
+ }
+ }
+ }
+ }
+}
+
+static void OBJECT_cache_populate(void *vedata, Object *ob)
+{
+ OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
+ OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
+ OBJECT_ShadingGroupList *sgl = (ob->dtx & OB_DRAWXRAY) ? &stl->g_data->sgl_ghost : &stl->g_data->sgl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ ModifierData *md = NULL;
+ int theme_id = TH_UNDEFINED;
+
+ /* Handle particles first in case the emitter itself shouldn't be rendered. */
+ if (ob->type == OB_MESH) {
+ OBJECT_cache_populate_particles(ob, psl);
+ }
+
+ if (DRW_object_is_visible_in_active_context(ob) == false) {
+ return;
+ }
+
+ const bool do_outlines = (draw_ctx->v3d->flag & V3D_SELECT_OUTLINE) && ((ob->base_flag & BASE_SELECTED) != 0) &&
+ ((DRW_object_is_renderable(ob) && (ob->dt > OB_WIRE)) || (ob->dt == OB_WIRE));
+ const bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
+ const bool hide_object_extra = (v3d->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_XTRAS) != 0;
+
+ if (do_outlines) {
+ if (!BKE_object_is_in_editmode(ob) && !((ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT))) {
+ struct GPUBatch *geom;
+
+ /* This fixes only the biggest case which is a plane in ortho view. */
+ int flat_axis = 0;
+ bool is_flat_object_viewed_from_side = (rv3d->persp == RV3D_ORTHO) &&
+ DRW_object_is_flat(ob, &flat_axis) &&
+ DRW_object_axis_orthogonal_to_view(ob, flat_axis);
+
+ if (stl->g_data->xray_enabled || is_flat_object_viewed_from_side) {
+ geom = DRW_cache_object_edge_detection_get(ob, NULL);
+ }
+ else {
+ geom = DRW_cache_object_surface_get(ob);
+ }
+
+ if (geom) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_outline_or(stl, theme_id, NULL);
+ if (shgroup != NULL) {
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ }
+ }
+ }
+
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ if (hide_object_extra) {
+ break;
+ }
+ if (ob != draw_ctx->object_edit) {
+ Mesh *me = ob->data;
+ if (me->totedge == 0) {
+ struct GPUBatch *geom = DRW_cache_mesh_verts_get(ob);
+ if (geom) {
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_point_or(sgl, theme_id, sgl->points);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ }
+ else {
+ struct GPUBatch *geom = DRW_cache_mesh_loose_edges_get(ob);
+ if (geom) {
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(sgl, theme_id, sgl->wire);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ }
+ }
+ break;
+ }
+ case OB_SURF:
+ break;
+ case OB_LATTICE:
+ {
+ if (ob != draw_ctx->object_edit && !BKE_object_is_in_editmode(ob)) {
+ if (hide_object_extra) {
+ break;
+ }
+ struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false);
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(sgl, theme_id, sgl->wire);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ break;
+ }
+ case OB_CURVE:
+ {
+ if (ob != draw_ctx->object_edit) {
+ if (hide_object_extra) {
+ break;
+ }
+ struct GPUBatch *geom = DRW_cache_curve_edge_wire_get(ob);
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(sgl, theme_id, sgl->wire);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ break;
+ }
+ case OB_MBALL:
+ {
+ if (ob != draw_ctx->object_edit) {
+ DRW_shgroup_mball_handles(sgl, ob, view_layer);
+ }
+ break;
+ }
+ case OB_LAMP:
+ if (hide_object_extra) {
+ break;
+ }
+ DRW_shgroup_lamp(sgl, ob, view_layer);
+ break;
+ case OB_CAMERA:
+ if (hide_object_extra) {
+ break;
+ }
+ DRW_shgroup_camera(sgl, ob, view_layer);
+ break;
+ case OB_EMPTY:
+ if (hide_object_extra) {
+ break;
+ }
+ DRW_shgroup_empty(sgl, ob, view_layer, rv3d);
+ break;
+ case OB_GPENCIL:
+ if (hide_object_extra) {
+ break;
+ }
+ /* in all modes except object mode hide always */
+ if (draw_ctx->object_mode != OB_MODE_OBJECT) {
+ break;
+ }
+ DRW_shgroup_gpencil(sgl, ob, view_layer);
+ break;
+ case OB_SPEAKER:
+ if (hide_object_extra) {
+ break;
+ }
+ DRW_shgroup_speaker(sgl, ob, view_layer);
+ break;
+ case OB_LIGHTPROBE:
+ if (hide_object_extra) {
+ break;
+ }
+ DRW_shgroup_lightprobe(stl, psl, ob, view_layer);
+ break;
+ case OB_ARMATURE:
+ {
+ if (v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) {
+ break;
+ }
+ bArmature *arm = ob->data;
+ if (arm->edbo == NULL) {
+ if (DRW_state_is_select() || !DRW_pose_mode_armature(ob, draw_ctx->obact)) {
+ DRWArmaturePasses passes = {
+ .bone_solid = sgl->bone_solid,
+ .bone_outline = sgl->bone_outline,
+ .bone_wire = sgl->bone_wire,
+ .bone_envelope = sgl->bone_envelope,
+ .bone_axes = sgl->bone_axes,
+ .relationship_lines = NULL, /* Don't draw relationship lines */
+ };
+ DRW_shgroup_armature_object(ob, view_layer, passes);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (ob->pd && ob->pd->forcefield) {
+ DRW_shgroup_forcefield(sgl, ob, view_layer);
+ }
+
+ if (ob->dt == OB_BOUNDBOX) {
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+ DRW_shgroup_bounds(sgl, ob, theme_id);
+ }
+
+ /* don't show object extras in set's */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROMDUPLI)) == 0) {
+ if ((draw_ctx->object_mode & (OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) == 0) {
+ DRW_shgroup_object_center(stl, ob, view_layer, v3d);
+ }
+
+ if (show_relations && !DRW_state_is_select()) {
+ DRW_shgroup_relationship_lines(sgl, draw_ctx->depsgraph, scene, ob);
+ }
+
+ const bool draw_extra = (ob->dtx != 0);
+ if (draw_extra && (theme_id == TH_UNDEFINED)) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+ uchar color[4];
+ UI_GetThemeColor4ubv(theme_id, color);
+
+ DRW_text_cache_add(
+ dt, ob->obmat[3],
+ ob->id.name + 2, strlen(ob->id.name + 2),
+ 10, 0, DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, color);
+ }
+
+ if ((ob->dtx & OB_TEXSPACE) && ELEM(ob->type, OB_MESH, OB_CURVE, OB_MBALL)) {
+ DRW_shgroup_texture_space(sgl, ob, theme_id);
+ }
+
+ /* Don't draw bounding box again if draw type is bound box. */
+ if (ob->dtx & OB_DRAWBOUNDOX && ob->dt != OB_BOUNDBOX) {
+ DRW_shgroup_bounds(sgl, ob, theme_id);
+ }
+
+ if (ob->dtx & OB_AXIS) {
+ float *color, axes_size = 1.0f;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ DRW_shgroup_call_dynamic_add(sgl->empty_axes, color, &axes_size, ob->obmat);
+ }
+
+ if ((md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
+ (((SmokeModifierData *)md)->domain != NULL))
+ {
+ DRW_shgroup_volume_extra(sgl, ob, view_layer, scene, md);
+ }
+ }
+}
+
+static void OBJECT_cache_finish(void *vedata)
+{
+ OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
+
+ DRW_pass_sort_shgroup_z(stl->g_data->sgl.image_empties);
+ DRW_pass_sort_shgroup_z(stl->g_data->sgl_ghost.image_empties);
+}
+
+static void OBJECT_draw_scene(void *vedata)
+{
+ OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
+ OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
+ OBJECT_FramebufferList *fbl = ((OBJECT_Data *)vedata)->fbl;
+ OBJECT_PrivateData *g_data = stl->g_data;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ int id_ct_select = g_data->id_ofs_select;
+ int id_ct_active = g_data->id_ofs_active;
+ int id_ct_transform = g_data->id_ofs_transform;
+
+ int id_ct_prb_select = g_data->id_ofs_prb_select;
+ int id_ct_prb_active = g_data->id_ofs_prb_active;
+ int id_ct_prb_transform = g_data->id_ofs_prb_transform;
+
+ int outline_calls = id_ct_select + id_ct_active + id_ct_transform;
+ outline_calls += id_ct_prb_select + id_ct_prb_active + id_ct_prb_transform;
+
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+// DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
+
+ /* This needs to be drawn after the oultine */
+ DRW_draw_pass(stl->g_data->sgl.spot_shapes);
+ DRW_draw_pass(stl->g_data->sgl.bone_solid);
+ DRW_draw_pass(stl->g_data->sgl.bone_wire);
+ DRW_draw_pass(stl->g_data->sgl.bone_outline);
+ DRW_draw_pass(stl->g_data->sgl.non_meshes);
+ DRW_draw_pass(psl->particle);
+ DRW_draw_pass(stl->g_data->sgl.image_empties);
+ DRW_draw_pass(stl->g_data->sgl.bone_axes);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl)
+
+ if (DRW_state_is_fbo() && outline_calls > 0) {
+ DRW_stats_group_start("Outlines");
+
+ g_data->id_ofs_active = 1;
+ g_data->id_ofs_select = g_data->id_ofs_active + id_ct_active + id_ct_prb_active + 1;
+ g_data->id_ofs_transform = g_data->id_ofs_select + id_ct_select + id_ct_prb_select + 1;
+
+ g_data->id_ofs_prb_active = g_data->id_ofs_active + id_ct_active;
+ g_data->id_ofs_prb_select = g_data->id_ofs_select + id_ct_select;
+ g_data->id_ofs_prb_transform = g_data->id_ofs_transform + id_ct_transform;
+
+ /* Render filled polygon on a separate framebuffer */
+ GPU_framebuffer_bind(fbl->outlines_fb);
+ GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f);
+ DRW_draw_pass(psl->outlines);
+ DRW_draw_pass(psl->lightprobes);
+
+ /* Search outline pixels */
+ GPU_framebuffer_bind(fbl->blur_fb);
+ DRW_draw_pass(psl->outlines_search);
+
+ /* Expand outline to form a 3px wide line */
+ GPU_framebuffer_bind(fbl->expand_fb);
+ DRW_draw_pass(psl->outlines_expand);
+
+ /* Bleed color so the AA can do it's stuff */
+ GPU_framebuffer_bind(fbl->blur_fb);
+ DRW_draw_pass(psl->outlines_bleed);
+
+ /* restore main framebuffer */
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_stats_group_end();
+ }
+ else if (DRW_state_is_select()) {
+ /* Render probes spheres/planes so we can select them. */
+ DRW_draw_pass(psl->lightprobes);
+ }
+
+ if (DRW_state_is_fbo()) {
+ if (e_data.draw_grid) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->grid);
+ }
+
+ /* Combine with scene buffer last */
+ if (outline_calls > 0) {
+ DRW_draw_pass(psl->outlines_resolve);
+ }
+ }
+
+ volumes_free_smoke_textures();
+ batch_camera_path_free(&stl->g_data->sgl.camera_path);
+
+ if (!DRW_pass_is_empty(stl->g_data->sgl_ghost.bone_solid) ||
+ !DRW_pass_is_empty(stl->g_data->sgl_ghost.bone_wire) ||
+ !DRW_pass_is_empty(stl->g_data->sgl_ghost.bone_outline) ||
+ !DRW_pass_is_empty(stl->g_data->sgl_ghost.non_meshes) ||
+ !DRW_pass_is_empty(stl->g_data->sgl_ghost.image_empties) ||
+ !DRW_pass_is_empty(stl->g_data->sgl_ghost.bone_axes))
+ {
+ if (DRW_state_is_fbo()) {
+ /* meh, late init to not request a depth buffer we won't use. */
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ GPUTexture *ghost_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_object_type);
+ GPU_framebuffer_ensure_config(&fbl->ghost_fb, {
+ GPU_ATTACHMENT_TEXTURE(ghost_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color),
+ });
+
+ GPU_framebuffer_bind(fbl->ghost_fb);
+ GPU_framebuffer_clear_depth(fbl->ghost_fb, 1.0f);
+ }
+ else if (DRW_state_is_select()) {
+ /* XXX `GPU_depth_range` is not a perfect solution
+ * since very distant geometries can still be occluded.
+ * Also the depth test precision of these geometries is impaired.
+ * However solves the selection for the vast majority of cases. */
+ GPU_depth_range(0.0f, 0.01f);
+ }
+
+ DRW_draw_pass(stl->g_data->sgl_ghost.spot_shapes);
+ DRW_draw_pass(stl->g_data->sgl_ghost.bone_solid);
+ DRW_draw_pass(stl->g_data->sgl_ghost.bone_wire);
+ DRW_draw_pass(stl->g_data->sgl_ghost.bone_outline);
+ DRW_draw_pass(stl->g_data->sgl_ghost.non_meshes);
+ DRW_draw_pass(stl->g_data->sgl_ghost.image_empties);
+ DRW_draw_pass(stl->g_data->sgl_ghost.bone_axes);
+
+ if (DRW_state_is_select()) {
+ GPU_depth_range(0.0f, 1.0f);
+ }
+ }
+
+ batch_camera_path_free(&stl->g_data->sgl_ghost.camera_path);
+
+ DRW_draw_pass(psl->ob_center);
+}
+
+static const DrawEngineDataSize OBJECT_data_size = DRW_VIEWPORT_DATA_SIZE(OBJECT_Data);
+
+DrawEngineType draw_engine_object_type = {
+ NULL, NULL,
+ N_("ObjectMode"),
+ &OBJECT_data_size,
+ &OBJECT_engine_init,
+ &OBJECT_engine_free,
+ &OBJECT_cache_init,
+ &OBJECT_cache_populate,
+ &OBJECT_cache_finish,
+ NULL,
+ &OBJECT_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c
new file mode 100644
index 00000000000..460b3d4240a
--- /dev/null
+++ b/source/blender/draw/modes/overlay_mode.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file overlay_mode.c
+ * \ingroup draw_engine
+ */
+
+#include "DNA_view3d_types.h"
+
+#include "BKE_object.h"
+
+#include "GPU_shader.h"
+#include "GPU_extensions.h"
+#include "DRW_render.h"
+
+#include "draw_mode_engines.h"
+
+/* Structures */
+typedef struct OVERLAY_StorageList {
+ struct OVERLAY_PrivateData *g_data;
+} OVERLAY_StorageList;
+
+typedef struct OVERLAY_PassList {
+ struct DRWPass *face_orientation_pass;
+ struct DRWPass *flat_wireframe_pass;
+ struct DRWPass *face_wireframe_pass;
+ struct DRWPass *face_wireframe_full_pass;
+} OVERLAY_PassList;
+
+typedef struct OVERLAY_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ OVERLAY_PassList *psl;
+ OVERLAY_StorageList *stl;
+} OVERLAY_Data;
+
+typedef struct OVERLAY_PrivateData {
+ DRWShadingGroup *face_orientation_shgrp;
+ DRWShadingGroup *sculpt_wires_full;
+ DRWShadingGroup *sculpt_wires;
+ View3DOverlay overlay;
+ float wire_step_param[2];
+ bool ghost_stencil_test;
+ bool show_overlays;
+} OVERLAY_PrivateData; /* Transient data */
+
+/* *********** STATIC *********** */
+static struct {
+ /* Face orientation shader */
+ struct GPUShader *face_orientation_sh;
+ /* Wireframe shader */
+ struct GPUShader *select_wireframe_sh;
+ struct GPUShader *face_wireframe_sh;
+ struct GPUShader *face_wireframe_pretty_sh;
+ struct GPUShader *face_wireframe_sculpt_sh;
+ struct GPUShader *face_wireframe_sculpt_pretty_sh;
+} e_data = {NULL};
+
+/* Shaders */
+extern char datatoc_overlay_face_orientation_frag_glsl[];
+extern char datatoc_overlay_face_orientation_vert_glsl[];
+
+extern char datatoc_overlay_face_wireframe_vert_glsl[];
+extern char datatoc_overlay_face_wireframe_geom_glsl[];
+extern char datatoc_overlay_face_wireframe_frag_glsl[];
+
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* Functions */
+static void overlay_engine_init(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_StorageList *stl = data->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+ stl->g_data->ghost_stencil_test = false;
+
+ if (!e_data.face_orientation_sh) {
+ /* Face orientation */
+ e_data.face_orientation_sh = DRW_shader_create(
+ datatoc_overlay_face_orientation_vert_glsl, NULL,
+ datatoc_overlay_face_orientation_frag_glsl, NULL);
+ }
+
+ if (!e_data.face_wireframe_sh) {
+ bool use_geom = GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY);
+
+ e_data.select_wireframe_sh = DRW_shader_create(
+ datatoc_overlay_face_wireframe_vert_glsl,
+ datatoc_overlay_face_wireframe_geom_glsl,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ "#define SELECT_EDGES\n"
+ "#define LIGHT_EDGES\n"
+ "#define USE_GEOM_SHADER\n");
+
+ e_data.face_wireframe_sh = DRW_shader_create(
+ datatoc_overlay_face_wireframe_vert_glsl,
+ use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ use_geom ? "#define USE_GEOM_SHADER\n"
+ : NULL);
+
+ e_data.face_wireframe_pretty_sh = DRW_shader_create(
+ datatoc_overlay_face_wireframe_vert_glsl,
+ use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ use_geom ? "#define USE_GEOM_SHADER\n"
+ "#define LIGHT_EDGES\n"
+ : "#define LIGHT_EDGES\n");
+
+ e_data.face_wireframe_sculpt_sh = DRW_shader_create(
+ datatoc_overlay_face_wireframe_vert_glsl,
+ datatoc_overlay_face_wireframe_geom_glsl,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ "#define USE_SCULPT\n"
+ "#define USE_GEOM_SHADER\n");
+
+ e_data.face_wireframe_sculpt_pretty_sh = DRW_shader_create(
+ datatoc_overlay_face_wireframe_vert_glsl,
+ datatoc_overlay_face_wireframe_geom_glsl,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ "#define USE_SCULPT\n"
+ "#define USE_GEOM_SHADER\n"
+ "#define LIGHT_EDGES\n");
+ }
+}
+
+static void overlay_cache_init(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PassList *psl = data->psl;
+ OVERLAY_StorageList *stl = data->stl;
+
+ const DRWContextState *DCS = DRW_context_state_get();
+
+ View3D *v3d = DCS->v3d;
+ if (v3d) {
+ stl->g_data->overlay = v3d->overlay;
+ stl->g_data->show_overlays = (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0;
+ }
+ else {
+ memset(&stl->g_data->overlay, 0, sizeof(stl->g_data->overlay));
+ stl->g_data->show_overlays = false;
+ }
+
+ if (stl->g_data->show_overlays == false) {
+ stl->g_data->overlay.flag = 0;
+ }
+
+ if (v3d->shading.type == OB_WIRE) {
+ stl->g_data->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
+ stl->g_data->show_overlays = true;
+ }
+
+ {
+ /* Face Orientation Pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND;
+ psl->face_orientation_pass = DRW_pass_create("Face Orientation", state);
+ stl->g_data->face_orientation_shgrp = DRW_shgroup_create(
+ e_data.face_orientation_sh, psl->face_orientation_pass);
+ }
+
+ {
+ /* Wireframe */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
+ float wire_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f;
+
+ psl->flat_wireframe_pass = DRW_pass_create("Flat Object Wires", state | DRW_STATE_WRITE_DEPTH);
+
+ psl->face_wireframe_full_pass = DRW_pass_create("All Face Wires", state);
+
+ stl->g_data->sculpt_wires_full = DRW_shgroup_create(e_data.face_wireframe_sculpt_sh, psl->face_wireframe_full_pass);
+ DRW_shgroup_uniform_float_copy(stl->g_data->sculpt_wires_full, "wireSize", wire_size);
+
+ DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.face_wireframe_sh, psl->face_wireframe_full_pass);
+ DRW_shgroup_uniform_float_copy(shgrp, "wireSize", wire_size);
+
+ psl->face_wireframe_pass = DRW_pass_create("Face Wires", state);
+
+ stl->g_data->sculpt_wires = DRW_shgroup_create(e_data.face_wireframe_sculpt_pretty_sh, psl->face_wireframe_pass);
+ DRW_shgroup_uniform_vec2(stl->g_data->sculpt_wires, "wireStepParam", stl->g_data->wire_step_param, 1);
+ DRW_shgroup_uniform_float_copy(stl->g_data->sculpt_wires, "wireSize", wire_size);
+
+ shgrp = DRW_shgroup_create(e_data.face_wireframe_pretty_sh, psl->face_wireframe_pass);
+ DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", stl->g_data->wire_step_param, 1);
+ DRW_shgroup_uniform_float_copy(shgrp, "wireSize", wire_size);
+
+ /**
+ * The wireframe threshold ranges from 0.0 to 1.0
+ * When 1.0 we show all the edges, when 0.5 we show as many as 2.7.
+ *
+ * If we wanted 0.0 to match 2.7, factor would need to be 0.003f.
+ * The range controls the falloff effect. If range was 0.0f we would get a hard cut (as in 2.7).
+ * That said we are using a different algorithm so the results will always differ.
+ */
+ const float factor = 0.0045f;
+ const float range = 0.00125f;
+ stl->g_data->wire_step_param[1] = (1.0f - factor) + stl->g_data->overlay.wireframe_threshold * factor;
+ stl->g_data->wire_step_param[0] = stl->g_data->wire_step_param[1] + range;
+ }
+}
+
+static void overlay_cache_populate(void *vedata, Object *ob)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_StorageList *stl = data->stl;
+ OVERLAY_PrivateData *pd = stl->g_data;
+ OVERLAY_PassList *psl = data->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ View3D *v3d = draw_ctx->v3d;
+
+ if ((!stl->g_data->show_overlays) ||
+ (ob->dt < OB_WIRE) ||
+ (!DRW_object_is_renderable(ob) && (ob->dt != OB_WIRE)))
+ {
+ return;
+ }
+
+ if (DRW_object_is_renderable(ob) && stl->g_data->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) {
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(pd->face_orientation_shgrp, geom, ob->obmat);
+ }
+ }
+
+ if ((stl->g_data->overlay.flag & V3D_OVERLAY_WIREFRAMES) ||
+ (v3d->shading.type == OB_WIRE) ||
+ (ob->dtx & OB_DRAWWIRE) ||
+ (ob->dt == OB_WIRE))
+ {
+ /* Don't do that in edit Mesh mode. */
+ if (((ob != draw_ctx->object_edit) && !BKE_object_is_in_editmode(ob)) || ob->type != OB_MESH) {
+ const bool is_active = (ob == draw_ctx->obact);
+ const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0;
+ const bool all_wires = (stl->g_data->overlay.wireframe_threshold == 1.0f) ||
+ (ob->dtx & OB_DRAW_ALL_EDGES);
+ const bool is_wire = (ob->dt < OB_SOLID);
+ const int stencil_mask = (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF;
+ DRWShadingGroup *shgrp = NULL;
+
+ /* This fixes only the biggest case which is a plane in ortho view. */
+ int flat_axis = 0;
+ bool is_flat_object_viewed_from_side = (rv3d->persp == RV3D_ORTHO) &&
+ DRW_object_is_flat(ob, &flat_axis) &&
+ DRW_object_axis_orthogonal_to_view(ob, flat_axis);
+
+ if (is_sculpt_mode) {
+ shgrp = (all_wires || DRW_object_is_flat_normal(ob))
+ ? stl->g_data->sculpt_wires_full
+ : stl->g_data->sculpt_wires;
+ if (is_wire) {
+ shgrp = DRW_shgroup_create_sub(shgrp);
+ }
+ DRW_shgroup_call_sculpt_add(shgrp, ob, ob->obmat);
+ }
+ else if (is_flat_object_viewed_from_side) {
+ /* Avoid losing flat objects when in ortho views (see T56549) */
+ struct GPUBatch *geom = DRW_cache_object_wire_outline_get(ob);
+ if (geom) {
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ shgrp = DRW_shgroup_create(sh, psl->flat_wireframe_pass);
+ DRW_shgroup_stencil_mask(shgrp, stencil_mask);
+ DRW_shgroup_uniform_vec4(shgrp, "color", ts.colorWire, 1);
+ DRW_shgroup_call_object_add(shgrp, geom, ob);
+ }
+ }
+ else {
+ int tri_count;
+ GPUTexture *verts = NULL, *faceids;
+ DRW_cache_object_face_wireframe_get(ob, &verts, &faceids, &tri_count);
+ if (verts) {
+ float *rim_col = ts.colorWire;
+ if ((ob->base_flag & BASE_SELECTED) != 0) {
+ rim_col = (ob == draw_ctx->obact) ? ts.colorActive : ts.colorSelect;
+ }
+ DRWPass *pass = (all_wires) ? psl->face_wireframe_full_pass : psl->face_wireframe_pass;
+ GPUShader *sh = (all_wires) ? e_data.face_wireframe_sh : e_data.face_wireframe_pretty_sh;
+
+ if ((DRW_state_is_select() || DRW_state_is_depth())) {
+ static float params[2] = {1.2f, 1.0f}; /* Parameters for all wires */
+
+ sh = e_data.select_wireframe_sh;
+ shgrp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", (all_wires)
+ ? params
+ : stl->g_data->wire_step_param, 1);
+ DRW_shgroup_uniform_texture(shgrp, "vertData", verts);
+ DRW_shgroup_uniform_texture(shgrp, "faceIds", faceids);
+ DRW_shgroup_call_object_procedural_triangles_culled_add(shgrp, tri_count, ob);
+ }
+ else {
+ shgrp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_stencil_mask(shgrp, stencil_mask);
+ DRW_shgroup_uniform_texture(shgrp, "vertData", verts);
+ DRW_shgroup_uniform_texture(shgrp, "faceIds", faceids);
+ DRW_shgroup_uniform_vec3(shgrp, "wireColor", ts.colorWire, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1);
+ DRW_shgroup_call_object_procedural_triangles_culled_add(shgrp, tri_count, ob);
+ }
+ }
+ }
+
+ if (is_wire && shgrp != NULL) {
+ /* If object is wireframe, don't try to use stencil test. */
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_STENCIL_EQUAL);
+
+ if (ob->dtx & OB_DRAWXRAY) {
+ DRW_shgroup_state_disable(shgrp, DRW_STATE_DEPTH_LESS_EQUAL);
+ }
+ }
+ else if ((ob->dtx & OB_DRAWXRAY) && shgrp != NULL) {
+ stl->g_data->ghost_stencil_test = true;
+ }
+ }
+ }
+}
+
+static void overlay_cache_finish(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PassList *psl = data->psl;
+ OVERLAY_StorageList *stl = data->stl;
+
+ const DRWContextState *ctx = DRW_context_state_get();
+ View3D *v3d = ctx->v3d;
+
+ /* only in solid mode */
+ if (v3d->shading.type == OB_SOLID && (v3d->shading.flag & XRAY_FLAG(v3d)) == 0) {
+ if (stl->g_data->ghost_stencil_test) {
+ DRW_pass_state_add(psl->face_wireframe_pass, DRW_STATE_STENCIL_EQUAL);
+ DRW_pass_state_add(psl->face_wireframe_full_pass, DRW_STATE_STENCIL_EQUAL);
+ }
+ }
+}
+
+static void overlay_draw_scene(void *vedata)
+{
+ OVERLAY_Data *data = vedata;
+ OVERLAY_PassList *psl = data->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+ DRW_draw_pass(psl->face_orientation_pass);
+ DRW_draw_pass(psl->flat_wireframe_pass);
+ DRW_draw_pass(psl->face_wireframe_pass);
+ DRW_draw_pass(psl->face_wireframe_full_pass);
+}
+
+static void overlay_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.face_orientation_sh);
+ DRW_SHADER_FREE_SAFE(e_data.select_wireframe_sh);
+ DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sh);
+ DRW_SHADER_FREE_SAFE(e_data.face_wireframe_pretty_sh);
+ DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sculpt_sh);
+ DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sculpt_pretty_sh);
+}
+
+static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data);
+
+DrawEngineType draw_engine_overlay_type = {
+ NULL, NULL,
+ N_("OverlayEngine"),
+ &overlay_data_size,
+ &overlay_engine_init,
+ &overlay_engine_free,
+ &overlay_cache_init,
+ &overlay_cache_populate,
+ &overlay_cache_finish,
+ NULL,
+ &overlay_draw_scene,
+ NULL,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c
new file mode 100644
index 00000000000..10b42c76b14
--- /dev/null
+++ b/source/blender/draw/modes/paint_texture_mode.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/paint_texture_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BIF_gl.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "DNA_mesh_types.h"
+
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_paint_texture_vert_glsl[];
+extern char datatoc_paint_texture_frag_glsl[];
+extern char datatoc_paint_wire_vert_glsl[];
+extern char datatoc_paint_wire_frag_glsl[];
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use PAINT_TEXTURE_engine_init() to
+ * initialize most of them and PAINT_TEXTURE_cache_init()
+ * for PAINT_TEXTURE_PassList */
+
+typedef struct PAINT_TEXTURE_PassList {
+ /* Declare all passes here and init them in
+ * PAINT_TEXTURE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *image_faces;
+
+ struct DRWPass *wire_overlay;
+ struct DRWPass *face_overlay;
+} PAINT_TEXTURE_PassList;
+
+typedef struct PAINT_TEXTURE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} PAINT_TEXTURE_FramebufferList;
+
+typedef struct PAINT_TEXTURE_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} PAINT_TEXTURE_TextureList;
+
+typedef struct PAINT_TEXTURE_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct PAINT_TEXTURE_PrivateData *g_data;
+} PAINT_TEXTURE_StorageList;
+
+typedef struct PAINT_TEXTURE_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ PAINT_TEXTURE_FramebufferList *fbl;
+ PAINT_TEXTURE_TextureList *txl;
+ PAINT_TEXTURE_PassList *psl;
+ PAINT_TEXTURE_StorageList *stl;
+} PAINT_TEXTURE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in PAINT_TEXTURE_engine_init();
+ * free in PAINT_TEXTURE_engine_free(); */
+ struct GPUShader *fallback_sh;
+ struct GPUShader *image_sh;
+
+ struct GPUShader *wire_overlay_shader;
+ struct GPUShader *face_overlay_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PAINT_TEXTURE_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in PAINT_TEXTURE_cache_populate() */
+ DRWShadingGroup *shgroup_fallback;
+ DRWShadingGroup **shgroup_image_array;
+
+ /* face-mask */
+ DRWShadingGroup *lwire_shgrp;
+ DRWShadingGroup *face_shgrp;
+} PAINT_TEXTURE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void PAINT_TEXTURE_engine_init(void *vedata)
+{
+ PAINT_TEXTURE_TextureList *txl = ((PAINT_TEXTURE_Data *)vedata)->txl;
+ PAINT_TEXTURE_FramebufferList *fbl = ((PAINT_TEXTURE_Data *)vedata)->fbl;
+ PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.fallback_sh) {
+ e_data.fallback_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+ if (!e_data.image_sh) {
+ e_data.image_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ e_data.image_sh = DRW_shader_create_with_lib(
+ datatoc_paint_texture_vert_glsl, NULL,
+ datatoc_paint_texture_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+
+ }
+
+ if (!e_data.wire_overlay_shader) {
+ e_data.wire_overlay_shader = DRW_shader_create_with_lib(
+ datatoc_paint_wire_vert_glsl, NULL,
+ datatoc_paint_wire_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define VERTEX_MODE\n");
+ }
+
+ if (!e_data.face_overlay_shader) {
+ e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void PAINT_TEXTURE_cache_init(void *vedata)
+{
+ PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
+ PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ stl->g_data->shgroup_image_array = NULL;
+ }
+
+ {
+ /* Create a pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND;
+ psl->image_faces = DRW_pass_create("Image Color Pass", state);
+
+ stl->g_data->shgroup_fallback = DRW_shgroup_create(e_data.fallback_sh, psl->image_faces);
+
+ /* Uniforms need a pointer to it's value so be sure it's accessible at
+ * any given time (i.e. use static vars) */
+ static float color[4] = {1.0f, 0.0f, 1.0f, 1.0};
+ DRW_shgroup_uniform_vec4(stl->g_data->shgroup_fallback, "color", color, 1);
+
+ MEM_SAFE_FREE(stl->g_data->shgroup_image_array);
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Object *ob = draw_ctx->obact;
+ if (ob && ob->type == OB_MESH) {
+ Scene *scene = draw_ctx->scene;
+ const bool use_material_slots = (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
+ const Mesh *me = ob->data;
+
+ stl->g_data->shgroup_image_array = MEM_mallocN(
+ sizeof(*stl->g_data->shgroup_image_array) * (use_material_slots ? me->totcol : 1), __func__);
+
+ if (use_material_slots) {
+ for (int i = 0; i < me->totcol; i++) {
+ Material *ma = give_current_material(ob, i + 1);
+ Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
+ GPUTexture *tex = ima ?
+ GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, 0.0f) : NULL;
+
+ if (tex) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ stl->g_data->shgroup_image_array[i] = grp;
+ }
+ else {
+ stl->g_data->shgroup_image_array[i] = NULL;
+ }
+ }
+ }
+ else {
+ Image *ima = scene->toolsettings->imapaint.canvas;
+ GPUTexture *tex = ima ?
+ GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, 0.0f) : NULL;
+
+ if (tex) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ stl->g_data->shgroup_image_array[0] = grp;
+ }
+ else {
+ stl->g_data->shgroup_image_array[0] = NULL;
+ }
+ }
+ }
+ }
+
+ /* Face Mask */
+ {
+ psl->wire_overlay = DRW_pass_create(
+ "Wire Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ DRW_shgroup_uniform_block(stl->g_data->lwire_shgrp, "globalsBlock", globals_ubo);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+
+ stl->g_data->face_shgrp = DRW_shgroup_create(e_data.face_overlay_shader, psl->face_overlay);
+
+ static float col[4] = {1.0f, 1.0f, 1.0f, 0.2f};
+ DRW_shgroup_uniform_vec4(stl->g_data->face_shgrp, "color", col, 1);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob)
+{
+ PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
+ PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ UNUSED_VARS(psl, stl);
+
+ if ((ob->type == OB_MESH) && (draw_ctx->obact == ob)) {
+ /* Get geometry cache */
+ const Mesh *me = ob->data;
+ Scene *scene = draw_ctx->scene;
+ const bool use_surface = draw_ctx->v3d->overlay.texture_paint_mode_opacity != 0.0; //DRW_object_is_mode_shade(ob) == true;
+ const bool use_material_slots = (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ bool ok = false;
+
+ if (use_surface) {
+ if (me->mloopuv != NULL) {
+ if (use_material_slots || use_face_sel) {
+ struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob, use_face_sel) : NULL;
+ if ((me->totcol == 0) || (geom_array == NULL)) {
+ struct GPUBatch *geom = DRW_cache_mesh_surface_get(ob, use_face_sel);
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat);
+ ok = true;
+ }
+ else {
+ for (int i = 0; i < me->totcol; i++) {
+ const int index = use_material_slots ? i : 0;
+ if (stl->g_data->shgroup_image_array[index]) {
+ DRW_shgroup_call_add(stl->g_data->shgroup_image_array[index], geom_array[i], ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom_array[i], ob->obmat);
+ }
+ ok = true;
+ }
+ }
+ }
+ else {
+ struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
+ if (geom && stl->g_data->shgroup_image_array[0]) {
+ DRW_shgroup_call_add(stl->g_data->shgroup_image_array[0], geom, ob->obmat);
+ ok = true;
+ }
+ }
+ }
+
+ if (!ok) {
+ struct GPUBatch *geom = DRW_cache_mesh_surface_get(ob, use_face_sel);
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat);
+ }
+ }
+
+ /* Face Mask */
+ if (use_face_sel) {
+ struct GPUBatch *geom;
+ /* Note: ideally selected faces wouldn't show interior wire. */
+ const bool use_wire = true;
+ geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel);
+ DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat);
+
+ geom = DRW_cache_mesh_faces_weight_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void PAINT_TEXTURE_cache_finish(void *vedata)
+{
+ PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
+ PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
+
+ /* Do something here! dependent on the objects gathered */
+ UNUSED_VARS(psl);
+
+ MEM_SAFE_FREE(stl->g_data->shgroup_image_array);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void PAINT_TEXTURE_draw_scene(void *vedata)
+{
+ PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
+ PAINT_TEXTURE_FramebufferList *fbl = ((PAINT_TEXTURE_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl, dfbl, dtxl);
+
+ DRW_draw_pass(psl->image_faces);
+
+ DRW_draw_pass(psl->face_overlay);
+ DRW_draw_pass(psl->wire_overlay);
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void PAINT_TEXTURE_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.image_sh);
+ DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader);
+}
+
+static const DrawEngineDataSize PAINT_TEXTURE_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_TEXTURE_Data);
+
+DrawEngineType draw_engine_paint_texture_type = {
+ NULL, NULL,
+ N_("PaintTextureMode"),
+ &PAINT_TEXTURE_data_size,
+ &PAINT_TEXTURE_engine_init,
+ &PAINT_TEXTURE_engine_free,
+ &PAINT_TEXTURE_cache_init,
+ &PAINT_TEXTURE_cache_populate,
+ &PAINT_TEXTURE_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &PAINT_TEXTURE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c
new file mode 100644
index 00000000000..d026e7a7924
--- /dev/null
+++ b/source/blender/draw/modes/paint_vertex_mode.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/paint_vertex_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern char datatoc_paint_vertex_vert_glsl[];
+extern char datatoc_paint_vertex_frag_glsl[];
+extern char datatoc_paint_wire_vert_glsl[];
+extern char datatoc_paint_wire_frag_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+
+/* *********** LISTS *********** */
+
+typedef struct PAINT_VERTEX_PassList {
+ struct DRWPass *vcolor_faces;
+ struct DRWPass *wire_overlay;
+ struct DRWPass *face_overlay;
+} PAINT_VERTEX_PassList;
+
+typedef struct PAINT_VERTEX_StorageList {
+ struct PAINT_VERTEX_PrivateData *g_data;
+} PAINT_VERTEX_StorageList;
+
+typedef struct PAINT_VERTEX_Data {
+ void *engine_type; /* Required */
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ PAINT_VERTEX_PassList *psl;
+ PAINT_VERTEX_StorageList *stl;
+} PAINT_VERTEX_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ struct GPUShader *vcolor_face_shader;
+ struct GPUShader *wire_overlay_shader;
+ struct GPUShader *face_overlay_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PAINT_VERTEX_PrivateData {
+ DRWShadingGroup *fvcolor_shgrp;
+ DRWShadingGroup *lwire_shgrp;
+ DRWShadingGroup *face_shgrp;
+} PAINT_VERTEX_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+static void PAINT_VERTEX_engine_init(void *UNUSED(vedata))
+{
+ if (!e_data.vcolor_face_shader) {
+ e_data.vcolor_face_shader = DRW_shader_create(
+ datatoc_paint_vertex_vert_glsl, NULL,
+ datatoc_paint_vertex_frag_glsl, NULL);
+
+ e_data.wire_overlay_shader = DRW_shader_create_with_lib(
+ datatoc_paint_wire_vert_glsl, NULL,
+ datatoc_paint_wire_frag_glsl,
+ datatoc_common_globals_lib_glsl, "#define VERTEX_MODE\n");
+
+ e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+static void PAINT_VERTEX_cache_init(void *vedata)
+{
+ PAINT_VERTEX_PassList *psl = ((PAINT_VERTEX_Data *)vedata)->psl;
+ PAINT_VERTEX_StorageList *stl = ((PAINT_VERTEX_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ psl->vcolor_faces = DRW_pass_create(
+ "Vert Color Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_MULTIPLY);
+
+ stl->g_data->fvcolor_shgrp = DRW_shgroup_create(e_data.vcolor_face_shader, psl->vcolor_faces);
+ DRW_shgroup_uniform_float_copy(stl->g_data->fvcolor_shgrp, "white_factor", 1.0f - v3d->overlay.vertex_paint_mode_opacity);
+ }
+
+ {
+ psl->wire_overlay = DRW_pass_create(
+ "Wire Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ DRW_shgroup_uniform_block(stl->g_data->lwire_shgrp, "globalsBlock", globals_ubo);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+
+ stl->g_data->face_shgrp = DRW_shgroup_create(e_data.face_overlay_shader, psl->face_overlay);
+
+ static float col[4] = {1.0f, 1.0f, 1.0f, 0.2f};
+ DRW_shgroup_uniform_vec4(stl->g_data->face_shgrp, "color", col, 1);
+ }
+}
+
+static void PAINT_VERTEX_cache_populate(void *vedata, Object *ob)
+{
+ PAINT_VERTEX_StorageList *stl = ((PAINT_VERTEX_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+
+ if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) {
+ /* We're always painting on original, display original data. */
+ ob = DEG_get_original_object(ob);
+ const Mesh *me = ob->data;
+ const bool use_wire = (v3d->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
+ const bool use_surface = v3d->overlay.vertex_paint_mode_opacity != 0.0f;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ struct GPUBatch *geom;
+
+ if (use_surface) {
+ geom = DRW_cache_mesh_surface_vert_colors_get(ob);
+ DRW_shgroup_call_add(stl->g_data->fvcolor_shgrp, geom, ob->obmat);
+ }
+
+ if (use_face_sel || use_wire) {
+ geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel);
+ DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat);
+ }
+
+ if (use_face_sel) {
+ geom = DRW_cache_mesh_faces_weight_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+static void PAINT_VERTEX_draw_scene(void *vedata)
+{
+ PAINT_VERTEX_PassList *psl = ((PAINT_VERTEX_Data *)vedata)->psl;
+
+ DRW_draw_pass(psl->vcolor_faces);
+ DRW_draw_pass(psl->face_overlay);
+ DRW_draw_pass(psl->wire_overlay);
+}
+
+static void PAINT_VERTEX_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.vcolor_face_shader);
+ DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader);
+}
+
+static const DrawEngineDataSize PAINT_VERTEX_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_VERTEX_Data);
+
+DrawEngineType draw_engine_paint_vertex_type = {
+ NULL, NULL,
+ N_("PaintVertexMode"),
+ &PAINT_VERTEX_data_size,
+ &PAINT_VERTEX_engine_init,
+ &PAINT_VERTEX_engine_free,
+ &PAINT_VERTEX_cache_init,
+ &PAINT_VERTEX_cache_populate,
+ NULL,
+ NULL,
+ &PAINT_VERTEX_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/paint_weight_mode.c b/source/blender/draw/modes/paint_weight_mode.c
new file mode 100644
index 00000000000..9060a97f412
--- /dev/null
+++ b/source/blender/draw/modes/paint_weight_mode.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/paint_weight_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_mesh.h"
+
+#include "DEG_depsgraph_query.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern struct GPUTexture *globals_weight_ramp; /* draw_common.c */
+
+extern char datatoc_paint_weight_vert_glsl[];
+extern char datatoc_paint_weight_frag_glsl[];
+extern char datatoc_paint_wire_vert_glsl[];
+extern char datatoc_paint_wire_frag_glsl[];
+extern char datatoc_paint_vert_frag_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+
+/* *********** LISTS *********** */
+
+typedef struct PAINT_WEIGHT_PassList {
+ struct DRWPass *weight_faces;
+ struct DRWPass *wire_overlay;
+ struct DRWPass *face_overlay;
+ struct DRWPass *vert_overlay;
+} PAINT_WEIGHT_PassList;
+
+typedef struct PAINT_WEIGHT_StorageList {
+ struct PAINT_WEIGHT_PrivateData *g_data;
+} PAINT_WEIGHT_StorageList;
+
+typedef struct PAINT_WEIGHT_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ PAINT_WEIGHT_PassList *psl;
+ PAINT_WEIGHT_StorageList *stl;
+} PAINT_WEIGHT_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ struct GPUShader *weight_face_shader;
+ struct GPUShader *wire_overlay_shader;
+ struct GPUShader *face_overlay_shader;
+ struct GPUShader *vert_overlay_shader;
+ int actdef;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PAINT_WEIGHT_PrivateData {
+ DRWShadingGroup *fweights_shgrp;
+ DRWShadingGroup *lwire_shgrp;
+ DRWShadingGroup *face_shgrp;
+ DRWShadingGroup *vert_shgrp;
+} PAINT_WEIGHT_PrivateData;
+
+/* *********** FUNCTIONS *********** */
+
+static void PAINT_WEIGHT_engine_init(void *UNUSED(vedata))
+{
+ if (!e_data.weight_face_shader) {
+ e_data.weight_face_shader = DRW_shader_create_with_lib(
+ datatoc_paint_weight_vert_glsl, NULL,
+ datatoc_paint_weight_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+
+ if (!e_data.wire_overlay_shader) {
+ e_data.wire_overlay_shader = DRW_shader_create_with_lib(
+ datatoc_paint_wire_vert_glsl, NULL,
+ datatoc_paint_wire_frag_glsl,
+ datatoc_common_globals_lib_glsl, "#define WEIGHT_MODE\n");
+ }
+
+ if (!e_data.face_overlay_shader) {
+ e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!e_data.vert_overlay_shader) {
+ e_data.vert_overlay_shader = DRW_shader_create_with_lib(
+ datatoc_paint_wire_vert_glsl, NULL,
+ datatoc_paint_vert_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+}
+
+static void PAINT_WEIGHT_cache_init(void *vedata)
+{
+ PAINT_WEIGHT_PassList *psl = ((PAINT_WEIGHT_Data *)vedata)->psl;
+ PAINT_WEIGHT_StorageList *stl = ((PAINT_WEIGHT_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ psl->weight_faces = DRW_pass_create(
+ "Weight Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_MULTIPLY);
+
+ stl->g_data->fweights_shgrp = DRW_shgroup_create(e_data.weight_face_shader, psl->weight_faces);
+
+ DRW_shgroup_uniform_bool_copy(stl->g_data->fweights_shgrp, "drawContours", (v3d->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0);
+
+ DRW_shgroup_uniform_float(stl->g_data->fweights_shgrp, "opacity", &v3d->overlay.weight_paint_mode_opacity, 1);
+ DRW_shgroup_uniform_texture(stl->g_data->fweights_shgrp, "colorramp", globals_weight_ramp);
+ DRW_shgroup_uniform_block(stl->g_data->fweights_shgrp, "globalsBlock", globals_ubo);
+ }
+
+ {
+ psl->wire_overlay = DRW_pass_create(
+ "Wire Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ DRW_shgroup_uniform_block(stl->g_data->lwire_shgrp, "globalsBlock", globals_ubo);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+
+ stl->g_data->face_shgrp = DRW_shgroup_create(e_data.face_overlay_shader, psl->face_overlay);
+
+ static float col[4] = {1.0f, 1.0f, 1.0f, 0.2f};
+ DRW_shgroup_uniform_vec4(stl->g_data->face_shgrp, "color", col, 1);
+ }
+
+ {
+ psl->vert_overlay = DRW_pass_create(
+ "Vert Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->vert_shgrp = DRW_shgroup_create(e_data.vert_overlay_shader, psl->vert_overlay);
+ DRW_shgroup_uniform_block(stl->g_data->vert_shgrp, "globalsBlock", globals_ubo);
+ }
+}
+
+static void PAINT_WEIGHT_cache_populate(void *vedata, Object *ob)
+{
+ PAINT_WEIGHT_StorageList *stl = ((PAINT_WEIGHT_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+
+ if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) {
+ const Mesh *me = ob->data;
+ const bool use_wire = (v3d->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
+ const bool use_surface = v3d->overlay.weight_paint_mode_opacity != 0.0f;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ struct GPUBatch *geom;
+
+ if (use_surface) {
+ geom = DRW_cache_mesh_surface_weights_get(ob, draw_ctx->scene->toolsettings, true);
+ DRW_shgroup_call_add(stl->g_data->fweights_shgrp, geom, ob->obmat);
+ }
+
+ if (use_face_sel || use_wire) {
+ geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel);
+ DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat);
+ }
+
+ if (use_face_sel) {
+ geom = DRW_cache_mesh_faces_weight_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat);
+ }
+
+ if (use_vert_sel) {
+ geom = DRW_cache_mesh_verts_weight_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->vert_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+static void PAINT_WEIGHT_draw_scene(void *vedata)
+{
+ PAINT_WEIGHT_PassList *psl = ((PAINT_WEIGHT_Data *)vedata)->psl;
+
+ DRW_draw_pass(psl->weight_faces);
+ DRW_draw_pass(psl->face_overlay);
+ DRW_draw_pass(psl->wire_overlay);
+ DRW_draw_pass(psl->vert_overlay);
+}
+
+static void PAINT_WEIGHT_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.weight_face_shader);
+ DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader);
+ DRW_SHADER_FREE_SAFE(e_data.vert_overlay_shader);
+}
+
+static const DrawEngineDataSize PAINT_WEIGHT_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_WEIGHT_Data);
+
+DrawEngineType draw_engine_paint_weight_type = {
+ NULL, NULL,
+ N_("PaintWeightMode"),
+ &PAINT_WEIGHT_data_size,
+ &PAINT_WEIGHT_engine_init,
+ &PAINT_WEIGHT_engine_free,
+ &PAINT_WEIGHT_cache_init,
+ &PAINT_WEIGHT_cache_populate,
+ NULL,
+ NULL,
+ &PAINT_WEIGHT_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c
new file mode 100644
index 00000000000..758218fe329
--- /dev/null
+++ b/source/blender/draw/modes/particle_mode.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/particle_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+
+#include "GPU_shader.h"
+#include "GPU_batch.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "ED_particle.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "draw_cache_impl.h"
+
+extern char datatoc_particle_strand_vert_glsl[];
+extern char datatoc_particle_strand_frag_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+
+/* *********** LISTS *********** */
+
+typedef struct PARTICLE_PassList {
+ struct DRWPass *psys_edit_pass;
+} PARTICLE_PassList;
+
+typedef struct PARTICLE_FramebufferList {
+ struct GPUFrameBuffer *fb;
+} PARTICLE_FramebufferList;
+
+typedef struct PARTICLE_TextureList {
+ struct GPUTexture *texture;
+} PARTICLE_TextureList;
+
+typedef struct PARTICLE_StorageList {
+ struct CustomStruct *block;
+ struct PARTICLE_PrivateData *g_data;
+} PARTICLE_StorageList;
+
+typedef struct PARTICLE_Data {
+ void *engine_type; /* Required */
+ PARTICLE_FramebufferList *fbl;
+ PARTICLE_TextureList *txl;
+ PARTICLE_PassList *psl;
+ PARTICLE_StorageList *stl;
+} PARTICLE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ struct GPUShader *strands_shader;
+ struct GPUShader *strands_weight_shader;
+ struct GPUShader *points_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PARTICLE_PrivateData {
+ DRWShadingGroup *strands_group;
+ DRWShadingGroup *inner_points_group;
+ DRWShadingGroup *tip_points_group;
+} PARTICLE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+static void particle_engine_init(void *UNUSED(vedata))
+{
+ if (!e_data.strands_shader) {
+ e_data.strands_shader = DRW_shader_create_with_lib(
+ datatoc_particle_strand_vert_glsl,
+ NULL,
+ datatoc_particle_strand_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "");
+
+ e_data.strands_weight_shader = DRW_shader_create_with_lib(
+ datatoc_particle_strand_vert_glsl,
+ NULL,
+ datatoc_particle_strand_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define USE_WEIGHT");
+
+ e_data.points_shader = DRW_shader_create_with_lib(
+ datatoc_particle_strand_vert_glsl,
+ NULL,
+ datatoc_particle_strand_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define USE_POINTS");
+ }
+}
+
+static void particle_cache_init(void *vedata)
+{
+ PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
+ PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ /* Create a pass */
+ psl->psys_edit_pass = DRW_pass_create("PSys Edit Pass",
+ (DRW_STATE_WRITE_COLOR |
+ DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_WIRE |
+ DRW_STATE_POINT));
+
+ GPUShader *strand_shader = (use_weight) ? e_data.strands_weight_shader : e_data.strands_shader;
+ stl->g_data->strands_group = DRW_shgroup_create(strand_shader, psl->psys_edit_pass);
+ stl->g_data->inner_points_group = DRW_shgroup_create(e_data.points_shader, psl->psys_edit_pass);
+ stl->g_data->tip_points_group = DRW_shgroup_create(e_data.points_shader, psl->psys_edit_pass);
+
+ DRW_shgroup_uniform_block(stl->g_data->strands_group, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_block(stl->g_data->inner_points_group, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_block(stl->g_data->tip_points_group, "globalsBlock", globals_ubo);
+}
+
+static void particle_edit_cache_populate(void *vedata,
+ Object *object,
+ ParticleSystem *psys,
+ PTCacheEdit *edit)
+{
+ PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
+ {
+ struct GPUBatch *strands =
+ DRW_cache_particles_get_edit_strands(object, psys, edit, use_weight);
+ DRW_shgroup_call_add(stl->g_data->strands_group, strands, NULL);
+ }
+ if (pset->selectmode == SCE_SELECT_POINT) {
+ struct GPUBatch *points =
+ DRW_cache_particles_get_edit_inner_points(object, psys, edit);
+ DRW_shgroup_call_add(stl->g_data->inner_points_group, points, NULL);
+ }
+ if (ELEM(pset->selectmode, SCE_SELECT_POINT, SCE_SELECT_END)) {
+ struct GPUBatch *points =
+ DRW_cache_particles_get_edit_tip_points(object, psys, edit);
+ DRW_shgroup_call_add(stl->g_data->tip_points_group, points, NULL);
+ }
+}
+
+static void particle_cache_populate(void *vedata, Object *object)
+{
+ if (object->mode != OB_MODE_PARTICLE_EDIT) {
+ return;
+ }
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
+ /* Usually the edit structure is created by Particle Edit Mode Toggle
+ * operator, but sometimes it's invoked after tagging hair as outdated
+ * (for example, when toggling edit mode). That makes it impossible to
+ * create edit structure for until after next dependency graph evaluation.
+ *
+ * Ideally, the edit structure will be created here already via some
+ * dependency graph callback or so, but currently trying to make it nicer
+ * only causes bad level calls and breaks design from the past.
+ */
+ Object *object_orig = DEG_get_original_object(object);
+ PTCacheEdit *edit = PE_create_current(
+ draw_ctx->depsgraph, scene_orig, object_orig);
+ if (edit == NULL) {
+ /* Happens when trying to edit particles in EMITTER mode without
+ * having them cached.
+ */
+ return;
+ }
+ /* NOTE: We need to pass evaluated particle system, which we need
+ * to find first.
+ */
+ ParticleSystem *psys = object->particlesystem.first;
+ ParticleSystem *psys_orig = object_orig->particlesystem.first;
+ while (psys_orig != NULL) {
+ if (PE_get_current_from_psys(psys_orig) == edit) {
+ break;
+ }
+ psys = psys->next;
+ psys_orig = psys_orig->next;
+ }
+ if (psys == NULL) {
+ printf("Error getting evaluated particle system for edit.\n");
+ return;
+ }
+ particle_edit_cache_populate(vedata, object, psys, edit);
+}
+
+/* Optional: Post-cache_populate callback */
+static void particle_cache_finish(void *UNUSED(vedata))
+{
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void particle_draw_scene(void *vedata)
+{
+
+ PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
+
+ DRW_draw_pass(psl->psys_edit_pass);
+}
+
+static void particle_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.strands_shader);
+ DRW_SHADER_FREE_SAFE(e_data.strands_weight_shader);
+ DRW_SHADER_FREE_SAFE(e_data.points_shader);
+}
+
+static const DrawEngineDataSize particle_data_size =
+ DRW_VIEWPORT_DATA_SIZE(PARTICLE_Data);
+
+DrawEngineType draw_engine_particle_type = {
+ NULL, NULL,
+ N_("Particle Mode"),
+ &particle_data_size,
+ &particle_engine_init,
+ &particle_engine_free,
+ &particle_cache_init,
+ &particle_cache_populate,
+ &particle_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &particle_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
new file mode 100644
index 00000000000..3c0a8048c9e
--- /dev/null
+++ b/source/blender/draw/modes/pose_mode.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/pose_mode.c
+ * \ingroup draw
+ */
+#include "BKE_modifier.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_view3d_types.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+extern GlobalsUboStorage ts;
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use POSE_engine_init() to
+ * initialize most of them and POSE_cache_init()
+ * for POSE_PassList */
+
+typedef struct POSE_PassList {
+ struct DRWPass *bone_solid[2];
+ struct DRWPass *bone_outline[2];
+ struct DRWPass *bone_wire[2];
+ struct DRWPass *bone_envelope[2];
+ struct DRWPass *bone_axes;
+ struct DRWPass *relationship[2];
+ struct DRWPass *bone_selection;
+} POSE_PassList;
+
+typedef struct POSE_StorageList {
+ struct POSE_PrivateData *g_data;
+} POSE_StorageList;
+
+typedef struct POSE_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ POSE_PassList *psl;
+ POSE_StorageList *stl;
+} POSE_Data;
+
+/* *********** STATIC *********** */
+
+typedef struct POSE_PrivateData {
+ DRWShadingGroup *bone_selection_shgrp;
+ DRWShadingGroup *bone_selection_invert_shgrp;
+ float blend_color[4];
+ float blend_color_invert[4];
+ bool transparent_bones;
+} POSE_PrivateData; /* Transient data */
+
+static struct {
+ struct GPUShader *bone_selection_sh;
+} e_data = {NULL};
+
+
+/* *********** FUNCTIONS *********** */
+static bool POSE_is_bone_selection_overlay_active(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+ return v3d && (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT) && draw_ctx->object_pose;
+}
+
+static void POSE_engine_init(void *UNUSED(vedata))
+{
+ if (!e_data.bone_selection_sh) {
+ e_data.bone_selection_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+static void POSE_engine_free(void)
+{
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void POSE_cache_init(void *vedata)
+{
+ POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
+ POSE_StorageList *stl = ((POSE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
+ }
+ POSE_PrivateData *ppd = stl->g_data;
+ ppd->transparent_bones = (draw_ctx->v3d->overlay.arm_flag & V3D_OVERLAY_ARM_TRANSP_BONES) != 0;
+
+ for (int i = 0; i < 2; ++i) {
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ psl->bone_solid[i] = DRW_pass_create("Bone Solid Pass", state);
+
+ /* Bones Outline */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ psl->bone_outline[i] = DRW_pass_create("Bone Outline Pass", state);
+
+ /* Wire bones */
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
+ psl->bone_wire[i] = DRW_pass_create("Bone Wire Pass", state);
+
+ /* distance outline around envelope bones */
+ state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_FRONT;
+ psl->bone_envelope[i] = DRW_pass_create("Bone Envelope Outline Pass", state);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND | DRW_STATE_WIRE;
+ psl->relationship[i] = DRW_pass_create("Bone Relationship Pass", state);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WIRE_SMOOTH | DRW_STATE_BLEND;
+ psl->bone_axes = DRW_pass_create("Bone Axes Pass", state);
+ }
+
+ {
+ if (POSE_is_bone_selection_overlay_active()) {
+ const float alpha = (draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) ? 0.0f : v3d->overlay.xray_alpha_bone;
+ copy_v4_fl4(ppd->blend_color, 0.0f, 0.0f, 0.0f, alpha);
+ copy_v4_fl4(ppd->blend_color_invert, 0.0f, 0.0f, 0.0f, pow(alpha, 4));
+ DRWShadingGroup *grp;
+ psl->bone_selection = DRW_pass_create(
+ "Bone Selection",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND);
+ grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection);
+ DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color, 1);
+ stl->g_data->bone_selection_shgrp = grp;
+ grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection);
+ DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color_invert, 1);
+ stl->g_data->bone_selection_invert_shgrp = grp;
+ }
+ }
+}
+
+static bool POSE_is_driven_by_active_armature(Object *ob)
+{
+ Object *ob_arm = modifiers_isDeformedByArmature(ob);
+ if (ob_arm) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ bool is_active = DRW_pose_mode_armature(ob_arm, draw_ctx->obact);
+ if (!is_active && ob_arm->proxy_from) {
+ is_active = DRW_pose_mode_armature(ob_arm->proxy_from, draw_ctx->obact);
+ }
+ return is_active;
+ }
+ else {
+ Object *ob_mesh_deform = modifiers_isDeformedByMeshDeform(ob);
+ if (ob_mesh_deform) {
+ return POSE_is_driven_by_active_armature(ob_mesh_deform);
+ }
+ }
+ return false;
+}
+
+/* Add geometry to shading groups. Execute for each objects */
+static void POSE_cache_populate(void *vedata, Object *ob)
+{
+ POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
+ POSE_PrivateData *ppd = ((POSE_Data *)vedata)->stl->g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ /* In the future this will allow us to implement face gizmos,
+ * and similar functionalities. For now we handle only pose bones. */
+
+ if (ob->type == OB_ARMATURE) {
+ if (draw_ctx->v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) {
+ return;
+ }
+ if (DRW_pose_mode_armature(ob, draw_ctx->obact)) {
+ int ghost = (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
+
+ DRWArmaturePasses passes = {
+ .bone_solid = psl->bone_solid[ghost],
+ .bone_outline = psl->bone_outline[ghost],
+ .bone_wire = psl->bone_wire[ghost],
+ .bone_envelope = psl->bone_envelope[ghost],
+ .bone_axes = psl->bone_axes,
+ .relationship_lines = psl->relationship[ghost],
+ };
+ DRW_shgroup_armature_pose(ob, passes, ppd->transparent_bones);
+ }
+ }
+ else if (ob->type == OB_MESH &&
+ !DRW_state_is_select() &&
+ POSE_is_bone_selection_overlay_active())
+ {
+ struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ if (POSE_is_driven_by_active_armature(ob)) {
+ DRW_shgroup_call_object_add(ppd->bone_selection_shgrp, geom, ob);
+ }
+ else {
+ DRW_shgroup_call_object_add(ppd->bone_selection_invert_shgrp, geom, ob);
+ }
+ }
+ }
+}
+
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
+bool DRW_pose_mode_armature(Object *ob, Object *active_ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ /* Pose armature is handled by pose mode engine. */
+ if (((ob == active_ob) || (ob->mode & OB_MODE_POSE)) &&
+ ((draw_ctx->object_mode & OB_MODE_POSE) != 0))
+ {
+ return true;
+ }
+
+ /* Armature parent is also handled by pose mode engine. */
+ if ((active_ob != NULL) && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) != 0)) {
+ if (ob == draw_ctx->object_pose) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void POSE_draw_scene(void *vedata)
+{
+ POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool transparent_bones = (draw_ctx->v3d->overlay.arm_flag & V3D_OVERLAY_ARM_TRANSP_BONES) != 0;
+ const bool bone_selection_overlay = POSE_is_bone_selection_overlay_active();
+
+ if (DRW_state_is_select()) {
+ DRW_draw_pass(psl->bone_solid[0]);
+ DRW_draw_pass(psl->bone_wire[0]);
+ DRW_draw_pass(psl->bone_solid[1]);
+ DRW_draw_pass(psl->bone_wire[1]);
+ return;
+ }
+
+ if (bone_selection_overlay) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->bone_selection);
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
+ GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0);
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+
+ DRW_draw_pass(psl->bone_envelope[0]);
+
+ if (transparent_bones) {
+ DRW_pass_state_add(psl->bone_solid[0], DRW_STATE_BLEND);
+ DRW_pass_state_remove(psl->bone_solid[0], DRW_STATE_WRITE_DEPTH);
+ DRW_draw_pass(psl->bone_solid[0]);
+ }
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
+
+ if (!transparent_bones) {
+ DRW_draw_pass(psl->bone_solid[0]);
+ }
+
+ DRW_draw_pass(psl->bone_outline[0]);
+ DRW_draw_pass(psl->bone_wire[0]);
+ DRW_draw_pass(psl->relationship[0]);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl);
+
+ if (!DRW_pass_is_empty(psl->bone_envelope[1]) ||
+ !DRW_pass_is_empty(psl->bone_solid[1]) ||
+ !DRW_pass_is_empty(psl->bone_outline[1]) ||
+ !DRW_pass_is_empty(psl->bone_wire[1]) ||
+ !DRW_pass_is_empty(psl->relationship[1]))
+ {
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
+ }
+
+ if (transparent_bones) {
+ DRW_pass_state_add(psl->bone_solid[1], DRW_STATE_BLEND);
+ DRW_pass_state_remove(psl->bone_solid[1], DRW_STATE_WRITE_DEPTH);
+ }
+
+ DRW_draw_pass(psl->bone_envelope[1]);
+ DRW_draw_pass(psl->bone_solid[1]);
+ DRW_draw_pass(psl->bone_outline[1]);
+ DRW_draw_pass(psl->bone_wire[1]);
+ DRW_draw_pass(psl->relationship[1]);
+ }
+
+ /* Draw axes with linesmooth and outside of multisample buffer. */
+ DRW_draw_pass(psl->bone_axes);
+}
+
+static const DrawEngineDataSize POSE_data_size = DRW_VIEWPORT_DATA_SIZE(POSE_Data);
+
+DrawEngineType draw_engine_pose_type = {
+ NULL, NULL,
+ N_("PoseMode"),
+ &POSE_data_size,
+ &POSE_engine_init,
+ &POSE_engine_free,
+ &POSE_cache_init,
+ &POSE_cache_populate,
+ NULL,
+ NULL,
+ &POSE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
new file mode 100644
index 00000000000..5bc5506cbb7
--- /dev/null
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/sculpt_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_pbvh.h"
+#include "BKE_paint.h"
+
+#include "DEG_depsgraph.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_matrix.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+extern char datatoc_sculpt_mask_vert_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use SCULPT_engine_init() to
+ * initialize most of them and SCULPT_cache_init()
+ * for SCULPT_PassList */
+
+typedef struct SCULPT_PassList {
+ /* Declare all passes here and init them in
+ * SCULPT_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *pass;
+} SCULPT_PassList;
+
+typedef struct SCULPT_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} SCULPT_FramebufferList;
+
+typedef struct SCULPT_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} SCULPT_TextureList;
+
+typedef struct SCULPT_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct SCULPT_PrivateData *g_data;
+} SCULPT_StorageList;
+
+typedef struct SCULPT_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ SCULPT_FramebufferList *fbl;
+ SCULPT_TextureList *txl;
+ SCULPT_PassList *psl;
+ SCULPT_StorageList *stl;
+} SCULPT_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in SCULPT_engine_init();
+ * free in SCULPT_engine_free(); */
+ struct GPUShader *shader_flat;
+ struct GPUShader *shader_smooth;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct SCULPT_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in SCULPT_cache_populate() */
+ DRWShadingGroup *group_flat;
+ DRWShadingGroup *group_smooth;
+} SCULPT_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void SCULPT_engine_init(void *vedata)
+{
+ SCULPT_TextureList *txl = ((SCULPT_Data *)vedata)->txl;
+ SCULPT_FramebufferList *fbl = ((SCULPT_Data *)vedata)->fbl;
+ SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ if (!e_data.shader_flat) {
+ e_data.shader_flat = DRW_shader_create(datatoc_sculpt_mask_vert_glsl, NULL,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ "#define SHADE_FLAT");
+ }
+ if (!e_data.shader_smooth) {
+ e_data.shader_smooth = DRW_shader_create(datatoc_sculpt_mask_vert_glsl, NULL,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void SCULPT_cache_init(void *vedata)
+{
+ SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
+ SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_MULTIPLY;
+ psl->pass = DRW_pass_create("Sculpt Pass", state);
+
+ /* Create a shadingGroup using a function in draw_common.c or custom one */
+ /*
+ * stl->g_data->group = shgroup_dynlines_uniform_color(psl->pass, ts.colorWire);
+ * -- or --
+ * stl->g_data->group = DRW_shgroup_create(e_data.custom_shader, psl->pass);
+ */
+ stl->g_data->group_flat = DRW_shgroup_create(e_data.shader_flat, psl->pass);
+ stl->g_data->group_smooth = DRW_shgroup_create(e_data.shader_smooth, psl->pass);
+ }
+}
+
+static bool object_is_flat(const Object *ob)
+{
+ Mesh *me = ob->data;
+ if (me->mpoly && me->mpoly[0].flag & ME_SMOOTH) {
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+static void sculpt_draw_mask_cb(
+ DRWShadingGroup *shgroup,
+ void (*draw_fn)(DRWShadingGroup *shgroup, struct GPUBatch *geom),
+ void *user_data)
+{
+ Object *ob = user_data;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ if (pbvh) {
+ BKE_pbvh_draw_cb(
+ pbvh, NULL, NULL, false, true,
+ (void (*)(void *, struct GPUBatch *))draw_fn, shgroup);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void SCULPT_cache_populate(void *vedata, Object *ob)
+{
+ SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
+ SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_MESH) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (ob->sculpt && (ob == draw_ctx->obact)) {
+ /* XXX, needed for dyntopo-undo (which clears).
+ * probably depsgraph should handlle? in 2.7x getting derived-mesh does this (mesh_build_data) */
+ if (ob->sculpt->pbvh == NULL) {
+ /* create PBVH immediately (would be created on the fly too,
+ * but this avoids waiting on first stroke) */
+ Scene *scene = draw_ctx->scene;
+
+ BKE_sculpt_update_mesh_elements(draw_ctx->depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
+ }
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ if (pbvh && pbvh_has_mask(pbvh)) {
+ /* Get geometry cache */
+ DRWShadingGroup *shgroup = object_is_flat(ob) ? stl->g_data->group_flat : stl->g_data->group_smooth;
+
+ DRW_shgroup_call_generate_add(shgroup, sculpt_draw_mask_cb, ob, ob->obmat);
+ }
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void SCULPT_cache_finish(void *vedata)
+{
+ SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
+ SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
+
+ /* Do something here! dependent on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void SCULPT_draw_scene(void *vedata)
+{
+ SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
+ SCULPT_FramebufferList *fbl = ((SCULPT_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl, dfbl, dtxl);
+
+ /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
+ /*
+ * DRW_framebuffer_texture_detach(dtxl->depth);
+ * DRW_framebuffer_bind(fbl->custom_fb);
+ * DRW_draw_pass(psl->pass);
+ * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ * DRW_framebuffer_bind(dfbl->default_fb);
+ */
+
+ /* ... or just render passes on default framebuffer. */
+ DRW_draw_pass(psl->pass);
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void SCULPT_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.shader_flat);
+ DRW_SHADER_FREE_SAFE(e_data.shader_smooth);
+}
+
+static const DrawEngineDataSize SCULPT_data_size = DRW_VIEWPORT_DATA_SIZE(SCULPT_Data);
+
+DrawEngineType draw_engine_sculpt_type = {
+ NULL, NULL,
+ N_("SculptMode"),
+ &SCULPT_data_size,
+ &SCULPT_engine_init,
+ &SCULPT_engine_free,
+ &SCULPT_cache_init,
+ &SCULPT_cache_populate,
+ &SCULPT_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &SCULPT_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl b/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl
new file mode 100644
index 00000000000..d9d59880e99
--- /dev/null
+++ b/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl
@@ -0,0 +1,38 @@
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+uniform int lineThickness = 2;
+
+in vec4 finalColor_geom[];
+in vec2 ssPos[];
+
+out vec4 finalColor;
+
+vec2 compute_dir(vec2 v0, vec2 v1)
+{
+ vec2 dir = normalize(v1 - v0 + 1e-8);
+ dir = vec2(-dir.y, dir.x);
+ return dir;
+}
+
+void main(void)
+{
+ vec2 t;
+ vec2 edge_dir = compute_dir(ssPos[0], ssPos[1]) / viewportSize;
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ finalColor = finalColor_geom[0];
+ t = edge_dir * (float(lineThickness) * (is_persp ? gl_in[0].gl_Position.w : 1.0));
+ gl_Position = gl_in[0].gl_Position + vec4(t, 0.0, 0.0); EmitVertex();
+ gl_Position = gl_in[0].gl_Position - vec4(t, 0.0, 0.0); EmitVertex();
+
+ finalColor = finalColor_geom[1];
+ t = edge_dir * (float(lineThickness) * (is_persp ? gl_in[1].gl_Position.w : 1.0));
+ gl_Position = gl_in[1].gl_Position + vec4(t, 0.0, 0.0); EmitVertex();
+ gl_Position = gl_in[1].gl_Position - vec4(t, 0.0, 0.0); EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl b/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl
new file mode 100644
index 00000000000..276f4004fb6
--- /dev/null
+++ b/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl
@@ -0,0 +1,91 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewProjectionMatrix;
+uniform vec2 viewportSize;
+
+uniform int frameCurrent;
+uniform int frameStart;
+uniform int frameEnd;
+uniform int cacheStart;
+uniform bool selected;
+uniform bool useCustomColor;
+uniform vec3 customColor;
+
+in vec3 pos;
+
+out vec2 ssPos;
+out vec4 finalColor_geom;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+#define SET_INTENSITY(A, B, C, min, max) (((1.0 - (float(C - B) / float(C - A))) * (max - min)) + min)
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+
+ ssPos = proj(gl_Position);
+
+ int frame = gl_VertexID + cacheStart;
+
+ float intensity; /* how faint */
+
+ vec3 blend_base = (abs(frame - frameCurrent) == 1) ? colorCurrentFrame.rgb : colorBackground.rgb; /* "bleed" cframe color to ease color blending */
+
+ /* TODO: We might want something more consistent with custom color and standard colors. */
+ if (frame < frameCurrent) {
+ if (useCustomColor) {
+ /* Custom color: previous frames color is darker than current frame */
+ finalColor_geom.rgb = customColor * 0.25;
+ }
+ else {
+ /* black - before frameCurrent */
+ if (selected) {
+ intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.25, 0.75);
+ }
+ else {
+ intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.68, 0.92);
+ }
+ finalColor_geom.rgb = mix(colorWire.rgb, blend_base, intensity);
+ }
+ }
+ else if (frame > frameCurrent) {
+ if (useCustomColor) {
+ /* Custom color: next frames color is equal to user selected color */
+ finalColor_geom.rgb = customColor;
+ }
+ else {
+ /* blue - after frameCurrent */
+ if (selected) {
+ intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.25, 0.75);
+ }
+ else {
+ intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.68, 0.92);
+ }
+
+ finalColor_geom.rgb = mix(colorBonePose.rgb, blend_base, intensity);
+ }
+ }
+ else {
+ if (useCustomColor) {
+ /* Custom color: current frame color is slightly darker than user selected color */
+ finalColor_geom.rgb = customColor * 0.5;
+ }
+ else {
+ /* green - on frameCurrent */
+ if (selected) {
+ intensity = 0.5f;
+ }
+ else {
+ intensity = 0.99f;
+ }
+ finalColor_geom.rgb = clamp(mix(colorCurrentFrame.rgb, colorBackground.rgb, intensity) - 0.1, 0.0, 0.1);
+ }
+ }
+
+ finalColor_geom.a = 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl b/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl
new file mode 100644
index 00000000000..3b2f170ca22
--- /dev/null
+++ b/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl
@@ -0,0 +1,47 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+uniform int pointSize = 2;
+uniform int frameCurrent;
+uniform int cacheStart;
+uniform bool showKeyFrames = true;
+uniform bool useCustomColor;
+uniform vec3 customColor;
+
+in vec3 pos;
+in int flag;
+
+#define MOTIONPATH_VERT_SEL (1 << 0)
+#define MOTIONPATH_VERT_KEY (1 << 1)
+
+out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = float(pointSize + 2);
+
+ int frame = gl_VertexID + cacheStart;
+ finalColor = (useCustomColor) ? vec4(customColor, 1.0) : vec4(1.0);
+
+ /* Bias to reduce z fighting with the path */
+ gl_Position.z -= 1e-4;
+
+ if (showKeyFrames) {
+ if ((flag & MOTIONPATH_VERT_KEY) != 0) {
+ gl_PointSize = float(pointSize + 5);
+ finalColor = colorVertexSelect;
+ /* Bias more to get these on top of regular points */
+ gl_Position.z -= 1e-4;
+ }
+ /* Draw big green dot where the current frame is.
+ * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter
+ */
+ if (frame == frameCurrent) {
+ gl_PointSize = float(pointSize + 8);
+ finalColor = colorCurrentFrame;
+ /* Bias more to get these on top of keyframes */
+ gl_Position.z -= 1e-4;
+ }
+ }
+}
diff --git a/source/blender/draw/modes/shaders/armature_axes_vert.glsl b/source/blender/draw/modes/shaders/armature_axes_vert.glsl
new file mode 100644
index 00000000000..53b2a3d3b3b
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_axes_vert.glsl
@@ -0,0 +1,30 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screenVecs[3];
+
+/* ---- Instantiated Attribs ---- */
+in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */
+in vec2 screenPos;
+in vec3 colorAxis;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 color;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz;
+ vec3 y_axis = InstanceModelMatrix[1].xyz;
+ vec3 bone_loc = InstanceModelMatrix[3].xyz;
+ vec3 wpos = bone_loc + y_axis + chosen_axis * fract(axis);
+ vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y;
+ /* Scale uniformly by axis length */
+ spos *= length(chosen_axis);
+
+ gl_Position = ViewProjectionMatrix * vec4(wpos + spos, 1.0);
+
+ finalColor.rgb = mix(colorAxis, color.rgb, color.a);
+ finalColor.a = 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/armature_dof_vert.glsl b/source/blender/draw/modes/shaders/armature_dof_vert.glsl
new file mode 100644
index 00000000000..5c89cf644d6
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_dof_vert.glsl
@@ -0,0 +1,30 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instantiated Attribs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attribs ---- */
+/* Assumed to be in world coordinate already. */
+in mat4 InstanceModelMatrix;
+in vec4 color;
+in vec2 amin;
+in vec2 amax;
+
+flat out vec4 finalColor;
+
+vec3 sphere_project(float ax, float az)
+{
+ float sine = 1.0 - ax * ax - az * az;
+ float q3 = sqrt(max(0.0, sine));
+
+ return vec3(-az * q3, 0.5 - sine, ax * q3) * 2.0;
+}
+
+void main()
+{
+ vec3 final_pos = sphere_project(pos.x * abs((pos.x > 0.0) ? amax.x : amin.x),
+ pos.y * abs((pos.y > 0.0) ? amax.y : amin.y));
+ gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(final_pos, 1.0));
+ finalColor = color;
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl
new file mode 100644
index 00000000000..cecc5447c7c
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl
@@ -0,0 +1,15 @@
+
+flat in vec3 finalStateColor; /* UNUSED */
+flat in vec3 finalBoneColor; /* UNUSED */
+in vec3 normalView;
+
+out vec4 fragColor;
+
+uniform vec4 color = vec4(1.0, 1.0, 1.0, 0.2);
+
+void main()
+{
+ float n = normalize(normalView).z;
+ n = 1.0 - clamp(-n, 0.0, 1.0);
+ fragColor = color * n;
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl
new file mode 100644
index 00000000000..307c7276184
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl
@@ -0,0 +1,156 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform vec2 viewportSize;
+uniform float lineThickness = 2.0;
+
+/* ---- Instantiated Attribs ---- */
+in vec2 pos0;
+in vec2 pos1;
+in vec2 pos2;
+
+/* ---- Per instance Attribs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 headSphere;
+in vec4 tailSphere;
+in vec4 outlineColorSize;
+in vec3 xAxis;
+
+flat out vec4 finalColor;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+vec2 compute_dir(vec2 v0, vec2 v1, vec2 v2)
+{
+ vec2 dir = normalize(v2 - v0);
+ dir = vec2(dir.y, -dir.x);
+ return dir;
+}
+
+mat3 compute_mat(vec4 sphere, vec3 bone_vec, out float z_ofs)
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ vec3 cam_ray = (is_persp) ? sphere.xyz - ViewMatrixInverse[3].xyz
+ : -ViewMatrixInverse[2].xyz;
+
+ /* Sphere center distance from the camera (persp) in world space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(bone_vec, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+ z_ofs = 0.0;
+
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ float rad = sphere.w;
+ /* Let be :
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ z_ofs = -rad * cos_b;
+ }
+
+ return mat3(x_axis, y_axis, z_axis);
+}
+
+struct Bone { vec3 vec; float sinb; };
+
+bool bone_blend_starts(vec3 p, Bone b)
+{
+ /* we just want to know when the head sphere starts interpolating. */
+ return dot(p, b.vec) > -b.sinb;
+}
+
+vec3 get_outline_point(
+ vec2 pos, vec4 sph_near, vec4 sph_far,
+ mat3 mat_near, mat3 mat_far, float z_ofs_near, float z_ofs_far, Bone b)
+{
+ /* Compute outline position on the nearest sphere and check
+ * if it penetrates the capsule body. If it does, put this
+ * vertex on the farthest sphere. */
+ vec3 wpos = mat_near * vec3(pos * sph_near.w, z_ofs_near);
+ if (bone_blend_starts(wpos, b)) {
+ wpos = sph_far.xyz + mat_far * vec3(pos * sph_far.w, z_ofs_far);
+ }
+ else {
+ wpos += sph_near.xyz;
+ }
+ return wpos;
+}
+
+void main()
+{
+ float dst_head = distance(headSphere.xyz, ViewMatrixInverse[3].xyz);
+ float dst_tail = distance(tailSphere.xyz, ViewMatrixInverse[3].xyz);
+ // float dst_head = -dot(headSphere.xyz, ViewMatrix[2].xyz);
+ // float dst_tail = -dot(tailSphere.xyz, ViewMatrix[2].xyz);
+
+ vec4 sph_near, sph_far;
+ if ((dst_head > dst_tail) && (ProjectionMatrix[3][3] == 0.0)) {
+ sph_near = tailSphere;
+ sph_far = headSphere;
+ }
+ else {
+ sph_near = headSphere;
+ sph_far = tailSphere;
+ }
+
+ vec3 bone_vec = (sph_far.xyz - sph_near.xyz) + 1e-8;
+
+ Bone b;
+ float bone_lenrcp = 1.0 / max(1e-8, sqrt(dot(bone_vec, bone_vec)));
+ b.sinb = (sph_far.w - sph_near.w) * bone_lenrcp * sph_near.w;
+ b.vec = bone_vec * bone_lenrcp;
+
+ float z_ofs_near, z_ofs_far;
+ mat3 mat_near = compute_mat(sph_near, bone_vec, z_ofs_near);
+ mat3 mat_far = compute_mat(sph_far, bone_vec, z_ofs_far);
+
+ vec3 wpos0 = get_outline_point(pos0, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+ vec3 wpos1 = get_outline_point(pos1, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+ vec3 wpos2 = get_outline_point(pos2, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+
+ vec4 V = ViewMatrix * vec4(wpos1, 1.0);
+ float pres_fac = (ProjectionMatrix[3][3] == 0.0) ? abs(V.z) : 1.0;
+
+ vec4 p0 = ViewProjectionMatrix * vec4(wpos0, 1.0);
+ vec4 p1 = ProjectionMatrix * V;
+ vec4 p2 = ViewProjectionMatrix * vec4(wpos2, 1.0);
+
+ /* compute position from 3 vertex because the change in direction
+ * can happen very quicky and lead to very thin edges. */
+ vec2 ss0 = proj(p0);
+ vec2 ss1 = proj(p1);
+ vec2 ss2 = proj(p2);
+ vec2 edge_dir = compute_dir(ss0, ss1, ss2);
+
+ bool outer = ((gl_VertexID & 1) == 1);
+ vec2 t = outlineColorSize.w * (lineThickness / viewportSize);
+ t *= pres_fac;
+ t = (outer) ? t : vec2(0.0);
+
+ gl_Position = p1;
+ gl_Position.xy += t * edge_dir;
+
+ finalColor = vec4(outlineColorSize.rgb, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl
new file mode 100644
index 00000000000..78b29296601
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl
@@ -0,0 +1,18 @@
+
+uniform float alpha = 0.6;
+
+flat in vec3 finalStateColor;
+flat in vec3 finalBoneColor;
+in vec3 normalView;
+
+out vec4 fragColor;
+
+void main()
+{
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float n = normalize(normalView).z;
+ float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
+ fragColor.rgb = mix(finalStateColor, finalBoneColor, fac);
+ fragColor.a = alpha;
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl
new file mode 100644
index 00000000000..11935e9001f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl
@@ -0,0 +1,55 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attribs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 headSphere;
+in vec4 tailSphere;
+in vec3 xAxis;
+in vec3 stateColor;
+in vec3 boneColor;
+
+flat out vec3 finalStateColor;
+flat out vec3 finalBoneColor;
+out vec3 normalView;
+
+void main()
+{
+ vec3 bone_vec = tailSphere.xyz - headSphere.xyz;
+ float bone_len = max(1e-8, sqrt(dot(bone_vec, bone_vec)));
+ float bone_lenrcp = 1.0 / bone_len;
+#ifdef SMOOTH_ENVELOPE
+ float sinb = (tailSphere.w - headSphere.w) * bone_lenrcp;
+#else
+ const float sinb = 0.0;
+#endif
+
+ vec3 y_axis = bone_vec * bone_lenrcp;
+ vec3 z_axis = normalize(cross(xAxis, -y_axis));
+ vec3 x_axis = cross(y_axis, z_axis); /* cannot trust xAxis to be orthogonal. */
+
+ vec3 sp, nor;
+ nor = sp = pos.xyz;
+
+ /* In bone space */
+ bool is_head = (pos.z < -sinb);
+ sp *= (is_head) ? headSphere.w : tailSphere.w;
+ sp.z += (is_head) ? 0.0 : bone_len;
+
+ /* Convert to world space */
+ mat3 bone_mat = mat3(x_axis, y_axis, z_axis);
+ sp = bone_mat * sp.xzy + headSphere.xyz;
+ nor = bone_mat * nor.xzy;
+
+ normalView = mat3(ViewMatrix) * nor;
+
+ gl_Position = ViewProjectionMatrix * vec4(sp, 1.0);
+
+ finalStateColor = stateColor;
+ finalBoneColor = boneColor;
+}
diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl
new file mode 100644
index 00000000000..bcfa097b277
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl
@@ -0,0 +1,101 @@
+
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 6) out;
+
+in vec4 pPos[];
+in vec3 vPos[];
+in vec2 ssPos[];
+in vec2 ssNor[];
+in vec4 vColSize[];
+
+flat out vec4 finalColor;
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+uniform float lineThickness = 2.0;
+
+vec2 compute_dir(vec2 v0, vec2 v1)
+{
+ vec2 dir = normalize(v1 - v0);
+ dir = vec2(-dir.y, dir.x);
+ return dir;
+}
+
+void emit_edge(vec2 edge_dir, vec2 hidden_dir, vec2 thick, bool is_persp)
+{
+ float fac = dot(-hidden_dir, edge_dir);
+ edge_dir *= (fac < 0.0) ? -1.0 : 1.0;
+
+ vec2 t = thick * (is_persp ? abs(vPos[1].z) : 1.0);
+ gl_Position = pPos[1];
+ EmitVertex();
+ gl_Position.xy += t * edge_dir;
+ EmitVertex();
+
+ t = thick * (is_persp ? abs(vPos[2].z) : 1.0);
+ gl_Position = pPos[2];
+ EmitVertex();
+ gl_Position.xy += t * edge_dir;
+ EmitVertex();
+}
+
+void emit_corner(const int e, vec2 thick, bool is_persp)
+{
+ vec2 corner_dir = ssNor[e];
+ vec2 t = thick * (is_persp ? abs(vPos[e].z) : 1.0);
+
+ gl_Position = pPos[e] + vec4(t * corner_dir, 0.0, 0.0);
+ EmitVertex();
+}
+
+void main(void)
+{
+ finalColor = vec4(vColSize[0].rgb, 1.0);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0);
+ vec3 v10 = vPos[0] - vPos[1];
+ vec3 v12 = vPos[2] - vPos[1];
+ vec3 v13 = vPos[3] - vPos[1];
+
+ vec3 n0 = cross(v12, v10);
+ vec3 n3 = cross(v13, v12);
+
+ float fac0 = dot(view_vec, n0);
+ float fac3 = dot(view_vec, n3);
+
+ /* If one of the face is perpendicular to the view,
+ * consider it and outline edge. */
+ if (abs(fac0) > 1e-5 && abs(fac3) > 1e-5) {
+ /* If both adjacent verts are facing the camera the same way,
+ * then it isn't an outline edge. */
+ if (sign(fac0) == sign(fac3))
+ return;
+ }
+
+ /* Don't outline if concave edge. */
+ if (dot(n0, v13) > 0.0001)
+ return;
+
+ vec2 thick = vColSize[0].w * (lineThickness / viewportSize);
+ vec2 edge_dir = compute_dir(ssPos[1], ssPos[2]);
+
+ vec2 hidden_point;
+ /* Take the farthest point to compute edge direction
+ * (avoid problems with point behind near plane).
+ * If the chosen point is parallel to the edge in screen space,
+ * choose the other point anyway.
+ * This fixes some issue with cubes in orthographic views.*/
+ if (vPos[0].z < vPos[3].z) {
+ hidden_point = (abs(fac0) > 1e-5) ? ssPos[0] : ssPos[3];
+ }
+ else {
+ hidden_point = (abs(fac3) > 1e-5) ? ssPos[3] : ssPos[0];
+ }
+ vec2 hidden_dir = normalize(hidden_point - ssPos[1]);
+
+ emit_corner(1, thick, is_persp);
+ emit_edge(edge_dir, hidden_dir, thick, is_persp);
+ emit_corner(2, thick, is_persp);
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl
new file mode 100644
index 00000000000..7619d8018f9
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl
@@ -0,0 +1,47 @@
+
+uniform mat3 NormalMatrix;
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos;
+in vec3 snor;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 outlineColorSize;
+
+out vec4 pPos;
+out vec3 vPos;
+out vec2 ssPos;
+out vec2 ssNor;
+out vec4 vColSize;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void main()
+{
+ /* This is slow and run per vertex, but it's still faster than
+ * doing it per instance on CPU and sending it on via instance attrib */
+ mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix)));
+
+ vec4 viewpos = ViewMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
+
+ vPos = viewpos.xyz;
+ pPos = ProjectionMatrix * viewpos;
+
+ /* TODO FIX: there is still a problem with this vector
+ * when the bone is scaled or in persp mode. But it's
+ * barelly visible at the outline corners. */
+ ssNor = normalize((NormalMatrix * snor).xy);
+
+ ssPos = proj(pPos);
+
+ vColSize = outlineColorSize;
+}
diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl
new file mode 100644
index 00000000000..45748bf5644
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl
@@ -0,0 +1,11 @@
+
+uniform float alpha = 0.6;
+
+in vec4 finalColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(finalColor.rgb, alpha);
+}
diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl
new file mode 100644
index 00000000000..7abbf7f3d25
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl
@@ -0,0 +1,36 @@
+
+uniform mat3 NormalMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewProjectionMatrix;
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos;
+in vec3 nor;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec3 boneColor;
+in vec3 stateColor;
+
+out vec4 finalColor;
+
+void main()
+{
+ mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix)));
+ vec3 normal = normalize(NormalMatrix * nor);
+
+ /* Do lighting at an angle to avoid flat shading on front facing bone. */
+ const vec3 light = vec3(0.1, 0.1, 0.8);
+ float n = dot(normal, light);
+
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
+ finalColor.rgb = mix(stateColor, boneColor, fac);
+ finalColor.a = 1.0;
+
+ gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
+}
diff --git a/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl
new file mode 100644
index 00000000000..0c1fefbf814
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl
@@ -0,0 +1,102 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+uniform float lineThickness = 2.0;
+
+/* ---- Instantiated Attribs ---- */
+in vec2 pos0;
+in vec2 pos1;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 outlineColorSize;
+
+flat out vec4 finalColor;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+vec2 compute_dir(vec2 v0, vec2 v1, vec2 c)
+{
+ vec2 dir = normalize(v1 - v0);
+ dir = vec2(dir.y, -dir.x);
+ /* The model matrix can be scaled negativly.
+ * Use projected sphere center to determine
+ * the outline direction. */
+ vec2 cv = c - v0;
+ dir = (dot(dir, cv) > 0.0) ? -dir : dir;
+ return dir;
+}
+
+void main()
+{
+ mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix;
+ mat4 sphereMatrix = inverse(model_view_matrix);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ /* This is the local space camera ray (not normalize).
+ * In perspective mode it's also the viewspace position
+ * of the sphere center. */
+ vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0);
+ cam_ray = mat3(sphereMatrix) * cam_ray;
+
+ /* Sphere center distance from the camera (persp) in local space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+ float z_ofs = 0.0;
+
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ const float rad = 0.05;
+ /* Let be (in local space):
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ z_ofs = -rad * cos_b;
+ }
+
+ /* Camera oriented position (but still in local space) */
+ vec3 cam_pos0 = x_axis * pos0.x + y_axis * pos0.y + z_axis * z_ofs;
+ vec3 cam_pos1 = x_axis * pos1.x + y_axis * pos1.y + z_axis * z_ofs;
+
+ vec4 V = model_view_matrix * vec4(cam_pos0, 1.0);
+ vec4 p0 = ProjectionMatrix * V;
+ vec4 p1 = ProjectionMatrix * (model_view_matrix * vec4(cam_pos1, 1.0));
+ vec4 c = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0);
+
+ vec2 ssc = proj(c);
+ vec2 ss0 = proj(p0);
+ vec2 ss1 = proj(p1);
+ vec2 edge_dir = compute_dir(ss0, ss1, ssc);
+
+ bool outer = ((gl_VertexID & 1) == 1);
+
+ vec2 t = outlineColorSize.w * (lineThickness / viewportSize);
+ t *= (is_persp) ? abs(V.z) : 1.0;
+ t = (outer) ? t : vec2(0.0);
+
+ gl_Position = p0;
+ gl_Position.xy += t * edge_dir;
+
+ finalColor = vec4(outlineColorSize.rgb, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl
new file mode 100644
index 00000000000..a0fdd55931f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl
@@ -0,0 +1,81 @@
+
+#extension GL_ARB_conservative_depth : enable
+
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ProjectionMatrix;
+uniform float alpha = 0.4;
+
+flat in vec3 finalStateColor;
+flat in vec3 finalBoneColor;
+flat in mat4 sphereMatrix;
+in vec3 viewPosition;
+
+#ifdef GL_ARB_conservative_depth
+/* Saves a lot of overdraw! */
+layout(depth_greater) out float gl_FragDepth;
+#endif
+
+out vec4 fragColor;
+
+#define cameraPos ViewMatrixInverse[3].xyz
+
+float get_depth_from_view_z(float z)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ z = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
+ }
+ else {
+ z = z * ProjectionMatrix[2][2] / (1.0 - ProjectionMatrix[3][2]);
+ }
+ return z * 0.5 + 0.5;
+}
+
+void main()
+{
+ const float sphere_radius = 0.05;
+
+ bool is_perp = (ProjectionMatrix[3][3] == 0.0);
+ vec3 ray_ori_view = (is_perp) ? vec3(0.0) : viewPosition.xyz;
+ vec3 ray_dir_view = (is_perp) ? viewPosition : vec3(0.0, 0.0, -1.0);
+
+ /* Single matrix mul without branch. */
+ vec4 mul_vec = (is_perp) ? vec4(ray_dir_view, 0.0) : vec4(ray_ori_view, 1.0);
+ vec3 mul_res = (sphereMatrix * mul_vec).xyz;
+
+ /* Reminder :
+ * sphereMatrix[3] is the view space origin in sphere space (sph_ori -> view_ori).
+ * sphereMatrix[2] is the view space Z axis in sphere space. */
+
+ /* convert to sphere local space */
+ vec3 ray_ori = (is_perp) ? sphereMatrix[3].xyz : mul_res;
+ vec3 ray_dir = (is_perp) ? mul_res : -sphereMatrix[2].xyz;
+ float ray_len = length(ray_dir);
+ ray_dir /= ray_len;
+
+ /* Line to sphere intersect */
+ const float sphere_radius_sqr = sphere_radius * sphere_radius;
+ float b = dot(ray_ori, ray_dir);
+ float c = dot(ray_ori, ray_ori) - sphere_radius_sqr;
+ float h = b * b - c;
+ float t = -sqrt(max(0.0, h)) - b;
+
+ /* Compute dot product for lighting */
+ vec3 p = ray_dir * t + ray_ori; /* Point on sphere */
+ vec3 n = normalize(p); /* Normal is just the point in sphere space, normalized. */
+ vec3 l = normalize(sphereMatrix[2].xyz); /* Just the view Z axis in the sphere space. */
+
+
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float fac = clamp((dot(n, l) * (1.0 - s)) + s, 0.0, 1.0);
+ fragColor.rgb = mix(finalStateColor, finalBoneColor, fac);
+
+ /* 2x2 dither pattern to smooth the lighting. */
+ float dither = (0.5 + dot(vec2(ivec2(gl_FragCoord.xy) & ivec2(1)), vec2(1.0, 2.0))) * 0.25;
+ dither *= (1.0 / 255.0); /* Assume 8bit per color buffer. */
+
+ fragColor = vec4(fragColor.rgb + dither, alpha);
+
+ t /= ray_len;
+ gl_FragDepth = get_depth_from_view_z(ray_dir_view.z * t + ray_ori_view.z);
+}
diff --git a/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl
new file mode 100644
index 00000000000..7cbc0c5bc3a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl
@@ -0,0 +1,82 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+
+/* ---- Instantiated Attribs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec3 stateColor;
+in vec3 boneColor;
+
+flat out vec3 finalStateColor;
+flat out vec3 finalBoneColor;
+flat out mat4 sphereMatrix;
+out vec3 viewPosition;
+
+/* Sphere radius */
+const float rad = 0.05;
+
+void main()
+{
+ mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix;
+ sphereMatrix = inverse(model_view_matrix);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ /* This is the local space camera ray (not normalize).
+ * In perspective mode it's also the viewspace position
+ * of the sphere center. */
+ vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0);
+ cam_ray = mat3(sphereMatrix) * cam_ray;
+
+ /* Sphere center distance from the camera (persp) in local space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+
+ float z_ofs = -rad - 1e-8; /* offset to the front of the sphere */
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ /* Let be (in local space):
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+#if 1
+ /* Instead of choosing the biggest circle in screenspace,
+ * we choose the nearest with the same angular size. This
+ * permit us to leverage GL_ARB_conservative_depth in the
+ * fragment shader. */
+ float minor = cam_dist - rad;
+ float major = cam_dist - cos_b * rad;
+ float fac = minor / major;
+ sin_b *= fac;
+#else
+ z_ofs = -rad * cos_b;
+#endif
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ }
+
+ /* Camera oriented position (but still in local space) */
+ vec3 cam_pos = x_axis * pos.x + y_axis * pos.y + z_axis * z_ofs;
+
+ vec4 V = model_view_matrix * vec4(cam_pos, 1.0);
+ gl_Position = ProjectionMatrix * V;
+ viewPosition = V.xyz;
+
+ finalStateColor = stateColor;
+ finalBoneColor = boneColor;
+}
diff --git a/source/blender/draw/modes/shaders/armature_stick_frag.glsl b/source/blender/draw/modes/shaders/armature_stick_frag.glsl
new file mode 100644
index 00000000000..d03cf4c0366
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_stick_frag.glsl
@@ -0,0 +1,13 @@
+
+noperspective in float colorFac;
+flat in vec4 finalWireColor;
+flat in vec4 finalInnerColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ float fac = smoothstep(1.0, 0.2, colorFac);
+ fragColor.rgb = mix(finalInnerColor.rgb, finalWireColor.rgb, fac);
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/armature_stick_vert.glsl b/source/blender/draw/modes/shaders/armature_stick_vert.glsl
new file mode 100644
index 00000000000..58fc48e608e
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_stick_vert.glsl
@@ -0,0 +1,88 @@
+
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ViewMatrix;
+uniform vec2 viewportSize;
+
+/* ---- Instantiated Attribs ---- */
+in vec2 pos; /* bone aligned screen space */
+in uint flag;
+
+#define COL_WIRE 1u /* (1 << 0) */
+#define COL_HEAD 2u /* (1 << 1) */
+#define COL_TAIL 4u /* (1 << 2) */
+#define COL_BONE 8u /* (1 << 3) */
+
+#define POS_HEAD 16u /* (1 << 4) */
+#define POS_TAIL 32u /* (1 << 5) */ /* UNUSED */
+#define POS_BONE 64u /* (1 << 6) */
+
+/* ---- Per instance Attribs ---- */
+in vec3 boneStart;
+in vec3 boneEnd;
+in vec4 wireColor; /* alpha encode if we do wire. If 0.0 we dont. */
+in vec4 boneColor; /* alpha encode if we do bone. If 0.0 we dont. */
+in vec4 headColor; /* alpha encode if we do head. If 0.0 we dont. */
+in vec4 tailColor; /* alpha encode if we do tail. If 0.0 we dont. */
+
+#define do_wire (wireColor.a > 0.0)
+#define is_head bool(flag & POS_HEAD)
+#define is_bone bool(flag & POS_BONE)
+
+noperspective out float colorFac;
+flat out vec4 finalWireColor;
+flat out vec4 finalInnerColor;
+
+uniform float stickSize = 5.0; /* might be dependent on DPI setting in the future. */
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void main()
+{
+ finalInnerColor = ((flag & COL_HEAD) != 0u) ? headColor : tailColor;
+ finalInnerColor = ((flag & COL_BONE) != 0u) ? boneColor : finalInnerColor;
+ finalWireColor = (do_wire) ? wireColor : finalInnerColor;
+ /* Make the color */
+ colorFac = ((flag & COL_WIRE) == 0u) ? ((flag & COL_BONE) != 0u) ? 1.0 : 2.0 : 0.0;
+
+ vec4 v0 = ViewMatrix * vec4(boneStart, 1.0);
+ vec4 v1 = ViewMatrix * vec4(boneEnd, 1.0);
+
+ /* Clip the bone to the camera origin plane (not the clip plane)
+ * to avoid glitches if one end is behind the camera origin (in persp). */
+ float clip_dist = (ProjectionMatrix[3][3] == 0.0) ? -1e-7 : 1e20; /* hardcoded, -1e-8 is giving gliches. */
+ vec3 bvec = v1.xyz - v0.xyz;
+ vec3 clip_pt = v0.xyz + bvec * ((v0.z - clip_dist) / -bvec.z);
+ if (v0.z > clip_dist) {
+ v0.xyz = clip_pt;
+ }
+ else if (v1.z > clip_dist) {
+ v1.xyz = clip_pt;
+ }
+
+ vec4 p0 = ProjectionMatrix * v0;
+ vec4 p1 = ProjectionMatrix * v1;
+
+ float h = (is_head) ? p0.w : p1.w;
+
+ vec2 x_screen_vec = normalize(proj(p1) - proj(p0) + 1e-8);
+ vec2 y_screen_vec = vec2(x_screen_vec.y, -x_screen_vec.x);
+
+ /* 2D screen aligned pos at the point */
+ vec2 vpos = pos.x * x_screen_vec + pos.y * y_screen_vec;
+ vpos *= (ProjectionMatrix[3][3] == 0.0) ? h : 1.0;
+ vpos *= (do_wire) ? 1.0 : 0.5;
+
+ if (finalInnerColor.a > 0.0) {
+ gl_Position = (is_head) ? p0 : p1;
+ gl_Position.xy += stickSize * (vpos / viewportSize);
+ gl_Position.z += (is_bone) ? 0.0 : 1e-6; /* Avoid Z fighting of head/tails. */
+ }
+ else {
+ gl_Position = vec4(0.0);
+ }
+}
diff --git a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl
new file mode 100644
index 00000000000..fc5cc1cdcc3
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl
@@ -0,0 +1,10 @@
+
+in vec2 pos;
+in vec2 uvs;
+out vec4 uvcoordsvar;
+
+void main()
+{
+ uvcoordsvar = vec4(uvs, 0.0, 0.0);
+ gl_Position = vec4(pos, 0.0, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/common_fxaa_lib.glsl b/source/blender/draw/modes/shaders/common_fxaa_lib.glsl
new file mode 100644
index 00000000000..236ac5c67f0
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_fxaa_lib.glsl
@@ -0,0 +1,677 @@
+//----------------------------------------------------------------------------------
+// File: es3-kepler\FXAA/FXAA3_11.h
+// SDK Version: v3.00
+// Email: gameworks@nvidia.com
+// Site: http://developer.nvidia.com/
+//
+// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of NVIDIA CORPORATION nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//----------------------------------------------------------------------------------
+
+/* BLENDER MODIFICATIONS:
+ *
+ * - (#B1#) Compute luma on the fly using BT. 709 luma function
+ * - (#B2#) main function instead of #include, due to lack of
+ * ARB_shading_language_include in 3.3
+ * - (#B3#) version and extension directives
+ * - removed "FXAA Console" algorithm support and shader parameters
+ * - removed HLSL support shims
+ * - (#B4#) change luma sampling to compute, not use A channel
+ * (this also removes GATHER4_ALPHA support)
+ * - removed all the console shaders (only remaining algorithm is "FXAA PC
+ * Quality")
+ *
+ * Note that this file doesn't follow the coding style guidelines.
+ */
+
+/*============================================================================
+ FXAA QUALITY - TUNING KNOBS
+------------------------------------------------------------------------------
+NOTE the other tuning knobs are now in the shader function inputs!
+============================================================================*/
+#ifndef FXAA_QUALITY__PRESET
+ //
+ // Choose the quality preset.
+ // This needs to be compiled into the shader as it effects code.
+ // Best option to include multiple presets is to
+ // in each shader define the preset, then include this file.
+ //
+ // OPTIONS
+ // -----------------------------------------------------------------------
+ // 10 to 15 - default medium dither (10=fastest, 15=highest quality)
+ // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality)
+ // 39 - no dither, very expensive
+ //
+ // NOTES
+ // -----------------------------------------------------------------------
+ // 12 = slightly faster then FXAA 3.9 and higher edge quality (default)
+ // 13 = about same speed as FXAA 3.9 and better than 12
+ // 23 = closest to FXAA 3.9 visually and performance wise
+ // _ = the lowest digit is directly related to performance
+ // _ = the highest digit is directly related to style
+ //
+ #define FXAA_QUALITY__PRESET 12
+#endif
+
+/*============================================================================
+
+ FXAA QUALITY - PRESETS
+
+============================================================================*/
+
+/*============================================================================
+ FXAA QUALITY - MEDIUM DITHER PRESETS
+============================================================================*/
+#if (FXAA_QUALITY__PRESET == 10)
+ #define FXAA_QUALITY__PS 3
+ #define FXAA_QUALITY__P0 1.5
+ #define FXAA_QUALITY__P1 3.0
+ #define FXAA_QUALITY__P2 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 11)
+ #define FXAA_QUALITY__PS 4
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 3.0
+ #define FXAA_QUALITY__P3 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 12)
+ #define FXAA_QUALITY__PS 5
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 4.0
+ #define FXAA_QUALITY__P4 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 13)
+ #define FXAA_QUALITY__PS 6
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 4.0
+ #define FXAA_QUALITY__P5 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 14)
+ #define FXAA_QUALITY__PS 7
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 4.0
+ #define FXAA_QUALITY__P6 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 15)
+ #define FXAA_QUALITY__PS 8
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 4.0
+ #define FXAA_QUALITY__P7 12.0
+#endif
+
+/*============================================================================
+ FXAA QUALITY - LOW DITHER PRESETS
+============================================================================*/
+#if (FXAA_QUALITY__PRESET == 20)
+ #define FXAA_QUALITY__PS 3
+ #define FXAA_QUALITY__P0 1.5
+ #define FXAA_QUALITY__P1 2.0
+ #define FXAA_QUALITY__P2 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 21)
+ #define FXAA_QUALITY__PS 4
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 22)
+ #define FXAA_QUALITY__PS 5
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 23)
+ #define FXAA_QUALITY__PS 6
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 24)
+ #define FXAA_QUALITY__PS 7
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 3.0
+ #define FXAA_QUALITY__P6 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 25)
+ #define FXAA_QUALITY__PS 8
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 4.0
+ #define FXAA_QUALITY__P7 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 26)
+ #define FXAA_QUALITY__PS 9
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 4.0
+ #define FXAA_QUALITY__P8 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 27)
+ #define FXAA_QUALITY__PS 10
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 2.0
+ #define FXAA_QUALITY__P8 4.0
+ #define FXAA_QUALITY__P9 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 28)
+ #define FXAA_QUALITY__PS 11
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 2.0
+ #define FXAA_QUALITY__P8 2.0
+ #define FXAA_QUALITY__P9 4.0
+ #define FXAA_QUALITY__P10 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 29)
+ #define FXAA_QUALITY__PS 12
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 2.0
+ #define FXAA_QUALITY__P8 2.0
+ #define FXAA_QUALITY__P9 2.0
+ #define FXAA_QUALITY__P10 4.0
+ #define FXAA_QUALITY__P11 8.0
+#endif
+
+/*============================================================================
+ FXAA QUALITY - EXTREME QUALITY
+============================================================================*/
+#if (FXAA_QUALITY__PRESET == 39)
+ #define FXAA_QUALITY__PS 12
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.0
+ #define FXAA_QUALITY__P2 1.0
+ #define FXAA_QUALITY__P3 1.0
+ #define FXAA_QUALITY__P4 1.0
+ #define FXAA_QUALITY__P5 1.5
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 2.0
+ #define FXAA_QUALITY__P8 2.0
+ #define FXAA_QUALITY__P9 2.0
+ #define FXAA_QUALITY__P10 4.0
+ #define FXAA_QUALITY__P11 8.0
+#endif
+
+#define FxaaSat(x) clamp(x, 0.0, 1.0)
+
+#ifdef FXAA_ALPHA
+
+#define FxaaTexTop(t, p) textureLod(t, p, 0.0).aaaa
+#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o).aaaa
+#define FxaaLuma(rgba) rgba.a
+
+#else
+
+#define FxaaTexTop(t, p) textureLod(t, p, 0.0)
+#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o)
+
+/* (#B1#) */
+float FxaaLuma(vec4 rgba) {
+ // note: sqrt because the sampled colors are in a linear colorspace!
+ // this approximates a perceptual conversion, which is good enough for the
+ // algorithm
+ return sqrt(dot(rgba.rgb, vec3(0.2126, 0.7152, 0.0722)));
+}
+
+#endif
+
+/*============================================================================
+
+ FXAA3 QUALITY - PC
+
+============================================================================*/
+/*--------------------------------------------------------------------------*/
+vec4 FxaaPixelShader(
+ //
+ // Use noperspective interpolation here (turn off perspective interpolation).
+ // {xy} = center of pixel
+ vec2 pos,
+ //
+ // Input color texture.
+ // {rgb_} = color in linear or perceptual color space
+ sampler2D tex,
+ //
+ // Only used on FXAA Quality.
+ // This must be from a constant/uniform.
+ // {x_} = 1.0/screenWidthInPixels
+ // {_y} = 1.0/screenHeightInPixels
+ vec2 fxaaQualityRcpFrame,
+ //
+ // Only used on FXAA Quality.
+ // This used to be the FXAA_QUALITY__SUBPIX define.
+ // It is here now to allow easier tuning.
+ // Choose the amount of sub-pixel aliasing removal.
+ // This can effect sharpness.
+ // 1.00 - upper limit (softer)
+ // 0.75 - default amount of filtering
+ // 0.50 - lower limit (sharper, less sub-pixel aliasing removal)
+ // 0.25 - almost off
+ // 0.00 - completely off
+ float fxaaQualitySubpix,
+ //
+ // Only used on FXAA Quality.
+ // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define.
+ // It is here now to allow easier tuning.
+ // The minimum amount of local contrast required to apply algorithm.
+ // 0.333 - too little (faster)
+ // 0.250 - low quality
+ // 0.166 - default
+ // 0.125 - high quality
+ // 0.063 - overkill (slower)
+ float fxaaQualityEdgeThreshold,
+ //
+ // Only used on FXAA Quality.
+ // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define.
+ // It is here now to allow easier tuning.
+ // Trims the algorithm from processing darks.
+ // 0.0833 - upper limit (default, the start of visible unfiltered edges)
+ // 0.0625 - high quality (faster)
+ // 0.0312 - visible limit (slower)
+ float fxaaQualityEdgeThresholdMin
+) {
+/*--------------------------------------------------------------------------*/
+ vec2 posM;
+ posM.x = pos.x;
+ posM.y = pos.y;
+ vec4 rgbyM = FxaaTexTop(tex, posM);
+ float lumaM = FxaaLuma(rgbyM); // (#B4#)
+ float lumaS = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 0, 1), fxaaQualityRcpFrame.xy));
+ float lumaE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1, 0), fxaaQualityRcpFrame.xy));
+ float lumaN = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 0,-1), fxaaQualityRcpFrame.xy));
+ float lumaW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1, 0), fxaaQualityRcpFrame.xy));
+/*--------------------------------------------------------------------------*/
+ float maxSM = max(lumaS, lumaM);
+ float minSM = min(lumaS, lumaM);
+ float maxESM = max(lumaE, maxSM);
+ float minESM = min(lumaE, minSM);
+ float maxWN = max(lumaN, lumaW);
+ float minWN = min(lumaN, lumaW);
+ float rangeMax = max(maxWN, maxESM);
+ float rangeMin = min(minWN, minESM);
+ float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;
+ float range = rangeMax - rangeMin;
+ float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);
+ bool earlyExit = range < rangeMaxClamped;
+/*--------------------------------------------------------------------------*/
+ if(earlyExit) {
+ return rgbyM;
+ }
+/*--------------------------------------------------------------------------*/
+ float lumaNW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1,-1), fxaaQualityRcpFrame.xy));
+ float lumaSE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1, 1), fxaaQualityRcpFrame.xy));
+ float lumaNE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1,-1), fxaaQualityRcpFrame.xy));
+ float lumaSW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1, 1), fxaaQualityRcpFrame.xy));
+/*--------------------------------------------------------------------------*/
+ float lumaNS = lumaN + lumaS;
+ float lumaWE = lumaW + lumaE;
+ float subpixRcpRange = 1.0/range;
+ float subpixNSWE = lumaNS + lumaWE;
+ float edgeHorz1 = (-2.0 * lumaM) + lumaNS;
+ float edgeVert1 = (-2.0 * lumaM) + lumaWE;
+/*--------------------------------------------------------------------------*/
+ float lumaNESE = lumaNE + lumaSE;
+ float lumaNWNE = lumaNW + lumaNE;
+ float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;
+ float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;
+/*--------------------------------------------------------------------------*/
+ float lumaNWSW = lumaNW + lumaSW;
+ float lumaSWSE = lumaSW + lumaSE;
+ float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);
+ float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);
+ float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;
+ float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;
+ float edgeHorz = abs(edgeHorz3) + edgeHorz4;
+ float edgeVert = abs(edgeVert3) + edgeVert4;
+/*--------------------------------------------------------------------------*/
+ float subpixNWSWNESE = lumaNWSW + lumaNESE;
+ float lengthSign = fxaaQualityRcpFrame.x;
+ bool horzSpan = edgeHorz >= edgeVert;
+ float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;
+/*--------------------------------------------------------------------------*/
+ if(!horzSpan) lumaN = lumaW;
+ if(!horzSpan) lumaS = lumaE;
+ if(horzSpan) lengthSign = fxaaQualityRcpFrame.y;
+ float subpixB = (subpixA * (1.0/12.0)) - lumaM;
+/*--------------------------------------------------------------------------*/
+ float gradientN = lumaN - lumaM;
+ float gradientS = lumaS - lumaM;
+ float lumaNN = lumaN + lumaM;
+ float lumaSS = lumaS + lumaM;
+ bool pairN = abs(gradientN) >= abs(gradientS);
+ float gradient = max(abs(gradientN), abs(gradientS));
+ if(pairN) lengthSign = -lengthSign;
+ float subpixC = FxaaSat(abs(subpixB) * subpixRcpRange);
+/*--------------------------------------------------------------------------*/
+ vec2 posB;
+ posB.x = posM.x;
+ posB.y = posM.y;
+ vec2 offNP;
+ offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
+ offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
+ if(!horzSpan) posB.x += lengthSign * 0.5;
+ if( horzSpan) posB.y += lengthSign * 0.5;
+/*--------------------------------------------------------------------------*/
+ vec2 posN;
+ posN.x = posB.x - offNP.x * FXAA_QUALITY__P0;
+ posN.y = posB.y - offNP.y * FXAA_QUALITY__P0;
+ vec2 posP;
+ posP.x = posB.x + offNP.x * FXAA_QUALITY__P0;
+ posP.y = posB.y + offNP.y * FXAA_QUALITY__P0;
+ float subpixD = ((-2.0)*subpixC) + 3.0;
+ float lumaEndN = FxaaLuma(FxaaTexTop(tex, posN));
+ float subpixE = subpixC * subpixC;
+ float lumaEndP = FxaaLuma(FxaaTexTop(tex, posP));
+/*--------------------------------------------------------------------------*/
+ if(!pairN) lumaNN = lumaSS;
+ float gradientScaled = gradient * 1.0/4.0;
+ float lumaMM = lumaM - lumaNN * 0.5;
+ float subpixF = subpixD * subpixE;
+ bool lumaMLTZero = lumaMM < 0.0;
+/*--------------------------------------------------------------------------*/
+ lumaEndN -= lumaNN * 0.5;
+ lumaEndP -= lumaNN * 0.5;
+ bool doneN = abs(lumaEndN) >= gradientScaled;
+ bool doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1;
+ bool doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1;
+/*--------------------------------------------------------------------------*/
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 3)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 4)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 5)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 6)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 7)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 8)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 9)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 10)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 11)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 12)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12;
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+/*--------------------------------------------------------------------------*/
+ float dstN = posM.x - posN.x;
+ float dstP = posP.x - posM.x;
+ if(!horzSpan) dstN = posM.y - posN.y;
+ if(!horzSpan) dstP = posP.y - posM.y;
+/*--------------------------------------------------------------------------*/
+ bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;
+ float spanLength = (dstP + dstN);
+ bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;
+ float spanLengthRcp = 1.0/spanLength;
+/*--------------------------------------------------------------------------*/
+ bool directionN = dstN < dstP;
+ float dst = min(dstN, dstP);
+ bool goodSpan = directionN ? goodSpanN : goodSpanP;
+ float subpixG = subpixF * subpixF;
+ float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;
+ float subpixH = subpixG * fxaaQualitySubpix;
+/*--------------------------------------------------------------------------*/
+ float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;
+ float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);
+ if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;
+ if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;
+ return vec4(FxaaTexTop(tex, posM).xyz, lumaM);
+}
+/*==========================================================================*/
diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl
new file mode 100644
index 00000000000..69ba304ca24
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl
@@ -0,0 +1,80 @@
+
+/* keep in sync with GlobalsUboStorage */
+layout(std140) uniform globalsBlock {
+ vec4 colorWire;
+ vec4 colorWireEdit;
+ vec4 colorActive;
+ vec4 colorSelect;
+ vec4 colorTransform;
+ vec4 colorLibrarySelect;
+ vec4 colorLibrary;
+ vec4 colorLamp;
+ vec4 colorSpeaker;
+ vec4 colorCamera;
+ vec4 colorEmpty;
+ vec4 colorVertex;
+ vec4 colorVertexSelect;
+ vec4 colorVertexUnreferenced;
+ vec4 colorVertexMissingData;
+ vec4 colorEditMeshActive;
+ vec4 colorEdgeSelect;
+ vec4 colorEdgeSeam;
+ vec4 colorEdgeSharp;
+ vec4 colorEdgeCrease;
+ vec4 colorEdgeBWeight;
+ vec4 colorEdgeFaceSelect;
+ vec4 colorEdgeFreestyle;
+ vec4 colorFace;
+ vec4 colorFaceSelect;
+ vec4 colorFaceFreestyle;
+ vec4 colorNormal;
+ vec4 colorVNormal;
+ vec4 colorLNormal;
+ vec4 colorFaceDot;
+ vec4 colorDeselect;
+ vec4 colorOutline;
+ vec4 colorLampNoAlpha;
+
+ vec4 colorBackground;
+
+ vec4 colorHandleFree;
+ vec4 colorHandleAuto;
+ vec4 colorHandleVect;
+ vec4 colorHandleAlign;
+ vec4 colorHandleAutoclamp;
+ vec4 colorHandleSelFree;
+ vec4 colorHandleSelAuto;
+ vec4 colorHandleSelVect;
+ vec4 colorHandleSelAlign;
+ vec4 colorHandleSelAutoclamp;
+ vec4 colorNurbUline;
+ vec4 colorNurbVline;
+ vec4 colorNurbSelUline;
+ vec4 colorNurbSelVline;
+ vec4 colorActiveSpline;
+
+ vec4 colorBonePose;
+
+ vec4 colorCurrentFrame;
+
+ vec4 colorGrid;
+ vec4 colorGridEmphasise;
+ vec4 colorGridAxisX;
+ vec4 colorGridAxisY;
+ vec4 colorGridAxisZ;
+
+ float sizeLampCenter;
+ float sizeLampCircle;
+ float sizeLampCircleShadow;
+ float sizeVertex;
+ float sizeEdge;
+ float sizeEdgeFix;
+ float sizeFaceDot;
+
+ float gridDistance;
+ float gridResolution;
+ float gridSubdivisions;
+ float gridScale;
+
+ float pad_globalsBlock;
+};
diff --git a/source/blender/draw/modes/shaders/common_hair_lib.glsl b/source/blender/draw/modes/shaders/common_hair_lib.glsl
new file mode 100644
index 00000000000..594a7b31f0b
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_hair_lib.glsl
@@ -0,0 +1,199 @@
+/**
+ * Library to create hairs dynamically from control points.
+ * This is less bandwidth intensive than fetching the vertex attributes
+ * but does more ALU work per vertex. This also reduce the number
+ * of data the CPU has to precompute and transfert for each update.
+ **/
+
+/**
+ * hairStrandsRes: Number of points per hair strand.
+ * 2 - no subdivision
+ * 3+ - 1 or more interpolated points per hair.
+ **/
+uniform int hairStrandsRes = 8;
+
+/**
+ * hairThicknessRes : Subdiv around the hair.
+ * 1 - Wire Hair: Only one pixel thick, independent of view distance.
+ * 2 - Polystrip Hair: Correct width, flat if camera is parallel.
+ * 3+ - Cylinder Hair: Massive calculation but potentially perfect. Still need proper support.
+ **/
+uniform int hairThicknessRes = 1;
+
+/* Hair thickness shape. */
+uniform float hairRadRoot = 0.01;
+uniform float hairRadTip = 0.0;
+uniform float hairRadShape = 0.5;
+uniform bool hairCloseTip = true;
+
+uniform mat4 hairDupliMatrix;
+
+/* -- Per control points -- */
+uniform samplerBuffer hairPointBuffer; /* RGBA32F */
+#define point_position xyz
+#define point_time w /* Position along the hair length */
+
+/* -- Per strands data -- */
+uniform usamplerBuffer hairStrandBuffer; /* R32UI */
+
+/* Not used, use one buffer per uv layer */
+//uniform samplerBuffer hairUVBuffer; /* RG32F */
+//uniform samplerBuffer hairColBuffer; /* RGBA16 linear color */
+
+void unpack_strand_data(uint data, out int strand_offset, out int strand_segments)
+{
+#if 0 /* Pack point count */
+ // strand_offset = (data & 0x1FFFFFFFu);
+ // strand_segments = 1u << (data >> 29u); /* We only need 3 bits to store subdivision level. */
+#else
+ strand_offset = int(data & 0x00FFFFFFu);
+ strand_segments = int(data >> 24u);
+#endif
+}
+
+/* -- Subdivision stage -- */
+/**
+ * We use a transform feedback to preprocess the strands and add more subdivision to it.
+ * For the moment theses are simple smooth interpolation but one could hope to see the full
+ * children particle modifiers being evaluated at this stage.
+ *
+ * If no more subdivision is needed, we can skip this step.
+ **/
+
+#ifdef HAIR_PHASE_SUBDIV
+int hair_get_base_id(float local_time, int strand_segments, out float interp_time)
+{
+ float time_per_strand_seg = 1.0 / float(strand_segments);
+
+ float ratio = local_time / time_per_strand_seg;
+ interp_time = fract(ratio);
+
+ return int(ratio);
+}
+
+void hair_get_interp_attribs(out vec4 data0, out vec4 data1, out vec4 data2, out vec4 data3, out float interp_time)
+{
+ float local_time = float(gl_VertexID % hairStrandsRes) / float(hairStrandsRes - 1);
+
+ int hair_id = gl_VertexID / hairStrandsRes;
+ uint strand_data = texelFetch(hairStrandBuffer, hair_id).x;
+
+ int strand_offset, strand_segments;
+ unpack_strand_data(strand_data, strand_offset, strand_segments);
+
+ int id = hair_get_base_id(local_time, strand_segments, interp_time);
+
+ int ofs_id = id + strand_offset;
+
+ data0 = texelFetch(hairPointBuffer, ofs_id - 1);
+ data1 = texelFetch(hairPointBuffer, ofs_id);
+ data2 = texelFetch(hairPointBuffer, ofs_id + 1);
+ data3 = texelFetch(hairPointBuffer, ofs_id + 2);
+
+ if (id <= 0) {
+ /* root points. Need to reconstruct previous data. */
+ data0 = data1 * 2.0 - data2;
+ }
+ if (id + 1 >= strand_segments) {
+ /* tip points. Need to reconstruct next data. */
+ data3 = data2 * 2.0 - data1;
+ }
+}
+#endif
+
+/* -- Drawing stage -- */
+/**
+ * For final drawing, the vertex index and the number of vertex per segment
+ **/
+
+#ifndef HAIR_PHASE_SUBDIV
+int hair_get_strand_id(void)
+{
+ return gl_VertexID / (hairStrandsRes * hairThicknessRes);
+}
+
+int hair_get_base_id(void)
+{
+ return gl_VertexID / hairThicknessRes;
+}
+
+/* Copied from cycles. */
+float hair_shaperadius(float shape, float root, float tip, float time)
+{
+ float radius = 1.0 - time;
+
+ if (shape < 0.0) {
+ radius = pow(radius, 1.0 + shape);
+ }
+ else {
+ radius = pow(radius, 1.0 / (1.0 - shape));
+ }
+
+ if (hairCloseTip && (time > 0.99)) {
+ return 0.0;
+ }
+
+ return (radius * (root - tip)) + tip;
+}
+
+void hair_get_pos_tan_binor_time(
+ bool is_persp, mat4 invmodel_mat, vec3 camera_pos, vec3 camera_z,
+ out vec3 wpos, out vec3 wtan, out vec3 wbinor, out float time, out float thickness, out float thick_time)
+{
+ int id = hair_get_base_id();
+ vec4 data = texelFetch(hairPointBuffer, id);
+ wpos = data.point_position;
+ time = data.point_time;
+ if (time == 0.0) {
+ /* Hair root */
+ wtan = texelFetch(hairPointBuffer, id + 1).point_position - wpos;
+ }
+ else {
+ wtan = wpos - texelFetch(hairPointBuffer, id - 1).point_position;
+ }
+
+ wpos = (hairDupliMatrix * vec4(wpos, 1.0)).xyz;
+ wtan = mat3(hairDupliMatrix) * wtan;
+
+ vec3 camera_vec = (is_persp) ? wpos - camera_pos : -camera_z;
+ wbinor = normalize(cross(camera_vec, wtan));
+
+ thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, time);
+
+ if (hairThicknessRes > 1) {
+ thick_time = float(gl_VertexID % hairThicknessRes) / float(hairThicknessRes - 1);
+ thick_time = thickness * (thick_time * 2.0 - 1.0);
+
+ /* Take object scale into account.
+ * NOTE: This only works fine with uniform scaling. */
+ float scale = 1.0 / length(mat3(invmodel_mat) * wbinor);
+
+ wpos += wbinor * thick_time * scale;
+ }
+}
+
+vec2 hair_get_customdata_vec2(const samplerBuffer cd_buf)
+{
+ int id = hair_get_strand_id();
+ return texelFetch(cd_buf, id).rg;
+}
+
+vec3 hair_get_customdata_vec3(const samplerBuffer cd_buf)
+{
+ int id = hair_get_strand_id();
+ return texelFetch(cd_buf, id).rgb;
+}
+
+vec4 hair_get_customdata_vec4(const samplerBuffer cd_buf)
+{
+ int id = hair_get_strand_id();
+ return texelFetch(cd_buf, id).rgba;
+}
+
+vec3 hair_get_strand_pos(void)
+{
+ int id = hair_get_strand_id() * hairStrandsRes;
+ return texelFetch(hairPointBuffer, id).point_position;
+}
+
+#endif
diff --git a/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl b/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl
new file mode 100644
index 00000000000..9f412c57db3
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl
@@ -0,0 +1,55 @@
+
+/* To be compiled with common_hair_lib.glsl */
+
+out vec4 outData;
+
+vec4 get_weights_cardinal(float t)
+{
+ float t2 = t * t;
+ float t3 = t2 * t;
+#if defined(CARDINAL)
+ float fc = 0.71;
+#else /* defined(CATMULL_ROM) */
+ float fc = 0.5;
+#endif
+
+ vec4 weights;
+ /* GLSL Optimized version of key_curve_position_weights() */
+ float fct = t * fc;
+ float fct2 = t2 * fc;
+ float fct3 = t3 * fc;
+ weights.x = ( fct2 * 2.0 - fct3) - fct;
+ weights.y = ( t3 * 2.0 - fct3) + (-t2 * 3.0 + fct2) + 1.0;
+ weights.z = (-t3 * 2.0 + fct3) + ( t2 * 3.0 - (2.0 * fct2)) + fct;
+ weights.w = fct3 - fct2;
+ return weights;
+}
+
+/* TODO(fclem): This one is buggy, find why. (it's not the optimization!!) */
+vec4 get_weights_bspline(float t)
+{
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ vec4 weights;
+ /* GLSL Optimized version of key_curve_position_weights() */
+ weights.xz = vec2(-0.16666666, -0.5) * t3 + (0.5 * t2 + 0.5 * vec2(-t, t) + 0.16666666);
+ weights.y = ( 0.5 * t3 - t2 + 0.66666666);
+ weights.w = ( 0.16666666 * t3);
+ return weights;
+}
+
+vec4 interp_data(vec4 v0, vec4 v1, vec4 v2, vec4 v3, vec4 w)
+{
+ return v0 * w.x + v1 * w.y + v2 * w.z + v3 * w.w;
+}
+
+void main(void)
+{
+ float interp_time;
+ vec4 data0, data1, data2, data3;
+ hair_get_interp_attribs(data0, data1, data2, data3, interp_time);
+
+ vec4 weights = get_weights_cardinal(interp_time);
+ outData = interp_data(data0, data1, data2, data3, weights);
+}
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl
new file mode 100644
index 00000000000..d261d263a6f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_view_lib.glsl
@@ -0,0 +1,14 @@
+/* keep in sync with DRWManager.view_data */
+layout(std140) uniform viewBlock {
+ /* Same order as DRWViewportMatrixType */
+ mat4 ViewProjectionMatrix;
+ mat4 ViewProjectionMatrixInverse;
+ mat4 ViewMatrix;
+ mat4 ViewMatrixInverse;
+ mat4 ProjectionMatrix;
+ mat4 ProjectionMatrixInverse;
+
+ vec4 CameraTexCoFactors;
+
+ vec4 clipPlanes[2];
+};
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl
new file mode 100644
index 00000000000..7bc9b381bad
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl
@@ -0,0 +1,96 @@
+
+#define VERTEX_ACTIVE 1 << 0
+#define VERTEX_SELECTED 1 << 1
+#define ACTIVE_NURB 1 << 2 /* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */
+#define EVEN_U_BIT 1 << 3
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 10) out;
+
+uniform vec2 viewportSize;
+uniform bool showCurveHandles;
+
+flat in int vertFlag[];
+
+out vec4 finalColor;
+
+void output_line(vec2 offset, vec4 color)
+{
+ finalColor = color;
+
+ gl_Position = gl_in[0].gl_Position;
+ gl_Position.xy += offset * gl_in[0].gl_Position.w;
+ EmitVertex();
+
+ gl_Position = gl_in[1].gl_Position;
+ gl_Position.xy += offset * gl_in[1].gl_Position.w;
+ EmitVertex();
+}
+
+void main()
+{
+ vec4 v1 = gl_in[0].gl_Position;
+ vec4 v2 = gl_in[1].gl_Position;
+
+ int is_active_nurb = (vertFlag[1] & ACTIVE_NURB);
+ int color_id = (vertFlag[1] >> 4);
+
+ /* Don't output any edges if we don't show handles */
+ if (!showCurveHandles && (color_id < 5))
+ return;
+
+ bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERTEX_SELECTED) != 0);
+
+ vec4 inner_color;
+ if (color_id == 0) inner_color = (edge_selected) ? colorHandleSelFree : colorHandleFree;
+ else if (color_id == 1) inner_color = (edge_selected) ? colorHandleSelAuto : colorHandleAuto;
+ else if (color_id == 2) inner_color = (edge_selected) ? colorHandleSelVect : colorHandleVect;
+ else if (color_id == 3) inner_color = (edge_selected) ? colorHandleSelAlign : colorHandleAlign;
+ else if (color_id == 4) inner_color = (edge_selected) ? colorHandleSelAutoclamp : colorHandleAutoclamp;
+ else {
+ bool is_selected = (((vertFlag[1] & vertFlag[0]) & VERTEX_SELECTED) != 0);
+ bool is_u_segment = (((vertFlag[1] ^ vertFlag[0]) & EVEN_U_BIT) != 0);
+ if (is_u_segment) {
+ inner_color = (is_selected) ? colorNurbSelUline : colorNurbUline;
+ }
+ else {
+ inner_color = (is_selected) ? colorNurbSelVline : colorNurbVline;
+ }
+ }
+
+ vec4 outer_color = (is_active_nurb != 0)
+ ? mix(colorActiveSpline, inner_color, 0.25) /* Minimize active color bleeding on inner_color. */
+ : vec4(inner_color.rgb, 0.0);
+
+ vec2 v1_2 = (v2.xy/v2.w - v1.xy/v1.w);
+ vec2 offset = sizeEdge * 4.0 / viewportSize; /* 4.0 is eyeballed */
+
+ if (abs(v1_2.x * viewportSize.x) < abs(v1_2.y * viewportSize.y)) {
+ offset.y = 0.0;
+ }
+ else {
+ offset.x = 0.0;
+ }
+
+ /* draw the transparent border (AA). */
+ if (is_active_nurb != 0) {
+ offset *= 0.75; /* Don't make the active "halo" appear very thick. */
+ output_line(offset * 2.0, vec4(colorActiveSpline.rgb, 0.0));
+ }
+
+ /* draw the outline. */
+ output_line(offset, outer_color);
+
+ /* draw the core of the line. */
+ output_line(vec2(0.0), inner_color);
+
+ /* draw the outline. */
+ output_line(-offset, outer_color);
+
+ /* draw the transparent border (AA). */
+ if (is_active_nurb != 0) {
+ output_line(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0));
+ }
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl
new file mode 100644
index 00000000000..d3f9deedf0c
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl
@@ -0,0 +1,15 @@
+
+/* Draw Curve Handles */
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in int data;
+
+flat out int vertFlag;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ vertFlag = data;
+}
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl
new file mode 100644
index 00000000000..85e38ba3b43
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl
@@ -0,0 +1,31 @@
+
+/* Draw Curve Vertices */
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec3 pos;
+in int data;
+
+out vec4 finalColor;
+
+#define VERTEX_ACTIVE (1 << 0)
+#define VERTEX_SELECTED (1 << 1)
+
+void main()
+{
+ if ((data & VERTEX_SELECTED) != 0) {
+ if ((data & VERTEX_ACTIVE) != 0) {
+ finalColor = colorEditMeshActive;
+ }
+ else {
+ finalColor = colorVertexSelect;
+ }
+ }
+ else {
+ finalColor = colorVertex;
+ }
+
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = sizeVertex * 2.0;
+}
diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl
new file mode 100644
index 00000000000..e78462b6915
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl
@@ -0,0 +1,22 @@
+
+flat in int vertFlag;
+
+#define VERTEX_SELECTED (1 << 0)
+#define VERTEX_ACTIVE (1 << 1)
+
+out vec4 FragColor;
+
+void main()
+{
+ /* TODO: vertex size */
+
+ if ((vertFlag & VERTEX_SELECTED) != 0) {
+ FragColor = colorVertexSelect;
+ }
+ else if ((vertFlag & VERTEX_ACTIVE) != 0) {
+ FragColor = colorEditMeshActive;
+ }
+ else {
+ FragColor = colorVertex;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl
new file mode 100644
index 00000000000..0cbc66a2b1f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl
@@ -0,0 +1,39 @@
+
+/* Draw Lattice Vertices */
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec3 pos;
+in int data;
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out int vertFlag;
+flat out int clipCase;
+
+/* See fragment shader */
+noperspective out vec4 eData1;
+flat out vec4 eData2;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void main()
+{
+ clipCase = 0;
+
+ vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ /* only vertex position 0 is used */
+ eData1 = eData2 = vec4(1e10);
+ eData2.zw = proj(pPos);
+
+ vertFlag = data;
+
+ gl_PointSize = sizeVertex;
+ gl_Position = pPos;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl
new file mode 100644
index 00000000000..b37862f2037
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl
@@ -0,0 +1,53 @@
+#define EDGE_EXISTS (1 << 0)
+#define EDGE_ACTIVE (1 << 1)
+#define EDGE_SELECTED (1 << 2)
+#define EDGE_SEAM (1 << 3)
+#define EDGE_SHARP (1 << 4)
+#define EDGE_FREESTYLE (1 << 5)
+#define EDGE_VERTEX_ACTIVE (1 << (0 + 8))
+#define EDGE_VERTEX_SELECTED (1 << (1 + 8))
+#define EDGE_VERTEX_EXISTS (1 << (2 + 8))
+
+#define VERTEX_ACTIVE (1 << 0)
+#define VERTEX_SELECTED (1 << 1)
+#define VERTEX_EXISTS (1 << 2)
+
+#define FACE_ACTIVE (1 << 3)
+#define FACE_SELECTED (1 << 4)
+#define FACE_FREESTYLE (1 << 5)
+
+uniform bool doEdges = true;
+
+vec4 EDIT_MESH_edge_color_outer(int edge_flag, bool face_active, float crease, float bweight)
+{
+ vec4 color = vec4(0.0);
+ color = ((edge_flag & EDGE_FREESTYLE) != 0) ? colorEdgeFreestyle : color;
+ color = ((edge_flag & EDGE_SHARP) != 0) ? colorEdgeSharp : color;
+ color = (crease > 0.0) ? vec4(colorEdgeCrease.rgb, crease) : color;
+ color = (bweight > 0.0) ? vec4(colorEdgeBWeight.rgb, bweight) : color;
+ color = ((edge_flag & EDGE_SEAM) != 0) ? colorEdgeSeam : color;
+
+ if (face_active) {
+ color = colorEditMeshActive;
+ }
+ return color;
+}
+
+vec4 EDIT_MESH_edge_color_inner(int edge_flag, bool face_active)
+{
+ vec4 color = colorWireEdit;
+#ifdef EDGE_SELECTION
+ color = ((edge_flag & EDGE_SELECTED) != 0) ? colorEdgeSelect : color;
+ color = ((edge_flag & EDGE_ACTIVE) != 0) ? colorEditMeshActive : color;
+#else
+ color = (doEdges && (edge_flag & EDGE_SELECTED) != 0) ? colorEdgeSelect : color;
+#endif
+ return color;
+}
+
+vec4 EDIT_MESH_vertex_color(int vertex_flag)
+{
+ vec4 color = colorWireEdit;
+ color = (doEdges && (vertex_flag & (VERTEX_ACTIVE | VERTEX_SELECTED)) != 0) ? colorEdgeSelect : color;
+ return color;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl
new file mode 100644
index 00000000000..71cc1ccde8d
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl
@@ -0,0 +1,19 @@
+
+flat in int isSelected;
+#ifdef VERTEX_FACING
+flat in float facing;
+#endif
+
+out vec4 FragColor;
+
+void main()
+{
+ if (isSelected != 0)
+ FragColor = colorFaceDot;
+ else
+ FragColor = colorVertex;
+
+#ifdef VERTEX_FACING
+ FragColor.a *= 1.0 - abs(facing) * 0.4;
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl
new file mode 100644
index 00000000000..50f6f3e2cf8
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl
@@ -0,0 +1,31 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 norAndFlag;
+
+flat out int isSelected;
+
+#ifdef VERTEX_FACING
+uniform mat4 ProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+
+flat out float facing;
+#endif
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ /* Bias Facedot Z position in clipspace. */
+ gl_Position.z -= 0.00035;
+ gl_PointSize = sizeFaceDot;
+ isSelected = int(norAndFlag.w);
+#ifdef VERTEX_FACING
+ vec3 view_normal = normalize(NormalMatrix * norAndFlag.xyz);
+ vec3 view_vec = (ProjectionMatrix[3][3] == 0.0)
+ ? normalize((ModelViewMatrix * vec4(pos, 1.0)).xyz)
+ : vec3(0.0, 0.0, 1.0);
+ facing = dot(view_vec, view_normal);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
new file mode 100644
index 00000000000..2e729009a38
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
@@ -0,0 +1,7 @@
+flat in vec4 faceColor;
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = faceColor;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl
new file mode 100644
index 00000000000..eb68eb9b0dc
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl
@@ -0,0 +1,28 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform ivec4 dataMask = ivec4(0xFF);
+
+in vec3 pos;
+in ivec4 data;
+
+flat out vec4 faceColor;
+
+#define FACE_ACTIVE (1 << 3)
+#define FACE_SELECTED (1 << 4)
+#define FACE_FREESTYLE (1 << 5)
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ ivec4 data_m = data & dataMask;
+
+ if ((data_m.x & FACE_ACTIVE) != 0)
+ faceColor = colorFaceSelect;
+ else if ((data_m.x & FACE_SELECTED) != 0)
+ faceColor = colorFaceSelect;
+ else if ((data_m.x & FACE_FREESTYLE) != 0)
+ faceColor = colorFaceFreestyle;
+ else
+ faceColor = colorFace;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
new file mode 100644
index 00000000000..8d7a653c2fe
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
@@ -0,0 +1,152 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+uniform float faceAlphaMod;
+uniform float edgeScale;
+uniform bool isXray = false;
+
+flat in vec3 edgesCrease;
+flat in vec3 edgesBweight;
+flat in vec4 faceColor;
+flat in ivec3 flag;
+#ifdef VERTEX_SELECTION
+in vec3 vertexColor;
+#endif
+
+#ifdef EDGE_FIX
+flat in vec2 ssPos[3];
+#else
+in vec3 barycentric;
+#endif
+
+#ifdef VERTEX_FACING
+in float facing;
+#endif
+
+out vec4 FragColor;
+
+/* Vertex flag is shifted and combined with the edge flag */
+#define FACE_ACTIVE_ (FACE_ACTIVE << 8)
+
+#define LARGE_EDGE_SIZE 2.15
+
+/* Enough to visually fill gaps and not enough to mess the AA gradient too much. */
+#define EDGE_FIX_ALPHA 0.67
+
+void distToEdgesAndPoints(out vec3 edges, out vec3 points)
+{
+#ifdef EDGE_FIX
+ vec2 e0 = normalize(ssPos[1] - ssPos[0] + 1e-8);
+ vec2 e1 = normalize(ssPos[2] - ssPos[1] + 1e-8);
+ vec2 e2 = normalize(ssPos[0] - ssPos[2] + 1e-8);
+ e0 = vec2(-e0.y, e0.x);
+ e1 = vec2(-e1.y, e1.x);
+ e2 = vec2(-e2.y, e2.x);
+ vec2 p0 = gl_FragCoord.xy - ssPos[0];
+ vec2 p1 = gl_FragCoord.xy - ssPos[1];
+ vec2 p2 = gl_FragCoord.xy - ssPos[2];
+ edges.z = abs(dot(e0, p0));
+ edges.x = abs(dot(e1, p1));
+ edges.y = abs(dot(e2, p2));
+#else
+ vec3 dx = dFdx(barycentric);
+ vec3 dy = dFdy(barycentric);
+ /* per component derivative */
+ vec2 d0 = vec2(dx.x, dy.x);
+ vec2 d1 = vec2(dx.y, dy.y);
+ vec2 d2 = vec2(dx.z, dy.z);
+ vec3 d = vec3(length(d0), length(d1), length(d2));
+
+ edges = abs(vec3(barycentric / d));
+#endif
+
+#if defined(VERTEX_SELECTION) && defined(EDGE_FIX)
+ points.x = dot(p0, p0);
+ points.y = dot(p1, p1);
+ points.z = dot(p2, p2);
+ points = sqrt(points);
+#else
+ points = vec3(1e10);
+#endif
+}
+
+void colorDist(vec4 color, float dist)
+{
+ FragColor = (dist < 0) ? color : FragColor;
+}
+
+#ifdef ANTI_ALIASING
+void colorDistEdge(vec4 color, float dist)
+{
+ FragColor.rgb *= FragColor.a;
+ FragColor = mix(color, FragColor, clamp(dist, 0.0, 1.0));
+ FragColor.rgb /= max(1e-8, FragColor.a);
+}
+#else
+#define colorDistEdge colorDist
+#endif
+
+void main()
+{
+ vec3 e, p;
+ distToEdgesAndPoints(e, p);
+
+ /* Face */
+ FragColor = faceColor;
+ FragColor.a *= faceAlphaMod;
+
+ /* Edges */
+ float sizeEdgeFinal = sizeEdge * edgeScale;
+
+ for (int v = 0; v < 3; ++v) {
+ if ((flag[v] & EDGE_EXISTS) != 0) {
+ /* Outer large edge */
+ float largeEdge = e[v] - sizeEdgeFinal * LARGE_EDGE_SIZE;
+
+ vec4 large_edge_color = EDIT_MESH_edge_color_outer(flag[v], (flag[0] & FACE_ACTIVE_) != 0, edgesCrease[v], edgesBweight[v]);
+#ifdef EDGE_FIX
+ large_edge_color *= isXray ? 1.0 : EDGE_FIX_ALPHA;
+#endif
+ if (large_edge_color.a != 0.0) {
+ colorDistEdge(large_edge_color, largeEdge);
+ }
+
+ /* Inner thin edge */
+ float innerEdge = e[v] - sizeEdgeFinal;
+#ifdef ANTI_ALIASING
+ innerEdge += 0.4;
+#endif
+
+#ifdef VERTEX_SELECTION
+ vec4 inner_edge_color = vec4(vertexColor, 1.0);
+#else
+ vec4 inner_edge_color = EDIT_MESH_edge_color_inner(flag[v], (flag[0] & FACE_ACTIVE_) != 0);
+#endif
+#ifdef EDGE_FIX
+ inner_edge_color *= isXray ? 1.0 : EDGE_FIX_ALPHA;
+#endif
+ colorDistEdge(inner_edge_color, innerEdge);
+ }
+ }
+
+#if defined(VERTEX_SELECTION) && defined(EDGE_FIX)
+ /* Points */
+ for (int v = 0; v < 3; ++v) {
+ if ((flag[v] & EDGE_VERTEX_EXISTS) != 0) {
+ float size = p[v] - sizeVertex;
+ vec4 point_color = colorVertex;
+ point_color = ((flag[v] & EDGE_VERTEX_SELECTED) != 0) ? colorVertexSelect : point_color;
+ point_color = ((flag[v] & EDGE_VERTEX_ACTIVE) != 0) ? vec4(colorEditMeshActive.xyz, 1.0) : point_color;
+ colorDist(point_color, size);
+ }
+ }
+#endif
+
+#ifdef VERTEX_FACING
+ FragColor.a *= 1.0 - abs(facing) * 0.4;
+#endif
+
+ /* don't write depth if not opaque */
+ if (FragColor.a == 0.0) discard;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl
new file mode 100644
index 00000000000..1a44e4a9e4f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl
@@ -0,0 +1,119 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+layout(lines) in;
+layout(triangle_strip, max_vertices=4) out;
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec4 pPos[];
+in ivec4 vData[];
+#ifdef VERTEX_FACING
+in float vFacing[];
+#endif
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out vec4 faceColor;
+flat out ivec3 flag;
+#ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+#endif
+#ifdef VERTEX_FACING
+out float facing;
+#endif
+
+/* See fragment shader */
+flat out vec2 ssPos[3];
+
+/* Some bugged AMD drivers need these global variables. See T55961 */
+#ifdef VERTEX_SELECTION
+vec3 vertex_color[3];
+#endif
+
+#ifdef VERTEX_FACING
+float v_facing[3];
+#endif
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void doVertex(int v, vec4 pos)
+{
+#ifdef VERTEX_SELECTION
+ vertexColor = vertex_color[v];
+#endif
+
+#ifdef VERTEX_FACING
+ facing = v_facing[v];
+#endif
+
+ gl_Position = pos;
+
+ EmitVertex();
+}
+
+void main()
+{
+ /* Face */
+ faceColor = vec4(0.0);
+
+ /* Proj Vertex */
+ vec2 pos[2] = vec2[2](proj(pPos[0]), proj(pPos[1]));
+
+ /* little optimization use a vec4 to vectorize
+ * following operations */
+ vec4 dirs1, dirs2;
+
+ /* Edge normalized vector */
+ dirs1.xy = normalize(pos[1] - pos[0]);
+
+ /* perpendicular to dir */
+ dirs1.zw = vec2(-dirs1.y, dirs1.x);
+
+ /* Make it view independent */
+ dirs1 *= sizeEdgeFix / viewportSize.xyxy;
+
+ dirs2 = dirs1;
+
+ /* Perspective */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ dirs1 *= pPos[0].w;
+ dirs2 *= pPos[1].w;
+ }
+
+#ifdef VERTEX_SELECTION
+ vertex_color[0] = EDIT_MESH_vertex_color(vData[0].x).rgb;
+ vertex_color[1] = EDIT_MESH_vertex_color(vData[1].x).rgb;
+#endif
+
+#ifdef VERTEX_FACING
+ /* Weird but some buggy AMD drivers need this. */
+ v_facing[0] = vFacing[0];
+ v_facing[1] = vFacing[1];
+#endif
+
+ /* Edge / Vert data */
+ ssPos[0] = ssPos[2] = pos[0];
+ ssPos[1] = pos[1];
+ flag[0] = flag[2] = (vData[0].x << 8);
+ flag[1] = (vData[1].x << 8);
+ doVertex(0, pPos[0] + vec4( dirs1.zw, 0.0, 0.0));
+ doVertex(0, pPos[0] + vec4(-dirs1.zw, 0.0, 0.0));
+
+ flag[2] |= vData[0].y;
+ edgesCrease[2] = vData[0].z / 255.0;
+ edgesBweight[2] = vData[0].w / 255.0;
+
+ doVertex(1, pPos[1] + vec4( dirs2.zw, 0.0, 0.0));
+ doVertex(1, pPos[1] + vec4(-dirs2.zw, 0.0, 0.0));
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl
new file mode 100644
index 00000000000..a04494d2ec4
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl
@@ -0,0 +1,211 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+layout(triangles) in;
+
+/* To fix the edge artifacts, we render
+ * an outline strip around the screenspace
+ * triangle. Order is important.
+ * TODO diagram
+ */
+layout(triangle_strip, max_vertices=12) out;
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+uniform bool isXray = false;
+
+in vec4 pPos[];
+in ivec4 vData[];
+#ifdef VERTEX_FACING
+in float vFacing[];
+#endif
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out vec4 faceColor;
+flat out ivec3 flag;
+
+flat out vec2 ssPos[3];
+#ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+#endif
+#ifdef VERTEX_FACING
+out float facing;
+#endif
+
+#ifdef ANTI_ALIASING
+#define Z_OFFSET -0.0005
+#else
+#define Z_OFFSET 0.0
+#endif
+
+/* Some bugged AMD drivers need these global variables. See T55961 */
+#ifdef VERTEX_SELECTION
+vec3 vertex_color[3];
+#endif
+
+#ifdef VERTEX_FACING
+float v_facing[3];
+#endif
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void doVertex(int v)
+{
+#ifdef VERTEX_SELECTION
+ vertexColor = vertex_color[v];
+#endif
+
+#ifdef VERTEX_FACING
+ facing = v_facing[v];
+#endif
+ gl_Position = pPos[v];
+
+ EmitVertex();
+}
+
+void doVertexOfs(int v, vec2 fixvec)
+{
+#ifdef VERTEX_SELECTION
+ vertexColor = vertex_color[v];
+#endif
+
+#ifdef VERTEX_FACING
+ facing = v_facing[v];
+#endif
+ float z_ofs = Z_OFFSET * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0);
+ gl_Position = pPos[v] + vec4(fixvec * pPos[v].w, z_ofs, 0.0);
+
+ EmitVertex();
+}
+
+void mask_edge_flag(int v, ivec3 eflag)
+{
+ int vaf = (v + 1) % 3;
+
+ /* Only shade the edge that we are currently drawing.
+ * (fix corner bleeding) */
+ flag = eflag & ~EDGE_VERTEX_EXISTS;
+ flag[vaf] &= ~EDGE_EXISTS;
+ flag[v] &= ~EDGE_EXISTS;
+}
+
+vec2 compute_fixvec(int i)
+{
+ int i1 = (i + 1) % 3;
+ int i2 = (i + 2) % 3;
+ /* This fix the case when 2 vertices are perfectly aligned
+ * and corner vectors have nowhere to go.
+ * ie: length(cornervec[i]) == 0 */
+ const float epsilon = 1e-2; /* in pixel so not that much */
+ const vec2 bias[3] = vec2[3](
+ vec2( epsilon, epsilon),
+ vec2(-epsilon, epsilon),
+ vec2( 0.0, -epsilon)
+ );
+ vec2 v1 = ssPos[i] + bias[i];
+ vec2 v2 = ssPos[i1] + bias[i1];
+ vec2 v3 = ssPos[i2] + bias[i2];
+ /* Edge normalized vector */
+ vec2 dir = normalize(v2 - v1);
+ vec2 dir2 = normalize(v3 - v1);
+ /* perpendicular to dir */
+ vec2 perp = vec2(-dir.y, dir.x);
+ /* Backface case */
+ if (dot(perp, dir2) > 0.0) {
+ perp = -perp;
+ }
+ /* Make it view independent */
+ return perp * sizeEdgeFix / viewportSize;
+}
+
+void main()
+{
+ /* Edge */
+ ivec3 eflag;
+ for (int v = 0; v < 3; ++v) {
+ eflag[v] = vData[v].y | (vData[v].x << 8);
+ edgesCrease[v] = vData[v].z / 255.0;
+ edgesBweight[v] = vData[v].w / 255.0;
+ }
+
+ /* Face */
+ vec4 fcol;
+ if ((vData[0].x & FACE_ACTIVE) != 0)
+ fcol = colorFaceSelect;
+ else if ((vData[0].x & FACE_SELECTED) != 0)
+ fcol = colorFaceSelect;
+ else if ((vData[0].x & FACE_FREESTYLE) != 0)
+ fcol = colorFaceFreestyle;
+ else
+ fcol = colorFace;
+
+ /* Vertex */
+ ssPos[0] = proj(pPos[0]);
+ ssPos[1] = proj(pPos[1]);
+ ssPos[2] = proj(pPos[2]);
+
+#ifdef VERTEX_SELECTION
+ vertex_color[0] = EDIT_MESH_vertex_color(vData[0].x).rgb;
+ vertex_color[1] = EDIT_MESH_vertex_color(vData[1].x).rgb;
+ vertex_color[2] = EDIT_MESH_vertex_color(vData[2].x).rgb;
+#endif
+
+#ifdef VERTEX_FACING
+ /* Weird but some buggy AMD drivers need this. */
+ v_facing[0] = vFacing[0];
+ v_facing[1] = vFacing[1];
+ v_facing[2] = vFacing[2];
+#endif
+
+ /* Remember that we are assuming the last vertex
+ * of a triangle is the provoking vertex (decide what flat attribs are). */
+
+ if ((eflag[2] & EDGE_EXISTS) != 0) {
+ /* Do 0 -> 1 edge strip */
+ faceColor = vec4(fcol.rgb, 0.0);
+ mask_edge_flag(0, eflag);
+
+ vec2 fixvec = compute_fixvec(0);
+ doVertexOfs(0, fixvec);
+ doVertexOfs(1, fixvec);
+ }
+
+ doVertex(0);
+ doVertex(1);
+
+ /* Do face triangle */
+ faceColor = fcol;
+ flag = (isXray) ? ivec3(0) : eflag;
+ doVertex(2);
+ faceColor.a = 0.0; /* to not let face color bleed */
+
+ if ((eflag[0] & EDGE_EXISTS) != 0) {
+ /* Do 1 -> 2 edge strip */
+ mask_edge_flag(1, eflag);
+
+ vec2 fixvec = compute_fixvec(1);
+ doVertexOfs(1, fixvec);
+ doVertexOfs(2, fixvec);
+ }
+ EndPrimitive();
+
+ if ((eflag[1] & EDGE_EXISTS) != 0) {
+ /* Do 2 -> 0 edge strip */
+ mask_edge_flag(2, eflag);
+ doVertex(2);
+ doVertex(0);
+
+ vec2 fixvec = compute_fixvec(2);
+ doVertexOfs(2, fixvec);
+ doVertexOfs(0, fixvec);
+ EndPrimitive();
+ }
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl
new file mode 100644
index 00000000000..3fd4d263aa2
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl
@@ -0,0 +1,7 @@
+
+in vec2 pos;
+
+void main()
+{
+ gl_Position = vec4(pos, 1.0, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl
new file mode 100644
index 00000000000..8f94a105332
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl
@@ -0,0 +1,22 @@
+
+out vec4 FragColor;
+
+uniform sampler2D wireColor;
+uniform sampler2D wireDepth;
+uniform sampler2D sceneDepth;
+uniform float alpha;
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ float wire_depth = texelFetch(wireDepth, uv, 0).r;
+ float scene_depth = texelFetch(sceneDepth, uv, 0).r;
+ vec4 wire_color = texelFetch(wireColor, uv, 0).rgba;
+
+ FragColor = wire_color;
+
+ /* Modulate alpha if occluded */
+ if (wire_depth > scene_depth) {
+ FragColor.a *= alpha;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl
new file mode 100644
index 00000000000..3886213ce49
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_points_vert.glsl
@@ -0,0 +1,49 @@
+
+uniform mat3 NormalMatrix;
+uniform mat4 ProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat4 ModelViewProjectionMatrix;
+uniform float ofs = 3e-5;
+
+in vec3 pos;
+in ivec4 data;
+#ifdef VERTEX_FACING
+in vec3 vnor;
+#endif
+
+out vec4 finalColor;
+
+void main()
+{
+ finalColor = colorVertex;
+ finalColor = ((data.x & VERTEX_SELECTED) != 0) ? colorVertexSelect : finalColor;
+ finalColor = ((data.x & VERTEX_ACTIVE) != 0) ? vec4(colorEditMeshActive.xyz, 1.0) : finalColor;
+
+ gl_PointSize = sizeVertex * 2.0;
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_Position.z -= ofs * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0);
+
+ /* Make selected and active vertex always on top. */
+ if ((data.x & VERTEX_SELECTED) != 0) {
+ gl_Position.z -= 1e-7;
+ }
+ if ((data.x & VERTEX_ACTIVE) != 0) {
+ gl_Position.z -= 1e-7;
+ }
+
+#ifdef VERTEX_FACING
+ vec4 vPos = ModelViewMatrix * vec4(pos, 1.0);
+ vec3 view_normal = normalize(NormalMatrix * vnor);
+ vec3 view_vec = (ProjectionMatrix[3][3] == 0.0)
+ ? normalize(vPos.xyz)
+ : vec3(0.0, 0.0, 1.0);
+ float facing = dot(view_vec, view_normal);
+
+ finalColor.a *= 1.0 - abs(facing) * 0.4;
+#endif
+
+ if ((data.x & VERTEX_EXISTS) == 0) {
+ gl_Position = vec4(0.0);
+ gl_PointSize = 0.0;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl
new file mode 100644
index 00000000000..e4268188e09
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl
@@ -0,0 +1,102 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+uniform mat3 NormalMatrix;
+uniform mat4 ProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat4 ModelViewProjectionMatrix;
+uniform ivec4 dataMask = ivec4(0xFF);
+
+uniform float ofs = 1e-5;
+
+uniform isamplerBuffer dataBuffer;
+
+in vec3 pos;
+#ifdef VERTEX_FACING
+in vec3 vnor;
+#endif
+
+#ifdef EDGE_FIX
+in ivec4 data;
+
+out vec4 pPos;
+out ivec4 vData;
+# ifdef VERTEX_FACING
+out float vFacing;
+# endif
+
+void main()
+{
+ pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ pPos.z -= ofs * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0);
+ vData = data & dataMask;
+# ifdef VERTEX_FACING
+ vec4 vpos = ModelViewMatrix * vec4(pos, 1.0);
+ vec3 view_normal = normalize(NormalMatrix * vnor);
+ vec3 view_vec = (ProjectionMatrix[3][3] == 0.0)
+ ? normalize(vpos.xyz)
+ : vec3(0.0, 0.0, 1.0);
+ vFacing = dot(view_vec, view_normal);
+# endif
+}
+
+#else /* EDGE_FIX */
+
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out vec4 faceColor;
+flat out ivec3 flag;
+# ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+# endif
+# ifdef VERTEX_FACING
+out float facing;
+# endif
+
+out vec3 barycentric;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_Position.z -= ofs * ((ProjectionMatrix[3][3] == 0.0) ? 1.0 : 0.0);
+
+ int v_0 = (gl_VertexID / 3) * 3;
+ int vidx = gl_VertexID % 3;
+ barycentric = vec3(equal(ivec3(0, 1, 2), ivec3(vidx)));
+
+ /* Edge */
+ ivec4 vData[3], data = ivec4(0);
+ ivec3 eflag;
+ for (int v = 0; v < 3; ++v) {
+ data = texelFetch(dataBuffer, v_0 + v);
+ vData[v] = data & dataMask;
+ flag[v] = eflag[v] = vData[v].y | (vData[v].x << 8);
+ edgesCrease[v] = vData[v].z / 255.0;
+ edgesBweight[v] = vData[v].w / 255.0;
+ }
+
+ /* Face */
+ if ((vData[0].x & FACE_ACTIVE) != 0)
+ faceColor = colorFaceSelect;
+ else if ((vData[0].x & FACE_SELECTED) != 0)
+ faceColor = colorFaceSelect;
+ else if ((vData[0].x & FACE_FREESTYLE) != 0)
+ faceColor = colorFaceFreestyle;
+ else
+ faceColor = colorFace;
+
+# ifdef VERTEX_SELECTION
+ vertexColor = EDIT_MESH_vertex_color(vData[vidx].x).rgb;
+# endif
+# ifdef VERTEX_FACING
+ vec4 vPos = ModelViewMatrix * vec4(pos, 1.0);
+ vec3 view_normal = normalize(NormalMatrix * vnor);
+ vec3 view_vec = (ProjectionMatrix[3][3] == 0.0)
+ ? normalize(vPos.xyz)
+ : vec3(0.0, 0.0, 1.0);
+ facing = dot(view_vec, view_normal);
+# endif
+}
+
+#endif
diff --git a/source/blender/draw/modes/shaders/edit_normals_geom.glsl b/source/blender/draw/modes/shaders/edit_normals_geom.glsl
new file mode 100644
index 00000000000..d17823f2f5a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_normals_geom.glsl
@@ -0,0 +1,15 @@
+
+layout(points) in;
+layout(line_strip, max_vertices=2) out;
+
+flat in vec4 v1[1];
+flat in vec4 v2[1];
+
+void main()
+{
+ gl_Position = v1[0];
+ EmitVertex();
+ gl_Position = v2[0];
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_normals_vert.glsl b/source/blender/draw/modes/shaders/edit_normals_vert.glsl
new file mode 100644
index 00000000000..3ce7e618511
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_normals_vert.glsl
@@ -0,0 +1,30 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 ProjectionMatrix;
+uniform float normalSize;
+
+in vec3 pos;
+
+#ifdef LOOP_NORMALS
+in vec3 lnor;
+#define nor lnor
+
+#elif defined(FACE_NORMALS)
+in vec4 norAndFlag;
+#define nor norAndFlag.xyz
+#else
+
+in vec3 vnor;
+#define nor vnor
+#endif
+
+flat out vec4 v1;
+flat out vec4 v2;
+
+void main()
+{
+ v1 = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ vec3 n = normalize(NormalMatrix * nor); /* viewspace */
+ v2 = v1 + ProjectionMatrix * vec4(n * normalSize, 0.0);
+}
diff --git a/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl b/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl
new file mode 100644
index 00000000000..10e8805ef55
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_empty_axes_vert.glsl
@@ -0,0 +1,29 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screenVecs[3];
+
+/* ---- Instantiated Attribs ---- */
+in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */
+in vec2 screenPos;
+
+/* ---- Per instance Attribs ---- */
+in vec3 color;
+in float size;
+in mat4 InstanceModelMatrix;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ float draw_size = 4.0 * size;
+ vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz;
+ vec3 loc = InstanceModelMatrix[3].xyz;
+ vec3 wpos = loc + chosen_axis * fract(axis) * draw_size;
+ vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y;
+ /* Scale uniformly by axis length */
+ spos *= length(chosen_axis) * draw_size;
+
+ gl_Position = ViewProjectionMatrix * vec4(wpos + spos, 1.0);
+
+ finalColor = vec4(color, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
new file mode 100644
index 00000000000..e47b28d80c6
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
@@ -0,0 +1,33 @@
+
+flat in vec4 finalColor;
+
+#ifndef USE_WIRE
+in vec2 texCoord_interp;
+#endif
+
+out vec4 fragColor;
+
+#ifndef USE_WIRE
+uniform sampler2D image;
+#endif
+
+uniform int depthMode;
+
+void main()
+{
+#ifdef USE_WIRE
+ fragColor = finalColor;
+#else
+ fragColor = finalColor * texture(image, texCoord_interp);
+#endif
+
+ if (depthMode == DEPTH_BACK) {
+ gl_FragDepth = 0.999999;
+ }
+ else if (depthMode == DEPTH_FRONT) {
+ gl_FragDepth = 0.000001;
+ }
+ else if (depthMode == DEPTH_UNCHANGED) {
+ gl_FragDepth = gl_FragCoord.z;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl
new file mode 100644
index 00000000000..3469e37358e
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl
@@ -0,0 +1,32 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform float aspectX;
+uniform float aspectY;
+uniform float size;
+uniform vec2 offset;
+#ifdef USE_WIRE
+uniform vec3 color;
+#else
+uniform vec4 objectColor;
+#endif
+
+in vec2 texCoord;
+in vec2 pos;
+
+flat out vec4 finalColor;
+
+#ifndef USE_WIRE
+out vec2 texCoord_interp;
+#endif
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(
+ (pos + offset) * (size * vec2(aspectX, aspectY)),
+ 0.0, 1.0);
+#ifdef USE_WIRE
+ finalColor = vec4(color, 1.0);
+#else
+ texCoord_interp = texCoord;
+ finalColor = objectColor;
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_grid_frag.glsl b/source/blender/draw/modes/shaders/object_grid_frag.glsl
new file mode 100644
index 00000000000..35a95e809df
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_grid_frag.glsl
@@ -0,0 +1,246 @@
+
+/* Infinite grid
+ * Author: Clément Foucault */
+
+out vec4 FragColor;
+
+uniform mat4 ProjectionMatrix;
+uniform vec3 cameraPos;
+uniform vec3 planeNormal;
+uniform vec3 planeAxes;
+uniform vec3 eye;
+uniform vec4 gridSettings;
+uniform vec2 viewportSize;
+uniform vec4 screenvecs[3];
+uniform float lineKernel = 0.0;
+uniform float gridOneOverLogSubdiv;
+uniform sampler2D depthBuffer;
+
+#define gridDistance gridSettings.x
+#define gridResolution gridSettings.y
+#define gridScale gridSettings.z
+#define gridSubdiv gridSettings.w
+
+uniform int gridFlag;
+
+#define AXIS_X (1 << 0)
+#define AXIS_Y (1 << 1)
+#define AXIS_Z (1 << 2)
+#define GRID (1 << 3)
+#define PLANE_XY (1 << 4)
+#define PLANE_XZ (1 << 5)
+#define PLANE_YZ (1 << 6)
+#define GRID_BACK (1 << 9) /* grid is behind objects */
+
+#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */
+
+/**
+ * We want to know how much a pixel is covered by a line.
+ * We replace the square pixel with acircle of the same area and try to find the intersection area.
+ * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment
+ * The formula for the area uses inverse trig function and is quite complexe.
+ * Instead, we approximate it by using the smoothstep function and a 1.05 factor to the disc radius.
+ **/
+#define DISC_RADIUS (M_1_SQRTPI * 1.05)
+#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS)
+#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS)
+
+float get_grid(vec2 co, vec2 fwidthCos, float grid_size)
+{
+ float half_size = grid_size / 2.0;
+ /* triangular wave pattern, amplitude is [0, half_size] */
+ vec2 grid_domain = abs(mod(co + half_size, grid_size) - half_size);
+ /* modulate by the absolute rate of change of the coordinates
+ * (make lines have the same width under perspective) */
+ grid_domain /= fwidthCos;
+
+ /* collapse waves */
+ float line_dist = min(grid_domain.x, grid_domain.y);
+
+ return 1.0 - smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, line_dist - lineKernel);
+}
+
+vec3 get_axes(vec3 co, vec3 fwidthCos, float line_size)
+{
+ vec3 axes_domain = abs(co);
+ /* modulate by the absolute rate of change of the coordinates
+ * (make line have the same width under perspective) */
+ axes_domain /= fwidthCos;
+
+ return 1.0 - smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, axes_domain - (line_size + lineKernel));
+}
+
+vec3 get_floor_pos(vec2 uv, out vec3 wPos)
+{
+ vec3 camera_vec, camera_pos, corner_pos;
+ vec3 floored_pos = planeAxes * floor(screenvecs[2].xyz);
+ corner_pos = screenvecs[2].xyz - floored_pos;
+
+ vec3 pixel_pos = corner_pos + uv.x * screenvecs[0].xyz + uv.y * screenvecs[1].xyz;
+
+ /* if perspective */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ camera_pos = cameraPos - floored_pos;
+ camera_vec = normalize(pixel_pos - camera_pos);
+ }
+ else {
+ camera_pos = pixel_pos;
+ camera_vec = normalize(eye);
+ }
+
+ float plane_normal_dot_camera_vec = dot(planeNormal, camera_vec);
+ float p = -dot(planeNormal, camera_pos);
+ if (plane_normal_dot_camera_vec != 0) {
+ p /= plane_normal_dot_camera_vec;
+ }
+ vec3 plane = camera_pos + camera_vec * p;
+
+ /* fix residual imprecision */
+ plane *= planeAxes;
+
+ /* Recover non-offseted world position */
+ wPos = plane + floored_pos;
+
+ return plane;
+}
+
+void main()
+{
+ vec2 sPos = gl_FragCoord.xy / viewportSize; /* Screen [0,1] position */
+
+ /* To reduce artifacts, use a local version of the positions
+ * to compute derivatives since they are not position dependent.
+ * This gets rid of the blocky artifacts. Unfortunately we still
+ * need the world position for the grid to scale properly from the origin. */
+ vec3 gPos, wPos; /* Grid pos., World pos. */
+ gPos = get_floor_pos(sPos, wPos);
+
+ vec3 fwidthPos = fwidth(gPos);
+
+ float dist, fade;
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ vec3 viewvec = cameraPos - wPos;
+ dist = length(viewvec);
+ viewvec /= dist;
+
+ float angle;
+ if ((gridFlag & PLANE_XZ) != 0) {
+ angle = viewvec.y;
+ }
+ else if ((gridFlag & PLANE_YZ) != 0) {
+ angle = viewvec.x;
+ }
+ else {
+ angle = viewvec.z;
+ }
+
+ angle = 1.0 - abs(angle);
+ angle *= angle;
+ fade = 1.0 - angle * angle;
+ fade *= 1.0 - smoothstep(0.0, gridDistance, dist - gridDistance);
+ }
+ else {
+ dist = abs(gl_FragCoord.z * 2.0 - 1.0);
+ fade = 1.0 - smoothstep(0.0, 0.5, dist - 0.5);
+ dist = 1.0; /* avoid branch after */
+
+ if ((gridFlag & PLANE_XY) != 0) {
+ float angle = 1.0 - abs(eye.z);
+ dist = 1.0 + angle * 2.0;
+ angle *= angle;
+ fade *= 1.0 - angle * angle;
+ }
+ }
+
+ if ((gridFlag & GRID) != 0) {
+ float grid_res = log(dist * gridResolution) * gridOneOverLogSubdiv;
+
+ float blend = fract(-max(grid_res, 0.0));
+ float lvl = floor(grid_res);
+
+ /* from biggest to smallest */
+ float scaleA = gridScale * pow(gridSubdiv, max(lvl - 1.0, 0.0));
+ float scaleB = gridScale * pow(gridSubdiv, max(lvl + 0.0, 0.0));
+ float scaleC = gridScale * pow(gridSubdiv, max(lvl + 1.0, 1.0));
+
+ vec2 grid_pos, grid_fwidth;
+ if ((gridFlag & PLANE_XZ) != 0) {
+ grid_pos = wPos.xz;
+ grid_fwidth = fwidthPos.xz;
+ }
+ else if ((gridFlag & PLANE_YZ) != 0) {
+ grid_pos = wPos.yz;
+ grid_fwidth = fwidthPos.yz;
+ }
+ else {
+ grid_pos = wPos.xy;
+ grid_fwidth = fwidthPos.xy;
+ }
+
+ float gridA = get_grid(grid_pos, grid_fwidth, scaleA);
+ float gridB = get_grid(grid_pos, grid_fwidth, scaleB);
+ float gridC = get_grid(grid_pos, grid_fwidth, scaleC);
+
+ FragColor = colorGrid;
+ FragColor.a *= gridA * blend;
+ FragColor = mix(FragColor, mix(colorGrid, colorGridEmphasise, blend), gridB);
+ FragColor = mix(FragColor, colorGridEmphasise, gridC);
+ }
+ else {
+ FragColor = vec4(colorGrid.rgb, 0.0);
+ }
+
+ if ((gridFlag & (AXIS_X | AXIS_Y | AXIS_Z)) != 0) {
+ /* Setup axes 'domains' */
+ vec3 axes_dist, axes_fwidth;
+
+ if ((gridFlag & AXIS_X) != 0) {
+ axes_dist.x = dot(wPos.yz, planeAxes.yz);
+ axes_fwidth.x = dot(fwidthPos.yz, planeAxes.yz);
+ }
+ if ((gridFlag & AXIS_Y) != 0) {
+ axes_dist.y = dot(wPos.xz, planeAxes.xz);
+ axes_fwidth.y = dot(fwidthPos.xz, planeAxes.xz);
+ }
+ if ((gridFlag & AXIS_Z) != 0) {
+ axes_dist.z = dot(wPos.xy, planeAxes.xy);
+ axes_fwidth.z = dot(fwidthPos.xy, planeAxes.xy);
+ }
+
+ /* Computing all axes at once using vec3 */
+ vec3 axes = get_axes(axes_dist, axes_fwidth, 0.1);
+
+ if ((gridFlag & AXIS_X) != 0) {
+ FragColor.a = max(FragColor.a, axes.x);
+ FragColor.rgb = (axes.x < 1e-8) ? FragColor.rgb : colorGridAxisX.rgb;
+ }
+ if ((gridFlag & AXIS_Y) != 0) {
+ FragColor.a = max(FragColor.a, axes.y);
+ FragColor.rgb = (axes.y < 1e-8) ? FragColor.rgb : colorGridAxisY.rgb;
+ }
+ if ((gridFlag & AXIS_Z) != 0) {
+ FragColor.a = max(FragColor.a, axes.z);
+ FragColor.rgb = (axes.z < 1e-8) ? FragColor.rgb : colorGridAxisZ.rgb;
+ }
+ }
+
+ /* Add a small bias so the grid will always
+ * be on top of a mesh with the same depth. */
+ float grid_depth = gl_FragCoord.z - 6e-8 - fwidth(gl_FragCoord.z);
+ float scene_depth = texture(depthBuffer, sPos).r;
+ if ((gridFlag & GRID_BACK) != 0) {
+ fade *= (scene_depth == 1.0) ? 1.0 : 0.0;
+ }
+ else {
+ /* Manual, non hard, depth test:
+ * Progressively fade the grid below occluders
+ * (avoids popping visuals due to depth buffer precision) */
+ /* Harder settings tend to flicker more,
+ * but have less "see through" appearance. */
+ const float test_hardness = 1e7;
+ fade *= 1.0 - clamp((grid_depth - scene_depth) * test_hardness, 0.0, 1.0);
+ }
+
+ FragColor.a *= fade;
+}
diff --git a/source/blender/draw/modes/shaders/object_grid_vert.glsl b/source/blender/draw/modes/shaders/object_grid_vert.glsl
new file mode 100644
index 00000000000..a346973a597
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_grid_vert.glsl
@@ -0,0 +1,63 @@
+
+/* Infinite grid
+ * Clément Foucault */
+
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+uniform vec3 cameraPos;
+uniform vec4 gridSettings;
+
+#define gridDistance gridSettings.x
+#define gridResolution gridSettings.y
+#define gridScale gridSettings.z
+#define gridSubdiv gridSettings.w
+
+uniform int gridFlag;
+
+#define PLANE_XY (1 << 4)
+#define PLANE_XZ (1 << 5)
+#define PLANE_YZ (1 << 6)
+#define CLIP_Z_POS (1 << 7)
+#define CLIP_Z_NEG (1 << 8)
+
+in vec3 pos;
+
+void main()
+{
+ vec3 vert_pos, proj_camera_pos;
+
+ /* Project camera pos to the needed plane */
+ if ((gridFlag & PLANE_XY) != 0) {
+ vert_pos = vec3(pos.x, pos.y, 0.0);
+ proj_camera_pos = vec3(cameraPos.x, cameraPos.y, 0.0);
+ }
+ else if ((gridFlag & PLANE_XZ) != 0) {
+ vert_pos = vec3(pos.x, 0.0, pos.y);
+ proj_camera_pos = vec3(cameraPos.x, 0.0, cameraPos.z);
+ }
+ else {
+ vert_pos = vec3(0.0, pos.x, pos.y);
+ proj_camera_pos = vec3(0.0, cameraPos.y, cameraPos.z);
+ }
+
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ vert_pos *= gridDistance * 2.0;
+ }
+ else {
+ float viewdist = 1.0 / min(abs(ProjectionMatrix[0][0]), abs(ProjectionMatrix[1][1]));
+ vert_pos *= viewdist * gridDistance * 2.0;
+ }
+
+ vec3 realPos = proj_camera_pos + vert_pos;
+
+ /* Used for additional Z axis */
+ if ((gridFlag & CLIP_Z_POS) != 0) {
+ realPos.z = max(realPos.z, 0.0);
+ }
+ if ((gridFlag & CLIP_Z_NEG) != 0) {
+ realPos.z = min(-realPos.z, 0.0);
+ }
+
+ gl_Position = ViewProjectionMatrix * vec4(realPos, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
new file mode 100644
index 00000000000..bcdf5adca55
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
@@ -0,0 +1,34 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+uniform float sphere_size;
+uniform ivec3 grid_resolution;
+uniform vec3 corner;
+uniform vec3 increment_x;
+uniform vec3 increment_y;
+uniform vec3 increment_z;
+uniform vec3 screen_vecs[2];
+
+uniform int call_id; /* we don't want the builtin callId which would be 0. */
+uniform int baseId;
+
+flat out uint finalId;
+
+void main()
+{
+ vec3 ls_cell_location;
+ /* Keep in sync with update_irradiance_probe */
+ ls_cell_location.z = float(gl_VertexID % grid_resolution.z);
+ ls_cell_location.y = float((gl_VertexID / grid_resolution.z) % grid_resolution.y);
+ ls_cell_location.x = float(gl_VertexID / (grid_resolution.z * grid_resolution.y));
+
+ vec3 ws_cell_location = corner +
+ (increment_x * ls_cell_location.x +
+ increment_y * ls_cell_location.y +
+ increment_z * ls_cell_location.z);
+
+ gl_Position = ViewProjectionMatrix * vec4(ws_cell_location, 1.0);
+ gl_PointSize = 2.0f;
+
+ finalId = uint(baseId + call_id);
+}
diff --git a/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl
new file mode 100644
index 00000000000..b1c10feb62c
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl
@@ -0,0 +1,34 @@
+
+/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view,
+ * and scales the shape according to per-instance attributes
+ * Note that if the stiffness is zero, it assumes the scale is directly multiplied by the radius */
+
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screen_vecs[2];
+
+/* ---- Instantiated Attribs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attribs ---- */
+in mat3x4 ScaleTranslationMatrix;
+in float radius;
+in vec3 color;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ mat3 Scamat = mat3(ScaleTranslationMatrix);
+ vec4 world_pos = vec4(
+ ScaleTranslationMatrix[0][3],
+ ScaleTranslationMatrix[1][3],
+ ScaleTranslationMatrix[2][3],
+ 1.0);
+
+ vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y;
+ world_pos.xyz += Scamat * (screen_pos * radius);
+
+ gl_Position = ViewProjectionMatrix * world_pos;
+ finalColor = vec4(color, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
new file mode 100644
index 00000000000..dbf7f411a20
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
@@ -0,0 +1,88 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform usampler2D outlineId;
+uniform sampler2D outlineDepth;
+uniform sampler2D sceneDepth;
+
+uniform int idOffsets[3];
+
+uniform float alphaOcclu;
+uniform vec2 viewportSize;
+
+vec4 convert_id_to_color(int id)
+{
+ if (id == 0) {
+ return vec4(0.0);
+ }
+ if (id < idOffsets[1]) {
+ return colorActive;
+ }
+ else if (id < idOffsets[2]) {
+ return colorSelect;
+ }
+ else {
+ return colorTransform;
+ }
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+
+#ifdef GPU_ARB_texture_gather
+ vec2 texel_size = 1.0 / vec2(textureSize(outlineId, 0).xy);
+ vec2 uv = ceil(gl_FragCoord.xy) * texel_size;
+
+ /* Samples order is CW starting from top left. */
+ uvec4 tmp1 = textureGather(outlineId, uv - texel_size);
+ uvec4 tmp2 = textureGather(outlineId, uv);
+
+ uint ref_id = tmp1.y;
+ uvec4 id = uvec4(tmp1.xz, tmp2.xz);
+#else
+ uvec4 id;
+ uint ref_id = texelFetch(outlineId, texel, 0).r;
+ id.x = texelFetchOffset(outlineId, texel, 0, ivec2(-1, 0)).r;
+ id.y = texelFetchOffset(outlineId, texel, 0, ivec2( 0, -1)).r;
+ id.z = texelFetchOffset(outlineId, texel, 0, ivec2( 0, 1)).r;
+ id.w = texelFetchOffset(outlineId, texel, 0, ivec2( 1, 0)).r;
+#endif
+
+#ifdef WIRE
+ /* We want only 2px outlines. */
+ /* TODO optimize, don't sample if we don't need to. */
+ id.xy = uvec2(ref_id);
+#endif
+
+ bool outline = any(notEqual(id, uvec4(ref_id)));
+
+ ivec2 depth_texel = texel;
+ /* If texel is an outline but has no valid id ...
+ * replace id and depth texel by a valid one.
+ * This keeps the outline thickness consistent everywhere. */
+ if (ref_id == 0u && outline) {
+ depth_texel = (id.x != 0u) ? texel + ivec2(-1, 0) : depth_texel;
+ depth_texel = (id.y != 0u) ? texel + ivec2( 0, -1) : depth_texel;
+ depth_texel = (id.z != 0u) ? texel + ivec2( 0, 1) : depth_texel;
+ depth_texel = (id.w != 0u) ? texel + ivec2( 1, 0) : depth_texel;
+
+ ref_id = (id.x != 0u) ? id.x : ref_id;
+ ref_id = (id.y != 0u) ? id.y : ref_id;
+ ref_id = (id.z != 0u) ? id.z : ref_id;
+ ref_id = (id.w != 0u) ? id.w : ref_id;
+ }
+
+ float ref_depth = texelFetch(outlineDepth, depth_texel, 0).r;
+ float scene_depth = texelFetch(sceneDepth, depth_texel, 0).r;
+
+ /* Avoid bad cases of zfighting for occlusion only. */
+ const float epsilon = 3.0 / 8388608.0;
+ bool occluded = (ref_depth > scene_depth + epsilon);
+
+ FragColor = convert_id_to_color(int(ref_id));
+ FragColor.a *= (occluded) ? alphaOcclu : 1.0;
+ FragColor.a = (outline) ? FragColor.a : 0.0;
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl b/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl
new file mode 100644
index 00000000000..7e288cde236
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl
@@ -0,0 +1,37 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineColor;
+
+uniform float alpha;
+uniform bool doExpand;
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ FragColor = texelFetch(outlineColor, uv, 0).rgba;
+
+ vec4 color[4];
+ color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2( 1, 0)).rgba;
+ color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2( 0, 1)).rgba;
+ color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-1, 0)).rgba;
+ color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2( 0, -1)).rgba;
+
+ vec4 values = vec4(color[0].a, color[1].a, color[2].a, color[3].a);
+
+ vec4 tests = step(vec4(1e-6), values); /* (color.a != 0.0) */
+ bvec4 btests = equal(tests, vec4(1.0));
+
+ if (FragColor.a != 0.0) {
+ return;
+ }
+
+ FragColor = (btests.x) ? color[0] : FragColor;
+ FragColor = (btests.y) ? color[1] : FragColor;
+ FragColor = (btests.z) ? color[2] : FragColor;
+ FragColor = (btests.w) ? color[3] : FragColor;
+
+ FragColor.a *= (!doExpand) ? 0.0 : 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
new file mode 100644
index 00000000000..776adb787ad
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
@@ -0,0 +1,10 @@
+uniform int callId;
+uniform int baseId;
+
+/* using uint because 16bit uint can contain more ids than int. */
+out uint outId;
+
+void main()
+{
+ outId = uint(baseId + callId);
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
new file mode 100644
index 00000000000..1fa0a9137c0
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
@@ -0,0 +1,40 @@
+
+layout(lines_adjacency) in;
+layout(line_strip, max_vertices = 2) out;
+
+uniform mat4 ProjectionMatrix;
+
+in vec4 pPos[];
+in vec3 vPos[];
+
+void main()
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0);
+
+ vec3 v10 = vPos[0] - vPos[1];
+ vec3 v12 = vPos[2] - vPos[1];
+ vec3 v13 = vPos[3] - vPos[1];
+
+ vec3 n0 = cross(v12, v10);
+ vec3 n3 = cross(v13, v12);
+
+ float fac0 = dot(view_vec, n0);
+ float fac3 = dot(view_vec, n3);
+
+ /* If both adjacent verts are facing the camera the same way,
+ * then it isn't an outline edge. */
+ if (sign(fac0) == sign(fac3))
+ return;
+
+ /* Don't outline if concave edge. */
+ /* That would hide a lot of non useful edge but it flickers badly.
+ * TODO revisit later... */
+ // if (dot(n0, v13) > 0.01)
+ // return;
+
+ gl_Position = pPos[1]; EmitVertex();
+ gl_Position = pPos[2]; EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
new file mode 100644
index 00000000000..ba824a7c007
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
@@ -0,0 +1,16 @@
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+
+out vec4 pPos;
+out vec3 vPos;
+
+void main()
+{
+ vPos = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
+ pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ /* Small bias to always be on top of the geom. */
+ pPos.z -= 1e-3;
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl b/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl
new file mode 100644
index 00000000000..964ebe72e81
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl
@@ -0,0 +1,27 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineBluredColor;
+uniform vec2 rcpDimensions;
+
+void main()
+{
+#ifdef USE_FXAA
+ float aa_alpha = FxaaPixelShader(
+ uvcoordsvar.st,
+ outlineBluredColor,
+ rcpDimensions,
+ 1.0,
+ 0.166,
+ 0.0833
+ ).r;
+#endif
+
+ FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba;
+
+#ifdef USE_FXAA
+ FragColor.a = aa_alpha;
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl b/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl
new file mode 100644
index 00000000000..e8bf7884701
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl
@@ -0,0 +1,52 @@
+
+uniform vec3 color;
+uniform vec3 outlineColor;
+uniform sampler1D ramp;
+
+in vec4 radii;
+flat in float finalVal;
+
+out vec4 fragColor;
+
+void main() {
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+// transparent outside of point
+// --- 0 ---
+// smooth transition
+// --- 1 ---
+// pure outline color
+// --- 2 ---
+// smooth transition
+// --- 3 ---
+// pure point color
+// ...
+// dist = 0 at center of point
+
+ float midStroke = 0.5 * (radii[1] + radii[2]);
+
+ if (dist > midStroke) {
+ if (finalVal < 0.0) {
+ fragColor.rgb = outlineColor;
+ }
+ else {
+ fragColor.rgb = texture(ramp, finalVal).rgb;
+ }
+
+ fragColor.a = mix(1.0, 0.0, smoothstep(radii[1], radii[0], dist));
+ }
+ else {
+ if (finalVal < 0.0) {
+ fragColor.rgb = mix(color, outlineColor, smoothstep(radii[3], radii[2], dist));
+ }
+ else {
+ fragColor.rgb = texture(ramp, finalVal).rgb;
+ }
+
+ fragColor.a = 1.0;
+ }
+
+ if (fragColor.a == 0.0) {
+ discard;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl
new file mode 100644
index 00000000000..6dfc212a776
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl
@@ -0,0 +1,35 @@
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform float pixel_size;
+uniform float size;
+
+in vec3 pos;
+in float val;
+
+out vec4 radii;
+flat out float finalVal;
+
+void main() {
+ gl_Position = ModelViewMatrix * vec4(pos, 1.0);
+
+ float psize = (ProjectionMatrix[3][3] == 0.0) ? (size / (-gl_Position.z * pixel_size)) : (size / pixel_size);
+
+ gl_PointSize = psize;
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * psize;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+ radii[2] = radius - 1.0;
+ radii[3] = radius - 2.0;
+
+ // convert to PointCoord units
+ radii /= psize;
+
+ gl_Position = ProjectionMatrix * gl_Position;
+
+ finalVal = val;
+}
diff --git a/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl
new file mode 100644
index 00000000000..54ae319307a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl
@@ -0,0 +1,56 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform int screen_space;
+uniform float draw_size;
+uniform vec3 color;
+uniform sampler1D ramp;
+
+in vec3 pos;
+in vec4 rot;
+in float val;
+in vec3 inst_pos;
+in int axis;
+
+flat out vec4 finalColor;
+
+vec3 rotate(vec3 vec, vec4 quat)
+{
+ /* The quaternion representation here stores the w component in the first index */
+ return vec + 2.0 * cross(quat.yzw, cross(quat.yzw, vec) + quat.x * vec);
+}
+
+void main()
+{
+ if (screen_space == 1) {
+ gl_Position = ModelViewMatrix * vec4(pos, 1.0) + vec4(inst_pos * draw_size, 0.0);
+ gl_Position = ProjectionMatrix * gl_Position;
+ }
+ else {
+ float size = draw_size;
+
+ if (axis > -1) {
+ size *= 2;
+ }
+
+ gl_Position = ModelViewProjectionMatrix * vec4(pos + rotate(inst_pos * size, rot), 1.0);
+ }
+
+#ifdef USE_AXIS
+ if (axis == 0)
+ finalColor = vec4(1.0, 0.0, 0.0, 1.0);
+ else if (axis == 1)
+ finalColor = vec4(0.0, 1.0, 0.0, 1.0);
+ else
+ finalColor = vec4(0.0, 0.0, 1.0, 1.0);
+#else
+ if (val < 0.0) {
+ finalColor = vec4(color, 1.0);
+ }
+ else {
+ finalColor = vec4(texture(ramp, val).rgb, 1.0);
+ }
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl
new file mode 100644
index 00000000000..5b0ad7863d1
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl
@@ -0,0 +1,10 @@
+uniform vec3 color_towards = vec3(0.0, 0.0, 1.0);
+uniform vec3 color_outwards = vec3(1.0, 0.0, 0.0);
+
+out vec4 fragColor;
+
+
+void main()
+{
+ fragColor = vec4(gl_FrontFacing ? color_towards: color_outwards, 0.7);
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl
new file mode 100644
index 00000000000..d8a72f28eee
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl
@@ -0,0 +1,7 @@
+uniform mat4 ModelViewProjectionMatrix;
+in vec3 pos;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
new file mode 100644
index 00000000000..69af4858a48
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
@@ -0,0 +1,57 @@
+#ifndef SELECT_EDGES
+uniform vec3 wireColor;
+uniform vec3 rimColor;
+
+in float facing;
+in vec3 barycentric;
+
+# ifdef LIGHT_EDGES
+flat in vec3 edgeSharpness;
+# endif
+
+out vec4 fragColor;
+#endif
+
+float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
+float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
+
+/* In pixels */
+uniform float wireSize = 0.0; /* Expands the core of the wire (part that is 100% wire color) */
+const float wire_smooth = 1.2; /* Smoothing distance after the 100% core. */
+
+/* Alpha constants could be exposed in the future. */
+const float front_alpha = 0.35;
+const float rim_alpha = 0.75;
+
+void main()
+{
+#ifndef SELECT_EDGES
+ vec3 dx = dFdx(barycentric);
+ vec3 dy = dFdy(barycentric);
+ vec3 d = vec3(
+ length(vec2(dx.x, dy.x)),
+ length(vec2(dx.y, dy.y)),
+ length(vec2(dx.z, dy.z))
+ );
+ vec3 dist_to_edge = barycentric / d;
+
+# ifdef LIGHT_EDGES
+ vec3 fac = abs(dist_to_edge);
+# else
+ float fac = min_v3(abs(dist_to_edge));
+# endif
+
+ fac = smoothstep(wireSize + wire_smooth, wireSize, fac);
+
+ float facing_clamped = clamp((gl_FrontFacing) ? facing : -facing, 0.0, 1.0);
+
+ vec3 final_front_col = mix(rimColor, wireColor, 0.05);
+ fragColor = mix(vec4(rimColor, rim_alpha), vec4(final_front_col, front_alpha), facing_clamped);
+
+# ifdef LIGHT_EDGES
+ fragColor.a *= max_v3(fac * edgeSharpness);
+# else
+ fragColor.a *= fac;
+# endif
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
new file mode 100644
index 00000000000..8abb6ecc737
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
@@ -0,0 +1,127 @@
+
+/* This shader is only used for intel GPU where the Geom shader is faster
+ * than doing everything thrice in the vertex shader. */
+
+layout(triangles) in;
+#ifdef SELECT_EDGES
+layout(line_strip, max_vertices = 6) out;
+#else
+layout(triangle_strip, max_vertices = 3) out;
+#endif
+
+uniform vec2 wireStepParam;
+
+in vec2 ssPos[];
+in float facingOut[];
+
+#ifndef SELECT_EDGES
+out vec3 barycentric;
+out float facing;
+#endif
+
+#ifdef LIGHT_EDGES
+in vec3 obPos[];
+in vec3 vNor[];
+in float forceEdge[];
+
+# ifndef SELECT_EDGES
+flat out vec3 edgeSharpness;
+# endif
+#endif
+
+#define NO_EDGE vec3(10000.0);
+
+vec3 get_edge_normal(vec3 n1, vec3 n2, vec3 edge)
+{
+ edge = normalize(edge);
+ vec3 n = n1 + n2;
+ float p = dot(edge, n);
+ return normalize(n - p * edge);
+}
+
+float get_edge_sharpness(vec3 fnor, vec3 vnor)
+{
+ float sharpness = abs(dot(fnor, vnor));
+ return smoothstep(wireStepParam.x, wireStepParam.y, sharpness);
+}
+
+vec3 get_barycentric(bvec3 do_edge, const int v)
+{
+ int v_n = v;
+ int v_n1 = (v + 1) % 3;
+ int v_n2 = (v + 2) % 3;
+ vec3 bary;
+ bary[v_n] = do_edge[v_n] ? 0.0 : 1.0;
+ bary[v_n1] = 1.0;
+ bary[v_n2] = do_edge[v_n2] ? 0.0 : 1.0;
+ return bary;
+}
+
+void main(void)
+{
+ vec3 facings = vec3(facingOut[0], facingOut[1], facingOut[2]);
+ bvec3 do_edge = greaterThan(abs(facings), vec3(1.0));
+ facings = fract(facings) - clamp(-sign(facings), 0.0, 1.0);
+
+#ifdef SELECT_EDGES
+ vec3 edgeSharpness;
+#endif
+
+#ifdef LIGHT_EDGES
+ vec3 edges[3];
+ edges[0] = obPos[1] - obPos[0];
+ edges[1] = obPos[2] - obPos[1];
+ edges[2] = obPos[0] - obPos[2];
+ vec3 fnor = normalize(cross(edges[0], -edges[2]));
+
+ edgeSharpness.x = get_edge_sharpness(fnor, get_edge_normal(vNor[0], vNor[1], edges[0]));
+ edgeSharpness.y = get_edge_sharpness(fnor, get_edge_normal(vNor[1], vNor[2], edges[1]));
+ edgeSharpness.z = get_edge_sharpness(fnor, get_edge_normal(vNor[2], vNor[0], edges[2]));
+ edgeSharpness.x = (forceEdge[0] == 1.0) ? 1.0 : edgeSharpness.x;
+ edgeSharpness.y = (forceEdge[1] == 1.0) ? 1.0 : edgeSharpness.y;
+ edgeSharpness.z = (forceEdge[2] == 1.0) ? 1.0 : edgeSharpness.z;
+#endif
+
+#ifdef SELECT_EDGES
+ const float edge_select_threshold = 0.3;
+ if (edgeSharpness.x > edge_select_threshold) {
+ gl_Position = gl_in[0].gl_Position;
+ EmitVertex();
+ gl_Position = gl_in[1].gl_Position;
+ EmitVertex();
+ EndPrimitive();
+ }
+
+ if (edgeSharpness.y > edge_select_threshold) {
+ gl_Position = gl_in[1].gl_Position;
+ EmitVertex();
+ gl_Position = gl_in[2].gl_Position;
+ EmitVertex();
+ EndPrimitive();
+ }
+
+ if (edgeSharpness.z > edge_select_threshold) {
+ gl_Position = gl_in[2].gl_Position;
+ EmitVertex();
+ gl_Position = gl_in[0].gl_Position;
+ EmitVertex();
+ EndPrimitive();
+ }
+#else
+ barycentric = get_barycentric(do_edge, 0);
+ gl_Position = gl_in[0].gl_Position;
+ facing = facings.x;
+ EmitVertex();
+
+ barycentric = get_barycentric(do_edge, 1);
+ gl_Position = gl_in[1].gl_Position;
+ facing = facings.y;
+ EmitVertex();
+
+ barycentric = get_barycentric(do_edge, 2);
+ gl_Position = gl_in[2].gl_Position;
+ facing = facings.z;
+ EmitVertex();
+ EndPrimitive();
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
new file mode 100644
index 00000000000..828bc551cad
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
@@ -0,0 +1,177 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform mat3 NormalMatrix;
+
+uniform vec2 wireStepParam;
+uniform float nearDist;
+
+uniform samplerBuffer vertData;
+uniform usamplerBuffer faceIds;
+
+#ifdef USE_SCULPT
+in vec3 pos;
+in vec3 nor;
+#endif
+
+float short_to_unit_float(uint s)
+{
+ int value = int(s) & 0x7FFF;
+ if ((s & 0x8000u) != 0u) {
+ value |= ~0x7FFF;
+ }
+ return float(value) / float(0x7FFF);
+}
+
+vec3 get_vertex_nor(uint id)
+{
+ int v_id = int(id) * 5; /* See vertex format for explanation. */
+ /* Fetch compressed normal as float and unpack them. */
+ vec2 data;
+ data.x = texelFetch(vertData, v_id + 3).r;
+ data.y = texelFetch(vertData, v_id + 4).r;
+
+ uvec2 udata = floatBitsToUint(data);
+
+ vec3 nor;
+ nor.x = short_to_unit_float(udata.x & 0xFFFFu);
+ nor.y = short_to_unit_float(udata.x >> 16u);
+ nor.z = short_to_unit_float(udata.y & 0xFFFFu);
+ return nor;
+}
+
+vec3 get_vertex_pos(uint id)
+{
+ int v_id = int(id) * 5; /* See vertex format for explanation. */
+ vec3 pos;
+ pos.x = texelFetch(vertData, v_id).r;
+ pos.y = texelFetch(vertData, v_id + 1).r;
+ pos.z = texelFetch(vertData, v_id + 2).r;
+ return pos;
+}
+
+vec3 get_edge_normal(vec3 n1, vec3 n2, vec3 edge)
+{
+ edge = normalize(edge);
+ vec3 n = n1 + n2;
+ float p = dot(edge, n);
+ return normalize(n - p * edge);
+}
+
+float get_edge_sharpness(vec3 fnor, vec3 vnor)
+{
+ float sharpness = abs(dot(fnor, vnor));
+ return smoothstep(wireStepParam.x, wireStepParam.y, sharpness);
+}
+
+#ifdef USE_GEOM_SHADER
+
+# ifdef LIGHT_EDGES
+out vec3 obPos;
+out vec3 vNor;
+out float forceEdge;
+# endif
+out float facingOut; /* abs(facing) > 1.0 if we do edge */
+
+void main()
+{
+# ifndef USE_SCULPT
+ uint v_id = texelFetch(faceIds, gl_VertexID).r;
+
+ bool do_edge = (v_id & (1u << 30u)) != 0u;
+ bool force_edge = (v_id & (1u << 31u)) != 0u;
+ v_id = (v_id << 2u) >> 2u;
+
+ vec3 pos = get_vertex_pos(v_id);
+ vec3 nor = get_vertex_nor(v_id);
+# else
+ const bool do_edge = true;
+ const bool force_edge = false;
+# endif
+
+ facingOut = normalize(NormalMatrix * nor).z;
+ facingOut += (do_edge) ? ((facingOut > 0.0) ? 2.0 : -2.0) : 0.0;
+
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+# ifdef LIGHT_EDGES
+ obPos = pos;
+ vNor = nor;
+ forceEdge = float(force_edge); /* meh, could try to also encode it in facingOut */
+# endif
+}
+
+#else /* USE_GEOM_SHADER */
+
+# ifdef LIGHT_EDGES
+flat out vec3 edgeSharpness;
+# endif
+out float facing;
+out vec3 barycentric;
+
+void main()
+{
+ int v_0 = (gl_VertexID / 3) * 3;
+ int v_n = gl_VertexID % 3;
+ int v_n1 = (gl_VertexID + 1) % 3;
+ int v_n2 = (gl_VertexID + 2) % 3;
+
+ /* Getting the same positions for each of the 3 verts. */
+ uvec3 v_id;
+ v_id.x = texelFetch(faceIds, v_0).r;
+ v_id.y = texelFetch(faceIds, v_0 + 1).r;
+ v_id.z = texelFetch(faceIds, v_0 + 2).r;
+
+ bvec3 do_edge, force_edge;
+ do_edge.x = (v_id.x & (1u << 30u)) != 0u;
+ do_edge.y = (v_id.y & (1u << 30u)) != 0u;
+ do_edge.z = (v_id.z & (1u << 30u)) != 0u;
+ force_edge.x = (v_id.x & (1u << 31u)) != 0u;
+ force_edge.y = (v_id.y & (1u << 31u)) != 0u;
+ force_edge.z = (v_id.z & (1u << 31u)) != 0u;
+ v_id = (v_id << 2u) >> 2u;
+
+ vec3 pos[3];
+ vec4 p_pos[3];
+
+ pos[v_n] = get_vertex_pos(v_id[v_n]);
+ gl_Position = p_pos[v_n] = ModelViewProjectionMatrix * vec4(pos[v_n], 1.0);
+
+ bvec3 bary = equal(ivec3(0, 1, 2), ivec3(v_n1));
+ /* This is equivalent to component wise : (do_edge ? bary : 1.0) */
+ barycentric = vec3(lessThanEqual(ivec3(do_edge), ivec3(bary)));
+
+# ifndef LIGHT_EDGES
+ vec3 nor = get_vertex_nor(v_id[v_n]);
+# else
+ p_pos[v_n1] = ModelViewProjectionMatrix * vec4(pos[v_n1], 1.0);
+ p_pos[v_n2] = ModelViewProjectionMatrix * vec4(pos[v_n2], 1.0);
+
+ pos[v_n1] = get_vertex_pos(v_id[v_n1]);
+ pos[v_n2] = get_vertex_pos(v_id[v_n2]);
+
+ vec3 edges[3];
+ edges[0] = pos[1] - pos[0];
+ edges[1] = pos[2] - pos[1];
+ edges[2] = pos[0] - pos[2];
+ vec3 fnor = normalize(cross(edges[0], -edges[2]));
+
+ vec3 nors[3];
+ nors[0] = get_vertex_nor(v_id.x);
+ nors[1] = get_vertex_nor(v_id.y);
+ nors[2] = get_vertex_nor(v_id.z);
+ edgeSharpness.x = get_edge_sharpness(fnor, get_edge_normal(nors[0], nors[1], edges[0]));
+ edgeSharpness.y = get_edge_sharpness(fnor, get_edge_normal(nors[1], nors[2], edges[1]));
+ edgeSharpness.z = get_edge_sharpness(fnor, get_edge_normal(nors[2], nors[0], edges[2]));
+ edgeSharpness.x = force_edge.x ? 1.0 : edgeSharpness.x;
+ edgeSharpness.y = force_edge.y ? 1.0 : edgeSharpness.y;
+ edgeSharpness.z = force_edge.z ? 1.0 : edgeSharpness.z;
+
+ vec3 nor = nors[v_n];
+# endif
+
+ facing = normalize(NormalMatrix * nor).z;
+}
+
+#endif /* USE_GEOM_SHADER */
diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl
new file mode 100644
index 00000000000..4305e20ce7b
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_texture_frag.glsl
@@ -0,0 +1,11 @@
+
+in vec2 uv_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+uniform float alpha = 1.0;
+
+void main()
+{
+ fragColor = vec4(texture(image, uv_interp).rgb, alpha);
+}
diff --git a/source/blender/draw/modes/shaders/paint_texture_vert.glsl b/source/blender/draw/modes/shaders/paint_texture_vert.glsl
new file mode 100644
index 00000000000..4ce12e048fa
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_texture_vert.glsl
@@ -0,0 +1,15 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 uv;
+in vec3 pos;
+
+out vec2 uv_interp;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ uv_interp = uv;
+
+}
diff --git a/source/blender/draw/modes/shaders/paint_vert_frag.glsl b/source/blender/draw/modes/shaders/paint_vert_frag.glsl
new file mode 100644
index 00000000000..5ea8c11ff9a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_vert_frag.glsl
@@ -0,0 +1,26 @@
+
+flat in int finalFlag;
+out vec4 fragColor;
+
+#define VERTEX_SELECTED (1 << 0)
+#define VERTEX_HIDE (1 << 4)
+
+void main()
+{
+ if (bool(finalFlag & VERTEX_HIDE)) {
+ discard;
+ }
+
+ vec2 centered = gl_PointCoord - vec2(0.5);
+ float dist_squared = dot(centered, centered);
+ const float rad_squared = 0.25;
+ const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0);
+ const vec4 colUnsel = vec4(0.0, 0.0, 0.0, 1.0);
+
+ // round point with jaggy edges
+ if (dist_squared > rad_squared) {
+ discard;
+ }
+
+ fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colUnsel;
+}
diff --git a/source/blender/draw/modes/shaders/paint_vertex_frag.glsl b/source/blender/draw/modes/shaders/paint_vertex_frag.glsl
new file mode 100644
index 00000000000..3ff264a5e22
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_vertex_frag.glsl
@@ -0,0 +1,18 @@
+
+in vec3 finalColor;
+
+out vec4 fragColor;
+uniform float white_factor = 1.0;
+
+vec3 linear_to_srgb_attrib(vec3 c) {
+ c = max(c, vec3(0.0));
+ vec3 c1 = c * 12.92;
+ vec3 c2 = 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055;
+ return mix(c1, c2, step(vec3(0.0031308), c));
+}
+
+void main()
+{
+ fragColor.rgb = mix(linear_to_srgb_attrib(finalColor), vec3(1.0), white_factor);
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl
new file mode 100644
index 00000000000..178f77c6b9c
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl
@@ -0,0 +1,21 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec3 color;
+
+out vec3 finalColor;
+
+vec3 srgb_to_linear_attrib(vec3 c) {
+ c = max(c, vec3(0.0));
+ vec3 c1 = c * (1.0 / 12.92);
+ vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
+ return mix(c1, c2, step(vec3(0.04045), c));
+}
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ finalColor = srgb_to_linear_attrib(color);
+}
diff --git a/source/blender/draw/modes/shaders/paint_weight_frag.glsl b/source/blender/draw/modes/shaders/paint_weight_frag.glsl
new file mode 100644
index 00000000000..faa36f5535e
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_weight_frag.glsl
@@ -0,0 +1,97 @@
+
+in vec2 weight_interp; /* (weight, alert) */
+
+out vec4 fragColor;
+
+uniform float opacity = 1.0;
+uniform sampler1D colorramp;
+
+uniform bool drawContours = false;
+
+float contours(float value, float steps, float width_px, float max_rel_width, float gradient)
+{
+ /* Minimum visible and minimum full strength line width in screen space for fade out. */
+ const float min_width_px = 1.3, fade_width_px = 2.3;
+ /* Line is thinner towards the increase in the weight gradient by this factor. */
+ const float hi_bias = 2.0;
+
+ /* Don't draw lines at 0 or 1. */
+ float rel_value = value * steps;
+
+ if (rel_value < 0.5 || rel_value > steps - 0.5)
+ return 0.0;
+
+ /* Check if completely invisible due to fade out. */
+ float rel_gradient = gradient * steps;
+ float rel_min_width = min_width_px * rel_gradient;
+
+ if (max_rel_width <= rel_min_width)
+ return 0.0;
+
+ /* Main shape of the line, accounting for width bias and maximum weight space width. */
+ float rel_width = width_px * rel_gradient;
+
+ float offset = fract(rel_value + 0.5) - 0.5;
+
+ float base_alpha = 1.0 - max(offset * hi_bias, -offset) / min(max_rel_width, rel_width);
+
+ /* Line fadeout when too thin in screen space. */
+ float rel_fade_width = fade_width_px * rel_gradient;
+
+ float fade_alpha = (max_rel_width - rel_min_width) / (rel_fade_width - rel_min_width);
+
+ return clamp(base_alpha, 0.0, 1.0) * clamp(fade_alpha, 0.0, 1.0);
+}
+
+vec4 contour_grid(float weight, float weight_gradient)
+{
+ /* Fade away when the gradient is too low to avoid big fills and noise. */
+ float flt_eps = max(1e-8, 1e-6 * weight);
+
+ if (weight_gradient <= flt_eps)
+ return vec4(0.0);
+
+ /* Three levels of grid lines */
+ float grid10 = contours(weight, 10.0, 5.0, 0.3, weight_gradient);
+ float grid100 = contours(weight, 100.0, 3.5, 0.35, weight_gradient) * 0.6;
+ float grid1000 = contours(weight, 1000.0, 2.5, 0.4, weight_gradient) * 0.25;
+
+ /* White lines for 0.1 and 0.01, and black for 0.001 */
+ vec4 grid = vec4(1.0) * max(grid10, grid100);
+
+ grid.a = max(grid.a, grid1000);
+
+ return grid * clamp((weight_gradient - flt_eps) / flt_eps, 0.0, 1.0);
+}
+
+void main()
+{
+ float alert = weight_interp.y;
+ vec4 color;
+
+ /* Missing vertex group alert color. Uniform in practice. */
+ if (alert > 1.1) {
+ color = colorVertexMissingData;
+ }
+ /* Weights are available */
+ else {
+ float weight = weight_interp.x;
+ vec4 weight_color = texture(colorramp, weight, 0);
+
+ /* Contour display */
+ if (drawContours) {
+ /* This must be executed uniformly for all fragments */
+ float weight_gradient = length(vec2(dFdx(weight), dFdy(weight)));
+
+ vec4 grid = contour_grid(weight, weight_gradient);
+
+ weight_color = grid + weight_color * (1 - grid.a);
+ }
+
+ /* Zero weight alert color. Nonlinear blend to reduce impact. */
+ color = mix(weight_color, colorVertexUnreferenced, alert * alert);
+ }
+
+ /* mix with 1.0 -> is like opacity when using multiply blend mode */
+ fragColor = vec4(mix(vec3(1.0), color.rgb, opacity), 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/paint_weight_vert.glsl b/source/blender/draw/modes/shaders/paint_weight_vert.glsl
new file mode 100644
index 00000000000..78a3695c82c
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_weight_vert.glsl
@@ -0,0 +1,15 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in float weight;
+in vec3 pos;
+
+out vec2 weight_interp; /* (weight, alert) */
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ /* Separate actual weight and alerts for independent interpolation */
+ weight_interp = max(vec2(weight, -weight), 0.0);
+}
diff --git a/source/blender/draw/modes/shaders/paint_wire_frag.glsl b/source/blender/draw/modes/shaders/paint_wire_frag.glsl
new file mode 100644
index 00000000000..c5d6198fc21
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_wire_frag.glsl
@@ -0,0 +1,25 @@
+
+flat in int finalFlag;
+out vec4 fragColor;
+
+#define VERTEX_SELECTED (1 << 0)
+#define VERTEX_HIDE (1 << 4)
+
+void main()
+{
+ if (bool(finalFlag & VERTEX_HIDE)) {
+ discard;
+ }
+
+ /* Apply depth offset by taking slope and distance into account. */
+ gl_FragDepth = gl_FragCoord.z - mix(exp2(-10), exp2(-23), gl_FragCoord.z) - 2.0 * fwidth(gl_FragCoord.z);
+
+#ifdef VERTEX_MODE
+ vec4 colSel = colorEdgeSelect;
+ colSel.rgb = clamp(colSel.rgb - 0.2, 0.0, 1.0);
+#else
+ const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0);
+#endif
+
+ fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colorWire;
+}
diff --git a/source/blender/draw/modes/shaders/paint_wire_vert.glsl b/source/blender/draw/modes/shaders/paint_wire_vert.glsl
new file mode 100644
index 00000000000..253c21745e2
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_wire_vert.glsl
@@ -0,0 +1,14 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in int data;
+
+flat out int finalFlag;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ finalFlag = data;
+}
diff --git a/source/blender/draw/modes/shaders/particle_strand_frag.glsl b/source/blender/draw/modes/shaders/particle_strand_frag.glsl
new file mode 100644
index 00000000000..8bb213dbd30
--- /dev/null
+++ b/source/blender/draw/modes/shaders/particle_strand_frag.glsl
@@ -0,0 +1,23 @@
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec4 finalColor;
+#ifdef USE_POINTS
+in vec2 radii;
+#endif
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = finalColor;
+
+#ifdef USE_POINTS
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+ fragColor.a = mix(finalColor.a, 0.0, smoothstep(radii[1], radii[0], dist));
+
+ if (fragColor.a == 0.0) {
+ discard;
+ }
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/particle_strand_vert.glsl b/source/blender/draw/modes/shaders/particle_strand_vert.glsl
new file mode 100644
index 00000000000..9db62a581cb
--- /dev/null
+++ b/source/blender/draw/modes/shaders/particle_strand_vert.glsl
@@ -0,0 +1,73 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in float color;
+
+out vec4 finalColor;
+#ifdef USE_POINTS
+out vec2 radii;
+#endif
+
+vec3 weight_to_rgb(float weight)
+{
+ vec3 r_rgb;
+ float blend = ((weight / 2.0) + 0.5);
+
+ if (weight <= 0.25) { /* blue->cyan */
+ r_rgb[0] = 0.0;
+ r_rgb[1] = blend * weight * 4.0;
+ r_rgb[2] = blend;
+ }
+ else if (weight <= 0.50) { /* cyan->green */
+ r_rgb[0] = 0.0;
+ r_rgb[1] = blend;
+ r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0));
+ }
+ else if (weight <= 0.75) { /* green->yellow */
+ r_rgb[0] = blend * ((weight - 0.50) * 4.0);
+ r_rgb[1] = blend;
+ r_rgb[2] = 0.0;
+ }
+ else if (weight <= 1.0) { /* yellow->red */
+ r_rgb[0] = blend;
+ r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0));
+ r_rgb[2] = 0.0;
+ }
+ else {
+ /* exceptional value, unclamped or nan,
+ * avoid uninitialized memory use */
+ r_rgb[0] = 1.0;
+ r_rgb[1] = 0.0;
+ r_rgb[2] = 1.0;
+ }
+
+ return r_rgb;
+}
+
+#define DECOMPRESS_RANGE 1.0039
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+#ifdef USE_WEIGHT
+ finalColor = vec4(weight_to_rgb(color * DECOMPRESS_RANGE), 1.0);
+#else
+ finalColor = mix(colorWire, colorEdgeSelect, color);
+#endif
+
+#ifdef USE_POINTS
+ gl_PointSize = sizeVertex;
+
+ /* calculate concentric radii in pixels */
+ float radius = 0.5 * sizeVertex;
+
+ /* start at the outside and progress toward the center */
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+
+ /* convert to PointCoord units */
+ radii /= sizeVertex;
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl b/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl
new file mode 100644
index 00000000000..e76d21eb43a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/sculpt_mask_vert.glsl
@@ -0,0 +1,19 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in float msk;
+
+#ifdef SHADE_FLAT
+flat out vec4 finalColor;
+#else
+out vec4 finalColor;
+#endif
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ float mask = 1.0 - msk * 0.75;
+ finalColor = vec4(mask, mask, mask, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/volume_velocity_vert.glsl b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl
new file mode 100644
index 00000000000..574c434920e
--- /dev/null
+++ b/source/blender/draw/modes/shaders/volume_velocity_vert.glsl
@@ -0,0 +1,115 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+uniform sampler3D velocityX;
+uniform sampler3D velocityY;
+uniform sampler3D velocityZ;
+uniform float displaySize = 1.0;
+uniform float slicePosition;
+uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
+
+flat out vec4 finalColor;
+
+const vec3 corners[4] = vec3[4](
+ vec3(0.0, 0.2, -0.5),
+ vec3(-0.2 * 0.866, -0.2 * 0.5, -0.5),
+ vec3(0.2 * 0.866, -0.2 * 0.5, -0.5),
+ vec3(0.0, 0.0, 0.5)
+);
+
+const int indices[12] = int[12](0, 1, 1, 2, 2, 0, 0, 3, 1, 3, 2, 3);
+
+/* Straight Port from BKE_defvert_weight_to_rgb()
+ * TODO port this to a color ramp. */
+vec3 weight_to_color(float weight)
+{
+ vec3 r_rgb = vec3(0.0);
+ float blend = ((weight / 2.0) + 0.5);
+
+ if (weight <= 0.25) { /* blue->cyan */
+ r_rgb.g = blend * weight * 4.0;
+ r_rgb.b = blend;
+ }
+ else if (weight <= 0.50) { /* cyan->green */
+ r_rgb.g = blend;
+ r_rgb.b = blend * (1.0 - ((weight - 0.25) * 4.0));
+ }
+ else if (weight <= 0.75) { /* green->yellow */
+ r_rgb.r = blend * ((weight - 0.50) * 4.0);
+ r_rgb.g = blend;
+ }
+ else if (weight <= 1.0) { /* yellow->red */
+ r_rgb.r = blend;
+ r_rgb.g = blend * (1.0 - ((weight - 0.75) * 4.0));
+ }
+ else {
+ /* exceptional value, unclamped or nan,
+ * avoid uninitialized memory use */
+ r_rgb = vec3(1.0, 0.0, 1.0);
+ }
+
+ return r_rgb;
+}
+
+mat3 rotation_from_vector(vec3 v)
+{
+ /* Add epsilon to avoid NaN. */
+ vec3 N = normalize(v + 1e-8);
+ vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0,0.0,1.0) : vec3(1.0,0.0,0.0);
+ vec3 T = normalize(cross(UpVector, N));
+ vec3 B = cross(N, T);
+ return mat3(T, B, N);
+}
+
+void main()
+{
+#ifdef USE_NEEDLE
+ int cell = gl_VertexID / 12;
+#else
+ int cell = gl_VertexID / 2;
+#endif
+
+ ivec3 volume_size = textureSize(velocityX, 0);
+ float voxel_size = 1.0 / float(max(max(volume_size.x, volume_size.y), volume_size.z));
+
+ ivec3 cell_ofs = ivec3(0);
+ ivec3 cell_div = volume_size;
+ if (sliceAxis == 0) {
+ cell_ofs.x = int(slicePosition * float(volume_size.x));
+ cell_div.x = 1;
+ }
+ else if (sliceAxis == 1) {
+ cell_ofs.y = int(slicePosition * float(volume_size.y));
+ cell_div.y = 1;
+ }
+ else if (sliceAxis == 2) {
+ cell_ofs.z = int(slicePosition * float(volume_size.z));
+ cell_div.z = 1;
+ }
+
+ ivec3 cell_co;
+ cell_co.x = cell % cell_div.x;
+ cell_co.y = (cell / cell_div.x) % cell_div.y;
+ cell_co.z = cell / (cell_div.x * cell_div.y);
+ cell_co += cell_ofs;
+
+ vec3 pos = (vec3(cell_co) + 0.5) / vec3(volume_size);
+ pos = pos * 2.0 - 1.0;
+
+ vec3 velocity;
+ velocity.x = texelFetch(velocityX, cell_co, 0).r;
+ velocity.y = texelFetch(velocityY, cell_co, 0).r;
+ velocity.z = texelFetch(velocityZ, cell_co, 0).r;
+
+ finalColor = vec4(weight_to_color(length(velocity)), 1.0);
+
+#ifdef USE_NEEDLE
+ mat3 rot_mat = rotation_from_vector(velocity);
+ vec3 rotated_pos = rot_mat * corners[indices[gl_VertexID % 12]];
+ pos += rotated_pos * length(velocity) * displaySize * voxel_size;
+#else
+ pos += (((gl_VertexID % 2) == 1) ? velocity : vec3(0.0)) * displaySize * voxel_size;
+#endif
+
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+}
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index 17a8eef1bdb..cf1db751c85 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -30,13 +30,14 @@ if(WITH_BLENDER)
add_subdirectory(interface)
add_subdirectory(io)
add_subdirectory(lattice)
+ add_subdirectory(gizmo_library)
add_subdirectory(mask)
add_subdirectory(mesh)
add_subdirectory(metaball)
add_subdirectory(object)
add_subdirectory(physics)
add_subdirectory(render)
- add_subdirectory(screen)
+ add_subdirectory(scene)
add_subdirectory(sculpt_paint)
add_subdirectory(sound)
add_subdirectory(space_action)
@@ -48,20 +49,21 @@ if(WITH_BLENDER)
add_subdirectory(space_graph)
add_subdirectory(space_image)
add_subdirectory(space_info)
- add_subdirectory(space_logic)
add_subdirectory(space_nla)
add_subdirectory(space_node)
add_subdirectory(space_outliner)
add_subdirectory(space_script)
add_subdirectory(space_sequencer)
+ add_subdirectory(space_statusbar)
add_subdirectory(space_text)
- add_subdirectory(space_time)
+ add_subdirectory(space_topbar)
add_subdirectory(space_userpref)
add_subdirectory(space_view3d)
add_subdirectory(transform)
add_subdirectory(undo)
add_subdirectory(util)
add_subdirectory(uvedit)
+ add_subdirectory(screen)
endif()
add_subdirectory(datafiles)
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index 1bf1bb2a474..13432e38669 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 8c306ab0159..8896de75472 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -64,11 +64,17 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
+#include "BKE_gpencil.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "DEG_depsgraph.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -77,7 +83,6 @@
#include "ED_keyframing.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -120,11 +125,10 @@ static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, floa
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
- UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
}
@@ -143,12 +147,18 @@ static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
/* no rounded corner - just rectangular box */
- glRectf(offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+ immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+
+ immUnbindProgram();
}
/* helper method to test if group colors should be drawn */
@@ -213,8 +223,8 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa
}
else {
// FIXME: what happens when the indention is 1 greater than what it should be (due to grouping)?
- int colOfs = 20 - 20 * indent;
- UI_GetThemeColorShade3fv(TH_HEADER, colOfs, r_color);
+ int colOfs = 10 - 10 * indent;
+ UI_GetThemeColorShade3fv(TH_SHADE2, colOfs, r_color);
}
}
@@ -226,12 +236,18 @@ static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, f
short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
float color[3];
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
/* no rounded corners - just rectangular box */
- glRectf(offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+ immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+
+ immUnbindProgram();
}
/* Indention + Offset ------------------------------------------- */
@@ -422,14 +438,13 @@ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float ymi
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
/* rounded corners on LHS only
* - top and bottom
* - special hack: make the top a bit higher, since we are first...
*/
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
- UI_draw_roundbox_gl_mode(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_3fvAlpha(true, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
}
/* name for summary entries */
@@ -624,7 +639,7 @@ static int acf_object_icon(bAnimListElem *ale)
/* icon depends on object-type */
switch (ob->type) {
case OB_LAMP:
- return ICON_OUTLINER_OB_LAMP;
+ return ICON_OUTLINER_OB_LIGHT;
case OB_MESH:
return ICON_OUTLINER_OB_MESH;
case OB_CAMERA:
@@ -637,6 +652,8 @@ static int acf_object_icon(bAnimListElem *ale)
return ICON_OUTLINER_OB_LATTICE;
case OB_SPEAKER:
return ICON_OUTLINER_OB_SPEAKER;
+ case OB_LIGHTPROBE:
+ return ICON_OUTLINER_OB_LIGHTPROBE;
case OB_ARMATURE:
return ICON_OUTLINER_OB_ARMATURE;
case OB_FONT:
@@ -645,6 +662,8 @@ static int acf_object_icon(bAnimListElem *ale)
return ICON_OUTLINER_OB_SURFACE;
case OB_EMPTY:
return ICON_OUTLINER_OB_EMPTY;
+ case OB_GPENCIL:
+ return ICON_OUTLINER_OB_GREASEPENCIL;
default:
return ICON_OBJECT_DATA;
}
@@ -798,9 +817,9 @@ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[
else {
/* highlight only for active */
if (ale->flag & AGRP_ACTIVE)
- UI_GetThemeColorShade3fv(TH_GROUP_ACTIVE, 10, r_color);
+ UI_GetThemeColor3fv(TH_GROUP_ACTIVE, r_color);
else
- UI_GetThemeColorShade3fv(TH_GROUP, 20, r_color);
+ UI_GetThemeColor3fv(TH_GROUP, r_color);
}
}
@@ -815,11 +834,10 @@ static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
- UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8);
+ UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f);
}
/* name for group entries */
@@ -1072,11 +1090,10 @@ static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, floa
/* set backdrop drawing color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
/* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */
UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT));
- UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5);
+ UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5, color, 1.0f);
}
/* name for nla controls expander entries */
@@ -1438,16 +1455,16 @@ static bAnimChannelType ACF_DSMAT =
acf_dsmat_setting_ptr /* pointer for setting */
};
-/* Lamp Expander ------------------------------------------- */
+/* Light Expander ------------------------------------------- */
// TODO: just get this from RNA?
-static int acf_dslam_icon(bAnimListElem *UNUSED(ale))
+static int acf_dslight_icon(bAnimListElem *UNUSED(ale))
{
- return ICON_LAMP_DATA;
+ return ICON_LIGHT_DATA;
}
/* get the appropriate flag(s) for the setting when it is valid */
-static int acf_dslam_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
+static int acf_dslight_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg)
{
/* clear extra return data first */
*neg = false;
@@ -1472,7 +1489,7 @@ static int acf_dslam_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Setting
}
/* get pointer to the setting */
-static void *acf_dslam_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+static void *acf_dslight_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
{
Lamp *la = (Lamp *)ale->data;
@@ -1496,9 +1513,9 @@ static void *acf_dslam_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings set
}
/* lamp expander type define */
-static bAnimChannelType ACF_DSLAM =
+static bAnimChannelType ACF_DSLIGHT =
{
- "Lamp Expander", /* type name */
+ "Light Expander", /* type name */
ACHANNEL_ROLE_EXPANDER, /* role */
acf_generic_dataexpand_color, /* backdrop color */
@@ -1507,12 +1524,12 @@ static bAnimChannelType ACF_DSLAM =
acf_generic_basic_offset, /* offset */
acf_generic_idblock_name, /* name */
- acf_generic_idblock_name_prop, /* name prop */
- acf_dslam_icon, /* icon */
+ acf_generic_idblock_name_prop, /* name prop */
+ acf_dslight_icon, /* icon */
acf_generic_dataexpand_setting_valid, /* has setting */
- acf_dslam_setting_flag, /* flag for setting */
- acf_dslam_setting_ptr /* pointer for setting */
+ acf_dslight_setting_flag, /* flag for setting */
+ acf_dslight_setting_ptr /* pointer for setting */
};
/* Texture Expander ------------------------------------------- */
@@ -2019,7 +2036,7 @@ static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
switch (setting) {
case ACHANNEL_SETTING_EXPAND: /* expanded */
- return PART_DS_EXPAND;
+ return 0;
case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
return ADT_NLA_EVAL_OFF;
@@ -2037,22 +2054,18 @@ static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settin
}
/* get pointer to the setting */
-static void *acf_dspart_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type)
+static void *acf_dspart_setting_ptr(bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting, short *type)
{
- ParticleSettings *part = (ParticleSettings *)ale->data;
-
/* clear extra return data first */
*type = 0;
switch (setting) {
case ACHANNEL_SETTING_EXPAND: /* expanded */
- return GET_ACF_FLAG_PTR(part->flag, type);
+ return NULL;
case ACHANNEL_SETTING_SELECT: /* selected */
case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
- if (part->adt)
- return GET_ACF_FLAG_PTR(part->adt->flag, type);
return NULL;
default: /* unsupported */
@@ -3421,14 +3434,10 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y
*/
nla_action_get_color(adt, (bAction *)ale->data, color);
- if (adt && (adt->flag & ADT_NLA_EDIT_ON)) {
- /* Yes, the color vector has 4 components, BUT we only want to be using 3 of them! */
- glColor3fv(color);
- }
- else {
- float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f;
- glColor4f(color[0], color[1], color[2], alpha);
- }
+ if (adt && (adt->flag & ADT_NLA_EDIT_ON))
+ color[3] = 1.0f;
+ else
+ color[3] = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f;
/* only on top left corner, to show that this channel sits on top of the preceding ones
* while still linking into the action line strip to the right
@@ -3438,7 +3447,7 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y
/* draw slightly shifted up vertically to look like it has more separation from other channels,
* but we then need to slightly shorten it so that it doesn't look like it overlaps
*/
- UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8);
+ UI_draw_roundbox_4fv(true, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8, color);
}
/* name for nla action entries */
@@ -3574,7 +3583,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_FILLDRIVERS; /* Drivers Expander */
animchannelTypeInfo[type++] = &ACF_DSMAT; /* Material Channel */
- animchannelTypeInfo[type++] = &ACF_DSLAM; /* Lamp Channel */
+ animchannelTypeInfo[type++] = &ACF_DSLIGHT; /* Light Channel */
animchannelTypeInfo[type++] = &ACF_DSCAM; /* Camera Channel */
animchannelTypeInfo[type++] = &ACF_DSCACHEFILE; /* CacheFile Channel */
animchannelTypeInfo[type++] = &ACF_DSCUR; /* Curve Channel */
@@ -3827,8 +3836,8 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
selected = 0;
/* set blending again, as may not be set in previous step */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
/* step 1) draw backdrop ........................................... */
if (acf->draw_backdrop)
@@ -3847,7 +3856,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
}
/* turn off blending, since not needed anymore... */
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* step 4) draw special toggles .................................
* - in Graph Editor, checkboxes for visibility in curves area
@@ -3862,15 +3871,20 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
/* for F-Curves, draw color-preview of curve behind checkbox */
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
FCurve *fcu = (FCurve *)ale->data;
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever
* color the curve has stored
*/
- glColor3fv(fcu->color);
+ immUniformColor3fv(fcu->color);
/* just a solid color rect
*/
- glRectf(offset, yminc, offset + ICON_WIDTH, ymaxc);
+ immRectf(pos, offset, yminc, offset + ICON_WIDTH, ymaxc);
+
+ immUnbindProgram();
}
/* icon is drawn as widget now... */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
@@ -3895,27 +3909,39 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) {
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
+ unsigned char col[4];
/* set text color */
/* XXX: if active, highlight differently? */
+
if (selected)
- UI_ThemeColor(TH_TEXT_HI);
+ UI_GetThemeColor4ubv(TH_TEXT_HI, col);
else
- UI_ThemeColor(TH_TEXT);
+ UI_GetThemeColor4ubv(TH_TEXT, col);
/* get name */
acf->name(ale, name);
offset += 3;
- UI_fontstyle_draw_simple(fstyle, offset, ytext, name);
+ UI_fontstyle_draw_simple(fstyle, offset, ytext, name, col);
/* draw red underline if channel is disabled */
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* FIXME: replace hardcoded color here, and check on extents! */
- glColor3f(1.0f, 0.0f, 0.0f);
- glLineWidth(2.0);
- fdrawline((float)(offset), yminc,
- (float)(v2d->cur.xmax), yminc);
+ immUniformColor3f(1.0f, 0.0f, 0.0f);
+
+ GPU_line_width(2.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, (float)offset, yminc);
+ immVertex2f(pos, (float)v2d->cur.xmax, yminc);
+ immEnd();
+
+ immUnbindProgram();
}
}
@@ -3929,10 +3955,13 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
short draw_sliders = 0;
float ymin_ofs = 0.0f;
float color[3];
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* get and set backdrop color */
acf->get_backdrop_color(ac, ale, color);
- glColor3fv(color);
+ immUniformColor3fv(color);
/* check if we need to show the sliders */
if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_IPO)) {
@@ -3990,7 +4019,9 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
* - starts from the point where the first toggle/slider starts,
* - ends past the space that might be reserved for a scroller
*/
- glRectf(v2d->cur.xmax - (float)offset, yminc + ymin_ofs, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+ immRectf(pos, v2d->cur.xmax - (float)offset, yminc + ymin_ofs, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc);
+
+ immUnbindProgram();
}
}
@@ -4020,8 +4051,25 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
return;
}
- if (ale_setting->type == ANIMTYPE_GPLAYER)
+ if (ale_setting->type == ANIMTYPE_GPLAYER) {
+ /* draw cache updates for settings that affect the visible strokes */
+ if (setting == ACHANNEL_SETTING_VISIBLE) {
+ bGPdata *gpd = (bGPdata *)ale_setting->id;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+
+ /* UI updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ }
+
+ /* tag copy-on-write flushing (so that the settings will have an effect) */
+ if (ale_setting->id) {
+ DEG_id_tag_update(ale_setting->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ if (ale_setting->adt && ale_setting->adt->action) {
+ /* action is it's own datablock, so has to be tagged specifically... */
+ DEG_id_tag_update(&ale_setting->adt->action->id, DEG_TAG_COPY_ON_WRITE);
+ }
/* verify animation context */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -4073,6 +4121,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
AnimData *adt = BKE_animdata_from_id(id);
FCurve *fcu = (FCurve *)fcu_poin;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -4098,7 +4147,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
+ done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -4113,6 +4162,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
KeyBlock *kb = (KeyBlock *)kb_poin;
char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -4136,14 +4186,14 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
/* find or create new F-Curve */
// XXX is the group name for this ok?
bAction *act = verify_adt_action(bmain, (ID *)key, 1);
- FCurve *fcu = verify_fcurve(act, NULL, &ptr, rna_path, 0, 1);
+ FCurve *fcu = verify_fcurve(bmain, act, NULL, &ptr, rna_path, 0, 1);
/* set the special 'replace' flag if on a keyframe */
if (fcurve_frame_has_keyframe(fcu, cfra, 0))
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
+ done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -4164,6 +4214,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_po
PropertyRNA *prop;
int index;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -4186,7 +4237,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_po
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
+ done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -4204,11 +4255,12 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
void *ptr;
const char *tooltip;
uiBut *but = NULL;
+ bool enabled;
/* get the flag and the pointer to that flag */
flag = acf->setting_flag(ac, setting, &negflag);
ptr = acf->setting_ptr(ale, setting, &ptrsize);
- /* enabled = ANIM_channel_setting_get(ac, ale, setting); */ /* UNUSED */
+ enabled = ANIM_channel_setting_get(ac, ale, setting);
/* get the base icon for the setting */
switch (setting) {
@@ -4230,8 +4282,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
break;
case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */
- icon = ICON_MODIFIER;
- usetoggle = false;
+ icon = ICON_MODIFIER_OFF;
tooltip = TIP_("F-Curve modifiers are disabled");
break;
@@ -4261,8 +4312,8 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
break;
case ACHANNEL_SETTING_MUTE: /* muted speaker */
- //icon = ((enabled) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
- icon = ICON_MUTE_IPO_OFF;
+ icon = ((enabled) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT);
+ usetoggle = false;
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
tooltip = TIP_("Does F-Curve contribute to result");
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index c125c129e1d..2dec9c251f5 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -50,13 +50,15 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_mask.h"
#include "BKE_global.h"
-#include "BKE_library.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_build.h"
#include "UI_view2d.h"
@@ -65,6 +67,7 @@
#include "ED_keyframes_edit.h" // XXX move the select modes out of there!
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -1725,8 +1728,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
bGPDlayer *gpl = (bGPDlayer *)ale->data;
/* try to delete the layer's data and the layer itself */
- BKE_gpencil_free_frames(gpl);
- BLI_freelinkN(&gpd->layers, gpl);
+ BKE_gpencil_layer_delete(gpd, gpl);
break;
}
case ANIMTYPE_MASKLAYER:
@@ -1747,7 +1749,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
return OPERATOR_FINISHED;
}
@@ -2298,18 +2300,9 @@ static int animchannels_find_exec(bContext *C, wmOperator *op)
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- /* update filter text, and ensure that filter is enabled if there's something there
- * NOTE: we turn the filter off if there's nothing (this is a quick shortcut for dismissing)
- */
+ /* update filter text */
RNA_string_get(op->ptr, "query", ac.ads->searchstr);
- if (ac.ads->searchstr[0]) {
- ac.ads->filterflag |= ADS_FILTER_BY_FCU_NAME;
- }
- else {
- ac.ads->filterflag &= ~ADS_FILTER_BY_FCU_NAME;
- }
-
/* redraw */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -2346,10 +2339,24 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* 'standard' behavior - check if selected, then apply relevant selection */
- if (RNA_boolean_get(op->ptr, "invert"))
- ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT);
- else
- ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
+ const int action = RNA_enum_get(op->ptr, "action");
+ switch (action) {
+ case SEL_TOGGLE:
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
+ break;
+ case SEL_SELECT:
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_ADD);
+ break;
+ case SEL_DESELECT:
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_CLEAR);
+ break;
+ case SEL_INVERT:
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
@@ -2357,11 +2364,11 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void ANIM_OT_channels_select_all_toggle(wmOperatorType *ot)
+static void ANIM_OT_channels_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select All";
- ot->idname = "ANIM_OT_channels_select_all_toggle";
+ ot->idname = "ANIM_OT_channels_select_all";
ot->description = "Toggle selection of all animation channels";
/* api callbacks */
@@ -2371,13 +2378,13 @@ static void ANIM_OT_channels_select_all_toggle(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "");
+ /* properties */
+ WM_operator_properties_select_all(ot);
}
-/* ******************** Borderselect Operator *********************** */
+/* ******************** Box Select Operator *********************** */
-static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selectmode)
+static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -2406,7 +2413,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* loop over data, doing border select */
+ /* loop over data, doing box select */
for (ale = anim_data.first; ale; ale = ale->next) {
if (ac->datatype == ANIMCONT_NLA)
ymin = ymax - NLACHANNEL_STEP(snla);
@@ -2451,7 +2458,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
/* ------------------- */
-static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
+static int animchannels_box_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
rcti rect;
@@ -2477,8 +2484,8 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
selectmode = ACHANNEL_SETFLAG_CLEAR;
}
- /* apply borderselect animation channels */
- borderselect_anim_channels(&ac, &rect, selectmode);
+ /* apply box_select animation channels */
+ box_select_anim_channels(&ac, &rect, selectmode);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
@@ -2486,18 +2493,18 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void ANIM_OT_channels_select_border(wmOperatorType *ot)
+static void ANIM_OT_channels_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "ANIM_OT_channels_select_border";
+ ot->name = "Box Select";
+ ot->idname = "ANIM_OT_channels_select_box";
ot->description = "Select all animation channels within the specified region";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = animchannels_borderselect_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = animchannels_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = animedit_poll_channels_nla_tweakmode_off;
@@ -2505,7 +2512,7 @@ static void ANIM_OT_channels_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
/* ******************* Rename Operator ***************************** */
@@ -2681,18 +2688,21 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
case ANIMTYPE_OBJECT:
{
+#if 0
bDopeSheet *ads = (bDopeSheet *)ac->data;
Scene *sce = (Scene *)ads->source;
+#endif
+ ViewLayer *view_layer = ac->view_layer;
Base *base = (Base *)ale->data;
Object *ob = base->object;
AnimData *adt = ob->adt;
/* set selection status */
- if ((ob->restrictflag & OB_RESTRICT_SELECT) == 0) {
+ if (base->flag & BASE_SELECTABLE) {
if (selectmode == SELECT_INVERT) {
/* swap select */
- base->flag ^= SELECT;
- ob->flag = base->flag;
+ ED_object_base_select(base, BA_INVERT);
+ BKE_scene_object_base_flag_sync_from_base(base);
if (adt) adt->flag ^= ADT_UI_SELECTED;
}
@@ -2701,26 +2711,26 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* deselect all */
/* TODO: should this deselect all other types of channels too? */
- for (b = sce->base.first; b; b = b->next) {
- b->flag &= ~SELECT;
- b->object->flag = b->flag;
+ for (b = view_layer->object_bases.first; b; b = b->next) {
+ ED_object_base_select(b, BA_DESELECT);
+ BKE_scene_object_base_flag_sync_from_base(b);
if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE);
}
/* select object now */
- base->flag |= SELECT;
- ob->flag |= SELECT;
+ ED_object_base_select(base, BA_SELECT);
+ BKE_scene_object_base_flag_sync_from_base(base);
if (adt) adt->flag |= ADT_UI_SELECTED;
}
/* change active object - regardless of whether it is now selected [T37883] */
- ED_base_object_activate(C, base); /* adds notifier */
+ ED_object_base_activate(C, base); /* adds notifier */
if ((adt) && (adt->flag & ADT_UI_SELECTED))
adt->flag |= ADT_UI_ACTIVE;
/* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
- if (ob != sce->obedit) {
+ if (ob != CTX_data_edit_object(C)) {
ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
}
@@ -2909,6 +2919,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
case ANIMTYPE_GPLAYER:
{
+ bGPdata *gpd = (bGPdata *)ale->id;
bGPDlayer *gpl = (bGPDlayer *)ale->data;
/* select/deselect */
@@ -2925,10 +2936,12 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* change active layer, if this is selected (since we must always have an active layer) */
if (gpl->flag & GP_LAYER_SELECT) {
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
+ /* update other layer status */
+ BKE_gpencil_layer_setactive(gpd, gpl);
}
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* Grease Pencil updates */
- notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Ediotrs updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); /* Grease Pencil updates */
+ notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Editors updates */
break;
}
case ANIMTYPE_MASKDATABLOCK:
@@ -3150,8 +3163,8 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
void ED_operatortypes_animchannels(void)
{
- WM_operatortype_append(ANIM_OT_channels_select_all_toggle);
- WM_operatortype_append(ANIM_OT_channels_select_border);
+ WM_operatortype_append(ANIM_OT_channels_select_all);
+ WM_operatortype_append(ANIM_OT_channels_select_box);
WM_operatortype_append(ANIM_OT_channels_click);
WM_operatortype_append(ANIM_OT_channel_select_keys);
@@ -3184,62 +3197,7 @@ void ED_operatortypes_animchannels(void)
// TODO: check on a poll callback for this, to get hotkeys into menus
void ED_keymap_animchannels(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Animation Channels", 0, 0);
- wmKeyMapItem *kmi;
-
- /* click-select */
- /* XXX for now, only leftmouse.... */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", true);
- RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "children_only", true);
-
- /* rename */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channel_select_keys", LEFTMOUSE, KM_DBL_CLICK, KM_SHIFT, 0)->ptr, "extend", true);
-
- /* find (i.e. a shortcut for setting the name filter) */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
-
- /* deselect all */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", true);
-
- /* borderselect */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
-
- /* delete */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", DELKEY, KM_PRESS, 0, 0);
-
- /* settings */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0);
-
- /* settings - specialized hotkeys */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
-
- /* expand/collapse */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "all", false);
- kmi = WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "all", false);
-
- /* rearranging */
- RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "direction", REARRANGE_ANIMCHAN_UP);
- RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "direction", REARRANGE_ANIMCHAN_DOWN);
- RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_TOP);
- RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_BOTTOM);
-
- /* grouping */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_group", GKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_channels_ungroup", GKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_ensure(keyconf, "Animation Channels", 0, 0);
}
/* ************************************************************************** */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 6697997b133..c9b393601b2 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -47,13 +47,14 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_sequencer.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "ED_anim_api.h"
@@ -77,7 +78,16 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
adt = BKE_animdata_from_id(id);
if (adt) {
adt->recalc |= ADT_RECALC_ANIM;
- DAG_id_tag_update(id, OB_RECALC_TIME);
+ DEG_id_tag_update(id, OB_RECALC_TIME);
+ if (adt->action != NULL) {
+ DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+
+ /* Tag copy on the main object if updating anything directly inside AnimData */
+ if (ELEM(ale->type, ANIMTYPE_ANIMDATA, ANIMTYPE_NLAACTION, ANIMTYPE_NLATRACK, ANIMTYPE_NLACURVE)) {
+ DEG_id_tag_update(id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
+ return;
}
/* update data */
@@ -98,13 +108,13 @@ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
else {
/* in other case we do standard depsgraph update, ideally
* we'd be calling property update functions here too ... */
- DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
+ DEG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
}
}
/* tags the given ID block for refreshes (if applicable) due to
* Animation Editor editing */
-void ANIM_id_update(Scene *UNUSED(scene), ID *id)
+void ANIM_id_update(Main *bmain, ID *id)
{
if (id) {
AnimData *adt = BKE_animdata_from_id(id);
@@ -114,7 +124,7 @@ void ANIM_id_update(Scene *UNUSED(scene), ID *id)
adt->recalc |= ADT_RECALC_ANIM;
/* set recalc flags */
- DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
+ DEG_id_tag_update_ex(bmain, id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); // XXX or do we want something more restrictive?
}
}
@@ -404,6 +414,10 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
ale->update &= ~ANIM_UPDATE_DEPS;
ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
+ /* disable handles to avoid crash */
+ if (ale->update & ANIM_UPDATE_HANDLES) {
+ ale->update &= ~ANIM_UPDATE_HANDLES;
+ }
}
else if (ale->datatype == ALE_FCURVE) {
FCurve *fcu = ale->key_data;
@@ -425,12 +439,22 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
}
- else if (ale->datatype == ALE_NLASTRIP) {
+ else if (ELEM(ale->type, ANIMTYPE_ANIMDATA, ANIMTYPE_NLAACTION, ANIMTYPE_NLATRACK, ANIMTYPE_NLACURVE)) {
if (ale->update & ANIM_UPDATE_DEPS) {
ale->update &= ~ANIM_UPDATE_DEPS;
ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
}
+ else if (ale->update) {
+#if 0
+ if (G.debug & G_DEBUG) {
+ printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n",
+ __func__, ale->update, ale->type, ale->data);
+ }
+#endif
+ /* Prevent crashes in cases where it can't be handled */
+ ale->update = 0;
+ }
BLI_assert(ale->update == 0);
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index a21bc4989b5..239ab5f8206 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -58,55 +58,77 @@
#include "RNA_access.h"
-#include "BIF_gl.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
/* *************************************************** */
/* CURRENT FRAME DRAWING */
/* Draw current frame number in a little green box beside the current frame indicator */
-static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const bool time)
+void ANIM_draw_cfra_number(const bContext *C, View2D *v2d, short flag)
{
+ Scene *scene = CTX_data_scene(C);
+ const float time = scene->r.cfra + scene->r.subframe;
+ const float cfra = (float)(time * scene->r.framelen);
+ const bool show_time = (flag & DRAWCFRA_UNIT_SECONDS) != 0;
+
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- float xscale, yscale, x, y;
- char numstr[32] = " t"; /* t is the character to start replacing from */
+ unsigned char col[4];
+ float color[4];
+ float xscale, x, y;
+ char numstr[32] = " t "; /* t is the character to start replacing from */
+ float hlen;
int slen;
/* because the frame number text is subject to the same scaling as the contents of the view */
- UI_view2d_scale_get(v2d, &xscale, &yscale);
- glScalef(1.0f / xscale, 1.0f, 1.0f);
+ UI_view2d_scale_get(v2d, &xscale, NULL);
+ GPU_matrix_push();
+ GPU_matrix_scale_2f(1.0f / xscale, 1.0f);
/* get timecode string
* - padding on str-buf passed so that it doesn't sit on the frame indicator
- * - power = 0, gives 'standard' behavior for time
- * but power = 1 is required for frames (to get integer frames)
*/
- if (time) {
- BLI_timecode_string_from_time(&numstr[4], sizeof(numstr) - 4, 0, FRA2TIME(cfra), FPS, U.timecode_style);
+ if (show_time) {
+ BLI_timecode_string_from_time(&numstr[2], sizeof(numstr) - 2, 0, FRA2TIME(cfra), FPS, U.timecode_style);
}
else {
- BLI_timecode_string_from_time_seconds(&numstr[4], sizeof(numstr) - 4, 1, cfra);
+ BLI_timecode_string_from_time_seconds(&numstr[2], sizeof(numstr) - 2, 1, cfra);
}
slen = UI_fontstyle_string_width(fstyle, numstr) - 1;
+ hlen = slen * 0.5f;
/* get starting coordinates for drawing */
x = cfra * xscale;
- y = 0.9f * U.widget_unit;
+ y = -0.1f * U.widget_unit;
/* draw green box around/behind text */
- UI_ThemeColorShade(TH_CFRAME, 0);
- glRectf(x, y, x + slen, y + 0.75f * U.widget_unit);
-
- /* draw current frame number - black text */
- UI_ThemeColor(TH_TEXT);
- UI_fontstyle_draw_simple(fstyle, x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr);
+ UI_GetThemeColor4fv(TH_CFRAME, color);
+ color[3] = 3.0f;
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_aa(true,
+ x - hlen - 0.1f * U.widget_unit,
+ y + 3.0f,
+ x + hlen + 0.1f * U.widget_unit,
+ y -3.0f + U.widget_unit,
+ 0.1f * U.widget_unit,
+ color);
+
+ /* draw current frame number */
+ UI_GetThemeColor4ubv(TH_TEXT_HI, col);
+ UI_fontstyle_draw_simple(fstyle,
+ x - hlen - 0.15f * U.widget_unit,
+ y + 0.28f * U.widget_unit,
+ numstr, col);
/* restore view transform */
- glScalef(xscale, 1.0, 1.0);
+ GPU_matrix_pop();
}
/* General call for drawing current frame indicator in animation editor */
@@ -114,24 +136,24 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
{
Scene *scene = CTX_data_scene(C);
- /* Draw a light green line to indicate current frame */
- UI_ThemeColor(TH_CFRAME);
-
const float time = scene->r.cfra + scene->r.subframe;
const float x = (float)(time * scene->r.framelen);
- glLineWidth((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
+ GPU_line_width((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
- glBegin(GL_LINES);
- glVertex2f(x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
- glVertex2f(x, v2d->cur.ymax);
- glEnd();
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- /* Draw current frame number in a little box */
- if (flag & DRAWCFRA_SHOW_NUMBOX) {
- UI_view2d_view_orthoSpecial(CTX_wm_region(C), v2d, 1);
- draw_cfra_number(scene, v2d, x, (flag & DRAWCFRA_UNIT_SECONDS) != 0);
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* Draw a light green line to indicate current frame */
+ immUniformThemeColor(TH_CFRAME);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
+ immVertex2f(pos, x, v2d->cur.ymax);
+ immEnd();
+ immUnbindProgram();
}
/* *************************************************** */
@@ -145,24 +167,74 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
/* only draw this if preview range is set */
if (PRVRANGEON) {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_ANIM_PREVIEW_RANGE, -25, -30);
+ //immUniformColor4f(0.8f, 0.44f, 0.1f, 0.2f); /* XXX: Fix this hardcoded color (anim_active) */
/* only draw two separate 'curtains' if there's no overlap between them */
if (PSFRA < PEFRA + end_frame_width) {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
- glRectf((float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
+ immRectf(pos, (float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
else {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
- glDisable(GL_BLEND);
+ immUnbindProgram();
+
+ GPU_blend(false);
}
}
/* *************************************************** */
+/* SCENE FRAME RANGE */
+
+/* Draw frame range guides (for scene frame range) in background */
+// TODO: Should we still show these when preview range is enabled?
+void ANIM_draw_framerange(Scene *scene, View2D *v2d)
+{
+ /* draw darkened area outside of active timeline frame range */
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
+
+ if (SFRA < EFRA) {
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
+ immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ }
+ else {
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ }
+
+ GPU_blend(false);
+
+ /* thin lines where the actual frames are */
+ immUniformThemeColorShade(TH_BACK, -60);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, (float)SFRA, v2d->cur.ymin);
+ immVertex2f(pos, (float)SFRA, v2d->cur.ymax);
+
+ immVertex2f(pos, (float)EFRA, v2d->cur.ymin);
+ immVertex2f(pos, (float)EFRA, v2d->cur.ymax);
+
+ immEnd();
+ immUnbindProgram();
+}
+
+/* *************************************************** */
/* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes) */
/* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
@@ -479,12 +551,12 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev
}
/* populate tree with keyframe nodes */
- scene_to_keylist(&ads, scene, &keys, NULL);
- gpencil_to_keylist(&ads, scene->gpd, &keys);
+ scene_to_keylist(&ads, scene, &keys, 0);
+ gpencil_to_keylist(&ads, scene->gpd, &keys, false);
if (ob) {
- ob_to_keylist(&ads, ob, &keys, NULL);
- gpencil_to_keylist(&ads, ob->gpd, &keys);
+ ob_to_keylist(&ads, ob, &keys, 0);
+ gpencil_to_keylist(&ads, ob->data, &keys, false);
}
if (mask) {
@@ -492,9 +564,6 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev
mask_to_keylist(&ads, masklay, &keys);
}
- /* build linked-list for searching */
- BLI_dlrbTree_linkedlist_sync(&keys);
-
/* find matching keyframe in the right direction */
do {
aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext);
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index e7430b5283c..2d528a0f0b9 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -72,8 +72,10 @@
#include "DNA_speaker_types.h"
#include "DNA_world_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_layer_types.h"
#include "MEM_guardedalloc.h"
@@ -83,13 +85,14 @@
#include "BLI_ghash.h"
#include "BLI_string.h"
-#include "BKE_animsys.h"
#include "BKE_action.h"
-#include "BKE_fcurve.h"
+#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
-#include "BKE_group.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
@@ -130,11 +133,11 @@ static void animedit_get_yscale_factor(bAnimContext *ac)
/* Note: there's a similar function in key.c (BKE_key_from_object) */
static Key *actedit_get_shapekeys(bAnimContext *ac)
{
- Scene *scene = ac->scene;
+ ViewLayer *view_layer = ac->view_layer;
Object *ob;
Key *key;
- ob = OBACT;
+ ob = OBACT(view_layer);
if (ob == NULL)
return NULL;
@@ -228,6 +231,7 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
ac->mode = saction->mode;
return true;
}
+
case SACTCONT_DOPESHEET: /* DopeSheet */
/* update scene-pointer (no need to check for pinning yet, as not implemented) */
saction->ads.source = (ID *)ac->scene;
@@ -238,6 +242,28 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
ac->mode = saction->mode;
return true;
+ case SACTCONT_TIMELINE: /* Timeline */
+ /* update scene-pointer (no need to check for pinning yet, as not implemented) */
+ saction->ads.source = (ID *)ac->scene;
+
+ /* sync scene's "selected keys only" flag with our "only selected" flag
+ * XXX: This is a workaround for T55525. We shouldn't really be syncing the flags like this,
+ * but it's a simpler fix for now than also figuring out how the next/prev keyframe tools
+ * should work in the 3D View if we allowed full access to the timeline's dopesheet filters
+ * (i.e. we'd have to figure out where to host those settings, to be on a scene level like
+ * this flag currently is, along with several other unknowns)
+ */
+ if (ac->scene->flag & SCE_KEYS_NO_SELONLY)
+ saction->ads.filterflag &= ~ADS_FILTER_ONLYSEL;
+ else
+ saction->ads.filterflag |= ADS_FILTER_ONLYSEL;
+
+ ac->datatype = ANIMCONT_TIMELINE;
+ ac->data = &saction->ads;
+
+ ac->mode = saction->mode;
+ return true;
+
default: /* unhandled yet */
ac->datatype = ANIMCONT_NONE;
ac->data = NULL;
@@ -380,8 +406,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
ac->scene = scene;
if (scene) {
ac->markers = ED_context_get_markers(C);
- ac->obact = (scene->basact) ? scene->basact->object : NULL;
}
+ ac->depsgraph = CTX_data_depsgraph(C);
+ ac->view_layer = CTX_data_view_layer(C);
+ ac->obact = (ac->view_layer->basact) ? ac->view_layer->basact->object : NULL;
ac->sa = sa;
ac->ar = ar;
ac->sl = sl;
@@ -1194,7 +1222,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, eAnim_Chan
/* only include if this curve is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
/* name based filtering... */
- if ( ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id) ) {
+ if ( ((ads) && (ads->searchstr[0] != '\0')) && (owner_id) ) {
if (skip_fcurve_with_name(ads, fcu, channel_type, owner, owner_id))
continue;
}
@@ -1426,7 +1454,7 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
/* only include if this track is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
/* name based filtering... */
- if (((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id)) {
+ if (((ads) && (ads->searchstr[0] != '\0')) && (owner_id)) {
bool track_ok = false, strip_ok = false;
/* check if the name of the track, or the strips it has are ok... */
@@ -1597,8 +1625,8 @@ static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, bDopeShee
bGPDlayer *gpl;
size_t items = 0;
- /* loop over layers as the conditions are acceptable */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* loop over layers as the conditions are acceptable (top-Down order) */
+ for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
/* only if selected */
if (ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) {
/* only if editable */
@@ -1606,7 +1634,7 @@ static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, bDopeShee
/* active... */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) {
/* skip layer if the name doesn't match the filter string */
- if ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) {
+ if ((ads) && (ads->searchstr[0] != '\0')) {
if (name_matches_dopesheet_filter(ads, gpl->info) == false)
continue;
}
@@ -1633,7 +1661,7 @@ static size_t animdata_filter_gpencil_data(ListBase *anim_data, bDopeSheet *ads,
*/
if (filter_mode & ANIMFILTER_ANIMDATA) {
/* just add GPD as a channel - this will add everything needed */
- ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, gpd);
}
else {
ListBase tmp_data = {NULL, NULL};
@@ -1673,6 +1701,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
if (ads->filterflag & ADS_FILTER_GP_3DONLY) {
Scene *scene = (Scene *)ads->source;
+ ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
Base *base;
/* Active scene's GPencil block first - No parent item needed... */
@@ -1681,9 +1710,9 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
}
/* Objects in the scene */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
/* Only consider this object if it has got some GP data (saving on all the other tests) */
- if (base->object && base->object->gpd) {
+ if (base->object && (base->object->type == OB_GPENCIL)) {
Object *ob = base->object;
/* firstly, check if object can be included, by the following factors:
@@ -1697,14 +1726,14 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
*/
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* layer visibility - we check both object and base, since these may not be in sync yet */
- if ((scene->lay & (ob->lay | base->lay)) == 0) continue;
+ if ((base->flag & BASE_VISIBLE) == 0) continue;
/* outliner restrict-flag */
if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
}
/* check selection and object type filters */
- if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == scene->basact)*/) ) {
+ if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED) /*|| (base == scene->basact)*/) ) {
/* only selected should be shown */
continue;
}
@@ -1713,14 +1742,14 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
* objects by the grouped status is on
* - used to ease the process of doing multiple-character choreographies
*/
- if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
- if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
+ if (ads->filter_grp != NULL) {
+ if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0)
continue;
}
/* finally, include this object's grease pencil datablock */
/* XXX: Should we store these under expanders per item? */
- items += animdata_filter_gpencil_data(anim_data, ads, ob->gpd, filter_mode);
+ items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode);
}
}
}
@@ -1944,25 +1973,26 @@ static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data,
static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
{
- SceneRenderLayer *srl;
+ ViewLayer *view_layer;
FreestyleLineSet *lineset;
size_t items = 0;
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
lineset->linestyle->id.tag |= LIB_TAG_DOIT;
}
}
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
/* skip render layers without Freestyle enabled */
- if (!(srl->layflag & SCE_LAY_FRS))
+ if ((view_layer->flag & VIEW_LAYER_FREESTYLE) == 0) {
continue;
+ }
/* loop over linesets defined in the render layer */
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
FreestyleLineStyle *linestyle = lineset->linestyle;
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
@@ -2047,7 +2077,9 @@ static size_t animdata_filter_ds_texture(bAnimContext *ac, ListBase *anim_data,
return items;
}
-/* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */
+/* NOTE: owner_id is the direct owner of the texture stack in question
+ * It used to be Material/Lamp/World before the Blender Internal removal for 2.8
+ */
static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
{
MTex **mtex = NULL;
@@ -2059,24 +2091,6 @@ static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data,
return 0;
switch (GS(owner_id->name)) {
- case ID_MA:
- {
- Material *ma = (Material *)owner_id;
- mtex = (MTex **)(&ma->mtex);
- break;
- }
- case ID_LA:
- {
- Lamp *la = (Lamp *)owner_id;
- mtex = (MTex **)(&la->mtex);
- break;
- }
- case ID_WO:
- {
- World *wo = (World *)owner_id;
- mtex = (MTex **)(&wo->mtex);
- break;
- }
case ID_PA:
{
ParticleSettings *part = (ParticleSettings *)owner_id;
@@ -2121,10 +2135,6 @@ static size_t animdata_filter_ds_material(bAnimContext *ac, ListBase *anim_data,
/* material's animation data */
tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ma, filter_mode);
- /* textures */
- if (!(ads->filterflag & ADS_FILTER_NOTEX))
- tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)ma, filter_mode);
-
/* nodes */
if ((ma->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE))
tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)ma, ma->nodetree, filter_mode);
@@ -2443,10 +2453,6 @@ static size_t animdata_filter_ds_obdata(bAnimContext *ac, ListBase *anim_data, b
/* nodetree */
if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE))
tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, &la->id, ntree, filter_mode);
-
- /* textures */
- if (!(ads->filterflag & ADS_FILTER_NOTEX))
- tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, &la->id, filter_mode);
break;
}
}
@@ -2608,8 +2614,10 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data
}
/* grease pencil */
- if ((ob->gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
- tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->gpd, filter_mode);
+ if ((ob->type == OB_GPENCIL) &&
+ (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL))
+ {
+ tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode);
}
}
END_ANIMFILTER_SUBCHANNELS;
@@ -2621,7 +2629,7 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data
if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
/* check if filtering by selection */
// XXX: double-check on this - most of the time, a lot of tools need to filter out these channels!
- if (ANIMCHANNEL_SELOK((base->flag & SELECT))) {
+ if (ANIMCHANNEL_SELOK((base->flag & BASE_SELECTED))) {
/* check if filtering by active status */
if (ANIMCHANNEL_ACTIVEOK(ob)) {
ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob);
@@ -2651,10 +2659,6 @@ static size_t animdata_filter_ds_world(bAnimContext *ac, ListBase *anim_data, bD
/* animation data filtering */
tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)wo, filter_mode);
- /* textures for world */
- if (!(ads->filterflag & ADS_FILTER_NOTEX))
- tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode);
-
/* nodes */
if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE))
tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)wo, wo->nodetree, filter_mode);
@@ -2845,7 +2849,7 @@ static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *a
}
/* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */
-static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base, int filter_mode)
+static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_mode)
{
Object *ob = base->object;
@@ -2863,7 +2867,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base
*/
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* layer visibility - we check both object and base, since these may not be in sync yet */
- if ((scene->lay & (ob->lay | base->lay)) == 0)
+ if ((base->flag & BASE_VISIBLE) == 0)
return false;
/* outliner restrict-flag */
@@ -2898,7 +2902,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base
}
/* check selection and object type filters */
- if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/)) {
+ if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED) /*|| (base == sce->basact)*/)) {
/* only selected should be shown */
return false;
}
@@ -2907,8 +2911,8 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base
* objects by the grouped status is on
* - used to ease the process of doing multiple-character choreographies
*/
- if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
- if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
+ if (ads->filter_grp != NULL) {
+ if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0)
return false;
}
@@ -2926,15 +2930,15 @@ static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr)
}
/* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */
-static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int filter_mode, size_t *r_usable_bases)
+static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, ViewLayer *view_layer, int filter_mode, size_t *r_usable_bases)
{
/* Create an array with space for all the bases, but only containing the usable ones */
- size_t tot_bases = BLI_listbase_count(&scene->base);
+ size_t tot_bases = BLI_listbase_count(&view_layer->object_bases);
size_t num_bases = 0;
Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases");
- for (Base *base = scene->base.first; base; base = base->next) {
- if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
sorted_bases[num_bases++] = base;
}
}
@@ -2952,6 +2956,7 @@ static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int
static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
{
Scene *scene = (Scene *)ads->source;
+ ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
size_t items = 0;
/* check that we do indeed have a scene */
@@ -2990,14 +2995,14 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
* - Don't do this if there's just a single object
*/
if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) &&
- (scene->base.first != scene->base.last))
+ (view_layer->object_bases.first != view_layer->object_bases.last))
{
/* Filter list of bases (i.e. objects), sort them, then add their contents normally... */
// TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort...
Base **sorted_bases;
size_t num_bases;
- sorted_bases = animdata_filter_ds_sorted_bases(ads, scene, filter_mode, &num_bases);
+ sorted_bases = animdata_filter_ds_sorted_bases(ads, view_layer, filter_mode, &num_bases);
if (sorted_bases) {
/* Add the necessary channels for these bases... */
for (size_t i = 0; i < num_bases; i++) {
@@ -3014,8 +3019,8 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
/* Filter and add contents of each base (i.e. object) without them sorting first
* NOTE: This saves performance in cases where order doesn't matter
*/
- for (Base *base = scene->base.first; base; base = base->next) {
- if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
/* since we're still here, this object should be usable */
items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
}
@@ -3258,6 +3263,15 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_F
}
+ /* Timeline Mode - Basically the same as dopesheet, except we only have the summary for now */
+ case ANIMCONT_TIMELINE:
+ {
+ /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
+ if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
+ items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
+ break;
+ }
+
/* Special/Internal Use */
case ANIMCONT_CHANNEL: /* animation channel */
{
diff --git a/source/blender/editors/animation/anim_intern.h b/source/blender/editors/animation/anim_intern.h
index 8f237652e77..73f2e85164b 100644
--- a/source/blender/editors/animation/anim_intern.h
+++ b/source/blender/editors/animation/anim_intern.h
@@ -79,6 +79,7 @@ void ANIM_OT_keying_set_active_set(struct wmOperatorType *ot);
/* Driver management operators for UI buttons (RMB menu) */
void ANIM_OT_driver_button_add(struct wmOperatorType *ot);
void ANIM_OT_driver_button_remove(struct wmOperatorType *ot);
+void ANIM_OT_driver_button_edit(struct wmOperatorType *ot);
void ANIM_OT_copy_driver_button(struct wmOperatorType *ot);
void ANIM_OT_paste_driver_button(struct wmOperatorType *ot);
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 05682292485..f82250df4d3 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -36,13 +36,14 @@
#include "DNA_object_types.h"
#include "BLI_blenlib.h"
-#include "BLI_math_base.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -56,9 +57,12 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_view2d.h"
@@ -67,12 +71,15 @@
#include "ED_anim_api.h"
#include "ED_markers.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_util.h"
#include "ED_numinput.h"
#include "ED_object.h"
#include "ED_transform.h"
#include "ED_types.h"
+#include "DEG_depsgraph.h"
+
/* ************* Marker API **************** */
/* helper function for getting the list of markers to work on */
@@ -332,6 +339,44 @@ void debug_markers_print_list(ListBase *markers)
/* ************* Marker Drawing ************ */
+static void draw_marker_name(
+ const uiFontStyle *fstyle, TimeMarker *marker, const char *name,
+ int cfra, const float xpos, const float ypixels)
+{
+ unsigned char text_col[4];
+ float x, y;
+
+ /* minimal y coordinate which wouldn't be occluded by scroll */
+ int min_y = 17.0f * UI_DPI_FAC;
+
+ if (marker->flag & SELECT) {
+ UI_GetThemeColor4ubv(TH_TEXT_HI, text_col);
+ x = xpos + 4.0f * UI_DPI_FAC;
+ y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
+ y = max_ii(y, min_y);
+ }
+ else {
+ UI_GetThemeColor4ubv(TH_TEXT, text_col);
+ if ((marker->frame <= cfra) && (marker->frame + 5 > cfra)) {
+ x = xpos + 8.0f * UI_DPI_FAC;
+ y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
+ y = max_ii(y, min_y);
+ }
+ else {
+ x = xpos + 8.0f * UI_DPI_FAC;
+ y = 17.0f * UI_DPI_FAC;
+ }
+ }
+
+#ifdef DURIAN_CAMERA_SWITCH
+ if (marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
+ text_col[3] = 100;
+ }
+#endif
+
+ UI_fontstyle_draw_simple(fstyle, x, y, name, text_col);
+}
+
/* function to draw markers */
static void draw_marker(
View2D *v2d, const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int flag,
@@ -339,10 +384,15 @@ static void draw_marker(
const float ypixels, const float xscale, const float yscale)
{
const float xpos = marker->frame * xscale;
+#ifdef DURIAN_CAMERA_SWITCH
+ const float yoffs = (marker->camera) ? 0.2f * UI_DPI_ICON_SIZE : 0.0f;
+#else
+ const float yoffs = 0.0f;
+#endif
int icon_id;
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* vertical line - dotted */
#ifdef DURIAN_CAMERA_SWITCH
@@ -351,19 +401,31 @@ static void draw_marker(
if (flag & DRAW_MARKERS_LINES)
#endif
{
- setlinestyle(3);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- if (marker->flag & SELECT)
- glColor4ub(255, 255, 255, 96);
- else
- glColor4ub(0, 0, 0, 96);
+ if (marker->flag & SELECT) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.38f);
+ }
+ else {
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.38f);
+ }
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- glBegin(GL_LINES);
- glVertex2f(xpos + 0.5f, 12.0f);
- glVertex2f(xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, xpos + 0.5f, 12.0f);
+ immVertex2f(pos, xpos + 0.5f, (v2d->cur.ymax + 12.0f) * yscale);
+ immEnd();
- setlinestyle(0);
+ immUnbindProgram();
}
/* 5 px to offset icon to align properly, space / pixels corrects for zoom */
@@ -372,52 +434,35 @@ static void draw_marker(
(marker->flag & SELECT) ? ICON_PMARKER_SEL :
ICON_PMARKER;
}
+#ifdef DURIAN_CAMERA_SWITCH
+ else if (marker->camera) {
+ icon_id = (marker->flag & SELECT) ? ICON_OUTLINER_OB_CAMERA :
+ ICON_CAMERA_DATA;
+ }
+#endif
else {
icon_id = (marker->flag & SELECT) ? ICON_MARKER_HLT :
ICON_MARKER;
}
- UI_icon_draw(xpos - 0.45f * UI_DPI_ICON_SIZE, UI_DPI_ICON_SIZE, icon_id);
+ UI_icon_draw(xpos - 0.45f * UI_DPI_ICON_SIZE, yoffs + UI_DPI_ICON_SIZE, icon_id);
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* and the marker name too, shifted slightly to the top-right */
- if (marker->name[0]) {
- float x, y;
-
- /* minimal y coordinate which wouldn't be occluded by scroll */
- int min_y = 17.0f * UI_DPI_FAC;
-
- if (marker->flag & SELECT) {
- UI_ThemeColor(TH_TEXT_HI);
- x = xpos + 4.0f * UI_DPI_FAC;
- y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
- y = max_ii(y, min_y);
- }
- else {
- UI_ThemeColor(TH_TEXT);
- if ((marker->frame <= cfra) && (marker->frame + 5 > cfra)) {
- x = xpos + 8.0f * UI_DPI_FAC;
- y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC;
- y = max_ii(y, min_y);
- }
- else {
- x = xpos + 8.0f * UI_DPI_FAC;
- y = 17.0f * UI_DPI_FAC;
- }
- }
-
#ifdef DURIAN_CAMERA_SWITCH
- if (marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
- float col[4];
- glGetFloatv(GL_CURRENT_COLOR, col);
- col[3] = 0.4;
- glColor4fv(col);
- }
-#endif
+ if (marker->camera) {
+ draw_marker_name(fstyle, marker, marker->camera->id.name + 2, cfra, xpos, ypixels);
+ }
+ else if (marker->name[0]) {
+ draw_marker_name(fstyle, marker, marker->name, cfra, xpos, ypixels);
+ }
+#else
+ if (marker->name[0]) {
+ draw_marker_name(fstyle, marker, marker->name, cfra, xpos, ypixels);
- UI_fontstyle_draw_simple(fstyle, x, y, marker->name);
}
+#endif
}
/* Draw Scene-Markers in time window */
@@ -443,21 +488,27 @@ void ED_markers_draw(const bContext *C, int flag)
v2d = UI_view2d_fromcontext(C);
if (flag & DRAW_MARKERS_MARGIN) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
const unsigned char shade[4] = {0, 0, 0, 16};
- glColor4ubv(shade);
+ immUniformColor4ubv(shade);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- glRectf(v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y);
+ immRectf(pos, v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y);
- glDisable(GL_BLEND);
+ GPU_blend(false);
+
+ immUnbindProgram();
}
/* no time correction for framelen! space is drawn with old values */
ypixels = BLI_rcti_size_y(&v2d->mask);
UI_view2d_scale_get(v2d, &xscale, &yscale);
- glScalef(1.0f / xscale, 1.0f, 1.0f);
+ GPU_matrix_push();
+ GPU_matrix_scale_2f(1.0f / xscale, 1.0f);
/* x-bounds with offset for text (adjust for long string, avoid checking string width) */
font_width_max = (10 * UI_DPI_FAC) / xscale;
@@ -480,7 +531,7 @@ void ED_markers_draw(const bContext *C, int flag)
}
}
- glScalef(xscale, 1.0f, 1.0f);
+ GPU_matrix_pop();
}
/* ************************ Marker Wrappers API ********************* */
@@ -552,7 +603,6 @@ static bool ed_markers_poll_markers_exist(bContext *C)
static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wmEvent *event,
int (*invoke_func)(bContext *, wmOperator *, const wmEvent *))
{
- ScrArea *sa = CTX_wm_area(C);
int retval = OPERATOR_PASS_THROUGH;
/* removed check for Y coord of event, keymap has bounbox now */
@@ -565,12 +615,10 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wm
else
BKE_report(op->reports, RPT_ERROR, "Programming error: operator does not actually have code to do anything!");
- /* return status modifications - for now, make this spacetype dependent as above */
- if (sa->spacetype != SPACE_TIME) {
- /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
- if ((retval & (OPERATOR_FINISHED | OPERATOR_INTERFACE)) == 0) {
- retval |= OPERATOR_PASS_THROUGH;
- }
+
+ /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
+ if ((retval & (OPERATOR_FINISHED | OPERATOR_INTERFACE)) == 0) {
+ retval |= OPERATOR_PASS_THROUGH;
}
return retval;
@@ -672,8 +720,7 @@ typedef struct MarkerMove {
static bool ed_marker_move_use_time(MarkerMove *mm)
{
- if (((mm->slink->spacetype == SPACE_TIME) && !(((SpaceTime *)mm->slink)->flag & TIME_DRAWFRAMES)) ||
- ((mm->slink->spacetype == SPACE_SEQ) && !(((SpaceSeq *)mm->slink)->flag & SEQ_DRAWFRAMES)) ||
+ if (((mm->slink->spacetype == SPACE_SEQ) && !(((SpaceSeq *)mm->slink)->flag & SEQ_DRAWFRAMES)) ||
((mm->slink->spacetype == SPACE_ACTION) && (((SpaceAction *)mm->slink)->flag & SACTION_DRAWTIME)) ||
((mm->slink->spacetype == SPACE_IPO) && !(((SpaceIpo *)mm->slink)->flag & SIPO_DRAWTIME)) ||
((mm->slink->spacetype == SPACE_NLA) && !(((SpaceNla *)mm->slink)->flag & SNLA_DRAWTIME)))
@@ -725,7 +772,7 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op)
BLI_snprintf(str, sizeof(str), IFACE_("Marker offset %s"), str_offs);
}
- ED_area_headerprint(CTX_wm_area(C), str);
+ ED_area_status_text(CTX_wm_area(C), str);
}
/* copy selection to temp buffer */
@@ -785,7 +832,7 @@ static void ed_marker_move_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
/* clear custom header prints */
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_area_status_text(CTX_wm_area(C), NULL);
}
static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -844,7 +891,7 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
if (camera != scene->camera) {
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
}
#endif
@@ -917,10 +964,7 @@ static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *even
mm->evtx = event->x;
fac = ((float)(event->x - mm->firstx) * dx);
- if (mm->slink->spacetype == SPACE_TIME)
- apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
- else
- apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
+ apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
RNA_int_set(op->ptr, "frames", (int)fac);
ed_marker_move_apply(C, op);
@@ -1129,12 +1173,13 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool
if (camera) {
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Base *base;
TimeMarker *marker;
int sel = 0;
if (!extend)
- BKE_scene_base_deselect_all(scene);
+ BKE_view_layer_base_deselect_all(view_layer);
for (marker = markers->first; marker; marker = marker->next) {
if (marker->frame == cfra) {
@@ -1146,16 +1191,17 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool
for (marker = markers->first; marker; marker = marker->next) {
if (marker->camera) {
if (marker->frame == cfra) {
- base = BKE_scene_base_find(scene, marker->camera);
+ base = BKE_view_layer_base_find(view_layer, marker->camera);
if (base) {
- ED_base_object_select(base, sel);
+ ED_object_base_select(base, sel);
if (sel)
- ED_base_object_activate(C, base);
+ ED_object_base_activate(C, base);
}
}
}
}
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
#else
@@ -1208,7 +1254,7 @@ static void MARKER_OT_select(wmOperatorType *ot)
#endif
}
-/* *************************** border select markers **************** */
+/* *************************** box select markers **************** */
/* operator state vars used: (added by default WM callbacks)
* xmin, ymin
@@ -1229,7 +1275,7 @@ static void MARKER_OT_select(wmOperatorType *ot)
* poll() has to be filled in by user for context
*/
-static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
+static int ed_marker_box_select_exec(bContext *C, wmOperator *op)
{
View2D *v2d = UI_view2d_fromcontext(C);
ListBase *markers = ED_context_get_markers(C);
@@ -1265,23 +1311,23 @@ static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
return 1;
}
-static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
+static int ed_marker_select_box_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event)
{
- return ed_markers_opwrap_invoke_custom(C, op, event, WM_gesture_border_invoke);
+ return ed_markers_opwrap_invoke_custom(C, op, event, WM_gesture_box_invoke);
}
-static void MARKER_OT_select_border(wmOperatorType *ot)
+static void MARKER_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Marker Border Select";
- ot->description = "Select all time markers using border selection";
- ot->idname = "MARKER_OT_select_border";
+ ot->name = "Marker Box Select";
+ ot->description = "Select all time markers using box selection";
+ ot->idname = "MARKER_OT_select_box";
/* api callbacks */
- ot->exec = ed_marker_border_select_exec;
- ot->invoke = ed_marker_select_border_invoke_wrapper;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->exec = ed_marker_box_select_exec;
+ ot->invoke = ed_marker_select_box_invoke_wrapper;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ed_markers_poll_markers_exist;
@@ -1289,7 +1335,7 @@ static void MARKER_OT_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
/* *********************** (de)select all ***************** */
@@ -1517,7 +1563,7 @@ static void MARKER_OT_make_links_scene(wmOperatorType *ot)
#ifdef DURIAN_CAMERA_SWITCH
/* ******************************* camera bind marker ***************** */
-static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
+static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
{
bScreen *sc = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
@@ -1525,15 +1571,37 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
ListBase *markers = ED_context_get_markers(C);
TimeMarker *marker;
- marker = ED_markers_get_first_selected(markers);
- if (marker == NULL)
+ /* Don't do anything if we don't have a camera selected */
+ if (ob == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Select a camera to bind to a marker on this frame");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* add new marker, unless we already have one on this frame, in which case, replace it */
+ if (markers == NULL)
return OPERATOR_CANCELLED;
+ marker = ED_markers_find_nearest_marker(markers, CFRA);
+ if ((marker == NULL) || (marker->frame != CFRA)) {
+ marker = MEM_callocN(sizeof(TimeMarker), "Camera TimeMarker");
+ marker->flag = SELECT;
+ marker->frame = CFRA;
+ BLI_addtail(markers, marker);
+
+ /* deselect all others, so that the user can then move it without problems */
+ for (TimeMarker *m = markers->first; m; m = m->next) {
+ if (m != marker) {
+ m->flag &= ~SELECT;
+ }
+ }
+ }
+
+ /* bind to the nominated camera (as set in operator props) */
marker->camera = ob;
/* camera may have changes */
BKE_scene_camera_switch_update(scene);
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
@@ -1546,13 +1614,13 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Bind Camera to Markers";
- ot->description = "Bind the active camera to selected marker(s)";
+ ot->description = "Bind the selected camera to a marker on the current frame";
ot->idname = "MARKER_OT_camera_bind";
/* api callbacks */
ot->exec = ed_marker_camera_bind_exec;
ot->invoke = ed_markers_opwrap_invoke;
- ot->poll = ed_markers_poll_selected_no_locked_markers;
+ ot->poll = ED_operator_animview_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1568,7 +1636,7 @@ void ED_operatortypes_marker(void)
WM_operatortype_append(MARKER_OT_move);
WM_operatortype_append(MARKER_OT_duplicate);
WM_operatortype_append(MARKER_OT_select);
- WM_operatortype_append(MARKER_OT_select_border);
+ WM_operatortype_append(MARKER_OT_select_box);
WM_operatortype_append(MARKER_OT_select_all);
WM_operatortype_append(MARKER_OT_delete);
WM_operatortype_append(MARKER_OT_rename);
@@ -1581,47 +1649,5 @@ void ED_operatortypes_marker(void)
/* called in screen_ops.c:ED_keymap_screen() */
void ED_keymap_marker(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Markers", 0, 0);
- wmKeyMapItem *kmi;
-
- WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
-#ifdef DURIAN_CAMERA_SWITCH
- kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "camera", true);
-
- kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "camera", true);
-#else
- (void)kmi;
-#endif
-
- WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
-#ifdef DURIAN_CAMERA_SWITCH
- WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
-#endif
-}
-
-/* to be called from animation editor keymaps, see note below */
-void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap)
-{
- /* duplicate of some marker-hotkeys but without the bounds checking
- * since these are handy to be able to do unrestricted and won't conflict
- * with primary function hotkeys (Usability tweak [#27469])
- */
- WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_ensure(keyconf, "Markers", 0, 0);
}
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 068d1c80f9b..8914cf9492c 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -76,7 +76,7 @@ static bool change_frame_poll(bContext *C)
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
if (sa) {
- if (ELEM(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
return true;
}
else if (sa->spacetype == SPACE_IPO) {
@@ -87,7 +87,7 @@ static bool change_frame_poll(bContext *C)
}
}
- CTX_wm_operator_poll_msg_set(C, "Expected an timeline/animation area to be active");
+ CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active");
return false;
}
@@ -231,9 +231,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
case LEFTMOUSE:
case RIGHTMOUSE:
case MIDDLEMOUSE:
- /* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init
- * the modal op) doesn't work for some reason
- */
+ /* We check for either mouse-button to end, to work with all user keymaps. */
if (event->val == KM_RELEASE)
ret = OPERATOR_FINISHED;
break;
@@ -282,6 +280,116 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
+/* ****************** Start/End Frame Operators *******************************/
+
+static bool anim_set_end_frames_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* XXX temp? prevent changes during render */
+ if (G.is_rendering) return false;
+
+ /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION,
+ * this shouldn't show up in 3D editor (or others without 2D timeline view) via search
+ */
+ if (sa) {
+ if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ return true;
+ }
+ }
+
+ CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active");
+ return false;
+}
+
+static int anim_set_sfra_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ int frame;
+
+ if (scene == NULL)
+ return OPERATOR_CANCELLED;
+
+ frame = CFRA;
+
+ /* if Preview Range is defined, set the 'start' frame for that */
+ if (PRVRANGEON)
+ scene->r.psfra = frame;
+ else
+ scene->r.sfra = frame;
+
+ if (PEFRA < frame) {
+ if (PRVRANGEON)
+ scene->r.pefra = frame;
+ else
+ scene->r.efra = frame;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_start_frame_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Start Frame";
+ ot->idname = "ANIM_OT_start_frame_set";
+ ot->description = "Set the current frame as the preview or scene start frame";
+
+ /* api callbacks */
+ ot->exec = anim_set_sfra_exec;
+ ot->poll = anim_set_end_frames_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int anim_set_efra_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ int frame;
+
+ if (scene == NULL)
+ return OPERATOR_CANCELLED;
+
+ frame = CFRA;
+
+ /* if Preview Range is defined, set the 'end' frame for that */
+ if (PRVRANGEON)
+ scene->r.pefra = frame;
+ else
+ scene->r.efra = frame;
+
+ if (PSFRA > frame) {
+ if (PRVRANGEON)
+ scene->r.psfra = frame;
+ else
+ scene->r.sfra = frame;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_end_frame_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set End Frame";
+ ot->idname = "ANIM_OT_end_frame_set";
+ ot->description = "Set the current frame as the preview or scene end frame";
+
+ /* api callbacks */
+ ot->exec = anim_set_efra_exec;
+ ot->poll = anim_set_end_frames_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ****************** set preview range operator ****************************/
static int previewrange_define_exec(bContext *C, wmOperator *op)
@@ -291,7 +399,7 @@ static int previewrange_define_exec(bContext *C, wmOperator *op)
float sfra, efra;
rcti rect;
- /* get min/max values from border select rect (already in region coordinates, not screen) */
+ /* get min/max values from box select rect (already in region coordinates, not screen) */
WM_operator_properties_border_to_rcti(op, &rect);
/* convert min/max values to frames (i.e. region to 'tot' rect) */
@@ -324,10 +432,10 @@ static void ANIM_OT_previewrange_set(wmOperatorType *ot)
ot->description = "Interactively define frame range used for playback";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = previewrange_define_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_animview_active;
@@ -338,7 +446,7 @@ static void ANIM_OT_previewrange_set(wmOperatorType *ot)
/* used to define frame range.
*
* note: border Y values are not used,
- * but are needed by borderselect gesture operator stuff */
+ * but are needed by box_select gesture operator stuff */
WM_operator_properties_border(ot);
}
@@ -389,6 +497,9 @@ void ED_operatortypes_anim(void)
/* Animation Editors only -------------------------- */
WM_operatortype_append(ANIM_OT_change_frame);
+ WM_operatortype_append(ANIM_OT_start_frame_set);
+ WM_operatortype_append(ANIM_OT_end_frame_set);
+
WM_operatortype_append(ANIM_OT_previewrange_set);
WM_operatortype_append(ANIM_OT_previewrange_clear);
@@ -405,6 +516,7 @@ void ED_operatortypes_anim(void)
WM_operatortype_append(ANIM_OT_driver_button_add);
WM_operatortype_append(ANIM_OT_driver_button_remove);
+ WM_operatortype_append(ANIM_OT_driver_button_edit);
WM_operatortype_append(ANIM_OT_copy_driver_button);
WM_operatortype_append(ANIM_OT_paste_driver_button);
@@ -422,17 +534,5 @@ void ED_operatortypes_anim(void)
void ED_keymap_anim(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Animation", 0, 0);
- wmKeyMapItem *kmi;
-
- /* frame management */
- /* NOTE: 'ACTIONMOUSE' not 'LEFTMOUSE', as user may have swapped mouse-buttons */
- WM_keymap_add_item(keymap, "ANIM_OT_change_frame", ACTIONMOUSE, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.show_seconds");
-
- /* preview range */
- WM_keymap_verify_item(keymap, "ANIM_OT_previewrange_set", PKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "ANIM_OT_previewrange_clear", PKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_ensure(keyconf, "Animation", 0, 0);
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index ebe085cd006..85e58521493 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -41,14 +41,17 @@
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
+#include "DNA_space_types.h"
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_context.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_keyframing.h"
#include "UI_interface.h"
@@ -115,7 +118,6 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* add some new driver data */
fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
- fcu->driver->flag |= DRIVER_FLAG_SHOWDEBUG;
/* F-Modifier or Keyframes? */
// FIXME: replace these magic numbers with defines
@@ -412,13 +414,20 @@ int ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int arra
/* set the type of the driver */
driver->type = type;
- /* creating drivers for buttons will create the driver(s) with type
+ /* Creating drivers for buttons will create the driver(s) with type
* "scripted expression" so that their values won't be lost immediately,
* so here we copy those values over to the driver's expression
+ *
+ * If the "default dvar" option (for easier UI setup of drivers) is provided,
+ * include "var" in the expressions too, so that the user doesn't have to edit
+ * it to get something to happen. It should be fine to just add it to the default
+ * value, so that we get both in the expression, even if it's a bit more confusing
+ * that way...
*/
if (type == DRIVER_TYPE_PYTHON) {
PropertyType proptype = RNA_property_type(prop);
int array = RNA_property_array_length(&ptr, prop);
+ const char *dvar_prefix = (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) ? "var + " : "";
char *expression = driver->expression;
int val, maxlen = sizeof(driver->expression);
float fval;
@@ -427,19 +436,23 @@ int ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int arra
if (!array) val = RNA_property_boolean_get(&ptr, prop);
else val = RNA_property_boolean_get_index(&ptr, prop, array_index);
- BLI_strncpy(expression, (val) ? "True" : "False", maxlen);
+ BLI_snprintf(expression, maxlen, "%s%s", dvar_prefix, (val) ? "True" : "False");
}
else if (proptype == PROP_INT) {
if (!array) val = RNA_property_int_get(&ptr, prop);
else val = RNA_property_int_get_index(&ptr, prop, array_index);
- BLI_snprintf(expression, maxlen, "%d", val);
+ BLI_snprintf(expression, maxlen, "%s%d", dvar_prefix, val);
}
else if (proptype == PROP_FLOAT) {
if (!array) fval = RNA_property_float_get(&ptr, prop);
else fval = RNA_property_float_get_index(&ptr, prop, array_index);
- BLI_snprintf(expression, maxlen, "%.3f", fval);
+ BLI_snprintf(expression, maxlen, "%s%.3f", dvar_prefix, fval);
+ BLI_str_rstrip_float_zero(expression, '\0');
+ }
+ else if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) {
+ BLI_strncpy(expression, "var", maxlen);
}
}
@@ -732,11 +745,8 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
driver->variables.last = tmp_list.last;
}
-#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
- if (driver->type == DRIVER_TYPE_PYTHON)
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
-#endif
+ BKE_driver_invalidate_expression(driver, false, true);
return true;
}
@@ -750,7 +760,7 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
/* NOTE: Used by ANIM_OT_driver_button_add and UI_OT_eyedropper_driver */
// XXX: These names need reviewing
EnumPropertyItem prop_driver_create_mapping_types[] = {
- {CREATEDRIVER_MAPPING_1_N, "SINGLE_MANY", ICON_UI, "All from Target",
+ {CREATEDRIVER_MAPPING_1_N, "SINGLE_MANY", 0, "All from Target",
"Drive all components of this property using the target picked"},
{CREATEDRIVER_MAPPING_1_1, "DIRECT", 0, "Single from Target",
"Drive this component of this property using the target picked"},
@@ -804,7 +814,7 @@ static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C, PointerRN
}
-/* Add Driver Button Operator ------------------------ */
+/* Add Driver (With Menu) Button Operator ------------------------ */
static bool add_driver_button_poll(bContext *C)
{
@@ -843,7 +853,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
return OPERATOR_FINISHED;
@@ -853,7 +863,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ
}
}
-static int add_driver_button_exec(bContext *C, wmOperator *op)
+static int add_driver_button_menu_exec(bContext *C, wmOperator *op)
{
short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
if (ELEM(mapping_type, CREATEDRIVER_MAPPING_NONE, CREATEDRIVER_MAPPING_NONE_ALL)) {
@@ -872,13 +882,13 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
}
/* Show menu or create drivers */
-static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int add_driver_button_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop;
if ((prop = RNA_struct_find_property(op->ptr, "mapping_type")) && RNA_property_is_set(op->ptr, prop)) {
/* Mapping Type is Set - Directly go into creating drivers */
- return add_driver_button_exec(C, op);
+ return add_driver_button_menu_exec(C, op);
}
else {
/* Show menu */
@@ -888,19 +898,16 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
}
}
-void ANIM_OT_driver_button_add(wmOperatorType *ot)
+static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Driver";
- ot->idname = "ANIM_OT_driver_button_add";
+ ot->name = "Add Driver Menu";
+ ot->idname = "ANIM_OT_driver_button_add_menu";
ot->description = "Add driver(s) for the property(s) represented by the highlighted button";
/* callbacks */
- /* NOTE: No exec, as we need all these to use the current context info
- * (especially the eyedropper, which is interactive)
- */
- ot->invoke = add_driver_button_invoke;
- ot->exec = add_driver_button_exec;
+ ot->invoke = add_driver_button_menu_invoke;
+ ot->exec = add_driver_button_menu_exec;
ot->poll = add_driver_button_poll;
/* flags */
@@ -912,6 +919,60 @@ void ANIM_OT_driver_button_add(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
}
+/* Add Driver Button Operator ------------------------ */
+
+static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index;
+
+ /* try to find driver using property retrieved from UI */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
+ /* 1) Create a new "empty" driver for this property */
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
+ short success = 0;
+
+ if (path) {
+ success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
+ MEM_freeN(path);
+ }
+
+ if (success) {
+ /* send updates */
+ UI_context_update_anim_flag(C);
+ DEG_id_tag_update(ptr.id.data, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);
+ }
+
+ /* 2) Show editing panel for setting up this driver */
+ /* TODO: Use a different one from the editing popever, so we can have the single/all toggle? */
+ UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports);
+ }
+
+ return OPERATOR_INTERFACE;
+}
+
+void ANIM_OT_driver_button_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Driver";
+ ot->idname = "ANIM_OT_driver_button_add";
+ ot->description = "Add driver for the property under the cursor";
+
+ /* callbacks */
+ /* NOTE: No exec, as we need all these to use the current context info */
+ ot->invoke = add_driver_button_invoke;
+ ot->poll = add_driver_button_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
/* Remove Driver Button Operator ------------------------ */
static int remove_driver_button_exec(bContext *C, wmOperator *op)
@@ -941,7 +1002,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
@@ -966,6 +1027,39 @@ void ANIM_OT_driver_button_remove(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array");
}
+/* Edit Driver Button Operator ------------------------ */
+
+static int edit_driver_button_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index;
+
+ /* try to find driver using property retrieved from UI */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (ptr.id.data && ptr.data && prop) {
+ UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports);
+ }
+
+ return OPERATOR_INTERFACE;
+}
+
+void ANIM_OT_driver_button_edit(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Driver";
+ ot->idname = "ANIM_OT_driver_button_edit";
+ ot->description = "Edit the drivers for the property connected represented by the highlighted button";
+
+ /* callbacks */
+ ot->exec = edit_driver_button_exec;
+ //op->poll = ??? // TODO: need to have some driver to be able to do this...
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
/* Copy Driver Button Operator ------------------------ */
static int copy_driver_button_exec(bContext *C, wmOperator *op)
@@ -1031,8 +1125,8 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
UI_context_update_anim_flag(C);
- DAG_relations_tag_update(CTX_data_main(C));
- DAG_id_tag_update(ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_relations_tag_update(CTX_data_main(C));
+ DEG_id_tag_update(ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 54e0839d802..72da71a8a0e 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -42,17 +42,21 @@
#include "BLI_dlrbTree.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_rect.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"
+#include "DNA_brush_types.h"
#include "DNA_mask_types.h"
#include "BKE_fcurve.h"
-#include "BIF_gl.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -64,6 +68,16 @@
/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
+BLI_INLINE bool is_cfra_eq(float a, float b)
+{
+ return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
+}
+
+BLI_INLINE bool is_cfra_lt(float a, float b)
+{
+ return (b - a) > BEZT_BINARYSEARCH_THRESH;
+}
+
/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
short compare_ak_cfraPtr(void *node, void *data)
@@ -72,63 +86,158 @@ short compare_ak_cfraPtr(void *node, void *data)
const float *cframe = data;
float val = *cframe;
- if (IS_EQT(val, ak->cfra, BEZT_BINARYSEARCH_THRESH))
+ if (is_cfra_eq(val, ak->cfra))
return 0;
if (val < ak->cfra)
return -1;
- else if (val > ak->cfra)
- return 1;
else
- return 0;
+ return 1;
}
/* --------------- */
-/* Comparator callback used for ActKeyColumns and BezTriple */
+/* Set of references to three logically adjacent keys. */
+typedef struct BezTripleChain {
+ /* Current keyframe. */
+ BezTriple *cur;
+
+ /* Logical neighbors. May be NULL. */
+ BezTriple *prev, *next;
+} BezTripleChain;
+
+/* Categorize the interpolation & handle type of the keyframe. */
+static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt)
+{
+ if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) {
+ return KEYFRAME_HANDLE_AUTO_CLAMP;
+ }
+ else if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) {
+ return KEYFRAME_HANDLE_AUTO;
+ }
+ else if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) {
+ return KEYFRAME_HANDLE_VECTOR;
+ }
+ else if (ELEM(HD_FREE, bezt->h1, bezt->h2)) {
+ return KEYFRAME_HANDLE_FREE;
+ }
+ else {
+ return KEYFRAME_HANDLE_ALIGNED;
+ }
+}
+
+/* Determine if the keyframe is an extreme by comparing with neighbors.
+ * Ends of fixed-value sections and of the whole curve are also marked.
+ */
+static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain)
+{
+ if (chain->prev == NULL && chain->next == NULL) {
+ return KEYFRAME_EXTREME_NONE;
+ }
+
+ /* Keyframe values for the current one and neighbors. */
+ float cur_y = chain->cur->vec[1][1];
+ float prev_y = cur_y, next_y = cur_y;
+
+ if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) {
+ prev_y = chain->prev->vec[1][1];
+ }
+ if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) {
+ next_y = chain->next->vec[1][1];
+ }
+
+ /* Static hold. */
+ if (prev_y == cur_y && next_y == cur_y) {
+ return KEYFRAME_EXTREME_FLAT;
+ }
+
+ /* Middle of an incline. */
+ if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) {
+ return KEYFRAME_EXTREME_NONE;
+ }
+
+ /* Bezier handle values for the overshoot check. */
+ bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ;
+ bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ;
+ float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y;
+ float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y;
+
+ /* Detect extremes. One of the neighbors is allowed to be equal to current. */
+ if (prev_y < cur_y || next_y < cur_y) {
+ bool is_overshoot = (handle_l > cur_y || handle_r > cur_y);
+
+ return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
+ }
+
+ if (prev_y > cur_y || next_y > cur_y) {
+ bool is_overshoot = (handle_l < cur_y || handle_r < cur_y);
+
+ return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0);
+ }
+
+ return KEYFRAME_EXTREME_NONE;
+}
+
+/* Comparator callback used for ActKeyColumns and BezTripleChain */
static short compare_ak_bezt(void *node, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- BezTriple *bezt = (BezTriple *)data;
+ BezTripleChain *chain = data;
- if (bezt->vec[1][0] < ak->cfra)
- return -1;
- else if (bezt->vec[1][0] > ak->cfra)
- return 1;
- else
- return 0;
+ return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
}
-/* New node callback used for building ActKeyColumns from BezTriples */
+/* New node callback used for building ActKeyColumns from BezTripleChain */
static DLRBT_Node *nalloc_ak_bezt(void *data)
{
ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
- BezTriple *bezt = (BezTriple *)data;
+ BezTripleChain *chain = data;
+ BezTriple *bezt = chain->cur;
/* store settings based on state of BezTriple */
ak->cfra = bezt->vec[1][0];
ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0;
ak->key_type = BEZKEYTYPE(bezt);
+ ak->handle_type = bezt_handle_type(bezt);
+ ak->extreme_type = bezt_extreme_type(chain);
- /* set 'modified', since this is used to identify long keyframes */
- ak->modified = 1;
+ /* count keyframes in this column */
+ ak->totkey = 1;
return (DLRBT_Node *)ak;
}
-/* Node updater callback used for building ActKeyColumns from BezTriples */
+/* Node updater callback used for building ActKeyColumns from BezTripleChain */
static void nupdate_ak_bezt(void *node, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- BezTriple *bezt = (BezTriple *)data;
+ ActKeyColumn *ak = node;
+ BezTripleChain *chain = data;
+ BezTriple *bezt = chain->cur;
/* set selection status and 'touched' status */
if (BEZT_ISSEL_ANY(bezt)) ak->sel = SELECT;
- ak->modified += 1;
+
+ /* count keyframes in this column */
+ ak->totkey++;
/* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME)
ak->key_type = BEZT_KEYTYPE_KEYFRAME;
+
+ /* For interpolation type, select the highest value (enum is sorted). */
+ ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt));
+
+ /* For extremes, detect when combining different states. */
+ char new_extreme = bezt_extreme_type(chain);
+
+ if (new_extreme != ak->extreme_type) {
+ /* Replace the flat status without adding mixed. */
+ if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) {
+ ak->extreme_type = new_extreme;
+ }
+ else if (new_extreme != KEYFRAME_EXTREME_FLAT) {
+ ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED);
+ }
+ }
}
/* ......... */
@@ -136,15 +245,10 @@ static void nupdate_ak_bezt(void *node, void *data)
/* Comparator callback used for ActKeyColumns and GPencil frame */
static short compare_ak_gpframe(void *node, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
bGPDframe *gpf = (bGPDframe *)data;
- if (gpf->framenum < ak->cfra)
- return -1;
- else if (gpf->framenum > ak->cfra)
- return 1;
- else
- return 0;
+ float frame = gpf->framenum;
+ return compare_ak_cfraPtr(node, &frame);
}
/* New node callback used for building ActKeyColumns from GPencil frames */
@@ -158,8 +262,8 @@ static DLRBT_Node *nalloc_ak_gpframe(void *data)
ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
ak->key_type = gpf->key_type;
- /* set 'modified', since this is used to identify long keyframes */
- ak->modified = 1;
+ /* count keyframes in this column */
+ ak->totkey = 1;
return (DLRBT_Node *)ak;
}
@@ -172,7 +276,9 @@ static void nupdate_ak_gpframe(void *node, void *data)
/* set selection status and 'touched' status */
if (gpf->flag & GP_FRAME_SELECT) ak->sel = SELECT;
- ak->modified += 1;
+
+ /* count keyframes in this column */
+ ak->totkey++;
/* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME)
@@ -184,15 +290,10 @@ static void nupdate_ak_gpframe(void *node, void *data)
/* Comparator callback used for ActKeyColumns and GPencil frame */
static short compare_ak_masklayshape(void *node, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
- if (masklay_shape->frame < ak->cfra)
- return -1;
- else if (masklay_shape->frame > ak->cfra)
- return 1;
- else
- return 0;
+ float frame = masklay_shape->frame;
+ return compare_ak_cfraPtr(node, &frame);
}
/* New node callback used for building ActKeyColumns from GPencil frames */
@@ -205,8 +306,8 @@ static DLRBT_Node *nalloc_ak_masklayshape(void *data)
ak->cfra = masklay_shape->frame;
ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0;
- /* set 'modified', since this is used to identify long keyframes */
- ak->modified = 1;
+ /* count keyframes in this column */
+ ak->totkey = 1;
return (DLRBT_Node *)ak;
}
@@ -219,14 +320,16 @@ static void nupdate_ak_masklayshape(void *node, void *data)
/* set selection status and 'touched' status */
if (masklay_shape->flag & MASK_SHAPE_SELECT) ak->sel = SELECT;
- ak->modified += 1;
+
+ /* count keyframes in this column */
+ ak->totkey++;
}
/* --------------- */
/* Add the given BezTriple to the given 'list' of Keyframes */
-static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTriple *bezt)
+static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt)
{
if (ELEM(NULL, keys, bezt))
return;
@@ -254,64 +357,11 @@ static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *mas
/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
-/* Comparator callback used for ActKeyBlock and cframe float-value pointer */
-/* NOTE: this is exported to other modules that use the ActKeyBlocks for finding long-keyframes */
-short compare_ab_cfraPtr(void *node, void *data)
-{
- ActKeyBlock *ab = (ActKeyBlock *)node;
- const float *cframe = data;
- float val = *cframe;
+static const ActKeyBlockInfo dummy_keyblock = { 0 };
- if (val < ab->start)
- return -1;
- else if (val > ab->start)
- return 1;
- else
- return 0;
-}
-
-/* --------------- */
-
-/* Create a ActKeyColumn for a pair of BezTriples */
-static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn)
+static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn)
{
- ActKeyBlock *ab = MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock");
-
- ab->start = prev->vec[1][0];
- ab->end = beztn->vec[1][0];
- ab->val = beztn->vec[1][1];
-
- ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0;
- ab->modified = 1;
-
- if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
- ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
-
- return ab;
-}
-
-static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt, BezTriple *beztn)
-{
- ActKeyBlock *new_ab = NULL;
- BezTriple *prev = NULL;
-
- /* get the BezTriple immediately before the given one which has the same value */
- if (beztn != first_bezt) {
- /* XXX: Unless I'm overlooking some details from the past, this should be sufficient?
- * The old code did some elaborate stuff trying to find keyframe columns for
- * the given BezTriple, then step backwards to the column before that, and find
- * an appropriate BezTriple with matching values there. Maybe that was warranted
- * in the past, but now, that list is only ever filled with keyframes from the
- * current FCurve.
- *
- * -- Aligorith (20140415)
- */
- prev = beztn - 1;
- }
-
-
- /* check if block needed */
- if (prev == NULL) return;
+ memset(info, 0, sizeof(ActKeyBlockInfo));
if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) {
/* Animator tagged a "moving hold"
@@ -319,191 +369,182 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt
* we're just dealing with the first of a pair, and we don't
* want to be creating any phantom holds...
*/
- if (BEZKEYTYPE(prev) != BEZT_KEYTYPE_MOVEHOLD)
- return;
+ if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) {
+ info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
+ }
}
- else {
- /* Check for same values...
- * - Handles must have same central value as each other
- * - Handles which control that section of the curve must be constant
- */
- if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
- if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
- if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
+ /* Check for same values...
+ * - Handles must have same central value as each other
+ * - Handles which control that section of the curve must be constant
+ */
+ if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) {
+ bool hold;
+
+ /* Only check handles in case of actual bezier interpolation. */
+ if (prev->ipo == BEZT_IPO_BEZ) {
+ hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) && IS_EQF(prev->vec[1][1], prev->vec[2][1]);
+ }
+ /* This interpolation type induces movement even between identical keys. */
+ else {
+ hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
+ }
+
+ if (hold) {
+ info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD;
+ }
}
- /* if there are no blocks already, just add as root */
- if (blocks->root == NULL) {
- /* just add this as the root, then call the tree-balancing functions to validate */
- new_ab = bezts_to_new_actkeyblock(prev, beztn);
- blocks->root = (DLRBT_Node *)new_ab;
+ /* Remember non-bezier interpolation info. */
+ if (prev->ipo != BEZT_IPO_BEZ) {
+ info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER;
}
+
+ info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn);
+}
+
+static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
+{
+ /* New curve and block. */
+ if (col->totcurve <= 1 && col->totblock == 0) {
+ memcpy(&col->block, block, sizeof(ActKeyBlockInfo));
+ }
+ /* Existing curve. */
else {
- ActKeyBlock *ab, *abn = NULL;
+ col->block.conflict |= (col->block.flag ^ block->flag);
+ col->block.flag |= block->flag;
+ col->block.sel |= block->sel;
+ }
- /* try to find a keyblock that starts on the previous beztriple, and add a new one if none start there
- * Note: we perform a tree traversal here NOT a standard linked-list traversal...
- * Note: we can't search from end to try to optimize this as it causes errors there's
- * an A ___ B |---| B situation
- */
- // FIXME: here there is a bug where we are trying to get the summary for the following channels
- // A|--------------|A ______________ B|--------------|B
- // A|------------------------------------------------|A
- // A|----|A|---|A|-----------------------------------|A
- for (ab = blocks->root; ab; ab = abn) {
- /* check if this is a match, or whether we go left or right
- * NOTE: we now use a float threshold to prevent precision errors causing problems with summaries
- */
- if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
- /* set selection status and 'touched' status */
- if (BEZT_ISSEL_ANY(beztn))
- ab->sel = SELECT;
+ if (block->flag) {
+ col->totblock++;
+ }
+}
- /* XXX: only when the first one was a moving hold? */
- if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD)
- ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD;
+static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
+{
+ ActKeyColumn *col = keys->first;
- ab->modified++;
+ if (bezt && bezt_len >= 2) {
+ ActKeyBlockInfo block;
- /* done... no need to insert */
- return;
- }
- else {
- ActKeyBlock **abnp = NULL; /* branch to go down - used to hook new blocks to parents */
-
- /* check if go left or right, but if not available, add new node */
- if (ab->start < prev->vec[1][0])
- abnp = &ab->right;
- else
- abnp = &ab->left;
-
- /* if this does not exist, add a new node, otherwise continue... */
- if (*abnp == NULL) {
- /* add a new node representing this, and attach it to the relevant place */
- new_ab = bezts_to_new_actkeyblock(prev, beztn);
- new_ab->parent = ab;
- *abnp = new_ab;
- break;
+ /* Find the first key column while inserting dummy blocks. */
+ for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) {
+ add_keyblock_info(col, &dummy_keyblock);
+ }
+
+ BLI_assert(col != NULL);
+
+ /* Insert real blocks. */
+ for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) {
+ /* Wrong order of bezier keys: resync position. */
+ if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
+ /* Backtrack to find the right location. */
+ if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
+ ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
+ keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
+
+ if (newcol != NULL) {
+ col = newcol;
+
+ /* The previous keyblock is garbage too. */
+ if (col->prev != NULL) {
+ add_keyblock_info(col->prev, &dummy_keyblock);
+ }
+ }
+ else {
+ BLI_assert(false);
+ }
}
- else
- abn = *abnp;
+
+ continue;
+ }
+
+ /* Normal sequence */
+ BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0]));
+
+ compute_keyblock_data(&block, bezt, bezt + 1);
+
+ for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) {
+ add_keyblock_info(col, &block);
}
+
+ BLI_assert(col != NULL);
}
}
- /* now, balance the tree taking into account this newly added node */
- BLI_dlrbTree_insert(blocks, (DLRBT_Node *)new_ab);
+ /* Insert dummy blocks at the end. */
+ for (; col != NULL; col = col->next) {
+ add_keyblock_info(col, &dummy_keyblock);
+ }
}
-/* --------- */
-
-/* Handle the 'touched' status of ActKeyColumn tree nodes */
-static void set_touched_actkeycolumn(ActKeyColumn *ak)
+/* Walk through columns and propagate blocks and totcurve.
+ *
+ * This must be called even by animation sources that don't generate
+ * keyblocks to keep the data structure consistent after adding columns.
+ */
+static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
{
- /* sanity check */
- if (ak == NULL)
- return;
+ /* Recompute the prev/next linked list. */
+ BLI_dlrbTree_linkedlist_sync(keys);
+
+ /* Find the curve count */
+ int max_curve = 0;
- /* deal with self first */
- if (ak->modified) {
- ak->modified = 0;
- ak->totcurve++;
+ for (ActKeyColumn *col = keys->first; col; col = col->next) {
+ max_curve = MAX2(max_curve, col->totcurve);
}
- /* children */
- set_touched_actkeycolumn(ak->left);
- set_touched_actkeycolumn(ak->right);
-}
+ /* Propagate blocks to inserted keys */
+ ActKeyColumn *prev_ready = NULL;
-/* Handle the 'touched' status of ActKeyBlock tree nodes */
-static void set_touched_actkeyblock(ActKeyBlock *ab)
-{
- /* sanity check */
- if (ab == NULL)
- return;
+ for (ActKeyColumn *col = keys->first; col; col = col->next) {
+ /* Pre-existing column. */
+ if (col->totcurve > 0) {
+ prev_ready = col;
+ }
+ /* Newly inserted column, so copy block data from previous. */
+ else if (prev_ready != NULL) {
+ col->totblock = prev_ready->totblock;
+ memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo));
+ }
- /* deal with self first */
- if (ab->modified) {
- ab->modified = 0;
- ab->totcurve++;
+ col->totcurve = max_curve + 1;
}
- /* children */
- set_touched_actkeyblock(ab->left);
- set_touched_actkeyblock(ab->right);
+ /* Add blocks on top */
+ add_bezt_to_keyblocks_list(keys, bezt, bezt_len);
}
/* --------- */
-/* Checks if ActKeyBlock should exist... */
-bool actkeyblock_is_valid(ActKeyBlock *ab, DLRBT_Tree *keys)
+bool actkeyblock_is_valid(ActKeyColumn *ac)
{
- ActKeyColumn *ak;
- short startCurves, endCurves, totCurves;
+ return ac != NULL && ac->next != NULL && ac->totblock > 0;
+}
+/* Checks if ActKeyBlock should exist... */
+int actkeyblock_get_valid_hold(ActKeyColumn *ac)
+{
/* check that block is valid */
- if (ab == NULL)
+ if (!actkeyblock_is_valid(ac))
return 0;
- /* find out how many curves occur at each keyframe */
- ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->start);
- startCurves = (ak) ? ak->totcurve : 0;
-
- ak = (ActKeyColumn *)BLI_dlrbTree_search_exact(keys, compare_ak_cfraPtr, &ab->end);
- endCurves = (ak) ? ak->totcurve : 0;
-
- /* only draw keyblock if it appears in at all of the keyframes at lowest end */
- if (!startCurves && !endCurves)
- return 0;
-
- totCurves = (startCurves > endCurves) ? endCurves : startCurves;
- return (ab->totcurve >= totCurves);
+ const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD);
+ return (ac->block.flag & ~ac->block.conflict) & hold_mask;
}
/* *************************** Keyframe Drawing *************************** */
-/* coordinates for diamond shape */
-static const float _unit_diamond_shape[4][2] = {
- {0.0f, 1.0f}, /* top vert */
- {1.0f, 0.0f}, /* mid-right */
- {0.0f, -1.0f}, /* bottom vert */
- {-1.0f, 0.0f} /* mid-left */
-};
-
-/* draw a simple diamond shape with OpenGL */
-void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha)
+void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type, short mode, float alpha,
+ unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id,
+ unsigned int flags_id, short handle_type, short extreme_type)
{
- static GLuint displist1 = 0;
- static GLuint displist2 = 0;
-
- /* initialize 2 display lists for diamond shape - one empty, one filled */
- if (displist1 == 0) {
- displist1 = glGenLists(1);
- glNewList(displist1, GL_COMPILE);
-
- glBegin(GL_LINE_LOOP);
- glVertex2fv(_unit_diamond_shape[0]);
- glVertex2fv(_unit_diamond_shape[1]);
- glVertex2fv(_unit_diamond_shape[2]);
- glVertex2fv(_unit_diamond_shape[3]);
- glEnd();
-
- glEndList();
- }
- if (displist2 == 0) {
- displist2 = glGenLists(1);
- glNewList(displist2, GL_COMPILE);
-
- glBegin(GL_QUADS);
- glVertex2fv(_unit_diamond_shape[0]);
- glVertex2fv(_unit_diamond_shape[1]);
- glVertex2fv(_unit_diamond_shape[2]);
- glVertex2fv(_unit_diamond_shape[3]);
- glEnd();
-
- glEndList();
- }
+ bool draw_fill = ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH);
+ bool draw_outline = ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH);
+
+ BLI_assert(draw_fill || draw_outline);
/* tweak size of keyframe shape according to type of keyframe
* - 'proper' keyframes have key_type = 0, so get drawn at full size
@@ -513,317 +554,349 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel,
break;
case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */
- hsize *= 0.85f;
+ size *= 0.85f;
break;
case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes (but by less than for breakdowns) */
- //hsize *= 0.72f;
- hsize *= 0.95f;
+ size *= 0.925f;
break;
case BEZT_KEYTYPE_EXTREME: /* slightly larger */
- hsize *= 1.2f;
+ size *= 1.2f;
break;
default:
- hsize -= 0.5f * key_type;
- break;
+ size -= 0.8f * key_type;
}
- /* adjust view transform before starting */
- glTranslatef(x, y, 0.0f);
- glScalef(1.0f / xscale * hsize, hsize, 1.0f);
-
- /* anti-aliased lines for more consistent appearance */
- glEnable(GL_LINE_SMOOTH);
+ unsigned char fill_col[4];
+ unsigned char outline_col[4];
+ unsigned int flags = 0;
/* draw! */
- if (ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH)) {
- float inner_col[4];
-
+ if (draw_fill) {
/* get interior colors from theme (for selected and unselected only) */
switch (key_type) {
case BEZT_KEYTYPE_BREAKDOWN: /* bluish frames (default theme) */
- {
- if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_BREAKDOWN_SELECT, inner_col);
- else UI_GetThemeColor4fv(TH_KEYTYPE_BREAKDOWN, inner_col);
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_BREAKDOWN_SELECT : TH_KEYTYPE_BREAKDOWN, fill_col);
break;
- }
case BEZT_KEYTYPE_EXTREME: /* reddish frames (default theme) */
- {
- if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_EXTREME_SELECT, inner_col);
- else UI_GetThemeColor4fv(TH_KEYTYPE_EXTREME, inner_col);
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_EXTREME_SELECT : TH_KEYTYPE_EXTREME, fill_col);
break;
- }
case BEZT_KEYTYPE_JITTER: /* greenish frames (default theme) */
- {
- if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_JITTER_SELECT, inner_col);
- else UI_GetThemeColor4fv(TH_KEYTYPE_JITTER, inner_col);
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_JITTER_SELECT : TH_KEYTYPE_JITTER, fill_col);
break;
- }
case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */
- {
- /* XXX: Should these get their own theme options instead? */
- if (sel) UI_GetThemeColorShade4fv(TH_STRIP_SELECT, 35, inner_col);
- else UI_GetThemeColorShade4fv(TH_STRIP, 50, inner_col);
-
- inner_col[3] = 1.0f; /* full opacity, to avoid problems with visual glitches */
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_MOVEHOLD_SELECT : TH_KEYTYPE_MOVEHOLD, fill_col);
break;
- }
case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */
default:
- {
- if (sel) UI_GetThemeColor4fv(TH_KEYTYPE_KEYFRAME_SELECT, inner_col);
- else UI_GetThemeColor4fv(TH_KEYTYPE_KEYFRAME, inner_col);
- break;
- }
+ UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_KEYFRAME_SELECT : TH_KEYTYPE_KEYFRAME, fill_col);
}
/* NOTE: we don't use the straight alpha from the theme, or else effects such as
* graying out protected/muted channels doesn't work correctly!
*/
- inner_col[3] *= alpha;
- glColor4fv(inner_col);
-
- /* draw the "filled in" interior poly now */
- glCallList(displist2);
+ fill_col[3] *= alpha;
+
+ if (!draw_outline) {
+ /* force outline color to match */
+ outline_col[0] = fill_col[0];
+ outline_col[1] = fill_col[1];
+ outline_col[2] = fill_col[2];
+ outline_col[3] = fill_col[3];
+ }
}
- if (ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH)) {
- float border_col[4];
-
+ if (draw_outline) {
/* exterior - black frame */
- if (sel) UI_GetThemeColor4fv(TH_KEYBORDER_SELECT, border_col);
- else UI_GetThemeColor4fv(TH_KEYBORDER, border_col);
+ UI_GetThemeColor4ubv(sel ? TH_KEYBORDER_SELECT : TH_KEYBORDER, outline_col);
+ outline_col[3] *= alpha;
+
+ if (!draw_fill) {
+ /* fill color needs to be (outline.rgb, 0) */
+ fill_col[0] = outline_col[0];
+ fill_col[1] = outline_col[1];
+ fill_col[2] = outline_col[2];
+ fill_col[3] = 0;
+ }
- border_col[3] *= alpha;
- glColor4fv(border_col);
+ /* Handle type to outline shape. */
+ switch (handle_type) {
+ case KEYFRAME_HANDLE_AUTO_CLAMP: flags = 0x2; break; /* circle */
+ case KEYFRAME_HANDLE_AUTO: flags = 0x12; break; /* circle with dot */
+ case KEYFRAME_HANDLE_VECTOR: flags = 0xC; break; /* square */
+ case KEYFRAME_HANDLE_ALIGNED: flags = 0x5; break; /* clipped diamond */
- glCallList(displist1);
- }
+ case KEYFRAME_HANDLE_FREE:
+ default:
+ flags = 1; /* diamond */
+ }
- glDisable(GL_LINE_SMOOTH);
+ /* Extreme type to arrow-like shading. */
+ if (extreme_type & KEYFRAME_EXTREME_MAX) {
+ flags |= 0x100;
+ }
+ if (extreme_type & KEYFRAME_EXTREME_MIN) {
+ flags |= 0x200;
+ }
+ if (extreme_type & KEYFRAME_EXTREME_MIXED) {
+ flags |= 0x400;
+ }
+ }
- /* restore view transform */
- glScalef(xscale / hsize, 1.0f / hsize, 1.0f);
- glTranslatef(-x, -y, 0.0f);
+ immAttr1f(size_id, size);
+ immAttr4ubv(color_id, fill_col);
+ immAttr4ubv(outline_color_id, outline_col);
+ immAttr1u(flags_id, flags);
+ immVertex2f(pos_id, x, y);
}
-static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, float yscale_fac, bool channelLocked)
+static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale_fac, bool channelLocked, int saction_flag)
{
- ActKeyColumn *ak;
- ActKeyBlock *ab;
- float alpha;
- float xscale;
-
- const float iconsize = (U.widget_unit / 4.0f) * yscale_fac;
- const float mhsize = iconsize * 0.7f;
+ const float icon_sz = U.widget_unit * 0.5f * yscale_fac;
+ const float half_icon_sz = 0.5f * icon_sz;
+ const float smaller_sz = 0.35f * icon_sz;
+ const float ipo_sz = 0.1f * icon_sz;
- glEnable(GL_BLEND);
-
- /* get View2D scaling factor */
- UI_view2d_scale_get(v2d, &xscale, NULL);
+ GPU_blend(true);
/* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */
/* TODO: allow this opacity factor to be themed? */
- alpha = (channelLocked) ? 0.25f : 1.0f;
+ float alpha = channelLocked ? 0.25f : 1.0f;
+
+ /* Show interpolation and handle type? */
+ bool show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0;
/* draw keyblocks */
- if (blocks) {
+ if (keys) {
float sel_color[4], unsel_color[4];
float sel_mhcol[4], unsel_mhcol[4];
+ float ipo_color[4], ipo_color_mix[4];
/* cache colours first */
UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color);
UI_GetThemeColor4fv(TH_STRIP, unsel_color);
+ UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ipo_color);
sel_color[3] *= alpha;
unsel_color[3] *= alpha;
+ ipo_color[3] *= alpha;
copy_v4_v4(sel_mhcol, sel_color);
sel_mhcol[3] *= 0.8f;
copy_v4_v4(unsel_mhcol, unsel_color);
unsel_mhcol[3] *= 0.8f;
+ copy_v4_v4(ipo_color_mix, ipo_color);
+ ipo_color_mix[3] *= 0.5f;
- /* NOTE: the tradeoff for changing colors between each draw is dwarfed by the cost of checking validity */
- for (ab = blocks->first; ab; ab = ab->next) {
- if (actkeyblock_is_valid(ab, keys)) {
- if (ab->flag & ACTKEYBLOCK_FLAG_MOVING_HOLD) {
- /* draw "moving hold" long-keyframe block - slightly smaller */
- if (ab->sel)
- glColor4fv(sel_mhcol);
- else
- glColor4fv(unsel_mhcol);
-
- glRectf(ab->start, ypos - mhsize, ab->end, ypos + mhsize);
+ uint block_len = 0;
+ for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
+ if (actkeyblock_get_valid_hold(ab)) {
+ block_len++;
+ }
+ if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
+ block_len++;
+ }
+ }
+
+ if (block_len > 0) {
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ immBegin(GPU_PRIM_TRIS, 6 * block_len);
+ for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
+ int valid_hold = actkeyblock_get_valid_hold(ab);
+ if (valid_hold != 0) {
+ if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* draw "moving hold" long-keyframe block - slightly smaller */
+ immRectf_fast_with_color(pos_id, color_id,
+ ab->cfra, ypos - smaller_sz, ab->next->cfra, ypos + smaller_sz,
+ (ab->block.sel) ? sel_mhcol : unsel_mhcol);
+ }
+ else {
+ /* draw standard long-keyframe block */
+ immRectf_fast_with_color(pos_id, color_id,
+ ab->cfra, ypos - half_icon_sz, ab->next->cfra, ypos + half_icon_sz,
+ (ab->block.sel) ? sel_color : unsel_color);
+ }
}
- else {
- /* draw standard long-keyframe block */
- if (ab->sel)
- glColor4fv(sel_color);
- else
- glColor4fv(unsel_color);
-
- glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize);
+ if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) {
+ /* draw an interpolation line */
+ immRectf_fast_with_color(pos_id, color_id,
+ ab->cfra, ypos - ipo_sz, ab->next->cfra, ypos + ipo_sz,
+ (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ipo_color_mix : ipo_color);
}
}
+ immEnd();
+ immUnbindProgram();
}
}
- /* draw keys */
if (keys) {
- for (ak = keys->first; ak; ak = ak->next) {
+ /* count keys */
+ uint key_len = 0;
+ for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
/* optimization: if keyframe doesn't appear within 5 units (screenspace) in visible area, don't draw
* - this might give some improvements, since we current have to flip between view/region matrices
*/
- if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax) == 0)
- continue;
+ if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax))
+ key_len++;
+ }
- /* draw using OpenGL - uglier but faster */
- /* NOTE1: a previous version of this didn't work nice for some intel cards
- * NOTE2: if we wanted to go back to icons, these are icon = (ak->sel & SELECT) ? ICON_SPACE2 : ICON_SPACE3; */
- draw_keyframe_shape(ak->cfra, ypos, xscale, iconsize, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha);
+ if (key_len > 0) {
+ /* draw keys */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ GPU_enable_program_point_size();
+ immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
+ immBegin(GPU_PRIM_POINTS, key_len);
+
+ short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
+
+ for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
+ if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
+ if (show_ipo) {
+ handle_type = ak->handle_type;
+ }
+ if (saction_flag & SACTION_SHOW_EXTREMES) {
+ extreme_type = ak->extreme_type;
+ }
+
+ draw_keyframe_shape(ak->cfra, ypos, icon_sz, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha,
+ pos_id, size_id, color_id, outline_color_id, flags_id, handle_type, extreme_type);
+ }
+ }
+
+ immEnd();
+ GPU_disable_program_point_size();
+ immUnbindProgram();
}
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
/* *************************** Channel Drawing Funcs *************************** */
-void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac)
+void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac, int saction_flag)
{
- DLRBT_Tree keys, blocks;
+ DLRBT_Tree keys;
- BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- summary_to_keylist(ac, &keys, &blocks);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ summary_to_keylist(ac, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac)
+void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac, int saction_flag)
{
- DLRBT_Tree keys, blocks;
+ DLRBT_Tree keys;
- BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- scene_to_keylist(ads, sce, &keys, &blocks);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ scene_to_keylist(ads, sce, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac)
+void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac, int saction_flag)
{
- DLRBT_Tree keys, blocks;
+ DLRBT_Tree keys;
- BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- ob_to_keylist(ads, ob, &keys, &blocks);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ ob_to_keylist(ads, ob, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac)
+void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac, int saction_flag)
{
- DLRBT_Tree keys, blocks;
+ DLRBT_Tree keys;
bool locked = (fcu->flag & FCURVE_PROTECTED) ||
((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ||
((adt && adt->action) && ID_IS_LINKED(adt->action));
BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
-
- fcurve_to_keylist(adt, fcu, &keys, &blocks);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ fcurve_to_keylist(adt, fcu, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac)
+void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag)
{
- DLRBT_Tree keys, blocks;
+ DLRBT_Tree keys;
bool locked = (agrp->flag & AGRP_PROTECTED) ||
((adt && adt->action) && ID_IS_LINKED(adt->action));
BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
-
- agroup_to_keylist(adt, agrp, &keys, &blocks);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ agroup_to_keylist(adt, agrp, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac)
+void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac, int saction_flag)
{
- DLRBT_Tree keys, blocks;
+ DLRBT_Tree keys;
bool locked = (act && ID_IS_LINKED(act));
- BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- action_to_keylist(adt, act, &keys, &blocks);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
+ action_to_keylist(adt, act, &keys, saction_flag);
- draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
}
-void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac)
+void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
- BLI_dlrbTree_init(&keys);
+ saction_flag &= ~SACTION_SHOW_EXTREMES;
- gpencil_to_keylist(ads, gpd, &keys);
+ BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
+ gpencil_to_keylist(ads, gpd, &keys, false);
- draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, false);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac)
+void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
@@ -833,14 +906,12 @@ void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos,
gpl_to_keylist(ads, gpl, &keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
-
- draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
}
-void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac)
+void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac, int saction_flag)
{
DLRBT_Tree keys;
@@ -850,16 +921,14 @@ void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, floa
mask_to_keylist(ads, masklay, &keys);
- BLI_dlrbTree_linkedlist_sync(&keys);
-
- draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, locked);
+ draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag);
BLI_dlrbTree_free(&keys);
}
/* *************************** Keyframe List Conversions *************************** */
-void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag)
{
if (ac) {
ListBase anim_data = {NULL, NULL};
@@ -879,7 +948,7 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks)
switch (ale->datatype) {
case ALE_FCURVE:
- fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
break;
case ALE_MASKLAY:
mask_to_keylist(ac->ads, ale->data, keys);
@@ -897,7 +966,7 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks)
}
}
-void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag)
{
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -925,12 +994,12 @@ void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, DLRBT_Tree
/* loop through each F-Curve, grabbing the keyframes */
for (ale = anim_data.first; ale; ale = ale->next)
- fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
ANIM_animdata_freelist(&anim_data);
}
-void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag)
{
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -961,12 +1030,12 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl
/* loop through each F-Curve, grabbing the keyframes */
for (ale = anim_data.first; ale; ale = ale->next)
- fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
ANIM_animdata_freelist(&anim_data);
}
-void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, int saction_flag)
{
if (cache_file == NULL) {
return;
@@ -991,33 +1060,40 @@ void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *ke
/* 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);
+ fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
}
ANIM_animdata_freelist(&anim_data);
}
-void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag)
{
- BezTriple *bezt;
- unsigned int v;
-
if (fcu && fcu->totvert && fcu->bezt) {
/* apply NLA-mapping (if applicable) */
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- /* loop through beztriples, making ActKeysColumns and ActKeyBlocks */
- for (v = 0, bezt = fcu->bezt; v < fcu->totvert; v++, bezt++) {
- add_bezt_to_keycolumns_list(keys, bezt);
- if (blocks) add_bezt_to_keyblocks_list(blocks, fcu->bezt, bezt);
+ /* Check if the curve is cyclic. */
+ bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2);
+ bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0;
+
+ /* loop through beztriples, making ActKeysColumns */
+ BezTripleChain chain = { 0 };
+
+ for (int v = 0; v < fcu->totvert; v++) {
+ chain.cur = &fcu->bezt[v];
+
+ /* Neighbor keys, accounting for being cyclic. */
+ if (do_extremes) {
+ chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL;
+ chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL;
+ }
+
+ add_bezt_to_keycolumns_list(keys, &chain);
}
- /* update the number of curves that elements have appeared in */
- if (keys)
- set_touched_actkeycolumn(keys->root);
- if (blocks)
- set_touched_actkeyblock(blocks->root);
+ /* Update keyblocks. */
+ update_keyblocks(keys, fcu->bezt, fcu->totvert);
/* unapply NLA-mapping if applicable */
if (adt)
@@ -1025,40 +1101,42 @@ void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree
}
}
-void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag)
{
FCurve *fcu;
if (agrp) {
/* loop through F-Curves */
for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) {
- fcurve_to_keylist(adt, fcu, keys, blocks);
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
}
}
}
-void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, DLRBT_Tree *blocks)
+void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag)
{
FCurve *fcu;
if (act) {
/* loop through F-Curves */
for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- fcurve_to_keylist(adt, fcu, keys, blocks);
+ fcurve_to_keylist(adt, fcu, keys, saction_flag);
}
}
}
-void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys)
+void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active)
{
bGPDlayer *gpl;
if (gpd && keys) {
/* for now, just aggregate out all the frames, but only for visible layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
if ((gpl->flag & GP_LAYER_HIDE) == 0) {
- gpl_to_keylist(ads, gpl, keys);
+ if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) {
+ gpl_to_keylist(ads, gpl, keys);
+ }
}
}
}
@@ -1072,6 +1150,8 @@ void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
/* although the frames should already be in an ordered list, they are not suitable for displaying yet */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next)
add_gpframe_to_keycolumns_list(keys, gpf);
+
+ update_keyblocks(keys, NULL, 0);
}
}
@@ -1086,5 +1166,7 @@ void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *ke
{
add_masklay_to_keycolumns_list(keys, masklay_shape);
}
+
+ update_keyblocks(keys, NULL, 0);
}
}
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index c8b0ed391f9..e733bb0f8b7 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -416,16 +416,14 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac)
filter = ANIMFILTER_DATA_VISIBLE;
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* loop over F-Curves that are likely to have been edited, and check them */
+ /* Loop over F-Curves that are likely to have been edited, and tag them to
+ * ensure the keyframes are in order and handles are in a valid position. */
for (ale = anim_data.first; ale; ale = ale->next) {
- FCurve *fcu = ale->key_data;
-
- /* make sure keyframes in F-Curve are all in order, and handles are in valid positions */
- sort_time_fcurve(fcu);
- calchandles_fcurve(fcu);
+ ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES | ANIM_UPDATE_ORDER;
}
/* free temp data */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index aad9835f2aa..df87e1b7a5f 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -47,7 +47,6 @@
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
-#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_global.h"
#include "BKE_deform.h"
@@ -183,7 +182,8 @@ void duplicate_fcurve_keys(FCurve *fcu)
/* Various Tools */
/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only
- * optionally clears up curve if one keyframe with default value remains */
+ * optionally clears up curve if one keyframe with default value remains
+ */
void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault)
{
FCurve *fcu = (FCurve *)ale->key_data;
@@ -206,7 +206,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
/* now insert first keyframe, as it should be ok */
bezt = old_bezts;
- insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
if (!(bezt->f2 & SELECT)) {
lastb = fcu->bezt;
lastb->f1 = lastb->f2 = lastb->f3 = 0;
@@ -235,7 +235,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
if (!(bezt->f2 & SELECT)) {
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
lastb = (fcu->bezt + (fcu->totvert - 1));
lastb->f1 = lastb->f2 = lastb->f3 = 0;
continue;
@@ -254,7 +254,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
if (cur[1] > next[1]) {
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
}
}
}
@@ -262,7 +262,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
/* only add if values are a considerable distance apart */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
}
}
}
@@ -271,19 +271,19 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
if (beztn) {
/* does current have same value as previous and next? */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
- /* add new keyframe*/
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ /* add new keyframe */
+ insert_bezt_fcurve(fcu, bezt, 0);
}
else if (IS_EQT(cur[1], next[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
}
}
else {
/* add if value doesn't equal that of previous */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
+ insert_bezt_fcurve(fcu, bezt, 0);
}
}
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 9ea43c160a6..4bf6c43e348 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -57,7 +57,6 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idcode.h"
@@ -67,6 +66,10 @@
#include "BKE_nla.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "ED_anim_api.h"
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
@@ -113,6 +116,10 @@ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode)
/* keyframing mode - only replace existing keyframes */
if (IS_AUTOKEY_MODE(scene, EDITKEYS))
flag |= INSERTKEY_REPLACE;
+
+ /* cycle-aware keyframe insertion - preserve cycle period and flow */
+ if (IS_AUTOKEY_FLAG(scene, CYCLEAWARE))
+ flag |= INSERTKEY_CYCLE_AWARE;
}
return flag;
@@ -154,11 +161,12 @@ bAction *verify_adt_action(Main *bmain, ID *id, short add)
*/
adt->action->idroot = GS(id->name);
- /* tag depsgraph to be rebuilt to include time dependency */
- /* XXX: we probably should have bmain passed down, but that involves altering too many API's */
- DAG_relations_tag_update(bmain);
+ /* Tag depsgraph to be rebuilt to include time dependency. */
+ DEG_relations_tag_update(bmain);
}
+ DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
+
/* return the action */
return adt->action;
}
@@ -166,7 +174,7 @@ bAction *verify_adt_action(Main *bmain, ID *id, short add)
/* Get (or add relevant data to be able to do so) F-Curve from the Active Action,
* for the given Animation Data block. This assumes that all the destinations are valid.
*/
-FCurve *verify_fcurve(bAction *act, const char group[], PointerRNA *ptr,
+FCurve *verify_fcurve(Main *bmain, bAction *act, const char group[], PointerRNA *ptr,
const char rna_path[], const int array_index, short add)
{
bActionGroup *agrp;
@@ -227,6 +235,11 @@ FCurve *verify_fcurve(bAction *act, const char group[], PointerRNA *ptr,
/* just add F-Curve to end of Action's list */
BLI_addtail(&act->curves, fcu);
}
+
+ /* New f-curve was added, meaning it's possible that it affects
+ * dependency graph component which wasn't previously animated.
+ */
+ DEG_relations_tag_update(bmain);
}
/* return the F-Curve */
@@ -294,8 +307,67 @@ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, Poin
/* ************************************************** */
/* KEYFRAME INSERTION */
+/* Move the point where a key is about to be inserted to be inside the main cycle range.
+ * Returns the type of the cycle if it is enabled and valid.
+ */
+static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, float *py)
+{
+ if (fcu->totvert < 2 || !fcu->bezt) {
+ return FCU_CYCLE_NONE;
+ }
+
+ eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu);
+
+ if (type == FCU_CYCLE_NONE) {
+ return FCU_CYCLE_NONE;
+ }
+
+ BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1];
+ float start = first->vec[1][0], end = last->vec[1][0];
+
+ if (start >= end) {
+ return FCU_CYCLE_NONE;
+ }
+
+ if (*px < start || *px > end) {
+ float period = end - start;
+ float step = floorf((*px - start) / period);
+ *px -= step * period;
+
+ if (type == FCU_CYCLE_OFFSET) {
+ /* Nasty check to handle the case when the modes are different better. */
+ FMod_Cycles *data = ((FModifier *)fcu->modifiers.first)->data;
+ short mode = (step >= 0) ? data->after_mode : data->before_mode;
+
+ if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
+ *py -= step * (last->vec[1][1] - first->vec[1][1]);
+ }
+ }
+ }
+
+ return type;
+}
+
/* -------------- BezTriple Insertion -------------------- */
+/* Change the Y position of a keyframe to match the input, adjusting handles. */
+static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt)
+{
+ /* just change the values when replacing, so as to not overwrite handles */
+ float dy = bezt->vec[1][1] - dst->vec[1][1];
+
+ /* just apply delta value change to the handle values */
+ dst->vec[0][1] += dy;
+ dst->vec[1][1] += dy;
+ dst->vec[2][1] += dy;
+
+ dst->f1 = bezt->f1;
+ dst->f2 = bezt->f2;
+ dst->f3 = bezt->f3;
+
+ /* TODO: perform some other operations? */
+}
+
/* This function adds a given BezTriple to an F-Curve. It will allocate
* memory for the array if needed, and will insert the BezTriple into a
* suitable place in chronological order.
@@ -320,20 +392,14 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag)
fcu->bezt[i] = *bezt;
}
else {
- /* just change the values when replacing, so as to not overwrite handles */
- BezTriple *dst = (fcu->bezt + i);
- float dy = bezt->vec[1][1] - dst->vec[1][1];
-
- /* just apply delta value change to the handle values */
- dst->vec[0][1] += dy;
- dst->vec[1][1] += dy;
- dst->vec[2][1] += dy;
-
- dst->f1 = bezt->f1;
- dst->f2 = bezt->f2;
- dst->f3 = bezt->f3;
+ replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt);
+ }
- /* TODO: perform some other operations? */
+ if (flag & INSERTKEY_CYCLE_AWARE) {
+ /* If replacing an end point of a cyclic curve without offset, modify the other end too. */
+ if ((i == 0 || i == fcu->totvert - 1) && BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT) {
+ replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt);
+ }
}
}
}
@@ -612,31 +678,36 @@ static short new_key_needed(FCurve *fcu, float cFrame, float nValue)
/* ------------------ RNA Data-Access Functions ------------------ */
/* Try to read value using RNA-properties obtained already */
-static float setting_get_rna_value(PointerRNA *ptr, PropertyRNA *prop, int index)
+static float setting_get_rna_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int index, const bool get_evaluated)
{
+ PointerRNA ptr_eval = *ptr;
float value = 0.0f;
+ if (get_evaluated) {
+ DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval);
+ }
+
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (RNA_property_array_check(prop))
- value = (float)RNA_property_boolean_get_index(ptr, prop, index);
+ value = (float)RNA_property_boolean_get_index(&ptr_eval, prop, index);
else
- value = (float)RNA_property_boolean_get(ptr, prop);
+ value = (float)RNA_property_boolean_get(&ptr_eval, prop);
break;
case PROP_INT:
if (RNA_property_array_check(prop))
- value = (float)RNA_property_int_get_index(ptr, prop, index);
+ value = (float)RNA_property_int_get_index(&ptr_eval, prop, index);
else
- value = (float)RNA_property_int_get(ptr, prop);
+ value = (float)RNA_property_int_get(&ptr_eval, prop);
break;
case PROP_FLOAT:
if (RNA_property_array_check(prop))
- value = RNA_property_float_get_index(ptr, prop, index);
+ value = RNA_property_float_get_index(&ptr_eval, prop, index);
else
- value = RNA_property_float_get(ptr, prop);
+ value = RNA_property_float_get(&ptr_eval, prop);
break;
case PROP_ENUM:
- value = (float)RNA_property_enum_get(ptr, prop);
+ value = (float)RNA_property_enum_get(&ptr_eval, prop);
break;
default:
break;
@@ -739,6 +810,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
switch (con->type) {
/* multi-transform constraints */
case CONSTRAINT_TYPE_CHILDOF:
+ case CONSTRAINT_TYPE_ARMATURE:
return true;
case CONSTRAINT_TYPE_TRANSFORM:
case CONSTRAINT_TYPE_TRANSLIKE:
@@ -797,7 +869,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
* In the event that it is not possible to perform visual keying, try to fall-back
* to using the default method. Assumes that all data it has been passed is valid.
*/
-static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_index)
+static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int array_index)
{
const char *identifier = RNA_property_identifier(prop);
float tmat[4][4];
@@ -812,20 +884,25 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
*/
if (ptr->type == &RNA_Object) {
Object *ob = (Object *)ptr->data;
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
/* Loc code is specific... */
if (strstr(identifier, "location")) {
- return ob->obmat[3][array_index];
+ return ob_eval->obmat[3][array_index];
}
- copy_m4_m4(tmat, ob->obmat);
- rotmode = ob->rotmode;
+ copy_m4_m4(tmat, ob_eval->obmat);
+ rotmode = ob_eval->rotmode;
}
else if (ptr->type == &RNA_PoseBone) {
+ Object *ob = (Object *)ptr->id.data;
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, tmat);
- rotmode = pchan->rotmode;
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+
+ BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, tmat);
+ rotmode = pchan_eval->rotmode;
/* Loc code is specific... */
if (strstr(identifier, "location")) {
@@ -835,7 +912,7 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
}
}
else {
- return setting_get_rna_value(ptr, prop, array_index);
+ return setting_get_rna_value(depsgraph, ptr, prop, array_index, true);
}
/* Rot/Scale code are common! */
@@ -873,7 +950,7 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
}
/* as the function hasn't returned yet, read value from system in the default way */
- return setting_get_rna_value(ptr, prop, array_index);
+ return setting_get_rna_value(depsgraph, ptr, prop, array_index, true);
}
/* ------------------------- Insert Key API ------------------------- */
@@ -888,7 +965,7 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
* the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
* and extra keyframe filtering.
*/
-bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
+bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
{
float curval = 0.0f;
@@ -939,7 +1016,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
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);
+ cfra = evaluate_driver(&anim_rna, fcu->driver, fcu->driver, cfra);
}
else {
cfra = 0.0f;
@@ -954,11 +1031,19 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
* it works by keyframing using a value extracted from the final matrix
* instead of using the kt system to extract a value.
*/
- curval = visualkey_get_value(&ptr, prop, fcu->array_index);
+ curval = visualkey_get_value(depsgraph, &ptr, prop, fcu->array_index);
}
else {
/* read value from system */
- curval = setting_get_rna_value(&ptr, prop, fcu->array_index);
+ curval = setting_get_rna_value(depsgraph, &ptr, prop, fcu->array_index, false);
+ }
+
+ /* adjust coordinates for cycle aware insertion */
+ if (flag & INSERTKEY_CYCLE_AWARE) {
+ if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) {
+ /* inhibit action from insert_vert_fcurve unless it's a perfect cycle */
+ flag &= ~INSERTKEY_CYCLE_AWARE;
+ }
}
/* only insert keyframes where they are needed */
@@ -1008,7 +1093,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
* index of -1 keys all array indices
*/
short insert_keyframe(
- Main *bmain, ReportList *reports, ID *id, bAction *act,
+ Main *bmain, Depsgraph *depsgraph, ReportList *reports, ID *id, bAction *act,
const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
{
PointerRNA id_ptr, ptr;
@@ -1068,7 +1153,7 @@ short insert_keyframe(
* - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet
* but still try to get the F-Curve if it exists...
*/
- fcu = verify_fcurve(act, group, &ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0);
+ fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0);
/* we may not have a F-Curve when we're replacing only... */
if (fcu) {
@@ -1087,7 +1172,16 @@ short insert_keyframe(
}
/* insert keyframe */
- ret += insert_keyframe_direct(reports, ptr, prop, fcu, cfra, keytype, flag);
+ ret += insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, keytype, flag);
+ }
+ }
+
+ if (ret) {
+ if (act != NULL) {
+ DEG_id_tag_update(&act->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ if (adt != NULL && adt->action != NULL && adt->action != act) {
+ DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -1132,7 +1226,9 @@ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra)
return false;
}
-short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, eInsertKeyFlags UNUSED(flag))
+short delete_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act,
+ const char group[], const char rna_path[], int array_index, float cfra,
+ eInsertKeyFlags UNUSED(flag))
{
AnimData *adt = BKE_animdata_from_id(id);
PointerRNA id_ptr, ptr;
@@ -1190,7 +1286,7 @@ short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
/* will only loop once unless the array index was -1 */
for (; array_index < array_index_max; array_index++) {
- FCurve *fcu = verify_fcurve(act, group, &ptr, rna_path, array_index, 0);
+ FCurve *fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, 0);
/* check if F-Curve exists and/or whether it can be edited */
if (fcu == NULL)
@@ -1221,7 +1317,9 @@ short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
* The flag argument is used for special settings that alter the behavior of
* the keyframe deletion. These include the quick refresh options.
*/
-static short clear_keyframe(ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, eInsertKeyFlags UNUSED(flag))
+static short clear_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act,
+ const char group[], const char rna_path[], int array_index,
+ eInsertKeyFlags UNUSED(flag))
{
AnimData *adt = BKE_animdata_from_id(id);
PointerRNA id_ptr, ptr;
@@ -1276,7 +1374,7 @@ static short clear_keyframe(ReportList *reports, ID *id, bAction *act, const cha
/* will only loop once unless the array index was -1 */
for (; array_index < array_index_max; array_index++) {
- FCurve *fcu = verify_fcurve(act, group, &ptr, rna_path, array_index, 0);
+ FCurve *fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, 0);
/* check if F-Curve exists and/or whether it can be edited */
if (fcu == NULL)
@@ -1621,7 +1719,7 @@ static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op))
/* delete F-Curve completely */
if (can_delete) {
ANIM_fcurve_delete_from_animdata(NULL, adt, fcu);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
changed = true;
}
}
@@ -1728,7 +1826,7 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op)
else
BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
CTX_DATA_END;
@@ -1760,6 +1858,7 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
static int insert_key_button_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@@ -1793,7 +1892,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
if (fcu) {
- success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
+ success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
}
else {
BKE_report(op->reports, RPT_ERROR,
@@ -1808,7 +1907,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
if (fcu && driven) {
- success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
+ success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
}
}
else {
@@ -1816,12 +1915,35 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
+ const char *identifier = RNA_property_identifier(prop);
+ const char *group = NULL;
+
+ /* Special exception for keyframing transforms:
+ * Set "group" for this manually, instead of having them appearing at the bottom (ungrouped)
+ * part of the channels list. Leaving these ungrouped is not a nice user behaviour in this case.
+ *
+ * TODO: Perhaps we can extend this behaviour in future for other properties...
+ */
+ if (ptr.type == &RNA_PoseBone) {
+ bPoseChannel *pchan = (bPoseChannel *)ptr.data;
+ group = pchan->name;
+ }
+ else if ((ptr.type == &RNA_Object) &&
+ (strstr(identifier, "location") || strstr(identifier, "rotation") || strstr(identifier, "scale")))
+ {
+ /* NOTE: Keep this label in sync with the "ID" case in
+ * keyingsets_utils.py :: get_transform_generators_base_info()
+ */
+ group = "Object Transforms";
+ }
+
+
if (all) {
/* -1 indicates operating on the entire array (or the property itself otherwise) */
index = -1;
}
- success = insert_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, cfra, ts->keyframe_type, flag);
+ success = insert_keyframe(bmain, depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, flag);
MEM_freeN(path);
}
@@ -1881,6 +2003,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
+ Main *bmain = CTX_data_main(C);
char *path;
float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
short success = 0;
@@ -1937,7 +2060,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
index = -1;
}
- success = delete_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0);
+ success = delete_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)
@@ -1985,6 +2108,7 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
+ Main *bmain = CTX_data_main(C);
char *path;
short success = 0;
int index;
@@ -2005,7 +2129,7 @@ static int clear_key_button_exec(bContext *C, wmOperator *op)
index = -1;
}
- success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, 0);
+ success += clear_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, 0);
MEM_freeN(path);
}
else if (G.debug & G_DEBUG)
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index e4aeef72755..d8e9c5a7790 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -48,9 +48,10 @@
#include "BKE_main.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "ED_keyframing.h"
#include "ED_screen.h"
@@ -923,7 +924,8 @@ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
/* Determine which keying flags apply based on the override flags */
static short keyingset_apply_keying_flags(const short base_flags, const short overrides, const short own_flags)
{
- short result = 0;
+ /* Pass through all flags by default (i.e. even not explicitly listed ones). */
+ short result = base_flags;
/* The logic for whether a keying flag applies is as follows:
* - If the flag in question is set in "overrides", that means that the
@@ -933,10 +935,8 @@ static short keyingset_apply_keying_flags(const short base_flags, const short ov
*/
#define APPLY_KEYINGFLAG_OVERRIDE(kflag) \
if (overrides & kflag) { \
+ result &= ~kflag; \
result |= (own_flags & kflag); \
- } \
- else { \
- result |= (base_flags & kflag); \
}
/* Apply the flags one by one...
@@ -957,6 +957,7 @@ static short keyingset_apply_keying_flags(const short base_flags, const short ov
*/
int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ReportList *reports = CTX_wm_reports(C);
@@ -1038,9 +1039,9 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
for (; i < arraylen; i++) {
/* action to take depends on mode */
if (mode == MODIFYKEY_MODE_INSERT)
- success += insert_keyframe(bmain, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2);
+ success += insert_keyframe(bmain, depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2);
else if (mode == MODIFYKEY_MODE_DELETE)
- success += delete_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
+ success += delete_keyframe(bmain, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
}
/* set recalc-flags */
@@ -1050,10 +1051,11 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
Object *ob = (Object *)ksp->id;
// XXX: only object transforms?
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
break;
}
default:
+ DEG_id_tag_update(ksp->id, DEG_TAG_COPY_ON_WRITE);
break;
}
diff --git a/source/blender/editors/armature/BIF_generate.h b/source/blender/editors/armature/BIF_generate.h
deleted file mode 100644
index e229b0f342a..00000000000
--- a/source/blender/editors/armature/BIF_generate.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/armature/BIF_generate.h
- * \ingroup edarmature
- */
-
-
-#ifndef __BIF_GENERATE_H__
-#define __BIF_GENERATE_H__
-
-struct ToolSettings;
-struct EditBone;
-struct BArcIterator;
-struct bArmature;
-struct ListBase;
-
-typedef int (NextSubdivisionFunc)(struct ToolSettings *, struct BArcIterator *, int, int, float[3], float[3]);
-
-float calcArcCorrelation(struct BArcIterator *iter, int start, int end, float v0[3], float n[3]);
-
-int nextFixedSubdivision(struct ToolSettings *toolsettings, struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
-int nextLengthSubdivision(struct ToolSettings *toolsettings, struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
-int nextAdaptativeSubdivision(struct ToolSettings *toolsettings, struct BArcIterator *iter, int start, int end, float head[3], float p[3]);
-
-struct EditBone *subdivideArcBy(struct ToolSettings *toolsettings, struct bArmature *arm, ListBase *editbones, struct BArcIterator *iter,
- float invmat[4][4], float tmat[3][3], NextSubdivisionFunc next_subdividion);
-
-void setBoneRollFromNormal(struct EditBone *bone, const float no[3], float invmat[4][4], float tmat[3][3]);
-
-
-#endif /* __BIF_GENERATE_H__ */
diff --git a/source/blender/editors/armature/BIF_retarget.h b/source/blender/editors/armature/BIF_retarget.h
deleted file mode 100644
index 2bd2b80190b..00000000000
--- a/source/blender/editors/armature/BIF_retarget.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/armature/BIF_retarget.h
- * \ingroup edarmature
- */
-
-#ifndef __BIF_RETARGET_H__
-#define __BIF_RETARGET_H__
-
-#include "DNA_listBase.h"
-
-#include "BLI_graph.h"
-#include "BLI_ghash.h"
-#include "BLI_task.h"
-#include "BLI_threads.h"
-
-#include "reeb.h"
-
-struct Object;
-struct bArmature;
-struct bContext;
-
-struct EditBone;
-
-struct RigGraph;
-struct RigNode;
-struct RigArc;
-struct RigEdge;
-
-#define USE_THREADS
-
-typedef struct RigGraph {
- ListBase arcs;
- ListBase nodes;
-
- float length;
-
- FreeArc free_arc;
- FreeNode free_node;
- RadialSymmetry radial_symmetry;
- AxialSymmetry axial_symmetry;
- /*********************************/
-
- int flag;
-
- ListBase controls;
- ListBase *editbones;
-
- struct RigNode *head;
- ReebGraph *link_mesh;
-
-
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
-
- GHash *bones_map; /* map of editbones by name */
- GHash *controls_map; /* map of rigcontrols by bone pointer */
-
- struct Object *ob;
-} RigGraph;
-
-typedef struct RigNode {
- void *next, *prev;
- float p[3];
- int flag;
-
- int degree;
- struct BArc **arcs;
-
- int subgraph_index;
-
- int symmetry_level;
- int symmetry_flag;
- float symmetry_axis[3];
- /*********************************/
-
- ReebNode *link_mesh;
-} RigNode;
-
-typedef struct RigArc {
- void *next, *prev;
- RigNode *head, *tail;
- int flag;
-
- float length;
-
- int symmetry_level;
- int symmetry_group;
- int symmetry_flag;
- /*********************************/
-
- ListBase edges;
- int count;
- ReebArc *link_mesh;
-} RigArc;
-
-typedef struct RigEdge {
- struct RigEdge *next, *prev;
- float head[3], tail[3];
- float length;
- float angle; /* angle to next edge */
- float up_angle; /* angle between up_axis and the joint normal (defined as Previous edge CrossProduct Current edge */
- struct EditBone *bone;
- float up_axis[3];
-} RigEdge;
-
-/* Graph flags */
-#define RIG_FREE_BONELIST 1
-
-/* Control flags */
-#define RIG_CTRL_HEAD_DONE 1
-#define RIG_CTRL_TAIL_DONE 2
-#define RIG_CTRL_PARENT_DEFORM 4
-#define RIG_CTRL_FIT_ROOT 8
-#define RIG_CTRL_FIT_BONE 16
-
-#define RIG_CTRL_DONE (RIG_CTRL_HEAD_DONE | RIG_CTRL_TAIL_DONE)
-
-/* Control tail flags */
-typedef enum {
- TL_NONE = 0,
- TL_TAIL,
- TL_HEAD
-} LinkTailMode;
-
-typedef struct RigControl {
- struct RigControl *next, *prev;
- float head[3], tail[3];
- struct EditBone *bone;
- struct EditBone *link;
- struct EditBone *link_tail;
- float up_axis[3];
- float offset[3];
- float qrot[4]; /* for dual linked bones, store the rotation of the linked bone for the finalization */
- int flag;
- LinkTailMode tail_mode;
-} RigControl;
-
-void BIF_retargetArc(struct bContext *C, ReebArc *earc, RigGraph *template_rigg);
-RigGraph *RIG_graphFromArmature(const struct bContext *C, struct Object *ob, struct bArmature *arm);
-int RIG_nbJoints(RigGraph *rg);
-const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index);
-void RIG_freeRigGraph(BGraph *rg);
-
-/* UNUSED */
-void BIF_retargetArmature(bContext *C);
-void BIF_adjustRetarget(bContext *C);
-/* UNUSED / print funcs */
-void RIG_printArc(struct RigGraph *rg, struct RigArc *arc);
-void RIG_printGraph(struct RigGraph *rg);
-void RIG_printArcBones(struct RigArc *arc);
-
-#endif /* __BIF_RETARGET_H__ */
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 4c394d7836a..96467ee2c2a 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
../../../../intern/eigen
../../../../intern/glew-mx
@@ -45,9 +47,6 @@ set(SRC
armature_select.c
armature_skinning.c
armature_utils.c
- editarmature_generate.c
- editarmature_retarget.c
- editarmature_sketch.c
editarmature_undo.c
meshlaplacian.c
pose_edit.c
@@ -57,13 +56,9 @@ set(SRC
pose_slide.c
pose_transform.c
pose_utils.c
- reeb.c
- BIF_generate.h
- BIF_retarget.h
armature_intern.h
meshlaplacian.h
- reeb.h
)
if(WITH_INTERNATIONAL)
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 08db73bf69d..0b39fe22e47 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -46,6 +46,7 @@
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_deform.h"
+#include "BKE_layer.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -120,19 +121,24 @@ EditBone *ED_armature_ebone_add_primitive(Object *obedit_arm, float length, bool
/* previously addvert_armature */
/* the ctrl-click method */
+
+/** Note this is already ported to multi-objects as it is.
+ * Since only the active bone is extruded even for single objects,
+ * it makes sense to stick to the active object here.
+ *
+ * If we want the support to be expanded we should something like the
+ * offset we do for mesh click extrude.
+ */
static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
{
- View3D *v3d;
bArmature *arm;
EditBone *ebone, *newbone, *flipbone;
float mat[3][3], imat[3][3];
- const float *curs;
int a, to_root = 0;
Object *obedit;
Scene *scene;
scene = CTX_data_scene(C);
- v3d = CTX_wm_view3d(C);
obedit = CTX_data_edit_object(C);
arm = obedit->data;
@@ -188,8 +194,8 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
newbone->flag |= BONE_CONNECTED;
}
- curs = ED_view3d_cursor3d_get(scene, v3d);
- copy_v3_v3(newbone->tail, curs);
+ const View3DCursor *curs = &scene->cursor;
+ copy_v3_v3(newbone->tail, curs->location);
sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]);
if (a == 1)
@@ -221,26 +227,26 @@ static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEv
Scene *scene;
ARegion *ar;
View3D *v3d;
- float *fp, tvec[3], oldcurs[3], mval_f[2];
+ float tvec[3], oldcurs[3], mval_f[2];
int retv;
scene = CTX_data_scene(C);
ar = CTX_wm_region(C);
v3d = CTX_wm_view3d(C);
- fp = ED_view3d_cursor3d_get(scene, v3d);
+ View3DCursor *cursor = &scene->cursor;
- copy_v3_v3(oldcurs, fp);
+ copy_v3_v3(oldcurs, cursor->location);
VECCOPY2D(mval_f, event->mval);
- ED_view3d_win_to_3d(v3d, ar, fp, mval_f, tvec);
- copy_v3_v3(fp, tvec);
+ ED_view3d_win_to_3d(v3d, ar, cursor->location, mval_f, tvec);
+ copy_v3_v3(cursor->location, tvec);
/* extrude to the where new cursor is and store the operation result */
retv = armature_click_extrude_exec(C, op);
/* restore previous 3d cursor position */
- copy_v3_v3(fp, oldcurs);
+ copy_v3_v3(cursor->location, oldcurs);
return retv;
}
@@ -474,118 +480,129 @@ EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editb
static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
{
- bArmature *arm;
- EditBone *ebone_iter;
- EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated bones in the edbo list */
-
- Object *obedit = CTX_data_edit_object(C);
- arm = obedit->data;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool do_flip_names = RNA_boolean_get(op->ptr, "do_flip_names");
/* cancel if nothing selected */
if (CTX_DATA_COUNT(C, selected_bones) == 0)
return OPERATOR_CANCELLED;
- const bool do_flip_names = RNA_boolean_get(op->ptr, "do_flip_names");
-
- ED_armature_edit_sync_selection(arm->edbo); // XXX why is this needed?
-
- preEditBoneDuplicate(arm->edbo);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ EditBone *ebone_iter;
+ EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated bones in the edbo list */
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ ED_armature_edit_sync_selection(arm->edbo); // XXX why is this needed?
+
+ preEditBoneDuplicate(arm->edbo);
+
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone;
+
+ ebone = ED_armature_ebone_get_mirrored(arm->edbo, ebone_iter);
+ if (ebone) {
+ ebone->flag |= BONE_SELECTED;
+ }
+ }
+ }
+ }
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ /* Find the selected bones and duplicate them as needed */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
if (EBONE_VISIBLE(arm, ebone_iter) &&
(ebone_iter->flag & BONE_SELECTED))
{
EditBone *ebone;
+ char new_bone_name_buff[MAXBONENAME];
+ char *new_bone_name = ebone_iter->name;
- ebone = ED_armature_ebone_get_mirrored(arm->edbo, ebone_iter);
- if (ebone) {
- ebone->flag |= BONE_SELECTED;
- }
- }
- }
- }
-
+ if (do_flip_names) {
+ BLI_string_flip_side_name(new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff));
- /* Find the selected bones and duplicate them as needed */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED))
- {
- EditBone *ebone;
- char new_bone_name_buff[MAXBONENAME];
- char *new_bone_name = ebone_iter->name;
+ /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings
+ * (different numbers), better keep default behavior in this case. */
+ if (ED_armature_ebone_find_name(arm->edbo, new_bone_name_buff) == NULL) {
+ new_bone_name = new_bone_name_buff;
+ }
+ }
- if (do_flip_names) {
- BLI_string_flip_side_name(new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff));
+ ebone = duplicateEditBone(ebone_iter, new_bone_name, arm->edbo, ob);
- /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings
- * (different numbers), better keep default behavior in this case. */
- if (ED_armature_ebone_find_name(arm->edbo, new_bone_name_buff) == NULL) {
- new_bone_name = new_bone_name_buff;
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
}
}
+ }
- ebone = duplicateEditBone(ebone_iter, new_bone_name, arm->edbo, obedit);
+ /* Run though the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ EditBone *ebone = ebone_iter->temp.ebone;
- if (!ebone_first_dupe) {
- ebone_first_dupe = ebone;
- }
- }
- }
+ if (!ebone_iter->parent) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ ebone->parent = NULL;
+ }
+ else if (ebone_iter->parent->temp.ebone) {
+ /* If this bone has a parent that was duplicated,
+ * Set the duplicate->parent to the curBone->parent->temp
+ */
+ ebone->parent = ebone_iter->parent->temp.ebone;
+ }
+ else {
+ /* If this bone has a parent that IS not selected,
+ * Set the duplicate->parent to the curBone->parent
+ */
+ ebone->parent = (EditBone *) ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
- /* Run though the list and fix the pointers */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED))
- {
- EditBone *ebone = ebone_iter->temp.ebone;
+ /* Update custom handle links. */
+ if (ebone_iter->bbone_prev && ebone_iter->bbone_prev->temp.ebone) {
+ ebone_iter->bbone_prev = ebone_iter->bbone_prev->temp.ebone;
+ }
+ if (ebone_iter->bbone_next && ebone_iter->bbone_next->temp.ebone) {
+ ebone_iter->bbone_next = ebone_iter->bbone_next->temp.ebone;
+ }
- if (!ebone_iter->parent) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- ebone->parent = NULL;
- }
- else if (ebone_iter->parent->temp.ebone) {
- /* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
*/
- ebone->parent = ebone_iter->parent->temp.ebone;
+ updateDuplicateSubtarget(ebone, arm->edbo, ob);
}
- else {
- /* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
- */
- ebone->parent = (EditBone *) ebone_iter->parent;
- ebone->flag &= ~BONE_CONNECTED;
- }
-
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
- */
- updateDuplicateSubtarget(ebone, arm->edbo, obedit);
}
- }
- /* correct the active bone */
- if (arm->act_edbone && arm->act_edbone->temp.ebone) {
- arm->act_edbone = arm->act_edbone->temp.ebone;
- }
+ /* correct the active bone */
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
+ }
- /* Deselect the old bones and select the new ones */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter)) {
- ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
}
- }
- postEditBoneDuplicate(arm->edbo, obedit);
+ postEditBoneDuplicate(arm->edbo, ob);
- ED_armature_edit_validate_active(arm);
+ ED_armature_edit_validate_active(arm);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -616,179 +633,200 @@ void ARMATURE_OT_duplicate(wmOperatorType *ot)
*/
static int armature_symmetrize_exec(bContext *C, wmOperator *op)
{
- bArmature *arm;
- EditBone *ebone_iter;
- EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated mirrored bones in the edbo list */
-
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const int direction = RNA_enum_get(op->ptr, "direction");
const int axis = 0;
- arm = obedit->data;
-
/* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ if (CTX_DATA_COUNT(C, selected_bones) == 0) {
return OPERATOR_CANCELLED;
+ }
- ED_armature_edit_sync_selection(arm->edbo); // XXX why is this needed?
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
- preEditBoneDuplicate(arm->edbo);
+ EditBone *ebone_iter;
+ EditBone *ebone_first_dupe = NULL; /* The beginning of the duplicated mirrored bones in the edbo list */
- /* Select mirrored bones */
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED))
- {
- char name_flip[MAXBONENAME];
+ ED_armature_edit_sync_selection(arm->edbo); // XXX why is this needed?
- BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
+ preEditBoneDuplicate(arm->edbo);
- if (STREQ(name_flip, ebone_iter->name)) {
- /* if the name matches, we don't have the potential to be mirrored, just skip */
- ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip);
+ /* Select mirrored bones */
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED))
+ {
+ char name_flip[MAXBONENAME];
- if (ebone) {
- if ((ebone->flag & BONE_SELECTED) == 0) {
- /* simple case, we're selected, the other bone isn't! */
- ebone_iter->temp.ebone = ebone;
- }
- else {
- /* complicated - choose which direction to copy */
- float axis_delta;
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
- axis_delta = ebone->head[axis] - ebone_iter->head[axis];
- if (axis_delta == 0.0f) {
- axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
- }
+ if (STREQ(name_flip, ebone_iter->name)) {
+ /* if the name matches, we don't have the potential to be mirrored, just skip */
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, name_flip);
- if (axis_delta == 0.0f) {
- /* both mirrored bones exist and point to eachother and overlap exactly.
- *
- * in this case there's no well defined solution, so de-select both and skip.
- */
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (ebone) {
+ if ((ebone->flag & BONE_SELECTED) == 0) {
+ /* simple case, we're selected, the other bone isn't! */
+ ebone_iter->temp.ebone = ebone;
}
else {
- EditBone *ebone_src, *ebone_dst;
- if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
- ebone_src = ebone;
- ebone_dst = ebone_iter;
+ /* complicated - choose which direction to copy */
+ float axis_delta;
+
+ axis_delta = ebone->head[axis] - ebone_iter->head[axis];
+ if (axis_delta == 0.0f) {
+ axis_delta = ebone->tail[axis] - ebone_iter->tail[axis];
}
- else {
- ebone_src = ebone_iter;
- ebone_dst = ebone;
+
+ if (axis_delta == 0.0f) {
+ /* both mirrored bones exist and point to eachother and overlap exactly.
+ *
+ * in this case there's no well defined solution, so de-select both and skip.
+ */
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
+ else {
+ EditBone *ebone_src, *ebone_dst;
+ if (((axis_delta < 0.0f) ? -1 : 1) == direction) {
+ ebone_src = ebone;
+ ebone_dst = ebone_iter;
+ }
+ else {
+ ebone_src = ebone_iter;
+ ebone_dst = ebone;
+ }
- ebone_src->temp.ebone = ebone_dst;
- ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone_src->temp.ebone = ebone_dst;
+ ebone_dst->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
}
}
}
}
}
- }
- /* Find the selected bones and duplicate them as needed, with mirrored name */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) &&
- (ebone_iter->flag & BONE_SELECTED) &&
- /* will be set if the mirror bone already exists (no need to make a new one) */
- (ebone_iter->temp.ebone == NULL))
- {
- char name_flip[MAXBONENAME];
+ /* Find the selected bones and duplicate them as needed, with mirrored name */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (EBONE_VISIBLE(arm, ebone_iter) &&
+ (ebone_iter->flag & BONE_SELECTED) &&
+ /* will be set if the mirror bone already exists (no need to make a new one) */
+ (ebone_iter->temp.ebone == NULL))
+ {
+ char name_flip[MAXBONENAME];
- BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
+ BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
- /* bones must have a side-suffix */
- if (!STREQ(name_flip, ebone_iter->name)) {
- EditBone *ebone;
+ /* bones must have a side-suffix */
+ if (!STREQ(name_flip, ebone_iter->name)) {
+ EditBone *ebone;
- ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit);
+ ebone = duplicateEditBone(ebone_iter, name_flip, arm->edbo, obedit);
- if (!ebone_first_dupe) {
- ebone_first_dupe = ebone;
+ if (!ebone_first_dupe) {
+ ebone_first_dupe = ebone;
+ }
}
}
}
- }
- /* Run through the list and fix the pointers */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (ebone_iter->temp.ebone) {
- /* copy all flags except for ... */
- const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ /* Run through the list and fix the pointers */
+ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
+ if (ebone_iter->temp.ebone) {
+ /* copy all flags except for ... */
+ const int flag_copy = ((int)~0) & ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- EditBone *ebone = ebone_iter->temp.ebone;
+ EditBone *ebone = ebone_iter->temp.ebone;
- /* copy flags incase bone is pre-existing data */
- ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);
+ /* copy flags incase bone is pre-existing data */
+ ebone->flag = (ebone->flag & ~flag_copy) | (ebone_iter->flag & flag_copy);
- if (ebone_iter->parent == NULL) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- ebone->parent = NULL;
- ebone->flag &= ~BONE_CONNECTED;
- }
- else {
- /* the parent may have been duplicated, if not lookup the mirror parent */
- EditBone *ebone_parent =
- (ebone_iter->parent->temp.ebone ?
- ebone_iter->parent->temp.ebone : ED_armature_ebone_get_mirrored(arm->edbo, ebone_iter->parent));
-
- if (ebone_parent == NULL) {
- /* If the mirror lookup failed, (but the current bone has a parent)
- * then we can assume the parent has no L/R but is a center bone.
- * So just use the same parent for both.
+ if (ebone_iter->parent == NULL) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
*/
- ebone_parent = ebone_iter->parent;
+ ebone->parent = NULL;
ebone->flag &= ~BONE_CONNECTED;
}
+ else {
+ /* the parent may have been duplicated, if not lookup the mirror parent */
+ EditBone *ebone_parent = (
+ ebone_iter->parent->temp.ebone ?
+ ebone_iter->parent->temp.ebone :
+ ED_armature_ebone_get_mirrored(arm->edbo, ebone_iter->parent));
+
+ if (ebone_parent == NULL) {
+ /* If the mirror lookup failed, (but the current bone has a parent)
+ * then we can assume the parent has no L/R but is a center bone.
+ * So just use the same parent for both.
+ */
+ ebone_parent = ebone_iter->parent;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
- ebone->parent = ebone_parent;
- }
+ ebone->parent = ebone_parent;
+ }
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
- */
- updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ /* Update custom handle links. */
+ if (ebone_iter->bbone_prev && ebone_iter->bbone_prev->temp.ebone) {
+ ebone_iter->bbone_prev = ebone_iter->bbone_prev->temp.ebone;
+ }
+ if (ebone_iter->bbone_next && ebone_iter->bbone_next->temp.ebone) {
+ ebone_iter->bbone_next = ebone_iter->bbone_next->temp.ebone;
+ }
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ }
}
- }
- ED_armature_edit_transform_mirror_update(obedit);
+ ED_armature_edit_transform_mirror_update(obedit);
- /* Selected bones now have their 'temp' pointer set,
- * so we don't need this anymore */
+ /* Selected bones now have their 'temp' pointer set,
+ * so we don't need this anymore */
- /* Deselect the old bones and select the new ones */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter)) {
- ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ /* Deselect the old bones and select the new ones */
+ for (ebone_iter = arm->edbo->first;
+ ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next)
+ {
+ if (EBONE_VISIBLE(arm, ebone_iter)) {
+ ebone_iter->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
}
- }
- /* New bones will be selected, but some of the bones may already exist */
- for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) {
- EditBone *ebone = ebone_iter->temp.ebone;
- if (ebone && EBONE_SELECTABLE(arm, ebone)) {
- ED_armature_ebone_select_set(ebone, true);
+ /* New bones will be selected, but some of the bones may already exist */
+ for (ebone_iter = arm->edbo->first;
+ ebone_iter && ebone_iter != ebone_first_dupe;
+ ebone_iter = ebone_iter->next)
+ {
+ EditBone *ebone = ebone_iter->temp.ebone;
+ if (ebone && EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_select_set(ebone, true);
+ }
}
- }
- /* correct the active bone */
- if (arm->act_edbone && arm->act_edbone->temp.ebone) {
- arm->act_edbone = arm->act_edbone->temp.ebone;
- }
+ /* correct the active bone */
+ if (arm->act_edbone && arm->act_edbone->temp.ebone) {
+ arm->act_edbone = arm->act_edbone->temp.ebone;
+ }
- postEditBoneDuplicate(arm->edbo, obedit);
+ postEditBoneDuplicate(arm->edbo, obedit);
- ED_armature_edit_validate_active(arm);
+ ED_armature_edit_validate_active(arm);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -827,158 +865,168 @@ void ARMATURE_OT_symmetrize(wmOperatorType *ot)
/* if forked && mirror-edit: makes two bones with flipped names */
static int armature_extrude_exec(bContext *C, wmOperator *op)
{
- Object *obedit;
- bArmature *arm;
- EditBone *newbone, *ebone, *flipbone, *first = NULL;
- int a, totbone = 0, do_extrude;
- bool forked = RNA_boolean_get(op->ptr, "forked");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool forked = RNA_boolean_get(op->ptr, "forked");
+ bool changed_multi = false;
- obedit = CTX_data_edit_object(C);
- arm = obedit->data;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool forked_iter = forked;
- /* since we allow root extrude too, we have to make sure selection is OK */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_ROOTSEL) {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- if (ebone->parent->flag & BONE_TIPSEL)
- ebone->flag &= ~BONE_ROOTSEL;
+ EditBone *newbone = NULL, *ebone, *flipbone, *first = NULL;
+ int a, totbone = 0, do_extrude;
+
+ /* since we allow root extrude too, we have to make sure selection is OK */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_ROOTSEL) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ if (ebone->parent->flag & BONE_TIPSEL)
+ ebone->flag &= ~BONE_ROOTSEL;
+ }
}
}
}
- }
- /* Duplicate the necessary bones */
- for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- /* we extrude per definition the tip */
- do_extrude = false;
- if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
- do_extrude = true;
- }
- else if (ebone->flag & BONE_ROOTSEL) {
- /* but, a bone with parent deselected we do the root... */
- if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
- /* pass */
- }
- else {
- do_extrude = 2;
+ /* Duplicate the necessary bones */
+ for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ /* we extrude per definition the tip */
+ do_extrude = false;
+ if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
+ do_extrude = true;
}
- }
-
- if (do_extrude) {
- /* we re-use code for mirror editing... */
- flipbone = NULL;
- if (arm->flag & ARM_MIRROR_EDIT) {
- flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if (flipbone) {
- forked = 0; // we extrude 2 different bones
- if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
- /* don't want this bone to be selected... */
- flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ else if (ebone->flag & BONE_ROOTSEL) {
+ /* but, a bone with parent deselected we do the root... */
+ if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
+ /* pass */
+ }
+ else {
+ do_extrude = 2;
}
- if ((flipbone == NULL) && (forked))
- flipbone = ebone;
}
- for (a = 0; a < 2; a++) {
- if (a == 1) {
- if (flipbone == NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
+ if (do_extrude) {
+ /* we re-use code for mirror editing... */
+ flipbone = NULL;
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if (flipbone) {
+ forked_iter = 0; // we extrude 2 different bones
+ if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
+ /* don't want this bone to be selected... */
+ flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
}
+ if ((flipbone == NULL) && (forked_iter))
+ flipbone = ebone;
}
- totbone++;
- newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
+ for (a = 0; a < 2; a++) {
+ if (a == 1) {
+ if (flipbone == NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
- if (do_extrude == true) {
- copy_v3_v3(newbone->head, ebone->tail);
- copy_v3_v3(newbone->tail, newbone->head);
- newbone->parent = ebone;
+ totbone++;
+ newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
- newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING); // copies it, in case mirrored bone
+ if (do_extrude == true) {
+ copy_v3_v3(newbone->head, ebone->tail);
+ copy_v3_v3(newbone->tail, newbone->head);
+ newbone->parent = ebone;
- if (newbone->parent) newbone->flag |= BONE_CONNECTED;
- }
- else {
- copy_v3_v3(newbone->head, ebone->head);
- copy_v3_v3(newbone->tail, ebone->head);
- newbone->parent = ebone->parent;
+ /* copies it, in case mirrored bone */
+ newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING);
+
+ if (newbone->parent) newbone->flag |= BONE_CONNECTED;
+ }
+ else {
+ copy_v3_v3(newbone->head, ebone->head);
+ copy_v3_v3(newbone->tail, ebone->head);
+ newbone->parent = ebone->parent;
- newbone->flag = BONE_TIPSEL;
+ newbone->flag = BONE_TIPSEL;
- if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
- newbone->flag |= BONE_CONNECTED;
+ if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
+ newbone->flag |= BONE_CONNECTED;
+ }
}
- }
- newbone->weight = ebone->weight;
- newbone->dist = ebone->dist;
- newbone->xwidth = ebone->xwidth;
- newbone->zwidth = ebone->zwidth;
- newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
- newbone->rad_tail = ebone->rad_tail;
- newbone->segments = 1;
- newbone->layer = ebone->layer;
-
- /* Bendy-Bone parameters */
- newbone->roll1 = ebone->roll1;
- newbone->roll2 = ebone->roll2;
- newbone->curveInX = ebone->curveInX;
- newbone->curveInY = ebone->curveInY;
- newbone->curveOutX = ebone->curveOutX;
- newbone->curveOutY = ebone->curveOutY;
- newbone->ease1 = ebone->ease1;
- newbone->ease2 = ebone->ease2;
- newbone->scaleIn = ebone->scaleIn;
- newbone->scaleOut = ebone->scaleOut;
-
-
- BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
-
- if (flipbone && forked) { // only set if mirror edit
- if (strlen(newbone->name) < (MAXBONENAME - 2)) {
- if (a == 0) strcat(newbone->name, "_L");
- else strcat(newbone->name, "_R");
+ newbone->weight = ebone->weight;
+ newbone->dist = ebone->dist;
+ newbone->xwidth = ebone->xwidth;
+ newbone->zwidth = ebone->zwidth;
+ newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
+ newbone->rad_tail = ebone->rad_tail;
+ newbone->segments = 1;
+ newbone->layer = ebone->layer;
+
+ /* Bendy-Bone parameters */
+ newbone->roll1 = ebone->roll1;
+ newbone->roll2 = ebone->roll2;
+ newbone->curveInX = ebone->curveInX;
+ newbone->curveInY = ebone->curveInY;
+ newbone->curveOutX = ebone->curveOutX;
+ newbone->curveOutY = ebone->curveOutY;
+ newbone->ease1 = ebone->ease1;
+ newbone->ease2 = ebone->ease2;
+ newbone->scaleIn = ebone->scaleIn;
+ newbone->scaleOut = ebone->scaleOut;
+
+
+ BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
+
+ if (flipbone && forked_iter) { // only set if mirror edit
+ if (strlen(newbone->name) < (MAXBONENAME - 2)) {
+ if (a == 0) strcat(newbone->name, "_L");
+ else strcat(newbone->name, "_R");
+ }
}
- }
- ED_armature_ebone_unique_name(arm->edbo, newbone->name, NULL);
+ ED_armature_ebone_unique_name(arm->edbo, newbone->name, NULL);
- /* Add the new bone to the list */
- BLI_addtail(arm->edbo, newbone);
- if (!first)
- first = newbone;
+ /* Add the new bone to the list */
+ BLI_addtail(arm->edbo, newbone);
+ if (!first)
+ first = newbone;
- /* restore ebone if we were flipping */
- if (a == 1 && flipbone)
- SWAP(EditBone *, flipbone, ebone);
+ /* restore ebone if we were flipping */
+ if (a == 1 && flipbone)
+ SWAP(EditBone *, flipbone, ebone);
+ }
}
+
+ /* Deselect the old bone */
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
}
+ }
+ /* if only one bone, make this one active */
+ if (totbone == 1 && first) {
+ arm->act_edbone = first;
+ }
+ else {
+ arm->act_edbone = newbone;
+ }
- /* Deselect the old bone */
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ if (totbone == 0) {
+ continue;
}
- }
- /* if only one bone, make this one active */
- if (totbone == 1 && first) {
- arm->act_edbone = first;
- }
- else {
- arm->act_edbone = newbone;
- }
- if (totbone == 0) {
- return OPERATOR_CANCELLED;
- }
+ changed_multi = true;
- /* Transform the endpoints */
- ED_armature_edit_sync_selection(arm->edbo);
+ /* Transform the endpoints */
+ ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void ARMATURE_OT_extrude(wmOperatorType *ot)
@@ -1013,7 +1061,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "name", name);
- copy_v3_v3(curs, ED_view3d_cursor3d_get(CTX_data_scene(C), CTX_wm_view3d(C)));
+ copy_v3_v3(curs, CTX_data_scene(C)->cursor.location);
/* Get inverse point for head and orientation for tail */
invert_m4_m4(obedit->imat, obedit->obmat);
@@ -1074,7 +1122,6 @@ void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
static int armature_subdivide_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
EditBone *newbone, *tbone;
int cuts, i;
@@ -1083,7 +1130,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op)
/* loop over all editable bones */
// XXX the old code did this in reverse order though!
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
{
for (i = cuts + 1; i > 1; i--) {
/* compute cut ratio first */
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 67ce05ceb99..f19fea32698 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -48,9 +48,11 @@
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_object.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -139,17 +141,16 @@ void ED_armature_transform(Main *bmain, bArmature *arm, float mat[4][4], const b
/* exported for use in editors/object/ */
/* 0 == do center, 1 == center new, 2 == center cursor */
-void ED_armature_origin_set(Main *bmain, Scene *scene, Object *ob, float cursor[3], int centermode, int around)
+void ED_armature_origin_set(Main *bmain, Object *ob, float cursor[3], int centermode, int around)
{
- Object *obedit = scene->obedit; // XXX get from context
+ const bool is_editmode = BKE_object_is_in_editmode(ob);
EditBone *ebone;
bArmature *arm = ob->data;
float cent[3];
/* Put the armature into editmode */
- if (ob != obedit) {
+ if (is_editmode == false) {
ED_armature_to_edit(arm);
- obedit = NULL; /* we cant use this so behave as if there is no obedit */
}
/* Find the centerpoint */
@@ -189,13 +190,13 @@ void ED_armature_origin_set(Main *bmain, Scene *scene, Object *ob, float cursor[
}
/* Turn the list into an armature */
- if (obedit == NULL) {
+ if (is_editmode == false) {
ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
}
/* Adjust object location for new centerpoint */
- if (centermode && obedit == NULL) {
+ if (centermode && (is_editmode == false)) {
mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
add_v3_v3(ob->loc, cent);
}
@@ -294,153 +295,171 @@ static const EnumPropertyItem prop_calc_roll_types[] = {
static int armature_calc_roll_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_edit_object(C);
+ int ret = OPERATOR_FINISHED;
+
eCalcRollTypes type = RNA_enum_get(op->ptr, "type");
const bool axis_only = RNA_boolean_get(op->ptr, "axis_only");
/* axis_flip when matching the active bone never makes sense */
bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") :
(type >= CALC_ROLL_TAN_NEG_X) ? true : false);
- float imat[3][3];
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
- bArmature *arm = ob->data;
- EditBone *ebone;
+ float imat[3][3];
+ EditBone *ebone;
- if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
- type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
- axis_flip = true;
- }
-
- copy_m3_m4(imat, ob->obmat);
- invert_m3(imat);
+ if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
+ type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
+ axis_flip = true;
+ }
- if (type == CALC_ROLL_CURSOR) { /* Cursor */
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
- float cursor_local[3];
- const float *cursor = ED_view3d_cursor3d_get(scene, v3d);
+ copy_m3_m4(imat, ob->obmat);
+ invert_m3(imat);
- invert_m4_m4(ob->imat, ob->obmat);
- copy_v3_v3(cursor_local, cursor);
- mul_m4_v3(ob->imat, cursor_local);
+ if (type == CALC_ROLL_CURSOR) { /* Cursor */
+ Scene *scene = CTX_data_scene(C);
+ float cursor_local[3];
+ const View3DCursor *cursor = &scene->cursor;
+ invert_m4_m4(ob->imat, ob->obmat);
+ copy_v3_v3(cursor_local, cursor->location);
+ mul_m4_v3(ob->imat, cursor_local);
- /* cursor */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- float cursor_rel[3];
- sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
- if (axis_flip) negate_v3(cursor_rel);
- if (normalize_v3(cursor_rel) != 0.0f) {
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, cursor_rel, axis_only);
+ /* cursor */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ float cursor_rel[3];
+ sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
+ if (axis_flip) negate_v3(cursor_rel);
+ if (normalize_v3(cursor_rel) != 0.0f) {
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, cursor_rel, axis_only);
+ changed = true;
+ }
}
}
}
- }
- else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent) {
- bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
- bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) && EBONE_EDITABLE(ebone->parent));
-
- if (is_edit || is_edit_parent) {
- EditBone *ebone_other = ebone->parent;
- float dir_a[3];
- float dir_b[3];
- float vec[3];
- bool is_vec_zero;
-
- sub_v3_v3v3(dir_a, ebone->tail, ebone->head);
- normalize_v3(dir_a);
-
- /* find the first bone in the chane with a different direction */
- do {
- sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
- normalize_v3(dir_b);
-
- if (type == CALC_ROLL_TAN_POS_Z) {
- cross_v3_v3v3(vec, dir_a, dir_b);
- }
- else {
- add_v3_v3v3(vec, dir_a, dir_b);
- }
- } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) &&
- (ebone_other = ebone_other->parent));
+ else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent) {
+ bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
+ bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) && EBONE_EDITABLE(ebone->parent));
+
+ if (is_edit || is_edit_parent) {
+ EditBone *ebone_other = ebone->parent;
+ float dir_a[3];
+ float dir_b[3];
+ float vec[3];
+ bool is_vec_zero;
+
+ sub_v3_v3v3(dir_a, ebone->tail, ebone->head);
+ normalize_v3(dir_a);
+
+ /* find the first bone in the chane with a different direction */
+ do {
+ sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
+ normalize_v3(dir_b);
+
+ if (type == CALC_ROLL_TAN_POS_Z) {
+ cross_v3_v3v3(vec, dir_a, dir_b);
+ }
+ else {
+ add_v3_v3v3(vec, dir_a, dir_b);
+ }
+ } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) &&
+ (ebone_other = ebone_other->parent));
- if (!is_vec_zero) {
- if (axis_flip) negate_v3(vec);
+ if (!is_vec_zero) {
+ if (axis_flip) negate_v3(vec);
- if (is_edit) {
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
- }
+ if (is_edit) {
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
+ changed = true;
+ }
- /* parentless bones use cross product with child */
- if (is_edit_parent) {
- if (ebone->parent->parent == NULL) {
- ebone->parent->roll = ED_armature_ebone_roll_to_vector(ebone->parent, vec, axis_only);
+ /* parentless bones use cross product with child */
+ if (is_edit_parent) {
+ if (ebone->parent->parent == NULL) {
+ ebone->parent->roll = ED_armature_ebone_roll_to_vector(ebone->parent, vec, axis_only);
+ changed = true;
+ }
}
}
}
}
}
}
- }
- else {
- float vec[3] = {0.0f, 0.0f, 0.0f};
- if (type == CALC_ROLL_VIEW) { /* View */
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No region view3d available");
- return OPERATOR_CANCELLED;
- }
+ else {
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ if (type == CALC_ROLL_VIEW) { /* View */
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No region view3d available");
+ ret = OPERATOR_CANCELLED;
+ goto cleanup;
+ }
- copy_v3_v3(vec, rv3d->viewinv[2]);
- mul_m3_v3(imat, vec);
- }
- else if (type == CALC_ROLL_ACTIVE) {
- float mat[3][3];
- ebone = (EditBone *)arm->act_edbone;
- if (ebone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active bone set");
- return OPERATOR_CANCELLED;
+ copy_v3_v3(vec, rv3d->viewinv[2]);
+ mul_m3_v3(imat, vec);
}
+ else if (type == CALC_ROLL_ACTIVE) {
+ float mat[3][3];
+ bArmature *arm_active = ob_active->data;
+ ebone = (EditBone *)arm_active->act_edbone;
+ if (ebone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active bone set");
+ ret = OPERATOR_CANCELLED;
+ goto cleanup;
+ }
- ED_armature_ebone_to_mat3(ebone, mat);
- copy_v3_v3(vec, mat[2]);
- }
- else { /* Axis */
- assert(type <= 5);
- if (type < 3) vec[type] = 1.0f;
- else vec[type - 2] = -1.0f;
- mul_m3_v3(imat, vec);
- normalize_v3(vec);
- }
+ ED_armature_ebone_to_mat3(ebone, mat);
+ copy_v3_v3(vec, mat[2]);
+ }
+ else { /* Axis */
+ assert(type <= 5);
+ if (type < 3) vec[type] = 1.0f;
+ else vec[type - 2] = -1.0f;
+ mul_m3_v3(imat, vec);
+ normalize_v3(vec);
+ }
- if (axis_flip) negate_v3(vec);
+ if (axis_flip) negate_v3(vec);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- /* roll func is a callback which assumes that all is well */
- ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ /* roll func is a callback which assumes that all is well */
+ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only);
+ changed = true;
+ }
}
}
- }
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
- EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
- ebone->roll = -ebone_mirr->roll;
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
+ EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
+ ebone->roll = -ebone_mirr->roll;
+ }
}
}
}
- }
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ if (changed) {
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
- return OPERATOR_FINISHED;
+cleanup:
+ MEM_freeN(objects);
+ return ret;
}
void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
@@ -466,33 +485,42 @@ void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
static int armature_roll_clear_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
-
- bArmature *arm = ob->data;
- EditBone *ebone;
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const float roll = RNA_float_get(op->ptr, "roll");
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- /* roll func is a callback which assumes that all is well */
- ebone->roll = roll;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ /* Roll func is a callback which assumes that all is well. */
+ ebone->roll = roll;
+ changed = true;
+ }
}
- }
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
- EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
- if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
- ebone->roll = -ebone_mirr->roll;
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
+ EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
+ ebone->roll = -ebone_mirr->roll;
+ changed = true;
+ }
}
}
}
- }
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ if (changed) {
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -631,25 +659,33 @@ static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
/* bone adding between selected joints */
static int armature_fill_bones_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = (obedit) ? obedit->data : NULL;
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ListBase points = {NULL, NULL};
EditBone *newbone = NULL;
int count;
-
- /* sanity checks */
- if (ELEM(NULL, obedit, arm))
- return OPERATOR_CANCELLED;
+ bool mixed_object_error = false;
/* loop over all bones, and only consider if visible */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ bArmature *arm = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, EditBone *, ebone, visible_bones, bArmature *, arm_iter)
{
- if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
+ bool check = false;
+ if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) {
fill_add_joint(ebone, 0, &points);
- if (ebone->flag & BONE_TIPSEL)
+ check = true;
+ }
+ if (ebone->flag & BONE_TIPSEL) {
fill_add_joint(ebone, 1, &points);
+ check = true;
+ }
+
+ if (check) {
+ if (arm && (arm != arm_iter)) {
+ mixed_object_error = true;
+ }
+ arm = arm_iter;
+ }
}
CTX_DATA_END;
@@ -664,7 +700,25 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No joints selected");
return OPERATOR_CANCELLED;
}
- else if (count == 1) {
+ else if (mixed_object_error) {
+ BKE_report(op->reports, RPT_ERROR, "Bones for different objects selected");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *obedit = NULL;
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_EDIT, ob_iter) {
+ if (ob_iter->data == arm) {
+ obedit = ob_iter;
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+ }
+ BLI_assert(obedit != NULL);
+
+ if (count == 1) {
EditBonePoint *ebp;
float curs[3];
@@ -673,7 +727,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
/* Get points - cursor (tail) */
invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
+ mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
/* Create a bone */
newbone = add_points_bone(obedit, ebp->vec, curs);
@@ -711,7 +765,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
/* get cursor location */
invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
+ mul_v3_m4v3(curs, obedit->imat, scene->cursor.location);
/* get distances */
dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
@@ -765,7 +819,6 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op)
}
}
else {
- /* FIXME.. figure out a method for multiple bones */
BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
BLI_freelistN(&points);
return OPERATOR_CANCELLED;
@@ -890,78 +943,84 @@ static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone
static int armature_merge_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = (obedit) ? obedit->data : NULL;
- short type = RNA_enum_get(op->ptr, "type");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const short type = RNA_enum_get(op->ptr, "type");
- /* sanity checks */
- if (ELEM(NULL, obedit, arm))
- return OPERATOR_CANCELLED;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* for now, there's only really one type of merging that's performed... */
- if (type == 1) {
- /* go down chains, merging bones */
- ListBase chains = {NULL, NULL};
- LinkData *chain, *nchain;
- EditBone *ebo;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
- armature_tag_select_mirrored(arm);
+ /* for now, there's only really one type of merging that's performed... */
+ if (type == 1) {
+ /* go down chains, merging bones */
+ ListBase chains = {NULL, NULL};
+ LinkData *chain, *nchain;
+ EditBone *ebo;
- /* get chains (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (BLI_listbase_is_empty(&chains)) return OPERATOR_CANCELLED;
-
- /* each 'chain' is the last bone in the chain (with no children) */
- for (chain = chains.first; chain; chain = nchain) {
- EditBone *bstart = NULL, *bend = NULL;
- EditBone *bchild = NULL, *child = NULL;
-
- /* temporarily remove chain from list of chains */
- nchain = chain->next;
- BLI_remlink(&chains, chain);
-
- /* only consider bones that are visible and selected */
- for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
- /* check if visible + selected */
- if (EBONE_VISIBLE(arm, ebo) &&
- ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
- (ebo->flag & BONE_SELECTED) )
- {
- /* set either end or start (end gets priority, unless it is already set) */
- if (bend == NULL) {
- bend = ebo;
- bchild = child;
+ armature_tag_select_mirrored(arm);
+
+ /* get chains (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (BLI_listbase_is_empty(&chains)) {
+ continue;
+ }
+
+ /* each 'chain' is the last bone in the chain (with no children) */
+ for (chain = chains.first; chain; chain = nchain) {
+ EditBone *bstart = NULL, *bend = NULL;
+ EditBone *bchild = NULL, *child = NULL;
+
+ /* temporarily remove chain from list of chains */
+ nchain = chain->next;
+ BLI_remlink(&chains, chain);
+
+ /* only consider bones that are visible and selected */
+ for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
+ /* check if visible + selected */
+ if (EBONE_VISIBLE(arm, ebo) &&
+ ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
+ (ebo->flag & BONE_SELECTED) )
+ {
+ /* set either end or start (end gets priority, unless it is already set) */
+ if (bend == NULL) {
+ bend = ebo;
+ bchild = child;
+ }
+ else
+ bstart = ebo;
+ }
+ else {
+ /* chain is broken... merge any continuous segments then clear */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ bstart = NULL;
+ bend = NULL;
+ bchild = NULL;
}
- else
- bstart = ebo;
}
- else {
- /* chain is broken... merge any continuous segments then clear */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
- bstart = NULL;
- bend = NULL;
- bchild = NULL;
- }
+ /* merge from bstart to bend if something not merged */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ /* put back link */
+ BLI_insertlinkbefore(&chains, nchain, chain);
}
- /* merge from bstart to bend if something not merged */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
+ armature_tag_unselect(arm);
- /* put back link */
- BLI_insertlinkbefore(&chains, nchain, chain);
+ BLI_freelistN(&chains);
}
- armature_tag_unselect(arm);
-
- BLI_freelistN(&chains);
+ /* updates */
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
}
-
- /* updates */
- ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1010,89 +1069,99 @@ static void armature_clear_swap_done_flags(bArmature *arm)
static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- ListBase chains = {NULL, NULL};
- LinkData *chain;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* get chains of bones (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (BLI_listbase_is_empty(&chains)) return OPERATOR_CANCELLED;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
- /* ensure that mirror bones will also be operated on */
- armature_tag_select_mirrored(arm);
+ ListBase chains = {NULL, NULL};
+ LinkData *chain;
- /* clear BONE_TRANSFORM flags
- * - used to prevent duplicate/canceling operations from occurring [#34123]
- * - BONE_DONE cannot be used here as that's already used for mirroring
- */
- armature_clear_swap_done_flags(arm);
+ /* get chains of bones (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (BLI_listbase_is_empty(&chains)) {
+ continue;
+ }
- /* loop over chains, only considering selected and visible bones */
- for (chain = chains.first; chain; chain = chain->next) {
- EditBone *ebo, *child = NULL, *parent = NULL;
+ /* ensure that mirror bones will also be operated on */
+ armature_tag_select_mirrored(arm);
- /* loop over bones in chain */
- for (ebo = chain->data; ebo; ebo = parent) {
- /* parent is this bone's original parent
- * - we store this, as the next bone that is checked is this one
- * but the value of ebo->parent may change here...
- */
- parent = ebo->parent;
-
- /* skip bone if already handled... [#34123] */
- if ((ebo->flag & BONE_TRANSFORM) == 0) {
- /* only if selected and editable */
- if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
- /* swap head and tail coordinates */
- swap_v3_v3(ebo->head, ebo->tail);
-
- /* do parent swapping:
- * - use 'child' as new parent
- * - connected flag is only set if points are coincidental
- */
- ebo->parent = child;
- if ((child) && equals_v3v3(ebo->head, child->tail))
- ebo->flag |= BONE_CONNECTED;
- else
- ebo->flag &= ~BONE_CONNECTED;
-
- /* get next bones
- * - child will become the new parent of next bone
- */
- child = ebo;
- }
- else {
- /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
- * as it will be facing in opposite direction
- */
- if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
- ebo->parent = NULL;
- ebo->flag &= ~BONE_CONNECTED;
+ /* clear BONE_TRANSFORM flags
+ * - used to prevent duplicate/canceling operations from occurring [#34123]
+ * - BONE_DONE cannot be used here as that's already used for mirroring
+ */
+ armature_clear_swap_done_flags(arm);
+
+ /* loop over chains, only considering selected and visible bones */
+ for (chain = chains.first; chain; chain = chain->next) {
+ EditBone *ebo, *child = NULL, *parent = NULL;
+
+ /* loop over bones in chain */
+ for (ebo = chain->data; ebo; ebo = parent) {
+ /* parent is this bone's original parent
+ * - we store this, as the next bone that is checked is this one
+ * but the value of ebo->parent may change here...
+ */
+ parent = ebo->parent;
+
+ /* skip bone if already handled... [#34123] */
+ if ((ebo->flag & BONE_TRANSFORM) == 0) {
+ /* only if selected and editable */
+ if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
+ /* swap head and tail coordinates */
+ swap_v3_v3(ebo->head, ebo->tail);
+
+ /* do parent swapping:
+ * - use 'child' as new parent
+ * - connected flag is only set if points are coincidental
+ */
+ ebo->parent = child;
+ if ((child) && equals_v3v3(ebo->head, child->tail))
+ ebo->flag |= BONE_CONNECTED;
+ else
+ ebo->flag &= ~BONE_CONNECTED;
+
+ /* get next bones
+ * - child will become the new parent of next bone
+ */
+ child = ebo;
}
+ else {
+ /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
+ * as it will be facing in opposite direction
+ */
+ if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
+ ebo->parent = NULL;
+ ebo->flag &= ~BONE_CONNECTED;
+ }
- /* get next bones
- * - child will become new parent of next bone (not swapping occurred,
- * so set to NULL to prevent infinite-loop)
- */
- child = NULL;
- }
+ /* get next bones
+ * - child will become new parent of next bone (not swapping occurred,
+ * so set to NULL to prevent infinite-loop)
+ */
+ child = NULL;
+ }
- /* tag as done (to prevent double-swaps) */
- ebo->flag |= BONE_TRANSFORM;
+ /* tag as done (to prevent double-swaps) */
+ ebo->flag |= BONE_TRANSFORM;
+ }
}
}
- }
- /* free chains */
- BLI_freelistN(&chains);
+ /* free chains */
+ BLI_freelistN(&chains);
- /* clear temp flags */
- armature_clear_swap_done_flags(arm);
- armature_tag_unselect(arm);
+ /* clear temp flags */
+ armature_clear_swap_done_flags(arm);
+ armature_tag_unselect(arm);
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1253,22 +1322,28 @@ void ARMATURE_OT_align(wmOperatorType *ot)
static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- EditBone *bone;
-
- for (bone = arm->edbo->first; bone; bone = bone->next) {
- if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
- bone->parent = NULL;
- bone->flag &= ~BONE_CONNECTED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
+ bone->parent = NULL;
+ bone->flag &= ~BONE_CONNECTED;
+ }
+ }
+ for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
}
- }
- for (bone = arm->edbo->first; bone; bone = bone->next) {
- ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
- }
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1302,38 +1377,50 @@ static bool armature_delete_ebone_cb(const char *bone_name, void *arm_p)
/* only editmode! */
static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
- bArmature *arm;
EditBone *curBone, *ebone_next;
- Object *obedit = CTX_data_edit_object(C);
- bool changed = false;
- arm = obedit->data;
+ bool changed_multi = false;
/* cancel if nothing selected */
if (CTX_DATA_COUNT(C, selected_bones) == 0)
return OPERATOR_CANCELLED;
- armature_select_mirrored(arm);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ armature_select_mirrored(arm);
+
+ BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
+
+ for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
+ ebone_next = curBone->next;
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED) {
+ if (curBone == arm->act_edbone) arm->act_edbone = NULL;
+ ED_armature_ebone_remove(arm, curBone);
+ changed = true;
+ }
+ }
+ }
- BKE_pose_channels_remove(obedit, armature_delete_ebone_cb, arm);
+ if (changed) {
+ changed_multi = true;
- for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
- ebone_next = curBone->next;
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
- if (curBone == arm->act_edbone) arm->act_edbone = NULL;
- ED_armature_ebone_remove(arm, curBone);
- changed = true;
- }
+ ED_armature_edit_sync_selection(arm->edbo);
+ BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
}
+ MEM_freeN(objects);
- if (!changed)
+ if (!changed_multi) {
return OPERATOR_CANCELLED;
-
- ED_armature_edit_sync_selection(arm->edbo);
- BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
return OPERATOR_FINISHED;
}
@@ -1365,139 +1452,147 @@ static bool armature_dissolve_ebone_cb(const char *bone_name, void *arm_p)
static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
- bArmature *arm;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
EditBone *ebone, *ebone_next;
- Object *obedit = CTX_data_edit_object(C);
- bool changed = false;
-
- /* store for mirror */
- GHash *ebone_flag_orig = NULL;
- int ebone_num = 0;
+ bool changed_multi = false;
- arm = obedit->data;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- ebone->temp.p = NULL;
- ebone->flag &= ~BONE_DONE;
- ebone_num++;
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
- if (arm->flag & ARM_MIRROR_EDIT) {
- GHashIterator gh_iter;
+ /* store for mirror */
+ GHash *ebone_flag_orig = NULL;
+ int ebone_num = 0;
- ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- union { int flag; void *p; } val = {0};
- val.flag = ebone->flag;
- BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
+ ebone->temp.p = NULL;
+ ebone->flag &= ~BONE_DONE;
+ ebone_num++;
}
- armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
-
- GHASH_ITER (gh_iter, ebone_flag_orig) {
- union { int flag; void *p; } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
- ebone = BLI_ghashIterator_getKey(&gh_iter);
- val_p->flag = ebone->flag & ~val_p->flag;
- }
- }
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ GHashIterator gh_iter;
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent && ebone->flag & BONE_CONNECTED) {
- if (ebone->parent->temp.ebone == ebone->parent) {
- /* ignore */
- }
- else if (ebone->parent->temp.ebone) {
- /* set ignored */
- ebone->parent->temp.ebone = ebone->parent;
+ ebone_flag_orig = BLI_ghash_ptr_new_ex(__func__, ebone_num);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union { int flag; void *p; } val = {0};
+ val.flag = ebone->flag;
+ BLI_ghash_insert(ebone_flag_orig, ebone, val.p);
}
- else {
- /* set child */
- ebone->parent->temp.ebone = ebone;
+
+ armature_select_mirrored_ex(arm, BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+
+ GHASH_ITER (gh_iter, ebone_flag_orig) {
+ union { int flag; void *p; } *val_p = (void *)BLI_ghashIterator_getValue_p(&gh_iter);
+ ebone = BLI_ghashIterator_getKey(&gh_iter);
+ val_p->flag = ebone->flag & ~val_p->flag;
}
}
- }
- /* cleanup multiple used bones */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->temp.ebone == ebone) {
- ebone->temp.ebone = NULL;
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && ebone->flag & BONE_CONNECTED) {
+ if (ebone->parent->temp.ebone == ebone->parent) {
+ /* ignore */
+ }
+ else if (ebone->parent->temp.ebone) {
+ /* set ignored */
+ ebone->parent->temp.ebone = ebone->parent;
+ }
+ else {
+ /* set child */
+ ebone->parent->temp.ebone = ebone;
+ }
+ }
}
- }
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* break connections for unseen bones */
- if (((arm->layer & ebone->layer) &&
- ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0)
- {
- ebone->temp.ebone = NULL;
+ /* cleanup multiple used bones */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.ebone == ebone) {
+ ebone->temp.ebone = NULL;
+ }
}
- if (((arm->layer & ebone->layer) &&
- ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0)
- {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- ebone->parent->temp.ebone = NULL;
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* break connections for unseen bones */
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_TIPSEL | BONE_SELECTED)))) == 0)
+ {
+ ebone->temp.ebone = NULL;
}
+ if (((arm->layer & ebone->layer) &&
+ ((ED_armature_ebone_selectflag_get(ebone) & (BONE_ROOTSEL | BONE_SELECTED)))) == 0)
+ {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ ebone->parent->temp.ebone = NULL;
+ }
+
+ }
}
- }
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent &&
- (ebone->parent->temp.ebone == ebone))
- {
- ebone->flag |= BONE_DONE;
+ if (ebone->parent &&
+ (ebone->parent->temp.ebone == ebone))
+ {
+ ebone->flag |= BONE_DONE;
+ }
}
- }
- BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
+ BKE_pose_channels_remove(obedit, armature_dissolve_ebone_cb, arm);
- for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
- ebone_next = ebone->next;
+ for (ebone = arm->edbo->first; ebone; ebone = ebone_next) {
+ ebone_next = ebone->next;
- if (ebone->flag & BONE_DONE) {
- copy_v3_v3(ebone->parent->tail, ebone->tail);
- ebone->parent->rad_tail = ebone->rad_tail;
- SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL);
+ if (ebone->flag & BONE_DONE) {
+ copy_v3_v3(ebone->parent->tail, ebone->tail);
+ ebone->parent->rad_tail = ebone->rad_tail;
+ SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL);
- ED_armature_ebone_remove_ex(arm, ebone, false);
- changed = true;
- }
- }
-
- if (changed) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent &&
- ebone->parent->temp.ebone &&
- (ebone->flag & BONE_CONNECTED))
- {
- ebone->rad_head = ebone->parent->rad_tail;
+ ED_armature_ebone_remove_ex(arm, ebone, false);
+ changed = true;
}
}
- if (arm->flag & ARM_MIRROR_EDIT) {
+ if (changed) {
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- union { int flag; void *p; } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
- if (val_p && val_p->flag) {
- ebone->flag &= ~val_p->flag;
+ if (ebone->parent &&
+ ebone->parent->temp.ebone &&
+ (ebone->flag & BONE_CONNECTED))
+ {
+ ebone->rad_head = ebone->parent->rad_tail;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ union { int flag; void *p; } *val_p = (void *)BLI_ghash_lookup_p(ebone_flag_orig, ebone);
+ if (val_p && val_p->flag) {
+ ebone->flag &= ~val_p->flag;
+ }
}
}
}
- }
- if (arm->flag & ARM_MIRROR_EDIT) {
- BLI_ghash_free(ebone_flag_orig, NULL, NULL);
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ BLI_ghash_free(ebone_flag_orig, NULL, NULL);
+ }
+
+ if (changed) {
+ changed_multi = true;
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
}
+ MEM_freeN(objects);
- if (!changed) {
+ if (!changed_multi) {
return OPERATOR_CANCELLED;
}
- ED_armature_edit_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
return OPERATOR_FINISHED;
}
@@ -1522,28 +1617,39 @@ void ARMATURE_OT_dissolve(wmOperatorType *ot)
static int armature_hide_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
/* cancel if nothing selected */
if (CTX_DATA_COUNT(C, selected_bones) == 0)
return OPERATOR_CANCELLED;
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if ((ebone->flag & BONE_SELECTED) != invert) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag |= BONE_HIDDEN_A;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if ((ebone->flag & BONE_SELECTED) != invert) {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ ebone->flag |= BONE_HIDDEN_A;
+ changed = true;
+ }
}
}
- }
- ED_armature_edit_validate_active(arm);
- ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ if (!changed) {
+ continue;
+ }
+ ED_armature_edit_validate_active(arm);
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1567,26 +1673,35 @@ void ARMATURE_OT_hide(wmOperatorType *ot)
static int armature_reveal_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool select = RNA_boolean_get(op->ptr, "select");
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_HIDDEN_A) {
- if (!(ebone->flag & BONE_UNSELECTABLE)) {
- SET_FLAG_FROM_TEST(ebone->flag, select, (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL));
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (arm->layer & ebone->layer) {
+ if (ebone->flag & BONE_HIDDEN_A) {
+ if (!(ebone->flag & BONE_UNSELECTABLE)) {
+ SET_FLAG_FROM_TEST(ebone->flag, select, (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL));
+ }
+ ebone->flag &= ~BONE_HIDDEN_A;
+ changed = true;
}
- ebone->flag &= ~BONE_HIDDEN_A;
}
}
- }
- ED_armature_edit_validate_active(arm);
- ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ if (changed) {
+ ED_armature_edit_validate_active(arm);
+ ED_armature_edit_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ }
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 67b8b266269..da24787fc18 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -128,6 +128,7 @@ void POSE_OT_group_deselect(struct wmOperatorType *ot);
void POSE_OT_paths_calculate(struct wmOperatorType *ot);
void POSE_OT_paths_update(struct wmOperatorType *ot);
void POSE_OT_paths_clear(struct wmOperatorType *ot);
+void POSE_OT_paths_range_update(struct wmOperatorType *ot);
void POSE_OT_autoside_names(struct wmOperatorType *ot);
void POSE_OT_flip_names(struct wmOperatorType *ot);
@@ -139,18 +140,6 @@ void POSE_OT_quaternions_flip(struct wmOperatorType *ot);
void POSE_OT_bone_layers(struct wmOperatorType *ot);
/* ******************************************************* */
-/* Etch-A-Ton (Skeleton Sketching) Operators */
-
-void SKETCH_OT_gesture(struct wmOperatorType *ot);
-void SKETCH_OT_delete(struct wmOperatorType *ot);
-void SKETCH_OT_draw_stroke(struct wmOperatorType *ot);
-void SKETCH_OT_draw_preview(struct wmOperatorType *ot);
-void SKETCH_OT_finish_stroke(struct wmOperatorType *ot);
-void SKETCH_OT_cancel_stroke(struct wmOperatorType *ot);
-void SKETCH_OT_convert(struct wmOperatorType *ot);
-void SKETCH_OT_select(struct wmOperatorType *ot);
-
-/* ******************************************************* */
/* Pose Tool Utilities (for PoseLib, Pose Sliding, etc.) */
/* pose_utils.c */
@@ -158,6 +147,8 @@ void SKETCH_OT_select(struct wmOperatorType *ot);
typedef struct tPChanFCurveLink {
struct tPChanFCurveLink *next, *prev;
+ struct Object *ob; /* Object this Pose Channel belongs to. */
+
ListBase fcurves; /* F-Curves for this PoseChannel (wrapped with LinkData) */
struct bPoseChannel *pchan; /* Pose Channel which data is attached to */
@@ -181,12 +172,13 @@ typedef struct tPChanFCurveLink {
/* ----------- */
-void poseAnim_mapping_get(struct bContext *C, ListBase *pfLinks, struct Object *ob, struct bAction *act);
+struct Object *poseAnim_object_get(struct Object *ob_);
+void poseAnim_mapping_get(struct bContext *C, ListBase *pfLinks);
void poseAnim_mapping_free(ListBase *pfLinks);
void poseAnim_mapping_refresh(struct bContext *C, struct Scene *scene, struct Object *ob);
void poseAnim_mapping_reset(ListBase *pfLinks);
-void poseAnim_mapping_autoKeyframe(struct bContext *C, struct Scene *scene, struct Object *ob, ListBase *pfLinks, float cframe);
+void poseAnim_mapping_autoKeyframe(struct bContext *C, struct Scene *scene, ListBase *pfLinks, float cframe);
LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path);
@@ -224,8 +216,7 @@ void POSE_OT_propagate(struct wmOperatorType *ot);
* within each file, but some tools still have a bit of overlap which makes things messy -- Feb 2013
*/
-EditBone *make_boneList(struct ListBase *edbo, struct ListBase *bones, struct EditBone *parent, struct Bone *actBone);
-bool BIF_sk_selectStroke(struct bContext *C, const int mval[2], const bool extend);
+EditBone *make_boneList(struct ListBase *edbo, struct ListBase *bones, struct Bone *actBone);
/* duplicate method */
void preEditBoneDuplicate(struct ListBase *editbones);
@@ -248,10 +239,15 @@ void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
void armature_tag_unselect(struct bArmature *arm);
-void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel);
+void *get_nearest_bone(
+ struct bContext *C, const int xy[2], bool findunsel,
+ struct Base **r_base);
+
void *get_bone_from_selectbuffer(
- struct Scene *scene, struct Base *base, const unsigned int *buffer, short hits,
- bool findunsel, bool do_nearest);
+ struct Base **bases, uint bases_len,
+ bool is_editmode, const unsigned int *buffer, short hits,
+ bool findunsel, bool do_nearest,
+ struct Base **r_base);
int bone_looper(struct Object *ob, struct Bone *bone, void *data,
int (*bone_func)(struct Object *, struct Bone *, void *));
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index b0614c84d14..629daf10255 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -31,9 +31,13 @@
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
@@ -48,10 +52,13 @@
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -174,6 +181,9 @@ void ED_armature_bone_rename(Main *bmain, bArmature *arm, const char *oldnamep,
}
}
+ /* force copy on write to update database */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+
/* do entire dbase - objects */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
@@ -264,6 +274,46 @@ void ED_armature_bone_rename(Main *bmain, bArmature *arm, const char *oldnamep,
break;
}
}
+
+ /* fix grease pencil modifiers and vertex groups */
+ if (ob->type == OB_GPENCIL) {
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->parent != NULL) && (gpl->parent->data == arm)) {
+ if (STREQ(gpl->parsubstr, oldname))
+ BLI_strncpy(gpl->parsubstr, newname, MAXBONENAME);
+ }
+ }
+
+ for (GpencilModifierData *gp_md = ob->greasepencil_modifiers.first; gp_md; gp_md = gp_md->next) {
+ switch (gp_md->type) {
+ case eGpencilModifierType_Armature:
+ {
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)gp_md;
+ if (mmd->object && mmd->object->data == arm) {
+ bDeformGroup *dg = defgroup_find_name(ob, oldname);
+ if (dg) {
+ BLI_strncpy(dg->name, newname, MAXBONENAME);
+ }
+ }
+ break;
+ }
+ case eGpencilModifierType_Hook:
+ {
+ HookGpencilModifierData *hgp_md = (HookGpencilModifierData *)gp_md;
+ if (hgp_md->object && (hgp_md->object->data == arm)) {
+ if (STREQ(hgp_md->subtarget, oldname))
+ BLI_strncpy(hgp_md->subtarget, newname, MAXBONENAME);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
/* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since
@@ -355,38 +405,59 @@ void ED_armature_bones_flip_names(Main *bmain, bArmature *arm, ListBase *bones_n
static int armature_flip_names_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm;
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_edit_object(C);
const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
- arm = ob->data;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
- ListBase bones_names = {NULL};
+ /* Paranoia check. */
+ if (ob_active->pose == NULL) {
+ continue;
+ }
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
- }
- CTX_DATA_END;
+ ListBase bones_names = {NULL};
- ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_SELECTED) {
+ BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
- BLI_freelistN(&bones_names);
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
+ BLI_addtail(&bones_names, BLI_genericNodeN(flipbone->name));
+ }
+ }
+ }
+ }
+ }
+
+ if (BLI_listbase_is_empty(&bones_names)) {
+ continue;
+ }
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
- /* copied from #rna_Bone_update_renamed */
- /* redraw view */
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ BLI_freelistN(&bones_names);
- /* update animation channels */
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, ob->data);
+ /* since we renamed stuff... */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* copied from #rna_Bone_update_renamed */
+ /* redraw view */
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ /* update animation channels */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, ob->data);
+
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -410,36 +481,64 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot)
"(WARNING: may result in incoherent naming in some cases)");
}
-
static int armature_autoside_names_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm;
char newname[MAXBONENAME];
- short axis = RNA_enum_get(op->ptr, "type");
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- BLI_strncpy(newname, ebone->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis]))
- ED_armature_bone_rename(bmain, arm, ebone->name, newname);
- }
- CTX_DATA_END;
+ const short axis = RNA_enum_get(op->ptr, "type");
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ /* Paranoia checks. */
+ if (ELEM(NULL, ob, ob->pose)) {
+ continue;
+ }
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_EDITABLE(ebone)) {
+
+ /* We first need to do the flipped bone, then the original one.
+ * Otherwise we can't find the flipped one because of the bone name change. */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+ if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
+ BLI_strncpy(newname, flipbone->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, flipbone->head[axis], flipbone->tail[axis])) {
+ ED_armature_bone_rename(bmain, arm, flipbone->name, newname);
+ changed = true;
+ }
+ }
+ }
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ BLI_strncpy(newname, ebone->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis])) {
+ ED_armature_bone_rename(bmain, arm, ebone->name, newname);
+ changed = true;
+ }
+ }
+ }
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ if (!changed) {
+ continue;
+ }
- return OPERATOR_FINISHED;
+ changed_multi = true;
+
+ /* Since we renamed stuff... */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ }
+ MEM_freeN(objects);
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void ARMATURE_OT_autoside_names(wmOperatorType *ot)
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index d0b87545798..b4c872c044d 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -35,6 +35,7 @@
#include "ED_armature.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
#include "armature_intern.h"
@@ -85,16 +86,6 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_armature_layers);
WM_operatortype_append(ARMATURE_OT_bone_layers);
- /* SKETCH */
- WM_operatortype_append(SKETCH_OT_gesture);
- WM_operatortype_append(SKETCH_OT_delete);
- WM_operatortype_append(SKETCH_OT_draw_stroke);
- WM_operatortype_append(SKETCH_OT_draw_preview);
- WM_operatortype_append(SKETCH_OT_finish_stroke);
- WM_operatortype_append(SKETCH_OT_cancel_stroke);
- WM_operatortype_append(SKETCH_OT_convert);
- WM_operatortype_append(SKETCH_OT_select);
-
/* POSE */
WM_operatortype_append(POSE_OT_hide);
WM_operatortype_append(POSE_OT_reveal);
@@ -132,6 +123,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_paths_calculate);
WM_operatortype_append(POSE_OT_paths_update);
WM_operatortype_append(POSE_OT_paths_clear);
+ WM_operatortype_append(POSE_OT_paths_range_update);
WM_operatortype_append(POSE_OT_autoside_names);
WM_operatortype_append(POSE_OT_flip_names);
@@ -198,224 +190,15 @@ void ED_operatormacros_armature(void)
void ED_keymap_armature(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
- wmKeyMapItem *kmi;
/* Armature ------------------------ */
+ /* only set in editmode armature, by space_view3d listener */
keymap = WM_keymap_ensure(keyconf, "Armature", 0, 0);
keymap->poll = ED_operator_editarmature;
- /* Armature -> Etch-A-Ton ------------------------ */
- WM_keymap_add_item(keymap, "SKETCH_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "SKETCH_OT_delete", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "SKETCH_OT_finish_stroke", RIGHTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "SKETCH_OT_cancel_stroke", ESCKEY, KM_PRESS, 0, 0);
- /* Already part of view3d select */
- //WM_keymap_add_item(keymap, "SKETCH_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
-
- /* sketch poll checks mode */
- WM_keymap_add_item(keymap, "SKETCH_OT_gesture", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "SKETCH_OT_draw_stroke", LEFTMOUSE, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "SKETCH_OT_draw_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "snap", true);
- WM_keymap_add_item(keymap, "SKETCH_OT_draw_preview", MOUSEMOVE, KM_ANY, 0, 0);
- kmi = WM_keymap_add_item(keymap, "SKETCH_OT_draw_preview", MOUSEMOVE, KM_ANY, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "snap", true);
-
- /* only set in editmode armature, by space_view3d listener */
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_align", AKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_calculate_roll", NKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_roll_clear", RKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_switch_direction", FKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_bone_primitive_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_parent_clear", PKEY, KM_PRESS, KM_ALT, 0);
-
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_mirror", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
-
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_PARENT);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_PARENT);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_CHILD);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "ARMATURE_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_CHILD);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_select_linked", LKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_armature_delete", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_extrude_forked", EKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_click_extrude", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_fill", FKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_split", YKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "ARMATURE_OT_separate", PKEY, KM_PRESS, 0, 0);
-
- /* set flags */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_enable", WKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_disable", WKEY, KM_PRESS, KM_ALT, 0);
-
- /* armature/bone layers */
- WM_keymap_add_item(keymap, "ARMATURE_OT_layers_show_all", ACCENTGRAVEKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_armature_layers", MKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_bone_layers", MKEY, KM_PRESS, 0, 0);
-
- /* special transforms: */
- /* 1) envelope/b-bone size */
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_BONESIZE);
- /* 2) envelope radius */
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_BONE_ENVELOPE);
- /* 3) set roll */
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", RKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_BONE_ROLL);
-
- /* menus */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_armature_specials", WKEY, KM_PRESS, 0, 0);
-
/* Pose ------------------------ */
/* only set in posemode, by space_view3d listener */
keymap = WM_keymap_ensure(keyconf, "Pose", 0, 0);
keymap->poll = ED_operator_posemode;
- /* set parent and add object are object-based operators, but we make them
- * available here because it's useful to do in pose mode too */
- WM_keymap_add_item(keymap, "OBJECT_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_menu(keymap, "INFO_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- kmi = WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "POSE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- WM_keymap_add_item(keymap, "POSE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_apply", AKEY, KM_PRESS, KM_CTRL, 0);
-
- /* TODO: clear pose */
- WM_keymap_add_item(keymap, "POSE_OT_rot_clear", RKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_loc_clear", GKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "POSE_OT_quaternions_flip", FKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "POSE_OT_rotation_mode_set", RKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "POSE_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
- kmi = WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "flipped", false);
- kmi = WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "flipped", true);
-
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "POSE_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- kmi = WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
- RNA_boolean_set(kmi->ptr, "flipped", false);
- kmi = WM_keymap_add_item(keymap, "POSE_OT_paste", VKEY, KM_PRESS, KM_OSKEY | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "flipped", true);
-#endif
-
- kmi = WM_keymap_add_item(keymap, "POSE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "POSE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "POSE_OT_select_parent", PKEY, KM_PRESS, KM_SHIFT, 0);
-
- kmi = WM_keymap_add_item(keymap, "POSE_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_PARENT);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "POSE_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_PARENT);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- kmi = WM_keymap_add_item(keymap, "POSE_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_CHILD);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "POSE_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_CHILD);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- WM_keymap_add_item(keymap, "POSE_OT_select_linked", LKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "POSE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_select_mirror", FKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "POSE_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_ik_add", IKEY, KM_PRESS, /*KM_CTRL|*/ KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_ik_clear", IKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_group", GKEY, KM_PRESS, KM_CTRL, 0);
-
- /* set flags */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_enable", WKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_bone_options_disable", WKEY, KM_PRESS, KM_ALT, 0);
-
- /* armature/bone layers */
- WM_keymap_add_item(keymap, "ARMATURE_OT_layers_show_all", ACCENTGRAVEKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ARMATURE_OT_armature_layers", MKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_bone_layers", MKEY, KM_PRESS, 0, 0);
-
- /* special transforms: */
- /* 1) envelope/b-bone size */
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_BONESIZE);
-
- /* keyframes management */
- WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_insert_menu", IKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_delete_v3d", IKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_verify_item(keymap, "ANIM_OT_keying_set_active_set", IKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0);
-
- /* Pose -> PoseLib ------------- */
- /* only set in posemode, by space_view3d listener */
- WM_keymap_add_item(keymap, "POSELIB_OT_browse_interactive", LKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "POSELIB_OT_pose_add", LKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "POSELIB_OT_pose_remove", LKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "POSELIB_OT_pose_rename", LKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
-
- /* Pose -> Pose Sliding ------------- */
- /* only set in posemode, by space_view3d listener */
- WM_keymap_add_item(keymap, "POSE_OT_push", EKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "POSE_OT_relax", EKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "POSE_OT_breakdown", EKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* menus */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_specials", WKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_pose_propagate", PKEY, KM_PRESS, KM_ALT, 0);
}
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index e4ce1d58208..16eb67c9df2 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -47,12 +47,15 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -244,23 +247,23 @@ int join_armature_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- bArmature *arm = (ob) ? ob->data : NULL;
+ Object *ob_active = CTX_data_active_object(C);
+ bArmature *arm = (ob_active) ? ob_active->data : NULL;
bPose *pose, *opose;
bPoseChannel *pchan, *pchann;
EditBone *curbone;
float mat[4][4], oimat[4][4];
bool ok = false;
- /* Ensure we're not in editmode and that the active object is an armature. */
- if (!ob || ob->type != OB_ARMATURE)
+ /* Ensure we're not in editmode and that the active object is an armature*/
+ if (!ob_active || ob_active->type != OB_ARMATURE)
return OPERATOR_CANCELLED;
if (!arm || arm->edbo)
return OPERATOR_CANCELLED;
- CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
{
- if (base->object == ob) {
+ if (ob_iter == ob_active) {
ok = true;
break;
}
@@ -277,34 +280,34 @@ int join_armature_exec(bContext *C, wmOperator *op)
ED_armature_to_edit(arm);
/* get pose of active object and move it out of posemode */
- pose = ob->pose;
- ob->mode &= ~OB_MODE_POSE;
+ pose = ob_active->pose;
+ ob_active->mode &= ~OB_MODE_POSE;
- CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
{
- if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
+ if ((ob_iter->type == OB_ARMATURE) && (ob_iter != ob_active)) {
tJoinArmature_AdtFixData afd = {NULL};
- bArmature *curarm = base->object->data;
+ bArmature *curarm = ob_iter->data;
/* we assume that each armature datablock is only used in a single place */
- BLI_assert(ob->data != base->object->data);
+ BLI_assert(ob_active->data != ob_iter->data);
/* init callback data for fixing up AnimData links later */
- afd.srcArm = base->object;
- afd.tarArm = ob;
+ afd.srcArm = ob_iter;
+ afd.tarArm = ob_active;
afd.names_map = BLI_ghash_str_new("join_armature_adt_fix");
/* Make a list of editbones in current armature */
- ED_armature_to_edit(base->object->data);
+ ED_armature_to_edit(ob_iter->data);
/* Get Pose of current armature */
- opose = base->object->pose;
- base->object->mode &= ~OB_MODE_POSE;
+ opose = ob_iter->pose;
+ ob_iter->mode &= ~OB_MODE_POSE;
//BASACT->flag &= ~OB_MODE_POSE;
/* Find the difference matrix */
- invert_m4_m4(oimat, ob->obmat);
- mul_m4_m4m4(mat, oimat, base->object->obmat);
+ invert_m4_m4(oimat, ob_active->obmat);
+ mul_m4_m4m4(mat, oimat, ob_iter->obmat);
/* Copy bones and posechannels from the object to the edit armature */
for (pchan = opose->chanbase.first; pchan; pchan = pchann) {
@@ -344,7 +347,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
}
/* Fix Constraints and Other Links to this Bone and Armature */
- joined_armature_fix_links(bmain, ob, base->object, pchan, curbone);
+ joined_armature_fix_links(bmain, ob_active, ob_iter, pchan, curbone);
/* Rename pchan */
BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
@@ -367,21 +370,21 @@ int join_armature_exec(bContext *C, wmOperator *op)
* so that we don't have to worry about ambiguities re which armature
* a bone came from!
*/
- if (base->object->adt) {
- if (ob->adt == NULL) {
+ if (ob_iter->adt) {
+ if (ob_active->adt == NULL) {
/* no animdata, so just use a copy of the whole thing */
- ob->adt = BKE_animdata_copy(bmain, base->object->adt, false);
+ ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
}
else {
/* merge in data - we'll fix the drivers manually */
- BKE_animdata_merge_copy(bmain, &ob->id, &base->object->id, ADT_MERGECOPY_KEEP_DST, false);
+ BKE_animdata_merge_copy(bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
}
}
if (curarm->adt) {
if (arm->adt == NULL) {
/* no animdata, so just use a copy of the whole thing */
- arm->adt = BKE_animdata_copy(bmain, curarm->adt, false);
+ arm->adt = BKE_animdata_copy(bmain, curarm->adt, 0);
}
else {
/* merge in data - we'll fix the drivers manually */
@@ -390,16 +393,17 @@ int join_armature_exec(bContext *C, wmOperator *op)
}
/* Free the old object data */
- ED_base_object_free_and_unlink(bmain, scene, base);
+ ED_object_base_free_and_unlink(bmain, scene, ob_iter);
}
}
CTX_DATA_END;
- DAG_relations_tag_update(bmain); /* because we removed object(s) */
+ DEG_relations_tag_update(bmain); /* because we removed object(s) */
ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
@@ -545,8 +549,15 @@ static void separate_armature_bones(Main *bmain, Object *ob, short sel)
/* clear the pchan->parent var of any pchan that had this as its parent */
for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
- if (pchn->parent == pchan)
+ if (pchn->parent == pchan) {
pchn->parent = NULL;
+ }
+ if (pchn->bbone_next == pchan) {
+ pchn->bbone_next = NULL;
+ }
+ if (pchn->bbone_prev == pchan) {
+ pchn->bbone_prev = NULL;
+ }
}
/* free any of the extra-data this pchan might have */
@@ -569,79 +580,90 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Object *oldob, *newob;
- Base *oldbase, *newbase;
-
- /* sanity checks */
- if (obedit == NULL)
- return OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bool ok = false;
/* set wait cursor in case this takes a while */
WM_cursor_wait(1);
- /* we are going to do this as follows (unlike every other instance of separate):
- * 1. exit editmode +posemode for active armature/base. Take note of what this is.
- * 2. duplicate base - BASACT is the new one now
- * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
- * 4. fix constraint links
- * 5. make original armature active and enter editmode
- */
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &bases_len);
- /* 1) only edit-base selected */
- /* TODO: use context iterators for this? */
CTX_DATA_BEGIN(C, Base *, base, visible_bases)
{
- if (base->object == obedit) base->flag |= SELECT;
- else base->flag &= ~SELECT;
+ ED_object_base_select(base, BA_DESELECT);
}
CTX_DATA_END;
- /* 1) store starting settings and exit editmode */
- oldob = obedit;
- oldbase = BASACT;
- oldob->mode &= ~OB_MODE_POSE;
- //oldbase->flag &= ~OB_POSEMODE;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
- ED_armature_from_edit(bmain, obedit->data);
- ED_armature_edit_free(obedit->data);
+ Object *oldob, *newob;
+ Base *oldbase, *newbase;
- /* 2) duplicate base */
- newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */
- DAG_relations_tag_update(bmain);
+ /* we are going to do this as follows (unlike every other instance of separate):
+ * 1. exit editmode +posemode for active armature/base. Take note of what this is.
+ * 2. duplicate base - BASACT is the new one now
+ * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
+ * 4. fix constraint links
+ * 5. make original armature active and enter editmode
+ */
- newob = newbase->object;
- newbase->flag &= ~SELECT;
+ /* 1) only edit-base selected */
+ ED_object_base_select(base_iter, BA_SELECT);
+ /* 1) store starting settings and exit editmode */
+ oldob = obedit;
+ oldbase = base_iter;
+ oldob->mode &= ~OB_MODE_POSE;
+ //oldbase->flag &= ~OB_POSEMODE;
- /* 3) remove bones that shouldn't still be around on both armatures */
- separate_armature_bones(bmain, oldob, 1);
- separate_armature_bones(bmain, newob, 0);
+ ED_armature_from_edit(bmain, obedit->data);
+ ED_armature_edit_free(obedit->data);
+ /* 2) duplicate base */
+ newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, USER_DUP_ARM); /* only duplicate linked armature */
+ DEG_relations_tag_update(bmain);
- /* 4) fix links before depsgraph flushes */ // err... or after?
- separated_armature_fix_links(bmain, oldob, newob);
+ newob = newbase->object;
+ newbase->flag &= ~BASE_SELECTED;
- DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
- DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */
+ /* 3) remove bones that shouldn't still be around on both armatures */
+ separate_armature_bones(bmain, oldob, 1);
+ separate_armature_bones(bmain, newob, 0);
- /* 5) restore original conditions */
- obedit = oldob;
- ED_armature_to_edit(obedit->data);
+ /* 4) fix links before depsgraph flushes */ // err... or after?
+ separated_armature_fix_links(bmain, oldob, newob);
- /* parents tips remain selected when connected children are removed. */
- ED_armature_edit_deselect_all(obedit);
+ DEG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
+ DEG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */
- BKE_report(op->reports, RPT_INFO, "Separated bones");
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ /* 5) restore original conditions */
+ obedit = oldob;
+
+ ED_armature_to_edit(obedit->data);
+
+ /* parents tips remain selected when connected children are removed. */
+ ED_armature_edit_deselect_all(obedit);
+
+ ok = true;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+ }
+ MEM_freeN(bases);
/* recalc/redraw + cleanup */
WM_cursor_wait(0);
+ if (ok) {
+ BKE_report(op->reports, RPT_INFO, "Separated bones");
+ }
+
return OPERATOR_FINISHED;
}
@@ -865,9 +887,8 @@ static void editbone_clear_parent(EditBone *ebone, int mode)
static int armature_parent_clear_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- int val = RNA_enum_get(op->ptr, "type");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const int val = RNA_enum_get(op->ptr, "type");
CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
{
@@ -875,10 +896,30 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- ED_armature_edit_sync_selection(arm->edbo);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_EDITABLE(ebone)) {
+ changed = true;
+ break;
+ }
+ }
+
+ if (!changed) {
+ continue;
+ }
+
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index eb723671594..1c5219e94c8 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -29,6 +29,8 @@
* \ingroup edarmature
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -39,7 +41,9 @@
#include "BKE_context.h"
#include "BKE_action.h"
+#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
#include "BIF_gl.h"
@@ -50,9 +54,13 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_view3d.h"
+#include "DEG_depsgraph.h"
+
#include "armature_intern.h"
/* utility macros for storing a temp int in the bone (selection flag) */
@@ -61,27 +69,84 @@
/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
-/* only for opengl selection indices */
-Bone *ED_armature_bone_find_index(Object *ob, int index)
+Base *ED_armature_base_and_ebone_from_select_buffer(
+ Base **bases, uint bases_len, int hit, EditBone **r_ebone)
+{
+ const uint hit_object = hit & 0xFFFF;
+ Base *base = NULL;
+ EditBone *ebone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ if (bases[base_index]->object->select_color == hit_object) {
+ base = bases[base_index];
+ break;
+ }
+ }
+ if (base != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bArmature *arm = base->object->data;
+ ebone = BLI_findlink(arm->edbo, hit_bone);
+ }
+ *r_ebone = ebone;
+ return base;
+}
+
+Object *ED_armature_object_and_ebone_from_select_buffer(
+ Object **objects, uint objects_len, int hit, EditBone **r_ebone)
{
- bPoseChannel *pchan;
- if (ob->pose == NULL) return NULL;
- index >>= 16; // bone selection codes use left 2 bytes
+ const uint hit_object = hit & 0xFFFF;
+ Object *ob = NULL;
+ EditBone *ebone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (objects[ob_index]->select_color == hit_object) {
+ ob = objects[ob_index];
+ break;
+ }
+ }
+ if (ob != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bArmature *arm = ob->data;
+ ebone = BLI_findlink(arm->edbo, hit_bone);
+ }
+ *r_ebone = ebone;
+ return ob;
+}
- pchan = BLI_findlink(&ob->pose->chanbase, index);
- return pchan ? pchan->bone : NULL;
+Base *ED_armature_base_and_bone_from_select_buffer(
+ Base **bases, uint bases_len, int hit, Bone **r_bone)
+{
+ const uint hit_object = hit & 0xFFFF;
+ Base *base = NULL;
+ Bone *bone = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ if (bases[base_index]->object->select_color == hit_object) {
+ base = bases[base_index];
+ break;
+ }
+ }
+ if (base != NULL) {
+ if (base->object->pose != NULL) {
+ const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
+ bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
+ bone = pchan ? pchan->bone : NULL;
+ }
+ }
+ *r_bone = bone;
+ return base;
}
/* See if there are any selected bones in this buffer */
/* only bones from base are checked on */
void *get_bone_from_selectbuffer(
- Scene *scene, Base *base, const unsigned int *buffer, short hits,
- bool findunsel, bool do_nearest)
+ Base **bases, uint bases_len, bool is_editmode, const unsigned int *buffer, short hits,
+ bool findunsel, bool do_nearest, Base **r_base)
{
- Object *obedit = scene->obedit; // XXX get from context
Bone *bone;
EditBone *ebone;
void *firstunSel = NULL, *firstSel = NULL, *data;
+ Base *firstunSel_base = NULL, *firstSel_base = NULL;
unsigned int hitresult;
short i;
bool takeNext = false;
@@ -92,15 +157,14 @@ void *get_bone_from_selectbuffer(
if (!(hitresult & BONESEL_NOSEL)) {
if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
+ Base *base = NULL;
bool sel;
hitresult &= ~(BONESEL_ANY);
/* Determine what the current bone is */
- if (obedit == NULL || base->object != obedit) {
- /* no singular posemode, so check for correct object */
- if (base->selcol == (hitresult & 0xFFFF)) {
- bone = ED_armature_bone_find_index(base->object, hitresult);
-
+ if (is_editmode == false) {
+ base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone);
+ if (bone != NULL) {
if (findunsel)
sel = (bone->flag & BONE_SELECTED);
else
@@ -114,9 +178,7 @@ void *get_bone_from_selectbuffer(
}
}
else {
- bArmature *arm = obedit->data;
-
- ebone = BLI_findlink(arm->edbo, hitresult);
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
if (findunsel)
sel = (ebone->flag & BONE_SELECTED);
else
@@ -130,11 +192,15 @@ void *get_bone_from_selectbuffer(
if (do_nearest) {
if (minsel > buffer[4 * i + 1]) {
firstSel = data;
+ firstSel_base = base;
minsel = buffer[4 * i + 1];
}
}
else {
- if (!firstSel) firstSel = data;
+ if (!firstSel) {
+ firstSel = data;
+ firstSel_base = base;
+ }
takeNext = 1;
}
}
@@ -142,12 +208,19 @@ void *get_bone_from_selectbuffer(
if (do_nearest) {
if (minunsel > buffer[4 * i + 1]) {
firstunSel = data;
+ firstunSel_base = base;
minunsel = buffer[4 * i + 1];
}
}
else {
- if (!firstunSel) firstunSel = data;
- if (takeNext) return data;
+ if (!firstunSel) {
+ firstunSel = data;
+ firstunSel_base = base;
+ }
+ if (takeNext) {
+ *r_base = base;
+ return data;
+ }
}
}
}
@@ -155,16 +228,22 @@ void *get_bone_from_selectbuffer(
}
}
- if (firstunSel)
+ if (firstunSel) {
+ *r_base = firstunSel_base;
return firstunSel;
- else
+ }
+ else {
+ *r_base = firstSel_base;
return firstSel;
+ }
}
/* used by posemode as well editmode */
/* only checks scene->basact! */
/* x and y are mouse coords (area space) */
-void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
+void *get_nearest_bone(
+ bContext *C, const int xy[2], bool findunsel,
+ Base **r_base)
{
ViewContext vc;
rcti rect;
@@ -177,11 +256,31 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
rect.xmin = rect.xmax = xy[0];
rect.ymin = rect.ymax = xy[1];
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
+ hits = view3d_opengl_select(
+ &vc, buffer, MAXPICKBUF, &rect,
+ VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
+
+ *r_base = NULL;
+
+ if (hits > 0) {
+ uint bases_len = 0;
+ Base **bases;
+
+ if (vc.obedit != NULL) {
+ bases = BKE_view_layer_array_from_bases_in_mode(
+ vc.view_layer, vc.v3d, &bases_len, {
+ .object_mode = OB_MODE_EDIT});
+ }
+ else {
+ bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len);
+ }
- if (hits > 0)
- return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel, true);
+ void *bone = get_bone_from_selectbuffer(
+ bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base);
+ MEM_freeN(bases);
+ return bone;
+ }
return NULL;
}
@@ -189,30 +288,25 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
/* called in space.c */
/* previously "selectconnected_armature" */
-static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int armature_select_linked_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
bArmature *arm;
EditBone *bone, *curBone, *next;
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- Object *obedit = CTX_data_edit_object(C);
- arm = obedit->data;
view3d_operator_needs_opengl(C);
- bone = get_nearest_bone(C, event->mval, !extend);
+ Base *base = NULL;
+ bone = get_nearest_bone(C, event->mval, true, &base);
if (!bone)
return OPERATOR_CANCELLED;
+ arm = base->object->data;
+
/* Select parents */
for (curBone = bone; curBone; curBone = next) {
if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (extend) {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
+ curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
if (curBone->flag & BONE_CONNECTED)
@@ -227,10 +321,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
next = curBone->next;
if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
if (curBone->flag & BONE_CONNECTED) {
- if (extend)
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- else
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
bone = curBone;
break;
}
@@ -246,7 +337,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
return OPERATOR_FINISHED;
}
@@ -270,9 +361,6 @@ void ARMATURE_OT_select_linked(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
}
/* utility function for get_nearest_editbonepoint */
@@ -292,37 +380,43 @@ static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const
/* note that BONE ROOT only gets drawn for root bones (or without IK) */
static EditBone *get_nearest_editbonepoint(
ViewContext *vc,
- bool findunsel, bool use_cycle, int *r_selmask)
+ bool findunsel, bool use_cycle,
+ Base **r_base, int *r_selmask)
{
- bArmature *arm = (bArmature *)vc->obedit->data;
- EditBone *ebone_next_act = arm->act_edbone;
-
- EditBone *ebone;
- rcti rect;
- unsigned int buffer[MAXPICKBUF];
- unsigned int hitresult, besthitresult = BONESEL_NOSEL;
- int i, mindep = 5;
- int hits12, hits5 = 0;
-
- static int last_mval[2] = {-100, -100};
+ uint buffer[MAXPICKBUF];
+ struct {
+ uint hitresult;
+ Base *base;
+ EditBone *ebone;
+ } best = {
+ .hitresult = BONESEL_NOSEL,
+ .base = NULL,
+ .ebone = NULL,
+ };
/* find the bone after the current active bone, so as to bump up its chances in selection.
* this way overlapping bones will cycle selection state as with objects. */
- if (ebone_next_act &&
- EBONE_VISIBLE(arm, ebone_next_act) &&
- ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))
+ EditBone *ebone_next_act = ((bArmature *)vc->obedit->data)->act_edbone;
{
- ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
- }
- else {
- ebone_next_act = NULL;
+ bArmature *arm = (bArmature *)vc->obedit->data;
+ if (ebone_next_act &&
+ EBONE_VISIBLE(arm, ebone_next_act) &&
+ ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))
+ {
+ ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
+ }
+ else {
+ ebone_next_act = NULL;
+ }
}
bool do_nearest = false;
/* define if we use solid nearest select or not */
if (use_cycle) {
- if (vc->v3d->drawtype > OB_WIRE) {
+ static int last_mval[2] = {-100, -100};
+
+ if (vc->v3d->shading.type > OB_WIRE) {
do_nearest = true;
if (len_manhattan_v2v2_int(vc->mval, last_mval) < 3) {
do_nearest = false;
@@ -331,58 +425,74 @@ static EditBone *get_nearest_editbonepoint(
copy_v2_v2_int(last_mval, vc->mval);
}
else {
- if (vc->v3d->drawtype > OB_WIRE) {
+ if (vc->v3d->shading.type > OB_WIRE) {
do_nearest = true;
}
}
/* matching logic from 'mixed_bones_object_selectbuffer' */
- const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
int hits = 0;
/* we _must_ end cache before return, use 'goto cache_end' */
view3d_opengl_select_cache_begin();
- BLI_rcti_init_pt_radius(&rect, vc->mval, 12);
- hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
- if (hits12 == 1) {
- hits = selectbuffer_ret_hits_12(buffer, hits12);
- goto cache_end;
- }
- else if (hits12 > 0) {
- int offs;
-
- offs = 4 * hits12;
- BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
- hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
-
- if (hits5 == 1) {
- hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
+ {
+ const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+ const eV3DSelectObjectFilter select_filter = VIEW3D_SELECT_FILTER_NOP;
+
+ rcti rect;
+ BLI_rcti_init_pt_radius(&rect, vc->mval, 12);
+ const int hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
+ if (hits12 == 1) {
+ hits = selectbuffer_ret_hits_12(buffer, hits12);
goto cache_end;
}
+ else if (hits12 > 0) {
+ int offs;
+
+ offs = 4 * hits12;
+ BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
+ const int hits5 = view3d_opengl_select(
+ vc, buffer + offs, MAXPICKBUF - offs, &rect,
+ select_mode, select_filter);
+
+ if (hits5 == 1) {
+ hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
+ goto cache_end;
+ }
- if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); goto cache_end; }
- else { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; }
+ if (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); goto cache_end; }
+ else { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; }
+ }
}
cache_end:
view3d_opengl_select_cache_end();
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc->view_layer, vc->v3d, &bases_len);
+
/* See if there are any selected bones in this group */
if (hits > 0) {
-
if (hits == 1) {
- if (!(buffer[3] & BONESEL_NOSEL))
- besthitresult = buffer[3];
+ if (!(buffer[3] & BONESEL_NOSEL)) {
+ best.hitresult = buffer[3];
+ best.base = ED_armature_base_and_ebone_from_select_buffer(
+ bases, bases_len, best.hitresult, &best.ebone);
+ }
}
else {
- for (i = 0; i < hits; i++) {
- hitresult = buffer[3 + (i * 4)];
+ int dep_min = 5;
+ for (int i = 0; i < hits; i++) {
+ const uint hitresult = buffer[3 + (i * 4)];
if (!(hitresult & BONESEL_NOSEL)) {
- int dep;
-
- ebone = BLI_findlink(arm->edbo, hitresult & ~BONESEL_ANY);
+ Base *base = NULL;
+ EditBone *ebone;
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ /* If this fails, selection code is setting the selection ID's incorrectly. */
+ BLI_assert(base && ebone);
+ int dep;
/* clicks on bone points get advantage */
if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
/* but also the unselected one */
@@ -415,29 +525,36 @@ cache_end:
dep -= 1;
}
- if (dep < mindep) {
- mindep = dep;
- besthitresult = hitresult;
+ if (dep < dep_min) {
+ dep_min = dep;
+ best.hitresult = hitresult;
+ best.base = base;
+ best.ebone = ebone;
}
}
}
}
- if (!(besthitresult & BONESEL_NOSEL)) {
-
- ebone = BLI_findlink(arm->edbo, besthitresult & ~BONESEL_ANY);
+ if (!(best.hitresult & BONESEL_NOSEL)) {
+ *r_base = best.base;
*r_selmask = 0;
- if (besthitresult & BONESEL_ROOT)
+ if (best.hitresult & BONESEL_ROOT) {
*r_selmask |= BONE_ROOTSEL;
- if (besthitresult & BONESEL_TIP)
+ }
+ if (best.hitresult & BONESEL_TIP) {
*r_selmask |= BONE_TIPSEL;
- if (besthitresult & BONESEL_BONE)
+ }
+ if (best.hitresult & BONESEL_BONE) {
*r_selmask |= BONE_SELECTED;
- return ebone;
+ }
+ MEM_freeN(bases);
+ return best.ebone;
}
}
*r_selmask = 0;
+ *r_base = NULL;
+ MEM_freeN(bases);
return NULL;
}
@@ -466,6 +583,23 @@ void ED_armature_edit_deselect_all_visible(Object *obedit)
ED_armature_edit_sync_selection(arm->edbo);
}
+
+void ED_armature_edit_deselect_all_multi(struct Object **objects, uint objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ED_armature_edit_deselect_all(obedit);
+ }
+}
+
+void ED_armature_edit_deselect_all_visible_multi(struct Object **objects, uint objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ED_armature_edit_deselect_all_visible(obedit);
+ }
+}
+
/* accounts for connected parents */
static int ebone_select_flag(EditBone *ebone)
{
@@ -480,25 +614,25 @@ static int ebone_select_flag(EditBone *ebone)
/* context: editmode armature in view3d */
bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
- Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
EditBone *nearBone = NULL;
int selmask;
+ Base *basact = NULL;
ED_view3d_viewcontext_init(C, &vc);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
- if (BIF_sk_selectStroke(C, mval, extend)) {
- return true;
- }
-
- nearBone = get_nearest_editbonepoint(&vc, true, true, &selmask);
+ nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask);
if (nearBone) {
- bArmature *arm = obedit->data;
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ bArmature *arm = vc.obedit->data;
if (!extend && !deselect && !toggle) {
- ED_armature_edit_deselect_all(obedit);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &objects_len);
+ ED_armature_edit_deselect_all_multi(objects, objects_len);
+ MEM_freeN(objects);
}
/* by definition the non-root connected bones have no root point drawn,
@@ -571,14 +705,16 @@ bool ED_armature_edit_select_pick(bContext *C, const int mval[2], bool extend, b
ED_armature_edit_sync_selection(arm->edbo);
- if (nearBone) {
- /* then now check for active status */
- if (ebone_select_flag(nearBone)) {
- arm->act_edbone = nearBone;
- }
+ /* then now check for active status */
+ if (ebone_select_flag(nearBone)) {
+ arm->act_edbone = nearBone;
+ }
+
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
return true;
}
@@ -748,10 +884,15 @@ static void armature_select_more_less(Object *ob, bool more)
static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- armature_select_more_less(obedit, true);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ armature_select_more_less(ob, true);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -772,10 +913,15 @@ void ARMATURE_OT_select_more(wmOperatorType *ot)
static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- armature_select_more_less(obedit, false);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ armature_select_more_less(ob, false);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -821,84 +967,171 @@ static const EnumPropertyItem prop_similar_types[] = {
{0, NULL, 0, NULL, NULL}
};
+static float bone_length_squared_worldspace_get(Object *ob, EditBone *ebone)
+{
+ float v1[3], v2[3];
+ mul_v3_mat3_m4v3(v1, ob->obmat, ebone->head);
+ mul_v3_mat3_m4v3(v2, ob->obmat, ebone->tail);
+ return len_squared_v3v3(v1, v2);
+}
-static void select_similar_length(bArmature *arm, EditBone *ebone_act, const float thresh)
+static void select_similar_length(bContext *C, const float thresh)
{
- EditBone *ebone;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_act = CTX_data_edit_object(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
- /* thresh is always relative to current length */
- const float len_min = ebone_act->length / (1.0f + thresh);
- const float len_max = ebone_act->length * (1.0f + thresh);
+ /* Thresh is always relative to current length. */
+ const float len = bone_length_squared_worldspace_get(ob_act, ebone_act);
+ const float len_min = len / (1.0f + (thresh - FLT_EPSILON));
+ const float len_max = len * (1.0f + (thresh + FLT_EPSILON));
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- if ((ebone->length >= len_min) &&
- (ebone->length <= len_max))
- {
- ED_armature_ebone_select_set(ebone, true);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ const float len_iter = bone_length_squared_worldspace_get(ob, ebone);
+ if ((len_iter > len_min) &&
+ (len_iter < len_max))
+ {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
}
}
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
}
+ MEM_freeN(objects);
}
-static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const float thresh)
+static void bone_direction_worldspace_get(Object *ob, EditBone *ebone, float *r_dir)
{
- EditBone *ebone;
+ float v1[3], v2[3];
+ copy_v3_v3(v1, ebone->head);
+ copy_v3_v3(v2, ebone->tail);
+
+ mul_m4_v3(ob->obmat, v1);
+ mul_m4_v3(ob->obmat, v2);
+
+ sub_v3_v3v3(r_dir, v1, v2);
+ normalize_v3(r_dir);
+}
+
+static void select_similar_direction(bContext *C, const float thresh)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_act = CTX_data_edit_object(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
float dir_act[3];
- sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail);
+ bone_direction_worldspace_get(ob_act, ebone_act, dir_act);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- float dir[3];
- sub_v3_v3v3(dir, ebone->head, ebone->tail);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
- if (angle_v3v3(dir_act, dir) / (float)M_PI < thresh) {
- ED_armature_ebone_select_set(ebone, true);
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ float dir[3];
+ bone_direction_worldspace_get(ob, ebone, dir);
+
+ if (angle_v3v3(dir_act, dir) / (float)M_PI < (thresh + FLT_EPSILON)) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
}
}
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
}
+ MEM_freeN(objects);
}
-static void select_similar_layer(bArmature *arm, EditBone *ebone_act)
+static void select_similar_layer(bContext *C)
{
- EditBone *ebone;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- if (ebone->layer & ebone_act->layer) {
- ED_armature_ebone_select_set(ebone, true);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ if (ebone->layer & ebone_act->layer) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
}
}
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
}
+ MEM_freeN(objects);
}
-static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
+static void select_similar_prefix(bContext *C)
{
- EditBone *ebone;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
char body_tmp[MAXBONENAME];
char prefix_act[MAXBONENAME];
BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name));
- if (prefix_act[0] == '\0')
+ if (prefix_act[0] == '\0') {
return;
+ }
- /* Find matches */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- char prefix_other[MAXBONENAME];
- BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
- if (STREQ(prefix_act, prefix_other)) {
- ED_armature_ebone_select_set(ebone, true);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ /* Find matches */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ char prefix_other[MAXBONENAME];
+ BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
+ if (STREQ(prefix_act, prefix_other)) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
}
}
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
}
+ MEM_freeN(objects);
}
-static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
+static void select_similar_suffix(bContext *C)
{
- EditBone *ebone;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EditBone *ebone_act = CTX_data_active_bone(C);
char body_tmp[MAXBONENAME];
char suffix_act[MAXBONENAME];
@@ -908,28 +1141,46 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
if (suffix_act[0] == '\0')
return;
- /* Find matches */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- char suffix_other[MAXBONENAME];
- BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
- if (STREQ(suffix_act, suffix_other)) {
- ED_armature_ebone_select_set(ebone, true);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bool changed = false;
+
+ /* Find matches */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ char suffix_other[MAXBONENAME];
+ BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
+ if (STREQ(suffix_act, suffix_other)) {
+ ED_armature_ebone_select_set(ebone, true);
+ changed = true;
+ }
}
}
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
}
+ MEM_freeN(objects);
}
/** Use for matching any pose channel data. */
static void select_similar_data_pchan(
- bArmature *arm, Object *obj, EditBone *ebone_active,
+ bContext *C,
const size_t bytes_size, const int offset)
{
- const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obj->pose, ebone_active->name);
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name);
const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset);
for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (EBONE_SELECTABLE(arm, ebone)) {
- const bPoseChannel *pchan = BKE_pose_channel_find_name(obj->pose, ebone->name);
+ const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name);
if (pchan) {
const char *data_test = (const char *)POINTER_OFFSET(pchan, offset);
if (memcmp(data_active, data_test, bytes_size) == 0) {
@@ -938,6 +1189,8 @@ static void select_similar_data_pchan(
}
}
}
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
static void is_ancestor(EditBone *bone, EditBone *ancestor)
@@ -951,58 +1204,68 @@ static void is_ancestor(EditBone *bone, EditBone *ancestor)
bone->temp.ebone = bone->temp.ebone->temp.ebone;
}
-static void select_similar_children(bArmature *arm, EditBone *ebone_act)
+static void select_similar_children(bContext *C)
{
- EditBone *ebone_iter;
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
ebone_iter->temp.ebone = ebone_iter->parent;
}
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
is_ancestor(ebone_iter, ebone_act);
if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter))
ED_armature_ebone_select_set(ebone_iter, true);
}
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
-static void select_similar_children_immediate(bArmature *arm, EditBone *ebone_act)
+static void select_similar_children_immediate(bContext *C)
{
- EditBone *ebone_iter;
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
ED_armature_ebone_select_set(ebone_iter, true);
}
}
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
-static void select_similar_siblings(bArmature *arm, EditBone *ebone_act)
+static void select_similar_siblings(bContext *C)
{
- EditBone *ebone_iter;
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
- if (ebone_act->parent == NULL)
+ if (ebone_act->parent == NULL) {
return;
+ }
- for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
ED_armature_ebone_select_set(ebone_iter, true);
}
}
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
}
static int armature_select_similar_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone_act = CTX_data_active_bone(C);
-
/* Get props */
int type = RNA_enum_get(op->ptr, "type");
float thresh = RNA_float_get(op->ptr, "threshold");
/* Check for active bone */
- if (ebone_act == NULL) {
+ if (CTX_data_active_bone(C) == NULL) {
BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
return OPERATOR_CANCELLED;
}
@@ -1012,45 +1275,43 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op)
switch (type) {
case SIMEDBONE_CHILDREN:
- select_similar_children(arm, ebone_act);
+ select_similar_children(C);
break;
case SIMEDBONE_CHILDREN_IMMEDIATE:
- select_similar_children_immediate(arm, ebone_act);
+ select_similar_children_immediate(C);
break;
case SIMEDBONE_SIBLINGS:
- select_similar_siblings(arm, ebone_act);
+ select_similar_siblings(C);
break;
case SIMEDBONE_LENGTH:
- select_similar_length(arm, ebone_act, thresh);
+ select_similar_length(C, thresh);
break;
case SIMEDBONE_DIRECTION:
- select_similar_direction(arm, ebone_act, thresh);
+ select_similar_direction(C, thresh);
break;
case SIMEDBONE_PREFIX:
- select_similar_prefix(arm, ebone_act);
+ select_similar_prefix(C);
break;
case SIMEDBONE_SUFFIX:
- select_similar_suffix(arm, ebone_act);
+ select_similar_suffix(C);
break;
case SIMEDBONE_LAYER:
- select_similar_layer(arm, ebone_act);
+ select_similar_layer(C);
break;
case SIMEDBONE_GROUP:
select_similar_data_pchan(
- arm, obedit, ebone_act,
+ C,
STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index));
break;
case SIMEDBONE_SHAPE:
select_similar_data_pchan(
- arm, obedit, ebone_act,
+ C,
STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom));
break;
}
#undef STRUCT_SIZE_AND_OFFSET
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
return OPERATOR_FINISHED;
}
@@ -1076,18 +1337,16 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
/* ********************* select hierarchy operator ************** */
+/* No need to convert to multi-objects. Just like we keep the non-active bones
+ * selected we then keep the non-active objects untouched (selected/unselected). */
static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Object *ob;
- bArmature *arm;
+ Object *ob = CTX_data_edit_object(C);
EditBone *ebone_active;
int direction = RNA_enum_get(op->ptr, "direction");
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
bool changed = false;
-
- ob = obedit;
- arm = (bArmature *)ob->data;
+ bArmature *arm = (bArmature *)ob->data;
ebone_active = arm->act_edbone;
if (ebone_active == NULL) {
@@ -1188,49 +1447,57 @@ void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
*/
static int armature_select_mirror_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone, *ebone_mirror_act = NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool active_only = RNA_boolean_get(op->ptr, "only_active");
const bool extend = RNA_boolean_get(op->ptr, "extend");
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- const int flag = ED_armature_ebone_selectflag_get(ebone);
- EBONE_PREV_FLAG_SET(ebone, flag);
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- EditBone *ebone_mirror;
- int flag_new = extend ? EBONE_PREV_FLAG_GET(ebone) : 0;
+ EditBone *ebone, *ebone_mirror_act = NULL;
- if ((ebone_mirror = ED_armature_ebone_get_mirrored(arm->edbo, ebone)) &&
- (EBONE_VISIBLE(arm, ebone_mirror)))
- {
- const int flag_mirror = EBONE_PREV_FLAG_GET(ebone_mirror);
- flag_new |= flag_mirror;
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ const int flag = ED_armature_ebone_selectflag_get(ebone);
+ EBONE_PREV_FLAG_SET(ebone, flag);
+ }
- if (ebone == arm->act_edbone) {
- ebone_mirror_act = ebone_mirror;
- }
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ EditBone *ebone_mirror;
+ int flag_new = extend ? EBONE_PREV_FLAG_GET(ebone) : 0;
+
+ if ((ebone_mirror = ED_armature_ebone_get_mirrored(arm->edbo, ebone)) &&
+ (EBONE_VISIBLE(arm, ebone_mirror)))
+ {
+ const int flag_mirror = EBONE_PREV_FLAG_GET(ebone_mirror);
+ flag_new |= flag_mirror;
+
+ if (ebone == arm->act_edbone) {
+ ebone_mirror_act = ebone_mirror;
+ }
- /* skip all but the active or its mirror */
- if (active_only && !ELEM(arm->act_edbone, ebone, ebone_mirror)) {
- continue;
+ /* skip all but the active or its mirror */
+ if (active_only && !ELEM(arm->act_edbone, ebone, ebone_mirror)) {
+ continue;
+ }
}
- }
- ED_armature_ebone_selectflag_set(ebone, flag_new);
+ ED_armature_ebone_selectflag_set(ebone, flag_new);
+ }
}
- }
- if (ebone_mirror_act) {
- arm->act_edbone = ebone_mirror_act;
- }
+ if (ebone_mirror_act) {
+ arm->act_edbone = ebone_mirror_act;
+ }
- ED_armature_edit_sync_selection(arm->edbo);
+ ED_armature_edit_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1291,17 +1558,23 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
EditBone *ebone_isect_parent = NULL;
EditBone *ebone_isect_child[2];
bool changed;
+ Base *base_dst = NULL;
view3d_operator_needs_opengl(C);
ebone_src = arm->act_edbone;
- ebone_dst = get_nearest_bone(C, event->mval, false);
+ ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst);
/* fallback to object selection */
if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
return OPERATOR_PASS_THROUGH;
}
+ if (base_dst && base_dst->object != obedit) {
+ /* Disconnected, ignore. */
+ return OPERATOR_CANCELLED;
+ }
+
ebone_isect_child[0] = ebone_src;
ebone_isect_child[1] = ebone_dst;
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 8ab8d60af75..c68c2720b0b 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -43,11 +43,16 @@
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_mesh_iterators.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
#include "BKE_subsurf.h"
-#include "BKE_modifier.h"
+
+#include "DEG_depsgraph.h"
#include "ED_armature.h"
#include "ED_mesh.h"
@@ -57,13 +62,9 @@
#include "armature_intern.h"
#include "meshlaplacian.h"
-#if 0
-#include "reeb.h"
-#endif
-
/* ********************************** Bone Skinning *********************************************** */
-static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap)
+static int bone_skinnable_cb(Object *UNUSED(ob), Bone *bone, void *datap)
{
/* Bones that are deforming
* are regarded to be "skinnable" and are eligible for
@@ -89,9 +90,9 @@ static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap)
*/
Bone ***hbone;
int a, segments;
- struct { Object *armob; void *list; int heat; } *data = datap;
+ struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap;
- if (!(ob->mode & OB_MODE_WEIGHT_PAINT) || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(data->is_weight_paint) || !(bone->flag & BONE_HIDDEN_P)) {
if (!(bone->flag & BONE_NO_DEFORM)) {
if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
segments = bone->segments;
@@ -103,7 +104,7 @@ static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap)
for (a = 0; a < segments; a++) {
**hbone = bone;
- ++*hbone;
+ (*hbone)++;
}
}
return segments;
@@ -154,18 +155,17 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
*/
bDeformGroup ***hgroup, *defgroup = NULL;
int a, segments;
- struct { Object *armob; void *list; int heat; } *data = datap;
- int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
+ struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap;
bArmature *arm = data->armob->data;
- if (!wpmode || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!data->is_weight_paint || !(bone->flag & BONE_HIDDEN_P)) {
if (!(bone->flag & BONE_NO_DEFORM)) {
if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
segments = bone->segments;
else
segments = 1;
- if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) {
+ if (!data->is_weight_paint || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) {
if (!(defgroup = defgroup_find_name(ob, bone->name))) {
defgroup = BKE_object_defgroup_add_name(ob, bone->name);
}
@@ -180,7 +180,7 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
for (a = 0; a < segments; a++) {
**hgroup = defgroup;
- ++*hgroup;
+ (*hgroup)++;
}
}
return segments;
@@ -189,9 +189,10 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
return 0;
}
-static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
- bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
- float (*root)[3], float (*tip)[3], const int *selected, float scale)
+static void envelope_bone_weighting(
+ Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
+ bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
+ float (*root)[3], float (*tip)[3], const int *selected, float scale)
{
/* Create vertex group weights from envelopes */
@@ -247,8 +248,9 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
}
}
-static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par,
- int heat, const bool mirror)
+static void add_verts_to_dgroups(
+ ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par,
+ int heat, const bool mirror)
{
/* This functions implements the automatic computation of vertex group
* weights, either through envelopes or using a heat equilibrium.
@@ -258,7 +260,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
* into account and vertex weights can be mirrored.
*
* The mesh vertex positions used are either the final deformed coords
- * from the derivedmesh in weightpaint mode, the final subsurf coords
+ * from the evaluated mesh in weightpaint mode, the final subsurf coords
* when parenting, or simply the original mesh coords.
*/
@@ -272,12 +274,13 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
float (*root)[3], (*tip)[3], (*verts)[3];
int *selected;
int numbones, vertsfilled = 0, i, j, segments = 0;
- int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
- struct { Object *armob; void *list; int heat; } looper_data;
+ const bool wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
+ struct { Object *armob; void *list; int heat; bool is_weight_paint; } looper_data;
looper_data.armob = par;
looper_data.heat = heat;
looper_data.list = NULL;
+ looper_data.is_weight_paint = wpmode;
/* count the number of skinnable bones */
numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
@@ -322,7 +325,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
if (bone->segments > 1) {
segments = bone->segments;
- b_bone_spline_setup(pchan, 1, bbone_array);
+ b_bone_spline_setup(pchan, true, bbone_array);
bbone = bbone_array;
}
}
@@ -371,15 +374,11 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");
if (wpmode) {
- /* if in weight paint mode, use final verts from derivedmesh */
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ /* if in weight paint mode, use final verts from evaluated mesh */
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH);
- if (dm->foreachMappedVert) {
- mesh_get_mapped_verts_coords(dm, verts, mesh->totvert);
- vertsfilled = 1;
- }
-
- dm->release(dm);
+ BKE_mesh_foreach_mapped_vert_coords_get(me_eval, verts, mesh->totvert);
+ vertsfilled = 1;
}
else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
/* is subsurf on? Lets use the verts on the limit surface then.
@@ -400,15 +399,17 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
if (heat) {
const char *error = NULL;
- heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
- root, tip, selected, &error);
+ heat_bone_weighting(
+ ob, mesh, verts, numbones, dgrouplist, dgroupflip,
+ root, tip, selected, &error);
if (error) {
BKE_report(reports, RPT_WARNING, error);
}
}
else {
- envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
- dgroupflip, root, tip, selected, mat4_to_scale(par->obmat));
+ envelope_bone_weighting(
+ ob, mesh, verts, numbones, bonelist, dgrouplist,
+ dgroupflip, root, tip, selected, mat4_to_scale(par->obmat));
}
/* only generated in some cases but can call anyway */
@@ -424,8 +425,9 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
MEM_freeN(verts);
}
-void ED_object_vgroup_calc_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par,
- const int mode, const bool mirror)
+void ED_object_vgroup_calc_from_armature(
+ ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par,
+ const int mode, const bool mirror)
{
/* Lets try to create some vertex groups
* based on the bones of the parent armature.
@@ -451,6 +453,6 @@ void ED_object_vgroup_calc_from_armature(ReportList *reports, Scene *scene, Obje
* that are populated with the vertices for which the
* bone is closest.
*/
- add_verts_to_dgroups(reports, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
+ add_verts_to_dgroups(reports, depsgraph, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
}
}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index c6cd9475008..53b07c59973 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -39,11 +39,12 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+
#include "ED_armature.h"
#include "ED_util.h"
@@ -130,6 +131,16 @@ void bone_free(bArmature *arm, EditBone *bone)
MEM_freeN(bone->prop);
}
+ /* Clear references from other edit bones. */
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->bbone_next == bone) {
+ ebone->bbone_next = NULL;
+ }
+ if (ebone->bbone_prev == bone) {
+ ebone->bbone_prev = NULL;
+ }
+ }
+
BLI_freelinkN(arm->edbo, bone);
}
@@ -425,7 +436,7 @@ void ED_armature_edit_transform_mirror_update(Object *obedit)
/* Armature EditMode Conversions */
/* converts Bones to EditBone list, used for tools as well */
-EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone *actBone)
+static EditBone *make_boneList_rec(ListBase *edbo, ListBase *bones, EditBone *parent, Bone *actBone)
{
EditBone *eBone;
EditBone *eBoneAct = NULL;
@@ -434,6 +445,7 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
for (curBone = bones->first; curBone; curBone = curBone->next) {
eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
+ eBone->temp.bone = curBone;
/* Copy relevant data from bone to eBone
* Keep selection logic in sync with ED_armature_edit_sync_selection.
@@ -489,6 +501,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
eBone->scaleIn = curBone->scaleIn;
eBone->scaleOut = curBone->scaleOut;
+ eBone->bbone_prev_type = curBone->bbone_prev_type;
+ eBone->bbone_next_type = curBone->bbone_next_type;
+
if (curBone->prop)
eBone->prop = IDP_CopyProperty(curBone->prop);
@@ -496,7 +511,7 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
/* Add children if necessary */
if (curBone->childbase.first) {
- eBoneTest = make_boneList(edbo, &curBone->childbase, eBone, actBone);
+ eBoneTest = make_boneList_rec(edbo, &curBone->childbase, eBone, actBone);
if (eBoneTest)
eBoneAct = eBoneTest;
}
@@ -508,6 +523,36 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
return eBoneAct;
}
+static EditBone *find_ebone_link(ListBase *edbo, Bone *link)
+{
+ if (link != NULL) {
+ for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->temp.bone == link) {
+ return ebone;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+EditBone *make_boneList(ListBase *edbo, ListBase *bones, struct Bone *actBone)
+{
+ BLI_assert(!edbo->first && !edbo->last);
+
+ EditBone *active = make_boneList_rec(edbo, bones, NULL, actBone);
+
+ for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ Bone *bone = ebone->temp.bone;
+
+ /* Convert custom B-Bone handle links. */
+ ebone->bbone_prev = find_ebone_link(edbo, bone->bbone_prev);
+ ebone->bbone_next = find_ebone_link(edbo, bone->bbone_next);
+ }
+
+ return active;
+}
+
/* This function:
* - sets local head/tail rest locations using parent bone's arm_mat.
* - calls BKE_armature_where_is_bone() which uses parent's transform (arm_mat) to define this bone's transform.
@@ -654,6 +699,8 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
newBone->scaleIn = eBone->scaleIn;
newBone->scaleOut = eBone->scaleOut;
+ newBone->bbone_prev_type = eBone->bbone_prev_type;
+ newBone->bbone_next_type = eBone->bbone_next_type;
if (eBone->prop)
newBone->prop = IDP_CopyProperty(eBone->prop);
@@ -672,6 +719,14 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
else {
BLI_addtail(&arm->bonebase, newBone);
}
+
+ /* Also transfer B-Bone custom handles. */
+ if (eBone->bbone_prev) {
+ newBone->bbone_prev = eBone->bbone_prev->temp.bone;
+ }
+ if (eBone->bbone_next) {
+ newBone->bbone_next = eBone->bbone_next->temp.bone;
+ }
}
/* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */
@@ -680,11 +735,11 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
/* so all users of this armature should get rebuilt */
for (obt = bmain->object.first; obt; obt = obt->id.next) {
if (obt->data == arm) {
- BKE_pose_rebuild(obt, arm);
+ BKE_pose_rebuild(bmain, obt, arm, true);
}
}
- DAG_id_tag_update(&arm->id, 0);
+ DEG_id_tag_update(&arm->id, 0);
}
void ED_armature_edit_free(struct bArmature *arm)
@@ -714,9 +769,7 @@ void ED_armature_to_edit(bArmature *arm)
{
ED_armature_edit_free(arm);
arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature");
- arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, NULL, arm->act_bone);
-
-// BIF_freeTemplates(); /* force template update when entering editmode */
+ arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, arm->act_bone);
}
/* *************************************************************** */
@@ -763,6 +816,12 @@ void ED_armature_ebone_listbase_copy(ListBase *lb_dst, ListBase *lb_src)
if (ebone_dst->parent) {
ebone_dst->parent = ebone_dst->parent->temp.ebone;
}
+ if (ebone_dst->bbone_next) {
+ ebone_dst->bbone_next = ebone_dst->bbone_next->temp.ebone;
+ }
+ if (ebone_dst->bbone_prev) {
+ ebone_dst->bbone_prev = ebone_dst->bbone_prev->temp.ebone;
+ }
}
}
diff --git a/source/blender/editors/armature/editarmature_generate.c b/source/blender/editors/armature/editarmature_generate.c
deleted file mode 100644
index f0135676523..00000000000
--- a/source/blender/editors/armature/editarmature_generate.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/armature/editarmature_generate.c
- * \ingroup edarmature
- */
-
-#include "DNA_scene_types.h"
-#include "DNA_armature_types.h"
-
-#include "BLI_math.h"
-#include "BLI_graph.h"
-
-#include "ED_armature.h"
-#include "BIF_generate.h"
-
-void setBoneRollFromNormal(EditBone *bone, const float no[3], float UNUSED(invmat[4][4]), float tmat[3][3])
-{
- if (no != NULL && !is_zero_v3(no)) {
- float normal[3];
-
- copy_v3_v3(normal, no);
- mul_m3_v3(tmat, normal);
-
- bone->roll = ED_armature_ebone_roll_to_vector(bone, normal, false);
- }
-}
-
-float calcArcCorrelation(BArcIterator *iter, int start, int end, float v0[3], float n[3])
-{
- int len = 2 + abs(end - start);
-
- if (len > 2) {
- float avg_t = 0.0f;
- float s_t = 0.0f;
- float s_xyz = 0.0f;
- int i;
-
- /* First pass, calculate average */
- for (i = start; i <= end; i++) {
- float v[3];
-
- IT_peek(iter, i);
- sub_v3_v3v3(v, iter->p, v0);
- avg_t += dot_v3v3(v, n);
- }
-
- avg_t /= dot_v3v3(n, n);
- avg_t += 1.0f; /* adding start (0) and end (1) values */
- avg_t /= len;
-
- /* Second pass, calculate s_xyz and s_t */
- for (i = start; i <= end; i++) {
- float v[3], d[3];
- float dt;
-
- IT_peek(iter, i);
- sub_v3_v3v3(v, iter->p, v0);
- project_v3_v3v3(d, v, n);
- sub_v3_v3(v, d);
-
- dt = len_v3(d) - avg_t;
-
- s_t += dt * dt;
- s_xyz += dot_v3v3(v, v);
- }
-
- /* adding start(0) and end(1) values to s_t */
- s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t);
-
- return 1.0f - s_xyz / s_t;
- }
- else {
- return 1.0f;
- }
-}
-
-int nextFixedSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float UNUSED(head[3]), float p[3])
-{
- static float stroke_length = 0;
- static float current_length;
- static char n;
- float *v1, *v2;
- float length_threshold;
- int i;
-
- if (stroke_length == 0) {
- current_length = 0;
-
- IT_peek(iter, start);
- v1 = iter->p;
-
- for (i = start + 1; i <= end; i++) {
- IT_peek(iter, i);
- v2 = iter->p;
-
- stroke_length += len_v3v3(v1, v2);
-
- v1 = v2;
- }
-
- n = 0;
- current_length = 0;
- }
-
- n++;
-
- length_threshold = n * stroke_length / toolsettings->skgen_subdivision_number;
-
- IT_peek(iter, start);
- v1 = iter->p;
-
- /* < and not <= because we don't care about end, it is P_EXACT anyway */
- for (i = start + 1; i < end; i++) {
- IT_peek(iter, i);
- v2 = iter->p;
-
- current_length += len_v3v3(v1, v2);
-
- if (current_length >= length_threshold) {
- copy_v3_v3(p, v2);
- return i;
- }
-
- v1 = v2;
- }
-
- stroke_length = 0;
-
- return -1;
-}
-int nextAdaptativeSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float head[3], float p[3])
-{
- float correlation_threshold = toolsettings->skgen_correlation_limit;
- float *start_p;
- float n[3];
- int i;
-
- IT_peek(iter, start);
- start_p = iter->p;
-
- for (i = start + 2; i <= end; i++) {
- /* Calculate normal */
- IT_peek(iter, i);
- sub_v3_v3v3(n, iter->p, head);
-
- if (calcArcCorrelation(iter, start, i, start_p, n) < correlation_threshold) {
- IT_peek(iter, i - 1);
- copy_v3_v3(p, iter->p);
- return i - 1;
- }
- }
-
- return -1;
-}
-
-int nextLengthSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float head[3], float p[3])
-{
- float lengthLimit = toolsettings->skgen_length_limit;
- int same = 1;
- int i;
-
- i = start + 1;
- while (i <= end) {
- float *vec0;
- float *vec1;
-
- IT_peek(iter, i - 1);
- vec0 = iter->p;
-
- IT_peek(iter, i);
- vec1 = iter->p;
-
- /* If lengthLimit hits the current segment */
- if (len_v3v3(vec1, head) > lengthLimit) {
- if (same == 0) {
- float dv[3], off[3];
- float a, b, c, f;
-
- /* Solve quadratic distance equation */
- sub_v3_v3v3(dv, vec1, vec0);
- a = dot_v3v3(dv, dv);
-
- sub_v3_v3v3(off, vec0, head);
- b = 2 * dot_v3v3(dv, off);
-
- c = dot_v3v3(off, off) - (lengthLimit * lengthLimit);
-
- f = (-b + sqrtf(b * b - 4 * a * c)) / (2 * a);
-
- //printf("a %f, b %f, c %f, f %f\n", a, b, c, f);
-
- if (isnan(f) == 0 && f < 1.0f) {
- copy_v3_v3(p, dv);
- mul_v3_fl(p, f);
- add_v3_v3(p, vec0);
- }
- else {
- copy_v3_v3(p, vec1);
- }
- }
- else {
- float dv[3];
-
- sub_v3_v3v3(dv, vec1, vec0);
- normalize_v3(dv);
-
- copy_v3_v3(p, dv);
- mul_v3_fl(p, lengthLimit);
- add_v3_v3(p, head);
- }
-
- return i - 1; /* restart at lower bound */
- }
- else {
- i++;
- same = 0; // Reset same
- }
- }
-
- return -1;
-}
-
-EditBone *subdivideArcBy(ToolSettings *toolsettings, bArmature *arm, ListBase *UNUSED(editbones), BArcIterator *iter,
- float invmat[4][4], float tmat[3][3], NextSubdivisionFunc next_subdividion)
-{
- EditBone *lastBone = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- float *normal = NULL;
- float size_buffer = 1.2;
- int bone_start = 0;
- int end = iter->length;
- int index;
-
- IT_head(iter);
-
- parent = ED_armature_ebone_add(arm, "Bone");
- copy_v3_v3(parent->head, iter->p);
-
- if (iter->size > FLT_EPSILON) {
- parent->rad_head = iter->size * size_buffer;
- }
-
- normal = iter->no;
-
- index = next_subdividion(toolsettings, iter, bone_start, end, parent->head, parent->tail);
- while (index != -1) {
- IT_peek(iter, index);
-
- child = ED_armature_ebone_add(arm, "Bone");
- copy_v3_v3(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED;
-
- if (iter->size > FLT_EPSILON) {
- child->rad_head = iter->size * size_buffer;
- parent->rad_tail = iter->size * size_buffer;
- }
-
- /* going to next bone, fix parent */
- mul_m4_v3(invmat, parent->tail);
- mul_m4_v3(invmat, parent->head);
- setBoneRollFromNormal(parent, normal, invmat, tmat);
-
- parent = child; // new child is next parent
- bone_start = index; // start next bone from current index
-
- normal = iter->no; /* use normal at head, not tail */
-
- index = next_subdividion(toolsettings, iter, bone_start, end, parent->head, parent->tail);
- }
-
- iter->tail(iter);
-
- copy_v3_v3(parent->tail, iter->p);
- if (iter->size > FLT_EPSILON) {
- parent->rad_tail = iter->size * size_buffer;
- }
-
- /* fix last bone */
- mul_m4_v3(invmat, parent->tail);
- mul_m4_v3(invmat, parent->head);
- setBoneRollFromNormal(parent, iter->no, invmat, tmat);
- lastBone = parent;
-
- return lastBone;
-}
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
deleted file mode 100644
index 89e510e6f3e..00000000000
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ /dev/null
@@ -1,2644 +0,0 @@
-/*
- * ***** 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): Martin Poirier
- *
- * ***** END GPL LICENSE BLOCK *****
- * autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...)
- */
-
-/** \file blender/editors/armature/editarmature_retarget.c
- * \ingroup edarmature
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "PIL_time.h"
-
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
-#include "BKE_constraint.h"
-#include "BKE_armature.h"
-#include "BKE_context.h"
-#include "BKE_main.h"
-
-#include "ED_armature.h"
-#include "ED_undo.h"
-
-#include "BIF_retarget.h"
-
-#include "armature_intern.h"
-
-/************ RIG RETARGET DATA STRUCTURES ***************/
-
-typedef struct MemoNode {
- float weight;
- int next;
-} MemoNode;
-
-typedef struct RetargetParam {
- RigGraph *rigg;
- RigArc *iarc;
- RigNode *inode_start;
- bContext *context;
-} RetargetParam;
-
-typedef enum {
- RETARGET_LENGTH,
- RETARGET_AGGRESSIVE
-} RetargetMode;
-
-typedef enum {
- METHOD_BRUTE_FORCE = 0,
- METHOD_MEMOIZE = 1
-} RetargetMethod;
-
-typedef enum {
- ARC_FREE = 0,
- ARC_TAKEN = 1,
- ARC_USED = 2
-} ArcUsageFlags;
-
-static RigGraph *GLOBAL_RIGG = NULL;
-
-/*******************************************************************************************************/
-
-void exec_retargetArctoArc(TaskPool * __restrict pool, void *taskdata, int threadid);
-
-static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second);
-float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]);
-
-/* two levels */
-#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX)
-
-/*********************************** EDITBONE UTILS ****************************************************/
-
-static int countEditBoneChildren(ListBase *list, EditBone *parent)
-{
- EditBone *ebone;
- int count = 0;
-
- for (ebone = list->first; ebone; ebone = ebone->next) {
- if (ebone->parent == parent) {
- count++;
- }
- }
-
- return count;
-}
-
-static EditBone *nextEditBoneChild(ListBase *list, EditBone *parent, int n)
-{
- EditBone *ebone;
-
- for (ebone = list->first; ebone; ebone = ebone->next) {
- if (ebone->parent == parent) {
- if (n == 0) {
- return ebone;
- }
- n--;
- }
- }
-
- return NULL;
-}
-
-static void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3])
-{
- float mat[3][3], nor[3];
-
- sub_v3_v3v3(nor, bone->tail, bone->head);
-
- vec_roll_to_mat3(nor, roll, mat);
- copy_v3_v3(up_axis, mat[2]);
-}
-
-static float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3])
-{
- float nor[3], new_up_axis[3], x_axis[3], z_axis[3];
-
- copy_v3_v3(new_up_axis, old_up_axis);
- mul_qt_v3(qrot, new_up_axis);
-
- sub_v3_v3v3(nor, bone->tail, bone->head);
-
- cross_v3_v3v3(x_axis, nor, aligned_axis);
- cross_v3_v3v3(z_axis, x_axis, nor);
-
- normalize_v3(new_up_axis);
- normalize_v3(x_axis);
- normalize_v3(z_axis);
-
- if (dot_v3v3(new_up_axis, x_axis) < 0) {
- negate_v3(x_axis);
- }
-
- if (dot_v3v3(new_up_axis, z_axis) < 0) {
- negate_v3(z_axis);
- }
-
- if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis)) {
- rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */
- return ED_armature_ebone_roll_to_vector(bone, x_axis, false);
- }
- else {
- rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */
- return ED_armature_ebone_roll_to_vector(bone, z_axis, false);
- }
-}
-
-static float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4], float up_axis[3])
-{
- if (previous == NULL) {
- /* default to up_axis if no previous */
- return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis);
- }
- else {
- float new_up_axis[3];
- float vec_first[3], vec_second[3], normal[3];
-
- if (previous->bone) {
- sub_v3_v3v3(vec_first, previous->bone->tail, previous->bone->head);
- }
- else if (previous->prev->bone) {
- sub_v3_v3v3(vec_first, edge->bone->head, previous->prev->bone->tail);
- }
- else {
- /* default to up_axis if first bone in the chain is an offset */
- return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis);
- }
-
- sub_v3_v3v3(vec_second, edge->bone->tail, edge->bone->head);
-
- normalize_v3(vec_first);
- normalize_v3(vec_second);
-
- cross_v3_v3v3(normal, vec_first, vec_second);
- normalize_v3(normal);
-
- axis_angle_to_quat(qroll, vec_second, edge->up_angle);
-
- mul_qt_v3(qroll, normal);
-
- copy_v3_v3(new_up_axis, edge->up_axis);
- mul_qt_v3(qrot, new_up_axis);
-
- normalize_v3(new_up_axis);
-
- /* real qroll between normal and up_axis */
- rotation_between_vecs_to_quat(qroll, new_up_axis, normal);
-
- return ED_armature_ebone_roll_to_vector(edge->bone, normal, false);
- }
-}
-
-float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4])
-{
- float new_up_axis[3];
-
- copy_v3_v3(new_up_axis, old_up_axis);
- mul_qt_v3(qrot, new_up_axis);
-
- return ED_armature_ebone_roll_to_vector(bone, new_up_axis, false);
-}
-
-/************************************ DESTRUCTORS ******************************************************/
-
-static void RIG_freeRigArc(BArc *arc)
-{
- BLI_freelistN(&((RigArc *)arc)->edges);
-}
-
-void RIG_freeRigGraph(BGraph *rg)
-{
- RigGraph *rigg = (RigGraph *)rg;
- BNode *node;
- BArc *arc;
-
- BLI_task_pool_free(rigg->task_pool);
- BLI_task_scheduler_free(rigg->task_scheduler);
-
- if (rigg->link_mesh) {
- REEB_freeGraph(rigg->link_mesh);
- }
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- RIG_freeRigArc(arc);
- }
- BLI_freelistN(&rg->arcs);
-
- for (node = rg->nodes.first; node; node = node->next) {
- BLI_freeNode(rg, (BNode *)node);
- }
- BLI_freelistN(&rg->nodes);
-
- BLI_freelistN(&rigg->controls);
-
- BLI_ghash_free(rigg->bones_map, NULL, NULL);
- BLI_ghash_free(rigg->controls_map, NULL, NULL);
-
- if (rigg->flag & RIG_FREE_BONELIST) {
- BLI_freelistN(rigg->editbones);
- MEM_freeN(rigg->editbones);
- }
-
- MEM_freeN(rg);
-}
-
-/************************************* ALLOCATORS ******************************************************/
-
-static RigGraph *newRigGraph(void)
-{
- RigGraph *rg;
- int totthread;
-
- rg = MEM_callocN(sizeof(RigGraph), "rig graph");
-
- rg->head = NULL;
-
- rg->bones_map = BLI_ghash_str_new("newRigGraph bones gh");
- rg->controls_map = BLI_ghash_str_new("newRigGraph cont gh");
-
- rg->free_arc = RIG_freeRigArc;
- rg->free_node = NULL;
-
-#ifdef USE_THREADS
- totthread = TASK_SCHEDULER_AUTO_THREADS;
-#else
- totthread = TASK_SCHEDULER_SINGLE_THREAD;
-#endif
-
- rg->task_scheduler = BLI_task_scheduler_create(totthread);
- rg->task_pool = BLI_task_pool_create(rg->task_scheduler, NULL);
-
- return rg;
-}
-
-static RigArc *newRigArc(RigGraph *rg)
-{
- RigArc *arc;
-
- arc = MEM_callocN(sizeof(RigArc), "rig arc");
- arc->count = 0;
- BLI_addtail(&rg->arcs, arc);
-
- return arc;
-}
-
-static RigControl *newRigControl(RigGraph *rg)
-{
- RigControl *ctrl;
-
- ctrl = MEM_callocN(sizeof(RigControl), "rig control");
-
- BLI_addtail(&rg->controls, ctrl);
-
- return ctrl;
-}
-
-static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3])
-{
- RigNode *node;
- node = MEM_callocN(sizeof(RigNode), "rig node");
- BLI_addtail(&rg->nodes, node);
-
- copy_v3_v3(node->p, p);
- node->degree = 1;
- node->arcs = NULL;
-
- arc->head = node;
-
- return node;
-}
-
-static void addRigNodeHead(RigGraph *UNUSED(rg), RigArc *arc, RigNode *node)
-{
- node->degree++;
-
- arc->head = node;
-}
-
-static RigNode *newRigNode(RigGraph *rg, float p[3])
-{
- RigNode *node;
- node = MEM_callocN(sizeof(RigNode), "rig node");
- BLI_addtail(&rg->nodes, node);
-
- copy_v3_v3(node->p, p);
- node->degree = 0;
- node->arcs = NULL;
-
- return node;
-}
-
-static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3])
-{
- RigNode *node = newRigNode(rg, p);
-
- node->degree = 1;
- arc->tail = node;
-
- return node;
-}
-
-static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge)
-{
- BLI_addtail(&arc->edges, edge);
-
- if (edge->prev == NULL) {
- copy_v3_v3(edge->head, arc->head->p);
- }
- else {
- RigEdge *last_edge = edge->prev;
- copy_v3_v3(edge->head, last_edge->tail);
- RIG_calculateEdgeAngles(last_edge, edge);
- }
-
- edge->length = len_v3v3(edge->head, edge->tail);
-
- arc->length += edge->length;
-
- arc->count += 1;
-}
-
-static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone)
-{
- RigEdge *edge;
-
- edge = MEM_callocN(sizeof(RigEdge), "rig edge");
-
- copy_v3_v3(edge->tail, tail);
- edge->bone = bone;
-
- if (bone) {
- getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis);
- }
-
- RIG_appendEdgeToArc(arc, edge);
-}
-/************************************** CLONING TEMPLATES **********************************************/
-
-static void renameTemplateBone(char *name, char *template_name, ListBase *editbones, char *side_string, char *num_string)
-{
- int i, j;
-
- for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) {
- if (template_name[i] == '&') {
- if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') {
- j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME);
- i++;
- }
- else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') {
- j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME);
- i++;
- }
- else {
- name[j] = template_name[i];
- j++;
- }
- }
- else {
- name[j] = template_name[i];
- j++;
- }
- }
-
- name[j] = '\0';
-
- ED_armature_ebone_unique_name(editbones, name, NULL);
-}
-
-static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash, char *side_string, char *num_string)
-{
- RigControl *ctrl;
- char name[MAXBONENAME];
-
- ctrl = newRigControl(rg);
-
- copy_v3_v3(ctrl->head, src_ctrl->head);
- copy_v3_v3(ctrl->tail, src_ctrl->tail);
- copy_v3_v3(ctrl->up_axis, src_ctrl->up_axis);
- copy_v3_v3(ctrl->offset, src_ctrl->offset);
-
- ctrl->tail_mode = src_ctrl->tail_mode;
- ctrl->flag = src_ctrl->flag;
-
- renameTemplateBone(name, src_ctrl->bone->name, rg->editbones, side_string, num_string);
- ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob);
- ctrl->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone);
-
- ctrl->link = src_ctrl->link;
- ctrl->link_tail = src_ctrl->link_tail;
-
- return ctrl;
-}
-
-static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash, char *side_string, char *num_string)
-{
- RigEdge *src_edge;
- RigArc *arc;
-
- arc = newRigArc(rg);
-
- arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head);
- arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail);
-
- arc->head->degree++;
- arc->tail->degree++;
-
- arc->length = src_arc->length;
-
- arc->count = src_arc->count;
-
- for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next) {
- RigEdge *edge;
-
- edge = MEM_callocN(sizeof(RigEdge), "rig edge");
-
- copy_v3_v3(edge->head, src_edge->head);
- copy_v3_v3(edge->tail, src_edge->tail);
- copy_v3_v3(edge->up_axis, src_edge->up_axis);
-
- edge->length = src_edge->length;
- edge->angle = src_edge->angle;
- edge->up_angle = src_edge->up_angle;
-
- if (src_edge->bone != NULL) {
- char name[MAXBONENAME];
- renameTemplateBone(name, src_edge->bone->name, rg->editbones, side_string, num_string);
- edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob);
- edge->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone);
- }
-
- BLI_addtail(&arc->edges, edge);
- }
-
- return arc;
-}
-
-static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob, char *side_string, char *num_string)
-{
- GHash *ptr_hash;
- RigNode *node;
- RigArc *arc;
- RigControl *ctrl;
- RigGraph *rg;
-
- ptr_hash = BLI_ghash_ptr_new("cloneRigGraph gh");
-
- rg = newRigGraph();
-
- rg->ob = ob;
- rg->editbones = editbones;
-
- preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */
- preEditBoneDuplicate(src->editbones); /* prime bones for duplication */
-
- /* Clone nodes */
- for (node = src->nodes.first; node; node = node->next) {
- RigNode *cloned_node = newRigNode(rg, node->p);
- BLI_ghash_insert(ptr_hash, node, cloned_node);
- }
-
- rg->head = BLI_ghash_lookup(ptr_hash, src->head);
-
- /* Clone arcs */
- for (arc = src->arcs.first; arc; arc = arc->next) {
- cloneArc(rg, src, arc, ptr_hash, side_string, num_string);
- }
-
- /* Clone controls */
- for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next) {
- cloneControl(rg, src, ctrl, ptr_hash, side_string, num_string);
- }
-
- /* Relink bones properly */
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- RigEdge *edge;
-
- for (edge = arc->edges.first; edge; edge = edge->next) {
- if (edge->bone != NULL) {
- EditBone *bone;
-
- updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob);
-
- if (edge->bone->parent) {
- bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent);
-
- if (bone != NULL) {
- edge->bone->parent = bone;
- }
- else {
- /* disconnect since parent isn't cloned
- * this will only happen when cloning from selected bones
- * */
- edge->bone->flag &= ~BONE_CONNECTED;
- }
- }
- }
- }
- }
-
- for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
- EditBone *bone;
-
- updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob);
-
- if (ctrl->bone->parent) {
- bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent);
-
- if (bone != NULL) {
- ctrl->bone->parent = bone;
- }
- else {
- /* disconnect since parent isn't cloned
- * this will only happen when cloning from selected bones
- * */
- ctrl->bone->flag &= ~BONE_CONNECTED;
- }
- }
-
- ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link);
- ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail);
- }
-
- BLI_ghash_free(ptr_hash, NULL, NULL);
-
- return rg;
-}
-
-
-/*******************************************************************************************************/
-
-static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second)
-{
- float vec_first[3], vec_second[3];
-
- sub_v3_v3v3(vec_first, edge_first->tail, edge_first->head);
- sub_v3_v3v3(vec_second, edge_second->tail, edge_second->head);
-
- normalize_v3(vec_first);
- normalize_v3(vec_second);
-
- edge_first->angle = angle_normalized_v3v3(vec_first, vec_second);
-
- if (edge_second->bone != NULL) {
- float normal[3];
-
- cross_v3_v3v3(normal, vec_first, vec_second);
- normalize_v3(normal);
-
- edge_second->up_angle = angle_normalized_v3v3(normal, edge_second->up_axis);
- }
-}
-
-/************************************ CONTROL BONES ****************************************************/
-
-static void RIG_addControlBone(RigGraph *rg, EditBone *bone)
-{
- RigControl *ctrl = newRigControl(rg);
- ctrl->bone = bone;
- copy_v3_v3(ctrl->head, bone->head);
- copy_v3_v3(ctrl->tail, bone->tail);
- getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis);
- ctrl->tail_mode = TL_NONE;
-
- BLI_ghash_insert(rg->controls_map, bone->name, ctrl);
-}
-
-static int RIG_parentControl(RigControl *ctrl, EditBone *link)
-{
- if (link) {
- float offset[3];
- int flag = 0;
-
- sub_v3_v3v3(offset, ctrl->bone->head, link->head);
-
- /* if root matches, check for direction too */
- if (dot_v3v3(offset, offset) < 0.0001f) {
- float vbone[3], vparent[3];
-
- flag |= RIG_CTRL_FIT_ROOT;
-
- sub_v3_v3v3(vbone, ctrl->bone->tail, ctrl->bone->head);
- sub_v3_v3v3(vparent, link->tail, link->head);
-
- /* test for opposite direction */
- if (dot_v3v3(vbone, vparent) > 0) {
- float nor[3];
- float len;
-
- cross_v3_v3v3(nor, vbone, vparent);
-
- len = dot_v3v3(nor, nor);
- if (len < 0.0001f) {
- flag |= RIG_CTRL_FIT_BONE;
- }
- }
- }
-
- /* Bail out if old one is automatically better */
- if (flag < ctrl->flag) {
- return 0;
- }
-
- /* if there's already a link
- * overwrite only if new link is higher in the chain */
- if (ctrl->link && flag == ctrl->flag) {
- EditBone *bone = NULL;
-
- for (bone = ctrl->link; bone; bone = bone->parent) {
- /* if link is in the chain, break and use that one */
- if (bone == link) {
- break;
- }
- }
-
- /* not in chain, don't update link */
- if (bone == NULL) {
- return 0;
- }
- }
-
-
- ctrl->link = link;
- ctrl->flag = flag;
-
- copy_v3_v3(ctrl->offset, offset);
-
- return 1;
- }
-
- return 0;
-}
-
-static void RIG_reconnectControlBones(RigGraph *rg)
-{
- RigControl *ctrl;
- bool changed = true;
-
- /* first pass, link to deform bones */
- for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
- bPoseChannel *pchan;
- bConstraint *con;
- int found = 0;
-
- /* DO SOME MAGIC HERE */
- for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- int target_index;
-
- cti->get_constraint_targets(con, &targets);
-
- for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) {
- if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
- /* SET bone link to bone corresponding to pchan */
- EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name);
-
- /* Making sure bone is in this armature */
- if (link != NULL) {
- /* for pole targets, link to parent bone instead, if possible */
- if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1) {
- if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name)) {
- link = link->parent;
- }
- }
-
- found = RIG_parentControl(ctrl, link);
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- /* if not found yet, check parent */
- if (found == 0) {
- if (ctrl->bone->parent) {
- /* make sure parent is a deforming bone
- * NULL if not
- * */
- EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name);
-
- found = RIG_parentControl(ctrl, link);
- }
-
- /* check if bone is not superposed on another one */
- {
- RigArc *arc;
- RigArc *best_arc = NULL;
- EditBone *link = NULL;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- RigEdge *edge;
- for (edge = arc->edges.first; edge; edge = edge->next) {
- if (edge->bone) {
- int fit = 0;
-
- fit = len_v3v3(ctrl->bone->head, edge->bone->head) < 0.0001f;
- fit = fit || len_v3v3(ctrl->bone->tail, edge->bone->tail) < 0.0001f;
-
- if (fit) {
- /* pick the bone on the arc with the lowest symmetry level
- * means you connect control to the trunk of the skeleton */
- if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) {
- best_arc = arc;
- link = edge->bone;
- }
- }
- }
- }
- }
-
- found = RIG_parentControl(ctrl, link);
- }
- }
-
- /* if not found yet, check child */
- if (found == 0) {
- RigArc *arc;
- RigArc *best_arc = NULL;
- EditBone *link = NULL;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- RigEdge *edge;
- for (edge = arc->edges.first; edge; edge = edge->next) {
- if (edge->bone && edge->bone->parent == ctrl->bone) {
- /* pick the bone on the arc with the lowest symmetry level
- * means you connect control to the trunk of the skeleton */
- if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) {
- best_arc = arc;
- link = edge->bone;
- }
- }
- }
- }
-
- found = RIG_parentControl(ctrl, link);
- }
-
- }
-
-
- /* second pass, make chains in control bones */
- while (changed) {
- changed = false;
-
- for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
- /* if control is not linked yet */
- if (ctrl->link == NULL) {
- bPoseChannel *pchan;
- bConstraint *con;
- RigControl *ctrl_parent = NULL;
- RigControl *ctrl_child;
- int found = 0;
-
- if (ctrl->bone->parent) {
- ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name);
- }
-
- /* check constraints first */
-
- /* DO SOME MAGIC HERE */
- for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
- /* SET bone link to ctrl corresponding to pchan */
- RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name);
-
- /* if owner is a control bone, link with it */
- if (link && link->link) {
- RIG_parentControl(ctrl, link->bone);
- found = 1;
- break;
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- if (found == 0) {
- /* check if parent is already linked */
- if (ctrl_parent && ctrl_parent->link) {
- RIG_parentControl(ctrl, ctrl_parent->bone);
- changed = true;
- }
- else {
- /* check childs */
- for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) {
- /* if a child is linked, link to that one */
- if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone) {
- RIG_parentControl(ctrl, ctrl_child->bone);
- changed = true;
- break;
- }
- }
- }
- }
- }
- }
- }
-
- /* third pass, link control tails */
- for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
- /* fit bone already means full match, so skip those */
- if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0) {
- GHashIterator ghi;
-
- /* look on deform bones first */
- BLI_ghashIterator_init(&ghi, rg->bones_map);
-
- for (; !BLI_ghashIterator_done(&ghi); BLI_ghashIterator_step(&ghi)) {
- EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi);
-
- /* don't link with parent */
- if (bone->parent != ctrl->bone) {
- if (len_v3v3(ctrl->bone->tail, bone->head) < 0.01f) {
- ctrl->tail_mode = TL_HEAD;
- ctrl->link_tail = bone;
- break;
- }
- else if (len_v3v3(ctrl->bone->tail, bone->tail) < 0.01f) {
- ctrl->tail_mode = TL_TAIL;
- ctrl->link_tail = bone;
- break;
- }
- }
- }
-
- /* if we haven't found one yet, look in control bones */
- if (ctrl->tail_mode == TL_NONE) {
- /* pass */
- }
- }
- }
-
-}
-
-/*******************************************************************************************************/
-
-static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2)
-{
- RigEdge *edge, *next_edge;
-
- /* ignore cases where joint is at start or end */
- if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) {
- return;
- }
-
- /* swap arcs to make sure arc1 is before arc2 */
- if (joined_arc1->head == joined_arc2->tail) {
- RigArc *tmp = joined_arc1;
- joined_arc1 = joined_arc2;
- joined_arc2 = tmp;
- }
-
- for (edge = joined_arc2->edges.first; edge; edge = next_edge) {
- next_edge = edge->next;
-
- RIG_appendEdgeToArc(joined_arc1, edge);
- }
-
- joined_arc1->tail = joined_arc2->tail;
-
- BLI_listbase_clear(&joined_arc2->edges);
-
- BLI_removeArc((BGraph *)rg, (BArc *)joined_arc2);
-
- BLI_removeNode((BGraph *)rg, (BNode *)node);
-}
-
-static void RIG_removeNormalNodes(RigGraph *rg)
-{
- RigNode *node, *next_node;
-
- for (node = rg->nodes.first; node; node = next_node) {
- next_node = node->next;
-
- if (node->degree == 2) {
- RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- if (arc->head == node || arc->tail == node) {
- if (joined_arc1 == NULL) {
- joined_arc1 = arc;
- }
- else {
- joined_arc2 = arc;
- break;
- }
- }
- }
-
- RIG_joinArcs(rg, node, joined_arc1, joined_arc2);
- }
- }
-}
-
-static void RIG_removeUneededOffsets(RigGraph *rg)
-{
- RigArc *arc;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- RigEdge *first_edge, *last_edge;
-
- first_edge = arc->edges.first;
- last_edge = arc->edges.last;
-
- if (first_edge->bone == NULL) {
- if (first_edge->bone == NULL && len_v3v3(first_edge->tail, arc->head->p) <= 0.001f) {
- BLI_remlink(&arc->edges, first_edge);
- MEM_freeN(first_edge);
- }
- else if (arc->head->degree == 1) {
- RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001f);
-
- if (new_node) {
- BLI_remlink(&arc->edges, first_edge);
- MEM_freeN(first_edge);
- BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head);
- }
- else {
- RigEdge *next_edge = first_edge->next;
-
- if (next_edge) {
- BLI_remlink(&arc->edges, first_edge);
- MEM_freeN(first_edge);
-
- copy_v3_v3(arc->head->p, next_edge->head);
- }
- }
- }
- else {
- /* check if all arc connected start with a null edge */
- RigArc *other_arc;
- for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
- if (other_arc != arc) {
- RigEdge *test_edge;
- if (other_arc->head == arc->head) {
- test_edge = other_arc->edges.first;
-
- if (test_edge->bone != NULL) {
- break;
- }
- }
- else if (other_arc->tail == arc->head) {
- test_edge = other_arc->edges.last;
-
- if (test_edge->bone != NULL) {
- break;
- }
- }
- }
- }
-
- if (other_arc == NULL) {
- RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001);
-
- if (new_node) {
- /* remove null edge in other arcs too */
- for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
- if (other_arc != arc) {
- RigEdge *test_edge;
- if (other_arc->head == arc->head) {
- BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->head);
- test_edge = other_arc->edges.first;
- BLI_remlink(&other_arc->edges, test_edge);
- MEM_freeN(test_edge);
- }
- else if (other_arc->tail == arc->head) {
- BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->tail);
- test_edge = other_arc->edges.last;
- BLI_remlink(&other_arc->edges, test_edge);
- MEM_freeN(test_edge);
- }
- }
- }
-
- BLI_remlink(&arc->edges, first_edge);
- MEM_freeN(first_edge);
- BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head);
- }
- else {
- RigEdge *next_edge = first_edge->next;
-
- if (next_edge) {
- BLI_remlink(&arc->edges, first_edge);
- MEM_freeN(first_edge);
-
- copy_v3_v3(arc->head->p, next_edge->head);
-
- /* remove null edge in other arcs too */
- for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
- if (other_arc != arc) {
- RigEdge *test_edge;
- if (other_arc->head == arc->head) {
- test_edge = other_arc->edges.first;
- BLI_remlink(&other_arc->edges, test_edge);
- MEM_freeN(test_edge);
- }
- else if (other_arc->tail == arc->head) {
- test_edge = other_arc->edges.last;
- BLI_remlink(&other_arc->edges, test_edge);
- MEM_freeN(test_edge);
- }
- }
- }
- }
- }
- }
- }
- }
-
- if (last_edge->bone == NULL) {
- if (len_v3v3(last_edge->head, arc->tail->p) <= 0.001f) {
- BLI_remlink(&arc->edges, last_edge);
- MEM_freeN(last_edge);
- }
- else if (arc->tail->degree == 1) {
- RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, last_edge->head, 0.001f);
-
- if (new_node) {
- RigEdge *previous_edge = last_edge->prev;
-
- BLI_remlink(&arc->edges, last_edge);
- MEM_freeN(last_edge);
- BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->tail);
-
- /* set previous angle to 0, since there's no following edges */
- if (previous_edge) {
- previous_edge->angle = 0;
- }
- }
- else {
- RigEdge *previous_edge = last_edge->prev;
-
- if (previous_edge) {
- BLI_remlink(&arc->edges, last_edge);
- MEM_freeN(last_edge);
-
- copy_v3_v3(arc->tail->p, previous_edge->tail);
- previous_edge->angle = 0;
- }
- }
- }
- }
- }
-}
-
-static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, bool selected)
-{
- EditBone *bone, *last_bone = root_bone;
- RigArc *arc = NULL;
- int contain_head = 0;
-
- for (bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) {
- int nb_children;
-
- if (selected == 0 || (bone->flag & BONE_SELECTED)) {
- if ((bone->flag & BONE_NO_DEFORM) == 0) {
- BLI_ghash_insert(rg->bones_map, bone->name, bone);
-
- if (arc == NULL) {
- arc = newRigArc(rg);
-
- if (starting_node == NULL) {
- starting_node = newRigNodeHead(rg, arc, root_bone->head);
- }
- else {
- addRigNodeHead(rg, arc, starting_node);
- }
- }
-
- if (bone->parent && (bone->flag & BONE_CONNECTED) == 0) {
- RIG_addEdgeToArc(arc, bone->head, NULL);
- }
-
- RIG_addEdgeToArc(arc, bone->tail, bone);
-
- last_bone = bone;
-
- if (STREQ(bone->name, "head")) {
- contain_head = 1;
- }
- }
- else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) { /* ignore locked bones */
- RIG_addControlBone(rg, bone);
- }
- }
-
- nb_children = countEditBoneChildren(list, bone);
- if (nb_children > 1) {
- RigNode *end_node = NULL;
- int i;
-
- if (arc != NULL) {
- end_node = newRigNodeTail(rg, arc, bone->tail);
- }
- else {
- end_node = newRigNode(rg, bone->tail);
- }
-
- for (i = 0; i < nb_children; i++) {
- root_bone = nextEditBoneChild(list, bone, i);
- RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected);
- }
-
- /* arc ends here, break */
- break;
- }
- }
-
- /* If the loop exited without forking */
- if (arc != NULL && bone == NULL) {
- newRigNodeTail(rg, arc, last_bone->tail);
- }
-
- if (contain_head) {
- rg->head = arc->tail;
- }
-}
-
-/*******************************************************************************************************/
-static void RIG_findHead(RigGraph *rg)
-{
- if (rg->head == NULL) {
- if (BLI_listbase_is_single(&rg->arcs)) {
- RigArc *arc = rg->arcs.first;
-
- rg->head = (RigNode *)arc->head;
- }
- else {
- RigArc *arc;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- RigEdge *edge = arc->edges.last;
-
- if (edge->bone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
- rg->head = arc->tail;
- break;
- }
- }
- }
-
- if (rg->head == NULL) {
- rg->head = rg->nodes.first;
- }
- }
-}
-
-/*******************************************************************************************************/
-
-static void RIG_printNode(RigNode *node, const char name[])
-{
- printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, (void *)node, node->degree, node->p[0], node->p[1], node->p[2]);
-
- if (node->symmetry_flag & SYM_TOPOLOGICAL) {
- if (node->symmetry_flag & SYM_AXIAL)
- printf("Symmetry AXIAL\n");
- else if (node->symmetry_flag & SYM_RADIAL)
- printf("Symmetry RADIAL\n");
-
- print_v3("symmetry axis", node->symmetry_axis);
- }
-}
-
-void RIG_printArcBones(RigArc *arc)
-{
- RigEdge *edge;
-
- for (edge = arc->edges.first; edge; edge = edge->next) {
- if (edge->bone)
- printf("%s ", edge->bone->name);
- else
- printf("---- ");
- }
- printf("\n");
-}
-
-static void RIG_printCtrl(RigControl *ctrl, char *indent)
-{
- char text[128];
-
- printf("%sBone: %s\n", indent, ctrl->bone->name);
- printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!");
-
- BLI_snprintf(text, sizeof(text), "%soffset", indent);
- print_v3(text, ctrl->offset);
-
- printf("%sFlag: %i\n", indent, ctrl->flag);
-}
-
-static void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs)
-{
- RigControl *ctrl;
- char indent[64];
- char *s = indent;
- int i;
-
- for (i = 0; i < tabs; i++) {
- s[0] = '\t';
- s++;
- }
- s[0] = 0;
-
- for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
- if (ctrl->link == bone) {
- RIG_printCtrl(ctrl, indent);
- RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1);
- }
- }
-}
-
-void RIG_printArc(RigGraph *rg, RigArc *arc)
-{
- RigEdge *edge;
-
- RIG_printNode((RigNode *)arc->head, "head");
-
- for (edge = arc->edges.first; edge; edge = edge->next) {
- printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]);
- printf("\t\tlength %f\n", edge->length);
- printf("\t\tangle %f\n", edge->angle * (float)(180 / M_PI));
- if (edge->bone) {
- printf("\t\t%s\n", edge->bone->name);
- RIG_printLinkedCtrl(rg, edge->bone, 3);
- }
- }
- printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group);
-
- RIG_printNode((RigNode *)arc->tail, "tail");
-}
-
-void RIG_printGraph(RigGraph *rg)
-{
- RigArc *arc;
-
- printf("---- ARCS ----\n");
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- RIG_printArc(rg, arc);
- printf("\n");
- }
-
- if (rg->head) {
- RIG_printNode(rg->head, "HEAD NODE:");
- }
- else {
- printf("HEAD NODE: NONE\n");
- }
-}
-
-/*******************************************************************************************************/
-
-RigGraph *RIG_graphFromArmature(const bContext *C, Object *ob, bArmature *arm)
-{
- Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
- EditBone *ebone;
- RigGraph *rg;
-
- rg = newRigGraph();
-
- if (obedit == ob) {
- rg->editbones = ((bArmature *)obedit->data)->edbo;
- }
- else {
- rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
- make_boneList(rg->editbones, &arm->bonebase, NULL, NULL);
- rg->flag |= RIG_FREE_BONELIST;
- }
-
- rg->ob = ob;
-
- /* Do the rotations */
- for (ebone = rg->editbones->first; ebone; ebone = ebone->next) {
- if (ebone->parent == NULL) {
- RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0);
- }
- }
-
- BLI_removeDoubleNodes((BGraph *)rg, 0.001);
-
- RIG_removeNormalNodes(rg);
-
- RIG_removeUneededOffsets(rg);
-
- BLI_buildAdjacencyList((BGraph *)rg);
-
- RIG_findHead(rg);
-
- BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit);
-
- RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
-
- if (BLI_isGraphCyclic((BGraph *)rg)) {
- printf("armature cyclic\n");
- }
-
- return rg;
-}
-
-static RigGraph *armatureSelectedToGraph(bContext *C, Object *ob, bArmature *arm)
-{
- Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
- EditBone *ebone;
- RigGraph *rg;
-
- rg = newRigGraph();
-
- if (obedit == ob) {
- rg->editbones = arm->edbo;
- }
- else {
- rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
- make_boneList(rg->editbones, &arm->bonebase, NULL, NULL);
- rg->flag |= RIG_FREE_BONELIST;
- }
-
- rg->ob = ob;
-
- /* Do the rotations */
- for (ebone = rg->editbones->first; ebone; ebone = ebone->next) {
- if (ebone->parent == NULL) {
- RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1);
- }
- }
-
- BLI_removeDoubleNodes((BGraph *)rg, 0.001);
-
- RIG_removeNormalNodes(rg);
-
- RIG_removeUneededOffsets(rg);
-
- BLI_buildAdjacencyList((BGraph *)rg);
-
- RIG_findHead(rg);
-
- BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit);
-
- RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
-
- if (BLI_isGraphCyclic((BGraph *)rg)) {
- printf("armature cyclic\n");
- }
-
- return rg;
-}
-/************************************ GENERATING *****************************************************/
-
-#if 0
-static EditBone *add_editbonetolist(char *name, ListBase *list)
-{
- EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
-
- BLI_strncpy(bone->name, name, sizeof(bone->name));
- ED_armature_ebone_unique_name(list, bone->name, NULL);
-
- BLI_addtail(list, bone);
-
- bone->flag |= BONE_TIPSEL;
- bone->weight = 1.0F;
- bone->dist = 0.25F;
- bone->xwidth = 0.1;
- bone->zwidth = 0.1;
- bone->rad_head = 0.10;
- bone->rad_tail = 0.05;
- bone->segments = 1;
- bone->layer = 1; //arm->layer;
-
- /* Bendy-Bone parameters */
- bone->roll1 = 0.0f;
- bone->roll2 = 0.0f;
- bone->curveInX = 0.0f;
- bone->curveInY = 0.0f;
- bone->curveOutX = 0.0f;
- bone->curveOutY = 0.0f;
- bone->ease1 = 1.0f;
- bone->ease2 = 1.0f;
- bone->scaleIn = 1.0f;
- bone->scaleOut = 1.0f;
-
- return bone;
-}
-#endif
-
-#if 0 /* UNUSED */
-static void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit)
-{
- while (node->multi_level > multi_level_limit && node->link_up)
- {
- node = node->link_up;
- }
-
- while (node->multi_level < multi_level_limit && node->link_down)
- {
- node = node->link_down;
- }
-
- if (node->multi_level == multi_level_limit)
- {
- int i;
-
- for (i = 0; i < node->degree; i++)
- {
- ReebArc *earc = node->arcs[i];
-
- if (earc->flag == ARC_FREE && earc->head == node)
- {
- ReebNode *other = BIF_otherNodeFromIndex(earc, node);
-
- earc->flag = ARC_USED;
-
- //generateBonesForArc(rigg, earc, node, other);
- generateMissingArcsFromNode(rigg, other, multi_level_limit);
- }
- }
- }
-}
-
-static void generateMissingArcs(RigGraph *rigg)
-{
- ReebGraph *reebg;
- int multi_level_limit = 5;
-
- for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up)
- {
- ReebArc *earc;
-
- for (earc = reebg->arcs.first; earc; earc = earc->next)
- {
- if (earc->flag == ARC_USED)
- {
- generateMissingArcsFromNode(rigg, earc->head, multi_level_limit);
- generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit);
- }
- }
- }
-}
-#endif
-
-/************************************ RETARGETTING *****************************************************/
-
-static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize);
-
-static void repositionTailControl(RigGraph *rigg, RigControl *ctrl);
-
-static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize)
-{
- if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE) {
- RigControl *ctrl_child;
-
-#if 0
- printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name);
-
- if (ctrl->link_tail)
- {
- printf(" TAIL: %s", ctrl->link_tail->name);
- }
-
- printf("\n");
-#endif
-
- /* if there was a tail link: apply link, recalc resize factor and qrot */
- if (ctrl->tail_mode != TL_NONE) {
- float *tail_vec = NULL;
- float v1[3], v2[3], qtail[4];
-
- if (ctrl->tail_mode == TL_TAIL) {
- tail_vec = ctrl->link_tail->tail;
- }
- else if (ctrl->tail_mode == TL_HEAD) {
- tail_vec = ctrl->link_tail->head;
- }
-
- sub_v3_v3v3(v1, ctrl->bone->tail, ctrl->bone->head);
- sub_v3_v3v3(v2, tail_vec, ctrl->bone->head);
-
- copy_v3_v3(ctrl->bone->tail, tail_vec);
-
- rotation_between_vecs_to_quat(qtail, v1, v2);
- mul_qt_qtqt(ctrl->qrot, qtail, ctrl->qrot);
-
- resize = len_v3(v2) / len_v3v3(ctrl->head, ctrl->tail);
- }
-
- ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot);
-
- /* Cascade to connected control bones */
- for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) {
- if (ctrl_child->link == ctrl->bone) {
- repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize);
- }
- if (ctrl_child->link_tail == ctrl->bone) {
- repositionTailControl(rigg, ctrl_child);
- }
- }
- }
-}
-
-static void repositionTailControl(RigGraph *rigg, RigControl *ctrl)
-{
- ctrl->flag |= RIG_CTRL_TAIL_DONE;
-
- finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */
-}
-
-static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float UNUSED(tail[3]), float qrot[4], float resize)
-{
- float parent_offset[3], tail_offset[3];
-
- copy_v3_v3(parent_offset, ctrl->offset);
- mul_v3_fl(parent_offset, resize);
- mul_qt_v3(qrot, parent_offset);
-
- add_v3_v3v3(ctrl->bone->head, head, parent_offset);
-
- ctrl->flag |= RIG_CTRL_HEAD_DONE;
-
- copy_qt_qt(ctrl->qrot, qrot);
-
- if (ctrl->tail_mode == TL_NONE) {
- sub_v3_v3v3(tail_offset, ctrl->tail, ctrl->head);
- mul_v3_fl(tail_offset, resize);
- mul_qt_v3(qrot, tail_offset);
-
- add_v3_v3v3(ctrl->bone->tail, ctrl->bone->head, tail_offset);
-
- ctrl->flag |= RIG_CTRL_TAIL_DONE;
- }
-
- finalizeControl(rigg, ctrl, resize);
-}
-
-static void repositionBone(bContext *C, RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3])
-{
- Scene *scene = CTX_data_scene(C);
- EditBone *bone;
- RigControl *ctrl;
- float qrot[4], resize;
- float v1[3], v2[3];
- float l1, l2;
-
- bone = edge->bone;
-
- sub_v3_v3v3(v1, edge->tail, edge->head);
- sub_v3_v3v3(v2, vec1, vec0);
-
- l1 = normalize_v3(v1);
- l2 = normalize_v3(v2);
-
- resize = l2 / l1;
-
- rotation_between_vecs_to_quat(qrot, v1, v2);
-
- copy_v3_v3(bone->head, vec0);
- copy_v3_v3(bone->tail, vec1);
-
- if (!is_zero_v3(up_axis)) {
- float qroll[4];
-
- if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW) {
- bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis);
- }
- else if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT) {
- bone->roll = rollBoneByQuatJoint(edge, edge->prev, qrot, qroll, up_axis);
- }
- else {
- unit_qt(qroll);
- }
-
- mul_qt_qtqt(qrot, qroll, qrot);
- }
- else {
- bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot);
- }
-
- for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) {
- if (ctrl->link == bone) {
- repositionControl(rigg, ctrl, vec0, vec1, qrot, resize);
- }
- if (ctrl->link_tail == bone) {
- repositionTailControl(rigg, ctrl);
- }
- }
-}
-
-static RetargetMode detectArcRetargetMode(RigArc *arc);
-static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start);
-
-
-static RetargetMode detectArcRetargetMode(RigArc *iarc)
-{
- RetargetMode mode = RETARGET_AGGRESSIVE;
- ReebArc *earc = iarc->link_mesh;
- RigEdge *edge;
- int large_angle = 0;
- float avg_angle = 0;
- /* float avg_length = 0; */ /* UNUSED */
- int nb_edges = 0;
-
-
- for (edge = iarc->edges.first; edge; edge = edge->next) {
- avg_angle += edge->angle;
- nb_edges++;
- }
-
- avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */
-
- /* avg_length = iarc->length / nb_edges; */ /* UNUSED */
-
-
- if (nb_edges > 2) {
- for (edge = iarc->edges.first; edge; edge = edge->next) {
- if (fabsf(edge->angle - avg_angle) > (float)(M_PI / 6)) {
- large_angle = 1;
- }
- }
- }
- else if (nb_edges == 2 && avg_angle > 0) {
- large_angle = 1;
- }
-
-
- if (large_angle == 0) {
- mode = RETARGET_LENGTH;
- }
-
- if (earc->bcount <= (iarc->count - 1)) {
- mode = RETARGET_LENGTH;
- }
-
- return mode;
-}
-
-#ifndef USE_THREADS
-static void printMovesNeeded(int *positions, int nb_positions)
-{
- int moves = 0;
- int i;
-
- for (i = 0; i < nb_positions; i++) {
- moves += positions[i] - (i + 1);
- }
-
- printf("%i moves needed\n", moves);
-}
-
-static void printPositions(int *positions, int nb_positions)
-{
- int i;
-
- for (i = 0; i < nb_positions; i++) {
- printf("%i ", positions[i]);
- }
- printf("\n");
-}
-#endif
-
-#define MAX_COST FLT_MAX /* FIX ME */
-
-static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1, float distance_weight)
-{
- EmbedBucket *bucket = NULL;
- float max_dist = 0;
- float v1[3], v2[3], c[3];
- float v1_inpf;
-
- if (distance_weight > 0) {
- sub_v3_v3v3(v1, vec0, vec1);
-
- v1_inpf = dot_v3v3(v1, v1);
-
- if (v1_inpf > 0) {
- int j;
- for (j = i0 + 1; j < i1 - 1; j++) {
- float dist;
-
- bucket = IT_peek(iter, j);
-
- sub_v3_v3v3(v2, bucket->p, vec1);
-
- cross_v3_v3v3(c, v1, v2);
-
- dist = dot_v3v3(c, c) / v1_inpf;
-
- max_dist = dist > max_dist ? dist : max_dist;
- }
-
- return distance_weight * max_dist;
- }
- else {
- return MAX_COST;
- }
- }
- else {
- return 0;
- }
-}
-
-static float costAngle(float original_angle, float vec_first[3], float vec_second[3], float angle_weight)
-{
- if (angle_weight > 0) {
- float current_angle;
-
- if (!is_zero_v3(vec_first) && !is_zero_v3(vec_second)) {
- current_angle = saacos(dot_v3v3(vec_first, vec_second));
-
- return angle_weight * fabsf(current_angle - original_angle);
- }
- else {
- return angle_weight * (float)M_PI;
- }
- }
- else {
- return 0;
- }
-}
-
-static float costLength(float original_length, float current_length, float length_weight)
-{
- if (current_length == 0) {
- return MAX_COST;
- }
- else {
- float length_ratio = fabsf((current_length - original_length) / original_length);
- return length_weight * length_ratio * length_ratio;
- }
-}
-
-#if 0
-static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2)
-{
- float vec[3];
- float length;
-
- sub_v3_v3v3(vec, vec2, vec1);
- length = normalize_v3(vec);
-
- return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2);
-}
-#endif
-
-static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge,
- float *vec0, float *vec1, float *vec2, int i1, int i2,
- float angle_weight, float length_weight, float distance_weight)
-{
- float vec_second[3], vec_first[3];
- float length2;
- float new_cost = 0;
-
- sub_v3_v3v3(vec_second, vec2, vec1);
- length2 = normalize_v3(vec_second);
-
-
- /* Angle cost */
- if (edge->prev) {
- sub_v3_v3v3(vec_first, vec1, vec0);
- normalize_v3(vec_first);
-
- new_cost += costAngle(edge->prev->angle, vec_first, vec_second, angle_weight);
- }
-
- /* Length cost */
- new_cost += costLength(edge->length, length2, length_weight);
-
- /* Distance cost */
- new_cost += costDistance(iter, vec1, vec2, i1, i2, distance_weight);
-
- return new_cost;
-}
-
-static int indexMemoNode(int nb_positions, int previous, int current, int joints_left)
-{
- return joints_left * nb_positions * nb_positions + current * nb_positions + previous;
-}
-
-static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left)
-{
- int previous = 0, current = 0;
- int i = 0;
-
- for (i = 0; joints_left > 0; joints_left--, i++) {
- MemoNode *node;
- node = table + indexMemoNode(nb_positions, previous, current, joints_left);
-
- positions[i] = node->next;
-
- previous = current;
- current = node->next;
- }
-}
-
-static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache,
- int nb_joints, int nb_positions, int previous, int current, RigEdge *edge,
- int joints_left, float angle_weight, float length_weight, float distance_weight)
-{
- MemoNode *node;
- int index = indexMemoNode(nb_positions, previous, current, joints_left);
-
- node = table + index;
-
- if (node->weight != 0) {
- return node;
- }
- else if (joints_left == 0) {
- float *vec0 = vec_cache[previous];
- float *vec1 = vec_cache[current];
- float *vec2 = vec_cache[nb_positions + 1];
-
- node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length, angle_weight, length_weight, distance_weight);
-
- return node;
- }
- else {
- MemoNode *min_node = NULL;
- float *vec0 = vec_cache[previous];
- float *vec1 = vec_cache[current];
- float min_weight = 0.0f;
- int min_next = 0;
- int next;
-
- for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) {
- MemoNode *next_node;
- float *vec2 = vec_cache[next];
- float weight = 0.0f;
-
- /* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */
- weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next, angle_weight, length_weight, distance_weight);
-
- if (weight >= MAX_COST) {
- continue;
- }
-
- /* add node weight */
- next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1, angle_weight, length_weight, distance_weight);
- weight += next_node->weight;
-
- if (min_node == NULL || weight < min_weight) {
- min_weight = weight;
- min_node = next_node;
- min_next = next;
- }
- }
-
- if (min_node) {
- node->weight = min_weight;
- node->next = min_next;
- return node;
- }
- else {
- node->weight = MAX_COST;
- return node;
- }
- }
-
-}
-
-static int testFlipArc(RigArc *iarc, RigNode *inode_start)
-{
- ReebArc *earc = iarc->link_mesh;
- ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh);
-
- /* no flip needed if both nodes are the same */
- if ((enode_start == earc->head && inode_start == iarc->head) ||
- (enode_start == earc->tail && inode_start == iarc->tail))
- {
- return 0;
- }
- else {
- return 1;
- }
-}
-
-static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
-{
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- RigEdge *edge;
- ReebNode *node_start, *node_end;
- ReebArc *earc = iarc->link_mesh;
- float angle_weight = 1.0; // GET FROM CONTEXT
- float length_weight = 1.0;
- float distance_weight = 1.0;
-#ifndef USE_THREADS
- float min_cost = FLT_MAX;
-#endif
- float *vec0, *vec1;
- int *best_positions;
- int nb_edges = BLI_listbase_count(&iarc->edges);
- int nb_joints = nb_edges - 1;
- RetargetMethod method = METHOD_MEMOIZE;
- int i;
-
- if (nb_joints > earc->bcount) {
- printf("NOT ENOUGH BUCKETS!\n");
- return;
- }
-
- best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions");
-
- if (testFlipArc(iarc, inode_start)) {
- node_start = earc->tail;
- node_end = earc->head;
- }
- else {
- node_start = earc->head;
- node_end = earc->tail;
- }
-
- /* equal number of joints and potential position, just fill them in */
- if (nb_joints == earc->bcount) {
- /* init with first values */
- for (i = 0; i < nb_joints; i++) {
- best_positions[i] = i + 1;
- }
- }
- if (method == METHOD_MEMOIZE) {
- int nb_positions = earc->bcount;
- int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1);
- MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table");
-#ifndef USE_THREADS
- MemoNode *result;
-#endif
- float **positions_cache = MEM_callocN(sizeof(float *) * (nb_positions + 2), "positions cache");
-
- positions_cache[0] = node_start->p;
- positions_cache[nb_positions + 1] = node_end->p;
-
- initArcIterator(iter, earc, node_start);
-
- for (i = 1; i <= nb_positions; i++) {
- EmbedBucket *bucket = IT_peek(iter, i);
- positions_cache[i] = bucket->p;
- }
-
-#ifndef USE_THREADS
- result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight);
- min_cost = result->weight;
-#else
- solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight);
-#endif
-
- copyMemoPositions(best_positions, table, earc->bcount, nb_joints);
-
- MEM_freeN(table);
- MEM_freeN(positions_cache);
- }
-
- vec0 = node_start->p;
- initArcIterator(iter, earc, node_start);
-
-#ifndef USE_THREADS
- printPositions(best_positions, nb_joints);
- printMovesNeeded(best_positions, nb_joints);
- printf("min_cost %f\n", min_cost);
- printf("buckets: %i\n", earc->bcount);
-#endif
-
- /* set joints to best position */
- for (edge = iarc->edges.first, i = 0;
- edge;
- edge = edge->next, i++)
- {
- float *no = NULL;
- if (i < nb_joints) {
- EmbedBucket *bucket = IT_peek(iter, best_positions[i]);
- vec1 = bucket->p;
- no = bucket->no;
- }
- else {
- vec1 = node_end->p;
- no = node_end->no;
- }
-
- if (edge->bone) {
- repositionBone(C, rigg, edge, vec0, vec1, no);
- }
-
- vec0 = vec1;
- }
-
- MEM_freeN(best_positions);
-}
-
-static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
-{
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- ReebArc *earc = iarc->link_mesh;
- ReebNode *node_start, *node_end;
- RigEdge *edge;
- EmbedBucket *bucket = NULL;
- float embedding_length = 0;
- float *vec0 = NULL;
- float *vec1 = NULL;
- float *previous_vec = NULL;
-
-
- if (testFlipArc(iarc, inode_start)) {
- node_start = (ReebNode *)earc->tail;
- node_end = (ReebNode *)earc->head;
- }
- else {
- node_start = (ReebNode *)earc->head;
- node_end = (ReebNode *)earc->tail;
- }
-
- initArcIterator(iter, earc, node_start);
-
- bucket = IT_next(iter);
-
- vec0 = node_start->p;
-
- while (bucket != NULL) {
- vec1 = bucket->p;
-
- embedding_length += len_v3v3(vec0, vec1);
-
- vec0 = vec1;
- bucket = IT_next(iter);
- }
-
- embedding_length += len_v3v3(node_end->p, vec1);
-
- /* fit bones */
- initArcIterator(iter, earc, node_start);
-
- bucket = IT_next(iter);
-
- vec0 = node_start->p;
- previous_vec = vec0;
- vec1 = bucket->p;
-
- for (edge = iarc->edges.first; edge; edge = edge->next) {
- float new_bone_length = edge->length / iarc->length * embedding_length;
- float *no = NULL;
- float length = 0;
-
- while (bucket && new_bone_length > length) {
- length += len_v3v3(previous_vec, vec1);
- bucket = IT_next(iter);
- previous_vec = vec1;
- vec1 = bucket->p;
- no = bucket->no;
- }
-
- if (bucket == NULL) {
- vec1 = node_end->p;
- no = node_end->no;
- }
-
- /* no need to move virtual edges (space between unconnected bones) */
- if (edge->bone) {
- repositionBone(C, rigg, edge, vec0, vec1, no);
- }
-
- vec0 = vec1;
- previous_vec = vec1;
- }
-}
-
-static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
-{
- RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam");
-
- p->rigg = rigg;
- p->iarc = iarc;
- p->inode_start = inode_start;
- p->context = C;
-
- BLI_task_pool_push(rigg->task_pool, exec_retargetArctoArc, p, true, TASK_PRIORITY_HIGH);
-}
-
-void exec_retargetArctoArc(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- RetargetParam *p = (RetargetParam *)taskdata;
- RigGraph *rigg = p->rigg;
- RigArc *iarc = p->iarc;
- bContext *C = p->context;
- RigNode *inode_start = p->inode_start;
- ReebArc *earc = iarc->link_mesh;
-
- if (BLI_listbase_is_single(&iarc->edges)) {
- RigEdge *edge = iarc->edges.first;
-
- if (testFlipArc(iarc, inode_start)) {
- repositionBone(C, rigg, edge, earc->tail->p, earc->head->p, earc->head->no);
- }
- else {
- repositionBone(C, rigg, edge, earc->head->p, earc->tail->p, earc->tail->no);
- }
- }
- else {
- RetargetMode mode = detectArcRetargetMode(iarc);
-
- if (mode == RETARGET_AGGRESSIVE) {
- retargetArctoArcAggresive(C, rigg, iarc, inode_start);
- }
- else {
- retargetArctoArcLength(C, rigg, iarc, inode_start);
- }
- }
-}
-
-static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node)
-{
- ReebNode *enode = top_node;
- ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode);
- int ishape, eshape;
-
- ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS;
- eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
-
- inode->link_mesh = enode;
-
- while (ishape == eshape && enode->link_down) {
- inode->link_mesh = enode;
-
- enode = enode->link_down;
- reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */
- eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
- }
-}
-
-static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode)
-{
- int i;
-
- for (i = 0; i < enode->degree; i++) {
- ReebArc *earc = (ReebArc *)enode->arcs[i];
-
- if (earc->flag == ARC_FREE) {
- earc->flag = ARC_TAKEN;
-
- if (earc->tail->degree > 1 && earc->tail != end_enode) {
- markMultiResolutionChildArc(end_enode, earc->tail);
- }
- break;
- }
- }
-}
-
-static void markMultiResolutionArc(ReebArc *start_earc)
-{
- if (start_earc->link_up) {
- ReebArc *earc;
- for (earc = start_earc->link_up; earc; earc = earc->link_up) {
- earc->flag = ARC_TAKEN;
-
- if (earc->tail->index != start_earc->tail->index) {
- markMultiResolutionChildArc(earc->tail, earc->tail);
- }
- }
- }
-}
-
-static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc)
-{
- ReebNode *enode = next_earc->head;
- ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode);
- int ishape, eshape;
-
- ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)start_node, (BArc *)next_iarc, 1) % SHAPE_LEVELS;
- eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS;
-
- while (ishape != eshape && next_earc->link_up) {
- next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels
-
- next_earc = next_earc->link_up;
- reebg = reebg->link_up;
- enode = next_earc->head;
- eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS;
- }
-
- next_earc->flag = ARC_USED;
- next_iarc->link_mesh = next_earc;
-
- /* mark all higher levels as taken too */
- markMultiResolutionArc(next_earc);
-// while (next_earc->link_up)
-// {
-// next_earc = next_earc->link_up;
-// next_earc->flag = ARC_TAKEN;
-// }
-}
-
-static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode)
-{
- ReebNode *enode;
- int ishape, eshape;
-
- enode = reebg->nodes.first;
-
- ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS;
- eshape = BLI_subtreeShape((BGraph *)rigg->link_mesh, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
-
- while (ishape != eshape && reebg->link_up) {
- reebg = reebg->link_up;
-
- enode = reebg->nodes.first;
-
- eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
- }
-
- inode->link_mesh = enode;
-}
-
-static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root)
-{
- ReebNode *enode = start_node->link_mesh;
- ReebArc *next_earc;
- int symmetry_level = next_iarc->symmetry_level;
- int symmetry_group = next_iarc->symmetry_group;
- int symmetry_flag = next_iarc->symmetry_flag;
- int i;
-
- next_iarc->link_mesh = NULL;
-
-// if (root)
-// {
-// printf("-----------------------\n");
-// printf("MATCHING LIMB\n");
-// RIG_printArcBones(next_iarc);
-// }
-
- for (i = 0; i < enode->degree; i++) {
- next_earc = (ReebArc *)enode->arcs[i];
-
-// if (next_earc->flag == ARC_FREE)
-// {
-// printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n",
-// symmetry_level, next_earc->symmetry_level,
-// symmetry_flag, next_earc->symmetry_flag,
-// symmetry_group, next_earc->symmetry_flag);
-// }
-
- if (next_earc->flag == ARC_FREE &&
- next_earc->symmetry_flag == symmetry_flag &&
- next_earc->symmetry_group == symmetry_group &&
- next_earc->symmetry_level == symmetry_level)
- {
-// printf("CORRESPONDING ARC FOUND\n");
-// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
-
- matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc);
- break;
- }
- }
-
- /* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */
- if (next_iarc->link_mesh == NULL) {
-// printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n");
-
- if (enode->link_up) {
- start_node->link_mesh = enode->link_up;
- findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0);
- }
- }
-
- /* still not found, print debug info */
- if (root && next_iarc->link_mesh == NULL) {
- start_node->link_mesh = enode; /* linking back with root node */
-
-// printf("NO CORRESPONDING ARC FOUND\n");
-// RIG_printArcBones(next_iarc);
-//
-// printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level);
-//
-// printf("LOOKING FOR\n");
-// printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group);
-//
-// printf("CANDIDATES\n");
-// for (i = 0; i < enode->degree; i++)
-// {
-// next_earc = (ReebArc *)enode->arcs[i];
-// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
-// }
-
- /* Emergency matching */
- for (i = 0; i < enode->degree; i++) {
- next_earc = (ReebArc *)enode->arcs[i];
-
- if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) {
-// printf("USING:\n");
-// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
- matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc);
- break;
- }
- }
- }
-
-}
-
-static void retargetSubgraph(bContext *C, RigGraph *rigg, RigArc *start_arc, RigNode *start_node)
-{
- RigNode *inode = start_node;
- int i;
-
- /* no start arc on first node */
- if (start_arc) {
- ReebNode *enode = start_node->link_mesh;
- ReebArc *earc = start_arc->link_mesh;
-
- retargetArctoArc(C, rigg, start_arc, start_node);
-
- enode = BIF_otherNodeFromIndex(earc, enode);
- inode = (RigNode *)BLI_otherNode((BArc *)start_arc, (BNode *)inode);
-
- /* match with lowest node with correct shape */
- matchMultiResolutionNode(rigg, inode, enode);
- }
-
- for (i = 0; i < inode->degree; i++) {
- RigArc *next_iarc = (RigArc *)inode->arcs[i];
-
- /* no back tracking */
- if (next_iarc != start_arc) {
- findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1);
- if (next_iarc->link_mesh) {
- retargetSubgraph(C, rigg, next_iarc, inode);
- }
- }
- }
-}
-
-static void finishRetarget(RigGraph *rigg)
-{
- BLI_task_pool_work_and_wait(rigg->task_pool);
-}
-
-static void adjustGraphs(bContext *C, RigGraph *rigg)
-{
- Main *bmain = CTX_data_main(C);
- bArmature *arm = rigg->ob->data;
- RigArc *arc;
-
- for (arc = rigg->arcs.first; arc; arc = arc->next) {
- if (arc->link_mesh) {
- retargetArctoArc(C, rigg, arc, arc->head);
- }
- }
-
- finishRetarget(rigg);
-
- /* Turn the list into an armature */
- arm->edbo = rigg->editbones;
- ED_armature_from_edit(bmain, arm);
-
- ED_undo_push(C, "Retarget Skeleton");
-}
-
-static void retargetGraphs(bContext *C, RigGraph *rigg)
-{
- Main *bmain = CTX_data_main(C);
- bArmature *arm = rigg->ob->data;
- ReebGraph *reebg = rigg->link_mesh;
- RigNode *inode;
-
- /* flag all ReebArcs as free */
- BIF_flagMultiArcs(reebg, ARC_FREE);
-
- /* return to first level */
- inode = rigg->head;
-
- matchMultiResolutionStartingNode(rigg, reebg, inode);
-
- retargetSubgraph(C, rigg, NULL, inode);
-
- //generateMissingArcs(rigg);
-
- finishRetarget(rigg);
-
- /* Turn the list into an armature */
- arm->edbo = rigg->editbones;
- ED_armature_from_edit(bmain, arm);
-}
-
-const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index)
-{
- RigArc *arc = BLI_findlink(&rg->arcs, arc_index);
- RigEdge *iedge;
-
- if (arc == NULL) {
- return "None";
- }
-
- if (bone_index == BLI_listbase_count(&arc->edges)) {
- return "Last joint";
- }
-
- iedge = BLI_findlink(&arc->edges, bone_index);
-
- if (iedge == NULL) {
- return "Done";
- }
-
- if (iedge->bone == NULL) {
- return "Bone offset";
- }
-
- return iedge->bone->name;
-}
-
-int RIG_nbJoints(RigGraph *rg)
-{
- RigArc *arc;
- int total = 0;
-
- total += BLI_listbase_count(&rg->nodes);
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */
- }
-
- return total;
-}
-
-static void BIF_freeRetarget(void)
-{
- if (GLOBAL_RIGG) {
- RIG_freeRigGraph((BGraph *)GLOBAL_RIGG);
- GLOBAL_RIGG = NULL;
- }
-}
-
-void BIF_retargetArmature(bContext *C)
-{
- ReebGraph *reebg;
- double start_time, end_time;
- double gstart_time, gend_time;
- double reeb_time, rig_time = 0.0, retarget_time = 0.0, total_time;
-
- gstart_time = start_time = PIL_check_seconds_timer();
-
- reebg = BIF_ReebGraphMultiFromEditMesh(C);
-
- end_time = PIL_check_seconds_timer();
- reeb_time = end_time - start_time;
-
- printf("Reeb Graph created\n");
-
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
- {
- Object *ob = base->object;
-
- if (ob->type == OB_ARMATURE) {
- RigGraph *rigg;
- bArmature *arm;
-
- arm = ob->data;
-
- /* Put the armature into editmode */
-
-
- start_time = PIL_check_seconds_timer();
-
- rigg = RIG_graphFromArmature(C, ob, arm);
-
- end_time = PIL_check_seconds_timer();
- rig_time = end_time - start_time;
-
- printf("Armature graph created\n");
-
- //RIG_printGraph(rigg);
-
- rigg->link_mesh = reebg;
-
- printf("retargetting %s\n", ob->id.name);
-
- start_time = PIL_check_seconds_timer();
-
- retargetGraphs(C, rigg);
-
- end_time = PIL_check_seconds_timer();
- retarget_time = end_time - start_time;
-
- BIF_freeRetarget();
-
- GLOBAL_RIGG = rigg;
-
- break; /* only one armature at a time */
- }
- }
- CTX_DATA_END;
-
-
- gend_time = PIL_check_seconds_timer();
-
- total_time = gend_time - gstart_time;
-
- printf("-----------\n");
- printf("runtime: \t%.3f\n", total_time);
- printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100);
- printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100);
- printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100);
- printf("-----------\n");
-
- ED_undo_push(C, "Retarget Skeleton");
-
- // XXX
-// allqueue(REDRAWVIEW3D, 0);
-}
-
-void BIF_retargetArc(bContext *C, ReebArc *earc, RigGraph *template_rigg)
-{
- Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
- bArmature *armedit = obedit->data;
- Object *ob;
- RigGraph *rigg;
- RigArc *iarc;
- char *side_string = scene->toolsettings->skgen_side_string;
- char *num_string = scene->toolsettings->skgen_num_string;
- int free_template = 0;
-
- if (template_rigg) {
- ob = template_rigg->ob;
- }
- else {
- free_template = 1;
- ob = obedit;
- template_rigg = armatureSelectedToGraph(C, ob, ob->data);
- }
-
- if (BLI_listbase_is_empty(&template_rigg->arcs)) {
-// XXX
-// error("No Template and no deforming bones selected");
- return;
- }
-
- rigg = cloneRigGraph(template_rigg, armedit->edbo, obedit, side_string, num_string);
-
- iarc = rigg->arcs.first;
-
- iarc->link_mesh = earc;
- iarc->head->link_mesh = earc->head;
- iarc->tail->link_mesh = earc->tail;
-
- retargetArctoArc(C, rigg, iarc, iarc->head);
-
- finishRetarget(rigg);
-
- /* free template if it comes from the edit armature */
- if (free_template) {
- RIG_freeRigGraph((BGraph *)template_rigg);
- }
- RIG_freeRigGraph((BGraph *)rigg);
-
- ED_armature_edit_validate_active(armedit);
-
-// XXX
-// allqueue(REDRAWVIEW3D, 0);
-}
-
-void BIF_adjustRetarget(bContext *C)
-{
- if (GLOBAL_RIGG) {
- adjustGraphs(C, GLOBAL_RIGG);
- }
-}
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
deleted file mode 100644
index f789cd0e80a..00000000000
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ /dev/null
@@ -1,2663 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/armature/editarmature_sketch.c
- * \ingroup edarmature
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_armature_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-
-#include "BKE_context.h"
-#include "BKE_sketch.h"
-
-#include "RNA_define.h"
-#include "RNA_access.h"
-
-#include "ED_view3d.h"
-#include "ED_screen.h"
-
-#include "BIF_gl.h"
-#include "ED_armature.h"
-#include "armature_intern.h"
-#include "BIF_retarget.h"
-#include "BIF_generate.h"
-
-#include "ED_transform.h"
-#include "ED_transform_snap_object_context.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "GPU_select.h"
-
-typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *);
-typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *);
-
-typedef struct SK_GestureAction {
- char name[64];
- GestureDetectFct detect;
- GestureApplyFct apply;
-} SK_GestureAction;
-
-#if 0 /* UNUSED 2.5 */
-static SK_Point boneSnap;
-#endif
-
-static int LAST_SNAP_POINT_VALID = 0;
-static float LAST_SNAP_POINT[3];
-
-
-typedef struct SK_StrokeIterator {
- HeadFct head;
- TailFct tail;
- PeekFct peek;
- NextFct next;
- NextNFct nextN;
- PreviousFct previous;
- StoppedFct stopped;
-
- float *p, *no;
- float size;
-
- int length;
- int index;
- /*********************************/
- SK_Stroke *stroke;
- int start;
- int end;
- int stride;
-} SK_StrokeIterator;
-
-/******************** PROTOTYPES ******************************/
-
-void initStrokeIterator(BArcIterator *iter, SK_Stroke *stk, int start, int end);
-
-int sk_detectCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-void sk_applyCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-void sk_applyTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-int sk_detectCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-void sk_applyCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-void sk_applyDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-void sk_applyMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-void sk_applyReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-int sk_detectConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-void sk_applyConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
-
-SK_Sketch *contextSketch(const bContext *c, int create);
-SK_Sketch *viewcontextSketch(ViewContext *vc, int create);
-
-void sk_resetOverdraw(SK_Sketch *sketch);
-int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk);
-
-/******************** GESTURE ACTIONS ******************************/
-
-static SK_GestureAction GESTURE_ACTIONS[] = {
- {"Cut", sk_detectCutGesture, sk_applyCutGesture},
- {"Trim", sk_detectTrimGesture, sk_applyTrimGesture},
- {"Command", sk_detectCommandGesture, sk_applyCommandGesture},
- {"Delete", sk_detectDeleteGesture, sk_applyDeleteGesture},
- {"Merge", sk_detectMergeGesture, sk_applyMergeGesture},
- {"Reverse", sk_detectReverseGesture, sk_applyReverseGesture},
- {"Convert", sk_detectConvertGesture, sk_applyConvertGesture},
- {"", NULL, NULL}
-};
-
-/******************** TEMPLATES UTILS *************************/
-
-static char *TEMPLATES_MENU = NULL;
-static int TEMPLATES_CURRENT = 0;
-static GHash *TEMPLATES_HASH = NULL;
-static RigGraph *TEMPLATE_RIGG = NULL;
-
-void BIF_makeListTemplates(const bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Base *base;
- int index = 0;
-
- if (TEMPLATES_HASH != NULL) {
- BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
- }
-
- TEMPLATES_HASH = BLI_ghash_int_new("makeListTemplates gh");
- TEMPLATES_CURRENT = 0;
-
- for (base = FIRSTBASE; base; base = base->next) {
- Object *ob = base->object;
-
- if (ob != obedit && ob->type == OB_ARMATURE) {
- index++;
- BLI_ghash_insert(TEMPLATES_HASH, POINTER_FROM_INT(index), ob);
-
- if (ob == ts->skgen_template) {
- TEMPLATES_CURRENT = index;
- }
- }
- }
-}
-
-#if 0 /* UNUSED */
-const char *BIF_listTemplates(const bContext *UNUSED(C))
-{
- GHashIterator ghi;
- const char *menu_header = IFACE_("Template %t|None %x0|");
- char *p;
- const size_t template_size = (BLI_ghash_len(TEMPLATES_HASH) * 32 + 30);
-
- if (TEMPLATES_MENU != NULL) {
- MEM_freeN(TEMPLATES_MENU);
- }
-
- TEMPLATES_MENU = MEM_callocN(sizeof(char) * template_size, "skeleton template menu");
-
- p = TEMPLATES_MENU;
- p += BLI_strncpy_rlen(p, menu_header, template_size);
-
- BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
-
- while (!BLI_ghashIterator_done(&ghi)) {
- Object *ob = BLI_ghashIterator_getValue(&ghi);
- int key = POINTER_AS_INT(BLI_ghashIterator_getKey(&ghi));
-
- p += sprintf(p, "|%s %%x%i", ob->id.name + 2, key);
-
- BLI_ghashIterator_step(&ghi);
- }
-
- return TEMPLATES_MENU;
-}
-#endif
-
-int BIF_currentTemplate(const bContext *C)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- if (TEMPLATES_CURRENT == 0 && ts->skgen_template != NULL) {
- GHashIterator ghi;
- BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
-
- while (!BLI_ghashIterator_done(&ghi)) {
- Object *ob = BLI_ghashIterator_getValue(&ghi);
- int key = POINTER_AS_INT(BLI_ghashIterator_getKey(&ghi));
-
- if (ob == ts->skgen_template) {
- TEMPLATES_CURRENT = key;
- break;
- }
-
- BLI_ghashIterator_step(&ghi);
- }
- }
-
- return TEMPLATES_CURRENT;
-}
-
-static RigGraph *sk_makeTemplateGraph(const bContext *C, Object *ob)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (ob == obedit) {
- return NULL;
- }
-
- if (ob != NULL) {
- if (TEMPLATE_RIGG && TEMPLATE_RIGG->ob != ob) {
- RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG);
- TEMPLATE_RIGG = NULL;
- }
-
- if (TEMPLATE_RIGG == NULL) {
- bArmature *arm;
-
- arm = ob->data;
-
- TEMPLATE_RIGG = RIG_graphFromArmature(C, ob, arm);
- }
- }
-
- return TEMPLATE_RIGG;
-}
-
-int BIF_nbJointsTemplate(const bContext *C)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- RigGraph *rg = sk_makeTemplateGraph(C, ts->skgen_template);
-
- if (rg) {
- return RIG_nbJoints(rg);
- }
- else {
- return -1;
- }
-}
-
-const char *BIF_nameBoneTemplate(const bContext *C)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- SK_Sketch *stk = contextSketch(C, 1);
- RigGraph *rg;
- int index = 0;
-
- if (stk && stk->active_stroke != NULL) {
- index = stk->active_stroke->nb_points;
- }
-
- rg = sk_makeTemplateGraph(C, ts->skgen_template);
-
- if (rg == NULL) {
- return "";
- }
-
- return RIG_nameBone(rg, 0, index);
-}
-
-void BIF_freeTemplates(bContext *UNUSED(C))
-{
- if (TEMPLATES_MENU != NULL) {
- MEM_freeN(TEMPLATES_MENU);
- TEMPLATES_MENU = NULL;
- }
-
- if (TEMPLATES_HASH != NULL) {
- BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
- TEMPLATES_HASH = NULL;
- }
-
- if (TEMPLATE_RIGG != NULL) {
- RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG);
- TEMPLATE_RIGG = NULL;
- }
-}
-
-void BIF_setTemplate(bContext *C, int index)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- if (index > 0) {
- ts->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, POINTER_FROM_INT(index));
- }
- else {
- ts->skgen_template = NULL;
-
- if (TEMPLATE_RIGG != NULL) {
- RIG_freeRigGraph((BGraph *)TEMPLATE_RIGG);
- }
- TEMPLATE_RIGG = NULL;
- }
-}
-
-/*********************** CONVERSION ***************************/
-
-static void sk_autoname(bContext *C, ReebArc *arc)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- if (ts->skgen_retarget_options & SK_RETARGET_AUTONAME) {
- if (arc == NULL) {
- char *num = ts->skgen_num_string;
- int i = atoi(num);
- i++;
- BLI_snprintf(num, 8, "%i", i);
- }
- else {
- char *side = ts->skgen_side_string;
- int valid = 0;
- int caps = 0;
-
- if (side[0] == '\0') {
- valid = 1;
- }
- else if (STREQ(side, "R") || STREQ(side, "L")) {
- valid = 1;
- caps = 1;
- }
- else if (STREQ(side, "r") || STREQ(side, "l")) {
- valid = 1;
- caps = 0;
- }
-
- if (valid) {
- if (arc->head->p[0] < 0) {
- BLI_snprintf(side, 8, caps ? "R" : "r");
- }
- else {
- BLI_snprintf(side, 8, caps ? "L" : "l");
- }
- }
- }
- }
-}
-
-static ReebNode *sk_pointToNode(SK_Point *pt, float imat[4][4], float tmat[3][3])
-{
- ReebNode *node;
-
- node = MEM_callocN(sizeof(ReebNode), "reeb node");
- copy_v3_v3(node->p, pt->p);
- mul_m4_v3(imat, node->p);
-
- copy_v3_v3(node->no, pt->no);
- mul_m3_v3(tmat, node->no);
-
- return node;
-}
-
-static ReebArc *sk_strokeToArc(SK_Stroke *stk, float imat[4][4], float tmat[3][3])
-{
- ReebArc *arc;
- int i;
-
- arc = MEM_callocN(sizeof(ReebArc), "reeb arc");
- arc->head = sk_pointToNode(stk->points, imat, tmat);
- arc->tail = sk_pointToNode(sk_lastStrokePoint(stk), imat, tmat);
-
- arc->bcount = stk->nb_points - 2; /* first and last are nodes, don't count */
- arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "Buckets");
-
- for (i = 0; i < arc->bcount; i++) {
- copy_v3_v3(arc->buckets[i].p, stk->points[i + 1].p);
- mul_m4_v3(imat, arc->buckets[i].p);
-
- copy_v3_v3(arc->buckets[i].no, stk->points[i + 1].no);
- mul_m3_v3(tmat, arc->buckets[i].no);
- }
-
- return arc;
-}
-
-static void sk_retargetStroke(bContext *C, SK_Stroke *stk)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *obedit = CTX_data_edit_object(C);
- float imat[4][4];
- float tmat[3][3];
- ReebArc *arc;
- RigGraph *rg;
-
- invert_m4_m4(imat, obedit->obmat);
- transpose_m3_m4(tmat, obedit->obmat);
-
- arc = sk_strokeToArc(stk, imat, tmat);
-
- sk_autoname(C, arc);
-
- rg = sk_makeTemplateGraph(C, ts->skgen_template);
-
- BIF_retargetArc(C, arc, rg);
-
- sk_autoname(C, NULL);
-
- MEM_freeN(arc->head);
- MEM_freeN(arc->tail);
- REEB_freeArc((BArc *)arc);
-}
-
-/**************************************************************/
-
-static void sk_cancelStroke(SK_Sketch *sketch)
-{
- if (sketch->active_stroke != NULL) {
- sk_resetOverdraw(sketch);
- sk_removeStroke(sketch, sketch->active_stroke);
- }
-}
-
-
-static float sk_clampPointSize(SK_Point *pt, float size)
-{
- return max_ff(size * pt->size, size / 2);
-}
-
-static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size)
-{
- glTranslate3fv(pt->p);
- gluSphere(quad, sk_clampPointSize(pt, size), 8, 8);
-}
-
-static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float size)
-{
- float vec1[3], vec2[3] = {0, 0, 1}, axis[3];
- float angle, length;
-
- sub_v3_v3v3(vec1, pt1->p, pt0->p);
- length = normalize_v3(vec1);
- cross_v3_v3v3(axis, vec2, vec1);
-
- if (is_zero_v3(axis)) {
- axis[1] = 1;
- }
-
- angle = angle_normalized_v3v3(vec2, vec1);
-
- glRotate3fv(angle * (float)(180.0 / M_PI) + 180.0f, axis);
-
- gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8);
-}
-
-static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float height)
-{
- float vec2[3] = {0, 0, 1}, axis[3];
- float angle;
-
- glPushMatrix();
-
- cross_v3_v3v3(axis, vec2, pt->no);
-
- if (is_zero_v3(axis)) {
- axis[1] = 1;
- }
-
- angle = angle_normalized_v3v3(vec2, pt->no);
-
- glRotate3fv(angle * (float)(180.0 / M_PI), axis);
-
- glColor3f(0, 1, 1);
- gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2);
-
- glPopMatrix();
-}
-
-static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int end)
-{
- float rgb[3];
- int i;
- GLUquadric *quad = gluNewQuadric();
- gluQuadricNormals(quad, GLU_SMOOTH);
-
- if (id != -1) {
- GPU_select_load_id(id);
-
- for (i = 0; i < stk->nb_points; i++) {
- glPushMatrix();
-
- sk_drawPoint(quad, stk->points + i, 0.1);
-
- if (i > 0) {
- sk_drawEdge(quad, stk->points + i - 1, stk->points + i, 0.1);
- }
-
- glPopMatrix();
- }
-
- }
- else {
- float d_rgb[3] = {1, 1, 1};
-
- copy_v3_v3(rgb, color);
- sub_v3_v3(d_rgb, rgb);
- mul_v3_fl(d_rgb, 1.0f / (float)stk->nb_points);
-
- for (i = 0; i < stk->nb_points; i++) {
- SK_Point *pt = stk->points + i;
-
- glPushMatrix();
-
- if (pt->type == PT_EXACT) {
- glColor3f(0, 0, 0);
- sk_drawPoint(quad, pt, 0.15);
- sk_drawNormal(quad, pt, 0.05, 0.9);
- }
-
- if (i >= start && i <= end) {
- glColor3f(0.3, 0.3, 0.3);
- }
- else {
- glColor3fv(rgb);
- }
-
- if (pt->type != PT_EXACT) {
-
- sk_drawPoint(quad, pt, 0.1);
- }
-
- if (i > 0) {
- sk_drawEdge(quad, pt - 1, pt, 0.1);
- }
-
- glPopMatrix();
-
- add_v3_v3(rgb, d_rgb);
- }
- }
-
- gluDeleteQuadric(quad);
-}
-
-static void drawSubdividedStrokeBy(ToolSettings *toolsettings, BArcIterator *iter, NextSubdivisionFunc next_subdividion)
-{
- SK_Stroke *stk = ((SK_StrokeIterator *)iter)->stroke;
- float head[3], tail[3];
- int bone_start = 0;
- int end = iter->length;
- int index;
- GLUquadric *quad = gluNewQuadric();
- gluQuadricNormals(quad, GLU_SMOOTH);
-
- iter->head(iter);
- copy_v3_v3(head, iter->p);
-
- index = next_subdividion(toolsettings, iter, bone_start, end, head, tail);
- while (index != -1) {
- SK_Point *pt = stk->points + index;
-
- glPushMatrix();
-
- glColor3f(0, 1, 0);
- sk_drawPoint(quad, pt, 0.15);
-
- sk_drawNormal(quad, pt, 0.05, 0.9);
-
- glPopMatrix();
-
- copy_v3_v3(head, tail);
- bone_start = index; // start next bone from current index
-
- index = next_subdividion(toolsettings, iter, bone_start, end, head, tail);
- }
-
- gluDeleteQuadric(quad);
-}
-
-static void sk_drawStrokeSubdivision(ToolSettings *toolsettings, SK_Stroke *stk)
-{
- int head_index = -1;
- int i;
-
- if (toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET) {
- return;
- }
-
-
- for (i = 0; i < stk->nb_points; i++) {
- SK_Point *pt = stk->points + i;
-
- if (pt->type == PT_EXACT || i == stk->nb_points - 1) /* stop on exact or on last point */ {
- if (head_index == -1) {
- head_index = i;
- }
- else {
- if (i - head_index > 1) {
- SK_StrokeIterator sk_iter;
- BArcIterator *iter = (BArcIterator *)&sk_iter;
-
- initStrokeIterator(iter, stk, head_index, i);
-
- if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) {
- drawSubdividedStrokeBy(toolsettings, iter, nextAdaptativeSubdivision);
- }
- else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) {
- drawSubdividedStrokeBy(toolsettings, iter, nextLengthSubdivision);
- }
- else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED) {
- drawSubdividedStrokeBy(toolsettings, iter, nextFixedSubdivision);
- }
-
- }
-
- head_index = i;
- }
- }
- }
-}
-
-static SK_Point *sk_snapPointStroke(bContext *C, SK_Stroke *stk, int mval[2], float *r_dist_px, int *index, int all_pts)
-{
- ARegion *ar = CTX_wm_region(C);
- SK_Point *pt = NULL;
- int i;
-
- for (i = 0; i < stk->nb_points; i++) {
- if (all_pts || stk->points[i].type == PT_EXACT) {
- short pval[2];
- int pdist;
-
- if (ED_view3d_project_short_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
-
- pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
-
- if (pdist < *r_dist_px) {
- *r_dist_px = pdist;
- pt = stk->points + i;
-
- if (index != NULL) {
- *index = i;
- }
- }
- }
- }
- }
-
- return pt;
-}
-
-#if 0 /* UNUSED 2.5 */
-static SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, int mval[2], int *dist)
-{
- ARegion *ar = CTX_wm_region(C);
- SK_Point *pt = NULL;
- EditBone *bone;
-
- for (bone = ebones->first; bone; bone = bone->next)
- {
- float vec[3];
- short pval[2];
- int pdist;
-
- if ((bone->flag & BONE_CONNECTED) == 0)
- {
- copy_v3_v3(vec, bone->head);
- mul_m4_v3(ob->obmat, vec);
- if (ED_view3d_project_short_noclip(ar, vec, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
-
- pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
-
- if (pdist < *dist)
- {
- *dist = pdist;
- pt = &boneSnap;
- copy_v3_v3(pt->p, vec);
- pt->type = PT_EXACT;
- }
- }
- }
-
-
- copy_v3_v3(vec, bone->tail);
- mul_m4_v3(ob->obmat, vec);
- if (ED_view3d_project_short_noclip(ar, vec, pval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
-
- pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
-
- if (pdist < *dist)
- {
- *dist = pdist;
- pt = &boneSnap;
- copy_v3_v3(pt->p, vec);
- pt->type = PT_EXACT;
- }
- }
- }
-
- return pt;
-}
-#endif
-
-void sk_resetOverdraw(SK_Sketch *sketch)
-{
- sketch->over.target = NULL;
- sketch->over.start = -1;
- sketch->over.end = -1;
- sketch->over.count = 0;
-}
-
-int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk)
-{
- return sketch->over.target &&
- sketch->over.count >= SK_OVERDRAW_LIMIT &&
- (sketch->over.target == stk || stk == NULL) &&
- (sketch->over.start != -1 || sketch->over.end != -1);
-}
-
-static void sk_updateOverdraw(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
-{
- if (sketch->over.target == NULL) {
- SK_Stroke *target;
- int closest_index = -1;
- float dist_px = SNAP_MIN_DISTANCE * 2;
-
- for (target = sketch->strokes.first; target; target = target->next) {
- if (target != stk) {
- int index;
-
- SK_Point *spt = sk_snapPointStroke(C, target, dd->mval, &dist_px, &index, 1);
-
- if (spt != NULL) {
- sketch->over.target = target;
- closest_index = index;
- }
- }
- }
-
- if (sketch->over.target != NULL) {
- if (closest_index > -1) {
- if (sk_lastStrokePoint(stk)->type == PT_EXACT) {
- sketch->over.count = SK_OVERDRAW_LIMIT;
- }
- else {
- sketch->over.count++;
- }
- }
-
- if (stk->nb_points == 1) {
- sketch->over.start = closest_index;
- }
- else {
- sketch->over.end = closest_index;
- }
- }
- }
- else if (sketch->over.target != NULL) {
- SK_Point *closest_pt = NULL;
- float dist_px = SNAP_MIN_DISTANCE * 2;
- int index;
-
- closest_pt = sk_snapPointStroke(C, sketch->over.target, dd->mval, &dist_px, &index, 1);
-
- if (closest_pt != NULL) {
- if (sk_lastStrokePoint(stk)->type == PT_EXACT) {
- sketch->over.count = SK_OVERDRAW_LIMIT;
- }
- else {
- sketch->over.count++;
- }
-
- sketch->over.end = index;
- }
- else {
- sketch->over.end = -1;
- }
- }
-}
-
-/* return 1 on reverse needed */
-static int sk_adjustIndexes(SK_Sketch *sketch, int *start, int *end)
-{
- int retval = 0;
-
- *start = sketch->over.start;
- *end = sketch->over.end;
-
- if (*start == -1) {
- *start = 0;
- }
-
- if (*end == -1) {
- *end = sketch->over.target->nb_points - 1;
- }
-
- if (*end < *start) {
- int tmp = *start;
- *start = *end;
- *end = tmp;
- retval = 1;
- }
-
- return retval;
-}
-
-static void sk_endOverdraw(SK_Sketch *sketch)
-{
- SK_Stroke *stk = sketch->active_stroke;
-
- if (sk_hasOverdraw(sketch, NULL)) {
- int start;
- int end;
-
- if (sk_adjustIndexes(sketch, &start, &end)) {
- sk_reverseStroke(stk);
- }
-
- if (stk->nb_points > 1) {
- stk->points->type = sketch->over.target->points[start].type;
- sk_lastStrokePoint(stk)->type = sketch->over.target->points[end].type;
- }
-
- sk_insertStrokePoints(sketch->over.target, stk->points, stk->nb_points, start, end);
-
- sk_removeStroke(sketch, stk);
-
- sk_resetOverdraw(sketch);
- }
-}
-
-
-static void sk_startStroke(SK_Sketch *sketch)
-{
- SK_Stroke *stk = sk_createStroke();
-
- BLI_addtail(&sketch->strokes, stk);
- sketch->active_stroke = stk;
-
- sk_resetOverdraw(sketch);
-}
-
-static void sk_endStroke(bContext *C, SK_Sketch *sketch)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- sk_shrinkStrokeBuffer(sketch->active_stroke);
-
- if (ts->bone_sketching & BONE_SKETCHING_ADJUST) {
- sk_endOverdraw(sketch);
- }
-
- sketch->active_stroke = NULL;
-}
-
-static void sk_updateDrawData(SK_DrawData *dd)
-{
- dd->type = PT_CONTINUOUS;
-
- dd->previous_mval[0] = dd->mval[0];
- dd->previous_mval[1] = dd->mval[1];
-}
-
-static float sk_distanceDepth(bContext *C, float p1[3], float p2[3])
-{
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
- float vec[3];
- float distance;
-
- sub_v3_v3v3(vec, p1, p2);
-
- project_v3_v3v3(vec, vec, rv3d->viewinv[2]);
-
- distance = len_v3(vec);
-
- if (dot_v3v3(rv3d->viewinv[2], vec) > 0) {
- distance *= -1;
- }
-
- return distance;
-}
-
-static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float length, float distance)
-{
- ARegion *ar = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
-
- float progress = 0;
- int i;
-
- progress = len_v3v3(stk->points[start].p, stk->points[start - 1].p);
-
- for (i = start; i <= end; i++) {
- float ray_start[3], ray_normal[3];
- float delta = len_v3v3(stk->points[i].p, stk->points[i + 1].p);
- float pval[2] = {0, 0};
-
- ED_view3d_project_float_global(ar, stk->points[i].p, pval, V3D_PROJ_TEST_NOP);
- ED_view3d_win_to_ray_clipped(ar, v3d, pval, ray_start, ray_normal, false);
-
- mul_v3_fl(ray_normal, distance * progress / length);
- add_v3_v3(stk->points[i].p, ray_normal);
-
- progress += delta;
- }
-}
-
-static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_DrawData *dd)
-{
- ARegion *ar = CTX_wm_region(C);
- /* copied from grease pencil, need fixing */
- SK_Point *last = sk_lastStrokePoint(stk);
- short cval[2];
- float fp[3] = {0, 0, 0};
- float dvec[3];
- float mval_f[2];
- float zfac;
-
- if (last != NULL) {
- copy_v3_v3(fp, last->p);
- }
-
- zfac = ED_view3d_calc_zfac(ar->regiondata, fp, NULL);
-
- if (ED_view3d_project_short_global(ar, fp, cval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- VECSUB2D(mval_f, cval, dd->mval);
- ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
- sub_v3_v3v3(vec, fp, dvec);
- }
- else {
- zero_v3(vec);
- }
-}
-
-static int sk_getStrokeDrawPoint(bContext *C, SK_Point *pt, SK_Sketch *UNUSED(sketch), SK_Stroke *stk, SK_DrawData *dd)
-{
- pt->type = dd->type;
- pt->mode = PT_PROJECT;
- sk_projectDrawPoint(C, pt->p, stk, dd);
-
- return 1;
-}
-
-static int sk_addStrokeDrawPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
-{
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
- SK_Point pt;
-
- sk_initPoint(&pt, dd, rv3d->viewinv[2]);
-
- sk_getStrokeDrawPoint(C, &pt, sketch, stk, dd);
-
- sk_appendStrokePoint(stk, &pt);
-
- return 1;
-}
-
-static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- int point_added = 0;
-
- /* TODO: Since the function `ED_transform_snap_object_context_create_view3d` creates a cache,
- * the ideal would be to call this function only at the beginning of the snap operation,
- * or at the beginning of the operator itself */
- struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), 0,
- CTX_wm_region(C), CTX_wm_view3d(C));
-
- float mvalf[2] = {UNPACK2(dd->mval)};
- float loc[3], dummy_no[3];
-
- if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) {
- float size;
- if (peelObjectsSnapContext(
- snap_context, mvalf,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_SELECTED,
- .use_object_edit_cage = false,
- },
- (ts->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
- loc, dummy_no, &size))
- {
- pt->type = dd->type;
- pt->mode = PT_SNAP;
- pt->size = size / 2;
- copy_v3_v3(pt->p, loc);
-
- point_added = 1;
- }
- }
- else {
- SK_Stroke *snap_stk;
- float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
-
- /* snap to strokes */
- // if (ts->snap_mode == SCE_SNAP_MODE_VERTEX) /* snap all the time to strokes */
- for (snap_stk = sketch->strokes.first; snap_stk; snap_stk = snap_stk->next) {
- SK_Point *spt = NULL;
- if (snap_stk == stk) {
- spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist_px, NULL, 0);
- }
- else {
- spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist_px, NULL, 1);
- }
-
- if (spt != NULL) {
- copy_v3_v3(pt->p, spt->p);
- point_added = 1;
- }
- }
-
- /* try to snap to closer object */
- {
- if (ED_transform_snap_object_project_view3d(
- snap_context,
- ts->snap_mode,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_SELECTED,
- .use_object_edit_cage = false,
- },
- mvalf, &dist_px, NULL,
- loc, dummy_no))
- {
- pt->type = dd->type;
- pt->mode = PT_SNAP;
- copy_v3_v3(pt->p, loc);
-
- point_added = 1;
- }
- }
- }
-
- /* TODO: The ideal would be to call this function only once.
- * At the end of the operator */
- ED_transform_snap_object_context_destroy(snap_context);
- return point_added;
-}
-
-static int sk_addStrokeSnapPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
-{
- int point_added;
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
- SK_Point pt;
-
- sk_initPoint(&pt, dd, rv3d->viewinv[2]);
-
- point_added = sk_getStrokeSnapPoint(C, &pt, sketch, stk, dd);
-
- if (point_added) {
- float final_p[3];
- float length, distance;
- int total;
- int i;
-
- copy_v3_v3(final_p, pt.p);
-
- sk_projectDrawPoint(C, pt.p, stk, dd);
- sk_appendStrokePoint(stk, &pt);
-
- /* update all previous point to give smooth Z progresion */
- total = 0;
- length = 0;
- for (i = stk->nb_points - 2; i > 0; i--) {
- length += len_v3v3(stk->points[i].p, stk->points[i + 1].p);
- total++;
- if (stk->points[i].mode == PT_SNAP || stk->points[i].type == PT_EXACT) {
- break;
- }
- }
-
- if (total > 1) {
- distance = sk_distanceDepth(C, final_p, stk->points[i].p);
-
- sk_interpolateDepth(C, stk, i + 1, stk->nb_points - 2, length, distance);
- }
-
- copy_v3_v3(stk->points[stk->nb_points - 1].p, final_p);
-
- point_added = 1;
- }
-
- return point_added;
-}
-
-static void sk_addStrokePoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, const bool snap)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- int point_added = 0;
-
- if (snap) {
- point_added = sk_addStrokeSnapPoint(C, sketch, stk, dd);
- }
-
- if (point_added == 0) {
- point_added = sk_addStrokeDrawPoint(C, sketch, stk, dd);
- }
-
- if (stk == sketch->active_stroke && ts->bone_sketching & BONE_SKETCHING_ADJUST) {
- sk_updateOverdraw(C, sketch, stk, dd);
- }
-}
-
-static void sk_getStrokePoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, const bool snap)
-{
- int point_added = 0;
-
- if (snap) {
- point_added = sk_getStrokeSnapPoint(C, pt, sketch, stk, dd);
- LAST_SNAP_POINT_VALID = 1;
- copy_v3_v3(LAST_SNAP_POINT, pt->p);
- }
- else {
- LAST_SNAP_POINT_VALID = 0;
- }
-
- if (point_added == 0) {
- point_added = sk_getStrokeDrawPoint(C, pt, sketch, stk, dd);
- }
-}
-
-/********************************************/
-
-static void *headPoint(void *arg);
-static void *tailPoint(void *arg);
-static void *nextPoint(void *arg);
-static void *nextNPoint(void *arg, int n);
-static void *peekPoint(void *arg, int n);
-static void *previousPoint(void *arg);
-static int iteratorStopped(void *arg);
-
-static void initIteratorFct(SK_StrokeIterator *iter)
-{
- iter->head = headPoint;
- iter->tail = tailPoint;
- iter->peek = peekPoint;
- iter->next = nextPoint;
- iter->nextN = nextNPoint;
- iter->previous = previousPoint;
- iter->stopped = iteratorStopped;
-}
-
-static SK_Point *setIteratorValues(SK_StrokeIterator *iter, int index)
-{
- SK_Point *pt = NULL;
-
- if (index >= 0 && index < iter->length) {
- pt = &(iter->stroke->points[iter->start + (iter->stride * index)]);
- iter->p = pt->p;
- iter->no = pt->no;
- iter->size = pt->size;
- }
- else {
- iter->p = NULL;
- iter->no = NULL;
- iter->size = 0;
- }
-
- return pt;
-}
-
-void initStrokeIterator(BArcIterator *arg, SK_Stroke *stk, int start, int end)
-{
- SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
-
- initIteratorFct(iter);
- iter->stroke = stk;
-
- if (start < end) {
- iter->start = start + 1;
- iter->end = end - 1;
- iter->stride = 1;
- }
- else {
- iter->start = start - 1;
- iter->end = end + 1;
- iter->stride = -1;
- }
-
- iter->length = iter->stride * (iter->end - iter->start + 1);
-
- iter->index = -1;
-}
-
-
-static void *headPoint(void *arg)
-{
- SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
- SK_Point *result = NULL;
-
- result = &(iter->stroke->points[iter->start - iter->stride]);
- iter->p = result->p;
- iter->no = result->no;
- iter->size = result->size;
-
- return result;
-}
-
-static void *tailPoint(void *arg)
-{
- SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
- SK_Point *result = NULL;
-
- result = &(iter->stroke->points[iter->end + iter->stride]);
- iter->p = result->p;
- iter->no = result->no;
- iter->size = result->size;
-
- return result;
-}
-
-static void *nextPoint(void *arg)
-{
- SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
- SK_Point *result = NULL;
-
- iter->index++;
- if (iter->index < iter->length) {
- result = setIteratorValues(iter, iter->index);
- }
-
- return result;
-}
-
-static void *nextNPoint(void *arg, int n)
-{
- SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
- SK_Point *result = NULL;
-
- iter->index += n;
-
- /* check if passed end */
- if (iter->index < iter->length) {
- result = setIteratorValues(iter, iter->index);
- }
-
- return result;
-}
-
-static void *peekPoint(void *arg, int n)
-{
- SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
- SK_Point *result = NULL;
- int index = iter->index + n;
-
- /* check if passed end */
- if (index < iter->length) {
- result = setIteratorValues(iter, index);
- }
-
- return result;
-}
-
-static void *previousPoint(void *arg)
-{
- SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
- SK_Point *result = NULL;
-
- if (iter->index > 0) {
- iter->index--;
- result = setIteratorValues(iter, iter->index);
- }
-
- return result;
-}
-
-static int iteratorStopped(void *arg)
-{
- SK_StrokeIterator *iter = (SK_StrokeIterator *)arg;
-
- if (iter->index >= iter->length) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static void sk_convertStroke(bContext *C, SK_Stroke *stk)
-{
- Object *obedit = CTX_data_edit_object(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- bArmature *arm = obedit->data;
- SK_Point *head;
- EditBone *parent = NULL;
- float invmat[4][4]; /* move in caller function */
- float tmat[3][3];
- int head_index = 0;
- int i;
-
- head = NULL;
-
- invert_m4_m4(invmat, obedit->obmat);
- transpose_m3_m4(tmat, obedit->obmat);
-
- for (i = 0; i < stk->nb_points; i++) {
- SK_Point *pt = stk->points + i;
-
- if (pt->type == PT_EXACT) {
- if (head == NULL) {
- head_index = i;
- head = pt;
- }
- else {
- EditBone *bone = NULL;
- EditBone *new_parent;
-
- if (i - head_index > 1) {
- SK_StrokeIterator sk_iter;
- BArcIterator *iter = (BArcIterator *)&sk_iter;
-
- initStrokeIterator(iter, stk, head_index, i);
-
- if (ts->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE) {
- bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
- }
- else if (ts->bone_sketching_convert == SK_CONVERT_CUT_LENGTH) {
- bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision);
- }
- else if (ts->bone_sketching_convert == SK_CONVERT_CUT_FIXED) {
- bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextFixedSubdivision);
- }
- }
-
- if (bone == NULL) {
- bone = ED_armature_ebone_add(arm, "Bone");
-
- copy_v3_v3(bone->head, head->p);
- copy_v3_v3(bone->tail, pt->p);
-
- mul_m4_v3(invmat, bone->head);
- mul_m4_v3(invmat, bone->tail);
- setBoneRollFromNormal(bone, head->no, invmat, tmat);
- }
-
- new_parent = bone;
- bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
-
- /* move to end of chain */
- while (bone->parent != NULL) {
- bone = bone->parent;
- bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
- }
-
- if (parent != NULL) {
- bone->parent = parent;
- bone->flag |= BONE_CONNECTED;
- }
-
- parent = new_parent;
- head_index = i;
- head = pt;
- }
- }
- }
-}
-
-static void sk_convert(bContext *C, SK_Sketch *sketch)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- SK_Stroke *stk;
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- if (stk->selected == 1) {
- if (ts->bone_sketching_convert == SK_CONVERT_RETARGET) {
- sk_retargetStroke(C, stk);
- }
- else {
- sk_convertStroke(C, stk);
- }
-// XXX
-// allqueue(REDRAWBUTSEDIT, 0);
- }
- }
-}
-/******************* GESTURE *************************/
-
-
-/* returns the number of self intersections */
-static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gesture)
-{
- ARegion *ar = CTX_wm_region(C);
- int added = 0;
- int s_i;
-
- for (s_i = 0; s_i < gesture->nb_points - 1; s_i++) {
- float s_p1[3] = {0, 0, 0};
- float s_p2[3] = {0, 0, 0};
- int g_i;
-
- ED_view3d_project_float_global(ar, gesture->points[s_i].p, s_p1, V3D_PROJ_TEST_NOP);
- ED_view3d_project_float_global(ar, gesture->points[s_i + 1].p, s_p2, V3D_PROJ_TEST_NOP);
-
- /* start checking from second next, because two consecutive cannot intersect */
- for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++) {
- float g_p1[3] = {0, 0, 0};
- float g_p2[3] = {0, 0, 0};
- float vi[3];
- float lambda;
-
- ED_view3d_project_float_global(ar, gesture->points[g_i].p, g_p1, V3D_PROJ_TEST_NOP);
- ED_view3d_project_float_global(ar, gesture->points[g_i + 1].p, g_p2, V3D_PROJ_TEST_NOP);
-
- if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) {
- SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
-
- isect->gesture_index = g_i;
- isect->before = s_i;
- isect->after = s_i + 1;
- isect->stroke = gesture;
-
- sub_v3_v3v3(isect->p, gesture->points[s_i + 1].p, gesture->points[s_i].p);
- mul_v3_fl(isect->p, lambda);
- add_v3_v3(isect->p, gesture->points[s_i].p);
-
- BLI_addtail(list, isect);
-
- added++;
- }
- }
- }
-
- return added;
-}
-
-static int cmpIntersections(const void *i1, const void *i2)
-{
- const SK_Intersection *isect1 = i1, *isect2 = i2;
-
- if (isect1->stroke == isect2->stroke) {
- if (isect1->before < isect2->before) {
- return -1;
- }
- else if (isect1->before > isect2->before) {
- return 1;
- }
- else {
- if (isect1->lambda < isect2->lambda) {
- return -1;
- }
- else if (isect1->lambda > isect2->lambda) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-
-/* returns the maximum number of intersections per stroke */
-static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture)
-{
- ARegion *ar = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- SK_Stroke *stk;
- int added = 0;
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- int s_added = 0;
- int s_i;
-
- for (s_i = 0; s_i < stk->nb_points - 1; s_i++) {
- float s_p1[3] = {0, 0, 0};
- float s_p2[3] = {0, 0, 0};
- int g_i;
-
- ED_view3d_project_float_global(ar, stk->points[s_i].p, s_p1, V3D_PROJ_TEST_NOP);
- ED_view3d_project_float_global(ar, stk->points[s_i + 1].p, s_p2, V3D_PROJ_TEST_NOP);
-
- for (g_i = 0; g_i < gesture->nb_points - 1; g_i++) {
- float g_p1[3] = {0, 0, 0};
- float g_p2[3] = {0, 0, 0};
- float vi[3];
- float lambda;
-
- ED_view3d_project_float_global(ar, gesture->points[g_i].p, g_p1, V3D_PROJ_TEST_NOP);
- ED_view3d_project_float_global(ar, gesture->points[g_i + 1].p, g_p2, V3D_PROJ_TEST_NOP);
-
- if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda)) {
- SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
- float ray_start[3], ray_end[3];
- float mval[2];
-
- isect->gesture_index = g_i;
- isect->before = s_i;
- isect->after = s_i + 1;
- isect->stroke = stk;
- isect->lambda = lambda;
-
- mval[0] = vi[0];
- mval[1] = vi[1];
- ED_view3d_win_to_segment_clipped(ar, v3d, mval, ray_start, ray_end, true);
-
- isect_line_line_v3(stk->points[s_i].p,
- stk->points[s_i + 1].p,
- ray_start,
- ray_end,
- isect->p,
- vi);
-
- BLI_addtail(list, isect);
-
- s_added++;
- }
- }
- }
-
- added = MAX2(s_added, added);
- }
-
- BLI_listbase_sort(list, cmpIntersections);
-
- return added;
-}
-
-static int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
-{
- SK_StrokeIterator sk_iter;
- BArcIterator *iter = (BArcIterator *)&sk_iter;
-
- float CORRELATION_THRESHOLD = 0.99f;
- float *vec;
- int i, j;
-
- sk_appendStrokePoint(segments, &gesture->points[0]);
- vec = segments->points[segments->nb_points - 1].p;
-
- initStrokeIterator(iter, gesture, 0, gesture->nb_points - 1);
-
- for (i = 1, j = 0; i < gesture->nb_points; i++) {
- float n[3];
-
- /* Calculate normal */
- sub_v3_v3v3(n, gesture->points[i].p, vec);
-
- if (calcArcCorrelation(iter, j, i, vec, n) < CORRELATION_THRESHOLD) {
- j = i - 1;
- sk_appendStrokePoint(segments, &gesture->points[j]);
- vec = segments->points[segments->nb_points - 1].p;
- segments->points[segments->nb_points - 1].type = PT_EXACT;
- }
- }
-
- sk_appendStrokePoint(segments, &gesture->points[gesture->nb_points - 1]);
-
- return segments->nb_points - 1;
-}
-
-int sk_detectCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- if (gest->nb_segments == 1 && gest->nb_intersections == 1) {
- return 1;
- }
-
- return 0;
-}
-
-void sk_applyCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- SK_Intersection *isect;
-
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- SK_Point pt;
-
- pt.type = PT_EXACT;
- pt.mode = PT_PROJECT; /* take mode from neighboring points */
- copy_v3_v3(pt.p, isect->p);
- copy_v3_v3(pt.no, isect->stroke->points[isect->before].no);
-
- sk_insertStrokePoint(isect->stroke, &pt, isect->after);
- }
-}
-
-int sk_detectTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- if (gest->nb_segments == 2 && gest->nb_intersections == 1 && gest->nb_self_intersections == 0) {
- float s1[3], s2[3];
- float angle;
-
- sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p);
- sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p);
-
- angle = RAD2DEGF(angle_v2v2(s1, s2));
-
- if (angle > 60 && angle < 120) {
- return 1;
- }
- }
-
- return 0;
-}
-
-void sk_applyTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- SK_Intersection *isect;
- float trim_dir[3];
-
- sub_v3_v3v3(trim_dir, gest->segments->points[2].p, gest->segments->points[1].p);
-
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- SK_Point pt;
- float stroke_dir[3];
-
- pt.type = PT_EXACT;
- pt.mode = PT_PROJECT; /* take mode from neighboring points */
- copy_v3_v3(pt.p, isect->p);
- copy_v3_v3(pt.no, isect->stroke->points[isect->before].no);
-
- sub_v3_v3v3(stroke_dir, isect->stroke->points[isect->after].p, isect->stroke->points[isect->before].p);
-
- /* same direction, trim end */
- if (dot_v3v3(stroke_dir, trim_dir) > 0) {
- sk_replaceStrokePoint(isect->stroke, &pt, isect->after);
- sk_trimStroke(isect->stroke, 0, isect->after);
- }
- /* else, trim start */
- else {
- sk_replaceStrokePoint(isect->stroke, &pt, isect->before);
- sk_trimStroke(isect->stroke, isect->before, isect->stroke->nb_points - 1);
- }
-
- }
-}
-
-int sk_detectCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1) {
- SK_Intersection *isect, *self_isect;
-
- /* get the last intersection of the first pair */
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- if (isect->stroke == isect->next->stroke) {
- isect = isect->next;
- break;
- }
- }
-
- self_isect = gest->self_intersections.first;
-
- if (isect && isect->gesture_index < self_isect->gesture_index) {
- return 1;
- }
- }
-
- return 0;
-}
-
-void sk_applyCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- SK_Intersection *isect;
- int command = 1;
-
-/* XXX */
-/* command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3"); */
- if (command < 1) return;
-
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- SK_Intersection *i2;
-
- i2 = isect->next;
-
- if (i2 && i2->stroke == isect->stroke) {
- switch (command) {
- case 1:
- sk_flattenStroke(isect->stroke, isect->before, i2->after);
- break;
- case 2:
- sk_straightenStroke(isect->stroke, isect->before, i2->after, isect->p, i2->p);
- break;
- case 3:
- sk_polygonizeStroke(isect->stroke, isect->before, i2->after);
- break;
- }
-
- isect = i2;
- }
- }
-}
-
-int sk_detectDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- if (gest->nb_segments == 2 && gest->nb_intersections == 2) {
- float s1[3], s2[3];
- float angle;
-
- sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p);
- sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p);
-
- angle = RAD2DEGF(angle_v2v2(s1, s2));
-
- if (angle > 120) {
- return 1;
- }
- }
-
- return 0;
-}
-
-void sk_applyDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *sketch)
-{
- SK_Intersection *isect;
-
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- /* only delete strokes that are crossed twice */
- if (isect->next && isect->next->stroke == isect->stroke) {
- isect = isect->next;
-
- sk_removeStroke(sketch, isect->stroke);
- }
- }
-}
-
-int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- ARegion *ar = CTX_wm_region(C);
- if (gest->nb_segments > 2 && gest->nb_intersections == 2) {
- int start_val[2], end_val[2];
- int dist;
-
- if ((ED_view3d_project_int_global(ar, gest->stk->points[0].p, start_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
- (ED_view3d_project_int_global(ar, sk_lastStrokePoint(gest->stk)->p, end_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
- {
- dist = len_manhattan_v2v2_int(start_val, end_val);
-
- /* if gesture is a circle */
- if (dist <= 20) {
- SK_Intersection *isect;
-
- /* check if it circled around an exact point */
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- /* only delete strokes that are crossed twice */
- if (isect->next && isect->next->stroke == isect->stroke) {
- int start_index, end_index;
- int i;
-
- start_index = MIN2(isect->after, isect->next->after);
- end_index = MAX2(isect->before, isect->next->before);
-
- for (i = start_index; i <= end_index; i++) {
- if (isect->stroke->points[i].type == PT_EXACT) {
- return 1; /* at least one exact point found, stop detect here */
- }
- }
-
- /* skip next */
- isect = isect->next;
- }
- }
- }
- }
- }
-
- return 0;
-}
-
-void sk_applyMergeGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- SK_Intersection *isect;
-
- /* check if it circled around an exact point */
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- /* only merge strokes that are crossed twice */
- if (isect->next && isect->next->stroke == isect->stroke) {
- int start_index, end_index;
- int i;
-
- start_index = MIN2(isect->after, isect->next->after);
- end_index = MAX2(isect->before, isect->next->before);
-
- for (i = start_index; i <= end_index; i++) {
- /* if exact, switch to continuous */
- if (isect->stroke->points[i].type == PT_EXACT) {
- isect->stroke->points[i].type = PT_CONTINUOUS;
- }
- }
-
- /* skip next */
- isect = isect->next;
- }
- }
-}
-
-int sk_detectReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 0) {
- SK_Intersection *isect;
-
- /* check if it circled around an exact point */
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- /* only delete strokes that are crossed twice */
- if (isect->next && isect->next->stroke == isect->stroke) {
- float start_v[3], end_v[3];
- float angle;
-
- if (isect->gesture_index < isect->next->gesture_index) {
- sub_v3_v3v3(start_v, isect->p, gest->stk->points[0].p);
- sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->next->p);
- }
- else {
- sub_v3_v3v3(start_v, isect->next->p, gest->stk->points[0].p);
- sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->p);
- }
-
- angle = RAD2DEGF(angle_v2v2(start_v, end_v));
-
- if (angle > 120) {
- return 1;
- }
-
- /* skip next */
- isect = isect->next;
- }
- }
- }
-
- return 0;
-}
-
-void sk_applyReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- SK_Intersection *isect;
-
- for (isect = gest->intersections.first; isect; isect = isect->next) {
- /* only reverse strokes that are crossed twice */
- if (isect->next && isect->next->stroke == isect->stroke) {
- sk_reverseStroke(isect->stroke);
-
- /* skip next */
- isect = isect->next;
- }
- }
-}
-
-int sk_detectConvertGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
-{
- if (gest->nb_segments == 3 && gest->nb_self_intersections == 1) {
- return 1;
- }
- return 0;
-}
-
-void sk_applyConvertGesture(bContext *C, SK_Gesture *UNUSED(gest), SK_Sketch *sketch)
-{
- sk_convert(C, sketch);
-}
-
-static void sk_initGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch)
-{
- BLI_listbase_clear(&gest->intersections);
- BLI_listbase_clear(&gest->self_intersections);
-
- gest->segments = sk_createStroke();
- gest->stk = sketch->gesture;
-
- gest->nb_self_intersections = sk_getSelfIntersections(C, &gest->self_intersections, gest->stk);
- gest->nb_intersections = sk_getIntersections(C, &gest->intersections, sketch, gest->stk);
- gest->nb_segments = sk_getSegments(gest->segments, gest->stk);
-}
-
-static void sk_freeGesture(SK_Gesture *gest)
-{
- sk_freeStroke(gest->segments);
- BLI_freelistN(&gest->intersections);
- BLI_freelistN(&gest->self_intersections);
-}
-
-static void sk_applyGesture(bContext *C, SK_Sketch *sketch)
-{
- SK_Gesture gest;
- SK_GestureAction *act;
-
- sk_initGesture(C, &gest, sketch);
-
- /* detect and apply */
- for (act = GESTURE_ACTIONS; act->apply != NULL; act++) {
- if (act->detect(C, &gest, sketch)) {
- act->apply(C, &gest, sketch);
- break;
- }
- }
-
- sk_freeGesture(&gest);
-}
-
-/********************************************/
-
-
-static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], const bool extend)
-{
- ViewContext vc;
- rcti rect;
- unsigned int buffer[MAXPICKBUF];
- short hits;
-
- ED_view3d_viewcontext_init(C, &vc);
-
- BLI_rcti_init_pt_radius(&rect, mval, 5);
-
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
-
- if (hits > 0) {
- int besthitresult = -1;
-
- if (hits == 1) {
- besthitresult = buffer[3];
- }
- else {
- besthitresult = buffer[3];
- /* loop and get best hit */
- }
-
- if (besthitresult > 0) {
- SK_Stroke *selected_stk = BLI_findlink(&sketch->strokes, besthitresult - 1);
-
- if (extend == 0) {
- sk_selectAllSketch(sketch, -1);
-
- selected_stk->selected = 1;
- }
- else {
- selected_stk->selected ^= 1;
- }
-
-
- }
- return 1;
- }
-
- return 0;
-}
-
-#if 0 /* UNUSED 2.5 */
-static void sk_queueRedrawSketch(SK_Sketch *sketch)
-{
- if (sketch->active_stroke != NULL)
- {
- SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
-
- if (last != NULL)
- {
-// XXX
-// allqueue(REDRAWVIEW3D, 0);
- }
- }
-}
-#endif
-
-static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, int with_names)
-{
- ToolSettings *ts = scene->toolsettings;
- SK_Stroke *stk;
-
- glClear(GL_DEPTH_BUFFER_BIT);
- glEnable(GL_DEPTH_TEST);
-
- if (with_names) {
- int id;
- for (id = 1, stk = sketch->strokes.first; stk; id++, stk = stk->next) {
- sk_drawStroke(stk, id, NULL, -1, -1);
- }
-
- GPU_select_load_id(-1);
- }
- else {
- float selected_rgb[3] = {1, 0, 0};
- float unselected_rgb[3] = {1, 0.5, 0};
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- int start = -1;
- int end = -1;
-
- if (sk_hasOverdraw(sketch, stk)) {
- sk_adjustIndexes(sketch, &start, &end);
- }
-
- sk_drawStroke(stk, -1, (stk->selected == 1 ? selected_rgb : unselected_rgb), start, end);
-
- if (stk->selected == 1) {
- sk_drawStrokeSubdivision(ts, stk);
- }
- }
-
- if (sketch->active_stroke != NULL) {
- SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
-
- if (ts->bone_sketching & BONE_SKETCHING_QUICK) {
- sk_drawStrokeSubdivision(ts, sketch->active_stroke);
- }
-
- if (last != NULL) {
- GLUquadric *quad = gluNewQuadric();
- gluQuadricNormals(quad, GLU_SMOOTH);
-
- glPushMatrix();
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- switch (sketch->next_point.mode) {
- case PT_SNAP:
- glColor3f(0, 1, 0);
- break;
- case PT_PROJECT:
- glColor3f(0, 0, 0);
- break;
- }
-
- sk_drawPoint(quad, &sketch->next_point, 0.1);
-
- glColor4f(selected_rgb[0], selected_rgb[1], selected_rgb[2], 0.3);
-
- sk_drawEdge(quad, last, &sketch->next_point, 0.1);
-
- glDisable(GL_BLEND);
-
- glPopMatrix();
-
- gluDeleteQuadric(quad);
- }
- }
- }
-
-#if 0
- if (BLI_listbase_is_empty(&sketch->depth_peels) == false) {
- float colors[8][3] = {
- {1, 0, 0},
- {0, 1, 0},
- {0, 0, 1},
- {1, 1, 0},
- {1, 0, 1},
- {0, 1, 1},
- {1, 1, 1},
- {0, 0, 0}
- };
- DepthPeel *p;
- GLUquadric *quad = gluNewQuadric();
- gluQuadricNormals(quad, GLU_SMOOTH);
-
- for (p = sketch->depth_peels.first; p; p = p->next)
- {
- int index = POINTER_AS_INT(p->ob);
- index = (index >> 5) & 7;
-
- glColor3fv(colors[index]);
- glPushMatrix();
- glTranslate3fv(p->p);
- gluSphere(quad, 0.02, 8, 8);
- glPopMatrix();
- }
-
- gluDeleteQuadric(quad);
- }
-#endif
-
- glDisable(GL_DEPTH_TEST);
-
- /* only draw gesture in active area */
- if (sketch->gesture != NULL /* && area_is_active_area(G.vd->area) */) {
- float gesture_rgb[3] = {0, 0.5, 1};
- sk_drawStroke(sketch->gesture, -1, gesture_rgb, -1, -1);
- }
-}
-
-static int sk_finish_stroke(bContext *C, SK_Sketch *sketch)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- if (sketch->active_stroke != NULL) {
- SK_Stroke *stk = sketch->active_stroke;
-
- sk_endStroke(C, sketch);
-
- if (ts->bone_sketching & BONE_SKETCHING_QUICK) {
- if (ts->bone_sketching_convert == SK_CONVERT_RETARGET) {
- sk_retargetStroke(C, stk);
- }
- else {
- sk_convertStroke(C, stk);
- }
-// XXX
-// BIF_undo_push("Convert Sketch");
- sk_removeStroke(sketch, stk);
-// XXX
-// allqueue(REDRAWBUTSEDIT, 0);
- }
-
-// XXX
-// allqueue(REDRAWVIEW3D, 0);
- return 1;
- }
-
- return 0;
-}
-
-static void sk_start_draw_stroke(SK_Sketch *sketch)
-{
- if (sketch->active_stroke == NULL) {
- sk_startStroke(sketch);
- sk_selectAllSketch(sketch, -1);
-
- sketch->active_stroke->selected = 1;
- }
-}
-
-static void sk_start_draw_gesture(SK_Sketch *sketch)
-{
- sketch->gesture = sk_createStroke();
-}
-
-static int sk_draw_stroke(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, bool snap)
-{
- if (sk_stroke_filtermval(dd)) {
- sk_addStrokePoint(C, sketch, stk, dd, snap);
- sk_updateDrawData(dd);
- sk_updateNextPoint(sketch, stk);
-
- return 1;
- }
-
- return 0;
-}
-
-static int ValidSketchViewContext(ViewContext *vc)
-{
- Object *obedit = vc->obedit;
- Scene *scene = vc->scene;
-
- if (obedit &&
- obedit->type == OB_ARMATURE &&
- scene->toolsettings->bone_sketching & BONE_SKETCHING)
- {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-int BDR_drawSketchNames(ViewContext *vc)
-{
- if (ValidSketchViewContext(vc)) {
- SK_Sketch *sketch = viewcontextSketch(vc, 0);
- if (sketch) {
- sk_drawSketch(vc->scene, vc->v3d, sketch, 1);
- return 1;
- }
- }
-
- return 0;
-}
-
-void BDR_drawSketch(const bContext *C)
-{
- if (ED_operator_sketch_mode(C)) {
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch) {
- sk_drawSketch(CTX_data_scene(C), CTX_wm_view3d(C), sketch, 0);
- }
- }
-}
-
-static int sketch_delete(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
-{
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch) {
- sk_deleteSelectedStrokes(sketch);
-// allqueue(REDRAWVIEW3D, 0);
- }
- WM_event_add_notifier(C, NC_SCREEN | ND_SKETCH | NA_REMOVED, NULL);
- return OPERATOR_FINISHED;
-}
-
-bool BIF_sk_selectStroke(bContext *C, const int mval[2], const bool extend)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- SK_Sketch *sketch = contextSketch(C, 0);
-
- if (sketch != NULL && ts->bone_sketching & BONE_SKETCHING) {
- if (sk_selectStroke(C, sketch, mval, extend)) {
- ED_area_tag_redraw(CTX_wm_area(C));
- return true;
- }
- }
-
- return false;
-}
-
-void BIF_convertSketch(bContext *C)
-{
- if (ED_operator_sketch_full_mode(C)) {
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch) {
- sk_convert(C, sketch);
-// BIF_undo_push("Convert Sketch");
-// allqueue(REDRAWVIEW3D, 0);
-// allqueue(REDRAWBUTSEDIT, 0);
- }
- }
-}
-
-void BIF_deleteSketch(bContext *C)
-{
- if (ED_operator_sketch_full_mode(C)) {
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch) {
- sk_deleteSelectedStrokes(sketch);
-// BIF_undo_push("Convert Sketch");
-// allqueue(REDRAWVIEW3D, 0);
- }
- }
-}
-
-#if 0
-void BIF_selectAllSketch(bContext *C, int mode)
-{
- if (BIF_validSketchMode(C))
- {
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch)
- {
- sk_selectAllSketch(sketch, mode);
-// XXX
-// allqueue(REDRAWVIEW3D, 0);
- }
- }
-}
-#endif
-
-SK_Sketch *contextSketch(const bContext *C, int create)
-{
- Object *obedit = CTX_data_edit_object(C);
- SK_Sketch *sketch = NULL;
-
- if (obedit && obedit->type == OB_ARMATURE) {
- bArmature *arm = obedit->data;
-
- if (arm->sketch == NULL && create) {
- arm->sketch = createSketch();
- }
- sketch = arm->sketch;
- }
-
- return sketch;
-}
-
-SK_Sketch *viewcontextSketch(ViewContext *vc, int create)
-{
- Object *obedit = vc->obedit;
- SK_Sketch *sketch = NULL;
-
- if (obedit && obedit->type == OB_ARMATURE) {
- bArmature *arm = obedit->data;
-
- if (arm->sketch == NULL && create) {
- arm->sketch = createSketch();
- }
- sketch = arm->sketch;
- }
-
- return sketch;
-}
-
-static int sketch_convert(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
-{
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch != NULL) {
- sk_convert(C, sketch);
- ED_area_tag_redraw(CTX_wm_area(C));
- }
- return OPERATOR_FINISHED;
-}
-
-static int sketch_cancel_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
-{
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch != NULL) {
- sk_cancelStroke(sketch);
- ED_area_tag_redraw(CTX_wm_area(C));
- return OPERATOR_FINISHED;
- }
- return OPERATOR_PASS_THROUGH;
-}
-
-static int sketch_finish(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
-{
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch != NULL) {
- if (sk_finish_stroke(C, sketch)) {
- ED_area_tag_redraw(CTX_wm_area(C));
- return OPERATOR_FINISHED;
- }
- }
- return OPERATOR_PASS_THROUGH;
-}
-
-static int sketch_select(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
-{
- SK_Sketch *sketch = contextSketch(C, 0);
- if (sketch) {
- short extend = 0;
- if (sk_selectStroke(C, sketch, event->mval, extend))
- ED_area_tag_redraw(CTX_wm_area(C));
- }
-
- return OPERATOR_FINISHED;
-}
-
-static void sketch_draw_stroke_cancel(bContext *C, wmOperator *op)
-{
- SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
- sk_cancelStroke(sketch);
- MEM_freeN(op->customdata);
-}
-
-static int sketch_draw_stroke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- const bool snap = RNA_boolean_get(op->ptr, "snap");
- SK_DrawData *dd;
- SK_Sketch *sketch = contextSketch(C, 1);
-
- op->customdata = dd = MEM_callocN(sizeof(SK_DrawData), "SketchDrawData");
- sk_initDrawData(dd, event->mval);
-
- sk_start_draw_stroke(sketch);
-
- sk_draw_stroke(C, sketch, sketch->active_stroke, dd, snap);
-
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void sketch_draw_gesture_cancel(bContext *C, wmOperator *op)
-{
- SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
- sk_cancelStroke(sketch);
- MEM_freeN(op->customdata);
-}
-
-static int sketch_draw_gesture(bContext *C, wmOperator *op, const wmEvent *event)
-{
- const bool snap = RNA_boolean_get(op->ptr, "snap");
- SK_DrawData *dd;
- SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
- sk_cancelStroke(sketch);
-
- op->customdata = dd = MEM_callocN(sizeof(SK_DrawData), "SketchDrawData");
- sk_initDrawData(dd, event->mval);
-
- sk_start_draw_gesture(sketch);
- sk_draw_stroke(C, sketch, sketch->gesture, dd, snap);
-
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int sketch_draw_modal(bContext *C, wmOperator *op, const wmEvent *event, short gesture, SK_Stroke *stk)
-{
- bool snap = RNA_boolean_get(op->ptr, "snap");
- SK_DrawData *dd = op->customdata;
- SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
- int retval = OPERATOR_RUNNING_MODAL;
-
- switch (event->type) {
- case LEFTCTRLKEY:
- case RIGHTCTRLKEY:
- snap = event->ctrl != 0;
- RNA_boolean_set(op->ptr, "snap", snap);
- break;
- case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
- dd->mval[0] = event->mval[0];
- dd->mval[1] = event->mval[1];
- sk_draw_stroke(C, sketch, stk, dd, snap);
- ED_area_tag_redraw(CTX_wm_area(C));
- break;
- case ESCKEY:
- op->type->cancel(C, op);
- ED_area_tag_redraw(CTX_wm_area(C));
- retval = OPERATOR_CANCELLED;
- break;
- case LEFTMOUSE:
- if (event->val == KM_RELEASE) {
- if (gesture == 0) {
- sk_endContinuousStroke(stk);
- sk_filterLastContinuousStroke(stk);
- sk_updateNextPoint(sketch, stk);
- ED_area_tag_redraw(CTX_wm_area(C));
- MEM_freeN(op->customdata);
- retval = OPERATOR_FINISHED;
- }
- else {
- sk_endContinuousStroke(stk);
- sk_filterLastContinuousStroke(stk);
-
- if (stk->nb_points > 1) {
- /* apply gesture here */
- sk_applyGesture(C, sketch);
- }
-
- sk_freeStroke(stk);
- sketch->gesture = NULL;
-
- ED_area_tag_redraw(CTX_wm_area(C));
- MEM_freeN(op->customdata);
- retval = OPERATOR_FINISHED;
- }
- }
- break;
- }
-
- return retval;
-}
-
-static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
- return sketch_draw_modal(C, op, event, 0, sketch->active_stroke);
-}
-
-static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
- return sketch_draw_modal(C, op, event, 1, sketch->gesture);
-}
-
-static int sketch_draw_preview(bContext *C, wmOperator *op, const wmEvent *event)
-{
- const bool snap = RNA_boolean_get(op->ptr, "snap");
- SK_Sketch *sketch = contextSketch(C, 0);
-
- if (sketch) {
- SK_DrawData dd;
-
- sk_initDrawData(&dd, event->mval);
- sk_getStrokePoint(C, &sketch->next_point, sketch, sketch->active_stroke, &dd, snap);
- ED_area_tag_redraw(CTX_wm_area(C));
- }
-
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
-}
-
-/* ============================================== Poll Functions ============================================= */
-
-bool ED_operator_sketch_mode_active_stroke(bContext *C)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- SK_Sketch *sketch = contextSketch(C, 0);
-
- if (ts->bone_sketching & BONE_SKETCHING &&
- sketch != NULL &&
- sketch->active_stroke != NULL)
- {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static bool ED_operator_sketch_mode_gesture(bContext *C)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- SK_Sketch *sketch = contextSketch(C, 0);
-
- if (ts->bone_sketching & BONE_SKETCHING &&
- (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0 &&
- sketch != NULL &&
- sketch->active_stroke == NULL)
- {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-bool ED_operator_sketch_full_mode(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- if (obedit &&
- obedit->type == OB_ARMATURE &&
- ts->bone_sketching & BONE_SKETCHING &&
- (ts->bone_sketching & BONE_SKETCHING_QUICK) == 0)
- {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-bool ED_operator_sketch_mode(const bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- if (obedit &&
- obedit->type == OB_ARMATURE &&
- ts->bone_sketching & BONE_SKETCHING)
- {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-/* ================================================ Operators ================================================ */
-
-void SKETCH_OT_delete(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Delete";
- ot->idname = "SKETCH_OT_delete";
- ot->description = "Delete a sketch stroke";
-
- /* api callbacks */
- ot->invoke = sketch_delete;
-
- ot->poll = ED_operator_sketch_full_mode;
-
- /* flags */
-// ot->flag = OPTYPE_UNDO;
-}
-
-void SKETCH_OT_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select";
- ot->idname = "SKETCH_OT_select";
- ot->description = "Select a sketch stroke";
-
- /* api callbacks */
- ot->invoke = sketch_select;
-
- ot->poll = ED_operator_sketch_full_mode;
-
- /* flags */
-// ot->flag = OPTYPE_UNDO;
-}
-
-void SKETCH_OT_cancel_stroke(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Cancel Stroke";
- ot->idname = "SKETCH_OT_cancel_stroke";
- ot->description = "Cancel the current sketch stroke";
-
- /* api callbacks */
- ot->invoke = sketch_cancel_invoke;
-
- ot->poll = ED_operator_sketch_mode_active_stroke;
-
- /* flags */
-// ot->flag = OPTYPE_UNDO;
-}
-
-void SKETCH_OT_convert(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Convert";
- ot->idname = "SKETCH_OT_convert";
- ot->description = "Convert the selected sketch strokes to bone chains";
-
- /* api callbacks */
- ot->invoke = sketch_convert;
-
- ot->poll = ED_operator_sketch_full_mode;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-}
-
-void SKETCH_OT_finish_stroke(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "End Stroke";
- ot->idname = "SKETCH_OT_finish_stroke";
- ot->description = "End and keep the current sketch stroke";
-
- /* api callbacks */
- ot->invoke = sketch_finish;
-
- ot->poll = ED_operator_sketch_mode_active_stroke;
-
- /* flags */
-// ot->flag = OPTYPE_UNDO;
-}
-
-void SKETCH_OT_draw_preview(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Draw Preview";
- ot->idname = "SKETCH_OT_draw_preview";
- ot->description = "Draw preview of current sketch stroke (internal use)";
-
- /* api callbacks */
- ot->invoke = sketch_draw_preview;
-
- ot->poll = ED_operator_sketch_mode_active_stroke;
-
- RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
-
- /* flags */
-// ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-void SKETCH_OT_draw_stroke(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Draw Stroke";
- ot->idname = "SKETCH_OT_draw_stroke";
- ot->description = "Start to draw a sketch stroke";
-
- /* api callbacks */
- ot->invoke = sketch_draw_stroke;
- ot->modal = sketch_draw_stroke_modal;
- ot->cancel = sketch_draw_stroke_cancel;
-
- ot->poll = (bool (*)(bContext *))ED_operator_sketch_mode;
-
- RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING; // OPTYPE_REGISTER|OPTYPE_UNDO
-}
-
-void SKETCH_OT_gesture(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Gesture";
- ot->idname = "SKETCH_OT_gesture";
- ot->description = "Start to draw a gesture stroke";
-
- /* api callbacks */
- ot->invoke = sketch_draw_gesture;
- ot->modal = sketch_draw_gesture_modal;
- ot->cancel = sketch_draw_gesture_cancel;
-
- ot->poll = ED_operator_sketch_mode_gesture;
-
- RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING; // OPTYPE_UNDO
-}
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index f27d68d0634..4346c7534dc 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -27,25 +27,34 @@
* \ingroup edarmature
*/
+#include "MEM_guardedalloc.h"
+
+
+#include "CLG_log.h"
+
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_math.h"
#include "BLI_array_utils.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_undo.h"
#include "ED_util.h"
#include "WM_types.h"
#include "WM_api.h"
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.armature"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -120,13 +129,20 @@ static Object *editarm_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
-typedef struct ArmatureUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-editmode. */
+typedef struct ArmatureUndoStep_Elem {
+ struct ArmatureUndoStep_Elem *next, *prev;
UndoRefID_Object obedit_ref;
UndoArmature data;
+} ArmatureUndoStep_Elem;
+
+typedef struct ArmatureUndoStep {
+ UndoStep step;
+ ArmatureUndoStep_Elem *elems;
+ uint elems_len;
} ArmatureUndoStep;
static bool armature_undosys_poll(bContext *C)
@@ -137,10 +153,24 @@ static bool armature_undosys_poll(bContext *C)
static bool armature_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- us->obedit_ref.ptr = editarm_object_from_context(C);
- bArmature *arm = us->obedit_ref.ptr->data;
- undoarm_from_editarm(&us->data, arm);
- us->step.data_size = us->data.undo_size;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
+ us->elems_len = objects_len;
+
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ bArmature *arm = elem->obedit_ref.ptr->data;
+ undoarm_from_editarm(&elem->data, arm);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
@@ -151,24 +181,46 @@ static void armature_undosys_step_decode(struct bContext *C, UndoStep *us_p, int
BLI_assert(armature_undosys_poll(C));
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- bArmature *arm = obedit->data;
- undoarm_to_editarm(&us->data, arm);
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ bArmature *arm = obedit->data;
+ if (arm->edbo == NULL) {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid", us_p->name, obedit->id.name);
+ continue;
+ }
+ undoarm_to_editarm(&elem->data, arm);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
+
+ /* The first element is always active */
+ ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
+
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
static void armature_undosys_step_free(UndoStep *us_p)
{
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- undoarm_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ undoarm_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
static void armature_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ ArmatureUndoStep_Elem *elem = &us->elems[i];
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
+ }
}
/* Export for ED_undo_sys. */
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 4e31fcc7a11..001c8ce215f 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
@@ -39,13 +40,16 @@
#include "BLT_translation.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_modifier.h"
+#include "BKE_bvhutils.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
#include "ED_mesh.h"
#include "ED_armature.h"
+#include "DEG_depsgraph.h"
+
#include "eigen_capi.h"
#include "meshlaplacian.h"
@@ -600,9 +604,10 @@ static float heat_limit_weight(float weight)
return weight;
}
-void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
- bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
- float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
+void heat_bone_weighting(
+ Object *ob, Mesh *me, float (*verts)[3], int numsource,
+ bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
+ float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
{
LaplacianSystem *sys;
MLoopTri *mlooptri;
@@ -830,7 +835,7 @@ typedef struct MeshDeformBind {
int size, size3;
/* meshes */
- DerivedMesh *cagedm;
+ Mesh *cagemesh;
float (*cagecos)[3];
float (*vertexcos)[3];
int totvert, totcagevert;
@@ -860,7 +865,7 @@ typedef struct MeshDeformBind {
const MLoop *mloop;
const MLoopTri *looptri;
const float (*poly_nors)[3];
- } cagedm_cache;
+ } cagemesh_cache;
} MeshDeformBind;
typedef struct MeshDeformIsect {
@@ -885,9 +890,9 @@ static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *r
{
struct MeshRayCallbackData *data = userdata;
MeshDeformBind *mdb = data->mdb;
- const MLoop *mloop = mdb->cagedm_cache.mloop;
- const MLoopTri *looptri = mdb->cagedm_cache.looptri, *lt;
- const float (*poly_nors)[3] = mdb->cagedm_cache.poly_nors;
+ const MLoop *mloop = mdb->cagemesh_cache.mloop;
+ const MLoopTri *looptri = mdb->cagemesh_cache.looptri, *lt;
+ const float (*poly_nors)[3] = mdb->cagemesh_cache.poly_nors;
MeshDeformIsect *isec = data->isec;
float no[3], co[3], dist;
float *face[3];
@@ -951,9 +956,9 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const
if (BLI_bvhtree_ray_cast_ex(mdb->bvhtree, isect_mdef.start, vec_normal,
0.0, &hit, harmonic_ray_callback, &data, BVH_RAYCAST_WATERTIGHT) != -1)
{
- const MLoop *mloop = mdb->cagedm_cache.mloop;
- const MLoopTri *lt = &mdb->cagedm_cache.looptri[hit.index];
- const MPoly *mp = &mdb->cagedm_cache.mpoly[lt->poly];
+ const MLoop *mloop = mdb->cagemesh_cache.mloop;
+ const MLoopTri *lt = &mdb->cagemesh_cache.looptri[hit.index];
+ const MPoly *mp = &mdb->cagemesh_cache.mpoly[lt->poly];
const float (*cagecos)[3] = mdb->cagecos;
const float len = isect_mdef.lambda;
MDefBoundIsect *isect;
@@ -1128,8 +1133,8 @@ static void meshdeform_bind_floodfill(MeshDeformBind *mdb)
static float meshdeform_boundary_phi(const MeshDeformBind *mdb, const MDefBoundIsect *isect, int cagevert)
{
- const MLoop *mloop = mdb->cagedm_cache.mloop;
- const MPoly *mp = &mdb->cagedm_cache.mpoly[isect->poly_index];
+ const MLoop *mloop = mdb->cagemesh_cache.mloop;
+ const MPoly *mp = &mdb->cagemesh_cache.mpoly[isect->poly_index];
int i;
for (i = 0; i < mp->totloop; i++) {
@@ -1444,7 +1449,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa
mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi");
mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect");
mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound");
- mdb->bvhtree = bvhtree_from_mesh_get(&mdb->bvhdata, mdb->cagedm, BVHTREE_FROM_LOOPTRI, 4);
+ mdb->bvhtree = BKE_bvhtree_from_mesh_get(&mdb->bvhdata, mdb->cagemesh, BVHTREE_FROM_LOOPTRI, 4);
mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside");
if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
@@ -1457,11 +1462,11 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa
/* initialize data from 'cagedm' for reuse */
{
- DerivedMesh *dm = mdb->cagedm;
- mdb->cagedm_cache.mpoly = dm->getPolyArray(dm);
- mdb->cagedm_cache.mloop = dm->getLoopArray(dm);
- mdb->cagedm_cache.looptri = dm->getLoopTriArray(dm);
- mdb->cagedm_cache.poly_nors = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */
+ Mesh *me = mdb->cagemesh;
+ mdb->cagemesh_cache.mpoly = me->mpoly;
+ mdb->cagemesh_cache.mloop = me->mloop;
+ mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
+ mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL); /* can be NULL */
}
/* make bounding box equal size in all directions, add padding, and compute
@@ -1573,7 +1578,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa
}
void ED_mesh_deform_bind_callback(
- Scene *scene, MeshDeformModifierData *mmd, DerivedMesh *cagedm,
+ Scene *scene, MeshDeformModifierData *mmd, Mesh *cagemesh,
float *vertexcos, int totvert, float cagemat[4][4])
{
MeshDeformBind mdb;
@@ -1589,12 +1594,12 @@ void ED_mesh_deform_bind_callback(
mdb.vertexcos = MEM_callocN(sizeof(float) * 3 * totvert, "MeshDeformCos");
mdb.totvert = totvert;
- mdb.cagedm = cagedm;
- mdb.totcagevert = mdb.cagedm->getNumVerts(mdb.cagedm);
+ mdb.cagemesh = cagemesh;
+ mdb.totcagevert = mdb.cagemesh->totvert;
mdb.cagecos = MEM_callocN(sizeof(*mdb.cagecos) * mdb.totcagevert, "MeshDeformBindCos");
copy_m4_m4(mdb.cagemat, cagemat);
- mvert = mdb.cagedm->getVertArray(mdb.cagedm);
+ mvert = mdb.cagemesh->mvert;
for (a = 0; a < mdb.totcagevert; a++)
copy_v3_v3(mdb.cagecos[a], mvert[a].co);
for (a = 0; a < mdb.totvert; a++)
diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h
index bd0d2888568..6758f9d16ac 100644
--- a/source/blender/editors/armature/meshlaplacian.h
+++ b/source/blender/editors/armature/meshlaplacian.h
@@ -52,10 +52,11 @@ float laplacian_system_get_solution(LaplacianSystem *sys, int v);
/* Heat Weighting */
-void heat_bone_weighting(struct Object *ob, struct Mesh *me, float (*verts)[3],
- int numbones, struct bDeformGroup **dgrouplist,
- struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3],
- int *selected, const char **error);
+void heat_bone_weighting(
+ struct Object *ob, struct Mesh *me, float (*verts)[3],
+ int numbones, struct bDeformGroup **dgrouplist,
+ struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3],
+ int *selected, const char **error);
#ifdef RIGID_DEFORM
/* As-Rigid-As-Possible Deformation */
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index f04106dac3a..715203135d9 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -31,6 +31,8 @@
* \ingroup edarmature
*/
+#include "MEM_guardedalloc.h"
+
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -39,14 +41,20 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "BKE_action.h"
#include "BKE_anim.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -59,11 +67,21 @@
#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_object.h"
+#include "ED_view3d.h"
#include "UI_interface.h"
#include "armature_intern.h"
+
+#define DEBUG_TIME
+
+#include "PIL_time.h"
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
+
/* matches logic with ED_operator_posemode_context() */
Object *ED_pose_object_from_context(bContext *C)
{
@@ -82,7 +100,7 @@ Object *ED_pose_object_from_context(bContext *C)
}
/* This function is used to process the necessary updates for */
-bool ED_object_posemode_enter_ex(Object *ob)
+bool ED_object_posemode_enter_ex(struct Main *bmain, Object *ob)
{
BLI_assert(!ID_IS_LINKED(ob));
bool ok = false;
@@ -91,6 +109,8 @@ bool ED_object_posemode_enter_ex(Object *ob)
case OB_ARMATURE:
ob->restore_mode = ob->mode;
ob->mode |= OB_MODE_POSE;
+ /* Inform all CoW versions that we changed the mode. */
+ DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_COPY_ON_WRITE);
ok = true;
break;
@@ -107,26 +127,31 @@ bool ED_object_posemode_enter(bContext *C, Object *ob)
BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
return false;
}
- bool ok = ED_object_posemode_enter_ex(ob);
+ struct Main *bmain = CTX_data_main(C);
+ bool ok = ED_object_posemode_enter_ex(bmain, ob);
if (ok) {
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
}
return ok;
}
-bool ED_object_posemode_exit_ex(Object *ob)
+bool ED_object_posemode_exit_ex(struct Main *bmain, Object *ob)
{
bool ok = false;
if (ob) {
ob->restore_mode = ob->mode;
ob->mode &= ~OB_MODE_POSE;
+
+ /* Inform all CoW versions that we changed the mode. */
+ DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_COPY_ON_WRITE);
ok = true;
}
return ok;
}
bool ED_object_posemode_exit(bContext *C, Object *ob)
{
- bool ok = ED_object_posemode_exit_ex(ob);
+ struct Main *bmain = CTX_data_main(C);
+ bool ok = ED_object_posemode_exit_ex(bmain, ob);
if (ok) {
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
}
@@ -168,17 +193,77 @@ static bool pose_has_protected_selected(Object *ob, short warn)
*
* To be called from various tools that do incremental updates
*/
-void ED_pose_recalculate_paths(Main *bmain, Scene *scene, Object *ob)
+void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool current_frame_only)
{
+ /* Transform doesn't always have context available to do update. */
+ if (C == NULL) {
+ return;
+ }
+
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ListBase targets = {NULL, NULL};
+ bool free_depsgraph = false;
+
+ /* Override depsgraph with a filtered, simpler copy */
+ if (!current_frame_only && G.debug_value != -1) {
+ DEG_FilterQuery query = {{0}};
+
+ DEG_FilterTarget *dft_ob = MEM_callocN(sizeof(DEG_FilterTarget), "DEG_FilterTarget");
+ dft_ob->id = &ob->id;
+ BLI_addtail(&query.targets, dft_ob);
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(filter_pose_depsgraph);
+#endif
+
+ depsgraph = DEG_graph_filter(depsgraph, bmain, &query);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(filter_pose_depsgraph);
+#endif
+
+ free_depsgraph = true;
+ MEM_freeN(dft_ob);
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(filter_pose_update);
+#endif
+
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(filter_pose_update);
+#endif
+ }
/* set flag to force recalc, then grab the relevant bones to target */
ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
animviz_get_object_motionpaths(ob, &targets);
/* recalculate paths, then free */
- animviz_calc_motionpaths(bmain, scene, &targets);
+#ifdef DEBUG_TIME
+ TIMEIT_START(pose_path_calc);
+#endif
+
+ animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, !free_depsgraph, current_frame_only);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(pose_path_calc);
+#endif
+
BLI_freelistN(&targets);
+
+ if (!current_frame_only) {
+ /* Tag armature object for copy on write - so paths will draw/redraw.
+ * For currently frame only we update evaluated object directly. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
+ /* Free temporary depsgraph instance */
+ if (free_depsgraph) {
+ DEG_graph_free(depsgraph);
+ }
}
@@ -204,7 +289,7 @@ static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEven
/* show popup dialog to allow editing of range... */
// FIXME: hardcoded dimensions here are just arbitrary
- return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 10 * UI_UNIT_Y);
+ return WM_operator_props_dialog_popup(C, op, 200, 200);
}
/* For the object with pose/action: create path curves for selected bones
@@ -212,7 +297,6 @@ static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEven
*/
static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
Scene *scene = CTX_data_scene(C);
@@ -232,16 +316,24 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
}
/* set up path data for bones being calculated */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones_from_active_object)
{
/* verify makes sure that the selected bone has a bone with the appropriate settings */
animviz_verify_motionpaths(op->reports, scene, ob, pchan);
}
CTX_DATA_END;
+#ifdef DEBUG_TIME
+ TIMEIT_START(recalc_pose_paths);
+#endif
+
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(bmain, scene, ob);
+ ED_pose_recalculate_paths(C, scene, ob, false);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(recalc_pose_paths);
+#endif
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -270,7 +362,8 @@ void POSE_OT_paths_calculate(wmOperatorType *ot)
RNA_def_int(ot->srna, "end_frame", 250, MINAFRAME, MAXFRAME, "End",
"Last frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
- RNA_def_enum(ot->srna, "bake_location", rna_enum_motionpath_bake_location_items, 0,
+ RNA_def_enum(ot->srna, "bake_location", rna_enum_motionpath_bake_location_items,
+ MOTIONPATH_BAKE_HEADS,
"Bake Location",
"Which point on the bones is used when calculating paths");
}
@@ -289,7 +382,6 @@ static bool pose_update_paths_poll(bContext *C)
static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
Scene *scene = CTX_data_scene(C);
@@ -298,7 +390,7 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(bmain, scene, ob);
+ ED_pose_recalculate_paths(C, scene, ob, false);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -348,6 +440,9 @@ static void ED_pose_clear_paths(Object *ob, bool only_selected)
/* if nothing was skipped, there should be no paths left! */
if (skipped == false)
ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
+
+ /* tag armature object for copy on write - so removed paths don't still show */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
/* operator callback - wrapper for the backend function */
@@ -399,6 +494,43 @@ void POSE_OT_paths_clear(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
+/* --------- */
+
+static int pose_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+
+ if (ELEM(NULL, scene, ob, ob->pose)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* use Preview Range or Full Frame Range - whichever is in use */
+ ob->pose->avs.path_sf = PSFRA;
+ ob->pose->avs.path_ef = PEFRA;
+
+ /* tag for updates */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_paths_range_update(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Range from Scene";
+ ot->idname = "POSE_OT_paths_range_update";
+ ot->description = "Update frame range for motion paths from the Scene's current frame range";
+
+ /* callbacks */
+ ot->exec = pose_update_paths_range_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ********************************************** */
#if 0 /* UNUSED 2.5 */
static void pose_copy_menu(Scene *scene)
@@ -596,7 +728,7 @@ static void pose_copy_menu(Scene *scene)
BKE_pose_tag_recalc(bmain, ob->pose);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
BIF_undo_push("Copy Pose Attributes");
@@ -608,34 +740,32 @@ static void pose_copy_menu(Scene *scene)
static int pose_flip_names_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm;
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
- arm = ob->data;
-
- ListBase bones_names = {NULL};
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob)
{
- BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
- }
- CTX_DATA_END;
+ bArmature *arm = ob->data;
+ ListBase bones_names = {NULL};
- ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
+ {
+ BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name));
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
- BLI_freelistN(&bones_names);
+ ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ BLI_freelistN(&bones_names);
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* since we renamed stuff... */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
return OPERATOR_FINISHED;
}
@@ -664,30 +794,29 @@ void POSE_OT_flip_names(wmOperatorType *ot)
static int pose_autoside_names_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm;
char newname[MAXBONENAME];
short axis = RNA_enum_get(op->ptr, "axis");
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
+ Object *ob_prev = NULL;
/* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
{
+ bArmature *arm = ob->data;
BLI_strncpy(newname, pchan->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]))
+ if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis])) {
ED_armature_bone_rename(bmain, arm, pchan->name, newname);
- }
- CTX_DATA_END;
+ }
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ if (ob_prev != ob) {
+ /* since we renamed stuff... */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ob_prev = ob;
+ }
+ }
+ CTX_DATA_END;
return OPERATOR_FINISHED;
}
@@ -722,20 +851,24 @@ void POSE_OT_autoside_names(wmOperatorType *ot)
static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- int mode = RNA_enum_get(op->ptr, "type");
+ const int mode = RNA_enum_get(op->ptr, "type");
+ Object *prev_ob = NULL;
/* set rotation mode of selected bones */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
{
pchan->rotmode = mode;
+
+ if (prev_ob != ob) {
+ /* Notifiers and updates. */
+ DEG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ prev_ob = ob;
+ }
}
CTX_DATA_END;
- /* notifiers and updates */
- DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
return OPERATOR_FINISHED;
}
@@ -813,6 +946,7 @@ static int pose_armature_layers_showall_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
/* done */
return OPERATOR_FINISHED;
@@ -880,6 +1014,7 @@ static int armature_layers_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
@@ -908,7 +1043,7 @@ void ARMATURE_OT_armature_layers(wmOperatorType *ot)
/* Present a popup to get the layers that should be used */
static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- bool layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ bool layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
/* get layers that are active already */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
@@ -932,29 +1067,29 @@ static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* Set the visible layers for the active armature (edit and pose modes) */
static int pose_bone_layers_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
PointerRNA ptr;
bool layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- if (ob == NULL || ob->data == NULL) {
- return OPERATOR_CANCELLED;
- }
-
/* get the values set in the operator properties */
RNA_boolean_get_array(op->ptr, "layers", layers);
+ Object *prev_ob = NULL;
+
/* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
{
/* get pointer for pchan, and write flags this way */
RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr);
RNA_boolean_set_array(&ptr, "layers", layers);
+
+ if (prev_ob != ob) {
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update((ID *)ob->data, DEG_TAG_COPY_ON_WRITE);
+ prev_ob = ob;
+ }
}
CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
return OPERATOR_FINISHED;
}
@@ -1009,7 +1144,6 @@ static int armature_bone_layers_invoke(bContext *C, wmOperator *op, const wmEven
static int armature_bone_layers_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (ob) ? ob->data : NULL;
PointerRNA ptr;
bool layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
@@ -1017,7 +1151,7 @@ static int armature_bone_layers_exec(bContext *C, wmOperator *op)
RNA_boolean_get_array(op->ptr, "layers", layers);
/* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
+ CTX_DATA_BEGIN_WITH_ID (C, EditBone *, ebone, selected_editable_bones, bArmature *, arm)
{
/* get pointer for pchan, and write flags this way */
RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
@@ -1053,55 +1187,54 @@ void ARMATURE_OT_bone_layers(wmOperatorType *ot)
/* ********************************************** */
/* Show/Hide Bones */
-static int hide_selected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+static int hide_pose_bone_fn(Object *ob, Bone *bone, void *ptr)
{
bArmature *arm = ob->data;
-
+ const bool hide_select = (bool)POINTER_AS_INT(ptr);
+ int count = 0;
if (arm->layer & bone->layer) {
- if (bone->flag & BONE_SELECTED) {
+ if (((bone->flag & BONE_SELECTED) != 0) == hide_select) {
bone->flag |= BONE_HIDDEN_P;
+ /* only needed when 'hide_select' is true, but harmless. */
bone->flag &= ~BONE_SELECTED;
- if (arm->act_bone == bone)
- arm->act_bone = NULL;
- }
- }
- return 0;
-}
-
-static int hide_unselected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- bArmature *arm = ob->data;
-
- if (arm->layer & bone->layer) {
- /* hrm... typo here? */
- if ((bone->flag & BONE_SELECTED) == 0) {
- bone->flag |= BONE_HIDDEN_P;
- if (arm->act_bone == bone)
+ if (arm->act_bone == bone) {
arm->act_bone = NULL;
+ }
+ count += 1;
}
}
- return 0;
+ return count;
}
/* active object is armature in posemode, poll checked */
static int pose_hide_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len;
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, CTX_wm_view3d(C), &objects_len);
+ bool changed_multi = false;
- if (ob->proxy != NULL) {
- BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected");
- }
+ const int hide_select = !RNA_boolean_get(op->ptr, "unselected");
+ void *hide_select_p = POINTER_FROM_INT(hide_select);
- if (RNA_boolean_get(op->ptr, "unselected"))
- bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb);
- else
- bone_looper(ob, arm->bonebase.first, NULL, hide_selected_pose_bone_cb);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ bArmature *arm = ob_iter->data;
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ if (ob_iter->proxy != NULL) {
+ BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected");
+ }
- return OPERATOR_FINISHED;
+ bool changed = bone_looper(ob_iter, arm->bonebase.first, hide_select_p, hide_pose_bone_fn) != 0;
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter);
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void POSE_OT_hide(wmOperatorType *ot)
@@ -1127,32 +1260,44 @@ static int show_pose_bone_cb(Object *ob, Bone *bone, void *data)
const bool select = POINTER_AS_INT(data);
bArmature *arm = ob->data;
-
+ int count = 0;
if (arm->layer & bone->layer) {
if (bone->flag & BONE_HIDDEN_P) {
if (!(bone->flag & BONE_UNSELECTABLE)) {
SET_FLAG_FROM_TEST(bone->flag, select, BONE_SELECTED);
}
bone->flag &= ~BONE_HIDDEN_P;
+ count += 1;
}
}
- return 0;
+ return count;
}
/* active object is armature in posemode, poll checked */
static int pose_reveal_exec(bContext *C, wmOperator *op)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len;
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, CTX_wm_view3d(C), &objects_len);
+ bool changed_multi = false;
const bool select = RNA_boolean_get(op->ptr, "select");
+ void *select_p = POINTER_FROM_INT(select);
- bone_looper(ob, arm->bonebase.first, POINTER_FROM_INT(select), show_pose_bone_cb);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ bArmature *arm = ob_iter->data;
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ bool changed = bone_looper(ob_iter, arm->bonebase.first, select_p, show_pose_bone_cb);
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob_iter);
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void POSE_OT_reveal(wmOperatorType *ot)
@@ -1178,27 +1323,35 @@ void POSE_OT_reveal(wmOperatorType *ot)
static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
- /* loop through all selected pchans, flipping and keying (as needed) */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* only if bone is using quaternion rotation */
- if (pchan->rotmode == ROT_MODE_QUAT) {
- /* quaternions have 720 degree range */
- negate_v4(pchan->quat);
+ bool changed_multi = false;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob_iter) {
+ bool changed = false;
+ /* loop through all selected pchans, flipping and keying (as needed) */
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
+ /* only if bone is using quaternion rotation */
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ changed = true;
+ /* quaternions have 720 degree range */
+ negate_v4(pchan->quat);
+
+ ED_autokeyframe_pchan(C, scene, ob_iter, pchan, ks);
+ }
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ if (changed) {
+ changed_multi = true;
+ /* notifiers and updates */
+ DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter);
}
- }
- CTX_DATA_END;
+ } FOREACH_OBJECT_IN_MODE_END;
- /* notifiers and updates */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void POSE_OT_quaternions_flip(wmOperatorType *ot)
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 97cf02523a6..3a619f771bd 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -38,9 +38,12 @@
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
+#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_context.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -104,6 +107,7 @@ static int pose_group_remove_exec(bContext *C, wmOperator *UNUSED(op))
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
@@ -204,15 +208,16 @@ static int pose_group_assign_exec(bContext *C, wmOperator *op)
BKE_pose_add_group(ob->pose, NULL);
/* add selected bones to group then */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
{
pchan->agrp_index = pose->active_group;
done = true;
}
- CTX_DATA_END;
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
/* report done status */
if (done)
@@ -251,17 +256,18 @@ static int pose_group_unassign_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* find selected bones to remove from all bone groups */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
{
if (pchan->agrp_index) {
pchan->agrp_index = 0;
done = true;
}
}
- CTX_DATA_END;
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
/* report done status */
if (done)
@@ -413,6 +419,7 @@ static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
@@ -432,11 +439,11 @@ void POSE_OT_group_sort(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static void pose_group_select(bContext *C, Object *ob, bool select)
+static void pose_group_select(Object *ob, bool select)
{
bPose *pose = ob->pose;
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (ob, pchan)
{
if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
if (select) {
@@ -449,7 +456,7 @@ static void pose_group_select(bContext *C, Object *ob, bool select)
}
}
}
- CTX_DATA_END;
+ FOREACH_PCHAN_VISIBLE_IN_OBJECT_END;
}
static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
@@ -460,7 +467,7 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
- pose_group_select(C, ob, 1);
+ pose_group_select(ob, 1);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -491,7 +498,7 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
- pose_group_select(C, ob, 0);
+ pose_group_select(ob, 0);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 1aa852c3863..18ce6476105 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -43,19 +43,20 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_armature.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
-#include "BKE_main.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_context.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -311,8 +312,7 @@ static int poselib_sanitize_exec(bContext *C, wmOperator *op)
/* determine which frames have keys */
BLI_dlrbTree_init(&keys);
- action_to_keylist(NULL, act, &keys, NULL);
- BLI_dlrbTree_linkedlist_sync(&keys);
+ action_to_keylist(NULL, act, &keys, 0);
/* for each key, make sure there is a corresponding pose */
for (ak = keys.first; ak; ak = ak->next) {
@@ -503,6 +503,7 @@ static int poselib_add_exec(bContext *C, wmOperator *op)
/* store new 'active' pose number */
act->active_marker = BLI_listbase_count(&act->markers);
+ DEG_id_tag_update(&act->id, DEG_TAG_COPY_ON_WRITE);
/* done */
return OPERATOR_FINISHED;
@@ -617,6 +618,7 @@ static int poselib_remove_exec(bContext *C, wmOperator *op)
* may be being shown in anim editors as active action
*/
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ DEG_id_tag_update(&act->id, DEG_TAG_COPY_ON_WRITE);
/* done */
return OPERATOR_FINISHED;
@@ -1024,7 +1026,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld)
}
if (ok)
- animsys_evaluate_action_group(ptr, act, agrp, NULL, (float)frame);
+ animsys_evaluate_action_group(ptr, act, agrp, (float)frame);
}
}
}
@@ -1104,18 +1106,16 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
*/
// FIXME: shouldn't this use the builtin stuff?
if ((pld->arm->flag & ARM_DELAYDEFORM) == 0)
- DAG_id_tag_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */
+ DEG_id_tag_update(&pld->ob->id, OB_RECALC_DATA); /* sets recalc flags */
else
- BKE_pose_where_is(pld->scene, pld->ob);
+ BKE_pose_where_is(CTX_data_depsgraph(C), pld->scene, pld->ob);
}
/* do header print - if interactively previewing */
if (pld->state == PL_PREVIEW_RUNNING) {
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
- BLI_strncpy(pld->headerstr,
- IFACE_("PoseLib Previewing Pose: [Showing Original Pose] | Use Tab to start previewing poses again"),
- sizeof(pld->headerstr));
- ED_area_headerprint(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->sa, IFACE_("PoseLib Previewing Pose: [Showing Original Pose]"));
+ ED_workspace_status_text(C, IFACE_("Use Tab to start previewing poses again"));
}
else if (pld->searchstr[0]) {
char tempstr[65];
@@ -1139,17 +1139,17 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
IFACE_("PoseLib Previewing Pose: Filter - [%s] | "
- "Current Pose - \"%s\" | "
- "Use ScrollWheel or PageUp/Down to change"),
+ "Current Pose - \"%s\""),
tempstr, markern);
- ED_area_headerprint(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->sa, pld->headerstr);
+ ED_workspace_status_text(C, IFACE_("Use ScrollWheel or PageUp/Down to change pose"));
}
else {
BLI_snprintf(pld->headerstr, sizeof(pld->headerstr),
- IFACE_("PoseLib Previewing Pose: \"%s\" | "
- "Use ScrollWheel or PageUp/Down to change"),
+ IFACE_("PoseLib Previewing Pose: \"%s\""),
pld->marker->name);
- ED_area_headerprint(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->sa, pld->headerstr);
+ ED_workspace_status_text(C, NULL);
}
}
@@ -1599,7 +1599,8 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
TimeMarker *marker = pld->marker;
/* redraw the header so that it doesn't show any of our stuff anymore */
- ED_area_headerprint(pld->sa, NULL);
+ ED_area_status_text(pld->sa, NULL);
+ ED_workspace_status_text(C, NULL);
/* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
pose->flag |= POSE_DO_UNLOCK;
@@ -1612,9 +1613,9 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
* - note: code copied from transform_generics.c -> recalcData()
*/
if ((arm->flag & ARM_DELAYDEFORM) == 0)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
else
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(CTX_data_depsgraph(C), scene, ob);
}
else if (pld->state == PL_PREVIEW_CONFIRM) {
/* tag poses as appropriate */
@@ -1625,14 +1626,14 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
action_set_activemarker(act, marker, NULL);
/* Update event for pose and deformation children */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
/* updates */
if (IS_AUTOKEY_MODE(scene, NORMAL)) {
//remake_action_ipos(ob->action);
}
else
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(CTX_data_depsgraph(C), scene, ob);
}
/* Request final redraw of the view. */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index e17d281af63..111a7b2c693 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -43,9 +43,11 @@
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -58,6 +60,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_view3d.h"
#include "armature_intern.h"
@@ -92,6 +95,23 @@ static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode)
}
}
+void ED_pose_bone_select_tag_update(Object *ob)
+{
+ BLI_assert(ob->type == OB_ARMATURE);
+ bArmature *arm = ob->data;
+ WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, ob);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ /* copy on write tag is needed (for the armature), or else no refresh happens */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+}
+
+
/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
@@ -117,23 +137,14 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
}
// TODO: select and activate corresponding vgroup?
-
- /* tag necessary depsgraph updates
- * (see rna_Bone_select_update() in rna_armature.c for details)
- */
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- /* send necessary notifiers */
- WM_main_add_notifier(NC_GEOM | ND_DATA, ob);
+ ED_pose_bone_select_tag_update(ob);
}
}
/* called from editview.c, for mode-less pose selection */
/* assumes scene obact and basact is still on old situation */
bool ED_armature_pose_select_pick_with_buffer(
- Scene *scene, Base *base, const unsigned int *buffer, short hits,
+ ViewLayer *view_layer, View3D *v3d, Base *base, const unsigned int *buffer, short hits,
bool extend, bool deselect, bool toggle, bool do_nearest)
{
Object *ob = base->object;
@@ -141,11 +152,15 @@ bool ED_armature_pose_select_pick_with_buffer(
if (!ob || !ob->pose) return 0;
- nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1, do_nearest);
+ Object *ob_act = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+
+ /* Callers happen to already get the active base */
+ Base *base_dummy = NULL;
+ nearBone = get_bone_from_selectbuffer(&base, 1, obedit != NULL, buffer, hits, 1, do_nearest, &base_dummy);
/* if the bone cannot be affected, don't do anything */
if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
- Object *ob_act = OBACT;
bArmature *arm = ob->data;
/* since we do unified select, we don't shift+select a bone if the
@@ -163,7 +178,12 @@ bool ED_armature_pose_select_pick_with_buffer(
}
if (!extend && !deselect && !toggle) {
- ED_pose_deselect_all(ob, SEL_DESELECT, true);
+ {
+ uint objects_len = 0;
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, v3d, &objects_len);
+ ED_pose_deselect_all_multi(objects, objects_len, SEL_DESELECT, true);
+ MEM_freeN(objects);
+ }
nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
arm->act_bone = nearBone;
}
@@ -197,7 +217,7 @@ bool ED_armature_pose_select_pick_with_buffer(
if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
if (nearBone == arm->act_bone) {
ED_vgroup_select_by_name(ob_act, nearBone->name);
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
}
}
/* if there are some dependencies for visualizing armature state
@@ -207,8 +227,11 @@ bool ED_armature_pose_select_pick_with_buffer(
/* NOTE: ob not ob_act here is intentional - it's the source of the
* bones being selected [T37247]
*/
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
+
+ /* tag armature for copy-on-write update (since act_bone is in armature not object) */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -217,14 +240,14 @@ bool ED_armature_pose_select_pick_with_buffer(
/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
* When true, 'ignore_visibility' makes this func also affect invisible bones (hidden or on hidden layers). */
-void ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
+bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
/* we call this from outliner too */
if (ob->pose == NULL) {
- return;
+ return false;
}
/* Determine if we're selecting or deselecting */
@@ -241,10 +264,53 @@ void ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibil
}
/* Set the flags accordingly */
+ bool changed = false;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* ignore the pchan if it isn't visible or if its selection cannot be changed */
if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ int flag_prev = pchan->bone->flag;
pose_do_bone_select(pchan, select_mode);
+ changed = (changed || flag_prev != pchan->bone->flag);
+ }
+ }
+ return changed;
+}
+
+static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
+{
+ bArmature *arm = ob->data;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool ed_pose_is_any_selected_multi(Object **objects, uint objects_len, bool ignore_visibility)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ if (ed_pose_is_any_selected(ob_iter, ignore_visibility)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ED_pose_deselect_all_multi(Object **objects, uint objects_len, int select_mode, const bool ignore_visibility)
+{
+ if (select_mode == SEL_TOGGLE) {
+ select_mode = ed_pose_is_any_selected_multi(
+ objects, objects_len, ignore_visibility) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ if (ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility)) {
+ ED_pose_bone_select_tag_update(ob_iter);
}
}
}
@@ -259,9 +325,6 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
return;
- /* XXX old cruft! use notifiers instead */
- //select_actionchannel_by_name (ob->action, bone->name, !(shift));
-
if (extend)
bone->flag &= ~BONE_SELECTED;
else
@@ -275,14 +338,13 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
/* previously known as "selectconnected_posearmature" */
static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
Bone *bone, *curBone, *next = NULL;
const bool extend = RNA_boolean_get(op->ptr, "extend");
view3d_operator_needs_opengl(C);
- bone = get_nearest_bone(C, event->mval, !extend);
+ Base *base = NULL;
+ bone = get_nearest_bone(C, event->mval, !extend, &base);
if (!bone)
return OPERATOR_CANCELLED;
@@ -307,15 +369,9 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
/* Select children */
for (curBone = bone->childbase.first; curBone; curBone = next)
- selectconnected_posebonechildren(ob, curBone, extend);
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ selectconnected_posebonechildren(base->object, curBone, extend);
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
+ ED_pose_bone_select_tag_update(base->object);
return OPERATOR_FINISHED;
}
@@ -332,7 +388,7 @@ void POSE_OT_select_linked(wmOperatorType *ot)
ot->idname = "POSE_OT_select_linked";
ot->description = "Select bones related to selected ones by parent/child relationships";
- /* api callbacks */
+ /* callbacks */
/* leave 'exec' unset */
ot->invoke = pose_select_connected_invoke;
ot->poll = pose_select_linked_poll;
@@ -351,28 +407,34 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
int action = RNA_enum_get(op->ptr, "action");
Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_context(C);
- bArmature *arm = ob->data;
int multipaint = scene->toolsettings->multipaint;
if (action == SEL_TOGGLE) {
action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
}
+ Object *ob_prev = NULL;
+
/* Set the flags */
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
{
+ bArmature *arm = ob->data;
pose_do_bone_select(pchan, action);
+
+ if (ob_prev != ob) {
+ /* weightpaint or mask modifiers need depsgraph updates */
+ if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ /* need to tag armature for cow updates, or else selection doesn't update */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+ ob_prev = ob;
+ }
}
CTX_DATA_END;
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
- /* weightpaint or mask modifiers need depsgraph updates */
- if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
return OPERATOR_FINISHED;
}
@@ -417,14 +479,7 @@ static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
+ ED_pose_bone_select_tag_update(ob);
return OPERATOR_FINISHED;
}
@@ -447,8 +502,6 @@ void POSE_OT_select_parent(wmOperatorType *ot)
static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
bConstraint *con;
int found = 0;
@@ -464,10 +517,18 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
cti->get_constraint_targets(con, &targets);
for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == ob) && (ct->subtarget[0])) {
+ Object *ob = ct->tar;
+
+ /* Any armature that is also in pose mode should be selected. */
+ if ((ct->subtarget[0] != '\0') &&
+ (ob != NULL) &&
+ (ob->type == OB_ARMATURE) &&
+ (ob->mode == OB_MODE_POSE))
+ {
bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
+ ED_pose_bone_select_tag_update(ob);
found = 1;
}
}
@@ -484,14 +545,6 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
if (!found)
return OPERATOR_CANCELLED;
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
return OPERATOR_FINISHED;
}
@@ -512,6 +565,8 @@ void POSE_OT_select_constraint_target(wmOperatorType *ot)
/* -------------------------------------- */
+/* No need to convert to multi-objects. Just like we keep the non-active bones
+ * selected we then keep the non-active objects untouched (selected/unselected). */
static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
@@ -578,13 +633,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
+ ED_pose_bone_select_tag_update(ob);
return OPERATOR_FINISHED;
}
@@ -623,113 +672,200 @@ typedef enum ePose_SelectSame_Mode {
POSE_SEL_SAME_KEYINGSET = 2,
} ePose_SelectSame_Mode;
-static bool pose_select_same_group(bContext *C, Object *ob, bool extend)
+static bool pose_select_same_group(bContext *C, bool extend)
{
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose = (ob) ? ob->pose : NULL;
- char *group_flags;
- int numGroups = 0;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bool *group_flags_array;
+ bool *group_flags = NULL;
+ int groups_len = 0;
bool changed = false, tagged = false;
+ Object *ob_prev = NULL;
+ uint ob_index;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose = (ob) ? ob->pose : NULL;
+
+ /* Sanity checks. */
+ if (ELEM(NULL, ob, pose, arm)) {
+ continue;
+ }
- /* sanity checks */
- if (ELEM(NULL, ob, pose, arm))
- return 0;
+ ob->id.tag &= ~LIB_TAG_DOIT;
+ groups_len = MAX2(groups_len, BLI_listbase_count(&pose->agroups));
+ }
- /* count the number of groups */
- numGroups = BLI_listbase_count(&pose->agroups);
- if (numGroups == 0)
- return 0;
+ /* Nothing to do here. */
+ if (groups_len == 0) {
+ MEM_freeN(objects);
+ return false;
+ }
/* alloc a small array to keep track of the groups to use
* - each cell stores on/off state for whether group should be used
- * - size is (numGroups + 1), since (index = 0) is used for no-group
+ * - size is (groups_len + 1), since (index = 0) is used for no-group
*/
- group_flags = MEM_callocN(numGroups + 1, "pose_select_same_group");
+ groups_len++;
+ group_flags_array = MEM_callocN(objects_len * groups_len * sizeof(bool), "pose_select_same_group");
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ group_flags = NULL;
+ ob_index = -1;
+ ob_prev = NULL;
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object, *ob)
{
+ if (ob != ob_prev) {
+ ob_index++;
+ group_flags = group_flags_array + (ob_index * groups_len);
+ ob_prev = ob;
+ }
+
/* keep track of group as group to use later? */
if (pchan->bone->flag & BONE_SELECTED) {
- group_flags[pchan->agrp_index] = 1;
+ group_flags[pchan->agrp_index] = true;
tagged = true;
}
/* deselect all bones before selecting new ones? */
- if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
pchan->bone->flag &= ~BONE_SELECTED;
+ }
}
CTX_DATA_END;
/* small optimization: only loop through bones a second time if there are any groups tagged */
if (tagged) {
+ group_flags = NULL;
+ ob_index = -1;
+ ob_prev = NULL;
/* only if group matches (and is not selected or current bone) */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
{
+ if (ob != ob_prev) {
+ ob_index++;
+ group_flags = group_flags_array + (ob_index * groups_len);
+ ob_prev = ob;
+ }
+
if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
/* check if the group used by this bone is counted */
if (group_flags[pchan->agrp_index]) {
pchan->bone->flag |= BONE_SELECTED;
- changed = true;
+ ob->id.tag |= LIB_TAG_DOIT;
}
}
}
CTX_DATA_END;
}
- /* free temp info */
- MEM_freeN(group_flags);
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ if (ob->id.tag & LIB_TAG_DOIT) {
+ ED_pose_bone_select_tag_update(ob);
+ changed = true;
+ }
+ }
+
+ /* Cleanup. */
+ MEM_freeN(group_flags_array);
+ MEM_freeN(objects);
return changed;
}
-static bool pose_select_same_layer(bContext *C, Object *ob, bool extend)
+static bool pose_select_same_layer(bContext *C, bool extend)
{
- bPose *pose = (ob) ? ob->pose : NULL;
- bArmature *arm = (ob) ? ob->data : NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int *layers_array, *layers = NULL;
+ Object *ob_prev = NULL;
+ uint ob_index;
bool changed = false;
- int layers = 0;
- if (ELEM(NULL, ob, pose, arm))
- return 0;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ ob->id.tag &= ~LIB_TAG_DOIT;
+ }
- /* figure out what bones are selected */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ layers_array = MEM_callocN(objects_len * sizeof(*layers_array), "pose_select_same_layer");
+
+ /* Figure out what bones are selected. */
+ layers = NULL;
+ ob_prev = NULL;
+ ob_index = -1;
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
{
- /* keep track of layers to use later? */
+ if (ob != ob_prev) {
+ layers = &layers_array[++ob_index];
+ ob_prev = ob;
+ }
+
+ /* Keep track of layers to use later? */
if (pchan->bone->flag & BONE_SELECTED)
- layers |= pchan->bone->layer;
+ *layers |= pchan->bone->layer;
- /* deselect all bones before selecting new ones? */
+ /* Deselect all bones before selecting new ones? */
if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
pchan->bone->flag &= ~BONE_SELECTED;
}
CTX_DATA_END;
- if (layers == 0)
- return 0;
- /* select bones that are on same layers as layers flag */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ bool any_layer = false;
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (layers_array[ob_index]) {
+ any_layer = true;
+ break;
+ }
+ }
+
+ if (!any_layer) {
+ goto cleanup;
+ }
+
+ /* Select bones that are on same layers as layers flag. */
+ ob_prev = NULL;
+ ob_index = -1;
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
{
+ if (ob != ob_prev) {
+ layers = &layers_array[++ob_index];
+ ob_prev = ob;
+ }
+
/* if bone is on a suitable layer, and the bone can have its selection changed, select it */
- if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ if ((*layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
pchan->bone->flag |= BONE_SELECTED;
- changed = true;
+ ob->id.tag |= LIB_TAG_DOIT;
}
}
CTX_DATA_END;
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ if (ob->id.tag & LIB_TAG_DOIT) {
+ ED_pose_bone_select_tag_update(ob);
+ changed = true;
+ }
+ }
+
+cleanup:
+ /* Cleanup. */
+ MEM_freeN(layers_array);
+ MEM_freeN(objects);
+
return changed;
}
-static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object *ob, bool extend)
+static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool extend)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bool changed_multi = false;
KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
KS_Path *ksp;
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose = (ob) ? ob->pose : NULL;
- bool changed = false;
-
/* sanity checks: validate Keying Set and object */
if (ks == NULL) {
BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
@@ -749,9 +885,6 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object
return false;
}
- if (ELEM(NULL, ob, pose, arm))
- return false;
-
/* if not extending selection, deselect all selected first */
if (extend == false) {
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
@@ -762,40 +895,59 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object
CTX_DATA_END;
}
- /* iterate over elements in the Keying Set, setting selection depending on whether
- * that bone is visible or not...
- */
- for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
- /* only items related to this object will be relevant */
- if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
- if (strstr(ksp->rna_path, "bones")) {
- char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
-
- if (boneName) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
-
- if (pchan) {
- /* select if bone is visible and can be affected */
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = true;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bool changed = false;
+
+ /* Sanity checks. */
+ if (ELEM(NULL, ob, pose, arm)) {
+ continue;
+ }
+
+ /* iterate over elements in the Keying Set, setting selection depending on whether
+ * that bone is visible or not...
+ */
+ for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
+ /* only items related to this object will be relevant */
+ if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
+ if (strstr(ksp->rna_path, "bones")) {
+ char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
+
+ if (boneName) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
+
+ if (pchan) {
+ /* select if bone is visible and can be affected */
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = true;
+ }
}
- }
- /* free temp memory */
- MEM_freeN(boneName);
+ /* free temp memory */
+ MEM_freeN(boneName);
+ }
}
}
}
+
+ if (changed || !extend) {
+ ED_pose_bone_select_tag_update(ob);
+ changed_multi = true;
+ }
}
+ MEM_freeN(objects);
- return changed;
+ return changed_multi;
}
static int pose_select_grouped_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
const ePose_SelectSame_Mode type = RNA_enum_get(op->ptr, "type");
const bool extend = RNA_boolean_get(op->ptr, "extend");
bool changed = false;
@@ -807,15 +959,15 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
/* selection types */
switch (type) {
case POSE_SEL_SAME_LAYER: /* layer */
- changed = pose_select_same_layer(C, ob, extend);
+ changed = pose_select_same_layer(C, extend);
break;
case POSE_SEL_SAME_GROUP: /* group */
- changed = pose_select_same_group(C, ob, extend);
+ changed = pose_select_same_group(C, extend);
break;
case POSE_SEL_SAME_KEYINGSET: /* Keying Set */
- changed = pose_select_same_keyingset(C, op->reports, ob, extend);
+ changed = pose_select_same_keyingset(C, op->reports, extend);
break;
default:
@@ -823,14 +975,6 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
break;
}
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
/* report done status */
if (changed)
return OPERATOR_FINISHED;
@@ -872,60 +1016,66 @@ void POSE_OT_select_grouped(wmOperatorType *ot)
*/
static int pose_select_mirror_exec(bContext *C, wmOperator *op)
{
- Object *ob_act = CTX_data_active_object(C);
- Object *ob = BKE_object_pose_armature_get(ob_act);
- bArmature *arm;
- bPoseChannel *pchan, *pchan_mirror_act = NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_active_object(C);
+
+ const bool is_weight_paint = (ob_active->mode & OB_MODE_WEIGHT_PAINT) != 0;
const bool active_only = RNA_boolean_get(op->ptr, "only_active");
const bool extend = RNA_boolean_get(op->ptr, "extend");
- if ((ob && (ob->mode & OB_MODE_POSE)) == 0) {
- return OPERATOR_CANCELLED;
- }
-
- arm = ob->data;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- const int flag = (pchan->bone->flag & BONE_SELECTED);
- PBONE_PREV_FLAG_SET(pchan, flag);
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, OB_MODE_POSE);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan, *pchan_mirror_act = NULL;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- bPoseChannel *pchan_mirror;
- int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ const int flag = (pchan->bone->flag & BONE_SELECTED);
+ PBONE_PREV_FLAG_SET(pchan, flag);
+ }
- if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
- (PBONE_VISIBLE(arm, pchan_mirror->bone)))
- {
- const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
- flag_new |= flag_mirror;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ bPoseChannel *pchan_mirror;
+ int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
+
+ if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
+ (PBONE_VISIBLE(arm, pchan_mirror->bone)))
+ {
+ const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
+ flag_new |= flag_mirror;
+
+ if (pchan->bone == arm->act_bone) {
+ pchan_mirror_act = pchan_mirror;
+ }
- if (pchan->bone == arm->act_bone) {
- pchan_mirror_act = pchan_mirror;
+ /* Skip all but the active or its mirror. */
+ if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
+ continue;
+ }
}
- /* skip all but the active or its mirror */
- if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
- continue;
- }
+ pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new;
}
-
- pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new;
}
- }
- if (pchan_mirror_act) {
- arm->act_bone = pchan_mirror_act->bone;
+ if (pchan_mirror_act) {
+ arm->act_bone = pchan_mirror_act->bone;
- /* in weightpaint we select the associated vertex group too */
- if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
- ED_vgroup_select_by_name(ob_act, pchan_mirror_act->name);
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ /* In weightpaint we select the associated vertex group too. */
+ if (is_weight_paint) {
+ ED_vgroup_select_by_name(ob, pchan_mirror_act->name);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
}
- }
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ /* Need to tag armature for cow updates, or else selection doesn't update. */
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 2980bf4637e..2e7c90cee21 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -42,6 +42,7 @@
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_unit.h"
@@ -89,10 +90,9 @@ typedef struct tPoseSlideOp {
Scene *scene; /* current scene */
ScrArea *sa; /* area that we're operating in (needed for modal()) */
ARegion *ar; /* region that we're operating in (needed for modal()) */
- Object *ob; /* active object that Pose Info comes from */
- bArmature *arm; /* armature for pose */
+ uint objects_len; /* len of the PoseSlideObject array. */
- ListBase pfLinks; /* links between posechannels and f-curves */
+ ListBase pfLinks; /* links between posechannels and f-curves for all the pose objects. */
DLRBT_Tree keys; /* binary tree for quicker searching for keyframes (when applicable) */
int cframe; /* current frame number - global time */
@@ -100,9 +100,6 @@ typedef struct tPoseSlideOp {
int prevFrame; /* frame before current frame (blend-from) - global time */
int nextFrame; /* frame after current frame (blend-to) - global time */
- float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
- float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
-
short mode; /* sliding mode (ePoseSlide_Modes) */
short flag; /* unused for now, but can later get used for storing runtime settings.... */
@@ -112,8 +109,17 @@ typedef struct tPoseSlideOp {
float percentage; /* 0-1 value for determining the influence of whatever is relevant */
NumInput num; /* numeric input */
+
+ struct tPoseSlideObject *ob_data_array;
} tPoseSlideOp;
+typedef struct tPoseSlideObject {
+ Object *ob; /* active object that Pose Info comes from */
+ float prevFrameF; /* prevFrame, but in local action time (for F-Curve lookups to work) */
+ float nextFrameF; /* nextFrame, but in local action time (for F-Curve lookups to work) */
+ bool valid;
+} tPoseSlideObject;
+
/* Pose Sliding Modes */
typedef enum ePoseSlide_Modes {
POSESLIDE_PUSH = 0, /* exaggerate the pose... */
@@ -167,18 +173,15 @@ static const EnumPropertyItem prop_axis_lock_types[] = {
/* ------------------------------------ */
/* operator init */
-static int pose_slide_init(bContext *C, wmOperator *op, short mode)
+static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
{
tPoseSlideOp *pso;
- bAction *act = NULL;
/* init slide-op data */
pso = op->customdata = MEM_callocN(sizeof(tPoseSlideOp), "tPoseSlideOp");
/* get info from context */
pso->scene = CTX_data_scene(C);
- pso->ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- pso->arm = (pso->ob) ? pso->ob->data : NULL;
pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
pso->ar = CTX_wm_region(C); /* only really needed when doing modal() */
@@ -194,25 +197,39 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
pso->channels = RNA_enum_get(op->ptr, "channels");
pso->axislock = RNA_enum_get(op->ptr, "axis_lock");
- /* ensure validity of the settings from the context */
- if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
- return 0;
-
- act = pso->ob->adt->action;
+ /* for each Pose-Channel which gets affected, get the F-Curves for that channel
+ * and set the relevant transform flags...
+ */
+ poseAnim_mapping_get(C, &pso->pfLinks);
+
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(CTX_data_view_layer(C),
+ CTX_wm_view3d(C),
+ &pso->objects_len,
+ OB_MODE_POSE);
+ pso->ob_data_array = MEM_callocN(pso->objects_len * sizeof(tPoseSlideObject), "pose slide objects data");
+
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ Object *ob_iter = poseAnim_object_get(objects[ob_index]);
+
+ /* Ensure validity of the settings from the context. */
+ if (ob_iter == NULL) {
+ continue;
+ }
- /* apply NLA mapping corrections so the frame lookups work */
- pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
- pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+ ob_data->ob = ob_iter;
+ ob_data->valid = true;
- /* for each Pose-Channel which gets affected, get the F-Curves for that channel
- * and set the relevant transform flags...
- */
- poseAnim_mapping_get(C, &pso->pfLinks, pso->ob, act);
+ /* apply NLA mapping corrections so the frame lookups work */
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
- /* set depsgraph flags */
- /* make sure the lock is set OK, unlock can be accidentally saved? */
- pso->ob->pose->flag |= POSE_LOCKED;
- pso->ob->pose->flag &= ~POSE_DO_UNLOCK;
+ /* set depsgraph flags */
+ /* make sure the lock is set OK, unlock can be accidentally saved? */
+ ob_data->ob->pose->flag |= POSE_LOCKED;
+ ob_data->ob->pose->flag &= ~POSE_DO_UNLOCK;
+ }
+ MEM_freeN(objects);
/* do basic initialize of RB-BST used for finding keyframes, but leave the filling of it up
* to the caller of this (usually only invoke() will do it, to make things more efficient).
@@ -242,6 +259,10 @@ static void pose_slide_exit(wmOperator *op)
/* free RB-BST for keyframes (if it contained data) */
BLI_dlrbTree_free(&pso->keys);
+ if (pso->ob_data_array != NULL) {
+ MEM_freeN(pso->ob_data_array);
+ }
+
/* free data itself */
MEM_freeN(pso);
}
@@ -256,21 +277,51 @@ static void pose_slide_exit(wmOperator *op)
static void pose_slide_refresh(bContext *C, tPoseSlideOp *pso)
{
/* wrapper around the generic version, allowing us to add some custom stuff later still */
- poseAnim_mapping_refresh(C, pso->scene, pso->ob);
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ if (ob_data->valid) {
+ poseAnim_mapping_refresh(C, pso->scene, ob_data->ob);
+ }
+ }
+}
+
+/** Although this lookup is not ideal, we won't be dealing with a lot of objects at a given time.
+ * But if it comes to that we can instead store prev/next frme in the tPChanFCurveLink. */
+static bool pose_frame_range_from_object_get(tPoseSlideOp *pso, Object *ob, float *prevFrameF, float *nextFrameF)
+{
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ Object *ob_iter = ob_data->ob;
+
+ if (ob_iter == ob) {
+ *prevFrameF = ob_data->prevFrameF;
+ *nextFrameF = ob_data->nextFrameF;
+ return true;
+ }
+ }
+ *prevFrameF = *nextFrameF = 0.0f;
+ return false;
}
/* helper for apply() - perform sliding for some value */
-static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
+static void pose_slide_apply_val(
+ tPoseSlideOp *pso,
+ FCurve *fcu,
+ Object *ob,
+ float *val)
{
+ float prevFrameF, nextFrameF;
float cframe = (float)pso->cframe;
float sVal, eVal;
float w1, w2;
+ pose_frame_range_from_object_get(pso, ob, &prevFrameF, &nextFrameF);
+
/* get keyframe values for endpoint poses to blend with */
/* previous/start */
- sVal = evaluate_fcurve(fcu, pso->prevFrameF);
+ sVal = evaluate_fcurve(fcu, prevFrameF);
/* next/end */
- eVal = evaluate_fcurve(fcu, pso->nextFrameF);
+ eVal = evaluate_fcurve(fcu, nextFrameF);
/* if both values are equal, don't do anything */
if (IS_EQF(sVal, eVal)) {
@@ -364,7 +415,7 @@ static void pose_slide_apply_vec3(tPoseSlideOp *pso, tPChanFCurveLink *pfl, floa
((lock & PS_LOCK_Z) && (idx == 2)))
{
/* just work on these channels one by one... there's no interaction between values */
- pose_slide_apply_val(pso, fcu, &vec[fcu->array_index]);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &vec[fcu->array_index]);
}
}
@@ -413,14 +464,14 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, con
case PROP_FLOAT:
{
float tval = RNA_property_float_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, &tval);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
RNA_property_float_set(&ptr, prop, tval);
break;
}
case PROP_INT:
{
float tval = (float)RNA_property_int_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, &tval);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
RNA_property_int_set(&ptr, prop, (int)tval);
break;
}
@@ -429,7 +480,7 @@ static void pose_slide_apply_props(tPoseSlideOp *pso, tPChanFCurveLink *pfl, con
case PROP_BOOLEAN:
{
float tval = (float)RNA_property_boolean_get(&ptr, prop);
- pose_slide_apply_val(pso, fcu, &tval);
+ pose_slide_apply_val(pso, fcu, pfl->ob, &tval);
RNA_property_boolean_set(&ptr, prop, (int)tval); // XXX: do we need threshold clamping here?
break;
}
@@ -459,6 +510,12 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
LinkData *ld = NULL;
char *path = NULL;
float cframe;
+ float prevFrameF, nextFrameF;
+
+ if (!pose_frame_range_from_object_get(pso, pfl->ob, &prevFrameF, &nextFrameF)) {
+ BLI_assert(!"Invalid pfl data");
+ return;
+ }
/* get the path to use - this should be quaternion rotations only (needs care) */
path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion");
@@ -492,15 +549,15 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
float quat_prev[4], quat_next[4];
/* get 2 quats */
- quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrameF);
- quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrameF);
- quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrameF);
- quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrameF);
+ quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF);
+ quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF);
+ quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF);
+ quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF);
- quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrameF);
- quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrameF);
- quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrameF);
- quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrameF);
+ quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF);
+ quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF);
+ quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF);
+ quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF);
/* perform blending */
if (pso->mode == POSESLIDE_BREAKDOWN) {
@@ -553,9 +610,21 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
pso->prevFrame--;
pso->nextFrame++;
- /* apply NLA mapping corrections so the frame lookups work */
- pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
- pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+
+ if (!ob_data->valid) {
+ continue;
+ }
+
+ /* apply NLA mapping corrections so the frame lookups work */
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
+ pso->prevFrame,
+ NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
+ pso->nextFrame,
+ NLATIME_CONVERT_UNMAP);
+ }
}
/* for each link, handle each set of transforms */
@@ -613,7 +682,7 @@ static void pose_slide_apply(bContext *C, tPoseSlideOp *pso)
static void pose_slide_autoKeyframe(bContext *C, tPoseSlideOp *pso)
{
/* wrapper around the generic call */
- poseAnim_mapping_autoKeyframe(C, pso->scene, pso->ob, &pso->pfLinks, (float)pso->cframe);
+ poseAnim_mapping_autoKeyframe(C, pso->scene, &pso->pfLinks, (float)pso->cframe);
}
/* reset changes made to current pose */
@@ -705,14 +774,13 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
BLI_snprintf(status_str, sizeof(status_str), "%s: %d %% | %s", mode_str, (int)(pso->percentage * 100.0f), limits_str);
}
- ED_area_headerprint(pso->sa, status_str);
+ ED_area_status_text(pso->sa, status_str);
}
/* common code for invoke() methods */
static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *pso)
{
tPChanFCurveLink *pfl;
- AnimData *adt = pso->ob->adt;
wmWindow *win = CTX_wm_window(C);
/* for each link, add all its keyframes to the search tree */
@@ -722,13 +790,10 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
/* do this for each F-Curve */
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
FCurve *fcu = (FCurve *)ld->data;
- fcurve_to_keylist(adt, fcu, &pso->keys, NULL);
+ fcurve_to_keylist(pfl->ob->adt, fcu, &pso->keys, 0);
}
}
- /* consolidate these keyframes, and figure out the nearest ones */
- BLI_dlrbTree_linkedlist_sync(&pso->keys);
-
/* cancel if no keyframes found... */
if (pso->keys.root) {
ActKeyColumn *ak;
@@ -761,8 +826,17 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
}
/* apply NLA mapping corrections so the frame lookups work */
- pso->prevFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->prevFrame, NLATIME_CONVERT_UNMAP);
- pso->nextFrameF = BKE_nla_tweakedit_remap(pso->ob->adt, pso->nextFrame, NLATIME_CONVERT_UNMAP);
+ for (uint ob_index = 0; ob_index < pso->objects_len; ob_index++) {
+ tPoseSlideObject *ob_data = &pso->ob_data_array[ob_index];
+ if (ob_data->valid) {
+ ob_data->prevFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
+ pso->prevFrame,
+ NLATIME_CONVERT_UNMAP);
+ ob_data->nextFrameF = BKE_nla_tweakedit_remap(ob_data->ob->adt,
+ pso->nextFrame,
+ NLATIME_CONVERT_UNMAP);
+ }
+ }
}
else {
BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
@@ -857,7 +931,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case PADENTER:
{
/* return to normal cursor and header status */
- ED_area_headerprint(pso->sa, NULL);
+ ED_area_status_text(pso->sa, NULL);
WM_cursor_modal_restore(win);
/* insert keyframes as required... */
@@ -872,7 +946,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE:
{
/* return to normal cursor and header status */
- ED_area_headerprint(pso->sa, NULL);
+ ED_area_status_text(pso->sa, NULL);
WM_cursor_modal_restore(win);
/* reset transforms back to original state */
@@ -1263,95 +1337,78 @@ typedef union tPosePropagate_ModeData {
* if this happens to be a major issue, scrap this, and just make this happen
* independently per F-Curve
*/
-static float pose_propagate_get_boneHoldEndFrame(Object *ob, tPChanFCurveLink *pfl, float startFrame)
+static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float startFrame)
{
- DLRBT_Tree keys, blocks;
- ActKeyBlock *ab;
+ DLRBT_Tree keys;
+ Object *ob = pfl->ob;
AnimData *adt = ob->adt;
LinkData *ld;
float endFrame = startFrame;
/* set up optimized data-structures for searching for relevant keyframes + holds */
BLI_dlrbTree_init(&keys);
- BLI_dlrbTree_init(&blocks);
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
FCurve *fcu = (FCurve *)ld->data;
- fcurve_to_keylist(adt, fcu, &keys, &blocks);
+ fcurve_to_keylist(adt, fcu, &keys, 0);
}
- BLI_dlrbTree_linkedlist_sync(&keys);
- BLI_dlrbTree_linkedlist_sync(&blocks);
-
/* find the long keyframe (i.e. hold), and hence obtain the endFrame value
* - the best case would be one that starts on the frame itself
*/
- ab = (ActKeyBlock *)BLI_dlrbTree_search_exact(&blocks, compare_ab_cfraPtr, &startFrame);
-
- if (actkeyblock_is_valid(ab, &keys) == 0) {
- /* There are only two cases for no-exact match:
- * 1) the current frame is just before another key but not on a key itself
- * 2) the current frame is on a key, but that key doesn't link to the next
- *
- * If we've got the first case, then we can search for another block,
- * otherwise forget it, as we'd be overwriting some valid data.
- */
- if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &startFrame) == NULL) {
- /* we've got case 1, so try the one after */
- ab = (ActKeyBlock *)BLI_dlrbTree_search_next(&blocks, compare_ab_cfraPtr, &startFrame);
-
- if (actkeyblock_is_valid(ab, &keys) == 0) {
- /* try the block before this frame then as last resort */
- ab = (ActKeyBlock *)BLI_dlrbTree_search_prev(&blocks, compare_ab_cfraPtr, &startFrame);
-
- /* whatever happens, stop searching now... */
- if (actkeyblock_is_valid(ab, &keys) == 0) {
- /* restrict range to just the frame itself
- * i.e. everything is in motion, so no holds to safely overwrite
- */
- ab = NULL;
- }
- }
- }
- else {
- /* we've got case 2 - set ab to NULL just in case, since we shouldn't do anything in this case */
- ab = NULL;
+ ActKeyColumn *ab = (ActKeyColumn *)BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &startFrame);
+
+ /* There are only two cases for no-exact match:
+ * 1) the current frame is just before another key but not on a key itself
+ * 2) the current frame is on a key, but that key doesn't link to the next
+ *
+ * If we've got the first case, then we can search for another block,
+ * otherwise forget it, as we'd be overwriting some valid data.
+ */
+ if (ab == NULL) {
+ /* we've got case 1, so try the one after */
+ ab = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &startFrame);
+
+ if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* try the block before this frame then as last resort */
+ ab = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &startFrame);
}
}
+ /* whatever happens, stop searching now... */
+ if ((actkeyblock_get_valid_hold(ab) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
+ /* restrict range to just the frame itself
+ * i.e. everything is in motion, so no holds to safely overwrite
+ */
+ ab = NULL;
+ }
+
/* check if we can go any further than we've already gone */
if (ab) {
/* go to next if it is also valid and meets "extension" criteria */
while (ab->next) {
- ActKeyBlock *abn = (ActKeyBlock *)ab->next;
+ ActKeyColumn *abn = ab->next;
/* must be valid */
- if (actkeyblock_is_valid(abn, &keys) == 0)
- break;
- /* should start on the same frame that the last ended on */
- if (ab->end != abn->start)
+ if ((actkeyblock_get_valid_hold(abn) & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
break;
+ }
/* should have the same number of curves */
- if (ab->totcurve != abn->totcurve)
- break;
- /* should have the same value
- * XXX: this may be a bit fuzzy on larger data sets, so be careful
- */
- if (ab->val != abn->val)
+ if (ab->totblock != abn->totblock) {
break;
+ }
/* we can extend the bounds to the end of this "next" block now */
ab = abn;
}
/* end frame can now take the value of the end of the block */
- endFrame = ab->end;
+ endFrame = ab->next->cfra;
}
/* free temp memory */
BLI_dlrbTree_free(&keys);
- BLI_dlrbTree_free(&blocks);
/* return the end frame we've found */
return endFrame;
@@ -1510,8 +1567,8 @@ static void pose_propagate_fcurve(wmOperator *op, Object *ob, FCurve *fcu,
static int pose_propagate_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bAction *act = (ob && ob->adt) ? ob->adt->action : NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
ListBase pflinks = {NULL, NULL};
tPChanFCurveLink *pfl;
@@ -1519,19 +1576,16 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
tPosePropagate_ModeData modeData;
const int mode = RNA_enum_get(op->ptr, "mode");
- /* sanity checks */
- if (ob == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No object to propagate poses for");
- return OPERATOR_CANCELLED;
- }
- if (act == NULL) {
+ /* isolate F-Curves related to the selected bones */
+ poseAnim_mapping_get(C, &pflinks);
+
+ if (BLI_listbase_is_empty(&pflinks)) {
+ /* There is a change the reason the list is empty is that there is no valid object to propagate poses for.
+ * This is very unlikely though, so we focus on the most likely issue. */
BKE_report(op->reports, RPT_ERROR, "No keyframed poses to propagate to");
return OPERATOR_CANCELLED;
}
- /* isolate F-Curves related to the selected bones */
- poseAnim_mapping_get(C, &pflinks, ob, act);
-
/* mode-specific data preprocessing (requiring no access to curves) */
if (mode == POSE_PROPAGATE_SELECTED_MARKERS) {
/* get a list of selected markers */
@@ -1551,12 +1605,13 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
/* we store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
* from the keyframe that occurs after the current frame
*/
- modeData.end_frame = pose_propagate_get_boneHoldEndFrame(ob, pfl, (float)CFRA);
+ modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
}
/* go through propagating pose to keyframes, curve by curve */
- for (ld = pfl->fcurves.first; ld; ld = ld->next)
- pose_propagate_fcurve(op, ob, (FCurve *)ld->data, (float)CFRA, modeData);
+ for (ld = pfl->fcurves.first; ld; ld = ld->next) {
+ pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
+ }
}
/* free temp data */
@@ -1566,7 +1621,9 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
BLI_freelistN(&modeData.sel_markers);
/* updates + notifiers */
- poseAnim_mapping_refresh(C, scene, ob);
+ FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_MODE_POSE, ob) {
+ poseAnim_mapping_refresh(C, scene, ob);
+ } FOREACH_OBJECT_IN_MODE_END;
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 304a1f8df8c..7945c85e6d7 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -38,20 +38,23 @@
#include "BLI_math.h"
#include "BLI_string_utils.h"
-#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_appdir.h"
#include "BKE_armature.h"
#include "BKE_blender_copybuffer.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -70,8 +73,10 @@
/* Pose Apply */
/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */
-static void applyarmature_fix_boneparents(Main *bmain, Scene *scene, Object *armob)
+static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Object *armob)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Main *bmain = CTX_data_main(C);
Object workob, *ob;
/* go through all objects in database */
@@ -83,7 +88,7 @@ static void applyarmature_fix_boneparents(Main *bmain, Scene *scene, Object *arm
*/
BKE_object_apply_mat4(ob, ob->obmat, false, false);
- BKE_object_workob_calc_parent(scene, ob, &workob);
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
}
}
@@ -93,8 +98,10 @@ static void applyarmature_fix_boneparents(Main *bmain, Scene *scene, Object *arm
static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
bArmature *arm = BKE_armature_from_object(ob);
bPose *pose;
bPoseChannel *pchan;
@@ -122,11 +129,12 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
pose = ob->pose;
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
curbone = ED_armature_ebone_find_name(arm->edbo, pchan->name);
/* simply copy the head/tail values from pchan over to curbone */
- copy_v3_v3(curbone->head, pchan->pose_head);
- copy_v3_v3(curbone->tail, pchan->pose_tail);
+ copy_v3_v3(curbone->head, pchan_eval->pose_head);
+ copy_v3_v3(curbone->tail, pchan_eval->pose_tail);
/* fix roll:
* 1. find auto-calculated roll value for this bone now
@@ -142,7 +150,7 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
invert_m3_m3(imat, premat);
/* get pchan 'visual' matrix */
- copy_m3_m4(pmat, pchan->pose_mat);
+ copy_m3_m4(pmat, pchan_eval->pose_mat);
/* remove auto from visual and get euler rotation */
mul_m3_m3m3(tmat, imat, pmat);
@@ -156,17 +164,19 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
* then clear the pchan values (so we don't get a double-up)
*/
if (pchan->bone->segments > 1) {
- curbone->curveInX += pchan->curveInX;
- curbone->curveInY += pchan->curveInY;
- curbone->curveOutX += pchan->curveOutX;
- curbone->curveOutY += pchan->curveOutY;
- curbone->roll1 += pchan->roll1;
- curbone->roll2 += pchan->roll2;
- curbone->ease1 += pchan->ease1;
- curbone->ease2 += pchan->ease2;
- curbone->scaleIn *= pchan->scaleIn;
- curbone->scaleOut *= pchan->scaleOut;
-
+ /* combine rest/pose values */
+ curbone->curveInX += pchan_eval->curveInX;
+ curbone->curveInY += pchan_eval->curveInY;
+ curbone->curveOutX += pchan_eval->curveOutX;
+ curbone->curveOutY += pchan_eval->curveOutY;
+ curbone->roll1 += pchan_eval->roll1;
+ curbone->roll2 += pchan_eval->roll2;
+ curbone->ease1 += pchan_eval->ease1;
+ curbone->ease2 += pchan_eval->ease2;
+ curbone->scaleIn += pchan_eval->scaleIn;
+ curbone->scaleOut += pchan_eval->scaleOut;
+
+ /* reset pose values */
pchan->curveInX = pchan->curveOutX = 0.0f;
pchan->curveInY = pchan->curveOutY = 0.0f;
pchan->roll1 = pchan->roll2 = 0.0f;
@@ -190,13 +200,14 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
ED_armature_edit_free(arm);
/* flush positions of posebones */
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob);
/* fix parenting of objects which are bone-parented */
- applyarmature_fix_boneparents(bmain, scene, ob);
+ applyarmature_fix_boneparents(C, scene, ob);
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
@@ -220,38 +231,42 @@ void POSE_OT_armature_apply(wmOperatorType *ot)
/* set the current pose as the restpose */
static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
- /* don't check if editmode (should be done by caller) */
- if (ob->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
-
- /* loop over all selected pchans
- *
- * TODO, loop over children before parents if multiple bones
- * at once are to be predictable*/
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
+ FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_MODE_POSE, ob)
{
- float delta_mat[4][4];
-
- /* chan_mat already contains the delta transform from rest pose to pose-mode pose
- * as that is baked into there so that B-Bones will work. Once we've set this as the
- * new raw-transform components, don't recalc the poses yet, otherwise IK result will
- * change, thus changing the result we may be trying to record.
- */
- /* XXX For some reason, we can't use pchan->chan_mat here, gives odd rotation/offset (see T38251).
- * Using pchan->pose_mat and bringing it back in bone space seems to work as expected!
- */
- BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, delta_mat);
+ /* loop over all selected pchans
+ *
+ * TODO, loop over children before parents if multiple bones
+ * at once are to be predictable*/
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob, pchan)
+ {
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ float delta_mat[4][4];
+
+ /* chan_mat already contains the delta transform from rest pose to pose-mode pose
+ * as that is baked into there so that B-Bones will work. Once we've set this as the
+ * new raw-transform components, don't recalc the poses yet, otherwise IK result will
+ * change, thus changing the result we may be trying to record.
+ */
+ /* XXX For some reason, we can't use pchan->chan_mat here, gives odd rotation/offset (see T38251).
+ * Using pchan->pose_mat and bringing it back in bone space seems to work as expected!
+ */
+ BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, delta_mat);
- BKE_pchan_apply_mat4(pchan, delta_mat, true);
- }
- CTX_DATA_END;
+ BKE_pchan_apply_mat4(pchan, delta_mat, true);
+ }
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
return OPERATOR_FINISHED;
}
@@ -502,7 +517,6 @@ void POSE_OT_copy(wmOperatorType *ot)
static int pose_paste_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
Scene *scene = CTX_data_scene(C);
bPoseChannel *chan;
@@ -567,11 +581,11 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
BKE_main_free(tmp_bmain);
/* Update event for pose and deformation children. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
/* Recalculate paths if any of the bones have paths... */
if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(bmain, scene, ob);
+ ED_pose_recalculate_paths(C, scene, ob, false);
}
/* Notifiers for updates, */
@@ -755,10 +769,8 @@ static void pchan_clear_transforms(bPoseChannel *pchan)
static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
void (*clear_func)(bPoseChannel *), const char default_ksName[])
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- short autokey = 0;
+ bool changed_multi = false;
/* sanity checks */
if (ELEM(NULL, clear_func, default_ksName)) {
@@ -767,47 +779,71 @@ static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
}
/* only clear relevant transforms for selected bones */
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob_iter)
{
- /* run provided clearing function */
- clear_func(pchan);
+ Object *ob_eval = DEG_get_evaluated_object(CTX_data_depsgraph(C), ob_iter); // XXX: UGLY HACK (for autokey + clear transforms)
+ ListBase dsources = {NULL, NULL};
+ bool changed = false;
- /* do auto-keyframing as appropriate */
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- /* clear any unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag &= ~BONE_UNKEYED;
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan)
+ {
+ /* run provided clearing function */
+ clear_func(pchan);
+ changed = true;
+
+ /* do auto-keyframing as appropriate */
+ if (autokeyframe_cfra_can_key(scene, &ob_iter->id)) {
+ /* clear any unkeyed tags */
+ if (pchan->bone) {
+ pchan->bone->flag &= ~BONE_UNKEYED;
+ }
+ /* tag for autokeying later */
+ ANIM_relative_keyingset_add_source(&dsources, &ob_iter->id, &RNA_PoseBone, pchan);
- /* tag for autokeying later */
- autokey = 1;
- }
- else {
- /* add unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag |= BONE_UNKEYED;
+#if 1 /* XXX: Ugly Hack - Run clearing function on evaluated copy of pchan */
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ clear_func(pchan_eval);
+#endif
+ }
+ else {
+ /* add unkeyed tags */
+ if (pchan->bone) {
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
}
- }
- CTX_DATA_END;
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
- /* perform autokeying on the bones if needed */
- if (autokey) {
- /* get KeyingSet to use */
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
+ if (changed) {
+ changed_multi = true;
- /* insert keyframes */
- ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ /* perform autokeying on the bones if needed */
+ if (!BLI_listbase_is_empty(&dsources)) {
+ /* get KeyingSet to use */
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
- /* now recalculate paths */
- if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS))
- ED_pose_recalculate_paths(bmain, scene, ob);
- }
+ /* insert keyframes */
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* now recalculate paths */
+ if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
+ ED_pose_recalculate_paths(C, scene, ob_iter, false);
+ }
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+ BLI_freelistN(&dsources);
+ }
- return OPERATOR_FINISHED;
+ DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob_iter);
+ }
+ }
+ FOREACH_OBJECT_IN_MODE_END;
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
/* --------------- */
@@ -900,57 +936,62 @@ void POSE_OT_transforms_clear(wmOperatorType *ot)
static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
float cframe = (float)CFRA;
const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
- if ((ob->adt) && (ob->adt->action)) {
- /* XXX: this is just like this to avoid contaminating anything else;
- * just pose values should change, so this should be fine
- */
- bPose *dummyPose = NULL;
- Object workob = {{NULL}};
- bPoseChannel *pchan;
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob)
+ {
+ if ((ob->adt) && (ob->adt->action)) {
+ /* XXX: this is just like this to avoid contaminating anything else;
+ * just pose values should change, so this should be fine
+ */
+ bPose *dummyPose = NULL;
+ Object workob = {{NULL}};
+ bPoseChannel *pchan;
- /* execute animation step for current frame using a dummy copy of the pose */
- BKE_pose_copy_data(&dummyPose, ob->pose, 0);
+ /* execute animation step for current frame using a dummy copy of the pose */
+ BKE_pose_copy_data(&dummyPose, ob->pose, 0);
- BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
- workob.type = OB_ARMATURE;
- workob.data = ob->data;
- workob.adt = ob->adt;
- workob.pose = dummyPose;
+ BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
+ workob.type = OB_ARMATURE;
+ workob.data = ob->data;
+ workob.adt = ob->adt;
+ workob.pose = dummyPose;
- BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(NULL, scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
- /* copy back values, but on selected bones only */
- for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
- pose_bone_do_paste(ob, pchan, only_select, 0);
- }
+ /* copy back values, but on selected bones only */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ pose_bone_do_paste(ob, pchan, only_select, 0);
+ }
- /* free temp data - free manually as was copied without constraints */
- for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
+ /* free temp data - free manually as was copied without constraints */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->prop) {
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ }
}
+
+ /* was copied without constraints */
+ BLI_freelistN(&dummyPose->chanbase);
+ MEM_freeN(dummyPose);
+ }
+ else {
+ /* no animation, so just reset whole pose to rest pose
+ * (cannot just restore for selected though)
+ */
+ BKE_pose_rest(ob->pose);
}
- /* was copied without constraints */
- BLI_freelistN(&dummyPose->chanbase);
- MEM_freeN(dummyPose);
+ /* notifiers and updates */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
}
- else {
- /* no animation, so just reset whole pose to rest pose
- * (cannot just restore for selected though)
- */
- BKE_pose_rest(ob->pose);
- }
-
- /* notifiers and updates */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+ FOREACH_OBJECT_IN_MODE_END;
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index f5ba688fd46..dc4b969371d 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -39,12 +39,15 @@
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_depsgraph.h"
#include "BKE_idprop.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_context.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "WM_api.h"
@@ -80,6 +83,7 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
tPChanFCurveLink *pfl = MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
PointerRNA ptr;
+ pfl->ob = ob;
pfl->fcurves = curves;
pfl->pchan = pchan;
@@ -126,16 +130,48 @@ static void fcurves_to_pchan_links_get(ListBase *pfLinks, Object *ob, bAction *a
}
}
+/**
+ * Returns a valid pose armature for this object, else returns NULL.
+ **/
+Object *poseAnim_object_get(Object *ob_)
+{
+ Object *ob = BKE_object_pose_armature_get(ob_);
+ if (!ELEM(NULL,
+ ob,
+ ob->data,
+ ob->adt,
+ ob->adt->action))
+ {
+ return ob;
+ }
+ return NULL;
+}
/* get sets of F-Curves providing transforms for the bones in the Pose */
-void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *act)
+void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
{
/* for each Pose-Channel which gets affected, get the F-Curves for that channel
* and set the relevant transform flags...
*/
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ Object *prev_ob, *ob_pose_armature;
+
+ prev_ob = NULL;
+ ob_pose_armature = NULL;
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
{
- fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
+ if (ob != prev_ob) {
+ prev_ob = ob;
+ ob_pose_armature = poseAnim_object_get(ob);
+ }
+
+ if (ob_pose_armature == NULL) {
+ continue;
+ }
+
+ fcurves_to_pchan_links_get(pfLinks,
+ ob_pose_armature,
+ ob_pose_armature->adt->action,
+ pchan);
}
CTX_DATA_END;
@@ -143,12 +179,25 @@ void poseAnim_mapping_get(bContext *C, ListBase *pfLinks, Object *ob, bAction *a
* i.e. if nothing selected, do whole pose
*/
if (BLI_listbase_is_empty(pfLinks)) {
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ prev_ob = NULL;
+ ob_pose_armature = NULL;
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob)
{
- fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
+ if (ob != prev_ob) {
+ prev_ob = ob;
+ ob_pose_armature = poseAnim_object_get(ob);
+ }
+
+ if (ob_pose_armature == NULL) {
+ continue;
+ }
+
+ fcurves_to_pchan_links_get(pfLinks,
+ ob_pose_armature,
+ ob_pose_armature->adt->action,
+ pchan);
}
CTX_DATA_END;
-
}
}
@@ -183,6 +232,7 @@ void poseAnim_mapping_free(ListBase *pfLinks)
/* helper for apply() / reset() - refresh the data */
void poseAnim_mapping_refresh(bContext *C, Scene *scene, Object *ob)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
bArmature *arm = (bArmature *)ob->data;
/* old optimize trick... this enforces to bypass the depgraph
@@ -190,11 +240,11 @@ void poseAnim_mapping_refresh(bContext *C, Scene *scene, Object *ob)
*/
/* FIXME: shouldn't this use the builtin stuff? */
if ((arm->flag & ARM_DELAYDEFORM) == 0)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
else
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob);
- /* note, notifier might evolve */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); /* otherwise animation doesn't get updated */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
}
@@ -234,44 +284,72 @@ void poseAnim_mapping_reset(ListBase *pfLinks)
}
/* perform autokeyframing after changes were made + confirmed */
-void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, Object *ob, ListBase *pfLinks, float cframe)
+void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
{
- Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ bool skip = true;
+
+ FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_MODE_POSE, ob) {
+ ob->id.tag &= ~LIB_TAG_DOIT;
+ ob = poseAnim_object_get(ob);
+
+ /* Ensure validity of the settings from the context. */
+ if (ob == NULL) {
+ continue;
+ }
+
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ ob->id.tag |= LIB_TAG_DOIT;
+ skip = false;
+ }
+ } FOREACH_OBJECT_IN_MODE_END;
+
+ if (skip) {
+ return;
+ }
/* insert keyframes as necessary if autokeyframing */
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
- ListBase dsources = {NULL, NULL};
- tPChanFCurveLink *pfl;
-
- /* iterate over each pose-channel affected, tagging bones to be keyed */
- /* XXX: here we already have the information about what transforms exist, though
- * it might be easier to just overwrite all using normal mechanisms
- */
- for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
- bPoseChannel *pchan = pfl->pchan;
-
- /* add datasource override for the PoseChannel, to be used later */
- ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan);
-
- /* clear any unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag &= ~BONE_UNKEYED;
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
+ ListBase dsources = {NULL, NULL};
+ tPChanFCurveLink *pfl;
+
+ /* iterate over each pose-channel affected, tagging bones to be keyed */
+ /* XXX: here we already have the information about what transforms exist, though
+ * it might be easier to just overwrite all using normal mechanisms
+ */
+ for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
+ bPoseChannel *pchan = pfl->pchan;
+
+ if ((pfl->ob->id.tag & LIB_TAG_DOIT) == 0) {
+ continue;
}
- /* insert keyframes for all relevant bones in one go */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
- BLI_freelistN(&dsources);
-
- /* do the bone paths
- * - only do this if keyframes should have been added
- * - do not calculate unless there are paths already to update...
- */
- if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
- //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
- ED_pose_recalculate_paths(bmain, scene, ob);
+ /* add datasource override for the PoseChannel, to be used later */
+ ANIM_relative_keyingset_add_source(&dsources, &pfl->ob->id, &RNA_PoseBone, pchan);
+
+ /* clear any unkeyed tags */
+ if (pchan->bone) {
+ pchan->bone->flag &= ~BONE_UNKEYED;
}
}
+
+ /* insert keyframes for all relevant bones in one go */
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
+ BLI_freelistN(&dsources);
+
+ /* do the bone paths
+ * - only do this if keyframes should have been added
+ * - do not calculate unless there are paths already to update...
+ */
+ FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, v3d, OB_MODE_POSE, ob) {
+ if (ob->id.tag & LIB_TAG_DOIT) {
+ if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
+ //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
+ ED_pose_recalculate_paths(C, scene, ob, false);
+ }
+ }
+ } FOREACH_OBJECT_IN_MODE_END;
}
/* ------------------------- */
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
deleted file mode 100644
index d837c702cb7..00000000000
--- a/source/blender/editors/armature/reeb.c
+++ /dev/null
@@ -1,3435 +0,0 @@
-/*
- * ***** 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): Martin Poirier
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/armature/reeb.c
- * \ingroup edarmature
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_edgehash.h"
-#include "BLI_ghash.h"
-
-#include "BKE_context.h"
-
-#include "reeb.h"
-
-#if 0 /* UNUSED 2.5 */
-static ReebGraph *GLOBAL_RG = NULL;
-static ReebGraph *FILTERED_RG = NULL;
-#endif
-
-/*
- * Skeleton generation algorithm based on:
- * "Harmonic Skeleton for Realistic Character Animation"
- * Gregoire Aujay, Franck Hetroy, Francis Lazarus and Christine Depraz
- * SIGGRAPH 2007
- *
- * Reeb graph generation algorithm based on:
- * "Robust On-line Computation of Reeb Graphs: Simplicity and Speed"
- * Valerio Pascucci, Giorgio Scorzelli, Peer-Timo Bremer and Ajith Mascarenhas
- * SIGGRAPH 2007
- *
- * */
-
-#if 0
-#define DEBUG_REEB
-#define DEBUG_REEB_NODE
-#endif
-
-/* place-holders! */
-typedef struct EditEdge {
- void *fake;
-} EditEdge;
-
-typedef struct EditFace {
- void *fake;
-} EditFace;
-/* end place-holders! */
-
-typedef struct VertexData {
- float w; /* weight */
- int i; /* index */
- ReebNode *n;
-} VertexData;
-
-typedef struct EdgeIndex {
- EditEdge **edges;
- int *offset;
-} EdgeIndex;
-
-typedef enum {
- MERGE_LOWER,
- MERGE_HIGHER,
- MERGE_APPEND
-} MergeDirection;
-
-int mergeArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1);
-void mergeArcEdges(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc, MergeDirection direction);
-int mergeConnectedArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1);
-EditEdge *NextEdgeForVert(EdgeIndex *indexed_edges, int index);
-void mergeArcFaces(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc);
-void addFacetoArc(ReebArc *arc, EditFace *efa);
-
-void REEB_RadialSymmetry(BNode *root_node, RadialArc *ring, int count);
-void REEB_AxialSymmetry(BNode *root_node, BNode *node1, BNode *node2, struct BArc *barc1, BArc *barc2);
-
-void flipArcBuckets(ReebArc *arc);
-
-
-/***************************************** UTILS **********************************************/
-
-#if 0 /* UNUSED */
-static VertexData *allocVertexData(EditMesh *em)
-{
- VertexData *data;
- EditVert *eve;
- int totvert, index;
-
- totvert = BLI_listbase_count(&em->verts);
-
- data = MEM_callocN(sizeof(VertexData) * totvert, "VertexData");
-
- for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next)
- {
- data[index].i = index;
- data[index].w = 0;
- eve->tmp.p = data + index;
- }
-
- return data;
-}
-
-static int indexData(EditVert *eve)
-{
- return ((VertexData *)eve->tmp.p)->i;
-}
-
-static float weightData(EditVert *eve)
-{
- return ((VertexData *)eve->tmp.p)->w;
-}
-
-static void weightSetData(EditVert *eve, float w)
-{
- ((VertexData *)eve->tmp.p)->w = w;
-}
-
-static ReebNode *nodeData(EditVert *eve)
-{
- return ((VertexData *)eve->tmp.p)->n;
-}
-
-static void nodeSetData(EditVert *eve, ReebNode *n)
-{
- ((VertexData *)eve->tmp.p)->n = n;
-}
-
-#endif
-
-void REEB_freeArc(BArc *barc)
-{
- ReebArc *arc = (ReebArc *)barc;
- BLI_freelistN(&arc->edges);
-
- if (arc->buckets)
- MEM_freeN(arc->buckets);
-
- if (arc->faces)
- BLI_ghash_free(arc->faces, NULL, NULL);
-
- MEM_freeN(arc);
-}
-
-void REEB_freeGraph(ReebGraph *rg)
-{
- ReebArc *arc;
- ReebNode *node;
-
- // free nodes
- for (node = rg->nodes.first; node; node = node->next) {
- BLI_freeNode((BGraph *)rg, (BNode *)node);
- }
- BLI_freelistN(&rg->nodes);
-
- // free arcs
- arc = rg->arcs.first;
- while (arc) {
- ReebArc *next = arc->next;
- REEB_freeArc((BArc *)arc);
- arc = next;
- }
-
- // free edge map
- BLI_edgehash_free(rg->emap, NULL);
-
- /* free linked graph */
- if (rg->link_up) {
- REEB_freeGraph(rg->link_up);
- }
-
- MEM_freeN(rg);
-}
-
-ReebGraph *newReebGraph(void)
-{
- ReebGraph *rg;
- rg = MEM_callocN(sizeof(ReebGraph), "reeb graph");
-
- rg->totnodes = 0;
- rg->emap = BLI_edgehash_new(__func__);
-
-
- rg->free_arc = REEB_freeArc;
- rg->free_node = NULL;
- rg->radial_symmetry = REEB_RadialSymmetry;
- rg->axial_symmetry = REEB_AxialSymmetry;
-
- return rg;
-}
-
-void BIF_flagMultiArcs(ReebGraph *rg, int flag)
-{
- for (; rg; rg = rg->link_up) {
- BLI_flagArcs((BGraph *)rg, flag);
- }
-}
-
-#if 0 /* UNUSED */
-static ReebNode *addNode(ReebGraph *rg, EditVert *eve)
-{
- float weight;
- ReebNode *node = NULL;
-
- weight = weightData(eve);
-
- node = MEM_callocN(sizeof(ReebNode), "reeb node");
-
- node->flag = 0; // clear flag on init
- node->symmetry_level = 0;
- node->arcs = NULL;
- node->degree = 0;
- node->weight = weight;
- node->index = rg->totnodes;
- copy_v3_v3(node->p, eve->co);
-
- BLI_addtail(&rg->nodes, node);
- rg->totnodes++;
-
- nodeSetData(eve, node);
-
- return node;
-}
-
-static ReebNode *copyNode(ReebGraph *rg, ReebNode *node)
-{
- ReebNode *cp_node = NULL;
-
- cp_node = MEM_callocN(sizeof(ReebNode), "reeb node copy");
-
- memcpy(cp_node, node, sizeof(ReebNode));
-
- cp_node->prev = NULL;
- cp_node->next = NULL;
- cp_node->arcs = NULL;
-
- cp_node->link_up = NULL;
- cp_node->link_down = NULL;
-
- BLI_addtail(&rg->nodes, cp_node);
- rg->totnodes++;
-
- return cp_node;
-}
-
-static void relinkNodes(ReebGraph *low_rg, ReebGraph *high_rg)
-{
- ReebNode *low_node, *high_node;
-
- if (low_rg == NULL || high_rg == NULL)
- {
- return;
- }
-
- for (low_node = low_rg->nodes.first; low_node; low_node = low_node->next)
- {
- for (high_node = high_rg->nodes.first; high_node; high_node = high_node->next)
- {
- if (low_node->index == high_node->index)
- {
- high_node->link_down = low_node;
- low_node->link_up = high_node;
- break;
- }
- }
- }
-}
-#endif
-
-ReebNode *BIF_otherNodeFromIndex(ReebArc *arc, ReebNode *node)
-{
- return (arc->head->index == node->index) ? arc->tail : arc->head;
-}
-
-ReebNode *BIF_NodeFromIndex(ReebArc *arc, ReebNode *node)
-{
- return (arc->head->index == node->index) ? arc->head : arc->tail;
-}
-
-ReebNode *BIF_lowestLevelNode(ReebNode *node)
-{
- while (node->link_down) {
- node = node->link_down;
- }
-
- return node;
-}
-
-#if 0 /* UNUSED */
-static ReebArc *copyArc(ReebGraph *rg, ReebArc *arc)
-{
- ReebArc *cp_arc;
- ReebNode *node;
-
- cp_arc = MEM_callocN(sizeof(ReebArc), "reeb arc copy");
-
- memcpy(cp_arc, arc, sizeof(ReebArc));
-
- cp_arc->link_up = arc;
-
- cp_arc->head = NULL;
- cp_arc->tail = NULL;
-
- cp_arc->prev = NULL;
- cp_arc->next = NULL;
-
- cp_arc->edges.first = NULL;
- cp_arc->edges.last = NULL;
-
- /* copy buckets */
- cp_arc->buckets = MEM_callocN(sizeof(EmbedBucket) * cp_arc->bcount, "embed bucket");
- memcpy(cp_arc->buckets, arc->buckets, sizeof(EmbedBucket) * cp_arc->bcount);
-
- /* copy faces map */
- cp_arc->faces = BLI_ghash_ptr_new("copyArc gh");
- mergeArcFaces(rg, cp_arc, arc);
-
- /* find corresponding head and tail */
- for (node = rg->nodes.first; node && (cp_arc->head == NULL || cp_arc->tail == NULL); node = node->next)
- {
- if (node->index == arc->head->index)
- {
- cp_arc->head = node;
- }
- else if (node->index == arc->tail->index)
- {
- cp_arc->tail = node;
- }
- }
-
- BLI_addtail(&rg->arcs, cp_arc);
-
- return cp_arc;
-}
-
-static ReebGraph *copyReebGraph(ReebGraph *rg, int level)
-{
- ReebNode *node;
- ReebArc *arc;
- ReebGraph *cp_rg = newReebGraph();
-
- cp_rg->resolution = rg->resolution;
- cp_rg->length = rg->length;
- cp_rg->link_up = rg;
- cp_rg->multi_level = level;
-
- /* Copy nodes */
- for (node = rg->nodes.first; node; node = node->next)
- {
- ReebNode *cp_node = copyNode(cp_rg, node);
- cp_node->multi_level = level;
- }
-
- /* Copy arcs */
- for (arc = rg->arcs.first; arc; arc = arc->next)
- {
- copyArc(cp_rg, arc);
- }
-
- BLI_buildAdjacencyList((BGraph *)cp_rg);
-
- return cp_rg;
-}
-#endif
-
-ReebGraph *BIF_graphForMultiNode(ReebGraph *rg, ReebNode *node)
-{
- ReebGraph *multi_rg = rg;
-
- while (multi_rg && multi_rg->multi_level != node->multi_level) {
- multi_rg = multi_rg->link_up;
- }
-
- return multi_rg;
-}
-
-#if 0 /* UNUSED */
-static ReebEdge *copyEdge(ReebEdge *edge)
-{
- ReebEdge *newEdge = NULL;
-
- newEdge = MEM_callocN(sizeof(ReebEdge), "reeb edge");
- memcpy(newEdge, edge, sizeof(ReebEdge));
-
- newEdge->next = NULL;
- newEdge->prev = NULL;
-
- return newEdge;
-}
-
-static void printArc(ReebArc *arc)
-{
- ReebEdge *edge;
- ReebNode *head = (ReebNode *)arc->head;
- ReebNode *tail = (ReebNode *)arc->tail;
- printf("arc: (%i) %f -> (%i) %f\n", head->index, head->weight, tail->index, tail->weight);
-
- for (edge = arc->edges.first; edge; edge = edge->next)
- {
- printf("\tedge (%i, %i)\n", edge->v1->index, edge->v2->index);
- }
-}
-
-static void flipArc(ReebArc *arc)
-{
- ReebNode *tmp;
- tmp = arc->head;
- arc->head = arc->tail;
- arc->tail = tmp;
-
- flipArcBuckets(arc);
-}
-
-#ifdef DEBUG_REEB_NODE
-static void NodeDegreeDecrement(ReebGraph *UNUSED(rg), ReebNode *node)
-{
- node->degree--;
-
-// if (node->degree == 0)
-// {
-// printf("would remove node %i\n", node->index);
-// }
-}
-
-static void NodeDegreeIncrement(ReebGraph *UNUSED(rg), ReebNode *node)
-{
-// if (node->degree == 0)
-// {
-// printf("first connect node %i\n", node->index);
-// }
-
- node->degree++;
-}
-
-#else
-# define NodeDegreeDecrement(rg, node) {node->degree--; } (void)0
-# define NodeDegreeIncrement(rg, node) {node->degree++; } (void)0
-#endif
-
-void repositionNodes(ReebGraph *rg)
-{
- BArc *arc = NULL;
- BNode *node = NULL;
-
- // Reset node positions
- for (node = rg->nodes.first; node; node = node->next) {
- node->p[0] = node->p[1] = node->p[2] = 0;
- }
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- if (((ReebArc *)arc)->bcount > 0) {
- float p[3];
-
- copy_v3_v3(p, ((ReebArc *)arc)->buckets[0].p);
- mul_v3_fl(p, 1.0f / arc->head->degree);
- add_v3_v3(arc->head->p, p);
-
- copy_v3_v3(p, ((ReebArc *)arc)->buckets[((ReebArc *)arc)->bcount - 1].p);
- mul_v3_fl(p, 1.0f / arc->tail->degree);
- add_v3_v3(arc->tail->p, p);
- }
- }
-}
-
-void verifyNodeDegree(ReebGraph *rg)
-{
-#ifdef DEBUG_REEB
- ReebNode *node = NULL;
- ReebArc *arc = NULL;
-
- for (node = rg->nodes.first; node; node = node->next) {
- int count = 0;
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- if (arc->head == node || arc->tail == node) {
- count++;
- }
- }
- if (count != node->degree) {
- printf("degree error in node %i: expected %i got %i\n", node->index, count, node->degree);
- }
- if (node->degree == 0) {
- printf("zero degree node %i with weight %f\n", node->index, node->weight);
- }
- }
-#endif
-}
-
-static void verifyBucketsArc(ReebGraph *UNUSED(rg), ReebArc *arc)
-{
- ReebNode *head = (ReebNode *)arc->head;
- ReebNode *tail = (ReebNode *)arc->tail;
-
- if (arc->bcount > 0) {
- int i;
- for (i = 0; i < arc->bcount; i++) {
- if (arc->buckets[i].nv == 0) {
- printArc(arc);
- printf("count error in bucket %i/%i\n", i + 1, arc->bcount);
- }
- }
-
- if (ceilf(head->weight) != arc->buckets[0].val) {
- printArc(arc);
- printf("alloc error in first bucket: %f should be %f\n", arc->buckets[0].val, ceil(head->weight));
- }
- if (floorf(tail->weight) != arc->buckets[arc->bcount - 1].val) {
- printArc(arc);
- printf("alloc error in last bucket: %f should be %f\n", arc->buckets[arc->bcount - 1].val, floor(tail->weight));
- }
- }
-}
-
-void verifyBuckets(ReebGraph *rg)
-{
-#ifdef DEBUG_REEB
- ReebArc *arc = NULL;
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- verifyBucketsArc(rg, arc);
- }
-#endif
-}
-
-void verifyFaces(ReebGraph *rg)
-{
-#ifdef DEBUG_REEB
- int total = 0;
- ReebArc *arc = NULL;
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- total += BLI_ghash_len(arc->faces);
- }
-
-#endif
-}
-
-void verifyArcs(ReebGraph *rg)
-{
- ReebArc *arc;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- if (arc->head->weight > arc->tail->weight) {
- printf("FLIPPED ARC!\n");
- }
- }
-}
-
-static void verifyMultiResolutionLinks(ReebGraph *rg, int level)
-{
-#ifdef DEBUG_REEB
- ReebGraph *lower_rg = rg->link_up;
-
- if (lower_rg) {
- ReebArc *arc;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- if (BLI_findindex(&lower_rg->arcs, arc->link_up) == -1) {
- printf("missing arc %p for level %i\n", (void *)arc->link_up, level);
- printf("Source arc was ---\n");
- printArc(arc);
-
- arc->link_up = NULL;
- }
- }
-
-
- verifyMultiResolutionLinks(lower_rg, level + 1);
- }
-#endif
-}
-/***************************************** BUCKET UTILS **********************************************/
-
-static void addVertToBucket(EmbedBucket *b, float co[3])
-{
- b->nv++;
- interp_v3_v3v3(b->p, b->p, co, 1.0f / b->nv);
-}
-
-#if 0 /* UNUSED 2.5 */
-static void removeVertFromBucket(EmbedBucket *b, float co[3])
-{
- mul_v3_fl(b->p, (float)b->nv);
- sub_v3_v3(b->p, co);
- b->nv--;
- mul_v3_fl(b->p, 1.0f / (float)b->nv);
-}
-#endif
-
-static void mergeBuckets(EmbedBucket *bDst, EmbedBucket *bSrc)
-{
- if (bDst->nv > 0 && bSrc->nv > 0) {
- bDst->nv += bSrc->nv;
- interp_v3_v3v3(bDst->p, bDst->p, bSrc->p, (float)bSrc->nv / (float)(bDst->nv));
- }
- else if (bSrc->nv > 0) {
- bDst->nv = bSrc->nv;
- copy_v3_v3(bDst->p, bSrc->p);
- }
-}
-
-static void mergeArcBuckets(ReebArc *aDst, ReebArc *aSrc, float start, float end)
-{
- if (aDst->bcount > 0 && aSrc->bcount > 0) {
- int indexDst = 0, indexSrc = 0;
-
- start = max_fff(start, aDst->buckets[0].val, aSrc->buckets[0].val);
-
- while (indexDst < aDst->bcount && aDst->buckets[indexDst].val < start) {
- indexDst++;
- }
-
- while (indexSrc < aSrc->bcount && aSrc->buckets[indexSrc].val < start) {
- indexSrc++;
- }
-
- for (; indexDst < aDst->bcount &&
- indexSrc < aSrc->bcount &&
- aDst->buckets[indexDst].val <= end &&
- aSrc->buckets[indexSrc].val <= end
-
- ; indexDst++, indexSrc++)
- {
- mergeBuckets(aDst->buckets + indexDst, aSrc->buckets + indexSrc);
- }
- }
-}
-
-void flipArcBuckets(ReebArc *arc)
-{
- int i, j;
-
- for (i = 0, j = arc->bcount - 1; i < j; i++, j--) {
- EmbedBucket tmp;
-
- tmp = arc->buckets[i];
- arc->buckets[i] = arc->buckets[j];
- arc->buckets[j] = tmp;
- }
-}
-
-static int countArcBuckets(ReebArc *arc)
-{
- return (int)(floor(arc->tail->weight) - ceil(arc->head->weight)) + 1;
-}
-
-static void allocArcBuckets(ReebArc *arc)
-{
- int i;
- float start = ceil(arc->head->weight);
- arc->bcount = countArcBuckets(arc);
-
- if (arc->bcount > 0) {
- arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "embed bucket");
-
- for (i = 0; i < arc->bcount; i++) {
- arc->buckets[i].val = start + i;
- }
- }
- else {
- arc->buckets = NULL;
- }
-}
-
-static void resizeArcBuckets(ReebArc *arc)
-{
- EmbedBucket *oldBuckets = arc->buckets;
- int oldBCount = arc->bcount;
-
- if (countArcBuckets(arc) == oldBCount) {
- return;
- }
-
- allocArcBuckets(arc);
-
- if (oldBCount != 0 && arc->bcount != 0) {
- int oldStart = (int)oldBuckets[0].val;
- int oldEnd = (int)oldBuckets[oldBCount - 1].val;
- int newStart = (int)arc->buckets[0].val;
- int newEnd = (int)arc->buckets[arc->bcount - 1].val;
- int oldOffset = 0;
- int newOffset = 0;
- int len;
-
- if (oldStart < newStart) {
- oldOffset = newStart - oldStart;
- }
- else {
- newOffset = oldStart - newStart;
- }
-
- len = MIN2(oldEnd - (oldStart + oldOffset) + 1, newEnd - (newStart - newOffset) + 1);
-
- memcpy(arc->buckets + newOffset, oldBuckets + oldOffset, len * sizeof(EmbedBucket));
- }
-
- if (oldBuckets != NULL) {
- MEM_freeN(oldBuckets);
- }
-}
-
-static void reweightBuckets(ReebArc *arc)
-{
- int i;
- float start = ceil((arc->head)->weight);
-
- if (arc->bcount > 0) {
- for (i = 0; i < arc->bcount; i++) {
- arc->buckets[i].val = start + i;
- }
- }
-}
-
-static void interpolateBuckets(ReebArc *arc, float *start_p, float *end_p, int start_index, int end_index)
-{
- int total;
- int j;
-
- total = end_index - start_index + 2;
-
- for (j = start_index; j <= end_index; j++) {
- EmbedBucket *empty = arc->buckets + j;
- empty->nv = 1;
- interp_v3_v3v3(empty->p, start_p, end_p, (float)(j - start_index + 1) / total);
- }
-}
-
-static void fillArcEmptyBuckets(ReebArc *arc)
-{
- float *start_p, *end_p;
- int start_index = 0, end_index = 0;
- int missing = 0;
- int i;
-
- start_p = arc->head->p;
-
- for (i = 0; i < arc->bcount; i++) {
- EmbedBucket *bucket = arc->buckets + i;
-
- if (missing) {
- if (bucket->nv > 0) {
- missing = 0;
-
- end_p = bucket->p;
- end_index = i - 1;
-
- interpolateBuckets(arc, start_p, end_p, start_index, end_index);
- }
- }
- else {
- if (bucket->nv == 0) {
- missing = 1;
-
- if (i > 0) {
- start_p = arc->buckets[i - 1].p;
- }
- start_index = i;
- }
- }
- }
-
- if (missing) {
- end_p = arc->tail->p;
- end_index = arc->bcount - 1;
-
- interpolateBuckets(arc, start_p, end_p, start_index, end_index);
- }
-}
-
-static void ExtendArcBuckets(ReebArc *arc)
-{
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- EmbedBucket *last_bucket, *first_bucket;
- float *previous = NULL;
- float average_length = 0, length;
- int padding_head = 0, padding_tail = 0;
-
- if (arc->bcount == 0) {
- return; /* failsafe, shouldn't happen */
- }
-
- initArcIterator(iter, arc, arc->head);
- IT_next(iter);
- previous = iter->p;
-
- for (IT_next(iter);
- IT_stopped(iter) == 0;
- previous = iter->p, IT_next(iter)
- )
- {
- average_length += len_v3v3(previous, iter->p);
- }
- average_length /= (arc->bcount - 1);
-
- first_bucket = arc->buckets;
- last_bucket = arc->buckets + (arc->bcount - 1);
-
- length = len_v3v3(first_bucket->p, arc->head->p);
- if (length > 2 * average_length) {
- padding_head = (int)floor(length / average_length);
- }
-
- length = len_v3v3(last_bucket->p, arc->tail->p);
- if (length > 2 * average_length) {
- padding_tail = (int)floor(length / average_length);
- }
-
- if (padding_head + padding_tail > 0) {
- EmbedBucket *old_buckets = arc->buckets;
-
- arc->buckets = MEM_callocN(sizeof(EmbedBucket) * (padding_head + arc->bcount + padding_tail), "embed bucket");
- memcpy(arc->buckets + padding_head, old_buckets, arc->bcount * sizeof(EmbedBucket));
-
- arc->bcount = padding_head + arc->bcount + padding_tail;
-
- MEM_freeN(old_buckets);
- }
-
- if (padding_head > 0) {
- interpolateBuckets(arc, arc->head->p, first_bucket->p, 0, padding_head);
- }
-
- if (padding_tail > 0) {
- interpolateBuckets(arc, last_bucket->p, arc->tail->p, arc->bcount - padding_tail, arc->bcount - 1);
- }
-}
-
-/* CALL THIS ONLY AFTER FILTERING, SINCE IT MESSES UP WEIGHT DISTRIBUTION */
-static void extendGraphBuckets(ReebGraph *rg)
-{
- ReebArc *arc;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- ExtendArcBuckets(arc);
- }
-}
-
-/**************************************** LENGTH CALCULATIONS ****************************************/
-
-static void calculateArcLength(ReebArc *arc)
-{
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- float *vec0, *vec1;
-
- arc->length = 0;
-
- initArcIterator(iter, arc, arc->head);
-
- vec0 = arc->head->p;
- vec1 = arc->head->p; /* in case there's no embedding */
-
- while (IT_next(iter)) {
- vec1 = iter->p;
-
- arc->length += len_v3v3(vec0, vec1);
-
- vec0 = vec1;
- }
-
- arc->length += len_v3v3(arc->tail->p, vec1);
-}
-
-static void calculateGraphLength(ReebGraph *rg)
-{
- ReebArc *arc;
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- calculateArcLength(arc);
- }
-}
-#endif
-
-/**************************************** SYMMETRY HANDLING ******************************************/
-
-void REEB_RadialSymmetry(BNode *root_node, RadialArc *ring, int count)
-{
- ReebNode *node = (ReebNode *)root_node;
- float axis[3];
- int i;
-
- copy_v3_v3(axis, root_node->symmetry_axis);
-
- /* first pass, merge incrementally */
- for (i = 0; i < count - 1; i++) {
- ReebNode *node1, *node2;
- ReebArc *arc1, *arc2;
- float tangent[3];
- float normal[3];
- int j = i + 1;
-
- add_v3_v3v3(tangent, ring[i].n, ring[j].n);
- cross_v3_v3v3(normal, tangent, axis);
-
- node1 = (ReebNode *)BLI_otherNode(ring[i].arc, root_node);
- node2 = (ReebNode *)BLI_otherNode(ring[j].arc, root_node);
-
- arc1 = (ReebArc *)ring[i].arc;
- arc2 = (ReebArc *)ring[j].arc;
-
- /* mirror first node and mix with the second */
- BLI_mirrorAlongAxis(node1->p, root_node->p, normal);
- interp_v3_v3v3(node2->p, node2->p, node1->p, 1.0f / (j + 1));
-
- /* Merge buckets
- * there shouldn't be any null arcs here, but just to be safe
- * */
- if (arc1->bcount > 0 && arc2->bcount > 0) {
- ReebArcIterator arc_iter1, arc_iter2;
- BArcIterator *iter1 = (BArcIterator *)&arc_iter1;
- BArcIterator *iter2 = (BArcIterator *)&arc_iter2;
- EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
-
- initArcIterator(iter1, arc1, (ReebNode *)root_node);
- initArcIterator(iter2, arc2, (ReebNode *)root_node);
-
- bucket1 = IT_next(iter1);
- bucket2 = IT_next(iter2);
-
- /* Make sure they both start at the same value */
- while (bucket1 && bucket2 && bucket1->val < bucket2->val) {
- bucket1 = IT_next(iter1);
- }
-
- while (bucket1 && bucket2 && bucket2->val < bucket1->val) {
- bucket2 = IT_next(iter2);
- }
-
-
- for (; bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) {
- bucket2->nv += bucket1->nv; /* add counts */
-
- /* mirror on axis */
- BLI_mirrorAlongAxis(bucket1->p, root_node->p, normal);
- /* add bucket2 in bucket1 */
- interp_v3_v3v3(bucket2->p, bucket2->p, bucket1->p, (float)bucket1->nv / (float)(bucket2->nv));
- }
- }
- }
-
- /* second pass, mirror back on previous arcs */
- for (i = count - 1; i > 0; i--) {
- ReebNode *node1, *node2;
- ReebArc *arc1, *arc2;
- float tangent[3];
- float normal[3];
- int j = i - 1;
-
- add_v3_v3v3(tangent, ring[i].n, ring[j].n);
- cross_v3_v3v3(normal, tangent, axis);
-
- node1 = (ReebNode *)BLI_otherNode(ring[i].arc, root_node);
- node2 = (ReebNode *)BLI_otherNode(ring[j].arc, root_node);
-
- arc1 = (ReebArc *)ring[i].arc;
- arc2 = (ReebArc *)ring[j].arc;
-
- /* copy first node than mirror */
- copy_v3_v3(node2->p, node1->p);
- BLI_mirrorAlongAxis(node2->p, root_node->p, normal);
-
- /* Copy buckets
- * there shouldn't be any null arcs here, but just to be safe
- * */
- if (arc1->bcount > 0 && arc2->bcount > 0) {
- ReebArcIterator arc_iter1, arc_iter2;
- BArcIterator *iter1 = (BArcIterator *)&arc_iter1;
- BArcIterator *iter2 = (BArcIterator *)&arc_iter2;
- EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
-
- initArcIterator(iter1, arc1, node);
- initArcIterator(iter2, arc2, node);
-
- bucket1 = IT_next(iter1);
- bucket2 = IT_next(iter2);
-
- /* Make sure they both start at the same value */
- while (bucket1 && bucket1->val < bucket2->val) {
- bucket1 = IT_next(iter1);
- }
-
- while (bucket2 && bucket2->val < bucket1->val) {
- bucket2 = IT_next(iter2);
- }
-
-
- for (; bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) {
- /* copy and mirror back to bucket2 */
- bucket2->nv = bucket1->nv;
- copy_v3_v3(bucket2->p, bucket1->p);
- BLI_mirrorAlongAxis(bucket2->p, node->p, normal);
- }
- }
- }
-}
-
-void REEB_AxialSymmetry(BNode *root_node, BNode *node1, BNode *node2, struct BArc *barc1, BArc *barc2)
-{
- ReebArc *arc1, *arc2;
- float nor[3], p[3];
-
- arc1 = (ReebArc *)barc1;
- arc2 = (ReebArc *)barc2;
-
- copy_v3_v3(nor, root_node->symmetry_axis);
-
- /* mirror node2 along axis */
- copy_v3_v3(p, node2->p);
- BLI_mirrorAlongAxis(p, root_node->p, nor);
-
- /* average with node1 */
- add_v3_v3(node1->p, p);
- mul_v3_fl(node1->p, 0.5f);
-
- /* mirror back on node2 */
- copy_v3_v3(node2->p, node1->p);
- BLI_mirrorAlongAxis(node2->p, root_node->p, nor);
-
- /* Merge buckets
- * there shouldn't be any null arcs here, but just to be safe
- * */
- if (arc1->bcount > 0 && arc2->bcount > 0) {
- ReebArcIterator arc_iter1, arc_iter2;
- BArcIterator *iter1 = (BArcIterator *)&arc_iter1;
- BArcIterator *iter2 = (BArcIterator *)&arc_iter2;
- EmbedBucket *bucket1 = NULL, *bucket2 = NULL;
-
- initArcIterator(iter1, arc1, (ReebNode *)root_node);
- initArcIterator(iter2, arc2, (ReebNode *)root_node);
-
- bucket1 = IT_next(iter1);
- bucket2 = IT_next(iter2);
-
- /* Make sure they both start at the same value */
- while (bucket1 && bucket1->val < bucket2->val) {
- bucket1 = IT_next(iter1);
- }
-
- while (bucket2 && bucket2->val < bucket1->val) {
- bucket2 = IT_next(iter2);
- }
-
-
- for (; bucket1 && bucket2; bucket1 = IT_next(iter1), bucket2 = IT_next(iter2)) {
- bucket1->nv += bucket2->nv; /* add counts */
-
- /* mirror on axis */
- BLI_mirrorAlongAxis(bucket2->p, root_node->p, nor);
- /* add bucket2 in bucket1 */
- interp_v3_v3v3(bucket1->p, bucket1->p, bucket2->p, (float)bucket2->nv / (float)(bucket1->nv));
-
- /* copy and mirror back to bucket2 */
- bucket2->nv = bucket1->nv;
- copy_v3_v3(bucket2->p, bucket1->p);
- BLI_mirrorAlongAxis(bucket2->p, root_node->p, nor);
- }
- }
-}
-
-/************************************** ADJACENCY LIST *************************************************/
-
-
-/****************************************** SMOOTHING **************************************************/
-
-#if 0 /* UNUSED */
-void postprocessGraph(ReebGraph *rg, char mode)
-{
- ReebArc *arc;
- float fac1 = 0, fac2 = 1, fac3 = 0;
-
- switch (mode)
- {
- case SKGEN_AVERAGE:
- fac1 = fac2 = fac3 = 1.0f / 3.0f;
- break;
- case SKGEN_SMOOTH:
- fac1 = fac3 = 0.25f;
- fac2 = 0.5f;
- break;
- case SKGEN_SHARPEN:
- fac1 = fac3 = -0.25f;
- fac2 = 1.5f;
- break;
- default:
-// XXX
-// error("Unknown post processing mode");
- return;
- }
-
- for (arc = rg->arcs.first; arc; arc = arc->next)
- {
- EmbedBucket *buckets = arc->buckets;
- int bcount = arc->bcount;
- int index;
-
- for (index = 1; index < bcount - 1; index++)
- {
- interp_v3_v3v3(buckets[index].p, buckets[index].p, buckets[index - 1].p, fac1 / (fac1 + fac2));
- interp_v3_v3v3(buckets[index].p, buckets[index].p, buckets[index + 1].p, fac3 / (fac1 + fac2 + fac3));
- }
- }
-}
-
-/********************************************SORTING****************************************************/
-
-static int compareNodesWeight(void *vnode1, void *vnode2)
-{
- ReebNode *node1 = (ReebNode *)vnode1;
- ReebNode *node2 = (ReebNode *)vnode2;
-
- if (node1->weight < node2->weight)
- {
- return -1;
- }
- if (node1->weight > node2->weight)
- {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-void sortNodes(ReebGraph *rg)
-{
- BLI_listbase_sort(&rg->nodes, compareNodesWeight);
-}
-
-static int compareArcsWeight(void *varc1, void *varc2)
-{
- ReebArc *arc1 = (ReebArc *)varc1;
- ReebArc *arc2 = (ReebArc *)varc2;
- ReebNode *node1 = (ReebNode *)arc1->head;
- ReebNode *node2 = (ReebNode *)arc2->head;
-
- if (node1->weight < node2->weight)
- {
- return -1;
- }
- if (node1->weight > node2->weight)
- {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-void sortArcs(ReebGraph *rg)
-{
- BLI_listbase_sort(&rg->arcs, compareArcsWeight);
-}
-/******************************************* JOINING ***************************************************/
-
-static void reweightArc(ReebGraph *rg, ReebArc *arc, ReebNode *start_node, float start_weight)
-{
- ReebNode *node;
- float old_weight;
- float end_weight = start_weight + ABS(arc->tail->weight - arc->head->weight);
- int i;
-
- node = (ReebNode *)BLI_otherNode((BArc *)arc, (BNode *)start_node);
-
- /* prevent backtracking */
- if (node->flag == 1)
- {
- return;
- }
-
- if (arc->tail == start_node)
- {
- flipArc(arc);
- }
-
- start_node->flag = 1;
-
- for (i = 0; i < node->degree; i++)
- {
- ReebArc *next_arc = node->arcs[i];
-
- reweightArc(rg, next_arc, node, end_weight);
- }
-
- /* update only if needed */
- if (arc->head->weight != start_weight || arc->tail->weight != end_weight)
- {
- old_weight = arc->head->weight; /* backup head weight, other arcs need it intact, it will be fixed by the source arc */
-
- arc->head->weight = start_weight;
- arc->tail->weight = end_weight;
-
- reweightBuckets(arc);
- resizeArcBuckets(arc);
- fillArcEmptyBuckets(arc);
-
- arc->head->weight = old_weight;
- }
-}
-
-static void reweightSubgraph(ReebGraph *rg, ReebNode *start_node, float start_weight)
-{
- int i;
-
- BLI_flagNodes((BGraph *)rg, 0);
-
- for (i = 0; i < start_node->degree; i++)
- {
- ReebArc *next_arc = start_node->arcs[i];
-
- reweightArc(rg, next_arc, start_node, start_weight);
- }
- start_node->weight = start_weight;
-}
-
-static int joinSubgraphsEnds(ReebGraph *rg, float threshold, int nb_subgraphs)
-{
- int joined = 0;
- int subgraph;
-
- for (subgraph = 1; subgraph <= nb_subgraphs; subgraph++)
- {
- ReebNode *start_node, *end_node;
- ReebNode *min_node_start = NULL, *min_node_end = NULL;
- float min_distance = FLT_MAX;
-
- for (start_node = rg->nodes.first; start_node; start_node = start_node->next)
- {
- if (start_node->subgraph_index == subgraph && start_node->degree == 1)
- {
-
- for (end_node = rg->nodes.first; end_node; end_node = end_node->next)
- {
- if (end_node->subgraph_index != subgraph)
- {
- float distance = len_v3v3(start_node->p, end_node->p);
-
- if (distance < threshold && distance < min_distance)
- {
- min_distance = distance;
- min_node_end = end_node;
- min_node_start = start_node;
- }
- }
- }
- }
- }
-
- end_node = min_node_end;
- start_node = min_node_start;
-
- if (end_node && start_node)
- {
- ReebArc *start_arc /* , *end_arc */ /* UNUSED */;
- int merging = 0;
-
- start_arc = start_node->arcs[0];
- /* end_arc = end_node->arcs[0]; */ /* UNUSED */
-
- if (start_arc->tail == start_node)
- {
- reweightSubgraph(rg, end_node, start_node->weight);
-
- start_arc->tail = end_node;
-
- merging = 1;
- }
- else if (start_arc->head == start_node)
- {
- reweightSubgraph(rg, start_node, end_node->weight);
-
- start_arc->head = end_node;
-
- merging = 2;
- }
-
- if (merging)
- {
- BLI_ReflagSubgraph((BGraph *)rg, end_node->flag, subgraph);
-
- resizeArcBuckets(start_arc);
- fillArcEmptyBuckets(start_arc);
-
- NodeDegreeIncrement(rg, end_node);
- BLI_rebuildAdjacencyListForNode((BGraph *)rg, (BNode *)end_node);
-
- BLI_removeNode((BGraph *)rg, (BNode *)start_node);
- }
-
- joined = 1;
- }
- }
-
- return joined;
-}
-
-/* Reweight graph from smallest node, fix fliped arcs */
-static void fixSubgraphsOrientation(ReebGraph *rg, int nb_subgraphs)
-{
- int subgraph;
-
- for (subgraph = 1; subgraph <= nb_subgraphs; subgraph++)
- {
- ReebNode *node;
- ReebNode *start_node = NULL;
-
- for (node = rg->nodes.first; node; node = node->next)
- {
- if (node->subgraph_index == subgraph)
- {
- if (start_node == NULL || node->weight < start_node->weight)
- {
- start_node = node;
- }
- }
- }
-
- if (start_node)
- {
- reweightSubgraph(rg, start_node, start_node->weight);
- }
- }
-}
-
-static int joinSubgraphs(ReebGraph *rg, float threshold)
-{
- int nb_subgraphs;
- int joined = 0;
-
- BLI_buildAdjacencyList((BGraph *)rg);
-
- if (BLI_isGraphCyclic((BGraph *)rg)) {
- /* don't deal with cyclic graphs YET */
- return 0;
- }
-
- /* sort nodes before flagging subgraphs to make sure root node is subgraph 0 */
- sortNodes(rg);
-
- nb_subgraphs = BLI_FlagSubgraphs((BGraph *)rg);
-
- /* Harmonic function can create flipped arcs, take the occasion to fix them */
-// XXX
-// if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC)
-// {
- fixSubgraphsOrientation(rg, nb_subgraphs);
-// }
-
- if (nb_subgraphs > 1)
- {
- joined |= joinSubgraphsEnds(rg, threshold, nb_subgraphs);
-
- if (joined)
- {
- removeNormalNodes(rg);
- BLI_buildAdjacencyList((BGraph *)rg);
- }
- }
-
- return joined;
-}
-
-/****************************************** FILTERING **************************************************/
-
-static float lengthArc(ReebArc *arc)
-{
-#if 0
- ReebNode *head = (ReebNode *)arc->head;
- ReebNode *tail = (ReebNode *)arc->tail;
-
- return tail->weight - head->weight;
-#else
- return arc->length;
-#endif
-}
-
-static int compareArcs(void *varc1, void *varc2)
-{
- ReebArc *arc1 = (ReebArc *)varc1;
- ReebArc *arc2 = (ReebArc *)varc2;
- float len1 = lengthArc(arc1);
- float len2 = lengthArc(arc2);
-
- if (len1 < len2) {
- return -1;
- }
- if (len1 > len2) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static void filterArc(ReebGraph *rg, ReebNode *newNode, ReebNode *removedNode, ReebArc *srcArc, int merging)
-{
- ReebArc *arc = NULL, *nextArc = NULL;
-
- if (merging) {
- /* first pass, merge buckets for arcs that spawned the two nodes into the source arc*/
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- if (arc->head == srcArc->head && arc->tail == srcArc->tail && arc != srcArc) {
- ReebNode *head = srcArc->head;
- ReebNode *tail = srcArc->tail;
- mergeArcBuckets(srcArc, arc, head->weight, tail->weight);
- }
- }
- }
-
- /* second pass, replace removedNode by newNode, remove arcs that are collapsed in a loop */
- arc = rg->arcs.first;
- while (arc) {
- nextArc = arc->next;
-
- if (arc->head == removedNode || arc->tail == removedNode) {
- if (arc->head == removedNode) {
- arc->head = newNode;
- }
- else {
- arc->tail = newNode;
- }
-
- // Remove looped arcs
- if (arc->head == arc->tail) {
- // v1 or v2 was already newNode, since we're removing an arc, decrement degree
- NodeDegreeDecrement(rg, newNode);
-
- // If it's srcArc, it'll be removed later, so keep it for now
- if (arc != srcArc) {
- BLI_remlink(&rg->arcs, arc);
- REEB_freeArc((BArc *)arc);
- }
- }
- else {
- /* flip arcs that flipped, can happen on diamond shapes, mostly on null arcs */
- if (arc->head->weight > arc->tail->weight) {
- flipArc(arc);
- }
- //newNode->degree++; // incrementing degree since we're adding an arc
- NodeDegreeIncrement(rg, newNode);
- mergeArcFaces(rg, arc, srcArc);
-
- if (merging) {
- ReebNode *head = arc->head;
- ReebNode *tail = arc->tail;
-
- // resize bucket list
- resizeArcBuckets(arc);
- mergeArcBuckets(arc, srcArc, head->weight, tail->weight);
-
- /* update length */
- arc->length += srcArc->length;
- }
- }
- }
-
- arc = nextArc;
- }
-}
-
-void filterNullReebGraph(ReebGraph *rg)
-{
- ReebArc *arc = NULL, *nextArc = NULL;
-
- arc = rg->arcs.first;
- while (arc) {
- nextArc = arc->next;
- // Only collapse arcs too short to have any embed bucket
- if (arc->bcount == 0) {
- ReebNode *newNode = (ReebNode *)arc->head;
- ReebNode *removedNode = (ReebNode *)arc->tail;
- float blend;
-
- blend = (float)newNode->degree / (float)(newNode->degree + removedNode->degree); // blending factors
-
- interp_v3_v3v3(newNode->p, removedNode->p, newNode->p, blend);
-
- filterArc(rg, newNode, removedNode, arc, 0);
-
- // Reset nextArc, it might have changed
- nextArc = arc->next;
-
- BLI_remlink(&rg->arcs, arc);
- REEB_freeArc((BArc *)arc);
-
- BLI_removeNode((BGraph *)rg, (BNode *)removedNode);
- }
-
- arc = nextArc;
- }
-}
-
-static int filterInternalExternalReebGraph(ReebGraph *rg, float threshold_internal, float threshold_external)
-{
- ReebArc *arc = NULL, *nextArc = NULL;
- int value = 0;
-
- BLI_listbase_sort(&rg->arcs, compareArcs);
-
- for (arc = rg->arcs.first; arc; arc = nextArc) {
- nextArc = arc->next;
-
- /* Only collapse non-terminal arcs that are shorter than threshold */
- if ((threshold_internal > 0) &&
- (arc->head->degree > 1) &&
- (arc->tail->degree > 1) &&
- (lengthArc(arc) < threshold_internal))
- {
- ReebNode *newNode = NULL;
- ReebNode *removedNode = NULL;
-
- /* Always remove lower node, so arcs don't flip */
- newNode = arc->head;
- removedNode = arc->tail;
-
- filterArc(rg, newNode, removedNode, arc, 1);
-
- // Reset nextArc, it might have changed
- nextArc = arc->next;
-
- BLI_remlink(&rg->arcs, arc);
- REEB_freeArc((BArc *)arc);
-
- BLI_removeNode((BGraph *)rg, (BNode *)removedNode);
- value = 1;
- }
-
- // Only collapse terminal arcs that are shorter than threshold
- else if ((threshold_external > 0) &&
- (arc->head->degree == 1 || arc->tail->degree == 1) &&
- (lengthArc(arc) < threshold_external))
- {
- ReebNode *terminalNode = NULL;
- ReebNode *middleNode = NULL;
- ReebNode *removedNode = NULL;
-
- // Assign terminal and middle nodes
- if (arc->head->degree == 1) {
- terminalNode = arc->head;
- middleNode = arc->tail;
- }
- else {
- terminalNode = arc->tail;
- middleNode = arc->head;
- }
-
- if (middleNode->degree == 2 && middleNode != rg->nodes.first) {
-#if 1
- // If middle node is a normal node, it will be removed later
- // Only if middle node is not the root node
- /* USE THIS IF YOU WANT TO PROLONG ARCS TO THEIR TERMINAL NODES
- * FOR HANDS, THIS IS NOT THE BEST RESULT
- * */
- continue;
-#else
- removedNode = terminalNode;
-
- // removing arc, so we need to decrease the degree of the remaining node
- NodeDegreeDecrement(rg, middleNode);
-#endif
- }
- // Otherwise, just plain remove of the arc
- else {
- removedNode = terminalNode;
-
- // removing arc, so we need to decrease the degree of the remaining node
- NodeDegreeDecrement(rg, middleNode);
- }
-
- // Reset nextArc, it might have changed
- nextArc = arc->next;
-
- BLI_remlink(&rg->arcs, arc);
- REEB_freeArc((BArc *)arc);
-
- BLI_removeNode((BGraph *)rg, (BNode *)removedNode);
- value = 1;
- }
- }
-
- return value;
-}
-
-static int filterCyclesReebGraph(ReebGraph *rg, float UNUSED(distance_threshold))
-{
- ReebArc *arc1, *arc2;
- ReebArc *next2;
- int filtered = 0;
-
- for (arc1 = rg->arcs.first; arc1; arc1 = arc1->next) {
- for (arc2 = arc1->next; arc2; arc2 = next2) {
- next2 = arc2->next;
- if (arc1 != arc2 && arc1->head == arc2->head && arc1->tail == arc2->tail) {
- mergeArcEdges(rg, arc1, arc2, MERGE_APPEND);
- mergeArcFaces(rg, arc1, arc2);
- mergeArcBuckets(arc1, arc2, arc1->head->weight, arc1->tail->weight);
-
- NodeDegreeDecrement(rg, arc1->head);
- NodeDegreeDecrement(rg, arc1->tail);
-
- BLI_remlink(&rg->arcs, arc2);
- REEB_freeArc((BArc *)arc2);
-
- filtered = 1;
- }
- }
- }
-
- return filtered;
-}
-
-int filterSmartReebGraph(ReebGraph *UNUSED(rg), float UNUSED(threshold))
-{
- int value = 0;
-#if 0 //XXX
- ReebArc *arc = NULL, *nextArc = NULL;
-
- BLI_listbase_sort(&rg->arcs, compareArcs);
-
-#ifdef DEBUG_REEB
- {
- EditFace *efa;
- for (efa = G.editMesh->faces.first; efa; efa = efa->next) {
- efa->tmp.fp = -1;
- }
- }
-#endif
-
- arc = rg->arcs.first;
- while (arc)
- {
- nextArc = arc->next;
-
- /* need correct normals and center */
- recalc_editnormals();
-
- // Only test terminal arcs
- if (arc->head->degree == 1 || arc->tail->degree == 1)
- {
- GHashIterator ghi;
- int merging = 0;
- int total = BLI_ghash_len(arc->faces);
- float avg_angle = 0;
- float avg_vec[3] = {0, 0, 0};
-
- for (BLI_ghashIterator_init(&ghi, arc->faces);
- BLI_ghashIterator_done(&ghi) == false;
- BLI_ghashIterator_step(&ghi))
- {
- EditFace *efa = BLI_ghashIterator_getValue(&ghi);
-
-#if 0
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- EmbedBucket *bucket = NULL;
- EmbedBucket *previous = NULL;
- float min_distance = -1;
- float angle = 0;
-
- initArcIterator(iter, arc, arc->head);
-
- bucket = nextBucket(iter);
-
- while (bucket != NULL)
- {
- float *vec0 = NULL;
- float *vec1 = bucket->p;
- float midpoint[3], tangent[3];
- float distance;
-
- /* first bucket. Previous is head */
- if (previous == NULL)
- {
- vec0 = arc->head->p;
- }
- /* Previous is a valid bucket */
- else {
- vec0 = previous->p;
- }
-
- copy_v3_v3(midpoint, vec1);
-
- distance = len_v3v3(midpoint, efa->cent);
-
- if (min_distance == -1 || distance < min_distance)
- {
- min_distance = distance;
-
- sub_v3_v3v3(tangent, vec1, vec0);
- normalize_v3(tangent);
-
- angle = dot_v3v3(tangent, efa->n);
- }
-
- previous = bucket;
- bucket = nextBucket(iter);
- }
-
- avg_angle += saacos(fabs(angle));
-#ifdef DEBUG_REEB
- efa->tmp.fp = saacos(fabs(angle));
-#endif
-#else
- add_v3_v3(avg_vec, efa->n);
-#endif
- }
-
-
-#if 0
- avg_angle /= total;
-#else
- mul_v3_fl(avg_vec, 1.0 / total);
- avg_angle = dot_v3v3(avg_vec, avg_vec);
-#endif
-
- arc->angle = avg_angle;
-
- if (avg_angle > threshold)
- merging = 1;
-
- if (merging) {
- ReebNode *terminalNode = NULL;
- ReebNode *middleNode = NULL;
- ReebNode *newNode = NULL;
- ReebNode *removedNode = NULL;
- int merging = 0;
-
- /* Assign terminal and middle nodes */
- if (arc->head->degree == 1) {
- terminalNode = arc->head;
- middleNode = arc->tail;
- }
- else {
- terminalNode = arc->tail;
- middleNode = arc->head;
- }
-
- /* If middle node is a normal node, merge to terminal node */
- if (middleNode->degree == 2) {
- merging = 1;
- newNode = terminalNode;
- removedNode = middleNode;
- }
- /* Otherwise, just plain remove of the arc */
- else {
- merging = 0;
- newNode = middleNode;
- removedNode = terminalNode;
- }
-
- /* Merging arc */
- if (merging) {
- filterArc(rg, newNode, removedNode, arc, 1);
- }
- else {
- /* removing arc, so we need to decrease the degree of the remaining node
- *newNode->degree--; */
- NodeDegreeDecrement(rg, newNode);
- }
-
- /* Reset nextArc, it might have changed */
- nextArc = arc->next;
-
- BLI_remlink(&rg->arcs, arc);
- REEB_freeArc((BArc *)arc);
-
- BLI_freelinkN(&rg->nodes, removedNode);
- value = 1;
- }
- }
-
- arc = nextArc;
- }
-
-#endif
-
- return value;
-}
-
-static void filterGraph(ReebGraph *rg, short options, float threshold_internal, float threshold_external)
-{
- bool done = true;
-
- calculateGraphLength(rg);
-
- if ((options & SKGEN_FILTER_EXTERNAL) == 0) {
- threshold_external = 0;
- }
-
- if ((options & SKGEN_FILTER_INTERNAL) == 0) {
- threshold_internal = 0;
- }
-
- if (threshold_internal > 0 || threshold_external > 0) {
- /* filter until there's nothing more to do */
- while (done == true) {
- done = false; /* no work done yet */
-
- done = filterInternalExternalReebGraph(rg, threshold_internal, threshold_external);
- }
- }
-
- if (options & SKGEN_FILTER_SMART) {
- filterSmartReebGraph(rg, 0.5);
- filterCyclesReebGraph(rg, 0.5);
- }
-
- repositionNodes(rg);
-
- /* Filtering might have created degree 2 nodes, so remove them */
- removeNormalNodes(rg);
-}
-
-static void finalizeGraph(ReebGraph *rg, char passes, char method)
-{
- int i;
-
- BLI_buildAdjacencyList((BGraph *)rg);
-
- sortNodes(rg);
-
- sortArcs(rg);
-
- for (i = 0; i < passes; i++) {
- postprocessGraph(rg, method);
- }
-
- extendGraphBuckets(rg);
-}
-
-/************************************** WEIGHT SPREADING ***********************************************/
-
-static int compareVerts(const void *a, const void *b)
-{
- EditVert *va = *(EditVert **)a;
- EditVert *vb = *(EditVert **)b;
- int value = 0;
-
- if (weightData(va) < weightData(vb)) {
- value = -1;
- }
- else if (weightData(va) > weightData(vb)) {
- value = 1;
- }
-
- return value;
-}
-
-static void spreadWeight(EditMesh *em)
-{
- EditVert **verts, *eve;
- float lastWeight = 0.0f;
- int totvert = BLI_listbase_count(&em->verts);
- int i;
- int work_needed = 1;
-
- verts = MEM_callocN(sizeof(EditVert *) * totvert, "verts array");
-
- for (eve = em->verts.first, i = 0; eve; eve = eve->next, i++) {
- verts[i] = eve;
- }
-
- while (work_needed == 1) {
- work_needed = 0;
- qsort(verts, totvert, sizeof(EditVert *), compareVerts);
-
- for (i = 0; i < totvert; i++) {
- eve = verts[i];
-
- if (i == 0 || (weightData(eve) - lastWeight) > FLT_EPSILON) {
- lastWeight = weightData(eve);
- }
- else {
- work_needed = 1;
- weightSetData(eve, lastWeight + FLT_EPSILON * 2);
- lastWeight = weightData(eve);
- }
- }
- }
-
- MEM_freeN(verts);
-}
-
-/******************************************** EXPORT ***************************************************/
-
-static void exportNode(FILE *f, const char *text, ReebNode *node)
-{
- fprintf(f, "%s i:%i w:%f d:%i %f %f %f\n", text, node->index, node->weight, node->degree, node->p[0], node->p[1], node->p[2]);
-}
-
-void REEB_exportGraph(ReebGraph *rg, int count)
-{
- ReebArc *arc;
- char filename[128];
- FILE *f;
-
- if (count == -1) {
- strcpy(filename, "test.txt");
- }
- else {
- sprintf(filename, "test%05i.txt", count);
- }
- f = BLI_fopen(filename, "w");
-
- for (arc = rg->arcs.first; arc; arc = arc->next) {
- int i;
- float p[3];
-
- exportNode(f, "v1", arc->head);
-
- for (i = 0; i < arc->bcount; i++) {
- fprintf(f, "b nv:%i %f %f %f\n", arc->buckets[i].nv, arc->buckets[i].p[0], arc->buckets[i].p[1], arc->buckets[i].p[2]);
- }
-
- add_v3_v3v3(p, arc->tail->p, arc->head->p);
- mul_v3_fl(p, 0.5f);
-
- fprintf(f, "angle %0.3f %0.3f %0.3f %0.3f %i\n", p[0], p[1], p[2], arc->angle, BLI_ghash_len(arc->faces));
- exportNode(f, "v2", arc->tail);
- }
-
- fclose(f);
-}
-
-/***************************************** MAIN ALGORITHM **********************************************/
-
-/* edges alone will create zero degree nodes, use this function to remove them */
-static void removeZeroNodes(ReebGraph *rg)
-{
- ReebNode *node, *next_node;
-
- for (node = rg->nodes.first; node; node = next_node) {
- next_node = node->next;
-
- if (node->degree == 0) {
- BLI_removeNode((BGraph *)rg, (BNode *)node);
- }
- }
-}
-
-void removeNormalNodes(ReebGraph *rg)
-{
- ReebArc *arc, *nextArc;
-
- // Merge degree 2 nodes
- for (arc = rg->arcs.first; arc; arc = nextArc) {
- nextArc = arc->next;
-
- while (arc->head->degree == 2 || arc->tail->degree == 2) {
- // merge at v1
- if (arc->head->degree == 2) {
- ReebArc *connectedArc = (ReebArc *)BLI_findConnectedArc((BGraph *)rg, (BArc *)arc, (BNode *)arc->head);
-
- /* If arcs are one after the other */
- if (arc->head == connectedArc->tail) {
- /* remove furthest arc */
- if (arc->tail->weight < connectedArc->head->weight) {
- mergeConnectedArcs(rg, arc, connectedArc);
- nextArc = arc->next;
- }
- else {
- mergeConnectedArcs(rg, connectedArc, arc);
- break; /* arc was removed, move to next */
- }
- }
- /* Otherwise, arcs are side by side */
- else {
- /* Don't do anything, we need to keep the lowest node, even if degree 2 */
- break;
- }
- }
-
- /* merge at v2 */
- if (arc->tail->degree == 2) {
- ReebArc *connectedArc = (ReebArc *)BLI_findConnectedArc((BGraph *)rg, (BArc *)arc, (BNode *)arc->tail);
-
- /* If arcs are one after the other */
- if (arc->tail == connectedArc->head) {
- /* remove furthest arc */
- if (arc->head->weight < connectedArc->tail->weight) {
- mergeConnectedArcs(rg, arc, connectedArc);
- nextArc = arc->next;
- }
- else {
- mergeConnectedArcs(rg, connectedArc, arc);
- break; /* arc was removed, move to next */
- }
- }
- /* Otherwise, arcs are side by side */
- else {
- /* Don't do anything, we need to keep the lowest node, even if degree 2 */
- break;
- }
- }
- }
- }
-
-}
-
-static int edgeEquals(ReebEdge *e1, ReebEdge *e2)
-{
- return (e1->v1 == e2->v1 && e1->v2 == e2->v2);
-}
-
-static ReebArc *nextArcMappedToEdge(ReebArc *arc, ReebEdge *e)
-{
- ReebEdge *nextEdge = NULL;
- ReebEdge *edge = NULL;
- ReebArc *result = NULL;
-
- /* Find the ReebEdge in the edge list */
- for (edge = arc->edges.first; edge && !edgeEquals(edge, e); edge = edge->next) { }
-
- nextEdge = edge->nextEdge;
-
- if (nextEdge != NULL) {
- result = nextEdge->arc;
- }
-
- return result;
-}
-
-void addFacetoArc(ReebArc *arc, EditFace *efa)
-{
- BLI_ghash_insert(arc->faces, efa, efa);
-}
-
-void mergeArcFaces(ReebGraph *UNUSED(rg), ReebArc *aDst, ReebArc *aSrc)
-{
- GHashIterator ghi;
-
- for (BLI_ghashIterator_init(&ghi, aSrc->faces);
- BLI_ghashIterator_done(&ghi) == false;
- BLI_ghashIterator_step(&ghi))
- {
- EditFace *efa = BLI_ghashIterator_getValue(&ghi);
- BLI_ghash_insert(aDst->faces, efa, efa);
- }
-}
-
-void mergeArcEdges(ReebGraph *rg, ReebArc *aDst, ReebArc *aSrc, MergeDirection direction)
-{
- ReebEdge *e = NULL;
-
- if (direction == MERGE_APPEND) {
- for (e = aSrc->edges.first; e; e = e->next) {
- e->arc = aDst; // Edge is stolen by new arc
- }
-
- BLI_movelisttolist(&aDst->edges, &aSrc->edges);
- }
- else {
- for (e = aSrc->edges.first; e; e = e->next) {
- ReebEdge *newEdge = copyEdge(e);
-
- newEdge->arc = aDst;
-
- BLI_addtail(&aDst->edges, newEdge);
-
- if (direction == MERGE_LOWER) {
- void **p = BLI_edgehash_lookup_p(rg->emap, e->v1->index, e->v2->index);
-
- newEdge->nextEdge = e;
-
- // if edge was the first in the list, point the edit edge to the new reeb edge instead.
- if (*p == e) {
- *p = (void *)newEdge;
- }
- // otherwise, advance in the list until the predecessor is found then insert it there
- else {
- ReebEdge *previous = (ReebEdge *)*p;
-
- while (previous->nextEdge != e) {
- previous = previous->nextEdge;
- }
-
- previous->nextEdge = newEdge;
- }
- }
- else {
- newEdge->nextEdge = e->nextEdge;
- e->nextEdge = newEdge;
- }
- }
- }
-}
-
-// return 1 on full merge
-int mergeConnectedArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1)
-{
- int result = 0;
- ReebNode *removedNode = NULL;
-
- a0->length += a1->length;
-
- mergeArcEdges(rg, a0, a1, MERGE_APPEND);
- mergeArcFaces(rg, a0, a1);
-
- // Bring a0 to the combine length of both arcs
- if (a0->tail == a1->head) {
- removedNode = a0->tail;
- a0->tail = a1->tail;
- }
- else if (a0->head == a1->tail) {
- removedNode = a0->head;
- a0->head = a1->head;
- }
-
- resizeArcBuckets(a0);
- // Merge a1 in a0
- mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight);
-
- // remove a1 from graph
- BLI_remlink(&rg->arcs, a1);
- REEB_freeArc((BArc *)a1);
-
- BLI_removeNode((BGraph *)rg, (BNode *)removedNode);
- result = 1;
-
- return result;
-}
-// return 1 on full merge
-int mergeArcs(ReebGraph *rg, ReebArc *a0, ReebArc *a1)
-{
- int result = 0;
- /* TRIANGLE POINTS DOWN */
- if (a0->head->weight == a1->head->weight) { /* heads are the same */
- if (a0->tail->weight == a1->tail->weight) { /* tails also the same, arcs can be totally merge together */
- mergeArcEdges(rg, a0, a1, MERGE_APPEND);
- mergeArcFaces(rg, a0, a1);
-
- mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight);
-
- // Adjust node degree
- //a1->head->degree--;
- NodeDegreeDecrement(rg, a1->head);
- //a1->tail->degree--;
- NodeDegreeDecrement(rg, a1->tail);
-
- // remove a1 from graph
- BLI_remlink(&rg->arcs, a1);
-
- REEB_freeArc((BArc *)a1);
- result = 1;
- }
- else if (a0->tail->weight > a1->tail->weight) { /* a1->tail->weight is in the middle */
- mergeArcEdges(rg, a1, a0, MERGE_LOWER);
- mergeArcFaces(rg, a1, a0);
-
- // Adjust node degree
- //a0->head->degree--;
- NodeDegreeDecrement(rg, a0->head);
- //a1->tail->degree++;
- NodeDegreeIncrement(rg, a1->tail);
-
- mergeArcBuckets(a1, a0, a1->head->weight, a1->tail->weight);
- a0->head = a1->tail;
- resizeArcBuckets(a0);
- }
- else { /* a0>n2 is in the middle */
- mergeArcEdges(rg, a0, a1, MERGE_LOWER);
- mergeArcFaces(rg, a0, a1);
-
- // Adjust node degree
- //a1->head->degree--;
- NodeDegreeDecrement(rg, a1->head);
- //a0->tail->degree++;
- NodeDegreeIncrement(rg, a0->tail);
-
- mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight);
- a1->head = a0->tail;
- resizeArcBuckets(a1);
- }
- }
- /* TRIANGLE POINTS UP */
- else if (a0->tail->weight == a1->tail->weight) { /* tails are the same */
- if (a0->head->weight > a1->head->weight) { /* a0->head->weight is in the middle */
- mergeArcEdges(rg, a0, a1, MERGE_HIGHER);
- mergeArcFaces(rg, a0, a1);
-
- // Adjust node degree
- //a1->tail->degree--;
- NodeDegreeDecrement(rg, a1->tail);
- //a0->head->degree++;
- NodeDegreeIncrement(rg, a0->head);
-
- mergeArcBuckets(a0, a1, a0->head->weight, a0->tail->weight);
- a1->tail = a0->head;
- resizeArcBuckets(a1);
- }
- else { /* a1->head->weight is in the middle */
- mergeArcEdges(rg, a1, a0, MERGE_HIGHER);
- mergeArcFaces(rg, a1, a0);
-
- // Adjust node degree
- //a0->tail->degree--;
- NodeDegreeDecrement(rg, a0->tail);
- //a1->head->degree++;
- NodeDegreeIncrement(rg, a1->head);
-
- mergeArcBuckets(a1, a0, a1->head->weight, a1->tail->weight);
- a0->tail = a1->head;
- resizeArcBuckets(a0);
- }
- }
- else {
- /* Need something here (OR NOT) */
- }
-
- return result;
-}
-
-static void glueByMergeSort(ReebGraph *rg, ReebArc *a0, ReebArc *a1, ReebEdge *e0, ReebEdge *e1)
-{
- int total = 0;
- while (total == 0 && a0 != a1 && a0 != NULL && a1 != NULL) {
- total = mergeArcs(rg, a0, a1);
-
- if (total == 0) // if it wasn't a total merge, go forward {
- if (a0->tail->weight < a1->tail->weight) {
- a0 = nextArcMappedToEdge(a0, e0);
- }
- else {
- a1 = nextArcMappedToEdge(a1, e1);
- }
- }
- }
-}
-
-static void mergePaths(ReebGraph *rg, ReebEdge *e0, ReebEdge *e1, ReebEdge *e2)
-{
- ReebArc *a0, *a1, *a2;
- a0 = e0->arc;
- a1 = e1->arc;
- a2 = e2->arc;
-
- glueByMergeSort(rg, a0, a1, e0, e1);
- glueByMergeSort(rg, a0, a2, e0, e2);
-}
-
-static ReebEdge *createArc(ReebGraph *rg, ReebNode *node1, ReebNode *node2)
-{
- ReebEdge *edge;
-
- edge = BLI_edgehash_lookup(rg->emap, node1->index, node2->index);
-
- // Only add existing edges that haven't been added yet
- if (edge == NULL) {
- ReebArc *arc;
- ReebNode *v1, *v2;
- float len, offset;
- int i;
-
- arc = MEM_callocN(sizeof(ReebArc), "reeb arc");
- edge = MEM_callocN(sizeof(ReebEdge), "reeb edge");
-
- arc->flag = 0; // clear flag on init
- arc->symmetry_level = 0;
- arc->faces = BLI_ghash_ptr_new("createArc gh");
-
- if (node1->weight <= node2->weight) {
- v1 = node1;
- v2 = node2;
- }
- else {
- v1 = node2;
- v2 = node1;
- }
-
- arc->head = v1;
- arc->tail = v2;
-
- // increase node degree
- //v1->degree++;
- NodeDegreeIncrement(rg, v1);
- //v2->degree++;
- NodeDegreeIncrement(rg, v2);
-
- BLI_edgehash_insert(rg->emap, node1->index, node2->index, edge);
-
- edge->arc = arc;
- edge->nextEdge = NULL;
- edge->v1 = v1;
- edge->v2 = v2;
-
- BLI_addtail(&rg->arcs, arc);
- BLI_addtail(&arc->edges, edge);
-
- /* adding buckets for embedding */
- allocArcBuckets(arc);
-
- offset = arc->head->weight;
- len = arc->tail->weight - arc->head->weight;
-
-#if 0
- /* This is the actual embedding filling described in the paper
- * the problem is that it only works with really dense meshes
- */
- if (arc->bcount > 0)
- {
- addVertToBucket(&(arc->buckets[0]), arc->head->co);
- addVertToBucket(&(arc->buckets[arc->bcount - 1]), arc->tail->co);
- }
-#else
- for (i = 0; i < arc->bcount; i++) {
- float co[3];
- float f = (arc->buckets[i].val - offset) / len;
-
- interp_v3_v3v3(co, v1->p, v2->p, f);
- addVertToBucket(&(arc->buckets[i]), co);
- }
-#endif
-
- }
-
- return edge;
-}
-
-static void addTriangleToGraph(ReebGraph *rg, ReebNode *n1, ReebNode *n2, ReebNode *n3, EditFace *efa)
-{
- ReebEdge *re1, *re2, *re3;
- ReebEdge *e1, *e2, *e3;
- float len1, len2, len3;
-
- re1 = createArc(rg, n1, n2);
- re2 = createArc(rg, n2, n3);
- re3 = createArc(rg, n3, n1);
-
- addFacetoArc(re1->arc, efa);
- addFacetoArc(re2->arc, efa);
- addFacetoArc(re3->arc, efa);
-
- len1 = (float)fabs(n1->weight - n2->weight);
- len2 = (float)fabs(n2->weight - n3->weight);
- len3 = (float)fabs(n3->weight - n1->weight);
-
- /* The rest of the algorithm assumes that e1 is the longest edge */
-
- if (len1 >= len2 && len1 >= len3) {
- e1 = re1;
- e2 = re2;
- e3 = re3;
- }
- else if (len2 >= len1 && len2 >= len3) {
- e1 = re2;
- e2 = re1;
- e3 = re3;
- }
- else {
- e1 = re3;
- e2 = re2;
- e3 = re1;
- }
-
- /* And e2 is the lowest edge
- * If e3 is lower than e2, swap them
- */
- if (e3->v1->weight < e2->v1->weight) {
- ReebEdge *etmp = e2;
- e2 = e3;
- e3 = etmp;
- }
-
-
- mergePaths(rg, e1, e2, e3);
-}
-
-ReebGraph *generateReebGraph(EditMesh *em, int subdivisions)
-{
- ReebGraph *rg;
- EditVert *eve;
- EditFace *efa;
- int index;
- /*int totvert;*/
-
-#ifdef DEBUG_REEB
- int totfaces;
- int countfaces = 0;
-#endif
-
- rg = newReebGraph();
-
- rg->resolution = subdivisions;
-
- /*totvert = BLI_listbase_count(&em->verts);*/ /*UNUSED*/
-#ifdef DEBUG_REEB
- totfaces = BLI_listbase_count(&em->faces);
-#endif
-
- renormalizeWeight(em, 1.0f);
-
- /* Spread weight to minimize errors */
- spreadWeight(em);
-
- renormalizeWeight(em, (float)rg->resolution);
-
- /* Adding vertice */
- for (index = 0, eve = em->verts.first; eve; eve = eve->next) {
- if (eve->h == 0) {
- addNode(rg, eve);
- eve->f2 = 0;
- index++;
- }
- }
-
- /* Adding face, edge per edge */
- for (efa = em->faces.first; efa; efa = efa->next) {
- if (efa->h == 0) {
- ReebNode *n1, *n2, *n3;
-
- n1 = nodeData(efa->v1);
- n2 = nodeData(efa->v2);
- n3 = nodeData(efa->v3);
-
- addTriangleToGraph(rg, n1, n2, n3, efa);
-
- if (efa->v4) {
- ReebNode *n4 = nodeData(efa->v4);
- addTriangleToGraph(rg, n1, n3, n4, efa);
- }
-#ifdef DEBUG_REEB
- countfaces++;
- if (countfaces % 100 == 0) {
- printf("\rface %i of %i", countfaces, totfaces);
- }
-#endif
- }
- }
-
- printf("\n");
-
- removeZeroNodes(rg);
-
- removeNormalNodes(rg);
-
- return rg;
-}
-
-/***************************************** WEIGHT UTILS **********************************************/
-
-void renormalizeWeight(EditMesh *em, float newmax)
-{
- EditVert *eve;
- float minimum, maximum, range;
-
- if (em == NULL || BLI_listbase_is_empty(&em->verts))
- return;
-
- /* First pass, determine maximum and minimum */
- eve = em->verts.first;
- minimum = weightData(eve);
- maximum = minimum;
- for (; eve; eve = eve->next) {
- maximum = MAX2(maximum, weightData(eve));
- minimum = MIN2(minimum, weightData(eve));
- }
-
- range = maximum - minimum;
-
- /* Normalize weights */
- for (eve = em->verts.first; eve; eve = eve->next) {
- float weight = (weightData(eve) - minimum) / range * newmax;
- weightSetData(eve, weight);
- }
-}
-
-
-int weightFromLoc(EditMesh *em, int axis)
-{
- EditVert *eve;
-
- if (em == NULL || BLI_listbase_is_empty(&em->verts) || axis < 0 || axis > 2)
- return 0;
-
- /* Copy coordinate in weight */
- for (eve = em->verts.first; eve; eve = eve->next) {
- weightSetData(eve, eve->co[axis]);
- }
-
- return 1;
-}
-
-static void addTriangle(LinearSolver *context, EditVert *v1, EditVert *v2, EditVert *v3, int e1, int e2, int e3)
-{
- /* Angle opposite e1 */
- float t1 = cotangent_tri_weight_v3(v1->co, v2->co, v3->co) / e2;
-
- /* Angle opposite e2 */
- float t2 = cotangent_tri_weight_v3(v2->co, v3->co, v1->co) / e3;
-
- /* Angle opposite e3 */
- float t3 = cotangent_tri_weight_v3(v3->co, v1->co, v2->co) / e1;
-
- int i1 = indexData(v1);
- int i2 = indexData(v2);
- int i3 = indexData(v3);
-
- EIG_linear_solver_matrix_add(context, i1, i1, t2 + t3);
- EIG_linear_solver_matrix_add(context, i2, i2, t1 + t3);
- EIG_linear_solver_matrix_add(context, i3, i3, t1 + t2);
-
- EIG_linear_solver_matrix_add(context, i1, i2, -t3);
- EIG_linear_solver_matrix_add(context, i2, i1, -t3);
-
- EIG_linear_solver_matrix_add(context, i2, i3, -t1);
- EIG_linear_solver_matrix_add(context, i3, i2, -t1);
-
- EIG_linear_solver_matrix_add(context, i3, i1, -t2);
- EIG_linear_solver_matrix_add(context, i1, i3, -t2);
-}
-
-int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges)
-{
- LinearSolver *context;
- NLboolean success;
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- int totvert = 0;
- int index;
- int rval;
-
- /* Find local extrema */
- for (eve = em->verts.first; eve; eve = eve->next) {
- totvert++;
- }
-
- /* Solve */
-
- context = EIG_linear_solver_new(, 0, totvert, 1);
-
- /* Find local extrema */
- for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) {
- if (eve->h == 0) {
- EditEdge *eed;
- int maximum = 1;
- int minimum = 1;
-
- NextEdgeForVert(indexed_edges, -1); /* Reset next edge */
- for (eed = NextEdgeForVert(indexed_edges, index); eed && (maximum || minimum); eed = NextEdgeForVert(indexed_edges, index)) {
- EditVert *eve2;
-
- if (eed->v1 == eve) {
- eve2 = eed->v2;
- }
- else {
- eve2 = eed->v1;
- }
-
- if (eve2->h == 0) {
- /* Adjacent vertex is bigger, not a local maximum */
- if (weightData(eve2) > weightData(eve)) {
- maximum = 0;
- }
- /* Adjacent vertex is smaller, not a local minimum */
- else if (weightData(eve2) < weightData(eve)) {
- minimum = 0;
- }
- }
- }
-
- if (maximum || minimum) {
- float w = weightData(eve);
- eve->f1 = 0;
- EIG_linear_solver_variable_set(context, 0, index, w);
- EIG_linear_solver_variable_lock(context, index);
- }
- else {
- eve->f1 = 1;
- }
- }
- }
-
- /* Zero edge weight */
- for (eed = em->edges.first; eed; eed = eed->next) {
- eed->tmp.l = 0;
- }
-
- /* Add faces count to the edge weight */
- for (efa = em->faces.first; efa; efa = efa->next) {
- if (efa->h == 0) {
- efa->e1->tmp.l++;
- efa->e2->tmp.l++;
- efa->e3->tmp.l++;
-
- if (efa->e4) {
- efa->e4->tmp.l++;
- }
- }
- }
-
- /* Add faces angle to the edge weight */
- for (efa = em->faces.first; efa; efa = efa->next) {
- if (efa->h == 0) {
- if (efa->v4 == NULL) {
- addTriangle(context, efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, efa->e3->tmp.l);
- }
- else {
- addTriangle(context, efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, 2);
- addTriangle(context, efa->v3, efa->v4, efa->v1, efa->e3->tmp.l, efa->e4->tmp.l, 2);
- }
- }
- }
-
- success = EIG_linear_solver_solve(context);
-
- if (success) {
- rval = 1;
- for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) {
- weightSetData(eve, EIG_linear_solver_variable_get(context, 0, index));
- }
- }
- else {
- rval = 0;
- }
-
- EIG_linear_solver_delete(context);
-
- return rval;
-}
-
-
-EditEdge *NextEdgeForVert(EdgeIndex *indexed_edges, int index)
-{
- static int offset = -1;
-
- /* Reset method, call with NULL mesh pointer */
- if (index == -1) {
- offset = -1;
- return NULL;
- }
-
- /* first pass, start at the head of the list */
- if (offset == -1) {
- offset = indexed_edges->offset[index];
- }
- /* subsequent passes, start on the next edge */
- else {
- offset++;
- }
-
- return indexed_edges->edges[offset];
-}
-
-static void shortestPathsFromVert(EditMesh *em, EditVert *starting_vert, EdgeIndex *indexed_edges)
-{
- Heap *edge_heap;
- EditVert *current_eve = NULL;
- EditEdge *eed = NULL;
- EditEdge *select_eed = NULL;
-
- edge_heap = BLI_heap_new();
-
- current_eve = starting_vert;
-
- /* insert guard in heap, when that is returned, no more edges */
- BLI_heap_insert(edge_heap, FLT_MAX, NULL);
-
- /* Initialize edge flag */
- for (eed = em->edges.first; eed; eed = eed->next) {
- eed->f1 = 0;
- }
-
- while (BLI_heap_len(edge_heap) > 0) {
- float current_weight;
-
- current_eve->f1 = 1; /* mark vertex as selected */
-
- /* Add all new edges connected to current_eve to the list */
- NextEdgeForVert(indexed_edges, -1); // Reset next edge
- for (eed = NextEdgeForVert(indexed_edges, indexData(current_eve)); eed; eed = NextEdgeForVert(indexed_edges, indexData(current_eve))) {
- if (eed->f1 == 0) {
- BLI_heap_insert(edge_heap, weightData(current_eve) + eed->tmp.fp, eed);
- eed->f1 = 1;
- }
- }
-
- /* Find next shortest edge with unselected verts */
- do {
- current_weight = BLI_heap_node_value(BLI_heap_top(edge_heap));
- select_eed = BLI_heap_pop_min(edge_heap);
- } while (select_eed != NULL && select_eed->v1->f1 != 0 && select_eed->v2->f1);
-
- if (select_eed != NULL) {
- select_eed->f1 = 2;
-
- if (select_eed->v1->f1 == 0) /* v1 is the new vertex */ {
- current_eve = select_eed->v1;
- }
- else { /* otherwise, it's v2 */
- current_eve = select_eed->v2;
- }
-
- weightSetData(current_eve, current_weight);
- }
- }
-
- BLI_heap_free(edge_heap, NULL);
-}
-
-static void freeEdgeIndex(EdgeIndex *indexed_edges)
-{
- MEM_freeN(indexed_edges->offset);
- MEM_freeN(indexed_edges->edges);
-}
-
-static void buildIndexedEdges(EditMesh *em, EdgeIndex *indexed_edges)
-{
- EditVert *eve;
- EditEdge *eed;
- int totvert = 0;
- int tot_indexed = 0;
- int offset = 0;
-
- totvert = BLI_listbase_count(&em->verts);
-
- indexed_edges->offset = MEM_callocN(totvert * sizeof(int), "EdgeIndex offset");
-
- for (eed = em->edges.first; eed; eed = eed->next) {
- if (eed->v1->h == 0 && eed->v2->h == 0) {
- tot_indexed += 2;
- indexed_edges->offset[indexData(eed->v1)]++;
- indexed_edges->offset[indexData(eed->v2)]++;
- }
- }
-
- tot_indexed += totvert;
-
- indexed_edges->edges = MEM_callocN(tot_indexed * sizeof(EditEdge *), "EdgeIndex edges");
-
- /* setting vert offsets */
- for (eve = em->verts.first; eve; eve = eve->next) {
- if (eve->h == 0) {
- int d = indexed_edges->offset[indexData(eve)];
- indexed_edges->offset[indexData(eve)] = offset;
- offset += d + 1;
- }
- }
-
- /* adding edges in array */
- for (eed = em->edges.first; eed; eed = eed->next) {
- if (eed->v1->h == 0 && eed->v2->h == 0) {
- int i;
- for (i = indexed_edges->offset[indexData(eed->v1)]; i < tot_indexed; i++) {
- if (indexed_edges->edges[i] == NULL) {
- indexed_edges->edges[i] = eed;
- break;
- }
- }
-
- for (i = indexed_edges->offset[indexData(eed->v2)]; i < tot_indexed; i++) {
- if (indexed_edges->edges[i] == NULL) {
- indexed_edges->edges[i] = eed;
- break;
- }
- }
- }
- }
-}
-
-int weightFromDistance(EditMesh *em, EdgeIndex *indexed_edges)
-{
- EditVert *eve;
- int totedge = 0;
- int totvert = 0;
- int vCount = 0;
-
- totvert = BLI_listbase_count(&em->verts);
-
- if (em == NULL || totvert == 0) {
- return 0;
- }
-
- totedge = BLI_listbase_count(&em->edges);
-
- if (totedge == 0) {
- return 0;
- }
-
- /* Initialize vertice flag and find at least one selected vertex */
- for (eve = em->verts.first; eve; eve = eve->next) {
- eve->f1 = 0;
- if (eve->f & SELECT) {
- vCount = 1;
- }
- }
-
- if (vCount == 0) {
- return 0; /* no selected vert, failure */
- }
- else {
- EditEdge *eed;
- int allDone = 0;
-
- /* Calculate edge weight */
- for (eed = em->edges.first; eed; eed = eed->next) {
- if (eed->v1->h == 0 && eed->v2->h == 0) {
- eed->tmp.fp = len_v3v3(eed->v1->co, eed->v2->co);
- }
- }
-
- /* Apply dijkstra spf for each selected vert */
- for (eve = em->verts.first; eve; eve = eve->next) {
- if (eve->f & SELECT) {
- shortestPathsFromVert(em, eve, indexed_edges);
- }
- }
-
- /* connect unselected islands */
- while (allDone == 0) {
- EditVert *selected_eve = NULL;
- float selected_weight = 0;
- float min_distance = FLT_MAX;
-
- allDone = 1;
-
- for (eve = em->verts.first; eve; eve = eve->next) {
- /* for every vertex visible that hasn't been processed yet */
- if (eve->h == 0 && eve->f1 != 1) {
- EditVert *closest_eve;
-
- /* find the closest processed vertex */
- for (closest_eve = em->verts.first; closest_eve; closest_eve = closest_eve->next) {
- /* vertex is already processed and distance is smaller than current minimum */
- if (closest_eve->f1 == 1) {
- float distance = len_v3v3(closest_eve->co, eve->co);
- if (distance < min_distance) {
- min_distance = distance;
- selected_eve = eve;
- selected_weight = weightData(closest_eve);
- }
- }
- }
- }
- }
-
- if (selected_eve) {
- allDone = 0;
-
- weightSetData(selected_eve, selected_weight + min_distance);
- shortestPathsFromVert(em, selected_eve, indexed_edges);
- }
- }
- }
-
- for (eve = em->verts.first; eve && vCount == 0; eve = eve->next) {
- if (eve->f1 == 0) {
- printf("vertex not reached\n");
- break;
- }
- }
-
- return 1;
-}
-#endif
-
-/****************************************** BUCKET ITERATOR **************************************************/
-
-static void *headNode(void *arg);
-static void *tailNode(void *arg);
-static void *nextBucket(void *arg);
-static void *nextNBucket(void *arg, int n);
-static void *peekBucket(void *arg, int n);
-static void *previousBucket(void *arg);
-static int iteratorStopped(void *arg);
-
-static void initIteratorFct(ReebArcIterator *iter)
-{
- iter->head = headNode;
- iter->tail = tailNode;
- iter->peek = peekBucket;
- iter->next = nextBucket;
- iter->nextN = nextNBucket;
- iter->previous = previousBucket;
- iter->stopped = iteratorStopped;
-}
-
-static void setIteratorValues(ReebArcIterator *iter, EmbedBucket *bucket)
-{
- if (bucket) {
- iter->p = bucket->p;
- iter->no = bucket->no;
- }
- else {
- iter->p = NULL;
- iter->no = NULL;
- }
- iter->size = 0;
-}
-
-void initArcIterator(BArcIterator *arg, ReebArc *arc, ReebNode *head)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
-
- initIteratorFct(iter);
- iter->arc = arc;
-
- if (head == arc->head) {
- iter->start = 0;
- iter->end = arc->bcount - 1;
- iter->stride = 1;
- }
- else {
- iter->start = arc->bcount - 1;
- iter->end = 0;
- iter->stride = -1;
- }
-
- iter->length = arc->bcount;
-
- iter->index = -1;
-}
-
-void initArcIteratorStart(BArcIterator *arg, struct ReebArc *arc, struct ReebNode *head, int start)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
-
- initIteratorFct(iter);
- iter->arc = arc;
-
- if (head == arc->head) {
- iter->start = start;
- iter->end = arc->bcount - 1;
- iter->stride = 1;
- }
- else {
- iter->start = arc->bcount - 1 - start;
- iter->end = 0;
- iter->stride = -1;
- }
-
- iter->index = -1;
-
- iter->length = arc->bcount - start;
-
- if (start >= arc->bcount) {
- iter->start = iter->end; /* stop iterator since it's past its end */
- }
-}
-
-void initArcIterator2(BArcIterator *arg, ReebArc *arc, int start, int end)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
-
- initIteratorFct(iter);
- iter->arc = arc;
-
- iter->start = start;
- iter->end = end;
-
- if (end > start) {
- iter->stride = 1;
- }
- else {
- iter->stride = -1;
- }
-
- iter->index = -1;
-
- iter->length = abs(iter->end - iter->start) + 1;
-}
-
-static void *headNode(void *arg)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
- ReebNode *node;
-
- if (iter->start < iter->end) {
- node = iter->arc->head;
- }
- else {
- node = iter->arc->tail;
- }
-
- iter->p = node->p;
- iter->no = node->no;
- iter->size = 0;
-
- return node;
-}
-
-static void *tailNode(void *arg)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
- ReebNode *node;
-
- if (iter->start < iter->end) {
- node = iter->arc->tail;
- }
- else {
- node = iter->arc->head;
- }
-
- iter->p = node->p;
- iter->no = node->no;
- iter->size = 0;
-
- return node;
-}
-
-static void *nextBucket(void *arg)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
- EmbedBucket *result = NULL;
-
- iter->index++;
-
- if (iter->index < iter->length) {
- result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
- }
-
- setIteratorValues(iter, result);
- return result;
-}
-
-static void *nextNBucket(void *arg, int n)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
- EmbedBucket *result = NULL;
-
- iter->index += n;
-
- /* check if passed end */
- if (iter->index < iter->length) {
- result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
- }
-
- setIteratorValues(iter, result);
- return result;
-}
-
-static void *peekBucket(void *arg, int n)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
- EmbedBucket *result = NULL;
- int index = iter->index + n;
-
- /* check if passed end */
- if (index < iter->length) {
- result = &(iter->arc->buckets[iter->start + (iter->stride * index)]);
- }
-
- setIteratorValues(iter, result);
- return result;
-}
-
-static void *previousBucket(void *arg)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
- EmbedBucket *result = NULL;
-
- if (iter->index > 0) {
- iter->index--;
- result = &(iter->arc->buckets[iter->start + (iter->stride * iter->index)]);
- }
-
- setIteratorValues(iter, result);
- return result;
-}
-
-static int iteratorStopped(void *arg)
-{
- ReebArcIterator *iter = (ReebArcIterator *)arg;
-
- if (iter->index >= iter->length) {
- return 1;
- }
- else {
- return 0;
- }
-}
-
-/************************ PUBLIC FUNCTIONS *********************************************/
-
-ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C)
-{
- (void)C;
- return NULL;
-#if 0
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- EditMesh *em = BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EdgeIndex indexed_edges;
- VertexData *data;
- ReebGraph *rg = NULL;
- ReebGraph *rgi, *previous;
- int i, nb_levels = REEB_MAX_MULTI_LEVEL;
-
- if (em == NULL)
- return NULL;
-
- data = allocVertexData(em);
-
- buildIndexedEdges(em, &indexed_edges);
-
- if (weightFromDistance(em, &indexed_edges) == 0)
- {
- // XXX error("No selected vertex\n");
- freeEdgeIndex(&indexed_edges);
- return NULL;
- }
-
- renormalizeWeight(em, 1.0f);
-
- if (scene->toolsettings->skgen_options & SKGEN_HARMONIC)
- {
- weightToHarmonic(em, &indexed_edges);
- }
-
- freeEdgeIndex(&indexed_edges);
-
- rg = generateReebGraph(em, scene->toolsettings->skgen_resolution);
-
- /* Remove arcs without embedding */
- filterNullReebGraph(rg);
-
- /* smart filter and loop filter on basic level */
- filterGraph(rg, SKGEN_FILTER_SMART, 0, 0);
-
- repositionNodes(rg);
-
- /* Filtering might have created degree 2 nodes, so remove them */
- removeNormalNodes(rg);
-
- joinSubgraphs(rg, 1.0);
-
- BLI_buildAdjacencyList((BGraph *)rg);
-
- /* calc length before copy, so we have same length on all levels */
- BLI_calcGraphLength((BGraph *)rg);
-
- previous = NULL;
- for (i = 0; i <= nb_levels; i++)
- {
- rgi = rg;
-
- /* don't filter last level */
- if (i > 0)
- {
- float internal_threshold;
- float external_threshold;
-
- /* filter internal progressively in second half only*/
- if (i > nb_levels / 2)
- {
- internal_threshold = rg->length * scene->toolsettings->skgen_threshold_internal;
- }
- else {
- internal_threshold = rg->length * scene->toolsettings->skgen_threshold_internal * (2 * i / (float)nb_levels);
- }
-
- external_threshold = rg->length * scene->toolsettings->skgen_threshold_external * (i / (float)nb_levels);
-
- filterGraph(rgi, scene->toolsettings->skgen_options, internal_threshold, external_threshold);
- }
-
- if (i < nb_levels)
- {
- rg = copyReebGraph(rgi, i + 1);
- }
-
- finalizeGraph(rgi, scene->toolsettings->skgen_postpro_passes, scene->toolsettings->skgen_postpro);
-
- BLI_markdownSymmetry((BGraph *)rgi, rgi->nodes.first, scene->toolsettings->skgen_symmetry_limit);
-
- if (previous != NULL)
- {
- relinkNodes(rgi, previous);
- }
- previous = rgi;
- }
-
- verifyMultiResolutionLinks(rg, 0);
-
- MEM_freeN(data);
-
- /* no need to load the editmesh back into the object, just
- * free it (avoids ngon conversion issues too going back the other way) */
- free_editMesh(em);
- MEM_freeN(em);
-
- return rg;
-#endif
-}
-
-#if 0
-
-ReebGraph *BIF_ReebGraphFromEditMesh(void)
-{
- EditMesh *em = G.editMesh;
- EdgeIndex indexed_edges;
- VertexData *data;
- ReebGraph *rg = NULL;
-
- if (em == NULL)
- return NULL;
-
- data = allocVertexData(em);
-
- buildIndexedEdges(em, &indexed_edges);
-
- if (weightFromDistance(em, &indexed_edges) == 0)
- {
- error("No selected vertex\n");
- freeEdgeIndex(&indexed_edges);
- freeEdgeIndex(&indexed_edges);
- return NULL;
- }
-
- renormalizeWeight(em, 1.0f);
-
- if (G.scene->toolsettings->skgen_options & SKGEN_HARMONIC)
- {
- weightToHarmonic(em, &indexed_edges);
- }
-
- freeEdgeIndex(&indexed_edges);
-
-#ifdef DEBUG_REEB
-// weightToVCol(em, 1);
-#endif
-
- rg = generateReebGraph(em, G.scene->toolsettings->skgen_resolution);
-
-
- /* Remove arcs without embedding */
- filterNullReebGraph(rg);
-
- /* smart filter and loop filter on basic level */
- filterGraph(rg, SKGEN_FILTER_SMART, 0, 0);
-
- repositionNodes(rg);
-
- /* Filtering might have created degree 2 nodes, so remove them */
- removeNormalNodes(rg);
-
- joinSubgraphs(rg, 1.0);
-
- BLI_buildAdjacencyList((BGraph *)rg);
-
- /* calc length before copy, so we have same length on all levels */
- BLI_calcGraphLength((BGraph *)rg);
-
- filterGraph(rg, G.scene->toolsettings->skgen_options, G.scene->toolsettings->skgen_threshold_internal, G.scene->toolsettings->skgen_threshold_external);
-
- finalizeGraph(rg, G.scene->toolsettings->skgen_postpro_passes, G.scene->toolsettings->skgen_postpro);
-
-#ifdef DEBUG_REEB
- REEB_exportGraph(rg, -1);
-
- arcToVCol(rg, em, 0);
- //angleToVCol(em, 1);
-#endif
-
- printf("DONE\n");
- printf("%i subgraphs\n", BLI_FlagSubgraphs((BGraph *)rg));
-
- MEM_freeN(data);
-
- return rg;
-}
-
-void BIF_GlobalReebFree()
-{
- if (GLOBAL_RG != NULL)
- {
- REEB_freeGraph(GLOBAL_RG);
- GLOBAL_RG = NULL;
- }
-}
-
-void BIF_GlobalReebGraphFromEditMesh(void)
-{
- ReebGraph *rg;
-
- BIF_GlobalReebFree();
-
- rg = BIF_ReebGraphMultiFromEditMesh();
-
- GLOBAL_RG = rg;
-}
-
-void REEB_draw()
-{
- ReebGraph *rg;
- ReebArc *arc;
- int i = 0;
-
- if (GLOBAL_RG == NULL)
- {
- return;
- }
-
- if (GLOBAL_RG->link_up && G.scene->toolsettings->skgen_options & SKGEN_DISP_ORIG)
- {
- for (rg = GLOBAL_RG; rg->link_up; rg = rg->link_up) ;
- }
- else {
- i = G.scene->toolsettings->skgen_multi_level;
-
- for (rg = GLOBAL_RG; rg->multi_level != i && rg->link_up; rg = rg->link_up) ;
- }
-
- glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
-
- glDisable(GL_DEPTH_TEST);
- for (arc = rg->arcs.first; arc; arc = arc->next, i++)
- {
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- float vec[3];
- char text[128];
- char *s = text;
-
- glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE) + 2);
- glColor3f(0, 0, 0);
- glBegin(GL_LINE_STRIP);
- glVertex3fv(arc->head->p);
-
- if (arc->bcount)
- {
- initArcIterator(iter, arc, arc->head);
- for (IT_next(iter); IT_stopped(iter) == 0; IT_next(iter))
- {
- glVertex3fv(iter->p);
- }
- }
-
- glVertex3fv(arc->tail->p);
- glEnd();
-
- glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE));
-
- if (arc->symmetry_level == 1)
- {
- glColor3f(1, 0, 0);
- }
- else if (arc->symmetry_flag == SYM_SIDE_POSITIVE || arc->symmetry_flag == SYM_SIDE_NEGATIVE)
- {
- glColor3f(1, 0.5f, 0);
- }
- else if (arc->symmetry_flag >= SYM_SIDE_RADIAL)
- {
- glColor3f(0.5f, 1, 0);
- }
- else {
- glColor3f(1, 1, 0);
- }
- glBegin(GL_LINE_STRIP);
- glVertex3fv(arc->head->p);
-
- if (arc->bcount)
- {
- initArcIterator(iter, arc, arc->head);
- for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter))
- {
- glVertex3fv(iter->p);
- }
- }
-
- glVertex3fv(arc->tail->p);
- glEnd();
-
-
- if (G.scene->toolsettings->skgen_options & SKGEN_DISP_EMBED)
- {
- glColor3f(1, 1, 1);
- glBegin(GL_POINTS);
- glVertex3fv(arc->head->p);
- glVertex3fv(arc->tail->p);
-
- glColor3f(0.5f, 0.5f, 1);
- if (arc->bcount)
- {
- initArcIterator(iter, arc, arc->head);
- for (iter->next(iter); IT_stopped(iter) == 0; iter->next(iter))
- {
- glVertex3fv(iter->p);
- }
- }
- glEnd();
- }
-
- if (G.scene->toolsettings->skgen_options & SKGEN_DISP_INDEX)
- {
- mid_v3_v3v3(vec, arc->head->p, arc->tail->p);
- s += sprintf(s, "%i (%i-%i-%i) ", i, arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group);
-
- if (G.scene->toolsettings->skgen_options & SKGEN_DISP_WEIGHT)
- {
- s += sprintf(s, "w:%0.3f ", arc->tail->weight - arc->head->weight);
- }
-
- if (G.scene->toolsettings->skgen_options & SKGEN_DISP_LENGTH)
- {
- s += sprintf(s, "l:%0.3f", arc->length);
- }
-
- glColor3f(0, 1, 0);
- glRasterPos3fv(vec);
- BMF_DrawString(G.fonts, text);
- }
-
- if (G.scene->toolsettings->skgen_options & SKGEN_DISP_INDEX)
- {
- sprintf(text, " %i", arc->head->index);
- glRasterPos3fv(arc->head->p);
- BMF_DrawString(G.fonts, text);
-
- sprintf(text, " %i", arc->tail->index);
- glRasterPos3fv(arc->tail->p);
- BMF_DrawString(G.fonts, text);
- }
- }
- glEnable(GL_DEPTH_TEST);
-}
-
-#endif
diff --git a/source/blender/editors/armature/reeb.h b/source/blender/editors/armature/reeb.h
deleted file mode 100644
index 9eed343f18a..00000000000
--- a/source/blender/editors/armature/reeb.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * ***** 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): Martin Poirier
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/armature/reeb.h
- * \ingroup edarmature
- */
-
-
-#ifndef __REEB_H__
-#define __REEB_H__
-
-#define WITH_BF_REEB
-
-#include "DNA_listBase.h"
-
-#include "BLI_graph.h"
-
-struct GHash;
-struct EdgeHash;
-struct ReebArc;
-struct ReebEdge;
-struct ReebNode;
-
-typedef struct ReebGraph {
- ListBase arcs;
- ListBase nodes;
-
- float length;
-
- FreeArc free_arc;
- FreeNode free_node;
- RadialSymmetry radial_symmetry;
- AxialSymmetry axial_symmetry;
- /*********************************/
-
- int resolution;
- int totnodes;
- struct EdgeHash *emap;
- int multi_level;
- struct ReebGraph *link_up; /* for multi resolution filtering, points to higher levels */
-} ReebGraph;
-
-typedef struct EmbedBucket {
- float val;
- int nv;
- float p[3];
- float no[3]; /* if non-null, normal of the bucket */
-} EmbedBucket;
-
-typedef struct ReebNode {
- void *next, *prev;
- float p[3];
- int flag;
-
- int degree;
- struct ReebArc **arcs;
-
- int subgraph_index;
-
- int symmetry_level;
- int symmetry_flag;
- float symmetry_axis[3];
- /*********************************/
-
- float no[3];
-
- int index;
- float weight;
- int multi_level;
- struct ReebNode *link_down; /* for multi resolution filtering, points to lower levels, if present */
- struct ReebNode *link_up;
-} ReebNode;
-
-typedef struct ReebEdge {
- struct ReebEdge *next, *prev;
- struct ReebArc *arc;
- struct ReebNode *v1, *v2;
- struct ReebEdge *nextEdge;
- int flag;
-} ReebEdge;
-
-typedef struct ReebArc {
- void *next, *prev;
- struct ReebNode *head, *tail;
- int flag;
-
- float length;
-
- int symmetry_level;
- int symmetry_group;
- int symmetry_flag;
- /*********************************/
-
- ListBase edges;
- int bcount;
- struct EmbedBucket *buckets;
-
- struct GHash *faces;
- float angle;
- struct ReebArc *link_up; /* for multi resolution filtering, points to higher levels */
-} ReebArc;
-
-typedef struct ReebArcIterator {
- HeadFct head;
- TailFct tail;
- PeekFct peek;
- NextFct next;
- NextNFct nextN;
- PreviousFct previous;
- StoppedFct stopped;
-
- float *p, *no;
- float size;
-
- int length;
- int index;
- /*********************************/
- struct ReebArc *arc;
- int start;
- int end;
- int stride;
-} ReebArcIterator;
-
-#if 0
-struct EditMesh;
-struct EdgeIndex;
-
-int weightToHarmonic(struct EditMesh *em, struct EdgeIndex *indexed_edges);
-int weightFromDistance(struct EditMesh *em, struct EdgeIndex *indexed_edges);
-int weightFromLoc(struct EditMesh *me, int axis);
-//void weightToVCol(struct EditMesh *em, int index);
-void arcToVCol(struct ReebGraph *rg, struct EditMesh *em, int index);
-//void angleToVCol(struct EditMesh *em, int index);
-void renormalizeWeight(struct EditMesh *em, float newmax);
-
-ReebGraph *generateReebGraph(struct EditMesh *me, int subdivisions);
-#endif
-
-ReebGraph *newReebGraph(void);
-
-void initArcIterator(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head);
-void initArcIterator2(BArcIterator *iter, struct ReebArc *arc, int start, int end);
-void initArcIteratorStart(BArcIterator *iter, struct ReebArc *arc, struct ReebNode *head, int start);
-
-/* Filtering */
-void filterNullReebGraph(ReebGraph *rg);
-int filterSmartReebGraph(ReebGraph *rg, float threshold);
-
-/* Post-Build processing */
-void repositionNodes(ReebGraph *rg);
-void postprocessGraph(ReebGraph *rg, char mode);
-void removeNormalNodes(ReebGraph *rg);
-
-void sortNodes(ReebGraph *rg);
-void sortArcs(ReebGraph *rg);
-
-/*------------ Sanity check ------------*/
-void verifyBuckets(ReebGraph *rg);
-void verifyFaces(ReebGraph *rg);
-void verifyArcs(ReebGraph *rg);
-void verifyNodeDegree(ReebGraph *rg);
-
-/*********************** PUBLIC *********************************/
-
-#define REEB_MAX_MULTI_LEVEL 10
-
-struct bContext;
-
-ReebGraph *BIF_ReebGraphFromEditMesh(void);
-ReebGraph *BIF_ReebGraphMultiFromEditMesh(struct bContext *C);
-void BIF_flagMultiArcs(ReebGraph *rg, int flag);
-
-void BIF_GlobalReebGraphFromEditMesh(void);
-void BIF_GlobalReebFree(void);
-
-ReebNode *BIF_otherNodeFromIndex(ReebArc *arc, ReebNode *node);
-ReebNode *BIF_NodeFromIndex(ReebArc *arc, ReebNode *node);
-ReebNode *BIF_lowestLevelNode(ReebNode *node);
-
-ReebGraph *BIF_graphForMultiNode(ReebGraph *rg, ReebNode *node);
-
-void REEB_freeGraph(ReebGraph *rg);
-void REEB_freeArc(BArc *barc);
-void REEB_exportGraph(ReebGraph *rg, int count);
-void REEB_draw(void);
-
-
-#endif /*__REEB_H__*/
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 13f12f62d95..301d333ebdb 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
../../../../intern/glew-mx
../../../../extern/curve_fit_nd
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 01047d4badd..cd7a344fcb0 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -135,13 +135,14 @@ struct GHash *ED_curve_keyindex_hash_duplicate(struct GHash *keyindex);
void ED_curve_keyindex_update_nurb(struct EditNurb *editnurb, struct Nurb *nu, struct Nurb *newnu);
bool ED_curve_pick_vert(
- struct ViewContext *vc, short sel, const int mval[2],
- struct Nurb **r_nurb, struct BezTriple **r_bezt, struct BPoint **r_bp, short *r_handle);
+ struct ViewContext *vc, short sel,
+ struct Nurb **r_nurb, struct BezTriple **r_bezt, struct BPoint **r_bp, short *r_handle,
+ struct Base **r_base);
/* helper functions */
void ed_editnurb_translate_flag(struct ListBase *editnurb, short flag, const float vec[3]);
bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const short flag);
-bool ed_editnurb_spin(float viewmat[4][4], struct Object *obedit, const float axis[3], const float cent[3]);
+bool ed_editnurb_spin(float viewmat[4][4], struct View3D *v3d, struct Object *obedit, const float axis[3], const float cent[3]);
/* editcurve_select.c */
void CURVE_OT_de_select_first(struct wmOperatorType *ot);
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 4a801d9de64..bd1c2248660 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -44,6 +44,7 @@
#include "ED_curve.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
#include "curve_intern.h"
@@ -166,135 +167,11 @@ void ED_operatormacros_curve(void)
void ED_keymap_curve(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
- keymap = WM_keymap_ensure(keyconf, "Font", 0, 0);
- keymap->poll = ED_operator_editfont;
-
/* only set in editmode font, by space_view3d listener */
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_style_toggle", BKEY, KM_PRESS, KM_CTRL, 0)->ptr, "style", CU_CHINFO_BOLD);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_style_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "style", CU_CHINFO_ITALIC);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_style_toggle", UKEY, KM_PRESS, KM_CTRL, 0)->ptr, "style", CU_CHINFO_UNDERLINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_style_toggle", PKEY, KM_PRESS, KM_CTRL, 0)->ptr, "style", CU_CHINFO_SMALLCAPS);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_SEL);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", DELKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_SEL);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", DEL_PREV_SEL); /* same as above [#26623] */
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_PAGE);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_PAGE);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", HOMEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", LINE_BEGIN);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", ENDKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", LINE_END);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)->ptr, "type", PREV_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)->ptr, "type", NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", UPARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_PAGE);
- RNA_enum_set(WM_keymap_add_item(keymap, "FONT_OT_move_select", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_PAGE);
-
- RNA_int_set(WM_keymap_add_item(keymap, "FONT_OT_change_spacing", LEFTARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "delta", -1);
- RNA_int_set(WM_keymap_add_item(keymap, "FONT_OT_change_spacing", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "FONT_OT_change_character", UPARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "FONT_OT_change_character", DOWNARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "delta", -1);
-
- WM_keymap_add_item(keymap, "FONT_OT_select_all", AKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "FONT_OT_text_copy", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "FONT_OT_text_cut", XKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "FONT_OT_text_paste", VKEY, KM_PRESS, KM_CTRL, 0);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "FONT_OT_select_all", AKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "FONT_OT_text_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "FONT_OT_text_cut", XKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "FONT_OT_text_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
-
- WM_keymap_add_item(keymap, "FONT_OT_line_break", RETKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FONT_OT_text_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last!
- kmi = WM_keymap_add_item(keymap, "FONT_OT_text_insert", BACKSPACEKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "accent", true); /* accented characters */
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Font", 0, 0);
+ keymap->poll = ED_operator_editfont;
/* only set in editmode curve, by space_view3d listener */
keymap = WM_keymap_ensure(keyconf, "Curve", 0, 0);
keymap->poll = ED_operator_editsurfcurve;
-
- WM_keymap_add_menu(keymap, "INFO_MT_edit_curve_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "CURVE_OT_handle_type_set", VKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "CURVE_OT_vertex_add", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
-
- kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", TABLET_STYLUS, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "CURVE_OT_select_row", RKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
-
- kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- WM_keymap_add_item(keymap, "CURVE_OT_shortest_path_pick", SELECTMOUSE, KM_CLICK, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "CURVE_OT_separate", PKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_split", YKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_make_segment", FKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_cyclic_toggle", CKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_curve_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_curve_delete", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "CURVE_OT_dissolve_verts", XKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "CURVE_OT_dissolve_verts", DELKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "CURVE_OT_tilt_clear", TKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "TRANSFORM_OT_tilt", TKEY, KM_PRESS, KM_CTRL, 0);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", TFM_CURVE_SHRINKFATTEN);
-
- WM_keymap_add_item(keymap, "CURVE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "CURVE_OT_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "CURVE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- WM_keymap_add_item(keymap, "CURVE_OT_normals_make_consistent", NKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_curve_specials", WKEY, KM_PRESS, 0, 0);
-
- /* menus */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_hook", HKEY, KM_PRESS, KM_CTRL, 0);
-
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_editmode(keyconf, keymap, true);
}
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 342eef063f4..8ec79ff50a9 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -43,19 +43,22 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_animsys.h"
-#include "BKE_action.h"
#include "BKE_modifier.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -82,8 +85,9 @@
#include "RNA_enum_types.h"
void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus);
-static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split);
-static int curve_delete_segments(Object *obedit, const bool split);
+static void adduplicateflagNurb(Object *obedit, View3D *v3d, ListBase *newnurb, const short flag, const bool split);
+static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split);
+static bool curve_delete_vertices(Object *obedit, View3D *v3d);
ListBase *object_editcurve_get(Object *ob)
{
@@ -162,7 +166,7 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
*origbezt_cpy = *origbezt;
keyIndex = init_cvKeyIndex(origbezt_cpy, key_index, nu_index, pt_index, vertex_index);
BLI_ghash_insert(gh, bezt, keyIndex);
- key_index += 12;
+ key_index += KEYELEM_FLOAT_LEN_BEZTRIPLE;
vertex_index += 3;
bezt++;
origbezt++;
@@ -182,7 +186,7 @@ static void init_editNurb_keyIndex(EditNurb *editnurb, ListBase *origBase)
*origbp_cpy = *origbp;
keyIndex = init_cvKeyIndex(origbp_cpy, key_index, nu_index, pt_index, vertex_index);
BLI_ghash_insert(gh, bp, keyIndex);
- key_index += 4;
+ key_index += KEYELEM_FLOAT_LEN_BPOINT;
bp++;
origbp++;
pt_index++;
@@ -465,13 +469,13 @@ static void switch_keys_direction(Curve *cu, Nurb *actnu)
if (getKeyIndexOrig_bezt(editnurb, bezt)) {
swap_v3_v3(fp, fp + 6);
*(fp + 9) = -*(fp + 9);
- fp += 12;
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
bezt++;
}
}
else {
- fp += a * 12;
+ fp += a * KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
@@ -481,13 +485,13 @@ static void switch_keys_direction(Curve *cu, Nurb *actnu)
while (a--) {
if (getKeyIndexOrig_bp(editnurb, bp)) {
*(fp + 3) = -*(fp + 3);
- fp += 4;
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
bp++;
}
}
else {
- fp += a * 4;
+ fp += a * KEYELEM_FLOAT_LEN_BPOINT;
}
}
@@ -538,12 +542,14 @@ static void key_to_bezt(float *key, BezTriple *basebezt, BezTriple *bezt)
memcpy(bezt, basebezt, sizeof(BezTriple));
memcpy(bezt->vec, key, sizeof(float) * 9);
bezt->alfa = key[9];
+ bezt->radius = key[10];
}
static void bezt_to_key(BezTriple *bezt, float *key)
{
memcpy(key, bezt->vec, sizeof(float) * 9);
key[9] = bezt->alfa;
+ key[10] = bezt->radius;
}
static void calc_keyHandles(ListBase *nurb, float *key)
@@ -566,7 +572,7 @@ static void calc_keyHandles(ListBase *nurb, float *key)
if (nu->flagu & CU_NURB_CYCLIC) {
prevp = bezt + (a - 1);
- prevfp = fp + (12 * (a - 1));
+ prevfp = fp + (KEYELEM_FLOAT_LEN_BEZTRIPLE * (a - 1));
}
else {
prevp = NULL;
@@ -574,7 +580,7 @@ static void calc_keyHandles(ListBase *nurb, float *key)
}
nextp = bezt + 1;
- nextfp = fp + 12;
+ nextfp = fp + KEYELEM_FLOAT_LEN_BEZTRIPLE;
while (a--) {
key_to_bezt(fp, bezt, &cur);
@@ -599,16 +605,16 @@ static void calc_keyHandles(ListBase *nurb, float *key)
}
else {
nextp++;
- nextfp += 12;
+ nextfp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
bezt++;
- fp += 12;
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
a = nu->pntsu * nu->pntsv;
- fp += a * 4;
+ fp += a * KEYELEM_FLOAT_LEN_BPOINT;
}
nu = nu->next;
@@ -628,7 +634,7 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
BezTriple *bezt, *oldbezt;
BPoint *bp, *oldbp;
Nurb *nu, *newnu;
- int totvert = BKE_nurbList_verts_count(&editnurb->nurbs);
+ int totvert = BKE_keyblock_curve_element_count(&editnurb->nurbs);
float (*ofs)[3] = NULL;
float *oldkey, *newkey, *ofp;
@@ -668,7 +674,9 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
sub_v3_v3v3(ofs[i], bezt->vec[j], oldbezt->vec[j]);
i++;
}
- ofs[i++][0] = bezt->alfa - oldbezt->alfa;
+ ofs[i][0] = bezt->alfa - oldbezt->alfa;
+ ofs[i][1] = bezt->radius - oldbezt->radius;
+ i++;
}
else {
i += 4;
@@ -684,6 +692,7 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
if (oldbp) {
sub_v3_v3v3(ofs[i], bp->vec, oldbp->vec);
ofs[i + 1][0] = bp->alfa - oldbp->alfa;
+ ofs[i + 1][1] = bp->radius - oldbp->radius;
}
i += 2;
bp++;
@@ -720,22 +729,23 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
int j;
oldbezt = getKeyIndexOrig_bezt(editnurb, bezt);
- for (j = 0; j < 3; ++j, ++i) {
- copy_v3_v3(fp, bezt->vec[j]);
+ for (j = 0; j < 3; j++, i++) {
+ copy_v3_v3(&fp[j * 3], bezt->vec[j]);
if (restore && oldbezt) {
copy_v3_v3(newbezt->vec[j], oldbezt->vec[j]);
}
-
- fp += 3;
}
- fp[0] = bezt->alfa;
+ fp[9] = bezt->alfa;
+ fp[10] = bezt->radius;
if (restore && oldbezt) {
newbezt->alfa = oldbezt->alfa;
+ newbezt->radius = oldbezt->radius;
}
- fp += 3; ++i; /* alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ i++;
bezt++;
newbezt++;
}
@@ -750,13 +760,15 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
copy_v3_v3(fp, bp->vec);
fp[3] = bp->alfa;
+ fp[4] = bp->radius;
if (restore && oldbp) {
copy_v3_v3(newbp->vec, oldbp->vec);
newbp->alfa = oldbp->alfa;
+ newbp->radius = oldbp->radius;
}
- fp += 4;
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
bp++;
newbp++;
i += 2;
@@ -778,34 +790,33 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
int j;
curofp = ofp + index;
- for (j = 0; j < 3; ++j, ++i) {
- copy_v3_v3(fp, curofp);
+ for (j = 0; j < 3; j++, i++) {
+ copy_v3_v3(&fp[j * 3], &curofp[j * 3]);
if (apply_offset) {
- add_v3_v3(fp, ofs[i]);
+ add_v3_v3(&fp[j * 3], ofs[i]);
}
-
- fp += 3; curofp += 3;
}
- fp[0] = curofp[0];
+ fp[9] = curofp[9];
+ fp[10] = curofp[10];
if (apply_offset) {
/* apply alfa offsets */
- add_v3_v3(fp, ofs[i]);
+ add_v3_v3(fp + 9, ofs[i]);
i++;
}
- fp += 3; /* alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
else {
int j;
- for (j = 0; j < 3; ++j, ++i) {
- copy_v3_v3(fp, bezt->vec[j]);
- fp += 3;
+ for (j = 0; j < 3; j++, i++) {
+ copy_v3_v3(&fp[j * 3], bezt->vec[j]);
}
- fp[0] = bezt->alfa;
+ fp[9] = bezt->alfa;
+ fp[10] = bezt->radius;
- fp += 3; /* alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
bezt++;
}
@@ -820,18 +831,20 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
curofp = ofp + index;
copy_v3_v3(fp, curofp);
fp[3] = curofp[3];
+ fp[4] = curofp[4];
if (apply_offset) {
add_v3_v3(fp, ofs[i]);
- fp[3] += ofs[i + 1][0];
+ add_v3_v3(&fp[3], ofs[i + 1]);
}
}
else {
copy_v3_v3(fp, bp->vec);
fp[3] = bp->alfa;
+ fp[4] = bp->radius;
}
- fp += 4;
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
bp++;
i += 2;
}
@@ -1279,61 +1292,117 @@ static int separate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *oldob, *newob;
- Base *oldbase, *newbase;
- Curve *oldcu, *newcu;
- EditNurb *newedit;
- ListBase newnurb = {NULL, NULL};
-
- oldbase = CTX_data_active_base(C);
- oldob = oldbase->object;
- oldcu = oldob->data;
-
- if (oldcu->key) {
- BKE_report(op->reports, RPT_ERROR, "Cannot separate a curve with vertex keys");
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ struct {
+ int changed;
+ int unselected;
+ int error_vertex_keys;
+ int error_generic;
+ } status = {0};
WM_cursor_wait(1);
- /* 1. duplicate geometry and check for valid selection for separate */
- adduplicateflagNurb(oldob, &newnurb, SELECT, true);
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &bases_len);
+ for (uint b_index = 0; b_index < bases_len; b_index++) {
+ Base *oldbase = bases[b_index];
+ Base *newbase;
+ Object *oldob, *newob;
+ Curve *oldcu, *newcu;
+ EditNurb *newedit;
+ ListBase newnurb = {NULL, NULL};
+
+ oldob = oldbase->object;
+ oldcu = oldob->data;
+
+ if (oldcu->key) {
+ status.error_vertex_keys++;
+ continue;
+ }
- if (BLI_listbase_is_empty(&newnurb)) {
- WM_cursor_wait(0);
- BKE_report(op->reports, RPT_ERROR, "Cannot separate current selection");
- return OPERATOR_CANCELLED;
- }
+ if (!ED_curve_select_check(v3d, oldcu->editnurb)) {
+ status.unselected++;
+ continue;
+ }
+
+ /* 1. Duplicate geometry and check for valid selection for separate. */
+ adduplicateflagNurb(oldob, v3d, &newnurb, SELECT, true);
- /* 2. duplicate the object and data */
- newbase = ED_object_add_duplicate(bmain, scene, oldbase, 0); /* 0 = fully linked */
- DAG_relations_tag_update(bmain);
+ if (BLI_listbase_is_empty(&newnurb)) {
+ status.error_generic++;
+ continue;
+ }
- newob = newbase->object;
- newcu = newob->data = BKE_curve_copy(bmain, oldcu);
- newcu->editnurb = NULL;
- id_us_min(&oldcu->id); /* because new curve is a copy: reduce user count */
+ /* 2. Duplicate the object and data. */
+ newbase = ED_object_add_duplicate(bmain, scene, view_layer, oldbase, 0); /* 0 = fully linked. */
+ DEG_relations_tag_update(bmain);
- /* 3. put new object in editmode, clear it and set separated nurbs */
- ED_curve_editnurb_make(newob);
- newedit = newcu->editnurb;
- BKE_nurbList_free(&newedit->nurbs);
- BKE_curve_editNurb_keyIndex_free(&newedit->keyindex);
- BLI_movelisttolist(&newedit->nurbs, &newnurb);
+ newob = newbase->object;
+ newcu = newob->data = BKE_curve_copy(bmain, oldcu);
+ newcu->editnurb = NULL;
+ id_us_min(&oldcu->id); /* Because new curve is a copy: reduce user count. */
- /* 4. put old object out of editmode and delete separated geometry */
- ED_curve_editnurb_load(bmain, newob);
- ED_curve_editnurb_free(newob);
- curve_delete_segments(oldob, true);
+ /* 3. Put new object in editmode, clear it and set separated nurbs. */
+ ED_curve_editnurb_make(newob);
+ newedit = newcu->editnurb;
+ BKE_nurbList_free(&newedit->nurbs);
+ BKE_curve_editNurb_keyIndex_free(&newedit->keyindex);
+ BLI_movelisttolist(&newedit->nurbs, &newnurb);
- DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
- DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */
+ /* 4. Put old object out of editmode and delete separated geometry. */
+ ED_curve_editnurb_load(bmain, newob);
+ ED_curve_editnurb_free(newob);
+ curve_delete_segments(oldob, v3d, true);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, oldob->data);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob);
+ DEG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* This is the original one. */
+ DEG_id_tag_update(&newob->id, OB_RECALC_DATA); /* This is the separated one. */
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, oldob->data);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob);
+ status.changed++;
+ }
+ MEM_freeN(bases);
WM_cursor_wait(0);
+ if (status.unselected == bases_len) {
+ BKE_report(op->reports, RPT_ERROR, "No point was selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ const int tot_errors = status.error_vertex_keys + status.error_generic;
+ if (tot_errors > 0) {
+
+ /* Some curves changed, but some curves failed: don't explain why it failed. */
+ if (status.changed) {
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ tot_errors == 1 ? "%d curve could not be separated" :
+ "%d curves could not be separated",
+ tot_errors);
+ return OPERATOR_FINISHED;
+ }
+
+ /* All curves failed: If there is more than one error give a generic error report. */
+ if (((status.error_vertex_keys ? 1 : 0) + (status.error_generic ? 1 : 0)) > 1) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ tot_errors == 1 ? "Could not separate selected curves" :
+ "Could not separate selected curve");
+ }
+
+ /* All curves failed due to the same error. */
+ if (status.error_vertex_keys) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot separate curves with vertex keys");
+ }
+ else {
+ BLI_assert(status.error_generic);
+ BKE_report(op->reports, RPT_ERROR, "Cannot separate current selection");
+ }
+ return OPERATOR_CANCELLED;
+ }
+
return OPERATOR_FINISHED;
}
@@ -1357,31 +1426,50 @@ void CURVE_OT_separate(wmOperatorType *ot)
static int curve_split_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
- ListBase newnurb = {NULL, NULL};
-
- adduplicateflagNurb(obedit, &newnurb, SELECT, true);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ int ok = -1;
- if (BLI_listbase_is_empty(&newnurb) == false) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
Curve *cu = obedit->data;
+
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
+
+ ListBase newnurb = {NULL, NULL};
+
+ adduplicateflagNurb(obedit, v3d, &newnurb, SELECT, true);
+
+ if (BLI_listbase_is_empty(&newnurb)) {
+ ok = MAX2(ok, 0);
+ continue;
+ }
+
+ ListBase *editnurb = object_editcurve_get(obedit);
const int len_orig = BLI_listbase_count(editnurb);
- curve_delete_segments(obedit, true);
+ curve_delete_segments(obedit, v3d, true);
cu->actnu -= len_orig - BLI_listbase_count(editnurb);
BLI_movelisttolist(editnurb, &newnurb);
- if (ED_curve_updateAnimPaths(obedit->data))
+ if (ED_curve_updateAnimPaths(obedit->data)) {
WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ }
+ ok = 1;
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
}
- else {
+ MEM_freeN(objects);
+
+ if (ok == 0) {
BKE_report(op->reports, RPT_ERROR, "Cannot split current selection");
return OPERATOR_CANCELLED;
}
-
return OPERATOR_FINISHED;
}
@@ -1677,7 +1765,7 @@ static void ed_surf_delete_selected(Object *obedit)
}
}
-static void ed_curve_delete_selected(Object *obedit)
+static void ed_curve_delete_selected(Object *obedit, View3D *v3d)
{
Curve *cu = obedit->data;
EditNurb *editnurb = cu->editnurb;
@@ -1696,7 +1784,7 @@ static void ed_curve_delete_selected(Object *obedit)
a = nu->pntsu;
if (a) {
while (a) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
/* pass */
}
else {
@@ -1758,7 +1846,7 @@ static void ed_curve_delete_selected(Object *obedit)
if (nu->type == CU_BEZIER) {
bezt = nu->bezt;
for (a = 0; a < nu->pntsu; a++) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
memmove(bezt, bezt + 1, (nu->pntsu - a - 1) * sizeof(BezTriple));
keyIndex_delBezt(editnurb, bezt);
keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu - a - 1);
@@ -1949,7 +2037,7 @@ static bool calc_duplicate_actvert(
return false;
}
-static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
+static void adduplicateflagNurb(Object *obedit, View3D *v3d, ListBase *newnurb,
const short flag, const bool split)
{
ListBase *editnurb = object_editcurve_get(obedit);
@@ -2095,7 +2183,7 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
}
}
else {
- if (ED_curve_nurb_select_check(cu, nu)) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
/* a rectangular area in nurb has to be selected and if splitting must be in U or V direction */
usel = MEM_callocN(nu->pntsu, "adduplicateN3");
bp = nu->bp;
@@ -2302,28 +2390,41 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = (Curve *)obedit->data;
- EditNurb *editnurb = cu->editnurb;
- Nurb *nu;
- int i;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
- for (nu = editnurb->nurbs.first, i = 0; nu; nu = nu->next, i++) {
- if (ED_curve_nurb_select_check(cu, nu)) {
- BKE_nurb_direction_switch(nu);
- keyData_switchDirectionNurb(cu, nu);
- if ((i == cu->actnu) && (cu->actvert != CU_ACT_NONE)) {
- cu->actvert = (nu->pntsu - 1) - cu->actvert;
- }
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
}
- }
- if (ED_curve_updateAnimPaths(obedit->data))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ EditNurb *editnurb = cu->editnurb;
+ Nurb *nu;
+ int i;
+
+ for (nu = editnurb->nurbs.first, i = 0; nu; nu = nu->next, i++) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
+ BKE_nurb_direction_switch(nu);
+ keyData_switchDirectionNurb(cu, nu);
+ if ((i == cu->actnu) && (cu->actvert != CU_ACT_NONE)) {
+ cu->actvert = (nu->pntsu - 1) - cu->actvert;
+ }
+ }
+ }
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ }
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -2369,7 +2470,7 @@ static int set_goal_weight_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
@@ -2422,7 +2523,7 @@ static int set_radius_exec(bContext *C, wmOperator *op)
}
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_FINISHED;
}
@@ -2574,7 +2675,7 @@ static int smooth_exec(bContext *C, wmOperator *UNUSED(op))
}
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_FINISHED;
}
@@ -2765,7 +2866,7 @@ static int curve_smooth_weight_exec(bContext *C, wmOperator *UNUSED(op))
curve_smooth_value(editnurb, offsetof(BezTriple, weight), offsetof(BPoint, weight));
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_FINISHED;
}
@@ -2793,7 +2894,7 @@ static int curve_smooth_radius_exec(bContext *C, wmOperator *UNUSED(op))
curve_smooth_value(editnurb, offsetof(BezTriple, radius), offsetof(BPoint, radius));
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_FINISHED;
}
@@ -2821,7 +2922,7 @@ static int curve_smooth_tilt_exec(bContext *C, wmOperator *UNUSED(op))
curve_smooth_value(editnurb, offsetof(BezTriple, alfa), offsetof(BPoint, alfa));
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_FINISHED;
}
@@ -2845,58 +2946,71 @@ void CURVE_OT_smooth_tilt(wmOperatorType *ot)
static int hide_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- ListBase *editnurb = object_editcurve_get(obedit);
- Nurb *nu;
- BPoint *bp;
- BezTriple *bezt;
- int a, sel;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
const bool invert = RNA_boolean_get(op->ptr, "unselected");
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- sel = 0;
- while (a--) {
- if (invert == 0 && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
- bezt->hide = 1;
- }
- else if (invert && !BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
- bezt->hide = 1;
- }
- if (bezt->hide) sel++;
- bezt++;
- }
- if (sel == nu->pntsu) nu->hide = 1;
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+
+ if (!(invert || ED_curve_select_check(v3d, cu->editnurb))) {
+ continue;
}
- else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- sel = 0;
- while (a--) {
- if (invert == 0 && (bp->f1 & SELECT)) {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
- bp->hide = 1;
+
+ ListBase *editnurb = object_editcurve_get(obedit);
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a, sel;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ sel = 0;
+ while (a--) {
+ if (invert == 0 && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
+ select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ bezt->hide = 1;
+ }
+ else if (invert && !BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
+ select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ bezt->hide = 1;
+ }
+ if (bezt->hide) sel++;
+ bezt++;
}
- else if (invert && (bp->f1 & SELECT) == 0) {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
- bp->hide = 1;
+ if (sel == nu->pntsu) nu->hide = 1;
+ }
+ else {
+ bp = nu->bp;
+ a = nu->pntsu * nu->pntsv;
+ sel = 0;
+ while (a--) {
+ if (invert == 0 && (bp->f1 & SELECT)) {
+ select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ bp->hide = 1;
+ }
+ else if (invert && (bp->f1 & SELECT) == 0) {
+ select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ bp->hide = 1;
+ }
+ if (bp->hide) sel++;
+ bp++;
}
- if (bp->hide) sel++;
- bp++;
+ if (sel == nu->pntsu * nu->pntsv) nu->hide = 1;
}
- if (sel == nu->pntsu * nu->pntsv) nu->hide = 1;
}
- }
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -2922,44 +3036,57 @@ void CURVE_OT_hide(wmOperatorType *ot)
static int reveal_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
- Nurb *nu;
- BPoint *bp;
- BezTriple *bezt;
- int a;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool select = RNA_boolean_get(op->ptr, "select");
+ bool changed_multi = false;
- for (nu = editnurb->first; nu; nu = nu->next) {
- nu->hide = 0;
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if (bezt->hide) {
- select_beztriple(bezt, select, SELECT, HIDDEN);
- bezt->hide = 0;
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ListBase *editnurb = object_editcurve_get(obedit);
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+ bool changed = false;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ nu->hide = 0;
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ if (bezt->hide) {
+ select_beztriple(bezt, select, SELECT, HIDDEN);
+ bezt->hide = 0;
+ changed = true;
+ }
+ bezt++;
}
- bezt++;
}
- }
- else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- if (bp->hide) {
- select_bpoint(bp, select, SELECT, HIDDEN);
- bp->hide = 0;
+ else {
+ bp = nu->bp;
+ a = nu->pntsu * nu->pntsv;
+ while (a--) {
+ if (bp->hide) {
+ select_bpoint(bp, select, SELECT, HIDDEN);
+ bp->hide = 0;
+ changed = true;
+ }
+ bp++;
}
- bp++;
}
}
- }
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
+ if (changed) {
+ DEG_id_tag_update(obedit->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ changed_multi = true;
+ }
+ }
+ MEM_freeN(objects);
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void CURVE_OT_reveal(wmOperatorType *ot)
@@ -2985,7 +3112,7 @@ void CURVE_OT_reveal(wmOperatorType *ot)
* curve nodes (Bezier or NURB). If there are no valid segment
* selections within the current selection, nothing happens.
*/
-static void subdividenurb(Object *obedit, int number_cuts)
+static void subdividenurb(Object *obedit, View3D *v3d, int number_cuts)
{
Curve *cu = obedit->data;
EditNurb *editnurb = cu->editnurb;
@@ -3017,7 +3144,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
break;
}
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt) && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nextbezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nextbezt)) {
amount += number_cuts;
}
bezt++;
@@ -3039,7 +3166,7 @@ static void subdividenurb(Object *obedit, int number_cuts)
break;
}
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt) && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nextbezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nextbezt)) {
float prevvec[3][3];
memcpy(prevvec, bezt->vec, sizeof(float) * 9);
@@ -3368,16 +3495,30 @@ static void subdividenurb(Object *obedit, int number_cuts)
static int subdivide_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- int number_cuts = RNA_int_get(op->ptr, "number_cuts");
+ const int number_cuts = RNA_int_get(op->ptr, "number_cuts");
- subdividenurb(obedit, number_cuts);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
- if (ED_curve_updateAnimPaths(obedit->data))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
+
+ subdividenurb(obedit, v3d, number_cuts);
+
+ if (ED_curve_updateAnimPaths(cu))
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, cu);
+ DEG_id_tag_update(obedit->data, 0);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3407,7 +3548,7 @@ void CURVE_OT_subdivide(wmOperatorType *ot)
static void ED_curve_pick_vert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
{
- struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; float dist; int hpoint, select; float mval_fl[2]; } *data = userData;
+ struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; float dist; int hpoint, select; float mval_fl[2]; bool is_changed; } *data = userData;
short flag;
float dist_test;
@@ -3438,26 +3579,41 @@ static void ED_curve_pick_vert__doClosest(void *userData, Nurb *nu, BPoint *bp,
data->bezt = bezt;
data->nurb = nu;
data->hpoint = bezt ? beztindex : 0;
+ data->is_changed = true;
}
}
bool ED_curve_pick_vert(
- ViewContext *vc, short sel, const int mval[2],
- Nurb **r_nurb, BezTriple **r_bezt, BPoint **r_bp, short *r_handle)
+ ViewContext *vc, short sel,
+ Nurb **r_nurb, BezTriple **r_bezt, BPoint **r_bp, short *r_handle,
+ Base **r_base)
{
/* (sel == 1): selected gets a disadvantage */
/* in nurb and bezt or bp the nearest is written */
/* return 0 1 2: handlepunt */
- struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; float dist; int hpoint, select; float mval_fl[2]; } data = {NULL};
+ struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; float dist; int hpoint, select; float mval_fl[2]; bool is_changed; } data = {NULL};
data.dist = ED_view3d_select_dist_px();
data.hpoint = 0;
data.select = sel;
- data.mval_fl[0] = mval[0];
- data.mval_fl[1] = mval[1];
+ data.mval_fl[0] = vc->mval[0];
+ data.mval_fl[1] = vc->mval[1];
+
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc->view_layer, vc->v3d, &bases_len);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base = bases[base_index];
+ data.is_changed = false;
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- nurbs_foreachScreenVert(vc, ED_curve_pick_vert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ ED_view3d_viewcontext_init_object(vc, base->object);
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ nurbs_foreachScreenVert(vc, ED_curve_pick_vert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ if (r_base && data.is_changed) {
+ *r_base = base;
+ }
+ }
+ MEM_freeN(bases);
*r_nurb = data.nurb;
*r_bezt = data.bezt;
@@ -3471,7 +3627,7 @@ bool ED_curve_pick_vert(
}
static void findselectedNurbvert(
- Curve *cu,
+ Curve *cu, View3D *v3d,
Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp)
{
/* in nu and (bezt or bp) selected are written if there's 1 sel. */
@@ -3491,7 +3647,7 @@ static void findselectedNurbvert(
bezt1 = nu1->bezt;
a = nu1->pntsu;
while (a--) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1)) {
if (*r_nu != NULL && *r_nu != nu1) {
*r_nu = NULL;
*r_bp = NULL;
@@ -3541,6 +3697,7 @@ static void findselectedNurbvert(
static int set_spline_type_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
+ View3D *v3d = CTX_wm_view3d(C);
ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
bool changed = false;
@@ -3554,7 +3711,7 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
}
for (nu = editnurb->first; nu; nu = nu->next) {
- if (ED_curve_nurb_select_check(obedit->data, nu)) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
const int pntsu_prev = nu->pntsu;
if (BKE_nurb_type_convert(nu, type, use_handles)) {
changed = true;
@@ -3572,7 +3729,7 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
if (ED_curve_updateAnimPaths(obedit->data))
WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
if (changed_size) {
@@ -3620,14 +3777,27 @@ void CURVE_OT_spline_type_set(wmOperatorType *ot)
static int set_handle_type_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ const int handle_type = RNA_enum_get(op->ptr, "type");
- BKE_nurbList_handles_set(editnurb, RNA_enum_get(op->ptr, "type"));
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
+
+ ListBase *editnurb = object_editcurve_get(obedit);
+ BKE_nurbList_handles_set(editnurb, handle_type);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3664,15 +3834,28 @@ void CURVE_OT_handle_type_set(wmOperatorType *ot)
static int curve_normals_make_consistent_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
const bool calc_length = RNA_boolean_get(op->ptr, "calc_length");
- BKE_nurbList_handles_recalculate(editnurb, calc_length, SELECT);
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
+ ListBase *editnurb = object_editcurve_get(obedit);
+ BKE_nurbList_handles_recalculate(editnurb, calc_length, SELECT);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3791,7 +3974,7 @@ typedef struct NurbSort {
static ListBase nsortbase = {NULL, NULL};
/* static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
-static void make_selection_list_nurb(Curve *cu, ListBase *editnurb)
+static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
{
ListBase nbase = {NULL, NULL};
NurbSort *nus, *nustest, *headdo, *taildo;
@@ -3801,7 +3984,7 @@ static void make_selection_list_nurb(Curve *cu, ListBase *editnurb)
int a;
for (nu = editnurb->first; nu; nu = nu->next) {
- if (ED_curve_nurb_select_check(cu, nu)) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
nus = (NurbSort *)MEM_callocN(sizeof(NurbSort), "sort");
BLI_addhead(&nbase, nus);
@@ -3858,7 +4041,14 @@ static void make_selection_list_nurb(Curve *cu, ListBase *editnurb)
}
}
-static void merge_2_nurb(wmOperator *op, Curve *cu, ListBase *editnurb, Nurb *nu1, Nurb *nu2)
+enum {
+ CURVE_MERGE_OK = 0,
+ CURVE_MERGE_ERR_FEW_SELECTION,
+ CURVE_MERGE_ERR_RESOLUTION_ALL,
+ CURVE_MERGE_ERR_RESOLUTION_SOME,
+};
+
+static bool merge_2_nurb(Curve *cu, ListBase *editnurb, Nurb *nu1, Nurb *nu2)
{
BPoint *bp, *bp1, *bp2, *temp;
float len1, len2;
@@ -3894,7 +4084,7 @@ static void merge_2_nurb(wmOperator *op, Curve *cu, ListBase *editnurb, Nurb *nu
else {
/* rotate again, now its OK! */
if (nu1->pntsv != 1) rotate_direction_nurb(nu1);
- return;
+ return true;
}
}
}
@@ -3924,15 +4114,14 @@ static void merge_2_nurb(wmOperator *op, Curve *cu, ListBase *editnurb, Nurb *nu
/* rotate again, now its OK! */
if (nu1->pntsu == 1) rotate_direction_nurb(nu1);
if (nu2->pntsv != 1) rotate_direction_nurb(nu2);
- return;
+ return true;
}
}
}
}
if (nu1->pntsv != nu2->pntsv) {
- BKE_report(op->reports, RPT_ERROR, "Resolution does not match");
- return;
+ return false;
}
/* ok, now nu1 has the rightmost column and nu2 the leftmost column selected */
@@ -3995,22 +4184,21 @@ static void merge_2_nurb(wmOperator *op, Curve *cu, ListBase *editnurb, Nurb *nu
MEM_freeN(temp);
BLI_remlink(editnurb, nu2);
BKE_nurb_free(nu2);
+ return true;
}
-static int merge_nurb(bContext *C, wmOperator *op)
+static int merge_nurb(View3D *v3d, Object *obedit)
{
- Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
ListBase *editnurb = object_editcurve_get(obedit);
NurbSort *nus1, *nus2;
bool ok = true;
- make_selection_list_nurb(cu, editnurb);
+ make_selection_list_nurb(v3d, editnurb);
if (nsortbase.first == nsortbase.last) {
BLI_freelistN(&nsortbase);
- BKE_report(op->reports, RPT_ERROR, "Too few selections to merge");
- return OPERATOR_CANCELLED;
+ return CURVE_MERGE_ERR_FEW_SELECTION;
}
nus1 = nsortbase.first;
@@ -4022,7 +4210,7 @@ static int merge_nurb(bContext *C, wmOperator *op)
/* pass */
}
else {
- ok = 0;
+ ok = false;
}
}
else if (nus2->nu->pntsv == 1) {
@@ -4030,7 +4218,7 @@ static int merge_nurb(bContext *C, wmOperator *op)
/* pass */
}
else {
- ok = 0;
+ ok = false;
}
}
else if (nus1->nu->pntsu == nus2->nu->pntsu || nus1->nu->pntsv == nus2->nu->pntsv) {
@@ -4040,233 +4228,309 @@ static int merge_nurb(bContext *C, wmOperator *op)
/* pass */
}
else {
- ok = 0;
+ ok = false;
}
- if (ok == 0) {
- BKE_report(op->reports, RPT_ERROR, "Resolution does not match");
+ if (ok == false) {
BLI_freelistN(&nsortbase);
- return OPERATOR_CANCELLED;
+ return CURVE_MERGE_ERR_RESOLUTION_ALL;
}
while (nus2) {
- merge_2_nurb(op, cu, editnurb, nus1->nu, nus2->nu);
+ /* There is a change a few curves merged properly, but not all.
+ * In this case we still update the curve, yet report the error. */
+ ok &= merge_2_nurb(cu, editnurb, nus1->nu, nus2->nu);
nus2 = nus2->next;
}
BLI_freelistN(&nsortbase);
-
BKE_curve_nurb_active_set(obedit->data, NULL);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
-
- return OPERATOR_FINISHED;
+ return ok ? CURVE_MERGE_OK : CURVE_MERGE_ERR_RESOLUTION_SOME;
}
static int make_segment_exec(bContext *C, wmOperator *op)
{
- /* joins 2 curves */
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- ListBase *nubase = object_editcurve_get(obedit);
- Nurb *nu, *nu1 = NULL, *nu2 = NULL;
- BPoint *bp;
- bool ok = false;
- /* int a; */ /* UNUSED */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
- /* first decide if this is a surface merge! */
- if (obedit->type == OB_SURF) nu = nubase->first;
- else nu = NULL;
+ struct {
+ int changed;
+ int unselected;
+ int error_selected_few;
+ int error_resolution;
+ int error_generic;
+ } status = {0};
+
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
- while (nu) {
- const int nu_select_num = ED_curve_nurb_select_count(cu, nu);
- if (nu_select_num) {
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ status.unselected++;
+ continue;
+ }
- if (nu->pntsu > 1 && nu->pntsv > 1) {
- break;
- }
+ ListBase *nubase = object_editcurve_get(obedit);
+ Nurb *nu, *nu1 = NULL, *nu2 = NULL;
+ BPoint *bp;
+ bool ok = false;
- if (nu_select_num > 1) {
- break;
- }
- else {
- /* only 1 selected, not first or last, a little complex, but intuitive */
- if (nu->pntsv == 1) {
- if ((nu->bp->f1 & SELECT) || (nu->bp[nu->pntsu - 1].f1 & SELECT)) {
- /* pass */
- }
- else {
- break;
+ /* first decide if this is a surface merge! */
+ if (obedit->type == OB_SURF) nu = nubase->first;
+ else nu = NULL;
+
+ while (nu) {
+ const int nu_select_num = ED_curve_nurb_select_count(v3d, nu);
+ if (nu_select_num) {
+
+ if (nu->pntsu > 1 && nu->pntsv > 1) {
+ break;
+ }
+
+ if (nu_select_num > 1) {
+ break;
+ }
+ else {
+ /* only 1 selected, not first or last, a little complex, but intuitive */
+ if (nu->pntsv == 1) {
+ if ((nu->bp->f1 & SELECT) || (nu->bp[nu->pntsu - 1].f1 & SELECT)) {
+ /* pass */
+ }
+ else {
+ break;
+ }
}
}
}
+ nu = nu->next;
}
- nu = nu->next;
- }
- if (nu)
- return merge_nurb(C, op);
+ if (nu) {
+ int merge_result = merge_nurb(v3d, obedit);
+ switch (merge_result) {
+ case CURVE_MERGE_OK:
+ status.changed++;
+ goto curve_merge_tag_object;
+ case CURVE_MERGE_ERR_RESOLUTION_SOME:
+ status.error_resolution++;
+ goto curve_merge_tag_object;
+ case CURVE_MERGE_ERR_FEW_SELECTION:
+ status.error_selected_few++;
+ break;
+ case CURVE_MERGE_ERR_RESOLUTION_ALL:
+ status.error_resolution++;
+ break;
+ }
+ continue;
+ }
- /* find both nurbs and points, nu1 will be put behind nu2 */
- for (nu = nubase->first; nu; nu = nu->next) {
- if (nu->pntsu == 1)
- nu->flagu &= ~CU_NURB_CYCLIC;
+ /* find both nurbs and points, nu1 will be put behind nu2 */
+ for (nu = nubase->first; nu; nu = nu->next) {
+ if (nu->pntsu == 1)
+ nu->flagu &= ~CU_NURB_CYCLIC;
- if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic */
- if (nu->type == CU_BEZIER) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, &(nu->bezt[nu->pntsu - 1]))) {
- /* Last point is selected, preferred for nu2 */
- if (nu2 == NULL) {
- nu2 = nu;
- }
- else if (nu1 == NULL) {
- nu1 = nu;
-
- /* Just in case both of first/last CV are selected check
- * whether we really need to switch the direction.
- */
- if (!BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nu1->bezt)) {
- BKE_nurb_direction_switch(nu1);
- keyData_switchDirectionNurb(cu, nu1);
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* not cyclic */
+ if (nu->type == CU_BEZIER) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &(nu->bezt[nu->pntsu - 1]))) {
+ /* Last point is selected, preferred for nu2 */
+ if (nu2 == NULL) {
+ nu2 = nu;
+ }
+ else if (nu1 == NULL) {
+ nu1 = nu;
+
+ /* Just in case both of first/last CV are selected check
+ * whether we really need to switch the direction.
+ */
+ if (!BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nu1->bezt)) {
+ BKE_nurb_direction_switch(nu1);
+ keyData_switchDirectionNurb(cu, nu1);
+ }
}
}
- }
- else if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nu->bezt)) {
- /* First point is selected, preferred for nu1 */
- if (nu1 == NULL) {
- nu1 = nu;
- }
- else if (nu2 == NULL) {
- nu2 = nu;
-
- /* Just in case both of first/last CV are selected check
- * whether we really need to switch the direction.
- */
- if (!BEZT_ISSEL_ANY_HIDDENHANDLES(cu, &(nu->bezt[nu2->pntsu - 1]))) {
- BKE_nurb_direction_switch(nu2);
- keyData_switchDirectionNurb(cu, nu2);
+ else if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nu->bezt)) {
+ /* First point is selected, preferred for nu1 */
+ if (nu1 == NULL) {
+ nu1 = nu;
+ }
+ else if (nu2 == NULL) {
+ nu2 = nu;
+
+ /* Just in case both of first/last CV are selected check
+ * whether we really need to switch the direction.
+ */
+ if (!BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &(nu->bezt[nu2->pntsu - 1]))) {
+ BKE_nurb_direction_switch(nu2);
+ keyData_switchDirectionNurb(cu, nu2);
+ }
}
}
}
- }
- else if (nu->pntsv == 1) {
- /* Same logic as above: if first point is selected spline is
- * preferred for nu1, if last point is selected spline is
- * preferred for u2u.
- */
+ else if (nu->pntsv == 1) {
+ /* Same logic as above: if first point is selected spline is
+ * preferred for nu1, if last point is selected spline is
+ * preferred for u2u.
+ */
- bp = nu->bp;
- if (bp[nu->pntsu - 1].f1 & SELECT) {
- if (nu2 == NULL) {
- nu2 = nu;
- }
- else if (nu1 == NULL) {
- nu1 = nu;
+ bp = nu->bp;
+ if (bp[nu->pntsu - 1].f1 & SELECT) {
+ if (nu2 == NULL) {
+ nu2 = nu;
+ }
+ else if (nu1 == NULL) {
+ nu1 = nu;
- if ((bp->f1 & SELECT) == 0) {
- BKE_nurb_direction_switch(nu);
- keyData_switchDirectionNurb(cu, nu);
+ if ((bp->f1 & SELECT) == 0) {
+ BKE_nurb_direction_switch(nu);
+ keyData_switchDirectionNurb(cu, nu);
+ }
}
}
- }
- else if (bp->f1 & SELECT) {
- if (nu1 == NULL) {
- nu1 = nu;
- }
- else if (nu2 == NULL) {
- nu2 = nu;
+ else if (bp->f1 & SELECT) {
+ if (nu1 == NULL) {
+ nu1 = nu;
+ }
+ else if (nu2 == NULL) {
+ nu2 = nu;
- if ((bp[nu->pntsu - 1].f1 & SELECT) == 0) {
- BKE_nurb_direction_switch(nu);
- keyData_switchDirectionNurb(cu, nu);
+ if ((bp[nu->pntsu - 1].f1 & SELECT) == 0) {
+ BKE_nurb_direction_switch(nu);
+ keyData_switchDirectionNurb(cu, nu);
+ }
}
}
}
}
- }
- if (nu1 && nu2) {
- /* Got second spline, no need to loop over rest of the splines. */
- break;
+ if (nu1 && nu2) {
+ /* Got second spline, no need to loop over rest of the splines. */
+ break;
+ }
}
- }
- if ((nu1 && nu2) && (nu1 != nu2)) {
- if (nu1->type == nu2->type) {
- if (nu1->type == CU_BEZIER) {
- BezTriple *bezt = (BezTriple *)MEM_mallocN((nu1->pntsu + nu2->pntsu) * sizeof(BezTriple), "addsegmentN");
- ED_curve_beztcpy(cu->editnurb, bezt, nu2->bezt, nu2->pntsu);
- ED_curve_beztcpy(cu->editnurb, bezt + nu2->pntsu, nu1->bezt, nu1->pntsu);
+ if ((nu1 && nu2) && (nu1 != nu2)) {
+ if (nu1->type == nu2->type) {
+ if (nu1->type == CU_BEZIER) {
+ BezTriple *bezt = (BezTriple *)MEM_mallocN((nu1->pntsu + nu2->pntsu) * sizeof(BezTriple), "addsegmentN");
+ ED_curve_beztcpy(cu->editnurb, bezt, nu2->bezt, nu2->pntsu);
+ ED_curve_beztcpy(cu->editnurb, bezt + nu2->pntsu, nu1->bezt, nu1->pntsu);
- MEM_freeN(nu1->bezt);
- nu1->bezt = bezt;
- nu1->pntsu += nu2->pntsu;
- BLI_remlink(nubase, nu2);
- keyIndex_delNurb(cu->editnurb, nu2);
- BKE_nurb_free(nu2); nu2 = NULL;
- BKE_nurb_handles_calc(nu1);
- }
- else {
- bp = (BPoint *)MEM_mallocN((nu1->pntsu + nu2->pntsu) * sizeof(BPoint), "addsegmentN2");
- ED_curve_bpcpy(cu->editnurb, bp, nu2->bp, nu2->pntsu);
- ED_curve_bpcpy(cu->editnurb, bp + nu2->pntsu, nu1->bp, nu1->pntsu);
- MEM_freeN(nu1->bp);
- nu1->bp = bp;
-
- /* a = nu1->pntsu + nu1->orderu; */ /* UNUSED */
-
- nu1->pntsu += nu2->pntsu;
- BLI_remlink(nubase, nu2);
-
- /* now join the knots */
- if (nu1->type == CU_NURBS) {
- if (nu1->knotsu != NULL) {
- MEM_freeN(nu1->knotsu);
- nu1->knotsu = NULL;
+ MEM_freeN(nu1->bezt);
+ nu1->bezt = bezt;
+ nu1->pntsu += nu2->pntsu;
+ BLI_remlink(nubase, nu2);
+ keyIndex_delNurb(cu->editnurb, nu2);
+ BKE_nurb_free(nu2); nu2 = NULL;
+ BKE_nurb_handles_calc(nu1);
+ }
+ else {
+ bp = (BPoint *)MEM_mallocN((nu1->pntsu + nu2->pntsu) * sizeof(BPoint), "addsegmentN2");
+ ED_curve_bpcpy(cu->editnurb, bp, nu2->bp, nu2->pntsu);
+ ED_curve_bpcpy(cu->editnurb, bp + nu2->pntsu, nu1->bp, nu1->pntsu);
+ MEM_freeN(nu1->bp);
+ nu1->bp = bp;
+
+ /* a = nu1->pntsu + nu1->orderu; */ /* UNUSED */
+
+ nu1->pntsu += nu2->pntsu;
+ BLI_remlink(nubase, nu2);
+
+ /* now join the knots */
+ if (nu1->type == CU_NURBS) {
+ if (nu1->knotsu != NULL) {
+ MEM_freeN(nu1->knotsu);
+ nu1->knotsu = NULL;
+ }
+
+ BKE_nurb_knot_calc_u(nu1);
}
+ keyIndex_delNurb(cu->editnurb, nu2);
+ BKE_nurb_free(nu2); nu2 = NULL;
+ }
+ BKE_curve_nurb_active_set(cu, nu1); /* for selected */
+ ok = true;
+ }
+ }
+ else if ((nu1 && !nu2) || (!nu1 && nu2)) {
+ if (nu2) {
+ SWAP(Nurb *, nu1, nu2);
+ }
+
+ if (!(nu1->flagu & CU_NURB_CYCLIC) && nu1->pntsu > 1) {
+ if (nu1->type == CU_BEZIER && BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, nu1->bezt) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu1->bezt[nu1->pntsu - 1]))
+ {
+ nu1->flagu |= CU_NURB_CYCLIC;
+ BKE_nurb_handles_calc(nu1);
+ ok = true;
+ }
+ else if (nu1->type == CU_NURBS && nu1->bp->f1 & SELECT && (nu1->bp[nu1->pntsu - 1].f1 & SELECT)) {
+ nu1->flagu |= CU_NURB_CYCLIC;
BKE_nurb_knot_calc_u(nu1);
+ ok = true;
}
- keyIndex_delNurb(cu->editnurb, nu2);
- BKE_nurb_free(nu2); nu2 = NULL;
}
-
- BKE_curve_nurb_active_set(cu, nu1); /* for selected */
- ok = 1;
}
- }
- else if ((nu1 && !nu2) || (!nu1 && nu2)) {
- if (nu2) {
- SWAP(Nurb *, nu1, nu2);
+
+ if (!ok) {
+ status.error_generic++;
+ continue;
}
- if (!(nu1->flagu & CU_NURB_CYCLIC) && nu1->pntsu > 1) {
- if (nu1->type == CU_BEZIER && BEZT_ISSEL_ANY_HIDDENHANDLES(cu, nu1->bezt) &&
- BEZT_ISSEL_ANY_HIDDENHANDLES(cu, &nu1->bezt[nu1->pntsu - 1]))
- {
- nu1->flagu |= CU_NURB_CYCLIC;
- BKE_nurb_handles_calc(nu1);
- ok = 1;
- }
- else if (nu1->type == CU_NURBS && nu1->bp->f1 & SELECT && (nu1->bp[nu1->pntsu - 1].f1 & SELECT)) {
- nu1->flagu |= CU_NURB_CYCLIC;
- BKE_nurb_knot_calc_u(nu1);
- ok = 1;
- }
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
}
+
+ status.changed++;
+
+curve_merge_tag_object:
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
}
+ MEM_freeN(objects);
- if (!ok) {
- BKE_report(op->reports, RPT_ERROR, "Cannot make segment");
+ if (status.unselected == objects_len) {
+ BKE_report(op->reports, RPT_ERROR, "No points were selected");
return OPERATOR_CANCELLED;
}
- if (ED_curve_updateAnimPaths(obedit->data))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ const int tot_errors = status.error_selected_few + status.error_resolution + status.error_generic;
+ if (tot_errors > 0) {
+ /* Some curves changed, but some curves failed: don't explain why it failed. */
+ if (status.changed) {
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ tot_errors == 1 ? "%d curve could not make segments" :
+ "%d curves could not make segments",
+ tot_errors);
+ return OPERATOR_FINISHED;
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ /* All curves failed: If there is more than one error give a generic error report. */
+ if (((status.error_selected_few ? 1 : 0) +
+ (status.error_resolution ? 1 : 0) +
+ (status.error_generic ? 1 : 0)) > 1)
+ {
+ BKE_report(op->reports, RPT_ERROR, "Could not make new segments");
+ }
+
+ /* All curves failed due to the same error. */
+ if (status.error_selected_few) {
+ BKE_report(op->reports, RPT_ERROR, "Too few selections to merge");
+ }
+ else if (status.error_resolution) {
+ BKE_report(op->reports, RPT_ERROR, "Resolution does not match");
+ }
+ else {
+ BLI_assert(status.error_generic);
+ BKE_report(op->reports, RPT_ERROR, "Cannot make segment");
+ }
+ return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
@@ -4290,24 +4554,37 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- ListBase *editnurb = object_editcurve_get(obedit);
ViewContext vc;
Nurb *nu;
BezTriple *bezt = NULL;
BPoint *bp = NULL;
- const void *vert = BKE_curve_vert_active_get(cu);
- int location[2];
+ Base *basact = NULL;
short hand;
view3d_operator_needs_opengl(C);
ED_view3d_viewcontext_init(C, &vc);
+ copy_v2_v2_int(vc.mval, mval);
+
+ if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) {
+ Object *obedit = basact->object;
+ Curve *cu = obedit->data;
+ ListBase *editnurb = object_editcurve_get(obedit);
+ const void *vert = BKE_curve_vert_active_get(cu);
+
+ if (!extend && !deselect && !toggle) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
- location[0] = mval[0];
- location[1] = mval[1];
+ ED_curve_deselect_all(((Curve *)ob_iter->data)->editnurb);
+
+ DEG_id_tag_update(ob_iter->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
+ }
+ MEM_freeN(objects);
+ }
- if (ED_curve_pick_vert(&vc, 1, location, &nu, &bezt, &bp, &hand)) {
if (extend) {
if (bezt) {
if (hand == 1) {
@@ -4397,6 +4674,11 @@ bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], bool extend,
BKE_curve_nurb_active_set(cu, nu);
}
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return true;
@@ -4409,7 +4691,7 @@ bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], bool extend,
/* 'cent' is in object space and 'dvec' in worldspace.
*/
-bool ed_editnurb_spin(float viewmat[4][4], Object *obedit, const float axis[3], const float cent[3])
+bool ed_editnurb_spin(float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3])
{
Curve *cu = (Curve *)obedit->data;
ListBase *editnurb = object_editcurve_get(obedit);
@@ -4473,7 +4755,7 @@ bool ed_editnurb_spin(float viewmat[4][4], Object *obedit, const float axis[3],
if (ok) {
for (nu = editnurb->first; nu; nu = nu->next) {
- if (ED_curve_nurb_select_check(cu, nu)) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
nu->orderv = 4;
nu->flagv |= CU_NURB_CYCLIC;
BKE_nurb_knot_calc_v(nu);
@@ -4486,46 +4768,64 @@ bool ed_editnurb_spin(float viewmat[4][4], Object *obedit, const float axis[3],
static int spin_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
float cent[3], axis[3], viewmat[4][4];
+ int ok = -1;
RNA_float_get_array(op->ptr, "center", cent);
RNA_float_get_array(op->ptr, "axis", axis);
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_m4_v3(obedit->imat, cent);
-
if (rv3d)
copy_m4_m4(viewmat, rv3d->viewmat);
else
unit_m4(viewmat);
- if (!ed_editnurb_spin(viewmat, obedit, axis, cent)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot spin");
- return OPERATOR_CANCELLED;
- }
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = (Curve *)obedit->data;
- if (ED_curve_updateAnimPaths(obedit->data))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_m4_v3(obedit->imat, cent);
+
+ if (!ed_editnurb_spin(viewmat, v3d, obedit, axis, cent)) {
+ ok = MAX2(ok, 0);
+ continue;
+ }
+
+ ok = 1;
+ if (ED_curve_updateAnimPaths(cu)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ }
+ MEM_freeN(objects);
+
+ if (ok == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot spin");
+ }
return OPERATOR_FINISHED;
}
static int spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
float axis[3] = {0.0f, 0.0f, 1.0f};
if (rv3d)
copy_v3_v3(axis, rv3d->viewinv[2]);
- RNA_float_set_array(op->ptr, "center", ED_view3d_cursor3d_get(scene, v3d));
+ RNA_float_set_array(op->ptr, "center", scene->cursor.location);
RNA_float_set_array(op->ptr, "axis", axis);
return spin_exec(C, op);
@@ -4553,7 +4853,7 @@ void CURVE_OT_spin(wmOperatorType *ot)
/***************** extrude vertex operator **********************/
-static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
+static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
{
Nurb *nu = NULL;
Nurb *nu_last = NULL;
@@ -4588,7 +4888,7 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
BezTriple *nu_bezt_old = nu->bezt;
BezTriple *bezt = nu->bezt;
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
BezTriple *bezt_new;
BEZT_DESEL_ALL(bezt);
@@ -4618,7 +4918,7 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
BezTriple *nu_bezt_old = nu->bezt;
BezTriple *bezt = &nu->bezt[nu->pntsu - 1];
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
BezTriple *bezt_new;
BEZT_DESEL_ALL(bezt);
@@ -4729,7 +5029,7 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
BezTriple *bezt;
for (bezt = &nu->bezt[i]; i < i_end; i++, bezt++) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
Nurb *nurb_new;
BezTriple *bezt_new;
@@ -4784,7 +5084,7 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
/***************** add vertex operator **********************/
-static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float location_init[3])
+static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, View3D *v3d, const float location_init[3])
{
Nurb *nu;
@@ -4802,7 +5102,7 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
BezTriple *bezt;
for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
add_v3_v3(center, bezt->vec[1]);
verts_len += 1;
}
@@ -4820,7 +5120,7 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
}
}
- if (verts_len && ed_editcurve_extrude(cu, editnurb)) {
+ if (verts_len && ed_editcurve_extrude(cu, editnurb, v3d)) {
float ofs[3];
int i;
@@ -4835,7 +5135,7 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
if (nu->type == CU_BEZIER) {
BezTriple *bezt;
for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
add_v3_v3(bezt->vec[0], ofs);
add_v3_v3(bezt->vec[1], ofs);
add_v3_v3(bezt->vec[2], ofs);
@@ -4949,6 +5249,7 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
static int add_vertex_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
+ View3D *v3d = CTX_wm_view3d(C);
Curve *cu = obedit->data;
EditNurb *editnurb = cu->editnurb;
float location[3];
@@ -4959,13 +5260,13 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
invert_m4_m4(imat, obedit->obmat);
mul_m4_v3(imat, location);
- if (ed_editcurve_addvert(cu, editnurb, location)) {
+ if (ed_editcurve_addvert(cu, editnurb, v3d, location)) {
if (ED_curve_updateAnimPaths(obedit->data)) {
WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
}
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_FINISHED;
}
@@ -4992,7 +5293,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cu = vc.obedit->data;
- findselectedNurbvert(cu, &nu, &bezt, &bp);
+ findselectedNurbvert(cu, vc.v3d, &nu, &bezt, &bp);
if (bezt) {
mul_v3_m4v3(location, vc.obedit->obmat, bezt->vec[1]);
@@ -5001,7 +5302,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
mul_v3_m4v3(location, vc.obedit->obmat, bp->vec);
}
else {
- copy_v3_v3(location, ED_view3d_cursor3d_get(vc.scene, vc.v3d));
+ copy_v3_v3(location, vc.scene->cursor.location);
}
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, location, event->mval, location);
@@ -5010,17 +5311,16 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const float mval[2] = {UNPACK2(event->mval)};
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), vc.scene, 0,
- vc.ar, vc.v3d);
+ vc.bmain, vc.scene, vc.depsgraph, 0, vc.ar, vc.v3d);
- ED_transform_snap_object_project_view3d_mixed(
+ ED_transform_snap_object_project_view3d(
snap_context,
- SCE_SELECT_FACE,
+ SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
- .snap_select = (vc.scene->obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
+ .snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
.use_object_edit_cage = false,
},
- mval, NULL, true,
+ mval, NULL,
location, NULL);
@@ -5088,41 +5388,52 @@ void CURVE_OT_vertex_add(wmOperatorType *ot)
static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- EditNurb *editnurb = cu->editnurb;
- bool changed = false;
- bool as_curve = false;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
- /* first test: curve? */
- if (obedit->type != OB_CURVE) {
- Nurb *nu;
- for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
- if ((nu->pntsv == 1) &&
- (ED_curve_nurb_select_count(cu, nu) == 1))
- {
- as_curve = true;
- break;
- }
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+ EditNurb *editnurb = cu->editnurb;
+ bool changed = false;
+ bool as_curve = false;
+
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
}
- }
- if (obedit->type == OB_CURVE || as_curve) {
- changed = ed_editcurve_extrude(cu, editnurb);
- }
- else {
- changed = ed_editnurb_extrude_flag(editnurb, SELECT);
- }
+ /* First test: curve? */
+ if (obedit->type != OB_CURVE) {
+ Nurb *nu;
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ if ((nu->pntsv == 1) &&
+ (ED_curve_nurb_select_count(v3d, nu) == 1))
+ {
+ as_curve = true;
+ break;
+ }
+ }
+ }
- if (changed) {
- if (ED_curve_updateAnimPaths(obedit->data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ if (obedit->type == OB_CURVE || as_curve) {
+ changed = ed_editcurve_extrude(cu, editnurb, v3d);
+ }
+ else {
+ changed = ed_editnurb_extrude_flag(editnurb, SELECT);
}
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
- }
+ if (changed) {
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ }
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -5146,15 +5457,13 @@ void CURVE_OT_extrude(wmOperatorType *ot)
/***************** make cyclic operator **********************/
-static int toggle_cyclic_exec(bContext *C, wmOperator *op)
+static bool curve_toggle_cyclic(View3D *v3d, ListBase *editnurb, int direction)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
BezTriple *bezt;
BPoint *bp;
- int a, direction = RNA_enum_get(op->ptr, "direction");
+ int a;
+ bool changed = false;
for (nu = editnurb->first; nu; nu = nu->next) {
if (nu->pntsu > 1 || nu->pntsv > 1) {
@@ -5164,6 +5473,7 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op)
while (a--) {
if (bp->f1 & SELECT) {
nu->flagu ^= CU_NURB_CYCLIC;
+ changed = true;
break;
}
bp++;
@@ -5173,8 +5483,9 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op)
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
nu->flagu ^= CU_NURB_CYCLIC;
+ changed = true;
break;
}
bezt++;
@@ -5189,6 +5500,7 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op)
if (bp->f1 & SELECT) {
nu->flagu ^= CU_NURB_CYCLIC;
BKE_nurb_knot_calc_u(nu); /* 1==u type is ignored for cyclic curves */
+ changed = true;
break;
}
bp++;
@@ -5204,24 +5516,50 @@ static int toggle_cyclic_exec(bContext *C, wmOperator *op)
if (direction == 0 && nu->pntsu > 1) {
nu->flagu ^= CU_NURB_CYCLIC;
BKE_nurb_knot_calc_u(nu); /* 1==u type is ignored for cyclic curves */
+ changed = true;
}
if (direction == 1 && nu->pntsv > 1) {
nu->flagv ^= CU_NURB_CYCLIC;
BKE_nurb_knot_calc_v(nu); /* 2==v type is ignored for cyclic curves */
+ changed = true;
}
break;
}
bp++;
}
-
}
}
}
+ return changed;
+}
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+static int toggle_cyclic_exec(bContext *C, wmOperator *op)
+{
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ View3D *v3d = CTX_wm_view3d(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bool changed_multi = false;
- return OPERATOR_FINISHED;
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
+
+ ListBase *editnurb = object_editcurve_get(obedit);
+ if (curve_toggle_cyclic(v3d, editnurb, direction)) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static int toggle_cyclic_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -5278,20 +5616,39 @@ void CURVE_OT_cyclic_toggle(wmOperatorType *ot)
static int duplicate_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- ListBase newnurb = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ int ok = -1;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
- adduplicateflagNurb(obedit, &newnurb, SELECT, false);
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
+
+ ListBase newnurb = {NULL, NULL};
+ adduplicateflagNurb(obedit, v3d, &newnurb, SELECT, false);
- if (BLI_listbase_is_empty(&newnurb) == false) {
+ if (BLI_listbase_is_empty(&newnurb)) {
+ ok = MAX2(ok, 0);
+ continue;
+ }
+
+ ok = 1;
BLI_movelisttolist(object_editcurve_get(obedit), &newnurb);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(&cu->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, &cu->id);
}
- else {
+ MEM_freeN(objects);
+
+ if (ok == 0) {
BKE_report(op->reports, RPT_ERROR, "Cannot duplicate current selection");
return OPERATOR_CANCELLED;
}
-
return OPERATOR_FINISHED;
}
@@ -5312,19 +5669,19 @@ void CURVE_OT_duplicate(wmOperatorType *ot)
/********************** delete operator *********************/
-static int curve_delete_vertices(Object *obedit)
+static bool curve_delete_vertices(Object *obedit, View3D *v3d)
{
if (obedit->type == OB_SURF) {
ed_surf_delete_selected(obedit);
}
else {
- ed_curve_delete_selected(obedit);
+ ed_curve_delete_selected(obedit, v3d);
}
- return OPERATOR_FINISHED;
+ return true;
}
-static int curve_delete_segments(Object *obedit, const bool split)
+static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split)
{
Curve *cu = obedit->data;
EditNurb *editnurb = cu->editnurb;
@@ -5341,12 +5698,12 @@ static int curve_delete_segments(Object *obedit, const bool split)
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
- if (!BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (!BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
enda = a;
if (starta == -1) starta = a;
if (a < nu->pntsu - 1) continue;
}
- else if (a < nu->pntsu - 1 && !BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt + 1)) {
+ else if (a < nu->pntsu - 1 && !BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt + 1)) {
/* if just single selected point then continue */
continue;
}
@@ -5370,8 +5727,8 @@ static int curve_delete_segments(Object *obedit, const bool split)
bezt2 = &nu->bezt[nu->pntsu - 2];
if ((nu->flagu & CU_NURB_CYCLIC) &&
- BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1) &&
- BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt2))
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt2))
{
/* check if need to join start of spline to end */
nu1 = BKE_nurb_copy(nu, cut + 1, 1);
@@ -5392,8 +5749,8 @@ static int curve_delete_segments(Object *obedit, const bool split)
bezt2 = &nu->bezt[1];
if ((nu->flagu & CU_NURB_CYCLIC) &&
- BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1) &&
- BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt2))
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt2))
{
/* check if need to join start of spline to end */
nu1 = BKE_nurb_copy(nu, cut + 1, 1);
@@ -5433,8 +5790,8 @@ static int curve_delete_segments(Object *obedit, const bool split)
bezt1 = nu->bezt;
bezt2 = &nu->bezt[1];
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1) &&
- BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt2))
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt2))
{
nu1 = BKE_nurb_copy(nu, 1, 1);
ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1);
@@ -5444,8 +5801,8 @@ static int curve_delete_segments(Object *obedit, const bool split)
bezt1 = &nu->bezt[nu->pntsu - 1];
bezt2 = &nu->bezt[nu->pntsu - 2];
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt1) &&
- BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt2))
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt2))
{
nu1 = BKE_nurb_copy(nu, 1, 1);
ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1);
@@ -5717,32 +6074,57 @@ static int curve_delete_segments(Object *obedit, const bool split)
BKE_nurbList_free(nubase);
BLI_movelisttolist(nubase, &newnurb);
- return OPERATOR_FINISHED;
+ return true;
}
static int curve_delete_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = (Curve *)obedit->data;
+ View3D *v3d = CTX_wm_view3d(C);
eCurveElem_Types type = RNA_enum_get(op->ptr, "type");
- int retval = OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ bool changed_multi = false;
- if (type == CURVE_VERTEX) retval = curve_delete_vertices(obedit);
- else if (type == CURVE_SEGMENT) retval = curve_delete_segments(obedit, false);
- else BLI_assert(0);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = (Curve *)obedit->data;
+ bool changed = false;
- if (retval == OPERATOR_FINISHED) {
- cu->actnu = cu->actvert = CU_ACT_NONE;
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
- if (ED_curve_updateAnimPaths(obedit->data)) WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ if (type == CURVE_VERTEX) {
+ changed = curve_delete_vertices(obedit, v3d);
+ }
+ else if (type == CURVE_SEGMENT) {
+ changed = curve_delete_segments(obedit, v3d, false);
+ }
+ else {
+ BLI_assert(0);
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ if (changed) {
+ changed_multi = true;
+ cu->actnu = cu->actvert = CU_ACT_NONE;
- return retval;
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ }
}
+ MEM_freeN(objects);
- return retval;
+ if (changed_multi) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static const EnumPropertyItem curve_delete_type_items[] = {
@@ -5788,23 +6170,32 @@ void CURVE_OT_delete(wmOperatorType *ot)
/* properties */
prop = RNA_def_enum(ot->srna, "type", curve_delete_type_items, 0, "Type", "Which elements to delete");
RNA_def_enum_funcs(prop, rna_curve_delete_type_itemf);
-
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
ot->prop = prop;
}
static bool test_bezt_is_sel_any(const void *bezt_v, void *user_data)
{
- Curve *cu = user_data;
+ View3D *v3d = user_data;
const BezTriple *bezt = bezt_v;
- return BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt);
+ return BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
}
static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = (Curve *)obedit->data;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = (Curve *)obedit->data;
+
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
+ }
- {
ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
@@ -5816,7 +6207,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
while (BLI_array_iter_span(
nu->bezt, nu->pntsu,
(nu->flagu & CU_NURB_CYCLIC) != 0, false,
- test_bezt_is_sel_any, cu,
+ test_bezt_is_sel_any, v3d,
span_step, &span_len))
{
BezTriple *bezt_prev = &nu->bezt[mod_i(span_step[0] - 1, nu->pntsu)];
@@ -5871,19 +6262,17 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
}
}
}
- }
- ed_curve_delete_selected(obedit);
+ ed_curve_delete_selected(obedit, v3d);
- {
cu->actnu = cu->actvert = CU_ACT_NONE;
if (ED_curve_updateAnimPaths(obedit->data)) WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
}
-
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -5918,47 +6307,59 @@ static bool nurb_bezt_flag_any(const Nurb *nu, const char flag_test)
static int curve_decimate_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = (Curve *)obedit->data;
- bool all_supported = true;
- bool changed = false;
+ const float error_sq_max = FLT_MAX;
+ float ratio = RNA_float_get(op->ptr, "ratio");
+ bool all_supported_multi = true;
- {
- const float error_sq_max = FLT_MAX;
- float ratio = RNA_float_get(op->ptr, "ratio");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = (Curve *)obedit->data;
+ bool all_supported = true;
+ bool changed = false;
- ListBase *editnurb = object_editcurve_get(obedit);
- Nurb *nu;
-
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- if ((nu->pntsu > 2) && nurb_bezt_flag_any(nu, SELECT)) {
- const int error_target_len = max_ii(2, nu->pntsu * ratio);
- if (error_target_len != nu->pntsu) {
- BKE_curve_decimate_nurb(nu, cu->resolu, error_sq_max, error_target_len);
- changed = true;
+ {
+ ListBase *editnurb = object_editcurve_get(obedit);
+ Nurb *nu;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ if ((nu->pntsu > 2) && nurb_bezt_flag_any(nu, SELECT)) {
+ const int error_target_len = max_ii(2, nu->pntsu * ratio);
+ if (error_target_len != nu->pntsu) {
+ BKE_curve_decimate_nurb(nu, cu->resolu, error_sq_max, error_target_len);
+ changed = true;
+ }
}
}
+ else {
+ all_supported = false;
+ }
}
- else {
- all_supported = false;
+ }
+
+ if (all_supported == false) {
+ all_supported_multi = false;
+ }
+
+ if (changed) {
+ cu->actnu = cu->actvert = CU_ACT_NONE;
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
}
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
}
}
- if (all_supported == false) {
+ if (all_supported_multi == false) {
BKE_report(op->reports, RPT_WARNING, "Only bezier curves are supported");
}
- if (changed) {
- cu->actnu = cu->actvert = CU_ACT_NONE;
- if (ED_curve_updateAnimPaths(obedit->data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
- }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -5987,6 +6388,7 @@ void CURVE_OT_decimate(wmOperatorType *ot)
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
+ View3D *v3d = CTX_wm_view3d(C);
ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
int clear = (STREQ(op->idname, "CURVE_OT_shade_flat"));
@@ -5995,14 +6397,14 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
for (nu = editnurb->first; nu; nu = nu->next) {
- if (ED_curve_nurb_select_check(obedit->data, nu)) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
if (!clear) nu->flag |= CU_SMOOTH;
else nu->flag &= ~CU_SMOOTH;
}
}
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_FINISHED;
}
@@ -6043,7 +6445,7 @@ int join_curve_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
+ Object *ob_active = CTX_data_active_object(C);
Curve *cu;
Nurb *nu, *newnu;
BezTriple *bezt;
@@ -6053,9 +6455,9 @@ int join_curve_exec(bContext *C, wmOperator *op)
int a;
bool ok = false;
- CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
{
- if (base->object == ob) {
+ if (ob_iter == ob_active) {
ok = true;
break;
}
@@ -6071,24 +6473,24 @@ int join_curve_exec(bContext *C, wmOperator *op)
BLI_listbase_clear(&tempbase);
/* trasnform all selected curves inverse in obact */
- invert_m4_m4(imat, ob->obmat);
+ invert_m4_m4(imat, ob_active->obmat);
- CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
{
- if (base->object->type == ob->type) {
- if (base->object != ob) {
+ if (ob_iter->type == ob_active->type) {
+ if (ob_iter != ob_active) {
- cu = base->object->data;
+ cu = ob_iter->data;
if (cu->nurb.first) {
/* watch it: switch order here really goes wrong */
- mul_m4_m4m4(cmat, imat, base->object->obmat);
+ mul_m4_m4m4(cmat, imat, ob_iter->obmat);
nu = cu->nurb.first;
while (nu) {
newnu = BKE_nurb_duplicate(nu);
- if (ob->totcol) { /* TODO, merge material lists */
- CLAMP(newnu->mat_nr, 0, ob->totcol - 1);
+ if (ob_active->totcol) { /* TODO, merge material lists */
+ CLAMP(newnu->mat_nr, 0, ob_active->totcol - 1);
}
else {
newnu->mat_nr = 0;
@@ -6116,23 +6518,24 @@ int join_curve_exec(bContext *C, wmOperator *op)
}
}
- ED_base_object_free_and_unlink(bmain, scene, base);
+ ED_object_base_free_and_unlink(bmain, scene, ob_iter);
}
}
}
CTX_DATA_END;
- cu = ob->data;
+ cu = ob_active->data;
BLI_movelisttolist(&cu->nurb, &tempbase);
- if (ob->type == OB_CURVE) {
+ if (ob_active->type == OB_CURVE) {
/* Account for mixed 2D/3D curves when joining */
BKE_curve_curve_dimension_update(cu);
}
- DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
+ DEG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_active->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -6144,36 +6547,48 @@ int join_curve_exec(bContext *C, wmOperator *op)
static int clear_tilt_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- ListBase *editnurb = object_editcurve_get(obedit);
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- int a;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->bezt) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) bezt->alfa = 0.0;
- bezt++;
- }
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
}
- else if (nu->bp) {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- if (bp->f1 & SELECT) bp->alfa = 0.0f;
- bp++;
+
+ ListBase *editnurb = object_editcurve_get(obedit);
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ for (nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->bezt) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) bezt->alfa = 0.0;
+ bezt++;
+ }
+ }
+ else if (nu->bp) {
+ bp = nu->bp;
+ a = nu->pntsu * nu->pntsv;
+ while (a--) {
+ if (bp->f1 & SELECT) bp->alfa = 0.0f;
+ bp++;
+ }
}
}
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, 0);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -6235,18 +6650,19 @@ static bool match_texture_space_poll(bContext *C)
static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *object = CTX_data_active_object(C);
Curve *curve = (Curve *) object->data;
float min[3], max[3], size[3], loc[3];
int a;
- if (object->curve_cache == NULL) {
- BKE_displist_make_curveTypes(scene, object, false);
+ if (object->runtime.curve_cache == NULL) {
+ BKE_displist_make_curveTypes(depsgraph, scene, object, false, false);
}
INIT_MINMAX(min, max);
- BKE_displist_minmax(&object->curve_cache->disp, min, max);
+ BKE_displist_minmax(&object->runtime.curve_cache->disp, min, max);
mid_v3_v3v3(loc, min, max);
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index a6100d9bb14..7eabd9c96e8 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -42,8 +42,8 @@
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_library.h"
+
+#include "DEG_depsgraph.h"
#include "RNA_access.h"
@@ -397,11 +397,11 @@ Nurb *ED_curve_add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4],
BLI_addtail(editnurb, nu); /* temporal for spin */
if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0)
- ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent);
+ ed_editnurb_spin(umat, NULL, obedit, tmp_vec, tmp_cent);
else if ((U.flag & USER_ADD_VIEWALIGNED))
- ed_editnurb_spin(viewmat, obedit, zvec, mat[3]);
+ ed_editnurb_spin(viewmat, NULL, obedit, zvec, mat[3]);
else
- ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]);
+ ed_editnurb_spin(umat, NULL, obedit, tmp_vec, mat[3]);
BKE_nurb_knot_calc_v(nu);
@@ -429,11 +429,11 @@ Nurb *ED_curve_add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4],
/* same as above */
if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0)
- ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent);
+ ed_editnurb_spin(umat, NULL, obedit, tmp_vec, tmp_cent);
else if ((U.flag & USER_ADD_VIEWALIGNED))
- ed_editnurb_spin(viewmat, obedit, zvec, mat[3]);
+ ed_editnurb_spin(viewmat, NULL, obedit, zvec, mat[3]);
else
- ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]);
+ ed_editnurb_spin(umat, NULL, obedit, tmp_vec, mat[3]);
BLI_remlink(editnurb, nu);
@@ -477,14 +477,13 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
Nurb *nu;
bool newob = false;
bool enter_editmode;
- unsigned int layer;
float dia;
float loc[3], rot[3];
float mat[4][4];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL))
return OPERATOR_CANCELLED;
if (!isSurf) { /* adding curve */
@@ -492,7 +491,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
const char *name = get_curve_defname(type);
Curve *cu;
- obedit = ED_object_add_type(C, OB_CURVE, name, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_CURVE, name, loc, rot, true);
newob = true;
cu = (Curve *)obedit->data;
@@ -502,17 +501,17 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
cu->flag |= CU_PATH | CU_3D;
}
else {
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
}
else { /* adding surface */
if (obedit == NULL || obedit->type != OB_SURF) {
const char *name = get_surf_defname(type);
- obedit = ED_object_add_type(C, OB_SURF, name, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_SURF, name, loc, rot, true);
newob = true;
}
else {
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
}
@@ -565,7 +564,7 @@ void CURVE_OT_primitive_bezier_curve_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -588,7 +587,7 @@ void CURVE_OT_primitive_bezier_circle_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -611,7 +610,7 @@ void CURVE_OT_primitive_nurbs_curve_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -634,7 +633,7 @@ void CURVE_OT_primitive_nurbs_circle_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -657,7 +656,7 @@ void CURVE_OT_primitive_nurbs_path_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -681,7 +680,7 @@ void SURFACE_OT_primitive_nurbs_surface_curve_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -704,7 +703,7 @@ void SURFACE_OT_primitive_nurbs_surface_circle_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -727,7 +726,7 @@ void SURFACE_OT_primitive_nurbs_surface_surface_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -750,7 +749,7 @@ void SURFACE_OT_primitive_nurbs_surface_cylinder_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -773,7 +772,7 @@ void SURFACE_OT_primitive_nurbs_surface_sphere_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -796,6 +795,6 @@ void SURFACE_OT_primitive_nurbs_surface_torus_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 7bdf17e9344..3fe880865bb 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -33,10 +33,12 @@
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -47,7 +49,13 @@
#include "ED_curve.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "curve_intern.h"
@@ -89,6 +97,8 @@ struct StrokeElem {
};
struct CurveDrawData {
+ Depsgraph *depsgraph;
+
short init_event_type;
short curve_type;
@@ -129,7 +139,6 @@ struct CurveDrawData {
} prev;
ViewContext vc;
- bglMats mats;
enum {
CURVE_DRAW_IDLE = 0,
CURVE_DRAW_PAINTING = 1,
@@ -209,7 +218,7 @@ static bool stroke_elem_project(
{
const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i);
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (ED_view3d_depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) {
+ if (ED_view3d_depth_unproject(ar, mval_i, depth, r_location_world)) {
is_location_world_set = true;
if (r_normal_world) {
zero_v3(r_normal_world);
@@ -218,7 +227,7 @@ static bool stroke_elem_project(
if (surface_offset != 0.0f) {
const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius;
float normal[3];
- if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, mval_i, normal)) {
+ if (ED_view3d_depth_read_cached_normal(&cdd->vc, mval_i, normal)) {
madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
if (r_normal_world) {
copy_v3_v3(r_normal_world, normal);
@@ -360,43 +369,46 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS
return;
}
- View3D *v3d = cdd->vc.v3d;
Object *obedit = cdd->vc.obedit;
Curve *cu = obedit->data;
- UI_ThemeColor(TH_WIRE);
-
if (cu->ext2 > 0.0f) {
- GLUquadricObj *qobj = gluNewQuadric();
-
- gluQuadricDrawStyle(qobj, GLU_FILL);
-
BLI_mempool_iter iter;
const struct StrokeElem *selem;
const float location_zero[3] = {0};
const float *location_prev = location_zero;
+ float color[3];
+ UI_GetThemeColor3fv(TH_WIRE, color);
+
+ GPUBatch *sphere = GPU_batch_preset_sphere(0);
+ GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_batch_uniform_3fv(sphere, "color", color);
+
/* scale to edit-mode space */
- glPushMatrix();
- glMultMatrixf(obedit->obmat);
+ GPU_matrix_push();
+ GPU_matrix_mul(obedit->obmat);
BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
- glTranslatef(
+ GPU_matrix_translate_3f(
selem->location_local[0] - location_prev[0],
selem->location_local[1] - location_prev[1],
selem->location_local[2] - location_prev[2]);
location_prev = selem->location_local;
+
const float radius = stroke_elem_radius(cdd, selem);
- gluSphere(qobj, radius, 12, 8);
+
+ GPU_matrix_push();
+ GPU_matrix_scale_1f(radius);
+ GPU_batch_draw(sphere);
+ GPU_matrix_pop();
location_prev = selem->location_local;
}
- glPopMatrix();
-
- gluDeleteQuadric(qobj);
+ GPU_matrix_pop();
}
if (stroke_len > 1) {
@@ -413,30 +425,37 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUS
}
{
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, coord_array);
-
- cpack(0x0);
- glLineWidth(3.0f);
- glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
-
- if (v3d->zbuf)
- glDisable(GL_DEPTH_TEST);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ GPU_depth_test(false);
+ GPU_blend(true);
+ GPU_line_smooth(true);
+ GPU_line_width(3.0f);
+
+ imm_cpack(0x0);
+ immBegin(GPU_PRIM_LINE_STRIP, stroke_len);
+ for (int i = 0; i < stroke_len; i++) {
+ immVertex3fv(pos, coord_array[i]);
+ }
+ immEnd();
- cpack(0xffffffff);
- glLineWidth(1.0f);
- glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
+ GPU_line_width(1.0f);
- if (v3d->zbuf)
- glEnable(GL_DEPTH_TEST);
+ imm_cpack(0xffffffff);
+ immBegin(GPU_PRIM_LINE_STRIP, stroke_len);
+ for (int i = 0; i < stroke_len; i++) {
+ immVertex3fv(pos, coord_array[i]);
+ }
+ immEnd();
- glDisableClientState(GL_VERTEX_ARRAY);
+ /* Reset defaults */
+ GPU_depth_test(true);
+ GPU_blend(false);
+ GPU_line_smooth(false);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ immUnbindProgram();
}
MEM_freeN(coord_array);
@@ -526,7 +545,7 @@ static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW,
CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE))
{
- if (ED_view3d_depth_read_cached_normal(&cdd->vc, &cdd->mats, event->mval, normal)) {
+ if (ED_view3d_depth_read_cached_normal(&cdd->vc, event->mval, normal)) {
if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) {
float cross_a[3], cross_b[3];
cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal);
@@ -575,6 +594,8 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
+ cdd->depsgraph = CTX_data_depsgraph(C);
+
if (is_invoke) {
ED_view3d_viewcontext_init(C, &cdd->vc);
if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
@@ -585,7 +606,9 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
}
else {
cdd->vc.bmain = CTX_data_main(C);
+ cdd->vc.depsgraph = CTX_data_depsgraph(C);
cdd->vc.scene = CTX_data_scene(C);
+ cdd->vc.view_layer = CTX_data_view_layer(C);
cdd->vc.obedit = CTX_data_edit_object(C);
}
@@ -678,7 +701,7 @@ static void curve_draw_exec_precalc(wmOperator *op)
const struct StrokeElem *selem, *selem_first, *selem_last;
BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
- selem_first = BLI_mempool_iterstep(&iter);
+ selem_first = selem_last = BLI_mempool_iterstep(&iter);
for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
selem_last = selem;
}
@@ -755,7 +778,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
struct CurveDrawData *cdd = op->customdata;
const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
- Object *obedit = cdd->vc.scene->obedit;
+ Object *obedit = cdd->vc.obedit;
Curve *cu = obedit->data;
ListBase *nurblist = object_editcurve_get(obedit);
@@ -769,7 +792,14 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
}
- ED_curve_deselect_all(cu->editnurb);
+ /* Deselect all existing curves. */
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ ED_curve_deselect_all_multi(objects, objects_len);
+ MEM_freeN(objects);
+ }
const float radius_min = cps->radius_min;
const float radius_max = cps->radius_max;
@@ -1014,7 +1044,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
cu->actvert = nu->pntsu - 1;
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
curve_draw_exit(op);
@@ -1067,14 +1097,12 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) &&
- (v3d->drawtype > OB_WIRE))
+ (v3d->shading.type > OB_WIRE))
{
- view3d_get_transformation(cdd->vc.ar, cdd->vc.rv3d, NULL, &cdd->mats);
-
/* needed or else the draw matrix can be incorrect */
view3d_operator_needs_opengl(C);
- ED_view3d_autodist_init(cdd->vc.bmain, cdd->vc.scene, cdd->vc.ar, cdd->vc.v3d, 0);
+ ED_view3d_autodist_init(cdd->vc.depsgraph, cdd->vc.ar, cdd->vc.v3d, 0);
if (cdd->vc.rv3d->depths) {
cdd->vc.rv3d->depths->damaged = true;
@@ -1093,7 +1121,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* use view plane (when set or as fallback when surface can't be found) */
if (cdd->project.use_depth == false) {
- plane_co = ED_view3d_cursor3d_get(cdd->vc.scene, v3d);
+ plane_co = cdd->vc.scene->cursor.location;
plane_no = rv3d->viewinv[2];
cdd->project.use_plane = true;
}
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 673faa37f2a..992c88a1492 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -38,26 +38,32 @@
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_heap.h"
+#include "BLI_heap_simple.h"
+#include "BLI_kdtree.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_layer.h"
#include "BKE_report.h"
+#include "BKE_object.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_types.h"
#include "ED_view3d.h"
#include "ED_curve.h"
#include "curve_intern.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
+#include "DEG_depsgraph.h"
/* returns 1 in case (de)selection was successful */
bool select_beztriple(BezTriple *bezt, bool selstatus, short flag, eVisible_Types hidden)
@@ -113,14 +119,14 @@ static bool swap_selection_bpoint(BPoint *bp)
return select_bpoint(bp, SELECT, SELECT, VISIBLE);
}
-bool ED_curve_nurb_select_check(Curve *cu, Nurb *nu)
+bool ED_curve_nurb_select_check(View3D *v3d, Nurb *nu)
{
if (nu->type == CU_BEZIER) {
BezTriple *bezt;
int i;
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
return true;
}
}
@@ -138,7 +144,7 @@ bool ED_curve_nurb_select_check(Curve *cu, Nurb *nu)
return false;
}
-int ED_curve_nurb_select_count(Curve *cu, Nurb *nu)
+int ED_curve_nurb_select_count(View3D *v3d, Nurb *nu)
{
int sel = 0;
@@ -147,7 +153,7 @@ int ED_curve_nurb_select_count(Curve *cu, Nurb *nu)
int i;
for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
sel++;
}
}
@@ -214,12 +220,24 @@ void ED_curve_nurb_deselect_all(Nurb *nu)
}
}
-bool ED_curve_select_check(Curve *cu, struct EditNurb *editnurb)
+int ED_curve_select_count(View3D *v3d, struct EditNurb *editnurb)
+{
+ int sel = 0;
+ Nurb *nu;
+
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ sel += ED_curve_nurb_select_count(v3d, nu);
+ }
+
+ return sel;
+}
+
+bool ED_curve_select_check(View3D *v3d, struct EditNurb *editnurb)
{
Nurb *nu;
for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
- if (ED_curve_nurb_select_check(cu, nu)) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
return true;
}
}
@@ -236,6 +254,15 @@ void ED_curve_deselect_all(EditNurb *editnurb)
}
}
+void ED_curve_deselect_all_multi(Object **objects, int objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+ ED_curve_deselect_all(cu->editnurb);
+ }
+}
+
void ED_curve_select_swap(EditNurb *editnurb, bool hide_handles)
{
Nurb *nu;
@@ -400,12 +427,18 @@ static void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap
static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
-
- selectend_nurb(obedit, FIRST, true, DESELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(obedit->data);
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ selectend_nurb(obedit, FIRST, true, DESELECT);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -426,12 +459,19 @@ void CURVE_OT_de_select_first(wmOperatorType *ot)
static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
-
- selectend_nurb(obedit, LAST, true, DESELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(obedit->data);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ selectend_nurb(obedit, LAST, true, DESELECT);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -452,32 +492,48 @@ void CURVE_OT_de_select_last(wmOperatorType *ot)
static int de_select_all_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
int action = RNA_enum_get(op->ptr, "action");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- if (ED_curve_select_check(cu, cu->editnurb)) {
- action = SEL_DESELECT;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+
+ if (ED_curve_select_check(v3d, cu->editnurb)) {
+ action = SEL_DESELECT;
+ break;
+ }
}
}
- switch (action) {
- case SEL_SELECT:
- ED_curve_select_all(cu->editnurb);
- break;
- case SEL_DESELECT:
- ED_curve_deselect_all(cu->editnurb);
- break;
- case SEL_INVERT:
- ED_curve_select_swap(cu->editnurb, (cu->drawflag & CU_HIDE_HANDLES) != 0);
- break;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+
+ switch (action) {
+ case SEL_SELECT:
+ ED_curve_select_all(cu->editnurb);
+ break;
+ case SEL_DESELECT:
+ ED_curve_deselect_all(cu->editnurb);
+ break;
+ case SEL_INVERT:
+ ED_curve_select_swap(cu->editnurb, (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0);
+ break;
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(cu);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BKE_curve_nurb_vert_active_validate(cu);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -505,19 +561,32 @@ void CURVE_OT_select_all(wmOperatorType *ot)
static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = (Curve *)obedit->data;
- EditNurb *editnurb = cu->editnurb;
- ListBase *nurbs = &editnurb->nurbs;
- Nurb *nu;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+ EditNurb *editnurb = cu->editnurb;
+ ListBase *nurbs = &editnurb->nurbs;
+ Nurb *nu;
+ bool changed = false;
+
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
+ ED_curve_nurb_select_all(nu);
+ changed = true;
+ }
+ }
- for (nu = nurbs->first; nu; nu = nu->next) {
- if (ED_curve_nurb_select_check(cu, nu)) {
- ED_curve_nurb_select_all(nu);
+ if (changed) {
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
}
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -532,7 +601,7 @@ void CURVE_OT_select_linked(wmOperatorType *ot)
/* identifiers */
ot->name = "Select Linked All";
ot->idname = "CURVE_OT_select_linked";
- ot->description = "Select all control points linked to active one";
+ ot->description = "Select all control points linked to the current selection";
/* api callbacks */
ot->exec = select_linked_exec;
@@ -550,18 +619,19 @@ void CURVE_OT_select_linked(wmOperatorType *ot)
static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt;
BPoint *bp;
int a;
const bool select = !RNA_boolean_get(op->ptr, "deselect");
+ Base *basact = NULL;
view3d_operator_needs_opengl(C);
ED_view3d_viewcontext_init(C, &vc);
+ copy_v2_v2_int(vc.mval, event->mval);
- if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu, &bezt, &bp, NULL)) {
+ if (!ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, NULL, &basact)) {
return OPERATOR_CANCELLED;
}
@@ -582,7 +652,11 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent
}
}
+ Object *obedit = basact->object;
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
if (!select) {
BKE_curve_nurb_vert_active_validate(obedit->data);
}
@@ -644,6 +718,7 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
}
}
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -668,12 +743,18 @@ void CURVE_OT_select_row(wmOperatorType *ot)
static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
-
- select_adjacent_cp(editnurb, 1, 0, SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ListBase *editnurb = object_editcurve_get(obedit);
+ select_adjacent_cp(editnurb, 1, 0, SELECT);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -696,12 +777,18 @@ void CURVE_OT_select_next(wmOperatorType *ot)
static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
-
- select_adjacent_cp(editnurb, -1, 0, SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ListBase *editnurb = object_editcurve_get(obedit);
+ select_adjacent_cp(editnurb, -1, 0, SELECT);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -722,9 +809,8 @@ void CURVE_OT_select_previous(wmOperatorType *ot)
/***************** select more operator **********************/
-static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
+static void curve_select_more(Object *obedit)
{
- Object *obedit = CTX_data_edit_object(C);
ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
BPoint *bp, *tempbp;
@@ -787,9 +873,20 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
select_adjacent_cp(editnurb, 1, 0, SELECT);
select_adjacent_cp(editnurb, -1, 0, SELECT);
}
+}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
+static int curve_select_more_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ curve_select_more(obedit);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -801,7 +898,7 @@ void CURVE_OT_select_more(wmOperatorType *ot)
ot->description = "Select control points directly linked to already selected ones";
/* api callbacks */
- ot->exec = select_more_exec;
+ ot->exec = curve_select_more_exec;
ot->poll = ED_operator_editsurfcurve;
/* flags */
@@ -811,9 +908,8 @@ void CURVE_OT_select_more(wmOperatorType *ot)
/******************** select less operator *****************/
/* basic method: deselect if control point doesn't have all neighbors selected */
-static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
+static void curve_select_less(Object *obedit)
{
- Object *obedit = CTX_data_edit_object(C);
ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
BPoint *bp;
@@ -974,10 +1070,20 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
}
}
}
+}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- BKE_curve_nurb_vert_active_validate(obedit->data);
-
+static int curve_select_less_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ curve_select_less(obedit);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -989,7 +1095,7 @@ void CURVE_OT_select_less(wmOperatorType *ot)
ot->description = "Reduce current selection by deselecting boundary elements";
/* api callbacks */
- ot->exec = select_less_exec;
+ ot->exec = curve_select_less_exec;
ot->poll = ED_operator_editsurfcurve;
/* flags */
@@ -1040,17 +1146,32 @@ static void curve_select_random(ListBase *editnurb, float randfac, int seed, boo
static int curve_select_random_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- ListBase *editnurb = object_editcurve_get(obedit);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
- curve_select_random(editnurb, randfac, seed, select);
- BKE_curve_nurb_vert_active_validate(obedit->data);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ListBase *editnurb = object_editcurve_get(obedit);
+ int seed_iter = seed;
+
+ /* This gives a consistent result regardless of object order. */
+ if (ob_index) {
+ seed_iter += BLI_ghashutil_strhash_p(obedit->id.name);
+ }
+
+ curve_select_random(editnurb, randfac, seed_iter, select);
+ BKE_curve_nurb_vert_active_validate(obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1141,24 +1262,47 @@ static bool ed_curve_select_nth(Curve *cu, const struct CheckerIntervalParams *p
static int select_nth_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- struct CheckerIntervalParams op_params;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = CTX_data_edit_object(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ bool changed = false;
+ struct CheckerIntervalParams op_params;
WM_operator_properties_checker_interval_from_op(op, &op_params);
- if (!ed_curve_select_nth(obedit->data, &op_params)) {
- if (obedit->type == OB_SURF) {
- BKE_report(op->reports, RPT_ERROR, "Surface has not got active point");
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+
+ if (!ED_curve_select_check(v3d, cu->editnurb)) {
+ continue;
}
- else {
- BKE_report(op->reports, RPT_ERROR, "Curve has not got active point");
+
+ if (ed_curve_select_nth(obedit->data, &op_params) == true) {
+ changed = true;
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
+ }
+ MEM_freeN(objects);
+ if (!changed) {
+ if (obact->type == OB_SURF) {
+ BKE_report(op->reports, RPT_ERROR,
+ (objects_len == 1 ?
+ "Surface has no active point" :
+ "Surfaces have no active point"));
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR,
+ (objects_len == 1 ?
+ "Curve has no active point" :
+ "Curves have no active point"));
+ }
return OPERATOR_CANCELLED;
}
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
return OPERATOR_FINISHED;
}
@@ -1186,12 +1330,6 @@ void CURVE_OT_select_nth(wmOperatorType *ot)
/** \name Select Similar
* \{ */
-enum {
- SIM_CMP_EQ = 0,
- SIM_CMP_GT,
- SIM_CMP_LT,
-};
-
static const EnumPropertyItem curve_prop_similar_compare_types[] = {
{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
{SIM_CMP_GT, "GREATER", 0, "Greater", ""},
@@ -1215,260 +1353,301 @@ static const EnumPropertyItem curve_prop_similar_types[] = {
{0, NULL, 0, NULL, NULL}
};
-static int curve_select_similar_cmp_fl(const float delta, const float thresh, const int compare)
+static void nurb_bezt_direction_worldspace_get(Object *ob, Nurb *nu, BezTriple *bezt, float r_dir[3])
{
- switch (compare) {
- case SIM_CMP_EQ:
- return (fabsf(delta) <= thresh);
- case SIM_CMP_GT:
- return ((delta + thresh) >= 0.0f);
- case SIM_CMP_LT:
- return ((delta - thresh) <= 0.0f);
- default:
- BLI_assert(0);
- return 0;
- }
+ float rsmat[3][3];
+ BKE_nurb_bezt_calc_normal(nu, bezt, r_dir);
+ copy_m3_m4(rsmat, ob->obmat);
+ mul_m3_v3(rsmat, r_dir);
+ normalize_v3(r_dir);
}
-
-static void curve_select_similar_direction__bezt(Nurb *nu, const float dir_ref[3], float angle_cos)
+static void nurb_bpoint_direction_worldspace_get(Object *ob, Nurb *nu, BPoint *bp, float r_dir[3])
{
- BezTriple *bezt;
- int i;
-
- for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
- if (!bezt->hide) {
- float dir[3];
- BKE_nurb_bezt_calc_normal(nu, bezt, dir);
- if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
- select_beztriple(bezt, SELECT, SELECT, VISIBLE);
- }
- }
- }
+ float rsmat[3][3];
+ BKE_nurb_bpoint_calc_normal(nu, bp, r_dir);
+ copy_m3_m4(rsmat, ob->obmat);
+ mul_m3_v3(rsmat, r_dir);
+ normalize_v3(r_dir);
}
-static void curve_select_similar_direction__bp(Nurb *nu, const float dir_ref[3], float angle_cos)
+static void curve_nurb_selected_type_get(Object *ob, Nurb *nu, const int type, KDTree *r_tree)
{
- BPoint *bp;
- int i;
+ float tree_entry[3] = {0.0f, 0.0f, 0.0f};
- for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
- if (!bp->hide) {
- float dir[3];
- BKE_nurb_bpoint_calc_normal(nu, bp, dir);
- if (fabsf(dot_v3v3(dir_ref, dir)) >= angle_cos) {
- select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+ int i;
+ int tree_index = 0;
+
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if ((!bezt->hide) && (bezt->f1 & SELECT)) {
+
+ switch (type) {
+ case SIMCURHAND_RADIUS:
+ {
+ float radius_ref = bezt->radius;
+ tree_entry[0] = radius_ref;
+ break;
+ }
+ case SIMCURHAND_WEIGHT:
+ {
+ float weight_ref = bezt->weight;
+ tree_entry[0] = weight_ref;
+ break;
+ }
+ case SIMCURHAND_DIRECTION:
+ {
+ nurb_bezt_direction_worldspace_get(ob, nu, bezt, tree_entry);
+ break;
+ }
+ }
+ BLI_kdtree_insert(r_tree, tree_index++, tree_entry);
}
}
}
-}
-
-static bool curve_select_similar_direction(ListBase *editnurb, Curve *cu, float thresh)
-{
- Nurb *nu, *act_nu;
- void *act_vert;
- float dir[3];
- float angle_cos;
-
- if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
- return false;
- }
-
- if (act_nu->type == CU_BEZIER) {
- BKE_nurb_bezt_calc_normal(act_nu, act_vert, dir);
- }
else {
- BKE_nurb_bpoint_calc_normal(act_nu, act_vert, dir);
- }
-
- /* map 0-1 to radians, 'cos' for comparison */
- angle_cos = cosf(thresh * (float)M_PI_2);
+ BPoint *bp;
+ int i;
+ int tree_index = 0;
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- curve_select_similar_direction__bezt(nu, dir, angle_cos);
- }
- else {
- curve_select_similar_direction__bp(nu, dir, angle_cos);
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ if (!bp->hide && bp->f1 & SELECT) {
+ switch (type) {
+ case SIMCURHAND_RADIUS:
+ {
+ float radius_ref = bp->radius;
+ tree_entry[0] = radius_ref;
+ break;
+ }
+ case SIMCURHAND_WEIGHT:
+ {
+ float weight_ref = bp->weight;
+ tree_entry[0] = weight_ref;
+ break;
+ }
+ case SIMCURHAND_DIRECTION:
+ {
+ nurb_bpoint_direction_worldspace_get(ob, nu, bp, tree_entry);
+ break;
+ }
+ }
+ BLI_kdtree_insert(r_tree, tree_index++, tree_entry);
+ }
}
}
-
- return true;
}
-static void curve_select_similar_radius__bezt(Nurb *nu, float radius_ref, int compare, float thresh)
+static bool curve_nurb_select_similar_type(
+ Object *ob, Nurb *nu, const int type,
+ const KDTree *tree, const float thresh, const int compare)
{
- BezTriple *bezt;
- int i;
+ const float thresh_cos = cosf(thresh * (float)M_PI_2);
+ bool changed = false;
+
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+ int i;
+
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if (!bezt->hide) {
+ bool select = false;
+
+ switch (type) {
+ case SIMCURHAND_RADIUS:
+ {
+ float radius_ref = bezt->radius;
+ if (ED_select_similar_compare_float_tree(tree, radius_ref, thresh, compare)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMCURHAND_WEIGHT:
+ {
+ float weight_ref = bezt->weight;
+ if (ED_select_similar_compare_float_tree(tree, weight_ref, thresh, compare)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMCURHAND_DIRECTION:
+ {
+ float dir[3];
+ nurb_bezt_direction_worldspace_get(ob, nu, bezt, dir);
+ KDTreeNearest nearest;
+ if (BLI_kdtree_find_nearest(tree, dir, &nearest) != -1) {
+ float orient = angle_normalized_v3v3(dir, nearest.co);
+ float delta = thresh_cos - fabsf(cosf(orient));
+ if (ED_select_similar_compare_float(delta, thresh, compare)) {
+ select = true;
+ }
+ }
+ break;
+ }
+ }
- for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
- if (!bezt->hide) {
- if (curve_select_similar_cmp_fl(bezt->radius - radius_ref, thresh, compare)) {
- select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+ if (select) {
+ select_beztriple(bezt, SELECT, SELECT, VISIBLE);
+ changed = true;
+ }
}
}
}
-}
+ else {
+ BPoint *bp;
+ int i;
-static void curve_select_similar_radius__bp(Nurb *nu, float radius_ref, int compare, float thresh)
-{
- BPoint *bp;
- int i;
+ for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
+ if (!bp->hide) {
+ bool select = false;
+
+ switch (type) {
+ case SIMCURHAND_RADIUS:
+ {
+ float radius_ref = bp->radius;
+ if (ED_select_similar_compare_float_tree(tree, radius_ref, thresh, compare)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMCURHAND_WEIGHT:
+ {
+ float weight_ref = bp->weight;
+ if (ED_select_similar_compare_float_tree(tree, weight_ref, thresh, compare)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMCURHAND_DIRECTION:
+ {
+ float dir[3];
+ nurb_bpoint_direction_worldspace_get(ob, nu, bp, dir);
+ KDTreeNearest nearest;
+ if (BLI_kdtree_find_nearest(tree, dir, &nearest) != -1) {
+ float orient = angle_normalized_v3v3(dir, nearest.co);
+ float delta = fabsf(cosf(orient)) - thresh_cos;
+ if (ED_select_similar_compare_float(delta, thresh, compare)) {
+ select = true;
+ }
+ }
+ break;
+ }
+ }
- for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
- if (!bp->hide) {
- if (curve_select_similar_cmp_fl(bp->radius - radius_ref, thresh, compare)) {
- select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ if (select) {
+ select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ changed = true;
+ }
}
}
}
+ return changed;
}
-static bool curve_select_similar_radius(ListBase *editnurb, Curve *cu, float compare, float thresh)
+static int curve_select_similar_exec(bContext *C, wmOperator *op)
{
- Nurb *nu, *act_nu;
- void *act_vert;
- float radius_ref;
+ /* Get props. */
+ const int optype = RNA_enum_get(op->ptr, "type");
+ const float thresh = RNA_float_get(op->ptr, "threshold");
+ const int compare = RNA_enum_get(op->ptr, "compare");
- if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert)) {
- return false;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ int tot_nurbs_selected_all = 0;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (act_nu->type == CU_BEZIER) {
- radius_ref = ((BezTriple *)act_vert)->radius;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+ tot_nurbs_selected_all += ED_curve_select_count(v3d, cu->editnurb);
}
- else {
- radius_ref = ((BPoint *)act_vert)->radius;
- }
-
- /* make relative */
- thresh *= radius_ref;
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- curve_select_similar_radius__bezt(nu, radius_ref, compare, thresh);
- }
- else {
- curve_select_similar_radius__bp(nu, radius_ref, compare, thresh);
- }
+ if (tot_nurbs_selected_all == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No control point selected");
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
}
- return true;
-}
+ KDTree *tree = NULL;
+ short type_ref = 0;
-static void curve_select_similar_weight__bezt(Nurb *nu, float weight_ref, int compare, float thresh)
-{
- BezTriple *bezt;
- int i;
-
- for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
- if (!bezt->hide) {
- if (curve_select_similar_cmp_fl(bezt->weight - weight_ref, thresh, compare)) {
- select_beztriple(bezt, SELECT, SELECT, VISIBLE);
- }
- }
+ switch (optype) {
+ case SIMCURHAND_RADIUS:
+ case SIMCURHAND_WEIGHT:
+ case SIMCURHAND_DIRECTION:
+ tree = BLI_kdtree_new(tot_nurbs_selected_all);
+ break;
}
-}
-static void curve_select_similar_weight__bp(Nurb *nu, float weight_ref, int compare, float thresh)
-{
- BPoint *bp;
- int i;
+ /* Get type of selected control points. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+ EditNurb *editnurb = cu->editnurb;
- for (i = nu->pntsu * nu->pntsv, bp = nu->bp; i--; bp++) {
- if (!bp->hide) {
- if (curve_select_similar_cmp_fl(bp->weight - weight_ref, thresh, compare)) {
- select_bpoint(bp, SELECT, SELECT, VISIBLE);
+ Nurb *nu;
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ if (!ED_curve_nurb_select_check(v3d, nu)) {
+ continue;
+ }
+ switch (optype) {
+ case SIMCURHAND_TYPE:
+ {
+ type_ref |= nu->type;
+ break;
+ }
+ case SIMCURHAND_RADIUS:
+ case SIMCURHAND_WEIGHT:
+ case SIMCURHAND_DIRECTION:
+ curve_nurb_selected_type_get(obedit, nu, optype, tree);
+ break;
}
}
}
-}
-
-static bool curve_select_similar_weight(ListBase *editnurb, Curve *cu, float compare, float thresh)
-{
- Nurb *nu, *act_nu;
- void *act_vert;
- float weight_ref;
-
- if (!BKE_curve_nurb_vert_active_get(cu, &act_nu, &act_vert))
- return false;
-
- if (act_nu->type == CU_BEZIER) {
- weight_ref = ((BezTriple *)act_vert)->weight;
- }
- else {
- weight_ref = ((BPoint *)act_vert)->weight;
- }
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- curve_select_similar_weight__bezt(nu, weight_ref, compare, thresh);
- }
- else {
- curve_select_similar_weight__bp(nu, weight_ref, compare, thresh);
- }
+ if (tree != NULL) {
+ BLI_kdtree_balance(tree);
}
- return true;
-}
+ /* Select control points with desired type. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Curve *cu = obedit->data;
+ EditNurb *editnurb = cu->editnurb;
+ bool changed = false;
+ Nurb *nu;
-static bool curve_select_similar_type(ListBase *editnurb, Curve *cu)
-{
- Nurb *nu, *act_nu;
- int type_ref;
-
- /* Get active nurb type */
- act_nu = BKE_curve_nurb_active_get(cu);
-
- if (!act_nu)
- return false;
-
- /* Get the active nurb type */
- type_ref = act_nu->type;
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ switch (optype) {
+ case SIMCURHAND_TYPE:
+ {
+ if (nu->type & type_ref) {
+ ED_curve_nurb_select_all(nu);
+ changed = true;
+ }
+ break;
+ }
+ case SIMCURHAND_RADIUS:
+ case SIMCURHAND_WEIGHT:
+ case SIMCURHAND_DIRECTION:
+ changed = curve_nurb_select_similar_type(obedit, nu, optype, tree, thresh, compare);
+ break;
+ }
+ }
- for (nu = editnurb->first; nu; nu = nu->next) {
- if (nu->type == type_ref) {
- ED_curve_nurb_select_all(nu);
+ if (changed) {
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
}
- return true;
-}
-
-static int curve_select_similar_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- ListBase *editnurb = object_editcurve_get(obedit);
- bool changed = false;
-
- /* Get props */
- const int type = RNA_enum_get(op->ptr, "type");
- const float thresh = RNA_float_get(op->ptr, "threshold");
- const int compare = RNA_enum_get(op->ptr, "compare");
-
- switch (type) {
- case SIMCURHAND_TYPE:
- changed = curve_select_similar_type(editnurb, cu);
- break;
- case SIMCURHAND_RADIUS:
- changed = curve_select_similar_radius(editnurb, cu, compare, thresh);
- break;
- case SIMCURHAND_WEIGHT:
- changed = curve_select_similar_weight(editnurb, cu, compare, thresh);
- break;
- case SIMCURHAND_DIRECTION:
- changed = curve_select_similar_direction(editnurb, cu, thresh);
- break;
+ MEM_freeN(objects);
+ if (tree != NULL) {
+ BLI_kdtree_free(tree);
}
+ return OPERATOR_FINISHED;
- if (changed) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
}
void CURVE_OT_select_similar(wmOperatorType *ot)
@@ -1574,7 +1753,7 @@ static void curve_select_shortest_path_curve(Nurb *nu, int vert_src, int vert_ds
static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst)
{
- Heap *heap;
+ HeapSimple *heap;
int i, vert_curr;
@@ -1597,17 +1776,18 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
}
/* init heap */
- heap = BLI_heap_new();
+ heap = BLI_heapsimple_new();
- BLI_heap_insert(heap, 0.0f, &data[vert_src].vert);
+ vert_curr = data[vert_src].vert;
+ BLI_heapsimple_insert(heap, 0.0f, &data[vert_src].vert);
data[vert_src].cost = 0.0f;
data[vert_src].vert_prev = vert_src; /* nop */
- while (!BLI_heap_is_empty(heap)) {
+ while (!BLI_heapsimple_is_empty(heap)) {
int axis, sign;
int u, v;
- vert_curr = *((int *)BLI_heap_pop_min(heap));
+ vert_curr = *((int *)BLI_heapsimple_pop_min(heap));
if (vert_curr == vert_dst) {
break;
}
@@ -1629,7 +1809,7 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
if (data[vert_other].cost > dist) {
data[vert_other].cost = dist;
if (data[vert_other].vert_prev == -1) {
- BLI_heap_insert(heap, data[vert_other].cost, &data[vert_other].vert);
+ BLI_heapsimple_insert(heap, data[vert_other].cost, &data[vert_other].vert);
}
data[vert_other].vert_prev = vert_curr;
}
@@ -1640,7 +1820,7 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
}
- BLI_heap_free(heap, NULL);
+ BLI_heapsimple_free(heap, NULL);
if (vert_curr == vert_dst) {
i = 0;
@@ -1660,26 +1840,29 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = obedit->data;
- Nurb *nu_src = BKE_curve_nurb_active_get(cu);
- int vert_src = cu->actvert;
-
ViewContext vc;
Nurb *nu_dst;
BezTriple *bezt_dst;
BPoint *bp_dst;
int vert_dst;
void *vert_dst_p;
+ Base *basact = NULL;
- if (vert_src == CU_ACT_NONE) {
+ view3d_operator_needs_opengl(C);
+ ED_view3d_viewcontext_init(C, &vc);
+ copy_v2_v2_int(vc.mval, event->mval);
+
+ if (!ED_curve_pick_vert(&vc, 1, &nu_dst, &bezt_dst, &bp_dst, NULL, &basact)) {
return OPERATOR_PASS_THROUGH;
}
- view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ Object *obedit = basact->object;
+ Curve *cu = obedit->data;
+ Nurb *nu_src = BKE_curve_nurb_active_get(cu);
+ int vert_src = cu->actvert;
- if (!ED_curve_pick_vert(&vc, 1, event->mval, &nu_dst, &bezt_dst, &bp_dst, NULL)) {
+ if (vert_src == CU_ACT_NONE) {
return OPERATOR_PASS_THROUGH;
}
@@ -1703,6 +1886,11 @@ static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
BKE_curve_nurb_vert_active_set(cu, nu_dst, vert_dst_p);
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 4ced6ce506c..ecc4ed8b602 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -22,25 +22,29 @@
* \ingroup edcurve
*/
+#include "MEM_guardedalloc.h"
+
+#include "CLG_log.h"
+
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_anim_types.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_array_utils.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
-#include "BKE_library.h"
-#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "ED_object.h"
+#include "ED_undo.h"
#include "ED_util.h"
#include "ED_curve.h"
@@ -49,6 +53,9 @@
#include "curve_intern.h"
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.curve"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -186,13 +193,19 @@ static Object *editcurve_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
-typedef struct CurveUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-editmode. */
+typedef struct CurveUndoStep_Elem {
UndoRefID_Object obedit_ref;
UndoCurve data;
+} CurveUndoStep_Elem;
+
+typedef struct CurveUndoStep {
+ UndoStep step;
+ CurveUndoStep_Elem *elems;
+ uint elems_len;
} CurveUndoStep;
static bool curve_undosys_poll(bContext *C)
@@ -204,9 +217,23 @@ static bool curve_undosys_poll(bContext *C)
static bool curve_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
CurveUndoStep *us = (CurveUndoStep *)us_p;
- us->obedit_ref.ptr = editcurve_object_from_context(C);
- undocurve_from_editcurve(&us->data, us->obedit_ref.ptr->data, us->obedit_ref.ptr->shapenr);
- us->step.data_size = us->data.undo_size;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
+ us->elems_len = objects_len;
+
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ CurveUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ undocurve_from_editcurve(&elem->data, ob->data, ob->shapenr);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
@@ -217,23 +244,47 @@ static void curve_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UN
BLI_assert(curve_undosys_poll(C));
CurveUndoStep *us = (CurveUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- undocurve_to_editcurve(&us->data, obedit->data, &obedit->shapenr);
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ CurveUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ Curve *cu = obedit->data;
+ if (cu->editnurb == NULL) {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
+ us_p->name, obedit->id.name);
+ continue;
+ }
+ undocurve_to_editcurve(&elem->data, obedit->data, &obedit->shapenr);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
+
+ /* The first element is always active */
+ ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
+
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
static void curve_undosys_step_free(UndoStep *us_p)
{
CurveUndoStep *us = (CurveUndoStep *)us_p;
- undocurve_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ CurveUndoStep_Elem *elem = &us->elems[i];
+ undocurve_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
static void curve_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
CurveUndoStep *us = (CurveUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ CurveUndoStep_Elem *elem = &us->elems[i];
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
+ }
}
/* Export for ED_undo_sys. */
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index bc4a4d0105d..b87584dc8b7 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -49,13 +49,15 @@
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_font.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -245,6 +247,7 @@ static int insert_into_textbuf(Object *obedit, uintptr_t c)
static void text_update_edited(bContext *C, Object *obedit, int mode)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
@@ -253,11 +256,12 @@ static void text_update_edited(bContext *C, Object *obedit, int mode)
/* run update first since it can move the cursor */
if (mode == FO_EDIT) {
/* re-tesselllate */
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
}
else {
/* depsgraph runs above, but since we're not tagging for update, call direct */
- BKE_vfont_to_curve(obedit, mode);
+ /* We need evaluated data here. */
+ BKE_vfont_to_curve(DEG_get_evaluated_object(depsgraph, obedit), mode);
}
cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
@@ -272,6 +276,7 @@ static void text_update_edited(bContext *C, Object *obedit, int mode)
}
}
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
}
@@ -418,7 +423,9 @@ void FONT_OT_text_paste_from_file(wmOperatorType *ot)
static void txt_add_object(bContext *C, TextLine *firstline, int totline, const float offset[3])
{
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Curve *cu;
Object *obedit;
Base *base;
@@ -428,13 +435,13 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const
int a;
float rot[3] = {0.f, 0.f, 0.f};
- obedit = BKE_object_add(bmain, scene, OB_FONT, NULL);
- base = scene->basact;
+ obedit = BKE_object_add(bmain, scene, view_layer, OB_FONT, NULL);
+ base = view_layer->basact;
/* seems to assume view align ? TODO - look into this, could be an operator option */
ED_object_base_init_transform(C, base, NULL, rot);
- BKE_object_where_is_calc(scene, obedit);
+ BKE_object_where_is_calc(depsgraph, scene, obedit);
add_v3_v3(obedit->loc, offset);
@@ -581,7 +588,7 @@ static int set_style(bContext *C, const int style, const bool clear)
ef->textbufinfo[i].flag |= style;
}
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
@@ -891,6 +898,7 @@ static const EnumPropertyItem move_type_items[] = {
static int move_cursor(bContext *C, int type, const bool select)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
@@ -973,17 +981,17 @@ static int move_cursor(bContext *C, int type, const bool select)
else if (ef->pos >= MAXTEXT) ef->pos = MAXTEXT;
else if (ef->pos < 0) ef->pos = 0;
- /* apply virtical cursor motion to position immediately
+ /* apply vertical cursor motion to position immediately
* otherwise the selection will lag behind */
if (FO_CURS_IS_MOTION(cursmove)) {
- BKE_vfont_to_curve(obedit, cursmove);
+ BKE_vfont_to_curve(DEG_get_evaluated_object(depsgraph, obedit), cursmove);
cursmove = FO_CURS;
}
if (select == 0) {
if (ef->selstart) {
ef->selstart = ef->selend = 0;
- BKE_vfont_to_curve(obedit, FO_SELCHANGE);
+ BKE_vfont_to_curve(DEG_get_evaluated_object(depsgraph, obedit), FO_SELCHANGE);
}
}
@@ -1427,7 +1435,7 @@ void FONT_OT_text_insert(wmOperatorType *ot)
ot->poll = ED_operator_editfont;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
RNA_def_string(ot->srna, "text", NULL, 0, "Text", "Text to insert at the cursor position");
@@ -1449,6 +1457,7 @@ static int textbox_add_exec(bContext *C, wmOperator *UNUSED(op))
cu->totbox++;
}
+ DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
}
@@ -1491,6 +1500,7 @@ static int textbox_remove_exec(bContext *C, wmOperator *op)
cu->actbox--;
}
+ DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 3a76d0333f9..d4d48e93f43 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -38,9 +38,10 @@
#include "BKE_context.h"
#include "BKE_font.h"
-#include "BKE_depsgraph.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "ED_object.h"
#include "ED_curve.h"
#include "ED_util.h"
@@ -358,7 +359,7 @@ static void font_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNU
Object *obedit = us->obedit_ref.ptr;
Curve *cu = obedit->data;
undofont_to_editfont(&us->data, cu);
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 3f6de14180a..1d58f3e6615 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -42,8 +42,8 @@ set(ICON_NAMES
tria_up
arrow_leftright
plus
- disclosure_tri_down
disclosure_tri_right
+ disclosure_tri_down
radiobut_off
radiobut_on
menu_panel
@@ -52,22 +52,19 @@ set(ICON_NAMES
dot
collapsemenu
x
- go_left
- plug
- ui
+ duplicate
node
node_sel
- fullscreen
- splitscreen
+ window
+ workspace
rightarrow_thin
bordermove
viewzoom
- zoomin
- zoomout
+ add
+ remove
panel_close
copy_id
eyedropper
- link_area
auto
checkbox_dehlt
checkbox_hlt
@@ -78,80 +75,86 @@ set(ICON_NAMES
screen_back
rightarrow
downarrow_hlt
- dotsup
- dotsdown
- link
- inlink
plugin
help
ghost_enabled
color
- linked
unlinked
+ linked
hand
zoom_all
zoom_selected
zoom_previous
zoom_in
zoom_out
- render_region
- border_rect
- border_lasso
+ driver_distance
+ driver_rotational_difference
+ driver_transform
freeze
stylus_pressure
ghost_disabled
- new
+ file_new
file_tick
quit
url
recover_last
+ three_dots
fullscreen_enter
fullscreen_exit
- lamp
+ light
material
texture
anim
world
scene
- edit
- game
- radio
+ output
script
particles
physics
speaker
- texture_shaded
+ tool_settings
+ shaderfx
+ fake_user_off
+ fake_user_on
view3d
- ipo
- oops
- buts
- filesel
- image_col
+ graph
+ outliner
+ properties
+ filebrowser
+ image
info
sequence
text
- imasel
sound
action
nla
- scriptwin
+ preferences
time
nodetree
- logic
console
- preferences
clip
asset_manager
+ node_compositing
+ node_texture
+ node_material
object_datamode
editmode_hlt
- facesel_hlt
+ uv
vpaint_hlt
tpaint_hlt
wpaint_hlt
sculptmode_hlt
pose_hlt
particlemode
- lightpaint
+ tracking
+ tracking_backwards
+ tracking_forwards
+ tracking_backwards_single
+ tracking_forwards_single
+ tracking_clear_backwards
+ tracking_clear_forwards
+ tracking_refine_backwards
+ tracking_refine_forwards
scene_data
renderlayers
world_data
@@ -160,7 +163,7 @@ set(ICON_NAMES
curve_data
meta_data
lattice_data
- lamp_data
+ light_data
material_data
texture_data
anim_data
@@ -169,7 +172,7 @@ set(ICON_NAMES
library_data_direct
group
armature_data
- pose_data
+ community
bone_data
constraint
shapekey_data
@@ -177,6 +180,7 @@ set(ICON_NAMES
camera_stereo
package
uglypackage
+ experimental
brush_data
image_data
file
@@ -185,7 +189,7 @@ set(ICON_NAMES
render_result
surface_data
empty_data
- settings
+ preset
render_animation
render_still
library_data_broken
@@ -194,18 +198,43 @@ set(ICON_NAMES
library_data_indirect
greasepencil
line_data
+ library_data_override
group_bone
group_vertex
group_vcol
group_uvs
+ face_maps
rna
rna_add
+ mouse_lmb
+ mouse_mmb
+ mouse_rmb
+ mouse_move
+ mouse_lmb_drag
+ mouse_mmb_drag
+ mouse_rmb_drag
+ preset_new
+ decorate
+ decorate_keyframe
+ decorate_animate
+ decorate_driver
+ decorate_linked
+ decorate_library_override
+ decorate_unlocked
+ decorate_locked
+ decorate_override
+ sealed
+ heart
+ orphan_data
+ user
+ system
+ settings
outliner_ob_empty
outliner_ob_mesh
outliner_ob_curve
outliner_ob_lattice
outliner_ob_meta
- outliner_ob_lamp
+ outliner_ob_light
outliner_ob_camera
outliner_ob_armature
outliner_ob_font
@@ -213,26 +242,39 @@ set(ICON_NAMES
outliner_ob_speaker
outliner_ob_force_field
outliner_ob_group_instance
+ outliner_ob_greasepencil
+ outliner_ob_lightprobe
+ outliner_ob_image
restrict_color_off
restrict_color_on
- restrict_view_off
- restrict_view_on
- restrict_select_off
+ hide_on
+ hide_off
restrict_select_on
- restrict_render_off
+ restrict_select_off
restrict_render_on
+ restrict_render_off
outliner_data_empty
outliner_data_mesh
outliner_data_curve
outliner_data_lattice
outliner_data_meta
- outliner_data_lamp
+ outliner_data_light
outliner_data_camera
outliner_data_armature
outliner_data_font
outliner_data_surface
outliner_data_speaker
- outliner_data_pose
+ outliner_data_greasepencil
+ gp_select_points
+ gp_select_strokes
+ gp_multiframe_editing
+ gp_only_selected
+ modifier_off
+ modifier_on
+ onionskin_off
+ onionskin_on
+ restrict_view_on
+ restrict_view_off
mesh_plane
mesh_cube
mesh_circle
@@ -244,12 +286,15 @@ set(ICON_NAMES
mesh_torus
mesh_cone
mesh_capsule
- lamp_point
- lamp_sun
- lamp_spot
- lamp_hemi
- lamp_area
- meta_empty
+ empty_single_arrow
+ light_point
+ light_sun
+ light_spot
+ light_hemi
+ light_area
+ cube
+ sphere
+ cone
meta_plane
meta_cube
meta_ball
@@ -261,11 +306,17 @@ set(ICON_NAMES
surface_ncylinder
surface_nsphere
surface_ntorus
+ empty_axis
+ stroke
+ empty_arrows
curve_bezcurve
curve_bezcircle
curve_ncurve
curve_ncircle
curve_path
+ lightprobe_cubemap
+ lightprobe_planar
+ lightprobe_grid
color_red
color_green
color_blue
@@ -286,8 +337,26 @@ set(ICON_NAMES
force_turbulence
force_drag
force_smokeflow
+ image_plane
+ image_background
+ image_reference
node_insert_on
node_insert_off
+ node_top
+ node_side
+ node_corner
+ align_left
+ align_center
+ align_right
+ align_justify
+ align_flush
+ align_top
+ align_middle
+ align_bottom
+ bold
+ italic
+ underline
+ small_caps
modifier
mod_wave
mod_build
@@ -305,7 +374,7 @@ set(ICON_NAMES
mod_displace
mod_curve
mod_lattice
- constraint_data
+ mod_tint
mod_armature
mod_shrinkwrap
mod_cast
@@ -331,6 +400,15 @@ set(ICON_NAMES
mod_wireframe
mod_data_transfer
mod_normaledit
+ mod_particle_instance
+ mod_hue_saturation
+ mod_noise
+ mod_offset
+ mod_simplify
+ mod_thickness
+ mod_instance
+ mod_time
+ mod_opacity
rec
play
ff
@@ -338,7 +416,6 @@ set(ICON_NAMES
pause
prev_keyframe
next_keyframe
- play_audio
play_reverse
preview_range
action_tweak
@@ -347,8 +424,8 @@ set(ICON_NAMES
pmarker
marker_hlt
marker
- space2
- space3
+ keyframe_hlt
+ keyframe
keyingset
key_dehlt
key_hlt
@@ -382,13 +459,12 @@ set(ICON_NAMES
vertexsel
edgesel
facesel
- loopsel
- rotate
- cursor
- rotatecollection
- rotatecenter
- rotactive
- align
+ pivot_boundbox
+ pivot_cursor
+ pivot_individual
+ pivot_median
+ pivot_active
+ center_only
smoothcurve
spherecurve
rootcurve
@@ -399,13 +475,10 @@ set(ICON_NAMES
prop_off
prop_on
prop_con
+ sculpt_dyntopo
particle_point
particle_tip
particle_path
- man_trans
- man_rot
- man_scale
- manipul
snap_off
snap_on
snap_normal
@@ -422,25 +495,37 @@ set(ICON_NAMES
clipuv_hlt
snap_peel_object
grid
- pastedown
+ object_origin
+ orientation_global
+ orientation_gimbal
+ orientation_local
+ orientation_normal
+ orientation_view
copydown
+ pastedown
pasteflipup
pasteflipdown
- snap_surface
+ vis_sel_11
+ vis_sel_10
+ vis_sel_01
+ vis_sel_00
automerge_on
automerge_off
- retopo
uv_vertexsel
uv_edgesel
uv_facesel
uv_islandsel
uv_sync_select
- bbox
- wire
- solid
- smooth
- potato
- ortho
+ normals_vertex
+ normals_face
+ normals_vertex_face
+ shading_bbox
+ shading_wire
+ shading_solid
+ shading_rendered
+ shading_texture
+ overlay
+ xray
lockview_off
lockview_on
axis_side
@@ -456,20 +541,17 @@ set(ICON_NAMES
sortbyext
sorttime
sortsize
- longdisplay
shortdisplay
- ghost
+ longdisplay
imgdisplay
- save_as
- save_copy
bookmarks
fontpreview
filter
newfolder
- open_recent
file_parent
file_refresh
file_folder
+ file_blank
file_blend
file_image
file_movie
@@ -477,18 +559,19 @@ set(ICON_NAMES
file_sound
file_font
file_text
- recover_auto
- save_prefs
+ sort_desc
+ sort_asc
link_blend
append_blend
import
export
- external_data
- load_factory
loop_back
loop_forwards
back
forward
+ file_volume
+ alembic
+ volume
file_hidden
file_backup
disk_drive
@@ -500,6 +583,9 @@ set(ICON_NAMES
aliased
antialiased
mat_sphere_sky
+ matshaderball
+ matcloth
+ matfluid
wordwrap_off
wordwrap_on
syntax_off
@@ -517,7 +603,149 @@ set(ICON_NAMES
image_rgb_alpha
image_alpha
image_zdepth
- imagefile
+ view_perspective
+ view_ortho
+ view_camera
+ view_pan
+ view_zoom
+)
+
+# This section is maintained by the updating script, keep BEGIN/END comments.
+set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
+ # BEGIN ICON_GEOM_NAMES
+ brush.gpencil_draw.draw
+ brush.gpencil_draw.erase
+ brush.gpencil_draw.fill
+ brush.paint_texture.airbrush
+ brush.paint_texture.clone
+ brush.paint_texture.draw
+ brush.paint_texture.fill
+ brush.paint_texture.mask
+ brush.paint_texture.masklort
+ brush.paint_texture.multiply
+ brush.paint_texture.smear
+ brush.paint_texture.soften
+ brush.paint_vertex.alpha
+ brush.paint_vertex.average
+ brush.paint_vertex.blur
+ brush.paint_vertex.draw
+ brush.paint_vertex.smear
+ brush.paint_weight.average
+ brush.paint_weight.blur
+ brush.paint_weight.draw
+ brush.paint_weight.mix
+ brush.paint_weight.smear
+ brush.particle.add
+ brush.particle.comb
+ brush.particle.cut
+ brush.particle.length
+ brush.particle.puff
+ brush.particle.smooth
+ brush.particle.weight
+ brush.sculpt.blob
+ brush.sculpt.clay
+ brush.sculpt.clay_strips
+ brush.sculpt.crease
+ brush.sculpt.draw
+ brush.sculpt.fill
+ brush.sculpt.flatten
+ brush.sculpt.grab
+ brush.sculpt.inflate
+ brush.sculpt.layer
+ brush.sculpt.mask
+ brush.sculpt.nudge
+ brush.sculpt.pinch
+ brush.sculpt.rotate
+ brush.sculpt.scrape
+ brush.sculpt.simplify
+ brush.sculpt.smooth
+ brush.sculpt.snake_hook
+ brush.sculpt.thumb
+ brush.uv_sculpt.grab
+ brush.uv_sculpt.pinch
+ brush.uv_sculpt.relax
+ none
+ ops.armature.bone.roll
+ ops.armature.extrude_cursor
+ ops.armature.extrude_move
+ ops.curve.draw
+ ops.curve.extrude_cursor
+ ops.curve.extrude_move
+ ops.generic.cursor
+ ops.generic.select
+ ops.generic.select_box
+ ops.generic.select_circle
+ ops.generic.select_lasso
+ ops.gpencil.draw
+ ops.gpencil.draw.eraser
+ ops.gpencil.draw.line
+ ops.gpencil.draw.poly
+ ops.gpencil.edit_bend
+ ops.gpencil.edit_mirror
+ ops.gpencil.edit_shear
+ ops.gpencil.edit_to_sphere
+ ops.gpencil.primitive_box
+ ops.gpencil.primitive_circle
+ ops.gpencil.primitive_line
+ ops.gpencil.sculpt_clone
+ ops.gpencil.sculpt_grab
+ ops.gpencil.sculpt_pinch
+ ops.gpencil.sculpt_push
+ ops.gpencil.sculpt_randomize
+ ops.gpencil.sculpt_smooth
+ ops.gpencil.sculpt_strength
+ ops.gpencil.sculpt_thickness
+ ops.gpencil.sculpt_twist
+ ops.gpencil.sculpt_weight
+ ops.mesh.bevel
+ ops.mesh.bisect
+ ops.mesh.dupli_extrude_cursor
+ ops.mesh.extrude_faces_move
+ ops.mesh.extrude_region_move
+ ops.mesh.extrude_region_shrink_fatten
+ ops.mesh.inset
+ ops.mesh.knife_tool
+ ops.mesh.loopcut_slide
+ ops.mesh.offset_edge_loops_slide
+ ops.mesh.polybuild_hover
+ ops.mesh.primitive_cone_add_gizmo
+ ops.mesh.primitive_cube_add_gizmo
+ ops.mesh.primitive_cylinder_add_gizmo
+ ops.mesh.primitive_grid_add_gizmo
+ ops.mesh.primitive_sphere_add_gizmo
+ ops.mesh.primitive_torus_add_gizmo
+ ops.mesh.rip
+ ops.mesh.rip_edge
+ ops.mesh.spin
+ ops.mesh.spin.duplicate
+ ops.mesh.vertices_smooth
+ ops.paint.vertex_color_fill
+ ops.paint.weight_fill
+ ops.paint.weight_gradient
+ ops.paint.weight_sample
+ ops.paint.weight_sample_group
+ ops.pose.breakdowner
+ ops.pose.push
+ ops.pose.relax
+ ops.sculpt.border_hide
+ ops.sculpt.border_mask
+ ops.transform.bone_envelope
+ ops.transform.bone_size
+ ops.transform.edge_slide
+ ops.transform.push_pull
+ ops.transform.resize.cage
+ ops.transform.resize
+ ops.transform.rotate
+ ops.transform.shear
+ ops.transform.shrink_fatten
+ ops.transform.tilt
+ ops.transform.tosphere
+ ops.transform.transform
+ ops.transform.translate
+ ops.transform.vert_slide
+ ops.transform.vertex_random
+ ops.view3d.ruler
+ # END ICON_GEOM_NAMES
)
data_to_c_simple(../../../../release/datafiles/bfont.pfb SRC)
@@ -531,8 +759,8 @@ if(WITH_BLENDER)
# blender UI only
# blends
- data_to_c_simple(../../../../release/datafiles/preview.blend SRC)
data_to_c_simple(../../../../release/datafiles/preview_cycles.blend SRC)
+ data_to_c_simple(../../../../release/datafiles/preview_grease_pencil.blend SRC)
# images
data_to_c_simple(../../../../release/datafiles/splash.png SRC)
@@ -555,24 +783,20 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/prvicons.png SRC)
# brushes
- data_to_c_simple(../../../../release/datafiles/brushicons/add.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/blob.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/blur.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/clay.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/claystrips.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/clone.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/crease.png SRC)
- data_to_c_simple(../../../../release/datafiles/brushicons/darken.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/draw.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/fill.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/flatten.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/grab.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/inflate.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/layer.png SRC)
- data_to_c_simple(../../../../release/datafiles/brushicons/lighten.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/mask.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/mix.png SRC)
- data_to_c_simple(../../../../release/datafiles/brushicons/multiply.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/nudge.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/pinch.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/scrape.png SRC)
@@ -580,39 +804,34 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/smooth.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/snake_hook.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/soften.png SRC)
- data_to_c_simple(../../../../release/datafiles/brushicons/subtract.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/texdraw.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/texfill.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/texmask.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/thumb.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/twist.png SRC)
- data_to_c_simple(../../../../release/datafiles/brushicons/vertexdraw.png SRC)
- # matcap
- data_to_c_simple(../../../../release/datafiles/matcaps/mc01.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc02.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc03.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc04.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc05.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc06.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc07.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc08.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc09.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc10.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc11.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc12.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc13.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc14.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc15.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc16.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc17.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc18.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc19.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc20.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc21.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc22.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc23.jpg SRC)
- data_to_c_simple(../../../../release/datafiles/matcaps/mc24.jpg SRC)
+ # grease pencil sculpt
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_smooth.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_thickness.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_strength.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_grab.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_push.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_twist.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pinch.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_randomize.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_clone.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_weight.png SRC)
+
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pencil.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pen.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_ink.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_inknoise.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_block.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_marker.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_fill.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_soft.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC)
endif()
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
new file mode 100644
index 00000000000..0e7b2a8be0f
--- /dev/null
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -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.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../bmesh
+ ../../depsgraph
+ ../../gpu
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+ ../../../../intern/eigen
+ ../../../../intern/glew-mx
+)
+
+set(INC_SYS
+ ${GLEW_INCLUDE_PATH}
+)
+
+set(SRC
+ gizmo_draw_utils.c
+ gizmo_geometry.h
+ gizmo_library_intern.h
+ gizmo_library_presets.c
+ gizmo_library_utils.c
+ geometry/geom_arrow_gizmo.c
+ geometry/geom_cube_gizmo.c
+ geometry/geom_dial_gizmo.c
+ gizmo_group_types/value2d_gizmo_group.c
+ gizmo_types/arrow2d_gizmo.c
+ gizmo_types/arrow3d_gizmo.c
+ gizmo_types/blank3d_gizmo.c
+ gizmo_types/button2d_gizmo.c
+ gizmo_types/cage2d_gizmo.c
+ gizmo_types/cage3d_gizmo.c
+ gizmo_types/dial3d_gizmo.c
+ gizmo_types/move3d_gizmo.c
+ gizmo_types/primitive3d_gizmo.c
+ gizmo_types/value2d_gizmo.c
+)
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_editor_gizmo_library "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
new file mode 100644
index 00000000000..55b33b0d8ad
--- /dev/null
+++ b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
@@ -0,0 +1,141 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file geom_arrow_gizmo.c
+ * \ingroup edgizmolib
+ */
+
+#include "../gizmo_geometry.h"
+
+static float verts[][3] = {
+ {-0.000000, 0.012320, 0.000000},
+ {-0.000000, 0.012320, 0.974306},
+ {0.008711, 0.008711, 0.000000},
+ {0.008711, 0.008711, 0.974306},
+ {0.012320, -0.000000, 0.000000},
+ {0.012320, -0.000000, 0.974306},
+ {0.008711, -0.008711, 0.000000},
+ {0.008711, -0.008711, 0.974306},
+ {-0.000000, -0.012320, 0.000000},
+ {-0.000000, -0.012320, 0.974306},
+ {-0.008711, -0.008711, 0.000000},
+ {-0.008711, -0.008711, 0.974306},
+ {-0.012320, 0.000000, 0.000000},
+ {-0.012320, 0.000000, 0.974306},
+ {-0.008711, 0.008711, 0.000000},
+ {-0.008711, 0.008711, 0.974306},
+ {0.000000, 0.072555, 0.974306},
+ {0.051304, 0.051304, 0.974306},
+ {0.072555, -0.000000, 0.974306},
+ {0.051304, -0.051304, 0.974306},
+ {-0.000000, -0.072555, 0.974306},
+ {-0.051304, -0.051304, 0.974306},
+ {-0.072555, 0.000000, 0.974306},
+ {-0.051304, 0.051304, 0.974306},
+ {0.000000, -0.000000, 1.268098},
+};
+
+static float normals[][3] = {
+ {0.000000, 0.776360, -0.630238},
+ {0.000000, 0.594348, -0.804163},
+ {0.548967, 0.548967, -0.630238},
+ {0.420270, 0.420270, -0.804163},
+ {0.776360, 0.000000, -0.630238},
+ {0.594378, 0.000000, -0.804163},
+ {0.548967, -0.548967, -0.630238},
+ {0.420270, -0.420270, -0.804163},
+ {0.000000, -0.776360, -0.630238},
+ {0.000000, -0.594378, -0.804163},
+ {-0.548967, -0.548967, -0.630238},
+ {-0.420270, -0.420270, -0.804163},
+ {-0.776360, 0.000000, -0.630238},
+ {-0.594378, 0.000000, -0.804163},
+ {-0.548967, 0.548967, -0.630238},
+ {-0.420270, 0.420270, -0.804163},
+ {0.000000, 0.843226, -0.537492},
+ {0.596271, 0.596271, -0.537492},
+ {0.843226, 0.000000, -0.537492},
+ {0.596271, -0.596271, -0.537492},
+ {0.000000, -0.843226, -0.537492},
+ {-0.596271, -0.596271, -0.537492},
+ {-0.843226, 0.000000, -0.537492},
+ {-0.596271, 0.596271, -0.537492},
+ {0.000000, 0.000000, 1.000000},
+};
+
+static unsigned short indices[] = {
+ 1, 3, 2,
+ 3, 5, 4,
+ 5, 7, 6,
+ 7, 9, 8,
+ 9, 11, 10,
+ 11, 13, 12,
+ 5, 18, 19,
+ 15, 1, 0,
+ 13, 15, 14,
+ 6, 10, 14,
+ 11, 21, 22,
+ 7, 19, 20,
+ 13, 22, 23,
+ 3, 17, 18,
+ 9, 20, 21,
+ 15, 23, 16,
+ 1, 16, 17,
+ 23, 22, 24,
+ 21, 20, 24,
+ 19, 18, 24,
+ 17, 16, 24,
+ 16, 23, 24,
+ 22, 21, 24,
+ 20, 19, 24,
+ 18, 17, 24,
+ 0, 1, 2,
+ 2, 3, 4,
+ 4, 5, 6,
+ 6, 7, 8,
+ 8, 9, 10,
+ 10, 11, 12,
+ 7, 5, 19,
+ 14, 15, 0,
+ 12, 13, 14,
+ 14, 0, 2,
+ 2, 4, 6,
+ 6, 8, 10,
+ 10, 12, 14,
+ 14, 2, 6,
+ 13, 11, 22,
+ 9, 7, 20,
+ 15, 13, 23,
+ 5, 3, 18,
+ 11, 9, 21,
+ 1, 15, 16,
+ 3, 1, 17,
+};
+
+GizmoGeomInfo wm_gizmo_geom_data_arrow = {
+ .nverts = 25,
+ .ntris = 46,
+ .verts = verts,
+ .normals = normals,
+ .indices = indices,
+};
diff --git a/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c
new file mode 100644
index 00000000000..410e2a5ad6e
--- /dev/null
+++ b/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c
@@ -0,0 +1,75 @@
+/*
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file geom_cube_gizmo.c
+ * \ingroup edgizmolib
+ */
+
+#include "../gizmo_geometry.h"
+
+static const float verts[][3] = {
+ {1.000000, 1.000000, -1.000000},
+ {1.000000, -1.000000, -1.000000},
+ {-1.000000, -1.000000, -1.000000},
+ {-1.000000, 1.000000, -1.000000},
+ {1.000000, 1.000000, 1.000000},
+ {0.999999, -1.000001, 1.000000},
+ {-1.000000, -1.000000, 1.000000},
+ {-1.000000, 1.000000, 1.000000},
+};
+
+static const float normals[][3] = {
+ {0.577349, 0.577349, -0.577349},
+ {0.577349, -0.577349, -0.577349},
+ {-0.577349, -0.577349, -0.577349},
+ {-0.577349, 0.577349, -0.577349},
+ {0.577349, 0.577349, 0.577349},
+ {0.577349, -0.577349, 0.577349},
+ {-0.577349, -0.577349, 0.577349},
+ {-0.577349, 0.577349, 0.577349},
+};
+
+static const unsigned short indices[] = {
+ 1, 2, 3,
+ 7, 6, 5,
+ 4, 5, 1,
+ 5, 6, 2,
+ 2, 6, 7,
+ 0, 3, 7,
+ 0, 1, 3,
+ 4, 7, 5,
+ 0, 4, 1,
+ 1, 5, 2,
+ 3, 2, 7,
+ 4, 0, 7,
+};
+
+GizmoGeomInfo wm_gizmo_geom_data_cube = {
+ .nverts = 8,
+ .ntris = 12,
+ .verts = verts,
+ .normals = normals,
+ .indices = indices,
+};
diff --git a/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c
new file mode 100644
index 00000000000..22cf0785c64
--- /dev/null
+++ b/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c
@@ -0,0 +1,813 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file geom_dial_gizmo.c
+ * \ingroup edgizmolib
+ */
+
+#include "../gizmo_geometry.h"
+
+static const float verts[][3] = {
+ {1.034000, 0.000000, 0.000000},
+ {1.017000, 0.000000, 0.029445},
+ {0.983000, 0.000000, 0.029445},
+ {0.966000, 0.000000, 0.000000},
+ {0.983000, 0.000000, -0.029445},
+ {1.017000, 0.000000, -0.029445},
+ {1.014132, 0.201723, 0.000000},
+ {0.997459, 0.198407, 0.029445},
+ {0.964112, 0.191774, 0.029445},
+ {0.947439, 0.188457, 0.000000},
+ {0.964112, 0.191774, -0.029445},
+ {0.997459, 0.198407, -0.029445},
+ {0.955292, 0.395695, 0.000000},
+ {0.939586, 0.389189, 0.029445},
+ {0.908174, 0.376178, 0.029445},
+ {0.892468, 0.369672, 0.000000},
+ {0.908174, 0.376178, -0.029445},
+ {0.939586, 0.389189, -0.029445},
+ {0.859740, 0.574460, 0.000000},
+ {0.845605, 0.565015, 0.029445},
+ {0.817335, 0.546126, 0.029445},
+ {0.803200, 0.536681, 0.000000},
+ {0.817335, 0.546126, -0.029445},
+ {0.845605, 0.565015, -0.029445},
+ {0.731148, 0.731148, 0.000000},
+ {0.719128, 0.719128, 0.029445},
+ {0.695086, 0.695086, 0.029445},
+ {0.683065, 0.683065, 0.000000},
+ {0.695086, 0.695086, -0.029445},
+ {0.719128, 0.719128, -0.029445},
+ {0.574460, 0.859740, 0.000000},
+ {0.565015, 0.845605, 0.029445},
+ {0.546125, 0.817335, 0.029445},
+ {0.536681, 0.803200, 0.000000},
+ {0.546125, 0.817335, -0.029445},
+ {0.565015, 0.845605, -0.029445},
+ {0.395695, 0.955291, 0.000000},
+ {0.389189, 0.939585, 0.029445},
+ {0.376178, 0.908173, 0.029445},
+ {0.369672, 0.892467, 0.000000},
+ {0.376178, 0.908173, -0.029445},
+ {0.389189, 0.939585, -0.029445},
+ {0.201724, 1.014132, 0.000000},
+ {0.198407, 0.997459, 0.029445},
+ {0.191774, 0.964112, 0.029445},
+ {0.188457, 0.947439, 0.000000},
+ {0.191774, 0.964112, -0.029445},
+ {0.198407, 0.997459, -0.029445},
+ {0.000000, 1.034000, 0.000000},
+ {0.000000, 1.017000, 0.029445},
+ {0.000000, 0.983000, 0.029445},
+ {0.000000, 0.966000, 0.000000},
+ {0.000000, 0.983000, -0.029445},
+ {0.000000, 1.017000, -0.029445},
+ {-0.201723, 1.014132, 0.000000},
+ {-0.198407, 0.997459, 0.029445},
+ {-0.191774, 0.964112, 0.029445},
+ {-0.188457, 0.947439, 0.000000},
+ {-0.191774, 0.964112, -0.029445},
+ {-0.198407, 0.997459, -0.029445},
+ {-0.395695, 0.955291, 0.000000},
+ {-0.389189, 0.939585, 0.029445},
+ {-0.376178, 0.908174, 0.029445},
+ {-0.369672, 0.892468, 0.000000},
+ {-0.376178, 0.908174, -0.029445},
+ {-0.389189, 0.939585, -0.029445},
+ {-0.574459, 0.859740, 0.000000},
+ {-0.565015, 0.845605, 0.029445},
+ {-0.546125, 0.817335, 0.029445},
+ {-0.536681, 0.803200, 0.000000},
+ {-0.546125, 0.817335, -0.029445},
+ {-0.565015, 0.845605, -0.029445},
+ {-0.731149, 0.731148, 0.000000},
+ {-0.719128, 0.719127, 0.029445},
+ {-0.695086, 0.695086, 0.029445},
+ {-0.683065, 0.683065, 0.000000},
+ {-0.695086, 0.695086, -0.029445},
+ {-0.719128, 0.719127, -0.029445},
+ {-0.859740, 0.574460, 0.000000},
+ {-0.845604, 0.565015, 0.029445},
+ {-0.817335, 0.546126, 0.029445},
+ {-0.803200, 0.536681, 0.000000},
+ {-0.817335, 0.546126, -0.029445},
+ {-0.845604, 0.565015, -0.029445},
+ {-0.955291, 0.395695, 0.000000},
+ {-0.939585, 0.389189, 0.029445},
+ {-0.908173, 0.376178, 0.029445},
+ {-0.892468, 0.369672, 0.000000},
+ {-0.908173, 0.376178, -0.029445},
+ {-0.939585, 0.389189, -0.029445},
+ {-1.014132, 0.201723, 0.000000},
+ {-0.997459, 0.198407, 0.029445},
+ {-0.964112, 0.191774, 0.029445},
+ {-0.947439, 0.188457, 0.000000},
+ {-0.964112, 0.191774, -0.029445},
+ {-0.997459, 0.198407, -0.029445},
+ {-1.034000, 0.000000, 0.000000},
+ {-1.017000, 0.000000, 0.029445},
+ {-0.983000, 0.000000, 0.029445},
+ {-0.966000, 0.000000, 0.000000},
+ {-0.983000, 0.000000, -0.029445},
+ {-1.017000, 0.000000, -0.029445},
+ {-1.014132, -0.201723, 0.000000},
+ {-0.997459, -0.198407, 0.029445},
+ {-0.964112, -0.191774, 0.029445},
+ {-0.947439, -0.188457, 0.000000},
+ {-0.964112, -0.191774, -0.029445},
+ {-0.997459, -0.198407, -0.029445},
+ {-0.955292, -0.395694, 0.000000},
+ {-0.939586, -0.389189, 0.029445},
+ {-0.908174, -0.376177, 0.029445},
+ {-0.892468, -0.369672, 0.000000},
+ {-0.908174, -0.376177, -0.029445},
+ {-0.939586, -0.389189, -0.029445},
+ {-0.859740, -0.574460, 0.000000},
+ {-0.845604, -0.565015, 0.029445},
+ {-0.817335, -0.546126, 0.029445},
+ {-0.803200, -0.536681, 0.000000},
+ {-0.817335, -0.546126, -0.029445},
+ {-0.845604, -0.565015, -0.029445},
+ {-0.731149, -0.731148, 0.000000},
+ {-0.719128, -0.719127, 0.029445},
+ {-0.695086, -0.695086, 0.029445},
+ {-0.683065, -0.683065, 0.000000},
+ {-0.695086, -0.695086, -0.029445},
+ {-0.719128, -0.719127, -0.029445},
+ {-0.574460, -0.859739, 0.000000},
+ {-0.565015, -0.845604, 0.029445},
+ {-0.546126, -0.817334, 0.029445},
+ {-0.536681, -0.803199, 0.000000},
+ {-0.546126, -0.817334, -0.029445},
+ {-0.565015, -0.845604, -0.029445},
+ {-0.395695, -0.955291, 0.000000},
+ {-0.389189, -0.939585, 0.029445},
+ {-0.376178, -0.908174, 0.029445},
+ {-0.369672, -0.892468, 0.000000},
+ {-0.376178, -0.908174, -0.029445},
+ {-0.389189, -0.939585, -0.029445},
+ {-0.201724, -1.014132, 0.000000},
+ {-0.198407, -0.997459, 0.029445},
+ {-0.191774, -0.964112, 0.029445},
+ {-0.188458, -0.947438, 0.000000},
+ {-0.191774, -0.964112, -0.029445},
+ {-0.198407, -0.997459, -0.029445},
+ {0.000000, -1.034000, 0.000000},
+ {0.000000, -1.017000, 0.029445},
+ {0.000000, -0.983000, 0.029445},
+ {0.000000, -0.966000, 0.000000},
+ {0.000000, -0.983000, -0.029445},
+ {0.000000, -1.017000, -0.029445},
+ {0.201723, -1.014132, 0.000000},
+ {0.198407, -0.997459, 0.029445},
+ {0.191773, -0.964112, 0.029445},
+ {0.188457, -0.947439, 0.000000},
+ {0.191773, -0.964112, -0.029445},
+ {0.198407, -0.997459, -0.029445},
+ {0.395695, -0.955291, 0.000000},
+ {0.389189, -0.939585, 0.029445},
+ {0.376178, -0.908173, 0.029445},
+ {0.369672, -0.892467, 0.000000},
+ {0.376178, -0.908173, -0.029445},
+ {0.389189, -0.939585, -0.029445},
+ {0.574460, -0.859740, 0.000000},
+ {0.565015, -0.845605, 0.029445},
+ {0.546125, -0.817335, 0.029445},
+ {0.536681, -0.803200, 0.000000},
+ {0.546125, -0.817335, -0.029445},
+ {0.565015, -0.845605, -0.029445},
+ {0.731148, -0.731149, 0.000000},
+ {0.719127, -0.719128, 0.029445},
+ {0.695086, -0.695086, 0.029445},
+ {0.683065, -0.683066, 0.000000},
+ {0.695086, -0.695086, -0.029445},
+ {0.719127, -0.719128, -0.029445},
+ {0.859740, -0.574460, 0.000000},
+ {0.845605, -0.565015, 0.029445},
+ {0.817335, -0.546126, 0.029445},
+ {0.803200, -0.536681, 0.000000},
+ {0.817335, -0.546126, -0.029445},
+ {0.845605, -0.565015, -0.029445},
+ {0.955291, -0.395695, 0.000000},
+ {0.939585, -0.389189, 0.029445},
+ {0.908173, -0.376178, 0.029445},
+ {0.892467, -0.369673, 0.000000},
+ {0.908173, -0.376178, -0.029445},
+ {0.939585, -0.389189, -0.029445},
+ {1.014132, -0.201723, 0.000000},
+ {0.997459, -0.198407, 0.029445},
+ {0.964112, -0.191774, 0.029445},
+ {0.947439, -0.188457, 0.000000},
+ {0.964112, -0.191774, -0.029445},
+ {0.997459, -0.198407, -0.029445},
+};
+
+static const float normals[][3] = {
+ {1.000000, 0.000000, 0.000000},
+ {0.522691, 0.000000, 0.852504},
+ {-0.475845, 0.000000, 0.879513},
+ {-1.000000, 0.000000, 0.000000},
+ {-0.475845, 0.000000, -0.879513},
+ {0.522691, 0.000000, -0.852504},
+ {0.980773, 0.195074, 0.000000},
+ {0.512650, 0.101962, 0.852504},
+ {-0.466689, -0.092807, 0.879513},
+ {-0.980773, -0.195074, 0.000000},
+ {-0.466689, -0.092807, -0.879513},
+ {0.512650, 0.101962, -0.852504},
+ {0.923856, 0.382672, 0.000000},
+ {0.482894, 0.200018, 0.852504},
+ {-0.439619, -0.182073, 0.879513},
+ {-0.923856, -0.382672, 0.000000},
+ {-0.439619, -0.182073, -0.879513},
+ {0.482894, 0.200018, -0.852504},
+ {0.831446, 0.555559, 0.000000},
+ {0.434614, 0.290384, 0.852504},
+ {-0.395642, -0.264351, 0.879513},
+ {-0.831446, -0.555559, 0.000000},
+ {-0.395642, -0.264351, -0.879513},
+ {0.434614, 0.290384, -0.852504},
+ {0.707083, 0.707083, 0.000000},
+ {0.369610, 0.369610, 0.852504},
+ {-0.336467, -0.336467, 0.879513},
+ {-0.707083, -0.707083, 0.000000},
+ {-0.336467, -0.336467, -0.879513},
+ {0.369610, 0.369610, -0.852504},
+ {0.555559, 0.831446, 0.000000},
+ {0.290384, 0.434614, 0.852504},
+ {-0.264351, -0.395642, 0.879513},
+ {-0.555559, -0.831446, 0.000000},
+ {-0.264351, -0.395642, -0.879513},
+ {0.290384, 0.434614, -0.852504},
+ {0.382672, 0.923856, 0.000000},
+ {0.200018, 0.482894, 0.852504},
+ {-0.182073, -0.439619, 0.879513},
+ {-0.382672, -0.923856, 0.000000},
+ {-0.182073, -0.439619, -0.879513},
+ {0.200018, 0.482894, -0.852504},
+ {0.195074, 0.980773, 0.000000},
+ {0.101962, 0.512650, 0.852504},
+ {-0.092807, -0.466689, 0.879513},
+ {-0.195074, -0.980773, 0.000000},
+ {-0.092807, -0.466689, -0.879513},
+ {0.101962, 0.512650, -0.852504},
+ {0.000000, 1.000000, 0.000000},
+ {0.000000, 0.522691, 0.852504},
+ {0.000000, -0.475845, 0.879513},
+ {0.000000, -1.000000, 0.000000},
+ {0.000000, -0.475845, -0.879513},
+ {0.000000, 0.522691, -0.852504},
+ {-0.195074, 0.980773, 0.000000},
+ {-0.101962, 0.512650, 0.852504},
+ {0.092807, -0.466689, 0.879513},
+ {0.195074, -0.980773, 0.000000},
+ {0.092807, -0.466689, -0.879513},
+ {-0.101962, 0.512650, -0.852504},
+ {-0.382672, 0.923856, 0.000000},
+ {-0.200018, 0.482894, 0.852504},
+ {0.182073, -0.439619, 0.879513},
+ {0.382672, -0.923856, 0.000000},
+ {0.182073, -0.439619, -0.879513},
+ {-0.200018, 0.482894, -0.852504},
+ {-0.555559, 0.831446, 0.000000},
+ {-0.290384, 0.434614, 0.852504},
+ {0.264351, -0.395642, 0.879513},
+ {0.555559, -0.831446, 0.000000},
+ {0.264351, -0.395642, -0.879513},
+ {-0.290384, 0.434614, -0.852504},
+ {-0.707083, 0.707083, 0.000000},
+ {-0.369610, 0.369610, 0.852504},
+ {0.336467, -0.336467, 0.879513},
+ {0.707083, -0.707083, 0.000000},
+ {0.336467, -0.336467, -0.879513},
+ {-0.369610, 0.369610, -0.852504},
+ {-0.831446, 0.555559, 0.000000},
+ {-0.434614, 0.290384, 0.852504},
+ {0.395642, -0.264351, 0.879513},
+ {0.831446, -0.555559, 0.000000},
+ {0.395642, -0.264351, -0.879513},
+ {-0.434614, 0.290384, -0.852504},
+ {-0.923856, 0.382672, 0.000000},
+ {-0.482894, 0.200018, 0.852504},
+ {0.439619, -0.182073, 0.879513},
+ {0.923856, -0.382672, 0.000000},
+ {0.439619, -0.182073, -0.879513},
+ {-0.482894, 0.200018, -0.852504},
+ {-0.980773, 0.195074, 0.000000},
+ {-0.512650, 0.101962, 0.852504},
+ {0.466689, -0.092807, 0.879513},
+ {0.980773, -0.195074, 0.000000},
+ {0.466689, -0.092807, -0.879513},
+ {-0.512650, 0.101962, -0.852504},
+ {-1.000000, 0.000000, 0.000000},
+ {-0.522691, 0.000000, 0.852504},
+ {0.475845, 0.000000, 0.879513},
+ {1.000000, 0.000000, 0.000000},
+ {0.475845, 0.000000, -0.879513},
+ {-0.522691, 0.000000, -0.852504},
+ {-0.980773, -0.195074, 0.000000},
+ {-0.512650, -0.101962, 0.852504},
+ {0.466689, 0.092807, 0.879513},
+ {0.980773, 0.195074, 0.000000},
+ {0.466689, 0.092807, -0.879513},
+ {-0.512650, -0.101962, -0.852504},
+ {-0.923856, -0.382672, 0.000000},
+ {-0.482894, -0.200018, 0.852504},
+ {0.439619, 0.182073, 0.879513},
+ {0.923856, 0.382672, 0.000000},
+ {0.439619, 0.182073, -0.879513},
+ {-0.482894, -0.200018, -0.852504},
+ {-0.831446, -0.555559, 0.000000},
+ {-0.434614, -0.290384, 0.852504},
+ {0.395642, 0.264351, 0.879513},
+ {0.831446, 0.555559, 0.000000},
+ {0.395642, 0.264351, -0.879513},
+ {-0.434614, -0.290384, -0.852504},
+ {-0.707083, -0.707083, 0.000000},
+ {-0.369610, -0.369610, 0.852504},
+ {0.336467, 0.336467, 0.879513},
+ {0.707083, 0.707083, 0.000000},
+ {0.336467, 0.336467, -0.879513},
+ {-0.369610, -0.369610, -0.852504},
+ {-0.555559, -0.831446, 0.000000},
+ {-0.290384, -0.434614, 0.852504},
+ {0.264351, 0.395642, 0.879513},
+ {0.555559, 0.831446, 0.000000},
+ {0.264351, 0.395642, -0.879513},
+ {-0.290384, -0.434614, -0.852504},
+ {-0.382672, -0.923856, 0.000000},
+ {-0.200018, -0.482894, 0.852504},
+ {0.182073, 0.439619, 0.879513},
+ {0.382672, 0.923856, 0.000000},
+ {0.182073, 0.439619, -0.879513},
+ {-0.200018, -0.482894, -0.852504},
+ {-0.195074, -0.980773, 0.000000},
+ {-0.101962, -0.512650, 0.852504},
+ {0.092807, 0.466689, 0.879513},
+ {0.195074, 0.980773, 0.000000},
+ {0.092807, 0.466689, -0.879513},
+ {-0.101962, -0.512650, -0.852504},
+ {0.000000, -1.000000, 0.000000},
+ {0.000000, -0.522691, 0.852504},
+ {0.000000, 0.475845, 0.879513},
+ {0.000000, 1.000000, 0.000000},
+ {0.000000, 0.475845, -0.879513},
+ {0.000000, -0.522691, -0.852504},
+ {0.195074, -0.980773, 0.000000},
+ {0.101962, -0.512650, 0.852504},
+ {-0.092807, 0.466689, 0.879513},
+ {-0.195074, 0.980773, 0.000000},
+ {-0.092807, 0.466689, -0.879513},
+ {0.101962, -0.512650, -0.852504},
+ {0.382672, -0.923856, 0.000000},
+ {0.200018, -0.482894, 0.852504},
+ {-0.182073, 0.439619, 0.879513},
+ {-0.382672, 0.923856, 0.000000},
+ {-0.182073, 0.439619, -0.879513},
+ {0.200018, -0.482894, -0.852504},
+ {0.555559, -0.831446, 0.000000},
+ {0.290384, -0.434614, 0.852504},
+ {-0.264351, 0.395642, 0.879513},
+ {-0.555559, 0.831446, 0.000000},
+ {-0.264351, 0.395642, -0.879513},
+ {0.290384, -0.434614, -0.852504},
+ {0.707083, -0.707083, 0.000000},
+ {0.369610, -0.369610, 0.852504},
+ {-0.336467, 0.336467, 0.879513},
+ {-0.707083, 0.707083, 0.000000},
+ {-0.336467, 0.336467, -0.879513},
+ {0.369610, -0.369610, -0.852504},
+ {0.831446, -0.555559, 0.000000},
+ {0.434614, -0.290384, 0.852504},
+ {-0.395642, 0.264351, 0.879513},
+ {-0.831446, 0.555559, 0.000000},
+ {-0.395642, 0.264351, -0.879513},
+ {0.434614, -0.290384, -0.852504},
+ {0.923856, -0.382672, 0.000000},
+ {0.482894, -0.200018, 0.852504},
+ {-0.439619, 0.182073, 0.879513},
+ {-0.923856, 0.382672, 0.000000},
+ {-0.439619, 0.182073, -0.879513},
+ {0.482894, -0.200018, -0.852504},
+ {0.980773, -0.195074, 0.000000},
+ {0.512650, -0.101962, 0.852504},
+ {-0.466689, 0.092807, 0.879513},
+ {-0.980773, 0.195074, 0.000000},
+ {-0.466689, 0.092807, -0.879513},
+ {0.512650, -0.101962, -0.852504},
+};
+
+static const unsigned short indices[] = {
+ 6, 7, 1,
+ 7, 8, 2,
+ 8, 9, 3,
+ 9, 10, 4,
+ 10, 11, 5,
+ 5, 11, 6,
+ 12, 13, 7,
+ 13, 14, 8,
+ 14, 15, 9,
+ 15, 16, 10,
+ 16, 17, 11,
+ 11, 17, 12,
+ 18, 19, 13,
+ 13, 19, 20,
+ 20, 21, 15,
+ 15, 21, 22,
+ 22, 23, 17,
+ 17, 23, 18,
+ 24, 25, 19,
+ 19, 25, 26,
+ 26, 27, 21,
+ 21, 27, 28,
+ 28, 29, 23,
+ 23, 29, 24,
+ 30, 31, 25,
+ 25, 31, 32,
+ 26, 32, 33,
+ 27, 33, 34,
+ 34, 35, 29,
+ 29, 35, 30,
+ 36, 37, 31,
+ 31, 37, 38,
+ 38, 39, 33,
+ 39, 40, 34,
+ 40, 41, 35,
+ 35, 41, 36,
+ 36, 42, 43,
+ 43, 44, 38,
+ 44, 45, 39,
+ 45, 46, 40,
+ 46, 47, 41,
+ 47, 42, 36,
+ 48, 49, 43,
+ 49, 50, 44,
+ 50, 51, 45,
+ 51, 52, 46,
+ 52, 53, 47,
+ 47, 53, 48,
+ 54, 55, 49,
+ 49, 55, 56,
+ 50, 56, 57,
+ 57, 58, 52,
+ 58, 59, 53,
+ 53, 59, 54,
+ 60, 61, 55,
+ 55, 61, 62,
+ 56, 62, 63,
+ 63, 64, 58,
+ 64, 65, 59,
+ 59, 65, 60,
+ 66, 67, 61,
+ 61, 67, 68,
+ 68, 69, 63,
+ 69, 70, 64,
+ 70, 71, 65,
+ 71, 66, 60,
+ 72, 73, 67,
+ 73, 74, 68,
+ 68, 74, 75,
+ 75, 76, 70,
+ 76, 77, 71,
+ 71, 77, 72,
+ 78, 79, 73,
+ 79, 80, 74,
+ 74, 80, 81,
+ 81, 82, 76,
+ 82, 83, 77,
+ 83, 78, 72,
+ 78, 84, 85,
+ 85, 86, 80,
+ 80, 86, 87,
+ 87, 88, 82,
+ 82, 88, 89,
+ 89, 84, 78,
+ 90, 91, 85,
+ 91, 92, 86,
+ 86, 92, 93,
+ 93, 94, 88,
+ 88, 94, 95,
+ 95, 90, 84,
+ 96, 97, 91,
+ 97, 98, 92,
+ 98, 99, 93,
+ 99, 100, 94,
+ 100, 101, 95,
+ 101, 96, 90,
+ 102, 103, 97,
+ 103, 104, 98,
+ 104, 105, 99,
+ 99, 105, 106,
+ 106, 107, 101,
+ 101, 107, 102,
+ 108, 109, 103,
+ 103, 109, 110,
+ 110, 111, 105,
+ 105, 111, 112,
+ 112, 113, 107,
+ 107, 113, 108,
+ 114, 115, 109,
+ 115, 116, 110,
+ 116, 117, 111,
+ 111, 117, 118,
+ 112, 118, 119,
+ 113, 119, 114,
+ 114, 120, 121,
+ 121, 122, 116,
+ 122, 123, 117,
+ 117, 123, 124,
+ 124, 125, 119,
+ 125, 120, 114,
+ 126, 127, 121,
+ 121, 127, 128,
+ 128, 129, 123,
+ 123, 129, 130,
+ 130, 131, 125,
+ 125, 131, 126,
+ 132, 133, 127,
+ 133, 134, 128,
+ 128, 134, 135,
+ 135, 136, 130,
+ 136, 137, 131,
+ 131, 137, 132,
+ 132, 138, 139,
+ 133, 139, 140,
+ 134, 140, 141,
+ 141, 142, 136,
+ 142, 143, 137,
+ 143, 138, 132,
+ 138, 144, 145,
+ 139, 145, 146,
+ 146, 147, 141,
+ 141, 147, 148,
+ 148, 149, 143,
+ 149, 144, 138,
+ 144, 150, 151,
+ 151, 152, 146,
+ 146, 152, 153,
+ 153, 154, 148,
+ 154, 155, 149,
+ 155, 150, 144,
+ 156, 157, 151,
+ 151, 157, 158,
+ 158, 159, 153,
+ 159, 160, 154,
+ 160, 161, 155,
+ 155, 161, 156,
+ 156, 162, 163,
+ 163, 164, 158,
+ 158, 164, 165,
+ 165, 166, 160,
+ 160, 166, 167,
+ 167, 162, 156,
+ 162, 168, 169,
+ 169, 170, 164,
+ 164, 170, 171,
+ 165, 171, 172,
+ 166, 172, 173,
+ 173, 168, 162,
+ 174, 175, 169,
+ 175, 176, 170,
+ 170, 176, 177,
+ 177, 178, 172,
+ 172, 178, 179,
+ 173, 179, 174,
+ 174, 180, 181,
+ 181, 182, 176,
+ 176, 182, 183,
+ 183, 184, 178,
+ 178, 184, 185,
+ 179, 185, 180,
+ 186, 187, 181,
+ 187, 188, 182,
+ 188, 189, 183,
+ 183, 189, 190,
+ 190, 191, 185,
+ 191, 186, 180,
+ 0, 1, 187,
+ 1, 2, 188,
+ 2, 3, 189,
+ 3, 4, 190,
+ 190, 4, 5,
+ 191, 5, 0,
+ 0, 6, 1,
+ 1, 7, 2,
+ 2, 8, 3,
+ 3, 9, 4,
+ 4, 10, 5,
+ 0, 5, 6,
+ 6, 12, 7,
+ 7, 13, 8,
+ 8, 14, 9,
+ 9, 15, 10,
+ 10, 16, 11,
+ 6, 11, 12,
+ 12, 18, 13,
+ 14, 13, 20,
+ 14, 20, 15,
+ 16, 15, 22,
+ 16, 22, 17,
+ 12, 17, 18,
+ 18, 24, 19,
+ 20, 19, 26,
+ 20, 26, 21,
+ 22, 21, 28,
+ 22, 28, 23,
+ 18, 23, 24,
+ 24, 30, 25,
+ 26, 25, 32,
+ 27, 26, 33,
+ 28, 27, 34,
+ 28, 34, 29,
+ 24, 29, 30,
+ 30, 36, 31,
+ 32, 31, 38,
+ 32, 38, 33,
+ 33, 39, 34,
+ 34, 40, 35,
+ 30, 35, 36,
+ 37, 36, 43,
+ 37, 43, 38,
+ 38, 44, 39,
+ 39, 45, 40,
+ 40, 46, 41,
+ 41, 47, 36,
+ 42, 48, 43,
+ 43, 49, 44,
+ 44, 50, 45,
+ 45, 51, 46,
+ 46, 52, 47,
+ 42, 47, 48,
+ 48, 54, 49,
+ 50, 49, 56,
+ 51, 50, 57,
+ 51, 57, 52,
+ 52, 58, 53,
+ 48, 53, 54,
+ 54, 60, 55,
+ 56, 55, 62,
+ 57, 56, 63,
+ 57, 63, 58,
+ 58, 64, 59,
+ 54, 59, 60,
+ 60, 66, 61,
+ 62, 61, 68,
+ 62, 68, 63,
+ 63, 69, 64,
+ 64, 70, 65,
+ 65, 71, 60,
+ 66, 72, 67,
+ 67, 73, 68,
+ 69, 68, 75,
+ 69, 75, 70,
+ 70, 76, 71,
+ 66, 71, 72,
+ 72, 78, 73,
+ 73, 79, 74,
+ 75, 74, 81,
+ 75, 81, 76,
+ 76, 82, 77,
+ 77, 83, 72,
+ 79, 78, 85,
+ 79, 85, 80,
+ 81, 80, 87,
+ 81, 87, 82,
+ 83, 82, 89,
+ 83, 89, 78,
+ 84, 90, 85,
+ 85, 91, 86,
+ 87, 86, 93,
+ 87, 93, 88,
+ 89, 88, 95,
+ 89, 95, 84,
+ 90, 96, 91,
+ 91, 97, 92,
+ 92, 98, 93,
+ 93, 99, 94,
+ 94, 100, 95,
+ 95, 101, 90,
+ 96, 102, 97,
+ 97, 103, 98,
+ 98, 104, 99,
+ 100, 99, 106,
+ 100, 106, 101,
+ 96, 101, 102,
+ 102, 108, 103,
+ 104, 103, 110,
+ 104, 110, 105,
+ 106, 105, 112,
+ 106, 112, 107,
+ 102, 107, 108,
+ 108, 114, 109,
+ 109, 115, 110,
+ 110, 116, 111,
+ 112, 111, 118,
+ 113, 112, 119,
+ 108, 113, 114,
+ 115, 114, 121,
+ 115, 121, 116,
+ 116, 122, 117,
+ 118, 117, 124,
+ 118, 124, 119,
+ 119, 125, 114,
+ 120, 126, 121,
+ 122, 121, 128,
+ 122, 128, 123,
+ 124, 123, 130,
+ 124, 130, 125,
+ 120, 125, 126,
+ 126, 132, 127,
+ 127, 133, 128,
+ 129, 128, 135,
+ 129, 135, 130,
+ 130, 136, 131,
+ 126, 131, 132,
+ 133, 132, 139,
+ 134, 133, 140,
+ 135, 134, 141,
+ 135, 141, 136,
+ 136, 142, 137,
+ 137, 143, 132,
+ 139, 138, 145,
+ 140, 139, 146,
+ 140, 146, 141,
+ 142, 141, 148,
+ 142, 148, 143,
+ 143, 149, 138,
+ 145, 144, 151,
+ 145, 151, 146,
+ 147, 146, 153,
+ 147, 153, 148,
+ 148, 154, 149,
+ 149, 155, 144,
+ 150, 156, 151,
+ 152, 151, 158,
+ 152, 158, 153,
+ 153, 159, 154,
+ 154, 160, 155,
+ 150, 155, 156,
+ 157, 156, 163,
+ 157, 163, 158,
+ 159, 158, 165,
+ 159, 165, 160,
+ 161, 160, 167,
+ 161, 167, 156,
+ 163, 162, 169,
+ 163, 169, 164,
+ 165, 164, 171,
+ 166, 165, 172,
+ 167, 166, 173,
+ 167, 173, 162,
+ 168, 174, 169,
+ 169, 175, 170,
+ 171, 170, 177,
+ 171, 177, 172,
+ 173, 172, 179,
+ 168, 173, 174,
+ 175, 174, 181,
+ 175, 181, 176,
+ 177, 176, 183,
+ 177, 183, 178,
+ 179, 178, 185,
+ 174, 179, 180,
+ 180, 186, 181,
+ 181, 187, 182,
+ 182, 188, 183,
+ 184, 183, 190,
+ 184, 190, 185,
+ 185, 191, 180,
+ 186, 0, 187,
+ 187, 1, 188,
+ 188, 2, 189,
+ 189, 3, 190,
+ 191, 190, 5,
+ 186, 191, 0,
+};
+
+GizmoGeomInfo wm_gizmo_geom_data_dial = {
+ .nverts = 192,
+ .ntris = 384,
+ .verts = verts,
+ .normals = normals,
+ .indices = indices,
+};
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
new file mode 100644
index 00000000000..9ef53d8f696
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -0,0 +1,121 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gizmo_draw_utils.c
+ * \ingroup edgizmolib
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "GPU_batch.h"
+#include "GPU_glew.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* only for own init/exit calls (wm_gizmotype_init/wm_gizmotype_free) */
+#include "wm.h"
+
+/* own includes */
+#include "gizmo_library_intern.h"
+
+/**
+ * Main draw call for GizmoGeomInfo data
+ */
+void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info, const bool UNUSED(select), const float color[4])
+{
+ /* TODO store the Batches inside the GizmoGeomInfo and updated it when geom changes
+ * So we don't need to re-created and discard it every time */
+
+ GPUVertBuf *vbo;
+ GPUIndexBuf *el;
+ GPUBatch *batch;
+ GPUIndexBufBuilder elb = {0};
+
+ GPUVertFormat format = {0};
+ uint pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ /* Elements */
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, info->ntris, info->nverts);
+ for (int i = 0; i < info->ntris; ++i) {
+ const unsigned short *idx = &info->indices[i * 3];
+ GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
+ }
+ el = GPU_indexbuf_build(&elb);
+
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, info->nverts);
+
+ GPU_vertbuf_attr_fill(vbo, pos_id, info->verts);
+
+ batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, el, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ /* We may want to re-visit this, for now disable
+ * since it causes issues leaving the GL state modified. */
+#if 0
+ glEnable(GL_CULL_FACE);
+ GPU_depth_test(true);
+#endif
+
+ GPU_batch_draw(batch);
+
+#if 0
+ GPU_depth_test(false);
+ glDisable(GL_CULL_FACE);
+#endif
+
+
+ GPU_batch_discard(batch);
+}
+
+void wm_gizmo_vec_draw(
+ const float color[4], const float (*verts)[3], uint vert_count,
+ uint pos, uint primitive_type)
+{
+ immUniformColor4fv(color);
+ immBegin(primitive_type, vert_count);
+ for (int i = 0; i < vert_count; i++) {
+ immVertex3fv(pos, verts[i]);
+ }
+ immEnd();
+}
diff --git a/source/blender/editors/gizmo_library/gizmo_geometry.h b/source/blender/editors/gizmo_library/gizmo_geometry.h
new file mode 100644
index 00000000000..53541b0aa01
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_geometry.h
@@ -0,0 +1,54 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file gizmo_geometry.h
+ * \ingroup edgizmolib
+ *
+ * \name Gizmo Geometry
+ *
+ * \brief Prototypes for arrays defining the gizmo geometry. The actual definitions can be found in files usually
+ * called geom_xxx_gizmo.c
+ */
+
+
+#ifndef __GIZMO_GEOMETRY_H__
+#define __GIZMO_GEOMETRY_H__
+
+typedef struct GizmoGeomInfo {
+ int nverts;
+ int ntris;
+ const float (*verts)[3];
+ const float (*normals)[3];
+ const unsigned short *indices;
+} GizmoGeomInfo;
+
+/* arrow gizmo */
+extern GizmoGeomInfo wm_gizmo_geom_data_arrow;
+
+/* cube gizmo */
+extern GizmoGeomInfo wm_gizmo_geom_data_cube;
+
+/* dial gizmo */
+extern GizmoGeomInfo wm_gizmo_geom_data_dial;
+
+#endif /* __GIZMO_GEOMETRY_H__ */
diff --git a/source/blender/editors/gizmo_library/gizmo_group_types/value2d_gizmo_group.c b/source/blender/editors/gizmo_library/gizmo_group_types/value2d_gizmo_group.c
new file mode 100644
index 00000000000..274d35269d1
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_group_types/value2d_gizmo_group.c
@@ -0,0 +1,176 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file value2d_gizmo_group.c
+ * \ingroup edgizmolib
+ *
+ * \name 2D Value Gizmo
+ *
+ * \brief Gizmo that edits a value for operator redo.
+ */
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "ED_undo.h"
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Value Gizmo
+ * \{ */
+
+struct ValueOpRedoGroup {
+ wmGizmo *gizmo;
+ struct {
+ const bContext *context; /* needed for redo. */
+ wmOperator *op;
+ } state;
+};
+
+static void gizmo_op_redo_exec(struct ValueOpRedoGroup *igzgroup)
+{
+ wmOperator *op = igzgroup->state.op;
+ if (op == WM_operator_last_redo((bContext *)igzgroup->state.context)) {
+ ED_undo_operator_repeat((bContext *)igzgroup->state.context, op);
+ }
+}
+
+/* translate callbacks */
+static void gizmo_value_operator_redo_value_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ float *value = value_p;
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ struct ValueOpRedoGroup *igzgroup = gz->parent_gzgroup->customdata;
+ wmOperator *op = igzgroup->state.op;
+ *value = RNA_property_float_get(op->ptr, op->type->prop);
+}
+
+static void gizmo_value_operator_redo_value_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ const float *value = value_p;
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ struct ValueOpRedoGroup *igzgroup = gz->parent_gzgroup->customdata;
+ wmOperator *op = igzgroup->state.op;
+ RNA_property_float_set(op->ptr, op->type->prop, *value);
+ gizmo_op_redo_exec(igzgroup);
+}
+
+static void WIDGETGROUP_value_operator_redo_modal_from_setup(
+ const bContext *C, wmGizmoGroup *gzgroup)
+{
+ /* Start off dragging. */
+ wmWindow *win = CTX_wm_window(C);
+ wmGizmo *gz = gzgroup->gizmos.first;
+ wmGizmoMap *gzmap = gzgroup->parent_gzmap;
+ WM_gizmo_modal_set_from_setup(
+ gzmap, (bContext *)C, gz, 0, win->eventstate);
+}
+
+static void WIDGETGROUP_value_operator_redo_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct ValueOpRedoGroup *igzgroup = MEM_mallocN(sizeof(struct ValueOpRedoGroup), __func__);
+
+ igzgroup->gizmo = WM_gizmo_new("GIZMO_GT_value_2d", gzgroup, NULL);
+ wmGizmo *gz = igzgroup->gizmo;
+
+ igzgroup->state.context = C;
+ igzgroup->state.op = WM_operator_last_redo(C);
+
+ gzgroup->customdata = igzgroup;
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+
+ WM_gizmo_target_property_def_func(
+ gz, "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_value_operator_redo_value_get,
+ .value_set_fn = gizmo_value_operator_redo_value_set,
+ .range_get_fn = NULL,
+ .user_data = igzgroup,
+ });
+
+ /* Become modal as soon as it's started. */
+ WIDGETGROUP_value_operator_redo_modal_from_setup(C, gzgroup);
+}
+
+static void WIDGETGROUP_value_operator_redo_refresh(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct ValueOpRedoGroup *igzgroup = gzgroup->customdata;
+ wmGizmo *gz = igzgroup->gizmo;
+ wmOperator *op = WM_operator_last_redo((bContext *)igzgroup->state.context);
+ wmGizmoMap *gzmap = gzgroup->parent_gzmap;
+
+ /* FIXME */
+ extern struct wmGizmo *wm_gizmomap_modal_get(struct wmGizmoMap *gzmap);
+ if ((op != igzgroup->state.op) ||
+ (wm_gizmomap_modal_get(gzmap) != gz))
+ {
+ WM_gizmo_group_type_unlink_delayed_ptr(gzgroup->type);
+ }
+}
+
+static void WM_GGT_value_operator_redo(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Value Operator Redo";
+ gzgt->idname = "WM_GGT_value_operator_redo";
+
+ /* FIXME, allow multiple. */
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_INIT;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+
+ gzgt->setup = WIDGETGROUP_value_operator_redo_setup;
+ gzgt->refresh = WIDGETGROUP_value_operator_redo_refresh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+void ED_gizmogrouptypes_value_2d(void)
+{
+ WM_gizmogrouptype_append(WM_GGT_value_operator_redo);
+}
+
+/** \} */
diff --git a/source/blender/editors/gizmo_library/gizmo_library_intern.h b/source/blender/editors/gizmo_library/gizmo_library_intern.h
new file mode 100644
index 00000000000..db88a52f087
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_library_intern.h
@@ -0,0 +1,111 @@
+/*
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gizmo_library_intern.h
+ * \ingroup edgizmolib
+ */
+
+#ifndef __GIZMO_LIBRARY_INTERN_H__
+#define __GIZMO_LIBRARY_INTERN_H__
+
+/* distance around which gizmos respond to input (and get highlighted) */
+#define GIZMO_HOTSPOT 14.0f
+
+/**
+ * Data for common interactions. Used in gizmo_library_utils.c functions.
+ */
+typedef struct GizmoCommonData {
+ int flag;
+
+ float range_fac; /* factor for arrow min/max distance */
+ float offset;
+
+ /* property range for constrained gizmos */
+ float range;
+ /* min/max value for constrained gizmos */
+ float min, max;
+} GizmoCommonData;
+
+typedef struct GizmoInteraction {
+ float init_value; /* initial property value */
+ float init_mval[2];
+ float init_offset;
+ float init_matrix_final[4][4];
+ float init_matrix_basis[4][4];
+
+ /* offset of last handling step */
+ float prev_offset;
+ /* Total offset added by precision tweaking.
+ * Needed to allow toggling precision on/off without causing jumps */
+ float precision_offset;
+} GizmoInteraction;
+
+/* GizmoCommonData->flag */
+enum {
+ GIZMO_CUSTOM_RANGE_SET = (1 << 0),
+};
+
+
+float gizmo_offset_from_value(
+ GizmoCommonData *data, const float value,
+ const bool constrained, const bool inverted);
+float gizmo_value_from_offset(
+ GizmoCommonData *data, GizmoInteraction *inter, const float offset,
+ const bool constrained, const bool inverted, const bool use_precision);
+
+void gizmo_property_data_update(
+ struct wmGizmo *gz, GizmoCommonData *data, wmGizmoProperty *gz_prop,
+ const bool constrained, const bool inverted);
+
+void gizmo_property_value_reset(
+ bContext *C, const struct wmGizmo *gz, GizmoInteraction *inter, wmGizmoProperty *gz_prop);
+
+
+/* -------------------------------------------------------------------- */
+
+void gizmo_color_get(
+ const struct wmGizmo *gz, const bool highlight,
+ float r_color[4]);
+
+bool gizmo_window_project_2d(
+ bContext *C, const struct wmGizmo *gz, const float mval[2], int axis, bool use_offset,
+ float r_co[2]);
+
+bool gizmo_window_project_3d(
+ bContext *C, const struct wmGizmo *gz, const float mval[2], bool use_offset,
+ float r_co[3]);
+
+/* -------------------------------------------------------------------- */
+/* Gizmo drawing */
+
+#include "gizmo_geometry.h"
+
+void wm_gizmo_geometryinfo_draw(const struct GizmoGeomInfo *info, const bool select, const float color[4]);
+void wm_gizmo_vec_draw(
+ const float color[4], const float (*verts)[3], uint vert_count,
+ uint pos, uint primitive_type);
+
+
+#endif /* __GIZMO_LIBRARY_INTERN_H__ */
diff --git a/source/blender/editors/gizmo_library/gizmo_library_presets.c b/source/blender/editors/gizmo_library/gizmo_library_presets.c
new file mode 100644
index 00000000000..4eeddb92664
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_library_presets.c
@@ -0,0 +1,150 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gizmo_library/gizmo_library_presets.c
+ * \ingroup edgizmolib
+ *
+ * \name Gizmo Lib Presets
+ *
+ * \brief Preset shapes that can be drawn from any gizmo type.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+
+#include "DEG_depsgraph.h"
+
+#include "RNA_access.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "ED_view3d.h"
+#include "ED_screen.h"
+
+/* own includes */
+#include "ED_gizmo_library.h" /* own include */
+#include "gizmo_library_intern.h" /* own include */
+
+/* TODO, this is to be used by RNA. might move to ED_gizmo_library */
+
+/**
+ * Given a single axis, orient the matrix to a different direction.
+ */
+static void single_axis_convert(
+ int src_axis, float src_mat[4][4],
+ int dst_axis, float dst_mat[4][4])
+{
+ copy_m4_m4(dst_mat, src_mat);
+ if (src_axis == dst_axis) {
+ return;
+ }
+
+ float rotmat[3][3];
+ mat3_from_axis_conversion_single(src_axis, dst_axis, rotmat);
+ transpose_m3(rotmat);
+ mul_m4_m4m3(dst_mat, src_mat, rotmat);
+}
+
+/**
+ * Use for all geometry.
+ */
+static void ed_gizmo_draw_preset_geometry(
+ const struct wmGizmo *gz, float mat[4][4], int select_id,
+ const GizmoGeomInfo *info)
+{
+ const bool is_select = (select_id != -1);
+ const bool is_highlight = is_select && (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
+
+ float color[4];
+ gizmo_color_get(gz, is_highlight, color);
+
+ if (is_select) {
+ GPU_select_load_id(select_id);
+ }
+
+ GPU_matrix_push();
+ GPU_matrix_mul(mat);
+ wm_gizmo_geometryinfo_draw(info, is_select, color);
+ GPU_matrix_pop();
+
+ if (is_select) {
+ GPU_select_load_id(-1);
+ }
+}
+
+void ED_gizmo_draw_preset_box(
+ const struct wmGizmo *gz, float mat[4][4], int select_id)
+{
+ ed_gizmo_draw_preset_geometry(gz, mat, select_id, &wm_gizmo_geom_data_cube);
+}
+
+void ED_gizmo_draw_preset_arrow(
+ const struct wmGizmo *gz, float mat[4][4], int axis, int select_id)
+{
+ float mat_rotate[4][4];
+ single_axis_convert(OB_POSZ, mat, axis, mat_rotate);
+ ed_gizmo_draw_preset_geometry(gz, mat_rotate, select_id, &wm_gizmo_geom_data_arrow);
+}
+
+void ED_gizmo_draw_preset_circle(
+ const struct wmGizmo *gz, float mat[4][4], int axis, int select_id)
+{
+ float mat_rotate[4][4];
+ single_axis_convert(OB_POSZ, mat, axis, mat_rotate);
+ ed_gizmo_draw_preset_geometry(gz, mat_rotate, select_id, &wm_gizmo_geom_data_dial);
+}
+
+void ED_gizmo_draw_preset_facemap(
+ const bContext *C, const struct wmGizmo *gz, Object *ob, const int facemap, int select_id)
+{
+ const bool is_select = (select_id != -1);
+ const bool is_highlight = is_select && (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
+
+ float color[4];
+ gizmo_color_get(gz, is_highlight, color);
+
+ if (is_select) {
+ GPU_select_load_id(select_id);
+ }
+
+ GPU_matrix_push();
+ GPU_matrix_mul(ob->obmat);
+ ED_draw_object_facemap(CTX_data_depsgraph(C), ob, color, facemap);
+ GPU_matrix_pop();
+
+ if (is_select) {
+ GPU_select_load_id(-1);
+ }
+}
diff --git a/source/blender/editors/gizmo_library/gizmo_library_utils.c b/source/blender/editors/gizmo_library/gizmo_library_utils.c
new file mode 100644
index 00000000000..25364652785
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_library_utils.c
@@ -0,0 +1,247 @@
+/*
+ * ***** 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) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gizmo_library_utils.c
+ * \ingroup edgizmolib
+ *
+ * \name Gizmo Library Utilities
+ *
+ * \brief This file contains functions for common behaviors of gizmos.
+ */
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_view3d.h"
+
+/* own includes */
+#include "gizmo_library_intern.h"
+
+/* factor for precision tweaking */
+#define GIZMO_PRECISION_FAC 0.05f
+
+
+BLI_INLINE float gizmo_offset_from_value_constr(
+ const float range_fac, const float min, const float range, const float value,
+ const bool inverted)
+{
+ return inverted ? (range_fac * (min + range - value) / range) : (range_fac * (value / range));
+}
+
+BLI_INLINE float gizmo_value_from_offset_constr(
+ const float range_fac, const float min, const float range, const float value,
+ const bool inverted)
+{
+ return inverted ? (min + range - (value * range / range_fac)) : (value * range / range_fac);
+}
+
+float gizmo_offset_from_value(
+ GizmoCommonData *data, const float value, const bool constrained, const bool inverted)
+{
+ if (constrained)
+ return gizmo_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
+
+ return value;
+}
+
+float gizmo_value_from_offset(
+ GizmoCommonData *data, GizmoInteraction *inter, const float offset,
+ const bool constrained, const bool inverted, const bool use_precision)
+{
+ const float max = data->min + data->range;
+
+ if (use_precision) {
+ /* add delta offset of this step to total precision_offset */
+ inter->precision_offset += offset - inter->prev_offset;
+ }
+ inter->prev_offset = offset;
+
+ float ofs_new = inter->init_offset + offset - inter->precision_offset * (1.0f - GIZMO_PRECISION_FAC);
+ float value;
+
+ if (constrained) {
+ value = gizmo_value_from_offset_constr(data->range_fac, data->min, data->range, ofs_new, inverted);
+ }
+ else {
+ value = ofs_new;
+ }
+
+ /* clamp to custom range */
+ if (data->flag & GIZMO_CUSTOM_RANGE_SET) {
+ CLAMP(value, data->min, max);
+ }
+
+ return value;
+}
+
+void gizmo_property_data_update(
+ wmGizmo *gz, GizmoCommonData *data, wmGizmoProperty *gz_prop,
+ const bool constrained, const bool inverted)
+{
+ if (gz_prop->custom_func.value_get_fn != NULL) {
+ /* pass */
+ }
+ else if (gz_prop->prop != NULL) {
+ /* pass */
+ }
+ else {
+ data->offset = 0.0f;
+ return;
+ }
+
+ float value = WM_gizmo_target_property_float_get(gz, gz_prop);
+
+ if (constrained) {
+ if ((data->flag & GIZMO_CUSTOM_RANGE_SET) == 0) {
+ float range[2];
+ if (WM_gizmo_target_property_float_range_get(gz, gz_prop, range)) {
+ data->range = range[1] - range[0];
+ data->min = range[0];
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ data->offset = gizmo_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
+ }
+ else {
+ data->offset = value;
+ }
+}
+
+void gizmo_property_value_reset(
+ bContext *C, const wmGizmo *gz, GizmoInteraction *inter,
+ wmGizmoProperty *gz_prop)
+{
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, inter->init_value);
+}
+
+/* -------------------------------------------------------------------- */
+
+void gizmo_color_get(
+ const wmGizmo *gz, const bool highlight,
+ float r_col[4])
+{
+ if (highlight && !(gz->flag & WM_GIZMO_DRAW_HOVER)) {
+ copy_v4_v4(r_col, gz->color_hi);
+ }
+ else {
+ copy_v4_v4(r_col, gz->color);
+ }
+}
+
+/* -------------------------------------------------------------------- */
+
+/**
+ * Takes mouse coordinates and returns them in relation to the gizmo.
+ * Both 2D & 3D supported, use so we can use 2D gizmos in the 3D view.
+ */
+bool gizmo_window_project_2d(
+ bContext *C, const struct wmGizmo *gz, const float mval[2], int axis, bool use_offset,
+ float r_co[2])
+{
+ float mat[4][4];
+ {
+ float mat_identity[4][4];
+ struct WM_GizmoMatrixParams params = {NULL};
+ if (use_offset == false) {
+ unit_m4(mat_identity);
+ params.matrix_offset = mat_identity;
+ }
+ WM_gizmo_calc_matrix_final_params(gz, &params, mat);
+ }
+
+ /* rotate mouse in relation to the center and relocate it */
+ if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
+ /* For 3d views, transform 2D mouse pos onto plane. */
+ ARegion *ar = CTX_wm_region(C);
+
+ float plane[4], co[3];
+ plane_from_point_normal_v3(plane, mat[3], mat[2]);
+ bool clip_ray = ((RegionView3D *)ar->regiondata)->is_persp;
+ if (ED_view3d_win_to_3d_on_plane(ar, plane, mval, clip_ray, co)) {
+ float imat[4][4];
+ invert_m4_m4(imat, mat);
+ mul_m4_v3(imat, co);
+ r_co[0] = co[(axis + 1) % 3];
+ r_co[1] = co[(axis + 2) % 3];
+ return true;
+ }
+ return false;
+ }
+ else {
+ float co[3] = {mval[0], mval[1], 0.0f};
+ float imat[4][4];
+ invert_m4_m4(imat, mat);
+ mul_m4_v3(imat, co);
+ copy_v2_v2(r_co, co);
+ return true;
+ }
+}
+
+bool gizmo_window_project_3d(
+ bContext *C, const struct wmGizmo *gz, const float mval[2], bool use_offset,
+ float r_co[3])
+{
+ float mat[4][4];
+ {
+ float mat_identity[4][4];
+ struct WM_GizmoMatrixParams params = {NULL};
+ if (use_offset == false) {
+ unit_m4(mat_identity);
+ params.matrix_offset = mat_identity;
+ }
+ WM_gizmo_calc_matrix_final_params(gz, &params, mat);
+ }
+
+ if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ /* Note: we might want a custom reference point passed in,
+ * instead of the gizmo center. */
+ ED_view3d_win_to_3d(v3d, ar, mat[3], mval, r_co);
+ invert_m4(mat);
+ mul_m4_v3(mat, r_co);
+ return true;
+ }
+ else {
+ float co[3] = {mval[0], mval[1], 0.0f};
+ float imat[4][4];
+ invert_m4_m4(imat, mat);
+ mul_m4_v3(imat, co);
+ copy_v2_v2(r_co, co);
+ return true;
+ }
+}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
new file mode 100644
index 00000000000..fb3583b7b27
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c
@@ -0,0 +1,225 @@
+/*
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file arrow2d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name 2D Arrow Gizmo
+ *
+ * \brief Simple arrow gizmo which is dragged into a certain direction.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+/* own includes */
+#include "WM_api.h"
+
+#include "../gizmo_library_intern.h"
+
+static void arrow2d_draw_geom(wmGizmo *gz, const float matrix[4][4], const float color[4])
+{
+ const float size = 0.11f;
+ const float size_breadth = size / 2.0f;
+ const float size_length = size * 1.7f;
+ /* Subtract the length so the arrow fits in the hotspot. */
+ const float arrow_length = RNA_float_get(gz->ptr, "length") - size_length;
+ const float arrow_angle = RNA_float_get(gz->ptr, "angle");
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix);
+ GPU_matrix_rotate_2d(RAD2DEGF(arrow_angle));
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4fv(color);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, 0.0f, 0.0f);
+ immVertex2f(pos, 0.0f, arrow_length);
+ immEnd();
+
+ immBegin(GPU_PRIM_TRIS, 3);
+ immVertex2f(pos, size_breadth, arrow_length);
+ immVertex2f(pos, -size_breadth, arrow_length);
+ immVertex2f(pos, 0.0f, arrow_length + size_length);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+}
+
+static void gizmo_arrow2d_draw(const bContext *UNUSED(C), wmGizmo *gz)
+{
+ float color[4];
+
+ float matrix_final[4][4];
+
+ gizmo_color_get(gz, gz->state & WM_GIZMO_STATE_HIGHLIGHT, color);
+
+ GPU_line_width(gz->line_width);
+
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ GPU_blend(true);
+ arrow2d_draw_geom(gz, matrix_final, color);
+ GPU_blend(false);
+
+ if (gz->interaction_data) {
+ GizmoInteraction *inter = gz->interaction_data;
+
+ GPU_blend(true);
+ arrow2d_draw_geom(gz, inter->init_matrix_final, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f});
+ GPU_blend(false);
+ }
+}
+
+static void gizmo_arrow2d_setup(wmGizmo *gz)
+{
+ gz->flag |= WM_GIZMO_DRAW_MODAL;
+}
+
+static int gizmo_arrow2d_invoke(
+ bContext *UNUSED(C), wmGizmo *gz, const wmEvent *UNUSED(event))
+{
+ GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__);
+
+ copy_m4_m4(inter->init_matrix_basis, gz->matrix_basis);
+ WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
+
+ gz->interaction_data = inter;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int gizmo_arrow2d_test_select(
+ bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
+{
+ const float mval_fl[2] = {UNPACK2(mval)};
+ const float arrow_length = RNA_float_get(gz->ptr, "length");
+ const float arrow_angle = RNA_float_get(gz->ptr, "angle");
+ const float line_len = arrow_length * gz->scale_final;
+ float mval_local[2];
+
+ copy_v2_v2(mval_local, mval_fl);
+ sub_v2_v2(mval_local, gz->matrix_basis[3]);
+
+ float line[2][2];
+ line[0][0] = line[0][1] = line[1][0] = 0.0f;
+ line[1][1] = line_len;
+
+ /* rotate only if needed */
+ if (arrow_angle != 0.0f) {
+ float rot_point[2];
+ copy_v2_v2(rot_point, line[1]);
+ rotate_v2_v2fl(line[1], rot_point, arrow_angle);
+ }
+
+ /* arrow line intersection check */
+ float isect_1[2], isect_2[2];
+ const int isect = isect_line_sphere_v2(
+ line[0], line[1], mval_local, GIZMO_HOTSPOT + gz->line_width * 0.5f,
+ isect_1, isect_2);
+
+ if (isect > 0) {
+ float line_ext[2][2]; /* extended line for segment check including hotspot */
+ copy_v2_v2(line_ext[0], line[0]);
+ line_ext[1][0] = line[1][0] + GIZMO_HOTSPOT * ((line[1][0] - line[0][0]) / line_len);
+ line_ext[1][1] = line[1][1] + GIZMO_HOTSPOT * ((line[1][1] - line[0][1]) / line_len);
+
+ const float lambda_1 = line_point_factor_v2(isect_1, line_ext[0], line_ext[1]);
+ if (isect == 1) {
+ if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f)) {
+ return 0;
+ }
+ }
+ else {
+ BLI_assert(isect == 2);
+ const float lambda_2 = line_point_factor_v2(isect_2, line_ext[0], line_ext[1]);
+ if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f) && IN_RANGE_INCL(lambda_2, 0.0f, 1.0f)) {
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name 2D Arrow Gizmo API
+ *
+ * \{ */
+
+static void GIZMO_GT_arrow_2d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_arrow_2d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_arrow2d_draw;
+ gzt->setup = gizmo_arrow2d_setup;
+ gzt->invoke = gizmo_arrow2d_invoke;
+ gzt->test_select = gizmo_arrow2d_test_select;
+
+ gzt->struct_size = sizeof(wmGizmo);
+
+ /* rna */
+ RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
+ RNA_def_float_rotation(
+ gzt->srna, "angle", 0, NULL, DEG2RADF(-360.0f), DEG2RADF(360.0f),
+ "Roll", "", DEG2RADF(-360.0f), DEG2RADF(360.0f));
+}
+
+void ED_gizmotypes_arrow_2d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_arrow_2d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
new file mode 100644
index 00000000000..4e41f95a063
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -0,0 +1,491 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file arrow3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Arrow Gizmo
+ *
+ * 3D Gizmo
+ *
+ * \brief Simple arrow gizmo which is dragged into a certain direction.
+ * The arrow head can have varying shapes, e.g. cone, box, etc.
+ *
+ * - `matrix[0]` is derived from Y and Z.
+ * - `matrix[1]` is 'up' for gizmo types that have an up.
+ * - `matrix[2]` is the arrow direction (for all arrowes).
+ */
+
+#include "BIF_gl.h"
+
+#include "BLI_math.h"
+
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+#include "GPU_state.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "ED_view3d.h"
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+/* to use custom arrows exported to geom_arrow_gizmo.c */
+//#define USE_GIZMO_CUSTOM_ARROWS
+
+typedef struct ArrowGizmo3D {
+ wmGizmo gizmo;
+ GizmoCommonData data;
+} ArrowGizmo3D;
+
+
+/* -------------------------------------------------------------------- */
+
+static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
+{
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+
+ copy_m4_m4(r_matrix, arrow->gizmo.matrix_basis);
+ madd_v3_v3fl(r_matrix[3], arrow->gizmo.matrix_basis[2], arrow->data.offset);
+}
+
+static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const float color[4])
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ bool unbind_shader = true;
+ const int draw_style = RNA_enum_get(arrow->gizmo.ptr, "draw_style");
+ const int draw_options = RNA_enum_get(arrow->gizmo.ptr, "draw_options");
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (draw_style == ED_GIZMO_ARROW_STYLE_CROSS) {
+ immUniformColor4fv(color);
+
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex3f(pos, -1.0f, 0.0f, 0.0f);
+ immVertex3f(pos, 1.0f, 0.0f, 0.0f);
+ immVertex3f(pos, 0.0f, -1.0f, 0.0f);
+ immVertex3f(pos, 0.0f, 1.0f, 0.0f);
+ immEnd();
+ }
+ else if (draw_style == ED_GIZMO_ARROW_STYLE_CONE) {
+ float aspect[2];
+ RNA_float_get_array(arrow->gizmo.ptr, "aspect", aspect);
+ const float unitx = aspect[0];
+ const float unity = aspect[1];
+ const float vec[4][3] = {
+ {-unitx, -unity, 0},
+ { unitx, -unity, 0},
+ { unitx, unity, 0},
+ {-unitx, unity, 0},
+ };
+
+ GPU_line_width(arrow->gizmo.line_width);
+ wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_LOOP);
+ }
+ else {
+#ifdef USE_GIZMO_CUSTOM_ARROWS
+ wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_arrow, select, color);
+#else
+ const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length");
+
+ const float vec[2][3] = {
+ {0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, arrow_length},
+ };
+
+ if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_STEM) {
+ GPU_line_width(arrow->gizmo.line_width);
+ wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_STRIP);
+ }
+ else {
+ immUniformColor4fv(color);
+ }
+
+ /* *** draw arrow head *** */
+
+ GPU_matrix_push();
+
+ if (draw_style == ED_GIZMO_ARROW_STYLE_BOX) {
+ const float size = 0.05f;
+
+ /* translate to line end with some extra offset so box starts exactly where line ends */
+ GPU_matrix_translate_3f(0.0f, 0.0f, arrow_length + size);
+ /* scale down to box size */
+ GPU_matrix_scale_3f(size, size, size);
+
+ /* draw cube */
+ immUnbindProgram();
+ unbind_shader = false;
+ wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_cube, select, color);
+ }
+ else {
+ BLI_assert(draw_style == ED_GIZMO_ARROW_STYLE_NORMAL);
+
+ const float len = 0.25f;
+ const float width = 0.06f;
+
+ /* translate to line end */
+ GPU_matrix_translate_3f(0.0f, 0.0f, arrow_length);
+
+ imm_draw_circle_fill_3d(pos, 0.0, 0.0, width, 8);
+ imm_draw_cylinder_fill_3d(pos, width, 0.0, len, 8, 1);
+ }
+
+ GPU_matrix_pop();
+#endif /* USE_GIZMO_CUSTOM_ARROWS */
+ }
+
+ if (unbind_shader) {
+ immUnbindProgram();
+ }
+}
+
+static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool highlight)
+{
+ wmGizmo *gz = &arrow->gizmo;
+ float color[4];
+ float matrix_final[4][4];
+
+ gizmo_color_get(gz, highlight, color);
+
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_final);
+ GPU_blend(true);
+ arrow_draw_geom(arrow, select, color);
+ GPU_blend(false);
+
+ GPU_matrix_pop();
+
+ if (gz->interaction_data) {
+ GizmoInteraction *inter = gz->interaction_data;
+
+ GPU_matrix_push();
+ GPU_matrix_mul(inter->init_matrix_final);
+
+
+ GPU_blend(true);
+ arrow_draw_geom(arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f});
+ GPU_blend(false);
+
+ GPU_matrix_pop();
+ }
+}
+
+static void gizmo_arrow_draw_select(
+ const bContext *UNUSED(C), wmGizmo *gz,
+ int select_id)
+{
+ GPU_select_load_id(select_id);
+ arrow_draw_intern((ArrowGizmo3D *)gz, true, false);
+}
+
+static void gizmo_arrow_draw(const bContext *UNUSED(C), wmGizmo *gz)
+{
+ arrow_draw_intern((ArrowGizmo3D *)gz, false, (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0);
+}
+
+/**
+ * Calculate arrow offset independent from prop min value,
+ * meaning the range will not be offset by min value first.
+ */
+static int gizmo_arrow_modal(
+ bContext *C, wmGizmo *gz, const wmEvent *event,
+ eWM_GizmoFlagTweak tweak_flag)
+{
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+ GizmoInteraction *inter = gz->interaction_data;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ float offset[3];
+ float facdir = 1.0f;
+
+ /* (src, dst) */
+ struct {
+ float mval[2];
+ float ray_origin[3], ray_direction[3];
+ float location[3];
+ } proj[2] = {
+ {.mval = {UNPACK2(inter->init_mval)}},
+ {.mval = {UNPACK2(event->mval)}},
+ };
+
+ float arrow_co[3];
+ float arrow_no[3];
+ copy_v3_v3(arrow_co, inter->init_matrix_basis[3]);
+ normalize_v3_v3(arrow_no, arrow->gizmo.matrix_basis[2]);
+
+ int ok = 0;
+
+ for (int j = 0; j < 2; j++) {
+ ED_view3d_win_to_ray(
+ ar, proj[j].mval,
+ proj[j].ray_origin, proj[j].ray_direction);
+ /* Force Y axis if we're view aligned */
+ if (j == 0) {
+ if (RAD2DEGF(acosf(dot_v3v3(proj[j].ray_direction, arrow->gizmo.matrix_basis[2]))) < 5.0f) {
+ normalize_v3_v3(arrow_no, rv3d->viewinv[1]);
+ }
+ }
+
+ float arrow_no_proj[3];
+ project_plane_v3_v3v3(arrow_no_proj, arrow_no, proj[j].ray_direction);
+
+ normalize_v3(arrow_no_proj);
+
+ float plane[4];
+ plane_from_point_normal_v3(plane, proj[j].ray_origin, arrow_no_proj);
+
+ float lambda;
+ if (isect_ray_plane_v3(arrow_co, arrow_no, plane, &lambda, false)) {
+ madd_v3_v3v3fl(proj[j].location, arrow_co, arrow_no, lambda);
+ ok++;
+ }
+ }
+
+ if (ok != 2) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ sub_v3_v3v3(offset, proj[1].location, proj[0].location);
+ facdir = dot_v3v3(arrow_no, offset) < 0.0f ? -1 : 1;
+
+ GizmoCommonData *data = &arrow->data;
+ const float ofs_new = facdir * len_v3(offset);
+
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+
+ /* set the property for the operator and call its modal function */
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ const int transform_flag = RNA_enum_get(arrow->gizmo.ptr, "transform");
+ const bool constrained = (transform_flag & ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED) != 0;
+ const bool inverted = (transform_flag & ED_GIZMO_ARROW_XFORM_FLAG_INVERTED) != 0;
+ const bool use_precision = (tweak_flag & WM_GIZMO_TWEAK_PRECISE) != 0;
+ float value = gizmo_value_from_offset(data, inter, ofs_new, constrained, inverted, use_precision);
+
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, value);
+ /* get clamped value */
+ value = WM_gizmo_target_property_float_get(gz, gz_prop);
+
+ data->offset = gizmo_offset_from_value(data, value, constrained, inverted);
+ }
+ else {
+ data->offset = ofs_new;
+ }
+
+ /* tag the region for redraw */
+ ED_region_tag_redraw(ar);
+ WM_event_add_mousemove(C);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_arrow_setup(wmGizmo *gz)
+{
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+
+ arrow->gizmo.flag |= WM_GIZMO_DRAW_MODAL;
+
+ arrow->data.range_fac = 1.0f;
+}
+
+static int gizmo_arrow_invoke(
+ bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
+{
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+ GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__);
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+
+ /* Some gizmos don't use properties. */
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ inter->init_value = WM_gizmo_target_property_float_get(gz, gz_prop);
+ }
+
+ inter->init_offset = arrow->data.offset;
+
+ inter->init_mval[0] = event->mval[0];
+ inter->init_mval[1] = event->mval[1];
+
+ gizmo_arrow_matrix_basis_get(gz, inter->init_matrix_basis);
+ WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
+
+ gz->interaction_data = inter;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_arrow_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
+{
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+ const int transform_flag = RNA_enum_get(arrow->gizmo.ptr, "transform");
+ const bool constrained = (transform_flag & ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED) != 0;
+ const bool inverted = (transform_flag & ED_GIZMO_ARROW_XFORM_FLAG_INVERTED) != 0;
+ gizmo_property_data_update(gz, &arrow->data, gz_prop, constrained, inverted);
+}
+
+static void gizmo_arrow_exit(bContext *C, wmGizmo *gz, const bool cancel)
+{
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+ GizmoCommonData *data = &arrow->data;
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ const bool is_prop_valid = WM_gizmo_target_property_is_valid(gz_prop);
+
+ if (!cancel) {
+ /* Assign incase applying the opetration needs an updated offset
+ * editmesh bisect needs this. */
+ if (is_prop_valid) {
+ data->offset = WM_gizmo_target_property_float_get(gz, gz_prop);
+ }
+ return;
+ }
+
+ GizmoInteraction *inter = gz->interaction_data;
+ if (is_prop_valid) {
+ gizmo_property_value_reset(C, gz, inter, gz_prop);
+ }
+ data->offset = inter->init_offset;
+}
+
+
+/* -------------------------------------------------------------------- */
+/** \name Arrow Gizmo API
+ *
+ * \{ */
+
+/**
+ * Define a custom property UI range
+ *
+ * \note Needs to be called before WM_gizmo_target_property_def_rna!
+ */
+void ED_gizmo_arrow3d_set_ui_range(wmGizmo *gz, const float min, const float max)
+{
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+
+ BLI_assert(min < max);
+ BLI_assert(!(WM_gizmo_target_property_is_valid(WM_gizmo_target_property_find(gz, "offset")) &&
+ "Make sure this function is called before WM_gizmo_target_property_def_rna"));
+
+ arrow->data.range = max - min;
+ arrow->data.min = min;
+ arrow->data.flag |= GIZMO_CUSTOM_RANGE_SET;
+}
+
+/**
+ * Define a custom factor for arrow min/max distance
+ *
+ * \note Needs to be called before WM_gizmo_target_property_def_rna!
+ */
+void ED_gizmo_arrow3d_set_range_fac(wmGizmo *gz, const float range_fac)
+{
+ ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
+ BLI_assert(!(WM_gizmo_target_property_is_valid(WM_gizmo_target_property_find(gz, "offset")) &&
+ "Make sure this function is called before WM_gizmo_target_property_def_rna"));
+
+ arrow->data.range_fac = range_fac;
+}
+
+static void GIZMO_GT_arrow_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_arrow_3d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_arrow_draw;
+ gzt->draw_select = gizmo_arrow_draw_select;
+ gzt->matrix_basis_get = gizmo_arrow_matrix_basis_get;
+ gzt->modal = gizmo_arrow_modal;
+ gzt->setup = gizmo_arrow_setup;
+ gzt->invoke = gizmo_arrow_invoke;
+ gzt->property_update = gizmo_arrow_property_update;
+ gzt->exit = gizmo_arrow_exit;
+
+ gzt->struct_size = sizeof(ArrowGizmo3D);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_style_items[] = {
+ {ED_GIZMO_ARROW_STYLE_NORMAL, "NORMAL", 0, "Normal", ""},
+ {ED_GIZMO_ARROW_STYLE_CROSS, "CROSS", 0, "Cross", ""},
+ {ED_GIZMO_ARROW_STYLE_BOX, "BOX", 0, "Box", ""},
+ {ED_GIZMO_ARROW_STYLE_CONE, "CONE", 0, "Cone", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_draw_options_items[] = {
+ {ED_GIZMO_ARROW_DRAW_FLAG_STEM, "STEM", 0, "Stem", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_transform_items[] = {
+ {ED_GIZMO_ARROW_XFORM_FLAG_INVERTED, "INVERT", 0, "Inverted", ""},
+ {ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED, "CONSTRAIN", 0, "Constrained", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ RNA_def_enum(
+ gzt->srna, "draw_style", rna_enum_draw_style_items,
+ ED_GIZMO_ARROW_STYLE_NORMAL,
+ "Draw Style", "");
+ RNA_def_enum_flag(
+ gzt->srna, "draw_options", rna_enum_draw_options_items,
+ ED_GIZMO_ARROW_DRAW_FLAG_STEM,
+ "Draw Options", "");
+ RNA_def_enum_flag(
+ gzt->srna, "transform", rna_enum_transform_items,
+ 0,
+ "Transform", "");
+
+ RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
+ RNA_def_float_vector(gzt->srna, "aspect", 2, NULL, 0, FLT_MAX, "Aspect", "Cone/box style only", 0.0f, FLT_MAX);
+
+ WM_gizmotype_target_property_def(gzt, "offset", PROP_FLOAT, 1);
+}
+
+void ED_gizmotypes_arrow_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_arrow_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/blank3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/blank3d_gizmo.c
new file mode 100644
index 00000000000..6bff72d75cd
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/blank3d_gizmo.c
@@ -0,0 +1,89 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blank3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Blank Gizmo
+ *
+ * \brief Gizmo to use as a fallback (catch events).
+ */
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "ED_view3d.h"
+#include "ED_gizmo_library.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+
+static void gizmo_blank_draw(const bContext *UNUSED(C), wmGizmo *UNUSED(gz))
+{
+ /* pass */
+}
+
+static int gizmo_blank_invoke(
+ bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event))
+{
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int gizmo_blank_test_select(
+ bContext *UNUSED(C), wmGizmo *UNUSED(gz), const int UNUSED(mval[2]))
+{
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Blank Gizmo API
+ *
+ * \{ */
+
+static void GIZMO_GT_blank_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_blank_3d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_blank_draw;
+ gzt->invoke = gizmo_blank_invoke;
+ gzt->test_select = gizmo_blank_test_select;
+
+ gzt->struct_size = sizeof(wmGizmo);
+}
+
+void ED_gizmotypes_blank_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_blank_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
new file mode 100644
index 00000000000..7b625364905
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -0,0 +1,332 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file button2d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Button Gizmo
+ *
+ * 2D Gizmo, also works in 3D views.
+ *
+ * \brief Single click button action for use in gizmo groups.
+ *
+ * \note Currently only basic icon & vector-shape buttons are supported.
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+#include "GPU_batch.h"
+#include "GPU_batch_utils.h"
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_gizmo_library.h"
+
+#include "UI_interface.h"
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+typedef struct ButtonGizmo2D {
+ wmGizmo gizmo;
+ bool is_init;
+ /* Use an icon or shape */
+ int icon;
+ GPUBatch *shape_batch[2];
+} ButtonGizmo2D;
+
+#define CIRCLE_RESOLUTION 32
+
+/* -------------------------------------------------------------------- */
+
+static void button2d_geom_draw_backdrop(
+ const wmGizmo *gz, const float color[4], const bool select)
+{
+ GPU_line_width(gz->line_width);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ immUniformColor4fv(color);
+
+ /* TODO, other draw styles */
+ imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
+
+ immUnbindProgram();
+
+ UNUSED_VARS(select);
+}
+
+static void button2d_draw_intern(
+ const bContext *C, wmGizmo *gz,
+ const bool select, const bool highlight)
+{
+ ButtonGizmo2D *button = (ButtonGizmo2D *)gz;
+
+ const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+ if (button->is_init == false) {
+ button->is_init = true;
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
+ if (RNA_property_is_set(gz->ptr, prop)) {
+ button->icon = RNA_property_enum_get(gz->ptr, prop);
+ }
+ else {
+ prop = RNA_struct_find_property(gz->ptr, "shape");
+ const uint polys_len = RNA_property_string_length(gz->ptr, prop);
+ /* We shouldn't need the +1, but a NULL char is set. */
+ char *polys = MEM_mallocN(polys_len + 1, __func__);
+ RNA_property_string_get(gz->ptr, prop, polys);
+ button->shape_batch[0] = GPU_batch_tris_from_poly_2d_encoded((uchar *)polys, polys_len, NULL);
+ button->shape_batch[1] = GPU_batch_wire_from_poly_2d_encoded((uchar *)polys, polys_len, NULL);
+ MEM_freeN(polys);
+ }
+ }
+
+ float color[4];
+ float matrix_final[4][4];
+
+ gizmo_color_get(gz, highlight, color);
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+
+ bool is_3d = (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) != 0;
+
+ if ((select == false) &&
+ (draw_options & ED_GIZMO_BUTTON_SHOW_HELPLINE))
+ {
+ float matrix_final_no_offset[4][4];
+ WM_gizmo_calc_matrix_final_no_offset(gz, matrix_final_no_offset);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+ GPU_line_width(gz->line_width);
+ immUniformColor4fv(color);
+ immBegin(GPU_PRIM_LINE_STRIP, 2);
+ immVertex3fv(pos, matrix_final[3]);
+ immVertex3fv(pos, matrix_final_no_offset[3]);
+ immEnd();
+ immUnbindProgram();
+ }
+
+ bool need_to_pop = true;
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_final);
+
+ if (is_3d) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ float matrix_align[4][4];
+ float matrix_final_unit[4][4];
+ normalize_m4_m4(matrix_final_unit, matrix_final);
+ mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit);
+ zero_v3(matrix_align[3]);
+ transpose_m4(matrix_align);
+ GPU_matrix_mul(matrix_align);
+ }
+
+ if (select) {
+ BLI_assert(is_3d);
+ button2d_geom_draw_backdrop(gz, color, select);
+ }
+ else {
+
+ GPU_blend(true);
+ if (button->shape_batch[0] != NULL) {
+ GPU_line_smooth(true);
+ GPU_polygon_smooth(false);
+ GPU_line_width(1.0f);
+ for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) {
+ /* Invert line color for wire. */
+ GPU_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4f(button->shape_batch[i], "color", UNPACK4(color));
+ GPU_batch_draw(button->shape_batch[i]);
+
+ if (draw_options & ED_GIZMO_BUTTON_SHOW_OUTLINE) {
+ color[0] = 1.0f - color[0];
+ color[1] = 1.0f - color[1];
+ color[2] = 1.0f - color[2];
+ }
+ }
+ GPU_line_smooth(false);
+ GPU_polygon_smooth(true);
+ }
+ else if (button->icon != ICON_NONE) {
+ if (draw_options & ED_GIZMO_BUTTON_SHOW_BACKDROP) {
+ button2d_geom_draw_backdrop(gz, color, select);
+ }
+
+ float pos[2];
+ if (is_3d) {
+ const float fac = 2.0f;
+ GPU_matrix_translate_2f(-(fac / 2), -(fac / 2));
+ GPU_matrix_scale_2f(fac / (ICON_DEFAULT_WIDTH * UI_DPI_FAC), fac / (ICON_DEFAULT_HEIGHT * UI_DPI_FAC));
+ pos[0] = 1.0f;
+ pos[1] = 1.0f;
+ }
+ else {
+ pos[0] = gz->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * UI_DPI_FAC;
+ pos[1] = gz->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * UI_DPI_FAC;
+ GPU_matrix_pop();
+ need_to_pop = false;
+ }
+
+ float alpha = (highlight) ? 1.0f : 0.8f;
+ GPU_polygon_smooth(false);
+ UI_icon_draw_alpha(pos[0], pos[1], button->icon, alpha);
+ GPU_polygon_smooth(true);
+ }
+ GPU_blend(false);
+ }
+
+ if (need_to_pop) {
+ GPU_matrix_pop();
+ }
+}
+
+static void gizmo_button2d_draw_select(const bContext *C, wmGizmo *gz, int select_id)
+{
+ GPU_select_load_id(select_id);
+ button2d_draw_intern(C, gz, true, false);
+}
+
+static void gizmo_button2d_draw(const bContext *C, wmGizmo *gz)
+{
+ const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
+
+ GPU_blend(true);
+ button2d_draw_intern(C, gz, false, is_highlight);
+ GPU_blend(false);
+}
+
+static int gizmo_button2d_test_select(
+ bContext *C, wmGizmo *gz, const int mval[2])
+{
+ float point_local[2];
+
+ if (0) {
+ /* correct, but unnecessarily slow. */
+ if (gizmo_window_project_2d(
+ C, gz, (const float[2]){UNPACK2(mval)}, 2, true, point_local) == false)
+ {
+ return -1;
+ }
+ }
+ else {
+ copy_v2_v2(point_local, (float[2]){UNPACK2(mval)});
+ sub_v2_v2(point_local, gz->matrix_basis[3]);
+ mul_v2_fl(point_local, 1.0f / (gz->scale_basis * UI_DPI_FAC));
+ }
+ /* The 'gz->scale_final' is already applied when projecting. */
+ if (len_squared_v2(point_local) < 1.0f) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static int gizmo_button2d_cursor_get(wmGizmo *gz)
+{
+ if (RNA_boolean_get(gz->ptr, "show_drag")) {
+ return BC_NSEW_SCROLLCURSOR;
+ }
+ return CURSOR_STD;
+}
+
+static void gizmo_button2d_free(wmGizmo *gz)
+{
+ ButtonGizmo2D *shape = (ButtonGizmo2D *)gz;
+
+ for (uint i = 0; i < ARRAY_SIZE(shape->shape_batch); i++) {
+ GPU_BATCH_DISCARD_SAFE(shape->shape_batch[i]);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Button Gizmo API
+ *
+ * \{ */
+
+static void GIZMO_GT_button_2d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_button_2d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_button2d_draw;
+ gzt->draw_select = gizmo_button2d_draw_select;
+ gzt->test_select = gizmo_button2d_test_select;
+ gzt->cursor_get = gizmo_button2d_cursor_get;
+ gzt->free = gizmo_button2d_free;
+
+ gzt->struct_size = sizeof(ButtonGizmo2D);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_options[] = {
+ {ED_GIZMO_BUTTON_SHOW_OUTLINE, "OUTLINE", 0, "Outline", ""},
+ {ED_GIZMO_BUTTON_SHOW_BACKDROP, "BACKDROP", 0, "Backdrop", ""},
+ {ED_GIZMO_BUTTON_SHOW_HELPLINE, "HELPLINE", 0, "Help Line", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ PropertyRNA *prop;
+
+ RNA_def_enum_flag(gzt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
+
+ prop = RNA_def_property(gzt->srna, "icon", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_icon_items);
+
+ /* Passed to 'GPU_batch_tris_from_poly_2d_encoded' */
+ RNA_def_property(gzt->srna, "shape", PROP_STRING, PROP_BYTESTRING);
+
+ /* Currently only used for cursor display. */
+ RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
+}
+
+void ED_gizmotypes_button_2d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_button_2d);
+}
+
+/** \} */ // Button Gizmo API
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
new file mode 100644
index 00000000000..04015ee9f1e
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -0,0 +1,1103 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file cage2d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Cage Gizmo
+ *
+ * 2D Gizmo
+ *
+ * \brief Rectangular gizmo acting as a 'cage' around its content.
+ * Interacting scales or translates the gizmo.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_dial_2d.h"
+#include "BLI_rect.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+
+#include "GPU_matrix.h"
+#include "GPU_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_select.h"
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_gizmo_library.h"
+
+/* own includes */
+#include "../gizmo_library_intern.h"
+
+#define GIZMO_RESIZER_SIZE 10.0f
+#define GIZMO_MARGIN_OFFSET_SCALE 1.5f
+
+static void gizmo_calc_rect_view_scale(
+ const wmGizmo *gz, const float dims[2], float scale[2])
+{
+ float matrix_final_no_offset[4][4];
+ float asp[2] = {1.0f, 1.0f};
+ if (dims[0] > dims[1]) {
+ asp[0] = dims[1] / dims[0];
+ }
+ else {
+ asp[1] = dims[0] / dims[1];
+ }
+ float x_axis[3], y_axis[3];
+ WM_gizmo_calc_matrix_final_no_offset(gz, matrix_final_no_offset);
+ mul_v3_mat3_m4v3(x_axis, matrix_final_no_offset, gz->matrix_offset[0]);
+ mul_v3_mat3_m4v3(y_axis, matrix_final_no_offset, gz->matrix_offset[1]);
+
+ mul_v2_v2(x_axis, asp);
+ mul_v2_v2(y_axis, asp);
+
+ scale[0] = 1.0f / len_v3(x_axis);
+ scale[1] = 1.0f / len_v3(y_axis);
+}
+
+static void gizmo_calc_rect_view_margin(
+ const wmGizmo *gz, const float dims[2], float margin[2])
+{
+ float handle_size;
+ if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
+ handle_size = 0.15f;
+ }
+ else {
+ handle_size = GIZMO_RESIZER_SIZE;
+ }
+ handle_size *= gz->scale_final;
+ float scale_xy[2];
+ gizmo_calc_rect_view_scale(gz, dims, scale_xy);
+ margin[0] = ((handle_size * scale_xy[0]));
+ margin[1] = ((handle_size * scale_xy[1]));
+}
+
+/* -------------------------------------------------------------------- */
+
+static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_constrain_axis[2])
+{
+ bool x = true, y = true;
+ switch (part) {
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X: { ARRAY_SET_ITEMS(r_pt, 0.5, 0.0); x = false; break; }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X: { ARRAY_SET_ITEMS(r_pt, -0.5, 0.0); x = false; break; }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y: { ARRAY_SET_ITEMS(r_pt, 0.0, 0.5); y = false; break; }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y: { ARRAY_SET_ITEMS(r_pt, 0.0, -0.5); y = false; break; }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y: { ARRAY_SET_ITEMS(r_pt, 0.5, 0.5); x = y = false; break; }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y: { ARRAY_SET_ITEMS(r_pt, 0.5, -0.5); x = y = false; break; }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y: { ARRAY_SET_ITEMS(r_pt, -0.5, 0.5); x = y = false; break; }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y: { ARRAY_SET_ITEMS(r_pt, -0.5, -0.5); x = y = false; break; }
+ default: BLI_assert(0);
+ }
+ r_constrain_axis[0] = x;
+ r_constrain_axis[1] = y;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Box Draw Style
+ *
+ * Useful for 3D views, see: #ED_GIZMO_CAGE2D_STYLE_BOX
+ * \{ */
+
+static void cage2d_draw_box_corners(
+ const rctf *r, const float margin[2], const float color[3])
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+
+ immBegin(GPU_PRIM_LINES, 16);
+
+ immVertex2f(pos, r->xmin, r->ymin + margin[1]);
+ immVertex2f(pos, r->xmin, r->ymin);
+ immVertex2f(pos, r->xmin, r->ymin);
+ immVertex2f(pos, r->xmin + margin[0], r->ymin);
+
+ immVertex2f(pos, r->xmax, r->ymin + margin[1]);
+ immVertex2f(pos, r->xmax, r->ymin);
+ immVertex2f(pos, r->xmax, r->ymin);
+ immVertex2f(pos, r->xmax - margin[0], r->ymin);
+
+ immVertex2f(pos, r->xmax, r->ymax - margin[1]);
+ immVertex2f(pos, r->xmax, r->ymax);
+ immVertex2f(pos, r->xmax, r->ymax);
+ immVertex2f(pos, r->xmax - margin[0], r->ymax);
+
+ immVertex2f(pos, r->xmin, r->ymax - margin[1]);
+ immVertex2f(pos, r->xmin, r->ymax);
+ immVertex2f(pos, r->xmin, r->ymax);
+ immVertex2f(pos, r->xmin + margin[0], r->ymax);
+
+ immEnd();
+
+ immUnbindProgram();
+}
+
+static void cage2d_draw_box_interaction(
+ const float color[4], const int highlighted,
+ const float size[2], const float margin[2],
+ const float line_width, const bool is_solid, const int draw_options)
+{
+ /* 4 verts for translate, otherwise only 3 are used. */
+ float verts[4][2];
+ uint verts_len = 0;
+ GPUPrimType prim_type = GPU_PRIM_NONE;
+
+ switch (highlighted) {
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
+ {
+ rctf r = {
+ .xmin = -size[0], .xmax = -size[0] + margin[0],
+ .ymin = -size[1] + margin[1], .ymax = size[1] - margin[1],
+ };
+ ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin);
+ ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymax);
+ verts_len = 2;
+ if (is_solid) {
+ ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax);
+ ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymin);
+ verts_len += 2;
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X:
+ {
+ rctf r = {
+ .xmin = size[0] - margin[0], .xmax = size[0],
+ .ymin = -size[1] + margin[1], .ymax = size[1] - margin[1],
+ };
+ ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymin);
+ ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax);
+ verts_len = 2;
+ if (is_solid) {
+ ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymax);
+ ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin);
+ verts_len += 2;
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
+ {
+ rctf r = {
+ .xmin = -size[0] + margin[0], .xmax = size[0] - margin[0],
+ .ymin = -size[1], .ymax = -size[1] + margin[1],
+ };
+ ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin);
+ ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymin);
+ verts_len = 2;
+ if (is_solid) {
+ ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax);
+ ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymax);
+ verts_len += 2;
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y:
+ {
+ rctf r = {
+ .xmin = -size[0] + margin[0], .xmax = size[0] - margin[0],
+ .ymin = size[1] - margin[1], .ymax = size[1],
+ };
+ ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymax);
+ ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax);
+ verts_len = 2;
+ if (is_solid) {
+ ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymin);
+ ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin);
+ verts_len += 2;
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y:
+ {
+ rctf r = {
+ .xmin = -size[0], .xmax = -size[0] + margin[0],
+ .ymin = -size[1], .ymax = -size[1] + margin[1],
+ };
+ ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymin);
+ ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax);
+ ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymax);
+ verts_len = 3;
+ if (is_solid) {
+ ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin);
+ verts_len += 1;
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y:
+ {
+ rctf r = {
+ .xmin = -size[0], .xmax = -size[0] + margin[0],
+ .ymin = size[1] - margin[1], .ymax = size[1],
+ };
+ ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymax);
+ ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymin);
+ ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymin);
+ verts_len = 3;
+ if (is_solid) {
+ ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymax);
+ verts_len += 1;
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y:
+ {
+ rctf r = {
+ .xmin = size[0] - margin[0], .xmax = size[0],
+ .ymin = -size[1], .ymax = -size[1] + margin[1],
+ };
+ ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin);
+ ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymax);
+ ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax);
+ verts_len = 3;
+ if (is_solid) {
+ ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymin);
+ verts_len += 1;
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y:
+ {
+ rctf r = {
+ .xmin = size[0] - margin[0], .xmax = size[0],
+ .ymin = size[1] - margin[1], .ymax = size[1],
+ };
+ ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymax);
+ ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymin);
+ ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymin);
+ verts_len = 3;
+ if (is_solid) {
+ ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymax);
+ verts_len += 1;
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+ case ED_GIZMO_CAGE2D_PART_ROTATE:
+ {
+ const float rotate_pt[2] = {0.0f, size[1] + margin[1]};
+ const rctf r_rotate = {
+ .xmin = rotate_pt[0] - margin[0] / 2.0f,
+ .xmax = rotate_pt[0] + margin[0] / 2.0f,
+ .ymin = rotate_pt[1] - margin[1] / 2.0f,
+ .ymax = rotate_pt[1] + margin[1] / 2.0f,
+ };
+
+ ARRAY_SET_ITEMS(verts[0], r_rotate.xmin, r_rotate.ymin);
+ ARRAY_SET_ITEMS(verts[1], r_rotate.xmin, r_rotate.ymax);
+ ARRAY_SET_ITEMS(verts[2], r_rotate.xmax, r_rotate.ymax);
+ ARRAY_SET_ITEMS(verts[3], r_rotate.xmax, r_rotate.ymin);
+ verts_len = 4;
+ if (is_solid) {
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ break;
+ }
+
+ case ED_GIZMO_CAGE2D_PART_TRANSLATE:
+ if (draw_options & ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) {
+ ARRAY_SET_ITEMS(verts[0], -margin[0] / 2, -margin[1] / 2);
+ ARRAY_SET_ITEMS(verts[1], margin[0] / 2, margin[1] / 2);
+ ARRAY_SET_ITEMS(verts[2], -margin[0] / 2, margin[1] / 2);
+ ARRAY_SET_ITEMS(verts[3], margin[0] / 2, -margin[1] / 2);
+ verts_len = 4;
+ if (is_solid) {
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ prim_type = GPU_PRIM_LINES;
+ }
+ }
+ else {
+ /* Only used for 3D view selection, never displayed to the user. */
+ ARRAY_SET_ITEMS(verts[0], -size[0], -size[1]);
+ ARRAY_SET_ITEMS(verts[1], -size[0], size[1]);
+ ARRAY_SET_ITEMS(verts[2], size[0], size[1]);
+ ARRAY_SET_ITEMS(verts[3], size[0], -size[1]);
+ verts_len = 4;
+ if (is_solid) {
+ prim_type = GPU_PRIM_TRI_FAN;
+ }
+ else {
+ /* unreachable */
+ BLI_assert(0);
+ prim_type = GPU_PRIM_LINE_STRIP;
+ }
+ }
+ break;
+ default:
+ return;
+ }
+
+ BLI_assert(prim_type != GPU_PRIM_NONE);
+
+ GPUVertFormat *format = immVertexFormat();
+ struct {
+ uint pos, col;
+ } attr_id = {
+ .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT),
+ .col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT),
+ };
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ {
+ if (is_solid) {
+ BLI_assert(ELEM(prim_type, GPU_PRIM_TRI_FAN));
+ immBegin(prim_type, verts_len);
+ immAttr3f(attr_id.col, 0.0f, 0.0f, 0.0f);
+ for (uint i = 0; i < verts_len; i++) {
+ immVertex2fv(attr_id.pos, verts[i]);
+ }
+ immEnd();
+ }
+ else {
+ BLI_assert(ELEM(prim_type, GPU_PRIM_LINE_STRIP, GPU_PRIM_LINES));
+ GPU_line_width(line_width + 3.0f);
+
+ immBegin(prim_type, verts_len);
+ immAttr3f(attr_id.col, 0.0f, 0.0f, 0.0f);
+ for (uint i = 0; i < verts_len; i++) {
+ immVertex2fv(attr_id.pos, verts[i]);
+ }
+ immEnd();
+
+ GPU_line_width(line_width);
+
+ immBegin(prim_type, verts_len);
+ immAttr3fv(attr_id.col, color);
+ for (uint i = 0; i < verts_len; i++) {
+ immVertex2fv(attr_id.pos, verts[i]);
+ }
+ immEnd();
+ }
+ }
+
+ immUnbindProgram();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Circle Draw Style
+ *
+ * Useful for 2D views, see: #ED_GIZMO_CAGE2D_STYLE_CIRCLE
+ * \{ */
+
+static void imm_draw_point_aspect_2d(
+ uint pos, float x, float y, float rad_x, float rad_y, bool solid)
+{
+ immBegin(solid ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, x - rad_x, y - rad_y);
+ immVertex2f(pos, x - rad_x, y + rad_y);
+ immVertex2f(pos, x + rad_x, y + rad_y);
+ immVertex2f(pos, x + rad_x, y - rad_y);
+ immEnd();
+}
+
+static void cage2d_draw_circle_wire(
+ const rctf *r, const float margin[2], const float color[3],
+ const int transform_flag, const int draw_options)
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, r->xmin, r->ymin);
+ immVertex2f(pos, r->xmax, r->ymin);
+ immVertex2f(pos, r->xmax, r->ymax);
+ immVertex2f(pos, r->xmin, r->ymax);
+ immEnd();
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE) {
+ immBegin(GPU_PRIM_LINE_LOOP, 2);
+ immVertex2f(pos, BLI_rctf_cent_x(r), r->ymax);
+ immVertex2f(pos, BLI_rctf_cent_x(r), r->ymax + margin[1]);
+ immEnd();
+ }
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
+ if (draw_options & ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) {
+ const float rad[2] = {margin[0] / 2, margin[1] / 2};
+ const float center[2] = {BLI_rctf_cent_x(r), BLI_rctf_cent_y(r)};
+
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, center[0] - rad[0], center[1] - rad[1]);
+ immVertex2f(pos, center[0] + rad[0], center[1] + rad[1]);
+ immVertex2f(pos, center[0] + rad[0], center[1] - rad[1]);
+ immVertex2f(pos, center[0] - rad[0], center[1] + rad[1]);
+ immEnd();
+ }
+ }
+
+ immUnbindProgram();
+}
+
+static void cage2d_draw_circle_handles(
+ const rctf *r, const float margin[2], const float color[3],
+ const int transform_flag,
+ bool solid)
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ void (*circle_fn)(uint, float, float, float, float, int) =
+ (solid) ? imm_draw_circle_fill_aspect_2d : imm_draw_circle_wire_aspect_2d;
+ const int resolu = 12;
+ const float rad[2] = {margin[0] / 3, margin[1] / 3};
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+
+ /* should really divide by two, but looks too bulky. */
+ {
+ imm_draw_point_aspect_2d(pos, r->xmin, r->ymin, rad[0], rad[1], solid);
+ imm_draw_point_aspect_2d(pos, r->xmax, r->ymin, rad[0], rad[1], solid);
+ imm_draw_point_aspect_2d(pos, r->xmax, r->ymax, rad[0], rad[1], solid);
+ imm_draw_point_aspect_2d(pos, r->xmin, r->ymax, rad[0], rad[1], solid);
+ }
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE) {
+ const float handle[2] = {BLI_rctf_cent_x(r), r->ymax + (margin[1] * GIZMO_MARGIN_OFFSET_SCALE)};
+ circle_fn(pos, handle[0], handle[1], rad[0], rad[1], resolu);
+ }
+
+ immUnbindProgram();
+}
+
+/** \} */
+
+static void gizmo_cage2d_draw_intern(
+ wmGizmo *gz, const bool select, const bool highlight, const int select_id)
+{
+ // const bool use_clamp = (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) == 0;
+ float dims[2];
+ RNA_float_get_array(gz->ptr, "dimensions", dims);
+ float matrix_final[4][4];
+
+ const int transform_flag = RNA_enum_get(gz->ptr, "transform");
+ const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
+ const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+
+ const float size_real[2] = {dims[0] / 2.0f, dims[1] / 2.0f};
+
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_final);
+
+ float margin[2];
+ gizmo_calc_rect_view_margin(gz, dims, margin);
+
+ /* Handy for quick testing draw (if it's outside bounds). */
+ if (false) {
+ GPU_blend(true);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv((const float[4]){1, 1, 1, 0.5f});
+ float s = 0.5f;
+ immRectf(pos, -s, -s, s, s);
+ immUnbindProgram();
+ GPU_blend(false);
+ }
+
+ if (select) {
+ /* expand for hotspot */
+ const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2};
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE) {
+ int scale_parts[] = {
+ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X,
+ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X,
+ ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y,
+ ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y,
+
+ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y,
+ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y,
+ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y,
+ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y,
+ };
+ for (int i = 0; i < ARRAY_SIZE(scale_parts); i++) {
+ GPU_select_load_id(select_id | scale_parts[i]);
+ cage2d_draw_box_interaction(
+ gz->color, scale_parts[i], size, margin, gz->line_width, true, draw_options);
+ }
+ }
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
+ const int transform_part = ED_GIZMO_CAGE2D_PART_TRANSLATE;
+ GPU_select_load_id(select_id | transform_part);
+ cage2d_draw_box_interaction(
+ gz->color, transform_part, size, margin, gz->line_width, true, draw_options);
+ }
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE) {
+ cage2d_draw_box_interaction(
+ gz->color, ED_GIZMO_CAGE2D_PART_ROTATE, size_real, margin, gz->line_width, true, draw_options);
+ }
+ }
+ else {
+ const rctf r = {
+ .xmin = -size_real[0],
+ .ymin = -size_real[1],
+ .xmax = size_real[0],
+ .ymax = size_real[1],
+ };
+ if (draw_style == ED_GIZMO_CAGE2D_STYLE_BOX) {
+ /* corner gizmos */
+ GPU_line_width(gz->line_width + 3.0f);
+ cage2d_draw_box_corners(&r, margin, (const float[3]){0, 0, 0});
+
+ /* corner gizmos */
+ float color[4];
+ gizmo_color_get(gz, highlight, color);
+ GPU_line_width(gz->line_width);
+ cage2d_draw_box_corners(&r, margin, color);
+
+ bool show = false;
+ if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_TRANSLATE) {
+ /* Only show if we're drawing the center handle
+ * otherwise the entire rectangle is the hotspot. */
+ if (draw_options & ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) {
+ show = true;
+ }
+ }
+ else {
+ show = true;
+ }
+
+ if (show) {
+ cage2d_draw_box_interaction(
+ gz->color, gz->highlight_part, size_real, margin, gz->line_width, false, draw_options);
+ }
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE) {
+ cage2d_draw_box_interaction(
+ gz->color, ED_GIZMO_CAGE2D_PART_ROTATE, size_real, margin, gz->line_width, false, draw_options);
+ }
+ }
+ else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
+ float color[4];
+ gizmo_color_get(gz, highlight, color);
+
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ GPU_line_width(gz->line_width + 3.0f);
+ cage2d_draw_circle_wire(&r, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options);
+ GPU_line_width(gz->line_width);
+ cage2d_draw_circle_wire(&r, margin, color, transform_flag, draw_options);
+
+
+ /* corner gizmos */
+ cage2d_draw_circle_handles(&r, margin, color, transform_flag, true);
+ cage2d_draw_circle_handles(&r, margin, (const float[3]){0, 0, 0}, transform_flag, false);
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ GPU_line_width(1.0);
+ GPU_matrix_pop();
+}
+
+/**
+ * For when we want to draw 2d cage in 3d views.
+ */
+static void gizmo_cage2d_draw_select(const bContext *UNUSED(C), wmGizmo *gz, int select_id)
+{
+ gizmo_cage2d_draw_intern(gz, true, false, select_id);
+}
+
+static void gizmo_cage2d_draw(const bContext *UNUSED(C), wmGizmo *gz)
+{
+ const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
+ gizmo_cage2d_draw_intern(gz, false, is_highlight, -1);
+}
+
+static int gizmo_cage2d_get_cursor(wmGizmo *gz)
+{
+ int highlight_part = gz->highlight_part;
+
+ if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
+ return BC_NSEW_SCROLLCURSOR;
+ }
+
+ switch (highlight_part) {
+ case ED_GIZMO_CAGE2D_PART_TRANSLATE:
+ return BC_NSEW_SCROLLCURSOR;
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X:
+ return CURSOR_X_MOVE;
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y:
+ return CURSOR_Y_MOVE;
+
+ /* TODO diagonal cursor */
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y:
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y:
+ return BC_NSEW_SCROLLCURSOR;
+ case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y:
+ case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y:
+ return BC_NSEW_SCROLLCURSOR;
+ case ED_GIZMO_CAGE2D_PART_ROTATE:
+ return BC_CROSSCURSOR;
+ default:
+ return CURSOR_STD;
+ }
+}
+
+static int gizmo_cage2d_test_select(
+ bContext *C, wmGizmo *gz, const int mval[2])
+{
+ float point_local[2];
+ float dims[2];
+ RNA_float_get_array(gz->ptr, "dimensions", dims);
+ const float size_real[2] = {dims[0] / 2.0f, dims[1] / 2.0f};
+
+ if (gizmo_window_project_2d(
+ C, gz, (const float[2]){UNPACK2(mval)}, 2, true, point_local) == false)
+ {
+ return -1;
+ }
+
+ float margin[2];
+ gizmo_calc_rect_view_margin(gz, dims, margin);
+ /* expand for hotspot */
+ const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2};
+
+ const int transform_flag = RNA_enum_get(gz->ptr, "transform");
+ const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
+ rctf r;
+ if (draw_options & ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) {
+ r.xmin = -margin[0] / 2;
+ r.ymin = -margin[1] / 2;
+ r.xmax = margin[0] / 2;
+ r.ymax = margin[1] / 2;
+ }
+ else {
+ r.xmin = -size[0] + margin[0];
+ r.ymin = -size[1] + margin[1];
+ r.xmax = size[0] - margin[0];
+ r.ymax = size[1] - margin[1];
+ };
+ bool isect = BLI_rctf_isect_pt_v(&r, point_local);
+ if (isect) {
+ return ED_GIZMO_CAGE2D_PART_TRANSLATE;
+ }
+ }
+
+ /* if gizmo does not have a scale intersection, don't do it */
+ if (transform_flag & (ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM)) {
+ const rctf r_xmin = {.xmin = -size[0], .ymin = -size[1], .xmax = -size[0] + margin[0], .ymax = size[1]};
+ const rctf r_xmax = {.xmin = size[0] - margin[0], .ymin = -size[1], .xmax = size[0], .ymax = size[1]};
+ const rctf r_ymin = {.xmin = -size[0], .ymin = -size[1], .xmax = size[0], .ymax = -size[1] + margin[1]};
+ const rctf r_ymax = {.xmin = -size[0], .ymin = size[1] - margin[1], .xmax = size[0], .ymax = size[1]};
+
+ if (BLI_rctf_isect_pt_v(&r_xmin, point_local)) {
+ if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) {
+ return ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y;
+ }
+ if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) {
+ return ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y;
+ }
+ return ED_GIZMO_CAGE2D_PART_SCALE_MIN_X;
+ }
+ if (BLI_rctf_isect_pt_v(&r_xmax, point_local)) {
+ if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) {
+ return ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y;
+ }
+ if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) {
+ return ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y;
+ }
+ return ED_GIZMO_CAGE2D_PART_SCALE_MAX_X;
+ }
+ if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) {
+ return ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y;
+ }
+ if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) {
+ return ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y;
+ }
+ }
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE) {
+ /* Rotate:
+ * (*) <-- hot spot is here!
+ * +---+
+ * | |
+ * +---+ */
+ const float r_rotate_pt[2] = {0.0f, size_real[1] + (margin[1] * GIZMO_MARGIN_OFFSET_SCALE)};
+ const rctf r_rotate = {
+ .xmin = r_rotate_pt[0] - margin[0] / 2.0f,
+ .xmax = r_rotate_pt[0] + margin[0] / 2.0f,
+ .ymin = r_rotate_pt[1] - margin[1] / 2.0f,
+ .ymax = r_rotate_pt[1] + margin[1] / 2.0f,
+ };
+
+ if (BLI_rctf_isect_pt_v(&r_rotate, point_local)) {
+ return ED_GIZMO_CAGE2D_PART_ROTATE;
+ }
+ }
+
+ return -1;
+}
+
+typedef struct RectTransformInteraction {
+ float orig_mouse[2];
+ float orig_matrix_offset[4][4];
+ float orig_matrix_final_no_offset[4][4];
+ Dial *dial;
+} RectTransformInteraction;
+
+static void gizmo_cage2d_setup(wmGizmo *gz)
+{
+ gz->flag |= WM_GIZMO_DRAW_MODAL | WM_GIZMO_DRAW_NO_SCALE;
+}
+
+static int gizmo_cage2d_invoke(
+ bContext *C, wmGizmo *gz, const wmEvent *event)
+{
+ RectTransformInteraction *data = MEM_callocN(sizeof(RectTransformInteraction), "cage_interaction");
+
+ copy_m4_m4(data->orig_matrix_offset, gz->matrix_offset);
+ WM_gizmo_calc_matrix_final_no_offset(gz, data->orig_matrix_final_no_offset);
+
+ if (gizmo_window_project_2d(
+ C, gz, (const float[2]){UNPACK2(event->mval)}, 2, false, data->orig_mouse) == 0)
+ {
+ zero_v2(data->orig_mouse);
+ }
+
+ gz->interaction_data = data;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int gizmo_cage2d_modal(
+ bContext *C, wmGizmo *gz, const wmEvent *event,
+ eWM_GizmoFlagTweak UNUSED(tweak_flag))
+{
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ /* For transform logic to be manageable we operate in -0.5..0.5 2D space,
+ * no matter the size of the rectangle, mouse coorts are scaled to unit space.
+ * The mouse coords have been projected into the matrix so we don't need to worry about axis alignment.
+ *
+ * - The cursor offset are multiplied by 'dims'.
+ * - Matrix translation is also multiplied by 'dims'.
+ */
+ RectTransformInteraction *data = gz->interaction_data;
+ float point_local[2];
+
+ float dims[2];
+ RNA_float_get_array(gz->ptr, "dimensions", dims);
+
+ {
+ float matrix_back[4][4];
+ copy_m4_m4(matrix_back, gz->matrix_offset);
+ copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
+
+ bool ok = gizmo_window_project_2d(
+ C, gz, (const float[2]){UNPACK2(event->mval)}, 2, false, point_local);
+ copy_m4_m4(gz->matrix_offset, matrix_back);
+ if (!ok) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ const int transform_flag = RNA_enum_get(gz->ptr, "transform");
+ wmGizmoProperty *gz_prop;
+
+ gz_prop = WM_gizmo_target_property_find(gz, "matrix");
+ if (gz_prop->type != NULL) {
+ WM_gizmo_target_property_float_get_array(gz, gz_prop, &gz->matrix_offset[0][0]);
+ }
+
+ if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_TRANSLATE) {
+ /* do this to prevent clamping from changing size */
+ copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
+ gz->matrix_offset[3][0] = data->orig_matrix_offset[3][0] + (point_local[0] - data->orig_mouse[0]);
+ gz->matrix_offset[3][1] = data->orig_matrix_offset[3][1] + (point_local[1] - data->orig_mouse[1]);
+ }
+ else if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_ROTATE) {
+
+#define MUL_V2_V3_M4_FINAL(test_co, mouse_co) \
+ mul_v3_m4v3(test_co, data->orig_matrix_final_no_offset, ((const float[3]){UNPACK2(mouse_co), 0.0}))
+
+ float test_co[3];
+
+ if (data->dial == NULL) {
+ MUL_V2_V3_M4_FINAL(test_co, data->orig_matrix_offset[3]);
+
+ data->dial = BLI_dial_initialize(test_co, FLT_EPSILON);
+
+ MUL_V2_V3_M4_FINAL(test_co, data->orig_mouse);
+ BLI_dial_angle(data->dial, test_co);
+ }
+
+ /* rotate */
+ MUL_V2_V3_M4_FINAL(test_co, point_local);
+ const float angle = BLI_dial_angle(data->dial, test_co);
+
+ float matrix_space_inv[4][4];
+ float matrix_rotate[4][4];
+ float pivot[3];
+
+ copy_v3_v3(pivot, data->orig_matrix_offset[3]);
+
+ invert_m4_m4(matrix_space_inv, gz->matrix_space);
+
+ unit_m4(matrix_rotate);
+ mul_m4_m4m4(matrix_rotate, matrix_rotate, matrix_space_inv);
+ rotate_m4(matrix_rotate, 'Z', -angle);
+ mul_m4_m4m4(matrix_rotate, matrix_rotate, gz->matrix_space);
+
+ zero_v3(matrix_rotate[3]);
+ transform_pivot_set_m4(matrix_rotate, pivot);
+
+ mul_m4_m4m4(gz->matrix_offset, matrix_rotate, data->orig_matrix_offset);
+
+#undef MUL_V2_V3_M4_FINAL
+ }
+ else {
+ /* scale */
+ copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
+ float pivot[2];
+ bool constrain_axis[2] = {false};
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
+ gizmo_rect_pivot_from_scale_part(gz->highlight_part, pivot, constrain_axis);
+ }
+ else {
+ zero_v2(pivot);
+ }
+
+ /* Cursor deltas scaled to (-0.5..0.5). */
+ float delta_orig[2], delta_curr[2];
+ for (int i = 0; i < 2; i++) {
+ delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i];
+ delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i];
+ }
+
+ float scale[2] = {1.0f, 1.0f};
+ for (int i = 0; i < 2; i++) {
+ if (constrain_axis[i] == false) {
+ if (delta_orig[i] < 0.0f) {
+ delta_orig[i] *= -1.0f;
+ delta_curr[i] *= -1.0f;
+ }
+ const int sign = signum_i(scale[i]);
+
+ scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i]));
+
+ if ((transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_SIGNED) == 0) {
+ if (sign != signum_i(scale[i])) {
+ scale[i] = 0.0f;
+ }
+ }
+ }
+ }
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM) {
+ if (constrain_axis[0] == false && constrain_axis[1] == false) {
+ scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f;
+ }
+ else if (constrain_axis[0] == false) {
+ scale[1] = scale[0];
+ }
+ else if (constrain_axis[1] == false) {
+ scale[0] = scale[1];
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ /* scale around pivot */
+ float matrix_scale[4][4];
+ unit_m4(matrix_scale);
+
+ mul_v3_fl(matrix_scale[0], scale[0]);
+ mul_v3_fl(matrix_scale[1], scale[1]);
+
+ transform_pivot_set_m4(matrix_scale, (const float[3]){pivot[0] * dims[0], pivot[1] * dims[1], 0.0f});
+ mul_m4_m4m4(gz->matrix_offset, data->orig_matrix_offset, matrix_scale);
+ }
+
+ if (gz_prop->type != NULL) {
+ WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &gz->matrix_offset[0][0]);
+ }
+
+ /* tag the region for redraw */
+ ED_region_tag_redraw(CTX_wm_region(C));
+ WM_event_add_mousemove(C);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_cage2d_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
+{
+ if (STREQ(gz_prop->type->idname, "matrix")) {
+ if (WM_gizmo_target_property_array_length(gz, gz_prop) == 16) {
+ WM_gizmo_target_property_float_get_array(gz, gz_prop, &gz->matrix_offset[0][0]);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+}
+
+static void gizmo_cage2d_exit(bContext *C, wmGizmo *gz, const bool cancel)
+{
+ RectTransformInteraction *data = gz->interaction_data;
+
+ MEM_SAFE_FREE(data->dial);
+
+ if (!cancel)
+ return;
+
+ wmGizmoProperty *gz_prop;
+
+ /* reset properties */
+ gz_prop = WM_gizmo_target_property_find(gz, "matrix");
+ if (gz_prop->type != NULL) {
+ WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &data->orig_matrix_offset[0][0]);
+ }
+
+ copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
+}
+
+
+/* -------------------------------------------------------------------- */
+/** \name Cage Gizmo API
+ *
+ * \{ */
+
+static void GIZMO_GT_cage_2d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_cage_2d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_cage2d_draw;
+ gzt->draw_select = gizmo_cage2d_draw_select;
+ gzt->test_select = gizmo_cage2d_test_select;
+ gzt->setup = gizmo_cage2d_setup;
+ gzt->invoke = gizmo_cage2d_invoke;
+ gzt->property_update = gizmo_cage2d_property_update;
+ gzt->modal = gizmo_cage2d_modal;
+ gzt->exit = gizmo_cage2d_exit;
+ gzt->cursor_get = gizmo_cage2d_get_cursor;
+
+ gzt->struct_size = sizeof(wmGizmo);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_style[] = {
+ {ED_GIZMO_CAGE2D_STYLE_BOX, "BOX", 0, "Box", ""},
+ {ED_GIZMO_CAGE2D_STYLE_CIRCLE, "CIRCLE", 0, "Circle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_transform[] = {
+ {ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE, "TRANSLATE", 0, "Move", ""},
+ {ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE, "ROTATE", 0, "Rotate", ""},
+ {ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE, "SCALE", 0, "Scale", ""},
+ {ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM, "SCALE_UNIFORM", 0, "Scale Uniform", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_draw_options[] = {
+ {ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "XFORM_CENTER_HANDLE", 0, "Center Handle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static float unit_v2[2] = {1.0f, 1.0f};
+ RNA_def_float_vector(gzt->srna, "dimensions", 2, unit_v2, 0, FLT_MAX, "Dimensions", "", 0.0f, FLT_MAX);
+ RNA_def_enum_flag(gzt->srna, "transform", rna_enum_transform, 0, "Transform Options", "");
+ RNA_def_enum(gzt->srna, "draw_style", rna_enum_draw_style, ED_GIZMO_CAGE2D_STYLE_CIRCLE, "Draw Style", "");
+ RNA_def_enum_flag(
+ gzt->srna, "draw_options", rna_enum_draw_options,
+ ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "Draw Options", "");
+
+ WM_gizmotype_target_property_def(gzt, "matrix", PROP_FLOAT, 16);
+}
+
+void ED_gizmotypes_cage_2d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_cage_2d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
new file mode 100644
index 00000000000..3bbe13362d0
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -0,0 +1,695 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file cage3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Cage Gizmo
+ *
+ * 2D Gizmo
+ *
+ * \brief Rectangular gizmo acting as a 'cage' around its content.
+ * Interacting scales or translates the gizmo.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+
+#include "GPU_matrix.h"
+#include "GPU_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_select.h"
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_gizmo_library.h"
+
+/* own includes */
+#include "../gizmo_library_intern.h"
+
+#define GIZMO_RESIZER_SIZE 10.0f
+#define GIZMO_MARGIN_OFFSET_SCALE 1.5f
+
+static void gizmo_calc_matrix_final_no_offset(
+ const wmGizmo *gz, float orig_matrix_final_no_offset[4][4], bool use_space)
+{
+ float mat_identity[4][4];
+ struct WM_GizmoMatrixParams params = {NULL};
+ unit_m4(mat_identity);
+ if (use_space == false) {
+ params.matrix_basis = mat_identity;
+ }
+ params.matrix_offset = mat_identity;
+ WM_gizmo_calc_matrix_final_params(gz, &params, orig_matrix_final_no_offset);
+}
+
+static void gizmo_calc_rect_view_scale(
+ const wmGizmo *gz, const float dims[3], float scale[3])
+{
+ UNUSED_VARS(dims);
+
+ /* Unlike cage2d, no need to correct for aspect. */
+ float matrix_final_no_offset[4][4];
+
+ float x_axis[3], y_axis[3], z_axis[3];
+ gizmo_calc_matrix_final_no_offset(gz, matrix_final_no_offset, false);
+ mul_v3_mat3_m4v3(x_axis, matrix_final_no_offset, gz->matrix_offset[0]);
+ mul_v3_mat3_m4v3(y_axis, matrix_final_no_offset, gz->matrix_offset[1]);
+ mul_v3_mat3_m4v3(z_axis, matrix_final_no_offset, gz->matrix_offset[2]);
+
+ scale[0] = 1.0f / len_v3(x_axis);
+ scale[1] = 1.0f / len_v3(y_axis);
+ scale[2] = 1.0f / len_v3(z_axis);
+}
+
+static void gizmo_calc_rect_view_margin(
+ const wmGizmo *gz, const float dims[3], float margin[3])
+{
+ float handle_size;
+ if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
+ handle_size = 0.15f;
+ }
+ else {
+ handle_size = GIZMO_RESIZER_SIZE;
+ }
+ // XXX, the scale isn't taking offset into account, we need to calculate scale per handle!
+ // handle_size *= gz->scale_final;
+
+ float scale_xyz[3];
+ gizmo_calc_rect_view_scale(gz, dims, scale_xyz);
+ margin[0] = ((handle_size * scale_xyz[0]));
+ margin[1] = ((handle_size * scale_xyz[1]));
+ margin[2] = ((handle_size * scale_xyz[2]));
+}
+
+/* -------------------------------------------------------------------- */
+
+static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[3], bool r_constrain_axis[3])
+{
+ if (part >= ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z &&
+ part <= ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z)
+ {
+ int index = (part - ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z);
+ int range[3];
+ range[2] = index % 3;
+ index = index / 3;
+ range[1] = index % 3;
+ index = index / 3;
+ range[0] = index % 3;
+
+ const float sign[3] = {0.5f, 0.0f, -0.5f};
+ for (int i = 0; i < 3; i++) {
+ r_pt[i] = sign[range[i]];
+ r_constrain_axis[i] = (range[i] == 1);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Box Draw Style
+ *
+ * Useful for 3D views, see: #ED_GIZMO_CAGE2D_STYLE_BOX
+ * \{ */
+
+static void cage3d_draw_box_corners(
+ const float r[3], const float margin[3], const float color[3])
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ UNUSED_VARS(margin);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+
+ imm_draw_cube_wire_3d(pos, (float[3]){0}, r);
+
+ immUnbindProgram();
+}
+
+static void cage3d_draw_box_interaction(
+ const float color[4], const int highlighted,
+ const float size[3], const float margin[3])
+{
+ if (highlighted >= ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z &&
+ highlighted <= ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z)
+ {
+ int index = (highlighted - ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z);
+ int range[3];
+ range[2] = index % 3;
+ index = index / 3;
+ range[1] = index % 3;
+ index = index / 3;
+ range[0] = index % 3;
+
+ const float sign[3] = {-1.0f, 0.0f, 1.0f};
+ float co[3];
+
+ for (int i = 0; i < 3; i++) {
+ co[i] = size[i] * sign[range[i]];
+ }
+ const float rad[3] = {margin[0] / 3, margin[1] / 3, margin[2] / 3};
+
+ {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+ imm_draw_cube_fill_3d(pos, co, rad);
+ immUnbindProgram();
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Circle Draw Style
+ *
+ * Useful for 2D views, see: #ED_GIZMO_CAGE2D_STYLE_CIRCLE
+ * \{ */
+
+static void imm_draw_point_aspect_3d(
+ uint pos, const float co[3], const float rad[3], bool solid)
+{
+ if (solid) {
+ imm_draw_cube_fill_3d(pos, co, rad);
+ }
+ else {
+ imm_draw_cube_wire_3d(pos, co, rad);
+ }
+}
+
+static void cage3d_draw_circle_wire(
+ const float r[3], const float margin[3], const float color[3],
+ const int transform_flag, const int draw_options)
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+
+ imm_draw_cube_wire_3d(pos, (float[3]){0}, r);
+
+#if 0
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
+ if (draw_options & ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) {
+ const float rad[2] = {margin[0] / 2, margin[1] / 2};
+ const float center[2] = {0.0f, 0.0f};
+
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, center[0] - rad[0], center[1] - rad[1]);
+ immVertex2f(pos, center[0] + rad[0], center[1] + rad[1]);
+ immVertex2f(pos, center[0] + rad[0], center[1] - rad[1]);
+ immVertex2f(pos, center[0] - rad[0], center[1] + rad[1]);
+ immEnd();
+ }
+ }
+#else
+ UNUSED_VARS(margin, transform_flag, draw_options);
+#endif
+
+
+ immUnbindProgram();
+}
+
+static void cage3d_draw_circle_handles(
+ const RegionView3D *rv3d, const float matrix_final[4][4],
+ const float r[3], const float margin[3], const float color[3],
+ bool solid, float scale)
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ const float rad[3] = {margin[0] / 3, margin[1] / 3, margin[2] / 3};
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+
+ float sign[3] = {-1.0f, 0.0f, 1.0f};
+ for (int x = 0; x < 3; x++) {
+ for (int y = 0; y < 3; y++) {
+ for (int z = 0; z < 3; z++) {
+ if (x == 1 && y == 1 && z == 1) {
+ continue;
+ }
+ const float co[3] = {r[0] * sign[x], r[1] * sign[y], r[2] * sign[z]};
+ float co_test[3];
+ mul_v3_m4v3(co_test, matrix_final, co);
+ float rad_scale[3];
+ mul_v3_v3fl(rad_scale, rad, ED_view3d_pixel_size(rv3d, co_test) * scale);
+ imm_draw_point_aspect_3d(pos, co, rad_scale, solid);
+ }
+ }
+ }
+
+ immUnbindProgram();
+}
+
+/** \} */
+
+static void gizmo_cage3d_draw_intern(
+ RegionView3D *rv3d,
+ wmGizmo *gz, const bool select, const bool highlight, const int select_id)
+{
+ // const bool use_clamp = (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) == 0;
+ float dims[3];
+ RNA_float_get_array(gz->ptr, "dimensions", dims);
+ float matrix_final[4][4];
+
+ const int transform_flag = RNA_enum_get(gz->ptr, "transform");
+ const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
+ const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+
+ const float size_real[3] = {dims[0] / 2.0f, dims[1] / 2.0f, dims[2] / 2.0f};
+
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_final);
+
+ float margin[3];
+ gizmo_calc_rect_view_margin(gz, dims, margin);
+
+ /* Handy for quick testing draw (if it's outside bounds). */
+ if (false) {
+ GPU_blend(true);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv((const float[4]){1, 1, 1, 0.5f});
+ float s = 0.5f;
+ immRectf(pos, -s, -s, s, s);
+ immUnbindProgram();
+ GPU_blend(false);
+ }
+
+ if (select) {
+ /* expand for hotspot */
+#if 0
+ const float size[3] = {
+ size_real[0] + margin[0] / 2,
+ size_real[1] + margin[1] / 2,
+ size_real[2] + margin[2] / 2,
+ };
+#else
+ /* just use same value for now. */
+ const float size[3] = {UNPACK3(size_real)};
+#endif
+
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE) {
+ for (int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
+ i <= ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z;
+ i++)
+ {
+ if (i == ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MID_Y_MID_Z) {
+ continue;
+ }
+ GPU_select_load_id(select_id | i);
+ cage3d_draw_box_interaction(
+ gz->color, i, size, margin);
+ }
+ }
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
+ const int transform_part = ED_GIZMO_CAGE3D_PART_TRANSLATE;
+ GPU_select_load_id(select_id | transform_part);
+ cage3d_draw_box_interaction(
+ gz->color, transform_part, size, margin);
+ }
+ }
+ else {
+#if 0
+ const rctf _r = {
+ .xmin = -size_real[0],
+ .ymin = -size_real[1],
+ .xmax = size_real[0],
+ .ymax = size_real[1],
+ };
+#endif
+ if (draw_style == ED_GIZMO_CAGE2D_STYLE_BOX) {
+ /* corner gizmos */
+ GPU_line_width(gz->line_width + 3.0f);
+ cage3d_draw_box_corners(size_real, margin, (const float[3]){0, 0, 0});
+
+ /* corner gizmos */
+ float color[4];
+ gizmo_color_get(gz, highlight, color);
+ GPU_line_width(gz->line_width);
+ cage3d_draw_box_corners(size_real, margin, color);
+
+ bool show = false;
+ if (gz->highlight_part == ED_GIZMO_CAGE3D_PART_TRANSLATE) {
+ /* Only show if we're drawing the center handle
+ * otherwise the entire rectangle is the hotspot. */
+ if (draw_options & ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) {
+ show = true;
+ }
+ }
+ else {
+ show = true;
+ }
+
+ if (show) {
+ cage3d_draw_box_interaction(
+ gz->color, gz->highlight_part, size_real, margin);
+ }
+ }
+ else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
+ float color[4];
+ gizmo_color_get(gz, highlight, color);
+
+ GPU_line_smooth(true);
+ GPU_polygon_smooth(true);
+ GPU_blend(true);
+
+ GPU_line_width(gz->line_width + 3.0f);
+ cage3d_draw_circle_wire(size_real, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options);
+ GPU_line_width(gz->line_width);
+ cage3d_draw_circle_wire(size_real, margin, color, transform_flag, draw_options);
+
+ /* corner gizmos */
+ cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, (const float[3]){0, 0, 0}, true, 60);
+ cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, color, true, 40);
+
+ GPU_blend(false);
+ GPU_polygon_smooth(false);
+ GPU_line_smooth(false);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ GPU_line_width(1.0);
+ GPU_matrix_pop();
+}
+
+/**
+ * For when we want to draw 3d cage in 3d views.
+ */
+static void gizmo_cage3d_draw_select(const bContext *C, wmGizmo *gz, int select_id)
+{
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ gizmo_cage3d_draw_intern(rv3d, gz, true, false, select_id);
+}
+
+static void gizmo_cage3d_draw(const bContext *C, wmGizmo *gz)
+{
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
+ gizmo_cage3d_draw_intern(rv3d, gz, false, is_highlight, -1);
+}
+
+static int gizmo_cage3d_get_cursor(wmGizmo *gz)
+{
+ if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
+ return BC_NSEW_SCROLLCURSOR;
+ }
+
+ return CURSOR_STD;
+}
+
+typedef struct RectTransformInteraction {
+ float orig_mouse[3];
+ float orig_matrix_offset[4][4];
+ float orig_matrix_final_no_offset[4][4];
+} RectTransformInteraction;
+
+static void gizmo_cage3d_setup(wmGizmo *gz)
+{
+ gz->flag |= /* WM_GIZMO_DRAW_MODAL | */ /* TODO */
+ WM_GIZMO_DRAW_NO_SCALE;
+}
+
+static int gizmo_cage3d_invoke(
+ bContext *C, wmGizmo *gz, const wmEvent *event)
+{
+ RectTransformInteraction *data = MEM_callocN(sizeof(RectTransformInteraction), "cage_interaction");
+
+ copy_m4_m4(data->orig_matrix_offset, gz->matrix_offset);
+ gizmo_calc_matrix_final_no_offset(gz, data->orig_matrix_final_no_offset, true);
+
+ if (gizmo_window_project_3d(
+ C, gz, (const float[2]){UNPACK2(event->mval)}, false, data->orig_mouse) == 0)
+ {
+ zero_v3(data->orig_mouse);
+ }
+
+ gz->interaction_data = data;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int gizmo_cage3d_modal(
+ bContext *C, wmGizmo *gz, const wmEvent *event,
+ eWM_GizmoFlagTweak UNUSED(tweak_flag))
+{
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ /* For transform logic to be manageable we operate in -0.5..0.5 2D space,
+ * no matter the size of the rectangle, mouse coorts are scaled to unit space.
+ * The mouse coords have been projected into the matrix so we don't need to worry about axis alignment.
+ *
+ * - The cursor offset are multiplied by 'dims'.
+ * - Matrix translation is also multiplied by 'dims'.
+ */
+ RectTransformInteraction *data = gz->interaction_data;
+ float point_local[3];
+
+ float dims[3];
+ RNA_float_get_array(gz->ptr, "dimensions", dims);
+
+ {
+ float matrix_back[4][4];
+ copy_m4_m4(matrix_back, gz->matrix_offset);
+ copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
+
+ bool ok = gizmo_window_project_3d(
+ C, gz, (const float[2]){UNPACK2(event->mval)}, false, point_local);
+ copy_m4_m4(gz->matrix_offset, matrix_back);
+ if (!ok) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ const int transform_flag = RNA_enum_get(gz->ptr, "transform");
+ wmGizmoProperty *gz_prop;
+
+ gz_prop = WM_gizmo_target_property_find(gz, "matrix");
+ if (gz_prop->type != NULL) {
+ WM_gizmo_target_property_float_get_array(gz, gz_prop, &gz->matrix_offset[0][0]);
+ }
+
+ if (gz->highlight_part == ED_GIZMO_CAGE3D_PART_TRANSLATE) {
+ /* do this to prevent clamping from changing size */
+ copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
+ gz->matrix_offset[3][0] = data->orig_matrix_offset[3][0] + (point_local[0] - data->orig_mouse[0]);
+ gz->matrix_offset[3][1] = data->orig_matrix_offset[3][1] + (point_local[1] - data->orig_mouse[1]);
+ gz->matrix_offset[3][2] = data->orig_matrix_offset[3][2] + (point_local[2] - data->orig_mouse[2]);
+ }
+ else if (gz->highlight_part == ED_GIZMO_CAGE3D_PART_ROTATE) {
+ /* TODO (if needed) */
+ }
+ else {
+ /* scale */
+ copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
+ float pivot[3];
+ bool constrain_axis[3] = {false};
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE) {
+ gizmo_rect_pivot_from_scale_part(gz->highlight_part, pivot, constrain_axis);
+ }
+ else {
+ zero_v3(pivot);
+ }
+
+ /* Cursor deltas scaled to (-0.5..0.5). */
+ float delta_orig[3], delta_curr[3];
+
+ for (int i = 0; i < 3; i++) {
+ delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i];
+ delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i];
+ }
+
+ float scale[3] = {1.0f, 1.0f, 1.0f};
+ for (int i = 0; i < 3; i++) {
+ if (constrain_axis[i] == false) {
+ if (delta_orig[i] < 0.0f) {
+ delta_orig[i] *= -1.0f;
+ delta_curr[i] *= -1.0f;
+ }
+ const int sign = signum_i(scale[i]);
+
+ scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i]));
+
+ if ((transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_SIGNED) == 0) {
+ if (sign != signum_i(scale[i])) {
+ scale[i] = 0.0f;
+ }
+ }
+ }
+ }
+
+ if (transform_flag & ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM) {
+ if (constrain_axis[0] == false && constrain_axis[1] == false) {
+ scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f;
+ }
+ else if (constrain_axis[0] == false) {
+ scale[1] = scale[0];
+ }
+ else if (constrain_axis[1] == false) {
+ scale[0] = scale[1];
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ /* scale around pivot */
+ float matrix_scale[4][4];
+ unit_m4(matrix_scale);
+
+ mul_v3_fl(matrix_scale[0], scale[0]);
+ mul_v3_fl(matrix_scale[1], scale[1]);
+ mul_v3_fl(matrix_scale[2], scale[2]);
+
+ transform_pivot_set_m4(
+ matrix_scale,
+ (const float[3]){pivot[0] * dims[0], pivot[1] * dims[1], pivot[2] * dims[2]});
+ mul_m4_m4m4(gz->matrix_offset, data->orig_matrix_offset, matrix_scale);
+ }
+
+ if (gz_prop->type != NULL) {
+ WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &gz->matrix_offset[0][0]);
+ }
+
+ /* tag the region for redraw */
+ ED_region_tag_redraw(CTX_wm_region(C));
+ WM_event_add_mousemove(C);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_cage3d_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
+{
+ if (STREQ(gz_prop->type->idname, "matrix")) {
+ if (WM_gizmo_target_property_array_length(gz, gz_prop) == 16) {
+ WM_gizmo_target_property_float_get_array(gz, gz_prop, &gz->matrix_offset[0][0]);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+}
+
+static void gizmo_cage3d_exit(bContext *C, wmGizmo *gz, const bool cancel)
+{
+ RectTransformInteraction *data = gz->interaction_data;
+
+ if (!cancel)
+ return;
+
+ wmGizmoProperty *gz_prop;
+
+ /* reset properties */
+ gz_prop = WM_gizmo_target_property_find(gz, "matrix");
+ if (gz_prop->type != NULL) {
+ WM_gizmo_target_property_float_set_array(C, gz, gz_prop, &data->orig_matrix_offset[0][0]);
+ }
+
+ copy_m4_m4(gz->matrix_offset, data->orig_matrix_offset);
+}
+
+
+/* -------------------------------------------------------------------- */
+/** \name Cage Gizmo API
+ *
+ * \{ */
+
+static void GIZMO_GT_cage_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_cage_3d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_cage3d_draw;
+ gzt->draw_select = gizmo_cage3d_draw_select;
+ gzt->setup = gizmo_cage3d_setup;
+ gzt->invoke = gizmo_cage3d_invoke;
+ gzt->property_update = gizmo_cage3d_property_update;
+ gzt->modal = gizmo_cage3d_modal;
+ gzt->exit = gizmo_cage3d_exit;
+ gzt->cursor_get = gizmo_cage3d_get_cursor;
+
+ gzt->struct_size = sizeof(wmGizmo);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_style[] = {
+ {ED_GIZMO_CAGE2D_STYLE_BOX, "BOX", 0, "Box", ""},
+ {ED_GIZMO_CAGE2D_STYLE_CIRCLE, "CIRCLE", 0, "Circle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_transform[] = {
+ {ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE, "TRANSLATE", 0, "Move", ""},
+ {ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE, "SCALE", 0, "Scale", ""},
+ {ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM, "SCALE_UNIFORM", 0, "Scale Uniform", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_draw_options[] = {
+ {ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "XFORM_CENTER_HANDLE", 0, "Center Handle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static float unit_v3[3] = {1.0f, 1.0f, 1.0f};
+ RNA_def_float_vector(gzt->srna, "dimensions", 3, unit_v3, 0, FLT_MAX, "Dimensions", "", 0.0f, FLT_MAX);
+ RNA_def_enum_flag(gzt->srna, "transform", rna_enum_transform, 0, "Transform Options", "");
+ RNA_def_enum(gzt->srna, "draw_style", rna_enum_draw_style, ED_GIZMO_CAGE2D_STYLE_CIRCLE, "Draw Style", "");
+ RNA_def_enum_flag(
+ gzt->srna, "draw_options", rna_enum_draw_options,
+ ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "Draw Options", "");
+
+ WM_gizmotype_target_property_def(gzt, "matrix", PROP_FLOAT, 16);
+}
+
+void ED_gizmotypes_cage_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_cage_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
new file mode 100644
index 00000000000..c391ec812c7
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -0,0 +1,623 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file dial3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Dial Gizmo
+ *
+ * 3D Gizmo
+ *
+ * \brief Circle shaped gizmo for circular interaction.
+ * Currently no own handling, use with operator only.
+ *
+ * - `matrix[0]` is derived from Y and Z.
+ * - `matrix[1]` is 'up' when DialGizmo.use_start_y_axis is set.
+ * - `matrix[2]` is the axis the dial rotates around (all dials).
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_transform.h"
+#include "ED_gizmo_library.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+/* To use custom dials exported to geom_dial_gizmo.c */
+// #define USE_GIZMO_CUSTOM_DIAL
+
+typedef struct DialInteraction {
+ struct {
+ float mval[2];
+ /* Only for when using properties. */
+ float prop_angle;
+ } init;
+ struct {
+ /* Cache the last angle to detect rotations bigger than -/+ PI. */
+ eWM_GizmoFlagTweak tweak_flag;
+ float angle;
+ } prev;
+
+ /* Number of full rotations. */
+ int rotations;
+ bool has_drag;
+ float angle_increment;
+
+ /* Final output values, used for drawing. */
+ struct {
+ float angle_ofs;
+ float angle_delta;
+ } output;
+} DialInteraction;
+
+#define DIAL_WIDTH 1.0f
+#define DIAL_RESOLUTION 48
+
+/* Could make option, negative to clip more (don't show when view aligned). */
+#define DIAL_CLIP_BIAS 0.02
+
+/* -------------------------------------------------------------------- */
+
+static void dial_geom_draw(
+ const float color[4], const float line_width,
+ const bool select,
+ const float axis_modal_mat[4][4], const float clip_plane[4],
+ const float arc_partial_angle, const float arc_inner_factor,
+ const int draw_options)
+{
+#ifdef USE_GIZMO_CUSTOM_DIAL
+ UNUSED_VARS(gz, axis_modal_mat, clip_plane);
+ wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_dial, select, color);
+#else
+ const bool filled = (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_FILL) != 0;
+
+ GPU_line_width(line_width);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ if (clip_plane) {
+ immBindBuiltinProgram(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR);
+ immUniform4fv("ClipPlane", clip_plane);
+ immUniformMatrix4fv("ModelMatrix", axis_modal_mat);
+ glEnable(GL_CLIP_DISTANCE0);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ immUniformColor4fv(color);
+
+ if (filled) {
+ imm_draw_circle_fill_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION);
+ }
+ else {
+ if (arc_partial_angle == 0.0f) {
+ imm_draw_circle_wire_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION);
+ if (arc_inner_factor != 0.0f) {
+ imm_draw_circle_wire_2d(pos, 0, 0, arc_inner_factor, DIAL_RESOLUTION);
+ }
+ }
+ else {
+ float arc_partial_deg = RAD2DEGF((M_PI * 2) - arc_partial_angle);
+ imm_draw_circle_partial_wire_2d(
+ pos, 0, 0, 1.0, DIAL_RESOLUTION,
+ -arc_partial_deg / 2, arc_partial_deg);
+#if 0
+ if (arc_inner_factor != 0.0f) {
+ BLI_assert(0);
+ }
+#endif
+ }
+ }
+
+ immUnbindProgram();
+
+ if (clip_plane) {
+ glDisable(GL_CLIP_DISTANCE0);
+ }
+
+ UNUSED_VARS(select);
+#endif
+}
+
+/**
+ * Draws a line from (0, 0, 0) to \a co_outer, at \a angle.
+ */
+static void dial_ghostarc_draw_helpline(
+ const float angle, const float co_outer[3], const float color[4])
+{
+ GPU_matrix_push();
+ GPU_matrix_rotate_3f(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ immUniformColor4fv(color);
+
+ immBegin(GPU_PRIM_LINE_STRIP, 2);
+ immVertex3f(pos, 0.0f, 0, 0.0f);
+ immVertex3fv(pos, co_outer);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+}
+
+/**
+ * Draws segments to indicate the position of each increment.
+ */
+static void dial_ghostarc_draw_incremental_angle(
+ const float incremental_angle, const float offset)
+{
+ const int tot_incr = (2 * M_PI) / incremental_angle;
+ GPU_line_width(1.0f);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+ immBegin(GPU_PRIM_LINES, tot_incr * 2);
+
+ float v[3] = { 0 };
+ for (int i = 0; i < tot_incr; i++) {
+ v[0] = sinf(offset + incremental_angle * i);
+ v[1] = cosf(offset + incremental_angle * i);
+
+ mul_v2_fl(v, DIAL_WIDTH * 1.1f);
+ immVertex3fv(pos, v);
+
+ mul_v2_fl(v, 1.1f);
+ immVertex3fv(pos, v);
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
+static void dial_ghostarc_draw(
+ const float angle_ofs, const float angle_delta,
+ const float arc_inner_factor, const float color[4])
+{
+ const float width_inner = DIAL_WIDTH;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (arc_inner_factor != 0.0) {
+ float color_dark[4] = {0};
+ color_dark[3] = color[3] / 2;
+ immUniformColor4fv(color_dark);
+ imm_draw_disk_partial_fill_2d(
+ pos, 0, 0, arc_inner_factor, width_inner, DIAL_RESOLUTION, RAD2DEGF(angle_ofs), RAD2DEGF(M_PI * 2));
+ }
+
+ immUniformColor4fv(color);
+ imm_draw_disk_partial_fill_2d(
+ pos, 0, 0, arc_inner_factor, width_inner, DIAL_RESOLUTION, RAD2DEGF(angle_ofs), RAD2DEGF(angle_delta));
+ immUnbindProgram();
+}
+
+static void dial_ghostarc_get_angles(
+ const wmGizmo *gz,
+ const wmEvent *event,
+ const ARegion *ar,
+ float mat[4][4], const float co_outer[3],
+ float *r_start, float *r_delta)
+{
+ DialInteraction *inter = gz->interaction_data;
+ const RegionView3D *rv3d = ar->regiondata;
+ const float mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin};
+
+ /* We might need to invert the direction of the angles. */
+ float view_vec[3], axis_vec[3];
+ ED_view3d_global_to_vector(rv3d, gz->matrix_basis[3], view_vec);
+ normalize_v3_v3(axis_vec, gz->matrix_basis[2]);
+
+ float proj_outer_rel[3];
+ mul_v3_project_m4_v3(proj_outer_rel, mat, co_outer);
+ sub_v3_v3(proj_outer_rel, gz->matrix_basis[3]);
+
+ float proj_mval_new_rel[3];
+ float proj_mval_init_rel[3];
+ float dial_plane[4];
+
+ plane_from_point_normal_v3(dial_plane, gz->matrix_basis[3], axis_vec);
+
+ if (!ED_view3d_win_to_3d_on_plane(ar, dial_plane, inter->init.mval, false, proj_mval_init_rel)) {
+ goto fail;
+ }
+ sub_v3_v3(proj_mval_init_rel, gz->matrix_basis[3]);
+
+ if (!ED_view3d_win_to_3d_on_plane(ar, dial_plane, mval, false, proj_mval_new_rel)) {
+ goto fail;
+ }
+ sub_v3_v3(proj_mval_new_rel, gz->matrix_basis[3]);
+
+ const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+
+ /* Start direction from mouse or set by user. */
+ const float *proj_init_rel =
+ (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y) ?
+ gz->matrix_basis[1] : proj_mval_init_rel;
+
+ /* Return angles. */
+ const float start = angle_wrap_rad(angle_signed_on_axis_v3v3_v3(proj_outer_rel, proj_init_rel, axis_vec));
+ const float delta = angle_wrap_rad(angle_signed_on_axis_v3v3_v3(proj_mval_init_rel, proj_mval_new_rel, axis_vec));
+
+ /* Change of sign, we passed the 180 degree threshold. This means we need to add a turn
+ * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2.
+ * Logic taken from #BLI_dial_angle */
+ if ((delta * inter->prev.angle < 0.0f) &&
+ (fabsf(inter->prev.angle) > (float)M_PI_2))
+ {
+ if (inter->prev.angle < 0.0f) {
+ inter->rotations--;
+ }
+ else {
+ inter->rotations++;
+ }
+ }
+ inter->prev.angle = delta;
+
+ const bool wrap_angle = RNA_boolean_get(gz->ptr, "wrap_angle");
+ const double delta_final = (double)delta + ((2 * M_PI) * (double)inter->rotations);
+ *r_start = start;
+ *r_delta = (float)(wrap_angle ? fmod(delta_final, 2 * M_PI) : delta_final);
+ return;
+
+ /* If we can't project (unlikely). */
+fail:
+ *r_start = 0.0;
+ *r_delta = 0.0;
+}
+
+static void dial_ghostarc_draw_with_helplines(
+ const float angle_ofs, const float angle_delta,
+ const float arc_inner_factor, const float color_helpline[4], const int draw_options)
+{
+ /* Coordinate at which the arc drawing will be started. */
+ const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f};
+ dial_ghostarc_draw(angle_ofs, angle_delta, arc_inner_factor, (const float[4]){0.8f, 0.8f, 0.8f, 0.4f});
+ GPU_line_width(1.0f);
+ dial_ghostarc_draw_helpline(angle_ofs, co_outer, color_helpline);
+ if (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE) {
+ GPU_line_width(3.0f);
+ }
+ dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, color_helpline);
+}
+
+static void dial_draw_intern(
+ const bContext *C, wmGizmo *gz,
+ const bool select, const bool highlight, float clip_plane[4])
+{
+ float matrix_final[4][4];
+ float color[4];
+
+ (void)C;
+ BLI_assert(CTX_wm_area(C)->spacetype == SPACE_VIEW3D);
+
+ gizmo_color_get(gz, highlight, color);
+
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ const float arc_partial_angle = RNA_float_get(gz->ptr, "arc_partial_angle");
+ const float arc_inner_factor = RNA_float_get(gz->ptr, "arc_inner_factor");
+ int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+ float angle_ofs = 0.0f;
+ float angle_delta = 0.0f;
+ float angle_increment = 0.0f;
+
+ if (select) {
+ draw_options &= ~ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE;
+ }
+
+ if (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE &&
+ (gz->flag & WM_GIZMO_DRAW_VALUE))
+ {
+ DialInteraction *inter = gz->interaction_data;
+ if (inter) {
+ angle_ofs = inter->output.angle_ofs;
+ angle_delta = inter->output.angle_delta;
+ angle_increment = inter->angle_increment;
+ }
+ else {
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ angle_delta = WM_gizmo_target_property_float_get(gz, gz_prop);
+ }
+ }
+ }
+
+ ED_gizmotypes_dial_3d_draw_util(
+ gz->matrix_basis, matrix_final, gz->line_width, color,
+ &(struct Dial3dParams){
+ .draw_options = draw_options,
+ .angle_ofs = angle_ofs,
+ .angle_delta = angle_delta,
+ .angle_increment = angle_increment,
+ .arc_partial_angle = arc_partial_angle,
+ .arc_inner_factor = arc_inner_factor,
+ .clip_plane = clip_plane,
+ });
+}
+
+static void gizmo_dial_draw_select(const bContext *C, wmGizmo *gz, int select_id)
+{
+ float clip_plane_buf[4];
+ const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+ float *clip_plane = (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_CLIP) ? clip_plane_buf : NULL;
+
+ if (clip_plane) {
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ copy_v3_v3(clip_plane, rv3d->viewinv[2]);
+ clip_plane[3] = -dot_v3v3(rv3d->viewinv[2], gz->matrix_basis[3]);
+ clip_plane[3] += DIAL_CLIP_BIAS;
+ }
+
+ GPU_select_load_id(select_id);
+ dial_draw_intern(C, gz, true, false, clip_plane);
+
+ if (clip_plane) {
+ glDisable(GL_CLIP_DISTANCE0);
+ }
+}
+
+static void gizmo_dial_draw(const bContext *C, wmGizmo *gz)
+{
+ const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL;
+ const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
+ float clip_plane_buf[4];
+ const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+ float *clip_plane = (!is_modal && (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_CLIP)) ? clip_plane_buf : NULL;
+
+ if (clip_plane) {
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ copy_v3_v3(clip_plane, rv3d->viewinv[2]);
+ clip_plane[3] = -dot_v3v3(rv3d->viewinv[2], gz->matrix_basis[3]);
+ clip_plane[3] += DIAL_CLIP_BIAS;
+ }
+
+ GPU_blend(true);
+ dial_draw_intern(C, gz, false, is_highlight, clip_plane);
+ GPU_blend(false);
+}
+
+static int gizmo_dial_modal(
+ bContext *C, wmGizmo *gz, const wmEvent *event,
+ eWM_GizmoFlagTweak tweak_flag)
+{
+ DialInteraction *inter = gz->interaction_data;
+ if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ /* Coordinate at which the arc drawing will be started. */
+ const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f};
+ float angle_ofs, angle_delta, angle_increment = 0.0f;
+
+ dial_ghostarc_get_angles(
+ gz, event, CTX_wm_region(C), gz->matrix_basis, co_outer, &angle_ofs, &angle_delta);
+
+ if (tweak_flag & WM_GIZMO_TWEAK_SNAP) {
+ angle_increment = RNA_float_get(gz->ptr, "incremental_angle");
+ angle_delta = (float)roundf((double)angle_delta / angle_increment) * angle_increment;
+ }
+ if (tweak_flag & WM_GIZMO_TWEAK_PRECISE) {
+ angle_increment *= 0.2f;
+ angle_delta *= 0.2f;
+ }
+ if (angle_delta != 0.0f) {
+ inter->has_drag = true;
+ }
+
+ inter->angle_increment = angle_increment;
+ inter->output.angle_delta = angle_delta;
+ inter->output.angle_ofs = angle_ofs;
+
+ /* Set the property for the operator and call its modal function. */
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, inter->init.prop_angle + angle_delta);
+ }
+
+ inter->prev.tweak_flag = tweak_flag;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_dial_exit(bContext *C, wmGizmo *gz, const bool cancel)
+{
+ DialInteraction *inter = gz->interaction_data;
+ bool use_reset_value = false;
+ float reset_value = 0.0f;
+ if (cancel) {
+ /* Set the property for the operator and call its modal function. */
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ use_reset_value = true;
+ reset_value = inter->init.prop_angle;
+ }
+ }
+ else {
+ if (inter->has_drag == false) {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value");
+ if (RNA_property_is_set(gz->ptr, prop)) {
+ use_reset_value = true;
+ reset_value = RNA_property_float_get(gz->ptr, prop);
+ }
+ }
+ }
+
+ if (use_reset_value) {
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value);
+ }
+ }
+
+}
+
+
+static void gizmo_dial_setup(wmGizmo *gz)
+{
+ const float dir_default[3] = {0.0f, 0.0f, 1.0f};
+
+ /* defaults */
+ copy_v3_v3(gz->matrix_basis[2], dir_default);
+}
+
+static int gizmo_dial_invoke(
+ bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
+{
+ DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__);
+
+ inter->init.mval[0] = event->mval[0];
+ inter->init.mval[1] = event->mval[1];
+
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ inter->init.prop_angle = WM_gizmo_target_property_float_get(gz, gz_prop);
+ }
+
+ gz->interaction_data = inter;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Dial Gizmo API
+ *
+ * \{ */
+
+void ED_gizmotypes_dial_3d_draw_util(
+ const float matrix_basis[4][4],
+ const float matrix_final[4][4],
+ const float line_width,
+ const float color[4],
+ struct Dial3dParams *params)
+{
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_final);
+
+ GPU_polygon_smooth(false);
+
+ if ((params->draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE) != 0) {
+ /* Draw rotation indicator arc first. */
+ dial_ghostarc_draw_with_helplines(
+ params->angle_ofs, params->angle_delta,
+ params->arc_inner_factor, color, params->draw_options);
+
+ if ((params->draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR) != 0) {
+ dial_ghostarc_draw_with_helplines(
+ params->angle_ofs + M_PI, params->angle_delta,
+ params->arc_inner_factor, color, params->draw_options);
+ }
+ }
+
+ if (params->angle_increment) {
+ dial_ghostarc_draw_incremental_angle(params->angle_increment, params->angle_ofs);
+ }
+
+ /* Draw actual dial gizmo. */
+ dial_geom_draw(
+ color, line_width, false, matrix_basis, params->clip_plane,
+ params->arc_partial_angle, params->arc_inner_factor, params->draw_options);
+
+ GPU_matrix_pop();
+}
+
+static void GIZMO_GT_dial_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_dial_3d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_dial_draw;
+ gzt->draw_select = gizmo_dial_draw_select;
+ gzt->setup = gizmo_dial_setup;
+ gzt->invoke = gizmo_dial_invoke;
+ gzt->modal = gizmo_dial_modal;
+ gzt->exit = gizmo_dial_exit;
+
+ gzt->struct_size = sizeof(wmGizmo);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_options[] = {
+ {ED_GIZMO_DIAL_DRAW_FLAG_CLIP, "CLIP", 0, "Clipped", ""},
+ {ED_GIZMO_DIAL_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
+ {ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR, "ANGLE_MIRROR", 0, "Angle Mirror", ""},
+ {ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y, "ANGLE_START_Y", 0, "Angle Start Y", ""},
+ {ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE, "ANGLE_VALUE", 0, "Show Angle Value", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ RNA_def_enum_flag(gzt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
+ RNA_def_boolean(gzt->srna, "wrap_angle", true, "Wrap Angle", "");
+ RNA_def_float_factor(gzt->srna, "arc_inner_factor", 0.0f, 0.0f, 1.0f, "Arc Inner Factor", "", 0.0f, 1.0f);
+ RNA_def_float_factor(gzt->srna, "arc_partial_angle", 0.0f, 0.0f, M_PI * 2, "Show Partial Dial", "", 0.0f, M_PI * 2);
+ RNA_def_float_factor(
+ gzt->srna, "incremental_angle", SNAP_INCREMENTAL_ANGLE, 0.0f,
+ M_PI * 2, "Incremental Angle", "Angle to snap in steps", 0.0f, M_PI * 2);
+ RNA_def_float(
+ gzt->srna, "click_value", 0.0f, -FLT_MAX, FLT_MAX,
+ "Click Value", "Value to use for a single click action",
+ -FLT_MAX, FLT_MAX);
+
+ WM_gizmotype_target_property_def(gzt, "offset", PROP_FLOAT, 1);
+}
+
+void ED_gizmotypes_dial_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_dial_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
new file mode 100644
index 00000000000..b91a193e9a0
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -0,0 +1,466 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file move3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Move Gizmo
+ *
+ * 3D Gizmo, also works in 2D views.
+ *
+ * \brief Simple gizmo to move and translate.
+ *
+ * - `matrix[0]` is derived from Y and Z.
+ * - `matrix[1]` currently not used.
+ * - `matrix[2]` is the widget direction (for all gizmos).
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_gizmo_library.h"
+#include "ED_transform_snap_object_context.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+#define MVAL_MAX_PX_DIST 12.0f
+
+typedef struct MoveGizmo3D {
+ wmGizmo gizmo;
+ /* Added to 'matrix_basis' when calculating the matrix. */
+ float prop_co[3];
+} MoveGizmo3D;
+
+static void gizmo_move_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
+{
+ MoveGizmo3D *move = (MoveGizmo3D *)gz;
+
+ copy_m4_m4(r_matrix, move->gizmo.matrix_basis);
+ add_v3_v3(r_matrix[3], move->prop_co);
+}
+
+static int gizmo_move_modal(
+ bContext *C, wmGizmo *gz, const wmEvent *event,
+ eWM_GizmoFlagTweak tweak_flag);
+
+typedef struct MoveInteraction {
+ struct {
+ float mval[2];
+ /* Only for when using properties. */
+ float prop_co[3];
+ float matrix_final[4][4];
+ } init;
+ struct {
+ eWM_GizmoFlagTweak tweak_flag;
+ } prev;
+
+ /* We could have other snap contexts, for now only support 3D view. */
+ struct SnapObjectContext *snap_context_v3d;
+
+} MoveInteraction;
+
+#define DIAL_RESOLUTION 32
+
+/* -------------------------------------------------------------------- */
+
+static void move_geom_draw(
+ const wmGizmo *gz, const float color[4], const bool select, const int draw_options)
+{
+#ifdef USE_GIZMO_CUSTOM_DIAL
+ UNUSED_VARS(move3d, col, axis_modal_mat);
+ wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_move3d, select);
+#else
+ const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
+ const bool filled = (draw_options & ED_GIZMO_MOVE_DRAW_FLAG_FILL) != 0;
+
+ GPU_line_width(gz->line_width);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ immUniformColor4fv(color);
+
+ if (draw_style == ED_GIZMO_MOVE_STYLE_RING_2D) {
+ if (filled) {
+ imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION);
+ }
+ else {
+ imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION);
+ }
+ }
+ else if (draw_style == ED_GIZMO_MOVE_STYLE_CROSS_2D) {
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, 1.0f, 1.0f);
+ immVertex2f(pos, -1.0f, -1.0f);
+
+ immVertex2f(pos, -1.0f, 1.0f);
+ immVertex2f(pos, 1.0f, -1.0f);
+ immEnd();
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ immUnbindProgram();
+
+ UNUSED_VARS(select);
+#endif
+}
+
+static void move3d_get_translate(
+ const wmGizmo *gz, const wmEvent *event, const ARegion *ar,
+ float co_delta[3])
+{
+ MoveInteraction *inter = gz->interaction_data;
+ const float mval_delta[2] = {
+ event->mval[0] - inter->init.mval[0],
+ event->mval[1] - inter->init.mval[1],
+ };
+
+ RegionView3D *rv3d = ar->regiondata;
+ float co_ref[3];
+ mul_v3_mat3_m4v3(co_ref, gz->matrix_space, inter->init.prop_co);
+ const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL);
+
+ ED_view3d_win_to_delta(ar, mval_delta, co_delta, zfac);
+
+ float matrix_space_inv[3][3];
+ copy_m3_m4(matrix_space_inv, gz->matrix_space);
+ invert_m3(matrix_space_inv);
+ mul_m3_v3(matrix_space_inv, co_delta);
+}
+
+static void move3d_draw_intern(
+ const bContext *C, wmGizmo *gz,
+ const bool select, const bool highlight)
+{
+ MoveInteraction *inter = gz->interaction_data;
+ const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
+ const bool align_view = (draw_options & ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW) != 0;
+ float color[4];
+ float matrix_final[4][4];
+ float matrix_align[4][4];
+
+ gizmo_color_get(gz, highlight, color);
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_final);
+
+ if (align_view) {
+ float matrix_final_unit[4][4];
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ normalize_m4_m4(matrix_final_unit, matrix_final);
+ mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit);
+ zero_v3(matrix_align[3]);
+ transpose_m4(matrix_align);
+ GPU_matrix_mul(matrix_align);
+ }
+
+ GPU_blend(true);
+ move_geom_draw(gz, color, select, draw_options);
+ GPU_blend(false);
+ GPU_matrix_pop();
+
+ if (gz->interaction_data) {
+ GPU_matrix_push();
+ GPU_matrix_mul(inter->init.matrix_final);
+
+ if (align_view) {
+ GPU_matrix_mul(matrix_align);
+ }
+
+ GPU_blend(true);
+ move_geom_draw(gz, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}, select, draw_options);
+ GPU_blend(false);
+ GPU_matrix_pop();
+ }
+}
+
+static void gizmo_move_draw_select(const bContext *C, wmGizmo *gz, int select_id)
+{
+ GPU_select_load_id(select_id);
+ move3d_draw_intern(C, gz, true, false);
+}
+
+static void gizmo_move_draw(const bContext *C, wmGizmo *gz)
+{
+ const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL;
+ const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
+
+ (void)is_modal;
+
+ GPU_blend(true);
+ move3d_draw_intern(C, gz, false, is_highlight);
+ GPU_blend(false);
+}
+
+static int gizmo_move_modal(
+ bContext *C, wmGizmo *gz, const wmEvent *event,
+ eWM_GizmoFlagTweak tweak_flag)
+{
+ MoveInteraction *inter = gz->interaction_data;
+ if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ MoveGizmo3D *move = (MoveGizmo3D *)gz;
+ ARegion *ar = CTX_wm_region(C);
+
+ float prop_delta[3];
+ if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D) {
+ move3d_get_translate(gz, event, ar, prop_delta);
+ }
+ else {
+ float mval_proj_init[2], mval_proj_curr[2];
+ if ((gizmo_window_project_2d(
+ C, gz, inter->init.mval, 2, false, mval_proj_init) == false) ||
+ (gizmo_window_project_2d(
+ C, gz, (const float[2]){UNPACK2(event->mval)}, 2, false, mval_proj_curr) == false))
+ {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init);
+ prop_delta[2] = 0.0f;
+ }
+
+ if (tweak_flag & WM_GIZMO_TWEAK_PRECISE) {
+ mul_v3_fl(prop_delta, 0.1f);
+ }
+
+ add_v3_v3v3(move->prop_co, inter->init.prop_co, prop_delta);
+
+ if (tweak_flag & WM_GIZMO_TWEAK_SNAP) {
+ if (inter->snap_context_v3d) {
+ float dist_px = MVAL_MAX_PX_DIST * U.pixelsize;
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ float co[3];
+ if (ED_transform_snap_object_project_view3d(
+ inter->snap_context_v3d,
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ .use_occlusion_test = true,
+ },
+ mval_fl, &dist_px,
+ co, NULL))
+ {
+ float matrix_space_inv[4][4];
+ invert_m4_m4(matrix_space_inv, gz->matrix_space);
+ mul_v3_m4v3(move->prop_co, matrix_space_inv, co);
+ }
+ }
+ }
+
+ /* set the property for the operator and call its modal function */
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set_array(C, gz, gz_prop, move->prop_co);
+ }
+ else {
+ zero_v3(move->prop_co);
+ }
+
+ ED_region_tag_redraw(ar);
+
+ inter->prev.tweak_flag = tweak_flag;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_move_exit(bContext *C, wmGizmo *gz, const bool cancel)
+{
+ MoveInteraction *inter = gz->interaction_data;
+ bool use_reset_value = false;
+ const float *reset_value = NULL;
+ if (cancel) {
+ /* Set the property for the operator and call its modal function. */
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ use_reset_value = true;
+ reset_value = inter->init.prop_co;
+ }
+ }
+
+ if (use_reset_value) {
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set_array(C, gz, gz_prop, reset_value);
+ }
+ }
+
+ if (inter->snap_context_v3d) {
+ ED_transform_snap_object_context_destroy(inter->snap_context_v3d);
+ inter->snap_context_v3d = NULL;
+ }
+}
+
+static int gizmo_move_invoke(
+ bContext *C, wmGizmo *gz, const wmEvent *event)
+{
+ const bool use_snap = RNA_boolean_get(gz->ptr, "use_snap");
+
+ MoveInteraction *inter = MEM_callocN(sizeof(MoveInteraction), __func__);
+ inter->init.mval[0] = event->mval[0];
+ inter->init.mval[1] = event->mval[1];
+
+#if 0
+ copy_v3_v3(inter->init.prop_co, move->prop_co);
+#else
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_get_array(gz, gz_prop, inter->init.prop_co);
+ }
+#endif
+
+ WM_gizmo_calc_matrix_final(gz, inter->init.matrix_final);
+
+ if (use_snap) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa) {
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ inter->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
+ CTX_data_main(C), CTX_data_scene(C), CTX_data_depsgraph(C), 0,
+ CTX_wm_region(C), CTX_wm_view3d(C));
+ break;
+ }
+ default:
+ /* Not yet supported. */
+ BLI_assert(0);
+ }
+ }
+ }
+
+ gz->interaction_data = inter;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+static int gizmo_move_test_select(
+ bContext *C, wmGizmo *gz, const int mval[2])
+{
+ float point_local[2];
+
+ if (gizmo_window_project_2d(
+ C, gz, (const float[2]){UNPACK2(mval)}, 2, true, point_local) == false)
+ {
+ return -1;
+ }
+
+ /* The 'gz->scale_final' is already applied when projecting. */
+ if (len_squared_v2(point_local) < 1.0f) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static void gizmo_move_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
+{
+ MoveGizmo3D *move = (MoveGizmo3D *)gz;
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_get_array(gz, gz_prop, move->prop_co);
+ }
+ else {
+ zero_v3(move->prop_co);
+ }
+}
+
+static int gizmo_move_cursor_get(wmGizmo *UNUSED(gz))
+{
+ return BC_NSEW_SCROLLCURSOR;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Move Gizmo API
+ *
+ * \{ */
+
+static void GIZMO_GT_move_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_move_3d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_move_draw;
+ gzt->draw_select = gizmo_move_draw_select;
+ gzt->test_select = gizmo_move_test_select;
+ gzt->matrix_basis_get = gizmo_move_matrix_basis_get;
+ gzt->invoke = gizmo_move_invoke;
+ gzt->property_update = gizmo_move_property_update;
+ gzt->modal = gizmo_move_modal;
+ gzt->exit = gizmo_move_exit;
+ gzt->cursor_get = gizmo_move_cursor_get;
+
+ gzt->struct_size = sizeof(MoveGizmo3D);
+
+ /* rna */
+ static EnumPropertyItem rna_enum_draw_style[] = {
+ {ED_GIZMO_MOVE_STYLE_RING_2D, "RING_2D", 0, "Ring", ""},
+ {ED_GIZMO_MOVE_STYLE_CROSS_2D, "CROSS_2D", 0, "Ring", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem rna_enum_draw_options[] = {
+ {ED_GIZMO_MOVE_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
+ {ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW, "ALIGN_VIEW", 0, "Align View", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ RNA_def_enum(gzt->srna, "draw_style", rna_enum_draw_style, ED_GIZMO_MOVE_STYLE_RING_2D, "Draw Style", "");
+ RNA_def_enum_flag(gzt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
+ RNA_def_boolean(gzt->srna, "use_snap", false, "Use Snap", "");
+
+ WM_gizmotype_target_property_def(gzt, "offset", PROP_FLOAT, 3);
+}
+
+void ED_gizmotypes_move_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_move_3d);
+}
+
+/** \} */ // Move Gizmo API
diff --git a/source/blender/editors/gizmo_library/gizmo_types/primitive3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/primitive3d_gizmo.c
new file mode 100644
index 00000000000..d5f1c23971c
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/primitive3d_gizmo.c
@@ -0,0 +1,191 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file primitive3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Primitive Gizmo
+ *
+ * 3D Gizmo
+ *
+ * \brief Gizmo with primitive drawing type (plane, cube, etc.).
+ * Currently only plane primitive supported without own handling, use with operator only.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_gizmo_library.h"
+
+/* own includes */
+#include "../gizmo_library_intern.h"
+
+static float verts_plane[4][3] = {
+ {-1, -1, 0},
+ { 1, -1, 0},
+ { 1, 1, 0},
+ {-1, 1, 0},
+};
+
+
+/* -------------------------------------------------------------------- */
+
+static void gizmo_primitive_draw_geom(
+ const float col_inner[4], const float col_outer[4], const int draw_style)
+{
+ float (*verts)[3];
+ uint vert_count = 0;
+
+ if (draw_style == ED_GIZMO_PRIMITIVE_STYLE_PLANE) {
+ verts = verts_plane;
+ vert_count = ARRAY_SIZE(verts_plane);
+ }
+
+ if (vert_count > 0) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ wm_gizmo_vec_draw(col_inner, verts, vert_count, pos, GPU_PRIM_TRI_FAN);
+ wm_gizmo_vec_draw(col_outer, verts, vert_count, pos, GPU_PRIM_LINE_LOOP);
+ immUnbindProgram();
+ }
+}
+
+static void gizmo_primitive_draw_intern(
+ wmGizmo *gz, const bool UNUSED(select),
+ const bool highlight)
+{
+ float color_inner[4], color_outer[4];
+ float matrix_final[4][4];
+ const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
+
+ gizmo_color_get(gz, highlight, color_outer);
+ copy_v4_v4(color_inner, color_outer);
+ color_inner[3] *= 0.5f;
+
+ WM_gizmo_calc_matrix_final(gz, matrix_final);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_final);
+
+ GPU_blend(true);
+ gizmo_primitive_draw_geom(color_inner, color_outer, draw_style);
+ GPU_blend(false);
+
+ GPU_matrix_pop();
+
+ if (gz->interaction_data) {
+ GizmoInteraction *inter = gz->interaction_data;
+
+ copy_v4_fl(color_inner, 0.5f);
+ copy_v3_fl(color_outer, 0.5f);
+ color_outer[3] = 0.8f;
+
+ GPU_matrix_push();
+ GPU_matrix_mul(inter->init_matrix_final);
+
+ GPU_blend(true);
+ gizmo_primitive_draw_geom(color_inner, color_outer, draw_style);
+ GPU_blend(false);
+
+ GPU_matrix_pop();
+ }
+}
+
+static void gizmo_primitive_draw_select(
+ const bContext *UNUSED(C), wmGizmo *gz,
+ int select_id)
+{
+ GPU_select_load_id(select_id);
+ gizmo_primitive_draw_intern(gz, true, false);
+}
+
+static void gizmo_primitive_draw(const bContext *UNUSED(C), wmGizmo *gz)
+{
+ gizmo_primitive_draw_intern(
+ gz, false,
+ (gz->state & WM_GIZMO_STATE_HIGHLIGHT));
+}
+
+static void gizmo_primitive_setup(wmGizmo *gz)
+{
+ gz->flag |= WM_GIZMO_DRAW_MODAL;
+}
+
+static int gizmo_primitive_invoke(
+ bContext *UNUSED(C), wmGizmo *gz, const wmEvent *UNUSED(event))
+{
+ GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__);
+
+ WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
+
+ gz->interaction_data = inter;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Gizmo API
+ *
+ * \{ */
+
+static void GIZMO_GT_primitive_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_primitive_3d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_primitive_draw;
+ gzt->draw_select = gizmo_primitive_draw_select;
+ gzt->setup = gizmo_primitive_setup;
+ gzt->invoke = gizmo_primitive_invoke;
+
+ gzt->struct_size = sizeof(wmGizmo);
+
+ static EnumPropertyItem rna_enum_draw_style[] = {
+ {ED_GIZMO_PRIMITIVE_STYLE_PLANE, "PLANE", 0, "Plane", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ RNA_def_enum(gzt->srna, "draw_style", rna_enum_draw_style, ED_GIZMO_PRIMITIVE_STYLE_PLANE, "Draw Style", "");
+}
+
+void ED_gizmotypes_primitive_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_primitive_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/value2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/value2d_gizmo.c
new file mode 100644
index 00000000000..46a6b8f3a5f
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/value2d_gizmo.c
@@ -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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file value2d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Value Gizmo
+ *
+ * \brief Gizmo that can be used to click and drag a value.
+ *
+ * Use this in cases where it may be useful to have a tool,
+ * but the tool doesn't relate to an on-screen handle.
+ * eg: smooth or randomize.
+ *
+ * Exactly how this maps X/Y axis, and draws - may change.
+ * The purpose here is to avoid having to write custom modal handlers for each operator.
+ *
+ * So we can use a single gizmo to make redoing an operator seem modal.
+ */
+
+#include <float.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_context.h"
+#include "BLI_string.h"
+
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Value Gizmo
+ *
+ * \{ */
+
+typedef struct ValueInteraction {
+ struct {
+ float mval[2];
+ float prop_value;
+ } init;
+ struct {
+ float prop_value;
+ eWM_GizmoFlagTweak tweak_flag;
+ } prev;
+ float range[2];
+} ValueInteraction;
+
+static void gizmo_value_draw(const bContext *UNUSED(C), wmGizmo *UNUSED(gz))
+{
+ /* pass */
+}
+
+static int gizmo_value_modal(
+ bContext *C, wmGizmo *gz, const wmEvent *event,
+ eWM_GizmoFlagTweak tweak_flag)
+{
+ ValueInteraction *inter = gz->interaction_data;
+ if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ ARegion *ar = CTX_wm_region(C);
+ const float value_scale = 4.0f; /* Could be option. */
+ const float value_range = inter->range[1] - inter->range[0];
+ float value_delta = (
+ inter->init.prop_value +
+ (((event->mval[0] - inter->init.mval[0]) / ar->winx) * value_range)) * value_scale;
+
+
+ if (tweak_flag & WM_GIZMO_TWEAK_SNAP) {
+ const double snap = 0.1;
+ value_delta = (float)roundf((double)value_delta / snap) * snap;
+
+ }
+ if (tweak_flag & WM_GIZMO_TWEAK_PRECISE) {
+ value_delta *= 0.1f;
+ }
+ const float value_final = inter->init.prop_value + value_delta;
+
+ if (value_final != inter->prev.prop_value) {
+ /* set the property for the operator and call its modal function */
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, value_final);
+ }
+
+ {
+ ScrArea *sa = CTX_wm_area(C);
+ char str[64];
+ SNPRINTF(str, "%.4f", value_final);
+ ED_area_status_text(sa, str);
+ }
+ }
+
+ inter->prev.prop_value = value_final;
+ inter->prev.tweak_flag = tweak_flag;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+static int gizmo_value_invoke(
+ bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
+{
+ ValueInteraction *inter = MEM_callocN(sizeof(ValueInteraction), __func__);
+
+ inter->init.mval[0] = event->mval[0];
+ inter->init.mval[1] = event->mval[1];
+ inter->prev.prop_value = -FLT_MAX;
+
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ inter->init.prop_value = WM_gizmo_target_property_float_get(gz, gz_prop);
+ if (!WM_gizmo_target_property_float_range_get(gz, gz_prop, inter->range)) {
+ inter->range[0] = 0.0f;
+ inter->range[1] = 1.0f;
+ }
+ }
+
+ gz->interaction_data = inter;
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_value_exit(bContext *C, wmGizmo *gz, const bool cancel)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ED_area_status_text(sa, NULL);
+ if (cancel) {
+ ValueInteraction *inter = gz->interaction_data;
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, inter->init.prop_value);
+ }
+ }
+}
+
+static int gizmo_value_test_select(
+ bContext *UNUSED(C), wmGizmo *UNUSED(gz), const int UNUSED(mval[2]))
+{
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Value Gizmo API
+ *
+ * \{ */
+
+static void GIZMO_GT_value_2d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_value_2d";
+
+ /* api callbacks */
+ gzt->draw = gizmo_value_draw;
+ gzt->invoke = gizmo_value_invoke;
+ gzt->exit = gizmo_value_exit;
+ gzt->modal = gizmo_value_modal;
+ gzt->test_select = gizmo_value_test_select;
+
+ gzt->struct_size = sizeof(wmGizmo);
+
+ WM_gizmotype_target_property_def(gzt, "offset", PROP_FLOAT, 1);
+ /* Options: relative / absolute */
+}
+
+void ED_gizmotypes_value_2d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_value_2d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 3d5317b2ebd..cea2e5d4269 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../imbuf
../../gpu
../../makesdna
@@ -38,18 +39,26 @@ set(INC_SYS
)
set(SRC
+ annotate_draw.c
+ annotate_paint.c
drawgpencil.c
editaction_gpencil.c
+ gpencil_add_monkey.c
+ gpencil_add_stroke.c
gpencil_brush.c
gpencil_convert.c
gpencil_data.c
gpencil_edit.c
gpencil_interpolate.c
+ gpencil_primitive.c
gpencil_ops.c
gpencil_paint.c
+ gpencil_fill.c
gpencil_select.c
gpencil_undo.c
gpencil_utils.c
+ gpencil_old.c
+ gpencil_armature.c
gpencil_intern.h
)
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
new file mode 100644
index 00000000000..1ef7e3883da
--- /dev/null
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -0,0 +1,1134 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung, Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/annotate_draw.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_sys_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_polyfill_2d.h"
+
+#include "BLF_api.h"
+#include "BLT_translation.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+
+#include "WM_api.h"
+
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+#include "GPU_state.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_space_api.h"
+
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
+
+/* ************************************************** */
+/* GREASE PENCIL DRAWING */
+
+/* ----- General Defines ------ */
+/* flags for sflag */
+typedef enum eDrawStrokeFlags {
+ GP_DRAWDATA_NOSTATUS = (1 << 0), /* don't draw status info */
+ GP_DRAWDATA_ONLY3D = (1 << 1), /* only draw 3d-strokes */
+ GP_DRAWDATA_ONLYV2D = (1 << 2), /* only draw 'canvas' strokes */
+ GP_DRAWDATA_ONLYI2D = (1 << 3), /* only draw 'image' strokes */
+ GP_DRAWDATA_IEDITHACK = (1 << 4), /* special hack for drawing strokes in Image Editor (weird coordinates) */
+ GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */
+ GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */
+} eDrawStrokeFlags;
+
+
+/* ----- Tool Buffer Drawing ------ */
+
+/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
+static void gp_draw_stroke_buffer(
+ const tGPspoint *points, int totpoints, short thickness,
+ short dflag, short sflag, float ink[4])
+{
+ int draw_points = 0;
+
+ /* error checking */
+ if ((points == NULL) || (totpoints <= 0))
+ return;
+
+ /* check if buffer can be drawn */
+ if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
+ return;
+
+ if (sflag & GP_STROKE_ERASER) {
+ /* don't draw stroke at all! */
+ return;
+ }
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+
+ const tGPspoint *pt = points;
+
+ if (totpoints == 1) {
+ /* if drawing a single point, draw it larger */
+ GPU_point_size((float)(thickness + 2) * points->pressure);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ immUniformColor3fvAlpha(ink, ink[3]);
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2iv(pos, &pt->x);
+ }
+ else {
+ float oldpressure = points[0].pressure;
+
+ /* draw stroke curve */
+ GPU_line_width(max_ff(oldpressure * thickness, 1.0));
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints);
+
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
+ * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
+ */
+ if (fabsf(pt->pressure - oldpressure) > 0.2f) {
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ immVertex2iv(pos, &(pt - 1)->x);
+ }
+
+ immEnd();
+ draw_points = 0;
+
+ GPU_line_width(max_ff(pt->pressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1);
+
+ /* need to roll-back one point to ensure that there are no gaps in the stroke */
+ if (i != 0) {
+ immVertex2iv(pos, &(pt - 1)->x);
+ draw_points++;
+ }
+
+ oldpressure = pt->pressure; /* reset our threshold */
+ }
+
+ /* now the point we want */
+ immVertex2iv(pos, &pt->x);
+ draw_points++;
+ }
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ immVertex2iv(pos, &(pt - 1)->x);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
+/* --------- 2D Stroke Drawing Helpers --------- */
+/* change in parameter list */
+static void gp_calc_2d_stroke_fxy(const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
+{
+ if (sflag & GP_STROKE_2DSPACE) {
+ r_co[0] = pt[0];
+ r_co[1] = pt[1];
+ }
+ else if (sflag & GP_STROKE_2DIMAGE) {
+ const float x = (float)((pt[0] * winx) + offsx);
+ const float y = (float)((pt[1] * winy) + offsy);
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
+ else {
+ const float x = (float)(pt[0] / 100 * winx) + offsx;
+ const float y = (float)(pt[1] / 100 * winy) + offsy;
+
+ r_co[0] = x;
+ r_co[1] = y;
+ }
+}
+
+/* ----- Existing Strokes Drawing (3D and Point) ------ */
+
+/* draw a given stroke - just a single dot (only one point) */
+static void gp_draw_stroke_point(
+ const bGPDspoint *points, short thickness, short UNUSED(dflag), short sflag,
+ int offsx, int offsy, int winx, int winy, const float ink[4])
+{
+ const bGPDspoint *pt = points;
+
+ /* get final position using parent matrix */
+ float fpt[3];
+ copy_v3_v3(fpt, &pt->x);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ if (sflag & GP_STROKE_3DSPACE) {
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+
+ /* get 2D coordinates of point */
+ float co[3] = { 0.0f };
+ gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
+ copy_v3_v3(fpt, co);
+ }
+
+ /* set color */
+ immUniformColor3fvAlpha(ink, ink[3]);
+
+ /* set point thickness (since there's only one of these) */
+ immUniform1f("size", (float)(thickness + 2) * pt->pressure);
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, fpt);
+ immEnd();
+
+ immUnbindProgram();
+}
+
+/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
+static void gp_draw_stroke_3d(
+ const bGPDspoint *points, int totpoints, short thickness,
+ short UNUSED(sflag), const float ink[4], bool cyclic)
+{
+ float curpressure = points[0].pressure;
+ float cyclic_fpt[3];
+ int draw_points = 0;
+
+ /* if cyclic needs one vertex more */
+ int cyclic_add = 0;
+ if (cyclic) {
+ cyclic_add++;
+ }
+
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+
+ /* draw stroke curve */
+ GPU_line_width(max_ff(curpressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
+ * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
+ * Note: we want more visible levels of pressures when thickness is bigger.
+ */
+ if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
+ /* if the pressure changes before get at least 2 vertices, need to repeat last point to avoid assert in immEnd() */
+ if (draw_points < 2) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ }
+ immEnd();
+ draw_points = 0;
+
+ curpressure = pt->pressure;
+ GPU_line_width(max_ff(curpressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add);
+
+ /* need to roll-back one point to ensure that there are no gaps in the stroke */
+ if (i != 0) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ draw_points++;
+ }
+ }
+
+ /* now the point we want */
+ immVertex3fv(pos, &pt->x);
+ draw_points++;
+
+ if (cyclic && i == 0) {
+ /* save first point to use in cyclic */
+ copy_v3_v3(cyclic_fpt, &pt->x);
+ }
+ }
+
+ if (cyclic) {
+ /* draw line to first point to complete the cycle */
+ immVertex3fv(pos, cyclic_fpt);
+ draw_points++;
+ }
+
+ /* if less of two points, need to repeat last point to avoid assert in immEnd() */
+ if (draw_points < 2) {
+ const bGPDspoint *pt2 = pt - 1;
+ immVertex3fv(pos, &pt2->x);
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
+/* ----- Fancy 2D-Stroke Drawing ------ */
+
+/* draw a given stroke in 2d */
+static void gp_draw_stroke_2d(
+ const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
+ int offsx, int offsy, int winx, int winy, const float ink[4])
+{
+ /* otherwise thickness is twice that of the 3D view */
+ float thickness = (float)thickness_s * 0.5f;
+
+ /* strokes in Image Editor need a scale factor, since units there are not pixels! */
+ float scalefac = 1.0f;
+ if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
+ scalefac = 0.001f;
+ }
+
+ /* tessellation code - draw stroke as series of connected quads (triangle strips in fact) with connection
+ * edges rotated to minimize shrinking artifacts, and rounded endcaps
+ */
+ {
+ const bGPDspoint *pt1, *pt2;
+ float s0[2], s1[2]; /* segment 'center' points */
+ float pm[2]; /* normal from previous segment. */
+ int i;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(ink, ink[3]);
+ immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
+
+ /* get x and y coordinates from first point */
+ gp_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, s0);
+
+ for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
+ float t0[2], t1[2]; /* tessellated coordinates */
+ float m1[2], m2[2]; /* gradient and normal */
+ float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
+ float pthick; /* thickness at segment point */
+
+ /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */
+ gp_calc_2d_stroke_fxy(&pt2->x, sflag, offsx, offsy, winx, winy, s1);
+
+ /* calculate gradient and normal - 'angle'=(ny/nx) */
+ m1[1] = s1[1] - s0[1];
+ m1[0] = s1[0] - s0[0];
+ normalize_v2(m1);
+ m2[1] = -m1[0];
+ m2[0] = m1[1];
+
+ /* always use pressure from first point here */
+ pthick = (pt1->pressure * thickness * scalefac);
+
+ /* if the first segment, start of segment is segment's normal */
+ if (i == 0) {
+ /* draw start cap first
+ * - make points slightly closer to center (about halfway across)
+ */
+ mt[0] = m2[0] * pthick * 0.5f;
+ mt[1] = m2[1] * pthick * 0.5f;
+ sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
+ sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
+
+ t0[0] = sc[0] - mt[0];
+ t0[1] = sc[1] - mt[1];
+ t1[0] = sc[0] + mt[0];
+ t1[1] = sc[1] + mt[1];
+
+ /* First two points of cap. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+
+ /* calculate points for start of segment */
+ mt[0] = m2[0] * pthick;
+ mt[1] = m2[1] * pthick;
+
+ t0[0] = s0[0] - mt[0];
+ t0[1] = s0[1] - mt[1];
+ t1[0] = s0[0] + mt[0];
+ t1[1] = s0[1] + mt[1];
+
+ /* Last two points of start cap (and first two points of first segment). */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+ /* if not the first segment, use bisector of angle between segments */
+ else {
+ float mb[2]; /* bisector normal */
+ float athick, dfac; /* actual thickness, difference between thicknesses */
+
+ /* calculate gradient of bisector (as average of normals) */
+ mb[0] = (pm[0] + m2[0]) / 2;
+ mb[1] = (pm[1] + m2[1]) / 2;
+ normalize_v2(mb);
+
+ /* calculate gradient to apply
+ * - as basis, use just pthick * bisector gradient
+ * - if cross-section not as thick as it should be, add extra padding to fix it
+ */
+ mt[0] = mb[0] * pthick;
+ mt[1] = mb[1] * pthick;
+ athick = len_v2(mt);
+ dfac = pthick - (athick * 2);
+
+ if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
+ mt[0] += (mb[0] * dfac);
+ mt[1] += (mb[1] * dfac);
+ }
+
+ /* calculate points for start of segment */
+ t0[0] = s0[0] - mt[0];
+ t0[1] = s0[1] - mt[1];
+ t1[0] = s0[0] + mt[0];
+ t1[1] = s0[1] + mt[1];
+
+ /* Last two points of previous segment, and first two points of current segment. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+
+ /* if last segment, also draw end of segment (defined as segment's normal) */
+ if (i == totpoints - 2) {
+ /* for once, we use second point's pressure (otherwise it won't be drawn) */
+ pthick = (pt2->pressure * thickness * scalefac);
+
+ /* calculate points for end of segment */
+ mt[0] = m2[0] * pthick;
+ mt[1] = m2[1] * pthick;
+
+ t0[0] = s1[0] - mt[0];
+ t0[1] = s1[1] - mt[1];
+ t1[0] = s1[0] + mt[0];
+ t1[1] = s1[1] + mt[1];
+
+ /* Last two points of last segment (and first two points of end cap). */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+
+ /* draw end cap as last step
+ * - make points slightly closer to center (about halfway across)
+ */
+ mt[0] = m2[0] * pthick * 0.5f;
+ mt[1] = m2[1] * pthick * 0.5f;
+ sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
+ sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
+
+ t0[0] = sc[0] - mt[0];
+ t0[1] = sc[1] - mt[1];
+ t1[0] = sc[0] + mt[0];
+ t1[1] = sc[1] + mt[1];
+
+ /* Last two points of end cap. */
+ immVertex2fv(pos, t0);
+ immVertex2fv(pos, t1);
+ }
+
+ /* store computed point2 coordinates as point1 ones of next segment. */
+ copy_v2_v2(s0, s1);
+ /* store stroke's 'natural' normal for next stroke to use */
+ copy_v2_v2(pm, m2);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
+}
+
+/* ----- Strokes Drawing ------ */
+
+/* Helper for doing all the checks on whether a stroke can be drawn */
+static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
+{
+ /* skip stroke if it isn't in the right display space for this drawing context */
+ /* 1) 3D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
+ return false;
+
+ /* 2) Screen Space 2D Strokes */
+ if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
+ return false;
+
+ /* 3) Image Space (2D) */
+ if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+ if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
+ return false;
+
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1))
+ return false;
+
+ /* stroke can be drawn */
+ return true;
+}
+
+/* draw a set of strokes */
+static void gp_draw_strokes(
+ bGPdata *UNUSED(gpd), bGPDlayer *UNUSED(gpl), const bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
+ int dflag, short lthick, const float color[4])
+{
+ GPU_enable_program_point_size();
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, dflag) == false) {
+ continue;
+ }
+
+ /* check which stroke-drawer to use */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
+ int mask_orig = 0;
+
+ if (no_xray) {
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
+ glDepthMask(0);
+ GPU_depth_test(true);
+
+ /* first arg is normally rv3d->dist, but this isn't
+ * available here and seems to work quite well without */
+ bglPolygonOffset(1.0f, 1.0f);
+ }
+
+ /* 3D Lines - OpenGL primitives-based */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
+ }
+ else {
+ gp_draw_stroke_3d(
+ gps->points, gps->totpoints, lthick, gps->flag,
+ color, gps->flag & GP_STROKE_CYCLIC);
+ }
+
+ if (no_xray) {
+ glDepthMask(mask_orig);
+ GPU_depth_test(false);
+
+ bglPolygonOffset(0.0, 0.0);
+ }
+ }
+ else {
+ /* 2D Strokes... */
+ if (gps->totpoints == 1) {
+ gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
+ }
+ else {
+ gp_draw_stroke_2d(
+ gps->points, gps->totpoints, lthick, dflag, gps->flag,
+ offsx, offsy, winx, winy, color);
+ }
+ }
+ }
+
+ GPU_disable_program_point_size();
+}
+
+/* Draw selected verts for strokes being edited */
+static void gp_draw_strokes_edit(
+ bGPdata *gpd, bGPDlayer *gpl, const bGPDframe *gpf,
+ int offsx, int offsy, int winx, int winy,
+ short dflag, short UNUSED(lflag), float alpha)
+{
+ /* if alpha 0 do not draw */
+ if (alpha == 0.0f)
+ return;
+
+ const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
+ int mask_orig = 0;
+
+ /* set up depth masks... */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ if (no_xray) {
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
+ glDepthMask(0);
+ GPU_depth_test(true);
+
+ /* first arg is normally rv3d->dist, but this isn't
+ * available here and seems to work quite well without */
+ bglPolygonOffset(1.0f, 1.0f);
+ }
+ }
+
+ GPU_enable_program_point_size();
+
+ /* draw stroke verts */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if (gp_can_draw_stroke(gps, dflag) == false)
+ continue;
+
+ /* Optimisation: only draw points for selected strokes
+ * We assume that selected points can only occur in
+ * strokes that are selected too.
+ */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ /* Get size of verts:
+ * - The selected state needs to be larger than the unselected state so that
+ * they stand out more.
+ * - We use the theme setting for size of the unselected verts
+ */
+ float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
+ float vsize;
+ if ((int)bsize > 8) {
+ vsize = 10.0f;
+ bsize = 8.0f;
+ }
+ else {
+ vsize = bsize + 2;
+ }
+
+ float selectColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
+ selectColor[3] = alpha;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos; /* specified later */
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+ else {
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+
+ immBegin(GPU_PRIM_POINTS, gps->totpoints);
+
+ /* Draw start and end point differently if enabled stroke direction hint */
+ bool show_direction_hint = (gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
+
+ /* Draw all the stroke points (selected or not) */
+ bGPDspoint *pt = gps->points;
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
+ /* size and color first */
+ if (show_direction_hint && i == 0) {
+ /* start point in green bigger */
+ immAttr3f(color, 0.0f, 1.0f, 0.0f);
+ immAttr1f(size, vsize + 4);
+ }
+ else if (show_direction_hint && (i == gps->totpoints - 1)) {
+ /* end point in red smaller */
+ immAttr3f(color, 1.0f, 0.0f, 0.0f);
+ immAttr1f(size, vsize + 1);
+ }
+ else if (pt->flag & GP_SPOINT_SELECT) {
+ immAttr3fv(color, selectColor);
+ immAttr1f(size, vsize);
+ }
+ else {
+ immAttr3fv(color, gpl->color);
+ immAttr1f(size, bsize);
+ }
+
+ /* then position */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ immVertex3fv(pos, &pt->x);
+ }
+ else {
+ float co[2];
+ gp_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
+
+ GPU_disable_program_point_size();
+
+ /* clear depth mask */
+ if (dflag & GP_DRAWDATA_ONLY3D) {
+ if (no_xray) {
+ glDepthMask(mask_orig);
+ GPU_depth_test(false);
+
+ bglPolygonOffset(0.0, 0.0);
+#if 0
+ glDisable(GL_POLYGON_OFFSET_LINE);
+ glPolygonOffset(0, 0);
+#endif
+ }
+ }
+}
+
+/* ----- General Drawing ------ */
+/* draw onion-skinning for a layer */
+static void gp_draw_onionskins(
+ bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
+ int UNUSED(cfra), int dflag)
+{
+ const float alpha = 1.0f;
+ float color[4];
+
+ /* 1) Draw Previous Frames First */
+ copy_v3_v3(color, gpl->gcolor_prev);
+
+ if (gpl->gstep > 0) {
+ bGPDframe *gf;
+ float fac;
+
+ /* draw previous frames first */
+ for (gf = gpf->prev; gf; gf = gf->prev) {
+ /* check if frame is drawable */
+ if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
+ /* alpha decreases with distance from curframe index */
+ fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
+ color[3] = alpha * fac * 0.66f;
+ gp_draw_strokes(
+ gpd, gpl, gf, offsx, offsy, winx, winy, dflag,
+ gpl->thickness, color);
+ }
+ else
+ break;
+ }
+ }
+ else if (gpl->gstep == 0) {
+ /* draw the strokes for the ghost frames (at half of the alpha set by user) */
+ if (gpf->prev) {
+ color[3] = (alpha / 7);
+ gp_draw_strokes(
+ gpd, gpl, gpf->prev, offsx, offsy, winx, winy, dflag,
+ gpl->thickness, color);
+ }
+ }
+ else {
+ /* don't draw - disabled */
+ }
+
+
+ /* 2) Now draw next frames */
+ copy_v3_v3(color, gpl->gcolor_next);
+
+ if (gpl->gstep_next > 0) {
+ bGPDframe *gf;
+ float fac;
+
+ /* now draw next frames */
+ for (gf = gpf->next; gf; gf = gf->next) {
+ /* check if frame is drawable */
+ if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
+ /* alpha decreases with distance from curframe index */
+ fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
+ color[3] = alpha * fac * 0.66f;
+ gp_draw_strokes(
+ gpd, gpl, gf, offsx, offsy, winx, winy, dflag,
+ gpl->thickness, color);
+ }
+ else
+ break;
+ }
+ }
+ else if (gpl->gstep_next == 0) {
+ /* draw the strokes for the ghost frames (at half of the alpha set by user) */
+ if (gpf->next) {
+ color[3] = (alpha / 4);
+ gp_draw_strokes(
+ gpd, gpl, gpf->next, offsx, offsy, winx, winy, dflag,
+ gpl->thickness, color);
+ }
+ }
+ else {
+ /* don't draw - disabled */
+ }
+
+}
+
+/* loop over gpencil data layers, drawing them */
+static void gp_draw_data_layers(
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, float alpha)
+{
+ float ink[4];
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* verify never thickness is less than 1 */
+ CLAMP_MIN(gpl->thickness, 1.0f);
+ short lthick = gpl->thickness;
+
+ /* apply layer opacity */
+ copy_v3_v3(ink, gpl->color);
+ ink[3] = gpl->opacity;
+
+ /* don't draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* get frame to draw */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
+ if (gpf == NULL)
+ continue;
+
+ /* set basic stroke thickness */
+ GPU_line_width(lthick);
+
+ /* Add layer drawing settings to the set of "draw flags"
+ * NOTE: If the setting doesn't apply, it *must* be cleared,
+ * as dflag's carry over from the previous layer
+ */
+
+ /* xray... */
+ SET_FLAG_FROM_TEST(dflag, gpl->flag & GP_LAYER_NO_XRAY, GP_DRAWDATA_NO_XRAY);
+
+ /* Draw 'onionskins' (frame left + right) */
+ if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
+ gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag);
+ }
+
+ /* draw the strokes already in active frame */
+ gp_draw_strokes(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, lthick, ink);
+
+ /* Draw verts of selected strokes
+ * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
+ * - locked layers can't be edited, so there's no point showing these verts
+ * as they will have no bearings on what gets edited
+ * - only show when in editmode, since operators shouldn't work otherwise
+ * (NOTE: doing it this way means that the toggling editmode shows visible change immediately)
+ */
+ /* XXX: perhaps we don't want to show these when users are drawing... */
+ if ((G.f & G_RENDER_OGL) == 0 &&
+ (gpl->flag & GP_LAYER_LOCKED) == 0 &&
+ (gpd->flag & GP_DATA_STROKE_EDITMODE))
+ {
+ gp_draw_strokes_edit(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, alpha);
+ }
+
+ /* Check if may need to draw the active stroke cache, only if this layer is the active layer
+ * that is being edited. (Stroke buffer is currently stored in gp-data)
+ */
+ if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
+ (gpf->flag & GP_FRAME_PAINT))
+ {
+ /* Buffer stroke needs to be drawn with a different linestyle
+ * to help differentiate them from normal strokes.
+ *
+ * It should also be noted that sbuffer contains temporary point types
+ * i.e. tGPspoints NOT bGPDspoints
+ */
+ gp_draw_stroke_buffer(
+ gpd->runtime.sbuffer,
+ gpd->runtime.sbuffer_size, lthick,
+ dflag, gpd->runtime.sbuffer_sflag, ink);
+ }
+ }
+}
+
+/* draw a short status message in the top-right corner */
+static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar)
+{
+ rcti rect;
+
+ /* Cannot draw any status text when drawing OpenGL Renders */
+ if (G.f & G_RENDER_OGL)
+ return;
+
+ /* Get bounds of region - Necessary to avoid problems with region overlap */
+ ED_region_visible_rect(ar, &rect);
+
+ /* for now, this should only be used to indicate when we are in stroke editmode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ const char *printable = IFACE_("GPencil Stroke Editing");
+ float printable_size[2];
+
+ int font_id = BLF_default();
+
+ BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+
+ int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
+ int yco = (rect.ymax - U.widget_unit);
+
+ /* text label */
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
+#ifdef WITH_INTERNATIONAL
+ BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#else
+ BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+#endif
+
+ /* grease pencil icon... */
+ // XXX: is this too intrusive?
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ xco -= U.widget_unit;
+ yco -= (int)printable_size[1] / 2;
+
+ UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
+
+ GPU_blend(false);
+ }
+}
+
+/* draw grease-pencil datablock */
+static void gp_draw_data(
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, float alpha)
+{
+ /* turn on smooth lines (i.e. anti-aliasing) */
+ GPU_line_smooth(true);
+
+ /* turn on alpha-blending */
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ /* draw! */
+ gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+
+ /* turn off alpha blending, then smooth lines */
+ GPU_blend(false); // alpha blending
+ GPU_line_smooth(false); // smooth lines
+}
+
+/* if we have strokes for scenes (3d view)/clips (movie clip editor)
+ * and objects/tracks, multiple data blocks have to be drawn */
+static void gp_draw_data_all(
+ Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, const char spacetype)
+{
+ bGPdata *gpd_source = NULL;
+ float alpha = 1.0f;
+
+ if (scene) {
+ if (spacetype == SPACE_VIEW3D) {
+ gpd_source = (scene->gpd ? scene->gpd : NULL);
+ }
+ else if (spacetype == SPACE_CLIP && scene->clip) {
+ /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
+ gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
+ }
+
+ if (gpd_source) {
+ gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ }
+ }
+
+ /* scene/clip data has already been drawn, only object/track data is drawn here
+ * if gpd_source == gpd, we don't have any object/track data and we can skip */
+ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
+ gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ }
+}
+
+/* ----- Grease Pencil Sketches Drawing API ------ */
+
+/* ............................
+ * XXX
+ * We need to review the calls below, since they may be/are not that suitable for
+ * the new ways that we intend to be drawing data...
+ * ............................ */
+
+/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
+void ED_gpencil_draw_2dimage(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+
+ int offsx, offsy, sizex, sizey;
+ int dflag = GP_DRAWDATA_NOSTATUS;
+
+ bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ if (gpd == NULL) return;
+
+ /* calculate rect */
+ switch (sa->spacetype) {
+ case SPACE_IMAGE: /* image */
+ case SPACE_CLIP: /* clip */
+ {
+ /* just draw using standard scaling (settings here are currently ignored anyways) */
+ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
+
+ dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
+ break;
+ }
+ case SPACE_SEQ: /* sequence */
+ {
+ /* just draw using standard scaling (settings here are currently ignored anyways) */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
+ * and everything moved to standard View2d
+ */
+ dflag |= GP_DRAWDATA_ONLYV2D;
+ break;
+ }
+ default: /* for spacetype not yet handled */
+ offsx = 0;
+ offsy = 0;
+ sizex = ar->winx;
+ sizey = ar->winy;
+
+ dflag |= GP_DRAWDATA_ONLYI2D;
+ break;
+ }
+
+ if (ED_screen_animation_playing(wm)) {
+ /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
+ * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
+ */
+ dflag |= GP_DRAWDATA_NO_ONIONS;
+ }
+
+ /* draw it! */
+ gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
+}
+
+/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
+ * Note: this gets called twice - first time with onlyv2d=true to draw 'canvas' strokes,
+ * second time with onlyv2d=false for screen-aligned strokes */
+void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ int dflag = 0;
+
+ /* check that we have grease-pencil stuff to draw */
+ if (sa == NULL) return;
+ bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX
+ if (gpd == NULL) return;
+
+ /* special hack for Image Editor */
+ /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
+ if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
+ dflag |= GP_DRAWDATA_IEDITHACK;
+
+ /* draw it! */
+ if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
+ if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS;
+
+ gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
+
+ /* draw status text (if in screen/pixel-space) */
+ if (!onlyv2d) {
+ gp_draw_status_text(gpd, ar);
+ }
+}
+
+
+/* draw annotations sketches to specified 3d-view assuming that matrices are already set correctly
+ * Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
+ * second time with only3d=false for screen-aligned strokes */
+void ED_gpencil_draw_view3d_annotations(
+ Scene *scene, struct Depsgraph *depsgraph,
+ View3D *v3d, ARegion *ar,
+ bool only3d)
+{
+ int dflag = 0;
+ RegionView3D *rv3d = ar->regiondata;
+ int offsx, offsy, winx, winy;
+
+ /* check that we have grease-pencil stuff to draw */
+ /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data */
+ bGPdata *gpd = scene->gpd;
+ if (gpd == NULL) return;
+
+ /* when rendering to the offscreen buffer we don't want to
+ * deal with the camera border, otherwise map the coords to the camera border. */
+ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
+ rctf rectf;
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
+
+ offsx = round_fl_to_int(rectf.xmin);
+ offsy = round_fl_to_int(rectf.ymin);
+ winx = round_fl_to_int(rectf.xmax - rectf.xmin);
+ winy = round_fl_to_int(rectf.ymax - rectf.ymin);
+ }
+ else {
+ offsx = 0;
+ offsy = 0;
+ winx = ar->winx;
+ winy = ar->winy;
+ }
+
+ /* set flags */
+ if (only3d) {
+ /* 3D strokes/3D space:
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ /* don't draw status text when "only render" flag is set */
+ dflag |= GP_DRAWDATA_NOSTATUS;
+ }
+
+ /* draw it! */
+ gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+}
+
+/* ************************************************** */
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
new file mode 100644
index 00000000000..c5dcb51ff6e
--- /dev/null
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -0,0 +1,2327 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008/2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/annotate_paint.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_geom.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+#include "BKE_tracking.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_clip.h"
+
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "gpencil_intern.h"
+
+/* ******************************************* */
+/* 'Globals' and Defines */
+
+/* values for tGPsdata->status */
+typedef enum eGPencil_PaintStatus {
+ GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
+ GP_STATUS_PAINTING, /* a stroke is in progress */
+ GP_STATUS_ERROR, /* something wasn't correctly set up */
+ GP_STATUS_DONE /* painting done */
+} eGPencil_PaintStatus;
+
+/* Return flags for adding points to stroke buffer */
+typedef enum eGP_StrokeAdd_Result {
+ GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
+ GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
+ GP_STROKEADD_NORMAL, /* point was successfully added */
+ GP_STROKEADD_FULL /* cannot add any more points to buffer */
+} eGP_StrokeAdd_Result;
+
+/* Runtime flags */
+typedef enum eGPencil_PaintFlags {
+ GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
+ GP_PAINTFLAG_STROKEADDED = (1 << 1),
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
+ GP_PAINTFLAG_SELECTMASK = (1 << 3),
+} eGPencil_PaintFlags;
+
+
+/* Temporary 'Stroke' Operation data
+ * "p" = op->customdata
+ */
+typedef struct tGPsdata {
+ Main *bmain;
+ Scene *scene; /* current scene from context */
+ struct Depsgraph *depsgraph;
+
+ wmWindow *win; /* window where painting originated */
+ ScrArea *sa; /* area where painting originated */
+ ARegion *ar; /* region where painting originated */
+ View2D *v2d; /* needed for GP_STROKE_2DSPACE */
+ rctf *subrect; /* for using the camera rect within the 3d view */
+ rctf subrect_data;
+
+ GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */
+
+ PointerRNA ownerPtr; /* pointer to owner of gp-datablock */
+ bGPdata *gpd; /* gp-datablock layer comes from */
+ bGPDlayer *gpl; /* layer we're working on */
+ bGPDframe *gpf; /* frame we're working on */
+
+ char *align_flag; /* projection-mode flags (toolsettings - eGPencil_Placement_Flags) */
+
+ eGPencil_PaintStatus status; /* current status of painting */
+ eGPencil_PaintModes paintmode; /* mode for painting */
+ eGPencil_PaintFlags flags; /* flags that can get set during runtime (eGPencil_PaintFlags) */
+
+ short radius; /* radius of influence for eraser */
+
+ int mval[2]; /* current mouse-position */
+ int mvalo[2]; /* previous recorded mouse-position */
+
+ float pressure; /* current stylus pressure */
+ float opressure; /* previous stylus pressure */
+
+ /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
+ * float (and its 7 digits precision) is definitively not enough here!
+ * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least.
+ */
+ double inittime; /* Used when converting to path */
+ double curtime; /* Used when converting to path */
+ double ocurtime; /* Used when converting to path */
+
+ float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space
+ * to region space */
+ float mat[4][4];
+
+ float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
+
+ void *erasercursor; /* radial cursor data for drawing eraser */
+
+ short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
+
+ short keymodifier; /* key used for invoking the operator */
+} tGPsdata;
+
+/* ------ */
+
+/* Macros for accessing sensitivity thresholds... */
+/* minimum number of pixels mouse should move before new point created */
+#define MIN_MANHATTEN_PX (U.gp_manhattendist)
+/* minimum length of new segment before new point can be added */
+#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
+
+static bool gp_stroke_added_check(tGPsdata *p)
+{
+ return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
+}
+
+static void gp_stroke_added_enable(tGPsdata *p)
+{
+ BLI_assert(p->gpf->strokes.last != NULL);
+ p->flags |= GP_PAINTFLAG_STROKEADDED;
+}
+
+/* ------ */
+/* Forward defines for some functions... */
+
+static void gp_session_validatebuffer(tGPsdata *p);
+
+/* ******************************************* */
+/* Context Wrangling... */
+
+/* check if context is suitable for drawing */
+static bool gpencil_draw_poll(bContext *C)
+{
+ if (ED_operator_regionactive(C)) {
+ /* check if current context can support GPencil data */
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ /* check if Grease Pencil isn't already running */
+ if (ED_gpencil_session_active() == 0)
+ return 1;
+ else
+ CTX_wm_operator_poll_msg_set(C, "Annotation operator is already active");
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ }
+
+ return 0;
+}
+
+/* check if projecting strokes into 3d-geometry in the 3D-View */
+static bool gpencil_project_check(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
+}
+
+/* ******************************************* */
+/* Calculations/Conversions */
+
+/* Utilities --------------------------------- */
+
+/* get the reference point for stroke-point conversions */
+static void gp_get_3d_reference(tGPsdata *p, float vec[3])
+{
+ const float *fp = p->scene->cursor.location;
+
+ /* use 3D-cursor */
+ copy_v3_v3(vec, fp);
+}
+
+/* Stroke Editing ---------------------------- */
+
+/* check if the current mouse position is suitable for adding a new point */
+static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
+{
+ int dx = abs(mval[0] - pmval[0]);
+ int dy = abs(mval[1] - pmval[1]);
+
+ /* if buffer is empty, just let this go through (i.e. so that dots will work) */
+ if (p->gpd->runtime.sbuffer_size == 0)
+ return true;
+
+ /* check if mouse moved at least certain distance on both axes (best case)
+ * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
+ */
+ else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX))
+ return true;
+
+ /* check if the distance since the last point is significant enough
+ * - prevents points being added too densely
+ * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though
+ */
+ else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX)
+ return true;
+
+ /* mouse 'didn't move' */
+ else
+ return false;
+}
+
+/* convert screen-coordinates to buffer-coordinates */
+static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth)
+{
+ bGPdata *gpd = p->gpd;
+
+ /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
+ if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval, out, 0, depth))) {
+ /* projecting onto 3D-Geometry
+ * - nothing more needs to be done here, since view_autodist_simple() has already done it
+ */
+ }
+ else {
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float mval_f[2] = {UNPACK2(mval)};
+ float zfac;
+
+ /* Current method just converts each point in screen-coordinates to
+ * 3D-coordinates using the 3D-cursor as reference. In general, this
+ * works OK, but it could of course be improved.
+ *
+ * TODO:
+ * - investigate using nearest point(s) on a previous stroke as
+ * reference point instead or as offset, for easier stroke matching
+ */
+
+ gp_get_3d_reference(p, rvec);
+ zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(out, rvec, dvec);
+ }
+ else {
+ zero_v3(out);
+ }
+ }
+ }
+
+ /* 2d - on 'canvas' (assume that p->v2d is set) */
+ else if ((gpd->runtime.sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
+ UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]);
+ mul_v3_m4v3(out, p->imat, out);
+ }
+
+ /* 2d - relative to screen (viewport area) */
+ else {
+ if (p->subrect == NULL) { /* normal 3D view */
+ out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100;
+ out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100;
+ }
+ else { /* camera view, use subrect */
+ out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
+ out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
+ }
+ }
+}
+
+/* add current stroke-point to buffer (returns whether point was successfully added) */
+static short gp_stroke_addpoint(
+ tGPsdata *p, const int mval[2], float pressure, double curtime)
+{
+ bGPdata *gpd = p->gpd;
+ tGPspoint *pt;
+ ToolSettings *ts = p->scene->toolsettings;
+
+ /* check painting mode */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ /* straight lines only - i.e. only store start and end point in buffer */
+ if (gpd->runtime.sbuffer_size == 0) {
+ /* first point in buffer (start point) */
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
+
+ /* store settings */
+ copy_v2_v2_int(&pt->x, mval);
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* increment buffer size */
+ gpd->runtime.sbuffer_size++;
+ }
+ else {
+ /* just reset the endpoint to the latest value
+ * - assume that pointers for this are always valid...
+ */
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
+
+ /* store settings */
+ copy_v2_v2_int(&pt->x, mval);
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
+ gpd->runtime.sbuffer_size = 2;
+ }
+
+ /* can keep carrying on this way :) */
+ return GP_STROKEADD_NORMAL;
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
+ /* check if still room in buffer */
+ if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_OVERFLOW;
+
+ /* get pointer to destination point */
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
+
+ /* store settings */
+ copy_v2_v2_int(&pt->x, mval);
+ pt->pressure = pressure;
+ pt->strength = 1.0f; /* unused for annotations, but initialise for easier conversions to GP Object */
+
+ /* point time */
+ pt->time = (float)(curtime - p->inittime);
+
+ /* increment counters */
+ gpd->runtime.sbuffer_size++;
+
+ /* check if another operation can still occur */
+ if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX)
+ return GP_STROKEADD_FULL;
+ else
+ return GP_STROKEADD_NORMAL;
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* get pointer to destination point */
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
+
+ /* store settings */
+ copy_v2_v2_int(&pt->x, mval);
+ pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */
+ pt->strength = 1.0f;
+ pt->time = (float)(curtime - p->inittime);
+
+ /* if there's stroke for this poly line session add (or replace last) point
+ * to stroke. This allows to draw lines more interactively (see new segment
+ * during mouse slide, e.g.)
+ */
+ if (gp_stroke_added_check(p)) {
+ bGPDstroke *gps = p->gpf->strokes.last;
+ bGPDspoint *pts;
+
+ /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
+ if (gpd->runtime.sbuffer_size == 0) {
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ gps->totpoints++;
+ }
+
+ pts = &gps->points[gps->totpoints - 1];
+
+ /* special case for poly lines: normally,
+ * depth is needed only when creating new stroke from buffer,
+ * but poly lines are converting to stroke instantly,
+ * so initialize depth buffer before converting coordinates
+ */
+ if (gpencil_project_check(p)) {
+ View3D *v3d = p->sa->spacedata.first;
+
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(
+ p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ }
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+
+ /* copy pressure and time */
+ pts->pressure = pt->pressure;
+ pts->strength = pt->strength;
+ pts->time = pt->time;
+
+ /* force fill recalc */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
+
+ /* increment counters */
+ if (gpd->runtime.sbuffer_size == 0)
+ gpd->runtime.sbuffer_size++;
+
+ return GP_STROKEADD_NORMAL;
+ }
+
+ /* return invalid state for now... */
+ return GP_STROKEADD_INVALID;
+}
+
+/* simplify a stroke (in buffer) before storing it
+ * - applies a reverse Chaikin filter
+ * - code adapted from etch-a-ton branch
+ */
+static void gp_stroke_simplify(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ tGPspoint *old_points = (tGPspoint *)gpd->runtime.sbuffer;
+ short num_points = gpd->runtime.sbuffer_size;
+ short flag = gpd->runtime.sbuffer_sflag;
+ short i, j;
+
+ /* only simplify if simplification is enabled, and we're not doing a straight line */
+ if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT))
+ return;
+
+ /* don't simplify if less than 4 points in buffer */
+ if ((num_points <= 4) || (old_points == NULL))
+ return;
+
+ /* clear buffer (but don't free mem yet) so that we can write to it
+ * - firstly set sbuffer to NULL, so a new one is allocated
+ * - secondly, reset flag after, as it gets cleared auto
+ */
+ gpd->runtime.sbuffer = NULL;
+ gp_session_validatebuffer(p);
+ gpd->runtime.sbuffer_sflag = flag;
+
+/* macro used in loop to get position of new point
+ * - used due to the mixture of datatypes in use here
+ */
+#define GP_SIMPLIFY_AVPOINT(offs, sfac) \
+ { \
+ co[0] += (float)(old_points[offs].x * sfac); \
+ co[1] += (float)(old_points[offs].y * sfac); \
+ pressure += old_points[offs].pressure * sfac; \
+ time += old_points[offs].time * sfac; \
+ } (void)0
+
+ /* XXX Here too, do not lose start and end points! */
+ gp_stroke_addpoint(p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time);
+ for (i = 0, j = 0; i < num_points; i++) {
+ if (i - j == 3) {
+ float co[2], pressure, time;
+ int mco[2];
+
+ /* initialize values */
+ co[0] = 0.0f;
+ co[1] = 0.0f;
+ pressure = 0.0f;
+ time = 0.0f;
+
+ /* using macro, calculate new point */
+ GP_SIMPLIFY_AVPOINT(j, -0.25f);
+ GP_SIMPLIFY_AVPOINT(j + 1, 0.75f);
+ GP_SIMPLIFY_AVPOINT(j + 2, 0.75f);
+ GP_SIMPLIFY_AVPOINT(j + 3, -0.25f);
+
+ /* set values for adding */
+ mco[0] = (int)co[0];
+ mco[1] = (int)co[1];
+
+ /* ignore return values on this... assume to be ok for now */
+ gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time);
+
+ j += 2;
+ }
+ }
+ gp_stroke_addpoint(
+ p, &old_points[num_points - 1].x, old_points[num_points - 1].pressure,
+ p->inittime + (double)old_points[num_points - 1].time);
+
+ /* free old buffer */
+ MEM_freeN(old_points);
+}
+
+/* make a new stroke from the buffer data */
+static void gp_stroke_newfrombuffer(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ bGPDlayer *gpl = p->gpl;
+ bGPDstroke *gps;
+ bGPDspoint *pt;
+ tGPspoint *ptc;
+ ToolSettings *ts = p->scene->toolsettings;
+
+ int i, totelem;
+ /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
+ int depth_margin = (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
+
+ /* get total number of points to allocate space for
+ * - drawing straight-lines only requires the endpoints
+ */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
+ totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
+ else
+ totelem = gpd->runtime.sbuffer_size;
+
+ /* exit with error if no valid points from this stroke */
+ if (totelem == 0) {
+ if (G.debug & G_DEBUG)
+ printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->runtime.sbuffer_size);
+ return;
+ }
+
+ /* special case for poly line -- for already added stroke during session
+ * coordinates are getting added to stroke immediately to allow more
+ * interactive behavior
+ */
+ if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ if (gp_stroke_added_check(p)) {
+ return;
+ }
+ }
+
+ /* allocate memory for a new stroke */
+ gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+
+ /* copy appropriate settings for stroke */
+ gps->totpoints = totelem;
+ gps->thickness = gpl->thickness;
+ gps->flag = gpd->runtime.sbuffer_sflag;
+ gps->inittime = p->inittime;
+
+ /* enable recalculation flag by default (only used if hq fill) */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* allocate enough memory for a continuous array for storage points */
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->tot_triangles = 0;
+
+ /* set pointer to first non-initialized point */
+ pt = gps->points + (gps->totpoints - totelem);
+
+ /* copy points from the buffer to the stroke */
+ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ /* straight lines only -> only endpoints */
+ {
+ /* first point */
+ ptc = gpd->runtime.sbuffer;
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+
+ /* copy pressure and time */
+ pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt->time = ptc->time;
+
+ pt++;
+ }
+
+ if (totelem == 2) {
+ /* last point if applicable */
+ ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+
+ /* copy pressure and time */
+ pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt->time = ptc->time;
+ }
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* first point */
+ ptc = gpd->runtime.sbuffer;
+
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+
+ /* copy pressure and time */
+ pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ pt->time = ptc->time;
+ }
+ else {
+ float *depth_arr = NULL;
+
+ /* get an array of depths, far depths are blended */
+ if (gpencil_project_check(p)) {
+ int mval[2], mval_prev[2] = { 0 };
+ int interp_depth = 0;
+ int found_depth = 0;
+
+ depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
+
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
+ copy_v2_v2_int(mval, &ptc->x);
+
+ if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
+ {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+
+ copy_v2_v2_int(mval_prev, mval);
+ }
+
+ if (found_depth == false) {
+ /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--)
+ depth_arr[i] = 0.9999f;
+ }
+ else {
+ if (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
+ /* remove all info between the valid endpoints */
+ int first_valid = 0;
+ int last_valid = 0;
+
+ for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ first_valid = i;
+
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ last_valid = i;
+
+ /* invalidate non-endpoints, so only blend between first and last */
+ for (i = first_valid + 1; i < last_valid; i++)
+ depth_arr[i] = FLT_MAX;
+
+ interp_depth = true;
+ }
+
+ if (interp_depth) {
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX);
+ }
+ }
+ }
+
+
+ pt = gps->points;
+
+ /* convert all points (normal behavior) */
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size && ptc; i++, ptc++, pt++) {
+ /* convert screen-coordinates to appropriate coordinates (and store them) */
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+
+ /* copy pressure and time */
+ pt->pressure = ptc->pressure;
+ pt->strength = ptc->strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt->time = ptc->time;
+ }
+
+ if (depth_arr)
+ MEM_freeN(depth_arr);
+ }
+
+ /* add stroke to frame */
+ BLI_addtail(&p->gpf->strokes, gps);
+ gp_stroke_added_enable(p);
+}
+
+/* --- 'Eraser' for 'Paint' Tool ------ */
+
+/* helper to free a stroke
+ * NOTE: gps->dvert and gps->triangles should be NULL, but check anyway for good measure
+ */
+static void gp_free_stroke(bGPDframe *gpf, bGPDstroke *gps)
+{
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
+
+ BLI_freelinkN(&gpf->strokes, gps);
+}
+
+
+/* which which point is infront (result should only be used for comparison) */
+static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
+{
+ if (rv3d->is_persp) {
+ return ED_view3d_calc_zfac(rv3d, co, NULL);
+ }
+ else {
+ return -dot_v3v3(rv3d->viewinv[2], co);
+ }
+}
+
+/* only erase stroke points that are visible (3d view) */
+static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
+{
+ if ((p->sa->spacetype == SPACE_VIEW3D) &&
+ (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
+ {
+ RegionView3D *rv3d = p->ar->regiondata;
+ const int mval[2] = {x, y};
+ float mval_3d[3];
+
+ if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) {
+ const float depth_mval = view3d_point_depth(rv3d, mval_3d);
+ const float depth_pt = view3d_point_depth(rv3d, &pt->x);
+
+ if (depth_pt > depth_mval) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* eraser tool - evaluation per stroke */
+/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
+static void gp_stroke_eraser_dostroke(
+ tGPsdata *p,
+ bGPDframe *gpf, bGPDstroke *gps,
+ const int mval[2], const int mvalo[2],
+ const int radius, const rcti *rect)
+{
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+
+ if (gps->totpoints == 0) {
+ /* just free stroke */
+ gp_free_stroke(gpf, gps);
+ }
+ else if (gps->totpoints == 1) {
+ /* only process if it hasn't been masked out... */
+ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
+ gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* free stroke */
+ gp_free_stroke(gpf, gps);
+ }
+ }
+ }
+ }
+ else {
+ /* Perform culling? */
+ bool do_cull = false;
+
+ /* Clear Tags
+ *
+ * Note: It's better this way, as we are sure that
+ * we don't miss anything, though things will be
+ * slightly slower as a result
+ */
+ for (i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+
+ /* First Pass: Loop over the points in the stroke
+ * 1) Thin out parts of the stroke under the brush
+ * 2) Tag "too thin" parts for removal (in second pass)
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
+ gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the eraser stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
+ {
+ /* Check if point segment of stroke had anything to do with
+ * eraser region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
+ (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false))
+ {
+ /* Edge is affected - Check individual points now */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ pt1->flag |= GP_SPOINT_TAG;
+ }
+ if (len_v2v2_int(mval, pc2) <= radius) {
+ pt2->flag |= GP_SPOINT_TAG;
+ }
+ do_cull = true;
+ }
+ }
+ }
+ }
+
+ /* Second Pass: Remove any points that are tagged */
+ if (do_cull) {
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false);
+ }
+ }
+}
+
+/* erase strokes which fall under the eraser strokes */
+static void gp_stroke_doeraser(tGPsdata *p)
+{
+ bGPDframe *gpf = p->gpf;
+ bGPDstroke *gps, *gpn;
+ rcti rect;
+
+ /* rect is rectangle of eraser */
+ rect.xmin = p->mval[0] - p->radius;
+ rect.ymin = p->mval[1] - p->radius;
+ rect.xmax = p->mval[0] + p->radius;
+ rect.ymax = p->mval[1] + p->radius;
+
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
+ View3D *v3d = p->sa->spacedata.first;
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0);
+ }
+ }
+
+ /* loop over strokes of active layer only (session init already took care of ensuring validity),
+ * checking segments for intersections to remove
+ */
+ for (gps = gpf->strokes.first; gps; gps = gpn) {
+ gpn = gps->next;
+ /* Not all strokes in the datablock may be valid in the current editor/context
+ * (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
+ */
+ if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
+ gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
+ }
+ }
+}
+
+/* ******************************************* */
+/* Sketching Operator */
+
+/* clear the session buffers (call this before AND after a paint operation) */
+static void gp_session_validatebuffer(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+
+ /* clear memory of buffer (or allocate it if starting a new session) */
+ if (gpd->runtime.sbuffer) {
+ /* printf("\t\tGP - reset sbuffer\n"); */
+ memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
+ }
+ else {
+ /* printf("\t\tGP - allocate sbuffer\n"); */
+ gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
+ }
+
+ /* reset indices */
+ gpd->runtime.sbuffer_size = 0;
+
+ /* reset flags */
+ gpd->runtime.sbuffer_sflag = 0;
+
+ /* reset inittime */
+ p->inittime = 0.0;
+}
+
+/* (re)init new painting data */
+static bool gp_session_initdata(bContext *C, tGPsdata *p)
+{
+ Main *bmain = CTX_data_main(C);
+ bGPdata **gpd_ptr = NULL;
+ ScrArea *curarea = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ /* make sure the active view (at the starting time) is a 3d-view */
+ if (curarea == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No active view for painting\n");
+ return 0;
+ }
+
+ /* pass on current scene and window */
+ p->bmain = CTX_data_main(C);
+ p->scene = CTX_data_scene(C);
+ p->depsgraph = CTX_data_depsgraph(C);
+ p->win = CTX_wm_window(C);
+
+ unit_m4(p->imat);
+ unit_m4(p->mat);
+
+ switch (curarea->spacetype) {
+ /* supported views first */
+ case SPACE_VIEW3D:
+ {
+ /* View3D *v3d = curarea->spacedata.first; */
+ /* RegionView3D *rv3d = ar->regiondata; */
+
+ /* set current area
+ * - must verify that region data is 3D-view (and not something else)
+ */
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
+ p->sa = curarea;
+ p->ar = ar;
+ p->align_flag = &ts->annotate_v3d_align;
+
+ if (ar->regiondata == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n");
+ return 0;
+ }
+ break;
+ }
+ case SPACE_NODE:
+ {
+ /* SpaceNode *snode = curarea->spacedata.first; */
+
+ /* set current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_v2d_align;
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = curarea->spacedata.first;
+
+ /* set current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_seq_align;
+
+ /* check that gpencil data is allowed to be drawn */
+ if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n");
+ return 0;
+ }
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ /* SpaceImage *sima = curarea->spacedata.first; */
+
+ /* set the current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_ima_align;
+ break;
+ }
+ case SPACE_CLIP:
+ {
+ SpaceClip *sc = curarea->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (clip == NULL) {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
+
+ /* set the current area */
+ p->sa = curarea;
+ p->ar = ar;
+ p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_v2d_align;
+
+ invert_m4_m4(p->imat, sc->unistabmat);
+
+ /* custom color for new layer */
+ p->custom_color[0] = 1.0f;
+ p->custom_color[1] = 0.0f;
+ p->custom_color[2] = 0.5f;
+ p->custom_color[3] = 0.9f;
+
+ if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
+ MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
+
+ if (marker) {
+ p->imat[3][0] -= marker->pos[0];
+ p->imat[3][1] -= marker->pos[1];
+ }
+ else {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
+ }
+
+ invert_m4_m4(p->mat, p->imat);
+ copy_m4_m4(p->gsc.mat, p->mat);
+ break;
+ }
+ /* unsupported views */
+ default:
+ {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Annotations are not supported in this editor\n");
+ return 0;
+ }
+ }
+
+ /* get gp-data */
+ gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
+ if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Current context doesn't allow for any Annotation data\n");
+ return 0;
+ }
+ else {
+ /* if no existing GPencil block exists, add one */
+ if (*gpd_ptr == NULL) {
+ bGPdata *gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
+ *gpd_ptr = gpd;
+
+ /* mark datablock as being used for annotations */
+ gpd->flag |= GP_DATA_ANNOTATIONS;
+
+ /* annotations always in front of all objects */
+ gpd->xray_mode = GP_XRAY_FRONT;
+ }
+ p->gpd = *gpd_ptr;
+ }
+
+ if (ED_gpencil_session_active() == 0) {
+ /* initialize undo stack,
+ * also, existing undo stack would make buffer drawn
+ */
+ gpencil_undo_init(p->gpd);
+ }
+
+ /* clear out buffer (stored in gp-data), in case something contaminated it */
+ gp_session_validatebuffer(p);
+
+ return 1;
+}
+
+/* init new painting session */
+static tGPsdata *gp_session_initpaint(bContext *C)
+{
+ tGPsdata *p = NULL;
+
+ /* create new context data */
+ p = MEM_callocN(sizeof(tGPsdata), "Annotation Drawing Data");
+
+ /* Try to initialise context data
+ * WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
+ */
+ if (gp_session_initdata(C, p) == 0) {
+ /* Invalid state - Exit
+ * NOTE: It should be safe to just free the data, since failing context checks should
+ * only happen when no data has been allocated.
+ */
+ MEM_freeN(p);
+ return NULL;
+ }
+
+ /* Radius for eraser circle is defined in userprefs */
+ /* NOTE: we do this here, so that if we exit immediately,
+ * erase size won't get lost
+ */
+ p->radius = U.gp_eraser;
+
+ /* return context data for running paint operator */
+ return p;
+}
+
+/* cleanup after a painting session */
+static void gp_session_cleanup(tGPsdata *p)
+{
+ bGPdata *gpd = (p) ? p->gpd : NULL;
+
+ /* error checking */
+ if (gpd == NULL)
+ return;
+
+ /* free stroke buffer */
+ if (gpd->runtime.sbuffer) {
+ /* printf("\t\tGP - free sbuffer\n"); */
+ MEM_freeN(gpd->runtime.sbuffer);
+ gpd->runtime.sbuffer = NULL;
+ }
+
+ /* clear flags */
+ gpd->runtime.sbuffer_size = 0;
+ gpd->runtime.sbuffer_sflag = 0;
+ p->inittime = 0.0;
+}
+
+static void gp_session_free(tGPsdata *p)
+{
+ MEM_freeN(p);
+}
+
+
+/* init new stroke */
+static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph)
+{
+ Scene *scene = p->scene;
+ ToolSettings *ts = scene->toolsettings;
+
+ /* get active layer (or add a new one if non-existent) */
+ p->gpl = BKE_gpencil_layer_getactive(p->gpd);
+ if (p->gpl == NULL) {
+ p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true);
+
+ if (p->custom_color[3])
+ copy_v3_v3(p->gpl->color, p->custom_color);
+ }
+ if (p->gpl->flag & GP_LAYER_LOCKED) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: Cannot paint on locked layer\n");
+ return;
+ }
+
+ /* get active frame (add a new one if not matching frame) */
+ if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Only allow erasing on the active layer (unlike for 3d-art Grease Pencil),
+ * since we won't be exposing layer locking in the UI
+ * 2) Ensure that p->gpf refers to the frame used for the active layer
+ * (to avoid problems with other tools which expect it to exist)
+ */
+ bool has_layer_to_erase = false;
+
+ if (gpencil_layer_is_editable(p->gpl)) {
+ /* Ensure that there's stuff to erase here (not including selection mask below)... */
+ if (p->gpl->actframe && p->gpl->actframe->strokes.first) {
+ has_layer_to_erase = true;
+ }
+ }
+
+ /* Ensure active frame is set correctly... */
+ p->gpf = p->gpl->actframe;
+
+ /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on
+ * (though this is only available in editmode)
+ */
+ if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
+ p->flags |= GP_PAINTFLAG_SELECTMASK;
+ }
+ }
+
+ if (has_layer_to_erase == false) {
+ p->status = GP_STATUS_ERROR;
+ //if (G.debug & G_DEBUG)
+ printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
+ return;
+ }
+ }
+ else {
+ /* Drawing Modes - Add a new frame if needed on the active layer */
+ short add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ else
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+ p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+
+ if (p->gpf == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No frame created (gpencil_paint_init)\n");
+ return;
+ }
+ else {
+ p->gpf->flag |= GP_FRAME_PAINT;
+ }
+ }
+
+ /* set 'eraser' for this stroke if using eraser */
+ p->paintmode = paintmode;
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
+
+ /* check if we should respect depth while erasing */
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->gpl->flag & GP_LAYER_NO_XRAY) {
+ p->flags |= GP_PAINTFLAG_V3D_ERASER_DEPTH;
+ }
+ }
+ }
+ else {
+ /* disable eraser flags - so that we can switch modes during a session */
+ p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
+
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->gpl->flag & GP_LAYER_NO_XRAY) {
+ p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH;
+ }
+ }
+ }
+
+ /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
+ p->flags |= GP_PAINTFLAG_FIRSTRUN;
+
+
+ /* when drawing in the camera view, in 2D space, set the subrect */
+ p->subrect = NULL;
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->sa->spacedata.first;
+ RegionView3D *rv3d = p->ar->regiondata;
+
+ /* for camera view set the subrect */
+ if (rv3d->persp == RV3D_CAMOB) {
+ ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */
+ p->subrect = &p->subrect_data;
+ }
+ }
+ }
+
+ /* init stroke point space-conversion settings... */
+ p->gsc.gpd = p->gpd;
+ p->gsc.gpl = p->gpl;
+
+ p->gsc.sa = p->sa;
+ p->gsc.ar = p->ar;
+ p->gsc.v2d = p->v2d;
+
+ p->gsc.subrect_data = p->subrect_data;
+ p->gsc.subrect = p->subrect;
+
+ copy_m4_m4(p->gsc.mat, p->mat);
+
+
+ /* check if points will need to be made in view-aligned space */
+ if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
+ switch (p->sa->spacetype) {
+ case SPACE_VIEW3D:
+ {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
+ break;
+ }
+ case SPACE_NODE:
+ {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ break;
+ }
+ case SPACE_SEQ:
+ {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = (SpaceImage *)p->sa->spacedata.first;
+
+ /* only set these flags if the image editor doesn't have an image active,
+ * otherwise user will be confused by strokes not appearing after they're drawn
+ *
+ * Admittedly, this is a bit hacky, but it works much nicer from an ergonomic standpoint!
+ */
+ if (ELEM(NULL, sima, sima->image)) {
+ /* make strokes be drawn in screen space */
+ p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_2DSPACE;
+ *(p->align_flag) &= ~GP_PROJECT_VIEWSPACE;
+ }
+ else {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ }
+ break;
+ }
+ case SPACE_CLIP:
+ {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE;
+ break;
+ }
+ }
+ }
+}
+
+/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
+static void gp_paint_strokeend(tGPsdata *p)
+{
+ ToolSettings *ts = p->scene->toolsettings;
+ /* for surface sketching, need to set the right OpenGL context stuff so that
+ * the conversions will project the values correctly...
+ */
+ if (gpencil_project_check(p)) {
+ View3D *v3d = p->sa->spacedata.first;
+
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(p->win, p->ar);
+ ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ }
+
+ /* check if doing eraser or not */
+ if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
+ /* simplify stroke before transferring? */
+ gp_stroke_simplify(p);
+
+ /* transfer stroke to frame */
+ gp_stroke_newfrombuffer(p);
+ }
+
+ /* clean up buffer now */
+ gp_session_validatebuffer(p);
+}
+
+/* finish off stroke painting operation */
+static void gp_paint_cleanup(tGPsdata *p)
+{
+ /* p->gpd==NULL happens when stroke failed to initialize,
+ * for example when GP is hidden in current space (sergey)
+ */
+ if (p->gpd) {
+ /* finish off a stroke */
+ gp_paint_strokeend(p);
+ }
+
+ /* "unlock" frame */
+ if (p->gpf)
+ p->gpf->flag &= ~GP_FRAME_PAINT;
+}
+
+/* ------------------------------- */
+
+/* Helper callback for drawing the cursor itself */
+static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
+{
+ tGPsdata *p = (tGPsdata *)p_ptr;
+
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ GPUVertFormat *format = immVertexFormat();
+ const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ imm_draw_circle_wire_2d(
+ shdr_pos, x, y, p->radius,
+ /* XXX Dashed shader gives bad results with sets of small segments currently,
+ * temp hack around the issue. :( */
+ max_ii(8, p->radius / 2)); /* was fixed 40 */
+
+ immUnbindProgram();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
+}
+
+/* Turn brush cursor in 3D view on/off */
+static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
+{
+ if (p->erasercursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ p->erasercursor = NULL;
+ }
+ else if (enable && !p->erasercursor) {
+ /* enable cursor */
+ p->erasercursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ NULL, /* XXX */
+ gpencil_draw_eraser, p);
+ }
+}
+
+/* Check if tablet eraser is being used (when processing events) */
+static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
+{
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ return (wmtab->Active == EVT_TABLET_ERASER);
+ }
+
+ return false;
+}
+
+/* ------------------------------- */
+
+static void gpencil_draw_exit(bContext *C, wmOperator *op)
+{
+ tGPsdata *p = op->customdata;
+
+ /* restore cursor to indicate end of drawing */
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ /* don't assume that operator data exists at all */
+ if (p) {
+ /* check size of buffer before cleanup, to determine if anything happened here */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* turn off radial brush cursor */
+ gpencil_draw_toggle_eraser_cursor(C, p, false);
+ }
+
+ /* always store the new eraser size to be used again next time
+ * NOTE: Do this even when not in eraser mode, as eraser may
+ * have been toggled at some point.
+ */
+ U.gp_eraser = p->radius;
+
+ /* clear undo stack */
+ gpencil_undo_finish();
+
+ /* cleanup */
+ gp_paint_cleanup(p);
+ gp_session_cleanup(p);
+ gp_session_free(p);
+ p = NULL;
+ }
+
+ op->customdata = NULL;
+}
+
+static void gpencil_draw_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_draw_exit(C, op);
+}
+
+/* ------------------------------- */
+
+
+static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPsdata *p;
+ eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
+
+ /* check context */
+ p = op->customdata = gp_session_initpaint(C);
+ if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
+ /* something wasn't set correctly in context */
+ gpencil_draw_exit(C, op);
+ return 0;
+ }
+
+ /* init painting data */
+ gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
+ if (p->status == GP_STATUS_ERROR) {
+ gpencil_draw_exit(C, op);
+ return 0;
+ }
+
+ if (event != NULL) {
+ p->keymodifier = event->keymodifier;
+ }
+ else {
+ p->keymodifier = -1;
+ }
+
+ /* everything is now setup ok */
+ return 1;
+}
+
+
+/* ------------------------------- */
+
+/* ensure that the correct cursor icon is set */
+static void gpencil_draw_cursor_set(tGPsdata *p)
+{
+ if (p->paintmode == GP_PAINTMODE_ERASER)
+ WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ else
+ WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+}
+
+/* update UI indicators of status, including cursor and header prints */
+static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
+{
+ /* header prints */
+ switch (p->status) {
+ case GP_STATUS_PAINTING:
+ switch (p->paintmode) {
+ case GP_PAINTMODE_DRAW_POLY:
+ /* Provide usage tips, since this is modal, and unintuitive without hints */
+ ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ default:
+ /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
+ * Showing any text would just be annoying as it would flicker.
+ */
+ break;
+ }
+ break;
+
+ case GP_STATUS_IDLING:
+ /* print status info */
+ switch (p->paintmode) {
+ case GP_PAINTMODE_ERASER:
+ ED_workspace_status_text(C, IFACE_("Annotation Eraser: Hold and drag LMB or RMB to erase | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW_STRAIGHT:
+ ED_workspace_status_text(C, IFACE_("Annotation Line Draw: Hold and drag LMB to draw | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW:
+ ED_workspace_status_text(C, IFACE_("Annotation Freehand Draw: Hold and drag LMB to draw | "
+ "E/ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW_POLY:
+ ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+
+ default: /* unhandled future cases */
+ ED_workspace_status_text(C, IFACE_("Annotation Session: ESC/Enter to end (or click outside this area)"));
+ break;
+ }
+ break;
+
+ case GP_STATUS_ERROR:
+ case GP_STATUS_DONE:
+ /* clear status string */
+ ED_workspace_status_text(C, NULL);
+ break;
+ }
+}
+
+/* ------------------------------- */
+
+/* create a new stroke point at the point indicated by the painting context */
+static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
+{
+ /* handle drawing/erasing -> test for erasing first */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* do 'live' erasing now */
+ gp_stroke_doeraser(p);
+
+ /* store used values */
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ }
+ /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */
+ else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
+ /* try to add point */
+ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+
+ /* handle errors while adding point */
+ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
+ /* finish off old stroke */
+ gp_paint_strokeend(p);
+ /* And start a new one!!! Else, projection errors! */
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
+
+ /* start a new stroke, starting from previous point */
+ /* XXX Must manually reset inittime... */
+ /* XXX We only need to reuse previous point if overflow! */
+ if (ok == GP_STROKEADD_OVERFLOW) {
+ p->inittime = p->ocurtime;
+ gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
+ }
+ else {
+ p->inittime = p->curtime;
+ }
+ gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ }
+ else if (ok == GP_STROKEADD_INVALID) {
+ /* the painting operation cannot continue... */
+ BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
+ p->status = GP_STATUS_ERROR;
+
+ if (G.debug & G_DEBUG)
+ printf("Error: Grease-Pencil Paint - Add Point Invalid\n");
+ return;
+ }
+
+ /* store used values */
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+ }
+}
+
+/* handle draw event */
+static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsgraph *depsgraph)
+{
+ tGPsdata *p = op->customdata;
+ PointerRNA itemptr;
+ float mousef[2];
+ int tablet = 0;
+
+ /* convert from window-space to area-space mouse coordinates
+ * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding...
+ */
+ p->mval[0] = event->mval[0] + 1;
+ p->mval[1] = event->mval[1] + 1;
+
+ /* verify key status for straight lines */
+ if ((event->ctrl > 0) || (event->alt > 0)) {
+ if (p->straight[0] == 0) {
+ int dx = abs(p->mval[0] - p->mvalo[0]);
+ int dy = abs(p->mval[1] - p->mvalo[1]);
+ if ((dx > 0) || (dy > 0)) {
+ /* check mouse direction to replace the other coordinate with previous values */
+ if (dx >= dy) {
+ /* horizontal */
+ p->straight[0] = 1;
+ p->straight[1] = p->mval[1]; /* save y */
+ }
+ else {
+ /* vertical */
+ p->straight[0] = 2;
+ p->straight[1] = p->mval[0]; /* save x */
+ }
+ }
+ }
+ }
+ else {
+ p->straight[0] = 0;
+ }
+
+ p->curtime = PIL_check_seconds_timer();
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+
+ tablet = (wmtab->Active != EVT_TABLET_NONE);
+ p->pressure = wmtab->Pressure;
+
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
+ }
+ }
+ }
+ else {
+ /* No tablet data -> No pressure info is available */
+ p->pressure = 1.0f;
+ }
+
+ /* special exception for start of strokes (i.e. maybe for just a dot) */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
+
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->inittime = p->ocurtime = p->curtime;
+ p->straight[0] = 0;
+ p->straight[1] = 0;
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch...
+ */
+ if (tablet && (p->pressure >= 0.99f))
+ return;
+ }
+
+ /* check if alt key is pressed and limit to straight lines */
+ if (p->straight[0] != 0) {
+ if (p->straight[0] == 1) {
+ /* horizontal */
+ p->mval[1] = p->straight[1]; /* replace y */
+ }
+ else {
+ /* vertical */
+ p->mval[0] = p->straight[1]; /* replace x */
+ }
+ }
+
+ /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ mousef[0] = p->mval[0];
+ mousef[1] = p->mval[1];
+ RNA_float_set_array(&itemptr, "mouse", mousef);
+ RNA_float_set(&itemptr, "pressure", p->pressure);
+ RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
+
+ RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
+
+ /* apply the current latest drawing point */
+ gpencil_draw_apply(op, p, depsgraph);
+
+ /* force refresh */
+ ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
+}
+
+/* ------------------------------- */
+
+/* operator 'redo' (i.e. after changing some properties, but also for repeat last) */
+static int gpencil_draw_exec(bContext *C, wmOperator *op)
+{
+ tGPsdata *p = NULL;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ /* printf("GPencil - Starting Re-Drawing\n"); */
+
+ /* try to initialize context data needed while drawing */
+ if (!gpencil_draw_init(C, op, NULL)) {
+ if (op->customdata) MEM_freeN(op->customdata);
+ /* printf("\tGP - no valid data\n"); */
+ return OPERATOR_CANCELLED;
+ }
+ else
+ p = op->customdata;
+
+ /* printf("\tGP - Start redrawing stroke\n"); */
+
+ /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
+ * setting the relevant values in context at each step, then applying
+ */
+ RNA_BEGIN (op->ptr, itemptr, "stroke")
+ {
+ float mousef[2];
+
+ /* printf("\t\tGP - stroke elem\n"); */
+
+ /* get relevant data for this point from stroke */
+ RNA_float_get_array(&itemptr, "mouse", mousef);
+ p->mval[0] = (int)mousef[0];
+ p->mval[1] = (int)mousef[1];
+ p->pressure = RNA_float_get(&itemptr, "pressure");
+ p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
+
+ if (RNA_boolean_get(&itemptr, "is_start")) {
+ /* if first-run flag isn't set already (i.e. not true first stroke),
+ * then we must terminate the previous one first before continuing
+ */
+ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
+ /* TODO: both of these ops can set error-status, but we probably don't need to worry */
+ gp_paint_strokeend(p);
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
+ }
+ }
+
+ /* if first run, set previous data too */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
+
+ p->mvalo[0] = p->mval[0];
+ p->mvalo[1] = p->mval[1];
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+ }
+
+ /* apply this data as necessary now (as per usual) */
+ gpencil_draw_apply(op, p, depsgraph);
+ }
+ RNA_END;
+
+ /* printf("\tGP - done\n"); */
+
+ /* cleanup */
+ gpencil_draw_exit(C, op);
+
+ /* refreshes */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+/* ------------------------------- */
+
+/* start of interactive drawing part of operator */
+static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+ tGPsdata *p = NULL;
+
+ /* if try to do annotations with a gp object selected, first
+ * unselect the object to avoid conflicts.
+ * The solution is not perfect but we can keep running the annotations while
+ * found a better solution.
+ */
+ if (sa && sa->spacetype == SPACE_VIEW3D) {
+ if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BKE_view_layer_base_deselect_all(view_layer);
+ view_layer->basact = NULL;
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ }
+ }
+
+ if (G.debug & G_DEBUG)
+ printf("GPencil - Starting Drawing\n");
+
+ /* try to initialize context data needed while drawing */
+ if (!gpencil_draw_init(C, op, event)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ if (G.debug & G_DEBUG)
+ printf("\tGP - no valid data\n");
+ return OPERATOR_CANCELLED;
+ }
+ else
+ p = op->customdata;
+
+ /* TODO: set any additional settings that we can take from the events?
+ * TODO? if tablet is erasing, force eraser to be on? */
+
+ /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
+
+ /* if eraser is on, draw radial aid */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ gpencil_draw_toggle_eraser_cursor(C, p, true);
+ }
+ /* set cursor
+ * NOTE: This may change later (i.e. intentionally via brush toggle,
+ * or unintentionally if the user scrolls outside the area)...
+ */
+ gpencil_draw_cursor_set(p);
+
+ /* only start drawing immediately if we're allowed to do so... */
+ if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
+ /* hotkey invoked - start drawing */
+ /* printf("\tGP - set first spot\n"); */
+ p->status = GP_STATUS_PAINTING;
+
+ /* handle the initial drawing - i.e. for just doing a simple dot */
+ gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C));
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+ else {
+ /* toolbar invoked - don't start drawing yet... */
+ /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ /* add a modal handler for this operator, so that we can then draw continuous strokes */
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
+{
+ bScreen *sc = CTX_wm_screen(C);
+ return (BLI_findindex(&sc->areabase, sa_test) != -1);
+}
+
+static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
+{
+ tGPsdata *p = op->customdata;
+
+ /* we must check that we're still within the area that we're set up to work from
+ * otherwise we could crash (see bug #20586)
+ */
+ if (CTX_wm_area(C) != p->sa) {
+ printf("\t\t\tGP - wrong area execution abort!\n");
+ p->status = GP_STATUS_ERROR;
+ }
+
+ /* printf("\t\tGP - start stroke\n"); */
+
+ /* we may need to set up paint env again if we're resuming */
+ /* XXX: watch it with the paintmode! in future,
+ * it'd be nice to allow changing paint-mode when in sketching-sessions */
+
+ if (gp_session_initdata(C, p))
+ gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
+
+ if (p->status != GP_STATUS_ERROR) {
+ p->status = GP_STATUS_PAINTING;
+ op->flag &= ~OP_IS_MODAL_CURSOR_REGION;
+ }
+
+ return op->customdata;
+}
+
+static void gpencil_stroke_end(wmOperator *op)
+{
+ tGPsdata *p = op->customdata;
+
+ gp_paint_cleanup(p);
+
+ gpencil_undo_push(p->gpd);
+
+ gp_session_cleanup(p);
+
+ p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
+ p->gpd = NULL;
+ p->gpl = NULL;
+ p->gpf = NULL;
+}
+
+/* events handling during interactive drawing part of operator */
+static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPsdata *p = op->customdata;
+ int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */
+
+ /* if (event->type == NDOF_MOTION)
+ * return OPERATOR_PASS_THROUGH;
+ * -------------------------------
+ * [mce] Not quite what I was looking
+ * for, but a good start! GP continues to
+ * draw on the screen while the 3D mouse
+ * moves the viewpoint. Problem is that
+ * the stroke is converted to 3D only after
+ * it is finished. This approach should work
+ * better in tools that immediately apply
+ * in 3D space.
+ */
+
+ if (p->status == GP_STATUS_IDLING) {
+ ARegion *ar = CTX_wm_region(C);
+ p->ar = ar;
+ }
+
+ /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
+ if (ISKEYBOARD(event->type)) {
+ if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) {
+ /* allow some keys:
+ * - for frame changing [#33412]
+ * - for undo (during sketching sessions)
+ */
+ }
+ else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
+ /* allow numpad keys so that camera/view manipulations can still take place
+ * - PAD0 in particular is really important for Grease Pencil drawing,
+ * as animators may be working "to camera", so having this working
+ * is essential for ensuring that they can quickly return to that view
+ */
+ }
+ else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
+ /* Add Blank Frame
+ * - Since this operator is non-modal, we can just call it here, and keep going...
+ * - This operator is especially useful when animating
+ */
+ WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ //printf("\tGP - handle modal event...\n");
+
+ /* exit painting mode (and/or end current stroke)
+ * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
+ */
+ if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
+ /* exit() ends the current stroke before cleaning up */
+ /* printf("\t\tGP - end of paint op + end of stroke\n"); */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+
+ /* toggle painting mode upon mouse-button movement
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
+ * - RIGHTMOUSE = polyline (hotkey) / eraser (all)
+ * (Disabling RIGHTMOUSE case here results in bugs like [#32647])
+ * also making sure we have a valid event value, to not exit too early
+ */
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
+ /* if painting, end stroke */
+ if (p->status == GP_STATUS_PAINTING) {
+ int sketch = 0;
+
+ /* basically, this should be mouse-button up = end stroke
+ * BUT, polyline drawing is an exception -- all knots should be added during one session
+ */
+ sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
+
+ if (sketch) {
+ /* end stroke only, and then wait to resume painting soon */
+ /* printf("\t\tGP - end stroke only\n"); */
+ gpencil_stroke_end(op);
+
+ /* If eraser mode is on, turn it off after the stroke finishes
+ * NOTE: This just makes it nicer to work with drawing sessions
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+
+ /* if the original mode was *still* eraser,
+ * we'll let it say for now, since this gives
+ * users an opportunity to have visual feedback
+ * when adjusting eraser size
+ */
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ /* turn off cursor...
+ * NOTE: this should be enough for now
+ * Just hiding this makes it seem like
+ * you can paint again...
+ */
+ gpencil_draw_toggle_eraser_cursor(C, p, false);
+ }
+ }
+
+ /* we've just entered idling state, so this event was processed (but no others yet) */
+ estate = OPERATOR_RUNNING_MODAL;
+
+ /* stroke could be smoothed, send notifier to refresh screen */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ }
+ else {
+ /* printf("\t\tGP - end of stroke + op\n"); */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else if (event->val == KM_PRESS) {
+ bool in_bounds = false;
+
+ /* Check if we're outside the bounds of the active region
+ * NOTE: An exception here is that if launched from the toolbar,
+ * whatever region we're now in should become the new region
+ */
+ if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) {
+ /* Change to whatever region is now under the mouse */
+ ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+
+ if (G.debug & G_DEBUG) {
+ printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ current_region, p->ar, event->x, event->y,
+ p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax);
+ }
+
+ if (current_region) {
+ /* Assume that since we found the cursor in here, it is in bounds
+ * and that this should be the region that we begin drawing in
+ */
+ p->ar = current_region;
+ in_bounds = true;
+ }
+ else {
+ /* Out of bounds, or invalid in some other way */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__);
+ }
+ }
+ else if (p->ar) {
+ rcti region_rect;
+
+ /* Perform bounds check using */
+ ED_region_visible_rect(p->ar, &region_rect);
+ in_bounds = BLI_rcti_isect_pt_v(&region_rect, event->mval);
+ }
+ else {
+ /* No region */
+ p->status = GP_STATUS_ERROR;
+ estate = OPERATOR_CANCELLED;
+
+ if (G.debug & G_DEBUG)
+ printf("%s: No active region found in GP Paint session data\n", __func__);
+ }
+
+ if (in_bounds) {
+ /* Switch paintmode (temporarily if need be) based on which button was used
+ * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
+ */
+ if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) {
+ /* turn on eraser */
+ p->paintmode = GP_PAINTMODE_ERASER;
+ }
+ else if (event->type == LEFTMOUSE) {
+ /* restore drawmode to default */
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+ }
+
+ gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+
+ /* not painting, so start stroke (this should be mouse-button down) */
+ p = gpencil_stroke_begin(C, op);
+
+ if (p->status == GP_STATUS_ERROR) {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else if (p->status != GP_STATUS_ERROR) {
+ /* User clicked outside bounds of window while idling, so exit paintmode
+ * NOTE: Don't enter this case if an error occurred while finding the
+ * region (as above)
+ */
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
+ }
+ }
+ else if (event->val == KM_RELEASE) {
+ p->status = GP_STATUS_IDLING;
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ }
+ }
+
+ /* handle mode-specific events */
+ if (p->status == GP_STATUS_PAINTING) {
+ /* handle painting mouse-movements? */
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
+ /* handle drawing event */
+ /* printf("\t\tGP - add point\n"); */
+ gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C));
+
+ /* finish painting operation if anything went wrong just now */
+ if (p->status == GP_STATUS_ERROR) {
+ printf("\t\t\t\tGP - add error done!\n");
+ estate = OPERATOR_CANCELLED;
+ }
+ else {
+ /* event handled, so just tag as running modal */
+ /* printf("\t\t\t\tGP - add point handled!\n"); */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+ /* eraser size */
+ else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
+ ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS))
+ {
+ /* just resize the brush (local version)
+ * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
+ */
+ /* printf("\t\tGP - resize eraser\n"); */
+ switch (event->type) {
+ case WHEELDOWNMOUSE: /* larger */
+ case PADPLUSKEY:
+ p->radius += 5;
+ break;
+
+ case WHEELUPMOUSE: /* smaller */
+ case PADMINUS:
+ p->radius -= 5;
+
+ if (p->radius <= 0)
+ p->radius = 1;
+ break;
+ }
+
+ /* force refresh */
+ ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
+
+ /* event handled, so just tag as running modal */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ /* there shouldn't be any other events, but just in case there are, let's swallow them
+ * (i.e. to prevent problems with undo)
+ */
+ else {
+ /* swallow event to save ourselves trouble */
+ estate = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+ if (0 == gpencil_area_exists(C, p->sa))
+ estate = OPERATOR_CANCELLED;
+ else {
+ /* update status indicators - cursor, header, etc. */
+ gpencil_draw_status_indicators(C, p);
+ gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */
+ }
+
+ /* process last operations before exiting */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ /* one last flush before we're done */
+ gpencil_draw_exit(C, op);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ break;
+
+ case OPERATOR_CANCELLED:
+ gpencil_draw_exit(C, op);
+ break;
+
+ case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
+ /* event doesn't need to be handled */
+#if 0
+ printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
+ event->type, event->type == MIDDLEMOUSE, event->type==MOUSEMOVE);
+#endif
+ break;
+ }
+
+ /* return status code */
+ return estate;
+}
+
+/* ------------------------------- */
+
+static const EnumPropertyItem prop_gpencil_drawmodes[] = {
+ {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
+ {GP_PAINTMODE_DRAW_STRAIGHT, "DRAW_STRAIGHT", 0, "Draw Straight Lines", "Draw straight line segment(s)"},
+ {GP_PAINTMODE_DRAW_POLY, "DRAW_POLY", 0, "Draw Poly Line", "Click to place endpoints of straight line segments (connected)"},
+ {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Annotation strokes"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+void GPENCIL_OT_annotate(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Annotation Draw";
+ ot->idname = "GPENCIL_OT_annotate";
+ ot->description = "Make annotations on the active data";
+
+ /* api callbacks */
+ ot->exec = gpencil_draw_exec;
+ ot->invoke = gpencil_draw_invoke;
+ ot->modal = gpencil_draw_modal;
+ ot->cancel = gpencil_draw_cancel;
+ ot->poll = gpencil_draw_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* settings for drawing */
+ ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
+
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index f4d4ce7fb63..7f67caf91ca 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -46,6 +46,7 @@
#include "BLF_api.h"
#include "BLT_translation.h"
+#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -55,14 +56,22 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
+#include "BKE_brush.h"
#include "BKE_global.h"
+#include "BKE_paint.h"
#include "BKE_gpencil.h"
+#include "BKE_image.h"
+
+#include "DEG_depsgraph.h"
#include "WM_api.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+#include "GPU_state.h"
+
#include "ED_gpencil.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -71,6 +80,10 @@
#include "UI_interface_icons.h"
#include "UI_resources.h"
+#include "IMB_imbuf_types.h"
+
+#include "gpencil_intern.h"
+
/* ************************************************** */
/* GREASE PENCIL DRAWING */
@@ -85,45 +98,112 @@ typedef enum eDrawStrokeFlags {
GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */
GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */
GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */
- GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */
- GP_DRAWDATA_HQ_FILL = (1 << 9) /* Use high quality fill */
+ GP_DRAWDATA_FILL = (1 << 8) /* fill insides/bounded-regions of strokes */
} eDrawStrokeFlags;
/* thickness above which we should use special drawing */
+#if 0
#define GP_DRAWTHICKNESS_SPECIAL 3
+#endif
+
+/* conversion utility (float --> normalized unsigned byte) */
+#define F2UB(x) (uchar)(255.0f * x)
/* ----- Tool Buffer Drawing ------ */
-/* helper function to set color of buffer point */
-static void gp_set_tpoint_color(tGPspoint *pt, float ink[4])
+/* helper functions to set color of buffer point */
+
+static void gp_set_tpoint_varying_color(const tGPspoint *pt, const float ink[4], uint attr_id)
{
float alpha = ink[3] * pt->strength;
CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- glColor4f(ink[0], ink[1], ink[2], alpha);
+ immAttr4ub(attr_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha));
}
-/* helper function to set color of point */
-static void gp_set_point_color(bGPDspoint *pt, float ink[4])
+static void gp_set_point_uniform_color(const bGPDspoint *pt, const float ink[4])
{
float alpha = ink[3] * pt->strength;
CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- glColor4f(ink[0], ink[1], ink[2], alpha);
+ immUniformColor3fvAlpha(ink, alpha);
}
-/* helper function to set color and point */
-static void gp_set_color_and_tpoint(tGPspoint *pt, float ink[4])
+static void gp_set_point_varying_color(const bGPDspoint *pt, const float ink[4], uint attr_id)
{
- gp_set_tpoint_color(pt, ink);
- glVertex2iv(&pt->x);
+ float alpha = ink[3] * pt->strength;
+ CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
+ immAttr4ub(attr_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha));
+}
+
+/* draw fills for buffer stroke */
+static void gp_draw_stroke_buffer_fill(const tGPspoint *points, int totpoints, float ink[4])
+{
+ if (totpoints < 3) {
+ return;
+ }
+ int tot_triangles = totpoints - 2;
+ /* allocate memory for temporary areas */
+ uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, "GP Stroke buffer temp triangulation");
+ float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, "GP Stroke buffer temp 2d points");
+
+ /* Convert points to array and triangulate
+ * Here a cache is not used because while drawing the information changes all the time, so the cache
+ * would be recalculated constantly, so it is better to do direct calculation for each function call
+ */
+ for (int i = 0; i < totpoints; i++) {
+ const tGPspoint *pt = &points[i];
+ points2d[i][0] = pt->x;
+ points2d[i][1] = pt->y;
+ }
+ BLI_polyfill_calc((const float(*)[2])points2d, (uint)totpoints, 0, (uint(*)[3])tmp_triangles);
+
+ /* draw triangulation data */
+ if (tot_triangles > 0) {
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ /* Draw all triangles for filling the polygon */
+ immBegin(GPU_PRIM_TRIS, tot_triangles * 3);
+ /* TODO: use batch instead of immediate mode, to share vertices */
+
+ const tGPspoint *pt;
+ for (int i = 0; i < tot_triangles; i++) {
+ /* vertex 1 */
+ pt = &points[tmp_triangles[i][0]];
+ gp_set_tpoint_varying_color(pt, ink, color);
+ immVertex2iv(pos, &pt->x);
+ /* vertex 2 */
+ pt = &points[tmp_triangles[i][1]];
+ gp_set_tpoint_varying_color(pt, ink, color);
+ immVertex2iv(pos, &pt->x);
+ /* vertex 3 */
+ pt = &points[tmp_triangles[i][2]];
+ gp_set_tpoint_varying_color(pt, ink, color);
+ immVertex2iv(pos, &pt->x);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
+
+ /* clear memory */
+ if (tmp_triangles) {
+ MEM_freeN(tmp_triangles);
+ }
+ if (points2d) {
+ MEM_freeN(points2d);
+ }
}
/* 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, float ink[4])
+static void gp_draw_stroke_buffer(
+ const tGPspoint *points, int totpoints, short thickness,
+ short dflag, short sflag, float ink[4], float fill_ink[4])
{
- tGPspoint *pt;
- int i;
+ int draw_points = 0;
/* error checking */
if ((points == NULL) || (totpoints <= 0))
@@ -133,58 +213,86 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
return;
+ if (sflag & GP_STROKE_ERASER) {
+ /* don't draw stroke at all! */
+ return;
+ }
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ const tGPspoint *pt = points;
+
if (totpoints == 1) {
/* if drawing a single point, draw it larger */
- glPointSize((float)(thickness + 2) * points->pressure);
- glBegin(GL_POINTS);
-
- gp_set_color_and_tpoint(points, ink);
- glEnd();
- }
- else if (sflag & GP_STROKE_ERASER) {
- /* don't draw stroke at all! */
+ GPU_point_size((float)(thickness + 2) * points->pressure);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
+ immBegin(GPU_PRIM_POINTS, 1);
+ gp_set_tpoint_varying_color(pt, ink, color);
+ immVertex2iv(pos, &pt->x);
}
else {
float oldpressure = points[0].pressure;
/* draw stroke curve */
- if (G.debug & G_DEBUG) setlinestyle(2);
+ GPU_line_width(max_ff(oldpressure * thickness, 1.0));
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints);
- glLineWidth(max_ff(oldpressure * thickness, 1.0));
- glBegin(GL_LINE_STRIP);
+ /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */
- for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
+ for (int i = 0; i < totpoints; i++, pt++) {
/* if there was a significant pressure change, stop the curve, change the thickness of the stroke,
* and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP)
*/
if (fabsf(pt->pressure - oldpressure) > 0.2f) {
- glEnd();
- glLineWidth(max_ff(pt->pressure * thickness, 1.0f));
- glBegin(GL_LINE_STRIP);
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ gp_set_tpoint_varying_color(pt - 1, ink, color);
+ immVertex2iv(pos, &(pt - 1)->x);
+ }
+
+ immEnd();
+ draw_points = 0;
+
+ GPU_line_width(max_ff(pt->pressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1);
/* need to roll-back one point to ensure that there are no gaps in the stroke */
if (i != 0) {
- gp_set_color_and_tpoint((pt - 1), ink);
+ gp_set_tpoint_varying_color(pt - 1, ink, color);
+ immVertex2iv(pos, &(pt - 1)->x);
+ draw_points++;
}
- /* now the point we want... */
- gp_set_color_and_tpoint(pt, ink);
-
- oldpressure = pt->pressure;
- }
- else {
- gp_set_color_and_tpoint(pt, ink);
+ oldpressure = pt->pressure; /* reset our threshold */
}
+
+ /* now the point we want */
+ gp_set_tpoint_varying_color(pt, ink, color);
+ immVertex2iv(pos, &pt->x);
+ draw_points++;
+ }
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ gp_set_tpoint_varying_color(pt - 1, ink, color);
+ immVertex2iv(pos, &(pt - 1)->x);
}
- glEnd();
+ }
- if (G.debug & G_DEBUG) setlinestyle(0);
+ immEnd();
+ immUnbindProgram();
+
+ // draw fill
+ if (fill_ink[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
+ gp_draw_stroke_buffer_fill(points, totpoints, fill_ink);
}
}
/* --------- 2D Stroke Drawing Helpers --------- */
/* 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])
+static void gp_calc_2d_stroke_fxy(const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
{
if (sflag & GP_STROKE_2DSPACE) {
r_co[0] = pt[0];
@@ -210,15 +318,10 @@ static void gp_calc_2d_stroke_fxy(float pt[3], short sflag, int offsx, int offsy
/* 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), float ink[4])
+static void gp_draw_stroke_volumetric_buffer(
+ const tGPspoint *points, int totpoints, short thickness,
+ short dflag, const float ink[4])
{
- GLUquadricObj *qobj = gluNewQuadric();
- float modelview[4][4];
-
- tGPspoint *pt;
- int i;
-
/* error checking */
if ((points == NULL) || (totpoints <= 0))
return;
@@ -227,152 +330,141 @@ static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, s
if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
return;
- /* get basic matrix - should be camera space (i.e "identity") */
- glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
-
- /* draw points */
- glPushMatrix();
-
- for (i = 0, pt = points; i < totpoints; i++, pt++) {
- /* set the transformed position */
- // TODO: scale should change based on zoom level, which requires proper translation mult too!
- modelview[3][0] = pt->x;
- modelview[3][1] = pt->y;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- glLoadMatrixf((float *)modelview);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ GPU_enable_program_point_size();
+ immBegin(GPU_PRIM_POINTS, totpoints);
- /* draw the disk using the current state... */
- gp_set_tpoint_color(pt, ink);
- gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
-
-
- modelview[3][0] = modelview[3][1] = 0.0f;
+ const tGPspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ gp_set_tpoint_varying_color(pt, ink, color);
+ immAttr1f(size, pt->pressure * thickness); /* TODO: scale based on view transform (zoom level) */
+ immVertex2f(pos, pt->x, pt->y);
}
- glPopMatrix();
- gluDeleteQuadric(qobj);
+ immEnd();
+ immUnbindProgram();
+ GPU_disable_program_point_size();
}
/* 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,
- float diff_mat[4][4], float ink[4])
+static void gp_draw_stroke_volumetric_2d(
+ const bGPDspoint *points, int totpoints, short thickness,
+ short UNUSED(dflag), short sflag,
+ int offsx, int offsy, int winx, int winy,
+ const float diff_mat[4][4], const float ink[4])
{
- GLUquadricObj *qobj = gluNewQuadric();
- float modelview[4][4];
- float baseloc[3];
- float scalefac = 1.0f;
-
- 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
- * else assumes 1 unit = 1 pixel. Otherwise, we only get a massive blob.
- */
- if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
- scalefac = 0.001f;
- }
-
- /* get basic matrix */
- glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
- copy_v3_v3(baseloc, modelview[3]);
-
- /* draw points */
- glPushMatrix();
-
- for (i = 0, pt = points; i < totpoints; i++, pt++) {
- /* color of point */
- gp_set_point_color(pt, ink);
-
- /* set the transformed position */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ GPU_enable_program_point_size();
+ immBegin(GPU_PRIM_POINTS, totpoints);
+
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* transform position to 2D */
float co[2];
+ float fpt[3];
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);
- /* draw the disk using the current state... */
- gluDisk(qobj, 0.0, pt->pressure * thickness * scalefac, 32, 1);
-
- /* restore matrix */
- copy_v3_v3(modelview[3], baseloc);
+ gp_set_point_varying_color(pt, ink, color);
+ immAttr1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */
+ immVertex2f(pos, co[0], co[1]);
}
- glPopMatrix();
- gluDeleteQuadric(qobj);
+ immEnd();
+ immUnbindProgram();
+ GPU_disable_program_point_size();
}
/* 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), float diff_mat[4][4], float ink[4])
+ const bGPDspoint *points, int totpoints, short thickness,
+ const float ink[4])
{
- GLUquadricObj *qobj = gluNewQuadric();
-
- float base_modelview[4][4], modelview[4][4];
- float base_loc[3];
-
- bGPDspoint *pt;
- int i;
- float fpt[3];
-
- /* Get the basic modelview matrix we use for performing calculations */
- glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview);
- copy_v3_v3(base_loc, base_modelview[3]);
-
- /* Create the basic view-aligned billboard matrix we're going to actually draw qobj with:
- * - We need to knock out the rotation so that we are
- * simply left with a camera-facing billboard
- * - The scale factors here are chosen so that the thickness
- * is relatively reasonable. Otherwise, it gets far too
- * large!
- */
- scale_m4_fl(modelview, 0.1f);
-
- /* draw each point as a disk... */
- 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);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ GPU_enable_program_point_size();
+ immBegin(GPU_PRIM_POINTS, totpoints);
+
+ const bGPDspoint *pt = points;
+ for (int i = 0; i < totpoints && pt; i++, pt++) {
+ gp_set_point_varying_color(pt, ink, color);
+ immAttr1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */
+ immVertex3fv(pos, &pt->x); /* we can adjust size in vertex shader based on view/projection! */
+ }
- /* apply translation to base_modelview, so that the translated point is put in the right place */
- translate_m4(base_modelview, fpt[0], fpt[1], fpt[2]);
+ immEnd();
+ immUnbindProgram();
+ GPU_disable_program_point_size();
+}
- /* 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
- * for the next point without accumulation/pollution effects
- */
- copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */
- copy_v3_v3(base_modelview[3], base_loc); /* restore */
- /* apply our billboard matrix for drawing... */
- glLoadMatrixf((float *)modelview);
+/* --------------- Stroke Fills ----------------- */
+/* calc bounding box in 2d using flat projection data */
+static void gp_calc_2d_bounding_box(const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], bool expand)
+{
+ copy_v2_v2(minv, points2d[0]);
+ copy_v2_v2(maxv, points2d[0]);
- /* draw the disk using the current state... */
- gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
+ for (int i = 1; i < totpoints; i++) {
+ /* min */
+ if (points2d[i][0] < minv[0]) {
+ minv[0] = points2d[i][0];
+ }
+ if (points2d[i][1] < minv[1]) {
+ minv[1] = points2d[i][1];
+ }
+ /* max */
+ if (points2d[i][0] > maxv[0]) {
+ maxv[0] = points2d[i][0];
+ }
+ if (points2d[i][1] > maxv[1]) {
+ maxv[1] = points2d[i][1];
+ }
+ }
+ /* If not expanded, use a perfect square */
+ if (expand == false) {
+ if (maxv[0] > maxv[1]) {
+ maxv[1] = maxv[0];
+ }
+ else {
+ maxv[0] = maxv[1];
+ }
}
-
- glPopMatrix();
- gluDeleteQuadric(qobj);
}
-
-/* --------------- Stroke Fills ----------------- */
+/* calc texture coordinates using flat projected points */
+static void gp_calc_stroke_text_coordinates(const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], float(*r_uv)[2])
+{
+ float d[2];
+ d[0] = maxv[0] - minv[0];
+ d[1] = maxv[1] - minv[1];
+ for (int i = 0; i < totpoints; i++) {
+ r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
+ r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
+ }
+}
/* Get points of stroke always flat to view not affected by camera view or view position */
-static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
+static void gp_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
{
- bGPDspoint *pt0 = &points[0];
- bGPDspoint *pt1 = &points[1];
- bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
float locx[3];
float locy[3];
@@ -397,7 +489,7 @@ static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d
/* Get all points in local space */
for (int i = 0; i < totpoints; i++) {
- bGPDspoint *pt = &points[i];
+ const bGPDspoint *pt = &points[i];
float loc[3];
/* Get local space using first point as origin */
@@ -411,7 +503,6 @@ static void gp_stroke_2d_flat(bGPDspoint *points, int totpoints, float(*points2d
*r_direction = (int)locy[2];
}
-
/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
static void gp_triangulate_stroke_fill(bGPDstroke *gps)
{
@@ -419,14 +510,23 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
/* allocate memory for temporary areas */
gps->tot_triangles = gps->totpoints - 2;
- unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
+ uint (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
+ float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
int direction = 0;
/* convert to 2d and triangulate */
gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
- BLI_polyfill_calc(points2d, (unsigned int)gps->totpoints, direction, tmp_triangles);
+ BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
+
+ /* calc texture coordinates automatically */
+ float minv[2];
+ float maxv[2];
+ /* first needs bounding box data */
+ gp_calc_2d_bounding_box((const float(*)[2])points2d, gps->totpoints, minv, maxv, false);
+ /* calc uv data */
+ gp_calc_stroke_text_coordinates((const float(*)[2])points2d, gps->totpoints, minv, maxv, uv);
/* Number of triangles */
gps->tot_triangles = gps->totpoints - 2;
@@ -442,6 +542,10 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
for (int i = 0; i < gps->tot_triangles; i++) {
bGPDtriangle *stroke_triangle = &gps->triangles[i];
memcpy(stroke_triangle->verts, tmp_triangles[i], sizeof(uint[3]));
+ /* copy texture coordinates */
+ copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]);
+ copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]);
+ copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]);
}
}
else {
@@ -458,218 +562,260 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps)
}
/* clear memory */
- if (tmp_triangles) MEM_freeN(tmp_triangles);
- if (points2d) MEM_freeN(points2d);
+ MEM_SAFE_FREE(tmp_triangles);
+ MEM_SAFE_FREE(points2d);
+ MEM_SAFE_FREE(uv);
}
-
-/* draw fills for shapes */
-static void gp_draw_stroke_fill(
- bGPdata *gpd, bGPDstroke *gps,
- int offsx, int offsy, int winx, int winy, float diff_mat[4][4])
+/* add a new fill point and texture coordinates to vertex buffer */
+static void gp_add_filldata_tobuffer(
+ const bGPDspoint *pt, const float uv[2], uint pos, uint texcoord, short flag,
+ int offsx, int offsy, int winx, int winy, const float diff_mat[4][4])
{
- bGPDpalettecolor *palcolor;
- int i;
float fpt[3];
+ float co[2];
- BLI_assert(gps->totpoints >= 3);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* if 2d, need conversion */
+ if (!(flag & GP_STROKE_3DSPACE)) {
+ gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co);
+ copy_v2_v2(fpt, co);
+ fpt[2] = 0.0f; /* 2d always is z=0.0f */
+ }
+
+ immAttr2f(texcoord, uv[0], uv[1]); /* texture coordinates */
+ immVertex3fv(pos, fpt); /* position */
+}
- palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
+#if 0 /* GPXX disabled, not used in annotations */
+/* assign image texture for filling stroke */
+static int gp_set_filling_texture(Image *image, short flag)
+{
+ ImBuf *ibuf;
+ uint *bind = &image->bindcode[TEXTARGET_TEXTURE_2D];
+ int error = GL_NO_ERROR;
+ ImageUser iuser = { NULL };
+ void *lock;
- /* Triangulation fill if high quality flag is enabled */
- if (palcolor->flag & PC_COLOR_HQ_FILL) {
- bGPDtriangle *stroke_triangle;
- bGPDspoint *pt;
+ iuser.ok = true;
- /* 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);
- if (gps->flag & GP_STROKE_3DSPACE) {
- for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- pt = &gps->points[stroke_triangle->verts[j]];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
- }
- }
- }
- else {
- for (i = 0, stroke_triangle = gps->triangles; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- float co[2];
- pt = &gps->points[stroke_triangle->verts[j]];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
- glVertex2fv(co);
- }
- }
- }
- glEnd();
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf == NULL || ibuf->rect == NULL) {
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ return (int)GL_INVALID_OPERATION;
+ }
+
+ GPU_create_gl_tex(bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D,
+ false, false, image);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ if (flag & GP_STYLE_COLOR_TEX_CLAMP) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}
else {
- /* 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 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;
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
- glBegin(GL_POLYGON);
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (gps->flag & GP_STROKE_3DSPACE) {
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
- }
- else {
- float co[2];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
- glVertex2fv(co);
- }
- }
+ return error;
+}
+#endif
- glEnd();
+/* draw fills for shapes */
+static void gp_draw_stroke_fill(
+ bGPdata *gpd, bGPDstroke *gps,
+ int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4])
+{
+ BLI_assert(gps->totpoints >= 3);
+ Material *ma = gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ /* Calculate triangles cache for filling area (must be done only after changes) */
+ if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
+ gp_triangulate_stroke_fill(gps);
+ }
+ BLI_assert(gps->tot_triangles >= 1);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_GPENCIL_FILL);
+
+ immUniformColor4fv(color);
+ immUniform4fv("color2", gp_style->mix_rgba);
+ immUniform1i("fill_type", gp_style->fill_style);
+ immUniform1f("mix_factor", gp_style->mix_factor);
+
+ immUniform1f("gradient_angle", gp_style->gradient_angle);
+ immUniform1f("gradient_radius", gp_style->gradient_radius);
+ immUniform1f("pattern_gridsize", gp_style->pattern_gridsize);
+ immUniform2fv("gradient_scale", gp_style->gradient_scale);
+ immUniform2fv("gradient_shift", gp_style->gradient_shift);
+
+ immUniform1f("texture_angle", gp_style->texture_angle);
+ immUniform2fv("texture_scale", gp_style->texture_scale);
+ immUniform2fv("texture_offset", gp_style->texture_offset);
+ immUniform1f("texture_opacity", gp_style->texture_opacity);
+ immUniform1i("t_mix", gp_style->flag & GP_STYLE_COLOR_TEX_MIX ? 1 : 0);
+ immUniform1i("t_flip", gp_style->flag & GP_STYLE_COLOR_FLIP_FILL ? 1 : 0);
+#if 0 /* GPXX disabled, not used in annotations */
+ /* image texture */
+ if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_TEXTURE) || (gp_style->flag & GP_STYLE_COLOR_TEX_MIX)) {
+ gp_set_filling_texture(gp_style->ima, gp_style->flag);
}
+#endif
+ /* Draw all triangles for filling the polygon (cache must be calculated before) */
+ immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3);
+ /* TODO: use batch instead of immediate mode, to share vertices */
+
+ const bGPDtriangle *stroke_triangle = gps->triangles;
+ for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
+ for (int j = 0; j < 3; j++) {
+ gp_add_filldata_tobuffer(
+ &gps->points[stroke_triangle->verts[j]], stroke_triangle->uv[j],
+ pos, texcoord, gps->flag,
+ offsx, offsy, winx, winy, diff_mat);
+ }
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* ----- Existing Strokes Drawing (3D and Point) ------ */
/* 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, float diff_mat[4][4], float ink[4])
+ const bGPDspoint *points, short thickness, short UNUSED(dflag), short sflag,
+ int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const 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);
+ const bGPDspoint *pt = points;
/* get final position using parent matrix */
+ float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* draw point */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
if (sflag & GP_STROKE_3DSPACE) {
- glBegin(GL_POINTS);
- glVertex3fv(fpt);
- glEnd();
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
}
else {
- float co[2];
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- /* get coordinates of point */
+ /* get 2D coordinates of point */
+ float co[3] = { 0.0f };
gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
+ copy_v3_v3(fpt, co);
+ }
- /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
- * - also mandatory in if Image Editor 'image-based' dot
- */
- if ((thickness < GP_DRAWTHICKNESS_SPECIAL) ||
- ((dflag & GP_DRAWDATA_IEDITHACK) && (sflag & GP_STROKE_2DSPACE)))
- {
- glBegin(GL_POINTS);
- glVertex2fv(co);
- glEnd();
- }
- else {
- /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */
- GLUquadricObj *qobj = gluNewQuadric();
-
- gluQuadricDrawStyle(qobj, GLU_FILL);
+ gp_set_point_uniform_color(pt, ink);
+ /* set point thickness (since there's only one of these) */
+ immUniform1f("size", (float)(thickness + 2) * pt->pressure);
- /* need to translate drawing position, but must reset after too! */
- glTranslate2fv(co);
- gluDisk(qobj, 0.0, thickness, 32, 1);
- glTranslatef(-co[0], -co[1], 0.0);
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, fpt);
+ immEnd();
- gluDeleteQuadric(qobj);
- }
- }
+ immUnbindProgram();
}
-/* 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), float diff_mat[4][4], float ink[4], bool cyclic)
+/* draw a given stroke in 3d (i.e. in 3d-space) */
+static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4], bool cyclic)
{
- bGPDspoint *pt, *pt2;
+ bGPDspoint *points = tgpw->gps->points;
+ int totpoints = tgpw->gps->totpoints;
+
+ const float viewport[2] = { (float)tgpw->winx, (float)tgpw->winy };
float curpressure = points[0].pressure;
- int i;
float fpt[3];
- float cyclic_fpt[3];
+
+ /* if cyclic needs more vertex */
+ int cyclic_add = (cyclic) ? 1 : 0;
+
+ GPUVertFormat *format = immVertexFormat();
+ const struct {
+ uint pos, color, thickness;
+ } attr_id = {
+ .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT),
+ .color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT),
+ .thickness = GPU_vertformat_attr_add(format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT),
+ };
+
+ immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE);
+ immUniform2fv("Viewport", viewport);
+ immUniform1f("pixsize", tgpw->rv3d->pixsize);
+ float obj_scale = tgpw->ob ? (tgpw->ob->size[0] + tgpw->ob->size[1] + tgpw->ob->size[2]) / 3.0f : 1.0f;
+
+ immUniform1f("objscale", obj_scale);
+ int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
+ immUniform1i("keep_size", keep_size);
+ immUniform1i("pixfactor", tgpw->gpd->pixfactor);
+ immUniform1i("xraymode", tgpw->gpd->xray_mode);
/* draw stroke curve */
- 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.
- */
- if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) {
- glEnd();
- curpressure = pt->pressure;
- glLineWidth(max_ff(curpressure * thickness, 1.0f));
- glBegin(GL_LINE_STRIP);
-
- /* need to roll-back one point to ensure that there are no gaps in the stroke */
- if (i != 0) {
- pt2 = pt - 1;
- mul_v3_m4v3(fpt, diff_mat, &pt2->x);
- glVertex3fv(fpt);
- }
+ GPU_line_width(max_ff(curpressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2);
+ const bGPDspoint *pt = points;
- /* now the point we want... */
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
- }
- else {
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
- }
- /* saves first point to use in cyclic */
+ for (int i = 0; i < totpoints; i++, pt++) {
+ /* first point for adjacency (not drawn) */
if (i == 0) {
- copy_v3_v3(cyclic_fpt, fpt);
+ gp_set_point_varying_color(points, ink, attr_id.color);
+ immAttr1f(attr_id.thickness, max_ff(curpressure * thickness, 1.0f));
+ if ((cyclic) && (totpoints > 2)) {
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 1)->x);
+ }
+ else {
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
+ }
+ mul_v3_fl(fpt, -1.0f);
+ immVertex3fv(attr_id.pos, fpt);
}
- }
- /* if cyclic draw line to first point */
- if (cyclic) {
- glVertex3fv(cyclic_fpt);
- }
- glEnd();
+ /* set point */
+ gp_set_point_varying_color(pt, ink, attr_id.color);
+ immAttr1f(attr_id.thickness, max_ff(curpressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x);
+ immVertex3fv(attr_id.pos, fpt);
- /* draw debug points of curve on top? */
- /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */
- if (debug) {
- glPointSize((float)(thickness + 2));
+ curpressure = pt->pressure;
+ }
- glBegin(GL_POINTS);
- for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
- }
- glEnd();
+ if (cyclic && totpoints > 2) {
+ /* draw line to first point to complete the cycle */
+ immAttr1f(attr_id.thickness, max_ff(points->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &points->x);
+ immVertex3fv(attr_id.pos, fpt);
+ /* now add adjacency point (not drawn) */
+ immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
+ immVertex3fv(attr_id.pos, fpt);
}
+ /* last adjacency point (not drawn) */
+ else {
+ gp_set_point_varying_color(points + totpoints - 1, ink, attr_id.color);
+ immAttr1f(attr_id.thickness, max_ff(curpressure * thickness, 1.0f));
+ mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 2)->x);
+ mul_v3_fl(fpt, -1.0f);
+ immVertex3fv(attr_id.pos, fpt);
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* ----- Fancy 2D-Stroke Drawing ------ */
/* 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, float diff_mat[4][4], float ink[4])
+static void gp_draw_stroke_2d(
+ const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
+ bool UNUSED(debug), int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4])
{
/* otherwise thickness is twice that of the 3D view */
float thickness = (float)thickness_s * 0.5f;
@@ -680,18 +826,28 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
scalefac = 0.001f;
}
- /* tessellation code - draw stroke as series of connected quads with connection
+ /* TODO: fancy++ with the magic of shaders */
+
+ /* tessellation code - draw stroke as series of connected quads (triangle strips in fact) with connection
* edges rotated to minimize shrinking artifacts, and rounded endcaps
*/
{
- bGPDspoint *pt1, *pt2;
+ const bGPDspoint *pt1, *pt2;
float s0[2], s1[2]; /* segment 'center' points */
float pm[2]; /* normal from previous segment. */
int i;
float fpt[3];
- glShadeModel(GL_FLAT);
- glBegin(GL_QUADS);
+ GPUVertFormat *format = immVertexFormat();
+ const struct {
+ uint pos, color;
+ } attr_id = {
+ .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT),
+ .color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT),
+ };
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
/* get x and y coordinates from first point */
mul_v3_m4v3(fpt, diff_mat, &points->x);
@@ -718,7 +874,7 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
pthick = (pt1->pressure * thickness * scalefac);
/* color of point */
- gp_set_point_color(pt1, ink);
+ gp_set_point_varying_color(pt1, ink, attr_id.color);
/* if the first segment, start of segment is segment's normal */
if (i == 0) {
@@ -735,8 +891,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
t1[0] = sc[0] + mt[0];
t1[1] = sc[1] + mt[1];
- glVertex2fv(t0);
- glVertex2fv(t1);
+ /* First two points of cap. */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
/* calculate points for start of segment */
mt[0] = m2[0] * pthick;
@@ -747,11 +904,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
t1[0] = s0[0] + mt[0];
t1[1] = s0[1] + mt[1];
- /* draw this line twice (first to finish off start cap, then for stroke) */
- glVertex2fv(t1);
- glVertex2fv(t0);
- glVertex2fv(t0);
- glVertex2fv(t1);
+ /* Last two points of start cap (and first two points of first segment). */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
}
/* if not the first segment, use bisector of angle between segments */
else {
@@ -783,11 +938,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
t1[0] = s0[0] + mt[0];
t1[1] = s0[1] + mt[1];
- /* draw this line twice (once for end of current segment, and once for start of next) */
- glVertex2fv(t1);
- glVertex2fv(t0);
- glVertex2fv(t0);
- glVertex2fv(t1);
+ /* Last two points of previous segment, and first two points of current segment. */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
}
/* if last segment, also draw end of segment (defined as segment's normal) */
@@ -796,7 +949,7 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
pthick = (pt2->pressure * thickness * scalefac);
/* color of point */
- gp_set_point_color(pt2, ink);
+ gp_set_point_varying_color(pt2, ink, attr_id.color);
/* calculate points for end of segment */
mt[0] = m2[0] * pthick;
@@ -807,12 +960,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
t1[0] = s1[0] + mt[0];
t1[1] = s1[1] + mt[1];
- /* draw this line twice (once for end of stroke, and once for endcap)*/
- glVertex2fv(t1);
- glVertex2fv(t0);
- glVertex2fv(t0);
- glVertex2fv(t1);
-
+ /* Last two points of last segment (and first two points of end cap). */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
/* draw end cap as last step
* - make points slightly closer to center (about halfway across)
@@ -827,8 +977,9 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
t1[0] = sc[0] + mt[0];
t1[1] = sc[1] + mt[1];
- glVertex2fv(t1);
- glVertex2fv(t0);
+ /* Last two points of end cap. */
+ immVertex2fv(attr_id.pos, t0);
+ immVertex2fv(attr_id.pos, t1);
}
/* store computed point2 coordinates as point1 ones of next segment. */
@@ -837,26 +988,8 @@ static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness
copy_v2_v2(pm, m2);
}
- glEnd();
- glShadeModel(GL_SMOOTH);
- }
-
- /* draw debug points of curve on top? (original stroke points) */
- 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];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
- glVertex2fv(co);
- }
- glEnd();
+ immEnd();
+ immUnbindProgram();
}
}
@@ -884,7 +1017,6 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
return false;
-
/* skip stroke if it doesn't have any valid data */
if ((gps->points == NULL) || (gps->totpoints < 1))
return false;
@@ -894,186 +1026,204 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
}
/* draw a set of strokes */
-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])
+static void gp_draw_strokes(tGPDdraw *tgpw)
{
- bGPDstroke *gps;
float tcolor[4];
float tfill[4];
short sthickness;
float ink[4];
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ GPU_enable_program_point_size();
+
+ for (bGPDstroke *gps = tgpw->t_gpf->strokes.first; gps; gps = gps->next) {
/* check if stroke can be drawn */
- if (gp_can_draw_stroke(gps, dflag) == false) {
+ if (gp_can_draw_stroke(gps, tgpw->dflag) == false) {
continue;
}
/* check if the color is visible */
- bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
- if ((palcolor == NULL) ||
- (palcolor->flag & PC_COLOR_HIDE) ||
+ Material *ma = tgpw->gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ if ((gp_style == NULL) ||
+ (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
/* if onion and ghost flag do not draw*/
- (onion && (palcolor->flag & PC_COLOR_ONIONSKIN)))
+ (tgpw->onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN)))
+ {
+ continue;
+ }
+
+ /* if disable fill, the colors with fill must be omitted too except fill boundary strokes */
+ if ((tgpw->disable_fill == 1) &&
+ (gp_style->fill_rgba[3] > 0.0f) &&
+ ((gps->flag & GP_STROKE_NOFILL) == 0))
{
continue;
}
/* calculate thickness */
- sthickness = gps->thickness + lthick;
+ sthickness = gps->thickness + tgpw->lthick;
+
+ if (sthickness <= 0) {
+ continue;
+ }
/* check which stroke-drawer to use */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
+ if (tgpw->dflag & GP_DRAWDATA_ONLY3D) {
+ const int no_xray = (tgpw->dflag & GP_DRAWDATA_NO_XRAY);
int mask_orig = 0;
if (no_xray) {
glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
glDepthMask(0);
- glEnable(GL_DEPTH_TEST);
+ GPU_depth_test(true);
/* first arg is normally rv3d->dist, but this isn't
* available here and seems to work quite well without */
bglPolygonOffset(1.0f, 1.0f);
-#if 0
- glEnable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(-1.0f, -1.0f);
-#endif
}
/* 3D Fill */
//if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- if (gps->totpoints >= 3) {
- /* set color using palette, tint color and opacity */
- interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
- tfill[3] = palcolor->fill[3] * opacity;
- if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
- if (!onion) {
- glColor4fv(tfill);
+ if ((gps->totpoints >= 3) && (tgpw->disable_fill != 1)) {
+ /* set color using material, tint color and opacity */
+ interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
+ if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
+ const float *color;
+ if (!tgpw->onion) {
+ color = tfill;
}
else {
- if (custonion) {
- glColor4fv(tintcolor);
+ if (tgpw->custonion) {
+ color = tgpw->tintcolor;
}
else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]);
- glColor4fv(tfill);
+ ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
+ color = tfill;
}
}
- gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+ gp_draw_stroke_fill(
+ tgpw->gpd, gps,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, color);
}
}
/* 3D Stroke */
- /* set color using palette, tint color and opacity */
- if (!onion) {
- interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
- tcolor[3] = palcolor->color[3] * opacity;
+ /* set color using material tint color and opacity */
+ if (!tgpw->onion) {
+ interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
copy_v4_v4(ink, tcolor);
}
else {
- if (custonion) {
- copy_v4_v4(ink, tintcolor);
+ if (tgpw->custonion) {
+ copy_v4_v4(ink, tgpw->tintcolor);
}
else {
- ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+ ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
copy_v4_v4(ink, tcolor);
}
}
- if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
+ if (gp_style->mode == GP_STYLE_MODE_DOTS) {
/* volumetric stroke drawing */
- gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, diff_mat, ink);
+ if (tgpw->disable_fill != 1) {
+ gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink);
+ }
}
else {
/* 3D Lines - OpenGL primitives-based */
if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
- diff_mat, ink);
+ if (tgpw->disable_fill != 1) {
+ gp_draw_stroke_point(gps->points, sthickness, tgpw->dflag, gps->flag,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy,
+ tgpw->diff_mat, ink);
+ }
}
else {
- gp_draw_stroke_3d(gps->points, gps->totpoints, sthickness, debug, gps->flag,
- diff_mat, ink, gps->flag & GP_STROKE_CYCLIC);
+ tgpw->gps = gps;
+ gp_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC);
}
}
if (no_xray) {
glDepthMask(mask_orig);
- glDisable(GL_DEPTH_TEST);
+ GPU_depth_test(false);
bglPolygonOffset(0.0, 0.0);
-#if 0
- glDisable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(0, 0);
-#endif
}
}
else {
/* 2D - Fill */
if (gps->totpoints >= 3) {
- /* set color using palette, tint color and opacity */
- interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]);
- tfill[3] = palcolor->fill[3] * opacity;
- if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) {
- if (!onion) {
- glColor4fv(tfill);
+ /* set color using material, tint color and opacity */
+ interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
+ if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
+ const float *color;
+ if (!tgpw->onion) {
+ color = tfill;
}
else {
- if (custonion) {
- glColor4fv(tintcolor);
+ if (tgpw->custonion) {
+ color = tgpw->tintcolor;
}
else {
- ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2],
- tintcolor[3]);
- glColor4fv(tfill);
+ ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
+ color = tfill;
}
}
- gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat);
+ gp_draw_stroke_fill(
+ tgpw->gpd, gps,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, color);
}
}
/* 2D Strokes... */
- /* set color using palette, tint color and opacity */
- if (!onion) {
- interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]);
- tcolor[3] = palcolor->color[3] * opacity;
+ /* set color using material, tint color and opacity */
+ if (!tgpw->onion) {
+ interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
+ tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
copy_v4_v4(ink, tcolor);
}
else {
- if (custonion) {
- copy_v4_v4(ink, tintcolor);
+ if (tgpw->custonion) {
+ copy_v4_v4(ink, tgpw->tintcolor);
}
else {
- ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity);
+ ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
copy_v4_v4(ink, tcolor);
}
}
- if (palcolor->flag & PC_COLOR_VOLUMETRIC) {
+ if (gp_style->mode == GP_STYLE_MODE_DOTS) {
/* blob/disk-based "volumetric" drawing */
- gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag,
- offsx, offsy, winx, winy, diff_mat, ink);
+ gp_draw_stroke_volumetric_2d(
+ gps->points, gps->totpoints, sthickness, tgpw->dflag, gps->flag,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, ink);
}
else {
/* normal 2D strokes */
if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy,
- diff_mat, ink);
+ gp_draw_stroke_point(
+ gps->points, sthickness, tgpw->dflag, gps->flag,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy,
+ tgpw->diff_mat, ink);
}
else {
- gp_draw_stroke_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, debug,
- offsx, offsy, winx, winy, diff_mat, ink);
+ gp_draw_stroke_2d(
+ gps->points, gps->totpoints, sthickness, tgpw->dflag, gps->flag, false,
+ tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, ink);
}
}
}
}
+
+ GPU_disable_program_point_size();
}
/* Draw selected verts for strokes being edited */
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)
+ bGPdata *gpd, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag,
+ short lflag, const float diff_mat[4][4], float alpha)
{
- bGPDstroke *gps;
-
/* if alpha 0 do not draw */
if (alpha == 0.0f)
return;
@@ -1086,26 +1236,18 @@ static void gp_draw_strokes_edit(
if (no_xray) {
glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
glDepthMask(0);
- glEnable(GL_DEPTH_TEST);
+ GPU_depth_test(true);
/* first arg is normally rv3d->dist, but this isn't
* available here and seems to work quite well without */
bglPolygonOffset(1.0f, 1.0f);
-#if 0
- glEnable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(-1.0f, -1.0f);
-#endif
}
}
+ GPU_enable_program_point_size();
/* draw stroke verts */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- bGPDspoint *pt;
- float vsize, bsize;
- int i;
- float fpt[3];
-
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* check if stroke can be drawn */
if (gp_can_draw_stroke(gps, dflag) == false)
continue;
@@ -1117,14 +1259,16 @@ static void gp_draw_strokes_edit(
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
- /* verify palette color lock */
+ /* verify color lock */
{
- bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps);
- if (palcolor != NULL) {
- if (palcolor->flag & PC_COLOR_HIDE) {
+ Material *ma = gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ if (gp_style != NULL) {
+ if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
continue;
}
- if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) {
+ if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
continue;
}
}
@@ -1135,7 +1279,8 @@ static void gp_draw_strokes_edit(
* they stand out more.
* - We use the theme setting for size of the unselected verts
*/
- bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
+ float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
+ float vsize;
if ((int)bsize > 8) {
vsize = 10.0f;
bsize = 8.0f;
@@ -1144,87 +1289,82 @@ static void gp_draw_strokes_edit(
vsize = bsize + 2;
}
- /* First Pass: Draw all the verts (i.e. these become the unselected state) */
/* 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);
+ /* set color using material */
+ Material *ma = gpd->mat[gps->mat_nr];
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ float selectColor[4];
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
+ selectColor[3] = alpha;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos; /* specified later */
+ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
+ else {
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
+ }
- glPointSize(bsize);
+ immBegin(GPU_PRIM_POINTS, gps->totpoints);
- glBegin(GL_POINTS);
- for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
+ /* Draw start and end point differently if enabled stroke direction hint */
+ bool show_direction_hint = (gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
+
+ /* Draw all the stroke points (selected or not) */
+ bGPDspoint *pt = gps->points;
+ float fpt[3];
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
+ /* size and color first */
+ if (show_direction_hint && i == 0) {
+ /* start point in green bigger */
+ immAttr3f(color, 0.0f, 1.0f, 0.0f);
+ immAttr1f(size, vsize + 4);
+ }
+ else if (show_direction_hint && (i == gps->totpoints - 1)) {
+ /* end point in red smaller */
+ immAttr3f(color, 1.0f, 0.0f, 0.0f);
+ immAttr1f(size, vsize + 1);
+ }
+ else if (pt->flag & GP_SPOINT_SELECT) {
+ immAttr3fv(color, selectColor);
+ immAttr1f(size, vsize);
+ }
+ else {
+ immAttr3fv(color, gp_style->stroke_rgba);
+ immAttr1f(size, bsize);
+ }
+
+ /* then position */
if (gps->flag & GP_STROKE_3DSPACE) {
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
+ immVertex3fv(pos, fpt);
}
else {
float co[2];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co);
- glVertex2fv(co);
+ immVertex2fv(pos, co);
}
}
- glEnd();
-
-
- /* Second Pass: Draw only verts which are selected */
- 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) {
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- glVertex3fv(fpt);
- }
- else {
- float co[2];
- 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();
- }
+ immEnd();
+ immUnbindProgram();
}
+ GPU_disable_program_point_size();
/* clear depth mask */
if (dflag & GP_DRAWDATA_ONLY3D) {
if (no_xray) {
glDepthMask(mask_orig);
- glDisable(GL_DEPTH_TEST);
+ GPU_depth_test(false);
bglPolygonOffset(0.0, 0.0);
#if 0
@@ -1237,106 +1377,75 @@ static void gp_draw_strokes_edit(
/* ----- General Drawing ------ */
-/* draw onion-skinning for a layer */
-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])
+
+/* draw interpolate strokes (used only while operator is running) */
+void ED_gp_draw_interpolation(const bContext *C, tGPDinterpolate *tgpi, const int type)
{
- const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
- const float alpha = 1.0f;
+ tGPDdraw tgpw;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ tGPDinterpolate_layer *tgpil;
+ Object *obact = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
float color[4];
- /* 1) Draw Previous Frames First */
- if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
- copy_v3_v3(color, gpl->gcolor_prev);
- }
- else {
- copy_v3_v3(color, default_color);
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
+ color[3] = 0.6f;
+ int dflag = 0;
+ /* if 3d stuff, enable flags */
+ if (type == REGION_DRAW_POST_VIEW) {
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
}
- if (gpl->gstep > 0) {
- bGPDframe *gf;
- float fac;
-
- /* draw previous frames first */
- for (gf = gpf->prev; gf; gf = gf->prev) {
- /* check if frame is drawable */
- if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
- /* alpha decreases with distance from curframe index */
- fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
- color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
- true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
- }
- else
- break;
- }
- }
- else if (gpl->gstep == 0) {
- /* draw the strokes for the ghost frames (at half of the alpha set by user) */
- if (gpf->prev) {
- color[3] = (alpha / 7);
- gp_draw_strokes(gpd, gpf->prev, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
- true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat);
- }
- }
- else {
- /* don't draw - disabled */
- }
+ tgpw.rv3d = rv3d;
+ tgpw.depsgraph = depsgraph;
+ tgpw.ob = obact;
+ tgpw.gpd = tgpi->gpd;
+ tgpw.offsx = 0;
+ tgpw.offsy = 0;
+ tgpw.winx = tgpi->ar->winx;
+ tgpw.winy = tgpi->ar->winy;
+ tgpw.dflag = dflag;
+ /* turn on alpha-blending */
+ glEnable(GL_BLEND);
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ /* calculate parent position */
+ ED_gpencil_parent_location(depsgraph, obact, tgpi->gpd, tgpil->gpl, tgpw.diff_mat);
+ if (tgpil->interFrame) {
+ tgpw.gpl = tgpil->gpl;
+ tgpw.gpf = tgpil->interFrame;
+ tgpw.t_gpf = tgpil->interFrame;
- /* 2) Now draw next frames */
- if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
- copy_v3_v3(color, gpl->gcolor_next);
- }
- else {
- copy_v3_v3(color, default_color);
- }
+ tgpw.lthick = tgpil->gpl->line_change;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, color);
+ tgpw.onion = true;
+ tgpw.custonion = true;
- if (gpl->gstep_next > 0) {
- bGPDframe *gf;
- float fac;
-
- /* now draw next frames */
- for (gf = gpf->next; gf; gf = gf->next) {
- /* check if frame is drawable */
- if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
- /* alpha decreases with distance from curframe index */
- fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
- color[3] = alpha * fac * 0.66f;
- gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
- true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
- }
- else
- break;
- }
- }
- else if (gpl->gstep_next == 0) {
- /* draw the strokes for the ghost frames (at half of the alpha set by user) */
- if (gpf->next) {
- color[3] = (alpha / 4);
- gp_draw_strokes(gpd, gpf->next, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color,
- true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat);
+ gp_draw_strokes(&tgpw);
}
}
- else {
- /* don't draw - disabled */
- }
-
+ glDisable(GL_BLEND);
}
/* draw interpolate strokes (used only while operator is running) */
-void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type)
+void ED_gp_draw_primitives(const bContext *C, tGPDprimitive *tgpi, const int type)
{
- tGPDinterpolate_layer *tgpil;
- float diff_mat[4][4];
- float color[4];
+ tGPDdraw tgpw;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
- int offsx = 0;
- int offsy = 0;
- int winx = tgpi->ar->winx;
- int winy = tgpi->ar->winy;
+ /* if idle, do not draw */
+ if (tgpi->flag == 0) {
+ return;
+ }
+ Object *obact = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ float color[4];
UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
color[3] = 0.6f;
int dflag = 0;
@@ -1345,86 +1454,107 @@ void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type)
dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
}
+ tgpw.rv3d = rv3d;
+ tgpw.depsgraph = depsgraph;
+ tgpw.ob = obact;
+ tgpw.gpd = tgpi->gpd;
+ tgpw.offsx = 0;
+ tgpw.offsy = 0;
+ tgpw.winx = tgpi->ar->winx;
+ tgpw.winy = tgpi->ar->winy;
+ tgpw.dflag = dflag;
+
/* turn on alpha-blending */
- glEnable(GL_BLEND);
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- /* calculate parent position */
- ED_gpencil_parent_location(tgpil->gpl, diff_mat);
- if (tgpil->interFrame) {
- gp_draw_strokes(tgpi->gpd, tgpil->interFrame, offsx, offsy, winx, winy, dflag, false,
- tgpil->gpl->thickness, 1.0f, color, true, true, diff_mat);
+ GPU_blend(true);
+ /* calculate parent position */
+ ED_gpencil_parent_location(depsgraph, obact, tgpi->gpd, tgpi->gpl, tgpw.diff_mat);
+ if (tgpi->gpf) {
+ tgpw.gps = tgpi->gpf->strokes.first;
+ if (tgpw.gps->totpoints > 0) {
+ tgpw.gpl = tgpi->gpl;
+ tgpw.gpf = tgpi->gpf;
+ tgpw.t_gpf = tgpi->gpf;
+
+ tgpw.lthick = tgpi->gpl->line_change;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, color);
+ tgpw.onion = true;
+ tgpw.custonion = true;
+
+ gp_draw_strokes(&tgpw);
}
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
+}
+
+/* wrapper to draw strokes for filling operator */
+void ED_gp_draw_fill(tGPDdraw *tgpw)
+{
+ gp_draw_strokes(tgpw);
}
/* loop over gpencil data layers, drawing them */
-static void gp_draw_data_layers(
- bGPDbrush *brush, float alpha, bGPdata *gpd,
+static void gp_draw_data_layers(RegionView3D *rv3d,
+ const Brush *brush, float alpha, Object *ob, bGPdata *gpd,
int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
- bGPDlayer *gpl;
float diff_mat[4][4];
-
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *gpf;
+ tGPDdraw tgpw;
+
+ tgpw.rv3d = rv3d;
+ tgpw.depsgraph = NULL; /* XXX: This is not used here */
+ tgpw.ob = ob;
+ tgpw.gpd = gpd;
+ tgpw.gpl = NULL;
+ tgpw.gpf = NULL;
+ tgpw.t_gpf = NULL;
+ tgpw.offsx = offsx;
+ tgpw.offsy = offsy;
+ tgpw.winx = winx;
+ tgpw.winy = winy;
+ tgpw.dflag = dflag;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* calculate parent position */
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, diff_mat);
- bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
- short lthick = brush->thickness + gpl->thickness;
+ short lthick = brush->size + gpl->line_change;
/* don't draw layer if hidden */
if (gpl->flag & GP_LAYER_HIDE)
continue;
/* get frame to draw */
- gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
if (gpf == NULL)
continue;
/* set basic stroke thickness */
- glLineWidth(lthick);
+ GPU_line_width(lthick);
/* Add layer drawing settings to the set of "draw flags"
* NOTE: If the setting doesn't apply, it *must* be cleared,
* as dflag's carry over from the previous layer
*/
-#define GP_DRAWFLAG_APPLY(condition, draw_flag_value) { \
- if (condition) dflag |= (draw_flag_value); \
- else dflag &= ~(draw_flag_value); \
- } (void)0
/* xray... */
- GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY);
+ SET_FLAG_FROM_TEST(dflag, gpl->flag & GP_LAYER_NO_XRAY, GP_DRAWDATA_NO_XRAY);
/* volumetric strokes... */
- GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC);
-
- /* HQ fills... */
- GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL);
-
-#undef GP_DRAWFLAG_APPLY
-
- /* Draw 'onionskins' (frame left + right)
- * - It is only possible to show these if the option is enabled
- * - The "no onions" flag prevents ghosts from appearing during animation playback/scrubbing
- * and in renders
- * - The per-layer "always show" flag however overrides the playback/render restriction,
- * allowing artists to selectively turn onionskins on/off during playback
- */
- if ((gpl->flag & GP_LAYER_ONIONSKIN) &&
- ((dflag & GP_DRAWDATA_NO_ONIONS) == 0 || (gpl->flag & GP_LAYER_GHOST_ALWAYS)))
- {
- /* Drawing method - only immediately surrounding (gstep = 0),
- * or within a frame range on either side (gstep > 0)
- */
- gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat);
- }
+ SET_FLAG_FROM_TEST(dflag, gpl->flag & GP_LAYER_VOLUMETRIC, GP_DRAWDATA_VOLUMETRIC);
+
+ tgpw.gpl = gpl;
+ tgpw.gpf = gpf;
+ tgpw.t_gpf = gpf; // XXX?
+ tgpw.lthick = gpl->line_change;
+ tgpw.opacity = gpl->opacity;
+ copy_v4_v4(tgpw.tintcolor, gpl->tintcolor);
+ tgpw.onion = false;
+ tgpw.custonion = false;
+ copy_m4_m4(tgpw.diff_mat, diff_mat);
/* draw the strokes already in active frame */
- gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness,
- gpl->opacity, gpl->tintcolor, false, false, diff_mat);
+ gp_draw_strokes(&tgpw);
/* Draw verts of selected strokes
* - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
@@ -1447,28 +1577,31 @@ static void gp_draw_data_layers(
if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) &&
(gpf->flag & GP_FRAME_PAINT))
{
- /* Set color for drawing buffer stroke - since this may not be set yet */
- // glColor4fv(gpl->color);
-
/* Buffer stroke needs to be drawn with a different linestyle
* to help differentiate them from normal strokes.
*
* It should also be noted that sbuffer contains temporary point types
* i.e. tGPspoints NOT bGPDspoints
*/
- if (gpd->sflag & PC_COLOR_VOLUMETRIC) {
- gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick,
- dflag, gpd->sbuffer_sflag, gpd->scolor);
+ if (gpd->runtime.mode == GP_STYLE_MODE_DOTS) {
+ gp_draw_stroke_volumetric_buffer(
+ gpd->runtime.sbuffer,
+ gpd->runtime.sbuffer_size, lthick,
+ dflag, gpd->runtime.scolor);
}
else {
- gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor);
+ gp_draw_stroke_buffer(
+ gpd->runtime.sbuffer,
+ gpd->runtime.sbuffer_size, lthick,
+ dflag, gpd->runtime.sbuffer_sflag,
+ gpd->runtime.scolor, gpd->runtime.sfill);
}
}
}
}
/* draw a short status message in the top-right corner */
-static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
+static void UNUSED_FUNCTION(gp_draw_status_text)(const bGPdata *gpd, ARegion *ar)
{
rcti rect;
@@ -1483,15 +1616,16 @@ static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
const char *printable = IFACE_("GPencil Stroke Editing");
float printable_size[2];
- int xco, yco;
- BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+ int font_id = BLF_default();
+
+ BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
- xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
- yco = (rect.ymax - U.widget_unit);
+ int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
+ int yco = (rect.ymax - U.widget_unit);
/* text label */
- UI_ThemeColor(TH_TEXT_HI);
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
#ifdef WITH_INTERNATIONAL
BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#else
@@ -1500,28 +1634,25 @@ static void gp_draw_status_text(bGPdata *gpd, ARegion *ar)
/* grease pencil icon... */
// XXX: is this too intrusive?
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
xco -= U.widget_unit;
yco -= (int)printable_size[1] / 2;
UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
}
/* draw grease-pencil datablock */
-static void gp_draw_data(
- bGPDbrush *brush, float alpha, bGPdata *gpd,
+static void gp_draw_data(RegionView3D *rv3d,
+ const Brush *brush, float alpha, Object *ob, bGPdata *gpd,
int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
- /* reset line drawing style (in case previous user didn't reset) */
- setlinestyle(0);
-
/* turn on smooth lines (i.e. anti-aliasing) */
- glEnable(GL_LINE_SMOOTH);
+ GPU_line_smooth(true);
/* XXX: turn on some way of ensuring that the polygon edges get smoothed
* GL_POLYGON_SMOOTH is nasty and shouldn't be used, as it ends up
@@ -1529,49 +1660,36 @@ static void gp_draw_data(
*/
/* turn on alpha-blending */
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
/* draw! */
- gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag);
+ gp_draw_data_layers(rv3d, brush, alpha, ob, gpd, offsx, offsy, winx, winy, cfra, dflag);
/* turn off alpha blending, then smooth lines */
- glDisable(GL_BLEND); // alpha blending
- glDisable(GL_LINE_SMOOTH); // smooth lines
-
- /* restore initial gl conditions */
- glColor4f(0, 0, 0, 1);
+ GPU_blend(false); // alpha blending
+ GPU_line_smooth(false); // smooth lines
}
/* if we have strokes for scenes (3d view)/clips (movie clip editor)
* and objects/tracks, multiple data blocks have to be drawn */
-static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy,
- int cfra, int dflag, const char spacetype)
+static void gp_draw_data_all(
+ ViewLayer *view_layer, RegionView3D *rv3d, Scene *scene, bGPdata *gpd,
+ int offsx, int offsy, int winx, int winy,
+ int cfra, int dflag, const char UNUSED(spacetype))
{
bGPdata *gpd_source = NULL;
- ToolSettings *ts;
- bGPDbrush *brush = NULL;
+ Brush *brush = NULL;
+ Object *ob = OBACT(view_layer);
if (scene) {
- ts = scene->toolsettings;
- brush = BKE_gpencil_brush_getactive(ts);
- /* if no brushes, create default set */
- if (brush == NULL) {
- BKE_gpencil_brush_init_presets(ts);
- brush = BKE_gpencil_brush_getactive(ts);
- }
-
- if (spacetype == SPACE_VIEW3D) {
- gpd_source = (scene->gpd ? scene->gpd : NULL);
- }
- else if (spacetype == SPACE_CLIP && scene->clip) {
- /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */
- gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL);
- }
+ ToolSettings *ts = scene->toolsettings;
+ brush = BKE_paint_brush(&ts->gp_paint->paint);
if (gpd_source) {
if (brush != NULL) {
- gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source,
- offsx, offsy, winx, winy, cfra, dflag);
+ gp_draw_data(
+ rv3d, brush, 1.0f, ob, gpd_source,
+ offsx, offsy, winx, winy, cfra, dflag);
}
}
}
@@ -1580,152 +1698,109 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
* if gpd_source == gpd, we don't have any object/track data and we can skip */
if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
if (brush != NULL) {
- gp_draw_data(brush, ts->gp_sculpt.alpha, gpd,
- offsx, offsy, winx, winy, cfra, dflag);
+ gp_draw_data(
+ rv3d, brush, 1.0f, ob, gpd,
+ offsx, offsy, winx, winy, cfra, dflag);
}
}
}
/* ----- Grease Pencil Sketches Drawing API ------ */
-/* ............................
- * XXX
- * We need to review the calls below, since they may be/are not that suitable for
- * the new ways that we intend to be drawing data...
- * ............................ */
-/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
-void ED_gpencil_draw_2dimage(const bContext *C)
+/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
+ * Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
+ * second time with only3d=false for screen-aligned strokes */
+void ED_gpencil_draw_view3d(
+ wmWindowManager *wm,
+ Scene *scene,
+ ViewLayer *view_layer,
+ struct Depsgraph *depsgraph,
+ View3D *v3d,
+ ARegion *ar,
+ bool only3d)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- bGPdata *gpd;
- int offsx, offsy, sizex, sizey;
- int dflag = GP_DRAWDATA_NOSTATUS;
+ int dflag = 0;
+ RegionView3D *rv3d = ar->regiondata;
+ int offsx, offsy, winx, winy;
- gpd = ED_gpencil_data_get_active(C); // XXX
+ /* check that we have grease-pencil stuff to draw */
+ // XXX: This is the only place that still uses this function
+ bGPdata *gpd = ED_gpencil_data_get_active_v3d(view_layer, v3d);
if (gpd == NULL) return;
- /* calculate rect */
- switch (sa->spacetype) {
- case SPACE_IMAGE: /* image */
- case SPACE_CLIP: /* clip */
- {
+ /* when rendering to the offscreen buffer we don't want to
+ * deal with the camera border, otherwise map the coords to the camera border. */
+ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
+ rctf rectf;
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
- /* just draw using standard scaling (settings here are currently ignored anyways) */
- /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
+ offsx = round_fl_to_int(rectf.xmin);
+ offsy = round_fl_to_int(rectf.ymin);
+ winx = round_fl_to_int(rectf.xmax - rectf.xmin);
+ winy = round_fl_to_int(rectf.ymax - rectf.ymin);
+ }
+ else {
+ offsx = 0;
+ offsy = 0;
+ winx = ar->winx;
+ winy = ar->winy;
+ }
- wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax);
+ /* set flags */
+ if (only3d) {
+ /* 3D strokes/3D space:
+ * - only 3D space points
+ * - don't status text either (as it's the wrong space)
+ */
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
- dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK;
- break;
- }
- case SPACE_SEQ: /* sequence */
- {
- /* just draw using standard scaling (settings here are currently ignored anyways) */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
-
- /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated
- * and everything moved to standard View2d
- */
- dflag |= GP_DRAWDATA_ONLYV2D;
- break;
- }
- default: /* for spacetype not yet handled */
- offsx = 0;
- offsy = 0;
- sizex = ar->winx;
- sizey = ar->winy;
-
- dflag |= GP_DRAWDATA_ONLYI2D;
- break;
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ /* don't draw status text when "only render" flag is set */
+ dflag |= GP_DRAWDATA_NOSTATUS;
}
- if (ED_screen_animation_playing(wm)) {
- /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
+ if ((wm == NULL) || ED_screen_animation_playing(wm)) {
+ /* don't show onion-skins during animation playback/scrub (i.e. it obscures the poses)
* OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
*/
dflag |= GP_DRAWDATA_NO_ONIONS;
}
-
- /* draw it! */
- gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
-}
-
-/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
- * Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes,
- * second time with onlyv2d=0 for screen-aligned strokes */
-void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- bGPdata *gpd;
- int dflag = 0;
-
- /* check that we have grease-pencil stuff to draw */
- if (sa == NULL) return;
- gpd = ED_gpencil_data_get_active(C); // XXX
- if (gpd == NULL) return;
-
- /* special hack for Image Editor */
- /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */
- if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP))
- dflag |= GP_DRAWDATA_IEDITHACK;
-
/* draw it! */
- if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
- if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS;
-
- gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
-
- /* draw status text (if in screen/pixel-space) */
- if (onlyv2d == false) {
- gp_draw_status_text(gpd, ar);
- }
+ gp_draw_data_all(view_layer, rv3d, scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
}
-/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
- * Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
- * second time with only3d=0 for screen-aligned strokes */
-void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
+/* draw grease-pencil sketches to specified 3d-view for gp object
+ * assuming that matrices are already set correctly
+ */
+void ED_gpencil_draw_view3d_object(wmWindowManager *wm, Scene *scene, Depsgraph *depsgraph, Object *ob, View3D *v3d, ARegion *ar, bool only3d)
{
- bGPdata *gpd;
int dflag = 0;
RegionView3D *rv3d = ar->regiondata;
- int offsx, offsy, winx, winy;
+ int offsx, offsy, winx, winy;
/* check that we have grease-pencil stuff to draw */
- gpd = ED_gpencil_data_get_active_v3d(scene, v3d);
+ bGPdata *gpd = ob->data;
if (gpd == NULL) return;
/* when rendering to the offscreen buffer we don't want to
* deal with the camera border, otherwise map the coords to the camera border. */
if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) {
rctf rectf;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &rectf, true); /* no shift */
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */
offsx = round_fl_to_int(rectf.xmin);
offsy = round_fl_to_int(rectf.ymin);
- winx = round_fl_to_int(rectf.xmax - rectf.xmin);
- winy = round_fl_to_int(rectf.ymax - rectf.ymin);
+ winx = round_fl_to_int(rectf.xmax - rectf.xmin);
+ winy = round_fl_to_int(rectf.ymax - rectf.ymin);
}
else {
offsx = 0;
offsy = 0;
- winx = ar->winx;
- winy = ar->winy;
+ winx = ar->winx;
+ winy = ar->winy;
}
/* set flags */
@@ -1750,15 +1825,19 @@ 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);
-
+ ToolSettings *ts = scene->toolsettings;
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ if (brush != NULL) {
+ gp_draw_data(rv3d, brush, 1.0f, ob, gpd,
+ offsx, offsy, winx, winy, CFRA, dflag);
+ }
}
-void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
+void ED_gpencil_draw_ex(
+ ViewLayer *view_layer, RegionView3D *rv3d, Scene *scene,
+ bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
{
int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
- gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
+ gp_draw_data_all(view_layer, rv3d, scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype);
}
-
-/* ************************************************** */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 3a3953579a6..57bba10fa50 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -191,7 +191,7 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
}
/* select the frames in this layer that occur within the bounds specified */
-void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short select_mode)
+void ED_gplayer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
{
bGPDframe *gpf;
@@ -477,7 +477,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
gpfs->framenum += offset;
/* get frame to copy data into (if no frame returned, then just ignore) */
- gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, 1);
+ gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
if (gpf) {
bGPDstroke *gps, *gpsn;
@@ -492,6 +492,10 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* make a copy of stroke, then of its points array */
gpsn = MEM_dupallocN(gps);
gpsn->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ gpsn->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsn);
+ }
/* duplicate triangle information */
gpsn->triangles = MEM_dupallocN(gps->triangles);
/* append stroke to frame */
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
new file mode 100644
index 00000000000..048e933db9a
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -0,0 +1,1569 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Matias Mendiola
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/gpencil_add_monkey.c
+ * \ingroup edgpencil
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "ED_gpencil.h"
+
+/* Definition of the most important info from a color */
+typedef struct ColorTemplate {
+ const char *name;
+ float line[4];
+ float fill[4];
+} ColorTemplate;
+
+/* Add color an ensure duplications (matched by name) */
+static int gpencil_monkey_color(Main *bmain, Object *ob, const ColorTemplate *pct)
+{
+ short *totcol = give_totcolp(ob);
+ Material *ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ if (STREQ(ma->id.name, pct->name)) {
+ return i;
+ }
+ }
+
+ /* create a new one */
+ BKE_object_material_slot_add(bmain, ob);
+ ma = BKE_material_add_gpencil(bmain, pct->name);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+
+ copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
+ copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
+
+ return BKE_gpencil_get_material_index(ob, ma) - 1;
+}
+
+/* ***************************************************************** */
+/* Monkey Geometry */
+
+static const float data0[538 * GP_PRIM_DATABUF_SIZE] = {
+ -0.509f, 0.0f, -0.156f, 0.267f, 0.362f, -0.522f, 0.0f, -0.159f, 0.31f, 0.407f, -0.531f, 0.0f, -0.16f, 0.347f, 0.426f, -0.543f, -0.0f, -0.162f, 0.38f, 0.439f,
+ -0.554f, -0.0f, -0.163f, 0.409f, 0.448f, -0.566f, -0.0f, -0.165f, 0.433f, 0.458f, -0.578f, -0.0f, -0.167f, 0.454f, 0.478f, -0.591f, -0.0f, -0.168f, 0.471f, 0.5f,
+ -0.604f, -0.0f, -0.169f, 0.485f, 0.51f, -0.619f, -0.0f, -0.171f, 0.496f, 0.516f, -0.634f, -0.0f, -0.171f, 0.504f, 0.519f, -0.649f, -0.0f, -0.171f, 0.511f, 0.519f,
+ -0.665f, -0.0f, -0.17f, 0.516f, 0.521f, -0.681f, -0.0f, -0.17f, 0.521f, 0.53f, -0.697f, -0.0f, -0.169f, 0.524f, 0.533f, -0.713f, -0.0f, -0.167f, 0.527f, 0.533f,
+ -0.729f, 0.0f, -0.165f, 0.53f, 0.534f, -0.745f, 0.0f, -0.161f, 0.531f, 0.534f, -0.761f, 0.0f, -0.157f, 0.533f, 0.535f, -0.777f, 0.0f, -0.153f, 0.534f, 0.535f,
+ -0.792f, 0.0f, -0.148f, 0.535f, 0.536f, -0.808f, 0.0f, -0.144f, 0.535f, 0.535f, -0.822f, 0.0f, -0.139f, 0.536f, 0.537f, -0.837f, 0.0f, -0.133f, 0.536f, 0.537f,
+ -0.852f, 0.0f, -0.128f, 0.536f, 0.537f, -0.866f, 0.0f, -0.122f, 0.536f, 0.537f, -0.88f, 0.0f, -0.115f, 0.536f, 0.537f, -0.894f, 0.0f, -0.109f, 0.536f, 0.537f,
+ -0.908f, 0.0f, -0.101f, 0.535f, 0.535f, -0.922f, 0.0f, -0.092f, 0.535f, 0.535f, -0.936f, 0.0f, -0.082f, 0.534f, 0.534f, -0.949f, 0.0f, -0.072f, 0.534f, 0.534f,
+ -0.963f, 0.0f, -0.061f, 0.534f, 0.534f, -0.976f, 0.0f, -0.05f, 0.534f, 0.534f, -0.988f, 0.0f, -0.039f, 0.534f, 0.534f, -1.0f, 0.0f, -0.028f, 0.533f, 0.534f,
+ -1.011f, 0.0f, -0.017f, 0.533f, 0.533f, -1.022f, 0.0f, -0.007f, 0.533f, 0.534f, -1.033f, 0.0f, 0.004f, 0.533f, 0.533f, -1.043f, 0.0f, 0.014f, 0.532f, 0.532f,
+ -1.053f, 0.0f, 0.025f, 0.532f, 0.532f, -1.062f, 0.0f, 0.036f, 0.531f, 0.531f, -1.071f, 0.0f, 0.046f, 0.531f, 0.531f, -1.078f, 0.0f, 0.057f, 0.531f, 0.531f,
+ -1.085f, 0.0f, 0.068f, 0.531f, 0.531f, -1.092f, 0.0f, 0.08f, 0.532f, 0.532f, -1.098f, 0.0f, 0.091f, 0.533f, 0.533f, -1.104f, 0.0f, 0.105f, 0.535f, 0.535f,
+ -1.11f, 0.0f, 0.119f, 0.539f, 0.539f, -1.115f, 0.0f, 0.133f, 0.54f, 0.54f, -1.118f, 0.0f, 0.148f, 0.541f, 0.541f, -1.121f, 0.0f, 0.162f, 0.542f, 0.542f,
+ -1.123f, 0.0f, 0.177f, 0.542f, 0.542f, -1.125f, 0.0f, 0.193f, 0.543f, 0.543f, -1.125f, 0.0f, 0.208f, 0.543f, 0.543f, -1.125f, 0.0f, 0.225f, 0.543f, 0.543f,
+ -1.124f, 0.0f, 0.241f, 0.545f, 0.545f, -1.122f, 0.0f, 0.258f, 0.546f, 0.546f, -1.119f, 0.0f, 0.274f, 0.548f, 0.548f, -1.116f, 0.0f, 0.29f, 0.549f, 0.549f,
+ -1.111f, 0.0f, 0.305f, 0.549f, 0.549f, -1.106f, 0.0f, 0.318f, 0.549f, 0.549f, -1.1f, 0.0f, 0.33f, 0.549f, 0.549f, -1.094f, 0.0f, 0.34f, 0.549f, 0.549f,
+ -1.087f, 0.0f, 0.349f, 0.55f, 0.55f, -1.08f, 0.0f, 0.357f, 0.549f, 0.549f, -1.072f, 0.0f, 0.365f, 0.55f, 0.55f, -1.063f, 0.0f, 0.372f, 0.551f, 0.551f,
+ -1.054f, 0.0f, 0.379f, 0.552f, 0.552f, -1.044f, 0.0f, 0.385f, 0.553f, 0.553f, -1.034f, 0.0f, 0.391f, 0.553f, 0.553f, -1.024f, 0.0f, 0.396f, 0.554f, 0.554f,
+ -1.013f, 0.0f, 0.401f, 0.554f, 0.554f, -1.003f, 0.0f, 0.405f, 0.554f, 0.554f, -0.991f, 0.0f, 0.409f, 0.554f, 0.554f, -0.978f, 0.0f, 0.412f, 0.555f, 0.555f,
+ -0.964f, -0.0f, 0.414f, 0.555f, 0.555f, -0.949f, -0.0f, 0.414f, 0.556f, 0.556f, -0.934f, -0.0f, 0.413f, 0.556f, 0.556f, -0.919f, -0.0f, 0.412f, 0.557f, 0.557f,
+ -0.905f, -0.0f, 0.41f, 0.557f, 0.557f, -0.892f, -0.0f, 0.406f, 0.557f, 0.557f, -0.879f, -0.0f, 0.402f, 0.557f, 0.558f, -0.867f, -0.0f, 0.398f, 0.557f, 0.557f,
+ -0.855f, -0.0f, 0.394f, 0.557f, 0.557f, -0.843f, -0.0f, 0.388f, 0.557f, 0.557f, -0.831f, -0.0f, 0.381f, 0.558f, 0.557f, -0.82f, -0.0f, 0.375f, 0.558f, 0.557f,
+ -0.81f, -0.0f, 0.368f, 0.558f, 0.558f, -0.801f, -0.0f, 0.362f, 0.558f, 0.558f, -0.793f, -0.0f, 0.357f, 0.557f, 0.559f, -0.784f, 0.0f, 0.353f, 0.557f, 0.559f,
+ -0.776f, 0.0f, 0.35f, 0.556f, 0.559f, -0.768f, 0.0f, 0.348f, 0.556f, 0.559f, -0.76f, 0.0f, 0.346f, 0.555f, 0.559f, -0.752f, 0.0f, 0.346f, 0.554f, 0.559f,
+ -0.744f, 0.0f, 0.347f, 0.553f, 0.554f, -0.737f, 0.0f, 0.348f, 0.552f, 0.548f, -0.729f, 0.0f, 0.351f, 0.551f, 0.544f, -0.723f, 0.0f, 0.355f, 0.551f, 0.546f,
+ -0.716f, 0.0f, 0.36f, 0.55f, 0.546f, -0.709f, 0.0f, 0.366f, 0.55f, 0.547f, -0.702f, 0.0f, 0.372f, 0.549f, 0.547f, -0.696f, 0.0f, 0.379f, 0.549f, 0.547f,
+ -0.689f, 0.0f, 0.386f, 0.549f, 0.548f, -0.683f, 0.0f, 0.394f, 0.549f, 0.548f, -0.676f, 0.0f, 0.403f, 0.549f, 0.549f, -0.67f, 0.0f, 0.413f, 0.549f, 0.548f,
+ -0.664f, 0.0f, 0.422f, 0.549f, 0.549f, -0.658f, 0.0f, 0.432f, 0.55f, 0.549f, -0.652f, 0.0f, 0.441f, 0.551f, 0.548f, -0.646f, 0.0f, 0.451f, 0.552f, 0.548f,
+ -0.639f, 0.0f, 0.46f, 0.554f, 0.548f, -0.632f, 0.0f, 0.469f, 0.556f, 0.549f, -0.624f, 0.0f, 0.478f, 0.559f, 0.549f, -0.616f, 0.0f, 0.487f, 0.563f, 0.549f,
+ -0.609f, 0.0f, 0.497f, 0.567f, 0.549f, -0.6f, 0.0f, 0.507f, 0.572f, 0.558f, -0.592f, 0.0f, 0.518f, 0.577f, 0.574f, -0.584f, 0.0f, 0.528f, 0.582f, 0.587f,
+ -0.575f, 0.0f, 0.538f, 0.586f, 0.592f, -0.566f, 0.0f, 0.548f, 0.591f, 0.595f, -0.556f, 0.0f, 0.557f, 0.594f, 0.597f, -0.546f, 0.0f, 0.567f, 0.597f, 0.598f,
+ -0.536f, 0.0f, 0.577f, 0.6f, 0.6f, -0.525f, 0.0f, 0.586f, 0.602f, 0.603f, -0.514f, 0.0f, 0.596f, 0.604f, 0.605f, -0.503f, 0.0f, 0.606f, 0.605f, 0.606f,
+ -0.492f, 0.0f, 0.615f, 0.606f, 0.607f, -0.482f, 0.0f, 0.624f, 0.607f, 0.607f, -0.471f, 0.0f, 0.632f, 0.608f, 0.607f, -0.462f, 0.0f, 0.64f, 0.609f, 0.607f,
+ -0.453f, 0.0f, 0.647f, 0.61f, 0.61f, -0.444f, 0.0f, 0.654f, 0.612f, 0.611f, -0.435f, 0.0f, 0.66f, 0.614f, 0.613f, -0.427f, 0.0f, 0.666f, 0.616f, 0.615f,
+ -0.418f, 0.0f, 0.672f, 0.617f, 0.618f, -0.409f, 0.0f, 0.677f, 0.619f, 0.621f, -0.399f, 0.0f, 0.683f, 0.621f, 0.622f, -0.389f, 0.0f, 0.69f, 0.623f, 0.623f,
+ -0.379f, 0.0f, 0.696f, 0.624f, 0.624f, -0.368f, 0.0f, 0.702f, 0.626f, 0.626f, -0.356f, 0.0f, 0.708f, 0.628f, 0.628f, -0.345f, 0.0f, 0.713f, 0.63f, 0.63f,
+ -0.333f, 0.0f, 0.719f, 0.633f, 0.631f, -0.32f, 0.0f, 0.724f, 0.637f, 0.632f, -0.307f, 0.0f, 0.729f, 0.641f, 0.64f, -0.294f, 0.0f, 0.732f, 0.646f, 0.644f,
+ -0.281f, 0.0f, 0.736f, 0.65f, 0.655f, -0.268f, 0.0f, 0.739f, 0.654f, 0.657f, -0.255f, 0.0f, 0.742f, 0.657f, 0.658f, -0.243f, 0.0f, 0.745f, 0.659f, 0.661f,
+ -0.23f, 0.0f, 0.747f, 0.662f, 0.663f, -0.217f, 0.0f, 0.75f, 0.664f, 0.664f, -0.203f, 0.0f, 0.753f, 0.666f, 0.666f, -0.19f, 0.0f, 0.755f, 0.667f, 0.668f,
+ -0.177f, 0.0f, 0.757f, 0.669f, 0.67f, -0.163f, 0.0f, 0.76f, 0.671f, 0.671f, -0.15f, 0.0f, 0.762f, 0.673f, 0.672f, -0.136f, 0.0f, 0.764f, 0.674f, 0.674f,
+ -0.122f, 0.0f, 0.767f, 0.676f, 0.676f, -0.108f, 0.0f, 0.769f, 0.677f, 0.678f, -0.093f, 0.0f, 0.771f, 0.678f, 0.68f, -0.079f, 0.0f, 0.773f, 0.678f, 0.68f,
+ -0.064f, 0.0f, 0.774f, 0.679f, 0.679f, -0.049f, 0.0f, 0.775f, 0.68f, 0.68f, -0.033f, 0.0f, 0.775f, 0.68f, 0.68f, -0.018f, 0.0f, 0.776f, 0.68f, 0.68f,
+ -0.002f, 0.0f, 0.776f, 0.681f, 0.68f, 0.013f, 0.0f, 0.777f, 0.681f, 0.681f, 0.029f, 0.0f, 0.777f, 0.682f, 0.681f, 0.045f, 0.0f, 0.777f, 0.682f, 0.681f,
+ 0.061f, 0.0f, 0.777f, 0.683f, 0.683f, 0.077f, 0.0f, 0.776f, 0.683f, 0.683f, 0.094f, 0.0f, 0.775f, 0.684f, 0.684f, 0.11f, 0.0f, 0.774f, 0.685f, 0.683f,
+ 0.126f, 0.0f, 0.773f, 0.685f, 0.685f, 0.142f, 0.0f, 0.771f, 0.687f, 0.685f, 0.158f, 0.0f, 0.769f, 0.688f, 0.685f, 0.174f, 0.0f, 0.767f, 0.69f, 0.686f,
+ 0.19f, 0.0f, 0.765f, 0.691f, 0.692f, 0.206f, 0.0f, 0.762f, 0.693f, 0.694f, 0.222f, 0.0f, 0.757f, 0.695f, 0.696f, 0.238f, 0.0f, 0.752f, 0.697f, 0.697f,
+ 0.254f, 0.0f, 0.747f, 0.699f, 0.698f, 0.27f, 0.0f, 0.742f, 0.7f, 0.7f, 0.286f, 0.0f, 0.736f, 0.702f, 0.702f, 0.302f, 0.0f, 0.73f, 0.704f, 0.704f,
+ 0.318f, 0.0f, 0.724f, 0.705f, 0.71f, 0.335f, 0.0f, 0.717f, 0.707f, 0.71f, 0.351f, 0.0f, 0.709f, 0.708f, 0.71f, 0.367f, 0.0f, 0.701f, 0.709f, 0.711f,
+ 0.382f, 0.0f, 0.692f, 0.71f, 0.713f, 0.397f, 0.0f, 0.683f, 0.711f, 0.713f, 0.41f, 0.0f, 0.675f, 0.712f, 0.713f, 0.422f, 0.0f, 0.666f, 0.712f, 0.714f,
+ 0.434f, 0.0f, 0.658f, 0.713f, 0.714f, 0.446f, 0.0f, 0.649f, 0.714f, 0.714f, 0.458f, 0.0f, 0.641f, 0.714f, 0.714f, 0.47f, 0.0f, 0.632f, 0.715f, 0.715f,
+ 0.483f, 0.0f, 0.622f, 0.715f, 0.716f, 0.496f, 0.0f, 0.611f, 0.715f, 0.716f, 0.51f, 0.0f, 0.6f, 0.716f, 0.717f, 0.523f, 0.0f, 0.588f, 0.716f, 0.716f,
+ 0.536f, 0.0f, 0.576f, 0.717f, 0.717f, 0.55f, 0.0f, 0.563f, 0.717f, 0.717f, 0.564f, 0.0f, 0.549f, 0.717f, 0.717f, 0.577f, 0.0f, 0.536f, 0.718f, 0.717f,
+ 0.59f, 0.0f, 0.522f, 0.718f, 0.717f, 0.603f, 0.0f, 0.508f, 0.718f, 0.718f, 0.615f, 0.0f, 0.496f, 0.718f, 0.718f, 0.625f, 0.0f, 0.484f, 0.718f, 0.718f,
+ 0.635f, 0.0f, 0.473f, 0.719f, 0.718f, 0.645f, 0.0f, 0.461f, 0.719f, 0.718f, 0.654f, 0.0f, 0.45f, 0.719f, 0.718f, 0.662f, 0.0f, 0.44f, 0.719f, 0.719f,
+ 0.67f, 0.0f, 0.431f, 0.719f, 0.719f, 0.676f, 0.0f, 0.422f, 0.719f, 0.719f, 0.682f, 0.0f, 0.414f, 0.719f, 0.719f, 0.687f, 0.0f, 0.407f, 0.719f, 0.719f,
+ 0.692f, 0.0f, 0.4f, 0.719f, 0.719f, 0.697f, 0.0f, 0.394f, 0.719f, 0.719f, 0.701f, 0.0f, 0.388f, 0.718f, 0.718f, 0.705f, 0.0f, 0.383f, 0.718f, 0.717f,
+ 0.708f, 0.0f, 0.378f, 0.718f, 0.717f, 0.711f, 0.0f, 0.374f, 0.717f, 0.717f, 0.714f, 0.0f, 0.37f, 0.717f, 0.717f, 0.717f, 0.0f, 0.366f, 0.717f, 0.717f,
+ 0.719f, 0.0f, 0.362f, 0.718f, 0.717f, 0.722f, 0.0f, 0.359f, 0.718f, 0.718f, 0.724f, 0.0f, 0.356f, 0.718f, 0.717f, 0.727f, 0.0f, 0.352f, 0.717f, 0.719f,
+ 0.73f, 0.0f, 0.349f, 0.717f, 0.719f, 0.734f, 0.0f, 0.347f, 0.715f, 0.719f, 0.737f, 0.0f, 0.344f, 0.714f, 0.714f, 0.742f, 0.0f, 0.341f, 0.713f, 0.709f,
+ 0.746f, 0.0f, 0.339f, 0.714f, 0.707f, 0.751f, 0.0f, 0.336f, 0.718f, 0.704f, 0.757f, 0.0f, 0.334f, 0.724f, 0.705f, 0.763f, 0.0f, 0.332f, 0.732f, 0.705f,
+ 0.769f, -0.0f, 0.329f, 0.742f, 0.704f, 0.775f, -0.0f, 0.328f, 0.753f, 0.713f, 0.782f, -0.0f, 0.327f, 0.764f, 0.804f, 0.789f, -0.0f, 0.327f, 0.774f, 0.813f,
+ 0.797f, -0.0f, 0.327f, 0.783f, 0.815f, 0.805f, -0.0f, 0.328f, 0.791f, 0.815f, 0.814f, -0.0f, 0.329f, 0.797f, 0.816f, 0.823f, -0.0f, 0.331f, 0.802f, 0.815f,
+ 0.832f, 0.0f, 0.335f, 0.806f, 0.816f, 0.841f, 0.0f, 0.341f, 0.809f, 0.816f, 0.851f, 0.0f, 0.346f, 0.811f, 0.816f, 0.861f, 0.0f, 0.351f, 0.812f, 0.816f,
+ 0.871f, 0.0f, 0.356f, 0.813f, 0.815f, 0.881f, 0.0f, 0.361f, 0.814f, 0.816f, 0.893f, 0.0f, 0.365f, 0.814f, 0.816f, 0.906f, 0.0f, 0.368f, 0.814f, 0.817f,
+ 0.922f, 0.0f, 0.372f, 0.813f, 0.816f, 0.939f, 0.0f, 0.375f, 0.812f, 0.817f, 0.957f, 0.0f, 0.377f, 0.811f, 0.817f, 0.977f, 0.0f, 0.379f, 0.81f, 0.815f,
+ 0.995f, 0.0f, 0.38f, 0.808f, 0.813f, 1.012f, 0.0f, 0.379f, 0.806f, 0.807f, 1.028f, 0.0f, 0.377f, 0.803f, 0.803f, 1.042f, 0.0f, 0.374f, 0.8f, 0.801f,
+ 1.054f, 0.0f, 0.371f, 0.797f, 0.8f, 1.065f, 0.0f, 0.366f, 0.794f, 0.8f, 1.076f, 0.0f, 0.361f, 0.791f, 0.792f, 1.085f, 0.0f, 0.355f, 0.788f, 0.781f,
+ 1.093f, 0.0f, 0.348f, 0.785f, 0.781f, 1.1f, 0.0f, 0.34f, 0.783f, 0.78f, 1.106f, 0.0f, 0.33f, 0.782f, 0.78f, 1.113f, 0.0f, 0.321f, 0.781f, 0.778f,
+ 1.117f, 0.0f, 0.31f, 0.78f, 0.777f, 1.122f, -0.0f, 0.299f, 0.779f, 0.777f, 1.125f, -0.0f, 0.286f, 0.778f, 0.776f, 1.129f, -0.0f, 0.274f, 0.778f, 0.777f,
+ 1.131f, -0.0f, 0.262f, 0.778f, 0.777f, 1.132f, -0.0f, 0.249f, 0.777f, 0.777f, 1.134f, -0.0f, 0.237f, 0.777f, 0.778f, 1.134f, -0.0f, 0.225f, 0.777f, 0.778f,
+ 1.135f, -0.0f, 0.213f, 0.776f, 0.777f, 1.134f, -0.0f, 0.201f, 0.776f, 0.776f, 1.134f, -0.0f, 0.189f, 0.776f, 0.775f, 1.132f, -0.0f, 0.177f, 0.775f, 0.776f,
+ 1.13f, -0.0f, 0.164f, 0.775f, 0.775f, 1.129f, -0.0f, 0.152f, 0.774f, 0.774f, 1.126f, -0.0f, 0.141f, 0.774f, 0.773f, 1.122f, -0.0f, 0.13f, 0.774f, 0.772f,
+ 1.118f, -0.0f, 0.118f, 0.773f, 0.772f, 1.113f, -0.0f, 0.108f, 0.773f, 0.773f, 1.107f, -0.0f, 0.097f, 0.773f, 0.774f, 1.102f, -0.0f, 0.087f, 0.772f, 0.773f,
+ 1.095f, -0.0f, 0.077f, 0.772f, 0.773f, 1.088f, -0.0f, 0.067f, 0.771f, 0.772f, 1.081f, -0.0f, 0.057f, 0.771f, 0.773f, 1.073f, -0.0f, 0.048f, 0.77f, 0.772f,
+ 1.066f, -0.0f, 0.038f, 0.769f, 0.767f, 1.058f, -0.0f, 0.029f, 0.768f, 0.766f, 1.05f, -0.0f, 0.019f, 0.768f, 0.765f, 1.041f, -0.0f, 0.011f, 0.767f, 0.765f,
+ 1.032f, -0.0f, 0.003f, 0.767f, 0.766f, 1.023f, -0.0f, -0.004f, 0.766f, 0.765f, 1.013f, -0.0f, -0.011f, 0.766f, 0.765f, 1.003f, -0.0f, -0.019f, 0.765f, 0.766f,
+ 0.993f, -0.0f, -0.026f, 0.765f, 0.765f, 0.983f, -0.0f, -0.034f, 0.764f, 0.765f, 0.972f, -0.0f, -0.041f, 0.762f, 0.765f, 0.962f, -0.0f, -0.048f, 0.761f, 0.765f,
+ 0.951f, -0.0f, -0.055f, 0.759f, 0.762f, 0.94f, -0.0f, -0.063f, 0.756f, 0.761f, 0.929f, -0.0f, -0.07f, 0.754f, 0.755f, 0.918f, -0.0f, -0.078f, 0.751f, 0.751f,
+ 0.907f, -0.0f, -0.085f, 0.748f, 0.747f, 0.896f, -0.0f, -0.092f, 0.745f, 0.744f, 0.884f, -0.0f, -0.099f, 0.742f, 0.742f, 0.873f, -0.0f, -0.105f, 0.739f, 0.738f,
+ 0.861f, -0.0f, -0.11f, 0.736f, 0.737f, 0.849f, 0.0f, -0.115f, 0.733f, 0.731f, 0.836f, 0.0f, -0.119f, 0.73f, 0.73f, 0.823f, 0.0f, -0.124f, 0.728f, 0.727f,
+ 0.81f, 0.0f, -0.128f, 0.725f, 0.725f, 0.796f, 0.0f, -0.132f, 0.723f, 0.723f, 0.783f, 0.0f, -0.136f, 0.72f, 0.719f, 0.77f, 0.0f, -0.141f, 0.718f, 0.717f,
+ 0.756f, 0.0f, -0.145f, 0.715f, 0.712f, 0.742f, 0.0f, -0.15f, 0.713f, 0.708f, 0.728f, 0.0f, -0.152f, 0.711f, 0.707f, 0.713f, 0.0f, -0.155f, 0.709f, 0.706f,
+ 0.699f, 0.0f, -0.156f, 0.706f, 0.706f, 0.684f, 0.0f, -0.158f, 0.704f, 0.705f, 0.67f, 0.0f, -0.159f, 0.702f, 0.705f, 0.656f, 0.0f, -0.16f, 0.7f, 0.704f,
+ 0.642f, 0.0f, -0.161f, 0.698f, 0.702f, 0.628f, 0.0f, -0.161f, 0.695f, 0.698f, 0.614f, 0.0f, -0.162f, 0.693f, 0.695f, 0.6f, 0.0f, -0.162f, 0.691f, 0.691f,
+ 0.587f, 0.0f, -0.162f, 0.688f, 0.686f, 0.574f, 0.0f, -0.162f, 0.686f, 0.685f, 0.561f, 0.0f, -0.161f, 0.683f, 0.683f, 0.548f, 0.0f, -0.161f, 0.681f, 0.683f,
+ 0.535f, 0.0f, -0.161f, 0.678f, 0.678f, 0.523f, 0.0f, -0.16f, 0.676f, 0.676f, 0.512f, 0.0f, -0.16f, 0.673f, 0.674f, 0.501f, 0.0f, -0.16f, 0.671f, 0.67f,
+ 0.49f, 0.0f, -0.16f, 0.668f, 0.668f, 0.48f, 0.0f, -0.161f, 0.666f, 0.663f, 0.469f, 0.0f, -0.162f, 0.665f, 0.66f, 0.458f, 0.0f, -0.165f, 0.663f, 0.66f,
+ 0.447f, 0.0f, -0.167f, 0.662f, 0.659f, 0.437f, 0.0f, -0.171f, 0.661f, 0.659f, 0.426f, 0.0f, -0.175f, 0.66f, 0.659f, 0.415f, 0.0f, -0.18f, 0.66f, 0.659f,
+ 0.404f, 0.0f, -0.185f, 0.659f, 0.659f, 0.393f, 0.0f, -0.191f, 0.659f, 0.657f, 0.383f, 0.0f, -0.196f, 0.659f, 0.657f, 0.373f, 0.0f, -0.202f, 0.658f, 0.659f,
+ 0.363f, -0.0f, -0.208f, 0.658f, 0.658f, 0.353f, -0.0f, -0.215f, 0.658f, 0.659f, 0.344f, -0.0f, -0.223f, 0.658f, 0.659f, 0.336f, -0.0f, -0.23f, 0.658f, 0.659f,
+ 0.327f, -0.0f, -0.238f, 0.658f, 0.658f, 0.319f, -0.0f, -0.245f, 0.657f, 0.657f, 0.312f, -0.0f, -0.253f, 0.657f, 0.656f, 0.305f, -0.0f, -0.261f, 0.656f, 0.658f,
+ 0.299f, -0.0f, -0.269f, 0.655f, 0.658f, 0.293f, 0.0f, -0.278f, 0.653f, 0.657f, 0.288f, 0.0f, -0.287f, 0.65f, 0.657f, 0.283f, 0.0f, -0.295f, 0.646f, 0.656f,
+ 0.279f, 0.0f, -0.304f, 0.642f, 0.655f, 0.275f, 0.0f, -0.313f, 0.637f, 0.642f, 0.271f, 0.0f, -0.322f, 0.633f, 0.637f, 0.268f, 0.0f, -0.331f, 0.628f, 0.609f,
+ 0.265f, 0.0f, -0.341f, 0.624f, 0.607f, 0.263f, 0.0f, -0.35f, 0.62f, 0.608f, 0.261f, 0.0f, -0.359f, 0.617f, 0.608f, 0.259f, 0.0f, -0.369f, 0.614f, 0.607f,
+ 0.258f, 0.0f, -0.379f, 0.612f, 0.606f, 0.257f, 0.0f, -0.389f, 0.61f, 0.606f, 0.258f, 0.0f, -0.399f, 0.609f, 0.605f, 0.258f, 0.0f, -0.41f, 0.608f, 0.604f,
+ 0.26f, 0.0f, -0.421f, 0.608f, 0.606f, 0.263f, 0.0f, -0.431f, 0.607f, 0.606f, 0.266f, 0.0f, -0.441f, 0.607f, 0.606f, 0.27f, 0.0f, -0.452f, 0.606f, 0.607f,
+ 0.274f, 0.0f, -0.463f, 0.606f, 0.607f, 0.279f, 0.0f, -0.475f, 0.605f, 0.607f, 0.283f, 0.0f, -0.487f, 0.604f, 0.607f, 0.288f, 0.0f, -0.498f, 0.603f, 0.607f,
+ 0.293f, 0.0f, -0.511f, 0.601f, 0.607f, 0.297f, 0.0f, -0.523f, 0.598f, 0.606f, 0.301f, 0.0f, -0.536f, 0.595f, 0.605f, 0.305f, 0.0f, -0.549f, 0.591f, 0.602f,
+ 0.309f, 0.0f, -0.562f, 0.588f, 0.597f, 0.312f, 0.0f, -0.576f, 0.583f, 0.585f, 0.315f, 0.0f, -0.59f, 0.579f, 0.577f, 0.318f, 0.0f, -0.604f, 0.574f, 0.576f,
+ 0.321f, 0.0f, -0.618f, 0.569f, 0.57f, 0.323f, 0.0f, -0.633f, 0.564f, 0.564f, 0.326f, 0.0f, -0.647f, 0.559f, 0.554f, 0.328f, 0.0f, -0.663f, 0.555f, 0.549f,
+ 0.33f, 0.0f, -0.678f, 0.551f, 0.546f, 0.332f, 0.0f, -0.693f, 0.547f, 0.543f, 0.334f, 0.0f, -0.709f, 0.544f, 0.543f, 0.336f, 0.0f, -0.726f, 0.541f, 0.541f,
+ 0.338f, 0.0f, -0.742f, 0.538f, 0.54f, 0.338f, 0.0f, -0.758f, 0.536f, 0.538f, 0.338f, 0.0f, -0.773f, 0.534f, 0.53f, 0.337f, 0.0f, -0.787f, 0.532f, 0.528f,
+ 0.337f, 0.0f, -0.801f, 0.53f, 0.528f, 0.336f, 0.0f, -0.814f, 0.529f, 0.528f, 0.334f, 0.0f, -0.827f, 0.527f, 0.528f, 0.333f, 0.0f, -0.84f, 0.525f, 0.529f,
+ 0.331f, 0.0f, -0.853f, 0.523f, 0.529f, 0.328f, 0.0f, -0.866f, 0.521f, 0.528f, 0.324f, 0.0f, -0.877f, 0.519f, 0.516f, 0.32f, 0.0f, -0.889f, 0.516f, 0.515f,
+ 0.315f, 0.0f, -0.9f, 0.513f, 0.515f, 0.31f, 0.0f, -0.91f, 0.51f, 0.514f, 0.304f, 0.0f, -0.921f, 0.507f, 0.513f, 0.297f, 0.0f, -0.931f, 0.505f, 0.507f,
+ 0.289f, 0.0f, -0.94f, 0.502f, 0.498f, 0.281f, 0.0f, -0.948f, 0.499f, 0.494f, 0.272f, 0.0f, -0.956f, 0.497f, 0.491f, 0.262f, 0.0f, -0.963f, 0.495f, 0.49f,
+ 0.253f, 0.0f, -0.969f, 0.494f, 0.491f, 0.242f, 0.0f, -0.975f, 0.493f, 0.491f, 0.231f, 0.0f, -0.98f, 0.492f, 0.49f, 0.22f, 0.0f, -0.986f, 0.491f, 0.489f,
+ 0.208f, 0.0f, -0.99f, 0.491f, 0.49f, 0.195f, 0.0f, -0.994f, 0.491f, 0.491f, 0.181f, 0.0f, -0.998f, 0.491f, 0.491f, 0.168f, 0.0f, -1.001f, 0.491f, 0.492f,
+ 0.154f, 0.0f, -1.005f, 0.491f, 0.492f, 0.141f, 0.0f, -1.008f, 0.492f, 0.492f, 0.126f, 0.0f, -1.01f, 0.492f, 0.492f, 0.112f, 0.0f, -1.011f, 0.492f, 0.492f,
+ 0.097f, 0.0f, -1.013f, 0.492f, 0.492f, 0.081f, 0.0f, -1.013f, 0.492f, 0.492f, 0.066f, 0.0f, -1.014f, 0.493f, 0.493f, 0.05f, 0.0f, -1.014f, 0.493f, 0.494f,
+ 0.035f, 0.0f, -1.014f, 0.493f, 0.494f, 0.019f, 0.0f, -1.013f, 0.493f, 0.494f, 0.004f, 0.0f, -1.012f, 0.493f, 0.494f, -0.011f, 0.0f, -1.011f, 0.493f, 0.493f,
+ -0.026f, 0.0f, -1.01f, 0.492f, 0.493f, -0.041f, 0.0f, -1.008f, 0.492f, 0.492f, -0.056f, 0.0f, -1.006f, 0.492f, 0.492f, -0.07f, 0.0f, -1.004f, 0.491f, 0.492f,
+ -0.084f, 0.0f, -1.001f, 0.491f, 0.492f, -0.098f, 0.0f, -0.999f, 0.491f, 0.491f, -0.112f, 0.0f, -0.995f, 0.491f, 0.49f, -0.125f, 0.0f, -0.992f, 0.49f, 0.49f,
+ -0.138f, 0.0f, -0.987f, 0.49f, 0.491f, -0.15f, 0.0f, -0.983f, 0.49f, 0.49f, -0.162f, 0.0f, -0.978f, 0.49f, 0.49f, -0.174f, 0.0f, -0.973f, 0.489f, 0.489f,
+ -0.185f, 0.0f, -0.967f, 0.489f, 0.488f, -0.196f, 0.0f, -0.961f, 0.489f, 0.489f, -0.207f, 0.0f, -0.955f, 0.489f, 0.489f, -0.218f, 0.0f, -0.949f, 0.489f, 0.49f,
+ -0.229f, 0.0f, -0.943f, 0.489f, 0.489f, -0.24f, 0.0f, -0.936f, 0.489f, 0.489f, -0.25f, 0.0f, -0.929f, 0.489f, 0.489f, -0.261f, 0.0f, -0.922f, 0.489f, 0.489f,
+ -0.271f, 0.0f, -0.914f, 0.489f, 0.49f, -0.28f, 0.0f, -0.907f, 0.49f, 0.49f, -0.289f, 0.0f, -0.898f, 0.49f, 0.489f, -0.298f, 0.0f, -0.89f, 0.49f, 0.489f,
+ -0.306f, 0.0f, -0.882f, 0.49f, 0.49f, -0.314f, 0.0f, -0.875f, 0.491f, 0.489f, -0.322f, 0.0f, -0.866f, 0.492f, 0.489f, -0.328f, 0.0f, -0.857f, 0.492f, 0.489f,
+ -0.333f, 0.0f, -0.847f, 0.493f, 0.49f, -0.336f, 0.0f, -0.836f, 0.494f, 0.488f, -0.338f, 0.0f, -0.824f, 0.496f, 0.49f, -0.338f, 0.0f, -0.811f, 0.497f, 0.49f,
+ -0.338f, 0.0f, -0.798f, 0.499f, 0.491f, -0.337f, 0.0f, -0.785f, 0.501f, 0.497f, -0.337f, 0.0f, -0.772f, 0.503f, 0.5f, -0.337f, 0.0f, -0.759f, 0.505f, 0.504f,
+ -0.336f, -0.0f, -0.746f, 0.507f, 0.505f, -0.336f, -0.0f, -0.733f, 0.51f, 0.51f, -0.335f, -0.0f, -0.719f, 0.512f, 0.513f, -0.334f, -0.0f, -0.706f, 0.515f, 0.515f,
+ -0.333f, -0.0f, -0.692f, 0.518f, 0.516f, -0.332f, -0.0f, -0.678f, 0.52f, 0.522f, -0.331f, -0.0f, -0.665f, 0.523f, 0.523f, -0.329f, -0.0f, -0.651f, 0.525f, 0.528f,
+ -0.327f, -0.0f, -0.637f, 0.528f, 0.53f, -0.325f, -0.0f, -0.624f, 0.53f, 0.532f, -0.322f, -0.0f, -0.61f, 0.532f, 0.534f, -0.319f, -0.0f, -0.597f, 0.535f, 0.535f,
+ -0.316f, -0.0f, -0.584f, 0.537f, 0.538f, -0.313f, -0.0f, -0.57f, 0.539f, 0.54f, -0.31f, -0.0f, -0.557f, 0.541f, 0.542f, -0.307f, -0.0f, -0.544f, 0.542f, 0.545f,
+ -0.303f, -0.0f, -0.531f, 0.544f, 0.546f, -0.3f, -0.0f, -0.519f, 0.546f, 0.549f, -0.298f, -0.0f, -0.506f, 0.547f, 0.549f, -0.295f, -0.0f, -0.494f, 0.548f, 0.549f,
+ -0.292f, -0.0f, -0.482f, 0.549f, 0.55f, -0.29f, -0.0f, -0.47f, 0.55f, 0.552f, -0.287f, -0.0f, -0.459f, 0.551f, 0.552f, -0.285f, -0.0f, -0.447f, 0.551f, 0.552f,
+ -0.284f, -0.0f, -0.436f, 0.552f, 0.552f, -0.282f, -0.0f, -0.425f, 0.552f, 0.553f, -0.281f, -0.0f, -0.413f, 0.553f, 0.553f, -0.28f, -0.0f, -0.402f, 0.553f, 0.553f,
+ -0.28f, -0.0f, -0.392f, 0.553f, 0.553f, -0.281f, -0.0f, -0.381f, 0.554f, 0.553f, -0.283f, -0.0f, -0.369f, 0.554f, 0.554f, -0.286f, -0.0f, -0.359f, 0.554f, 0.554f,
+ -0.289f, -0.0f, -0.348f, 0.555f, 0.554f, -0.294f, -0.0f, -0.337f, 0.555f, 0.555f, -0.299f, -0.0f, -0.327f, 0.555f, 0.554f, -0.305f, -0.0f, -0.317f, 0.556f, 0.555f,
+ -0.312f, -0.0f, -0.307f, 0.556f, 0.555f, -0.319f, -0.0f, -0.297f, 0.556f, 0.557f, -0.326f, 0.0f, -0.287f, 0.557f, 0.558f, -0.334f, 0.0f, -0.278f, 0.557f, 0.557f,
+ -0.341f, 0.0f, -0.268f, 0.557f, 0.558f, -0.349f, 0.0f, -0.259f, 0.558f, 0.558f, -0.359f, 0.0f, -0.251f, 0.558f, 0.558f, -0.368f, 0.0f, -0.243f, 0.558f, 0.558f,
+ -0.378f, 0.0f, -0.235f, 0.558f, 0.559f, -0.388f, 0.0f, -0.228f, 0.558f, 0.558f, -0.398f, 0.0f, -0.221f, 0.559f, 0.559f, -0.408f, 0.0f, -0.214f, 0.559f, 0.559f,
+ -0.418f, 0.0f, -0.208f, 0.559f, 0.559f, -0.427f, 0.0f, -0.202f, 0.559f, 0.558f, -0.436f, 0.0f, -0.196f, 0.559f, 0.559f, -0.445f, 0.0f, -0.191f, 0.559f, 0.559f,
+ -0.453f, 0.0f, -0.187f, 0.558f, 0.559f, -0.462f, 0.0f, -0.183f, 0.558f, 0.558f, -0.469f, 0.0f, -0.18f, 0.558f, 0.558f, -0.477f, 0.0f, -0.176f, 0.558f, 0.558f,
+ -0.484f, 0.0f, -0.174f, 0.557f, 0.558f, -0.493f, 0.0f, -0.17f, 0.555f, 0.559f,
+};
+
+
+static const float data1[136 * GP_PRIM_DATABUF_SIZE] = {
+ -0.369f, 0.0f, -0.048f, 0.065f, 0.065f, -0.378f, 0.0f, -0.046f, 0.239f, 0.293f, -0.383f, 0.0f, -0.044f, 0.316f, 0.339f, -0.39f, 0.0f, -0.041f, 0.348f, 0.355f,
+ -0.398f, 0.0f, -0.038f, 0.364f, 0.368f, -0.405f, 0.0f, -0.035f, 0.373f, 0.374f, -0.413f, 0.0f, -0.031f, 0.381f, 0.381f, -0.421f, 0.0f, -0.026f, 0.388f, 0.391f,
+ -0.429f, 0.0f, -0.02f, 0.392f, 0.394f, -0.437f, 0.0f, -0.014f, 0.395f, 0.396f, -0.445f, 0.0f, -0.008f, 0.397f, 0.397f, -0.453f, 0.0f, -0.001f, 0.399f, 0.4f,
+ -0.461f, 0.0f, 0.007f, 0.401f, 0.401f, -0.468f, -0.0f, 0.016f, 0.404f, 0.404f, -0.474f, 0.0f, 0.023f, 0.406f, 0.407f, -0.479f, 0.0f, 0.03f, 0.409f, 0.409f,
+ -0.485f, 0.0f, 0.039f, 0.412f, 0.412f, -0.49f, 0.0f, 0.048f, 0.415f, 0.415f, -0.495f, 0.0f, 0.057f, 0.417f, 0.417f, -0.499f, 0.0f, 0.068f, 0.42f, 0.421f,
+ -0.503f, 0.0f, 0.079f, 0.421f, 0.421f, -0.507f, -0.0f, 0.091f, 0.423f, 0.423f, -0.51f, -0.0f, 0.102f, 0.424f, 0.424f, -0.513f, -0.0f, 0.112f, 0.424f, 0.425f,
+ -0.515f, -0.0f, 0.123f, 0.425f, 0.425f, -0.517f, -0.0f, 0.135f, 0.425f, 0.425f, -0.518f, -0.0f, 0.146f, 0.426f, 0.425f, -0.519f, -0.0f, 0.158f, 0.426f, 0.425f,
+ -0.52f, -0.0f, 0.169f, 0.426f, 0.426f, -0.52f, -0.0f, 0.181f, 0.427f, 0.427f, -0.519f, -0.0f, 0.192f, 0.427f, 0.427f, -0.518f, -0.0f, 0.203f, 0.427f, 0.427f,
+ -0.517f, -0.0f, 0.213f, 0.427f, 0.428f, -0.515f, -0.0f, 0.222f, 0.428f, 0.427f, -0.513f, -0.0f, 0.232f, 0.428f, 0.427f, -0.51f, -0.0f, 0.241f, 0.429f, 0.427f,
+ -0.508f, -0.0f, 0.25f, 0.43f, 0.428f, -0.505f, -0.0f, 0.259f, 0.431f, 0.431f, -0.501f, -0.0f, 0.267f, 0.431f, 0.432f, -0.497f, -0.0f, 0.276f, 0.432f, 0.433f,
+ -0.493f, -0.0f, 0.284f, 0.433f, 0.433f, -0.488f, -0.0f, 0.293f, 0.434f, 0.434f, -0.484f, -0.0f, 0.301f, 0.434f, 0.435f, -0.479f, -0.0f, 0.308f, 0.435f, 0.436f,
+ -0.474f, -0.0f, 0.316f, 0.435f, 0.435f, -0.468f, -0.0f, 0.322f, 0.436f, 0.436f, -0.463f, -0.0f, 0.329f, 0.436f, 0.436f, -0.457f, -0.0f, 0.335f, 0.436f, 0.436f,
+ -0.451f, -0.0f, 0.341f, 0.437f, 0.436f, -0.445f, -0.0f, 0.347f, 0.438f, 0.437f, -0.438f, -0.0f, 0.352f, 0.44f, 0.437f, -0.432f, -0.0f, 0.357f, 0.442f, 0.441f,
+ -0.426f, 0.0f, 0.362f, 0.444f, 0.446f, -0.419f, 0.0f, 0.366f, 0.445f, 0.447f, -0.413f, 0.0f, 0.369f, 0.446f, 0.447f, -0.407f, 0.0f, 0.373f, 0.446f, 0.447f,
+ -0.401f, 0.0f, 0.376f, 0.447f, 0.447f, -0.395f, 0.0f, 0.378f, 0.447f, 0.448f, -0.388f, 0.0f, 0.381f, 0.447f, 0.448f, -0.382f, 0.0f, 0.383f, 0.448f, 0.448f,
+ -0.375f, 0.0f, 0.384f, 0.448f, 0.448f, -0.369f, 0.0f, 0.386f, 0.448f, 0.448f, -0.362f, 0.0f, 0.387f, 0.448f, 0.448f, -0.355f, 0.0f, 0.388f, 0.448f, 0.448f,
+ -0.348f, 0.0f, 0.388f, 0.448f, 0.448f, -0.341f, 0.0f, 0.387f, 0.448f, 0.449f, -0.334f, 0.0f, 0.387f, 0.448f, 0.448f, -0.327f, 0.0f, 0.386f, 0.448f, 0.449f,
+ -0.32f, 0.0f, 0.384f, 0.449f, 0.449f, -0.313f, 0.0f, 0.382f, 0.449f, 0.449f, -0.307f, 0.0f, 0.38f, 0.449f, 0.449f, -0.3f, 0.0f, 0.377f, 0.449f, 0.45f,
+ -0.294f, 0.0f, 0.375f, 0.45f, 0.45f, -0.288f, -0.0f, 0.372f, 0.45f, 0.45f, -0.282f, -0.0f, 0.368f, 0.45f, 0.451f, -0.276f, -0.0f, 0.365f, 0.45f, 0.451f,
+ -0.27f, -0.0f, 0.361f, 0.45f, 0.451f, -0.264f, -0.0f, 0.357f, 0.45f, 0.451f, -0.258f, -0.0f, 0.352f, 0.45f, 0.45f, -0.251f, -0.0f, 0.347f, 0.45f, 0.451f,
+ -0.245f, -0.0f, 0.341f, 0.451f, 0.451f, -0.24f, -0.0f, 0.335f, 0.451f, 0.451f, -0.234f, -0.0f, 0.329f, 0.451f, 0.451f, -0.228f, -0.0f, 0.323f, 0.452f, 0.452f,
+ -0.223f, -0.0f, 0.316f, 0.452f, 0.453f, -0.218f, -0.0f, 0.309f, 0.452f, 0.453f, -0.213f, -0.0f, 0.301f, 0.453f, 0.453f, -0.208f, -0.0f, 0.294f, 0.453f, 0.453f,
+ -0.204f, -0.0f, 0.286f, 0.453f, 0.453f, -0.2f, -0.0f, 0.277f, 0.453f, 0.454f, -0.196f, -0.0f, 0.269f, 0.453f, 0.454f, -0.192f, -0.0f, 0.26f, 0.454f, 0.454f,
+ -0.189f, -0.0f, 0.25f, 0.454f, 0.454f, -0.186f, -0.0f, 0.241f, 0.454f, 0.455f, -0.183f, -0.0f, 0.231f, 0.454f, 0.455f, -0.181f, -0.0f, 0.221f, 0.454f, 0.455f,
+ -0.179f, -0.0f, 0.209f, 0.455f, 0.455f, -0.177f, -0.0f, 0.197f, 0.455f, 0.455f, -0.176f, -0.0f, 0.184f, 0.455f, 0.455f, -0.176f, -0.0f, 0.171f, 0.455f, 0.456f,
+ -0.176f, -0.0f, 0.158f, 0.455f, 0.456f, -0.177f, -0.0f, 0.145f, 0.455f, 0.456f, -0.178f, -0.0f, 0.132f, 0.455f, 0.456f, -0.18f, -0.0f, 0.12f, 0.456f, 0.456f,
+ -0.182f, -0.0f, 0.108f, 0.456f, 0.456f, -0.185f, -0.0f, 0.097f, 0.456f, 0.456f, -0.188f, -0.0f, 0.086f, 0.456f, 0.457f, -0.191f, -0.0f, 0.076f, 0.456f, 0.457f,
+ -0.194f, -0.0f, 0.067f, 0.457f, 0.457f, -0.198f, -0.0f, 0.058f, 0.457f, 0.457f, -0.202f, -0.0f, 0.05f, 0.457f, 0.457f, -0.206f, -0.0f, 0.042f, 0.457f, 0.457f,
+ -0.21f, -0.0f, 0.034f, 0.458f, 0.457f, -0.215f, -0.0f, 0.027f, 0.458f, 0.457f, -0.22f, -0.0f, 0.02f, 0.458f, 0.458f, -0.225f, -0.0f, 0.014f, 0.458f, 0.458f,
+ -0.23f, -0.0f, 0.007f, 0.458f, 0.458f, -0.235f, -0.0f, 0.002f, 0.459f, 0.458f, -0.24f, -0.0f, -0.004f, 0.459f, 0.458f, -0.246f, -0.0f, -0.009f, 0.46f, 0.459f,
+ -0.251f, 0.0f, -0.013f, 0.464f, 0.463f, -0.257f, 0.0f, -0.018f, 0.467f, 0.468f, -0.262f, 0.0f, -0.022f, 0.469f, 0.469f, -0.268f, 0.0f, -0.026f, 0.471f, 0.47f,
+ -0.274f, 0.0f, -0.029f, 0.477f, 0.478f, -0.28f, 0.0f, -0.033f, 0.478f, 0.478f, -0.286f, 0.0f, -0.036f, 0.478f, 0.478f, -0.292f, 0.0f, -0.038f, 0.479f, 0.479f,
+ -0.298f, 0.0f, -0.041f, 0.48f, 0.48f, -0.305f, 0.0f, -0.043f, 0.48f, 0.48f, -0.311f, 0.0f, -0.045f, 0.482f, 0.482f, -0.318f, 0.0f, -0.047f, 0.482f, 0.482f,
+ -0.324f, 0.0f, -0.048f, 0.482f, 0.482f, -0.331f, 0.0f, -0.049f, 0.48f, 0.482f, -0.336f, 0.0f, -0.05f, 0.457f, 0.485f, -0.344f, 0.0f, -0.05f, 0.32f, 0.32f,
+};
+
+static const float data2[2 * GP_PRIM_DATABUF_SIZE] = {
+ -0.512f, 0.0f, -0.168f, 0.545f, 0.557f, -0.521f, 0.0f, -0.167f, 0.535f, 0.558f,
+};
+
+static const float data3[1 * GP_PRIM_DATABUF_SIZE] = {
+ -1.014f, 0.0f, 0.186f, 0.0f, 0.003f,
+};
+
+static const float data4[1 * GP_PRIM_DATABUF_SIZE] = {
+ -1.014f, 0.0f, 0.186f, 0.02f, 0.02f,
+};
+
+static const float data5[48 * GP_PRIM_DATABUF_SIZE] = {
+ -1.014f, 0.0f, 0.187f, 0.066f, 0.066f, -1.013f, 0.0f, 0.2f, 0.222f, 0.356f, -1.01f, 0.0f, 0.208f, 0.295f, 0.404f, -1.006f, 0.0f, 0.218f, 0.354f, 0.431f,
+ -1.001f, 0.0f, 0.226f, 0.392f, 0.445f, -0.994f, 0.0f, 0.233f, 0.418f, 0.453f, -0.987f, 0.0f, 0.238f, 0.437f, 0.457f, -0.979f, 0.0f, 0.242f, 0.45f, 0.47f,
+ -0.97f, 0.0f, 0.245f, 0.459f, 0.473f, -0.96f, -0.0f, 0.246f, 0.465f, 0.474f, -0.951f, -0.0f, 0.245f, 0.469f, 0.475f, -0.942f, 0.0f, 0.242f, 0.471f, 0.473f,
+ -0.932f, 0.0f, 0.239f, 0.472f, 0.474f, -0.924f, 0.0f, 0.234f, 0.471f, 0.474f, -0.915f, 0.0f, 0.228f, 0.469f, 0.474f, -0.906f, 0.0f, 0.22f, 0.464f, 0.47f,
+ -0.898f, 0.0f, 0.212f, 0.458f, 0.46f, -0.89f, 0.0f, 0.203f, 0.451f, 0.453f, -0.882f, 0.0f, 0.193f, 0.443f, 0.443f, -0.875f, 0.0f, 0.182f, 0.435f, 0.437f,
+ -0.869f, 0.0f, 0.172f, 0.426f, 0.428f, -0.863f, 0.0f, 0.161f, 0.417f, 0.415f, -0.858f, 0.0f, 0.148f, 0.409f, 0.41f, -0.854f, 0.0f, 0.137f, 0.399f, 0.399f,
+ -0.85f, 0.0f, 0.126f, 0.39f, 0.392f, -0.847f, 0.0f, 0.116f, 0.379f, 0.386f, -0.846f, 0.0f, 0.109f, 0.369f, 0.371f, -0.846f, 0.0f, 0.104f, 0.361f, 0.357f,
+ -0.847f, 0.0f, 0.101f, 0.355f, 0.339f, -0.849f, 0.0f, 0.101f, 0.353f, 0.334f, -0.853f, 0.0f, 0.103f, 0.354f, 0.345f, -0.859f, 0.0f, 0.108f, 0.357f, 0.35f,
+ -0.865f, 0.0f, 0.116f, 0.363f, 0.365f, -0.873f, 0.0f, 0.126f, 0.369f, 0.375f, -0.881f, 0.0f, 0.137f, 0.375f, 0.379f, -0.89f, 0.0f, 0.149f, 0.381f, 0.38f,
+ -0.899f, 0.0f, 0.159f, 0.387f, 0.385f, -0.908f, 0.0f, 0.168f, 0.394f, 0.394f, -0.919f, 0.0f, 0.177f, 0.401f, 0.398f, -0.932f, 0.0f, 0.184f, 0.409f, 0.404f,
+ -0.945f, 0.0f, 0.191f, 0.418f, 0.415f, -0.958f, 0.0f, 0.195f, 0.427f, 0.431f, -0.969f, 0.0f, 0.197f, 0.434f, 0.443f, -0.979f, 0.0f, 0.197f, 0.436f, 0.445f,
+ -0.987f, 0.0f, 0.195f, 0.428f, 0.463f, -0.995f, 0.0f, 0.192f, 0.398f, 0.46f, -1.001f, 0.0f, 0.189f, 0.345f, 0.465f, -1.01f, 0.0f, 0.183f, 0.236f, 0.236f,
+};
+
+static const float data6[47 * GP_PRIM_DATABUF_SIZE] = {
+ 0.022f, 0.0f, -0.353f, 0.125f, 0.125f, 0.012f, 0.0f, -0.352f, 0.175f, 0.288f, 0.004f, 0.0f, -0.352f, 0.206f, 0.313f, -0.006f, 0.0f, -0.352f, 0.241f, 0.323f,
+ -0.017f, 0.0f, -0.352f, 0.27f, 0.33f, -0.029f, 0.0f, -0.351f, 0.295f, 0.334f, -0.041f, 0.0f, -0.349f, 0.314f, 0.337f, -0.052f, 0.0f, -0.344f, 0.327f, 0.341f,
+ -0.063f, 0.0f, -0.337f, 0.336f, 0.344f, -0.072f, 0.0f, -0.329f, 0.341f, 0.345f, -0.081f, 0.0f, -0.32f, 0.345f, 0.345f, -0.088f, 0.0f, -0.311f, 0.348f, 0.345f,
+ -0.093f, 0.0f, -0.303f, 0.352f, 0.347f, -0.098f, 0.0f, -0.295f, 0.356f, 0.352f, -0.101f, 0.0f, -0.287f, 0.361f, 0.357f, -0.102f, 0.0f, -0.279f, 0.367f, 0.364f,
+ -0.103f, 0.0f, -0.271f, 0.373f, 0.378f, -0.102f, 0.0f, -0.263f, 0.379f, 0.382f, -0.1f, 0.0f, -0.255f, 0.383f, 0.389f, -0.098f, 0.0f, -0.247f, 0.387f, 0.391f,
+ -0.094f, 0.0f, -0.24f, 0.389f, 0.393f, -0.09f, 0.0f, -0.233f, 0.391f, 0.393f, -0.086f, 0.0f, -0.227f, 0.392f, 0.393f, -0.082f, 0.0f, -0.222f, 0.393f, 0.393f,
+ -0.078f, 0.0f, -0.219f, 0.394f, 0.393f, -0.075f, 0.0f, -0.217f, 0.397f, 0.393f, -0.072f, 0.0f, -0.217f, 0.4f, 0.393f, -0.07f, 0.0f, -0.219f, 0.402f, 0.408f,
+ -0.069f, 0.0f, -0.222f, 0.404f, 0.408f, -0.069f, 0.0f, -0.228f, 0.406f, 0.409f, -0.069f, 0.0f, -0.234f, 0.407f, 0.409f, -0.07f, 0.0f, -0.241f, 0.408f, 0.409f,
+ -0.07f, 0.0f, -0.248f, 0.408f, 0.409f, -0.07f, 0.0f, -0.256f, 0.409f, 0.409f, -0.07f, 0.0f, -0.263f, 0.409f, 0.41f, -0.069f, 0.0f, -0.271f, 0.41f, 0.411f,
+ -0.068f, 0.0f, -0.279f, 0.41f, 0.411f, -0.065f, 0.0f, -0.287f, 0.41f, 0.411f, -0.062f, 0.0f, -0.295f, 0.409f, 0.411f, -0.057f, 0.0f, -0.303f, 0.409f, 0.409f,
+ -0.052f, 0.0f, -0.31f, 0.408f, 0.409f, -0.047f, 0.0f, -0.318f, 0.407f, 0.408f, -0.041f, 0.0f, -0.324f, 0.406f, 0.407f, -0.035f, 0.0f, -0.329f, 0.403f, 0.407f,
+ -0.027f, 0.0f, -0.333f, 0.4f, 0.408f, -0.021f, 0.0f, -0.336f, 0.398f, 0.403f, -0.012f, 0.0f, -0.339f, 0.393f, 0.393f,
+};
+
+static const float data7[162 * GP_PRIM_DATABUF_SIZE] = {
+ -0.291f, 0.0f, -0.34f, 0.093f, 0.093f, -0.289f, -0.0f, -0.35f, 0.149f, 0.176f, -0.287f, -0.0f, -0.357f, 0.182f, 0.242f, -0.284f, -0.0f, -0.365f, 0.215f, 0.257f,
+ -0.281f, -0.0f, -0.374f, 0.242f, 0.266f, -0.278f, -0.0f, -0.384f, 0.266f, 0.287f, -0.275f, -0.0f, -0.394f, 0.285f, 0.304f, -0.271f, 0.0f, -0.405f, 0.302f, 0.316f,
+ -0.267f, 0.0f, -0.417f, 0.317f, 0.326f, -0.263f, 0.0f, -0.429f, 0.33f, 0.337f, -0.259f, 0.0f, -0.442f, 0.342f, 0.346f, -0.256f, 0.0f, -0.454f, 0.354f, 0.351f,
+ -0.253f, 0.0f, -0.467f, 0.365f, 0.362f, -0.251f, 0.0f, -0.48f, 0.376f, 0.38f, -0.249f, -0.0f, -0.493f, 0.386f, 0.391f, -0.247f, -0.0f, -0.505f, 0.394f, 0.396f,
+ -0.246f, -0.0f, -0.518f, 0.401f, 0.405f, -0.245f, 0.0f, -0.53f, 0.408f, 0.409f, -0.245f, 0.0f, -0.542f, 0.415f, 0.413f, -0.245f, 0.0f, -0.554f, 0.421f, 0.42f,
+ -0.245f, 0.0f, -0.565f, 0.426f, 0.43f, -0.246f, 0.0f, -0.575f, 0.43f, 0.433f, -0.246f, -0.0f, -0.585f, 0.432f, 0.435f, -0.247f, -0.0f, -0.594f, 0.434f, 0.436f,
+ -0.247f, -0.0f, -0.603f, 0.435f, 0.436f, -0.248f, -0.0f, -0.612f, 0.436f, 0.436f, -0.25f, -0.0f, -0.621f, 0.437f, 0.438f, -0.252f, -0.0f, -0.631f, 0.437f, 0.438f,
+ -0.254f, -0.0f, -0.642f, 0.438f, 0.438f, -0.255f, 0.0f, -0.653f, 0.438f, 0.438f, -0.258f, 0.0f, -0.664f, 0.438f, 0.439f, -0.26f, 0.0f, -0.674f, 0.439f, 0.439f,
+ -0.261f, 0.0f, -0.685f, 0.439f, 0.439f, -0.262f, 0.0f, -0.696f, 0.439f, 0.439f, -0.264f, 0.0f, -0.706f, 0.439f, 0.439f, -0.265f, 0.0f, -0.717f, 0.439f, 0.439f,
+ -0.265f, 0.0f, -0.727f, 0.438f, 0.439f, -0.266f, 0.0f, -0.738f, 0.437f, 0.439f, -0.266f, 0.0f, -0.749f, 0.435f, 0.438f, -0.266f, 0.0f, -0.76f, 0.433f, 0.433f,
+ -0.265f, 0.0f, -0.771f, 0.431f, 0.428f, -0.265f, 0.0f, -0.781f, 0.43f, 0.428f, -0.263f, 0.0f, -0.792f, 0.429f, 0.428f, -0.26f, 0.0f, -0.802f, 0.428f, 0.429f,
+ -0.257f, 0.0f, -0.812f, 0.426f, 0.427f, -0.254f, 0.0f, -0.821f, 0.423f, 0.426f, -0.25f, 0.0f, -0.829f, 0.421f, 0.42f, -0.247f, 0.0f, -0.837f, 0.418f, 0.416f,
+ -0.242f, 0.0f, -0.844f, 0.417f, 0.415f, -0.238f, 0.0f, -0.85f, 0.415f, 0.413f, -0.234f, 0.0f, -0.857f, 0.415f, 0.413f, -0.229f, 0.0f, -0.864f, 0.414f, 0.413f,
+ -0.224f, 0.0f, -0.87f, 0.414f, 0.413f, -0.219f, 0.0f, -0.877f, 0.414f, 0.414f, -0.214f, 0.0f, -0.883f, 0.414f, 0.413f, -0.208f, 0.0f, -0.89f, 0.413f, 0.413f,
+ -0.203f, 0.0f, -0.897f, 0.413f, 0.413f, -0.197f, 0.0f, -0.903f, 0.413f, 0.413f, -0.191f, 0.0f, -0.909f, 0.413f, 0.413f, -0.186f, 0.0f, -0.914f, 0.413f, 0.413f,
+ -0.181f, 0.0f, -0.92f, 0.413f, 0.413f, -0.175f, -0.0f, -0.925f, 0.413f, 0.413f, -0.17f, -0.0f, -0.931f, 0.413f, 0.413f, -0.164f, -0.0f, -0.936f, 0.413f, 0.413f,
+ -0.159f, -0.0f, -0.942f, 0.413f, 0.413f, -0.152f, -0.0f, -0.948f, 0.413f, 0.413f, -0.145f, -0.0f, -0.955f, 0.413f, 0.413f, -0.137f, -0.0f, -0.961f, 0.414f, 0.413f,
+ -0.13f, -0.0f, -0.967f, 0.414f, 0.413f, -0.122f, -0.0f, -0.974f, 0.414f, 0.414f, -0.114f, -0.0f, -0.979f, 0.414f, 0.413f, -0.106f, -0.0f, -0.985f, 0.414f, 0.413f,
+ -0.098f, -0.0f, -0.989f, 0.414f, 0.414f, -0.091f, -0.0f, -0.993f, 0.414f, 0.413f, -0.083f, -0.0f, -0.997f, 0.414f, 0.414f, -0.075f, -0.0f, -0.999f, 0.414f, 0.414f,
+ -0.066f, -0.0f, -1.001f, 0.414f, 0.414f, -0.057f, -0.0f, -1.003f, 0.414f, 0.413f, -0.046f, -0.0f, -1.006f, 0.414f, 0.413f, -0.038f, -0.0f, -1.008f, 0.414f, 0.413f,
+ -0.031f, -0.0f, -1.009f, 0.421f, 0.413f, -0.036f, -0.0f, -1.008f, 0.423f, 0.424f, -0.045f, -0.0f, -1.006f, 0.425f, 0.425f, -0.054f, -0.0f, -1.005f, 0.425f, 0.425f,
+ -0.064f, -0.0f, -1.005f, 0.425f, 0.425f, -0.073f, -0.0f, -1.004f, 0.425f, 0.425f, -0.084f, -0.0f, -1.003f, 0.425f, 0.425f, -0.095f, -0.0f, -1.001f, 0.424f, 0.424f,
+ -0.105f, -0.0f, -0.997f, 0.423f, 0.424f, -0.116f, -0.0f, -0.994f, 0.422f, 0.422f, -0.127f, -0.0f, -0.991f, 0.421f, 0.419f, -0.137f, -0.0f, -0.987f, 0.42f, 0.419f,
+ -0.148f, -0.0f, -0.983f, 0.42f, 0.419f, -0.158f, -0.0f, -0.98f, 0.42f, 0.419f, -0.167f, -0.0f, -0.976f, 0.419f, 0.419f, -0.176f, -0.0f, -0.973f, 0.419f, 0.419f,
+ -0.184f, -0.0f, -0.969f, 0.419f, 0.419f, -0.192f, -0.0f, -0.966f, 0.419f, 0.418f, -0.2f, 0.0f, -0.962f, 0.419f, 0.418f, -0.207f, 0.0f, -0.957f, 0.419f, 0.419f,
+ -0.215f, 0.0f, -0.953f, 0.419f, 0.418f, -0.223f, 0.0f, -0.948f, 0.419f, 0.419f, -0.231f, 0.0f, -0.944f, 0.419f, 0.419f, -0.239f, 0.0f, -0.939f, 0.419f, 0.419f,
+ -0.247f, 0.0f, -0.934f, 0.419f, 0.419f, -0.255f, 0.0f, -0.929f, 0.419f, 0.419f, -0.262f, 0.0f, -0.924f, 0.419f, 0.419f, -0.269f, 0.0f, -0.919f, 0.419f, 0.418f,
+ -0.275f, 0.0f, -0.914f, 0.419f, 0.419f, -0.281f, 0.0f, -0.909f, 0.419f, 0.418f, -0.287f, 0.0f, -0.904f, 0.419f, 0.418f, -0.293f, 0.0f, -0.899f, 0.419f, 0.418f,
+ -0.299f, 0.0f, -0.894f, 0.42f, 0.419f, -0.304f, 0.0f, -0.888f, 0.421f, 0.42f, -0.311f, 0.0f, -0.882f, 0.423f, 0.422f, -0.317f, 0.0f, -0.876f, 0.424f, 0.424f,
+ -0.322f, 0.0f, -0.869f, 0.426f, 0.426f, -0.328f, 0.0f, -0.861f, 0.427f, 0.427f, -0.332f, 0.0f, -0.853f, 0.429f, 0.429f, -0.336f, 0.0f, -0.843f, 0.43f, 0.429f,
+ -0.339f, 0.0f, -0.834f, 0.432f, 0.431f, -0.341f, 0.0f, -0.821f, 0.435f, 0.434f, -0.342f, 0.0f, -0.809f, 0.438f, 0.439f, -0.343f, 0.0f, -0.796f, 0.44f, 0.44f,
+ -0.343f, 0.0f, -0.783f, 0.442f, 0.442f, -0.343f, 0.0f, -0.772f, 0.446f, 0.445f, -0.342f, 0.0f, -0.76f, 0.45f, 0.45f, -0.342f, 0.0f, -0.748f, 0.454f, 0.455f,
+ -0.34f, 0.0f, -0.735f, 0.457f, 0.457f, -0.339f, 0.0f, -0.723f, 0.46f, 0.46f, -0.338f, 0.0f, -0.711f, 0.463f, 0.464f, -0.336f, 0.0f, -0.7f, 0.465f, 0.465f,
+ -0.335f, 0.0f, -0.688f, 0.466f, 0.466f, -0.332f, 0.0f, -0.676f, 0.467f, 0.467f, -0.331f, 0.0f, -0.664f, 0.467f, 0.467f, -0.33f, 0.0f, -0.651f, 0.467f, 0.467f,
+ -0.328f, 0.0f, -0.638f, 0.467f, 0.467f, -0.325f, 0.0f, -0.625f, 0.467f, 0.467f, -0.323f, 0.0f, -0.614f, 0.467f, 0.467f, -0.321f, 0.0f, -0.603f, 0.467f, 0.466f,
+ -0.318f, 0.0f, -0.592f, 0.467f, 0.466f, -0.315f, 0.0f, -0.581f, 0.467f, 0.466f, -0.313f, 0.0f, -0.569f, 0.467f, 0.467f, -0.311f, -0.0f, -0.557f, 0.467f, 0.467f,
+ -0.309f, -0.0f, -0.543f, 0.467f, 0.467f, -0.306f, -0.0f, -0.531f, 0.467f, 0.467f, -0.303f, -0.0f, -0.519f, 0.467f, 0.467f, -0.301f, -0.0f, -0.507f, 0.467f, 0.468f,
+ -0.299f, -0.0f, -0.497f, 0.467f, 0.467f, -0.297f, -0.0f, -0.487f, 0.467f, 0.467f, -0.295f, 0.0f, -0.476f, 0.465f, 0.467f, -0.293f, 0.0f, -0.466f, 0.463f, 0.467f,
+ -0.292f, 0.0f, -0.456f, 0.46f, 0.466f, -0.291f, 0.0f, -0.445f, 0.455f, 0.459f, -0.29f, 0.0f, -0.435f, 0.449f, 0.457f, -0.29f, 0.0f, -0.424f, 0.44f, 0.448f,
+ -0.29f, 0.0f, -0.413f, 0.43f, 0.44f, -0.29f, 0.0f, -0.403f, 0.418f, 0.437f, -0.29f, -0.0f, -0.393f, 0.404f, 0.415f, -0.291f, -0.0f, -0.384f, 0.388f, 0.393f,
+ -0.29f, -0.0f, -0.376f, 0.374f, 0.379f, -0.29f, -0.0f, -0.365f, 0.352f, 0.352f,
+};
+
+static const float data8[55 * GP_PRIM_DATABUF_SIZE] = {
+ 0.781f, 0.0f, 0.098f, 0.109f, 0.109f, 0.784f, 0.0f, 0.105f, 0.202f, 0.338f, 0.785f, 0.0f, 0.108f, 0.254f, 0.369f, 0.787f, 0.0f, 0.113f, 0.306f, 0.382f,
+ 0.787f, 0.0f, 0.118f, 0.344f, 0.392f, 0.789f, 0.0f, 0.123f, 0.372f, 0.401f, 0.79f, 0.0f, 0.128f, 0.392f, 0.41f, 0.792f, 0.0f, 0.135f, 0.406f, 0.42f,
+ 0.794f, 0.0f, 0.142f, 0.416f, 0.424f, 0.797f, 0.0f, 0.152f, 0.424f, 0.428f, 0.801f, 0.0f, 0.161f, 0.429f, 0.431f, 0.807f, 0.0f, 0.172f, 0.432f, 0.435f,
+ 0.814f, 0.0f, 0.182f, 0.435f, 0.438f, 0.821f, 0.0f, 0.19f, 0.437f, 0.439f, 0.828f, 0.0f, 0.197f, 0.439f, 0.44f, 0.836f, 0.0f, 0.204f, 0.44f, 0.441f,
+ 0.845f, -0.0f, 0.211f, 0.44f, 0.441f, 0.853f, -0.0f, 0.215f, 0.441f, 0.441f, 0.861f, -0.0f, 0.219f, 0.441f, 0.441f, 0.87f, -0.0f, 0.222f, 0.441f, 0.442f,
+ 0.878f, -0.0f, 0.224f, 0.441f, 0.442f, 0.886f, -0.0f, 0.226f, 0.441f, 0.442f, 0.895f, -0.0f, 0.227f, 0.44f, 0.442f, 0.903f, 0.0f, 0.226f, 0.439f, 0.441f,
+ 0.911f, 0.0f, 0.225f, 0.436f, 0.441f, 0.919f, 0.0f, 0.224f, 0.432f, 0.441f, 0.927f, 0.0f, 0.221f, 0.425f, 0.436f, 0.934f, 0.0f, 0.218f, 0.415f, 0.429f,
+ 0.94f, 0.0f, 0.215f, 0.404f, 0.406f, 0.944f, 0.0f, 0.211f, 0.393f, 0.389f, 0.947f, 0.0f, 0.208f, 0.384f, 0.378f, 0.948f, 0.0f, 0.204f, 0.376f, 0.371f,
+ 0.946f, 0.0f, 0.2f, 0.369f, 0.364f, 0.943f, 0.0f, 0.196f, 0.365f, 0.358f, 0.937f, 0.0f, 0.193f, 0.364f, 0.354f, 0.931f, 0.0f, 0.189f, 0.366f, 0.359f,
+ 0.925f, 0.0f, 0.186f, 0.37f, 0.367f, 0.917f, 0.0f, 0.182f, 0.374f, 0.375f, 0.908f, 0.0f, 0.177f, 0.378f, 0.382f, 0.899f, 0.0f, 0.172f, 0.381f, 0.384f,
+ 0.889f, 0.0f, 0.167f, 0.384f, 0.385f, 0.876f, 0.0f, 0.163f, 0.387f, 0.387f, 0.864f, 0.0f, 0.156f, 0.39f, 0.388f, 0.852f, 0.0f, 0.15f, 0.393f, 0.39f,
+ 0.841f, 0.0f, 0.144f, 0.396f, 0.396f, 0.832f, 0.0f, 0.138f, 0.399f, 0.401f, 0.826f, 0.0f, 0.133f, 0.401f, 0.404f, 0.82f, 0.0f, 0.127f, 0.403f, 0.405f,
+ 0.816f, 0.0f, 0.122f, 0.403f, 0.407f, 0.812f, 0.0f, 0.119f, 0.399f, 0.406f, 0.808f, 0.0f, 0.115f, 0.39f, 0.405f, 0.805f, 0.0f, 0.113f, 0.371f, 0.407f,
+ 0.801f, 0.0f, 0.111f, 0.341f, 0.407f, 0.799f, 0.0f, 0.109f, 0.309f, 0.405f, 0.795f, 0.0f, 0.106f, 0.255f, 0.255f,
+};
+
+static const float data9[70 * GP_PRIM_DATABUF_SIZE] = {
+ 0.819f, -0.0f, 0.325f, 0.109f, 0.109f, 0.829f, -0.0f, 0.328f, 0.258f, 0.403f, 0.835f, -0.0f, 0.329f, 0.327f, 0.428f, 0.843f, -0.0f, 0.331f, 0.383f, 0.452f,
+ 0.851f, -0.0f, 0.332f, 0.419f, 0.465f, 0.861f, -0.0f, 0.334f, 0.444f, 0.473f, 0.87f, -0.0f, 0.336f, 0.461f, 0.48f, 0.881f, -0.0f, 0.337f, 0.473f, 0.486f,
+ 0.892f, -0.0f, 0.339f, 0.482f, 0.496f, 0.904f, -0.0f, 0.341f, 0.489f, 0.501f, 0.917f, -0.0f, 0.342f, 0.494f, 0.503f, 0.931f, -0.0f, 0.342f, 0.498f, 0.505f,
+ 0.945f, -0.0f, 0.342f, 0.501f, 0.505f, 0.958f, -0.0f, 0.342f, 0.503f, 0.506f, 0.971f, -0.0f, 0.341f, 0.505f, 0.506f, 0.984f, -0.0f, 0.341f, 0.506f, 0.506f,
+ 0.997f, -0.0f, 0.339f, 0.507f, 0.508f, 1.009f, -0.0f, 0.337f, 0.507f, 0.507f, 1.021f, -0.0f, 0.333f, 0.508f, 0.508f, 1.033f, -0.0f, 0.33f, 0.508f, 0.508f,
+ 1.044f, -0.0f, 0.326f, 0.508f, 0.508f, 1.056f, -0.0f, 0.322f, 0.508f, 0.508f, 1.068f, -0.0f, 0.317f, 0.508f, 0.508f, 1.078f, -0.0f, 0.311f, 0.507f, 0.508f,
+ 1.089f, -0.0f, 0.304f, 0.506f, 0.508f, 1.099f, 0.0f, 0.294f, 0.503f, 0.506f, 1.107f, 0.0f, 0.287f, 0.498f, 0.506f, 1.113f, 0.0f, 0.28f, 0.49f, 0.505f,
+ 1.117f, 0.0f, 0.276f, 0.48f, 0.501f, 1.121f, 0.0f, 0.272f, 0.468f, 0.492f, 1.124f, 0.0f, 0.27f, 0.455f, 0.467f, 1.127f, 0.0f, 0.27f, 0.443f, 0.431f,
+ 1.129f, 0.0f, 0.271f, 0.431f, 0.4f, 1.13f, 0.0f, 0.274f, 0.422f, 0.399f, 1.13f, 0.0f, 0.278f, 0.414f, 0.399f, 1.13f, 0.0f, 0.286f, 0.408f, 0.399f,
+ 1.128f, 0.0f, 0.295f, 0.404f, 0.399f, 1.124f, 0.0f, 0.305f, 0.402f, 0.399f, 1.119f, 0.0f, 0.316f, 0.403f, 0.4f, 1.113f, -0.0f, 0.327f, 0.405f, 0.401f,
+ 1.107f, -0.0f, 0.337f, 0.408f, 0.411f, 1.1f, -0.0f, 0.345f, 0.412f, 0.412f, 1.094f, -0.0f, 0.352f, 0.416f, 0.413f, 1.087f, -0.0f, 0.357f, 0.421f, 0.422f,
+ 1.08f, -0.0f, 0.363f, 0.426f, 0.428f, 1.071f, -0.0f, 0.368f, 0.429f, 0.43f, 1.062f, -0.0f, 0.373f, 0.431f, 0.431f, 1.051f, -0.0f, 0.377f, 0.433f, 0.431f,
+ 1.039f, -0.0f, 0.381f, 0.436f, 0.437f, 1.026f, -0.0f, 0.383f, 0.438f, 0.44f, 1.013f, -0.0f, 0.384f, 0.44f, 0.44f, 1.0f, -0.0f, 0.385f, 0.441f, 0.443f,
+ 0.987f, -0.0f, 0.385f, 0.442f, 0.443f, 0.975f, -0.0f, 0.384f, 0.443f, 0.443f, 0.962f, -0.0f, 0.383f, 0.443f, 0.444f, 0.949f, -0.0f, 0.381f, 0.443f, 0.443f,
+ 0.936f, -0.0f, 0.38f, 0.443f, 0.444f, 0.923f, -0.0f, 0.378f, 0.443f, 0.444f, 0.909f, -0.0f, 0.375f, 0.443f, 0.444f, 0.897f, -0.0f, 0.371f, 0.443f, 0.444f,
+ 0.886f, -0.0f, 0.367f, 0.443f, 0.443f, 0.876f, -0.0f, 0.363f, 0.443f, 0.444f, 0.868f, -0.0f, 0.359f, 0.443f, 0.442f, 0.86f, -0.0f, 0.355f, 0.442f, 0.443f,
+ 0.852f, -0.0f, 0.35f, 0.441f, 0.443f, 0.844f, -0.0f, 0.347f, 0.433f, 0.443f, 0.837f, -0.0f, 0.343f, 0.409f, 0.443f, 0.83f, -0.0f, 0.338f, 0.344f, 0.443f,
+ 0.824f, -0.0f, 0.335f, 0.239f, 0.437f, 0.815f, -0.0f, 0.326f, 0.0f, 0.003f,
+};
+
+static const float data10[227 * GP_PRIM_DATABUF_SIZE] = {
+ -0.675f, 0.0f, 0.411f, 0.099f, 0.099f, -0.669f, 0.0f, 0.418f, 0.358f, 0.358f, -0.666f, 0.0f, 0.424f, 0.381f, 0.381f, -0.662f, 0.0f, 0.431f, 0.389f, 0.389f,
+ -0.658f, 0.0f, 0.438f, 0.393f, 0.393f, -0.649f, 0.0f, 0.448f, 0.404f, 0.404f, -0.641f, 0.0f, 0.458f, 0.419f, 0.419f, -0.632f, 0.0f, 0.468f, 0.431f, 0.434f,
+ -0.626f, 0.0f, 0.476f, 0.435f, 0.436f, -0.62f, 0.0f, 0.484f, 0.437f, 0.438f, -0.615f, 0.0f, 0.492f, 0.439f, 0.439f, -0.61f, 0.0f, 0.499f, 0.439f, 0.44f,
+ -0.605f, 0.0f, 0.506f, 0.44f, 0.44f, -0.6f, 0.0f, 0.512f, 0.44f, 0.44f, -0.595f, 0.0f, 0.519f, 0.44f, 0.44f, -0.59f, 0.0f, 0.526f, 0.441f, 0.441f,
+ -0.584f, 0.0f, 0.532f, 0.441f, 0.441f, -0.579f, 0.0f, 0.539f, 0.441f, 0.441f, -0.573f, 0.0f, 0.545f, 0.442f, 0.442f, -0.566f, 0.0f, 0.551f, 0.443f, 0.443f,
+ -0.559f, 0.0f, 0.557f, 0.443f, 0.443f, -0.552f, 0.0f, 0.563f, 0.444f, 0.444f, -0.545f, 0.0f, 0.569f, 0.445f, 0.445f, -0.538f, 0.0f, 0.576f, 0.447f, 0.447f,
+ -0.532f, 0.0f, 0.582f, 0.448f, 0.448f, -0.525f, 0.0f, 0.589f, 0.45f, 0.45f, -0.519f, 0.0f, 0.595f, 0.451f, 0.452f, -0.513f, 0.0f, 0.602f, 0.452f, 0.453f,
+ -0.506f, 0.0f, 0.608f, 0.453f, 0.453f, -0.5f, 0.0f, 0.613f, 0.453f, 0.454f, -0.493f, 0.0f, 0.619f, 0.453f, 0.454f, -0.486f, 0.0f, 0.625f, 0.453f, 0.454f,
+ -0.479f, 0.0f, 0.631f, 0.453f, 0.454f, -0.472f, 0.0f, 0.637f, 0.453f, 0.454f, -0.464f, 0.0f, 0.642f, 0.453f, 0.454f, -0.457f, 0.0f, 0.649f, 0.453f, 0.454f,
+ -0.45f, 0.0f, 0.655f, 0.453f, 0.453f, -0.443f, 0.0f, 0.661f, 0.453f, 0.453f, -0.435f, 0.0f, 0.667f, 0.453f, 0.454f, -0.427f, 0.0f, 0.672f, 0.453f, 0.454f,
+ -0.419f, 0.0f, 0.677f, 0.453f, 0.454f, -0.411f, 0.0f, 0.682f, 0.453f, 0.453f, -0.403f, 0.0f, 0.688f, 0.453f, 0.453f, -0.395f, 0.0f, 0.692f, 0.453f, 0.454f,
+ -0.387f, 0.0f, 0.697f, 0.453f, 0.454f, -0.379f, 0.0f, 0.702f, 0.453f, 0.454f, -0.372f, 0.0f, 0.707f, 0.454f, 0.454f, -0.364f, 0.0f, 0.712f, 0.454f, 0.454f,
+ -0.356f, 0.0f, 0.716f, 0.454f, 0.454f, -0.349f, 0.0f, 0.721f, 0.454f, 0.454f, -0.342f, 0.0f, 0.725f, 0.454f, 0.454f, -0.334f, 0.0f, 0.73f, 0.454f, 0.454f,
+ -0.326f, 0.0f, 0.733f, 0.454f, 0.454f, -0.318f, 0.0f, 0.737f, 0.454f, 0.454f, -0.31f, 0.0f, 0.74f, 0.454f, 0.454f, -0.301f, 0.0f, 0.743f, 0.454f, 0.454f,
+ -0.293f, 0.0f, 0.746f, 0.454f, 0.455f, -0.284f, 0.0f, 0.749f, 0.454f, 0.455f, -0.274f, 0.0f, 0.752f, 0.455f, 0.455f, -0.265f, 0.0f, 0.755f, 0.455f, 0.455f,
+ -0.255f, 0.0f, 0.757f, 0.455f, 0.455f, -0.245f, 0.0f, 0.76f, 0.456f, 0.455f, -0.234f, 0.0f, 0.762f, 0.457f, 0.456f, -0.223f, 0.0f, 0.764f, 0.458f, 0.458f,
+ -0.212f, 0.0f, 0.766f, 0.459f, 0.46f, -0.201f, 0.0f, 0.769f, 0.461f, 0.46f, -0.189f, 0.0f, 0.771f, 0.462f, 0.461f, -0.177f, 0.0f, 0.773f, 0.464f, 0.463f,
+ -0.166f, 0.0f, 0.775f, 0.465f, 0.465f, -0.153f, 0.0f, 0.777f, 0.467f, 0.467f, -0.141f, 0.0f, 0.779f, 0.469f, 0.469f, -0.128f, 0.0f, 0.781f, 0.472f, 0.472f,
+ -0.116f, 0.0f, 0.782f, 0.474f, 0.473f, -0.101f, 0.0f, 0.782f, 0.477f, 0.477f, -0.087f, 0.0f, 0.783f, 0.482f, 0.477f, -0.073f, 0.0f, 0.783f, 0.489f, 0.483f,
+ -0.059f, 0.0f, 0.783f, 0.497f, 0.5f, -0.046f, 0.0f, 0.784f, 0.503f, 0.509f, -0.033f, 0.0f, 0.784f, 0.508f, 0.51f, -0.022f, 0.0f, 0.784f, 0.51f, 0.512f,
+ -0.011f, 0.0f, 0.785f, 0.512f, 0.512f, -0.0f, 0.0f, 0.786f, 0.513f, 0.512f, 0.011f, 0.0f, 0.786f, 0.515f, 0.513f, 0.022f, 0.0f, 0.786f, 0.517f, 0.517f,
+ 0.032f, 0.0f, 0.786f, 0.52f, 0.519f, 0.044f, 0.0f, 0.786f, 0.522f, 0.524f, 0.055f, 0.0f, 0.785f, 0.525f, 0.525f, 0.066f, 0.0f, 0.785f, 0.527f, 0.525f,
+ 0.076f, 0.0f, 0.784f, 0.53f, 0.53f, 0.086f, 0.0f, 0.783f, 0.532f, 0.533f, 0.097f, 0.0f, 0.782f, 0.535f, 0.534f, 0.108f, 0.0f, 0.782f, 0.538f, 0.541f,
+ 0.119f, 0.0f, 0.781f, 0.54f, 0.542f, 0.13f, 0.0f, 0.781f, 0.543f, 0.543f, 0.141f, 0.0f, 0.78f, 0.545f, 0.545f, 0.154f, 0.0f, 0.779f, 0.547f, 0.547f,
+ 0.165f, 0.0f, 0.777f, 0.549f, 0.548f, 0.177f, 0.0f, 0.775f, 0.55f, 0.552f, 0.188f, 0.0f, 0.772f, 0.552f, 0.552f, 0.199f, 0.0f, 0.77f, 0.553f, 0.553f,
+ 0.209f, 0.0f, 0.767f, 0.554f, 0.554f, 0.218f, 0.0f, 0.765f, 0.555f, 0.556f, 0.226f, 0.0f, 0.763f, 0.556f, 0.557f, 0.235f, 0.0f, 0.761f, 0.557f, 0.557f,
+ 0.244f, 0.0f, 0.758f, 0.558f, 0.558f, 0.253f, 0.0f, 0.755f, 0.559f, 0.559f, 0.263f, 0.0f, 0.752f, 0.56f, 0.559f, 0.272f, 0.0f, 0.749f, 0.561f, 0.56f,
+ 0.285f, 0.0f, 0.745f, 0.562f, 0.56f, 0.299f, 0.0f, 0.741f, 0.563f, 0.563f, 0.316f, 0.0f, 0.736f, 0.564f, 0.564f, 0.331f, 0.0f, 0.728f, 0.565f, 0.567f,
+ 0.349f, 0.0f, 0.718f, 0.565f, 0.568f, 0.365f, 0.0f, 0.708f, 0.566f, 0.568f, 0.38f, 0.0f, 0.699f, 0.566f, 0.568f, 0.39f, 0.0f, 0.693f, 0.566f, 0.568f,
+ 0.397f, 0.0f, 0.687f, 0.566f, 0.569f, 0.4f, 0.0f, 0.683f, 0.566f, 0.569f, 0.401f, 0.0f, 0.681f, 0.565f, 0.57f, 0.4f, 0.0f, 0.679f, 0.565f, 0.57f,
+ 0.397f, 0.0f, 0.678f, 0.564f, 0.57f, 0.393f, 0.0f, 0.678f, 0.564f, 0.565f, 0.387f, 0.0f, 0.678f, 0.563f, 0.559f, 0.379f, 0.0f, 0.679f, 0.562f, 0.558f,
+ 0.37f, 0.0f, 0.681f, 0.561f, 0.557f, 0.357f, 0.0f, 0.684f, 0.561f, 0.557f, 0.342f, 0.0f, 0.689f, 0.56f, 0.557f, 0.324f, 0.0f, 0.694f, 0.56f, 0.557f,
+ 0.307f, 0.0f, 0.697f, 0.559f, 0.558f, 0.291f, 0.0f, 0.699f, 0.559f, 0.558f, 0.274f, 0.0f, 0.701f, 0.559f, 0.557f, 0.26f, 0.0f, 0.703f, 0.558f, 0.558f,
+ 0.246f, 0.0f, 0.705f, 0.558f, 0.558f, 0.235f, 0.0f, 0.707f, 0.558f, 0.558f, 0.224f, 0.0f, 0.709f, 0.558f, 0.558f, 0.214f, 0.0f, 0.711f, 0.558f, 0.558f,
+ 0.203f, 0.0f, 0.713f, 0.558f, 0.559f, 0.192f, 0.0f, 0.714f, 0.558f, 0.558f, 0.181f, 0.0f, 0.714f, 0.557f, 0.557f, 0.17f, 0.0f, 0.714f, 0.557f, 0.557f,
+ 0.16f, 0.0f, 0.715f, 0.557f, 0.556f, 0.149f, 0.0f, 0.715f, 0.557f, 0.556f, 0.139f, 0.0f, 0.716f, 0.557f, 0.556f, 0.129f, 0.0f, 0.716f, 0.558f, 0.556f,
+ 0.119f, 0.0f, 0.717f, 0.558f, 0.556f, 0.109f, 0.0f, 0.717f, 0.558f, 0.557f, 0.099f, 0.0f, 0.718f, 0.558f, 0.557f, 0.089f, 0.0f, 0.718f, 0.559f, 0.557f,
+ 0.079f, 0.0f, 0.718f, 0.559f, 0.558f, 0.068f, 0.0f, 0.719f, 0.559f, 0.559f, 0.057f, 0.0f, 0.719f, 0.56f, 0.56f, 0.046f, 0.0f, 0.718f, 0.56f, 0.561f,
+ 0.035f, 0.0f, 0.718f, 0.561f, 0.561f, 0.024f, 0.0f, 0.718f, 0.561f, 0.562f, 0.013f, 0.0f, 0.717f, 0.562f, 0.562f, 0.002f, 0.0f, 0.717f, 0.562f, 0.563f,
+ -0.01f, 0.0f, 0.717f, 0.563f, 0.564f, -0.021f, 0.0f, 0.717f, 0.563f, 0.564f, -0.032f, 0.0f, 0.716f, 0.563f, 0.564f, -0.044f, 0.0f, 0.715f, 0.564f, 0.564f,
+ -0.055f, 0.0f, 0.714f, 0.564f, 0.565f, -0.066f, 0.0f, 0.713f, 0.564f, 0.565f, -0.078f, 0.0f, 0.712f, 0.564f, 0.564f, -0.089f, 0.0f, 0.711f, 0.564f, 0.564f,
+ -0.101f, 0.0f, 0.709f, 0.565f, 0.564f, -0.112f, 0.0f, 0.708f, 0.565f, 0.564f, -0.124f, 0.0f, 0.707f, 0.565f, 0.564f, -0.135f, 0.0f, 0.705f, 0.565f, 0.564f,
+ -0.146f, 0.0f, 0.704f, 0.566f, 0.564f, -0.158f, 0.0f, 0.702f, 0.566f, 0.564f, -0.169f, 0.0f, 0.7f, 0.566f, 0.566f, -0.18f, 0.0f, 0.698f, 0.567f, 0.568f,
+ -0.191f, 0.0f, 0.696f, 0.567f, 0.568f, -0.203f, 0.0f, 0.693f, 0.567f, 0.568f, -0.215f, 0.0f, 0.69f, 0.567f, 0.568f, -0.227f, 0.0f, 0.687f, 0.567f, 0.568f,
+ -0.238f, 0.0f, 0.684f, 0.567f, 0.568f, -0.25f, 0.0f, 0.681f, 0.567f, 0.569f, -0.262f, 0.0f, 0.678f, 0.567f, 0.569f, -0.273f, 0.0f, 0.675f, 0.567f, 0.567f,
+ -0.284f, 0.0f, 0.673f, 0.567f, 0.566f, -0.295f, 0.0f, 0.671f, 0.567f, 0.567f, -0.305f, 0.0f, 0.669f, 0.566f, 0.567f, -0.316f, 0.0f, 0.666f, 0.566f, 0.567f,
+ -0.326f, 0.0f, 0.663f, 0.565f, 0.566f, -0.337f, 0.0f, 0.66f, 0.565f, 0.566f, -0.348f, 0.0f, 0.655f, 0.564f, 0.564f, -0.359f, 0.0f, 0.652f, 0.563f, 0.564f,
+ -0.369f, 0.0f, 0.648f, 0.562f, 0.563f, -0.379f, 0.0f, 0.644f, 0.561f, 0.56f, -0.389f, 0.0f, 0.64f, 0.561f, 0.559f, -0.399f, 0.0f, 0.636f, 0.56f, 0.559f,
+ -0.409f, 0.0f, 0.633f, 0.559f, 0.559f, -0.419f, 0.0f, 0.629f, 0.559f, 0.559f, -0.428f, 0.0f, 0.625f, 0.559f, 0.558f, -0.438f, 0.0f, 0.62f, 0.559f, 0.559f,
+ -0.447f, 0.0f, 0.615f, 0.559f, 0.559f, -0.457f, 0.0f, 0.61f, 0.559f, 0.559f, -0.466f, 0.0f, 0.605f, 0.559f, 0.559f, -0.474f, 0.0f, 0.6f, 0.559f, 0.559f,
+ -0.483f, 0.0f, 0.595f, 0.559f, 0.559f, -0.492f, 0.0f, 0.591f, 0.559f, 0.559f, -0.5f, 0.0f, 0.586f, 0.559f, 0.559f, -0.508f, 0.0f, 0.58f, 0.559f, 0.559f,
+ -0.515f, 0.0f, 0.574f, 0.559f, 0.559f, -0.523f, 0.0f, 0.568f, 0.559f, 0.559f, -0.531f, 0.0f, 0.562f, 0.559f, 0.558f, -0.54f, 0.0f, 0.556f, 0.559f, 0.558f,
+ -0.548f, 0.0f, 0.549f, 0.559f, 0.559f, -0.556f, 0.0f, 0.543f, 0.559f, 0.559f, -0.562f, 0.0f, 0.537f, 0.559f, 0.559f, -0.568f, 0.0f, 0.531f, 0.559f, 0.559f,
+ -0.574f, 0.0f, 0.524f, 0.559f, 0.559f, -0.58f, 0.0f, 0.518f, 0.558f, 0.559f, -0.586f, 0.0f, 0.512f, 0.557f, 0.558f, -0.591f, 0.0f, 0.506f, 0.555f, 0.557f,
+ -0.597f, 0.0f, 0.5f, 0.551f, 0.556f, -0.603f, 0.0f, 0.493f, 0.546f, 0.547f, -0.609f, 0.0f, 0.487f, 0.541f, 0.538f, -0.614f, 0.0f, 0.48f, 0.536f, 0.535f,
+ -0.621f, 0.0f, 0.473f, 0.534f, 0.534f, -0.628f, 0.0f, 0.467f, 0.534f, 0.534f, -0.637f, 0.0f, 0.459f, 0.534f, 0.534f, -0.642f, 0.0f, 0.452f, 0.532f, 0.532f,
+ -0.65f, 0.0f, 0.445f, 0.528f, 0.528f, -0.654f, 0.0f, 0.438f, 0.525f, 0.525f, -0.659f, 0.0f, 0.431f, 0.522f, 0.522f,
+};
+
+static const float data11[1 * GP_PRIM_DATABUF_SIZE] = {
+ -0.525f, 0.0f, 0.174f, 0.124f, 0.124f,
+};
+
+static const float data12[123 * GP_PRIM_DATABUF_SIZE] = {
+ -0.53f, 0.0f, 0.193f, 0.147f, 0.147f, -0.532f, 0.0f, 0.186f, 0.316f, 0.316f, -0.534f, 0.0f, 0.18f, 0.353f, 0.353f, -0.535f, 0.0f, 0.173f, 0.382f, 0.382f,
+ -0.537f, 0.0f, 0.165f, 0.384f, 0.384f, -0.538f, 0.0f, 0.155f, 0.387f, 0.387f, -0.539f, 0.0f, 0.145f, 0.393f, 0.393f, -0.54f, -0.0f, 0.134f, 0.399f, 0.399f,
+ -0.541f, -0.0f, 0.123f, 0.4f, 0.4f, -0.542f, -0.0f, 0.11f, 0.401f, 0.401f, -0.542f, 0.0f, 0.094f, 0.402f, 0.402f, -0.54f, 0.0f, 0.078f, 0.403f, 0.403f,
+ -0.538f, 0.0f, 0.061f, 0.404f, 0.404f, -0.535f, 0.0f, 0.045f, 0.404f, 0.404f, -0.531f, 0.0f, 0.031f, 0.404f, 0.404f, -0.526f, 0.0f, 0.018f, 0.404f, 0.404f,
+ -0.52f, -0.0f, 0.005f, 0.405f, 0.405f, -0.513f, -0.0f, -0.01f, 0.405f, 0.405f, -0.505f, -0.0f, -0.024f, 0.405f, 0.405f, -0.495f, -0.0f, -0.037f, 0.405f, 0.405f,
+ -0.485f, 0.0f, -0.051f, 0.405f, 0.405f, -0.474f, 0.0f, -0.064f, 0.406f, 0.406f, -0.462f, 0.0f, -0.076f, 0.405f, 0.405f, -0.451f, 0.0f, -0.086f, 0.406f, 0.406f,
+ -0.442f, 0.0f, -0.094f, 0.406f, 0.406f, -0.432f, 0.0f, -0.102f, 0.406f, 0.406f, -0.422f, 0.0f, -0.108f, 0.405f, 0.405f, -0.411f, 0.0f, -0.114f, 0.406f, 0.406f,
+ -0.4f, 0.0f, -0.119f, 0.405f, 0.405f, -0.389f, 0.0f, -0.122f, 0.406f, 0.406f, -0.378f, 0.0f, -0.125f, 0.407f, 0.407f, -0.365f, 0.0f, -0.127f, 0.412f, 0.412f,
+ -0.354f, 0.0f, -0.129f, 0.418f, 0.418f, -0.342f, 0.0f, -0.131f, 0.44f, 0.44f, -0.33f, 0.0f, -0.131f, 0.448f, 0.448f, -0.317f, 0.0f, -0.131f, 0.469f, 0.469f,
+ -0.305f, 0.0f, -0.13f, 0.477f, 0.477f, -0.293f, 0.0f, -0.128f, 0.482f, 0.482f, -0.278f, 0.0f, -0.125f, 0.494f, 0.494f, -0.266f, 0.0f, -0.121f, 0.5f, 0.5f,
+ -0.253f, 0.0f, -0.116f, 0.507f, 0.507f, -0.242f, 0.0f, -0.111f, 0.509f, 0.509f, -0.231f, 0.0f, -0.105f, 0.511f, 0.511f, -0.222f, 0.0f, -0.099f, 0.511f, 0.511f,
+ -0.213f, 0.0f, -0.092f, 0.512f, 0.512f, -0.206f, 0.0f, -0.084f, 0.513f, 0.513f, -0.199f, 0.0f, -0.076f, 0.514f, 0.514f, -0.192f, 0.0f, -0.067f, 0.515f, 0.515f,
+ -0.186f, -0.0f, -0.058f, 0.516f, 0.516f, -0.18f, -0.0f, -0.049f, 0.516f, 0.516f, -0.175f, -0.0f, -0.04f, 0.515f, 0.515f, -0.17f, -0.0f, -0.03f, 0.515f, 0.515f,
+ -0.166f, -0.0f, -0.02f, 0.516f, 0.516f, -0.163f, -0.0f, -0.01f, 0.504f, 0.504f, -0.159f, -0.0f, 0.002f, 0.502f, 0.502f, -0.155f, -0.0f, 0.014f, 0.501f, 0.501f,
+ -0.152f, -0.0f, 0.027f, 0.502f, 0.502f, -0.149f, -0.0f, 0.043f, 0.5f, 0.5f, -0.148f, -0.0f, 0.058f, 0.49f, 0.49f, -0.147f, -0.0f, 0.075f, 0.47f, 0.47f,
+ -0.146f, -0.0f, 0.09f, 0.463f, 0.463f, -0.146f, -0.0f, 0.105f, 0.454f, 0.454f, -0.146f, -0.0f, 0.12f, 0.427f, 0.427f, -0.148f, 0.0f, 0.133f, 0.413f, 0.413f,
+ -0.15f, 0.0f, 0.144f, 0.4f, 0.4f, -0.153f, 0.0f, 0.152f, 0.383f, 0.383f, -0.156f, 0.0f, 0.157f, 0.369f, 0.369f, -0.158f, 0.0f, 0.16f, 0.36f, 0.36f,
+ -0.16f, 0.0f, 0.158f, 0.349f, 0.349f, -0.162f, 0.0f, 0.154f, 0.364f, 0.364f, -0.164f, 0.0f, 0.147f, 0.37f, 0.37f, -0.166f, 0.0f, 0.139f, 0.378f, 0.378f,
+ -0.168f, 0.0f, 0.13f, 0.386f, 0.386f, -0.172f, 0.0f, 0.119f, 0.394f, 0.394f, -0.176f, -0.0f, 0.108f, 0.405f, 0.405f, -0.18f, -0.0f, 0.096f, 0.412f, 0.412f,
+ -0.185f, -0.0f, 0.084f, 0.417f, 0.417f, -0.191f, -0.0f, 0.073f, 0.425f, 0.425f, -0.196f, -0.0f, 0.063f, 0.431f, 0.431f, -0.202f, -0.0f, 0.053f, 0.441f, 0.441f,
+ -0.208f, -0.0f, 0.043f, 0.444f, 0.444f, -0.214f, -0.0f, 0.034f, 0.451f, 0.451f, -0.22f, 0.0f, 0.026f, 0.46f, 0.46f, -0.226f, 0.0f, 0.018f, 0.463f, 0.463f,
+ -0.232f, 0.0f, 0.01f, 0.474f, 0.474f, -0.239f, 0.0f, 0.004f, 0.477f, 0.477f, -0.247f, 0.0f, -0.003f, 0.48f, 0.48f, -0.255f, 0.0f, -0.008f, 0.483f, 0.483f,
+ -0.264f, 0.0f, -0.013f, 0.497f, 0.497f, -0.274f, 0.0f, -0.018f, 0.501f, 0.501f, -0.285f, 0.0f, -0.022f, 0.505f, 0.505f, -0.297f, 0.0f, -0.024f, 0.509f, 0.509f,
+ -0.311f, 0.0f, -0.025f, 0.51f, 0.51f, -0.325f, 0.0f, -0.024f, 0.512f, 0.512f, -0.339f, 0.0f, -0.023f, 0.512f, 0.512f, -0.354f, 0.0f, -0.022f, 0.513f, 0.513f,
+ -0.368f, 0.0f, -0.02f, 0.513f, 0.513f, -0.382f, 0.0f, -0.017f, 0.514f, 0.514f, -0.397f, 0.0f, -0.013f, 0.514f, 0.514f, -0.41f, 0.0f, -0.007f, 0.514f, 0.514f,
+ -0.422f, 0.0f, 0.001f, 0.513f, 0.513f, -0.434f, 0.0f, 0.009f, 0.514f, 0.514f, -0.446f, 0.0f, 0.018f, 0.514f, 0.514f, -0.458f, 0.0f, 0.028f, 0.514f, 0.514f,
+ -0.47f, -0.0f, 0.039f, 0.514f, 0.514f, -0.48f, 0.0f, 0.048f, 0.514f, 0.514f, -0.487f, 0.0f, 0.057f, 0.514f, 0.514f, -0.493f, 0.0f, 0.068f, 0.514f, 0.514f,
+ -0.498f, 0.0f, 0.08f, 0.514f, 0.514f, -0.502f, 0.0f, 0.092f, 0.514f, 0.514f, -0.506f, 0.0f, 0.104f, 0.514f, 0.514f, -0.509f, -0.0f, 0.116f, 0.515f, 0.515f,
+ -0.511f, -0.0f, 0.125f, 0.515f, 0.515f, -0.513f, -0.0f, 0.133f, 0.515f, 0.515f, -0.515f, -0.0f, 0.141f, 0.515f, 0.515f, -0.517f, 0.0f, 0.148f, 0.515f, 0.515f,
+ -0.519f, 0.0f, 0.155f, 0.514f, 0.514f, -0.52f, 0.0f, 0.161f, 0.514f, 0.514f, -0.522f, 0.0f, 0.168f, 0.514f, 0.514f, -0.523f, 0.0f, 0.174f, 0.514f, 0.514f,
+ -0.525f, 0.0f, 0.18f, 0.514f, 0.514f, -0.526f, 0.0f, 0.185f, 0.514f, 0.514f, -0.527f, 0.0f, 0.191f, 0.513f, 0.513f,
+};
+
+static const float data13[125 * GP_PRIM_DATABUF_SIZE] = {
+ 0.184f, 0.0f, 0.22f, 0.026f, 0.026f, 0.182f, 0.0f, 0.21f, 0.275f, 0.275f, 0.18f, 0.0f, 0.203f, 0.301f, 0.301f, 0.178f, 0.0f, 0.195f, 0.322f, 0.322f,
+ 0.176f, 0.0f, 0.186f, 0.343f, 0.343f, 0.173f, 0.0f, 0.176f, 0.36f, 0.36f, 0.17f, -0.0f, 0.166f, 0.367f, 0.367f, 0.168f, -0.0f, 0.156f, 0.38f, 0.38f,
+ 0.165f, -0.0f, 0.145f, 0.385f, 0.385f, 0.163f, -0.0f, 0.132f, 0.391f, 0.391f, 0.161f, -0.0f, 0.119f, 0.401f, 0.401f, 0.16f, -0.0f, 0.103f, 0.405f, 0.405f,
+ 0.161f, -0.0f, 0.086f, 0.405f, 0.405f, 0.163f, -0.0f, 0.068f, 0.407f, 0.407f, 0.165f, 0.0f, 0.051f, 0.409f, 0.409f, 0.168f, 0.0f, 0.034f, 0.409f, 0.409f,
+ 0.172f, 0.0f, 0.018f, 0.409f, 0.409f, 0.177f, 0.0f, 0.004f, 0.409f, 0.409f, 0.183f, 0.0f, -0.008f, 0.411f, 0.411f, 0.19f, 0.0f, -0.022f, 0.411f, 0.411f,
+ 0.196f, 0.0f, -0.034f, 0.411f, 0.411f, 0.203f, 0.0f, -0.045f, 0.411f, 0.411f, 0.211f, 0.0f, -0.055f, 0.411f, 0.411f, 0.219f, 0.0f, -0.064f, 0.411f, 0.411f,
+ 0.227f, 0.0f, -0.072f, 0.411f, 0.411f, 0.235f, 0.0f, -0.08f, 0.412f, 0.412f, 0.244f, 0.0f, -0.087f, 0.412f, 0.412f, 0.253f, 0.0f, -0.094f, 0.413f, 0.413f,
+ 0.262f, 0.0f, -0.1f, 0.413f, 0.413f, 0.273f, 0.0f, -0.105f, 0.413f, 0.413f, 0.284f, 0.0f, -0.11f, 0.413f, 0.413f, 0.295f, 0.0f, -0.114f, 0.419f, 0.419f,
+ 0.307f, 0.0f, -0.117f, 0.425f, 0.425f, 0.321f, -0.0f, -0.118f, 0.433f, 0.433f, 0.334f, -0.0f, -0.12f, 0.446f, 0.446f, 0.347f, -0.0f, -0.12f, 0.474f, 0.474f,
+ 0.36f, -0.0f, -0.12f, 0.481f, 0.481f, 0.374f, -0.0f, -0.119f, 0.491f, 0.491f, 0.387f, -0.0f, -0.118f, 0.494f, 0.494f, 0.401f, 0.0f, -0.116f, 0.5f, 0.5f,
+ 0.414f, 0.0f, -0.112f, 0.505f, 0.505f, 0.426f, -0.0f, -0.107f, 0.51f, 0.51f, 0.438f, -0.0f, -0.101f, 0.513f, 0.513f, 0.449f, -0.0f, -0.094f, 0.515f, 0.515f,
+ 0.46f, -0.0f, -0.086f, 0.517f, 0.517f, 0.47f, -0.0f, -0.078f, 0.519f, 0.519f, 0.478f, -0.0f, -0.07f, 0.52f, 0.52f, 0.486f, -0.0f, -0.061f, 0.522f, 0.522f,
+ 0.493f, -0.0f, -0.052f, 0.523f, 0.523f, 0.499f, -0.0f, -0.044f, 0.522f, 0.522f, 0.505f, -0.0f, -0.035f, 0.522f, 0.522f, 0.51f, -0.0f, -0.027f, 0.523f, 0.523f,
+ 0.514f, -0.0f, -0.018f, 0.523f, 0.523f, 0.517f, -0.0f, -0.009f, 0.523f, 0.523f, 0.52f, -0.0f, -0.001f, 0.524f, 0.524f, 0.522f, -0.0f, 0.008f, 0.523f, 0.523f,
+ 0.525f, -0.0f, 0.018f, 0.521f, 0.522f, 0.527f, -0.0f, 0.027f, 0.515f, 0.514f, 0.529f, -0.0f, 0.036f, 0.512f, 0.512f, 0.531f, -0.0f, 0.045f, 0.509f, 0.51f,
+ 0.533f, -0.0f, 0.053f, 0.506f, 0.505f, 0.535f, -0.0f, 0.062f, 0.503f, 0.503f, 0.536f, -0.0f, 0.071f, 0.5f, 0.5f, 0.538f, -0.0f, 0.08f, 0.496f, 0.497f,
+ 0.538f, -0.0f, 0.09f, 0.491f, 0.492f, 0.539f, -0.0f, 0.1f, 0.485f, 0.486f, 0.539f, 0.0f, 0.11f, 0.475f, 0.476f, 0.539f, 0.0f, 0.12f, 0.46f, 0.459f,
+ 0.539f, 0.0f, 0.13f, 0.444f, 0.448f, 0.538f, 0.0f, 0.139f, 0.406f, 0.405f, 0.537f, 0.0f, 0.144f, 0.399f, 0.399f, 0.536f, 0.0f, 0.146f, 0.395f, 0.395f,
+ 0.535f, 0.0f, 0.144f, 0.412f, 0.412f, 0.533f, 0.0f, 0.139f, 0.413f, 0.413f, 0.53f, 0.0f, 0.131f, 0.414f, 0.413f, 0.528f, 0.0f, 0.122f, 0.419f, 0.418f,
+ 0.525f, 0.0f, 0.112f, 0.425f, 0.424f, 0.521f, 0.0f, 0.102f, 0.444f, 0.444f, 0.518f, 0.0f, 0.094f, 0.451f, 0.452f, 0.514f, 0.0f, 0.085f, 0.457f, 0.457f,
+ 0.509f, 0.0f, 0.078f, 0.461f, 0.46f, 0.504f, 0.0f, 0.069f, 0.469f, 0.468f, 0.499f, 0.0f, 0.06f, 0.481f, 0.481f, 0.493f, 0.0f, 0.052f, 0.489f, 0.489f,
+ 0.487f, 0.0f, 0.044f, 0.492f, 0.492f, 0.481f, 0.0f, 0.037f, 0.501f, 0.5f, 0.474f, 0.0f, 0.029f, 0.513f, 0.513f, 0.467f, 0.0f, 0.022f, 0.521f, 0.521f,
+ 0.458f, 0.0f, 0.015f, 0.524f, 0.524f, 0.449f, 0.0f, 0.008f, 0.525f, 0.525f, 0.439f, 0.0f, 0.001f, 0.528f, 0.528f, 0.427f, 0.0f, -0.005f, 0.532f, 0.532f,
+ 0.416f, 0.0f, -0.011f, 0.533f, 0.533f, 0.401f, 0.0f, -0.015f, 0.537f, 0.537f, 0.386f, 0.0f, -0.018f, 0.539f, 0.539f, 0.371f, 0.0f, -0.02f, 0.538f, 0.538f,
+ 0.356f, 0.0f, -0.021f, 0.543f, 0.543f, 0.341f, 0.0f, -0.023f, 0.543f, 0.543f, 0.326f, 0.0f, -0.023f, 0.543f, 0.543f, 0.312f, 0.0f, -0.022f, 0.543f, 0.543f,
+ 0.298f, 0.0f, -0.018f, 0.543f, 0.543f, 0.286f, 0.0f, -0.014f, 0.543f, 0.543f, 0.273f, 0.0f, -0.006f, 0.543f, 0.543f, 0.26f, 0.0f, 0.004f, 0.543f, 0.543f,
+ 0.247f, 0.0f, 0.013f, 0.543f, 0.543f, 0.235f, 0.0f, 0.022f, 0.543f, 0.543f, 0.225f, 0.0f, 0.033f, 0.543f, 0.543f, 0.215f, 0.0f, 0.045f, 0.542f, 0.542f,
+ 0.206f, 0.0f, 0.061f, 0.54f, 0.54f, 0.199f, 0.0f, 0.078f, 0.542f, 0.542f, 0.193f, 0.0f, 0.094f, 0.542f, 0.542f, 0.189f, -0.0f, 0.109f, 0.541f, 0.541f,
+ 0.186f, -0.0f, 0.119f, 0.542f, 0.542f, 0.185f, -0.0f, 0.127f, 0.542f, 0.542f, 0.184f, -0.0f, 0.135f, 0.542f, 0.542f, 0.184f, -0.0f, 0.142f, 0.542f, 0.542f,
+ 0.183f, -0.0f, 0.149f, 0.541f, 0.541f, 0.183f, -0.0f, 0.156f, 0.538f, 0.538f, 0.183f, -0.0f, 0.163f, 0.539f, 0.539f, 0.183f, -0.0f, 0.17f, 0.54f, 0.54f,
+ 0.183f, 0.0f, 0.177f, 0.54f, 0.54f, 0.183f, 0.0f, 0.184f, 0.54f, 0.54f, 0.183f, 0.0f, 0.191f, 0.54f, 0.54f, 0.184f, 0.0f, 0.196f, 0.539f, 0.539f,
+ 0.184f, 0.0f, 0.204f, 0.518f, 0.518f,
+};
+
+static const float data14[45 * GP_PRIM_DATABUF_SIZE] = {
+ -0.096f, -0.0f, -0.305f, 0.01f, 0.01f, -0.09f, -0.0f, -0.313f, 0.121f, 0.362f, -0.086f, -0.0f, -0.318f, 0.179f, 0.368f, -0.081f, -0.0f, -0.325f, 0.234f, 0.37f,
+ -0.075f, -0.0f, -0.331f, 0.272f, 0.37f, -0.068f, -0.0f, -0.338f, 0.302f, 0.371f, -0.061f, -0.0f, -0.345f, 0.324f, 0.374f, -0.053f, -0.0f, -0.352f, 0.34f, 0.377f,
+ -0.044f, -0.0f, -0.358f, 0.352f, 0.378f, -0.035f, -0.0f, -0.362f, 0.362f, 0.377f, -0.026f, -0.0f, -0.366f, 0.37f, 0.378f, -0.018f, -0.0f, -0.368f, 0.377f, 0.378f,
+ -0.009f, -0.0f, -0.369f, 0.383f, 0.376f, -0.001f, -0.0f, -0.369f, 0.389f, 0.369f, 0.007f, -0.0f, -0.368f, 0.395f, 0.364f, 0.015f, -0.0f, -0.367f, 0.4f, 0.388f,
+ 0.023f, -0.0f, -0.365f, 0.405f, 0.41f, 0.03f, -0.0f, -0.363f, 0.41f, 0.429f, 0.038f, -0.0f, -0.36f, 0.414f, 0.438f, 0.044f, -0.0f, -0.357f, 0.417f, 0.441f,
+ 0.05f, -0.0f, -0.355f, 0.419f, 0.444f, 0.055f, -0.0f, -0.352f, 0.42f, 0.441f, 0.06f, -0.0f, -0.349f, 0.421f, 0.445f, 0.063f, -0.0f, -0.347f, 0.421f, 0.446f,
+ 0.065f, -0.0f, -0.344f, 0.42f, 0.443f, 0.065f, -0.0f, -0.342f, 0.42f, 0.437f, 0.065f, -0.0f, -0.341f, 0.419f, 0.413f, 0.063f, -0.0f, -0.339f, 0.418f, 0.404f,
+ 0.061f, -0.0f, -0.338f, 0.418f, 0.403f, 0.057f, -0.0f, -0.337f, 0.418f, 0.402f, 0.052f, -0.0f, -0.337f, 0.418f, 0.407f, 0.046f, -0.0f, -0.337f, 0.419f, 0.411f,
+ 0.04f, 0.0f, -0.336f, 0.42f, 0.416f, 0.032f, 0.0f, -0.337f, 0.422f, 0.421f, 0.023f, 0.0f, -0.339f, 0.424f, 0.425f, 0.014f, 0.0f, -0.34f, 0.426f, 0.427f,
+ 0.003f, 0.0f, -0.341f, 0.428f, 0.427f, -0.007f, 0.0f, -0.341f, 0.43f, 0.433f, -0.018f, 0.0f, -0.339f, 0.432f, 0.437f, -0.027f, 0.0f, -0.335f, 0.434f, 0.438f,
+ -0.037f, 0.0f, -0.33f, 0.435f, 0.437f, -0.046f, -0.0f, -0.326f, 0.436f, 0.438f, -0.055f, -0.0f, -0.321f, 0.436f, 0.44f, -0.062f, -0.0f, -0.316f, 0.437f, 0.439f,
+ -0.073f, -0.0f, -0.31f, 0.437f, 0.437f,
+};
+
+static const float data16[84 * GP_PRIM_DATABUF_SIZE] = {
+ 0.737f, 0.0f, 0.177f, 0.148f, 0.148f, 0.735f, 0.0f, 0.164f, 0.214f, 0.39f, 0.734f, 0.0f, 0.155f, 0.254f, 0.402f, 0.732f, 0.0f, 0.143f, 0.295f, 0.413f,
+ 0.73f, 0.0f, 0.132f, 0.328f, 0.415f, 0.728f, 0.0f, 0.121f, 0.355f, 0.415f, 0.726f, 0.0f, 0.109f, 0.375f, 0.416f, 0.724f, 0.0f, 0.097f, 0.39f, 0.417f,
+ 0.721f, 0.0f, 0.086f, 0.401f, 0.418f, 0.719f, 0.0f, 0.074f, 0.408f, 0.419f, 0.716f, 0.0f, 0.062f, 0.413f, 0.42f, 0.713f, 0.0f, 0.05f, 0.416f, 0.42f,
+ 0.71f, 0.0f, 0.039f, 0.418f, 0.421f, 0.707f, 0.0f, 0.028f, 0.42f, 0.421f, 0.703f, 0.0f, 0.017f, 0.421f, 0.422f, 0.7f, 0.0f, 0.006f, 0.421f, 0.422f,
+ 0.696f, 0.0f, -0.005f, 0.422f, 0.422f, 0.693f, 0.0f, -0.015f, 0.422f, 0.422f, 0.689f, 0.0f, -0.025f, 0.423f, 0.423f, 0.685f, 0.0f, -0.034f, 0.423f, 0.423f,
+ 0.681f, 0.0f, -0.044f, 0.423f, 0.423f, 0.677f, 0.0f, -0.053f, 0.423f, 0.423f, 0.672f, 0.0f, -0.062f, 0.423f, 0.423f, 0.668f, 0.0f, -0.071f, 0.422f, 0.424f,
+ 0.662f, 0.0f, -0.08f, 0.422f, 0.424f, 0.657f, 0.0f, -0.088f, 0.422f, 0.422f, 0.651f, 0.0f, -0.095f, 0.421f, 0.419f, 0.645f, 0.0f, -0.103f, 0.42f, 0.419f,
+ 0.638f, 0.0f, -0.109f, 0.42f, 0.419f, 0.631f, 0.0f, -0.115f, 0.419f, 0.419f, 0.624f, 0.0f, -0.12f, 0.419f, 0.419f, 0.617f, 0.0f, -0.125f, 0.419f, 0.419f,
+ 0.61f, 0.0f, -0.129f, 0.418f, 0.418f, 0.602f, 0.0f, -0.133f, 0.418f, 0.416f, 0.594f, 0.0f, -0.137f, 0.417f, 0.416f, 0.587f, 0.0f, -0.14f, 0.417f, 0.415f,
+ 0.579f, 0.0f, -0.142f, 0.417f, 0.416f, 0.571f, 0.0f, -0.144f, 0.417f, 0.415f, 0.564f, 0.0f, -0.145f, 0.417f, 0.416f, 0.556f, 0.0f, -0.146f, 0.417f, 0.415f,
+ 0.549f, 0.0f, -0.146f, 0.417f, 0.415f, 0.541f, 0.0f, -0.146f, 0.417f, 0.415f, 0.535f, 0.0f, -0.145f, 0.417f, 0.416f, 0.53f, 0.0f, -0.143f, 0.418f, 0.418f,
+ 0.526f, 0.0f, -0.14f, 0.418f, 0.418f, 0.524f, 0.0f, -0.136f, 0.42f, 0.418f, 0.524f, 0.0f, -0.132f, 0.422f, 0.416f, 0.527f, 0.0f, -0.126f, 0.424f, 0.424f,
+ 0.531f, 0.0f, -0.121f, 0.427f, 0.428f, 0.536f, 0.0f, -0.115f, 0.43f, 0.433f, 0.542f, 0.0f, -0.109f, 0.433f, 0.436f, 0.548f, 0.0f, -0.102f, 0.435f, 0.436f,
+ 0.555f, 0.0f, -0.095f, 0.436f, 0.437f, 0.562f, 0.0f, -0.088f, 0.437f, 0.438f, 0.568f, 0.0f, -0.081f, 0.437f, 0.438f, 0.575f, 0.0f, -0.073f, 0.438f, 0.438f,
+ 0.581f, 0.0f, -0.065f, 0.438f, 0.438f, 0.587f, 0.0f, -0.058f, 0.438f, 0.438f, 0.593f, 0.0f, -0.05f, 0.438f, 0.438f, 0.599f, 0.0f, -0.041f, 0.438f, 0.438f,
+ 0.605f, 0.0f, -0.033f, 0.438f, 0.438f, 0.61f, 0.0f, -0.024f, 0.438f, 0.438f, 0.615f, 0.0f, -0.015f, 0.438f, 0.438f, 0.621f, 0.0f, -0.006f, 0.438f, 0.438f,
+ 0.626f, 0.0f, 0.004f, 0.438f, 0.438f, 0.631f, 0.0f, 0.013f, 0.437f, 0.438f, 0.636f, 0.0f, 0.023f, 0.436f, 0.438f, 0.641f, 0.0f, 0.032f, 0.434f, 0.438f,
+ 0.647f, 0.0f, 0.042f, 0.432f, 0.437f, 0.652f, 0.0f, 0.051f, 0.431f, 0.429f, 0.657f, 0.0f, 0.06f, 0.429f, 0.426f, 0.662f, 0.0f, 0.069f, 0.427f, 0.425f,
+ 0.668f, 0.0f, 0.078f, 0.425f, 0.425f, 0.673f, 0.0f, 0.087f, 0.423f, 0.424f, 0.678f, 0.0f, 0.095f, 0.42f, 0.422f, 0.683f, 0.0f, 0.104f, 0.416f, 0.42f,
+ 0.688f, 0.0f, 0.112f, 0.411f, 0.421f, 0.693f, 0.0f, 0.12f, 0.403f, 0.417f, 0.698f, 0.0f, 0.128f, 0.394f, 0.411f, 0.702f, 0.0f, 0.135f, 0.382f, 0.404f,
+ 0.707f, 0.0f, 0.143f, 0.369f, 0.388f, 0.711f, 0.0f, 0.15f, 0.352f, 0.371f, 0.714f, 0.0f, 0.155f, 0.338f, 0.352f, 0.719f, 0.0f, 0.164f, 0.315f, 0.315f,
+};
+
+static const float data15[44 * GP_PRIM_DATABUF_SIZE] = {
+ -0.085f, 0.0f, -0.816f, 0.138f, 0.138f, -0.079f, 0.0f, -0.825f, 0.246f, 0.309f, -0.074f, 0.0f, -0.832f, 0.302f, 0.34f, -0.067f, 0.0f, -0.84f, 0.335f, 0.352f,
+ -0.059f, 0.0f, -0.848f, 0.357f, 0.374f, -0.05f, 0.0f, -0.855f, 0.371f, 0.378f, -0.041f, 0.0f, -0.861f, 0.382f, 0.383f, -0.031f, 0.0f, -0.866f, 0.391f, 0.396f,
+ -0.021f, 0.0f, -0.871f, 0.398f, 0.401f, -0.011f, 0.0f, -0.874f, 0.404f, 0.407f, -0.001f, 0.0f, -0.877f, 0.409f, 0.411f, 0.01f, 0.0f, -0.878f, 0.415f, 0.412f,
+ 0.02f, 0.0f, -0.878f, 0.422f, 0.417f, 0.031f, 0.0f, -0.878f, 0.43f, 0.421f, 0.042f, 0.0f, -0.876f, 0.438f, 0.437f, 0.052f, 0.0f, -0.873f, 0.445f, 0.451f,
+ 0.062f, 0.0f, -0.868f, 0.451f, 0.459f, 0.071f, 0.0f, -0.863f, 0.456f, 0.463f, 0.08f, 0.0f, -0.857f, 0.46f, 0.465f, 0.087f, 0.0f, -0.85f, 0.462f, 0.465f,
+ 0.094f, 0.0f, -0.842f, 0.461f, 0.465f, 0.098f, 0.0f, -0.835f, 0.458f, 0.467f, 0.101f, 0.0f, -0.827f, 0.451f, 0.457f, 0.103f, 0.0f, -0.82f, 0.436f, 0.451f,
+ 0.102f, 0.0f, -0.815f, 0.422f, 0.418f, 0.1f, 0.0f, -0.811f, 0.419f, 0.378f, 0.096f, 0.0f, -0.814f, 0.436f, 0.447f, 0.089f, 0.0f, -0.817f, 0.454f, 0.465f,
+ 0.082f, 0.0f, -0.821f, 0.465f, 0.47f, 0.072f, 0.0f, -0.825f, 0.473f, 0.477f, 0.061f, 0.0f, -0.828f, 0.477f, 0.479f, 0.049f, 0.0f, -0.832f, 0.48f, 0.485f,
+ 0.036f, 0.0f, -0.834f, 0.483f, 0.48f, 0.023f, 0.0f, -0.836f, 0.484f, 0.485f, 0.01f, 0.0f, -0.838f, 0.486f, 0.487f, -0.003f, 0.0f, -0.84f, 0.486f, 0.488f,
+ -0.016f, 0.0f, -0.84f, 0.486f, 0.489f, -0.027f, 0.0f, -0.84f, 0.485f, 0.485f, -0.039f, 0.0f, -0.839f, 0.484f, 0.484f, -0.049f, 0.0f, -0.837f, 0.483f, 0.485f,
+ -0.058f, 0.0f, -0.834f, 0.48f, 0.481f, -0.066f, 0.0f, -0.83f, 0.473f, 0.479f, -0.072f, 0.0f, -0.827f, 0.462f, 0.472f, -0.081f, 0.0f, -0.823f, 0.442f, 0.442f,
+};
+
+static const float data17[56 * GP_PRIM_DATABUF_SIZE] = {
+ -1.007f, -0.0f, 0.183f, 0.022f, 0.022f, -1.003f, -0.0f, 0.181f, 0.192f, 0.436f, -0.998f, -0.0f, 0.18f, 0.28f, 0.451f, -0.99f, -0.0f, 0.178f, 0.355f, 0.459f,
+ -0.98f, -0.0f, 0.175f, 0.402f, 0.464f, -0.967f, -0.0f, 0.169f, 0.432f, 0.467f, -0.952f, -0.0f, 0.152f, 0.449f, 0.468f, -0.943f, 0.0f, 0.138f, 0.459f, 0.469f,
+ -0.939f, 0.0f, 0.128f, 0.464f, 0.469f, -0.934f, 0.0f, 0.119f, 0.467f, 0.47f, -0.929f, 0.0f, 0.11f, 0.469f, 0.47f, -0.924f, 0.0f, 0.101f, 0.47f, 0.47f,
+ -0.919f, 0.0f, 0.092f, 0.47f, 0.471f, -0.913f, 0.0f, 0.082f, 0.471f, 0.471f, -0.908f, 0.0f, 0.072f, 0.471f, 0.471f, -0.903f, 0.0f, 0.063f, 0.472f, 0.472f,
+ -0.897f, 0.0f, 0.053f, 0.472f, 0.472f, -0.892f, 0.0f, 0.044f, 0.473f, 0.473f, -0.886f, 0.0f, 0.035f, 0.473f, 0.473f, -0.881f, 0.0f, 0.026f, 0.473f, 0.473f,
+ -0.876f, 0.0f, 0.018f, 0.473f, 0.473f, -0.87f, 0.0f, 0.012f, 0.472f, 0.473f, -0.865f, 0.0f, 0.006f, 0.47f, 0.473f, -0.86f, 0.0f, 0.003f, 0.468f, 0.473f,
+ -0.855f, 0.0f, 0.001f, 0.466f, 0.469f, -0.85f, 0.0f, 0.001f, 0.463f, 0.469f, -0.846f, 0.0f, 0.003f, 0.46f, 0.45f, -0.843f, 0.0f, 0.008f, 0.458f, 0.454f,
+ -0.84f, 0.0f, 0.014f, 0.456f, 0.454f, -0.838f, 0.0f, 0.021f, 0.455f, 0.454f, -0.836f, 0.0f, 0.03f, 0.453f, 0.455f, -0.835f, 0.0f, 0.039f, 0.451f, 0.455f,
+ -0.835f, 0.0f, 0.049f, 0.449f, 0.453f, -0.836f, 0.0f, 0.059f, 0.447f, 0.445f, -0.837f, 0.0f, 0.068f, 0.445f, 0.441f, -0.84f, 0.0f, 0.078f, 0.443f, 0.44f,
+ -0.843f, 0.0f, 0.087f, 0.442f, 0.44f, -0.846f, 0.0f, 0.095f, 0.442f, 0.44f, -0.851f, -0.0f, 0.103f, 0.441f, 0.441f, -0.855f, -0.0f, 0.111f, 0.441f, 0.44f,
+ -0.86f, -0.0f, 0.119f, 0.441f, 0.441f, -0.865f, -0.0f, 0.127f, 0.441f, 0.441f, -0.871f, -0.0f, 0.134f, 0.441f, 0.441f, -0.877f, -0.0f, 0.141f, 0.441f, 0.441f,
+ -0.883f, -0.0f, 0.149f, 0.441f, 0.442f, -0.889f, -0.0f, 0.156f, 0.441f, 0.441f, -0.896f, -0.0f, 0.163f, 0.441f, 0.442f, -0.904f, -0.0f, 0.169f, 0.442f, 0.441f,
+ -0.913f, -0.0f, 0.176f, 0.442f, 0.441f, -0.925f, -0.0f, 0.183f, 0.443f, 0.441f, -0.941f, -0.0f, 0.19f, 0.444f, 0.442f, -0.956f, -0.0f, 0.195f, 0.446f, 0.443f,
+ -0.971f, -0.0f, 0.198f, 0.448f, 0.443f, -0.983f, -0.0f, 0.198f, 0.451f, 0.452f, -0.992f, -0.0f, 0.198f, 0.454f, 0.456f, -1.001f, 0.0f, 0.196f, 0.457f, 0.457f,
+};
+
+static const float data18[59 * GP_PRIM_DATABUF_SIZE] = {
+ 0.782f, 0.0f, 0.099f, 0.04f, 0.04f, 0.779f, 0.0f, 0.088f, 0.108f, 0.34f, 0.777f, 0.0f, 0.08f, 0.149f, 0.35f, 0.774f, 0.0f, 0.071f, 0.194f, 0.352f,
+ 0.772f, 0.0f, 0.062f, 0.231f, 0.352f, 0.771f, 0.0f, 0.053f, 0.263f, 0.353f, 0.769f, 0.0f, 0.044f, 0.289f, 0.353f, 0.768f, 0.0f, 0.036f, 0.31f, 0.353f,
+ 0.767f, 0.0f, 0.029f, 0.327f, 0.353f, 0.767f, 0.0f, 0.023f, 0.341f, 0.353f, 0.767f, 0.0f, 0.017f, 0.353f, 0.353f, 0.768f, 0.0f, 0.013f, 0.363f, 0.353f,
+ 0.769f, 0.0f, 0.01f, 0.373f, 0.353f, 0.771f, 0.0f, 0.009f, 0.382f, 0.351f, 0.773f, 0.0f, 0.008f, 0.39f, 0.393f, 0.776f, 0.0f, 0.009f, 0.399f, 0.41f,
+ 0.779f, 0.0f, 0.011f, 0.407f, 0.425f, 0.783f, 0.0f, 0.015f, 0.415f, 0.434f, 0.787f, 0.0f, 0.019f, 0.423f, 0.44f, 0.792f, 0.0f, 0.024f, 0.429f, 0.441f,
+ 0.797f, 0.0f, 0.03f, 0.435f, 0.444f, 0.802f, 0.0f, 0.037f, 0.441f, 0.447f, 0.807f, 0.0f, 0.044f, 0.445f, 0.453f, 0.813f, 0.0f, 0.051f, 0.449f, 0.457f,
+ 0.819f, 0.0f, 0.058f, 0.452f, 0.458f, 0.825f, 0.0f, 0.066f, 0.455f, 0.46f, 0.831f, 0.0f, 0.074f, 0.457f, 0.462f, 0.838f, 0.0f, 0.082f, 0.459f, 0.462f,
+ 0.845f, 0.0f, 0.09f, 0.461f, 0.462f, 0.852f, 0.0f, 0.098f, 0.462f, 0.463f, 0.859f, 0.0f, 0.106f, 0.463f, 0.464f, 0.867f, 0.0f, 0.113f, 0.464f, 0.464f,
+ 0.874f, 0.0f, 0.121f, 0.465f, 0.465f, 0.882f, 0.0f, 0.129f, 0.465f, 0.465f, 0.889f, 0.0f, 0.136f, 0.466f, 0.466f, 0.897f, 0.0f, 0.143f, 0.466f, 0.467f,
+ 0.904f, 0.0f, 0.15f, 0.467f, 0.466f, 0.911f, 0.0f, 0.157f, 0.467f, 0.467f, 0.916f, 0.0f, 0.163f, 0.468f, 0.468f, 0.921f, 0.0f, 0.169f, 0.468f, 0.469f,
+ 0.924f, 0.0f, 0.173f, 0.468f, 0.469f, 0.926f, 0.0f, 0.177f, 0.469f, 0.468f, 0.925f, 0.0f, 0.18f, 0.469f, 0.468f, 0.922f, 0.0f, 0.181f, 0.469f, 0.469f,
+ 0.918f, 0.0f, 0.181f, 0.469f, 0.469f, 0.912f, 0.0f, 0.18f, 0.469f, 0.469f, 0.905f, 0.0f, 0.178f, 0.468f, 0.47f, 0.898f, 0.0f, 0.175f, 0.466f, 0.471f,
+ 0.89f, 0.0f, 0.172f, 0.462f, 0.469f, 0.882f, 0.0f, 0.168f, 0.454f, 0.468f, 0.874f, 0.0f, 0.164f, 0.442f, 0.467f, 0.866f, 0.0f, 0.159f, 0.423f, 0.467f,
+ 0.858f, 0.0f, 0.154f, 0.398f, 0.468f, 0.851f, 0.0f, 0.149f, 0.366f, 0.468f, 0.844f, 0.0f, 0.144f, 0.326f, 0.469f, 0.837f, 0.0f, 0.139f, 0.282f, 0.469f,
+ 0.83f, 0.0f, 0.134f, 0.231f, 0.467f, 0.824f, 0.0f, 0.13f, 0.184f, 0.415f, 0.816f, 0.0f, 0.124f, 0.111f, 0.111f,
+};
+
+static const float data19[100 * GP_PRIM_DATABUF_SIZE] = {
+ -0.279f, 0.0f, 0.568f, 0.154f, 0.154f, -0.266f, 0.0f, 0.569f, 0.249f, 0.318f, -0.258f, 0.0f, 0.57f, 0.296f, 0.357f, -0.248f, 0.0f, 0.571f, 0.337f, 0.383f,
+ -0.238f, 0.0f, 0.571f, 0.363f, 0.396f, -0.229f, 0.0f, 0.571f, 0.381f, 0.403f, -0.219f, 0.0f, 0.57f, 0.392f, 0.407f, -0.209f, 0.0f, 0.568f, 0.399f, 0.407f,
+ -0.2f, 0.0f, 0.566f, 0.403f, 0.408f, -0.19f, 0.0f, 0.563f, 0.406f, 0.41f, -0.181f, 0.0f, 0.559f, 0.407f, 0.41f, -0.171f, 0.0f, 0.555f, 0.409f, 0.41f,
+ -0.161f, 0.0f, 0.551f, 0.409f, 0.411f, -0.152f, 0.0f, 0.546f, 0.41f, 0.411f, -0.142f, 0.0f, 0.542f, 0.41f, 0.412f, -0.132f, 0.0f, 0.537f, 0.411f, 0.411f,
+ -0.122f, 0.0f, 0.533f, 0.411f, 0.411f, -0.112f, 0.0f, 0.528f, 0.411f, 0.412f, -0.102f, 0.0f, 0.524f, 0.411f, 0.412f, -0.092f, 0.0f, 0.519f, 0.41f, 0.412f,
+ -0.081f, 0.0f, 0.515f, 0.407f, 0.411f, -0.071f, 0.0f, 0.511f, 0.403f, 0.408f, -0.061f, 0.0f, 0.507f, 0.399f, 0.401f, -0.051f, 0.0f, 0.503f, 0.394f, 0.395f,
+ -0.041f, 0.0f, 0.499f, 0.39f, 0.388f, -0.031f, 0.0f, 0.495f, 0.386f, 0.383f, -0.021f, 0.0f, 0.491f, 0.383f, 0.38f, -0.011f, 0.0f, 0.488f, 0.381f, 0.378f,
+ -0.001f, 0.0f, 0.486f, 0.379f, 0.377f, 0.009f, 0.0f, 0.484f, 0.378f, 0.377f, 0.019f, 0.0f, 0.483f, 0.377f, 0.375f, 0.03f, 0.0f, 0.482f, 0.377f, 0.375f,
+ 0.041f, 0.0f, 0.482f, 0.378f, 0.376f, 0.051f, 0.0f, 0.483f, 0.379f, 0.376f, 0.062f, 0.0f, 0.484f, 0.381f, 0.376f, 0.073f, 0.0f, 0.486f, 0.385f, 0.379f,
+ 0.085f, 0.0f, 0.488f, 0.389f, 0.382f, 0.096f, 0.0f, 0.491f, 0.395f, 0.392f, 0.108f, 0.0f, 0.494f, 0.402f, 0.4f, 0.12f, 0.0f, 0.497f, 0.409f, 0.409f,
+ 0.132f, 0.0f, 0.501f, 0.415f, 0.416f, 0.144f, 0.0f, 0.505f, 0.421f, 0.427f, 0.157f, 0.0f, 0.509f, 0.425f, 0.43f, 0.17f, 0.0f, 0.513f, 0.429f, 0.433f,
+ 0.181f, 0.0f, 0.517f, 0.431f, 0.433f, 0.192f, 0.0f, 0.52f, 0.433f, 0.434f, 0.201f, 0.0f, 0.522f, 0.433f, 0.435f, 0.208f, 0.0f, 0.524f, 0.433f, 0.435f,
+ 0.213f, 0.0f, 0.524f, 0.432f, 0.436f, 0.216f, 0.0f, 0.523f, 0.431f, 0.435f, 0.217f, 0.0f, 0.521f, 0.43f, 0.426f, 0.215f, 0.0f, 0.518f, 0.429f, 0.427f,
+ 0.213f, 0.0f, 0.515f, 0.428f, 0.427f, 0.208f, 0.0f, 0.511f, 0.428f, 0.427f, 0.203f, 0.0f, 0.506f, 0.428f, 0.427f, 0.196f, 0.0f, 0.502f, 0.428f, 0.427f,
+ 0.189f, 0.0f, 0.497f, 0.428f, 0.427f, 0.181f, 0.0f, 0.492f, 0.428f, 0.427f, 0.173f, 0.0f, 0.487f, 0.428f, 0.428f, 0.163f, 0.0f, 0.482f, 0.429f, 0.428f,
+ 0.154f, 0.0f, 0.477f, 0.429f, 0.429f, 0.145f, 0.0f, 0.472f, 0.43f, 0.43f, 0.135f, 0.0f, 0.467f, 0.431f, 0.431f, 0.125f, 0.0f, 0.462f, 0.432f, 0.43f,
+ 0.116f, 0.0f, 0.457f, 0.433f, 0.431f, 0.106f, 0.0f, 0.453f, 0.435f, 0.434f, 0.096f, 0.0f, 0.448f, 0.436f, 0.436f, 0.086f, 0.0f, 0.444f, 0.437f, 0.438f,
+ 0.076f, 0.0f, 0.44f, 0.438f, 0.44f, 0.065f, 0.0f, 0.436f, 0.439f, 0.441f, 0.055f, 0.0f, 0.433f, 0.44f, 0.441f, 0.044f, 0.0f, 0.431f, 0.441f, 0.442f,
+ 0.033f, 0.0f, 0.429f, 0.441f, 0.442f, 0.022f, 0.0f, 0.427f, 0.441f, 0.442f, 0.011f, 0.0f, 0.426f, 0.442f, 0.443f, -0.0f, 0.0f, 0.426f, 0.442f, 0.442f,
+ -0.011f, 0.0f, 0.426f, 0.442f, 0.442f, -0.022f, 0.0f, 0.427f, 0.442f, 0.442f, -0.033f, 0.0f, 0.429f, 0.442f, 0.442f, -0.042f, 0.0f, 0.432f, 0.441f, 0.442f,
+ -0.052f, 0.0f, 0.435f, 0.441f, 0.441f, -0.061f, 0.0f, 0.439f, 0.441f, 0.441f, -0.07f, 0.0f, 0.443f, 0.441f, 0.441f, -0.078f, 0.0f, 0.448f, 0.441f, 0.441f,
+ -0.087f, 0.0f, 0.453f, 0.441f, 0.442f, -0.095f, 0.0f, 0.458f, 0.441f, 0.441f, -0.104f, 0.0f, 0.463f, 0.44f, 0.44f, -0.113f, 0.0f, 0.468f, 0.44f, 0.44f,
+ -0.122f, 0.0f, 0.473f, 0.44f, 0.44f, -0.132f, 0.0f, 0.479f, 0.44f, 0.44f, -0.143f, 0.0f, 0.485f, 0.44f, 0.44f, -0.154f, 0.0f, 0.491f, 0.44f, 0.44f,
+ -0.165f, 0.0f, 0.498f, 0.44f, 0.44f, -0.176f, 0.0f, 0.504f, 0.439f, 0.439f, -0.187f, 0.0f, 0.51f, 0.435f, 0.44f, -0.198f, 0.0f, 0.516f, 0.424f, 0.44f,
+ -0.209f, 0.0f, 0.522f, 0.393f, 0.44f, -0.219f, 0.0f, 0.527f, 0.324f, 0.44f, -0.228f, 0.0f, 0.532f, 0.222f, 0.404f, -0.241f, 0.0f, 0.538f, 0.037f, 0.037f,
+};
+
+static const float data20[136 * GP_PRIM_DATABUF_SIZE] = {
+ 0.331f, 0.0f, -0.036f, 0.065f, 0.065f, 0.322f, 0.0f, -0.034f, 0.239f, 0.293f, 0.317f, 0.0f, -0.032f, 0.316f, 0.339f, 0.31f, 0.0f, -0.029f, 0.348f, 0.355f,
+ 0.302f, 0.0f, -0.027f, 0.364f, 0.368f, 0.295f, 0.0f, -0.023f, 0.373f, 0.374f, 0.287f, 0.0f, -0.02f, 0.381f, 0.381f, 0.279f, 0.0f, -0.015f, 0.388f, 0.391f,
+ 0.271f, 0.0f, -0.01f, 0.392f, 0.394f, 0.263f, 0.0f, -0.004f, 0.395f, 0.396f, 0.255f, 0.0f, 0.002f, 0.397f, 0.397f, 0.247f, 0.0f, 0.008f, 0.399f, 0.4f,
+ 0.239f, 0.0f, 0.016f, 0.401f, 0.401f, 0.232f, -0.0f, 0.024f, 0.404f, 0.404f, 0.226f, 0.0f, 0.031f, 0.406f, 0.407f, 0.221f, 0.0f, 0.038f, 0.409f, 0.409f,
+ 0.215f, 0.0f, 0.045f, 0.412f, 0.412f, 0.21f, 0.0f, 0.054f, 0.415f, 0.415f, 0.205f, 0.0f, 0.063f, 0.417f, 0.417f, 0.201f, 0.0f, 0.073f, 0.42f, 0.421f,
+ 0.197f, 0.0f, 0.083f, 0.421f, 0.421f, 0.193f, -0.0f, 0.094f, 0.423f, 0.423f, 0.19f, -0.0f, 0.104f, 0.424f, 0.424f, 0.187f, -0.0f, 0.114f, 0.424f, 0.425f,
+ 0.185f, -0.0f, 0.125f, 0.425f, 0.425f, 0.183f, -0.0f, 0.135f, 0.425f, 0.425f, 0.182f, -0.0f, 0.146f, 0.426f, 0.425f, 0.181f, -0.0f, 0.157f, 0.426f, 0.425f,
+ 0.18f, -0.0f, 0.168f, 0.426f, 0.426f, 0.18f, -0.0f, 0.179f, 0.427f, 0.427f, 0.181f, -0.0f, 0.189f, 0.427f, 0.427f, 0.182f, -0.0f, 0.199f, 0.427f, 0.427f,
+ 0.183f, -0.0f, 0.208f, 0.427f, 0.428f, 0.185f, -0.0f, 0.218f, 0.428f, 0.427f, 0.187f, -0.0f, 0.226f, 0.428f, 0.427f, 0.19f, -0.0f, 0.235f, 0.429f, 0.427f,
+ 0.192f, -0.0f, 0.243f, 0.43f, 0.428f, 0.196f, -0.0f, 0.252f, 0.431f, 0.431f, 0.199f, -0.0f, 0.26f, 0.431f, 0.432f, 0.203f, -0.0f, 0.268f, 0.432f, 0.433f,
+ 0.207f, -0.0f, 0.276f, 0.433f, 0.433f, 0.212f, -0.0f, 0.283f, 0.434f, 0.434f, 0.216f, -0.0f, 0.291f, 0.434f, 0.435f, 0.221f, -0.0f, 0.298f, 0.435f, 0.436f,
+ 0.227f, -0.0f, 0.305f, 0.435f, 0.435f, 0.232f, -0.0f, 0.311f, 0.436f, 0.436f, 0.238f, -0.0f, 0.317f, 0.436f, 0.436f, 0.243f, -0.0f, 0.323f, 0.436f, 0.436f,
+ 0.249f, -0.0f, 0.329f, 0.437f, 0.436f, 0.255f, -0.0f, 0.334f, 0.438f, 0.437f, 0.262f, -0.0f, 0.339f, 0.44f, 0.437f, 0.268f, -0.0f, 0.344f, 0.442f, 0.441f,
+ 0.274f, 0.0f, 0.348f, 0.444f, 0.446f, 0.281f, 0.0f, 0.352f, 0.445f, 0.447f, 0.287f, 0.0f, 0.355f, 0.446f, 0.447f, 0.293f, 0.0f, 0.358f, 0.446f, 0.447f,
+ 0.299f, 0.0f, 0.361f, 0.447f, 0.447f, 0.306f, 0.0f, 0.363f, 0.447f, 0.448f, 0.312f, 0.0f, 0.366f, 0.447f, 0.448f, 0.318f, 0.0f, 0.368f, 0.448f, 0.448f,
+ 0.325f, 0.0f, 0.369f, 0.448f, 0.448f, 0.331f, 0.0f, 0.371f, 0.448f, 0.448f, 0.338f, 0.0f, 0.372f, 0.448f, 0.448f, 0.345f, 0.0f, 0.372f, 0.448f, 0.448f,
+ 0.352f, 0.0f, 0.372f, 0.448f, 0.448f, 0.359f, 0.0f, 0.372f, 0.448f, 0.449f, 0.366f, 0.0f, 0.371f, 0.448f, 0.448f, 0.373f, 0.0f, 0.37f, 0.448f, 0.449f,
+ 0.38f, 0.0f, 0.369f, 0.449f, 0.449f, 0.387f, 0.0f, 0.367f, 0.449f, 0.449f, 0.393f, 0.0f, 0.365f, 0.449f, 0.449f, 0.4f, 0.0f, 0.363f, 0.449f, 0.45f,
+ 0.406f, 0.0f, 0.36f, 0.45f, 0.45f, 0.412f, -0.0f, 0.357f, 0.45f, 0.45f, 0.418f, -0.0f, 0.354f, 0.45f, 0.451f, 0.424f, -0.0f, 0.351f, 0.45f, 0.451f,
+ 0.43f, -0.0f, 0.347f, 0.45f, 0.451f, 0.436f, -0.0f, 0.343f, 0.45f, 0.451f, 0.443f, -0.0f, 0.339f, 0.45f, 0.45f, 0.449f, -0.0f, 0.334f, 0.45f, 0.451f,
+ 0.455f, -0.0f, 0.329f, 0.451f, 0.451f, 0.46f, -0.0f, 0.323f, 0.451f, 0.451f, 0.466f, -0.0f, 0.318f, 0.451f, 0.451f, 0.472f, -0.0f, 0.311f, 0.452f, 0.452f,
+ 0.477f, -0.0f, 0.305f, 0.452f, 0.453f, 0.482f, -0.0f, 0.298f, 0.452f, 0.453f, 0.487f, -0.0f, 0.291f, 0.453f, 0.453f, 0.492f, -0.0f, 0.284f, 0.453f, 0.453f,
+ 0.496f, -0.0f, 0.277f, 0.453f, 0.453f, 0.5f, -0.0f, 0.269f, 0.453f, 0.454f, 0.504f, -0.0f, 0.261f, 0.453f, 0.454f, 0.508f, -0.0f, 0.252f, 0.454f, 0.454f,
+ 0.511f, -0.0f, 0.244f, 0.454f, 0.454f, 0.514f, -0.0f, 0.235f, 0.454f, 0.455f, 0.517f, -0.0f, 0.225f, 0.454f, 0.455f, 0.519f, -0.0f, 0.216f, 0.454f, 0.455f,
+ 0.521f, -0.0f, 0.205f, 0.455f, 0.455f, 0.523f, -0.0f, 0.194f, 0.455f, 0.455f, 0.524f, -0.0f, 0.182f, 0.455f, 0.455f, 0.524f, -0.0f, 0.169f, 0.455f, 0.456f,
+ 0.524f, -0.0f, 0.157f, 0.455f, 0.456f, 0.523f, -0.0f, 0.145f, 0.455f, 0.456f, 0.522f, -0.0f, 0.133f, 0.455f, 0.456f, 0.52f, -0.0f, 0.122f, 0.456f, 0.456f,
+ 0.518f, -0.0f, 0.11f, 0.456f, 0.456f, 0.515f, -0.0f, 0.1f, 0.456f, 0.456f, 0.513f, -0.0f, 0.09f, 0.456f, 0.457f, 0.509f, -0.0f, 0.081f, 0.456f, 0.457f,
+ 0.506f, -0.0f, 0.072f, 0.457f, 0.457f, 0.502f, -0.0f, 0.064f, 0.457f, 0.457f, 0.498f, -0.0f, 0.056f, 0.457f, 0.457f, 0.494f, -0.0f, 0.049f, 0.457f, 0.457f,
+ 0.49f, -0.0f, 0.041f, 0.458f, 0.457f, 0.485f, -0.0f, 0.034f, 0.458f, 0.457f, 0.48f, -0.0f, 0.028f, 0.458f, 0.458f, 0.475f, -0.0f, 0.022f, 0.458f, 0.458f,
+ 0.47f, -0.0f, 0.016f, 0.458f, 0.458f, 0.465f, -0.0f, 0.011f, 0.459f, 0.458f, 0.46f, -0.0f, 0.006f, 0.459f, 0.458f, 0.454f, -0.0f, 0.001f, 0.46f, 0.459f,
+ 0.449f, 0.0f, -0.003f, 0.464f, 0.463f, 0.443f, 0.0f, -0.007f, 0.467f, 0.468f, 0.438f, 0.0f, -0.011f, 0.469f, 0.469f, 0.432f, 0.0f, -0.015f, 0.471f, 0.47f,
+ 0.426f, 0.0f, -0.018f, 0.477f, 0.478f, 0.42f, 0.0f, -0.021f, 0.478f, 0.478f, 0.414f, 0.0f, -0.024f, 0.478f, 0.478f, 0.408f, 0.0f, -0.027f, 0.479f, 0.479f,
+ 0.402f, 0.0f, -0.029f, 0.48f, 0.48f, 0.395f, 0.0f, -0.031f, 0.48f, 0.48f, 0.389f, 0.0f, -0.033f, 0.482f, 0.482f, 0.382f, 0.0f, -0.035f, 0.482f, 0.482f,
+ 0.376f, 0.0f, -0.036f, 0.482f, 0.482f, 0.369f, 0.0f, -0.037f, 0.48f, 0.482f, 0.364f, 0.0f, -0.037f, 0.457f, 0.485f, 0.356f, 0.0f, -0.038f, 0.32f, 0.32f,
+};
+
+static const float data21[353 * GP_PRIM_DATABUF_SIZE] = {
+ -0.382f, 0.0f, 0.397f, 0.0f, 1.0f, -0.386f, 0.0f, 0.394f, 0.0f, 1.0f, -0.389f, 0.0f, 0.392f, 0.0f, 1.0f, -0.392f, 0.0f, 0.39f, 0.0f, 1.0f,
+ -0.395f, 0.0f, 0.388f, 0.0f, 1.0f, -0.399f, 0.0f, 0.385f, 0.0f, 1.0f, -0.402f, 0.0f, 0.383f, 0.0f, 1.0f, -0.405f, 0.0f, 0.381f, 0.0f, 1.0f,
+ -0.408f, 0.0f, 0.379f, 0.0f, 1.0f, -0.411f, 0.0f, 0.377f, 0.0f, 1.0f, -0.414f, 0.0f, 0.375f, 0.0f, 1.0f, -0.417f, 0.0f, 0.372f, 0.0f, 1.0f,
+ -0.42f, 0.0f, 0.37f, 0.0f, 1.0f, -0.423f, 0.0f, 0.368f, 0.0f, 1.0f, -0.425f, 0.0f, 0.366f, 0.0f, 1.0f, -0.428f, 0.0f, 0.364f, 0.0f, 1.0f,
+ -0.431f, 0.0f, 0.362f, 0.0f, 1.0f, -0.433f, 0.0f, 0.359f, 0.0f, 1.0f, -0.436f, 0.0f, 0.357f, 0.0f, 1.0f, -0.438f, 0.0f, 0.355f, 0.0f, 1.0f,
+ -0.441f, 0.0f, 0.353f, 0.0f, 1.0f, -0.443f, 0.0f, 0.351f, 0.0f, 1.0f, -0.445f, 0.0f, 0.349f, 0.0f, 1.0f, -0.447f, 0.0f, 0.346f, 0.0f, 1.0f,
+ -0.45f, 0.0f, 0.344f, 0.0f, 1.0f, -0.452f, 0.0f, 0.342f, 0.0f, 1.0f, -0.454f, 0.0f, 0.34f, 0.0f, 1.0f, -0.456f, 0.0f, 0.337f, 0.0f, 1.0f,
+ -0.458f, 0.0f, 0.335f, 0.0f, 1.0f, -0.46f, 0.0f, 0.333f, 0.0f, 1.0f, -0.462f, 0.0f, 0.33f, 0.0f, 1.0f, -0.464f, 0.0f, 0.328f, 0.0f, 1.0f,
+ -0.466f, 0.0f, 0.326f, 0.0f, 1.0f, -0.468f, 0.0f, 0.323f, 0.0f, 1.0f, -0.47f, 0.0f, 0.321f, 0.0f, 1.0f, -0.472f, 0.0f, 0.319f, 0.0f, 1.0f,
+ -0.474f, 0.0f, 0.316f, 0.0f, 1.0f, -0.475f, 0.0f, 0.314f, 0.0f, 1.0f, -0.477f, 0.0f, 0.311f, 0.0f, 1.0f, -0.479f, 0.0f, 0.309f, 0.0f, 1.0f,
+ -0.481f, 0.0f, 0.307f, 0.0f, 1.0f, -0.482f, 0.0f, 0.304f, 0.0f, 1.0f, -0.484f, 0.0f, 0.302f, 0.0f, 1.0f, -0.486f, 0.0f, 0.299f, 0.0f, 1.0f,
+ -0.487f, 0.0f, 0.297f, 0.0f, 1.0f, -0.489f, 0.0f, 0.294f, 0.0f, 1.0f, -0.49f, 0.0f, 0.292f, 0.0f, 1.0f, -0.492f, 0.0f, 0.289f, 0.0f, 1.0f,
+ -0.494f, 0.0f, 0.286f, 0.0f, 1.0f, -0.495f, 0.0f, 0.284f, 0.0f, 1.0f, -0.497f, 0.0f, 0.281f, 0.0f, 1.0f, -0.498f, 0.0f, 0.279f, 0.001f, 1.0f,
+ -0.499f, 0.0f, 0.276f, 0.001f, 1.0f, -0.501f, 0.0f, 0.273f, 0.002f, 1.0f, -0.502f, 0.0f, 0.271f, 0.003f, 1.0f, -0.504f, 0.0f, 0.268f, 0.005f, 1.0f,
+ -0.505f, 0.0f, 0.265f, 0.008f, 1.0f, -0.506f, 0.0f, 0.262f, 0.011f, 1.0f, -0.508f, 0.0f, 0.259f, 0.016f, 1.0f, -0.509f, 0.0f, 0.256f, 0.021f, 1.0f,
+ -0.51f, 0.0f, 0.254f, 0.027f, 1.0f, -0.512f, 0.0f, 0.251f, 0.035f, 1.0f, -0.513f, 0.0f, 0.248f, 0.043f, 1.0f, -0.514f, 0.0f, 0.245f, 0.053f, 1.0f,
+ -0.515f, 0.0f, 0.242f, 0.064f, 1.0f, -0.516f, 0.0f, 0.239f, 0.076f, 1.0f, -0.517f, 0.0f, 0.235f, 0.09f, 1.0f, -0.519f, 0.0f, 0.232f, 0.105f, 1.0f,
+ -0.52f, 0.0f, 0.229f, 0.122f, 1.0f, -0.521f, 0.0f, 0.226f, 0.14f, 1.0f, -0.521f, 0.0f, 0.222f, 0.159f, 1.0f, -0.522f, 0.0f, 0.219f, 0.179f, 1.0f,
+ -0.523f, 0.0f, 0.216f, 0.2f, 1.0f, -0.524f, 0.0f, 0.212f, 0.221f, 1.0f, -0.525f, 0.0f, 0.209f, 0.243f, 1.0f, -0.526f, 0.0f, 0.205f, 0.265f, 1.0f,
+ -0.526f, 0.0f, 0.202f, 0.286f, 1.0f, -0.527f, 0.0f, 0.198f, 0.306f, 1.0f, -0.527f, 0.0f, 0.195f, 0.326f, 1.0f, -0.528f, 0.0f, 0.191f, 0.345f, 1.0f,
+ -0.528f, 0.0f, 0.187f, 0.363f, 1.0f, -0.529f, 0.0f, 0.184f, 0.38f, 1.0f, -0.529f, 0.0f, 0.18f, 0.395f, 1.0f, -0.529f, 0.0f, 0.176f, 0.41f, 1.0f,
+ -0.53f, 0.0f, 0.173f, 0.424f, 1.0f, -0.53f, 0.0f, 0.169f, 0.438f, 1.0f, -0.53f, 0.0f, 0.165f, 0.452f, 1.0f, -0.53f, 0.0f, 0.161f, 0.465f, 1.0f,
+ -0.53f, 0.0f, 0.157f, 0.478f, 1.0f, -0.53f, 0.0f, 0.154f, 0.492f, 1.0f, -0.53f, 0.0f, 0.15f, 0.505f, 1.0f, -0.53f, 0.0f, 0.146f, 0.517f, 1.0f,
+ -0.53f, 0.0f, 0.142f, 0.53f, 1.0f, -0.529f, 0.0f, 0.138f, 0.542f, 1.0f, -0.529f, 0.0f, 0.134f, 0.553f, 1.0f, -0.528f, 0.0f, 0.13f, 0.564f, 1.0f,
+ -0.528f, 0.0f, 0.127f, 0.574f, 1.0f, -0.527f, 0.0f, 0.123f, 0.583f, 1.0f, -0.527f, 0.0f, 0.119f, 0.592f, 1.0f, -0.526f, 0.0f, 0.115f, 0.6f, 1.0f,
+ -0.526f, 0.0f, 0.111f, 0.608f, 1.0f, -0.525f, 0.0f, 0.108f, 0.615f, 1.0f, -0.524f, 0.0f, 0.104f, 0.622f, 1.0f, -0.523f, 0.0f, 0.1f, 0.628f, 1.0f,
+ -0.522f, 0.0f, 0.097f, 0.635f, 1.0f, -0.521f, 0.0f, 0.093f, 0.641f, 1.0f, -0.52f, 0.0f, 0.089f, 0.647f, 1.0f, -0.519f, 0.0f, 0.086f, 0.653f, 1.0f,
+ -0.518f, 0.0f, 0.082f, 0.659f, 1.0f, -0.517f, 0.0f, 0.079f, 0.664f, 1.0f, -0.515f, 0.0f, 0.075f, 0.67f, 1.0f, -0.514f, 0.0f, 0.072f, 0.675f, 1.0f,
+ -0.513f, 0.0f, 0.069f, 0.68f, 1.0f, -0.511f, 0.0f, 0.065f, 0.685f, 1.0f, -0.51f, 0.0f, 0.062f, 0.69f, 1.0f, -0.509f, 0.0f, 0.059f, 0.695f, 1.0f,
+ -0.507f, 0.0f, 0.056f, 0.7f, 1.0f, -0.505f, 0.0f, 0.053f, 0.704f, 1.0f, -0.504f, 0.0f, 0.049f, 0.709f, 1.0f, -0.502f, 0.0f, 0.046f, 0.714f, 1.0f,
+ -0.5f, 0.0f, 0.043f, 0.719f, 1.0f, -0.499f, 0.0f, 0.04f, 0.724f, 1.0f, -0.497f, 0.0f, 0.038f, 0.73f, 1.0f, -0.495f, 0.0f, 0.035f, 0.735f, 1.0f,
+ -0.493f, 0.0f, 0.032f, 0.741f, 1.0f, -0.491f, 0.0f, 0.029f, 0.748f, 1.0f, -0.489f, 0.0f, 0.026f, 0.754f, 1.0f, -0.488f, -0.0f, 0.024f, 0.76f, 1.0f,
+ -0.486f, -0.0f, 0.022f, 0.767f, 1.0f, -0.485f, -0.0f, 0.019f, 0.773f, 1.0f, -0.483f, -0.0f, 0.017f, 0.779f, 1.0f, -0.482f, -0.0f, 0.015f, 0.785f, 1.0f,
+ -0.48f, -0.0f, 0.013f, 0.79f, 1.0f, -0.478f, -0.0f, 0.01f, 0.795f, 1.0f, -0.476f, -0.0f, 0.008f, 0.8f, 1.0f, -0.474f, -0.0f, 0.006f, 0.804f, 1.0f,
+ -0.472f, -0.0f, 0.004f, 0.808f, 1.0f, -0.47f, -0.0f, 0.002f, 0.811f, 1.0f, -0.468f, -0.0f, -0.0f, 0.814f, 1.0f, -0.466f, -0.0f, -0.002f, 0.816f, 1.0f,
+ -0.464f, -0.0f, -0.004f, 0.818f, 1.0f, -0.461f, -0.0f, -0.006f, 0.82f, 1.0f, -0.459f, -0.0f, -0.008f, 0.822f, 1.0f, -0.456f, -0.0f, -0.01f, 0.823f, 1.0f,
+ -0.454f, -0.0f, -0.012f, 0.825f, 1.0f, -0.451f, -0.0f, -0.014f, 0.826f, 1.0f, -0.448f, -0.0f, -0.016f, 0.827f, 1.0f, -0.445f, -0.0f, -0.018f, 0.828f, 1.0f,
+ -0.442f, -0.0f, -0.02f, 0.829f, 1.0f, -0.439f, -0.0f, -0.022f, 0.829f, 1.0f, -0.436f, -0.0f, -0.024f, 0.83f, 1.0f, -0.433f, -0.0f, -0.026f, 0.83f, 1.0f,
+ -0.43f, -0.0f, -0.027f, 0.83f, 1.0f, -0.426f, -0.0f, -0.029f, 0.83f, 1.0f, -0.423f, 0.0f, -0.031f, 0.83f, 1.0f, -0.42f, 0.0f, -0.032f, 0.83f, 1.0f,
+ -0.417f, 0.0f, -0.033f, 0.831f, 1.0f, -0.414f, 0.0f, -0.034f, 0.831f, 1.0f, -0.411f, 0.0f, -0.035f, 0.831f, 1.0f, -0.408f, 0.0f, -0.037f, 0.831f, 1.0f,
+ -0.405f, 0.0f, -0.038f, 0.831f, 1.0f, -0.402f, 0.0f, -0.039f, 0.831f, 1.0f, -0.399f, 0.0f, -0.039f, 0.831f, 1.0f, -0.396f, 0.0f, -0.04f, 0.832f, 1.0f,
+ -0.393f, 0.0f, -0.041f, 0.832f, 1.0f, -0.389f, 0.0f, -0.042f, 0.832f, 1.0f, -0.386f, 0.0f, -0.043f, 0.832f, 1.0f, -0.383f, 0.0f, -0.044f, 0.832f, 1.0f,
+ -0.379f, 0.0f, -0.044f, 0.832f, 1.0f, -0.376f, 0.0f, -0.045f, 0.832f, 1.0f, -0.372f, 0.0f, -0.045f, 0.832f, 1.0f, -0.369f, 0.0f, -0.046f, 0.832f, 1.0f,
+ -0.366f, 0.0f, -0.047f, 0.832f, 1.0f, -0.362f, 0.0f, -0.047f, 0.832f, 1.0f, -0.359f, 0.0f, -0.047f, 0.831f, 1.0f, -0.355f, 0.0f, -0.048f, 0.831f, 1.0f,
+ -0.352f, 0.0f, -0.048f, 0.83f, 1.0f, -0.348f, 0.0f, -0.048f, 0.83f, 1.0f, -0.345f, 0.0f, -0.049f, 0.829f, 1.0f, -0.341f, 0.0f, -0.049f, 0.828f, 1.0f,
+ -0.338f, 0.0f, -0.049f, 0.827f, 1.0f, -0.334f, 0.0f, -0.049f, 0.826f, 1.0f, -0.331f, 0.0f, -0.049f, 0.823f, 1.0f, -0.327f, 0.0f, -0.049f, 0.82f, 1.0f,
+ -0.323f, 0.0f, -0.048f, 0.816f, 1.0f, -0.32f, 0.0f, -0.048f, 0.811f, 1.0f, -0.316f, 0.0f, -0.048f, 0.804f, 1.0f, -0.313f, 0.0f, -0.048f, 0.797f, 1.0f,
+ -0.309f, 0.0f, -0.047f, 0.79f, 1.0f, -0.306f, 0.0f, -0.047f, 0.782f, 1.0f, -0.302f, 0.0f, -0.046f, 0.774f, 1.0f, -0.299f, 0.0f, -0.045f, 0.767f, 1.0f,
+ -0.295f, 0.0f, -0.044f, 0.76f, 1.0f, -0.292f, 0.0f, -0.044f, 0.753f, 1.0f, -0.288f, 0.0f, -0.043f, 0.748f, 1.0f, -0.285f, 0.0f, -0.042f, 0.742f, 1.0f,
+ -0.282f, 0.0f, -0.041f, 0.738f, 1.0f, -0.278f, 0.0f, -0.04f, 0.734f, 1.0f, -0.275f, 0.0f, -0.039f, 0.73f, 1.0f, -0.272f, 0.0f, -0.037f, 0.726f, 1.0f,
+ -0.269f, 0.0f, -0.036f, 0.723f, 1.0f, -0.266f, 0.0f, -0.035f, 0.72f, 1.0f, -0.263f, 0.0f, -0.034f, 0.717f, 1.0f, -0.26f, 0.0f, -0.032f, 0.713f, 1.0f,
+ -0.257f, 0.0f, -0.031f, 0.71f, 1.0f, -0.255f, 0.0f, -0.029f, 0.706f, 1.0f, -0.252f, 0.0f, -0.028f, 0.702f, 1.0f, -0.249f, 0.0f, -0.026f, 0.698f, 1.0f,
+ -0.247f, 0.0f, -0.025f, 0.693f, 1.0f, -0.244f, 0.0f, -0.023f, 0.688f, 1.0f, -0.242f, 0.0f, -0.021f, 0.684f, 1.0f, -0.239f, 0.0f, -0.02f, 0.679f, 1.0f,
+ -0.237f, 0.0f, -0.018f, 0.675f, 1.0f, -0.234f, 0.0f, -0.016f, 0.671f, 1.0f, -0.232f, 0.0f, -0.014f, 0.667f, 1.0f, -0.23f, 0.0f, -0.013f, 0.663f, 1.0f,
+ -0.228f, 0.0f, -0.011f, 0.66f, 1.0f, -0.225f, 0.0f, -0.009f, 0.657f, 1.0f, -0.223f, 0.0f, -0.007f, 0.654f, 1.0f, -0.221f, 0.0f, -0.005f, 0.651f, 1.0f,
+ -0.219f, 0.0f, -0.003f, 0.649f, 1.0f, -0.217f, 0.0f, -0.001f, 0.645f, 1.0f, -0.215f, 0.0f, 0.002f, 0.642f, 1.0f, -0.213f, 0.0f, 0.004f, 0.639f, 1.0f,
+ -0.211f, 0.0f, 0.006f, 0.635f, 1.0f, -0.209f, 0.0f, 0.008f, 0.631f, 1.0f, -0.207f, 0.0f, 0.011f, 0.627f, 1.0f, -0.206f, 0.0f, 0.013f, 0.623f, 1.0f,
+ -0.204f, 0.0f, 0.016f, 0.619f, 1.0f, -0.202f, 0.0f, 0.018f, 0.615f, 1.0f, -0.2f, 0.0f, 0.021f, 0.61f, 1.0f, -0.199f, 0.0f, 0.023f, 0.606f, 1.0f,
+ -0.197f, 0.0f, 0.026f, 0.602f, 1.0f, -0.195f, 0.0f, 0.029f, 0.598f, 1.0f, -0.194f, 0.0f, 0.032f, 0.595f, 1.0f, -0.192f, 0.0f, 0.034f, 0.592f, 1.0f,
+ -0.191f, 0.0f, 0.037f, 0.589f, 1.0f, -0.19f, 0.0f, 0.04f, 0.587f, 1.0f, -0.188f, 0.0f, 0.043f, 0.585f, 1.0f, -0.187f, 0.0f, 0.046f, 0.584f, 1.0f,
+ -0.186f, 0.0f, 0.05f, 0.583f, 1.0f, -0.185f, 0.0f, 0.053f, 0.582f, 1.0f, -0.183f, 0.0f, 0.056f, 0.581f, 1.0f, -0.182f, 0.0f, 0.059f, 0.581f, 1.0f,
+ -0.181f, 0.0f, 0.062f, 0.581f, 1.0f, -0.18f, 0.0f, 0.066f, 0.581f, 1.0f, -0.179f, 0.0f, 0.069f, 0.58f, 1.0f, -0.178f, 0.0f, 0.072f, 0.58f, 1.0f,
+ -0.177f, 0.0f, 0.076f, 0.58f, 1.0f, -0.177f, 0.0f, 0.079f, 0.58f, 1.0f, -0.176f, 0.0f, 0.083f, 0.58f, 1.0f, -0.175f, 0.0f, 0.086f, 0.58f, 1.0f,
+ -0.174f, 0.0f, 0.09f, 0.58f, 1.0f, -0.174f, 0.0f, 0.093f, 0.58f, 1.0f, -0.173f, 0.0f, 0.097f, 0.58f, 1.0f, -0.172f, 0.0f, 0.1f, 0.58f, 1.0f,
+ -0.172f, 0.0f, 0.104f, 0.58f, 1.0f, -0.171f, 0.0f, 0.108f, 0.579f, 1.0f, -0.171f, 0.0f, 0.111f, 0.579f, 1.0f, -0.17f, 0.0f, 0.115f, 0.578f, 1.0f,
+ -0.17f, 0.0f, 0.119f, 0.578f, 1.0f, -0.17f, 0.0f, 0.122f, 0.577f, 1.0f, -0.169f, 0.0f, 0.126f, 0.577f, 1.0f, -0.169f, 0.0f, 0.13f, 0.576f, 1.0f,
+ -0.169f, 0.0f, 0.134f, 0.576f, 1.0f, -0.169f, 0.0f, 0.137f, 0.575f, 1.0f, -0.169f, 0.0f, 0.141f, 0.575f, 1.0f, -0.169f, 0.0f, 0.145f, 0.574f, 1.0f,
+ -0.169f, 0.0f, 0.149f, 0.572f, 1.0f, -0.169f, 0.0f, 0.153f, 0.571f, 1.0f, -0.169f, 0.0f, 0.157f, 0.569f, 1.0f, -0.169f, 0.0f, 0.16f, 0.566f, 1.0f,
+ -0.169f, 0.0f, 0.164f, 0.562f, 1.0f, -0.17f, 0.0f, 0.168f, 0.558f, 1.0f, -0.17f, 0.0f, 0.172f, 0.553f, 1.0f, -0.17f, 0.0f, 0.176f, 0.547f, 1.0f,
+ -0.171f, 0.0f, 0.18f, 0.539f, 1.0f, -0.171f, 0.0f, 0.183f, 0.531f, 1.0f, -0.172f, 0.0f, 0.187f, 0.522f, 1.0f, -0.172f, 0.0f, 0.191f, 0.513f, 1.0f,
+ -0.173f, 0.0f, 0.194f, 0.503f, 1.0f, -0.173f, 0.0f, 0.198f, 0.493f, 1.0f, -0.174f, 0.0f, 0.202f, 0.483f, 1.0f, -0.175f, 0.0f, 0.205f, 0.473f, 1.0f,
+ -0.176f, 0.0f, 0.209f, 0.464f, 1.0f, -0.177f, 0.0f, 0.212f, 0.455f, 1.0f, -0.178f, 0.0f, 0.215f, 0.446f, 1.0f, -0.178f, 0.0f, 0.219f, 0.438f, 1.0f,
+ -0.179f, 0.0f, 0.222f, 0.428f, 1.0f, -0.18f, 0.0f, 0.226f, 0.418f, 1.0f, -0.182f, 0.0f, 0.229f, 0.407f, 1.0f, -0.183f, 0.0f, 0.232f, 0.394f, 1.0f,
+ -0.184f, 0.0f, 0.236f, 0.38f, 1.0f, -0.185f, 0.0f, 0.239f, 0.364f, 1.0f, -0.186f, 0.0f, 0.242f, 0.348f, 1.0f, -0.187f, 0.0f, 0.245f, 0.33f, 1.0f,
+ -0.188f, 0.0f, 0.249f, 0.311f, 1.0f, -0.19f, 0.0f, 0.252f, 0.293f, 1.0f, -0.191f, 0.0f, 0.255f, 0.275f, 1.0f, -0.192f, 0.0f, 0.258f, 0.258f, 1.0f,
+ -0.194f, 0.0f, 0.261f, 0.242f, 1.0f, -0.195f, 0.0f, 0.264f, 0.228f, 1.0f, -0.196f, 0.0f, 0.267f, 0.214f, 1.0f, -0.198f, 0.0f, 0.27f, 0.202f, 1.0f,
+ -0.199f, 0.0f, 0.273f, 0.191f, 1.0f, -0.201f, 0.0f, 0.276f, 0.181f, 1.0f, -0.202f, 0.0f, 0.279f, 0.171f, 1.0f, -0.204f, 0.0f, 0.282f, 0.162f, 1.0f,
+ -0.205f, 0.0f, 0.285f, 0.152f, 1.0f, -0.206f, 0.0f, 0.287f, 0.143f, 1.0f, -0.208f, 0.0f, 0.29f, 0.134f, 1.0f, -0.21f, 0.0f, 0.293f, 0.126f, 1.0f,
+ -0.211f, 0.0f, 0.295f, 0.117f, 1.0f, -0.213f, 0.0f, 0.298f, 0.109f, 1.0f, -0.214f, 0.0f, 0.301f, 0.101f, 1.0f, -0.216f, 0.0f, 0.303f, 0.094f, 1.0f,
+ -0.217f, 0.0f, 0.306f, 0.087f, 1.0f, -0.219f, 0.0f, 0.308f, 0.081f, 1.0f, -0.221f, 0.0f, 0.311f, 0.076f, 1.0f, -0.223f, 0.0f, 0.313f, 0.071f, 1.0f,
+ -0.224f, 0.0f, 0.316f, 0.067f, 1.0f, -0.226f, 0.0f, 0.318f, 0.065f, 1.0f, -0.228f, 0.0f, 0.321f, 0.062f, 1.0f, -0.23f, 0.0f, 0.323f, 0.061f, 1.0f,
+ -0.232f, 0.0f, 0.326f, 0.06f, 1.0f, -0.233f, 0.0f, 0.328f, 0.06f, 1.0f, -0.235f, 0.0f, 0.331f, 0.061f, 1.0f, -0.237f, 0.0f, 0.334f, 0.061f, 1.0f,
+ -0.239f, 0.0f, 0.336f, 0.062f, 1.0f, -0.241f, 0.0f, 0.339f, 0.063f, 1.0f, -0.243f, 0.0f, 0.341f, 0.064f, 1.0f, -0.245f, 0.0f, 0.344f, 0.065f, 1.0f,
+ -0.248f, 0.0f, 0.346f, 0.065f, 1.0f, -0.25f, 0.0f, 0.349f, 0.065f, 1.0f, -0.252f, 0.0f, 0.351f, 0.064f, 1.0f, -0.254f, 0.0f, 0.354f, 0.062f, 1.0f,
+ -0.256f, 0.0f, 0.356f, 0.06f, 1.0f, -0.258f, 0.0f, 0.359f, 0.058f, 1.0f, -0.261f, 0.0f, 0.361f, 0.055f, 1.0f, -0.263f, 0.0f, 0.364f, 0.051f, 1.0f,
+ -0.265f, 0.0f, 0.366f, 0.046f, 1.0f, -0.267f, 0.0f, 0.368f, 0.04f, 1.0f, -0.269f, 0.0f, 0.37f, 0.034f, 1.0f, -0.272f, 0.0f, 0.373f, 0.027f, 1.0f,
+ -0.274f, 0.0f, 0.375f, 0.019f, 1.0f, -0.276f, 0.0f, 0.377f, 0.012f, 1.0f, -0.278f, 0.0f, 0.379f, 0.007f, 1.0f, -0.28f, 0.0f, 0.381f, 0.003f, 1.0f,
+ -0.282f, 0.0f, 0.383f, 0.001f, 1.0f, -0.284f, 0.0f, 0.385f, 0.0f, 1.0f, -0.286f, 0.0f, 0.387f, 0.0f, 1.0f, -0.287f, 0.0f, 0.388f, 0.0f, 1.0f,
+ -0.289f, 0.0f, 0.39f, 0.0f, 1.0f,
+};
+
+static const float data22[309 * GP_PRIM_DATABUF_SIZE] = {
+ 0.294f, 0.0f, 0.372f, 0.0f, 1.0f, 0.291f, 0.0f, 0.37f, 0.001f, 1.0f, 0.289f, 0.0f, 0.368f, 0.002f, 1.0f, 0.286f, 0.0f, 0.366f, 0.003f, 1.0f,
+ 0.284f, 0.0f, 0.364f, 0.006f, 1.0f, 0.282f, 0.0f, 0.362f, 0.01f, 1.0f, 0.279f, 0.0f, 0.36f, 0.015f, 1.0f, 0.277f, 0.0f, 0.358f, 0.022f, 1.0f,
+ 0.274f, 0.0f, 0.356f, 0.03f, 1.0f, 0.272f, 0.0f, 0.353f, 0.04f, 1.0f, 0.269f, 0.0f, 0.351f, 0.051f, 1.0f, 0.267f, 0.0f, 0.349f, 0.062f, 1.0f,
+ 0.265f, 0.0f, 0.347f, 0.074f, 1.0f, 0.262f, 0.0f, 0.344f, 0.086f, 1.0f, 0.26f, 0.0f, 0.342f, 0.097f, 1.0f, 0.258f, 0.0f, 0.34f, 0.108f, 1.0f,
+ 0.256f, 0.0f, 0.337f, 0.119f, 1.0f, 0.253f, 0.0f, 0.335f, 0.128f, 1.0f, 0.251f, 0.0f, 0.333f, 0.137f, 1.0f, 0.249f, 0.0f, 0.33f, 0.145f, 1.0f,
+ 0.247f, 0.0f, 0.328f, 0.153f, 1.0f, 0.246f, 0.0f, 0.325f, 0.161f, 1.0f, 0.244f, 0.0f, 0.323f, 0.168f, 1.0f, 0.242f, 0.0f, 0.321f, 0.176f, 1.0f,
+ 0.24f, 0.0f, 0.318f, 0.183f, 1.0f, 0.239f, 0.0f, 0.316f, 0.191f, 1.0f, 0.237f, 0.0f, 0.314f, 0.198f, 1.0f, 0.235f, 0.0f, 0.311f, 0.206f, 1.0f,
+ 0.233f, 0.0f, 0.309f, 0.214f, 1.0f, 0.231f, 0.0f, 0.306f, 0.223f, 1.0f, 0.23f, 0.0f, 0.304f, 0.231f, 1.0f, 0.228f, 0.0f, 0.301f, 0.24f, 1.0f,
+ 0.226f, 0.0f, 0.299f, 0.248f, 1.0f, 0.224f, 0.0f, 0.296f, 0.256f, 1.0f, 0.223f, 0.0f, 0.294f, 0.264f, 1.0f, 0.221f, 0.0f, 0.291f, 0.272f, 1.0f,
+ 0.219f, 0.0f, 0.288f, 0.28f, 1.0f, 0.218f, 0.0f, 0.286f, 0.287f, 1.0f, 0.216f, 0.0f, 0.283f, 0.294f, 1.0f, 0.214f, 0.0f, 0.281f, 0.301f, 1.0f,
+ 0.213f, 0.0f, 0.278f, 0.307f, 1.0f, 0.211f, 0.0f, 0.275f, 0.314f, 1.0f, 0.21f, 0.0f, 0.273f, 0.32f, 1.0f, 0.208f, 0.0f, 0.27f, 0.327f, 1.0f,
+ 0.206f, 0.0f, 0.267f, 0.333f, 1.0f, 0.205f, 0.0f, 0.265f, 0.339f, 1.0f, 0.204f, 0.0f, 0.262f, 0.345f, 1.0f, 0.202f, 0.0f, 0.259f, 0.351f, 1.0f,
+ 0.201f, 0.0f, 0.256f, 0.357f, 1.0f, 0.199f, 0.0f, 0.253f, 0.362f, 1.0f, 0.198f, 0.0f, 0.25f, 0.368f, 1.0f, 0.197f, 0.0f, 0.247f, 0.373f, 1.0f,
+ 0.195f, 0.0f, 0.244f, 0.379f, 1.0f, 0.194f, 0.0f, 0.241f, 0.383f, 1.0f, 0.193f, 0.0f, 0.238f, 0.388f, 1.0f, 0.192f, 0.0f, 0.235f, 0.392f, 1.0f,
+ 0.191f, 0.0f, 0.232f, 0.396f, 1.0f, 0.19f, 0.0f, 0.229f, 0.399f, 1.0f, 0.189f, 0.0f, 0.226f, 0.402f, 1.0f, 0.188f, 0.0f, 0.222f, 0.405f, 1.0f,
+ 0.187f, 0.0f, 0.219f, 0.407f, 1.0f, 0.186f, 0.0f, 0.216f, 0.409f, 1.0f, 0.185f, 0.0f, 0.213f, 0.411f, 1.0f, 0.184f, 0.0f, 0.209f, 0.412f, 1.0f,
+ 0.183f, 0.0f, 0.206f, 0.413f, 1.0f, 0.183f, 0.0f, 0.203f, 0.414f, 1.0f, 0.182f, 0.0f, 0.199f, 0.415f, 1.0f, 0.181f, 0.0f, 0.196f, 0.416f, 1.0f,
+ 0.181f, 0.0f, 0.193f, 0.417f, 1.0f, 0.18f, 0.0f, 0.189f, 0.417f, 1.0f, 0.18f, 0.0f, 0.186f, 0.418f, 1.0f, 0.179f, 0.0f, 0.182f, 0.419f, 1.0f,
+ 0.179f, 0.0f, 0.179f, 0.421f, 1.0f, 0.179f, 0.0f, 0.176f, 0.422f, 1.0f, 0.178f, 0.0f, 0.172f, 0.423f, 1.0f, 0.178f, 0.0f, 0.169f, 0.425f, 1.0f,
+ 0.178f, 0.0f, 0.165f, 0.427f, 1.0f, 0.178f, 0.0f, 0.162f, 0.429f, 1.0f, 0.178f, 0.0f, 0.158f, 0.431f, 1.0f, 0.178f, 0.0f, 0.155f, 0.434f, 1.0f,
+ 0.178f, 0.0f, 0.152f, 0.436f, 1.0f, 0.178f, 0.0f, 0.148f, 0.439f, 1.0f, 0.178f, 0.0f, 0.145f, 0.442f, 1.0f, 0.178f, 0.0f, 0.141f, 0.446f, 1.0f,
+ 0.178f, 0.0f, 0.138f, 0.449f, 1.0f, 0.178f, 0.0f, 0.134f, 0.453f, 1.0f, 0.178f, 0.0f, 0.131f, 0.458f, 1.0f, 0.179f, 0.0f, 0.127f, 0.462f, 1.0f,
+ 0.179f, 0.0f, 0.124f, 0.467f, 1.0f, 0.179f, 0.0f, 0.12f, 0.472f, 1.0f, 0.18f, 0.0f, 0.117f, 0.478f, 1.0f, 0.18f, 0.0f, 0.113f, 0.483f, 1.0f,
+ 0.181f, 0.0f, 0.11f, 0.489f, 1.0f, 0.182f, 0.0f, 0.106f, 0.494f, 1.0f, 0.182f, 0.0f, 0.103f, 0.5f, 1.0f, 0.183f, 0.0f, 0.099f, 0.505f, 1.0f,
+ 0.184f, 0.0f, 0.096f, 0.511f, 1.0f, 0.185f, 0.0f, 0.092f, 0.516f, 1.0f, 0.185f, 0.0f, 0.089f, 0.521f, 1.0f, 0.186f, 0.0f, 0.086f, 0.525f, 1.0f,
+ 0.187f, 0.0f, 0.082f, 0.53f, 1.0f, 0.188f, 0.0f, 0.079f, 0.534f, 1.0f, 0.189f, 0.0f, 0.076f, 0.537f, 1.0f, 0.191f, 0.0f, 0.073f, 0.541f, 1.0f,
+ 0.192f, 0.0f, 0.069f, 0.544f, 1.0f, 0.193f, 0.0f, 0.066f, 0.547f, 1.0f, 0.194f, 0.0f, 0.063f, 0.55f, 1.0f, 0.196f, 0.0f, 0.061f, 0.553f, 1.0f,
+ 0.197f, 0.0f, 0.058f, 0.556f, 1.0f, 0.198f, 0.0f, 0.055f, 0.559f, 1.0f, 0.2f, 0.0f, 0.052f, 0.562f, 1.0f, 0.201f, 0.0f, 0.049f, 0.564f, 1.0f,
+ 0.203f, 0.0f, 0.047f, 0.566f, 1.0f, 0.205f, 0.0f, 0.044f, 0.569f, 1.0f, 0.206f, 0.0f, 0.042f, 0.571f, 1.0f, 0.208f, 0.0f, 0.039f, 0.573f, 1.0f,
+ 0.21f, 0.0f, 0.037f, 0.575f, 1.0f, 0.212f, 0.0f, 0.035f, 0.576f, 1.0f, 0.214f, 0.0f, 0.032f, 0.578f, 1.0f, 0.215f, 0.0f, 0.03f, 0.579f, 1.0f,
+ 0.217f, 0.0f, 0.028f, 0.581f, 1.0f, 0.22f, 0.0f, 0.025f, 0.582f, 1.0f, 0.222f, 0.0f, 0.023f, 0.583f, 1.0f, 0.224f, 0.0f, 0.021f, 0.585f, 1.0f,
+ 0.226f, 0.0f, 0.019f, 0.587f, 1.0f, 0.228f, 0.0f, 0.016f, 0.589f, 1.0f, 0.231f, 0.0f, 0.014f, 0.592f, 1.0f, 0.233f, 0.0f, 0.012f, 0.596f, 1.0f,
+ 0.236f, 0.0f, 0.01f, 0.599f, 1.0f, 0.238f, 0.0f, 0.008f, 0.604f, 1.0f, 0.241f, 0.0f, 0.006f, 0.608f, 1.0f, 0.243f, 0.0f, 0.004f, 0.612f, 1.0f,
+ 0.246f, 0.0f, 0.002f, 0.615f, 1.0f, 0.249f, 0.0f, 0.0f, 0.619f, 1.0f, 0.251f, 0.0f, -0.002f, 0.622f, 1.0f, 0.254f, 0.0f, -0.003f, 0.624f, 1.0f,
+ 0.257f, 0.0f, -0.005f, 0.626f, 1.0f, 0.26f, 0.0f, -0.007f, 0.628f, 1.0f, 0.263f, 0.0f, -0.008f, 0.63f, 1.0f, 0.266f, 0.0f, -0.01f, 0.632f, 1.0f,
+ 0.269f, 0.0f, -0.011f, 0.634f, 1.0f, 0.272f, 0.0f, -0.013f, 0.636f, 1.0f, 0.275f, 0.0f, -0.014f, 0.638f, 1.0f, 0.278f, 0.0f, -0.015f, 0.64f, 1.0f,
+ 0.281f, 0.0f, -0.017f, 0.642f, 1.0f, 0.284f, 0.0f, -0.018f, 0.644f, 1.0f, 0.288f, 0.0f, -0.019f, 0.647f, 1.0f, 0.291f, 0.0f, -0.02f, 0.649f, 1.0f,
+ 0.294f, 0.0f, -0.021f, 0.651f, 1.0f, 0.297f, 0.0f, -0.022f, 0.653f, 1.0f, 0.301f, 0.0f, -0.023f, 0.656f, 1.0f, 0.304f, 0.0f, -0.024f, 0.658f, 1.0f,
+ 0.307f, 0.0f, -0.025f, 0.659f, 1.0f, 0.31f, 0.0f, -0.026f, 0.661f, 1.0f, 0.314f, 0.0f, -0.027f, 0.662f, 1.0f, 0.317f, 0.0f, -0.027f, 0.664f, 1.0f,
+ 0.32f, 0.0f, -0.028f, 0.665f, 1.0f, 0.324f, 0.0f, -0.028f, 0.665f, 1.0f, 0.327f, 0.0f, -0.029f, 0.666f, 1.0f, 0.33f, 0.0f, -0.029f, 0.666f, 1.0f,
+ 0.334f, 0.0f, -0.029f, 0.667f, 1.0f, 0.337f, 0.0f, -0.03f, 0.667f, 1.0f, 0.341f, 0.0f, -0.03f, 0.668f, 1.0f, 0.344f, 0.0f, -0.03f, 0.668f, 1.0f,
+ 0.348f, 0.0f, -0.03f, 0.668f, 1.0f, 0.351f, 0.0f, -0.03f, 0.668f, 1.0f, 0.354f, 0.0f, -0.03f, 0.668f, 1.0f, 0.358f, 0.0f, -0.029f, 0.668f, 1.0f,
+ 0.361f, 0.0f, -0.029f, 0.668f, 1.0f, 0.365f, 0.0f, -0.029f, 0.668f, 1.0f, 0.368f, 0.0f, -0.028f, 0.668f, 1.0f, 0.372f, 0.0f, -0.028f, 0.668f, 1.0f,
+ 0.375f, 0.0f, -0.027f, 0.668f, 1.0f, 0.378f, 0.0f, -0.027f, 0.668f, 1.0f, 0.382f, 0.0f, -0.026f, 0.667f, 1.0f, 0.385f, 0.0f, -0.025f, 0.667f, 1.0f,
+ 0.388f, 0.0f, -0.025f, 0.666f, 1.0f, 0.392f, 0.0f, -0.024f, 0.666f, 1.0f, 0.395f, 0.0f, -0.023f, 0.665f, 1.0f, 0.398f, 0.0f, -0.022f, 0.664f, 1.0f,
+ 0.401f, 0.0f, -0.021f, 0.664f, 1.0f, 0.405f, 0.0f, -0.02f, 0.663f, 1.0f, 0.408f, 0.0f, -0.019f, 0.663f, 1.0f, 0.411f, 0.0f, -0.018f, 0.662f, 1.0f,
+ 0.414f, 0.0f, -0.017f, 0.662f, 1.0f, 0.417f, 0.0f, -0.016f, 0.662f, 1.0f, 0.42f, 0.0f, -0.015f, 0.662f, 1.0f, 0.423f, 0.0f, -0.014f, 0.661f, 1.0f,
+ 0.426f, 0.0f, -0.012f, 0.661f, 1.0f, 0.429f, 0.0f, -0.011f, 0.661f, 1.0f, 0.432f, 0.0f, -0.01f, 0.661f, 1.0f, 0.434f, 0.0f, -0.009f, 0.66f, 1.0f,
+ 0.437f, 0.0f, -0.007f, 0.66f, 1.0f, 0.44f, 0.0f, -0.006f, 0.659f, 1.0f, 0.442f, 0.0f, -0.005f, 0.659f, 1.0f, 0.445f, 0.0f, -0.003f, 0.658f, 1.0f,
+ 0.448f, 0.0f, -0.002f, 0.658f, 1.0f, 0.45f, 0.0f, -0.001f, 0.657f, 1.0f, 0.452f, 0.0f, 0.001f, 0.656f, 1.0f, 0.455f, 0.0f, 0.002f, 0.655f, 1.0f,
+ 0.457f, 0.0f, 0.004f, 0.654f, 1.0f, 0.459f, 0.0f, 0.005f, 0.653f, 1.0f, 0.462f, 0.0f, 0.007f, 0.652f, 1.0f, 0.464f, 0.0f, 0.009f, 0.651f, 1.0f,
+ 0.466f, 0.0f, 0.01f, 0.65f, 1.0f, 0.468f, 0.0f, 0.012f, 0.65f, 1.0f, 0.47f, 0.0f, 0.014f, 0.649f, 1.0f, 0.472f, 0.0f, 0.016f, 0.648f, 1.0f,
+ 0.474f, 0.0f, 0.018f, 0.647f, 1.0f, 0.476f, 0.0f, 0.019f, 0.646f, 1.0f, 0.478f, 0.0f, 0.021f, 0.645f, 1.0f, 0.479f, 0.0f, 0.023f, 0.644f, 1.0f,
+ 0.481f, 0.0f, 0.025f, 0.643f, 1.0f, 0.483f, 0.0f, 0.027f, 0.642f, 1.0f, 0.485f, 0.0f, 0.03f, 0.642f, 1.0f, 0.486f, 0.0f, 0.032f, 0.641f, 1.0f,
+ 0.488f, 0.0f, 0.034f, 0.64f, 1.0f, 0.49f, 0.0f, 0.036f, 0.639f, 1.0f, 0.491f, 0.0f, 0.038f, 0.638f, 1.0f, 0.493f, 0.0f, 0.041f, 0.637f, 1.0f,
+ 0.494f, 0.0f, 0.043f, 0.636f, 1.0f, 0.496f, 0.0f, 0.045f, 0.635f, 1.0f, 0.497f, 0.0f, 0.048f, 0.635f, 1.0f, 0.499f, 0.0f, 0.05f, 0.634f, 1.0f,
+ 0.5f, 0.0f, 0.053f, 0.633f, 1.0f, 0.502f, 0.0f, 0.055f, 0.632f, 1.0f, 0.503f, 0.0f, 0.058f, 0.631f, 1.0f, 0.505f, 0.0f, 0.06f, 0.63f, 1.0f,
+ 0.506f, 0.0f, 0.063f, 0.63f, 1.0f, 0.507f, 0.0f, 0.066f, 0.629f, 1.0f, 0.509f, 0.0f, 0.068f, 0.628f, 1.0f, 0.51f, 0.0f, 0.071f, 0.628f, 1.0f,
+ 0.511f, 0.0f, 0.074f, 0.627f, 1.0f, 0.513f, 0.0f, 0.077f, 0.626f, 1.0f, 0.514f, 0.0f, 0.079f, 0.625f, 1.0f, 0.515f, 0.0f, 0.082f, 0.625f, 1.0f,
+ 0.516f, 0.0f, 0.085f, 0.624f, 1.0f, 0.518f, 0.0f, 0.088f, 0.623f, 1.0f, 0.519f, 0.0f, 0.091f, 0.622f, 1.0f, 0.52f, 0.0f, 0.094f, 0.62f, 1.0f,
+ 0.521f, 0.0f, 0.098f, 0.619f, 1.0f, 0.522f, 0.0f, 0.101f, 0.617f, 1.0f, 0.523f, 0.0f, 0.104f, 0.615f, 1.0f, 0.524f, 0.0f, 0.107f, 0.613f, 1.0f,
+ 0.525f, 0.0f, 0.111f, 0.611f, 1.0f, 0.526f, 0.0f, 0.114f, 0.609f, 1.0f, 0.527f, 0.0f, 0.118f, 0.607f, 1.0f, 0.527f, 0.0f, 0.121f, 0.605f, 1.0f,
+ 0.528f, 0.0f, 0.124f, 0.603f, 1.0f, 0.529f, 0.0f, 0.128f, 0.602f, 1.0f, 0.529f, 0.0f, 0.132f, 0.6f, 1.0f, 0.53f, 0.0f, 0.135f, 0.599f, 1.0f,
+ 0.531f, 0.0f, 0.139f, 0.598f, 1.0f, 0.531f, 0.0f, 0.142f, 0.598f, 1.0f, 0.531f, 0.0f, 0.146f, 0.597f, 1.0f, 0.532f, 0.0f, 0.15f, 0.596f, 1.0f,
+ 0.532f, 0.0f, 0.154f, 0.596f, 1.0f, 0.532f, 0.0f, 0.157f, 0.595f, 1.0f, 0.532f, 0.0f, 0.161f, 0.595f, 1.0f, 0.532f, 0.0f, 0.165f, 0.594f, 1.0f,
+ 0.532f, 0.0f, 0.169f, 0.593f, 1.0f, 0.532f, 0.0f, 0.173f, 0.592f, 1.0f, 0.532f, 0.0f, 0.177f, 0.591f, 1.0f, 0.532f, 0.0f, 0.181f, 0.59f, 1.0f,
+ 0.531f, 0.0f, 0.185f, 0.589f, 1.0f, 0.531f, 0.0f, 0.189f, 0.588f, 1.0f, 0.53f, 0.0f, 0.194f, 0.587f, 1.0f, 0.529f, 0.0f, 0.198f, 0.586f, 1.0f,
+ 0.528f, 0.0f, 0.202f, 0.585f, 1.0f, 0.527f, 0.0f, 0.207f, 0.584f, 1.0f, 0.526f, 0.0f, 0.211f, 0.584f, 1.0f, 0.525f, 0.0f, 0.215f, 0.583f, 1.0f,
+ 0.523f, 0.0f, 0.22f, 0.583f, 1.0f, 0.522f, 0.0f, 0.224f, 0.583f, 1.0f, 0.52f, 0.0f, 0.229f, 0.582f, 1.0f, 0.518f, 0.0f, 0.234f, 0.582f, 1.0f,
+ 0.515f, 0.0f, 0.238f, 0.582f, 1.0f, 0.513f, 0.0f, 0.243f, 0.581f, 1.0f, 0.51f, 0.0f, 0.247f, 0.58f, 1.0f, 0.508f, 0.0f, 0.252f, 0.579f, 1.0f,
+ 0.505f, 0.0f, 0.257f, 0.578f, 1.0f, 0.502f, 0.0f, 0.261f, 0.576f, 1.0f, 0.499f, 0.0f, 0.266f, 0.573f, 1.0f, 0.496f, 0.0f, 0.27f, 0.57f, 1.0f,
+ 0.492f, 0.0f, 0.275f, 0.566f, 1.0f, 0.489f, 0.0f, 0.279f, 0.561f, 1.0f, 0.485f, 0.0f, 0.284f, 0.555f, 1.0f, 0.481f, 0.0f, 0.288f, 0.548f, 1.0f,
+ 0.478f, 0.0f, 0.293f, 0.54f, 1.0f, 0.473f, 0.0f, 0.297f, 0.531f, 1.0f, 0.469f, 0.0f, 0.301f, 0.521f, 1.0f, 0.465f, 0.0f, 0.305f, 0.509f, 1.0f,
+ 0.461f, 0.0f, 0.309f, 0.496f, 1.0f, 0.456f, 0.0f, 0.313f, 0.481f, 1.0f, 0.452f, 0.0f, 0.317f, 0.464f, 1.0f, 0.448f, 0.0f, 0.321f, 0.445f, 1.0f,
+ 0.443f, 0.0f, 0.324f, 0.424f, 1.0f, 0.438f, 0.0f, 0.328f, 0.401f, 1.0f, 0.434f, 0.0f, 0.331f, 0.374f, 1.0f, 0.429f, 0.0f, 0.334f, 0.346f, 1.0f,
+ 0.425f, 0.0f, 0.337f, 0.314f, 1.0f, 0.421f, 0.0f, 0.34f, 0.281f, 1.0f, 0.416f, 0.0f, 0.343f, 0.245f, 1.0f, 0.412f, 0.0f, 0.346f, 0.208f, 1.0f,
+ 0.408f, 0.0f, 0.349f, 0.169f, 1.0f, 0.404f, 0.0f, 0.351f, 0.13f, 1.0f, 0.401f, 0.0f, 0.354f, 0.089f, 1.0f, 0.398f, 0.0f, 0.356f, 0.054f, 1.0f,
+ 0.394f, 0.0f, 0.359f, 0.0f, 1.0f,
+};
+
+static const float data23[209 * GP_PRIM_DATABUF_SIZE] = {
+ -0.751f, 0.0f, 0.173f, 0.0f, 1.0f, -0.751f, 0.0f, 0.168f, 0.0f, 1.0f, -0.75f, 0.0f, 0.164f, 0.0f, 1.0f, -0.75f, 0.0f, 0.16f, 0.0f, 1.0f,
+ -0.75f, 0.0f, 0.156f, 0.0f, 1.0f, -0.749f, 0.0f, 0.152f, 0.0f, 1.0f, -0.749f, 0.0f, 0.148f, 0.0f, 1.0f, -0.748f, 0.0f, 0.144f, 0.0f, 1.0f,
+ -0.747f, 0.0f, 0.14f, 0.001f, 1.0f, -0.747f, 0.0f, 0.137f, 0.002f, 1.0f, -0.746f, 0.0f, 0.133f, 0.005f, 1.0f, -0.745f, 0.0f, 0.129f, 0.008f, 1.0f,
+ -0.745f, 0.0f, 0.125f, 0.013f, 1.0f, -0.744f, 0.0f, 0.122f, 0.02f, 1.0f, -0.743f, 0.0f, 0.118f, 0.028f, 1.0f, -0.742f, 0.0f, 0.115f, 0.038f, 1.0f,
+ -0.741f, 0.0f, 0.111f, 0.049f, 1.0f, -0.74f, 0.0f, 0.108f, 0.061f, 1.0f, -0.739f, 0.0f, 0.105f, 0.073f, 1.0f, -0.738f, 0.0f, 0.101f, 0.085f, 1.0f,
+ -0.736f, 0.0f, 0.098f, 0.097f, 1.0f, -0.735f, 0.0f, 0.095f, 0.109f, 1.0f, -0.734f, 0.0f, 0.091f, 0.119f, 1.0f, -0.732f, 0.0f, 0.088f, 0.129f, 1.0f,
+ -0.731f, 0.0f, 0.085f, 0.138f, 1.0f, -0.729f, 0.0f, 0.082f, 0.146f, 1.0f, -0.728f, 0.0f, 0.079f, 0.153f, 1.0f, -0.726f, 0.0f, 0.076f, 0.158f, 1.0f,
+ -0.725f, 0.0f, 0.073f, 0.163f, 1.0f, -0.723f, 0.0f, 0.07f, 0.167f, 1.0f, -0.722f, 0.0f, 0.067f, 0.17f, 1.0f, -0.72f, 0.0f, 0.065f, 0.173f, 1.0f,
+ -0.718f, 0.0f, 0.062f, 0.174f, 1.0f, -0.717f, 0.0f, 0.059f, 0.175f, 1.0f, -0.715f, 0.0f, 0.057f, 0.176f, 1.0f, -0.714f, 0.0f, 0.054f, 0.176f, 1.0f,
+ -0.712f, 0.0f, 0.051f, 0.176f, 1.0f, -0.71f, 0.0f, 0.049f, 0.176f, 1.0f, -0.709f, 0.0f, 0.046f, 0.176f, 1.0f, -0.707f, 0.0f, 0.043f, 0.176f, 1.0f,
+ -0.705f, 0.0f, 0.041f, 0.176f, 1.0f, -0.703f, 0.0f, 0.038f, 0.176f, 1.0f, -0.701f, 0.0f, 0.035f, 0.176f, 1.0f, -0.7f, 0.0f, 0.033f, 0.177f, 1.0f,
+ -0.698f, 0.0f, 0.03f, 0.177f, 1.0f, -0.696f, 0.0f, 0.027f, 0.178f, 1.0f, -0.694f, 0.0f, 0.024f, 0.179f, 1.0f, -0.692f, 0.0f, 0.022f, 0.18f, 1.0f,
+ -0.69f, 0.0f, 0.019f, 0.181f, 1.0f, -0.688f, 0.0f, 0.016f, 0.182f, 1.0f, -0.685f, 0.0f, 0.013f, 0.184f, 1.0f, -0.683f, 0.0f, 0.01f, 0.187f, 1.0f,
+ -0.681f, 0.0f, 0.007f, 0.19f, 1.0f, -0.679f, 0.0f, 0.004f, 0.194f, 1.0f, -0.677f, 0.0f, 0.001f, 0.198f, 1.0f, -0.675f, 0.0f, -0.002f, 0.203f, 1.0f,
+ -0.673f, 0.0f, -0.005f, 0.209f, 1.0f, -0.67f, 0.0f, -0.008f, 0.215f, 1.0f, -0.668f, 0.0f, -0.011f, 0.222f, 1.0f, -0.666f, 0.0f, -0.014f, 0.229f, 1.0f,
+ -0.664f, 0.0f, -0.017f, 0.237f, 1.0f, -0.661f, 0.0f, -0.02f, 0.246f, 1.0f, -0.659f, 0.0f, -0.023f, 0.255f, 1.0f, -0.657f, 0.0f, -0.025f, 0.264f, 1.0f,
+ -0.654f, 0.0f, -0.028f, 0.275f, 1.0f, -0.652f, 0.0f, -0.031f, 0.285f, 1.0f, -0.65f, 0.0f, -0.034f, 0.297f, 1.0f, -0.647f, 0.0f, -0.037f, 0.309f, 1.0f,
+ -0.644f, 0.0f, -0.04f, 0.322f, 1.0f, -0.642f, 0.0f, -0.043f, 0.335f, 1.0f, -0.639f, 0.0f, -0.046f, 0.348f, 1.0f, -0.636f, 0.0f, -0.049f, 0.361f, 1.0f,
+ -0.633f, 0.0f, -0.052f, 0.374f, 1.0f, -0.63f, 0.0f, -0.055f, 0.386f, 1.0f, -0.627f, 0.0f, -0.058f, 0.397f, 1.0f, -0.624f, 0.0f, -0.061f, 0.408f, 1.0f,
+ -0.62f, 0.0f, -0.064f, 0.418f, 1.0f, -0.617f, 0.0f, -0.067f, 0.427f, 1.0f, -0.614f, 0.0f, -0.07f, 0.435f, 1.0f, -0.611f, 0.0f, -0.073f, 0.443f, 1.0f,
+ -0.607f, 0.0f, -0.075f, 0.451f, 1.0f, -0.604f, 0.0f, -0.078f, 0.458f, 1.0f, -0.6f, 0.0f, -0.081f, 0.465f, 1.0f, -0.597f, 0.0f, -0.084f, 0.472f, 1.0f,
+ -0.593f, 0.0f, -0.086f, 0.479f, 1.0f, -0.59f, 0.0f, -0.089f, 0.486f, 1.0f, -0.586f, 0.0f, -0.092f, 0.492f, 1.0f, -0.583f, 0.0f, -0.094f, 0.499f, 1.0f,
+ -0.579f, 0.0f, -0.097f, 0.505f, 1.0f, -0.575f, 0.0f, -0.099f, 0.512f, 1.0f, -0.571f, 0.0f, -0.102f, 0.518f, 1.0f, -0.567f, 0.0f, -0.105f, 0.524f, 1.0f,
+ -0.563f, 0.0f, -0.107f, 0.53f, 1.0f, -0.559f, 0.0f, -0.11f, 0.536f, 1.0f, -0.555f, 0.0f, -0.112f, 0.541f, 1.0f, -0.551f, 0.0f, -0.115f, 0.546f, 1.0f,
+ -0.546f, 0.0f, -0.117f, 0.551f, 1.0f, -0.542f, 0.0f, -0.12f, 0.555f, 1.0f, -0.538f, 0.0f, -0.122f, 0.559f, 1.0f, -0.533f, 0.0f, -0.125f, 0.562f, 1.0f,
+ -0.529f, 0.0f, -0.127f, 0.565f, 1.0f, -0.525f, 0.0f, -0.129f, 0.568f, 1.0f, -0.52f, 0.0f, -0.132f, 0.57f, 1.0f, -0.516f, 0.0f, -0.134f, 0.572f, 1.0f,
+ -0.512f, 0.0f, -0.137f, 0.574f, 1.0f, -0.508f, 0.0f, -0.139f, 0.576f, 1.0f, -0.503f, 0.0f, -0.141f, 0.577f, 1.0f, -0.499f, 0.0f, -0.144f, 0.578f, 1.0f,
+ -0.495f, 0.0f, -0.146f, 0.579f, 1.0f, -0.491f, 0.0f, -0.148f, 0.579f, 1.0f, -0.487f, 0.0f, -0.151f, 0.578f, 1.0f, -0.483f, 0.0f, -0.153f, 0.577f, 1.0f,
+ -0.479f, 0.0f, -0.155f, 0.574f, 1.0f, -0.475f, 0.0f, -0.158f, 0.571f, 1.0f, -0.471f, 0.0f, -0.16f, 0.567f, 1.0f, -0.467f, 0.0f, -0.162f, 0.561f, 1.0f,
+ -0.463f, 0.0f, -0.165f, 0.555f, 1.0f, -0.459f, 0.0f, -0.167f, 0.548f, 1.0f, -0.456f, 0.0f, -0.169f, 0.54f, 1.0f, -0.452f, 0.0f, -0.172f, 0.532f, 1.0f,
+ -0.448f, 0.0f, -0.174f, 0.523f, 1.0f, -0.445f, 0.0f, -0.176f, 0.514f, 1.0f, -0.441f, 0.0f, -0.179f, 0.505f, 1.0f, -0.438f, 0.0f, -0.181f, 0.497f, 1.0f,
+ -0.435f, 0.0f, -0.183f, 0.488f, 1.0f, -0.431f, 0.0f, -0.185f, 0.48f, 1.0f, -0.428f, 0.0f, -0.188f, 0.472f, 1.0f, -0.425f, 0.0f, -0.19f, 0.464f, 1.0f,
+ -0.422f, 0.0f, -0.192f, 0.457f, 1.0f, -0.419f, 0.0f, -0.194f, 0.451f, 1.0f, -0.416f, 0.0f, -0.196f, 0.444f, 1.0f, -0.413f, 0.0f, -0.198f, 0.439f, 1.0f,
+ -0.41f, 0.0f, -0.2f, 0.434f, 1.0f, -0.407f, 0.0f, -0.202f, 0.429f, 1.0f, -0.404f, 0.0f, -0.204f, 0.426f, 1.0f, -0.401f, 0.0f, -0.206f, 0.422f, 1.0f,
+ -0.398f, 0.0f, -0.208f, 0.419f, 1.0f, -0.396f, 0.0f, -0.21f, 0.417f, 1.0f, -0.393f, 0.0f, -0.212f, 0.415f, 1.0f, -0.39f, 0.0f, -0.213f, 0.413f, 1.0f,
+ -0.388f, 0.0f, -0.215f, 0.412f, 1.0f, -0.385f, 0.0f, -0.217f, 0.411f, 1.0f, -0.382f, 0.0f, -0.219f, 0.41f, 1.0f, -0.38f, 0.0f, -0.221f, 0.41f, 1.0f,
+ -0.377f, 0.0f, -0.222f, 0.409f, 1.0f, -0.375f, 0.0f, -0.224f, 0.409f, 1.0f, -0.372f, 0.0f, -0.226f, 0.409f, 1.0f, -0.37f, 0.0f, -0.228f, 0.409f, 1.0f,
+ -0.367f, 0.0f, -0.229f, 0.409f, 1.0f, -0.365f, 0.0f, -0.231f, 0.409f, 1.0f, -0.362f, 0.0f, -0.233f, 0.409f, 1.0f, -0.36f, 0.0f, -0.235f, 0.409f, 1.0f,
+ -0.357f, 0.0f, -0.236f, 0.409f, 1.0f, -0.355f, 0.0f, -0.238f, 0.409f, 1.0f, -0.352f, 0.0f, -0.24f, 0.408f, 1.0f, -0.35f, 0.0f, -0.242f, 0.408f, 1.0f,
+ -0.348f, 0.0f, -0.243f, 0.407f, 1.0f, -0.345f, 0.0f, -0.245f, 0.406f, 1.0f, -0.343f, 0.0f, -0.247f, 0.405f, 1.0f, -0.34f, 0.0f, -0.249f, 0.404f, 1.0f,
+ -0.338f, 0.0f, -0.251f, 0.403f, 1.0f, -0.336f, 0.0f, -0.253f, 0.401f, 1.0f, -0.333f, 0.0f, -0.255f, 0.399f, 1.0f, -0.331f, 0.0f, -0.256f, 0.397f, 1.0f,
+ -0.329f, 0.0f, -0.258f, 0.394f, 1.0f, -0.327f, 0.0f, -0.26f, 0.391f, 1.0f, -0.324f, 0.0f, -0.262f, 0.387f, 1.0f, -0.322f, 0.0f, -0.264f, 0.383f, 1.0f,
+ -0.32f, 0.0f, -0.266f, 0.379f, 1.0f, -0.318f, 0.0f, -0.268f, 0.374f, 1.0f, -0.316f, 0.0f, -0.27f, 0.368f, 1.0f, -0.314f, 0.0f, -0.272f, 0.362f, 1.0f,
+ -0.312f, 0.0f, -0.275f, 0.356f, 1.0f, -0.309f, 0.0f, -0.277f, 0.349f, 1.0f, -0.307f, 0.0f, -0.279f, 0.341f, 1.0f, -0.305f, 0.0f, -0.281f, 0.333f, 1.0f,
+ -0.303f, 0.0f, -0.283f, 0.325f, 1.0f, -0.301f, 0.0f, -0.286f, 0.316f, 1.0f, -0.299f, 0.0f, -0.288f, 0.307f, 1.0f, -0.297f, 0.0f, -0.29f, 0.298f, 1.0f,
+ -0.295f, 0.0f, -0.293f, 0.289f, 1.0f, -0.293f, 0.0f, -0.295f, 0.279f, 1.0f, -0.291f, 0.0f, -0.298f, 0.269f, 1.0f, -0.29f, 0.0f, -0.3f, 0.259f, 1.0f,
+ -0.288f, 0.0f, -0.303f, 0.249f, 1.0f, -0.286f, 0.0f, -0.306f, 0.238f, 1.0f, -0.284f, 0.0f, -0.308f, 0.227f, 1.0f, -0.282f, 0.0f, -0.311f, 0.215f, 1.0f,
+ -0.28f, 0.0f, -0.314f, 0.203f, 1.0f, -0.278f, 0.0f, -0.317f, 0.191f, 1.0f, -0.277f, 0.0f, -0.32f, 0.178f, 1.0f, -0.275f, 0.0f, -0.323f, 0.165f, 1.0f,
+ -0.273f, 0.0f, -0.326f, 0.151f, 1.0f, -0.271f, 0.0f, -0.33f, 0.138f, 1.0f, -0.27f, 0.0f, -0.333f, 0.124f, 1.0f, -0.268f, 0.0f, -0.336f, 0.11f, 1.0f,
+ -0.267f, 0.0f, -0.34f, 0.097f, 1.0f, -0.265f, 0.0f, -0.343f, 0.085f, 1.0f, -0.264f, 0.0f, -0.346f, 0.073f, 1.0f, -0.262f, 0.0f, -0.35f, 0.062f, 1.0f,
+ -0.261f, 0.0f, -0.353f, 0.052f, 1.0f, -0.259f, 0.0f, -0.357f, 0.043f, 1.0f, -0.258f, 0.0f, -0.36f, 0.035f, 1.0f, -0.257f, 0.0f, -0.363f, 0.028f, 1.0f,
+ -0.255f, 0.0f, -0.366f, 0.021f, 1.0f, -0.254f, 0.0f, -0.369f, 0.016f, 1.0f, -0.253f, 0.0f, -0.372f, 0.01f, 1.0f, -0.252f, 0.0f, -0.375f, 0.006f, 1.0f,
+ -0.251f, 0.0f, -0.379f, 0.0f, 1.0f,
+};
+
+static const float data24[133 * GP_PRIM_DATABUF_SIZE] = {
+ 0.233f, 0.0f, -0.376f, 0.021f, 1.0f, 0.234f, 0.0f, -0.372f, 0.08f, 1.0f, 0.234f, 0.0f, -0.369f, 0.116f, 1.0f, 0.234f, 0.0f, -0.366f, 0.156f, 1.0f,
+ 0.235f, 0.0f, -0.362f, 0.191f, 1.0f, 0.236f, 0.0f, -0.359f, 0.222f, 1.0f, 0.236f, 0.0f, -0.356f, 0.248f, 1.0f, 0.237f, 0.0f, -0.353f, 0.27f, 1.0f,
+ 0.238f, 0.0f, -0.35f, 0.289f, 1.0f, 0.239f, 0.0f, -0.346f, 0.304f, 1.0f, 0.24f, 0.0f, -0.343f, 0.319f, 1.0f, 0.241f, 0.0f, -0.34f, 0.334f, 1.0f,
+ 0.242f, 0.0f, -0.337f, 0.35f, 1.0f, 0.243f, 0.0f, -0.335f, 0.367f, 1.0f, 0.244f, 0.0f, -0.332f, 0.385f, 1.0f, 0.245f, 0.0f, -0.329f, 0.401f, 1.0f,
+ 0.247f, 0.0f, -0.327f, 0.415f, 1.0f, 0.248f, 0.0f, -0.324f, 0.426f, 1.0f, 0.249f, 0.0f, -0.322f, 0.435f, 1.0f, 0.251f, 0.0f, -0.32f, 0.443f, 1.0f,
+ 0.252f, 0.0f, -0.318f, 0.449f, 1.0f, 0.254f, 0.0f, -0.316f, 0.455f, 1.0f, 0.255f, 0.0f, -0.314f, 0.461f, 1.0f, 0.257f, 0.0f, -0.312f, 0.467f, 1.0f,
+ 0.258f, 0.0f, -0.311f, 0.474f, 1.0f, 0.26f, 0.0f, -0.309f, 0.48f, 1.0f, 0.262f, 0.0f, -0.307f, 0.487f, 1.0f, 0.263f, 0.0f, -0.305f, 0.493f, 1.0f,
+ 0.265f, 0.0f, -0.303f, 0.499f, 1.0f, 0.267f, 0.0f, -0.3f, 0.505f, 1.0f, 0.269f, 0.0f, -0.298f, 0.511f, 1.0f, 0.271f, 0.0f, -0.296f, 0.518f, 1.0f,
+ 0.273f, 0.0f, -0.294f, 0.524f, 1.0f, 0.276f, 0.0f, -0.291f, 0.531f, 1.0f, 0.278f, 0.0f, -0.289f, 0.539f, 1.0f, 0.281f, 0.0f, -0.287f, 0.546f, 1.0f,
+ 0.283f, 0.0f, -0.284f, 0.552f, 1.0f, 0.286f, 0.0f, -0.281f, 0.557f, 1.0f, 0.289f, 0.0f, -0.279f, 0.561f, 1.0f, 0.292f, 0.0f, -0.276f, 0.565f, 1.0f,
+ 0.294f, 0.0f, -0.274f, 0.568f, 1.0f, 0.297f, 0.0f, -0.271f, 0.57f, 1.0f, 0.3f, 0.0f, -0.269f, 0.572f, 1.0f, 0.303f, 0.0f, -0.267f, 0.574f, 1.0f,
+ 0.306f, 0.0f, -0.264f, 0.575f, 1.0f, 0.308f, 0.0f, -0.262f, 0.576f, 1.0f, 0.311f, 0.0f, -0.26f, 0.577f, 1.0f, 0.314f, 0.0f, -0.257f, 0.578f, 1.0f,
+ 0.316f, 0.0f, -0.255f, 0.578f, 1.0f, 0.319f, 0.0f, -0.253f, 0.579f, 1.0f, 0.322f, 0.0f, -0.25f, 0.579f, 1.0f, 0.325f, 0.0f, -0.248f, 0.58f, 1.0f,
+ 0.328f, 0.0f, -0.246f, 0.58f, 1.0f, 0.331f, 0.0f, -0.243f, 0.58f, 1.0f, 0.334f, 0.0f, -0.241f, 0.58f, 1.0f, 0.337f, 0.0f, -0.239f, 0.58f, 1.0f,
+ 0.341f, 0.0f, -0.236f, 0.58f, 1.0f, 0.344f, 0.0f, -0.233f, 0.581f, 1.0f, 0.348f, 0.0f, -0.231f, 0.581f, 1.0f, 0.352f, 0.0f, -0.228f, 0.581f, 1.0f,
+ 0.356f, 0.0f, -0.225f, 0.582f, 1.0f, 0.36f, 0.0f, -0.222f, 0.582f, 1.0f, 0.365f, 0.0f, -0.219f, 0.582f, 1.0f, 0.369f, 0.0f, -0.216f, 0.582f, 1.0f,
+ 0.374f, 0.0f, -0.214f, 0.582f, 1.0f, 0.378f, 0.0f, -0.211f, 0.582f, 1.0f, 0.383f, 0.0f, -0.208f, 0.583f, 1.0f, 0.387f, 0.0f, -0.205f, 0.583f, 1.0f,
+ 0.392f, 0.0f, -0.202f, 0.583f, 1.0f, 0.397f, 0.0f, -0.199f, 0.583f, 1.0f, 0.401f, 0.0f, -0.197f, 0.583f, 1.0f, 0.406f, 0.0f, -0.194f, 0.583f, 1.0f,
+ 0.411f, 0.0f, -0.191f, 0.583f, 1.0f, 0.416f, 0.0f, -0.188f, 0.583f, 1.0f, 0.42f, 0.0f, -0.186f, 0.583f, 1.0f, 0.425f, 0.0f, -0.183f, 0.583f, 1.0f,
+ 0.43f, 0.0f, -0.18f, 0.583f, 1.0f, 0.434f, 0.0f, -0.178f, 0.583f, 1.0f, 0.439f, 0.0f, -0.175f, 0.583f, 1.0f, 0.444f, 0.0f, -0.172f, 0.583f, 1.0f,
+ 0.449f, 0.0f, -0.17f, 0.584f, 1.0f, 0.453f, 0.0f, -0.167f, 0.584f, 1.0f, 0.458f, 0.0f, -0.164f, 0.584f, 1.0f, 0.463f, 0.0f, -0.161f, 0.585f, 1.0f,
+ 0.468f, 0.0f, -0.158f, 0.585f, 1.0f, 0.473f, 0.0f, -0.155f, 0.585f, 1.0f, 0.478f, 0.0f, -0.152f, 0.585f, 1.0f, 0.483f, 0.0f, -0.149f, 0.585f, 1.0f,
+ 0.488f, 0.0f, -0.146f, 0.585f, 1.0f, 0.492f, 0.0f, -0.143f, 0.585f, 1.0f, 0.497f, 0.0f, -0.14f, 0.586f, 1.0f, 0.501f, 0.0f, -0.137f, 0.586f, 1.0f,
+ 0.506f, 0.0f, -0.134f, 0.586f, 1.0f, 0.51f, 0.0f, -0.13f, 0.586f, 1.0f, 0.515f, 0.0f, -0.127f, 0.586f, 1.0f, 0.52f, 0.0f, -0.124f, 0.586f, 1.0f,
+ 0.524f, 0.0f, -0.12f, 0.586f, 1.0f, 0.529f, 0.0f, -0.117f, 0.586f, 1.0f, 0.534f, 0.0f, -0.113f, 0.586f, 1.0f, 0.539f, 0.0f, -0.109f, 0.586f, 1.0f,
+ 0.544f, 0.0f, -0.105f, 0.586f, 1.0f, 0.55f, 0.0f, -0.1f, 0.586f, 1.0f, 0.555f, 0.0f, -0.095f, 0.586f, 1.0f, 0.561f, 0.0f, -0.09f, 0.586f, 1.0f,
+ 0.567f, 0.0f, -0.084f, 0.587f, 1.0f, 0.573f, 0.0f, -0.078f, 0.587f, 1.0f, 0.579f, 0.0f, -0.071f, 0.587f, 1.0f, 0.586f, 0.0f, -0.063f, 0.588f, 1.0f,
+ 0.593f, 0.0f, -0.055f, 0.588f, 1.0f, 0.6f, 0.0f, -0.047f, 0.588f, 1.0f, 0.607f, 0.0f, -0.038f, 0.589f, 1.0f, 0.614f, 0.0f, -0.028f, 0.589f, 1.0f,
+ 0.621f, 0.0f, -0.018f, 0.589f, 1.0f, 0.629f, 0.0f, -0.007f, 0.589f, 1.0f, 0.636f, 0.0f, 0.004f, 0.589f, 1.0f, 0.643f, 0.0f, 0.015f, 0.59f, 1.0f,
+ 0.65f, 0.0f, 0.026f, 0.589f, 1.0f, 0.656f, 0.0f, 0.038f, 0.589f, 1.0f, 0.663f, 0.0f, 0.049f, 0.588f, 1.0f, 0.669f, 0.0f, 0.06f, 0.587f, 1.0f,
+ 0.676f, 0.0f, 0.072f, 0.584f, 1.0f, 0.682f, 0.0f, 0.084f, 0.579f, 1.0f, 0.688f, 0.0f, 0.096f, 0.571f, 1.0f, 0.694f, 0.0f, 0.108f, 0.558f, 1.0f,
+ 0.7f, 0.0f, 0.12f, 0.54f, 1.0f, 0.706f, 0.0f, 0.133f, 0.514f, 1.0f, 0.712f, 0.0f, 0.145f, 0.478f, 1.0f, 0.718f, 0.0f, 0.158f, 0.431f, 1.0f,
+ 0.723f, 0.0f, 0.17f, 0.369f, 1.0f, 0.728f, 0.0f, 0.182f, 0.294f, 1.0f, 0.733f, 0.0f, 0.194f, 0.205f, 1.0f, 0.737f, 0.0f, 0.204f, 0.125f, 1.0f,
+ 0.743f, 0.0f, 0.218f, 0.0f, 1.0f,
+};
+
+static const float data25[389 * GP_PRIM_DATABUF_SIZE] = {
+ -0.284f, 0.0f, -0.444f, 0.0f, 1.0f, -0.285f, 0.0f, -0.448f, 0.0f, 1.0f, -0.285f, 0.0f, -0.45f, 0.0f, 1.0f, -0.286f, 0.0f, -0.454f, 0.0f, 1.0f,
+ -0.286f, 0.0f, -0.457f, 0.0f, 1.0f, -0.287f, 0.0f, -0.46f, 0.0f, 1.0f, -0.288f, 0.0f, -0.463f, 0.0f, 1.0f, -0.289f, 0.0f, -0.466f, 0.0f, 1.0f,
+ -0.289f, 0.0f, -0.47f, 0.0f, 1.0f, -0.29f, 0.0f, -0.473f, 0.0f, 1.0f, -0.291f, 0.0f, -0.476f, 0.0f, 1.0f, -0.292f, 0.0f, -0.48f, 0.0f, 1.0f,
+ -0.293f, 0.0f, -0.484f, 0.0f, 1.0f, -0.294f, 0.0f, -0.487f, 0.0f, 1.0f, -0.295f, 0.0f, -0.491f, 0.0f, 1.0f, -0.296f, 0.0f, -0.494f, 0.0f, 1.0f,
+ -0.297f, 0.0f, -0.498f, 0.0f, 1.0f, -0.298f, 0.0f, -0.502f, 0.0f, 1.0f, -0.299f, 0.0f, -0.505f, 0.0f, 1.0f, -0.3f, 0.0f, -0.509f, 0.0f, 1.0f,
+ -0.301f, 0.0f, -0.513f, 0.0f, 1.0f, -0.302f, 0.0f, -0.517f, 0.0f, 1.0f, -0.303f, 0.0f, -0.52f, 0.0f, 1.0f, -0.304f, 0.0f, -0.524f, 0.0f, 1.0f,
+ -0.305f, 0.0f, -0.528f, 0.0f, 1.0f, -0.306f, 0.0f, -0.532f, 0.0f, 1.0f, -0.307f, 0.0f, -0.535f, 0.0f, 1.0f, -0.308f, 0.0f, -0.539f, 0.0f, 1.0f,
+ -0.309f, 0.0f, -0.543f, 0.0f, 1.0f, -0.31f, 0.0f, -0.547f, 0.0f, 1.0f, -0.311f, 0.0f, -0.55f, 0.0f, 1.0f, -0.312f, 0.0f, -0.554f, 0.0f, 1.0f,
+ -0.313f, 0.0f, -0.558f, 0.0f, 1.0f, -0.314f, 0.0f, -0.562f, 0.0f, 1.0f, -0.315f, 0.0f, -0.565f, 0.0f, 1.0f, -0.316f, 0.0f, -0.569f, 0.0f, 1.0f,
+ -0.317f, 0.0f, -0.573f, 0.0f, 1.0f, -0.318f, 0.0f, -0.576f, 0.0f, 1.0f, -0.319f, 0.0f, -0.58f, 0.0f, 1.0f, -0.32f, 0.0f, -0.583f, 0.0f, 1.0f,
+ -0.321f, 0.0f, -0.587f, 0.0f, 1.0f, -0.322f, 0.0f, -0.591f, 0.0f, 1.0f, -0.323f, 0.0f, -0.594f, 0.0f, 1.0f, -0.323f, 0.0f, -0.598f, 0.0f, 1.0f,
+ -0.324f, 0.0f, -0.601f, 0.0f, 1.0f, -0.325f, 0.0f, -0.605f, 0.0f, 1.0f, -0.326f, 0.0f, -0.608f, 0.0f, 1.0f, -0.326f, 0.0f, -0.612f, 0.0f, 1.0f,
+ -0.327f, 0.0f, -0.615f, 0.0f, 1.0f, -0.328f, 0.0f, -0.619f, 0.0f, 1.0f, -0.328f, 0.0f, -0.622f, 0.0f, 1.0f, -0.329f, 0.0f, -0.625f, 0.0f, 1.0f,
+ -0.33f, 0.0f, -0.629f, 0.0f, 1.0f, -0.33f, 0.0f, -0.632f, 0.0f, 1.0f, -0.331f, 0.0f, -0.635f, 0.001f, 1.0f, -0.331f, 0.0f, -0.639f, 0.001f, 1.0f,
+ -0.332f, 0.0f, -0.642f, 0.002f, 1.0f, -0.332f, 0.0f, -0.645f, 0.002f, 1.0f, -0.333f, 0.0f, -0.649f, 0.003f, 1.0f, -0.333f, 0.0f, -0.652f, 0.005f, 1.0f,
+ -0.334f, 0.0f, -0.655f, 0.006f, 1.0f, -0.334f, 0.0f, -0.658f, 0.009f, 1.0f, -0.335f, 0.0f, -0.662f, 0.011f, 1.0f, -0.335f, 0.0f, -0.665f, 0.015f, 1.0f,
+ -0.335f, 0.0f, -0.668f, 0.019f, 1.0f, -0.336f, 0.0f, -0.672f, 0.024f, 1.0f, -0.336f, 0.0f, -0.675f, 0.031f, 1.0f, -0.337f, 0.0f, -0.678f, 0.038f, 1.0f,
+ -0.337f, 0.0f, -0.682f, 0.046f, 1.0f, -0.337f, 0.0f, -0.685f, 0.056f, 1.0f, -0.338f, 0.0f, -0.689f, 0.067f, 1.0f, -0.338f, 0.0f, -0.692f, 0.079f, 1.0f,
+ -0.338f, 0.0f, -0.696f, 0.093f, 1.0f, -0.339f, 0.0f, -0.699f, 0.107f, 1.0f, -0.339f, 0.0f, -0.703f, 0.123f, 1.0f, -0.34f, 0.0f, -0.706f, 0.139f, 1.0f,
+ -0.34f, 0.0f, -0.71f, 0.157f, 1.0f, -0.34f, 0.0f, -0.714f, 0.174f, 1.0f, -0.34f, 0.0f, -0.717f, 0.193f, 1.0f, -0.341f, 0.0f, -0.721f, 0.211f, 1.0f,
+ -0.341f, 0.0f, -0.725f, 0.23f, 1.0f, -0.341f, 0.0f, -0.729f, 0.248f, 1.0f, -0.342f, 0.0f, -0.732f, 0.266f, 1.0f, -0.342f, 0.0f, -0.736f, 0.284f, 1.0f,
+ -0.342f, 0.0f, -0.74f, 0.302f, 1.0f, -0.342f, 0.0f, -0.744f, 0.318f, 1.0f, -0.342f, 0.0f, -0.748f, 0.334f, 1.0f, -0.342f, 0.0f, -0.752f, 0.349f, 1.0f,
+ -0.343f, 0.0f, -0.756f, 0.364f, 1.0f, -0.343f, 0.0f, -0.76f, 0.377f, 1.0f, -0.343f, 0.0f, -0.763f, 0.389f, 1.0f, -0.343f, 0.0f, -0.767f, 0.401f, 1.0f,
+ -0.343f, 0.0f, -0.771f, 0.411f, 1.0f, -0.343f, 0.0f, -0.775f, 0.421f, 1.0f, -0.342f, 0.0f, -0.779f, 0.429f, 1.0f, -0.342f, 0.0f, -0.783f, 0.437f, 1.0f,
+ -0.342f, 0.0f, -0.786f, 0.444f, 1.0f, -0.342f, 0.0f, -0.79f, 0.451f, 1.0f, -0.342f, 0.0f, -0.794f, 0.456f, 1.0f, -0.341f, 0.0f, -0.797f, 0.461f, 1.0f,
+ -0.341f, 0.0f, -0.801f, 0.466f, 1.0f, -0.34f, 0.0f, -0.805f, 0.469f, 1.0f, -0.34f, 0.0f, -0.808f, 0.473f, 1.0f, -0.339f, 0.0f, -0.812f, 0.476f, 1.0f,
+ -0.339f, 0.0f, -0.815f, 0.478f, 1.0f, -0.338f, 0.0f, -0.818f, 0.48f, 1.0f, -0.338f, 0.0f, -0.822f, 0.482f, 1.0f, -0.337f, 0.0f, -0.825f, 0.483f, 1.0f,
+ -0.336f, 0.0f, -0.828f, 0.484f, 1.0f, -0.335f, 0.0f, -0.831f, 0.485f, 1.0f, -0.334f, 0.0f, -0.834f, 0.486f, 1.0f, -0.333f, 0.0f, -0.837f, 0.487f, 1.0f,
+ -0.332f, 0.0f, -0.84f, 0.487f, 1.0f, -0.331f, 0.0f, -0.843f, 0.487f, 1.0f, -0.33f, 0.0f, -0.846f, 0.488f, 1.0f, -0.329f, 0.0f, -0.849f, 0.488f, 1.0f,
+ -0.328f, 0.0f, -0.852f, 0.488f, 1.0f, -0.326f, 0.0f, -0.855f, 0.488f, 1.0f, -0.325f, 0.0f, -0.857f, 0.488f, 1.0f, -0.324f, 0.0f, -0.86f, 0.488f, 1.0f,
+ -0.322f, 0.0f, -0.863f, 0.488f, 1.0f, -0.321f, 0.0f, -0.865f, 0.488f, 1.0f, -0.319f, 0.0f, -0.868f, 0.488f, 1.0f, -0.318f, 0.0f, -0.871f, 0.488f, 1.0f,
+ -0.316f, 0.0f, -0.873f, 0.489f, 1.0f, -0.314f, 0.0f, -0.876f, 0.489f, 1.0f, -0.312f, 0.0f, -0.878f, 0.489f, 1.0f, -0.311f, 0.0f, -0.881f, 0.489f, 1.0f,
+ -0.309f, 0.0f, -0.883f, 0.489f, 1.0f, -0.307f, 0.0f, -0.885f, 0.489f, 1.0f, -0.305f, 0.0f, -0.888f, 0.49f, 1.0f, -0.303f, 0.0f, -0.89f, 0.491f, 1.0f,
+ -0.301f, 0.0f, -0.892f, 0.491f, 1.0f, -0.298f, 0.0f, -0.894f, 0.492f, 1.0f, -0.296f, 0.0f, -0.897f, 0.494f, 1.0f, -0.294f, 0.0f, -0.899f, 0.495f, 1.0f,
+ -0.292f, 0.0f, -0.901f, 0.497f, 1.0f, -0.289f, 0.0f, -0.903f, 0.5f, 1.0f, -0.287f, 0.0f, -0.905f, 0.502f, 1.0f, -0.284f, 0.0f, -0.907f, 0.505f, 1.0f,
+ -0.282f, 0.0f, -0.909f, 0.509f, 1.0f, -0.279f, 0.0f, -0.912f, 0.512f, 1.0f, -0.277f, 0.0f, -0.914f, 0.517f, 1.0f, -0.274f, 0.0f, -0.916f, 0.521f, 1.0f,
+ -0.271f, 0.0f, -0.918f, 0.526f, 1.0f, -0.269f, 0.0f, -0.919f, 0.531f, 1.0f, -0.266f, 0.0f, -0.921f, 0.537f, 1.0f, -0.263f, 0.0f, -0.923f, 0.543f, 1.0f,
+ -0.26f, 0.0f, -0.925f, 0.548f, 1.0f, -0.257f, 0.0f, -0.927f, 0.554f, 1.0f, -0.255f, 0.0f, -0.929f, 0.56f, 1.0f, -0.252f, 0.0f, -0.931f, 0.566f, 1.0f,
+ -0.249f, 0.0f, -0.932f, 0.571f, 1.0f, -0.246f, 0.0f, -0.934f, 0.577f, 1.0f, -0.243f, 0.0f, -0.936f, 0.582f, 1.0f, -0.24f, 0.0f, -0.938f, 0.587f, 1.0f,
+ -0.237f, 0.0f, -0.939f, 0.592f, 1.0f, -0.234f, 0.0f, -0.941f, 0.597f, 1.0f, -0.231f, 0.0f, -0.943f, 0.601f, 1.0f, -0.228f, 0.0f, -0.944f, 0.605f, 1.0f,
+ -0.225f, 0.0f, -0.946f, 0.609f, 1.0f, -0.222f, 0.0f, -0.948f, 0.613f, 1.0f, -0.219f, 0.0f, -0.949f, 0.617f, 1.0f, -0.216f, 0.0f, -0.951f, 0.62f, 1.0f,
+ -0.213f, 0.0f, -0.953f, 0.624f, 1.0f, -0.21f, 0.0f, -0.954f, 0.627f, 1.0f, -0.207f, 0.0f, -0.956f, 0.63f, 1.0f, -0.204f, 0.0f, -0.958f, 0.633f, 1.0f,
+ -0.201f, 0.0f, -0.959f, 0.636f, 1.0f, -0.198f, 0.0f, -0.961f, 0.639f, 1.0f, -0.195f, 0.0f, -0.962f, 0.641f, 1.0f, -0.191f, 0.0f, -0.964f, 0.643f, 1.0f,
+ -0.188f, 0.0f, -0.965f, 0.646f, 1.0f, -0.185f, 0.0f, -0.967f, 0.648f, 1.0f, -0.181f, 0.0f, -0.968f, 0.649f, 1.0f, -0.178f, 0.0f, -0.969f, 0.651f, 1.0f,
+ -0.175f, 0.0f, -0.971f, 0.653f, 1.0f, -0.171f, 0.0f, -0.972f, 0.654f, 1.0f, -0.168f, 0.0f, -0.973f, 0.655f, 1.0f, -0.165f, 0.0f, -0.974f, 0.657f, 1.0f,
+ -0.161f, 0.0f, -0.976f, 0.658f, 1.0f, -0.158f, 0.0f, -0.977f, 0.659f, 1.0f, -0.154f, 0.0f, -0.978f, 0.66f, 1.0f, -0.151f, 0.0f, -0.979f, 0.661f, 1.0f,
+ -0.148f, 0.0f, -0.98f, 0.662f, 1.0f, -0.144f, 0.0f, -0.981f, 0.664f, 1.0f, -0.141f, 0.0f, -0.982f, 0.665f, 1.0f, -0.137f, 0.0f, -0.983f, 0.667f, 1.0f,
+ -0.134f, 0.0f, -0.984f, 0.669f, 1.0f, -0.13f, 0.0f, -0.985f, 0.671f, 1.0f, -0.127f, 0.0f, -0.986f, 0.673f, 1.0f, -0.124f, 0.0f, -0.987f, 0.675f, 1.0f,
+ -0.12f, 0.0f, -0.988f, 0.678f, 1.0f, -0.117f, 0.0f, -0.989f, 0.68f, 1.0f, -0.113f, 0.0f, -0.99f, 0.683f, 1.0f, -0.11f, 0.0f, -0.991f, 0.685f, 1.0f,
+ -0.107f, 0.0f, -0.992f, 0.688f, 1.0f, -0.103f, 0.0f, -0.992f, 0.691f, 1.0f, -0.1f, 0.0f, -0.993f, 0.693f, 1.0f, -0.097f, 0.0f, -0.994f, 0.696f, 1.0f,
+ -0.093f, 0.0f, -0.995f, 0.698f, 1.0f, -0.09f, 0.0f, -0.996f, 0.701f, 1.0f, -0.087f, 0.0f, -0.997f, 0.703f, 1.0f, -0.084f, 0.0f, -0.997f, 0.705f, 1.0f,
+ -0.08f, 0.0f, -0.998f, 0.707f, 1.0f, -0.077f, 0.0f, -0.999f, 0.708f, 1.0f, -0.074f, 0.0f, -1.0f, 0.71f, 1.0f, -0.07f, 0.0f, -1.0f, 0.712f, 1.0f,
+ -0.067f, 0.0f, -1.001f, 0.713f, 1.0f, -0.063f, 0.0f, -1.002f, 0.715f, 1.0f, -0.06f, 0.0f, -1.002f, 0.717f, 1.0f, -0.056f, 0.0f, -1.003f, 0.718f, 1.0f,
+ -0.053f, 0.0f, -1.003f, 0.72f, 1.0f, -0.049f, 0.0f, -1.004f, 0.723f, 1.0f, -0.045f, 0.0f, -1.004f, 0.725f, 1.0f, -0.041f, 0.0f, -1.005f, 0.728f, 1.0f,
+ -0.038f, 0.0f, -1.005f, 0.73f, 1.0f, -0.034f, 0.0f, -1.006f, 0.733f, 1.0f, -0.03f, 0.0f, -1.006f, 0.736f, 1.0f, -0.026f, 0.0f, -1.007f, 0.738f, 1.0f,
+ -0.022f, 0.0f, -1.007f, 0.741f, 1.0f, -0.018f, 0.0f, -1.007f, 0.743f, 1.0f, -0.014f, 0.0f, -1.008f, 0.746f, 1.0f, -0.01f, 0.0f, -1.008f, 0.748f, 1.0f,
+ -0.006f, 0.0f, -1.009f, 0.75f, 1.0f, -0.001f, 0.0f, -1.009f, 0.752f, 1.0f, 0.003f, 0.0f, -1.009f, 0.754f, 1.0f, 0.007f, 0.0f, -1.01f, 0.755f, 1.0f,
+ 0.011f, 0.0f, -1.01f, 0.757f, 1.0f, 0.015f, 0.0f, -1.01f, 0.758f, 1.0f, 0.02f, 0.0f, -1.011f, 0.759f, 1.0f, 0.024f, 0.0f, -1.011f, 0.76f, 1.0f,
+ 0.028f, 0.0f, -1.011f, 0.761f, 1.0f, 0.033f, 0.0f, -1.011f, 0.761f, 1.0f, 0.037f, 0.0f, -1.012f, 0.762f, 1.0f, 0.041f, 0.0f, -1.012f, 0.762f, 1.0f,
+ 0.045f, 0.0f, -1.012f, 0.763f, 1.0f, 0.05f, 0.0f, -1.012f, 0.763f, 1.0f, 0.054f, 0.0f, -1.012f, 0.764f, 1.0f, 0.058f, 0.0f, -1.013f, 0.764f, 1.0f,
+ 0.062f, 0.0f, -1.013f, 0.764f, 1.0f, 0.066f, 0.0f, -1.013f, 0.764f, 1.0f, 0.071f, 0.0f, -1.013f, 0.764f, 1.0f, 0.075f, 0.0f, -1.013f, 0.765f, 1.0f,
+ 0.079f, 0.0f, -1.013f, 0.765f, 1.0f, 0.083f, 0.0f, -1.013f, 0.765f, 1.0f, 0.087f, 0.0f, -1.013f, 0.765f, 1.0f, 0.091f, 0.0f, -1.013f, 0.765f, 1.0f,
+ 0.095f, 0.0f, -1.013f, 0.765f, 1.0f, 0.099f, 0.0f, -1.013f, 0.766f, 1.0f, 0.103f, 0.0f, -1.013f, 0.766f, 1.0f, 0.108f, 0.0f, -1.012f, 0.766f, 1.0f,
+ 0.112f, 0.0f, -1.012f, 0.766f, 1.0f, 0.116f, 0.0f, -1.012f, 0.766f, 1.0f, 0.119f, 0.0f, -1.012f, 0.767f, 1.0f, 0.123f, 0.0f, -1.011f, 0.767f, 1.0f,
+ 0.127f, 0.0f, -1.011f, 0.767f, 1.0f, 0.131f, 0.0f, -1.01f, 0.767f, 1.0f, 0.135f, 0.0f, -1.01f, 0.767f, 1.0f, 0.139f, 0.0f, -1.009f, 0.768f, 1.0f,
+ 0.143f, 0.0f, -1.009f, 0.768f, 1.0f, 0.147f, 0.0f, -1.008f, 0.768f, 1.0f, 0.151f, 0.0f, -1.007f, 0.769f, 1.0f, 0.154f, 0.0f, -1.007f, 0.769f, 1.0f,
+ 0.158f, 0.0f, -1.006f, 0.769f, 1.0f, 0.162f, 0.0f, -1.005f, 0.769f, 1.0f, 0.166f, 0.0f, -1.004f, 0.77f, 1.0f, 0.17f, 0.0f, -1.003f, 0.77f, 1.0f,
+ 0.173f, 0.0f, -1.003f, 0.77f, 1.0f, 0.177f, 0.0f, -1.002f, 0.771f, 1.0f, 0.181f, 0.0f, -1.001f, 0.771f, 1.0f, 0.184f, 0.0f, -1.0f, 0.772f, 1.0f,
+ 0.188f, 0.0f, -0.999f, 0.772f, 1.0f, 0.192f, 0.0f, -0.998f, 0.773f, 1.0f, 0.195f, 0.0f, -0.997f, 0.773f, 1.0f, 0.199f, 0.0f, -0.996f, 0.774f, 1.0f,
+ 0.202f, 0.0f, -0.995f, 0.774f, 1.0f, 0.206f, 0.0f, -0.994f, 0.775f, 1.0f, 0.209f, 0.0f, -0.993f, 0.776f, 1.0f, 0.213f, 0.0f, -0.992f, 0.776f, 1.0f,
+ 0.216f, 0.0f, -0.991f, 0.777f, 1.0f, 0.22f, 0.0f, -0.99f, 0.777f, 1.0f, 0.223f, 0.0f, -0.988f, 0.778f, 1.0f, 0.227f, 0.0f, -0.987f, 0.778f, 1.0f,
+ 0.23f, 0.0f, -0.986f, 0.778f, 1.0f, 0.233f, 0.0f, -0.985f, 0.779f, 1.0f, 0.237f, 0.0f, -0.983f, 0.779f, 1.0f, 0.24f, 0.0f, -0.982f, 0.779f, 1.0f,
+ 0.243f, 0.0f, -0.981f, 0.779f, 1.0f, 0.246f, 0.0f, -0.979f, 0.778f, 1.0f, 0.249f, 0.0f, -0.978f, 0.778f, 1.0f, 0.252f, 0.0f, -0.976f, 0.777f, 1.0f,
+ 0.255f, 0.0f, -0.975f, 0.777f, 1.0f, 0.258f, 0.0f, -0.973f, 0.776f, 1.0f, 0.261f, 0.0f, -0.972f, 0.775f, 1.0f, 0.264f, 0.0f, -0.97f, 0.773f, 1.0f,
+ 0.267f, 0.0f, -0.968f, 0.772f, 1.0f, 0.269f, 0.0f, -0.967f, 0.77f, 1.0f, 0.272f, 0.0f, -0.965f, 0.769f, 1.0f, 0.275f, 0.0f, -0.963f, 0.767f, 1.0f,
+ 0.277f, 0.0f, -0.961f, 0.765f, 1.0f, 0.279f, 0.0f, -0.959f, 0.763f, 1.0f, 0.282f, 0.0f, -0.957f, 0.761f, 1.0f, 0.284f, 0.0f, -0.955f, 0.759f, 1.0f,
+ 0.286f, 0.0f, -0.953f, 0.756f, 1.0f, 0.288f, 0.0f, -0.951f, 0.754f, 1.0f, 0.29f, 0.0f, -0.948f, 0.752f, 1.0f, 0.292f, 0.0f, -0.946f, 0.749f, 1.0f,
+ 0.294f, 0.0f, -0.944f, 0.746f, 1.0f, 0.296f, 0.0f, -0.941f, 0.744f, 1.0f, 0.298f, 0.0f, -0.939f, 0.741f, 1.0f, 0.3f, 0.0f, -0.937f, 0.738f, 1.0f,
+ 0.302f, 0.0f, -0.934f, 0.736f, 1.0f, 0.303f, 0.0f, -0.932f, 0.733f, 1.0f, 0.305f, 0.0f, -0.929f, 0.73f, 1.0f, 0.306f, 0.0f, -0.926f, 0.727f, 1.0f,
+ 0.308f, 0.0f, -0.924f, 0.724f, 1.0f, 0.309f, 0.0f, -0.921f, 0.721f, 1.0f, 0.311f, 0.0f, -0.918f, 0.719f, 1.0f, 0.312f, 0.0f, -0.916f, 0.716f, 1.0f,
+ 0.313f, 0.0f, -0.913f, 0.713f, 1.0f, 0.315f, 0.0f, -0.91f, 0.71f, 1.0f, 0.316f, 0.0f, -0.907f, 0.707f, 1.0f, 0.317f, 0.0f, -0.904f, 0.704f, 1.0f,
+ 0.318f, 0.0f, -0.901f, 0.7f, 1.0f, 0.319f, 0.0f, -0.898f, 0.697f, 1.0f, 0.32f, 0.0f, -0.895f, 0.693f, 1.0f, 0.321f, 0.0f, -0.892f, 0.69f, 1.0f,
+ 0.322f, 0.0f, -0.889f, 0.686f, 1.0f, 0.323f, 0.0f, -0.886f, 0.681f, 1.0f, 0.324f, 0.0f, -0.883f, 0.677f, 1.0f, 0.325f, 0.0f, -0.88f, 0.672f, 1.0f,
+ 0.326f, 0.0f, -0.876f, 0.667f, 1.0f, 0.326f, 0.0f, -0.873f, 0.661f, 1.0f, 0.327f, 0.0f, -0.87f, 0.655f, 1.0f, 0.328f, 0.0f, -0.867f, 0.649f, 1.0f,
+ 0.329f, 0.0f, -0.864f, 0.643f, 1.0f, 0.329f, 0.0f, -0.861f, 0.637f, 1.0f, 0.33f, 0.0f, -0.857f, 0.63f, 1.0f, 0.331f, 0.0f, -0.854f, 0.624f, 1.0f,
+ 0.331f, 0.0f, -0.851f, 0.618f, 1.0f, 0.332f, 0.0f, -0.848f, 0.613f, 1.0f, 0.333f, 0.0f, -0.845f, 0.607f, 1.0f, 0.333f, 0.0f, -0.841f, 0.603f, 1.0f,
+ 0.334f, 0.0f, -0.838f, 0.598f, 1.0f, 0.334f, 0.0f, -0.835f, 0.594f, 1.0f, 0.335f, 0.0f, -0.832f, 0.591f, 1.0f, 0.335f, 0.0f, -0.828f, 0.588f, 1.0f,
+ 0.335f, 0.0f, -0.825f, 0.586f, 1.0f, 0.336f, 0.0f, -0.821f, 0.584f, 1.0f, 0.336f, 0.0f, -0.818f, 0.582f, 1.0f, 0.336f, 0.0f, -0.814f, 0.581f, 1.0f,
+ 0.337f, 0.0f, -0.811f, 0.58f, 1.0f, 0.337f, 0.0f, -0.807f, 0.58f, 1.0f, 0.337f, 0.0f, -0.803f, 0.579f, 1.0f, 0.337f, 0.0f, -0.799f, 0.579f, 1.0f,
+ 0.337f, 0.0f, -0.795f, 0.578f, 1.0f, 0.337f, 0.0f, -0.79f, 0.578f, 1.0f, 0.337f, 0.0f, -0.786f, 0.578f, 1.0f, 0.338f, 0.0f, -0.782f, 0.577f, 1.0f,
+ 0.338f, 0.0f, -0.777f, 0.576f, 1.0f, 0.337f, 0.0f, -0.772f, 0.574f, 1.0f, 0.337f, 0.0f, -0.767f, 0.572f, 1.0f, 0.337f, 0.0f, -0.762f, 0.569f, 1.0f,
+ 0.337f, 0.0f, -0.756f, 0.565f, 1.0f, 0.337f, 0.0f, -0.751f, 0.559f, 1.0f, 0.337f, 0.0f, -0.745f, 0.553f, 1.0f, 0.336f, 0.0f, -0.739f, 0.544f, 1.0f,
+ 0.336f, 0.0f, -0.732f, 0.534f, 1.0f, 0.335f, 0.0f, -0.725f, 0.521f, 1.0f, 0.334f, 0.0f, -0.718f, 0.505f, 1.0f, 0.333f, 0.0f, -0.711f, 0.487f, 1.0f,
+ 0.332f, 0.0f, -0.703f, 0.466f, 1.0f, 0.331f, 0.0f, -0.694f, 0.441f, 1.0f, 0.33f, 0.0f, -0.686f, 0.413f, 1.0f, 0.328f, 0.0f, -0.677f, 0.383f, 1.0f,
+ 0.326f, 0.0f, -0.667f, 0.35f, 1.0f, 0.325f, 0.0f, -0.657f, 0.316f, 1.0f, 0.323f, 0.0f, -0.647f, 0.281f, 1.0f, 0.32f, 0.0f, -0.636f, 0.246f, 1.0f,
+ 0.318f, 0.0f, -0.625f, 0.212f, 1.0f, 0.316f, 0.0f, -0.614f, 0.18f, 1.0f, 0.313f, 0.0f, -0.603f, 0.149f, 1.0f, 0.311f, 0.0f, -0.592f, 0.12f, 1.0f,
+ 0.308f, 0.0f, -0.581f, 0.093f, 1.0f, 0.306f, 0.0f, -0.57f, 0.069f, 1.0f, 0.303f, 0.0f, -0.559f, 0.046f, 1.0f, 0.301f, 0.0f, -0.55f, 0.027f, 1.0f,
+ 0.298f, 0.0f, -0.537f, 0.0f, 1.0f,
+};
+
+static const float data26[41 * GP_PRIM_DATABUF_SIZE] = {
+ -0.104f, 0.0f, -0.795f, 0.258f, 1.0f, -0.1f, 0.0f, -0.799f, 0.28f, 1.0f, -0.097f, 0.0f, -0.801f, 0.294f, 1.0f, -0.094f, 0.0f, -0.805f, 0.312f, 1.0f,
+ -0.09f, 0.0f, -0.808f, 0.328f, 1.0f, -0.086f, 0.0f, -0.811f, 0.345f, 1.0f, -0.082f, 0.0f, -0.815f, 0.361f, 1.0f, -0.078f, 0.0f, -0.818f, 0.377f, 1.0f,
+ -0.073f, 0.0f, -0.821f, 0.392f, 1.0f, -0.068f, 0.0f, -0.824f, 0.407f, 1.0f, -0.063f, 0.0f, -0.827f, 0.421f, 1.0f, -0.057f, 0.0f, -0.83f, 0.435f, 1.0f,
+ -0.051f, 0.0f, -0.833f, 0.448f, 1.0f, -0.045f, 0.0f, -0.835f, 0.46f, 1.0f, -0.039f, 0.0f, -0.837f, 0.471f, 1.0f, -0.033f, 0.0f, -0.839f, 0.481f, 1.0f,
+ -0.026f, 0.0f, -0.841f, 0.491f, 1.0f, -0.019f, 0.0f, -0.842f, 0.5f, 1.0f, -0.012f, 0.0f, -0.843f, 0.508f, 1.0f, -0.005f, 0.0f, -0.843f, 0.515f, 1.0f,
+ 0.002f, 0.0f, -0.843f, 0.522f, 1.0f, 0.009f, 0.0f, -0.843f, 0.527f, 1.0f, 0.016f, 0.0f, -0.842f, 0.532f, 1.0f, 0.023f, 0.0f, -0.841f, 0.535f, 1.0f,
+ 0.03f, 0.0f, -0.839f, 0.538f, 1.0f, 0.037f, 0.0f, -0.837f, 0.538f, 1.0f, 0.044f, 0.0f, -0.835f, 0.537f, 1.0f, 0.05f, 0.0f, -0.833f, 0.532f, 1.0f,
+ 0.056f, 0.0f, -0.83f, 0.524f, 1.0f, 0.062f, 0.0f, -0.827f, 0.513f, 1.0f, 0.068f, 0.0f, -0.823f, 0.496f, 1.0f, 0.074f, 0.0f, -0.82f, 0.474f, 1.0f,
+ 0.079f, 0.0f, -0.817f, 0.446f, 1.0f, 0.084f, 0.0f, -0.813f, 0.411f, 1.0f, 0.089f, 0.0f, -0.809f, 0.37f, 1.0f, 0.093f, 0.0f, -0.806f, 0.323f, 1.0f,
+ 0.098f, 0.0f, -0.802f, 0.269f, 1.0f, 0.102f, 0.0f, -0.798f, 0.211f, 1.0f, 0.106f, 0.0f, -0.795f, 0.146f, 1.0f, 0.109f, 0.0f, -0.792f, 0.089f, 1.0f,
+ 0.114f, 0.0f, -0.787f, 0.0f, 1.0f,
+};
+
+static const float data27[77 * GP_PRIM_DATABUF_SIZE] = {
+ -0.105f, 0.0f, -0.259f, 0.214f, 1.0f, -0.103f, 0.0f, -0.253f, 0.263f, 1.0f, -0.101f, 0.0f, -0.249f, 0.291f, 1.0f, -0.099f, 0.0f, -0.244f, 0.324f, 1.0f,
+ -0.098f, 0.0f, -0.24f, 0.351f, 1.0f, -0.096f, 0.0f, -0.235f, 0.376f, 1.0f, -0.094f, 0.0f, -0.231f, 0.397f, 1.0f, -0.092f, 0.0f, -0.227f, 0.416f, 1.0f,
+ -0.09f, 0.0f, -0.222f, 0.432f, 1.0f, -0.088f, 0.0f, -0.218f, 0.446f, 1.0f, -0.086f, 0.0f, -0.215f, 0.458f, 1.0f, -0.084f, 0.0f, -0.211f, 0.469f, 1.0f,
+ -0.082f, 0.0f, -0.208f, 0.478f, 1.0f, -0.079f, 0.0f, -0.205f, 0.486f, 1.0f, -0.077f, 0.0f, -0.203f, 0.494f, 1.0f, -0.075f, 0.0f, -0.2f, 0.501f, 1.0f,
+ -0.073f, 0.0f, -0.198f, 0.508f, 1.0f, -0.071f, 0.0f, -0.197f, 0.515f, 1.0f, -0.068f, 0.0f, -0.195f, 0.521f, 1.0f, -0.066f, 0.0f, -0.194f, 0.528f, 1.0f,
+ -0.064f, 0.0f, -0.194f, 0.534f, 1.0f, -0.061f, 0.0f, -0.194f, 0.54f, 1.0f, -0.059f, 0.0f, -0.194f, 0.546f, 1.0f, -0.056f, 0.0f, -0.194f, 0.551f, 1.0f,
+ -0.054f, 0.0f, -0.195f, 0.555f, 1.0f, -0.051f, 0.0f, -0.196f, 0.559f, 1.0f, -0.049f, 0.0f, -0.198f, 0.562f, 1.0f, -0.046f, 0.0f, -0.2f, 0.565f, 1.0f,
+ -0.044f, 0.0f, -0.201f, 0.567f, 1.0f, -0.041f, 0.0f, -0.204f, 0.568f, 1.0f, -0.039f, 0.0f, -0.206f, 0.569f, 1.0f, -0.036f, 0.0f, -0.208f, 0.57f, 1.0f,
+ -0.034f, 0.0f, -0.21f, 0.571f, 1.0f, -0.032f, 0.0f, -0.213f, 0.571f, 1.0f, -0.029f, 0.0f, -0.215f, 0.571f, 1.0f, -0.027f, 0.0f, -0.217f, 0.572f, 1.0f,
+ -0.024f, 0.0f, -0.219f, 0.572f, 1.0f, -0.022f, 0.0f, -0.221f, 0.572f, 1.0f, -0.019f, 0.0f, -0.222f, 0.572f, 1.0f, -0.016f, 0.0f, -0.224f, 0.572f, 1.0f,
+ -0.013f, 0.0f, -0.225f, 0.572f, 1.0f, -0.01f, 0.0f, -0.226f, 0.573f, 1.0f, -0.007f, 0.0f, -0.227f, 0.573f, 1.0f, -0.004f, 0.0f, -0.227f, 0.573f, 1.0f,
+ -0.001f, 0.0f, -0.227f, 0.574f, 1.0f, 0.002f, 0.0f, -0.227f, 0.575f, 1.0f, 0.005f, 0.0f, -0.227f, 0.576f, 1.0f, 0.008f, 0.0f, -0.226f, 0.577f, 1.0f,
+ 0.011f, 0.0f, -0.225f, 0.578f, 1.0f, 0.015f, 0.0f, -0.224f, 0.579f, 1.0f, 0.018f, 0.0f, -0.222f, 0.58f, 1.0f, 0.021f, 0.0f, -0.221f, 0.581f, 1.0f,
+ 0.024f, 0.0f, -0.219f, 0.582f, 1.0f, 0.027f, 0.0f, -0.217f, 0.582f, 1.0f, 0.03f, 0.0f, -0.215f, 0.583f, 1.0f, 0.033f, 0.0f, -0.213f, 0.583f, 1.0f,
+ 0.036f, 0.0f, -0.212f, 0.583f, 1.0f, 0.039f, 0.0f, -0.21f, 0.583f, 1.0f, 0.042f, 0.0f, -0.208f, 0.583f, 1.0f, 0.045f, 0.0f, -0.207f, 0.583f, 1.0f,
+ 0.048f, 0.0f, -0.205f, 0.583f, 1.0f, 0.051f, 0.0f, -0.204f, 0.583f, 1.0f, 0.054f, 0.0f, -0.203f, 0.583f, 1.0f, 0.058f, 0.0f, -0.203f, 0.583f, 1.0f,
+ 0.061f, 0.0f, -0.202f, 0.583f, 1.0f, 0.064f, 0.0f, -0.202f, 0.574f, 1.0f, 0.067f, 0.0f, -0.202f, 0.565f, 1.0f, 0.07f, 0.0f, -0.203f, 0.556f, 1.0f,
+ 0.073f, 0.0f, -0.203f, 0.547f, 1.0f, 0.075f, 0.0f, -0.204f, 0.515f, 1.0f, 0.078f, 0.0f, -0.204f, 0.483f, 1.0f, 0.08f, 0.0f, -0.205f, 0.451f, 1.0f,
+ 0.083f, 0.0f, -0.206f, 0.419f, 1.0f, 0.085f, 0.0f, -0.207f, 0.314f, 1.0f, 0.087f, 0.0f, -0.208f, 0.21f, 1.0f, 0.089f, 0.0f, -0.209f, 0.105f, 1.0f,
+ 0.091f, 0.0f, -0.21f, 0.0f, 1.0f,
+};
+
+static const float data28[257 * GP_PRIM_DATABUF_SIZE] = {
+ -0.637f, 0.0f, -0.172f, 0.0f, 1.0f, -0.641f, 0.0f, -0.172f, 0.0f, 1.0f, -0.643f, 0.0f, -0.172f, 0.0f, 1.0f, -0.646f, 0.0f, -0.172f, 0.0f, 1.0f,
+ -0.65f, 0.0f, -0.172f, 0.0f, 1.0f, -0.653f, 0.0f, -0.172f, 0.0f, 1.0f, -0.657f, 0.0f, -0.172f, 0.0f, 1.0f, -0.66f, 0.0f, -0.172f, 0.0f, 1.0f,
+ -0.664f, 0.0f, -0.171f, 0.0f, 1.0f, -0.668f, 0.0f, -0.171f, 0.0f, 1.0f, -0.672f, 0.0f, -0.171f, 0.0f, 1.0f, -0.677f, 0.0f, -0.171f, 0.0f, 1.0f,
+ -0.681f, 0.0f, -0.171f, 0.0f, 1.0f, -0.685f, 0.0f, -0.171f, 0.0f, 1.0f, -0.69f, 0.0f, -0.17f, 0.0f, 1.0f, -0.694f, 0.0f, -0.17f, 0.0f, 1.0f,
+ -0.699f, 0.0f, -0.17f, 0.0f, 1.0f, -0.704f, 0.0f, -0.169f, 0.0f, 1.0f, -0.708f, 0.0f, -0.169f, 0.0f, 1.0f, -0.713f, 0.0f, -0.168f, 0.0f, 1.0f,
+ -0.717f, 0.0f, -0.168f, 0.0f, 1.0f, -0.722f, 0.0f, -0.167f, 0.0f, 1.0f, -0.727f, 0.0f, -0.167f, 0.0f, 1.0f, -0.731f, 0.0f, -0.166f, 0.0f, 1.0f,
+ -0.735f, 0.0f, -0.166f, 0.0f, 1.0f, -0.74f, 0.0f, -0.165f, 0.0f, 1.0f, -0.744f, 0.0f, -0.164f, 0.0f, 1.0f, -0.749f, 0.0f, -0.163f, 0.0f, 1.0f,
+ -0.753f, 0.0f, -0.163f, 0.0f, 1.0f, -0.757f, 0.0f, -0.162f, 0.0f, 1.0f, -0.761f, 0.0f, -0.161f, 0.0f, 1.0f, -0.765f, 0.0f, -0.16f, 0.0f, 1.0f,
+ -0.769f, 0.0f, -0.159f, 0.0f, 1.0f, -0.773f, 0.0f, -0.158f, 0.0f, 1.0f, -0.777f, 0.0f, -0.157f, 0.0f, 1.0f, -0.781f, 0.0f, -0.156f, 0.001f, 1.0f,
+ -0.785f, 0.0f, -0.155f, 0.001f, 1.0f, -0.789f, 0.0f, -0.154f, 0.002f, 1.0f, -0.793f, 0.0f, -0.153f, 0.003f, 1.0f, -0.797f, 0.0f, -0.152f, 0.004f, 1.0f,
+ -0.801f, 0.0f, -0.15f, 0.005f, 1.0f, -0.805f, 0.0f, -0.149f, 0.006f, 1.0f, -0.81f, 0.0f, -0.147f, 0.008f, 1.0f, -0.814f, 0.0f, -0.146f, 0.009f, 1.0f,
+ -0.818f, 0.0f, -0.144f, 0.011f, 1.0f, -0.823f, 0.0f, -0.143f, 0.014f, 1.0f, -0.827f, 0.0f, -0.141f, 0.016f, 1.0f, -0.831f, 0.0f, -0.139f, 0.019f, 1.0f,
+ -0.836f, 0.0f, -0.138f, 0.022f, 1.0f, -0.84f, 0.0f, -0.136f, 0.024f, 1.0f, -0.844f, 0.0f, -0.135f, 0.026f, 1.0f, -0.849f, 0.0f, -0.133f, 0.027f, 1.0f,
+ -0.853f, 0.0f, -0.131f, 0.027f, 1.0f, -0.857f, 0.0f, -0.13f, 0.027f, 1.0f, -0.861f, 0.0f, -0.128f, 0.027f, 1.0f, -0.865f, 0.0f, -0.126f, 0.027f, 1.0f,
+ -0.868f, 0.0f, -0.125f, 0.026f, 1.0f, -0.872f, 0.0f, -0.123f, 0.025f, 1.0f, -0.876f, 0.0f, -0.121f, 0.025f, 1.0f, -0.879f, 0.0f, -0.119f, 0.024f, 1.0f,
+ -0.883f, 0.0f, -0.118f, 0.023f, 1.0f, -0.886f, 0.0f, -0.116f, 0.022f, 1.0f, -0.89f, 0.0f, -0.114f, 0.022f, 1.0f, -0.894f, 0.0f, -0.112f, 0.021f, 1.0f,
+ -0.898f, 0.0f, -0.11f, 0.022f, 1.0f, -0.901f, 0.0f, -0.107f, 0.022f, 1.0f, -0.905f, 0.0f, -0.105f, 0.024f, 1.0f, -0.909f, 0.0f, -0.103f, 0.026f, 1.0f,
+ -0.913f, 0.0f, -0.1f, 0.029f, 1.0f, -0.917f, 0.0f, -0.098f, 0.032f, 1.0f, -0.921f, 0.0f, -0.095f, 0.035f, 1.0f, -0.926f, 0.0f, -0.092f, 0.039f, 1.0f,
+ -0.93f, 0.0f, -0.09f, 0.043f, 1.0f, -0.934f, 0.0f, -0.087f, 0.047f, 1.0f, -0.938f, 0.0f, -0.084f, 0.051f, 1.0f, -0.942f, 0.0f, -0.081f, 0.055f, 1.0f,
+ -0.946f, 0.0f, -0.078f, 0.06f, 1.0f, -0.95f, 0.0f, -0.075f, 0.065f, 1.0f, -0.954f, 0.0f, -0.073f, 0.07f, 1.0f, -0.958f, 0.0f, -0.07f, 0.075f, 1.0f,
+ -0.961f, 0.0f, -0.067f, 0.081f, 1.0f, -0.965f, 0.0f, -0.064f, 0.087f, 1.0f, -0.968f, 0.0f, -0.061f, 0.092f, 1.0f, -0.972f, 0.0f, -0.058f, 0.098f, 1.0f,
+ -0.975f, 0.0f, -0.055f, 0.103f, 1.0f, -0.979f, 0.0f, -0.053f, 0.108f, 1.0f, -0.982f, 0.0f, -0.05f, 0.112f, 1.0f, -0.985f, 0.0f, -0.047f, 0.116f, 1.0f,
+ -0.988f, 0.0f, -0.045f, 0.12f, 1.0f, -0.991f, 0.0f, -0.042f, 0.123f, 1.0f, -0.994f, 0.0f, -0.039f, 0.126f, 1.0f, -0.997f, 0.0f, -0.037f, 0.129f, 1.0f,
+ -1.0f, 0.0f, -0.034f, 0.131f, 1.0f, -1.003f, 0.0f, -0.031f, 0.133f, 1.0f, -1.005f, 0.0f, -0.029f, 0.135f, 1.0f, -1.008f, 0.0f, -0.026f, 0.137f, 1.0f,
+ -1.01f, 0.0f, -0.024f, 0.139f, 1.0f, -1.013f, 0.0f, -0.021f, 0.141f, 1.0f, -1.016f, 0.0f, -0.018f, 0.143f, 1.0f, -1.018f, 0.0f, -0.016f, 0.144f, 1.0f,
+ -1.02f, 0.0f, -0.013f, 0.146f, 1.0f, -1.023f, 0.0f, -0.011f, 0.148f, 1.0f, -1.025f, 0.0f, -0.008f, 0.149f, 1.0f, -1.027f, 0.0f, -0.006f, 0.151f, 1.0f,
+ -1.029f, 0.0f, -0.003f, 0.152f, 1.0f, -1.032f, 0.0f, -0.001f, 0.154f, 1.0f, -1.034f, 0.0f, 0.001f, 0.154f, 1.0f, -1.036f, 0.0f, 0.004f, 0.155f, 1.0f,
+ -1.038f, 0.0f, 0.006f, 0.156f, 1.0f, -1.041f, 0.0f, 0.008f, 0.156f, 1.0f, -1.043f, 0.0f, 0.01f, 0.157f, 1.0f, -1.045f, 0.0f, 0.013f, 0.157f, 1.0f,
+ -1.047f, 0.0f, 0.015f, 0.157f, 1.0f, -1.049f, 0.0f, 0.018f, 0.158f, 1.0f, -1.051f, 0.0f, 0.02f, 0.158f, 1.0f, -1.053f, 0.0f, 0.023f, 0.158f, 1.0f,
+ -1.055f, 0.0f, 0.025f, 0.158f, 1.0f, -1.057f, 0.0f, 0.028f, 0.158f, 1.0f, -1.059f, 0.0f, 0.03f, 0.158f, 1.0f, -1.061f, 0.0f, 0.033f, 0.158f, 1.0f,
+ -1.063f, 0.0f, 0.036f, 0.158f, 1.0f, -1.065f, 0.0f, 0.038f, 0.158f, 1.0f, -1.067f, 0.0f, 0.041f, 0.158f, 1.0f, -1.069f, 0.0f, 0.044f, 0.157f, 1.0f,
+ -1.071f, 0.0f, 0.047f, 0.157f, 1.0f, -1.073f, 0.0f, 0.049f, 0.156f, 1.0f, -1.074f, 0.0f, 0.052f, 0.155f, 1.0f, -1.076f, 0.0f, 0.055f, 0.154f, 1.0f,
+ -1.078f, 0.0f, 0.058f, 0.153f, 1.0f, -1.08f, 0.0f, 0.061f, 0.152f, 1.0f, -1.082f, 0.0f, 0.064f, 0.15f, 1.0f, -1.083f, 0.0f, 0.067f, 0.148f, 1.0f,
+ -1.085f, 0.0f, 0.07f, 0.146f, 1.0f, -1.087f, 0.0f, 0.073f, 0.144f, 1.0f, -1.089f, 0.0f, 0.076f, 0.142f, 1.0f, -1.091f, 0.0f, 0.08f, 0.14f, 1.0f,
+ -1.092f, 0.0f, 0.083f, 0.138f, 1.0f, -1.094f, 0.0f, 0.086f, 0.136f, 1.0f, -1.096f, 0.0f, 0.09f, 0.135f, 1.0f, -1.097f, 0.0f, 0.093f, 0.134f, 1.0f,
+ -1.099f, 0.0f, 0.096f, 0.134f, 1.0f, -1.101f, 0.0f, 0.1f, 0.134f, 1.0f, -1.103f, 0.0f, 0.103f, 0.136f, 1.0f, -1.104f, 0.0f, 0.107f, 0.139f, 1.0f,
+ -1.106f, 0.0f, 0.111f, 0.144f, 1.0f, -1.107f, 0.0f, 0.114f, 0.15f, 1.0f, -1.109f, 0.0f, 0.118f, 0.158f, 1.0f, -1.11f, 0.0f, 0.122f, 0.167f, 1.0f,
+ -1.111f, 0.0f, 0.126f, 0.178f, 1.0f, -1.113f, 0.0f, 0.13f, 0.191f, 1.0f, -1.114f, 0.0f, 0.134f, 0.205f, 1.0f, -1.115f, 0.0f, 0.138f, 0.22f, 1.0f,
+ -1.116f, 0.0f, 0.142f, 0.237f, 1.0f, -1.117f, 0.0f, 0.146f, 0.254f, 1.0f, -1.118f, 0.0f, 0.15f, 0.272f, 1.0f, -1.119f, 0.0f, 0.155f, 0.291f, 1.0f,
+ -1.119f, 0.0f, 0.159f, 0.31f, 1.0f, -1.12f, 0.0f, 0.163f, 0.329f, 1.0f, -1.121f, 0.0f, 0.167f, 0.348f, 1.0f, -1.121f, 0.0f, 0.172f, 0.367f, 1.0f,
+ -1.122f, 0.0f, 0.176f, 0.386f, 1.0f, -1.122f, 0.0f, 0.18f, 0.405f, 1.0f, -1.123f, 0.0f, 0.184f, 0.423f, 1.0f, -1.123f, 0.0f, 0.189f, 0.441f, 1.0f,
+ -1.124f, 0.0f, 0.193f, 0.458f, 1.0f, -1.124f, 0.0f, 0.197f, 0.475f, 1.0f, -1.124f, 0.0f, 0.202f, 0.492f, 1.0f, -1.124f, 0.0f, 0.206f, 0.508f, 1.0f,
+ -1.125f, 0.0f, 0.21f, 0.524f, 1.0f, -1.125f, 0.0f, 0.214f, 0.539f, 1.0f, -1.125f, 0.0f, 0.218f, 0.554f, 1.0f, -1.124f, 0.0f, 0.223f, 0.568f, 1.0f,
+ -1.124f, 0.0f, 0.227f, 0.581f, 1.0f, -1.124f, 0.0f, 0.231f, 0.593f, 1.0f, -1.124f, 0.0f, 0.235f, 0.604f, 1.0f, -1.123f, 0.0f, 0.239f, 0.614f, 1.0f,
+ -1.123f, 0.0f, 0.243f, 0.624f, 1.0f, -1.122f, 0.0f, 0.247f, 0.632f, 1.0f, -1.122f, 0.0f, 0.251f, 0.64f, 1.0f, -1.121f, 0.0f, 0.255f, 0.646f, 1.0f,
+ -1.121f, 0.0f, 0.258f, 0.653f, 1.0f, -1.12f, 0.0f, 0.262f, 0.658f, 1.0f, -1.119f, 0.0f, 0.266f, 0.663f, 1.0f, -1.118f, 0.0f, 0.269f, 0.668f, 1.0f,
+ -1.117f, 0.0f, 0.272f, 0.673f, 1.0f, -1.117f, 0.0f, 0.276f, 0.678f, 1.0f, -1.116f, 0.0f, 0.279f, 0.682f, 1.0f, -1.115f, 0.0f, 0.282f, 0.687f, 1.0f,
+ -1.113f, 0.0f, 0.285f, 0.692f, 1.0f, -1.112f, 0.0f, 0.289f, 0.697f, 1.0f, -1.111f, 0.0f, 0.292f, 0.702f, 1.0f, -1.11f, 0.0f, 0.294f, 0.708f, 1.0f,
+ -1.109f, 0.0f, 0.297f, 0.713f, 1.0f, -1.108f, 0.0f, 0.3f, 0.718f, 1.0f, -1.106f, 0.0f, 0.303f, 0.724f, 1.0f, -1.105f, 0.0f, 0.306f, 0.73f, 1.0f,
+ -1.104f, 0.0f, 0.309f, 0.735f, 1.0f, -1.102f, 0.0f, 0.312f, 0.741f, 1.0f, -1.101f, 0.0f, 0.315f, 0.746f, 1.0f, -1.099f, 0.0f, 0.318f, 0.751f, 1.0f,
+ -1.098f, 0.0f, 0.321f, 0.756f, 1.0f, -1.096f, 0.0f, 0.323f, 0.761f, 1.0f, -1.094f, 0.0f, 0.326f, 0.766f, 1.0f, -1.093f, 0.0f, 0.329f, 0.771f, 1.0f,
+ -1.091f, 0.0f, 0.332f, 0.776f, 1.0f, -1.089f, 0.0f, 0.335f, 0.781f, 1.0f, -1.087f, 0.0f, 0.338f, 0.786f, 1.0f, -1.085f, 0.0f, 0.341f, 0.791f, 1.0f,
+ -1.082f, 0.0f, 0.344f, 0.797f, 1.0f, -1.08f, 0.0f, 0.347f, 0.802f, 1.0f, -1.078f, 0.0f, 0.349f, 0.808f, 1.0f, -1.075f, 0.0f, 0.352f, 0.814f, 1.0f,
+ -1.072f, 0.0f, 0.355f, 0.82f, 1.0f, -1.069f, 0.0f, 0.358f, 0.826f, 1.0f, -1.066f, 0.0f, 0.36f, 0.831f, 1.0f, -1.063f, 0.0f, 0.363f, 0.837f, 1.0f,
+ -1.059f, 0.0f, 0.366f, 0.842f, 1.0f, -1.055f, 0.0f, 0.368f, 0.847f, 1.0f, -1.051f, 0.0f, 0.371f, 0.851f, 1.0f, -1.047f, 0.0f, 0.373f, 0.856f, 1.0f,
+ -1.042f, 0.0f, 0.375f, 0.86f, 1.0f, -1.037f, 0.0f, 0.378f, 0.863f, 1.0f, -1.031f, 0.0f, 0.38f, 0.866f, 1.0f, -1.026f, 0.0f, 0.382f, 0.869f, 1.0f,
+ -1.02f, 0.0f, 0.384f, 0.871f, 1.0f, -1.014f, 0.0f, 0.386f, 0.873f, 1.0f, -1.007f, 0.0f, 0.387f, 0.875f, 1.0f, -1.0f, 0.0f, 0.389f, 0.876f, 1.0f,
+ -0.994f, 0.0f, 0.39f, 0.877f, 1.0f, -0.987f, 0.0f, 0.392f, 0.878f, 1.0f, -0.979f, 0.0f, 0.393f, 0.879f, 1.0f, -0.972f, 0.0f, 0.394f, 0.88f, 1.0f,
+ -0.964f, 0.0f, 0.395f, 0.881f, 1.0f, -0.956f, 0.0f, 0.395f, 0.881f, 1.0f, -0.948f, 0.0f, 0.395f, 0.882f, 1.0f, -0.94f, 0.0f, 0.395f, 0.882f, 1.0f,
+ -0.932f, 0.0f, 0.395f, 0.883f, 1.0f, -0.923f, 0.0f, 0.394f, 0.883f, 1.0f, -0.915f, 0.0f, 0.393f, 0.883f, 1.0f, -0.906f, 0.0f, 0.391f, 0.883f, 1.0f,
+ -0.896f, 0.0f, 0.389f, 0.881f, 1.0f, -0.887f, 0.0f, 0.386f, 0.876f, 1.0f, -0.877f, 0.0f, 0.382f, 0.866f, 1.0f, -0.867f, 0.0f, 0.378f, 0.85f, 1.0f,
+ -0.857f, 0.0f, 0.373f, 0.828f, 1.0f, -0.848f, 0.0f, 0.368f, 0.799f, 1.0f, -0.838f, 0.0f, 0.363f, 0.764f, 1.0f, -0.829f, 0.0f, 0.357f, 0.723f, 1.0f,
+ -0.819f, 0.0f, 0.352f, 0.679f, 1.0f, -0.811f, 0.0f, 0.347f, 0.631f, 1.0f, -0.802f, 0.0f, 0.342f, 0.579f, 1.0f, -0.794f, 0.0f, 0.338f, 0.525f, 1.0f,
+ -0.786f, 0.0f, 0.333f, 0.469f, 1.0f, -0.779f, 0.0f, 0.329f, 0.412f, 1.0f, -0.772f, 0.0f, 0.325f, 0.351f, 1.0f, -0.766f, 0.0f, 0.321f, 0.3f, 1.0f,
+ -0.757f, 0.0f, 0.317f, 0.219f, 1.0f,
+};
+
+static const float data29[205 * GP_PRIM_DATABUF_SIZE] = {
+ 0.816f, 0.0f, 0.326f, 0.285f, 1.0f, 0.819f, 0.0f, 0.328f, 0.287f, 1.0f, 0.821f, 0.0f, 0.33f, 0.29f, 1.0f, 0.823f, 0.0f, 0.331f, 0.295f, 1.0f,
+ 0.825f, 0.0f, 0.333f, 0.304f, 1.0f, 0.828f, 0.0f, 0.335f, 0.315f, 1.0f, 0.83f, 0.0f, 0.337f, 0.328f, 1.0f, 0.833f, 0.0f, 0.339f, 0.341f, 1.0f,
+ 0.836f, 0.0f, 0.341f, 0.355f, 1.0f, 0.839f, 0.0f, 0.343f, 0.368f, 1.0f, 0.842f, 0.0f, 0.345f, 0.38f, 1.0f, 0.845f, 0.0f, 0.347f, 0.392f, 1.0f,
+ 0.848f, 0.0f, 0.349f, 0.402f, 1.0f, 0.851f, 0.0f, 0.351f, 0.412f, 1.0f, 0.854f, 0.0f, 0.352f, 0.421f, 1.0f, 0.857f, 0.0f, 0.354f, 0.429f, 1.0f,
+ 0.861f, 0.0f, 0.356f, 0.437f, 1.0f, 0.865f, 0.0f, 0.357f, 0.444f, 1.0f, 0.869f, 0.0f, 0.359f, 0.452f, 1.0f, 0.872f, 0.0f, 0.36f, 0.46f, 1.0f,
+ 0.876f, 0.0f, 0.361f, 0.47f, 1.0f, 0.881f, 0.0f, 0.363f, 0.481f, 1.0f, 0.885f, 0.0f, 0.364f, 0.491f, 1.0f, 0.889f, 0.0f, 0.365f, 0.501f, 1.0f,
+ 0.893f, 0.0f, 0.366f, 0.511f, 1.0f, 0.898f, 0.0f, 0.367f, 0.52f, 1.0f, 0.902f, 0.0f, 0.368f, 0.528f, 1.0f, 0.906f, 0.0f, 0.37f, 0.535f, 1.0f,
+ 0.911f, 0.0f, 0.371f, 0.542f, 1.0f, 0.915f, 0.0f, 0.372f, 0.548f, 1.0f, 0.92f, 0.0f, 0.373f, 0.554f, 1.0f, 0.924f, 0.0f, 0.374f, 0.559f, 1.0f,
+ 0.929f, 0.0f, 0.375f, 0.564f, 1.0f, 0.933f, 0.0f, 0.376f, 0.567f, 1.0f, 0.938f, 0.0f, 0.377f, 0.57f, 1.0f, 0.943f, 0.0f, 0.378f, 0.572f, 1.0f,
+ 0.947f, 0.0f, 0.378f, 0.574f, 1.0f, 0.952f, 0.0f, 0.379f, 0.576f, 1.0f, 0.956f, 0.0f, 0.38f, 0.577f, 1.0f, 0.961f, 0.0f, 0.38f, 0.579f, 1.0f,
+ 0.966f, 0.0f, 0.381f, 0.581f, 1.0f, 0.971f, 0.0f, 0.381f, 0.585f, 1.0f, 0.975f, 0.0f, 0.382f, 0.588f, 1.0f, 0.98f, 0.0f, 0.382f, 0.591f, 1.0f,
+ 0.985f, 0.0f, 0.382f, 0.595f, 1.0f, 0.989f, 0.0f, 0.382f, 0.597f, 1.0f, 0.994f, 0.0f, 0.382f, 0.6f, 1.0f, 0.999f, 0.0f, 0.382f, 0.603f, 1.0f,
+ 1.003f, 0.0f, 0.382f, 0.605f, 1.0f, 1.008f, 0.0f, 0.381f, 0.607f, 1.0f, 1.013f, 0.0f, 0.381f, 0.61f, 1.0f, 1.017f, 0.0f, 0.381f, 0.611f, 1.0f,
+ 1.021f, 0.0f, 0.381f, 0.613f, 1.0f, 1.025f, 0.0f, 0.38f, 0.613f, 1.0f, 1.029f, 0.0f, 0.38f, 0.614f, 1.0f, 1.033f, 0.0f, 0.379f, 0.614f, 1.0f,
+ 1.037f, 0.0f, 0.379f, 0.614f, 1.0f, 1.041f, 0.0f, 0.378f, 0.614f, 1.0f, 1.044f, 0.0f, 0.378f, 0.614f, 1.0f, 1.048f, 0.0f, 0.377f, 0.614f, 1.0f,
+ 1.051f, 0.0f, 0.376f, 0.613f, 1.0f, 1.054f, 0.0f, 0.375f, 0.612f, 1.0f, 1.057f, 0.0f, 0.374f, 0.611f, 1.0f, 1.06f, 0.0f, 0.373f, 0.61f, 1.0f,
+ 1.063f, 0.0f, 0.372f, 0.609f, 1.0f, 1.066f, 0.0f, 0.371f, 0.609f, 1.0f, 1.068f, 0.0f, 0.37f, 0.608f, 1.0f, 1.071f, 0.0f, 0.368f, 0.608f, 1.0f,
+ 1.073f, 0.0f, 0.367f, 0.608f, 1.0f, 1.076f, 0.0f, 0.365f, 0.608f, 1.0f, 1.078f, 0.0f, 0.364f, 0.607f, 1.0f, 1.081f, 0.0f, 0.362f, 0.607f, 1.0f,
+ 1.083f, 0.0f, 0.36f, 0.607f, 1.0f, 1.085f, 0.0f, 0.358f, 0.606f, 1.0f, 1.087f, 0.0f, 0.356f, 0.606f, 1.0f, 1.09f, 0.0f, 0.354f, 0.606f, 1.0f,
+ 1.092f, 0.0f, 0.352f, 0.606f, 1.0f, 1.094f, 0.0f, 0.35f, 0.606f, 1.0f, 1.096f, 0.0f, 0.348f, 0.606f, 1.0f, 1.097f, 0.0f, 0.346f, 0.606f, 1.0f,
+ 1.099f, 0.0f, 0.344f, 0.606f, 1.0f, 1.101f, 0.0f, 0.341f, 0.606f, 1.0f, 1.103f, 0.0f, 0.339f, 0.606f, 1.0f, 1.104f, 0.0f, 0.337f, 0.607f, 1.0f,
+ 1.106f, 0.0f, 0.335f, 0.607f, 1.0f, 1.108f, 0.0f, 0.332f, 0.607f, 1.0f, 1.109f, 0.0f, 0.33f, 0.608f, 1.0f, 1.111f, 0.0f, 0.327f, 0.608f, 1.0f,
+ 1.113f, 0.0f, 0.324f, 0.608f, 1.0f, 1.114f, 0.0f, 0.322f, 0.609f, 1.0f, 1.116f, 0.0f, 0.319f, 0.609f, 1.0f, 1.117f, 0.0f, 0.316f, 0.609f, 1.0f,
+ 1.118f, 0.0f, 0.313f, 0.609f, 1.0f, 1.12f, 0.0f, 0.31f, 0.609f, 1.0f, 1.121f, 0.0f, 0.307f, 0.609f, 1.0f, 1.123f, 0.0f, 0.304f, 0.608f, 1.0f,
+ 1.124f, 0.0f, 0.301f, 0.608f, 1.0f, 1.125f, 0.0f, 0.297f, 0.607f, 1.0f, 1.126f, 0.0f, 0.294f, 0.606f, 1.0f, 1.127f, 0.0f, 0.29f, 0.605f, 1.0f,
+ 1.129f, 0.0f, 0.287f, 0.603f, 1.0f, 1.13f, 0.0f, 0.283f, 0.601f, 1.0f, 1.131f, 0.0f, 0.279f, 0.599f, 1.0f, 1.132f, 0.0f, 0.276f, 0.597f, 1.0f,
+ 1.132f, 0.0f, 0.272f, 0.595f, 1.0f, 1.133f, 0.0f, 0.268f, 0.593f, 1.0f, 1.134f, 0.0f, 0.264f, 0.592f, 1.0f, 1.135f, 0.0f, 0.26f, 0.591f, 1.0f,
+ 1.135f, 0.0f, 0.256f, 0.59f, 1.0f, 1.136f, 0.0f, 0.252f, 0.589f, 1.0f, 1.136f, 0.0f, 0.248f, 0.588f, 1.0f, 1.137f, 0.0f, 0.244f, 0.587f, 1.0f,
+ 1.137f, 0.0f, 0.24f, 0.586f, 1.0f, 1.138f, 0.0f, 0.236f, 0.585f, 1.0f, 1.138f, 0.0f, 0.232f, 0.584f, 1.0f, 1.138f, 0.0f, 0.228f, 0.582f, 1.0f,
+ 1.138f, 0.0f, 0.224f, 0.581f, 1.0f, 1.138f, 0.0f, 0.22f, 0.579f, 1.0f, 1.138f, 0.0f, 0.216f, 0.578f, 1.0f, 1.138f, 0.0f, 0.212f, 0.576f, 1.0f,
+ 1.138f, 0.0f, 0.208f, 0.575f, 1.0f, 1.138f, 0.0f, 0.204f, 0.573f, 1.0f, 1.137f, 0.0f, 0.2f, 0.572f, 1.0f, 1.137f, 0.0f, 0.196f, 0.571f, 1.0f,
+ 1.137f, 0.0f, 0.192f, 0.569f, 1.0f, 1.136f, 0.0f, 0.188f, 0.568f, 1.0f, 1.136f, 0.0f, 0.184f, 0.567f, 1.0f, 1.135f, 0.0f, 0.18f, 0.566f, 1.0f,
+ 1.134f, 0.0f, 0.176f, 0.565f, 1.0f, 1.133f, 0.0f, 0.172f, 0.563f, 1.0f, 1.132f, 0.0f, 0.168f, 0.561f, 1.0f, 1.131f, 0.0f, 0.164f, 0.559f, 1.0f,
+ 1.13f, 0.0f, 0.16f, 0.556f, 1.0f, 1.129f, 0.0f, 0.156f, 0.552f, 1.0f, 1.128f, 0.0f, 0.152f, 0.548f, 1.0f, 1.127f, 0.0f, 0.148f, 0.543f, 1.0f,
+ 1.126f, 0.0f, 0.144f, 0.537f, 1.0f, 1.124f, 0.0f, 0.14f, 0.53f, 1.0f, 1.123f, 0.0f, 0.136f, 0.522f, 1.0f, 1.122f, 0.0f, 0.132f, 0.514f, 1.0f,
+ 1.12f, 0.0f, 0.128f, 0.505f, 1.0f, 1.118f, 0.0f, 0.123f, 0.495f, 1.0f, 1.117f, 0.0f, 0.119f, 0.486f, 1.0f, 1.115f, 0.0f, 0.115f, 0.476f, 1.0f,
+ 1.113f, 0.0f, 0.111f, 0.466f, 1.0f, 1.111f, 0.0f, 0.107f, 0.456f, 1.0f, 1.11f, 0.0f, 0.102f, 0.446f, 1.0f, 1.108f, 0.0f, 0.098f, 0.436f, 1.0f,
+ 1.105f, 0.0f, 0.094f, 0.425f, 1.0f, 1.103f, 0.0f, 0.09f, 0.414f, 1.0f, 1.101f, 0.0f, 0.085f, 0.402f, 1.0f, 1.099f, 0.0f, 0.081f, 0.389f, 1.0f,
+ 1.096f, 0.0f, 0.077f, 0.377f, 1.0f, 1.094f, 0.0f, 0.072f, 0.364f, 1.0f, 1.091f, 0.0f, 0.068f, 0.351f, 1.0f, 1.088f, 0.0f, 0.063f, 0.338f, 1.0f,
+ 1.085f, 0.0f, 0.059f, 0.325f, 1.0f, 1.082f, 0.0f, 0.054f, 0.313f, 1.0f, 1.079f, 0.0f, 0.05f, 0.301f, 1.0f, 1.075f, 0.0f, 0.045f, 0.29f, 1.0f,
+ 1.071f, 0.0f, 0.04f, 0.281f, 1.0f, 1.067f, 0.0f, 0.035f, 0.272f, 1.0f, 1.063f, 0.0f, 0.031f, 0.266f, 1.0f, 1.059f, 0.0f, 0.026f, 0.261f, 1.0f,
+ 1.054f, 0.0f, 0.021f, 0.258f, 1.0f, 1.049f, 0.0f, 0.016f, 0.257f, 1.0f, 1.043f, 0.0f, 0.011f, 0.259f, 1.0f, 1.037f, 0.0f, 0.006f, 0.264f, 1.0f,
+ 1.031f, 0.0f, 0.0f, 0.272f, 1.0f, 1.025f, 0.0f, -0.005f, 0.283f, 1.0f, 1.018f, 0.0f, -0.01f, 0.296f, 1.0f, 1.011f, 0.0f, -0.015f, 0.313f, 1.0f,
+ 1.003f, 0.0f, -0.021f, 0.33f, 1.0f, 0.996f, 0.0f, -0.026f, 0.348f, 1.0f, 0.988f, 0.0f, -0.032f, 0.365f, 1.0f, 0.979f, 0.0f, -0.038f, 0.379f, 1.0f,
+ 0.971f, 0.0f, -0.044f, 0.389f, 1.0f, 0.962f, 0.0f, -0.05f, 0.394f, 1.0f, 0.953f, 0.0f, -0.057f, 0.392f, 1.0f, 0.944f, 0.0f, -0.063f, 0.384f, 1.0f,
+ 0.934f, 0.0f, -0.069f, 0.368f, 1.0f, 0.924f, 0.0f, -0.075f, 0.347f, 1.0f, 0.914f, 0.0f, -0.081f, 0.32f, 1.0f, 0.903f, 0.0f, -0.087f, 0.289f, 1.0f,
+ 0.893f, 0.0f, -0.092f, 0.256f, 1.0f, 0.882f, 0.0f, -0.098f, 0.223f, 1.0f, 0.871f, 0.0f, -0.103f, 0.191f, 1.0f, 0.86f, 0.0f, -0.108f, 0.162f, 1.0f,
+ 0.849f, 0.0f, -0.112f, 0.136f, 1.0f, 0.838f, 0.0f, -0.117f, 0.112f, 1.0f, 0.827f, 0.0f, -0.121f, 0.091f, 1.0f, 0.815f, 0.0f, -0.125f, 0.074f, 1.0f,
+ 0.804f, 0.0f, -0.128f, 0.059f, 1.0f, 0.793f, 0.0f, -0.132f, 0.046f, 1.0f, 0.782f, 0.0f, -0.135f, 0.036f, 1.0f, 0.771f, 0.0f, -0.138f, 0.028f, 1.0f,
+ 0.76f, 0.0f, -0.141f, 0.021f, 1.0f, 0.749f, 0.0f, -0.144f, 0.016f, 1.0f, 0.738f, 0.0f, -0.147f, 0.012f, 1.0f, 0.728f, 0.0f, -0.149f, 0.009f, 1.0f,
+ 0.718f, 0.0f, -0.152f, 0.006f, 1.0f, 0.708f, 0.0f, -0.154f, 0.004f, 1.0f, 0.699f, 0.0f, -0.157f, 0.003f, 1.0f, 0.691f, 0.0f, -0.159f, 0.002f, 1.0f,
+ 0.68f, 0.0f, -0.162f, 0.0f, 1.0f,
+};
+
+static const float data30[33 * GP_PRIM_DATABUF_SIZE] = {
+ -1.02f, 0.0f, 0.179f, 0.21f, 1.0f, -1.014f, 0.0f, 0.182f, 0.301f, 1.0f, -1.01f, 0.0f, 0.184f, 0.36f, 1.0f, -1.004f, 0.0f, 0.186f, 0.426f, 1.0f,
+ -0.999f, 0.0f, 0.188f, 0.479f, 1.0f, -0.993f, 0.0f, 0.19f, 0.519f, 1.0f, -0.987f, 0.0f, 0.191f, 0.545f, 1.0f, -0.981f, 0.0f, 0.192f, 0.562f, 1.0f,
+ -0.975f, 0.0f, 0.193f, 0.575f, 1.0f, -0.968f, 0.0f, 0.193f, 0.582f, 1.0f, -0.961f, 0.0f, 0.193f, 0.587f, 1.0f, -0.954f, 0.0f, 0.191f, 0.592f, 1.0f,
+ -0.946f, 0.0f, 0.19f, 0.597f, 1.0f, -0.938f, 0.0f, 0.187f, 0.6f, 1.0f, -0.93f, 0.0f, 0.183f, 0.603f, 1.0f, -0.922f, 0.0f, 0.178f, 0.606f, 1.0f,
+ -0.913f, 0.0f, 0.173f, 0.608f, 1.0f, -0.905f, 0.0f, 0.168f, 0.61f, 1.0f, -0.898f, 0.0f, 0.162f, 0.612f, 1.0f, -0.89f, 0.0f, 0.156f, 0.613f, 1.0f,
+ -0.883f, 0.0f, 0.15f, 0.612f, 1.0f, -0.877f, 0.0f, 0.143f, 0.608f, 1.0f, -0.871f, 0.0f, 0.137f, 0.602f, 1.0f, -0.865f, 0.0f, 0.131f, 0.593f, 1.0f,
+ -0.86f, 0.0f, 0.125f, 0.577f, 1.0f, -0.855f, 0.0f, 0.12f, 0.554f, 1.0f, -0.85f, 0.0f, 0.114f, 0.524f, 1.0f, -0.846f, 0.0f, 0.109f, 0.487f, 1.0f,
+ -0.842f, 0.0f, 0.104f, 0.443f, 1.0f, -0.838f, 0.0f, 0.1f, 0.394f, 1.0f, -0.835f, 0.0f, 0.095f, 0.339f, 1.0f, -0.832f, 0.0f, 0.091f, 0.295f, 1.0f,
+ -0.828f, 0.0f, 0.086f, 0.227f, 1.0f,
+};
+
+static const float data31[37 * GP_PRIM_DATABUF_SIZE] = {
+ 0.777f, 0.0f, 0.096f, 0.278f, 1.0f, 0.779f, 0.0f, 0.1f, 0.307f, 1.0f, 0.781f, 0.0f, 0.103f, 0.326f, 1.0f, 0.782f, 0.0f, 0.106f, 0.349f, 1.0f,
+ 0.784f, 0.0f, 0.109f, 0.372f, 1.0f, 0.786f, 0.0f, 0.112f, 0.395f, 1.0f, 0.789f, 0.0f, 0.116f, 0.418f, 1.0f, 0.791f, 0.0f, 0.119f, 0.44f, 1.0f,
+ 0.794f, 0.0f, 0.123f, 0.462f, 1.0f, 0.798f, 0.0f, 0.127f, 0.484f, 1.0f, 0.801f, 0.0f, 0.13f, 0.504f, 1.0f, 0.806f, 0.0f, 0.134f, 0.522f, 1.0f,
+ 0.81f, 0.0f, 0.138f, 0.54f, 1.0f, 0.815f, 0.0f, 0.142f, 0.556f, 1.0f, 0.82f, 0.0f, 0.146f, 0.571f, 1.0f, 0.826f, 0.0f, 0.15f, 0.584f, 1.0f,
+ 0.832f, 0.0f, 0.154f, 0.596f, 1.0f, 0.839f, 0.0f, 0.159f, 0.607f, 1.0f, 0.846f, 0.0f, 0.163f, 0.616f, 1.0f, 0.854f, 0.0f, 0.166f, 0.623f, 1.0f,
+ 0.862f, 0.0f, 0.17f, 0.628f, 1.0f, 0.87f, 0.0f, 0.174f, 0.632f, 1.0f, 0.878f, 0.0f, 0.177f, 0.632f, 1.0f, 0.887f, 0.0f, 0.18f, 0.63f, 1.0f,
+ 0.895f, 0.0f, 0.183f, 0.623f, 1.0f, 0.903f, 0.0f, 0.186f, 0.611f, 1.0f, 0.912f, 0.0f, 0.188f, 0.592f, 1.0f, 0.92f, 0.0f, 0.19f, 0.567f, 1.0f,
+ 0.928f, 0.0f, 0.192f, 0.533f, 1.0f, 0.935f, 0.0f, 0.193f, 0.492f, 1.0f, 0.943f, 0.0f, 0.194f, 0.442f, 1.0f, 0.95f, 0.0f, 0.196f, 0.385f, 1.0f,
+ 0.957f, 0.0f, 0.197f, 0.321f, 1.0f, 0.963f, 0.0f, 0.197f, 0.253f, 1.0f, 0.97f, 0.0f, 0.198f, 0.175f, 1.0f, 0.975f, 0.0f, 0.199f, 0.107f, 1.0f,
+ 0.983f, 0.0f, 0.199f, 0.0f, 1.0f,
+};
+
+static const float data32[201 * GP_PRIM_DATABUF_SIZE] = {
+ -0.437f, 0.0f, 0.508f, 0.0f, 1.0f, -0.435f, 0.0f, 0.51f, 0.0f, 1.0f, -0.434f, 0.0f, 0.511f, 0.0f, 1.0f, -0.432f, 0.0f, 0.512f, 0.0f, 1.0f,
+ -0.43f, 0.0f, 0.513f, 0.0f, 1.0f, -0.428f, 0.0f, 0.514f, 0.001f, 1.0f, -0.426f, 0.0f, 0.515f, 0.002f, 1.0f, -0.424f, 0.0f, 0.517f, 0.004f, 1.0f,
+ -0.422f, 0.0f, 0.518f, 0.007f, 1.0f, -0.42f, 0.0f, 0.519f, 0.012f, 1.0f, -0.418f, 0.0f, 0.521f, 0.018f, 1.0f, -0.416f, 0.0f, 0.522f, 0.025f, 1.0f,
+ -0.414f, 0.0f, 0.523f, 0.034f, 1.0f, -0.411f, 0.0f, 0.525f, 0.043f, 1.0f, -0.409f, 0.0f, 0.526f, 0.053f, 1.0f, -0.407f, 0.0f, 0.528f, 0.063f, 1.0f,
+ -0.404f, 0.0f, 0.529f, 0.073f, 1.0f, -0.402f, 0.0f, 0.531f, 0.083f, 1.0f, -0.399f, 0.0f, 0.532f, 0.092f, 1.0f, -0.396f, 0.0f, 0.534f, 0.101f, 1.0f,
+ -0.394f, 0.0f, 0.535f, 0.11f, 1.0f, -0.391f, 0.0f, 0.536f, 0.118f, 1.0f, -0.388f, 0.0f, 0.538f, 0.126f, 1.0f, -0.386f, 0.0f, 0.539f, 0.133f, 1.0f,
+ -0.383f, 0.0f, 0.54f, 0.14f, 1.0f, -0.38f, 0.0f, 0.542f, 0.147f, 1.0f, -0.377f, 0.0f, 0.543f, 0.153f, 1.0f, -0.374f, 0.0f, 0.544f, 0.159f, 1.0f,
+ -0.37f, 0.0f, 0.545f, 0.166f, 1.0f, -0.367f, 0.0f, 0.546f, 0.172f, 1.0f, -0.364f, 0.0f, 0.547f, 0.179f, 1.0f, -0.361f, 0.0f, 0.548f, 0.186f, 1.0f,
+ -0.357f, 0.0f, 0.549f, 0.193f, 1.0f, -0.354f, 0.0f, 0.55f, 0.202f, 1.0f, -0.35f, 0.0f, 0.551f, 0.211f, 1.0f, -0.347f, 0.0f, 0.552f, 0.221f, 1.0f,
+ -0.343f, 0.0f, 0.552f, 0.233f, 1.0f, -0.339f, 0.0f, 0.553f, 0.245f, 1.0f, -0.336f, 0.0f, 0.553f, 0.258f, 1.0f, -0.332f, 0.0f, 0.554f, 0.272f, 1.0f,
+ -0.328f, 0.0f, 0.554f, 0.286f, 1.0f, -0.324f, 0.0f, 0.554f, 0.301f, 1.0f, -0.321f, 0.0f, 0.555f, 0.317f, 1.0f, -0.317f, 0.0f, 0.555f, 0.332f, 1.0f,
+ -0.313f, 0.0f, 0.555f, 0.348f, 1.0f, -0.309f, 0.0f, 0.555f, 0.364f, 1.0f, -0.305f, 0.0f, 0.555f, 0.38f, 1.0f, -0.302f, 0.0f, 0.555f, 0.396f, 1.0f,
+ -0.298f, 0.0f, 0.555f, 0.411f, 1.0f, -0.294f, 0.0f, 0.555f, 0.426f, 1.0f, -0.29f, 0.0f, 0.554f, 0.44f, 1.0f, -0.287f, 0.0f, 0.554f, 0.454f, 1.0f,
+ -0.283f, 0.0f, 0.554f, 0.467f, 1.0f, -0.28f, 0.0f, 0.553f, 0.479f, 1.0f, -0.276f, 0.0f, 0.553f, 0.49f, 1.0f, -0.273f, 0.0f, 0.552f, 0.5f, 1.0f,
+ -0.269f, 0.0f, 0.552f, 0.51f, 1.0f, -0.266f, 0.0f, 0.551f, 0.519f, 1.0f, -0.263f, 0.0f, 0.55f, 0.527f, 1.0f, -0.26f, 0.0f, 0.549f, 0.534f, 1.0f,
+ -0.256f, 0.0f, 0.549f, 0.541f, 1.0f, -0.253f, 0.0f, 0.548f, 0.547f, 1.0f, -0.25f, 0.0f, 0.547f, 0.552f, 1.0f, -0.247f, 0.0f, 0.546f, 0.557f, 1.0f,
+ -0.244f, 0.0f, 0.545f, 0.561f, 1.0f, -0.241f, 0.0f, 0.544f, 0.564f, 1.0f, -0.238f, 0.0f, 0.543f, 0.567f, 1.0f, -0.235f, 0.0f, 0.542f, 0.57f, 1.0f,
+ -0.233f, 0.0f, 0.541f, 0.572f, 1.0f, -0.23f, 0.0f, 0.54f, 0.574f, 1.0f, -0.227f, 0.0f, 0.539f, 0.575f, 1.0f, -0.224f, 0.0f, 0.538f, 0.576f, 1.0f,
+ -0.221f, 0.0f, 0.537f, 0.577f, 1.0f, -0.219f, 0.0f, 0.535f, 0.578f, 1.0f, -0.216f, 0.0f, 0.534f, 0.578f, 1.0f, -0.213f, 0.0f, 0.533f, 0.579f, 1.0f,
+ -0.211f, 0.0f, 0.532f, 0.579f, 1.0f, -0.208f, 0.0f, 0.53f, 0.579f, 1.0f, -0.206f, 0.0f, 0.529f, 0.578f, 1.0f, -0.203f, 0.0f, 0.528f, 0.578f, 1.0f,
+ -0.2f, 0.0f, 0.526f, 0.577f, 1.0f, -0.198f, 0.0f, 0.525f, 0.576f, 1.0f, -0.195f, 0.0f, 0.523f, 0.575f, 1.0f, -0.193f, 0.0f, 0.522f, 0.574f, 1.0f,
+ -0.19f, 0.0f, 0.52f, 0.572f, 1.0f, -0.188f, 0.0f, 0.518f, 0.571f, 1.0f, -0.185f, 0.0f, 0.517f, 0.569f, 1.0f, -0.182f, 0.0f, 0.515f, 0.568f, 1.0f,
+ -0.18f, 0.0f, 0.513f, 0.567f, 1.0f, -0.177f, 0.0f, 0.512f, 0.565f, 1.0f, -0.174f, 0.0f, 0.51f, 0.564f, 1.0f, -0.172f, 0.0f, 0.508f, 0.562f, 1.0f,
+ -0.169f, 0.0f, 0.506f, 0.56f, 1.0f, -0.166f, 0.0f, 0.504f, 0.559f, 1.0f, -0.164f, 0.0f, 0.502f, 0.556f, 1.0f, -0.161f, 0.0f, 0.501f, 0.554f, 1.0f,
+ -0.158f, 0.0f, 0.499f, 0.552f, 1.0f, -0.155f, 0.0f, 0.497f, 0.55f, 1.0f, -0.153f, 0.0f, 0.495f, 0.547f, 1.0f, -0.15f, 0.0f, 0.493f, 0.545f, 1.0f,
+ -0.147f, 0.0f, 0.491f, 0.543f, 1.0f, -0.144f, 0.0f, 0.489f, 0.54f, 1.0f, -0.142f, 0.0f, 0.487f, 0.538f, 1.0f, -0.139f, 0.0f, 0.485f, 0.536f, 1.0f,
+ -0.136f, 0.0f, 0.483f, 0.533f, 1.0f, -0.133f, 0.0f, 0.481f, 0.53f, 1.0f, -0.13f, 0.0f, 0.479f, 0.527f, 1.0f, -0.127f, 0.0f, 0.477f, 0.524f, 1.0f,
+ -0.124f, 0.0f, 0.475f, 0.521f, 1.0f, -0.121f, 0.0f, 0.473f, 0.519f, 1.0f, -0.118f, 0.0f, 0.471f, 0.516f, 1.0f, -0.115f, 0.0f, 0.469f, 0.514f, 1.0f,
+ -0.112f, 0.0f, 0.467f, 0.511f, 1.0f, -0.109f, 0.0f, 0.465f, 0.509f, 1.0f, -0.106f, 0.0f, 0.463f, 0.506f, 1.0f, -0.103f, 0.0f, 0.461f, 0.503f, 1.0f,
+ -0.099f, 0.0f, 0.458f, 0.501f, 1.0f, -0.096f, 0.0f, 0.456f, 0.5f, 1.0f, -0.093f, 0.0f, 0.454f, 0.498f, 1.0f, -0.09f, 0.0f, 0.452f, 0.497f, 1.0f,
+ -0.086f, 0.0f, 0.45f, 0.496f, 1.0f, -0.083f, 0.0f, 0.448f, 0.496f, 1.0f, -0.079f, 0.0f, 0.446f, 0.495f, 1.0f, -0.076f, 0.0f, 0.444f, 0.495f, 1.0f,
+ -0.072f, 0.0f, 0.442f, 0.494f, 1.0f, -0.069f, 0.0f, 0.44f, 0.494f, 1.0f, -0.065f, 0.0f, 0.438f, 0.494f, 1.0f, -0.062f, 0.0f, 0.436f, 0.494f, 1.0f,
+ -0.058f, 0.0f, 0.435f, 0.494f, 1.0f, -0.054f, 0.0f, 0.433f, 0.494f, 1.0f, -0.05f, 0.0f, 0.431f, 0.494f, 1.0f, -0.046f, 0.0f, 0.43f, 0.494f, 1.0f,
+ -0.042f, 0.0f, 0.428f, 0.494f, 1.0f, -0.038f, 0.0f, 0.427f, 0.494f, 1.0f, -0.033f, 0.0f, 0.426f, 0.494f, 1.0f, -0.029f, 0.0f, 0.425f, 0.494f, 1.0f,
+ -0.025f, 0.0f, 0.424f, 0.494f, 1.0f, -0.02f, 0.0f, 0.423f, 0.494f, 1.0f, -0.015f, 0.0f, 0.422f, 0.494f, 1.0f, -0.011f, 0.0f, 0.422f, 0.494f, 1.0f,
+ -0.006f, 0.0f, 0.421f, 0.494f, 1.0f, -0.001f, 0.0f, 0.421f, 0.495f, 1.0f, 0.004f, 0.0f, 0.421f, 0.495f, 1.0f, 0.009f, 0.0f, 0.421f, 0.495f, 1.0f,
+ 0.014f, 0.0f, 0.422f, 0.495f, 1.0f, 0.019f, 0.0f, 0.422f, 0.495f, 1.0f, 0.024f, 0.0f, 0.423f, 0.495f, 1.0f, 0.029f, 0.0f, 0.424f, 0.495f, 1.0f,
+ 0.034f, 0.0f, 0.426f, 0.495f, 1.0f, 0.039f, 0.0f, 0.427f, 0.495f, 1.0f, 0.044f, 0.0f, 0.429f, 0.496f, 1.0f, 0.049f, 0.0f, 0.43f, 0.497f, 1.0f,
+ 0.054f, 0.0f, 0.432f, 0.498f, 1.0f, 0.059f, 0.0f, 0.435f, 0.5f, 1.0f, 0.064f, 0.0f, 0.438f, 0.502f, 1.0f, 0.069f, 0.0f, 0.44f, 0.506f, 1.0f,
+ 0.074f, 0.0f, 0.443f, 0.51f, 1.0f, 0.08f, 0.0f, 0.446f, 0.516f, 1.0f, 0.085f, 0.0f, 0.45f, 0.522f, 1.0f, 0.09f, 0.0f, 0.453f, 0.528f, 1.0f,
+ 0.095f, 0.0f, 0.456f, 0.533f, 1.0f, 0.101f, 0.0f, 0.46f, 0.537f, 1.0f, 0.107f, 0.0f, 0.463f, 0.539f, 1.0f, 0.112f, 0.0f, 0.467f, 0.542f, 1.0f,
+ 0.118f, 0.0f, 0.471f, 0.543f, 1.0f, 0.124f, 0.0f, 0.475f, 0.545f, 1.0f, 0.13f, 0.0f, 0.478f, 0.546f, 1.0f, 0.137f, 0.0f, 0.482f, 0.546f, 1.0f,
+ 0.143f, 0.0f, 0.486f, 0.547f, 1.0f, 0.149f, 0.0f, 0.49f, 0.546f, 1.0f, 0.156f, 0.0f, 0.493f, 0.544f, 1.0f, 0.163f, 0.0f, 0.497f, 0.54f, 1.0f,
+ 0.17f, 0.0f, 0.5f, 0.533f, 1.0f, 0.176f, 0.0f, 0.503f, 0.525f, 1.0f, 0.183f, 0.0f, 0.507f, 0.515f, 1.0f, 0.191f, 0.0f, 0.509f, 0.503f, 1.0f,
+ 0.198f, 0.0f, 0.512f, 0.491f, 1.0f, 0.205f, 0.0f, 0.515f, 0.477f, 1.0f, 0.214f, 0.0f, 0.518f, 0.462f, 1.0f, 0.222f, 0.0f, 0.521f, 0.445f, 1.0f,
+ 0.23f, 0.0f, 0.524f, 0.427f, 1.0f, 0.238f, 0.0f, 0.527f, 0.409f, 1.0f, 0.245f, 0.0f, 0.529f, 0.388f, 1.0f, 0.254f, 0.0f, 0.531f, 0.366f, 1.0f,
+ 0.262f, 0.0f, 0.532f, 0.343f, 1.0f, 0.272f, 0.0f, 0.533f, 0.317f, 1.0f, 0.282f, 0.0f, 0.534f, 0.289f, 1.0f, 0.292f, 0.0f, 0.535f, 0.258f, 1.0f,
+ 0.301f, 0.0f, 0.535f, 0.224f, 1.0f, 0.311f, 0.0f, 0.536f, 0.189f, 1.0f, 0.32f, 0.0f, 0.536f, 0.153f, 1.0f, 0.328f, 0.0f, 0.536f, 0.117f, 1.0f,
+ 0.338f, 0.0f, 0.537f, 0.084f, 1.0f, 0.346f, 0.0f, 0.537f, 0.057f, 1.0f, 0.353f, 0.0f, 0.536f, 0.037f, 1.0f, 0.361f, 0.0f, 0.536f, 0.022f, 1.0f,
+ 0.37f, 0.0f, 0.537f, 0.013f, 1.0f, 0.376f, 0.0f, 0.536f, 0.007f, 1.0f, 0.384f, 0.0f, 0.536f, 0.004f, 1.0f, 0.39f, 0.0f, 0.536f, 0.002f, 1.0f,
+ 0.399f, 0.0f, 0.535f, 0.0f, 1.0f,
+};
+
+static const float data33[69 * GP_PRIM_DATABUF_SIZE] = {
+ -0.308f, 0.0f, 0.151f, 0.363f, 1.0f, -0.31f, 0.0f, 0.15f, 0.377f, 1.0f, -0.311f, 0.0f, 0.149f, 0.386f, 1.0f, -0.313f, 0.0f, 0.149f, 0.397f, 1.0f,
+ -0.314f, 0.0f, 0.149f, 0.408f, 1.0f, -0.316f, 0.0f, 0.148f, 0.42f, 1.0f, -0.318f, 0.0f, 0.148f, 0.431f, 1.0f, -0.32f, 0.0f, 0.148f, 0.443f, 1.0f,
+ -0.322f, 0.0f, 0.148f, 0.455f, 1.0f, -0.325f, 0.0f, 0.149f, 0.467f, 1.0f, -0.327f, 0.0f, 0.149f, 0.478f, 1.0f, -0.33f, 0.0f, 0.151f, 0.49f, 1.0f,
+ -0.333f, 0.0f, 0.152f, 0.501f, 1.0f, -0.336f, 0.0f, 0.154f, 0.512f, 1.0f, -0.34f, 0.0f, 0.157f, 0.522f, 1.0f, -0.343f, 0.0f, 0.161f, 0.533f, 1.0f,
+ -0.346f, 0.0f, 0.166f, 0.543f, 1.0f, -0.349f, 0.0f, 0.171f, 0.553f, 1.0f, -0.351f, 0.0f, 0.178f, 0.563f, 1.0f, -0.352f, 0.0f, 0.186f, 0.572f, 1.0f,
+ -0.353f, 0.0f, 0.193f, 0.582f, 1.0f, -0.352f, 0.0f, 0.2f, 0.591f, 1.0f, -0.351f, 0.0f, 0.206f, 0.6f, 1.0f, -0.349f, 0.0f, 0.211f, 0.608f, 1.0f,
+ -0.347f, 0.0f, 0.215f, 0.616f, 1.0f, -0.345f, 0.0f, 0.219f, 0.623f, 1.0f, -0.343f, 0.0f, 0.222f, 0.63f, 1.0f, -0.341f, 0.0f, 0.224f, 0.637f, 1.0f,
+ -0.339f, 0.0f, 0.226f, 0.642f, 1.0f, -0.337f, 0.0f, 0.228f, 0.647f, 1.0f, -0.335f, 0.0f, 0.229f, 0.652f, 1.0f, -0.333f, 0.0f, 0.23f, 0.656f, 1.0f,
+ -0.332f, 0.0f, 0.231f, 0.66f, 1.0f, -0.33f, 0.0f, 0.232f, 0.663f, 1.0f, -0.328f, 0.0f, 0.232f, 0.666f, 1.0f, -0.327f, 0.0f, 0.233f, 0.669f, 1.0f,
+ -0.325f, 0.0f, 0.233f, 0.672f, 1.0f, -0.324f, 0.0f, 0.234f, 0.676f, 1.0f, -0.322f, 0.0f, 0.234f, 0.679f, 1.0f, -0.321f, 0.0f, 0.234f, 0.682f, 1.0f,
+ -0.319f, 0.0f, 0.234f, 0.686f, 1.0f, -0.317f, 0.0f, 0.234f, 0.689f, 1.0f, -0.316f, 0.0f, 0.234f, 0.693f, 1.0f, -0.314f, 0.0f, 0.234f, 0.697f, 1.0f,
+ -0.312f, 0.0f, 0.233f, 0.701f, 1.0f, -0.31f, 0.0f, 0.232f, 0.705f, 1.0f, -0.307f, 0.0f, 0.231f, 0.709f, 1.0f, -0.305f, 0.0f, 0.23f, 0.713f, 1.0f,
+ -0.302f, 0.0f, 0.228f, 0.716f, 1.0f, -0.299f, 0.0f, 0.225f, 0.719f, 1.0f, -0.295f, 0.0f, 0.222f, 0.722f, 1.0f, -0.292f, 0.0f, 0.217f, 0.725f, 1.0f,
+ -0.289f, 0.0f, 0.21f, 0.727f, 1.0f, -0.287f, 0.0f, 0.202f, 0.728f, 1.0f, -0.285f, 0.0f, 0.194f, 0.729f, 1.0f, -0.286f, 0.0f, 0.185f, 0.729f, 1.0f,
+ -0.287f, 0.0f, 0.178f, 0.728f, 1.0f, -0.289f, 0.0f, 0.171f, 0.726f, 1.0f, -0.292f, 0.0f, 0.166f, 0.723f, 1.0f, -0.294f, 0.0f, 0.162f, 0.717f, 1.0f,
+ -0.297f, 0.0f, 0.159f, 0.71f, 1.0f, -0.299f, 0.0f, 0.157f, 0.701f, 1.0f, -0.301f, 0.0f, 0.155f, 0.689f, 1.0f, -0.303f, 0.0f, 0.154f, 0.675f, 1.0f,
+ -0.305f, 0.0f, 0.152f, 0.659f, 1.0f, -0.306f, 0.0f, 0.151f, 0.641f, 1.0f, -0.308f, 0.0f, 0.151f, 0.62f, 1.0f, -0.309f, 0.0f, 0.15f, 0.602f, 1.0f,
+ -0.31f, 0.0f, 0.15f, 0.572f, 1.0f,
+};
+
+static const float data34[57 * GP_PRIM_DATABUF_SIZE] = {
+ 0.302f, 0.0f, 0.166f, 0.25f, 1.0f, 0.301f, 0.0f, 0.167f, 0.319f, 1.0f, 0.3f, 0.0f, 0.167f, 0.363f, 1.0f, 0.299f, 0.0f, 0.167f, 0.414f, 1.0f,
+ 0.298f, 0.0f, 0.167f, 0.459f, 1.0f, 0.296f, 0.0f, 0.168f, 0.501f, 1.0f, 0.295f, 0.0f, 0.168f, 0.539f, 1.0f, 0.293f, 0.0f, 0.169f, 0.573f, 1.0f,
+ 0.291f, 0.0f, 0.17f, 0.603f, 1.0f, 0.289f, 0.0f, 0.171f, 0.629f, 1.0f, 0.286f, 0.0f, 0.173f, 0.652f, 1.0f, 0.283f, 0.0f, 0.176f, 0.672f, 1.0f,
+ 0.279f, 0.0f, 0.18f, 0.69f, 1.0f, 0.276f, 0.0f, 0.186f, 0.705f, 1.0f, 0.272f, 0.0f, 0.195f, 0.719f, 1.0f, 0.271f, 0.0f, 0.205f, 0.73f, 1.0f,
+ 0.272f, 0.0f, 0.217f, 0.741f, 1.0f, 0.275f, 0.0f, 0.227f, 0.75f, 1.0f, 0.279f, 0.0f, 0.234f, 0.758f, 1.0f, 0.283f, 0.0f, 0.24f, 0.765f, 1.0f,
+ 0.287f, 0.0f, 0.243f, 0.771f, 1.0f, 0.291f, 0.0f, 0.245f, 0.776f, 1.0f, 0.294f, 0.0f, 0.247f, 0.781f, 1.0f, 0.296f, 0.0f, 0.248f, 0.785f, 1.0f,
+ 0.299f, 0.0f, 0.249f, 0.789f, 1.0f, 0.301f, 0.0f, 0.249f, 0.793f, 1.0f, 0.303f, 0.0f, 0.249f, 0.796f, 1.0f, 0.305f, 0.0f, 0.25f, 0.799f, 1.0f,
+ 0.306f, 0.0f, 0.25f, 0.802f, 1.0f, 0.308f, 0.0f, 0.249f, 0.805f, 1.0f, 0.31f, 0.0f, 0.249f, 0.808f, 1.0f, 0.311f, 0.0f, 0.249f, 0.81f, 1.0f,
+ 0.313f, 0.0f, 0.249f, 0.813f, 1.0f, 0.314f, 0.0f, 0.248f, 0.816f, 1.0f, 0.316f, 0.0f, 0.248f, 0.819f, 1.0f, 0.317f, 0.0f, 0.247f, 0.822f, 1.0f,
+ 0.319f, 0.0f, 0.246f, 0.825f, 1.0f, 0.321f, 0.0f, 0.245f, 0.828f, 1.0f, 0.323f, 0.0f, 0.244f, 0.832f, 1.0f, 0.325f, 0.0f, 0.243f, 0.835f, 1.0f,
+ 0.328f, 0.0f, 0.24f, 0.838f, 1.0f, 0.33f, 0.0f, 0.237f, 0.841f, 1.0f, 0.333f, 0.0f, 0.233f, 0.844f, 1.0f, 0.337f, 0.0f, 0.228f, 0.847f, 1.0f,
+ 0.339f, 0.0f, 0.219f, 0.849f, 1.0f, 0.341f, 0.0f, 0.209f, 0.852f, 1.0f, 0.34f, 0.0f, 0.197f, 0.854f, 1.0f, 0.336f, 0.0f, 0.186f, 0.856f, 1.0f,
+ 0.331f, 0.0f, 0.178f, 0.858f, 1.0f, 0.325f, 0.0f, 0.173f, 0.86f, 1.0f, 0.321f, 0.0f, 0.17f, 0.861f, 1.0f, 0.318f, 0.0f, 0.169f, 0.862f, 1.0f,
+ 0.315f, 0.0f, 0.168f, 0.864f, 1.0f, 0.312f, 0.0f, 0.167f, 0.865f, 1.0f, 0.311f, 0.0f, 0.167f, 0.866f, 1.0f, 0.309f, 0.0f, 0.166f, 0.867f, 1.0f,
+ 0.308f, 0.0f, 0.166f, 0.868f, 1.0f,
+};
+
+static const float data35[261 * GP_PRIM_DATABUF_SIZE] = {
+ -0.685f, 0.0f, 0.408f, 0.0f, 1.0f, -0.683f, 0.0f, 0.41f, 0.023f, 1.0f, -0.681f, 0.0f, 0.412f, 0.051f, 1.0f, -0.679f, 0.0f, 0.414f, 0.092f, 1.0f,
+ -0.678f, 0.0f, 0.415f, 0.125f, 1.0f, -0.676f, 0.0f, 0.417f, 0.149f, 1.0f, -0.674f, 0.0f, 0.419f, 0.167f, 1.0f, -0.672f, 0.0f, 0.42f, 0.183f, 1.0f,
+ -0.67f, 0.0f, 0.422f, 0.199f, 1.0f, -0.668f, 0.0f, 0.424f, 0.218f, 1.0f, -0.666f, 0.0f, 0.426f, 0.237f, 1.0f, -0.664f, 0.0f, 0.429f, 0.257f, 1.0f,
+ -0.661f, 0.0f, 0.431f, 0.275f, 1.0f, -0.659f, 0.0f, 0.434f, 0.291f, 1.0f, -0.657f, 0.0f, 0.436f, 0.305f, 1.0f, -0.655f, 0.0f, 0.439f, 0.315f, 1.0f,
+ -0.653f, 0.0f, 0.442f, 0.322f, 1.0f, -0.65f, 0.0f, 0.444f, 0.327f, 1.0f, -0.648f, 0.0f, 0.447f, 0.331f, 1.0f, -0.646f, 0.0f, 0.45f, 0.334f, 1.0f,
+ -0.643f, 0.0f, 0.453f, 0.334f, 1.0f, -0.641f, 0.0f, 0.456f, 0.334f, 1.0f, -0.639f, 0.0f, 0.459f, 0.334f, 1.0f, -0.636f, 0.0f, 0.462f, 0.333f, 1.0f,
+ -0.634f, 0.0f, 0.466f, 0.332f, 1.0f, -0.631f, 0.0f, 0.469f, 0.332f, 1.0f, -0.628f, 0.0f, 0.473f, 0.332f, 1.0f, -0.625f, 0.0f, 0.476f, 0.333f, 1.0f,
+ -0.622f, 0.0f, 0.48f, 0.335f, 1.0f, -0.618f, 0.0f, 0.483f, 0.338f, 1.0f, -0.615f, 0.0f, 0.488f, 0.342f, 1.0f, -0.611f, 0.0f, 0.492f, 0.347f, 1.0f,
+ -0.608f, 0.0f, 0.495f, 0.352f, 1.0f, -0.605f, 0.0f, 0.5f, 0.358f, 1.0f, -0.601f, 0.0f, 0.505f, 0.363f, 1.0f, -0.597f, 0.0f, 0.509f, 0.366f, 1.0f,
+ -0.593f, 0.0f, 0.514f, 0.367f, 1.0f, -0.589f, 0.0f, 0.518f, 0.367f, 1.0f, -0.585f, 0.0f, 0.522f, 0.369f, 1.0f, -0.582f, 0.0f, 0.526f, 0.372f, 1.0f,
+ -0.578f, 0.0f, 0.531f, 0.376f, 1.0f, -0.575f, 0.0f, 0.535f, 0.382f, 1.0f, -0.571f, 0.0f, 0.539f, 0.388f, 1.0f, -0.567f, 0.0f, 0.543f, 0.394f, 1.0f,
+ -0.563f, 0.0f, 0.547f, 0.4f, 1.0f, -0.56f, 0.0f, 0.551f, 0.406f, 1.0f, -0.556f, 0.0f, 0.555f, 0.411f, 1.0f, -0.552f, 0.0f, 0.559f, 0.415f, 1.0f,
+ -0.548f, 0.0f, 0.563f, 0.418f, 1.0f, -0.544f, 0.0f, 0.566f, 0.419f, 1.0f, -0.54f, 0.0f, 0.569f, 0.42f, 1.0f, -0.537f, 0.0f, 0.572f, 0.421f, 1.0f,
+ -0.533f, 0.0f, 0.576f, 0.421f, 1.0f, -0.529f, 0.0f, 0.579f, 0.421f, 1.0f, -0.526f, 0.0f, 0.582f, 0.422f, 1.0f, -0.523f, 0.0f, 0.585f, 0.422f, 1.0f,
+ -0.52f, 0.0f, 0.588f, 0.423f, 1.0f, -0.516f, 0.0f, 0.591f, 0.426f, 1.0f, -0.513f, 0.0f, 0.594f, 0.43f, 1.0f, -0.51f, 0.0f, 0.597f, 0.435f, 1.0f,
+ -0.507f, 0.0f, 0.6f, 0.441f, 1.0f, -0.504f, 0.0f, 0.603f, 0.447f, 1.0f, -0.501f, 0.0f, 0.606f, 0.453f, 1.0f, -0.498f, 0.0f, 0.609f, 0.458f, 1.0f,
+ -0.496f, 0.0f, 0.611f, 0.461f, 1.0f, -0.493f, 0.0f, 0.614f, 0.465f, 1.0f, -0.49f, 0.0f, 0.616f, 0.468f, 1.0f, -0.487f, 0.0f, 0.619f, 0.472f, 1.0f,
+ -0.484f, 0.0f, 0.621f, 0.476f, 1.0f, -0.482f, 0.0f, 0.624f, 0.48f, 1.0f, -0.479f, 0.0f, 0.627f, 0.484f, 1.0f, -0.476f, 0.0f, 0.629f, 0.487f, 1.0f,
+ -0.473f, 0.0f, 0.632f, 0.491f, 1.0f, -0.471f, 0.0f, 0.634f, 0.495f, 1.0f, -0.468f, 0.0f, 0.637f, 0.499f, 1.0f, -0.465f, 0.0f, 0.639f, 0.504f, 1.0f,
+ -0.462f, 0.0f, 0.641f, 0.508f, 1.0f, -0.459f, 0.0f, 0.643f, 0.513f, 1.0f, -0.456f, 0.0f, 0.646f, 0.519f, 1.0f, -0.453f, 0.0f, 0.648f, 0.525f, 1.0f,
+ -0.45f, 0.0f, 0.65f, 0.533f, 1.0f, -0.447f, 0.0f, 0.652f, 0.54f, 1.0f, -0.444f, 0.0f, 0.655f, 0.546f, 1.0f, -0.441f, 0.0f, 0.657f, 0.553f, 1.0f,
+ -0.438f, 0.0f, 0.659f, 0.56f, 1.0f, -0.435f, 0.0f, 0.662f, 0.567f, 1.0f, -0.432f, 0.0f, 0.664f, 0.574f, 1.0f, -0.429f, 0.0f, 0.666f, 0.58f, 1.0f,
+ -0.426f, 0.0f, 0.669f, 0.585f, 1.0f, -0.423f, 0.0f, 0.671f, 0.591f, 1.0f, -0.419f, 0.0f, 0.673f, 0.595f, 1.0f, -0.416f, 0.0f, 0.675f, 0.6f, 1.0f,
+ -0.412f, 0.0f, 0.678f, 0.604f, 1.0f, -0.409f, 0.0f, 0.68f, 0.609f, 1.0f, -0.405f, 0.0f, 0.682f, 0.613f, 1.0f, -0.401f, 0.0f, 0.684f, 0.618f, 1.0f,
+ -0.398f, 0.0f, 0.687f, 0.622f, 1.0f, -0.394f, 0.0f, 0.689f, 0.627f, 1.0f, -0.39f, 0.0f, 0.692f, 0.632f, 1.0f, -0.386f, 0.0f, 0.694f, 0.638f, 1.0f,
+ -0.381f, 0.0f, 0.697f, 0.643f, 1.0f, -0.377f, 0.0f, 0.7f, 0.649f, 1.0f, -0.373f, 0.0f, 0.702f, 0.654f, 1.0f, -0.368f, 0.0f, 0.705f, 0.659f, 1.0f,
+ -0.363f, 0.0f, 0.707f, 0.663f, 1.0f, -0.359f, 0.0f, 0.71f, 0.667f, 1.0f, -0.354f, 0.0f, 0.712f, 0.671f, 1.0f, -0.349f, 0.0f, 0.715f, 0.674f, 1.0f,
+ -0.345f, 0.0f, 0.717f, 0.677f, 1.0f, -0.34f, 0.0f, 0.72f, 0.68f, 1.0f, -0.335f, 0.0f, 0.722f, 0.683f, 1.0f, -0.33f, 0.0f, 0.725f, 0.685f, 1.0f,
+ -0.326f, 0.0f, 0.727f, 0.687f, 1.0f, -0.321f, 0.0f, 0.73f, 0.689f, 1.0f, -0.316f, 0.0f, 0.732f, 0.691f, 1.0f, -0.312f, 0.0f, 0.734f, 0.693f, 1.0f,
+ -0.307f, 0.0f, 0.736f, 0.694f, 1.0f, -0.302f, 0.0f, 0.738f, 0.696f, 1.0f, -0.298f, 0.0f, 0.74f, 0.697f, 1.0f, -0.293f, 0.0f, 0.741f, 0.698f, 1.0f,
+ -0.288f, 0.0f, 0.743f, 0.699f, 1.0f, -0.284f, 0.0f, 0.745f, 0.699f, 1.0f, -0.279f, 0.0f, 0.746f, 0.7f, 1.0f, -0.275f, 0.0f, 0.748f, 0.701f, 1.0f,
+ -0.27f, 0.0f, 0.749f, 0.702f, 1.0f, -0.265f, 0.0f, 0.751f, 0.702f, 1.0f, -0.261f, 0.0f, 0.752f, 0.704f, 1.0f, -0.256f, 0.0f, 0.753f, 0.705f, 1.0f,
+ -0.252f, 0.0f, 0.755f, 0.706f, 1.0f, -0.247f, 0.0f, 0.756f, 0.707f, 1.0f, -0.242f, 0.0f, 0.757f, 0.709f, 1.0f, -0.237f, 0.0f, 0.758f, 0.711f, 1.0f,
+ -0.233f, 0.0f, 0.759f, 0.713f, 1.0f, -0.228f, 0.0f, 0.761f, 0.715f, 1.0f, -0.223f, 0.0f, 0.762f, 0.717f, 1.0f, -0.218f, 0.0f, 0.763f, 0.719f, 1.0f,
+ -0.213f, 0.0f, 0.764f, 0.721f, 1.0f, -0.209f, 0.0f, 0.765f, 0.723f, 1.0f, -0.204f, 0.0f, 0.765f, 0.726f, 1.0f, -0.199f, 0.0f, 0.766f, 0.728f, 1.0f,
+ -0.194f, 0.0f, 0.767f, 0.73f, 1.0f, -0.189f, 0.0f, 0.768f, 0.731f, 1.0f, -0.183f, 0.0f, 0.769f, 0.733f, 1.0f, -0.178f, 0.0f, 0.77f, 0.735f, 1.0f,
+ -0.173f, 0.0f, 0.77f, 0.736f, 1.0f, -0.168f, 0.0f, 0.771f, 0.738f, 1.0f, -0.163f, 0.0f, 0.772f, 0.739f, 1.0f, -0.158f, 0.0f, 0.772f, 0.741f, 1.0f,
+ -0.152f, 0.0f, 0.773f, 0.742f, 1.0f, -0.147f, 0.0f, 0.774f, 0.744f, 1.0f, -0.142f, 0.0f, 0.774f, 0.746f, 1.0f, -0.137f, 0.0f, 0.775f, 0.748f, 1.0f,
+ -0.132f, 0.0f, 0.775f, 0.749f, 1.0f, -0.127f, 0.0f, 0.776f, 0.751f, 1.0f, -0.122f, 0.0f, 0.776f, 0.752f, 1.0f, -0.117f, 0.0f, 0.776f, 0.753f, 1.0f,
+ -0.112f, 0.0f, 0.777f, 0.754f, 1.0f, -0.108f, 0.0f, 0.777f, 0.755f, 1.0f, -0.103f, 0.0f, 0.777f, 0.755f, 1.0f, -0.099f, 0.0f, 0.777f, 0.756f, 1.0f,
+ -0.095f, 0.0f, 0.778f, 0.757f, 1.0f, -0.09f, 0.0f, 0.778f, 0.758f, 1.0f, -0.086f, 0.0f, 0.778f, 0.759f, 1.0f, -0.082f, 0.0f, 0.778f, 0.759f, 1.0f,
+ -0.077f, 0.0f, 0.778f, 0.76f, 1.0f, -0.073f, 0.0f, 0.779f, 0.76f, 1.0f, -0.069f, 0.0f, 0.779f, 0.761f, 1.0f, -0.064f, 0.0f, 0.779f, 0.761f, 1.0f,
+ -0.06f, 0.0f, 0.779f, 0.761f, 1.0f, -0.055f, 0.0f, 0.78f, 0.762f, 1.0f, -0.051f, 0.0f, 0.78f, 0.762f, 1.0f, -0.046f, 0.0f, 0.78f, 0.762f, 1.0f,
+ -0.041f, 0.0f, 0.78f, 0.762f, 1.0f, -0.037f, 0.0f, 0.781f, 0.762f, 1.0f, -0.032f, 0.0f, 0.781f, 0.763f, 1.0f, -0.027f, 0.0f, 0.781f, 0.763f, 1.0f,
+ -0.022f, 0.0f, 0.781f, 0.763f, 1.0f, -0.017f, 0.0f, 0.781f, 0.764f, 1.0f, -0.012f, 0.0f, 0.782f, 0.764f, 1.0f, -0.006f, 0.0f, 0.782f, 0.764f, 1.0f,
+ -0.001f, 0.0f, 0.782f, 0.765f, 1.0f, 0.004f, 0.0f, 0.782f, 0.766f, 1.0f, 0.009f, 0.0f, 0.782f, 0.766f, 1.0f, 0.015f, 0.0f, 0.782f, 0.767f, 1.0f,
+ 0.02f, 0.0f, 0.782f, 0.768f, 1.0f, 0.025f, 0.0f, 0.782f, 0.769f, 1.0f, 0.031f, 0.0f, 0.782f, 0.77f, 1.0f, 0.036f, 0.0f, 0.782f, 0.771f, 1.0f,
+ 0.042f, 0.0f, 0.782f, 0.772f, 1.0f, 0.048f, 0.0f, 0.782f, 0.773f, 1.0f, 0.053f, 0.0f, 0.782f, 0.774f, 1.0f, 0.059f, 0.0f, 0.782f, 0.775f, 1.0f,
+ 0.065f, 0.0f, 0.782f, 0.775f, 1.0f, 0.07f, 0.0f, 0.782f, 0.776f, 1.0f, 0.076f, 0.0f, 0.782f, 0.776f, 1.0f, 0.082f, 0.0f, 0.782f, 0.776f, 1.0f,
+ 0.088f, 0.0f, 0.782f, 0.776f, 1.0f, 0.094f, 0.0f, 0.782f, 0.777f, 1.0f, 0.1f, 0.0f, 0.781f, 0.777f, 1.0f, 0.106f, 0.0f, 0.781f, 0.778f, 1.0f,
+ 0.111f, 0.0f, 0.781f, 0.779f, 1.0f, 0.117f, 0.0f, 0.781f, 0.779f, 1.0f, 0.123f, 0.0f, 0.781f, 0.78f, 1.0f, 0.129f, 0.0f, 0.78f, 0.78f, 1.0f,
+ 0.135f, 0.0f, 0.78f, 0.781f, 1.0f, 0.141f, 0.0f, 0.779f, 0.781f, 1.0f, 0.147f, 0.0f, 0.779f, 0.782f, 1.0f, 0.153f, 0.0f, 0.778f, 0.783f, 1.0f,
+ 0.159f, 0.0f, 0.777f, 0.784f, 1.0f, 0.165f, 0.0f, 0.776f, 0.785f, 1.0f, 0.171f, 0.0f, 0.775f, 0.786f, 1.0f, 0.178f, 0.0f, 0.774f, 0.787f, 1.0f,
+ 0.185f, 0.0f, 0.773f, 0.788f, 1.0f, 0.192f, 0.0f, 0.772f, 0.789f, 1.0f, 0.2f, 0.0f, 0.771f, 0.79f, 1.0f, 0.208f, 0.0f, 0.77f, 0.791f, 1.0f,
+ 0.218f, 0.0f, 0.768f, 0.793f, 1.0f, 0.228f, 0.0f, 0.766f, 0.796f, 1.0f, 0.239f, 0.0f, 0.764f, 0.799f, 1.0f, 0.25f, 0.0f, 0.762f, 0.802f, 1.0f,
+ 0.261f, 0.0f, 0.759f, 0.806f, 1.0f, 0.271f, 0.0f, 0.755f, 0.81f, 1.0f, 0.282f, 0.0f, 0.752f, 0.815f, 1.0f, 0.293f, 0.0f, 0.748f, 0.819f, 1.0f,
+ 0.304f, 0.0f, 0.744f, 0.825f, 1.0f, 0.315f, 0.0f, 0.74f, 0.83f, 1.0f, 0.326f, 0.0f, 0.736f, 0.836f, 1.0f, 0.337f, 0.0f, 0.731f, 0.843f, 1.0f,
+ 0.349f, 0.0f, 0.727f, 0.85f, 1.0f, 0.361f, 0.0f, 0.722f, 0.858f, 1.0f, 0.372f, 0.0f, 0.718f, 0.866f, 1.0f, 0.384f, 0.0f, 0.712f, 0.874f, 1.0f,
+ 0.395f, 0.0f, 0.706f, 0.882f, 1.0f, 0.407f, 0.0f, 0.7f, 0.89f, 1.0f, 0.418f, 0.0f, 0.693f, 0.898f, 1.0f, 0.43f, 0.0f, 0.685f, 0.905f, 1.0f,
+ 0.442f, 0.0f, 0.677f, 0.912f, 1.0f, 0.458f, 0.0f, 0.666f, 0.918f, 1.0f, 0.473f, 0.0f, 0.654f, 0.924f, 1.0f, 0.49f, 0.0f, 0.64f, 0.93f, 1.0f,
+ 0.506f, 0.0f, 0.625f, 0.935f, 1.0f, 0.522f, 0.0f, 0.611f, 0.939f, 1.0f, 0.538f, 0.0f, 0.596f, 0.941f, 1.0f, 0.554f, 0.0f, 0.58f, 0.942f, 1.0f,
+ 0.569f, 0.0f, 0.564f, 0.941f, 1.0f, 0.584f, 0.0f, 0.548f, 0.935f, 1.0f, 0.598f, 0.0f, 0.533f, 0.925f, 1.0f, 0.612f, 0.0f, 0.517f, 0.91f, 1.0f,
+ 0.625f, 0.0f, 0.501f, 0.891f, 1.0f, 0.638f, 0.0f, 0.484f, 0.868f, 1.0f, 0.65f, 0.0f, 0.468f, 0.839f, 1.0f, 0.662f, 0.0f, 0.452f, 0.806f, 1.0f,
+ 0.671f, 0.0f, 0.437f, 0.766f, 1.0f, 0.679f, 0.0f, 0.423f, 0.718f, 1.0f, 0.685f, 0.0f, 0.412f, 0.661f, 1.0f, 0.691f, 0.0f, 0.403f, 0.595f, 1.0f,
+ 0.697f, 0.0f, 0.396f, 0.519f, 1.0f, 0.701f, 0.0f, 0.391f, 0.44f, 1.0f, 0.704f, 0.0f, 0.387f, 0.344f, 1.0f, 0.707f, 0.0f, 0.384f, 0.264f, 1.0f,
+ 0.711f, 0.0f, 0.38f, 0.133f, 1.0f,
+};
+
+/* ***************************************************************** */
+/* Monkey Color Data */
+
+static const ColorTemplate gp_monkey_pct_black = {
+ "Black",
+ {0.0f, 0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_skin = {
+ "Skin",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.733f, 0.567f, 0.359f, 1.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_skin_light = {
+ "Skin_Light",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.913f, 0.828f, 0.637f, 1.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_skin_shadow = {
+ "Skin_Shadow",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.32f, 0.29f, 0.223f, 1.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_eyes = {
+ "Eyes",
+ {0.553f, 0.39f, 0.266f, 0.0f},
+ {0.773f, 0.762f, 0.73f, 1.0f},
+};
+
+static const ColorTemplate gp_monkey_pct_pupils = {
+ "Pupils",
+ {0.107f, 0.075f, 0.051f, 0.0f},
+ {0.153f, 0.057f, 0.063f, 1.0f},
+};
+
+/* ***************************************************************** */
+/* Monkey API */
+
+/* add a 2D Suzanne (original model created by Matias Mendiola) */
+void ED_gpencil_create_monkey(bContext *C, float mat[4][4])
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDstroke *gps;
+
+ /* create colors */
+ int color_Black = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_black);
+ int color_Skin = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin);
+ int color_Skin_Light = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_light);
+ int color_Skin_Shadow = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_shadow);
+ int color_Eyes = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_eyes);
+ int color_Pupils = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_pupils);
+
+ /* set first color as active */
+ ob->actcol = color_Black + 1;
+
+ /* layers */
+ /* NOTE: For now, we just add new layers, to make it easier to separate out old/new instances */
+ bGPDlayer *Colors = BKE_gpencil_layer_addnew(gpd, "Colors", false);
+ bGPDlayer *Lines = BKE_gpencil_layer_addnew(gpd, "Lines", true);
+
+ /* frames */
+ /* NOTE: No need to check for existing, as this will take care of it for us */
+ bGPDframe *frameColor = BKE_gpencil_frame_addnew(Colors, cfra_eval);
+ bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, cfra_eval);
+
+ /* generate strokes */
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin, 538, 3);
+ BKE_gpencil_stroke_add_points(gps, data0, 538, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Eyes, 136, 3);
+ BKE_gpencil_stroke_add_points(gps, data1, 136, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin, 2, 3);
+ BKE_gpencil_stroke_add_points(gps, data2, 2, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 1, 3);
+ BKE_gpencil_stroke_add_points(gps, data3, 1, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 1, 3);
+ BKE_gpencil_stroke_add_points(gps, data4, 1, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 48, 3);
+ BKE_gpencil_stroke_add_points(gps, data5, 48, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 47, 3);
+ BKE_gpencil_stroke_add_points(gps, data6, 47, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 162, 3);
+ BKE_gpencil_stroke_add_points(gps, data7, 162, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 55, 3);
+ BKE_gpencil_stroke_add_points(gps, data8, 55, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 70, 3);
+ BKE_gpencil_stroke_add_points(gps, data9, 70, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 227, 3);
+ BKE_gpencil_stroke_add_points(gps, data10, 227, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 1, 3);
+ BKE_gpencil_stroke_add_points(gps, data11, 1, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 123, 3);
+ BKE_gpencil_stroke_add_points(gps, data12, 123, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 125, 3);
+ BKE_gpencil_stroke_add_points(gps, data13, 125, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 45, 3);
+ BKE_gpencil_stroke_add_points(gps, data14, 45, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 44, 3);
+ BKE_gpencil_stroke_add_points(gps, data15, 44, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 84, 3);
+ BKE_gpencil_stroke_add_points(gps, data16, 84, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 56, 3);
+ BKE_gpencil_stroke_add_points(gps, data17, 56, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 59, 3);
+ BKE_gpencil_stroke_add_points(gps, data18, 59, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 100, 3);
+ BKE_gpencil_stroke_add_points(gps, data19, 100, mat);
+
+ gps = BKE_gpencil_add_stroke(frameColor, color_Eyes, 136, 3);
+ BKE_gpencil_stroke_add_points(gps, data20, 136, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 353, 3);
+ BKE_gpencil_stroke_add_points(gps, data21, 353, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 309, 3);
+ BKE_gpencil_stroke_add_points(gps, data22, 309, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 209, 3);
+ BKE_gpencil_stroke_add_points(gps, data23, 209, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 133, 3);
+ BKE_gpencil_stroke_add_points(gps, data24, 133, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 389, 3);
+ BKE_gpencil_stroke_add_points(gps, data25, 389, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 41, 3);
+ BKE_gpencil_stroke_add_points(gps, data26, 41, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 77, 3);
+ BKE_gpencil_stroke_add_points(gps, data27, 77, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 257, 3);
+ BKE_gpencil_stroke_add_points(gps, data28, 257, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 205, 3);
+ BKE_gpencil_stroke_add_points(gps, data29, 205, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 3);
+ BKE_gpencil_stroke_add_points(gps, data30, 33, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 37, 3);
+ BKE_gpencil_stroke_add_points(gps, data31, 37, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 201, 3);
+ BKE_gpencil_stroke_add_points(gps, data32, 201, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 69, 3);
+ BKE_gpencil_stroke_add_points(gps, data33, 69, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 57, 3);
+ BKE_gpencil_stroke_add_points(gps, data34, 57, mat);
+
+ gps = BKE_gpencil_add_stroke(frameLines, color_Black, 261, 3);
+ BKE_gpencil_stroke_add_points(gps, data35, 261, mat);
+
+ /* update depsgraph */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+}
+
+
+/* ***************************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
new file mode 100644
index 00000000000..6c3107c602b
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -0,0 +1,251 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Matias Mendiola
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/gpencil/gpencil_add_stroke.c
+ * \ingroup edgpencil
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "ED_gpencil.h"
+
+/* Definition of the most important info from a color */
+typedef struct ColorTemplate {
+ const char *name;
+ float line[4];
+ float fill[4];
+} ColorTemplate;
+
+/* Add color an ensure duplications (matched by name) */
+static int gp_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct)
+{
+ short *totcol = give_totcolp(ob);
+ Material *ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ if (STREQ(ma->id.name, pct->name)) {
+ return i;
+ }
+ }
+
+ /* create a new one */
+ BKE_object_material_slot_add(bmain, ob);
+ ma = BKE_material_add_gpencil(bmain, pct->name);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+
+ copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
+ copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
+
+ return BKE_gpencil_get_material_index(ob, ma) - 1;
+}
+
+/* ***************************************************************** */
+/* Stroke Geometry */
+
+static const float data0[175 * GP_PRIM_DATABUF_SIZE] = {
+ -1.281f, 0.0f, -0.315f, 0.038f, 1.0f, -1.269f, 0.0f, -0.302f, 0.069f, 1.0f,
+ -1.261f, 0.0f, -0.293f, 0.089f, 1.0f, -1.251f, 0.0f, -0.282f, 0.112f, 1.0f,
+ -1.241f, 0.0f, -0.271f, 0.134f, 1.0f, -1.23f, 0.0f, -0.259f, 0.155f, 1.0f,
+ -1.219f, 0.0f, -0.247f, 0.175f, 1.0f, -1.208f, 0.0f, -0.234f, 0.194f, 1.0f,
+ -1.196f, 0.0f, -0.221f, 0.211f, 1.0f, -1.184f, 0.0f, -0.208f, 0.227f, 1.0f,
+ -1.172f, 0.0f, -0.194f, 0.242f, 1.0f, -1.159f, 0.0f, -0.18f, 0.256f, 1.0f,
+ -1.147f, 0.0f, -0.165f, 0.268f, 1.0f, -1.134f, 0.0f, -0.151f, 0.28f, 1.0f,
+ -1.121f, 0.0f, -0.136f, 0.29f, 1.0f, -1.108f, 0.0f, -0.121f, 0.299f, 1.0f,
+ -1.094f, 0.0f, -0.106f, 0.307f, 1.0f, -1.08f, 0.0f, -0.091f, 0.315f, 1.0f,
+ -1.066f, 0.0f, -0.076f, 0.322f, 1.0f, -1.052f, 0.0f, -0.061f, 0.329f, 1.0f,
+ -1.037f, 0.0f, -0.047f, 0.335f, 1.0f, -1.022f, 0.0f, -0.032f, 0.341f, 1.0f,
+ -1.007f, 0.0f, -0.017f, 0.346f, 1.0f, -0.991f, 0.0f, -0.003f, 0.351f, 1.0f,
+ -0.975f, 0.0f, 0.012f, 0.355f, 1.0f, -0.959f, 0.0f, 0.027f, 0.36f, 1.0f,
+ -0.942f, 0.0f, 0.041f, 0.364f, 1.0f, -0.926f, 0.0f, 0.056f, 0.368f, 1.0f,
+ -0.909f, 0.0f, 0.071f, 0.371f, 1.0f, -0.893f, 0.0f, 0.086f, 0.373f, 1.0f,
+ -0.876f, 0.0f, 0.1f, 0.376f, 1.0f, -0.859f, 0.0f, 0.115f, 0.377f, 1.0f,
+ -0.842f, 0.0f, 0.129f, 0.378f, 1.0f, -0.824f, 0.0f, 0.144f, 0.379f, 1.0f,
+ -0.807f, 0.0f, 0.158f, 0.379f, 1.0f, -0.79f, 0.0f, 0.172f, 0.379f, 1.0f,
+ -0.773f, 0.0f, 0.186f, 0.38f, 1.0f, -0.755f, 0.0f, 0.199f, 0.38f, 1.0f,
+ -0.738f, 0.0f, 0.212f, 0.381f, 1.0f, -0.721f, 0.0f, 0.224f, 0.382f, 1.0f,
+ -0.703f, 0.0f, 0.236f, 0.384f, 1.0f, -0.686f, 0.0f, 0.248f, 0.386f, 1.0f,
+ -0.67f, 0.0f, 0.26f, 0.388f, 1.0f, -0.653f, 0.0f, 0.27f, 0.39f, 1.0f,
+ -0.637f, 0.0f, 0.28f, 0.393f, 1.0f, -0.621f, 0.0f, 0.29f, 0.396f, 1.0f,
+ -0.605f, 0.0f, 0.298f, 0.399f, 1.0f, -0.589f, 0.0f, 0.306f, 0.403f, 1.0f,
+ -0.574f, 0.0f, 0.313f, 0.407f, 1.0f, -0.559f, 0.0f, 0.319f, 0.411f, 1.0f,
+ -0.544f, 0.0f, 0.325f, 0.415f, 1.0f, -0.53f, 0.0f, 0.331f, 0.42f, 1.0f,
+ -0.516f, 0.0f, 0.336f, 0.425f, 1.0f, -0.503f, 0.0f, 0.34f, 0.431f, 1.0f,
+ -0.489f, 0.0f, 0.344f, 0.437f, 1.0f, -0.477f, 0.0f, 0.347f, 0.443f, 1.0f,
+ -0.464f, 0.0f, 0.35f, 0.45f, 1.0f, -0.452f, 0.0f, 0.352f, 0.457f, 1.0f,
+ -0.44f, 0.0f, 0.354f, 0.464f, 1.0f, -0.429f, 0.0f, 0.355f, 0.471f, 1.0f,
+ -0.418f, 0.0f, 0.355f, 0.479f, 1.0f, -0.407f, 0.0f, 0.355f, 0.487f, 1.0f,
+ -0.397f, 0.0f, 0.354f, 0.495f, 1.0f, -0.387f, 0.0f, 0.353f, 0.503f, 1.0f,
+ -0.378f, 0.0f, 0.351f, 0.512f, 1.0f, -0.368f, 0.0f, 0.348f, 0.52f, 1.0f,
+ -0.36f, 0.0f, 0.344f, 0.528f, 1.0f, -0.351f, 0.0f, 0.34f, 0.537f, 1.0f,
+ -0.344f, 0.0f, 0.336f, 0.545f, 1.0f, -0.336f, 0.0f, 0.33f, 0.553f, 1.0f,
+ -0.329f, 0.0f, 0.324f, 0.562f, 1.0f, -0.322f, 0.0f, 0.318f, 0.57f, 1.0f,
+ -0.316f, 0.0f, 0.31f, 0.579f, 1.0f, -0.311f, 0.0f, 0.303f, 0.588f, 1.0f,
+ -0.306f, 0.0f, 0.294f, 0.597f, 1.0f, -0.301f, 0.0f, 0.285f, 0.606f, 1.0f,
+ -0.297f, 0.0f, 0.275f, 0.615f, 1.0f, -0.293f, 0.0f, 0.264f, 0.625f, 1.0f,
+ -0.29f, 0.0f, 0.253f, 0.635f, 1.0f, -0.288f, 0.0f, 0.241f, 0.644f, 1.0f,
+ -0.286f, 0.0f, 0.229f, 0.654f, 1.0f, -0.285f, 0.0f, 0.216f, 0.664f, 1.0f,
+ -0.284f, 0.0f, 0.202f, 0.675f, 1.0f, -0.283f, 0.0f, 0.188f, 0.685f, 1.0f,
+ -0.283f, 0.0f, 0.173f, 0.696f, 1.0f, -0.284f, 0.0f, 0.158f, 0.707f, 1.0f,
+ -0.285f, 0.0f, 0.142f, 0.718f, 1.0f, -0.286f, 0.0f, 0.125f, 0.729f, 1.0f,
+ -0.288f, 0.0f, 0.108f, 0.74f, 1.0f, -0.29f, 0.0f, 0.091f, 0.751f, 1.0f,
+ -0.293f, 0.0f, 0.073f, 0.761f, 1.0f, -0.295f, 0.0f, 0.054f, 0.772f, 1.0f,
+ -0.298f, 0.0f, 0.035f, 0.782f, 1.0f, -0.302f, 0.0f, 0.016f, 0.793f, 1.0f,
+ -0.305f, 0.0f, -0.004f, 0.804f, 1.0f, -0.309f, 0.0f, -0.024f, 0.815f, 1.0f,
+ -0.313f, 0.0f, -0.044f, 0.828f, 1.0f, -0.317f, 0.0f, -0.065f, 0.843f, 1.0f,
+ -0.321f, 0.0f, -0.085f, 0.86f, 1.0f, -0.326f, 0.0f, -0.106f, 0.879f, 1.0f,
+ -0.33f, 0.0f, -0.127f, 0.897f, 1.0f, -0.335f, 0.0f, -0.148f, 0.915f, 1.0f,
+ -0.339f, 0.0f, -0.168f, 0.932f, 1.0f, -0.344f, 0.0f, -0.189f, 0.947f, 1.0f,
+ -0.348f, 0.0f, -0.21f, 0.962f, 1.0f, -0.353f, 0.0f, -0.23f, 0.974f, 1.0f,
+ -0.357f, 0.0f, -0.25f, 0.985f, 1.0f, -0.361f, 0.0f, -0.27f, 0.995f, 1.0f,
+ -0.365f, 0.0f, -0.29f, 1.004f, 1.0f, -0.369f, 0.0f, -0.309f, 1.011f, 1.0f,
+ -0.372f, 0.0f, -0.328f, 1.018f, 1.0f, -0.375f, 0.0f, -0.347f, 1.024f, 1.0f,
+ -0.377f, 0.0f, -0.365f, 1.029f, 1.0f, -0.379f, 0.0f, -0.383f, 1.033f, 1.0f,
+ -0.38f, 0.0f, -0.4f, 1.036f, 1.0f, -0.38f, 0.0f, -0.417f, 1.037f, 1.0f,
+ -0.38f, 0.0f, -0.434f, 1.037f, 1.0f, -0.379f, 0.0f, -0.449f, 1.035f, 1.0f,
+ -0.377f, 0.0f, -0.464f, 1.032f, 1.0f, -0.374f, 0.0f, -0.478f, 1.029f, 1.0f,
+ -0.371f, 0.0f, -0.491f, 1.026f, 1.0f, -0.366f, 0.0f, -0.503f, 1.023f, 1.0f,
+ -0.361f, 0.0f, -0.513f, 1.021f, 1.0f, -0.354f, 0.0f, -0.523f, 1.019f, 1.0f,
+ -0.347f, 0.0f, -0.531f, 1.017f, 1.0f, -0.339f, 0.0f, -0.538f, 1.016f, 1.0f,
+ -0.33f, 0.0f, -0.543f, 1.016f, 1.0f, -0.32f, 0.0f, -0.547f, 1.016f, 1.0f,
+ -0.31f, 0.0f, -0.549f, 1.016f, 1.0f, -0.298f, 0.0f, -0.55f, 1.017f, 1.0f,
+ -0.286f, 0.0f, -0.55f, 1.017f, 1.0f, -0.274f, 0.0f, -0.548f, 1.018f, 1.0f,
+ -0.261f, 0.0f, -0.544f, 1.017f, 1.0f, -0.247f, 0.0f, -0.539f, 1.017f, 1.0f,
+ -0.232f, 0.0f, -0.533f, 1.016f, 1.0f, -0.218f, 0.0f, -0.525f, 1.015f, 1.0f,
+ -0.202f, 0.0f, -0.515f, 1.013f, 1.0f, -0.186f, 0.0f, -0.503f, 1.009f, 1.0f,
+ -0.169f, 0.0f, -0.49f, 1.005f, 1.0f, -0.151f, 0.0f, -0.475f, 0.998f, 1.0f,
+ -0.132f, 0.0f, -0.458f, 0.99f, 1.0f, -0.112f, 0.0f, -0.44f, 0.98f, 1.0f,
+ -0.091f, 0.0f, -0.42f, 0.968f, 1.0f, -0.069f, 0.0f, -0.398f, 0.955f, 1.0f,
+ -0.045f, 0.0f, -0.375f, 0.939f, 1.0f, -0.021f, 0.0f, -0.35f, 0.923f, 1.0f,
+ 0.005f, 0.0f, -0.324f, 0.908f, 1.0f, 0.031f, 0.0f, -0.297f, 0.895f, 1.0f,
+ 0.06f, 0.0f, -0.268f, 0.882f, 1.0f, 0.089f, 0.0f, -0.238f, 0.87f, 1.0f,
+ 0.12f, 0.0f, -0.207f, 0.858f, 1.0f, 0.153f, 0.0f, -0.175f, 0.844f, 1.0f,
+ 0.187f, 0.0f, -0.14f, 0.828f, 1.0f, 0.224f, 0.0f, -0.104f, 0.81f, 1.0f,
+ 0.262f, 0.0f, -0.067f, 0.79f, 1.0f, 0.302f, 0.0f, -0.027f, 0.769f, 1.0f,
+ 0.344f, 0.0f, 0.014f, 0.747f, 1.0f, 0.388f, 0.0f, 0.056f, 0.724f, 1.0f,
+ 0.434f, 0.0f, 0.1f, 0.7f, 1.0f, 0.483f, 0.0f, 0.145f, 0.676f, 1.0f,
+ 0.533f, 0.0f, 0.191f, 0.651f, 1.0f, 0.585f, 0.0f, 0.238f, 0.625f, 1.0f,
+ 0.637f, 0.0f, 0.284f, 0.599f, 1.0f, 0.69f, 0.0f, 0.33f, 0.573f, 1.0f,
+ 0.746f, 0.0f, 0.376f, 0.546f, 1.0f, 0.802f, 0.0f, 0.421f, 0.516f, 1.0f,
+ 0.859f, 0.0f, 0.464f, 0.483f, 1.0f, 0.915f, 0.0f, 0.506f, 0.446f, 1.0f,
+ 0.97f, 0.0f, 0.545f, 0.407f, 1.0f, 1.023f, 0.0f, 0.581f, 0.365f, 1.0f,
+ 1.075f, 0.0f, 0.614f, 0.322f, 1.0f, 1.122f, 0.0f, 0.643f, 0.28f, 1.0f,
+ 1.169f, 0.0f, 0.671f, 0.236f, 1.0f, 1.207f, 0.0f, 0.693f, 0.202f, 1.0f,
+ 1.264f, 0.0f, 0.725f, 0.155f, 1.0f,
+};
+
+/* ***************************************************************** */
+/* Color Data */
+
+static const ColorTemplate gp_stroke_material_black = {
+ "Black",
+ {0.0f, 0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+static const ColorTemplate gp_stroke_material_white = {
+ "White",
+ {1.0f, 1.0f, 1.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+static const ColorTemplate gp_stroke_material_red = {
+ "Red",
+ {1.0f, 0.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+static const ColorTemplate gp_stroke_material_green = {
+ "Green",
+ {0.0f, 1.0f, 0.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+static const ColorTemplate gp_stroke_material_blue = {
+ "Blue",
+ {0.0f, 0.0f, 1.0f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+static const ColorTemplate gp_stroke_material_grey = {
+ "Grey",
+ {0.358f, 0.358f, 0.358f, 1.0f},
+ {0.5f, 0.5f, 0.5f, 1.0f},
+};
+
+/* ***************************************************************** */
+/* Stroke API */
+
+/* add a Simple stroke with colors (original design created by Daniel M. Lara and Matias Mendiola) */
+void ED_gpencil_create_stroke(bContext *C, float mat[4][4])
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDstroke *gps;
+
+ /* create colors */
+ int color_black = gp_stroke_material(bmain, ob, &gp_stroke_material_black);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_white);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_red);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_green);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_blue);
+ gp_stroke_material(bmain, ob, &gp_stroke_material_grey);
+
+ /* set first color as active */
+ ob->actcol = color_black + 1;
+
+ /* layers */
+ bGPDlayer *colors = BKE_gpencil_layer_addnew(gpd, "Colors", false);
+ bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true);
+
+ /* frames */
+ bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, cfra_eval);
+ bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, cfra_eval);
+ UNUSED_VARS(frame_color);
+
+ /* generate stroke */
+ gps = BKE_gpencil_add_stroke(frame_lines, color_black, 175, 3);
+ BKE_gpencil_stroke_add_points(gps, data0, 175, mat);
+
+ /* update depsgraph */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+}
diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c
new file mode 100644
index 00000000000..d69f64f3eaf
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_armature.c
@@ -0,0 +1,678 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for dealing with armatures and GP datablocks
+ */
+
+/** \file blender/editors/gpencil/gpencil_armature.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_main.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object_deform.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "ED_gpencil.h"
+#include "ED_object.h"
+#include "ED_mesh.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+enum {
+ GP_ARMATURE_NAME = 0,
+ GP_ARMATURE_AUTO = 1
+};
+
+#define DEFAULT_RATIO 0.10f
+#define DEFAULT_DECAY 0.8f
+
+static int gpencil_bone_looper(
+ Object *ob, Bone *bone, void *data,
+ int(*bone_func)(Object *, Bone *, void *))
+{
+ /* We want to apply the function bone_func to every bone
+ * in an armature -- feed bone_looper the first bone and
+ * a pointer to the bone_func and watch it go!. The int count
+ * can be useful for counting bones with a certain property
+ * (e.g. skinnable)
+ */
+ int count = 0;
+
+ if (bone) {
+ /* only do bone_func if the bone is non null */
+ count += bone_func(ob, bone, data);
+
+ /* try to execute bone_func for the first child */
+ count += gpencil_bone_looper(ob, bone->childbase.first, data, bone_func);
+
+ /* try to execute bone_func for the next bone at this
+ * depth of the recursion.
+ */
+ count += gpencil_bone_looper(ob, bone->next, data, bone_func);
+ }
+
+ return count;
+}
+
+static int gpencil_bone_skinnable_cb(Object *UNUSED(ob), Bone *bone, void *datap)
+{
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) It returns 1 if the bone is skinnable.
+ * If we loop over all bones with this
+ * function, we can count the number of
+ * skinnable bones.
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bone pointer -- the bone pointer
+ * is set to point at this bone, and
+ * the pointer the handle points to
+ * is incremented to point to the
+ * next member of an array of pointers
+ * to bones. This way we can loop using
+ * this function to construct an array of
+ * pointers to bones that point to all
+ * skinnable bones.
+ */
+ Bone ***hbone;
+ int a, segments;
+ struct { Object *armob; void *list; int heat;} *data = datap;
+
+ if (!(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose &&
+ BKE_pose_channel_find_name(data->armob->pose, bone->name))
+ {
+ segments = bone->segments;
+ }
+ else {
+ segments = 1;
+ }
+
+ if (data->list != NULL) {
+ hbone = (Bone ***)&data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hbone = bone;
+ (*hbone)++;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
+}
+
+static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ /* This group creates a vertex group to ob that has the
+ * same name as bone (provided the bone is skinnable).
+ * If such a vertex group already exist the routine exits.
+ */
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (!defgroup_find_name(ob, bone->name)) {
+ BKE_object_defgroup_add_name(ob, bone->name);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
+{
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) If the bone is skinnable, it creates
+ * a vertex group for ob that has
+ * the name of the skinnable bone
+ * (if one doesn't exist already).
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bDeformGroup pointer -- the
+ * bDeformGroup pointer is set to point
+ * to the deform group with the bone's
+ * name, and the pointer the handle
+ * points to is incremented to point to the
+ * next member of an array of pointers
+ * to bDeformGroups. This way we can loop using
+ * this function to construct an array of
+ * pointers to bDeformGroups, all with names
+ * of skinnable bones.
+ */
+ bDeformGroup ***hgroup, *defgroup = NULL;
+ int a, segments;
+ struct { Object *armob; void *list; int heat; } *data = datap;
+ bArmature *arm = data->armob->data;
+
+ if (!(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose &&
+ BKE_pose_channel_find_name(data->armob->pose, bone->name))
+ {
+ segments = bone->segments;
+ }
+ else {
+ segments = 1;
+ }
+
+ if (arm->layer & bone->layer) {
+ if (!(defgroup = defgroup_find_name(ob, bone->name))) {
+ defgroup = BKE_object_defgroup_add_name(ob, bone->name);
+ }
+ else if (defgroup->flag & DG_LOCK_WEIGHT) {
+ /* In case vgroup already exists and is locked, do not modify it here. See T43814. */
+ defgroup = NULL;
+ }
+ }
+
+ if (data->list != NULL) {
+ hgroup = (bDeformGroup ***)&data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hgroup = defgroup;
+ (*hgroup)++;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
+}
+
+/* get weight value depending of distance and decay value */
+static float get_weight(float dist, float decay_rad, float dif_rad)
+{
+ float weight = 1.0f;
+ if (dist < decay_rad) {
+ weight = 1.0f;
+ }
+ else {
+ weight = interpf(0.0f, 0.9f, (dist - decay_rad) / dif_rad);
+ }
+
+ return weight;
+}
+
+/* This functions implements the automatic computation of vertex group weights */
+static void gpencil_add_verts_to_dgroups(
+ const bContext *C, Object *ob, Object *ob_arm, const float ratio, const float decay)
+{
+ bArmature *arm = ob_arm->data;
+ Bone **bonelist, *bone;
+ bDeformGroup **dgrouplist;
+ bPoseChannel *pchan;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL;
+ float(*root)[3], (*tip)[3], (*verts)[3];
+ float *radsqr;
+ int *selected;
+ float weight;
+ int numbones, i, j, segments = 0;
+ struct { Object *armob; void *list; int heat; } looper_data;
+
+ looper_data.armob = ob_arm;
+ looper_data.heat = true;
+ looper_data.list = NULL;
+
+ /* count the number of skinnable bones */
+ numbones = gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb);
+
+ if (numbones == 0)
+ return;
+
+ /* create an array of pointer to bones that are skinnable
+ * and fill it with all of the skinnable bones */
+ bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
+ looper_data.list = bonelist;
+ gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb);
+
+ /* create an array of pointers to the deform groups that
+ * correspond to the skinnable bones (creating them
+ * as necessary. */
+ dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
+
+ looper_data.list = dgrouplist;
+ gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
+
+ /* create an array of root and tip positions transformed into
+ * global coords */
+ root = MEM_callocN(numbones * sizeof(float) * 3, "root");
+ tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
+ selected = MEM_callocN(numbones * sizeof(int), "selected");
+ radsqr = MEM_callocN(numbones * sizeof(float), "radsqr");
+
+ for (j = 0; j < numbones; j++) {
+ bone = bonelist[j];
+
+ /* handle bbone */
+ if (segments == 0) {
+ segments = 1;
+ bbone = NULL;
+
+ if ((ob_arm->pose) &&
+ (pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name)))
+ {
+ if (bone->segments > 1) {
+ segments = bone->segments;
+ b_bone_spline_setup(pchan, true, bbone_array);
+ bbone = bbone_array;
+ }
+ }
+ }
+
+ segments--;
+
+ /* compute root and tip */
+ if (bbone) {
+ mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
+ if ((segments + 1) < bone->segments) {
+ mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
+ }
+ else {
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+ }
+ else {
+ copy_v3_v3(root[j], bone->arm_head);
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+
+ mul_m4_v3(ob_arm->obmat, root[j]);
+ mul_m4_v3(ob_arm->obmat, tip[j]);
+
+ selected[j] = 1;
+
+ /* calculate radius squared */
+ radsqr[j] = len_squared_v3v3(root[j], tip[j]) * ratio;
+ }
+
+ /* loop all strokes */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDspoint *pt = NULL;
+
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) ||
+ ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit)))
+ {
+
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ BKE_gpencil_dvert_ensure(gps);
+
+ /* create verts array */
+ verts = MEM_callocN(gps->totpoints * sizeof(*verts), __func__);
+
+ /* transform stroke points to global space */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(verts[i], &pt->x);
+ mul_m4_v3(ob->obmat, verts[i]);
+ }
+
+ /* loop groups and assign weight */
+ for (j = 0; j < numbones; j++) {
+ int def_nr = BLI_findindex(&ob->defbase, dgrouplist[j]);
+ if (def_nr < 0) {
+ continue;
+ }
+
+ float decay_rad = radsqr[j] - (radsqr[j] * decay);
+ float dif_rad = radsqr[j] - decay_rad;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ float dist = dist_squared_to_line_segment_v3(verts[i], root[j], tip[j]);
+ if (dist > radsqr[j]) {
+ /* if not in cylinder, check if inside extreme spheres */
+ weight = 0.0f;
+ dist = len_squared_v3v3(root[j], verts[i]);
+ if (dist < radsqr[j]) {
+ weight = get_weight(dist, decay_rad, dif_rad);
+ }
+ else {
+ dist = len_squared_v3v3(tip[j], verts[i]);
+ if (dist < radsqr[j]) {
+ weight = get_weight(dist, decay_rad, dif_rad);
+ }
+ }
+ }
+ else {
+ /* inside bone cylinder */
+ weight = get_weight(dist, decay_rad, dif_rad);
+ }
+
+ /* assign weight */
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = weight;
+ }
+ }
+ }
+ MEM_SAFE_FREE(verts);
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+
+ /* free the memory allocated */
+ MEM_SAFE_FREE(bonelist);
+ MEM_SAFE_FREE(dgrouplist);
+ MEM_SAFE_FREE(root);
+ MEM_SAFE_FREE(tip);
+ MEM_SAFE_FREE(radsqr);
+ MEM_SAFE_FREE(selected);
+}
+
+static void gpencil_object_vgroup_calc_from_armature(
+ const bContext *C,
+ Object *ob, Object *ob_arm,
+ const int mode, const float ratio, const float decay)
+{
+ /* Lets try to create some vertex groups
+ * based on the bones of the parent armature.
+ */
+ bArmature *arm = ob_arm->data;
+
+ /* always create groups */
+ const int defbase_tot = BLI_listbase_count(&ob->defbase);
+ int defbase_add;
+ /* Traverse the bone list, trying to create empty vertex
+ * groups corresponding to the bone.
+ */
+ defbase_add = gpencil_bone_looper(
+ ob, arm->bonebase.first, NULL,
+ vgroup_add_unique_bone_cb);
+
+ if (defbase_add) {
+ /* its possible there are DWeight's outside the range of the current
+ * objects deform groups, in this case the new groups wont be empty */
+ ED_vgroup_data_clamp_range(ob->data, defbase_tot);
+ }
+
+ if (mode == GP_ARMATURE_AUTO) {
+ /* Traverse the bone list, trying to fill vertex groups
+ * with the corresponding vertice weights for which the
+ * bone is closest.
+ */
+ gpencil_add_verts_to_dgroups(
+ C, ob, ob_arm,
+ ratio, decay);
+ }
+}
+
+bool ED_gpencil_add_armature_weights(
+ const bContext *C, ReportList *reports,
+ Object *ob, Object *ob_arm, int mode)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ /* if no armature modifier, add a new one */
+ GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Armature);
+ if (md == NULL) {
+ md = ED_object_gpencil_modifier_add(
+ reports, bmain, scene,
+ ob, "Armature", eGpencilModifierType_Armature);
+ if (md == NULL) {
+ BKE_report(reports, RPT_ERROR,
+ "Unable to add a new Armature modifier to object");
+ return false;
+ }
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+
+ /* verify armature */
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
+ if (mmd->object == NULL) {
+ mmd->object = ob_arm;
+ }
+ else {
+ if (ob_arm != mmd->object) {
+ BKE_report(reports, RPT_ERROR,
+ "The existing Armature modifier is already using a different Armature object");
+ return false;
+ }
+ }
+
+ /* add weights */
+ gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, DEFAULT_RATIO, DEFAULT_DECAY);
+
+ return true;
+}
+/* ***************** Generate armature weights ************************** */
+static bool gpencil_generate_weights_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob->type != OB_GPENCIL) {
+ return false;
+ }
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ if (BLI_listbase_count(&gpd->layers) == 0) {
+ return false;
+ }
+
+ /* need some armature in the view layer */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->type == OB_ARMATURE) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int gpencil_generate_weights_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = CTX_data_active_object(C);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Object *ob_arm = NULL;
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ const float ratio = RNA_float_get(op->ptr, "ratio");
+ const float decay = RNA_float_get(op->ptr, "decay");
+
+ /* sanity checks */
+ if (ELEM(NULL, ob, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* get armature */
+ const int arm_idx = RNA_enum_get(op->ptr, "armature");
+ if (arm_idx > 0) {
+ Base *base = BLI_findlink(&view_layer->object_bases, arm_idx - 1);
+ ob_arm = base->object;
+ }
+ else {
+ /* get armature from modifier */
+ GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob_eval, eGpencilModifierType_Armature);
+ if (md == NULL) {
+ BKE_report(op->reports, RPT_ERROR,
+ "The grease pencil object need an Armature modifier");
+ return OPERATOR_CANCELLED;
+ }
+
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
+ if (mmd->object == NULL) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Armature modifier is not valid or wrong defined");
+ return OPERATOR_CANCELLED;
+ }
+
+ ob_arm = mmd->object;
+ }
+
+ if (ob_arm == NULL) {
+ BKE_report(op->reports, RPT_ERROR,
+ "No Armature object in the view layer");
+ return OPERATOR_CANCELLED;
+ }
+
+ gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, ratio, decay);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Dynamically populate an enum of Armatures */
+static const EnumPropertyItem *gpencil_armatures_enum_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ EnumPropertyItem *item = NULL, item_tmp = { 0 };
+ int totitem = 0;
+ int i = 0;
+
+ if (C == NULL) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* add default */
+ item_tmp.identifier = "DEFAULT";
+ item_tmp.name = "Default";
+ item_tmp.value = 0;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ i++;
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if (ob->type == OB_ARMATURE) {
+ item_tmp.identifier = item_tmp.name = ob->id.name + 2;
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ i++;
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void GPENCIL_OT_generate_weights(wmOperatorType *ot)
+{
+ static const EnumPropertyItem mode_type[] = {
+ {GP_ARMATURE_NAME, "NAME", 0, "Empty Groups", ""},
+ {GP_ARMATURE_AUTO, "AUTO", 0, "Automatic Weights", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Generate Automatic Weights";
+ ot->idname = "GPENCIL_OT_generate_weights";
+ ot->description = "Generate automatic weights for armatures (requires armature modifier)";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gpencil_generate_weights_exec;
+ ot->poll = gpencil_generate_weights_poll;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", mode_type, 0, "Mode", "");
+
+ prop = RNA_def_enum(ot->srna, "armature", DummyRNA_DEFAULT_items, 0, "Armature", "Armature to use");
+ RNA_def_enum_funcs(prop, gpencil_armatures_enum_itemf);
+
+ RNA_def_float(
+ ot->srna, "ratio", DEFAULT_RATIO, 0.0f, 2.0f, "Ratio",
+ "Ratio between bone length and influence radius", 0.001f, 1.0f);
+
+ RNA_def_float(
+ ot->srna, "decay", DEFAULT_DECAY, 0.0f, 1.0f, "Decay",
+ "Factor to reduce influence depending of distance to bone axis", 0.0f, 1.0f);
+}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index a5c6fd8b8cf..d73b39811ce 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -44,8 +44,11 @@
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+#include "PIL_time.h"
+
#include "BLT_translation.h"
+#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -53,9 +56,12 @@
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_gpencil.h"
-#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_object_deform.h"
#include "BKE_report.h"
#include "BKE_screen.h"
@@ -74,8 +80,12 @@
#include "ED_screen.h"
#include "ED_view3d.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_state.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "gpencil_intern.h"
@@ -86,7 +96,9 @@
typedef struct tGP_BrushEditData {
/* Current editor/region/etc. */
/* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
+ Depsgraph *depsgraph;
Scene *scene;
+ Object *object;
ScrArea *sa;
ARegion *ar;
@@ -95,11 +107,11 @@ typedef struct tGP_BrushEditData {
bGPdata *gpd;
/* Brush Settings */
- GP_BrushEdit_Settings *settings;
- GP_EditBrush_Data *brush;
+ GP_Sculpt_Settings *settings;
+ GP_Sculpt_Data *gp_brush;
- eGP_EditBrush_Types brush_type;
- eGP_EditBrush_Flag flag;
+ eGP_Sculpt_Types brush_type;
+ eGP_Sculpt_Flag flag;
/* Space Conversion Data */
GP_SpaceConversion gsc;
@@ -111,6 +123,10 @@ typedef struct tGP_BrushEditData {
/* Start of new sculpt stroke */
bool first;
+ /* Is multiframe editing enabled, and are we using falloff for that? */
+ bool is_multiframe;
+ bool use_multiframe_falloff;
+
/* Current frame */
int cfra;
@@ -125,6 +141,13 @@ typedef struct tGP_BrushEditData {
/* - effect vector (e.g. 2D/3D translation for grab brush) */
float dvec[3];
+ /* - multiframe falloff factor */
+ float mf_falloff;
+
+ /* active vertex group */
+ int vrgroup;
+
+
/* brush geometry (bounding box) */
rcti brush_rect;
@@ -138,29 +161,62 @@ typedef struct tGP_BrushEditData {
/* Timer for in-place accumulation of brush effect */
wmTimer *timer;
bool timerTick; /* is this event from a timer */
+
+ RNG *rng;
} tGP_BrushEditData;
/* Callback for performing some brush operation on a single point */
-typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2]);
+typedef bool (*GP_BrushApplyCb)(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2]);
/* ************************************************ */
/* Utility Functions */
+/* apply lock axis reset */
+static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, const float save_pt[3])
+{
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ return;
+ }
+
+ ToolSettings *ts = gso->scene->toolsettings;
+ int axis = ts->gp_sculpt.lock_axis;
+
+ /* lock axis control */
+ if (axis == 1) {
+ pt->x = save_pt[0];
+ }
+ if (axis == 2) {
+ pt->y = save_pt[1];
+ }
+ if (axis == 3) {
+ pt->z = save_pt[2];
+ }
+}
+
/* Context ---------------------------------------- */
/* Get the sculpting settings */
-static GP_BrushEdit_Settings *gpsculpt_get_settings(Scene *scene)
+static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene)
{
return &scene->toolsettings->gp_sculpt;
}
/* Get the active brush */
-static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene)
+static GP_Sculpt_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode)
{
- GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
- return &gset->brush[gset->brushtype];
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ GP_Sculpt_Data *gp_brush = NULL;
+ if (is_weight_mode) {
+ gp_brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ gp_brush = &gset->brush[gset->brushtype];
+ }
+
+ return gp_brush;
}
/* Brush Operations ------------------------------- */
@@ -169,31 +225,39 @@ static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene)
static bool gp_brush_invert_check(tGP_BrushEditData *gso)
{
/* The basic setting is the brush's setting (from the panel) */
- bool invert = ((gso->brush->flag & GP_EDITBRUSH_FLAG_INVERT) != 0);
+ bool invert = ((gso->gp_brush->flag & GP_SCULPT_FLAG_INVERT) != 0);
/* During runtime, the user can hold down the Ctrl key to invert the basic behaviour */
- if (gso->flag & GP_EDITBRUSH_FLAG_INVERT) {
+ if (gso->flag & GP_SCULPT_FLAG_INVERT) {
invert ^= true;
}
+ /* set temporary status */
+ if (invert) {
+ gso->gp_brush->flag |= GP_SCULPT_FLAG_TMP_INVERT;
+ }
+ else {
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
+ }
+
return invert;
}
/* Compute strength of effect */
static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2])
{
- GP_EditBrush_Data *brush = gso->brush;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
/* basic strength factor from brush settings */
- float influence = brush->strength;
+ float influence = gp_brush->strength;
/* use pressure? */
- if (brush->flag & GP_EDITBRUSH_FLAG_USE_PRESSURE) {
+ if (gp_brush->flag & GP_SCULPT_FLAG_USE_PRESSURE) {
influence *= gso->pressure;
}
/* distance fading */
- if (brush->flag & GP_EDITBRUSH_FLAG_USE_FALLOFF) {
+ if (gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
float distance = (float)len_v2v2_int(gso->mval, co);
float fac;
@@ -203,6 +267,9 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c
influence *= fac;
}
+ /* apply multiframe falloff */
+ influence *= gso->mf_falloff;
+
/* return influence */
return influence;
}
@@ -217,30 +284,37 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c
/* Smooth Brush */
/* A simple (but slower + inaccurate) smooth-brush implementation to test the algorithm for stroke smoothing */
-static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_smooth_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- GP_EditBrush_Data *brush = gso->brush;
+ // GP_Sculpt_Data *gp_brush = gso->brush;
float inf = gp_brush_influence_calc(gso, radius, co);
- bool affect_pressure = (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) != 0;
/* need one flag enabled by default */
- if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
- GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
- GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0)
+ if ((gso->settings->flag &
+ (GP_SCULPT_SETT_FLAG_APPLY_POSITION |
+ GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
+ GP_SCULPT_SETT_FLAG_APPLY_THICKNESS |
+ GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0)
{
- gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
+ gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
}
/* perform smoothing */
- if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) {
- gp_smooth_stroke(gps, i, inf, affect_pressure);
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
+ BKE_gpencil_smooth_stroke(gps, pt_index, inf);
}
- if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
- gp_smooth_stroke_strength(gps, i, inf);
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
}
- if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) {
- gp_smooth_stroke_thickness(gps, i, inf);
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
+ BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf);
}
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
+ BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf);
+ }
+
+ gps->flag |= GP_STROKE_RECALC_CACHES;
return true;
}
@@ -249,10 +323,11 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i
/* Line Thickness Brush */
/* Make lines thicker or thinner by the specified amounts */
-static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_thickness_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
float inf;
/* Compute strength of effect
@@ -289,28 +364,29 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
/* Make color more or less transparent by the specified amounts */
static bool gp_brush_strength_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
float inf;
/* Compute strength of effect
- * - We divide the strength by 10, so that users can set "sane" values.
+ * - We divide the strength, so that users can set "sane" values.
* Otherwise, good default values are in the range of 0.093
*/
- inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
+ inf = gp_brush_influence_calc(gso, radius, co) / 20.0f;
/* apply */
- // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff
if (gp_brush_invert_check(gso)) {
- /* make line thinner - reduce stroke pressure */
+ /* make line more transparent - reduce alpha factor */
pt->strength -= inf;
}
else {
- /* make line thicker - increase stroke pressure */
+ /* make line more opaque - increase stroke strength */
pt->strength += inf;
}
+ /* smooth the strength */
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
/* Strength should stay within [0.0, 1.0] */
CLAMP(pt->strength, 0.0f, 1.0f);
@@ -377,8 +453,9 @@ static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps)
}
/* store references to stroke points in the initial stage */
-static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_grab_store_points(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
float inf = gp_brush_influence_calc(gso, radius, co);
@@ -387,7 +464,7 @@ static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps,
BLI_assert(data->size < data->capacity);
/* insert this point into the set of affected points */
- data->points[data->size] = i;
+ data->points[data->size] = pt_index;
data->weights[data->size] = inf;
data->size++;
@@ -402,9 +479,8 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
// TODO: incorporate pressure into this?
// XXX: screen-space strokes in 3D space will suffer!
if (gso->sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = gso->sa->spacedata.first;
RegionView3D *rv3d = gso->ar->regiondata;
- float *rvec = ED_view3d_cursor3d_get(gso->scene, v3d);
+ float *rvec = gso->scene->cursor.location;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -426,7 +502,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
/* Apply grab transform to all relevant points of the affected strokes */
static void gp_brush_grab_apply_cached(
- tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, float diff_mat[4][4])
+ tGP_BrushEditData *gso, bGPDstroke *gps, float diff_mat[4][4])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
int i;
@@ -438,24 +514,23 @@ static void gp_brush_grab_apply_cached(
/* adjust the amount of displacement to apply */
mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
- if (!parented) {
- /* apply */
- add_v3_v3(&pt->x, delta);
- }
- else {
- float fpt[3];
- /* apply transformation */
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* apply */
- add_v3_v3(fpt, delta);
- copy_v3_v3(&pt->x, fpt);
- /* undo transformation to the init parent position */
- float inverse_diff_mat[4][4];
- invert_m4_m4(inverse_diff_mat, diff_mat);
- mul_m4_v3(inverse_diff_mat, &pt->x);
- }
+ float fpt[3];
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+ /* apply transformation */
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* apply */
+ add_v3_v3v3(&pt->x, fpt, delta);
+ /* undo transformation to the init parent position */
+ float inverse_diff_mat[4][4];
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
}
+ gps->flag |= GP_STROKE_RECALC_CACHES;
}
/* free customdata used for handling this stroke */
@@ -475,10 +550,14 @@ static void gp_brush_grab_stroke_free(void *ptr)
/* Push Brush */
/* NOTE: Depends on gp_brush_grab_calc_dvec() */
-static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_push_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+
float inf = gp_brush_influence_calc(gso, radius, co);
float delta[3] = {0.0f};
@@ -488,6 +567,11 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
/* apply */
add_v3_v3(&pt->x, delta);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
/* done */
return true;
}
@@ -502,12 +586,12 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
/* Convert mouse position to 3D space
* See: gpencil_paint.c :: gp_stroke_convertcoords()
*/
- View3D *v3d = gso->sa->spacedata.first;
RegionView3D *rv3d = gso->ar->regiondata;
- float *rvec = ED_view3d_cursor3d_get(gso->scene, v3d);
+ const float *rvec = gso->scene->cursor.location;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
- float mval_f[2] = {UNPACK2(gso->mval)};
+ float mval_f[2];
+ copy_v2fl_v2i(mval_f, gso->mval);
float mval_prj[2];
float dvec[3];
@@ -531,12 +615,15 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
}
/* Shrink distance between midpoint and this point... */
-static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_pinch_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
float fac, inf;
float vec[3];
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
/* Scale down standard influence value to get it more manageable...
* - No damping = Unmanageable at > 0.5 strength
@@ -566,6 +653,11 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
/* 3) Translate back to original space, with the shrinkage applied */
add_v3_v3v3(&pt->x, gso->dvec, vec);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
/* done */
return true;
}
@@ -577,11 +669,14 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
* convert the rotated point and convert it into "data" space
*/
-static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_twist_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
float angle, inf;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
/* Angle to rotate by */
inf = gp_brush_influence_calc(gso, radius, co);
@@ -610,6 +705,9 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center (center is stored in dvec) */
mul_m3_v3(rmat, vec);
add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
}
else {
const float axis[3] = {0.0f, 0.0f, 1.0f};
@@ -640,6 +738,8 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
}
}
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
/* done */
return true;
}
@@ -649,26 +749,31 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
/* Randomize Brush */
/* Apply some random jitter to the point */
-static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
- const int radius, const int co[2])
+static bool gp_brush_randomize_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + i;
+ bGPDspoint *pt = gps->points + pt_index;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
/* Amount of jitter to apply depends on the distance of the point to the cursor,
* as well as the strength of the brush
*/
const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
- const float fac = BLI_frand() * inf;
+ const float fac = BLI_rng_get_float(gso->rng) * inf;
/* need one flag enabled by default */
- if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION |
- GP_BRUSHEDIT_FLAG_APPLY_STRENGTH |
- GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0)
+ if ((gso->settings->flag &
+ (GP_SCULPT_SETT_FLAG_APPLY_POSITION |
+ GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
+ GP_SCULPT_SETT_FLAG_APPLY_THICKNESS |
+ GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0)
{
- gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
+ gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
}
/* apply random to position */
- if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) {
+ if (gso->settings->flag & GP_SCULPT_SETT_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
@@ -685,7 +790,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
svec[1] = mvec[0];
/* scale the displacement by the random displacement, and apply */
- if (BLI_frand() > 0.5f) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
mul_v2_fl(svec, -fac);
}
else {
@@ -705,6 +810,8 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
float dvec[3];
ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
add_v3_v3(&pt->x, dvec);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
}
}
else {
@@ -723,8 +830,8 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
}
}
/* apply random to strength */
- if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) {
- if (BLI_frand() > 0.5f) {
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
pt->strength += fac;
}
else {
@@ -734,8 +841,8 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
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) {
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
pt->pressure += fac;
}
else {
@@ -744,11 +851,80 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in
/* only limit lower value */
CLAMP_MIN(pt->pressure, 0.0f);
}
+ /* apply random to UV (use pressure) */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ pt->uv_rot += fac;
+ }
+ else {
+ pt->uv_rot -= fac;
+ }
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
+
+ gps->flag |= GP_STROKE_RECALC_CACHES;
/* done */
return true;
}
+/* Weight Paint Brush */
+
+/* Change weight paint for vertex groups */
+static bool gp_brush_weight_apply(
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
+ const int radius, const int co[2])
+{
+ /* create dvert */
+ BKE_gpencil_dvert_ensure(gps);
+
+ bGPDspoint *pt = gps->points + pt_index;
+ MDeformVert *dvert = gps->dvert + pt_index;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
+
+ /* need a vertex group */
+ if (gso->vrgroup == -1) {
+ if (gso->object) {
+ BKE_object_defgroup_add(gso->object);
+ gso->vrgroup = 0;
+ }
+ }
+ /* get current weight */
+ MDeformWeight *dw = defvert_verify_index(dvert, gso->vrgroup);
+ float curweight = dw ? dw->weight : 0.0f;
+
+ if (gp_brush_invert_check(gso)) {
+ /* reduce weight */
+ curweight -= inf;
+ }
+ else {
+ /* increase weight */
+ curweight += inf;
+ }
+
+ /* verify target weight */
+ CLAMP_MAX(curweight, gso->gp_brush->target_weight);
+
+ CLAMP(curweight, 0.0f, 1.0f);
+ if (dw) {
+ dw->weight = curweight;
+ }
+
+ /* weight should stay within [0.0, 1.0] */
+ if (pt->pressure < 0.0f)
+ pt->pressure = 0.0f;
+
+ return true;
+}
+
+
+
/* ************************************************ */
/* Non Callback-Based Brushes */
@@ -822,7 +998,7 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
/* Init colormap for mapping between the pasted stroke's source colour(names)
* and the final colours that will be used here instead...
*/
- data->new_colors = gp_copybuf_validate_colormap(gso->gpd);
+ data->new_colors = gp_copybuf_validate_colormap(C);
}
/* Free custom data used for "clone" brush */
@@ -852,9 +1028,12 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
{
tGPSB_CloneBrushData *data = gso->customdata;
- Scene *scene = gso->scene;
+ Object *ob = CTX_data_active_object(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
bGPDstroke *gps;
float delta[3];
@@ -877,17 +1056,24 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
new_stroke = MEM_dupallocN(gps);
new_stroke->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ new_stroke->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
+ }
new_stroke->triangles = MEM_dupallocN(gps->triangles);
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
/* Fix color references */
- BLI_assert(new_stroke->colorname[0] != '\0');
- new_stroke->palcolor = BLI_ghash_lookup(data->new_colors, new_stroke->colorname);
-
- BLI_assert(new_stroke->palcolor != NULL);
- BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname));
+ Material *ma = BLI_ghash_lookup(data->new_colors, &new_stroke->mat_nr);
+ if ((ma) && (BKE_gpencil_get_material_index(ob, ma) > 0)) {
+ gps->mat_nr = BKE_gpencil_get_material_index(ob, ma) - 1;
+ CLAMP_MIN(gps->mat_nr, 0);
+ }
+ else {
+ gps->mat_nr = 0; /* only if the color is not found */
+ }
/* Adjust all the stroke's points, so that the strokes
* get pasted relative to where the cursor is now
@@ -923,7 +1109,7 @@ static void gp_brush_clone_adjust(tGP_BrushEditData *gso)
int i;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (gso->brush->flag & GP_EDITBRUSH_FLAG_USE_FALLOFF) {
+ if (gso->gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
/* "Smudge" Effect when falloff is enabled */
float delta[3] = {0.0f};
int sco[2] = {0};
@@ -931,7 +1117,7 @@ static void gp_brush_clone_adjust(tGP_BrushEditData *gso)
/* compute influence on point */
gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
- influence = gp_brush_influence_calc(gso, gso->brush->size, sco);
+ influence = gp_brush_influence_calc(gso, gso->gp_brush->size, sco);
/* adjust the amount of displacement to apply */
mul_v3_v3fl(delta, gso->dvec, influence);
@@ -972,57 +1158,6 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
}
/* ************************************************ */
-/* Cursor drawing */
-
-/* Helper callback for drawing the cursor itself */
-static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
-{
- GP_EditBrush_Data *brush = gpsculpt_get_brush(CTX_data_scene(C));
-
- if (brush) {
- glPushMatrix();
-
- glTranslatef((float)x, (float)y, 0.0f);
-
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
-
- /* Inner Ring: Light color for action of the brush */
- /* TODO: toggle between add and remove? */
- glColor4ub(255, 255, 255, 200);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size, 40);
-
- /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
- glColor3ub(30, 30, 30);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size + 1, 40);
-
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
-
- glPopMatrix();
- }
-}
-
-/* Turn brush cursor in on/off */
-static void gpencil_toggle_brush_cursor(bContext *C, bool enable)
-{
- GP_BrushEdit_Settings *gset = gpsculpt_get_settings(CTX_data_scene(C));
-
- if (gset->paintcursor && !enable) {
- /* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
- gset->paintcursor = NULL;
- }
- else if (enable) {
- /* enable cursor */
- gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- NULL,
- gp_brush_drawcursor, NULL);
- }
-}
-
-
-/* ************************************************ */
/* Header Info for GPencil Sculpt */
static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
@@ -1038,7 +1173,7 @@ static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
" | Shift-Wheel Up/Down for Strength"),
(brush_name) ? brush_name : "<?>");
- ED_area_headerprint(CTX_wm_area(C), str);
+ ED_workspace_status_text(C, str);
}
/* ************************************************ */
@@ -1049,18 +1184,37 @@ static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+
+ const bool is_weight_mode = ob->mode == OB_MODE_GPENCIL_WEIGHT;
+ /* set the brush using the tool */
+#if 0
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ eGP_Sculpt_Types mode = is_weight_mode ? gset->weighttype : gset->brushtype;
+#endif
tGP_BrushEditData *gso;
/* setup operator data */
gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
op->customdata = gso;
+ gso->depsgraph = CTX_data_depsgraph(C);
/* store state */
gso->settings = gpsculpt_get_settings(scene);
- gso->brush = gpsculpt_get_brush(scene);
+ gso->gp_brush = gpsculpt_get_brush(scene, is_weight_mode);
- gso->brush_type = gso->settings->brushtype;
+ if (is_weight_mode) {
+ gso->brush_type = gso->settings->weighttype;
+ }
+ else {
+ gso->brush_type = gso->settings->brushtype;
+ }
+ /* Random generator, only init once. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= POINTER_AS_UINT(gso);
+ gso->rng = BLI_rng_new(rng_seed);
gso->is_painting = false;
gso->first = true;
@@ -1068,14 +1222,40 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gso->gpd = ED_gpencil_data_get_active(C);
gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
+ /* some brushes cannot use pressure for radius */
+ if (ELEM(gso->brush_type, GP_SCULPT_TYPE_GRAB, GP_SCULPT_TYPE_CLONE)) {
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_PRESSURE_RADIUS;
+ }
+
gso->scene = scene;
+ gso->object = ob;
+ if (ob) {
+ gso->vrgroup = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
+ gso->vrgroup = -1;
+ }
+ }
+ else {
+ gso->vrgroup = - 1;
+ }
gso->sa = CTX_wm_area(C);
gso->ar = CTX_wm_region(C);
+ /* multiframe settings */
+ gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+
+ /* init multiedit falloff curve data before doing anything,
+ * so we won't have to do it again later
+ */
+ if (gso->is_multiframe) {
+ curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
/* initialise custom data for brushes */
switch (gso->brush_type) {
- case GP_EDITBRUSH_TYPE_CLONE:
+ case GP_SCULPT_TYPE_CLONE:
{
bGPDstroke *gps;
bool found = false;
@@ -1104,7 +1284,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
break;
}
- case GP_EDITBRUSH_TYPE_GRAB:
+ case GP_SCULPT_TYPE_GRAB:
{
/* initialise the cache needed for this brush */
gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
@@ -1124,9 +1304,10 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gpsculpt_brush_header_set(C, gso);
/* setup cursor drawing */
- WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
- gpencil_toggle_brush_cursor(C, true);
-
+ //WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
return true;
}
@@ -1137,7 +1318,7 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
/* free brush-specific data */
switch (gso->brush_type) {
- case GP_EDITBRUSH_TYPE_GRAB:
+ case GP_SCULPT_TYPE_GRAB:
{
/* Free per-stroke customdata
* - Keys don't need to be freed, as those are the strokes
@@ -1147,7 +1328,7 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
break;
}
- case GP_EDITBRUSH_TYPE_CLONE:
+ case GP_SCULPT_TYPE_CLONE:
{
/* Free customdata */
gp_brush_clone_free(gso);
@@ -1163,10 +1344,19 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer);
}
+ if (gso->rng != NULL) {
+ BLI_rng_free(gso->rng);
+ }
+
/* disable cursor and headerprints */
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
WM_cursor_modal_restore(win);
- gpencil_toggle_brush_cursor(C, false);
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+
+ /* disable temp invert flag */
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
/* free operator data */
MEM_freeN(gso);
@@ -1184,13 +1374,13 @@ static bool gpsculpt_brush_poll(bContext *C)
static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
{
- Scene *scene = gso->scene;
bGPdata *gpd = gso->gpd;
+
bGPDlayer *gpl;
- int cfra = CFRA;
+ int cfra_eval = (int)DEG_get_ctime(gso->depsgraph);
/* only try to add a new frame if this is the first stroke, or the frame has changed */
- if ((gpd == NULL) || (cfra == gso->cfra))
+ if ((gpd == NULL) || (cfra_eval == gso->cfra))
return;
/* go through each layer, and ensure that we've got a valid frame to use */
@@ -1204,26 +1394,27 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* spent too much time editing the wrong frame...
*/
// XXX: should this be allowed when framelock is enabled?
- if (gpf->framenum != cfra) {
- BKE_gpencil_frame_addcopy(gpl, cfra);
+ if (gpf->framenum != cfra_eval) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
}
}
}
/* save off new current frame, so that next update works fine */
- gso->cfra = cfra;
+ gso->cfra = cfra_eval;
}
/* Apply ----------------------------------------------- */
/* Apply brush operation to points in this stroke */
static bool gpsculpt_brush_do_stroke(
- tGP_BrushEditData *gso, bGPDstroke *gps, bool parented,
+ tGP_BrushEditData *gso, bGPDstroke *gps,
float diff_mat[4][4], GP_BrushApplyCb apply)
{
GP_SpaceConversion *gsc = &gso->gsc;
rcti *rect = &gso->brush_rect;
- const int radius = gso->brush->size;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ? gso->gp_brush->size * gso->pressure : gso->gp_brush->size;
bGPDspoint *pt1, *pt2;
int pc1[2] = {0};
@@ -1233,14 +1424,9 @@ static bool gpsculpt_brush_do_stroke(
bool changed = false;
if (gps->totpoints == 1) {
- if (!parented) {
- gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]);
- }
- else {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
- }
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
@@ -1261,25 +1447,18 @@ static bool gpsculpt_brush_do_stroke(
pt2 = gps->points + i + 1;
/* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */
- if (gso->settings->flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
include_last = false;
continue;
}
}
- if (!parented) {
- gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]);
- }
- else {
- bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- gp_point_to_parent_space(pt2, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- }
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
/* Check that point segment of the boundbox of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
@@ -1329,30 +1508,135 @@ static bool gpsculpt_brush_do_stroke(
return changed;
}
+/* Apply sculpt brushes to strokes in the given frame */
+static bool gpsculpt_brush_do_frame(
+ bContext *C, tGP_BrushEditData *gso,
+ bGPDlayer *gpl, bGPDframe *gpf,
+ float diff_mat[4][4])
+{
+ bool changed = false;
+ Object *ob = CTX_data_active_object(C);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_SMOOTH: /* Smooth strokes */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_THICKNESS: /* Adjust stroke thickness */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_STRENGTH: /* Adjust stroke color strength */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_GRAB: /* Grab points */
+ {
+ if (gso->first) {
+ /* First time this brush stroke is being applied:
+ * 1) Prepare data buffers (init/clear) for this stroke
+ * 2) Use the points now under the cursor
+ */
+ gp_brush_grab_stroke_init(gso, gps);
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
+ }
+ else {
+ /* Apply effect to the stored points */
+ gp_brush_grab_apply_cached(gso, gps, diff_mat);
+ changed |= true;
+ }
+ break;
+ }
+
+ case GP_SCULPT_TYPE_PUSH: /* Push points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_PINCH: /* Pinch points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_RANDOMIZE: /* Apply jitter */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_WEIGHT: /* Adjust vertex group weight */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply);
+ break;
+ }
+
+
+ default:
+ printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
+ break;
+ }
+ /* Triangulation must be calculated if changed */
+ if (changed) {
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ }
+ }
+
+ return changed;
+}
+
/* Perform two-pass brushes which modify the existing strokes */
static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = gso->object;
+ bGPdata *gpd = gso->gpd;
bool changed = false;
/* Calculate brush-specific data which applies equally to all points */
switch (gso->brush_type) {
- case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */
- case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
+ case GP_SCULPT_TYPE_GRAB: /* Grab points */
+ case GP_SCULPT_TYPE_PUSH: /* Push points */
{
/* calculate amount of displacement to apply */
gp_brush_grab_calc_dvec(gso);
break;
}
- case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
- case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
+ case GP_SCULPT_TYPE_PINCH: /* Pinch points */
+ case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
{
/* calculate midpoint of the brush (in data space) */
gp_brush_calc_midpoint(gso);
break;
}
- case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Random jitter */
+ case GP_SCULPT_TYPE_RANDOMIZE: /* Random jitter */
{
/* compute the displacement vector for the cursor (in data space) */
gp_brush_grab_calc_dvec(gso);
@@ -1365,104 +1649,53 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
/* Find visible strokes, and perform operations on those if hit */
- float diff_mat[4][4];
- bool parented = false;
-
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL)
+ /* If no active frame, don't do anything... */
+ if (gpl->actframe == NULL) {
continue;
-
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- parented = true;
- }
- else {
- parented = false;
}
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
+ /* calculate difference matrix */
+ float diff_mat[4][4];
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
- 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;
- }
-
- case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_thickness_apply);
- break;
- }
+ /* Active Frame or MultiFrame? */
+ if (gso->is_multiframe) {
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
- case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_strength_apply);
- break;
- }
+ if (gso->use_multiframe_falloff) {
+ BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ }
- case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */
- {
- if (gso->first) {
- /* First time this brush stroke is being applied:
- * 1) Prepare data buffers (init/clear) for this stroke
- * 2) Use the points now under the cursor
- */
- gp_brush_grab_stroke_init(gso, gps);
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_grab_store_points);
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* Always do active frame; Otherwise, only include selected frames */
+ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
+ /* compute multiframe falloff factor */
+ if (gso->use_multiframe_falloff) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
+ gpf, gpl->actframe->framenum,
+ f_init, f_end,
+ ts->gp_sculpt.cur_falloff);
}
else {
- /* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps, parented, diff_mat);
- changed |= true;
+ /* No falloff */
+ gso->mf_falloff = 1.0f;
}
- break;
- }
-
- case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_push_apply);
- break;
- }
- case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_pinch_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_twist_apply);
- break;
- }
-
- case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_randomize_apply);
- break;
+ /* affect strokes in this frame */
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
}
-
- default:
- printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
- break;
- }
- /* Triangulation must be calculated if changed */
- if (changed) {
- gps->flag |= GP_STROKE_RECALC_CACHES;
- gps->tot_triangles = 0;
}
}
+ else {
+ /* Apply to active frame's strokes */
+ gso->mf_falloff = 1.0f;
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
+ }
}
CTX_DATA_END;
@@ -1473,7 +1706,10 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
tGP_BrushEditData *gso = op->customdata;
- const int radius = gso->brush->size;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ const int radius = (
+ (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
+ gso->gp_brush->size * gso->pressure : gso->gp_brush->size);
float mousef[2];
int mouse[2];
bool changed = false;
@@ -1486,9 +1722,9 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt
gso->pressure = RNA_float_get(itemptr, "pressure");
if (RNA_boolean_get(itemptr, "pen_flip"))
- gso->flag |= GP_EDITBRUSH_FLAG_INVERT;
+ gso->flag |= GP_SCULPT_FLAG_INVERT;
else
- gso->flag &= ~GP_EDITBRUSH_FLAG_INVERT;
+ gso->flag &= ~GP_SCULPT_FLAG_INVERT;
/* Store coordinates as reference, if operator just started running */
@@ -1506,7 +1742,7 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt
/* Apply brush */
- if (gso->brush_type == GP_EDITBRUSH_TYPE_CLONE) {
+ if (gso->brush_type == GP_SCULPT_TYPE_CLONE) {
changed = gpsculpt_brush_apply_clone(C, gso);
}
else {
@@ -1516,6 +1752,7 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt
/* Updates */
if (changed) {
+ DEG_id_tag_update(&gso->gpd->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
@@ -1592,9 +1829,18 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
{
tGP_BrushEditData *gso = NULL;
const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
bool needs_timer = false;
float brush_rate = 0.0f;
+ /* the operator cannot work while play animation */
+ if (is_playing) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Cannot sculpt while play animation");
+
+ return OPERATOR_CANCELLED;
+ }
+
/* init painting data */
if (!gpsculpt_brush_init(C, op))
return OPERATOR_CANCELLED;
@@ -1604,22 +1850,22 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
/* initialise type-specific data (used for the entire session) */
switch (gso->brush_type) {
/* Brushes requiring timer... */
- case GP_EDITBRUSH_TYPE_THICKNESS:
+ case GP_SCULPT_TYPE_THICKNESS:
brush_rate = 0.01f; // XXX: hardcoded
needs_timer = true;
break;
- case GP_EDITBRUSH_TYPE_STRENGTH:
+ case GP_SCULPT_TYPE_STRENGTH:
brush_rate = 0.01f; // XXX: hardcoded
needs_timer = true;
break;
- case GP_EDITBRUSH_TYPE_PINCH:
+ case GP_SCULPT_TYPE_PINCH:
brush_rate = 0.001f; // XXX: hardcoded
needs_timer = true;
break;
- case GP_EDITBRUSH_TYPE_TWIST:
+ case GP_SCULPT_TYPE_TWIST:
brush_rate = 0.01f; // XXX: hardcoded
needs_timer = true;
break;
@@ -1691,13 +1937,13 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
case PADPLUSKEY:
if (event->shift) {
/* increase strength */
- gso->brush->strength += 0.05f;
- CLAMP_MAX(gso->brush->strength, 1.0f);
+ gso->gp_brush->strength += 0.05f;
+ CLAMP_MAX(gso->gp_brush->strength, 1.0f);
}
else {
/* increase brush size */
- gso->brush->size += 3;
- CLAMP_MAX(gso->brush->size, 300);
+ gso->gp_brush->size += 3;
+ CLAMP_MAX(gso->gp_brush->size, 300);
}
redraw_region = true;
@@ -1708,13 +1954,13 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
case PADMINUS:
if (event->shift) {
/* decrease strength */
- gso->brush->strength -= 0.05f;
- CLAMP_MIN(gso->brush->strength, 0.0f);
+ gso->gp_brush->strength -= 0.05f;
+ CLAMP_MIN(gso->gp_brush->strength, 0.0f);
}
else {
/* decrease brush size */
- gso->brush->size -= 3;
- CLAMP_MIN(gso->brush->size, 1);
+ gso->gp_brush->size -= 3;
+ CLAMP_MIN(gso->gp_brush->size, 1);
}
redraw_region = true;
@@ -1782,13 +2028,13 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
case PADPLUSKEY:
if (event->shift) {
/* increase strength */
- gso->brush->strength += 0.05f;
- CLAMP_MAX(gso->brush->strength, 1.0f);
+ gso->gp_brush->strength += 0.05f;
+ CLAMP_MAX(gso->gp_brush->strength, 1.0f);
}
else {
/* increase brush size */
- gso->brush->size += 3;
- CLAMP_MAX(gso->brush->size, 300);
+ gso->gp_brush->size += 3;
+ CLAMP_MAX(gso->gp_brush->size, 300);
}
redraw_region = true;
@@ -1799,13 +2045,13 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
case PADMINUS:
if (event->shift) {
/* decrease strength */
- gso->brush->strength -= 0.05f;
- CLAMP_MIN(gso->brush->strength, 0.0f);
+ gso->gp_brush->strength -= 0.05f;
+ CLAMP_MIN(gso->gp_brush->strength, 0.0f);
}
else {
/* decrease brush size */
- gso->brush->size -= 3;
- CLAMP_MIN(gso->brush->size, 1);
+ gso->gp_brush->size -= 3;
+ CLAMP_MIN(gso->gp_brush->size, 1);
}
redraw_region = true;
@@ -1819,7 +2065,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
case DOWNARROWKEY:
return OPERATOR_PASS_THROUGH;
- /* Camera/View Manipulations - Allowed */
+ /* Camera/View Gizmo's - Allowed */
/* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
@@ -1839,20 +2085,18 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
/* Redraw toolsettings (brush settings)? */
if (redraw_toolsettings) {
+ DEG_id_tag_update(&gso->gpd->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
}
return OPERATOR_RUNNING_MODAL;
}
-
-/* Operator --------------------------------------------- */
-
-void GPENCIL_OT_brush_paint(wmOperatorType *ot)
+void GPENCIL_OT_sculpt_paint(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Stroke Sculpt";
- ot->idname = "GPENCIL_OT_brush_paint";
+ ot->idname = "GPENCIL_OT_sculpt_paint";
ot->description = "Apply tweaks to strokes by painting over the strokes"; // XXX
/* api callbacks */
@@ -1872,7 +2116,5 @@ void GPENCIL_OT_brush_paint(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input",
"Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-
-/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 9f94cf3beb8..013b5ff7103 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -47,6 +47,7 @@
#include "BLT_translation.h"
#include "DNA_anim_types.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_node_types.h"
@@ -56,13 +57,13 @@
#include "DNA_view3d_types.h"
#include "DNA_gpencil_types.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_library.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
@@ -70,6 +71,9 @@
#include "BKE_screen.h"
#include "BKE_tracking.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "UI_interface.h"
#include "WM_api.h"
@@ -129,8 +133,9 @@ static const EnumPropertyItem prop_gpencil_convert_timingmodes[] = {
{0, NULL, 0, NULL, NULL},
};
-static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
- bool *UNUSED(r_free))
+static const EnumPropertyItem *rna_GPConvert_mode_items(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
{
if (RNA_boolean_get(ptr, "use_timing_data")) {
return prop_gpencil_convert_timingmodes;
@@ -144,28 +149,24 @@ static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), Poi
* - assumes that the active space is the 3D-View
*/
static void gp_strokepoint_convertcoords(
- bContext *C, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt,
+ bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt,
float p3d[3], const rctf *subrect)
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
bGPDspoint mypt, *pt;
float diff_mat[4][4];
pt = &mypt;
- /* calculate difference matrix if parent object */
- if (gpl->parent == NULL) {
- copy_v3_v3(&pt->x, &source_pt->x);
- }
- else {
- /* apply parent transform */
- float fpt[3];
- ED_gpencil_parent_location(gpl, diff_mat);
- mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
- copy_v3_v3(&pt->x, fpt);
- }
+ /* apply parent transform */
+ float fpt[3];
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
+ copy_v3_v3(&pt->x, fpt);
if (gps->flag & GP_STROKE_3DSPACE) {
@@ -173,7 +174,7 @@ static void gp_strokepoint_convertcoords(
copy_v3_v3(p3d, &pt->x);
}
else {
- const float *fp = ED_view3d_cursor3d_get(scene, v3d);
+ const float *fp = scene->cursor.location;
float mvalf[2];
/* get screen coordinate */
@@ -253,8 +254,9 @@ static void gp_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
}
/* add stroke point to timing buffers */
-static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_inittime, const float time,
- const float delta_dist)
+static void gp_timing_data_add_point(
+ tGpTimingData *gtd, const double stroke_inittime, const float time,
+ const float delta_dist)
{
float delta_time = 0.0f;
const int cur_point = gtd->cur_point;
@@ -289,9 +291,10 @@ static void gp_timing_data_add_point(tGpTimingData *gtd, const double stroke_ini
#define MIN_TIME_DELTA 0.02f
/* Loop over next points to find the end of the stroke, and compute */
-static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
- int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
- float *next_delta_time)
+static int gp_find_end_of_stroke_idx(
+ tGpTimingData *gtd, RNG *rng, const int idx, const int nbr_gaps,
+ int *nbr_done_gaps, const float tot_gaps_time, const float delta_time,
+ float *next_delta_time)
{
int j;
@@ -369,9 +372,10 @@ static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rn
}
}
-static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
- Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
- const int nbr_gaps, const float tot_gaps_time)
+static void gp_stroke_path_animation_add_keyframes(
+ Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu,
+ Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range,
+ const int nbr_gaps, const float tot_gaps_time)
{
/* Use actual recorded timing! */
const float time_start = (float)gtd->start_frame;
@@ -397,8 +401,9 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
start_stroke_idx = i;
delta_time = next_delta_time;
/* find end of that new stroke */
- end_stroke_idx = gp_find_end_of_stroke_idx(gtd, rng, i, nbr_gaps, &nbr_done_gaps,
- tot_gaps_time, delta_time, &next_delta_time);
+ end_stroke_idx = gp_find_end_of_stroke_idx(
+ gtd, rng, i, nbr_gaps, &nbr_done_gaps,
+ tot_gaps_time, delta_time, &next_delta_time);
/* This one should *never* be negative! */
end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
}
@@ -418,7 +423,7 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
cfra = last_valid_time + MIN_TIME_DELTA;
}
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
+ insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
last_valid_time = cfra;
}
else if (G.debug & G_DEBUG) {
@@ -430,7 +435,7 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
cfra = last_valid_time + MIN_TIME_DELTA;
}
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
+ insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
last_valid_time = cfra;
}
else {
@@ -438,7 +443,7 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
* and also far enough from (not yet added!) end_stroke keyframe!
*/
if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_BREAKDOWN, INSERTKEY_FAST);
+ insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_BREAKDOWN, INSERTKEY_FAST);
last_valid_time = cfra;
}
else if (G.debug & G_DEBUG) {
@@ -451,6 +456,7 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bAction *act;
@@ -476,7 +482,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
/* Ensure we have an F-Curve to add keyframes to */
act = verify_adt_action(bmain, (ID *)cu, true);
- fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true);
+ fcu = verify_fcurve(bmain, act, NULL, &ptr, "eval_time", 0, true);
if (G.debug & G_DEBUG) {
printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time);
@@ -493,7 +499,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
cu->ctime = 0.0f;
cfra = (float)gtd->start_frame;
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
+ insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
cu->ctime = cu->pathlen;
if (gtd->realtime) {
@@ -502,7 +508,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
else {
cfra = (float)gtd->end_frame;
}
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
+ insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
}
else {
/* Use actual recorded timing! */
@@ -528,8 +534,9 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
printf("GP Stroke Path Conversion: Starting keying!\n");
}
- gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, rng, time_range,
- nbr_gaps, tot_gaps_time);
+ gp_stroke_path_animation_add_keyframes(
+ depsgraph, reports, ptr, prop, fcu, cu, gtd, rng, time_range,
+ nbr_gaps, tot_gaps_time);
BLI_rng_free(rng);
}
@@ -548,7 +555,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
/* send updates */
- DAG_id_tag_update(&cu->id, 0);
+ DEG_id_tag_update(&cu->id, 0);
}
#undef MIN_TIME_DELTA
@@ -560,9 +567,10 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
/* convert stroke to 3d path */
/* helper */
-static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
+static void gp_stroke_to_path_add_point(
+ tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
+ const bool do_gtd, const double inittime, const float time,
+ const float width, const float rad_fac, float minmax_weights[2])
{
copy_v3_v3(bp->vec, p);
bp->vec[3] = 1.0f;
@@ -585,9 +593,10 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl
}
}
-static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
+static void gp_stroke_to_path(
+ bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+ float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
+ const bool add_end_point, tGpTimingData *gtd)
{
bGPDspoint *pt;
Nurb *nu = (curnu) ? *curnu : NULL;
@@ -649,7 +658,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
bp = &nu->bp[old_nbp - 1];
/* First point */
- gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
if (prev_bp) {
interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
if (do_gtd) {
@@ -664,13 +673,14 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
}
}
bp++;
- gp_stroke_to_path_add_point(gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
+ gp_stroke_to_path_add_point(
+ gtd, bp, p1, (bp - 1)->vec, do_gtd, gps->prev->inittime, dt1,
+ 0.0f, rad_fac, minmax_weights);
/* Second point */
/* Note dt2 is always negative, which marks the gap. */
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -691,9 +701,9 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
float p[3], next_p[3];
float dt = 0.0f;
- gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -722,13 +732,14 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
i++, pt++, bp++)
{
float p[3];
- float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
+ float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
/* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, p, subrect);
- gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time,
- width, rad_fac, minmax_weights);
+ 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);
prev_bp = bp;
}
@@ -767,10 +778,11 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv
/* convert stroke to 3d bezier */
/* helper */
-static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
- const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
- const bool do_gtd, const double inittime, const float time,
- const float width, const float rad_fac, float minmax_weights[2])
+static void gp_stroke_to_bezier_add_point(
+ tGpTimingData *gtd, BezTriple *bezt,
+ const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
+ const bool do_gtd, const double inittime, const float time,
+ const float width, const float rad_fac, float minmax_weights[2])
{
copy_v3_v3(bezt->vec[0], h1);
copy_v3_v3(bezt->vec[1], p);
@@ -795,9 +807,10 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
}
}
-static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
- float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
- const bool add_end_point, tGpTimingData *gtd)
+static void gp_stroke_to_bezier(
+ bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu,
+ float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point,
+ const bool add_end_point, tGpTimingData *gtd)
{
bGPDspoint *pt;
Nurb *nu = (curnu) ? *curnu : NULL;
@@ -837,12 +850,12 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
/* get initial coordinates */
pt = gps->points;
if (tot) {
- gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
if (tot > 1) {
- gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
}
if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
}
}
@@ -916,15 +929,17 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
bezt++;
- gp_stroke_to_bezier_add_point(gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
- 0.0f, rad_fac, minmax_weights);
+ gp_stroke_to_bezier_add_point(
+ gtd, bezt, p1, h1, h2, (bezt - 1)->vec[1], do_gtd, gps->prev->inittime, dt1,
+ 0.0f, rad_fac, minmax_weights);
/* Second point */
interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
bezt++;
- gp_stroke_to_bezier_add_point(gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
- 0.0f, rad_fac, minmax_weights);
+ gp_stroke_to_bezier_add_point(
+ gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2,
+ 0.0f, rad_fac, minmax_weights);
old_nbezt += 2;
copy_v3_v3(p3d_prev, p2);
@@ -948,8 +963,9 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
bezt = &nu->bezt[old_nbezt];
- gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
+ gp_stroke_to_bezier_add_point(
+ gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt,
+ 0.0f, rad_fac, minmax_weights);
old_nbezt++;
copy_v3_v3(p3d_prev, p);
@@ -961,7 +977,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
/* add points */
for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
- float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC;
+ float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
if (i || old_nbezt) {
interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
@@ -977,15 +993,16 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
}
- gp_stroke_to_bezier_add_point(gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
- do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
+ gp_stroke_to_bezier_add_point(
+ gtd, bezt, p3d_cur, h1, h2, prev_bezt ? prev_bezt->vec[1] : p3d_cur,
+ do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights);
/* shift coord vects */
copy_v3_v3(p3d_prev, p3d_cur);
copy_v3_v3(p3d_cur, p3d_next);
if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
}
prev_bezt = bezt;
@@ -1016,8 +1033,9 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu
interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
/* Note bezt has already been incremented in main loop above, so it points to the right place. */
- gp_stroke_to_bezier_add_point(gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
- 0.0f, rad_fac, minmax_weights);
+ gp_stroke_to_bezier_add_point(
+ gtd, bezt, p, h1, h2, prev_bezt->vec[1], do_gtd, gps->inittime, dt,
+ 0.0f, rad_fac, minmax_weights);
}
/* must calculate handles or else we crash */
@@ -1110,7 +1128,8 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect)
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {
Scene *scene = CTX_data_scene(C);
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, subrect, true); /* no shift */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, subrect, true); /* no shift */
return 1;
}
}
@@ -1119,18 +1138,22 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect)
}
/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
-static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
- const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
+static void gp_layer_to_curve(
+ bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode,
+ const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
{
struct Main *bmain = CTX_data_main(C);
- View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Collection *collection = CTX_data_collection(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
bGPDstroke *gps, *prev_gps = NULL;
Object *ob;
Curve *cu;
Nurb *nu = NULL;
- Base *base_orig = BASACT, *base_new = NULL;
+ Base *base_new = NULL;
float minmax_weights[2] = {1.0f, 0.0f};
/* camera framing */
@@ -1154,7 +1177,8 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
*/
ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
- base_new = BKE_scene_base_add(scene, ob);
+ BKE_collection_object_add(bmain, collection, ob);
+ base_new = BKE_view_layer_base_find(view_layer, ob);
cu->flag |= CU_3D;
@@ -1183,13 +1207,15 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
switch (mode) {
case GP_STROKECONVERT_PATH:
- gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
+ gp_stroke_to_path(
+ C, gpd, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ add_start_point, add_end_point, gtd);
break;
case GP_STROKECONVERT_CURVE:
case GP_STROKECONVERT_POLY: /* convert after */
- gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
- add_start_point, add_end_point, gtd);
+ gp_stroke_to_bezier(
+ C, gpd, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch,
+ add_start_point, add_end_point, gtd);
break;
default:
BLI_assert(!"invalid mode");
@@ -1218,8 +1244,8 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
}
/* set the layer and select */
- base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene);
- base_new->flag = ob->flag = base_new->flag | SELECT;
+ base_new->flag |= SELECT;
+ BKE_scene_object_base_flag_sync_from_base(base_new);
}
/* --- */
@@ -1229,7 +1255,9 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
*/
static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
bGPDframe *gpf = NULL;
bGPDstroke *gps = NULL;
bGPDspoint *pt;
@@ -1237,7 +1265,7 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe
int i;
bool valid = true;
- if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first))
+ if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV)) || !(gps = gpf->strokes.first))
return false;
do {
@@ -1285,19 +1313,22 @@ static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UN
static bool gp_convert_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
bGPDlayer *gpl = NULL;
bGPDframe *gpf = NULL;
ScrArea *sa = CTX_wm_area(C);
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
/* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
* and if we are not in edit mode!
*/
return ((sa && sa->spacetype == SPACE_VIEW3D) &&
(gpl = BKE_gpencil_layer_getactive(gpd)) &&
- (gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) &&
+ (gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV)) &&
(gpf->strokes.first) &&
- (scene->obedit == NULL));
+ (OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL));
}
static int gp_convert_layer_exec(bContext *C, wmOperator *op)
@@ -1364,6 +1395,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 1bdeeefe223..236d6964c26 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -46,18 +46,31 @@
#include "BLT_translation.h"
+#include "DNA_anim_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
-#include "DNA_gpencil_types.h"
-#include "BKE_colortools.h"
+#include "BKE_animsys.h"
+#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_fcurve.h"
+#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -72,8 +85,13 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "ED_object.h"
#include "ED_gpencil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
/* ************************************************ */
@@ -84,9 +102,9 @@
/* add new datablock - wrapper around API */
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- ToolSettings *ts = CTX_data_tool_settings(C);
+ PointerRNA gpd_owner = {{NULL}};
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
+ bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
@@ -94,19 +112,36 @@ static int gp_data_add_exec(bContext *C, wmOperator *op)
}
else {
/* decrement user count and add new datablock */
- bGPdata *gpd = (*gpd_ptr);
+ /* TODO: if a datablock exists, we should make a copy of it instead of starting fresh (as in other areas) */
+ Main *bmain = CTX_data_main(C);
- id_us_min(&gpd->id);
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+ /* decrement user count of old GP datablock */
+ if (*gpd_ptr) {
+ bGPdata *gpd = (*gpd_ptr);
+ id_us_min(&gpd->id);
+ }
- /* if not exist brushes, create a new set */
- if (ts) {
- if (BLI_listbase_is_empty(&ts->gp_brushes)) {
- /* create new brushes */
- BKE_gpencil_brush_init_presets(ts);
- }
+ /* add new datablock, with a single layer ready to use (so users don't have to perform an extra step) */
+ if (is_annotation) {
+ bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
+ *gpd_ptr = gpd;
+
+ /* tag for annotations */
+ gpd->flag |= GP_DATA_ANNOTATIONS;
+
+ /* add new layer (i.e. a "note") */
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
}
+ else {
+ /* GP Object Case - This shouldn't happen! */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+
+ /* add default sets of colors and brushes */
+ ED_gpencil_add_defaults(C);
+ /* add new layer */
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ }
}
/* notifiers */
@@ -185,30 +220,46 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
/* add new layer - wrapper around API */
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
- ToolSettings *ts = CTX_data_tool_settings(C);
+ PointerRNA gpd_owner = {{NULL}};
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner);
+ bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd_ptr == NULL) {
BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
return OPERATOR_CANCELLED;
}
- if (*gpd_ptr == NULL)
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
- /* if not exist brushes, create a new set */
- if (ts) {
- if (BLI_listbase_is_empty(&ts->gp_brushes)) {
- /* create new brushes */
- BKE_gpencil_brush_init_presets(ts);
+ if (*gpd_ptr == NULL) {
+ Main *bmain = CTX_data_main(C);
+ if (is_annotation) {
+ /* Annotations */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations"));
+
+ /* mark as annotation */
+ (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS;
+ }
+ else {
+ /* GP Object */
+ /* NOTE: This shouldn't actually happen in practice */
+ *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
+
+ /* add default sets of colors and brushes */
+ ED_gpencil_add_defaults(C);
}
}
/* add new layer now */
- BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ if (is_annotation) {
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true);
+ }
+ else {
+ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
+ }
/* notifiers */
+ bGPdata *gpd = *gpd_ptr;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -219,7 +270,7 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add New Layer";
ot->idname = "GPENCIL_OT_layer_add";
- ot->description = "Add new Grease Pencil layer for the active Grease Pencil data-block";
+ ot->description = "Add new layer or note for the active data-block";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -257,6 +308,7 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op)
BKE_gpencil_layer_delete(gpd, gpl);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -288,7 +340,7 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- int direction = RNA_enum_get(op->ptr, "type");
+ const int direction = RNA_enum_get(op->ptr, "type") * -1;
/* sanity checks */
if (ELEM(NULL, gpd, gpl))
@@ -296,6 +348,7 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op)
BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
@@ -346,6 +399,7 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
BKE_gpencil_layer_setactive(gpd, new_layer);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -366,6 +420,372 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ********************* Duplicate Layer in a new object ************************** */
+enum {
+ GP_LAYER_COPY_OBJECT_ALL_FRAME = 0,
+ GP_LAYER_COPY_OBJECT_ACT_FRAME = 1
+};
+
+static bool gp_layer_duplicate_object_poll(bContext *C)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL))
+ return false;
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ if (gpl == NULL)
+ return false;
+
+ /* check there are more grease pencil objects */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if ((base->object != ob) && (base->object->type == OB_GPENCIL))
+ return true;
+ }
+
+ return false;
+}
+
+static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "object", name);
+
+ if (name[0] == '\0') {
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ Object *ob_src = CTX_data_active_object(C);
+ bGPdata *gpd_src = (bGPdata *)ob_src->data;
+ bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
+ return OPERATOR_CANCELLED;
+ }
+ /* cannot copy itself and check destination type */
+ if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
+
+ /* make copy of layer */
+ bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
+ gpl_dst->prev = gpl_dst->next = NULL;
+ BLI_addtail(&gpd_dst->layers, gpl_dst);
+ BLI_uniquename(&gpd_dst->layers, gpl_dst, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_dst->info));
+
+ /* copy frames */
+ BLI_listbase_clear(&gpl_dst->frames);
+ for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
+
+ if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
+ continue;
+ }
+
+ /* make a copy of source frame */
+ bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
+ gpf_dst->prev = gpf_dst->next = NULL;
+ BLI_addtail(&gpl_dst->frames, gpf_dst);
+
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+
+ /* check if material is in destination object,
+ * otherwise add the slot with the material
+ */
+ Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
+ int idx = BKE_gpencil_get_material_index(ob_dst, ma_src);
+ if (idx == 0) {
+ BKE_object_material_slot_add(bmain, ob_dst);
+ assign_material(bmain, ob_dst, ma_src, ob_dst->totcol, BKE_MAT_ASSIGN_USERPREF);
+ idx = ob_dst->totcol;
+ }
+
+ /* reasign the stroke material to the right slot in destination object */
+ gps_dst->mat_nr = idx - 1;
+
+ /* add new stroke to frame */
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
+ }
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd_dst->id, OB_RECALC_OB | OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE);
+ DEG_id_tag_update(&ob_dst->id, DEG_TAG_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
+{
+ static const EnumPropertyItem copy_mode[] = {
+ {GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""},
+ {GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Duplicate Layer to new Object";
+ ot->idname = "GPENCIL_OT_layer_duplicate_object";
+ ot->description = "Make a copy of the active Grease Pencil layer to new object";
+
+ /* callbacks */
+ ot->exec = gp_layer_duplicate_object_exec;
+ ot->poll = gp_layer_duplicate_object_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_string(ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", "");
+}
+
+/* ********************* Duplicate Frame ************************** */
+enum {
+ GP_FRAME_DUP_ACTIVE = 0,
+ GP_FRAME_DUP_ALL = 1
+};
+
+static int gp_frame_duplicate_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl))
+ return OPERATOR_CANCELLED;
+
+ if (mode == 0) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
+ }
+ else {
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
+ }
+ }
+
+ }
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_frame_duplicate(wmOperatorType *ot)
+{
+ static const EnumPropertyItem duplicate_mode[] = {
+ {GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only"},
+ {GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Duplicate Frame";
+ ot->idname = "GPENCIL_OT_frame_duplicate";
+ ot->description = "Make a copy of the active Grease Pencil Frame";
+
+ /* callbacks */
+ ot->exec = gp_frame_duplicate_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
+}
+
+/* ********************* Clean Fill Boundaries on Frame ************************** */
+enum {
+ GP_FRAME_CLEAN_FILL_ACTIVE = 0,
+ GP_FRAME_CLEAN_FILL_ALL = 1
+};
+
+static int gp_frame_clean_fill_exec(bContext *C, wmOperator *op)
+{
+ bool changed = false;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (mode == GP_FRAME_CLEAN_FILL_ALL) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || (mode == GP_FRAME_CLEAN_FILL_ALL)) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete strokes which are no fill */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* free stroke */
+ if (gps->flag & GP_STROKE_NOFILL) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_SAFE_FREE(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot)
+{
+ static const EnumPropertyItem duplicate_mode[] = {
+ {GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only"},
+ {GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Clean Fill Boundaries";
+ ot->idname = "GPENCIL_OT_frame_clean_fill";
+ ot->description = "Remove 'no fill' boundary strokes";
+
+ /* callbacks */
+ ot->exec = gp_frame_clean_fill_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", "");
+}
+
+/* ********************* Clean Loose Boundaries on Frame ************************** */
+static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
+{
+ bool changed = false;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int limit = RNA_int_get(op->ptr, "limit");
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ bGPDstroke *gpsn = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ /* simply delete strokes which are no loose */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* free stroke */
+ if (gps->totpoints <= limit) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_SAFE_FREE(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clean Loose points";
+ ot->idname = "GPENCIL_OT_frame_clean_loose";
+ ot->description = "Remove loose points";
+
+ /* callbacks */
+ ot->exec = gp_frame_clean_loose_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "limit", 1, 1, INT_MAX, "Limit", "Number of points to consider stroke as loose", 1, INT_MAX);
+}
+
/* *********************** Hide Layers ******************************** */
static int gp_hide_exec(bContext *C, wmOperator *op)
@@ -394,6 +814,7 @@ static int gp_hide_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -481,6 +902,7 @@ static int gp_reveal_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -521,6 +943,7 @@ static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -558,6 +981,7 @@ static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -630,6 +1054,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -659,8 +1084,8 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
static int gp_merge_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl_current = BKE_gpencil_layer_getactive(gpd);
- bGPDlayer *gpl_next = gpl_current->next;
+ bGPDlayer *gpl_next = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl_current = gpl_next->prev;
if (ELEM(NULL, gpd, gpl_current, gpl_next)) {
BKE_report(op->reports, RPT_ERROR, "No layers to merge");
@@ -673,22 +1098,28 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op)
BLI_ghash_insert(gh_frames_cur, POINTER_FROM_INT(gpf->framenum), gpf);
}
- /* read all frames from next layer */
+ /* read all frames from next layer and add any missing in current layer */
for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
- /* try to find frame in active layer */
+ /* try to find frame in current layer */
bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, POINTER_FROM_INT(gpf->framenum));
if (!frame) {
- /* nothing found, create new */
+ bGPDframe *actframe = BKE_gpencil_layer_getframe(gpl_current, gpf->framenum, GP_GETFRAME_USE_PREV);
frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
+ /* duplicate strokes of current active frame */
+ if (actframe) {
+ BKE_gpencil_frame_copy_strokes(actframe, frame);
+ }
}
/* add to tail all strokes */
BLI_movelisttolist(&frame->strokes, &gpf->strokes);
}
+
/* Now delete next layer */
BKE_gpencil_layer_delete(gpd, gpl_next);
BLI_ghash_free(gh_frames_cur, NULL, NULL);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -750,6 +1181,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
BKE_gpencil_layer_setactive(gpd, gpl);
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -788,6 +1220,7 @@ enum {
static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
{
+ Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
bGPDstroke *gps;
@@ -797,79 +1230,95 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- bGPDframe *gpf = gpl->actframe;
- /* temp listbase to store selected strokes */
- ListBase selected = {NULL};
const int direction = RNA_enum_get(op->ptr, "direction");
- /* verify if any selected stroke is in the extreme of the stack and select to move */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
- /* some stroke is already at front*/
- if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
- if (gps == gpf->strokes.last) {
- return OPERATOR_CANCELLED;
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* temp listbase to store selected strokes by layer */
+ ListBase selected = { NULL };
+ bGPDframe *gpf = gpl->actframe;
+ if (gpl->flag & GP_LAYER_LOCKED) {
+ continue;
+ }
+
+ if (gpf == NULL) {
+ continue;
+ }
+ bool gpf_lock = false;
+ /* verify if any selected stroke is in the extreme of the stack and select to move */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
}
- }
- /* some stroke is already at botom */
- if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
- if (gps == gpf->strokes.first) {
- return OPERATOR_CANCELLED;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* some stroke is already at front*/
+ if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) {
+ if (gps == gpf->strokes.last) {
+ gpf_lock = true;
+ continue;
+ }
+ }
+ /* some stroke is already at botom */
+ if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) {
+ if (gps == gpf->strokes.first) {
+ gpf_lock = true;
+ continue;
+ }
+ }
+ /* add to list (if not locked) */
+ if (!gpf_lock) {
+ BLI_addtail(&selected, BLI_genericNodeN(gps));
}
}
- /* add to list */
- BLI_addtail(&selected, BLI_genericNodeN(gps));
}
- }
-
- /* Now do the movement of the stroke */
- switch (direction) {
- /* Bring to Front */
- case GP_STROKE_MOVE_TOP:
- for (LinkData *link = selected.first; link; link = link->next) {
- gps = link->data;
- BLI_remlink(&gpf->strokes, gps);
- BLI_addtail(&gpf->strokes, gps);
- }
- break;
- /* Bring Forward */
- case GP_STROKE_MOVE_UP:
- for (LinkData *link = selected.last; link; link = link->prev) {
- gps = link->data;
- BLI_listbase_link_move(&gpf->strokes, gps, 1);
- }
- break;
- /* Send Backward */
- case GP_STROKE_MOVE_DOWN:
- for (LinkData *link = selected.first; link; link = link->next) {
- gps = link->data;
- BLI_listbase_link_move(&gpf->strokes, gps, -1);
- }
- break;
- /* Send to Back */
- case GP_STROKE_MOVE_BOTTOM:
- for (LinkData *link = selected.last; link; link = link->prev) {
- gps = link->data;
- BLI_remlink(&gpf->strokes, gps);
- BLI_addhead(&gpf->strokes, gps);
+ /* Now do the movement of the stroke */
+ if (!gpf_lock) {
+ switch (direction) {
+ /* Bring to Front */
+ case GP_STROKE_MOVE_TOP:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addtail(&gpf->strokes, gps);
+ }
+ break;
+ /* Bring Forward */
+ case GP_STROKE_MOVE_UP:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_listbase_link_move(&gpf->strokes, gps, 1);
+ }
+ break;
+ /* Send Backward */
+ case GP_STROKE_MOVE_DOWN:
+ for (LinkData *link = selected.first; link; link = link->next) {
+ gps = link->data;
+ BLI_listbase_link_move(&gpf->strokes, gps, -1);
+ }
+ break;
+ /* Send to Back */
+ case GP_STROKE_MOVE_BOTTOM:
+ for (LinkData *link = selected.last; link; link = link->prev) {
+ gps = link->data;
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addhead(&gpf->strokes, gps);
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- break;
- default:
- BLI_assert(0);
- break;
+ }
+ BLI_freelistN(&selected);
}
- BLI_freelistN(&selected);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -890,58 +1339,92 @@ void GPENCIL_OT_stroke_arrange(wmOperatorType *ot)
ot->idname = "GPENCIL_OT_stroke_arrange";
ot->description = "Arrange selected strokes up/down in the drawing order of the active layer";
- /* api callbacks */
+ /* callbacks */
ot->exec = gp_stroke_arrange_exec;
ot->poll = gp_active_layer_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* properties */
ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", "");
}
+
/* ******************* Move Stroke to new color ************************** */
-static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op))
+static int gp_stroke_change_color_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
+ Material *ma = NULL;
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "material", name);
+
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette;
- bGPDpalettecolor *color;
+ Object *ob = CTX_data_active_object(C);
+ if (name[0] == '\0') {
+ ma = give_current_material(ob, ob->actcol);
+ }
+ else {
+ ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
+ if (ma == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ /* try to find slot */
+ int idx = BKE_gpencil_get_material_index(ob, ma) - 1;
+ if (idx < 0) {
+ return OPERATOR_CANCELLED;
+ }
/* 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)) {
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ if (ELEM(NULL, ma)) {
return OPERATOR_CANCELLED;
}
/* loop all strokes */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
- continue;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- /* asign new color (only if different) */
- if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) {
- BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname));
- gps->palcolor = color;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
+
+ /* assign new color */
+ gps->mat_nr = idx;
}
}
}
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+
}
}
+ CTX_DATA_END;
+
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -952,11 +1435,17 @@ 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";
+ ot->description = "Move selected strokes to active material";
- /* api callbacks */
+ /* callbacks */
ot->exec = gp_stroke_change_color_exec;
ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_string(ot->srna, "material", NULL, MAX_ID_NAME - 2, "Material", "Name of the material");
+
}
/* ******************* Lock color of non selected Strokes colors ************************** */
@@ -964,19 +1453,20 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette;
+
+ Object *ob = CTX_data_active_object(C);
+
+ short *totcol = give_totcolp(ob);
/* sanity checks */
if (ELEM(NULL, gpd))
return OPERATOR_CANCELLED;
- palette = BKE_gpencil_palette_getactive(gpd);
- if (ELEM(NULL, palette))
- return OPERATOR_CANCELLED;
-
/* first lock all colors */
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag |= PC_COLOR_LOCKED;
+ for (short i = 0; i < *totcol; i++) {
+ Material *tmp_ma = give_current_material(ob, i + 1);
+ tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&tmp_ma->id, DEG_TAG_COPY_ON_WRITE);
}
/* loop all selected strokes and unlock any color */
@@ -991,14 +1481,22 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
/* unlock color */
- if (gps->palcolor != NULL) {
- gps->palcolor->flag &= ~PC_COLOR_LOCKED;
- }
+ Material *tmp_ma = give_current_material(ob, gps->mat_nr + 1);
+
+ tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&tmp_ma->id, DEG_TAG_COPY_ON_WRITE);
}
}
}
}
+ /* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1014,25 +1512,18 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
/* api callbacks */
ot->exec = gp_stroke_lock_color_exec;
ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ************************************************ */
/* Drawing Brushes Operators */
-/* ******************* Add New Brush ************************ */
-
-/* add new brush - wrapper around API */
-static int gp_brush_add_exec(bContext *C, wmOperator *op)
+/* ******************* Brush create presets ************************** */
+static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- /* if there's no existing container */
- if (ts == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
- return OPERATOR_CANCELLED;
- }
- /* add new brush now */
- BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true);
+ BKE_brush_gpencil_presets(C);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -1040,513 +1531,665 @@ static int gp_brush_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_add(wmOperatorType *ot)
+void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Brush";
- ot->idname = "GPENCIL_OT_brush_add";
- ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil data-block";
+ ot->name = "Create Preset Brushes";
+ ot->idname = "GPENCIL_OT_brush_presets_create";
+ ot->description = "Create a set of predefined Grease Pencil drawing brushes";
+ /* api callbacks */
+ ot->exec = gp_brush_presets_create_exec;
+
+ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_brush_add_exec;
- ot->poll = gp_add_poll;
}
-/* ******************* Remove Active Brush ************************* */
+/*********************** Vertex Groups ***********************************/
-static int gp_brush_remove_exec(bContext *C, wmOperator *op)
+static bool gpencil_vertex_group_poll(bContext *C)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
-
- /* sanity checks */
- if (ELEM(NULL, ts, brush))
- return OPERATOR_CANCELLED;
+ Object *ob = CTX_data_active_object(C);
- if (BLI_listbase_count_at_most(&ts->gp_brushes, 2) < 2) {
- BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush, unable to delete the last one");
- return OPERATOR_CANCELLED;
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
+ if (ELEM(ob->mode,
+ OB_MODE_GPENCIL_EDIT,
+ OB_MODE_GPENCIL_SCULPT))
+ {
+ return true;
+ }
+ }
}
-
- /* 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;
+ return false;
}
-void GPENCIL_OT_brush_remove(wmOperatorType *ot)
+static bool gpencil_vertex_group_weight_poll(bContext *C)
{
- /* 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;
+ Object *ob = CTX_data_active_object(C);
- /* 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);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) {
+ if (ob->mode == OB_MODE_GPENCIL_WEIGHT) {
+ return true;
+ }
+ }
+ }
- return OPERATOR_INTERFACE;
+ return false;
}
-static int gp_brush_change_exec(bContext *C, wmOperator *op)
+static int gpencil_vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(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);
+ Object *ob = CTX_data_active_object(C);
- if (brush == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent brush (index = %d)", brush_num);
- return OPERATOR_CANCELLED;
- }
- }
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data))
+ return OPERATOR_CANCELLED;
- /* Set active brush */
- BKE_gpencil_brush_setactive(ts, brush);
+ ED_gpencil_vgroup_assign(C, ob, ts->vgroup_weight);
- /* updates */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* notifiers */
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_change(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_assign(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Change Brush";
- ot->idname = "GPENCIL_OT_brush_change";
- ot->description = "Change active Grease Pencil drawing brush";
+ ot->name = "Assign to Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_assign";
+ ot->description = "Assign the selected vertices to the active vertex group";
- /* callbacks */
- ot->invoke = gp_brush_change_invoke;
- ot->exec = gp_brush_change_exec;
- ot->poll = gp_active_brush_poll;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_assign_exec;
/* 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)
+/* remove point from vertex group */
+static int gpencil_vertex_group_remove_from_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
-
- int direction = RNA_enum_get(op->ptr, "type");
+ Object *ob = CTX_data_active_object(C);
/* sanity checks */
- if (ELEM(NULL, ts, brush)) {
+ if (ELEM(NULL, ob, ob->data))
return OPERATOR_CANCELLED;
- }
- /* up or down? */
- if (direction == GP_BRUSH_MOVE_UP) {
- /* up */
- BLI_remlink(&ts->gp_brushes, brush);
- BLI_insertlinkbefore(&ts->gp_brushes, brush->prev, brush);
- }
- else if (direction == GP_BRUSH_MOVE_DOWN) {
- /* down */
- BLI_remlink(&ts->gp_brushes, brush);
- BLI_insertlinkafter(&ts->gp_brushes, brush->next, brush);
- }
- else {
- BLI_assert(0);
- }
+ ED_gpencil_vgroup_remove(C, ob);
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_move(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_remove_from(wmOperatorType *ot)
{
- static const EnumPropertyItem slot_move[] = {
- {GP_BRUSH_MOVE_UP, "UP", 0, "Up", ""},
- {GP_BRUSH_MOVE_DOWN, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL }
- };
-
/* identifiers */
- ot->name = "Move Brush";
- ot->idname = "GPENCIL_OT_brush_move";
- ot->description = "Move the active Grease Pencil drawing brush up/down in the list";
+ ot->name = "Remove from Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_remove_from";
+ ot->description = "Remove the selected vertices from active or all vertex group(s)";
/* api callbacks */
- ot->exec = gp_brush_move_exec;
- ot->poll = gp_active_brush_poll;
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_remove_from_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", slot_move, GP_BRUSH_MOVE_UP, "Type", "");
}
-/* ******************* Brush create presets ************************** */
-
-static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- BKE_gpencil_brush_init_presets(ts);
+ Object *ob = CTX_data_active_object(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, ob, ob->data))
+ return OPERATOR_CANCELLED;
+
+ ED_gpencil_vgroup_select(C, ob);
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_select(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Create Preset Brushes";
- ot->idname = "GPENCIL_OT_brush_presets_create";
- ot->description = "Create a set of predefined Grease Pencil drawing brushes";
+ ot->name = "Select Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_select";
+ ot->description = "Select all the vertices assigned to the active vertex group";
/* api callbacks */
- ot->exec = gp_brush_presets_create_exec;
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_select_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
}
-/* ***************** Copy Brush ************************ */
-
-static int gp_brush_copy_exec(bContext *C, wmOperator *op)
+static int gpencil_vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
-
- /* if there's no existing container */
- if (ts == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go");
- return OPERATOR_CANCELLED;
- }
-
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
- bGPDbrush *newbrush;
+ Object *ob = CTX_data_active_object(C);
/* sanity checks */
- if (ELEM(NULL, brush))
+ if (ELEM(NULL, ob, ob->data))
return OPERATOR_CANCELLED;
- /* create a brush and duplicate data */
- newbrush = BKE_gpencil_brush_addnew(ts, brush->info, true);
- newbrush->thickness = brush->thickness;
- newbrush->draw_smoothfac = brush->draw_smoothfac;
- newbrush->draw_smoothlvl = brush->draw_smoothlvl;
- newbrush->sublevel = brush->sublevel;
- newbrush->flag = brush->flag;
- newbrush->draw_sensitivity = brush->draw_sensitivity;
- newbrush->draw_strength = brush->draw_strength;
- newbrush->draw_jitter = brush->draw_jitter;
- newbrush->draw_angle = brush->draw_angle;
- newbrush->draw_angle_factor = brush->draw_angle_factor;
- newbrush->draw_random_press = brush->draw_random_press;
- newbrush->draw_random_sub = brush->draw_random_sub;
-
- /* free automatic curves created by default (replaced by copy) */
- curvemapping_free(newbrush->cur_sensitivity);
- curvemapping_free(newbrush->cur_strength);
- curvemapping_free(newbrush->cur_jitter);
-
- /* make a copy of curves */
- newbrush->cur_sensitivity = curvemapping_copy(brush->cur_sensitivity);
- newbrush->cur_strength = curvemapping_copy(brush->cur_strength);
- newbrush->cur_jitter = curvemapping_copy(brush->cur_jitter);
-
- BKE_gpencil_brush_setactive(ts, newbrush);
+ ED_gpencil_vgroup_deselect(C, ob);
+
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_copy(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_deselect(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy Brush";
- ot->idname = "GPENCIL_OT_brush_copy";
- ot->description = "Copy current Grease Pencil drawing brush";
+ ot->name = "Deselect Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_deselect";
+ ot->description = "Deselect all selected vertices assigned to the active vertex group";
- /* callbacks */
- ot->exec = gp_brush_copy_exec;
- ot->poll = gp_active_brush_poll;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_poll;
+ ot->exec = gpencil_vertex_group_deselect_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Select Brush ************************ */
-
-static int gp_brush_select_exec(bContext *C, wmOperator *op)
+/* invert */
+static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *UNUSED(op))
{
ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
- /* if there's no existing container */
- if (ts == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere to go");
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data))
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)) {
+ MDeformVert *dvert;
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
return OPERATOR_CANCELLED;
- }
- BKE_gpencil_brush_setactive(ts, brush);
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ MDeformWeight *dw = defvert_find_index(dvert, def_nr);
+ if (dw == NULL) {
+ defvert_add_index_notest(dvert, def_nr, 1.0f);
+ }
+ else if (dw->weight == 1.0f) {
+ defvert_remove_group(dvert, dw);
+ }
+ else {
+ dw->weight = 1.0f - dw->weight;
+ }
+ }
+ }
+ CTX_DATA_END;
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_select(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_invert(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select Brush";
- ot->idname = "GPENCIL_OT_brush_select";
- ot->description = "Select a Grease Pencil drawing brush";
+ ot->name = "Invert Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_invert";
+ ot->description = "Invert weights to the active vertex group";
- /* callbacks */
- ot->exec = gp_brush_select_exec;
- ot->poll = gp_active_brush_poll;
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_weight_poll;
+ ot->exec = gpencil_vertex_group_invert_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX);
}
-/* ************************************************ */
-/* Palette Operators */
+/* smooth */
+static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op)
+{
+ const float fac = RNA_float_get(op->ptr, "factor");
+ const int repeat = RNA_int_get(op->ptr, "repeat");
-/* ******************* Add New Palette ************************ */
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
-/* add new palette - wrapper around API */
-static int gp_palette_add_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
+ /* sanity checks */
+ if (ELEM(NULL, ts, ob, ob->data))
+ return OPERATOR_CANCELLED;
- /* 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");
+ bGPDspoint *pta, *ptb, *ptc;
+ MDeformVert *dverta, *dvertb;
+
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
return OPERATOR_CANCELLED;
- }
- if (*gpd_ptr == NULL)
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
- /* add new palette now */
- BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ for (int s = 0; s < repeat; s++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ /* previous point */
+ if (i > 0) {
+ pta = &gps->points[i - 1];
+ dverta = &gps->dvert[i - 1];
+ }
+ else {
+ pta = &gps->points[i];
+ dverta = &gps->dvert[i];
+ }
+ /* current */
+ ptb = &gps->points[i];
+ dvertb = &gps->dvert[i];
+ /* next point */
+ if (i + 1 < gps->totpoints) {
+ ptc = &gps->points[i + 1];
+ }
+ else {
+ ptc = &gps->points[i];
+ }
+
+ float wa = defvert_find_weight(dverta, def_nr);
+ float wb = defvert_find_weight(dvertb, def_nr);
+
+ /* the optimal value is the corresponding to the interpolation of the weight
+ * at the distance of point b
+ */
+ const float opfac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ const float optimal = interpf(wa, wb, opfac);
+ /* Based on influence factor, blend between original and optimal */
+ MDeformWeight *dw = defvert_verify_index(dvertb, def_nr);
+ if (dw) {
+ dw->weight = interpf(wb, optimal, fac);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palette_add(wmOperatorType *ot)
+void GPENCIL_OT_vertex_group_smooth(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Palette";
- ot->idname = "GPENCIL_OT_palette_add";
- ot->description = "Add new Grease Pencil palette for the active Grease Pencil data-block";
+ ot->name = "Smooth Vertex Group";
+ ot->idname = "GPENCIL_OT_vertex_group_smooth";
+ ot->description = "Smooth weights to the active vertex group";
+
+ /* api callbacks */
+ ot->poll = gpencil_vertex_group_weight_poll;
+ ot->exec = gpencil_vertex_group_smooth_exec;
+ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* callbacks */
- ot->exec = gp_palette_add_exec;
- ot->poll = gp_add_poll;
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
}
-/* ******************* Remove Active Palette ************************* */
+/****************************** Join ***********************************/
-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);
+/* userdata for joined_gpencil_fix_animdata_cb() */
+typedef struct tJoinGPencil_AdtFixData {
+ bGPdata *src_gpd;
+ bGPdata *tar_gpd;
- /* sanity checks */
- if (ELEM(NULL, gpd, palette))
- return OPERATOR_CANCELLED;
+ GHash *names_map;
+} tJoinGPencil_AdtFixData;
- if (BLI_listbase_count_at_most(&gpd->palettes, 2) < 2) {
- BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one");
- return OPERATOR_CANCELLED;
- }
+/* Callback to pass to BKE_fcurves_main_cb() for RNA Paths attached to each F-Curve used in the AnimData */
+static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
+{
+ tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data;
+ ID *src_id = &afd->src_gpd->id;
+ ID *dst_id = &afd->tar_gpd->id;
+ GHashIterator gh_iter;
- /* 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);
+ /* Fix paths - If this is the target datablock, it will have some "dirty" paths */
+ if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) {
+ GHASH_ITER(gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
- /* delete the palette now... */
- BKE_gpencil_palette_delete(gpd, palette);
+ /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */
+ if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
+ fcu->rna_path = BKE_animsys_fix_rna_path_rename(
+ id, fcu->rna_path, "layers",
+ old_name, new_name, 0, 0, false);
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ /* we don't want to apply a second remapping on this F-Curve now,
+ * so stop trying to fix names names
+ */
+ break;
+ }
+ }
+ }
- return OPERATOR_FINISHED;
+ /* Fix driver targets */
+ if (fcu->driver) {
+ /* Fix driver references to invalid ID's */
+ for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
+ {
+ /* change the ID's used... */
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+
+ /* also check on the subtarget...
+ * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
+ * little twists so that we know that it isn't going to clobber the wrong data
+ */
+ if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) {
+ GHASH_ITER(gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed */
+ if (!STREQ(old_name, new_name)) {
+ if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
+ /* Fix up path */
+ dtar->rna_path = BKE_animsys_fix_rna_path_rename(
+ id, dtar->rna_path, "layers",
+ old_name, new_name, 0, 0, false);
+ break; /* no need to try any more names for layer path */
+ }
+ }
+ }
+ }
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
}
-void GPENCIL_OT_palette_remove(wmOperatorType *ot)
+/* join objects called from OBJECT_OT_join */
+int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
{
- /* identifiers */
- ot->name = "Remove palette";
- ot->idname = "GPENCIL_OT_palette_remove";
- ot->description = "Remove active Grease Pencil palette";
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob_active = CTX_data_active_object(C);
+ bGPdata *gpd_dst = NULL;
+ bool ok = false;
+
+ /* Ensure we're in right mode and that the active object is correct */
+ if (!ob_active || ob_active->type != OB_GPENCIL)
+ return OPERATOR_CANCELLED;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ bGPdata *gpd = (bGPdata *)ob_active->data;
+ if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
- /* callbacks */
- ot->exec = gp_palette_remove_exec;
- ot->poll = gp_active_palette_poll;
-}
+ /* Ensure all rotations are applied before */
+ // XXX: Why don't we apply them here instead of warning?
+ CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
+ {
+ if (ob_iter->type == OB_GPENCIL) {
+ if ((ob_iter->rot[0] != 0) ||
+ (ob_iter->rot[1] != 0) ||
+ (ob_iter->rot[2] != 0))
+ {
+ BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+ CTX_DATA_END;
-/* ********************** Change Palette ***************************** */
+ CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
+ {
+ if (ob_iter == ob_active) {
+ ok = true;
+ break;
+ }
+ }
+ CTX_DATA_END;
-static int gp_palette_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
-{
- uiPopupMenu *pup;
- uiLayout *layout;
+ /* that way the active object is always selected */
+ if (ok == false) {
+ BKE_report(op->reports, RPT_WARNING, "Active object is not a selected grease pencil");
+ return OPERATOR_CANCELLED;
+ }
- /* 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);
+ gpd_dst = ob_active->data;
+ Object *ob_dst = ob_active;
+
+ /* loop and join all data */
+ CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
+ {
+ if ((ob_iter->type == OB_GPENCIL) && (ob_iter != ob_active)) {
+ /* we assume that each datablock is not already used in active object */
+ if (ob_active->data != ob_iter->data) {
+ Object *ob_src = ob_iter;
+ bGPdata *gpd_src = ob_iter->data;
+
+ /* Apply all GP modifiers before */
+ for (GpencilModifierData *md = ob_iter->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ if (mti->bakeModifier) {
+ mti->bakeModifier(bmain, depsgraph, md, ob_iter);
+ }
+ }
- return OPERATOR_INTERFACE;
-}
+ /* copy vertex groups to the base one's */
+ int old_idx = 0;
+ for (bDeformGroup *dg = ob_iter->defbase.first; dg; dg = dg->next) {
+ bDeformGroup *vgroup = MEM_dupallocN(dg);
+ int idx = BLI_listbase_count(&ob_active->defbase);
+ defgroup_unique_name(vgroup, ob_active);
+ BLI_addtail(&ob_active->defbase, vgroup);
+ /* update vertex groups in strokes in original data */
+ for (bGPDlayer *gpl_src = gpd->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ for (bGPDframe *gpf = gpl_src->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ MDeformVert *dvert;
+ int i;
+ for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) {
+ if ((dvert->dw) && (dvert->dw->def_nr == old_idx)) {
+ dvert->dw->def_nr = idx;
+ }
+ }
+ }
+ }
+ }
+ old_idx++;
+ }
+ if (ob_active->defbase.first && ob_active->actdef == 0) {
+ ob_active->actdef = 1;
+ }
-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");
+ /* add missing materials reading source materials and checking in destination object */
+ short *totcol = give_totcolp(ob_src);
- /* 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);
+ for (short i = 0; i < *totcol; i++) {
+ Material *tmp_ma = give_current_material(ob_src, i + 1);
+ if (BKE_gpencil_get_material_index(ob_dst, tmp_ma) == 0) {
+ BKE_object_material_slot_add(bmain, ob_dst);
+ assign_material(bmain, ob_dst, tmp_ma, ob_dst->totcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+ }
- if (palette == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent palette (index = %d)", palette_num);
- return OPERATOR_CANCELLED;
+ /* duplicate bGPDlayers */
+ tJoinGPencil_AdtFixData afd = {0};
+ afd.src_gpd = gpd_src;
+ afd.tar_gpd = gpd_dst;
+ afd.names_map = BLI_ghash_str_new("joined_gp_layers_map");
+
+ float imat[3][3], bmat[3][3];
+ float offset_global[3];
+ float offset_local[3];
+
+ sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]);
+ copy_m3_m4(bmat, ob_active->obmat);
+ invert_m3_m3(imat, bmat);
+ mul_m3_v3(imat, offset_global);
+ mul_v3_m3v3(offset_local, imat, offset_global);
+
+
+ for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ /* recalculate all stroke points */
+ ED_gpencil_parent_location(depsgraph, ob_iter, gpd_src, gpl_src, diff_mat);
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
+ Material *ma_src = NULL;
+ int idx;
+ for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ /* reasign material. Look old material and try to find in dst */
+ ma_src = give_current_material(ob_src, gps->mat_nr + 1);
+ if (ma_src != NULL) {
+ idx = BKE_gpencil_get_material_index(ob_dst, ma_src);
+ if (idx > 0) {
+ gps->mat_nr = idx - 1;
+ }
+ else {
+ gps->mat_nr = 0;
+ }
+ }
+ else {
+ gps->mat_nr = 0;
+ }
+
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(&pt->x, diff_mat, mpt);
+ }
+ }
+ }
+
+ /* be sure name is unique in new object */
+ BLI_uniquename(&gpd_dst->layers, gpl_new, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_new->info));
+ BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info);
+
+ /* add to destination datablock */
+ BLI_addtail(&gpd_dst->layers, gpl_new);
+ }
+
+ /* Fix all the animation data */
+ BKE_fcurves_main_cb(bmain, joined_gpencil_fix_animdata_cb, &afd);
+ BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
+
+ /* Only copy over animdata now, after all the remapping has been done,
+ * so that we don't have to worry about ambiguities re which datablock
+ * a layer came from!
+ */
+ if (ob_iter->adt) {
+ if (ob_active->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ ob_active->adt = BKE_animdata_copy(bmain, ob_iter->adt, 0);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(bmain, &ob_active->id, &ob_iter->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ if (gpd_src->adt) {
+ if (gpd_dst->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ gpd_dst->adt = BKE_animdata_copy(bmain, gpd_src->adt, 0);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(bmain, &gpd_dst->id, &gpd_src->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+ }
+
+ /* Free the old object */
+ ED_object_base_free_and_unlink(bmain, scene, ob_iter);
}
}
+ CTX_DATA_END;
- /* Set active palette */
- BKE_gpencil_palette_setactive(gpd, palette);
+ DEG_relations_tag_update(bmain); /* because we removed object(s) */
- /* updates */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palette_change(wmOperatorType *ot)
+/* Color Handle operator */
+static bool gpencil_active_color_poll(bContext *C)
{
- /* 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);
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->data && (ob->type == OB_GPENCIL)) {
+ short *totcolp = give_totcolp(ob);
+ return *totcolp > 0;
+ }
+ return false;
}
-/* ******************* Lock and hide any color non used in current layer ************************** */
-static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
+/* ******************* Lock and hide any color non used in current layer ************************** */
+static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette;
+ Object *ob = CTX_data_active_object(C);
+ MaterialGPencilStyle *gp_style = NULL;
/* sanity checks */
if (ELEM(NULL, gpd))
return OPERATOR_CANCELLED;
- palette = BKE_gpencil_palette_getactive(gpd);
- if (ELEM(NULL, palette))
+ /* first lock and hide all colors */
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
+ if (totcol == 0)
return OPERATOR_CANCELLED;
- /* first lock and hide all colors */
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag |= PC_COLOR_LOCKED;
- palcolor->flag |= PC_COLOR_HIDE;
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ gp_style->flag |= GP_STYLE_COLOR_HIDE;
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
}
/* loop all selected strokes and unlock any color used in active layer */
@@ -1558,140 +2201,58 @@ static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
+ ma = give_current_material(ob, gps->mat_nr + 1);
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
+
+ gp_style = ma->gp_style;
/* unlock/unhide color if not unlocked before */
- if (gps->palcolor != NULL) {
- gps->palcolor->flag &= ~PC_COLOR_LOCKED;
- gps->palcolor->flag &= ~PC_COLOR_HIDE;
+ if (gp_style != NULL) {
+ gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
}
}
}
}
+ /* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palette_lock_layer(wmOperatorType *ot)
+void GPENCIL_OT_lock_layer(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Disable Unused Layer Colors";
- ot->idname = "GPENCIL_OT_palette_lock_layer";
+ ot->idname = "GPENCIL_OT_lock_layer";
ot->description = "Lock and hide any color not used in any layer";
/* api callbacks */
- ot->exec = gp_palette_lock_layer_exec;
+ ot->exec = gpencil_lock_layer_exec;
ot->poll = gp_active_layer_poll;
}
-/* ************************************************ */
-/* Palette Colors Operators */
-
-/* ******************* Add New Palette ************************ */
-
-/* add new palette - wrapper around API */
-static int gp_palettecolor_add_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
-
- /* if there's no existing Grease-Pencil data there, add some */
- if (gpd_ptr == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
- return OPERATOR_CANCELLED;
- }
- if (*gpd_ptr == NULL)
- *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil"));
-
- /* verify palette */
- bGPDpalette *palette = BKE_gpencil_palette_getactive(*gpd_ptr);
- if (palette == NULL)
- palette = BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true);
-
- /* add new palette color now */
- BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_palettecolor_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Palette Color";
- ot->idname = "GPENCIL_OT_palettecolor_add";
- ot->description = "Add new Grease Pencil palette color for the active Grease Pencil data-block";
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* callbacks */
- ot->exec = gp_palettecolor_add_exec;
- ot->poll = gp_add_poll;
-}
-
-/* ******************* Remove Active Palette color ************************* */
+/* ********************** Isolate gpencil_ color **************************** */
-static int gp_palettecolor_remove_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *color = BKE_gpencil_palettecolor_getactive(palette);
+ Object *ob = CTX_data_active_object(C);
+ Material *active_ma = give_current_material(ob, ob->actcol);
+ MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
+ MaterialGPencilStyle *gp_style;
- /* 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;
+ int flags = GP_STYLE_COLOR_LOCKED;
bool isolate = false;
if (RNA_boolean_get(op->ptr, "affect_visibility"))
- flags |= PC_COLOR_HIDE;
+ flags |= GP_STYLE_COLOR_HIDE;
if (ELEM(NULL, gpd, active_color)) {
BKE_report(op->reports, RPT_ERROR, "No active color to isolate");
@@ -1699,15 +2260,19 @@ static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op)
}
/* Test whether to isolate or clear all flags */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
/* Skip if this is the active one */
- if (palcolor == active_color)
+ if (ma == active_ma)
continue;
/* If the flags aren't set, that means that the color is
* not alone, so we have some colors to isolate still
*/
- if ((palcolor->flag & flags) == 0) {
+ gp_style = ma->gp_style;
+ if ((gp_style->flag & flags) == 0) {
isolate = true;
break;
}
@@ -1716,92 +2281,112 @@ static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op)
/* Set/Clear flags as appropriate */
if (isolate) {
/* Set flags on all "other" colors */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- if (palcolor == active_color)
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ if (gp_style == active_color)
continue;
else
- palcolor->flag |= flags;
+ gp_style->flag |= flags;
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
}
}
else {
/* Clear flags - Restore everything else */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~flags;
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~flags;
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
}
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_isolate(wmOperatorType *ot)
+void GPENCIL_OT_color_isolate(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Isolate Palette Color";
- ot->idname = "GPENCIL_OT_palettecolor_isolate";
+ ot->name = "Isolate Color";
+ ot->idname = "GPENCIL_OT_color_isolate";
ot->description = "Toggle whether the active color is the only one that is editable and/or visible";
/* callbacks */
- ot->exec = gp_isolate_palettecolor_exec;
- ot->poll = gp_active_palettecolor_poll;
+ ot->exec = gpencil_color_isolate_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling "
- "the editability, also affect the visibility");
+ "the editability, also affect the visibility");
}
-/* *********************** Hide Palette colors ******************************** */
+/* *********************** Hide colors ******************************** */
-static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op)
+static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
bool unselected = RNA_boolean_get(op->ptr, "unselected");
- /* sanity checks */
- if (ELEM(NULL, gpd, palette, palcolor))
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
+ if (totcol == 0)
return OPERATOR_CANCELLED;
if (unselected) {
- bGPDpalettecolor *color;
-
/* hide unselected */
- for (color = palette->colors.first; color; color = color->next) {
- if (color != palcolor) {
- color->flag |= PC_COLOR_HIDE;
+ MaterialGPencilStyle *color = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ color = ma->gp_style;
+ if (active_color != color) {
+ color->flag |= GP_STYLE_COLOR_HIDE;
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
}
}
}
else {
/* hide selected/active */
- palcolor->flag |= PC_COLOR_HIDE;
+ active_color->flag |= GP_STYLE_COLOR_HIDE;
}
+ /* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot)
+void GPENCIL_OT_color_hide(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Hide Color(s)";
- ot->idname = "GPENCIL_OT_palettecolor_hide";
+ ot->idname = "GPENCIL_OT_color_hide";
ot->description = "Hide selected/unselected Grease Pencil colors";
/* callbacks */
- ot->exec = gp_palettecolor_hide_exec;
- ot->poll = gp_active_palettecolor_poll; /* NOTE: we need an active color to play with */
+ ot->exec = gpencil_color_hide_exec;
+ ot->poll = gpencil_active_color_poll; /* NOTE: we need an active color to play with */
- /* flags */
+ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
@@ -1810,81 +2395,98 @@ void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot)
/* ********************** Show All Colors ***************************** */
-/* poll callback for showing colors */
-static bool gp_palettecolor_reveal_poll(bContext *C)
+static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
{
- return ED_gpencil_data_get_active(C) != NULL;
-}
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
-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))
+ if (totcol == 0)
return OPERATOR_CANCELLED;
/* make all colors visible */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~PC_COLOR_HIDE;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
}
+ /* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_reveal(wmOperatorType *ot)
+void GPENCIL_OT_color_reveal(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Show All Colors";
- ot->idname = "GPENCIL_OT_palettecolor_reveal";
- ot->description = "Unhide all hidden Grease Pencil palette colors";
+ ot->idname = "GPENCIL_OT_color_reveal";
+ ot->description = "Unhide all hidden Grease Pencil colors";
/* callbacks */
- ot->exec = gp_palettecolor_reveal_exec;
- ot->poll = gp_palettecolor_reveal_poll;
+ ot->exec = gpencil_color_reveal_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Lock/Unlock All Palette colors ************************ */
+/* ***************** Lock/Unlock All colors ************************ */
-static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor;
- /* sanity checks */
- if (ELEM(NULL, gpd, palette))
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
+
+ if (totcol == 0)
return OPERATOR_CANCELLED;
/* make all layers non-editable */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag |= PC_COLOR_LOCKED;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
}
+ /* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot)
+void GPENCIL_OT_color_lock_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Lock All Colors";
- ot->idname = "GPENCIL_OT_palettecolor_lock_all";
+ ot->idname = "GPENCIL_OT_color_lock_all";
ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified";
/* callbacks */
- ot->exec = gp_palettecolor_lock_all_exec;
- ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+ ot->exec = gpencil_color_lock_all_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1892,200 +2494,142 @@ void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot)
/* -------------------------- */
-static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor;
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Material *ma = NULL;
+ short *totcol = give_totcolp(ob);
- /* sanity checks */
- if (ELEM(NULL, gpd, palette))
+ if (totcol == 0)
return OPERATOR_CANCELLED;
/* make all layers editable again*/
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~PC_COLOR_LOCKED;
+ MaterialGPencilStyle *gp_style = NULL;
+
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ gp_style = ma->gp_style;
+ gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
}
+ /* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_unlock_all(wmOperatorType *ot)
+void GPENCIL_OT_color_unlock_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Unlock All Colors";
- ot->idname = "GPENCIL_OT_palettecolor_unlock_all";
+ ot->idname = "GPENCIL_OT_color_unlock_all";
ot->description = "Unlock all Grease Pencil colors so that they can be edited";
/* callbacks */
- ot->exec = gp_palettecolor_unlock_all_exec;
- ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+ ot->exec = gpencil_color_unlock_all_exec;
+ ot->poll = gpencil_active_color_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Move Color Up/Down ************************** */
-enum {
- GP_COLOR_MOVE_UP = -1,
- GP_COLOR_MOVE_DOWN = 1
-};
+/* ***************** Select all strokes using color ************************ */
-static int gp_palettecolor_move_exec(bContext *C, wmOperator *op)
+static int gpencil_color_select_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");
+ Object *ob = CTX_data_active_object(C);
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool deselected = RNA_boolean_get(op->ptr, "deselect");
/* sanity checks */
- if (ELEM(NULL, gpd, palette, palcolor))
- return OPERATOR_CANCELLED;
-
- /* up or down? */
- if (direction == GP_COLOR_MOVE_UP) {
- /* up */
- BLI_remlink(&palette->colors, palcolor);
- BLI_insertlinkbefore(&palette->colors, palcolor->prev, palcolor);
- }
- else if (direction == GP_COLOR_MOVE_DOWN) {
- /* down */
- BLI_remlink(&palette->colors, palcolor);
- BLI_insertlinkafter(&palette->colors, palcolor->next, palcolor);
- }
- else {
- BLI_assert(0);
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_palettecolor_move(wmOperatorType *ot)
-{
- static const EnumPropertyItem slot_move[] = {
- {GP_COLOR_MOVE_UP, "UP", 0, "Up", ""},
- {GP_COLOR_MOVE_DOWN, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Move Palette color";
- ot->idname = "GPENCIL_OT_palettecolor_move";
- ot->description = "Move the active Grease Pencil palette color up/down in the list";
-
- /* api callbacks */
- ot->exec = gp_palettecolor_move_exec;
- ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
-
- /* 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))
+ if (ELEM(NULL, gpd, gp_style))
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;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- /* select */
- if (strcmp(palcolor->info, gps->colorname) == 0) {
- bGPDspoint *pt;
- int i;
+ /* verify something to do */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
- gps->flag |= GP_STROKE_SELECT;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag |= GP_SPOINT_SELECT;
+ /* select */
+ if (ob->actcol == gps->mat_nr + 1) {
+ bGPDspoint *pt;
+ int i;
+
+ if (!deselected) {
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ else {
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (!deselected) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
}
}
}
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+
}
}
+ CTX_DATA_END;
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_palettecolor_select(wmOperatorType *ot)
+void GPENCIL_OT_color_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Color";
- ot->idname = "GPENCIL_OT_palettecolor_select";
+ ot->idname = "GPENCIL_OT_color_select";
ot->description = "Select all Grease Pencil strokes using current color";
/* callbacks */
- ot->exec = gp_palettecolor_select_exec;
- ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */
+ ot->exec = gpencil_color_select_exec;
+ ot->poll = gpencil_active_color_poll;
/* 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;
+ /* props */
+ ot->prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Unselect strokes");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 2c87bd86da1..89c1409f05c 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -25,9 +25,9 @@
* Operators for editing Grease Pencil strokes
*/
-/** \file blender/editors/gpencil/gpencil_edit.c
- * \ingroup edgpencil
- */
+ /** \file blender/editors/gpencil/gpencil_edit.c
+ * \ingroup edgpencil
+ */
#include <stdio.h>
@@ -47,6 +47,7 @@
#include "BLT_translation.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -54,18 +55,26 @@
#include "DNA_view3d_types.h"
#include "DNA_gpencil_types.h"
+#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -79,39 +88,128 @@
#include "ED_view3d.h"
#include "ED_space_api.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
-/* ************************************************ */
-/* Stroke Edit Mode Management */
+ /* ************************************************ */
+ /* Stroke Edit Mode Management */
+
+/* poll callback for all stroke editing operators */
+static bool gp_stroke_edit_poll(bContext *C)
+{
+ /* edit only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+}
+
+/* poll callback to verify edit mode in 3D view only */
+static bool gp_strokes_edit3d_poll(bContext *C)
+{
+ /* edit only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+
+ /* 2 Requirements:
+ * - 1) Editable GP data
+ * - 2) 3D View only
+ */
+ return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
+}
static bool gpencil_editmode_toggle_poll(bContext *C)
{
+ /* edit only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ /* if using gpencil object, use this gpd */
+ if (ob->type == OB_GPENCIL) {
+ return ob->data != NULL;
+ }
+
return ED_gpencil_data_get_active(C) != NULL;
}
-static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op)
{
+ const int back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
- if (gpd == NULL)
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active GP data");
return OPERATOR_CANCELLED;
+ }
/* Just toggle editmode flag... */
gpd->flag ^= GP_DATA_STROKE_EDITMODE;
/* recalculate parent matrix */
if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- ED_gpencil_reset_layers_parent(gpd);
+ ED_gpencil_reset_layers_parent(depsgraph, ob, gpd);
+ }
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
+ mode = OB_MODE_GPENCIL_EDIT;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
}
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_EDITMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
return OPERATOR_FINISHED;
}
void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Strokes Edit Mode Toggle";
ot->idname = "GPENCIL_OT_editmode_toggle";
@@ -123,33 +221,344 @@ void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* ************************************************ */
-/* Stroke Editing Operators */
+/* set select mode */
+static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ const int mode = RNA_int_get(op->ptr, "mode");
-/* poll callback for all stroke editing operators */
-static bool gp_stroke_edit_poll(bContext *C)
+ /* Just set mode */
+ ts->gpencil_selectmode = mode;
+
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_selectmode_toggle(wmOperatorType *ot)
{
- /* NOTE: this is a bit slower, but is the most accurate... */
- return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Mode Toggle";
+ ot->idname = "GPENCIL_OT_selectmode_toggle";
+ ot->description = "Set selection mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_selectmode_toggle_exec;
+ ot->poll = gp_strokes_edit3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "mode", 0, 0, 1, "Select mode", "Select mode", 0, 1);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* ************ Stroke Hide selection Toggle ************** */
+/* Stroke Paint Mode Management */
-static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+static bool gpencil_paintmode_toggle_poll(bContext *C)
{
+ /* if using gpencil object, use this gpd */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return ob->data != NULL;
+ }
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- if (ts == NULL)
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
+
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle paintmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_PAINTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ mode = OB_MODE_GPENCIL_PAINT;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ if (mode == OB_MODE_GPENCIL_PAINT) {
+ /* be sure we have brushes */
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
+ Paint *paint = &ts->gp_paint->paint;
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ BKE_brush_gpencil_presets(C);
+ }
+ BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_paintmode_toggle(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Strokes Paint Mode Toggle";
+ ot->idname = "GPENCIL_OT_paintmode_toggle";
+ ot->description = "Enter/Exit paint mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_paintmode_toggle_exec;
+ ot->poll = gpencil_paintmode_toggle_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/* Stroke Sculpt Mode Management */
+
+static bool gpencil_sculptmode_toggle_poll(bContext *C)
+{
+ /* if using gpencil object, use this gpd */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return ob->data != NULL;
+ }
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
+
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle sculptmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_SCULPTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
+ mode = OB_MODE_GPENCIL_SCULPT;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_SCULPTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_sculptmode_toggle(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Strokes Sculpt Mode Toggle";
+ ot->idname = "GPENCIL_OT_sculptmode_toggle";
+ ot->description = "Enter/Exit sculpt mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_sculptmode_toggle_exec;
+ ot->poll = gpencil_sculptmode_toggle_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/* Stroke Weight Paint Mode Management */
+
+static bool gpencil_weightmode_toggle_poll(bContext *C)
+{
+ /* if using gpencil object, use this gpd */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return ob->data != NULL;
+ }
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
+
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle weightmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_WEIGHTMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) {
+ mode = OB_MODE_GPENCIL_WEIGHT;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Strokes Weight Mode Toggle";
+ ot->idname = "GPENCIL_OT_weightmode_toggle";
+ ot->description = "Enter/Exit weight paint mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_weightmode_toggle_exec;
+ ot->poll = gpencil_weightmode_toggle_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/* ************************************************ */
+/* Stroke Editing Operators */
+
+/* ************ Stroke Hide selection Toggle ************** */
+
+static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d == NULL)
return OPERATOR_CANCELLED;
/* Just toggle alpha... */
- if (ts->gp_sculpt.alpha > 0.0f) {
- ts->gp_sculpt.alpha = 0.0f;
+ if (v3d->vertex_opacity > 0.0f) {
+ v3d->vertex_opacity = 0.0f;
}
else {
- ts->gp_sculpt.alpha = 1.0f;
+ v3d->vertex_opacity = 1.0f;
}
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
@@ -218,7 +627,7 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co
/* make a stupid copy first of the entire stroke (to get the flags too) */
gpsd = MEM_dupallocN(gps);
- BLI_strncpy(gpsd->tmp_layerinfo, layername, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */
+ BLI_strncpy(gpsd->runtime.tmp_layerinfo, layername, sizeof(gpsd->runtime.tmp_layerinfo)); /* saves original layer name */
/* initialize triangle memory - will be calculated on next redraw */
gpsd->triangles = NULL;
@@ -230,6 +639,20 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co
memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
gpsd->totpoints = len;
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_callocN(sizeof(MDeformVert) * len, "gps stroke weights copy");
+ memcpy(gpsd->dvert, gps->dvert + start_idx, sizeof(MDeformVert) * len);
+
+ /* Copy weights */
+ int e = start_idx;
+ for (int j = 0; j < gpsd->totpoints; j++) {
+ MDeformVert *dvert_dst = &gps->dvert[e];
+ MDeformVert *dvert_src = &gps->dvert[j];
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ e++;
+ }
+ }
+
/* add to temp buffer */
gpsd->next = gpsd->prev = NULL;
BLI_addtail(new_strokes, gpsd);
@@ -250,6 +673,11 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
/* for each visible (and editable) layer's selected strokes,
* copy the strokes into a temporary buffer, then append
* once all done
@@ -277,8 +705,12 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
- BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo));
+ BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
gpsd->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
+ }
/* triangle information - will be calculated on next redraw */
gpsd->flag |= GP_STROKE_RECALC_CACHES;
@@ -307,6 +739,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -336,24 +769,58 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot)
* from several different layers into a single layer.
*/
-/* list of bGPDstroke instances */
-/* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
+ /* list of bGPDstroke instances */
+ /* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
ListBase gp_strokes_copypastebuf = {NULL, NULL};
-/* Hash for hanging on to all the palette colors used by strokes in the buffer
+/* Hash for hanging on to all the colors used by strokes in the buffer
*
* This is needed to prevent dangling and unsafe pointers when pasting across datablocks,
* or after a color used by a stroke in the buffer gets deleted (via user action or undo).
*/
static GHash *gp_strokes_copypastebuf_colors = NULL;
+static GHash *gp_strokes_copypastebuf_colors_material_to_name_create(Main *bmain)
+{
+ GHash *ma_to_name = BLI_ghash_ptr_new(__func__);
+
+ for (Material *ma = bmain->mat.first; ma != NULL; ma = ma->id.next) {
+ char *name = BKE_id_to_unique_string_key(&ma->id);
+ BLI_ghash_insert(ma_to_name, ma, name);
+ }
+
+ return ma_to_name;
+}
+
+static void gp_strokes_copypastebuf_colors_material_to_name_free(GHash *ma_to_name)
+{
+ BLI_ghash_free(ma_to_name, NULL, MEM_freeN);
+}
+
+static GHash *gp_strokes_copypastebuf_colors_name_to_material_create(Main *bmain)
+{
+ GHash *name_to_ma = BLI_ghash_str_new(__func__);
+
+ for (Material *ma = bmain->mat.first; ma != NULL; ma = ma->id.next) {
+ char *name = BKE_id_to_unique_string_key(&ma->id);
+ BLI_ghash_insert(name_to_ma, name, ma);
+ }
+
+ return name_to_ma;
+}
+
+static void gp_strokes_copypastebuf_colors_name_to_material_free(GHash *name_to_ma)
+{
+ BLI_ghash_free(name_to_ma, MEM_freeN, NULL);
+}
+
/* Free copy/paste buffer data */
void ED_gpencil_strokes_copybuf_free(void)
{
bGPDstroke *gps, *gpsn;
- /* Free the palettes buffer
- * NOTE: This is done before the strokes so that the name ptrs (keys) are still safe
+ /* Free the colors buffer
+ * NOTE: This is done before the strokes so that the ptrs are still safe
*/
if (gp_strokes_copypastebuf_colors) {
BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN);
@@ -364,8 +831,15 @@ void ED_gpencil_strokes_copybuf_free(void)
for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) {
gpsn = gps->next;
- if (gps->points) MEM_freeN(gps->points);
- if (gps->triangles) MEM_freeN(gps->triangles);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ MEM_SAFE_FREE(gps->triangles);
BLI_freelinkN(&gp_strokes_copypastebuf, gps);
}
@@ -376,40 +850,32 @@ void ED_gpencil_strokes_copybuf_free(void)
/* Ensure that destination datablock has all the colours the pasted strokes need
* Helper function for copy-pasting strokes
*/
-GHash *gp_copybuf_validate_colormap(bGPdata *gpd)
+GHash *gp_copybuf_validate_colormap(bContext *C)
{
- GHash *new_colors = BLI_ghash_str_new("GPencil Paste Dst Colors");
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ GHash *new_colors = BLI_ghash_int_new("GPencil Paste Dst Colors");
GHashIterator gh_iter;
- /* If there's no active palette yet (i.e. new datablock), add one */
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- if (palette == NULL) {
- palette = BKE_gpencil_palette_addnew(gpd, "Pasted Palette", true);
- }
+ /* For each color, check if exist and add if not */
+ GHash *name_to_ma = gp_strokes_copypastebuf_colors_name_to_material_create(bmain);
- /* For each color, figure out what to map to... */
GHASH_ITER(gh_iter, gp_strokes_copypastebuf_colors) {
- bGPDpalettecolor *palcolor;
- char *name = BLI_ghashIterator_getKey(&gh_iter);
-
- /* Look for existing color to map to */
- /* XXX: What to do if same name but different color? Behaviour here should depend on a property? */
- palcolor = BKE_gpencil_palettecolor_getbyname(palette, name);
- if (palcolor == NULL) {
- /* Doesn't Exist - Create new matching color for this palette */
- /* XXX: This still doesn't fix the pasting across file boundaries problem... */
- bGPDpalettecolor *src_color = BLI_ghashIterator_getValue(&gh_iter);
+ int *key = BLI_ghashIterator_getKey(&gh_iter);
+ char *ma_name = BLI_ghashIterator_getValue(&gh_iter);
+ Material *ma = BLI_ghash_lookup(name_to_ma, ma_name);
- palcolor = MEM_dupallocN(src_color);
- BLI_addtail(&palette->colors, palcolor);
-
- BLI_uniquename(&palette->colors, palcolor, DATA_("GP Color"), '.', offsetof(bGPDpalettecolor, info), sizeof(palcolor->info));
+ if (ma != NULL && BKE_gpencil_get_material_index(ob, ma) == 0) {
+ BKE_object_material_slot_add(bmain, ob);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
}
/* Store this mapping (for use later when pasting) */
- BLI_ghash_insert(new_colors, name, palcolor);
+ BLI_ghash_insert(new_colors, key, ma);
}
+ gp_strokes_copypastebuf_colors_name_to_material_free(name_to_ma);
+
return new_colors;
}
@@ -418,6 +884,8 @@ GHash *gp_copybuf_validate_colormap(bGPdata *gpd)
static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
if (gpd == NULL) {
@@ -425,6 +893,11 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
/* clear the buffer first */
ED_gpencil_strokes_copybuf_free();
@@ -453,8 +926,12 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
/* make direct copies of the stroke and its points */
gpsd = MEM_dupallocN(gps);
- BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */
+ BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo)); /* saves original layer name */
gpsd->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ gpsd->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
+ }
/* triangles cache - will be recalculated on next redraw */
gpsd->flag |= GP_STROKE_RECALC_CACHES;
@@ -474,20 +951,21 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* Build up hash of colors used in these strokes, making copies of these to protect against dangling pointers */
+ /* Build up hash of material colors used in these strokes */
if (gp_strokes_copypastebuf.first) {
- gp_strokes_copypastebuf_colors = BLI_ghash_str_new("GPencil CopyBuf Colors");
-
+ gp_strokes_copypastebuf_colors = BLI_ghash_int_new("GPencil CopyBuf Colors");
+ GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain);
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
- if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, gps->colorname) == false) {
- bGPDpalettecolor *color = MEM_dupallocN(gps->palcolor);
-
- BLI_ghash_insert(gp_strokes_copypastebuf_colors, gps->colorname, color);
- gps->palcolor = color;
+ char **ma_name_val;
+ if (!BLI_ghash_ensure_p(gp_strokes_copypastebuf_colors, &gps->mat_nr, (void ***)&ma_name_val)) {
+ Material *ma = give_current_material(ob, gps->mat_nr + 1);
+ char *ma_name = BLI_ghash_lookup(ma_to_name, ma);
+ *ma_name_val = MEM_dupallocN(ma_name);
}
}
}
+ gp_strokes_copypastebuf_colors_material_to_name_free(ma_to_name);
}
/* updates (to ensure operator buttons are refreshed, when used via hotkeys) */
@@ -532,9 +1010,11 @@ typedef enum eGP_PasteMode {
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
bGPDframe *gpf;
eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
@@ -545,6 +1025,10 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
return OPERATOR_CANCELLED;
}
+ else if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
else if (BLI_listbase_is_empty(&gp_strokes_copypastebuf)) {
BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again");
return OPERATOR_CANCELLED;
@@ -597,14 +1081,14 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* Ensure that all the necessary colors exist */
- new_colors = gp_copybuf_validate_colormap(gpd);
+ new_colors = gp_copybuf_validate_colormap(C);
/* Copy over the strokes from the buffer (and adjust the colors) */
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
/* Need to verify if layer exists */
if (type != GP_COPY_MERGE) {
- gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info));
+ gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
if (gpl == NULL) {
/* no layer - use active (only if layer deleted before paste) */
gpl = CTX_data_active_gpencil_layer(C);
@@ -616,28 +1100,33 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
* we are obliged to add a new frame if one
* doesn't exist already
*/
- gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
if (gpf) {
/* Create new stroke */
bGPDstroke *new_stroke = MEM_dupallocN(gps);
- new_stroke->tmp_layerinfo[0] = '\0';
+ new_stroke->runtime.tmp_layerinfo[0] = '\0';
new_stroke->points = MEM_dupallocN(gps->points);
-
+ if (gps->dvert != NULL) {
+ new_stroke->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
+ }
new_stroke->flag |= GP_STROKE_RECALC_CACHES;
new_stroke->triangles = NULL;
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
- /* Fix color references */
- BLI_assert(new_stroke->colorname[0] != '\0');
- new_stroke->palcolor = BLI_ghash_lookup(new_colors, new_stroke->colorname);
-
- BLI_assert(new_stroke->palcolor != NULL);
- BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname));
+ /* Remap material */
+ Material *ma = BLI_ghash_lookup(new_colors, &new_stroke->mat_nr);
+ if ((ma) && (BKE_gpencil_get_material_index(ob, ma) > 0)) {
+ gps->mat_nr = BKE_gpencil_get_material_index(ob, ma) - 1;
+ CLAMP_MIN(gps->mat_nr, 0);
+ }
+ else {
+ gps->mat_nr = 0; /* only if the color is not found */
+ }
- /*new_stroke->flag |= GP_STROKE_RECALC_COLOR; */
}
}
}
@@ -646,6 +1135,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
BLI_ghash_free(new_colors, NULL, NULL);
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -669,7 +1159,7 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
ot->poll = gp_strokes_paste_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
@@ -695,10 +1185,17 @@ static int gp_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *U
static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
bGPDlayer *target_layer = NULL;
ListBase strokes = {NULL, NULL};
int layer_num = RNA_enum_get(op->ptr, "layer");
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
+ return OPERATOR_CANCELLED;
+ }
+
/* Get layer or create new one */
if (layer_num == -1) {
/* Create layer */
@@ -746,14 +1243,14 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
/* Paste them all in one go */
if (strokes.first) {
- Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, CFRA, true);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, cfra_eval, GP_GETFRAME_ADD_NEW);
BLI_movelisttolist(&gpf->strokes, &strokes);
BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
}
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -802,8 +1299,10 @@ static bool UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C)
static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd);
const bool all_layers = RNA_boolean_get(op->ptr, "all_layers");
@@ -824,7 +1323,7 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
}
/* 1) Check for an existing frame on the current frame */
- bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, CFRA);
+ bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, cfra_eval);
if (gpf) {
/* Shunt all frames after (and including) the existing one later by 1-frame */
for (; gpf; gpf = gpf->next) {
@@ -833,11 +1332,12 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
}
/* 2) Now add a new frame, with nothing in it */
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
}
CTX_DATA_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -849,7 +1349,7 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
ot->name = "Insert Blank Frame";
ot->idname = "GPENCIL_OT_blank_frame_add";
ot->description = "Insert a blank frame on the current frame "
- "(all subsequently existing frames, if any, are shifted right by one frame)";
+ "(all subsequently existing frames, if any, are shifted right by one frame)";
/* callbacks */
ot->exec = gp_blank_frame_add_exec;
@@ -874,10 +1374,13 @@ static bool gp_actframe_delete_poll(bContext *C)
/* delete active frame - wrapper around API calls */
static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
+
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd == NULL) {
@@ -893,6 +1396,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
BKE_gpencil_layer_delframe(gpl, gpf);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -926,13 +1430,16 @@ static bool gp_actframe_delete_all_poll(bContext *C)
static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
bool success = false;
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
/* try to get the "active" frame - but only if it actually occurs on this frame */
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
if (gpf == NULL)
continue;
@@ -947,6 +1454,7 @@ static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
/* updates */
if (success) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -981,43 +1489,69 @@ typedef enum eGP_DeleteMode {
GP_DELETEOP_FRAME = 2,
} eGP_DeleteMode;
+typedef enum eGP_DissolveMode {
+ /* dissolve all selected points */
+ GP_DISSOLVE_POINTS = 0,
+ /* dissolve between selected points */
+ GP_DISSOLVE_BETWEEN = 1,
+ /* dissolve unselected points */
+ GP_DISSOLVE_UNSELECT = 2,
+} eGP_DissolveMode;
+
/* ----------------------------------- */
/* Delete selected strokes */
static int gp_delete_selected_strokes(bContext *C)
{
bool changed = false;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps, *gpsn;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- if (gpf == NULL)
- continue;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
- /* simply delete strokes which are selected */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ if (gpf == NULL)
+ continue;
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
+ /* simply delete strokes which are selected */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
- /* free stroke if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- /* free stroke memory arrays, then stroke itself */
- if (gps->points) MEM_freeN(gps->points);
- if (gps->triangles) MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
- changed = true;
+ /* free stroke if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* free stroke memory arrays, then stroke itself */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ MEM_SAFE_FREE(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+
+ changed = true;
+ }
+ }
}
}
}
CTX_DATA_END;
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1029,88 +1563,238 @@ static int gp_delete_selected_strokes(bContext *C)
/* ----------------------------------- */
/* Delete selected points but keep the stroke */
-static int gp_dissolve_selected_points(bContext *C)
+static int gp_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bool changed = false;
+ int first = 0;
+ int last = 0;
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps, *gpsn;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- if (gpf == NULL)
- continue;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- /* simply delete points from selected strokes
- * NOTE: we may still have to remove the stroke if it ends up having no points!
- */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ bGPDstroke *gps, *gpsn;
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
- continue;
+ if (gpf == NULL)
+ continue;
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
+ /* simply delete points from selected strokes
+ * NOTE: we may still have to remove the stroke if it ends up having no points!
+ */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
+
+ /* the stroke must have at least one point selected for any operator */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ MDeformVert *dvert = NULL;
+ int i;
+
+ int tot = gps->totpoints; /* number of points in new buffer */
+
+ /* first pass: count points to remove */
+ switch (mode) {
+ case GP_DISSOLVE_POINTS:
+ /* Count how many points are selected (i.e. how many to remove) */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ /* selected point - one of the points to remove */
+ tot--;
+ }
+ }
+ break;
+ case GP_DISSOLVE_BETWEEN:
+ /* need to find first and last point selected */
+ first = -1;
+ last = 0;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ if (first < 0) {
+ first = i;
+ }
+ last = i;
+ }
+ }
+ /* count unselected points in the range */
+ for (i = first, pt = gps->points + first; i < last; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ tot--;
+ }
+ }
+ break;
+ case GP_DISSOLVE_UNSELECT:
+ /* count number of unselected points */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ tot--;
+ }
+ }
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ /* if no points are left, we simply delete the entire stroke */
+ if (tot <= 0) {
+ /* remove the entire stroke */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles) {
+ MEM_freeN(gps->triangles);
+ }
+ BLI_freelinkN(&gpf->strokes, gps);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+ else {
+ /* just copy all points to keep into a smaller buffer */
+ bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy");
+ bGPDspoint *npt = new_points;
- int tot = gps->totpoints; /* number of points in new buffer */
+ MDeformVert *new_dvert = NULL;
+ MDeformVert *ndvert = NULL;
- /* First Pass: Count how many points are selected (i.e. how many to remove) */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- /* selected point - one of the points to remove */
- tot--;
- }
- }
+ if (gps->dvert != NULL) {
+ new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy");
+ ndvert = new_dvert;
+ }
- /* if no points are left, we simply delete the entire stroke */
- if (tot <= 0) {
- /* remove the entire stroke */
- MEM_freeN(gps->points);
- if (gps->triangles) {
- MEM_freeN(gps->triangles);
- }
- BLI_freelinkN(&gpf->strokes, gps);
- }
- else {
- /* just copy all unselected into a smaller buffer */
- bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy");
- bGPDspoint *npt = new_points;
+ switch (mode) {
+ case GP_DISSOLVE_POINTS:
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) == 0) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ break;
+ case GP_DISSOLVE_BETWEEN:
+ /* copy first segment */
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < first; i++, pt++) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ /* copy segment (selected points) */
+ (gps->dvert != NULL) ? dvert = gps->dvert + first : NULL;
+ for (i = first, pt = gps->points + first; i < last; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ /* copy last segment */
+ (gps->dvert != NULL) ? dvert = gps->dvert + last : NULL;
+ for (i = last, pt = gps->points + last; i < gps->totpoints; i++, pt++) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+
+ break;
+ case GP_DISSOLVE_UNSELECT:
+ /* copy any selected point */
+ (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ *npt = *pt;
+ npt++;
+
+ if (gps->dvert != NULL) {
+ *ndvert = *dvert;
+ ndvert->dw = MEM_dupallocN(dvert->dw);
+ ndvert++;
+ dvert++;
+ }
+ }
+ }
+ break;
+ }
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((pt->flag & GP_SPOINT_SELECT) == 0) {
- *npt = *pt;
- npt++;
- }
- }
+ /* free the old buffer */
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
- /* free the old buffer */
- MEM_freeN(gps->points);
+ /* save the new buffer */
+ gps->points = new_points;
+ gps->dvert = new_dvert;
+ gps->totpoints = tot;
- /* save the new buffer */
- gps->points = new_points;
- gps->totpoints = tot;
+ /* triangles cache needs to be recalculated */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
- /* triangles cache needs to be recalculated */
- gps->flag |= GP_STROKE_RECALC_CACHES;
- gps->tot_triangles = 0;
+ /* deselect the stroke, since none of its selected points will still be selected */
+ gps->flag &= ~GP_STROKE_SELECT;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
- /* deselect the stroke, since none of its selected points will still be selected */
- gps->flag &= ~GP_STROKE_SELECT;
+ changed = true;
+ }
}
-
- changed = true;
}
}
}
CTX_DATA_END;
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1144,17 +1828,17 @@ typedef struct tGPDeleteIsland {
* becomes much less
* 2) Each island gets converted to a new stroke
*/
-void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags)
+void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke,
+ int tag_flags, bool select)
{
tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
bool in_island = false;
int num_islands = 0;
- bGPDspoint *pt;
- int i;
/* First Pass: Identify start/end of islands */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bGPDspoint *pt = gps->points;
+ for (int i = 0; i < gps->totpoints; i++, pt++) {
if (pt->flag & tag_flags) {
/* selected - stop accumulating to island */
in_island = false;
@@ -1187,7 +1871,7 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
/* Create each new stroke... */
for (idx = 0; idx < num_islands; idx++) {
tGPDeleteIsland *island = &islands[idx];
- bGPDstroke *new_stroke = MEM_dupallocN(gps);
+ bGPDstroke *new_stroke = MEM_dupallocN(gps);
/* initialize triangle memory - to be calculated on next redraw */
new_stroke->triangles = NULL;
@@ -1196,11 +1880,26 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
/* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
new_stroke->totpoints = island->end_idx - island->start_idx + 1;
- new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
- /* Copy over the relevant points */
+ /* Copy over the relevant point data */
+ new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints);
+ /* Copy over vertex weight data (if available) */
+ if (new_stroke->dvert != NULL) {
+ /* Copy over the relevant vertex-weight points */
+ new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, "gp delete stroke fragment weight");
+ memcpy(new_stroke->dvert, gps->dvert + island->start_idx, sizeof(MDeformVert) * new_stroke->totpoints);
+
+ /* Copy weights */
+ int e = island->start_idx;
+ for (int i = 0; i < new_stroke->totpoints; i++) {
+ MDeformVert *dvert_dst = &gps->dvert[e];
+ MDeformVert *dvert_src = &new_stroke->dvert[i];
+ dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+ e++;
+ }
+ }
/* Each island corresponds to a new stroke. We must adjust the
* timings of these new strokes:
@@ -1220,6 +1919,11 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
pts = new_stroke->points;
for (j = 0; j < new_stroke->totpoints; j++, pts++) {
pts->time -= delta;
+ /* set flag for select again later */
+ if (select == true) {
+ pts->flag &= ~GP_SPOINT_SELECT;
+ pts->flag |= GP_SPOINT_TAG;
+ }
}
}
@@ -1237,53 +1941,70 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke
MEM_freeN(islands);
/* Delete the old stroke */
- MEM_freeN(gps->points);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
if (gps->triangles) {
MEM_freeN(gps->triangles);
}
BLI_freelinkN(&gpf->strokes, gps);
}
-
/* Split selected strokes into segments, splitting on selected points */
static int gp_delete_selected_points(bContext *C)
{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bool changed = false;
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps, *gpsn;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- if (gpf == NULL)
- continue;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
- /* simply delete strokes which are selected */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ if (gpf == NULL)
+ continue;
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
- continue;
+ /* simply delete strokes which are selected */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)
+ continue;
- if (gps->flag & GP_STROKE_SELECT) {
- /* deselect old stroke, since it will be used as template for the new strokes */
- gps->flag &= ~GP_STROKE_SELECT;
- /* delete unwanted points by splitting stroke into several smaller ones */
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT);
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* deselect old stroke, since it will be used as template for the new strokes */
+ gps->flag &= ~GP_STROKE_SELECT;
+
+ /* delete unwanted points by splitting stroke into several smaller ones */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false);
- changed = true;
+ changed = true;
+ }
+ }
}
}
}
CTX_DATA_END;
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1292,6 +2013,12 @@ static int gp_delete_selected_points(bContext *C)
}
}
+/* simple wrapper to external call */
+int gp_delete_selected_point_wrap(bContext *C)
+{
+ return gp_delete_selected_points(C);
+}
+
/* ----------------------------------- */
static int gp_delete_exec(bContext *C, wmOperator *op)
@@ -1342,24 +2069,37 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_delete_types, 0, "Type", "Method used for deleting Grease Pencil data");
}
-static int gp_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
+static int gp_dissolve_exec(bContext *C, wmOperator *op)
{
- return gp_dissolve_selected_points(C);
+ eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type");
+
+ return gp_dissolve_selected_points(C, mode);
}
void GPENCIL_OT_dissolve(wmOperatorType *ot)
{
+ static EnumPropertyItem prop_gpencil_dissolve_types[] = {
+ {GP_DISSOLVE_POINTS, "POINTS", 0, "Dissolve", "Dissolve selected points"},
+ {GP_DISSOLVE_BETWEEN, "BETWEEN", 0, "Dissolve Between", "Dissolve points between selected points"},
+ {GP_DISSOLVE_UNSELECT, "UNSELECT", 0, "Dissolve Unselect", "Dissolve all unselected points"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Dissolve";
ot->idname = "GPENCIL_OT_dissolve";
ot->description = "Delete selected points without splitting strokes";
/* callbacks */
+ ot->invoke = WM_menu_invoke;
ot->exec = gp_dissolve_exec;
ot->poll = gp_stroke_edit_poll;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_dissolve_types, 0, "Type", "Method used for disolving Stroke points");
}
/* ****************** Snapping - Strokes <-> Cursor ************************ */
@@ -1381,8 +2121,11 @@ static bool gp_snap_poll(bContext *C)
static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- RegionView3D *rv3d = CTX_wm_region_data(C);
- const float gridf = rv3d->gridview;
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
+ const float gridf = ED_view3d_grid_scale(scene, v3d, NULL);
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
@@ -1390,10 +2133,8 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix object */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
bGPDspoint *pt;
@@ -1403,37 +2144,32 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
continue;
// TODO: if entire stroke is selected, offset entire stroke by same amount?
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
/* only if point is selected */
if (pt->flag & GP_SPOINT_SELECT) {
- if (gpl->parent == NULL) {
- pt->x = gridf * floorf(0.5f + pt->x / gridf);
- pt->y = gridf * floorf(0.5f + pt->y / gridf);
- pt->z = gridf * floorf(0.5f + pt->z / gridf);
- }
- else {
- /* apply parent transformations */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
- fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
- fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
- fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
+ fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
+ fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
+ fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
- /* return data */
- copy_v3_v3(&pt->x, fpt);
- gp_apply_parent_point(gpl, pt);
- }
+ /* return data */
+ copy_v3_v3(&pt->x, fpt);
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
}
}
}
}
}
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&obact->id, DEG_TAG_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1460,10 +2196,11 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
- const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d);
+ const float *cursor_global = scene->cursor.location;
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
@@ -1471,10 +2208,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
bGPDspoint *pt;
@@ -1484,7 +2219,7 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
continue;
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
@@ -1507,9 +2242,7 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
copy_v3_v3(&pt->x, cursor_global);
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pt);
- }
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
}
}
}
@@ -1518,6 +2251,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
}
}
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&obact->id, DEG_TAG_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -1538,7 +2273,7 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
/* props */
ot->prop = RNA_def_boolean(ot->srna, "use_offset", true, "With Offset",
- "Offset the entire stroke instead of selected points only");
+ "Offset the entire stroke instead of selected points only");
}
/* ------------------------------- */
@@ -1549,8 +2284,10 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = CTX_data_active_object(C);
- float *cursor = ED_view3d_cursor3d_get(scene, v3d);
+ float *cursor = scene->cursor.location;
float centroid[3] = {0.0f};
float min[3], max[3];
size_t count = 0;
@@ -1564,10 +2301,8 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
bGPDspoint *pt;
@@ -1577,7 +2312,7 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false)
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false)
continue;
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
@@ -1585,18 +2320,13 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
- if (gpl->parent == NULL) {
- add_v3_v3(centroid, &pt->x);
- minmax_v3v3_v3(min, max, &pt->x);
- }
- else {
- /* apply parent transformations */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* apply parent transformations */
+ float fpt[3];
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+
+ add_v3_v3(centroid, fpt);
+ minmax_v3v3_v3(min, max, fpt);
- add_v3_v3(centroid, fpt);
- minmax_v3v3_v3(min, max, fpt);
- }
count++;
}
}
@@ -1605,7 +2335,7 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
}
}
- if (v3d->around == V3D_AROUND_CENTER_MEAN && count) {
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEAN && count) {
mul_v3_fl(centroid, 1.0f / (float)count);
copy_v3_v3(cursor, centroid);
}
@@ -1614,7 +2344,9 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
}
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+
return OPERATOR_FINISHED;
}
@@ -1648,13 +2380,20 @@ static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* Apply thickness */
- gps->thickness = gps->thickness + gpl->thickness;
+ if ((gps->thickness == 0) && (gpl->line_change == 0)) {
+ gps->thickness = gpl->thickness;
+ }
+ else {
+ gps->thickness = gps->thickness + gpl->line_change;
+ }
}
}
/* clear value */
gpl->thickness = 0.0f;
+ gpl->line_change = 0;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1683,6 +2422,8 @@ enum {
static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+
const int type = RNA_enum_get(op->ptr, "type");
/* sanity checks */
@@ -1696,13 +2437,13 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
continue;
for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- bGPDpalettecolor *palcolor = gps->palcolor;
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
/* skip strokes that are not selected or invalid for current view */
if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* skip hidden or locked colors */
- if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED))
+ if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) || (gp_style->flag & GP_STYLE_COLOR_LOCKED))
continue;
switch (type) {
@@ -1727,6 +2468,7 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1807,15 +2549,18 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
}
/* Helper: copy point between strokes */
-static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3],
- float pressure, float strength, float deltatime)
+static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, int idx, float delta[3],
+ float pressure, float strength, float deltatime)
{
bGPDspoint *newpoint;
gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
+ }
gps->totpoints++;
-
newpoint = &gps->points[gps->totpoints - 1];
+
newpoint->x = point->x * delta[0];
newpoint->y = point->y * delta[1];
newpoint->z = point->z * delta[2];
@@ -1823,6 +2568,14 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float
newpoint->pressure = pressure;
newpoint->strength = strength;
newpoint->time = point->time + deltatime;
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert = &gps->dvert[idx];
+ MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1];
+
+ newdvert->totweight = dvert->totweight;
+ newdvert->dw = MEM_dupallocN(dvert->dw);
+ }
}
/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
@@ -1868,18 +2621,18 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, co
/* 1st: add one tail point to start invisible area */
point = gps_a->points[gps_a->totpoints - 1];
deltatime = point.time;
- gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f);
+ gpencil_stroke_copy_point(gps_a, &point, gps_a->totpoints - 1, delta, 0.0f, 0.0f, 0.0f);
/* 2nd: add one head point to finish invisible area */
point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime);
+ gpencil_stroke_copy_point(gps_a, &point, 0, delta, 0.0f, 0.0f, deltatime);
}
/* 3rd: add all points */
for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
/* check if still room in buffer */
if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
- gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime);
+ gpencil_stroke_copy_point(gps_a, pt, i, delta, pt->pressure, pt->strength, deltatime);
}
}
}
@@ -1889,8 +2642,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
bGPDstroke *gps, *gpsn;
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+ Object *ob = CTX_data_active_object(C);
bGPDframe *gpf_a = NULL;
bGPDstroke *stroke_a = NULL;
@@ -1926,7 +2678,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
@@ -1946,15 +2698,17 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
if (new_stroke == NULL) {
new_stroke = MEM_dupallocN(stroke_a);
new_stroke->points = MEM_dupallocN(stroke_a->points);
+ if (stroke_a->dvert != NULL) {
+ new_stroke->dvert = MEM_dupallocN(stroke_a->dvert);
+ BKE_gpencil_stroke_weights_duplicate(stroke_a, new_stroke);
+ }
new_stroke->triangles = NULL;
new_stroke->tot_triangles = 0;
new_stroke->flag |= GP_STROKE_RECALC_CACHES;
/* if new, set current color */
if (type == GP_STROKE_JOINCOPY) {
- new_stroke->palcolor = palcolor;
- BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname));
- new_stroke->flag |= GP_STROKE_RECALC_COLOR;
+ new_stroke->mat_nr = stroke_a->mat_nr;
}
}
@@ -1993,6 +2747,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -2028,6 +2783,7 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot)
static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
/* sanity checks */
if (ELEM(NULL, gpd))
@@ -2047,7 +2803,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
@@ -2059,6 +2815,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -2082,27 +2839,30 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
/* ***************** Reproject Strokes ********************** */
typedef enum eGP_ReprojectModes {
+ /* Axis */
+ GP_REPROJECT_FRONT = 0,
+ GP_REPROJECT_SIDE,
+ GP_REPROJECT_TOP,
/* On same plane, parallel to viewplane */
- GP_REPROJECT_PLANAR = 0,
+ GP_REPROJECT_VIEW,
/* Reprojected on to the scene geometry */
GP_REPROJECT_SURFACE,
} eGP_ReprojectModes;
-static bool gp_strokes_reproject_poll(bContext *C)
-{
- /* 2 Requirements:
- * - 1) Editable GP data
- * - 2) 3D View only (2D editors don't have projection issues)
- */
- return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
-}
-
static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
GP_SpaceConversion gsc = {NULL};
- eGP_ReprojectModes mode = RNA_boolean_get(op->ptr, "type");
+ eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type");
+
+ float origin[3];
/* init space conversion stuff */
gp_point_conversion_init(C, &gsc);
@@ -2110,13 +2870,13 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
/* init autodist for geometry projection */
if (mode == GP_REPROJECT_SURFACE) {
view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar);
- ED_view3d_autodist_init(bmain, scene, gsc.ar, CTX_wm_view3d(C), 0);
+ ED_view3d_autodist_init(depsgraph, gsc.ar, CTX_wm_view3d(C), 0);
}
// TODO: For deforming geometry workflow, create new frames?
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
- GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
if (gps->flag & GP_STROKE_SELECT) {
bGPDspoint *pt;
@@ -2125,9 +2885,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
/* Compute inverse matrix for unapplying parenting once instead of doing per-point */
/* TODO: add this bit to the iteration macro? */
- if (gpl->parent) {
- invert_m4_m4(inverse_diff_mat, diff_mat);
- }
+ invert_m4_m4(inverse_diff_mat, gpstroke_iter.diff_mat);
/* Adjust each point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
@@ -2138,19 +2896,51 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
* coordinates, resulting in lost precision, which in turn causes stairstepping
* artifacts in the final points.
*/
- if (gpl->parent == NULL) {
- gp_point_to_xy_fl(&gsc, gps, pt, &xy[0], &xy[1]);
- }
- else {
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
- }
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
+ gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
+
+ /* Project stroke in one axis */
+ if (ELEM(mode, GP_REPROJECT_FRONT, GP_REPROJECT_SIDE, GP_REPROJECT_TOP)) {
+ ED_gp_get_drawing_reference(scene, ob, gpl,
+ ts->gpencil_v3d_align, origin);
+
+ int axis = 0;
+ switch (mode) {
+ case GP_REPROJECT_FRONT:
+ {
+ axis = 1;
+ break;
+ }
+ case GP_REPROJECT_SIDE:
+ {
+ axis = 0;
+ break;
+ }
+ case GP_REPROJECT_TOP:
+ {
+ axis = 2;
+ break;
+ }
+ default:
+ {
+ axis = 1;
+ break;
+ }
+ }
+
+ ED_gp_project_point_to_plane(ob, rv3d, origin,
+ axis, &pt2);
+ copy_v3_v3(&pt->x, &pt2.x);
+
+ /* apply parent again */
+ gp_apply_parent_point(depsgraph, ob, gpd, gpl, pt);
+ }
/* Project screenspace back to 3D space (from current perspective)
* so that all points have been treated the same way
*/
- if (mode == GP_REPROJECT_PLANAR) {
+ else if (mode == GP_REPROJECT_VIEW) {
/* Planar - All on same plane parallel to the viewplane */
gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
}
@@ -2173,14 +2963,15 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
}
/* Unapply parent corrections */
- if (gpl->parent) {
+ if (!ELEM(mode, GP_REPROJECT_FRONT, GP_REPROJECT_SIDE, GP_REPROJECT_TOP)) {
mul_m4_v3(inverse_diff_mat, &pt->x);
}
}
}
}
- GP_EDITABLE_STROKES_END;
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -2188,7 +2979,13 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_reproject(wmOperatorType *ot)
{
static const EnumPropertyItem reproject_type[] = {
- {GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar",
+ {GP_REPROJECT_FRONT, "FRONT", 0, "Front",
+ "Reproject the strokes using the X-Z plane"},
+ {GP_REPROJECT_SIDE, "SIDE", 0, "Side",
+ "Reproject the strokes using the Y-Z plane"},
+ {GP_REPROJECT_TOP, "TOP", 0, "Top",
+ "Reproject the strokes using the X-Y plane"},
+ {GP_REPROJECT_VIEW, "VIEW", 0, "View",
"Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
"using 'Cursor' Stroke Placement"},
{GP_REPROJECT_SURFACE, "SURFACE", 0, "Surface",
@@ -2200,19 +2997,19 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
ot->name = "Reproject Strokes";
ot->idname = "GPENCIL_OT_reproject";
ot->description = "Reproject the selected strokes from the current viewpoint as if they had been newly drawn "
- "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, "
- "or for matching deforming geometry)";
+ "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, "
+ "or for matching deforming geometry)";
/* callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = gp_strokes_reproject_exec;
- ot->poll = gp_strokes_reproject_poll;
+ ot->poll = gp_strokes_edit3d_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", reproject_type, GP_REPROJECT_PLANAR, "Projection Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", reproject_type, GP_REPROJECT_VIEW, "Projection Type", "");
}
/* ******************* Stroke subdivide ************************** */
@@ -2227,7 +3024,7 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps)
if (pt->flag & GP_SPOINT_SELECT) {
if (i + 1 < gps->totpoints) {
if (gps->points[i + 1].flag & GP_SPOINT_SELECT) {
- ++totnewpoints;
+ totnewpoints++;
}
}
}
@@ -2235,6 +3032,7 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps)
return totnewpoints;
}
+
static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -2249,7 +3047,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* Go through each editable + selected stroke */
- GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
if (gps->flag & GP_STROKE_SELECT) {
/* loop as many times as cuts */
@@ -2262,9 +3060,20 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
temp_points = MEM_dupallocN(gps->points);
oldtotpoints = gps->totpoints;
- /* resize the points arrys */
+ MDeformVert *temp_dverts = NULL;
+ MDeformVert *dvert_final = NULL;
+ MDeformVert *dvert = NULL;
+ MDeformVert *dvert_next = NULL;
+ if (gps->dvert != NULL) {
+ temp_dverts = MEM_dupallocN(gps->dvert);
+ }
+
+ /* resize the points arrays */
gps->totpoints += totnewpoints;
gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
gps->flag |= GP_STROKE_RECALC_CACHES;
/* loop and interpolate */
@@ -2279,13 +3088,23 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
pt_final->strength = pt->strength;
pt_final->time = pt->time;
pt_final->flag = pt->flag;
- ++i2;
+
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_final = &gps->dvert[i2];
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ }
+ i2++;
/* if next point is selected add a half way point */
if (pt->flag & GP_SPOINT_SELECT) {
if (i + 1 < oldtotpoints) {
if (temp_points[i + 1].flag & GP_SPOINT_SELECT) {
pt_final = &gps->points[i2];
+ if (gps->dvert != NULL) {
+ dvert_final = &gps->dvert[i2];
+ }
/* Interpolate all values */
bGPDspoint *next = &temp_points[i + 1];
interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
@@ -2294,19 +3113,46 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt_final->time = interpf(pt->time, next->time, 0.5f);
pt_final->flag |= GP_SPOINT_SELECT;
- ++i2;
+
+ /* interpolate weights */
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_next = &temp_dverts[i + 1];
+ dvert_final = &gps->dvert[i2];
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = MEM_dupallocN(dvert->dw);
+
+ /* interpolate weight values */
+ for (int d = 0; d < dvert->totweight; d++) {
+ MDeformWeight *dw_a = &dvert->dw[d];
+ if (dvert_next->totweight > d) {
+ MDeformWeight *dw_b = &dvert_next->dw[d];
+ MDeformWeight *dw_final = &dvert_final->dw[d];
+ dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
+ }
+ }
+ }
+
+ i2++;
}
}
}
}
/* free temp memory */
- MEM_freeN(temp_points);
+ MEM_SAFE_FREE(temp_points);
+ MEM_SAFE_FREE(temp_dverts);
}
+
+ /* triangles cache needs to be recalculated */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
}
}
- GP_EDITABLE_STROKES_END;
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -2326,7 +3172,7 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
ot->poll = gp_active_layer_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, 5);
@@ -2334,3 +3180,414 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
+/* ** simplify stroke *** */
+static int gp_stroke_simplify_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ float factor = RNA_float_get(op->ptr, "factor");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* simplify stroke using Ramer-Douglas-Peucker algorithm */
+ BKE_gpencil_simplify_stroke(gps, factor);
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_simplify(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Simplify Stroke";
+ ot->idname = "GPENCIL_OT_stroke_simplify";
+ ot->description = "Simplify selected stroked reducing number of points";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_simplify_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, 100.0f, "Factor", "", 0.0f, 100.0f);
+ /* avoid re-using last var */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ** simplify stroke using fixed algorithm *** */
+static int gp_stroke_simplify_fixed_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ int steps = RNA_int_get(op->ptr, "step");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* Go through each editable + selected stroke */
+ GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ for (int i = 0; i < steps; i++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_simplify_fixed(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Simplify Fixed Stroke";
+ ot->idname = "GPENCIL_OT_stroke_simplify_fixed";
+ ot->description = "Simplify selected stroked reducing number of points using fixed algorithm";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_simplify_fixed_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Steps", "Number of simplify steps", 1, 10);
+
+ /* avoid re-using last var */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+}
+
+/* ***************** Separate Strokes ********************** */
+typedef enum eGP_SeparateModes {
+ /* Points */
+ GP_SEPARATE_POINT = 0,
+ /* Selected Strokes */
+ GP_SEPARATE_STROKE,
+ /* Current Layer */
+ GP_SEPARATE_LAYER,
+} eGP_SeparateModes;
+
+static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
+{
+ Base *base_new;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Base *base_old = CTX_data_active_base(C);
+ bGPdata *gpd_src = ED_gpencil_data_get_active(C);
+ Object *ob = CTX_data_active_object(C);
+
+ Object *ob_dst = NULL;
+ bGPdata *gpd_dst = NULL;
+ bGPDlayer *gpl_dst = NULL;
+ bGPDframe *gpf_dst = NULL;
+ bGPDspoint *pt;
+ Material *ma = NULL;
+ int i, idx;
+
+ eGP_SeparateModes mode = RNA_enum_get(op->ptr, "mode");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd_src)) {
+ return OPERATOR_CANCELLED;
+ }
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src);
+
+ /* create a new object */
+ base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, 0);
+ ob_dst = base_new->object;
+ ob_dst->mode = OB_MODE_OBJECT;
+ /* create new grease pencil datablock */
+ // XXX: check usercounts
+ gpd_dst = BKE_gpencil_data_addnew(bmain, gpd_src->id.name + 2);
+ ob_dst->data = (bGPdata *)gpd_dst;
+
+ int totslots = ob_dst->totcol;
+ int totadd = 0;
+
+ /* loop old datablock and separate parts */
+ if ((mode == GP_SEPARATE_POINT) || (mode == GP_SEPARATE_STROKE)) {
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ gpl_dst = NULL;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL) {
+ continue;
+ }
+
+ gpf_dst = NULL;
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* separate selected strokes */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* add layer if not created before */
+ if (gpl_dst == NULL) {
+ gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false);
+ }
+
+ /* add frame if not created before */
+ if (gpf_dst == NULL) {
+ gpf_dst = BKE_gpencil_layer_getframe(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW);
+ }
+
+ /* add duplicate materials */
+ ma = give_current_material(ob, gps->mat_nr + 1);
+ idx = BKE_gpencil_get_material_index(ob_dst, ma);
+ if (idx == 0) {
+
+ totadd++;
+ ob_dst->actcol = totadd;
+ ob_dst->totcol = totadd;
+
+ if (totadd > totslots) {
+ BKE_object_material_slot_add(bmain, ob_dst);
+ }
+
+ assign_material(bmain, ob_dst, ma, ob_dst->totcol, BKE_MAT_ASSIGN_USERPREF);
+ idx = totadd;
+ }
+
+ /* selected points mode */
+ if (mode == GP_SEPARATE_POINT) {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+
+ /* reasign material */
+ gps_dst->mat_nr = idx - 1;
+
+ /* link to destination frame */
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+
+ /* Invert selection status of all points in destination stroke */
+ for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
+ pt->flag ^= GP_SPOINT_SELECT;
+ }
+
+ /* delete selected points from destination stroke */
+ gp_stroke_delete_tagged_points(gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false);
+
+ /* delete selected points from origin stroke */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false);
+ }
+ /* selected strokes mode */
+ else if (mode == GP_SEPARATE_STROKE) {
+ /* deselect old stroke */
+ gps->flag &= ~GP_STROKE_SELECT;
+ /* unlink from source frame */
+ BLI_remlink(&gpf->strokes, gps);
+ gps->prev = gps->next = NULL;
+ /* relink to destination frame */
+ BLI_addtail(&gpf_dst->strokes, gps);
+ /* reasign material */
+ gps->mat_nr = idx - 1;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+ else if (mode == GP_SEPARATE_LAYER) {
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ if (gpl) {
+ /* try to set a new active layer in source datablock */
+ if (gpl->prev) {
+ BKE_gpencil_layer_setactive(gpd_src, gpl->prev);
+ }
+ else if (gpl->next) {
+ BKE_gpencil_layer_setactive(gpd_src, gpl->next);
+ }
+ /* unlink from source datablock */
+ BLI_remlink(&gpd_src->layers, gpl);
+ gpl->prev = gpl->next = NULL;
+ /* relink to destination datablock */
+ BLI_addtail(&gpd_dst->layers, gpl);
+ }
+ }
+ DEG_id_tag_update(&gpd_src->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&gpd_dst->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_separate(wmOperatorType *ot)
+{
+ static const EnumPropertyItem separate_type[] = {
+ {GP_SEPARATE_POINT, "POINT", 0, "Selected Points", "Separate the selected points"},
+ {GP_SEPARATE_STROKE, "STROKE", 0, "Selected Strokes", "Separate the selected strokes"},
+ {GP_SEPARATE_LAYER, "LAYER", 0, "Active Layer", "Separate the strokes of the current layer"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Separate Strokes";
+ ot->idname = "GPENCIL_OT_stroke_separate";
+ ot->description = "Separate the selected strokes or layer in a new grease pencil object";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gp_stroke_separate_exec;
+ ot->poll = gp_strokes_edit3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", "");
+}
+
+/* ***************** Split Strokes ********************** */
+static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDspoint *pt;
+ int i;
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+
+ /* loop strokes and split parts */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ bGPDstroke *gps, *gpsn;
+
+ if (gpf == NULL) {
+ continue;
+ }
+
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ /* split selected strokes */
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* make copy of source stroke */
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+
+ /* link to same frame */
+ BLI_addtail(&gpf->strokes, gps_dst);
+
+ /* invert selection status of all points in destination stroke */
+ for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) {
+ pt->flag ^= GP_SPOINT_SELECT;
+ }
+
+ /* delete selected points from destination stroke */
+ gp_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true);
+
+ /* delete selected points from origin stroke */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false);
+ }
+ }
+ /* select again tagged points */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *ptn = gps->points;
+ for (int i2 = 0; i2 < gps->totpoints; i2++, ptn++) {
+ if (ptn->flag & GP_SPOINT_TAG) {
+ ptn->flag |= GP_SPOINT_SELECT;
+ ptn->flag &= ~GP_SPOINT_TAG;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Split Strokes";
+ ot->idname = "GPENCIL_OT_stroke_split";
+ ot->description = "Split selected points as new stroke on same frame";
+
+ /* callbacks */
+ ot->exec = gp_stroke_split_exec;
+ ot->poll = gp_strokes_edit3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
new file mode 100644
index 00000000000..50b7d25394d
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -0,0 +1,1285 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation, Joshua Leung
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+ /** \file blender/editors/gpencil/gpencil_fill.c
+ * \ingroup edgpencil
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_stack.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_main.h"
+#include "BKE_brush.h"
+#include "BKE_deform.h"
+#include "BKE_image.h"
+#include "BKE_gpencil.h"
+#include "BKE_material.h"
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_paint.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+#include "GPU_matrix.h"
+#include "GPU_framebuffer.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+#define LEAK_HORZ 0
+#define LEAK_VERT 1
+
+
+ /* Temporary fill operation data (op->customdata) */
+typedef struct tGPDfill {
+ struct Main *bmain;
+ struct Depsgraph *depsgraph;
+ struct wmWindow *win; /* window where painting originated */
+ struct Scene *scene; /* current scene from context */
+ struct Object *ob; /* current active gp object */
+ struct ScrArea *sa; /* area where painting originated */
+ struct RegionView3D *rv3d; /* region where painting originated */
+ struct View3D *v3d; /* view3 where painting originated */
+ struct ARegion *ar; /* region where painting originated */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct Material *mat; /* current material */
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *gpf; /* frame */
+
+ short flag; /* flags */
+ short oldkey; /* avoid too fast events */
+ bool on_back; /* send to back stroke */
+
+ int center[2]; /* mouse fill center position */
+ int sizex; /* windows width */
+ int sizey; /* window height */
+ int lock_axis; /* lock to viewport axis */
+
+ short fill_leak; /* number of pixel to consider the leak is too small (x 2) */
+ float fill_threshold; /* factor for transparency */
+ int fill_simplylvl; /* number of simplify steps */
+ int fill_draw_mode; /* boundary limits drawing mode */
+
+ short sbuffer_size; /* number of elements currently in cache */
+ void *sbuffer; /* temporary points */
+ float *depth_arr; /* depth array for reproject */
+
+ Image *ima; /* temp image */
+ BLI_Stack *stack; /* temp points data */
+ void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
+} tGPDfill;
+
+
+/* draw a given stroke using same thickness and color for all points */
+static void gp_draw_basic_stroke(
+ tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4],
+ const bool cyclic, const float ink[4], const int flag, const float thershold)
+{
+ bGPDspoint *points = gps->points;
+
+ Material *ma = tgpf->mat;
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ int totpoints = gps->totpoints;
+ float fpt[3];
+ float col[4];
+
+ copy_v4_v4(col, ink);
+
+ /* if cyclic needs more vertex */
+ int cyclic_add = (cyclic) ? 1 : 0;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ /* draw stroke curve */
+ glLineWidth(1.0f);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ const bGPDspoint *pt = points;
+
+ for (int i = 0; i < totpoints; i++, pt++) {
+
+ if (flag & GP_BRUSH_FILL_HIDE) {
+ float alpha = gp_style->stroke_rgba[3] * pt->strength;
+ CLAMP(alpha, 0.0f, 1.0f);
+ col[3] = alpha <= thershold ? 0.0f : 1.0f;
+ }
+ else {
+ col[3] = 1.0f;
+ }
+ /* set point */
+ immAttr4fv(color, col);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ immVertex3fv(pos, fpt);
+ }
+
+ if (cyclic && totpoints > 2) {
+ /* draw line to first point to complete the cycle */
+ immAttr4fv(color, col);
+ mul_v3_m4v3(fpt, diff_mat, &points->x);
+ immVertex3fv(pos, fpt);
+ }
+
+ immEnd();
+ immUnbindProgram();
+}
+
+/* loop all layers */
+static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
+{
+ /* duplicated: etempFlags */
+ enum {
+ GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */
+ GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */
+ };
+
+ Object *ob = tgpf->ob;
+ bGPdata *gpd = tgpf->gpd;
+ int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
+
+ tGPDdraw tgpw;
+ tgpw.rv3d = tgpf->rv3d;
+ tgpw.depsgraph = tgpf->depsgraph;
+ tgpw.ob = ob;
+ tgpw.gpd = gpd;
+ tgpw.offsx = 0;
+ tgpw.offsy = 0;
+ tgpw.winx = tgpf->ar->winx;
+ tgpw.winy = tgpf->ar->winy;
+ tgpw.dflag = 0;
+ tgpw.disable_fill = 1;
+ tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS);
+
+ glEnable(GL_BLEND);
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* calculate parent position */
+ ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
+
+ /* do not draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* get frame to draw */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if ((gps->points == NULL) || (gps->totpoints < 2)) {
+ continue;
+ }
+ /* check if the color is visible */
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) {
+ continue;
+ }
+
+ tgpw.gps = gps;
+ tgpw.gpl = gpl;
+ tgpw.gpf = gpf;
+ tgpw.t_gpf = gpf;
+
+ /* reduce thickness to avoid gaps */
+ tgpw.lthick = gpl->line_change - 4;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, ink);
+ tgpw.onion = true;
+ tgpw.custonion = true;
+
+ /* normal strokes */
+ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH))
+ {
+ ED_gp_draw_fill(&tgpw);
+
+ }
+
+ /* 3D Lines with basic shapes and invisible lines */
+ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH))
+ {
+ gp_draw_basic_stroke(
+ tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink,
+ tgpf->flag, tgpf->fill_threshold);
+ }
+ }
+ }
+
+ glDisable(GL_BLEND);
+}
+
+/* draw strokes in offscreen buffer */
+static void gp_render_offscreen(tGPDfill *tgpf)
+{
+ bool is_ortho = false;
+ float winmat[4][4];
+
+ if (!tgpf->gpd) {
+ return;
+ }
+
+ char err_out[256] = "unknown";
+ GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, 0, true, false, err_out);
+ GPU_offscreen_bind(offscreen, true);
+ uint flag = IB_rect | IB_rectfloat;
+ ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag);
+
+ rctf viewplane;
+ float clipsta, clipend;
+
+ is_ortho = ED_view3d_viewplane_get(tgpf->depsgraph, tgpf->v3d, tgpf->rv3d, tgpf->sizex, tgpf->sizey, &viewplane, &clipsta, &clipend, NULL);
+ if (is_ortho) {
+ orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
+ }
+ else {
+ perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+ }
+
+ /* set temporary new size */
+ int bwinx = tgpf->ar->winx;
+ int bwiny = tgpf->ar->winy;
+ rcti brect = tgpf->ar->winrct;
+
+ tgpf->ar->winx = (short)tgpf->sizex;
+ tgpf->ar->winy = (short)tgpf->sizey;
+ tgpf->ar->winrct.xmin = 0;
+ tgpf->ar->winrct.ymin = 0;
+ tgpf->ar->winrct.xmax = tgpf->sizex;
+ tgpf->ar->winrct.ymax = tgpf->sizey;
+
+ GPU_matrix_push_projection();
+ GPU_matrix_identity_set();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ED_view3d_update_viewmat(
+ tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar,
+ NULL, winmat, NULL);
+ /* set for opengl */
+ GPU_matrix_projection_set(tgpf->rv3d->winmat);
+ GPU_matrix_set(tgpf->rv3d->viewmat);
+
+ /* draw strokes */
+ float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ gp_draw_datablock(tgpf, ink);
+
+ /* restore size */
+ tgpf->ar->winx = (short)bwinx;
+ tgpf->ar->winy = (short)bwiny;
+ tgpf->ar->winrct = brect;
+
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
+
+ /* create a image to see result of template */
+ if (ibuf->rect_float) {
+ GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
+ }
+ else if (ibuf->rect) {
+ GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
+ }
+ if (ibuf->rect_float && ibuf->rect) {
+ IMB_rect_from_float(ibuf);
+ }
+
+ tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill");
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+
+ BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
+
+ /* switch back to window-system-provided framebuffer */
+ GPU_offscreen_unbind(offscreen, true);
+ GPU_offscreen_free(offscreen);
+}
+
+/* return pixel data (rgba) at index */
+static void get_pixel(const ImBuf *ibuf, const int idx, float r_col[4])
+{
+ if (ibuf->rect_float) {
+ const float *frgba = &ibuf->rect_float[idx * 4];
+ copy_v4_v4(r_col, frgba);
+ }
+ else {
+ /* XXX: This case probably doesn't happen, as we only write to the float buffer,
+ * but we get compiler warnings about uninitialised vars otherwise
+ */
+ BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!");
+ zero_v4(r_col);
+ }
+}
+
+/* set pixel data (rgba) at index */
+static void set_pixel(ImBuf *ibuf, int idx, const float col[4])
+{
+ //BLI_assert(idx <= ibuf->x * ibuf->y);
+ if (ibuf->rect) {
+ uint *rrect = &ibuf->rect[idx];
+ uchar ccol[4];
+
+ rgba_float_to_uchar(ccol, col);
+ *rrect = *((uint *)ccol);
+ }
+
+ if (ibuf->rect_float) {
+ float *rrectf = &ibuf->rect_float[idx * 4];
+ copy_v4_v4(rrectf, col);
+ }
+}
+
+/* check if the size of the leak is narrow to determine if the stroke is closed
+ * this is used for strokes with small gaps between them to get a full fill
+ * and do not get a full screen fill.
+ *
+ * \param ibuf Image pixel data
+ * \param maxpixel Maximum index
+ * \param limit Limit of pixels to analyze
+ * \param index Index of current pixel
+ * \param type 0-Horizontal 1-Vertical
+ */
+static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type)
+{
+ float rgba[4];
+ int i;
+ int pt;
+ bool t_a = false;
+ bool t_b = false;
+
+ /* Horizontal leak (check vertical pixels)
+ * X
+ * X
+ * xB7
+ * X
+ * X
+ */
+ if (type == LEAK_HORZ) {
+ /* pixels on top */
+ for (i = 1; i <= limit; i++) {
+ pt = index + (ibuf->x * i);
+ if (pt <= maxpixel) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_a = true;
+ break;
+ }
+ }
+ else {
+ t_a = true; /* edge of image*/
+ break;
+ }
+ }
+ /* pixels on bottom */
+ for (i = 1; i <= limit; i++) {
+ pt = index - (ibuf->x * i);
+ if (pt >= 0) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_b = true;
+ break;
+ }
+ }
+ else {
+ t_b = true; /* edge of image*/
+ break;
+ }
+ }
+ }
+
+ /* Vertical leak (check horizontal pixels)
+ *
+ * XXXxB7XX
+ */
+ if (type == LEAK_VERT) {
+ /* get pixel range of the row */
+ int row = index / ibuf->x;
+ int lowpix = row * ibuf->x;
+ int higpix = lowpix + ibuf->x - 1;
+
+ /* pixels to right */
+ for (i = 0; i < limit; i++) {
+ pt = index - (limit - i);
+ if (pt >= lowpix) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_a = true;
+ break;
+ }
+ }
+ else {
+ t_a = true; /* edge of image*/
+ break;
+ }
+ }
+ /* pixels to left */
+ for (i = 0; i < limit; i++) {
+ pt = index + (limit - i);
+ if (pt <= higpix) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_b = true;
+ break;
+ }
+ }
+ else {
+ t_b = true; /* edge of image */
+ break;
+ }
+ }
+ }
+ return (bool)(t_a && t_b);
+}
+
+/* Boundary fill inside strokes
+ * Fills the space created by a set of strokes using the stroke color as the boundary
+ * of the shape to fill.
+ *
+ * \param tgpf Temporary fill data
+ */
+static void gpencil_boundaryfill_area(tGPDfill *tgpf)
+{
+ ImBuf *ibuf;
+ float rgba[4];
+ void *lock;
+ const float fill_col[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ const int maxpixel = (ibuf->x * ibuf->y) - 1;
+
+ BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
+
+ /* calculate index of the seed point using the position of the mouse */
+ int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0];
+ if ((index >= 0) && (index < maxpixel)) {
+ BLI_stack_push(stack, &index);
+ }
+
+ /* the fill use a stack to save the pixel list instead of the common recursive
+ * 4-contact point method.
+ * The problem with recursive calls is that for big fill areas, we can get max limit
+ * of recursive calls and STACK_OVERFLOW error.
+ *
+ * The 4-contact point analyze the pixels to the left, right, bottom and top
+ * -----------
+ * | X |
+ * | XoX |
+ * | X |
+ * -----------
+ */
+ while (!BLI_stack_is_empty(stack)) {
+ int v;
+ BLI_stack_pop(stack, &v);
+
+ get_pixel(ibuf, v, rgba);
+
+ if (true) { /* Was: 'rgba' */
+ /* check if no border(red) or already filled color(green) */
+ if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
+ /* fill current pixel */
+ set_pixel(ibuf, v, fill_col);
+
+ /* add contact pixels */
+ /* pixel left */
+ if (v - 1 >= 0) {
+ index = v - 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel right */
+ if (v + 1 < maxpixel) {
+ index = v + 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel top */
+ if (v + tgpf->sizex < maxpixel) {
+ index = v + tgpf->sizex;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel bottom */
+ if (v - tgpf->sizex >= 0) {
+ index = v - tgpf->sizex;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ }
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+ /* free temp stack data */
+ BLI_stack_free(stack);
+}
+
+/* clean external border of image to avoid infinite loops */
+static void gpencil_clean_borders(tGPDfill *tgpf)
+{
+ ImBuf *ibuf;
+ void *lock;
+ const float fill_col[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int idx;
+ int pixel = 0;
+
+ /* horizontal lines */
+ for (idx = 0; idx < ibuf->x - 1; idx++) {
+ /* bottom line */
+ set_pixel(ibuf, idx, fill_col);
+ /* top line */
+ pixel = idx + (ibuf->x * (ibuf->y - 1));
+ set_pixel(ibuf, pixel, fill_col);
+ }
+ /* vertical lines */
+ for (idx = 0; idx < ibuf->y; idx++) {
+ /* left line */
+ set_pixel(ibuf, ibuf->x * idx, fill_col);
+ /* right line */
+ pixel = ibuf->x * idx + (ibuf->x - 1);
+ set_pixel(ibuf, pixel, fill_col);
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+}
+
+/* Get the outline points of a shape using Moore Neighborhood algorithm
+ *
+ * This is a Blender customized version of the general algorithm described
+ * in https://en.wikipedia.org/wiki/Moore_neighborhood
+ */
+static void gpencil_get_outline_points(tGPDfill *tgpf)
+{
+ ImBuf *ibuf;
+ float rgba[4];
+ void *lock;
+ int v[2];
+ int boundary_co[2];
+ int start_co[2];
+ int backtracked_co[2];
+ int current_check_co[2];
+ int prev_check_co[2];
+ int backtracked_offset[1][2] = {{0, 0}};
+ // bool boundary_found = false;
+ bool start_found = false;
+ const int NEIGHBOR_COUNT = 8;
+
+ const int offset[8][2] = {
+ {-1, -1},
+ {0, -1},
+ {1, -1},
+ {1, 0},
+ {1, 1},
+ {0, 1},
+ {-1, 1},
+ {-1, 0}
+ };
+
+ tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__);
+
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int imagesize = ibuf->x * ibuf->y;
+
+ /* find the initial point to start outline analysis */
+ for (int idx = imagesize - 1; idx != 0; idx--) {
+ get_pixel(ibuf, idx, rgba);
+ if (rgba[1] == 1.0f) {
+ boundary_co[0] = idx % ibuf->x;
+ boundary_co[1] = idx / ibuf->x;
+ copy_v2_v2_int(start_co, boundary_co);
+ backtracked_co[0] = (idx - 1) % ibuf->x;
+ backtracked_co[1] = (idx - 1) / ibuf->x;
+ backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
+ backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
+ copy_v2_v2_int(prev_check_co, start_co);
+
+ BLI_stack_push(tgpf->stack, &boundary_co);
+ start_found = true;
+ break;
+ }
+ }
+
+ while (start_found) {
+ int cur_back_offset = -1;
+ for (int i = 0; i < NEIGHBOR_COUNT; i++) {
+ if (backtracked_offset[0][0] == offset[i][0] &&
+ backtracked_offset[0][1] == offset[i][1])
+ {
+ /* Finding the bracktracked pixel offset index */
+ cur_back_offset = i;
+ break;
+ }
+ }
+
+ int loop = 0;
+ while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) {
+ int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT;
+ current_check_co[0] = boundary_co[0] + offset[offset_idx][0];
+ current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
+
+ int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
+ get_pixel(ibuf, image_idx, rgba);
+
+ /* find next boundary pixel */
+ if (rgba[1] == 1.0f) {
+ copy_v2_v2_int(boundary_co, current_check_co);
+ copy_v2_v2_int(backtracked_co, prev_check_co);
+ backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
+ backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
+
+ BLI_stack_push(tgpf->stack, &boundary_co);
+
+ break;
+ }
+ copy_v2_v2_int(prev_check_co, current_check_co);
+ cur_back_offset++;
+ loop++;
+ }
+ /* current pixel is equal to starting pixel */
+ if (boundary_co[0] == start_co[0] &&
+ boundary_co[1] == start_co[1])
+ {
+ BLI_stack_pop(tgpf->stack, &v);
+ // boundary_found = true;
+ break;
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+}
+
+/* get z-depth array to reproject on surface */
+static void gpencil_get_depth_array(tGPDfill *tgpf)
+{
+ tGPspoint *ptc;
+ ToolSettings *ts = tgpf->scene->toolsettings;
+ int totpoints = tgpf->sbuffer_size;
+ int i = 0;
+
+ if (totpoints == 0) {
+ return;
+ }
+
+ /* for surface sketching, need to set the right OpenGL context stuff so that
+ * the conversions will project the values correctly...
+ */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar);
+ ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0);
+
+ /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
+ int depth_margin = 0;
+
+ /* get an array of depths, far depths are blended */
+ int mval[2], mval_prev[2] = { 0 };
+ int interp_depth = 0;
+ int found_depth = 0;
+
+ tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
+
+ for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
+ copy_v2_v2_int(mval, &ptc->x);
+
+ if ((ED_view3d_autodist_depth(
+ tgpf->ar, mval, depth_margin, tgpf->depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(
+ tgpf->ar, mval, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0)))
+ {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+
+ copy_v2_v2_int(mval_prev, mval);
+ }
+
+ if (found_depth == false) {
+ /* eeh... not much we can do.. :/, ignore depth in this case */
+ for (i = totpoints - 1; i >= 0; i--)
+ tgpf->depth_arr[i] = 0.9999f;
+ }
+ else {
+ if (interp_depth) {
+ interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
+ }
+ }
+ }
+}
+
+/* create array of points using stack as source */
+static void gpencil_points_from_stack(tGPDfill *tgpf)
+{
+ tGPspoint *point2D;
+ int totpoints = BLI_stack_count(tgpf->stack);
+ if (totpoints == 0) {
+ return;
+ }
+
+ tgpf->sbuffer_size = (short)totpoints;
+ tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__);
+
+ point2D = tgpf->sbuffer;
+ while (!BLI_stack_is_empty(tgpf->stack)) {
+ int v[2];
+ BLI_stack_pop(tgpf->stack, &v);
+ point2D->x = v[0];
+ point2D->y = v[1];
+
+ point2D->pressure = 1.0f;
+ point2D->strength = 1.0f;
+ point2D->time = 0.0f;
+ point2D++;
+ }
+}
+
+/* create a grease pencil stroke using points in buffer */
+static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
+{
+ const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
+
+ ToolSettings *ts = tgpf->scene->toolsettings;
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ if (brush == NULL) {
+ return;
+ }
+
+ bGPDspoint *pt;
+ MDeformVert *dvert = NULL;
+ tGPspoint *point2D;
+
+ if (tgpf->sbuffer_size == 0) {
+ return;
+ }
+
+ /* get frame or create a new one */
+ tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+
+ /* create new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+ gps->thickness = brush->size;
+ gps->inittime = 0.0f;
+
+ /* the polygon must be closed, so enabled cyclic */
+ gps->flag |= GP_STROKE_CYCLIC;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = BKE_gpencil_get_material_index(tgpf->ob, tgpf->mat) - 1;
+ if (gps->mat_nr < 0) {
+ BKE_object_material_slot_add(tgpf->bmain, tgpf->ob);
+ assign_material(tgpf->bmain, tgpf->ob, tgpf->mat, tgpf->ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+ gps->mat_nr = tgpf->ob->totcol - 1;
+ }
+
+ /* allocate memory for storage points */
+ gps->totpoints = tgpf->sbuffer_size;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points");
+
+ /* initialize triangle memory to dummy data */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* add stroke to frame */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) {
+ BLI_addhead(&tgpf->gpf->strokes, gps);
+ }
+ else {
+ BLI_addtail(&tgpf->gpf->strokes, gps);
+ }
+
+ /* add points */
+ pt = gps->points;
+ point2D = (tGPspoint *)tgpf->sbuffer;
+
+ const int def_nr = tgpf->ob->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr);
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ dvert = gps->dvert;
+ }
+
+ for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++) {
+ /* convert screen-coordinates to 3D coordinates */
+ gp_stroke_convertcoords_tpoint(
+ tgpf->scene, tgpf->ar, tgpf->ob,
+ tgpf->gpl, point2D,
+ tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
+ &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = 0.0f;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+
+ dvert++;
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ dvert++;
+ }
+ }
+ }
+
+ /* smooth stroke */
+ float reduce = 0.0f;
+ float smoothfac = 1.0f;
+ for (int r = 0; r < 1; r++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
+ }
+ reduce += 0.25f; // reduce the factor
+ }
+
+ /* if axis locked, reproject to plane locked */
+ if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
+ float origin[3];
+ ED_gp_get_drawing_reference(
+ tgpf->scene, tgpf->ob, tgpf->gpl,
+ ts->gpencil_v3d_align, origin);
+ ED_gp_project_stroke_to_plane(
+ tgpf->ob, tgpf->rv3d, gps, origin,
+ tgpf->lock_axis - 1);
+ }
+
+ /* if parented change position relative to parent object */
+ for (int a = 0; a < tgpf->sbuffer_size; a++) {
+ pt = &gps->points[a];
+ gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
+ }
+
+ /* simplify stroke */
+ for (int b = 0; b < tgpf->fill_simplylvl; b++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
+}
+
+/* ----------------------- */
+/* Drawing */
+/* Helper: Draw status message while the user is running the operator */
+static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf))
+{
+ const char *status_str = IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
+ ED_workspace_status_text(C, status_str);
+}
+
+/* draw boundary lines to see fill limits */
+static void gpencil_draw_boundary_lines(const bContext *UNUSED(C), tGPDfill *tgpf)
+{
+ if (!tgpf->gpd) {
+ return;
+ }
+ const float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ gp_draw_datablock(tgpf, ink);
+}
+
+/* Drawing callback for modal operator in 3d mode */
+static void gpencil_fill_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
+{
+ tGPDfill *tgpf = (tGPDfill *)arg;
+ /* draw only in the region that originated operator. This is required for multiwindow */
+ ARegion *ar = CTX_wm_region(C);
+ if (ar != tgpf->ar) {
+ return;
+ }
+
+ gpencil_draw_boundary_lines(C, tgpf);
+}
+
+/* check if context is suitable for filling */
+static bool gpencil_fill_poll(bContext *C)
+{
+ if (ED_operator_regionactive(C)) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa->spacetype == SPACE_VIEW3D) {
+ return 1;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator");
+ return 0;
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ return 0;
+ }
+}
+
+/* Allocate memory and initialize values */
+static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
+{
+ tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data");
+
+ /* define initial values */
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Main *bmain = CTX_data_main(C);
+
+ /* set current scene and window info */
+ tgpf->bmain = CTX_data_main(C);
+ tgpf->scene = CTX_data_scene(C);
+ tgpf->ob = CTX_data_active_object(C);
+ tgpf->sa = CTX_wm_area(C);
+ tgpf->ar = CTX_wm_region(C);
+ tgpf->rv3d = tgpf->ar->regiondata;
+ tgpf->v3d = tgpf->sa->spacedata.first;
+ tgpf->depsgraph = CTX_data_depsgraph(C);
+ tgpf->win = CTX_wm_window(C);
+
+ /* set GP datablock */
+ tgpf->gpd = gpd;
+ tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
+ if (tgpf->gpl == NULL) {
+ tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true);
+ }
+ tgpf->lock_axis = ts->gp_sculpt.lock_axis;
+
+ tgpf->oldkey = -1;
+ tgpf->sbuffer_size = 0;
+ tgpf->sbuffer = NULL;
+ tgpf->depth_arr = NULL;
+
+ /* save filling parameters */
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ tgpf->flag = brush->gpencil_settings->flag;
+ tgpf->fill_leak = brush->gpencil_settings->fill_leak;
+ tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
+ tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
+ tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
+
+ /* get color info */
+ Material *ma = BKE_gpencil_get_material_from_brush(brush);
+ /* if no brush defaults, get material and color info */
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
+ ma = BKE_gpencil_material_ensure(bmain, tgpf->ob);
+ /* assign always the first material to the brush */
+ brush->gpencil_settings->material = give_current_material(tgpf->ob, 1);
+ }
+
+ tgpf->mat = ma;
+
+ /* init undo */
+ gpencil_undo_init(tgpf->gpd);
+
+ /* return context data for running operator */
+ return tgpf;
+}
+
+/* end operator */
+static void gpencil_fill_exit(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* clear undo stack */
+ gpencil_undo_finish();
+
+ /* restore cursor to indicate end of fill */
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ tGPDfill *tgpf = op->customdata;
+
+ /* don't assume that operator data exists at all */
+ if (tgpf) {
+ /* clear status message area */
+ ED_workspace_status_text(C, NULL);
+
+ MEM_SAFE_FREE(tgpf->sbuffer);
+ MEM_SAFE_FREE(tgpf->depth_arr);
+
+ /* remove drawing handler */
+ if (tgpf->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d);
+ }
+
+ /* delete temp image */
+ if (tgpf->ima) {
+ for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
+ if (ima == tgpf->ima) {
+ BLI_remlink(&bmain->image, ima);
+ BKE_image_free(tgpf->ima);
+ MEM_SAFE_FREE(tgpf->ima);
+ break;
+ }
+ }
+ }
+
+ /* finally, free memory used by temp data */
+ MEM_freeN(tgpf);
+ }
+
+ /* clear pointer */
+ op->customdata = NULL;
+
+ /* drawing batch cache is dirty now */
+ if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) {
+ bGPdata *gpd2 = ob->data;
+ DEG_id_tag_update(&gpd2->id, OB_RECALC_OB | OB_RECALC_DATA);
+ gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+}
+
+static void gpencil_fill_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_fill_exit(C, op);
+}
+
+/* Init: Allocate memory and set init values */
+static int gpencil_fill_init(bContext *C, wmOperator *op)
+{
+ tGPDfill *tgpf;
+ /* cannot paint in locked layer */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) {
+ return 0;
+ }
+
+ /* check context */
+ tgpf = op->customdata = gp_session_init_fill(C, op);
+ if (tgpf == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_fill_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
+}
+
+/* start of interactive part of operator */
+static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ tGPDfill *tgpf = NULL;
+
+ /* try to initialize context data needed */
+ if (!gpencil_fill_init(C, op)) {
+ gpencil_fill_exit(C, op);
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ tgpf = op->customdata;
+ }
+
+ /* Enable custom drawing handlers to show help lines */
+ if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) {
+ tgpf->draw_handle_3d = ED_region_draw_cb_activate(tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
+ }
+
+ WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
+
+ gpencil_fill_status_indicators(C, tgpf);
+
+ DEG_id_tag_update(&tgpf->gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator*/
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* events handling during interactive part of operator */
+static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPDfill *tgpf = op->customdata;
+
+ int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ estate = OPERATOR_CANCELLED;
+ break;
+ case LEFTMOUSE:
+ tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
+ /* first time the event is not enabled to show help lines */
+ if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
+ ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
+ if (ar) {
+ bool in_bounds = false;
+
+ /* Perform bounds check */
+ in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y);
+
+ if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) {
+ /* TODO GPXX: Verify the mouse click is right for any window size */
+ tgpf->center[0] = event->mval[0];
+ tgpf->center[1] = event->mval[1];
+
+ /* save size */
+ tgpf->sizex = ar->winx;
+ tgpf->sizey = ar->winy;
+
+ /* render screen to temp image */
+ gp_render_offscreen(tgpf);
+
+ /* apply boundary fill */
+ gpencil_boundaryfill_area(tgpf);
+
+ /* clean borders to avoid infinite loops */
+ gpencil_clean_borders(tgpf);
+
+ /* analyze outline */
+ gpencil_get_outline_points(tgpf);
+
+ /* create array of points from stack */
+ gpencil_points_from_stack(tgpf);
+
+ /* create z-depth array for reproject */
+ gpencil_get_depth_array(tgpf);
+
+ /* create stroke and reproject */
+ gpencil_stroke_from_buffer(tgpf);
+
+ /* free temp stack data */
+ if (tgpf->stack) {
+ BLI_stack_free(tgpf->stack);
+ }
+
+ /* push undo data */
+ gpencil_undo_push(tgpf->gpd);
+
+ estate = OPERATOR_FINISHED;
+ }
+ else {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ tgpf->oldkey = event->type;
+ break;
+ }
+ /* process last operations before exiting */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ gpencil_fill_exit(C, op);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ break;
+
+ case OPERATOR_CANCELLED:
+ gpencil_fill_exit(C, op);
+ break;
+
+ case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
+ break;
+ }
+
+ /* return status code */
+ return estate;
+}
+
+void GPENCIL_OT_fill(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Grease Pencil Fill";
+ ot->idname = "GPENCIL_OT_fill";
+ ot->description = "Fill with color the shape formed by strokes";
+
+ /* api callbacks */
+ ot->invoke = gpencil_fill_invoke;
+ ot->modal = gpencil_fill_modal;
+ ot->poll = gpencil_fill_poll;
+ ot->cancel = gpencil_fill_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index f48736a15e1..93d75063bff 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -34,24 +34,146 @@
#include "DNA_vec_types.h"
+#include "ED_numinput.h"
+
/* internal exports only */
struct bGPdata;
struct bGPDstroke;
struct bGPDspoint;
+struct tGPspoint;
+struct Material;
struct GHash;
+struct RNG;
+struct Brush;
+struct Scene;
struct ARegion;
+struct View3D;
struct View2D;
struct wmOperatorType;
+struct Depsgraph;
+
struct PointerRNA;
struct PropertyRNA;
struct EnumPropertyItem;
/* ***************************************************** */
+/* Modal Operator Geometry Preview
+ *
+ * Several modal operators (Fill, Interpolate, Primitive)
+ * need to run some drawing code to display previews, or
+ * to perform screen-space/image-based analysis routines.
+ * The following structs + function prototypes are used
+ * by these operators so that the operator code
+ * (in gpencil_<opname>.c) can communicate with the drawing
+ * code (in drawgpencil.c).
+ *
+ * NOTE: All this is within the gpencil module, so nothing needs
+ * to be exported to other modules.
+ */
+
+/* Internal Operator-State Data ------------------------ */
+
+/* Temporary draw data (no draw manager mode) */
+typedef struct tGPDdraw {
+ struct RegionView3D *rv3d; /* region to draw */
+ struct Depsgraph *depsgraph; /* depsgraph */
+ struct Object *ob; /* GP object */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *gpf; /* frame */
+ struct bGPDframe *t_gpf; /* temporal frame */
+ struct bGPDstroke *gps; /* stroke */
+ int disable_fill; /* disable fill */
+ int offsx; /* windows offset x */
+ int offsy; /* windows offset y */
+ int winx; /* windows width */
+ int winy; /* windows height */
+ int dflag; /* flags datablock */
+ short lthick; /* layer thickness */
+ float opacity; /* opacity */
+ float tintcolor[4]; /* tint color */
+ bool onion; /* onion flag */
+ bool custonion; /* use custom onion colors */
+ float diff_mat[4][4]; /* matrix */
+} tGPDdraw;
+
+
+/* Temporary interpolate operation data */
+typedef struct tGPDinterpolate_layer {
+ struct tGPDinterpolate_layer *next, *prev;
+
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */
+ struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */
+ struct bGPDframe *interFrame; /* interpolated frame */
+ float factor; /* interpolate factor */
+
+} tGPDinterpolate_layer;
+
+typedef struct tGPDinterpolate {
+ struct Scene *scene; /* current scene from context */
+ struct ScrArea *sa; /* area where painting originated */
+ struct ARegion *ar; /* region where painting originated */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct Material *mat; /* current material */
+
+ int cframe; /* current frame number */
+ ListBase ilayers; /* (tGPDinterpolate_layer) layers to be interpolated */
+ float shift; /* value for determining the displacement influence */
+ float init_factor; /* initial interpolation factor for active layer */
+ float low_limit; /* shift low limit (-100%) */
+ float high_limit; /* shift upper limit (200%) */
+ int flag; /* flag from toolsettings */
+
+ NumInput num; /* numeric input */
+ void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
+ void *draw_handle_screen; /* handle for drawing strokes while operator is running screen stuff */
+} tGPDinterpolate;
+
+
+/* Temporary primitive operation data */
+typedef struct tGPDprimitive {
+ struct Depsgraph *depsgraph;
+ struct wmWindow *win; /* window where painting originated */
+ struct Scene *scene; /* current scene from context */
+ struct Object *ob; /* current active gp object */
+ struct ScrArea *sa; /* area where painting originated */
+ struct RegionView3D *rv3d; /* region where painting originated */
+ struct View3D *v3d; /* view3d where painting originated */
+ struct ARegion *ar; /* region where painting originated */
+ struct bGPdata *gpd; /* current GP datablock */
+ struct Material *mat; /* current material */
+ struct Brush *brush; /* current brush */
+
+ int cframe; /* current frame number */
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *gpf; /* frame */
+ int type; /* type of primitive */
+ int tot_edges; /* number of polygon edges */
+ int top[2]; /* first box corner */
+ int bottom[2]; /* last box corner */
+ int origin[2]; /* initial box corner */
+ int flag; /* flag to determine operations in progress */
+
+ int lock_axis; /* lock to viewport axis */
+
+ NumInput num; /* numeric input */
+ void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
+} tGPDprimitive;
+
+
+/* Modal Operator Drawing Callbacks ------------------------ */
+
+void ED_gp_draw_interpolation(const struct bContext *C, struct tGPDinterpolate *tgpi, const int type);
+void ED_gp_draw_primitives(const struct bContext *C, struct tGPDprimitive *tgpi, const int type);
+void ED_gp_draw_fill(struct tGPDdraw *tgpw);
+
+/* ***************************************************** */
/* Internal API */
/* Stroke Coordinates API ------------------------------ */
@@ -71,33 +193,45 @@ typedef struct GP_SpaceConversion {
float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
} GP_SpaceConversion;
-bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
- int rad, int x0, int y0, int x1, int y1);
+bool gp_stroke_inside_circle(
+ const int mval[2], const int UNUSED(mvalo[2]),
+ int rad, int x0, int y0, int x1, int y1);
void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
-void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
- int *r_x, int *r_y);
-
-void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
- float *r_x, float *r_y);
+void gp_point_to_xy(
+ const GP_SpaceConversion *gsc, const struct bGPDstroke *gps, const struct bGPDspoint *pt,
+ int *r_x, int *r_y);
-void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt);
+void gp_point_to_xy_fl(
+ const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt,
+ float *r_x, float *r_y);
-void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps);
-
-void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt);
+void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt);
+/**
+ * Change points position relative to parent object
+ */
+void gp_apply_parent(struct Depsgraph *depsgraph, struct Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps);
+/**
+ * Change point position relative to parent object
+ */
+void gp_apply_parent_point(struct Depsgraph *depsgraph, struct Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt);
bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float screen_co[2], float r_out[3]);
+/* helper to convert 2d to 3d */
+void gp_stroke_convertcoords_tpoint(
+ struct Scene *scene, struct ARegion *ar,
+ struct Object *ob,
+ bGPDlayer *gpl, const struct tGPspoint *point2D,
+ float *depth, float out[3]);
+
/* Poll Callbacks ------------------------------------ */
/* gpencil_utils.c */
bool gp_add_poll(struct bContext *C);
bool gp_active_layer_poll(struct bContext *C);
bool gp_active_brush_poll(struct bContext *C);
-bool gp_active_palette_poll(struct bContext *C);
-bool gp_active_palettecolor_poll(struct bContext *C);
bool gp_brush_crt_presets_poll(bContext *C);
/* Copy/Paste Buffer --------------------------------- */
@@ -106,18 +240,20 @@ bool gp_brush_crt_presets_poll(bContext *C);
extern ListBase gp_strokes_copypastebuf;
/* Build a map for converting between old colornames and destination-color-refs */
-struct GHash *gp_copybuf_validate_colormap(bGPdata *gpd);
+struct GHash *gp_copybuf_validate_colormap(struct bContext *C);
/* Stroke Editing ------------------------------------ */
-void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags);
-
+void gp_stroke_delete_tagged_points(
+ bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke,
+ int tag_flags, bool select);
+int gp_delete_selected_point_wrap(bContext *C);
bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf);
bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf);
-void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
-void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush);
+void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide);
+void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, struct RNG *rng);
/* Layers Enums -------------------------------------- */
@@ -128,22 +264,18 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
bool *r_free);
-/* Enums of GP Brushes */
-const EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free);
-
-/* Enums of GP palettes */
-const EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free);
-
/* ***************************************************** */
/* Operator Defines */
+/* annotations ------ */
+
+void GPENCIL_OT_annotate(struct wmOperatorType *ot);
+
+
/* drawing ---------- */
void GPENCIL_OT_draw(struct wmOperatorType *ot);
+void GPENCIL_OT_fill(struct wmOperatorType *ot);
/* Paint Modes for operator */
typedef enum eGPencil_PaintModes {
@@ -159,12 +291,16 @@ typedef enum eGPencil_PaintModes {
/* stroke editing ----- */
void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot);
+void GPENCIL_OT_selectmode_toggle(struct wmOperatorType *ot);
+void GPENCIL_OT_paintmode_toggle(struct wmOperatorType *ot);
+void GPENCIL_OT_sculptmode_toggle(struct wmOperatorType *ot);
+void GPENCIL_OT_weightmode_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_selection_opacity_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_select(struct wmOperatorType *ot);
void GPENCIL_OT_select_all(struct wmOperatorType *ot);
void GPENCIL_OT_select_circle(struct wmOperatorType *ot);
-void GPENCIL_OT_select_border(struct wmOperatorType *ot);
+void GPENCIL_OT_select_box(struct wmOperatorType *ot);
void GPENCIL_OT_select_lasso(struct wmOperatorType *ot);
void GPENCIL_OT_select_linked(struct wmOperatorType *ot);
@@ -173,6 +309,7 @@ void GPENCIL_OT_select_more(struct wmOperatorType *ot);
void GPENCIL_OT_select_less(struct wmOperatorType *ot);
void GPENCIL_OT_select_first(struct wmOperatorType *ot);
void GPENCIL_OT_select_last(struct wmOperatorType *ot);
+void GPENCIL_OT_select_alternate(struct wmOperatorType *ot);
void GPENCIL_OT_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_delete(struct wmOperatorType *ot);
@@ -192,7 +329,7 @@ void GPENCIL_OT_reproject(struct wmOperatorType *ot);
/* stroke sculpting -- */
-void GPENCIL_OT_brush_paint(struct wmOperatorType *ot);
+void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot);
/* buttons editing --- */
@@ -203,6 +340,7 @@ void GPENCIL_OT_layer_add(struct wmOperatorType *ot);
void GPENCIL_OT_layer_remove(struct wmOperatorType *ot);
void GPENCIL_OT_layer_move(struct wmOperatorType *ot);
void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_duplicate_object(struct wmOperatorType *ot);
void GPENCIL_OT_hide(struct wmOperatorType *ot);
void GPENCIL_OT_reveal(struct wmOperatorType *ot);
@@ -217,6 +355,9 @@ void GPENCIL_OT_blank_frame_add(struct wmOperatorType *ot);
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot);
+void GPENCIL_OT_frame_duplicate(struct wmOperatorType *ot);
+void GPENCIL_OT_frame_clean_fill(struct wmOperatorType *ot);
+void GPENCIL_OT_frame_clean_loose(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
@@ -225,6 +366,13 @@ enum {
GP_STROKE_JOINCOPY = 1
};
+enum {
+ GP_STROKE_BOX = -1,
+ GP_STROKE_LINE = 1,
+ GP_STROKE_CIRCLE = 2
+};
+
+
void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_change_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_lock_color(struct wmOperatorType *ot);
@@ -233,30 +381,12 @@ void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_join(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_subdivide(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_simplify(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_simplify_fixed(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_separate(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_split(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_add(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_remove(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_change(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_move(struct wmOperatorType *ot);
void GPENCIL_OT_brush_presets_create(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_copy(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_select(struct wmOperatorType *ot);
-
-void GPENCIL_OT_palette_add(struct wmOperatorType *ot);
-void GPENCIL_OT_palette_remove(struct wmOperatorType *ot);
-void GPENCIL_OT_palette_change(struct wmOperatorType *ot);
-void GPENCIL_OT_palette_lock_layer(struct wmOperatorType *ot);
-
-void GPENCIL_OT_palettecolor_add(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_remove(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_isolate(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_hide(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_reveal(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_lock_all(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_unlock_all(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_move(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_select(struct wmOperatorType *ot);
-void GPENCIL_OT_palettecolor_copy(struct wmOperatorType *ot);
/* undo stack ---------- */
@@ -270,6 +400,33 @@ void GPENCIL_OT_interpolate(struct wmOperatorType *ot);
void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot);
void GPENCIL_OT_interpolate_reverse(struct wmOperatorType *ot);
+/* primitives ---------- */
+
+void GPENCIL_OT_primitive(struct wmOperatorType *ot);
+
+/* vertex groups ------------ */
+void GPENCIL_OT_vertex_group_assign(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_remove_from(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_select(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_deselect(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_invert(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_group_smooth(struct wmOperatorType *ot);
+
+/* color handle */
+void GPENCIL_OT_lock_layer(struct wmOperatorType *ot);
+void GPENCIL_OT_color_isolate(struct wmOperatorType *ot);
+void GPENCIL_OT_color_hide(struct wmOperatorType *ot);
+void GPENCIL_OT_color_reveal(struct wmOperatorType *ot);
+void GPENCIL_OT_color_lock_all(struct wmOperatorType *ot);
+void GPENCIL_OT_color_unlock_all(struct wmOperatorType *ot);
+void GPENCIL_OT_color_select(struct wmOperatorType *ot);
+
+/* convert old 2.7 files to 2.8 */
+void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot);
+
+/* armatures */
+void GPENCIL_OT_generate_weights(struct wmOperatorType *ot);
+
/* ****************************************************** */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
@@ -318,6 +475,10 @@ typedef enum ACTCONT_TYPES {
/* ****************************************************** */
/* Stroke Iteration Utilities */
+struct GP_EditableStrokes_Iter {
+ float diff_mat[4][4];
+};
+
/**
* Iterate over all editable strokes in the current context,
* stopping on each usable layer + stroke pair (i.e. gpl and gps)
@@ -328,26 +489,38 @@ typedef enum ACTCONT_TYPES {
* \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) \
+#define GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) \
{ \
- CTX_DATA_BEGIN(C, bGPDlayer*, gpl, editable_gpencil_layers) \
+ struct GP_EditableStrokes_Iter gpstroke_iter = {0}; \
+ Depsgraph *depsgraph_ = CTX_data_depsgraph(C); \
+ Object *obact_ = CTX_data_active_object(C); \
+ bGPdata *gpd_ = CTX_data_gpencil_data(C); \
+ const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) \
{ \
- if (gpl->actframe == NULL) \
- continue; \
- /* calculate difference matrix if parent object */ \
- float diff_mat[4][4]; \
- ED_gpencil_parent_location(gpl, diff_mat); \
- /* loop over strokes */ \
- for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { \
- /* skip strokes that are invalid for current view */ \
- if (ED_gpencil_stroke_can_use(C, gps) == false) \
- continue; \
- /* check if the color is editable */ \
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) \
- continue; \
- /* ... Do Stuff With Strokes ... */
-
-#define GP_EDITABLE_STROKES_END \
+ bGPDframe *init_gpf_ = gpl->actframe; \
+ if (is_multiedit_) { \
+ init_gpf_ = gpl->frames.first; \
+ } \
+ for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
+ if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
+ ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
+ /* loop over strokes */ \
+ for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \
+ /* skip strokes that are invalid for current view */ \
+ if (ED_gpencil_stroke_can_use(C, gps) == false) \
+ continue; \
+ /* check if the color is editable */ \
+ if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) \
+ continue; \
+ /* ... Do Stuff With Strokes ... */
+
+#define GP_EDITABLE_STROKES_END(gpstroke_iter) \
+ } \
+ } \
+ if (!is_multiedit_) { \
+ break; \
+ } \
} \
} \
CTX_DATA_END; \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index e2d70803695..ae1d1454eae 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -1,4 +1,4 @@
-/*
+/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -47,6 +47,7 @@
#include "DNA_color_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -55,9 +56,9 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_library.h"
#include "BKE_report.h"
#include "BKE_screen.h"
@@ -79,6 +80,9 @@
#include "ED_view3d.h"
#include "ED_space_api.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
/* ************************************************ */
@@ -105,21 +109,27 @@ static bool gpencil_view3d_poll(bContext *C)
}
/* Perform interpolation */
-static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
+static void gp_interpolate_update_points(
+ const bGPDstroke *gps_from, const bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
{
- bGPDspoint *prev, *pt, *next;
-
/* update points */
for (int i = 0; i < new_stroke->totpoints; i++) {
- prev = &gps_from->points[i];
- pt = &new_stroke->points[i];
- next = &gps_to->points[i];
+ const bGPDspoint *prev = &gps_from->points[i];
+ const bGPDspoint *next = &gps_to->points[i];
+ bGPDspoint *pt = &new_stroke->points[i];
/* Interpolate all values */
interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor);
pt->strength = interpf(prev->strength, next->strength, 1.0f - factor);
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+
+ /* GPXX interpolate dverts */
+#if 0
+ MDeformVert *dvert = &new_stroke->dvert[i];
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+#endif
}
}
@@ -128,6 +138,7 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t
/* Helper: Update all strokes interpolated */
static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
{
+ bGPdata *gpd = tgpi->gpd;
tGPDinterpolate_layer *tgpil;
const float shift = tgpi->shift;
@@ -156,12 +167,14 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
}
}
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
/* Helper: Verify valid strokes for interpolation */
static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
{
+ Object *ob = CTX_data_active_object(C);
ToolSettings *ts = CTX_data_tool_settings(C);
eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag;
@@ -190,7 +203,7 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
continue;
}
@@ -213,6 +226,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
bGPdata *gpd = tgpi->gpd;
bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
bGPDframe *actframe = active_gpl->actframe;
+ Object *ob = CTX_data_active_object(C);
/* save initial factor for active layer to define shift limits */
tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1);
@@ -255,7 +269,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
bGPDstroke *gps_to;
int fFrame;
- bGPDstroke *new_stroke;
+ bGPDstroke *new_stroke = NULL;
bool valid = true;
@@ -269,7 +283,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_color_use(ob, tgpil->gpl, gps_from) == false) {
valid = false;
}
@@ -281,16 +295,15 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
}
/* create new stroke */
- new_stroke = MEM_dupallocN(gps_from);
- new_stroke->points = MEM_dupallocN(gps_from->points);
- new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
if (valid) {
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ if (new_stroke->dvert != NULL) {
+ new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert) * gps_to->totpoints);
+ }
new_stroke->totpoints = gps_to->totpoints;
new_stroke->tot_triangles = 0;
new_stroke->flag |= GP_STROKE_RECALC_CACHES;
@@ -302,6 +315,9 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
/* need an empty stroke to keep index correct for lookup, but resize to smallest size */
new_stroke->totpoints = 0;
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
+ if (new_stroke->dvert != NULL) {
+ new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert));
+ }
new_stroke->tot_triangles = 0;
new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles));
new_stroke->flag |= GP_STROKE_RECALC_CACHES;
@@ -317,17 +333,17 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
/* Drawing Callbacks */
/* Drawing callback for modal operator in screen mode */
-static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+static void gpencil_interpolate_draw_screen(const struct bContext *C, ARegion *UNUSED(ar), void *arg)
{
tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
- ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL);
+ ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_PIXEL);
}
/* Drawing callback for modal operator in 3d mode */
-static void gpencil_interpolate_draw_3d(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+static void gpencil_interpolate_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
{
tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
- ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW);
+ ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_VIEW);
}
/* ----------------------- */
@@ -352,32 +368,33 @@ static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, co
}
/* Helper: Draw status message while the user is running the operator */
-static void gpencil_interpolate_status_indicators(tGPDinterpolate *p)
+static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate *p)
{
Scene *scene = p->scene;
char status_str[UI_MAX_DRAW_STR];
char msg_str[UI_MAX_DRAW_STR];
- BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"), UI_MAX_DRAW_STR);
+ BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: "), UI_MAX_DRAW_STR);
if (hasNumInput(&p->num)) {
char str_offs[NUM_STR_REP_LEN];
outputNumInput(&p->num, str_offs, &scene->unit);
- BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_offs);
}
else {
- BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f));
+ BLI_snprintf(status_str, sizeof(status_str), "%s%d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f));
}
- ED_area_headerprint(p->sa, status_str);
+ ED_area_status_text(p->sa, status_str);
+ ED_workspace_status_text(C, IFACE_("ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"));
}
/* Update screen and stroke */
static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
{
/* update shift indicator in header */
- gpencil_interpolate_status_indicators(tgpi);
+ gpencil_interpolate_status_indicators(C, tgpi);
/* apply... */
tgpi->shift = RNA_float_get(op->ptr, "shift");
/* update points position */
@@ -391,6 +408,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
{
tGPDinterpolate *tgpi = op->customdata;
tGPDinterpolate_layer *tgpil;
+ bGPdata *gpd = tgpi->gpd;
/* don't assume that operator data exists at all */
if (tgpi) {
@@ -403,7 +421,8 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
}
/* clear status message area */
- ED_area_headerprint(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->sa, NULL);
+ ED_workspace_status_text(C, NULL);
/* finally, free memory used by temp data */
for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
@@ -414,6 +433,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
BLI_freelistN(&tgpi->ilayers);
MEM_freeN(tgpi);
}
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
/* clear pointer */
@@ -481,9 +501,10 @@ static int gpencil_interpolate_init(bContext *C, wmOperator *op)
static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
wmWindow *win = CTX_wm_window(C);
- Scene *scene = CTX_data_scene(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
bGPDframe *actframe = gpl->actframe;
tGPDinterpolate *tgpi = NULL;
@@ -494,7 +515,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
}
/* cannot interpolate in extremes */
- if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) {
+ if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) {
BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
return OPERATOR_CANCELLED;
}
@@ -526,7 +547,8 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
/* update shift indicator in header */
- gpencil_interpolate_status_indicators(tgpi);
+ gpencil_interpolate_status_indicators(C, tgpi);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
/* add a modal handler for this operator */
@@ -550,7 +572,8 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
case RETKEY:
{
/* return to normal cursor and header status */
- ED_area_headerprint(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->sa, NULL);
+ ED_workspace_status_text(C, NULL);
WM_cursor_modal_restore(win);
/* insert keyframes as required... */
@@ -568,6 +591,10 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
/* make copy of source stroke, then adjust pointer to points too */
gps_dst = MEM_dupallocN(gps_src);
gps_dst->points = MEM_dupallocN(gps_src->points);
+ if (gps_src->dvert != NULL) {
+ gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
+ }
gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
gps_dst->flag |= GP_STROKE_RECALC_CACHES;
BLI_addtail(&gpf_dst->strokes, gps_dst);
@@ -585,7 +612,8 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
case RIGHTMOUSE:
{
/* return to normal cursor and header status */
- ED_area_headerprint(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->sa, NULL);
+ ED_workspace_status_text(C, NULL);
WM_cursor_modal_restore(win);
/* clean up temp data */
@@ -898,8 +926,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
bGPDframe *actframe = active_gpl->actframe;
- Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
eGP_Interpolate_SettingsFlag flag = ipo_settings->flag;
@@ -909,7 +940,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* cannot interpolate in extremes */
- if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) {
+ if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) {
BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames");
return OPERATOR_CANCELLED;
}
@@ -957,7 +988,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
/* create new strokes data with interpolated points reading original stroke */
for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
- bGPDstroke *new_stroke;
+ bGPDstroke *new_stroke = NULL;
/* only selected */
if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
@@ -968,7 +999,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
continue;
}
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) {
continue;
}
@@ -986,15 +1017,20 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* create new stroke */
- new_stroke = MEM_dupallocN(gps_from);
- new_stroke->points = MEM_dupallocN(gps_from->points);
- new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
+ /* free weights of removed points */
+ if (gps_from->dvert != NULL) {
+ BKE_defvert_array_free_elems(gps_from->dvert + gps_to->totpoints, gps_from->totpoints - gps_to->totpoints);
+ }
+
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+
+ if (new_stroke->dvert != NULL) {
+ new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert) * gps_to->totpoints);
+ }
new_stroke->totpoints = gps_to->totpoints;
new_stroke->tot_triangles = 0;
new_stroke->flag |= GP_STROKE_RECALC_CACHES;
@@ -1010,6 +1046,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -1051,6 +1088,8 @@ static bool gpencil_interpolate_reverse_poll(bContext *C)
static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
/* Go through each layer, deleting the breakdowns around the current frame,
* but only if there is a keyframe nearby to stop at
*/
@@ -1119,6 +1158,7 @@ static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* notifiers */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/gpencil/gpencil_old.c b/source/blender/editors/gpencil/gpencil_old.c
new file mode 100644
index 00000000000..a2012be223d
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_old.c
@@ -0,0 +1,211 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation,
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Use deprecated data to convert old 2.7x files
+ */
+
+/** \file blender/editors/gpencil/gpencil_old.c
+ * \ingroup edgpencil
+ */
+
+ /* allow to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_main.h"
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_object.h"
+#include "BKE_material.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_gpencil.h"
+
+#include "gpencil_intern.h"
+
+ /* Free all of a gp-colors */
+static void free_gpencil_colors(bGPDpalette *palette)
+{
+ /* error checking */
+ if (palette == NULL) {
+ return;
+ }
+
+ /* free colors */
+ BLI_freelistN(&palette->colors);
+}
+
+/* Free all of the gp-palettes and colors */
+static void free_palettes(ListBase *list)
+{
+ bGPDpalette *palette_next;
+
+ /* error checking */
+ if (list == NULL) {
+ return;
+ }
+
+ /* delete palettes */
+ for (bGPDpalette *palette = list->first; palette; palette = palette_next) {
+ palette_next = palette->next;
+ /* free palette colors */
+ free_gpencil_colors(palette);
+
+ MEM_freeN(palette);
+ }
+ BLI_listbase_clear(list);
+}
+
+/* ***************** Convert old 2.7 files to 2.8 ************************ */
+static bool gpencil_convert_old_files_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ return (int) (scene->gpd != NULL);
+}
+
+static int gpencil_convert_old_files_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ /* Convert grease pencil scene datablock to GP object */
+ if ((scene->gpd) && (view_layer != NULL)) {
+ Object *ob;
+ ob = BKE_object_add_for_data(bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false);
+ zero_v3(ob->loc);
+
+ /* convert grease pencil palettes (version >= 2.78) to materials and weights */
+ bGPdata *gpd = scene->gpd;
+ for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
+ for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+
+ /* create material slot */
+ BKE_object_material_slot_add(bmain, ob);
+ Material *ma = BKE_material_add_gpencil(bmain, palcolor->info);
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+
+ /* copy color settings */
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ copy_v4_v4(gp_style->stroke_rgba, palcolor->color);
+ copy_v4_v4(gp_style->fill_rgba, palcolor->fill);
+ gp_style->flag = palcolor->flag;
+
+ /* fix strokes */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if ((gps->colorname[0] != '\0') &&
+ (STREQ(gps->colorname, palcolor->info)))
+ {
+ gps->mat_nr = ob->totcol - 1;
+ gps->colorname[0] = '\0';
+ /* weights array */
+ gps->dvert = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* free palettes */
+ free_palettes(&gpd->palettes);
+
+ /* disable all GP modes */
+ ED_gpencil_setup_modes(C, gpd, 0);
+
+ /* set cache as dirty */
+ BKE_gpencil_batch_cache_dirty_tag(ob->data);
+
+ scene->gpd = NULL;
+ }
+
+#if 0 /* GPXX */
+ /* Handle object-linked grease pencil datablocks */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->gpd) {
+ if (ob->type == OB_GPENCIL) {
+ /* GP Object - remap the links */
+ ob->data = ob->gpd;
+ ob->gpd = NULL;
+ }
+ else if (ob->type == OB_EMPTY) {
+ /* Empty with GP data - This should be able to be converted
+ * to a GP object with little data loss
+ */
+ ob->data = ob->gpd;
+ ob->gpd = NULL;
+ ob->type = OB_GPENCIL;
+ }
+ else {
+ /* FIXME: What to do in this case?
+ *
+ * We cannot create new objects for these, as we don't have a scene & scene layer
+ * to put them into from here...
+ */
+ printf("WARNING: Old Grease Pencil data ('%s') still exists on Object '%s'\n",
+ ob->gpd->id.name + 2, ob->id.name + 2);
+ }
+ }
+ }
+#endif
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_convert_old_files(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Convert 2.7 Grease Pencil File";
+ ot->idname = "GPENCIL_OT_convert_old_files";
+ ot->description = "Convert 2.7x grease pencil files to 2.8";
+
+ /* callbacks */
+ ot->exec = gpencil_convert_old_files_exec;
+ ot->poll = gpencil_convert_old_files_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index e209b7f46e7..01221f57f05 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -35,15 +35,24 @@
#include "BLI_sys_types.h"
#include "BKE_context.h"
+#include "BKE_brush.h"
+#include "BKE_gpencil.h"
+#include "BKE_paint.h"
+#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "ED_gpencil.h"
+#include "ED_select_utils.h"
#include "ED_object.h"
#include "ED_transform.h"
@@ -52,63 +61,10 @@
/* ****************************************** */
/* Grease Pencil Keymaps */
-/* Generic Drawing Keymap */
+/* Generic Drawing Keymap - Annotations */
static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil", 0, 0);
- wmKeyMapItem *kmi;
-
- /* Draw --------------------------------------- */
- /* draw */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, DKEY);
- RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- /* draw - straight lines */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, DKEY);
- RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- /* draw - poly lines */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, KM_CTRL, DKEY);
- RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- /* erase */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, 0, DKEY);
- RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- /* Tablet Mappings for Drawing ------------------ */
- /* For now, only support direct drawing using the eraser, as most users using a tablet
- * may still want to use that as their primary pointing device!
- */
-#if 0
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_STYLUS, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-#endif
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- /* Viewport Tools ------------------------------- */
-
- /* Enter EditMode */
- WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, DKEY);
-
- /* Pie Menu - For standard tools */
- WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_tool_palette", QKEY, KM_PRESS, 0, DKEY);
- WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_settings_palette", WKEY, KM_PRESS, 0, DKEY);
-
- /* Add Blank Frame */
- /* XXX: BKEY or NKEY? BKEY is easier to reach from DKEY, so we'll use that for now */
- WM_keymap_add_item(keymap, "GPENCIL_OT_blank_frame_add", BKEY, KM_PRESS, 0, DKEY);
-
- /* Delete Active Frame - For easier video tutorials/review sessions */
- /* NOTE: This works even when not in EditMode */
- WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY);
+ WM_keymap_ensure(keyconf, "Grease Pencil", 0, 0);
}
/* ==================== */
@@ -120,248 +76,171 @@ static bool gp_stroke_editmode_poll(bContext *C)
return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE));
}
-/* Stroke Editing Keymap - Only when editmode is enabled */
-static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
+/* Poll callback for stroke painting mode */
+static bool gp_stroke_paintmode_poll(bContext *C)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0);
- wmKeyMapItem *kmi;
-
- /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */
- keymap->poll = gp_stroke_editmode_poll;
-
- /* ----------------------------------------------- */
-
- /* Exit EditMode */
- WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0);
-
- /* Pie Menu - For settings/tools easy access */
- WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_sculpt", EKEY, KM_PRESS, 0, DKEY);
-
- /* Brush Settings */
- /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys
- * in other modes. However, when we are dealing with Stroke Edit Mode, we know for certain
- * that the only data being edited is that of the Grease Pencil strokes
- */
-
- /* CTRL + FKEY = Eraser Radius */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius");
-
- /* Interpolation */
- WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate", EKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate_sequence", EKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
-
- /* Sculpting ------------------------------------- */
-
- /* Brush-Based Editing:
- * EKEY + LMB = Single stroke, draw immediately
- * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
- *
- * For the modal version, use D+E -> Sculpt
- */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
- /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY);
- RNA_boolean_set(kmi->ptr, "wait_for_input", false);
- /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
-
-
- /* Shift-FKEY = Sculpt Strength */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
-
- /* FKEY = Sculpt Brush Size */
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
-
-
- /* Selection ------------------------------------- */
- /* select all */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- /* circle select */
- WM_keymap_add_item(keymap, "GPENCIL_OT_select_circle", CKEY, KM_PRESS, 0, 0);
-
- /* border select */
- WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0);
-
- /* lasso select */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- /* In the Node Editor, lasso select needs ALT modifier too (as somehow CTRL+LMB drag gets taken for "cut" quite early)
- * There probably isn't too much harm adding this for other editors too as part of standard GP editing keymap. This hotkey
- * combo doesn't seem to see much use under standard scenarios?
- */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- /* normal select */
- WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- /* whole stroke select */
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "entire_strokes", true);
-
- /* select linked */
- /* NOTE: While LKEY is redundant, not having it breaks the mode illusion too much */
- WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
-
- /* select grouped */
- WM_keymap_add_item(keymap, "GPENCIL_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* select more/less */
- WM_keymap_add_item(keymap, "GPENCIL_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- /* Editing ----------------------------------------- */
-
- /* duplicate and move selected points */
- WM_keymap_add_item(keymap, "GPENCIL_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* delete */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_gpencil_delete", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* menu edit specials */
- WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_edit_specials", WKEY, KM_PRESS, 0, 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);
-
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
-
- /* snap */
- WM_keymap_add_menu(keymap, "GPENCIL_MT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
-
-
- /* convert to geometry */
- WM_keymap_add_item(keymap, "GPENCIL_OT_convert", CKEY, KM_PRESS, KM_ALT, 0);
-
-
- /* Show/Hide */
- /* NOTE: These are available only in EditMode now, since they clash with general-purpose hotkeys */
- WM_keymap_add_item(keymap, "GPENCIL_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
-
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
+ /* TODO: limit this to mode, but review 2D editors */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE));
+}
- kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
+static bool gp_stroke_paintmode_poll_with_tool(bContext *C, const char gpencil_tool)
+{
+ /* TODO: limit this to mode, but review 2D editors */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ return ((gpd) && (gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
+ (brush && brush->gpencil_settings) &&
+ WM_toolsystem_active_tool_is_brush(C) &&
+ (brush->gpencil_tool == gpencil_tool));
+}
- WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
+/* Poll callback for stroke painting (draw brush) */
+static bool gp_stroke_paintmode_draw_poll(bContext *C)
+{
+ return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_DRAW);
+}
- /* Isolate Layer */
- WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0);
+/* Poll callback for stroke painting (erase brush) */
+static bool gp_stroke_paintmode_erase_poll(bContext *C)
+{
+ return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_ERASE);
+}
- /* Move to Layer */
- WM_keymap_add_item(keymap, "GPENCIL_OT_move_to_layer", MKEY, KM_PRESS, 0, 0);
+/* Poll callback for stroke painting (fill) */
+static bool gp_stroke_paintmode_fill_poll(bContext *C)
+{
+ return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_FILL);
+}
- /* 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);
+/* Poll callback for stroke sculpting mode */
+static bool gp_stroke_sculptmode_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* if not gpencil object and not view3d, need sculpt keys if edit mode */
+ if (sa->spacetype != SPACE_VIEW3D) {
+ return ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
+ }
+ else {
+ /* weight paint is a submode of sculpt */
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd);
+ }
+ }
+
+ return 0;
+}
- /* Transform Tools */
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
+/* Poll callback for stroke weight paint mode */
+static bool gp_stroke_weightmode_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = CTX_data_active_object(C);
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return (gpd && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE));
+ }
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0);
+ return 0;
+}
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0);
+/* Stroke Editing Keymap - Only when editmode is enabled */
+static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0);
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0);
+ /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */
+ keymap->poll = gp_stroke_editmode_poll;
+}
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_bend", WKEY, KM_PRESS, KM_SHIFT, 0);
+/* keys for draw with a drawing brush (no fill) */
+static void ed_keymap_gpencil_painting_draw(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0);
+ keymap->poll = gp_stroke_paintmode_draw_poll;
+}
- WM_keymap_add_item(keymap, "TRANSFORM_OT_tosphere", SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
+/* keys for draw with a eraser brush (erase) */
+static void ed_keymap_gpencil_painting_erase(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Erase)", 0, 0);
+ keymap->poll = gp_stroke_paintmode_erase_poll;
+}
- WM_keymap_add_item(keymap, "TRANSFORM_OT_shear", SKEY, KM_PRESS, KM_ALT | KM_CTRL | KM_SHIFT, 0);
+/* keys for draw with a fill brush */
+static void ed_keymap_gpencil_painting_fill(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Fill)", 0, 0);
+ keymap->poll = gp_stroke_paintmode_fill_poll;
+}
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_GPENCIL_SHRINKFATTEN);
+/* Stroke Painting Keymap - Only when paintmode is enabled */
+static void ed_keymap_gpencil_painting(wmKeyConfig *keyconf)
+{
+ /* set poll callback - so that this keymap only gets enabled when stroke paintmode is enabled */
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint Mode", 0, 0);
+ keymap->poll = gp_stroke_paintmode_poll;
+}
- /* Proportional Editing */
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_editmode(keyconf, keymap, true);
+/* Stroke Sculpting Keymap - Only when sculptmode is enabled */
+static void ed_keymap_gpencil_sculpting(wmKeyConfig *keyconf)
+{
+ /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt Mode", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_poll;
}
+/* Stroke Weight Paint Keymap - Only when weight is enabled */
+static void ed_keymap_gpencil_weightpainting(wmKeyConfig *keyconf)
+{
+ /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight Mode", 0, 0);
+ keymap->poll = gp_stroke_weightmode_poll;
+}
/* ==================== */
void ED_keymap_gpencil(wmKeyConfig *keyconf)
{
ed_keymap_gpencil_general(keyconf);
ed_keymap_gpencil_editing(keyconf);
+ ed_keymap_gpencil_painting(keyconf);
+ ed_keymap_gpencil_painting_draw(keyconf);
+ ed_keymap_gpencil_painting_erase(keyconf);
+ ed_keymap_gpencil_painting_fill(keyconf);
+ ed_keymap_gpencil_sculpting(keyconf);
+ ed_keymap_gpencil_weightpainting(keyconf);
}
/* ****************************************** */
void ED_operatortypes_gpencil(void)
{
+ /* Annotations -------------------- */
+
+ WM_operatortype_append(GPENCIL_OT_annotate);
+
/* Drawing ----------------------- */
WM_operatortype_append(GPENCIL_OT_draw);
+ WM_operatortype_append(GPENCIL_OT_fill);
/* Editing (Strokes) ------------ */
WM_operatortype_append(GPENCIL_OT_editmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_selectmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_paintmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_sculptmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_weightmode_toggle);
WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle);
WM_operatortype_append(GPENCIL_OT_select);
WM_operatortype_append(GPENCIL_OT_select_all);
WM_operatortype_append(GPENCIL_OT_select_circle);
- WM_operatortype_append(GPENCIL_OT_select_border);
+ WM_operatortype_append(GPENCIL_OT_select_box);
WM_operatortype_append(GPENCIL_OT_select_lasso);
WM_operatortype_append(GPENCIL_OT_select_linked);
@@ -370,6 +249,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_select_less);
WM_operatortype_append(GPENCIL_OT_select_first);
WM_operatortype_append(GPENCIL_OT_select_last);
+ WM_operatortype_append(GPENCIL_OT_select_alternate);
WM_operatortype_append(GPENCIL_OT_duplicate);
WM_operatortype_append(GPENCIL_OT_delete);
@@ -386,7 +266,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_reproject);
- WM_operatortype_append(GPENCIL_OT_brush_paint);
+ WM_operatortype_append(GPENCIL_OT_sculpt_paint);
/* Editing (Buttons) ------------ */
@@ -397,6 +277,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_remove);
WM_operatortype_append(GPENCIL_OT_layer_move);
WM_operatortype_append(GPENCIL_OT_layer_duplicate);
+ WM_operatortype_append(GPENCIL_OT_layer_duplicate_object);
WM_operatortype_append(GPENCIL_OT_hide);
WM_operatortype_append(GPENCIL_OT_reveal);
@@ -409,6 +290,9 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
WM_operatortype_append(GPENCIL_OT_active_frames_delete_all);
+ WM_operatortype_append(GPENCIL_OT_frame_duplicate);
+ WM_operatortype_append(GPENCIL_OT_frame_clean_fill);
+ WM_operatortype_append(GPENCIL_OT_frame_clean_loose);
WM_operatortype_append(GPENCIL_OT_convert);
@@ -420,29 +304,29 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_stroke_join);
WM_operatortype_append(GPENCIL_OT_stroke_flip);
WM_operatortype_append(GPENCIL_OT_stroke_subdivide);
+ WM_operatortype_append(GPENCIL_OT_stroke_simplify);
+ WM_operatortype_append(GPENCIL_OT_stroke_simplify_fixed);
+ WM_operatortype_append(GPENCIL_OT_stroke_separate);
+ WM_operatortype_append(GPENCIL_OT_stroke_split);
- WM_operatortype_append(GPENCIL_OT_palette_add);
- WM_operatortype_append(GPENCIL_OT_palette_remove);
- WM_operatortype_append(GPENCIL_OT_palette_change);
- WM_operatortype_append(GPENCIL_OT_palette_lock_layer);
- WM_operatortype_append(GPENCIL_OT_palettecolor_add);
- WM_operatortype_append(GPENCIL_OT_palettecolor_remove);
- WM_operatortype_append(GPENCIL_OT_palettecolor_isolate);
- WM_operatortype_append(GPENCIL_OT_palettecolor_hide);
- WM_operatortype_append(GPENCIL_OT_palettecolor_reveal);
- WM_operatortype_append(GPENCIL_OT_palettecolor_lock_all);
- WM_operatortype_append(GPENCIL_OT_palettecolor_unlock_all);
- WM_operatortype_append(GPENCIL_OT_palettecolor_move);
- WM_operatortype_append(GPENCIL_OT_palettecolor_select);
- WM_operatortype_append(GPENCIL_OT_palettecolor_copy);
-
- WM_operatortype_append(GPENCIL_OT_brush_add);
- WM_operatortype_append(GPENCIL_OT_brush_remove);
- WM_operatortype_append(GPENCIL_OT_brush_change);
- WM_operatortype_append(GPENCIL_OT_brush_move);
WM_operatortype_append(GPENCIL_OT_brush_presets_create);
- WM_operatortype_append(GPENCIL_OT_brush_copy);
- WM_operatortype_append(GPENCIL_OT_brush_select);
+
+ /* vertex groups */
+ WM_operatortype_append(GPENCIL_OT_vertex_group_assign);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_remove_from);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_select);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_deselect);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_invert);
+ WM_operatortype_append(GPENCIL_OT_vertex_group_smooth);
+
+ /* color handle */
+ WM_operatortype_append(GPENCIL_OT_lock_layer);
+ WM_operatortype_append(GPENCIL_OT_color_isolate);
+ WM_operatortype_append(GPENCIL_OT_color_hide);
+ WM_operatortype_append(GPENCIL_OT_color_reveal);
+ WM_operatortype_append(GPENCIL_OT_color_lock_all);
+ WM_operatortype_append(GPENCIL_OT_color_unlock_all);
+ WM_operatortype_append(GPENCIL_OT_color_select);
/* Editing (Time) --------------- */
@@ -450,6 +334,15 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_interpolate);
WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
WM_operatortype_append(GPENCIL_OT_interpolate_reverse);
+
+ /* Primitives */
+ WM_operatortype_append(GPENCIL_OT_primitive);
+
+ /* convert old 2.7 files to 2.8 */
+ WM_operatortype_append(GPENCIL_OT_convert_old_files);
+
+ /* armatures */
+ WM_operatortype_append(GPENCIL_OT_generate_weights);
}
void ED_operatormacros_gpencil(void)
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 27cde27fdf7..f932e59c869 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -23,9 +23,9 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/gpencil/gpencil_paint.c
- * \ingroup edgpencil
- */
+ /** \file blender/editors/gpencil/gpencil_paint.c
+ * \ingroup edgpencil
+ */
#include <stdio.h>
@@ -46,44 +46,57 @@
#include "PIL_time.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_windowmanager_types.h"
+
#include "BKE_colortools.h"
+#include "BKE_main.h"
+#include "BKE_brush.h"
+#include "BKE_paint.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_main.h"
-#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
+#include "BKE_material.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_windowmanager_types.h"
-
#include "UI_view2d.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
+#include "ED_object.h"
#include "ED_view3d.h"
#include "ED_clip.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_state.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
-/* ******************************************* */
-/* 'Globals' and Defines */
+ /* ******************************************* */
+ /* 'Globals' and Defines */
-/* values for tGPsdata->status */
+ /* values for tGPsdata->status */
typedef enum eGPencil_PaintStatus {
GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
GP_STATUS_PAINTING, /* a stroke is in progress */
@@ -105,6 +118,8 @@ typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_STROKEADDED = (1 << 1),
GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
GP_PAINTFLAG_SELECTMASK = (1 << 3),
+ GP_PAINTFLAG_HARD_ERASER = (1 << 4),
+ GP_PAINTFLAG_STROKE_ERASER = (1 << 5),
} eGPencil_PaintFlags;
@@ -112,9 +127,13 @@ typedef enum eGPencil_PaintFlags {
* "p" = op->customdata
*/
typedef struct tGPsdata {
- Main *bmain;
+ bContext *C;
+
+ Main *bmain; /* main database pointer */
Scene *scene; /* current scene from context */
+ struct Depsgraph *depsgraph;
+ Object *ob; /* current object */
wmWindow *win; /* window where painting originated */
ScrArea *sa; /* area where painting originated */
ARegion *ar; /* region where painting originated */
@@ -152,19 +171,30 @@ typedef struct tGPsdata {
double ocurtime; /* Used when converting to path */
float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space
- * to region space */
+ * to region space */
float mat[4][4];
float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
void *erasercursor; /* radial cursor data for drawing eraser */
- bGPDpalettecolor *palettecolor; /* current palette color */
- bGPDbrush *brush; /* current drawing brush */
+ /* mat settings are only used for 3D view */
+ Material *material; /* current material */
+
+ Brush *brush; /* current drawing brush */
+ Brush *eraser; /* default eraser brush */
short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */
int lock_axis; /* lock drawing to one axis */
+ bool disable_fill; /* the stroke is no fill mode */
+
+ RNG *rng;
short keymodifier; /* key used for invoking the operator */
+ short shift; /* shift modifier flag */
+
+ float totpixlen; /* size in pixels for uv calculation */
+
+ ReportList *reports;
} tGPsdata;
/* ------ */
@@ -175,6 +205,14 @@ typedef struct tGPsdata {
/* minimum length of new segment before new point can be added */
#define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
+static void gp_update_cache(bGPdata *gpd)
+{
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+}
+
static bool gp_stroke_added_check(tGPsdata *p)
{
return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
@@ -184,6 +222,9 @@ static void gp_stroke_added_enable(tGPsdata *p)
{
BLI_assert(p->gpf->strokes.last != NULL);
p->flags |= GP_PAINTFLAG_STROKEADDED;
+
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
}
/* ------ */
@@ -198,30 +239,42 @@ static void gp_session_validatebuffer(tGPsdata *p);
static bool gpencil_draw_poll(bContext *C)
{
if (ED_operator_regionactive(C)) {
- /* check if current context can support GPencil data */
- if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
- /* check if Grease Pencil isn't already running */
- if (ED_gpencil_session_active() == 0)
- return 1;
- else
- CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active");
+ ScrArea *sa = CTX_wm_area(C);
+ if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
+ /* check if current context can support GPencil data */
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
+ /* check if Grease Pencil isn't already running */
+ if (ED_gpencil_session_active() == 0)
+ return 1;
+ else
+ CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active");
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ }
+ return 0;
}
+ /* 3D Viewport */
else {
- CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
+ if (ED_gpencil_session_active() == 0) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
}
else {
CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ return 0;
}
-
- return 0;
}
/* check if projecting strokes into 3d-geometry in the 3D-View */
static bool gpencil_project_check(tGPsdata *p)
{
bGPdata *gpd = p->gpd;
- return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
+ return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
}
/* ******************************************* */
@@ -232,39 +285,39 @@ static bool gpencil_project_check(tGPsdata *p)
/* get the reference point for stroke-point conversions */
static void gp_get_3d_reference(tGPsdata *p, float vec[3])
{
- View3D *v3d = p->sa->spacedata.first;
- const float *fp = ED_view3d_cursor3d_get(p->scene, v3d);
-
- /* the reference point used depends on the owner... */
-#if 0 /* XXX: disabled for now, since we can't draw relative to the owner yet */
+ Object *ob = NULL;
if (p->ownerPtr.type == &RNA_Object) {
- Object *ob = (Object *)p->ownerPtr.data;
-
- /* active Object
- * - use relative distance of 3D-cursor from object center
- */
- sub_v3_v3v3(vec, fp, ob->loc);
- }
- else
-#endif
- {
- /* use 3D-cursor */
- copy_v3_v3(vec, fp);
+ ob = (Object *)p->ownerPtr.data;
}
+ ED_gp_get_drawing_reference(p->scene, ob, p->gpl, *p->align_flag, vec);
}
/* Stroke Editing ---------------------------- */
-
/* check if the current mouse position is suitable for adding a new point */
static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
{
+ Brush *brush = p->brush;
int dx = abs(mval[0] - pmval[0]);
int dy = abs(mval[1] - pmval[1]);
+ brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP;
/* if buffer is empty, just let this go through (i.e. so that dots will work) */
- if (p->gpd->sbuffer_size == 0)
+ if (p->gpd->runtime.sbuffer_size == 0) {
return true;
-
+ }
+ /* if lazy mouse, check minimum distance */
+ else if (GPENCIL_LAZY_MODE(brush, p->shift)) {
+ brush->gpencil_settings->flag |= GP_BRUSH_STABILIZE_MOUSE_TEMP;
+ if ((dx * dx + dy * dy) > (brush->smooth_stroke_radius * brush->smooth_stroke_radius)) {
+ return true;
+ }
+ else {
+ /* If the mouse is moving within the radius of the last move,
+ * don't update the mouse position. This allows sharp turns. */
+ copy_v2_v2_int(p->mval, p->mvalo);
+ return false;
+ }
+ }
/* check if mouse moved at least certain distance on both axes (best case)
* - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
*/
@@ -283,47 +336,17 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
return false;
}
-/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */
-static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
-{
- float plane_normal[3];
- float vn[3];
-
- float ray[3];
- float rpoint[3];
-
- /* normal vector for a plane locked to axis */
- zero_v3(plane_normal);
- plane_normal[axis] = 1.0f;
-
- /* Reproject the points in the plane */
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
-
- /* get a vector from the point with the current view direction of the viewport */
- ED_view3d_global_to_vector(rv3d, &pt->x, vn);
-
- /* calculate line extrem point to create a ray that cross the plane */
- mul_v3_fl(vn, -50.0f);
- add_v3_v3v3(ray, &pt->x, vn);
-
- /* if the line never intersect, the point is not changed */
- if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
- copy_v3_v3(&pt->x, rpoint);
- }
- }
-}
-
/* reproject stroke to plane locked to axis in 3d cursor location */
static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
{
bGPdata *gpd = p->gpd;
+ Object *obact = (Object *)p->ownerPtr.data;
+
float origin[3];
- float cursor[3];
RegionView3D *rv3d = p->ar->regiondata;
/* verify the stroke mode is CURSOR 3d space mode */
- if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) {
+ if ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) == 0) {
return;
}
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
@@ -333,12 +356,9 @@ static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps)
return;
}
- /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */
- gp_get_3d_reference(p, cursor);
- zero_v3(origin);
- origin[p->lock_axis - 1] = cursor[p->lock_axis - 1];
-
- gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1);
+ /* get drawing origin */
+ gp_get_3d_reference(p, origin);
+ ED_gp_project_stroke_to_plane(obact, rv3d, gps, origin, p->lock_axis - 1);
}
/* convert screen-coordinates to buffer-coordinates */
@@ -348,75 +368,70 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3]
bGPdata *gpd = p->gpd;
/* in 3d-space - pt->x/y/z are 3 side-by-side floats */
- if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) {
+
+ /* add small offset to keep stroke over the surface */
+ if ((depth) && (gpd->zdepth_offset > 0.0f)) {
+ *depth *= (1.0f - gpd->zdepth_offset);
+ }
+
if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval, out, 0, depth))) {
/* projecting onto 3D-Geometry
* - nothing more needs to be done here, since view_autodist_simple() has already done it
*/
- }
- else {
- float mval_prj[2];
- float rvec[3], dvec[3];
- float mval_f[2] = {UNPACK2(mval)};
- float zfac;
-
- /* Current method just converts each point in screen-coordinates to
- * 3D-coordinates using the 3D-cursor as reference. In general, this
- * works OK, but it could of course be improved.
- *
- * TODO:
- * - investigate using nearest point(s) on a previous stroke as
- * reference point instead or as offset, for easier stroke matching
- */
- gp_get_3d_reference(p, rvec);
- zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
-
- if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- sub_v2_v2v2(mval_f, mval_prj, mval_f);
- ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
- sub_v3_v3v3(out, rvec, dvec);
- }
- else {
- zero_v3(out);
+ /* verify valid zdepth, if it's wrong, the default darwing mode is used
+ * and the function doesn't return now */
+ if ((depth == NULL) || (*depth <= 1.0f)) {
+ return;
}
}
- }
- /* 2d - on 'canvas' (assume that p->v2d is set) */
- else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
- UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]);
- mul_v3_m4v3(out, p->imat, out);
- }
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float mval_f[2];
+ copy_v2fl_v2i(mval_f, mval);
+ float zfac;
- /* 2d - relative to screen (viewport area) */
- else {
- if (p->subrect == NULL) { /* normal 3D view */
- out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100;
- out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100;
+ /* Current method just converts each point in screen-coordinates to
+ * 3D-coordinates using the 3D-cursor as reference. In general, this
+ * works OK, but it could of course be improved.
+ *
+ * TODO:
+ * - investigate using nearest point(s) on a previous stroke as
+ * reference point instead or as offset, for easier stroke matching
+ */
+
+ gp_get_3d_reference(p, rvec);
+ zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(out, rvec, dvec);
}
- else { /* camera view, use subrect */
- out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
- out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
+ else {
+ zero_v3(out);
}
}
}
/* apply jitter to stroke */
-static void gp_brush_jitter(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2], int r_mval[2])
+static void gp_brush_jitter(
+ bGPdata *gpd, Brush *brush, tGPspoint *pt, const int mval[2],
+ const float pressure, int r_mval[2], RNG *rng)
{
- float pressure = pt->pressure;
- float tmp_pressure = pt->pressure;
- if (brush->draw_jitter > 0.0f) {
- float curvef = curvemapping_evaluateF(brush->cur_jitter, 0, pressure);
- tmp_pressure = curvef * brush->draw_sensitivity;
- }
- const float exfactor = (brush->draw_jitter + 2.0f) * (brush->draw_jitter + 2.0f); /* exponential value */
- const float fac = BLI_frand() * exfactor * tmp_pressure;
+ float tmp_pressure = pressure;
+ if (brush->gpencil_settings->draw_jitter > 0.0f) {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, pressure);
+ tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
+ }
+ const float exfactor = (brush->gpencil_settings->draw_jitter + 2.0f) * (brush->gpencil_settings->draw_jitter + 2.0f); /* exponential value */
+ const float fac = BLI_rng_get_float(rng) * exfactor * tmp_pressure;
/* Jitter is applied perpendicular to the mouse movement vector (2D space) */
float mvec[2], svec[2];
/* mouse movement in ints -> floats */
- if (gpd->sbuffer_size > 1) {
+ if (gpd->runtime.sbuffer_size > 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
@@ -429,7 +444,7 @@ static void gp_brush_jitter(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const
svec[0] = -mvec[1];
svec[1] = mvec[0];
/* scale the displacement by the random, and apply */
- if (BLI_frand() > 0.5f) {
+ if (BLI_rng_get_float(rng) > 0.5f) {
mul_v2_fl(svec, -fac);
}
else {
@@ -442,18 +457,18 @@ static void gp_brush_jitter(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const
}
/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
-static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2])
+static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const int mval[2])
{
float mvec[2];
- float sen = brush->draw_angle_factor; /* sensitivity */;
+ float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */;
float fac;
float mpressure;
- float angle = brush->draw_angle; /* default angle of brush in radians */;
+ float angle = brush->gpencil_settings->draw_angle; /* default angle of brush in radians */;
float v0[2] = { cos(angle), sin(angle) }; /* angle vector of the brush with full thickness */
/* Apply to first point (only if there are 2 points because before no data to do it ) */
- if (gpd->sbuffer_size == 1) {
+ if (gpd->runtime.sbuffer_size == 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
@@ -466,7 +481,7 @@ static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const
}
/* apply from second point */
- if (gpd->sbuffer_size >= 1) {
+ if (gpd->runtime.sbuffer_size >= 1) {
mvec[0] = (float)(mval[0] - (pt - 1)->x);
mvec[1] = (float)(mval[1] - (pt - 1)->y);
normalize_v2(mvec);
@@ -481,20 +496,85 @@ static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const
}
+/* Apply smooth to buffer while drawing
+ * to smooth point C, use 2 before (A, B) and current point (D):
+ *
+ * A----B-----C------D
+ *
+ * \param p Temp data
+ * \param inf Influence factor
+ * \param idx Index of the last point (need minimum 3 points in the array)
+ */
+static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
+{
+ bGPdata *gpd = p->gpd;
+ short num_points = gpd->runtime.sbuffer_size;
+
+ /* Do nothing if not enough points to smooth out */
+ if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ float steps = 4.0f;
+ if (idx < 4) {
+ steps--;
+ }
+
+ tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
+ tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
+ tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL;
+ tGPspoint *ptd = &points[idx - 1];
+
+ float sco[2] = { 0.0f };
+ float a[2], b[2], c[2], d[2];
+ const float average_fac = 1.0f / steps;
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ if (pta) {
+ copy_v2fl_v2i(a, &pta->x);
+ madd_v2_v2fl(sco, a, average_fac);
+ }
+ if (ptb) {
+ copy_v2fl_v2i(b, &ptb->x);
+ madd_v2_v2fl(sco, b, average_fac);
+ }
+ if (ptc) {
+ copy_v2fl_v2i(c, &ptc->x);
+ madd_v2_v2fl(sco, c, average_fac);
+ }
+ if (ptd) {
+ copy_v2fl_v2i(d, &ptd->x);
+ madd_v2_v2fl(sco, d, average_fac);
+ }
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v2_v2v2(c, c, sco, inf);
+ round_v2i_v2fl(&ptc->x, c);
+}
+
/* add current stroke-point to buffer (returns whether point was successfully added) */
-static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, double curtime)
+static short gp_stroke_addpoint(
+ tGPsdata *p, const int mval[2], float pressure, double curtime)
{
bGPdata *gpd = p->gpd;
- bGPDbrush *brush = p->brush;
+ Brush *brush = p->brush;
tGPspoint *pt;
ToolSettings *ts = p->scene->toolsettings;
+ Object *obact = (Object *)p->ownerPtr.data;
+ Depsgraph *depsgraph = p->depsgraph;
+ RegionView3D *rv3d = p->ar->regiondata;
+ View3D *v3d = p->sa->spacedata.first;
+ MaterialGPencilStyle *gp_style = p->material->gp_style;
+ const int def_nr = obact->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr);
/* check painting mode */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only - i.e. only store start and end point in buffer */
- if (gpd->sbuffer_size == 0) {
+ if (gpd->runtime.sbuffer_size == 0) {
/* first point in buffer (start point) */
- pt = (tGPspoint *)(gpd->sbuffer);
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
@@ -503,13 +583,13 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
pt->time = (float)(curtime - p->inittime);
/* increment buffer size */
- gpd->sbuffer_size++;
+ gpd->runtime.sbuffer_size++;
}
else {
/* just reset the endpoint to the latest value
* - assume that pointers for this are always valid...
*/
- pt = ((tGPspoint *)(gpd->sbuffer) + 1);
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
@@ -518,7 +598,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
pt->time = (float)(curtime - p->inittime);
/* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
- gpd->sbuffer_size = 2;
+ gpd->runtime.sbuffer_size = 2;
}
/* can keep carrying on this way :) */
@@ -526,67 +606,89 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
}
else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
/* check if still room in buffer */
- if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
+ if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX)
return GP_STROKEADD_OVERFLOW;
/* get pointer to destination point */
- pt = ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size);
/* store settings */
/* pressure */
- if (brush->flag & GP_BRUSH_USE_PRESSURE) {
- float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure);
- pt->pressure = curvef * brush->draw_sensitivity;
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_sensitivity, 0, pressure);
+ pt->pressure = curvef * brush->gpencil_settings->draw_sensitivity;
}
else {
pt->pressure = 1.0f;
}
+
/* Apply jitter to position */
- if (brush->draw_jitter > 0.0f) {
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_jitter > 0.0f))
+ {
int r_mval[2];
- gp_brush_jitter(gpd, brush, pt, mval, r_mval);
+ const float jitpress = (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) ? pressure : 1.0f;
+ gp_brush_jitter(gpd, brush, pt, mval, jitpress, r_mval, p->rng);
copy_v2_v2_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();
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_press > 0.0f))
+ {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_sensitivity, 0, pressure);
+ float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
+ if (BLI_rng_get_float(p->rng) > 0.5f) {
+ pt->pressure -= tmp_pressure * brush->gpencil_settings->draw_random_press * BLI_rng_get_float(p->rng);
}
else {
- pt->pressure += tmp_pressure * brush->draw_random_press * BLI_frand();
+ pt->pressure += tmp_pressure * brush->gpencil_settings->draw_random_press * BLI_rng_get_float(p->rng);
}
CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
}
+ /* apply randomness to uv texture rotation */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (brush->gpencil_settings->uv_random > 0.0f)) {
+ if (BLI_rng_get_float(p->rng) > 0.5f) {
+ pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI * -1) * brush->gpencil_settings->uv_random;
+ }
+ else {
+ pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI) * brush->gpencil_settings->uv_random;
+ }
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
+ else {
+ pt->uv_rot = 0.0f;
+ }
+
/* apply angle of stroke to brush size */
- if (brush->draw_angle_factor > 0.0f) {
+ if (brush->gpencil_settings->draw_angle_factor != 0.0f) {
gp_brush_angle(gpd, brush, pt, mval);
}
/* color strength */
- if (brush->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- float curvef = curvemapping_evaluateF(brush->cur_strength, 0, pressure);
- float tmp_pressure = curvef * brush->draw_sensitivity;
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_strength, 0, pressure);
+ float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
- pt->strength = tmp_pressure * brush->draw_strength;
+ pt->strength = tmp_pressure * brush->gpencil_settings->draw_strength;
}
else {
- pt->strength = brush->draw_strength;
+ pt->strength = brush->gpencil_settings->draw_strength;
}
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
/* apply randomness to color strength */
- if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_STRENGTH)) {
- if (BLI_frand() > 0.5f) {
- pt->strength -= pt->strength * brush->draw_random_press * BLI_frand();
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_strength > 0.0f))
+ {
+ if (BLI_rng_get_float(p->rng) > 0.5f) {
+ pt->strength -= pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng);
}
else {
- pt->strength += pt->strength * brush->draw_random_press * BLI_frand();
+ pt->strength += pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng);
}
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
@@ -594,20 +696,57 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
/* point time */
pt->time = (float)(curtime - p->inittime);
+ /* point uv (only 3d view) */
+ if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_size > 1)) {
+ float pixsize = gp_style->texture_pixsize / 1000000.0f;
+ tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 2;
+ bGPDspoint spt, spt2;
+
+ /* get origin to reproject point */
+ float origin[3];
+ gp_get_3d_reference(p, origin);
+ /* reproject current */
+ ED_gpencil_tpoint_to_point(p->ar, origin, pt, &spt);
+ ED_gp_project_point_to_plane(obact, rv3d, origin, p->lock_axis - 1, &spt);
+
+ /* reproject previous */
+ ED_gpencil_tpoint_to_point(p->ar, origin, ptb, &spt2);
+ ED_gp_project_point_to_plane(obact, rv3d, origin, p->lock_axis - 1, &spt2);
+ p->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
+ pt->uv_fac = p->totpixlen;
+ if ((gp_style) && (gp_style->sima)) {
+ pt->uv_fac /= gp_style->sima->gen_x;
+ }
+ }
+ else {
+ p->totpixlen = 0.0f;
+ pt->uv_fac = 0.0f;
+ }
+
/* increment counters */
- gpd->sbuffer_size++;
+ gpd->runtime.sbuffer_size++;
+
+ /* smooth while drawing previous points with a reduction factor for previous */
+ if (brush->gpencil_settings->active_smooth > 0.0f) {
+ for (int s = 0; s < 3; s++) {
+ gp_smooth_buffer(p, brush->gpencil_settings->active_smooth * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_size - s);
+ }
+ }
/* check if another operation can still occur */
- if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX)
+ if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX)
return GP_STROKEADD_FULL;
else
return GP_STROKEADD_NORMAL;
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* enable special flag for drawing engine */
+ gpd->flag |= GP_DATA_STROKE_POLYGON;
+
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
/* get pointer to destination point */
- pt = (tGPspoint *)(gpd->sbuffer);
+ pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
copy_v2_v2_int(&pt->x, mval);
@@ -622,48 +761,68 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
if (gp_stroke_added_check(p)) {
bGPDstroke *gps = p->gpf->strokes.last;
bGPDspoint *pts;
+ MDeformVert *dvert = NULL;
/* first time point is adding to temporary buffer -- need to allocate new point in stroke */
- if (gpd->sbuffer_size == 0) {
+ if (gpd->runtime.sbuffer_size == 0) {
gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
+ }
gps->totpoints++;
}
pts = &gps->points[gps->totpoints - 1];
-
+ if (gps->dvert != NULL) {
+ dvert = &gps->dvert[gps->totpoints - 1];
+ }
/* special case for poly lines: normally,
* depth is needed only when creating new stroke from buffer,
* but poly lines are converting to stroke instantly,
* so initialize depth buffer before converting coordinates
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
-
view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->bmain, p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ ED_view3d_autodist_init(
+ p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
/* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pts);
- }
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pts);
/* copy pressure and time */
pts->pressure = pt->pressure;
pts->strength = pt->strength;
pts->time = pt->time;
+ pts->uv_fac = pt->uv_fac;
+ pts->uv_rot = pt->uv_rot;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+ }
+
/* force fill recalc */
gps->flag |= GP_STROKE_RECALC_CACHES;
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
}
/* increment counters */
- if (gpd->sbuffer_size == 0)
- gpd->sbuffer_size++;
+ if (gpd->runtime.sbuffer_size == 0)
+ gpd->runtime.sbuffer_size++;
return GP_STROKEADD_NORMAL;
}
@@ -672,81 +831,6 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
return GP_STROKEADD_INVALID;
}
-/* simplify a stroke (in buffer) before storing it
- * - applies a reverse Chaikin filter
- * - code adapted from etch-a-ton branch (editarmature_sketch.c)
- */
-static void gp_stroke_simplify(tGPsdata *p)
-{
- bGPdata *gpd = p->gpd;
- tGPspoint *old_points = (tGPspoint *)gpd->sbuffer;
- short num_points = gpd->sbuffer_size;
- short flag = gpd->sbuffer_sflag;
- short i, j;
-
- /* only simplify if simplification is enabled, and we're not doing a straight line */
- if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT))
- return;
-
- /* don't simplify if less than 4 points in buffer */
- if ((num_points <= 4) || (old_points == NULL))
- return;
-
- /* clear buffer (but don't free mem yet) so that we can write to it
- * - firstly set sbuffer to NULL, so a new one is allocated
- * - secondly, reset flag after, as it gets cleared auto
- */
- gpd->sbuffer = NULL;
- gp_session_validatebuffer(p);
- gpd->sbuffer_sflag = flag;
-
-/* macro used in loop to get position of new point
- * - used due to the mixture of datatypes in use here
- */
-#define GP_SIMPLIFY_AVPOINT(offs, sfac) \
- { \
- co[0] += (float)(old_points[offs].x * sfac); \
- co[1] += (float)(old_points[offs].y * sfac); \
- pressure += old_points[offs].pressure * sfac; \
- time += old_points[offs].time * sfac; \
- } (void)0
-
- /* XXX Here too, do not lose start and end points! */
- gp_stroke_addpoint(p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time);
- for (i = 0, j = 0; i < num_points; i++) {
- if (i - j == 3) {
- float co[2], pressure, time;
- int mco[2];
-
- /* initialize values */
- co[0] = 0.0f;
- co[1] = 0.0f;
- pressure = 0.0f;
- time = 0.0f;
-
- /* using macro, calculate new point */
- GP_SIMPLIFY_AVPOINT(j, -0.25f);
- GP_SIMPLIFY_AVPOINT(j + 1, 0.75f);
- GP_SIMPLIFY_AVPOINT(j + 2, 0.75f);
- GP_SIMPLIFY_AVPOINT(j + 3, -0.25f);
-
- /* set values for adding */
- mco[0] = (int)co[0];
- mco[1] = (int)co[1];
-
- /* ignore return values on this... assume to be ok for now */
- gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time);
-
- j += 2;
- }
- }
- gp_stroke_addpoint(p, &old_points[num_points - 1].x, old_points[num_points - 1].pressure,
- p->inittime + (double)old_points[num_points - 1].time);
-
- /* free old buffer */
- MEM_freeN(old_points);
-}
-
/* make a new stroke from the buffer data */
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
@@ -755,8 +839,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
bGPDstroke *gps;
bGPDspoint *pt;
tGPspoint *ptc;
- bGPDbrush *brush = p->brush;
+ MDeformVert *dvert = NULL;
+ Brush *brush = p->brush;
ToolSettings *ts = p->scene->toolsettings;
+ Depsgraph *depsgraph = p->depsgraph;
+ Object *obact = (Object *)p->ownerPtr.data;
+ const int def_nr = obact->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr);
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
@@ -766,14 +855,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
* - drawing straight-lines only requires the endpoints
*/
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
- totelem = (gpd->sbuffer_size >= 2) ? 2 : gpd->sbuffer_size;
+ totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size;
else
- totelem = gpd->sbuffer_size;
+ totelem = gpd->runtime.sbuffer_size;
/* exit with error if no valid points from this stroke */
if (totelem == 0) {
if (G.debug & G_DEBUG)
- printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->sbuffer_size);
+ printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->runtime.sbuffer_size);
return;
}
@@ -782,6 +871,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
* interactive behavior
*/
if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
+ /* be sure to hide any lazy cursor */
+ ED_gpencil_toggle_brush_cursor(p->C, true, NULL);
+
if (gp_stroke_added_check(p)) {
return;
}
@@ -792,95 +884,128 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* copy appropriate settings for stroke */
gps->totpoints = totelem;
- gps->thickness = brush->thickness;
- gps->flag = gpd->sbuffer_sflag;
+ gps->thickness = brush->size;
+ gps->flag = gpd->runtime.sbuffer_sflag;
gps->inittime = p->inittime;
/* enable recalculation flag by default (only used if hq fill) */
gps->flag |= GP_STROKE_RECALC_CACHES;
/* allocate enough memory for a continuous array for storage points */
- int sublevel = brush->sublevel;
- int new_totpoints = gps->totpoints;
+ const int subdivide = brush->gpencil_settings->draw_subdivide;
+
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- for (i = 0; i < sublevel; i++) {
- new_totpoints += new_totpoints - 1;
- }
- gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points");
/* initialize triangle memory to dummy data */
gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
gps->flag |= GP_STROKE_RECALC_CACHES;
gps->tot_triangles = 0;
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
/* set pointer to first non-initialized point */
pt = gps->points + (gps->totpoints - totelem);
+ if (gps->dvert != NULL) {
+ dvert = gps->dvert + (gps->totpoints - totelem);
+ }
/* copy points from the buffer to the stroke */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only -> only endpoints */
{
/* first point */
- ptc = gpd->sbuffer;
+ ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
- /* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pt);
- }
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
-
pt++;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ dvert++;
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ dvert++;
+ }
+ }
}
if (totelem == 2) {
/* last point if applicable */
- ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
+ ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1);
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
- /* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pt);
- }
-
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+ }
+ }
+
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
+ pt = gps->points;
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ /* if parented change position relative to parent object */
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
}
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
/* first point */
- ptc = gpd->sbuffer;
+ ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
/* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent_point(gpl, pt);
- }
+ gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+ }
+
}
else {
float *depth_arr = NULL;
@@ -891,9 +1016,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
int interp_depth = 0;
int found_depth = 0;
- depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
+ depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points");
- for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) {
copy_v2_v2_int(mval, &ptc->x);
if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
@@ -910,45 +1035,55 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
if (found_depth == false) {
/* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
- for (i = gpd->sbuffer_size - 1; i >= 0; i--)
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--)
depth_arr[i] = 0.9999f;
}
else {
- if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
- /* remove all info between the valid endpoints */
+ if ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) ||
+ (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST))
+ {
int first_valid = 0;
int last_valid = 0;
- for (i = 0; i < gpd->sbuffer_size; i++) {
+ /* find first valid contact point */
+ for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
if (depth_arr[i] != FLT_MAX)
break;
}
first_valid = i;
- for (i = gpd->sbuffer_size - 1; i >= 0; i--) {
- if (depth_arr[i] != FLT_MAX)
- break;
+ /* find last valid contact point */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_FIRST) {
+ last_valid = first_valid;
+ }
+ else {
+ for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) {
+ if (depth_arr[i] != FLT_MAX)
+ break;
+ }
+ last_valid = i;
+ }
+ /* invalidate any point other point, to interpolate between
+ * first and last contact in an imaginary line between them */
+ for (i = 0; i < gpd->runtime.sbuffer_size; i++) {
+ if ((i != first_valid) && (i != last_valid)) {
+ depth_arr[i] = FLT_MAX;
+ }
}
- last_valid = i;
-
- /* invalidate non-endpoints, so only blend between first and last */
- for (i = first_valid + 1; i < last_valid; i++)
- depth_arr[i] = FLT_MAX;
-
interp_depth = true;
}
if (interp_depth) {
- interp_sparse_array(depth_arr, gpd->sbuffer_size, FLT_MAX);
+ interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX);
}
}
}
-
pt = gps->points;
+ dvert = gps->dvert;
/* convert all points (normal behavior) */
- for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) {
+ for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size && ptc; i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
@@ -957,55 +1092,68 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
- }
-
- /* subdivide the stroke */
- if (sublevel > 0) {
- int totpoints = gps->totpoints;
- for (i = 0; i < sublevel; i++) {
- /* we're adding one new point between each pair of verts on each step */
- totpoints += totpoints - 1;
+ pt->uv_fac = ptc->uv_fac;
+ pt->uv_rot = ptc->uv_rot;
- gp_subdivide_stroke(gps, totpoints);
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ dvert++;
}
}
+
+ /* subdivide and smooth the stroke */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (subdivide > 0)) {
+ gp_subdivide_stroke(gps, subdivide);
+ }
/* apply randomness to stroke */
- if (brush->draw_random_sub > 0.0f) {
- gp_randomize_stroke(gps, brush);
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
+ (brush->gpencil_settings->draw_random_sub > 0.0f))
+ {
+ gp_randomize_stroke(gps, brush, p->rng);
}
/* smooth stroke after subdiv - only if there's something to do
* for each iteration, the factor is reduced to get a better smoothing without changing too much
* the original stroke
*/
- if (brush->draw_smoothfac > 0.0f) {
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ (brush->gpencil_settings->draw_smoothfac > 0.0f))
+ {
float reduce = 0.0f;
- for (int r = 0; r < brush->draw_smoothlvl; ++r) {
- for (i = 0; i < gps->totpoints; i++) {
- /* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */
- gp_smooth_stroke(gps, i, brush->draw_smoothfac - reduce, false);
+ for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
+ for (i = 0; i < gps->totpoints - 1; i++) {
+ BKE_gpencil_smooth_stroke(gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ BKE_gpencil_smooth_stroke_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
}
reduce += 0.25f; // reduce the factor
}
}
-
- /* if axis locked, reproject to plane locked (only in 3d space) */
- if (p->lock_axis > GP_LOCKAXIS_NONE) {
- gp_reproject_toplane(p, gps);
- }
- /* if parented change position relative to parent object */
- if (gpl->parent != NULL) {
- gp_apply_parent(gpl, gps);
+ /* smooth thickness */
+ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
+ (brush->gpencil_settings->thick_smoothfac > 0.0f))
+ {
+ for (int r = 0; r < brush->gpencil_settings->thick_smoothlvl * 2; r++) {
+ for (i = 0; i < gps->totpoints - 1; i++) {
+ BKE_gpencil_smooth_stroke_thickness(gps, i, brush->gpencil_settings->thick_smoothfac);
+ }
+ }
}
+ /* reproject to plane (only in 3d space) */
+ gp_reproject_toplane(p, gps);
+ /* change position relative to parent object */
+ gp_apply_parent(depsgraph, obact, gpd, gpl, gps);
+
if (depth_arr)
MEM_freeN(depth_arr);
}
- /* Save palette color */
- bGPDpalette *palette = BKE_gpencil_palette_getactive(p->gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
- gps->palcolor = palcolor;
- BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
+
+ /* Save material index */
+ gps->mat_nr = BKE_gpencil_get_material_index(p->ob, p->material) - 1;
+
+ /* calculate UVs along the stroke */
+ ED_gpencil_calc_stroke_uv(obact, gps);
/* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head
* because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist
@@ -1017,6 +1165,18 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
else {
BLI_addtail(&p->gpf->strokes, gps);
}
+ /* add weights */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ for (i = 0; i < gps->totpoints; i++) {
+ MDeformVert *ve = &gps->dvert[i];
+ MDeformWeight *dw = defvert_verify_index(ve, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+ }
+ }
+
gp_stroke_added_enable(p);
}
@@ -1036,6 +1196,8 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
/* only erase stroke points that are visible */
static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
{
+ Object *obact = (Object *)p->ownerPtr.data;
+
if ((p->sa->spacetype == SPACE_VIEW3D) &&
(p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH))
{
@@ -1048,13 +1210,13 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons
float diff_mat[4][4];
/* calculate difference matrix if parent object */
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(p->depsgraph, obact, p->gpd, gpl, diff_mat);
if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) {
const float depth_mval = view3d_point_depth(rv3d, mval_3d);
mul_v3_m4v3(fpt, diff_mat, &pt->x);
- const float depth_pt = view3d_point_depth(rv3d, fpt);
+ const float depth_pt = view3d_point_depth(rv3d, fpt);
if (depth_pt > depth_mval) {
return true;
@@ -1067,6 +1229,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons
/* apply a falloff effect to brush strength, based on distance */
static float gp_stroke_eraser_calc_influence(tGPsdata *p, const int mval[2], const int radius, const int co[2])
{
+ Brush *brush = p->brush;
/* Linear Falloff... */
float distance = (float)len_v2v2_int(mval, co);
float fac;
@@ -1074,60 +1237,150 @@ static float gp_stroke_eraser_calc_influence(tGPsdata *p, const int mval[2], con
CLAMP(distance, 0.0f, (float)radius);
fac = 1.0f - (distance / (float)radius);
- /* Control this further using pen pressure */
- fac *= p->pressure;
+ /* apply strength factor */
+ fac *= brush->gpencil_settings->draw_strength;
+ /* Control this further using pen pressure */
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
+ fac *= p->pressure;
+ }
/* Return influence factor computed here */
return fac;
}
+/* helper to free a stroke */
+static void gp_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps)
+{
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+
+ if (gps->triangles)
+ MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ gp_update_cache(gpd);
+}
+
+/* analyze points to be removed when soft eraser is used
+ * to avoid that segments gets the end points rounded. This
+ * round cpas breaks the artistic effect.
+ */
+static void gp_stroke_soft_refine(bGPDstroke *gps, const float cull_thresh)
+{
+ bGPDspoint *pt = NULL;
+ bGPDspoint *pt_before = NULL;
+ bGPDspoint *pt_after = NULL;
+ int i;
+
+ /* check if enough points*/
+ if (gps->totpoints < 3) {
+ return;
+ }
+
+ /* loop all points from second to last minus one
+ * to untag any point that is not surrounded by tagged points
+ */
+ pt = gps->points;
+ for (i = 1; i < gps->totpoints - 1; i++, pt++) {
+ if (pt->flag & GP_SPOINT_TAG) {
+ pt_before = &gps->points[i - 1];
+ pt_after = &gps->points[i + 1];
+
+ /* if any of the side points are not tagged, mark to keep */
+ if (((pt_before->flag & GP_SPOINT_TAG) == 0) ||
+ ((pt_after->flag & GP_SPOINT_TAG) == 0))
+ {
+ if (pt->pressure > cull_thresh) {
+ pt->flag |= GP_SPOINT_TEMP_TAG;
+ }
+ }
+ else {
+ /* reduce opacity of extreme points */
+ if ((pt_before->flag & GP_SPOINT_TAG) == 0) {
+ pt_before->strength *= 0.5f;
+ }
+ if ((pt_after->flag & GP_SPOINT_TAG) == 0) {
+ pt_after->strength *= 0.5f;
+ }
+ }
+ }
+ }
+
+ /* now untag temp tagged */
+ pt = gps->points;
+ for (i = 1; i < gps->totpoints - 1; i++, pt++) {
+ if (pt->flag & GP_SPOINT_TEMP_TAG) {
+ pt->flag &= ~GP_SPOINT_TAG;
+ pt->flag &= ~GP_SPOINT_TEMP_TAG;
+ }
+ }
+}
+
/* eraser tool - evaluation per stroke */
/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
static void gp_stroke_eraser_dostroke(tGPsdata *p,
- bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
- const int mval[2], const int mvalo[2],
- const int radius, const rcti *rect)
+ bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
+ const int mval[2], const int mvalo[2],
+ const int radius, const rcti *rect)
{
- bGPDspoint *pt1, *pt2;
+ Depsgraph *depsgraph = p->depsgraph;
+ Object *obact = (Object *)p->ownerPtr.data;
+ Brush *eraser = p->eraser;
+ bGPDspoint *pt0, *pt1, *pt2;
+ int pc0[2] = {0};
int pc1[2] = {0};
int pc2[2] = {0};
int i;
float diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- }
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, p->gpd, gpl, diff_mat);
if (gps->totpoints == 0) {
/* just free stroke */
- if (gps->points)
- MEM_freeN(gps->points);
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ gp_free_stroke(p->gpd, gpf, gps);
}
else if (gps->totpoints == 1) {
/* only process if it hasn't been masked out... */
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
- if (gpl->parent == NULL) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
- }
- else {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(mval, pc1) <= radius) {
+ /* free stroke */
+ gp_free_stroke(p->gpd, gpf, gps);
+ }
}
+ }
+ }
+ else if ((p->flags & GP_PAINTFLAG_STROKE_ERASER) || (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_STROKE)) {
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+
+ /* only process if it hasn't been masked out... */
+ if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
+ continue;
+
+ /* get points to work with */
+ pt1 = gps->points + i;
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval, pc1) <= radius) {
/* free stroke */
- // XXX: pressure sensitive eraser should apply here too?
- MEM_freeN(gps->points);
- if (gps->triangles)
- MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
+ gp_free_stroke(p->gpd, gpf, gps);
+ return;
}
}
}
@@ -1136,7 +1389,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 = (gps->thickness) ? 1.0f / ((float)gps->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?
@@ -1163,6 +1416,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
*/
for (i = 0; (i + 1) < gps->totpoints; i++) {
/* get points to work with */
+ pt0 = i > 0 ? gps->points + i - 1 : NULL;
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
@@ -1170,45 +1424,93 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT))
continue;
- if (gpl->parent == NULL) {
- gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
- gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
+ bGPDspoint npt;
+ if (pt0) {
+ gp_point_to_parent_space(pt0, diff_mat, &npt);
+ gp_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[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]);
+ /* avoid null values */
+ copy_v2_v2_int(pc0, pc1);
}
+ 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])) ||
+ if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
{
/* Check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
- if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
+ if (gp_stroke_inside_circle(mval, mvalo, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
+ if ((gp_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) ||
+ (gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false))
{
/* Point is affected: */
- /* 1) Adjust thickness
- * - Influence of eraser falls off with distance from the middle of the eraser
- * - Second point gets less influence, as it might get hit again in the next segment
+ /* Adjust thickness
+ * - Influence of eraser falls off with distance from the middle of the eraser
+ * - Second point gets less influence, as it might get hit again in the next segment
*/
- pt1->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength;
- pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength / 2.0f;
+
+ /* Adjust strength if the eraser is soft */
+ if (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_SOFT) {
+ float f_strength = eraser->gpencil_settings->era_strength_f / 100.0f;
+ float f_thickness = eraser->gpencil_settings->era_thickness_f / 100.0f;
+
+ if (pt0) {
+ pt0->strength -= gp_stroke_eraser_calc_influence(p, mval, radius, pc0) * strength * f_strength * 0.5f;
+ CLAMP_MIN(pt0->strength, 0.0f);
+ pt0->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc0) * strength * f_thickness * 0.5f;
+ }
+
+ pt1->strength -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength * f_strength;
+ CLAMP_MIN(pt1->strength, 0.0f);
+ pt1->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength * f_thickness;
+
+ pt2->strength -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength * f_strength * 0.5f;
+ CLAMP_MIN(pt2->strength, 0.0f);
+ pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength * f_thickness * 0.5f;
+
+ /* if invisible, delete point */
+ if ((pt0) &&
+ ((pt0->strength <= GPENCIL_ALPHA_OPACITY_THRESH) ||
+ (pt0->pressure < cull_thresh)))
+ {
+ pt0->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ if ((pt1->strength <= GPENCIL_ALPHA_OPACITY_THRESH) || (pt1->pressure < cull_thresh)) {
+ pt1->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ if ((pt2->strength <= GPENCIL_ALPHA_OPACITY_THRESH) || (pt2->pressure < cull_thresh)) {
+ pt2->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ }
+ else {
+ pt1->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength;
+ pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength * 0.5f;
+ }
/* 2) Tag any point with overly low influence for removal in the next pass */
- if (pt1->pressure < cull_thresh) {
+ if ((pt1->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD))
+ {
pt1->flag |= GP_SPOINT_TAG;
do_cull = true;
}
- if (pt2->pressure < cull_thresh) {
+ if ((pt2->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD))
+ {
pt2->flag |= GP_SPOINT_TAG;
do_cull = true;
}
@@ -1219,8 +1521,15 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* Second Pass: Remove any points that are tagged */
if (do_cull) {
- gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG);
+ /* if soft eraser, must analyze points to be sure the stroke ends
+ * don't get rounded */
+ if (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_SOFT) {
+ gp_stroke_soft_refine(gps, cull_thresh);
+ }
+
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false);
}
+ gp_update_cache(p->gpd);
}
}
@@ -1230,19 +1539,34 @@ static void gp_stroke_doeraser(tGPsdata *p)
bGPDlayer *gpl;
bGPDstroke *gps, *gpn;
rcti rect;
+ Brush *brush = p->brush;
+ Brush *eraser = p->eraser;
+ bool use_pressure = false;
+ float press = 1.0f;
+ /* detect if use pressure in eraser */
+ if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
+ use_pressure = (bool)(brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE);
+ }
+ else if ((eraser != NULL) & (eraser->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ use_pressure = (bool)(eraser->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE);
+ }
+ if (use_pressure) {
+ press = p->pressure;
+ CLAMP(press, 0.01f, 1.0f);
+ }
/* rect is rectangle of eraser */
- rect.xmin = p->mval[0] - p->radius;
- rect.ymin = p->mval[1] - p->radius;
- rect.xmax = p->mval[0] + p->radius;
- rect.ymax = p->mval[1] + p->radius;
+ const int calc_radius = (int)p->radius * press;
+ rect.xmin = p->mval[0] - calc_radius;
+ rect.ymin = p->mval[1] - calc_radius;
+ rect.xmax = p->mval[0] + calc_radius;
+ rect.ymax = p->mval[1] + calc_radius;
if (p->sa->spacetype == SPACE_VIEW3D) {
if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
View3D *v3d = p->sa->spacedata.first;
-
view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->bmain, p->scene, p->ar, v3d, 0);
+ ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0);
}
}
@@ -1265,14 +1589,14 @@ static void gp_stroke_doeraser(tGPsdata *p)
for (gps = gpf->strokes.first; gps; gps = gpn) {
gpn = gps->next;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(p->ob, gpl, gps) == false) {
continue;
}
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpl, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
+ gp_stroke_eraser_dostroke(p, gpl, gpf, gps, p->mval, p->mvalo, calc_radius, &rect);
}
}
}
@@ -1285,107 +1609,170 @@ static void gp_stroke_doeraser(tGPsdata *p)
static void gp_session_validatebuffer(tGPsdata *p)
{
bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
/* clear memory of buffer (or allocate it if starting a new session) */
- if (gpd->sbuffer) {
+ if (gpd->runtime.sbuffer) {
/* printf("\t\tGP - reset sbuffer\n"); */
- memset(gpd->sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
+ memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
}
else {
/* printf("\t\tGP - allocate sbuffer\n"); */
- gpd->sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
+ gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
}
/* reset indices */
- gpd->sbuffer_size = 0;
+ gpd->runtime.sbuffer_size = 0;
/* reset flags */
- gpd->sbuffer_sflag = 0;
+ gpd->runtime.sbuffer_sflag = 0;
/* reset inittime */
p->inittime = 0.0;
+
+ /* reset lazy */
+ if (brush) {
+ brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP;
+ }
}
-/* create a new palette color */
-static bGPDpalettecolor *gp_create_new_color(bGPDpalette *palette)
+/* helper to get default eraser and create one if no eraser brush */
+static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts)
{
- bGPDpalettecolor *palcolor;
+ Brush *brush_dft = NULL;
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *brush_old = paint->brush;
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if ((brush->ob_mode == OB_MODE_GPENCIL_PAINT) &&
+ (brush->gpencil_tool == GPAINT_TOOL_ERASE))
+ {
+ /* save first eraser to use later if no default */
+ if (brush_dft == NULL) {
+ brush_dft = brush;
+ }
+ /* found default */
+ if (brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) {
+ return brush;
+ }
+ }
+ }
+ /* if no default, but exist eraser brush, return this and set as default */
+ if (brush_dft) {
+ brush_dft->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER;
+ return brush_dft;
+ }
+ /* create a new soft eraser brush */
+ else {
+ brush_dft = BKE_brush_add_gpencil(bmain, ts, "Soft Eraser");
+ brush_dft->size = 30.0f;
+ brush_dft->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush_dft->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ brush_dft->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush_dft->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
- palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
+ /* reset current brush */
+ BKE_paint_brush_set(paint, brush_old);
- return palcolor;
+ return brush_dft;
+ }
}
/* initialize a drawing brush */
-static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p)
+static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
{
- bGPDbrush *brush;
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ Paint *paint = &ts->gp_paint->paint;
/* if not exist, create a new one */
- if (BLI_listbase_is_empty(&ts->gp_brushes)) {
+ if (paint->brush == NULL) {
/* create new brushes */
- BKE_gpencil_brush_init_presets(ts);
- brush = BKE_gpencil_brush_getactive(ts);
+ BKE_brush_gpencil_presets(C);
+ }
+ /* be sure curves are initializated */
+ curvemapping_initialize(paint->brush->gpencil_settings->curve_sensitivity);
+ curvemapping_initialize(paint->brush->gpencil_settings->curve_strength);
+ curvemapping_initialize(paint->brush->gpencil_settings->curve_jitter);
+
+ /* assign to temp tGPsdata */
+ p->brush = paint->brush;
+ if (paint->brush->gpencil_tool != GPAINT_TOOL_ERASE) {
+ p->eraser = gp_get_default_eraser(p->bmain, ts);
}
else {
- /* Use the current */
- brush = BKE_gpencil_brush_getactive(ts);
+ p->eraser = paint->brush;
}
- /* be sure curves are initializated */
- curvemapping_initialize(brush->cur_sensitivity);
- curvemapping_initialize(brush->cur_strength);
- curvemapping_initialize(brush->cur_jitter);
+ /* use radius of eraser */
+ p->radius = (short)p->eraser->size;
- /* asign to temp tGPsdata */
- p->brush = brush;
+ /* GPXX: Need this update to synchronize brush with draw manager.
+ * Maybe this update can be removed when the new tool system
+ * will be in place, but while, we need this to keep drawing working.
+ */
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
}
-/* initialize a paint palette brush and a default color if not exist */
-static void gp_init_palette(tGPsdata *p)
+/* initialize a paint brush and a default color if not exist */
+static void gp_init_colors(tGPsdata *p)
{
- bGPdata *gpd;
- bGPDpalette *palette;
- bGPDpalettecolor *palcolor;
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+
+ Material *ma = NULL;
+ MaterialGPencilStyle *gp_style = NULL;
- gpd = p->gpd;
+ /* use brush material */
+ ma = BKE_gpencil_get_material_from_brush(brush);
- /* 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);
+ /* if no brush defaults, get material and color info
+ * NOTE: Ensures that everything we need will exist...
+ */
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
+ BKE_gpencil_material_ensure(p->bmain, p->ob);
+
+ /* assign always the first material to the brush */
+ p->material = give_current_material(p->ob, 1);
+ brush->gpencil_settings->material = p->material;
}
else {
- /* Use the current palette and color */
- palette = BKE_gpencil_palette_getactive(gpd);
- /* the palette needs one color */
- if (BLI_listbase_is_empty(&palette->colors)) {
- palcolor = gp_create_new_color(palette);
- }
- else {
- palcolor = BKE_gpencil_palettecolor_getactive(palette);
- }
- /* in some situations can be null, so use first */
- if (palcolor == NULL) {
- BKE_gpencil_palettecolor_setactive(palette, palette->colors.first);
- palcolor = palette->colors.first;
- }
+ p->material = ma;
+ }
+
+ /* check if the material is already on object material slots and add it if missing */
+ if (BKE_gpencil_get_material_index(p->ob, p->material) == 0) {
+ BKE_object_material_slot_add(p->bmain, p->ob);
+ assign_material(p->bmain, p->ob, ma, p->ob->totcol, BKE_MAT_ASSIGN_USERPREF);
}
- /* asign to temp tGPsdata */
- p->palettecolor = palcolor;
+ /* assign color information to temp tGPsdata */
+ gp_style = p->material->gp_style;
+ if (gp_style) {
+
+ /* set colors */
+ copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba);
+ copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba);
+ /* add some alpha to make easy the filling without hide strokes */
+ if (gpd->runtime.sfill[3] > 0.8f) {
+ gpd->runtime.sfill[3] = 0.8f;
+ }
+
+ gpd->runtime.mode = (short)gp_style->mode;
+ gpd->runtime.bstroke_style = gp_style->stroke_style;
+ gpd->runtime.bfill_style = gp_style->fill_style;
+ }
}
/* (re)init new painting data */
-static bool gp_session_initdata(bContext *C, tGPsdata *p)
+static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
{
Main *bmain = CTX_data_main(C);
bGPdata **gpd_ptr = NULL;
ScrArea *curarea = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *obact = CTX_data_active_object(C);
/* make sure the active view (at the starting time) is a 3d-view */
if (curarea == NULL) {
@@ -1396,9 +1783,12 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
}
/* pass on current scene and window */
+ p->C = C;
p->bmain = CTX_data_main(C);
p->scene = CTX_data_scene(C);
+ p->depsgraph = CTX_data_depsgraph(C);
p->win = CTX_wm_window(C);
+ p->disable_fill = RNA_boolean_get(op->ptr, "disable_fill");
unit_m4(p->imat);
unit_m4(p->mat);
@@ -1413,7 +1803,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* set current area
* - must verify that region data is 3D-view (and not something else)
*/
- /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
+ /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
p->sa = curarea;
p->ar = ar;
p->align_flag = &ts->gpencil_v3d_align;
@@ -1424,92 +1814,19 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n");
return 0;
}
- break;
- }
- case SPACE_NODE:
- {
- /* SpaceNode *snode = curarea->spacedata.first; */
- /* set current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_v2d_align;
- break;
- }
- case SPACE_SEQ:
- {
- SpaceSeq *sseq = curarea->spacedata.first;
-
- /* set current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_seq_align;
-
- /* check that gpencil data is allowed to be drawn */
- if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n");
- return 0;
+ /* if active object doesn't exist or isn't a GP Object, create one */
+ const float *cur = p->scene->cursor.location;
+ if ((!obact) || (obact->type != OB_GPENCIL)) {
+ /* create new default object */
+ obact = ED_add_gpencil_object(C, p->scene, cur);
}
- break;
- }
- case SPACE_IMAGE:
- {
- /* SpaceImage *sima = curarea->spacedata.first; */
+ /* assign object after all checks to be sure we have one active */
+ p->ob = obact;
- /* set the current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_ima_align;
break;
}
- case SPACE_CLIP:
- {
- SpaceClip *sc = curarea->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip == NULL) {
- p->status = GP_STATUS_ERROR;
- return false;
- }
-
- /* set the current area */
- p->sa = curarea;
- p->ar = ar;
- p->v2d = &ar->v2d;
- p->align_flag = &ts->gpencil_v2d_align;
-
- invert_m4_m4(p->imat, sc->unistabmat);
-
- /* custom color for new layer */
- p->custom_color[0] = 1.0f;
- p->custom_color[1] = 0.0f;
- p->custom_color[2] = 0.5f;
- p->custom_color[3] = 0.9f;
-
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- int framenr = ED_space_clip_get_clip_frame_number(sc);
- MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
- MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
-
- if (marker) {
- p->imat[3][0] -= marker->pos[0];
- p->imat[3][1] -= marker->pos[1];
- }
- else {
- p->status = GP_STATUS_ERROR;
- return false;
- }
- }
- invert_m4_m4(p->mat, p->imat);
- copy_m4_m4(p->gsc.mat, p->mat);
- break;
- }
/* unsupported views */
default:
{
@@ -1522,7 +1839,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* get gp-data */
gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
- if (gpd_ptr == NULL) {
+ if ((gpd_ptr == NULL) || ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
p->status = GP_STATUS_ERROR;
if (G.debug & G_DEBUG)
printf("Error: Current context doesn't allow for any Grease Pencil data\n");
@@ -1544,36 +1861,58 @@ 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;
- /* lock axis */
- p->lock_axis = ts->gp_sculpt.lock_axis;
+ gp_init_drawing_brush(C, p);
+
+ /* setup active color */
+ if (curarea->spacetype == SPACE_VIEW3D) {
+ /* NOTE: This is only done for 3D view, as Materials aren't used for
+ * annotations in 2D editors
+ */
+ gp_init_colors(p);
+ }
+
+ /* lock axis (in some modes, disable) */
+ if (((*p->align_flag & GP_PROJECT_DEPTH_VIEW) == 0) &&
+ ((*p->align_flag & GP_PROJECT_DEPTH_STROKE) == 0))
+ {
+ p->lock_axis = ts->gp_sculpt.lock_axis;
+ }
+ else {
+ p->lock_axis = 0;
+ }
+
+ /* region where paint was originated */
+ p->gpd->runtime.ar = CTX_wm_region(C);
return 1;
}
/* init new painting session */
-static tGPsdata *gp_session_initpaint(bContext *C)
+static tGPsdata *gp_session_initpaint(bContext *C, wmOperator *op)
{
tGPsdata *p = NULL;
- /* create new context data */
+ /* Create new context data */
p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data");
- gp_session_initdata(C, p);
-
- /* radius for eraser circle is defined in userprefs now */
- /* NOTE: we do this here, so that if we exit immediately,
- * erase size won't get lost
+ /* Try to initialise context data
+ * WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
*/
- p->radius = U.gp_eraser;
+ if (gp_session_initdata(C, op, p) == 0) {
+ /* Invalid state - Exit
+ * NOTE: It should be safe to just free the data, since failing context checks should
+ * only happen when no data has been allocated.
+ */
+ MEM_freeN(p);
+ return NULL;
+ }
+
+ /* Random generator, only init once. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= POINTER_AS_UINT(p);
+ p->rng = BLI_rng_new(rng_seed);
/* return context data for running paint operator */
return p;
@@ -1589,28 +1928,38 @@ static void gp_session_cleanup(tGPsdata *p)
return;
/* free stroke buffer */
- if (gpd->sbuffer) {
+ if (gpd->runtime.sbuffer) {
/* printf("\t\tGP - free sbuffer\n"); */
- MEM_freeN(gpd->sbuffer);
- gpd->sbuffer = NULL;
+ MEM_freeN(gpd->runtime.sbuffer);
+ gpd->runtime.sbuffer = NULL;
}
/* clear flags */
- gpd->sbuffer_size = 0;
- gpd->sbuffer_sflag = 0;
+ gpd->runtime.sbuffer_size = 0;
+ gpd->runtime.sbuffer_sflag = 0;
p->inittime = 0.0;
}
+static void gp_session_free(tGPsdata *p)
+{
+ if (p->rng != NULL) {
+ BLI_rng_free(p->rng);
+ }
+ MEM_freeN(p);
+}
+
+
/* init new stroke */
-static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
+static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph)
{
Scene *scene = p->scene;
ToolSettings *ts = scene->toolsettings;
+ int cfra_eval = (int)DEG_get_ctime(p->depsgraph);
/* get active layer (or add a new one if non-existent) */
p->gpl = BKE_gpencil_layer_getactive(p->gpd);
if (p->gpl == NULL) {
- p->gpl = BKE_gpencil_layer_addnew(p->gpd, "GP_Layer", true);
+ p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true);
if (p->custom_color[3])
copy_v3_v3(p->gpl->color, p->custom_color);
@@ -1644,7 +1993,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
* -> If there are no strokes in that frame, don't add a new empty frame
*/
if (gpl->actframe && gpl->actframe->strokes.first) {
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_COPY);
has_layer_to_erase = true;
}
@@ -1661,7 +2010,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
* (though this is only available in editmode)
*/
if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) {
- if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ if (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
p->flags |= GP_PAINTFLAG_SELECTMASK;
}
}
@@ -1669,7 +2018,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
//if (G.debug & G_DEBUG)
- printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
+ printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
return;
}
}
@@ -1682,7 +2031,9 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
else
add_frame_mode = GP_GETFRAME_ADD_NEW;
- p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_getframe(p->gpl, cfra_eval, add_frame_mode);
+ /* set as dirty draw manager cache */
+ gp_update_cache(p->gpd);
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
@@ -1698,7 +2049,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* set 'eraser' for this stroke if using eraser */
p->paintmode = paintmode;
if (p->paintmode == GP_PAINTMODE_ERASER) {
- p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
/* check if we should respect depth while erasing */
if (p->sa->spacetype == SPACE_VIEW3D) {
@@ -1709,7 +2060,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
else {
/* disable eraser flags - so that we can switch modes during a session */
- p->gpd->sbuffer_sflag &= ~GP_STROKE_ERASER;
+ p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
if (p->sa->spacetype == SPACE_VIEW3D) {
if (p->gpl->flag & GP_LAYER_NO_XRAY) {
@@ -1718,10 +2069,16 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
}
}
+ /* set special fill stroke mode */
+ if (p->disable_fill == true) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_NOFILL;
+ /* replace stroke color with fill color */
+ copy_v4_v4(p->gpd->runtime.scolor, p->gpd->runtime.sfill);
+ }
+
/* set 'initial run' flag, which is only used to denote when a new stroke is starting */
p->flags |= GP_PAINTFLAG_FIRSTRUN;
-
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
@@ -1731,7 +2088,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(p->scene, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */
+ ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */
p->subrect = &p->subrect_data;
}
}
@@ -1756,41 +2113,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
switch (p->sa->spacetype) {
case SPACE_VIEW3D:
{
- p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
- break;
- }
- case SPACE_NODE:
- {
- p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
- break;
- }
- case SPACE_SEQ:
- {
- p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
- break;
- }
- case SPACE_IMAGE:
- {
- SpaceImage *sima = (SpaceImage *)p->sa->spacedata.first;
-
- /* only set these flags if the image editor doesn't have an image active,
- * otherwise user will be confused by strokes not appearing after they're drawn
- *
- * Admittedly, this is a bit hacky, but it works much nicer from an ergonomic standpoint!
- */
- if (ELEM(NULL, sima, sima->image)) {
- /* make strokes be drawn in screen space */
- p->gpd->sbuffer_sflag &= ~GP_STROKE_2DSPACE;
- *(p->align_flag) &= ~GP_PROJECT_VIEWSPACE;
- }
- else {
- p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
- }
- break;
- }
- case SPACE_CLIP:
- {
- p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
break;
}
}
@@ -1809,14 +2132,11 @@ static void gp_paint_strokeend(tGPsdata *p)
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->ar);
- ED_view3d_autodist_init(p->bmain, p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
+ ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* check if doing eraser or not */
- if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
- /* simplify stroke before transferring? */
- gp_stroke_simplify(p);
-
+ if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
/* transfer stroke to frame */
gp_stroke_newfrombuffer(p);
}
@@ -1849,26 +2169,39 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
tGPsdata *p = (tGPsdata *)p_ptr;
if (p->paintmode == GP_PAINTMODE_ERASER) {
- glPushMatrix();
+ GPUVertFormat *format = immVertexFormat();
+ const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glTranslatef((float)x, (float)y, 0.0f);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
- glColor4ub(255, 100, 100, 20);
- glutil_draw_filled_arc(0.0, M_PI * 2.0, p->radius, 40);
+ immUnbindProgram();
- setlinestyle(6);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- glColor4ub(255, 100, 100, 200);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, p->radius, 40);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- setlinestyle(0);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
- glPopMatrix();
+ imm_draw_circle_wire_2d(shdr_pos, x, y, p->radius,
+ /* XXX Dashed shader gives bad results with sets of small segments currently,
+ * temp hack around the issue. :( */
+ max_ii(8, p->radius / 2)); /* was fixed 40 */
+
+ immUnbindProgram();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
}
}
@@ -1881,10 +2214,13 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
p->erasercursor = NULL;
}
else if (enable && !p->erasercursor) {
+ ED_gpencil_toggle_brush_cursor(p->C, false, NULL);
/* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- NULL, /* XXX */
- gpencil_draw_eraser, p);
+ p->erasercursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ NULL, /* XXX */
+ gpencil_draw_eraser, p);
}
}
@@ -1905,12 +2241,6 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
{
tGPsdata *p = op->customdata;
- /* clear undo stack */
- gpencil_undo_finish();
-
- /* restore cursor to indicate end of drawing */
- WM_cursor_modal_restore(CTX_wm_window(C));
-
/* don't assume that operator data exists at all */
if (p) {
/* check size of buffer before cleanup, to determine if anything happened here */
@@ -1923,14 +2253,39 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
* NOTE: Do this even when not in eraser mode, as eraser may
* have been toggled at some point.
*/
- U.gp_eraser = p->radius;
+ if (p->eraser) {
+ p->eraser->size = p->radius;
+ }
+
+ /* restore cursor to indicate end of drawing */
+ if (p->sa->spacetype != SPACE_VIEW3D) {
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ }
+ else {
+ /* or restore paint if 3D view */
+ if ((p) && (p->paintmode == GP_PAINTMODE_ERASER)) {
+ WM_cursor_modal_set(p->win, CURSOR_STD);
+ }
+
+ /* drawing batch cache is dirty now */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd) {
+ gpd->flag &= ~GP_DATA_STROKE_POLYGON;
+ gp_update_cache(gpd);
+ }
+ }
+
+ /* clear undo stack */
+ gpencil_undo_finish();
/* cleanup */
gp_paint_cleanup(p);
gp_session_cleanup(p);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
/* finally, free the temp data */
- MEM_freeN(p);
+ gp_session_free(p);
+ p = NULL;
}
op->customdata = NULL;
@@ -1949,9 +2304,18 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p;
eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+
+ /* if mode is draw and the brush is eraser, cancel */
+ if (paintmode != GP_PAINTMODE_ERASER) {
+ if ((brush) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ return 0;
+ }
+ }
/* check context */
- p = op->customdata = gp_session_initpaint(C);
+ p = op->customdata = gp_session_initpaint(C, op);
if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
/* something wasn't set correctly in context */
gpencil_draw_exit(C, op);
@@ -1959,7 +2323,7 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
}
/* init painting data */
- gp_paint_initstroke(p, paintmode);
+ gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C));
if (p->status == GP_STATUS_ERROR) {
gpencil_draw_exit(C, op);
return 0;
@@ -1972,6 +2336,8 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
p->keymodifier = -1;
}
+ p->reports = op->reports;
+
/* everything is now setup ok */
return 1;
}
@@ -1982,45 +2348,63 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
/* ensure that the correct cursor icon is set */
static void gpencil_draw_cursor_set(tGPsdata *p)
{
- if (p->paintmode == GP_PAINTMODE_ERASER)
+ Brush *brush = p->brush;
+ if ((p->paintmode == GP_PAINTMODE_ERASER) ||
+ (brush->gpencil_tool == GPAINT_TOOL_ERASE))
+ {
WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
- else
- WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+ }
+ else {
+ WM_cursor_modal_set(p->win, CURSOR_NONE);
+
+ }
}
/* update UI indicators of status, including cursor and header prints */
-static void gpencil_draw_status_indicators(tGPsdata *p)
+static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
{
/* header prints */
switch (p->status) {
- case GP_STATUS_PAINTING:
- /* only print this for paint-sessions, otherwise it gets annoying */
- if (GPENCIL_SKETCH_SESSIONS_ON(p->scene))
- ED_area_headerprint(p->sa, IFACE_("Grease Pencil: Drawing/erasing stroke... Release to end stroke"));
- break;
+
+#if 0 /* FIXME, this never runs! */
+ switch (p->paintmode) {
+ case GP_PAINTMODE_DRAW_POLY:
+ /* Provide usage tips, since this is modal, and unintuitive without hints */
+ ED_workspace_status_text(
+ C, IFACE_(
+ "Annotation Create Poly: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"
+ ));
+ break;
+ default:
+ /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
+ * Showing any text would just be annoying as it would flicker.
+ */
+ break;
+ }
+#endif
case GP_STATUS_IDLING:
/* print status info */
switch (p->paintmode) {
case GP_PAINTMODE_ERASER:
- ED_area_headerprint(p->sa, IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | "
- "ESC/Enter to end (or click outside this area)"));
+ ED_workspace_status_text(C, IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | "
+ "ESC/Enter to end (or click outside this area)"));
break;
case GP_PAINTMODE_DRAW_STRAIGHT:
- ED_area_headerprint(p->sa, IFACE_("Grease Pencil Line Session: Hold and drag LMB to draw | "
- "ESC/Enter to end (or click outside this area)"));
+ ED_workspace_status_text(C, IFACE_("Grease Pencil Line Session: Hold and drag LMB to draw | "
+ "ESC/Enter to end (or click outside this area)"));
break;
case GP_PAINTMODE_DRAW:
- ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
- "E/ESC/Enter to end (or click outside this area)"));
+ ED_workspace_status_text(C, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw"));
break;
case GP_PAINTMODE_DRAW_POLY:
- ED_area_headerprint(p->sa, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
- "ESC/Enter to end (or click outside this area)"));
+ ED_workspace_status_text(C, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
+ "Release Shift/ESC/Enter to end (or click outside this area)"));
break;
default: /* unhandled future cases */
- ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end (or click outside this area)"));
+ ED_workspace_status_text(C, IFACE_("Grease Pencil Session: ESC/Enter to end (or click outside this area)"));
break;
}
break;
@@ -2028,7 +2412,9 @@ static void gpencil_draw_status_indicators(tGPsdata *p)
case GP_STATUS_ERROR:
case GP_STATUS_DONE:
/* clear status string */
- ED_area_headerprint(p->sa, NULL);
+ ED_workspace_status_text(C, NULL);
+ break;
+ case GP_STATUS_PAINTING:
break;
}
}
@@ -2036,8 +2422,11 @@ static void gpencil_draw_status_indicators(tGPsdata *p)
/* ------------------------------- */
/* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
+static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
{
+ bGPdata *gpd = p->gpd;
+ tGPspoint *pt = NULL;
+
/* handle drawing/erasing -> test for erasing first */
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* do 'live' erasing now */
@@ -2050,6 +2439,17 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
}
/* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */
else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
+
+ /* if lazy mouse, interpolate the last and current mouse positions */
+ if (GPENCIL_LAZY_MODE(p->brush, p->shift)) {
+ float now_mouse[2];
+ float last_mouse[2];
+ copy_v2fl_v2i(now_mouse, p->mval);
+ copy_v2fl_v2i(last_mouse, p->mvalo);
+ interp_v2_v2v2(now_mouse, now_mouse, last_mouse, p->brush->smooth_stroke_factor);
+ round_v2i_v2fl(p->mval, now_mouse);
+ }
+
/* try to add point */
short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
@@ -2058,7 +2458,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
/* finish off old stroke */
gp_paint_strokeend(p);
/* And start a new one!!! Else, projection errors! */
- gp_paint_initstroke(p, p->paintmode);
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
/* start a new stroke, starting from previous point */
/* XXX Must manually reset inittime... */
@@ -2087,11 +2487,24 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
p->mvalo[1] = p->mval[1];
p->opressure = p->pressure;
p->ocurtime = p->curtime;
+
+ pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ }
+ }
+ else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
+ (gpd->runtime.sbuffer_size > 0))
+ {
+ pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1;
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ }
}
}
/* handle draw event */
-static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
+static void gpencil_draw_apply_event(bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, int x, int y)
{
tGPsdata *p = op->customdata;
PointerRNA itemptr;
@@ -2099,13 +2512,15 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
int tablet = 0;
/* convert from window-space to area-space mouse coordinates
+ * add any x,y override position for fake events
* NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding...
*/
- p->mval[0] = event->mval[0] + 1;
- p->mval[1] = event->mval[1] + 1;
+ p->mval[0] = event->mval[0] + 1 - x;
+ p->mval[1] = event->mval[1] + 1 - y;
+ p->shift = event->shift;
/* verify key status for straight lines */
- if ((event->ctrl > 0) || (event->alt > 0)) {
+ if ((event->alt > 0) && (RNA_boolean_get(op->ptr, "disable_straight") == false)) {
if (p->straight[0] == 0) {
int dx = abs(p->mval[0] - p->mvalo[0]);
int dy = abs(p->mval[1] - p->mvalo[1]);
@@ -2114,12 +2529,12 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
if (dx >= dy) {
/* horizontal */
p->straight[0] = 1;
- p->straight[1] = p->mval[1]; /* save y */
+ p->straight[1] = (short)p->mval[1]; /* save y */
}
else {
/* vertical */
p->straight[0] = 2;
- p->straight[1] = p->mval[0]; /* save x */
+ p->straight[1] = (short)p->mval[0]; /* save x */
}
}
}
@@ -2154,6 +2569,22 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
p->pressure = 1.0f;
}
+ /* special eraser modes */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if (event->shift > 0) {
+ p->flags |= GP_PAINTFLAG_HARD_ERASER;
+ }
+ else {
+ p->flags &= ~GP_PAINTFLAG_HARD_ERASER;
+ }
+ if (event->alt > 0) {
+ p->flags |= GP_PAINTFLAG_STROKE_ERASER;
+ }
+ else {
+ p->flags &= ~GP_PAINTFLAG_STROKE_ERASER;
+ }
+ }
+
/* special exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
@@ -2196,7 +2627,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
- gpencil_draw_apply(op, p);
+ gpencil_draw_apply(C, op, p, depsgraph);
/* force refresh */
ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
@@ -2208,12 +2639,13 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
static int gpencil_draw_exec(bContext *C, wmOperator *op)
{
tGPsdata *p = NULL;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
/* printf("GPencil - Starting Re-Drawing\n"); */
/* try to initialize context data needed while drawing */
if (!gpencil_draw_init(C, op, NULL)) {
- if (op->customdata) MEM_freeN(op->customdata);
+ MEM_SAFE_FREE(op->customdata);
/* printf("\tGP - no valid data\n"); */
return OPERATOR_CANCELLED;
}
@@ -2225,7 +2657,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
/* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
* setting the relevant values in context at each step, then applying
*/
- RNA_BEGIN (op->ptr, itemptr, "stroke")
+ RNA_BEGIN(op->ptr, itemptr, "stroke")
{
float mousef[2];
@@ -2245,7 +2677,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
/* TODO: both of these ops can set error-status, but we probably don't need to worry */
gp_paint_strokeend(p);
- gp_paint_initstroke(p, p->paintmode);
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
}
}
@@ -2260,7 +2692,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
}
/* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(op, p);
+ gpencil_draw_apply(C, op, p, depsgraph);
}
RNA_END;
@@ -2286,6 +2718,11 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (G.debug & G_DEBUG)
printf("GPencil - Starting Drawing\n");
+ /* support for tablets eraser pen */
+ if (gpencil_is_tablet_eraser_active(event)) {
+ RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
+ }
+
/* try to initialize context data needed while drawing */
if (!gpencil_draw_init(C, op, event)) {
if (op->customdata)
@@ -2300,12 +2737,15 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
/* TODO: set any additional settings that we can take from the events?
* TODO? if tablet is erasing, force eraser to be on? */
- /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
+ /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
- /* if eraser is on, draw radial aid */
+ /* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
}
+ else {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
/* set cursor
* NOTE: This may change later (i.e. intentionally via brush toggle,
* or unintentionally if the user scrolls outside the area)...
@@ -2319,7 +2759,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
p->status = GP_STATUS_PAINTING;
/* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(op, event);
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0, 0);
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
@@ -2328,9 +2768,30 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
+ /* enable paint mode */
+ if (p->sa->spacetype == SPACE_VIEW3D) {
+ Object *ob = CTX_data_active_object(C);
+ if (ob && (ob->type == OB_GPENCIL) && ((p->gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)) {
+ /* FIXME: use the mode switching operator, this misses notifiers, messages. */
+ /* Just set paintmode flag... */
+ p->gpd->flag |= GP_DATA_STROKE_PAINTMODE;
+ /* disable other GP modes */
+ p->gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ p->gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ p->gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ /* set workspace mode */
+ ob->restore_mode = ob->mode;
+ ob->mode = OB_MODE_GPENCIL_PAINT;
+ /* redraw mode on screen */
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+ }
+ }
+
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
/* add a modal handler for this operator, so that we can then draw continuous strokes */
WM_event_add_modal_handler(C, op);
+
return OPERATOR_RUNNING_MODAL;
}
@@ -2359,8 +2820,8 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
/* XXX: watch it with the paintmode! in future,
* it'd be nice to allow changing paint-mode when in sketching-sessions */
- if (gp_session_initdata(C, p))
- gp_paint_initstroke(p, p->paintmode);
+ if (gp_session_initdata(C, op, p))
+ gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C));
if (p->status != GP_STATUS_ERROR) {
p->status = GP_STATUS_PAINTING;
@@ -2410,6 +2871,76 @@ static void gpencil_move_last_stroke_to_back(bContext *C)
BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
}
+/* add events for missing mouse movements when the artist draw very fast */
+static void gpencil_add_missing_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
+{
+ Brush *brush = p->brush;
+ if (brush->gpencil_settings->input_samples == 0) {
+ return;
+ }
+ RegionView3D *rv3d = p->ar->regiondata;
+ float defaultpixsize = rv3d->pixsize * 1000.0f;
+ int samples = (GP_MAX_INPUT_SAMPLES - brush->gpencil_settings->input_samples + 1);
+ float thickness = (float)brush->size;
+
+ float pt[2], a[2], b[2];
+ float vec[3];
+ float scale = 1.0f;
+
+ /* get pixel scale */
+ gp_get_3d_reference(p, vec);
+ mul_m4_v3(rv3d->persmat, vec);
+ if (rv3d->is_persp) {
+ scale = vec[2] * defaultpixsize;
+ }
+ else {
+ scale = defaultpixsize;
+ }
+
+ /* The thickness of the brush is reduced of thickness to get overlap dots */
+ float dot_factor = 0.50f;
+ if (samples < 2) {
+ dot_factor = 0.05f;
+ }
+ else if (samples < 4) {
+ dot_factor = 0.10f;
+ }
+ else if (samples < 7) {
+ dot_factor = 0.3f;
+ }
+ else if (samples < 10) {
+ dot_factor = 0.4f;
+ }
+ float factor = ((thickness * dot_factor) / scale) * samples;
+
+ copy_v2fl_v2i(a, p->mvalo);
+ b[0] = event->mval[0] + 1;
+ b[1] = event->mval[1] + 1;
+
+ /* get distance in pixels */
+ float dist = len_v2v2(a, b);
+
+ /* for very small distances, add a half way point */
+ if (dist <= 2.0f) {
+ interp_v2_v2v2(pt, a, b, 0.5f);
+ sub_v2_v2v2(pt, b, pt);
+ /* create fake event */
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C),
+ (int)pt[0], (int)pt[1]);
+ }
+ else if (dist >= factor) {
+ int slices = 2 + (int)((dist - 1.0) / factor);
+ float n = 1.0f / slices;
+ for (int i = 1; i < slices; i++) {
+ interp_v2_v2v2(pt, a, b, n * i);
+ sub_v2_v2v2(pt, b, pt);
+ /* create fake event */
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C),
+ (int)pt[0], (int)pt[1]);
+ }
+ }
+}
+
/* events handling during interactive drawing part of operator */
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -2450,14 +2981,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, p->keymodifier)) && (event->val == KM_RELEASE)) {
- /* enable continuous if release D key in mid drawing */
- p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON;
- }
else if ((event->type == BKEY) && (event->val == KM_RELEASE)) {
/* Add Blank Frame
* - Since this operator is non-modal, we can just call it here, and keep going...
- * - This operator is especially useful when animating
+ * - This operator is especially useful when animating
*/
WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
estate = OPERATOR_RUNNING_MODAL;
@@ -2472,7 +2999,10 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* exit painting mode (and/or end current stroke)
* NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
*/
- if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
+ /* if polyline and release shift must cancel */
+ if ((ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) ||
+ ((p->paintmode == GP_PAINTMODE_DRAW_POLY) && (event->shift == 0)))
+ {
/* exit() ends the current stroke before cleaning up */
/* printf("\t\tGP - end of paint op + end of stroke\n"); */
/* if drawing polygon and enable on back, must move stroke */
@@ -2499,10 +3029,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
int sketch = 0;
/* basically, this should be mouse-button up = end stroke
- * BUT what happens next depends on whether we 'painting sessions' is enabled
+ * BUT, polyline drawing is an exception -- all knots should be added during one session
*/
- sketch |= GPENCIL_SKETCH_SESSIONS_ON(p->scene);
- /* polyline drawing is also 'sketching' -- all knots should be added during one session */
sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
if (sketch) {
@@ -2547,6 +3075,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
}
+ /* drawing batch cache is dirty now */
+ gp_update_cache(p->gpd);
+
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
@@ -2627,7 +3158,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* NOTE: Don't enter this case if an error occurred while finding the
* region (as above)
*/
- /* if drawing polygon and enable on back, must move stroke */
+ /* if drawing polygon and enable on back, must move stroke */
if (ts) {
if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
if (p->flags & GP_PAINTFLAG_STROKEADDED) {
@@ -2651,7 +3182,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
/* handle drawing event */
/* printf("\t\tGP - add point\n"); */
- gpencil_draw_apply_event(op, event);
+ gpencil_add_missing_events(C, op, event, p);
+
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0, 0);
/* finish painting operation if anything went wrong just now */
if (p->status == GP_STATUS_ERROR) {
@@ -2671,7 +3204,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* just resize the brush (local version)
* TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
*/
- /* printf("\t\tGP - resize eraser\n"); */
+ /* printf("\t\tGP - resize eraser\n"); */
switch (event->type) {
case WHEELDOWNMOUSE: /* larger */
case PADPLUSKEY:
@@ -2707,7 +3240,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
estate = OPERATOR_CANCELLED;
else {
/* update status indicators - cursor, header, etc. */
- gpencil_draw_status_indicators(p);
+ gpencil_draw_status_indicators(C, p);
gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */
}
@@ -2727,7 +3260,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* event doesn't need to be handled */
#if 0
printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
- event->type, event->type == MIDDLEMOUSE, event->type==MOUSEMOVE);
+ event->type, event->type == MIDDLEMOUSE, event->type == MOUSEMOVE);
#endif
break;
}
@@ -2753,7 +3286,7 @@ void GPENCIL_OT_draw(wmOperatorType *ot)
/* identifiers */
ot->name = "Grease Pencil Draw";
ot->idname = "GPENCIL_OT_draw";
- ot->description = "Make annotations on the active data";
+ ot->description = "Draw a new stroke in the active Grease Pencil Object";
/* api callbacks */
ot->exec = gpencil_draw_exec;
@@ -2773,5 +3306,11 @@ void GPENCIL_OT_draw(wmOperatorType *ot)
/* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */
prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "disable_straight", false, "No Straight lines", "Disable key for straight lines");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "disable_fill", false, "No Fill Areas", "Disable fill to use stroke as fill boundary");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
new file mode 100644
index 00000000000..ee2cf7fad48
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -0,0 +1,781 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for creating new Grease Pencil primitives (boxes, circles, ...)
+ */
+
+ /** \file blender/editors/gpencil/gpencil_primitive.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "ED_gpencil.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_space_api.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+#define MIN_EDGES 2
+#define MAX_EDGES 100
+
+#define IDLE 0
+#define IN_PROGRESS 1
+
+ /* ************************************************ */
+ /* Core/Shared Utilities */
+
+ /* Poll callback for primitive operators */
+static bool gpencil_primitive_add_poll(bContext *C)
+{
+ /* only 3D view */
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype != SPACE_VIEW3D) {
+ return 0;
+ }
+
+ /* need data to create primitive */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd == NULL) {
+ return 0;
+ }
+
+ /* only in edit and paint modes
+ * - paint as it's the "drawing/creation mode"
+ * - edit as this is more of an atomic editing operation
+ * (similar to copy/paste), and also for consistency
+ */
+ if ((gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE)) == 0) {
+ CTX_wm_operator_poll_msg_set(C, "Primitives can only be added in Draw or Edit modes");
+ return 0;
+ }
+
+ /* don't allow operator to function if the active layer is locked/hidden
+ * (BUT, if there isn't an active layer, we are free to add new layer when the time comes)
+ */
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ if ((gpl) && (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE))) {
+ CTX_wm_operator_poll_msg_set(C, "Primitives cannot be added as active layer is locked or hidden");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* ****************** Primitive Interactive *********************** */
+
+/* Helper: Create internal strokes primitives data */
+static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+
+ /* if brush doesn't exist, create a new one */
+ Paint *paint = &ts->gp_paint->paint;
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ }
+ tgpi->brush = paint->brush;
+
+ /* if layer doesn't exist, create a new one */
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true);
+ }
+ tgpi->gpl = gpl;
+
+ /* create a new temporary frame */
+ tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe");
+ tgpi->gpf->framenum = tgpi->cframe = cfra_eval;
+
+ /* create new temp stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke");
+ gps->thickness = 2.0f;
+ gps->inittime = 0.0f;
+
+ /* enable recalculation flag by default */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ /* the polygon must be closed, so enabled cyclic */
+ if (tgpi->type != GP_STROKE_LINE) {
+ gps->flag |= GP_STROKE_CYCLIC;
+ }
+ else {
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ }
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = BKE_gpencil_get_material_index(tgpi->ob, tgpi->mat) - 1;
+
+ /* allocate memory for storage points, but keep empty */
+ gps->totpoints = 0;
+ gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ /* initialize triangle memory to dummy data */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* add to strokes */
+ BLI_addtail(&tgpi->gpf->strokes, gps);
+}
+
+/* ----------------------- */
+/* Drawing Callbacks */
+
+/* Drawing callback for modal operator in 3d mode */
+static void gpencil_primitive_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
+{
+ tGPDprimitive *tgpi = (tGPDprimitive *)arg;
+ ED_gp_draw_primitives(C, tgpi, REGION_DRAW_POST_VIEW);
+}
+
+/* ----------------------- */
+
+/* Helper: Draw status message while the user is running the operator */
+static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi)
+{
+ Scene *scene = tgpi->scene;
+ char status_str[UI_MAX_DRAW_STR];
+ char msg_str[UI_MAX_DRAW_STR];
+
+ if (tgpi->type == GP_STROKE_BOX) {
+ BLI_strncpy(msg_str, IFACE_("Rectangle: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm, Shift to square, Alt to center"), UI_MAX_DRAW_STR);
+ }
+ else if (tgpi->type == GP_STROKE_LINE) {
+ BLI_strncpy(msg_str, IFACE_("Line: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm, Alt to center"), UI_MAX_DRAW_STR);
+ }
+ else {
+ BLI_strncpy(msg_str, IFACE_("Circle: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL to adjust edge number, Shift to square, Alt to center"), UI_MAX_DRAW_STR);
+ }
+
+ if (tgpi->type == GP_STROKE_CIRCLE) {
+ if (hasNumInput(&tgpi->num)) {
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&tgpi->num, str_offs, &scene->unit);
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ }
+ else {
+ if (tgpi->flag == IN_PROGRESS) {
+ BLI_snprintf(
+ status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, (int)tgpi->tot_edges,
+ tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]);
+ }
+ else {
+ BLI_snprintf(
+ status_str, sizeof(status_str), "%s: %d (%d, %d)", msg_str, (int)tgpi->tot_edges,
+ tgpi->bottom[0], tgpi->bottom[1]);
+ }
+ }
+ }
+ else {
+ if (tgpi->flag == IN_PROGRESS) {
+ BLI_snprintf(
+ status_str, sizeof(status_str), "%s: (%d, %d) (%d, %d)", msg_str,
+ tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]);
+ }
+ else {
+ BLI_snprintf(
+ status_str, sizeof(status_str), "%s: (%d, %d)", msg_str,
+ tgpi->bottom[0], tgpi->bottom[1]);
+ }
+ }
+ ED_workspace_status_text(C, status_str);
+}
+
+/* ----------------------- */
+
+/* create a rectangle */
+static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D)
+{
+ BLI_assert(tgpi->tot_edges == 4);
+
+ points2D[0].x = tgpi->top[0];
+ points2D[0].y = tgpi->top[1];
+
+ points2D[1].x = tgpi->bottom[0];
+ points2D[1].y = tgpi->top[1];
+
+ points2D[2].x = tgpi->bottom[0];
+ points2D[2].y = tgpi->bottom[1];
+
+ points2D[3].x = tgpi->top[0];
+ points2D[3].y = tgpi->bottom[1];
+}
+
+/* create a line */
+static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
+{
+ BLI_assert(tgpi->tot_edges == 2);
+
+ points2D[0].x = tgpi->top[0];
+ points2D[0].y = tgpi->top[1];
+
+ points2D[1].x = tgpi->bottom[0];
+ points2D[1].y = tgpi->bottom[1];
+}
+
+/* create a circle */
+static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
+{
+ const int totpoints = tgpi->tot_edges;
+ const float step = (2.0f * M_PI) / (float)(totpoints);
+ float center[2];
+ float radius[2];
+ float a = 0.0f;
+
+ /* TODO: Use math-lib functions for these? */
+ center[0] = tgpi->top[0] + ((tgpi->bottom[0] - tgpi->top[0]) / 2.0f);
+ center[1] = tgpi->top[1] + ((tgpi->bottom[1] - tgpi->top[1]) / 2.0f);
+ radius[0] = fabsf(((tgpi->bottom[0] - tgpi->top[0]) / 2.0f));
+ radius[1] = fabsf(((tgpi->bottom[1] - tgpi->top[1]) / 2.0f));
+
+ for (int i = 0; i < totpoints; i++) {
+ tGPspoint *p2d = &points2D[i];
+
+ p2d->x = (int)(center[0] + cosf(a) * radius[0]);
+ p2d->y = (int)(center[1] + sinf(a) * radius[1]);
+ a += step;
+ }
+}
+
+/* Helper: Update shape of the stroke */
+static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
+{
+ ToolSettings *ts = tgpi->scene->toolsettings;
+ bGPdata *gpd = tgpi->gpd;
+ bGPDstroke *gps = tgpi->gpf->strokes.first;
+
+ /* realloc points to new size */
+ /* TODO: only do this if the size has changed? */
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * tgpi->tot_edges);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * tgpi->tot_edges);
+ }
+ gps->totpoints = tgpi->tot_edges;
+
+ /* compute screen-space coordinates for points */
+ tGPspoint *points2D = MEM_callocN(sizeof(tGPspoint) * tgpi->tot_edges, "gp primitive points2D");
+ switch (tgpi->type) {
+ case GP_STROKE_BOX:
+ gp_primitive_rectangle(tgpi, points2D);
+ break;
+ case GP_STROKE_LINE:
+ gp_primitive_line(tgpi, points2D);
+ break;
+ case GP_STROKE_CIRCLE:
+ gp_primitive_circle(tgpi, points2D);
+ break;
+ default:
+ break;
+ }
+
+ /* convert screen-coordinates to 3D coordinates */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ tGPspoint *p2d = &points2D[i];
+
+
+ /* convert screen-coordinates to 3D coordinates */
+ gp_stroke_convertcoords_tpoint(tgpi->scene, tgpi->ar, tgpi->ob, tgpi->gpl, p2d, NULL, &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = tgpi->brush->gpencil_settings->draw_strength;
+ pt->time = 0.0f;
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert = &gps->dvert[i];
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ }
+ }
+
+ /* if axis locked, reproject to plane locked */
+ if (tgpi->lock_axis > GP_LOCKAXIS_VIEW) {
+ bGPDspoint *tpt = gps->points;
+ float origin[3];
+ ED_gp_get_drawing_reference(tgpi->scene, tgpi->ob, tgpi->gpl,
+ ts->gpencil_v3d_align, origin);
+
+ for (int i = 0; i < gps->totpoints; i++, tpt++) {
+ ED_gp_project_point_to_plane(tgpi->ob, tgpi->rv3d, origin,
+ ts->gp_sculpt.lock_axis - 1,
+ tpt);
+ }
+ }
+
+ /* if parented change position relative to parent object */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpd, tgpi->gpl, pt);
+ }
+
+ /* force fill recalc */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* free temp data */
+ MEM_SAFE_FREE(points2D);
+
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+}
+
+/* Update screen and stroke */
+static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive *tgpi)
+{
+ /* update indicator in header */
+ gpencil_primitive_status_indicators(C, tgpi);
+ /* apply... */
+ tgpi->type = RNA_enum_get(op->ptr, "type");
+ tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
+ /* update points position */
+ gp_primitive_update_strokes(C, tgpi);
+}
+
+/* ----------------------- */
+
+static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event)
+{
+ tgpi->origin[0] = event->mval[0];
+ tgpi->origin[1] = event->mval[1];
+
+ tgpi->top[0] = event->mval[0];
+ tgpi->top[1] = event->mval[1];
+
+ tgpi->bottom[0] = event->mval[0];
+ tgpi->bottom[1] = event->mval[1];
+}
+
+/* Exit and free memory */
+static void gpencil_primitive_exit(bContext *C, wmOperator *op)
+{
+ tGPDprimitive *tgpi = op->customdata;
+ bGPdata *gpd = tgpi->gpd;
+
+ /* don't assume that operator data exists at all */
+ if (tgpi) {
+ /* remove drawing handler */
+ if (tgpi->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
+ }
+
+ /* clear status message area */
+ ED_workspace_status_text(C, NULL);
+
+ /* finally, free memory used by temp data */
+ BKE_gpencil_free_strokes(tgpi->gpf);
+ MEM_freeN(tgpi->gpf);
+ MEM_freeN(tgpi);
+ }
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* clear pointer */
+ op->customdata = NULL;
+}
+
+/* Init new temporary primitive data */
+static void gpencil_primitive_init(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ /* create temporary operator data */
+ tGPDprimitive *tgpi = MEM_callocN(sizeof(tGPDprimitive), "GPencil Primitive Data");
+ op->customdata = tgpi;
+
+ /* set current scene and window info */
+ tgpi->scene = scene;
+ tgpi->ob = CTX_data_active_object(C);
+ tgpi->sa = CTX_wm_area(C);
+ tgpi->ar = CTX_wm_region(C);
+ tgpi->rv3d = tgpi->ar->regiondata;
+ tgpi->v3d = tgpi->sa->spacedata.first;
+ tgpi->depsgraph = CTX_data_depsgraph(C);
+ tgpi->win = CTX_wm_window(C);
+
+ /* set current frame number */
+ tgpi->cframe = cfra_eval;
+
+ /* set GP datablock */
+ tgpi->gpd = gpd;
+
+ /* getcolor info */
+ tgpi->mat = BKE_gpencil_material_ensure(bmain, tgpi->ob);
+
+ /* set parameters */
+ tgpi->type = RNA_enum_get(op->ptr, "type");
+
+ /* if circle set default to 32 */
+ if (tgpi->type == GP_STROKE_CIRCLE) {
+ RNA_int_set(op->ptr, "edges", 32);
+ }
+ else if (tgpi->type == GP_STROKE_BOX) {
+ RNA_int_set(op->ptr, "edges", 4);
+ }
+ else { /* LINE */
+ RNA_int_set(op->ptr, "edges", 2);
+ }
+
+ tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
+ tgpi->flag = IDLE;
+
+ tgpi->lock_axis = ts->gp_sculpt.lock_axis;
+
+ /* set temp layer, frame and stroke */
+ gp_primitive_set_initdata(C, tgpi);
+}
+
+/* ----------------------- */
+
+/* Invoke handler: Initialize the operator */
+static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ wmWindow *win = CTX_wm_window(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ tGPDprimitive *tgpi = NULL;
+
+ /* initialize operator runtime data */
+ gpencil_primitive_init(C, op);
+ tgpi = op->customdata;
+
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ if (!is_modal) {
+ tgpi->flag = IN_PROGRESS;
+ gpencil_primitive_interaction_begin(tgpi, event);
+ }
+
+ /* if in tools region, wait till we get to the main (3d-space)
+ * region before allowing drawing to take place.
+ */
+ op->flag |= OP_IS_MODAL_CURSOR_REGION;
+
+ /* Enable custom drawing handlers */
+ tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_primitive_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
+
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_CROSSCURSOR);
+
+ /* update sindicator in header */
+ gpencil_primitive_status_indicators(C, tgpi);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Helper to complete a primitive */
+static void gpencil_primitive_interaction_end(bContext *C, wmOperator *op, wmWindow *win, tGPDprimitive *tgpi)
+{
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+
+ ToolSettings *ts = tgpi->scene->toolsettings;
+
+ const int def_nr = tgpi->ob->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr);
+
+ /* return to normal cursor and header status */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
+
+ /* prepare stroke to get transferred */
+ gps = tgpi->gpf->strokes.first;
+ if (gps) {
+ gps->thickness = tgpi->brush->size;
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ }
+
+ /* transfer stroke from temporary buffer to the actual frame */
+ BLI_movelisttolist(&gpf->strokes, &tgpi->gpf->strokes);
+ BLI_assert(BLI_listbase_is_empty(&tgpi->gpf->strokes));
+
+ /* add weights if required */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *ve = &gps->dvert[i];
+ MDeformWeight *dw = defvert_verify_index(ve, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+
+ }
+ }
+
+ DEG_id_tag_update(&tgpi->gpd->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_id_tag_update(&tgpi->gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ /* clean up temp data */
+ gpencil_primitive_exit(C, op);
+}
+
+/* Modal handler: Events handling during interactive part */
+static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPDprimitive *tgpi = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ const bool has_numinput = hasNumInput(&tgpi->num);
+
+ switch (event->type) {
+ case LEFTMOUSE:
+ if ((event->val == KM_PRESS) && (tgpi->flag == IDLE)) {
+ /* start drawing primitive */
+ /* TODO: Ignore if not in main region yet */
+ tgpi->flag = IN_PROGRESS;
+ gpencil_primitive_interaction_begin(tgpi, event);
+ }
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
+ /* stop drawing primitive */
+ tgpi->flag = IDLE;
+ gpencil_primitive_interaction_end(C, op, win, tgpi);
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+ else {
+ if (G.debug & G_DEBUG) {
+ printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag);
+ }
+ }
+ break;
+ case RETKEY: /* confirm */
+ {
+ tgpi->flag = IDLE;
+ gpencil_primitive_interaction_end(C, op, win, tgpi);
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE:
+ {
+ /* return to normal cursor and header status */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_primitive_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+
+ case WHEELUPMOUSE:
+ {
+ if (tgpi->type == GP_STROKE_CIRCLE) {
+ tgpi->tot_edges = tgpi->tot_edges + 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case WHEELDOWNMOUSE:
+ {
+ if (tgpi->type == GP_STROKE_CIRCLE) {
+ tgpi->tot_edges = tgpi->tot_edges - 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update position of mouse */
+ tgpi->bottom[0] = event->mval[0];
+ tgpi->bottom[1] = event->mval[1];
+ tgpi->top[0] = tgpi->origin[0];
+ tgpi->top[1] = tgpi->origin[1];
+ if (tgpi->flag == IDLE) {
+ tgpi->origin[0] = event->mval[0];
+ tgpi->origin[1] = event->mval[1];
+ }
+ /* Keep square if shift key */
+ if (event->shift) {
+ int x = tgpi->bottom[0] - tgpi->origin[0];
+ int y = tgpi->bottom[1] - tgpi->origin[1];
+ int w = abs(x);
+ int h = abs(y);
+ if ((x > 0 && y > 0) || (x < 0 && y < 0)) {
+ if (w > h)
+ tgpi->bottom[1] = tgpi->origin[1] + x;
+ else
+ tgpi->bottom[0] = tgpi->origin[0] + y;
+ }
+ else {
+ if (w > h)
+ tgpi->bottom[1] = tgpi->origin[1] - x;
+ else
+ tgpi->bottom[0] = tgpi->origin[0] - y;
+ }
+ }
+ /* Center primitive if alt key */
+ if (event->alt) {
+ tgpi->top[0] = tgpi->origin[0] - (tgpi->bottom[0] - tgpi->origin[0]);
+ tgpi->top[1] = tgpi->origin[1] - (tgpi->bottom[1] - tgpi->origin[1]);
+ }
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ default:
+ {
+ if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
+ float value;
+
+ /* Grab data from numeric input, and store this new value (the user see an int) */
+ value = tgpi->tot_edges;
+ applyNumInput(&tgpi->num, &value);
+ tgpi->tot_edges = value;
+
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+
+ /* update screen */
+ gpencil_primitive_update(C, op, tgpi);
+
+ break;
+ }
+ else {
+ /* unhandled event - allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+ }
+
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Cancel handler */
+static void gpencil_primitive_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_primitive_exit(C, op);
+}
+
+void GPENCIL_OT_primitive(wmOperatorType *ot)
+{
+ static EnumPropertyItem primitive_type[] = {
+ {GP_STROKE_BOX, "BOX", 0, "Box", ""},
+ {GP_STROKE_LINE, "LINE", 0, "Line", ""},
+ {GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Grease Pencil Shapes";
+ ot->idname = "GPENCIL_OT_primitive";
+ ot->description = "Create predefined grease pencil stroke shapes";
+
+ /* callbacks */
+ ot->invoke = gpencil_primitive_invoke;
+ ot->modal = gpencil_primitive_modal;
+ ot->cancel = gpencil_primitive_cancel;
+ ot->poll = gpencil_primitive_add_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ RNA_def_int(ot->srna, "edges", 4, MIN_EDGES, MAX_EDGES, "Edges", "Number of polygon edges", MIN_EDGES, MAX_EDGES);
+ RNA_def_enum(ot->srna, "type", primitive_type, GP_STROKE_BOX, "Type", "Type of shape");
+
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/* *************************************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 7bb0c005184..ad943a38a64 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -43,6 +43,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_object_types.h"
@@ -61,18 +62,23 @@
#include "UI_view2d.h"
#include "ED_gpencil.h"
+#include "ED_select_utils.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "gpencil_intern.h"
-/* ********************************************** */
-/* Polling callbacks */
+/* -------------------------------------------------------------------- */
+/** \name Shared Utilities
+ * \{ */
static bool gpencil_select_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- /* we just need some visible strokes, and to be in editmode */
- if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ /* we just need some visible strokes, and to be in editmode or other modes only to catch event */
+ if (GPENCIL_ANY_MODE(gpd)) {
/* TODO: include a check for visible strokes? */
if (gpd->layers.first)
return true;
@@ -81,8 +87,11 @@ static bool gpencil_select_poll(bContext *C)
return false;
}
-/* ********************************************** */
-/* Select All Operator */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select All Operator
+ * \{ */
static int gpencil_select_all_exec(bContext *C, wmOperator *op)
{
@@ -94,6 +103,11 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
/* for "toggle", test for existing selected strokes */
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
@@ -180,6 +194,11 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op)
}
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -201,8 +220,11 @@ void GPENCIL_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/* ********************************************** */
-/* Select Linked */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
static int gpencil_select_linked_exec(bContext *C, wmOperator *op)
{
@@ -213,6 +235,11 @@ static int gpencil_select_linked_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
/* select all points in selected strokes */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
@@ -228,6 +255,11 @@ static int gpencil_select_linked_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -247,15 +279,101 @@ void GPENCIL_OT_select_linked(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************************** */
-/* Select Grouped */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Alternate Operator
+ * \{ */
+
+static int gpencil_select_alternate_exec(bContext *C, wmOperator *op)
+{
+ const bool unselect_ends = RNA_boolean_get(op->ptr, "unselect_ends");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* select all points in selected strokes */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ bGPDspoint *pt;
+ int row = 0;
+ int start = 0;
+ if (unselect_ends) {
+ start = 1;
+ }
+
+ for (int i = start; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ if ((row % 2) == 0) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ row++;
+ }
+
+ /* unselect start and end points */
+ if (unselect_ends) {
+ pt = &gps->points[0];
+ pt->flag &= ~GP_SPOINT_SELECT;
+
+ pt = &gps->points[gps->totpoints - 1];
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_alternate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Alternated";
+ ot->idname = "GPENCIL_OT_select_alternate";
+ ot->description = "Select alternative points in same strokes as already selected points";
+
+ /* callbacks */
+ ot->exec = gpencil_select_alternate_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "unselect_ends", true, "Unselect Ends", "Do not select the first and last point of the stroke");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Grouped Operator
+ * \{ */
typedef enum eGP_SelectGrouped {
/* Select strokes in the same layer */
GP_SEL_SAME_LAYER = 0,
/* Select strokes with the same color */
- GP_SEL_SAME_COLOR = 1,
+ GP_SEL_SAME_MATERIAL = 1,
/* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */
/* TODO: All with same appearance - colour/opacity/volumetric/fills ? */
@@ -266,11 +384,12 @@ typedef enum eGP_SelectGrouped {
/* On each visible layer, check for selected strokes - if found, select all others */
static void gp_select_same_layer(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
{
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
bGPDstroke *gps;
bool found = false;
@@ -307,12 +426,9 @@ static void gp_select_same_layer(bContext *C)
}
/* Select all strokes with same colors as selected ones */
-static void gp_select_same_color(bContext *C)
+static void gp_select_same_material(bContext *C)
{
- /* First, build set containing all the colors of selected strokes
- * - We use the palette names, so that we can select all strokes with one
- * (potentially missing) color, and remap them to something else
- */
+ /* First, build set containing all the colors of selected strokes */
GSet *selected_colors = BLI_gset_str_new("GP Selected Colors");
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
@@ -321,7 +437,7 @@ static void gp_select_same_color(bContext *C)
/* add instead of insert here, otherwise the uniqueness check gets skipped,
* and we get many duplicate entries...
*/
- BLI_gset_add(selected_colors, gps->colorname);
+ BLI_gset_add(selected_colors, &gps->mat_nr);
}
}
CTX_DATA_END;
@@ -329,7 +445,7 @@ static void gp_select_same_color(bContext *C)
/* Second, select any visible stroke that uses these colors */
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
- if (BLI_gset_haskey(selected_colors, gps->colorname)) {
+ if (BLI_gset_haskey(selected_colors, &gps->mat_nr)) {
/* select this stroke */
bGPDspoint *pt;
int i;
@@ -342,6 +458,11 @@ static void gp_select_same_color(bContext *C)
}
}
CTX_DATA_END;
+
+ /* free memomy */
+ if (selected_colors != NULL) {
+ BLI_gset_free(selected_colors, NULL);
+ }
}
@@ -350,13 +471,18 @@ static void gp_select_same_color(bContext *C)
static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
{
eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type");
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
switch (mode) {
case GP_SEL_SAME_LAYER:
gp_select_same_layer(C);
break;
- case GP_SEL_SAME_COLOR:
- gp_select_same_color(C);
+ case GP_SEL_SAME_MATERIAL:
+ gp_select_same_material(C);
break;
default:
@@ -365,6 +491,11 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
}
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -373,7 +504,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
{
static const EnumPropertyItem prop_select_grouped_types[] = {
{GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
- {GP_SEL_SAME_COLOR, "COLOR", 0, "Color", "Shared colors"},
+ {GP_SEL_SAME_MATERIAL, "MATERIAL", 0, "Material", "Shared materials"},
{0, NULL, 0, NULL, NULL}
};
@@ -394,11 +525,20 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, GP_SEL_SAME_LAYER, "Type", "");
}
-/* ********************************************** */
-/* Select First */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select First
+ * \{ */
static int gpencil_select_first_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
const bool extend = RNA_boolean_get(op->ptr, "extend");
@@ -429,6 +569,11 @@ static int gpencil_select_first_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -454,11 +599,20 @@ void GPENCIL_OT_select_first(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points");
}
-/* ********************************************** */
-/* Select First */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select First
+ * \{ */
static int gpencil_select_last_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes");
const bool extend = RNA_boolean_get(op->ptr, "extend");
@@ -489,6 +643,11 @@ static int gpencil_select_last_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -514,11 +673,20 @@ void GPENCIL_OT_select_last(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting all other selected points");
}
-/* ********************************************** */
-/* Select More */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Mode Operator
+ * \{ */
static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
if (gps->flag & GP_STROKE_SELECT) {
@@ -565,6 +733,11 @@ static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -584,11 +757,20 @@ void GPENCIL_OT_select_more(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************************** */
-/* Select Less */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Less Operator
+ * \{ */
static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
if (gps->flag & GP_STROKE_SELECT) {
@@ -636,6 +818,11 @@ static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
/* updates */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -655,8 +842,11 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************************** */
-/* Circle Select Operator */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Circle Select Operator
+ * \{ */
/* Helper to check if a given stroke is within the area */
/* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke()
@@ -665,7 +855,7 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
static bool gp_stroke_do_circle_sel(
bGPDstroke *gps, GP_SpaceConversion *gsc,
const int mx, const int my, const int radius,
- const bool select, rcti *rect, const bool parented, float diff_mat[4][4])
+ const bool select, rcti *rect, float diff_mat[4][4], const int selectmode)
{
bGPDspoint *pt1, *pt2;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
@@ -673,14 +863,9 @@ static bool gp_stroke_do_circle_sel(
bool changed = false;
if (gps->totpoints == 1) {
- if (!parented) {
- gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
- }
- else {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
- }
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
@@ -704,22 +889,17 @@ static bool gp_stroke_do_circle_sel(
/* Loop over the points in the stroke, checking for intersections
* - an intersection means that we touched the stroke
*/
+ bool hit = false;
for (i = 0; (i + 1) < gps->totpoints; i++) {
/* get points to work with */
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
- if (!parented) {
- gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
- gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
- }
- else {
- bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &x0, &y0);
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &x0, &y0);
- gp_point_to_parent_space(pt2, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &x1, &y1);
- }
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &x1, &y1);
/* check that point segment of the boundbox of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
@@ -737,6 +917,7 @@ static bool gp_stroke_do_circle_sel(
* (as the last point otherwise wouldn't get selected
* as we only do n-1 loops through).
*/
+ hit = true;
if (select) {
pt1->flag |= GP_SPOINT_SELECT;
pt2->flag |= GP_SPOINT_SELECT;
@@ -751,6 +932,22 @@ static bool gp_stroke_do_circle_sel(
}
}
}
+ /* if stroke mode, don't check more points */
+ if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
+ break;
+ }
+ }
+
+ /* if stroke mode expand selection */
+ if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
+ for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
+ if (select) {
+ pt1->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt1->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
}
/* Ensure that stroke selection is in sync with its points */
@@ -763,6 +960,15 @@ static bool gp_stroke_do_circle_sel(
static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ const int selectmode = ts->gpencil_selectmode;
+
+ /* if not edit/sculpt mode, the event is catched but not processed */
+ if (GPENCIL_NONE_EDIT_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
ScrArea *sa = CTX_wm_area(C);
const int mx = RNA_int_get(op->ptr, "x");
@@ -795,16 +1001,20 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
/* find visible strokes, and select if hit */
- GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
changed |= gp_stroke_do_circle_sel(
- gps, &gsc, mx, my, radius, select, &rect,
- (gpl->parent != NULL), diff_mat);
+ gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode);
}
- GP_EDITABLE_STROKES_END;
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
/* updates */
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
}
@@ -826,28 +1036,42 @@ void GPENCIL_OT_select_circle(wmOperatorType *ot)
ot->cancel = WM_gesture_circle_cancel;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* properties */
WM_operator_properties_gesture_circle_select(ot);
}
-/* ********************************************** */
-/* Box Selection */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Select Utility
+ *
+ * Use for lasso & box select.
+ *
+ * \{ */
-static int gpencil_border_select_exec(bContext *C, wmOperator *op)
+typedef bool (*GPencilTestFn)(
+ bGPDstroke *gps, bGPDspoint *pt,
+ const GP_SpaceConversion *gsc, const float diff_mat[4][4], void *user_data);
+
+static int gpencil_generic_select_exec(
+ bContext *C, wmOperator *op,
+ GPencilTestFn is_inside_fn, void *user_data)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
ScrArea *sa = CTX_wm_area(C);
+ const bool strokemode = (
+ (ts->gpencil_selectmode == GP_SELECTMODE_STROKE) &&
+ ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- const bool select = !RNA_boolean_get(op->ptr, "deselect");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
GP_SpaceConversion gsc = {NULL};
- rcti rect = {0};
bool changed = false;
-
/* sanity checks */
if (sa == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
@@ -857,9 +1081,9 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
/* init space conversion stuff */
gp_point_conversion_init(C, &gsc);
-
/* deselect all strokes first? */
- if (select && !extend) {
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
{
bGPDspoint *pt;
@@ -874,38 +1098,47 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
}
- /* get settings from operator */
- WM_operator_properties_border_to_rcti(op, &rect);
-
/* select/deselect points */
- GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
bGPDspoint *pt;
int i;
-
+ bool hit = false;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- int x0, y0;
-
/* convert point coords to screenspace */
- if (gpl->parent == NULL) {
- gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
+ const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
+
+ if (strokemode == false) {
+ const bool is_select = (pt->flag & GP_SPOINT_SELECT) != 0;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(pt->flag, sel_op_result, GP_SPOINT_SELECT);
+ changed = true;
+ }
}
else {
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0);
+ if (is_inside) {
+ hit = true;
+ break;
+ }
}
+ }
- /* test if in selection rect */
- if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) {
- if (select) {
- pt->flag |= GP_SPOINT_SELECT;
- }
- else {
- pt->flag &= ~GP_SPOINT_SELECT;
+ /* if stroke mode expand selection */
+ if (strokemode) {
+ const bool is_select = BKE_gpencil_stroke_select_check(gps);
+ const bool is_inside = hit;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (sel_op_result) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ else {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
}
-
changed = true;
}
}
@@ -913,127 +1146,131 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op)
/* Ensure that stroke selection is in sync with its points */
BKE_gpencil_stroke_sync_selection(gps);
}
- GP_EDITABLE_STROKES_END;
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* if paint mode,delete selected points */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ gp_delete_selected_point_wrap(C);
+ changed = true;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
/* updates */
if (changed) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
}
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_select_border(wmOperatorType *ot)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Box Select Operator
+ * \{ */
+
+struct GP_SelectBoxUserData {
+ rcti rect;
+};
+
+static bool gpencil_test_box(
+ bGPDstroke *gps, bGPDspoint *pt,
+ const GP_SpaceConversion *gsc, const float diff_mat[4][4], void *user_data)
+{
+ const struct GP_SelectBoxUserData *data = user_data;
+ bGPDspoint pt2;
+ int x0, y0;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
+ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) &&
+ BLI_rcti_isect_pt(&data->rect, x0, y0));
+}
+
+static int gpencil_box_select_exec(bContext *C, wmOperator *op)
+{
+ struct GP_SelectBoxUserData data = {0};
+ WM_operator_properties_border_to_rcti(op, &data.rect);
+ return gpencil_generic_select_exec(
+ C, op,
+ gpencil_test_box, &data);
+}
+
+void GPENCIL_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
+ ot->name = "Box Select";
ot->description = "Select Grease Pencil strokes within a rectangular region";
- ot->idname = "GPENCIL_OT_select_border";
+ ot->idname = "GPENCIL_OT_select_box";
/* callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = gpencil_border_select_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = gpencil_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = gpencil_select_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_select_operation(ot);
+ WM_operator_properties_gesture_box(ot);
}
-/* ********************************************** */
-/* Lasso */
+/** \} */
-static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
-{
- GP_SpaceConversion gsc = {NULL};
- rcti rect = {0};
+/* -------------------------------------------------------------------- */
+/** \name Lasso Select Operator
+ * \{ */
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool select = !RNA_boolean_get(op->ptr, "deselect");
+struct GP_SelectLassoUserData {
+ rcti rect;
+ const int (*mcords)[2];
+ int mcords_len;
+};
- int mcords_tot;
- const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+static bool gpencil_test_lasso(
+ bGPDstroke *gps, bGPDspoint *pt,
+ const GP_SpaceConversion *gsc, const float diff_mat[4][4],
+ void *user_data)
+{
+ const struct GP_SelectLassoUserData *data = user_data;
+ bGPDspoint pt2;
+ int x0, y0;
+ 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 */
+ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) &&
+ BLI_rcti_isect_pt(&data->rect, x0, y0) &&
+ BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+}
- bool changed = false;
+static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
+{
+ struct GP_SelectLassoUserData data = {0};
+ data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
- /* sanity check */
- if (mcords == NULL)
+ /* Sanity check. */
+ if (data.mcords == NULL) {
return OPERATOR_PASS_THROUGH;
-
- /* compute boundbox of lasso (for faster testing later) */
- BLI_lasso_boundbox(&rect, mcords, mcords_tot);
-
- /* init space conversion stuff */
- gp_point_conversion_init(C, &gsc);
-
- /* deselect all strokes first? */
- if (select && !extend) {
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- bGPDspoint *pt;
- int i;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- gps->flag &= ~GP_STROKE_SELECT;
- }
- CTX_DATA_END;
}
- /* select/deselect points */
- 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 */
- 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))
- {
- if (select) {
- pt->flag |= GP_SPOINT_SELECT;
- }
- else {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- changed = true;
- }
- }
-
- /* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps);
- }
- GP_EDITABLE_STROKES_END;
+ /* Compute boundbox of lasso (for faster testing later). */
+ BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
- /* cleanup */
- MEM_freeN((void *)mcords);
+ int ret = gpencil_generic_select_exec(
+ C, op,
+ gpencil_test_lasso, &data);
- /* updates */
- if (changed) {
- WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
- }
+ MEM_freeN((void *)data.mcords);
- return OPERATOR_FINISHED;
+ return ret;
}
void GPENCIL_OT_select_lasso(wmOperatorType *ot)
@@ -1049,21 +1286,49 @@ void GPENCIL_OT_select_lasso(wmOperatorType *ot)
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
- ot->flag = OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* properties */
- WM_operator_properties_gesture_lasso_select(ot);
+ WM_operator_properties_select_operation(ot);
+ WM_operator_properties_gesture_lasso(ot);
}
-/* ********************************************** */
-/* Mouse Click to Select */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mouse Pick Select Operator
+ * \{ */
+
+/* helper to deselect all selected strokes/points */
+static void deselect_all_selected(bContext *C)
+{
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ /* deselect stroke and its points if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ /* deselect points */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ /* deselect stroke itself too */
+ gps->flag &= ~GP_STROKE_SELECT;
+ }
+ }
+ CTX_DATA_END;
+}
static int gpencil_select_exec(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
- const float radius = 0.75f * U.widget_unit;
+ const float radius = 0.50f * U.widget_unit;
const int radius_squared = (int)(radius * radius);
bool extend = RNA_boolean_get(op->ptr, "extend");
@@ -1085,6 +1350,11 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ /* if select mode is stroke, use whole stroke */
+ if (ts->gpencil_selectmode == GP_SELECTMODE_STROKE) {
+ whole = true;
+ }
+
/* init space conversion stuff */
gp_point_conversion_init(C, &gsc);
@@ -1093,7 +1363,7 @@ 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... */
- GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
bGPDspoint *pt;
int i;
@@ -1102,14 +1372,9 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
- if (gpl->parent == NULL) {
- gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]);
- }
- else {
- bGPDspoint pt2;
- gp_point_to_parent_space(pt, diff_mat, &pt2);
- gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]);
- }
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, gpstroke_iter.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])) {
@@ -1127,10 +1392,19 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
}
}
}
- GP_EDITABLE_STROKES_END;
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
/* Abort if nothing hit... */
if (ELEM(NULL, hit_stroke, hit_point)) {
+
+ /* since left mouse select change, deselect all if click outside any hit */
+ deselect_all_selected(C);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+
return OPERATOR_CANCELLED;
}
@@ -1141,23 +1415,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* If not extending selection, deselect everything else */
if (extend == false) {
- CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
- {
- /* deselect stroke and its points if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- /* deselect points */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
- }
-
- /* deselect stroke itself too */
- gps->flag &= ~GP_STROKE_SELECT;
- }
- }
- CTX_DATA_END;
+ deselect_all_selected(C);
}
/* Perform selection operations... */
@@ -1197,6 +1455,11 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* updates */
if (hit_point != NULL) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
}
@@ -1224,7 +1487,7 @@ void GPENCIL_OT_select(wmOperatorType *ot)
ot->poll = gpencil_select_poll;
/* flag */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* properties */
WM_operator_properties_mouse_select(ot);
@@ -1236,4 +1499,4 @@ void GPENCIL_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/* ********************************************** */
+/** \} */
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 23d80f66630..1dc46d2850d 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
#include "DNA_listBase.h"
#include "DNA_windowmanager_types.h"
@@ -51,6 +52,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph.h"
+
#include "gpencil_intern.h"
typedef struct bGPundonode {
@@ -111,6 +114,9 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
}
}
}
+ /* drawing batch cache is dirty now */
+ DEG_id_tag_update(&new_gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ new_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
}
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 2b49b2bd3d1..73be10a537f 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -40,7 +40,9 @@
#include "BLT_translation.h"
#include "BLI_rand.h"
+#include "DNA_meshdata_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -48,9 +50,15 @@
#include "DNA_view3d_types.h"
#include "BKE_action.h"
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_main.h"
+#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
-#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_material.h"
#include "BKE_tracking.h"
#include "WM_api.h"
@@ -65,6 +73,14 @@
#include "ED_gpencil.h"
#include "ED_clip.h"
#include "ED_view3d.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "gpencil_intern.h"
@@ -74,7 +90,7 @@
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
* when context info is not available.
*/
-bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr)
+bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob, PointerRNA *r_ptr)
{
/* if there's an active area, check if the particular editor may
* have defined any special Grease Pencil context for editing...
@@ -83,26 +99,37 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
SpaceLink *sl = sa->spacedata.first;
switch (sa->spacetype) {
- case SPACE_VIEW3D: /* 3D-View */
+ /* XXX: Should we reduce reliance on context.gpencil_data for these cases? */
+ case SPACE_BUTS: /* properties */
+ case SPACE_INFO: /* header info (needed after workspaces merge) */
{
- BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
- GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* GP Object */
+ if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr);
+ return (bGPdata **)&ob->data;
+ }
+ else {
+ return NULL;
+ }
- if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) {
- /* legacy behaviour for usage with old addons requiring object-linked to objects */
+ break;
+ }
- /* just in case no active/selected object... */
- if (ob && (ob->flag & SELECT)) {
- /* for now, as long as there's an object, default to using that in 3D-View */
- if (ptr) RNA_id_pointer_create(&ob->id, ptr);
- return &ob->gpd;
- }
- /* else: defaults to scene... */
+ case SPACE_TOPBAR: /* Topbar (needed after topbar merge) */
+ case SPACE_VIEW3D: /* 3D-View */
+ {
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* GP Object */
+ if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr);
+ return (bGPdata **)&ob->data;
}
else {
- if (ptr) RNA_id_pointer_create(&scene->id, ptr);
+ /* Annotations */
+ /* XXX: */
+ if (r_ptr) RNA_id_pointer_create(&scene->id, r_ptr);
return &scene->gpd;
}
+
break;
}
case SPACE_NODE: /* Nodes Editor */
@@ -112,7 +139,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
/* return the GP data for the active node block/node */
if (snode && snode->nodetree) {
/* for now, as long as there's an active node tree, default to using that in the Nodes Editor */
- if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr);
+ if (r_ptr) RNA_id_pointer_create(&snode->nodetree->id, r_ptr);
return &snode->nodetree->gpd;
}
@@ -125,7 +152,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
/* for now, Grease Pencil data is associated with the space (actually preview region only) */
/* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr);
+ if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr);
return &sseq->gpd;
}
case SPACE_IMAGE: /* Image/UV Editor */
@@ -134,7 +161,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
/* for now, Grease Pencil data is associated with the space... */
/* XXX our convention for everything else is to link to data though... */
- if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr);
+ if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr);
return &sima->gpd;
}
case SPACE_CLIP: /* Nodes Editor */
@@ -149,15 +176,11 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
if (!track)
return NULL;
- if (ptr)
- RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr);
-
+ if (r_ptr) RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, r_ptr);
return &track->gpd;
}
else {
- if (ptr)
- RNA_id_pointer_create(&clip->id, ptr);
-
+ if (r_ptr) RNA_id_pointer_create(&clip->id, r_ptr);
return &clip->gpd;
}
}
@@ -168,79 +191,102 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
}
}
- /* just fall back on the scene's GP data */
- if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
- return (scene) ? &scene->gpd : NULL;
+ return NULL;
}
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
-bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
+bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ID *screen_id = (ID *)CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
ScrArea *sa = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
- return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr);
+ return ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, r_ptr);
}
/* -------------------------------------------------------- */
/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob)
+bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL);
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/* Get the active Grease Pencil datablock */
+/**
+ * Get the active Grease Pencil datablock
+ * \note This is the original (bmain) copy of the datablock, stored in files.
+ * Do not use for reading evaluated copies of GP Objects data
+ */
bGPdata *ED_gpencil_data_get_active(const bContext *C)
{
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
+/**
+ * Get the evaluated copy of the active Grease Pencil datablock (where applicable)
+ * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP datablock
+ * (i.e. a copy of the active GP datablock for the active object, where modifiers have been
+ * applied). This is needed to correctly work with "Copy-on-Write"
+ * - For all other editors (i.e. "GP Annotations"), this just gives the active datablock
+ * like for ED_gpencil_data_get_active()
+ */
+bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
+{
+ ID *screen_id = (ID *)CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob = CTX_data_active_object(C);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ /* if (ob && ob->type == OB_GPENCIL) BLI_assert(ob_eval->data == DEG_get_evaluated_id(ob->data)); */
+ return ED_gpencil_data_get_active_direct(screen_id, sa, scene_eval, ob_eval);
+}
+
+/* -------------------------------------------------------- */
+
+/**
+ * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers()
+ * is for annotation usage.
+ */
+bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
+{
+ /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data.
+ * Otherwise, the GP datablock is being used for annotations (i.e. everywhere else)
+ */
+ return ((owner_ptr) && (owner_ptr->type != &RNA_Object));
+}
+
/* -------------------------------------------------------- */
// XXX: this should be removed... We really shouldn't duplicate logic like this!
-bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
+bGPdata *ED_gpencil_data_get_active_v3d(ViewLayer *view_layer, View3D *v3d)
{
- Base *base = scene->basact;
+ Base *base = view_layer->basact;
bGPdata *gpd = NULL;
+
/* We have to make sure active object is actually visible and selected, else we must use default scene gpd,
* to be consistent with ED_gpencil_data_get_active's behavior.
*/
-
if (base && TESTBASE(v3d, base)) {
- gpd = base->object->gpd;
+ if (base->object->type == OB_GPENCIL)
+ gpd = base->object->data;
}
- return gpd ? gpd : scene->gpd;
+ return gpd ? gpd : NULL;
}
/* ******************************************************** */
/* Keyframe Indicator Checks */
/* Check whether there's an active GP keyframe on the current frame */
-bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra)
+bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
{
- /* just check both for now... */
- // XXX: this could get confusing (e.g. if only on the object, but other places don't show this)
- if (scene->gpd) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(scene->gpd);
- if (gpl) {
- if (gpl->actframe) {
- // XXX: assumes that frame has been fetched already
- return (gpl->actframe->framenum == cfra);
- }
- else {
- /* XXX: disabled as could be too much of a penalty */
- /* return BKE_gpencil_layer_find_frame(gpl, cfra); */
- }
- }
- }
-
- if (ob && ob->gpd) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->gpd);
+ if (ob && ob->data && (ob->type == OB_GPENCIL)) {
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->data);
if (gpl) {
if (gpl->actframe) {
// XXX: assumes that frame has been fetched already
@@ -279,28 +325,13 @@ bool gp_active_layer_poll(bContext *C)
bool gp_active_brush_poll(bContext *C)
{
ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush = BKE_gpencil_brush_getactive(ts);
-
- return (brush != NULL);
-}
-
-/* poll callback for checking if there is an active palette */
-bool gp_active_palette_poll(bContext *C)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
-
- return (palette != NULL);
-}
-
-/* poll callback for checking if there is an active palette color */
-bool gp_active_palettecolor_poll(bContext *C)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
-
- return (palcolor != NULL);
+ Paint *paint = &ts->gp_paint->paint;
+ if (paint) {
+ return (paint->brush != NULL);
+ }
+ else {
+ return false;
+ }
}
/* ******************************************************** */
@@ -358,22 +389,22 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
/* Create new layer */
/* TODO: have some way of specifying that we don't want this? */
{
- /* active Keying Set */
+ /* "New Layer" entry */
item_tmp.identifier = "__CREATE__";
item_tmp.name = "New Layer";
item_tmp.value = -1;
- item_tmp.icon = ICON_ZOOMIN;
+ item_tmp.icon = ICON_ADD;
RNA_enum_item_add(&item, &totitem, &item_tmp);
/* separator */
RNA_enum_item_add_separator(&item, &totitem);
}
-
+ const int tot = BLI_listbase_count(&gpd->layers);
/* Existing layers */
- for (gpl = gpd->layers.first, i = 0; gpl; gpl = gpl->next, i++) {
+ for (gpl = gpd->layers.last, i = 0; gpl; gpl = gpl->prev, i++) {
item_tmp.identifier = gpl->info;
item_tmp.name = gpl->info;
- item_tmp.value = i;
+ item_tmp.value = tot - i - 1;
if (gpl->flag & GP_LAYER_ACTIVE)
item_tmp.icon = ICON_GREASEPENCIL;
@@ -390,7 +421,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
}
-
/* ******************************************************** */
/* Brush Tool Core */
@@ -404,8 +434,9 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(
* \param x0, y0 The screen-space x and y coordinates of the start of the stroke segment
* \param x1, y1 The screen-space x and y coordinates of the end of the stroke segment
*/
-bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
- int rad, int x0, int y0, int x1, int y1)
+bool gp_stroke_inside_circle(
+ const int mval[2], const int UNUSED(mvalo[2]),
+ int rad, int x0, int y0, int x1, int y1)
{
/* simple within-radius check for now */
const float mval_fl[2] = {mval[0], mval[1]};
@@ -424,7 +455,7 @@ bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
/* Stroke Validity Testing */
/* Check whether given stroke can be edited given the supplied context */
-// XXX: do we need additional flags for screenspace vs dataspace?
+/* TODO: do we need additional flags for screenspace vs dataspace? */
bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
{
/* sanity check */
@@ -434,7 +465,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
/* filter stroke types by flags + spacetype */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D strokes - only in 3D view */
- return (sa->spacetype == SPACE_VIEW3D);
+ return ((sa->spacetype == SPACE_VIEW3D) || (sa->spacetype == SPACE_BUTS));
}
else if (gps->flag & GP_STROKE_2DIMAGE) {
/* Special "image" strokes - only in Image Editor */
@@ -458,59 +489,21 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
}
/* Check whether given stroke can be edited for the current color */
-bool ED_gpencil_stroke_color_use(const bGPDlayer *gpl, const bGPDstroke *gps)
+bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
{
/* check if the color is editable */
- bGPDpalettecolor *palcolor = gps->palcolor;
- if (palcolor != NULL) {
- if (palcolor->flag & PC_COLOR_HIDE)
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ if (gp_style != NULL) {
+ if (gp_style->flag & GP_STYLE_COLOR_HIDE)
return false;
- if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED))
+ if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED))
return false;
}
return true;
}
-/* Get palette color or create a new one */
-bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps)
-{
- bGPDpalette *palette;
- bGPDpalettecolor *palcolor;
-
- if ((gps->palcolor != NULL) && ((gps->flag & GP_STROKE_RECALC_COLOR) == 0))
- return gps->palcolor;
-
- /* get palette */
- palette = BKE_gpencil_palette_getactive(gpd);
- if (palette == NULL) {
- palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
- }
- /* get color */
- palcolor = BKE_gpencil_palettecolor_getbyname(palette, gps->colorname);
- if (palcolor == NULL) {
- if (gps->palcolor == NULL) {
- palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
- /* set to a different color */
- ARRAY_SET_ITEMS(palcolor->color, 1.0f, 0.0f, 1.0f, 0.9f);
- }
- else {
- palcolor = BKE_gpencil_palettecolor_addnew(palette, gps->colorname, true);
- /* set old color and attributes */
- bGPDpalettecolor *gpscolor = gps->palcolor;
- copy_v4_v4(palcolor->color, gpscolor->color);
- copy_v4_v4(palcolor->fill, gpscolor->fill);
- palcolor->flag = gpscolor->flag;
- }
- }
-
- /* clear flag and set pointer */
- gps->flag &= ~GP_STROKE_RECALC_COLOR;
- gps->palcolor = palcolor;
-
- return palcolor;
-}
-
/* ******************************************************** */
/* Space Conversion */
@@ -521,7 +514,6 @@ bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps)
*/
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
- Main *bmain = CTX_data_main(C);
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -538,6 +530,7 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
if (sa->spacetype == SPACE_VIEW3D) {
wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
View3D *v3d = (View3D *)CTX_wm_space_data(C);
RegionView3D *rv3d = ar->regiondata;
@@ -545,11 +538,11 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
view3d_operator_needs_opengl(C);
view3d_region_operator_needs_opengl(win, ar);
- ED_view3d_autodist_init(bmain, scene, ar, v3d, 0);
+ ED_view3d_autodist_init(depsgraph, ar, v3d, 0);
/* for camera view set the subrect */
if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */
+ ED_view3d_calc_camera_border(scene, CTX_data_depsgraph(C), ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */
r_gsc->subrect = &r_gsc->subrect_data;
}
}
@@ -558,11 +551,11 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
/**
* 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
+ * \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)
+void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt)
{
float fpt[3];
@@ -571,9 +564,9 @@ void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *
}
/**
- * Change points position relative to parent object
+ * Change position relative to parent object
*/
-void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
+void gp_apply_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
int i;
@@ -583,7 +576,7 @@ void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
float inverse_diff_mat[4][4];
float fpt[3];
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
for (i = 0; i < gps->totpoints; i++) {
@@ -596,14 +589,14 @@ void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps)
/**
* Change point position relative to parent object
*/
-void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
+void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt)
{
/* undo matrix */
float diff_mat[4][4];
float inverse_diff_mat[4][4];
float fpt[3];
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
@@ -618,12 +611,13 @@ void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt)
*
* \warning This assumes that the caller has already checked whether the stroke in question can be drawn.
*/
-void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
- int *r_x, int *r_y)
+void gp_point_to_xy(
+ const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt,
+ int *r_x, int *r_y)
{
- ARegion *ar = gsc->ar;
- View2D *v2d = gsc->v2d;
- rctf *subrect = gsc->subrect;
+ const ARegion *ar = gsc->ar;
+ const View2D *v2d = gsc->v2d;
+ const rctf *subrect = gsc->subrect;
int xyval[2];
/* sanity checks */
@@ -671,12 +665,13 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
*
* \warning This assumes that the caller has already checked whether the stroke in question can be drawn
*/
-void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
- float *r_x, float *r_y)
+void gp_point_to_xy_fl(
+ const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt,
+ float *r_x, float *r_y)
{
- ARegion *ar = gsc->ar;
- View2D *v2d = gsc->v2d;
- rctf *subrect = gsc->subrect;
+ const ARegion *ar = gsc->ar;
+ const View2D *v2d = gsc->v2d;
+ const rctf *subrect = gsc->subrect;
float xyval[2];
/* sanity checks */
@@ -742,9 +737,8 @@ void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
*/
bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen_co[2], float r_out[3])
{
- View3D *v3d = gsc->sa->spacedata.first;
- RegionView3D *rv3d = gsc->ar->regiondata;
- float *rvec = ED_view3d_cursor3d_get(scene, v3d);
+ const RegionView3D *rv3d = gsc->ar->regiondata;
+ float *rvec = scene->cursor.location;
float ref[3] = {rvec[0], rvec[1], rvec[2]};
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
@@ -768,202 +762,276 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen
}
/**
- * Apply smooth to stroke point
- * \param gps Stroke to smooth
- * \param i Point index
- * \param inf Amount of smoothing to apply
- * \param affect_pressure Apply smoothing to pressure values too?
+ * Convert tGPspoint (temporary 2D/screenspace point data used by GP modal operators)
+ * to 3D coordinates.
+ *
+ * \param point2D: The screenspace 2D point data to convert
+ * \param depth: Depth array (via ED_view3d_autodist_depth())
+ * \param[out] r_out: The resulting 2D point data
*/
-bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
+void gp_stroke_convertcoords_tpoint(
+ Scene *scene, ARegion *ar,
+ Object *ob, bGPDlayer *gpl,
+ const tGPspoint *point2D, float *depth,
+ float r_out[3])
{
- bGPDspoint *pt = &gps->points[i];
- float pressure = 0.0f;
- float sco[3] = {0.0f};
+ ToolSettings *ts = scene->toolsettings;
+ const int mval[2] = {point2D->x, point2D->y};
- /* Do nothing if not enough points to smooth out */
- if (gps->totpoints <= 2) {
- return false;
+ if ((depth != NULL) && (ED_view3d_autodist_simple(ar, mval, r_out, 0, depth))) {
+ /* projecting onto 3D-Geometry
+ * - nothing more needs to be done here, since view_autodist_simple() has already done it
+ */
}
-
- /* Only affect endpoints by a fraction of the normal strength,
- * to prevent the stroke from shrinking too much
- */
- if ((i == 0) || (i == gps->totpoints - 1)) {
- inf *= 0.1f;
- }
-
- /* Compute smoothed coordinate by taking the ones nearby */
- /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
- {
- // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
- const int steps = 2;
- const float average_fac = 1.0f / (float)(steps * 2 + 1);
- int step;
-
- /* add the point itself */
- madd_v3_v3fl(sco, &pt->x, average_fac);
-
- if (affect_pressure) {
- pressure += pt->pressure * average_fac;
+ else {
+ float mval_f[2] = {(float)point2D->x, (float)point2D->y};
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float zfac;
+
+ /* Current method just converts each point in screen-coordinates to
+ * 3D-coordinates using the 3D-cursor as reference.
+ */
+ ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, rvec);
+ zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(r_out, rvec, dvec);
+ }
+ else {
+ zero_v3(r_out);
}
+ }
+}
- /* n-steps before/after current point */
- // XXX: review how the endpoints are treated by this algorithm
- // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
- for (step = 1; step <= steps; step++) {
- bGPDspoint *pt1, *pt2;
- int before = i - step;
- int after = i + step;
-
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
- pt1 = &gps->points[before];
- pt2 = &gps->points[after];
-
- /* add both these points to the average-sum (s += p[i]/n) */
- madd_v3_v3fl(sco, &pt1->x, average_fac);
- madd_v3_v3fl(sco, &pt2->x, average_fac);
-
-#if 0
- /* XXX: Disabled because get weird result */
- /* do pressure too? */
- if (affect_pressure) {
- pressure += pt1->pressure * average_fac;
- pressure += pt2->pressure * average_fac;
+/**
+ * Get drawing reference point for conversion or projection of the stroke
+ * \param[out] r_vec : Reference point found
+ */
+void ED_gp_get_drawing_reference(
+ const Scene *scene, const Object *ob, bGPDlayer *UNUSED(gpl),
+ char align_flag, float r_vec[3])
+{
+ const float *fp = scene->cursor.location;
+
+ /* if using a gpencil object at cursor mode, can use the location of the object */
+ if (align_flag & GP_PROJECT_VIEWSPACE) {
+ if (ob && (ob->type == OB_GPENCIL)) {
+ /* fallback (no strokes) - use cursor or object location */
+ if (align_flag & GP_PROJECT_CURSOR) {
+ /* use 3D-cursor */
+ copy_v3_v3(r_vec, fp);
+ }
+ else {
+ /* use object location */
+ copy_v3_v3(r_vec, ob->obmat[3]);
}
-#endif
}
}
-
- /* Based on influence factor, blend between original and optimal smoothed coordinate */
- interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
-
-#if 0
- /* XXX: Disabled because get weird result */
- if (affect_pressure) {
- pt->pressure = pressure;
+ else {
+ /* use 3D-cursor */
+ copy_v3_v3(r_vec, fp);
}
-#endif
-
- return true;
}
+
/**
-* Apply smooth for strength to stroke point
-* \param gps Stroke to smooth
-* \param i Point index
-* \param inf Amount of smoothing to apply
-*/
-bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf)
+ * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset
+ */
+void ED_gp_project_stroke_to_plane(
+ const Object *ob, const RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis)
{
- bGPDspoint *ptb = &gps->points[i];
-
- /* Do nothing if not enough points */
- if (gps->totpoints <= 2) {
- return false;
+ float plane_normal[3];
+ float vn[3];
+
+ float ray[3];
+ float rpoint[3];
+
+ /* normal vector for a plane locked to axis */
+ zero_v3(plane_normal);
+ if (axis < 0) {
+ /* if the axis is not locked, need a vector to the view direction
+ * in order to get the right size of the stroke.
+ */
+ ED_view3d_global_to_vector(rv3d, origin, plane_normal);
+ }
+ else {
+ plane_normal[axis] = 1.0f;
+ /* if object, apply object rotation */
+ if (ob && (ob->type == OB_GPENCIL)) {
+ mul_mat3_m4_v3(ob->obmat, plane_normal);
+ }
}
- /* Compute theoretical optimal value using distances */
- bGPDspoint *pta, *ptc;
- int before = i - 1;
- int after = i + 1;
-
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
- pta = &gps->points[before];
- ptc = &gps->points[after];
+ /* Reproject the points in the plane */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
- /* the optimal value is the corresponding to the interpolation of the strength
- * at the distance of point b
- */
- const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
+ /* get a vector from the point with the current view direction of the viewport */
+ ED_view3d_global_to_vector(rv3d, &pt->x, vn);
- /* Based on influence factor, blend between original and optimal */
- ptb->strength = (1.0f - inf) * ptb->strength + inf * optimal;
+ /* calculate line extreme point to create a ray that cross the plane */
+ mul_v3_fl(vn, -50.0f);
+ add_v3_v3v3(ray, &pt->x, vn);
- return true;
+ /* if the line never intersect, the point is not changed */
+ if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
+ copy_v3_v3(&pt->x, rpoint);
+ }
+ }
}
/**
-* Apply smooth for thickness to stroke point (use pressure)
-* \param gps Stroke to smooth
-* \param i Point index
-* \param inf Amount of smoothing to apply
-*/
-bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf)
+ * Reproject given point to a plane locked to axis to avoid stroke offset
+ * \param[in, out] pt : Point to affect
+ */
+void ED_gp_project_point_to_plane(
+ const Object *ob, const RegionView3D *rv3d, const float origin[3], const int axis, bGPDspoint *pt)
{
- bGPDspoint *ptb = &gps->points[i];
-
- /* Do nothing if not enough points */
- if (gps->totpoints <= 2) {
- return false;
+ float plane_normal[3];
+ float vn[3];
+
+ float ray[3];
+ float rpoint[3];
+
+ /* normal vector for a plane locked to axis */
+ zero_v3(plane_normal);
+ if (axis < 0) {
+ /* if the axis is not locked, need a vector to the view direction
+ * in order to get the right size of the stroke.
+ */
+ ED_view3d_global_to_vector(rv3d, origin, plane_normal);
+ }
+ else {
+ plane_normal[axis] = 1.0f;
+ /* if object, apply object rotation */
+ if (ob && (ob->type == OB_GPENCIL)) {
+ mul_mat3_m4_v3(ob->obmat, plane_normal);
+ }
}
- /* Compute theoretical optimal value using distances */
- bGPDspoint *pta, *ptc;
- int before = i - 1;
- int after = i + 1;
-
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
- pta = &gps->points[before];
- ptc = &gps->points[after];
- /* the optimal value is the corresponding to the interpolation of the pressure
- * at the distance of point b
- */
- float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- float optimal = (1.0f - fac) * pta->pressure + fac * ptc->pressure;
+ /* Reproject the points in the plane */
+ /* get a vector from the point with the current view direction of the viewport */
+ ED_view3d_global_to_vector(rv3d, &pt->x, vn);
- /* Based on influence factor, blend between original and optimal */
- ptb->pressure = (1.0f - inf) * ptb->pressure + inf * optimal;
+ /* calculate line extrem point to create a ray that cross the plane */
+ mul_v3_fl(vn, -50.0f);
+ add_v3_v3v3(ray, &pt->x, vn);
- return true;
+ /* if the line never intersect, the point is not changed */
+ if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) {
+ copy_v3_v3(&pt->x, rpoint);
+ }
}
+/* ******************************************************** */
+/* Stroke Operations */
+// XXX: Check if these functions duplicate stuff in blenkernel, and/or whether we should just deduplicate
+
/**
* Subdivide a stroke once, by adding a point half way between each pair of existing points
- * \param gps Stroke data
- * \param new_totpoints Total number of points (after subdividing)
+ * \param gps: Stroke data
+ * \param subdivide: Number of times to subdivide
*/
-void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
+void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
{
- /* Move points towards end of enlarged points array to leave space for new points */
- int y = 1;
- for (int i = gps->totpoints - 1; i > 0; i--) {
- gps->points[new_totpoints - y] = gps->points[i];
- y += 2;
- }
+ bGPDspoint *temp_points;
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ /* loop as many times as levels */
+ for (int s = 0; s < subdivide; s++) {
+ totnewpoints = gps->totpoints - 1;
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrays */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* move points from last to first to new place */
+ i2 = gps->totpoints - 1;
+ for (int i = oldtotpoints - 1; i > 0; i--) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+ pt_final->uv_fac = pt->uv_fac;
+ pt_final->uv_rot = pt->uv_rot;
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert = &gps->dvert[i];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ }
- /* Create interpolated points */
- for (int i = 0; i < new_totpoints - 1; i += 2) {
- bGPDspoint *prev = &gps->points[i];
- bGPDspoint *pt = &gps->points[i + 1];
- bGPDspoint *next = &gps->points[i + 2];
+ i2 -= 2;
+ }
+ /* interpolate mid points */
+ i2 = 1;
+ for (int i = 0; i < oldtotpoints - 1; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ /* add a half way point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+ pt_final->uv_fac = interpf(pt->uv_fac, next->uv_fac, 0.5f);
+ pt_final->uv_rot = interpf(pt->uv_rot, next->uv_rot, 0.5f);
+
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert_final = &gps->dvert[i2];
+ dvert_final->totweight = 0;
+ dvert_final->dw = NULL;
+ }
- /* Interpolate all values */
- interp_v3_v3v3(&pt->x, &prev->x, &next->x, 0.5f);
+ i2 += 2;
+ }
- pt->pressure = interpf(prev->pressure, next->pressure, 0.5f);
- pt->strength = interpf(prev->strength, next->strength, 0.5f);
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- pt->time = interpf(prev->time, next->time, 0.5f);
- }
+ MEM_SAFE_FREE(temp_points);
- /* Update to new total number of points */
- gps->totpoints = new_totpoints;
+ /* move points to smooth stroke */
+ /* duplicate points in a temp area with the new subdivide data */
+ temp_points = MEM_dupallocN(gps->points);
+
+ /* extreme points are not changed */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i + 1];
+
+ /* move point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ }
}
/**
* Add randomness to stroke
- * \param gps Stroke data
- * \param brush Brush data
+ * \param gps: Stroke data
+ * \param brush: Brush data
*/
-void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
+void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, RNG *rng)
{
bGPDspoint *pt1, *pt2, *pt3;
float v1[3];
@@ -993,13 +1061,13 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
normalize_v3(ortho);
/* Read all points and apply shift vector (first and last point not modified) */
- for (int i = 1; i < gps->totpoints - 1; ++i) {
+ for (int i = 1; i < gps->totpoints - 1; i++) {
bGPDspoint *pt = &gps->points[i];
/* get vector with shift (apply a division because random is too sensitive */
- const float fac = BLI_frand() * (brush->draw_random_sub / 10.0f);
+ const float fac = BLI_rng_get_float(rng) * (brush->gpencil_settings->draw_random_sub / 10.0f);
float svec[3];
copy_v3_v3(svec, ortho);
- if (BLI_frand() > 0.5f) {
+ if (BLI_rng_get_float(rng) > 0.5f) {
mul_v3_fl(svec, -fac);
}
else {
@@ -1009,31 +1077,46 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
/* apply shift */
add_v3_v3(&pt->x, svec);
}
-
}
+
+/* ******************************************************** */
+/* Layer Parenting - Compute Parent Transforms */
+
/* calculate difference matrix */
-void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4])
+void ED_gpencil_parent_location(
+ const Depsgraph *depsgraph, Object *obact, bGPdata *UNUSED(gpd),
+ bGPDlayer *gpl, float diff_mat[4][4])
{
- Object *ob = gpl->parent;
-
- if (ob == NULL) {
+ Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obact) : obact;
+ Object *obparent = gpl->parent;
+ Object *obparent_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obparent) : obparent;
+
+ /* if not layer parented, try with object parented */
+ if (obparent_eval == NULL) {
+ if (ob_eval != NULL) {
+ if (ob_eval->type == OB_GPENCIL) {
+ copy_m4_m4(diff_mat, ob_eval->obmat);
+ return;
+ }
+ }
+ /* not gpencil object */
unit_m4(diff_mat);
return;
}
else {
if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
- mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse);
+ mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse);
return;
}
else if (gpl->partype == PARBONE) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, gpl->parsubstr);
+ bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr);
if (pchan) {
float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, ob->obmat, pchan->pose_mat);
+ mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat);
mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse);
}
else {
- mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse); /* if bone not found use object (armature) */
+ mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); /* if bone not found use object (armature) */
}
return;
}
@@ -1044,7 +1127,7 @@ void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4])
}
/* reset parent matrix for all layers */
-void ED_gpencil_reset_layers_parent(bGPdata *gpd)
+void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
{
bGPDspoint *pt;
int i;
@@ -1069,7 +1152,7 @@ void ED_gpencil_reset_layers_parent(bGPdata *gpd)
/* only redo if any change */
if (!equals_m4m4(gpl->inverse, cur_mat)) {
/* first apply current transformation to all strokes */
- ED_gpencil_parent_location(gpl, diff_mat);
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
@@ -1084,90 +1167,733 @@ void ED_gpencil_reset_layers_parent(bGPdata *gpd)
}
}
/* ******************************************************** */
-bool ED_gpencil_stroke_minmax(
- const bGPDstroke *gps, const bool use_select,
- float r_min[3], float r_max[3])
+/* GP Object Stuff */
+
+/* Helper function to create new OB_GPENCIL Object */
+Object *ED_add_gpencil_object(bContext *C, Scene *UNUSED(scene), const float loc[3])
{
- const bGPDspoint *pt;
- int i;
- bool changed = false;
+ float rot[3] = {0.0f};
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {;
- minmax_v3v3_v3(r_min, r_max, &pt->x);
- changed = true;
+ Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false);
+
+ /* define size */
+ BKE_object_obdata_size_init(ob, GP_OBGPENCIL_DEFAULT_SIZE);
+ /* create default brushes and colors */
+ ED_gpencil_add_defaults(C);
+
+ return ob;
+}
+
+/* Helper function to create default colors and drawing brushes */
+void ED_gpencil_add_defaults(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ /* first try to reuse default material */
+ if (ob->actcol > 0) {
+ Material *ma = give_current_material(ob, ob->actcol);
+ if ((ma) && (ma->gp_style == NULL)) {
+ BKE_material_init_gpencil_settings(ma);
}
}
- return changed;
+
+ /* ensure color exist */
+ BKE_gpencil_material_ensure(bmain, ob);
+
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
+ Paint *paint = &ts->gp_paint->paint;
+ /* if not exist, create a new one */
+ if (paint->brush == NULL) {
+ /* create new brushes */
+ BKE_brush_gpencil_presets(C);
+ }
+
+ /* ensure multiframe falloff curve */
+ if (ts->gp_sculpt.cur_falloff == NULL) {
+ ts->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_falloff_curve = ts->gp_sculpt.cur_falloff;
+ curvemapping_initialize(gp_falloff_curve);
+ curvemap_reset(gp_falloff_curve->cm,
+ &gp_falloff_curve->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+ }
}
-/* Dynamic Enums of GP Brushes */
-const EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free)
+/* ******************************************************** */
+/* Vertex Groups */
+
+/* assign points to vertex group */
+void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPDbrush *brush;
- EnumPropertyItem *item = NULL, item_tmp = { 0 };
- int totitem = 0;
- int i = 0;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
- if (ELEM(NULL, C, ts)) {
- return DummyRNA_DEFAULT_items;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ 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;
+
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* verify the weight array is created */
+ BKE_gpencil_dvert_ensure(gps);
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+ if (pt->flag & GP_SPOINT_SELECT) {
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = weight;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
}
+ CTX_DATA_END;
+}
- /* Existing brushes */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next, i++) {
- item_tmp.identifier = brush->info;
- item_tmp.name = brush->info;
- item_tmp.value = i;
+/* remove points from vertex group */
+void ED_gpencil_vgroup_remove(bContext *C, Object *ob)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
- if (brush->flag & GP_BRUSH_ACTIVE)
- item_tmp.icon = ICON_BRUSH_DATA;
- else
- item_tmp.icon = ICON_NONE;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- RNA_enum_item_add(&item, &totitem, &item_tmp);
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (gps->dvert == NULL) {
+ continue;
+ }
+ MDeformVert *dvert = &gps->dvert[i];
+
+ if ((pt->flag & GP_SPOINT_SELECT) && (dvert->totweight > 0)) {
+ MDeformWeight *dw = defvert_find_index(dvert, def_nr);
+ if (dw != NULL) {
+ defvert_remove_group(dvert, dw);
+ }
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
}
+ CTX_DATA_END;
+}
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
+/* select points of vertex group */
+void ED_gpencil_vgroup_select(bContext *C, Object *ob)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
- return item;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ 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;
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (gps->dvert == NULL) {
+ continue;
+ }
+ MDeformVert *dvert = &gps->dvert[i];
+
+ if (defvert_find_index(dvert, def_nr) != NULL) {
+ pt->flag |= GP_SPOINT_SELECT;
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
}
-/* Dynamic Enums of GP Palettes */
-const EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free)
+/* unselect points of vertex group */
+void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
{
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDpalette *palette;
- EnumPropertyItem *item = NULL, item_tmp = { 0 };
- int totitem = 0;
- int i = 0;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const int def_nr = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, def_nr))
+ return;
- if (ELEM(NULL, C, gpd)) {
- return DummyRNA_DEFAULT_items;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *init_gpf = gpl->actframe;
+ bGPDstroke *gps = NULL;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL)
+ continue;
+
+ 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;
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ if (gps->dvert == NULL) {
+ continue;
+ }
+ MDeformVert *dvert = &gps->dvert[i];
+
+ if (defvert_find_index(dvert, def_nr) != NULL) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+ }
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
+ break;
+ }
+ }
}
+ CTX_DATA_END;
+}
- /* Existing palettes */
- for (palette = gpd->palettes.first; palette; palette = palette->next, i++) {
- item_tmp.identifier = palette->info;
- item_tmp.name = palette->info;
- item_tmp.value = i;
+/* ******************************************************** */
+/* Cursor drawing */
- if (palette->flag & PL_PALETTE_ACTIVE)
- item_tmp.icon = ICON_COLOR;
- else
- item_tmp.icon = ICON_NONE;
+/* check if cursor is in drawing region */
+static bool gp_check_cursor_region(bContext *C, int mval[2])
+{
+ ARegion *ar = CTX_wm_region(C);
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob = CTX_data_active_object(C);
- RNA_enum_item_add(&item, &totitem, &item_tmp);
+ if ((ob == NULL) ||
+ (!ELEM(ob->mode, OB_MODE_GPENCIL_PAINT, OB_MODE_GPENCIL_SCULPT, OB_MODE_GPENCIL_WEIGHT)))
+ {
+ return false;
}
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
+ /* TODO: add more spacetypes */
+ if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
+ return false;
+ }
+ if ((ar) && (ar->regiontype != RGN_TYPE_WINDOW)) {
+ return false;
+ }
+ else if (ar) {
+ return BLI_rcti_isect_pt_v(&ar->winrct, mval);
+ }
+ else {
+ return false;
+ }
+}
- return item;
+/* draw eraser cursor */
+void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y)
+{
+ short radius = (short)brush->size;
+
+ GPUVertFormat *format = immVertexFormat();
+ const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ immUniformColor4ub(255, 100, 100, 20);
+ imm_draw_circle_fill_2d(shdr_pos, x, y, radius, 40);
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 12.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ imm_draw_circle_wire_2d(
+ shdr_pos, x, y, radius,
+ /* XXX Dashed shader gives bad results with sets of small segments currently,
+ * temp hack around the issue. :( */
+ max_ii(8, radius / 2)); /* was fixed 40 */
+
+ immUnbindProgram();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+}
+
+/* Helper callback for drawing the cursor itself */
+static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ GP_Sculpt_Data *gp_brush = NULL;
+ Brush *brush = NULL;
+ Material *ma = NULL;
+ MaterialGPencilStyle *gp_style = NULL;
+ int *last_mouse_position = customdata;
+
+ if ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)) {
+ gp_brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ gp_brush = &gset->brush[gset->brushtype];
+ }
+
+ /* default radius and color */
+ float color[3] = {1.0f, 1.0f, 1.0f};
+ float darkcolor[3];
+ float radius = 3.0f;
+
+ int mval[2] = {x, y};
+ /* check if cursor is in drawing region and has valid datablock */
+ if ((!gp_check_cursor_region(C, mval)) || (gpd == NULL)) {
+ return;
+ }
+
+ /* for paint use paint brush size and color */
+ if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
+ brush = scene->toolsettings->gp_paint->paint.brush;
+ /* while drawing hide */
+ if ((gpd->runtime.sbuffer_size > 0) &&
+ (brush) && ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0))
+ {
+ return;
+ }
+
+ if (brush) {
+ if ((brush->gpencil_settings->flag & GP_BRUSH_ENABLE_CURSOR) == 0) {
+ return;
+ }
+
+ /* eraser has special shape and use a different shader program */
+ if (brush->gpencil_tool == GPAINT_TOOL_ERASE) {
+ ED_gpencil_brush_draw_eraser(brush, x, y);
+ return;
+ }
+
+ /* get current drawing color */
+ ma = BKE_gpencil_get_material_from_brush(brush);
+ if (ma == NULL) {
+ BKE_gpencil_material_ensure(bmain, ob);
+ /* assign the first material to the brush */
+ ma = give_current_material(ob, 1);
+ brush->gpencil_settings->material = ma;
+ }
+ gp_style = ma->gp_style;
+
+ /* after some testing, display the size of the brush is not practical because
+ * is too disruptive and the size of cursor does not change with zoom factor.
+ * The decision was to use a fix size, instead of brush->thickness value.
+ */
+ if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
+ (brush->gpencil_tool == GPAINT_TOOL_DRAW))
+ {
+ radius = 2.0f;
+ copy_v3_v3(color, gp_style->stroke_rgba);
+ }
+ else {
+ radius = 5.0f;
+ copy_v3_v3(color, brush->add_col);
+ }
+ }
+ else {
+ return;
+ }
+ }
+
+ /* for sculpt use sculpt brush size */
+ if (GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd)) {
+ if (gp_brush) {
+ if ((gp_brush->flag & GP_SCULPT_FLAG_ENABLE_CURSOR) == 0) {
+ return;
+ }
+
+ radius = gp_brush->size;
+ if (gp_brush->flag & (GP_SCULPT_FLAG_INVERT | GP_SCULPT_FLAG_TMP_INVERT)) {
+ copy_v3_v3(color, gp_brush->curcolor_sub);
+ }
+ else {
+ copy_v3_v3(color, gp_brush->curcolor_add);
+ }
+ }
+ }
+
+ /* draw icon */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ /* Inner Ring: Color from UI panel */
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+ if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
+ ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
+ (brush->gpencil_tool == GPAINT_TOOL_DRAW))
+ {
+ imm_draw_circle_fill_2d(pos, x, y, radius, 40);
+ }
+ else {
+ imm_draw_circle_wire_2d(pos, x, y, radius, 40);
+ }
+
+ /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
+ mul_v3_v3fl(darkcolor, color, 0.40f);
+ immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
+ imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+
+ /* Draw line for lazy mouse */
+ if ((last_mouse_position) &&
+ (brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP))
+ {
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ copy_v3_v3(color, brush->add_col);
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, y);
+ immVertex2f(
+ pos,
+ last_mouse_position[0] + ar->winrct.xmin,
+ last_mouse_position[1] + ar->winrct.ymin);
+ immEnd();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
+
+ immUnbindProgram();
+}
+
+/* Turn brush cursor in on/off */
+void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
+{
+ Scene *scene = CTX_data_scene(C);
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ int *lastpost = customdata;
+
+ if (gset->paintcursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ gset->paintcursor = NULL;
+ }
+ else if (enable) {
+ /* in some situations cursor could be duplicated, so it is better disable first if exist */
+ if (gset->paintcursor) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ gset->paintcursor = NULL;
+ }
+ /* enable cursor */
+ gset->paintcursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ NULL,
+ gp_brush_drawcursor,
+ (lastpost) ? customdata : NULL);
+ }
+}
+
+/* verify if is using the right brush */
+static void gpencil_verify_brush_type(bContext *C, int newmode)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+
+ switch (newmode) {
+ case OB_MODE_GPENCIL_SCULPT:
+ gset->flag &= ~GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
+ if ((gset->brushtype < 0) || (gset->brushtype >= GP_SCULPT_TYPE_WEIGHT)) {
+ gset->brushtype = GP_SCULPT_TYPE_PUSH;
+ }
+ break;
+ case OB_MODE_GPENCIL_WEIGHT:
+ gset->flag |= GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
+ if ((gset->weighttype < GP_SCULPT_TYPE_WEIGHT) || (gset->weighttype >= GP_SCULPT_TYPE_MAX)) {
+ gset->weighttype = GP_SCULPT_TYPE_WEIGHT;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* set object modes */
+void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
+{
+ if (!gpd) {
+ return;
+ }
+
+ switch (newmode) {
+ case OB_MODE_GPENCIL_EDIT:
+ gpd->flag |= GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ break;
+ case OB_MODE_GPENCIL_PAINT:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag |= GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ case OB_MODE_GPENCIL_SCULPT:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag |= GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ gpencil_verify_brush_type(C, OB_MODE_GPENCIL_SCULPT);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ case OB_MODE_GPENCIL_WEIGHT:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag |= GP_DATA_STROKE_WEIGHTMODE;
+ gpencil_verify_brush_type(C, OB_MODE_GPENCIL_WEIGHT);
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ default:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ break;
+ }
+}
+
+/* helper to convert 2d to 3d for simple drawing buffer */
+static void gpencil_stroke_convertcoords(ARegion *ar, const tGPspoint *point2D, float origin[3], float out[3])
+{
+ float mval_f[2] = { (float)point2D->x, (float)point2D->y };
+ float mval_prj[2];
+ float rvec[3], dvec[3];
+ float zfac;
+
+ copy_v3_v3(rvec, origin);
+
+ zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL);
+
+ if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(out, rvec, dvec);
+ }
+ else {
+ zero_v3(out);
+ }
+}
+
+/* convert 2d tGPspoint to 3d bGPDspoint */
+void ED_gpencil_tpoint_to_point(ARegion *ar, float origin[3], const tGPspoint *tpt, bGPDspoint *pt)
+{
+ float p3d[3];
+ /* conversion to 3d format */
+ gpencil_stroke_convertcoords(ar, tpt, origin, p3d);
+ copy_v3_v3(&pt->x, p3d);
+
+ pt->pressure = tpt->pressure;
+ pt->strength = tpt->strength;
+ pt->uv_fac = tpt->uv_fac;
+ pt->uv_rot = tpt->uv_rot;
+}
+
+/* texture coordinate utilities */
+void ED_gpencil_calc_stroke_uv(Object *ob, bGPDstroke *gps)
+{
+ if (gps == NULL) {
+ return;
+ }
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ float pixsize;
+ if (gp_style) {
+ pixsize = gp_style->texture_pixsize / 1000000.0f;
+ }
+ else {
+ /* use this value by default */
+ pixsize = 0.0001f;
+ }
+ pixsize = MAX2(pixsize, 0.0000001f);
+
+ bGPDspoint *pt = NULL;
+ bGPDspoint *ptb = NULL;
+ int i;
+ float totlen = 0.0f;
+
+ /* first read all points and calc distance */
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ /* first point */
+ if (i == 0) {
+ pt->uv_fac = 0.0f;
+ continue;
+ }
+
+ ptb = &gps->points[i - 1];
+ totlen += len_v3v3(&pt->x, &ptb->x) / pixsize;
+ pt->uv_fac = totlen;
+ }
+
+ /* normalize the distance using a factor */
+ float factor;
+
+ /* if image, use texture width */
+ if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) &&
+ (gp_style->sima))
+ {
+ factor = gp_style->sima->gen_x;
+ }
+ else if (totlen == 0) {
+ return;
+ }
+ else {
+ factor = totlen;
+ }
+
+ for (i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->uv_fac /= factor;
+ }
+}
+
+/* recalc uv for any stroke using the material */
+void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
+{
+ Material *gps_ma = NULL;
+ /* read all strokes */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ if (gpd == NULL) {
+ continue;
+ }
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl)) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if it is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ gps_ma = give_current_material(ob, gps->mat_nr + 1);
+ /* update */
+ if ((gps_ma) && (gps_ma == mat)) {
+ ED_gpencil_calc_stroke_uv(ob, gps);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
/* ******************************************************** */
diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h
index ac896216e51..e2e110ffc31 100644
--- a/source/blender/editors/include/BIF_gl.h
+++ b/source/blender/editors/include/BIF_gl.h
@@ -36,45 +36,6 @@
#include "GPU_glew.h"
#include "BLI_utildefines.h"
-/*
- * these should be phased out. cpack should be replaced in
- * code with calls to glColor3ub. - zr
- */
-/*
- *
- * This define converts a numerical value to the equivalent 24-bit
- * color, while not being endian-sensitive. On little-endians, this
- * is the same as doing a 'naive' indexing, on big-endian, it is not!
- * */
-void cpack(unsigned int x);
-
-#ifdef WITH_GL_PROFILE_COMPAT
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
-# define glMultMatrixf(x) \
- glMultMatrixf(_Generic((x), \
- float *: (float *)(x), \
- float [16]: (float *)(x), \
- float (*)[4]: (float *)(x), \
- float [4][4]: (float *)(x), \
- const float *: (float *)(x), \
- const float [16]: (float *)(x), \
- const float (*)[4]: (float *)(x), \
- const float [4][4]: (float *)(x)) \
-)
-# define glLoadMatrixf(x) \
- glLoadMatrixf(_Generic((x), \
- float *: (float *)(x), \
- float [16]: (float *)(x), \
- float (*)[4]: (float *)(x), \
- float [4][4]: (float *)(x)) \
-)
-#else
-# define glMultMatrixf(x) glMultMatrixf((float *)(x))
-# define glLoadMatrixf(x) glLoadMatrixf((float *)(x))
-#endif /* C11 */
-#endif /* WITH_GL_PROFILE_COMPAT */
-
-
/* hacking pointsize and linewidth */
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define glPointSize(f) glPointSize(U.pixelsize * _Generic((f), double: (float)(f), default: (f)))
@@ -86,18 +47,4 @@ void cpack(unsigned int x);
#define GLA_PIXEL_OFS 0.375f
-
-BLI_INLINE void glTranslate3iv(const int vec[3]) { glTranslatef(UNPACK3_EX((const float), vec, )); }
-BLI_INLINE void glTranslate2iv(const int vec[2]) { glTranslatef(UNPACK2_EX((const float), vec, ), 0.0f); }
-BLI_INLINE void glTranslate3fv(const float vec[3]) { glTranslatef(UNPACK3(vec)); }
-BLI_INLINE void glTranslate2fv(const float vec[2]) { glTranslatef(UNPACK2(vec), 0.0f); }
-
-BLI_INLINE void glScale3iv(const int vec[3]) { glTranslatef(UNPACK3_EX((const float), vec, )); }
-BLI_INLINE void glScale2iv(const int vec[2]) { glTranslatef(UNPACK2_EX((const float), vec, ), 0.0f); }
-BLI_INLINE void glScale3fv(const float vec[3]) { glScalef(UNPACK3(vec)); }
-BLI_INLINE void glScale2fv(const float vec[2]) { glScalef(UNPACK2(vec), 0.0); }
-
-/* v2 versions don't make much sense for rotation */
-BLI_INLINE void glRotate3fv(const float angle, const float vec[3]) { glRotatef(angle, UNPACK3(vec)); }
-
#endif /* #ifdef __BIF_GL_H__ */
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index efd66dd79cf..863d817d19a 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -38,56 +38,14 @@ struct bContext;
struct ColorManagedViewSettings;
struct ColorManagedDisplaySettings;
-void fdrawbezier(float vec[4][3]);
-void fdrawline(float x1, float y1, float x2, float y2);
-void fdrawbox(float x1, float y1, float x2, float y2);
-void sdrawline(int x1, int y1, int x2, int y2);
-#if 0
-void sdrawtri(int x1, int y1, int x2, int y2);
-void sdrawtrifill(int x1, int y1, int x2, int y2);
-#endif
-void sdrawbox(int x1, int y1, int x2, int y2);
-
-void sdrawXORline(int x0, int y0, int x1, int y1);
-void sdrawXORline4(int nr, int x0, int y0, int x1, int y1);
-
-void fdrawXORellipse(float xofs, float yofs, float hw, float hh);
-void fdrawXORcirc(float xofs, float yofs, float rad);
-
-void fdrawcheckerboard(float x1, float y1, float x2, float y2);
-
-/* OpenGL stipple defines */
-extern const unsigned char stipple_halftone[128];
-extern const unsigned char stipple_quarttone[128];
-extern const unsigned char stipple_diag_stripes_pos[128];
-extern const unsigned char stipple_diag_stripes_neg[128];
-extern const unsigned char stipple_checker_8px[128];
-
-/**
- * Draw a lined (non-looping) arc with the given
- * \a radius, starting at angle \a start and arcing
- * through \a angle. The arc is centered at the origin
- * and drawn in the XY plane.
+/* A few functions defined here are being DEPRECATED for Blender 2.8
*
- * \param start The initial angle (in radians).
- * \param angle The length of the arc (in radians).
- * \param radius The arc radius.
- * \param nsegments The number of segments to use in drawing the arc.
- */
-void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments);
-
-/**
- * Draw a filled arc with the given \a radius,
- * starting at angle \a start and arcing through
- * \a angle. The arc is centered at the origin
- * and drawn in the XY plane.
+ * Do not use them in new code, and you are encouraged to
+ * convert existing code to draw without these.
*
- * \param start The initial angle (in radians).
- * \param angle The length of the arc (in radians).
- * \param radius The arc radius.
- * \param nsegments The number of segments to use in drawing the arc.
+ * These will be deleted before we ship 2.8!
+ * - merwin
*/
-void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments);
/**
* Returns a float value as obtained by glGetFloatv.
@@ -109,88 +67,46 @@ int glaGetOneInt(int param);
*/
void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y);
-/**
- * Functions like a limited glDrawPixels, except ensures that
- * the image is displayed onscreen even if the \a x and \a y
- * coordinates for would be clipped. The routine respects the
- * glPixelZoom values, pixel unpacking parameters are _not_
- * respected.
- *
- * \attention This routine makes many assumptions: the rect data
- * is expected to be in RGBA unsigned byte format, the coordinate
- * (GLA_PIXEL_OFS, GLA_PIXEL_OFS) is assumed to be within the view frustum,
- * and the modelview and projection matrices are assumed to define a
- * 1-to-1 mapping to screen space.
- * \attention Furthermore, in the case of zoomed or unpixel aligned
- * images extending outside the view frustum, but still within the
- * window, some portion of the image may be visible left and/or
- * below of the given \a x and \a y coordinates. It is recommended
- * to use the glScissor functionality if images are to be drawn
- * with an inset view matrix.
- */
-void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect);
+typedef struct IMMDrawPixelsTexState {
+ struct GPUShader *shader;
+ unsigned int pos;
+ unsigned int texco;
+ bool do_shader_unbind;
+} IMMDrawPixelsTexState;
+
+/* To be used before calling immDrawPixelsTex
+ * Default shader is GPU_SHADER_2D_IMAGE_COLOR
+ * Returns a shader to be able to set uniforms */
+IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
/**
- * glaDrawPixelsTex - Functions like a limited glDrawPixels, but actually draws the
+ * immDrawPixelsTex - Functions like a limited glDrawPixels, but actually draws the
* image using textures, which can be tremendously faster on low-end
* cards, and also avoids problems with the raster position being
- * clipped when offscreen. The routine respects the glPixelZoom values,
- * pixel unpacking parameters are _not_ respected.
+ * clipped when offscreen. Pixel unpacking parameters and
+ * the glPixelZoom values are _not_ respected.
+ *
+ * \attention Use immDrawPixelsTexSetup before calling this function.
*
* \attention This routine makes many assumptions: the rect data
* is expected to be in RGBA byte or float format, and the
* modelview and projection matrices are assumed to define a
* 1-to-1 mapping to screen space.
*/
-
-void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect);
-void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect,
- float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y);
-
-/**
- * glaDrawPixelsAuto - Switches between texture or pixel drawing using UserDef.
- * only RGBA
- * needs glaDefine2DArea to be set.
- */
-void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect);
-void glaDrawPixelsAuto_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect,
- float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y);
-
-
-void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY);
-void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY,
- float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y);
-
-/* 2D Drawing Assistance */
-
-/** Define a 2D area (viewport, scissor, matrices) for OpenGL rendering.
- *
- * glaDefine2DArea and glaBegin2DDraw set up an OpenGL state appropriate
- * for drawing using both vertex (Vertex, etc) and raster (RasterPos, Rect)
- * commands. All coordinates should be at integer positions. There is little
- * to no reason to use glVertex2f etc. functions during 2D rendering, and
- * thus no reason to +-0.5 the coordinates or perform other silly
- * tricks.
- *
- * \param screen_rect The screen rectangle to be defined for 2D drawing.
- */
-void glaDefine2DArea(struct rcti *screen_rect);
-
-typedef struct gla2DDrawInfo gla2DDrawInfo;
-
-/* UNUSED */
-#if 0
-
-gla2DDrawInfo *glaBegin2DDraw(struct rcti *screen_rect, struct rctf *world_rect);
-void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y);
-void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]);
-
-void glaEnd2DDraw(gla2DDrawInfo *di);
-
-/** Adjust the transformation mapping of a 2d area */
-void gla2DGetMap(gla2DDrawInfo *di, struct rctf *rect);
-void gla2DSetMap(gla2DDrawInfo *di, struct rctf *rect);
-#endif
+void immDrawPixelsTex(IMMDrawPixelsTexState *state,
+ float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect,
+ float xzoom, float yzoom, float color[4]);
+void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
+ float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect,
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y,
+ float xzoom, float yzoom, float color[4]);
+void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
+ float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY,
+ float xzoom, float yzoom, float color[4]);
+void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
+ float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY,
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y,
+ float xzoom, float yzoom, float color[4]);
void set_inverted_drawing(int enable);
void setlinestyle(int nr);
@@ -198,36 +114,32 @@ void setlinestyle(int nr);
/* own working polygon offset */
void bglPolygonOffset(float viewdist, float dist);
-/* For caching opengl matrices (gluProject/gluUnProject) */
-typedef struct bglMats {
- double modelview[16];
- double projection[16];
- int viewport[4];
-} bglMats;
-void bgl_get_mats(bglMats *mats);
-
/* **** Color management helper functions for GLSL display/transform ***** */
/* Draw imbuf on a screen, preferably using GLSL display transform */
void glaDrawImBuf_glsl(struct ImBuf *ibuf, float x, float y, int zoomfilter,
struct ColorManagedViewSettings *view_settings,
- struct ColorManagedDisplaySettings *display_settings);
+ struct ColorManagedDisplaySettings *display_settings,
+ float zoom_x, float zoom_y);
void glaDrawImBuf_glsl_clipping(struct ImBuf *ibuf, float x, float y, int zoomfilter,
struct ColorManagedViewSettings *view_settings,
struct ColorManagedDisplaySettings *display_settings,
float clip_min_x, float clip_min_y,
- float clip_max_x, float clip_max_y);
+ float clip_max_x, float clip_max_y,
+ float zoom_x, float zoom_y);
/* Draw imbuf on a screen, preferably using GLSL display transform */
-void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter);
+void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter,
+ float zoom_x, float zoom_y);
void glaDrawImBuf_glsl_ctx_clipping(const struct bContext *C,
struct ImBuf *ibuf,
float x, float y,
int zoomfilter,
float clip_min_x, float clip_min_y,
- float clip_max_x, float clip_max_y);
+ float clip_max_x, float clip_max_y,
+ float zoom_x, float zoom_y);
-void glaDrawBorderCorners(const struct rcti *border, float zoomx, float zoomy);
+void immDrawBorderCorners(unsigned int pos, const struct rcti *border, float zoomx, float zoomy);
#endif /* __BIF_GLUTIL_H__ */
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index b805b2ea0ff..f7cd7bc3786 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -82,8 +82,10 @@ typedef struct bAnimContext {
struct bDopeSheet *ads; /* dopesheet data for editor (or which is being used) */
+ struct Depsgraph *depsgraph; /* active dependency graph */
struct Main *bmain; /* Current Main */
struct Scene *scene; /* active scene */
+ struct ViewLayer *view_layer; /* active scene layer */
struct Object *obact; /* active object */
ListBase *markers; /* active set of markers */
@@ -103,7 +105,8 @@ typedef enum eAnimCont_Types {
ANIMCONT_DRIVERS = 6, /* drivers (bDopesheet) */
ANIMCONT_NLA = 7, /* nla (bDopesheet) */
ANIMCONT_CHANNEL = 8, /* animation channel (bAnimListElem) */
- ANIMCONT_MASK = 9 /* mask dopesheet */
+ ANIMCONT_MASK = 9, /* mask dopesheet */
+ ANIMCONT_TIMELINE = 10, /* "timeline" editor (bDopeSheet) */
} eAnimCont_Types;
/* --------------- Channels -------------------- */
@@ -194,6 +197,8 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_NLATRACK,
ANIMTYPE_NLAACTION,
+ ANIMTYPE_PALETTE,
+
/* always as last item, the total number of channel types... */
ANIMTYPE_NUM_TYPES
} eAnim_ChannelType;
@@ -344,6 +349,9 @@ typedef enum eAnimFilter_Flags {
/* Movie clip only */
#define EXPANDED_MCLIP(clip) (clip->flag & MCLIP_DATA_EXPAND)
+/* Palette only */
+#define EXPANDED_PALETTE(palette) (palette->flag & PALETTE_DATA_EXPAND)
+
/* AnimData - NLA mostly... */
#define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED)
@@ -535,22 +543,29 @@ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, struct AnimData *adt, st
enum eAnimEditDraw_CurrentFrame {
/* plain time indicator with no special indicators */
DRAWCFRA_PLAIN = 0,
- /* draw box indicating current frame number */
- DRAWCFRA_SHOW_NUMBOX = (1 << 0),
/* time indication in seconds or frames */
- DRAWCFRA_UNIT_SECONDS = (1 << 1),
+ DRAWCFRA_UNIT_SECONDS = (1 << 0),
/* draw indicator extra wide (for timeline) */
- DRAWCFRA_WIDE = (1 << 2)
+ DRAWCFRA_WIDE = (1 << 1)
};
/* main call to draw current-frame indicator in an Animation Editor */
void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag);
+/* main call to draw "number box" in scrollbar for current frame indicator */
+void ANIM_draw_cfra_number(const struct bContext *C, struct View2D *v2d, short flag);
+
/* ------------- Preview Range Drawing -------------- */
/* main call to draw preview range curtains */
void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d, int end_frame_width);
+
+/* -------------- Frame Range Drawing --------------- */
+
+/* main call to draw normal frame range indicators */
+void ANIM_draw_framerange(struct Scene *scene, struct View2D *v2d);
+
/* ************************************************* */
/* F-MODIFIER TOOLS */
@@ -673,13 +688,14 @@ float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FC
/* --------- anim_deps.c, animation updates -------- */
-void ANIM_id_update(struct Scene *scene, struct ID *id);
+void ANIM_id_update(struct Main *bmain, struct ID *id);
void ANIM_list_elem_update(struct Main *bmain, struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
void ANIM_center_frame(struct bContext *C, int smooth_viewtx);
+
/* ************************************************* */
/* OPERATORS */
@@ -706,6 +722,10 @@ void ED_animedit_unlink_action(struct bContext *C, struct ID *id,
struct AnimData *adt, struct bAction *act,
struct ReportList *reports, bool force_delete);
+
+/* Drivers Editor - Utility to set up UI correctly */
+void ED_drivers_editor_init(struct bContext *C, struct ScrArea *sa);
+
/* ************************************************ */
#endif /* __ED_ANIM_API_H__ */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 9ad716cf07c..d5698ecadf7 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -39,17 +39,21 @@ struct Base;
struct bContext;
struct Bone;
struct bPoseChannel;
+struct Depsgraph;
struct IDProperty;
struct ListBase;
struct Main;
struct MeshDeformModifierData;
-struct DerivedMesh;
+struct Mesh;
struct Object;
struct ReportList;
struct Scene;
+struct View3D;
+struct ViewLayer;
struct ViewContext;
struct wmKeyConfig;
struct wmOperator;
+struct Main;
struct UndoType;
typedef struct EditBone {
@@ -87,6 +91,19 @@ typedef struct EditBone {
short segments;
+ char bbone_prev_type; /* Type of next/prev bone handles */
+ char bbone_next_type;
+ struct EditBone *bbone_prev; /* Next/prev bones to use as handle references when calculating bbones (optional) */
+ struct EditBone *bbone_next;
+
+ /* Used for display */
+ float disp_mat[4][4]; /* in Armature space, rest pos matrix */
+ float disp_tail_mat[4][4]; /* in Armature space, rest pos matrix */
+ /* 32 == MAX_BBONE_SUBDIV */
+ float disp_bbone_mat[32][4][4]; /* in Armature space, rest pos matrix */
+
+ struct EditBone *bbone_child; /* connected child temporary during drawing */
+
/* Used to store temporary data */
union {
struct EditBone *ebone;
@@ -134,19 +151,29 @@ void ED_armature_edit_free(struct bArmature *arm);
void ED_armature_edit_deselect_all(struct Object *obedit);
void ED_armature_edit_deselect_all_visible(struct Object *obedit);
+void ED_armature_edit_deselect_all_multi(struct Object **objects, uint objects_len);
+void ED_armature_edit_deselect_all_visible_multi(struct Object **objects, uint objects_len);
+
bool ED_armature_pose_select_pick_with_buffer(
- struct Scene *scene, struct Base *base, const unsigned int *buffer, short hits,
+ struct ViewLayer *view_layer, struct View3D *v3d, struct Base *base, const unsigned int *buffer, short hits,
bool extend, bool deselect, bool toggle, bool do_nearest);
bool ED_armature_edit_select_pick(
struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
int join_armature_exec(struct bContext *C, struct wmOperator *op);
-struct Bone *ED_armature_bone_find_index(struct Object *ob, int index);
float ED_armature_ebone_roll_to_vector(const EditBone *bone, const float new_up_axis[3], const bool axis_only);
EditBone *ED_armature_ebone_find_name(const struct ListBase *edbo, const char *name);
EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, EditBone *ebo);
void ED_armature_edit_sync_selection(struct ListBase *edbo);
void ED_armature_edit_validate_active(struct bArmature *arm);
+struct Base *ED_armature_base_and_ebone_from_select_buffer(
+ struct Base **bases, uint bases_len, int hit, struct EditBone **r_ebone);
+struct Object *ED_armature_object_and_ebone_from_select_buffer(
+ struct Object **objects, uint objects_len, int hit, struct EditBone **r_ebone);
+
+struct Base *ED_armature_base_and_bone_from_select_buffer(
+ struct Base **bases, uint bases_len, int hit, struct Bone **r_bone);
+
EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm, float length, bool view_aligned);
EditBone *ED_armature_ebone_add(struct bArmature *arm, const char *name);
@@ -163,7 +190,7 @@ void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3]);
void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]);
void ED_armature_edit_transform_mirror_update(struct Object *obedit);
-void ED_armature_origin_set(struct Main *bmain, struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around);
+void ED_armature_origin_set(struct Main *bmain, struct Object *ob, float cursor[3], int centermode, int around);
void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props);
void ED_armature_transform_apply(struct Main *bmain, struct Object *ob, float mat[4][4], const bool do_props);
@@ -173,8 +200,9 @@ void ED_armature_transform(struct Main *bmain, struct bArmature *arm, float mat[
#define ARM_GROUPS_ENVELOPE 2
#define ARM_GROUPS_AUTO 3
-void ED_object_vgroup_calc_from_armature(struct ReportList *reports, struct Scene *scene, struct Object *ob,
- struct Object *par, const int mode, const bool mirror);
+void ED_object_vgroup_calc_from_armature(
+ struct ReportList *reports, struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct Object *par, const int mode, const bool mirror);
/* if bone is already in list, pass it as param to ignore it */
void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, EditBone *bone);
@@ -197,40 +225,23 @@ void ED_armature_ebone_listbase_free(struct ListBase *lb);
void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src);
/* poseobject.c */
-bool ED_object_posemode_exit_ex(struct Object *ob);
+bool ED_object_posemode_exit_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_exit(struct bContext *C, struct Object *ob);
-bool ED_object_posemode_enter_ex(struct Object *ob);
+bool ED_object_posemode_enter_ex(struct Main *bmain, struct Object *ob);
bool ED_object_posemode_enter(struct bContext *C, struct Object *ob);
-void ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
+bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
+void ED_pose_deselect_all_multi(struct Object **objects, uint objects_len, int select_mode, const bool ignore_visibility);
+void ED_pose_bone_select_tag_update(struct Object *ob);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
-void ED_pose_recalculate_paths(struct Main *bmain, struct Scene *scene, struct Object *ob);
+void ED_pose_recalculate_paths(struct bContext *C, struct Scene *scene, struct Object *ob, bool current_frame_only);
struct Object *ED_pose_object_from_context(struct bContext *C);
-/* sketch */
-
-bool ED_operator_sketch_mode_active_stroke(struct bContext *C);
-bool ED_operator_sketch_full_mode(struct bContext *C);
-bool ED_operator_sketch_mode(const struct bContext *C);
-
-void BIF_convertSketch(struct bContext *C);
-void BIF_deleteSketch(struct bContext *C);
-void BIF_selectAllSketch(struct bContext *C, int mode); /* -1: deselect, 0: select, 1: toggle */
-
-void BIF_makeListTemplates(const struct bContext *C);
-int BIF_currentTemplate(const struct bContext *C);
-void BIF_freeTemplates(struct bContext *C);
-void BIF_setTemplate(struct bContext *C, int index);
-int BIF_nbJointsTemplate(const struct bContext *C);
-const char *BIF_nameBoneTemplate(const struct bContext *C);
-
-void BDR_drawSketch(const struct bContext *vc);
-int BDR_drawSketchNames(struct ViewContext *vc);
-
/* meshlaplacian.c */
-void ED_mesh_deform_bind_callback(struct Scene *scene,
- struct MeshDeformModifierData *mmd,
- struct DerivedMesh *cagedm,
- float *vertexcos, int totvert, float cagemat[4][4]);
+void ED_mesh_deform_bind_callback(
+ struct Scene *scene,
+ struct MeshDeformModifierData *mmd,
+ struct Mesh *cagemesh,
+ float *vertexcos, int totvert, float cagemat[4][4]);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 64c16605dec..5cc695b6ce8 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -27,14 +27,4 @@
#ifndef __ED_BUTTONS_H__
#define __ED_BUTTONS_H__
-#include "BLI_utildefines.h"
-
-/* Used to check whether a given texture context is valid in current context. */
-bool ED_texture_context_check_world(const struct bContext *C);
-bool ED_texture_context_check_material(const struct bContext *C);
-bool ED_texture_context_check_lamp(const struct bContext *C);
-bool ED_texture_context_check_particles(const struct bContext *C);
-bool ED_texture_context_check_linestyle(const struct bContext *C);
-bool ED_texture_context_check_others(const struct bContext *C);
-
#endif /* __ED_BUTTONS_H__ */
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 8fcfb4743d5..e4eea9921db 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -43,6 +43,7 @@ struct Text;
struct wmOperator;
struct wmKeyConfig;
struct UndoType;
+struct View3D;
/* curve_ops.c */
void ED_operatortypes_curve(void);
@@ -60,18 +61,20 @@ bool ED_curve_editnurb_select_pick(struct bContext *C, const int mval[2], boo
struct Nurb *ED_curve_add_nurbs_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], int type, int newob);
-bool ED_curve_nurb_select_check(struct Curve *cu, struct Nurb *nu);
-int ED_curve_nurb_select_count(struct Curve *cu, struct Nurb *nu);
+bool ED_curve_nurb_select_check(struct View3D *v3d, struct Nurb *nu);
+int ED_curve_nurb_select_count(struct View3D *v3d, struct Nurb *nu);
void ED_curve_nurb_select_all(struct Nurb *nu);
void ED_curve_nurb_deselect_all(struct Nurb *nu);
int join_curve_exec(struct bContext *C, struct wmOperator *op);
/* editcurve_select.c */
-bool ED_curve_select_check(struct Curve *cu, struct EditNurb *editnurb);
+bool ED_curve_select_check(struct View3D *v3d, struct EditNurb *editnurb);
void ED_curve_deselect_all(struct EditNurb *editnurb);
+void ED_curve_deselect_all_multi(struct Object **objects, int objects_len);
void ED_curve_select_all(struct EditNurb *editnurb);
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
+int ED_curve_select_count(struct View3D *v3d, struct EditNurb *editnurb);
/* editcurve_undo.c */
void ED_curve_undosys_type(struct UndoType *ut);
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index 7d509d1243a..c21ef288aeb 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -36,12 +36,12 @@
extern int datatoc_startup_blend_size;
extern char datatoc_startup_blend[];
-extern int datatoc_preview_blend_size;
-extern char datatoc_preview_blend[];
-
extern int datatoc_preview_cycles_blend_size;
extern char datatoc_preview_cycles_blend[];
+extern int datatoc_preview_grease_pencil_blend_size;
+extern char datatoc_preview_grease_pencil_blend[];
+
extern int datatoc_blender_icons16_png_size;
extern char datatoc_blender_icons16_png[];
@@ -239,6 +239,66 @@ extern char datatoc_mc23_jpg[];
extern int datatoc_mc24_jpg_size;
extern char datatoc_mc24_jpg[];
+/* grease pencil sculpt brushes files */
+
+extern int datatoc_gp_brush_smooth_png_size;
+extern char datatoc_gp_brush_smooth_png[];
+
+extern int datatoc_gp_brush_thickness_png_size;
+extern char datatoc_gp_brush_thickness_png[];
+
+extern int datatoc_gp_brush_strength_png_size;
+extern char datatoc_gp_brush_strength_png[];
+
+extern int datatoc_gp_brush_grab_png_size;
+extern char datatoc_gp_brush_grab_png[];
+
+extern int datatoc_gp_brush_push_png_size;
+extern char datatoc_gp_brush_push_png[];
+
+extern int datatoc_gp_brush_twist_png_size;
+extern char datatoc_gp_brush_twist_png[];
+
+extern int datatoc_gp_brush_pinch_png_size;
+extern char datatoc_gp_brush_pinch_png[];
+
+extern int datatoc_gp_brush_randomize_png_size;
+extern char datatoc_gp_brush_randomize_png[];
+
+extern int datatoc_gp_brush_clone_png_size;
+extern char datatoc_gp_brush_clone_png[];
+
+extern int datatoc_gp_brush_weight_png_size;
+extern char datatoc_gp_brush_weight_png[];
+
+extern int datatoc_gp_brush_pencil_png_size;
+extern char datatoc_gp_brush_pencil_png[];
+
+extern int datatoc_gp_brush_pen_png_size;
+extern char datatoc_gp_brush_pen_png[];
+
+extern int datatoc_gp_brush_ink_png_size;
+extern char datatoc_gp_brush_ink_png[];
+
+extern int datatoc_gp_brush_inknoise_png_size;
+extern char datatoc_gp_brush_inknoise_png[];
+
+extern int datatoc_gp_brush_block_png_size;
+extern char datatoc_gp_brush_block_png[];
+
+extern int datatoc_gp_brush_marker_png_size;
+extern char datatoc_gp_brush_marker_png[];
+
+extern int datatoc_gp_brush_fill_png_size;
+extern char datatoc_gp_brush_fill_png[];
+
+extern int datatoc_gp_brush_erase_soft_png_size;
+extern char datatoc_gp_brush_erase_soft_png[];
+
+extern int datatoc_gp_brush_erase_hard_png_size;
+extern char datatoc_gp_brush_erase_hard_png[];
+extern int datatoc_gp_brush_erase_stroke_png_size;
+extern char datatoc_gp_brush_erase_stroke_png[];
#endif /* __ED_DATAFILES_H__ */
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index e2c8ecf6812..64739d968b8 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -113,6 +113,17 @@ void ED_file_change_dir(struct bContext *C);
/* File menu stuff */
+/* FSMenuEntry's without paths indicate separators */
+typedef struct FSMenuEntry {
+ struct FSMenuEntry *next;
+
+ char *path;
+ char name[256]; /* FILE_MAXFILE */
+ short save;
+ short valid;
+ short pad[2];
+} FSMenuEntry;
+
typedef enum FSMenuCategory {
FS_CATEGORY_SYSTEM,
FS_CATEGORY_SYSTEM_BOOKMARKS,
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
new file mode 100644
index 00000000000..be772a6af98
--- /dev/null
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -0,0 +1,254 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_gizmo_library.h
+ * \ingroup wm
+ *
+ * \name Generic Gizmos.
+ *
+ * This is exposes pre-defined gizmos for re-use.
+ */
+
+
+#ifndef __ED_GIZMO_LIBRARY_H__
+#define __ED_GIZMO_LIBRARY_H__
+
+/* initialize gizmos */
+void ED_gizmotypes_arrow_2d(void);
+void ED_gizmotypes_arrow_3d(void);
+void ED_gizmotypes_button_2d(void);
+void ED_gizmotypes_cage_2d(void);
+void ED_gizmotypes_cage_3d(void);
+void ED_gizmotypes_dial_3d(void);
+void ED_gizmotypes_move_3d(void);
+void ED_gizmotypes_facemap_3d(void);
+void ED_gizmotypes_preselect_3d(void);
+void ED_gizmotypes_primitive_3d(void);
+void ED_gizmotypes_blank_3d(void);
+void ED_gizmotypes_value_2d(void);
+
+/* gizmo group types */
+void ED_gizmogrouptypes_value_2d(void);
+
+struct bContext;
+struct Object;
+struct Scene;
+struct wmGizmo;
+struct wmGizmoGroup;
+
+
+/* -------------------------------------------------------------------- */
+/* Shape Presets
+ *
+ * Intended to be called by custom draw functions.
+ */
+
+/* gizmo_library_presets.c */
+void ED_gizmo_draw_preset_box(
+ const struct wmGizmo *gz, float mat[4][4], int select_id);
+void ED_gizmo_draw_preset_arrow(
+ const struct wmGizmo *gz, float mat[4][4], int axis, int select_id);
+void ED_gizmo_draw_preset_circle(
+ const struct wmGizmo *gz, float mat[4][4], int axis, int select_id);
+void ED_gizmo_draw_preset_facemap(
+ const struct bContext *C, const struct wmGizmo *gz,
+ struct Object *ob, const int facemap, int select_id);
+
+
+/* -------------------------------------------------------------------- */
+/* 3D Arrow Gizmo */
+
+enum {
+ ED_GIZMO_ARROW_STYLE_NORMAL = 0,
+ ED_GIZMO_ARROW_STYLE_CROSS = 1,
+ ED_GIZMO_ARROW_STYLE_BOX = 2,
+ ED_GIZMO_ARROW_STYLE_CONE = 3,
+};
+
+/* transform */
+enum {
+ /* inverted offset during interaction - if set it also sets constrained below */
+ ED_GIZMO_ARROW_XFORM_FLAG_INVERTED = (1 << 3),
+ /* clamp arrow interaction to property width */
+ ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED = (1 << 4),
+};
+
+/* draw_options */
+enum {
+ /* Show arrow stem. */
+ ED_GIZMO_ARROW_DRAW_FLAG_STEM = (1 << 0),
+};
+
+void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, const float min, const float max);
+void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, const float range_fac);
+
+/* -------------------------------------------------------------------- */
+/* 2D Arrow Gizmo */
+
+/* none */
+
+/* -------------------------------------------------------------------- */
+/* Cage Gizmo */
+
+enum {
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE = (1 << 0), /* Translates */
+ ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE = (1 << 1), /* Rotates */
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE = (1 << 2), /* Scales */
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM = (1 << 3), /* Scales uniformly */
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_SIGNED = (1 << 4), /* Negative scale allowed */
+};
+
+/* draw_style */
+enum {
+ ED_GIZMO_CAGE2D_STYLE_BOX = 0,
+ ED_GIZMO_CAGE2D_STYLE_CIRCLE = 1,
+};
+
+/* draw_options */
+enum {
+ /** Draw a central handle (instead of having the entire area selectable)
+ * Needed for large rectangles that we don't want to swallow all events. */
+ ED_GIZMO_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE = (1 << 0),
+};
+
+/** #wmGizmo.highlight_part */
+enum {
+ ED_GIZMO_CAGE2D_PART_TRANSLATE = 0,
+ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X = 1,
+ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X = 2,
+ ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y = 3,
+ ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y = 4,
+ /* Corners */
+ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y = 5,
+ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y = 6,
+ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y = 7,
+ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y = 8,
+
+ ED_GIZMO_CAGE2D_PART_ROTATE = 9,
+};
+
+/** #wmGizmo.highlight_part */
+enum {
+ /* ordered min/mid/max so we can loop over values (MIN/MID/MAX) on each axis. */
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z = 0,
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MAX_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MID_Y_MIN_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MID_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MID_Y_MAX_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MIN_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MAX_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MIN_Y_MIN_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MIN_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MIN_Y_MAX_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MID_Y_MIN_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MID_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MID_Y_MAX_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MAX_Y_MIN_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MAX_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MID_X_MAX_Y_MAX_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MIN_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MAX_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MID_Y_MIN_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MID_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MID_Y_MAX_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MIN_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MID_Z,
+ ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z,
+
+ ED_GIZMO_CAGE3D_PART_TRANSLATE,
+
+ ED_GIZMO_CAGE3D_PART_ROTATE,
+};
+
+/* -------------------------------------------------------------------- */
+/* Dial Gizmo */
+
+/* draw_options */
+enum {
+ ED_GIZMO_DIAL_DRAW_FLAG_NOP = 0,
+ ED_GIZMO_DIAL_DRAW_FLAG_CLIP = (1 << 0),
+ ED_GIZMO_DIAL_DRAW_FLAG_FILL = (1 << 1),
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR = (1 << 2),
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y = (1 << 3),
+ /* Always show the angle value as an arc in the dial. */
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE = (1 << 4),
+};
+
+/* -------------------------------------------------------------------- */
+/* Move Gizmo */
+
+/* draw_options */
+enum {
+ ED_GIZMO_MOVE_DRAW_FLAG_NOP = 0,
+ /* only for solid shapes */
+ ED_GIZMO_MOVE_DRAW_FLAG_FILL = (1 << 0),
+ ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW = (1 << 1),
+};
+
+enum {
+ ED_GIZMO_MOVE_STYLE_RING_2D = 0,
+ ED_GIZMO_MOVE_STYLE_CROSS_2D = 1,
+};
+
+/* -------------------------------------------------------------------- */
+/* Button Gizmo */
+
+enum {
+ ED_GIZMO_BUTTON_SHOW_OUTLINE = (1 << 0),
+ ED_GIZMO_BUTTON_SHOW_BACKDROP = (1 << 1),
+ /**
+ * Draw a line from the origin to the offset (similar to an arrow)
+ * sometimes needed to show what the button edits.
+ */
+ ED_GIZMO_BUTTON_SHOW_HELPLINE = (1 << 2),
+};
+
+
+/* -------------------------------------------------------------------- */
+/* Primitive Gizmo */
+
+enum {
+ ED_GIZMO_PRIMITIVE_STYLE_PLANE = 0,
+};
+
+
+/* -------------------------------------------------------------------- */
+/* Gizmo Drawing Functions */
+
+struct Dial3dParams {
+ int draw_options;
+ float angle_ofs;
+ float angle_delta;
+ float angle_increment;
+ float arc_partial_angle;
+ float arc_inner_factor;
+ float *clip_plane;
+};
+void ED_gizmotypes_dial_3d_draw_util(
+ const float matrix_basis[4][4],
+ const float matrix_final[4][4],
+ const float line_width,
+ const float color[4],
+ struct Dial3dParams *params);
+
+#endif /* __ED_GIZMO_LIBRARY_H__ */
diff --git a/source/blender/editors/include/ED_gizmo_utils.h b/source/blender/editors/include/ED_gizmo_utils.h
new file mode 100644
index 00000000000..77956b9ca0d
--- /dev/null
+++ b/source/blender/editors/include/ED_gizmo_utils.h
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_gizmo_utils.h
+ * \ingroup editors
+ *
+ * \name Generic Gizmo Utilities.
+ */
+
+#ifndef __ED_GIZMO_UTILS_H__
+#define __ED_GIZMO_UTILS_H__
+
+struct bContext;
+struct wmGizmoGroupType;
+
+/** Wrapper function (operator name can't be guessed). */
+bool ED_gizmo_poll_or_unlink_delayed_from_operator(
+ const struct bContext *C, struct wmGizmoGroupType *gzgt,
+ const char *idname);
+
+bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(
+ const struct bContext *C, struct wmGizmoGroupType *gzgt,
+ const char *gzgt_idname);
+
+/** Use this as poll function directly for: #wmGizmoGroupType.poll */
+bool ED_gizmo_poll_or_unlink_delayed_from_tool(
+ const struct bContext *C, struct wmGizmoGroupType *gzgt);
+
+#endif /* __ED_GIZMO_UTILS_H__ */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 6b9cf23ce73..850969cce96 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -30,61 +30,45 @@
#ifndef __ED_GPENCIL_H__
#define __ED_GPENCIL_H__
-#include "ED_numinput.h"
-
struct ID;
struct ListBase;
-struct bContext;
-struct ScrArea;
-struct ARegion;
-struct View3D;
-struct Object;
+struct PointerRNA;
+struct rcti;
+
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
-struct bGPDpalette;
-struct bGPDpalettecolor;
-struct bAnimContext;
-struct KeyframeEditData;
-struct PointerRNA;
-struct wmWindowManager;
-struct wmKeyConfig;
-
+struct bGPDspoint;
+struct Brush;
-/* ------------- Grease-Pencil Helpers ---------------- */
-typedef struct tGPDinterpolate_layer {
- struct tGPDinterpolate_layer *next, *prev;
-
- struct bGPDlayer *gpl; /* layer */
- struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */
- struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */
- struct bGPDframe *interFrame; /* interpolated frame */
- float factor; /* interpolate factor */
+struct Main;
+struct bContext;
+struct EvaluationContext;
+struct Depsgraph;
+struct ScrArea;
+struct ARegion;
+struct RegionView3D;
+struct ReportList;
+struct Scene;
+struct ToolSettings;
+struct ViewLayer;
+struct View3D;
-} tGPDinterpolate_layer;
+struct Object;
+struct Material;
-/* Temporary interpolate operation data */
-typedef struct tGPDinterpolate {
- struct Scene *scene; /* current scene from context */
- struct ScrArea *sa; /* area where painting originated */
- struct ARegion *ar; /* region where painting originated */
- struct bGPdata *gpd; /* current GP datablock */
+struct bAnimContext;
+struct KeyframeEditData;
- int cframe; /* current frame number */
- ListBase ilayers; /* (tGPDinterpolate_layer) layers to be interpolated */
- float shift; /* value for determining the displacement influence */
- float init_factor; /* initial interpolation factor for active layer */
- float low_limit; /* shift low limit (-100%) */
- float high_limit; /* shift upper limit (200%) */
- int flag; /* flag from toolsettings */
+struct wmKeyConfig;
+struct wmOperator;
+struct wmWindow;
+struct wmWindowManager;
- NumInput num; /* numeric input */
- void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
- void *draw_handle_screen; /* handle for drawing strokes while operator is running screen stuff */
-} tGPDinterpolate;
+/* ------------- Grease-Pencil Runtime Data ---------------- */
-/* Temporary 'Stroke Point' data
+/* Temporary 'Stroke Point' data (2D / screen-space)
*
* Used as part of the 'stroke cache' used during drawing of new strokes
*/
@@ -93,27 +77,43 @@ typedef struct tGPspoint {
float pressure; /* pressure of tablet at this point */
float strength; /* pressure of tablet at this point for alpha factor */
float time; /* Time relative to stroke start (used when converting to path) */
+ float uv_fac; /* factor of uv along the stroke */
+ float uv_rot; /* uv rotation for dor mode */
} tGPspoint;
-
-/* Check if 'sketching sessions' are enabled */
-#define GPENCIL_SKETCH_SESSIONS_ON(scene) ((scene)->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINTSESSIONS_ON)
+/* used to sort by zdepth gpencil objects in viewport */
+/* TODO: this could be a system parameter in userprefs screen */
+#define GP_CACHE_BLOCK_SIZE 16
+typedef struct tGPencilSort {
+ struct Base *base;
+ float zdepth;
+} tGPencilSort;
/* ----------- Grease Pencil Tools/Context ------------- */
/* Context-dependent */
-struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr);
+struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *r_ptr);
+
struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
+struct bGPdata *ED_gpencil_data_get_active_evaluated(const struct bContext *C);
/* Context independent (i.e. each required part is passed in instead) */
-struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ID *screen_id, struct Scene *scene,
- struct ScrArea *sa, struct Object *ob,
- struct PointerRNA *ptr);
-struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct Scene *scene,
- struct ScrArea *sa, struct Object *ob);
+struct bGPdata **ED_gpencil_data_get_pointers_direct(
+ struct ID *screen_id,
+ struct ScrArea *sa,
+ struct Scene *scene,
+ struct Object *ob,
+ struct PointerRNA *r_ptr);
+struct bGPdata *ED_gpencil_data_get_active_direct(
+ struct ID *screen_id,
+ struct ScrArea *sa,
+ struct Scene *scene,
+ struct Object *ob);
+
+bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr);
/* 3D View */
-struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d);
+struct bGPdata *ED_gpencil_data_get_active_v3d(struct ViewLayer *view_layer, struct View3D *v3d);
bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfra);
@@ -121,13 +121,7 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
-bool ED_gpencil_stroke_color_use(const struct bGPDlayer *gpl, const struct bGPDstroke *gps);
-
-struct bGPDpalettecolor *ED_gpencil_stroke_getcolor(struct bGPdata *gpd, struct bGPDstroke *gps);
-
-bool ED_gpencil_stroke_minmax(
- const struct bGPDstroke *gps, const bool use_select,
- float r_min[3], float r_max[3]);
+bool ED_gpencil_stroke_color_use(struct Object *ob, const struct bGPDlayer *gpl, const struct bGPDstroke *gps);
/* ----------- Grease Pencil Operators ----------------- */
@@ -147,10 +141,30 @@ void ED_gpencil_strokes_copybuf_free(void);
void ED_gpencil_draw_2dimage(const struct bContext *C);
void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d);
-void ED_gpencil_draw_view3d(struct wmWindowManager *wm, struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d);
-void ED_gpencil_draw_ex(struct Scene *scene, struct bGPdata *gpd, int winx, int winy,
- const int cfra, const char spacetype);
-void ED_gp_draw_interpolation(struct tGPDinterpolate *tgpi, const int type);
+void ED_gpencil_draw_view3d(
+ struct wmWindowManager *wm,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct Depsgraph *depsgraph,
+ struct View3D *v3d,
+ struct ARegion *ar,
+ bool only3d);
+void ED_gpencil_draw_view3d_annotations(
+ struct Scene *scene, struct Depsgraph *depsgraph,
+ struct View3D *v3d, struct ARegion *ar,
+ bool only3d);
+void ED_gpencil_draw_view3d_object(
+ struct wmWindowManager *wm,
+ struct Scene *scene,
+ struct Depsgraph *depsgraph,
+ struct Object *ob,
+ struct View3D *v3d,
+ struct ARegion *ar,
+ bool only3d);
+void ED_gpencil_draw_ex(
+ struct ViewLayer *view_layer, struct RegionView3D *rv3d, struct Scene *scene,
+ struct bGPdata *gpd, int winx, int winy,
+ const int cfra, const char spacetype);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene,
@@ -159,7 +173,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only
bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode);
-void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode);
+void ED_gplayer_frames_select_box(struct bGPDlayer *gpl, float min, float max, short select_mode);
void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode);
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
@@ -181,12 +195,63 @@ 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);
+/* ------------ Grease-Pencil Armature weights ------------------ */
+bool ED_gpencil_add_armature_weights(
+ const struct bContext *C, struct ReportList *reports,
+ struct Object *ob, struct Object *ob_arm, int mode);
+
+/* keep this aligned with gpencil_armature enum */
+#define GP_PAR_ARMATURE_NAME 0
+#define GP_PAR_ARMATURE_AUTO 1
+
/* ------------ Transformation Utilities ------------ */
-/* get difference matrix using parent */
-void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]);
+/* get difference matrix */
+void ED_gpencil_parent_location(
+ const struct Depsgraph *depsgraph, struct Object *obact, struct bGPdata *gpd,
+ struct bGPDlayer *gpl, float diff_mat[4][4]);
/* reset parent matrix for all layers */
-void ED_gpencil_reset_layers_parent(struct bGPdata *gpd);
-
+void ED_gpencil_reset_layers_parent(struct Depsgraph *depsgraph, struct Object *obact, struct bGPdata *gpd);
+
+/* cursor utilities */
+void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
+
+/* ----------- Add Primitive Utilities -------------- */
+
+void ED_gpencil_create_monkey(struct bContext *C, float mat[4][4]);
+void ED_gpencil_create_stroke(struct bContext *C, float mat[4][4]);
+
+/* ------------ Object Utilities ------------ */
+struct Object *ED_add_gpencil_object(struct bContext *C, struct Scene *scene, const float loc[3]);
+void ED_gpencil_add_defaults(struct bContext *C);
+/* set object modes */
+void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode);
+
+void ED_gp_project_stroke_to_plane(
+ const struct Object *ob, const struct RegionView3D *rv3d,
+ struct bGPDstroke *gps, const float origin[3], const int axis);
+void ED_gp_project_point_to_plane(
+ const struct Object *ob, const struct RegionView3D *rv3d,
+ const float origin[3], const int axis, struct bGPDspoint *pt);
+void ED_gp_get_drawing_reference(
+ const struct Scene *scene, const struct Object *ob,
+ struct bGPDlayer *gpl, char align_flag, float vec[3]);
+
+/* set sculpt cursor */
+void ED_gpencil_toggle_brush_cursor(struct bContext *C, bool enable, void *customdata);
+
+/* vertex groups */
+void ED_gpencil_vgroup_assign(struct bContext *C, struct Object *ob, float weight);
+void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob);
+void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob);
+void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob);
+
+/* join objects */
+int ED_gpencil_join_objects_exec(struct bContext *C, struct wmOperator *op);
+
+/* texture coordinate utilities */
+void ED_gpencil_tpoint_to_point(struct ARegion *ar, float origin[3], const struct tGPspoint *tpt, struct bGPDspoint *pt);
+void ED_gpencil_calc_stroke_uv(struct Object *ob, struct bGPDstroke *gps);
+void ED_gpencil_update_color_uv(struct Main *bmain, struct Material *mat);
#endif /* __ED_GPENCIL_H__ */
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index e5631c4e191..f8af67b55ff 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -39,11 +39,11 @@ struct ToolSettings;
struct wmWindowManager;
struct ARegion;
struct Scene;
+struct ViewLayer;
/* image_edit.c, exported for transform */
struct Image *ED_space_image(struct SpaceImage *sima);
-void ED_space_image_set(
- struct Main *bmain, struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima);
+void ED_space_image_set(struct Main *bmain, struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima);
struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
@@ -75,7 +75,7 @@ bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit);
bool ED_space_image_paint_curve(const struct bContext *C);
-bool ED_space_image_check_show_maskedit(struct Scene *scene, struct SpaceImage *sima);
+bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct ViewLayer *view_layer);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index 6970abaa633..072b1a135a3 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -28,7 +28,7 @@
#define __ED_INFO_H__
/* info_stats.c */
-void ED_info_stats_clear(struct Scene *scene);
-const char *ED_info_stats_string(struct Scene *scene);
+void ED_info_stats_clear(struct ViewLayer *view_layer);
+const char *ED_info_stats_string(struct Scene *scene, struct ViewLayer *view_layer);
#endif /* __ED_INFO_H__ */
diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h
index a29057197ed..6421c5817b0 100644
--- a/source/blender/editors/include/ED_keyframes_draw.h
+++ b/source/blender/editors/include/ED_keyframes_draw.h
@@ -42,6 +42,7 @@ struct bActionGroup;
struct Object;
struct ListBase;
struct bGPDlayer;
+struct Palette;
struct MaskLayer;
struct Scene;
struct View2D;
@@ -49,6 +50,17 @@ struct DLRBT_Tree;
/* ****************************** Base Structs ****************************** */
+/* Information about the stretch of time from current to the next column */
+typedef struct ActKeyBlockInfo {
+ /* Combination of flags from all curves. */
+ short flag;
+ /* Mask of flags that differ between curves. */
+ short conflict;
+
+ /* Selection flag. */
+ char sel;
+} ActKeyBlockInfo;
+
/* Keyframe Column Struct */
typedef struct ActKeyColumn {
/* ListBase linkage */
@@ -61,39 +73,28 @@ typedef struct ActKeyColumn {
/* keyframe info */
char key_type; /* eBezTripe_KeyframeType */
+ char handle_type; /* eKeyframeHandleDrawOpts */
+ char extreme_type; /* eKeyframeExtremeDrawOpts */
short sel;
float cfra;
- /* only while drawing - used to determine if long-keyframe needs to be drawn */
- short modified;
- short totcurve;
-} ActKeyColumn;
-
-/* 'Long Keyframe' Struct */
-typedef struct ActKeyBlock {
- /* ListBase linkage */
- struct ActKeyBlock *next, *prev;
-
- /* sorting-tree linkage */
- struct ActKeyBlock *left, *right; /* 'children' of this node, less than and greater than it (respectively) */
- struct ActKeyBlock *parent; /* parent of this node in the tree */
- char tree_col; /* DLRB_BLACK or DLRB_RED */
-
/* key-block info */
- char sel;
- short flag;
- float val;
- float start, end;
+ ActKeyBlockInfo block;
- /* only while drawing - used to determine if block needs to be drawn */
- short modified;
- short totcurve;
-} ActKeyBlock;
+ /* number of curves and keys in this column */
+ short totcurve, totkey, totblock;
+} ActKeyColumn;
-/* ActKeyBlock - Flag */
-typedef enum eActKeyBlock_Flag {
+/* ActKeyBlockInfo - Flag */
+typedef enum eActKeyBlock_Hold {
/* Key block represents a moving hold */
ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0),
+ /* Key block represents a static hold */
+ ACTKEYBLOCK_FLAG_STATIC_HOLD = (1 << 1),
+ /* Key block represents any kind of hold */
+ ACTKEYBLOCK_FLAG_ANY_HOLD = (1 << 2),
+ /* The curve segment uses non-bezier interpolation */
+ ACTKEYBLOCK_FLAG_NON_BEZIER = (1 << 3),
} eActKeyBlock_Flag;
/* *********************** Keyframe Drawing ****************************** */
@@ -108,50 +109,79 @@ typedef enum eKeyframeShapeDrawOpts {
KEYFRAME_SHAPE_BOTH
} eKeyframeShapeDrawOpts;
-/* draw simple diamond-shape keyframe (with OpenGL) */
-void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, short key_type, short mode, float alpha);
+/* Handle type. */
+typedef enum eKeyframeHandleDrawOpts {
+ /* Don't draw */
+ KEYFRAME_HANDLE_NONE = 0,
+ /* Various marks in order of increasing display priority. */
+ KEYFRAME_HANDLE_AUTO_CLAMP,
+ KEYFRAME_HANDLE_AUTO,
+ KEYFRAME_HANDLE_VECTOR,
+ KEYFRAME_HANDLE_ALIGNED,
+ KEYFRAME_HANDLE_FREE,
+} eKeyframeHandleDrawOpts;
+
+/* Extreme type. */
+typedef enum eKeyframeExtremeDrawOpts {
+ KEYFRAME_EXTREME_NONE = 0,
+ /* Minimum/maximum present. */
+ KEYFRAME_EXTREME_MIN = (1 << 0),
+ KEYFRAME_EXTREME_MAX = (1 << 1),
+ /* Grouped keys have different states. */
+ KEYFRAME_EXTREME_MIXED = (1 << 2),
+ /* Both neigbors are equal to this key. */
+ KEYFRAME_EXTREME_FLAT = (1 << 3),
+} eKeyframeExtremeDrawOpts;
+
+/* draw simple diamond-shape keyframe */
+/* caller should set up vertex format, bind GPU_SHADER_KEYFRAME_DIAMOND, immBegin(GPU_PRIM_POINTS, n), then call this n times */
+void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type, short mode, float alpha,
+ unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id,
+ unsigned int linemask_id, short ipo_type, short extreme_type);
/* ******************************* Methods ****************************** */
/* Channel Drawing ------------------ */
/* F-Curve */
-void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos, float yscale_fac);
+void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos, float yscale_fac, int saction_flag);
/* Action Group Summary */
-void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos, float yscale_fac);
+void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag);
/* Action Summary */
-void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos, float yscale_fac);
+void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos, float yscale_fac, int saction_flag);
/* Object Summary */
-void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos, float yscale_fac);
+void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos, float yscale_fac, int saction_flag);
/* Scene Summary */
-void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos, float yscale_fac);
+void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos, float yscale_fac, int saction_flag);
/* DopeSheet Summary */
-void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos, float yscale_fac);
+void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos, float yscale_fac, int saction_flag);
/* Grease Pencil datablock summary */
-void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos, float yscale_fac);
+void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos, float yscale_fac, int saction_flag);
/* Grease Pencil Layer */
-void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos, float yscale_fac);
+void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag);
/* Mask Layer */
-void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos, float yscale_fac);
+void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos, float yscale_fac, int saction_flag);
/* Keydata Generation --------------- */
/* F-Curve */
-void fcurve_to_keylist(struct AnimData *adt, struct FCurve *fcu, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+void fcurve_to_keylist(struct AnimData *adt, struct FCurve *fcu, struct DLRBT_Tree *keys, int saction_flag);
/* Action Group */
-void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct DLRBT_Tree *keys, int saction_flag);
/* Action */
-void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, int saction_flag);
/* Object */
-void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree *keys, int saction_flag);
/* Cache File */
-void cachefile_to_keylist(struct bDopeSheet *ads, struct CacheFile *cache_file, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+void cachefile_to_keylist(struct bDopeSheet *ads, struct CacheFile *cache_file, struct DLRBT_Tree *keys, int saction_flag);
/* Scene */
-void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, int saction_flag);
/* DopeSheet Summary */
-void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
+void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, int saction_flag);
/* Grease Pencil datablock summary */
-void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys);
+void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys, const bool active);
/* Grease Pencil Layer */
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys);
+/* Palette */
+void palette_to_keylist(struct bDopeSheet *ads, struct Palette *palette, struct DLRBT_Tree *keys);
/* Mask */
void mask_to_keylist(struct bDopeSheet *UNUSED(ads), struct MaskLayer *masklay, struct DLRBT_Tree *keys);
@@ -159,10 +189,10 @@ void mask_to_keylist(struct bDopeSheet *UNUSED(ads), struct MaskLayer *masklay,
/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
short compare_ak_cfraPtr(void *node, void *data);
-/* Comparator callback used for ActKeyBlocks and cframe float-value pointer */
-short compare_ab_cfraPtr(void *node, void *data);
+/* Checks if ActKeyColumn has any block data */
+bool actkeyblock_is_valid(ActKeyColumn *ab);
-/* Checks if ActKeyBlock can be used (i.e. drawn/used to detect "holds") */
-bool actkeyblock_is_valid(ActKeyBlock *ab, struct DLRBT_Tree *keys);
+/* Checks if ActKeyColumn can be used as a block (i.e. drawn/used to detect "holds") */
+int actkeyblock_get_valid_hold(ActKeyColumn *ab);
#endif /* __ED_KEYFRAMES_DRAW_H__ */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index b3496b1c088..ed38e9cae58 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -50,6 +50,8 @@ struct bPoseChannel;
struct bContext;
struct ReportList;
+struct Depsgraph;
+
struct PointerRNA;
struct PropertyRNA;
struct EnumPropertyItem;
@@ -74,7 +76,7 @@ struct bAction *verify_adt_action(struct Main *bmain, struct ID *id, short add);
/* Get (or add relevant data to be able to do so) F-Curve from the given Action.
* This assumes that all the destinations are valid.
*/
-struct FCurve *verify_fcurve(struct bAction *act, const char group[], struct PointerRNA *ptr,
+struct FCurve *verify_fcurve(struct Main *bmain, struct bAction *act, const char group[], struct PointerRNA *ptr,
const char rna_path[], const int array_index, short add);
/* -------- */
@@ -107,7 +109,7 @@ int insert_vert_fcurve(struct FCurve *fcu, float x, float y, eBezTriple_Keyframe
* Use this to insert a keyframe using the current value being keyframed, in the
* nominated F-Curve (no creation of animation data performed). Returns success.
*/
-bool insert_keyframe_direct(struct ReportList *reports, struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag);
+bool insert_keyframe_direct(struct Depsgraph *depsgraph, struct ReportList *reports, struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag);
/* -------- */
@@ -116,13 +118,15 @@ bool insert_keyframe_direct(struct ReportList *reports, struct PointerRNA ptr, s
* using the current value being keyframed, in the relevant place. Returns success.
*/
short insert_keyframe(
- struct Main *bmain, struct ReportList *reports, struct ID *id, struct bAction *act,
+ struct Main *bmain, struct Depsgraph *depsgraph, struct ReportList *reports, struct ID *id, struct bAction *act,
const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag);
/* Main Keyframing API call:
* Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case.
*/
-short delete_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, eInsertKeyFlags flag);
+short delete_keyframe(
+ struct Main *bmain, struct ReportList *reports, struct ID *id, struct bAction *act,
+ const char group[], const char rna_path[], int array_index, float cfra, eInsertKeyFlags flag);
/* ************ Keying Sets ********************** */
diff --git a/source/blender/editors/include/ED_markers.h b/source/blender/editors/include/ED_markers.h
index a95e283f218..fa907010870 100644
--- a/source/blender/editors/include/ED_markers.h
+++ b/source/blender/editors/include/ED_markers.h
@@ -72,9 +72,6 @@ void ED_operatortypes_marker(void);
/* called in screen_ops.c:ED_keymap_screen() */
void ED_keymap_marker(struct wmKeyConfig *keyconf);
-/* called in animation editors - keymap defines */
-void ED_marker_keymap_animedit_conflictfree(struct wmKeyMap *keymap);
-
/* debugging only */
void debug_markers_print_list(struct ListBase *markers);
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 2ab788d5e2a..af9d87b8e0e 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -80,7 +80,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo
bool ED_masklayer_frame_select_check(struct MaskLayer *masklay);
void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode);
-void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode);
+void ED_masklayer_frames_select_box(struct MaskLayer *masklay, float min, float max, short select_mode);
void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode);
void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode);
void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode);
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 46c34d36efc..47ea3929883 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -51,4 +51,11 @@ void ED_mball_editmball_load(struct Object *obedit);
/* editmball_undo.c */
void ED_mball_undosys_type(struct UndoType *ut);
+
+#define MBALLSEL_STIFF (1 << 29)
+#define MBALLSEL_RADIUS (1 << 30)
+#define MBALLSEL_ANY (MBALLSEL_STIFF | MBALLSEL_RADIUS)
+
+#define MBALL_NOSEL (1u << 31u)
+
#endif /* __ED_MBALL_H__ */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index c2094b4215c..d427454cd7b 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -35,10 +35,12 @@
extern "C" {
#endif
+struct Base;
struct ID;
struct View3D;
struct ARegion;
struct bContext;
+struct Depsgraph;
struct wmOperator;
struct wmKeyConfig;
struct ReportList;
@@ -47,10 +49,10 @@ struct bDeformGroup;
struct MDeformVert;
struct Scene;
struct Mesh;
-struct MTexPoly;
struct UvVertMap;
struct UvMapVert;
struct BMEditMesh;
+struct BMElem;
struct BMesh;
struct BMVert;
struct BMLoop;
@@ -84,7 +86,6 @@ void EDBM_selectmode_to_scene(struct bContext *C);
void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index);
void EDBM_mesh_free(struct BMEditMesh *em);
void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
-struct DerivedMesh *EDBM_mesh_deform_dm_get(struct BMEditMesh *em);
/* flushes based on the current select mode. if in vertex select mode,
* verts select/deselect edges and faces, if in edge select mode,
@@ -114,8 +115,7 @@ struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *
bool EDBM_uv_check(struct BMEditMesh *em);
struct BMFace *EDBM_uv_active_face_get(
- struct BMEditMesh *em, const bool sloppy, const bool selected,
- struct MTexPoly **r_tf);
+ struct BMEditMesh *em, const bool sloppy, const bool selected);
void BM_uv_vert_map_free(struct UvVertMap *vmap);
struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v);
@@ -127,6 +127,7 @@ void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
+ struct Depsgraph *depsgraph,
struct ARegion *ar, struct View3D *v3d, struct Object *obedit);
/* editmesh_undo.c */
@@ -169,6 +170,25 @@ struct BMFace *EDBM_face_find_nearest_ex(
struct BMFace *EDBM_face_find_nearest(
struct ViewContext *vc, float *r_dist);
+bool EDBM_unified_findnearest(
+ struct ViewContext *vc,
+ struct Base **bases,
+ const uint bases_len,
+ int *r_base_index,
+ struct BMVert **r_eve,
+ struct BMEdge **r_eed,
+ struct BMFace **r_efa);
+
+bool EDBM_unified_findnearest_from_raycast(
+ struct ViewContext *vc,
+ struct Base **bases,
+ const uint bases_len,
+ bool use_boundary,
+ int *r_base_index,
+ struct BMVert **r_eve,
+ struct BMEdge **r_eed,
+ struct BMFace **r_efa);
+
bool EDBM_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
void EDBM_selectmode_set(struct BMEditMesh *em);
@@ -192,6 +212,26 @@ void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* renam
extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs;
+/* editmesh_preselect_edgering.c */
+struct EditMesh_PreSelEdgeRing;
+struct EditMesh_PreSelEdgeRing *EDBM_preselect_edgering_create(void);
+void EDBM_preselect_edgering_destroy(struct EditMesh_PreSelEdgeRing *psel);
+void EDBM_preselect_edgering_clear(struct EditMesh_PreSelEdgeRing *psel);
+void EDBM_preselect_edgering_draw(struct EditMesh_PreSelEdgeRing *psel, const float matrix[4][4]);
+void EDBM_preselect_edgering_update_from_edge(
+ struct EditMesh_PreSelEdgeRing *psel,
+ struct BMesh *bm, struct BMEdge *eed_start, int previewlines, const float (*coords)[3]);
+
+/* editmesh_preselect_elem.c */
+struct EditMesh_PreSelElem;
+struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void);
+void EDBM_preselect_elem_destroy(struct EditMesh_PreSelElem *psel);
+void EDBM_preselect_elem_clear(struct EditMesh_PreSelElem *psel);
+void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matrix[4][4]);
+void EDBM_preselect_elem_update_from_single(
+ struct EditMesh_PreSelElem *psel,
+ struct BMesh *bm, struct BMElem *ele, const float (*coords)[3]);
+
/* mesh_ops.c */
void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
@@ -203,8 +243,9 @@ void EDBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct BMEd
/* editface.c */
void paintface_flush_flags(struct Object *ob, short flag);
+void paintface_tag_select_update(struct bContext *C, struct Object *ob);
bool paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], bool extend, bool deselect, bool toggle);
-int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, bool select, bool extend);
+int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, int sel_op);
void paintface_deselect_all_visible(struct Object *ob, int action, bool flush_flags);
void paintface_select_linked(struct bContext *C, struct Object *ob, const int mval[2], const bool select);
bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]);
@@ -215,19 +256,20 @@ void paintface_reveal(struct Object *ob, const bool select);
void paintvert_deselect_all_visible(struct Object *ob, int action, bool flush_flags);
void paintvert_select_ungrouped(struct Object *ob, bool extend, bool flush_flags);
void paintvert_flush_flags(struct Object *ob);
+void paintvert_tag_select_update(struct bContext *C, struct Object *ob);
/* mirrtopo */
typedef struct MirrTopoStore_t {
intptr_t *index_lookup;
int prev_vert_tot;
int prev_edge_tot;
- int prev_ob_mode;
+ bool prev_is_editmode;
} MirrTopoStore_t;
bool ED_mesh_mirrtopo_recalc_check(
- struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store);
+ struct Mesh *me, struct Mesh *me_eval, MirrTopoStore_t *mesh_topo_store);
void ED_mesh_mirrtopo_init(
- struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
+ struct Mesh *me, struct Mesh *me_eval, MirrTopoStore_t *mesh_topo_store,
const bool skip_em_vert_array_init);
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
@@ -266,7 +308,6 @@ void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGrou
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
-
/* mesh_data.c */
// void ED_mesh_geometry_add(struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces);
void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count);
@@ -280,7 +321,7 @@ void ED_mesh_edges_remove(struct Mesh *mesh, struct ReportList *reports, int cou
void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_calc_tessface(struct Mesh *mesh, bool free_mpoly);
-void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_tessface);
+void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose, bool calc_tessface);
void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name);
int ED_mesh_uv_texture_add(struct Mesh *me, const char *name, const bool active_set);
@@ -318,17 +359,17 @@ int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
/* mirror lookup api */
int ED_mesh_mirror_spatial_table(
- struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, const float co[3], char mode);
-int ED_mesh_mirror_topo_table(struct Object *ob, struct DerivedMesh *dm, char mode);
+ struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval, const float co[3], char mode);
+int ED_mesh_mirror_topo_table(struct Object *ob, struct Mesh *me_eval, char mode);
/* retrieves mirrored cache vert, or NULL if there isn't one.
* note: calling this without ensuring the mirror cache state
* is bad.*/
-int mesh_get_x_mirror_vert(struct Object *ob, struct DerivedMesh *dm, int index, const bool use_topology);
+int mesh_get_x_mirror_vert(struct Object *ob, struct Mesh *me_eval, int index, const bool use_topology);
struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em,
struct BMVert *eve, const float co[3],
int index, const bool use_topology);
-int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm);
+int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval);
int ED_mesh_mirror_get_vert(struct Object *ob, int index);
@@ -341,6 +382,9 @@ struct MDeformVert *ED_mesh_active_dvert_get_em(struct Object *ob, struct BMVert
struct MDeformVert *ED_mesh_active_dvert_get_ob(struct Object *ob, int *r_index);
struct MDeformVert *ED_mesh_active_dvert_get_only(struct Object *ob);
+void EDBM_mesh_stats_multi(struct Object **objects, const uint objects_len, int totelem[3], int totelem_sel[3]);
+void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, const uint objects_len, const char htype);
+
#define ED_MESH_PICK_DEFAULT_VERT_SIZE 50
#define ED_MESH_PICK_DEFAULT_FACE_SIZE 3
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index c2382f7f9b9..8d652609fbc 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -75,7 +75,7 @@ void ED_init_custom_node_socket_type(struct bNodeSocketType *stype);
void ED_init_standard_node_socket_type(struct bNodeSocketType *stype);
void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype);
void ED_node_sample_set(const float col[4]);
-void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, NodeBorder border);
+void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned pos);
/* node_draw.c */
void ED_node_tree_update(const struct bContext *C);
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index 00558a3a787..f674a0d87f9 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -88,4 +88,6 @@ bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event
#define NUM_MODAL_INCREMENT_UP 18
#define NUM_MODAL_INCREMENT_DOWN 19
+bool user_string_to_number(bContext *C, const char *str, const struct UnitSettings *unit, int type, double *r_value);
+
#endif /* __ED_NUMINPUT_H__ */
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index d40c4f8dec9..a6be1c833eb 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -35,14 +35,19 @@
extern "C" {
#endif
+struct bFaceMap;
struct Base;
struct EnumPropertyItem;
struct ID;
struct Main;
+struct Menu;
struct ModifierData;
+struct ShaderFxData;
struct Object;
struct ReportList;
struct Scene;
+struct View3D;
+struct ViewLayer;
struct bConstraint;
struct bContext;
struct bPoseChannel;
@@ -50,10 +55,13 @@ struct wmKeyConfig;
struct wmKeyMap;
struct wmOperator;
struct wmOperatorType;
+struct wmWindow;
+struct wmWindowManager;
struct PointerRNA;
struct PropertyRNA;
struct EnumPropertyItem;
-struct wmWindowManager;
+struct Depsgraph;
+struct uiLayout;
#include "DNA_object_enums.h"
#include "BLI_compiler_attrs.h"
@@ -61,6 +69,7 @@ struct wmWindowManager;
/* object_edit.c */
struct Object *ED_object_context(struct bContext *C); /* context.object */
struct Object *ED_object_active_context(struct bContext *C); /* context.object or context.active_object */
+void ED_hide_collections_menu_draw(const struct bContext *C, struct uiLayout *layout);
/* object_ops.c */
void ED_operatortypes_object(void);
@@ -84,32 +93,30 @@ typedef enum eParentType {
PAR_VERTEX_TRI,
} eParentType;
+typedef enum eObjectSelect_Mode {
+ BA_DESELECT = 0,
+ BA_SELECT = 1,
+ BA_INVERT = 2,
+} eObjectSelect_Mode;
+
#ifdef __RNA_TYPES_H__
extern struct EnumPropertyItem prop_clear_parent_types[];
extern struct EnumPropertyItem prop_make_parent_types[];
#endif
-bool ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob,
+bool ED_object_parent_set(struct ReportList *reports, const struct bContext *C, struct Scene *scene, struct Object *ob,
struct Object *par, int partype, const bool xmirror, const bool keep_transform,
const int vert_par[3]);
void ED_object_parent_clear(struct Object *ob, const int type);
-struct Base *ED_object_scene_link(struct Scene *scene, struct Object *ob);
-
-void ED_keymap_proportional_cycle(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap);
-void ED_keymap_proportional_obmode(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap);
-void ED_keymap_proportional_maskmode(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap);
-void ED_keymap_proportional_editmode(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap,
- const bool do_connected);
-/* send your own notifier for select! */
-void ED_base_object_select(struct Base *base, short mode);
-/* includes notifier */
-void ED_base_object_activate(struct bContext *C, struct Base *base);
-
-void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Base *base);
+void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode);
+void ED_object_base_activate(struct bContext *C, struct Base *base);
+void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob);
+bool ED_object_base_deselect_all_ex(struct ViewLayer *view_layer, struct View3D *v3d, int action, bool *r_any_visible);
+bool ED_object_base_deselect_all(struct ViewLayer *view_layer, struct View3D *v3d, int action);
/* single object duplicate, if (dupflag == 0), fully linked, else it uses the flags given */
-struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct Base *base, int dupflag);
+struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, int dupflag);
void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr);
@@ -118,9 +125,13 @@ enum {
EM_FREEDATA = (1 << 0),
EM_WAITCURSOR = (1 << 1),
EM_IGNORE_LAYER = (1 << 3),
+ EM_NO_CONTEXT = (1 << 4),
};
-bool ED_object_editmode_exit_ex(struct Main *bmain, struct Scene *scene, struct Object *obedit, int flag);
+bool ED_object_editmode_exit_ex(
+ struct Main *bmain, struct Scene *scene, struct Object *obedit, int flag);
bool ED_object_editmode_exit(struct bContext *C, int flag);
+
+bool ED_object_editmode_enter_ex(struct Main *bmain, struct Scene *scene, struct Object *ob, int flag);
bool ED_object_editmode_enter(struct bContext *C, int flag);
bool ED_object_editmode_load(struct Main *bmain, struct Object *obedit);
@@ -128,11 +139,11 @@ bool ED_object_editmode_calc_active_center(struct Object *obedit, const bool sel
void ED_object_vpaintmode_enter_ex(
- struct Main *bmain, struct wmWindowManager *wm,
+ struct Main *bmain, struct Depsgraph *depsgraph, struct wmWindowManager *wm,
struct Scene *scene, struct Object *ob);
void ED_object_vpaintmode_enter(struct bContext *C);
void ED_object_wpaintmode_enter_ex(
- struct Main *bmain, struct wmWindowManager *wm,
+ struct Main *bmain, struct Depsgraph *depsgraph, struct wmWindowManager *wm,
struct Scene *scene, struct Object *ob);
void ED_object_wpaintmode_enter(struct bContext *C);
@@ -142,10 +153,12 @@ void ED_object_wpaintmode_exit_ex(struct Object *ob);
void ED_object_wpaintmode_exit(struct bContext *C);
void ED_object_sculptmode_enter_ex(
- struct Main *bmain, struct Scene *scene, struct Object *ob,
+ struct Main *bmain, struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *ob,
struct ReportList *reports);
void ED_object_sculptmode_enter(struct bContext *C, struct ReportList *reports);
void ED_object_sculptmode_exit_ex(
+ struct Depsgraph *depsgraph,
struct Scene *scene, struct Object *ob);
void ED_object_sculptmode_exit(struct bContext *C);
@@ -161,17 +174,18 @@ float ED_object_new_primitive_matrix(
/* Avoid allowing too much insane values even by typing (typos can hang/crash Blender otherwise). */
#define OBJECT_ADD_SIZE_MAXF 1.0e12f
-void ED_object_add_unit_props(struct wmOperatorType *ot);
+void ED_object_add_unit_props_size(struct wmOperatorType *ot);
+void ED_object_add_unit_props_radius(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
void ED_object_add_mesh_props(struct wmOperatorType *ot);
bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, const char view_align_axis,
float loc[3], float rot[3],
- bool *enter_editmode, unsigned int *layer, bool *is_view_aligned);
+ bool *enter_editmode, bool *is_view_aligned);
struct Object *ED_object_add_type(
struct bContext *C,
int type, const char *name, const float loc[3], const float rot[3],
- bool enter_editmode, unsigned int layer)
+ bool enter_editmode)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
void ED_object_single_users(struct Main *bmain, struct Scene *scene, const bool full, const bool copy_groups);
@@ -179,7 +193,7 @@ void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Objec
/* object motion paths */
void ED_objects_clear_paths(struct bContext *C, bool only_selected);
-void ED_objects_recalculate_paths(struct bContext *C, struct Scene *scene);
+void ED_objects_recalculate_paths(struct bContext *C, struct Scene *scene, bool current_frame_only);
/* constraints */
struct ListBase *get_active_constraints(struct Object *ob);
@@ -200,6 +214,18 @@ bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports);
void ED_object_mode_toggle(struct bContext *C, eObjectMode mode);
void ED_object_mode_set(struct bContext *C, eObjectMode mode);
+void ED_object_mode_exit(struct bContext *C);
+
+bool ED_object_mode_generic_enter(
+ struct bContext *C,
+ eObjectMode object_mode);
+void ED_object_mode_generic_exit(
+ struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *ob);
+bool ED_object_mode_generic_has_data(
+ struct Depsgraph *depsgraph,
+ struct Object *ob);
/* object_modifier.c */
enum {
@@ -217,9 +243,10 @@ int ED_object_modifier_move_down(struct ReportList *reports, struct Object *ob,
int ED_object_modifier_move_up(struct ReportList *reports, struct Object *ob, struct ModifierData *md);
int ED_object_modifier_convert(
struct ReportList *reports, struct Main *bmain, struct Scene *scene,
- struct Object *ob, struct ModifierData *md);
-int ED_object_modifier_apply(struct Main *bmain, struct ReportList *reports, struct Scene *scene,
- struct Object *ob, struct ModifierData *md, int mode);
+ struct ViewLayer *view_layer, struct Object *ob, struct ModifierData *md);
+int ED_object_modifier_apply(
+ struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct ModifierData *md, int mode);
int ED_object_modifier_copy(struct ReportList *reports, struct Object *ob, struct ModifierData *md);
bool ED_object_iter_other(
@@ -229,6 +256,40 @@ bool ED_object_iter_other(
bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v);
+
+/* object_greasepencil_modifier.c */
+struct GpencilModifierData *ED_object_gpencil_modifier_add(
+ struct ReportList *reports, struct Main *bmain, struct Scene *scene,
+ struct Object *ob, const char *name, int type);
+bool ED_object_gpencil_modifier_remove(
+ struct ReportList *reports, struct Main *bmain,
+ struct Object *ob, struct GpencilModifierData *md);
+void ED_object_gpencil_modifier_clear(
+ struct Main *bmain, struct Object *ob);
+int ED_object_gpencil_modifier_move_down(
+ struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md);
+int ED_object_gpencil_modifier_move_up(
+ struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md);
+int ED_object_gpencil_modifier_apply(
+ struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph,
+ struct Object *ob, struct GpencilModifierData *md, int mode);
+int ED_object_gpencil_modifier_copy(
+ struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md);
+
+/* object_shader_fx.c */
+struct ShaderFxData *ED_object_shaderfx_add(
+ struct ReportList *reports, struct Main *bmain, struct Scene *scene,
+ struct Object *ob, const char *name, int type);
+bool ED_object_shaderfx_remove(
+ struct ReportList *reports, struct Main *bmain,
+ struct Object *ob, struct ShaderFxData *fx);
+void ED_object_shaderfx_clear(
+ struct Main *bmain, struct Object *ob);
+int ED_object_shaderfx_move_down(
+ struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx);
+int ED_object_shaderfx_move_up(
+ struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx);
+
/* object_select.c */
void ED_object_select_linked_by_id(struct bContext *C, struct ID *id);
@@ -242,6 +303,19 @@ const struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
void ED_object_check_force_modifiers(
struct Main *bmain, struct Scene *scene, struct Object *object);
+struct Base *ED_object_find_first_by_data_id(struct ViewLayer *view_layer, struct ID *id);
+
+bool ED_object_jump_to_object(
+ struct bContext *C, struct Object *ob,
+ const bool reveal_hidden);
+bool ED_object_jump_to_bone(
+ struct bContext *C, struct Object *ob, const char *bone_name,
+ const bool reveal_hidden);
+
+/* object_facemap_ops.c */
+void ED_object_facemap_face_add(struct Object *ob, struct bFaceMap *fmap, int facenum);
+void ED_object_facemap_face_remove(struct Object *ob, struct bFaceMap *fmap, int facenum);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index 73ee2542247..52fdeb2045c 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -27,4 +27,11 @@
#ifndef __ED_OUTLINER_H__
#define __ED_OUTLINER_H__
+struct bContext;
+struct ListBase;
+
+bool ED_outliner_collections_editor_poll(struct bContext *C);
+
+void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
+
#endif /* __ED_OUTLINER_H__ */
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 00111887332..7e7198a8ace 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -34,10 +34,12 @@
struct bContext;
struct Object;
+struct ParticleSystem;
struct ParticleEditSettings;
struct rcti;
struct PTCacheEdit;
struct Scene;
+struct ViewLayer;
struct UndoType;
/* particle edit mode */
@@ -45,21 +47,24 @@ void PE_free_ptcache_edit(struct PTCacheEdit *edit);
int PE_start_edit(struct PTCacheEdit *edit);
/* access */
-struct PTCacheEdit *PE_get_current(struct Main *bmain, struct Scene *scene, struct Object *ob);
-struct PTCacheEdit *PE_create_current(struct Main *bmain, struct Scene *scene, struct Object *ob);
-void PE_current_changed(struct Main *bmain, struct Scene *scene, struct Object *ob);
-int PE_minmax(struct Main *bmain, struct Scene *scene, float min[3], float max[3]);
+struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
+struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
+struct PTCacheEdit *PE_create_current(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+void PE_current_changed(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]);
struct ParticleEditSettings *PE_settings(struct Scene *scene);
/* update calls */
void PE_hide_keys_time(struct Scene *scene, struct PTCacheEdit *edit, float cfra);
-void PE_update_object(struct Main *bmain, struct Scene *scene, struct Object *ob, int useflag);
+void PE_update_object(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, int useflag);
/* selection tools */
int PE_mouse_particles(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-int PE_border_select(struct bContext *C, const struct rcti *rect, bool select, bool extend);
+int PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
int PE_circle_select(struct bContext *C, int selecting, const int mval[2], float rad);
-int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, bool extend, bool select);
+int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, const int sel_op);
void PE_deselect_all_visible(struct PTCacheEdit *edit);
/* particle_edit_undo.c */
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 707d7c6c693..2615847e90a 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -31,6 +31,7 @@
#include "DNA_vec_types.h"
struct bContext;
+struct DEGEditorUpdateContext;
struct ID;
struct Main;
struct MTex;
@@ -43,15 +44,16 @@ struct wmWindowManager;
void ED_operatortypes_render(void);
-/* render_shading.c */
+/* render_update.c */
-void ED_render_id_flush_update(struct Main *bmain, struct ID *id);
void ED_render_engine_changed(struct Main *bmain);
void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa);
-void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated);
-void ED_render_scene_update_pre(struct Main *bmain, struct Scene *scene, bool time);
-void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database);
+/* Callbacks handling data update events coming from depsgraph. */
+
+void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx, struct ID *id);
+void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, int updated);
+
struct Scene *ED_render_job_get_scene(const struct bContext *C);
struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h
new file mode 100644
index 00000000000..116d9bd24fc
--- /dev/null
+++ b/source/blender/editors/include/ED_scene.h
@@ -0,0 +1,41 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_scene.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_SCENE_H__
+#define __ED_SCENE_H__
+
+#include "BLI_compiler_attrs.h"
+
+enum eSceneCopyMethod;
+
+struct Scene *ED_scene_add(struct Main *bmain, struct bContext *C, struct wmWindow *win, enum eSceneCopyMethod method) ATTR_NONNULL();
+bool ED_scene_delete(struct bContext *C, struct Main *bmain, struct wmWindow *win, struct Scene *scene) ATTR_NONNULL();
+void ED_scene_change_update(struct Main *bmain, struct Scene *scene, struct ViewLayer *layer) ATTR_NONNULL();
+bool ED_scene_view_layer_delete(
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *layer,
+ struct ReportList *reports) ATTR_NONNULL(1, 2, 3);
+
+void ED_operatortypes_scene(void);
+
+#endif /* __ED_SCENE_H__ */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index b4d9a2629cf..a5660c43416 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -35,47 +35,97 @@
#include "DNA_space_types.h"
#include "DNA_view2d_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_object_enums.h"
+
+#include "BLI_compiler_attrs.h"
+
+struct Depsgraph;
struct wmWindowManager;
struct wmWindow;
struct wmNotifier;
struct wmEvent;
struct wmKeyConfig;
+struct WorkSpace;
+struct WorkSpaceInstanceHook;
struct bContext;
struct Scene;
+struct ViewLayer;
struct bScreen;
struct ARegion;
struct uiBlock;
struct rcti;
struct Main;
+struct wmMsgBus;
+struct wmMsgSubscribeKey;
+struct wmMsgSubscribeValue;
+struct wmOperatorType;
+struct IDProperty;
+struct MenuType;
+struct PropertyRNA;
/* regions */
-void ED_region_do_listen(struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, struct wmNotifier *note);
+void ED_region_do_listen(
+ struct wmWindow *win, struct ScrArea *sa, struct ARegion *ar,
+ struct wmNotifier *note, const Scene *scene);
+void ED_region_do_layout(struct bContext *C, struct ARegion *ar);
void ED_region_do_draw(struct bContext *C, struct ARegion *ar);
void ED_region_exit(struct bContext *C, struct ARegion *ar);
void ED_region_pixelspace(struct ARegion *ar);
-void ED_region_set(const struct bContext *C, struct ARegion *ar);
-void ED_region_update_rect(struct bContext *C, struct ARegion *ar);
-void ED_region_init(struct bContext *C, struct ARegion *ar);
+void ED_region_update_rect(struct ARegion *ar);
+void ED_region_init(struct ARegion *ar);
void ED_region_tag_redraw(struct ARegion *ar);
void ED_region_tag_redraw_partial(struct ARegion *ar, const struct rcti *rct);
void ED_region_tag_redraw_overlay(struct ARegion *ar);
+void ED_region_tag_redraw_no_rebuild(struct ARegion *ar);
void ED_region_tag_refresh_ui(struct ARegion *ar);
-void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *ar);
-void ED_region_panels(
- const struct bContext *C, struct ARegion *ar,
- const char *context, int contextnr,
- const bool vertical);
-void ED_region_header_init(struct ARegion *ar);
-void ED_region_header(const struct bContext *C, struct ARegion *ar);
+
+void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *ar);
+void ED_region_panels_ex(
+ const struct bContext *C, struct ARegion *ar,
+ const char *contexts[], int contextnr, const bool vertical);
+void ED_region_panels(
+ const struct bContext *C, struct ARegion *ar);
+void ED_region_panels_layout_ex(
+ const struct bContext *C, struct ARegion *ar,
+ const char *contexts[], int contextnr, const bool vertical);
+void ED_region_panels_layout(
+ const struct bContext *C, struct ARegion *ar);
+void ED_region_panels_draw(
+ const struct bContext *C, struct ARegion *ar);
+
+void ED_region_header_init(struct ARegion *ar);
+void ED_region_header(const struct bContext *C, struct ARegion *ar);
+void ED_region_header_layout(const struct bContext *C, struct ARegion *ar);
+void ED_region_header_draw(const struct bContext *C, struct ARegion *ar);
+
void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *sa, struct ARegion *ar);
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *ar);
+void ED_region_visibility_change_update(struct bContext *C, struct ARegion *ar);
void ED_region_info_draw(struct ARegion *ar, const char *text, float fill_color[4], const bool full_redraw);
+void ED_region_info_draw_multiline(ARegion *ar, const char *text_array[], float fill_color[4], const bool full_redraw);
void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
-float ED_region_blend_factor(struct ARegion *ar);
+float ED_region_blend_alpha(struct ARegion *ar);
void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
+bool ED_region_is_overlap(int spacetype, int regiontype);
+int ED_region_snap_size_test(const struct ARegion *ar);
+bool ED_region_snap_size_apply(struct ARegion *ar, int snap_flag);
+
+/* message_bus callbacks */
+void ED_region_do_msg_notify_tag_redraw(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+void ED_area_do_msg_notify_tag_refresh(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+
+/* message bus */
+void ED_region_message_subscribe(
+ struct bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus);
/* spaces */
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
@@ -85,17 +135,45 @@ int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *bl
void ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa);
void ED_area_exit(struct bContext *C, struct ScrArea *sa);
int ED_screen_area_active(const struct bContext *C);
-void ED_area_do_listen(struct bScreen *sc, ScrArea *sa, struct wmNotifier *note);
+void ED_screen_global_areas_refresh(struct wmWindow *win);
+void ED_screen_global_areas_sync(struct wmWindow *win);
+void ED_area_do_listen(struct wmWindow *win, ScrArea *sa, struct wmNotifier *note, Scene *scene);
void ED_area_tag_redraw(ScrArea *sa);
+void ED_area_tag_redraw_no_rebuild(ScrArea *sa);
void ED_area_tag_redraw_regiontype(ScrArea *sa, int type);
void ED_area_tag_refresh(ScrArea *sa);
void ED_area_do_refresh(struct bContext *C, ScrArea *sa);
void ED_area_azones_update(ScrArea *sa, const int mouse_xy[]);
-void ED_area_headerprint(ScrArea *sa, const char *str);
+void ED_area_status_text(ScrArea *sa, const char *str);
void ED_area_newspace(struct bContext *C, ScrArea *sa, int type, const bool skip_ar_exit);
void ED_area_prevspace(struct bContext *C, ScrArea *sa);
void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
int ED_area_headersize(void);
+int ED_area_header_alignment(const ScrArea *area);
+int ED_area_global_size_y(const ScrArea *area);
+int ED_area_global_min_size_y(const ScrArea *area);
+int ED_area_global_max_size_y(const ScrArea *area);
+bool ED_area_is_global(const ScrArea *area);
+int ED_region_global_size_y(void);
+void ED_area_update_region_sizes(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *area);
+
+ScrArea *ED_screen_areas_iter_first(const struct wmWindow *win, const bScreen *screen);
+ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
+/**
+ * Iterate over all areas visible in the screen (screen as in everything
+ * visible in the window, not just bScreen).
+ * \note Skips global areas with flag GLOBAL_AREA_IS_HIDDEN.
+ */
+#define ED_screen_areas_iter(win, screen, area_name) \
+ for (ScrArea *area_name = ED_screen_areas_iter_first(win, screen); \
+ area_name != NULL; \
+ area_name = ED_screen_areas_iter_next(screen, area_name))
+#define ED_screen_verts_iter(win, screen, vert_name) \
+ for (ScrVert *vert_name = (win)->global_areas.vertbase.first ? \
+ (win)->global_areas.vertbase.first : \
+ screen->vertbase.first; \
+ vert_name != NULL; \
+ vert_name = (vert_name == (win)->global_areas.vertbase.last) ? (screen)->vertbase.first : vert_name->next)
/* screens */
void ED_screens_initialize(struct Main *bmain, struct wmWindowManager *wm);
@@ -103,14 +181,11 @@ void ED_screen_draw_edges(struct wmWindow *win);
void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2);
void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac);
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
+void ED_screen_ensure_updated(struct wmWindowManager *wm, struct wmWindow *win, struct bScreen *screen);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
-bScreen *ED_screen_duplicate(struct Main *bmain, struct wmWindow *win, struct bScreen *sc);
-bScreen *ED_screen_add(struct Main *bmain, struct wmWindow *win, struct Scene *scene, const char *name);
-bool ED_screen_set(struct bContext *C, struct bScreen *sc);
-bool ED_screen_delete(struct bContext *C, struct bScreen *sc);
-void ED_screen_set_scene(struct bContext *C, struct bScreen *screen, struct Scene *scene);
-bool ED_screen_delete_scene(struct bContext *C, struct Scene *scene);
-void ED_screen_set_subwinactive(struct bContext *C, const struct wmEvent *event);
+bool ED_screen_change(struct bContext *C, struct bScreen *sc);
+void ED_screen_scene_change(struct bContext *C, struct wmWindow *win, struct Scene *scene);
+void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2]);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh);
@@ -120,10 +195,50 @@ void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
-bool ED_screen_stereo3d_required(struct bScreen *screen);
+void ED_screens_navigation_bar_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
+bool ED_screen_stereo3d_required(const struct bScreen *screen, const struct Scene *scene);
+Scene *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm);
+Scene *ED_screen_scene_find_with_window(const struct bScreen *screen, const struct wmWindowManager *wm, struct wmWindow **r_window);
+struct wmWindow *ED_screen_window_find(const struct bScreen *screen, const struct wmWindowManager *wm);
+void ED_screen_preview_render(const struct bScreen *screen, int size_x, int size_y, unsigned int *r_rect) ATTR_NONNULL();
+
+/* workspaces */
+struct WorkSpace *ED_workspace_add(
+ struct Main *bmain,
+ const char *name) ATTR_NONNULL();
+bool ED_workspace_change(
+ struct WorkSpace *workspace_new,
+ struct bContext *C,
+ struct wmWindowManager *wm, struct wmWindow *win) ATTR_NONNULL();
+struct WorkSpace *ED_workspace_duplicate(
+ struct WorkSpace *workspace_old,
+ struct Main *bmain, struct wmWindow *win);
+bool ED_workspace_delete(
+ struct WorkSpace *workspace,
+ struct Main *bmain, struct bContext *C,
+ struct wmWindowManager *wm) ATTR_NONNULL();
+void ED_workspace_scene_data_sync(
+ struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL();
+struct WorkSpaceLayout *ED_workspace_layout_add(
+ struct Main *bmain,
+ struct WorkSpace *workspace,
+ struct wmWindow *win,
+ const char *name) ATTR_NONNULL();
+struct WorkSpaceLayout *ED_workspace_layout_duplicate(
+ struct Main *bmain,
+ struct WorkSpace *workspace, const struct WorkSpaceLayout *layout_old,
+ struct wmWindow *win) ATTR_NONNULL();
+bool ED_workspace_layout_delete(
+ struct WorkSpace *workspace, struct WorkSpaceLayout *layout_old,
+ struct bContext *C) ATTR_NONNULL();
+bool ED_workspace_layout_cycle(
+ struct WorkSpace *workspace, const short direction,
+ struct bContext *C) ATTR_NONNULL();
+
+void ED_workspace_status_text(struct bContext *C, const char *str);
/* anim */
-void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute);
+void ED_update_for_newframe(struct Main *bmain, struct Depsgraph *depsgraph);
void ED_refresh_viewport_fps(struct bContext *C);
int ED_screen_animation_play(struct bContext *C, int sync, int mode);
@@ -133,6 +248,8 @@ bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/* screen keymaps */
void ED_operatortypes_screen(void);
void ED_keymap_screen(struct wmKeyConfig *keyconf);
+/* workspace keymaps */
+void ED_operatortypes_workspace(void);
/* operators; context poll callbacks */
bool ED_operator_screenactive(struct bContext *C);
@@ -147,7 +264,6 @@ bool ED_operator_objectmode(struct bContext *C);
bool ED_operator_view3d_active(struct bContext *C);
bool ED_operator_region_view3d_active(struct bContext *C);
bool ED_operator_animview_active(struct bContext *C);
-bool ED_operator_timeline_active(struct bContext *C);
bool ED_operator_outliner_active(struct bContext *C);
bool ED_operator_outliner_active_no_editobject(struct bContext *C);
bool ED_operator_file_active(struct bContext *C);
@@ -160,7 +276,6 @@ bool ED_operator_sequencer_active(struct bContext *C);
bool ED_operator_sequencer_active_editable(struct bContext *C);
bool ED_operator_image_active(struct bContext *C);
bool ED_operator_nla_active(struct bContext *C);
-bool ED_operator_logic_active(struct bContext *C);
bool ED_operator_info_active(struct bContext *C);
bool ED_operator_console_active(struct bContext *C);
@@ -172,6 +287,7 @@ bool ED_operator_object_active_editable_font(struct bContext *C);
bool ED_operator_editmesh(struct bContext *C);
bool ED_operator_editmesh_view3d(struct bContext *C);
bool ED_operator_editmesh_region_view3d(struct bContext *C);
+bool ED_operator_editmesh_auto_smooth(struct bContext *C);
bool ED_operator_editarmature(struct bContext *C);
bool ED_operator_editcurve(struct bContext *C);
bool ED_operator_editcurve_3d(struct bContext *C);
@@ -189,7 +305,37 @@ bool ED_operator_posemode_context(struct bContext *C);
bool ED_operator_posemode(struct bContext *C);
bool ED_operator_posemode_local(struct bContext *C);
bool ED_operator_mask(struct bContext *C);
+bool ED_operator_camera(struct bContext *C);
+
+/* screen_user_menu.c */
+
+struct bUserMenu *ED_screen_user_menu_find(struct bContext *C);
+struct bUserMenu *ED_screen_user_menu_ensure(struct bContext *C);
+
+
+struct bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(
+ struct ListBase *lb,
+ const struct wmOperatorType *ot, struct IDProperty *prop, short opcontext);
+struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(
+ struct ListBase *lb,
+ const struct MenuType *mt);
+struct bUserMenuItem_Prop *ED_screen_user_menu_item_find_prop(
+ struct ListBase *lb,
+ const char *context_data_path, const char *prop_id, int prop_index);
+void ED_screen_user_menu_item_add_operator(
+ struct ListBase *lb, const char *ui_name,
+ const struct wmOperatorType *ot, const struct IDProperty *prop, short opcontext);
+void ED_screen_user_menu_item_add_menu(
+ struct ListBase *lb, const char *ui_name,
+ const struct MenuType *mt);
+void ED_screen_user_menu_item_add_prop(
+ ListBase *lb, const char *ui_name,
+ const char *context_data_path, const char *prop_id, int prop_index);
+
+void ED_screen_user_menu_item_remove(
+ struct ListBase *lb, struct bUserMenuItem *umi);
+void ED_screen_user_menu_register(void);
/* Cache display helpers */
@@ -197,13 +343,35 @@ void ED_region_cache_draw_background(const struct ARegion *ar);
void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y);
void ED_region_cache_draw_cached_segments(const struct ARegion *ar, const int num_segments, const int *points, const int sfra, const int efra);
-/* default keymaps, bitflags */
-#define ED_KEYMAP_UI 1
-#define ED_KEYMAP_VIEW2D 2
-#define ED_KEYMAP_MARKERS 4
-#define ED_KEYMAP_ANIMATION 8
-#define ED_KEYMAP_FRAMES 16
-#define ED_KEYMAP_GPENCIL 32
-#define ED_KEYMAP_HEADER 64
+/* area_utils.c */
+void ED_region_generic_tools_region_message_subscribe(
+ const struct bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus);
+int ED_region_generic_tools_region_snap_size(const struct ARegion *ar, int size, int axis);
+
+/* interface_region_hud.c */
+struct ARegionType *ED_area_type_hud(int space_type);
+void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *sa_keep);
+void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *sa);
+
+/* default keymaps, bitflags (matches order of evaluation). */
+enum {
+ ED_KEYMAP_UI = (1 << 1),
+ ED_KEYMAP_GIZMO = (1 << 2),
+ ED_KEYMAP_VIEW2D = (1 << 3),
+ ED_KEYMAP_MARKERS = (1 << 4),
+ ED_KEYMAP_ANIMATION = (1 << 5),
+ ED_KEYMAP_FRAMES = (1 << 6),
+ ED_KEYMAP_HEADER = (1 << 7),
+ ED_KEYMAP_GPENCIL = (1 << 8),
+};
+
+/* SCREEN_OT_space_context_cycle direction */
+enum {
+ SPACE_CONTEXT_CYCLE_PREV,
+ SPACE_CONTEXT_CYCLE_NEXT,
+};
#endif /* __ED_SCREEN_H__ */
diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h
index 2b1ce461b0e..8ef7fee0f32 100644
--- a/source/blender/editors/include/ED_screen_types.h
+++ b/source/blender/editors/include/ED_screen_types.h
@@ -83,13 +83,22 @@ typedef enum {
AE_BOTTOM_TO_TOPLEFT /* Region located at the top, _bottom_ edge is action zone. Region minimized to the top left */
} AZEdge;
+typedef enum {
+ AZ_SCROLL_VERT,
+ AZ_SCROLL_HOR,
+} AZScrollDirection;
+
/* for editing areas/regions */
typedef struct AZone {
struct AZone *next, *prev;
ARegion *ar;
int type;
- /* region-azone, which of the edges (only for AZONE_REGION) */
- AZEdge edge;
+
+ union {
+ /* region-azone, which of the edges (only for AZONE_REGION) */
+ AZEdge edge;
+ AZScrollDirection direction;
+ };
/* for draw */
short x1, y1, x2, y2;
/* for clip */
@@ -99,8 +108,15 @@ typedef struct AZone {
} AZone;
/* actionzone type */
-#define AZONE_AREA 1 /* corner widgets for splitting areas */
-#define AZONE_REGION 2 /* when a region is collapsed, draw a handle to expose */
-#define AZONE_FULLSCREEN 3 /* when in editor fullscreen draw a corner to go to normal mode */
+enum {
+ /* corner widgets for splitting areas */
+ AZONE_AREA = 1,
+ /* when a region is collapsed, draw a handle to expose */
+ AZONE_REGION,
+ /* when in editor fullscreen draw a corner to go to normal mode */
+ AZONE_FULLSCREEN,
+ /* Hotspot azone around scrollbars to show/hide them. */
+ AZONE_REGION_SCROLL,
+};
#endif /* __ED_SCREEN_TYPES_H__ */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index ee2eff3ebba..94508a98dcb 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -42,9 +42,8 @@ struct ListBase;
/* sculpt.c */
void ED_operatortypes_sculpt(void);
-void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar,
- struct RegionView3D *rv3d, struct Object *ob);
-int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend);
+void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar, struct Object *ob);
+int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select);
/* sculpt_undo.c */
void ED_sculpt_undosys_type(struct UndoType *ut);
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
new file mode 100644
index 00000000000..d7f55e2a2d6
--- /dev/null
+++ b/source/blender/editors/include/ED_select_utils.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_select_utils.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_SELECT_UTILS_H__
+#define __ED_SELECT_UTILS_H__
+
+struct KDTree;
+
+enum {
+ SEL_TOGGLE = 0,
+ SEL_SELECT = 1,
+ SEL_DESELECT = 2,
+ SEL_INVERT = 3,
+};
+
+/** See #WM_operator_properties_select_operation */
+typedef enum {
+ SEL_OP_ADD = 1,
+ SEL_OP_SUB,
+ SEL_OP_SET,
+ SEL_OP_AND,
+ SEL_OP_XOR,
+} eSelectOp;
+
+/* Select Similar */
+enum {
+ SIM_CMP_EQ = 0,
+ SIM_CMP_GT,
+ SIM_CMP_LT
+};
+
+#define SEL_OP_USE_OUTSIDE(sel_op) (ELEM(sel_op, SEL_OP_AND))
+#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET))
+#define SEL_OP_CAN_DESELECT(sel_op) (!ELEM(sel_op, SEL_OP_ADD))
+
+/* Use when we've de-selected all first for 'SEL_OP_SET' */
+int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside);
+int ED_select_op_action_deselected(const eSelectOp sel_op, const bool is_select, const bool is_inside);
+
+int ED_select_similar_compare_float(const float delta, const float thresh, const int compare);
+bool ED_select_similar_compare_float_tree(const struct KDTree *tree, const float length, const float thresh, const int compare);
+#endif /* __ED_SELECT_UTILS_H__ */
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index ff9e66ea151..709af6e8b09 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -41,7 +41,6 @@ void ED_spacemacros_init(void);
/* calls for registering default spaces */
void ED_spacetype_outliner(void);
-void ED_spacetype_time(void);
void ED_spacetype_view3d(void);
void ED_spacetype_ipo(void);
void ED_spacetype_image(void);
@@ -58,6 +57,8 @@ void ED_spacetype_logic(void);
void ED_spacetype_console(void);
void ED_spacetype_userpref(void);
void ED_spacetype_clip(void);
+void ED_spacetype_statusbar(void);
+void ED_spacetype_topbar(void);
/* calls for instancing and freeing spacetype static data
* called in WM_init_exit */
@@ -74,7 +75,6 @@ void *ED_region_draw_cb_activate(struct ARegionType *,
void *custumdata, int type);
void ED_region_draw_cb_draw(const struct bContext *, struct ARegion *, int);
void ED_region_draw_cb_exit(struct ARegionType *, void *);
-void *ED_region_draw_cb_customdata(void *handle);
/* generic callbacks */
/* ed_util.c */
void ED_region_draw_mouse_line_cb(const struct bContext *C, struct ARegion *ar, void *arg_info);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 9a0a7f8f1bb..718c8a48300 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -43,11 +43,12 @@ struct wmEvent;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperatorType;
+struct WorkSpace;
struct Main;
struct SnapObjectContext;
struct SnapObjectParams;
-void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid);
+void ED_keymap_transform(struct wmKeyConfig *keyconf);
void transform_operatortypes(void);
/* ******************** Macros & Prototypes *********************** */
@@ -88,6 +89,7 @@ enum TfmMode {
TFM_VERT_SLIDE,
TFM_SEQ_SLIDE,
TFM_BONE_ENVELOPE_DIST,
+ TFM_NORMAL_ROTATION,
};
/* TRANSFORM CONTEXTS */
@@ -101,6 +103,7 @@ enum TfmMode {
#define CTX_MASK (1 << 7)
#define CTX_PAINT_CURVE (1 << 8)
#define CTX_GPENCIL_STROKES (1 << 9)
+#define CTX_CURSOR (1 << 10)
/* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection)
@@ -109,9 +112,10 @@ enum TfmMode {
bool calculateTransformCenter(struct bContext *C, int centerMode, float cent3d[3], float cent2d[2]);
struct TransInfo;
-struct Base;
struct Scene;
struct Object;
+struct wmGizmoGroup;
+struct wmGizmoGroupType;
struct wmOperator;
/* UNUSED */
@@ -128,7 +132,7 @@ void BIF_createTransformOrientation(struct bContext *C, struct ReportList *repor
const char *name, const bool use_view,
const bool activate, const bool overwrite);
void BIF_selectTransformOrientation(struct bContext *C, struct TransformOrientation *ts);
-void BIF_selectTransformOrientationValue(struct bContext *C, int orientation);
+void BIF_selectTransformOrientationValue(struct Scene *scene, int orientation);
void ED_getTransformOrientationMatrix(const struct bContext *C, float orientation_mat[3][3], const short around);
@@ -140,6 +144,7 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_MIRROR_DUMMY (P_MIRROR | (1 << 9))
#define P_PROPORTIONAL (1 << 1)
#define P_AXIS (1 << 2)
+#define P_AXIS_ORTHO (1 << 16)
#define P_SNAP (1 << 3)
#define P_GEO_SNAP (P_SNAP | (1 << 4))
#define P_ALIGN_SNAP (P_GEO_SNAP | (1 << 5))
@@ -150,17 +155,30 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_NO_TEXSPACE (1 << 11)
#define P_CENTER (1 << 12)
#define P_GPENCIL_EDIT (1 << 13)
+#define P_CURSOR_EDIT (1 << 14)
+#define P_CLNOR_INVALIDATE (1 << 15)
void Transform_Properties(struct wmOperatorType *ot, int flags);
-/* view3d manipulators */
+/* transform gizmos */
+
+void TRANSFORM_GGT_gizmo(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_xform_cage(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_xform_shear(struct wmGizmoGroupType *gzgt);
+
+/* *** transform_gizmo_extrude_3d.c *** */
+void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt);
+
+bool ED_widgetgroup_gizmo2d_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt);
+void ED_widgetgroup_gizmo2d_setup(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup);
+void ED_widgetgroup_gizmo2d_draw_prepare(const struct bContext *C, struct wmGizmoGroup *gzgroup);
-int BIF_do_manipulator(struct bContext *C, const struct wmEvent *event, struct wmOperator *op);
-void BIF_draw_manipulator(const struct bContext *C);
/* Snapping */
#define SNAP_MIN_DISTANCE 30
+#define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0)
bool peelObjectsTransform(
struct TransInfo *t,
@@ -186,4 +204,32 @@ bool snapNodesTransform(
/* return args */
float r_loc[2], float *r_dist_px, char *r_node_border);
+void ED_transform_calc_orientation_from_type(
+ const struct bContext *C, float r_mat[3][3]);
+ void ED_transform_calc_orientation_from_type_ex(
+ const struct bContext *C, float r_mat[3][3],
+ /* extra args */
+ struct Scene *scene, struct RegionView3D *rv3d, struct Object *ob, struct Object *obedit,
+ const short orientation_type, const int pivot_point);
+
+struct TransformBounds {
+ float center[3]; /* Center for transform widget. */
+ float min[3], max[3]; /* Boundbox of selection for transform widget. */
+
+ /* Normalized axis */
+ float axis[3][3];
+ float axis_min[3], axis_max[3];
+};
+
+struct TransformCalcParams {
+ uint use_only_center : 1;
+ uint use_local_axis : 1;
+ /* Use 'Scene.orientation_type' when zero, otherwise subtract one and use. */
+ ushort orientation_type;
+};
+int ED_transform_calc_gizmo_stats(
+ const struct bContext *C,
+ const struct TransformCalcParams *params,
+ struct TransformBounds *tbounds);
+
#endif /* __ED_TRANSFORM_H__ */
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index c20d92963a9..8ac7dfcf9d8 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -29,12 +29,15 @@ struct BMVert;
struct BMEdge;
struct BMFace;
+struct Depsgraph;
struct ListBase;
struct Scene;
+struct ViewLayer;
struct Main;
struct Object;
struct ARegion;
struct View3D;
+struct bContext;
/* transform_snap_object.c */
@@ -69,13 +72,16 @@ struct SnapObjectParams {
char snap_select;
/* use editmode cage */
unsigned int use_object_edit_cage : 1;
+ /* snap to the closest element, use when using more than one snap type */
+ unsigned int use_occlusion_test : 1;
+
};
typedef struct SnapObjectContext SnapObjectContext;
SnapObjectContext *ED_transform_snap_object_context_create(
- struct Main *bmain, struct Scene *scene, int flag);
+ struct Main *bmain, struct Scene *scene, struct Depsgraph *depsgraph, int flag);
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
- struct Main *bmain, struct Scene *scene, int flag,
+ struct Main *bmain, struct Scene *scene, struct Depsgraph *depsgraph, int flag,
/* extra args for view3d */
const struct ARegion *ar, const struct View3D *v3d);
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
@@ -113,7 +119,6 @@ bool ED_transform_snap_object_project_view3d_ex(
const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
- float *ray_depth,
float r_loc[3], float r_no[3], int *r_index,
struct Object **r_ob, float r_obmat[4][4]);
bool ED_transform_snap_object_project_view3d(
@@ -121,16 +126,8 @@ bool ED_transform_snap_object_project_view3d(
const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
- float *ray_depth,
/* return args */
float r_loc[3], float r_no[3]);
-bool ED_transform_snap_object_project_view3d_mixed(
- SnapObjectContext *sctx,
- const unsigned short snap_to_flag,
- const struct SnapObjectParams *params,
- const float mval_fl[2], float *dist_px,
- bool use_depth,
- float r_co[3], float r_no[3]);
bool ED_transform_snap_object_project_all_view3d_ex(
SnapObjectContext *sctx,
diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h
index 784ae33f3b0..7995644f39e 100644
--- a/source/blender/editors/include/ED_undo.h
+++ b/source/blender/editors/include/ED_undo.h
@@ -25,7 +25,10 @@
#ifndef __ED_UNDO_H__
#define __ED_UNDO_H__
+#include "BLI_compiler_attrs.h"
+
struct bContext;
+struct CLG_LogRef;
struct wmOperator;
struct wmOperatorType;
struct UndoStack;
@@ -53,6 +56,10 @@ bool ED_undo_is_valid(const struct bContext *C, const char *undoname);
struct UndoStack *ED_undo_stack_get(void);
+/* helpers */
+void ED_undo_object_set_active_or_warn(
+ struct ViewLayer *view_layer, struct Object *ob, const char *info, struct CLG_LogRef *log);
+
/* undo_system_types.c */
void ED_undosys_type_init(void);
void ED_undosys_type_free(void);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 741c586d41f..7e91b5b88c1 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -31,11 +31,10 @@
#ifndef __ED_UTIL_H__
#define __ED_UTIL_H__
+#include "BLI_compiler_attrs.h"
+
struct bContext;
struct wmOperatorType;
-struct ScrArea;
-struct SpaceLink;
-struct PackedFile;
/* ed_util.c */
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index e9398bbd94c..f7d647bd89c 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -35,12 +35,14 @@ struct BMesh;
struct BMEditMesh;
struct BMFace;
struct BMLoop;
+struct Depsgraph;
struct Image;
struct ImageUser;
-struct MTexPoly;
struct Main;
struct Object;
struct Scene;
+struct View3D;
+struct ViewLayer;
struct SpaceImage;
struct bNode;
struct wmKeyConfig;
@@ -49,11 +51,15 @@ struct wmKeyConfig;
void ED_operatortypes_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
-void ED_uvedit_assign_image(
- struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
+bool ED_uvedit_center(Scene *scene, Image *ima, struct Object *obedit, float cent[2], char mode);
void ED_uvedit_select_all(struct BMesh *bm);
+bool ED_uvedit_minmax_multi(
+ struct Scene *scene, struct Image *ima, struct Object **objects_edit, uint objects_len, float r_min[2], float r_max[2]);
+bool ED_uvedit_center_multi(
+ Scene *scene, Image *ima, struct Object **objects_edit, uint objects_len, float r_cent[2], char mode);
+
bool ED_object_get_active_image(
struct Object *ob, int mat_nr,
struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
@@ -62,7 +68,8 @@ void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int ma
bool ED_uvedit_test(struct Object *obedit);
/* visibility and selection */
-bool uvedit_face_visible_test(struct Scene *scene, struct Image *ima, struct BMFace *efa, struct MTexPoly *tf);
+bool uvedit_face_visible_test(
+ struct Scene *scene, struct Object *obedit, struct Image *ima, struct BMFace *efa);
bool uvedit_face_select_test(
struct Scene *scene, struct BMFace *efa,
const int cd_loop_uv_offset);
@@ -104,8 +111,12 @@ void uvedit_uv_select_disable(
const int cd_loop_uv_offset);
bool ED_uvedit_nearest_uv(
- struct Scene *scene, struct Object *obedit, struct Image *ima,
- const float co[2], float r_uv[2]);
+ struct Scene *scene, struct Object *obedit, struct Image *ima, const float co[2],
+ float *dist_sq, float r_uv[2]);
+bool ED_uvedit_nearest_uv_multi(
+ struct Scene *scene, struct Image *ima,
+ struct Object **objects, const uint objects_len, const float co[2],
+ float *dist_sq, float r_uv[2]);
void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
@@ -116,21 +127,24 @@ void ED_uvedit_live_unwrap_end(short cancel);
void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit);
void ED_uvedit_pack_islands(
- struct Scene *scene, struct Object *ob, struct BMesh *bm,
+ struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
+void ED_uvedit_pack_islands_multi(
+ struct Scene *scene, struct Object **objects, const uint objects_len,
bool selected, bool correct_aspect, bool do_rotate);
void ED_uvedit_unwrap_cube_project(
struct BMesh *bm, float cube_size, bool use_select, const float center[3]);
/* single call up unwrap using scene settings, used for edge tag unwrapping */
-void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
+void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel, const bool pack);
/* uvedit_draw.c */
void ED_image_draw_cursor(
- struct ARegion *ar, const float cursor[2]);
+ struct ARegion *ar, const float cursor[2]);
void ED_uvedit_draw_main(
- struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene,
- struct Object *obedit, struct Object *obact);
+ struct SpaceImage *sima,
+ struct ARegion *ar, struct Scene *scene, struct ViewLayer *view_layer,
+ struct Object *obedit, struct Object *obact, struct Depsgraph *depsgraph);
/* uvedit_buttons.c */
void ED_uvedit_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index c21a6cccb2e..0e9c2cf3759 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -40,6 +40,8 @@ struct BPoint;
struct Base;
struct BezTriple;
struct BoundBox;
+struct Camera;
+struct Depsgraph;
struct EditBone;
struct ImBuf;
struct MVert;
@@ -49,14 +51,15 @@ struct Nurb;
struct Object;
struct RV3DMatrixStore;
struct RegionView3D;
+struct RenderEngineType;
struct Scene;
+struct ViewLayer;
struct ScrArea;
struct View3D;
struct ViewContext;
struct bContext;
struct bPoseChannel;
struct bScreen;
-struct bglMats;
struct rctf;
struct rcti;
struct wmOperator;
@@ -66,12 +69,17 @@ struct wmWindowManager;
struct GPUFX;
struct GPUOffScreen;
struct GPUFXSettings;
+struct GPUViewport;
+struct WorkSpace;
enum eGPUFXFlags;
/* for derivedmesh drawing callbacks, for view3d_select, .... */
typedef struct ViewContext {
+ struct bContext *C;
struct Main *bmain;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
+ struct ViewLayer *view_layer;
struct Object *obact;
struct Object *obedit;
struct ARegion *ar;
@@ -91,17 +99,41 @@ typedef struct ViewDepths {
bool damaged;
} ViewDepths;
-float *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d);
-void ED_view3d_cursor3d_position(struct bContext *C, const int mval[2], float cursor_co[3]);
-void ED_view3d_cursor3d_update(struct bContext *C, const int mval[2]);
+
+/* Rotate 3D cursor on placement. */
+enum eV3DCursorOrient {
+ V3D_CURSOR_ORIENT_NONE = 0,
+ V3D_CURSOR_ORIENT_VIEW,
+ V3D_CURSOR_ORIENT_XFORM,
+ V3D_CURSOR_ORIENT_GEOM,
+};
+
+void ED_view3d_background_color_get(const struct Scene *scene, const struct View3D *v3d, float r_color[3]);
+void ED_view3d_cursor3d_calc_mat3(const struct Scene *scene, float mat[3][3]);
+void ED_view3d_cursor3d_calc_mat4(const struct Scene *scene, float mat[4][4]);
+void ED_view3d_cursor3d_position(
+ struct bContext *C, const int mval[2],
+ const bool use_depth,
+ float cursor_co[3]);
+void ED_view3d_cursor3d_position_rotation(
+ struct bContext *C, const int mval[2],
+ const bool use_depth, enum eV3DCursorOrient orientation,
+ float cursor_co[3], float cursor_quat[4]);
+void ED_view3d_cursor3d_update(
+ struct bContext *C, const int mval[2],
+ const bool use_depth, enum eV3DCursorOrient orientation);
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist);
-void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist);
+void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], float *dist);
-void ED_view3d_from_object(struct Object *ob, float ofs[3], float quat[4], float *dist, float *lens);
-void ED_view3d_to_object(struct Object *ob, const float ofs[3], const float quat[4], const float dist);
+void ED_view3d_from_object(
+ const struct Object *ob,
+ float ofs[3], float quat[4], float *dist, float *lens);
+void ED_view3d_to_object(
+ const struct Depsgraph *depsgraph, struct Object *ob,
+ const float ofs[3], const float quat[4], const float dist);
void ED_view3d_lastview_store(struct RegionView3D *rv3d);
@@ -109,10 +141,10 @@ void ED_view3d_lastview_store(struct RegionView3D *rv3d);
void ED_view3d_depth_update(struct ARegion *ar);
float ED_view3d_depth_read_cached(const struct ViewContext *vc, const int mval[2]);
bool ED_view3d_depth_read_cached_normal(
- const ViewContext *vc, const struct bglMats *mats, const int mval[2],
+ const ViewContext *vc, const int mval[2],
float r_normal[3]);
bool ED_view3d_depth_unproject(
- const struct ARegion *ar, const struct bglMats *mats,
+ const struct ARegion *ar,
const int mval[2], const double depth,
float r_location_world[3]);
void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
@@ -222,9 +254,11 @@ float ED_view3d_pixel_size_no_ui_scale(const struct RegionView3D *rv3d, const fl
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]);
bool ED_view3d_win_to_ray_clipped(
+ struct Depsgraph *depsgraph,
const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
float ray_start[3], float ray_normal[3], const bool do_clip);
bool ED_view3d_win_to_ray_clipped_ex(
+ struct Depsgraph *depsgraph,
const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
void ED_view3d_win_to_ray(
@@ -251,11 +285,14 @@ void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float
void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]);
void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]);
bool ED_view3d_win_to_segment_clipped(
+ struct Depsgraph *depsgraph,
const struct ARegion *ar, struct View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_end[3], const bool do_clip);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
void ED_view3d_ob_project_mat_get_from_obmat(const struct RegionView3D *rv3d, float obmat[4][4], float pmat[4][4]);
-void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, const float y, const float z);
+
+void ED_view3d_project(const struct ARegion *ar, const float world[3], float region[3]);
+bool ED_view3d_unproject(const struct ARegion *ar, float regionx, float regiony, float regionz, float world[3]);
/* end */
@@ -264,28 +301,34 @@ void ED_view3d_dist_range_get(
const struct View3D *v3d,
float r_dist_range[2]);
bool ED_view3d_clip_range_get(
+ struct Depsgraph *depsgraph,
const struct View3D *v3d, const struct RegionView3D *rv3d,
float *r_clipsta, float *r_clipend, const bool use_ortho_factor);
bool ED_view3d_viewplane_get(
+ struct Depsgraph *depsgraph,
const struct View3D *v3d, const struct RegionView3D *rv3d, int winxi, int winyi,
struct rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize);
void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist);
void ED_view3d_calc_camera_border(
- const struct Scene *scene, const struct ARegion *ar,
+ const struct Scene *scene, struct Depsgraph *depsgraph,
+ const struct ARegion *ar,
const struct View3D *v3d, const struct RegionView3D *rv3d,
struct rctf *r_viewborder, const bool no_shift);
void ED_view3d_calc_camera_border_size(
- const struct Scene *scene, const struct ARegion *ar,
+ const struct Scene *scene, struct Depsgraph *depsgraph,
+ const struct ARegion *ar,
const struct View3D *v3d, const struct RegionView3D *rv3d,
float r_size[2]);
bool ED_view3d_calc_render_border(
- const struct Scene *scene, const struct View3D *v3d,
- const struct ARegion *ar, struct rcti *rect);
+ const struct Scene *scene, struct Depsgraph *depsgraph,
+ struct View3D *v3d,
+ struct ARegion *ar, struct rcti *rect);
void ED_view3d_clipping_calc_from_boundbox(float clip[6][4], const struct BoundBox *clipbb, const bool is_flip);
-void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, const struct rcti *rect);
+void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4],
+ const struct ARegion *ar, const struct Object *ob, const struct rcti *rect);
void ED_view3d_clipping_local(struct RegionView3D *rv3d, float mat[4][4]);
bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], const bool is_local);
void ED_view3d_clipping_set(struct RegionView3D *rv3d);
@@ -296,27 +339,32 @@ float ED_view3d_radius_to_dist_persp(const float angle, const float radius);
float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
float ED_view3d_radius_to_dist(
const struct View3D *v3d, const struct ARegion *ar,
+ const struct Depsgraph *depsgraph,
const char persp, const bool use_aspect,
const float radius);
-void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4]);
+void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos);
/* backbuffer select and draw support */
+void ED_view3d_backbuf_validate_with_select_mode(struct ViewContext *vc, short select_mode);
void ED_view3d_backbuf_validate(struct ViewContext *vc);
-struct ImBuf *ED_view3d_backbuf_read(struct ViewContext *vc, int xmin, int ymin, int xmax, int ymax);
+struct ImBuf *ED_view3d_backbuf_read(
+ struct ViewContext *vc, int xmin, int ymin, int xmax, int ymax);
unsigned int ED_view3d_backbuf_sample_rect(
struct ViewContext *vc, const int mval[2], int size,
unsigned int min, unsigned int max, float *r_dist);
int ED_view3d_backbuf_sample_size_clamp(struct ARegion *ar, const float dist);
-unsigned int ED_view3d_backbuf_sample(struct ViewContext *vc, int x, int y);
+unsigned int ED_view3d_backbuf_sample(
+ struct ViewContext *vc, int x, int y);
bool ED_view3d_autodist(
- struct Main *bmain, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
+ struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d,
const int mval[2], float mouse_worldloc[3],
const bool alphaoverride, const float fallback_depth_pt[3]);
/* only draw so ED_view3d_autodist_simple can be called many times after */
-void ED_view3d_autodist_init(struct Main *bmain, struct Scene *scene, struct ARegion *ar, struct View3D *v3d, int mode);
+void ED_view3d_autodist_init(
+ struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, int mode);
bool ED_view3d_autodist_simple(struct ARegion *ar, const int mval[2], float mouse_worldloc[3], int margin, float *force_depth);
bool ED_view3d_autodist_depth(struct ARegion *ar, const int mval[2], int margin, float *depth);
bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], const int mval_end[2], int margin, float *depth);
@@ -334,20 +382,31 @@ typedef enum {
VIEW3D_SELECT_PICK_NEAREST = 2,
} eV3DSelectMode;
+typedef enum {
+ /** Don't exclude anything. */
+ VIEW3D_SELECT_FILTER_NOP = 0,
+ /** Don't select objects outside the current mode. */
+ VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK = 1,
+ /** A version of #VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK that allows pose-bone selection. */
+ VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK = 2,
+} eV3DSelectObjectFilter;
+
+eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *scene, const struct Object *obact);
+
void view3d_opengl_select_cache_begin(void);
void view3d_opengl_select_cache_end(void);
int view3d_opengl_select(
struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input,
- eV3DSelectMode select_mode);
+ eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter);
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc);
+void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
void view3d_opengl_read_pixels(struct ARegion *ar, int x, int y, int w, int h, int format, int type, void *data);
-void view3d_get_transformation(const struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob, struct bglMats *mats);
/* XXX should move to BLI_math */
bool edge_inside_circle(const float cent[2], float radius, const float screen_co_a[2], const float screen_co_b[2]);
@@ -366,51 +425,60 @@ void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d);
# define ED_view3d_clear_mats_rv3d(rv3d) (void)(rv3d)
# define ED_view3d_check_mats_rv3d(rv3d) (void)(rv3d)
#endif
-int ED_view3d_scene_layer_set(int lay, const bool *values, int *active);
+int ED_view3d_view_layer_set(int lay, const bool *values, int *active);
struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d);
void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat);
+void ED_draw_object_facemap(
+ struct Depsgraph *depsgraph, struct Object *ob, const float col[4], const int facemap);
+
+struct RenderEngineType *ED_view3d_engine_type(struct Scene *scene, int drawtype);
+
bool ED_view3d_context_activate(struct bContext *C);
-void ED_view3d_draw_offscreen_init(struct Main *bmain, struct Scene *scene, struct View3D *v3d);
void ED_view3d_draw_offscreen(
- struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
- float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
- struct GPUFX *fx, struct GPUFXSettings *fx_settings,
- struct GPUOffScreen *ofs);
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ int drawtype,
+ struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
+ float winmat[4][4], bool do_sky, bool is_persp, const char *viewname,
+ struct GPUFXSettings *fx_settings,
+ struct GPUOffScreen *ofs, struct GPUViewport *viewport);
void ED_view3d_draw_setup_view(
- struct wmWindow *win, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
+ struct wmWindow *win, struct Depsgraph *depsgraph, struct Scene *scene, struct ARegion *ar, struct View3D *v3d,
float viewmat[4][4], float winmat[4][4], const struct rcti *rect);
enum {
V3D_OFSDRAW_NONE = (0),
- V3D_OFSDRAW_USE_BACKGROUND = (1 << 0),
- V3D_OFSDRAW_USE_FULL_SAMPLE = (1 << 1),
+ V3D_OFSDRAW_USE_FULL_SAMPLE = (1 << 0),
/* Only works with ED_view3d_draw_offscreen_imbuf_simple(). */
- V3D_OFSDRAW_USE_GPENCIL = (1 << 2),
+ V3D_OFSDRAW_USE_GPENCIL = (1 << 1),
V3D_OFSDRAW_USE_SOLID_TEX = (1 << 2),
V3D_OFSDRAW_USE_CAMERA_DOF = (1 << 3),
};
struct ImBuf *ED_view3d_draw_offscreen_imbuf(
- struct Main *bmain, struct Scene *scene,
- struct View3D *v3d, struct ARegion *ar, int sizex, int sizey,
- unsigned int flag, unsigned int draw_flags,
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ int drawtype,
+ struct View3D *v3d, struct ARegion *ar,
+ int sizex, int sizey, unsigned int flag, unsigned int draw_flags,
int alpha_mode, int samples, const char *viewname,
- struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
+ struct GPUOffScreen *ofs, char err_out[256]);
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
- struct Main *bmain, struct Scene *scene,
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ int drawtype,
struct Object *camera, int width, int height,
- unsigned int flag, unsigned int draw_flags, int drawtype, int alpha_mode,
+ unsigned int flag, unsigned int draw_flags, int alpha_mode,
int samples, const char *viewname,
- struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
+ struct GPUOffScreen *ofs, char err_out[256]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
+struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
+bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
void ED_view3d_update_viewmat(
- struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
float viewmat[4][4], float winmat[4][4], const struct rcti *rect);
bool ED_view3d_quat_from_axis_view(const char view, float quat[4]);
char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon);
@@ -419,20 +487,28 @@ char ED_view3d_axis_view_opposite(char view);
bool ED_view3d_lock(struct RegionView3D *rv3d);
uint64_t ED_view3d_datamask(const struct Scene *scene, const struct View3D *v3d);
-uint64_t ED_view3d_screen_datamask(const struct bScreen *screen);
+uint64_t ED_view3d_screen_datamask(const struct Scene *scene, const struct bScreen *screen);
bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
-void ED_view3d_persp_switch_from_camera(struct View3D *v3d, struct RegionView3D *rv3d, const char persp);
-bool ED_view3d_persp_ensure(struct View3D *v3d, struct ARegion *ar);
+void ED_view3d_persp_switch_from_camera(
+ const struct Depsgraph *depsgraph,
+ struct View3D *v3d, struct RegionView3D *rv3d, const char persp);
+bool ED_view3d_persp_ensure(
+ const struct Depsgraph *depsgraph,
+ struct View3D *v3d, struct ARegion *ar);
/* camera lock functions */
bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionView3D *rv3d);
/* copy the camera to the view before starting a view transformation */
-void ED_view3d_camera_lock_init_ex(struct View3D *v3d, struct RegionView3D *rv3d, const bool calc_dist);
-void ED_view3d_camera_lock_init(struct View3D *v3d, struct RegionView3D *rv3d);
+void ED_view3d_camera_lock_init_ex(
+ const struct Depsgraph *depsgraph,
+ struct View3D *v3d, struct RegionView3D *rv3d, const bool calc_dist);
+void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph, struct View3D *v3d, struct RegionView3D *rv3d);
/* copy the view to the camera, return true if */
-bool ED_view3d_camera_lock_sync(struct View3D *v3d, struct RegionView3D *rv3d);
+bool ED_view3d_camera_lock_sync(
+ const struct Depsgraph *depsgraph,
+ struct View3D *v3d, struct RegionView3D *rv3d);
bool ED_view3d_camera_autokey(
struct Scene *scene, struct ID *id_key,
@@ -443,10 +519,6 @@ bool ED_view3d_camera_lock_autokey(
void ED_view3d_lock_clear(struct View3D *v3d);
-struct BGpic *ED_view3d_background_image_new(struct View3D *v3d);
-void ED_view3d_background_image_remove(struct View3D *v3d, struct BGpic *bgpic);
-void ED_view3d_background_image_clear(struct View3D *v3d);
-
#define VIEW3D_MARGIN 1.4f
#define VIEW3D_DIST_FALLBACK 1.0f
@@ -455,8 +527,10 @@ void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist);
float ED_scene_grid_scale(struct Scene *scene, const char **grid_unit);
float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit);
+float ED_view3d_grid_view_scale(
+ struct Scene *scene, struct View3D *v3d, struct RegionView3D *rv3d, const char **grid_unit);
-void ED_scene_draw_fps(struct Scene *scene, const struct rcti *rect);
+void ED_scene_draw_fps(struct Scene *scene, int xoffset, int *yoffset);
/* view matrix properties utilities */
/* unused */
@@ -470,9 +544,16 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx,
void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *ar);
void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa);
-#define V3D_IS_ZBUF(v3d) \
- (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE))
+#define V3D_XRAY_FLAG(v3d) (((v3d)->shading.type == OB_WIRE) ? V3D_SHADING_XRAY_BONE : V3D_SHADING_XRAY)
+#define V3D_IS_ZBUF(v3d) (((v3d)->shading.flag & V3D_XRAY_FLAG(v3d)) == 0)
void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id);
+/* view3d_draw_legacy.c */
+/* Try avoid using these more move out of legacy. */
+void ED_view3d_draw_bgpic_test(
+ struct Scene *scene, struct Depsgraph *depsgraph,
+ struct ARegion *ar, struct View3D *v3d,
+ const bool do_foreground, const bool do_camera_frame);
+
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 24a44fe307c..9b4ee0c8264 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -28,12 +28,30 @@
* \ingroup editorui
*/
-/* Note: this is included twice with different #defines for DEF_ICON
- * once from UI_resources.h for the internal icon enum and
- * once for interface_api.c for the definition of the RNA enum for the icons */
+/* Note: this is included multiple times with different #defines for DEF_ICON. */
+
+/* Auto define more specific types for places that do not need the distinction. */
+#ifndef DEF_ICON_COLLECTION
+# define DEF_ICON_COLLECTION DEF_ICON
+#endif
+#ifndef DEF_ICON_OBJECT
+# define DEF_ICON_OBJECT DEF_ICON
+#endif
+#ifndef DEF_ICON_OBJECT_DATA
+# define DEF_ICON_OBJECT_DATA DEF_ICON
+#endif
+#ifndef DEF_ICON_MODIFIER
+# define DEF_ICON_MODIFIER DEF_ICON
+#endif
+#ifndef DEF_ICON_SHADING
+# define DEF_ICON_SHADING DEF_ICON
+#endif
+#ifndef DEF_ICON_COLOR
+# define DEF_ICON_COLOR DEF_ICON
+#endif
/* ICON_ prefix added */
-DEF_ICON(NONE)
+DEF_ICON_COLOR(NONE)
DEF_ICON(QUESTION)
DEF_ICON(ERROR)
DEF_ICON(CANCEL)
@@ -43,8 +61,8 @@ DEF_ICON(TRIA_LEFT)
DEF_ICON(TRIA_UP)
DEF_ICON(ARROW_LEFTRIGHT)
DEF_ICON(PLUS)
-DEF_ICON(DISCLOSURE_TRI_DOWN)
DEF_ICON(DISCLOSURE_TRI_RIGHT)
+DEF_ICON(DISCLOSURE_TRI_DOWN)
DEF_ICON(RADIOBUT_OFF)
DEF_ICON(RADIOBUT_ON)
DEF_ICON(MENU_PANEL)
@@ -53,30 +71,28 @@ DEF_ICON(GRIP)
DEF_ICON(DOT)
DEF_ICON(COLLAPSEMENU)
DEF_ICON(X)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK005) /* XXX 'DOWNARROW' icon! */
-#endif
-DEF_ICON(GO_LEFT)
-DEF_ICON(PLUG)
-DEF_ICON(UI)
+DEF_ICON(DUPLICATE)
+DEF_ICON_BLANK(75)
+DEF_ICON_BLANK(76)
+DEF_ICON_BLANK(77)
DEF_ICON(NODE)
DEF_ICON(NODE_SEL)
/* ui */
-DEF_ICON(FULLSCREEN)
-DEF_ICON(SPLITSCREEN)
+DEF_ICON(WINDOW)
+DEF_ICON(WORKSPACE)
DEF_ICON(RIGHTARROW_THIN)
DEF_ICON(BORDERMOVE)
DEF_ICON(VIEWZOOM)
-DEF_ICON(ZOOMIN)
-DEF_ICON(ZOOMOUT)
+DEF_ICON(ADD)
+DEF_ICON(REMOVE)
DEF_ICON(PANEL_CLOSE)
DEF_ICON(COPY_ID)
DEF_ICON(EYEDROPPER)
-DEF_ICON(LINK_AREA)
+DEF_ICON_BLANK(92)
DEF_ICON(AUTO)
-DEF_ICON(CHECKBOX_DEHLT)
-DEF_ICON(CHECKBOX_HLT)
+DEF_ICON(CHECKBOX_DEHLT) /* de-Hilight - Checkbox OFF */
+DEF_ICON(CHECKBOX_HLT) /* Hilight - Checkbox ON */
DEF_ICON(UNLOCKED)
DEF_ICON(LOCKED)
DEF_ICON(UNPINNED)
@@ -84,171 +100,161 @@ DEF_ICON(PINNED)
DEF_ICON(SCREEN_BACK)
DEF_ICON(RIGHTARROW)
DEF_ICON(DOWNARROW_HLT)
-DEF_ICON(DOTSUP)
-DEF_ICON(DOTSDOWN)
-DEF_ICON(LINK)
-DEF_ICON(INLINK)
+DEF_ICON_BLANK(103)
+DEF_ICON_BLANK(104)
+DEF_ICON_BLANK(105)
+DEF_ICON_BLANK(106)
DEF_ICON(PLUGIN)
/* various ui */
DEF_ICON(HELP)
DEF_ICON(GHOST_ENABLED)
DEF_ICON(COLOR) /* see COLOR_RED/GREEN/BLUE */
-DEF_ICON(LINKED)
DEF_ICON(UNLINKED)
+DEF_ICON(LINKED)
DEF_ICON(HAND)
DEF_ICON(ZOOM_ALL)
DEF_ICON(ZOOM_SELECTED)
DEF_ICON(ZOOM_PREVIOUS)
DEF_ICON(ZOOM_IN)
DEF_ICON(ZOOM_OUT)
-DEF_ICON(RENDER_REGION)
-DEF_ICON(BORDER_RECT)
-DEF_ICON(BORDER_LASSO)
+DEF_ICON(DRIVER_DISTANCE)
+DEF_ICON(DRIVER_ROTATIONAL_DIFFERENCE)
+DEF_ICON(DRIVER_TRANSFORM)
DEF_ICON(FREEZE)
DEF_ICON(STYLUS_PRESSURE)
DEF_ICON(GHOST_DISABLED)
-DEF_ICON(NEW)
+DEF_ICON(FILE_NEW)
DEF_ICON(FILE_TICK)
DEF_ICON(QUIT)
DEF_ICON(URL)
DEF_ICON(RECOVER_LAST)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK038)
-#endif
+DEF_ICON(THREE_DOTS)
DEF_ICON(FULLSCREEN_ENTER)
DEF_ICON(FULLSCREEN_EXIT)
-DEF_ICON(BLANK1) // Not actually blank - this is used all over the place
+DEF_ICON_BLANK(135)
/* BUTTONS */
-DEF_ICON(LAMP)
-DEF_ICON(MATERIAL)
-DEF_ICON(TEXTURE)
+DEF_ICON_SHADING(LIGHT)
+DEF_ICON_SHADING(MATERIAL)
+DEF_ICON_SHADING(TEXTURE)
DEF_ICON(ANIM)
-DEF_ICON(WORLD)
+DEF_ICON_SHADING(WORLD)
DEF_ICON(SCENE)
-DEF_ICON(EDIT)
-DEF_ICON(GAME)
-DEF_ICON(RADIO)
+DEF_ICON(OUTPUT)
+DEF_ICON_BLANK(145)
+DEF_ICON_BLANK(146)
DEF_ICON(SCRIPT)
-DEF_ICON(PARTICLES)
+DEF_ICON_MODIFIER(PARTICLES)
DEF_ICON(PHYSICS)
DEF_ICON(SPEAKER)
-DEF_ICON(TEXTURE_SHADED)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK042)
- DEF_ICON(BLANK043)
- DEF_ICON(BLANK044)
- DEF_ICON(BLANK045)
- DEF_ICON(BLANK046)
- DEF_ICON(BLANK047)
- DEF_ICON(BLANK048)
- DEF_ICON(BLANK049)
- DEF_ICON(BLANK050)
- DEF_ICON(BLANK051)
- DEF_ICON(BLANK052)
- DEF_ICON(BLANK052b)
-#endif
+DEF_ICON_BLANK(151)
+DEF_ICON(TOOL_SETTINGS)
+DEF_ICON(SHADERFX)
+DEF_ICON_BLANK(154)
+DEF_ICON_BLANK(155)
+DEF_ICON_BLANK(156)
+DEF_ICON_BLANK(157)
+DEF_ICON_BLANK(158)
+DEF_ICON_BLANK(159)
+DEF_ICON_BLANK(160)
+DEF_ICON(BLANK1) // Not actually blank - this is used all over the place
+DEF_ICON(FAKE_USER_OFF)
+DEF_ICON(FAKE_USER_ON)
/* EDITORS */
DEF_ICON(VIEW3D)
-DEF_ICON(IPO)
-DEF_ICON(OOPS)
-DEF_ICON(BUTS)
-DEF_ICON(FILESEL)
-DEF_ICON(IMAGE_COL)
+DEF_ICON(GRAPH)
+DEF_ICON(OUTLINER)
+DEF_ICON(PROPERTIES)
+DEF_ICON(FILEBROWSER)
+DEF_ICON(IMAGE)
DEF_ICON(INFO)
DEF_ICON(SEQUENCE)
DEF_ICON(TEXT)
-DEF_ICON(IMASEL)
+DEF_ICON_BLANK(174)
DEF_ICON(SOUND)
DEF_ICON(ACTION)
DEF_ICON(NLA)
-DEF_ICON(SCRIPTWIN)
+DEF_ICON(PREFERENCES)
DEF_ICON(TIME)
DEF_ICON(NODETREE)
-DEF_ICON(LOGIC)
+DEF_ICON_BLANK(181)
DEF_ICON(CONSOLE)
-DEF_ICON(PREFERENCES)
+DEF_ICON_BLANK(183)
DEF_ICON(CLIP)
DEF_ICON(ASSET_MANAGER)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK057)
- DEF_ICON(BLANK058)
- DEF_ICON(BLANK059)
- DEF_ICON(BLANK060)
- DEF_ICON(BLANK061)
-#endif
+DEF_ICON(NODE_COMPOSITING)
+DEF_ICON(NODE_TEXTURE)
+DEF_ICON(NODE_MATERIAL)
+DEF_ICON_BLANK(189)
+DEF_ICON_BLANK(190)
/* MODES */
DEF_ICON(OBJECT_DATAMODE) // XXX fix this up
DEF_ICON(EDITMODE_HLT)
-DEF_ICON(FACESEL_HLT)
+DEF_ICON(UV)
DEF_ICON(VPAINT_HLT)
DEF_ICON(TPAINT_HLT)
DEF_ICON(WPAINT_HLT)
DEF_ICON(SCULPTMODE_HLT)
DEF_ICON(POSE_HLT)
DEF_ICON(PARTICLEMODE)
-DEF_ICON(LIGHTPAINT)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK063)
- DEF_ICON(BLANK064)
- DEF_ICON(BLANK065)
- DEF_ICON(BLANK066)
- DEF_ICON(BLANK067)
- DEF_ICON(BLANK068)
- DEF_ICON(BLANK069)
- DEF_ICON(BLANK070)
- DEF_ICON(BLANK071)
- DEF_ICON(BLANK072)
- DEF_ICON(BLANK073)
- DEF_ICON(BLANK074)
- DEF_ICON(BLANK075)
- DEF_ICON(BLANK076)
- DEF_ICON(BLANK077)
- DEF_ICON(BLANK077b)
-#endif
+DEF_ICON_BLANK(202)
+DEF_ICON_BLANK(203)
+DEF_ICON_BLANK(204)
+DEF_ICON_BLANK(205)
+DEF_ICON_BLANK(206)
+DEF_ICON_BLANK(207)
+DEF_ICON_BLANK(208)
+DEF_ICON(TRACKING)
+DEF_ICON(TRACKING_BACKWARDS)
+DEF_ICON(TRACKING_FORWARDS)
+DEF_ICON(TRACKING_BACKWARDS_SINGLE)
+DEF_ICON(TRACKING_FORWARDS_SINGLE)
+DEF_ICON(TRACKING_CLEAR_BACKWARDS)
+DEF_ICON(TRACKING_CLEAR_FORWARDS)
+DEF_ICON(TRACKING_REFINE_BACKWARDS)
+DEF_ICON(TRACKING_REFINE_FORWARDS)
+DEF_ICON_BLANK(77b)
/* DATA */
DEF_ICON(SCENE_DATA)
DEF_ICON(RENDERLAYERS)
-DEF_ICON(WORLD_DATA)
+DEF_ICON_SHADING(WORLD_DATA)
DEF_ICON(OBJECT_DATA)
DEF_ICON(MESH_DATA)
DEF_ICON(CURVE_DATA)
DEF_ICON(META_DATA)
DEF_ICON(LATTICE_DATA)
-DEF_ICON(LAMP_DATA)
-DEF_ICON(MATERIAL_DATA)
-DEF_ICON(TEXTURE_DATA)
+DEF_ICON_SHADING(LIGHT_DATA)
+DEF_ICON_SHADING(MATERIAL_DATA)
+DEF_ICON_SHADING(TEXTURE_DATA)
DEF_ICON(ANIM_DATA)
DEF_ICON(CAMERA_DATA)
DEF_ICON(PARTICLE_DATA)
DEF_ICON(LIBRARY_DATA_DIRECT)
-DEF_ICON(GROUP)
+DEF_ICON_COLLECTION(GROUP)
DEF_ICON(ARMATURE_DATA)
-DEF_ICON(POSE_DATA)
+DEF_ICON(COMMUNITY)
DEF_ICON(BONE_DATA)
-DEF_ICON(CONSTRAINT)
+DEF_ICON_MODIFIER(CONSTRAINT)
DEF_ICON(SHAPEKEY_DATA)
-DEF_ICON(CONSTRAINT_BONE)
+DEF_ICON_MODIFIER(CONSTRAINT_BONE)
DEF_ICON(CAMERA_STEREO)
DEF_ICON(PACKAGE)
DEF_ICON(UGLYPACKAGE)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK079b)
-#endif
+DEF_ICON(EXPERIMENTAL)
/* DATA */
-DEF_ICON(BRUSH_DATA)
-DEF_ICON(IMAGE_DATA)
+DEF_ICON_SHADING(BRUSH_DATA)
+DEF_ICON_SHADING(IMAGE_DATA)
DEF_ICON(FILE)
DEF_ICON(FCURVE)
DEF_ICON(FONT_DATA)
DEF_ICON(RENDER_RESULT)
DEF_ICON(SURFACE_DATA)
DEF_ICON(EMPTY_DATA)
-DEF_ICON(SETTINGS)
+DEF_ICON(PRESET)
DEF_ICON(RENDER_ANIMATION)
DEF_ICON(RENDER_STILL)
DEF_ICON(LIBRARY_DATA_BROKEN)
@@ -256,112 +262,100 @@ DEF_ICON(BOIDS)
DEF_ICON(STRANDS)
DEF_ICON(LIBRARY_DATA_INDIRECT)
DEF_ICON(GREASEPENCIL)
-DEF_ICON(LINE_DATA)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK084)
-#endif
+DEF_ICON_SHADING(LINE_DATA)
+DEF_ICON(LIBRARY_DATA_OVERRIDE)
DEF_ICON(GROUP_BONE)
DEF_ICON(GROUP_VERTEX)
DEF_ICON(GROUP_VCOL)
DEF_ICON(GROUP_UVS)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK089)
- DEF_ICON(BLANK090)
-#endif
+DEF_ICON(FACE_MAPS)
+DEF_ICON_BLANK(272)
DEF_ICON(RNA)
DEF_ICON(RNA_ADD)
- /* available */
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK092)
- DEF_ICON(BLANK093)
- DEF_ICON(BLANK094)
- DEF_ICON(BLANK095)
- DEF_ICON(BLANK096)
- DEF_ICON(BLANK097)
- DEF_ICON(BLANK098)
- DEF_ICON(BLANK099)
- DEF_ICON(BLANK100)
- DEF_ICON(BLANK101)
- DEF_ICON(BLANK102)
- DEF_ICON(BLANK103)
- DEF_ICON(BLANK104)
- DEF_ICON(BLANK105)
- DEF_ICON(BLANK106)
- DEF_ICON(BLANK107)
- DEF_ICON(BLANK108)
- DEF_ICON(BLANK109)
- DEF_ICON(BLANK110)
- DEF_ICON(BLANK111)
- DEF_ICON(BLANK112)
- DEF_ICON(BLANK113)
- DEF_ICON(BLANK114)
- DEF_ICON(BLANK115)
- DEF_ICON(BLANK116)
- DEF_ICON(BLANK116b)
-#endif
+ /* INPUT + DECORATOR */
+DEF_ICON(MOUSE_LMB)
+DEF_ICON(MOUSE_MMB)
+DEF_ICON(MOUSE_RMB)
+DEF_ICON(MOUSE_MOVE)
+DEF_ICON(MOUSE_LMB_DRAG)
+DEF_ICON(MOUSE_MMB_DRAG)
+DEF_ICON(MOUSE_RMB_DRAG)
+DEF_ICON_BLANK(284)
+DEF_ICON(PRESET_NEW)
+DEF_ICON_BLANK(286)
+DEF_ICON(DECORATE)
+DEF_ICON(DECORATE_KEYFRAME)
+DEF_ICON(DECORATE_ANIMATE)
+DEF_ICON(DECORATE_DRIVER)
+DEF_ICON(DECORATE_LINKED)
+DEF_ICON(DECORATE_LIBRARY_OVERRIDE)
+DEF_ICON(DECORATE_UNLOCKED)
+DEF_ICON(DECORATE_LOCKED)
+DEF_ICON(DECORATE_OVERRIDE)
+DEF_ICON_BLANK(111)
+DEF_ICON(SEALED)
+DEF_ICON(HEART)
+DEF_ICON(ORPHAN_DATA)
+DEF_ICON(USER)
+DEF_ICON(SYSTEM)
+DEF_ICON(SETTINGS)
/* OUTLINER */
-DEF_ICON(OUTLINER_OB_EMPTY)
-DEF_ICON(OUTLINER_OB_MESH)
-DEF_ICON(OUTLINER_OB_CURVE)
-DEF_ICON(OUTLINER_OB_LATTICE)
-DEF_ICON(OUTLINER_OB_META)
-DEF_ICON(OUTLINER_OB_LAMP)
-DEF_ICON(OUTLINER_OB_CAMERA)
-DEF_ICON(OUTLINER_OB_ARMATURE)
-DEF_ICON(OUTLINER_OB_FONT)
-DEF_ICON(OUTLINER_OB_SURFACE)
-DEF_ICON(OUTLINER_OB_SPEAKER)
-DEF_ICON(OUTLINER_OB_FORCE_FIELD)
-DEF_ICON(OUTLINER_OB_GROUP_INSTANCE)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK122)
- DEF_ICON(BLANK123)
- DEF_ICON(BLANK124)
- DEF_ICON(BLANK125)
-#endif
+DEF_ICON_OBJECT(OUTLINER_OB_EMPTY)
+DEF_ICON_OBJECT(OUTLINER_OB_MESH)
+DEF_ICON_OBJECT(OUTLINER_OB_CURVE)
+DEF_ICON_OBJECT(OUTLINER_OB_LATTICE)
+DEF_ICON_OBJECT(OUTLINER_OB_META)
+DEF_ICON_OBJECT(OUTLINER_OB_LIGHT)
+DEF_ICON_OBJECT(OUTLINER_OB_CAMERA)
+DEF_ICON_OBJECT(OUTLINER_OB_ARMATURE)
+DEF_ICON_OBJECT(OUTLINER_OB_FONT)
+DEF_ICON_OBJECT(OUTLINER_OB_SURFACE)
+DEF_ICON_OBJECT(OUTLINER_OB_SPEAKER)
+DEF_ICON_OBJECT(OUTLINER_OB_FORCE_FIELD)
+DEF_ICON_OBJECT(OUTLINER_OB_GROUP_INSTANCE)
+DEF_ICON_OBJECT(OUTLINER_OB_GREASEPENCIL)
+DEF_ICON_OBJECT(OUTLINER_OB_LIGHTPROBE)
+DEF_ICON_OBJECT(OUTLINER_OB_IMAGE)
+DEF_ICON_BLANK(321)
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)
+DEF_ICON(HIDE_ON)
+DEF_ICON(HIDE_OFF)
DEF_ICON(RESTRICT_SELECT_ON)
-DEF_ICON(RESTRICT_RENDER_OFF)
+DEF_ICON(RESTRICT_SELECT_OFF)
DEF_ICON(RESTRICT_RENDER_ON)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK127b)
-#endif
+DEF_ICON(RESTRICT_RENDER_OFF)
+DEF_ICON_BLANK(330)
/* OUTLINER */
-DEF_ICON(OUTLINER_DATA_EMPTY)
-DEF_ICON(OUTLINER_DATA_MESH)
-DEF_ICON(OUTLINER_DATA_CURVE)
-DEF_ICON(OUTLINER_DATA_LATTICE)
-DEF_ICON(OUTLINER_DATA_META)
-DEF_ICON(OUTLINER_DATA_LAMP)
-DEF_ICON(OUTLINER_DATA_CAMERA)
-DEF_ICON(OUTLINER_DATA_ARMATURE)
-DEF_ICON(OUTLINER_DATA_FONT)
-DEF_ICON(OUTLINER_DATA_SURFACE)
-DEF_ICON(OUTLINER_DATA_SPEAKER)
-DEF_ICON(OUTLINER_DATA_POSE)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK130)
- DEF_ICON(BLANK131)
- DEF_ICON(BLANK132)
- DEF_ICON(BLANK133)
- DEF_ICON(BLANK134)
- DEF_ICON(BLANK135)
- DEF_ICON(BLANK136)
- DEF_ICON(BLANK137)
- DEF_ICON(BLANK138)
- DEF_ICON(BLANK139)
- DEF_ICON(BLANK140)
- DEF_ICON(BLANK141)
- DEF_ICON(BLANK142)
- DEF_ICON(BLANK142b)
-#endif
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_EMPTY)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_MESH)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_CURVE)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_LATTICE)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_META)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_LIGHT)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_CAMERA)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_ARMATURE)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_FONT)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_SURFACE)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_SPEAKER)
+DEF_ICON_BLANK(344)
+DEF_ICON_BLANK(345)
+DEF_ICON_OBJECT_DATA(OUTLINER_DATA_GREASEPENCIL)
+DEF_ICON(GP_SELECT_POINTS)
+DEF_ICON(GP_SELECT_STROKES)
+DEF_ICON(GP_MULTIFRAME_EDITING)
+DEF_ICON(GP_ONLY_SELECTED)
+DEF_ICON_BLANK(351)
+DEF_ICON(MODIFIER_OFF)
+DEF_ICON(MODIFIER_ON)
+DEF_ICON(ONIONSKIN_OFF)
+DEF_ICON(ONIONSKIN_ON)
+DEF_ICON(RESTRICT_VIEW_ON)
+DEF_ICON(RESTRICT_VIEW_OFF)
+DEF_ICON_BLANK(353)
/* PRIMITIVES */
DEF_ICON(MESH_PLANE)
@@ -375,27 +369,21 @@ DEF_ICON(MESH_CYLINDER)
DEF_ICON(MESH_TORUS)
DEF_ICON(MESH_CONE)
DEF_ICON(MESH_CAPSULE)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK611)
-#endif
-DEF_ICON(LAMP_POINT)
-DEF_ICON(LAMP_SUN)
-DEF_ICON(LAMP_SPOT)
-DEF_ICON(LAMP_HEMI)
-DEF_ICON(LAMP_AREA)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK617)
- DEF_ICON(BLANK618)
-#endif
-DEF_ICON(META_EMPTY)
+DEF_ICON(EMPTY_SINGLE_ARROW)
+DEF_ICON_SHADING(LIGHT_POINT)
+DEF_ICON_SHADING(LIGHT_SUN)
+DEF_ICON_SHADING(LIGHT_SPOT)
+DEF_ICON_SHADING(LIGHT_HEMI)
+DEF_ICON_SHADING(LIGHT_AREA)
+DEF_ICON(CUBE)
+DEF_ICON(SPHERE)
+DEF_ICON(CONE)
DEF_ICON(META_PLANE)
DEF_ICON(META_CUBE)
DEF_ICON(META_BALL)
DEF_ICON(META_ELLIPSOID)
DEF_ICON(META_CAPSULE)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK625)
-#endif
+DEF_ICON_BLANK(625)
/* PRIMITIVES */
DEF_ICON(SURFACE_NCURVE)
@@ -404,23 +392,19 @@ DEF_ICON(SURFACE_NSURFACE)
DEF_ICON(SURFACE_NCYLINDER)
DEF_ICON(SURFACE_NSPHERE)
DEF_ICON(SURFACE_NTORUS)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK636)
- DEF_ICON(BLANK637)
- DEF_ICON(BLANK638)
-#endif
+DEF_ICON(EMPTY_AXIS)
+DEF_ICON(STROKE)
+DEF_ICON(EMPTY_ARROWS)
DEF_ICON(CURVE_BEZCURVE)
DEF_ICON(CURVE_BEZCIRCLE)
DEF_ICON(CURVE_NCURVE)
DEF_ICON(CURVE_NCIRCLE)
DEF_ICON(CURVE_PATH)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK644)
- DEF_ICON(BLANK645)
- DEF_ICON(BLANK646)
- DEF_ICON(BLANK647)
- DEF_ICON(BLANK648)
-#endif
+DEF_ICON_SHADING(LIGHTPROBE_CUBEMAP)
+DEF_ICON_SHADING(LIGHTPROBE_PLANAR)
+DEF_ICON_SHADING(LIGHTPROBE_GRID)
+DEF_ICON_BLANK(406)
+DEF_ICON_BLANK(407)
DEF_ICON(COLOR_RED)
DEF_ICON(COLOR_GREEN)
DEF_ICON(COLOR_BLUE)
@@ -443,165 +427,159 @@ DEF_ICON(FORCE_BOID)
DEF_ICON(FORCE_TURBULENCE)
DEF_ICON(FORCE_DRAG)
DEF_ICON(FORCE_SMOKEFLOW)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK673)
- DEF_ICON(BLANK674)
- DEF_ICON(BLANK675)
- DEF_ICON(BLANK676)
- DEF_ICON(BLANK677)
- DEF_ICON(BLANK678)
- DEF_ICON(BLANK679)
- DEF_ICON(BLANK680)
- DEF_ICON(BLANK681)
- DEF_ICON(BLANK682)
- DEF_ICON(BLANK683)
- DEF_ICON(BLANK684)
- DEF_ICON(BLANK685)
+DEF_ICON_BLANK(673)
+DEF_ICON_BLANK(674)
+DEF_ICON_BLANK(675)
+DEF_ICON_BLANK(676)
+DEF_ICON_BLANK(677)
+DEF_ICON_BLANK(678)
+DEF_ICON_BLANK(679)
+DEF_ICON_BLANK(680)
+DEF_ICON_BLANK(681)
+DEF_ICON_BLANK(682)
+DEF_ICON(IMAGE_PLANE)
+DEF_ICON(IMAGE_BACKGROUND)
+DEF_ICON(IMAGE_REFERENCE)
/* EMPTY */
- DEF_ICON(BLANK690) /* XXX 'Temperature' icon! */
- DEF_ICON(BLANK691) /* XXX 'Temperature' icon! */
- DEF_ICON(BLANK692) /* XXX 'Gear' icon! */
-#endif
+DEF_ICON_BLANK(445)
+DEF_ICON_BLANK(446)
+DEF_ICON_BLANK(447)
DEF_ICON(NODE_INSERT_ON)
DEF_ICON(NODE_INSERT_OFF)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK695)
- DEF_ICON(BLANK696)
- DEF_ICON(BLANK697)
- DEF_ICON(BLANK698)
- DEF_ICON(BLANK699)
- DEF_ICON(BLANK700)
- DEF_ICON(BLANK701)
- DEF_ICON(BLANK702)
- DEF_ICON(BLANK703)
- DEF_ICON(BLANK704)
- DEF_ICON(BLANK705)
- DEF_ICON(BLANK706)
- DEF_ICON(BLANK707)
- DEF_ICON(BLANK708)
- DEF_ICON(BLANK709)
- DEF_ICON(BLANK710)
- DEF_ICON(BLANK711)
- DEF_ICON(BLANK712)
- DEF_ICON(BLANK713)
- DEF_ICON(BLANK714)
- DEF_ICON(BLANK715)
+DEF_ICON(NODE_TOP)
+DEF_ICON(NODE_SIDE)
+DEF_ICON(NODE_CORNER)
+DEF_ICON_BLANK(698)
+DEF_ICON_BLANK(699)
+DEF_ICON_BLANK(700)
+DEF_ICON_BLANK(701)
+DEF_ICON_BLANK(702)
+DEF_ICON_BLANK(703)
+DEF_ICON_BLANK(704)
+DEF_ICON_BLANK(705)
+DEF_ICON_BLANK(706)
+DEF_ICON_BLANK(707)
+DEF_ICON_BLANK(708)
+DEF_ICON_BLANK(709)
+DEF_ICON_BLANK(710)
+DEF_ICON_BLANK(711)
+DEF_ICON_BLANK(712)
+DEF_ICON_BLANK(713)
+DEF_ICON_BLANK(714)
+DEF_ICON_BLANK(715)
/* EMPTY */
- DEF_ICON(BLANK720)
- DEF_ICON(BLANK721)
- DEF_ICON(BLANK722)
- DEF_ICON(BLANK733)
- DEF_ICON(BLANK734)
- DEF_ICON(BLANK735)
- DEF_ICON(BLANK736)
- DEF_ICON(BLANK737)
- DEF_ICON(BLANK738)
- DEF_ICON(BLANK739)
- DEF_ICON(BLANK740)
- DEF_ICON(BLANK741)
- DEF_ICON(BLANK742)
- DEF_ICON(BLANK743)
- DEF_ICON(BLANK744)
- DEF_ICON(BLANK745)
- DEF_ICON(BLANK746)
- DEF_ICON(BLANK747)
- DEF_ICON(BLANK748)
- DEF_ICON(BLANK749)
- DEF_ICON(BLANK750)
- DEF_ICON(BLANK751)
- DEF_ICON(BLANK752)
- DEF_ICON(BLANK753)
- DEF_ICON(BLANK754)
- DEF_ICON(BLANK755)
+DEF_ICON(ALIGN_LEFT)
+DEF_ICON(ALIGN_CENTER)
+DEF_ICON(ALIGN_RIGHT)
+DEF_ICON(ALIGN_JUSTIFY)
+DEF_ICON(ALIGN_FLUSH)
+DEF_ICON(ALIGN_TOP)
+DEF_ICON(ALIGN_MIDDLE)
+DEF_ICON(ALIGN_BOTTOM)
+DEF_ICON(BOLD)
+DEF_ICON(ITALIC)
+DEF_ICON(UNDERLINE)
+DEF_ICON(SMALL_CAPS)
+DEF_ICON_BLANK(742)
+DEF_ICON_BLANK(743)
+DEF_ICON_BLANK(744)
+DEF_ICON_BLANK(745)
+DEF_ICON_BLANK(746)
+DEF_ICON_BLANK(747)
+DEF_ICON_BLANK(748)
+DEF_ICON_BLANK(749)
+DEF_ICON_BLANK(750)
+DEF_ICON_BLANK(751)
+DEF_ICON_BLANK(752)
+DEF_ICON_BLANK(753)
+DEF_ICON_BLANK(754)
+DEF_ICON_BLANK(755)
/* EMPTY */
- DEF_ICON(BLANK760)
- DEF_ICON(BLANK761)
- DEF_ICON(BLANK762)
- DEF_ICON(BLANK763)
- DEF_ICON(BLANK764)
- DEF_ICON(BLANK765)
- DEF_ICON(BLANK766)
- DEF_ICON(BLANK767)
- DEF_ICON(BLANK768)
- DEF_ICON(BLANK769)
- DEF_ICON(BLANK770)
- DEF_ICON(BLANK771)
- DEF_ICON(BLANK772)
- DEF_ICON(BLANK773)
- DEF_ICON(BLANK774)
- DEF_ICON(BLANK775)
- DEF_ICON(BLANK776)
- DEF_ICON(BLANK777)
- DEF_ICON(BLANK778)
- DEF_ICON(BLANK779)
- DEF_ICON(BLANK780)
- DEF_ICON(BLANK781)
- DEF_ICON(BLANK782)
- DEF_ICON(BLANK783)
- DEF_ICON(BLANK784)
- DEF_ICON(BLANK785)
-#endif
+DEF_ICON_BLANK(501)
+DEF_ICON_BLANK(502)
+DEF_ICON_BLANK(503)
+DEF_ICON_BLANK(504)
+DEF_ICON_BLANK(505)
+DEF_ICON_BLANK(506)
+DEF_ICON_BLANK(507)
+DEF_ICON_BLANK(508)
+DEF_ICON_BLANK(509)
+DEF_ICON_BLANK(510)
+DEF_ICON_BLANK(511)
+DEF_ICON_BLANK(512)
+DEF_ICON_BLANK(513)
+DEF_ICON_BLANK(514)
+DEF_ICON_BLANK(515)
+DEF_ICON_BLANK(516)
+DEF_ICON_BLANK(517)
+DEF_ICON_BLANK(518)
+DEF_ICON_BLANK(519)
+DEF_ICON_BLANK(520)
+DEF_ICON_BLANK(521)
+DEF_ICON_BLANK(522)
+DEF_ICON_BLANK(523)
+DEF_ICON_BLANK(524)
+DEF_ICON_BLANK(525)
+DEF_ICON_BLANK(526)
/* MODIFIERS */
-DEF_ICON(MODIFIER)
-DEF_ICON(MOD_WAVE)
-DEF_ICON(MOD_BUILD)
-DEF_ICON(MOD_DECIM)
-DEF_ICON(MOD_MIRROR)
-DEF_ICON(MOD_SOFT)
-DEF_ICON(MOD_SUBSURF)
-DEF_ICON(HOOK)
-DEF_ICON(MOD_PHYSICS)
-DEF_ICON(MOD_PARTICLES)
-DEF_ICON(MOD_BOOLEAN)
-DEF_ICON(MOD_EDGESPLIT)
-DEF_ICON(MOD_ARRAY)
-DEF_ICON(MOD_UVPROJECT)
-DEF_ICON(MOD_DISPLACE)
-DEF_ICON(MOD_CURVE)
-DEF_ICON(MOD_LATTICE)
-DEF_ICON(CONSTRAINT_DATA)
-DEF_ICON(MOD_ARMATURE)
-DEF_ICON(MOD_SHRINKWRAP)
-DEF_ICON(MOD_CAST)
-DEF_ICON(MOD_MESHDEFORM)
-DEF_ICON(MOD_BEVEL)
-DEF_ICON(MOD_SMOOTH)
-DEF_ICON(MOD_SIMPLEDEFORM)
-DEF_ICON(MOD_MASK)
+DEF_ICON_MODIFIER(MODIFIER)
+DEF_ICON_MODIFIER(MOD_WAVE)
+DEF_ICON_MODIFIER(MOD_BUILD)
+DEF_ICON_MODIFIER(MOD_DECIM)
+DEF_ICON_MODIFIER(MOD_MIRROR)
+DEF_ICON_MODIFIER(MOD_SOFT)
+DEF_ICON_MODIFIER(MOD_SUBSURF)
+DEF_ICON_MODIFIER(HOOK)
+DEF_ICON_MODIFIER(MOD_PHYSICS)
+DEF_ICON_MODIFIER(MOD_PARTICLES)
+DEF_ICON_MODIFIER(MOD_BOOLEAN)
+DEF_ICON_MODIFIER(MOD_EDGESPLIT)
+DEF_ICON_MODIFIER(MOD_ARRAY)
+DEF_ICON_MODIFIER(MOD_UVPROJECT)
+DEF_ICON_MODIFIER(MOD_DISPLACE)
+DEF_ICON_MODIFIER(MOD_CURVE)
+DEF_ICON_MODIFIER(MOD_LATTICE)
+DEF_ICON_MODIFIER(MOD_TINT)
+DEF_ICON_MODIFIER(MOD_ARMATURE)
+DEF_ICON_MODIFIER(MOD_SHRINKWRAP)
+DEF_ICON_MODIFIER(MOD_CAST)
+DEF_ICON_MODIFIER(MOD_MESHDEFORM)
+DEF_ICON_MODIFIER(MOD_BEVEL)
+DEF_ICON_MODIFIER(MOD_SMOOTH)
+DEF_ICON_MODIFIER(MOD_SIMPLEDEFORM)
+DEF_ICON_MODIFIER(MOD_MASK)
/* MODIFIERS */
-DEF_ICON(MOD_CLOTH)
-DEF_ICON(MOD_EXPLODE)
-DEF_ICON(MOD_FLUIDSIM)
-DEF_ICON(MOD_MULTIRES)
-DEF_ICON(MOD_SMOKE)
-DEF_ICON(MOD_SOLIDIFY)
-DEF_ICON(MOD_SCREW)
-DEF_ICON(MOD_VERTEX_WEIGHT)
-DEF_ICON(MOD_DYNAMICPAINT)
-DEF_ICON(MOD_REMESH)
-DEF_ICON(MOD_OCEAN)
-DEF_ICON(MOD_WARP)
-DEF_ICON(MOD_SKIN)
-DEF_ICON(MOD_TRIANGULATE)
-DEF_ICON(MOD_WIREFRAME)
-DEF_ICON(MOD_DATA_TRANSFER)
-DEF_ICON(MOD_NORMALEDIT)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK169)
- DEF_ICON(BLANK170)
- DEF_ICON(BLANK171)
- DEF_ICON(BLANK172)
- DEF_ICON(BLANK173)
- DEF_ICON(BLANK174)
- DEF_ICON(BLANK175)
- DEF_ICON(BLANK176)
- DEF_ICON(BLANK177)
-#endif
+DEF_ICON_MODIFIER(MOD_CLOTH)
+DEF_ICON_MODIFIER(MOD_EXPLODE)
+DEF_ICON_MODIFIER(MOD_FLUIDSIM)
+DEF_ICON_MODIFIER(MOD_MULTIRES)
+DEF_ICON_MODIFIER(MOD_SMOKE)
+DEF_ICON_MODIFIER(MOD_SOLIDIFY)
+DEF_ICON_MODIFIER(MOD_SCREW)
+DEF_ICON_MODIFIER(MOD_VERTEX_WEIGHT)
+DEF_ICON_MODIFIER(MOD_DYNAMICPAINT)
+DEF_ICON_MODIFIER(MOD_REMESH)
+DEF_ICON_MODIFIER(MOD_OCEAN)
+DEF_ICON_MODIFIER(MOD_WARP)
+DEF_ICON_MODIFIER(MOD_SKIN)
+DEF_ICON_MODIFIER(MOD_TRIANGULATE)
+DEF_ICON_MODIFIER(MOD_WIREFRAME)
+DEF_ICON_MODIFIER(MOD_DATA_TRANSFER)
+DEF_ICON_MODIFIER(MOD_NORMALEDIT)
+DEF_ICON_MODIFIER(MOD_PARTICLE_INSTANCE)
+DEF_ICON_MODIFIER(MOD_HUE_SATURATION)
+DEF_ICON_MODIFIER(MOD_NOISE)
+DEF_ICON_MODIFIER(MOD_OFFSET)
+DEF_ICON_MODIFIER(MOD_SIMPLIFY)
+DEF_ICON_MODIFIER(MOD_THICKNESS)
+DEF_ICON_MODIFIER(MOD_INSTANCE)
+DEF_ICON_MODIFIER(MOD_TIME)
+DEF_ICON_MODIFIER(MOD_OPACITY)
/* ANIMATION */
DEF_ICON(REC)
@@ -611,7 +589,7 @@ DEF_ICON(REW)
DEF_ICON(PAUSE)
DEF_ICON(PREV_KEYFRAME)
DEF_ICON(NEXT_KEYFRAME)
-DEF_ICON(PLAY_AUDIO)
+DEF_ICON_BLANK(185)
DEF_ICON(PLAY_REVERSE)
DEF_ICON(PREVIEW_RANGE)
DEF_ICON(ACTION_TWEAK)
@@ -620,8 +598,8 @@ DEF_ICON(PMARKER_SEL)
DEF_ICON(PMARKER)
DEF_ICON(MARKER_HLT)
DEF_ICON(MARKER)
-DEF_ICON(SPACE2) // XXX
-DEF_ICON(SPACE3) // XXX
+DEF_ICON(KEYFRAME_HLT)
+DEF_ICON(KEYFRAME)
DEF_ICON(KEYINGSET)
DEF_ICON(KEY_DEHLT)
DEF_ICON(KEY_HLT)
@@ -654,31 +632,24 @@ DEF_ICON(IPO_EASE_IN)
DEF_ICON(IPO_EASE_OUT)
DEF_ICON(IPO_EASE_IN_OUT)
DEF_ICON(NORMALIZE_FCURVES)
-#ifndef DEF_ICON_BLANK_SKIP
- /* available */
- DEF_ICON(BLANK204)
- DEF_ICON(BLANK205)
- DEF_ICON(BLANK206)
- DEF_ICON(BLANK207)
-#endif
+DEF_ICON_BLANK(635)
+DEF_ICON_BLANK(636)
+DEF_ICON_BLANK(637)
+DEF_ICON_BLANK(638)
/* EDITING */
DEF_ICON(VERTEXSEL)
DEF_ICON(EDGESEL)
DEF_ICON(FACESEL)
-DEF_ICON(LOOPSEL)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK210)
-#endif
-DEF_ICON(ROTATE)
-DEF_ICON(CURSOR)
-DEF_ICON(ROTATECOLLECTION)
-DEF_ICON(ROTATECENTER)
-DEF_ICON(ROTACTIVE)
-DEF_ICON(ALIGN)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK211)
-#endif
+DEF_ICON_BLANK(209)
+DEF_ICON_BLANK(210)
+DEF_ICON(PIVOT_BOUNDBOX)
+DEF_ICON(PIVOT_CURSOR)
+DEF_ICON(PIVOT_INDIVIDUAL)
+DEF_ICON(PIVOT_MEDIAN)
+DEF_ICON(PIVOT_ACTIVE)
+DEF_ICON(CENTER_ONLY)
+DEF_ICON_BLANK(652)
DEF_ICON(SMOOTHCURVE)
DEF_ICON(SPHERECURVE)
DEF_ICON(ROOTCURVE)
@@ -695,10 +666,10 @@ DEF_ICON(PARTICLE_TIP)
DEF_ICON(PARTICLE_PATH)
/* EDITING */
-DEF_ICON(MAN_TRANS)
-DEF_ICON(MAN_ROT)
-DEF_ICON(MAN_SCALE)
-DEF_ICON(MANIPUL)
+DEF_ICON_BLANK(669)
+DEF_ICON_BLANK(670)
+DEF_ICON_BLANK(671)
+DEF_ICON_BLANK(672)
DEF_ICON(SNAP_OFF)
DEF_ICON(SNAP_ON)
DEF_ICON(SNAP_NORMAL)
@@ -715,66 +686,54 @@ DEF_ICON(CLIPUV_DEHLT)
DEF_ICON(CLIPUV_HLT)
DEF_ICON(SNAP_PEEL_OBJECT)
DEF_ICON(GRID)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK221)
- DEF_ICON(BLANK222)
- DEF_ICON(BLANK224)
- DEF_ICON(BLANK225)
- DEF_ICON(BLANK226)
- DEF_ICON(BLANK226b)
-#endif
+DEF_ICON(OBJECT_ORIGIN)
+DEF_ICON(ORIENTATION_GLOBAL)
+DEF_ICON(ORIENTATION_GIMBAL)
+DEF_ICON(ORIENTATION_LOCAL)
+DEF_ICON(ORIENTATION_NORMAL)
+DEF_ICON(ORIENTATION_VIEW)
/* EDITING */
-DEF_ICON(PASTEDOWN)
DEF_ICON(COPYDOWN)
+DEF_ICON(PASTEDOWN)
DEF_ICON(PASTEFLIPUP)
DEF_ICON(PASTEFLIPDOWN)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK227)
- DEF_ICON(BLANK228)
- DEF_ICON(BLANK229)
- DEF_ICON(BLANK230)
-#endif
-DEF_ICON(SNAP_SURFACE)
+DEF_ICON(VIS_SEL_11)
+DEF_ICON(VIS_SEL_10)
+DEF_ICON(VIS_SEL_01)
+DEF_ICON(VIS_SEL_00)
+DEF_ICON_BLANK(231)
DEF_ICON(AUTOMERGE_ON)
DEF_ICON(AUTOMERGE_OFF)
-DEF_ICON(RETOPO)
+DEF_ICON_BLANK(234)
DEF_ICON(UV_VERTEXSEL)
DEF_ICON(UV_EDGESEL)
DEF_ICON(UV_FACESEL)
DEF_ICON(UV_ISLANDSEL)
DEF_ICON(UV_SYNC_SELECT)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK240)
- DEF_ICON(BLANK241)
- DEF_ICON(BLANK242)
- DEF_ICON(BLANK243)
- DEF_ICON(BLANK244)
- DEF_ICON(BLANK245)
- DEF_ICON(BLANK246)
- DEF_ICON(BLANK247)
- DEF_ICON(BLANK247b)
-#endif
+DEF_ICON_BLANK(240)
+DEF_ICON_BLANK(241)
+DEF_ICON_BLANK(242)
+DEF_ICON_BLANK(243)
+DEF_ICON_BLANK(244)
+DEF_ICON_BLANK(245)
+DEF_ICON(NORMALS_VERTEX)
+DEF_ICON(NORMALS_FACE)
+DEF_ICON(NORMALS_VERTEX_FACE)
/* 3D VIEW */
-DEF_ICON(BBOX)
-DEF_ICON(WIRE)
-DEF_ICON(SOLID)
-DEF_ICON(SMOOTH)
-DEF_ICON(POTATO)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK248)
-#endif
-DEF_ICON(ORTHO)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK249)
- DEF_ICON(BLANK250)
-#endif
+DEF_ICON(SHADING_BBOX)
+DEF_ICON(SHADING_WIRE)
+DEF_ICON(SHADING_SOLID)
+DEF_ICON(SHADING_RENDERED)
+DEF_ICON(SHADING_TEXTURE)
+DEF_ICON(OVERLAY)
+DEF_ICON(XRAY)
+DEF_ICON_BLANK(249)
+DEF_ICON_BLANK(250)
DEF_ICON(LOCKVIEW_OFF)
DEF_ICON(LOCKVIEW_ON)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK251)
-#endif
+DEF_ICON_BLANK(251)
DEF_ICON(AXIS_SIDE)
DEF_ICON(AXIS_FRONT)
DEF_ICON(AXIS_TOP)
@@ -784,57 +743,55 @@ DEF_ICON(NDOF_FLY)
DEF_ICON(NDOF_TRANS)
DEF_ICON(LAYER_USED)
DEF_ICON(LAYER_ACTIVE)
-#ifndef DEF_ICON_BLANK_SKIP
/* available */
- DEF_ICON(BLANK254)
- DEF_ICON(BLANK255)
- DEF_ICON(BLANK256)
- DEF_ICON(BLANK257)
- DEF_ICON(BLANK257b)
- DEF_ICON(BLANK258)
- DEF_ICON(BLANK259)
- DEF_ICON(BLANK260)
- DEF_ICON(BLANK261)
- DEF_ICON(BLANK262)
- DEF_ICON(BLANK263)
- DEF_ICON(BLANK264)
- DEF_ICON(BLANK265)
- DEF_ICON(BLANK266)
- DEF_ICON(BLANK267)
- DEF_ICON(BLANK268)
- DEF_ICON(BLANK269)
- DEF_ICON(BLANK270)
- DEF_ICON(BLANK271)
- DEF_ICON(BLANK272)
- DEF_ICON(BLANK273)
- DEF_ICON(BLANK274)
- DEF_ICON(BLANK275)
- DEF_ICON(BLANK276)
- DEF_ICON(BLANK277)
- DEF_ICON(BLANK278)
- DEF_ICON(BLANK279)
- DEF_ICON(BLANK280)
- DEF_ICON(BLANK281)
- DEF_ICON(BLANK282)
- DEF_ICON(BLANK282b)
-#endif
+DEF_ICON_BLANK(254)
+DEF_ICON_BLANK(255)
+DEF_ICON_BLANK(256)
+DEF_ICON_BLANK(257)
+DEF_ICON_BLANK(257b)
+DEF_ICON_BLANK(258)
+DEF_ICON_BLANK(259)
+DEF_ICON_BLANK(260)
+DEF_ICON_BLANK(261)
+DEF_ICON_BLANK(262)
+DEF_ICON_BLANK(263)
+DEF_ICON_BLANK(264)
+DEF_ICON_BLANK(265)
+DEF_ICON_BLANK(266)
+DEF_ICON_BLANK(267)
+DEF_ICON_BLANK(268)
+DEF_ICON_BLANK(269)
+DEF_ICON_BLANK(270)
+DEF_ICON_BLANK(271)
+DEF_ICON_BLANK(766)
+DEF_ICON_BLANK(767)
+DEF_ICON_BLANK(274)
+DEF_ICON_BLANK(275)
+DEF_ICON_BLANK(276)
+DEF_ICON_BLANK(277)
+DEF_ICON_BLANK(772)
+DEF_ICON_BLANK(773)
+DEF_ICON_BLANK(774)
+DEF_ICON_BLANK(775)
+DEF_ICON_BLANK(776)
+DEF_ICON_BLANK(777)
/* FILE SELECT */
DEF_ICON(SORTALPHA)
DEF_ICON(SORTBYEXT)
DEF_ICON(SORTTIME)
DEF_ICON(SORTSIZE)
-DEF_ICON(LONGDISPLAY)
DEF_ICON(SHORTDISPLAY)
-DEF_ICON(GHOST)
+DEF_ICON(LONGDISPLAY)
+DEF_ICON_BLANK(786)
DEF_ICON(IMGDISPLAY)
-DEF_ICON(SAVE_AS)
-DEF_ICON(SAVE_COPY)
+DEF_ICON_BLANK(788)
+DEF_ICON_BLANK(789)
DEF_ICON(BOOKMARKS)
DEF_ICON(FONTPREVIEW)
DEF_ICON(FILTER)
DEF_ICON(NEWFOLDER)
-DEF_ICON(OPEN_RECENT)
+DEF_ICON_BLANK(794)
DEF_ICON(FILE_PARENT)
DEF_ICON(FILE_REFRESH)
DEF_ICON(FILE_FOLDER)
@@ -848,33 +805,29 @@ DEF_ICON(FILE_FONT)
DEF_ICON(FILE_TEXT)
/* FILE SELECT */
-DEF_ICON(RECOVER_AUTO)
-DEF_ICON(SAVE_PREFS)
+DEF_ICON(SORT_DESC)
+DEF_ICON(SORT_ASC)
DEF_ICON(LINK_BLEND)
DEF_ICON(APPEND_BLEND)
DEF_ICON(IMPORT)
DEF_ICON(EXPORT)
-DEF_ICON(EXTERNAL_DATA)
-DEF_ICON(LOAD_FACTORY)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK300)
- DEF_ICON(BLANK301)
- DEF_ICON(BLANK302)
- DEF_ICON(BLANK303)
- DEF_ICON(BLANK304)
-#endif
+DEF_ICON_BLANK(814)
+DEF_ICON_BLANK(815)
+DEF_ICON_BLANK(816)
+DEF_ICON_BLANK(817)
+DEF_ICON_BLANK(818)
+DEF_ICON_BLANK(819)
+DEF_ICON_BLANK(820)
DEF_ICON(LOOP_BACK)
DEF_ICON(LOOP_FORWARDS)
DEF_ICON(BACK)
DEF_ICON(FORWARD)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK309)
- DEF_ICON(BLANK310)
- DEF_ICON(BLANK311)
- DEF_ICON(BLANK312)
- DEF_ICON(BLANK313)
- DEF_ICON(BLANK314)
-#endif
+DEF_ICON_BLANK(825)
+DEF_ICON_BLANK(826)
+DEF_ICON_BLANK(827)
+DEF_ICON(FILE_VOLUME)
+DEF_ICON(ALEMBIC)
+DEF_ICON(VOLUME)
DEF_ICON(FILE_HIDDEN)
DEF_ICON(FILE_BACKUP)
DEF_ICON(DISK_DRIVE)
@@ -888,28 +841,24 @@ DEF_ICON(HAIR)
DEF_ICON(ALIASED)
DEF_ICON(ANTIALIASED)
DEF_ICON(MAT_SPHERE_SKY)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK319)
- DEF_ICON(BLANK320)
- DEF_ICON(BLANK321)
- DEF_ICON(BLANK322)
-#endif
+DEF_ICON(MATSHADERBALL)
+DEF_ICON(MATCLOTH)
+DEF_ICON(MATFLUID)
+DEF_ICON_BLANK(847)
DEF_ICON(WORDWRAP_OFF)
DEF_ICON(WORDWRAP_ON)
DEF_ICON(SYNTAX_OFF)
DEF_ICON(SYNTAX_ON)
DEF_ICON(LINENUMBERS_OFF)
DEF_ICON(LINENUMBERS_ON)
-DEF_ICON(SCRIPTPLUGINS) // XXX CREATE NEW
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK323)
- DEF_ICON(BLANK324)
- DEF_ICON(BLANK325)
- DEF_ICON(BLANK326)
- DEF_ICON(BLANK327)
- DEF_ICON(BLANK328)
- DEF_ICON(BLANK328b)
-#endif
+DEF_ICON(SCRIPTPLUGINS)
+DEF_ICON_BLANK(855)
+DEF_ICON_BLANK(856)
+DEF_ICON_BLANK(857)
+DEF_ICON_BLANK(858)
+DEF_ICON_BLANK(859)
+DEF_ICON_BLANK(860)
+DEF_ICON_BLANK(861)
/* SEQUENCE / IMAGE EDITOR */
DEF_ICON(SEQ_SEQUENCER)
@@ -918,118 +867,209 @@ DEF_ICON(SEQ_LUMA_WAVEFORM)
DEF_ICON(SEQ_CHROMA_SCOPE)
DEF_ICON(SEQ_HISTOGRAM)
DEF_ICON(SEQ_SPLITVIEW)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK331)
- DEF_ICON(BLANK332)
- DEF_ICON(BLANK333)
-#endif
+DEF_ICON_BLANK(870)
+DEF_ICON_BLANK(871)
+DEF_ICON_BLANK(872)
DEF_ICON(IMAGE_RGB) // XXX CHANGE TO STRAIGHT ALPHA, Z ETC
DEF_ICON(IMAGE_RGB_ALPHA)
DEF_ICON(IMAGE_ALPHA)
DEF_ICON(IMAGE_ZDEPTH)
-DEF_ICON(IMAGEFILE)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK336)
- DEF_ICON(BLANK337)
- DEF_ICON(BLANK338)
- DEF_ICON(BLANK339)
- DEF_ICON(BLANK340)
- DEF_ICON(BLANK341)
- DEF_ICON(BLANK342)
- DEF_ICON(BLANK343)
- DEF_ICON(BLANK344)
- DEF_ICON(BLANK345)
- DEF_ICON(BLANK346)
- DEF_ICON(BLANK346b)
-#endif
+DEF_ICON_BLANK(877)
+DEF_ICON_BLANK(878)
+DEF_ICON_BLANK(879)
+DEF_ICON_BLANK(880)
+DEF_ICON_BLANK(881)
+DEF_ICON_BLANK(882)
+DEF_ICON_BLANK(883)
+DEF_ICON_BLANK(884)
+DEF_ICON(VIEW_PERSPECTIVE)
+DEF_ICON(VIEW_ORTHO)
+DEF_ICON(VIEW_CAMERA)
+DEF_ICON(VIEW_PAN)
+DEF_ICON(VIEW_ZOOM)
/* brush icons */
-DEF_ICON(BRUSH_ADD)
-DEF_ICON(BRUSH_BLOB)
-DEF_ICON(BRUSH_BLUR)
-DEF_ICON(BRUSH_CLAY)
-DEF_ICON(BRUSH_CLAY_STRIPS)
-DEF_ICON(BRUSH_CLONE)
-DEF_ICON(BRUSH_CREASE)
-DEF_ICON(BRUSH_DARKEN)
-DEF_ICON(BRUSH_FILL)
-DEF_ICON(BRUSH_FLATTEN)
-DEF_ICON(BRUSH_GRAB)
-DEF_ICON(BRUSH_INFLATE)
-DEF_ICON(BRUSH_LAYER)
-DEF_ICON(BRUSH_LIGHTEN)
-DEF_ICON(BRUSH_MASK)
-DEF_ICON(BRUSH_MIX)
-DEF_ICON(BRUSH_MULTIPLY)
-DEF_ICON(BRUSH_NUDGE)
-DEF_ICON(BRUSH_PINCH)
-DEF_ICON(BRUSH_SCRAPE)
-DEF_ICON(BRUSH_SCULPT_DRAW)
-DEF_ICON(BRUSH_SMEAR)
-DEF_ICON(BRUSH_SMOOTH)
-DEF_ICON(BRUSH_SNAKE_HOOK)
-DEF_ICON(BRUSH_SOFTEN)
-DEF_ICON(BRUSH_SUBTRACT)
-DEF_ICON(BRUSH_TEXDRAW)
-DEF_ICON(BRUSH_TEXFILL)
-DEF_ICON(BRUSH_TEXMASK)
-DEF_ICON(BRUSH_THUMB)
-DEF_ICON(BRUSH_ROTATE)
-DEF_ICON(BRUSH_VERTEXDRAW)
+DEF_ICON_COLOR(BRUSH_ADD)
+DEF_ICON_COLOR(BRUSH_BLOB)
+DEF_ICON_COLOR(BRUSH_BLUR)
+DEF_ICON_COLOR(BRUSH_CLAY)
+DEF_ICON_COLOR(BRUSH_CLAY_STRIPS)
+DEF_ICON_COLOR(BRUSH_CLONE)
+DEF_ICON_COLOR(BRUSH_CREASE)
+DEF_ICON_COLOR(BRUSH_DARKEN)
+DEF_ICON_COLOR(BRUSH_FILL)
+DEF_ICON_COLOR(BRUSH_FLATTEN)
+DEF_ICON_COLOR(BRUSH_GRAB)
+DEF_ICON_COLOR(BRUSH_INFLATE)
+DEF_ICON_COLOR(BRUSH_LAYER)
+DEF_ICON_COLOR(BRUSH_LIGHTEN)
+DEF_ICON_COLOR(BRUSH_MASK)
+DEF_ICON_COLOR(BRUSH_MIX)
+DEF_ICON_COLOR(BRUSH_MULTIPLY)
+DEF_ICON_COLOR(BRUSH_NUDGE)
+DEF_ICON_COLOR(BRUSH_PINCH)
+DEF_ICON_COLOR(BRUSH_SCRAPE)
+DEF_ICON_COLOR(BRUSH_SCULPT_DRAW)
+DEF_ICON_COLOR(BRUSH_SMEAR)
+DEF_ICON_COLOR(BRUSH_SMOOTH)
+DEF_ICON_COLOR(BRUSH_SNAKE_HOOK)
+DEF_ICON_COLOR(BRUSH_SOFTEN)
+DEF_ICON_COLOR(BRUSH_SUBTRACT)
+DEF_ICON_COLOR(BRUSH_TEXDRAW)
+DEF_ICON_COLOR(BRUSH_TEXFILL)
+DEF_ICON_COLOR(BRUSH_TEXMASK)
+DEF_ICON_COLOR(BRUSH_THUMB)
+DEF_ICON_COLOR(BRUSH_ROTATE)
+DEF_ICON_COLOR(BRUSH_VERTEXDRAW)
/* Matcaps */
-DEF_ICON(MATCAP_01)
-DEF_ICON(MATCAP_02)
-DEF_ICON(MATCAP_03)
-DEF_ICON(MATCAP_04)
-DEF_ICON(MATCAP_05)
-DEF_ICON(MATCAP_06)
-DEF_ICON(MATCAP_07)
-DEF_ICON(MATCAP_08)
-DEF_ICON(MATCAP_09)
-DEF_ICON(MATCAP_10)
-DEF_ICON(MATCAP_11)
-DEF_ICON(MATCAP_12)
-DEF_ICON(MATCAP_13)
-DEF_ICON(MATCAP_14)
-DEF_ICON(MATCAP_15)
-DEF_ICON(MATCAP_16)
-DEF_ICON(MATCAP_17)
-DEF_ICON(MATCAP_18)
-DEF_ICON(MATCAP_19)
-DEF_ICON(MATCAP_20)
-DEF_ICON(MATCAP_21)
-DEF_ICON(MATCAP_22)
-DEF_ICON(MATCAP_23)
-DEF_ICON(MATCAP_24)
+DEF_ICON_COLOR(MATCAP_01)
+DEF_ICON_COLOR(MATCAP_02)
+DEF_ICON_COLOR(MATCAP_03)
+DEF_ICON_COLOR(MATCAP_04)
+DEF_ICON_COLOR(MATCAP_05)
+DEF_ICON_COLOR(MATCAP_06)
+DEF_ICON_COLOR(MATCAP_07)
+DEF_ICON_COLOR(MATCAP_08)
+DEF_ICON_COLOR(MATCAP_09)
+DEF_ICON_COLOR(MATCAP_10)
+DEF_ICON_COLOR(MATCAP_11)
+DEF_ICON_COLOR(MATCAP_12)
+DEF_ICON_COLOR(MATCAP_13)
+DEF_ICON_COLOR(MATCAP_14)
+DEF_ICON_COLOR(MATCAP_15)
+DEF_ICON_COLOR(MATCAP_16)
+DEF_ICON_COLOR(MATCAP_17)
+DEF_ICON_COLOR(MATCAP_18)
+DEF_ICON_COLOR(MATCAP_19)
+DEF_ICON_COLOR(MATCAP_20)
+DEF_ICON_COLOR(MATCAP_21)
+DEF_ICON_COLOR(MATCAP_22)
+DEF_ICON_COLOR(MATCAP_23)
+DEF_ICON_COLOR(MATCAP_24)
+
+/* grease pencil sculpt */
+DEF_ICON_COLOR(GPBRUSH_SMOOTH)
+DEF_ICON_COLOR(GPBRUSH_THICKNESS)
+DEF_ICON_COLOR(GPBRUSH_STRENGTH)
+DEF_ICON_COLOR(GPBRUSH_GRAB)
+DEF_ICON_COLOR(GPBRUSH_PUSH)
+DEF_ICON_COLOR(GPBRUSH_TWIST)
+DEF_ICON_COLOR(GPBRUSH_PINCH)
+DEF_ICON_COLOR(GPBRUSH_RANDOMIZE)
+DEF_ICON_COLOR(GPBRUSH_CLONE)
+DEF_ICON_COLOR(GPBRUSH_WEIGHT)
+
+DEF_ICON_COLOR(GPBRUSH_PENCIL)
+DEF_ICON_COLOR(GPBRUSH_PEN)
+DEF_ICON_COLOR(GPBRUSH_INK)
+DEF_ICON_COLOR(GPBRUSH_INKNOISE)
+DEF_ICON_COLOR(GPBRUSH_BLOCK)
+DEF_ICON_COLOR(GPBRUSH_MARKER)
+DEF_ICON_COLOR(GPBRUSH_CUSTOM)
+DEF_ICON_COLOR(GPBRUSH_FILL)
+DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT)
+DEF_ICON_COLOR(GPBRUSH_ERASE_HARD)
+DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE)
+
+/* Vector Icons */
+DEF_ICON_VECTOR(SMALL_TRI_RIGHT_VEC)
+
+DEF_ICON_VECTOR(KEYTYPE_KEYFRAME_VEC)
+DEF_ICON_VECTOR(KEYTYPE_BREAKDOWN_VEC)
+DEF_ICON_VECTOR(KEYTYPE_EXTREME_VEC)
+DEF_ICON_VECTOR(KEYTYPE_JITTER_VEC)
+DEF_ICON_VECTOR(KEYTYPE_MOVING_HOLD_VEC)
+
+DEF_ICON_VECTOR(HANDLETYPE_FREE_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_ALIGNED_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_VECTOR_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_AUTO_VEC)
+DEF_ICON_VECTOR(HANDLETYPE_AUTO_CLAMP_VEC)
+
+DEF_ICON_VECTOR(COLORSET_01_VEC)
+DEF_ICON_VECTOR(COLORSET_02_VEC)
+DEF_ICON_VECTOR(COLORSET_03_VEC)
+DEF_ICON_VECTOR(COLORSET_04_VEC)
+DEF_ICON_VECTOR(COLORSET_05_VEC)
+DEF_ICON_VECTOR(COLORSET_06_VEC)
+DEF_ICON_VECTOR(COLORSET_07_VEC)
+DEF_ICON_VECTOR(COLORSET_08_VEC)
+DEF_ICON_VECTOR(COLORSET_09_VEC)
+DEF_ICON_VECTOR(COLORSET_10_VEC)
+DEF_ICON_VECTOR(COLORSET_11_VEC)
+DEF_ICON_VECTOR(COLORSET_12_VEC)
+DEF_ICON_VECTOR(COLORSET_13_VEC)
+DEF_ICON_VECTOR(COLORSET_14_VEC)
+DEF_ICON_VECTOR(COLORSET_15_VEC)
+DEF_ICON_VECTOR(COLORSET_16_VEC)
+DEF_ICON_VECTOR(COLORSET_17_VEC)
+DEF_ICON_VECTOR(COLORSET_18_VEC)
+DEF_ICON_VECTOR(COLORSET_19_VEC)
+DEF_ICON_VECTOR(COLORSET_20_VEC)
-/* vector icons, VICO_ prefix added */
-DEF_VICO(SMALL_TRI_RIGHT_VEC)
+/* Events */
+DEF_ICON_COLOR(EVENT_A)
+DEF_ICON_COLOR(EVENT_B)
+DEF_ICON_COLOR(EVENT_C)
+DEF_ICON_COLOR(EVENT_D)
+DEF_ICON_COLOR(EVENT_E)
+DEF_ICON_COLOR(EVENT_F)
+DEF_ICON_COLOR(EVENT_G)
+DEF_ICON_COLOR(EVENT_H)
+DEF_ICON_COLOR(EVENT_I)
+DEF_ICON_COLOR(EVENT_J)
+DEF_ICON_COLOR(EVENT_K)
+DEF_ICON_COLOR(EVENT_L)
+DEF_ICON_COLOR(EVENT_M)
+DEF_ICON_COLOR(EVENT_N)
+DEF_ICON_COLOR(EVENT_O)
+DEF_ICON_COLOR(EVENT_P)
+DEF_ICON_COLOR(EVENT_Q)
+DEF_ICON_COLOR(EVENT_R)
+DEF_ICON_COLOR(EVENT_S)
+DEF_ICON_COLOR(EVENT_T)
+DEF_ICON_COLOR(EVENT_U)
+DEF_ICON_COLOR(EVENT_V)
+DEF_ICON_COLOR(EVENT_W)
+DEF_ICON_COLOR(EVENT_X)
+DEF_ICON_COLOR(EVENT_Y)
+DEF_ICON_COLOR(EVENT_Z)
+DEF_ICON_COLOR(EVENT_SHIFT)
+DEF_ICON_COLOR(EVENT_CTRL)
+DEF_ICON_COLOR(EVENT_ALT)
+DEF_ICON_COLOR(EVENT_OS)
+DEF_ICON_COLOR(EVENT_F1)
+DEF_ICON_COLOR(EVENT_F2)
+DEF_ICON_COLOR(EVENT_F3)
+DEF_ICON_COLOR(EVENT_F4)
+DEF_ICON_COLOR(EVENT_F5)
+DEF_ICON_COLOR(EVENT_F6)
+DEF_ICON_COLOR(EVENT_F7)
+DEF_ICON_COLOR(EVENT_F8)
+DEF_ICON_COLOR(EVENT_F9)
+DEF_ICON_COLOR(EVENT_F10)
+DEF_ICON_COLOR(EVENT_F11)
+DEF_ICON_COLOR(EVENT_F12)
+DEF_ICON_COLOR(EVENT_ESC)
+DEF_ICON_COLOR(EVENT_TAB)
+DEF_ICON_COLOR(EVENT_PAGEUP)
+DEF_ICON_COLOR(EVENT_PAGEDOWN)
+DEF_ICON_COLOR(EVENT_HOME)
+DEF_ICON_COLOR(EVENT_END)
+DEF_ICON_COLOR(EVENT_RETURN)
+/* add as needed. */
-DEF_VICO(KEYTYPE_KEYFRAME_VEC)
-DEF_VICO(KEYTYPE_BREAKDOWN_VEC)
-DEF_VICO(KEYTYPE_EXTREME_VEC)
-DEF_VICO(KEYTYPE_JITTER_VEC)
-DEF_VICO(KEYTYPE_MOVING_HOLD_VEC)
+/* Undefine all types. */
-DEF_VICO(COLORSET_01_VEC)
-DEF_VICO(COLORSET_02_VEC)
-DEF_VICO(COLORSET_03_VEC)
-DEF_VICO(COLORSET_04_VEC)
-DEF_VICO(COLORSET_05_VEC)
-DEF_VICO(COLORSET_06_VEC)
-DEF_VICO(COLORSET_07_VEC)
-DEF_VICO(COLORSET_08_VEC)
-DEF_VICO(COLORSET_09_VEC)
-DEF_VICO(COLORSET_10_VEC)
-DEF_VICO(COLORSET_11_VEC)
-DEF_VICO(COLORSET_12_VEC)
-DEF_VICO(COLORSET_13_VEC)
-DEF_VICO(COLORSET_14_VEC)
-DEF_VICO(COLORSET_15_VEC)
-DEF_VICO(COLORSET_16_VEC)
-DEF_VICO(COLORSET_17_VEC)
-DEF_VICO(COLORSET_18_VEC)
-DEF_VICO(COLORSET_19_VEC)
-DEF_VICO(COLORSET_20_VEC)
+#undef DEF_ICON
+#undef DEF_ICON_ERROR
+#undef DEF_ICON_COLLECTION
+#undef DEF_ICON_OBJECT
+#undef DEF_ICON_OBJECT_DATA
+#undef DEF_ICON_MODIFIER
+#undef DEF_ICON_SHADING
+#undef DEF_ICON_VECTOR
+#undef DEF_ICON_COLOR
+#undef DEF_ICON_BLANK
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 48c917040f7..dac1ca95eff 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -42,6 +42,7 @@ struct ID;
struct IDProperty;
struct ListBase;
struct ARegion;
+struct ARegionType;
struct ScrArea;
struct bScreen;
struct wmEvent;
@@ -64,7 +65,6 @@ struct Image;
struct ImageUser;
struct wmKeyConfig;
struct wmOperatorType;
-struct uiWidgetColors;
struct MTex;
struct ImBuf;
struct bNodeTree;
@@ -73,6 +73,10 @@ struct bNodeSocket;
struct wmDropBox;
struct wmDrag;
struct wmEvent;
+struct wmGizmo;
+struct wmMsgBus;
+struct wmKeyMap;
+struct wmKeyMapItem;
typedef struct uiBut uiBut;
typedef struct uiBlock uiBlock;
@@ -99,6 +103,8 @@ enum {
UI_EMBOSS_NONE = 1, /* Nothing, only icon and/or text */
UI_EMBOSS_PULLDOWN = 2, /* Pulldown menu style */
UI_EMBOSS_RADIAL = 3, /* Pie Menu */
+
+ UI_EMBOSS_UNDEFINED = 255, /* For layout engine, use emboss from block. */
};
/* uiBlock->direction */
@@ -107,7 +113,8 @@ enum {
UI_DIR_DOWN = (1 << 1),
UI_DIR_LEFT = (1 << 2),
UI_DIR_RIGHT = (1 << 3),
- UI_DIR_CENTER_Y = (1 << 4),
+ UI_DIR_CENTER_X = (1 << 4),
+ UI_DIR_CENTER_Y = (1 << 5),
UI_DIR_ALL = (UI_DIR_UP | UI_DIR_DOWN | UI_DIR_LEFT | UI_DIR_RIGHT),
};
@@ -139,6 +146,10 @@ enum {
#define UI_BLOCK_POPUP_HOLD (1 << 18)
#define UI_BLOCK_LIST_ITEM (1 << 19)
#define UI_BLOCK_RADIAL (1 << 20)
+#define UI_BLOCK_POPOVER (1 << 21)
+#define UI_BLOCK_POPOVER_ONCE (1 << 22)
+/** Always show keymaps, even for non-menus. */
+#define UI_BLOCK_SHOW_SHORTCUT_ALWAYS (1 << 23)
/* uiPopupBlockHandle->menuretval */
#define UI_RETURN_CANCEL (1 << 0) /* cancel all menus cascading */
@@ -178,15 +189,18 @@ enum {
UI_BUT_COLOR_CUBIC = (1 << 23), /* cubic saturation for the color wheel */
UI_BUT_LIST_ITEM = (1 << 24), /* This but is "inside" a list item (currently used to change theme colors). */
UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */
- UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be gray out */
+
UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */
UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */
UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */
+
+ UI_BUT_OVERRIDEN = (1 << 31), /* RNA property of the button is overridden from linked reference data. */
};
#define UI_PANEL_WIDTH 340
#define UI_COMPACT_PANEL_WIDTH 160
+#define UI_NAVIGATION_REGION_WIDTH UI_COMPACT_PANEL_WIDTH
#define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f)
@@ -218,11 +232,19 @@ enum {
UI_BUT_ALIGN_ALL = (UI_BUT_ALIGN | UI_BUT_ALIGN_STITCH_TOP | UI_BUT_ALIGN_STITCH_LEFT),
UI_BUT_BOX_ITEM = (1 << 20), /* This but is "inside" a box item (currently used to change theme colors). */
+
+ UI_BUT_ACTIVE_LEFT = (1 << 21), /* Active left part of number button */
+ UI_BUT_ACTIVE_RIGHT = (1 << 22), /* Active right part of number button */
+
+ /* (also used by search buttons to enforce shortcut display for their items). */
+ UI_BUT_HAS_SHORTCUT = (1 << 23), /* Button has shortcut text. */
+
+ UI_BUT_ICON_REVERSE = (1 << 24), /* Reverse order of consecutive off/on icons */
};
/* scale fixed button widths by this to account for DPI */
-#define UI_DPI_FAC ((U.pixelsize * (float)U.dpi) / 72.0f)
+#define UI_DPI_FAC (U.dpi_fac)
/* 16 to copy ICON_DEFAULT_HEIGHT */
#define UI_DPI_ICON_SIZE ((float)16 * UI_DPI_FAC)
@@ -261,11 +283,11 @@ typedef enum {
UI_BTYPE_CHECKBOX = (13 << 9), /* similar to toggle, display a 'tick' */
UI_BTYPE_CHECKBOX_N = (14 << 9),
UI_BTYPE_COLOR = (15 << 9),
+ UI_BTYPE_TAB = (16 << 9),
+ UI_BTYPE_POPOVER = (17 << 9),
UI_BTYPE_SCROLL = (18 << 9),
UI_BTYPE_BLOCK = (19 << 9),
UI_BTYPE_LABEL = (20 << 9),
- UI_BTYPE_LINK = (22 << 9),
- UI_BTYPE_INLINK = (23 << 9),
UI_BTYPE_KEY_EVENT = (24 << 9),
UI_BTYPE_HSVCUBE = (26 << 9),
UI_BTYPE_PULLDOWN = (27 << 9), /* menu (often used in headers), **_MENU /w different draw-type */
@@ -290,7 +312,8 @@ typedef enum {
UI_BTYPE_NODE_SOCKET = (53 << 9),
UI_BTYPE_SEPR = (54 << 9),
UI_BTYPE_SEPR_LINE = (55 << 9),
- UI_BTYPE_GRIP = (56 << 9), /* resize handle (resize uilist) */
+ UI_BTYPE_SEPR_SPACER = (56 << 9), /* Dynamically fill available space. */
+ UI_BTYPE_GRIP = (57 << 9), /* resize handle (resize uilist) */
} eButType;
#define BUTTYPE (63 << 9)
@@ -313,18 +336,25 @@ typedef enum {
* Functions to draw various shapes, taking theme settings into account.
* Used for code that draws its own UI style elements. */
-void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad);
+void UI_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]);
+void UI_draw_anti_fan(float tri_array[][2], unsigned int length, const float color[4]);
+
void UI_draw_roundbox_corner_set(int type);
+void UI_draw_roundbox_aa(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4]);
+void UI_draw_roundbox_4fv(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[4]);
+void UI_draw_roundbox_3ubAlpha(bool filled, float minx, float miny, float maxx, float maxy, float rad, const unsigned char col[3], unsigned char alpha);
+void UI_draw_roundbox_3fvAlpha(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[3], float alpha);
+void UI_draw_roundbox_shade_x(bool filled, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown, const float col[4]);
+
+#if 0 /* unused */
int UI_draw_roundbox_corner_get(void);
-void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad);
+void UI_draw_roundbox_shade_y(bool filled, float minx, float miny, float maxx, float maxy, float rad, float shadeleft, float shaderight, const float col[4]);
+#endif
+
void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy);
-void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad);
-void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown);
-void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight);
-void UI_draw_text_underline(int pos_x, int pos_y, int len, int height);
+void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]);
-void UI_draw_safe_areas(
- float x1, float x2, float y1, float y2,
+void UI_draw_safe_areas(uint pos, float x1, float x2, float y1, float y2,
const float title_aspect[2], const float action_aspect[2]);
/* state for scrolldrawing */
@@ -381,6 +411,11 @@ typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1);
/* interface_query.c */
+bool UI_but_has_tooltip_label(const uiBut *but);
+bool UI_but_is_tool(const uiBut *but);
+#define UI_but_is_decorator(but) \
+ ((but)->func == ui_but_anim_decorate_cb)
+
bool UI_block_is_empty(const uiBlock *block);
@@ -409,6 +444,19 @@ int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportLi
void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but);
+/* interface_region_popover.c */
+
+typedef struct uiPopover uiPopover;
+
+int UI_popover_panel_invoke(
+ struct bContext *C, const char *idname,
+ bool keep_open, struct ReportList *reports);
+
+uiPopover *UI_popover_begin(struct bContext *C, int menu_width) ATTR_NONNULL(1);
+void UI_popover_end(struct bContext *C, struct uiPopover *head, struct wmKeyMap *keymap);
+struct uiLayout *UI_popover_layout(uiPopover *head);
+void UI_popover_once_clear(uiPopover *pup);
+
/* interface_region_menu_pie.c */
/* Pie menus */
typedef struct uiPieMenu uiPieMenu;
@@ -458,10 +506,10 @@ uiBlock *UI_block_begin(const struct bContext *C, struct ARegion *region, const
void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2], int r_xy[2]);
void UI_block_end(const struct bContext *C, uiBlock *block);
void UI_block_draw(const struct bContext *C, struct uiBlock *block);
+void UI_blocklist_update_window_matrix(const struct bContext *C, const struct ListBase *lb);
+void UI_blocklist_draw(const struct bContext *C, const struct ListBase *lb);
void UI_block_update_from_old(const struct bContext *C, struct uiBlock *block);
-uiBlock *UI_block_find_in_region(const char *name, struct ARegion *ar);
-
enum {
UI_BLOCK_THEME_STYLE_REGULAR = 0,
UI_BLOCK_THEME_STYLE_POPUP = 1,
@@ -507,6 +555,7 @@ void UI_block_direction_set(uiBlock *block, char direction);
void UI_block_order_flip(uiBlock *block);
void UI_block_flag_enable(uiBlock *block, int flag);
void UI_block_flag_disable(uiBlock *block, int flag);
+void UI_block_translate(uiBlock *block, int x, int y);
int UI_but_return_value_get(uiBut *but);
@@ -673,6 +722,7 @@ void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0
#define UI_ID_FAKE_USER (1 << 8)
#define UI_ID_PIN (1 << 9)
#define UI_ID_PREVIEWS (1 << 10)
+#define UI_ID_OVERRIDE (1 << 11)
#define UI_ID_FULL (UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | UI_ID_DELETE | UI_ID_LOCAL)
/**
@@ -687,6 +737,9 @@ enum {
int UI_icon_from_id(struct ID *id);
int UI_icon_from_report_type(int type);
+int UI_icon_from_event_type(short event_type, short event_value);
+int UI_icon_from_keymap_item(const struct wmKeyMapItem *kmi, int r_icon_mod[4]);
+
uiBut *uiDefPulldownBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip);
uiBut *uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip);
uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, const char *str, int x, int y, short width, short height, const char *tip);
@@ -707,22 +760,30 @@ uiBut *uiDefSearchButO_ptr(
void *arg, int retval, int icon, int maxlen, int x, int y,
short width, short height, float a1, float a2, const char *tip);
-uiBut *uiDefAutoButR(uiBlock *block, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, const char *name, int icon, int x1, int y1, int x2, int y2);
-int uiDefAutoButsRNA(
+/* For uiDefAutoButsRNA */
+typedef enum {
+ /* Keep current layout for aligning label with property button. */
+ UI_BUT_LABEL_ALIGN_NONE,
+ /* Align label and property button vertically. */
+ UI_BUT_LABEL_ALIGN_COLUMN,
+ /* Split layout into a column for the label and one for property button. */
+ UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
+} eButLabelAlign;
+
+/* Return info for uiDefAutoButsRNA */
+typedef enum {
+ /* Returns when no buttons were added */
+ UI_PROP_BUTS_NONE_ADDED = (1 << 0),
+ /* Returned when any property failed the custom check callback (check_prop) */
+ UI_PROP_BUTS_ANY_FAILED_CHECK = (1 << 1),
+} eAutoPropButsReturn;
+
+uiBut *uiDefAutoButR(uiBlock *block, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, const char *name, int icon, int x1, int y1, int x2, int y2);
+eAutoPropButsReturn uiDefAutoButsRNA(
uiLayout *layout, struct PointerRNA *ptr,
bool (*check_prop)(struct PointerRNA *ptr, struct PropertyRNA *prop, void *user_data), void *user_data,
- const char label_align);
-
-/* Links
- *
- * Game engine logic brick links. Non-functional currently in 2.5,
- * code to handle and draw these is disabled internally. */
-
-void UI_but_link_set(struct uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to);
-
-void UI_block_links_compose(uiBlock *block);
-uiBut *UI_block_links_find_inlink(uiBlock *block, void *poin);
+ eButLabelAlign label_align, const bool compact);
/* use inside searchfunc to add items */
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid);
@@ -793,12 +854,15 @@ void UI_panels_begin(const struct bContext *C, struct ARegion *ar);
void UI_panels_end(const struct bContext *C, struct ARegion *ar, int *x, int *y);
void UI_panels_draw(const struct bContext *C, struct ARegion *ar);
-struct Panel *UI_panel_find_by_type(struct ARegion *ar, struct PanelType *pt);
+struct Panel *UI_panel_find_by_type(struct ListBase *lb, struct PanelType *pt);
struct Panel *UI_panel_begin(
- struct ScrArea *sa, struct ARegion *ar, uiBlock *block,
- struct PanelType *pt, struct Panel *pa, bool *r_open);
+ struct ScrArea *sa, struct ARegion *ar, struct ListBase *lb,
+ uiBlock *block, struct PanelType *pt, struct Panel *pa,
+ bool *r_open);
void UI_panel_end(uiBlock *block, int width, int height);
void UI_panels_scale(struct ARegion *ar, float new_width);
+void UI_panel_label_offset(struct uiBlock *block, int *x, int *y);
+int UI_panel_size_y(const struct Panel *pa);
bool UI_panel_category_is_visible(struct ARegion *ar);
void UI_panel_category_add(struct ARegion *ar, const char *name);
@@ -811,6 +875,8 @@ struct PanelCategoryDyn *UI_panel_category_find_mouse_over(struct ARegion *ar,
void UI_panel_category_clear_all(struct ARegion *ar);
void UI_panel_category_draw_all(struct ARegion *ar, const char *category_id_active);
+struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname);
+
/* Handlers
*
* Handlers that can be registered in regions, areas and windows for
@@ -830,7 +896,6 @@ void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers)
void UI_init(void);
void UI_init_userdef(struct Main *bmain);
void UI_reinit_font(void);
-void UI_reinit_gl_state(void);
void UI_exit(void);
/* Layout
@@ -852,6 +917,7 @@ void UI_exit(void);
#define UI_LAYOUT_MENU 2
#define UI_LAYOUT_TOOLBAR 3
#define UI_LAYOUT_PIEMENU 4
+#define UI_LAYOUT_VERT_BAR 5
#define UI_UNIT_X ((void)0, U.widget_unit)
#define UI_UNIT_Y ((void)0, U.widget_unit)
@@ -861,6 +927,7 @@ void UI_exit(void);
#define UI_LAYOUT_ALIGN_CENTER 2
#define UI_LAYOUT_ALIGN_RIGHT 3
+#define UI_ITEM_O_RETURN_PROPS (1 << 0)
#define UI_ITEM_R_EXPAND (1 << 1)
#define UI_ITEM_R_SLIDER (1 << 2)
#define UI_ITEM_R_TOGGLE (1 << 3)
@@ -870,10 +937,17 @@ void UI_exit(void);
#define UI_ITEM_R_NO_BG (1 << 7)
#define UI_ITEM_R_IMMEDIATE (1 << 8)
#define UI_ITEM_O_DEPRESS (1 << 9)
+#define UI_ITEM_R_COMPACT (1 << 10)
+
+#define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X)
-/* uiTemplateOperatorPropertyButs flags */
-#define UI_TEMPLATE_OP_PROPS_SHOW_TITLE 1
-#define UI_TEMPLATE_OP_PROPS_SHOW_EMPTY 2
+/* uiLayoutOperatorButs flags */
+enum {
+ UI_TEMPLATE_OP_PROPS_SHOW_TITLE = (1 << 0),
+ UI_TEMPLATE_OP_PROPS_SHOW_EMPTY = (1 << 1),
+ UI_TEMPLATE_OP_PROPS_COMPACT = (1 << 2),
+ UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED = (1 << 3),
+};
/* used for transp checkers */
#define UI_ALPHA_CHECKER_DARK 100
@@ -895,20 +969,21 @@ enum {
UI_CNR_ALL = (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)
};
-/* not apart of the corner flags but mixed in some functions */
-#define UI_RB_ALPHA (UI_CNR_ALL + 1)
-
uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, struct uiStyle *style);
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *x, int *y);
+void UI_region_message_subscribe(struct ARegion *ar, struct wmMsgBus *mbus);
+
uiBlock *uiLayoutGetBlock(uiLayout *layout);
void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr);
void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context);
struct MenuType *UI_but_menutype_get(uiBut *but);
+struct PanelType *UI_but_paneltype_get(uiBut *but);
void UI_menutype_draw(struct bContext *C, struct MenuType *mt, struct uiLayout *layout);
+void UI_paneltype_draw(struct bContext *C, struct PanelType *pt, struct uiLayout *layout);
/* Only for convenience. */
void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but);
@@ -921,6 +996,11 @@ void uiLayoutSetAlignment(uiLayout *layout, char alignment);
void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect);
void uiLayoutSetScaleX(uiLayout *layout, float scale);
void uiLayoutSetScaleY(uiLayout *layout, float scale);
+void uiLayoutSetUnitsX(uiLayout *layout, float unit);
+void uiLayoutSetUnitsY(uiLayout *layout, float unit);
+void uiLayoutSetEmboss(uiLayout *layout, char emboss);
+void uiLayoutSetPropSep(uiLayout *layout, bool is_sep);
+void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep);
int uiLayoutGetOperatorContext(uiLayout *layout);
bool uiLayoutGetActive(uiLayout *layout);
@@ -931,11 +1011,18 @@ bool uiLayoutGetKeepAspect(uiLayout *layout);
int uiLayoutGetWidth(uiLayout *layout);
float uiLayoutGetScaleX(uiLayout *layout);
float uiLayoutGetScaleY(uiLayout *layout);
+float uiLayoutGetUnitsX(uiLayout *layout);
+float uiLayoutGetUnitsY(uiLayout *layout);
+int uiLayoutGetEmboss(uiLayout *layout);
+bool uiLayoutGetPropSep(uiLayout *layout);
+bool uiLayoutGetPropDecorate(uiLayout *layout);
/* layout specifiers */
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
+uiLayout *uiLayoutGridFlow(
+ uiLayout *layout, bool row_major, int columns_len, bool even_columns, bool even_rows, bool align);
uiLayout *uiLayoutBox(uiLayout *layout);
uiLayout *uiLayoutListBox(
uiLayout *layout, struct uiList *ui_list, struct PointerRNA *ptr, struct PropertyRNA *prop,
@@ -950,41 +1037,66 @@ uiLayout *uiLayoutRadial(uiLayout *layout);
void uiTemplateHeader(uiLayout *layout, struct bContext *C);
void uiTemplateID(
uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop, int filter);
+ const char *newop, const char *openop, const char *unlinkop,
+ int filter, const bool live_icon);
void uiTemplateIDBrowse(
uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
const char *newop, const char *openop, const char *unlinkop, int filter);
void uiTemplateIDPreview(
uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop, int rows, int cols, int filter);
+ const char *newop, const char *openop, const char *unlinkop, int rows, int cols,
+ int filter, const bool hide_buttons);
+void uiTemplateIDTabs(
+ uiLayout *layout, struct bContext *C,
+ PointerRNA *ptr, const char *propname,
+ const char *newop, const char *menu,
+ int filter);
void uiTemplateAnyID(
uiLayout *layout, struct PointerRNA *ptr, const char *propname,
const char *proptypename, const char *text);
+void uiTemplateSearch(
+ uiLayout *layout, struct bContext *C,
+ struct PointerRNA *ptr, const char *propname,
+ struct PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop);
+void uiTemplateSearchPreview(
+ uiLayout *layout, struct bContext *C,
+ struct PointerRNA *ptr, const char *propname,
+ struct PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop,
+ const int rows, const int cols);
void uiTemplatePathBuilder(
uiLayout *layout, struct PointerRNA *ptr, const char *propname,
struct PointerRNA *root_ptr, const char *text);
uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
+uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
+void uiTemplateGpencilColorPreview(
+ uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
+ int rows, int cols, float scale, int filter);
+
+uiLayout *uiTemplateShaderFx(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
+
+void uiTemplateOperatorRedoProperties(uiLayout *layout, const struct bContext *C);
+
uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplatePreview(
uiLayout *layout, struct bContext *C, struct ID *id, bool show_buttons, struct ID *parent,
struct MTex *slot, const char *preview_id);
void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool expand);
+void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale);
void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool show_labels, float icon_scale);
void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateWaveform(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateCurveMapping(
uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type,
- bool levels, bool brush, bool neg_slope);
+ bool levels, bool brush, bool neg_slope, bool tone);
void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic);
void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool color);
void uiTemplateCryptoPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateLayers(
uiLayout *layout, struct PointerRNA *ptr, const char *propname,
PointerRNA *used_ptr, const char *used_propname, int active_layer);
-void uiTemplateGameStates(
- uiLayout *layout, struct PointerRNA *ptr, const char *propname,
- PointerRNA *used_ptr, const char *used_propname, int active_state);
void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, bool compact, bool multiview);
void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, bool color_management);
void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
@@ -995,12 +1107,14 @@ void uiTemplateImageInfo(uiLayout *layout, struct bContext *C, struct Image *ima
void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C);
void UI_but_func_operator_search(uiBut *but);
void uiTemplateOperatorSearch(uiLayout *layout);
-void uiTemplateOperatorPropertyButs(
+eAutoPropButsReturn uiTemplateOperatorPropertyButs(
const struct bContext *C, uiLayout *layout, struct wmOperator *op,
- const char label_align, const short flag);
+ const eButLabelAlign label_align, const short flag);
+void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C);
void uiTemplateHeader3D(uiLayout *layout, struct bContext *C);
void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
+void uiTemplateInputStatus(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);
@@ -1012,7 +1126,7 @@ void uiTemplateList(
uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id,
struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr,
const char *active_propname, const char *item_dyntip_propname,
- int rows, int maxrows, int layout_type, int columns);
+ int rows, int maxrows, int layout_type, int columns, bool reverse);
void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
@@ -1026,6 +1140,8 @@ void uiTemplateMovieclipInformation(struct uiLayout *layout, struct PointerRNA *
void uiTemplateColorspaceSettings(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateColormanagedViewSettings(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname);
+int uiTemplateRecentFiles(struct uiLayout *layout, int rows);
+
/* items */
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname);
void uiItemEnumO_ptr(uiLayout *layout, struct wmOperatorType *ot, const char *name, int icon, const char *propname, int value);
@@ -1074,6 +1190,21 @@ void uiItemLDrag(uiLayout *layout, struct PointerRNA *ptr, const char *name, int
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon); /* menu */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval); /* value */
void uiItemS(uiLayout *layout); /* separator */
+void uiItemS_ex(uiLayout *layout, float factor);
+void uiItemSpacer(uiLayout *layout); /* Special separator. */
+
+void uiItemPopoverPanel_ptr(
+ uiLayout *layout, struct bContext *C,
+ struct PanelType *pt,
+ const char *name, int icon);
+void uiItemPopoverPanel(
+ uiLayout *layout, struct bContext *C,
+ const char *panelname,
+ const char *name, int icon);
+void uiItemPopoverPanelFromGroup(
+ uiLayout *layout, struct bContext *C,
+ int space_id, int region_id,
+ const char *context, const char *category);
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg);
void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN);
@@ -1081,6 +1212,7 @@ void uiItemMenuEnumO_ptr(uiLayout *layout, struct bContext *C, struct wmOperator
void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, const char *propname, const char *name, int icon);
void uiItemMenuEnumR_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon);
void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon);
+void uiItemTabsEnumR_prop(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, PropertyRNA *prop, bool icon_only);
/* UI Operators */
typedef struct uiDragColorHandle {
@@ -1092,7 +1224,7 @@ void ED_operatortypes_ui(void);
void ED_keymap_ui(struct wmKeyConfig *keyconf);
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
-bool UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
+bool UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event, const char **tooltip);
bool UI_context_copy_to_selected_list(
struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
@@ -1112,6 +1244,7 @@ void UI_context_active_but_prop_get_filebrowser(
void UI_context_active_but_prop_get_templateID(
struct bContext *C,
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
+struct ID *UI_context_active_but_get_tab_ID(struct bContext *C);
uiBut *UI_region_active_but_get(struct ARegion *ar);
@@ -1119,18 +1252,24 @@ uiBut *UI_region_active_but_get(struct ARegion *ar);
void UI_fontstyle_set(const struct uiFontStyle *fs);
void UI_fontstyle_draw_ex(
const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
- size_t len, float *r_xofs, float *r_yofs);
-void UI_fontstyle_draw(const struct uiFontStyle *fs, const struct rcti *rect, const char *str);
-void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs, const struct rcti *rect, const char *str);
-void UI_fontstyle_draw_simple(const struct uiFontStyle *fs, float x, float y, const char *str);
+ const unsigned char col[4], size_t len, float *r_xofs, float *r_yofs);
+void UI_fontstyle_draw(
+ const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
+ const unsigned char col[4]);
+void UI_fontstyle_draw_rotated(
+ const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
+ const unsigned char col[4]);
+void UI_fontstyle_draw_simple(
+ const struct uiFontStyle *fs, float x, float y, const char *str,
+ const unsigned char col[4]);
void UI_fontstyle_draw_simple_backdrop(
const struct uiFontStyle *fs, float x, float y, const char *str,
- const unsigned char fg[4], const unsigned char bg[4]);
+ const float col_fg[4], const float col_bg[4]);
int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str);
int UI_fontstyle_height_max(const struct uiFontStyle *fs);
-void UI_draw_icon_tri(float x, float y, char dir);
+void UI_draw_icon_tri(float x, float y, char dir, const float[4]);
struct uiStyle *UI_style_get(void); /* use for fonts etc */
struct uiStyle *UI_style_get_dpi(void); /* DPI scaled settings for drawing */
@@ -1157,11 +1296,13 @@ bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *bu
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
/* ui_interface_region_tooltip.c */
-struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but);
+struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but, bool is_label);
+struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz);
void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar);
/* How long before a tool-tip shows. */
#define UI_TOOLTIP_DELAY 0.5
+#define UI_TOOLTIP_DELAY_LABEL 0.2
/* Float precision helpers */
#define UI_PRECISION_FLOAT_MAX 6
@@ -1173,4 +1314,15 @@ void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar)
int UI_calc_float_precision(int prec, double value);
+/* widget batched drawing */
+void UI_widgetbase_draw_cache_begin(void);
+void UI_widgetbase_draw_cache_flush(void);
+void UI_widgetbase_draw_cache_end(void);
+
+/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
+#define USE_UI_TOOLBAR_HACK
+
+/* Support click-drag motion which presses the button and closes a popover (like a menu). */
+#define USE_UI_POPOVER_ONCE
+
#endif /* __UI_INTERFACE_H__ */
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 308504ef4c4..640d66c9ac4 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -49,6 +49,8 @@ typedef struct IconFile {
#define ICON_DEFAULT_HEIGHT 16
#define ICON_DEFAULT_WIDTH 16
+#define ICON_DEFAULT_HEIGHT_TOOLBAR 32
+
#define ICON_DEFAULT_HEIGHT_SCALE ((int)(UI_UNIT_Y * 0.8f))
#define ICON_DEFAULT_WIDTH_SCALE ((int)(UI_UNIT_X * 0.8f))
@@ -57,7 +59,7 @@ typedef struct IconFile {
/*
* Resizable Icons for Blender
*/
-void UI_icons_init(int first_dyn_id);
+void UI_icons_init(void);
int UI_icon_get_width(int icon_id);
int UI_icon_get_height(int icon_id);
@@ -66,16 +68,21 @@ void UI_id_icon_render(
int UI_preview_render_size(enum eIconSizes size);
void UI_icon_draw(float x, float y, int icon_id);
+void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha);
void UI_icon_draw_preview(float x, float y, int icon_id);
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect);
void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size);
-void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha);
-void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, const float rgb[3]);
+void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha, const char mono_color[4]);
+void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, const float rgb[3], const char mono_color[4]);
void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha);
+void UI_icon_draw_desaturate(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const char mono_color[4]);
void UI_icons_free(void);
void UI_icons_free_drawinfo(void *drawinfo);
+void UI_icon_draw_cache_begin(void);
+void UI_icon_draw_cache_end(void);
+
struct ListBase *UI_iconfile_list(void);
int UI_iconfile_get_index(const char *filename);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index b0cb2418e6f..277aae923d6 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -29,13 +29,16 @@
* \ingroup editorui
*/
+#include "BLI_sys_types.h"
+
#ifndef __UI_RESOURCES_H__
#define __UI_RESOURCES_H__
-/* elubie: TODO: move the typedef for icons to UI_interface_icons.h */
-/* and add/replace include of UI_resources.h by UI_interface_icons.h */
+/* Define icon enum. */
#define DEF_ICON(name) ICON_##name,
-#define DEF_VICO(name) VICO_##name,
+#define DEF_ICON_VECTOR(name) ICON_##name,
+#define DEF_ICON_COLOR(name) ICON_##name,
+#define DEF_ICON_BLANK(name) ICON_BLANK_##name,
typedef enum {
/* ui */
@@ -45,13 +48,10 @@ typedef enum {
#define BIFICONID_FIRST (ICON_NONE)
-#undef DEF_ICON
-#undef DEF_VICO
-
/* use to denote intentionally unset theme color */
#define TH_UNDEFINED -1
-enum {
+typedef enum ThemeColorID {
TH_REDALERT,
TH_THEMEUI,
@@ -74,8 +74,7 @@ enum {
/* panels */
TH_PANEL_HEADER,
TH_PANEL_BACK,
- TH_PANEL_SHOW_HEADER,
- TH_PANEL_SHOW_BACK,
+ TH_PANEL_SUB_BACK,
TH_BUTBACK,
TH_BUTBACK_TEXT,
@@ -157,6 +156,8 @@ enum {
TH_KEYTYPE_BREAKDOWN_SELECT,
TH_KEYTYPE_JITTER,
TH_KEYTYPE_JITTER_SELECT,
+ TH_KEYTYPE_MOVEHOLD,
+ TH_KEYTYPE_MOVEHOLD_SELECT,
TH_KEYBORDER,
TH_KEYBORDER_SELECT,
@@ -216,6 +217,7 @@ enum {
TH_DOPESHEET_CHANNELOB,
TH_DOPESHEET_CHANNELSUBOB,
+ TH_DOPESHEET_IPOLINE,
TH_PREVIEW_BACK,
@@ -262,6 +264,13 @@ enum {
TH_ANIM_ACTIVE, /* active action */
TH_ANIM_INACTIVE, /* no active action */
+ TH_ANIM_PREVIEW_RANGE,/* preview range overlay */
+
+ TH_ICON_COLLECTION,
+ TH_ICON_OBJECT,
+ TH_ICON_OBJECT_DATA,
+ TH_ICON_MODIFIER,
+ TH_ICON_SHADING,
TH_NLA_TWEAK, /* 'tweaking' track in NLA */
TH_NLA_TWEAK_DUPLI, /* error/warning flag for other strips referencing dupli strip */
@@ -275,10 +284,18 @@ enum {
TH_WIDGET_EMBOSS,
+ TH_EDITOR_OUTLINE,
+
TH_AXIS_X, /* X/Y/Z Axis */
TH_AXIS_Y,
TH_AXIS_Z,
+ TH_GIZMO_HI,
+ TH_GIZMO_PRIMARY,
+ TH_GIZMO_SECONDARY,
+ TH_GIZMO_A,
+ TH_GIZMO_B,
+
TH_LOW_GRAD,
TH_HIGH_GRAD,
TH_SHOW_BACK_GRAD,
@@ -302,7 +319,7 @@ enum {
TH_EDGE_BEVEL,
TH_VERTEX_BEVEL
-};
+} ThemeColorID;
/* specific defines per space should have higher define values */
@@ -315,24 +332,6 @@ struct bThemeState {
// THE CODERS API FOR THEMES:
-// sets the color
-void UI_ThemeColor(int colorid);
-
-// sets the color plus alpha
-void UI_ThemeColor4(int colorid);
-
-// sets color plus offset for shade
-void UI_ThemeColorShade(int colorid, int offset);
-
-// sets color plus offset for alpha
-void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset);
-
-// sets color, which is blend between two theme colors
-void UI_ThemeColorBlend(int colorid1, int colorid2, float fac);
-// same, with shade offset
-void UI_ThemeColorBlendShade(int colorid1, int colorid2, float fac, int offset);
-void UI_ThemeColorBlendShadeAlpha(int colorid1, int colorid2, float fac, int offset, int alphaoffset);
-
// returns one value, not scaled
float UI_GetThemeValuef(int colorid);
int UI_GetThemeValue(int colorid);
@@ -343,14 +342,27 @@ int UI_GetThemeValueType(int colorid, int spacetype);
// get three color values, scaled to 0.0-1.0 range
void UI_GetThemeColor3fv(int colorid, float col[3]);
void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3]);
+void UI_GetThemeColorBlend3f(int colorid1, int colorid2, float fac, float r_col[3]);
// get the color, range 0.0-1.0, complete with shading offset
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3]);
void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]);
+void UI_GetThemeColorShade4ubv(int colorid, int offset, unsigned char col[4]);
+
+// get three color values, range 0-255, complete with shading offset for the RGB components and blending
+void UI_GetThemeColorBlendShade3ubv(int colorid1, int colorid2, float fac, int offset, unsigned char col[3]);
// get four color values, scaled to 0.0-1.0 range
void UI_GetThemeColor4fv(int colorid, float col[4]);
// get four color values, range 0.0-1.0, complete with shading offset for the RGB components
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]);
+void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4]);
+
+// get four colour values ranged between 0 and 255; includes the alpha channel
+void UI_GetThemeColorShadeAlpha4ubv(int colorid, int coloffset, int alphaoffset, unsigned char col[4]);
+
+// get four color values, range 0.0-1.0, complete with shading offset for the RGB components and blending
+void UI_GetThemeColorBlendShade3fv(int colorid1, int colorid2, float fac, int offset, float col[3]);
+void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int offset, float col[4]);
// get the 3 or 4 byte values
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]);
@@ -359,8 +371,8 @@ void UI_GetThemeColor4ubv(int colorid, unsigned char col[4]);
// get a theme color from specified space type
void UI_GetThemeColorType4ubv(int colorid, int spacetype, char col[4]);
-// blends and shades between two color pointers
-void UI_ColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned char cp2[3], float fac, int offset);
+// get theme color for coloring monochrome icons
+bool UI_GetIconThemeColor4fv(int colorid, float col[4]);
// shade a 3 byte color (same as UI_GetColorPtrBlendShade3ubv with 0.0 factor)
void UI_GetColorPtrShade3ubv(const unsigned char cp1[3], unsigned char col[3], int offset);
@@ -368,6 +380,10 @@ void UI_GetColorPtrShade3ubv(const unsigned char cp1[3], unsigned char col[3]
// get a 3 byte color, blended and shaded between two other char color pointers
void UI_GetColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned char cp2[3], unsigned char col[3], float fac, int offset);
+// sets the font color
+// (for anything fancy use UI_GetThemeColor[Fancy] then BLF_color)
+void UI_FontThemeColor(int fontid, int colorid);
+
// clear the openGL ClearColor using the input colorid
void UI_ThemeClearColor(int colorid);
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index a7ae4ea1241..f35976750c9 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -103,8 +103,11 @@ enum eView2D_Gridlines {
/* ------ Defines for Scrollers ----- */
/* scroller area */
-#define V2D_SCROLL_HEIGHT (0.85f * U.widget_unit)
-#define V2D_SCROLL_WIDTH (0.85f * U.widget_unit)
+#define V2D_SCROLL_HEIGHT (0.45f * U.widget_unit)
+#define V2D_SCROLL_WIDTH (0.45f * U.widget_unit)
+/* For scrollers with scale markings (text written onto them) */
+#define V2D_SCROLL_HEIGHT_TEXT (0.79f * U.widget_unit)
+#define V2D_SCROLL_WIDTH_TEXT (0.79f * U.widget_unit)
/* scroller 'handles' hotspot radius for mouse */
#define V2D_SCROLLER_HANDLE_SIZE (0.6f * U.widget_unit)
@@ -155,6 +158,8 @@ void UI_view2d_sync(struct bScreen *screen, struct ScrArea *sa, struct View2D *v
void UI_view2d_totRect_set(struct View2D *v2d, int width, int height);
void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize);
+void UI_view2d_mask_from_win(const struct View2D *v2d, struct rcti *r_mask);
+
/* per tab offsets, returns 1 if tab changed */
bool UI_view2d_tab_set(struct View2D *v2d, int tab);
@@ -175,8 +180,9 @@ void UI_view2d_grid_size(View2DGrid *grid, float *r_dx, float *r_dy);
void UI_view2d_grid_free(View2DGrid *grid);
/* scrollbar drawing */
-View2DScrollers *UI_view2d_scrollers_calc(const struct bContext *C, struct View2D *v2d,
- short xunits, short xclamp, short yunits, short yclamp);
+View2DScrollers *UI_view2d_scrollers_calc(
+ const struct bContext *C, struct View2D *v2d, const struct rcti *mask_custom,
+ short xunits, short xclamp, short yunits, short yclamp);
void UI_view2d_scrollers_draw(const struct bContext *C, struct View2D *v2d, View2DScrollers *scrollers);
void UI_view2d_scrollers_free(View2DScrollers *scrollers);
@@ -192,14 +198,14 @@ void UI_view2d_listview_visible_cells(struct View2D *v2d, float columnwidth, flo
int *row_min, int *row_max);
/* coordinate conversion */
-float UI_view2d_region_to_view_x(struct View2D *v2d, float x);
-float UI_view2d_region_to_view_y(struct View2D *v2d, float y);
-void UI_view2d_region_to_view(struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL();
-void UI_view2d_region_to_view_rctf(struct View2D *v2d, const struct rctf *rect_src, struct rctf *rect_dst) ATTR_NONNULL();
+float UI_view2d_region_to_view_x(const struct View2D *v2d, float x);
+float UI_view2d_region_to_view_y(const struct View2D *v2d, float y);
+void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL();
+void UI_view2d_region_to_view_rctf(const struct View2D *v2d, const struct rctf *rect_src, struct rctf *rect_dst) ATTR_NONNULL();
-float UI_view2d_view_to_region_x(struct View2D *v2d, float x);
-float UI_view2d_view_to_region_y(struct View2D *v2d, float y);
-bool UI_view2d_view_to_region_clip(struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
+float UI_view2d_view_to_region_x(const struct View2D *v2d, float x);
+float UI_view2d_view_to_region_y(const struct View2D *v2d, float y);
+bool UI_view2d_view_to_region_clip(const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
void UI_view2d_view_to_region_fl(struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL();
@@ -219,7 +225,11 @@ void UI_view2d_center_set(struct View2D *v2d, float x, float y);
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac);
-short UI_view2d_mouse_in_scrollers(const struct bContext *C, struct View2D *v2d, int x, int y);
+char UI_view2d_mouse_in_scrollers_ex(
+ const struct ARegion *ar, struct View2D *v2d, int x, int y,
+ int *r_scroll);
+char UI_view2d_mouse_in_scrollers(
+ const struct ARegion *ar, struct View2D *v2d, int x, int y);
/* cached text drawing in v2d, to allow pixel-aligned draw as post process */
void UI_view2d_text_cache_add(struct View2D *v2d, float x, float y,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 2c984d64266..c2c2438b942 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -23,7 +23,10 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blenloader
../../blentranslation
+ ../../depsgraph
+ ../../draw
../../gpu
../../imbuf
../../makesdna
@@ -52,13 +55,16 @@ set(SRC
interface_eyedropper_driver.c
interface_handlers.c
interface_icons.c
+ interface_icons_event.c
interface_layout.c
interface_ops.c
interface_panel.c
interface_query.c
interface_region_color_picker.c
+ interface_region_hud.c
interface_region_menu_pie.c
interface_region_menu_popup.c
+ interface_region_popover.c
interface_region_popup.c
interface_region_search.c
interface_region_tooltip.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 3188829bf31..82238744205 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -41,6 +41,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -50,6 +51,7 @@
#include "BLI_utildefines.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
@@ -57,27 +59,39 @@
#include "BKE_screen.h"
#include "BKE_unit.h"
-#include "BIF_gl.h"
+#include "GPU_glew.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "BLF_api.h"
#include "BLT_translation.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
#include "IMB_imbuf.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "wm_subwindow.h"
+#include "WM_message.h"
#include "RNA_access.h"
#include "BPY_extern.h"
+#include "ED_screen.h"
+#include "ED_numinput.h"
+
#include "IMB_colormanagement.h"
+#include "DEG_depsgraph_query.h"
+
#include "interface_intern.h"
+/* prototypes. */
+static void ui_but_to_pixelrect(struct rcti *rect, const struct ARegion *ar, struct uiBlock *block, struct uiBut *but);
+static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *but_p);
+
/* avoid unneeded calls to ui_but_value_get */
#define UI_BUT_VALUE_UNSET DBL_MAX
#define UI_GET_BUT_VALUE_INIT(_but, _value) if (_value == DBL_MAX) { (_value) = ui_but_value_get(_but); } (void)0
@@ -205,6 +219,84 @@ void ui_region_to_window(const ARegion *ar, int *x, int *y)
*y += ar->winrct.ymin;
}
+static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
+{
+ int sepr_flex_len = 0;
+ for (uiBut *but = block->buttons.first; but; but = but->next) {
+ if (but->type == UI_BTYPE_SEPR_SPACER) {
+ sepr_flex_len++;
+ }
+ }
+
+ if (sepr_flex_len == 0) {
+ return;
+ }
+
+ rcti rect;
+ ui_but_to_pixelrect(&rect, region, block, block->buttons.last);
+ const float buttons_width = (float)rect.xmax + UI_HEADER_OFFSET;
+ const float region_width = (float)region->sizex * U.dpi_fac;
+
+ if (region_width <= buttons_width) {
+ return;
+ }
+
+ /* We could get rid of this loop if we agree on a max number of spacer */
+ int *spacers_pos = alloca(sizeof(*spacers_pos) * (size_t)sepr_flex_len);
+ int i = 0;
+ for (uiBut *but = block->buttons.first; but; but = but->next) {
+ if (but->type == UI_BTYPE_SEPR_SPACER) {
+ ui_but_to_pixelrect(&rect, region, block, but);
+ spacers_pos[i] = rect.xmax + UI_HEADER_OFFSET;
+ i++;
+ }
+ }
+
+ const float segment_width = region_width / (float)sepr_flex_len;
+ float offset = 0, remaining_space = region_width - buttons_width;
+ i = 0;
+ for (uiBut *but = block->buttons.first; but; but = but->next) {
+ BLI_rctf_translate(&but->rect, offset, 0);
+ if (but->type == UI_BTYPE_SEPR_SPACER) {
+ /* How much the next block overlap with the current segment */
+ int overlap = (
+ (i == sepr_flex_len - 1) ?
+ buttons_width - spacers_pos[i] :
+ (spacers_pos[i + 1] - spacers_pos[i]) / 2);
+ int segment_end = segment_width * (i + 1);
+ int spacer_end = segment_end - overlap;
+ int spacer_sta = spacers_pos[i] + offset;
+ if (spacer_end > spacer_sta) {
+ float step = min_ff(remaining_space, spacer_end - spacer_sta);
+ remaining_space -= step;
+ offset += step;
+ }
+ i++;
+ }
+ }
+ ui_block_bounds_calc(block);
+}
+
+static void ui_update_window_matrix(const wmWindow *window, const ARegion *region, uiBlock *block)
+{
+ /* window matrix and aspect */
+ if (region && region->visible) {
+ /* Get projection matrix which includes View2D translation and zoom. */
+ GPU_matrix_projection_get(block->winmat);
+ block->aspect = 2.0f / fabsf(region->winx * block->winmat[0][0]);
+ }
+ else {
+ /* No subwindow created yet, for menus for example, so we use the main
+ * window instead, since buttons are created there anyway. */
+ int width = WM_window_pixels_x(window);
+ int height = WM_window_pixels_y(window);
+ rcti winrct = {0, width - 1, 0, height - 1};
+
+ wmGetProjectionMatrix(block->winmat, &winrct);
+ block->aspect = 2.0f / fabsf(width * block->winmat[0][0]);
+ }
+}
+
/**
* Popups will add a margin to #ARegion.winrct for shadow,
* for interactivity (point-inside tests for eg), we want the winrct without the margin added.
@@ -223,7 +315,7 @@ void ui_region_winrct_get_no_margin(const struct ARegion *ar, struct rcti *r_rec
/* ******************* block calc ************************* */
-void ui_block_translate(uiBlock *block, int x, int y)
+void UI_block_translate(uiBlock *block, int x, int y)
{
uiBut *but;
@@ -243,7 +335,7 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset)
UI_fontstyle_set(&style->widget);
for (init_col_bt = bt = block->buttons.first; bt; bt = bt->next) {
- if (!ELEM(bt->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
+ if (!ELEM(bt->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER)) {
j = BLF_width(style->widget.uifont_id, bt->drawstr, sizeof(bt->drawstr));
if (j > i)
@@ -333,7 +425,7 @@ static void ui_block_bounds_calc_centered(wmWindow *window, uiBlock *block)
startx = (xmax * 0.5f) - (width * 0.5f);
starty = (ymax * 0.5f) - (height * 0.5f);
- ui_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin);
+ UI_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin);
/* now recompute bounds and safety */
ui_block_bounds_calc(block);
@@ -347,7 +439,7 @@ static void ui_block_bounds_calc_centered_pie(uiBlock *block)
block->pie_data.pie_center_spawned[1]
};
- ui_block_translate(block, xy[0], xy[1]);
+ UI_block_translate(block, xy[0], xy[1]);
/* now recompute bounds and safety */
ui_block_bounds_calc(block);
@@ -407,7 +499,7 @@ static void ui_block_bounds_calc_popup(
rect_bounds.ymax = ymax - UI_POPUP_MENU_TOP;
BLI_rcti_clamp(&rect, &rect_bounds, ofs_dummy);
- ui_block_translate(block, rect.xmin - block->rect.xmin, rect.ymin - block->rect.ymin);
+ UI_block_translate(block, rect.xmin - block->rect.xmin, rect.ymin - block->rect.ymin);
/* now recompute bounds and safety */
ui_block_bounds_calc(block);
@@ -491,86 +583,6 @@ static int ui_but_calc_float_precision(uiBut *but, double value)
return UI_calc_float_precision(prec, value);
}
-/* ************** LINK LINE DRAWING ************* */
-
-/* link line drawing is not part of buttons or theme.. so we stick with it here */
-
-static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines, int dashInactiveLines)
-{
- rcti rect;
-
- if (line->from == NULL || line->to == NULL) return;
-
- rect.xmin = BLI_rctf_cent_x(&line->from->rect);
- rect.ymin = BLI_rctf_cent_y(&line->from->rect);
- rect.xmax = BLI_rctf_cent_x(&line->to->rect);
- rect.ymax = BLI_rctf_cent_y(&line->to->rect);
-
- if (dashInactiveLines)
- UI_ThemeColor(TH_GRID);
- else if (line->flag & UI_SELECT)
- glColor3ub(100, 100, 100);
- else if (highlightActiveLines && ((line->from->flag & UI_ACTIVE) || (line->to->flag & UI_ACTIVE)))
- UI_ThemeColor(TH_TEXT_HI);
- else
- glColor3ub(0, 0, 0);
-
- ui_draw_link_bezier(&rect);
-}
-
-static void ui_draw_links(uiBlock *block)
-{
- uiBut *but;
- uiLinkLine *line;
-
- /* Draw the gray out lines. Do this first so they appear at the
- * bottom of inactive or active lines.
- * As we go, remember if we see any active or selected lines. */
- bool found_selectline = false;
- bool found_activeline = false;
-
- for (but = block->buttons.first; but; but = but->next) {
- if (but->type == UI_BTYPE_LINK && but->link) {
- for (line = but->link->lines.first; line; line = line->next) {
- if (!(line->from->flag & UI_ACTIVE) && !(line->to->flag & UI_ACTIVE)) {
- if (line->deactive)
- ui_draw_linkline(line, 0, true);
- }
- else
- found_activeline = true;
-
- if ((line->from->flag & UI_SELECT) || (line->to->flag & UI_SELECT))
- found_selectline = true;
- }
- }
- }
-
- /* Draw the inactive lines (lines with neither button being hovered over) */
- for (but = block->buttons.first; but; but = but->next) {
- if (but->type == UI_BTYPE_LINK && but->link) {
- for (line = but->link->lines.first; line; line = line->next) {
- if (!(line->from->flag & UI_ACTIVE) && !(line->to->flag & UI_ACTIVE)) {
- if (!line->deactive)
- ui_draw_linkline(line, 0, false);
- }
- }
- }
- }
-
- /* Draw any active lines (lines with either button being hovered over).
- * Do this last so they appear on top of inactive and gray out lines. */
- if (found_activeline) {
- for (but = block->buttons.first; but; but = but->next) {
- if (but->type == UI_BTYPE_LINK && but->link) {
- for (line = but->link->lines.first; line; line = line->next) {
- if ((line->from->flag & UI_ACTIVE) || (line->to->flag & UI_ACTIVE))
- ui_draw_linkline(line, !found_selectline, false);
- }
- }
- }
- }
-}
-
/* ************** BLOCK ENDING FUNCTION ************* */
/* NOTE: if but->poin is allocated memory for every defbut, things fail... */
@@ -613,38 +625,6 @@ uiBut *ui_but_find_new(uiBlock *block_new, const uiBut *but_old)
return but_new;
}
-/* oldbut is being inserted in new block, so we use the lines from new button, and replace button pointers */
-static void ui_but_update_linklines(uiBlock *block, uiBut *oldbut, uiBut *newbut)
-{
- uiLinkLine *line;
- uiBut *but;
-
- /* if active button is UI_BTYPE_LINK */
- if (newbut->type == UI_BTYPE_LINK && newbut->link) {
-
- SWAP(uiLink *, oldbut->link, newbut->link);
-
- for (line = oldbut->link->lines.first; line; line = line->next) {
- if (line->to == newbut)
- line->to = oldbut;
- if (line->from == newbut)
- line->from = oldbut;
- }
- }
-
- /* check all other button links */
- for (but = block->buttons.first; but; but = but->next) {
- if (but != newbut && but->type == UI_BTYPE_LINK && but->link) {
- for (line = but->link->lines.first; line; line = line->next) {
- if (line->to == newbut)
- line->to = oldbut;
- if (line->from == newbut)
- line->from = oldbut;
- }
- }
- }
-}
-
/**
* \return true when \a but_p is set (only done for active buttons).
*/
@@ -701,8 +681,6 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
but->selend = oldbut->selend;
but->softmin = oldbut->softmin;
but->softmax = oldbut->softmax;
- but->linkto[0] = oldbut->linkto[0];
- but->linkto[1] = oldbut->linkto[1];
oldbut->active = NULL;
#endif
@@ -744,8 +722,6 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
oldbut->a1 = but->a1;
}
- ui_but_update_linklines(block, oldbut, but);
-
if (!BLI_listbase_is_empty(&block->butstore)) {
UI_butstore_register_update(block, oldbut, but);
}
@@ -968,6 +944,7 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str
MEM_freeN(butstr_orig);
but->str = but->strdata;
but->flag |= UI_BUT_HAS_SEP_CHAR;
+ but->drawflag |= UI_BUT_HAS_SHORTCUT;
ui_but_update(but);
}
}
@@ -1012,8 +989,8 @@ static bool ui_but_event_operator_string_from_menu(
IDP_AddToGroup(prop_menu, IDP_NewString(mt->idname, "name", sizeof(mt->idname)));
if (WM_key_event_operator_string(
- C, "WM_OT_call_menu", WM_OP_INVOKE_REGION_WIN, prop_menu, true,
- buf, buf_len))
+ C, "WM_OT_call_menu", WM_OP_INVOKE_REGION_WIN, prop_menu, true,
+ buf, buf_len))
{
found = true;
}
@@ -1023,6 +1000,41 @@ static bool ui_but_event_operator_string_from_menu(
return found;
}
+static bool ui_but_event_operator_string_from_panel(
+ const bContext *C, uiBut *but,
+ char *buf, const size_t buf_len)
+{
+ /** Nearly exact copy of #ui_but_event_operator_string_from_menu */
+ PanelType *pt = UI_but_paneltype_get(but);
+ BLI_assert(pt != NULL);
+
+ bool found = false;
+ IDProperty *prop_panel;
+
+ /* annoying, create a property */
+ IDPropertyTemplate val = {0};
+ prop_panel = IDP_New(IDP_GROUP, &val, __func__); /* dummy, name is unimportant */
+ IDP_AddToGroup(prop_panel, IDP_NewString(pt->idname, "name", sizeof(pt->idname)));
+ IDP_AddToGroup(prop_panel, IDP_New(IDP_INT, &(IDPropertyTemplate){ .i = pt->space_type, }, "space_type"));
+ IDP_AddToGroup(prop_panel, IDP_New(IDP_INT, &(IDPropertyTemplate){ .i = pt->region_type, }, "region_type"));
+
+ for (int i = 0; i < 2; i++) {
+ /* FIXME(campbell): We can't reasonably search all configurations - long term. */
+ IDP_ReplaceInGroup(prop_panel, IDP_New(IDP_INT, &(IDPropertyTemplate){ .i = i, }, "keep_open"));
+ if (WM_key_event_operator_string(
+ C, "WM_OT_call_panel", WM_OP_INVOKE_REGION_WIN, prop_panel, true,
+ buf, buf_len))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ IDP_FreeProperty(prop_panel);
+ MEM_freeN(prop_panel);
+ return found;
+}
+
static bool ui_but_event_operator_string(
const bContext *C, uiBut *but,
char *buf, const size_t buf_len)
@@ -1035,6 +1047,9 @@ static bool ui_but_event_operator_string(
else if (UI_but_menutype_get(but) != NULL) {
found = ui_but_event_operator_string_from_menu(C, but, buf, buf_len);
}
+ else if (UI_but_paneltype_get(but) != NULL) {
+ found = ui_but_event_operator_string_from_panel(C, but, buf, buf_len);
+ }
return found;
}
@@ -1044,6 +1059,11 @@ static bool ui_but_event_property_operator_string(
char *buf, const size_t buf_len)
{
/* context toggle operator names to check... */
+
+ /* This function could use a refactor to generalize button type to operator relationship
+ * as well as which operators use properties.
+ * - Campbell
+ * */
const char *ctx_toggle_opnames[] = {
"WM_OT_context_toggle",
"WM_OT_context_toggle_enum",
@@ -1053,54 +1073,110 @@ static bool ui_but_event_property_operator_string(
"WM_OT_context_menu_enum",
NULL
};
- const size_t num_ops = sizeof(ctx_toggle_opnames) / sizeof(const char *);
+
+ const char *ctx_enum_opnames[] = {
+ "WM_OT_context_set_enum",
+ NULL
+ };
+
+ const char *ctx_enum_opnames_for_Area_ui_type[] = {
+ "SCREEN_OT_space_type_set_or_cycle",
+ NULL
+ };
+
+ const char **opnames = ctx_toggle_opnames;
+ int opnames_len = ARRAY_SIZE(ctx_toggle_opnames);
+
+
+ int prop_enum_value = -1;
+ bool prop_enum_value_ok = false;
+ bool prop_enum_value_is_int = false;
+ const char *prop_enum_value_id = "value";
+ PointerRNA *ptr = &but->rnapoin;
+ PropertyRNA *prop = but->rnaprop;
+ if ((but->type == UI_BTYPE_BUT_MENU) && (but->block->handle != NULL)) {
+ uiBut *but_parent = but->block->handle->popup_create_vars.but;
+ if ((but->type == UI_BTYPE_BUT_MENU) &&
+ (but_parent && but_parent->rnaprop) &&
+ (RNA_property_type(but_parent->rnaprop) == PROP_ENUM) &&
+ (but_parent->menu_create_func == ui_def_but_rna__menu))
+ {
+ prop_enum_value = (int)but->hardmin;
+ ptr = &but_parent->rnapoin;
+ prop = but_parent->rnaprop;
+ prop_enum_value_ok = true;
+
+ opnames = ctx_enum_opnames;
+ opnames_len = ARRAY_SIZE(ctx_enum_opnames);
+ }
+ }
bool found = false;
+ /* Don't use the button again. */
+ but = NULL;
+
/* this version is only for finding hotkeys for properties (which get set via context using operators) */
- if (but->rnaprop) {
+ if (prop) {
/* to avoid massive slowdowns on property panels, for now, we only check the
* hotkeys for Editor / Scene settings...
*
* TODO: userpref settings?
*/
- // TODO: value (for enum stuff)?
char *data_path = NULL;
- if (but->rnapoin.id.data) {
- ID *id = but->rnapoin.id.data;
+ if (ptr->id.data) {
+ ID *id = ptr->id.data;
if (GS(id->name) == ID_SCR) {
/* screen/editor property
* NOTE: in most cases, there is actually no info for backwards tracing
* how to get back to ID from the editor data we may be dealing with
*/
- if (RNA_struct_is_a(but->rnapoin.type, &RNA_Space)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_Space)) {
+ /* data should be directly on here... */
+ data_path = BLI_sprintfN("space_data.%s", RNA_property_identifier(prop));
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Area)) {
/* data should be directly on here... */
- data_path = BLI_sprintfN("space_data.%s", RNA_property_identifier(but->rnaprop));
+ const char *prop_id = RNA_property_identifier(prop);
+ /* Hack since keys access 'type', UI shows 'ui_type'. */
+ if (STREQ(prop_id, "ui_type")) {
+ prop_id = "type";
+ prop_enum_value >>= 16;
+ prop = RNA_struct_find_property(ptr, prop_id);
+
+ opnames = ctx_enum_opnames_for_Area_ui_type;
+ opnames_len = ARRAY_SIZE(ctx_enum_opnames_for_Area_ui_type);
+ prop_enum_value_id = "space_type";
+ prop_enum_value_is_int = true;
+ }
+ else {
+ data_path = BLI_sprintfN("area.%s", prop_id);
+ }
}
else {
/* special exceptions for common nested data in editors... */
- if (RNA_struct_is_a(but->rnapoin.type, &RNA_DopeSheet)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_DopeSheet)) {
/* dopesheet filtering options... */
- data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(but->rnaprop));
+ data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(prop));
}
- else if (RNA_struct_is_a(but->rnapoin.type, &RNA_FileSelectParams)) {
+ else if (RNA_struct_is_a(ptr->type, &RNA_FileSelectParams)) {
/* Filebrowser options... */
- data_path = BLI_sprintfN("space_data.params.%s", RNA_property_identifier(but->rnaprop));
+ data_path = BLI_sprintfN("space_data.params.%s", RNA_property_identifier(prop));
}
}
}
else if (GS(id->name) == ID_SCE) {
- if (RNA_struct_is_a(but->rnapoin.type, &RNA_ToolSettings)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_ToolSettings)) {
/* toolsettings property
* NOTE: toolsettings is usually accessed directly (i.e. not through scene)
*/
- data_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
+ data_path = RNA_path_from_ID_to_property(ptr, prop);
}
else {
/* scene property */
- char *path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
+ char *path = RNA_path_from_ID_to_property(ptr, prop);
if (path) {
data_path = BLI_sprintfN("scene.%s", path);
@@ -1109,7 +1185,7 @@ static bool ui_but_event_property_operator_string(
#if 0
else {
printf("ERROR in %s(): Couldn't get path for scene property - %s\n",
- __func__, RNA_property_identifier(but->rnaprop));
+ __func__, RNA_property_identifier(prop));
}
#endif
}
@@ -1118,27 +1194,50 @@ static bool ui_but_event_property_operator_string(
//puts("other id");
}
- //printf("prop shortcut: '%s' (%s)\n", RNA_property_identifier(but->rnaprop), data_path);
+ //printf("prop shortcut: '%s' (%s)\n", RNA_property_identifier(prop), data_path);
}
/* we have a datapath! */
- if (data_path) {
- size_t i;
-
+ if (data_path || prop_enum_value_id) {
/* create a property to host the "datapath" property we're sending to the operators */
IDProperty *prop_path;
- IDProperty *prop_path_value;
IDPropertyTemplate val = {0};
prop_path = IDP_New(IDP_GROUP, &val, __func__);
- prop_path_value = IDP_NewString(data_path, "data_path", strlen(data_path) + 1);
- IDP_AddToGroup(prop_path, prop_path_value);
+ if (data_path) {
+ IDP_AddToGroup(prop_path, IDP_NewString(data_path, "data_path", strlen(data_path) + 1));
+ }
+ if (prop_enum_value_ok) {
+ const EnumPropertyItem *item;
+ bool free;
+ RNA_property_enum_items((bContext *)C, ptr, prop, &item, NULL, &free);
+ int index = RNA_enum_from_value(item, prop_enum_value);
+ if (index != -1) {
+ IDProperty *prop_value;
+ if (prop_enum_value_is_int) {
+ int value = item[index].value;
+ prop_value = IDP_New(IDP_INT, &(IDPropertyTemplate){ .i = value, }, prop_enum_value_id);
+ }
+ else {
+ const char *id = item[index].identifier;
+ prop_value = IDP_NewString(id, prop_enum_value_id, strlen(id) + 1);
+ }
+ IDP_AddToGroup(prop_path, prop_value);
+ }
+ else {
+ opnames_len = 0; /* Do nothing. */
+ }
+ if (free) {
+ MEM_freeN((void *)item);
+ }
+ }
/* check each until one works... */
- for (i = 0; (i < num_ops) && (ctx_toggle_opnames[i]); i++) {
+
+ for (int i = 0; (i < opnames_len) && (opnames[i]); i++) {
if (WM_key_event_operator_string(
- C, ctx_toggle_opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false,
- buf, buf_len))
+ C, opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false,
+ buf, buf_len))
{
found = true;
break;
@@ -1148,7 +1247,9 @@ static bool ui_but_event_property_operator_string(
/* cleanup */
IDP_FreeProperty(prop_path);
MEM_freeN(prop_path);
- MEM_freeN(data_path);
+ if (data_path) {
+ MEM_freeN(data_path);
+ }
}
}
@@ -1200,11 +1301,15 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
uiBut *but;
char buf[128];
- BLI_assert(block->flag & UI_BLOCK_LOOP);
+ BLI_assert(block->flag & (UI_BLOCK_LOOP | UI_BLOCK_SHOW_SHORTCUT_ALWAYS));
/* only do it before bounding */
- if (block->rect.xmin != block->rect.xmax)
+ if (block->rect.xmin != block->rect.xmax) {
return;
+ }
+ if (STREQ(block->name, "splash")) {
+ return;
+ }
if (block->flag & UI_BLOCK_RADIAL) {
for (but = block->buttons.first; but; but = but->next) {
@@ -1216,7 +1321,17 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
}
else {
for (but = block->buttons.first; but; but = but->next) {
- if (but->dt != UI_EMBOSS_PULLDOWN) {
+ if (block->flag & UI_BLOCK_SHOW_SHORTCUT_ALWAYS) {
+ /* Skip icon-only buttons (as used in the toolbar). */
+ if (but->drawstr[0] == '\0') {
+ continue;
+ }
+ else if (((block->flag & UI_BLOCK_POPOVER) == 0) && UI_but_is_tool(but)) {
+ /* For non-popovers, shown in shortcut only (has special shortcut handling code). */
+ continue;
+ }
+ }
+ else if (but->dt != UI_EMBOSS_PULLDOWN) {
continue;
}
@@ -1230,6 +1345,18 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
}
}
+void ui_but_override_flag(uiBut *but)
+{
+ const int override_status = RNA_property_static_override_status(&but->rnapoin, but->rnaprop, but->rnaindex);
+
+ if (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN) {
+ but->flag |= UI_BUT_OVERRIDEN;
+ }
+ else {
+ but->flag &= ~UI_BUT_OVERRIDEN;
+ }
+}
+
void UI_block_update_from_old(const bContext *C, uiBlock *block)
{
uiBut *but_old;
@@ -1267,6 +1394,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
{
wmWindow *window = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
+ ARegion *region = CTX_wm_region(C);
uiBut *but;
BLI_assert(block->active);
@@ -1294,6 +1422,10 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
}
ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f);
+ ui_but_override_flag(but);
+ if (UI_but_is_decorator(but)) {
+ ui_but_anim_decorate_update_from_flag(but);
+ }
}
@@ -1302,12 +1434,12 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
if (block->layouts.first) {
UI_block_layout_resolve(block, NULL, NULL);
}
- ui_block_align_calc(block);
+ ui_block_align_calc(block, CTX_wm_region(C));
if ((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT)) {
ui_menu_block_set_keyaccels(block); /* could use a different flag to check */
}
- if (block->flag & UI_BLOCK_LOOP) {
+ if (block->flag & (UI_BLOCK_LOOP | UI_BLOCK_SHOW_SHORTCUT_ALWAYS)) {
ui_menu_block_set_keymaps(C, block);
}
@@ -1342,6 +1474,8 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
UI_block_align_end(block);
}
+ ui_update_flexible_spacing(region, block);
+
block->endblock = 1;
}
@@ -1388,7 +1522,6 @@ void UI_block_draw(const bContext *C, uiBlock *block)
ARegion *ar;
uiBut *but;
rcti rect;
- int multisample_enabled;
/* get menu region or area region */
ar = CTX_wm_menu(C);
@@ -1398,13 +1531,8 @@ void UI_block_draw(const bContext *C, uiBlock *block)
if (!block->endblock)
UI_block_end(C, block);
- /* disable AA, makes widgets too blurry */
- multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
- if (multisample_enabled)
- glDisable(GL_MULTISAMPLE);
-
/* we set this only once */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* scale fonts */
ui_fontscale(&style.paneltitle.points, block->aspect);
@@ -1416,21 +1544,29 @@ void UI_block_draw(const bContext *C, uiBlock *block)
ui_but_to_pixelrect(&rect, ar, block, NULL);
/* pixel space for AA widgets */
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
wmOrtho2_region_pixelspace(ar);
/* back */
if (block->flag & UI_BLOCK_RADIAL)
ui_draw_pie_center(block);
+ else if (block->flag & UI_BLOCK_POPOVER)
+ ui_draw_popover_back(ar, &style, block, &rect);
else if (block->flag & UI_BLOCK_LOOP)
ui_draw_menu_back(&style, block, &rect);
- else if (block->panel)
- ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar));
+ else if (block->panel) {
+ bool show_background = ar->alignment != RGN_ALIGN_FLOAT;
+ ui_draw_aligned_panel(
+ &style, block, &rect,
+ UI_panel_category_is_visible(ar), show_background);
+ }
+
+ BLF_batch_draw_begin();
+ UI_icon_draw_cache_begin();
+ UI_widgetbase_draw_cache_begin();
/* widgets */
for (but = block->buttons.first; but; but = but->next) {
@@ -1444,16 +1580,47 @@ void UI_block_draw(const bContext *C, uiBlock *block)
}
}
- /* restore matrix */
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ UI_widgetbase_draw_cache_end();
+ UI_icon_draw_cache_end();
+ BLF_batch_draw_end();
- if (multisample_enabled)
- glEnable(GL_MULTISAMPLE);
+ /* restore matrix */
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
+}
+
+static void ui_block_message_subscribe(ARegion *ar, struct wmMsgBus *mbus, uiBlock *block)
+{
+ uiBut *but_prev = NULL;
+ /* possibly we should keep the region this block is contained in? */
+ for (uiBut *but = block->buttons.first; but; but = but->next) {
+ if (but->rnapoin.type && but->rnaprop) {
+ /* quick check to avoid adding buttons representing a vector, multiple times. */
+ if ((but_prev &&
+ (but_prev->rnaprop == but->rnaprop) &&
+ (but_prev->rnapoin.type == but->rnapoin.type) &&
+ (but_prev->rnapoin.data == but->rnapoin.data) &&
+ (but_prev->rnapoin.id.data == but->rnapoin.id.data)) == false)
+ {
+ /* TODO: could make this into utility function. */
+ WM_msg_subscribe_rna(
+ mbus, &but->rnapoin, but->rnaprop,
+ &(const wmMsgSubscribeValue){
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ }, __func__);
+ but_prev = but;
+ }
+ }
+ }
+}
- ui_draw_links(block);
+void UI_region_message_subscribe(ARegion *ar, struct wmMsgBus *mbus)
+{
+ for (uiBlock *block = ar->uiblocks.first; block; block = block->next) {
+ ui_block_message_subscribe(ar, mbus, block);
+ }
}
/* ************* EVENTS ************* */
@@ -1502,6 +1669,22 @@ int ui_but_is_pushed_ex(uiBut *but, double *value)
break;
case UI_BTYPE_ROW:
case UI_BTYPE_LISTROW:
+ case UI_BTYPE_TAB:
+ if ((but->type == UI_BTYPE_TAB) && but->rnaprop && but->custom_data) {
+ /* uiBut.custom_data points to data this tab represents (e.g. workspace).
+ * uiBut.rnapoin/prop store an active value (e.g. active workspace). */
+ if (RNA_property_type(but->rnaprop) == PROP_POINTER) {
+ PointerRNA active_ptr = RNA_property_pointer_get(&but->rnapoin, but->rnaprop);
+ if (active_ptr.data == but->custom_data) {
+ is_push = true;
+ }
+ }
+ break;
+ }
+ else if (but->optype) {
+ break;
+ }
+
UI_GET_BUT_VALUE_INIT(but, *value);
/* support for rna enum buts */
if (but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) {
@@ -1537,83 +1720,6 @@ static void ui_but_update_select_flag(uiBut *but, double *value)
}
}
-static uiBut *ui_linkline_find_inlink(uiBlock *block, void *poin)
-{
- uiBut *but;
-
- but = block->buttons.first;
- while (but) {
- if (but->type == UI_BTYPE_INLINK) {
- if (but->poin == poin) return but;
- }
- but = but->next;
- }
- return NULL;
-}
-
-static void ui_linkline_add(ListBase *listb, uiBut *but, uiBut *bt, short deactive)
-{
- uiLinkLine *line;
-
- line = MEM_callocN(sizeof(uiLinkLine), "linkline");
- BLI_addtail(listb, line);
- line->from = but;
- line->to = bt;
- line->deactive = deactive;
-}
-
-uiBut *UI_block_links_find_inlink(uiBlock *block, void *poin)
-{
- return ui_linkline_find_inlink(block, poin);
-}
-
-void UI_block_links_compose(uiBlock *block)
-{
- uiBut *but, *bt;
- uiLink *link;
- void ***ppoin;
- int a;
-
- but = block->buttons.first;
- while (but) {
- if (but->type == UI_BTYPE_LINK) {
- link = but->link;
-
- /* for all pointers in the array */
- if (link) {
- if (link->ppoin) {
- ppoin = link->ppoin;
- for (a = 0; a < *(link->totlink); a++) {
- bt = ui_linkline_find_inlink(block, (*ppoin)[a]);
- if (bt) {
- if ((but->flag & UI_BUT_SCA_LINK_GREY) || (bt->flag & UI_BUT_SCA_LINK_GREY)) {
- ui_linkline_add(&link->lines, but, bt, true);
- }
- else {
- ui_linkline_add(&link->lines, but, bt, false);
- }
-
- }
- }
- }
- else if (link->poin) {
- bt = ui_linkline_find_inlink(block, *link->poin);
- if (bt) {
- if ((but->flag & UI_BUT_SCA_LINK_GREY) || (bt->flag & UI_BUT_SCA_LINK_GREY)) {
- ui_linkline_add(&link->lines, but, bt, true);
- }
- else {
- ui_linkline_add(&link->lines, but, bt, false);
- }
- }
- }
- }
- }
- but = but->next;
- }
-}
-
-
/* ************************************************ */
void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr)
@@ -1630,48 +1736,78 @@ void UI_block_lock_clear(uiBlock *block)
block->lockstr = NULL;
}
-/* *************************************************************** */
-
-void ui_linkline_remove(uiLinkLine *line, uiBut *but)
-{
- uiLink *link;
- int a, b;
-
- BLI_remlink(&but->link->lines, line);
-
- link = line->from->link;
-
- /* are there more pointers allowed? */
- if (link->ppoin) {
+/* *********************** data get/set ***********************
+ * this either works with the pointed to data, or can work with
+ * an edit override pointer while dragging for example */
- if (*(link->totlink) == 1) {
- *(link->totlink) = 0;
- MEM_freeN(*(link->ppoin));
- *(link->ppoin) = NULL;
- }
- else {
- b = 0;
- for (a = 0; a < (*(link->totlink)); a++) {
- if ((*(link->ppoin))[a] != line->to->poin) {
- (*(link->ppoin))[b] = (*(link->ppoin))[a];
- b++;
- }
- }
- (*(link->totlink))--;
+/* Get PointerRNA which will point to a data inside of an evaluated
+ * ID datablock.
+ */
+static PointerRNA ui_but_evaluated_rnapoin_get(uiBut *but)
+{
+ BLI_assert(but->rnaprop != NULL);
+ /* TODO(sergey): evil_C sounds.. EVIL! Any clear way to avoid this? */
+ PointerRNA rnapoin_eval = but->rnapoin;
+ /* If there is no animation or drivers, it doesn't matter if we read value
+ * from evaluated datablock or from original one.
+ *
+ * Reading from original one is much faster, since we don't need to do any
+ * PointerRNA remapping or hash lookup.
+ */
+ if (BKE_animdata_from_id(but->rnapoin.id.data) == NULL) {
+ return rnapoin_eval;
+ }
+ /* Same goes for the properties which can not be animated. */
+ if (!RNA_property_animateable(&but->rnapoin, but->rnaprop)) {
+ return rnapoin_eval;
+ }
+ Depsgraph *depsgraph = CTX_data_depsgraph(but->block->evil_C);
+ /* ID pointer we can always remap, they are inside of depsgraph. */
+ rnapoin_eval.id.data =
+ DEG_get_evaluated_id(depsgraph, rnapoin_eval.id.data);
+ /* Some of ID datablocks do not have their evaluated copy inside
+ * of dependency graph. If it's such datablock, no need to worry about
+ * data pointer.
+ */
+ if (rnapoin_eval.id.data == but->rnapoin.id.data) {
+ return rnapoin_eval;
+ }
+ /* For the data pointer it's getting a bit more involved, since it can
+ * whether be and ID, or can be a property deep inside of ID.
+ *
+ * We start from checking if it's an ID, since that is the less involved
+ * code path, and probably is executed in most of the cases.
+ */
+ if (but->rnapoin.data == but->rnapoin.id.data) {
+ rnapoin_eval.data = DEG_get_evaluated_id(depsgraph, rnapoin_eval.data);
+ return rnapoin_eval;
+ }
+ /* We aren't as lucky as we thought we are :(
+ *
+ * Since we don't know what the property is, we get it's RNA path
+ * relative to the original ID, and then we decent down from evaluated
+ * ID to the same property.
+ *
+ * This seems to be most straightforward way to get sub-data pointers
+ * which can be buried deep inside of ID block.
+ */
+ const char *rna_path =
+ RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
+ if (rna_path != NULL) {
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(rnapoin_eval.id.data, &id_ptr);
+ if (!RNA_path_resolve_full(&id_ptr,
+ rna_path,
+ &rnapoin_eval,
+ NULL, NULL))
+ {
+ /* TODO(sergey): Anything to do here to recover? */
}
+ MEM_freeN((void *)rna_path);
}
- else {
- *(link->poin) = NULL;
- }
-
- MEM_freeN(line);
- //REDRAW
+ return rnapoin_eval;
}
-/* *********************** data get/set ***********************
- * this either works with the pointed to data, or can work with
- * an edit override pointer while dragging for example */
-
/* for buttons pointing to color for example */
void ui_but_v3_get(uiBut *but, float vec[3])
{
@@ -1687,16 +1823,18 @@ void ui_but_v3_get(uiBut *but, float vec[3])
zero_v3(vec);
+ PointerRNA rnapoin_eval = ui_but_evaluated_rnapoin_get(but);
+
if (RNA_property_type(prop) == PROP_FLOAT) {
- int tot = RNA_property_array_length(&but->rnapoin, prop);
+ int tot = RNA_property_array_length(&rnapoin_eval, prop);
BLI_assert(tot > 0);
if (tot == 3) {
- RNA_property_float_get_array(&but->rnapoin, prop, vec);
+ RNA_property_float_get_array(&rnapoin_eval, prop, vec);
}
else {
tot = min_ii(tot, 3);
for (a = 0; a < tot; a++) {
- vec[a] = RNA_property_float_get_index(&but->rnapoin, prop, a);
+ vec[a] = RNA_property_float_get_index(&rnapoin_eval, prop, a);
}
}
}
@@ -1778,7 +1916,7 @@ bool ui_but_is_float(const uiBut *but)
bool ui_but_is_bool(const uiBut *but)
{
- if (ELEM(but->type, UI_BTYPE_TOGGLE, UI_BTYPE_TOGGLE_N, UI_BTYPE_ICON_TOGGLE, UI_BTYPE_ICON_TOGGLE_N))
+ if (ELEM(but->type, UI_BTYPE_TOGGLE, UI_BTYPE_TOGGLE_N, UI_BTYPE_ICON_TOGGLE, UI_BTYPE_ICON_TOGGLE_N, UI_BTYPE_TAB))
return true;
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN)
@@ -1876,27 +2014,29 @@ double ui_but_value_get(uiBut *but)
BLI_assert(but->rnaindex != -1);
+ PointerRNA rnapoin_eval = ui_but_evaluated_rnapoin_get(but);
+
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (RNA_property_array_check(prop))
- value = RNA_property_boolean_get_index(&but->rnapoin, prop, but->rnaindex);
+ value = RNA_property_boolean_get_index(&rnapoin_eval, prop, but->rnaindex);
else
- value = RNA_property_boolean_get(&but->rnapoin, prop);
+ value = RNA_property_boolean_get(&rnapoin_eval, prop);
break;
case PROP_INT:
if (RNA_property_array_check(prop))
- value = RNA_property_int_get_index(&but->rnapoin, prop, but->rnaindex);
+ value = RNA_property_int_get_index(&rnapoin_eval, prop, but->rnaindex);
else
- value = RNA_property_int_get(&but->rnapoin, prop);
+ value = RNA_property_int_get(&rnapoin_eval, prop);
break;
case PROP_FLOAT:
if (RNA_property_array_check(prop))
- value = RNA_property_float_get_index(&but->rnapoin, prop, but->rnaindex);
+ value = RNA_property_float_get_index(&rnapoin_eval, prop, but->rnaindex);
else
- value = RNA_property_float_get(&but->rnapoin, prop);
+ value = RNA_property_float_get(&rnapoin_eval, prop);
break;
case PROP_ENUM:
- value = RNA_property_enum_get(&but->rnapoin, prop);
+ value = RNA_property_enum_get(&rnapoin_eval, prop);
break;
default:
value = 0.0;
@@ -2039,7 +2179,7 @@ static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
{
- BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
+ BLI_assert(ELEM(but->type, UI_BTYPE_SEARCH_MENU));
return ((but->editstr == NULL) &&
(but->drawstr[0] != '\0') &&
(but->flag & UI_BUT_VALUE_CLEAR));
@@ -2129,7 +2269,6 @@ void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, bool pad, int float_precision)
{
UnitSettings *unit = but->block->unit;
- const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
int unit_type = UI_but_unit_type_get(but);
int precision;
@@ -2146,9 +2285,9 @@ static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double va
precision = float_precision;
}
- bUnit_AsString(
+ bUnit_AsString2(
str, len_max, ui_get_but_scale_unit(but, value), precision,
- unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type), do_split, pad);
+ RNA_SUBTYPE_UNIT_VALUE(unit_type), unit, pad);
}
static float ui_get_but_step_unit(uiBut *but, float step_default)
@@ -2196,14 +2335,23 @@ void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int
*r_use_exp_float = false;
}
- if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
+ if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU, UI_BTYPE_TAB)) {
PropertyType type;
const char *buf = NULL;
int buf_len;
type = RNA_property_type(but->rnaprop);
- if (type == PROP_STRING) {
+ if ((but->type == UI_BTYPE_TAB) && (but->custom_data)) {
+ StructRNA *ptr_type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
+ PointerRNA ptr;
+
+ /* uiBut.custom_data points to data this tab represents (e.g. workspace).
+ * uiBut.rnapoin/prop store an active value (e.g. active workspace). */
+ RNA_pointer_create(but->rnapoin.id.data, ptr_type, but->custom_data, &ptr);
+ buf = RNA_struct_name_get_alloc(&ptr, str, maxlen, &buf_len);
+ }
+ else if (type == PROP_STRING) {
/* RNA string */
buf = RNA_property_string_get_alloc(&but->rnapoin, but->rnaprop, str, maxlen, &buf_len);
}
@@ -2239,12 +2387,7 @@ void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int
MEM_freeN((void *)buf);
}
}
- else if (but->type == UI_BTYPE_TEXT) {
- /* string */
- BLI_strncpy(str, but->poin, maxlen);
- return;
- }
- else if (but->type == UI_BTYPE_SEARCH_MENU) {
+ else if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
/* string */
BLI_strncpy(str, but->poin, maxlen);
return;
@@ -2354,27 +2497,13 @@ char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
return str;
}
-#ifdef WITH_PYTHON
-
static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *r_value)
{
- char str_unit_convert[256];
- const int unit_type = UI_but_unit_type_get(but);
-
- BLI_strncpy(str_unit_convert, str, sizeof(str_unit_convert));
-
- /* ugly, use the draw string to get the value,
- * this could cause problems if it includes some text which resolves to a unit */
- bUnit_ReplaceString(
- str_unit_convert, sizeof(str_unit_convert), but->drawstr,
- ui_get_but_scale_unit(but, 1.0), but->block->unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
-
- return BPY_execute_string_as_number(C, NULL, str_unit_convert, true, r_value);
+ const UnitSettings *unit = but->block->unit;
+ int type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but));
+ return user_string_to_number(C, str, unit, type, r_value);
}
-#endif /* WITH_PYTHON */
-
-
bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double *r_value)
{
bool ok = false;
@@ -2443,7 +2572,7 @@ static void ui_but_string_free_internal(uiBut *but)
bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
{
- if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
+ if (but->rnaprop && but->rnapoin.data && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
PropertyType type;
@@ -2455,17 +2584,15 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
return true;
}
else if (type == PROP_POINTER) {
- /* RNA pointer */
- PointerRNA ptr, rptr;
- PropertyRNA *prop;
-
if (str[0] == '\0') {
RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL);
return true;
}
else {
- ptr = but->rnasearchpoin;
- prop = but->rnasearchprop;
+ /* RNA pointer */
+ PointerRNA rptr;
+ PointerRNA ptr = but->rnasearchpoin;
+ PropertyRNA *prop = but->rnasearchprop;
if (prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr))
RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr);
@@ -2488,10 +2615,32 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
}
}
}
+ else if (but->type == UI_BTYPE_TAB) {
+ if (but->rnaprop && but->custom_data) {
+ StructRNA *ptr_type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* uiBut.custom_data points to data this tab represents (e.g. workspace).
+ * uiBut.rnapoin/prop store an active value (e.g. active workspace). */
+ RNA_pointer_create(but->rnapoin.id.data, ptr_type, but->custom_data, &ptr);
+ prop = RNA_struct_name_property(ptr_type);
+ if (RNA_property_editable(&ptr, prop)) {
+ RNA_property_string_set(&ptr, prop, str);
+ }
+ }
+ }
else if (but->type == UI_BTYPE_TEXT) {
/* string */
- if (ui_but_is_utf8(but)) BLI_strncpy_utf8(but->poin, str, but->hardmax);
- else BLI_strncpy(but->poin, str, but->hardmax);
+ if (!but->poin || (str[0] == '\0')) {
+ str = "";
+ }
+ else if (ui_but_is_utf8(but)) {
+ BLI_strncpy_utf8(but->poin, str, but->hardmax);
+ }
+ else {
+ BLI_strncpy(but->poin, str, but->hardmax);
+ }
return true;
}
@@ -2675,14 +2824,6 @@ static void ui_set_but_soft_range(uiBut *but)
/* ******************* Free ********************/
-static void ui_free_link(uiLink *link)
-{
- if (link) {
- BLI_freelistN(&link->lines);
- MEM_freeN(link);
- }
-}
-
/* can be called with C==NULL */
static void ui_but_free(const bContext *C, uiBut *but)
{
@@ -2703,6 +2844,10 @@ static void ui_but_free(const bContext *C, uiBut *but)
MEM_freeN(but->hold_argN);
}
+ if (!but->editstr && but->free_search_arg) {
+ MEM_SAFE_FREE(but->search_arg);
+ }
+
if (but->active) {
/* XXX solve later, buttons should be free-able without context ideally,
* however they may have open tooltips or popup windows, which need to
@@ -2719,7 +2864,6 @@ static void ui_but_free(const bContext *C, uiBut *but)
if (but->str && but->str != but->strdata) {
MEM_freeN(but->str);
}
- ui_free_link(but->link);
if ((but->type == UI_BTYPE_IMAGE) && but->poin) {
IMB_freeImBuf((struct ImBuf *)but->poin);
@@ -2761,6 +2905,27 @@ void UI_block_free(const bContext *C, uiBlock *block)
MEM_freeN(block);
}
+void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb)
+{
+ ARegion *region = CTX_wm_region(C);
+ wmWindow *window = CTX_wm_window(C);
+
+ for (uiBlock *block = lb->first; block; block = block->next) {
+ if (block->active) {
+ ui_update_window_matrix(window, region, block);
+ }
+ }
+}
+
+void UI_blocklist_draw(const bContext *C, const ListBase *lb)
+{
+ for (uiBlock *block = lb->first; block; block = block->next) {
+ if (block->active) {
+ UI_block_draw(C, block);
+ }
+ }
+}
+
/* can be called with C==NULL */
void UI_blocklist_free(const bContext *C, ListBase *lb)
{
@@ -2817,7 +2982,6 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh
uiBlock *block;
wmWindow *window;
Scene *scn;
- int getsizex, getsizey;
window = CTX_wm_window(C);
scn = CTX_data_scene(C);
@@ -2847,33 +3011,18 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh
if (region)
UI_block_region_set(block, region);
- /* window matrix and aspect */
- if (region && region->swinid) {
- wm_subwindow_matrix_get(window, region->swinid, block->winmat);
- wm_subwindow_size_get(window, region->swinid, &getsizex, &getsizey);
+ /* Set window matrix and aspect for region and OpenGL state. */
+ ui_update_window_matrix(window, region, block);
- block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]);
- }
- else {
- /* no subwindow created yet, for menus for example, so we
- * use the main window instead, since buttons are created
- * there anyway */
- wm_subwindow_matrix_get(window, window->screen->mainwin, block->winmat);
- wm_subwindow_size_get(window, window->screen->mainwin, &getsizex, &getsizey);
-
- block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]);
+ /* Tag as popup menu if not created within a region. */
+ if (!(region && region->visible)) {
block->auto_open = true;
- block->flag |= UI_BLOCK_LOOP; /* tag as menu */
+ block->flag |= UI_BLOCK_LOOP;
}
return block;
}
-uiBlock *UI_block_find_in_region(const char *name, ARegion *ar)
-{
- return BLI_findstring(&ar->uiblocks, name, offsetof(uiBlock, name));
-}
-
void UI_block_emboss_set(uiBlock *block, char dt)
{
block->dt = dt;
@@ -2893,7 +3042,6 @@ void ui_but_update_ex(uiBut *but, const bool validate)
{
/* if something changed in the button */
double value = UI_BUT_VALUE_UNSET;
-// float okwidth; // UNUSED
ui_but_update_select_flag(but, &value);
@@ -2928,9 +3076,12 @@ void ui_but_update_ex(uiBut *but, const bool validate)
case UI_BTYPE_ICON_TOGGLE:
case UI_BTYPE_ICON_TOGGLE_N:
- if (!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) {
- if (but->flag & UI_SELECT) but->iconadd = 1;
- else but->iconadd = 0;
+ if ((but->rnaprop == NULL) || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) {
+ if (but->rnaprop && RNA_property_flag(but->rnaprop) & PROP_ICONS_REVERSE) {
+ but->drawflag |= UI_BUT_ICON_REVERSE;
+ }
+
+ but->iconadd = (but->flag & UI_SELECT) ? 1 : 0;
}
break;
@@ -2955,8 +3106,8 @@ void ui_but_update_ex(uiBut *but, const bool validate)
EnumPropertyItem item;
if (RNA_property_enum_item_from_value_gettexted(
- but->block->evil_C,
- &but->rnapoin, but->rnaprop, value_enum, &item))
+ but->block->evil_C,
+ &but->rnapoin, but->rnaprop, value_enum, &item))
{
size_t slen = strlen(item.name);
ui_but_string_free_internal(but);
@@ -3158,6 +3309,16 @@ void ui_block_cm_to_display_space_range(uiBlock *block, float *min, float *max)
*max = max_fff(UNPACK3(pixel));
}
+static uiBut *ui_but_alloc(const eButType type)
+{
+ switch (type) {
+ case UI_BTYPE_TAB:
+ return MEM_callocN(sizeof(uiButTab), "uiButTab");
+ default:
+ return MEM_callocN(sizeof(uiBut), "uiBut");
+ }
+}
+
/**
* \brief ui_def_but is the function that draws many button types
*
@@ -3191,7 +3352,7 @@ static uiBut *ui_def_but(
}
}
- but = MEM_callocN(sizeof(uiBut), "uiBut");
+ but = ui_but_alloc(type & BUTTYPE);
but->type = type & BUTTYPE;
but->pointype = type & UI_BUT_POIN_TYPES;
@@ -3248,14 +3409,15 @@ static uiBut *ui_def_but(
if (block->flag & UI_BLOCK_RADIAL) {
but->drawflag |= UI_BUT_TEXT_LEFT;
- if (but->str && but->str[0])
+ if (but->str && but->str[0]) {
but->drawflag |= UI_BUT_ICON_LEFT;
+ }
}
- else if ((block->flag & UI_BLOCK_LOOP) ||
+ else if (((block->flag & UI_BLOCK_LOOP) && !ui_block_is_popover(block)) ||
ELEM(but->type,
UI_BTYPE_MENU, UI_BTYPE_TEXT, UI_BTYPE_LABEL,
UI_BTYPE_BLOCK, UI_BTYPE_BUT_MENU, UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_PROGRESS_BAR))
+ UI_BTYPE_PROGRESS_BAR, UI_BTYPE_POPOVER))
{
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@@ -3278,7 +3440,8 @@ static uiBut *ui_def_but(
UI_BTYPE_BLOCK, UI_BTYPE_BUT, UI_BTYPE_LABEL,
UI_BTYPE_PULLDOWN, UI_BTYPE_ROUNDBOX, UI_BTYPE_LISTBOX,
UI_BTYPE_BUT_MENU, UI_BTYPE_SCROLL, UI_BTYPE_GRIP,
- UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE) ||
+ UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE,
+ UI_BTYPE_SEPR_SPACER) ||
(but->type >= UI_BTYPE_SEARCH_MENU))
{
/* pass */
@@ -3446,6 +3609,12 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
block->flag |= UI_BLOCK_IS_FLIP;
}
+static void ui_but_submenu_enable(uiBlock *block, uiBut *but)
+{
+ but->flag |= UI_BUT_ICON_SUBMENU;
+ block->content_hints |= UI_BLOCK_CONTAINS_SUBMENU_BUT;
+}
+
/**
* ui_def_but_rna_propname and ui_def_but_rna
* both take the same args except for propname vs prop, this is done so we can
@@ -3581,11 +3750,11 @@ static uiBut *ui_def_but_rna(
}
if ((type == UI_BTYPE_MENU) && (but->dt == UI_EMBOSS_PULLDOWN)) {
- but->flag |= UI_BUT_ICON_SUBMENU;
+ ui_but_submenu_enable(block, but);
}
const char *info;
- if (!RNA_property_editable_info(&but->rnapoin, prop, &info)) {
+ if (but->rnapoin.data && !RNA_property_editable_info(&but->rnapoin, prop, &info)) {
ui_def_but_rna__disable(but, info);
}
@@ -4004,19 +4173,6 @@ uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcon
/* END Button containing both string label and icon */
-void UI_but_link_set(uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to)
-{
- uiLink *link;
-
- link = but->link = MEM_callocN(sizeof(uiLink), "new uilink");
-
- link->poin = poin;
- link->ppoin = ppoin;
- link->totlink = tot;
- link->fromcode = from;
- link->tocode = to;
-}
-
/* cruft to make uiBlock and uiBut private */
int UI_blocklist_min_y_get(ListBase *lb)
@@ -4333,7 +4489,7 @@ uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, in
ui_def_but_icon(but, icon, UI_HAS_ICON);
but->drawflag |= UI_BUT_ICON_LEFT;
- but->flag |= UI_BUT_ICON_SUBMENU;
+ ui_but_submenu_enable(block, but);
but->menu_create_func = func;
ui_but_update(but);
@@ -4365,7 +4521,7 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg,
but->drawflag |= UI_BUT_ICON_LEFT;
}
but->flag |= UI_HAS_ICON;
- but->flag |= UI_BUT_ICON_SUBMENU;
+ ui_but_submenu_enable(block, but);
but->block_create_func = func;
ui_but_update(but);
@@ -4484,7 +4640,7 @@ static void operator_enum_search_cb(const struct bContext *C, void *but, const c
for (item = item_array; item->identifier; item++) {
/* note: need to give the index rather than the identifier because the enum can be freed */
if (BLI_strcasestr(item->name, str)) {
- if (false == UI_search_item_add(items, item->name, POINTER_FROM_INT(item->value), 0))
+ if (false == UI_search_item_add(items, item->name, POINTER_FROM_INT(item->value), item->icon))
break;
}
}
@@ -4615,7 +4771,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
tmp = BLI_strdup(RNA_property_identifier(but->rnaprop));
}
else if (type == BUT_GET_RNASTRUCT_IDENTIFIER) {
- if (but->rnaprop)
+ if (but->rnaprop && but->rnapoin.data)
tmp = BLI_strdup(RNA_struct_identifier(but->rnapoin.type));
else if (but->optype)
tmp = BLI_strdup(but->optype->idname);
@@ -4686,12 +4842,15 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
/* enum property */
ptr = &but->rnapoin;
prop = but->rnaprop;
- value = (but->type == UI_BTYPE_ROW) ? (int)but->hardmax : (int)ui_but_value_get(but);
+ value = (ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_TAB)) ? (int)but->hardmax : (int)ui_but_value_get(but);
}
else if (but->optype) {
PointerRNA *opptr = UI_but_operator_ptr_get(but);
wmOperatorType *ot = but->optype;
+ /* so the context is passed to itemf functions */
+ WM_operator_properties_sanitize(opptr, false);
+
/* if the default property of the operator is enum and it is set,
* fetch the tooltip of the selected value so that "Snap" and "Mirror"
* operator menus in the Anim Editors will show tooltips for the different
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index 36b0b938b5a..d102c7c582d 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -110,9 +110,25 @@ enum {
bool ui_but_can_align(const uiBut *but)
{
- return (
- !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE) &&
- (BLI_rctf_size_x(&but->rect) > 0.0f) && (BLI_rctf_size_y(&but->rect) > 0.0f));
+ const bool btype_can_align = !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N,
+ UI_BTYPE_TAB, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER);
+ return (btype_can_align && (BLI_rctf_size_x(&but->rect) > 0.0f) && (BLI_rctf_size_y(&but->rect) > 0.0f));
+}
+
+int ui_but_align_opposite_to_area_align_get(const ARegion *ar)
+{
+ switch (ar->alignment) {
+ case RGN_ALIGN_TOP:
+ return UI_BUT_ALIGN_DOWN;
+ case RGN_ALIGN_BOTTOM:
+ return UI_BUT_ALIGN_TOP;
+ case RGN_ALIGN_LEFT:
+ return UI_BUT_ALIGN_RIGHT;
+ case RGN_ALIGN_RIGHT:
+ return UI_BUT_ALIGN_LEFT;
+ }
+
+ return 0;
}
/**
@@ -320,13 +336,43 @@ static int ui_block_align_butal_cmp(const void *a, const void *b)
return 0;
}
+static void ui_block_align_but_to_region(uiBut *but, const ARegion *region)
+{
+ rctf *rect = &but->rect;
+ const float but_width = BLI_rctf_size_x(rect);
+ const float but_height = BLI_rctf_size_y(rect);
+ const float outline_px = U.pixelsize; /* This may have to be made more variable. */
+
+ switch (but->drawflag & UI_BUT_ALIGN) {
+ case UI_BUT_ALIGN_TOP:
+ rect->ymax = region->winy + outline_px;
+ rect->ymin = but->rect.ymax - but_height;
+ break;
+ case UI_BUT_ALIGN_DOWN:
+ rect->ymin = -outline_px;
+ rect->ymax = rect->ymin + but_height;
+ break;
+ case UI_BUT_ALIGN_LEFT:
+ rect->xmin = -outline_px;
+ rect->xmax = rect->xmin + but_width;
+ break;
+ case UI_BUT_ALIGN_RIGHT:
+ rect->xmax = region->winx + outline_px;
+ rect->xmin = rect->xmax - but_width;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+}
+
/**
* Compute the alignment of all 'align groups' of buttons in given block.
*
* This is using an order-independent algorithm, i.e. alignment of buttons should be OK regardless of order in which
* they are added to the block.
*/
-void ui_block_align_calc(uiBlock *block)
+void ui_block_align_calc(uiBlock *block, const ARegion *region)
{
uiBut *but;
int num_buttons = 0;
@@ -338,10 +384,17 @@ void ui_block_align_calc(uiBlock *block)
int side;
int i, j;
- /* First loop: we count number of buttons belonging to an align group, and clear their align flag. */
+ /* First loop: we count number of buttons belonging to an align group, and clear their align flag.
+ * Tabs get some special treatment here, they get aligned to region border. */
for (but = block->buttons.first; but; but = but->next) {
- /* Clear old align flags. */
- but->drawflag &= ~UI_BUT_ALIGN_ALL;
+ /* special case: tabs need to be aligned to a region border, drawflag tells which one */
+ if (but->type == UI_BTYPE_TAB) {
+ ui_block_align_but_to_region(but, region);
+ }
+ else {
+ /* Clear old align flags. */
+ but->drawflag &= ~UI_BUT_ALIGN_ALL;
+ }
if (but->alignnr != 0) {
num_buttons++;
@@ -462,7 +515,8 @@ void ui_block_align_calc(uiBlock *block)
bool ui_but_can_align(uiBut *but)
{
- return !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE);
+ return !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N,
+ UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER);
}
static bool buts_are_horiz(uiBut *but1, uiBut *but2)
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 10a23792e8f..4fe555615c2 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -39,12 +39,14 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_nla.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_keyframing.h"
#include "UI_interface.h"
@@ -101,6 +103,30 @@ void ui_but_anim_flag(uiBut *but, float cfra)
}
}
+void ui_but_anim_decorate_update_from_flag(uiBut *but)
+{
+ BLI_assert(UI_but_is_decorator(but) && but->prev);
+ int flag = but->prev->flag;
+ if (flag & UI_BUT_DRIVEN) {
+ but->icon = ICON_DECORATE_DRIVER;
+ }
+ else if (flag & UI_BUT_ANIMATED_KEY) {
+ but->icon = ICON_DECORATE_KEYFRAME;
+ }
+ else if (flag & UI_BUT_ANIMATED) {
+ but->icon = ICON_DECORATE_ANIMATE;
+ }
+ else if (flag & UI_BUT_OVERRIDEN) {
+ but->icon = ICON_DECORATE_OVERRIDE;
+ }
+ else {
+ but->icon = ICON_DECORATE;
+ }
+
+ const int flag_copy = (UI_BUT_DISABLED | UI_BUT_INACTIVE);
+ but->flag = (but->flag & ~flag_copy) | (flag & flag_copy);
+}
+
/**
* \a str can be NULL to only perform check if \a but has an expression at all.
* \return if button has an expression.
@@ -142,7 +168,7 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str)
BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression));
/* tag driver as needing to be recompiled */
- driver->flag |= DRIVER_FLAG_RECOMPILE;
+ BKE_driver_invalidate_expression(driver, true, false);
/* clear invalid flags which may prevent this from working */
driver->flag &= ~DRIVER_FLAG_INVALID;
@@ -211,8 +237,8 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression));
/* updates */
- driver->flag |= DRIVER_FLAG_RECOMPILE;
- DAG_relations_tag_update(CTX_data_main(C));
+ BKE_driver_invalidate_expression(driver, true, false);
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL);
ok = true;
}
@@ -240,10 +266,11 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
if (special) {
/* NLA Strip property */
if (IS_AUTOKEY_ON(scene)) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
- insert_keyframe_direct(reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, 0);
+ insert_keyframe_direct(depsgraph, reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, 0);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
@@ -252,10 +279,11 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
* making it easier to set up corrective drivers
*/
if (IS_AUTOKEY_ON(scene)) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
- insert_keyframe_direct(reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
+ insert_keyframe_direct(depsgraph, reports, but->rnapoin, but->rnaprop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
@@ -264,6 +292,7 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
/* TODO: this should probably respect the keyingset only option for anim */
if (autokeyframe_cfra_can_key(scene, id)) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
short flag = ANIM_get_keyframing_flags(scene, 1);
@@ -274,7 +303,8 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
* because a button may control all items of an array at once.
* E.g., color wheels (see T42567). */
BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1));
- insert_keyframe(bmain, reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ insert_keyframe(bmain, depsgraph, reports, id, action,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
fcu->rna_path, but->rnaindex, cfra, ts->keyframe_type, flag);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -293,3 +323,38 @@ void ui_but_anim_paste_driver(bContext *C)
/* this operator calls UI_context_active_but_prop_get */
WM_operator_name_call(C, "ANIM_OT_paste_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
}
+
+void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ uiBut *but = arg_but;
+ but = but->prev;
+
+ /* FIXME(campbell), swapping active pointer is weak. */
+ SWAP(struct uiHandleButtonData *, but->active, but->next->active);
+ wm->op_undo_depth++;
+
+ if (but->flag & UI_BUT_DRIVEN) {
+ /* pass */
+ /* TODO: report? */
+ }
+ else if (but->flag & UI_BUT_ANIMATED_KEY) {
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false);
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+ WM_operator_properties_free(&props_ptr);
+ }
+ else {
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false);
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+ WM_operator_properties_free(&props_ptr);
+ }
+
+ SWAP(struct uiHandleButtonData *, but->active, but->next->active);
+ wm->op_undo_depth--;
+}
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 54e755f6cc6..0ffc97444e1 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -24,6 +24,8 @@
* Generic context popup menus.
*/
+#include <string.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
@@ -214,6 +216,98 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but, NULL);
}
+static bool ui_but_is_user_menu_compatible(bContext *C, uiBut *but)
+{
+ return (but->optype ||
+ (but->rnaprop &&
+ (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) &&
+ (WM_context_member_from_ptr(C, &but->rnapoin) != NULL)) ||
+ UI_but_menutype_get(but));
+}
+
+static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *um)
+{
+ MenuType *mt = NULL;
+ if (but->optype) {
+ IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
+ return (bUserMenuItem *)ED_screen_user_menu_item_find_operator(
+ &um->items, but->optype, prop, but->opcontext);
+ }
+ else if (but->rnaprop) {
+ const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin);
+ const char *prop_id = RNA_property_identifier(but->rnaprop);
+ return (bUserMenuItem *)ED_screen_user_menu_item_find_prop(
+ &um->items, member_id, prop_id, but->rnaindex);
+ }
+ else if ((mt = UI_but_menutype_get(but))) {
+ return (bUserMenuItem *)ED_screen_user_menu_item_find_menu(
+ &um->items, mt);
+ }
+ else {
+ return NULL;
+ }
+}
+
+static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
+{
+ BLI_assert(ui_but_is_user_menu_compatible(C, but));
+
+ char drawstr[sizeof(but->drawstr)];
+ STRNCPY(drawstr, but->drawstr);
+ if (but->flag & UI_BUT_HAS_SEP_CHAR) {
+ char *sep = strrchr(drawstr, UI_SEP_CHAR);
+ if (sep) {
+ *sep = '\0';
+ }
+ }
+
+ MenuType *mt = NULL;
+ if (but->optype) {
+ ED_screen_user_menu_item_add_operator(
+ &um->items, drawstr,
+ but->optype, but->opptr ? but->opptr->data : NULL, but->opcontext);
+ }
+ else if (but->rnaprop) {
+ /* Note: 'member_id' may be a path. */
+ const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin);
+ const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin);
+ const char *member_id_data_path = member_id;
+ if (data_path) {
+ member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path);
+ }
+ const char *prop_id = RNA_property_identifier(but->rnaprop);
+ /* Note, ignore 'drawstr', use property idname always. */
+ ED_screen_user_menu_item_add_prop(
+ &um->items, "",
+ member_id_data_path, prop_id, but->rnaindex);
+ if (data_path) {
+ MEM_freeN((void *)data_path);
+ }
+ if (member_id != member_id_data_path) {
+ MEM_freeN((void *)member_id_data_path);
+ }
+ }
+ else if ((mt = UI_but_menutype_get(but))) {
+ ED_screen_user_menu_item_add_menu(
+ &um->items, drawstr,
+ mt);
+ }
+}
+
+static void popup_user_menu_add_or_replace_func(bContext *C, void *arg1, void *UNUSED(arg2))
+{
+ uiBut *but = arg1;
+ bUserMenu *um = ED_screen_user_menu_ensure(C);
+ ui_but_user_menu_add(C, but, um);
+}
+
+static void popup_user_menu_remove_func(bContext *UNUSED(C), void *arg1, void *arg2)
+{
+ bUserMenu *um = arg1;
+ bUserMenuItem *umi = arg2;
+ ED_screen_user_menu_item_remove(&um->items, umi);
+}
+
static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop)
{
const PropertySubType subtype = RNA_property_subtype(prop);
@@ -267,7 +361,19 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
}
- if (but->rnapoin.data && but->rnaprop) {
+ const bool is_disabled = but->flag & UI_BUT_DISABLED;
+
+ if (is_disabled) {
+ /* Suppress editing commands. */
+ }
+ else if (but->type == UI_BTYPE_TAB) {
+ uiButTab *tab = (uiButTab *)but;
+ if (tab->menu) {
+ UI_menutype_draw(C, tab->menu, layout);
+ uiItemS(layout);
+ }
+ }
+ else if (but->rnapoin.data && but->rnaprop) {
PointerRNA *ptr = &but->rnapoin;
PropertyRNA *prop = but->rnaprop;
const PropertyType type = RNA_property_type(prop);
@@ -285,6 +391,9 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
const bool is_array = RNA_property_array_length(&but->rnapoin, but->rnaprop) != 0;
const bool is_array_component = (is_array && but->rnaindex != -1);
+ const int override_status = RNA_property_static_override_status(ptr, prop, -1);
+ const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0;
+
/* Keyframes */
if (but->flag & UI_BUT_ANIMATED_KEY) {
/* Set the (button_pointer, button_prop) and pointer data for Python access to the hovered ui element. */
@@ -378,6 +487,12 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
ICON_NONE, "ANIM_OT_paste_driver_button");
}
+
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Edit Driver"),
+ ICON_DRIVER, "ANIM_OT_driver_button_edit");
+
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Drivers Editor"),
+ ICON_NONE, "SCREEN_OT_drivers_editor_show");
}
else if (but->flag & (UI_BUT_ANIMATED_KEY | UI_BUT_ANIMATED)) {
/* pass */
@@ -385,23 +500,16 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
else if (is_anim) {
uiItemS(layout);
- if (is_array_component) {
- uiItemMenuEnumO(
- layout, C, "ANIM_OT_driver_button_add", "mapping_type",
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"),
- ICON_DRIVER);
- }
- else {
- uiItemMenuEnumO(
- layout, C, "ANIM_OT_driver_button_add", "mapping_type",
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"),
- ICON_DRIVER);
- }
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"),
+ ICON_DRIVER, "ANIM_OT_driver_button_add");
if (ANIM_driver_can_paste()) {
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"),
ICON_NONE, "ANIM_OT_paste_driver_button");
}
+
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Drivers Editor"),
+ ICON_NONE, "SCREEN_OT_drivers_editor_show");
}
/* Keying Sets */
@@ -428,6 +536,65 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
}
}
+ if (is_overridable) {
+ wmOperatorType *ot;
+ PointerRNA op_ptr;
+ /* Override Operators */
+ uiItemS(layout);
+
+ if (but->flag & UI_BUT_OVERRIDEN) {
+ if (is_array_component) {
+#if 0 /* Disabled for now. */
+ ot = WM_operatortype_find("UI_OT_override_type_set_button", false);
+ uiItemFullO_ptr(
+ layout, ot, "Overrides Type", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", true);
+ uiItemFullO_ptr(
+ layout, ot, "Single Override Type", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", false);
+#endif
+ uiItemBooleanO(
+ layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Overrides"),
+ ICON_X, "UI_OT_override_remove_button", "all", true);
+ uiItemBooleanO(
+ layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Single Override"),
+ ICON_X, "UI_OT_override_remove_button", "all", false);
+ }
+ else {
+#if 0 /* Disabled for now. */
+ uiItemFullO(
+ layout, "UI_OT_override_type_set_button", "Override Type", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", false);
+#endif
+ uiItemBooleanO(
+ layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Override"),
+ ICON_X, "UI_OT_override_remove_button", "all", true);
+ }
+ }
+ else {
+ if (is_array_component) {
+ ot = WM_operatortype_find("UI_OT_override_type_set_button", false);
+ uiItemFullO_ptr(
+ layout, ot, "Define Overrides", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", true);
+ uiItemFullO_ptr(
+ layout, ot, "Define Single Override", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", false);
+ }
+ else {
+ uiItemFullO(
+ layout, "UI_OT_override_type_set_button", "Define Override", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", false);
+ }
+ }
+ }
+
uiItemS(layout);
/* Property Operators */
@@ -477,6 +644,44 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
}
}
+ /* Pointer properties and string properties with prop_search support jumping to target object/bone. */
+ if (but->rnapoin.data && but->rnaprop) {
+ const PropertyType type = RNA_property_type(but->rnaprop);
+
+ if ((type == PROP_POINTER) || (type == PROP_STRING && but->type == UI_BTYPE_SEARCH_MENU && but->search_func == ui_rna_collection_search_cb)) {
+ uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump To Target"),
+ ICON_NONE, "UI_OT_jump_to_target_button");
+ uiItemS(layout);
+ }
+ }
+
+ /* Favorites Menu */
+ if (ui_but_is_user_menu_compatible(C, but)) {
+ uiBlock *block = uiLayoutGetBlock(layout);
+ const int w = uiLayoutGetWidth(layout);
+ uiBut *but2;
+
+ but2 = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, ICON_MENU_PANEL,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Quick Favorites"),
+ 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0,
+ "Add to a user defined context menu (stored in the user preferences)");
+ UI_but_func_set(but2, popup_user_menu_add_or_replace_func, but, NULL);
+
+ bUserMenu *um = ED_screen_user_menu_find(C);
+ if (um) {
+ bUserMenuItem *umi = ui_but_user_menu_find(C, but, um);
+ if (umi != NULL) {
+ but2 = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, ICON_BLANK1,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Quick Favorites"),
+ 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ UI_but_func_set(but2, popup_user_menu_remove_func, um, umi);
+ }
+ }
+ uiItemS(layout);
+ }
+
/* Operator buttons */
if (but->optype) {
uiBlock *block = uiLayoutGetBlock(layout);
@@ -487,7 +692,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
/* We want to know if this op has a shortcut, be it hotkey or not. */
wmKeyMapItem *kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, false, &km);
- /* We do have a shortcut, but only keyboard ones are editbale that way... */
+ /* We do have a shortcut, but only keyboard ones are editable that way... */
if (kmi) {
if (ISKEYBOARD(kmi->type)) {
#if 0 /* would rather use a block but, but gets weirdly positioned... */
@@ -503,7 +708,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
UI_but_func_set(but2, popup_change_shortcut_func, but, NULL);
but2 = uiDefIconTextBut(
- block, UI_BTYPE_BUT, 0, ICON_NONE,
+ block, UI_BTYPE_BUT, 0, ICON_BLANK1,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
UI_but_func_set(but2, remove_shortcut_func, but, NULL);
@@ -517,11 +722,11 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
UI_but_flag_enable(but2, UI_BUT_DISABLED);
}
}
- /* only show 'add' if there's a suitable key map for it to go in */
+ /* only show 'assign' if there's a suitable key map for it to go in */
else if (WM_keymap_guess_opname(C, but->optype->idname)) {
but2 = uiDefIconTextBut(
block, UI_BTYPE_BUT, 0, ICON_HAND,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
UI_but_func_set(but2, popup_add_shortcut_func, but, NULL);
}
@@ -532,15 +737,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
uiItemS(layout);
}
- /* Show header tools for header buttons. */
- if (ui_block_is_popup_any(but->block) == false) {
- ARegion *ar = CTX_wm_region(C);
- if (ar && (ar->regiontype == RGN_TYPE_HEADER)) {
- uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL);
- uiItemS(layout);
- }
- }
-
{ /* Docs */
char buf[512];
@@ -549,11 +745,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
ICON_URL, "WM_OT_doc_view_manual_ui_context");
- uiItemFullO(
- layout, "WM_OT_doc_view",
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
- ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr_props);
- RNA_string_set(&ptr_props, "doc_id", buf);
+ if (U.flag & USER_DEVELOPER_UI) {
+ uiItemFullO(
+ layout, "WM_OT_doc_view",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
+ ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr_props);
+ RNA_string_set(&ptr_props, "doc_id", buf);
+ }
/* XXX inactive option, not for public! */
#if 0
@@ -566,7 +764,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
}
}
- if (but->optype) {
+ if (but->optype && U.flag & USER_DEVELOPER_UI) {
uiItemO(layout, NULL,
ICON_NONE, "UI_OT_copy_python_command_button");
}
@@ -582,6 +780,21 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
uiItemFullO(layout, "UI_OT_edittranslation_init", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0, NULL);
}
+ /* Show header tools for header buttons. */
+ if (ui_block_is_popup_any(but->block) == false) {
+ const ARegion *ar = CTX_wm_region(C);
+
+ if (!ar) {
+ /* skip */
+ }
+ else if (ar->regiontype == RGN_TYPE_HEADER) {
+ uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL);
+ }
+ else if (ar->regiontype == RGN_TYPE_NAV_BAR) {
+ uiItemMenuF(layout, IFACE_("Navigation Bar"), ICON_NONE, ED_screens_navigation_bar_tools_menu_create, NULL);
+ }
+ }
+
MenuType *mt = WM_menutype_find("WM_MT_button_context", true);
if (mt) {
UI_menutype_draw(C, mt, uiLayoutColumn(layout, false));
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 50cd1c544c4..8c785f63978 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -50,19 +50,23 @@
#include "IMB_imbuf_types.h"
#include "IMB_colormanagement.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "BLF_api.h"
-#include "GPU_draw.h"
-#include "GPU_basic_shader.h"
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "UI_interface.h"
/* own include */
#include "interface_intern.h"
+
static int roundboxtype = UI_CNR_ALL;
void UI_draw_roundbox_corner_set(int type)
@@ -71,340 +75,564 @@ void UI_draw_roundbox_corner_set(int type)
* if this is undone, it's not that big a deal, only makes curves edges
* square for the */
roundboxtype = type;
-
}
+#if 0 /* unused */
int UI_draw_roundbox_corner_get(void)
{
return roundboxtype;
}
+#endif
+
+void UI_draw_roundbox_3ubAlpha(bool filled, float minx, float miny, float maxx, float maxy, float rad, const unsigned char col[3], unsigned char alpha)
+{
+ float colv[4];
+ colv[0] = ((float)col[0]) / 255;
+ colv[1] = ((float)col[1]) / 255;
+ colv[2] = ((float)col[2]) / 255;
+ colv[3] = ((float)alpha) / 255;
+ UI_draw_roundbox_4fv(filled, minx, miny, maxx, maxy, rad, colv);
+}
+
+void UI_draw_roundbox_3fvAlpha(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[3], float alpha)
+{
+ float colv[4];
+ colv[0] = col[0];
+ colv[1] = col[1];
+ colv[2] = col[2];
+ colv[3] = alpha;
+ UI_draw_roundbox_4fv(filled, minx, miny, maxx, maxy, rad, colv);
+}
+
+void UI_draw_roundbox_aa(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4])
+{
+ uiWidgetBaseParameters widget_params = {
+ .recti.xmin = minx, .recti.ymin = miny,
+ .recti.xmax = maxx, .recti.ymax = maxy,
+ .radi = rad,
+ .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
+ .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
+ .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
+ .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
+ .color_inner1[0] = color[0], .color_inner2[0] = color[0],
+ .color_inner1[1] = color[1], .color_inner2[1] = color[1],
+ .color_inner1[2] = color[2], .color_inner2[2] = color[2],
+ .color_inner1[3] = color[3], .color_inner2[3] = color[3],
+ .alpha_discard = 1.0f,
+ };
+
+ GPU_blend(true);
+
+ if (filled) {
+ /* plain antialiased filled box */
+ widget_params.color_inner1[3] *= 0.125f;
+ widget_params.color_inner2[3] *= 0.125f;
+
+ /* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space.
+ * If it has been scaled, then it's no longer valid. */
+ GPUBatch *batch = ui_batch_roundbox_get(filled, true);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
+ GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
+ GPU_batch_draw(batch);
+ }
+ else {
+ /* plain antialiased unfilled box */
+ GPU_line_smooth(true);
+
+ GPUBatch *batch = ui_batch_roundbox_get(filled, false);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
+ GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
+ GPU_batch_draw(batch);
+
+ GPU_line_smooth(false);
+ }
+
+ GPU_blend(false);
+}
-void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad)
+void UI_draw_roundbox_4fv(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[4])
{
+#if 0
float vec[7][2] = {
{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
{0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805},
};
int a;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
/* mult */
for (a = 0; a < 7; a++) {
mul_v2_fl(vec[a], rad);
}
- glBegin(mode);
+ uint vert_len = 0;
+ vert_len += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
+ vert_len += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
+ vert_len += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
+ vert_len += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(col);
+
+ immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_len);
/* start with corner right-bottom */
if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
- glVertex2f(maxx - rad, miny);
+ immVertex2f(pos, maxx - rad, miny);
for (a = 0; a < 7; a++) {
- glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]);
+ immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
}
- glVertex2f(maxx, miny + rad);
+ immVertex2f(pos, maxx, miny + rad);
}
else {
- glVertex2f(maxx, miny);
+ immVertex2f(pos, maxx, miny);
}
/* corner right-top */
if (roundboxtype & UI_CNR_TOP_RIGHT) {
- glVertex2f(maxx, maxy - rad);
+ immVertex2f(pos, maxx, maxy - rad);
for (a = 0; a < 7; a++) {
- glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]);
+ immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
}
- glVertex2f(maxx - rad, maxy);
+ immVertex2f(pos, maxx - rad, maxy);
}
else {
- glVertex2f(maxx, maxy);
+ immVertex2f(pos, maxx, maxy);
}
/* corner left-top */
if (roundboxtype & UI_CNR_TOP_LEFT) {
- glVertex2f(minx + rad, maxy);
+ immVertex2f(pos, minx + rad, maxy);
for (a = 0; a < 7; a++) {
- glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]);
+ immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
}
- glVertex2f(minx, maxy - rad);
+ immVertex2f(pos, minx, maxy - rad);
}
else {
- glVertex2f(minx, maxy);
+ immVertex2f(pos, minx, maxy);
}
/* corner left-bottom */
if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
- glVertex2f(minx, miny + rad);
+ immVertex2f(pos, minx, miny + rad);
for (a = 0; a < 7; a++) {
- glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]);
+ immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
}
- glVertex2f(minx + rad, miny);
+ immVertex2f(pos, minx + rad, miny);
}
else {
- glVertex2f(minx, miny);
+ immVertex2f(pos, minx, miny);
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
+#endif
+
+ uiWidgetBaseParameters widget_params = {
+ .recti.xmin = minx, .recti.ymin = miny,
+ .recti.xmax = maxx, .recti.ymax = maxy,
+ .radi = rad,
+ .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
+ .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
+ .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
+ .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
+ .color_inner1[0] = col[0], .color_inner2[0] = col[0],
+ .color_inner1[1] = col[1], .color_inner2[1] = col[1],
+ .color_inner1[2] = col[2], .color_inner2[2] = col[2],
+ .color_inner1[3] = col[3], .color_inner2[3] = col[3],
+ .alpha_discard = 1.0f,
+ };
+
+ GPUBatch *batch = ui_batch_roundbox_get(filled, false);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
+ GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
+ GPU_batch_draw(batch);
}
-static void round_box_shade_col(const float col1[3], float const col2[3], const float fac)
+#if 0
+static void round_box_shade_col(unsigned attrib, const float col1[3], float const col2[3], const float fac)
{
- float col[3] = {
+ float col[4] = {
fac * col1[0] + (1.0f - fac) * col2[0],
fac * col1[1] + (1.0f - fac) * col2[1],
- fac * col1[2] + (1.0f - fac) * col2[2]
+ fac * col1[2] + (1.0f - fac) * col2[2],
+ 1.0f
};
- glColor3fv(col);
+ immAttr4fv(attrib, col);
}
+#endif
/* linear horizontal shade within button or in outline */
/* view2d scrollers use it */
void UI_draw_roundbox_shade_x(
- int mode, float minx, float miny, float maxx, float maxy,
- float rad, float shadetop, float shadedown)
+ bool filled, float minx, float miny, float maxx, float maxy,
+ float rad, float shadetop, float shadedown, const float col[4])
{
+#if 0
float vec[7][2] = {
{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
- {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
+ {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805},
+ };
const float div = maxy - miny;
const float idiv = 1.0f / div;
- float coltop[3], coldown[3], color[4];
+ float coltop[3], coldown[3];
+ int vert_count = 0;
int a;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
/* mult */
for (a = 0; a < 7; a++) {
mul_v2_fl(vec[a], rad);
}
- /* get current color, needs to be outside of glBegin/End */
- glGetFloatv(GL_CURRENT_COLOR, color);
/* 'shade' defines strength of shading */
- coltop[0] = min_ff(1.0f, color[0] + shadetop);
- coltop[1] = min_ff(1.0f, color[1] + shadetop);
- coltop[2] = min_ff(1.0f, color[2] + shadetop);
- coldown[0] = max_ff(0.0f, color[0] + shadedown);
- coldown[1] = max_ff(0.0f, color[1] + shadedown);
- coldown[2] = max_ff(0.0f, color[2] + shadedown);
+ coltop[0] = min_ff(1.0f, col[0] + shadetop);
+ coltop[1] = min_ff(1.0f, col[1] + shadetop);
+ coltop[2] = min_ff(1.0f, col[2] + shadetop);
+ coldown[0] = max_ff(0.0f, col[0] + shadedown);
+ coldown[1] = max_ff(0.0f, col[1] + shadedown);
+ coldown[2] = max_ff(0.0f, col[2] + shadedown);
- glBegin(mode);
+ vert_count += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
+ vert_count += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
+ vert_count += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
+ vert_count += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
+
+ immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_count);
/* start with corner right-bottom */
if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
- round_box_shade_col(coltop, coldown, 0.0);
- glVertex2f(maxx - rad, miny);
+ round_box_shade_col(color, coltop, coldown, 0.0);
+ immVertex2f(pos, maxx - rad, miny);
for (a = 0; a < 7; a++) {
- round_box_shade_col(coltop, coldown, vec[a][1] * idiv);
- glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]);
+ round_box_shade_col(color, coltop, coldown, vec[a][1] * idiv);
+ immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
}
- round_box_shade_col(coltop, coldown, rad * idiv);
- glVertex2f(maxx, miny + rad);
+ round_box_shade_col(color, coltop, coldown, rad * idiv);
+ immVertex2f(pos, maxx, miny + rad);
}
else {
- round_box_shade_col(coltop, coldown, 0.0);
- glVertex2f(maxx, miny);
+ round_box_shade_col(color, coltop, coldown, 0.0);
+ immVertex2f(pos, maxx, miny);
}
/* corner right-top */
if (roundboxtype & UI_CNR_TOP_RIGHT) {
- round_box_shade_col(coltop, coldown, (div - rad) * idiv);
- glVertex2f(maxx, maxy - rad);
+ round_box_shade_col(color, coltop, coldown, (div - rad) * idiv);
+ immVertex2f(pos, maxx, maxy - rad);
for (a = 0; a < 7; a++) {
- round_box_shade_col(coltop, coldown, (div - rad + vec[a][1]) * idiv);
- glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]);
+ round_box_shade_col(color, coltop, coldown, (div - rad + vec[a][1]) * idiv);
+ immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
}
- round_box_shade_col(coltop, coldown, 1.0);
- glVertex2f(maxx - rad, maxy);
+ round_box_shade_col(color, coltop, coldown, 1.0);
+ immVertex2f(pos, maxx - rad, maxy);
}
else {
- round_box_shade_col(coltop, coldown, 1.0);
- glVertex2f(maxx, maxy);
+ round_box_shade_col(color, coltop, coldown, 1.0);
+ immVertex2f(pos, maxx, maxy);
}
/* corner left-top */
if (roundboxtype & UI_CNR_TOP_LEFT) {
- round_box_shade_col(coltop, coldown, 1.0);
- glVertex2f(minx + rad, maxy);
+ round_box_shade_col(color, coltop, coldown, 1.0);
+ immVertex2f(pos, minx + rad, maxy);
for (a = 0; a < 7; a++) {
- round_box_shade_col(coltop, coldown, (div - vec[a][1]) * idiv);
- glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]);
+ round_box_shade_col(color, coltop, coldown, (div - vec[a][1]) * idiv);
+ immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
}
- round_box_shade_col(coltop, coldown, (div - rad) * idiv);
- glVertex2f(minx, maxy - rad);
+ round_box_shade_col(color, coltop, coldown, (div - rad) * idiv);
+ immVertex2f(pos, minx, maxy - rad);
}
else {
- round_box_shade_col(coltop, coldown, 1.0);
- glVertex2f(minx, maxy);
+ round_box_shade_col(color, coltop, coldown, 1.0);
+ immVertex2f(pos, minx, maxy);
}
/* corner left-bottom */
if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
- round_box_shade_col(coltop, coldown, rad * idiv);
- glVertex2f(minx, miny + rad);
+ round_box_shade_col(color, coltop, coldown, rad * idiv);
+ immVertex2f(pos, minx, miny + rad);
for (a = 0; a < 7; a++) {
- round_box_shade_col(coltop, coldown, (rad - vec[a][1]) * idiv);
- glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]);
+ round_box_shade_col(color, coltop, coldown, (rad - vec[a][1]) * idiv);
+ immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
}
- round_box_shade_col(coltop, coldown, 0.0);
- glVertex2f(minx + rad, miny);
+ round_box_shade_col(color, coltop, coldown, 0.0);
+ immVertex2f(pos, minx + rad, miny);
}
else {
- round_box_shade_col(coltop, coldown, 0.0);
- glVertex2f(minx, miny);
+ round_box_shade_col(color, coltop, coldown, 0.0);
+ immVertex2f(pos, minx, miny);
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
+#endif
+
+ uiWidgetBaseParameters widget_params = {
+ .recti.xmin = minx, .recti.ymin = miny,
+ .recti.xmax = maxx, .recti.ymax = maxy,
+ .radi = rad,
+ .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
+ .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
+ .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
+ .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
+ .color_inner1[0] = min_ff(1.0f, col[0] + shadetop),
+ .color_inner2[0] = max_ff(0.0f, col[0] + shadedown),
+ .color_inner1[1] = min_ff(1.0f, col[1] + shadetop),
+ .color_inner2[1] = max_ff(0.0f, col[1] + shadedown),
+ .color_inner1[2] = min_ff(1.0f, col[2] + shadetop),
+ .color_inner2[2] = max_ff(0.0f, col[2] + shadedown),
+ .color_inner1[3] = 1.0f,
+ .color_inner2[3] = 1.0f,
+ .alpha_discard = 1.0f,
+ };
+
+ GPUBatch *batch = ui_batch_roundbox_get(filled, false);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
+ GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float *)&widget_params);
+ GPU_batch_draw(batch);
}
+#if 0 /* unused */
/* linear vertical shade within button or in outline */
/* view2d scrollers use it */
void UI_draw_roundbox_shade_y(
- int mode, float minx, float miny, float maxx, float maxy,
- float rad, float shadeLeft, float shadeRight)
+ bool filled, float minx, float miny, float maxx, float maxy,
+ float rad, float shadeleft, float shaderight, const float col[4])
{
float vec[7][2] = {
{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
- {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
+ {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805},
+ };
const float div = maxx - minx;
const float idiv = 1.0f / div;
- float colLeft[3], colRight[3], color[4];
+ float colLeft[3], colRight[3];
+ int vert_count = 0;
int a;
/* mult */
for (a = 0; a < 7; a++) {
mul_v2_fl(vec[a], rad);
}
- /* get current color, needs to be outside of glBegin/End */
- glGetFloatv(GL_CURRENT_COLOR, color);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
/* 'shade' defines strength of shading */
- colLeft[0] = min_ff(1.0f, color[0] + shadeLeft);
- colLeft[1] = min_ff(1.0f, color[1] + shadeLeft);
- colLeft[2] = min_ff(1.0f, color[2] + shadeLeft);
- colRight[0] = max_ff(0.0f, color[0] + shadeRight);
- colRight[1] = max_ff(0.0f, color[1] + shadeRight);
- colRight[2] = max_ff(0.0f, color[2] + shadeRight);
+ colLeft[0] = min_ff(1.0f, col[0] + shadeleft);
+ colLeft[1] = min_ff(1.0f, col[1] + shadeleft);
+ colLeft[2] = min_ff(1.0f, col[2] + shadeleft);
+ colRight[0] = max_ff(0.0f, col[0] + shaderight);
+ colRight[1] = max_ff(0.0f, col[1] + shaderight);
+ colRight[2] = max_ff(0.0f, col[2] + shaderight);
+
- glBegin(mode);
+ vert_count += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 9 : 1;
+ vert_count += (roundboxtype & UI_CNR_TOP_RIGHT) ? 9 : 1;
+ vert_count += (roundboxtype & UI_CNR_TOP_LEFT) ? 9 : 1;
+ vert_count += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 9 : 1;
+
+ immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, vert_count);
/* start with corner right-bottom */
if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
- round_box_shade_col(colLeft, colRight, 0.0);
- glVertex2f(maxx - rad, miny);
+ round_box_shade_col(color, colLeft, colRight, 0.0);
+ immVertex2f(pos, maxx - rad, miny);
for (a = 0; a < 7; a++) {
- round_box_shade_col(colLeft, colRight, vec[a][0] * idiv);
- glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]);
+ round_box_shade_col(color, colLeft, colRight, vec[a][0] * idiv);
+ immVertex2f(pos, maxx - rad + vec[a][0], miny + vec[a][1]);
}
- round_box_shade_col(colLeft, colRight, rad * idiv);
- glVertex2f(maxx, miny + rad);
+ round_box_shade_col(color, colLeft, colRight, rad * idiv);
+ immVertex2f(pos, maxx, miny + rad);
}
else {
- round_box_shade_col(colLeft, colRight, 0.0);
- glVertex2f(maxx, miny);
+ round_box_shade_col(color, colLeft, colRight, 0.0);
+ immVertex2f(pos, maxx, miny);
}
/* corner right-top */
if (roundboxtype & UI_CNR_TOP_RIGHT) {
- round_box_shade_col(colLeft, colRight, 0.0);
- glVertex2f(maxx, maxy - rad);
+ round_box_shade_col(color, colLeft, colRight, 0.0);
+ immVertex2f(pos, maxx, maxy - rad);
for (a = 0; a < 7; a++) {
- round_box_shade_col(colLeft, colRight, (div - rad - vec[a][0]) * idiv);
- glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]);
+ round_box_shade_col(color, colLeft, colRight, (div - rad - vec[a][0]) * idiv);
+ immVertex2f(pos, maxx - vec[a][1], maxy - rad + vec[a][0]);
}
- round_box_shade_col(colLeft, colRight, (div - rad) * idiv);
- glVertex2f(maxx - rad, maxy);
+ round_box_shade_col(color, colLeft, colRight, (div - rad) * idiv);
+ immVertex2f(pos, maxx - rad, maxy);
}
else {
- round_box_shade_col(colLeft, colRight, 0.0);
- glVertex2f(maxx, maxy);
+ round_box_shade_col(color, colLeft, colRight, 0.0);
+ immVertex2f(pos, maxx, maxy);
}
/* corner left-top */
if (roundboxtype & UI_CNR_TOP_LEFT) {
- round_box_shade_col(colLeft, colRight, (div - rad) * idiv);
- glVertex2f(minx + rad, maxy);
+ round_box_shade_col(color, colLeft, colRight, (div - rad) * idiv);
+ immVertex2f(pos, minx + rad, maxy);
for (a = 0; a < 7; a++) {
- round_box_shade_col(colLeft, colRight, (div - rad + vec[a][0]) * idiv);
- glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]);
+ round_box_shade_col(color, colLeft, colRight, (div - rad + vec[a][0]) * idiv);
+ immVertex2f(pos, minx + rad - vec[a][0], maxy - vec[a][1]);
}
- round_box_shade_col(colLeft, colRight, 1.0);
- glVertex2f(minx, maxy - rad);
+ round_box_shade_col(color, colLeft, colRight, 1.0);
+ immVertex2f(pos, minx, maxy - rad);
}
else {
- round_box_shade_col(colLeft, colRight, 1.0);
- glVertex2f(minx, maxy);
+ round_box_shade_col(color, colLeft, colRight, 1.0);
+ immVertex2f(pos, minx, maxy);
}
/* corner left-bottom */
if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
- round_box_shade_col(colLeft, colRight, 1.0);
- glVertex2f(minx, miny + rad);
+ round_box_shade_col(color, colLeft, colRight, 1.0);
+ immVertex2f(pos, minx, miny + rad);
for (a = 0; a < 7; a++) {
- round_box_shade_col(colLeft, colRight, (vec[a][0]) * idiv);
- glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]);
+ round_box_shade_col(color, colLeft, colRight, (vec[a][0]) * idiv);
+ immVertex2f(pos, minx + vec[a][1], miny + rad - vec[a][0]);
}
- round_box_shade_col(colLeft, colRight, 1.0);
- glVertex2f(minx + rad, miny);
+ round_box_shade_col(color, colLeft, colRight, 1.0);
+ immVertex2f(pos, minx + rad, miny);
}
else {
- round_box_shade_col(colLeft, colRight, 1.0);
- glVertex2f(minx, miny);
+ round_box_shade_col(color, colLeft, colRight, 1.0);
+ immVertex2f(pos, minx, miny);
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
}
+#endif /* unused */
-/* plain antialiased unfilled rectangle */
-void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad)
+void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4])
{
- float color[4];
-
- if (roundboxtype & UI_RB_ALPHA) {
- glGetFloatv(GL_CURRENT_COLOR, color);
- color[3] = 0.5;
- glColor4fv(color);
- glEnable(GL_BLEND);
- }
+ int ofs_y = 4 * U.pixelsize;
- /* set antialias line */
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ immRecti(pos, pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize));
+ immUnbindProgram();
}
-/* (old, used in outliner) plain antialiased filled box */
-void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad)
-{
- ui_draw_anti_roundbox(GL_POLYGON, minx, miny, maxx, maxy, rad, roundboxtype & UI_RB_ALPHA);
-}
+/* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
-void UI_draw_text_underline(int pos_x, int pos_y, int len, int height)
+/* based on UI_draw_roundbox_gl_mode, check on making a version which allows us to skip some sides */
+void ui_draw_but_TAB_outline(const rcti *rect, float rad, unsigned char highlight[3], unsigned char highlight_fade[3])
{
- int ofs_y = 4 * U.pixelsize;
- glRecti(pos_x, pos_y - ofs_y, pos_x + len, pos_y - ofs_y + (height * U.pixelsize));
-}
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ /* add a 1px offset, looks nicer */
+ const int minx = rect->xmin + U.pixelsize, maxx = rect->xmax - U.pixelsize;
+ const int miny = rect->ymin + U.pixelsize, maxy = rect->ymax - U.pixelsize;
+ int a;
+ float vec[4][2] = {
+ {0.195, 0.02},
+ {0.55, 0.169},
+ {0.831, 0.45},
+ {0.98, 0.805},
+ };
-/* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */
+
+ /* mult */
+ for (a = 0; a < 4; a++) {
+ mul_v2_fl(vec[a], rad);
+ }
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, 25);
+
+ immAttr3ubv(col, highlight);
+
+ /* start with corner left-top */
+ if (roundboxtype & UI_CNR_TOP_LEFT) {
+ immVertex2f(pos, minx, maxy - rad);
+ for (a = 0; a < 4; a++) {
+ immVertex2f(pos, minx + vec[a][1], maxy - rad + vec[a][0]);
+ }
+ immVertex2f(pos, minx + rad, maxy);
+ }
+ else {
+ immVertex2f(pos, minx, maxy);
+ }
+
+ /* corner right-top */
+ if (roundboxtype & UI_CNR_TOP_RIGHT) {
+ immVertex2f(pos, maxx - rad, maxy);
+ for (a = 0; a < 4; a++) {
+ immVertex2f(pos, maxx - rad + vec[a][0], maxy - vec[a][1]);
+ }
+ immVertex2f(pos, maxx, maxy - rad);
+ }
+ else {
+ immVertex2f(pos, maxx, maxy);
+ }
+
+ immAttr3ubv(col, highlight_fade);
+
+ /* corner right-bottom */
+ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
+ immVertex2f(pos, maxx, miny + rad);
+ for (a = 0; a < 4; a++) {
+ immVertex2f(pos, maxx - vec[a][1], miny + rad - vec[a][0]);
+ }
+ immVertex2f(pos, maxx - rad, miny);
+ }
+ else {
+ immVertex2f(pos, maxx, miny);
+ }
+
+ /* corner left-bottom */
+ if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
+ immVertex2f(pos, minx + rad, miny);
+ for (a = 0; a < 4; a++) {
+ immVertex2f(pos, minx + rad - vec[a][0], miny + vec[a][1]);
+ }
+ immVertex2f(pos, minx, miny + rad);
+ }
+ else {
+ immVertex2f(pos, minx, miny);
+ }
+
+ immAttr3ubv(col, highlight);
+
+ /* back to corner left-top */
+ immVertex2f(pos, minx, roundboxtype & UI_CNR_TOP_LEFT ? maxy - rad : maxy);
+
+ immEnd();
+ immUnbindProgram();
+}
void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect)
{
@@ -416,37 +644,37 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
if (!ibuf) return;
+ float facx = 1.0f;
+ float facy = 1.0f;
+
int w = BLI_rcti_size_x(rect);
int h = BLI_rcti_size_y(rect);
/* scissor doesn't seem to be doing the right thing...? */
#if 0
- //glColor4f(1.0, 0.f, 0.f, 1.f);
- //fdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax)
-
/* prevent drawing outside widget area */
- GLint scissor[4];
- glGetIntegerv(GL_SCISSOR_BOX, scissor);
- glScissor(ar->winrct.xmin + rect->xmin, ar->winrct.ymin + rect->ymin, w, h);
+ int scissor[4];
+ GPU_scissor_get_i(scissor);
+ GPU_scissor(rect->xmin, rect->ymin, w, h);
#endif
- glEnable(GL_BLEND);
- glColor4f(0.0, 0.0, 0.0, 0.0);
+ GPU_blend(true);
if (w != ibuf->x || h != ibuf->y) {
- float facx = (float)w / (float)ibuf->x;
- float facy = (float)h / (float)ibuf->y;
- glPixelZoom(facx, facy);
+ facx = (float)w / (float)ibuf->x;
+ facy = (float)h / (float)ibuf->y;
}
- glaDrawPixelsAuto((float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, ibuf->rect);
- glPixelZoom(1.0f, 1.0f);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(
+ &state, (float)rect->xmin, (float)rect->ymin, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, ibuf->rect,
+ facx, facy, NULL);
- glDisable(GL_BLEND);
+ GPU_blend(false);
#if 0
// restore scissortest
- glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
#endif
#endif
@@ -455,43 +683,34 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
/**
* Draw title and text safe areas.
*
- * The first 4 parameters are the offsets for the view, not the zones.
+ * \Note This functionn is to be used with the 2D dashed shader enabled.
+ *
+ * \param pos is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attrib
+ * \param line_origin is a PRIM_FLOAT, 2, GPU_FETCH_FLOAT vertex attrib
+ *
+ * The next 4 parameters are the offsets for the view, not the zones.
*/
void UI_draw_safe_areas(
- float x1, float x2, float y1, float y2,
+ uint pos, float x1, float x2, float y1, float y2,
const float title_aspect[2], const float action_aspect[2])
{
const float size_x_half = (x2 - x1) * 0.5f;
const float size_y_half = (y2 - y1) * 0.5f;
const float *safe_areas[] = {title_aspect, action_aspect};
- int safe_len = ARRAY_SIZE(safe_areas);
- bool is_first = true;
+ const int safe_len = ARRAY_SIZE(safe_areas);
for (int i = 0; i < safe_len; i++) {
if (safe_areas[i][0] || safe_areas[i][1]) {
- float margin_x, margin_y;
- float minx, miny, maxx, maxy;
+ float margin_x = safe_areas[i][0] * size_x_half;
+ float margin_y = safe_areas[i][1] * size_y_half;
- if (is_first) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0);
- is_first = false;
- }
-
- margin_x = safe_areas[i][0] * size_x_half;
- margin_y = safe_areas[i][1] * size_y_half;
+ float minx = x1 + margin_x;
+ float miny = y1 + margin_y;
+ float maxx = x2 - margin_x;
+ float maxy = y2 - margin_y;
- minx = x1 + margin_x;
- miny = y1 + margin_y;
- maxx = x2 - margin_x;
- maxy = y2 - margin_y;
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(maxx, miny);
- glVertex2f(maxx, maxy);
- glVertex2f(minx, maxy);
- glVertex2f(minx, miny);
- glEnd();
+ imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
}
}
}
@@ -500,65 +719,73 @@ void UI_draw_safe_areas(
static void draw_scope_end(const rctf *rect, GLint *scissor)
{
/* restore scissortest */
- glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* outline */
- glColor4f(0.f, 0.f, 0.f, 0.5f);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f);
+ float color[4] = {0.0f, 0.0f, 0.0f, 0.5f};
+ UI_draw_roundbox_4fv(false, rect->xmin - 1, rect->ymin, rect->xmax + 1, rect->ymax + 1, 3.0f, color);
}
static void histogram_draw_one(
float r, float g, float b, float alpha,
- float x, float y, float w, float h, const float *data, int res, const bool is_line)
+ float x, float y, float w, float h, const float *data, int res, const bool is_line,
+ unsigned int pos_attrib)
{
- glEnable(GL_LINE_SMOOTH);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glColor4f(r, g, b, alpha);
+ float color[4] = {r, g, b, alpha};
+
+ /* that can happen */
+ if (res == 0)
+ return;
+
+ GPU_line_smooth(true);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
+
+ immUniformColor4fv(color);
if (is_line) {
/* curve outline */
- glLineWidth(1.5);
+ GPU_line_width(1.5);
- glBegin(GL_LINE_STRIP);
+ immBegin(GPU_PRIM_LINE_STRIP, res);
for (int i = 0; i < res; i++) {
float x2 = x + i * (w / (float)res);
- glVertex2f(x2, y + (data[i] * h));
+ immVertex2f(pos_attrib, x2, y + (data[i] * h));
}
- glEnd();
+ immEnd();
}
else {
/* under the curve */
- glBegin(GL_TRIANGLE_STRIP);
- glVertex2f(x, y);
- glVertex2f(x, y + (data[0] * h));
+ immBegin(GPU_PRIM_TRI_STRIP, res * 2);
+ immVertex2f(pos_attrib, x, y);
+ immVertex2f(pos_attrib, x, y + (data[0] * h));
for (int i = 1; i < res; i++) {
float x2 = x + i * (w / (float)res);
- glVertex2f(x2, y + (data[i] * h));
- glVertex2f(x2, y);
+ immVertex2f(pos_attrib, x2, y + (data[i] * h));
+ immVertex2f(pos_attrib, x2, y);
}
- glEnd();
+ immEnd();
/* curve outline */
- glColor4f(0.f, 0.f, 0.f, 0.25f);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.25f);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glBegin(GL_LINE_STRIP);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ immBegin(GPU_PRIM_LINE_STRIP, res);
for (int i = 0; i < res; i++) {
float x2 = x + i * (w / (float)res);
- glVertex2f(x2, y + (data[i] * h));
+ immVertex2f(pos_attrib, x2, y + (data[i] * h));
}
- glEnd();
+ immEnd();
}
- glDisable(GL_LINE_SMOOTH);
+ GPU_line_smooth(false);
}
#define HISTOGRAM_TOT_GRID_LINES 4
-void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
+void ui_draw_but_HISTOGRAM(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
{
Histogram *hist = (Histogram *)but->poin;
int res = hist->x_resolution;
@@ -574,60 +801,95 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
float w = BLI_rctf_size_x(&rect);
float h = BLI_rctf_size_y(&rect) * hist->ymax;
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- UI_ThemeColor4(TH_PREVIEW_BACK);
+ float color[4];
+ UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
/* need scissor test, histogram can draw outside of boundary */
- GLint scissor[4];
- glGetIntegerv(GL_VIEWPORT, scissor);
- glScissor(ar->winrct.xmin + (rect.xmin - 1),
- ar->winrct.ymin + (rect.ymin - 1),
- (rect.xmax + 1) - (rect.xmin - 1),
- (rect.ymax + 1) - (rect.ymin - 1));
-
- glColor4f(1.f, 1.f, 1.f, 0.08f);
+ int scissor[4];
+ GPU_scissor_get_i(scissor);
+ GPU_scissor(
+ (rect.xmin - 1),
+ (rect.ymin - 1),
+ (rect.xmax + 1) - (rect.xmin - 1),
+ (rect.ymax + 1) - (rect.ymin - 1));
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
/* draw grid lines here */
for (int i = 1; i <= HISTOGRAM_TOT_GRID_LINES; i++) {
const float fac = (float)i / (float)HISTOGRAM_TOT_GRID_LINES;
/* so we can tell the 1.0 color point */
if (i == HISTOGRAM_TOT_GRID_LINES) {
- glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
}
- fdrawline(rect.xmin, rect.ymin + fac * h, rect.xmax, rect.ymin + fac * h);
- fdrawline(rect.xmin + fac * w, rect.ymin, rect.xmin + fac * w, rect.ymax);
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, rect.xmin, rect.ymin + fac * h);
+ immVertex2f(pos, rect.xmax, rect.ymin + fac * h);
+
+ immVertex2f(pos, rect.xmin + fac * w, rect.ymin);
+ immVertex2f(pos, rect.xmin + fac * w, rect.ymax);
+
+ immEnd();
}
if (hist->mode == HISTO_MODE_LUMA) {
- histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_luma, res, is_line);
+ histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_luma, res, is_line, pos);
}
else if (hist->mode == HISTO_MODE_ALPHA) {
- histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_a, res, is_line);
+ histogram_draw_one(1.0, 1.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_a, res, is_line, pos);
}
else {
if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_R)
- histogram_draw_one(1.0, 0.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_r, res, is_line);
+ histogram_draw_one(1.0, 0.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_r, res, is_line, pos);
if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_G)
- histogram_draw_one(0.0, 1.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_g, res, is_line);
+ histogram_draw_one(0.0, 1.0, 0.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_g, res, is_line, pos);
if (hist->mode == HISTO_MODE_RGB || hist->mode == HISTO_MODE_B)
- histogram_draw_one(0.0, 0.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_b, res, is_line);
+ histogram_draw_one(0.0, 0.0, 1.0, 0.75, rect.xmin, rect.ymin, w, h, hist->data_b, res, is_line, pos);
}
+ immUnbindProgram();
+
/* outline */
draw_scope_end(&rect, scissor);
}
#undef HISTOGRAM_TOT_GRID_LINES
-void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
+static void waveform_draw_one(float *waveform, int nbr, const float col[3])
+{
+ GPUVertFormat format = {0};
+ uint pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, nbr);
+
+ GPU_vertbuf_attr_fill(vbo, pos_id, waveform);
+
+ /* TODO store the GPUBatch inside the scope */
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4f(batch, "color", col[0], col[1], col[2], 1.0f);
+ GPU_batch_draw(batch);
+
+ GPU_batch_discard(batch);
+}
+
+void ui_draw_but_WAVEFORM(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
{
Scopes *scopes = (Scopes *)but->poin;
- GLint scissor[4];
+ int scissor[4];
float colors[3][3];
float colorsycc[3][3] = {{1, 0, 1}, {1, 1, 0}, {0, 1, 1}};
float colors_alpha[3][3], colorsycc_alpha[3][3]; /* colors pre multiplied by alpha for speed up */
@@ -646,7 +908,7 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
scopes->wavefrm_yfac = 0.98f;
float w = BLI_rctf_size_x(&rect) - 7;
float h = BLI_rctf_size_y(&rect) * scopes->wavefrm_yfac;
- float yofs = rect.ymin + (BLI_rctf_size_y(&rect) - h) / 2.0f;
+ float yofs = rect.ymin + (BLI_rctf_size_y(&rect) - h) * 0.5f;
float w3 = w / 3.0f;
/* log scale for alpha */
@@ -661,108 +923,141 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
}
}
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ /* Flush text cache before changing scissors. */
+ BLF_batch_draw_flush();
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- UI_ThemeColor4(TH_PREVIEW_BACK);
+ float color[4];
+ UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
/* need scissor test, waveform can draw outside of boundary */
- glGetIntegerv(GL_VIEWPORT, scissor);
- glScissor(ar->winrct.xmin + (rect.xmin - 1),
- ar->winrct.ymin + (rect.ymin - 1),
- (rect.xmax + 1) - (rect.xmin - 1),
- (rect.ymax + 1) - (rect.ymin - 1));
-
- glColor4f(1.f, 1.f, 1.f, 0.08f);
- /* draw grid lines here */
+ GPU_scissor_get_i(scissor);
+ GPU_scissor(
+ (rect.xmin - 1),
+ (rect.ymin - 1),
+ (rect.xmax + 1) - (rect.xmin - 1),
+ (rect.ymax + 1) - (rect.ymin - 1));
+
+ /* draw scale numbers first before binding any shader */
for (int i = 0; i < 6; i++) {
char str[4];
BLI_snprintf(str, sizeof(str), "%-3d", i * 20);
str[3] = '\0';
- fdrawline(rect.xmin + 22, yofs + (i / 5.f) * h, rect.xmax + 1, yofs + (i / 5.f) * h);
- BLF_draw_default(rect.xmin + 1, yofs - 5 + (i / 5.f) * h, 0, str, sizeof(str) - 1);
- /* in the loop because blf_draw reset it */
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ BLF_color4f(BLF_default(), 1.0f, 1.0f, 1.0f, 0.08f);
+ BLF_draw_default(rect.xmin + 1, yofs - 5 + (i * 0.2f) * h, 0, str, sizeof(str) - 1);
+ }
+
+ /* Flush text cache before drawing things on top. */
+ BLF_batch_draw_flush();
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
+
+ /* draw grid lines here */
+ immBegin(GPU_PRIM_LINES, 12);
+
+ for (int i = 0; i < 6; i++) {
+ immVertex2f(pos, rect.xmin + 22, yofs + (i * 0.2f) * h);
+ immVertex2f(pos, rect.xmax + 1, yofs + (i * 0.2f) * h);
}
+
+ immEnd();
+
/* 3 vertical separation */
if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA) {
+ immBegin(GPU_PRIM_LINES, 4);
+
for (int i = 1; i < 3; i++) {
- fdrawline(rect.xmin + i * w3, rect.ymin, rect.xmin + i * w3, rect.ymax);
+ immVertex2f(pos, rect.xmin + i * w3, rect.ymin);
+ immVertex2f(pos, rect.xmin + i * w3, rect.ymax);
}
+
+ immEnd();
}
/* separate min max zone on the right */
- fdrawline(rect.xmin + w, rect.ymin, rect.xmin + w, rect.ymax);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, rect.xmin + w, rect.ymin);
+ immVertex2f(pos, rect.xmin + w, rect.ymax);
+ immEnd();
+
/* 16-235-240 level in case of ITU-R BT601/709 */
- glColor4f(1.f, 0.4f, 0.f, 0.2f);
+ immUniformColor4f(1.0f, 0.4f, 0.0f, 0.2f);
if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_YCC_601, SCOPES_WAVEFRM_YCC_709)) {
- fdrawline(rect.xmin + 22, yofs + h * 16.0f / 255.0f, rect.xmax + 1, yofs + h * 16.0f / 255.0f);
- fdrawline(rect.xmin + 22, yofs + h * 235.0f / 255.0f, rect.xmin + w3, yofs + h * 235.0f / 255.0f);
- fdrawline(rect.xmin + 3 * w3, yofs + h * 235.0f / 255.0f, rect.xmax + 1, yofs + h * 235.0f / 255.0f);
- fdrawline(rect.xmin + w3, yofs + h * 240.0f / 255.0f, rect.xmax + 1, yofs + h * 240.0f / 255.0f);
+ immBegin(GPU_PRIM_LINES, 8);
+
+ immVertex2f(pos, rect.xmin + 22, yofs + h * 16.0f / 255.0f);
+ immVertex2f(pos, rect.xmax + 1, yofs + h * 16.0f / 255.0f);
+
+ immVertex2f(pos, rect.xmin + 22, yofs + h * 235.0f / 255.0f);
+ immVertex2f(pos, rect.xmin + w3, yofs + h * 235.0f / 255.0f);
+
+ immVertex2f(pos, rect.xmin + 3 * w3, yofs + h * 235.0f / 255.0f);
+ immVertex2f(pos, rect.xmax + 1, yofs + h * 235.0f / 255.0f);
+
+ immVertex2f(pos, rect.xmin + w3, yofs + h * 240.0f / 255.0f);
+ immVertex2f(pos, rect.xmax + 1, yofs + h * 240.0f / 255.0f);
+
+ immEnd();
}
/* 7.5 IRE black point level for NTSC */
- if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA)
- fdrawline(rect.xmin, yofs + h * 0.075f, rect.xmax + 1, yofs + h * 0.075f);
+ if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA) {
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, rect.xmin, yofs + h * 0.075f);
+ immVertex2f(pos, rect.xmax + 1, yofs + h * 0.075f);
+ immEnd();
+ }
if (scopes->ok && scopes->waveform_1 != NULL) {
-
- /* LUMA (1 channel) */
glBlendFunc(GL_ONE, GL_ONE);
- glColor3f(alpha, alpha, alpha);
- glPointSize(1.0);
+ GPU_point_size(1.0);
+ /* LUMA (1 channel) */
if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA) {
+ float col[3] = {alpha, alpha, alpha};
- glBlendFunc(GL_ONE, GL_ONE);
-
- glPushMatrix();
- glEnableClientState(GL_VERTEX_ARRAY);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(rect.xmin, yofs);
+ GPU_matrix_scale_2f(w, h);
- glTranslatef(rect.xmin, yofs, 0.f);
- glScalef(w, h, 0.f);
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+ waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, col);
- glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ GPU_matrix_pop();
/* min max */
- glColor3f(0.5f, 0.5f, 0.5f);
+ immUniformColor3f(0.5f, 0.5f, 0.5f);
min = yofs + scopes->minmax[0][0] * h;
max = yofs + scopes->minmax[0][1] * h;
CLAMP(min, rect.ymin, rect.ymax);
CLAMP(max, rect.ymin, rect.ymax);
- fdrawline(rect.xmax - 3, min, rect.xmax - 3, max);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, rect.xmax - 3, min);
+ immVertex2f(pos, rect.xmax - 3, max);
+ immEnd();
}
/* RGB (3 channel) */
else if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) {
- glBlendFunc(GL_ONE, GL_ONE);
-
- glEnableClientState(GL_VERTEX_ARRAY);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(rect.xmin, yofs);
+ GPU_matrix_scale_2f(w, h);
- glPushMatrix();
+ waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, colors_alpha[0]);
+ waveform_draw_one(scopes->waveform_2, scopes->waveform_tot, colors_alpha[1]);
+ waveform_draw_one(scopes->waveform_3, scopes->waveform_tot, colors_alpha[2]);
- glTranslatef(rect.xmin, yofs, 0.f);
- glScalef(w, h, 0.f);
-
- glColor3fv( colors_alpha[0] );
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
- glColor3fv( colors_alpha[1] );
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
- glColor3fv( colors_alpha[2] );
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ GPU_matrix_pop();
}
/* PARADE / YCC (3 channels) */
else if (ELEM(scopes->wavefrm_mode,
@@ -774,49 +1069,47 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
{
int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB_PARADE);
- glBlendFunc(GL_ONE, GL_ONE);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(rect.xmin, yofs);
+ GPU_matrix_scale_2f(w3, h);
- glPushMatrix();
- glEnableClientState(GL_VERTEX_ARRAY);
+ waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, (rgb) ? colors_alpha[0] : colorsycc_alpha[0]);
- glTranslatef(rect.xmin, yofs, 0.f);
- glScalef(w3, h, 0.f);
+ GPU_matrix_translate_2f(1.0f, 0.0f);
+ waveform_draw_one(scopes->waveform_2, scopes->waveform_tot, (rgb) ? colors_alpha[1] : colorsycc_alpha[1]);
- glColor3fv((rgb) ? colors_alpha[0] : colorsycc_alpha[0]);
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+ GPU_matrix_translate_2f(1.0f, 0.0f);
+ waveform_draw_one(scopes->waveform_3, scopes->waveform_tot, (rgb) ? colors_alpha[2] : colorsycc_alpha[2]);
- glTranslatef(1.f, 0.f, 0.f);
- glColor3fv((rgb) ? colors_alpha[1] : colorsycc_alpha[1]);
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
- glTranslatef(1.f, 0.f, 0.f);
- glColor3fv((rgb) ? colors_alpha[2] : colorsycc_alpha[2]);
- glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ GPU_matrix_pop();
}
+
/* min max */
if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA ) {
for (int c = 0; c < 3; c++) {
if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_RGB))
- glColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f);
+ immUniformColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f);
else
- glColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f);
+ immUniformColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f);
min = yofs + scopes->minmax[c][0] * h;
max = yofs + scopes->minmax[c][1] * h;
CLAMP(min, rect.ymin, rect.ymax);
CLAMP(max, rect.ymin, rect.ymax);
- fdrawline(rect.xmin + w + 2 + c * 2, min, rect.xmin + w + 2 + c * 2, max);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, rect.xmin + w + 2 + c * 2, min);
+ immVertex2f(pos, rect.xmin + w + 2 + c * 2, max);
+ immEnd();
}
}
}
+ immUnbindProgram();
+
/* outline */
draw_scope_end(&rect, scissor);
+
+ GPU_blend(false);
}
static float polar_to_x(float center, float diam, float ampli, float angle)
@@ -829,10 +1122,10 @@ static float polar_to_y(float center, float diam, float ampli, float angle)
return center + diam * ampli * sinf(angle);
}
-static void vectorscope_draw_target(float centerx, float centery, float diam, const float colf[3])
+static void vectorscope_draw_target(unsigned int pos, float centerx, float centery, float diam, const float colf[3])
{
float y, u, v;
- float tangle = 0.f, tampli;
+ float tangle = 0.0f, tampli;
float dangle, dampli, dangle2, dampli2;
rgb_to_yuv(colf[0], colf[1], colf[2], &y, &u, &v, BLI_YUV_ITU_BT709);
@@ -844,44 +1137,44 @@ static void vectorscope_draw_target(float centerx, float centery, float diam, co
tampli = sqrtf(u * u + v * v);
/* small target vary by 2.5 degree and 2.5 IRE unit */
- glColor4f(1.0f, 1.0f, 1.0, 0.12f);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.12f);
dangle = DEG2RADF(2.5f);
dampli = 2.5f / 200.0f;
- glBegin(GL_LINE_LOOP);
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
- glEnd();
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
+ immEnd();
/* big target vary by 10 degree and 20% amplitude */
- glColor4f(1.0f, 1.0f, 1.0, 0.12f);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.12f);
dangle = DEG2RADF(10.0f);
dampli = 0.2f * tampli;
dangle2 = DEG2RADF(5.0f);
dampli2 = 0.5f * dampli;
- glBegin(GL_LINE_STRIP);
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle + dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle + dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli + dampli, tangle + dangle - dangle2));
- glEnd();
- glBegin(GL_LINE_STRIP);
- glVertex2f(polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle + dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle + dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli - dampli, tangle + dangle - dangle2));
- glEnd();
- glBegin(GL_LINE_STRIP);
- glVertex2f(polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle - dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle - dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli - dampli, tangle - dangle + dangle2));
- glEnd();
- glBegin(GL_LINE_STRIP);
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle - dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle - dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli + dampli, tangle - dangle + dangle2));
- glEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle + dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle + dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli + dampli, tangle + dangle - dangle2));
+ immEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle + dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle + dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle + dangle - dangle2), polar_to_y(centery, diam, tampli - dampli, tangle + dangle - dangle2));
+ immEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli + dampli2, tangle - dangle), polar_to_y(centery, diam, tampli - dampli + dampli2, tangle - dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli - dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli - dampli, tangle - dangle + dangle2));
+ immEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli - dampli2, tangle - dangle), polar_to_y(centery, diam, tampli + dampli - dampli2, tangle - dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
+ immVertex2f(pos, polar_to_x(centerx, diam, tampli + dampli, tangle - dangle + dangle2), polar_to_y(centery, diam, tampli + dampli, tangle - dangle + dangle2));
+ immEnd();
}
-void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
+void ui_draw_but_VECTORSCOPE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
{
const float skin_rad = DEG2RADF(123.0f); /* angle in radians of the skin tone line */
Scopes *scopes = (Scopes *)but->poin;
@@ -899,114 +1192,132 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
float w = BLI_rctf_size_x(&rect);
float h = BLI_rctf_size_y(&rect);
- float centerx = rect.xmin + w / 2;
- float centery = rect.ymin + h / 2;
+ float centerx = rect.xmin + w * 0.5f;
+ float centery = rect.ymin + h * 0.5f;
float diam = (w < h) ? w : h;
float alpha = scopes->vecscope_alpha * scopes->vecscope_alpha * scopes->vecscope_alpha;
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- UI_ThemeColor4(TH_PREVIEW_BACK);
+ float color[4];
+ UI_GetThemeColor4fv(TH_PREVIEW_BACK, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
/* need scissor test, hvectorscope can draw outside of boundary */
- GLint scissor[4];
- glGetIntegerv(GL_VIEWPORT, scissor);
- glScissor(ar->winrct.xmin + (rect.xmin - 1),
- ar->winrct.ymin + (rect.ymin - 1),
- (rect.xmax + 1) - (rect.xmin - 1),
- (rect.ymax + 1) - (rect.ymin - 1));
-
- glColor4f(1.f, 1.f, 1.f, 0.08f);
+ int scissor[4];
+ GPU_scissor_get_i(scissor);
+ GPU_scissor(
+ (rect.xmin - 1),
+ (rect.ymin - 1),
+ (rect.xmax + 1) - (rect.xmin - 1),
+ (rect.ymax + 1) - (rect.ymin - 1));
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.08f);
/* draw grid elements */
/* cross */
- fdrawline(centerx - (diam / 2) - 5, centery, centerx + (diam / 2) + 5, centery);
- fdrawline(centerx, centery - (diam / 2) - 5, centerx, centery + (diam / 2) + 5);
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, centerx - (diam * 0.5f) - 5, centery);
+ immVertex2f(pos, centerx + (diam * 0.5f) + 5, centery);
+
+ immVertex2f(pos, centerx, centery - (diam * 0.5f) - 5);
+ immVertex2f(pos, centerx, centery + (diam * 0.5f) + 5);
+
+ immEnd();
+
/* circles */
for (int j = 0; j < 5; j++) {
- glBegin(GL_LINE_LOOP);
const int increment = 15;
+ immBegin(GPU_PRIM_LINE_LOOP, (int)(360 / increment));
for (int i = 0; i <= 360 - increment; i += increment) {
const float a = DEG2RADF((float)i);
- const float r = (j + 1) / 10.0f;
- glVertex2f(polar_to_x(centerx, diam, r, a), polar_to_y(centery, diam, r, a));
+ const float r = (j + 1) * 0.1f;
+ immVertex2f(pos, polar_to_x(centerx, diam, r, a), polar_to_y(centery, diam, r, a));
}
- glEnd();
+ immEnd();
}
/* skin tone line */
- glColor4f(1.f, 0.4f, 0.f, 0.2f);
- fdrawline(polar_to_x(centerx, diam, 0.5f, skin_rad), polar_to_y(centery, diam, 0.5, skin_rad),
- polar_to_x(centerx, diam, 0.1f, skin_rad), polar_to_y(centery, diam, 0.1, skin_rad));
+ immUniformColor4f(1.0f, 0.4f, 0.0f, 0.2f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, polar_to_x(centerx, diam, 0.5f, skin_rad), polar_to_y(centery, diam, 0.5f, skin_rad));
+ immVertex2f(pos, polar_to_x(centerx, diam, 0.1f, skin_rad), polar_to_y(centery, diam, 0.1f, skin_rad));
+ immEnd();
+
/* saturation points */
for (int i = 0; i < 6; i++)
- vectorscope_draw_target(centerx, centery, diam, colors[i]);
+ vectorscope_draw_target(pos, centerx, centery, diam, colors[i]);
if (scopes->ok && scopes->vecscope != NULL) {
/* pixel point cloud */
- glBlendFunc(GL_ONE, GL_ONE);
- glColor3f(alpha, alpha, alpha);
+ float col[3] = {alpha, alpha, alpha};
- glPushMatrix();
- glEnableClientState(GL_VERTEX_ARRAY);
+ glBlendFunc(GL_ONE, GL_ONE);
+ GPU_point_size(1.0);
- glTranslatef(centerx, centery, 0.f);
- glScalef(diam, diam, 0.f);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(centerx, centery);
+ GPU_matrix_scale_1f(diam);
- glVertexPointer(2, GL_FLOAT, 0, scopes->vecscope);
- glPointSize(1.0);
- glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+ waveform_draw_one(scopes->vecscope, scopes->waveform_tot, col);
- glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ GPU_matrix_pop();
}
+ immUnbindProgram();
+
/* outline */
draw_scope_end(&rect, scissor);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
-static void ui_draw_colorband_handle_tri_hlight(float x1, float y1, float halfwidth, float height)
+static void ui_draw_colorband_handle_tri_hlight(unsigned int pos, float x1, float y1, float halfwidth, float height)
{
- glEnable(GL_LINE_SMOOTH);
+ GPU_line_smooth(true);
- glBegin(GL_LINE_STRIP);
- glVertex2f(x1 + halfwidth, y1);
- glVertex2f(x1, y1 + height);
- glVertex2f(x1 - halfwidth, y1);
- glEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, x1 + halfwidth, y1);
+ immVertex2f(pos, x1, y1 + height);
+ immVertex2f(pos, x1 - halfwidth, y1);
+ immEnd();
- glDisable(GL_LINE_SMOOTH);
+ GPU_line_smooth(false);
}
-static void ui_draw_colorband_handle_tri(float x1, float y1, float halfwidth, float height, bool fill)
+static void ui_draw_colorband_handle_tri(unsigned int pos, float x1, float y1, float halfwidth, float height, bool fill)
{
glEnable(fill ? GL_POLYGON_SMOOTH : GL_LINE_SMOOTH);
- glBegin(fill ? GL_TRIANGLES : GL_LINE_LOOP);
- glVertex2f(x1 + halfwidth, y1);
- glVertex2f(x1, y1 + height);
- glVertex2f(x1 - halfwidth, y1);
- glEnd();
+ immBegin(fill ? GPU_PRIM_TRIS : GPU_PRIM_LINE_LOOP, 3);
+ immVertex2f(pos, x1 + halfwidth, y1);
+ immVertex2f(pos, x1, y1 + height);
+ immVertex2f(pos, x1 - halfwidth, y1);
+ immEnd();
glDisable(fill ? GL_POLYGON_SMOOTH : GL_LINE_SMOOTH);
}
-static void ui_draw_colorband_handle_box(float x1, float y1, float x2, float y2, bool fill)
+static void ui_draw_colorband_handle_box(unsigned int pos, float x1, float y1, float x2, float y2, bool fill)
{
- glBegin(fill ? GL_QUADS : GL_LINE_LOOP);
- glVertex2f(x1, y1);
- glVertex2f(x1, y2);
- glVertex2f(x2, y2);
- glVertex2f(x2, y1);
- glEnd();
+ immBegin(fill ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x2, y1);
+ immEnd();
}
static void ui_draw_colorband_handle(
- const rcti *rect, float x,
+ uint shdr_pos, const rcti *rect, float x,
const float rgb[3], struct ColorManagedDisplay *display,
bool active)
{
@@ -1025,18 +1336,26 @@ static void ui_draw_colorband_handle(
y1 = floorf(y1 + 0.5f);
if (active || half_width < min_width) {
- glBegin(GL_LINES);
- glColor3ub(0, 0, 0);
- glVertex2f(x, y1);
- glVertex2f(x, y2);
- glEnd();
- setlinestyle(active ? 2 : 1);
- glBegin(GL_LINES);
- glColor3ub(200, 200, 200);
- glVertex2f(x, y1);
- glVertex2f(x, y2);
- glEnd();
- setlinestyle(0);
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.8f, 0.8f, 0.8f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", active ? 4.0f : 2.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(shdr_pos, x, y1);
+ immVertex2f(shdr_pos, x, y2);
+ immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* hide handles when zoomed out too far */
if (half_width < min_width) {
@@ -1047,45 +1366,46 @@ static void ui_draw_colorband_handle(
/* shift handle down */
y1 -= half_width;
- glColor3ub(0, 0, 0);
- ui_draw_colorband_handle_box(x - half_width, y1 - 1, x + half_width, y1 + height, false);
+ immUniformColor3ub(0, 0, 0);
+ ui_draw_colorband_handle_box(shdr_pos, x - half_width, y1 - 1, x + half_width, y1 + height, false);
/* draw all triangles blended */
- glEnable(GL_BLEND);
+ GPU_blend(true);
- ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true);
+ ui_draw_colorband_handle_tri(shdr_pos, x, y1 + height, half_width, half_width, true);
if (active)
- glColor3ub(196, 196, 196);
+ immUniformColor3ub(196, 196, 196);
else
- glColor3ub(96, 96, 96);
- ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true);
+ immUniformColor3ub(96, 96, 96);
+ ui_draw_colorband_handle_tri(shdr_pos, x, y1 + height, half_width, half_width, true);
if (active)
- glColor3ub(255, 255, 255);
+ immUniformColor3ub(255, 255, 255);
else
- glColor3ub(128, 128, 128);
- ui_draw_colorband_handle_tri_hlight(x, y1 + height - 1, (half_width - 1), (half_width - 1));
+ immUniformColor3ub(128, 128, 128);
+ ui_draw_colorband_handle_tri_hlight(shdr_pos, x, y1 + height - 1, (half_width - 1), (half_width - 1));
- glColor3ub(0, 0, 0);
- ui_draw_colorband_handle_tri_hlight(x, y1 + height, half_width, half_width);
+ immUniformColor3ub(0, 0, 0);
+ ui_draw_colorband_handle_tri_hlight(shdr_pos, x, y1 + height, half_width, half_width);
- glDisable(GL_BLEND);
+ GPU_blend(false);
- glColor3ub(128, 128, 128);
- ui_draw_colorband_handle_box(x - (half_width - 1), y1, x + (half_width - 1), y1 + height, true);
+ immUniformColor3ub(128, 128, 128);
+ ui_draw_colorband_handle_box(shdr_pos, x - (half_width - 1), y1, x + (half_width - 1), y1 + height, true);
if (display) {
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
}
- glColor3fv(colf);
- ui_draw_colorband_handle_box(x - (half_width - 2), y1 + 1, x + (half_width - 2), y1 + height - 2, true);
+ immUniformColor3fv(colf);
+ ui_draw_colorband_handle_box(shdr_pos, x - (half_width - 2), y1 + 1, x + (half_width - 2), y1 + height - 2, true);
}
void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect)
{
struct ColorManagedDisplay *display = NULL;
+ uint pos_id, col_id;
ColorBand *coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin);
if (coba == NULL) return;
@@ -1096,23 +1416,28 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
float x1 = rect->xmin;
float sizex = rect->xmax - x1;
float sizey = BLI_rcti_size_y(rect);
- float sizey_solid = sizey / 4;
+ float sizey_solid = sizey * 0.25f;
float y1 = rect->ymin;
- /* Drawing the checkerboard.
- * This could be optimized with a single checkerboard shader,
- * instead of drawing twice and using stippling the second time. */
- /* layer: background, to show tranparency */
- glColor4ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, 255);
- glRectf(x1, y1, x1 + sizex, rect->ymax);
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX);
- glRectf(x1, y1, x1 + sizex, rect->ymax);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ GPUVertFormat *format = immVertexFormat();
+ pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
+
+ /* Drawing the checkerboard. */
+ immUniform4f("color1", UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_DARK / 255.0f, 1.0f);
+ immUniform4f("color2", UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 1.0f);
+ immUniform1i("size", 8);
+ immRectf(pos_id, x1, y1, x1 + sizex, rect->ymax);
+ immUnbindProgram();
+
+ /* New format */
+ format = immVertexFormat();
+ pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
/* layer: color ramp */
- glEnable(GL_BLEND);
+ GPU_blend(true);
CBData *cbd = coba->data;
@@ -1122,7 +1447,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
v1[1] = y1 + sizey_solid;
v2[1] = rect->ymax;
- glBegin(GL_TRIANGLE_STRIP);
+ immBegin(GPU_PRIM_TRI_STRIP, (sizex + 1) * 2);
for (int a = 0; a <= sizex; a++) {
float pos = ((float)a) / sizex;
BKE_colorband_evaluate(coba, pos, colf);
@@ -1131,17 +1456,17 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
v1[0] = v2[0] = x1 + a;
- glColor4fv(colf);
- glVertex2fv(v1);
- glVertex2fv(v2);
+ immAttr4fv(col_id, colf);
+ immVertex2fv(pos_id, v1);
+ immVertex2fv(pos_id, v2);
}
- glEnd();
+ immEnd();
/* layer: color ramp without alpha for reference when manipulating ramp properties */
v1[1] = y1;
v2[1] = y1 + sizey_solid;
- glBegin(GL_TRIANGLE_STRIP);
+ immBegin(GPU_PRIM_TRI_STRIP, (sizex + 1) * 2);
for (int a = 0; a <= sizex; a++) {
float pos = ((float)a) / sizex;
BKE_colorband_evaluate(coba, pos, colf);
@@ -1150,31 +1475,48 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
v1[0] = v2[0] = x1 + a;
- glColor4f(colf[0], colf[1], colf[2], 1.0f);
- glVertex2fv(v1);
- glVertex2fv(v2);
+ immAttr4f(col_id, colf[0], colf[1], colf[2], 1.0f);
+ immVertex2fv(pos_id, v1);
+ immVertex2fv(pos_id, v2);
}
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
- glDisable(GL_BLEND);
+ GPU_blend(false);
+
+ /* New format */
+ format = immVertexFormat();
+ pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* layer: box outline */
- glColor4f(0.0, 0.0, 0.0, 1.0);
- fdrawbox(x1, y1, x1 + sizex, rect->ymax);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 1.0f);
+ imm_draw_box_wire_2d(pos_id, x1, y1, x1 + sizex, rect->ymax);
/* layer: box outline */
- glEnable(GL_BLEND);
- glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
- fdrawline(x1, y1, x1 + sizex, y1);
- glColor4f(1.0f, 1.0f, 1.0f, 0.25f);
- fdrawline(x1, y1 - 1, x1 + sizex, y1 - 1);
- glDisable(GL_BLEND);
+ GPU_blend(true);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos_id, x1, y1);
+ immVertex2f(pos_id, x1 + sizex, y1);
+ immEnd();
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.25f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos_id, x1, y1 - 1);
+ immVertex2f(pos_id, x1 + sizex, y1 - 1);
+ immEnd();
+
+ GPU_blend(false);
/* layer: draw handles */
for (int a = 0; a < coba->tot; a++, cbd++) {
if (a != coba->cur) {
float pos = x1 + cbd->pos * (sizex - 1) + 1;
- ui_draw_colorband_handle(rect, pos, &cbd->r, display, false);
+ ui_draw_colorband_handle(pos_id, rect, pos, &cbd->r, display, false);
}
}
@@ -1182,117 +1524,102 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
if (coba->tot != 0) {
cbd = &coba->data[coba->cur];
float pos = x1 + cbd->pos * (sizex - 1) + 1;
- ui_draw_colorband_handle(rect, pos, &cbd->r, display, true);
+ ui_draw_colorband_handle(pos_id, rect, pos, &cbd->r, display, true);
}
+
+ immUnbindProgram();
}
void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
{
- static GLuint displist = 0;
+ /* sphere color */
float diffuse[3] = {1.0f, 1.0f, 1.0f};
+ float light[3];
float size;
/* backdrop */
- glColor3ubv((unsigned char *)wcol->inner);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_POLYGON, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f);
+ UI_draw_roundbox_3ubAlpha(true, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f, (unsigned char *)wcol->inner, 255);
- /* sphere color */
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
/* setup lights */
- GPULightData light = {0};
- light.type = GPU_LIGHT_SUN;
- copy_v3_v3(light.diffuse, diffuse);
- zero_v3(light.specular);
- ui_but_v3_get(but, light.direction);
-
- GPU_basic_shader_light_set(0, &light);
- for (int a = 1; a < 8; a++)
- GPU_basic_shader_light_set(a, NULL);
-
- /* setup shader */
- GPU_basic_shader_colors(diffuse, NULL, 0, 1.0f);
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING);
+ ui_but_v3_get(but, light);
/* transform to button */
- glPushMatrix();
- glTranslatef(rect->xmin + 0.5f * BLI_rcti_size_x(rect), rect->ymin + 0.5f * BLI_rcti_size_y(rect), 0.0f);
+ GPU_matrix_push();
if (BLI_rcti_size_x(rect) < BLI_rcti_size_y(rect))
- size = BLI_rcti_size_x(rect) / 200.f;
+ size = 0.5f * BLI_rcti_size_x(rect);
else
- size = BLI_rcti_size_y(rect) / 200.f;
-
- glScalef(size, size, MIN2(size, 1.0f));
-
- if (displist == 0) {
- GLUquadricObj *qobj;
+ size = 0.5f * BLI_rcti_size_y(rect);
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
+ GPU_matrix_translate_2f(rect->xmin + 0.5f * BLI_rcti_size_x(rect), rect->ymin + 0.5f * BLI_rcti_size_y(rect));
+ GPU_matrix_scale_1f(size);
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
- GPU_basic_shader_bind(GPU_basic_shader_bound_options());
- gluSphere(qobj, 100.0, 32, 24);
- gluDeleteQuadric(qobj);
-
- glEndList();
- }
-
- glCallList(displist);
+ GPUBatch *sphere = GPU_batch_preset_sphere(2);
+ GPU_batch_program_set_builtin(sphere, GPU_SHADER_SIMPLE_LIGHTING);
+ GPU_batch_uniform_4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f);
+ GPU_batch_uniform_3fv(sphere, "light", light);
+ GPU_batch_draw(sphere);
/* restore */
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- GPU_default_lights();
glDisable(GL_CULL_FACE);
/* AA circle */
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
- glColor3ubv((unsigned char *)wcol->inner);
- glutil_draw_lined_arc(0.0f, M_PI * 2.0, 100.0f, 32);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ubv((unsigned char *)wcol->inner);
+
+ GPU_blend(true);
+ GPU_line_smooth(true);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, 1.0f, 32);
+ GPU_blend(false);
+ GPU_line_smooth(false);
/* matrix after circle */
- glPopMatrix();
+ GPU_matrix_pop();
- /* We disabled all blender lights above, so restore them here. */
- GPU_default_lights();
+ immUnbindProgram();
}
-static void ui_draw_but_curve_grid(const rcti *rect, float zoomx, float zoomy, float offsx, float offsy, float step)
+static void ui_draw_but_curve_grid(unsigned int pos, const rcti *rect, float zoomx, float zoomy, float offsx, float offsy, float step)
{
- glBegin(GL_LINES);
float dx = step * zoomx;
float fx = rect->xmin + zoomx * (-offsx);
if (fx > rect->xmin) fx -= dx * (floorf(fx - rect->xmin));
- while (fx < rect->xmax) {
- glVertex2f(fx, rect->ymin);
- glVertex2f(fx, rect->ymax);
- fx += dx;
- }
float dy = step * zoomy;
float fy = rect->ymin + zoomy * (-offsy);
if (fy > rect->ymin) fy -= dy * (floorf(fy - rect->ymin));
+
+ float line_count = (
+ floorf((rect->xmax - fx) / dx) + 1.0f +
+ floorf((rect->ymax - fy) / dy) + 1.0f);
+
+ immBegin(GPU_PRIM_LINES, (int)line_count * 2);
+ while (fx < rect->xmax) {
+ immVertex2f(pos, fx, rect->ymin);
+ immVertex2f(pos, fx, rect->ymax);
+ fx += dx;
+ }
while (fy < rect->ymax) {
- glVertex2f(rect->xmin, fy);
- glVertex2f(rect->xmax, fy);
+ immVertex2f(pos, rect->xmin, fy);
+ immVertex2f(pos, rect->xmax, fy);
fy += dy;
}
- glEnd();
+ immEnd();
}
static void gl_shaded_color(unsigned char *col, int shade)
{
- glColor3ub(col[0] - shade > 0 ? col[0] - shade : 0,
- col[1] - shade > 0 ? col[1] - shade : 0,
- col[2] - shade > 0 ? col[2] - shade : 0);
+ immUniformColor3ub(
+ col[0] - shade > 0 ? col[0] - shade : 0,
+ col[1] - shade > 0 ? col[1] - shade : 0,
+ col[2] - shade > 0 ? col[2] - shade : 0);
}
void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti *rect)
@@ -1309,19 +1636,21 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
CurveMap *cuma = &cumap->cm[cumap->cur];
/* need scissor test, curve can draw outside of boundary */
- GLint scissor[4];
- glGetIntegerv(GL_VIEWPORT, scissor);
+ int scissor[4];
+ GPU_scissor_get_i(scissor);
rcti scissor_new = {
- .xmin = ar->winrct.xmin + rect->xmin,
- .ymin = ar->winrct.ymin + rect->ymin,
- .xmax = ar->winrct.xmin + rect->xmax,
- .ymax = ar->winrct.ymin + rect->ymax
+ .xmin = rect->xmin,
+ .ymin = rect->ymin,
+ .xmax = rect->xmax,
+ .ymax = rect->ymax
};
- BLI_rcti_isect(&scissor_new, &ar->winrct, &scissor_new);
- glScissor(scissor_new.xmin,
- scissor_new.ymin,
- BLI_rcti_size_x(&scissor_new),
- BLI_rcti_size_y(&scissor_new));
+ rcti scissor_region = {0, ar->winx, 0, ar->winy};
+ BLI_rcti_isect(&scissor_new, &scissor_region, &scissor_new);
+ GPU_scissor(
+ scissor_new.xmin,
+ scissor_new.ymin,
+ BLI_rcti_size_x(&scissor_new),
+ BLI_rcti_size_y(&scissor_new));
/* calculate offset and zoom */
float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr);
@@ -1329,9 +1658,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
float offsx = cumap->curr.xmin - (1.0f / zoomx);
float offsy = cumap->curr.ymin - (1.0f / zoomy);
- glLineWidth(1.0f);
-
- /* backdrop */
+ /* Do this first to not mess imm context */
if (but->a1 == UI_GRAD_H) {
/* magic trigger for curve backgrounds */
float col[3] = {0.0f, 0.0f, 0.0f}; /* dummy arg */
@@ -1344,153 +1671,206 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
};
ui_draw_gradient(&grid, col, UI_GRAD_H, 1.0f);
+ }
+
+ GPU_line_width(1.0f);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* backdrop */
+ if (but->a1 == UI_GRAD_H) {
/* grid, hsv uses different grid */
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4ub(0, 0, 0, 48);
- ui_draw_but_curve_grid(rect, zoomx, zoomy, offsx, offsy, 0.1666666f);
- glDisable(GL_BLEND);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ immUniformColor4ub(0, 0, 0, 48);
+ ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.1666666f);
+ GPU_blend(false);
}
else {
if (cumap->flag & CUMA_DO_CLIP) {
gl_shaded_color((unsigned char *)wcol->inner, -20);
- glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glColor3ubv((unsigned char *)wcol->inner);
- glRectf(rect->xmin + zoomx * (cumap->clipr.xmin - offsx),
- rect->ymin + zoomy * (cumap->clipr.ymin - offsy),
- rect->xmin + zoomx * (cumap->clipr.xmax - offsx),
- rect->ymin + zoomy * (cumap->clipr.ymax - offsy));
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ immUniformColor3ubv((unsigned char *)wcol->inner);
+ immRectf(pos,
+ rect->xmin + zoomx * (cumap->clipr.xmin - offsx),
+ rect->ymin + zoomy * (cumap->clipr.ymin - offsy),
+ rect->xmin + zoomx * (cumap->clipr.xmax - offsx),
+ rect->ymin + zoomy * (cumap->clipr.ymax - offsy));
}
else {
- glColor3ubv((unsigned char *)wcol->inner);
- glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ immUniformColor3ubv((unsigned char *)wcol->inner);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
}
/* grid, every 0.25 step */
gl_shaded_color((unsigned char *)wcol->inner, -16);
- ui_draw_but_curve_grid(rect, zoomx, zoomy, offsx, offsy, 0.25f);
+ ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.25f);
/* grid, every 1.0 step */
gl_shaded_color((unsigned char *)wcol->inner, -24);
- ui_draw_but_curve_grid(rect, zoomx, zoomy, offsx, offsy, 1.0f);
+ ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 1.0f);
/* axes */
gl_shaded_color((unsigned char *)wcol->inner, -50);
- glBegin(GL_LINES);
- glVertex2f(rect->xmin, rect->ymin + zoomy * (-offsy));
- glVertex2f(rect->xmax, rect->ymin + zoomy * (-offsy));
- glVertex2f(rect->xmin + zoomx * (-offsx), rect->ymin);
- glVertex2f(rect->xmin + zoomx * (-offsx), rect->ymax);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, rect->xmin, rect->ymin + zoomy * (-offsy));
+ immVertex2f(pos, rect->xmax, rect->ymin + zoomy * (-offsy));
+ immVertex2f(pos, rect->xmin + zoomx * (-offsx), rect->ymin);
+ immVertex2f(pos, rect->xmin + zoomx * (-offsx), rect->ymax);
+ immEnd();
}
/* cfra option */
/* XXX 2.48 */
#if 0
if (cumap->flag & CUMA_DRAW_CFRA) {
- glColor3ub(0x60, 0xc0, 0x40);
- glBegin(GL_LINES);
- glVertex2f(rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymin);
- glVertex2f(rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymax);
- glEnd();
+ immUniformColor3ub(0x60, 0xc0, 0x40);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymin);
+ immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[0] - offsx), rect->ymax);
+ immEnd();
}
#endif
/* sample option */
if (cumap->flag & CUMA_DRAW_SAMPLE) {
- glBegin(GL_LINES); /* will draw one of the following 3 lines */
+ immBegin(GPU_PRIM_LINES, 2); /* will draw one of the following 3 lines */
if (but->a1 == UI_GRAD_H) {
float tsample[3];
float hsv[3];
linearrgb_to_srgb_v3_v3(tsample, cumap->sample);
rgb_to_hsv_v(tsample, hsv);
- glColor3ub(240, 240, 240);
+ immUniformColor3ub(240, 240, 240);
- glVertex2f(rect->xmin + zoomx * (hsv[0] - offsx), rect->ymin);
- glVertex2f(rect->xmin + zoomx * (hsv[0] - offsx), rect->ymax);
+ immVertex2f(pos, rect->xmin + zoomx * (hsv[0] - offsx), rect->ymin);
+ immVertex2f(pos, rect->xmin + zoomx * (hsv[0] - offsx), rect->ymax);
}
else if (cumap->cur == 3) {
float lum = IMB_colormanagement_get_luminance(cumap->sample);
- glColor3ub(240, 240, 240);
+ immUniformColor3ub(240, 240, 240);
- glVertex2f(rect->xmin + zoomx * (lum - offsx), rect->ymin);
- glVertex2f(rect->xmin + zoomx * (lum - offsx), rect->ymax);
+ immVertex2f(pos, rect->xmin + zoomx * (lum - offsx), rect->ymin);
+ immVertex2f(pos, rect->xmin + zoomx * (lum - offsx), rect->ymax);
}
else {
if (cumap->cur == 0)
- glColor3ub(240, 100, 100);
+ immUniformColor3ub(240, 100, 100);
else if (cumap->cur == 1)
- glColor3ub(100, 240, 100);
+ immUniformColor3ub(100, 240, 100);
else
- glColor3ub(100, 100, 240);
+ immUniformColor3ub(100, 100, 240);
- glVertex2f(rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymin);
- glVertex2f(rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymax);
+ immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymin);
+ immVertex2f(pos, rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymax);
}
- glEnd();
+ immEnd();
}
+ immUnbindProgram();
+
- /* the curve */
- glColor3ubv((unsigned char *)wcol->item);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glBegin(GL_LINE_STRIP);
if (cuma->table == NULL)
curvemapping_changed(cumap, false);
CurveMapPoint *cmp = cuma->table;
+ rctf line_range;
- /* first point */
+ /* First curve point. */
if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
- glVertex2f(rect->xmin, rect->ymin + zoomy * (cmp[0].y - offsy));
+ line_range.xmin = rect->xmin;
+ line_range.ymin = rect->ymin + zoomy * (cmp[0].y - offsy);
}
else {
- float fx = rect->xmin + zoomx * (cmp[0].x - offsx + cuma->ext_in[0]);
- float fy = rect->ymin + zoomy * (cmp[0].y - offsy + cuma->ext_in[1]);
- glVertex2f(fx, fy);
+ line_range.xmin = rect->xmin + zoomx * (cmp[0].x - offsx + cuma->ext_in[0]);
+ line_range.ymin = rect->ymin + zoomy * (cmp[0].y - offsy + cuma->ext_in[1]);
}
- for (int a = 0; a <= CM_TABLE; a++) {
- float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
- float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
- glVertex2f(fx, fy);
- }
- /* last point */
+ /* Last curve point. */
if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
- glVertex2f(rect->xmax, rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy));
+ line_range.xmax = rect->xmax;
+ line_range.ymax = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy);
}
else {
- float fx = rect->xmin + zoomx * (cmp[CM_TABLE].x - offsx - cuma->ext_out[0]);
- float fy = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy - cuma->ext_out[1]);
- glVertex2f(fx, fy);
+ line_range.xmax = rect->xmin + zoomx * (cmp[CM_TABLE].x - offsx - cuma->ext_out[0]);
+ line_range.ymax = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy - cuma->ext_out[1]);
+ }
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_blend(true);
+
+ /* Curve filled. */
+ immUniformColor3ubvAlpha((unsigned char *)wcol->item, 128);
+ GPU_polygon_smooth(true);
+ immBegin(GPU_PRIM_TRI_STRIP, (CM_TABLE * 2 + 2) + 4);
+ immVertex2f(pos, line_range.xmin, rect->ymin);
+ immVertex2f(pos, line_range.xmin, line_range.ymin);
+ for (int a = 0; a <= CM_TABLE; a++) {
+ float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
+ float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
+ immVertex2f(pos, fx, rect->ymin);
+ immVertex2f(pos, fx, fy);
+ }
+ immVertex2f(pos, line_range.xmax, rect->ymin);
+ immVertex2f(pos, line_range.xmax, rect->ymax);
+ immEnd();
+ GPU_polygon_smooth(false);
+
+ /* Curve line. */
+ GPU_line_width(1.0f);
+ immUniformColor3ubvAlpha((unsigned char *)wcol->item, 255);
+ GPU_line_smooth(true);
+ immBegin(GPU_PRIM_LINE_STRIP, (CM_TABLE + 1) + 2);
+ immVertex2f(pos, line_range.xmin, line_range.ymin);
+ for (int a = 0; a <= CM_TABLE; a++) {
+ float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
+ float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
+ immVertex2f(pos, fx, fy);
}
- glEnd();
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ immVertex2f(pos, line_range.xmax, line_range.ymax);
+ immEnd();
+
+ /* Reset state for fill & line. */
+ GPU_line_smooth(false);
+ GPU_blend(false);
+ immUnbindProgram();
+
+ /* The points, use aspect to make them visible on edges. */
+ format = immVertexFormat();
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- /* the points, use aspect to make them visible on edges */
cmp = cuma->curve;
- glPointSize(3.0f);
- glBegin(GL_POINTS);
+ GPU_point_size(max_ff(1.0f, min_ff(UI_DPI_FAC / but->block->aspect * 4.0f, 4.0f)));
+ immBegin(GPU_PRIM_POINTS, cuma->totpoint);
for (int a = 0; a < cuma->totpoint; a++) {
+ float color[4];
if (cmp[a].flag & CUMA_SELECT)
- UI_ThemeColor(TH_TEXT_HI);
+ UI_GetThemeColor4fv(TH_TEXT_HI, color);
else
- UI_ThemeColor(TH_TEXT);
+ UI_GetThemeColor4fv(TH_TEXT, color);
float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
- glVertex2f(fx, fy);
+ immAttr4fv(col, color);
+ immVertex2f(pos, fx, fy);
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
/* restore scissortest */
- glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
/* outline */
- glColor3ubv((unsigned char *)wcol->outline);
- fdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ format = immVertexFormat();
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3ubv((unsigned char *)wcol->outline);
+ imm_draw_box_wire_2d(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+
+ immUnbindProgram();
}
-void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
+void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
{
bool ok = false;
MovieClipScopes *scopes = (MovieClipScopes *)but->poin;
@@ -1505,21 +1885,22 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
int width = BLI_rctf_size_x(&rect) + 1;
int height = BLI_rctf_size_y(&rect);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* need scissor test, preview image can draw outside of boundary */
- GLint scissor[4];
- glGetIntegerv(GL_VIEWPORT, scissor);
- glScissor(ar->winrct.xmin + (rect.xmin - 1),
- ar->winrct.ymin + (rect.ymin - 1),
- (rect.xmax + 1) - (rect.xmin - 1),
- (rect.ymax + 1) - (rect.ymin - 1));
+ int scissor[4];
+ GPU_scissor_get_i(scissor);
+ GPU_scissor(
+ (rect.xmin - 1),
+ (rect.ymin - 1),
+ (rect.xmax + 1) - (rect.xmin - 1),
+ (rect.ymax + 1) - (rect.ymin - 1));
if (scopes->track_disabled) {
- glColor4f(0.7f, 0.3f, 0.3f, 0.3f);
+ float color[4] = {0.7f, 0.3f, 0.3f, 0.3f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
ok = true;
}
@@ -1547,69 +1928,79 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
}
if (!ok && scopes->track_preview) {
- glPushMatrix();
+ GPU_matrix_push();
/* draw content of pattern area */
- glScissor(ar->winrct.xmin + rect.xmin, ar->winrct.ymin + rect.ymin, scissor[2], scissor[3]);
+ GPU_scissor(rect.xmin, rect.ymin, scissor[2], scissor[3]);
if (width > 0 && height > 0) {
ImBuf *drawibuf = scopes->track_preview;
+ float col_sel[4], col_outline[4];
if (scopes->use_track_mask) {
- glColor4f(0.0f, 0.0f, 0.0f, 0.3f);
+ float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
}
- glaDrawPixelsSafe(
- rect.xmin, rect.ymin + 1, drawibuf->x, drawibuf->y,
- drawibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, drawibuf->rect);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(&state, rect.xmin, rect.ymin + 1, drawibuf->x, drawibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, drawibuf->rect, 1.0f, 1.0f, NULL);
/* draw cross for pixel position */
- glTranslatef(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1], 0.f);
- glScissor(ar->winrct.xmin + rect.xmin,
- ar->winrct.ymin + rect.ymin,
- BLI_rctf_size_x(&rect),
- BLI_rctf_size_y(&rect));
-
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
-
- for (int a = 0; a < 2; a++) {
- if (a == 1) {
- GPU_basic_shader_bind_enable(GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(3, 0xAAAA);
- UI_ThemeColor(TH_SEL_MARKER);
- }
- else {
- UI_ThemeColor(TH_MARKER_OUTLINE);
+ GPU_matrix_translate_2f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1]);
+ GPU_scissor(
+ rect.xmin,
+ rect.ymin,
+ BLI_rctf_size_x(&rect),
+ BLI_rctf_size_y(&rect));
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ UI_GetThemeColor4fv(TH_SEL_MARKER, col_sel);
+ UI_GetThemeColor4fv(TH_MARKER_OUTLINE, col_outline);
+
+ /* Do stipple cross with geometry */
+ immBegin(GPU_PRIM_LINES, 7 * 2 * 2);
+ float pos_sel[8] = {-10.0f, -7.0f, -4.0f, -1.0f, 2.0f, 5.0f, 8.0f, 11.0f};
+ for (int axe = 0; axe < 2; ++axe) {
+ for (int i = 0; i < 7; ++i) {
+ float x1 = pos_sel[i] * (1 - axe);
+ float y1 = pos_sel[i] * axe;
+ float x2 = pos_sel[i + 1] * (1 - axe);
+ float y2 = pos_sel[i + 1] * axe;
+
+ if (i % 2 == 1)
+ immAttr4fv(col, col_sel);
+ else
+ immAttr4fv(col, col_outline);
+
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y2);
}
-
- glBegin(GL_LINES);
- glVertex2f(-10.0f, 0.0f);
- glVertex2f(10.0f, 0.0f);
- glVertex2f(0.0f, -10.0f);
- glVertex2f(0.0f, 10.0f);
- glEnd();
}
+ immEnd();
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ immUnbindProgram();
}
- glPopMatrix();
+ GPU_matrix_pop();
ok = true;
}
if (!ok) {
- glColor4f(0.f, 0.f, 0.f, 0.3f);
+ float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
+ UI_draw_roundbox_4fv(true, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f, color);
}
/* outline */
draw_scope_end(&rect, scissor);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
@@ -1631,93 +2022,148 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol
0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
};
- GLint scissor[4];
+ int scissor[4];
/* need scissor test, can draw outside of boundary */
- glGetIntegerv(GL_VIEWPORT, scissor);
+ GPU_scissor_get_i(scissor);
rcti scissor_new = {
- .xmin = ar->winrct.xmin + recti->xmin,
- .ymin = ar->winrct.ymin + recti->ymin,
- .xmax = ar->winrct.xmin + recti->xmax,
- .ymax = ar->winrct.ymin + recti->ymax
+ .xmin = recti->xmin,
+ .ymin = recti->ymin,
+ .xmax = recti->xmax,
+ .ymax = recti->ymax
};
- BLI_rcti_isect(&scissor_new, &ar->winrct, &scissor_new);
- glScissor(scissor_new.xmin,
- scissor_new.ymin,
- BLI_rcti_size_x(&scissor_new),
- BLI_rcti_size_y(&scissor_new));
+ rcti scissor_region = {0, ar->winx, 0, ar->winy};
- glColor4ubv(but->col);
+ BLI_rcti_isect(&scissor_new, &scissor_region, &scissor_new);
+ GPU_scissor(
+ scissor_new.xmin,
+ scissor_new.ymin,
+ BLI_rcti_size_x(&scissor_new),
+ BLI_rcti_size_y(&scissor_new));
float x = 0.5f * (recti->xmin + recti->xmax);
float y = 0.5f * (recti->ymin + recti->ymax);
- glEnable(GL_BLEND);
- glBegin(GL_POLYGON);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(but->col);
+
+ GPU_blend(true);
+ immBegin(GPU_PRIM_TRI_FAN, 16);
for (int a = 0; a < 16; a++)
- glVertex2f(x + size * si[a], y + size * co[a]);
- glEnd();
+ immVertex2f(pos, x + size * si[a], y + size * co[a]);
+ immEnd();
- glColor4ub(0, 0, 0, 150);
- glLineWidth(1);
- glEnable(GL_LINE_SMOOTH);
- glBegin(GL_LINE_LOOP);
+ immUniformColor4ub(0, 0, 0, 150);
+ GPU_line_width(1);
+ GPU_line_smooth(true);
+ immBegin(GPU_PRIM_LINE_LOOP, 16);
for (int a = 0; a < 16; a++)
- glVertex2f(x + size * si[a], y + size * co[a]);
- glEnd();
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ immVertex2f(pos, x + size * si[a], y + size * co[a]);
+ immEnd();
+ GPU_line_smooth(false);
+ GPU_blend(false);
+
+ immUnbindProgram();
/* restore scissortest */
- glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
}
/* ****************************************************** */
+/* TODO: high quality UI drop shadows using GLSL shader and single draw call
+ * would replace / modify the following 3 functions - merwin
+ */
-static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha)
+static void ui_shadowbox(unsigned pos, unsigned color, float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha)
{
+ /**
+ * <pre>
+ * v1-_
+ * | -_v2
+ * | |
+ * | |
+ * | |
+ * v7_______v3____v4
+ * \ | /
+ * \ | _v5
+ * v8______v6_-
+ * </pre>
+ */
+ const float v1[2] = {maxx, maxy - 0.3f * shadsize};
+ const float v2[2] = {maxx + shadsize, maxy - 0.75f * shadsize};
+ const float v3[2] = {maxx, miny};
+ const float v4[2] = {maxx + shadsize, miny};
+
+ const float v5[2] = {maxx + 0.7f * shadsize, miny - 0.7f * shadsize};
+
+ const float v6[2] = {maxx, miny - shadsize};
+ const float v7[2] = {minx + 0.3f * shadsize, miny};
+ const float v8[2] = {minx + 0.5f * shadsize, miny - shadsize};
+
/* right quad */
- glColor4ub(0, 0, 0, alpha);
- glVertex2f(maxx, miny);
- glVertex2f(maxx, maxy - 0.3f * shadsize);
- glColor4ub(0, 0, 0, 0);
- glVertex2f(maxx + shadsize, maxy - 0.75f * shadsize);
- glVertex2f(maxx + shadsize, miny);
+ immAttr4ub(color, 0, 0, 0, alpha);
+ immVertex2fv(pos, v3);
+ immVertex2fv(pos, v1);
+ immAttr4ub(color, 0, 0, 0, 0);
+ immVertex2fv(pos, v2);
+
+ immVertex2fv(pos, v2);
+ immVertex2fv(pos, v4);
+ immAttr4ub(color, 0, 0, 0, alpha);
+ immVertex2fv(pos, v3);
/* corner shape */
- glColor4ub(0, 0, 0, alpha);
- glVertex2f(maxx, miny);
- glColor4ub(0, 0, 0, 0);
- glVertex2f(maxx + shadsize, miny);
- glVertex2f(maxx + 0.7f * shadsize, miny - 0.7f * shadsize);
- glVertex2f(maxx, miny - shadsize);
+ /* immAttr4ub(color, 0, 0, 0, alpha); */ /* Not needed, done above in previous tri */
+ immVertex2fv(pos, v3);
+ immAttr4ub(color, 0, 0, 0, 0);
+ immVertex2fv(pos, v4);
+ immVertex2fv(pos, v5);
+
+ immVertex2fv(pos, v5);
+ immVertex2fv(pos, v6);
+ immAttr4ub(color, 0, 0, 0, alpha);
+ immVertex2fv(pos, v3);
/* bottom quad */
- glColor4ub(0, 0, 0, alpha);
- glVertex2f(minx + 0.3f * shadsize, miny);
- glVertex2f(maxx, miny);
- glColor4ub(0, 0, 0, 0);
- glVertex2f(maxx, miny - shadsize);
- glVertex2f(minx + 0.5f * shadsize, miny - shadsize);
+ /* immAttr4ub(color, 0, 0, 0, alpha); */ /* Not needed, done above in previous tri */
+ immVertex2fv(pos, v3);
+ immAttr4ub(color, 0, 0, 0, 0);
+ immVertex2fv(pos, v6);
+ immVertex2fv(pos, v8);
+
+ immVertex2fv(pos, v8);
+ immAttr4ub(color, 0, 0, 0, alpha);
+ immVertex2fv(pos, v7);
+ immVertex2fv(pos, v3);
}
void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
{
- glEnable(GL_BLEND);
+ GPU_blend(true);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- glBegin(GL_QUADS);
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ immBegin(GPU_PRIM_TRIS, 54);
/* accumulated outline boxes to make shade not linear, is more pleasant */
- ui_shadowbox(minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8);
- ui_shadowbox(minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8);
- ui_shadowbox(minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8);
+ ui_shadowbox(pos, color, minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8);
+ ui_shadowbox(pos, color, minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8);
+ ui_shadowbox(pos, color, minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8);
+
+ immEnd();
- glEnd();
+ immUnbindProgram();
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
@@ -1725,8 +2171,8 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha
{
float rad;
- if (radius > (BLI_rctf_size_y(rct) - 10.0f) / 2.0f)
- rad = (BLI_rctf_size_y(rct) - 10.0f) / 2.0f;
+ if (radius > (BLI_rctf_size_y(rct) - 10.0f) * 0.5f)
+ rad = (BLI_rctf_size_y(rct) - 10.0f) * 0.5f;
else
rad = radius;
@@ -1741,35 +2187,47 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha
a = i * aspect;
}
- glEnable(GL_BLEND);
-
+ GPU_blend(true);
const float dalpha = alpha * 2.0f / 255.0f;
float calpha = dalpha;
- for (; i--; a -= aspect) {
+ float visibility = 1.0f;
+ for (; i--;) {
/* alpha ranges from 2 to 20 or so */
- glColor4f(0.0f, 0.0f, 0.0f, calpha);
+#if 0 /* Old Method (pre 2.8) */
+ float color[4] = {0.0f, 0.0f, 0.0f, calpha};
+ UI_draw_roundbox_4fv(true, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a, color);
+#endif
+ /* Compute final visibility to match old method result. */
+ /* TODO we could just find a better fit function inside the shader instead of this. */
+ visibility = visibility * (1.0f - calpha);
calpha += dalpha;
-
- UI_draw_roundbox_gl_mode(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a);
}
- /* outline emphasis */
- glEnable(GL_LINE_SMOOTH);
- glColor4ub(0, 0, 0, 100);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f);
- glDisable(GL_LINE_SMOOTH);
+ uiWidgetBaseParameters widget_params = {
+ .recti.xmin = rct->xmin, .recti.ymin = rct->ymin,
+ .recti.xmax = rct->xmax, .recti.ymax = rct->ymax - 10.0f,
+ .rect.xmin = rct->xmin - a, .rect.ymin = rct->ymin - a,
+ .rect.xmax = rct->xmax + a, .rect.ymax = rct->ymax - 10.0f + a,
+ .radi = rad,
+ .rad = rad + a,
+ .round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
+ .round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
+ .round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
+ .round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
+ .alpha_discard = 1.0f,
+ };
- glDisable(GL_BLEND);
-}
+ GPUBatch *batch = ui_batch_roundbox_shadow_get();
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_SHADOW);
+ GPU_batch_uniform_4fv_array(batch, "parameters", 4, (float *)&widget_params);
+ GPU_batch_uniform_1f(batch, "alpha", 1.0f - visibility);
+ GPU_batch_draw(batch);
-/**
- * Reset GL state (keep minimal).
- *
- * \note Blender's internal code doesn't assume these are reset,
- * but external callbacks may depend on their state.
- */
-void UI_reinit_gl_state(void)
-{
- glLineWidth(1.0f);
- glPointSize(1.0f);
+ /* outline emphasis */
+ GPU_line_smooth(true);
+ float color[4] = {0.0f, 0.0f, 0.0f, 0.4f};
+ UI_draw_roundbox_4fv(false, rct->xmin - 0.5f, rct->ymin - 0.5f, rct->xmax + 0.5f, rct->ymax + 0.5f, radius + 0.5f, color);
+ GPU_line_smooth(false);
+
+ GPU_blend(false);
}
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 67486f38760..3a799c6e7db 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -70,15 +70,6 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "Eyedropper Modal Map", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_SAMPLE_BEGIN);
- WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET);
-
/* assign to operators */
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
@@ -106,15 +97,6 @@ wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "Eyedropper ColorBand PointSampling Map", modal_items_point);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, BACKSPACEKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_REMOVE_LAST);
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_SAMPLE);
- WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_RESET);
-
/* assign to operators */
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband_point");
@@ -136,8 +118,8 @@ void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *ar, co
wmWindow *win = CTX_wm_window(C);
int x = win->eventstate->x;
int y = win->eventstate->y;
- const unsigned char fg[4] = {255, 255, 255, 255};
- const unsigned char bg[4] = {0, 0, 0, 50};
+ const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
if ((name[0] == '\0') ||
@@ -151,7 +133,7 @@ void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *ar, co
y += U.widget_unit;
- UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg);
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg);
}
@@ -166,8 +148,8 @@ void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *ar, co
*/
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, event->x, event->y);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
uiBut *but = ui_but_find_mouse_over(ar, event);
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 34f33f1d970..8e80d5657d7 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -137,8 +137,8 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
{
/* we could use some clever */
Main *bmain = CTX_data_main(C);
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
const char *display_device = CTX_data_scene(C)->display_settings.display_device;
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 43ccd65ddf2..781032ef971 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -150,8 +150,8 @@ static void datadropper_exit(bContext *C, wmOperator *op)
static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
{
/* we could use some clever */
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = BKE_screen_find_area_xy(win->screen, -1, mx, my);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
ScrArea *area_prev = CTX_wm_area(C);
ARegion *ar_prev = CTX_wm_region(C);
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 954259140c3..1dae076f930 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -45,6 +45,8 @@
#include "BKE_screen.h"
#include "BKE_unit.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "UI_interface.h"
@@ -152,12 +154,9 @@ static void depthdropper_exit(bContext *C, wmOperator *op)
static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
{
/* we could use some clever */
- Main *bmain = CTX_data_main(C);
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
- Scene *scene = win->screen->scene;
- UnitSettings *unit = &scene->unit;
- const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ Scene *scene = CTX_data_scene(C);
ScrArea *area_prev = CTX_wm_area(C);
ARegion *ar_prev = CTX_wm_region(C);
@@ -168,6 +167,7 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
if (sa->spacetype == SPACE_VIEW3D) {
ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
if (ar) {
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
/* weak, we could pass in some reference point */
@@ -185,7 +185,7 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
view3d_operator_needs_opengl(C);
- if (ED_view3d_autodist(bmain, scene, ar, v3d, mval, co, true, NULL)) {
+ if (ED_view3d_autodist(depsgraph, ar, v3d, mval, co, true, NULL)) {
const float mval_center_fl[2] = {
(float)ar->winx / 2,
(float)ar->winy / 2};
@@ -196,9 +196,9 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
*r_depth = len_v3v3(view_co, co_align);
- bUnit_AsString(ddr->name, sizeof(ddr->name),
- (double)*r_depth,
- 4, unit->system, B_UNIT_LENGTH, do_split, false);
+ bUnit_AsString2(
+ ddr->name, sizeof(ddr->name), (double)*r_depth,
+ 4, B_UNIT_LENGTH, &scene->unit, false);
}
else {
BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index d6569bd840c..852f7ea71b6 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -42,7 +42,9 @@
#include "BKE_context.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -130,8 +132,8 @@ static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *eve
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
- DAG_relations_tag_update(CTX_data_main(C));
- DAG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_relations_tag_update(CTX_data_main(C));
+ DEG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
}
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 64c3ae32eaa..b8355b31ff0 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -38,11 +38,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
-#include "DNA_sensor_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
-#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@@ -72,6 +68,7 @@
#include "ED_undo.h"
#include "UI_interface.h"
+#include "UI_view2d.h"
#include "BLF_api.h"
@@ -109,8 +106,6 @@
#define UI_MAX_PASSWORD_STR 128
/* proto */
-static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to);
-static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to);
static int ui_do_but_EXIT(bContext *C, uiBut *but, struct uiHandleButtonData *data, const wmEvent *event);
static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b);
static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str);
@@ -125,7 +120,7 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve
#define BUTTON_FLASH_DELAY 0.020
#define MENU_SCROLL_INTERVAL 0.1
#define PIE_MENU_INTERVAL 0.01
-#define BUTTON_AUTO_OPEN_THRESH 0.3
+#define BUTTON_AUTO_OPEN_THRESH 0.2
#define BUTTON_MOUSE_TOWARDS_THRESH 1.0
/* pixels to move the cursor to get out of keyboard navigation */
#define BUTTON_KEYNAV_PX_LIMIT 8
@@ -276,6 +271,7 @@ typedef struct uiHandleButtonData {
/* booleans (could be made into flags) */
bool cancel, escapecancel;
bool applied, applied_interactive;
+ bool changed_cursor;
wmTimer *flashtimer;
/* edited value */
@@ -619,11 +615,8 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext,
static void popup_check(bContext *C, wmOperator *op)
{
- if (op && op->type->check && op->type->check(C, op)) {
- /* check for popup and re-layout buttons */
- ARegion *ar_menu = CTX_wm_menu(C);
- if (ar_menu)
- ED_region_tag_refresh_ui(ar_menu);
+ if (op && op->type->check) {
+ op->type->check(C, op);
}
}
@@ -704,8 +697,7 @@ static void ui_apply_but_undo(uiBut *but)
const char *str = NULL;
/* define which string to use for undo */
- if (ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK)) str = "Add button link";
- else if (but->type == UI_BTYPE_MENU) str = but->drawstr;
+ if (but->type == UI_BTYPE_MENU) str = but->drawstr;
else if (but->drawstr[0]) str = but->drawstr;
else str = but->tip;
@@ -917,6 +909,21 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
data->applied = true;
}
+static void ui_apply_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data)
+{
+ if (data->str) {
+ ui_but_string_set(C, but, data->str);
+ ui_but_update_edited(but);
+ }
+ else {
+ ui_but_value_set(but, but->hardmax);
+ ui_apply_but_func(C, but);
+ }
+
+ data->retval = but->retval;
+ data->applied = true;
+}
+
static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
{
if (data->str) {
@@ -1219,6 +1226,9 @@ static bool ui_drag_toggle_but_is_supported(const uiBut *but)
if (ui_but_is_bool(but)) {
return true;
}
+ else if (UI_but_is_decorator(but)) {
+ return ELEM(but->icon, ICON_DECORATE, ICON_DECORATE_KEYFRAME, ICON_DECORATE_ANIMATE, ICON_DECORATE_OVERRIDE);
+ }
else {
return false;
}
@@ -1229,6 +1239,9 @@ static bool ui_drag_toggle_but_is_pushed(uiBut *but)
if (ui_but_is_bool(but)) {
return ui_but_is_pushed(but);
}
+ else if (UI_but_is_decorator(but)) {
+ return (but->icon == ICON_DECORATE_KEYFRAME);
+ }
else {
return false;
}
@@ -1236,18 +1249,18 @@ static bool ui_drag_toggle_but_is_pushed(uiBut *but)
typedef struct uiDragToggleHandle {
/* init */
- bool is_init;
bool is_set;
float but_cent_start[2];
- eButType but_type_start;
- bool xy_lock[2];
+ bool is_xy_lock_init;
+ bool xy_lock[2];
+
int xy_init[2];
int xy_last[2];
} uiDragToggleHandle;
static bool ui_drag_toggle_set_xy_xy(
- bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
+ bContext *C, ARegion *ar, const bool is_set,
const int xy_src[2], const int xy_dst[2])
{
/* popups such as layers won't re-evaluate on redraw */
@@ -1271,7 +1284,7 @@ static bool ui_drag_toggle_set_xy_xy(
if (BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
/* execute the button */
- if (ui_drag_toggle_but_is_supported(but) && but->type == but_type_start) {
+ if (ui_drag_toggle_but_is_supported(but)) {
/* is it pressed? */
bool is_set_but = ui_drag_toggle_but_is_pushed(but);
if (is_set_but != is_set) {
@@ -1308,7 +1321,7 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
* Check if we need to initialize the lock axis by finding if the first
* button we mouse over is X or Y aligned, then lock the mouse to that axis after.
*/
- if (drag_info->is_init == false) {
+ if (drag_info->is_xy_lock_init == false) {
/* first store the buttons original coords */
uiBut *but = ui_but_find_mouse_over_ex(ar, xy_input[0], xy_input[1], true);
@@ -1329,11 +1342,11 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
else {
drag_info->xy_lock[1] = true;
}
- drag_info->is_init = true;
+ drag_info->is_xy_lock_init = true;
}
}
else {
- drag_info->is_init = true;
+ drag_info->is_xy_lock_init = true;
}
}
}
@@ -1345,7 +1358,7 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
/* touch all buttons between last mouse coord and this one */
- do_draw = ui_drag_toggle_set_xy_xy(C, ar, drag_info->is_set, drag_info->but_type_start, drag_info->xy_last, xy);
+ do_draw = ui_drag_toggle_set_xy_xy(C, ar, drag_info->is_set, drag_info->xy_last, xy);
if (do_draw) {
ED_region_tag_redraw(ar);
@@ -1709,7 +1722,7 @@ static bool ui_but_drag_init(
/* prevent other WM gestures to start while we try to drag */
WM_gestures_remove(C);
- if (ABS(data->dragstartx - event->x) + ABS(data->dragstarty - event->y) > U.dragthreshold) {
+ if (ABS(data->dragstartx - event->x) + ABS(data->dragstarty - event->y) > U.dragthreshold * U.dpi_fac) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
data->cancel = true;
@@ -1725,7 +1738,6 @@ static bool ui_but_drag_init(
drag_info->is_set = ui_drag_toggle_but_is_pushed(but);
drag_info->but_cent_start[0] = BLI_rctf_cent_x(&but->rect);
drag_info->but_cent_start[1] = BLI_rctf_cent_y(&but->rect);
- drag_info->but_type_start = but->type;
copy_v2_v2_int(drag_info->xy_init, &event->x);
copy_v2_v2_int(drag_info->xy_last, &event->x);
@@ -1740,6 +1752,22 @@ static bool ui_but_drag_init(
drag_info, WM_HANDLER_BLOCKING);
CTX_wm_region_set(C, ar_prev);
+
+ /* Initialize alignment for single row/column regions,
+ * otherwise we use the relative position of the first other button dragged over. */
+ if (ELEM(data->region->regiontype, RGN_TYPE_NAV_BAR, RGN_TYPE_HEADER)) {
+ int lock_axis = -1;
+ if (ELEM(data->region->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ lock_axis = 0;
+ }
+ else if (ELEM(data->region->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ lock_axis = 1;
+ }
+ if (lock_axis != -1) {
+ drag_info->xy_lock[lock_axis] = true;
+ drag_info->is_xy_lock_init = true;
+ }
+ }
}
else
#endif
@@ -1792,223 +1820,6 @@ static bool ui_but_drag_init(
/* ********************** linklines *********************** */
-static void ui_linkline_remove_active(uiBlock *block)
-{
- uiBut *but;
- uiLink *link;
- uiLinkLine *line, *nline;
- int a, b;
-
- for (but = block->buttons.first; but; but = but->next) {
- if (but->type == UI_BTYPE_LINK && but->link) {
- for (line = but->link->lines.first; line; line = nline) {
- nline = line->next;
-
- if (line->flag & UI_SELECT) {
- BLI_remlink(&but->link->lines, line);
-
- link = line->from->link;
-
- /* are there more pointers allowed? */
- if (link->ppoin) {
-
- if (*(link->totlink) == 1) {
- *(link->totlink) = 0;
- MEM_freeN(*(link->ppoin));
- *(link->ppoin) = NULL;
- }
- else {
- b = 0;
- for (a = 0; a < (*(link->totlink)); a++) {
-
- if ((*(link->ppoin))[a] != line->to->poin) {
- (*(link->ppoin))[b] = (*(link->ppoin))[a];
- b++;
- }
- }
- (*(link->totlink))--;
- }
- }
- else {
- *(link->poin) = NULL;
- }
-
- MEM_freeN(line);
- }
- }
- }
- }
-}
-
-
-static uiLinkLine *ui_but_find_link(uiBut *from, uiBut *to)
-{
- uiLinkLine *line;
- uiLink *link;
-
- link = from->link;
- if (link) {
- for (line = link->lines.first; line; line = line->next) {
- if (line->from == from && line->to == to) {
- return line;
- }
- }
- }
- return NULL;
-}
-
-/* XXX BAD BAD HACK, fixme later **************** */
-/* Try to add an AND Controller between the sensor and the actuator logic bricks and to connect them all */
-static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to)
-{
- Object *ob = NULL;
- bSensor *sens_iter;
- bActuator *act_to, *act_iter;
- bController *cont;
- bController ***sens_from_links;
- uiBut *tmp_but;
-
- uiLink *link = from->link;
-
- PointerRNA props_ptr, object_ptr;
-
- if (link->ppoin)
- sens_from_links = (bController ***)(link->ppoin);
- else return;
-
- act_to = (bActuator *)(to->poin);
-
- /* (1) get the object */
- CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects)
- {
- for (sens_iter = ob_iter->sensors.first; sens_iter; sens_iter = sens_iter->next) {
- if (&(sens_iter->links) == sens_from_links) {
- ob = ob_iter;
- break;
- }
- }
- if (ob) break;
- } CTX_DATA_END;
-
- if (!ob) return;
-
- /* (2) check if the sensor and the actuator are from the same object */
- for (act_iter = ob->actuators.first; act_iter; act_iter = (bActuator *)act_iter->next) {
- if (act_iter == act_to)
- break;
- }
-
- /* only works if the sensor and the actuator are from the same object */
- if (!act_iter) return;
-
- /* in case the linked controller is not the active one */
- RNA_pointer_create((ID *)ob, &RNA_Object, ob, &object_ptr);
-
- WM_operator_properties_create(&props_ptr, "LOGIC_OT_controller_add");
- RNA_string_set(&props_ptr, "object", ob->id.name + 2);
-
- /* (3) add a new controller */
- if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, &props_ptr) & OPERATOR_FINISHED) {
- cont = (bController *)ob->controllers.last;
- /* Quick fix to make sure we always have an AND controller.
- * It might be nicer to make sure the operator gives us the right one though... */
- cont->type = CONT_LOGIC_AND;
-
- /* (4) link the sensor->controller->actuator */
- tmp_but = MEM_callocN(sizeof(uiBut), "uiBut");
- UI_but_link_set(
- tmp_but, (void **)&cont, (void ***)&(cont->links),
- &cont->totlinks, from->link->tocode, (int)to->hardmin);
- tmp_but->hardmin = from->link->tocode;
- tmp_but->poin = (char *)cont;
-
- tmp_but->type = UI_BTYPE_INLINK;
- ui_but_link_add(C, from, tmp_but);
-
- tmp_but->type = UI_BTYPE_LINK;
- ui_but_link_add(C, tmp_but, to);
-
- /* (5) garbage collection */
- MEM_freeN(tmp_but->link);
- MEM_freeN(tmp_but);
- }
- WM_operator_properties_free(&props_ptr);
-}
-
-static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to)
-{
- /* in 'from' we have to add a link to 'to' */
- uiLink *link;
- uiLinkLine *line;
- void **oldppoin;
- int a;
-
- if ((line = ui_but_find_link(from, to))) {
- line->flag |= UI_SELECT;
- ui_linkline_remove_active(from->block);
- return;
- }
-
- if (from->type == UI_BTYPE_INLINK && to->type == UI_BTYPE_INLINK) {
- return;
- }
- else if (from->type == UI_BTYPE_LINK && to->type == UI_BTYPE_INLINK) {
- if (from->link->tocode != (int)to->hardmin) {
- ui_but_smart_controller_add(C, from, to);
- return;
- }
- }
- else if (from->type == UI_BTYPE_INLINK && to->type == UI_BTYPE_LINK) {
- if (to->link->tocode == (int)from->hardmin) {
- return;
- }
- }
-
- link = from->link;
-
- /* are there more pointers allowed? */
- if (link->ppoin) {
- oldppoin = *(link->ppoin);
-
- (*(link->totlink))++;
- *(link->ppoin) = MEM_callocN(*(link->totlink) * sizeof(void *), "new link");
-
- for (a = 0; a < (*(link->totlink)) - 1; a++) {
- (*(link->ppoin))[a] = oldppoin[a];
- }
- (*(link->ppoin))[a] = to->poin;
-
- if (oldppoin) MEM_freeN(oldppoin);
- }
- else {
- *(link->poin) = to->poin;
- }
-
-}
-
-
-static void ui_apply_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data)
-{
- ARegion *ar = CTX_wm_region(C);
- uiBut *bt;
-
- for (bt = but->block->buttons.first; bt; bt = bt->next) {
- if (ui_but_contains_point_px(ar, bt, but->linkto[0] + ar->winrct.xmin, but->linkto[1] + ar->winrct.ymin) )
- break;
- }
- if (bt && bt != but) {
- if (!ELEM(bt->type, UI_BTYPE_LINK, UI_BTYPE_INLINK) || !ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK))
- return;
-
- if (but->type == UI_BTYPE_LINK) ui_but_link_add(C, but, bt);
- else ui_but_link_add(C, bt, but);
-
- ui_apply_but_func(C, but);
- data->retval = but->retval;
- }
- data->applied = true;
-}
-
static void ui_apply_but_IMAGE(bContext *C, uiBut *but, uiHandleButtonData *data)
{
ui_apply_but_func(C, but);
@@ -2127,6 +1938,9 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
case UI_BTYPE_LISTROW:
ui_apply_but_ROW(C, block, but, data);
break;
+ case UI_BTYPE_TAB:
+ ui_apply_but_TAB(C, but, data);
+ break;
case UI_BTYPE_SCROLL:
case UI_BTYPE_GRIP:
case UI_BTYPE_NUM:
@@ -2162,10 +1976,6 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
case UI_BTYPE_HOTKEY_EVENT:
ui_apply_but_BUT(C, but, data);
break;
- case UI_BTYPE_LINK:
- case UI_BTYPE_INLINK:
- ui_apply_but_LINK(C, but, data);
- break;
case UI_BTYPE_IMAGE:
ui_apply_but_IMAGE(C, but, data);
break;
@@ -2225,7 +2035,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
if (wmd->type == WM_DRAG_ID) {
/* align these types with UI_but_active_drop_name */
if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- ID *id = (ID *)wmd->poin;
+ ID *id = WM_drag_ID(wmd, 0);
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
@@ -2245,278 +2055,404 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
/* ******************* copy and paste ******************** */
-/* c = copy, v = paste */
-static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, const char mode, const bool copy_array)
+static bool ui_but_contains_password(uiBut *but)
{
- int buf_paste_len = 0;
- const char *buf_paste = "";
- bool buf_paste_alloc = false;
- bool show_report = false; /* use to display errors parsing paste input */
+ return but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD);
+}
- BLI_assert((but->flag & UI_BUT_DISABLED) == 0); /* caller should check */
+static void ui_but_get_pasted_text_from_clipboard(char **buf_paste, int *buf_len)
+{
+ char *text;
+ int length;
+ /* get only first line even if the clipboard contains multiple lines */
+ text = WM_clipboard_text_get_firstline(false, &length);
- if (mode == 'c') {
- /* disallow copying from any passwords */
- if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) {
- return;
- }
+ if (text) {
+ *buf_paste = text;
+ *buf_len = length;
+ }
+ else {
+ *buf_paste = MEM_callocN(sizeof(char), __func__);
+ *buf_len = 0;
}
+}
- if (mode == 'v') {
- /* extract first line from clipboard in case of multi-line copies */
- const char *buf_paste_test;
+static int get_but_property_array_length(uiBut *but)
+{
+ return RNA_property_array_length(&but->rnapoin, but->rnaprop);
+}
- buf_paste_test = WM_clipboard_text_get_firstline(false, &buf_paste_len);
- if (buf_paste_test) {
- buf_paste = buf_paste_test;
- buf_paste_alloc = true;
- }
+static void ui_but_set_float_array(bContext *C, uiBut *but, uiHandleButtonData *data, float *values, int array_length)
+{
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+
+ for (int i = 0; i < array_length; i++) {
+ RNA_property_float_set_index(&but->rnapoin, but->rnaprop, i, values[i]);
}
+ if (data) data->value = values[but->rnaindex];
- /* No return from here down */
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+}
+static void float_array_to_string(float *values, int array_length, char *output, int output_len_max)
+{
+ /* to avoid buffer overflow attacks; numbers are quite arbitrary */
+ BLI_assert(output_len_max > 15);
+ output_len_max -= 10;
- /* numeric value */
- if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
+ int current_index = 0;
+ output[current_index] = '[';
+ current_index++;
- if (but->poin == NULL && but->rnapoin.data == NULL) {
- /* pass */
- }
- else if (copy_array && but->rnapoin.data && but->rnaprop &&
- ELEM(RNA_property_subtype(but->rnaprop), PROP_COLOR, PROP_TRANSLATION, PROP_DIRECTION,
- PROP_VELOCITY, PROP_ACCELERATION, PROP_MATRIX, PROP_EULER, PROP_QUATERNION, PROP_AXISANGLE,
- PROP_XYZ, PROP_XYZ_LENGTH, PROP_COLOR_GAMMA, PROP_COORDS))
- {
- float values[4];
- int array_length = RNA_property_array_length(&but->rnapoin, but->rnaprop);
+ for (int i = 0; i < array_length; i++) {
+ int length = BLI_snprintf(output + current_index, output_len_max - current_index, "%f", values[i]);
+ current_index += length;
- if (mode == 'c') {
- char buf_copy[UI_MAX_DRAW_STR];
+ if (i < array_length - 1) {
+ if (current_index < output_len_max) {
+ output[current_index + 0] = ',';
+ output[current_index + 1] = ' ';
+ current_index += 2;
+ }
+ }
+ }
- if (array_length == 4) {
- values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
- }
- else {
- values[3] = 0.0f;
- }
- ui_but_v3_get(but, values);
+ output[current_index + 0] = ']';
+ output[current_index + 1] = '\0';
+}
- BLI_snprintf(buf_copy, sizeof(buf_copy), "[%f, %f, %f, %f]", values[0], values[1], values[2], values[3]);
- WM_clipboard_text_set(buf_copy, 0);
- }
- else {
- if (sscanf(buf_paste, "[%f, %f, %f, %f]", &values[0], &values[1], &values[2], &values[3]) >= array_length) {
- button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+static void ui_but_copy_numeric_array(uiBut *but, char *output, int output_len_max)
+{
+ int array_length = get_but_property_array_length(but);
+ float *values = alloca(array_length * sizeof(float));
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, values);
+ float_array_to_string(values, array_length, output, output_len_max);
+}
- ui_but_v3_set(but, values);
- if (but->rnaprop && array_length == 4) {
- RNA_property_float_set_index(&but->rnapoin, but->rnaprop, 3, values[3]);
- }
- data->value = values[but->rnaindex];
+static bool parse_float_array(char *text, float *values, int expected_length)
+{
+ /* can parse max 4 floats for now */
+ BLI_assert(0 <= expected_length && expected_length <= 4);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- else {
- WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'");
- show_report = true;
- }
- }
- }
- else if (mode == 'c') {
- /* Get many decimal places, then strip trailing zeros.
- * note: too high values start to give strange results */
- char buf_copy[UI_MAX_DRAW_STR];
- ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX, false, NULL);
- BLI_str_rstrip_float_zero(buf_copy, '\0');
+ float v[5];
+ int actual_length = sscanf(text, "[%f, %f, %f, %f, %f]", &v[0], &v[1], &v[2], &v[3], &v[4]);
- WM_clipboard_text_set(buf_copy, 0);
- }
- else {
- double val;
+ if (actual_length == expected_length) {
+ memcpy(values, v, sizeof(float) * expected_length);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
- if (ui_but_string_set_eval_num(C, but, buf_paste, &val)) {
- button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- data->value = val;
- ui_but_string_set(C, but, buf_paste);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- else {
- /* evaluating will report errors */
- show_report = true;
- }
- }
+static void ui_but_paste_numeric_array(bContext *C, uiBut *but, uiHandleButtonData *data, char *buf_paste)
+{
+ int array_length = get_but_property_array_length(but);
+ if (array_length > 4) {
+ // not supported for now
+ return;
}
- /* NORMAL button */
- else if (but->type == UI_BTYPE_UNITVEC) {
- float xyz[3];
+ float *values = alloca(sizeof(float) * array_length);
- if (but->poin == NULL && but->rnapoin.data == NULL) {
- /* pass */
- }
- else if (mode == 'c') {
- char buf_copy[UI_MAX_DRAW_STR];
- ui_but_v3_get(but, xyz);
- BLI_snprintf(buf_copy, sizeof(buf_copy), "[%f, %f, %f]", xyz[0], xyz[1], xyz[2]);
- WM_clipboard_text_set(buf_copy, 0);
- }
- else {
- if (sscanf(buf_paste, "[%f, %f, %f]", &xyz[0], &xyz[1], &xyz[2]) == 3) {
- if (normalize_v3(xyz) == 0.0f) {
- /* better set Z up then have a zero vector */
- xyz[2] = 1.0;
- }
- button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- ui_but_v3_set(but, xyz);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- else {
- WM_report(RPT_ERROR, "Paste expected 3 numbers, formatted: '[n, n, n]'");
- show_report = true;
- }
- }
+ if (parse_float_array(buf_paste, values, array_length)) {
+ ui_but_set_float_array(C, but, data, values, array_length);
}
+ else {
+ WM_report(RPT_ERROR, "Expected an array of numbers: [n, n, ...]");
+ }
+}
+static void ui_but_copy_numeric_value(uiBut *but, char *output, int output_len_max)
+{
+ /* Get many decimal places, then strip trailing zeros.
+ * note: too high values start to give strange results */
+ ui_but_string_get_ex(but, output, output_len_max, UI_PRECISION_FLOAT_MAX, false, NULL);
+ BLI_str_rstrip_float_zero(output, '\0');
+}
- /* RGB triple */
- else if (but->type == UI_BTYPE_COLOR) {
- float rgba[4];
+static void ui_but_paste_numeric_value(bContext *C, uiBut *but, uiHandleButtonData *data, char *buf_paste)
+{
+ double value;
- if (but->poin == NULL && but->rnapoin.data == NULL) {
- /* pass */
+ if (ui_but_string_set_eval_num(C, but, buf_paste, &value)) {
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+ data->value = value;
+ ui_but_string_set(C, but, buf_paste);
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ else {
+ WM_report(RPT_ERROR, "Expected a number");
+ }
+}
+
+static bool ui_but_has_array_value(uiBut *but)
+{
+ return (but->rnapoin.data && but->rnaprop &&
+ ELEM(RNA_property_subtype(but->rnaprop), PROP_COLOR, PROP_TRANSLATION, PROP_DIRECTION,
+ PROP_VELOCITY, PROP_ACCELERATION, PROP_MATRIX, PROP_EULER, PROP_QUATERNION, PROP_AXISANGLE,
+ PROP_XYZ, PROP_XYZ_LENGTH, PROP_COLOR_GAMMA, PROP_COORDS));
+}
+
+static void ui_but_paste_normalized_vector(bContext *C, uiBut *but, char *buf_paste)
+{
+ float xyz[3];
+ if (parse_float_array(buf_paste, xyz, 3)) {
+ if (normalize_v3(xyz) == 0.0f) {
+ /* better set Z up then have a zero vector */
+ xyz[2] = 1.0;
}
- else if (mode == 'c') {
- char buf_copy[UI_MAX_DRAW_STR];
+ ui_but_set_float_array(C, but, NULL, xyz, 3);
+ }
+ else {
+ WM_report(RPT_ERROR, "Paste expected 3 numbers, formatted: '[n, n, n]'");
+ }
+}
- if (but->rnaprop && RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4)
- rgba[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
- else
- rgba[3] = 1.0f;
+static void ui_but_copy_color(uiBut *but, char *output, int output_len_max)
+{
+ float rgba[4];
- ui_but_v3_get(but, rgba);
- /* convert to linear color to do compatible copy between gamma and non-gamma */
- if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
- srgb_to_linearrgb_v3_v3(rgba, rgba);
+ if (but->rnaprop && get_but_property_array_length(but) == 4)
+ rgba[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
+ else
+ rgba[3] = 1.0f;
- BLI_snprintf(buf_copy, sizeof(buf_copy), "[%f, %f, %f, %f]", rgba[0], rgba[1], rgba[2], rgba[3]);
- WM_clipboard_text_set(buf_copy, 0);
+ ui_but_v3_get(but, rgba);
- }
- else {
- if (sscanf(buf_paste, "[%f, %f, %f, %f]", &rgba[0], &rgba[1], &rgba[2], &rgba[3]) == 4) {
- /* assume linear colors in buffer */
- if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
- linearrgb_to_srgb_v3_v3(rgba, rgba);
+ /* convert to linear color to do compatible copy between gamma and non-gamma */
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
+ srgb_to_linearrgb_v3_v3(rgba, rgba);
- button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- ui_but_v3_set(but, rgba);
- if (but->rnaprop && RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4)
- RNA_property_float_set_index(&but->rnapoin, but->rnaprop, 3, rgba[3]);
+ float_array_to_string(rgba, 4, output, output_len_max);
+}
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- else {
- WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'");
- show_report = true;
+static void ui_but_paste_color(bContext *C, uiBut *but, char *buf_paste)
+{
+ float rgba[4];
+ if (parse_float_array(buf_paste, rgba, 4)) {
+ if (but->rnaprop) {
+ /* Assume linear colors in buffer. */
+ if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ linearrgb_to_srgb_v3_v3(rgba, rgba);
}
+
+ /* Some color properties are RGB, not RGBA. */
+ int array_len = get_but_property_array_length(but);
+ BLI_assert(ELEM(array_len, 3, 4));
+ ui_but_set_float_array(C, but, NULL, rgba, array_len);
}
}
+ else {
+ WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'");
+ }
+}
- /* text/string and ID data */
- else if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- uiHandleButtonData *active_data = but->active;
+static void ui_but_copy_text(uiBut *but, char *output, int output_len_max)
+{
+ ui_but_string_get(but, output, output_len_max);
+}
- if (but->poin == NULL && but->rnapoin.data == NULL) {
- /* pass */
- }
- else if (mode == 'c') {
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- WM_clipboard_text_set(active_data->str, 0);
- active_data->cancel = true;
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- else {
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+static void ui_but_paste_text(bContext *C, uiBut *but, uiHandleButtonData *data, char *buf_paste)
+{
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ ui_textedit_string_set(but, but->active, buf_paste);
- ui_textedit_string_set(but, active_data, buf_paste);
+ if (but->type == UI_BTYPE_SEARCH_MENU) {
+ but->changed = true;
+ ui_searchbox_update(C, data->searchbox, but, true);
+ }
- if (but->type == UI_BTYPE_SEARCH_MENU) {
- /* else uiSearchboxData.active member is not updated [#26856] */
- but->changed = true;
- ui_searchbox_update(C, data->searchbox, but, true);
- }
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+}
+
+static void ui_but_copy_colorband(uiBut *but)
+{
+ if (but->poin != NULL) {
+ memcpy(&but_copypaste_coba, but->poin, sizeof(ColorBand));
}
- /* colorband (not supported by system clipboard) */
- else if (but->type == UI_BTYPE_COLORBAND) {
- if (mode == 'c') {
- if (but->poin != NULL) {
- memcpy(&but_copypaste_coba, but->poin, sizeof(ColorBand));
- }
- }
- else {
- if (but_copypaste_coba.tot != 0) {
- if (!but->poin)
- but->poin = MEM_callocN(sizeof(ColorBand), "colorband");
+}
- button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- memcpy(data->coba, &but_copypaste_coba, sizeof(ColorBand));
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- }
+static void ui_but_paste_colorband(bContext *C, uiBut *but, uiHandleButtonData *data)
+{
+ if (but_copypaste_coba.tot != 0) {
+ if (!but->poin)
+ but->poin = MEM_callocN(sizeof(ColorBand), "colorband");
+
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+ memcpy(data->coba, &but_copypaste_coba, sizeof(ColorBand));
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
}
- else if (but->type == UI_BTYPE_CURVE) {
- if (mode == 'c') {
- if (but->poin != NULL) {
- but_copypaste_curve_alive = true;
- curvemapping_free_data(&but_copypaste_curve);
- curvemapping_copy_data(&but_copypaste_curve, (CurveMapping *) but->poin);
- }
- }
- else {
- if (but_copypaste_curve_alive) {
- if (!but->poin)
- but->poin = MEM_callocN(sizeof(CurveMapping), "curvemapping");
+}
- button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- curvemapping_free_data((CurveMapping *) but->poin);
- curvemapping_copy_data((CurveMapping *) but->poin, &but_copypaste_curve);
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- }
+static void ui_but_copy_curvemapping(uiBut *but)
+{
+ if (but->poin != NULL) {
+ but_copypaste_curve_alive = true;
+ curvemapping_free_data(&but_copypaste_curve);
+ curvemapping_copy_data(&but_copypaste_curve, (CurveMapping *) but->poin);
}
- /* operator button (any type) */
- else if (but->optype) {
- if (mode == 'c') {
- PointerRNA *opptr;
- char *str;
- opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
+}
- str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr);
+static void ui_but_paste_curvemapping(bContext *C, uiBut *but)
+{
+ if (but_copypaste_curve_alive) {
+ if (!but->poin)
+ but->poin = MEM_callocN(sizeof(CurveMapping), "curvemapping");
- WM_clipboard_text_set(str, 0);
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
+ curvemapping_free_data((CurveMapping *) but->poin);
+ curvemapping_copy_data((CurveMapping *) but->poin, &but_copypaste_curve);
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+}
- MEM_freeN(str);
- }
+static void ui_but_copy_operator(bContext *C, uiBut *but, char *output, int output_len_max)
+{
+ PointerRNA *opptr;
+ opptr = UI_but_operator_ptr_get(but);
+
+ char *str;
+ str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr);
+ BLI_strncpy(output, str, output_len_max);
+ MEM_freeN(str);
+}
+
+static void ui_but_copy_menu(uiBut *but, char *output, int output_len_max)
+{
+ MenuType *mt = UI_but_menutype_get(but);
+ if (mt) {
+ BLI_snprintf(output, output_len_max, "bpy.ops.wm.call_menu(name=\"%s\")", mt->idname);
}
- /* menu (any type) */
- else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
- MenuType *mt = UI_but_menutype_get(but);
- if (mt) {
- char str[32 + sizeof(mt->idname)];
- BLI_snprintf(str, sizeof(str), "bpy.ops.wm.call_menu(name=\"%s\")", mt->idname);
- WM_clipboard_text_set(str, 0);
- }
+}
+
+static void ui_but_copy(bContext *C, uiBut *but, const bool copy_array)
+{
+ if (ui_but_contains_password(but)) {
+ return;
+ }
+
+ /* Arbitrary large value (allow for paths: 'PATH_MAX') */
+ char buf[4096] = {0};
+ const int buf_max_len = sizeof(buf);
+
+ /* Left false for copying internal data (color-band for eg). */
+ bool is_buf_set = false;
+
+ bool has_required_data = !(but->poin == NULL && but->rnapoin.data == NULL);
+
+ switch (but->type) {
+ case UI_BTYPE_NUM:
+ case UI_BTYPE_NUM_SLIDER:
+ if (!has_required_data) break;
+ if (copy_array && ui_but_has_array_value(but)) {
+ ui_but_copy_numeric_array(but, buf, buf_max_len);
+ }
+ else {
+ ui_but_copy_numeric_value(but, buf, buf_max_len);
+ }
+ is_buf_set = true;
+ break;
+
+ case UI_BTYPE_UNITVEC:
+ if (!has_required_data) break;
+ ui_but_copy_numeric_array(but, buf, buf_max_len);
+ is_buf_set = true;
+ break;
+
+ case UI_BTYPE_COLOR:
+ if (!has_required_data) break;
+ ui_but_copy_color(but, buf, buf_max_len);
+ is_buf_set = true;
+ break;
+
+ case UI_BTYPE_TEXT:
+ case UI_BTYPE_SEARCH_MENU:
+ if (!has_required_data) break;
+ ui_but_copy_text(but, buf, buf_max_len);
+ is_buf_set = true;
+ break;
+
+ case UI_BTYPE_COLORBAND:
+ ui_but_copy_colorband(but);
+ break;
+
+ case UI_BTYPE_CURVE:
+ ui_but_copy_curvemapping(but);
+ break;
+
+ case UI_BTYPE_BUT:
+ ui_but_copy_operator(C, but, buf, buf_max_len);
+ is_buf_set = true;
+ break;
+
+ case UI_BTYPE_MENU:
+ case UI_BTYPE_PULLDOWN:
+ ui_but_copy_menu(but, buf, buf_max_len);
+ is_buf_set = true;
+ break;
+
+ default:
+ break;
}
- if (buf_paste_alloc) {
- MEM_freeN((void *)buf_paste);
+ if (is_buf_set) {
+ WM_clipboard_text_set(buf, 0);
}
+}
+
+static void ui_but_paste(bContext *C, uiBut *but, uiHandleButtonData *data, const bool paste_array)
+{
+ BLI_assert((but->flag & UI_BUT_DISABLED) == 0); /* caller should check */
+
+ int buf_paste_len = 0;
+ char *buf_paste;
+ ui_but_get_pasted_text_from_clipboard(&buf_paste, &buf_paste_len);
+
+ bool has_required_data = !(but->poin == NULL && but->rnapoin.data == NULL);
+
+ switch (but->type) {
+ case UI_BTYPE_NUM:
+ case UI_BTYPE_NUM_SLIDER:
+ if (!has_required_data) break;
+ if (paste_array && ui_but_has_array_value(but)) {
+ ui_but_paste_numeric_array(C, but, data, buf_paste);
+ }
+ else {
+ ui_but_paste_numeric_value(C, but, data, buf_paste);
+ }
+ break;
- if (show_report) {
- WM_report_banner_show();
+ case UI_BTYPE_UNITVEC:
+ if (!has_required_data) break;
+ ui_but_paste_normalized_vector(C, but, buf_paste);
+ break;
+
+ case UI_BTYPE_COLOR:
+ if (!has_required_data) break;
+ ui_but_paste_color(C, but, buf_paste);
+ break;
+
+ case UI_BTYPE_TEXT:
+ case UI_BTYPE_SEARCH_MENU:
+ if (!has_required_data) break;
+ ui_but_paste_text(C, but, data, buf_paste);
+ break;
+
+ case UI_BTYPE_COLORBAND:
+ ui_but_paste_colorband(C, but, data);
+ break;
+
+ case UI_BTYPE_CURVE:
+ ui_but_paste_curvemapping(C, but);
+ break;
+
+ default:
+ break;
}
+
+ MEM_freeN((void *)buf_paste);
}
/**
@@ -3179,6 +3115,9 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_searchbox_free(C, data->searchbox);
data->searchbox = NULL;
+ if (but->free_search_arg) {
+ MEM_SAFE_FREE(but->search_arg);
+ }
}
but->editstr = NULL;
@@ -3658,6 +3597,7 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
uiBlockCreateFunc func = NULL;
uiBlockHandleCreateFunc handlefunc = NULL;
uiMenuCreateFunc menufunc = NULL;
+ uiMenuCreateFunc popoverfunc = NULL;
void *arg = NULL;
switch (but->type) {
@@ -3677,6 +3617,11 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
menufunc = but->menu_create_func;
arg = but->poin;
break;
+ case UI_BTYPE_POPOVER:
+ BLI_assert(but->menu_create_func);
+ popoverfunc = but->menu_create_func;
+ arg = but->poin;
+ break;
case UI_BTYPE_COLOR:
ui_but_v3_get(but, data->origvec);
copy_v3_v3(data->vec, data->origvec);
@@ -3701,6 +3646,11 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
if (but->block->handle)
data->menu->popup = but->block->handle->popup;
}
+ else if (popoverfunc) {
+ data->menu = ui_popover_panel_create(C, data->region, but, popoverfunc, arg);
+ if (but->block->handle)
+ data->menu->popup = but->block->handle->popup;
+ }
#ifdef USE_ALLSELECT
{
@@ -3947,6 +3897,46 @@ static bool ui_but_is_mouse_over_icon_extra(const ARegion *region, uiBut *but, c
return BLI_rcti_isect_pt(&icon_rect, x, y);
}
+static int ui_do_but_TAB(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+{
+#ifdef USE_DRAG_TOGGLE
+ {
+ int retval;
+ if (ui_do_but_ANY_drag_toggle(C, but, data, event, &retval)) {
+ return retval;
+ }
+ }
+#endif
+
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
+ const int rna_type = but->rnaprop ? RNA_property_type(but->rnaprop) : 0;
+
+ if (but->rnaprop &&
+ ELEM(rna_type, PROP_POINTER, PROP_STRING) &&
+ (but->custom_data != NULL) &&
+ (event->type == LEFTMOUSE) &&
+ ((event->val == KM_DBL_CLICK) || event->ctrl))
+ {
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ return WM_UI_HANDLER_BREAK;
+ }
+ else if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && (event->val == KM_PRESS)) {
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+ else if (data->state == BUTTON_STATE_TEXT_EDITING) {
+ ui_do_but_textedit(C, block, but, data, event);
+ return WM_UI_HANDLER_BREAK;
+ }
+ else if (data->state == BUTTON_STATE_TEXT_SELECTING) {
+ ui_do_but_textedit_select(C, block, but, data, event);
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
static int ui_do_but_TEX(
bContext *C, uiBlock *block, uiBut *but,
uiHandleButtonData *data, const wmEvent *event)
@@ -4375,6 +4365,54 @@ static bool ui_numedit_but_NUM(
return changed;
}
+static void ui_numedit_set_active(uiBut *but)
+{
+ int oldflag = but->drawflag;
+ but->drawflag &= ~(UI_BUT_ACTIVE_LEFT | UI_BUT_ACTIVE_RIGHT);
+
+ uiHandleButtonData *data = but->active;
+ if (!data) {
+ return;
+ }
+
+ /* Ignore once we start dragging. */
+ if (data->dragchange == false) {
+ const float handle_width = min_ff(BLI_rctf_size_x(&but->rect) / 3, BLI_rctf_size_y(&but->rect) * 0.7f);
+ /* we can click on the side arrows to increment/decrement,
+ * or click inside to edit the value directly */
+ int mx = data->window->eventstate->x;
+ int my = data->window->eventstate->x;
+ ui_window_to_block(data->region, but->block, &mx, &my);
+
+ if (mx < (but->rect.xmin + handle_width)) {
+ but->drawflag |= UI_BUT_ACTIVE_LEFT;
+ }
+ else if (mx > (but->rect.xmax - handle_width)) {
+ but->drawflag |= UI_BUT_ACTIVE_RIGHT;
+ }
+ }
+
+ /* Don't change the cursor once pressed. */
+ if ((but->flag & UI_SELECT) == 0) {
+ if ((but->drawflag & (UI_BUT_ACTIVE_LEFT)) || (but->drawflag & (UI_BUT_ACTIVE_RIGHT))) {
+ if (data->changed_cursor) {
+ WM_cursor_modal_restore(data->window);
+ data->changed_cursor = false;
+ }
+ }
+ else {
+ if (data->changed_cursor == false) {
+ WM_cursor_modal_set(data->window, CURSOR_X_MOVE);
+ data->changed_cursor = true;
+ }
+ }
+ }
+
+ if (but->drawflag != oldflag) {
+ ED_region_tag_redraw(data->region);
+ }
+}
+
static int ui_do_but_NUM(
bContext *C, uiBlock *block, uiBut *but,
uiHandleButtonData *data, const wmEvent *event)
@@ -4388,6 +4426,7 @@ static int ui_do_but_NUM(
my = screen_my = event->y;
ui_window_to_block(data->region, block, &mx, &my);
+ ui_numedit_set_active(but);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
int type = event->type, val = event->val;
@@ -4401,10 +4440,14 @@ static int ui_do_but_NUM(
retval = WM_UI_HANDLER_BREAK; /* allow accumulating values, otherwise scrolling gets preference */
else if (type == WHEELDOWNMOUSE && event->ctrl) {
mx = but->rect.xmin;
+ but->drawflag &= ~UI_BUT_ACTIVE_RIGHT;
+ but->drawflag |= UI_BUT_ACTIVE_LEFT;
click = 1;
}
else if (type == WHEELUPMOUSE && event->ctrl) {
mx = but->rect.xmax;
+ but->drawflag &= ~UI_BUT_ACTIVE_LEFT;
+ but->drawflag |= UI_BUT_ACTIVE_RIGHT;
click = 1;
}
else if (event->val == KM_PRESS) {
@@ -4497,16 +4540,13 @@ static int ui_do_but_NUM(
/* we can click on the side arrows to increment/decrement,
* or click inside to edit the value directly */
float tempf, softmin, softmax;
- float handlewidth;
int temp;
softmin = but->softmin;
softmax = but->softmax;
- handlewidth = min_ff(BLI_rctf_size_x(&but->rect) / 3, BLI_rctf_size_y(&but->rect));
-
if (!ui_but_is_float(but)) {
- if (mx < (but->rect.xmin + handlewidth)) {
+ if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
temp = (int)data->value - 1;
@@ -4517,7 +4557,7 @@ static int ui_do_but_NUM(
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
- else if (mx > (but->rect.xmax - handlewidth)) {
+ else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
temp = (int)data->value + 1;
@@ -4533,7 +4573,7 @@ static int ui_do_but_NUM(
}
}
else {
- if (mx < (but->rect.xmin + handlewidth)) {
+ if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
tempf = (float)data->value - (UI_PRECISION_FLOAT_SCALE * but->a1);
@@ -4542,7 +4582,7 @@ static int ui_do_but_NUM(
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
- else if (mx > but->rect.xmax - handlewidth) {
+ else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
tempf = (float)data->value + (UI_PRECISION_FLOAT_SCALE * but->a1);
@@ -5265,7 +5305,8 @@ static int ui_do_but_COLOR(
if (!event->ctrl) {
float color[3];
Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active(scene);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Paint *paint = BKE_paint_get_active(scene, view_layer);
Brush *brush = BKE_paint_brush(paint);
if (brush->flag & BRUSH_USE_GRADIENT) {
@@ -6182,6 +6223,7 @@ static int ui_do_but_CURVE(
int mx, my, a;
bool changed = false;
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
mx = event->x;
my = event->y;
@@ -6310,7 +6352,7 @@ static int ui_do_but_CURVE(
}
else {
curvemapping_changed(cumap, true); /* remove doubles */
- BKE_paint_invalidate_cursor_overlay(scene, cumap);
+ BKE_paint_invalidate_cursor_overlay(scene, view_layer, cumap);
}
}
@@ -6476,35 +6518,6 @@ static int ui_do_but_WAVEFORM(
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_LINK(
- bContext *C, uiBut *but,
- uiHandleButtonData *data, const wmEvent *event)
-{
- VECCOPY2D(but->linkto, event->mval);
-
- if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
- button_activate_state(C, but, BUTTON_STATE_WAIT_RELEASE);
- return WM_UI_HANDLER_BREAK;
- }
- else if (event->type == LEFTMOUSE && but->block->handle) {
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
- }
- }
- else if (data->state == BUTTON_STATE_WAIT_RELEASE) {
-
- if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- if (!(but->flag & UI_SELECT))
- data->cancel = true;
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
- }
- }
-
- return WM_UI_HANDLER_CONTINUE;
-}
-
static bool ui_numedit_but_TRACKPREVIEW(
bContext *C, uiBut *but, uiHandleButtonData *data,
int mx, int my,
@@ -6597,8 +6610,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
data = but->active;
retval = WM_UI_HANDLER_CONTINUE;
- if (but->flag & UI_BUT_DISABLED)
- return WM_UI_HANDLER_CONTINUE;
+ bool is_disabled = but->flag & UI_BUT_DISABLED;
/* if but->pointype is set, but->poin should be too */
BLI_assert(!but->pointype || but->poin);
@@ -6607,35 +6619,55 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
* keymaps are handled using operators (see #ED_keymap_ui). */
if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
- /* handle copy-paste */
- if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS &&
- IS_EVENT_MOD(event, ctrl, oskey) && !event->shift)
- {
- /* Specific handling for listrows, we try to find their overlapping tex button. */
- if (but->type == UI_BTYPE_LISTROW) {
- uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER);
- if (labelbut) {
- but = labelbut;
- data = but->active;
- }
+
+ /* handle copy and paste */
+ bool is_press_ctrl_but_no_shift = event->val == KM_PRESS && IS_EVENT_MOD(event, ctrl, oskey) && !event->shift;
+ bool do_copy = event->type == CKEY && is_press_ctrl_but_no_shift;
+ bool do_paste = event->type == VKEY && is_press_ctrl_but_no_shift;
+
+ /* Specific handling for listrows, we try to find their overlapping tex button. */
+ if ((do_copy || do_paste) && but->type == UI_BTYPE_LISTROW) {
+ uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER);
+ if (labelbut) {
+ but = labelbut;
+ data = but->active;
}
- ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v', event->alt);
- return WM_UI_HANDLER_BREAK;
}
- /* handle drop */
- else if (event->type == EVT_DROP) {
- ui_but_drop(C, event, but, data);
+
+ /* do copy first, because it is the only allowed operator when disabled */
+ if (do_copy) {
+ ui_but_copy(C, but, event->alt);
+ return WM_UI_HANDLER_BREAK;
}
+
/* handle menu */
- else if ((event->type == RIGHTMOUSE) &&
- !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
- (event->val == KM_PRESS))
+ if ((event->type == RIGHTMOUSE) &&
+ !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
+ (event->val == KM_PRESS))
{
/* RMB has two options now */
if (ui_popup_context_menu_for_button(C, but)) {
return WM_UI_HANDLER_BREAK;
}
}
+
+ if (is_disabled) {
+ return WM_UI_HANDLER_CONTINUE;
+ }
+
+ if (do_paste) {
+ ui_but_paste(C, but, data, event->alt);
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ /* handle drop */
+ if (event->type == EVT_DROP) {
+ ui_but_drop(C, event, but, data);
+ }
+ }
+
+ if (but->flag & UI_BUT_DISABLED) {
+ return WM_UI_HANDLER_CONTINUE;
}
switch (but->type) {
@@ -6648,6 +6680,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_HOTKEY_EVENT:
retval = ui_do_but_HOTKEYEVT(C, but, data, event);
break;
+ case UI_BTYPE_TAB:
+ retval = ui_do_but_TAB(C, block, but, data, event);
+ break;
case UI_BTYPE_BUT_TOGGLE:
case UI_BTYPE_TOGGLE:
case UI_BTYPE_ICON_TOGGLE:
@@ -6705,6 +6740,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
retval = ui_do_but_TEX(C, block, but, data, event);
break;
case UI_BTYPE_MENU:
+ case UI_BTYPE_POPOVER:
case UI_BTYPE_BLOCK:
case UI_BTYPE_PULLDOWN:
retval = ui_do_but_BLOCK(C, but, data, event);
@@ -6733,10 +6769,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_HSVCIRCLE:
retval = ui_do_but_HSVCIRCLE(C, block, but, data, event);
break;
- case UI_BTYPE_LINK:
- case UI_BTYPE_INLINK:
- retval = ui_do_but_LINK(C, but, data, event);
- break;
case UI_BTYPE_TRACK_PREVIEW:
retval = ui_do_but_TRACKPREVIEW(C, block, but, data, event);
break;
@@ -6744,6 +6776,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* quiet warnings for unhandled types */
case UI_BTYPE_SEPR:
case UI_BTYPE_SEPR_LINE:
+ case UI_BTYPE_SEPR_SPACER:
case UI_BTYPE_EXTRA:
break;
}
@@ -6920,12 +6953,11 @@ bool ui_but_is_active(ARegion *ar)
/* is called by notifier */
void UI_screen_free_active_but(const bContext *C, bScreen *screen)
{
- ScrArea *sa = screen->areabase.first;
+ wmWindow *win = CTX_wm_window(C);
- for (; sa; sa = sa->next) {
- ARegion *ar = sa->regionbase.first;
- for (; ar; ar = ar->next) {
- uiBut *but = ui_but_find_active_in_region(ar);
+ ED_screen_areas_iter(win, screen, area) {
+ for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ uiBut *but = ui_but_find_active_in_region(region);
if (but) {
uiHandleButtonData *data = but->active;
@@ -7011,7 +7043,7 @@ static bool ui_region_contains_point_px(ARegion *ar, int x, int y)
ui_window_to_region(ar, &mx, &my);
/* check if in the rect */
- if (!BLI_rcti_isect_pt(&v2d->mask, mx, my)) {
+ if (!BLI_rcti_isect_pt(&v2d->mask, mx, my) || UI_view2d_mouse_in_scrollers(ar, &ar->v2d, x, y)) {
return false;
}
}
@@ -7166,7 +7198,7 @@ void UI_but_tooltip_refresh(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
if (data) {
- bScreen *sc = data->window->screen;
+ bScreen *sc = WM_window_get_active_screen(data->window);
if (sc->tool_tip && sc->tool_tip->region) {
WM_tooltip_refresh(C, data->window);
}
@@ -7191,12 +7223,21 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
}
}
-static ARegion *ui_but_tooltip_init(bContext *C, ARegion *ar, bool *r_exit_on_event)
+static ARegion *ui_but_tooltip_init(
+ bContext *C, ARegion *ar,
+ int *pass, double *r_pass_delay, bool *r_exit_on_event)
{
+ bool is_label = false;
+ if (*pass == 1) {
+ is_label = true;
+ (*pass)--;
+ (*r_pass_delay) = UI_TOOLTIP_DELAY - UI_TOOLTIP_DELAY_LABEL;
+ }
+
uiBut *but = UI_region_active_but_get(ar);
*r_exit_on_event = false;
if (but) {
- return UI_tooltip_create_from_button(C, ar, but);
+ return UI_tooltip_create_from_button(C, ar, but, is_label);
}
return NULL;
}
@@ -7211,7 +7252,15 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but)
if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) {
if (!but->block->tooltipdisabled) {
if (!wm->drags.first) {
- WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init);
+ bool is_label = UI_but_has_tooltip_label(but);
+ double delay = is_label ? UI_TOOLTIP_DELAY_LABEL : UI_TOOLTIP_DELAY;
+ WM_tooltip_timer_init_ex(C, data->window, data->region, ui_but_tooltip_init, delay);
+ if (is_label) {
+ bScreen *sc = WM_window_get_active_screen(data->window);
+ if (sc->tool_tip) {
+ sc->tool_tip->pass = 1;
+ }
+ }
}
}
}
@@ -7232,7 +7281,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
button_tooltip_timer_reset(C, but);
/* automatic open pulldown block timer */
- if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN)) {
+ if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) {
if (data->used_mouse && !data->autoopentimer) {
int time;
@@ -7395,6 +7444,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
/* activate button */
but->flag |= UI_ACTIVE;
+
but->active = data;
/* we disable auto_open in the block after a threshold, because we still
@@ -7442,6 +7492,22 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect));
WM_cursor_modal_set(data->window, horizontal ? CURSOR_X_MOVE : CURSOR_Y_MOVE);
}
+ else if (but->type == UI_BTYPE_NUM) {
+ ui_numedit_set_active(but);
+ }
+
+ if (UI_but_has_tooltip_label(but)) {
+ /* Show a label for this button. */
+ bScreen *sc = WM_window_get_active_screen(data->window);
+ if ((PIL_check_seconds_timer() - WM_tooltip_time_closed()) < 0.1) {
+ WM_tooltip_immediate_init(
+ C, CTX_wm_window(C), ar,
+ ui_but_tooltip_init);
+ if (sc->tool_tip) {
+ sc->tool_tip->pass = 1;
+ }
+ }
+ }
}
static void button_activate_exit(
@@ -7535,8 +7601,13 @@ static void button_activate_exit(
ui_selectcontext_end(but, &data->select_others);
#endif
- /* redraw (data is but->active!) */
+ if (data->changed_cursor) {
+ WM_cursor_modal_restore(data->window);
+ }
+
+ /* redraw and refresh (for popups) */
ED_region_tag_redraw(data->region);
+ ED_region_tag_refresh_ui(data->region);
/* clean up button */
if (but->active) {
@@ -7722,6 +7793,11 @@ void UI_context_update_anim_flag(const bContext *C)
for (block = ar->uiblocks.first; block; block = block->next) {
for (but = block->buttons.first; but; but = but->next) {
ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f);
+ ui_but_override_flag(but);
+ if (UI_but_is_decorator(but)) {
+ ui_but_anim_decorate_update_from_flag(but);
+ }
+
ED_region_tag_redraw(ar);
if (but->active) {
@@ -7909,8 +7985,29 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
case EVT_BUT_CANCEL:
data->cancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
- retval = WM_UI_HANDLER_CONTINUE;
break;
+#ifdef USE_UI_POPOVER_ONCE
+ case LEFTMOUSE:
+ {
+ if (event->val == KM_RELEASE) {
+ if (block->flag & UI_BLOCK_POPOVER_ONCE) {
+ if (!(but->flag & UI_BUT_DISABLED)) {
+ if (ui_but_is_popover_once_compat(but)) {
+ data->cancel = false;
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ retval = WM_UI_HANDLER_BREAK;
+ block->handle->menuretval = UI_RETURN_OK;
+ }
+ else if (ui_but_is_editable_as_text(but)) {
+ ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_TEXT_EDITING);
+ retval = WM_UI_HANDLER_BREAK;
+ }
+ }
+ }
+ }
+ break;
+ }
+#endif
case MOUSEMOVE:
{
uiBut *but_other = ui_but_find_mouse_over(ar, event);
@@ -7949,7 +8046,6 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
}
- retval = WM_UI_HANDLER_CONTINUE;
break;
}
/* XXX hardcoded keymap check... but anyway, while view changes, tooltips should be removed */
@@ -7960,10 +8056,11 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
UI_but_tooltip_timer_remove(C, but);
ATTR_FALLTHROUGH;
default:
- /* handle button type specific events */
- retval = ui_do_button(C, block, but, event);
break;
}
+
+ /* handle button type specific events */
+ retval = ui_do_button(C, block, but, event);
}
else if (data->state == BUTTON_STATE_WAIT_RELEASE) {
switch (event->type) {
@@ -7992,43 +8089,38 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
break;
}
case MOUSEMOVE:
- if (ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK)) {
- but->flag |= UI_SELECT;
- ui_do_button(C, block, but, event);
- ED_region_tag_redraw(ar);
- }
- else {
- /* deselect the button when moving the mouse away */
- /* also de-activate for buttons that only show higlights */
- if (ui_but_contains_point_px(ar, but, event->x, event->y)) {
-
- /* Drag on a hold button (used in the toolbar) now opens it immediately. */
- if (data->hold_action_timer) {
- if (but->flag & UI_SELECT) {
- if ((abs(event->x - event->prevx)) > 2 ||
- (abs(event->y - event->prevy)) > 2)
- {
- WM_event_remove_timer(data->wm, data->window, data->hold_action_timer);
- data->hold_action_timer = WM_event_add_timer(data->wm, data->window, TIMER, 0.0f);
- }
+ {
+ /* deselect the button when moving the mouse away */
+ /* also de-activate for buttons that only show highlights */
+ if (ui_but_contains_point_px(ar, but, event->x, event->y)) {
+
+ /* Drag on a hold button (used in the toolbar) now opens it immediately. */
+ if (data->hold_action_timer) {
+ if (but->flag & UI_SELECT) {
+ if ((abs(event->x - event->prevx)) > 2 ||
+ (abs(event->y - event->prevy)) > 2)
+ {
+ WM_event_remove_timer(data->wm, data->window, data->hold_action_timer);
+ data->hold_action_timer = WM_event_add_timer(data->wm, data->window, TIMER, 0.0f);
}
}
+ }
- if (!(but->flag & UI_SELECT)) {
- but->flag |= (UI_SELECT | UI_ACTIVE);
- data->cancel = false;
- ED_region_tag_redraw(data->region);
- }
+ if (!(but->flag & UI_SELECT)) {
+ but->flag |= (UI_SELECT | UI_ACTIVE);
+ data->cancel = false;
+ ED_region_tag_redraw(data->region);
}
- else {
- if (but->flag & UI_SELECT) {
- but->flag &= ~(UI_SELECT | UI_ACTIVE);
- data->cancel = true;
- ED_region_tag_redraw(data->region);
- }
+ }
+ else {
+ if (but->flag & UI_SELECT) {
+ but->flag &= ~(UI_SELECT | UI_ACTIVE);
+ data->cancel = true;
+ ED_region_tag_redraw(data->region);
}
}
break;
+ }
default:
/* otherwise catch mouse release event */
ui_do_button(C, block, but, event);
@@ -8260,13 +8352,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
}
if (redraw) {
- if (listbox->block->flag & UI_BLOCK_POPUP) {
- /* popups need special refreshing */
- ED_region_tag_refresh_ui(ar);
- }
- else {
- ED_region_tag_redraw(ar);
- }
+ ED_region_tag_redraw(ar);
+ ED_region_tag_refresh_ui(ar);
}
return retval;
@@ -8338,7 +8425,7 @@ static void ui_handle_button_return_submenu(bContext *C, const wmEvent *event, u
static void ui_mouse_motion_towards_init_ex(uiPopupBlockHandle *menu, const int xy[2], const bool force)
{
- BLI_assert(((uiBlock *)menu->region->uiblocks.first)->flag & UI_BLOCK_MOVEMOUSE_QUIT);
+ BLI_assert(((uiBlock *)menu->region->uiblocks.first)->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER));
if (!menu->dotowards || force) {
menu->dotowards = true;
@@ -8373,7 +8460,7 @@ static bool ui_mouse_motion_towards_check(
const float margin = MENU_TOWARDS_MARGIN;
rctf rect_px;
- BLI_assert(block->flag & UI_BLOCK_MOVEMOUSE_QUIT);
+ BLI_assert(block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER));
/* annoying fix for [#36269], this is a bit odd but in fact works quite well
@@ -8525,6 +8612,9 @@ static int ui_menu_scroll(ARegion *ar, uiBlock *block, int my, uiBut *to_bt)
dy = block->rect.ymin - ymin + UI_MENU_SCROLL_PAD;
}
+ /* remember scroll offset for refreshes */
+ block->handle->scrolloffset += dy;
+
/* apply scroll offset */
for (bt = block->buttons.first; bt; bt = bt->next) {
bt->rect.ymin += dy;
@@ -8627,7 +8717,7 @@ float ui_block_calc_pie_segment(uiBlock *block, const float event_xy[2])
len = normalize_v2_v2(block->pie_data.pie_dir, seg2);
- if (len < U.pie_menu_threshold * U.pixelsize)
+ if (len < U.pie_menu_threshold * U.dpi_fac)
block->pie_data.flags |= UI_PIE_INVALID_DIR;
else
block->pie_data.flags &= ~UI_PIE_INVALID_DIR;
@@ -8677,7 +8767,7 @@ static int ui_handle_menu_event(
add_v2_v2v2_int(menu->popup_create_vars.event_xy, menu->popup_create_vars.event_xy, mdiff);
- ui_popup_translate(C, ar, mdiff);
+ ui_popup_translate(ar, mdiff);
}
return retval;
@@ -8686,9 +8776,9 @@ static int ui_handle_menu_event(
#endif
if (but && button_modal_state(but->active->state)) {
- if (block->flag & UI_BLOCK_MOVEMOUSE_QUIT) {
+ if (block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER)) {
/* if a button is activated modal, always reset the start mouse
- * position of the towards mechanism to avoid loosing focus,
+ * position of the towards mechanism to avoid losing focus,
* and don't handle events */
ui_mouse_motion_towards_reinit(menu, &event->x);
}
@@ -8700,7 +8790,7 @@ static int ui_handle_menu_event(
else {
/* for ui_mouse_motion_towards_block */
if (event->type == MOUSEMOVE) {
- if (block->flag & UI_BLOCK_MOVEMOUSE_QUIT) {
+ if (block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER)) {
ui_mouse_motion_towards_init(menu, &event->x);
}
@@ -9017,7 +9107,7 @@ static int ui_handle_menu_event(
else {
/* check mouse moving outside of the menu */
- if (inside == 0 && (block->flag & UI_BLOCK_MOVEMOUSE_QUIT)) {
+ if (inside == 0 && (block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER))) {
uiSafetyRct *saferct;
ui_mouse_motion_towards_check(block, menu, &event->x, is_parent_inside == false);
@@ -9061,6 +9151,15 @@ static int ui_handle_menu_event(
retval = ui_handle_menu_button(C, event, menu);
}
+#ifdef USE_UI_POPOVER_ONCE
+ if (block->flag & UI_BLOCK_POPOVER_ONCE) {
+ if ((event->type == LEFTMOUSE) && (event->val == KM_RELEASE)) {
+ UI_popover_once_clear(menu->popup_create_vars.arg);
+ block->flag &= ~UI_BLOCK_POPOVER_ONCE;
+ }
+ }
+#endif
+
/* Don't handle double click events, rehandle as regular press/release. */
if (retval == WM_UI_HANDLER_CONTINUE && event->val == KM_DBL_CLICK) {
return retval;
@@ -9117,7 +9216,7 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
submenu->menuretval = 0;
}
- if (block->flag & UI_BLOCK_MOVEMOUSE_QUIT) {
+ if (block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER)) {
/* for cases where close does not cascade, allow the user to
* move the mouse back towards the menu without closing */
ui_mouse_motion_towards_reinit(menu, &event->x);
@@ -9336,7 +9435,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
but = ui_but_find_active_in_region(menu->region);
if (but && (U.pie_menu_confirm > 0) &&
- (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
+ (dist >= U.dpi_fac * (U.pie_menu_threshold + U.pie_menu_confirm)))
{
if (but)
return ui_but_pie_menu_apply(C, menu, but, true);
@@ -9363,7 +9462,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
/* here instead, we use the offset location to account for the initial direction timeout */
if ((U.pie_menu_confirm > 0) &&
- (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
+ (dist >= U.dpi_fac * (U.pie_menu_threshold + U.pie_menu_confirm)))
{
block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT;
copy_v2_v2(block->pie_data.last_pos, event_xy);
@@ -9517,7 +9616,7 @@ static int ui_handle_menus_recursive(
retval = ui_handle_menu_button(C, event, menu);
- if (block->flag & UI_BLOCK_MOVEMOUSE_QUIT) {
+ if (block->flag & (UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_POPOVER)) {
/* when there is a active search button and we close it,
* we need to reinit the mouse coords [#35346] */
if (ui_but_find_active_in_region(menu->region) != but) {
@@ -9680,10 +9779,10 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE
if ((data->state == BUTTON_STATE_MENU_OPEN) &&
(is_inside_menu == false) && /* make sure mouse isn't inside another menu (see T43247) */
- (but->type == UI_BTYPE_PULLDOWN) &&
+ (ELEM(but->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) &&
(but_other = ui_but_find_mouse_over(ar, event)) &&
(but != but_other) &&
- (but->type == but_other->type))
+ (ELEM(but_other->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)))
{
/* if mouse moves to a different root-level menu button,
* open it to replace the current menu */
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index eed7f2ec0f2..36624f475ce 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -33,35 +33,46 @@
#include "MEM_guardedalloc.h"
-#include "GPU_extensions.h"
-#include "GPU_basic_shader.h"
+#include "GPU_draw.h"
+#include "GPU_matrix.h"
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_fileops_types.h"
+#include "BLI_math_vector.h"
#include "DNA_brush_types.h"
#include "DNA_curve_types.h"
#include "DNA_dynamicpaint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_workspace_types.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_paint.h"
#include "BKE_icons.h"
#include "BKE_appdir.h"
+#include "BKE_studiolight.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
+
+#include "DRW_engine.h"
+
#include "ED_datafiles.h"
#include "ED_keyframes_draw.h"
#include "ED_render.h"
@@ -69,6 +80,9 @@
#include "UI_interface.h"
#include "UI_interface_icons.h"
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "interface_intern.h"
#ifndef WITH_HEADLESS
@@ -90,10 +104,15 @@ typedef struct IconImage {
typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
-#define ICON_TYPE_PREVIEW 0
-#define ICON_TYPE_TEXTURE 1
-#define ICON_TYPE_BUFFER 2
-#define ICON_TYPE_VECTOR 3
+#define ICON_TYPE_PREVIEW 0
+#define ICON_TYPE_COLOR_TEXTURE 1
+#define ICON_TYPE_MONO_TEXTURE 2
+#define ICON_TYPE_BUFFER 3
+#define ICON_TYPE_VECTOR 4
+#define ICON_TYPE_GEOM 5
+#define ICON_TYPE_EVENT 6 /* draw keymap entries using custom renderer. */
+#define ICON_TYPE_GPLAYER 7
+#define ICON_TYPE_BLANK 8
typedef struct DrawInfo {
int type;
@@ -104,11 +123,23 @@ typedef struct DrawInfo {
VectorDrawFunc func;
} vector;
struct {
+ ImBuf *image_cache;
+ } geom;
+ struct {
IconImage *image;
} buffer;
struct {
int x, y, w, h;
+ int theme_color;
} texture;
+ struct {
+ /* Can be packed into a single int. */
+ short event_type;
+ short event_value;
+ int icon;
+ /* Allow lookups. */
+ struct DrawInfo *next;
+ } input;
} data;
} DrawInfo;
@@ -120,17 +151,35 @@ typedef struct IconTexture {
float invh;
} IconTexture;
+typedef struct IconType {
+ int type;
+ int theme_color;
+} IconType;
+
/* ******************* STATIC LOCAL VARS ******************* */
/* static here to cache results of icon directory scan, so it's not
* scanning the filesystem each time the menu is drawn */
static struct ListBase iconfilelist = {NULL, NULL};
static IconTexture icongltex = {0, 0, 0, 0.0f, 0.0f};
-/* **************************************************** */
-
#ifndef WITH_HEADLESS
-static DrawInfo *def_internal_icon(ImBuf *bbuf, int icon_id, int xofs, int yofs, int size, int type)
+static const IconType icontypes[] = {
+#define DEF_ICON(name) {ICON_TYPE_MONO_TEXTURE, 0},
+#define DEF_ICON_COLLECTION(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_COLLECTION},
+#define DEF_ICON_OBJECT(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT},
+#define DEF_ICON_OBJECT_DATA(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT_DATA},
+#define DEF_ICON_MODIFIER(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_MODIFIER},
+#define DEF_ICON_SHADING(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SHADING},
+#define DEF_ICON_VECTOR(name) {ICON_TYPE_VECTOR, 0},
+#define DEF_ICON_COLOR(name) {ICON_TYPE_COLOR_TEXTURE, 0},
+#define DEF_ICON_BLANK(name) {ICON_TYPE_BLANK, 0},
+#include "UI_icons.h"
+};
+
+/* **************************************************** */
+
+static DrawInfo *def_internal_icon(ImBuf *bbuf, int icon_id, int xofs, int yofs, int size, int type, int theme_color)
{
Icon *new_icon = NULL;
IconImage *iimg = NULL;
@@ -144,7 +193,8 @@ static DrawInfo *def_internal_icon(ImBuf *bbuf, int icon_id, int xofs, int yofs,
di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
di->type = type;
- if (type == ICON_TYPE_TEXTURE) {
+ if (ELEM(type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) {
+ di->data.texture.theme_color = theme_color;
di->data.texture.x = xofs;
di->data.texture.y = yofs;
di->data.texture.w = size;
@@ -224,22 +274,25 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float
viconutil_set_point(pts[1], cx - d2, cy - d);
viconutil_set_point(pts[2], cx + d2, cy);
- glColor4f(0.2f, 0.2f, 0.2f, alpha);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(0.2f, 0.2f, 0.2f, alpha);
+
+ immBegin(GPU_PRIM_TRIS, 3);
+ immVertex2iv(pos, pts[0]);
+ immVertex2iv(pos, pts[1]);
+ immVertex2iv(pos, pts[2]);
+ immEnd();
- glBegin(GL_TRIANGLES);
- glVertex2iv(pts[0]);
- glVertex2iv(pts[1]);
- glVertex2iv(pts[2]);
- glEnd();
+ immUnbindProgram();
}
-static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type)
+static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type, short handle_type)
{
/* init dummy theme state for Action Editor - where these colors are defined
* (since we're doing this offscreen, free from any particular space_id)
*/
struct bThemeState theme_state;
- int xco, yco;
UI_Theme_Store(&theme_state);
UI_SetTheme(SPACE_ACTION, RGN_TYPE_WINDOW);
@@ -248,42 +301,86 @@ static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha,
* while the draw_keyframe_shape() function needs the midpoint for
* the keyframe
*/
- xco = x + w / 2;
- yco = y + h / 2;
+ float xco = x + w / 2 + 0.5f;
+ float yco = y + h / 2 + 0.5f;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
+
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ GPU_enable_program_point_size();
+ immUniform2f("ViewportSize", -1.0f, -1.0f);
+ immBegin(GPU_PRIM_POINTS, 1);
/* draw keyframe
- * - xscale: 1.0 (since there's no timeline scaling to compensate for)
- * - yscale: 0.3 * h (found out experimentally... dunno why!)
- * - sel: true (so that "keyframe" state shows the iconic yellow icon)
+ * - size: (default icon size == 16, default dopesheet icon size == 10)
+ * - sel: true unless in handletype icons (so that "keyframe" state shows the iconic yellow icon)
*/
- draw_keyframe_shape(xco, yco, 1.0f, 0.3f * h, true, key_type, KEYFRAME_SHAPE_BOTH, alpha);
+ bool sel = (handle_type == KEYFRAME_HANDLE_NONE);
+
+ draw_keyframe_shape(xco, yco, (10.0f / 16.0f) * h, sel, key_type, KEYFRAME_SHAPE_BOTH, alpha,
+ pos_id, size_id, color_id, outline_color_id,
+ flags_id, handle_type, KEYFRAME_EXTREME_NONE);
+
+ immEnd();
+ GPU_disable_program_point_size();
+ immUnbindProgram();
UI_Theme_Restore(&theme_state);
}
static void vicon_keytype_keyframe_draw(int x, int y, int w, int h, float alpha)
{
- vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_NONE);
}
static void vicon_keytype_breakdown_draw(int x, int y, int w, int h, float alpha)
{
- vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_BREAKDOWN);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_BREAKDOWN, KEYFRAME_HANDLE_NONE);
}
static void vicon_keytype_extreme_draw(int x, int y, int w, int h, float alpha)
{
- vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_EXTREME);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_EXTREME, KEYFRAME_HANDLE_NONE);
}
static void vicon_keytype_jitter_draw(int x, int y, int w, int h, float alpha)
{
- vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER, KEYFRAME_HANDLE_NONE);
}
static void vicon_keytype_moving_hold_draw(int x, int y, int w, int h, float alpha)
{
- vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_MOVEHOLD);
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_MOVEHOLD, KEYFRAME_HANDLE_NONE);
+}
+
+static void vicon_handletype_free_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_FREE);
+}
+
+static void vicon_handletype_aligned_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_ALIGNED);
+}
+
+static void vicon_handletype_vector_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_VECTOR);
+}
+
+static void vicon_handletype_auto_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_AUTO);
+}
+
+static void vicon_handletype_auto_clamp_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_AUTO_CLAMP);
}
static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha))
@@ -300,48 +397,75 @@ static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNU
const int b = x + w / 3 * 2;
const int c = x + w;
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* XXX: Include alpha into this... */
/* normal */
- glColor3ubv((unsigned char *)cs->solid);
- glRecti(x, y, a, y + h);
+ immUniformColor3ubv((unsigned char *)cs->solid);
+ immRecti(pos, x, y, a, y + h);
/* selected */
- glColor3ubv((unsigned char *)cs->select);
- glRecti(a, y, b, y + h);
+ immUniformColor3ubv((unsigned char *)cs->select);
+ immRecti(pos, a, y, b, y + h);
/* active */
- glColor3ubv((unsigned char *)cs->active);
- glRecti(b, y, c, y + h);
+ immUniformColor3ubv((unsigned char *)cs->active);
+ immRecti(pos, b, y, c, y + h);
+
+ immUnbindProgram();
}
-#define DEF_VICON_COLORSET_DRAW_NTH(prefix, index) \
+#define DEF_ICON_VECTOR_COLORSET_DRAW_NTH(prefix, index) \
static void vicon_colorset_draw_##prefix(int x, int y, int w, int h, float alpha) \
{ \
vicon_colorset_draw(index, x, y, w, h, alpha); \
}
-DEF_VICON_COLORSET_DRAW_NTH(01, 0)
-DEF_VICON_COLORSET_DRAW_NTH(02, 1)
-DEF_VICON_COLORSET_DRAW_NTH(03, 2)
-DEF_VICON_COLORSET_DRAW_NTH(04, 3)
-DEF_VICON_COLORSET_DRAW_NTH(05, 4)
-DEF_VICON_COLORSET_DRAW_NTH(06, 5)
-DEF_VICON_COLORSET_DRAW_NTH(07, 6)
-DEF_VICON_COLORSET_DRAW_NTH(08, 7)
-DEF_VICON_COLORSET_DRAW_NTH(09, 8)
-DEF_VICON_COLORSET_DRAW_NTH(10, 9)
-DEF_VICON_COLORSET_DRAW_NTH(11, 10)
-DEF_VICON_COLORSET_DRAW_NTH(12, 11)
-DEF_VICON_COLORSET_DRAW_NTH(13, 12)
-DEF_VICON_COLORSET_DRAW_NTH(14, 13)
-DEF_VICON_COLORSET_DRAW_NTH(15, 14)
-DEF_VICON_COLORSET_DRAW_NTH(16, 15)
-DEF_VICON_COLORSET_DRAW_NTH(17, 16)
-DEF_VICON_COLORSET_DRAW_NTH(18, 17)
-DEF_VICON_COLORSET_DRAW_NTH(19, 18)
-DEF_VICON_COLORSET_DRAW_NTH(20, 19)
-
-#undef DEF_VICON_COLORSET_DRAW_NTH
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(01, 0)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(02, 1)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(03, 2)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(04, 3)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(05, 4)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(06, 5)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(07, 6)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(08, 7)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(09, 8)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(10, 9)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(11, 10)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(12, 11)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(13, 12)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(14, 13)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(15, 14)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(16, 15)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(17, 16)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(18, 17)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(19, 18)
+DEF_ICON_VECTOR_COLORSET_DRAW_NTH(20, 19)
+
+#undef DEF_ICON_VECTOR_COLORSET_DRAW_NTH
+
+/* Dynamically render icon instead of rendering a plain color to a texture/buffer
+ * This is mot strictly a "vicon", as it needs access to icon->obj to get the color info,
+ * but it works in a very similar way.
+ */
+static void vicon_gplayer_color_draw(Icon *icon, int x, int y, int w, int h)
+{
+ bGPDlayer *gpl = (bGPDlayer *)icon->obj;
+
+ /* Just draw a colored rect - Like for vicon_colorset_draw() */
+ /* TODO: Make this have rounded corners, and maybe be a bit smaller.
+ * However, UI_draw_roundbox_aa() draws the colors too dark, so can't be used.
+ */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3fv(gpl->color);
+ immRecti(pos, x, y, x + w - 1, y + h - 1);
+
+ immUnbindProgram();
+}
+
#ifndef WITH_HEADLESS
@@ -354,7 +478,7 @@ static void init_brush_icons(void)
int size = datatoc_ ##name## _png_size; \
DrawInfo *di; \
\
- di = def_internal_icon(NULL, icon_id, 0, 0, w, ICON_TYPE_BUFFER); \
+ di = def_internal_icon(NULL, icon_id, 0, 0, w, ICON_TYPE_BUFFER, 0); \
di->data.buffer.image->datatoc_rect = rect; \
di->data.buffer.image->datatoc_size = size; \
}
@@ -362,24 +486,20 @@ static void init_brush_icons(void)
const int w = 96; /* warning, brush size hardcoded in C, but it gets scaled */
- INIT_BRUSH_ICON(ICON_BRUSH_ADD, add);
INIT_BRUSH_ICON(ICON_BRUSH_BLOB, blob);
INIT_BRUSH_ICON(ICON_BRUSH_BLUR, blur);
INIT_BRUSH_ICON(ICON_BRUSH_CLAY, clay);
INIT_BRUSH_ICON(ICON_BRUSH_CLAY_STRIPS, claystrips);
INIT_BRUSH_ICON(ICON_BRUSH_CLONE, clone);
INIT_BRUSH_ICON(ICON_BRUSH_CREASE, crease);
- INIT_BRUSH_ICON(ICON_BRUSH_DARKEN, darken);
INIT_BRUSH_ICON(ICON_BRUSH_SCULPT_DRAW, draw);
INIT_BRUSH_ICON(ICON_BRUSH_FILL, fill);
INIT_BRUSH_ICON(ICON_BRUSH_FLATTEN, flatten);
INIT_BRUSH_ICON(ICON_BRUSH_GRAB, grab);
INIT_BRUSH_ICON(ICON_BRUSH_INFLATE, inflate);
INIT_BRUSH_ICON(ICON_BRUSH_LAYER, layer);
- INIT_BRUSH_ICON(ICON_BRUSH_LIGHTEN, lighten);
INIT_BRUSH_ICON(ICON_BRUSH_MASK, mask);
INIT_BRUSH_ICON(ICON_BRUSH_MIX, mix);
- INIT_BRUSH_ICON(ICON_BRUSH_MULTIPLY, multiply);
INIT_BRUSH_ICON(ICON_BRUSH_NUDGE, nudge);
INIT_BRUSH_ICON(ICON_BRUSH_PINCH, pinch);
INIT_BRUSH_ICON(ICON_BRUSH_SCRAPE, scrape);
@@ -387,17 +507,176 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_SMOOTH, smooth);
INIT_BRUSH_ICON(ICON_BRUSH_SNAKE_HOOK, snake_hook);
INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften);
- INIT_BRUSH_ICON(ICON_BRUSH_SUBTRACT, subtract);
INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw);
INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill);
INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask);
INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb);
INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
- INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw);
+
+ /* grease pencil sculpt */
+ INIT_BRUSH_ICON(ICON_GPBRUSH_SMOOTH, gp_brush_smooth);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_THICKNESS, gp_brush_thickness);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_STRENGTH, gp_brush_strength);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_GRAB, gp_brush_grab);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_PUSH, gp_brush_push);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_TWIST, gp_brush_twist);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_PINCH, gp_brush_pinch);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_RANDOMIZE, gp_brush_randomize);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_CLONE, gp_brush_clone);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_WEIGHT, gp_brush_weight);
+
+ /* grease pencil drawing brushes */
+ INIT_BRUSH_ICON(ICON_GPBRUSH_PENCIL, gp_brush_pencil);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_PEN, gp_brush_pen);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_INK, gp_brush_ink);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_INKNOISE, gp_brush_inknoise);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_BLOCK, gp_brush_block);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_MARKER, gp_brush_marker);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_FILL, gp_brush_fill);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_SOFT, gp_brush_erase_soft);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard);
+ INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke);
#undef INIT_BRUSH_ICON
}
+static DrawInfo *g_di_event_list = NULL;
+
+int UI_icon_from_event_type(short event_type, short event_value)
+{
+ if (event_type == RIGHTSHIFTKEY) {
+ event_type = LEFTSHIFTKEY;
+ }
+ else if (event_type == RIGHTCTRLKEY) {
+ event_type = LEFTCTRLKEY;
+ }
+ else if (event_type == RIGHTALTKEY) {
+ event_type = LEFTALTKEY;
+ }
+ else if (event_type == EVT_TWEAK_L) {
+ event_type = LEFTMOUSE;
+ event_value = KM_CLICK_DRAG;
+ }
+ else if (event_type == EVT_TWEAK_M) {
+ event_type = MIDDLEMOUSE;
+ event_value = KM_CLICK_DRAG;
+ }
+ else if (event_type == EVT_TWEAK_R) {
+ event_type = RIGHTMOUSE;
+ event_value = KM_CLICK_DRAG;
+ }
+
+ DrawInfo *di = g_di_event_list;
+ do {
+ if (di->data.input.event_type == event_type) {
+ return di->data.input.icon;
+ }
+ } while ((di = di->data.input.next));
+
+ if (event_type == LEFTMOUSE) {
+ return ELEM(event_value, KM_CLICK, KM_PRESS) ? ICON_MOUSE_LMB : ICON_MOUSE_LMB_DRAG;
+ }
+ else if (event_type == MIDDLEMOUSE) {
+ return ELEM(event_value, KM_CLICK, KM_PRESS) ? ICON_MOUSE_MMB : ICON_MOUSE_MMB_DRAG;
+ }
+ else if (event_type == RIGHTMOUSE) {
+ return ELEM(event_value, KM_CLICK, KM_PRESS) ? ICON_MOUSE_RMB : ICON_MOUSE_RMB_DRAG;
+ }
+
+ return ICON_NONE;
+}
+
+int UI_icon_from_keymap_item(const wmKeyMapItem *kmi, int r_icon_mod[4])
+{
+ if (r_icon_mod) {
+ memset(r_icon_mod, 0x0, sizeof(int[4]));
+ int i = 0;
+ if (!ELEM(kmi->ctrl, KM_NOTHING, KM_ANY)) {
+ r_icon_mod[i++] = ICON_EVENT_CTRL;
+ }
+ if (!ELEM(kmi->alt, KM_NOTHING, KM_ANY)) {
+ r_icon_mod[i++] = ICON_EVENT_ALT;
+ }
+ if (!ELEM(kmi->shift, KM_NOTHING, KM_ANY)) {
+ r_icon_mod[i++] = ICON_EVENT_SHIFT;
+ }
+ if (!ELEM(kmi->oskey, KM_NOTHING, KM_ANY)) {
+ r_icon_mod[i++] = ICON_EVENT_OS;
+ }
+ }
+ return UI_icon_from_event_type(kmi->type, kmi->val);
+}
+
+static void init_event_icons(void)
+{
+ DrawInfo *di_next = NULL;
+
+#define INIT_EVENT_ICON(icon_id, type, value) \
+ { \
+ DrawInfo *di = def_internal_icon(NULL, icon_id, 0, 0, w, ICON_TYPE_EVENT, 0); \
+ di->data.input.event_type = type; \
+ di->data.input.event_value = value; \
+ di->data.input.icon = icon_id; \
+ di->data.input.next = di_next; \
+ di_next = di; \
+ }
+ /* end INIT_EVENT_ICON */
+
+ const int w = 16; /* DUMMY */
+
+ INIT_EVENT_ICON(ICON_EVENT_A, AKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_B, BKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_C, CKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_D, DKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_E, EKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F, FKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_G, GKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_H, HKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_I, IKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_J, JKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_K, KKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_L, LKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_M, MKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_N, NKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_O, OKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_P, PKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_Q, QKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_R, RKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_S, SKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_T, TKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_U, UKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_V, VKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_W, WKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_X, XKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_Y, YKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_Z, ZKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_SHIFT, LEFTSHIFTKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_CTRL, LEFTCTRLKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_ALT, LEFTALTKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_OS, OSKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F1, F1KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F2, F2KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F3, F3KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F4, F4KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F5, F5KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F6, F6KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F7, F7KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F8, F8KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F9, F9KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F10, F10KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F11, F11KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_F12, F12KEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_ESC, ESCKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_TAB, TABKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_PAGEUP, PAGEUPKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_PAGEDOWN, PAGEDOWNKEY, KM_ANY);
+ INIT_EVENT_ICON(ICON_EVENT_RETURN, RETKEY, KM_ANY);
+
+ g_di_event_list = di_next;
+
+#undef INIT_EVENT_ICON
+}
+
static void icon_verify_datatoc(IconImage *iimg)
{
/* if it has own rect, things are all OK */
@@ -417,54 +696,11 @@ static void icon_verify_datatoc(IconImage *iimg)
}
}
-static void init_matcap_icons(void)
-{
- /* dynamic allocation now, tucking datatoc pointers in DrawInfo */
-#define INIT_MATCAP_ICON(icon_id, name) \
- { \
- unsigned char *rect = (unsigned char *)datatoc_ ##name## _jpg; \
- int size = datatoc_ ##name## _jpg_size; \
- DrawInfo *di; \
- \
- di = def_internal_icon(NULL, icon_id, 0, 0, 96, ICON_TYPE_BUFFER); \
- di->data.buffer.image->datatoc_rect = rect; \
- di->data.buffer.image->datatoc_size = size; \
- } (void)0
-
- INIT_MATCAP_ICON(ICON_MATCAP_01, mc01);
- INIT_MATCAP_ICON(ICON_MATCAP_02, mc02);
- INIT_MATCAP_ICON(ICON_MATCAP_03, mc03);
- INIT_MATCAP_ICON(ICON_MATCAP_04, mc04);
- INIT_MATCAP_ICON(ICON_MATCAP_05, mc05);
- INIT_MATCAP_ICON(ICON_MATCAP_06, mc06);
- INIT_MATCAP_ICON(ICON_MATCAP_07, mc07);
- INIT_MATCAP_ICON(ICON_MATCAP_08, mc08);
- INIT_MATCAP_ICON(ICON_MATCAP_09, mc09);
- INIT_MATCAP_ICON(ICON_MATCAP_10, mc10);
- INIT_MATCAP_ICON(ICON_MATCAP_11, mc11);
- INIT_MATCAP_ICON(ICON_MATCAP_12, mc12);
- INIT_MATCAP_ICON(ICON_MATCAP_13, mc13);
- INIT_MATCAP_ICON(ICON_MATCAP_14, mc14);
- INIT_MATCAP_ICON(ICON_MATCAP_15, mc15);
- INIT_MATCAP_ICON(ICON_MATCAP_16, mc16);
- INIT_MATCAP_ICON(ICON_MATCAP_17, mc17);
- INIT_MATCAP_ICON(ICON_MATCAP_18, mc18);
- INIT_MATCAP_ICON(ICON_MATCAP_19, mc19);
- INIT_MATCAP_ICON(ICON_MATCAP_20, mc20);
- INIT_MATCAP_ICON(ICON_MATCAP_21, mc21);
- INIT_MATCAP_ICON(ICON_MATCAP_22, mc22);
- INIT_MATCAP_ICON(ICON_MATCAP_23, mc23);
- INIT_MATCAP_ICON(ICON_MATCAP_24, mc24);
-
-#undef INIT_MATCAP_ICON
-
-}
-
static void init_internal_icons(void)
{
// bTheme *btheme = UI_GetTheme();
ImBuf *b16buf = NULL, *b32buf = NULL;
- int x, y, icontype;
+ int x, y;
#if 0 // temp disabled
if ((btheme != NULL) && btheme->tui.iconfile[0]) {
@@ -498,94 +734,93 @@ static void init_internal_icons(void)
IMB_premultiply_alpha(b32buf);
if (b16buf && b32buf) {
- /* free existing texture if any */
+ /* Free existing texture if any. */
if (icongltex.id) {
glDeleteTextures(1, &icongltex.id);
icongltex.id = 0;
}
- /* we only use a texture for cards with non-power of two */
- if (GPU_full_non_power_of_two_support()) {
- glGenTextures(1, &icongltex.id);
+ /* Allocate OpenGL texture. */
+ glGenTextures(1, &icongltex.id);
- if (icongltex.id) {
- int level = 2;
+ if (icongltex.id) {
+ int level = 2;
- icongltex.w = b32buf->x;
- icongltex.h = b32buf->y;
- icongltex.invw = 1.0f / b32buf->x;
- icongltex.invh = 1.0f / b32buf->y;
+ icongltex.w = b32buf->x;
+ icongltex.h = b32buf->y;
+ icongltex.invw = 1.0f / b32buf->x;
+ icongltex.invh = 1.0f / b32buf->y;
- glBindTexture(GL_TEXTURE_2D, icongltex.id);
+ glBindTexture(GL_TEXTURE_2D, icongltex.id);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, b32buf->x, b32buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b32buf->rect);
- glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, b32buf->x, b32buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b32buf->rect);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect);
- while (b16buf->x > 1) {
- ImBuf *nbuf = IMB_onehalf(b16buf);
- glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect);
- level++;
- IMB_freeImBuf(b16buf);
- b16buf = nbuf;
- }
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ while (b16buf->x > 1) {
+ ImBuf *nbuf = IMB_onehalf(b16buf);
+ glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect);
+ level++;
+ IMB_freeImBuf(b16buf);
+ b16buf = nbuf;
+ }
- glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- if (glGetError() == GL_OUT_OF_MEMORY) {
- glDeleteTextures(1, &icongltex.id);
- icongltex.id = 0;
- }
- }
+ glBindTexture(GL_TEXTURE_2D, 0);
}
- }
-
- if (icongltex.id)
- icontype = ICON_TYPE_TEXTURE;
- else
- icontype = ICON_TYPE_BUFFER;
- if (b32buf) {
+ /* Define icons. */
for (y = 0; y < ICON_GRID_ROWS; y++) {
+ /* Row W has monochrome icons. */
for (x = 0; x < ICON_GRID_COLS; x++) {
+ IconType icontype = icontypes[y * ICON_GRID_COLS + x];
+ if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) {
+ continue;
+ }
+
def_internal_icon(b32buf, BIFICONID_FIRST + y * ICON_GRID_COLS + x,
x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN,
y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, ICON_GRID_W,
- icontype);
+ icontype.type, icontype.theme_color);
}
}
}
- def_internal_vicon(VICO_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
-
- def_internal_vicon(VICO_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw);
- def_internal_vicon(VICO_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw);
- def_internal_vicon(VICO_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw);
- def_internal_vicon(VICO_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw);
- def_internal_vicon(VICO_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw);
-
- def_internal_vicon(VICO_COLORSET_01_VEC, vicon_colorset_draw_01);
- def_internal_vicon(VICO_COLORSET_02_VEC, vicon_colorset_draw_02);
- def_internal_vicon(VICO_COLORSET_03_VEC, vicon_colorset_draw_03);
- def_internal_vicon(VICO_COLORSET_04_VEC, vicon_colorset_draw_04);
- def_internal_vicon(VICO_COLORSET_05_VEC, vicon_colorset_draw_05);
- def_internal_vicon(VICO_COLORSET_06_VEC, vicon_colorset_draw_06);
- def_internal_vicon(VICO_COLORSET_07_VEC, vicon_colorset_draw_07);
- def_internal_vicon(VICO_COLORSET_08_VEC, vicon_colorset_draw_08);
- def_internal_vicon(VICO_COLORSET_09_VEC, vicon_colorset_draw_09);
- def_internal_vicon(VICO_COLORSET_10_VEC, vicon_colorset_draw_10);
- def_internal_vicon(VICO_COLORSET_11_VEC, vicon_colorset_draw_11);
- def_internal_vicon(VICO_COLORSET_12_VEC, vicon_colorset_draw_12);
- def_internal_vicon(VICO_COLORSET_13_VEC, vicon_colorset_draw_13);
- def_internal_vicon(VICO_COLORSET_14_VEC, vicon_colorset_draw_14);
- def_internal_vicon(VICO_COLORSET_15_VEC, vicon_colorset_draw_15);
- def_internal_vicon(VICO_COLORSET_16_VEC, vicon_colorset_draw_16);
- def_internal_vicon(VICO_COLORSET_17_VEC, vicon_colorset_draw_17);
- def_internal_vicon(VICO_COLORSET_18_VEC, vicon_colorset_draw_18);
- def_internal_vicon(VICO_COLORSET_19_VEC, vicon_colorset_draw_19);
- def_internal_vicon(VICO_COLORSET_20_VEC, vicon_colorset_draw_20);
+ def_internal_vicon(ICON_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
+
+ def_internal_vicon(ICON_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw);
+ def_internal_vicon(ICON_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw);
+ def_internal_vicon(ICON_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw);
+ def_internal_vicon(ICON_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw);
+ def_internal_vicon(ICON_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw);
+
+ def_internal_vicon(ICON_HANDLETYPE_FREE_VEC, vicon_handletype_free_draw);
+ def_internal_vicon(ICON_HANDLETYPE_ALIGNED_VEC, vicon_handletype_aligned_draw);
+ def_internal_vicon(ICON_HANDLETYPE_VECTOR_VEC, vicon_handletype_vector_draw);
+ def_internal_vicon(ICON_HANDLETYPE_AUTO_VEC, vicon_handletype_auto_draw);
+ def_internal_vicon(ICON_HANDLETYPE_AUTO_CLAMP_VEC, vicon_handletype_auto_clamp_draw);
+
+ def_internal_vicon(ICON_COLORSET_01_VEC, vicon_colorset_draw_01);
+ def_internal_vicon(ICON_COLORSET_02_VEC, vicon_colorset_draw_02);
+ def_internal_vicon(ICON_COLORSET_03_VEC, vicon_colorset_draw_03);
+ def_internal_vicon(ICON_COLORSET_04_VEC, vicon_colorset_draw_04);
+ def_internal_vicon(ICON_COLORSET_05_VEC, vicon_colorset_draw_05);
+ def_internal_vicon(ICON_COLORSET_06_VEC, vicon_colorset_draw_06);
+ def_internal_vicon(ICON_COLORSET_07_VEC, vicon_colorset_draw_07);
+ def_internal_vicon(ICON_COLORSET_08_VEC, vicon_colorset_draw_08);
+ def_internal_vicon(ICON_COLORSET_09_VEC, vicon_colorset_draw_09);
+ def_internal_vicon(ICON_COLORSET_10_VEC, vicon_colorset_draw_10);
+ def_internal_vicon(ICON_COLORSET_11_VEC, vicon_colorset_draw_11);
+ def_internal_vicon(ICON_COLORSET_12_VEC, vicon_colorset_draw_12);
+ def_internal_vicon(ICON_COLORSET_13_VEC, vicon_colorset_draw_13);
+ def_internal_vicon(ICON_COLORSET_14_VEC, vicon_colorset_draw_14);
+ def_internal_vicon(ICON_COLORSET_15_VEC, vicon_colorset_draw_15);
+ def_internal_vicon(ICON_COLORSET_16_VEC, vicon_colorset_draw_16);
+ def_internal_vicon(ICON_COLORSET_17_VEC, vicon_colorset_draw_17);
+ def_internal_vicon(ICON_COLORSET_18_VEC, vicon_colorset_draw_18);
+ def_internal_vicon(ICON_COLORSET_19_VEC, vicon_colorset_draw_19);
+ def_internal_vicon(ICON_COLORSET_20_VEC, vicon_colorset_draw_20);
IMB_freeImBuf(b16buf);
IMB_freeImBuf(b32buf);
@@ -717,18 +952,53 @@ void UI_icons_free_drawinfo(void *drawinfo)
MEM_freeN(di->data.buffer.image);
}
}
+ else if (di->type == ICON_TYPE_GEOM) {
+ if (di->data.geom.image_cache) {
+ IMB_freeImBuf(di->data.geom.image_cache);
+ }
+ }
MEM_freeN(di);
}
}
-static DrawInfo *icon_create_drawinfo(void)
+/**
+ * #Icon.data_type and #Icon.obj
+ */
+static DrawInfo *icon_create_drawinfo(Icon *icon)
{
+ int icon_data_type = icon->obj_type;
DrawInfo *di = NULL;
di = MEM_callocN(sizeof(DrawInfo), "di_icon");
- di->type = ICON_TYPE_PREVIEW;
+ if (ELEM(icon_data_type, ICON_DATA_ID, ICON_DATA_PREVIEW)) {
+ di->type = ICON_TYPE_PREVIEW;
+ }
+ else if (icon_data_type == ICON_DATA_GEOM) {
+ di->type = ICON_TYPE_GEOM;
+ }
+ else if (icon_data_type == ICON_DATA_STUDIOLIGHT) {
+ di->type = ICON_TYPE_BUFFER;
+ }
+ else if (icon_data_type == ICON_DATA_GPLAYER) {
+ di->type = ICON_TYPE_GPLAYER;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ return di;
+}
+
+static DrawInfo *icon_ensure_drawinfo(Icon *icon)
+{
+ if (icon->drawinfo) {
+ return icon->drawinfo;
+ }
+ DrawInfo *di = icon_create_drawinfo(icon);
+ icon->drawinfo = di;
+ icon->drawinfo_free = UI_icons_free_drawinfo;
return di;
}
@@ -746,52 +1016,38 @@ int UI_icon_get_width(int icon_id)
return 0;
}
- di = (DrawInfo *)icon->drawinfo;
- if (!di) {
- di = icon_create_drawinfo();
- icon->drawinfo = di;
- }
-
- if (di)
+ di = icon_ensure_drawinfo(icon);
+ if (di) {
return ICON_DEFAULT_WIDTH;
+ }
return 0;
}
int UI_icon_get_height(int icon_id)
{
- Icon *icon = NULL;
- DrawInfo *di = NULL;
-
- icon = BKE_icon_get(icon_id);
-
+ Icon *icon = BKE_icon_get(icon_id);
if (icon == NULL) {
if (G.debug & G_DEBUG)
printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
return 0;
}
- di = (DrawInfo *)icon->drawinfo;
-
- if (!di) {
- di = icon_create_drawinfo();
- icon->drawinfo = di;
- }
-
- if (di)
+ DrawInfo *di = icon_ensure_drawinfo(icon);
+ if (di) {
return ICON_DEFAULT_HEIGHT;
+ }
return 0;
}
-void UI_icons_init(int first_dyn_id)
+void UI_icons_init()
{
- BKE_icons_init(first_dyn_id);
#ifndef WITH_HEADLESS
init_iconfile_list(&iconfilelist);
init_internal_icons();
init_brush_icons();
- init_matcap_icons();
+ init_event_icons();
#endif
}
@@ -831,19 +1087,59 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
static void ui_id_preview_image_render_size(
const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job);
-void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
+static void ui_studiolight_icon_job_exec(void *customdata, short *UNUSED(stop), short *UNUSED(do_update), float *UNUSED(progress))
+{
+ Icon **tmp = (Icon **)customdata;
+ Icon *icon = *tmp;
+ DrawInfo *di = icon_ensure_drawinfo(icon);
+ StudioLight *sl = icon->obj;
+ BKE_studiolight_preview(di->data.buffer.image->rect, sl, icon->id_type);
+}
+
+static void ui_studiolight_kill_icon_preview_job(wmWindowManager *wm, int icon_id)
{
Icon *icon = BKE_icon_get(icon_id);
+ WM_jobs_kill_type(wm, icon, WM_JOB_TYPE_STUDIOLIGHT);
+ icon->obj = NULL;
+}
- if (icon) {
- DrawInfo *di = (DrawInfo *)icon->drawinfo;
+static void ui_studiolight_free_function(StudioLight *sl, void *data)
+{
+ wmWindowManager *wm = data;
- if (!di) {
- di = icon_create_drawinfo();
+ /* Happens if job was canceled or already finished. */
+ if (wm == NULL)
+ return;
- icon->drawinfo = di;
- icon->drawinfo_free = UI_icons_free_drawinfo;
- }
+ // get icons_id, get icons and kill wm jobs
+ if (sl->icon_id_radiance) {
+ ui_studiolight_kill_icon_preview_job(wm, sl->icon_id_radiance);
+ }
+ if (sl->icon_id_irradiance) {
+ ui_studiolight_kill_icon_preview_job(wm, sl->icon_id_irradiance);
+ }
+ if (sl->icon_id_matcap) {
+ ui_studiolight_kill_icon_preview_job(wm, sl->icon_id_matcap);
+ }
+ if (sl->icon_id_matcap_flipped) {
+ ui_studiolight_kill_icon_preview_job(wm, sl->icon_id_matcap_flipped);
+ }
+}
+
+static void ui_studiolight_icon_job_end(void *customdata)
+{
+ Icon **tmp = (Icon **)customdata;
+ Icon *icon = *tmp;
+ StudioLight *sl = icon->obj;
+ BKE_studiolight_set_free_function(sl, &ui_studiolight_free_function, NULL);
+}
+
+void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
+{
+ Icon *icon = BKE_icon_get(icon_id);
+
+ if (icon) {
+ DrawInfo *di = icon_ensure_drawinfo(icon);
if (di) {
switch (di->type) {
@@ -851,12 +1147,42 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi
{
ID *id = (icon->id_type != 0) ? icon->obj : NULL;
PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj;
+ /* Using jobs for screen previews crashes due to offscreen rendering.
+ * XXX would be nicer if PreviewImage could store if it supports jobs */
+ const bool use_jobs = !id || (GS(id->name) != ID_SCR);
if (prv) {
const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON;
if (id || (prv->tag & PRV_TAG_DEFFERED) != 0) {
- ui_id_preview_image_render_size(C, NULL, id, prv, size, true);
+ ui_id_preview_image_render_size(C, NULL, id, prv, size, use_jobs);
+ }
+ }
+ break;
+ }
+ case ICON_TYPE_BUFFER:
+ {
+ if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
+ if (di->data.buffer.image == NULL) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ StudioLight *sl = icon->obj;
+ BKE_studiolight_set_free_function(sl, &ui_studiolight_free_function, wm);
+ IconImage *img = MEM_mallocN(sizeof(IconImage), __func__);
+
+ img->w = STUDIOLIGHT_ICON_SIZE;
+ img->h = STUDIOLIGHT_ICON_SIZE;
+ size_t size = STUDIOLIGHT_ICON_SIZE * STUDIOLIGHT_ICON_SIZE * sizeof(uint);
+ img->rect = MEM_mallocN(size, __func__);
+ memset(img->rect, 0, size);
+ di->data.buffer.image = img;
+
+ wmJob *wm_job = WM_jobs_get(wm, CTX_wm_window(C), icon, "StudioLight Icon", 0, WM_JOB_TYPE_STUDIOLIGHT);
+ Icon **tmp = MEM_callocN(sizeof(Icon *), __func__);
+ *tmp = icon;
+ WM_jobs_customdata_set(wm_job, tmp, MEM_freeN);
+ WM_jobs_timer(wm_job, 0.01, 0, NC_WINDOW);
+ WM_jobs_callbacks(wm_job, ui_studiolight_icon_job_exec, NULL, NULL, ui_studiolight_icon_job_end);
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
}
}
break;
@@ -936,7 +1262,7 @@ PreviewImage *UI_icon_to_preview(int icon_id)
}
static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect), int rw, int rh,
- unsigned int *rect, float alpha, const float rgb[3], const bool is_preview)
+ unsigned int *rect, float alpha, const float rgb[3], const float desaturate)
{
ImBuf *ima = NULL;
int draw_w = w;
@@ -950,15 +1276,13 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
BLI_assert(!"invalid icon size");
return;
}
-
/* modulate color */
- if (alpha != 1.0f)
- glPixelTransferf(GL_ALPHA_SCALE, alpha);
+ float col[4] = {1.0f, 1.0f, 1.0f, alpha};
if (rgb) {
- glPixelTransferf(GL_RED_SCALE, rgb[0]);
- glPixelTransferf(GL_GREEN_SCALE, rgb[1]);
- glPixelTransferf(GL_BLUE_SCALE, rgb[2]);
+ col[0] = rgb[0];
+ col[1] = rgb[1];
+ col[2] = rgb[2];
}
/* rect contains image in 'rendersize', we only scale if needed */
@@ -983,72 +1307,170 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
rect = ima->rect;
}
+ /* We need to flush widget base first to ensure correct ordering. */
+ UI_widgetbase_draw_cache_flush();
+
/* draw */
- if (is_preview) {
- glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ GPUBuiltinShader shader;
+ if (desaturate != 0.0f) {
+ shader = GPU_SHADER_2D_IMAGE_DESATURATE_COLOR;
}
else {
- int bound_options;
- GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
-
- glRasterPos2f(draw_x, draw_y);
- glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ shader = GPU_SHADER_2D_IMAGE_COLOR;
+ }
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(shader);
- GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
+ if (shader == GPU_SHADER_2D_IMAGE_DESATURATE_COLOR) {
+ immUniform1f("factor", desaturate);
}
+ immDrawPixelsTex(&state, draw_x, draw_y, draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, rect,
+ 1.0f, 1.0f, col);
+
if (ima)
IMB_freeImBuf(ima);
+}
+
+/* High enough to make a difference, low enough so that
+ * small draws are still efficient with the use of glUniform.
+ * NOTE TODO: We could use UBO but we would need some triple
+ * buffer system + persistent mapping for this to be more
+ * efficient than simple glUniform calls. */
+#define ICON_DRAW_CACHE_SIZE 16
+
+typedef struct IconDrawCall {
+ rctf pos;
+ rctf tex;
+ float color[4];
+} IconDrawCall;
+
+static struct {
+ IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE];
+ int calls; /* Number of calls batched together */
+ bool enabled;
+ float mat[4][4];
+} g_icon_draw_cache = {{{{0}}}};
+
+void UI_icon_draw_cache_begin(void)
+{
+ BLI_assert(g_icon_draw_cache.enabled == false);
+ g_icon_draw_cache.enabled = true;
+}
- /* restore color */
- if (alpha != 0.0f)
- glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
+static void icon_draw_cache_flush_ex(void)
+{
+ if (g_icon_draw_cache.calls == 0)
+ return;
- if (rgb) {
- glPixelTransferf(GL_RED_SCALE, 1.0f);
- glPixelTransferf(GL_GREEN_SCALE, 1.0f);
- glPixelTransferf(GL_BLUE_SCALE, 1.0f);
+ /* We need to flush widget base first to ensure correct ordering. */
+ UI_widgetbase_draw_cache_flush();
+
+ GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, icongltex.id);
+
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
+ GPU_shader_bind(shader);
+
+ int img_loc = GPU_shader_get_uniform(shader, "image");
+ int data_loc = GPU_shader_get_uniform(shader, "calls_data[0]");
+
+ glUniform1i(img_loc, 0);
+ glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)g_icon_draw_cache.drawcall_cache);
+
+ GPU_draw_primitive(GPU_PRIM_TRIS, 6 * g_icon_draw_cache.calls);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ g_icon_draw_cache.calls = 0;
+
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+}
+
+void UI_icon_draw_cache_end(void)
+{
+ BLI_assert(g_icon_draw_cache.enabled == true);
+ g_icon_draw_cache.enabled = false;
+
+ /* Don't change blend state if it's not needed. */
+ if (g_icon_draw_cache.calls == 0)
+ return;
+
+ GPU_blend(true);
+ icon_draw_cache_flush_ex();
+ GPU_blend(false);
+}
+
+static void icon_draw_texture_cached(
+ float x, float y, float w, float h, int ix, int iy,
+ int UNUSED(iw), int ih, float alpha, const float rgb[3])
+{
+
+ float mvp[4][4];
+ GPU_matrix_model_view_projection_get(mvp);
+
+ IconDrawCall *call = &g_icon_draw_cache.drawcall_cache[g_icon_draw_cache.calls];
+ g_icon_draw_cache.calls++;
+
+ /* Manual mat4*vec2 */
+ call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0];
+ call->pos.ymin = x * mvp[0][1] + y * mvp[1][1] + mvp[3][1];
+ call->pos.xmax = call->pos.xmin + w * mvp[0][0] + h * mvp[1][0];
+ call->pos.ymax = call->pos.ymin + w * mvp[0][1] + h * mvp[1][1];
+
+ call->tex.xmin = ix * icongltex.invw;
+ call->tex.xmax = (ix + ih) * icongltex.invw;
+ call->tex.ymin = iy * icongltex.invh;
+ call->tex.ymax = (iy + ih) * icongltex.invh;
+
+ if (rgb) copy_v4_fl4(call->color, rgb[0], rgb[1], rgb[2], alpha);
+ else copy_v4_fl(call->color, alpha);
+
+ if (g_icon_draw_cache.calls == ICON_DRAW_CACHE_SIZE) {
+ icon_draw_cache_flush_ex();
}
}
static void icon_draw_texture(
float x, float y, float w, float h, int ix, int iy,
- int UNUSED(iw), int ih, float alpha, const float rgb[3])
+ int iw, int ih, float alpha, const float rgb[3])
{
- float x1, x2, y1, y2;
+ if (g_icon_draw_cache.enabled) {
+ icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb);
+ return;
+ }
- if (rgb) glColor4f(rgb[0], rgb[1], rgb[2], alpha);
- else glColor4f(alpha, alpha, alpha, alpha);
+ /* We need to flush widget base first to ensure correct ordering. */
+ UI_widgetbase_draw_cache_flush();
+
+ GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ float x1, x2, y1, y2;
x1 = ix * icongltex.invw;
x2 = (ix + ih) * icongltex.invw;
y1 = iy * icongltex.invh;
y2 = (iy + ih) * icongltex.invh;
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, icongltex.id);
- /* sharper downscaling, has no effect when scale matches with a mip level */
- glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -0.5f);
-
- glBegin(GL_QUADS);
- glTexCoord2f(x1, y1);
- glVertex2f(x, y);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
+ GPU_shader_bind(shader);
- glTexCoord2f(x2, y1);
- glVertex2f(x + w, y);
+ if (rgb) glUniform4f(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), rgb[0], rgb[1], rgb[2], alpha);
+ else glUniform4f(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), alpha, alpha, alpha, alpha);
- glTexCoord2f(x2, y2);
- glVertex2f(x + w, y + h);
+ glUniform1i(GPU_shader_get_uniform(shader, "image"), 0);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), x1, y1, x2, y2);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), x, y, x + w, y + h);
- glTexCoord2f(x1, y2);
- glVertex2f(x, y + h);
- glEnd();
-
- glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f);
+ GPU_draw_primitive(GPU_PRIM_TRI_STRIP, 4);
glBindTexture(GL_TEXTURE_2D, 0);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
}
/* Drawing size for preview images */
@@ -1068,11 +1490,10 @@ static int get_draw_size(enum eIconSizes size)
static void icon_draw_size(
float x, float y, int icon_id, float aspect, float alpha, const float rgb[3],
- enum eIconSizes size, int draw_size, const bool UNUSED(nocreate), const bool is_preview)
+ enum eIconSizes size, int draw_size, const float desaturate, const char mono_rgba[4])
{
bTheme *btheme = UI_GetTheme();
Icon *icon = NULL;
- DrawInfo *di = NULL;
IconImage *iimg;
const float fdraw_size = (float)draw_size;
int w, h;
@@ -1086,31 +1507,82 @@ static void icon_draw_size(
return;
}
- di = (DrawInfo *)icon->drawinfo;
-
- if (!di) {
- di = icon_create_drawinfo();
-
- icon->drawinfo = di;
- icon->drawinfo_free = UI_icons_free_drawinfo;
- }
-
/* scale width and height according to aspect */
w = (int)(fdraw_size / aspect + 0.5f);
h = (int)(fdraw_size / aspect + 0.5f);
+ DrawInfo *di = icon_ensure_drawinfo(icon);
+
if (di->type == ICON_TYPE_VECTOR) {
+ /* We need to flush widget base first to ensure correct ordering. */
+ UI_widgetbase_draw_cache_flush();
/* vector icons use the uiBlock transformation, they are not drawn
* with untransformed coordinates like the other icons */
di->data.vector.func((int)x, (int)y, w, h, 1.0f);
}
- else if (di->type == ICON_TYPE_TEXTURE) {
+ else if (di->type == ICON_TYPE_GEOM) {
+ /* We need to flush widget base first to ensure correct ordering. */
+ UI_widgetbase_draw_cache_flush();
+
+#ifdef USE_UI_TOOLBAR_HACK
+ /* TODO(campbell): scale icons up for toolbar, we need a way to detect larger buttons and do this automatic. */
+ {
+ float scale = (float)ICON_DEFAULT_HEIGHT_TOOLBAR / (float)ICON_DEFAULT_HEIGHT;
+ y = (y + (h / 2)) - ((h * scale) / 2);
+ w *= scale;
+ h *= scale;
+ }
+#endif
+
+ /* This could re-generate often if rendered at different sizes in the one interface.
+ * TODO(campbell): support caching multiple sizes. */
+ ImBuf *ibuf = di->data.geom.image_cache;
+ if ((ibuf == NULL) ||
+ (ibuf->x != w) ||
+ (ibuf->y != h))
+ {
+ if (ibuf) {
+ IMB_freeImBuf(ibuf);
+ }
+ ibuf = BKE_icon_geom_rasterize(icon->obj, w, h);
+ di->data.geom.image_cache = ibuf;
+ }
+ glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, rgb, desaturate);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ }
+ else if (di->type == ICON_TYPE_EVENT) {
+ const short event_type = di->data.input.event_type;
+ const short event_value = di->data.input.event_value;
+ icon_draw_rect_input(x, y, w, h, alpha, event_type, event_value);
+ }
+ else if (di->type == ICON_TYPE_COLOR_TEXTURE) {
/* texture image use premul alpha for correct scaling */
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
icon_draw_texture(x, y, (float)w, (float)h, di->data.texture.x, di->data.texture.y,
di->data.texture.w, di->data.texture.h, alpha, rgb);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
+ else if (di->type == ICON_TYPE_MONO_TEXTURE) {
+ /* icon that matches text color, assumed to be white */
+ float color[4];
+ if (!UI_GetIconThemeColor4fv(di->data.texture.theme_color, color)) {
+ if (mono_rgba) {
+ rgba_uchar_to_float(color, (const uchar *)mono_rgba);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_TEXT, color);
+ }
+ }
+
+ if (rgb) {
+ mul_v3_v3(color, rgb);
+ }
+
+ mul_v4_fl(color, alpha);
+
+ icon_draw_texture(x, y, (float)w, (float)h, di->data.texture.x, di->data.texture.y,
+ di->data.texture.w, di->data.texture.h, color[3], color);
+ }
+
else if (di->type == ICON_TYPE_BUFFER) {
/* it is a builtin icon */
iimg = di->data.buffer.image;
@@ -1119,9 +1591,9 @@ static void icon_draw_size(
#endif
if (!iimg->rect) return; /* something has gone wrong! */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, rgb, is_preview);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, rgb, desaturate);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
}
else if (di->type == ICON_TYPE_PREVIEW) {
PreviewImage *pi = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
@@ -1131,12 +1603,23 @@ static void icon_draw_size(
if (!pi->rect[size]) return; /* something has gone wrong! */
/* preview images use premul alpha ... */
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, is_preview);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, desaturate);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
}
}
+ else if (di->type == ICON_TYPE_GPLAYER) {
+ BLI_assert(icon->obj != NULL);
+
+ /* We need to flush widget base first to ensure correct ordering. */
+ UI_widgetbase_draw_cache_flush();
+
+ /* Just draw a colored rect - Like for vicon_colorset_draw() */
+#ifndef WITH_HEADLESS
+ vicon_gplayer_color_draw(icon, (int)x, (int)y, w, h);
+#endif
+ }
}
static void ui_id_preview_image_render_size(
@@ -1162,7 +1645,7 @@ void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big,
}
}
-static void ui_id_brush_render(const bContext *C, ID *id)
+static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs)
{
PreviewImage *pi = BKE_previewimg_id_ensure(id);
enum eIconSizes i;
@@ -1174,7 +1657,7 @@ static void ui_id_brush_render(const bContext *C, ID *id)
/* check if rect needs to be created; changed
* only set by dynamic icons */
if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) {
- icon_set_image(C, NULL, id, pi, i, true);
+ icon_set_image(C, NULL, id, pi, i, use_jobs);
pi->flag[i] &= ~PRV_CHANGED;
}
}
@@ -1187,53 +1670,120 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
if (br->flag & BRUSH_CUSTOM_ICON) {
BKE_icon_id_ensure(id);
- ui_id_brush_render(C, id);
+ ui_id_icon_render(C, id, true);
}
else {
+ WorkSpace *workspace = CTX_wm_workspace(C);
Object *ob = CTX_data_active_object(C);
- SpaceImage *sima;
const EnumPropertyItem *items = NULL;
- int tool = PAINT_TOOL_DRAW, mode = 0;
+ ePaintMode paint_mode = PAINT_MODE_INVALID;
+ ScrArea *sa = CTX_wm_area(C);
+ char space_type = sa->spacetype;
+ /* When in an unsupported space. */
+ if (!ELEM(space_type, SPACE_VIEW3D, SPACE_IMAGE)) {
+ space_type = workspace->tools_space_type;
+ }
/* XXX: this is not nice, should probably make brushes
* be strictly in one paint mode only to avoid
* checking various context stuff here */
- if (CTX_wm_view3d(C) && ob) {
- if (ob->mode & OB_MODE_SCULPT)
- mode = OB_MODE_SCULPT;
- else if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT))
- mode = OB_MODE_VERTEX_PAINT;
- else if (ob->mode & OB_MODE_TEXTURE_PAINT)
- mode = OB_MODE_TEXTURE_PAINT;
+ if ((space_type == SPACE_VIEW3D) && ob) {
+ if (ob->mode & OB_MODE_SCULPT) {
+ paint_mode = PAINT_MODE_SCULPT;
+ }
+ else if (ob->mode & OB_MODE_VERTEX_PAINT) {
+ paint_mode = PAINT_MODE_VERTEX;
+ }
+ else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ paint_mode = PAINT_MODE_WEIGHT;
+ }
+ else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ paint_mode = PAINT_MODE_TEXTURE_3D;
+ }
}
- else if ((sima = CTX_wm_space_image(C)) &&
- (sima->mode == SI_MODE_PAINT))
- {
- mode = OB_MODE_TEXTURE_PAINT;
+ else if (space_type == SPACE_IMAGE) {
+ int sima_mode;
+ if (sa->spacetype == space_type) {
+ SpaceImage *sima = sa->spacedata.first;
+ sima_mode = sima->mode;
+ }
+ else {
+ sima_mode = workspace->tools_mode;
+ }
+
+ if (sima_mode == SI_MODE_PAINT) {
+ paint_mode = PAINT_MODE_TEXTURE_2D;
+ }
}
/* reset the icon */
- if (mode == OB_MODE_SCULPT) {
- items = rna_enum_brush_sculpt_tool_items;
- tool = br->sculpt_tool;
- }
- else if (mode == OB_MODE_VERTEX_PAINT) {
- items = rna_enum_brush_vertex_tool_items;
- tool = br->vertexpaint_tool;
+ if ((ob != NULL) &&
+ (ob->mode & OB_MODE_GPENCIL_PAINT) &&
+ (br->gpencil_settings != NULL))
+ {
+ switch (br->gpencil_settings->icon_id) {
+ case GP_BRUSH_ICON_PENCIL:
+ br->id.icon_id = ICON_GPBRUSH_PENCIL;
+ break;
+ case GP_BRUSH_ICON_PEN:
+ br->id.icon_id = ICON_GPBRUSH_PEN;
+ break;
+ case GP_BRUSH_ICON_INK:
+ br->id.icon_id = ICON_GPBRUSH_INK;
+ break;
+ case GP_BRUSH_ICON_INKNOISE:
+ br->id.icon_id = ICON_GPBRUSH_INKNOISE;
+ break;
+ case GP_BRUSH_ICON_BLOCK:
+ br->id.icon_id = ICON_GPBRUSH_BLOCK;
+ break;
+ case GP_BRUSH_ICON_MARKER:
+ br->id.icon_id = ICON_GPBRUSH_MARKER;
+ break;
+ case GP_BRUSH_ICON_FILL:
+ br->id.icon_id = ICON_GPBRUSH_FILL;
+ break;
+ case GP_BRUSH_ICON_ERASE_SOFT:
+ br->id.icon_id = ICON_GPBRUSH_ERASE_SOFT;
+ break;
+ case GP_BRUSH_ICON_ERASE_HARD:
+ br->id.icon_id = ICON_GPBRUSH_ERASE_HARD;
+ break;
+ case GP_BRUSH_ICON_ERASE_STROKE:
+ br->id.icon_id = ICON_GPBRUSH_ERASE_STROKE;
+ break;
+ default:
+ br->id.icon_id = ICON_GPBRUSH_PEN;
+ break;
+ }
+ return id->icon_id;
}
- else if (mode == OB_MODE_TEXTURE_PAINT) {
- items = rna_enum_brush_image_tool_items;
- tool = br->imagepaint_tool;
+ else if (paint_mode != PAINT_MODE_INVALID) {
+ items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ const uint tool_offset = BKE_paint_get_brush_tool_offset_from_paintmode(paint_mode);
+ const int tool_type = *(char *)POINTER_OFFSET(br, tool_offset);
+ if (!items || !RNA_enum_icon_from_value(items, tool_type, &id->icon_id)) {
+ id->icon_id = 0;
+ }
}
-
- if (!items || !RNA_enum_icon_from_value(items, tool, &id->icon_id))
+ else {
id->icon_id = 0;
+ }
}
return id->icon_id;
}
+static int ui_id_screen_get_icon(const bContext *C, ID *id)
+{
+ BKE_icon_id_ensure(id);
+ /* Don't use jobs here, offscreen rendering doesn't like this and crashes. */
+ ui_id_icon_render(C, id, false);
+
+ return id->icon_id;
+}
+
int ui_id_icon_get(const bContext *C, ID *id, const bool big)
{
int iconid = 0;
@@ -1252,6 +1802,9 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big)
/* checks if not exists, or changed */
UI_id_icon_render(C, NULL, id, big, true);
break;
+ case ID_SCR:
+ iconid = ui_id_screen_get_icon(C, id);
+ break;
default:
break;
}
@@ -1277,15 +1830,27 @@ int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, const bool big
id = RNA_pointer_get(ptr, "texture").data;
}
else if (RNA_struct_is_a(ptr->type, &RNA_DynamicPaintSurface)) {
- DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
+ DynamicPaintSurface *surface = ptr->data;
if (surface->format == MOD_DPAINT_SURFACE_F_PTEX)
- return ICON_TEXTURE_SHADED;
+ return ICON_SHADING_TEXTURE;
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX)
return ICON_OUTLINER_DATA_MESH;
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
return ICON_FILE_IMAGE;
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_StudioLight)) {
+ StudioLight *sl = ptr->data;
+ switch (sl->flag & STUDIOLIGHT_FLAG_ORIENTATIONS) {
+ case STUDIOLIGHT_TYPE_STUDIO:
+ return sl->icon_id_irradiance;
+ case STUDIOLIGHT_TYPE_WORLD:
+ default:
+ return sl->icon_id_radiance;
+ case STUDIOLIGHT_TYPE_MATCAP:
+ return sl->icon_id_matcap;
+ }
+ }
/* get icon from ID */
if (id) {
@@ -1319,7 +1884,7 @@ int UI_idcode_icon_get(const int idcode)
case ID_IM:
return ICON_IMAGE_DATA;
case ID_LA:
- return ICON_LAMP_DATA;
+ return ICON_LIGHT_DATA;
case ID_LS:
return ICON_LINE_DATA;
case ID_LT:
@@ -1344,6 +1909,8 @@ int UI_idcode_icon_get(const int idcode)
return ICON_COLOR; /* TODO! this would need its own icon! */
case ID_PC:
return ICON_CURVE_BEZCURVE; /* TODO! this would need its own icon! */
+ case ID_LP:
+ return ICON_LIGHTPROBE_CUBEMAP;
case ID_SCE:
return ICON_SCENE_DATA;
case ID_SPK:
@@ -1365,45 +1932,55 @@ int UI_idcode_icon_get(const int idcode)
static void icon_draw_at_size(
float x, float y, int icon_id, float aspect, float alpha,
- enum eIconSizes size, const bool nocreate)
+ enum eIconSizes size, const float desaturate, const char mono_color[4])
{
int draw_size = get_draw_size(size);
- icon_draw_size(x, y, icon_id, aspect, alpha, NULL, size, draw_size, nocreate, false);
+ icon_draw_size(x, y, icon_id, aspect, alpha, NULL, size, draw_size, desaturate, mono_color);
}
-void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha)
+void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha, const char mono_color[4])
{
- icon_draw_at_size(x, y, icon_id, aspect, alpha, ICON_SIZE_ICON, 0);
+ icon_draw_at_size(x, y, icon_id, aspect, alpha, ICON_SIZE_ICON, 0.0f, mono_color);
}
-void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, const float rgb[3])
+void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, const float rgb[3], const char mono_color[4])
{
int draw_size = get_draw_size(ICON_SIZE_ICON);
- icon_draw_size(x, y, icon_id, aspect, 1.0f, rgb, ICON_SIZE_ICON, draw_size, false, false);
+ icon_draw_size(x, y, icon_id, aspect, 1.0f, rgb, ICON_SIZE_ICON, draw_size, false, mono_color);
+}
+
+void UI_icon_draw_desaturate(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const char mono_color[4])
+{
+ icon_draw_at_size(x, y, icon_id, aspect, alpha, ICON_SIZE_ICON, desaturate, mono_color);
}
/* draws icon with dpi scale factor */
void UI_icon_draw(float x, float y, int icon_id)
{
- UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, 1.0f);
+ UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, 1.0f, NULL);
+}
+
+void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha)
+{
+ UI_icon_draw_aspect(x, y, icon_id, 1.0f / UI_DPI_FAC, alpha, NULL);
}
void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha)
{
- icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, ICON_SIZE_ICON, size, true, false);
+ icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, ICON_SIZE_ICON, size, false, NULL);
}
void UI_icon_draw_preview(float x, float y, int icon_id)
{
- icon_draw_at_size(x, y, icon_id, 1.0f, 1.0f, ICON_SIZE_PREVIEW, 0);
+ icon_draw_at_size(x, y, icon_id, 1.0f, 1.0f, ICON_SIZE_PREVIEW, false, NULL);
}
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
{
- icon_draw_at_size(x, y, icon_id, aspect, 1.0f, ICON_SIZE_PREVIEW, 0);
+ icon_draw_at_size(x, y, icon_id, aspect, 1.0f, ICON_SIZE_PREVIEW, false, NULL);
}
void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, float alpha, int size)
{
- icon_draw_size(x, y, icon_id, aspect, alpha, NULL, ICON_SIZE_PREVIEW, size, false, true);
+ icon_draw_size(x, y, icon_id, aspect, alpha, NULL, ICON_SIZE_PREVIEW, size, false, NULL);
}
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
new file mode 100644
index 00000000000..598adcce87f
--- /dev/null
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -0,0 +1,296 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_icons_event.c
+ * \ingroup edinterface
+ *
+ * A special set of icons to represent input devices,
+ * this is a mix of text (via fonts) and a handful of custom glyphs for special keys.
+ *
+ * Event codes are used as identifiers.
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_draw.h"
+#include "GPU_matrix.h"
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_fileops_types.h"
+#include "BLI_math_vector.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_dynamicpaint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_workspace_types.h"
+
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_icons.h"
+#include "BKE_appdir.h"
+#include "BKE_studiolight.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
+
+#include "BIF_glutil.h"
+#include "BLF_api.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DRW_engine.h"
+
+#include "ED_datafiles.h"
+#include "ED_keyframes_draw.h"
+#include "ED_render.h"
+
+#include "UI_interface.h"
+#include "UI_interface_icons.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "interface_intern.h"
+
+static void icon_draw_rect_input_small_text_ex(
+ const rctf *rect, const float color[4], const float margin[2], const char *str,
+ int font_size)
+{
+ BLF_batch_draw_flush();
+ const int font_id = BLF_default();
+ BLF_color4fv(font_id, color);
+ BLF_size(font_id, font_size * U.pixelsize, U.dpi);
+ BLF_position(font_id, rect->xmin + margin[0] * 2, rect->ymin + margin[1] * 5, 0.0f);
+ BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_batch_draw_flush();
+}
+
+static void icon_draw_rect_input_small_text(
+ const rctf *rect, const float color[4], const float margin[2], const char *str)
+{
+ icon_draw_rect_input_small_text_ex(rect, color, margin, str, 8);
+}
+
+static void icon_draw_rect_input_default_text(
+ const rctf *rect,
+ const float color[4], const float margin[2], const char *str)
+{
+ BLF_batch_draw_flush();
+ const int font_id = BLF_default();
+ BLF_color4fv(font_id, color);
+ BLF_position(font_id, (int)(rect->xmin + margin[0] * 5), (int)(rect->ymin + margin[1] * 5), 0.0f);
+ BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_batch_draw_flush();
+}
+
+static void icon_draw_rect_input_mono_text(
+ const rctf *rect,
+ const float color[4], const float margin[2], const char *str)
+{
+ BLF_batch_draw_flush();
+ const int font_id = blf_mono_font;
+ BLF_color4fv(font_id, color);
+ BLF_size(font_id, 20 * U.pixelsize, U.dpi);
+ BLF_position(font_id, (int)(rect->xmin + margin[0] * 5), (int)(rect->ymin + margin[1] * 5), 0.0f);
+ BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_batch_draw_flush();
+}
+
+static void icon_draw_rect_input_line_prim(
+ const rctf *rect,
+ const float color[4],
+ const int prim,
+ const char lines[][2], int lines_len)
+{
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ BLI_assert(ELEM(prim, GPU_PRIM_LINE_LOOP, GPU_PRIM_LINE_STRIP));
+ const uint pos_id = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+ immBegin(prim, lines_len);
+ float w_inv = BLI_rctf_size_x(rect) / 255.0f;
+ float h_inv = BLI_rctf_size_y(rect) / 255.0f;
+ for (int i = 0; i < lines_len; i++) {
+ immVertex2f(
+ pos_id,
+ round_fl_to_int(rect->xmin + ((float)lines[i][0] * w_inv)),
+ round_fl_to_int(rect->ymin + ((float)lines[i][1] * h_inv))
+ );
+ }
+ immEnd();
+ immUnbindProgram();
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_BLEND);
+}
+
+void icon_draw_rect_input(
+ float x, float y, int w, int h, float UNUSED(alpha),
+ short event_type, short UNUSED(event_value))
+{
+ float color[4];
+ const float margin[2] = {w / 20.0f, h / 20.0f};
+ GPU_line_width(1.0f);
+ UI_GetThemeColor4fv(TH_TEXT, color);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_aa(
+ false,
+ (int)x,
+ (int)y,
+ (int)(x + w),
+ (int)(y + h), 4.0f, color
+ );
+
+ const rctf rect = {
+ .xmin = x,
+ .ymin = y,
+ .xmax = x + w,
+ .ymax = y + h,
+ };
+
+ const bool simple_text = false;
+
+ if ((event_type >= AKEY) || (ZKEY <= event_type)) {
+ char str[2] = {'A' + (event_type - AKEY), '\0'};
+ icon_draw_rect_input_default_text(&rect, color, margin, str);
+ }
+ if ((event_type >= F1KEY) || (F12KEY <= event_type)) {
+ char str[3] = {'F', '1' + (event_type - F1KEY), '\0'};
+ icon_draw_rect_input_default_text(&rect, color, margin, str);
+ }
+ else if (event_type == LEFTSHIFTKEY) {
+ if (simple_text) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "Shift");
+ }
+ else {
+ rctf rect_ofs = rect;
+ BLI_rctf_translate(&rect_ofs, (w / -14.0f), (w / -14.0f));
+ icon_draw_rect_input_mono_text(&rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa7, 0x0});
+ }
+ }
+ else if (event_type == LEFTCTRLKEY) {
+ if (simple_text) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "Ctrl");
+ }
+ else {
+ rctf rect_ofs = rect;
+ BLI_rctf_translate(&rect_ofs, (w / -16.0f), 0.0f);
+ icon_draw_rect_input_default_text(&rect_ofs, color, margin, "^");
+ }
+ }
+ else if (event_type == LEFTALTKEY) {
+ if (simple_text) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "Alt");
+ }
+ else {
+ rctf rect_ofs = rect;
+ BLI_rctf_translate(&rect_ofs, (w / -8.0f), 0.0f);
+ icon_draw_rect_input_default_text(&rect_ofs, color, margin, (const char[]){0xe2, 0x8c, 0xa5, 0x0});
+ }
+ }
+ else if (event_type == OSKEY) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "OS");
+ }
+ else if (event_type == DELKEY) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "Del");
+ }
+ else if (event_type == TABKEY) {
+ if (simple_text) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "Tab");
+ }
+ else {
+ rctf rect_ofs = rect;
+ BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f));
+ icon_draw_rect_input_mono_text(&rect_ofs, color, margin, (const char[]){0xe2, 0x86, 0xb9, 0x0});
+ }
+ }
+ else if (event_type == HOMEKEY) {
+ if (simple_text) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "Home");
+ }
+ else {
+ rctf rect_ofs = rect;
+ BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f));
+ icon_draw_rect_input_mono_text(&rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa4, 0x0});
+ }
+ }
+ else if (event_type == ENDKEY) {
+ if (simple_text) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "End");
+ }
+ else {
+ rctf rect_ofs = rect;
+ BLI_rctf_translate(&rect_ofs, (w / -12.0f), (w / -12.0f));
+ icon_draw_rect_input_mono_text(&rect_ofs, color, margin, (const char[]){0xe2, 0x87, 0xa5, 0x0});
+ }
+ }
+ else if (event_type == RETKEY) {
+ if (simple_text) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "Ret");
+ }
+ else {
+ rctf rect_ofs = rect;
+ BLI_rctf_translate(&rect_ofs, (w / -8.0f), (w / -6.0f));
+ icon_draw_rect_input_mono_text(&rect_ofs, color, margin, (const char[]){0xe2, 0x8f, 0x8e, 0x0});
+ }
+ }
+ else if (event_type == ESCKEY) {
+ icon_draw_rect_input_small_text(&rect, color, margin, "Esc");
+ }
+ else if (event_type == PAGEUPKEY) {
+ icon_draw_rect_input_small_text_ex(&rect, color, margin, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 10);
+ }
+ else if (event_type == PAGEDOWNKEY) {
+ icon_draw_rect_input_small_text_ex(&rect, color, margin, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 10);
+ }
+ else if (event_type == LEFTARROWKEY) {
+ icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x90, 0x0});
+ }
+ else if (event_type == UPARROWKEY) {
+ icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x91, 0x0});
+ }
+ else if (event_type == RIGHTARROWKEY) {
+ icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x92, 0x0});
+ }
+ else if (event_type == DOWNARROWKEY) {
+ icon_draw_rect_input_default_text(&rect, color, margin, (const char[]){0xe2, 0x86, 0x93, 0x0});
+ }
+ else if (event_type == SPACEKEY) {
+ const uchar lines[] = {60, 118, 60, 60, 195, 60, 195, 118};
+ icon_draw_rect_input_line_prim(
+ &rect, color, GPU_PRIM_LINE_STRIP,
+ (const void *)lines, ARRAY_SIZE(lines) / 2);
+ }
+}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 11691fd8365..7e8653bfc56 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -72,6 +72,8 @@ typedef enum {
UI_WTYPE_NUMBER,
UI_WTYPE_SLIDER,
UI_WTYPE_EXEC,
+ UI_WTYPE_TOOLBAR_ITEM,
+ UI_WTYPE_TAB,
UI_WTYPE_TOOLTIP,
/* strings */
@@ -103,6 +105,9 @@ typedef enum {
UI_WTYPE_PROGRESSBAR,
} uiWidgetTypeEnum;
+#define UI_MENU_WIDTH_MIN (UI_UNIT_Y * 9)
+#define UI_MENU_SUBMENU_PADDING (6 * UI_DPI_FAC) /* some extra padding added to menus containing submenu icons */
+
/* menu scrolling */
#define UI_MENU_SCROLL_ARROW 12
#define UI_MENU_SCROLL_MOUSE (UI_MENU_SCROLL_ARROW + 2)
@@ -112,6 +117,9 @@ typedef enum {
#define UI_PANEL_MINX 100
#define UI_PANEL_MINY 70
+/* popover width (multiplied by 'U.widget_unit') */
+#define UI_POPOVER_WIDTH_UNITS 10
+
/* uiBut->flag */
enum {
UI_SELECT = (1 << 0), /* use when the button is pressed */
@@ -187,23 +195,6 @@ enum {
/* max amount of items a radial menu (pie menu) can contain */
#define PIE_MAX_ITEMS 8
-typedef struct uiLinkLine { /* only for draw/edit */
- struct uiLinkLine *next, *prev;
- struct uiBut *from, *to;
- short flag, deactive;
-} uiLinkLine;
-
-typedef struct {
- void **poin; /* pointer to original pointer */
- void ***ppoin; /* pointer to original pointer-array */
- short *totlink; /* if pointer-array, here is the total */
-
- short maxlink, pad;
- short fromcode, tocode;
-
- ListBase lines;
-} uiLink;
-
struct uiBut {
struct uiBut *next, *prev;
int flag, drawflag;
@@ -258,6 +249,7 @@ struct uiBut {
uiButSearchCreateFunc search_create_func;
uiButSearchFunc search_func;
+ bool free_search_arg;
void *search_arg;
uiButHandleRenameFunc rename_func;
@@ -268,9 +260,6 @@ struct uiBut {
uiButHandleHoldFunc hold_func;
void *hold_argN;
- uiLink *link;
- short linkto[2]; /* region relative coords */
-
const char *tip;
uiButToolTipFunc tip_func;
void *tip_argN;
@@ -281,7 +270,7 @@ struct uiBut {
BIFIconID icon;
char dt; /* drawtype: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied from the block */
signed char pie_dir; /* direction in a pie menu, used for collision detection (RadialDirection) */
- char changed; /* could be made into a single flag */
+ bool changed; /* could be made into a single flag */
unsigned char unit_type; /* so buttons can support unit systems which are not RNA */
short modifier_key;
short iconadd;
@@ -331,6 +320,11 @@ struct uiBut {
uiBlock *block;
};
+typedef struct uiButTab {
+ uiBut but;
+ struct MenuType *menu;
+} uiButTab;
+
typedef struct ColorPicker {
struct ColorPicker *next, *prev;
float color_data[3]; /* colr data may be HSV or HSL for now */
@@ -356,6 +350,13 @@ struct PieMenuData {
float alphafac;
};
+/* uiBlock.content_hints */
+enum eBlockContentHints {
+ /* In a menu block, if there is a single sub-menu button, we add some
+ * padding to the right to put nicely aligned triangle icons there. */
+ UI_BLOCK_CONTAINS_SUBMENU_BUT = (1 << 0),
+};
+
struct uiBlock {
uiBlock *next, *prev;
@@ -402,12 +403,16 @@ struct uiBlock {
int flag;
short alignnr;
+ /* Hints about the buttons of this block. Used to avoid iterating over
+ * buttons to find out if some criteria is met by any. Instead, check this
+ * criteria when adding the button and set a flag here if it's met. */
+ short content_hints; /* eBlockContentHints */
char direction;
char theme_style; /* UI_BLOCK_THEME_STYLE_* */
char dt; /* drawtype: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied to buttons */
bool auto_open;
- char _pad[6];
+ char _pad[5];
double auto_open_last;
const char *lockstr;
@@ -450,8 +455,6 @@ typedef struct uiSafetyRct {
/* interface.c */
-extern void ui_linkline_remove(uiLinkLine *line, uiBut *but);
-
void ui_fontscale(short *points, float aspect);
extern void ui_block_to_window_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y);
@@ -506,9 +509,9 @@ extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+void ui_but_override_flag(uiBut *but);
extern void ui_block_bounds_calc(uiBlock *block);
-extern void ui_block_translate(uiBlock *block, int x, int y);
extern struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block);
void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]);
@@ -525,16 +528,19 @@ struct uiKeyNavLock {
};
typedef uiBlock * (*uiBlockHandleCreateFunc)(struct bContext *C, struct uiPopupBlockHandle *handle, void *arg1);
+typedef void (*uiBlockHandleFreeFunc)(struct uiPopupBlockHandle *handle, void *arg1);
struct uiPopupBlockCreate {
- uiBlockCreateFunc create_func;
+ uiBlockCreateFunc create_func;
uiBlockHandleCreateFunc handle_create_func;
+ uiBlockHandleFreeFunc free_func;
void *arg;
int event_xy[2];
/* when popup is initialized from a button */
ARegion *butregion;
+ uiBut *but;
};
struct uiPopupBlockHandle {
@@ -555,8 +561,10 @@ struct uiPopupBlockHandle {
struct uiPopupBlockCreate popup_create_vars;
/* true if we can re-create the popup using 'popup_create_vars' */
bool can_refresh;
+ bool refresh;
struct wmTimer *scrolltimer;
+ float scrolloffset;
struct uiKeyNavLock keynav_state;
@@ -576,6 +584,15 @@ struct uiPopupBlockHandle {
/* menu direction */
int direction;
+ /* Previous values so we don't resize or reposition on refresh. */
+ rctf prev_block_rect;
+ rctf prev_butrct;
+ short prev_dir1, prev_dir2;
+ int prev_mx, prev_my;
+
+ /* Maximum estimated size to avoid having to reposition on refresh. */
+ float max_size_x, max_size_y;
+
/* #ifdef USE_DRAG_POPUP */
bool is_grab;
int grab_xy_prev[2];
@@ -628,13 +645,25 @@ uiPopupBlockHandle *ui_popup_menu_create(
struct bContext *C, struct ARegion *butregion, uiBut *but,
uiMenuCreateFunc create_func, void *arg);
+/* interface_region_popover.c */
+uiBlock *ui_popover_block_refresh(
+ struct bContext *C, uiPopupBlockHandle *handle,
+ ARegion *butregion, uiBut *but);
+uiPopupBlockHandle *ui_popover_block_create(
+ struct bContext *C, struct ARegion *butregion, uiBut *but,
+ uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
+ void *arg);
+uiPopupBlockHandle *ui_popover_panel_create(
+ struct bContext *C, struct ARegion *butregion, uiBut *but,
+ uiMenuCreateFunc create_func, void *arg);
+
/* interface_region_menu_pie.c */
void ui_pie_menu_level_create(
uiBlock *block, struct wmOperatorType *ot, const char *propname, IDProperty *properties,
const EnumPropertyItem *items, int totitem, int context, int flag);
/* interface_region_popup.c */
-void ui_popup_translate(struct bContext *C, struct ARegion *ar, const int mdiff[2]);
+void ui_popup_translate(struct ARegion *ar, const int mdiff[2]);
void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle);
void ui_popup_block_scrolltest(struct uiBlock *block);
@@ -645,13 +674,17 @@ void ui_popup_block_scrolltest(struct uiBlock *block);
extern int ui_handler_panel_region(
struct bContext *C, const struct wmEvent *event,
struct ARegion *ar, const uiBut *active_but);
-extern void ui_draw_aligned_panel(struct uiStyle *style, uiBlock *block, const rcti *rect, const bool show_pin);
+extern void ui_draw_aligned_panel(
+ struct uiStyle *style, uiBlock *block, const rcti *rect,
+ const bool show_pin, const bool show_background);
/* interface_draw.c */
extern void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int select);
void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha);
+
+void ui_draw_but_TAB_outline(const rcti *rect, float rad, unsigned char highlight[3], unsigned char highlight_fade[3]);
void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
@@ -691,20 +724,55 @@ struct wmIMEData *ui_but_ime_data_get(uiBut *but);
#endif
/* interface_widgets.c */
-void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
-void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha);
+
+/* Widget shader parameters, must match the shader layout. */
+typedef struct uiWidgetBaseParameters {
+ rctf recti, rect;
+ float radi, rad;
+ float facxi, facyi;
+ float round_corners[4];
+ float color_inner1[4], color_inner2[4];
+ float color_outline[4], color_emboss[4];
+ float color_tria[4];
+ float tria1_center[2], tria2_center[2];
+ float tria1_size, tria2_size;
+ float shade_dir;
+ /* We pack alpha check and discard factor in alpha_discard.
+ * If the value is negative then we do alpha check.
+ * The absolute value itself is the discard factor.
+ * Initialize value to 1.0.f if you don't want discard */
+ float alpha_discard;
+} uiWidgetBaseParameters;
+
+enum {
+ ROUNDBOX_TRIA_NONE = 0,
+ ROUNDBOX_TRIA_ARROWS,
+ ROUNDBOX_TRIA_SCROLL,
+ ROUNDBOX_TRIA_MENU,
+ ROUNDBOX_TRIA_CHECK,
+ ROUNDBOX_TRIA_HOLD_ACTION_ARROW,
+
+ ROUNDBOX_TRIA_MAX, /* don't use */
+};
+
+struct GPUBatch *ui_batch_roundbox_get(bool filled, bool antialiased);
+struct GPUBatch *ui_batch_roundbox_widget_get(int tria);
+struct GPUBatch *ui_batch_roundbox_shadow_get(void);
+
+void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
+void ui_draw_popover_back(ARegion *ar, struct uiStyle *style, uiBlock *block, rcti *rect);
void ui_draw_pie_center(uiBlock *block);
struct uiWidgetColors *ui_tooltip_get_theme(void);
+
+void ui_draw_widget_back_color(
+ uiWidgetTypeEnum type, bool use_shadow, const rcti *rect,
+ const float color[4]);
+void ui_draw_widget_back(
+ uiWidgetTypeEnum type, bool use_shadow, const rcti *rect);
void ui_draw_tooltip_background(struct uiStyle *UNUSED(style), uiBlock *block, rcti *rect);
-void ui_draw_search_back(struct uiStyle *style, uiBlock *block, rcti *rect);
-bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol);
-void ui_draw_link_bezier(const rcti *rect);
extern void ui_draw_but(const struct bContext *C, ARegion *ar, struct uiStyle *style, uiBut *but, rcti *rect);
-/* theme color init */
-struct ThemeUI;
-void ui_widget_color_init(struct ThemeUI *tui);
void ui_draw_menu_item(struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, bool use_sep);
void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state);
@@ -714,6 +782,9 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na
/* margin at top of screen for popups */
#define UI_POPUP_MENU_TOP (int)(8 * UI_DPI_FAC)
+#define UI_PIXEL_AA_JITTER 8
+extern const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2];
+
/* interface_style.c */
void uiStyleInit(void);
@@ -721,6 +792,11 @@ void uiStyleInit(void);
void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big);
int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
+/* interface_icons_event.c */
+void icon_draw_rect_input(
+ float x, float y, int w, int h, float alpha,
+ short event_type, short event_value);
+
/* resources.c */
void init_userdef_do_versions(struct Main *bmain);
void ui_theme_init_default(void);
@@ -732,10 +808,13 @@ void ui_resources_free(void);
void ui_layout_add_but(uiLayout *layout, uiBut *but);
void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop);
void ui_layout_list_set_labels_active(uiLayout *layout);
+/* menu callback */
+void ui_item_paneltype_func(struct bContext *C, struct uiLayout *layout, void *arg_pt);
/* interface_align.c */
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-void ui_block_align_calc(uiBlock *block);
+int ui_but_align_opposite_to_area_align_get(const ARegion *ar) ATTR_WARN_UNUSED_RESULT;
+void ui_block_align_calc(uiBlock *block, const ARegion *region);
/* interface_anim.c */
void ui_but_anim_flag(uiBut *but, float cfra);
@@ -746,12 +825,17 @@ bool ui_but_anim_expression_set(uiBut *but, const char *str);
bool ui_but_anim_expression_create(uiBut *but, const char *str);
void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, float cfra);
+void ui_but_anim_decorate_cb(struct bContext *C, void *arg_but, void *arg_dummy);
+void ui_but_anim_decorate_update_from_flag(uiBut *but);
+
/* interface_query.c */
bool ui_but_is_editable(const uiBut *but);
bool ui_but_is_editable_as_text(const uiBut *but);
bool ui_but_is_toggle(const uiBut *but);
+bool ui_but_is_popover_once_compat(const uiBut *but);
extern bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
extern bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
extern bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
@@ -780,4 +864,20 @@ void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
/* interface_eyedropper_driver.c */
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
+/* interface_util.c */
+
+/**
+ * For use with #ui_rna_collection_search_cb.
+ */
+typedef struct uiRNACollectionSearch {
+ PointerRNA target_ptr;
+ PropertyRNA *target_prop;
+
+ PointerRNA search_ptr;
+ PropertyRNA *search_prop;
+
+ bool *but_changed; /* pointer to uiBut.changed */
+} uiRNACollectionSearch;
+void ui_rna_collection_search_cb(const struct bContext *C, void *arg, const char *str, uiSearchItems *items);
+
#endif /* __INTERFACE_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 922b5779c9f..8a27fd55d37 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -37,6 +37,7 @@
#include "DNA_armature_types.h"
#include "DNA_userdef_types.h"
+#include "BLI_alloca.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_rect.h"
@@ -49,6 +50,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_screen.h"
+#include "BKE_animsys.h"
#include "RNA_access.h"
@@ -62,6 +64,13 @@
#include "interface_intern.h"
+/* Show an icon button after each RNA button to use to quickly set keyframes,
+ * this is a way to display animation/driven/override status, see T54951. */
+#define UI_PROP_DECORATE
+/* Alternate draw mode where some buttons can use single icon width,
+ * giving more room for the text at the expense of nicely aligned text. */
+#define UI_PROP_SEP_ICON_WIDTH_EXCEPTION
+
/************************ Structs and Defines *************************/
#define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \
@@ -71,6 +80,7 @@
return_statement; \
} (void)0 \
+#define UI_ITEM_PROP_SEP_DIVIDE 0.5f
/* uiLayoutRoot */
@@ -100,6 +110,7 @@ typedef enum uiItemType {
ITEM_LAYOUT_COLUMN,
ITEM_LAYOUT_COLUMN_FLOW,
ITEM_LAYOUT_ROW_FLOW,
+ ITEM_LAYOUT_GRID_FLOW,
ITEM_LAYOUT_BOX,
ITEM_LAYOUT_ABSOLUTE,
ITEM_LAYOUT_SPLIT,
@@ -128,6 +139,11 @@ enum {
UI_ITEM_MIN = 1 << 1,
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
+ UI_ITEM_PROP_SEP = 1 << 3,
+ /* Show an icon button next to each property (to set keyframes, show status).
+ * Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
+ UI_ITEM_PROP_DECORATE = 1 << 4,
+ UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 5,
};
typedef struct uiButtonItem {
@@ -142,6 +158,9 @@ struct uiLayout {
bContextStore *context;
ListBase items;
+ /* Sub layout to add child items, if not the layout itself. */
+ uiLayout *child_items_layout;
+
int x, y, w, h;
float scale[2];
short space;
@@ -150,7 +169,10 @@ struct uiLayout {
bool enabled;
bool redalert;
bool keepaspect;
+ bool variable_size; /* For layouts inside gridflow, they and their items shall never have a fixed maximal size. */
char alignment;
+ char emboss;
+ float units[2]; /* for fixed width or height to avoid UI size changes */
};
typedef struct uiLayoutItemFlow {
@@ -159,6 +181,22 @@ typedef struct uiLayoutItemFlow {
int totcol;
} uiLayoutItemFlow;
+typedef struct uiLayoutItemGridFlow {
+ uiLayout litem;
+
+ /* Extra parameters */
+ bool row_major; /* Fill first row first, instead of filling first column first. */
+ bool even_columns; /* Same width for all columns. */
+ bool even_rows; /* Same height for all rows. */
+ /* If positive, absolute fixed number of columns.
+ * If 0, fully automatic (based on available width).
+ * If negative, automatic but only generates number of columns/rows multiple of given (absolute) value. */
+ int columns_len;
+
+ /* Pure internal runtime storage. */
+ int tot_items, tot_columns, tot_rows;
+} uiLayoutItemGridFlow;
+
typedef struct uiLayoutItemBx {
uiLayout litem;
uiBut *roundbox;
@@ -230,33 +268,41 @@ static int ui_item_fit(int item, int pos, int all, int available, bool is_last,
static int ui_layout_vary_direction(uiLayout *layout)
{
return ((ELEM(layout->root->type, UI_LAYOUT_HEADER, UI_LAYOUT_PIEMENU) ||
- (layout->alignment != UI_LAYOUT_ALIGN_EXPAND)) ?
+ (layout->alignment != UI_LAYOUT_ALIGN_EXPAND)) ?
UI_ITEM_VARY_X : UI_ITEM_VARY_Y);
}
+static bool ui_layout_variable_size(uiLayout *layout)
+{
+ /* Note that this code is probably a bit flacky, we'd probably want to know whether it's variable in X and/or Y,
+ * etc. But for now it mimics previous one, with addition of variable flag set for children of gridflow layouts. */
+ return ui_layout_vary_direction(layout) == UI_ITEM_VARY_X || layout->variable_size;
+}
+
/* estimated size of text + icon */
static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool compact)
{
bool variable;
+ const int unit_x = UI_UNIT_X * (layout->scale[0] ? layout->scale[0] : 1.0f);
if (icon && !name[0])
- return UI_UNIT_X; /* icon only */
+ return unit_x; /* icon only */
- variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X);
+ variable = ui_layout_variable_size(layout);
if (variable) {
if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
layout->item.flag |= UI_ITEM_MIN;
}
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- /* it may seem odd that the icon only adds (UI_UNIT_X / 4)
+ /* it may seem odd that the icon only adds (unit_x / 4)
* but taking margins into account its fine */
return (UI_fontstyle_string_width(fstyle, name) +
- (UI_UNIT_X * ((compact ? 1.25f : 1.50f) +
- (icon ? 0.25f : 0.0f))));
+ (unit_x * ((compact ? 1.25f : 1.50f) +
+ (icon ? 0.25f : 0.0f))));
}
else {
- return UI_UNIT_X * 10;
+ return unit_x * 10;
}
}
@@ -343,6 +389,7 @@ static int ui_layout_local_dir(uiLayout *layout)
return UI_LAYOUT_HORIZONTAL;
case ITEM_LAYOUT_COLUMN:
case ITEM_LAYOUT_COLUMN_FLOW:
+ case ITEM_LAYOUT_GRID_FLOW:
case ITEM_LAYOUT_SPLIT:
case ITEM_LAYOUT_ABSOLUTE:
case ITEM_LAYOUT_BOX:
@@ -392,7 +439,7 @@ static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
static void ui_item_array(
uiLayout *layout, uiBlock *block, const char *name, int icon,
PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
- bool expand, bool slider, bool toggle, bool icon_only)
+ bool expand, bool slider, bool toggle, bool icon_only, bool compact, bool show_text)
{
uiStyle *style = layout->root->style;
uiBut *but;
@@ -409,8 +456,9 @@ static void ui_item_array(
UI_block_layout_set_current(block, sub);
/* create label */
- if (name[0])
+ if (name[0] && show_text) {
uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ }
/* create buttons */
if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
@@ -528,7 +576,7 @@ static void ui_item_array(
/* layout for known array subtypes */
char str[3] = {'\0'};
- if (!icon_only) {
+ if (!icon_only && show_text) {
if (type != PROP_BOOLEAN) {
str[1] = ':';
}
@@ -540,10 +588,22 @@ static void ui_item_array(
RNA_property_boolean_get_array(ptr, prop, boolarr);
}
+ const char *str_buf = show_text ? str: "";
for (a = 0; a < len; a++) {
- if (!icon_only) str[0] = RNA_property_array_item_char(prop, a);
- if (boolarr) icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
- but = uiDefAutoButR(block, ptr, prop, a, str, icon, 0, 0, w, UI_UNIT_Y);
+ int width_item;
+
+ if (!icon_only && show_text) {
+ str[0] = RNA_property_array_item_char(prop, a);
+ }
+ if (boolarr) {
+ icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
+ }
+
+ width_item = (
+ (compact && type == PROP_BOOLEAN) ?
+ min_ii(w, ui_text_icon_width(layout, str_buf, icon, false)) : w);
+
+ but = uiDefAutoButR(block, ptr, prop, a, str_buf, icon, 0, 0, width_item, UI_UNIT_Y);
if (slider && but->type == UI_BTYPE_NUM)
but->type = UI_BTYPE_NUM_SLIDER;
if (toggle && but->type == UI_BTYPE_CHECKBOX)
@@ -579,9 +639,9 @@ static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
RNA_property_enum_set(&but->rnapoin, but->rnaprop, current_value);
}
}
-static void ui_item_enum_expand(
+static void ui_item_enum_expand_exec(
uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
- const char *uiname, int h, bool icon_only)
+ const char *uiname, int h, int but_type, bool icon_only)
{
/* XXX The way this function currently handles uiname parameter is insane and inconsistent with general UI API:
* * uiname is the *enum property* label.
@@ -595,10 +655,13 @@ static void ui_item_enum_expand(
uiLayout *layout_radial = NULL;
const EnumPropertyItem *item, *item_array;
const char *name;
+ char group_name[UI_MAX_NAME_STR];
int itemw, icon, value;
bool free;
bool radial = (layout->root->type == UI_LAYOUT_PIEMENU);
+ BLI_assert(RNA_property_type(prop) == PROP_ENUM);
+
if (radial)
RNA_property_enum_items_gettexted_all(block->evil_C, ptr, prop, &item_array, NULL, &free);
else
@@ -625,9 +688,27 @@ static void ui_item_enum_expand(
}
for (item = item_array; item->identifier; item++) {
+ const bool is_first = item == item_array;
+
if (!item->identifier[0]) {
- if (radial && layout_radial) {
- uiItemS(layout_radial);
+ const EnumPropertyItem *next_item = item + 1;
+
+ /* Separate items, potentially with a label. */
+ if (next_item->identifier) {
+ /* Item without identifier but with name: Add group label for the following items. */
+ if (item->name) {
+ if (!is_first) {
+ uiItemS(block->curlayout);
+ }
+ BLI_snprintf(group_name, sizeof(group_name), "%s:", item->name);
+ uiItemL(block->curlayout, group_name, item->icon);
+ }
+ else if (radial && layout_radial) {
+ uiItemS(layout_radial);
+ }
+ else {
+ uiItemS(block->curlayout);
+ }
}
continue;
}
@@ -638,11 +719,11 @@ static void ui_item_enum_expand(
itemw = ui_text_icon_width(block->curlayout, icon_only ? "" : name, icon, 0);
if (icon && name[0] && !icon_only)
- but = uiDefIconTextButR_prop(block, UI_BTYPE_ROW, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ but = uiDefIconTextButR_prop(block, but_type, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
else if (icon)
- but = uiDefIconButR_prop(block, UI_BTYPE_ROW, 0, icon, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ but = uiDefIconButR_prop(block, but_type, 0, icon, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
else
- but = uiDefButR_prop(block, UI_BTYPE_ROW, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
+ but = uiDefButR_prop(block, but_type, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
UI_but_func_set(but, ui_item_enum_expand_handle, but, POINTER_FROM_INT(value));
@@ -650,6 +731,11 @@ static void ui_item_enum_expand(
if (ui_layout_local_dir(layout) != UI_LAYOUT_HORIZONTAL)
but->drawflag |= UI_BUT_TEXT_LEFT;
+
+ /* Allow quick, inaccurate swipe motions to switch tabs (no need to keep cursor over them). */
+ if (but_type == UI_BTYPE_TAB) {
+ but->flag |= UI_BUT_DRAG_LOCK;
+ }
}
UI_block_layout_set_current(block, layout);
@@ -657,6 +743,24 @@ static void ui_item_enum_expand(
MEM_freeN((void *)item_array);
}
}
+static void ui_item_enum_expand(
+ uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
+ const char *uiname, int h, bool icon_only)
+{
+ ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_ROW, icon_only);
+}
+static void ui_item_enum_expand_tabs(
+ uiLayout *layout, bContext *C, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
+ const char *uiname, int h, bool icon_only)
+{
+ uiBut *last = block->buttons.last;
+
+ ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only);
+ BLI_assert(last != block->buttons.last);
+ for (uiBut *tab = last ? last->next : block->buttons.first; tab; tab = tab->next) {
+ UI_but_drawflag_enable(tab, ui_but_align_opposite_to_area_align_get(CTX_wm_region(C)));
+ }
+}
/* callback for keymap item change button */
static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
@@ -669,28 +773,50 @@ static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_
RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
}
-/* create label + button for RNA property */
-static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int flag)
+/**
+ * Create label + button for RNA property
+ *
+ * \param w_hint: For varying width layout, this becomes the label width.
+ * Otherwise it's used to fit both items into it.
+ **/
+static uiBut *ui_item_with_label(
+ uiLayout *layout, uiBlock *block, const char *name, int icon,
+ PointerRNA *ptr, PropertyRNA *prop, int index,
+ int x, int y, int w_hint, int h, int flag)
{
uiLayout *sub;
uiBut *but = NULL;
PropertyType type;
PropertySubType subtype;
- int labelw;
+ int prop_but_width = w_hint;
+ const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
/* Always align item with label since text is already given enough space not to overlap. */
sub = uiLayoutRow(layout, true);
UI_block_layout_set_current(block, sub);
if (name[0]) {
- /* XXX UI_fontstyle_string_width is not accurate */
-#if 0
- labelw = UI_fontstyle_string_width(fstyle, name);
- CLAMP(labelw, w / 4, 3 * w / 4);
-#endif
- labelw = w / 3;
- uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
- w = w - labelw;
+ int w_label;
+
+ if (use_prop_sep) {
+ w_label = (int)((w_hint * 2) * UI_ITEM_PROP_SEP_DIVIDE);
+ }
+ else {
+ if (ui_layout_variable_size(layout)) {
+ /* w_hint is width for label in this case. Use a default width for property button(s) */
+ prop_but_width = UI_UNIT_X * 5;
+ w_label = w_hint;
+ }
+ else {
+ w_label = w_hint / 3;
+ }
+ }
+
+ uiBut *but_label = uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
+ if (use_prop_sep) {
+ but_label->drawflag |= UI_BUT_TEXT_RIGHT;
+ but_label->drawflag &= ~UI_BUT_TEXT_LEFT;
+ }
}
type = RNA_property_type(prop);
@@ -698,15 +824,15 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n
if (subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
UI_block_layout_set_current(block, uiLayoutRow(sub, true));
- but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w - UI_UNIT_X, h);
+ but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, prop_but_width - UI_UNIT_X, h);
/* BUTTONS_OT_file_browse calls UI_context_active_but_prop_get_filebrowser */
uiDefIconButO(
block, UI_BTYPE_BUT, subtype == PROP_DIRPATH ? "BUTTONS_OT_directory_browse" : "BUTTONS_OT_file_browse",
- WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL);
+ WM_OP_INVOKE_DEFAULT, ICON_FILEBROWSER, x, y, UI_UNIT_X, h, NULL);
}
else if (flag & UI_ITEM_R_EVENT) {
- but = uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, prop_but_width, h, ptr, prop, index, 0, 0, -1, -1, NULL);
}
else if (flag & UI_ITEM_R_FULL_EVENT) {
if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
@@ -714,14 +840,29 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n
WM_keymap_item_to_string(ptr->data, false, buf, sizeof(buf));
- but = uiDefButR_prop(block, UI_BTYPE_HOTKEY_EVENT, 0, buf, x, y, w, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
+ but = uiDefButR_prop(block, UI_BTYPE_HOTKEY_EVENT, 0, buf, x, y, prop_but_width, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
UI_but_func_set(but, ui_keymap_but_cb, but, NULL);
if (flag & UI_ITEM_R_IMMEDIATE)
UI_but_flag_enable(but, UI_BUT_IMMEDIATE);
}
}
- else
- but = uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "", icon, x, y, w, h);
+ else {
+ const char *str = (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "";
+ but = uiDefAutoButR(
+ block, ptr, prop, index, str, icon,
+ x, y, prop_but_width, h);
+ }
+
+#ifdef UI_PROP_DECORATE
+ /* Only for alignment. */
+ if (layout->item.flag & UI_ITEM_PROP_SEP) {
+ if ((layout->item.flag & UI_ITEM_PROP_DECORATE) &&
+ (layout->item.flag & UI_ITEM_PROP_DECORATE_NO_PAD) == 0)
+ {
+ uiItemL(sub, NULL, ICON_BLANK1);
+ }
+ }
+#endif /* UI_PROP_DECORATE */
UI_block_layout_set_current(block, layout);
return but;
@@ -822,8 +963,10 @@ static uiBut *uiItemFullO_ptr_ex(
w = ui_text_icon_width(layout, name, icon, 0);
- if (flag & UI_ITEM_R_NO_BG)
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ int prev_emboss = layout->emboss;
+ if (flag & UI_ITEM_R_NO_BG) {
+ layout->emboss = UI_EMBOSS_NONE;
+ }
/* create the button */
if (icon) {
@@ -844,8 +987,9 @@ static uiBut *uiItemFullO_ptr_ex(
if ((layout->root->type == UI_LAYOUT_TOOLBAR) && !icon)
but->drawflag |= UI_BUT_TEXT_LEFT;
- if (flag & UI_ITEM_R_NO_BG)
- UI_block_emboss_set(block, UI_EMBOSS);
+ if (flag & UI_ITEM_R_NO_BG) {
+ layout->emboss = prev_emboss;
+ }
if (flag & UI_ITEM_O_DEPRESS) {
but->flag |= UI_SELECT_DRAW;
@@ -872,7 +1016,7 @@ static uiBut *uiItemFullO_ptr_ex(
return but;
}
-static void ui_item_hold_menu(struct bContext *C, ARegion *butregion, uiBut *but)
+static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but)
{
uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
@@ -880,6 +1024,24 @@ static void ui_item_hold_menu(struct bContext *C, ARegion *butregion, uiBut *but
UI_popup_menu_but_set(pup, butregion, but);
block->flag |= UI_BLOCK_POPUP_HOLD;
+ block->flag |= UI_BLOCK_IS_FLIP;
+
+ char direction = UI_DIR_DOWN;
+ if (!but->drawstr[0]) {
+ if (butregion->alignment == RGN_ALIGN_LEFT) {
+ direction = UI_DIR_RIGHT;
+ }
+ else if (butregion->alignment == RGN_ALIGN_RIGHT) {
+ direction = UI_DIR_LEFT;
+ }
+ else if (butregion->alignment == RGN_ALIGN_BOTTOM) {
+ direction = UI_DIR_UP;
+ }
+ else {
+ direction = UI_DIR_DOWN;
+ }
+ }
+ UI_block_direction_set(block, direction);
const char *menu_id = but->hold_argN;
MenuType *mt = WM_menutype_find(menu_id, true);
@@ -909,7 +1071,7 @@ void uiItemFullOMenuHold_ptr(
PointerRNA *r_opptr)
{
uiBut *but = uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, r_opptr);
- UI_but_func_hold_set(but, ui_item_hold_menu, BLI_strdup(menu_id));
+ UI_but_func_hold_set(but, ui_item_menu_hold, BLI_strdup(menu_id));
}
void uiItemFullO(
@@ -1137,7 +1299,15 @@ void uiItemsFullEnumO(
bool free;
if (ui_layout_is_radial(layout)) {
+ /* XXX: While "_all()" guarantees spatial stability, it's bad when an enum has > 8 items total,
+ * but only a small subset will ever be shown at once (e.g. Mode Switch menu, after the
+ * introduction of GP editing modes)
+ */
+#if 0
RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
+#else
+ RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
+#endif
}
else {
RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
@@ -1303,8 +1473,10 @@ void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
/* RNA property items */
static void ui_item_rna_size(
- uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
- int index, bool icon_only, int *r_w, int *r_h)
+ uiLayout *layout, const char *name, int icon,
+ PointerRNA *ptr, PropertyRNA *prop,
+ int index, bool icon_only, bool compact,
+ int *r_w, int *r_h)
{
PropertyType type;
PropertySubType subtype;
@@ -1330,7 +1502,7 @@ static void ui_item_rna_size(
RNA_property_enum_items_gettexted(layout->root->block->evil_C, ptr, prop, &item_array, NULL, &free);
for (item = item_array; item->identifier; item++) {
if (item->identifier[0]) {
- w = max_ii(w, ui_text_icon_width(layout, item->name, item->icon, 0));
+ w = max_ii(w, ui_text_icon_width(layout, item->name, item->icon, compact));
}
}
if (free) {
@@ -1341,12 +1513,13 @@ static void ui_item_rna_size(
if (!w) {
if (type == PROP_ENUM && icon_only) {
- w = ui_text_icon_width(layout, "", ICON_BLANK1, 0);
+ w = ui_text_icon_width(layout, "", ICON_BLANK1, compact);
if (index != RNA_ENUM_VALUE)
w += 0.6f * UI_UNIT_X;
}
else {
- w = ui_text_icon_width(layout, name, icon, 0);
+ /* not compact for float/int buttons, looks too squashed */
+ w = ui_text_icon_width(layout, name, icon, ELEM(type, PROP_FLOAT, PROP_INT) ? false : compact);
}
}
h = UI_UNIT_Y;
@@ -1355,7 +1528,8 @@ static void ui_item_rna_size(
if (index == RNA_NO_INDEX && len > 0) {
if (!name[0] && icon == ICON_NONE)
h = 0;
-
+ if (layout->item.flag & UI_ITEM_PROP_SEP)
+ h = 0;
if (ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER))
h += 2 * UI_UNIT_Y;
else if (subtype == PROP_MATRIX)
@@ -1363,7 +1537,7 @@ static void ui_item_rna_size(
else
h += len * UI_UNIT_Y;
}
- else if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
+ else if (ui_layout_variable_size(layout)) {
if (type == PROP_BOOLEAN && name[0])
w += UI_UNIT_X / 5;
else if (type == PROP_ENUM && !icon_only)
@@ -1383,8 +1557,22 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
PropertyType type;
char namestr[UI_MAX_NAME_STR];
int len, w, h;
- bool slider, toggle, expand, icon_only, no_bg;
+ bool slider, toggle, expand, icon_only, no_bg, compact;
bool is_array;
+ const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
+
+#ifdef UI_PROP_DECORATE
+ struct {
+ bool use_prop_decorate;
+ int len;
+ uiLayout *layout;
+ uiBut *but;
+ } ui_decorate = {
+ .use_prop_decorate = (
+ ((layout->item.flag & UI_ITEM_PROP_DECORATE) != 0) &&
+ (use_prop_sep && ptr->id.data && id_can_have_animdata(ptr->id.data))),
+ };
+#endif /* UI_PROP_DECORATE */
UI_block_layout_set_current(block, layout);
@@ -1410,13 +1598,24 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
/* pass */
}
else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
- name = ui_item_name_add_colon(name, namestr);
+ if (use_prop_sep == false) {
+ name = ui_item_name_add_colon(name, namestr);
+ }
}
else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) {
- name = ui_item_name_add_colon(name, namestr);
+ if (use_prop_sep == false) {
+ name = ui_item_name_add_colon(name, namestr);
+ }
}
else if (type == PROP_ENUM && index != RNA_ENUM_VALUE) {
- name = ui_item_name_add_colon(name, namestr);
+ if (flag & UI_ITEM_R_COMPACT) {
+ name = "";
+ }
+ else {
+ if (use_prop_sep == false) {
+ name = ui_item_name_add_colon(name, namestr);
+ }
+ }
}
/* menus and pie-menus don't show checkbox without this */
@@ -1424,13 +1623,24 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
/* use checkboxes only as a fallback in pie-menu's, when no icon is defined */
((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE)))
{
+ int prop_flag = RNA_property_flag(prop);
if (type == PROP_BOOLEAN && ((is_array == false) || (index != RNA_NO_INDEX))) {
- if (is_array) icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
- else icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
+ if (prop_flag & PROP_ICONS_CONSECUTIVE) {
+ icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
+ }
+ else if (is_array) {
+ icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
+ }
+ else {
+ icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
+ }
}
else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
int enum_value = RNA_property_enum_get(ptr, prop);
- if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
+ if (prop_flag & PROP_ICONS_CONSECUTIVE) {
+ icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
+ }
+ else if (prop_flag & PROP_ENUM_FLAG) {
icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
}
else {
@@ -1448,16 +1658,135 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
expand = (flag & UI_ITEM_R_EXPAND) != 0;
icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0;
no_bg = (flag & UI_ITEM_R_NO_BG) != 0;
+ compact = (flag & UI_ITEM_R_COMPACT) != 0;
/* get size */
- ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, &w, &h);
+ ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, compact, &w, &h);
+
+ int prev_emboss = layout->emboss;
+ if (no_bg) {
+ layout->emboss = UI_EMBOSS_NONE;
+ }
+
+ /* Split the label / property. */
+ uiLayout *layout_parent = layout;
+ if (use_prop_sep) {
+ uiLayout *layout_row = NULL;
+#ifdef UI_PROP_DECORATE
+ if (ui_decorate.use_prop_decorate) {
+ layout_row = uiLayoutRow(layout, true);
+ layout_row->space = 0;
+ ui_decorate.len = max_ii(1, len);
+ }
+#endif /* UI_PROP_DECORATE */
- if (no_bg)
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ if (name[0] == '\0') {
+ /* Ensure we get a column when text is not set. */
+ layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
+ layout->space = 0;
+ }
+ else {
+ const PropertySubType subtype = RNA_property_subtype(prop);
+ uiLayout *layout_split;
+#ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION
+ if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
+ layout_split = uiLayoutRow(layout_row ? layout_row : layout, true);
+ }
+ else
+#endif /* UI_PROP_SEP_ICON_WIDTH_EXCEPTION */
+ {
+ layout_split = uiLayoutSplit(
+ layout_row ? layout_row : layout,
+ UI_ITEM_PROP_SEP_DIVIDE, true);
+ }
+ layout_split->space = 0;
+ uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
+ layout_sub->space = 0;
+
+ if ((index == RNA_NO_INDEX && is_array) &&
+ ((!expand && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION)) == 0))
+ {
+ char name_with_suffix[UI_MAX_DRAW_STR + 2];
+ char str[2] = {'\0'};
+ for (int a = 0; a < len; a++) {
+ str[0] = RNA_property_array_item_char(prop, a);
+ const bool use_prefix = (a == 0 && name && name[0]);
+ if (use_prefix) {
+ char *s = name_with_suffix;
+ s += STRNCPY_RLEN(name_with_suffix, name);
+ *s++ = ' ';
+ *s++ = str[0];
+ *s++ = '\0';
+ }
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, use_prefix ? name_with_suffix : str,
+ 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ but->drawflag |= UI_BUT_TEXT_RIGHT;
+ but->drawflag &= ~UI_BUT_TEXT_LEFT;
+ }
+ }
+ else {
+ if (name) {
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, name,
+ 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ but->drawflag |= UI_BUT_TEXT_RIGHT;
+ but->drawflag &= ~UI_BUT_TEXT_LEFT;
+ }
+ }
+
+ /* Hack to add further items in a row into the second part of
+ * the split layout, so the label part keeps a fixed size. */
+ if (layout_parent && layout_parent->item.type == ITEM_LAYOUT_ROW) {
+ layout_split = uiLayoutRow(layout_split, true);
+ layout_parent->child_items_layout = layout_split;
+ }
+
+ /* Watch out! We can only write into the new layout now. */
+ if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) {
+ /* Expanded enums each have their own name. */
+
+ /* Often expanded enum's are better arranged into a row, so check the existing layout. */
+ if (ui_layout_local_dir(layout) == UI_LAYOUT_HORIZONTAL) {
+ layout = uiLayoutRow(layout_split, true);
+ }
+ else {
+ layout = uiLayoutColumn(layout_split, true);
+ }
+ }
+ else {
+ name = "";
+ layout = uiLayoutColumn(layout_split, true);
+ }
+ layout->space = 0;
+
+#ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION
+ if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
+ w = UI_UNIT_X;
+ }
+#endif /* UI_PROP_SEP_ICON_WIDTH_EXCEPTION */
+ }
+
+#ifdef UI_PROP_DECORATE
+ if (ui_decorate.use_prop_decorate) {
+ ui_decorate.layout = uiLayoutColumn(layout_row, true);
+ ui_decorate.layout->space = 0;
+ UI_block_layout_set_current(block, layout);
+ ui_decorate.but = block->buttons.last;
+
+ /* Clear after. */
+ layout->item.flag |= UI_ITEM_PROP_DECORATE_NO_PAD;
+ }
+#endif /* UI_PROP_DECORATE */
+ }
+ /* End split. */
/* array property */
- if (index == RNA_NO_INDEX && is_array)
- ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider, toggle, icon_only);
+ if (index == RNA_NO_INDEX && is_array) {
+ ui_item_array(
+ layout, block, name, icon, ptr, prop, len, 0, 0, w, h,
+ expand, slider, toggle, icon_only, compact, !use_prop_sep);
+ }
/* enum item */
else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
if (icon && name[0] && !icon_only)
@@ -1498,8 +1827,45 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
UI_but_flag_enable(but, UI_BUT_LIST_ITEM);
}
- if (no_bg)
- UI_block_emboss_set(block, UI_EMBOSS);
+#ifdef UI_PROP_DECORATE
+ if (ui_decorate.use_prop_decorate) {
+ const bool is_anim = RNA_property_animateable(ptr, prop);
+ uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first;
+ uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
+ layout_col->space = 0;
+ layout_col->emboss = UI_EMBOSS_NONE;
+ int i;
+ for (i = 0; i < ui_decorate.len && but_decorate; i++) {
+ /* The icons are set in 'ui_but_anim_flag' */
+ if (is_anim) {
+ but = uiDefIconBut(
+ block, UI_BTYPE_BUT, 0, ICON_DOT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Animate property"));
+ UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
+ but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
+ }
+ else {
+ /* We may show other information here in future, for now use empty space. */
+ but = uiDefIconBut(
+ block, UI_BTYPE_BUT, 0, ICON_BLANK1, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, "");
+ but->flag |= UI_BUT_DISABLED;
+ }
+ /* Order the decorator after the button we decorate, this is used so we can always
+ * do a quick lookup. */
+ BLI_remlink(&block->buttons, but);
+ BLI_insertlinkafter(&block->buttons, but_decorate, but);
+ but_decorate = but->next;
+ }
+ BLI_assert(ELEM(i, 1, ui_decorate.len));
+
+ layout->item.flag &= ~UI_ITEM_PROP_DECORATE_NO_PAD;
+ }
+#endif /* UI_PROP_DECORATE */
+
+ if (no_bg) {
+ layout->emboss = prev_emboss;
+ }
/* ensure text isn't added to icon_only buttons */
if (but && icon_only) {
@@ -1664,94 +2030,6 @@ void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname
/* Pointer RNA button with search */
-typedef struct CollItemSearch {
- struct CollItemSearch *next, *prev;
- char *name;
- int index;
- int iconid;
-} CollItemSearch;
-
-static int sort_search_items_list(const void *a, const void *b)
-{
- const CollItemSearch *cis1 = a;
- const CollItemSearch *cis2 = b;
-
- if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
- return 1;
- else
- return 0;
-}
-
-static void rna_search_cb(const struct bContext *C, void *arg_but, const char *str, uiSearchItems *items)
-{
- uiBut *but = arg_but;
- char *name;
- int i = 0, iconid = 0, flag = RNA_property_flag(but->rnaprop);
- ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
- CollItemSearch *cis;
- const bool skip_filter = !but->changed;
-
- /* build a temporary list of relevant items first */
- RNA_PROP_BEGIN (&but->rnasearchpoin, itemptr, but->rnasearchprop)
- {
- if (flag & PROP_ID_SELF_CHECK)
- if (itemptr.data == but->rnapoin.id.data)
- continue;
-
- /* use filter */
- if (RNA_property_type(but->rnaprop) == PROP_POINTER) {
- if (RNA_property_pointer_poll(&but->rnapoin, but->rnaprop, &itemptr) == 0)
- continue;
- }
-
- if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
- ID *id = itemptr.data;
- char name_ui[MAX_ID_NAME];
-
-#if 0 /* this name is used for a string comparison and can't be modified, TODO */
- /* if ever enabled, make name_ui be MAX_ID_NAME+1 */
- BKE_id_ui_prefix(name_ui, id);
-#else
- BLI_strncpy(name_ui, id->name + 2, sizeof(name_ui));
-#endif
- name = BLI_strdup(name_ui);
- iconid = ui_id_icon_get(C, id, false);
- }
- else {
- name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
- iconid = 0;
- }
-
- if (name) {
- if (skip_filter || BLI_strcasestr(name, str)) {
- cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
- cis->name = MEM_dupallocN(name);
- cis->index = i;
- cis->iconid = iconid;
- BLI_addtail(items_list, cis);
- }
- MEM_freeN(name);
- }
-
- i++;
- }
- RNA_PROP_END;
-
- BLI_listbase_sort(items_list, sort_search_items_list);
-
- /* add search items from temporary list */
- for (cis = items_list->first; cis; cis = cis->next) {
- if (false == UI_search_item_add(items, cis->name, POINTER_FROM_INT(cis->index), cis->iconid)) {
- break;
- }
- }
-
- for (cis = items_list->first; cis; cis = cis->next) {
- MEM_freeN(cis->name);
- }
- BLI_freelistN(items_list);
- MEM_freeN(items_list);
-}
static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
{
@@ -1794,6 +2072,8 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
/* turn button into search button */
if (searchprop) {
+ uiRNACollectionSearch *coll_search = MEM_mallocN(sizeof(*coll_search), __func__);
+
but->type = UI_BTYPE_SEARCH_MENU;
but->hardmax = MAX2(but->hardmax, 256.0f);
but->rnasearchpoin = *searchptr;
@@ -1803,13 +2083,22 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
but->flag |= UI_BUT_VALUE_CLEAR;
}
+ coll_search->target_ptr = *ptr;
+ coll_search->target_prop = prop;
+ coll_search->search_ptr = *searchptr;
+ coll_search->search_prop = searchprop;
+ coll_search->but_changed = &but->changed;
+
if (RNA_property_type(prop) == PROP_ENUM) {
/* XXX, this will have a menu string,
* but in this case we just want the text */
but->str[0] = 0;
}
- UI_but_func_search_set(but, ui_searchbox_create_generic, rna_search_cb, but, NULL, NULL);
+ UI_but_func_search_set(
+ but, ui_searchbox_create_generic, ui_rna_collection_search_cb,
+ coll_search, NULL, NULL);
+ but->free_search_arg = true;
}
else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */
@@ -1829,6 +2118,7 @@ void uiItemPointerR_prop(
StructRNA *icontype;
int w, h;
char namestr[UI_MAX_NAME_STR];
+ const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
type = RNA_property_type(prop);
if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
@@ -1854,12 +2144,14 @@ void uiItemPointerR_prop(
if (!name)
name = RNA_property_ui_name(prop);
- name = ui_item_name_add_colon(name, namestr);
+ if (use_prop_sep == false) {
+ name = ui_item_name_add_colon(name, namestr);
+ }
/* create button */
block = uiLayoutGetBlock(layout);
- ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, &w, &h);
+ ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, false, &w, &h);
w += UI_UNIT_X; /* X icon needs more space */
but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
@@ -1902,6 +2194,15 @@ static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
}
+void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt)
+{
+ PanelType *pt = (PanelType *)arg_pt;
+ UI_paneltype_draw(C, pt, layout);
+
+ /* panels are created flipped (from event handling pov) */
+ layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
+}
+
static uiBut *ui_item_menu(
uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
const char *tip, bool force_menu)
@@ -1912,9 +2213,6 @@ static uiBut *ui_item_menu(
UI_block_layout_set_current(block, layout);
- if (layout->root->type == UI_LAYOUT_HEADER)
- UI_block_emboss_set(block, UI_EMBOSS);
-
if (!name)
name = "";
if (layout->root->type == UI_LAYOUT_MENU && !icon)
@@ -1924,7 +2222,10 @@ static uiBut *ui_item_menu(
h = UI_UNIT_Y;
if (layout->root->type == UI_LAYOUT_HEADER) { /* ugly .. */
- if (force_menu) {
+ if (icon == ICON_NONE && force_menu) {
+ /* pass */
+ }
+ else if (force_menu) {
w += UI_UNIT_X;
}
else {
@@ -1949,9 +2250,6 @@ static uiBut *ui_item_menu(
but->func_argN = argN;
}
- if (layout->root->type == UI_LAYOUT_HEADER) {
- UI_block_emboss_set(block, UI_EMBOSS);
- }
if (ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR) ||
(force_menu && layout->root->type != UI_LAYOUT_MENU)) /* We never want a dropdown in menu! */
{
@@ -1984,6 +2282,76 @@ void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon)
mt->description ? TIP_(mt->description) : "", false);
}
+/* popover */
+void uiItemPopoverPanel_ptr(uiLayout *layout, bContext *C, PanelType *pt, const char *name, int icon)
+{
+ if (!name) {
+ name = CTX_IFACE_(pt->translation_context, pt->label);
+ }
+
+ if (layout->root->type == UI_LAYOUT_MENU && !icon) {
+ icon = ICON_BLANK1;
+ }
+
+ const bool ok = (pt->poll == NULL) || pt->poll(C, pt);
+ if (ok && (pt->draw_header != NULL)) {
+ layout = uiLayoutRow(layout, true);
+ Panel panel = {
+ .type = pt,
+ .layout = layout,
+ .flag = PNL_POPOVER,
+ };
+ pt->draw_header(C, &panel);
+ }
+ uiBut *but = ui_item_menu(layout, name, icon, ui_item_paneltype_func, pt, NULL, NULL, true);
+ but->type = UI_BTYPE_POPOVER;
+ if (!ok) {
+ but->flag |= UI_BUT_DISABLED;
+ }
+}
+
+void uiItemPopoverPanel(
+ uiLayout *layout, bContext *C,
+ const char *panel_type, const char *name, int icon)
+{
+ PanelType *pt = WM_paneltype_find(panel_type, true);
+ if (pt == NULL) {
+ RNA_warning("Panel type not found '%s'", panel_type);
+ return;
+ }
+ uiItemPopoverPanel_ptr(layout, C, pt, name, icon);
+}
+
+void uiItemPopoverPanelFromGroup(
+ uiLayout *layout, bContext *C,
+ int space_id, int region_id, const char *context, const char *category)
+{
+ SpaceType *st = BKE_spacetype_from_id(space_id);
+ if (st == NULL) {
+ RNA_warning("space type not found %d", space_id);
+ return;
+ }
+ ARegionType *art = BKE_regiontype_from_id(st, region_id);
+ if (art == NULL) {
+ RNA_warning("region type not found %d", region_id);
+ return;
+ }
+
+ for (PanelType *pt = art->paneltypes.first; pt; pt = pt->next) {
+ /* Causes too many panels, check context. */
+ if (pt->parent_id[0] == '\0') {
+ if (/* (*context == '\0') || */ STREQ(pt->context, context)) {
+ if ((*category == '\0') || STREQ(pt->category, category)) {
+ if (pt->poll == NULL || pt->poll(C, pt)) {
+ uiItemPopoverPanel_ptr(layout, C, pt, NULL, ICON_NONE);
+ }
+ }
+ }
+ }
+ }
+}
+
+
/* label item */
static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
{
@@ -2000,12 +2368,15 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
w = ui_text_icon_width(layout, name, icon, 0);
- if (icon && name[0])
- but = uiDefIconTextBut(block, UI_BTYPE_LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
- else if (icon)
- but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
- else
- but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ if (icon && name[0]) {
+ but = uiDefIconTextBut(block, UI_BTYPE_LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
+ }
+ else if (icon) {
+ but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
+ }
+ else {
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
+ }
/* to compensate for string size padding in ui_text_icon_width,
* make text aligned right if the layout is aligned right.
@@ -2020,6 +2391,10 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
but->flag |= UI_BUT_LIST_ITEM;
}
+ if (layout->redalert) {
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ }
+
return but;
}
@@ -2064,16 +2439,43 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
}
/* separator item */
-void uiItemS(uiLayout *layout)
+void uiItemS_ex(uiLayout *layout, float factor)
{
uiBlock *block = layout->root->block;
bool is_menu = ui_block_is_menu(block);
int space = (is_menu) ? 0.45f * UI_UNIT_X : 0.3f * UI_UNIT_X;
+ space *= factor;
UI_block_layout_set_current(block, layout);
uiDefBut(block, (is_menu) ? UI_BTYPE_SEPR_LINE : UI_BTYPE_SEPR, 0, "", 0, 0, space, space, NULL, 0.0, 0.0, 0, 0, "");
}
+/* separator item */
+void uiItemS(uiLayout *layout)
+{
+ uiItemS_ex(layout, 1.0f);
+}
+
+/* Flexible spacing. */
+void uiItemSpacer(uiLayout *layout)
+{
+ uiBlock *block = layout->root->block;
+ const bool is_popup = ui_block_is_popup_any(block);
+
+ if (is_popup) {
+ printf("Error: separator_spacer() not supported in popups.\n");
+ return;
+ }
+
+ if (block->direction & UI_DIR_RIGHT) {
+ printf("Error: separator_spacer() only supported in horizontal blocks.\n");
+ return;
+ }
+
+ UI_block_layout_set_current(block, layout);
+ uiDefBut(block, UI_BTYPE_SEPR_SPACER, 0, "", 0, 0, 0.3f * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+}
+
/* level items */
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
{
@@ -2149,8 +2551,8 @@ void uiItemMenuEnumO_ptr(
{
char keybuf[128];
if (WM_key_event_operator_string(
- C, ot->idname, layout->root->opcontext, NULL, false,
- keybuf, sizeof(keybuf)))
+ C, ot->idname, layout->root->opcontext, NULL, false,
+ keybuf, sizeof(keybuf)))
{
ui_but_add_shortcut(but, keybuf, false);
}
@@ -2214,6 +2616,14 @@ void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propn
uiItemMenuEnumR_prop(layout, ptr, prop, name, icon);
}
+void uiItemTabsEnumR_prop(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool icon_only)
+{
+ uiBlock *block = layout->root->block;
+
+ UI_block_layout_set_current(block, layout);
+ ui_item_enum_expand_tabs(layout, C, block, ptr, prop, NULL, UI_UNIT_Y, icon_only);
+}
+
/**************************** Layout Items ***************************/
/* single-row layout */
@@ -2470,7 +2880,7 @@ static bool ui_item_is_radial_displayable(uiItem *item)
static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
{
- if (ELEM(bitem->but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE))
+ if (ELEM(bitem->but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER))
return false;
return true;
@@ -2565,7 +2975,7 @@ static void ui_litem_layout_root_radial(uiLayout *litem)
ui_item_size(item, &itemw, &itemh);
- ui_item_position(item, x - itemw / 2, y + U.pixelsize * (U.pie_menu_threshold + 9.0f), itemw, itemh);
+ ui_item_position(item, x - itemw / 2, y + U.dpi_fac * (U.pie_menu_threshold + 9.0f), itemw, itemh);
}
}
@@ -2743,6 +3153,364 @@ static void ui_litem_layout_column_flow(uiLayout *litem)
litem->y = miny;
}
+/* multi-column and multi-row layout. */
+typedef struct UILayoutGridFlowInput {
+ /* General layout control settings. */
+ const bool row_major : 1; /* Fill rows before columns */
+ const bool even_columns : 1; /* All columns will have same width. */
+ const bool even_rows : 1; /* All rows will have same height. */
+ const int space_x; /* Space between columns. */
+ const int space_y; /* Space between rows. */
+ /* Real data about current position and size of this layout item (either estimated, or final values). */
+ const int litem_w; /* Layout item width. */
+ const int litem_x; /* Layout item X position. */
+ const int litem_y; /* Layout item Y position. */
+ /* Actual number of columns and rows to generate (computed from first pass usually). */
+ const int tot_columns; /* Number of columns. */
+ const int tot_rows; /* Number of rows. */
+} UILayoutGridFlowInput;
+
+typedef struct UILayoutGridFlowOutput {
+ int *tot_items; /* Total number of items in this grid layout. */
+ /* Width / X pos data. */
+ float *global_avg_w; /* Computed average width of the columns. */
+ int *cos_x_array; /* Computed X coordinate of each column. */
+ int *widths_array; /* Computed width of each column. */
+ int *tot_w; /* Computed total width. */
+ /* Height / Y pos data. */
+ int *global_max_h; /* Computed height of the tallest item in the grid. */
+ int *cos_y_array; /* Computed Y coordinate of each column. */
+ int *heights_array; /* Computed height of each column. */
+ int *tot_h; /* Computed total height. */
+} UILayoutGridFlowOutput;
+
+static void ui_litem_grid_flow_compute(
+ ListBase *items, UILayoutGridFlowInput *parameters, UILayoutGridFlowOutput *results)
+{
+ uiItem *item;
+ int i;
+
+ float tot_w = 0.0f, tot_h = 0.0f;
+ float global_avg_w = 0.0f, global_totweight_w = 0.0f;
+ int global_max_h = 0;
+
+ float *avg_w = NULL, *totweight_w = NULL;
+ int *max_h = NULL;
+
+ BLI_assert(parameters->tot_columns != 0 || (results->cos_x_array == NULL && results->widths_array == NULL && results->tot_w == NULL));
+ BLI_assert(parameters->tot_rows != 0 || (results->cos_y_array == NULL && results->heights_array == NULL && results->tot_h == NULL));
+
+ if (results->tot_items) {
+ *results->tot_items = 0;
+ }
+
+ if (items->first == NULL) {
+ if (results->global_avg_w) {
+ *results->global_avg_w = 0.0f;
+ }
+ if (results->global_max_h) {
+ *results->global_max_h = 0;
+ }
+ return;
+ }
+
+ if (parameters->tot_columns != 0) {
+ avg_w = BLI_array_alloca(avg_w, parameters->tot_columns);
+ totweight_w = BLI_array_alloca(totweight_w, parameters->tot_columns);
+ memset(avg_w, 0, sizeof(*avg_w) * parameters->tot_columns);
+ memset(totweight_w, 0, sizeof(*totweight_w) * parameters->tot_columns);
+ }
+ if (parameters->tot_rows != 0) {
+ max_h = BLI_array_alloca(max_h, parameters->tot_rows);
+ memset(max_h, 0, sizeof(*max_h) * parameters->tot_rows);
+ }
+
+ for (i = 0, item = items->first; item; item = item->next, i++) {
+ int item_w, item_h;
+ ui_item_size(item, &item_w, &item_h);
+
+ global_avg_w += (float)(item_w * item_w);
+ global_totweight_w += (float)item_w;
+ global_max_h = max_ii(global_max_h, item_h);
+
+ if (parameters->tot_rows != 0 && parameters->tot_columns != 0) {
+ const int index_col = parameters->row_major ? i % parameters->tot_columns : i / parameters->tot_rows;
+ const int index_row = parameters->row_major ? i / parameters->tot_columns : i % parameters->tot_rows;
+
+ avg_w[index_col] += (float)(item_w * item_w);
+ totweight_w[index_col] += (float)item_w;
+
+ max_h[index_row] = max_ii(max_h[index_row], item_h);
+ }
+
+ if (results->tot_items) {
+ (*results->tot_items)++;
+ }
+ }
+
+ /* Finalize computing of column average sizes */
+ global_avg_w /= global_totweight_w;
+ if (parameters->tot_columns != 0) {
+ for (i = 0; i < parameters->tot_columns; i++) {
+ avg_w[i] /= totweight_w[i];
+ tot_w += avg_w[i];
+ }
+ if (parameters->even_columns) {
+ tot_w = ceilf(global_avg_w) * parameters->tot_columns;
+ }
+ }
+ /* Finalize computing of rows max sizes */
+ if (parameters->tot_rows != 0) {
+ for (i = 0; i < parameters->tot_rows; i++) {
+ tot_h += max_h[i];
+ }
+ if (parameters->even_rows) {
+ tot_h = global_max_h * parameters->tot_columns;
+ }
+ }
+
+ /* Compute positions and sizes of all cells. */
+ if (results->cos_x_array != NULL && results->widths_array != NULL) {
+ /* We enlarge/narrow columns evenly to match available width. */
+ const float wfac = (float)(parameters->litem_w - (parameters->tot_columns - 1) * parameters->space_x) / tot_w;
+
+ for (int col = 0; col < parameters->tot_columns; col++) {
+ results->cos_x_array[col] = (
+ col ?
+ results->cos_x_array[col - 1] + results->widths_array[col - 1] + parameters->space_x :
+ parameters->litem_x
+ );
+ if (parameters->even_columns) {
+ /* (< remaining width > - < space between remaining columns >) / < remaining columns > */
+ results->widths_array[col] = (
+ ((parameters->litem_w - (results->cos_x_array[col] - parameters->litem_x)) -
+ (parameters->tot_columns - col - 1) * parameters->space_x) / (parameters->tot_columns - col));
+ }
+ else if (col == parameters->tot_columns - 1) {
+ /* Last column copes width rounding errors... */
+ results->widths_array[col] = parameters->litem_w - (results->cos_x_array[col] - parameters->litem_x);
+ }
+ else {
+ results->widths_array[col] = (int)(avg_w[col] * wfac);
+ }
+ }
+ }
+ if (results->cos_y_array != NULL && results->heights_array != NULL) {
+ for (int row = 0; row < parameters->tot_rows; row++) {
+ if (parameters->even_rows) {
+ results->heights_array[row] = global_max_h;
+ }
+ else {
+ results->heights_array[row] = max_h[row];
+ }
+ results->cos_y_array[row] = (
+ row ?
+ results->cos_y_array[row - 1] - parameters->space_y - results->heights_array[row] :
+ parameters->litem_y - results->heights_array[row]);
+ }
+ }
+
+ if (results->global_avg_w) {
+ *results->global_avg_w = global_avg_w;
+ }
+ if (results->global_max_h) {
+ *results->global_max_h = global_max_h;
+ }
+ if (results->tot_w) {
+ *results->tot_w = (int)tot_w + parameters->space_x * (parameters->tot_columns - 1);
+ }
+ if (results->tot_h) {
+ *results->tot_h = tot_h + parameters->space_y * (parameters->tot_rows - 1);
+ }
+}
+
+static void ui_litem_estimate_grid_flow(uiLayout *litem)
+{
+ uiStyle *style = litem->root->style;
+ uiLayoutItemGridFlow *gflow = (uiLayoutItemGridFlow *)litem;
+
+ const int space_x = style->columnspace;
+ const int space_y = style->buttonspacey;
+
+ /* Estimate average needed width and height per item. */
+ {
+ float avg_w;
+ int max_h;
+
+ ui_litem_grid_flow_compute(
+ &litem->items,
+ &((UILayoutGridFlowInput) {
+ .row_major = gflow->row_major,
+ .even_columns = gflow->even_columns,
+ .even_rows = gflow->even_rows,
+ .litem_w = litem->w,
+ .litem_x = litem->x,
+ .litem_y = litem->y,
+ .space_x = space_x,
+ .space_y = space_y,
+ }),
+ &((UILayoutGridFlowOutput) {
+ .tot_items = &gflow->tot_items,
+ .global_avg_w = &avg_w,
+ .global_max_h = &max_h,
+ }));
+
+ if (gflow->tot_items == 0) {
+ litem->w = litem->h = 0;
+ gflow->tot_columns = gflow->tot_rows = 0;
+ return;
+ }
+
+ /* Even in varying column width case, we fix our columns number from weighted average width of items,
+ * a proper solving of required width would be too costly, and this should give reasonably good results
+ * in all reasonable cases... */
+ if (gflow->columns_len > 0) {
+ gflow->tot_columns = gflow->columns_len;
+ }
+ else {
+ if (avg_w == 0.0f) {
+ gflow->tot_columns = 1;
+ }
+ else {
+ gflow->tot_columns = min_ii(max_ii((int)(litem->w / avg_w), 1), gflow->tot_items);
+ }
+ }
+ gflow->tot_rows = (int)ceilf((float)gflow->tot_items / gflow->tot_columns);
+
+ /* Try to tweak number of columns and rows to get better filling of last column or row,
+ * and apply 'modulo' value to number of columns or rows.
+ * Note that modulo does not prevent ending with fewer columns/rows than modulo, if mandatory
+ * to avoid empty column/row. */
+ {
+ const int modulo = (gflow->columns_len < -1) ? -gflow->columns_len : 0;
+ const int step = modulo ? modulo : 1;
+
+ if (gflow->row_major) {
+ /* Adjust number of columns to be multiple of given modulo. */
+ if (modulo && gflow->tot_columns % modulo != 0 && gflow->tot_columns > modulo) {
+ gflow->tot_columns = gflow->tot_columns - (gflow->tot_columns % modulo);
+ }
+ /* Find smallest number of columns conserving computed optimal number of rows. */
+ for (gflow->tot_rows = (int)ceilf((float)gflow->tot_items / gflow->tot_columns);
+ (gflow->tot_columns - step) > 0 &&
+ (int)ceilf((float)gflow->tot_items / (gflow->tot_columns - step)) <= gflow->tot_rows;
+ gflow->tot_columns -= step);
+ }
+ else {
+ /* Adjust number of rows to be multiple of given modulo. */
+ if (modulo && gflow->tot_rows % modulo != 0) {
+ gflow->tot_rows = min_ii(gflow->tot_rows + modulo - (gflow->tot_rows % modulo), gflow->tot_items);
+ }
+ /* Find smallest number of rows conserving computed optimal number of columns. */
+ for (gflow->tot_columns = (int)ceilf((float)gflow->tot_items / gflow->tot_rows);
+ (gflow->tot_rows - step) > 0 &&
+ (int)ceilf((float)gflow->tot_items / (gflow->tot_rows - step)) <= gflow->tot_columns;
+ gflow->tot_rows -= step);
+ }
+ }
+
+ /* Set evenly-spaced axes size (quick optimization in case we have even columns and rows). */
+ if (gflow->even_columns && gflow->even_rows) {
+ litem->w = (int)(gflow->tot_columns * avg_w) + space_x * (gflow->tot_columns - 1);
+ litem->h = (int)(gflow->tot_rows * max_h) + space_y * (gflow->tot_rows - 1);
+ return;
+ }
+ }
+
+ /* Now that we have our final number of columns and rows,
+ * we can compute actual needed space for non-evenly sized axes. */
+ {
+ int tot_w, tot_h;
+
+ ui_litem_grid_flow_compute(
+ &litem->items,
+ &((UILayoutGridFlowInput) {
+ .row_major = gflow->row_major,
+ .even_columns = gflow->even_columns,
+ .even_rows = gflow->even_rows,
+ .litem_w = litem->w,
+ .litem_x = litem->x,
+ .litem_y = litem->y,
+ .space_x = space_x,
+ .space_y = space_y,
+ .tot_columns = gflow->tot_columns,
+ .tot_rows = gflow->tot_rows,
+ }),
+ &((UILayoutGridFlowOutput) {
+ .tot_w = &tot_w,
+ .tot_h = &tot_h,
+ }));
+
+ litem->w = tot_w;
+ litem->h = tot_h;
+ }
+}
+
+static void ui_litem_layout_grid_flow(uiLayout *litem)
+{
+ int i;
+ uiStyle *style = litem->root->style;
+ uiLayoutItemGridFlow *gflow = (uiLayoutItemGridFlow *)litem;
+ uiItem *item;
+
+ if (gflow->tot_items == 0) {
+ litem->w = litem->h = 0;
+ return;
+ }
+
+ BLI_assert(gflow->tot_columns > 0);
+ BLI_assert(gflow->tot_rows > 0);
+
+ const int space_x = style->columnspace;
+ const int space_y = style->buttonspacey;
+
+ int *widths = BLI_array_alloca(widths, gflow->tot_columns);
+ int *heights = BLI_array_alloca(heights, gflow->tot_rows);
+ int *cos_x = BLI_array_alloca(cos_x, gflow->tot_columns);
+ int *cos_y = BLI_array_alloca(cos_y, gflow->tot_rows);
+
+ /* This time we directly compute coordinates and sizes of all cells. */
+ ui_litem_grid_flow_compute(
+ &litem->items,
+ &((UILayoutGridFlowInput) {
+ .row_major = gflow->row_major,
+ .even_columns = gflow->even_columns,
+ .even_rows = gflow->even_rows,
+ .litem_w = litem->w,
+ .litem_x = litem->x,
+ .litem_y = litem->y,
+ .space_x = space_x,
+ .space_y = space_y,
+ .tot_columns = gflow->tot_columns,
+ .tot_rows = gflow->tot_rows,
+ }),
+ &((UILayoutGridFlowOutput) {
+ .cos_x_array = cos_x,
+ .cos_y_array = cos_y,
+ .widths_array = widths,
+ .heights_array = heights,
+ }));
+
+ for (item = litem->items.first, i = 0; item; item = item->next, i++) {
+ const int col = gflow->row_major ? i % gflow->tot_columns : i / gflow->tot_rows;
+ const int row = gflow->row_major ? i / gflow->tot_columns : i % gflow->tot_rows;
+ int item_w, item_h;
+ ui_item_size(item, &item_w, &item_h);
+
+ const int w = widths[col];
+ const int h = heights[row];
+
+ item_w = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? w : min_ii(w, item_w);
+ item_h = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? h : min_ii(h, item_h);
+
+ ui_item_position(item, cos_x[col], cos_y[row], item_w, item_h);
+ }
+
+ litem->h = litem->y - cos_y[gflow->tot_rows - 1];
+ litem->x = (cos_x[gflow->tot_columns - 1] - litem->x) + widths[gflow->tot_columns - 1];
+ litem->y = litem->y - litem->h;
+}
+
/* free layout */
static void ui_litem_estimate_absolute(uiLayout *litem)
{
@@ -2912,22 +3680,38 @@ static void ui_litem_layout_overlap(uiLayout *litem)
litem->y = y - litem->h;
}
-/* layout create functions */
-uiLayout *uiLayoutRow(uiLayout *layout, bool align)
+static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int align)
{
- uiLayout *litem;
-
- litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
- litem->item.type = ITEM_LAYOUT_ROW;
litem->root = layout->root;
litem->align = align;
+ /* Children of gridflow layout shall never have "ideal big size" returned as estimated size. */
+ litem->variable_size = layout->variable_size || layout->item.type == ITEM_LAYOUT_GRID_FLOW;
litem->active = true;
litem->enabled = true;
litem->context = layout->context;
- litem->space = (align) ? 0 : layout->root->style->buttonspacex;
litem->redalert = layout->redalert;
litem->w = layout->w;
- BLI_addtail(&layout->items, litem);
+ litem->emboss = layout->emboss;
+ litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE));
+
+ if (layout->child_items_layout) {
+ BLI_addtail(&layout->child_items_layout->items, litem);
+ }
+ else {
+ BLI_addtail(&layout->items, litem);
+ }
+}
+
+/* layout create functions */
+uiLayout *uiLayoutRow(uiLayout *layout, bool align)
+{
+ uiLayout *litem;
+
+ litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
+ ui_litem_init_from_parent(litem, layout, align);
+
+ litem->item.type = ITEM_LAYOUT_ROW;
+ litem->space = (align) ? 0 : layout->root->style->buttonspacex;
UI_block_layout_set_current(layout->root->block, litem);
@@ -2939,16 +3723,10 @@ uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
uiLayout *litem;
litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
+ ui_litem_init_from_parent(litem, layout, align);
+
litem->item.type = ITEM_LAYOUT_COLUMN;
- litem->root = layout->root;
- litem->align = align;
- litem->active = true;
- litem->enabled = true;
- litem->context = layout->context;
- litem->space = (litem->align) ? 0 : layout->root->style->buttonspacey;
- litem->redalert = layout->redalert;
- litem->w = layout->w;
- BLI_addtail(&layout->items, litem);
+ litem->space = (align) ? 0 : layout->root->style->buttonspacey;
UI_block_layout_set_current(layout->root->block, litem);
@@ -2960,17 +3738,31 @@ uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align)
uiLayoutItemFlow *flow;
flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
+ ui_litem_init_from_parent(&flow->litem, layout, align);
+
flow->litem.item.type = ITEM_LAYOUT_COLUMN_FLOW;
- flow->litem.root = layout->root;
- flow->litem.align = align;
- flow->litem.active = true;
- flow->litem.enabled = true;
- flow->litem.context = layout->context;
flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
- flow->litem.redalert = layout->redalert;
- flow->litem.w = layout->w;
flow->number = number;
- BLI_addtail(&layout->items, flow);
+
+ UI_block_layout_set_current(layout->root->block, &flow->litem);
+
+ return &flow->litem;
+}
+
+uiLayout *uiLayoutGridFlow(
+ uiLayout *layout, bool row_major, int columns_len, bool even_columns, bool even_rows, bool align)
+{
+ uiLayoutItemGridFlow *flow;
+
+ flow = MEM_callocN(sizeof(uiLayoutItemGridFlow), __func__);
+ flow->litem.item.type = ITEM_LAYOUT_GRID_FLOW;
+ ui_litem_init_from_parent(&flow->litem, layout, align);
+
+ flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
+ flow->row_major = row_major;
+ flow->columns_len = columns_len;
+ flow->even_columns = even_columns;
+ flow->even_rows = even_rows;
UI_block_layout_set_current(layout->root->block, &flow->litem);
@@ -2982,15 +3774,10 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
uiLayoutItemBx *box;
box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
+ ui_litem_init_from_parent(&box->litem, layout, false);
+
box->litem.item.type = ITEM_LAYOUT_BOX;
- box->litem.root = layout->root;
- box->litem.active = 1;
- box->litem.enabled = 1;
- box->litem.context = layout->context;
box->litem.space = layout->root->style->columnspace;
- box->litem.redalert = layout->redalert;
- box->litem.w = layout->w;
- BLI_addtail(&layout->items, box);
UI_block_layout_set_current(layout->root->block, &box->litem);
@@ -3018,14 +3805,9 @@ uiLayout *uiLayoutRadial(uiLayout *layout)
}
litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial");
+ ui_litem_init_from_parent(litem, layout, false);
+
litem->item.type = ITEM_LAYOUT_RADIAL;
- litem->root = layout->root;
- litem->active = true;
- litem->enabled = true;
- litem->context = layout->context;
- litem->redalert = layout->redalert;
- litem->w = layout->w;
- BLI_addtail(&layout->root->layout->items, litem);
UI_block_layout_set_current(layout->root->block, litem);
@@ -3082,14 +3864,9 @@ uiLayout *uiLayoutAbsolute(uiLayout *layout, bool align)
uiLayout *litem;
litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute");
+ ui_litem_init_from_parent(litem, layout, align);
+
litem->item.type = ITEM_LAYOUT_ABSOLUTE;
- litem->root = layout->root;
- litem->align = align;
- litem->active = 1;
- litem->enabled = 1;
- litem->context = layout->context;
- litem->redalert = layout->redalert;
- BLI_addtail(&layout->items, litem);
UI_block_layout_set_current(layout->root->block, litem);
@@ -3111,13 +3888,9 @@ uiLayout *uiLayoutOverlap(uiLayout *layout)
uiLayout *litem;
litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap");
+ ui_litem_init_from_parent(litem, layout, false);
+
litem->item.type = ITEM_LAYOUT_OVERLAP;
- litem->root = layout->root;
- litem->active = true;
- litem->enabled = true;
- litem->context = layout->context;
- litem->redalert = layout->redalert;
- BLI_addtail(&layout->items, litem);
UI_block_layout_set_current(layout->root->block, litem);
@@ -3129,17 +3902,11 @@ uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, bool align)
uiLayoutItemSplit *split;
split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit");
+ ui_litem_init_from_parent(&split->litem, layout, align);
+
split->litem.item.type = ITEM_LAYOUT_SPLIT;
- split->litem.root = layout->root;
- split->litem.align = align;
- split->litem.active = true;
- split->litem.enabled = true;
- split->litem.context = layout->context;
split->litem.space = layout->root->style->columnspace;
- split->litem.redalert = layout->redalert;
- split->litem.w = layout->w;
split->percentage = percentage;
- BLI_addtail(&layout->items, split);
UI_block_layout_set_current(layout->root->block, &split->litem);
@@ -3181,6 +3948,41 @@ void uiLayoutSetScaleY(uiLayout *layout, float scale)
layout->scale[1] = scale;
}
+void uiLayoutSetUnitsX(uiLayout *layout, float unit)
+{
+ layout->units[0] = unit;
+}
+
+void uiLayoutSetUnitsY(uiLayout *layout, float unit)
+{
+ layout->units[1] = unit;
+}
+
+void uiLayoutSetEmboss(uiLayout *layout, char emboss)
+{
+ layout->emboss = emboss;
+}
+
+bool uiLayoutGetPropSep(uiLayout *layout)
+{
+ return (layout->item.flag & UI_ITEM_PROP_SEP) != 0;
+}
+
+void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
+{
+ SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_SEP);
+}
+
+bool uiLayoutGetPropDecorate(uiLayout *layout)
+{
+ return (layout->item.flag & UI_ITEM_PROP_DECORATE) != 0;
+}
+
+void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
+{
+ SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_DECORATE);
+}
+
bool uiLayoutGetActive(uiLayout *layout)
{
return layout->active;
@@ -3221,6 +4023,26 @@ float uiLayoutGetScaleY(uiLayout *layout)
return layout->scale[1];
}
+float uiLayoutGetUnitsX(uiLayout *layout)
+{
+ return layout->units[0];
+}
+
+float uiLayoutGetUnitsY(uiLayout *layout)
+{
+ return layout->units[1];
+}
+
+int uiLayoutGetEmboss(uiLayout *layout)
+{
+ if (layout->emboss == UI_EMBOSS_UNDEFINED) {
+ return layout->root->block->dt;
+ }
+ else {
+ return layout->emboss;
+ }
+}
+
/********************** Layout *******************/
static void ui_item_scale(uiLayout *litem, const float scale[2])
@@ -3229,6 +4051,11 @@ static void ui_item_scale(uiLayout *litem, const float scale[2])
int x, y, w, h;
for (item = litem->items.last; item; item = item->prev) {
+ if (item->type != ITEM_BUTTON) {
+ uiLayout *subitem = (uiLayout *)item;
+ ui_item_scale(subitem, scale);
+ }
+
ui_item_size(item, &w, &h);
ui_item_offset(item, &x, &y);
@@ -3272,6 +4099,9 @@ static void ui_item_estimate(uiItem *item)
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_estimate_column_flow(litem);
break;
+ case ITEM_LAYOUT_GRID_FLOW:
+ ui_litem_estimate_grid_flow(litem);
+ break;
case ITEM_LAYOUT_ROW:
ui_litem_estimate_row(litem);
break;
@@ -3293,6 +4123,14 @@ static void ui_item_estimate(uiItem *item)
default:
break;
}
+
+ /* Force fixed size. */
+ if (litem->units[0] > 0) {
+ litem->w = UI_UNIT_X * litem->units[0];
+ }
+ if (litem->units[1] > 0) {
+ litem->h = UI_UNIT_Y * litem->units[1];
+ }
}
}
@@ -3371,6 +4209,9 @@ static void ui_item_layout(uiItem *item)
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_layout_column_flow(litem);
break;
+ case ITEM_LAYOUT_GRID_FLOW:
+ ui_litem_layout_grid_flow(litem);
+ break;
case ITEM_LAYOUT_ROW:
ui_litem_layout_row(litem);
break;
@@ -3465,7 +4306,10 @@ uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int s
root->opcontext = WM_OP_INVOKE_REGION_WIN;
layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
- layout->item.type = ITEM_LAYOUT_ROOT;
+ layout->item.type = (type == UI_LAYOUT_VERT_BAR) ? ITEM_LAYOUT_COLUMN : ITEM_LAYOUT_ROOT;
+
+ /* Only used when 'UI_ITEM_PROP_SEP' is set. */
+ layout->item.flag = UI_ITEM_PROP_DECORATE;
layout->x = x;
layout->y = y;
@@ -3474,6 +4318,7 @@ uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int s
layout->active = 1;
layout->enabled = 1;
layout->context = NULL;
+ layout->emboss = UI_EMBOSS_UNDEFINED;
if (type == UI_LAYOUT_MENU || type == UI_LAYOUT_PIEMENU)
layout->space = 0;
@@ -3528,12 +4373,21 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
bitem->item.flag |= UI_ITEM_MIN;
}
- BLI_addtail(&layout->items, bitem);
+ if (layout->child_items_layout) {
+ BLI_addtail(&layout->child_items_layout->items, bitem);
+ }
+ else {
+ BLI_addtail(&layout->items, bitem);
+ }
if (layout->context) {
but->context = layout->context;
but->context->used = true;
}
+
+ if (layout->emboss != UI_EMBOSS_UNDEFINED) {
+ but->dt = layout->emboss;
+ }
}
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
@@ -3613,6 +4467,18 @@ MenuType *UI_but_menutype_get(uiBut *but)
}
}
+/* this is a bit of a hack but best keep it in one place at least */
+PanelType *UI_but_paneltype_get(uiBut *but)
+{
+ if (but->menu_create_func == ui_item_paneltype_func) {
+ return (PanelType *)but->poin;
+ }
+ else {
+ return NULL;
+ }
+}
+
+
void UI_menutype_draw(bContext *C, MenuType *mt, struct uiLayout *layout)
{
Menu menu = {
@@ -3634,3 +4500,64 @@ void UI_menutype_draw(bContext *C, MenuType *mt, struct uiLayout *layout)
CTX_store_set(C, NULL);
}
}
+
+
+static void ui_paneltype_draw_impl(
+ bContext *C, PanelType *pt, uiLayout *layout, bool show_header)
+{
+ Panel *panel = MEM_callocN(sizeof(Panel), "popover panel");
+ panel->type = pt;
+ panel->flag = PNL_POPOVER;
+
+ uiLayout *last_item = layout->items.last;
+
+ /* Draw main panel. */
+ if (show_header) {
+ uiLayout *row = uiLayoutRow(layout, false);
+ if (pt->draw_header) {
+ panel->layout = row;
+ pt->draw_header(C, panel);
+ panel->layout = NULL;
+ }
+ uiItemL(row, pt->label, ICON_NONE);
+ }
+
+ panel->layout = layout;
+ pt->draw(C, panel);
+ panel->layout = NULL;
+
+ MEM_freeN(panel);
+
+ /* Draw child panels. */
+ for (LinkData *link = pt->children.first; link; link = link->next) {
+ PanelType *child_pt = link->data;
+
+ if (child_pt->poll == NULL || child_pt->poll(C, child_pt)) {
+ /* Add space if something was added to the layout. */
+ if (last_item != layout->items.last) {
+ uiItemS(layout);
+ last_item = layout->items.last;
+ }
+
+ uiLayout *col = uiLayoutColumn(layout, false);
+ ui_paneltype_draw_impl(C, child_pt, col, true);
+ }
+ }
+}
+
+/**
+ * Used for popup panels only.
+ */
+void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
+{
+ if (layout->context) {
+ CTX_store_set(C, layout->context);
+ }
+
+ ui_paneltype_draw_impl(C, pt, layout, false);
+
+ if (layout->context) {
+ CTX_store_set(C, NULL);
+ }
+
+}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 56f95cd929c..cc609216e9a 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_armature_types.h"
#include "DNA_screen_types.h"
#include "DNA_text_types.h" /* for UI_OT_reports_to_text */
#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
@@ -42,14 +43,21 @@
#include "BLT_lang.h"
#include "BKE_context.h"
-#include "BKE_screen.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_node.h"
-#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
+#include "BKE_screen.h"
+#include "BKE_text.h" /* for UI_OT_reports_to_text */
+
+#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_types.h"
#include "UI_interface.h"
@@ -58,6 +66,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_object.h"
#include "ED_paint.h"
/* only for UI_OT_editsource */
@@ -328,6 +337,217 @@ static void UI_OT_unset_property_button(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
}
+
+/* Note that we use different values for UI/UX than 'real' override operations, user does not care
+ * whether it's added or removed for the differential operation e.g. */
+enum {
+ UIOverride_Type_NOOP = 0,
+ UIOverride_Type_Replace = 1,
+ UIOverride_Type_Difference = 2, /* Add/subtract */
+ UIOverride_Type_Factor = 3, /* Multiply */
+ /* TODO: should/can we expose insert/remove ones for collections? Doubt it... */
+};
+
+static EnumPropertyItem override_type_items[] = {
+ {UIOverride_Type_NOOP, "NOOP", 0, "NoOp",
+ "'No-Operation', place holder preventing automatic override to ever affect the property"},
+ {UIOverride_Type_Replace, "REPLACE", 0, "Replace", "Completely replace value from linked data by local one"},
+ {UIOverride_Type_Difference, "DIFFERENCE", 0, "Difference", "Store difference to linked data value"},
+ {UIOverride_Type_Factor, "FACTOR", 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
+static bool override_type_set_button_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ const int override_status = RNA_property_static_override_status(&ptr, prop, index);
+
+ return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE));
+}
+
+static int override_type_set_button_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+ bool created;
+ const bool all = RNA_boolean_get(op->ptr, "all");
+ const int op_type = RNA_enum_get(op->ptr, "type");
+
+ short operation;
+
+ switch (op_type) {
+ case UIOverride_Type_NOOP:
+ operation = IDOVERRIDESTATIC_OP_NOOP;
+ break;
+ case UIOverride_Type_Replace:
+ operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ case UIOverride_Type_Difference:
+ operation = IDOVERRIDESTATIC_OP_ADD; /* override code will automatically switch to subtract if needed. */
+ break;
+ case UIOverride_Type_Factor:
+ operation = IDOVERRIDESTATIC_OP_MULTIPLY;
+ break;
+ default:
+ operation = IDOVERRIDESTATIC_OP_REPLACE;
+ BLI_assert(0);
+ break;
+ }
+
+ /* try to reset the nominated setting to its default value */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ BLI_assert(ptr.id.data != NULL);
+
+ if (all) {
+ index = -1;
+ }
+
+ IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_get(
+ &ptr, prop, operation, index, true, NULL, &created);
+ if (!created) {
+ opop->operation = operation;
+ }
+
+ return operator_button_property_finish(C, &ptr, prop);
+}
+
+static int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+#if 0 /* Disabled for now */
+ return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
+#else
+ RNA_enum_set(op->ptr, "type", IDOVERRIDESTATIC_OP_REPLACE);
+ return override_type_set_button_exec(C, op);
+#endif
+}
+
+static void UI_OT_override_type_set_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Define Override Type";
+ ot->idname = "UI_OT_override_type_set_button";
+ ot->description = "Create an override operation, or set the type of an existing one";
+
+ /* callbacks */
+ ot->poll = override_type_set_button_poll;
+ ot->exec = override_type_set_button_exec;
+ ot->invoke = override_type_set_button_invoke;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+ ot->prop = RNA_def_enum(
+ ot->srna, "type", override_type_items, UIOverride_Type_Replace,
+ "Type", "Type of override operation");
+ /* TODO: add itemf callback, not all options are available for all data types... */
+}
+
+
+static bool override_remove_button_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ const int override_status = RNA_property_static_override_status(&ptr, prop, index);
+
+ return (ptr.data && ptr.id.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN));
+}
+
+static int override_remove_button_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ PointerRNA ptr, id_refptr, src;
+ PropertyRNA *prop;
+ int index;
+ const bool all = RNA_boolean_get(op->ptr, "all");
+
+ /* try to reset the nominated setting to its default value */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ ID *id = ptr.id.data;
+ IDOverrideStaticProperty *oprop = RNA_property_override_property_find(&ptr, prop);
+ BLI_assert(oprop != NULL);
+ BLI_assert(id != NULL && id->override_static != NULL);
+
+ const bool is_template = (id->override_static->reference == NULL);
+
+ /* We need source (i.e. linked data) to restore values of deleted overrides...
+ * If this is an override template, we obviously do not need to restore anything. */
+ if (!is_template) {
+ RNA_id_pointer_create(id->override_static->reference, &id_refptr);
+ if (!RNA_path_resolve(&id_refptr, oprop->rna_path, &src, NULL)) {
+ BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer");
+ }
+ }
+
+ if (!all && index != -1) {
+ bool is_strict_find;
+ /* Remove override operation for given item, add singular operations for the other items as needed. */
+ IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(
+ oprop, NULL, NULL, index, index, false, &is_strict_find);
+ BLI_assert(opop != NULL);
+ if (!is_strict_find) {
+ /* No specific override operation, we have to get generic one,
+ * and create item-specific override operations for all but given index, before removing generic one. */
+ for (int idx = RNA_property_array_length(&ptr, prop); idx--; ) {
+ if (idx != index) {
+ BKE_override_static_property_operation_get(oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL);
+ }
+ }
+ }
+ BKE_override_static_property_operation_delete(oprop, opop);
+ if (!is_template) {
+ RNA_property_copy(bmain, &ptr, &src, prop, index);
+ }
+ if (BLI_listbase_is_empty(&oprop->operations)) {
+ BKE_override_static_property_delete(id->override_static, oprop);
+ }
+ }
+ else {
+ /* Just remove whole generic override operation of this property. */
+ BKE_override_static_property_delete(id->override_static, oprop);
+ if (!is_template) {
+ RNA_property_copy(bmain, &ptr, &src, prop, -1);
+ }
+ }
+
+ return operator_button_property_finish(C, &ptr, prop);
+}
+
+static void UI_OT_override_remove_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Override";
+ ot->idname = "UI_OT_override_remove_button";
+ ot->description = "Remove an override operation";
+
+ /* callbacks */
+ ot->poll = override_remove_button_poll;
+ ot->exec = override_remove_button_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+}
+
+
+
+
/* Copy To Selected Operator ------------------------ */
bool UI_context_copy_to_selected_list(
@@ -484,6 +704,7 @@ bool UI_context_copy_to_selected_list(
*/
static bool copy_to_selected_button(bContext *C, bool all, bool poll)
{
+ Main *bmain = CTX_data_main(C);
PointerRNA ptr, lptr, idptr;
PropertyRNA *prop, *lprop;
bool success = false;
@@ -532,7 +753,7 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
break;
}
else {
- if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
+ if (RNA_property_copy(bmain, &lptr, &ptr, prop, (all) ? -1 : index)) {
RNA_property_update(C, &lptr, prop);
success = true;
}
@@ -583,6 +804,153 @@ static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
}
+
+/* -------------------------------------------------------------------- */
+/** \name Jump to Target Operator
+ * \{ */
+
+/** Jump to the object or bone referenced by the pointer, or check if it is possible. */
+static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
+{
+ if (RNA_pointer_is_null(&ptr)) {
+ return false;
+ }
+
+ /* Verify pointer type. */
+ char bone_name[MAXBONENAME];
+ const StructRNA *target_type = NULL;
+
+ if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) {
+ RNA_string_get(&ptr, "name", bone_name);
+ if (bone_name[0] != '\0') {
+ target_type = &RNA_Bone;
+ }
+ }
+ else if (RNA_struct_is_a(ptr.type, &RNA_Object)) {
+ target_type = &RNA_Object;
+ }
+
+ if (target_type == NULL) {
+ return false;
+ }
+
+ /* Find the containing Object. */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Base *base = NULL;
+ const short id_type = GS(((ID *)ptr.id.data)->name);
+ if (id_type == ID_OB) {
+ base = BKE_view_layer_base_find(view_layer, ptr.id.data);
+ }
+ else if (OB_DATA_SUPPORT_ID(id_type)) {
+ base = ED_object_find_first_by_data_id(view_layer, ptr.id.data);
+ }
+
+ bool ok = false;
+ if ((base == NULL) ||
+ ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE)))
+ {
+ /* pass */
+ }
+ else if (poll) {
+ ok = true;
+ }
+ else {
+ /* Make optional. */
+ const bool reveal_hidden = true;
+ /* Select and activate the target. */
+ if (target_type == &RNA_Bone) {
+ ok = ED_object_jump_to_bone(C, base->object, bone_name, reveal_hidden);
+ }
+ else if (target_type == &RNA_Object) {
+ ok = ED_object_jump_to_object(C, base->object, reveal_hidden);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ return ok;
+}
+
+/**
+ * Jump to the object or bone referred to by the current UI field value.
+ *
+ * \note quite heavy for a poll callback, but the operator is only
+ * used as a right click menu item for certain UI field types, and
+ * this will fail quickly if the context is completely unsuitable.
+ */
+static bool jump_to_target_button(bContext *C, bool poll)
+{
+ PointerRNA ptr, target_ptr;
+ PropertyRNA *prop;
+ int index;
+
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ /* If there is a valid property... */
+ if (ptr.data && prop) {
+ const PropertyType type = RNA_property_type(prop);
+
+ /* For pointer properties, use their value directly. */
+ if (type == PROP_POINTER) {
+ target_ptr = RNA_property_pointer_get(&ptr, prop);
+
+ return jump_to_target_ptr(C, target_ptr, poll);
+ }
+ /* For string properties with prop_search, look up the search collection item. */
+ else if (type == PROP_STRING) {
+ const uiBut *but = UI_context_active_but_get(C);
+
+ if (but->type == UI_BTYPE_SEARCH_MENU && but->search_func == ui_rna_collection_search_cb) {
+ uiRNACollectionSearch *coll_search = but->search_arg;
+
+ char str_buf[MAXBONENAME];
+ char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL);
+
+ int found = RNA_property_collection_lookup_string(&coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr);
+
+ if (str_ptr != str_buf) {
+ MEM_freeN(str_ptr);
+ }
+
+ if (found) {
+ return jump_to_target_ptr(C, target_ptr, poll);
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool jump_to_target_button_poll(bContext *C)
+{
+ return jump_to_target_button(C, true);
+}
+
+static int jump_to_target_button_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bool success = jump_to_target_button(C, false);
+
+ return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+static void UI_OT_jump_to_target_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Jump To Target";
+ ot->idname = "UI_OT_jump_to_target_button";
+ ot->description = "Switch to the target object or bone";
+
+ /* callbacks */
+ ot->poll = jump_to_target_button_poll;
+ ot->exec = jump_to_target_button_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
/* Reports to Textblock Operator ------------------------ */
/* FIXME: this is just a temporary operator so that we can see all the reports somewhere
@@ -792,6 +1160,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
ui_editsource_active_but_set(but);
/* redraw and get active button python info */
+ ED_region_do_layout(C, ar);
ED_region_do_draw(C, ar);
ar->do_draw = false;
@@ -1024,7 +1393,67 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
ot->exec = reloadtranslation_exec;
}
-bool UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+
+static ARegion *region_event_inside_for_screen(bContext *C, const int xy[2])
+{
+ bScreen *sc = CTX_wm_screen(C);
+ if (sc) {
+ for (ARegion *ar = sc->regionbase.first; ar; ar = ar->next) {
+ if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) {
+ return ar;
+ }
+ }
+ }
+ return NULL;
+}
+
+static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
+ ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *ar = region_event_inside_for_screen(C, &event->x);
+
+ if (ar == NULL) {
+ ar = ar_prev;
+ }
+
+ CTX_wm_region_set(C, ar);
+ uiBut *but = UI_context_active_but_get(C);
+ CTX_wm_region_set(C, ar_prev);
+
+ if (but == NULL) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ if (skip_depressed && (but->flag & (UI_SELECT | UI_SELECT_DRAW))) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ /* Weak, this is a workaround for 'UI_but_is_tool', which checks the operator type,
+ * having this avoids a minor drawing glitch. */
+ void *but_optype = but->optype;
+
+ UI_but_execute(C, but);
+
+ but->optype = but_optype;
+
+ WM_event_add_mousemove(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_button_execute(wmOperatorType *ot)
+{
+ ot->name = "Press Button";
+ ot->idname = "UI_OT_button_execute";
+ ot->description = "Presses active button";
+
+ ot->invoke = ui_button_press_invoke;
+ ot->flag = OPTYPE_INTERNAL;
+
+ RNA_def_boolean(ot->srna, "skip_depressed", 0, "Skip Depressed", "");
+}
+
+bool UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
/* should only return true for regions that include buttons, for now
* return true always */
@@ -1127,7 +1556,10 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_copy_python_command_button);
WM_operatortype_append(UI_OT_reset_default_button);
WM_operatortype_append(UI_OT_unset_property_button);
+ WM_operatortype_append(UI_OT_override_type_set_button);
+ WM_operatortype_append(UI_OT_override_remove_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
+ WM_operatortype_append(UI_OT_jump_to_target_button);
WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */
WM_operatortype_append(UI_OT_drop_color);
#ifdef WITH_PYTHON
@@ -1135,6 +1567,7 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_edittranslation_init);
#endif
WM_operatortype_append(UI_OT_reloadtranslation);
+ WM_operatortype_append(UI_OT_button_execute);
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
@@ -1151,34 +1584,7 @@ void ED_operatortypes_ui(void)
*/
void ED_keymap_ui(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "User Interface", 0, 0);
- wmKeyMapItem *kmi;
-
- /* eyedroppers - notice they all have the same shortcut, but pass the event
- * through until a suitable eyedropper for the active button is found */
- WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband", EKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband_point", EKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0);
-
- /* Copy Data Path */
- WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- kmi = WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "full_path", true);
-
- /* keyframes */
- WM_keymap_add_item(keymap, "ANIM_OT_keyframe_insert_button", IKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_keyframe_delete_button", IKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_keyframe_clear_button", IKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0);
-
- /* drivers */
- WM_keymap_add_item(keymap, "ANIM_OT_driver_button_add", DKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_driver_button_remove", DKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
-
- /* keyingsets */
- WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_add", KKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_remove", KKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_ensure(keyconf, "User Interface", 0, 0);
eyedropper_modal_keymap(keyconf);
eyedropper_colorband_modal_keymap(keyconf);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 20f38b91b98..58dc5617202 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -50,9 +50,6 @@
#include "BKE_context.h"
#include "BKE_screen.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
#include "BLF_api.h"
#include "WM_api.h"
@@ -65,6 +62,9 @@
#include "UI_interface_icons.h"
#include "UI_resources.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
#include "interface_intern.h"
/*********************** defines and structs ************************/
@@ -111,68 +111,107 @@ typedef struct uiHandlePanelData {
int startsizex, startsizey;
} uiHandlePanelData;
+static int get_panel_real_size_y(const Panel *pa);
static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelState state);
/*********************** space specific code ************************/
/* temporary code to remove all sbuts stuff from panel code */
+/* SpaceButs.align */
+typedef enum eSpaceButtons_Align {
+ BUT_HORIZONTAL = 0,
+ BUT_VERTICAL = 1,
+ BUT_AUTO = 2,
+} eSpaceButtons_Align;
+
static int panel_aligned(ScrArea *sa, ARegion *ar)
{
- if (sa->spacetype == SPACE_BUTS && ar->regiontype == RGN_TYPE_WINDOW) {
- SpaceButs *sbuts = sa->spacedata.first;
- return sbuts->align;
- }
+ if (sa->spacetype == SPACE_BUTS && ar->regiontype == RGN_TYPE_WINDOW)
+ return BUT_VERTICAL;
else if (sa->spacetype == SPACE_USERPREF && ar->regiontype == RGN_TYPE_WINDOW)
return BUT_VERTICAL;
else if (sa->spacetype == SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS)
return BUT_VERTICAL;
else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
return BUT_VERTICAL;
- else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
+ else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS, RGN_TYPE_HUD, RGN_TYPE_NAV_BAR))
return BUT_VERTICAL;
return 0;
}
-static int panels_re_align(ScrArea *sa, ARegion *ar, Panel **r_pa)
+static bool panel_active_animation_changed(ListBase *lb, Panel **pa_animation, bool *no_animation)
{
- Panel *pa;
- int active = 0;
+ for (Panel *pa = lb->first; pa; pa = pa->next) {
+ /* Detect panel active flag changes. */
+ if (!(pa->type && pa->type->parent)) {
+ if ((pa->runtime_flag & PNL_WAS_ACTIVE) && !(pa->runtime_flag & PNL_ACTIVE)) {
+ return true;
+ }
+ if (!(pa->runtime_flag & PNL_WAS_ACTIVE) && (pa->runtime_flag & PNL_ACTIVE)) {
+ return true;
+ }
+ }
- *r_pa = NULL;
+ if ((pa->runtime_flag & PNL_ACTIVE) && !(pa->flag & PNL_CLOSED)) {
+ if (panel_active_animation_changed(&pa->children, pa_animation, no_animation)) {
+ return true;
+ }
+ }
+
+ /* Detect animation. */
+ if (pa->activedata) {
+ uiHandlePanelData *data = pa->activedata;
+ if (data->state == PANEL_STATE_ANIMATION) {
+ *pa_animation = pa;
+ }
+ else {
+ /* Don't animate while handling other interaction. */
+ *no_animation = true;
+ }
+ }
+ if ((pa->runtime_flag & PNL_ANIM_ALIGN) && !(*pa_animation)) {
+ *pa_animation = pa;
+ }
+ }
+
+ return false;
+}
+
+static bool panels_need_realign(ScrArea *sa, ARegion *ar, Panel **pa_animate)
+{
+ *pa_animate = NULL;
if (sa->spacetype == SPACE_BUTS && ar->regiontype == RGN_TYPE_WINDOW) {
SpaceButs *sbuts = sa->spacedata.first;
- if (sbuts->align)
- if (sbuts->re_align || sbuts->mainbo != sbuts->mainb)
- return 1;
+ if (sbuts->mainbo != sbuts->mainb) {
+ return true;
+ }
+ }
+ else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW) {
+ return true;
+ }
+ else if (sa->spacetype == SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS) {
+ return true;
}
- else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
- return 1;
- else if (sa->spacetype == SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS)
- return 1;
- /* in case panel is added or disappears */
- for (pa = ar->panels.first; pa; pa = pa->next) {
- if ((pa->runtime_flag & PNL_WAS_ACTIVE) && !(pa->runtime_flag & PNL_ACTIVE))
- return 1;
- if (!(pa->runtime_flag & PNL_WAS_ACTIVE) && (pa->runtime_flag & PNL_ACTIVE))
- return 1;
- if (pa->activedata)
- active = 1;
+ /* Detect if a panel was added or removed. */
+ Panel *pa_animation = NULL;
+ bool no_animation = false;
+ if (panel_active_animation_changed(&ar->panels, &pa_animation, &no_animation)) {
+ return true;
}
- /* in case we need to do an animation (size changes) */
- for (pa = ar->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ANIM_ALIGN) {
- if (!active)
- *r_pa = pa;
- return 1;
+ /* Detect panel marked for animation, if we're not already animating. */
+ if (pa_animation) {
+ if (!no_animation) {
+ *pa_animate = pa_animation;
}
+ return true;
}
- return 0;
+ return false;
}
/****************************** panels ******************************/
@@ -216,14 +255,14 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
*/
/* #define UI_USE_PANELTAB */
-Panel *UI_panel_find_by_type(ARegion *ar, PanelType *pt)
+Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt)
{
Panel *pa;
const char *idname = pt->idname;
#ifdef UI_USE_PANELTAB
const char *tabname = pt->idname;
- for (pa = ar->panels.first; pa; pa = pa->next) {
+ for (pa = lb->first; pa; pa = pa->next) {
if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
if (STREQLEN(pa->tabname, tabname, sizeof(pa->tabname))) {
return pa;
@@ -231,7 +270,7 @@ Panel *UI_panel_find_by_type(ARegion *ar, PanelType *pt)
}
}
#else
- for (pa = ar->panels.first; pa; pa = pa->next) {
+ for (pa = lb->first; pa; pa = pa->next) {
if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
return pa;
}
@@ -244,7 +283,7 @@ Panel *UI_panel_find_by_type(ARegion *ar, PanelType *pt)
/**
* \note \a pa should be return value from #UI_panel_find_by_type and can be NULL.
*/
-Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open)
+Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, ListBase *lb, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open)
{
Panel *palast, *panext;
const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
@@ -276,9 +315,11 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
pa->ofsy = 0;
pa->sizex = 0;
pa->sizey = 0;
+ pa->blocksizex = 0;
+ pa->blocksizey = 0;
pa->runtime_flag |= PNL_NEW_ADDED;
- BLI_addtail(&ar->panels, pa);
+ BLI_addtail(lb, pa);
#ifdef UI_USE_PANELTAB
BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname));
@@ -286,7 +327,7 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
/* make new Panel tabbed? */
if (hookname) {
Panel *patab;
- for (patab = ar->panels.first; patab; patab = patab->next) {
+ for (patab = lb->first; patab; patab = patab->next) {
if ((patab->runtime_flag & PNL_ACTIVE) && patab->paneltab == NULL) {
if (STREQLEN(hookname, patab->panelname, sizeof(patab->panelname))) {
if (STREQLEN(tabname, patab->tabname, sizeof(patab->tabname))) {
@@ -309,6 +350,8 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
/* Force update of panels' positions! */
pa->sizex = 0;
pa->sizey = 0;
+ pa->blocksizex = 0;
+ pa->blocksizey = 0;
}
BLI_strncpy(pa->drawname, drawname, sizeof(pa->drawname));
@@ -316,14 +359,18 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
/* if a new panel is added, we insert it right after the panel
* that was last added. this way new panels are inserted in the
* right place between versions */
- for (palast = ar->panels.first; palast; palast = palast->next)
- if (palast->runtime_flag & PNL_LAST_ADDED)
+ for (palast = lb->first; palast; palast = palast->next) {
+ if (palast->runtime_flag & PNL_LAST_ADDED) {
+ BLI_remlink(lb, pa);
+ BLI_insertlinkafter(lb, palast, pa);
break;
+ }
+ }
if (newpanel) {
pa->sortorder = (palast) ? palast->sortorder + 1 : 0;
- for (panext = ar->panels.first; panext; panext = panext->next)
+ for (panext = lb->first; panext; panext = panext->next)
if (panext != pa && panext->sortorder >= pa->sortorder)
panext->sortorder++;
}
@@ -334,6 +381,9 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
/* assign to block */
block->panel = pa;
pa->runtime_flag |= PNL_ACTIVE | PNL_LAST_ADDED;
+ if (ar->alignment == RGN_ALIGN_FLOAT) {
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+ }
*r_open = false;
@@ -349,6 +399,19 @@ void UI_panel_end(uiBlock *block, int width, int height)
{
Panel *pa = block->panel;
+ /* Set panel size excluding children. */
+ pa->blocksizex = width;
+ pa->blocksizey = height;
+
+ /* Compute total panel size including children. */
+ for (Panel *pachild = pa->children.first; pachild; pachild = pachild->next) {
+ if (pachild->runtime_flag & PNL_ACTIVE) {
+ width = max_ii(width, pachild->sizex);
+ height += get_panel_real_size_y(pachild);
+ }
+ }
+
+ /* Update total panel size. */
if (pa->runtime_flag & PNL_NEW_ADDED) {
pa->runtime_flag &= ~PNL_NEW_ADDED;
pa->sizex = width;
@@ -373,15 +436,13 @@ void UI_panel_end(uiBlock *block, int width, int height)
static void ui_offset_panel_block(uiBlock *block)
{
uiStyle *style = UI_style_get_dpi();
- uiBut *but;
- int ofsy;
/* compute bounds and offset */
ui_block_bounds_calc(block);
- ofsy = block->panel->sizey - style->panelspace;
+ int ofsy = block->panel->sizey - style->panelspace;
- for (but = block->buttons.first; but; but = but->next) {
+ for (uiBut *but = block->buttons.first; but; but = but->next) {
but->rect.ymin += ofsy;
but->rect.ymax += ofsy;
}
@@ -393,81 +454,59 @@ static void ui_offset_panel_block(uiBlock *block)
/**************************** drawing *******************************/
-/* extern used by previewrender */
-#if 0 /*UNUSED 2.5*/
-static void uiPanelPush(uiBlock *block)
-{
- glPushMatrix();
-
- if (block->panel)
- glTranslatef((float)block->panel->ofsx, (float)block->panel->ofsy, 0.0);
-}
-
-static void uiPanelPop(uiBlock *UNUSED(block))
-{
- glPopMatrix();
-}
-#endif
-
/* triangle 'icon' for panel header */
-void UI_draw_icon_tri(float x, float y, char dir)
+void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
{
- float f3 = 0.15 * U.widget_unit;
- float f5 = 0.25 * U.widget_unit;
- float f7 = 0.35 * U.widget_unit;
+ float f3 = 0.05 * U.widget_unit;
+ float f5 = 0.15 * U.widget_unit;
+ float f7 = 0.25 * U.widget_unit;
if (dir == 'h') {
- ui_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y);
+ UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
}
else if (dir == 't') {
- ui_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3);
+ UI_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
}
else { /* 'v' = vertical, down */
- ui_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7);
+ UI_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
}
}
-/* triangle 'icon' inside rect */
-static void ui_draw_tria_rect(const rctf *rect, char dir)
-{
- if (dir == 'h') {
- float half = 0.5f * BLI_rctf_size_y(rect);
- ui_draw_anti_tria(rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half);
- }
- else {
- float half = 0.5f * BLI_rctf_size_x(rect);
- ui_draw_anti_tria(rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin);
- }
-}
-
-static void ui_draw_anti_x(float x1, float y1, float x2, float y2)
+static void ui_draw_anti_x(unsigned int pos, float x1, float y1, float x2, float y2)
{
/* set antialias line */
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ GPU_line_width(2.0);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y2);
- glLineWidth(2.0);
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x2, y1);
- fdrawline(x1, y1, x2, y2);
- fdrawline(x1, y2, x2, y1);
+ immEnd();
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ GPU_line_smooth(false);
+ GPU_blend(false);
}
/* x 'icon' for panel header */
-static void ui_draw_x_icon(float x, float y)
+static void ui_draw_x_icon(unsigned int pos, float x, float y)
{
- ui_draw_anti_x(x, y, x + 9.375f, y + 9.375f);
+ ui_draw_anti_x(pos, x, y, x + 9.375f, y + 9.375f);
}
#define PNL_ICON UI_UNIT_X /* could be UI_UNIT_Y too */
-static void ui_draw_panel_scalewidget(const rcti *rect)
+static void ui_draw_panel_scalewidget(unsigned int pos, const rcti *rect)
{
float xmin, xmax, dx;
float ymin, ymax, dy;
@@ -480,19 +519,56 @@ static void ui_draw_panel_scalewidget(const rcti *rect)
dx = 0.5f * (xmax - xmin);
dy = 0.5f * (ymax - ymin);
- glEnable(GL_BLEND);
- glColor4ub(255, 255, 255, 50);
- fdrawline(xmin, ymin, xmax, ymax);
- fdrawline(xmin + dx, ymin, xmax, ymax - dy);
+ GPU_blend(true);
+ immUniformColor4ub(255, 255, 255, 50);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, xmin, ymin);
+ immVertex2f(pos, xmax, ymax);
+
+ immVertex2f(pos, xmin + dx, ymin);
+ immVertex2f(pos, xmax, ymax - dy);
+
+ immEnd();
+
+ immUniformColor4ub(0, 0, 0, 50);
+
+ immBegin(GPU_PRIM_LINES, 4);
- glColor4ub(0, 0, 0, 50);
- fdrawline(xmin, ymin + 1, xmax, ymax + 1);
- fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1);
- glDisable(GL_BLEND);
+ immVertex2f(pos, xmin, ymin + 1);
+ immVertex2f(pos, xmax, ymax + 1);
+
+ immVertex2f(pos, xmin + dx, ymin + 1);
+ immVertex2f(pos, xmax, ymax - dy + 1);
+
+ immEnd();
+
+ GPU_blend(false);
}
-static void ui_draw_panel_dragwidget(const rctf *rect)
+
+static void immRectf_tris_color_ex(
+ unsigned int pos, float x1, float y1, float x2, float y2,
+ unsigned int col, const float color[3])
+{
+ immAttr4fv(col, color);
+ immVertex2f(pos, x1, y1);
+ immAttr4fv(col, color);
+ immVertex2f(pos, x2, y1);
+ immAttr4fv(col, color);
+ immVertex2f(pos, x2, y2);
+
+ immAttr4fv(col, color);
+ immVertex2f(pos, x1, y1);
+ immAttr4fv(col, color);
+ immVertex2f(pos, x2, y2);
+ immAttr4fv(col, color);
+ immVertex2f(pos, x1, y2);
+}
+
+static void ui_draw_panel_dragwidget(unsigned int pos, unsigned int col, const rctf *rect)
{
- unsigned char col_back[3], col_high[3], col_dark[3];
+ float col_high[4], col_dark[4];
const int col_tint = 84;
const int px = (int)U.pixelsize;
@@ -503,30 +579,45 @@ static void ui_draw_panel_dragwidget(const rctf *rect)
const int x_min = rect->xmin;
const int y_min = rect->ymin;
- const int y_ofs = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 3.0f), px);
+ const int y_ofs = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 2.5f), px);
const int x_ofs = y_ofs;
int i_x, i_y;
-
- UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back);
- UI_GetColorPtrShade3ubv(col_back, col_high, col_tint);
- UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint);
-
+ UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high);
+ UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark);
/* draw multiple boxes */
+ immBegin(GPU_PRIM_TRIS, 4 * 2 * (6 * 2));
for (i_x = 0; i_x < 4; i_x++) {
for (i_y = 0; i_y < 2; i_y++) {
const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin));
const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin));
- glColor3ubv(col_dark);
- glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom);
- glColor3ubv(col_high);
- glRectf(x_co - box_size, y_co, x_co, y_co + box_size);
+ immRectf_tris_color_ex(
+ pos, x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom,
+ col, col_dark);
+ immRectf_tris_color_ex(
+ pos, x_co - box_size, y_co, x_co, y_co + box_size,
+ col, col_high);
}
}
+ immEnd();
}
+/* For button layout next to label. */
+void UI_panel_label_offset(uiBlock *block, int *x, int *y)
+{
+ Panel *panel = block->panel;
+ uiStyle *style = UI_style_get_dpi();
+ const bool is_subpanel = (panel->type && panel->type->parent);
+
+ *x = UI_UNIT_X * 1.1f;
+ *y = (UI_UNIT_Y * 1.1f) + style->panelspace;
+
+ if (is_subpanel) {
+ *x += 5.0f / block->aspect;
+ }
+}
static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const rcti *rect, char dir)
{
@@ -534,6 +625,9 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const r
rcti hrect;
int pnl_icons;
const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname;
+ const bool is_subpanel = (panel->type && panel->type->parent);
+ uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
+ unsigned char col_title[4];
/* + 0.001f to avoid flirting with float inaccuracy */
if (panel->control & UI_PNL_CLOSE)
@@ -541,34 +635,42 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const r
else
pnl_icons = (panel->labelofs + PNL_ICON + 5) / block->aspect + 0.001f;
- /* active tab */
/* draw text label */
- UI_ThemeColor(TH_TITLE);
+ UI_GetThemeColor3ubv(TH_TITLE, col_title);
+ col_title[3] = 255;
hrect = *rect;
if (dir == 'h') {
hrect.xmin = rect->xmin + pnl_icons;
hrect.ymin += 2.0f / block->aspect;
- UI_fontstyle_draw(&style->paneltitle, &hrect, activename);
+ UI_fontstyle_draw(fontstyle, &hrect, activename, col_title);
}
else {
/* ignore 'pnl_icons', otherwise the text gets offset horizontally
* + 0.001f to avoid flirting with float inaccuracy
*/
hrect.xmin = rect->xmin + (PNL_ICON + 5) / block->aspect + 0.001f;
- UI_fontstyle_draw_rotated(&style->paneltitle, &hrect, activename);
+ UI_fontstyle_draw_rotated(fontstyle, &hrect, activename, col_title);
}
}
/* panel integrated in buttonswindow, tool/property lists etc */
-void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, const bool show_pin)
+void ui_draw_aligned_panel(
+ uiStyle *style, uiBlock *block, const rcti *rect,
+ const bool show_pin, const bool show_background)
{
Panel *panel = block->panel;
rcti headrect;
rctf itemrect;
- int ofsx;
+ float color[4];
const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false;
+ const bool is_subpanel = (panel->type && panel->type->parent);
+ const bool show_drag = (
+ !is_subpanel &&
+ /* FIXME(campbell): currently no background means floating panel which can't be dragged.
+ * This may be changed in future. */
+ show_background);
if (panel->paneltab) return;
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) return;
@@ -579,38 +681,40 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
headrect.ymin = headrect.ymax;
headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f);
- {
+ rcti titlerect = headrect;
+ if (is_subpanel) {
+ titlerect.xmin += 5.0f / block->aspect;
+ }
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ if (show_background && !is_subpanel) {
float minx = rect->xmin;
float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
- glEnable(GL_BLEND);
+ GPU_blend(true);
- if (UI_GetThemeValue(TH_PANEL_SHOW_HEADER)) {
- /* draw with background color */
- UI_ThemeColor4(TH_PANEL_HEADER);
- glRectf(minx, headrect.ymin + 1, maxx, y);
+ /* draw with background color */
+ immUniformThemeColor(TH_PANEL_HEADER);
+ immRectf(pos, minx, headrect.ymin, maxx, y);
- fdrawline(minx, y, maxx, y);
- fdrawline(minx, y, maxx, y);
- }
- else if (!(panel->runtime_flag & PNL_FIRST)) {
- /* draw embossed separator */
+ immBegin(GPU_PRIM_LINES, 4);
- if (is_closed_x == false) {
- minx += 5.0f / block->aspect;
- maxx -= 5.0f / block->aspect;
- }
+ immVertex2f(pos, minx, y);
+ immVertex2f(pos, maxx, y);
- glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
- fdrawline(minx, y, maxx, y);
- glColor4f(1.0f, 1.0f, 1.0f, 0.25f);
- fdrawline(minx, y - 1, maxx, y - 1);
- }
+ immVertex2f(pos, minx, y);
+ immVertex2f(pos, maxx, y);
- glDisable(GL_BLEND);
+ immEnd();
+
+ GPU_blend(false);
}
+ immUnbindProgram();
+
/* draw optional pin icon */
#ifdef USE_PIN_HIDDEN
@@ -619,26 +723,42 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
if (show_pin)
#endif
{
- glEnable(GL_BLEND);
+ char col_title[4];
+ UI_GetThemeColor4ubv(TH_TITLE, (uchar *)col_title);
+
+ GPU_blend(true);
UI_icon_draw_aspect(
headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect), headrect.ymin + (5.0f / block->aspect),
(panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED,
- (block->aspect / UI_DPI_FAC), 1.0f);
- glDisable(GL_BLEND);
+ (block->aspect / UI_DPI_FAC), 1.0f, col_title);
+ GPU_blend(false);
}
+
/* horizontal title */
if (is_closed_x == false) {
- ui_draw_aligned_panel_header(style, block, &headrect, 'h');
-
- /* itemrect smaller */
- itemrect.xmax = headrect.xmax - 5.0f / block->aspect;
- itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect);
- itemrect.ymin = headrect.ymin;
- itemrect.ymax = headrect.ymax;
-
- BLI_rctf_scale(&itemrect, 0.7f);
- ui_draw_panel_dragwidget(&itemrect);
+ ui_draw_aligned_panel_header(style, block, &titlerect, 'h');
+
+ if (show_drag) {
+ uint col;
+ GPUVertFormat *format = immVertexFormat();
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ /* itemrect smaller */
+ itemrect.xmax = headrect.xmax - 5.0f / block->aspect;
+ itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect);
+ itemrect.ymin = headrect.ymin;
+ itemrect.ymax = headrect.ymax;
+
+ BLI_rctf_scale(&itemrect, 0.7f);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ ui_draw_panel_dragwidget(pos, col, &itemrect);
+ immUnbindProgram();
+
+ /* Restore format for the following draws. */
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
}
/* if the panel is minimized vertically:
@@ -650,6 +770,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
else if (is_closed_x) {
/* draw vertical title */
ui_draw_aligned_panel_header(style, block, &headrect, 'v');
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
/* an open panel */
else {
@@ -658,55 +779,65 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
if (panel->control & UI_PNL_SOLID) UI_draw_roundbox_corner_set(UI_CNR_ALL);
else UI_draw_roundbox_corner_set(UI_CNR_NONE);
- UI_ThemeColorShade(TH_BACK, -120);
- UI_draw_roundbox_unfilled(0.5f + rect->xmin, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax + 1, 8);
+ UI_GetThemeColorShade4fv(TH_BACK, -120, color);
+ UI_draw_roundbox_aa(false, 0.5f + rect->xmin, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax + 1, 8, color);
}
- /* panel backdrop */
- if (UI_GetThemeValue(TH_PANEL_SHOW_BACK)) {
- /* draw with background color */
- glEnable(GL_BLEND);
- UI_ThemeColor4(TH_PANEL_BACK);
- glRecti(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_blend(true);
+
+ if (show_background) {
+ /* panel backdrop */
+ int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK;
+
+ immUniformThemeColor(panel_col);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
}
if (panel->control & UI_PNL_SCALE)
- ui_draw_panel_scalewidget(rect);
+ ui_draw_panel_scalewidget(pos, rect);
+
+ immUnbindProgram();
}
/* draw optional close icon */
- ofsx = 6;
if (panel->control & UI_PNL_CLOSE) {
- UI_ThemeColor(TH_TITLE);
- ui_draw_x_icon(rect->xmin + 2 + ofsx, rect->ymax + 2);
- ofsx = 22;
+ const int ofsx = 6;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor3(TH_TITLE);
+ ui_draw_x_icon(pos, rect->xmin + 2 + ofsx, rect->ymax + 2);
+ immUnbindProgram();
}
/* draw collapse icon */
- UI_ThemeColor(TH_TITLE);
/* itemrect smaller */
- itemrect.xmin = headrect.xmin + 5.0f / block->aspect;
- itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&headrect);
- itemrect.ymin = headrect.ymin;
- itemrect.ymax = headrect.ymax;
-
- BLI_rctf_scale(&itemrect, 0.35f);
+ itemrect.xmin = titlerect.xmin + 3.0f / block->aspect;
+ itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&titlerect);
+ itemrect.ymin = titlerect.ymin;
+ itemrect.ymax = titlerect.ymax;
- if (is_closed_y)
- ui_draw_tria_rect(&itemrect, 'h');
- else if (is_closed_x)
- ui_draw_tria_rect(&itemrect, 'h');
- else
- ui_draw_tria_rect(&itemrect, 'v');
+ BLI_rctf_scale(&itemrect, 0.25f);
- (void)ofsx;
+ {
+ float tria_color[4];
+ UI_GetThemeColor3fv(TH_TITLE, tria_color);
+ tria_color[3] = 1.0f;
+
+ if (is_closed_y)
+ ui_draw_anti_tria_rect(&itemrect, 'h', tria_color);
+ else if (is_closed_x)
+ ui_draw_anti_tria_rect(&itemrect, 'h', tria_color);
+ else
+ ui_draw_anti_tria_rect(&itemrect, 'v', tria_color);
+ }
}
/************************** panel alignment *************************/
-static int get_panel_header(Panel *pa)
+static int get_panel_header(const Panel *pa)
{
if (pa->type && (pa->type->flag & PNL_NO_HEADER))
return 0;
@@ -714,7 +845,7 @@ static int get_panel_header(Panel *pa)
return PNL_HEADER;
}
-static int get_panel_size_y(Panel *pa)
+static int get_panel_size_y(const Panel *pa)
{
if (pa->type && (pa->type->flag & PNL_NO_HEADER))
return pa->sizey;
@@ -722,6 +853,21 @@ static int get_panel_size_y(Panel *pa)
return PNL_HEADER + pa->sizey;
}
+static int get_panel_real_size_y(const Panel *pa)
+{
+ int sizey = (pa->flag & PNL_CLOSED) ? 0 : pa->sizey;
+
+ if (pa->type && (pa->type->flag & PNL_NO_HEADER))
+ return sizey;
+
+ return PNL_HEADER + sizey;
+}
+
+int UI_panel_size_y(const Panel *pa)
+{
+ return get_panel_real_size_y(pa);
+}
+
/* this function is needed because uiBlock and Panel itself don't
* change sizey or location when closed */
static int get_panel_real_ofsy(Panel *pa)
@@ -794,7 +940,25 @@ static int compare_panel(const void *a1, const void *a2)
return 0;
}
-/* this doesnt draw */
+static void align_sub_panels(Panel *pa)
+{
+ /* Position sub panels. */
+ int ofsy = get_panel_real_ofsy(pa) + pa->sizey - pa->blocksizey;
+
+ for (Panel *pachild = pa->children.first; pachild; pachild = pachild->next) {
+ if (pachild->runtime_flag & PNL_ACTIVE) {
+ pachild->ofsx = pa->ofsx;
+ pachild->ofsy = ofsy - get_panel_size_y(pachild);
+ ofsy -= get_panel_real_size_y(pachild);
+
+ if (pachild->children.first) {
+ align_sub_panels(pachild);
+ }
+ }
+ }
+}
+
+/* this doesn't draw */
/* returns 1 when it did something */
static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bool drag)
{
@@ -854,7 +1018,7 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo
ps->pa->ofsy = -get_panel_size_y(ps->pa);
if (has_category_tabs) {
- if (align == BUT_VERTICAL) {
+ if (align == BUT_VERTICAL && (ar->alignment != RGN_ALIGN_RIGHT)) {
ps->pa->ofsx += UI_PANEL_CATEGORY_MARGIN_WIDTH;
}
}
@@ -885,10 +1049,17 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo
}
}
- /* copy locations to tabs */
- for (pa = ar->panels.first; pa; pa = pa->next)
- if (pa->paneltab && (pa->runtime_flag & PNL_ACTIVE))
- ui_panel_copy_offset(pa, pa->paneltab);
+ /* set locations for tabbed and sub panels */
+ for (pa = ar->panels.first; pa; pa = pa->next) {
+ if (pa->runtime_flag & PNL_ACTIVE) {
+ if (pa->paneltab) {
+ ui_panel_copy_offset(pa, pa->paneltab);
+ }
+ if (pa->children.first) {
+ align_sub_panels(pa);
+ }
+ }
+ }
/* free panelsort array */
for (ps = panelsort, a = 0; a < tot; a++, ps++) {
@@ -958,20 +1129,27 @@ static void ui_do_animate(const bContext *C, Panel *panel)
}
}
-void UI_panels_begin(const bContext *UNUSED(C), ARegion *ar)
+static void panel_list_clear_active(ListBase *lb)
{
- Panel *pa;
-
/* set all panels as inactive, so that at the end we know
* which ones were used */
- for (pa = ar->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE)
+ for (Panel *pa = lb->first; pa; pa = pa->next) {
+ if (pa->runtime_flag & PNL_ACTIVE) {
pa->runtime_flag = PNL_WAS_ACTIVE;
- else
+ }
+ else {
pa->runtime_flag = 0;
+ }
+
+ panel_list_clear_active(&pa->children);
}
}
+void UI_panels_begin(const bContext *UNUSED(C), ARegion *ar)
+{
+ panel_list_clear_active(&ar->panels);
+}
+
/* only draws blocks with panels */
void UI_panels_end(const bContext *C, ARegion *ar, int *x, int *y)
{
@@ -1010,8 +1188,7 @@ void UI_panels_end(const bContext *C, ARegion *ar, int *x, int *y)
}
/* re-align, possibly with animation */
- if (panels_re_align(sa, ar, &pa)) {
- /* XXX code never gets here... PNL_ANIM_ALIGN flag is never set */
+ if (panels_need_realign(sa, ar, &pa)) {
if (pa)
panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
else
@@ -1036,16 +1213,20 @@ void UI_panels_draw(const bContext *C, ARegion *ar)
{
uiBlock *block;
- UI_ThemeClearColor(TH_BACK);
+ if (ar->alignment != RGN_ALIGN_FLOAT) {
+ UI_ThemeClearColor(TH_BACK);
+ }
- /* draw panels, selected on top */
- for (block = ar->uiblocks.first; block; block = block->next) {
+ /* Draw panels, selected on top. Also in reverse order, because
+ * UI blocks are added in reverse order and we need child panels
+ * to draw on top. */
+ for (block = ar->uiblocks.last; block; block = block->prev) {
if (block->active && block->panel && !(block->panel->flag & PNL_SELECT)) {
UI_block_draw(C, block);
}
}
- for (block = ar->uiblocks.first; block; block = block->next) {
+ for (block = ar->uiblocks.last; block; block = block->prev) {
if (block->active && block->panel && (block->panel->flag & PNL_SELECT)) {
UI_block_draw(C, block);
}
@@ -1307,6 +1488,8 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
#else
const bool show_pin = UI_panel_category_is_visible(ar);
#endif
+ const bool is_subpanel = (block->panel->type && block->panel->type->parent);
+ const bool show_drag = !is_subpanel;
int align = panel_aligned(sa, ar), button = 0;
@@ -1396,12 +1579,21 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
}
}
- if (align)
+ if (align) {
panel_activate_state(C, block->panel, PANEL_STATE_ANIMATION);
- else
+ }
+ else {
+ /* FIXME: this doesn't update the panel drawing, assert to avoid debugging why this is.
+ * We could fix this in the future if it's ever needed. */
+ BLI_assert(0);
ED_region_tag_redraw(ar);
+ }
}
- else if (BLI_rctf_isect_x(&rect_drag, mx)) {
+ else if (show_drag && BLI_rctf_isect_x(&rect_drag, mx)) {
+ /* XXX, for now don't allow dragging in floating windows yet. */
+ if (ar->alignment == RGN_ALIGN_FLOAT) {
+ return;
+ }
panel_activate_state(C, block->panel, PANEL_STATE_DRAG);
}
else if (show_pin && BLI_rctf_isect_x(&rect_pin, mx)) {
@@ -1514,12 +1706,23 @@ void UI_panel_category_clear_all(ARegion *ar)
BLI_freelistN(&ar->panels_category);
}
-/* based on UI_draw_roundbox_gl_mode, check on making a version which allows us to skip some sides */
+static void imm_buf_append(
+ float vbuf[][2],
+ uchar cbuf[][3],
+ float x, float y, const uchar col[3], int *index)
+{
+ ARRAY_SET_ITEMS(vbuf[*index], x, y);
+ ARRAY_SET_ITEMS(cbuf[*index], UNPACK3(col));
+ (*index)++;
+}
+
+/* based on UI_draw_roundbox, check on making a version which allows us to skip some sides */
static void ui_panel_category_draw_tab(
- int mode, float minx, float miny, float maxx, float maxy, float rad,
- int roundboxtype,
- const bool use_highlight, const bool use_shadow,
- const unsigned char highlight_fade[3])
+ bool filled, float minx, float miny, float maxx, float maxy, float rad,
+ const int roundboxtype,
+ const bool use_highlight, const bool use_shadow, const bool use_flip_x,
+ const unsigned char highlight_fade[3],
+ const unsigned char col[3])
{
float vec[4][2] = {
{0.195, 0.02},
@@ -1533,69 +1736,98 @@ static void ui_panel_category_draw_tab(
mul_v2_fl(vec[a], rad);
}
- glBegin(mode);
+ uint vert_len = 0;
+ if (use_highlight) {
+ vert_len += (roundboxtype & UI_CNR_TOP_RIGHT) ? 6 : 1;
+ vert_len += (roundboxtype & UI_CNR_TOP_LEFT) ? 6 : 1;
+ }
+ if (use_highlight && !use_shadow) {
+ vert_len++;
+ }
+ else {
+ vert_len += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 6 : 1;
+ vert_len += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 6 : 1;
+ }
+ /* Maximum size. */
+ float vbuf[24][2];
+ uchar cbuf[24][3];
+ int buf_index = 0;
/* start with corner right-top */
if (use_highlight) {
if (roundboxtype & UI_CNR_TOP_RIGHT) {
- glVertex2f(maxx, maxy - rad);
+ imm_buf_append(vbuf, cbuf, maxx, maxy - rad, col, &buf_index);
for (a = 0; a < 4; a++) {
- glVertex2f(maxx - vec[a][1], maxy - rad + vec[a][0]);
+ imm_buf_append(vbuf, cbuf, maxx - vec[a][1], maxy - rad + vec[a][0], col, &buf_index);
}
- glVertex2f(maxx - rad, maxy);
+ imm_buf_append(vbuf, cbuf, maxx - rad, maxy, col, &buf_index);
}
else {
- glVertex2f(maxx, maxy);
+ imm_buf_append(vbuf, cbuf, maxx, maxy, col, &buf_index);
}
/* corner left-top */
if (roundboxtype & UI_CNR_TOP_LEFT) {
- glVertex2f(minx + rad, maxy);
+ imm_buf_append(vbuf, cbuf, minx + rad, maxy, col, &buf_index);
for (a = 0; a < 4; a++) {
- glVertex2f(minx + rad - vec[a][0], maxy - vec[a][1]);
+ imm_buf_append(vbuf, cbuf, minx + rad - vec[a][0], maxy - vec[a][1], col, &buf_index);
}
- glVertex2f(minx, maxy - rad);
+ imm_buf_append(vbuf, cbuf, minx, maxy - rad, col, &buf_index);
}
else {
- glVertex2f(minx, maxy);
+ imm_buf_append(vbuf, cbuf, minx, maxy, col, &buf_index);
}
}
if (use_highlight && !use_shadow) {
- if (highlight_fade) {
- glColor3ubv(highlight_fade);
- }
- glVertex2f(minx, miny + rad);
- glEnd();
- return;
+ imm_buf_append(vbuf, cbuf, minx, miny + rad, highlight_fade ? col : highlight_fade, &buf_index);
}
+ else {
+ /* corner left-bottom */
+ if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
+ imm_buf_append(vbuf, cbuf, minx, miny + rad, col, &buf_index);
+ for (a = 0; a < 4; a++) {
+ imm_buf_append(vbuf, cbuf, minx + vec[a][1], miny + rad - vec[a][0], col, &buf_index);
+ }
+ imm_buf_append(vbuf, cbuf, minx + rad, miny, col, &buf_index);
+ }
+ else {
+ imm_buf_append(vbuf, cbuf, minx, miny, col, &buf_index);
+ }
- /* corner left-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
- glVertex2f(minx, miny + rad);
- for (a = 0; a < 4; a++) {
- glVertex2f(minx + vec[a][1], miny + rad - vec[a][0]);
+ /* corner right-bottom */
+ if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
+ imm_buf_append(vbuf, cbuf, maxx - rad, miny, col, &buf_index);
+ for (a = 0; a < 4; a++) {
+ imm_buf_append(vbuf, cbuf, maxx - rad + vec[a][0], miny + vec[a][1], col, &buf_index);
+ }
+ imm_buf_append(vbuf, cbuf, maxx, miny + rad, col, &buf_index);
+ }
+ else {
+ imm_buf_append(vbuf, cbuf, maxx, miny, col, &buf_index);
}
- glVertex2f(minx + rad, miny);
- }
- else {
- glVertex2f(minx, miny);
}
- /* corner right-bottom */
-
- if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
- glVertex2f(maxx - rad, miny);
- for (a = 0; a < 4; a++) {
- glVertex2f(maxx - rad + vec[a][0], miny + vec[a][1]);
+ if (use_flip_x) {
+ float midx = (minx + maxx) / 2.0f;
+ for (int i = 0; i < buf_index; i++) {
+ vbuf[i][0] = midx - (vbuf[i][0] - midx);
}
- glVertex2f(maxx, miny + rad);
- }
- else {
- glVertex2f(maxx, miny);
+
}
- glEnd();
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_STRIP, vert_len);
+ for (int i = 0; i < buf_index; i++) {
+ immAttr3ubv(color, cbuf[i]);
+ immVertex2fv(pos, vbuf[i]);
+ }
+ immEnd();
+ immUnbindProgram();
}
@@ -1607,21 +1839,23 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
{
/* no tab outlines for */
// #define USE_FLAT_INACTIVE
+ const bool is_left = (ar->alignment != RGN_ALIGN_RIGHT);
View2D *v2d = &ar->v2d;
uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
const int fontid = fstyle->uifont_id;
short fstyle_points = fstyle->points;
-
PanelCategoryDyn *pc_dyn;
const float aspect = ((uiBlock *)ar->uiblocks.first)->aspect;
const float zoom = 1.0f / aspect;
const int px = max_ii(1, round_fl_to_int(U.pixelsize));
+ const int px_x_sign = is_left ? px : -px;
const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom);
const float dpi_fac = UI_DPI_FAC;
const int tab_v_pad_text = round_fl_to_int((2 + ((px * 3) * dpi_fac)) * zoom); /* padding of tabs around text */
const int tab_v_pad = round_fl_to_int((4 + (2 * px * dpi_fac)) * zoom); /* padding between tabs */
const float tab_curve_radius = ((px * 3) * dpi_fac) * zoom;
+ /* We flip the tab drawing, so always use these flags. */
const int roundboxtype = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
bool is_alpha;
bool do_scaletabs = false;
@@ -1630,8 +1864,9 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
#endif
float scaletabs = 1.0f;
/* same for all tabs */
- const int rct_xmin = v2d->mask.xmin + 3; /* intentionally dont scale by 'px' */
- const int rct_xmax = v2d->mask.xmin + category_tabs_width;
+ /* intentionally dont scale by 'px' */
+ const int rct_xmin = is_left ? v2d->mask.xmin + 3 : (v2d->mask.xmax - category_tabs_width);
+ const int rct_xmax = is_left ? v2d->mask.xmin + category_tabs_width : (v2d->mask.xmax - 3);
const int text_v_ofs = (rct_xmax - rct_xmin) * 0.3f;
int y_ofs = tab_v_pad;
@@ -1679,10 +1914,6 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
ui_fontscale(&fstyle_points, aspect / (U.pixelsize * 1.1f));
BLF_size(fontid, fstyle_points, U.dpi);
- BLF_enable(fontid, BLF_SHADOW);
- BLF_shadow(fontid, 3, (const float[4]){1.0f, 1.0f, 1.0f, 0.25f});
- BLF_shadow_offset(fontid, -1, -1);
-
BLI_assert(UI_panel_category_is_visible(ar));
@@ -1716,23 +1947,38 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
/* begin drawing */
- glEnable(GL_LINE_SMOOTH);
+ GPU_line_smooth(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* draw the background */
if (is_alpha) {
- glEnable(GL_BLEND);
- glColor4ubv(theme_col_tab_bg);
+ GPU_blend(true);
+ immUniformColor4ubv(theme_col_tab_bg);
}
else {
- glColor3ubv(theme_col_tab_bg);
+ immUniformColor3ubv(theme_col_tab_bg);
}
- glRecti(v2d->mask.xmin, v2d->mask.ymin, v2d->mask.xmin + category_tabs_width, v2d->mask.ymax);
+ if (is_left) {
+ immRecti(pos, v2d->mask.xmin, v2d->mask.ymin, v2d->mask.xmin + category_tabs_width, v2d->mask.ymax);
+ }
+ else {
+ immRecti(pos, v2d->mask.xmax - category_tabs_width, v2d->mask.ymin, v2d->mask.xmax, v2d->mask.ymax);
+ }
if (is_alpha) {
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
+ immUnbindProgram();
+
+ const int divider_xmin =
+ is_left ? (v2d->mask.xmin + (category_tabs_width - px)) : (v2d->mask.xmax - category_tabs_width) + px;
+ const int divider_xmax =
+ is_left ? (v2d->mask.xmin + category_tabs_width) : (v2d->mask.xmax - (category_tabs_width + px)) + px;
+
for (pc_dyn = ar->panels_category.first; pc_dyn; pc_dyn = pc_dyn->next) {
const rcti *rct = &pc_dyn->rect;
const char *category_id = pc_dyn->idname;
@@ -1743,43 +1989,46 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
const bool is_active = STREQ(category_id, category_id_active);
-#ifdef DEBUG
- if (STREQ(category_id, PNL_CATEGORY_FALLBACK)) {
- printf("WARNING: Panel has no 'bl_category', script needs updating!\n");
- }
-#endif
-
- glEnable(GL_BLEND);
+ GPU_blend(true);
#ifdef USE_FLAT_INACTIVE
if (is_active)
#endif
{
- glColor3ubv(is_active ? theme_col_tab_active : theme_col_tab_inactive);
+ const bool use_flip_x = !is_left;
ui_panel_category_draw_tab(
- GL_POLYGON, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
- tab_curve_radius - px, roundboxtype, true, true, NULL);
+ true, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
+ tab_curve_radius - px, roundboxtype, true, true, use_flip_x,
+ NULL,
+ is_active ? theme_col_tab_active : theme_col_tab_inactive);
/* tab outline */
- glColor3ubv(theme_col_tab_outline);
ui_panel_category_draw_tab(
- GL_LINE_STRIP, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px,
- tab_curve_radius, roundboxtype, true, true, NULL);
+ false, rct->xmin - px_x_sign, rct->ymin - px, rct->xmax - px_x_sign, rct->ymax + px,
+ tab_curve_radius, roundboxtype, true, true, use_flip_x,
+ NULL,
+ theme_col_tab_outline);
+
/* tab highlight (3d look) */
- glColor3ubv(is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive);
ui_panel_category_draw_tab(
- GL_LINE_STRIP, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
- tab_curve_radius, roundboxtype, true, false,
- is_active ? theme_col_back : theme_col_tab_inactive);
+ false, rct->xmin, rct->ymin, rct->xmax, rct->ymax,
+ tab_curve_radius, roundboxtype, true, false, use_flip_x,
+ is_active ? theme_col_back : theme_col_tab_inactive,
+ is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive);
}
/* tab blackline */
if (!is_active) {
- glColor3ubv(theme_col_tab_divider);
- glRecti(v2d->mask.xmin + category_tabs_width - px,
- rct->ymin - tab_v_pad,
- v2d->mask.xmin + category_tabs_width,
- rct->ymax + tab_v_pad);
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3ubv(theme_col_tab_divider);
+ immRecti(pos,
+ divider_xmin,
+ rct->ymin - tab_v_pad,
+ divider_xmax,
+ rct->ymax + tab_v_pad);
+ immUnbindProgram();
}
if (do_scaletabs) {
@@ -1793,52 +2042,60 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
/* tab titles */
/* draw white shadow to give text more depth */
- glColor3ubv(theme_col_text);
+ BLF_color3ubv(fontid, theme_col_text);
/* main tab title */
BLF_draw(fontid, category_id_draw, category_draw_len);
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* tab blackline remaining (last tab) */
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
if (pc_dyn->prev == NULL) {
- glColor3ubv(theme_col_tab_divider);
- glRecti(v2d->mask.xmin + category_tabs_width - px,
- rct->ymax + px,
- v2d->mask.xmin + category_tabs_width,
- v2d->mask.ymax);
+ immUniformColor3ubv(theme_col_tab_divider);
+ immRecti(pos,
+ divider_xmin,
+ rct->ymax + px,
+ divider_xmax,
+ v2d->mask.ymax);
}
if (pc_dyn->next == NULL) {
- glColor3ubv(theme_col_tab_divider);
- glRecti(v2d->mask.xmin + category_tabs_width - px,
- 0,
- v2d->mask.xmin + category_tabs_width,
- rct->ymin);
+ immUniformColor3ubv(theme_col_tab_divider);
+ immRecti(pos,
+ divider_xmin,
+ 0,
+ divider_xmax,
+ rct->ymin);
}
#ifdef USE_FLAT_INACTIVE
/* draw line between inactive tabs */
if (is_active == false && is_active_prev == false && pc_dyn->prev) {
- glColor3ubv(theme_col_tab_divider);
- glRecti(v2d->mask.xmin + (category_tabs_width / 5),
- rct->ymax + px,
- (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5),
- rct->ymax + (px * 3));
+ immUniformColor3ubv(theme_col_tab_divider);
+ immRecti(pos, v2d->mask.xmin + (category_tabs_width / 5),
+ rct->ymax + px,
+ (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5),
+ rct->ymax + (px * 3));
}
is_active_prev = is_active;
#endif
+ immUnbindProgram();
/* not essential, but allows events to be handled right up until the region edge [#38171] */
- pc_dyn->rect.xmin = v2d->mask.xmin;
+ if (is_left) {
+ pc_dyn->rect.xmin = v2d->mask.xmin;
+ }
+ else {
+ pc_dyn->rect.xmax = v2d->mask.xmax;
+ }
}
- glDisable(GL_LINE_SMOOTH);
+ GPU_line_smooth(false);
BLF_disable(fontid, BLF_ROTATION);
- BLF_disable(fontid, BLF_SHADOW);
-
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
@@ -1849,7 +2106,10 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
static int ui_handle_panel_category_cycling(const wmEvent *event, ARegion *ar, const uiBut *active_but)
{
const bool is_mousewheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE);
- const bool inside_tabregion = (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax);
+ const bool inside_tabregion = (
+ (ar->alignment != RGN_ALIGN_RIGHT) ?
+ (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax) :
+ (event->mval[0] > ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmin));
/* if mouse is inside non-tab region, ctrl key is required */
if (is_mousewheel && !event->ctrl && !inside_tabregion)
@@ -1904,6 +2164,11 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons
retval = WM_UI_HANDLER_CONTINUE;
+ /* Scrollbars can overlap panels now, they have handling priority. */
+ if (UI_view2d_mouse_in_scrollers(ar, &ar->v2d, event->x, event->y)) {
+ return retval;
+ }
+
/* handle category tabs */
if (has_category_tabs) {
if (event->val == KM_PRESS) {
@@ -2153,3 +2418,15 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
ED_region_tag_redraw(ar);
}
+
+PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname)
+{
+ SpaceType *st = BKE_spacetype_from_id(space_id);
+ if (st) {
+ ARegionType *art = BKE_regiontype_from_id(st, region_id);
+ if (art) {
+ return BLI_findstring(&art->paneltypes, idname, offsetof(PanelType, idname));
+ }
+ }
+ return NULL;
+}
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 1ad4a7d7f31..d49a1a727aa 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -32,6 +32,9 @@
#include "interface_intern.h"
+#include "WM_api.h"
+#include "WM_types.h"
+
/* -------------------------------------------------------------------- */
/** \name Button (uiBut)
* \{ */
@@ -68,6 +71,39 @@ bool ui_but_is_toggle(const uiBut *but)
);
}
+#ifdef USE_UI_POPOVER_ONCE
+bool ui_but_is_popover_once_compat(const uiBut *but)
+{
+ return (
+ (but->type == UI_BTYPE_BUT) ||
+ ui_but_is_toggle(but)
+ );
+}
+#endif
+
+bool UI_but_is_tool(const uiBut *but)
+{
+ /* very evil! */
+ if (but->optype != NULL) {
+ static wmOperatorType *ot = NULL;
+ if (ot == NULL) {
+ ot = WM_operatortype_find("WM_OT_tool_set_by_name", false);
+ }
+ if (but->optype == ot) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool UI_but_has_tooltip_label(const uiBut *but)
+{
+ if ((but->drawstr[0] == '\0') && !ui_block_is_popover(but->block)) {
+ return UI_but_is_tool(but);
+ }
+ return false;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -81,6 +117,11 @@ bool ui_block_is_menu(const uiBlock *block)
((block->flag & UI_BLOCK_KEEP_OPEN) == 0));
}
+bool ui_block_is_popover(const uiBlock *block)
+{
+ return (block->flag & UI_BLOCK_POPOVER) != 0;
+}
+
bool ui_block_is_pie_menu(const uiBlock *block)
{
return ((block->flag & UI_BLOCK_RADIAL) != 0);
@@ -90,6 +131,7 @@ bool ui_block_is_popup_any(const uiBlock *block)
{
return (
ui_block_is_menu(block) ||
+ ui_block_is_popover(block) ||
ui_block_is_pie_menu(block)
);
}
diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c
index afa3486cf6c..a99bcb2b73c 100644
--- a/source/blender/editors/interface/interface_region_color_picker.c
+++ b/source/blender/editors/interface/interface_region_color_picker.c
@@ -549,8 +549,8 @@ static void ui_block_colorpicker(
UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
bt->custom_data = cpicker;
uiDefBut(
- block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y,
- butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y,
+ butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
ui_rgb_to_color_picker_v(rgb_gamma, hsv);
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
new file mode 100644
index 00000000000..0a5a88f2cb6
--- /dev/null
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -0,0 +1,363 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_region_hud.c
+ * \ingroup edinterface
+ *
+ * Floating Persistent Region
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BLI_string.h"
+#include "BLI_rect.h"
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_color.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_main.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+
+#include "BIF_gl.h"
+
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "BLT_translation.h"
+
+#include "ED_screen.h"
+#include "ED_undo.h"
+
+#include "interface_intern.h"
+#include "GPU_framebuffer.h"
+
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+static bool last_redo_poll(const bContext *C)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+ if (op == NULL) {
+ return false;
+ }
+ bool success = false;
+ if (WM_operator_repeat_check(C, op) &&
+ WM_operator_check_ui_empty(op->type) == false)
+ {
+ success = WM_operator_poll((bContext *)C, op->type);
+ }
+ return success;
+}
+
+static void hud_region_hide(ARegion *ar)
+{
+ ar->flag |= RGN_FLAG_HIDDEN;
+ /* Avoids setting 'AREA_FLAG_REGION_SIZE_UPDATE'
+ * since other regions don't depend on this. */
+ BLI_rcti_init(&ar->winrct, 0, 0, 0, 0);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Redo Panel
+ * \{ */
+
+static bool hud_panel_operator_redo_poll(const bContext *C, PanelType *UNUSED(pt))
+{
+ return last_redo_poll(C);
+}
+
+static void hud_panel_operator_redo_draw_header(const bContext *C, Panel *pa)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+ BLI_strncpy(pa->drawname, RNA_struct_ui_name(op->type->srna), sizeof(pa->drawname));
+}
+
+static void hud_panel_operator_redo_draw(const bContext *C, Panel *pa)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+ if (op == NULL) {
+ return;
+ }
+ if (!WM_operator_check_ui_enabled(C, op->type->name)) {
+ uiLayoutSetEnabled(pa->layout, false);
+ }
+ uiLayout *col = uiLayoutColumn(pa->layout, false);
+ uiTemplateOperatorRedoProperties(col, C);
+}
+
+static void hud_panels_register(ARegionType *art, int space_type, int region_type)
+{
+ PanelType *pt;
+
+ pt = MEM_callocN(sizeof(PanelType), __func__);
+ strcpy(pt->idname, "OPERATOR_PT_redo");
+ strcpy(pt->label, N_("Redo"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw_header = hud_panel_operator_redo_draw_header;
+ pt->draw = hud_panel_operator_redo_draw;
+ pt->poll = hud_panel_operator_redo_poll;
+ pt->space_type = space_type;
+ pt->region_type = region_type;
+ pt->flag |= PNL_DEFAULT_CLOSED;
+ BLI_addtail(&art->paneltypes, pt);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for Floating Region
+ * \{ */
+
+struct HudRegionData {
+ short regionid;
+};
+
+static void hud_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ ED_region_panels_init(wm, ar);
+ UI_region_handlers_add(&ar->handlers);
+ ar->flag |= RGN_FLAG_TEMP_REGIONDATA;
+}
+
+static void hud_region_free(ARegion *ar)
+{
+ MEM_SAFE_FREE(ar->regiondata);
+}
+
+static void hud_region_layout(const bContext *C, ARegion *ar)
+{
+ bool ok = false;
+
+ {
+ struct HudRegionData *hrd = ar->regiondata;
+ if (hrd != NULL) {
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar_op = (hrd->regionid != -1) ? BKE_area_find_region_type(sa, hrd->regionid) : NULL;
+ ARegion *ar_prev = CTX_wm_region(C);
+ CTX_wm_region_set((bContext *)C, ar_op);
+ ok = last_redo_poll(C);
+ CTX_wm_region_set((bContext *)C, ar_prev);
+ }
+ }
+
+ if (!ok) {
+ ED_region_tag_redraw(ar);
+ hud_region_hide(ar);
+ return;
+ }
+
+ int size_y = ar->sizey;
+
+ ED_region_panels_layout(C, ar);
+
+ if (ar->panels.first && (ar->sizey != size_y)) {
+ View2D *v2d = &ar->v2d;
+ ar->winx = ar->sizex;
+ ar->winy = ar->sizey;
+
+ ar->winrct.xmax = (ar->winrct.xmin + ar->winx) - 1;
+ ar->winrct.ymax = (ar->winrct.ymin + ar->winy) - 1;
+
+ UI_view2d_region_reinit(v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy);
+
+ /* Weak, but needed to avoid glitches, especially with hi-dpi (where resizing the view glitches often).
+ * Fortunately this only happens occasionally. */
+ ED_region_panels_layout(C, ar);
+ }
+
+ /* restore view matrix */
+ UI_view2d_view_restore(C);
+}
+
+static void hud_region_draw(const bContext *C, ARegion *ar)
+{
+ UI_view2d_view_ortho(&ar->v2d);
+ wmOrtho2_region_pixelspace(ar);
+ GPU_clear_color(0, 0, 0, 0.0f);
+ GPU_clear(GPU_COLOR_BIT);
+
+ if ((ar->flag & RGN_FLAG_HIDDEN) == 0) {
+ ui_draw_menu_back(NULL, NULL, &(rcti){.xmax = ar->winx, .ymax = ar->winy});
+ ED_region_panels_draw(C, ar);
+ }
+}
+
+ARegionType *ED_area_type_hud(int space_type)
+{
+ ARegionType *art = MEM_callocN(sizeof(ARegionType), __func__);
+ art->regionid = RGN_TYPE_HUD;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
+ art->layout = hud_region_layout;
+ art->draw = hud_region_draw;
+ art->init = hud_region_init;
+ art->free = hud_region_free;
+
+ hud_panels_register(art, space_type, art->regionid);
+
+ art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */
+ return art;
+}
+
+static ARegion *hud_region_add(ScrArea *sa)
+{
+ ARegion *ar = MEM_callocN(sizeof(ARegion), "area region");
+ ARegion *ar_win = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ if (ar_win) {
+ BLI_insertlinkbefore(&sa->regionbase, ar_win, ar);
+ }
+ else {
+ BLI_addtail(&sa->regionbase, ar);
+ }
+ ar->regiontype = RGN_TYPE_HUD;
+ ar->alignment = RGN_ALIGN_FLOAT;
+ ar->overlap = true;
+ ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
+
+ return ar;
+}
+
+void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *sa_keep)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa != sa_keep) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_HUD) {
+ if ((ar->flag & RGN_FLAG_HIDDEN) == 0) {
+ hud_region_hide(ar);
+ ED_region_tag_redraw(ar);
+ ED_area_tag_redraw(sa);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ED_area_type_hud_clear(wm, sa);
+
+ ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_HUD);
+ if (art == NULL) {
+ return;
+ }
+
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HUD);
+ bool init = false;
+ bool was_hidden = ar == NULL || ar->visible == false;
+ if (!last_redo_poll(C)) {
+ if (ar) {
+ ED_region_tag_redraw(ar);
+ hud_region_hide(ar);
+ }
+ return;
+ }
+
+ if (ar == NULL) {
+ init = true;
+ ar = hud_region_add(sa);
+ ar->type = art;
+ }
+
+ /* Let 'ED_area_update_region_sizes' do the work of placing the region.
+ * Otherwise we could set the 'ar->winrct' & 'ar->winx/winy' here. */
+ if (init) {
+ sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ }
+ else {
+ if (ar->flag & RGN_FLAG_HIDDEN) {
+ sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ }
+ ar->flag &= ~RGN_FLAG_HIDDEN;
+ }
+
+ {
+ ARegion *ar_op = CTX_wm_region(C);
+ BLI_assert((ar_op == NULL) || (ar_op->regiontype != RGN_TYPE_HUD));
+ struct HudRegionData *hrd = ar->regiondata;
+ if (hrd == NULL) {
+ hrd = MEM_callocN(sizeof(*hrd), __func__);
+ ar->regiondata = hrd;
+ }
+ if (ar_op) {
+ hrd->regionid = ar_op->regiontype;
+ }
+ else {
+ hrd->regionid = -1;
+ }
+ }
+
+ if (init) {
+ /* This is needed or 'winrct' will be invalid. */
+ wmWindow *win = CTX_wm_window(C);
+ ED_area_update_region_sizes(wm, win, sa);
+ }
+
+ ED_region_init(ar);
+ ED_region_tag_redraw(ar);
+
+ /* Reset zoom level (not well supported). */
+ ar->v2d.cur = ar->v2d.tot = (rctf){.xmax = ar->winx, .ymax = ar->winy};
+ ar->v2d.minzoom = 1.0f;
+ ar->v2d.maxzoom = 1.0f;
+
+ ar->visible = !(ar->flag & RGN_FLAG_HIDDEN);
+
+ /* We shouldn't need to do this every time :S */
+ /* XXX, this is evil! - it also makes the menu show on first draw. :( */
+ if (ar->visible) {
+ ARegion *ar_prev = CTX_wm_region(C);
+ CTX_wm_region_set((bContext *)C, ar);
+ hud_region_layout(C, ar);
+ if (was_hidden) {
+ ar->winx = ar->v2d.winx;
+ ar->winy = ar->v2d.winy;
+ ar->v2d.cur = ar->v2d.tot = (rctf){.xmax = ar->winx, .ymax = ar->winy};
+ }
+ CTX_wm_region_set((bContext *)C, ar_prev);
+ }
+
+ ar->visible = !((ar->flag & RGN_FLAG_HIDDEN) || (ar->flag & RGN_FLAG_TOO_SMALL));
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c
index ef2d273bab6..44effc8c097 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.c
+++ b/source/blender/editors/interface/interface_region_menu_pie.c
@@ -76,7 +76,7 @@ static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handl
uiPieMenu *pie = arg_pie;
int minwidth, width, height;
- minwidth = 50;
+ minwidth = UI_MENU_WIDTH_MIN;
block = pie->block_radial;
/* in some cases we create the block before the region,
@@ -105,7 +105,7 @@ static float ui_pie_menu_title_width(const char *name, int icon)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
return (UI_fontstyle_string_width(fstyle, name) +
- (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
+ (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
}
uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, const wmEvent *event)
@@ -152,15 +152,9 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co
pie->layout = UI_block_layout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
- /* Open from where we started dragging. */
- if (event->val == KM_CLICK_DRAG) {
- pie->mx = event->prevclickx;
- pie->my = event->prevclicky;
- }
- else {
- pie->mx = event->x;
- pie->my = event->y;
- }
+ /* Note event->x/y is where we started dragging in case of KM_CLICK_DRAG. */
+ pie->mx = event->x;
+ pie->my = event->y;
/* create title button */
if (title[0]) {
@@ -203,7 +197,6 @@ 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);
}
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index fac96fc2154..bdac03de86b 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -191,7 +191,13 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
if (pup->but) {
/* minimum width to enforece */
- minwidth = BLI_rctf_size_x(&pup->but->rect);
+ if (pup->but->drawstr[0]) {
+ minwidth = BLI_rctf_size_x(&pup->but->rect);
+ }
+ else {
+ /* For buttons with no text, use the minimum (typically icon only). */
+ minwidth = UI_MENU_WIDTH_MIN;
+ }
/* settings (typically rna-enum-popups) show above the button,
* menu's like file-menu, show below */
@@ -209,7 +215,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
}
}
else {
- minwidth = 50;
+ minwidth = UI_MENU_WIDTH_MIN;
direction = UI_DIR_DOWN;
}
@@ -285,7 +291,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
/* for a header menu we set the direction automatic */
if (!pup->slideout && flip) {
ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->headertype == HEADERDOWN) {
+ if (sa && ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
ARegion *ar = CTX_wm_region(C);
if (ar && ar->regiontype == RGN_TYPE_HEADER) {
UI_block_direction_set(block, UI_DIR_UP);
@@ -360,7 +366,6 @@ uiPopupBlockHandle *ui_popup_menu_create(
WM_event_add_mousemove(C);
}
- handle->can_refresh = false;
MEM_freeN(pup);
return handle;
@@ -451,7 +456,6 @@ 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);
}
@@ -570,6 +574,7 @@ void UI_popup_block_invoke_ex(bContext *C, uiBlockCreateFunc func, void *arg, co
handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg);
handle->popup = true;
+ handle->can_refresh = true;
handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
handle->opcontext = opcontext;
@@ -592,6 +597,7 @@ void UI_popup_block_ex(
handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg);
handle->popup = true;
handle->retvalue = 1;
+ handle->can_refresh = true;
handle->popup_op = op;
handle->popup_arg = arg;
@@ -612,6 +618,7 @@ void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int
handle = ui_popup_block_create(C, NULL, NULL, func, NULL, op);
handle->popup = 1;
handle->retvalue = 1;
+ handle->can_refresh = true;
handle->popup_arg = op;
handle->popup_func = operator_cb;
@@ -628,11 +635,13 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
/* if loading new .blend while popup is open, window will be NULL */
if (block->handle) {
if (win) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
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 another, see: T48874 */
- for (ARegion *ar = win->screen->regionbase.first; ar; ar = ar->next) {
+ for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) {
ED_region_tag_refresh_ui(ar);
}
}
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
new file mode 100644
index 00000000000..cb4939adc56
--- /dev/null
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -0,0 +1,396 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_region_popover.c
+ * \ingroup edinterface
+ *
+ * Pop-Over Region
+ *
+ * \note This is very close to 'interface_region_menu_popup.c'
+ *
+ * We could even merge them, however menu logic is already over-loaded.
+ * PopOver's have the following differences.
+ *
+ * - UI is not constrained to a list.
+ * - Pressing a button won't close the pop-over.
+ * - Different draw style (to show this is has different behavior from a menu).
+ * - #PanelType are used instead of #MenuType.
+ * - No menu flipping support.
+ * - No moving the menu to fit the mouse cursor.
+ * - No key accelerators to access menu items
+ * (if we add support they would work differently).
+ * - No arrow key navigation.
+ * - No menu memory.
+ * - No title.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BLI_rect.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_report.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+
+#include "UI_interface.h"
+
+#include "interface_intern.h"
+#include "interface_regions_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Popup Menu with Callback or String
+ * \{ */
+
+struct uiPopover {
+ uiBlock *block;
+ uiLayout *layout;
+ uiBut *but;
+
+ /* Needed for keymap removal. */
+ wmWindow *window;
+ wmKeyMap *keymap;
+ struct wmEventHandler *keymap_handler;
+
+ uiMenuCreateFunc menu_func;
+ void *menu_arg;
+
+ /* Size in pixels (ui scale applied). */
+ int ui_size_x;
+
+#ifdef USE_UI_POPOVER_ONCE
+ bool is_once;
+#endif
+};
+
+static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext)
+{
+ BLI_assert(pup->ui_size_x != 0);
+
+ uiStyle *style = UI_style_get_dpi();
+
+ pup->block = UI_block_begin(C, NULL, __func__, UI_EMBOSS);
+ UI_block_flag_enable(pup->block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER);
+#ifdef USE_UI_POPOVER_ONCE
+ if (pup->is_once) {
+ UI_block_flag_enable(pup->block, UI_BLOCK_POPOVER_ONCE);
+ }
+#endif
+
+ pup->layout = UI_block_layout(
+ pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0,
+ pup->ui_size_x, 0, MENU_PADDING, style);
+
+ uiLayoutSetOperatorContext(pup->layout, opcontext);
+
+ if (pup->but) {
+ if (pup->but->context) {
+ uiLayoutContextCopy(pup->layout, pup->but->context);
+ }
+ }
+
+ pup->block->flag |= UI_BLOCK_NO_FLIP;
+}
+
+static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
+{
+ uiPopover *pup = arg_pup;
+
+ /* Create UI block and layout now if it wasn't done between begin/end. */
+ if (!pup->layout) {
+ ui_popover_create_block(C, pup, WM_OP_INVOKE_REGION_WIN);
+
+ if (pup->menu_func) {
+ pup->block->handle = handle;
+ pup->menu_func(C, pup->layout, pup->menu_arg);
+ pup->block->handle = NULL;
+ }
+
+ pup->layout = NULL;
+ }
+
+ /* Setup and resolve UI layout for block. */
+ uiBlock *block = pup->block;
+ int width, height;
+
+ UI_block_region_set(block, handle->region);
+ UI_block_layout_resolve(block, &width, &height);
+ UI_block_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X);
+
+ const int block_margin = U.widget_unit / 2;
+
+ if (pup->but) {
+ /* For a header menu we set the direction automatic. */
+ block->minbounds = BLI_rctf_size_x(&pup->but->rect);
+ UI_block_bounds_set_normal(block, block_margin);
+
+ /* If menu slides out of other menu, override direction. */
+ bool slideout = ui_block_is_menu(pup->but->block);
+ if (slideout)
+ UI_block_direction_set(block, UI_DIR_RIGHT);
+
+ /* Store the button location for positioning the popover arrow hint. */
+ if (!handle->refresh) {
+ float center[2] = {BLI_rctf_cent_x(&pup->but->rect), BLI_rctf_cent_y(&pup->but->rect)};
+ ui_block_to_window_fl(handle->ctx_region, pup->but->block, &center[0], &center[1]);
+ /* These variables aren't used for popovers, we could add new variables if there is a conflict. */
+ handle->prev_mx = block->mx = (int)center[0];
+ handle->prev_my = block->my = (int)center[1];
+ }
+ else {
+ block->mx = handle->prev_mx;
+ block->my = handle->prev_my;
+ }
+
+ if (!slideout) {
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (ar && ar->panels.first) {
+ /* For regions with panels, prefer to open to top so we can
+ * see the values of the buttons below changing. */
+ UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
+ }
+ else if (sa && ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
+ /* Prefer popover from header to be positioned into the editor. */
+ if (ar && ar->regiontype == RGN_TYPE_HEADER) {
+ UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
+ }
+ }
+ }
+
+ /* Estimated a maximum size so we don't go offscreen for low height
+ * areas near the bottom of the window on refreshes. */
+ handle->max_size_y = UI_UNIT_Y * 16.0f;
+ }
+ else {
+ /* Not attached to a button. */
+ int offset[2] = {0, 0};
+ UI_block_flag_enable(block, UI_BLOCK_LOOP);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+ UI_block_direction_set(block, block->direction);
+ block->minbounds = UI_MENU_WIDTH_MIN;
+ bool use_place_under_active = !handle->refresh;
+
+ if (use_place_under_active) {
+ uiBut *but = NULL;
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->flag & (UI_SELECT | UI_SELECT_DRAW)) {
+ break;
+ }
+ }
+
+ if (but) {
+ offset[0] = -(but->rect.xmin + 0.8f * BLI_rctf_size_x(&but->rect));
+ offset[1] = -(but->rect.ymin + 0.5f * BLI_rctf_size_y(&but->rect));
+ }
+ }
+
+ UI_block_bounds_set_popup(block, block_margin, offset[0], offset[1]);
+ }
+
+ return block;
+}
+
+static void ui_block_free_func_POPOVER(uiPopupBlockHandle *UNUSED(handle), void *arg_pup)
+{
+ uiPopover *pup = arg_pup;
+ if (pup->keymap != NULL) {
+ wmWindow *window = pup->window;
+ WM_event_remove_keymap_handler(&window->modalhandlers, pup->keymap);
+ }
+ MEM_freeN(pup);
+}
+
+uiPopupBlockHandle *ui_popover_panel_create(
+ bContext *C, ARegion *butregion, uiBut *but,
+ uiMenuCreateFunc menu_func, void *arg)
+{
+ /* Create popover, buttons are created from callback. */
+ uiPopover *pup = MEM_callocN(sizeof(uiPopover), __func__);
+ pup->but = but;
+
+ /* FIXME: maybe one day we want non panel popovers? */
+ {
+ int ui_units_x = ((PanelType *)arg)->ui_units_x;
+ pup->ui_size_x = U.widget_unit * (ui_units_x ? ui_units_x : UI_POPOVER_WIDTH_UNITS);
+ }
+
+ pup->menu_func = menu_func;
+ pup->menu_arg = arg;
+
+#ifdef USE_UI_POPOVER_ONCE
+ pup->is_once = true;
+#endif
+
+ /* Create popup block. */
+ uiPopupBlockHandle *handle;
+ handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup);
+ handle->popup_create_vars.free_func = ui_block_free_func_POPOVER;
+ handle->can_refresh = true;
+
+ /* Add handlers. If attached to a button, the button will already
+ * add a modal handler and pass on events. */
+ if (!but) {
+ wmWindow *window = CTX_wm_window(C);
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
+ WM_event_add_mousemove(C);
+ handle->popup = true;
+ }
+
+ return handle;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Standard Popover Panels
+ * \{ */
+
+int UI_popover_panel_invoke(
+ bContext *C, const char *idname,
+ bool keep_open, ReportList *reports)
+{
+ uiLayout *layout;
+ PanelType *pt = WM_paneltype_find(idname, true);
+ if (pt == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Panel \"%s\" not found", idname);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (pt->poll && (pt->poll(C, pt) == false)) {
+ /* cancel but allow event to pass through, just like operators do */
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
+ if (keep_open) {
+ ui_popover_panel_create(C, NULL, NULL, ui_item_paneltype_func, pt);
+ }
+ else {
+ uiPopover *pup = UI_popover_begin(C, U.widget_unit * pt->ui_units_x);
+ layout = UI_popover_layout(pup);
+ UI_paneltype_draw(C, pt, layout);
+ UI_popover_end(C, pup, NULL);
+ }
+
+ return OPERATOR_INTERFACE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Popup Menu API with begin & end
+ * \{ */
+
+/**
+ * Only return handler, and set optional title.
+ */
+uiPopover *UI_popover_begin(bContext *C, int ui_size_x)
+{
+ uiPopover *pup = MEM_callocN(sizeof(uiPopover), "popover menu");
+ if (ui_size_x == 0) {
+ ui_size_x = U.widget_unit * UI_POPOVER_WIDTH_UNITS;
+ }
+ pup->ui_size_x = ui_size_x;
+
+ /* Opertor context default same as menus, change if needed. */
+ ui_popover_create_block(C, pup, WM_OP_EXEC_REGION_WIN);
+
+ /* create in advance so we can let buttons point to retval already */
+ pup->block->handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
+
+ return pup;
+}
+
+static void popover_keymap_fn(wmKeyMap *UNUSED(keymap), wmKeyMapItem *UNUSED(kmi), void *user_data)
+{
+ uiPopover *pup = user_data;
+ pup->block->handle->menuretval = UI_RETURN_OK;
+}
+
+/* set the whole structure to work */
+void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap)
+{
+ wmWindow *window = CTX_wm_window(C);
+ /* Create popup block. No refresh support since the buttons were created
+ * between begin/end and we have no callback to recreate them. */
+ uiPopupBlockHandle *handle;
+
+ if (keymap) {
+ /* Add so we get keymaps shown in the buttons. */
+ UI_block_flag_enable(pup->block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
+ pup->keymap = keymap;
+ pup->keymap_handler = WM_event_add_keymap_handler_priority(&window->modalhandlers, keymap, 0);
+ WM_event_set_keymap_handler_callback(pup->keymap_handler, popover_keymap_fn, pup);
+ }
+
+ handle = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPOVER, pup);
+ handle->popup_create_vars.free_func = ui_block_free_func_POPOVER;
+
+ /* Add handlers. */
+ UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
+ WM_event_add_mousemove(C);
+ handle->popup = true;
+
+ /* Re-add so it gets priority. */
+ if (keymap) {
+ BLI_remlink(&window->modalhandlers, pup->keymap_handler);
+ BLI_addhead(&window->modalhandlers, pup->keymap_handler);
+ }
+
+ pup->window = window;
+
+ /* TODO(campbell): we may want to make this configurable.
+ * The begin/end stype of calling popups doesn't allow to 'can_refresh' to be set.
+ * For now close this style of popvers when accessed. */
+ UI_block_flag_disable(pup->block, UI_BLOCK_KEEP_OPEN);
+
+ /* panels are created flipped (from event handling pov) */
+ pup->block->flag ^= UI_BLOCK_IS_FLIP;
+}
+
+uiLayout *UI_popover_layout(uiPopover *pup)
+{
+ return pup->layout;
+}
+
+#ifdef USE_UI_POPOVER_ONCE
+void UI_popover_once_clear(uiPopover *pup)
+{
+ pup->is_once = false;
+}
+#endif
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 93fd62b5c66..b62857983df 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -48,7 +48,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "wm_subwindow.h"
#include "UI_interface.h"
@@ -64,13 +63,13 @@
/**
* Translate any popup regions (so we can drag them).
*/
-void ui_popup_translate(bContext *C, ARegion *ar, const int mdiff[2])
+void ui_popup_translate(ARegion *ar, const int mdiff[2])
{
uiBlock *block;
BLI_rcti_translate(&ar->winrct, UNPACK2(mdiff));
- ED_region_update_rect(C, ar);
+ ED_region_update_rect(ar);
ED_region_tag_redraw(ar);
@@ -85,32 +84,41 @@ void ui_popup_translate(bContext *C, ARegion *ar, const int mdiff[2])
}
/* position block relative to but, result is in window space */
-static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block)
+static void ui_popup_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block)
{
- uiBut *bt;
- uiSafetyRct *saferct;
+ uiPopupBlockHandle *handle = block->handle;
+
+ /* Compute button position in window coordinates using the source
+ * button region/block, to position the popup attached to it. */
rctf butrct;
- /*float aspect;*/ /*UNUSED*/
- int size_x, size_y, offset_x = 0, offset_y = 0;
- short dir1 = 0, dir2 = 0;
- /* transform to window coordinates, using the source button region/block */
- ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect);
+ if (!handle->refresh) {
+ ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect);
+
+ /* widget_roundbox_set has this correction too, keep in sync */
+ if (but->type != UI_BTYPE_PULLDOWN) {
+ if (but->drawflag & UI_BUT_ALIGN_TOP)
+ butrct.ymax += U.pixelsize;
+ if (but->drawflag & UI_BUT_ALIGN_LEFT)
+ butrct.xmin -= U.pixelsize;
+ }
- /* widget_roundbox_set has this correction too, keep in sync */
- if (but->type != UI_BTYPE_PULLDOWN) {
- if (but->drawflag & UI_BUT_ALIGN_TOP)
- butrct.ymax += U.pixelsize;
- if (but->drawflag & UI_BUT_ALIGN_LEFT)
- butrct.xmin -= U.pixelsize;
+ handle->prev_butrct = butrct;
+ }
+ else {
+ /* For refreshes, keep same button position so popup doesn't move. */
+ butrct = handle->prev_butrct;
}
- /* calc block rect */
+ /* Compute block size in window space, based on buttons contained in it. */
if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) {
if (block->buttons.first) {
BLI_rctf_init_minmax(&block->rect);
- for (bt = block->buttons.first; bt; bt = bt->next) {
+ for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ if (block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT) {
+ bt->rect.xmax += UI_MENU_SUBMENU_PADDING;
+ }
BLI_rctf_union(&block->rect, &bt->rect);
}
}
@@ -121,34 +129,34 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
}
}
- /* aspect = (float)(BLI_rcti_size_x(&block->rect) + 4);*/ /*UNUSED*/
ui_block_to_window_rctf(butregion, but->block, &block->rect, &block->rect);
- //block->rect.xmin -= 2.0; block->rect.ymin -= 2.0;
- //block->rect.xmax += 2.0; block->rect.ymax += 2.0;
+ /* Compute direction relative to button, based on available space. */
+ const int size_x = BLI_rctf_size_x(&block->rect) + 0.2f * UI_UNIT_X; /* 4 for shadow */
+ const int size_y = BLI_rctf_size_y(&block->rect) + 0.2f * UI_UNIT_Y;
+ const int center_x = (block->direction & UI_DIR_CENTER_X) ? size_x / 2 : 0;
+ const int center_y = (block->direction & UI_DIR_CENTER_Y) ? size_y / 2 : 0;
- size_x = BLI_rctf_size_x(&block->rect) + 0.2f * UI_UNIT_X; /* 4 for shadow */
- size_y = BLI_rctf_size_y(&block->rect) + 0.2f * UI_UNIT_Y;
- /* aspect /= (float)size_x;*/ /*UNUSED*/
+ short dir1 = 0, dir2 = 0;
- {
+ if (!handle->refresh) {
bool left = 0, right = 0, top = 0, down = 0;
- // int offscreen;
const int win_x = WM_window_pixels_x(window);
const int win_y = WM_window_pixels_y(window);
- // wm_window_get_size(window, &win_x, &win_y);
- const int center_y = (block->direction & UI_DIR_CENTER_Y) ? size_y / 2 : 0;
+ /* Take into account maximum size so we don't have to flip on refresh. */
+ const float max_size_x = max_ff(size_x, handle->max_size_x);
+ const float max_size_y = max_ff(size_y, handle->max_size_y);
/* check if there's space at all */
- if (butrct.xmin - size_x > 0.0f) left = 1;
- if (butrct.xmax + size_x < win_x) right = 1;
- if (butrct.ymin - size_y + center_y > 0.0f) down = 1;
- if (butrct.ymax + size_y - center_y < win_y) top = 1;
+ if (butrct.xmin - max_size_x + center_x > 0.0f) left = 1;
+ if (butrct.xmax + max_size_x - center_x < win_x) right = 1;
+ if (butrct.ymin - max_size_y + center_y > 0.0f) down = 1;
+ if (butrct.ymax + max_size_y - center_y < win_y) top = 1;
if (top == 0 && down == 0) {
- if (butrct.ymin - size_y < win_y - butrct.ymax - size_y)
+ if (butrct.ymin - max_size_y < win_y - butrct.ymax - max_size_y)
top = 1;
else
down = 1;
@@ -182,65 +190,57 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
if (dir2 == UI_DIR_DOWN && down == 0) dir2 = UI_DIR_UP;
}
- if (dir1 == UI_DIR_LEFT) {
- offset_x = butrct.xmin - block->rect.xmax;
- if (dir2 == UI_DIR_UP) offset_y = butrct.ymin - block->rect.ymin - center_y - MENU_PADDING;
- else offset_y = butrct.ymax - block->rect.ymax + center_y + MENU_PADDING;
- }
- else if (dir1 == UI_DIR_RIGHT) {
- offset_x = butrct.xmax - block->rect.xmin;
- if (dir2 == UI_DIR_UP) offset_y = butrct.ymin - block->rect.ymin - center_y - MENU_PADDING;
- else offset_y = butrct.ymax - block->rect.ymax + center_y + MENU_PADDING;
- }
- else if (dir1 == UI_DIR_UP) {
- offset_y = butrct.ymax - block->rect.ymin;
- if (dir2 == UI_DIR_RIGHT) offset_x = butrct.xmax - block->rect.xmax;
- else offset_x = butrct.xmin - block->rect.xmin;
- /* changed direction? */
- if ((dir1 & block->direction) == 0) {
- UI_block_order_flip(block);
- }
- }
- else if (dir1 == UI_DIR_DOWN) {
- offset_y = butrct.ymin - block->rect.ymax;
- if (dir2 == UI_DIR_RIGHT) offset_x = butrct.xmax - block->rect.xmax;
- else offset_x = butrct.xmin - block->rect.xmin;
- /* changed direction? */
- if ((dir1 & block->direction) == 0) {
- UI_block_order_flip(block);
- }
- }
+ handle->prev_dir1 = dir1;
+ handle->prev_dir2 = dir2;
+ }
+ else {
+ /* For refreshes, keep same popup direct so popup doesn't move
+ * to a totally different position while editing in it. */
+ dir1 = handle->prev_dir1;
+ dir2 = handle->prev_dir2;
+ }
- /* and now we handle the exception; no space below or to top */
- if (top == 0 && down == 0) {
- if (dir1 == UI_DIR_LEFT || dir1 == UI_DIR_RIGHT) {
- /* align with bottom of screen */
- // offset_y = size_y; (not with menu scrolls)
- }
- }
+ /* Compute offset based on direction. */
+ int offset_x = 0, offset_y = 0;
-#if 0 /* seems redundant and causes issues with blocks inside big regions */
- /* or no space left or right */
- if (left == 0 && right == 0) {
- if (dir1 == UI_DIR_UP || dir1 == UI_DIR_DOWN) {
- /* align with left size of screen */
- offset_x = -block->rect.xmin + 5;
- }
+ if (dir1 == UI_DIR_LEFT) {
+ offset_x = butrct.xmin - block->rect.xmax;
+ if (dir2 == UI_DIR_UP) offset_y = butrct.ymin - block->rect.ymin - center_y - MENU_PADDING;
+ else offset_y = butrct.ymax - block->rect.ymax + center_y + MENU_PADDING;
+ }
+ else if (dir1 == UI_DIR_RIGHT) {
+ offset_x = butrct.xmax - block->rect.xmin;
+ if (dir2 == UI_DIR_UP) offset_y = butrct.ymin - block->rect.ymin - center_y - MENU_PADDING;
+ else offset_y = butrct.ymax - block->rect.ymax + center_y + MENU_PADDING;
+ }
+ else if (dir1 == UI_DIR_UP) {
+ offset_y = butrct.ymax - block->rect.ymin;
+ if (dir2 == UI_DIR_RIGHT) offset_x = butrct.xmax - block->rect.xmax + center_x;
+ else offset_x = butrct.xmin - block->rect.xmin - center_x;
+ /* changed direction? */
+ if ((dir1 & block->direction) == 0) {
+ /* TODO: still do */
+ UI_block_order_flip(block);
+ }
+ }
+ else if (dir1 == UI_DIR_DOWN) {
+ offset_y = butrct.ymin - block->rect.ymax;
+ if (dir2 == UI_DIR_RIGHT) offset_x = butrct.xmax - block->rect.xmax + center_x;
+ else offset_x = butrct.xmin - block->rect.xmin - center_x;
+ /* changed direction? */
+ if ((dir1 & block->direction) == 0) {
+ /* TODO: still do */
+ UI_block_order_flip(block);
}
-#endif
-
-#if 0
- /* clamp to window bounds, could be made into an option if its ever annoying */
- if ( (offscreen = (block->rect.ymin + offset_y)) < 0) offset_y -= offscreen; /* bottom */
- else if ((offscreen = (block->rect.ymax + offset_y) - winy) > 0) offset_y -= offscreen; /* top */
- if ( (offscreen = (block->rect.xmin + offset_x)) < 0) offset_x -= offscreen; /* left */
- else if ((offscreen = (block->rect.xmax + offset_x) - winx) > 0) offset_x -= offscreen; /* right */
-#endif
}
- /* apply offset, buttons in window coords */
+ /* Center over popovers for eg. */
+ if (block->direction & UI_DIR_CENTER_X) {
+ offset_x += BLI_rctf_size_x(&butrct) / ((dir2 == UI_DIR_LEFT) ? 2 : - 2);
+ }
- for (bt = block->buttons.first; bt; bt = bt->next) {
+ /* Apply offset, buttons in window coords. */
+ for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
ui_block_to_window_rctf(butregion, but->block, &bt->rect, &bt->rect);
BLI_rctf_translate(&bt->rect, offset_x, offset_y);
@@ -251,7 +251,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
BLI_rctf_translate(&block->rect, offset_x, offset_y);
- /* safety calculus */
+ /* Safety calculus. */
{
const float midx = BLI_rctf_cent_x(&butrct);
const float midy = BLI_rctf_cent_y(&butrct);
@@ -281,7 +281,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
}
/* keep a list of these, needed for pulldown menus */
- saferct = MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct");
+ uiSafetyRct *saferct = MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct");
saferct->parent = butrct;
saferct->safety = block->safety;
BLI_freelistN(&block->saferct);
@@ -295,7 +295,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
/** \name Menu Block Creation
* \{ */
-static void ui_block_region_draw(const bContext *C, ARegion *ar)
+static void ui_block_region_refresh(const bContext *C, ARegion *ar)
{
ScrArea *ctx_area = CTX_wm_area(C);
ARegion *ctx_region = CTX_wm_region(C);
@@ -309,9 +309,11 @@ 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;
- if (block->handle->can_refresh) {
- handle_ctx_area = block->handle->ctx_area;
- handle_ctx_region = block->handle->ctx_region;
+ uiPopupBlockHandle *handle = block->handle;
+
+ if (handle->can_refresh) {
+ handle_ctx_area = handle->ctx_area;
+ handle_ctx_region = handle->ctx_region;
if (handle_ctx_area) {
CTX_wm_area_set((bContext *)C, handle_ctx_area);
@@ -319,13 +321,21 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
if (handle_ctx_region) {
CTX_wm_region_set((bContext *)C, handle_ctx_region);
}
- ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL);
+
+ uiBut *but = handle->popup_create_vars.but;
+ ARegion *butregion = handle->popup_create_vars.butregion;
+ ui_popup_block_refresh((bContext *)C, handle, butregion, but);
}
}
}
CTX_wm_area_set((bContext *)C, ctx_area);
CTX_wm_region_set((bContext *)C, ctx_region);
+}
+
+static void ui_block_region_draw(const bContext *C, ARegion *ar)
+{
+ uiBlock *block;
for (block = ar->uiblocks.first; block; block = block->next)
UI_block_draw(C, block);
@@ -335,7 +345,7 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
* Use to refresh centered popups on screen resizing (for splash).
*/
static void ui_block_region_popup_window_listener(
- bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn, const Scene *UNUSED(scene))
{
switch (wmn->category) {
case NC_WINDOW:
@@ -455,8 +465,6 @@ 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;
@@ -468,6 +476,10 @@ uiBlock *ui_popup_block_refresh(
uiBlock *block_old = ar->uiblocks.first;
uiBlock *block;
+ handle->refresh = (block_old != NULL);
+
+ BLI_assert(!handle->refresh || handle->can_refresh);
+
#ifdef DEBUG
wmEvent *event_back = window->eventstate;
#endif
@@ -514,7 +526,7 @@ uiBlock *ui_popup_block_refresh(
/* if this is being created from a button */
if (but) {
block->aspect = but->block->aspect;
- ui_block_position(window, butregion, but, block);
+ ui_popup_block_position(window, butregion, but, block);
handle->direction = block->direction;
}
else {
@@ -552,7 +564,7 @@ uiBlock *ui_popup_block_refresh(
block->pie_data.pie_center_spawned[0] += x_offset;
block->pie_data.pie_center_spawned[1] += y_offset;
- ui_block_translate(block, x_offset, y_offset);
+ UI_block_translate(block, x_offset, y_offset);
if (U.pie_initial_timeout > 0)
block->pie_data.flags |= UI_PIE_INITIAL_DIRECTION;
@@ -577,6 +589,17 @@ uiBlock *ui_popup_block_refresh(
else {
/* clip block with window boundary */
ui_popup_block_clip(window, block);
+
+ /* Avoid menu moving down and losing cursor focus by keeping it at
+ * the same height. */
+ if (handle->refresh && handle->prev_block_rect.ymax > block->rect.ymax) {
+ float offset = handle->prev_block_rect.ymax - block->rect.ymax;
+ UI_block_translate(block, 0, offset);
+ block->rect.ymin = handle->prev_block_rect.ymin;
+ }
+
+ handle->prev_block_rect = block->rect;
+
/* the block and buttons were positioned in window space as in 2.4x, now
* these menu blocks are regions so we bring it back to region space.
* additionally we add some padding for the menu shadow or rounded menus */
@@ -585,7 +608,15 @@ uiBlock *ui_popup_block_refresh(
ar->winrct.ymin = block->rect.ymin - margin;
ar->winrct.ymax = block->rect.ymax + UI_POPUP_MENU_TOP;
- ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
+ UI_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
+
+ /* apply scroll offset */
+ if (handle->scrolloffset != 0.0f) {
+ for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ bt->rect.ymin += handle->scrolloffset;
+ bt->rect.ymax += handle->scrolloffset;
+ }
+ }
}
if (block_old) {
@@ -598,17 +629,15 @@ uiBlock *ui_popup_block_refresh(
ui_popup_block_scrolltest(block);
/* adds subwindow */
- ED_region_init(C, ar);
+ ED_region_init(ar);
/* get winmat now that we actually have the subwindow */
- wmSubWindowSet(window, ar->swinid);
-
- wm_subwindow_matrix_get(window, ar->swinid, block->winmat);
+ wmGetProjectionMatrix(block->winmat, &ar->winrct);
/* notify change and redraw */
ED_region_tag_redraw(ar);
- ED_region_update_rect(C, ar);
+ ED_region_update_rect(ar);
#ifdef DEBUG
window->eventstate = event_back;
@@ -647,10 +676,12 @@ uiPopupBlockHandle *ui_popup_block_create(
handle->popup_create_vars.create_func = create_func;
handle->popup_create_vars.handle_create_func = handle_create_func;
handle->popup_create_vars.arg = arg;
+ handle->popup_create_vars.but = but;
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;
+
+ /* don't allow by default, only if popup type explicitly supports it */
+ handle->can_refresh = false;
/* create area region */
ar = ui_region_temp_add(CTX_wm_screen(C));
@@ -658,6 +689,7 @@ uiPopupBlockHandle *ui_popup_block_create(
memset(&type, 0, sizeof(ARegionType));
type.draw = ui_block_region_draw;
+ type.layout = ui_block_region_refresh;
type.regionid = RGN_TYPE_TEMPORARY;
ar->type = &type;
@@ -667,7 +699,7 @@ uiPopupBlockHandle *ui_popup_block_create(
handle = block->handle;
/* keep centered on window resizing */
- if ((block->bounds_type == UI_BLOCK_BOUNDS_POPUP_CENTER) && handle->can_refresh) {
+ if (block->bounds_type == UI_BLOCK_BOUNDS_POPUP_CENTER) {
type.listener = ui_block_region_popup_window_listener;
}
@@ -676,6 +708,25 @@ uiPopupBlockHandle *ui_popup_block_create(
void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
{
+ /* If this popup is created from a popover which does NOT have keep-open flag set,
+ * then close the popover too. We could extend this to other popup types too. */
+ ARegion *ar = handle->popup_create_vars.butregion;
+ if (ar != NULL) {
+ for (uiBlock *block = ar->uiblocks.first; block; block = block->next) {
+ if (block->handle &&
+ (block->flag & UI_BLOCK_POPOVER) &&
+ (block->flag & UI_BLOCK_KEEP_OPEN) == 0)
+ {
+ uiPopupBlockHandle *menu = block->handle;
+ menu->menuretval = UI_RETURN_OK;
+ }
+ }
+ }
+
+ if (handle->popup_create_vars.free_func) {
+ handle->popup_create_vars.free_func(handle, handle->popup_create_vars.arg);
+ }
+
ui_popup_block_remove(C, handle);
MEM_freeN(handle);
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index 8d4389c73e6..48d59830c2a 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -64,6 +64,7 @@
#include "interface_intern.h"
#include "interface_regions_intern.h"
+#include "GPU_state.h"
#define MENU_BORDER (int)(0.3f * U.widget_unit)
@@ -397,15 +398,16 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *ar, uiBut *but, char *str)
return match;
}
-static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
+static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *ar)
{
uiSearchboxData *data = ar->regiondata;
/* pixel space */
wmOrtho2_region_pixelspace(ar);
- if (data->noback == false)
- ui_draw_search_back(NULL, NULL, &data->bbox); /* style not used yet */
+ if (data->noback == false) {
+ ui_draw_widget_back(UI_WTYPE_MENU_BACK, true, &data->bbox);
+ }
/* draw text */
if (data->items.totitem) {
@@ -415,6 +417,9 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
if (data->preview) {
/* draw items */
for (a = 0; a < data->items.totitem; a++) {
+ /* ensure icon is up-to-date */
+ ui_icon_ensure_deferred(C, data->items.icons[a], data->preview);
+
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
@@ -426,15 +431,15 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* indicate more */
if (data->items.more) {
ui_searchbox_butrect(&rect, data, data->items.maxitem - 1);
- glEnable(GL_BLEND);
+ GPU_blend(true);
UI_icon_draw(rect.xmax - 18, rect.ymin - 7, ICON_TRIA_DOWN);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
if (data->items.offset) {
ui_searchbox_butrect(&rect, data, 0);
- glEnable(GL_BLEND);
+ GPU_blend(true);
UI_icon_draw(rect.xmin, rect.ymax - 9, ICON_TRIA_UP);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
}
@@ -452,15 +457,15 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* indicate more */
if (data->items.more) {
ui_searchbox_butrect(&rect, data, data->items.maxitem - 1);
- glEnable(GL_BLEND);
+ GPU_blend(true);
UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymin - 9, ICON_TRIA_DOWN);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
if (data->items.offset) {
ui_searchbox_butrect(&rect, data, 0);
- glEnable(GL_BLEND);
+ GPU_blend(true);
UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymax - 7, ICON_TRIA_UP);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
}
}
@@ -528,8 +533,10 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but
data->prv_cols = but->a2;
}
- /* only show key shortcuts when needed (not rna buttons) [#36699] */
- if (but->rnaprop == NULL) {
+ /* Only show key shortcuts when needed (checking RNA prop pointer is useless here, a lot of buttons are about data
+ * without having that pointer defined, let's rather try with optype!). One can also enforce that behavior by
+ * setting UI_BUT_HAS_SHORTCUT drawflag of search button. */
+ if (but->optype != NULL || (but->drawflag & UI_BUT_HAS_SHORTCUT) != 0) {
data->use_sep = true;
}
@@ -624,7 +631,7 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but
}
/* adds subwindow */
- ED_region_init(C, ar);
+ ED_region_init(ar);
/* notify change and redraw */
ED_region_tag_redraw(ar);
@@ -680,8 +687,9 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
/* pixel space */
wmOrtho2_region_pixelspace(ar);
- if (data->noback == false)
- ui_draw_search_back(NULL, NULL, &data->bbox); /* style not used yet */
+ if (data->noback == false) {
+ ui_draw_widget_back(UI_WTYPE_MENU_BACK, true, &data->bbox);
+ }
/* draw text */
if (data->items.totitem) {
@@ -730,15 +738,15 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
/* indicate more */
if (data->items.more) {
ui_searchbox_butrect(&rect, data, data->items.maxitem - 1);
- glEnable(GL_BLEND);
+ GPU_blend(true);
UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymin - 9, ICON_TRIA_DOWN);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
if (data->items.offset) {
ui_searchbox_butrect(&rect, data, 0);
- glEnable(GL_BLEND);
+ GPU_blend(true);
UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymax - 7, ICON_TRIA_UP);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
}
}
@@ -747,6 +755,7 @@ ARegion *ui_searchbox_create_operator(bContext *C, ARegion *butregion, uiBut *bu
{
ARegion *ar;
+ UI_but_drawflag_enable(but, UI_BUT_HAS_SHORTCUT);
ar = ui_searchbox_create_generic(C, butregion, but);
ar->type->draw = ui_searchbox_region_draw_cb__operator;
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 7bb0a02bbf6..1a167b3fd72 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -45,6 +45,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
+#include "DNA_brush_types.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -53,6 +54,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_paint.h"
#include "BKE_screen.h"
#include "WM_api.h"
@@ -67,6 +69,10 @@
#include "BLF_api.h"
#include "BLT_translation.h"
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
#include "ED_screen.h"
#include "interface_intern.h"
@@ -164,6 +170,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
uiWidgetColors *theme = ui_tooltip_get_theme();
rcti bbox = data->bbox;
float tip_colors[UI_TIP_LC_MAX][3];
+ unsigned char drawcol[4] = {0, 0, 0, 255}; /* to store color in while drawing (alpha is always 255) */
float *main_color = tip_colors[UI_TIP_LC_MAIN]; /* the color from the theme */
float *value_color = tip_colors[UI_TIP_LC_VALUE];
@@ -174,12 +181,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
float background_color[3];
float tone_bg;
- int i, multisample_enabled;
-
- /* disable AA, makes widgets too blurry */
- multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
- if (multisample_enabled)
- glDisable(GL_MULTISAMPLE);
+ int i;
wmOrtho2_region_pixelspace(ar);
@@ -226,17 +228,11 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
uiFontStyle fstyle_header = data->fstyle;
/* override text-style */
- fstyle_header.shadow = 1;
- fstyle_header.shadowcolor = rgb_to_grayscale(tip_colors[UI_TIP_LC_MAIN]);
- fstyle_header.shadx = fstyle_header.shady = 0;
- fstyle_header.shadowalpha = 1.0f;
fstyle_header.word_wrap = true;
+ rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]);
UI_fontstyle_set(&fstyle_header);
- glColor3fv(tip_colors[UI_TIP_LC_MAIN]);
- UI_fontstyle_draw(&fstyle_header, &bbox, field->text);
-
- fstyle_header.shadow = 0;
+ UI_fontstyle_draw(&fstyle_header, &bbox, field->text, drawcol);
/* offset to the end of the last line */
if (field->text_suffix) {
@@ -245,8 +241,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
bbox.xmin += xofs;
bbox.ymax -= yofs;
- glColor3fv(tip_colors[UI_TIP_LC_ACTIVE]);
- UI_fontstyle_draw(&fstyle_header, &bbox, field->text_suffix);
+ rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]);
+ UI_fontstyle_draw(&fstyle_header, &bbox, field->text_suffix, drawcol);
/* undo offset */
bbox.xmin -= xofs;
@@ -261,8 +257,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
UI_fontstyle_set(&fstyle_mono);
/* XXX, needed because we dont have mono in 'U.uifonts' */
BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi);
- glColor3fv(tip_colors[field->format.color_id]);
- UI_fontstyle_draw(&fstyle_mono, &bbox, field->text);
+ rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
+ UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, drawcol);
}
else {
uiFontStyle fstyle_normal = data->fstyle;
@@ -270,9 +266,9 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
fstyle_normal.word_wrap = true;
/* draw remaining data */
+ rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
UI_fontstyle_set(&fstyle_normal);
- glColor3fv(tip_colors[field->format.color_id]);
- UI_fontstyle_draw(&fstyle_normal, &bbox, field->text);
+ UI_fontstyle_draw(&fstyle_normal, &bbox, field->text, drawcol);
}
bbox.ymax -= data->lineh * field->geom.lines;
@@ -284,9 +280,6 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
BLF_disable(data->fstyle.uifont_id, BLF_WORD_WRAP);
BLF_disable(blf_mono_font, BLF_WORD_WRAP);
-
- if (multisample_enabled)
- glEnable(GL_MULTISAMPLE);
}
static void ui_tooltip_region_free_cb(ARegion *ar)
@@ -313,6 +306,285 @@ static void ui_tooltip_region_free_cb(ARegion *ar)
/** \name ToolTip Creation
* \{ */
+static bool ui_tooltip_data_append_from_keymap(
+ bContext *C, uiTooltipData *data,
+ wmKeyMap *keymap)
+{
+ const int fields_len_init = data->fields_len;
+ char buf[512];
+
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, true);
+ if (ot != NULL) {
+ /* Tip */
+ {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_MAIN,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup(ot->description ? ot->description : ot->name);
+ }
+ /* Shortcut */
+ {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_NORMAL,
+ });
+ bool found = false;
+ if (WM_keymap_item_to_string(kmi, false, buf, sizeof(buf))) {
+ found = true;
+ }
+ field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None");
+ }
+
+ /* Python */
+ if (U.flag & USER_TOOLTIPS_PYTHON) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_PYTHON,
+ });
+ char *str = WM_operator_pystring_ex(C, NULL, false, false, ot, kmi->ptr);
+ WM_operator_pystring_abbreviate(str, 32);
+ field->text = BLI_sprintfN(TIP_("Python: %s"), str);
+ MEM_freeN(str);
+ }
+ }
+ }
+
+ return (fields_len_init != data->fields_len);
+}
+
+
+/**
+ * Special tool-system exception.
+ */
+static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is_label)
+{
+ if (but->optype == NULL) {
+ return NULL;
+ }
+
+ if (!STREQ(but->optype->idname, "WM_OT_tool_set_by_name")) {
+ return NULL;
+ }
+
+ /* Needed to get the space-data's type (below). */
+ if (CTX_wm_space_data(C) == NULL) {
+ return NULL;
+ }
+
+ char tool_name[MAX_NAME];
+ RNA_string_get(but->opptr, "name", tool_name);
+ BLI_assert(tool_name[0] != '\0');
+
+ /* We have a tool, now extract the info. */
+ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
+
+#ifdef WITH_PYTHON
+ /* it turns out to be most simple to do this via Python since C
+ * doesn't have access to information about non-active tools.
+ */
+
+ /* Title (when icon-only). */
+ if (but->drawstr[0] == '\0') {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_MAIN,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup(tool_name);
+ }
+
+ /* Tip. */
+ if (is_label == false) {
+ const char *expr_imports[] = {"bpy", "bl_ui", NULL};
+ char expr[256];
+ SNPRINTF(
+ expr,
+ "bl_ui.space_toolsystem_common.description_from_name("
+ "bpy.context, "
+ "bpy.context.space_data.type, "
+ "'%s') + '.'",
+ tool_name);
+
+ char *expr_result = NULL;
+ bool is_error = false;
+ if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
+ if (STREQ(expr_result, ".")) {
+ MEM_freeN(expr_result);
+ expr_result = NULL;
+ }
+ }
+ else {
+ /* Note, this is an exceptional case, we could even remove it
+ * however there have been reports of tooltips failing, so keep it for now. */
+ expr_result = BLI_strdup("Internal error!");
+ is_error = true;
+ }
+
+ if (expr_result != NULL) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_MAIN,
+ .is_pad = true,
+ });
+ field->text = expr_result;
+
+ if (UNLIKELY(is_error)) {
+ field->format.color_id = UI_TIP_LC_ALERT;
+ }
+ }
+ }
+
+ /* Shortcut. */
+ if (is_label == false && ((but->block->flag & UI_BLOCK_SHOW_SHORTCUT_ALWAYS) == 0)) {
+ /* There are different kinds of shortcuts:
+ *
+ * - Direct access to the tool (as if the toolbar button is pressed).
+ * - The key is bound to a brush type (not the exact brush name).
+ * - The key is assigned to the operator it's self (bypassing the tool, executing the operator).
+ *
+ * Either way case it's useful to show the shortcut.
+ */
+ char *shortcut = NULL;
+
+ {
+ uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL};
+ UI_but_string_info_get(C, but, &op_keymap, NULL);
+ shortcut = op_keymap.strinfo;
+ }
+
+ if (shortcut == NULL) {
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
+ if (tool_attr != NULL) {
+ const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ const int i = RNA_enum_from_name(items, tool_name);
+ if (i != -1) {
+ wmOperatorType *ot = WM_operatortype_find("paint.brush_select", true);
+ PointerRNA op_props;
+ WM_operator_properties_create_ptr(&op_props, ot);
+ RNA_enum_set(&op_props, tool_attr, items[i].value);
+
+ /* Check for direct access to the tool. */
+ char shortcut_brush[128] = "";
+ if (WM_key_event_operator_string(
+ C, ot->idname, WM_OP_INVOKE_REGION_WIN, op_props.data, true,
+ shortcut_brush, ARRAY_SIZE(shortcut_brush)))
+ {
+ shortcut = BLI_strdup(shortcut_brush);
+ }
+ WM_operator_properties_free(&op_props);
+ }
+ }
+ }
+
+ if (shortcut == NULL) {
+ /* Check for direct access to the tool. */
+ char shortcut_toolbar[128] = "";
+ if (WM_key_event_operator_string(
+ C, "WM_OT_toolbar", WM_OP_INVOKE_REGION_WIN, NULL, true,
+ shortcut_toolbar, ARRAY_SIZE(shortcut_toolbar)))
+ {
+ /* Generate keymap in order to inspect it.
+ * Note, we could make a utility to avoid the keymap generation part of this. */
+ const char *expr_imports[] = {"bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", NULL};
+ const char *expr = (
+ "getattr("
+ "bl_keymap_utils.keymap_from_toolbar.generate("
+ "bpy.context, "
+ "bpy.context.space_data.type), "
+ "'as_pointer', lambda: 0)()");
+
+ intptr_t expr_result = 0;
+ if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
+ if (expr_result != 0) {
+ wmKeyMap *keymap = (wmKeyMap *)expr_result;
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (STREQ(kmi->idname, but->optype->idname)) {
+ char tool_name_test[MAX_NAME];
+ RNA_string_get(kmi->ptr, "name", tool_name_test);
+ if (STREQ(tool_name, tool_name_test)) {
+ char buf[128];
+ WM_keymap_item_to_string(kmi, false, buf, sizeof(buf));
+ shortcut = BLI_sprintfN("%s, %s", shortcut_toolbar, buf);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ }
+
+ if (shortcut != NULL) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_sprintfN(TIP_("Shortcut: %s"), shortcut);
+ MEM_freeN(shortcut);
+ }
+ }
+
+ /* Keymap */
+
+ /* This is too handy not to expose somehow, let's be sneaky for now. */
+ if ((is_label == false) && CTX_wm_window(C)->eventstate->shift) {
+ const char *expr_imports[] = {"bpy", "bl_ui", NULL};
+ char expr[256];
+ SNPRINTF(
+ expr,
+ "getattr("
+ "bl_ui.space_toolsystem_common.keymap_from_name("
+ "bpy.context, "
+ "bpy.context.space_data.type, "
+ "'%s'), "
+ "'as_pointer', lambda: 0)()",
+ tool_name);
+
+ intptr_t expr_result = 0;
+ if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
+ if (expr_result != 0) {
+ {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_NORMAL,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup("Tool Keymap:");
+ }
+ wmKeyMap *keymap = (wmKeyMap *)expr_result;
+ ui_tooltip_data_append_from_keymap(C, data, keymap);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+#endif /* WITH_PYTHON */
+
+ if (data->fields_len == 0) {
+ MEM_freeN(data);
+ return NULL;
+ }
+ else {
+ return data;
+ }
+}
+
static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
{
uiStringInfo but_tip = {BUT_GET_TIP, NULL};
@@ -463,7 +735,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
WM_operator_pystring_abbreviate(str, 32);
/* operator info */
- if ((U.flag & USER_TOOLTIPS_PYTHON) == 0) {
+ if (U.flag & USER_TOOLTIPS_PYTHON) {
uiTooltipField *field = text_field_add(
data, &(uiTooltipFormat){
.style = UI_TIP_STYLE_MONO,
@@ -501,7 +773,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
}
- if ((U.flag & USER_TOOLTIPS_PYTHON) == 0 && !but->optype && rna_struct.strinfo) {
+ if ((U.flag & USER_TOOLTIPS_PYTHON) && !but->optype && rna_struct.strinfo) {
{
uiTooltipField *field = text_field_add(
data, &(uiTooltipFormat){
@@ -565,9 +837,113 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
}
+static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz)
+{
+ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
+
+ /* TODO(campbell): a way for gizmos to have their own descriptions (low priority). */
+
+ /* Operator Actions */
+ {
+ bool use_drag = gz->drag_part != -1 && gz->highlight_part != gz->drag_part;
+
+ const struct {
+ int part;
+ const char *prefix;
+ } gzop_actions[] = {
+ {
+ .part = gz->highlight_part,
+ .prefix = use_drag ? TIP_("Click") : NULL,
+ }, {
+ .part = use_drag ? gz->drag_part : -1,
+ .prefix = use_drag ? TIP_("Drag") : NULL,
+ },
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(gzop_actions); i++) {
+ wmGizmoOpElem *gzop = (gzop_actions[i].part != -1) ? WM_gizmo_operator_get(gz, gzop_actions[i].part) : NULL;
+ if (gzop != NULL) {
+ /* Description */
+ const char *info = RNA_struct_ui_description(gzop->type->srna);
+ if (!(info && info[0])) {
+ info = RNA_struct_ui_name(gzop->type->srna);
+ }
+
+ if (info && info[0]) {
+ char *text = NULL;
+ if (gzop_actions[i].prefix != NULL) {
+ text = BLI_sprintfN("%s: %s", gzop_actions[i].prefix, info);
+ }
+ else {
+ text = BLI_strdup(info);
+ }
+
+ if (text != NULL) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_HEADER,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = text;
+ }
+ }
+
+ /* Shortcut */
+ {
+ IDProperty *prop = gzop->ptr.data;
+ char buf[128];
+ if (WM_key_event_operator_string(
+ C, gzop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true,
+ buf, ARRAY_SIZE(buf)))
+ {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_sprintfN(TIP_("Shortcut: %s"), buf);
+ }
+ }
+ }
+ }
+ }
+
+ /* Property Actions */
+ if (gz->type->target_property_defs_len) {
+ wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);
+ for (int i = 0; i < gz->type->target_property_defs_len; i++) {
+ /* TODO(campbell): function callback descriptions. */
+ wmGizmoProperty *gz_prop = &gz_prop_array[i];
+ if (gz_prop->prop != NULL) {
+ const char *info = RNA_property_ui_description(gz_prop->prop);
+ if (info && info[0]) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup(info);
+ }
+ }
+ }
+ }
+
+ if (data->fields_len == 0) {
+ MEM_freeN(data);
+ return NULL;
+ }
+ else {
+ return data;
+ }
+}
+
+
static ARegion *ui_tooltip_create_with_data(
bContext *C, uiTooltipData *data,
- const float init_position[2],
+ const float init_position[2], const rcti *init_rect_overlap,
const float aspect)
{
const float pad_px = UI_TIP_PADDING;
@@ -671,21 +1047,119 @@ static ARegion *ui_tooltip_create_with_data(
#undef TIP_BORDER_X
#undef TIP_BORDER_Y
+// #define USE_ALIGN_Y_CENTER
+
/* Clamp to window bounds. */
{
/* Ensure at least 5 px above screen bounds
* UI_UNIT_Y is just a guess to be above the menu item */
- const int pad = max_ff(1.0f, U.pixelsize) * 5;
- const rcti rect_clamp = {
- .xmin = pad,
- .xmax = winx - pad,
- .ymin = pad + (UI_UNIT_Y * 2),
- .ymax = winy - pad,
- };
- int offset_dummy[2];
- BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy);
+ if (init_rect_overlap != NULL) {
+ const int pad = max_ff(1.0f, U.pixelsize) * 5;
+ const rcti init_rect = {
+ .xmin = init_rect_overlap->xmin - pad,
+ .xmax = init_rect_overlap->xmax + pad,
+ .ymin = init_rect_overlap->ymin - pad,
+ .ymax = init_rect_overlap->ymax + pad,
+ };
+ const rcti rect_clamp = {
+ .xmin = 0,
+ .xmax = winx,
+ .ymin = 0,
+ .ymax = winy,
+ };
+ /* try right. */
+ const int size_x = BLI_rcti_size_x(&rect_i);
+ const int size_y = BLI_rcti_size_y(&rect_i);
+ const int cent_overlap_x = BLI_rcti_cent_x(&init_rect);
+#ifdef USE_ALIGN_Y_CENTER
+ const int cent_overlap_y = BLI_rcti_cent_y(&init_rect);
+#endif
+ struct {
+ rcti xpos;
+ rcti xneg;
+ rcti ypos;
+ rcti yneg;
+ } rect;
+
+ { /* xpos */
+ rcti r = rect_i;
+ r.xmin = init_rect.xmax;
+ r.xmax = r.xmin + size_x;
+#ifdef USE_ALIGN_Y_CENTER
+ r.ymin = cent_overlap_y - (size_y / 2);
+ r.ymax = r.ymin + size_y;
+#else
+ r.ymin = init_rect.ymax - BLI_rcti_size_y(&rect_i);
+ r.ymax = init_rect.ymax;
+ r.ymin -= UI_POPUP_MARGIN;
+ r.ymax -= UI_POPUP_MARGIN;
+#endif
+ rect.xpos = r;
+ }
+ { /* xneg */
+ rcti r = rect_i;
+ r.xmin = init_rect.xmin - size_x;
+ r.xmax = r.xmin + size_x;
+#ifdef USE_ALIGN_Y_CENTER
+ r.ymin = cent_overlap_y - (size_y / 2);
+ r.ymax = r.ymin + size_y;
+#else
+ r.ymin = init_rect.ymax - BLI_rcti_size_y(&rect_i);
+ r.ymax = init_rect.ymax;
+ r.ymin -= UI_POPUP_MARGIN;
+ r.ymax -= UI_POPUP_MARGIN;
+#endif
+ rect.xneg = r;
+ }
+ { /* ypos */
+ rcti r = rect_i;
+ r.xmin = cent_overlap_x - (size_x / 2);
+ r.xmax = r.xmin + size_x;
+ r.ymin = init_rect.ymax;
+ r.ymax = r.ymin + size_y;
+ rect.ypos = r;
+ }
+ { /* yneg */
+ rcti r = rect_i;
+ r.xmin = cent_overlap_x - (size_x / 2);
+ r.xmax = r.xmin + size_x;
+ r.ymin = init_rect.ymin - size_y;
+ r.ymax = r.ymin + size_y;
+ rect.yneg = r;
+ }
+
+ bool found = false;
+ for (int j = 0; j < 4; j++) {
+ const rcti *r = (&rect.xpos) + j;
+ if (BLI_rcti_inside_rcti(&rect_clamp, r)) {
+ rect_i = *r;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ /* Fallback, we could pick the best fallback, for now just use xpos. */
+ int offset_dummy[2];
+ rect_i = rect.xpos;
+ BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy);
+ }
+
+ }
+ else {
+ const int pad = max_ff(1.0f, U.pixelsize) * 5;
+ const rcti rect_clamp = {
+ .xmin = pad,
+ .xmax = winx - pad,
+ .ymin = pad + (UI_UNIT_Y * 2),
+ .ymax = winy - pad,
+ };
+ int offset_dummy[2];
+ BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy);
+ }
}
+#undef USE_ALIGN_Y_CENTER
+
/* add padding */
BLI_rcti_resize(&rect_i,
BLI_rcti_size_x(&rect_i) + pad_px,
@@ -693,7 +1167,11 @@ static ARegion *ui_tooltip_create_with_data(
/* widget rect, in region coords */
{
+ /* Compensate for margin offset, visually this corrects the position. */
const int margin = UI_POPUP_MARGIN;
+ if (init_rect_overlap != NULL) {
+ BLI_rcti_translate(&rect_i, margin, margin / 2);
+ }
data->bbox.xmin = margin;
data->bbox.xmax = BLI_rcti_size_x(&rect_i) - margin;
@@ -708,7 +1186,7 @@ static ARegion *ui_tooltip_create_with_data(
}
/* adds subwindow */
- ED_region_init(C, ar);
+ ED_region_init(ar);
/* notify change and redraw */
ED_region_tag_redraw(ar);
@@ -723,7 +1201,7 @@ static ARegion *ui_tooltip_create_with_data(
* \{ */
-ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but)
+ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
{
wmWindow *win = CTX_wm_window(C);
/* aspect values that shrink text are likely unreadable */
@@ -736,21 +1214,61 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
uiTooltipData *data = NULL;
if (data == NULL) {
+ data = ui_tooltip_data_from_tool(C, but, is_label);
+ }
+
+ if (data == NULL) {
data = ui_tooltip_data_from_button(C, but);
}
+
if (data == NULL) {
return NULL;
}
- init_position[0] = BLI_rctf_cent_x(&but->rect);
- init_position[1] = but->rect.ymin;
+ const bool is_no_overlap = UI_but_has_tooltip_label(but) || UI_but_is_tool(but);
+ rcti init_rect;
+ if (is_no_overlap) {
+ rctf overlap_rect_fl;
+ init_position[0] = BLI_rctf_cent_x(&but->rect);
+ init_position[1] = BLI_rctf_cent_y(&but->rect);
+ if (butregion) {
+ ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
+ ui_block_to_window_rctf(butregion, but->block, &overlap_rect_fl, &but->rect);
+ }
+ else {
+ overlap_rect_fl = but->rect;
+ }
+ BLI_rcti_rctf_copy_round(&init_rect, &overlap_rect_fl);
+ }
+ else {
+ init_position[0] = BLI_rctf_cent_x(&but->rect);
+ init_position[1] = but->rect.ymin - (UI_POPUP_MARGIN / 2);
+ if (butregion) {
+ ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
+ init_position[0] = win->eventstate->x;
+ }
+ }
+
+ ARegion *ar = ui_tooltip_create_with_data(C, data, init_position, is_no_overlap ? &init_rect : NULL, aspect);
- if (butregion) {
- ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
- init_position[0] = win->eventstate->x;
+ return ar;
+}
+
+ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
+{
+ wmWindow *win = CTX_wm_window(C);
+ const float aspect = 1.0f;
+ float init_position[2];
+
+ uiTooltipData *data = ui_tooltip_data_from_gizmo(C, gz);
+ if (data == NULL) {
+ return NULL;
}
- return ui_tooltip_create_with_data(C, data, init_position, aspect);
+ init_position[0] = win->eventstate->x;
+ init_position[1] = win->eventstate->y;
+
+ return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
}
void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar)
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 2c3d94214d1..0decc937e19 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -61,6 +61,9 @@ ARegion *ui_region_temp_add(bScreen *sc)
void ui_region_temp_remove(bContext *C, bScreen *sc, ARegion *ar)
{
wmWindow *win = CTX_wm_window(C);
+
+ BLI_assert(ar->regiontype == RGN_TYPE_TEMPORARY);
+ BLI_assert(BLI_findindex(&sc->regionbase, ar) != -1);
if (win)
wm_draw_region_clear(win, ar);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index c7ecc37b0bf..d4f6933693e 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -94,11 +94,11 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id
style->paneltitle.uifont_id = uifont_id;
style->paneltitle.points = 12;
style->paneltitle.kerning = 1;
- style->paneltitle.shadow = 1;
+ style->paneltitle.shadow = 3;
style->paneltitle.shadx = 0;
style->paneltitle.shady = -1;
- style->paneltitle.shadowalpha = 0.15f;
- style->paneltitle.shadowcolor = 1.0f;
+ style->paneltitle.shadowalpha = 0.5f;
+ style->paneltitle.shadowcolor = 0.0f;
style->grouplabel.uifont_id = uifont_id;
style->grouplabel.points = 12;
@@ -106,7 +106,8 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id
style->grouplabel.shadow = 3;
style->grouplabel.shadx = 0;
style->grouplabel.shady = -1;
- style->grouplabel.shadowalpha = 0.25f;
+ style->grouplabel.shadowalpha = 0.5f;
+ style->grouplabel.shadowcolor = 0.0f;
style->widgetlabel.uifont_id = uifont_id;
style->widgetlabel.points = 11;
@@ -114,13 +115,16 @@ static uiStyle *ui_style_new(ListBase *styles, const char *name, short uifont_id
style->widgetlabel.shadow = 3;
style->widgetlabel.shadx = 0;
style->widgetlabel.shady = -1;
- style->widgetlabel.shadowalpha = 0.15f;
- style->widgetlabel.shadowcolor = 1.0f;
+ style->widgetlabel.shadowalpha = 0.5f;
+ style->widgetlabel.shadowcolor = 0.0f;
style->widget.uifont_id = uifont_id;
style->widget.points = 11;
style->widget.kerning = 1;
- style->widget.shadowalpha = 0.25f;
+ style->widget.shadow = 1;
+ style->widget.shady = -1;
+ style->widget.shadowalpha = 0.5f;
+ style->widget.shadowcolor = 0.0f;
style->columnspace = 8;
style->templatespace = 5;
@@ -149,7 +153,7 @@ static uiFont *uifont_to_blfont(int id)
void UI_fontstyle_draw_ex(
- const uiFontStyle *fs, const rcti *rect, const char *str,
+ const uiFontStyle *fs, const rcti *rect, const char *str, const unsigned char col[4],
size_t len, float *r_xofs, float *r_yofs)
{
int xofs = 0, yofs;
@@ -179,7 +183,8 @@ void UI_fontstyle_draw_ex(
}
else {
/* draw from boundbox center */
- yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - BLF_ascender(fs->uifont_id)));
+ float height = BLF_ascender(fs->uifont_id) + BLF_descender(fs->uifont_id);
+ yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - height));
}
if (fs->align == UI_STYLE_TEXT_CENTER) {
@@ -196,6 +201,7 @@ void UI_fontstyle_draw_ex(
/* clip is very strict, so we give it some space */
BLF_clipping(fs->uifont_id, rect->xmin - 2, rect->ymin - 4, rect->xmax + 1, rect->ymax + 4);
BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f);
+ BLF_color4ubv(fs->uifont_id, col);
BLF_draw(fs->uifont_id, str, len);
@@ -205,17 +211,17 @@ void UI_fontstyle_draw_ex(
*r_yofs = yofs;
}
-void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str)
+void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str, const unsigned char col[4])
{
float xofs, yofs;
UI_fontstyle_draw_ex(
- fs, rect, str,
+ fs, rect, str, col,
BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs);
}
/* drawn same as above, but at 90 degree angle */
-void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const char *str)
+void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const char *str, const unsigned char col[4])
{
float height;
int xofs, yofs;
@@ -224,7 +230,7 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const ch
UI_fontstyle_set(fs);
- height = BLF_ascender(fs->uifont_id);
+ height = BLF_ascender(fs->uifont_id) + BLF_descender(fs->uifont_id);
/* becomes x-offset when rotated */
xofs = ceil(0.5f * (BLI_rcti_size_y(rect) - height));
@@ -249,6 +255,7 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const ch
BLF_enable(fs->uifont_id, BLF_ROTATION);
BLF_rotation(fs->uifont_id, angle);
+ BLF_color4ubv(fs->uifont_id, col);
if (fs->shadow) {
BLF_enable(fs->uifont_id, BLF_SHADOW);
@@ -275,13 +282,14 @@ void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const ch
*
* For drawing on-screen labels.
*/
-void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str)
+void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str, const unsigned char col[4])
{
if (fs->kerning == 1)
BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
UI_fontstyle_set(fs);
BLF_position(fs->uifont_id, x, y, 0.0f);
+ BLF_color4ubv(fs->uifont_id, col);
BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
if (fs->kerning == 1)
@@ -293,7 +301,7 @@ void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const cha
*/
void UI_fontstyle_draw_simple_backdrop(
const uiFontStyle *fs, float x, float y, const char *str,
- const unsigned char fg[4], const unsigned char bg[4])
+ const float col_fg[4], const float col_bg[4])
{
if (fs->kerning == 1)
BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
@@ -307,21 +315,20 @@ void UI_fontstyle_draw_simple_backdrop(
const float margin = height / 4.0f;
/* backdrop */
- glColor4ubv(bg);
+ float color[4] = { col_bg[0], col_bg[1], col_bg[2], 0.5f };
- UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA);
- UI_draw_roundbox(
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_aa(
+ true,
x - margin,
(y + decent) - margin,
x + width + margin,
(y + decent) + height + margin,
- margin);
-
- glColor4ubv(fg);
+ margin, color);
}
-
BLF_position(fs->uifont_id, x, y, 0.0f);
+ BLF_color4fv(fs->uifont_id, col_fg);
BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
if (fs->kerning == 1)
@@ -523,10 +530,11 @@ void uiStyleInit(void)
/* Set default flags based on UI preferences (not render fonts) */
{
- int flag_disable = BLF_MONOCHROME |
- BLF_HINTING_NONE |
- BLF_HINTING_SLIGHT |
- BLF_HINTING_FULL;
+ int flag_disable = (
+ BLF_MONOCHROME |
+ BLF_HINTING_NONE |
+ BLF_HINTING_SLIGHT |
+ BLF_HINTING_FULL);
int flag_enable = 0;
if (U.text_render & USER_TEXT_HINTING_NONE) {
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index f9fcf9520be..5b9f9b1faf3 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -39,6 +39,8 @@
#include "DNA_object_force_types.h"
#include "DNA_brush_types.h"
#include "DNA_texture_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
@@ -48,6 +50,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_fnmatch.h"
+#include "BLI_path_util.h"
#include "BLI_timecode.h"
#include "BLF_api.h"
@@ -56,21 +59,26 @@
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_packedFile.h"
-#include "BKE_particle.h"
#include "BKE_paint.h"
+#include "BKE_particle.h"
#include "BKE_report.h"
-#include "BKE_sca.h"
#include "BKE_screen.h"
+#include "BKE_shader_fx.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_screen.h"
#include "ED_object.h"
@@ -82,6 +90,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "BLO_readfile.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "interface_intern.h"
@@ -91,11 +101,137 @@
// #define USE_OP_RESET_BUT // we may want to make this optional, disable for now.
+/* defines for templateID/TemplateSearch */
+#define TEMPLATE_SEARCH_TEXTBUT_WIDTH (UI_UNIT_X * 6)
+#define TEMPLATE_SEARCH_TEXTBUT_HEIGHT UI_UNIT_Y
+
void UI_template_fix_linking(void)
{
}
+/**
+ * Add a block button for the search menu for templateID and templateSearch.
+ */
+static void template_add_button_search_menu(
+ const bContext *C, uiLayout *layout, uiBlock *block,
+ PointerRNA *ptr, PropertyRNA *prop,
+ uiBlockCreateFunc block_func, void *block_argN, const char * const tip,
+ const bool use_previews, const bool editable, const bool live_icon)
+{
+ PointerRNA active_ptr = RNA_property_pointer_get(ptr, prop);
+ ID *id = (active_ptr.data && RNA_struct_is_ID(active_ptr.type)) ? active_ptr.data : NULL;
+ const ID *idfrom = ptr->id.data;
+ const StructRNA *type = active_ptr.type ? active_ptr.type : RNA_property_pointer_type(ptr, prop);
+ uiBut *but;
+
+ if (use_previews) {
+ ARegion *region = CTX_wm_region(C);
+ ScrArea *area = CTX_wm_area(C);
+ /* XXX ugly top-bar exception */
+ const bool use_big_size = (region->regiontype != RGN_TYPE_HEADER) && (area->spacetype != SPACE_TOPBAR); /* silly check, could be more generic */
+ /* Ugly exception for screens here, drawing their preview in icon size looks ugly/useless */
+ const bool use_preview_icon = use_big_size || (id && (GS(id->name) != ID_SCR));
+ const short width = UI_UNIT_X * (use_big_size ? 6 : 1.6f);
+ const short height = UI_UNIT_Y * (use_big_size ? 6 : 1);
+
+ but = uiDefBlockButN(block, block_func, block_argN, "", 0, 0, width, height, tip);
+ if (use_preview_icon) {
+ int icon = id ? ui_id_icon_get(C, id, use_big_size) : RNA_struct_ui_icon(type);
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ }
+ else {
+ ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
+ UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
+ }
+
+ if ((idfrom && idfrom->lib) || !editable)
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ if (use_big_size) {
+ uiLayoutRow(layout, true);
+ }
+ }
+ else {
+ but = uiDefBlockButN(block, block_func, block_argN, "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y, tip);
+
+ if (live_icon) {
+ int icon = id ? ui_id_icon_get(C, id, false) : RNA_struct_ui_icon(type);
+ ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ }
+ else {
+ ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
+ }
+ if (id) {
+ /* default dragging of icon for id browse buttons */
+ UI_but_drag_set_id(but, id);
+ }
+ UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
+
+ if ((idfrom && idfrom->lib) || !editable)
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+}
+
+static uiBlock *template_common_search_menu(
+ const bContext *C, ARegion *region,
+ uiButSearchFunc search_func, void *search_arg,
+ uiButHandleFunc handle_func, void *active_item,
+ const int preview_rows, const int preview_cols,
+ float scale)
+{
+ static char search[256];
+ wmWindow *win = CTX_wm_window(C);
+ uiBlock *block;
+ uiBut *but;
+
+ /* clear initial search string, then all items show */
+ search[0] = 0;
+
+ block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+
+ /* preview thumbnails */
+ if (preview_rows > 0 && preview_cols > 0) {
+ const int w = 4 * U.widget_unit * preview_cols * scale;
+ const int h = 5 * U.widget_unit * preview_rows * scale;
+
+ /* fake button, it holds space for search items */
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL);
+
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y,
+ preview_rows, preview_cols, "");
+ }
+ /* list view */
+ else {
+ const int searchbox_width = UI_searchbox_size_x();
+ const int searchbox_height = UI_searchbox_size_y();
+
+ /* fake button, it holds space for search items */
+ uiDefBut(
+ block, UI_BTYPE_LABEL, 0, "", 10, 15, searchbox_width, searchbox_height,
+ NULL, 0, 0, 0, 0, NULL);
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0,
+ searchbox_width, UI_UNIT_Y - 1, 0, 0, "");
+ }
+ UI_but_func_search_set(
+ but, ui_searchbox_create_generic, search_func,
+ search_arg, handle_func, active_item);
+
+
+ UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
+ UI_block_direction_set(block, UI_DIR_DOWN);
+
+ /* give search-field focus */
+ UI_but_focus_on_enter_event(win, but);
+ /* this type of search menu requires undo */
+ but->flag |= UI_BUT_UNDO;
+
+ return block;
+}
+
/********************** Header Template *************************/
void uiTemplateHeader(uiLayout *layout, bContext *C)
@@ -117,10 +253,11 @@ typedef struct TemplateID {
short filter;
int prv_rows, prv_cols;
bool preview;
+ float scale;
} TemplateID;
/* Search browse menu, assign */
-static void id_search_call_cb(bContext *C, void *arg_template, void *item)
+static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item)
{
TemplateID *template_ui = (TemplateID *)arg_template;
@@ -160,11 +297,11 @@ static bool id_search_add(
}
if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) {
- /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
- * followed by ID_NAME-2 characters from id->name
+ /* +1 is needed because BKE_id_ui_prefix uses 3 letter prefix
+ * followed by ID_NAME-2 characters from id->name.
*/
- char name_ui[MAX_ID_NAME + 1];
- BKE_id_ui_prefix(name_ui, id);
+ char name_ui[MAX_ID_FULL_NAME];
+ BKE_id_full_name_ui_prefix_get(name_ui, id);
int iconid = ui_id_icon_get(C, id, template_ui->preview);
@@ -231,30 +368,25 @@ static void id_search_cb_objects_from_scene(const bContext *C, void *arg_templat
}
BKE_main_id_flag_listbase(lb, LIB_TAG_DOIT, false);
- for (Base *base = scene->base.first; base; base = base->next) {
- base->object->id.tag |= LIB_TAG_DOIT;
+
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter)
+ {
+ ob_iter->id.tag |= LIB_TAG_DOIT;
}
+ FOREACH_SCENE_OBJECT_END;
id_search_cb_tagged(C, arg_template, str, items);
}
/* ID Search browse menu, open */
static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
{
- static char search[256];
static TemplateID template_ui;
- PointerRNA idptr;
- wmWindow *win = CTX_wm_window(C);
- uiBlock *block;
- uiBut *but;
+ PointerRNA active_item_ptr;
void (*id_search_cb_p)(const bContext *, void *, const char *, uiSearchItems *) = id_search_cb;
- /* clear initial search string, then all items show */
- search[0] = 0;
/* arg_litem is malloced, can be freed by parent button */
template_ui = *((TemplateID *)arg_litem);
-
- /* get active id for showing first item */
- idptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop);
+ active_item_ptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop);
if (template_ui.filter) {
/* Currently only used for objects. */
@@ -265,48 +397,9 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
}
}
- block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
- UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
- UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
-
- /* preview thumbnails */
- if (template_ui.prv_rows > 0 && template_ui.prv_cols > 0) {
- int w = 4 * U.widget_unit * template_ui.prv_cols;
- int h = 5 * U.widget_unit * template_ui.prv_rows;
-
- /* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL);
-
- but = uiDefSearchBut(
- block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y,
- template_ui.prv_rows, template_ui.prv_cols, "");
- UI_but_func_search_set(
- but, ui_searchbox_create_generic, id_search_cb_p,
- &template_ui, id_search_call_cb, idptr.data);
- }
- /* list view */
- else {
- const int searchbox_width = UI_searchbox_size_x();
- const int searchbox_height = UI_searchbox_size_y();
-
- /* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, searchbox_width, searchbox_height, NULL, 0, 0, 0, 0, NULL);
- but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, searchbox_width, UI_UNIT_Y - 1, 0, 0, "");
- UI_but_func_search_set(
- but, ui_searchbox_create_generic, id_search_cb_p,
- &template_ui, id_search_call_cb, idptr.data);
- }
-
-
- UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
- UI_block_direction_set(block, UI_DIR_DOWN);
-
- /* give search-field focus */
- UI_but_focus_on_enter_event(win, but);
- /* this type of search menu requires undo */
- but->flag |= UI_BUT_UNDO;
-
- return block;
+ return template_common_search_menu(
+ C, ar, id_search_cb_p, &template_ui, template_ID_set_property_cb, active_item_ptr.data,
+ template_ui.prv_rows, template_ui.prv_cols, template_ui.scale);
}
/************************ ID Template ***************************/
@@ -314,36 +407,22 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* for new/open operators */
void UI_context_active_but_prop_get_templateID(
- bContext *C,
- PointerRNA *r_ptr, PropertyRNA **r_prop)
+ bContext *C,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
{
TemplateID *template_ui;
- ARegion *ar = CTX_wm_region(C);
- uiBlock *block;
- uiBut *but;
+ uiBut *but = UI_context_active_but_get(C);
memset(r_ptr, 0, sizeof(*r_ptr));
*r_prop = NULL;
- if (!ar)
- return;
-
- for (block = ar->uiblocks.first; block; block = block->next) {
- for (but = block->buttons.first; but; but = but->next) {
- /* find the button before the active one */
- if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
- if (but->func_argN) {
- template_ui = but->func_argN;
- *r_ptr = template_ui->ptr;
- *r_prop = template_ui->prop;
- return;
- }
- }
- }
+ if (but && but->func_argN) {
+ template_ui = but->func_argN;
+ *r_ptr = template_ui->ptr;
+ *r_prop = template_ui->prop;
}
}
-
static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
{
TemplateID *template_ui = (TemplateID *)arg_litem;
@@ -384,14 +463,34 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
case UI_ID_LOCAL:
if (id) {
Main *bmain = CTX_data_main(C);
- if (id_make_local(bmain, id, false, false)) {
- BKE_main_id_clear_newpoins(bmain);
+ if (BKE_override_static_is_enabled() && CTX_wm_window(C)->eventstate->shift) {
+ ID *override_id = BKE_override_static_create_from_id(bmain, id);
+ if (override_id != NULL) {
+ BKE_main_id_clear_newpoins(bmain);
- /* reassign to get get proper updates/notifiers */
- idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
- RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
- RNA_property_update(C, &template_ui->ptr, template_ui->prop);
+ /* Assign new pointer, takes care of updates/notifiers */
+ RNA_id_pointer_create(override_id, &idptr);
+ }
}
+ else {
+ if (id_make_local(bmain, id, false, false)) {
+ BKE_main_id_clear_newpoins(bmain);
+
+ /* reassign to get get proper updates/notifiers */
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
+ }
+ }
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
+ }
+ break;
+ case UI_ID_OVERRIDE:
+ if (id && id->override_static) {
+ BKE_override_static_free(&id->override_static);
+ /* reassign to get get proper updates/notifiers */
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
}
break;
case UI_ID_ALONE:
@@ -405,14 +504,15 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ED_object_single_user(bmain, scene, (struct Object *)id);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
else {
if (id) {
Main *bmain = CTX_data_main(C);
id_single_user(C, id, &template_ui->ptr, template_ui->prop);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
}
}
@@ -424,7 +524,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
}
-static const char *template_id_browse_tip(StructRNA *type)
+static const char *template_id_browse_tip(const StructRNA *type)
{
if (type) {
switch (RNA_type_to_ID_code(type)) {
@@ -438,7 +538,7 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_IM: return N_("Browse Image to be linked");
case ID_LS: return N_("Browse Line Style Data to be linked");
case ID_LT: return N_("Browse Lattice Data to be linked");
- case ID_LA: return N_("Browse Lamp Data to be linked");
+ case ID_LA: return N_("Browse Light Data to be linked");
case ID_CA: return N_("Browse Camera Data to be linked");
case ID_WO: return N_("Browse World Settings to be linked");
case ID_SCR: return N_("Choose Screen layout");
@@ -456,6 +556,8 @@ static const char *template_id_browse_tip(StructRNA *type)
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");
+ case ID_WS: return N_("Browse Workspace to be linked");
+ case ID_LP: return N_("Browse LightProbe to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -475,9 +577,79 @@ static const char *template_id_context(StructRNA *type)
}
#endif
+static uiBut *template_id_def_new_but(
+ uiBlock *block, const ID *id, const TemplateID *template_ui, StructRNA *type,
+ const char * const newop, const bool editable, const bool id_open, const bool use_tab_but,
+ int but_height)
+{
+ ID *idfrom = template_ui->ptr.id.data;
+ uiBut *but;
+ const int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
+ const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT;
+
+ /* i18n markup, does nothing! */
+ BLT_I18N_MSGID_MULTI_CTXT(
+ "New",
+ BLT_I18NCONTEXT_DEFAULT,
+ BLT_I18NCONTEXT_ID_SCENE,
+ BLT_I18NCONTEXT_ID_OBJECT,
+ BLT_I18NCONTEXT_ID_MESH,
+ BLT_I18NCONTEXT_ID_CURVE,
+ BLT_I18NCONTEXT_ID_METABALL,
+ BLT_I18NCONTEXT_ID_MATERIAL,
+ BLT_I18NCONTEXT_ID_TEXTURE,
+ BLT_I18NCONTEXT_ID_IMAGE,
+ BLT_I18NCONTEXT_ID_LATTICE,
+ BLT_I18NCONTEXT_ID_LAMP,
+ BLT_I18NCONTEXT_ID_CAMERA,
+ BLT_I18NCONTEXT_ID_WORLD,
+ BLT_I18NCONTEXT_ID_SCREEN,
+ BLT_I18NCONTEXT_ID_TEXT,
+ );
+ BLT_I18N_MSGID_MULTI_CTXT(
+ "New",
+ BLT_I18NCONTEXT_ID_SPEAKER,
+ BLT_I18NCONTEXT_ID_SOUND,
+ BLT_I18NCONTEXT_ID_ARMATURE,
+ BLT_I18NCONTEXT_ID_ACTION,
+ BLT_I18NCONTEXT_ID_NODETREE,
+ BLT_I18NCONTEXT_ID_BRUSH,
+ BLT_I18NCONTEXT_ID_PARTICLESETTINGS,
+ BLT_I18NCONTEXT_ID_GPENCIL,
+ BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE,
+ BLT_I18NCONTEXT_ID_WORKSPACE,
+ BLT_I18NCONTEXT_ID_LIGHTPROBE,
+ );
+
+ if (newop) {
+ but = uiDefIconTextButO(
+ block, but_type, newop, WM_OP_INVOKE_DEFAULT, (id && !use_tab_but) ? ICON_DUPLICATE : ICON_ADD,
+ (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, but_height, NULL);
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW));
+ }
+ else {
+ but = uiDefIconTextBut(
+ block, but_type, 0, (id && !use_tab_but) ? ICON_DUPLICATE : ICON_ADD,
+ (id) ? "" : CTX_IFACE_(template_id_context(type), "New"),
+ 0, 0, w, but_height, NULL, 0, 0, 0, 0, NULL);
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW));
+ }
+
+ if ((idfrom && idfrom->lib) || !editable) {
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+
+#ifndef WITH_INTERNATIONAL
+ UNUSED_VARS(type);
+#endif
+
+ return but;
+}
+
static void template_ID(
bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, int flag,
- const char *newop, const char *openop, const char *unlinkop)
+ const char *newop, const char *openop, const char *unlinkop,
+ const bool live_icon, const bool hide_buttons)
{
uiBut *but;
uiBlock *block;
@@ -485,6 +657,7 @@ static void template_ID(
// ListBase *lb; // UNUSED
ID *id, *idfrom;
const bool editable = RNA_property_editable(&template_ui->ptr, template_ui->prop);
+ const bool use_previews = template_ui->preview = (flag & UI_ID_PREVIEWS) != 0;
idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
id = idptr.data;
@@ -497,32 +670,11 @@ static void template_ID(
if (idptr.type)
type = idptr.type;
- if (flag & UI_ID_PREVIEWS) {
- template_ui->preview = true;
-
- but = uiDefBlockButN(
- block, id_search_menu, MEM_dupallocN(template_ui), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6,
- TIP_(template_id_browse_tip(type)));
- ui_def_but_icon(
- but, id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type),
- UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
-
- if ((idfrom && idfrom->lib) || !editable)
- UI_but_flag_enable(but, UI_BUT_DISABLED);
-
- uiLayoutRow(layout, true);
- }
- else if (flag & UI_ID_BROWSE) {
- but = uiDefBlockButN(
- block, id_search_menu, MEM_dupallocN(template_ui), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y,
- TIP_(template_id_browse_tip(type)));
- ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON);
- /* default dragging of icon for id browse buttons */
- UI_but_drag_set_id(but, id);
- UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
-
- if ((idfrom && idfrom->lib) || !editable)
- UI_but_flag_enable(but, UI_BUT_DISABLED);
+ if (flag & UI_ID_BROWSE) {
+ template_add_button_search_menu(
+ C, layout, block, &template_ui->ptr, template_ui->prop,
+ id_search_menu, MEM_dupallocN(template_ui), TIP_(template_id_browse_tip(type)),
+ use_previews, editable, live_icon);
}
/* text button with name */
@@ -533,7 +685,7 @@ static void template_ID(
//text_idbutton(id, name);
name[0] = '\0';
but = uiDefButR(
- block, UI_BTYPE_TEXT, 0, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y,
+ block, UI_BTYPE_TEXT, 0, name, 0, 0, TEMPLATE_SEARCH_TEXTBUT_WIDTH, TEMPLATE_SEARCH_TEXTBUT_HEIGHT,
&idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type));
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_RENAME));
if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
@@ -546,21 +698,35 @@ static void template_ID(
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
+ const bool disabled = (
+ !id_make_local(CTX_data_main(C), id, true /* test */, false) ||
+ (idfrom && idfrom->lib));
but = uiDefIconBut(
block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Direct linked library data-block, click to make local"));
- if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib))
+ NULL, 0, 0, 0, 0,
+ TIP_("Direct linked library data-block, click to make local, "
+ "Shift + Click to create a static override"));
+ if (disabled) {
UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+ else {
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_LOCAL));
+ }
}
-
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_LOCAL));
+ }
+ else if (ID_IS_STATIC_OVERRIDE(id)) {
+ but = uiDefIconBut(
+ block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_OVERRIDE, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0, 0, 0, 0,
+ TIP_("Static override of linked library data-block, click to make fully local"));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OVERRIDE));
}
- if (id->us > 1) {
+ if ((ID_REAL_USERS(id) > 1) && (hide_buttons == false)) {
char numstr[32];
short numstr_len;
- numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", id->us);
+ numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", ID_REAL_USERS(id));
but = uiDefBut(
block, UI_BTYPE_BUT, 0, numstr, 0, 0,
@@ -580,63 +746,21 @@ static void template_ID(
}
}
- if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
-
- if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
- uiDefButR(block, UI_BTYPE_TOGGLE, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
+ if (user_alert) {
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
}
- }
- if (flag & UI_ID_ADD_NEW) {
- int w = id ? UI_UNIT_X : (flag & UI_ID_OPEN) ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
-
- /* i18n markup, does nothing! */
- BLT_I18N_MSGID_MULTI_CTXT(
- "New",
- BLT_I18NCONTEXT_DEFAULT,
- BLT_I18NCONTEXT_ID_SCENE,
- BLT_I18NCONTEXT_ID_OBJECT,
- BLT_I18NCONTEXT_ID_MESH,
- BLT_I18NCONTEXT_ID_CURVE,
- BLT_I18NCONTEXT_ID_METABALL,
- BLT_I18NCONTEXT_ID_MATERIAL,
- BLT_I18NCONTEXT_ID_TEXTURE,
- BLT_I18NCONTEXT_ID_IMAGE,
- BLT_I18NCONTEXT_ID_LATTICE,
- BLT_I18NCONTEXT_ID_LAMP,
- BLT_I18NCONTEXT_ID_CAMERA,
- BLT_I18NCONTEXT_ID_WORLD,
- BLT_I18NCONTEXT_ID_SCREEN,
- BLT_I18NCONTEXT_ID_TEXT,
- );
- BLT_I18N_MSGID_MULTI_CTXT(
- "New",
- BLT_I18NCONTEXT_ID_SPEAKER,
- BLT_I18NCONTEXT_ID_SOUND,
- BLT_I18NCONTEXT_ID_ARMATURE,
- BLT_I18NCONTEXT_ID_ACTION,
- BLT_I18NCONTEXT_ID_NODETREE,
- BLT_I18NCONTEXT_ID_BRUSH,
- BLT_I18NCONTEXT_ID_PARTICLESETTINGS,
- BLT_I18NCONTEXT_ID_GPENCIL,
- BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE,
- );
-
- if (newop) {
- but = uiDefIconTextButO(
- block, UI_BTYPE_BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN,
- (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, UI_UNIT_Y, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW));
- }
- else {
- but = uiDefIconTextBut(
- block, UI_BTYPE_BUT, 0, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"),
- 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW));
+ if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS)) &&
+ (hide_buttons == false))
+ {
+ uiDefIconButR(
+ block, UI_BTYPE_ICON_TOGGLE, 0, ICON_FAKE_USER_OFF, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
}
+ }
- if ((idfrom && idfrom->lib) || !editable)
- UI_but_flag_enable(but, UI_BUT_DISABLED);
+ if ((flag & UI_ID_ADD_NEW) && (hide_buttons == false)) {
+ template_id_def_new_but(block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false, UI_UNIT_X);
}
/* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack.
@@ -656,13 +780,13 @@ static void template_ID(
if (openop) {
but = uiDefIconTextButO(
- block, UI_BTYPE_BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id) ? "" : IFACE_("Open"),
+ block, UI_BTYPE_BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILEBROWSER, (id) ? "" : IFACE_("Open"),
0, 0, w, UI_UNIT_Y, NULL);
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OPEN));
}
else {
but = uiDefIconTextBut(
- block, UI_BTYPE_BUT, 0, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y,
+ block, UI_BTYPE_BUT, 0, ICON_FILEBROWSER, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y,
NULL, 0, 0, 0, 0, NULL);
UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OPEN));
}
@@ -673,7 +797,7 @@ static void template_ID(
/* delete button */
/* don't use RNA_property_is_unlink here */
- if (id && (flag & UI_ID_DELETE)) {
+ if (id && (flag & UI_ID_DELETE) && (hide_buttons == false)) {
/* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */
but = NULL;
@@ -709,9 +833,74 @@ static void template_ID(
UI_block_align_end(block);
}
+
+ID *UI_context_active_but_get_tab_ID(bContext *C)
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but && but->type == UI_BTYPE_TAB) {
+ return but->custom_data;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static void template_ID_tabs(
+ bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag,
+ const char *newop, const char *menu)
+{
+ const ARegion *region = CTX_wm_region(C);
+ const PointerRNA active_ptr = RNA_property_pointer_get(&template->ptr, template->prop);
+ MenuType *mt = WM_menutype_find(menu, false);
+
+ const int but_align = ui_but_align_opposite_to_area_align_get(region);
+ const int but_height = UI_UNIT_Y * 1.1;
+
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiStyle *style = UI_style_get_dpi();
+
+ ListBase ordered;
+ BKE_id_ordered_list(&ordered, template->idlb);
+
+ for (LinkData *link = ordered.first; link; link = link->next) {
+ ID *id = link->data;
+ const int name_width = UI_fontstyle_string_width(&style->widgetlabel, id->name + 2);
+ const int but_width = name_width + UI_UNIT_X;
+
+ uiButTab *tab = (uiButTab *)uiDefButR_prop(
+ block, UI_BTYPE_TAB, 0, id->name + 2, 0, 0, but_width, but_height,
+ &template->ptr, template->prop, 0, 0.0f,
+ sizeof(id->name) - 2, 0.0f, 0.0f, "");
+ UI_but_funcN_set(&tab->but, template_ID_set_property_cb, MEM_dupallocN(template), id);
+ tab->but.custom_data = (void *)id;
+ tab->but.dragpoin = id;
+ tab->menu = mt;
+
+ UI_but_drawflag_enable(&tab->but, but_align);
+ }
+
+ BLI_freelistN(&ordered);
+
+ if (flag & UI_ID_ADD_NEW) {
+ const bool editable = RNA_property_editable(&template->ptr, template->prop);
+ uiBut *but;
+
+ if (active_ptr.type) {
+ type = active_ptr.type;
+ }
+
+ but = template_id_def_new_but(block, active_ptr.data, template, type, newop, editable, flag & UI_ID_OPEN, true, but_height);
+ UI_but_drawflag_enable(but, but_align);
+ }
+}
+
static void ui_template_id(
- uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols, int filter)
+ uiLayout *layout, bContext *C,
+ PointerRNA *ptr, const char *propname,
+ const char *newop, const char *openop, const char *unlinkop,
+ int flag, int prv_rows, int prv_cols, int filter, bool use_tabs,
+ float scale, const bool live_icon, const bool hide_buttons)
{
TemplateID *template_ui;
PropertyRNA *prop;
@@ -730,6 +919,7 @@ static void ui_template_id(
template_ui->prop = prop;
template_ui->prv_rows = prv_rows;
template_ui->prv_cols = prv_cols;
+ template_ui->scale = scale;
if ((flag & UI_ID_PIN) == 0) {
template_ui->filter = filter;
@@ -752,8 +942,16 @@ static void ui_template_id(
* - template_ID makes a copy of the template data and assigns it to the relevant buttons
*/
if (template_ui->idlb) {
- uiLayoutRow(layout, true);
- template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop);
+ if (use_tabs) {
+ uiLayoutRow(layout, true);
+ template_ID_tabs(C, layout, template_ui, type, flag, newop, unlinkop);
+ }
+ else {
+ uiLayoutRow(layout, true);
+ template_ID(
+ C, layout, template_ui, type, flag, newop, openop,
+ unlinkop, live_icon, hide_buttons);
+ }
}
MEM_freeN(template_ui);
@@ -761,27 +959,64 @@ static void ui_template_id(
void uiTemplateID(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int filter)
+ const char *openop, const char *unlinkop,
+ int filter, const bool live_icon)
{
ui_template_id(
- layout, C, ptr, propname, newop, openop, unlinkop,
- UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, 0, 0, filter);
+ layout, C, ptr, propname,
+ newop, openop, unlinkop,
+ UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
+ 0, 0, filter, false, 1.0f, live_icon, false);
}
void uiTemplateIDBrowse(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
const char *openop, const char *unlinkop, int filter)
{
- ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME, 0, 0, filter);
+ ui_template_id(
+ layout, C, ptr, propname,
+ newop, openop, unlinkop,
+ UI_ID_BROWSE | UI_ID_RENAME,
+ 0, 0, filter, false, 1.0f, false, false);
}
void uiTemplateIDPreview(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int rows, int cols, int filter)
+ const char *openop, const char *unlinkop, int rows, int cols, int filter,
+ const bool hide_buttons)
+{
+ ui_template_id(
+ layout, C, ptr, propname,
+ newop, openop, unlinkop,
+ UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS,
+ rows, cols, filter, false, 1.0f, false, hide_buttons);
+}
+
+void uiTemplateGpencilColorPreview(
+ uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname,
+ int rows, int cols, float scale, int filter)
{
ui_template_id(
- layout, C, ptr, propname, newop, openop, unlinkop,
- UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, rows, cols, filter);
+ layout, C, ptr, propname,
+ NULL, NULL, NULL,
+ UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE,
+ rows, cols, filter, false, scale < 0.5f ? 0.5f : scale, false, false);
+}
+
+/**
+ * Version of #uiTemplateID using tabs.
+ */
+void uiTemplateIDTabs(
+ uiLayout *layout, bContext *C,
+ PointerRNA *ptr, const char *propname,
+ const char *newop, const char *unlinkop,
+ int filter)
+{
+ ui_template_id(
+ layout, C, ptr, propname,
+ newop, NULL, unlinkop,
+ UI_ID_BROWSE | UI_ID_RENAME,
+ 0, 0, filter, true, 1.0f, false, false);
}
/************************ ID Chooser Template ***************************/
@@ -843,6 +1078,209 @@ void uiTemplateAnyID(
uiItemFullR(sub, ptr, propID, 0, 0, 0, "", ICON_NONE);
}
+/********************* Search Template ********************/
+
+typedef struct TemplateSearch {
+ uiRNACollectionSearch search_data;
+
+ bool use_previews;
+ int preview_rows, preview_cols;
+} TemplateSearch;
+
+static void template_search_handle_cb(bContext *C, void *arg_template, void *item)
+{
+ TemplateSearch *template_search = arg_template;
+ uiRNACollectionSearch *coll_search = &template_search->search_data;
+ StructRNA *type = RNA_property_pointer_type(&coll_search->target_ptr, coll_search->target_prop);
+ PointerRNA item_ptr;
+
+ RNA_pointer_create(NULL, type, item, &item_ptr);
+ RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr);
+ RNA_property_update(C, &coll_search->target_ptr, coll_search->target_prop);
+}
+
+static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_template)
+{
+ static TemplateSearch template_search;
+ PointerRNA active_ptr;
+
+ /* arg_template is malloced, can be freed by parent button */
+ template_search = *((TemplateSearch *)arg_template);
+ active_ptr = RNA_property_pointer_get(
+ &template_search.search_data.target_ptr,
+ template_search.search_data.target_prop);
+
+ return template_common_search_menu(
+ C, region, ui_rna_collection_search_cb, &template_search,
+ template_search_handle_cb, active_ptr.data,
+ template_search.preview_rows, template_search.preview_cols, 1.0f);
+}
+
+static void template_search_add_button_searchmenu(
+ const bContext *C, uiLayout *layout, uiBlock *block,
+ TemplateSearch *template_search, const bool editable, const bool live_icon)
+{
+ const char *ui_description = RNA_property_ui_description(template_search->search_data.target_prop);
+
+ template_add_button_search_menu(
+ C, layout, block,
+ &template_search->search_data.target_ptr, template_search->search_data.target_prop,
+ template_search_menu, MEM_dupallocN(template_search), ui_description,
+ template_search->use_previews, editable, live_icon);
+}
+
+static void template_search_add_button_name(
+ uiBlock *block, PointerRNA *active_ptr, const StructRNA *type)
+{
+ uiDefAutoButR(
+ block, active_ptr, RNA_struct_name_property(type), 0, "", ICON_NONE,
+ 0, 0, TEMPLATE_SEARCH_TEXTBUT_WIDTH, TEMPLATE_SEARCH_TEXTBUT_HEIGHT);
+}
+
+static void template_search_add_button_operator(
+ uiBlock *block, const char * const operator_name,
+ const int opcontext, const int icon, const bool editable)
+{
+ if (!operator_name) {
+ return;
+ }
+
+ uiBut *but = uiDefIconButO(
+ block, UI_BTYPE_BUT, operator_name, opcontext, icon,
+ 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+
+ if (!editable) {
+ UI_but_drawflag_enable(but, UI_BUT_DISABLED);
+ }
+}
+
+static void template_search_buttons(
+ const bContext *C, uiLayout *layout, TemplateSearch *template_search,
+ const char *newop, const char *unlinkop)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiRNACollectionSearch *search_data = &template_search->search_data;
+ StructRNA *type = RNA_property_pointer_type(&search_data->target_ptr, search_data->target_prop);
+ const bool editable = RNA_property_editable(&search_data->target_ptr, search_data->target_prop);
+ PointerRNA active_ptr = RNA_property_pointer_get(&search_data->target_ptr, search_data->target_prop);
+
+ if (active_ptr.type) {
+ /* can only get correct type when there is an active item */
+ type = active_ptr.type;
+ }
+
+ uiLayoutRow(layout, true);
+ UI_block_align_begin(block);
+
+ template_search_add_button_searchmenu(C, layout, block, template_search, editable, false);
+ template_search_add_button_name(block, &active_ptr, type);
+ template_search_add_button_operator(block, newop, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE, editable);
+ template_search_add_button_operator(block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable);
+
+ UI_block_align_end(block);
+}
+
+static PropertyRNA *template_search_get_searchprop(
+ PointerRNA *targetptr, PropertyRNA *targetprop,
+ PointerRNA *searchptr, const char * const searchpropname)
+{
+ PropertyRNA *searchprop;
+
+ if (searchptr && !searchptr->data) {
+ searchptr = NULL;
+ }
+
+ if (!searchptr && !searchpropname) {
+ /* both NULL means we don't use a custom rna collection to search in */
+ }
+ else if (!searchptr && searchpropname) {
+ RNA_warning("searchpropname defined (%s) but searchptr is missing", searchpropname);
+ }
+ else if (searchptr && !searchpropname) {
+ RNA_warning("searchptr defined (%s) but searchpropname is missing", RNA_struct_identifier(searchptr->type));
+ }
+ else if (!(searchprop = RNA_struct_find_property(searchptr, searchpropname))) {
+ RNA_warning("search collection property not found: %s.%s",
+ RNA_struct_identifier(searchptr->type), searchpropname);
+ }
+ else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
+ RNA_warning("search collection property is not a collection type: %s.%s",
+ RNA_struct_identifier(searchptr->type), searchpropname);
+ }
+ /* check if searchprop has same type as targetprop */
+ else if (RNA_property_pointer_type(searchptr, searchprop) != RNA_property_pointer_type(targetptr, targetprop)) {
+ RNA_warning("search collection items from %s.%s are not of type %s",
+ RNA_struct_identifier(searchptr->type), searchpropname,
+ RNA_struct_identifier(RNA_property_pointer_type(targetptr, targetprop)));
+ }
+ else {
+ return searchprop;
+ }
+
+ return NULL;
+}
+
+static TemplateSearch *template_search_setup(
+ PointerRNA *ptr, const char * const propname,
+ PointerRNA *searchptr, const char * const searchpropname)
+{
+ TemplateSearch *template_search;
+ PropertyRNA *prop, *searchprop;
+
+ prop = RNA_struct_find_property(ptr, propname);
+
+ if (!prop || RNA_property_type(prop) != PROP_POINTER) {
+ RNA_warning("pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return NULL;
+ }
+ searchprop = template_search_get_searchprop(ptr, prop, searchptr, searchpropname);
+
+ template_search = MEM_callocN(sizeof(*template_search), __func__);
+ template_search->search_data.target_ptr = *ptr;
+ template_search->search_data.target_prop = prop;
+ template_search->search_data.search_ptr = *searchptr;
+ template_search->search_data.search_prop = searchprop;
+
+ return template_search;
+}
+
+/**
+ * Search menu to pick an item from a collection.
+ * A version of uiTemplateID that works for non-ID types.
+ */
+void uiTemplateSearch(
+ uiLayout *layout, bContext *C,
+ PointerRNA *ptr, const char *propname,
+ PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop)
+{
+ TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname);
+ if (template_search != NULL) {
+ template_search_buttons(C, layout, template_search, newop, unlinkop);
+ MEM_freeN(template_search);
+ }
+}
+
+void uiTemplateSearchPreview(
+ uiLayout *layout, bContext *C,
+ PointerRNA *ptr, const char *propname,
+ PointerRNA *searchptr, const char *searchpropname,
+ const char *newop, const char *unlinkop,
+ const int rows, const int cols)
+{
+ TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname);
+
+ if (template_search != NULL) {
+ template_search->use_previews = true;
+ template_search->preview_rows = rows;
+ template_search->preview_cols = cols;
+
+ template_search_buttons(C, layout, template_search, newop, unlinkop);
+
+ MEM_freeN(template_search);
+ }
+}
+
/********************* RNA Path Builder Template ********************/
/* ---------- */
@@ -897,7 +1335,7 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
ob->partype = PAROBJECT;
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
ED_undo_push(C, "Modifier convert to real");
}
@@ -917,7 +1355,7 @@ static int modifier_is_simulation(ModifierData *md)
{
/* Physic Tab */
if (ELEM(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke,
- eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint))
+ eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint))
{
return 1;
}
@@ -980,8 +1418,7 @@ static uiLayout *draw_modifier(
UI_block_emboss_set(block, UI_EMBOSS);
/* modifier name */
- md->scene = scene;
- if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
uiLayoutSetRedAlert(row, true);
}
uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
@@ -1042,16 +1479,15 @@ static uiLayout *draw_modifier(
UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* When Modifier is a simulation, show button to switch to context rather than the delete button. */
if (modifier_can_delete(md) &&
- (!modifier_is_simulation(md) ||
- STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)))
+ !modifier_is_simulation(md))
{
uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
}
else if (modifier_is_simulation(md) == 1) {
- uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PHYSICS");
+ uiItemStringO(row, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PHYSICS");
}
else if (modifier_is_simulation(md) == 2) {
- uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PARTICLES");
+ uiItemStringO(row, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PARTICLES");
}
UI_block_emboss_set(block, UI_EMBOSS);
}
@@ -1081,13 +1517,15 @@ static uiLayout *draw_modifier(
}
else {
uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
- uiItemEnumO(row, "OBJECT_OT_modifier_apply", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
- 0, "apply_as", MODIFIER_APPLY_DATA);
+ uiItemEnumO(
+ row, "OBJECT_OT_modifier_apply", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
+ 0, "apply_as", MODIFIER_APPLY_DATA);
if (modifier_isSameTopology(md) && !modifier_isNonGeometrical(md)) {
- uiItemEnumO(row, "OBJECT_OT_modifier_apply",
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply as Shape Key"),
- 0, "apply_as", MODIFIER_APPLY_SHAPE);
+ uiItemEnumO(
+ row, "OBJECT_OT_modifier_apply",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply as Shape Key"),
+ 0, "apply_as", MODIFIER_APPLY_SHAPE);
}
}
@@ -1095,7 +1533,7 @@ static uiLayout *draw_modifier(
UI_block_lock_set(block, ob && ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE);
if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
- eModifierType_Cloth, eModifierType_Smoke))
+ eModifierType_Cloth, eModifierType_Smoke))
{
uiItemO(row, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE,
"OBJECT_OT_modifier_copy");
@@ -1157,6 +1595,316 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
return NULL;
}
+/************************ Grease Pencil Modifier Template *************************/
+
+static uiLayout *gpencil_draw_modifier(
+ uiLayout *layout, Object *ob,
+ GpencilModifierData *md)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ PointerRNA ptr;
+ uiBlock *block;
+ uiLayout *box, *column, *row, *sub;
+ uiLayout *result = NULL;
+
+ /* create RNA pointer */
+ RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr);
+
+ column = uiLayoutColumn(layout, true);
+ uiLayoutSetContextPointer(column, "modifier", &ptr);
+
+ /* rounded header ------------------------------------------------------------------- */
+ box = uiLayoutBox(column);
+
+ row = uiLayoutRow(box, false);
+ block = uiLayoutGetBlock(row);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* Open/Close ................................. */
+ uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
+
+ /* modifier-type icon */
+ uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* modifier name */
+ if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ uiLayoutSetRedAlert(row, true);
+ }
+ uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
+ uiLayoutSetRedAlert(row, false);
+
+ /* mode enabling buttons */
+ UI_block_align_begin(block);
+ uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
+ uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
+
+ if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) {
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetActive(sub, false);
+ uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ }
+
+ UI_block_align_end(block);
+
+ /* Up/Down + Delete ........................... */
+ UI_block_align_begin(block);
+ uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_gpencil_modifier_move_up");
+ uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_gpencil_modifier_move_down");
+ UI_block_align_end(block);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ uiItemO(row, "", ICON_X, "OBJECT_OT_gpencil_modifier_remove");
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* modifier settings (under the header) --------------------------------------------------- */
+ if (md->mode & eGpencilModifierMode_Expanded) {
+ /* apply/convert/copy */
+ box = uiLayoutBox(column);
+ row = uiLayoutRow(box, false);
+
+ /* only here obdata, the rest of modifiers is ob level */
+ UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
+
+ sub = uiLayoutRow(row, false);
+ if (mti->flags & eGpencilModifierTypeFlag_NoApply) {
+ uiLayoutSetEnabled(sub, false);
+ }
+ uiItemEnumO(sub, "OBJECT_OT_gpencil_modifier_apply", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
+ 0, "apply_as", MODIFIER_APPLY_DATA);
+ uiItemO(row, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE,
+ "OBJECT_OT_gpencil_modifier_copy");
+
+ /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
+ result = uiLayoutColumn(box, false);
+ block = uiLayoutAbsoluteBlock(box);
+ }
+
+ /* error messages */
+ if (md->error) {
+ box = uiLayoutBox(column);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, md->error, ICON_ERROR);
+ }
+
+ return result;
+}
+
+uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ Object *ob;
+ GpencilModifierData *md, *vmd;
+ int i;
+
+ /* verify we have valid data */
+ if (!RNA_struct_is_a(ptr->type, &RNA_GpencilModifier)) {
+ RNA_warning("Expected modifier on object");
+ return NULL;
+ }
+
+ ob = ptr->id.data;
+ md = ptr->data;
+
+ if (!ob || !(GS(ob->id.name) == ID_OB)) {
+ RNA_warning("Expected modifier on object");
+ return NULL;
+ }
+
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE);
+
+ /* find modifier and draw it */
+ vmd = ob->greasepencil_modifiers.first;
+ for (i = 0; vmd; i++, vmd = vmd->next) {
+ if (md == vmd)
+ return gpencil_draw_modifier(layout, ob, md);
+ }
+
+ return NULL;
+}
+
+/************************ Shader FX Template *************************/
+
+static uiLayout *gpencil_draw_shaderfx(
+ uiLayout *layout, Object *ob,
+ ShaderFxData *md)
+{
+ const ShaderFxTypeInfo *mti = BKE_shaderfxType_getInfo(md->type);
+ PointerRNA ptr;
+ uiBlock *block;
+ uiLayout *box, *column, *row, *sub;
+ uiLayout *result = NULL;
+
+ /* create RNA pointer */
+ RNA_pointer_create(&ob->id, &RNA_ShaderFx, md, &ptr);
+
+ column = uiLayoutColumn(layout, true);
+ uiLayoutSetContextPointer(column, "shaderfx", &ptr);
+
+ /* rounded header ------------------------------------------------------------------- */
+ box = uiLayoutBox(column);
+
+ row = uiLayoutRow(box, false);
+ block = uiLayoutGetBlock(row);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ /* Open/Close ................................. */
+ uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
+
+ /* shader-type icon */
+ uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* effect name */
+ if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ uiLayoutSetRedAlert(row, true);
+ }
+ uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
+ uiLayoutSetRedAlert(row, false);
+
+ /* mode enabling buttons */
+ UI_block_align_begin(block);
+ uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
+ uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
+
+ if (mti->flags & eShaderFxTypeFlag_SupportsEditmode) {
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetActive(sub, false);
+ uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ }
+
+ UI_block_align_end(block);
+
+ /* Up/Down + Delete ........................... */
+ UI_block_align_begin(block);
+ uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_shaderfx_move_up");
+ uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_shaderfx_move_down");
+ UI_block_align_end(block);
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ uiItemO(row, "", ICON_X, "OBJECT_OT_shaderfx_remove");
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ /* effect settings (under the header) --------------------------------------------------- */
+ if (md->mode & eShaderFxMode_Expanded) {
+ /* apply/convert/copy */
+ box = uiLayoutBox(column);
+ row = uiLayoutRow(box, false);
+
+ /* only here obdata, the rest of effect is ob level */
+ UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ /* result is the layout block inside the box, that we return so that effect settings can be drawn */
+ result = uiLayoutColumn(box, false);
+ block = uiLayoutAbsoluteBlock(box);
+ }
+
+ /* error messages */
+ if (md->error) {
+ box = uiLayoutBox(column);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, md->error, ICON_ERROR);
+ }
+
+ return result;
+}
+
+uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ Object *ob;
+ ShaderFxData *fx, *vfx;
+ int i;
+
+ /* verify we have valid data */
+ if (!RNA_struct_is_a(ptr->type, &RNA_ShaderFx)) {
+ RNA_warning("Expected shader fx on object");
+ return NULL;
+ }
+
+ ob = ptr->id.data;
+ fx = ptr->data;
+
+ if (!ob || !(GS(ob->id.name) == ID_OB)) {
+ RNA_warning("Expected shader fx on object");
+ return NULL;
+ }
+
+ UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE);
+
+ /* find modifier and draw it */
+ vfx = ob->shader_fx.first;
+ for (i = 0; vfx; i++, vfx = vfx->next) {
+ if (fx == vfx)
+ return gpencil_draw_shaderfx(layout, ob, fx);
+ }
+
+ return NULL;
+}
+
+/************************ Redo Buttons Template *************************/
+
+static void template_operator_redo_property_buts_draw(
+ const bContext *C, wmOperator *op,
+ uiLayout *layout, int layout_flags,
+ bool *r_has_advanced)
+{
+ if (op->type->flag & OPTYPE_MACRO) {
+ for (wmOperator *macro_op = op->macro.first; macro_op; macro_op = macro_op->next) {
+ template_operator_redo_property_buts_draw(C, macro_op, layout, layout_flags, r_has_advanced);
+ }
+ }
+ else {
+ /* Might want to make label_align adjustable somehow. */
+ eAutoPropButsReturn return_info = uiTemplateOperatorPropertyButs(
+ C, layout, op,
+ UI_BUT_LABEL_ALIGN_NONE,
+ layout_flags);
+ if (return_info & UI_PROP_BUTS_ANY_FAILED_CHECK) {
+ if (r_has_advanced) {
+ *r_has_advanced = true;
+ }
+ }
+ }
+}
+
+void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+ uiBlock *block = uiLayoutGetBlock(layout);
+
+ if (op == NULL) {
+ return;
+ }
+
+ /* Disable for now, doesn't fit well in popover. */
+#if 0
+ /* Repeat button with operator name as text. */
+ uiItemFullO(layout, "SCREEN_OT_repeat_last", RNA_struct_ui_name(op->type->srna),
+ ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0, NULL);
+#endif
+
+ if (WM_operator_repeat_check(C, op)) {
+ int layout_flags = 0;
+ if (block->panel == NULL) {
+ layout_flags = UI_TEMPLATE_OP_PROPS_SHOW_TITLE;
+ }
+#if 0
+ bool has_advanced = false;
+#endif
+
+ UI_block_func_set(block, ED_undo_operator_repeat_cb, op, NULL);
+ template_operator_redo_property_buts_draw(C, op, layout, layout_flags, NULL /* &has_advanced */ );
+ UI_block_func_set(block, NULL, NULL, NULL); /* may want to reset to old state instead of NULLing all */
+
+#if 0
+ if (has_advanced) {
+ uiItemO(layout, IFACE_("More..."), ICON_NONE, "SCREEN_OT_redo_last");
+ }
+#endif
+ }
+}
+
/************************ Constraint Template *************************/
#include "DNA_constraint_types.h"
@@ -1180,7 +1928,7 @@ static void do_constraint_panels(bContext *C, void *ob_pt, int event)
Main *bmain = CTX_data_main(C);
if (ob->pose)
BKE_pose_tag_recalc(bmain, ob->pose); /* checks & sorts pose channels */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
break;
}
#endif
@@ -1194,8 +1942,8 @@ static void do_constraint_panels(bContext *C, void *ob_pt, int event)
* object_test_constraints(ob);
* if (ob->pose) BKE_pose_update_constraint_flags(ob->pose); */
- if (ob->type == OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
- else DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ if (ob->type == OB_ARMATURE) DEG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
+ else DEG_id_tag_update(&ob->id, OB_RECALC_OB);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
}
@@ -1273,7 +2021,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
- uiDefIconBut(block, UI_BTYPE_BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco + 12.2f * UI_UNIT_X, yco, 0.95f * UI_UNIT_X, 0.95f * UI_UNIT_Y,
+ uiDefIconBut(block, UI_BTYPE_BUT, B_CONSTRAINT_TEST, ICON_GHOST_ENABLED, xco + 12.2f * UI_UNIT_X, yco, 0.95f * UI_UNIT_X, 0.95f * UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Proxy Protected"));
uiDefIconBut(block, UI_BTYPE_BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco + 13.1f * UI_UNIT_X, yco, 0.95f * UI_UNIT_X, 0.95f * UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Proxy Protected"));
@@ -1306,7 +2054,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
/* enabled */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
uiItemR(row, &ptr, "mute", 0, "",
- (con->flag & CONSTRAINT_OFF) ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF);
+ (con->flag & CONSTRAINT_OFF) ? ICON_HIDE_ON : ICON_HIDE_OFF);
UI_block_emboss_set(block, UI_EMBOSS);
uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
@@ -1416,7 +2164,7 @@ void uiTemplatePreview(
char _preview_id[UI_MAX_NAME_STR];
if (id && !ELEM(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) {
- RNA_warning("Expected ID of type material, texture, lamp, world or line style");
+ RNA_warning("Expected ID of type material, texture, light, world or line style");
return;
}
@@ -1507,7 +2255,7 @@ void uiTemplatePreview(
pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
}
else if (GS(parent->name) == ID_LA) {
- uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, IFACE_("Lamp"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+ uiDefButS(block, UI_BTYPE_ROW, B_MATPRV, IFACE_("Light"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
}
else if (GS(parent->name) == ID_WO) {
@@ -1548,6 +2296,110 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
RNA_property_update(C, &cb->ptr, cb->prop);
}
+enum {
+ CB_FUNC_FLIP,
+ CB_FUNC_DISTRIBUTE_LR,
+ CB_FUNC_DISTRIBUTE_EVENLY,
+ CB_FUNC_RESET,
+};
+
+static void colorband_flip_cb(bContext *C, ColorBand *coba)
+{
+ CBData data_tmp[MAXCOLORBAND];
+
+ int a;
+
+ for (a = 0; a < coba->tot; a++) {
+ data_tmp[a] = coba->data[coba->tot - (a + 1)];
+ }
+ for (a = 0; a < coba->tot; a++) {
+ data_tmp[a].pos = 1.0f - data_tmp[a].pos;
+ coba->data[a] = data_tmp[a];
+ }
+
+ /* may as well flip the cur*/
+ coba->cur = coba->tot - (coba->cur + 1);
+
+ ED_undo_push(C, "Flip Color Ramp");
+}
+
+static void colorband_distribute_cb(bContext *C, ColorBand *coba, bool evenly)
+{
+ if (coba->tot > 1) {
+ int a;
+ int tot = evenly ? coba->tot - 1 : coba->tot;
+ float gap = 1.0f / tot;
+ float pos = 0.0f;
+ for (a = 0; a < coba->tot; a++) {
+ coba->data[a].pos = pos;
+ pos += gap;
+ }
+ ED_undo_push(C, evenly ? "Distribute Stops Evenly" : "Distribute Stops from Left");
+ }
+}
+
+static void colorband_tools_dofunc(bContext *C, void *coba_v, int event)
+{
+ ColorBand *coba = coba_v;
+
+ switch (event) {
+ case CB_FUNC_FLIP:
+ colorband_flip_cb(C, coba);
+ break;
+ case CB_FUNC_DISTRIBUTE_LR:
+ colorband_distribute_cb(C, coba, false);
+ break;
+ case CB_FUNC_DISTRIBUTE_EVENLY:
+ colorband_distribute_cb(C, coba, true);
+ break;
+ case CB_FUNC_RESET:
+ BKE_colorband_init(coba, true);
+ ED_undo_push(C, "Reset Color Ramp");
+ break;
+ }
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
+static uiBlock *colorband_tools_func(
+ bContext *C, ARegion *ar, void *coba_v)
+{
+ ColorBand *coba = coba_v;
+ uiBlock *block;
+ short yco = 0, menuwidth = 10 * UI_UNIT_X;
+
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ UI_block_func_butmenu_set(block, colorband_tools_dofunc, coba);
+
+ {
+ uiBut *but;
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1,
+ IFACE_("Flip Color Ramp"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0, CB_FUNC_FLIP, "");
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1,
+ IFACE_("Distribute Stops from Left"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0, CB_FUNC_DISTRIBUTE_LR, "");
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1,
+ IFACE_("Distribute Stops Evenly"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0, CB_FUNC_DISTRIBUTE_EVENLY, "");
+ but = uiDefIconTextButO(
+ block, UI_BTYPE_BUT_MENU, "UI_OT_eyedropper_colorband", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER,
+ IFACE_("Eyedropper"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y,
+ "");
+ but->custom_data = coba;
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset Color Ramp"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, CB_FUNC_RESET, "");
+ }
+
+ UI_block_direction_set(block, UI_DIR_DOWN);
+ UI_block_bounds_set_text(block, 3.0f * UI_UNIT_X);
+
+ return block;
+}
+
static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
{
ColorBand *coba = coba_v;
@@ -1560,7 +2412,7 @@ static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
if (BKE_colorband_element_add(coba, pos)) {
rna_update_cb(C, cb_v, NULL);
- ED_undo_push(C, "Add colorband");
+ ED_undo_push(C, "Add Color Ramp Stop");
}
}
@@ -1569,34 +2421,11 @@ static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
ColorBand *coba = coba_v;
if (BKE_colorband_element_remove(coba, coba->cur)) {
- ED_undo_push(C, "Delete colorband");
+ ED_undo_push(C, "Delete Color Ramp Stop");
rna_update_cb(C, cb_v, NULL);
}
}
-static void colorband_flip_cb(bContext *C, void *cb_v, void *coba_v)
-{
- CBData data_tmp[MAXCOLORBAND];
-
- ColorBand *coba = coba_v;
- int a;
-
- for (a = 0; a < coba->tot; a++) {
- data_tmp[a] = coba->data[coba->tot - (a + 1)];
- }
- for (a = 0; a < coba->tot; a++) {
- data_tmp[a].pos = 1.0f - data_tmp[a].pos;
- coba->data[a] = data_tmp[a];
- }
-
- /* may as well flip the cur*/
- coba->cur = coba->tot - (coba->cur + 1);
-
- ED_undo_push(C, "Flip colorband");
-
- rna_update_cb(C, cb_v, NULL);
-}
-
static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
{
uiBut *bt = bt_v;
@@ -1628,24 +2457,19 @@ static void colorband_buttons_layout(
row = uiLayoutRow(split, false);
bt = uiDefIconTextBut(
- block, UI_BTYPE_BUT, 0, ICON_ZOOMIN, "", 0, 0, 2.0f * unit, UI_UNIT_Y, NULL,
- 0, 0, 0, 0, TIP_("Add a new color stop to the colorband"));
-
+ block, UI_BTYPE_BUT, 0, ICON_ADD, "", 0, 0, 2.0f * unit, UI_UNIT_Y, NULL,
+ 0, 0, 0, 0, TIP_("Add a new color stop to the color ramp"));
UI_but_funcN_set(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
bt = uiDefIconTextBut(
- block, UI_BTYPE_BUT, 0, ICON_ZOOMOUT, "", xs + 2.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
+ block, UI_BTYPE_BUT, 0, ICON_REMOVE, "", xs + 2.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Delete the active position"));
UI_but_funcN_set(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
- bt = uiDefIconTextBut(
- block, UI_BTYPE_BUT, 0, ICON_ARROW_LEFTRIGHT, "", xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Flip the color ramp"));
- UI_but_funcN_set(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
-
- bt = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_colorband", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, xs + 6.0f * unit, ys + UI_UNIT_Y, UI_UNIT_X, UI_UNIT_Y, NULL);
- bt->custom_data = coba;
- bt->func_argN = MEM_dupallocN(cb);
+ bt = uiDefIconBlockBut(
+ block, colorband_tools_func, coba, 0, ICON_DOWNARROW_HLT,
+ xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y, TIP_("Tools"));
+ UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), coba);
UI_block_align_end(block);
UI_block_emboss_set(block, UI_EMBOSS);
@@ -1747,6 +2571,19 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
MEM_freeN(cb);
}
+/********************* Icon Template ************************/
+/**
+ * \param icon_scale: Scale of the icon, 1x == button height.
+ */
+void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale)
+{
+ uiBlock *block;
+ uiBut *but;
+
+ block = uiLayoutAbsoluteBlock(layout);
+ but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, ICON_X, 0, 0, UI_UNIT_X * icon_scale, UI_UNIT_Y * icon_scale, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ ui_def_but_icon(but, icon_value, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+}
/********************* Icon viewer Template ************************/
typedef struct IconViewMenuArgs {
@@ -1834,13 +2671,20 @@ void uiTemplateIconView(uiLayout *layout, PointerRNA *ptr, const char *propname,
value = RNA_property_enum_get(ptr, prop);
RNA_enum_icon_from_value(items, value, &icon);
- cb_args = MEM_callocN(sizeof(IconViewMenuArgs), __func__);
- cb_args->ptr = *ptr;
- cb_args->prop = prop;
- cb_args->show_labels = show_labels;
- cb_args->icon_scale = icon_scale;
- but = uiDefBlockButN(block, ui_icon_view_menu_cb, cb_args, "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, "");
+ if (RNA_property_editable(ptr, prop)) {
+ cb_args = MEM_callocN(sizeof(IconViewMenuArgs), __func__);
+ cb_args->ptr = *ptr;
+ cb_args->prop = prop;
+ cb_args->show_labels = show_labels;
+ cb_args->icon_scale = icon_scale;
+
+ but = uiDefBlockButN(block, ui_icon_view_menu_cb, cb_args, "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, "");
+ }
+ else {
+ but = uiDefIconBut(block, UI_BTYPE_LABEL, 0, ICON_X, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ }
+
ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
@@ -2154,8 +2998,8 @@ static uiBlock *curvemap_tools_func(
0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, reset_mode, "");
}
- UI_block_direction_set(block, UI_DIR_RIGHT);
- UI_block_bounds_set_text(block, 50);
+ UI_block_direction_set(block, UI_DIR_DOWN);
+ UI_block_bounds_set_text(block, 3.0f * UI_UNIT_X);
return block;
}
@@ -2208,7 +3052,7 @@ static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
/* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
static void curvemap_buttons_layout(
uiLayout *layout, PointerRNA *ptr, char labeltype, bool levels,
- bool brush, bool neg_slope, RNAUpdateCb *cb)
+ bool brush, bool neg_slope, bool tone, RNAUpdateCb *cb)
{
CurveMapping *cumap = ptr->data;
CurveMap *cm = &cumap->cm[cumap->cur];
@@ -2222,6 +3066,11 @@ static void curvemap_buttons_layout(
block = uiLayoutGetBlock(layout);
+ if (tone) {
+ split = uiLayoutSplit(layout, 0.0f, false);
+ uiItemR(uiLayoutRow(split, false), ptr, "tone", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ }
+
/* curve chooser */
row = uiLayoutRow(layout, false);
@@ -2301,14 +3150,14 @@ static void curvemap_buttons_layout(
UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, NULL);
if (brush)
- bt = uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
+ bt = uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_DOWNARROW_HLT, 0, 0, dx, dx, TIP_("Tools"));
else if (neg_slope)
bt = uiDefIconBlockBut(
- block, curvemap_tools_negslope_func, cumap, 0, ICON_MODIFIER,
+ block, curvemap_tools_negslope_func, cumap, 0, ICON_DOWNARROW_HLT,
0, 0, dx, dx, TIP_("Tools"));
else
bt = uiDefIconBlockBut(
- block, curvemap_tools_posslope_func, cumap, 0, ICON_MODIFIER,
+ block, curvemap_tools_posslope_func, cumap, 0, ICON_DOWNARROW_HLT,
0, 0, dx, dx, TIP_("Tools"));
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
@@ -2373,7 +3222,7 @@ static void curvemap_buttons_layout(
void uiTemplateCurveMapping(
uiLayout *layout, PointerRNA *ptr, const char *propname, int type,
- bool levels, bool brush, bool neg_slope)
+ bool levels, bool brush, bool neg_slope, bool tone)
{
RNAUpdateCb *cb;
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -2404,7 +3253,7 @@ void uiTemplateCurveMapping(
id = cptr.id.data;
UI_block_lock_set(block, (id && ID_IS_LINKED(id)), ERROR_LIBDATA_MESSAGE);
- curvemap_buttons_layout(layout, &cptr, type, levels, brush, neg_slope, cb);
+ curvemap_buttons_layout(layout, &cptr, type, levels, brush, neg_slope, tone, cb);
UI_block_lock_clear(block);
@@ -2551,8 +3400,8 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
col = uiLayoutColumn(layout, true);
uiLayoutRow(col, true);
- uiDefIconButO(block, UI_BTYPE_BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
- uiDefIconButO(block, UI_BTYPE_BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ uiDefIconButO(block, UI_BTYPE_BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ADD, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ uiDefIconButO(block, UI_BTYPE_BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_REMOVE, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
col = uiLayoutColumn(layout, true);
uiLayoutRow(col, true);
@@ -2689,78 +3538,6 @@ void uiTemplateLayers(
}
}
-void uiTemplateGameStates(
- uiLayout *layout, PointerRNA *ptr, const char *propname,
- PointerRNA *used_ptr, const char *used_propname, int active_state)
-{
- uiLayout *uRow, *uCol;
- PropertyRNA *prop, *used_prop = NULL;
- int groups, cols, states;
- int group, col, state, row;
- int cols_per_group = 5;
- Object *ob = (Object *)ptr->id.data;
-
- prop = RNA_struct_find_property(ptr, propname);
- if (!prop) {
- RNA_warning("states property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
- return;
- }
-
- /* the number of states determines the way we group them
- * - we want 2 rows only (for now)
- * - the number of columns (cols) is the total number of buttons per row
- * the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
- * - for now, only split into groups if group will have at least 5 items
- */
- states = RNA_property_array_length(ptr, prop);
- cols = (states / 2) + (states % 2);
- groups = ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
-
- if (used_ptr && used_propname) {
- used_prop = RNA_struct_find_property(used_ptr, used_propname);
- if (!used_prop) {
- RNA_warning("used layers property not found: %s.%s", RNA_struct_identifier(ptr->type), used_propname);
- return;
- }
-
- if (RNA_property_array_length(used_ptr, used_prop) < states)
- used_prop = NULL;
- }
-
- /* layers are laid out going across rows, with the columns being divided into groups */
-
- for (group = 0; group < groups; group++) {
- uCol = uiLayoutColumn(layout, true);
-
- for (row = 0; row < 2; row++) {
- uiBlock *block;
- uiBut *but;
-
- uRow = uiLayoutRow(uCol, true);
- block = uiLayoutGetBlock(uRow);
- state = groups * cols_per_group * row + cols_per_group * group;
-
- /* add layers as toggle buts */
- for (col = 0; (col < cols_per_group) && (state < states); col++, state++) {
- int icon = 0;
- int butlay = 1 << state;
-
- if (active_state & butlay)
- icon = ICON_LAYER_ACTIVE;
- else if (used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, state))
- icon = ICON_LAYER_USED;
-
- but = uiDefIconButR_prop(
- block, UI_BTYPE_ICON_TOGGLE, 0, icon, 0, 0, UI_UNIT_X / 2, UI_UNIT_Y / 2, ptr, prop,
- state, 0, 0, -1, -1, sca_state_name_get(ob, state));
- UI_but_func_set(but, handle_layer_buttons, but, POINTER_FROM_INT(state));
- but->type = UI_BTYPE_TOGGLE;
- }
- }
- }
-}
-
-
/************************* List Template **************************/
static void uilist_draw_item_default(
struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout,
@@ -2788,7 +3565,7 @@ static void uilist_draw_item_default(
}
}
-static void uilist_draw_filter_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout)
+static void uilist_draw_filter_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout, bool reverse)
{
PointerRNA listptr;
uiLayout *row, *subrow;
@@ -2802,10 +3579,13 @@ static void uilist_draw_filter_default(struct uiList *ui_list, struct bContext *
uiItemR(subrow, &listptr, "use_filter_invert", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "",
(ui_list->filter_flag & UILST_FLT_EXCLUDE) ? ICON_ZOOM_OUT : ICON_ZOOM_IN);
- subrow = uiLayoutRow(row, true);
- uiItemR(subrow, &listptr, "use_filter_sort_alpha", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- uiItemR(subrow, &listptr, "use_filter_sort_reverse", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "",
- (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) ? ICON_TRIA_UP : ICON_TRIA_DOWN);
+ /* a reverse list, cannot sort or invert order in filter */
+ if (!reverse) {
+ subrow = uiLayoutRow(row, true);
+ uiItemR(subrow, &listptr, "use_filter_sort_alpha", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(subrow, &listptr, "use_filter_sort_reverse", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "",
+ (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) ? ICON_SORT_DESC : ICON_SORT_ASC);
+ }
}
typedef struct {
@@ -3028,7 +3808,7 @@ static char *uilist_item_tooltip_func(bContext *UNUSED(C), void *argN, const cha
void uiTemplateList(
uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname,
- const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns)
+ const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns, bool reverse)
{
uiListType *ui_list_type;
uiList *ui_list = NULL;
@@ -3149,6 +3929,19 @@ void uiTemplateList(
MEM_SAFE_FREE(dyn_data->items_filter_neworder);
dyn_data->items_len = dyn_data->items_shown = -1;
+ /* if reverse, enable reverse and forced flag */
+ if (reverse) {
+ ui_list->filter_sort_flag |= UILST_FLT_SORT_REVERSE;
+ ui_list->filter_sort_flag |= UILST_FLT_FORCED_REVERSE;
+ }
+ else {
+ /* if it was forced, disable forced flag to restore all normal behavior */
+ if (ui_list->filter_sort_flag & UILST_FLT_FORCED_REVERSE) {
+ ui_list->filter_sort_flag &= ~UILST_FLT_SORT_REVERSE;
+ ui_list->filter_sort_flag &= ~UILST_FLT_FORCED_REVERSE;
+ }
+ }
+
/* When active item changed since last draw, scroll to it. */
if (activei != ui_list->list_last_activei) {
ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
@@ -3426,7 +4219,7 @@ void uiTemplateList(
subblock = uiLayoutGetBlock(col);
uiDefBut(subblock, UI_BTYPE_SEPR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y * 0.05f, NULL, 0.0, 0.0, 0, 0, "");
- draw_filter(ui_list, C, col);
+ draw_filter(ui_list, C, col, reverse);
}
else {
but = uiDefIconButBitI(subblock, UI_BTYPE_TOGGLE, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_RIGHT, 0, 0,
@@ -3508,8 +4301,8 @@ static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char
/* check for hotkey */
if (len < sizeof(name) - 6) {
if (WM_key_event_operator_string(
- C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, true,
- &name[len + 1], sizeof(name) - len - 1))
+ C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, true,
+ &name[len + 1], sizeof(name) - len - 1))
{
name[len] = UI_SEP_CHAR;
}
@@ -3554,12 +4347,18 @@ static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt,
struct uiTemplateOperatorPropertyPollParam {
const bContext *C;
wmOperator *op;
+ short flag;
};
static bool ui_layout_operator_buts_poll_property(
struct PointerRNA *UNUSED(ptr), struct PropertyRNA *prop, void *user_data)
{
struct uiTemplateOperatorPropertyPollParam *params = user_data;
+ if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) &&
+ (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED))
+ {
+ return false;
+ }
return params->op->type->poll_property(params->C, params->op, prop);
}
@@ -3567,48 +4366,50 @@ static bool ui_layout_operator_buts_poll_property(
* Draw Operator property buttons for redoing execution with different settings.
* This function does not initialize the layout, functions can be called on the layout before and after.
*/
-void uiTemplateOperatorPropertyButs(
+eAutoPropButsReturn uiTemplateOperatorPropertyButs(
const bContext *C, uiLayout *layout, wmOperator *op,
- const char label_align, const short flag)
+ const eButLabelAlign label_align, const short flag)
{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ eAutoPropButsReturn return_info = 0;
+
if (!op->properties) {
IDPropertyTemplate val = {0};
op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
}
- if (flag & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
- uiItemL(layout, RNA_struct_ui_name(op->type->srna), ICON_NONE);
- }
-
/* poll() on this operator may still fail, at the moment there is no nice feedback when this happens
* just fails silently */
if (!WM_operator_repeat_check(C, op)) {
- UI_block_lock_set(uiLayoutGetBlock(layout), true, "Operator can't' redo");
-
- /* XXX, could give some nicer feedback or not show redo panel at all? */
- uiItemL(layout, IFACE_("* Redo Unsupported *"), ICON_NONE);
+ UI_block_lock_set(block, true, "Operator can't' redo");
+ return return_info;
}
else {
/* useful for macros where only one of the steps can't be re-done */
- UI_block_lock_clear(uiLayoutGetBlock(layout));
+ UI_block_lock_clear(block);
+ }
+
+ if (flag & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
+ uiItemL(layout, RNA_struct_ui_name(op->type->srna), ICON_NONE);
}
+
/* menu */
if (op->type->flag & OPTYPE_PRESET) {
/* XXX, no simple way to get WM_MT_operator_presets.bl_label from python! Label remains the same always! */
PointerRNA op_ptr;
uiLayout *row;
- uiLayoutGetBlock(layout)->ui_operator = op;
+ block->ui_operator = op;
row = uiLayoutRow(layout, true);
uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE);
wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
- uiItemFullO_ptr(row, ot, "", ICON_ZOOMIN, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_string_set(&op_ptr, "operator", op->type->idname);
- uiItemFullO_ptr(row, ot, "", ICON_ZOOMOUT, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_string_set(&op_ptr, "operator", op->type->idname);
RNA_boolean_set(&op_ptr, "remove_active", true);
}
@@ -3618,24 +4419,26 @@ void uiTemplateOperatorPropertyButs(
op->type->ui((bContext *)C, op);
op->layout = NULL;
- /* UI_LAYOUT_OP_SHOW_EMPTY ignored */
+ /* UI_LAYOUT_OP_SHOW_EMPTY ignored. return_info is ignored too. We could
+ * allow ot.ui callback to return this, but not needed right now. */
}
else {
wmWindowManager *wm = CTX_wm_manager(C);
PointerRNA ptr;
- int empty;
- struct uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op};
+ struct uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = flag};
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+ uiLayoutSetPropSep(layout, true);
+
/* main draw call */
- empty = uiDefAutoButsRNA(
+ return_info = uiDefAutoButsRNA(
layout, &ptr,
op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL,
op->type->poll_property ? &user_data : NULL,
- label_align) == 0;
+ label_align, (flag & UI_TEMPLATE_OP_PROPS_COMPACT));
- if (empty && (flag & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) {
+ if ((return_info & UI_PROP_BUTS_NONE_ADDED) && (flag & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) {
uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
}
}
@@ -3645,7 +4448,6 @@ void uiTemplateOperatorPropertyButs(
* but this is not so important if this button is drawn in those cases
* (which isn't all that likely anyway) - campbell */
if (op->properties->len) {
- uiBlock *block;
uiBut *but;
uiLayout *col; /* needed to avoid alignment errors with previous buttons */
@@ -3658,8 +4460,9 @@ void uiTemplateOperatorPropertyButs(
#endif
/* set various special settings for buttons */
- {
- uiBlock *block = uiLayoutGetBlock(layout);
+
+ /* Only do this if we're not refreshing an existing UI. */
+ if (block->oldblock == NULL) {
const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
uiBut *but;
@@ -3679,6 +4482,8 @@ void uiTemplateOperatorPropertyButs(
}
}
}
+
+ return return_info;
}
/************************* Running Jobs Template **************************/
@@ -3783,7 +4588,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
owner = sa;
}
handle_event = B_STOPFILE;
- icon = ICON_FILESEL;
+ icon = ICON_FILEBROWSER;
}
else {
Scene *scene;
@@ -3808,7 +4613,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
*/
if (sa->spacetype != SPACE_NODE) {
handle_event = B_STOPOTHER;
- icon = ICON_IMAGE_COL;
+ icon = ICON_IMAGE;
break;
}
}
@@ -3916,23 +4721,20 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
UI_fontstyle_set(&style->widgetlabel);
width = BLF_width(style->widgetlabel.uifont_id, report->message, report->len);
width = min_ii((int)(rti->widthfac * width), width);
- width = max_ii(width, 10);
+ width = max_ii(width, 10 * UI_DPI_FAC);
/* make a box around the report to make it stand out */
UI_block_align_begin(block);
- but = uiDefBut(block, UI_BTYPE_ROUNDBOX, 0, "", 0, 0, UI_UNIT_X + 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
+ but = uiDefBut(block, UI_BTYPE_ROUNDBOX, 0, "", 0, 0, UI_UNIT_X + 5, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
/* set the report's bg color in but->col - UI_BTYPE_ROUNDBOX feature */
- rgb_float_to_uchar(but->col, rti->col);
- but->col[3] = 255;
+ rgba_float_to_uchar(but->col, rti->col);
- but = uiDefBut(block, UI_BTYPE_ROUNDBOX, 0, "", UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y,
+ but = uiDefBut(block, UI_BTYPE_ROUNDBOX, 0, "", UI_UNIT_X + 5, 0, UI_UNIT_X + width, UI_UNIT_Y,
NULL, 0.0f, 0.0f, 0, 0, "");
- but->col[0] = but->col[1] = but->col[2] = unit_float_to_uchar_clamp(rti->grayscale);
- but->col[3] = 255;
+ rgba_float_to_uchar(but->col, rti->col);
UI_block_align_end(block);
-
/* icon and report message on top */
icon = UI_icon_from_report_type(report->type);
@@ -3949,10 +4751,50 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
UI_block_emboss_set(block, UI_EMBOSS);
- uiDefBut(block, UI_BTYPE_LABEL, 0, report->message, UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y,
+ uiDefBut(block, UI_BTYPE_LABEL, 0, report->message, UI_UNIT_X + 5, 0, UI_UNIT_X + width, UI_UNIT_Y,
NULL, 0.0f, 0.0f, 0, 0, "");
}
+
+void uiTemplateInputStatus(uiLayout *layout, struct bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = CTX_wm_workspace(C);
+
+ /* Workspace status text has priority. */
+ if (workspace->status_text) {
+ uiItemL(layout, workspace->status_text, ICON_NONE);
+ return;
+ }
+
+ if (WM_window_modal_keymap_status_draw(C, win, layout)) {
+ return;
+ }
+
+ /* Otherwise should cursor keymap status. */
+ for (int i = 0; i < 3; i++) {
+ uiLayout *box = uiLayoutRow(layout, false);
+ uiLayout *col = uiLayoutColumn(box, false);
+ uiLayout *row = uiLayoutRow(col, true);
+ uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
+
+ const char *msg = WM_window_cursor_keymap_status_get(win, i, 0);
+ const char *msg_drag = WM_window_cursor_keymap_status_get(win, i, 1);
+
+ if (msg || (msg_drag == NULL)) {
+ uiItemL(row, msg ? msg : "", (ICON_MOUSE_LMB + i));
+ }
+
+ if (msg_drag) {
+ uiItemL(row, msg_drag, (ICON_MOUSE_LMB_DRAG + i));
+ }
+
+ /* Use trick with empty string to keep icons in same position. */
+ row = uiLayoutRow(col, false);
+ uiItemL(row, " ", ICON_NONE);
+ }
+}
+
/********************************* Keymap *************************************/
static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED(unused))
@@ -4015,6 +4857,7 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
if (propptr.data) {
uiBut *but = uiLayoutGetBlock(layout)->buttons.last;
+ WM_operator_properties_sanitize(&propptr, false);
template_keymap_item_properties(layout, NULL, &propptr);
/* attach callbacks to compensate for missing properties update,
@@ -4083,7 +4926,7 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE);
if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES)
- uiTemplateCurveMapping(col, &view_transform_ptr, "curve_mapping", 'c', true, false, false);
+ uiTemplateCurveMapping(col, &view_transform_ptr, "curve_mapping", 'c', true, false, false, false);
}
/********************************* Component Menu *************************************/
@@ -4179,7 +5022,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
- uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!file) {
return;
@@ -4227,3 +5070,20 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiItemR(row, &fileptr, "up_axis", 0, "Up Axis", ICON_NONE);
#endif
}
+
+/******************************* Recent Files *******************************/
+
+int uiTemplateRecentFiles(uiLayout *layout, int rows)
+{
+ const RecentFile *recent;
+ int i;
+
+ for (recent = G.recent_files.first, i = 0; (i < rows) && (recent); recent = recent->next, i++) {
+ const char *filename = BLI_path_basename(recent->filepath);
+ uiItemStringO(layout, filename,
+ BLO_has_bfile_extension(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP,
+ "WM_OT_open_mainfile", "filepath", recent->filepath);
+ }
+
+ return i;
+}
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 2b9c6265eeb..d74bfe93f2f 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -43,6 +43,7 @@
#include "BLT_translation.h"
+#include "BKE_library.h"
#include "BKE_report.h"
#include "MEM_guardedalloc.h"
@@ -157,67 +158,165 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
* \a check_prop callback filters functions to avoid drawing certain properties,
* in cases where PROP_HIDDEN flag can't be used for a property.
*/
-int uiDefAutoButsRNA(
+eAutoPropButsReturn uiDefAutoButsRNA(
uiLayout *layout, PointerRNA *ptr,
bool (*check_prop)(PointerRNA *ptr, PropertyRNA *prop, void *user_data), void *user_data,
- const char label_align)
+ const eButLabelAlign label_align, const bool compact)
{
+ eAutoPropButsReturn return_info = UI_PROP_BUTS_NONE_ADDED;
uiLayout *split, *col;
int flag;
const char *name;
- int tot = 0;
-
- assert(ELEM(label_align, '\0', 'H', 'V'));
RNA_STRUCT_BEGIN (ptr, prop)
{
flag = RNA_property_flag(prop);
- if (flag & PROP_HIDDEN || (check_prop && check_prop(ptr, prop, user_data) == 0)) {
+
+ if (flag & PROP_HIDDEN) {
+ continue;
+ }
+ if (check_prop && check_prop(ptr, prop, user_data) == 0) {
+ return_info |= UI_PROP_BUTS_ANY_FAILED_CHECK;
continue;
}
- if (label_align != '\0') {
- PropertyType type = RNA_property_type(prop);
- const bool is_boolean = (type == PROP_BOOLEAN && !RNA_property_array_check(prop));
+ switch (label_align) {
+ case UI_BUT_LABEL_ALIGN_COLUMN:
+ case UI_BUT_LABEL_ALIGN_SPLIT_COLUMN:
+ {
+ PropertyType type = RNA_property_type(prop);
+ const bool is_boolean = (type == PROP_BOOLEAN && !RNA_property_array_check(prop));
- name = RNA_property_ui_name(prop);
+ name = RNA_property_ui_name(prop);
- if (label_align == 'V') {
- col = uiLayoutColumn(layout, true);
+ if (label_align == UI_BUT_LABEL_ALIGN_COLUMN) {
+ col = uiLayoutColumn(layout, true);
- if (!is_boolean)
- uiItemL(col, name, ICON_NONE);
- }
- else { /* (label_align == 'H') */
- BLI_assert(label_align == 'H');
- split = uiLayoutSplit(layout, 0.5f, false);
+ if (!is_boolean)
+ uiItemL(col, name, ICON_NONE);
+ }
+ else {
+ BLI_assert(label_align == UI_BUT_LABEL_ALIGN_SPLIT_COLUMN);
+ split = uiLayoutSplit(layout, 0.5f, false);
+
+ col = uiLayoutColumn(split, false);
+ uiItemL(col, (is_boolean) ? "" : name, ICON_NONE);
+ col = uiLayoutColumn(split, false);
+ }
+
+ /* may meed to add more cases here.
+ * don't override enum flag names */
+
+ /* name is shown above, empty name for button below */
+ name = (flag & PROP_ENUM_FLAG || is_boolean) ? NULL : "";
- col = uiLayoutColumn(split, false);
- uiItemL(col, (is_boolean) ? "" : name, ICON_NONE);
- col = uiLayoutColumn(split, false);
+ break;
}
+ case UI_BUT_LABEL_ALIGN_NONE:
+ default:
+ col = layout;
+ name = NULL; /* no smart label alignment, show default name with button */
+ break;
+ }
+
+ uiItemFullR(col, ptr, prop, -1, 0, compact ? UI_ITEM_R_COMPACT : 0, name, ICON_NONE);
+ return_info &= ~UI_PROP_BUTS_NONE_ADDED;
+ }
+ RNA_STRUCT_END;
+
+ return return_info;
+}
+
+/* *** RNA collection search menu *** */
+
+typedef struct CollItemSearch {
+ struct CollItemSearch *next, *prev;
+ void *data;
+ char *name;
+ int index;
+ int iconid;
+} CollItemSearch;
+
+static int sort_search_items_list(const void *a, const void *b)
+{
+ const CollItemSearch *cis1 = a;
+ const CollItemSearch *cis2 = b;
- /* may meed to add more cases here.
- * don't override enum flag names */
+ if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
+ return 1;
+ else
+ return 0;
+}
+
+void ui_rna_collection_search_cb(const struct bContext *C, void *arg, const char *str, uiSearchItems *items)
+{
+ uiRNACollectionSearch *data = arg;
+ char *name;
+ int i = 0, iconid = 0, flag = RNA_property_flag(data->target_prop);
+ ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
+ CollItemSearch *cis;
+ const bool skip_filter = !(data->but_changed && *data->but_changed);
+
+ /* build a temporary list of relevant items first */
+ RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop)
+ {
+
+ if (flag & PROP_ID_SELF_CHECK)
+ if (itemptr.data == data->target_ptr.id.data)
+ continue;
- /* name is shown above, empty name for button below */
- name = (flag & PROP_ENUM_FLAG || is_boolean) ? NULL : "";
+ /* use filter */
+ if (RNA_property_type(data->target_prop) == PROP_POINTER) {
+ if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0)
+ continue;
+ }
+
+ iconid = 0;
+ if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
+ name = MEM_malloc_arrayN(MAX_ID_FULL_NAME, sizeof(*name), __func__);
+ BKE_id_full_name_ui_prefix_get(name, itemptr.data);
+ iconid = ui_id_icon_get(C, itemptr.data, false);
}
else {
- col = layout;
- name = NULL; /* no smart label alignment, show default name with button */
+ name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
}
- uiItemFullR(col, ptr, prop, -1, 0, 0, name, ICON_NONE);
- tot++;
+ if (name) {
+ if (skip_filter || BLI_strcasestr(name, str)) {
+ cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
+ cis->data = itemptr.data;
+ cis->name = name; /* Still ownership of that memory. */
+ cis->index = i;
+ cis->iconid = iconid;
+ BLI_addtail(items_list, cis);
+ }
+ else {
+ MEM_freeN(name);
+ }
+ }
+
+ i++;
+ }
+ RNA_PROP_END;
+
+ BLI_listbase_sort(items_list, sort_search_items_list);
+
+ /* add search items from temporary list */
+ for (cis = items_list->first; cis; cis = cis->next) {
+ if (UI_search_item_add(items, cis->name, cis->data, cis->iconid) == false) {
+ break;
+ }
}
- RNA_STRUCT_END;
- return tot;
+ for (cis = items_list->first; cis; cis = cis->next) {
+ MEM_freeN(cis->name);
+ }
+ BLI_freelistN(items_list);
+ MEM_freeN(items_list);
}
-/***************************** ID Utilities *******************************/
+/***************************** ID Utilities *******************************/
int UI_icon_from_id(ID *id)
{
Object *ob;
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index a655dea9215..2d906079e21 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -43,13 +43,9 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
#include "RNA_access.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
#include "BLF_api.h"
#include "UI_interface.h"
@@ -57,7 +53,12 @@
#include "interface_intern.h"
-#include "GPU_basic_shader.h"
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#ifdef WITH_INPUT_IME
# include "WM_types.h"
@@ -72,13 +73,19 @@ enum {
/* Show that holding the button opens a menu. */
UI_STATE_HOLD_ACTION = UI_BUT_UPDATE_DELAY,
UI_STATE_TEXT_INPUT = UI_BUT_UNDO,
+ UI_STATE_ACTIVE_LEFT = UI_BUT_VALUE_CLEAR,
+ UI_STATE_ACTIVE_RIGHT = UI_BUT_TEXTEDIT_UPDATE,
- UI_STATE_FLAGS_ALL = (UI_STATE_HOLD_ACTION | UI_STATE_TEXT_INPUT),
+ UI_STATE_FLAGS_ALL = (UI_STATE_HOLD_ACTION |
+ UI_STATE_TEXT_INPUT |
+ UI_STATE_ACTIVE_LEFT |
+ UI_STATE_ACTIVE_RIGHT),
};
/* Prevent accidental use. */
#define UI_BUT_UPDATE_DELAY ((void)0)
#define UI_BUT_UNDO ((void)0)
+
/* ************** widget base functions ************** */
/**
* - in: roundbox codes for corner types and radius
@@ -98,6 +105,8 @@ enum {
typedef struct uiWidgetTrias {
unsigned int tot;
+ int type;
+ float size, center[2];
float vec[16][2];
const unsigned int (*index)[3];
@@ -105,21 +114,24 @@ typedef struct uiWidgetTrias {
} uiWidgetTrias;
/* max as used by round_box__edges */
+/* Make sure to change widget_base_vert.glsl accordingly. */
#define WIDGET_CURVE_RESOLU 9
#define WIDGET_SIZE_MAX (WIDGET_CURVE_RESOLU * 4)
typedef struct uiWidgetBase {
-
+ /* TODO remove these completely */
int totvert, halfwayvert;
float outer_v[WIDGET_SIZE_MAX][2];
float inner_v[WIDGET_SIZE_MAX][2];
float inner_uv[WIDGET_SIZE_MAX][2];
- bool draw_inner, draw_outline, draw_emboss, draw_shadedir;
+ bool draw_inner, draw_outline, draw_emboss;
uiWidgetTrias tria1;
uiWidgetTrias tria2;
+ /* Widget shader parameters, must match the shader layout. */
+ uiWidgetBaseParameters uniform_params;
} uiWidgetBase;
/** uiWidgetType: for time being only for visual appearance,
@@ -150,13 +162,15 @@ static const float cornervec[WIDGET_CURVE_RESOLU][2] = {
{0.924, 0.617}, {0.98, 0.805}, {1.0, 1.0}
};
-#define WIDGET_AA_JITTER 8
-static const float jit[WIDGET_AA_JITTER][2] = {
+
+const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2] = {
{ 0.468813, -0.481430}, {-0.155755, -0.352820},
{ 0.219306, -0.238501}, {-0.393286, -0.110949},
{-0.024699, 0.013908}, { 0.343805, 0.147431},
{-0.272855, 0.269918}, { 0.095909, 0.388710}
};
+#define WIDGET_AA_JITTER UI_PIXEL_AA_JITTER
+#define jit ui_pixel_jitter
/* -------------------------------------------------------------------- */
/** \name Shape Preset Data
@@ -195,8 +209,8 @@ static const uint g_shape_preset_checkmark_face[4][3] = {
{3, 2, 4}, {3, 4, 5}, {1, 0, 3}, {0, 2, 3}
};
-#define OY -0.2
-#define SC 0.35
+#define OY (-0.2 / 2)
+#define SC (0.35 * 2)
static const float g_shape_preset_hold_action_vert[6][2] = {
{-0.5 + SC, 1.0 + OY}, {0.5, 1.0 + OY}, {0.5, 0.0 + OY + SC},
};
@@ -206,53 +220,364 @@ static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}}
/** \} */
+/* **************** Batch creations ****************** */
+/**
+ * In order to speed up UI drawing we create some batches that are then
+ * modified by specialized shaders to draw certain elements really fast.
+ * TODO: find a better place. Maybe it's own file?
+ **/
+
+/* offset in triavec[] in shader per type */
+static const int tria_ofs[ROUNDBOX_TRIA_MAX] = {
+ [ROUNDBOX_TRIA_NONE] = 0,
+ [ROUNDBOX_TRIA_ARROWS] = 0,
+ [ROUNDBOX_TRIA_SCROLL] = 12,
+ [ROUNDBOX_TRIA_MENU] = 28,
+ [ROUNDBOX_TRIA_CHECK] = 34,
+ [ROUNDBOX_TRIA_HOLD_ACTION_ARROW] = 40,
+};
+static const int tria_vcount[ROUNDBOX_TRIA_MAX] = {
+ [ROUNDBOX_TRIA_NONE] = 0,
+ [ROUNDBOX_TRIA_ARROWS] = 6,
+ [ROUNDBOX_TRIA_SCROLL] = 16,
+ [ROUNDBOX_TRIA_MENU] = 6,
+ [ROUNDBOX_TRIA_CHECK] = 6,
+ [ROUNDBOX_TRIA_HOLD_ACTION_ARROW] = 3,
+};
+
+static struct {
+ GPUBatch *roundbox_widget[ROUNDBOX_TRIA_MAX];
+
+ GPUBatch *roundbox_simple;
+ GPUBatch *roundbox_simple_aa;
+ GPUBatch *roundbox_simple_outline;
+ GPUBatch *roundbox_shadow;
+
+ GPUVertFormat format;
+ uint vflag_id;
+} g_ui_batch_cache = {{0}};
+
+static GPUVertFormat *vflag_format(void)
+{
+ if (g_ui_batch_cache.format.attr_len == 0) {
+ GPUVertFormat *format = &g_ui_batch_cache.format;
+ g_ui_batch_cache.vflag_id = GPU_vertformat_attr_add(format, "vflag", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ return &g_ui_batch_cache.format;
+}
+
+#define INNER 0
+#define OUTLINE 1
+#define EMBOSS 2
+#define NO_AA WIDGET_AA_JITTER
+
+static void set_roundbox_vertex_data(
+ GPUVertBufRaw *vflag_step, uint32_t d)
+{
+ uint32_t *data = GPU_vertbuf_raw_step(vflag_step);
+ *data = d;
+}
+
+static uint32_t set_roundbox_vertex(
+ GPUVertBufRaw *vflag_step,
+ int corner_id, int corner_v, int jit_v, bool inner, bool emboss, int color)
+{
+ uint32_t *data = GPU_vertbuf_raw_step(vflag_step);
+ *data = corner_id;
+ *data |= corner_v << 2;
+ *data |= jit_v << 6;
+ *data |= color << 12;
+ *data |= (inner) ? (1 << 10) : 0; /* is inner vert */
+ *data |= (emboss) ? (1 << 11) : 0; /* is emboss vert */
+ return *data;
+}
+
+static uint32_t set_tria_vertex(
+ GPUVertBufRaw *vflag_step,
+ int tria_type, int tria_v, int tria_id, int jit_v)
+{
+ uint32_t *data = GPU_vertbuf_raw_step(vflag_step);
+ if (ELEM(tria_type, ROUNDBOX_TRIA_ARROWS)) {
+ tria_v += tria_id * tria_vcount[ROUNDBOX_TRIA_ARROWS];
+ }
+ *data = tria_ofs[tria_type] + tria_v;
+ *data |= jit_v << 6;
+ *data |= (tria_id == 0) ? (1 << 10) : 0; /* is first tria */
+ *data |= 1 << 14; /* is tria vert */
+ return *data;
+}
+
+static void roundbox_batch_add_tria(GPUVertBufRaw *vflag_step, int tria, uint32_t last_data)
+{
+ const int tria_num = ELEM(tria, ROUNDBOX_TRIA_CHECK, ROUNDBOX_TRIA_HOLD_ACTION_ARROW, ROUNDBOX_TRIA_MENU) ? 1 : 2;
+ /* for each tria */
+ for (int t = 0; t < tria_num; ++t) {
+ for (int j = 0; j < WIDGET_AA_JITTER; j++) {
+ /* restart */
+ set_roundbox_vertex_data(vflag_step, last_data);
+ set_tria_vertex(vflag_step, tria, 0, t, j);
+ for (int v = 0; v < tria_vcount[tria]; v++) {
+ last_data = set_tria_vertex(vflag_step, tria, v, t, j);
+ }
+ }
+ }
+}
+
+GPUBatch *ui_batch_roundbox_widget_get(int tria)
+{
+ if (g_ui_batch_cache.roundbox_widget[tria] == NULL) {
+ uint32_t last_data;
+ GPUVertBufRaw vflag_step;
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format());
+ int vcount = WIDGET_SIZE_MAX; /* inner */
+ vcount += 2; /* restart */
+ vcount += ((WIDGET_SIZE_MAX + 1) * 2) * WIDGET_AA_JITTER; /* outline (edges) */
+ vcount += 2; /* restart */
+ vcount += ((WIDGET_CURVE_RESOLU * 2) * 2) * WIDGET_AA_JITTER; /* emboss */
+ if (tria) {
+ vcount += (tria_vcount[tria] + 2) * WIDGET_AA_JITTER; /* tria1 */
+ if (!ELEM(tria, ROUNDBOX_TRIA_CHECK, ROUNDBOX_TRIA_HOLD_ACTION_ARROW, ROUNDBOX_TRIA_MENU)) {
+ vcount += (tria_vcount[tria] + 2) * WIDGET_AA_JITTER; /* tria2 */
+ }
+ }
+ GPU_vertbuf_data_alloc(vbo, vcount);
+ GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
+ /* Inner */
+ for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
+ for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU -1; a2 >= 0; a1++, a2--) {
+ last_data = set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER);
+ last_data = set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER);
+ }
+ }
+ /* restart */
+ set_roundbox_vertex_data(&vflag_step, last_data);
+ set_roundbox_vertex(&vflag_step, 0, 0, 0, true, false, OUTLINE);
+ /* Outlines */
+ for (int j = 0; j < WIDGET_AA_JITTER; j++) {
+ for (int c = 0; c < 4; c++) {
+ for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
+ set_roundbox_vertex(&vflag_step, c, a, j, true, false, OUTLINE);
+ set_roundbox_vertex(&vflag_step, c, a, j, false, false, OUTLINE);
+ }
+ }
+ /* Close the loop. */
+ set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, OUTLINE);
+ last_data = set_roundbox_vertex(&vflag_step, 0, 0, j, false, false, OUTLINE);
+ }
+ /* restart */
+ set_roundbox_vertex_data(&vflag_step, last_data);
+ set_roundbox_vertex(&vflag_step, 0, 0, 0, false, false, EMBOSS);
+ /* Emboss */
+ bool rev = false; /* go back and forth : avoid degenerate triangle (but beware of backface cull) */
+ for (int j = 0; j < WIDGET_AA_JITTER; j++, rev = !rev) {
+ for (int c = (rev) ? 1 : 0; (rev) ? c >= 0 : c < 2; (rev) ? c-- : c++) {
+ int sta = (rev) ? WIDGET_CURVE_RESOLU - 1 : 0;
+ int end = WIDGET_CURVE_RESOLU;
+ for (int a = sta; (rev) ? a >= 0 : a < end; (rev) ? a-- : a++) {
+ set_roundbox_vertex(&vflag_step, c, a, j, false, false, EMBOSS);
+ last_data = set_roundbox_vertex(&vflag_step, c, a, j, false, true, EMBOSS);
+ }
+ }
+ }
+ if (tria) {
+ roundbox_batch_add_tria(&vflag_step, tria, last_data);
+ }
+ g_ui_batch_cache.roundbox_widget[tria] = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ gpu_batch_presets_register(g_ui_batch_cache.roundbox_widget[tria]);
+ }
+ return g_ui_batch_cache.roundbox_widget[tria];
+}
+
+GPUBatch *ui_batch_roundbox_get(bool filled, bool antialiased)
+{
+ GPUBatch **batch = NULL;
+
+ if (filled) {
+ if (antialiased)
+ batch = &g_ui_batch_cache.roundbox_simple_aa;
+ else
+ batch = &g_ui_batch_cache.roundbox_simple;
+ }
+ else {
+ if (antialiased)
+ BLI_assert(0); /* Use GL_LINE_SMOOTH instead!!: */
+ else
+ batch = &g_ui_batch_cache.roundbox_simple_outline;
+ }
+
+ if (*batch == NULL) {
+ uint32_t last_data;
+ GPUVertBufRaw vflag_step;
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format());
+ int vcount = WIDGET_SIZE_MAX;
+ vcount += (filled) ? 2 : 0;
+ vcount *= (antialiased) ? WIDGET_AA_JITTER : 1;
+ GPU_vertbuf_data_alloc(vbo, vcount);
+ GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
+
+ if (filled) {
+ for (int j = 0; j < WIDGET_AA_JITTER; j++) {
+ if (!antialiased) {
+ j = NO_AA;
+ }
+ /* restart */
+ set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, INNER);
+ for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
+ for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU -1; a2 >= 0; a1++, a2--) {
+ last_data = set_roundbox_vertex(&vflag_step, c1, a1, j, true, false, INNER);
+ last_data = set_roundbox_vertex(&vflag_step, c2, a2, j, true, false, INNER);
+ }
+ }
+ /* restart */
+ set_roundbox_vertex_data(&vflag_step, last_data);
+ if (!antialiased) {
+ break;
+ }
+ }
+ *batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ else {
+ for (int j = 0; j < WIDGET_AA_JITTER; j++) {
+ if (!antialiased) {
+ j = NO_AA;
+ }
+ for (int c = 0; c < 4; c++) {
+ for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
+ set_roundbox_vertex(&vflag_step, c, a, j, true, false, INNER);
+ }
+ }
+ if (!antialiased) {
+ break;
+ }
+ }
+ *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+
+ gpu_batch_presets_register(*batch);
+ }
+ return *batch;
+}
+
+GPUBatch *ui_batch_roundbox_shadow_get(void)
+{
+ if (g_ui_batch_cache.roundbox_shadow == NULL) {
+ uint32_t last_data;
+ GPUVertBufRaw vflag_step;
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format());
+ int vcount = (WIDGET_SIZE_MAX + 1) * 2 + 2 + WIDGET_SIZE_MAX;
+ GPU_vertbuf_data_alloc(vbo, vcount);
+ GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
+
+ for (int c = 0; c < 4; c++) {
+ for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
+ set_roundbox_vertex(&vflag_step, c, a, NO_AA, true, false, INNER);
+ set_roundbox_vertex(&vflag_step, c, a, NO_AA, false, false, INNER);
+ }
+ }
+ /* close loop */
+ last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
+ last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, false, false, INNER);
+ /* restart */
+ set_roundbox_vertex_data(&vflag_step, last_data);
+ set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
+ /* filled */
+ for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
+ for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU -1; a2 >= 0; a1++, a2--) {
+ set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER);
+ set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER);
+ }
+ }
+ g_ui_batch_cache.roundbox_shadow = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ gpu_batch_presets_register(g_ui_batch_cache.roundbox_shadow);
+ }
+ return g_ui_batch_cache.roundbox_shadow;
+}
+
+#undef INNER
+#undef OUTLINE
+#undef EMBOSS
+#undef NO_AA
+
/* ************************************************* */
-void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3)
+void UI_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3,
+ const float color[4])
{
float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}};
- float color[4];
- int j;
+ float draw_color[4];
+
+ copy_v4_v4(draw_color, color);
+ /* Note: This won't give back the original color. */
+ draw_color[3] *= 1.0f / WIDGET_AA_JITTER;
- glEnable(GL_BLEND);
- glGetFloatv(GL_CURRENT_COLOR, color);
- color[3] *= 0.125f;
- glColor4fv(color);
+ GPU_blend(true);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, tri_arr);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4fv(draw_color);
+ immBegin(GPU_PRIM_TRIS, 3 * WIDGET_AA_JITTER);
/* for each AA step */
- for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslate2fv(jit[j]);
- glDrawArrays(GL_TRIANGLES, 0, 3);
- glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
+ for (int j = 0; j < WIDGET_AA_JITTER; j++) {
+ immVertex2f(pos, tri_arr[0][0] + jit[j][0], tri_arr[0][1] + jit[j][1]);
+ immVertex2f(pos, tri_arr[1][0] + jit[j][0], tri_arr[1][1] + jit[j][1]);
+ immVertex2f(pos, tri_arr[2][0] + jit[j][0], tri_arr[2][1] + jit[j][1]);
}
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisable(GL_BLEND);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_blend(false);
}
-void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha)
+/* triangle 'icon' inside rect */
+void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
{
- float color[4];
- int j;
-
- glEnable(GL_BLEND);
- glGetFloatv(GL_CURRENT_COLOR, color);
- if (use_alpha) {
- color[3] = 0.5f;
+ if (dir == 'h') {
+ float half = 0.5f * BLI_rctf_size_y(rect);
+ UI_draw_anti_tria(rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, color);
}
- color[3] *= 0.125f;
- glColor4fv(color);
+ else {
+ float half = 0.5f * BLI_rctf_size_x(rect);
+ UI_draw_anti_tria(rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color);
+ }
+}
+
+
+void UI_draw_anti_fan(float tri_array[][2], unsigned int length, const float color[4])
+{
+ float draw_color[4];
+
+ copy_v4_v4(draw_color, color);
+ draw_color[3] *= 2.0f / WIDGET_AA_JITTER;
+
+ GPU_blend(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4fv(draw_color);
+
+ /* for each AA step */
+ for (int j = 0; j < WIDGET_AA_JITTER; j++) {
+ immBegin(GPU_PRIM_TRI_FAN, length);
+ immVertex2f(pos, tri_array[0][0], tri_array[0][1]);
+ immVertex2f(pos, tri_array[1][0], tri_array[1][1]);
+
+ /* We jitter only the middle of the fan, the extremes are pinned. */
+ for (int i = 2; i < length - 1; i++) {
+ immVertex2f(pos, tri_array[i][0] + jit[j][0], tri_array[i][1] + jit[j][1]);
+ }
- for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslate2fv(jit[j]);
- UI_draw_roundbox_gl_mode(mode, minx, miny, maxx, maxy, rad);
- glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
+ immVertex2f(pos, tri_array[length - 1][0], tri_array[length - 1][1]);
+ immEnd();
}
- glDisable(GL_BLEND);
+ immUnbindProgram();
+
+ GPU_blend(false);
}
static void widget_init(uiWidgetBase *wtb)
@@ -260,11 +585,16 @@ static void widget_init(uiWidgetBase *wtb)
wtb->totvert = wtb->halfwayvert = 0;
wtb->tria1.tot = 0;
wtb->tria2.tot = 0;
+ wtb->tria1.type = ROUNDBOX_TRIA_NONE;
+ wtb->tria1.size = 0;
+ wtb->tria2.size = 0;
wtb->draw_inner = true;
wtb->draw_outline = true;
wtb->draw_emboss = true;
- wtb->draw_shadedir = true;
+
+ wtb->uniform_params.shade_dir = 1.0f;
+ wtb->uniform_params.alpha_discard = 1.0f;
}
/* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
@@ -375,6 +705,17 @@ static void round_box__edges(uiWidgetBase *wt, int roundboxalign, const rcti *re
if (2.0f * (radi + 1.0f) > minsize)
radi = 0.5f * minsize - U.pixelsize;
+ wt->uniform_params.rad = rad;
+ wt->uniform_params.radi = radi;
+ wt->uniform_params.facxi = facxi;
+ wt->uniform_params.facyi = facyi;
+ wt->uniform_params.round_corners[0] = (roundboxalign & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f;
+ wt->uniform_params.round_corners[1] = (roundboxalign & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f;
+ wt->uniform_params.round_corners[2] = (roundboxalign & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f;
+ wt->uniform_params.round_corners[3] = (roundboxalign & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f;
+ BLI_rctf_rcti_copy(&wt->uniform_params.rect, rect);
+ BLI_rctf_init(&wt->uniform_params.recti, minxi, maxxi, minyi, maxyi);
+
/* mult */
for (a = 0; a < WIDGET_CURVE_RESOLU; a++) {
veci[a][0] = radi * cornervec[a][0];
@@ -519,23 +860,30 @@ static void shape_preset_init_trias_ex(
float centx, centy, sizex, sizey, minsize;
int a, i1 = 0, i2 = 1;
- minsize = min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
+ if (where == 'r' || where == 'l') {
+ minsize = BLI_rcti_size_y(rect);
+ }
+ else {
+ minsize = BLI_rcti_size_x(rect);
+ }
/* center position and size */
centx = (float)rect->xmin + 0.4f * minsize;
centy = (float)rect->ymin + 0.5f * minsize;
- sizex = sizey = -0.5f * triasize * minsize;
+ tria->size = sizex = sizey = -0.5f * triasize * minsize;
if (where == 'r') {
centx = (float)rect->xmax - 0.4f * minsize;
sizex = -sizex;
}
else if (where == 't') {
+ centx = (float)rect->xmin + 0.5f * minsize;
centy = (float)rect->ymax - 0.5f * minsize;
sizey = -sizey;
i2 = 0; i1 = 1;
}
else if (where == 'b') {
+ centx = (float)rect->xmin + 0.5f * minsize;
sizex = -sizex;
i2 = 0; i1 = 1;
}
@@ -545,12 +893,16 @@ static void shape_preset_init_trias_ex(
tria->vec[a][1] = sizey * verts[a][i2] + centy;
}
+ tria->center[0] = centx;
+ tria->center[1] = centy;
+
tria->tot = tris_tot;
tria->index = tris;
}
static void shape_preset_init_number_arrows(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
{
+ tria->type = ROUNDBOX_TRIA_ARROWS;
shape_preset_init_trias_ex(
tria, rect, triasize, where,
g_shape_preset_number_arrow_vert, ARRAY_SIZE(g_shape_preset_number_arrow_vert),
@@ -559,6 +911,12 @@ static void shape_preset_init_number_arrows(uiWidgetTrias *tria, const rcti *rec
static void shape_preset_init_hold_action(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
{
+ tria->type = ROUNDBOX_TRIA_HOLD_ACTION_ARROW;
+ /* With the current changes to use batches for widget drawing, the code
+ * below is doing almost nothing effectively. 'where' doesn't work either,
+ * shader is currently hardcoded to work for the button triangle pointing
+ * at the lower right. The same limitation applies to other trias as well.
+ * XXX Should be addressed. */
shape_preset_init_trias_ex(
tria, rect, triasize, where,
g_shape_preset_hold_action_vert, ARRAY_SIZE(g_shape_preset_hold_action_vert),
@@ -567,29 +925,37 @@ static void shape_preset_init_hold_action(uiWidgetTrias *tria, const rcti *rect,
static void shape_preset_init_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
{
+ tria->type = ROUNDBOX_TRIA_SCROLL;
shape_preset_init_trias_ex(
tria, rect, triasize, where,
g_shape_preset_scroll_circle_vert, ARRAY_SIZE(g_shape_preset_scroll_circle_vert),
g_shape_preset_scroll_circle_face, ARRAY_SIZE(g_shape_preset_scroll_circle_face));
}
-static void shape_preset_draw_trias(uiWidgetTrias *tria)
+static void widget_draw_vertex_buffer(unsigned int pos, unsigned int col, int mode,
+ const float quads_pos[WIDGET_SIZE_MAX][2],
+ const unsigned char quads_col[WIDGET_SIZE_MAX][4],
+ unsigned int totvert)
{
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, tria->vec);
- glDrawElements(GL_TRIANGLES, tria->tot * 3, GL_UNSIGNED_INT, tria->index);
- glDisableClientState(GL_VERTEX_ARRAY);
+ immBegin(mode, totvert);
+ for (int i = 0; i < totvert; ++i) {
+ if (quads_col)
+ immAttr4ubv(col, quads_col[i]);
+ immVertex2fv(pos, quads_pos[i]);
+ }
+ immEnd();
}
static void shape_preset_trias_from_rect_menu(uiWidgetTrias *tria, const rcti *rect)
{
float centx, centy, size;
int a;
+ tria->type = ROUNDBOX_TRIA_MENU;
/* center position and size */
- centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect);
- centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect);
- size = 0.4f * BLI_rcti_size_y(rect);
+ tria->center[0] = centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect);
+ tria->center[1] = centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect);
+ tria->size = size = 0.4f * BLI_rcti_size_y(rect);
for (a = 0; a < 6; a++) {
tria->vec[a][0] = size * g_shape_preset_menu_arrow_vert[a][0] + centx;
@@ -604,11 +970,12 @@ static void shape_preset_trias_from_rect_checkmark(uiWidgetTrias *tria, const rc
{
float centx, centy, size;
int a;
+ tria->type = ROUNDBOX_TRIA_CHECK;
/* center position and size */
- centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
- centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
- size = 0.5f * BLI_rcti_size_y(rect);
+ tria->center[0] = centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
+ tria->center[1] = centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
+ tria->size = size = 0.5f * BLI_rcti_size_y(rect);
for (a = 0; a < 6; a++) {
tria->vec[a][0] = size * g_shape_preset_checkmark_vert[a][0] + centx;
@@ -658,192 +1025,220 @@ static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert,
copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]);
}
-static void widget_verts_to_triangle_strip_open(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2][2])
-{
- int a;
- for (a = 0; a < totvert; a++) {
- triangle_strip[a * 2][0] = wtb->outer_v[a][0];
- triangle_strip[a * 2][1] = wtb->outer_v[a][1];
- triangle_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
- triangle_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
- }
-}
-
-static void widgetbase_outline(uiWidgetBase *wtb)
+static void widgetbase_outline(uiWidgetBase *wtb, unsigned int pos)
{
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
- glDisableClientState(GL_VERTEX_ARRAY);
+ widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2);
}
-static void widgetbase_draw_ex(
- uiWidgetBase *wtb, uiWidgetColors *wcol,
- const bool show_alpha_checkers)
+static void widgetbase_set_uniform_alpha_discard(
+ uiWidgetBase *wtb,
+ const bool alpha_check,
+ const float discard_factor)
{
- int j, a;
+ if (alpha_check) {
+ wtb->uniform_params.alpha_discard = -discard_factor;
+ }
+ else {
+ wtb->uniform_params.alpha_discard = discard_factor;
+ }
+}
- glEnable(GL_BLEND);
+static void widgetbase_set_uniform_alpha_check(
+ uiWidgetBase *wtb,
+ const bool alpha_check)
+{
+ const float discard_factor = fabs(wtb->uniform_params.alpha_discard);
+ widgetbase_set_uniform_alpha_discard(wtb, alpha_check, discard_factor);
+}
- /* backdrop non AA */
- if (wtb->draw_inner) {
- BLI_assert(wtb->totvert != 0);
- if (wcol->shaded == 0) {
- if (show_alpha_checkers) {
- float inner_v_half[WIDGET_SIZE_MAX][2];
- float x_mid = 0.0f; /* used for dumb clamping of values */
+static void widgetbase_set_uniform_discard_factor(
+ uiWidgetBase *wtb,
+ const float discard_factor)
+{
+ bool alpha_check = wtb->uniform_params.alpha_discard < 0.0f;
+ widgetbase_set_uniform_alpha_discard(wtb, alpha_check, discard_factor);
+}
- /* dark checkers */
- glColor4ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, 255);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
+static void widgetbase_set_uniform_colors_ubv(
+ uiWidgetBase *wtb,
+ const unsigned char *col1, const unsigned char *col2,
+ const unsigned char *outline,
+ const unsigned char *emboss,
+ const unsigned char *tria,
+ const bool alpha_check)
+{
+ widgetbase_set_uniform_alpha_check(wtb, alpha_check);
+ rgba_float_args_set_ch(wtb->uniform_params.color_inner1, col1[0], col1[1], col1[2], col1[3]);
+ rgba_float_args_set_ch(wtb->uniform_params.color_inner2, col2[0], col2[1], col2[2], col2[3]);
+ rgba_float_args_set_ch(wtb->uniform_params.color_outline, outline[0], outline[1], outline[2], outline[3]);
+ rgba_float_args_set_ch(wtb->uniform_params.color_emboss, emboss[0], emboss[1], emboss[2], emboss[3]);
+ rgba_float_args_set_ch(wtb->uniform_params.color_tria, tria[0], tria[1], tria[2], tria[3]);
+}
- /* light checkers */
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX);
+/* keep in sync with shader */
+#define MAX_WIDGET_BASE_BATCH 6
+#define MAX_WIDGET_PARAMETERS 11
- glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
+static struct {
+ GPUBatch *batch; /* Batch type */
+ uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH];
+ int count;
+ bool enabled;
+} g_widget_base_batch = {0};
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+void UI_widgetbase_draw_cache_flush(void)
+{
+ float checker_params[3] = {UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
- /* alpha fill */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (g_widget_base_batch.count == 0)
+ return;
- glColor4ubv((unsigned char *)wcol->inner);
+ GPUBatch *batch = g_widget_base_batch.batch;
+ if (g_widget_base_batch.count == 1) {
+ /* draw single */
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
+ GPU_batch_uniform_4fv_array(batch, "parameters", MAX_WIDGET_PARAMETERS, (float *)g_widget_base_batch.params);
+ GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
+ GPU_batch_draw(batch);
+ }
+ else {
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE_INST);
+ GPU_batch_uniform_4fv_array(batch, "parameters", MAX_WIDGET_PARAMETERS * MAX_WIDGET_BASE_BATCH,
+ (float *)g_widget_base_batch.params);
+ GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
+ GPU_matrix_bind(batch->interface);
+ GPU_batch_draw_range_ex(batch, 0, g_widget_base_batch.count, true);
+ GPU_batch_program_use_end(batch);
+ }
+ g_widget_base_batch.count = 0;
+}
- for (a = 0; a < wtb->totvert; a++) {
- x_mid += wtb->inner_v[a][0];
- }
- x_mid /= wtb->totvert;
+void UI_widgetbase_draw_cache_begin(void)
+{
+ BLI_assert(g_widget_base_batch.enabled == false);
+ g_widget_base_batch.enabled = true;
+}
- glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
+void UI_widgetbase_draw_cache_end(void)
+{
+ BLI_assert(g_widget_base_batch.enabled == true);
+ g_widget_base_batch.enabled = false;
- /* 1/2 solid color */
- glColor4ub(wcol->inner[0], wcol->inner[1], wcol->inner[2], 255);
+ GPU_blend(true);
- for (a = 0; a < wtb->totvert; a++) {
- inner_v_half[a][0] = MIN2(wtb->inner_v[a][0], x_mid);
- inner_v_half[a][1] = wtb->inner_v[a][1];
- }
+ UI_widgetbase_draw_cache_flush();
- glVertexPointer(2, GL_FLOAT, 0, inner_v_half);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
- glDisableClientState(GL_VERTEX_ARRAY);
- }
- else {
- /* simple fill */
- glColor4ubv((unsigned char *)wcol->inner);
+ GPU_blend(false);
+}
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
- glDisableClientState(GL_VERTEX_ARRAY);
- }
+static void draw_widgetbase_batch(GPUBatch *batch, uiWidgetBase *wtb)
+{
+ wtb->uniform_params.tria1_size = wtb->tria1.size;
+ wtb->uniform_params.tria2_size = wtb->tria2.size;
+ copy_v2_v2(wtb->uniform_params.tria1_center, wtb->tria1.center);
+ copy_v2_v2(wtb->uniform_params.tria2_center, wtb->tria2.center);
+
+ if (g_widget_base_batch.enabled) {
+ if (g_widget_base_batch.batch == NULL) {
+ g_widget_base_batch.batch = ui_batch_roundbox_widget_get(ROUNDBOX_TRIA_ARROWS);
}
- else {
- char col1[4], col2[4];
- unsigned char col_array[WIDGET_SIZE_MAX * 4];
- unsigned char *col_pt = col_array;
-
- shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
- for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
- round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]);
- }
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, col_array);
- glDrawArrays(GL_POLYGON, 0, wtb->totvert);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
+ /* draw multi */
+ if (batch != g_ui_batch_cache.roundbox_widget[ROUNDBOX_TRIA_NONE] &&
+ batch != g_widget_base_batch.batch)
+ {
+ /* issue previous calls before changing batch type. */
+ UI_widgetbase_draw_cache_flush();
+ g_widget_base_batch.batch = batch;
}
- }
- /* for each AA step */
- if (wtb->draw_outline) {
- BLI_assert(wtb->totvert != 0);
- float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
- float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
-
- const unsigned char tcol[4] = {
- wcol->outline[0],
- wcol->outline[1],
- wcol->outline[2],
- wcol->outline[3] / WIDGET_AA_JITTER,
- };
- unsigned char emboss[4];
+ /* No need to change batch if tria is not visible. Just scale it to 0. */
+ if (batch == g_ui_batch_cache.roundbox_widget[ROUNDBOX_TRIA_NONE]) {
+ wtb->uniform_params.tria1_size = wtb->uniform_params.tria2_size = 0;
+ }
- widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
+ g_widget_base_batch.params[g_widget_base_batch.count] = wtb->uniform_params;
+ g_widget_base_batch.count++;
- if (wtb->draw_emboss) {
- widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss);
- UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
+ if (g_widget_base_batch.count == MAX_WIDGET_BASE_BATCH) {
+ UI_widgetbase_draw_cache_flush();
}
+ }
+ else {
+ float checker_params[3] = {UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
+ /* draw single */
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
+ GPU_batch_uniform_4fv_array(batch, "parameters", MAX_WIDGET_PARAMETERS, (float *)&wtb->uniform_params);
+ GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
+ GPU_batch_draw(batch);
+ }
+}
- glEnableClientState(GL_VERTEX_ARRAY);
-
- for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslate2fv(jit[j]);
+static void widgetbase_draw_ex(
+ uiWidgetBase *wtb, const uiWidgetColors *wcol,
+ bool show_alpha_checkers)
+{
+ unsigned char inner_col1[4] = {0};
+ unsigned char inner_col2[4] = {0};
+ unsigned char emboss_col[4] = {0};
+ unsigned char outline_col[4] = {0};
+ unsigned char tria_col[4] = {0};
+ /* For color widget. */
+ if (wcol->shaded != 0) {
+ show_alpha_checkers = false;
+ }
- /* outline */
- glColor4ubv(tcol);
+ GPU_blend(true);
- glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
+ /* backdrop non AA */
+ if (wtb->draw_inner) {
+ if (wcol->shaded == 0) {
+ /* simple fill */
+ inner_col1[0] = inner_col2[0] = (unsigned char)wcol->inner[0];
+ inner_col1[1] = inner_col2[1] = (unsigned char)wcol->inner[1];
+ inner_col1[2] = inner_col2[2] = (unsigned char)wcol->inner[2];
+ inner_col1[3] = inner_col2[3] = (unsigned char)wcol->inner[3];
+ }
+ else {
+ /* gradient fill */
+ shadecolors4((char *)inner_col1, (char *)inner_col2, wcol->inner, wcol->shadetop, wcol->shadedown);
+ }
+ }
- /* emboss bottom shadow */
- if (wtb->draw_emboss) {
- if (emboss[3]) {
- glColor4ubv(emboss);
- glVertexPointer(2, GL_FLOAT, 0, triangle_strip_emboss);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->halfwayvert * 2);
- }
- }
+ if (wtb->draw_outline) {
+ outline_col[0] = wcol->outline[0];
+ outline_col[1] = wcol->outline[1];
+ outline_col[2] = wcol->outline[2];
+ outline_col[3] = wcol->outline[3] / WIDGET_AA_JITTER;
- glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
+ /* emboss bottom shadow */
+ if (wtb->draw_emboss) {
+ UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col);
}
+ }
- glDisableClientState(GL_VERTEX_ARRAY);
+ if (wtb->tria1.type != ROUNDBOX_TRIA_NONE) {
+ tria_col[0] = wcol->item[0];
+ tria_col[1] = wcol->item[1];
+ tria_col[2] = wcol->item[2];
+ tria_col[3] = (unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER);
}
- /* decoration */
- if (wtb->tria1.tot || wtb->tria2.tot) {
- const unsigned char tcol[4] = {
- wcol->item[0],
- wcol->item[1],
- wcol->item[2],
- (unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER),
- };
- glColor4ubv(tcol);
-
- /* for each AA step */
- for (j = 0; j < WIDGET_AA_JITTER; j++) {
- glTranslate2fv(jit[j]);
-
- if (wtb->tria1.tot) {
- shape_preset_draw_trias(&wtb->tria1);
- }
- if (wtb->tria2.tot) {
- shape_preset_draw_trias(&wtb->tria2);
- }
+ /* Draw everything in one drawcall */
+ if (inner_col1[3] || inner_col2[3] || outline_col[3] || emboss_col[3] || tria_col[3] || show_alpha_checkers) {
+ widgetbase_set_uniform_colors_ubv(wtb, inner_col1, inner_col2, outline_col, emboss_col, tria_col, show_alpha_checkers);
- glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
- }
+ GPUBatch *roundbox_batch = ui_batch_roundbox_widget_get(wtb->tria1.type);
+ draw_widgetbase_batch(roundbox_batch, wtb);
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
-static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
+static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
{
widgetbase_draw_ex(wtb, wcol, false);
}
@@ -882,17 +1277,17 @@ static int ui_but_draw_menu_icon(const uiBut *but)
/* icons have been standardized... and this call draws in untransformed coordinates */
-static void widget_draw_icon_ex(
- const uiBut *but, BIFIconID icon, float alpha, const rcti *rect, const bool show_menu_icon,
- const int icon_size)
+static void widget_draw_icon(
+ const uiBut *but, BIFIconID icon, float alpha,
+ const rcti *rect, const char mono_color[4])
{
float xs = 0.0f, ys = 0.0f;
float aspect, height;
if (but->flag & UI_BUT_ICON_PREVIEW) {
- glEnable(GL_BLEND);
+ GPU_blend(true);
widget_draw_preview(icon, alpha, rect);
- glDisable(GL_BLEND);
+ GPU_blend(false);
return;
}
@@ -900,13 +1295,13 @@ static void widget_draw_icon_ex(
if (icon == ICON_BLANK1 && (but->flag & UI_BUT_ICON_SUBMENU) == 0) return;
aspect = but->block->aspect / UI_DPI_FAC;
- height = icon_size / aspect;
+ height = ICON_DEFAULT_HEIGHT / aspect;
/* calculate blend color */
if (ELEM(but->type, UI_BTYPE_TOGGLE, UI_BTYPE_ROW, UI_BTYPE_TOGGLE_N, UI_BTYPE_LISTROW)) {
if (but->flag & UI_SELECT) {}
else if (but->flag & UI_ACTIVE) {}
- else alpha = 0.5f;
+ else alpha = 0.75f;
}
else if ((but->type == UI_BTYPE_LABEL)) {
/* extra feature allows more alpha blending */
@@ -920,14 +1315,14 @@ static void widget_draw_icon_ex(
}
}
- glEnable(GL_BLEND);
+ GPU_blend(true);
if (icon && icon != ICON_BLANK1) {
float ofs = 1.0f / aspect;
if (but->drawflag & UI_BUT_ICON_LEFT) {
/* special case - icon_only pie buttons */
- if (ui_block_is_pie_menu(but->block) && but->type != UI_BTYPE_MENU && but->str && but->str[0] == '\0')
+ if (ui_block_is_pie_menu(but->block) && !ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && but->str && but->str[0] == '\0')
xs = rect->xmin + 2.0f * ofs;
else if (but->dt == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL)
xs = rect->xmin + 2.0f * ofs;
@@ -948,26 +1343,40 @@ static void widget_draw_icon_ex(
/* to indicate draggable */
if (but->dragpoin && (but->flag & UI_ACTIVE)) {
float rgb[3] = {1.25f, 1.25f, 1.25f};
- UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb);
+ UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb, mono_color);
+ }
+ else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) || !UI_but_is_tool(but)) {
+ UI_icon_draw_aspect(xs, ys, icon, aspect, alpha, mono_color);
+ }
+ else {
+ const bTheme *btheme = UI_GetTheme();
+ UI_icon_draw_desaturate(xs, ys, icon, aspect, alpha, 1.0 - btheme->tui.icon_saturation, mono_color);
}
- else
- UI_icon_draw_aspect(xs, ys, icon, aspect, alpha);
- }
-
- if (show_menu_icon) {
- xs = rect->xmax - UI_DPI_ICON_SIZE - aspect;
- ys = (rect->ymin + rect->ymax - height) / 2.0f;
-
- UI_icon_draw_aspect(xs, ys, ICON_RIGHTARROW_THIN, aspect, alpha);
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
-static void widget_draw_icon(
- const uiBut *but, BIFIconID icon, float alpha, const rcti *rect, const bool show_menu_icon)
+static void widget_draw_submenu_tria(const uiBut *but, const rcti *rect, const uiWidgetColors *wcol)
{
- widget_draw_icon_ex(but, icon, alpha, rect, show_menu_icon, ICON_DEFAULT_HEIGHT);
+ const float aspect = but->block->aspect / UI_DPI_FAC;
+ const int tria_height = (int)(ICON_DEFAULT_HEIGHT / aspect);
+ const int tria_width = (int)(ICON_DEFAULT_WIDTH / aspect) - 2 * U.pixelsize;
+ const int xs = rect->xmax - tria_width;
+ const int ys = (rect->ymin + rect->ymax - tria_height) / 2.0f;
+ float col[4];
+ rctf tria_rect;
+
+ rgba_uchar_to_float(col, (const uchar *)wcol->text);
+ col[3] *= 0.8f;
+
+ BLI_rctf_init(&tria_rect, xs, xs + tria_width, ys, ys + tria_height);
+ BLI_rctf_scale(&tria_rect, 0.4f);
+
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
+ ui_draw_anti_tria_rect(&tria_rect, 'h', col);
}
static void ui_text_clip_give_prev_off(uiBut *but, const char *str)
@@ -1047,7 +1456,7 @@ float UI_text_clip_middle_ex(
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
if ((okwidth > 0.0f) && (strwidth > okwidth)) {
- /* utf8 ellipsis '..', some compilers complain */
+ /* utf8 two-dots leader '..' (shorter than ellipsis '...'), some compilers complain with real litteral string. */
const char sep[] = {0xe2, 0x80, 0xA5, 0x0};
const int sep_len = sizeof(sep) - 1;
const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
@@ -1087,7 +1496,7 @@ float UI_text_clip_middle_ex(
rpart = rpart_buf;
}
- l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width);
+ l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, NULL);
if (l_end < 10 || min_ff(parts_strwidth, strwidth - okwidth) < minwidth) {
/* If we really have no place, or we would clip a very small piece of string in the middle,
* only show start of string.
@@ -1097,7 +1506,7 @@ float UI_text_clip_middle_ex(
else {
size_t r_offset, r_len;
- r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width);
+ r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, NULL);
r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'. */
if (l_end + sep_len + r_len + rpart_len > max_len) {
@@ -1112,12 +1521,23 @@ float UI_text_clip_middle_ex(
memmove(str + l_end + sep_len, str + r_offset, r_len);
memcpy(str + l_end, sep, sep_len);
final_lpart_len = (size_t)(l_end + sep_len + r_len - 1); /* -1 to remove trailing '\0'! */
+
+ while (BLF_width(fstyle->uifont_id, str, max_len) > okwidth) {
+ /* This will happen because a lot of string width processing is done in integer pixels,
+ * which can introduce a rather high error in the end (about 2 pixels or so).
+ * Only one char removal shall ever be needed in real-life situation... */
+ r_len--;
+ final_lpart_len--;
+ char *c = str + l_end + sep_len;
+ memmove(c, c + 1, r_len);
+ }
}
}
if (rpart) {
/* Add back preserved right part to our shorten str. */
memcpy(str + final_lpart_len, rpart, rpart_len + 1); /* +1 for trailing '\0'. */
+ okwidth += rpart_width;
}
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
@@ -1127,6 +1547,8 @@ float UI_text_clip_middle_ex(
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
+ BLI_assert(strwidth <= okwidth);
+
return strwidth;
}
@@ -1136,7 +1558,7 @@ float UI_text_clip_middle_ex(
static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
/* No margin for labels! */
- const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
+ const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU, UI_BTYPE_POPOVER) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0);
const size_t max_len = sizeof(but->drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
@@ -1152,7 +1574,7 @@ static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rec
static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char rsep)
{
/* No margin for labels! */
- const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
+ const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU, UI_BTYPE_POPOVER) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0);
const size_t max_len = sizeof(but->drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
@@ -1305,6 +1727,7 @@ static void widget_draw_text_ime_underline(
int ofs_x, width;
int rect_x = BLI_rcti_size_x(rect);
int sel_start = ime_data->sel_start, sel_end = ime_data->sel_end;
+ float fcol[4];
if (drawstr[0] != 0) {
if (but->pos >= but->ofs) {
@@ -1318,8 +1741,8 @@ static void widget_draw_text_ime_underline(
fstyle->uifont_id, drawstr + but->ofs,
ime_data->composite_len + but->pos - but->ofs);
- glColor4ubv((unsigned char *)wcol->text);
- UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 1);
+ rgba_uchar_to_float(fcol, wcol->text);
+ UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 1, fcol);
/* draw the thick line */
if (sel_start != -1 && sel_end != -1) {
@@ -1337,7 +1760,7 @@ static void widget_draw_text_ime_underline(
fstyle->uifont_id, drawstr + but->ofs,
sel_end + sel_start - but->ofs);
- UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 2);
+ UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 2, fcol);
}
}
}
@@ -1412,6 +1835,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
int selsta_draw, selwidth_draw;
if (drawstr[0] != 0) {
+ /* We are drawing on top of widget bases. Flush cache. */
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
if (but->selsta >= but->ofs) {
selsta_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selsta - but->ofs);
@@ -1422,11 +1849,16 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
selwidth_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selend - but->ofs);
- glColor4ubv((unsigned char *)wcol->item);
- glRecti(rect->xmin + selsta_draw,
- rect->ymin + 2,
- min_ii(rect->xmin + selwidth_draw, rect->xmax - 2),
- rect->ymax - 2);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4ubv((unsigned char *)wcol->item);
+ immRecti(pos, rect->xmin + selsta_draw,
+ rect->ymin + 2,
+ min_ii(rect->xmin + selwidth_draw, rect->xmax - 2),
+ rect->ymax - 2);
+
+ immUnbindProgram();
}
}
@@ -1448,14 +1880,23 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
else {
t = 0;
}
+ /* We are drawing on top of widget bases. Flush cache. */
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glColor3f(0.2, 0.6, 0.9);
+ immUniformColor3f(0.2f, 0.6f, 0.9f);
tx = rect->xmin + t + 2;
ty = rect->ymin + 2;
/* draw cursor */
- glRecti(rect->xmin + t, ty, tx, rect->ymax - 2);
+ immRecti(pos, rect->xmin + t, ty, tx, rect->ymax - 2);
+
+ immUnbindProgram();
}
#ifdef WITH_INPUT_IME
@@ -1480,7 +1921,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
#endif
/* cut string in 2 parts - only for menu entries */
- if ((but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) &&
+ if ((but->drawflag & UI_BUT_HAS_SHORTCUT) &&
(but->editstr == NULL))
{
if (but->flag & UI_BUT_HAS_SEP_CHAR) {
@@ -1516,44 +1957,46 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
}
#endif
- glColor4ubv((unsigned char *)wcol->text);
-
if (!use_right_only) {
/* for underline drawing */
float font_xofs, font_yofs;
- UI_fontstyle_draw_ex(
- fstyle, rect, drawstr + but->ofs,
- drawstr_left_len - but->ofs, &font_xofs, &font_yofs);
+ int drawlen = (drawstr_left_len == INT_MAX) ? strlen(drawstr + but->ofs) : (drawstr_left_len - but->ofs);
- if (but->menu_key != '\0') {
- char fixedbuf[128];
- const char *str;
+ if (drawlen > 0) {
+ UI_fontstyle_draw_ex(fstyle, rect, drawstr + but->ofs, (unsigned char *)wcol->text,
+ drawlen, &font_xofs, &font_yofs);
- BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawstr_left_len));
+ if (but->menu_key != '\0') {
+ char fixedbuf[128];
+ const char *str;
- str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
- if (str == NULL)
- str = strchr(fixedbuf, but->menu_key);
+ BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawlen));
- if (str) {
- int ul_index = -1;
- float ul_advance;
+ str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
+ if (str == NULL)
+ str = strchr(fixedbuf, but->menu_key);
- ul_index = (int)(str - fixedbuf);
+ if (str) {
+ int ul_index = -1;
+ float ul_advance;
- if (fstyle->kerning == 1) {
- BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
- }
+ ul_index = (int)(str - fixedbuf);
- fixedbuf[ul_index] = '\0';
- ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index);
+ if (fstyle->kerning == 1) {
+ BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
+ }
+
+ fixedbuf[ul_index] = '\0';
+ ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index) + (1.0f * UI_DPI_FAC);
- BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f);
- BLF_draw(fstyle->uifont_id, "_", 2);
+ BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f);
+ BLF_color4ubv(fstyle->uifont_id, (unsigned char *)wcol->text);
+ BLF_draw(fstyle->uifont_id, "_", 2);
- if (fstyle->kerning == 1) {
- BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
+ if (fstyle->kerning == 1) {
+ BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
+ }
}
}
}
@@ -1561,9 +2004,30 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
/* part text right aligned */
if (drawstr_right) {
+ char col[4];
+ copy_v4_v4_char(col, wcol->text);
+ if (but->drawflag & UI_BUT_HAS_SHORTCUT) {
+ col[3] *= 0.5f;
+ }
+
fstyle->align = UI_STYLE_TEXT_RIGHT;
rect->xmax -= UI_TEXT_CLIP_MARGIN;
- UI_fontstyle_draw(fstyle, rect, drawstr_right);
+ UI_fontstyle_draw(fstyle, rect, drawstr_right, (const uchar *)col);
+ }
+}
+
+static BIFIconID widget_icon_id(uiBut *but)
+{
+ if (!(but->flag & UI_HAS_ICON)) {
+ return ICON_NONE;
+ }
+
+ /* Consecutive icons can be toggle between. */
+ if (but->drawflag & UI_BUT_ICON_REVERSE) {
+ return but->icon - but->iconadd;
+ }
+ else {
+ return but->icon + but->iconadd;
}
}
@@ -1578,10 +2042,10 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
ui_but_text_password_hide(password_str, but, false);
/* check for button text label */
- if (but->type == UI_BTYPE_MENU && (but->flag & UI_BUT_NODE_LINK)) {
+ if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && (but->flag & UI_BUT_NODE_LINK)) {
rcti temp = *rect;
temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
- widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, false);
+ widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, wcol->text);
rect->xmax = temp.xmin;
}
@@ -1590,7 +2054,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* Big previews with optional text label below */
if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
- const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
+ const BIFIconID icon = widget_icon_id(but);
int icon_size = BLI_rcti_size_y(rect);
int text_size = 0;
@@ -1603,9 +2067,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* draw icon in rect above the space reserved for the label */
rect->ymin += text_size;
- glEnable(GL_BLEND);
+ GPU_blend(true);
widget_draw_preview(icon, alpha, rect);
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* offset rect to draw label in */
rect->ymin -= text_size;
@@ -1616,25 +2080,53 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
}
/* Icons on the left with optional text label on the right */
else if (but->flag & UI_HAS_ICON || show_menu_icon) {
- const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
- const float icon_size = ICON_DEFAULT_WIDTH_SCALE;
+ const bool is_tool = UI_but_is_tool(but);
+
+ /* XXX add way to draw icons at a different size!
+ * Use small icons for popup. */
+#ifdef USE_UI_TOOLBAR_HACK
+ const float aspect_orig = but->block->aspect;
+ if (is_tool && (but->block->flag & UI_BLOCK_POPOVER)) {
+ but->block->aspect *= 2.0f;
+ }
+#endif
+
+ const BIFIconID icon = widget_icon_id(but);
+ int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT;
+ const float icon_size = icon_size_init / (but->block->aspect / UI_DPI_FAC);
+ const float icon_padding = 2 * UI_DPI_FAC;
+
+#ifdef USE_UI_TOOLBAR_HACK
+ if (is_tool) {
+ /* pass (even if its a menu toolbar) */
+ but->drawflag |= UI_BUT_TEXT_LEFT;
+ but->drawflag |= UI_BUT_ICON_LEFT;
+ }
+#endif
/* menu item - add some more padding so menus don't feel cramped. it must
* be part of the button so that this area is still clickable */
- if (ui_block_is_pie_menu(but->block)) {
+ if (is_tool) {
+ /* pass (even if its a menu toolbar) */
+ }
+ else if (ui_block_is_pie_menu(but->block)) {
if (but->dt == UI_EMBOSS_RADIAL)
rect->xmin += 0.3f * U.widget_unit;
}
else if (ui_block_is_menu(but->block))
- rect->xmin += 0.3f * U.widget_unit;
-
- widget_draw_icon(but, icon, alpha, rect, show_menu_icon);
+ rect->xmin += 0.2f * U.widget_unit;
- rect->xmin += icon_size;
- /* without this menu keybindings will overlap the arrow icon [#38083] */
+ widget_draw_icon(but, icon, alpha, rect, wcol->text);
if (show_menu_icon) {
- rect->xmax -= icon_size / 2.0f;
+ BLI_assert(but->block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT);
+ widget_draw_submenu_tria(but, rect, wcol);
}
+
+#ifdef USE_UI_TOOLBAR_HACK
+ but->block->aspect = aspect_orig;
+#endif
+
+ rect->xmin += icon_size + icon_padding;
}
if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT)) {
@@ -1644,6 +2136,12 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
}
+ /* Menu contains sub-menu items with triangle icon on their right. Shortcut
+ * strings should be drawn with some padding to the right then. */
+ if (ui_block_is_menu(but->block) && (but->block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT)) {
+ rect->xmax -= UI_MENU_SUBMENU_PADDING;
+ }
+
/* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
if (extra_icon_type != UI_BUT_ICONEXTRA_NONE) {
rcti temp = *rect;
@@ -1651,10 +2149,10 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) {
- widget_draw_icon(but, ICON_PANEL_CLOSE, alpha, &temp, false);
+ widget_draw_icon(but, ICON_PANEL_CLOSE, alpha, &temp, wcol->text);
}
else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
- widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false);
+ widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, wcol->text);
}
else {
BLI_assert(0);
@@ -1687,6 +2185,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
widget_draw_text(fstyle, wcol, but, rect);
ui_but_text_password_hide(password_str, but, true);
+
+ /* if a widget uses font shadow it has to be deactivated now */
+ BLF_disable(fstyle->uifont_id, BLF_SHADOW);
}
#undef UI_TEXT_CLIP_MARGIN
@@ -1694,297 +2195,6 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
/* *********************** widget types ************************************* */
-static struct uiWidgetStateColors wcol_state_colors = {
- {115, 190, 76, 255},
- {90, 166, 51, 255},
- {240, 235, 100, 255},
- {215, 211, 75, 255},
- {180, 0, 255, 255},
- {153, 0, 230, 255},
- 0.5f, 0.0f
-};
-
-static struct uiWidgetColors wcol_num = {
- {25, 25, 25, 255},
- {180, 180, 180, 255},
- {153, 153, 153, 255},
- {90, 90, 90, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 1,
- -20, 0
-};
-
-static struct uiWidgetColors wcol_numslider = {
- {25, 25, 25, 255},
- {180, 180, 180, 255},
- {153, 153, 153, 255},
- {128, 128, 128, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 1,
- -20, 0
-};
-
-static struct uiWidgetColors wcol_text = {
- {25, 25, 25, 255},
- {153, 153, 153, 255},
- {153, 153, 153, 255},
- {90, 90, 90, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 1,
- 0, 25
-};
-
-static struct uiWidgetColors wcol_option = {
- {0, 0, 0, 255},
- {70, 70, 70, 255},
- {70, 70, 70, 255},
- {255, 255, 255, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 1,
- 15, -15
-};
-
-/* button that shows popup */
-static struct uiWidgetColors wcol_menu = {
- {0, 0, 0, 255},
- {70, 70, 70, 255},
- {70, 70, 70, 255},
- {255, 255, 255, 255},
-
- {255, 255, 255, 255},
- {204, 204, 204, 255},
-
- 1,
- 15, -15
-};
-
-/* button that starts pulldown */
-static struct uiWidgetColors wcol_pulldown = {
- {0, 0, 0, 255},
- {63, 63, 63, 255},
- {86, 128, 194, 255},
- {255, 255, 255, 255},
-
- {0, 0, 0, 255},
- {0, 0, 0, 255},
-
- 0,
- 25, -20
-};
-
-/* button inside menu */
-static struct uiWidgetColors wcol_menu_item = {
- {0, 0, 0, 255},
- {0, 0, 0, 0},
- {86, 128, 194, 255},
- {172, 172, 172, 128},
-
- {255, 255, 255, 255},
- {0, 0, 0, 255},
-
- 1,
- 38, 0
-};
-
-/* backdrop menu + title text color */
-static struct uiWidgetColors wcol_menu_back = {
- {0, 0, 0, 255},
- {25, 25, 25, 230},
- {45, 45, 45, 230},
- {100, 100, 100, 255},
-
- {160, 160, 160, 255},
- {255, 255, 255, 255},
-
- 0,
- 25, -20
-};
-
-/* pie menus */
-static struct uiWidgetColors wcol_pie_menu = {
- {10, 10, 10, 200},
- {25, 25, 25, 230},
- {140, 140, 140, 255},
- {45, 45, 45, 230},
-
- {160, 160, 160, 255},
- {255, 255, 255, 255},
-
- 1,
- 10, -10
-};
-
-
-/* tooltip color */
-static struct uiWidgetColors wcol_tooltip = {
- {0, 0, 0, 255},
- {25, 25, 25, 230},
- {45, 45, 45, 230},
- {100, 100, 100, 255},
-
- {255, 255, 255, 255},
- {255, 255, 255, 255},
-
- 0,
- 25, -20
-};
-
-static struct uiWidgetColors wcol_radio = {
- {0, 0, 0, 255},
- {70, 70, 70, 255},
- {86, 128, 194, 255},
- {255, 255, 255, 255},
-
- {255, 255, 255, 255},
- {0, 0, 0, 255},
-
- 1,
- 15, -15
-};
-
-static struct uiWidgetColors wcol_regular = {
- {25, 25, 25, 255},
- {153, 153, 153, 255},
- {100, 100, 100, 255},
- {25, 25, 25, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 0,
- 0, 0
-};
-
-static struct uiWidgetColors wcol_tool = {
- {25, 25, 25, 255},
- {153, 153, 153, 255},
- {100, 100, 100, 255},
- {25, 25, 25, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 1,
- 15, -15
-};
-
-static struct uiWidgetColors wcol_box = {
- {25, 25, 25, 255},
- {128, 128, 128, 255},
- {100, 100, 100, 255},
- {25, 25, 25, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 0,
- 0, 0
-};
-
-static struct uiWidgetColors wcol_toggle = {
- {25, 25, 25, 255},
- {153, 153, 153, 255},
- {100, 100, 100, 255},
- {25, 25, 25, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 0,
- 0, 0
-};
-
-static struct uiWidgetColors wcol_scroll = {
- {50, 50, 50, 180},
- {80, 80, 80, 180},
- {100, 100, 100, 180},
- {128, 128, 128, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 1,
- 5, -5
-};
-
-static struct uiWidgetColors wcol_progress = {
- {0, 0, 0, 255},
- {190, 190, 190, 255},
- {100, 100, 100, 180},
- {128, 128, 128, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 0,
- 0, 0
-};
-
-static struct uiWidgetColors wcol_list_item = {
- {0, 0, 0, 255},
- {0, 0, 0, 0},
- {86, 128, 194, 255},
- {90, 90, 90, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 0,
- 0, 0
-};
-
-/* free wcol struct to play with */
-static struct uiWidgetColors wcol_tmp = {
- {0, 0, 0, 255},
- {128, 128, 128, 255},
- {100, 100, 100, 255},
- {25, 25, 25, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 0,
- 0, 0
-};
-
-
-/* called for theme init (new theme) and versions */
-void ui_widget_color_init(ThemeUI *tui)
-{
- tui->wcol_regular = wcol_regular;
- tui->wcol_tool = wcol_tool;
- tui->wcol_text = wcol_text;
- tui->wcol_radio = wcol_radio;
- tui->wcol_option = wcol_option;
- tui->wcol_toggle = wcol_toggle;
- tui->wcol_num = wcol_num;
- tui->wcol_numslider = wcol_numslider;
- tui->wcol_menu = wcol_menu;
- tui->wcol_pulldown = wcol_pulldown;
- tui->wcol_menu_back = wcol_menu_back;
- tui->wcol_pie_menu = wcol_pie_menu;
- tui->wcol_tooltip = wcol_tooltip;
- tui->wcol_menu_item = wcol_menu_item;
- tui->wcol_box = wcol_box;
- tui->wcol_scroll = wcol_scroll;
- tui->wcol_list_item = wcol_list_item;
- tui->wcol_progress = wcol_progress;
-
- tui->wcol_state = wcol_state_colors;
-}
-
/* ************ button callbacks, state ***************** */
static void widget_state_blend(char cp[3], const char cpstate[3], const float fac)
@@ -2013,6 +2223,13 @@ static void ui_widget_color_disabled(uiWidgetType *wt)
wt->wcol_theme = &wcol_theme_s;
}
+static void widget_active_color(char cp[3])
+{
+ cp[0] = cp[0] >= 240 ? 255 : cp[0] + 15;
+ cp[1] = cp[1] >= 240 ? 255 : cp[1] + 15;
+ cp[2] = cp[2] >= 240 ? 255 : cp[2] + 15;
+}
+
/* copy colors from theme, and set changes in it based on state */
static void widget_state(uiWidgetType *wt, int state)
{
@@ -2039,6 +2256,8 @@ static void widget_state(uiWidgetType *wt, int state)
widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend);
else if (state & UI_BUT_DRIVEN)
widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend);
+ else if (state & UI_BUT_OVERRIDEN)
+ widget_state_blend(wt->wcol.inner, wcol_state->inner_overridden_sel, wcol_state->blend);
copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
@@ -2052,17 +2271,22 @@ static void widget_state(uiWidgetType *wt, int state)
widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend);
else if (state & UI_BUT_DRIVEN)
widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend);
+ else if (state & UI_BUT_OVERRIDEN)
+ widget_state_blend(wt->wcol.inner, wcol_state->inner_overridden, wcol_state->blend);
if (state & UI_ACTIVE) { /* mouse over? */
- wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15;
- wt->wcol.inner[1] = wt->wcol.inner[1] >= 240 ? 255 : wt->wcol.inner[1] + 15;
- wt->wcol.inner[2] = wt->wcol.inner[2] >= 240 ? 255 : wt->wcol.inner[2] + 15;
+ widget_active_color(wt->wcol.inner);
}
}
if (state & UI_BUT_REDALERT) {
char red[4] = {255, 0, 0};
- widget_state_blend(wt->wcol.inner, red, 0.4f);
+ if (wt->draw) {
+ widget_state_blend(wt->wcol.inner, red, 0.4f);
+ }
+ else {
+ widget_state_blend(wt->wcol.text, red, 0.4f);
+ }
}
if (state & UI_BUT_DRAG_MULTI) {
@@ -2097,6 +2321,8 @@ static void widget_state_numslider(uiWidgetType *wt, int state)
widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
else if (state & UI_BUT_DRIVEN)
widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
+ else if (state & UI_BUT_OVERRIDEN)
+ widget_state_blend(wt->wcol.item, wcol_state->inner_overridden_sel, blend);
if (state & UI_SELECT)
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
@@ -2108,6 +2334,8 @@ static void widget_state_numslider(uiWidgetType *wt, int state)
widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
else if (state & UI_BUT_DRIVEN)
widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
+ else if (state & UI_BUT_OVERRIDEN)
+ widget_state_blend(wt->wcol.item, wcol_state->inner_overridden, blend);
}
}
@@ -2133,15 +2361,9 @@ static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state))
}
/* special case, button that calls pulldown */
-static void widget_state_pulldown(uiWidgetType *wt, int state)
+static void widget_state_pulldown(uiWidgetType *wt, int UNUSED(state))
{
wt->wcol = *(wt->wcol_theme);
-
- copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
- copy_v3_v3_char(wt->wcol.outline, wt->wcol.inner);
-
- if (state & UI_ACTIVE)
- copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
}
/* special case, pie menu items */
@@ -2157,18 +2379,22 @@ static void widget_state_pie_menu_item(uiWidgetType *wt, int state)
copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
wt->wcol.inner[3] = 64;
}
- /* regular disabled */
- else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
- widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
- }
- /* regular active */
- else if (state & UI_SELECT) {
- copy_v4_v4_char(wt->wcol.outline, wt->wcol.inner_sel);
- copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
- }
- else if (state & UI_ACTIVE) {
- copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
- copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
+ else {
+ /* regular active */
+ if (state & (UI_SELECT | UI_ACTIVE)) {
+ copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
+ }
+ else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ /* regular disabled */
+ widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
+ }
+
+ if (state & UI_SELECT) {
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
+ }
+ else if (state & UI_ACTIVE) {
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
+ }
}
}
@@ -2185,14 +2411,19 @@ static void widget_state_menu_item(uiWidgetType *wt, int state)
copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
wt->wcol.inner[3] = 64;
}
- /* regular disabled */
- else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
- widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
- }
- /* regular active */
- else if (state & UI_ACTIVE) {
- copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
- copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
+ else {
+ /* regular active */
+ if (state & UI_ACTIVE) {
+ copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
+ }
+ else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ /* regular disabled */
+ widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
+ }
+
+ if (state & UI_ACTIVE) {
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
+ }
}
}
@@ -2226,22 +2457,23 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
/* we draw a number of increasing size alpha quad strips */
alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout;
- glEnableClientState(GL_VERTEX_ARRAY);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
for (step = 1; step <= (int)radout; step++) {
float expfac = sqrtf(step / radout);
round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
- glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
+ immUniformColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip);
- glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
+ widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, totvert * 2);
}
- glDisableClientState(GL_VERTEX_ARRAY);
+ immUnbindProgram();
}
static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
@@ -2265,33 +2497,34 @@ static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int dir
rect->ymax += 0.1f * U.widget_unit;
}
- glEnable(GL_BLEND);
- widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
- round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
+ round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
-
static void ui_hsv_cursor(float x, float y)
{
- glPushMatrix();
- glTranslatef(x, y, 0.0f);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glColor3f(1.0f, 1.0f, 1.0f);
- glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 8);
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+ imm_draw_circle_fill_2d(pos, x, y, 3.0f * U.pixelsize, 8);
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
- glColor3f(0.0f, 0.0f, 0.0f);
- glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 12);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ GPU_blend(true);
+ GPU_line_smooth(true);
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+ imm_draw_circle_wire_2d(pos, x, y, 3.0f * U.pixelsize, 12);
+ GPU_blend(false);
+ GPU_line_smooth(false);
- glPopMatrix();
+ immUnbindProgram();
}
void ui_hsvcircle_vals_from_pos(
@@ -2332,18 +2565,17 @@ void ui_hsvcircle_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float
static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
{
+ /* TODO(merwin): reimplement as shader for pixel-perfect colors */
+
const int tot = 64;
const float radstep = 2.0f * (float)M_PI / (float)tot;
const float centx = BLI_rcti_cent_x_fl(rect);
const float centy = BLI_rcti_cent_y_fl(rect);
float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
- /* gouraud triangle fan */
ColorPicker *cpicker = but->custom_data;
const float *hsv_ptr = cpicker->color_data;
- float xpos, ypos, ang = 0.0f;
float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
- int a;
bool color_profile = ui_but_is_colorpicker_display_space(but);
/* color */
@@ -2374,11 +2606,18 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
ui_color_picker_to_rgb(0.0f, 0.0f, hsv[2], colcent, colcent + 1, colcent + 2);
- glBegin(GL_TRIANGLE_FAN);
- glColor3fv(colcent);
- glVertex2f(centx, centy);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+
+ immBegin(GPU_PRIM_TRI_FAN, tot + 2);
+ immAttr3fv(color, colcent);
+ immVertex2f(pos, centx, centy);
- for (a = 0; a <= tot; a++, ang += radstep) {
+ float ang = 0.0f;
+ for (int a = 0; a <= tot; a++, ang += radstep) {
float si = sinf(ang);
float co = cosf(ang);
@@ -2386,25 +2625,32 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
ui_color_picker_to_rgb_v(hsv, col);
- glColor3fv(col);
- glVertex2f(centx + co * radius, centy + si * radius);
+ immAttr3fv(color, col);
+ immVertex2f(pos, centx + co * radius, centy + si * radius);
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
/* fully rounded outline */
- glPushMatrix();
- glTranslatef(centx, centy, 0.0f);
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
- glColor3ubv((unsigned char *)wcol->outline);
- glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
- glPopMatrix();
+ format = immVertexFormat();
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_blend(true);
+ GPU_line_smooth(true);
+
+ immUniformColor3ubv((unsigned char *)wcol->outline);
+ imm_draw_circle_wire_2d(pos, centx, centy, radius, tot);
+
+ immUnbindProgram();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
/* cursor */
+ float xpos, ypos;
ui_hsvcircle_pos_from_vals(but, rect, hsvo, &xpos, &ypos);
-
ui_hsv_cursor(xpos, ypos);
}
@@ -2414,7 +2660,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
{
/* allows for 4 steps (red->yellow) */
- const float color_step = 1.0f / 48.0f;
+ const int steps = 48;
+ const float color_step = 1.0f / steps;
int a;
float h = hsv[0], s = hsv[1], v = hsv[2];
float dx, dy, sx1, sx2, sy;
@@ -2470,7 +2717,12 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
}
/* old below */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
+ immBegin(GPU_PRIM_TRIS, steps * 3 * 6);
for (dx = 0.0f; dx < 0.999f; dx += color_step) { /* 0.999 = prevent float inaccuracy for steps */
const float dx_next = dx + color_step;
@@ -2528,22 +2780,29 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
sy = rect->ymin;
dy = (float)BLI_rcti_size_y(rect) / 3.0f;
- glBegin(GL_QUADS);
for (a = 0; a < 3; a++, sy += dy) {
- glColor4f(col0[a][0], col0[a][1], col0[a][2], alpha);
- glVertex2f(sx1, sy);
+ immAttr4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
+ immVertex2f(pos, sx1, sy);
+
+ immAttr4f(col, col1[a][0], col1[a][1], col1[a][2], alpha);
+ immVertex2f(pos, sx2, sy);
+
+ immAttr4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
+ immVertex2f(pos, sx2, sy + dy);
- glColor4f(col1[a][0], col1[a][1], col1[a][2], alpha);
- glVertex2f(sx2, sy);
+ immAttr4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
+ immVertex2f(pos, sx1, sy);
- glColor4f(col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
- glVertex2f(sx2, sy + dy);
+ immAttr4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
+ immVertex2f(pos, sx2, sy + dy);
- glColor4f(col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
- glVertex2f(sx1, sy + dy);
+ immAttr4f(col, col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
+ immVertex2f(pos, sx1, sy + dy);
}
- glEnd();
}
+ immEnd();
+
+ immUnbindProgram();
}
bool ui_but_is_colorpicker_display_space(uiBut *but)
@@ -2619,15 +2878,20 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
ui_hsv_cursor(x, y);
/* outline */
- glColor3ub(0, 0, 0);
- fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(0, 0, 0);
+ imm_draw_box_wire_2d(pos, (rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
+ immUnbindProgram();
}
/* vertical 'value' slider, using new widget code */
static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
{
+ bTheme *btheme = UI_GetTheme();
+ uiWidgetColors *wcol = &btheme->tui.wcol_numslider;
uiWidgetBase wtb;
- const float rad = 0.5f * BLI_rcti_size_x(rect);
+ const float rad = wcol->roundness * BLI_rcti_size_x(rect);
float x, y;
float rgb[3], hsv[3], v;
bool color_profile = but->block->color_profile;
@@ -2661,13 +2925,21 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
/* setup temp colors */
- wcol_tmp.outline[0] = wcol_tmp.outline[1] = wcol_tmp.outline[2] = 0;
- wcol_tmp.inner[0] = wcol_tmp.inner[1] = wcol_tmp.inner[2] = 128;
- wcol_tmp.shadetop = 127;
- wcol_tmp.shadedown = -128;
- wcol_tmp.shaded = 1;
-
- widgetbase_draw(&wtb, &wcol_tmp);
+ widgetbase_draw(
+ &wtb,
+ &((uiWidgetColors){
+ .outline = {0, 0, 0, 255},
+ .inner = {128, 128, 128, 255},
+ .shadetop = 127,
+ .shadedown = -128,
+ .shaded = 1,
+ })
+ );
+
+ /* We are drawing on top of widget bases. Flush cache. */
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
/* cursor */
x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
@@ -2677,6 +2949,20 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
ui_hsv_cursor(x, y);
}
+/* Generic round-box drawing. */
+static void ui_draw_roundbox(const rcti *rect, const float rad, const uiWidgetColors *wcol)
+{
+ uiWidgetBase wtb;
+ widget_init(&wtb);
+ round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
+ widgetbase_draw(&wtb, wcol);
+
+ /* We are drawing on top of widget bases. Flush cache. */
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
+}
+
/* ************ separator, for menus etc ***************** */
static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol)
@@ -2689,19 +2975,29 @@ static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol)
30
};
- glEnable(GL_BLEND);
- glColor4ubv(col);
- glLineWidth(1.0f);
- sdrawline(rect->xmin, y, rect->xmax, y);
- glDisable(GL_BLEND);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_blend(true);
+ immUniformColor4ubv(col);
+ GPU_line_width(1.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, rect->xmin, y);
+ immVertex2f(pos, rect->xmax, y);
+ immEnd();
+
+ GPU_blend(false);
+
+ immUnbindProgram();
}
/* ************ button callbacks, draw ***************** */
static void widget_numbut_draw(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss)
{
uiWidgetBase wtb;
- const float rad = 0.5f * BLI_rcti_size_y(rect);
- float textofs = rad * 0.85f;
+ const float rad = wcol->roundness * BLI_rcti_size_y(rect);
+ const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
if (state & UI_SELECT)
SWAP(short, wcol->shadetop, wcol->shadedown);
@@ -2717,14 +3013,80 @@ static void widget_numbut_draw(uiWidgetColors *wcol, rcti *rect, int state, int
}
/* decoration */
- if (!(state & UI_STATE_TEXT_INPUT)) {
- shape_preset_init_number_arrows(&wtb.tria1, rect, 0.6f, 'l');
- shape_preset_init_number_arrows(&wtb.tria2, rect, 0.6f, 'r');
- }
+ if ((state & UI_ACTIVE) && !(state & UI_STATE_TEXT_INPUT)) {
+ uiWidgetColors wcol_zone;
+ uiWidgetBase wtb_zone;
+ rcti rect_zone;
+ int roundboxalign_zone;
+
+ /* left arrow zone */
+ widget_init(&wtb_zone);
+ wtb_zone.draw_outline = false;
+ wtb_zone.draw_emboss = false;
+
+ wcol_zone = *wcol;
+ copy_v3_v3_char(wcol_zone.item, wcol->text);
+ if (state & UI_STATE_ACTIVE_LEFT) {
+ widget_active_color(wcol_zone.inner);
+ }
- widgetbase_draw(&wtb, wcol);
+ rect_zone = *rect;
+ rect_zone.xmax = rect->xmin + handle_width + U.pixelsize;
+ roundboxalign_zone = roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
+ round_box_edges(&wtb_zone, roundboxalign_zone, &rect_zone, rad);
+
+ shape_preset_init_number_arrows(&wtb_zone.tria1, &rect_zone, 0.6f, 'l');
+ widgetbase_draw(&wtb_zone, &wcol_zone);
+
+ /* right arrow zone */
+ widget_init(&wtb_zone);
+ wtb_zone.draw_outline = false;
+ wtb_zone.draw_emboss = false;
+ wtb_zone.tria1.type = ROUNDBOX_TRIA_ARROWS;
+
+ wcol_zone = *wcol;
+ copy_v3_v3_char(wcol_zone.item, wcol->text);
+ if (state & UI_STATE_ACTIVE_RIGHT) {
+ widget_active_color(wcol_zone.inner);
+ }
+
+ rect_zone = *rect;
+ rect_zone.xmin = rect->xmax - handle_width - U.pixelsize;
+ roundboxalign_zone = roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
+ round_box_edges(&wtb_zone, roundboxalign_zone, &rect_zone, rad);
+
+ shape_preset_init_number_arrows(&wtb_zone.tria2, &rect_zone, 0.6f, 'r');
+ widgetbase_draw(&wtb_zone, &wcol_zone);
+
+ /* middle highlight zone */
+ widget_init(&wtb_zone);
+ wtb_zone.draw_outline = false;
+ wtb_zone.draw_emboss = false;
+
+ wcol_zone = *wcol;
+ copy_v3_v3_char(wcol_zone.item, wcol->text);
+ if (!(state & (UI_STATE_ACTIVE_LEFT | UI_STATE_ACTIVE_RIGHT))) {
+ widget_active_color(wcol_zone.inner);
+ }
+
+ rect_zone = *rect;
+ rect_zone.xmin = rect->xmin + handle_width - U.pixelsize;
+ rect_zone.xmax = rect->xmax - handle_width + U.pixelsize;
+ round_box_edges(&wtb_zone, 0, &rect_zone, 0);
+ widgetbase_draw(&wtb_zone, &wcol_zone);
+
+ /* outline */
+ wtb.draw_inner = false;
+ widgetbase_draw(&wtb, wcol);
+ }
+ else {
+ /* inner and outline */
+ widgetbase_draw(&wtb, wcol);
+ }
if (!(state & UI_STATE_TEXT_INPUT)) {
+ const float textofs = 0.425f * BLI_rcti_size_y(rect);
+
/* text space */
rect->xmin += textofs;
rect->xmax -= textofs;
@@ -2744,53 +3106,6 @@ static void widget_numbut_embossn(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti
widget_numbut_draw(wcol, rect, state, roundboxalign, true);
}
-bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
-{
- float dist, vec[4][2];
-
- vec[0][0] = rect->xmin;
- vec[0][1] = rect->ymin;
- vec[3][0] = rect->xmax;
- vec[3][1] = rect->ymax;
-
- dist = 0.5f * fabsf(vec[0][0] - vec[3][0]);
-
- vec[1][0] = vec[0][0] + dist;
- vec[1][1] = vec[0][1];
-
- vec[2][0] = vec[3][0] - dist;
- vec[2][1] = vec[3][1];
-
- BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], &coord_array[0][0], resol, sizeof(float[2]));
- BKE_curve_forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], &coord_array[0][1], resol, sizeof(float[2]));
-
- /* TODO: why return anything if always true? */
- return true;
-}
-
-#define LINK_RESOL 24
-void ui_draw_link_bezier(const rcti *rect)
-{
- float coord_array[LINK_RESOL + 1][2];
-
- if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
-#if 0 /* unused */
- /* we can reuse the dist variable here to increment the GL curve eval amount*/
- const float dist = 1.0f / (float)LINK_RESOL;
-#endif
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, coord_array);
- glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL + 1);
- glDisableClientState(GL_VERTEX_ARRAY);
-
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
- }
-}
-
/* function in use for buttons and for view2d sliders */
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
{
@@ -2805,11 +3120,11 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s
horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
if (horizontal)
- rad = 0.5f * BLI_rcti_size_y(rect);
+ rad = wcol->roundness * BLI_rcti_size_y(rect);
else
- rad = 0.5f * BLI_rcti_size_x(rect);
+ rad = wcol->roundness * BLI_rcti_size_x(rect);
- wtb.draw_shadedir = (horizontal) ? true : false;
+ wtb.uniform_params.shade_dir = (horizontal) ? 1.0f : 0.0;
/* draw back part, colors swapped and shading inverted */
if (horizontal)
@@ -2941,7 +3256,7 @@ static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int
/* round corners */
float value = but->a1;
- float offs = 0.25f * BLI_rcti_size_y(&rect_prog);
+ float offs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
float w = value * BLI_rcti_size_x(&rect_prog);
/* ensure minimium size */
@@ -2964,96 +3279,85 @@ static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int
rect->xmax += (BLI_rcti_size_x(&rect_prog) / 2);
}
-static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
-{
-
- if (but->flag & UI_SELECT) {
- rcti rectlink;
-
- UI_ThemeColor(TH_TEXT_HI);
-
- rectlink.xmin = BLI_rcti_cent_x(rect);
- rectlink.ymin = BLI_rcti_cent_y(rect);
- rectlink.xmax = but->linkto[0];
- rectlink.ymax = but->linkto[1];
-
- ui_draw_link_bezier(&rectlink);
- }
-}
-
static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
uiWidgetBase wtb, wtb1;
rcti rect1;
- double value;
- float offs, toffs, fac = 0;
+ float offs, toffs;
char outline[3];
widget_init(&wtb);
widget_init(&wtb1);
- /* backdrop first */
-
- /* fully rounded */
- offs = 0.5f * BLI_rcti_size_y(rect);
+ /* Backdrop first. */
+ offs = wcol->roundness * BLI_rcti_size_y(rect);
toffs = offs * 0.75f;
round_box_edges(&wtb, roundboxalign, rect, offs);
wtb.draw_outline = false;
widgetbase_draw(&wtb, wcol);
- /* draw left/right parts only when not in text editing */
+ /* Draw slider part only when not in text editing. */
if (!(state & UI_STATE_TEXT_INPUT)) {
- int roundboxalign_slider;
+ int roundboxalign_slider = roundboxalign;
- /* slider part */
copy_v3_v3_char(outline, wcol->outline);
copy_v3_v3_char(wcol->outline, wcol->item);
copy_v3_v3_char(wcol->inner, wcol->item);
- if (!(state & UI_SELECT))
+ if (!(state & UI_SELECT)) {
SWAP(short, wcol->shadetop, wcol->shadedown);
+ }
rect1 = *rect;
+ float factor, factor_ui;
+ float factor_discard = 1.0f; /* No discard. */
+ float value = (float)ui_but_value_get(but);
- value = ui_but_value_get(but);
- if ((but->softmax - but->softmin) > 0) {
- fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
+ if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PERCENTAGE)) {
+ factor = value / but->softmax;
+ }
+ else {
+ factor = (value - but->softmin) / (but->softmax - but->softmin);
}
- /* left part of slider, always rounded */
- rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
- round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
- wtb1.draw_outline = false;
- widgetbase_draw(&wtb1, wcol);
-
- /* right part of slider, interpolate roundness */
- rect1.xmax = rect1.xmin + fac + offs;
- rect1.xmin += floor(offs - U.pixelsize);
+ float width = (float)BLI_rcti_size_x(rect);
+ factor_ui = factor * width;
- if (rect1.xmax + offs > rect->xmax) {
- roundboxalign_slider = roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
- offs *= (rect1.xmax + offs - rect->xmax) / offs;
+ if (factor_ui <= offs) {
+ /* Left part only. */
+ roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
+ rect1.xmax = rect1.xmin + offs;
+ factor_discard = factor_ui / offs;
+ }
+ else if (factor_ui <= width - offs) {
+ /* Left part + middle part. */
+ roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
+ rect1.xmax = rect1.xmin + factor_ui;
}
else {
- roundboxalign_slider = 0;
- offs = 0.0f;
+ /* Left part + middle part + right part. */
+ factor_discard = factor;
}
- round_box_edges(&wtb1, roundboxalign_slider, &rect1, offs);
+ round_box_edges(&wtb1, roundboxalign_slider, &rect1, offs);
+ wtb1.draw_outline = false;
+ widgetbase_set_uniform_discard_factor(&wtb1, factor_discard);
widgetbase_draw(&wtb1, wcol);
+
copy_v3_v3_char(wcol->outline, outline);
- if (!(state & UI_SELECT))
+ if (!(state & UI_SELECT)) {
SWAP(short, wcol->shadetop, wcol->shadedown);
+ }
}
- /* outline */
+ /* Outline. */
wtb.draw_outline = true;
wtb.draw_inner = false;
widgetbase_draw(&wtb, wcol);
- /* add space at either side of the button so text aligns with numbuttons (which have arrow icons) */
+ /* Add space at either side of the button so text aligns with numbuttons (which have arrow icons). */
if (!(state & UI_STATE_TEXT_INPUT)) {
rect->xmax -= toffs;
rect->xmin += toffs;
@@ -3084,13 +3388,12 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
widget_init(&wtb);
- /* half rounded */
- rad = 0.25f * U.widget_unit;
+ rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
ui_but_v3_get(but, col);
- if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
+ if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDEN | UI_BUT_REDALERT)) {
/* draw based on state - color for keyed etc */
widgetbase_draw(&wtb, wcol);
@@ -3121,7 +3424,6 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
}
widgetbase_draw_ex(&wtb, wcol, show_alpha_checkers);
-
if (but->a1 == UI_PALETTE_COLOR && ((Palette *)but->rnapoin.id.data)->active_color == (int)but->a2) {
float width = rect->xmax - rect->xmin;
float height = rect->ymax - rect->ymin;
@@ -3130,12 +3432,22 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
bw += (bw < 0.5f) ? 0.5f : -0.5f;
- glColor4f(bw, bw, bw, 1.0);
- glBegin(GL_TRIANGLES);
- glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
- glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
- glVertex2f(rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
- glEnd();
+ /* We are drawing on top of widget bases. Flush cache. */
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(bw, bw, bw);
+ immBegin(GPU_PRIM_TRIS, 3);
+ immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
+ immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
+ immVertex2f(pos, rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
+ immEnd();
+
+ immUnbindProgram();
}
}
@@ -3153,8 +3465,7 @@ static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, i
widget_init(&wtb);
wtb.draw_outline = false;
- /* rounded */
- rad = 0.5f * BLI_rcti_size_y(rect);
+ rad = wcol->roundness * BLI_rcti_size_y(rect);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
@@ -3176,8 +3487,7 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
widget_init(&wtb);
- /* half rounded */
- rad = 0.2f * U.widget_unit;
+ rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -3191,12 +3501,13 @@ static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
widget_init(&wtb);
- /* half rounded */
- rad = 0.2f * U.widget_unit;
+ rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
shape_preset_trias_from_rect_menu(&wtb.tria1, rect);
+ /* copy size and center to 2nd tria */
+ wtb.tria2 = wtb.tria1;
widgetbase_draw(&wtb, wcol);
@@ -3211,44 +3522,31 @@ static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(stat
widget_init(&wtb);
- /* half rounded */
- rad = 0.2f * U.widget_unit;
- round_box_edges(&wtb, roundboxalign, rect, rad);
-
- /* decoration */
- widgetbase_draw(&wtb, wcol);
-}
-
-static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
-{
- /* silly node link button hacks */
- uiWidgetBase wtb;
- uiWidgetColors wcol_backup = *wcol;
- float rad;
-
- widget_init(&wtb);
-
- /* half rounded */
- rad = 0.2f * U.widget_unit;
+ rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
- wcol->inner[0] = min_ii(wcol->inner[0] + 15, 255);
- wcol->inner[1] = min_ii(wcol->inner[1] + 15, 255);
- wcol->inner[2] = min_ii(wcol->inner[2] + 15, 255);
- wcol->outline[0] = min_ii(wcol->outline[0] + 15, 255);
- wcol->outline[1] = min_ii(wcol->outline[1] + 15, 255);
- wcol->outline[2] = min_ii(wcol->outline[2] + 15, 255);
-
/* decoration */
widgetbase_draw(&wtb, wcol);
- *wcol = wcol_backup;
}
static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
- if (state & UI_ACTIVE) {
+ float back[4];
+ UI_GetThemeColor4fv(TH_BACK, back);
+
+ if ((state & UI_ACTIVE) || (back[3] < 1.0f)) {
uiWidgetBase wtb;
- const float rad = 0.2f * U.widget_unit;
+ const float rad = wcol->roundness * U.widget_unit;
+
+ if (state & UI_ACTIVE) {
+ copy_v4_v4_char(wcol->inner, wcol->inner_sel);
+ copy_v3_v3_char(wcol->text, wcol->text_sel);
+ copy_v3_v3_char(wcol->outline, wcol->inner);
+ }
+ else {
+ wcol->inner[3] *= 1.0f - back[3];
+ wcol->outline[3] = 0.0f;
+ }
widget_init(&wtb);
@@ -3282,7 +3580,7 @@ static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *r
wtb.draw_emboss = false;
- rad = 0.5f * BLI_rcti_size_y(rect);
+ rad = wcol->roundness * BLI_rcti_size_y(rect);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
wcol->inner[3] *= fac;
@@ -3302,9 +3600,9 @@ static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widget_init(&wtb);
- /* rounded, but no outline */
+ /* no outline */
wtb.draw_outline = false;
- rad = 0.2f * U.widget_unit;
+ rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -3329,8 +3627,7 @@ static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UN
recttemp.xmax -= delta;
recttemp.ymax -= delta;
- /* half rounded */
- rad = BLI_rcti_size_y(&recttemp) / 3;
+ rad = wcol->roundness * BLI_rcti_size_y(&recttemp);
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
/* decoration */
@@ -3362,6 +3659,11 @@ static void widget_state_label(uiWidgetType *wt, int state)
else
UI_GetThemeColor3ubv(TH_TEXT, (unsigned char *)wt->wcol.text);
}
+
+ if (state & UI_BUT_REDALERT) {
+ char red[4] = {255, 0, 0};
+ widget_state_blend(wt->wcol.text, red, 0.4f);
+ }
}
static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
@@ -3371,8 +3673,7 @@ static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
widget_init(&wtb);
- /* half rounded */
- rad = 0.2f * U.widget_unit;
+ rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -3393,10 +3694,10 @@ static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(
wcol->inner[0] = but->col[0];
wcol->inner[1] = but->col[1];
wcol->inner[2] = but->col[2];
+ wcol->inner[3] = but->col[3];
}
- /* half rounded */
- rad = 0.2f * U.widget_unit;
+ rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -3411,8 +3712,7 @@ static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int
widget_init(&wtb);
- /* half rounded */
- rad = 0.2f * U.widget_unit;
+ rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
@@ -3422,7 +3722,7 @@ static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int
static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
{
uiWidgetBase wtb;
- const float rad = 0.25f * U.widget_unit;
+ const float rad = wcol->roundness * U.widget_unit;
widget_init(&wtb);
@@ -3436,7 +3736,7 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
uiWidgetBase wtb;
- const float rad = 0.25f * U.widget_unit;
+ const float rad = wcol->roundness * U.widget_unit;
widget_init(&wtb);
@@ -3451,10 +3751,61 @@ static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, in
widgetbase_draw(&wtb, wcol);
}
+static void widget_tab(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
+{
+ const float rad = wcol->roundness * U.widget_unit;
+ const bool is_active = (state & UI_SELECT);
+
+/* Draw shaded outline - Disabled for now, seems incorrect and also looks nicer without it imho ;) */
+//#define USE_TAB_SHADED_HIGHLIGHT
+
+ uiWidgetBase wtb;
+ unsigned char theme_col_tab_highlight[3];
+
+#ifdef USE_TAB_SHADED_HIGHLIGHT
+ /* create outline highlight colors */
+ if (is_active) {
+ interp_v3_v3v3_uchar(theme_col_tab_highlight, (unsigned char *)wcol->inner_sel,
+ (unsigned char *)wcol->outline, 0.2f);
+ }
+ else {
+ interp_v3_v3v3_uchar(theme_col_tab_highlight, (unsigned char *)wcol->inner,
+ (unsigned char *)wcol->outline, 0.12f);
+ }
+#endif
+
+ widget_init(&wtb);
+
+ /* half rounded */
+ round_box_edges(&wtb, roundboxalign, rect, rad);
+
+ /* draw inner */
+#ifdef USE_TAB_SHADED_HIGHLIGHT
+ wtb.draw_outline = 0;
+#endif
+ widgetbase_draw(&wtb, wcol);
+
+ /* We are drawing on top of widget bases. Flush cache. */
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
+
+#ifdef USE_TAB_SHADED_HIGHLIGHT
+ /* draw outline (3d look) */
+ ui_draw_but_TAB_outline(rect, rad, theme_col_tab_highlight, (unsigned char *)wcol->inner);
+#endif
+
+#ifndef USE_TAB_SHADED_HIGHLIGHT
+ UNUSED_VARS(is_active, theme_col_tab_highlight);
+#endif
+}
+
static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
{
+ bTheme *btheme = UI_GetTheme();
+ uiWidgetColors *wcol = &btheme->tui.wcol_radio;
uiWidgetBase wtb;
- const float rad = 0.25f * U.widget_unit;
+ const float rad = wcol->roundness * U.widget_unit;
unsigned char col[4];
/* state copy! */
@@ -3466,12 +3817,17 @@ static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *
/* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* make mask to draw over image */
UI_GetThemeColor3ubv(TH_BACK, col);
- glColor3ubv(col);
+ immUniformColor3ubv(col);
round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
- widgetbase_outline(&wtb);
+ widgetbase_outline(&wtb, pos);
+
+ immUnbindProgram();
}
/* outline */
@@ -3533,6 +3889,16 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.draw = widget_roundbut_exec;
break;
+ case UI_WTYPE_TOOLBAR_ITEM:
+ wt.wcol_theme = &btheme->tui.wcol_toolbar_item;
+ wt.draw = widget_roundbut_exec;
+ break;
+
+ case UI_WTYPE_TAB:
+ wt.wcol_theme = &btheme->tui.wcol_tab;
+ wt.draw = widget_tab;
+ break;
+
case UI_WTYPE_TOOLTIP:
wt.wcol_theme = &btheme->tui.wcol_tooltip;
wt.draw = widget_menu_back;
@@ -3562,6 +3928,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
break;
case UI_WTYPE_MENU_ICON_RADIO:
+ case UI_WTYPE_MENU_NODE_LINK:
wt.wcol_theme = &btheme->tui.wcol_menu;
wt.draw = widget_menuiconbut;
break;
@@ -3571,11 +3938,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.draw = widget_menubut;
break;
- case UI_WTYPE_MENU_NODE_LINK:
- wt.wcol_theme = &btheme->tui.wcol_menu;
- wt.draw = widget_menunodebut;
- break;
-
case UI_WTYPE_PULLDOWN:
wt.wcol_theme = &btheme->tui.wcol_pulldown;
wt.draw = widget_pulldownbut;
@@ -3655,7 +4017,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
/* alignment */
if ((but->drawflag & UI_BUT_ALIGN) && but->type != UI_BTYPE_PULLDOWN) {
- /* ui_block_position has this correction too, keep in sync */
+ /* ui_popup_block_position has this correction too, keep in sync */
if (but->drawflag & (UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_STITCH_TOP))
rect->ymax += U.pixelsize;
if (but->drawflag & (UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_STITCH_LEFT))
@@ -3693,7 +4055,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
}
/* align with open menu */
- if (but->active) {
+ if (but->active && (but->type != UI_BTYPE_POPOVER)) {
int direction = ui_but_menu_direction(but);
if (direction == UI_DIR_UP) roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT);
@@ -3717,6 +4079,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
uiFontStyle *fstyle = &style->widget;
uiWidgetType *wt = NULL;
+#ifdef USE_UI_POPOVER_ONCE
+ const rcti rect_orig = *rect;
+#endif
+
/* handle menus separately */
if (but->dt == UI_EMBOSS_PULLDOWN) {
switch (but->type) {
@@ -3764,10 +4130,20 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
case UI_BTYPE_SEPR:
case UI_BTYPE_SEPR_LINE:
+ case UI_BTYPE_SEPR_SPACER:
break;
case UI_BTYPE_BUT:
+#ifdef USE_UI_TOOLBAR_HACK
+ if (UI_but_is_tool(but)) {
+ wt = widget_type(UI_WTYPE_TOOLBAR_ITEM);
+ }
+ else {
+ wt = widget_type(UI_WTYPE_EXEC);
+ }
+#else
wt = widget_type(UI_WTYPE_EXEC);
+#endif
break;
case UI_BTYPE_NUM:
@@ -3797,6 +4173,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
}
break;
+ case UI_BTYPE_TAB:
+ wt = widget_type(UI_WTYPE_TAB);
+ break;
+
case UI_BTYPE_BUT_TOGGLE:
case UI_BTYPE_TOGGLE:
case UI_BTYPE_TOGGLE_N:
@@ -3820,6 +4200,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
case UI_BTYPE_MENU:
case UI_BTYPE_BLOCK:
+ case UI_BTYPE_POPOVER:
if (but->flag & UI_BUT_NODE_LINK) {
/* new node-link button, not active yet XXX */
wt = widget_type(UI_WTYPE_MENU_NODE_LINK);
@@ -3859,13 +4240,6 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
wt = widget_type(UI_WTYPE_BOX);
break;
- case UI_BTYPE_LINK:
- case UI_BTYPE_INLINK:
- wt = widget_type(UI_WTYPE_ICON);
- wt->custom = widget_link;
-
- break;
-
case UI_BTYPE_EXTRA:
widget_draw_extra_mask(C, but, widget_type(UI_WTYPE_BOX), rect);
break;
@@ -3962,6 +4336,15 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
state |= UI_STATE_HOLD_ACTION;
}
+ if (state & UI_ACTIVE) {
+ if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
+ state |= UI_STATE_ACTIVE_LEFT;
+ }
+ else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
+ state |= UI_STATE_ACTIVE_RIGHT;
+ }
+ }
+
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE))
if (but->dt != UI_EMBOSS_PULLDOWN)
disabled = true;
@@ -3976,10 +4359,29 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
wt->draw(&wt->wcol, rect, state, roundboxalign);
if (disabled)
- glEnable(GL_BLEND);
+ GPU_blend(true);
+
+#ifdef USE_UI_POPOVER_ONCE
+ if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
+ if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
+ uiWidgetType wt_back = *wt;
+ uiWidgetType *wt_temp = widget_type(UI_WTYPE_MENU_ITEM);
+ wt_temp->state(wt_temp, state);
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
+ wt->wcol.inner[3] = 128;
+ wt->wcol.roundness = 0.5f;
+ ui_draw_roundbox(
+ &rect_orig,
+ 0.25f * min_ff(BLI_rcti_size_x(&rect_orig), BLI_rcti_size_y(&rect_orig)),
+ &wt_temp->wcol);
+ *wt = wt_back;
+ }
+ }
+#endif
+
wt->text(fstyle, &wt->wcol, but, rect);
if (disabled)
- glDisable(GL_BLEND);
+ GPU_blend(false);
// if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE))
// if (but->dt != UI_EMBOSS_PULLDOWN)
@@ -3987,6 +4389,28 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
}
}
+static void ui_draw_clip_tri(uiBlock *block, rcti *rect, uiWidgetType *wt)
+{
+ if (block) {
+ float draw_color[4];
+ unsigned char *color = (unsigned char *)wt->wcol.text;
+
+ draw_color[0] = ((float)color[0]) / 255.0f;
+ draw_color[1] = ((float)color[1]) / 255.0f;
+ draw_color[2] = ((float)color[2]) / 255.0f;
+ draw_color[3] = 1.0f;
+
+ if (block->flag & UI_BLOCK_CLIPTOP) {
+ /* XXX no scaling for UI here yet */
+ UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 8, 't', draw_color);
+ }
+ if (block->flag & UI_BLOCK_CLIPBOTTOM) {
+ /* XXX no scaling for UI here yet */
+ UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v', draw_color);
+ }
+ }
+}
+
void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
@@ -3997,18 +4421,79 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
else
wt->draw(&wt->wcol, rect, 0, 0);
- if (block) {
- if (block->flag & UI_BLOCK_CLIPTOP) {
- /* XXX no scaling for UI here yet */
- glColor3ubv((unsigned char *)wt->wcol.text);
- UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 8, 't');
+ ui_draw_clip_tri(block, rect, wt);
+}
+
+/**
+ * Similar to 'widget_menu_back', however we can't use the widget preset system
+ * because we need to pass in the original location so we know where to show the arrow.
+ */
+static void ui_draw_popover_back_impl(
+ const uiWidgetColors *wcol, rcti *rect, int direction, const float unit_size,
+ const float mval_origin[2])
+{
+ /* tsk, this isn't nice. */
+ const float unit_half = unit_size / 2;
+ const float cent_x = mval_origin ? mval_origin[0] : BLI_rcti_cent_x(rect);
+ rect->ymax -= unit_half;
+ rect->ymin += unit_half;
+
+ GPU_blend(true);
+
+ /* Extracted from 'widget_menu_back', keep separate to avoid menu changes breaking popovers */
+ {
+ uiWidgetBase wtb;
+ widget_init(&wtb);
+
+ const int roundboxalign = UI_CNR_ALL;
+ widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
+
+ round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
+ wtb.draw_emboss = false;
+ widgetbase_draw(&wtb, wcol);
+ }
+
+ /* Draw popover arrow (top/bottom) */
+ if (ELEM(direction, UI_DIR_UP, UI_DIR_DOWN)) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv((unsigned char *)wcol->inner);
+ GPU_blend(true);
+ immBegin(GPU_PRIM_TRIS, 3);
+ if (direction == UI_DIR_DOWN) {
+ const float y = rect->ymax;
+ immVertex2f(pos, cent_x - unit_half, y);
+ immVertex2f(pos, cent_x + unit_half, y);
+ immVertex2f(pos, cent_x, y + unit_half);
}
- if (block->flag & UI_BLOCK_CLIPBOTTOM) {
- /* XXX no scaling for UI here yet */
- glColor3ubv((unsigned char *)wt->wcol.text);
- UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v');
+ else {
+ const float y = rect->ymin;
+ immVertex2f(pos, cent_x - unit_half, y);
+ immVertex2f(pos, cent_x + unit_half, y);
+ immVertex2f(pos, cent_x, y - unit_half);
}
+ immEnd();
+ immUnbindProgram();
}
+
+ GPU_blend(false);
+}
+
+void ui_draw_popover_back(ARegion *ar, uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
+{
+ uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
+
+ if (block) {
+ float mval_origin[2] = {block->mx, block->my};
+ ui_window_to_block_fl(ar, block, &mval_origin[0], &mval_origin[1]);
+ ui_draw_popover_back_impl(wt->wcol_theme, rect, block->direction, U.widget_unit / block->aspect, mval_origin);
+ }
+ else {
+ wt->state(wt, 0);
+ wt->draw(&wt->wcol, rect, 0, 0);
+ }
+
+ ui_draw_clip_tri(block, rect, wt);
}
static void draw_disk_shaded(
@@ -4024,33 +4509,21 @@ static void draw_disk_shaded(
float y1, y2;
float fac;
unsigned char r_col[4];
+ unsigned int pos, col;
- glBegin(GL_TRIANGLE_STRIP);
-
- s = sinf(start);
- c = cosf(start);
-
- y1 = s * radius_int;
- y2 = s * radius_ext;
-
+ GPUVertFormat *format = immVertexFormat();
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (shaded) {
- fac = (y1 + radius_ext) * radius_ext_scale;
- round_box_shade_col4_r(r_col, col1, col2, fac);
-
- glColor4ubv(r_col);
+ col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
}
-
- glVertex2f(c * radius_int, s * radius_int);
-
- if (shaded) {
- fac = (y2 + radius_ext) * radius_ext_scale;
- round_box_shade_col4_r(r_col, col1, col2, fac);
-
- glColor4ubv(r_col);
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv((unsigned char *)col1);
}
- glVertex2f(c * radius_ext, s * radius_ext);
- for (i = 1; i < subd; i++) {
+ immBegin(GPU_PRIM_TRI_STRIP, subd * 2);
+ for (i = 0; i < subd; i++) {
float a;
a = start + ((i) / (float)(subd - 1)) * angle;
@@ -4062,20 +4535,20 @@ static void draw_disk_shaded(
if (shaded) {
fac = (y1 + radius_ext) * radius_ext_scale;
round_box_shade_col4_r(r_col, col1, col2, fac);
-
- glColor4ubv(r_col);
+ immAttr4ubv(col, r_col);
}
- glVertex2f(c * radius_int, s * radius_int);
+ immVertex2f(pos, c * radius_int, s * radius_int);
if (shaded) {
fac = (y2 + radius_ext) * radius_ext_scale;
round_box_shade_col4_r(r_col, col1, col2, fac);
-
- glColor4ubv(r_col);
+ immAttr4ubv(col, r_col);
}
- glVertex2f(c * radius_ext, s * radius_ext);
+ immVertex2f(pos, c * radius_ext, s * radius_ext);
}
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
void ui_draw_pie_center(uiBlock *block)
@@ -4086,26 +4559,25 @@ void ui_draw_pie_center(uiBlock *block)
float *pie_dir = block->pie_data.pie_dir;
- float pie_radius_internal = U.pixelsize * U.pie_menu_threshold;
- float pie_radius_external = U.pixelsize * (U.pie_menu_threshold + 7.0f);
+ float pie_radius_internal = U.dpi_fac * U.pie_menu_threshold;
+ float pie_radius_external = U.dpi_fac * (U.pie_menu_threshold + 7.0f);
int subd = 40;
float angle = atan2f(pie_dir[1], pie_dir[0]);
float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_2 : M_PI_4;
- glPushMatrix();
- glTranslatef(cx, cy, 0.0f);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(cx, cy);
- glEnable(GL_BLEND);
+ GPU_blend(true);
if (btheme->tui.wcol_pie_menu.shaded) {
char col1[4], col2[4];
shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown);
draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, col1, col2, true);
}
else {
- glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner);
- draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, NULL, NULL, false);
+ draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, btheme->tui.wcol_pie_menu.inner, NULL, false);
}
if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) {
@@ -4115,25 +4587,34 @@ void ui_draw_pie_center(uiBlock *block)
draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, col1, col2, true);
}
else {
- glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner_sel);
- draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, NULL, NULL, false);
+ draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, btheme->tui.wcol_pie_menu.inner_sel, NULL, false);
}
}
- glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.outline);
- glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_internal, subd);
- glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_external, subd);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv((unsigned char *)btheme->tui.wcol_pie_menu.outline);
+
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_internal, subd);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_external, subd);
+
+ immUnbindProgram();
if (U.pie_menu_confirm > 0 && !(block->pie_data.flags & (UI_PIE_INVALID_DIR | UI_PIE_CLICK_STYLE))) {
- float pie_confirm_radius = U.pixelsize * (pie_radius_internal + U.pie_menu_confirm);
- float pie_confirm_external = U.pixelsize * (pie_radius_internal + U.pie_menu_confirm + 7.0f);
+ float pie_confirm_radius = U.dpi_fac * (pie_radius_internal + U.pie_menu_confirm);
+ float pie_confirm_external = U.dpi_fac * (pie_radius_internal + U.pie_menu_confirm + 7.0f);
- glColor4ub(btheme->tui.wcol_pie_menu.text_sel[0], btheme->tui.wcol_pie_menu.text_sel[1], btheme->tui.wcol_pie_menu.text_sel[2], 64);
- draw_disk_shaded(angle - range / 2.0f, range, pie_confirm_radius, pie_confirm_external, subd, NULL, NULL, false);
+ const char col[4] = {btheme->tui.wcol_pie_menu.text_sel[0],
+ btheme->tui.wcol_pie_menu.text_sel[1],
+ btheme->tui.wcol_pie_menu.text_sel[2],
+ 64};
+
+ draw_disk_shaded(angle - range / 2.0f, range, pie_confirm_radius, pie_confirm_external, subd, col, NULL, false);
}
- glDisable(GL_BLEND);
- glPopMatrix();
+ GPU_blend(false);
+ GPU_matrix_pop();
}
@@ -4143,30 +4624,42 @@ uiWidgetColors *ui_tooltip_get_theme(void)
return wt->wcol_theme;
}
-void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *UNUSED(block), rcti *rect)
+/**
+ * Generic drawing for background.
+ */
+void ui_draw_widget_back_color(
+ uiWidgetTypeEnum type, bool use_shadow, const rcti *rect,
+ const float color[4])
{
- uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
+ uiWidgetType *wt = widget_type(type);
+
+ if (use_shadow) {
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ widget_softshadow(rect, UI_CNR_ALL, 0.25f * U.widget_unit);
+ GPU_blend(false);
+ }
+
+ rcti rect_copy = *rect;
wt->state(wt, 0);
- /* wt->draw ends up using same function to draw the tooltip as menu_back */
- wt->draw(&wt->wcol, rect, 0, 0);
+ if (color) {
+ rgba_float_to_uchar((unsigned char *)wt->wcol.inner, color);
+ }
+ wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL);
}
-
-void ui_draw_search_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
+void ui_draw_widget_back(uiWidgetTypeEnum type, bool use_shadow, const rcti *rect)
{
- uiWidgetType *wt = widget_type(UI_WTYPE_BOX);
-
- glEnable(GL_BLEND);
- widget_softshadow(rect, UI_CNR_ALL, 0.25f * U.widget_unit);
- glDisable(GL_BLEND);
+ ui_draw_widget_back_color(type, use_shadow, rect, NULL);
+}
+void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *UNUSED(block), rcti *rect)
+{
+ uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
wt->state(wt, 0);
- if (block)
- wt->draw(&wt->wcol, rect, block->flag, UI_CNR_ALL);
- else
- wt->draw(&wt->wcol, rect, 0, UI_CNR_ALL);
+ /* wt->draw ends up using same function to draw the tooltip as menu_back */
+ wt->draw(&wt->wcol, rect, 0, 0);
}
-
/* helper call to draw a menu item without button */
/* state: UI_ACTIVE or 0 */
void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, bool use_sep)
@@ -4217,8 +4710,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
}
- glColor4ubv((unsigned char *)wt->wcol.text);
- UI_fontstyle_draw(fstyle, rect, drawstr);
+ UI_fontstyle_draw(fstyle, rect, drawstr, (unsigned char *)wt->wcol.text);
}
/* part text right aligned */
@@ -4226,7 +4718,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
if (cpoin) {
fstyle->align = UI_STYLE_TEXT_RIGHT;
rect->xmax = _rect.xmax - 5;
- UI_fontstyle_draw(fstyle, rect, cpoin + 1);
+ UI_fontstyle_draw(fstyle, rect, cpoin + 1, (unsigned char *)wt->wcol.text);
*cpoin = UI_SEP_CHAR;
}
}
@@ -4242,9 +4734,9 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
height = ICON_SIZE_FROM_BUTRECT(rect);
aspect = ICON_DEFAULT_HEIGHT / height;
- glEnable(GL_BLEND);
- UI_icon_draw_aspect(xs, ys, iconid, aspect, 1.0f); /* XXX scale weak get from fstyle? */
- glDisable(GL_BLEND);
+ GPU_blend(true);
+ UI_icon_draw_aspect(xs, ys, iconid, aspect, 1.0f, wt->wcol.text); /* XXX scale weak get from fstyle? */
+ GPU_blend(false);
}
}
@@ -4261,9 +4753,9 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int
/* draw icon in rect above the space reserved for the label */
rect->ymin += text_size;
- glEnable(GL_BLEND);
+ GPU_blend(true);
widget_draw_preview(iconid, 1.0f, rect);
- glDisable(GL_BLEND);
+ GPU_blend(false);
BLF_width_and_height(fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
@@ -4284,8 +4776,7 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int
BLI_strncpy(drawstr, name, sizeof(drawstr));
UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
- glColor4ubv((unsigned char *)wt->wcol.text);
- UI_fontstyle_draw(fstyle, &trect, drawstr);
+ UI_fontstyle_draw(fstyle, &trect, drawstr, (unsigned char *)wt->wcol.text);
}
}
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 77c36bf47f3..09b8933206e 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -35,11 +35,9 @@
#include "MEM_guardedalloc.h"
-#include "DNA_curve_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
-#include "DNA_windowmanager_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -47,17 +45,20 @@
#include "BKE_addon.h"
#include "BKE_appdir.h"
-#include "BKE_colorband.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_mesh_runtime.h"
-#include "BIF_gl.h"
+#include "BLO_readfile.h" /* for UserDef version patching. */
+
+#include "BLF_api.h"
+
+#include "ED_screen.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "interface_intern.h"
+#include "GPU_framebuffer.h"
/* global for themes */
typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
@@ -75,7 +76,7 @@ static struct bThemeState g_theme_state = {
void ui_resources_init(void)
{
- UI_icons_init(BIFICONID_LAST);
+ UI_icons_init();
}
void ui_resources_free(void)
@@ -94,6 +95,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
static char error[4] = {240, 0, 240, 255};
static char alert[4] = {240, 60, 60, 255};
static char headerdesel[4] = {0, 0, 0, 255};
+ static char back[4] = {0, 0, 0, 255};
static char setting = 0;
const char *cp = error;
@@ -154,18 +156,18 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case SPACE_CONSOLE:
ts = &btheme->tconsole;
break;
- case SPACE_TIME:
- ts = &btheme->ttime;
- break;
case SPACE_NODE:
ts = &btheme->tnode;
break;
- case SPACE_LOGIC:
- ts = &btheme->tlogic;
- break;
case SPACE_CLIP:
ts = &btheme->tclip;
break;
+ case SPACE_TOPBAR:
+ ts = &btheme->ttopbar;
+ break;
+ case SPACE_STATUSBAR:
+ ts = &btheme->tstatusbar;
+ break;
default:
ts = &btheme->tv3d;
break;
@@ -179,8 +181,16 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->list;
else if (theme_regionid == RGN_TYPE_HEADER)
cp = ts->header;
+ else if (theme_regionid == RGN_TYPE_NAV_BAR)
+ cp = ts->navigation_bar;
else
cp = ts->button;
+
+ copy_v4_v4_char(back, cp);
+ if (!ED_region_is_overlap(spacetype, theme_regionid)) {
+ back[3] = 255;
+ }
+ cp = back;
break;
case TH_LOW_GRAD:
cp = ts->gradients.gradient;
@@ -231,6 +241,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
headerdesel[0] = cp[0] > 10 ? cp[0] - 10 : 0;
headerdesel[1] = cp[1] > 10 ? cp[1] - 10 : 0;
headerdesel[2] = cp[2] > 10 ? cp[2] - 10 : 0;
+ headerdesel[3] = cp[3];
cp = headerdesel;
break;
case TH_HEADER_TEXT:
@@ -242,14 +253,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->panelcolors.header; break;
case TH_PANEL_BACK:
cp = ts->panelcolors.back; break;
- case TH_PANEL_SHOW_HEADER:
- cp = &setting;
- setting = ts->panelcolors.show_header;
- break;
- case TH_PANEL_SHOW_BACK:
- cp = &setting;
- setting = ts->panelcolors.show_back;
- break;
+ case TH_PANEL_SUB_BACK:
+ cp = ts->panelcolors.sub_back; break;
case TH_BUTBACK:
cp = ts->button; break;
@@ -378,6 +383,10 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->keytype_jitter; break;
case TH_KEYTYPE_JITTER_SELECT:
cp = ts->keytype_jitter_select; break;
+ case TH_KEYTYPE_MOVEHOLD:
+ cp = ts->keytype_movehold; break;
+ case TH_KEYTYPE_MOVEHOLD_SELECT:
+ cp = ts->keytype_movehold_select; break;
case TH_KEYBORDER:
cp = ts->keyborder; break;
case TH_KEYBORDER_SELECT:
@@ -541,6 +550,9 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_DOPESHEET_CHANNELSUBOB:
cp = ts->ds_subchannel;
break;
+ case TH_DOPESHEET_IPOLINE:
+ cp = ts->ds_ipoline;
+ break;
case TH_PREVIEW_BACK:
cp = ts->preview_back;
@@ -629,6 +641,9 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_ANIM_INACTIVE:
cp = ts->anim_non_active;
break;
+ case TH_ANIM_PREVIEW_RANGE:
+ cp = ts->anim_preview_range;
+ break;
case TH_NLA_TWEAK:
cp = ts->nla_tweaking;
@@ -659,6 +674,9 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_WIDGET_EMBOSS:
cp = btheme->tui.widget_emboss; break;
+ case TH_EDITOR_OUTLINE:
+ cp = btheme->tui.editor_outline;
+ break;
case TH_AXIS_X:
cp = btheme->tui.xaxis; break;
case TH_AXIS_Y:
@@ -666,6 +684,28 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_AXIS_Z:
cp = btheme->tui.zaxis; break;
+ case TH_GIZMO_HI:
+ cp = btheme->tui.gizmo_hi; break;
+ case TH_GIZMO_PRIMARY:
+ cp = btheme->tui.gizmo_primary; break;
+ case TH_GIZMO_SECONDARY:
+ cp = btheme->tui.gizmo_secondary; break;
+ case TH_GIZMO_A:
+ cp = btheme->tui.gizmo_a; break;
+ case TH_GIZMO_B:
+ cp = btheme->tui.gizmo_b; break;
+
+ case TH_ICON_COLLECTION:
+ cp = btheme->tui.icon_collection; break;
+ case TH_ICON_OBJECT:
+ cp = btheme->tui.icon_object; break;
+ case TH_ICON_OBJECT_DATA:
+ cp = btheme->tui.icon_object_data; break;
+ case TH_ICON_MODIFIER:
+ cp = btheme->tui.icon_modifier; break;
+ case TH_ICON_SHADING:
+ cp = btheme->tui.icon_shading; break;
+
case TH_INFO_SELECTED:
cp = ts->info_selected;
break;
@@ -706,136 +746,6 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
return (const unsigned char *)cp;
}
-/* use this call to init new bone color sets in Theme */
-static void ui_theme_init_boneColorSets(bTheme *btheme)
-{
- int i;
-
- /* define default color sets - currently we only define 15 of these, though that should be ample */
- /* set 1 */
- rgba_char_args_set(btheme->tarm[0].solid, 0x9a, 0x00, 0x00, 255);
- rgba_char_args_set(btheme->tarm[0].select, 0xbd, 0x11, 0x11, 255);
- rgba_char_args_set(btheme->tarm[0].active, 0xf7, 0x0a, 0x0a, 255);
- /* set 2 */
- rgba_char_args_set(btheme->tarm[1].solid, 0xf7, 0x40, 0x18, 255);
- rgba_char_args_set(btheme->tarm[1].select, 0xf6, 0x69, 0x13, 255);
- rgba_char_args_set(btheme->tarm[1].active, 0xfa, 0x99, 0x00, 255);
- /* set 3 */
- rgba_char_args_set(btheme->tarm[2].solid, 0x1e, 0x91, 0x09, 255);
- rgba_char_args_set(btheme->tarm[2].select, 0x59, 0xb7, 0x0b, 255);
- rgba_char_args_set(btheme->tarm[2].active, 0x83, 0xef, 0x1d, 255);
- /* set 4 */
- rgba_char_args_set(btheme->tarm[3].solid, 0x0a, 0x36, 0x94, 255);
- rgba_char_args_set(btheme->tarm[3].select, 0x36, 0x67, 0xdf, 255);
- rgba_char_args_set(btheme->tarm[3].active, 0x5e, 0xc1, 0xef, 255);
- /* set 5 */
- rgba_char_args_set(btheme->tarm[4].solid, 0xa9, 0x29, 0x4e, 255);
- rgba_char_args_set(btheme->tarm[4].select, 0xc1, 0x41, 0x6a, 255);
- rgba_char_args_set(btheme->tarm[4].active, 0xf0, 0x5d, 0x91, 255);
- /* set 6 */
- rgba_char_args_set(btheme->tarm[5].solid, 0x43, 0x0c, 0x78, 255);
- rgba_char_args_set(btheme->tarm[5].select, 0x54, 0x3a, 0xa3, 255);
- rgba_char_args_set(btheme->tarm[5].active, 0x87, 0x64, 0xd5, 255);
- /* set 7 */
- rgba_char_args_set(btheme->tarm[6].solid, 0x24, 0x78, 0x5a, 255);
- rgba_char_args_set(btheme->tarm[6].select, 0x3c, 0x95, 0x79, 255);
- rgba_char_args_set(btheme->tarm[6].active, 0x6f, 0xb6, 0xab, 255);
- /* set 8 */
- rgba_char_args_set(btheme->tarm[7].solid, 0x4b, 0x70, 0x7c, 255);
- rgba_char_args_set(btheme->tarm[7].select, 0x6a, 0x86, 0x91, 255);
- rgba_char_args_set(btheme->tarm[7].active, 0x9b, 0xc2, 0xcd, 255);
- /* set 9 */
- rgba_char_args_set(btheme->tarm[8].solid, 0xf4, 0xc9, 0x0c, 255);
- rgba_char_args_set(btheme->tarm[8].select, 0xee, 0xc2, 0x36, 255);
- rgba_char_args_set(btheme->tarm[8].active, 0xf3, 0xff, 0x00, 255);
- /* set 10 */
- rgba_char_args_set(btheme->tarm[9].solid, 0x1e, 0x20, 0x24, 255);
- rgba_char_args_set(btheme->tarm[9].select, 0x48, 0x4c, 0x56, 255);
- rgba_char_args_set(btheme->tarm[9].active, 0xff, 0xff, 0xff, 255);
- /* set 11 */
- rgba_char_args_set(btheme->tarm[10].solid, 0x6f, 0x2f, 0x6a, 255);
- rgba_char_args_set(btheme->tarm[10].select, 0x98, 0x45, 0xbe, 255);
- rgba_char_args_set(btheme->tarm[10].active, 0xd3, 0x30, 0xd6, 255);
- /* set 12 */
- rgba_char_args_set(btheme->tarm[11].solid, 0x6c, 0x8e, 0x22, 255);
- rgba_char_args_set(btheme->tarm[11].select, 0x7f, 0xb0, 0x22, 255);
- rgba_char_args_set(btheme->tarm[11].active, 0xbb, 0xef, 0x5b, 255);
- /* set 13 */
- rgba_char_args_set(btheme->tarm[12].solid, 0x8d, 0x8d, 0x8d, 255);
- rgba_char_args_set(btheme->tarm[12].select, 0xb0, 0xb0, 0xb0, 255);
- rgba_char_args_set(btheme->tarm[12].active, 0xde, 0xde, 0xde, 255);
- /* set 14 */
- rgba_char_args_set(btheme->tarm[13].solid, 0x83, 0x43, 0x26, 255);
- rgba_char_args_set(btheme->tarm[13].select, 0x8b, 0x58, 0x11, 255);
- rgba_char_args_set(btheme->tarm[13].active, 0xbd, 0x6a, 0x11, 255);
- /* set 15 */
- rgba_char_args_set(btheme->tarm[14].solid, 0x08, 0x31, 0x0e, 255);
- rgba_char_args_set(btheme->tarm[14].select, 0x1c, 0x43, 0x0b, 255);
- rgba_char_args_set(btheme->tarm[14].active, 0x34, 0x62, 0x2b, 255);
-
- /* reset flags too */
- for (i = 0; i < 20; i++)
- btheme->tarm[i].flag = 0;
-}
-
-/* use this call to init new variables in themespace, if they're same for all */
-static void ui_theme_init_new_do(ThemeSpace *ts)
-{
- rgba_char_args_set(ts->header_text, 0, 0, 0, 255);
- rgba_char_args_set(ts->header_title, 0, 0, 0, 255);
- rgba_char_args_set(ts->header_text_hi, 255, 255, 255, 255);
-
-#if 0
- rgba_char_args_set(ts->panel_text, 0, 0, 0, 255);
- rgba_char_args_set(ts->panel_title, 0, 0, 0, 255);
- rgba_char_args_set(ts->panel_text_hi, 255, 255, 255, 255);
-#endif
-
- ts->panelcolors.show_back = false;
- ts->panelcolors.show_header = false;
- rgba_char_args_set(ts->panelcolors.back, 114, 114, 114, 128);
- rgba_char_args_set(ts->panelcolors.header, 0, 0, 0, 25);
-
- rgba_char_args_set(ts->button, 145, 145, 145, 245);
- rgba_char_args_set(ts->button_title, 0, 0, 0, 255);
- rgba_char_args_set(ts->button_text, 0, 0, 0, 255);
- rgba_char_args_set(ts->button_text_hi, 255, 255, 255, 255);
-
- rgba_char_args_set(ts->list, 165, 165, 165, 255);
- rgba_char_args_set(ts->list_title, 0, 0, 0, 255);
- rgba_char_args_set(ts->list_text, 0, 0, 0, 255);
- rgba_char_args_set(ts->list_text_hi, 255, 255, 255, 255);
-
- rgba_char_args_set(ts->tab_active, 114, 114, 114, 255);
- rgba_char_args_set(ts->tab_inactive, 83, 83, 83, 255);
- rgba_char_args_set(ts->tab_back, 64, 64, 64, 255);
- rgba_char_args_set(ts->tab_outline, 60, 60, 60, 255);
-}
-
-static void ui_theme_init_new(bTheme *btheme)
-{
- ThemeSpace *ts;
-
- for (ts = UI_THEMESPACE_START(btheme); ts != UI_THEMESPACE_END(btheme); ts++) {
- ui_theme_init_new_do(ts);
- }
-}
-
-static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
-{
- rgba_char_args_set(theme_space->handle_free, 0, 0, 0, 255);
- rgba_char_args_set(theme_space->handle_auto, 0x90, 0x90, 0x00, 255);
- rgba_char_args_set(theme_space->handle_vect, 0x40, 0x90, 0x30, 255);
- rgba_char_args_set(theme_space->handle_align, 0x80, 0x30, 0x60, 255);
- rgba_char_args_set(theme_space->handle_sel_free, 0, 0, 0, 255);
- rgba_char_args_set(theme_space->handle_sel_auto, 0xf0, 0xff, 0x40, 255);
- rgba_char_args_set(theme_space->handle_sel_vect, 0x40, 0xc0, 0x30, 255);
- rgba_char_args_set(theme_space->handle_sel_align, 0xf0, 0x90, 0xa0, 255);
- rgba_char_args_set(theme_space->handle_vertex, 0x00, 0x00, 0x00, 0xff);
- rgba_char_args_set(theme_space->handle_vertex_select, 0xff, 0xff, 0, 0xff);
- rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255);
-}
-
/**
* initialize default theme
* \note: when you add new colors, created & saved themes need initialized
@@ -843,370 +753,19 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
*/
void ui_theme_init_default(void)
{
- bTheme *btheme;
/* we search for the theme with name Default */
- btheme = BLI_findstring(&U.themes, "Default", offsetof(bTheme, name));
-
+ bTheme *btheme = BLI_findstring(&U.themes, "Default", offsetof(bTheme, name));
if (btheme == NULL) {
- btheme = MEM_callocN(sizeof(bTheme), "theme");
+ btheme = MEM_callocN(sizeof(bTheme), __func__);
BLI_addtail(&U.themes, btheme);
- strcpy(btheme->name, "Default");
}
UI_SetTheme(0, 0); /* make sure the global used in this file is set */
- /* UI buttons */
- ui_widget_color_init(&btheme->tui);
-
- btheme->tui.iconfile[0] = 0;
- rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255);
- rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f);
-
- rgba_char_args_set(btheme->tui.xaxis, 220, 0, 0, 255);
- rgba_char_args_set(btheme->tui.yaxis, 0, 220, 0, 255);
- rgba_char_args_set(btheme->tui.zaxis, 0, 0, 220, 255);
-
- btheme->tui.menu_shadow_fac = 0.5f;
- btheme->tui.menu_shadow_width = 12;
-
- /* Bone Color Sets */
- ui_theme_init_boneColorSets(btheme);
-
- /* common (new) variables */
- ui_theme_init_new(btheme);
-
- /* space view3d */
- rgba_char_args_set_fl(btheme->tv3d.back, 0.225, 0.225, 0.225, 1.0);
- rgba_char_args_set(btheme->tv3d.text, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.text_hi, 255, 255, 255, 255);
-
- rgba_char_args_set_fl(btheme->tv3d.header, 0.45, 0.45, 0.45, 1.0);
- rgba_char_args_set_fl(btheme->tv3d.button, 0.45, 0.45, 0.45, 0.5);
-// rgba_char_args_set(btheme->tv3d.panel, 165, 165, 165, 127);
-
- rgba_char_args_set(btheme->tv3d.shade1, 160, 160, 160, 100);
- rgba_char_args_set(btheme->tv3d.shade2, 0x7f, 0x70, 0x70, 100);
-
- rgba_char_args_set_fl(btheme->tv3d.grid, 0.251, 0.251, 0.251, 1.0);
- rgba_char_args_set(btheme->tv3d.view_overlay, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.wire, 0x0, 0x0, 0x0, 255);
- rgba_char_args_set(btheme->tv3d.wire_edit, 0x0, 0x0, 0x0, 255);
- rgba_char_args_set(btheme->tv3d.lamp, 0, 0, 0, 40);
- rgba_char_args_set(btheme->tv3d.speaker, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.camera, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.empty, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.select, 241, 88, 0, 255);
- rgba_char_args_set(btheme->tv3d.active, 255, 170, 64, 255);
- rgba_char_args_set(btheme->tv3d.group, 8, 48, 8, 255);
- rgba_char_args_set(btheme->tv3d.group_active, 85, 187, 85, 255);
- rgba_char_args_set(btheme->tv3d.transform, 0xff, 0xff, 0xff, 255);
- rgba_char_args_set(btheme->tv3d.vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.vertex_select, 255, 133, 0, 255);
- rgba_char_args_set(btheme->tv3d.vertex_bevel, 0, 165, 255, 255);
- rgba_char_args_set(btheme->tv3d.vertex_unreferenced, 0, 0, 0, 255);
- btheme->tv3d.vertex_size = 3;
- btheme->tv3d.outline_width = 1;
- rgba_char_args_set(btheme->tv3d.edge, 0x0, 0x0, 0x0, 255);
- rgba_char_args_set(btheme->tv3d.edge_select, 255, 160, 0, 255);
- rgba_char_args_set(btheme->tv3d.edge_seam, 219, 37, 18, 255);
- rgba_char_args_set(btheme->tv3d.edge_bevel, 0, 165, 255, 255);
- rgba_char_args_set(btheme->tv3d.edge_facesel, 75, 75, 75, 255);
- rgba_char_args_set(btheme->tv3d.face, 0, 0, 0, 18);
- rgba_char_args_set(btheme->tv3d.face_select, 255, 133, 0, 60);
- rgba_char_args_set(btheme->tv3d.normal, 0x22, 0xDD, 0xDD, 255);
- rgba_char_args_set(btheme->tv3d.vertex_normal, 0x23, 0x61, 0xDD, 255);
- rgba_char_args_set(btheme->tv3d.loop_normal, 0xDD, 0x23, 0xDD, 255);
- rgba_char_args_set(btheme->tv3d.face_dot, 255, 133, 0, 255);
- rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128);
- rgba_char_args_set_fl(btheme->tv3d.edge_crease, 0.8, 0, 0.6, 1.0);
- rgba_char_args_set(btheme->tv3d.edge_sharp, 0, 255, 255, 255);
- rgba_char_args_set(btheme->tv3d.header_text, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.header_text_hi, 255, 255, 255, 255);
- rgba_char_args_set(btheme->tv3d.button_text, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.button_text_hi, 255, 255, 255, 255);
- rgba_char_args_set(btheme->tv3d.button_title, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.title, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
- rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
- rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
- rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
- rgba_char_args_set(btheme->tv3d.gp_vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.gp_vertex_select, 255, 133, 0, 255);
- btheme->tv3d.gp_vertex_size = 3;
-
- btheme->tv3d.facedot_size = 4;
-
- rgba_char_args_set(btheme->tv3d.extra_edge_len, 32, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.extra_edge_angle, 32, 32, 0, 255);
- rgba_char_args_set(btheme->tv3d.extra_face_area, 0, 32, 0, 255);
- rgba_char_args_set(btheme->tv3d.extra_face_angle, 0, 0, 128, 255);
-
- rgba_char_args_set(btheme->tv3d.cframe, 0x60, 0xc0, 0x40, 255);
-
- rgba_char_args_set(btheme->tv3d.nurb_uline, 0x90, 0x90, 0x00, 255);
- rgba_char_args_set(btheme->tv3d.nurb_vline, 0x80, 0x30, 0x60, 255);
- rgba_char_args_set(btheme->tv3d.nurb_sel_uline, 0xf0, 0xff, 0x40, 255);
- rgba_char_args_set(btheme->tv3d.nurb_sel_vline, 0xf0, 0x90, 0xa0, 255);
-
- ui_theme_space_init_handles_color(&btheme->tv3d);
-
- rgba_char_args_set(btheme->tv3d.act_spline, 0xdb, 0x25, 0x12, 255);
- rgba_char_args_set(btheme->tv3d.lastsel_point, 0xff, 0xff, 0xff, 255);
-
- rgba_char_args_set(btheme->tv3d.bone_solid, 200, 200, 200, 255);
- /* alpha 80 is not meant editable, used for wire+action draw */
- rgba_char_args_set(btheme->tv3d.bone_pose, 80, 200, 255, 80);
- rgba_char_args_set(btheme->tv3d.bone_pose_active, 140, 255, 255, 80);
-
- rgba_char_args_set(btheme->tv3d.bundle_solid, 200, 200, 200, 255);
- rgba_char_args_set(btheme->tv3d.camera_path, 0x00, 0x00, 0x00, 255);
-
- rgba_char_args_set(btheme->tv3d.skin_root, 180, 77, 77, 255);
- rgba_char_args_set(btheme->tv3d.gradients.gradient, 0, 0, 0, 0);
- rgba_char_args_set(btheme->tv3d.gradients.high_gradient, 58, 58, 58, 255);
- btheme->tv3d.gradients.show_grad = false;
-
- rgba_char_args_set(btheme->tv3d.clipping_border_3d, 50, 50, 50, 255);
-
- rgba_char_args_set(btheme->tv3d.time_keyframe, 0xDD, 0xD7, 0x00, 0xFF);
- rgba_char_args_set(btheme->tv3d.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 0xFF);
-
- /* space buttons */
- /* to have something initialized */
- btheme->tbuts = btheme->tv3d;
-
- rgba_char_args_set_fl(btheme->tbuts.back, 0.45, 0.45, 0.45, 1.0);
-// rgba_char_args_set(btheme->tbuts.panel, 0x82, 0x82, 0x82, 255);
-
- /* graph editor */
- btheme->tipo = btheme->tv3d;
- rgba_char_args_set_fl(btheme->tipo.back, 0.42, 0.42, 0.42, 1.0);
- rgba_char_args_set_fl(btheme->tipo.list, 0.4, 0.4, 0.4, 1.0);
- rgba_char_args_set(btheme->tipo.grid, 94, 94, 94, 255);
-// rgba_char_args_set(btheme->tipo.panel, 255, 255, 255, 150);
- rgba_char_args_set(btheme->tipo.shade1, 150, 150, 150, 100); /* scrollbars */
- rgba_char_args_set(btheme->tipo.shade2, 0x70, 0x70, 0x70, 100);
- rgba_char_args_set(btheme->tipo.vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tipo.vertex_select, 255, 133, 0, 255);
- rgba_char_args_set(btheme->tipo.hilite, 0x60, 0xc0, 0x40, 255);
- btheme->tipo.vertex_size = 6;
-
- rgba_char_args_set(btheme->tipo.handle_vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tipo.handle_vertex_select, 255, 133, 0, 255);
- rgba_char_args_set(btheme->tipo.handle_auto_clamped, 0x99, 0x40, 0x30, 255);
- rgba_char_args_set(btheme->tipo.handle_sel_auto_clamped, 0xf0, 0xaf, 0x90, 255);
- btheme->tipo.handle_vertex_size = 5;
-
- rgba_char_args_set(btheme->tipo.ds_channel, 82, 96, 110, 255);
- rgba_char_args_set(btheme->tipo.ds_subchannel, 124, 137, 150, 255);
- rgba_char_args_set(btheme->tipo.group, 79, 101, 73, 255);
- rgba_char_args_set(btheme->tipo.group_active, 135, 177, 125, 255);
-
- /* dopesheet */
- btheme->tact = btheme->tipo;
- rgba_char_args_set(btheme->tact.strip, 12, 10, 10, 128);
- rgba_char_args_set(btheme->tact.strip_select, 255, 140, 0, 255);
-
- rgba_char_args_set(btheme->tact.anim_active, 204, 112, 26, 102);
-
- rgba_char_args_set(btheme->tact.keytype_keyframe, 232, 232, 232, 255);
- rgba_char_args_set(btheme->tact.keytype_keyframe_select, 255, 190, 50, 255);
- rgba_char_args_set(btheme->tact.keytype_extreme, 232, 179, 204, 255);
- rgba_char_args_set(btheme->tact.keytype_extreme_select, 242, 128, 128, 255);
- rgba_char_args_set(btheme->tact.keytype_breakdown, 179, 219, 232, 255);
- rgba_char_args_set(btheme->tact.keytype_breakdown_select, 84, 191, 237, 255);
- rgba_char_args_set(btheme->tact.keytype_jitter, 148, 229, 117, 255);
- rgba_char_args_set(btheme->tact.keytype_jitter_select, 97, 192, 66, 255);
-
- rgba_char_args_set(btheme->tact.keyborder, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tact.keyborder_select, 0, 0, 0, 255);
-
- btheme->tact.keyframe_scale_fac = 1.0f;
-
- /* space nla */
- btheme->tnla = btheme->tact;
-
- rgba_char_args_set(btheme->tnla.anim_active, 204, 112, 26, 102); /* same as for dopesheet; duplicate here for easier reference */
- rgba_char_args_set(btheme->tnla.anim_non_active, 153, 135, 97, 77);
-
- rgba_char_args_set(btheme->tnla.nla_tweaking, 77, 243, 26, 77);
- rgba_char_args_set(btheme->tnla.nla_tweakdupli, 217, 0, 0, 255);
-
- rgba_char_args_set(btheme->tnla.nla_transition, 28, 38, 48, 255);
- rgba_char_args_set(btheme->tnla.nla_transition_sel, 46, 117, 219, 255);
- rgba_char_args_set(btheme->tnla.nla_meta, 51, 38, 66, 255);
- rgba_char_args_set(btheme->tnla.nla_meta_sel, 105, 33, 150, 255);
- rgba_char_args_set(btheme->tnla.nla_sound, 43, 61, 61, 255);
- rgba_char_args_set(btheme->tnla.nla_sound_sel, 31, 122, 122, 255);
-
- rgba_char_args_set(btheme->tnla.keyborder, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tnla.keyborder_select, 0, 0, 0, 255);
-
- /* space file */
- /* to have something initialized */
- btheme->tfile = btheme->tv3d;
- rgba_char_args_set_fl(btheme->tfile.back, 0.3, 0.3, 0.3, 1);
-// rgba_char_args_set_fl(btheme->tfile.panel, 0.3, 0.3, 0.3, 1);
- rgba_char_args_set_fl(btheme->tfile.list, 0.4, 0.4, 0.4, 1);
- rgba_char_args_set(btheme->tfile.text, 250, 250, 250, 255);
- rgba_char_args_set(btheme->tfile.text_hi, 15, 15, 15, 255);
-// rgba_char_args_set(btheme->tfile.panel, 145, 145, 145, 255); /* bookmark/ui regions */
- rgba_char_args_set(btheme->tfile.hilite, 255, 140, 25, 255); /* selected files */
-
- rgba_char_args_set(btheme->tfile.image, 250, 250, 250, 255);
- rgba_char_args_set(btheme->tfile.movie, 250, 250, 250, 255);
- rgba_char_args_set(btheme->tfile.scene, 250, 250, 250, 255);
-
-
- /* space seq */
- btheme->tseq = btheme->tv3d;
- rgba_char_args_set(btheme->tseq.back, 116, 116, 116, 255);
- rgba_char_args_set(btheme->tseq.movie, 81, 105, 135, 255);
- rgba_char_args_set(btheme->tseq.movieclip, 32, 32, 143, 255);
- rgba_char_args_set(btheme->tseq.mask, 152, 78, 62, 255);
- rgba_char_args_set(btheme->tseq.image, 109, 88, 129, 255);
- rgba_char_args_set(btheme->tseq.scene, 78, 152, 62, 255);
- rgba_char_args_set(btheme->tseq.audio, 46, 143, 143, 255);
- rgba_char_args_set(btheme->tseq.effect, 169, 84, 124, 255);
- rgba_char_args_set(btheme->tseq.transition, 162, 95, 111, 255);
- rgba_char_args_set(btheme->tseq.meta, 109, 145, 131, 255);
- rgba_char_args_set(btheme->tseq.text_strip, 162, 151, 0, 255);
- rgba_char_args_set(btheme->tseq.preview_back, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tseq.grid, 64, 64, 64, 255);
-
- /* space image */
- btheme->tima = btheme->tv3d;
- rgba_char_args_set(btheme->tima.back, 53, 53, 53, 255);
- rgba_char_args_set(btheme->tima.vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tima.vertex_select, 255, 133, 0, 255);
- rgba_char_args_set(btheme->tima.wire_edit, 192, 192, 192, 255);
- rgba_char_args_set(btheme->tima.edge_select, 255, 133, 0, 255);
- btheme->tima.vertex_size = 3;
- btheme->tima.facedot_size = 3;
- rgba_char_args_set(btheme->tima.face, 255, 255, 255, 10);
- rgba_char_args_set(btheme->tima.face_select, 255, 133, 0, 60);
- rgba_char_args_set(btheme->tima.editmesh_active, 255, 255, 255, 128);
- rgba_char_args_set_fl(btheme->tima.preview_back, 0.0, 0.0, 0.0, 0.3);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_face, 0.5, 0.5, 0.0, 0.2);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_edge, 1.0, 0.0, 1.0, 0.2);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_vert, 0.0, 0.0, 1.0, 0.2);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_stitchable, 0.0, 1.0, 0.0, 1.0);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140);
-
- rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255);
- rgba_char_args_test_set(btheme->tima.uv_shadow, 112, 112, 112, 255);
-
- ui_theme_space_init_handles_color(&btheme->tima);
- btheme->tima.handle_vertex_size = 5;
-
- /* space text */
- btheme->text = btheme->tv3d;
- rgba_char_args_set(btheme->text.back, 153, 153, 153, 255);
- rgba_char_args_set(btheme->text.shade1, 143, 143, 143, 255);
- rgba_char_args_set(btheme->text.shade2, 0xc6, 0x77, 0x77, 255);
- rgba_char_args_set(btheme->text.hilite, 255, 0, 0, 255);
-
- /* syntax highlighting */
- rgba_char_args_set(btheme->text.syntaxn, 0, 0, 200, 255); /* Numbers Blue*/
- rgba_char_args_set(btheme->text.syntaxl, 100, 0, 0, 255); /* Strings Red */
- rgba_char_args_set(btheme->text.syntaxc, 0, 100, 50, 255); /* Comments Greenish */
- rgba_char_args_set(btheme->text.syntaxv, 95, 95, 0, 255); /* Special Yellow*/
- rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */
- rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange*/
- rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin Red-purple */
- rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Gray (mix between fg/bg) */
-
- /* space oops */
- btheme->toops = btheme->tv3d;
- rgba_char_args_set_fl(btheme->toops.back, 0.45, 0.45, 0.45, 1.0);
-
- rgba_char_args_set_fl(btheme->toops.match, 0.2, 0.5, 0.2, 0.3); /* highlighting search match - soft green*/
- rgba_char_args_set_fl(btheme->toops.selected_highlight, 0.51, 0.53, 0.55, 0.3);
-
- /* space info */
- btheme->tinfo = btheme->tv3d;
- rgba_char_args_set_fl(btheme->tinfo.back, 0.45, 0.45, 0.45, 1.0);
- rgba_char_args_set(btheme->tinfo.info_selected, 96, 128, 255, 255);
- rgba_char_args_set(btheme->tinfo.info_selected_text, 255, 255, 255, 255);
- rgba_char_args_set(btheme->tinfo.info_error, 220, 0, 0, 255);
- rgba_char_args_set(btheme->tinfo.info_error_text, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tinfo.info_warning, 220, 128, 96, 255);
- rgba_char_args_set(btheme->tinfo.info_warning_text, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tinfo.info_info, 0, 170, 0, 255);
- rgba_char_args_set(btheme->tinfo.info_info_text, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tinfo.info_debug, 196, 196, 196, 255);
- rgba_char_args_set(btheme->tinfo.info_debug_text, 0, 0, 0, 255);
-
- /* space user preferences */
- btheme->tuserpref = btheme->tv3d;
- rgba_char_args_set_fl(btheme->tuserpref.back, 0.45, 0.45, 0.45, 1.0);
-
- /* space console */
- btheme->tconsole = btheme->tv3d;
- rgba_char_args_set(btheme->tconsole.back, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tconsole.console_output, 96, 128, 255, 255);
- rgba_char_args_set(btheme->tconsole.console_input, 255, 255, 255, 255);
- rgba_char_args_set(btheme->tconsole.console_info, 0, 170, 0, 255);
- rgba_char_args_set(btheme->tconsole.console_error, 220, 96, 96, 255);
- rgba_char_args_set(btheme->tconsole.console_cursor, 220, 96, 96, 255);
- rgba_char_args_set(btheme->tconsole.console_select, 255, 255, 255, 48);
-
- /* space time */
- btheme->ttime = btheme->tv3d;
- rgba_char_args_set_fl(btheme->ttime.back, 0.45, 0.45, 0.45, 1.0);
- rgba_char_args_set_fl(btheme->ttime.grid, 0.36, 0.36, 0.36, 1.0);
- rgba_char_args_set(btheme->ttime.shade1, 173, 173, 173, 255); /* sliders */
-
- rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 0xFF);
- rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 0xFF);
-
- /* space node, re-uses syntax and console color storage */
- btheme->tnode = btheme->tv3d;
- rgba_char_args_set(btheme->tnode.syntaxr, 115, 115, 115, 255); /* wire inner color */
- rgba_char_args_set(btheme->tnode.edge_select, 255, 255, 255, 255); /* wire selected */
- rgba_char_args_set(btheme->tnode.syntaxl, 155, 155, 155, 160); /* TH_NODE, backdrop */
- rgba_char_args_set(btheme->tnode.syntaxn, 100, 100, 100, 255); /* in */
- rgba_char_args_set(btheme->tnode.nodeclass_output, 100, 100, 100, 255); /* output */
- rgba_char_args_set(btheme->tnode.syntaxb, 108, 105, 111, 255); /* operator */
- rgba_char_args_set(btheme->tnode.syntaxv, 104, 106, 117, 255); /* generator */
- rgba_char_args_set(btheme->tnode.syntaxc, 105, 117, 110, 255); /* group */
- rgba_char_args_set(btheme->tnode.nodeclass_texture, 108, 105, 111, 255); /* operator */
- rgba_char_args_set(btheme->tnode.nodeclass_shader, 108, 105, 111, 255); /* operator */
- rgba_char_args_set(btheme->tnode.nodeclass_filter, 108, 105, 111, 255); /* operator */
- rgba_char_args_set(btheme->tnode.nodeclass_script, 108, 105, 111, 255); /* operator */
- rgba_char_args_set(btheme->tnode.nodeclass_pattern, 108, 105, 111, 255); /* operator */
- rgba_char_args_set(btheme->tnode.nodeclass_vector, 108, 105, 111, 255); /* operator */
- rgba_char_args_set(btheme->tnode.nodeclass_layout, 108, 105, 111, 255); /* operator */
- rgba_char_args_set(btheme->tnode.movie, 155, 155, 155, 160); /* frame */
- rgba_char_args_set(btheme->tnode.syntaxs, 151, 116, 116, 255); /* matte nodes */
- rgba_char_args_set(btheme->tnode.syntaxd, 116, 151, 151, 255); /* distort nodes */
- rgba_char_args_set(btheme->tnode.console_output, 223, 202, 53, 255); /* interface nodes */
- btheme->tnode.noodle_curving = 5;
-
- /* space logic */
- btheme->tlogic = btheme->tv3d;
- rgba_char_args_set(btheme->tlogic.back, 100, 100, 100, 255);
-
- /* space clip */
- btheme->tclip = btheme->tv3d;
-
- rgba_char_args_set(btheme->tclip.marker_outline, 0x00, 0x00, 0x00, 255);
- rgba_char_args_set(btheme->tclip.marker, 0x7f, 0x7f, 0x00, 255);
- rgba_char_args_set(btheme->tclip.act_marker, 0xff, 0xff, 0xff, 255);
- rgba_char_args_set(btheme->tclip.sel_marker, 0xff, 0xff, 0x00, 255);
- rgba_char_args_set(btheme->tclip.dis_marker, 0x7f, 0x00, 0x00, 255);
- rgba_char_args_set(btheme->tclip.lock_marker, 0x7f, 0x7f, 0x7f, 255);
- rgba_char_args_set(btheme->tclip.path_before, 0xff, 0x00, 0x00, 255);
- rgba_char_args_set(btheme->tclip.path_after, 0x00, 0x00, 0xff, 255);
- rgba_char_args_set(btheme->tclip.grid, 0x5e, 0x5e, 0x5e, 255);
- rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff);
- rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80);
- rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff);
- btheme->tclip.handle_vertex_size = 5;
- ui_theme_space_init_handles_color(&btheme->tclip);
+ const int active_theme_area = btheme->active_theme_area;
+ memcpy(btheme, &U_theme_default, sizeof(*btheme));
+ btheme->active_theme_area = active_theme_area;
}
void ui_style_init_default(void)
@@ -1256,42 +815,7 @@ void UI_Theme_Restore(struct bThemeState *theme_state)
g_theme_state = *theme_state;
}
-/* for space windows only */
-void UI_ThemeColor(int colorid)
-{
- const unsigned char *cp;
-
- cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
- glColor3ubv(cp);
-
-}
-
-/* plus alpha */
-void UI_ThemeColor4(int colorid)
-{
- const unsigned char *cp;
-
- cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
- glColor4ubv(cp);
-
-}
-
-/* set the color with offset for shades */
-void UI_ThemeColorShade(int colorid, int offset)
-{
- int r, g, b;
- const unsigned char *cp;
-
- cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
- r = offset + (int) cp[0];
- CLAMP(r, 0, 255);
- g = offset + (int) cp[1];
- CLAMP(g, 0, 255);
- b = offset + (int) cp[2];
- CLAMP(b, 0, 255);
- glColor4ub(r, g, b, cp[3]);
-}
-void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
+void UI_GetThemeColorShadeAlpha4ubv(int colorid, int coloffset, int alphaoffset, unsigned char col[4])
{
int r, g, b, a;
const unsigned char *cp;
@@ -1305,7 +829,11 @@ void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
CLAMP(b, 0, 255);
a = alphaoffset + (int) cp[3];
CLAMP(a, 0, 255);
- glColor4ub(r, g, b, a);
+
+ col[0] = r;
+ col[1] = g;
+ col[2] = b;
+ col[3] = a;
}
void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3])
@@ -1321,59 +849,26 @@ void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned c
col[2] = floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
}
-/* blend between to theme colors, and set it */
-void UI_ThemeColorBlend(int colorid1, int colorid2, float fac)
-{
- unsigned char col[3];
- UI_GetThemeColorBlend3ubv(colorid1, colorid2, fac, col);
- glColor3ubv(col);
-}
-
-/* blend between to theme colors, shade it, and set it */
-void UI_ThemeColorBlendShade(int colorid1, int colorid2, float fac, int offset)
+void UI_GetThemeColorBlend3f(int colorid1, int colorid2, float fac, float r_col[3])
{
- int r, g, b;
const unsigned char *cp1, *cp2;
cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1);
cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2);
CLAMP(fac, 0.0f, 1.0f);
- r = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]);
- g = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]);
- b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
-
- CLAMP(r, 0, 255);
- CLAMP(g, 0, 255);
- CLAMP(b, 0, 255);
-
- glColor3ub(r, g, b);
+ r_col[0] = ((1.0f - fac) * cp1[0] + fac * cp2[0]) / 255.0f;
+ r_col[1] = ((1.0f - fac) * cp1[1] + fac * cp2[1]) / 255.0f;
+ r_col[2] = ((1.0f - fac) * cp1[2] + fac * cp2[2]) / 255.0f;
}
-/* blend between to theme colors, shade it, and set it */
-void UI_ThemeColorBlendShadeAlpha(int colorid1, int colorid2, float fac, int offset, int alphaoffset)
+void UI_FontThemeColor(int fontid, int colorid)
{
- int r, g, b, a;
- const unsigned char *cp1, *cp2;
-
- cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1);
- cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2);
-
- CLAMP(fac, 0.0f, 1.0f);
- r = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]);
- g = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]);
- b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
- a = alphaoffset + floorf((1.0f - fac) * cp1[3] + fac * cp2[3]);
-
- CLAMP(r, 0, 255);
- CLAMP(g, 0, 255);
- CLAMP(b, 0, 255);
- CLAMP(a, 0, 255);
-
- glColor4ub(r, g, b, a);
+ unsigned char color[4];
+ UI_GetThemeColor4ubv(colorid, color);
+ BLF_color4ubv(fontid, color);
}
-
/* get individual values, not scaled */
float UI_GetThemeValuef(int colorid)
{
@@ -1471,6 +966,111 @@ void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3])
col[2] = b;
}
+void UI_GetThemeColorBlendShade3ubv(int colorid1, int colorid2, float fac, int offset, unsigned char col[3])
+{
+ const unsigned char *cp1, *cp2;
+
+ cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1);
+ cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2);
+
+ CLAMP(fac, 0.0f, 1.0f);
+
+ float blend[3];
+ blend[0] = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]);
+ blend[1] = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]);
+ blend[2] = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
+
+ unit_float_to_uchar_clamp_v3(col, blend);
+}
+
+void UI_GetThemeColorShade4ubv(int colorid, int offset, unsigned char col[4])
+{
+ int r, g, b;
+ const unsigned char *cp;
+
+ cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ r = offset + (int) cp[0];
+ CLAMP(r, 0, 255);
+ g = offset + (int) cp[1];
+ CLAMP(g, 0, 255);
+ b = offset + (int) cp[2];
+ CLAMP(b, 0, 255);
+
+ col[0] = r;
+ col[1] = g;
+ col[2] = b;
+ col[3] = cp[3];
+}
+
+void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4])
+{
+ int r, g, b, a;
+ const unsigned char *cp;
+
+ cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+
+ r = coloffset + (int) cp[0];
+ CLAMP(r, 0, 255);
+ g = coloffset + (int) cp[1];
+ CLAMP(g, 0, 255);
+ b = coloffset + (int) cp[2];
+ CLAMP(b, 0, 255);
+ a = alphaoffset + (int) cp[3];
+ CLAMP(b, 0, 255);
+
+ col[0] = ((float)r) / 255.0f;
+ col[1] = ((float)g) / 255.0f;
+ col[2] = ((float)b) / 255.0f;
+ col[3] = ((float)a) / 255.0f;
+}
+
+void UI_GetThemeColorBlendShade3fv(int colorid1, int colorid2, float fac, int offset, float col[3])
+{
+ int r, g, b;
+ const unsigned char *cp1, *cp2;
+
+ cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1);
+ cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2);
+
+ CLAMP(fac, 0.0f, 1.0f);
+
+ r = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]);
+ CLAMP(r, 0, 255);
+ g = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]);
+ CLAMP(g, 0, 255);
+ b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
+ CLAMP(b, 0, 255);
+
+ col[0] = ((float)r) / 255.0f;
+ col[1] = ((float)g) / 255.0f;
+ col[2] = ((float)b) / 255.0f;
+}
+
+void UI_GetThemeColorBlendShade4fv(int colorid1, int colorid2, float fac, int offset, float col[4])
+{
+ int r, g, b, a;
+ const unsigned char *cp1, *cp2;
+
+ cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1);
+ cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2);
+
+ CLAMP(fac, 0.0f, 1.0f);
+
+ r = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]);
+ CLAMP(r, 0, 255);
+ g = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]);
+ CLAMP(g, 0, 255);
+ b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
+ CLAMP(b, 0, 255);
+ a = offset + floorf((1.0f - fac) * cp1[3] + fac * cp2[3]);
+ CLAMP(a, 0, 255);
+
+ col[0] = ((float)r) / 255.0f;
+ col[1] = ((float)g) / 255.0f;
+ col[2] = ((float)b) / 255.0f;
+ col[3] = ((float)a) / 255.0f;
+}
+
/* get the color, in char pointer */
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
{
@@ -1529,20 +1129,29 @@ void UI_GetThemeColorType4ubv(int colorid, int spacetype, char col[4])
col[3] = cp[3];
}
-/* blends and shades between two char color pointers */
-void UI_ColorPtrBlendShade3ubv(const unsigned char cp1[3], const unsigned char cp2[3], float fac, int offset)
+bool UI_GetIconThemeColor4fv(int colorid, float col[4])
{
- int r, g, b;
- CLAMP(fac, 0.0f, 1.0f);
- r = offset + floorf((1.0f - fac) * cp1[0] + fac * cp2[0]);
- g = offset + floorf((1.0f - fac) * cp1[1] + fac * cp2[1]);
- b = offset + floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
+ if (colorid == 0) {
+ return false;
+ }
+
+ /* Only colored icons in outliner and popups, overall UI is intended
+ * to stay monochrome and out of the way except a few places where it
+ * is important to communicate different data types. */
+ if (!((theme_spacetype == SPACE_OUTLINER) ||
+ (theme_regionid == RGN_TYPE_TEMPORARY)))
+ {
+ return false;
+ }
- r = r < 0 ? 0 : (r > 255 ? 255 : r);
- g = g < 0 ? 0 : (g > 255 ? 255 : g);
- b = b < 0 ? 0 : (b > 255 ? 255 : b);
+ const unsigned char *cp;
+ cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ col[0] = ((float)cp[0]) / 255.0f;
+ col[1] = ((float)cp[1]) / 255.0f;
+ col[2] = ((float)cp[2]) / 255.0f;
+ col[3] = ((float)cp[3]) / 255.0f;
- glColor3ub(r, g, b);
+ return true;
}
void UI_GetColorPtrShade3ubv(const unsigned char cp[3], unsigned char col[3], int offset)
@@ -1588,14 +1197,14 @@ void UI_ThemeClearColor(int colorid)
float col[3];
UI_GetThemeColor3fv(colorid, col);
- glClearColor(col[0], col[1], col[2], 0.0f);
+ GPU_clear_color(col[0], col[1], col[2], 0.0f);
}
void UI_ThemeClearColorAlpha(int colorid, float alpha)
{
float col[3];
UI_GetThemeColor3fv(colorid, col);
- glClearColor(col[0], col[1], col[2], alpha);
+ GPU_clear_color(col[0], col[1], col[2], alpha);
}
@@ -1628,1172 +1237,18 @@ void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3]
}
}
-/* ************************************************************* */
-
/* patching UserDef struct and Themes */
void init_userdef_do_versions(Main *bmain)
{
-#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(bmain, ver, subver)
+ BLO_version_defaults_userpref_blend(bmain, &U);
- /* the UserDef struct is not corrected with do_versions() .... ugh! */
- if (U.wheellinescroll == 0) U.wheellinescroll = 3;
- if (U.menuthreshold1 == 0) {
- U.menuthreshold1 = 5;
- U.menuthreshold2 = 2;
- }
- if (U.tb_leftmouse == 0) {
- U.tb_leftmouse = 5;
- U.tb_rightmouse = 5;
- }
- if (U.mixbufsize == 0) U.mixbufsize = 2048;
if (STREQ(U.tempdir, "/")) {
BKE_tempdir_system_init(U.tempdir);
}
- if (U.autokey_mode == 0) {
- /* 'add/replace' but not on */
- U.autokey_mode = 2;
- }
- if (U.savetime <= 0) {
- U.savetime = 1;
-// XXX error(STRINGIFY(BLENDER_STARTUP_FILE)" is buggy, please consider removing it.\n");
- }
- /* transform widget settings */
- if (U.tw_hotspot == 0) {
- U.tw_hotspot = 14;
- U.tw_size = 25; /* percentage of window size */
- U.tw_handlesize = 16; /* percentage of widget radius */
- }
- if (U.pad_rot_angle == 0.0f)
- U.pad_rot_angle = 15.0f;
-
- /* graph editor - unselected F-Curve visibility */
- if (U.fcu_inactive_alpha == 0) {
- U.fcu_inactive_alpha = 0.25f;
- }
-
- /* signal for derivedmesh to use colorband */
- /* run in case this was on and is now off in the user prefs [#28096] */
- vDM_ColorBand_store((U.flag & USER_CUSTOM_RANGE) ? (&U.coba_weight) : NULL, UI_GetTheme()->tv3d.vertex_unreferenced);
-
- if (!USER_VERSION_ATLEAST(192, 0)) {
- strcpy(U.sounddir, "/");
- }
-
- /* patch to set Dupli Armature */
- if (!USER_VERSION_ATLEAST(220, 0)) {
- U.dupflag |= USER_DUP_ARM;
- }
-
- /* added seam, normal color, undo */
- if (!USER_VERSION_ATLEAST(235, 0)) {
- bTheme *btheme;
-
- U.uiflag |= USER_GLOBALUNDO;
- if (U.undosteps == 0) U.undosteps = 32;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* check for (alpha == 0) is safe, then color was never set */
- if (btheme->tv3d.edge_seam[3] == 0) {
- rgba_char_args_set(btheme->tv3d.edge_seam, 230, 150, 50, 255);
- }
- if (btheme->tv3d.normal[3] == 0) {
- rgba_char_args_set(btheme->tv3d.normal, 0x22, 0xDD, 0xDD, 255);
- }
- if (btheme->tv3d.vertex_normal[3] == 0) {
- rgba_char_args_set(btheme->tv3d.vertex_normal, 0x23, 0x61, 0xDD, 255);
- }
- if (btheme->tv3d.face_dot[3] == 0) {
- rgba_char_args_set(btheme->tv3d.face_dot, 255, 138, 48, 255);
- btheme->tv3d.facedot_size = 4;
- }
- }
- }
- if (!USER_VERSION_ATLEAST(236, 0)) {
- /* illegal combo... */
- if (U.flag & USER_LMOUSESELECT)
- U.flag &= ~USER_TWOBUTTONMOUSE;
- }
- if (!USER_VERSION_ATLEAST(237, 0)) {
- bTheme *btheme;
- /* new space type */
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* check for (alpha == 0) is safe, then color was never set */
- if (btheme->ttime.back[3] == 0) {
- /* copied from ui_theme_init_default */
- btheme->ttime = btheme->tv3d;
- rgba_char_args_set_fl(btheme->ttime.back, 0.45, 0.45, 0.45, 1.0);
- rgba_char_args_set_fl(btheme->ttime.grid, 0.36, 0.36, 0.36, 1.0);
- rgba_char_args_set(btheme->ttime.shade1, 173, 173, 173, 255); /* sliders */
- }
- if (btheme->text.syntaxn[3] == 0) {
- rgba_char_args_set(btheme->text.syntaxn, 0, 0, 200, 255); /* Numbers Blue*/
- rgba_char_args_set(btheme->text.syntaxl, 100, 0, 0, 255); /* Strings red */
- rgba_char_args_set(btheme->text.syntaxc, 0, 100, 50, 255); /* Comments greenish */
- rgba_char_args_set(btheme->text.syntaxv, 95, 95, 0, 255); /* Special */
- rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin, red-purple */
- }
- }
- }
- if (!USER_VERSION_ATLEAST(238, 0)) {
- bTheme *btheme;
- /* bone colors */
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* check for alpha==0 is safe, then color was never set */
- if (btheme->tv3d.bone_solid[3] == 0) {
- rgba_char_args_set(btheme->tv3d.bone_solid, 200, 200, 200, 255);
- rgba_char_args_set(btheme->tv3d.bone_pose, 80, 200, 255, 80);
- }
- }
- }
- if (!USER_VERSION_ATLEAST(239, 0)) {
- bTheme *btheme;
- /* bone colors */
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* check for alpha==0 is safe, then color was never set */
- if (btheme->tnla.strip[3] == 0) {
- rgba_char_args_set(btheme->tnla.strip_select, 0xff, 0xff, 0xaa, 255);
- rgba_char_args_set(btheme->tnla.strip, 0xe4, 0x9c, 0xc6, 255);
- }
- }
- }
- if (!USER_VERSION_ATLEAST(240, 0)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* Lamp theme, check for alpha==0 is safe, then color was never set */
- if (btheme->tv3d.lamp[3] == 0) {
- rgba_char_args_set(btheme->tv3d.lamp, 0, 0, 0, 40);
-/* TEMPORAL, remove me! (ton) */
- U.uiflag |= USER_PLAINMENUS;
- }
-
- }
- if (U.obcenter_dia == 0) U.obcenter_dia = 6;
- }
- if (!USER_VERSION_ATLEAST(242, 0)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* Node editor theme, check for alpha==0 is safe, then color was never set */
- if (btheme->tnode.syntaxn[3] == 0) {
- /* re-uses syntax color storage */
- btheme->tnode = btheme->tv3d;
- rgba_char_args_set(btheme->tnode.edge_select, 255, 255, 255, 255);
- rgba_char_args_set(btheme->tnode.syntaxl, 150, 150, 150, 255); /* TH_NODE, backdrop */
- rgba_char_args_set(btheme->tnode.syntaxn, 129, 131, 144, 255); /* in/output */
- rgba_char_args_set(btheme->tnode.syntaxb, 127, 127, 127, 255); /* operator */
- rgba_char_args_set(btheme->tnode.syntaxv, 142, 138, 145, 255); /* generator */
- rgba_char_args_set(btheme->tnode.syntaxc, 120, 145, 120, 255); /* group */
- }
- /* Group theme colors */
- if (btheme->tv3d.group[3] == 0) {
- rgba_char_args_set(btheme->tv3d.group, 0x0C, 0x30, 0x0C, 255);
- rgba_char_args_set(btheme->tv3d.group_active, 0x66, 0xFF, 0x66, 255);
- }
- /* Sequence editor theme*/
- if (btheme->tseq.movie[3] == 0) {
- rgba_char_args_set(btheme->tseq.movie, 81, 105, 135, 255);
- rgba_char_args_set(btheme->tseq.image, 109, 88, 129, 255);
- rgba_char_args_set(btheme->tseq.scene, 78, 152, 62, 255);
- rgba_char_args_set(btheme->tseq.audio, 46, 143, 143, 255);
- rgba_char_args_set(btheme->tseq.effect, 169, 84, 124, 255);
- rgba_char_args_set(btheme->tseq.transition, 162, 95, 111, 255);
- rgba_char_args_set(btheme->tseq.meta, 109, 145, 131, 255);
- }
- }
-
- /* set defaults for 3D View rotating axis indicator */
- /* since size can't be set to 0, this indicates it's not saved in startup.blend */
- if (U.rvisize == 0) {
- U.rvisize = 15;
- U.rvibright = 8;
- U.uiflag |= USER_SHOW_ROTVIEWICON;
- }
-
- }
- if (!USER_VERSION_ATLEAST(243, 0)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* long keyframe color */
- /* check for alpha==0 is safe, then color was never set */
- if (btheme->tact.strip[3] == 0) {
- rgba_char_args_set(btheme->tv3d.edge_sharp, 255, 32, 32, 255);
- rgba_char_args_set(btheme->tact.strip_select, 0xff, 0xff, 0xaa, 204);
- rgba_char_args_set(btheme->tact.strip, 0xe4, 0x9c, 0xc6, 204);
- }
-
- /* IPO-Editor - Vertex Size*/
- if (btheme->tipo.vertex_size == 0) {
- btheme->tipo.vertex_size = 3;
- }
- }
- }
- if (!USER_VERSION_ATLEAST(244, 0)) {
- /* set default number of recently-used files (if not set) */
- if (U.recent_files == 0) U.recent_files = 10;
- }
- if (!USER_VERSION_ATLEAST(245, 3)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128);
- }
- if (U.coba_weight.tot == 0)
- BKE_colorband_init(&U.coba_weight, true);
- }
- if (!USER_VERSION_ATLEAST(245, 3)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* these should all use the same color */
- rgba_char_args_set(btheme->tv3d.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tipo.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tact.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tnla.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tseq.cframe, 0x60, 0xc0, 0x40, 255);
- //rgba_char_args_set(btheme->tsnd.cframe, 0x60, 0xc0, 0x40, 255); Not needed anymore
- rgba_char_args_set(btheme->ttime.cframe, 0x60, 0xc0, 0x40, 255);
- }
- }
- if (!USER_VERSION_ATLEAST(245, 3)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* action channel groups (recolor anyway) */
- rgba_char_args_set(btheme->tact.group, 0x39, 0x7d, 0x1b, 255);
- rgba_char_args_set(btheme->tact.group_active, 0x7d, 0xe9, 0x60, 255);
-
- /* bone custom-color sets */
- if (btheme->tarm[0].solid[3] == 0)
- ui_theme_init_boneColorSets(btheme);
- }
- }
- if (!USER_VERSION_ATLEAST(245, 3)) {
- U.flag |= USER_ADD_VIEWALIGNED | USER_ADD_EDITMODE;
- }
- if (!USER_VERSION_ATLEAST(245, 3)) {
- bTheme *btheme;
-
- /* adjust themes */
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- const char *col;
-
- /* IPO Editor: Handles/Vertices */
- col = btheme->tipo.vertex;
- rgba_char_args_set(btheme->tipo.handle_vertex, col[0], col[1], col[2], 255);
- col = btheme->tipo.vertex_select;
- rgba_char_args_set(btheme->tipo.handle_vertex_select, col[0], col[1], col[2], 255);
- btheme->tipo.handle_vertex_size = btheme->tipo.vertex_size;
-
- /* Sequence/Image Editor: colors for GPencil text */
- col = btheme->tv3d.bone_pose;
- rgba_char_args_set(btheme->tseq.bone_pose, col[0], col[1], col[2], 255);
- rgba_char_args_set(btheme->tima.bone_pose, col[0], col[1], col[2], 255);
- col = btheme->tv3d.vertex_select;
- rgba_char_args_set(btheme->tseq.vertex_select, col[0], col[1], col[2], 255);
- }
- }
- if (!USER_VERSION_ATLEAST(250, 0)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* this was not properly initialized in 2.45 */
- if (btheme->tima.face_dot[3] == 0) {
- rgba_char_args_set(btheme->tima.editmesh_active, 255, 255, 255, 128);
- rgba_char_args_set(btheme->tima.face_dot, 255, 133, 0, 255);
- btheme->tima.facedot_size = 2;
- }
-
- /* DopeSheet - (Object) Channel color */
- rgba_char_args_set(btheme->tact.ds_channel, 82, 96, 110, 255);
- rgba_char_args_set(btheme->tact.ds_subchannel, 124, 137, 150, 255);
- /* DopeSheet - Group Channel color (saner version) */
- rgba_char_args_set(btheme->tact.group, 79, 101, 73, 255);
- rgba_char_args_set(btheme->tact.group_active, 135, 177, 125, 255);
-
- /* Graph Editor - (Object) Channel color */
- rgba_char_args_set(btheme->tipo.ds_channel, 82, 96, 110, 255);
- rgba_char_args_set(btheme->tipo.ds_subchannel, 124, 137, 150, 255);
- /* Graph Editor - Group Channel color */
- rgba_char_args_set(btheme->tipo.group, 79, 101, 73, 255);
- rgba_char_args_set(btheme->tipo.group_active, 135, 177, 125, 255);
-
- /* Nla Editor - (Object) Channel color */
- rgba_char_args_set(btheme->tnla.ds_channel, 82, 96, 110, 255);
- rgba_char_args_set(btheme->tnla.ds_subchannel, 124, 137, 150, 255);
- /* NLA Editor - New Strip colors */
- rgba_char_args_set(btheme->tnla.strip, 12, 10, 10, 128);
- rgba_char_args_set(btheme->tnla.strip_select, 255, 140, 0, 255);
- }
-
- /* adjust grease-pencil distances */
- U.gp_manhattendist = 1;
- U.gp_euclideandist = 2;
-
- /* adjust default interpolation for new IPO-curves */
- U.ipo_new = BEZT_IPO_BEZ;
- }
-
- if (!USER_VERSION_ATLEAST(250, 1)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
-
- /* common (new) variables, it checks for alpha==0 */
- ui_theme_init_new(btheme);
-
- if (btheme->tui.wcol_num.outline[3] == 0)
- ui_widget_color_init(&btheme->tui);
-
- /* Logic editor theme, check for alpha==0 is safe, then color was never set */
- if (btheme->tlogic.syntaxn[3] == 0) {
- /* re-uses syntax color storage */
- btheme->tlogic = btheme->tv3d;
- rgba_char_args_set(btheme->tlogic.back, 100, 100, 100, 255);
- }
-
- rgba_char_args_set_fl(btheme->tinfo.back, 0.45, 0.45, 0.45, 1.0);
- rgba_char_args_set_fl(btheme->tuserpref.back, 0.45, 0.45, 0.45, 1.0);
- }
- }
-
- if (!USER_VERSION_ATLEAST(250, 3)) {
- /* new audio system */
- if (U.audiochannels == 0)
- U.audiochannels = 2;
- if (U.audiodevice == 0) {
-#ifdef WITH_OPENAL
- U.audiodevice = 2;
-#endif
-#ifdef WITH_SDL
- U.audiodevice = 1;
-#endif
- }
- if (U.audioformat == 0)
- U.audioformat = 0x24;
- if (U.audiorate == 0)
- U.audiorate = 48000;
- }
-
- if (!USER_VERSION_ATLEAST(250, 8)) {
- wmKeyMap *km;
-
- for (km = U.user_keymaps.first; km; km = km->next) {
- if (STREQ(km->idname, "Armature_Sketch"))
- strcpy(km->idname, "Armature Sketch");
- else if (STREQ(km->idname, "View3D"))
- strcpy(km->idname, "3D View");
- else if (STREQ(km->idname, "View3D Generic"))
- strcpy(km->idname, "3D View Generic");
- else if (STREQ(km->idname, "EditMesh"))
- strcpy(km->idname, "Mesh");
- else if (STREQ(km->idname, "TimeLine"))
- strcpy(km->idname, "Timeline");
- else if (STREQ(km->idname, "UVEdit"))
- strcpy(km->idname, "UV Editor");
- else if (STREQ(km->idname, "Animation_Channels"))
- strcpy(km->idname, "Animation Channels");
- else if (STREQ(km->idname, "GraphEdit Keys"))
- strcpy(km->idname, "Graph Editor");
- else if (STREQ(km->idname, "GraphEdit Generic"))
- strcpy(km->idname, "Graph Editor Generic");
- else if (STREQ(km->idname, "Action_Keys"))
- strcpy(km->idname, "Dopesheet");
- else if (STREQ(km->idname, "NLA Data"))
- strcpy(km->idname, "NLA Editor");
- else if (STREQ(km->idname, "Node Generic"))
- strcpy(km->idname, "Node Editor");
- else if (STREQ(km->idname, "Logic Generic"))
- strcpy(km->idname, "Logic Editor");
- else if (STREQ(km->idname, "File"))
- strcpy(km->idname, "File Browser");
- else if (STREQ(km->idname, "FileMain"))
- strcpy(km->idname, "File Browser Main");
- else if (STREQ(km->idname, "FileButtons"))
- strcpy(km->idname, "File Browser Buttons");
- else if (STREQ(km->idname, "Buttons Generic"))
- strcpy(km->idname, "Property Editor");
- }
- }
- if (!USER_VERSION_ATLEAST(250, 16)) {
- if (U.wmdrawmethod == USER_DRAW_TRIPLE)
- U.wmdrawmethod = USER_DRAW_AUTOMATIC;
- }
-
- if (!USER_VERSION_ATLEAST(252, 3)) {
- if (U.flag & USER_LMOUSESELECT)
- U.flag &= ~USER_TWOBUTTONMOUSE;
- }
- if (!USER_VERSION_ATLEAST(252, 4)) {
- bTheme *btheme;
-
- /* default new handle type is auto handles */
- U.keyhandles_new = HD_AUTO;
-
- /* init new curve colors */
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- ui_theme_space_init_handles_color(&btheme->tv3d);
- ui_theme_space_init_handles_color(&btheme->tipo);
-
- /* edge crease */
- rgba_char_args_set_fl(btheme->tv3d.edge_crease, 0.8, 0, 0.6, 1.0);
- }
- }
- if (!USER_VERSION_ATLEAST(253, 0)) {
- bTheme *btheme;
-
- /* init new curve colors */
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tv3d.lastsel_point[3] == 0)
- rgba_char_args_set(btheme->tv3d.lastsel_point, 0xff, 0xff, 0xff, 255);
- }
- }
- if (!USER_VERSION_ATLEAST(252, 5)) {
- bTheme *btheme;
-
- /* interface_widgets.c */
- struct uiWidgetColors wcol_progress = {
- {0, 0, 0, 255},
- {190, 190, 190, 255},
- {100, 100, 100, 180},
- {128, 128, 128, 255},
-
- {0, 0, 0, 255},
- {255, 255, 255, 255},
-
- 0,
- 5, -5
- };
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* init progress bar theme */
- btheme->tui.wcol_progress = wcol_progress;
- }
- }
-
- if (!USER_VERSION_ATLEAST(255, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tv3d.extra_edge_len, 32, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.extra_face_angle, 0, 32, 0, 255);
- rgba_char_args_set(btheme->tv3d.extra_face_area, 0, 0, 128, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(256, 4)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if ((btheme->tv3d.outline_width) == 0) btheme->tv3d.outline_width = 1;
- }
- }
-
- if (!USER_VERSION_ATLEAST(257, 0)) {
- /* clear "AUTOKEY_FLAG_ONLYKEYINGSET" flag from userprefs,
- * so that it doesn't linger around from old configs like a ghost */
- U.autokey_flag &= ~AUTOKEY_FLAG_ONLYKEYINGSET;
- }
-
- if (!USER_VERSION_ATLEAST(258, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- btheme->tnode.noodle_curving = 5;
- }
- }
-
- if (!USER_VERSION_ATLEAST(259, 1)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- btheme->tv3d.speaker[3] = 255;
- }
- }
-
- if (!USER_VERSION_ATLEAST(260, 3)) {
- bTheme *btheme;
-
- /* if new keyframes handle default is stuff "auto", make it "auto-clamped" instead
- * was changed in 260 as part of GSoC11, but version patch was wrong
- */
- if (U.keyhandles_new == HD_AUTO)
- U.keyhandles_new = HD_AUTO_ANIM;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tv3d.bundle_solid[3] == 0)
- rgba_char_args_set(btheme->tv3d.bundle_solid, 200, 200, 200, 255);
-
- if (btheme->tv3d.camera_path[3] == 0)
- rgba_char_args_set(btheme->tv3d.camera_path, 0x00, 0x00, 0x00, 255);
-
- if ((btheme->tclip.back[3]) == 0) {
- btheme->tclip = btheme->tv3d;
-
- rgba_char_args_set(btheme->tclip.marker_outline, 0x00, 0x00, 0x00, 255);
- rgba_char_args_set(btheme->tclip.marker, 0x7f, 0x7f, 0x00, 255);
- rgba_char_args_set(btheme->tclip.act_marker, 0xff, 0xff, 0xff, 255);
- rgba_char_args_set(btheme->tclip.sel_marker, 0xff, 0xff, 0x00, 255);
- rgba_char_args_set(btheme->tclip.dis_marker, 0x7f, 0x00, 0x00, 255);
- rgba_char_args_set(btheme->tclip.lock_marker, 0x7f, 0x7f, 0x7f, 255);
- rgba_char_args_set(btheme->tclip.path_before, 0xff, 0x00, 0x00, 255);
- rgba_char_args_set(btheme->tclip.path_after, 0x00, 0x00, 0xff, 255);
- rgba_char_args_set(btheme->tclip.grid, 0x5e, 0x5e, 0x5e, 255);
- rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff);
- rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff);
- btheme->tclip.handle_vertex_size = 5;
- }
-
- /* auto-clamped handles -> based on auto */
- if (btheme->tipo.handle_auto_clamped[3] == 0)
- rgba_char_args_set(btheme->tipo.handle_auto_clamped, 0x99, 0x40, 0x30, 255);
- if (btheme->tipo.handle_sel_auto_clamped[3] == 0)
- rgba_char_args_set(btheme->tipo.handle_sel_auto_clamped, 0xf0, 0xaf, 0x90, 255);
- }
-
- /* enable (Cycles) addon by default */
- BKE_addon_ensure(&U.addons, "cycles");
- }
-
- if (!USER_VERSION_ATLEAST(260, 5)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tui.panel.header, 0, 0, 0, 25);
- btheme->tui.icon_alpha = 1.0;
- }
- }
-
- if (!USER_VERSION_ATLEAST(261, 4)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set_fl(btheme->tima.preview_stitch_face, 0.071, 0.259, 0.694, 0.150);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_edge, 1.0, 0.522, 0.0, 0.7);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_vert, 1.0, 0.522, 0.0, 0.5);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_stitchable, 0.0, 1.0, 0.0, 1.0);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0);
- rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140);
-
- rgba_char_args_set_fl(btheme->toops.match, 0.2, 0.5, 0.2, 0.3);
- rgba_char_args_set_fl(btheme->toops.selected_highlight, 0.51, 0.53, 0.55, 0.3);
- }
-
- U.use_16bit_textures = true;
- }
-
- if (!USER_VERSION_ATLEAST(262, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tui.wcol_menu_item.item[3] == 255)
- rgba_char_args_set(btheme->tui.wcol_menu_item.item, 172, 172, 172, 128);
- }
- }
-
- if (!USER_VERSION_ATLEAST(262, 3)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tui.wcol_tooltip.inner[3] == 0) {
- btheme->tui.wcol_tooltip = btheme->tui.wcol_menu_back;
- }
- if (btheme->tui.wcol_tooltip.text[0] == 160) { /* hrmf */
- rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255);
- }
- }
- }
-
- if (!USER_VERSION_ATLEAST(262, 4)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tseq.movieclip[3] == 0) {
- rgba_char_args_set(btheme->tseq.movieclip, 32, 32, 143, 255);
- }
- }
- }
-
- if (!USER_VERSION_ATLEAST(263, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tclip.strip[0] == 0) {
- rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff);
- rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80);
- rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff);
- }
- }
- }
-
- if (!USER_VERSION_ATLEAST(263, 6)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next)
- rgba_char_args_set(btheme->tv3d.skin_root, 180, 77, 77, 255);
- }
-
- if (!USER_VERSION_ATLEAST(263, 7)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* DopeSheet Summary */
- rgba_char_args_set(btheme->tact.anim_active, 204, 112, 26, 102);
-
- /* NLA Colors */
- rgba_char_args_set(btheme->tnla.anim_active, 204, 112, 26, 102); /* same as dopesheet above */
- rgba_char_args_set(btheme->tnla.anim_non_active, 153, 135, 97, 77);
-
- rgba_char_args_set(btheme->tnla.nla_tweaking, 77, 243, 26, 77);
- rgba_char_args_set(btheme->tnla.nla_tweakdupli, 217, 0, 0, 255);
-
- rgba_char_args_set(btheme->tnla.nla_transition, 28, 38, 48, 255);
- rgba_char_args_set(btheme->tnla.nla_transition_sel, 46, 117, 219, 255);
- rgba_char_args_set(btheme->tnla.nla_meta, 51, 38, 66, 255);
- rgba_char_args_set(btheme->tnla.nla_meta_sel, 105, 33, 150, 255);
- rgba_char_args_set(btheme->tnla.nla_sound, 43, 61, 61, 255);
- rgba_char_args_set(btheme->tnla.nla_sound_sel, 31, 122, 122, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(263, 11)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tseq.mask[3] == 0) {
- rgba_char_args_set(btheme->tseq.mask, 152, 78, 62, 255);
- }
- }
- }
-
- if (!USER_VERSION_ATLEAST(263, 15)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tv3d.bone_pose_active, 140, 255, 255, 80);
- }
- }
-
- if (!USER_VERSION_ATLEAST(263, 16)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tact.anim_active[3] == 0)
- rgba_char_args_set(btheme->tact.anim_active, 204, 112, 26, 102);
-
- if (btheme->tnla.anim_active[3] == 0)
- rgba_char_args_set(btheme->tnla.anim_active, 204, 112, 26, 102);
- }
- }
-
- if (!USER_VERSION_ATLEAST(263, 22)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tipo.lastsel_point[3] == 0)
- rgba_char_args_set(btheme->tipo.lastsel_point, 0xff, 0xff, 0xff, 255);
-
- if (btheme->tv3d.skin_root[3] == 0)
- rgba_char_args_set(btheme->tv3d.skin_root, 180, 77, 77, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(264, 9)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tui.xaxis, 220, 0, 0, 255);
- rgba_char_args_set(btheme->tui.yaxis, 0, 220, 0, 255);
- rgba_char_args_set(btheme->tui.zaxis, 0, 0, 220, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(267, 0)) {
- /* Freestyle color settings */
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* check for alpha == 0 is safe, then color was never set */
- if (btheme->tv3d.freestyle_edge_mark[3] == 0) {
- rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
- rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
- }
-
- if (btheme->tv3d.wire_edit[3] == 0) {
- rgba_char_args_set(btheme->tv3d.wire_edit, 0x0, 0x0, 0x0, 255);
- }
- }
-
- /* GL Texture Garbage Collection */
- if (U.textimeout == 0) {
- U.texcollectrate = 60;
- U.textimeout = 120;
- }
- if (U.memcachelimit <= 0) {
- U.memcachelimit = 32;
- }
- if (U.frameserverport == 0) {
- U.frameserverport = 8080;
- }
- if (U.dbl_click_time == 0) {
- U.dbl_click_time = 350;
- }
- if (U.v2d_min_gridsize == 0) {
- U.v2d_min_gridsize = 35;
- }
- if (U.dragthreshold == 0)
- U.dragthreshold = 5;
- if (U.widget_unit == 0)
- U.widget_unit = 20;
- if (U.anisotropic_filter <= 0)
- U.anisotropic_filter = 1;
-
- if (U.ndof_sensitivity == 0.0f) {
- U.ndof_sensitivity = 1.0f;
- U.ndof_flag = (NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | NDOF_SHOULD_ROTATE);
- }
-
- if (U.ndof_orbit_sensitivity == 0.0f) {
- U.ndof_orbit_sensitivity = U.ndof_sensitivity;
-
- if (!(U.flag & USER_TRACKBALL))
- U.ndof_flag |= NDOF_TURNTABLE;
- }
- if (U.tweak_threshold == 0)
- U.tweak_threshold = 10;
- }
-
- if (!USER_VERSION_ATLEAST(265, 1)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* note: the toggle operator for transparent backdrops limits to these spacetypes */
- if (btheme->tnode.button[3] == 255) {
- btheme->tv3d.button[3] = 128;
- btheme->tnode.button[3] = 128;
- btheme->tima.button[3] = 128;
- btheme->tseq.button[3] = 128;
- btheme->tclip.button[3] = 128;
- }
- }
- }
-
- /* panel header/backdrop supported locally per editor now */
- if (!USER_VERSION_ATLEAST(265, 2)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- ThemeSpace *ts;
-
- /* new color, panel backdrop. Not used anywhere yet, until you enable it */
- copy_v3_v3_char(btheme->tui.panel.back, btheme->tbuts.button);
- btheme->tui.panel.back[3] = 128;
-
- for (ts = UI_THEMESPACE_START(btheme); ts != UI_THEMESPACE_END(btheme); ts++) {
- ts->panelcolors = btheme->tui.panel;
- }
- }
- }
-
- /* NOTE!! from now on use U.versionfile and U.subversionfile */
-#undef USER_VERSION_ATLEAST
-#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST((&(U)), ver, subver)
-
- if (!USER_VERSION_ATLEAST(266, 0)) {
- bTheme *btheme;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* rna definition limits fac to 0.01 */
- if (btheme->tui.menu_shadow_fac == 0.0f) {
- btheme->tui.menu_shadow_fac = 0.5f;
- btheme->tui.menu_shadow_width = 12;
- }
- }
- }
-
- if (!USER_VERSION_ATLEAST(265, 4)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */
- rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange */
- rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Gray (mix between fg/bg) */
- }
- }
-
- if (!USER_VERSION_ATLEAST(265, 6)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- copy_v4_v4_char(btheme->tv3d.gradients.high_gradient, btheme->tv3d.back);
- }
- }
-
- if (!USER_VERSION_ATLEAST(265, 9)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_test_set(btheme->tnode.syntaxs, 151, 116, 116, 255); /* matte nodes */
- rgba_char_args_test_set(btheme->tnode.syntaxd, 116, 151, 151, 255); /* distort nodes */
- }
- }
-
- if (!USER_VERSION_ATLEAST(265, 11)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_test_set(btheme->tconsole.console_select, 255, 255, 255, 48);
- }
- }
-
- if (!USER_VERSION_ATLEAST(266, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_test_set(btheme->tnode.console_output, 223, 202, 53, 255); /* interface nodes */
- }
- }
-
- if (!USER_VERSION_ATLEAST(268, 3)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255);
- rgba_char_args_test_set(btheme->tima.uv_shadow, 112, 112, 112, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(269, 5)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tima.wire_edit, 192, 192, 192, 255);
- rgba_char_args_set(btheme->tima.edge_select, 255, 133, 0, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(269, 6)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- char r, g, b;
- r = btheme->tnode.syntaxn[0];
- g = btheme->tnode.syntaxn[1];
- b = btheme->tnode.syntaxn[2];
- rgba_char_args_test_set(btheme->tnode.nodeclass_output, r, g, b, 255);
- r = btheme->tnode.syntaxb[0];
- g = btheme->tnode.syntaxb[1];
- b = btheme->tnode.syntaxb[2];
- rgba_char_args_test_set(btheme->tnode.nodeclass_filter, r, g, b, 255);
- rgba_char_args_test_set(btheme->tnode.nodeclass_vector, r, g, b, 255);
- rgba_char_args_test_set(btheme->tnode.nodeclass_texture, r, g, b, 255);
- rgba_char_args_test_set(btheme->tnode.nodeclass_shader, r, g, b, 255);
- rgba_char_args_test_set(btheme->tnode.nodeclass_script, r, g, b, 255);
- rgba_char_args_test_set(btheme->tnode.nodeclass_pattern, r, g, b, 255);
- rgba_char_args_test_set(btheme->tnode.nodeclass_layout, r, g, b, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(269, 8)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_test_set(btheme->tinfo.info_selected, 96, 128, 255, 255);
- rgba_char_args_test_set(btheme->tinfo.info_selected_text, 255, 255, 255, 255);
- rgba_char_args_test_set(btheme->tinfo.info_error, 220, 0, 0, 255);
- rgba_char_args_test_set(btheme->tinfo.info_error_text, 0, 0, 0, 255);
- rgba_char_args_test_set(btheme->tinfo.info_warning, 220, 128, 96, 255);
- rgba_char_args_test_set(btheme->tinfo.info_warning_text, 0, 0, 0, 255);
- rgba_char_args_test_set(btheme->tinfo.info_info, 0, 170, 0, 255);
- rgba_char_args_test_set(btheme->tinfo.info_info_text, 0, 0, 0, 255);
- rgba_char_args_test_set(btheme->tinfo.info_debug, 196, 196, 196, 255);
- rgba_char_args_test_set(btheme->tinfo.info_debug_text, 0, 0, 0, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(269, 9)) {
- bTheme *btheme;
-
- U.tw_size = U.tw_size * 5.0f;
-
- /* Action Editor (and NLA Editor) - Keyframe Colors */
- /* Graph Editor - larger vertex size defaults */
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* Action Editor ................. */
- /* key types */
- rgba_char_args_set(btheme->tact.keytype_keyframe, 232, 232, 232, 255);
- rgba_char_args_set(btheme->tact.keytype_keyframe_select, 255, 190, 50, 255);
- rgba_char_args_set(btheme->tact.keytype_extreme, 232, 179, 204, 255);
- rgba_char_args_set(btheme->tact.keytype_extreme_select, 242, 128, 128, 255);
- rgba_char_args_set(btheme->tact.keytype_breakdown, 179, 219, 232, 255);
- rgba_char_args_set(btheme->tact.keytype_breakdown_select, 84, 191, 237, 255);
- rgba_char_args_set(btheme->tact.keytype_jitter, 148, 229, 117, 255);
- rgba_char_args_set(btheme->tact.keytype_jitter_select, 97, 192, 66, 255);
-
- /* key border */
- rgba_char_args_set(btheme->tact.keyborder, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tact.keyborder_select, 0, 0, 0, 255);
-
- /* NLA ............................ */
- /* key border */
- rgba_char_args_set(btheme->tnla.keyborder, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tnla.keyborder_select, 0, 0, 0, 255);
-
- /* Graph Editor ................... */
- btheme->tipo.vertex_size = 6;
- btheme->tipo.handle_vertex_size = 5;
- }
-
- /* grease pencil - new layer color */
- if (U.gpencil_new_layer_col[3] < 0.1f) {
- /* defaults to black, but must at least be visible! */
- U.gpencil_new_layer_col[3] = 0.9f;
- }
- }
-
- if (!USER_VERSION_ATLEAST(269, 10)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- ThemeSpace *ts;
-
- for (ts = UI_THEMESPACE_START(btheme); ts != UI_THEMESPACE_END(btheme); ts++) {
- rgba_char_args_set(ts->tab_active, 114, 114, 114, 255);
- rgba_char_args_set(ts->tab_inactive, 83, 83, 83, 255);
- rgba_char_args_set(ts->tab_back, 64, 64, 64, 255);
- rgba_char_args_set(ts->tab_outline, 60, 60, 60, 255);
- }
- }
- }
-
- if (!USER_VERSION_ATLEAST(271, 0)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(272, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
- rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
- rgba_char_args_set_fl(btheme->tima.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
- rgba_char_args_set_fl(btheme->tima.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
- rgba_char_args_set(btheme->tnode.syntaxr, 115, 115, 115, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(271, 5)) {
- bTheme *btheme;
-
- struct uiWidgetColors wcol_pie_menu = {
- {10, 10, 10, 200},
- {25, 25, 25, 230},
- {140, 140, 140, 255},
- {45, 45, 45, 230},
-
- {160, 160, 160, 255},
- {255, 255, 255, 255},
-
- 1,
- 10, -10
- };
-
- U.pie_menu_radius = 100;
- U.pie_menu_threshold = 12;
- U.pie_animation_timeout = 6;
-
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- btheme->tui.wcol_pie_menu = wcol_pie_menu;
-
- ui_theme_space_init_handles_color(&btheme->tclip);
- ui_theme_space_init_handles_color(&btheme->tima);
- btheme->tima.handle_vertex_size = 5;
- btheme->tclip.handle_vertex_size = 5;
- }
- }
-
- if (!USER_VERSION_ATLEAST(271, 6)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* check for (alpha == 0) is safe, then color was never set */
- if (btheme->tv3d.loop_normal[3] == 0) {
- rgba_char_args_set(btheme->tv3d.loop_normal, 0xDD, 0x23, 0xDD, 255);
- }
- }
- }
-
- if (!USER_VERSION_ATLEAST(272, 3)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set_fl(btheme->tui.widget_emboss, 1.0f, 1.0f, 1.0f, 0.02f);
- }
- }
-
- if (!USER_VERSION_ATLEAST(273, 1)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* Grease Pencil vertex settings */
- rgba_char_args_set(btheme->tv3d.gp_vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tv3d.gp_vertex_select, 255, 133, 0, 255);
- btheme->tv3d.gp_vertex_size = 3;
-
- rgba_char_args_set(btheme->tseq.gp_vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tseq.gp_vertex_select, 255, 133, 0, 255);
- btheme->tseq.gp_vertex_size = 3;
-
- rgba_char_args_set(btheme->tima.gp_vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tima.gp_vertex_select, 255, 133, 0, 255);
- btheme->tima.gp_vertex_size = 3;
-
- rgba_char_args_set(btheme->tnode.gp_vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tnode.gp_vertex_select, 255, 133, 0, 255);
- btheme->tnode.gp_vertex_size = 3;
-
- /* Timeline Keyframe Indicators */
- rgba_char_args_set(btheme->ttime.time_keyframe, 0xDD, 0xD7, 0x00, 0xFF);
- rgba_char_args_set(btheme->ttime.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 0xFF);
- }
- }
-
- if (!USER_VERSION_ATLEAST(273, 5)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- unsigned char *cp = (unsigned char *)btheme->tv3d.clipping_border_3d;
- int c;
- copy_v4_v4_char((char *)cp, btheme->tv3d.back);
- c = cp[0] - 8;
- CLAMP(c, 0, 255);
- cp[0] = c;
- c = cp[1] - 8;
- CLAMP(c, 0, 255);
- cp[1] = c;
- c = cp[2] - 8;
- CLAMP(c, 0, 255);
- cp[2] = c;
- cp[3] = 255;
- }
- }
-
- if (!USER_VERSION_ATLEAST(274, 5)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- copy_v4_v4_char(btheme->tima.metadatatext, btheme->tima.text_hi);
- copy_v4_v4_char(btheme->tseq.metadatatext, btheme->tseq.text_hi);
- }
- }
-
- if (!USER_VERSION_ATLEAST(275, 1)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- copy_v4_v4_char(btheme->tclip.metadatatext, btheme->tseq.text_hi);
- }
- }
-
- if (!USER_VERSION_ATLEAST(275, 2)) {
- U.ndof_deadzone = 0.1;
- }
-
- if (!USER_VERSION_ATLEAST(275, 4)) {
- U.node_margin = 80;
- }
-
- if (!USER_VERSION_ATLEAST(276, 1)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set_fl(btheme->tima.preview_back, 0.0f, 0.0f, 0.0f, 0.3f);
- }
- }
-
- if (!USER_VERSION_ATLEAST(276, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tclip.gp_vertex, 0, 0, 0, 255);
- rgba_char_args_set(btheme->tclip.gp_vertex_select, 255, 133, 0, 255);
- btheme->tclip.gp_vertex_size = 3;
- }
- }
-
- if (!USER_VERSION_ATLEAST(276, 3)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tseq.text_strip, 162, 151, 0, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(276, 8)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tui.wcol_progress.item, 128, 128, 128, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(276, 10)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* 3dView Keyframe Indicators */
- rgba_char_args_set(btheme->tv3d.time_keyframe, 0xDD, 0xD7, 0x00, 0xFF);
- rgba_char_args_set(btheme->tv3d.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 0xFF);
- }
- }
-
- if (!USER_VERSION_ATLEAST(277, 0)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (memcmp(btheme->tui.wcol_list_item.item, btheme->tui.wcol_list_item.text_sel, sizeof(char) * 3) == 0) {
- copy_v4_v4_char(btheme->tui.wcol_list_item.item, btheme->tui.wcol_text.item);
- copy_v4_v4_char(btheme->tui.wcol_list_item.text_sel, btheme->tui.wcol_text.text_sel);
- }
- }
- }
-
- if (!USER_VERSION_ATLEAST(277, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- if (btheme->tact.keyframe_scale_fac < 0.1f)
- btheme->tact.keyframe_scale_fac = 1.0f;
- }
- }
-
- if (!USER_VERSION_ATLEAST(278, 2)) {
- bTheme *btheme;
- for (btheme = U.themes.first; btheme; btheme = btheme->next) {
- rgba_char_args_set(btheme->tv3d.vertex_bevel, 0, 165, 255, 255);
- rgba_char_args_set(btheme->tv3d.edge_bevel, 0, 165, 255, 255);
- }
- }
-
- if (!USER_VERSION_ATLEAST(278, 3)) {
- for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
- /* Keyframe Indicators (were using wrong alpha) */
- btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255;
- btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255;
- }
- }
-
- if (!USER_VERSION_ATLEAST(278, 6)) {
- /* Clear preference flags for re-use. */
- U.flag &= ~(
- USER_FLAG_DEPRECATED_1 | USER_FLAG_DEPRECATED_2 | USER_FLAG_DEPRECATED_3 |
- USER_FLAG_DEPRECATED_6 | USER_FLAG_DEPRECATED_7 |
- USER_FLAG_DEPRECATED_9 | USER_DEVELOPER_UI);
- U.uiflag &= ~(
- USER_UIFLAG_DEPRECATED_7);
- U.transopts &= ~(
- USER_TR_DEPRECATED_2 | USER_TR_DEPRECATED_3 | USER_TR_DEPRECATED_4 |
- USER_TR_DEPRECATED_6 | USER_TR_DEPRECATED_7);
- U.gameflags &= ~(
- USER_GL_RENDER_DEPRECATED_0 | USER_GL_RENDER_DEPRECATED_1 |
- USER_GL_RENDER_DEPRECATED_3 | USER_GL_RENDER_DEPRECATED_4);
-
- U.uiflag |= USER_LOCK_CURSOR_ADJUST;
- }
-
- /**
- * Include next version bump.
- */
- {
- /* (keep this block even if it becomes empty). */
- }
-
- if (U.pixelsize == 0.0f)
- U.pixelsize = 1.0f;
-
- if (U.image_draw_method == 0)
- U.image_draw_method = IMAGE_DRAW_METHOD_2DTEXTURE;
-
- // keep the following until the new audaspace is default to be built with
-#ifdef WITH_SYSTEM_AUDASPACE
- // we default to the first audio device
- U.audiodevice = 0;
-#endif
/* Not versioning, just avoid errors. */
#ifndef WITH_CYCLES
BKE_addon_remove_safe(&U.addons, "cycles");
#endif
- /* funny name, but it is GE stuff, moves userdef stuff to engine */
-// XXX space_set_commmandline_options();
- /* this timer uses U */
-// XXX reset_autosave();
-
}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 622d47bae18..80f4bb57baa 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -49,11 +49,12 @@
#include "BKE_screen.h"
#include "BKE_global.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "WM_api.h"
-#include "BIF_gl.h"
-
#include "BLF_api.h"
#include "ED_screen.h"
@@ -115,15 +116,28 @@ static int view2d_scroll_mapped(int scroll)
return scroll;
}
-/* called each time cur changes, to dynamically update masks */
-static void view2d_masks(View2D *v2d, bool check_scrollers)
+void UI_view2d_mask_from_win(const View2D *v2d, rcti *r_mask)
+{
+ r_mask->xmin = 0;
+ r_mask->ymin = 0;
+ r_mask->xmax = v2d->winx - 1; /* -1 yes! masks are pixels */
+ r_mask->ymax = v2d->winy - 1;
+}
+
+/**
+ * Called each time #View2D.cur changes, to dynamically update masks.
+ *
+ * \param mask_scroll: Optionally clamp scrollbars by this region.
+ */
+static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scroll)
{
int scroll;
/* mask - view frame */
- v2d->mask.xmin = v2d->mask.ymin = 0;
- v2d->mask.xmax = v2d->winx - 1; /* -1 yes! masks are pixels */
- v2d->mask.ymax = v2d->winy - 1;
+ UI_view2d_mask_from_win(v2d, &v2d->mask);
+ if (mask_scroll == NULL) {
+ mask_scroll = &v2d->mask;
+ }
if (check_scrollers) {
/* check size if hiding flag is set: */
@@ -147,50 +161,50 @@ static void view2d_masks(View2D *v2d, bool check_scrollers)
scroll = view2d_scroll_mapped(v2d->scroll);
- /* scrollers shrink mask area, but should be based off regionsize
+ /* scrollers are based off regionsize
* - they can only be on one to two edges of the region they define
* - if they overlap, they must not occupy the corners (which are reserved for other widgets)
*/
if (scroll) {
+ const int scroll_width = (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) ?
+ V2D_SCROLL_WIDTH_TEXT : V2D_SCROLL_WIDTH;
+ const int scroll_height = (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) ?
+ V2D_SCROLL_HEIGHT_TEXT : V2D_SCROLL_HEIGHT;
+
/* vertical scroller */
if (scroll & V2D_SCROLL_LEFT) {
/* on left-hand edge of region */
- v2d->vert = v2d->mask;
- v2d->vert.xmax = V2D_SCROLL_WIDTH;
- v2d->mask.xmin = v2d->vert.xmax + 1;
+ v2d->vert = *mask_scroll;
+ v2d->vert.xmax = scroll_width;
}
else if (scroll & V2D_SCROLL_RIGHT) {
/* on right-hand edge of region */
- v2d->vert = v2d->mask;
+ v2d->vert = *mask_scroll;
v2d->vert.xmax++; /* one pixel extra... was leaving a minor gap... */
- v2d->vert.xmin = v2d->vert.xmax - V2D_SCROLL_WIDTH;
- v2d->mask.xmax = v2d->vert.xmin - 1;
+ v2d->vert.xmin = v2d->vert.xmax - scroll_width;
}
/* horizontal scroller */
if (scroll & (V2D_SCROLL_BOTTOM)) {
/* on bottom edge of region */
- v2d->hor = v2d->mask;
- v2d->hor.ymax = V2D_SCROLL_HEIGHT;
- v2d->mask.ymin = v2d->hor.ymax + 1;
+ v2d->hor = *mask_scroll;
+ v2d->hor.ymax = scroll_height;
}
else if (scroll & V2D_SCROLL_TOP) {
/* on upper edge of region */
- v2d->hor = v2d->mask;
- v2d->hor.ymin = v2d->hor.ymax - V2D_SCROLL_HEIGHT;
- v2d->mask.ymax = v2d->hor.ymin - 1;
+ v2d->hor = *mask_scroll;
+ v2d->hor.ymin = v2d->hor.ymax - scroll_height;
}
/* adjust vertical scroller if there's a horizontal scroller, to leave corner free */
if (scroll & V2D_SCROLL_VERTICAL) {
- /* just set y min/max for vertical scroller to y min/max of mask as appropriate */
if (scroll & (V2D_SCROLL_BOTTOM)) {
/* on bottom edge of region */
- v2d->vert.ymin = v2d->mask.ymin;
+ v2d->vert.ymin = v2d->hor.ymax;
}
else if (scroll & V2D_SCROLL_TOP) {
/* on upper edge of region */
- v2d->vert.ymax = v2d->mask.ymax;
+ v2d->vert.ymax = v2d->hor.ymin;
}
}
}
@@ -355,7 +369,12 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
v2d->winy = winy;
/* set masks (always do), but leave scroller scheck to totrect_set */
- view2d_masks(v2d, 0);
+ view2d_masks(v2d, 0, NULL);
+
+ if (do_init) {
+ /* Visible by default. */
+ v2d->alpha_hor = v2d->alpha_vert = 255;
+ }
/* set 'tot' rect before setting cur? */
/* XXX confusing stuff here still - I made this function not check scroller hide - that happens in totrect_set */
@@ -774,7 +793,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mas
}
/* set masks */
- view2d_masks(v2d, mask_scrollers);
+ view2d_masks(v2d, mask_scrollers, NULL);
}
void UI_view2d_curRect_validate(View2D *v2d)
@@ -813,7 +832,7 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
}
/* region possibly changed, so refresh */
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_no_rebuild(ar);
}
}
}
@@ -839,7 +858,7 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
}
/* region possibly changed, so refresh */
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_no_rebuild(ar);
}
}
}
@@ -1107,9 +1126,6 @@ void UI_view2d_view_ortho(View2D *v2d)
/* set matrix on all appropriate axes */
wmOrtho2(curmasked.xmin, curmasked.xmax, curmasked.ymin, curmasked.ymax);
-
- /* XXX is this necessary? */
- glLoadIdentity();
}
/**
@@ -1137,9 +1153,6 @@ void UI_view2d_view_orthoSpecial(ARegion *ar, View2D *v2d, const bool xaxis)
wmOrtho2(curmasked.xmin - xofs, curmasked.xmax - xofs, -yofs, ar->winy - yofs);
else
wmOrtho2(-xofs, ar->winx - xofs, curmasked.ymin - yofs, curmasked.ymax - yofs);
-
- /* XXX is this necessary? */
- glLoadIdentity();
}
@@ -1151,7 +1164,7 @@ void UI_view2d_view_restore(const bContext *C)
int height = BLI_rcti_size_y(&ar->winrct) + 1;
wmOrtho2(0.0f, (float)width, 0.0f, (float)height);
- glLoadIdentity();
+ GPU_matrix_identity_set();
// ED_region_pixelspace(CTX_wm_region(C));
}
@@ -1305,12 +1318,45 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
{
float vec1[2], vec2[2];
int a, step;
+ int vertical_minor_step = (BLI_rcti_size_x(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC),
+ horizontal_major_step = (BLI_rcti_size_y(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC);
+ unsigned char grid_line_color[3];
/* check for grid first, as it may not exist */
if (grid == NULL)
return;
- glBegin(GL_LINES);
+ /* Count the needed vertices for the gridlines */
+ unsigned vertex_count = 0;
+ if (flag & V2D_VERTICAL_LINES) {
+ /* vertical lines */
+ vertex_count += 2 * vertical_minor_step; /* minor gridlines */
+ vertex_count += 2 * (vertical_minor_step + 2); /* major gridlines */
+ }
+ if (flag & V2D_HORIZONTAL_LINES) {
+ /* horizontal lines */
+ vertex_count += 2 * (horizontal_major_step + 1); /* major gridlines */
+
+ /* fine lines */
+ if (flag & V2D_HORIZONTAL_FINELINES)
+ vertex_count += 2 * (horizontal_major_step + 1);
+ }
+ /* axes */
+ if (flag & V2D_HORIZONTAL_AXIS)
+ vertex_count += 2;
+ if (flag & V2D_VERTICAL_AXIS)
+ vertex_count += 2;
+
+ /* If there is nothing to render, exit early */
+ if (vertex_count == 0)
+ return;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GPU_PRIM_LINES, vertex_count);
/* vertical lines */
if (flag & V2D_VERTICAL_LINES) {
@@ -1320,24 +1366,31 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
vec2[1] = v2d->cur.ymax;
/* minor gridlines */
- step = (BLI_rcti_size_x(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC);
- UI_ThemeColor(TH_GRID);
+ step = vertical_minor_step;
+ if (step != 0) {
+ UI_GetThemeColor3ubv(TH_GRID, grid_line_color);
- for (a = 0; a < step; a++) {
- glVertex2fv(vec1);
- glVertex2fv(vec2);
+ for (a = 0; a < step; a++) {
+ immAttrSkip(color);
+ immVertex2fv(pos, vec1);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
- vec2[0] = vec1[0] += grid->dx;
+ vec2[0] = vec1[0] += grid->dx;
+ }
}
/* major gridlines */
vec2[0] = vec1[0] -= 0.5f * grid->dx;
- UI_ThemeColorShade(TH_GRID, 16);
+
+ UI_GetThemeColorShade3ubv(TH_GRID, 16, grid_line_color);
step++;
for (a = 0; a <= step; a++) {
- glVertex2fv(vec1);
- glVertex2fv(vec2);
+ immAttrSkip(color);
+ immVertex2fv(pos, vec1);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
vec2[0] = vec1[0] -= grid->dx;
}
@@ -1350,12 +1403,15 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
vec1[0] = grid->startx;
vec2[0] = v2d->cur.xmax;
- step = (BLI_rcti_size_y(&v2d->mask) + 1) / (U.v2d_min_gridsize * UI_DPI_FAC);
+ step = horizontal_major_step;
+
+ UI_GetThemeColor3ubv(TH_GRID, grid_line_color);
- UI_ThemeColor(TH_GRID);
for (a = 0; a <= step; a++) {
- glVertex2fv(vec1);
- glVertex2fv(vec2);
+ immAttrSkip(color);
+ immVertex2fv(pos, vec1);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
vec2[1] = vec1[1] += grid->dy;
}
@@ -1365,10 +1421,12 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
step++;
if (flag & V2D_HORIZONTAL_FINELINES) {
- UI_ThemeColorShade(TH_GRID, 16);
+ UI_GetThemeColorShade3ubv(TH_GRID, 16, grid_line_color);
for (a = 0; a < step; a++) {
- glVertex2fv(vec1);
- glVertex2fv(vec2);
+ immAttrSkip(color);
+ immVertex2fv(pos, vec1);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
vec2[1] = vec1[1] -= grid->dy;
}
@@ -1376,7 +1434,7 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
}
/* Axes are drawn as darker lines */
- UI_ThemeColorShade(TH_GRID, -50);
+ UI_GetThemeColorShade3ubv(TH_GRID, -50, grid_line_color);
/* horizontal axis */
if (flag & V2D_HORIZONTAL_AXIS) {
@@ -1384,8 +1442,10 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
vec2[0] = v2d->cur.xmax;
vec1[1] = vec2[1] = 0.0f;
- glVertex2fv(vec1);
- glVertex2fv(vec2);
+ immAttrSkip(color);
+ immVertex2fv(pos, vec1);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
}
/* vertical axis */
@@ -1394,91 +1454,157 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
vec2[1] = v2d->cur.ymax;
vec1[0] = vec2[0] = 0.0f;
- glVertex2fv(vec1);
- glVertex2fv(vec2);
+ immAttrSkip(color);
+ immVertex2fv(pos, vec1);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2fv(pos, vec2);
}
- glEnd();
+ immEnd();
+ immUnbindProgram();
}
/* Draw a constant grid in given 2d-region */
void UI_view2d_constant_grid_draw(View2D *v2d, float step)
{
- float start;
+ float start_x, start_y;
+ int count_x, count_y;
- UI_ThemeColorShade(TH_BACK, -10);
+ start_x = v2d->cur.xmin;
+ if (start_x < 0.0)
+ start_x += -(float)fmod(v2d->cur.xmin, step);
+ else
+ start_x += (step - (float)fmod(v2d->cur.xmin, step));
- start = v2d->cur.xmin - (float)fmod(v2d->cur.xmin, step);
+ if (start_x > v2d->cur.xmax)
+ count_x = 0;
+ else
+ count_x = (v2d->cur.xmax - start_x) / step + 1;
- glBegin(GL_LINES);
- for (; start < v2d->cur.xmax; start += step) {
- glVertex2f(start, v2d->cur.ymin);
- glVertex2f(start, v2d->cur.ymax);
- }
+ start_y = v2d->cur.ymin;
+ if (start_y < 0.0)
+ start_y += -(float)fmod(v2d->cur.ymin, step);
+ else
+ start_y += (step - (float)fabs(fmod(v2d->cur.ymin, step)));
- start = v2d->cur.ymin - (float)fmod(v2d->cur.ymin, step);
- for (; start < v2d->cur.ymax; start += step) {
- glVertex2f(v2d->cur.xmin, start);
- glVertex2f(v2d->cur.xmax, start);
- }
+ if (start_y > v2d->cur.ymax)
+ count_y = 0;
+ else
+ count_y = (v2d->cur.ymax - start_y) / step + 1;
- /* X and Y axis */
- UI_ThemeColorShade(TH_BACK, -18);
- glVertex2f(0.0f, v2d->cur.ymin);
- glVertex2f(0.0f, v2d->cur.ymax);
- glVertex2f(v2d->cur.xmin, 0.0f);
- glVertex2f(v2d->cur.xmax, 0.0f);
+ if (count_x > 0 || count_y > 0) {
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ float theme_color[3];
+
+ UI_GetThemeColorShade3fv(TH_BACK, -10, theme_color);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GPU_PRIM_LINES, count_x * 2 + count_y * 2 + 4);
+
+ immAttr3fv(color, theme_color);
+ for (int i = 0; i < count_x ; start_x += step, i++) {
+ immVertex2f(pos, start_x, v2d->cur.ymin);
+ immVertex2f(pos, start_x, v2d->cur.ymax);
+ }
+
+ for (int i = 0; i < count_y; start_y += step, i++) {
+ immVertex2f(pos, v2d->cur.xmin, start_y);
+ immVertex2f(pos, v2d->cur.xmax, start_y);
+ }
- glEnd();
+ /* X and Y axis */
+ UI_GetThemeColorShade3fv(TH_BACK, -18, theme_color);
+
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, 0.0f, v2d->cur.ymin);
+ immVertex2f(pos, 0.0f, v2d->cur.ymax);
+ immVertex2f(pos, v2d->cur.xmin, 0.0f);
+ immVertex2f(pos, v2d->cur.xmax, 0.0f);
+
+ immEnd();
+ immUnbindProgram();
+ }
}
/* Draw a multi-level grid in given 2d-region */
void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels)
{
+ /* Exit if there is nothing to draw */
+ if (totlevels == 0)
+ return;
+
int offset = -10;
float lstep = step;
- int level;
+ unsigned char grid_line_color[3];
- glLineWidth(1.0f);
- for (level = 0; level < totlevels; ++level) {
- int i;
- float start;
+ /* Make an estimate of at least how many vertices will be needed */
+ unsigned vertex_count = 4;
+ vertex_count += 2 * ((int)((v2d->cur.xmax - v2d->cur.xmin) / lstep) + 1);
+ vertex_count += 2 * ((int)((v2d->cur.ymax - v2d->cur.ymin) / lstep) + 1);
- UI_ThemeColorShade(colorid, offset);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- i = (v2d->cur.xmin >= 0.0f ? -(int)(-v2d->cur.xmin / lstep) : (int)(v2d->cur.xmin / lstep));
- start = i * lstep;
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBeginAtMost(GPU_PRIM_LINES, vertex_count);
+
+ for (int level = 0; level < totlevels; ++level) {
+ UI_GetThemeColorShade3ubv(colorid, offset, grid_line_color);
+
+ int i = (int)(v2d->cur.xmin / lstep);
+ if (v2d->cur.xmin > 0.0f)
+ i++;
+ float start = i * lstep;
- glBegin(GL_LINES);
for (; start < v2d->cur.xmax; start += lstep, ++i) {
if (i == 0 || (level < totlevels - 1 && i % level_size == 0))
continue;
- glVertex2f(start, v2d->cur.ymin);
- glVertex2f(start, v2d->cur.ymax);
+
+ immAttrSkip(color);
+ immVertex2f(pos, start, v2d->cur.ymin);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2f(pos, start, v2d->cur.ymax);
}
- i = (v2d->cur.ymin >= 0.0f ? -(int)(-v2d->cur.ymin / lstep) : (int)(v2d->cur.ymin / lstep));
+ i = (int)(v2d->cur.ymin / lstep);
+ if (v2d->cur.ymin > 0.0f)
+ i++;
start = i * lstep;
for (; start < v2d->cur.ymax; start += lstep, ++i) {
if (i == 0 || (level < totlevels - 1 && i % level_size == 0))
continue;
- glVertex2f(v2d->cur.xmin, start);
- glVertex2f(v2d->cur.xmax, start);
- }
- /* X and Y axis */
- UI_ThemeColorShade(colorid, offset - 8);
- glVertex2f(0.0f, v2d->cur.ymin);
- glVertex2f(0.0f, v2d->cur.ymax);
- glVertex2f(v2d->cur.xmin, 0.0f);
- glVertex2f(v2d->cur.xmax, 0.0f);
-
- glEnd();
+ immAttrSkip(color);
+ immVertex2f(pos, v2d->cur.xmin, start);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2f(pos, v2d->cur.xmax, start);
+ }
lstep *= level_size;
offset -= 6;
}
+
+ /* X and Y axis */
+ UI_GetThemeColorShade3ubv(colorid, -18 + ((totlevels - 1) * -6), grid_line_color);
+
+ immAttrSkip(color);
+ immVertex2f(pos, 0.0f, v2d->cur.ymin);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2f(pos, 0.0f, v2d->cur.ymax);
+
+ immAttrSkip(color);
+ immVertex2f(pos, v2d->cur.xmin, 0.0f);
+ immAttr3ubv(color, grid_line_color);
+ immVertex2f(pos, v2d->cur.xmax, 0.0f);
+
+ immEnd();
+ immUnbindProgram();
}
/* the price we pay for not exposting structs :( */
@@ -1522,7 +1648,7 @@ struct View2DScrollers {
/* Calculate relevant scroller properties */
View2DScrollers *UI_view2d_scrollers_calc(
- const bContext *C, View2D *v2d,
+ const bContext *C, View2D *v2d, const rcti *mask_custom,
short xunits, short xclamp, short yunits, short yclamp)
{
View2DScrollers *scrollers;
@@ -1534,11 +1660,14 @@ View2DScrollers *UI_view2d_scrollers_calc(
/* scrollers is allocated here... */
scrollers = MEM_callocN(sizeof(View2DScrollers), "View2DScrollers");
+ /* Always update before drawing (for dynamically sized scrollers). */
+ view2d_masks(v2d, false, mask_custom);
+
vert = v2d->vert;
hor = v2d->hor;
/* slider rects need to be smaller than region */
- smaller = (int)(0.2f * U.widget_unit);
+ smaller = (int)(0.1f * U.widget_unit);
hor.xmin += smaller;
hor.xmax -= smaller;
if (scroll & V2D_SCROLL_BOTTOM)
@@ -1698,9 +1827,15 @@ static void scroll_printstr(Scene *scene, float x, float y, float val, int power
/* Draw scrollbars in the given 2d-region */
void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *vs)
{
+ bTheme *btheme = UI_GetTheme();
Scene *scene = CTX_data_scene(C);
rcti vert, hor;
- int scroll = view2d_scroll_mapped(v2d->scroll);
+ const int scroll = view2d_scroll_mapped(v2d->scroll);
+ const char emboss_alpha = btheme->tui.widget_emboss[3];
+ unsigned char scrollers_back_color[4];
+
+ /* Color for scrollbar backs */
+ UI_GetThemeColor4ubv(TH_BACK, scrollers_back_color);
/* make copies of rects for less typing */
vert = vs->vert;
@@ -1708,11 +1843,10 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
/* horizontal scrollbar */
if (scroll & V2D_SCROLL_HORIZONTAL) {
- bTheme *btheme = UI_GetTheme();
uiWidgetColors wcol = btheme->tui.wcol_scroll;
+ const float alpha_fac = v2d->alpha_hor / 255.0f;
rcti slider;
int state;
- unsigned char col[4];
slider.xmin = vs->hor_min;
slider.xmax = vs->hor_max;
@@ -1721,6 +1855,11 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
state = (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE) ? UI_SCROLL_PRESSED : 0;
+ wcol.inner[3] *= alpha_fac;
+ wcol.item[3] *= alpha_fac;
+ wcol.outline[3] *= alpha_fac;
+ btheme->tui.widget_emboss[3] *= alpha_fac; /* will be reset later */
+
/* show zoom handles if:
* - zooming on x-axis is allowed (no scroll otherwise)
* - slider bubble is large enough (no overdraw confusion)
@@ -1735,17 +1874,11 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
state |= UI_SCROLL_ARROWS;
}
- /* clean rect behind slider, but not with transparent background */
- UI_GetThemeColor4ubv(TH_BACK, col);
- if (col[3] == 255) {
- glColor3ub(col[0], col[1], col[2]);
- glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax);
- }
-
UI_draw_widget_scroll(&wcol, &hor, &slider, state);
/* scale indicators */
if ((scroll & V2D_SCROLL_SCALE_HORIZONTAL) && (vs->grid)) {
+ const int font_id = BLF_default();
View2DGrid *grid = vs->grid;
float fac, dfac, fac2, val;
@@ -1760,7 +1893,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
dfac = dfac * BLI_rcti_size_x(&hor);
/* set starting value, and text color */
- UI_ThemeColor(TH_TEXT);
+ UI_FontThemeColor(font_id, TH_TEXT);
val = grid->startx;
/* if we're clamping to whole numbers only, make sure entries won't be repeated */
@@ -1777,6 +1910,8 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
if (dfac > 0.0f) {
float h = 0.1f * UI_UNIT_Y + (float)(hor.ymin);
+ BLF_batch_draw_begin();
+
for (; fac < hor.xmax - 0.5f * U.widget_unit; fac += dfac, val += grid->dx) {
/* make prints look nicer for scrollers */
@@ -1803,17 +1938,18 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
break;
}
}
+
+ BLF_batch_draw_end();
}
}
}
/* vertical scrollbar */
if (scroll & V2D_SCROLL_VERTICAL) {
- bTheme *btheme = UI_GetTheme();
uiWidgetColors wcol = btheme->tui.wcol_scroll;
rcti slider;
+ const float alpha_fac = v2d->alpha_vert / 255.0f;
int state;
- unsigned char col[4];
slider.xmin = vert.xmin;
slider.xmax = vert.xmax;
@@ -1822,6 +1958,11 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
state = (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE) ? UI_SCROLL_PRESSED : 0;
+ wcol.inner[3] *= alpha_fac;
+ wcol.item[3] *= alpha_fac;
+ wcol.outline[3] *= alpha_fac;
+ btheme->tui.widget_emboss[3] *= alpha_fac; /* will be reset later */
+
/* show zoom handles if:
* - zooming on y-axis is allowed (no scroll otherwise)
* - slider bubble is large enough (no overdraw confusion)
@@ -1836,13 +1977,6 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
state |= UI_SCROLL_ARROWS;
}
- /* clean rect behind slider, but not with transparent background */
- UI_GetThemeColor4ubv(TH_BACK, col);
- if (col[3] == 255) {
- glColor3ub(col[0], col[1], col[2]);
- glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax);
- }
-
UI_draw_widget_scroll(&wcol, &vert, &slider, state);
@@ -1864,7 +1998,8 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
dfac = dfac * BLI_rcti_size_y(&vert);
/* set starting value, and text color */
- UI_ThemeColor(TH_TEXT);
+ const int font_id = BLF_default();
+ UI_FontThemeColor(font_id, TH_TEXT);
val = grid->starty;
/* if vertical clamping (to whole numbers) is used (i.e. in Sequencer), apply correction */
@@ -1873,9 +2008,8 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
/* draw vertical steps */
if (dfac > 0.0f) {
-
- BLF_rotation_default(M_PI_2);
- BLF_enable_default(BLF_ROTATION);
+ BLF_rotation(font_id, M_PI_2);
+ BLF_enable(font_id, BLF_ROTATION);
for (; fac < vert.ymax - 10; fac += dfac, val += grid->dy) {
@@ -1886,11 +2020,13 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
scroll_printstr(scene, (float)(vert.xmax) - 2.0f, fac, val, grid->powery, vs->yunits, 'v');
}
- BLF_disable_default(BLF_ROTATION);
+ BLF_disable(font_id, BLF_ROTATION);
}
}
}
+ /* Was changed above, so reset. */
+ btheme->tui.widget_emboss[3] = emboss_alpha;
}
/* free temporary memory used for drawing scrollers */
@@ -2023,11 +2159,11 @@ void UI_view2d_listview_visible_cells(
/* *********************************************************************** */
/* Coordinate Conversions */
-float UI_view2d_region_to_view_x(struct View2D *v2d, float x)
+float UI_view2d_region_to_view_x(const struct View2D *v2d, float x)
{
return (v2d->cur.xmin + (BLI_rctf_size_x(&v2d->cur) * (x - v2d->mask.xmin) / BLI_rcti_size_x(&v2d->mask)));
}
-float UI_view2d_region_to_view_y(struct View2D *v2d, float y)
+float UI_view2d_region_to_view_y(const struct View2D *v2d, float y)
{
return (v2d->cur.ymin + (BLI_rctf_size_y(&v2d->cur) * (y - v2d->mask.ymin) / BLI_rcti_size_y(&v2d->mask)));
}
@@ -2038,13 +2174,13 @@ float UI_view2d_region_to_view_y(struct View2D *v2d, float y)
* \param x, y: coordinates to convert
* \param r_view_x, r_view_y: resultant coordinates
*/
-void UI_view2d_region_to_view(View2D *v2d, float x, float y, float *r_view_x, float *r_view_y)
+void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y)
{
*r_view_x = UI_view2d_region_to_view_x(v2d, x);
*r_view_y = UI_view2d_region_to_view_y(v2d, y);
}
-void UI_view2d_region_to_view_rctf(View2D *v2d, const rctf *rect_src, rctf *rect_dst)
+void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)};
@@ -2055,11 +2191,11 @@ void UI_view2d_region_to_view_rctf(View2D *v2d, const rctf *rect_src, rctf *rect
rect_dst->ymax = (v2d->cur.ymin + (cur_size[1] * (rect_src->ymax - v2d->mask.ymin) / mask_size[1]));
}
-float UI_view2d_view_to_region_x(View2D *v2d, float x)
+float UI_view2d_view_to_region_x(const View2D *v2d, float x)
{
return (v2d->mask.xmin + (((x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur)) * BLI_rcti_size_x(&v2d->mask)));
}
-float UI_view2d_view_to_region_y(View2D *v2d, float y)
+float UI_view2d_view_to_region_y(const View2D *v2d, float y)
{
return (v2d->mask.ymin + (((y - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur)) * BLI_rcti_size_y(&v2d->mask)));
}
@@ -2071,7 +2207,7 @@ float UI_view2d_view_to_region_y(View2D *v2d, float y)
* \param x, y: Coordinates to convert.
* \param r_region_x, r_region_y: Resultant coordinates.
*/
-bool UI_view2d_view_to_region_clip(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
+bool UI_view2d_view_to_region_clip(const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
/* express given coordinates as proportional values */
x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
@@ -2293,17 +2429,20 @@ void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac)
* Check if mouse is within scrollers
*
* \param x, y: Mouse coordinates in screen (not region) space.
+ * \param r_scroll: Mapped view2d scroll flag.
*
* \return appropriate code for match.
* - 'h' = in horizontal scroller.
* - 'v' = in vertical scroller.
* - 0 = not in scroller.
*/
-short UI_view2d_mouse_in_scrollers(const bContext *C, View2D *v2d, int x, int y)
+char UI_view2d_mouse_in_scrollers_ex(
+ const ARegion *ar, View2D *v2d, int x, int y,
+ int *r_scroll)
{
- ARegion *ar = CTX_wm_region(C);
int co[2];
int scroll = view2d_scroll_mapped(v2d->scroll);
+ *r_scroll = scroll;
/* clamp x,y to region-coordinates first */
co[0] = x - ar->winrct.xmin;
@@ -2321,6 +2460,13 @@ short UI_view2d_mouse_in_scrollers(const bContext *C, View2D *v2d, int x, int y)
return 0;
}
+char UI_view2d_mouse_in_scrollers(
+ const ARegion *ar, View2D *v2d, int x, int y)
+{
+ int scroll_dummy = 0;
+ return UI_view2d_mouse_in_scrollers_ex(ar, v2d, x, y, &scroll_dummy);
+}
+
/* ******************* view2d text drawing cache ******************** */
typedef struct View2DString {
@@ -2410,7 +2556,8 @@ void UI_view2d_text_cache_draw(ARegion *ar)
int col_pack_prev = 0;
/* investigate using BLF_ascender() */
- const float default_height = g_v2d_strings ? BLF_height_default("28", 3) : 0.0f;
+ const int font_id = BLF_default();
+ const float default_height = g_v2d_strings ? BLF_height(font_id, "28", 3) : 0.0f;
wmOrtho2_region_pixelspace(ar);
@@ -2421,7 +2568,7 @@ void UI_view2d_text_cache_draw(ARegion *ar)
if (yofs < 1) yofs = 1;
if (col_pack_prev != v2s->col.pack) {
- glColor3ubv(v2s->col.ub);
+ BLF_color3ubv(font_id, v2s->col.ub);
col_pack_prev = v2s->col.pack;
}
@@ -2430,12 +2577,11 @@ void UI_view2d_text_cache_draw(ARegion *ar)
(float)(v2s->mval[0] + xofs), (float)(v2s->mval[1] + yofs), 0.0,
v2s->str, BLF_DRAW_STR_DUMMY_MAX);
else {
- BLF_clipping_default(v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4);
- BLF_enable_default(BLF_CLIPPING);
- BLF_draw_default(
- v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f,
- v2s->str, BLF_DRAW_STR_DUMMY_MAX);
- BLF_disable_default(BLF_CLIPPING);
+ BLF_enable(font_id, BLF_CLIPPING);
+ BLF_clipping(font_id, v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4);
+ BLF_draw_default(v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f,
+ v2s->str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_disable(font_id, BLF_CLIPPING);
}
}
g_v2d_strings = NULL;
@@ -2444,11 +2590,6 @@ void UI_view2d_text_cache_draw(ARegion *ar)
BLI_memarena_free(g_v2d_strings_arena);
g_v2d_strings_arena = NULL;
}
-
- // glMatrixMode(GL_PROJECTION);
- // glPopMatrix();
- // glMatrixMode(GL_MODELVIEW);
- // glPopMatrix();
}
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index e08f9535e1f..62bc7e87f0e 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -169,18 +170,13 @@ static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float
/* validate that view is in valid configuration after this operation */
UI_view2d_curRect_validate(v2d);
+ /* don't rebuild full tree in outliner, since we're just changing our view */
+ ED_region_tag_redraw_no_rebuild(vpd->ar);
+
/* request updates to be done... */
- ED_region_tag_redraw(vpd->ar);
WM_event_add_mousemove(C);
UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY);
-
- /* exceptions */
- if (vpd->sa->spacetype == SPACE_OUTLINER) {
- /* don't rebuild full tree, since we're just changing our view */
- SpaceOops *soops = vpd->sa->spacedata.first;
- soops->storeflag |= SO_TREESTORE_REDRAW;
- }
}
static void view_pan_apply(bContext *C, wmOperator *op)
@@ -358,7 +354,7 @@ static int view_scrollright_exec(bContext *C, wmOperator *op)
}
/* set RNA-Props - only movement in positive x-direction */
- RNA_int_set(op->ptr, "deltax", 20);
+ RNA_int_set(op->ptr, "deltax", 40);
RNA_int_set(op->ptr, "deltay", 0);
/* apply movement, then we're done */
@@ -402,7 +398,7 @@ static int view_scrollleft_exec(bContext *C, wmOperator *op)
}
/* set RNA-Props - only movement in negative x-direction */
- RNA_int_set(op->ptr, "deltax", -20);
+ RNA_int_set(op->ptr, "deltax", -40);
RNA_int_set(op->ptr, "deltay", 0);
/* apply movement, then we're done */
@@ -642,6 +638,7 @@ static void view_zoomstep_apply_ex(
View2D *v2d = &ar->v2d;
const rctf cur_old = v2d->cur;
float dx, dy;
+ const int snap_test = ED_region_snap_size_test(ar);
/* calculate amount to move view by, ensuring symmetry so the
* old zoom level is restored after zooming back the same amount
@@ -726,8 +723,14 @@ static void view_zoomstep_apply_ex(
/* validate that view is in valid configuration after this operation */
UI_view2d_curRect_validate(v2d);
+ if (ED_region_snap_size_apply(ar, snap_test)) {
+ ScrArea *sa = CTX_wm_area(C);
+ ED_area_tag_redraw(sa);
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ }
+
/* request updates to be done... */
- ED_region_tag_redraw(vzd->ar);
+ ED_region_tag_redraw_no_rebuild(vzd->ar);
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
}
@@ -902,6 +905,7 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op)
v2dViewZoomData *vzd = op->customdata;
View2D *v2d = vzd->v2d;
float dx, dy;
+ const int snap_test = ED_region_snap_size_test(vzd->ar);
/* get amount to move view by */
dx = RNA_float_get(op->ptr, "deltax");
@@ -966,8 +970,14 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op)
/* validate that view is in valid configuration after this operation */
UI_view2d_curRect_validate(v2d);
+ if (ED_region_snap_size_apply(vzd->ar, snap_test)) {
+ ScrArea *sa = CTX_wm_area(C);
+ ED_area_tag_redraw(sa);
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ }
+
/* request updates to be done... */
- ED_region_tag_redraw(vzd->ar);
+ ED_region_tag_redraw_no_rebuild(vzd->ar);
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
}
@@ -1212,7 +1222,7 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
/* BORDER-ZOOM */
/**
- * The user defines a rect using standard borderselect tools, and we use this rect to
+ * The user defines a rect using standard box select tools, and we use this rect to
* define the new zoom-level of the view in the following ways:
*
* -# LEFTMOUSE - zoom in to view
@@ -1292,15 +1302,15 @@ static void VIEW2D_OT_zoom_border(wmOperatorType *ot)
ot->idname = "VIEW2D_OT_zoom_border";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = view_borderzoom_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = view_zoom_poll;
/* rna */
- WM_operator_properties_gesture_border_zoom(ot);
+ WM_operator_properties_gesture_box_zoom(ot);
}
#ifdef WITH_INPUT_NDOF
@@ -1488,7 +1498,7 @@ void UI_view2d_smooth_view(
v2d->cur = sms.new_cur;
UI_view2d_curRect_validate(v2d);
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_no_rebuild(ar);
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
}
}
@@ -1532,7 +1542,7 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
UI_view2d_curRect_validate(v2d);
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_no_rebuild(ar);
if (v2d->sms == NULL) {
UI_view2d_zoom_cache_reset();
@@ -1555,7 +1565,7 @@ static void VIEW2D_OT_smoothview(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
/* rna */
- WM_operator_properties_gesture_border(ot);
+ WM_operator_properties_gesture_box(ot);
}
/* ********************************************************* */
@@ -1576,7 +1586,7 @@ typedef struct v2dScrollerMove {
View2D *v2d; /* View2D data that this operation affects */
ARegion *ar; /* region that the scroller is in */
- short scroller; /* scroller that mouse is in ('h' or 'v') */
+ char scroller; /* scroller that mouse is in ('h' or 'v') */
short zone; /* -1 is min zoomer, 0 is bar, 1 is max zoomer */ // XXX find some way to provide visual feedback of this (active color?)
float fac; /* view adjustment factor, based on size of region */
@@ -1667,8 +1677,23 @@ static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_
return SCROLLHANDLE_BAR;
}
+static bool scroller_activate_poll(bContext *C)
+{
+ if (!view2d_poll(C)) {
+ return false;
+ }
+
+ wmWindow *win = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ View2D *v2d = &ar->v2d;
+ wmEvent *event = win->eventstate;
+
+ /* check if mouse in scrollbars, if they're enabled */
+ return (UI_view2d_mouse_in_scrollers(ar, v2d, event->x, event->y) != 0);
+}
+
/* initialize customdata for scroller manipulation operator */
-static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *event, short in_scroller)
+static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *event, const char in_scroller)
{
v2dScrollerMove *vsm;
View2DScrollers *scrollers;
@@ -1692,7 +1717,7 @@ static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *e
/* 'zone' depends on where mouse is relative to bubble
* - zooming must be allowed on this axis, otherwise, default to pan
*/
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
/* use a union of 'cur' & 'tot' incase the current view is far outside 'tot'.
* In this cases moving the scroll bars has far too little effect and the view can get stuck [#31476] */
@@ -1745,7 +1770,7 @@ static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *e
}
UI_view2d_scrollers_free(scrollers);
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_no_rebuild(ar);
}
/* cleanup temp customdata */
@@ -1759,7 +1784,7 @@ static void scroller_activate_exit(bContext *C, wmOperator *op)
MEM_freeN(op->customdata);
op->customdata = NULL;
- ED_region_tag_redraw(CTX_wm_region(C));
+ ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
}
}
@@ -1821,7 +1846,7 @@ static void scroller_activate_apply(bContext *C, wmOperator *op)
UI_view2d_curRect_validate(v2d);
/* request updates to be done... */
- ED_region_tag_redraw(vsm->ar);
+ ED_region_tag_redraw_no_rebuild(vsm->ar);
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
}
@@ -1902,10 +1927,9 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent *
{
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
- short in_scroller = 0;
/* check if mouse in scrollbars, if they're enabled */
- in_scroller = UI_view2d_mouse_in_scrollers(C, v2d, event->x, event->y);
+ const char in_scroller = UI_view2d_mouse_in_scrollers(ar, v2d, event->x, event->y);
/* if in a scroller, init customdata then set modal handler which will catch mousedown to start doing useful stuff */
if (in_scroller) {
@@ -1999,7 +2023,7 @@ static void VIEW2D_OT_scroller_activate(wmOperatorType *ot)
ot->modal = scroller_activate_modal;
ot->cancel = scroller_activate_cancel;
- ot->poll = view2d_poll;
+ ot->poll = scroller_activate_poll;
}
/* ********************************************************* */
@@ -2011,6 +2035,7 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
int winx, winy;
+ const int snap_test = ED_region_snap_size_test(ar);
/* zoom 1.0 */
winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1);
@@ -2045,6 +2070,12 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
/* validate that view is in valid configuration after this operation */
UI_view2d_curRect_validate(v2d);
+ if (ED_region_snap_size_apply(ar, snap_test)) {
+ ScrArea *sa = CTX_wm_area(C);
+ ED_area_tag_redraw(sa);
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ }
+
/* request updates to be done... */
ED_region_tag_redraw(ar);
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
@@ -2097,85 +2128,5 @@ void ED_operatortypes_view2d(void)
void ED_keymap_view2d(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "View2D", 0, 0);
- wmKeyMapItem *kmi;
-
- /* scrollers */
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroller_activate", LEFTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroller_activate", MIDDLEMOUSE, KM_PRESS, 0, 0);
-
- /* pan/scroll */
- WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MOUSEPAN, 0, 0, 0);
-
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0);
-
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "VIEW2D_OT_ndof", NDOF_MOTION, 0, 0, 0);
-#endif
-
- /* zoom - single step */
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0);
-
- WM_keymap_verify_item(keymap, "VIEW2D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
-
- /* scroll up/down - no modifiers, only when zoom fails */
- /* these may fail if zoom is disallowed, in which case they should pass on event */
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, 0, 0);
- /* these may be necessary if vertical scroll is disallowed */
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", WHEELDOWNMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", WHEELUPMOUSE, KM_PRESS, 0, 0);
-
- /* alternatives for page up/down to scroll */
-#if 0 // XXX disabled, since this causes conflicts with hotkeys in animation editors
- /* scroll up/down may fall through to left/right */
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", PAGEDOWNKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", PAGEUPKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", PAGEDOWNKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", PAGEUPKEY, KM_PRESS, 0, 0);
- /* shift for moving view left/right with page up/down */
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0);
-#endif
-
- /* zoom - drag */
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0);
-
- /* borderzoom - drag */
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_border", BKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* Alternative keymap for buttons listview */
- keymap = WM_keymap_ensure(keyconf, "View2D Buttons List", 0, 0);
-
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroller_activate", LEFTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroller_activate", MIDDLEMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MOUSEPAN, 0, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", PAGEDOWNKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "page", true);
- kmi = WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", PAGEUPKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "page", true);
-
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW2D_OT_reset", HOMEKEY, KM_PRESS, 0, 0);
+ WM_keymap_ensure(keyconf, "View2D", 0, 0);
}
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index b3bbce939a5..4d3f106a5d6 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../depsgraph
../../makesdna
../../makesrna
../../windowmanager
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 9131243b926..8e446c73eab 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -22,6 +22,10 @@
*
*/
+/** \file blender/editors/io/io_alembic.c
+ * \ingroup editor/io
+ */
+
#ifdef WITH_ALEMBIC
/* needed for directory lookup */
@@ -545,20 +549,10 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op)
}
}
- /* Switch to object mode to avoid being stuck in other modes (T54326). */
- if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT) {
- Object *obedit = CTX_data_edit_object(C);
-
- if (obedit != NULL) {
- ED_object_mode_toggle(C, obedit->mode);
- }
- else {
- Object *ob = CTX_data_active_object(C);
-
- if (ob) {
- ED_object_mode_toggle(C, ob->mode);
- }
- }
+ /* Switch out of edit mode to avoid being stuck in it (T54326). */
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit) {
+ ED_object_mode_toggle(C, OB_MODE_EDIT);
}
bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range,
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index 221142a6cf8..953dc24f6a5 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -22,6 +22,10 @@
*
*/
+/** \file blender/editors/io/io_cache.c
+ * \ingroup editor/io
+ */
+
#include "MEM_guardedalloc.h"
#include "DNA_cachefile_types.h"
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 76ddd221ea4..1b4298171fe 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -28,7 +28,7 @@
* \ingroup collada
*/
#ifdef WITH_COLLADA
-#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
@@ -36,11 +36,12 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_main.h"
-#include "BKE_report.h"
#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
#include "ED_screen.h"
#include "ED_object.h"
@@ -93,10 +94,12 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int deform_bones_only;
int include_animations;
- int sample_animations;
+ int include_all_actions;
int sampling_rate;
+ int keep_smooth_curves;
+ int keep_keyframes;
- int export_texture_type;
+ int export_animation_type;
int use_texture_copies;
int active_uv_only;
@@ -111,6 +114,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int keep_bind_info;
int export_count;
+ int sample_animations;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@@ -147,12 +151,15 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
include_shapekeys = RNA_boolean_get(op->ptr, "include_shapekeys");
include_animations = RNA_boolean_get(op->ptr, "include_animations");
- sample_animations = RNA_boolean_get(op->ptr, "sample_animations");
+ include_all_actions = RNA_boolean_get(op->ptr, "include_all_actions");
+ export_animation_type = RNA_enum_get(op->ptr, "export_animation_type_selection");
+ sample_animations = (export_animation_type == BC_ANIMATION_EXPORT_SAMPLES);
sampling_rate = (sample_animations) ? RNA_int_get(op->ptr, "sampling_rate") : 0;
+ keep_smooth_curves = RNA_boolean_get(op->ptr, "keep_smooth_curves");
+ keep_keyframes = RNA_boolean_get(op->ptr, "keep_keyframes");
deform_bones_only = RNA_boolean_get(op->ptr, "deform_bones_only");
- export_texture_type = RNA_enum_get(op->ptr, "export_texture_type_selection");
use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies");
active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only");
@@ -171,8 +178,8 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
/* get editmode results */
ED_object_editmode_load(bmain, CTX_data_edit_object(C));
- EvaluationContext *eval_ctx = bmain->eval_ctx;
- Scene *scene = CTX_data_scene(C);
+ //Scene *scene = CTX_data_scene(C);
+
ExportSettings export_settings;
export_settings.filepath = filepath;
@@ -184,18 +191,36 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
export_settings.include_armatures = include_armatures != 0;
export_settings.include_shapekeys = include_shapekeys != 0;
export_settings.deform_bones_only = deform_bones_only != 0;
- export_settings.include_animations = include_animations;
+ export_settings.include_animations = include_animations != 0;
+ export_settings.include_all_actions = include_all_actions != 0;
export_settings.sampling_rate = sampling_rate;
+ export_settings.keep_keyframes = keep_keyframes != 0 || sampling_rate < 1;
export_settings.active_uv_only = active_uv_only != 0;
- export_settings.export_texture_type = export_texture_type;
+ export_settings.export_animation_type = export_animation_type;
export_settings.use_texture_copies = use_texture_copies != 0;
export_settings.triangulate = triangulate != 0;
export_settings.use_object_instantiation = use_object_instantiation != 0;
export_settings.use_blender_profile = use_blender_profile != 0;
export_settings.sort_by_name = sort_by_name != 0;
- export_settings.export_transformation_type = export_transformation_type;
+
+ if (export_animation_type == BC_ANIMATION_EXPORT_SAMPLES) {
+ export_settings.export_transformation_type = export_transformation_type;
+ }
+ else {
+ // When curves are exported then we can not export as matrix
+ export_settings.export_transformation_type = BC_TRANSFORMATION_TYPE_TRANSROTLOC;
+ }
+
+ if (export_settings.export_transformation_type == BC_TRANSFORMATION_TYPE_TRANSROTLOC) {
+ export_settings.keep_smooth_curves = keep_smooth_curves != 0;
+ }
+ else {
+ // Can not export smooth curves when Matrix export is enabled.
+ export_settings.keep_smooth_curves = false;
+ }
+
export_settings.open_sim = open_sim != 0;
export_settings.limit_precision = limit_precision != 0;
export_settings.keep_bind_info = keep_bind_info != 0;
@@ -204,12 +229,10 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE;
if (export_settings.include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE;
-
export_count = collada_export(
C,
- eval_ctx,
- scene,
- &export_settings);
+ &export_settings
+ );
if (export_count == 0) {
BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file");
@@ -231,96 +254,134 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
{
uiLayout *box, *row, *col, *split;
bool include_animations = RNA_boolean_get(imfptr, "include_animations");
+ int ui_section = RNA_enum_get(imfptr, "prop_bc_export_ui_section");
+
+ BC_export_animation_type animation_type = RNA_enum_get(imfptr, "export_animation_type_selection");
+ BC_export_transformation_type transformation_type = RNA_enum_get(imfptr, "export_transformation_type_selection");
+
+ bool sampling = animation_type == BC_ANIMATION_EXPORT_SAMPLES;
/* Export Options: */
box = uiLayoutBox(layout);
- row = uiLayoutRow(box, false);
- uiItemL(row, IFACE_("Export Data Options:"), ICON_MESH_DATA);
row = uiLayoutRow(box, false);
- split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
- col = uiLayoutColumn(split, false);
- uiItemR(col, imfptr, "apply_modifiers", 0, NULL, ICON_NONE);
- col = uiLayoutColumn(split, false);
- uiItemR(col, imfptr, "export_mesh_type_selection", 0, "", ICON_NONE);
- uiLayoutSetEnabled(col, RNA_boolean_get(imfptr, "apply_modifiers"));
+ uiItemR(row, imfptr, "prop_bc_export_ui_section", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
+ if (ui_section == BC_UI_SECTION_MAIN) {
+ /* =================== */
+ /* Export Data options */
+ /* =================== */
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "include_children", 0, NULL, ICON_NONE);
- uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "include_armatures", 0, NULL, ICON_NONE);
- uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "include_children", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "include_shapekeys", 0, NULL, ICON_NONE);
- uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "include_armatures", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "include_animations", 0, NULL, ICON_NONE);
- row = uiLayoutRow(box, false);
- if (include_animations) {
- uiItemR(row, imfptr, "sample_animations", 0, NULL, ICON_NONE);
- row = uiLayoutColumn(box, false);
- uiItemR(row, imfptr, "sampling_rate", 0, NULL, ICON_NONE);
- uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "sample_animations"));
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "include_shapekeys", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "selected"));
+
+ /* Texture options */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Texture Options:"), ICON_TEXTURE_DATA);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "active_uv_only", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "use_texture_copies", 1, NULL, ICON_NONE);
+
+ }
+ else if (ui_section == BC_UI_SECTION_GEOMETRY) {
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Export Data Options:"), ICON_MESH_DATA);
+
+ row = uiLayoutRow(box, false);
+ split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
+ col = uiLayoutColumn(split, false);
+ uiItemR(col, imfptr, "apply_modifiers", 0, NULL, ICON_NONE);
+ col = uiLayoutColumn(split, false);
+ uiItemR(col, imfptr, "export_mesh_type_selection", 0, "", ICON_NONE);
+ uiLayoutSetEnabled(col, RNA_boolean_get(imfptr, "apply_modifiers"));
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "triangulate", 1, NULL, ICON_NONE);
}
+ else if (ui_section == BC_UI_SECTION_ARMATURE) {
+ /* Armature options */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Armature Options:"), ICON_ARMATURE_DATA);
- /* Texture options */
- box = uiLayoutBox(layout);
- row = uiLayoutRow(box, false);
- uiItemL(row, IFACE_("Texture Options:"), ICON_TEXTURE_DATA);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "deform_bones_only", 0, NULL, ICON_NONE);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "active_uv_only", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "open_sim", 0, NULL, ICON_NONE);
+ }
+ else if (ui_section == BC_UI_SECTION_ANIMATION) {
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "export_texture_type_selection", 0, "", ICON_NONE);
+ /* ====================== */
+ /* Animation Data options */
+ /* ====================== */
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "use_texture_copies", 1, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "include_animations", 0, NULL, ICON_NONE);
- /* Armature options */
- box = uiLayoutBox(layout);
- row = uiLayoutRow(box, false);
- uiItemL(row, IFACE_("Armature Options:"), ICON_ARMATURE_DATA);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "export_animation_type_selection", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "deform_bones_only", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
+ uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE);
+ uiLayoutSetEnabled(row, animation_type == BC_ANIMATION_EXPORT_SAMPLES);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "open_sim", 0, NULL, ICON_NONE);
+ row = uiLayoutColumn(box, false);
+ uiItemR(row, imfptr, "keep_smooth_curves", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, include_animations &&
+ (transformation_type == BC_TRANSFORMATION_TYPE_TRANSROTLOC || animation_type == BC_ANIMATION_EXPORT_KEYS));
- /* Collada options: */
- box = uiLayoutBox(layout);
- row = uiLayoutRow(box, false);
- uiItemL(row, IFACE_("Collada Options:"), ICON_MODIFIER);
+ row = uiLayoutColumn(box, false);
+ uiItemR(row, imfptr, "sampling_rate", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, sampling && include_animations);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "triangulate", 1, NULL, ICON_NONE);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "use_object_instantiation", 1, NULL, ICON_NONE);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "use_blender_profile", 1, NULL, ICON_NONE);
+ row = uiLayoutColumn(box, false);
+ uiItemR(row, imfptr, "keep_keyframes", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, sampling && include_animations);
- row = uiLayoutRow(box, false);
- split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
- uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
- uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "include_all_actions", 0, NULL, ICON_NONE);
+ uiLayoutSetEnabled(row, include_animations);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
+ }
+ else if (ui_section == BC_UI_SECTION_COLLADA) {
+ /* Collada options: */
+ box = uiLayoutBox(layout);
+ row = uiLayoutRow(box, false);
+ uiItemL(row, IFACE_("Collada Options:"), ICON_MODIFIER);
- row = uiLayoutRow(box, false);
- uiItemR(row, imfptr, "limit_precision", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "use_object_instantiation", 1, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "use_blender_profile", 1, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "limit_precision", 0, NULL, ICON_NONE);
+ }
}
static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op)
@@ -361,12 +422,22 @@ void WM_OT_collada_export(wmOperatorType *ot)
{ 0, NULL, 0, NULL, NULL }
};
- static const EnumPropertyItem prop_bc_export_texture_type[] = {
- { BC_TEXTURE_TYPE_MAT, "mat", 0, "Materials", "Export Materials" },
- { BC_TEXTURE_TYPE_UV, "uv", 0, "UV Textures", "Export UV Textures (Face textures) as materials" },
- { 0, NULL, 0, NULL, NULL }
+ static const EnumPropertyItem prop_bc_export_animation_type[] = {
+ { BC_ANIMATION_EXPORT_SAMPLES, "sample", 0, "Samples", "Export Sampled points guided by sampling rate" },
+ { BC_ANIMATION_EXPORT_KEYS, "keys", 0, "Curves", "Export Curves\n Note: guided by curve keys" },
+ { 0, NULL, 0, NULL, NULL }
};
+ static const EnumPropertyItem prop_bc_export_ui_section[] = {
+ { BC_UI_SECTION_MAIN, "main", 0, "Main", "Data Export Section" },
+ { BC_UI_SECTION_GEOMETRY, "geometry", 0, "Geom", "Geometry Export Section" },
+ { BC_UI_SECTION_ARMATURE, "armature", 0, "Arm", "Armature Export Section" },
+ { BC_UI_SECTION_ANIMATION, "animation", 0, "Anim", "Animation Export Section" },
+ { BC_UI_SECTION_COLLADA, "collada", 0, "Extra", "Collada Export Section" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+
ot->name = "Export COLLADA";
ot->description = "Save a Collada file";
ot->idname = "WM_OT_collada_export";
@@ -384,6 +455,9 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ RNA_def_enum(func, "prop_bc_export_ui_section", prop_bc_export_ui_section, 0,
+ "Export Section", "Only for User Interface Organisation");
+
RNA_def_boolean(func,
"apply_modifiers", 0, "Apply Modifiers",
"Apply modifiers to exported mesh (non destructive))");
@@ -409,15 +483,26 @@ void WM_OT_collada_export(wmOperatorType *ot)
RNA_def_boolean(func, "deform_bones_only", false, "Deform Bones only",
"Only export deforming bones with armatures");
+
+
RNA_def_boolean(func, "include_animations", true,
"Include Animations", "Export Animations if available.\nExporting Animations will enforce the decomposition of node transforms\ninto <translation> <rotation> and <scale> components");
- RNA_def_boolean(func, "sample_animations", 0,
- "Sample Animations", "Auto-generate keyframes with a frame distance set by 'Sampling Rate'.\nWhen disabled, export only the keyframes defined in the animation f-curves (may be less accurate)");
+ RNA_def_boolean(func, "include_all_actions", true,
+ "Include all Actions", "Export also unassigned actions.\nThis allows you to export entire animation libraries for your charater(s)");
+
+ RNA_def_enum(func, "export_animation_type_selection", prop_bc_export_animation_type, 0,
+ "Key Type", "Type for exported animations (use sample keys or Curve keys)");
RNA_def_int(func, "sampling_rate", 1, 1, INT_MAX,
"Sampling Rate", "The distance between 2 keyframes. 1 means: Every frame is keyed", 1, INT_MAX);
+ RNA_def_boolean(func, "keep_smooth_curves", 0,
+ "Keep Smooth curves", "Export also the curve handles (if available).\nThis does only work when the inverse parent matrix is the Unity matrix\nOtherwise you may end up with odd results\n");
+
+ RNA_def_boolean(func, "keep_keyframes", 0,
+ "Keep Keyframes", "Use existing keyframes as additional sample points.\nThis helps when you want to keep manual tweeks");
+
RNA_def_boolean(func, "active_uv_only", 0, "Only Selected UV Map",
"Export only the selected UV Map");
@@ -437,20 +522,11 @@ void WM_OT_collada_export(wmOperatorType *ot)
RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name",
"Sort exported data by Object name");
-
RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX,
- "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
+ "Transform", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX);
RNA_def_enum(func, "export_transformation_type_selection", prop_bc_export_transformation_type, 0,
- "Transform", "Transformation type for translation, scale and rotation");
-
-
- RNA_def_int(func, "export_texture_type", 0, INT_MIN, INT_MAX,
- "Texture Type", "Type for exported Textures (UV or MAT)", INT_MIN, INT_MAX);
-
- RNA_def_enum(func, "export_texture_type_selection", prop_bc_export_texture_type, 0,
- "Texture Type", "Type for exported Textures (UV or MAT)");
-
+ "Transform", "Transformation type for translation, scale and rotation");
RNA_def_boolean(func, "open_sim", 0, "Export to SL/OpenSim",
"Compatibility mode for SL, OpenSim and other compatible online worlds");
@@ -503,10 +579,11 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
import_settings.keep_bind_info = keep_bind_info != 0;
if (collada_import(C, &import_settings)) {
+ DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_BASE_FLAGS_UPDATE);
return OPERATOR_FINISHED;
}
else {
- BKE_report(op->reports, RPT_ERROR, "Errors found during parsing COLLADA document (see console for details)");
+ BKE_report(op->reports, RPT_ERROR, "Parsing errors in Document (see Blender Console)");
return OPERATOR_CANCELLED;
}
}
diff --git a/source/blender/editors/lattice/CMakeLists.txt b/source/blender/editors/lattice/CMakeLists.txt
index 3bb954ddf46..2207e0fa736 100644
--- a/source/blender/editors/lattice/CMakeLists.txt
+++ b/source/blender/editors/lattice/CMakeLists.txt
@@ -22,10 +22,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../depsgraph
../../makesdna
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index d0d64b85195..bf5844cdafb 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -50,14 +50,19 @@
#include "BKE_context.h"
#include "BKE_lattice.h"
#include "BKE_report.h"
+#include "BKE_layer.h"
+#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_lattice.h"
#include "ED_view3d.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph.h"
+
#include "lattice_intern.h"
/* -------------------------------------------------------------------- */
@@ -84,36 +89,44 @@ static void bpoint_select_set(BPoint *bp, bool select)
static int lattice_select_random_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
-
const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
- RNG *rng = BLI_rng_new_srandom(seed);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
- int tot;
- BPoint *bp;
+ RNG *rng = BLI_rng_new_srandom(seed);
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- bp = lt->def;
- while (tot--) {
- if (!bp->hide) {
- if (BLI_rng_get_float(rng) < randfac) {
- bpoint_select_set(bp, select);
+ int tot;
+ BPoint *bp;
+
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ bp = lt->def;
+ while (tot--) {
+ if (!bp->hide) {
+ if (BLI_rng_get_float(rng) < randfac) {
+ bpoint_select_set(bp, select);
+ }
}
+ bp++;
}
- bp++;
- }
- if (select == false) {
- lt->actbp = LT_ACTBP_NONE;
- }
+ if (select == false) {
+ lt->actbp = LT_ACTBP_NONE;
+ }
- BLI_rng_free(rng);
+ BLI_rng_free(rng);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -183,18 +196,28 @@ static void ed_lattice_select_mirrored(Lattice *lt, const int axis, const bool e
static int lattice_select_mirror_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
const int axis_flag = RNA_enum_get(op->ptr, "axis");
const bool extend = RNA_boolean_get(op->ptr, "extend");
- for (int axis = 0; axis < 3; axis++) {
- if ((1 << axis) & axis_flag) {
- ed_lattice_select_mirrored(lt, axis, extend);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
+
+ for (int axis = 0; axis < 3; axis++) {
+ if ((1 << axis) & axis_flag) {
+ ed_lattice_select_mirrored(lt, axis, extend);
+ }
}
- }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ /* TODO, only notify changes */
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -244,42 +267,53 @@ static bool lattice_test_bitmap_uvw(Lattice *lt, BLI_bitmap *selpoints, int u, i
static int lattice_select_more_less(bContext *C, const bool select)
{
- Object *obedit = CTX_data_edit_object(C);
- Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
- BPoint *bp;
- const int tot = lt->pntsu * lt->pntsv * lt->pntsw;
- int u, v, w;
- BLI_bitmap *selpoints;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len;
+ bool changed = false;
+
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
+ BPoint *bp;
+ const int tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ int u, v, w;
+ BLI_bitmap *selpoints;
- lt->actbp = LT_ACTBP_NONE;
-
- selpoints = BLI_BITMAP_NEW(tot, __func__);
- BKE_lattice_bitmap_from_flag(lt, selpoints, SELECT, false, false);
+ lt->actbp = LT_ACTBP_NONE;
- bp = lt->def;
- for (w = 0; w < lt->pntsw; w++) {
- for (v = 0; v < lt->pntsv; v++) {
- for (u = 0; u < lt->pntsu; u++) {
- if ((bp->hide == 0) && (((bp->f1 & SELECT) == 0) == select)) {
- if (lattice_test_bitmap_uvw(lt, selpoints, u + 1, v, w, select) ||
- lattice_test_bitmap_uvw(lt, selpoints, u - 1, v, w, select) ||
- lattice_test_bitmap_uvw(lt, selpoints, u, v + 1, w, select) ||
- lattice_test_bitmap_uvw(lt, selpoints, u, v - 1, w, select) ||
- lattice_test_bitmap_uvw(lt, selpoints, u, v, w + 1, select) ||
- lattice_test_bitmap_uvw(lt, selpoints, u, v, w - 1, select))
- {
- SET_FLAG_FROM_TEST(bp->f1, select, SELECT);
+ selpoints = BLI_BITMAP_NEW(tot, __func__);
+ BKE_lattice_bitmap_from_flag(lt, selpoints, SELECT, false, false);
+
+ bp = lt->def;
+ for (w = 0; w < lt->pntsw; w++) {
+ for (v = 0; v < lt->pntsv; v++) {
+ for (u = 0; u < lt->pntsu; u++) {
+ if ((bp->hide == 0) && (((bp->f1 & SELECT) == 0) == select)) {
+ if (lattice_test_bitmap_uvw(lt, selpoints, u + 1, v, w, select) ||
+ lattice_test_bitmap_uvw(lt, selpoints, u - 1, v, w, select) ||
+ lattice_test_bitmap_uvw(lt, selpoints, u, v + 1, w, select) ||
+ lattice_test_bitmap_uvw(lt, selpoints, u, v - 1, w, select) ||
+ lattice_test_bitmap_uvw(lt, selpoints, u, v, w + 1, select) ||
+ lattice_test_bitmap_uvw(lt, selpoints, u, v, w - 1, select))
+ {
+ SET_FLAG_FROM_TEST(bp->f1, select, SELECT);
+ }
}
+ bp++;
}
- bp++;
}
}
- }
- MEM_freeN(selpoints);
+ MEM_freeN(selpoints);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- return OPERATOR_FINISHED;
+ changed = true;
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
+
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static int lattice_select_more_exec(bContext *C, wmOperator *UNUSED(op))
@@ -349,51 +383,56 @@ void ED_lattice_flags_set(Object *obedit, int flag)
static int lattice_select_all_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Lattice *lt = obedit->data;
- BPoint *bp;
- int a;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
int action = RNA_enum_get(op->ptr, "action");
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
-
- bp = lt->editlatt->latt->def;
- a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
-
- while (a--) {
- if (bp->hide == 0) {
- if (bp->f1 & SELECT) {
- action = SEL_DESELECT;
- break;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Lattice *lt = obedit->data;
+ if (BKE_lattice_is_any_selected(lt->editlatt->latt)) {
+ action = SEL_DESELECT;
+ break;
}
- bp++;
}
}
- switch (action) {
- case SEL_SELECT:
- ED_lattice_flags_set(obedit, 1);
- break;
- case SEL_DESELECT:
- ED_lattice_flags_set(obedit, 0);
- break;
- case SEL_INVERT:
- bp = lt->editlatt->latt->def;
- a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
- lt->editlatt->latt->actbp = LT_ACTBP_NONE;
-
- while (a--) {
- if (bp->hide == 0) {
- bp->f1 ^= SELECT;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Lattice *lt;
+ BPoint *bp;
+ int a;
+
+ switch (action) {
+ case SEL_SELECT:
+ ED_lattice_flags_set(obedit, 1);
+ break;
+ case SEL_DESELECT:
+ ED_lattice_flags_set(obedit, 0);
+ break;
+ case SEL_INVERT:
+ lt = obedit->data;
+ bp = lt->editlatt->latt->def;
+ a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
+ lt->editlatt->latt->actbp = LT_ACTBP_NONE;
+
+ while (a--) {
+ if (bp->hide == 0) {
+ bp->f1 ^= SELECT;
+ }
+ bp++;
}
- bp++;
- }
- break;
+ break;
+ }
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
+ MEM_freeN(objects);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -423,34 +462,51 @@ void LATTICE_OT_select_all(wmOperatorType *ot)
static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
- MDeformVert *dv;
- BPoint *bp;
- int a, tot;
-
- if (BLI_listbase_is_empty(&obedit->defbase) || lt->dvert == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object");
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len;
+ const bool is_extend = RNA_boolean_get(op->ptr, "extend");
+ bool changed = false;
+
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
+ MDeformVert *dv;
+ BPoint *bp;
+ int a, tot;
+
+ if (BLI_listbase_is_empty(&obedit->defbase) || lt->dvert == NULL) {
+ continue;
+ }
- if (!RNA_boolean_get(op->ptr, "extend")) {
- ED_lattice_flags_set(obedit, 0);
- }
+ if (!is_extend) {
+ ED_lattice_flags_set(obedit, 0);
+ }
- dv = lt->dvert;
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ dv = lt->dvert;
+ tot = lt->pntsu * lt->pntsv * lt->pntsw;
- for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
- if (bp->hide == 0) {
- if (dv->dw == NULL) {
- bp->f1 |= SELECT;
+ for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
+ if (bp->hide == 0) {
+ if (dv->dw == NULL) {
+ bp->f1 |= SELECT;
+ }
}
}
- }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ changed = true;
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
+ if (!changed) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ objects_len > 1 ? "No weights/vertex groups on objects" :
+ "No weights/vertex groups on object");
+ return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
@@ -484,7 +540,7 @@ void LATTICE_OT_select_ungrouped(wmOperatorType *ot)
static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const float screen_co[2])
{
- struct { BPoint *bp; float dist; int select; float mval_fl[2]; } *data = userData;
+ struct { BPoint *bp; float dist; int select; float mval_fl[2]; bool is_changed; } *data = userData;
float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
if ((bp->f1 & SELECT) && data->select)
@@ -492,26 +548,38 @@ static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const flo
if (dist_test < data->dist) {
data->dist = dist_test;
-
data->bp = bp;
+ data->is_changed = true;
}
}
-static BPoint *findnearestLattvert(ViewContext *vc, const int mval[2], int sel)
+static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base)
{
/* (sel == 1): selected gets a disadvantage */
/* in nurb and bezt or bp the nearest is written */
/* return 0 1 2: handlepunt */
- struct { BPoint *bp; float dist; int select; float mval_fl[2]; } data = {NULL};
+ struct { BPoint *bp; float dist; int select; float mval_fl[2]; bool is_changed; } data = {NULL};
data.dist = ED_view3d_select_dist_px();
data.select = sel;
- data.mval_fl[0] = mval[0];
- data.mval_fl[1] = mval[1];
+ data.mval_fl[0] = vc->mval[0];
+ data.mval_fl[1] = vc->mval[1];
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- lattice_foreachScreenVert(vc, findnearestLattvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(vc->view_layer, vc->v3d, &bases_len);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base = bases[base_index];
+ data.is_changed = false;
+ ED_view3d_viewcontext_init_object(vc, base->object);
+ ED_view3d_init_mats_rv3d(base->object, vc->rv3d);
+ lattice_foreachScreenVert(vc, findnearestLattvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ if (data.is_changed) {
+ *r_base = base;
+ }
+ }
+ MEM_freeN(bases);
return data.bp;
}
@@ -519,13 +587,30 @@ bool ED_lattice_select_pick(bContext *C, const int mval[2], bool extend, bool de
{
ViewContext vc;
BPoint *bp = NULL;
- Lattice *lt;
+ Base *basact = NULL;
ED_view3d_viewcontext_init(C, &vc);
- lt = ((Lattice *)vc.obedit->data)->editlatt->latt;
- bp = findnearestLattvert(&vc, mval, true);
+ vc.mval[0] = mval[0];
+ vc.mval[1] = mval[1];
+ bp = findnearestLattvert(&vc, true, &basact);
if (bp) {
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ Lattice *lt = ((Lattice *)vc.obedit->data)->editlatt->latt;
+
+ if (!extend && !deselect && !toggle) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ ED_lattice_flags_set(ob, 0);
+
+ DEG_id_tag_update(ob->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
+ MEM_freeN(objects);
+ }
+
if (extend) {
bp->f1 |= SELECT;
}
@@ -547,6 +632,11 @@ bool ED_lattice_select_pick(bContext *C, const int mval[2], bool extend, bool de
lt->actbp = LT_ACTBP_NONE;
}
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
+ DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
return true;
diff --git a/source/blender/editors/lattice/editlattice_tools.c b/source/blender/editors/lattice/editlattice_tools.c
index 8ecb182528a..8cb3666c2af 100644
--- a/source/blender/editors/lattice/editlattice_tools.c
+++ b/source/blender/editors/lattice/editlattice_tools.c
@@ -27,6 +27,9 @@
* \ingroup edlattice
*/
+
+#include "MEM_guardedalloc.h"
+
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -39,8 +42,10 @@
#include "RNA_define.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
#include "ED_screen.h"
@@ -67,22 +72,41 @@ static bool make_regular_poll(bContext *C)
static int make_regular_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_edit_object(C);
- Lattice *lt;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ const bool is_editmode = CTX_data_edit_object(C) != NULL;
+
+ if (is_editmode) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ Lattice *lt = ob->data;
+
+ if (lt->editlatt->latt == NULL) {
+ continue;
+ }
+
+ BKE_lattice_resize(lt->editlatt->latt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
- if (ob) {
- lt = ob->data;
- BKE_lattice_resize(lt->editlatt->latt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ }
+ MEM_freeN(objects);
}
else {
- ob = CTX_data_active_object(C);
- lt = ob->data;
- BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
- }
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, v3d, ob) {
+ if (ob->type != OB_LATTICE) {
+ continue;
+ }
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ Lattice *lt = ob->data;
+ BKE_lattice_resize(lt, lt->pntsu, lt->pntsv, lt->pntsw, NULL);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ } FOREACH_SELECTED_OBJECT_END;
+ }
return OPERATOR_FINISHED;
}
@@ -190,126 +214,135 @@ static void lattice_swap_point_pairs(Lattice *lt, int u, int v, int w, float mid
static int lattice_flip_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Lattice *lt;
-
- eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis");
- int numU, numV, numW;
- int totP;
-
- float mid = 0.0f;
- short isOdd = 0;
-
- /* get lattice - we need the "edit lattice" from the lattice... confusing... */
- lt = (Lattice *)obedit->data;
- lt = lt->editlatt->latt;
-
- numU = lt->pntsu;
- numV = lt->pntsv;
- numW = lt->pntsw;
- totP = numU * numV * numW;
-
- /* First Pass: determine midpoint - used for flipping center verts if there are odd number of points on axis */
- switch (axis) {
- case LATTICE_FLIP_U:
- isOdd = numU & 1;
- break;
- case LATTICE_FLIP_V:
- isOdd = numV & 1;
- break;
- case LATTICE_FLIP_W:
- isOdd = numW & 1;
- break;
-
- default:
- printf("lattice_flip(): Unknown flipping axis (%u)\n", axis);
- return OPERATOR_CANCELLED;
- }
-
- if (isOdd) {
- BPoint *bp;
- float avgInv = 1.0f / (float)totP;
- int i;
-
- /* midpoint calculation - assuming that u/v/w are axis-aligned */
- for (i = 0, bp = lt->def; i < totP; i++, bp++) {
- mid += bp->vec[axis] * avgInv;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len;
+ bool changed = false;
+ const eLattice_FlipAxes axis = RNA_enum_get(op->ptr, "axis");
+
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Lattice *lt;
+
+ int numU, numV, numW;
+ int totP;
+
+ float mid = 0.0f;
+ short isOdd = 0;
+
+ /* get lattice - we need the "edit lattice" from the lattice... confusing... */
+ lt = (Lattice *)obedit->data;
+ lt = lt->editlatt->latt;
+
+ numU = lt->pntsu;
+ numV = lt->pntsv;
+ numW = lt->pntsw;
+ totP = numU * numV * numW;
+
+ /* First Pass: determine midpoint - used for flipping center verts if there are odd number of points on axis */
+ switch (axis) {
+ case LATTICE_FLIP_U:
+ isOdd = numU & 1;
+ break;
+ case LATTICE_FLIP_V:
+ isOdd = numV & 1;
+ break;
+ case LATTICE_FLIP_W:
+ isOdd = numW & 1;
+ break;
+
+ default:
+ printf("lattice_flip(): Unknown flipping axis (%u)\n", axis);
+ return OPERATOR_CANCELLED;
}
- }
-
- /* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */
- switch (axis) {
- case LATTICE_FLIP_U:
- {
- int u, v, w;
- /* v/w strips - front to back, top to bottom */
- for (w = 0; w < numW; w++) {
- for (v = 0; v < numV; v++) {
- /* swap coordinates of pairs of vertices on u */
- for (u = 0; u < (numU / 2); u++) {
- lattice_swap_point_pairs(lt, u, v, w, mid, axis);
- }
+ if (isOdd) {
+ BPoint *bp;
+ float avgInv = 1.0f / (float)totP;
+ int i;
- /* flip u-coordinate of midpoint (i.e. unpaired point on u) */
- if (isOdd) {
- u = (numU / 2);
- lattice_flip_point_value(lt, u, v, w, mid, axis);
- }
- }
+ /* midpoint calculation - assuming that u/v/w are axis-aligned */
+ for (i = 0, bp = lt->def; i < totP; i++, bp++) {
+ mid += bp->vec[axis] * avgInv;
}
- break;
}
- case LATTICE_FLIP_V:
- {
- int u, v, w;
-
- /* u/w strips - front to back, left to right */
- for (w = 0; w < numW; w++) {
- for (u = 0; u < numU; u++) {
- /* swap coordinates of pairs of vertices on v */
- for (v = 0; v < (numV / 2); v++) {
- lattice_swap_point_pairs(lt, u, v, w, mid, axis);
- }
- /* flip v-coordinate of midpoint (i.e. unpaired point on v) */
- if (isOdd) {
- v = (numV / 2);
- lattice_flip_point_value(lt, u, v, w, mid, axis);
+ /* Second Pass: swap pairs of vertices per axis, assuming they are all sorted */
+ switch (axis) {
+ case LATTICE_FLIP_U:
+ {
+ int u, v, w;
+
+ /* v/w strips - front to back, top to bottom */
+ for (w = 0; w < numW; w++) {
+ for (v = 0; v < numV; v++) {
+ /* swap coordinates of pairs of vertices on u */
+ for (u = 0; u < (numU / 2); u++) {
+ lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+ }
+
+ /* flip u-coordinate of midpoint (i.e. unpaired point on u) */
+ if (isOdd) {
+ u = (numU / 2);
+ lattice_flip_point_value(lt, u, v, w, mid, axis);
+ }
}
}
+ break;
}
- break;
- }
- case LATTICE_FLIP_W:
- {
- int u, v, w;
-
- for (v = 0; v < numV; v++) {
- for (u = 0; u < numU; u++) {
- /* swap coordinates of pairs of vertices on w */
- for (w = 0; w < (numW / 2); w++) {
- lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+ case LATTICE_FLIP_V:
+ {
+ int u, v, w;
+
+ /* u/w strips - front to back, left to right */
+ for (w = 0; w < numW; w++) {
+ for (u = 0; u < numU; u++) {
+ /* swap coordinates of pairs of vertices on v */
+ for (v = 0; v < (numV / 2); v++) {
+ lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+ }
+
+ /* flip v-coordinate of midpoint (i.e. unpaired point on v) */
+ if (isOdd) {
+ v = (numV / 2);
+ lattice_flip_point_value(lt, u, v, w, mid, axis);
+ }
}
+ }
+ break;
+ }
+ case LATTICE_FLIP_W:
+ {
+ int u, v, w;
- /* flip w-coordinate of midpoint (i.e. unpaired point on w) */
- if (isOdd) {
- w = (numW / 2);
- lattice_flip_point_value(lt, u, v, w, mid, axis);
+ for (v = 0; v < numV; v++) {
+ for (u = 0; u < numU; u++) {
+ /* swap coordinates of pairs of vertices on w */
+ for (w = 0; w < (numW / 2); w++) {
+ lattice_swap_point_pairs(lt, u, v, w, mid, axis);
+ }
+
+ /* flip w-coordinate of midpoint (i.e. unpaired point on w) */
+ if (isOdd) {
+ w = (numW / 2);
+ lattice_flip_point_value(lt, u, v, w, mid, axis);
+ }
}
}
+ break;
}
- break;
+ default: /* shouldn't happen, but just in case */
+ break;
}
- default: /* shouldn't happen, but just in case */
- break;
- }
- /* updates */
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ /* updates */
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ changed = true;
+ }
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void LATTICE_OT_flip(wmOperatorType *ot)
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index 7a7372f5a6a..c1a10843460 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -33,6 +33,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "BLI_utildefines.h"
#include "BLI_array_utils.h"
@@ -42,11 +44,14 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "ED_object.h"
#include "ED_lattice.h"
+#include "ED_undo.h"
#include "ED_util.h"
#include "WM_types.h"
@@ -54,6 +59,9 @@
#include "lattice_intern.h"
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.lattice"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -123,13 +131,19 @@ static Object *editlatt_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
-typedef struct LatticeUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-editmode. */
+typedef struct LatticeUndoStep_Elem {
UndoRefID_Object obedit_ref;
UndoLattice data;
+} LatticeUndoStep_Elem;
+
+typedef struct LatticeUndoStep {
+ UndoStep step;
+ LatticeUndoStep_Elem *elems;
+ uint elems_len;
} LatticeUndoStep;
static bool lattice_undosys_poll(bContext *C)
@@ -140,10 +154,24 @@ static bool lattice_undosys_poll(bContext *C)
static bool lattice_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- us->obedit_ref.ptr = editlatt_object_from_context(C);
- Lattice *lt = us->obedit_ref.ptr->data;
- undolatt_from_editlatt(&us->data, lt->editlatt);
- us->step.data_size = us->data.undo_size;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
+ us->elems_len = objects_len;
+
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ LatticeUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ Lattice *lt = ob->data;
+ undolatt_from_editlatt(&elem->data, lt->editlatt);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
@@ -154,25 +182,47 @@ static void lattice_undosys_step_decode(struct bContext *C, UndoStep *us_p, int
BLI_assert(lattice_undosys_poll(C));
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- Lattice *lt = obedit->data;
- EditLatt *editlatt = lt->editlatt;
- undolatt_to_editlatt(&us->data, editlatt);
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ LatticeUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ Lattice *lt = obedit->data;
+ if (lt->editlatt == NULL) {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
+ us_p->name, obedit->id.name);
+ continue;
+ }
+ undolatt_to_editlatt(&elem->data, lt->editlatt);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
+
+ /* The first element is always active */
+ ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
+
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
static void lattice_undosys_step_free(UndoStep *us_p)
{
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- undolatt_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ LatticeUndoStep_Elem *elem = &us->elems[i];
+ undolatt_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
static void lattice_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ LatticeUndoStep_Elem *elem = &us->elems[i];
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
+ }
}
/* Export for ED_undo_sys. */
diff --git a/source/blender/editors/lattice/lattice_ops.c b/source/blender/editors/lattice/lattice_ops.c
index 561397d71ff..76ccc2250ee 100644
--- a/source/blender/editors/lattice/lattice_ops.c
+++ b/source/blender/editors/lattice/lattice_ops.c
@@ -36,6 +36,7 @@
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_object.h"
#include "ED_lattice.h"
@@ -55,26 +56,6 @@ void ED_operatortypes_lattice(void)
void ED_keymap_lattice(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
- keymap = WM_keymap_ensure(keyconf, "Lattice", 0, 0);
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Lattice", 0, 0);
keymap->poll = ED_operator_editlattice;
-
- kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "LATTICE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
- WM_keymap_add_item(keymap, "LATTICE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "LATTICE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "LATTICE_OT_flip", FKEY, KM_PRESS, KM_CTRL, 0);
-
- /* menus */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_hook", HKEY, KM_PRESS, KM_CTRL, 0);
-
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_editmode(keyconf, keymap, false);
}
diff --git a/source/blender/editors/mask/CMakeLists.txt b/source/blender/editors/mask/CMakeLists.txt
index 033d034cf4e..d17df344dc9 100644
--- a/source/blender/editors/mask/CMakeLists.txt
+++ b/source/blender/editors/mask/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 69335195b96..df07326c590 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -34,9 +34,10 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_mask.h"
+#include "DEG_depsgraph.h"
+
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_mask_types.h"
@@ -44,6 +45,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_select_utils.h"
#include "ED_mask.h" /* own include */
#include "ED_screen.h"
@@ -692,7 +694,7 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 407c19a3860..fc9cfc85bc5 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -36,6 +36,7 @@
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_task.h"
+#include "BLI_listbase.h"
#include "BKE_context.h"
#include "BKE_mask.h"
@@ -48,11 +49,16 @@
#include "ED_clip.h"
#include "ED_mask.h" /* own include */
#include "ED_space_api.h"
-#include "BIF_gl.h"
+
#include "BIF_glutil.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
+#include "GPU_shader.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -93,40 +99,6 @@ static void mask_spline_feather_color_get(MaskLayer *UNUSED(masklay), MaskSpline
r_rgb[3] = 255;
}
-#if 0
-static void draw_spline_parents(MaskLayer *UNUSED(masklay), MaskSpline *spline)
-{
- int i;
- MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
-
- if (!spline->tot_point)
- return;
-
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(1, 0xAAAA);
-
- glColor3ub(0, 0, 0);
- glBegin(GL_LINES);
-
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point = &points_array[i];
- BezTriple *bezt = &point->bezt;
-
- if (point->parent.id) {
- glVertex2f(bezt->vec[1][0],
- bezt->vec[1][1]);
-
- glVertex2f(bezt->vec[1][0] - point->parent.offset[0],
- bezt->vec[1][1] - point->parent.offset[1]);
- }
- }
-
- glEnd();
-
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
-}
-#endif
-
static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
{
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
@@ -134,46 +106,9 @@ static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float c
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
}
-static void draw_circle(const float x, const float y,
- const float size, const bool fill,
- const float xscale, const float yscale)
-{
- static GLuint wire_displist = 0;
- static GLuint fill_displist = 0;
- GLuint displist = fill ? fill_displist : wire_displist;
-
- /* Initialize round circle shape. */
- if (displist == 0) {
- GLUquadricObj *qobj;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, fill ? GLU_FILL : GLU_SILHOUETTE);
- gluDisk(qobj, 0, 0.7, 8, 1);
- gluDeleteQuadric(qobj);
-
- glEndList();
-
- if (fill) {
- fill_displist = displist;
- }
- else {
- wire_displist = displist;
- }
- }
-
- glPushMatrix();
- glTranslatef(x, y, 0.0f);
- glScalef(1.0f / xscale * size, 1.0f / yscale * size, 1.0f);
- glCallList(displist);
- glPopMatrix();
-}
-
static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoint *point,
const eMaskWhichHandle which_handle, const int draw_type,
- const float handle_size, const float xscale, const float yscale,
+ const float handle_size,
const float point_pos[2], const float handle_pos[2])
{
const BezTriple *bezt = &point->bezt;
@@ -190,54 +125,70 @@ static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoin
return;
}
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ubv(rgb_gray);
+
/* this could be split into its own loop */
if (draw_type == MASK_DT_OUTLINE) {
- const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
- glLineWidth(3);
- glColor4ubv(rgb_gray);
- glBegin(GL_LINES);
- glVertex2fv(point_pos);
- glVertex2fv(handle_pos);
- glEnd();
+ GPU_line_width(3.0f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(pos, point_pos);
+ immVertex2fv(pos, handle_pos);
+ immEnd();
}
switch (handle_type) {
case HD_FREE:
- UI_ThemeColor(TH_HANDLE_FREE);
+ immUniformThemeColor(TH_HANDLE_FREE);
break;
case HD_AUTO:
- UI_ThemeColor(TH_HANDLE_AUTO);
+ immUniformThemeColor(TH_HANDLE_AUTO);
break;
case HD_ALIGN:
case HD_ALIGN_DOUBLESIDE:
- UI_ThemeColor(TH_HANDLE_ALIGN);
+ immUniformThemeColor(TH_HANDLE_ALIGN);
break;
}
- glLineWidth(1);
- glBegin(GL_LINES);
- glVertex2fv(point_pos);
- glVertex2fv(handle_pos);
- glEnd();
+ GPU_line_width(1.0f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(pos, point_pos);
+ immVertex2fv(pos, handle_pos);
+ immEnd();
+ immUnbindProgram();
/* draw handle points */
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+ immUniform1f("size", handle_size);
+ immUniform1f("outlineWidth", 1.5f);
+
+ float point_color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; /* active color by default */
if (MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
- if (point == mask_layer->act_point)
- glColor3f(1.0f, 1.0f, 1.0f);
- else
- UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
+ if (point != mask_layer->act_point) {
+ UI_GetThemeColor3fv(TH_HANDLE_VERTEX_SELECT, point_color);
+ }
}
else {
- UI_ThemeColor(TH_HANDLE_VERTEX);
+ UI_GetThemeColor3fv(TH_HANDLE_VERTEX, point_color);
}
- draw_circle(handle_pos[0], handle_pos[1], handle_size, false, xscale, yscale);
+ immUniform4fv("outlineColor", point_color);
+ immUniformColor3fvAlpha(point_color, 0.25f);
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2fv(pos, handle_pos);
+ immEnd();
+
+ immUnbindProgram();
}
/* return non-zero if spline is selected */
static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline *spline,
- const char draw_flag, const char draw_type,
- const float xscale, const float yscale)
+ const char draw_flag, const char draw_type)
{
const bool is_spline_sel = (spline->flag & SELECT) && (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
@@ -247,7 +198,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
SpaceClip *sc = CTX_wm_space_clip(C);
bool undistort = false;
- int i, handle_size, tot_feather_point;
+ int tot_feather_point;
float (*feather_points)[2], (*fp)[2];
float min[2], max[2];
@@ -258,22 +209,24 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
/* TODO, add this to sequence editor */
- handle_size = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
-
- glPointSize(handle_size);
+ float handle_size = 2.0f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ immUniform1f("size", 0.7f * handle_size);
+
/* feather points */
feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
- for (i = 0; i < spline->tot_point; i++) {
+ for (int i = 0; i < spline->tot_point; i++) {
/* watch it! this is intentionally not the deform array, only check for sel */
MaskSplinePoint *point = &spline->points[i];
- int j;
-
- for (j = 0; j <= point->tot_uw; j++) {
+ for (int j = 0; j <= point->tot_uw; j++) {
float feather_point[2];
bool sel = false;
@@ -291,32 +244,32 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
if (sel) {
if (point == masklay->act_point)
- glColor3f(1.0f, 1.0f, 1.0f);
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
else
- UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
+ immUniformThemeColor(TH_HANDLE_VERTEX_SELECT);
}
else {
- UI_ThemeColor(TH_HANDLE_VERTEX);
+ immUniformThemeColor(TH_HANDLE_VERTEX);
}
- glBegin(GL_POINTS);
- glVertex2fv(feather_point);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2fv(pos, feather_point);
+ immEnd();
fp++;
}
}
MEM_freeN(feather_points);
+ immUnbindProgram();
+
if (is_smooth) {
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_line_smooth(true);
}
/* control points */
INIT_MINMAX2(min, max);
- for (i = 0; i < spline->tot_point; i++) {
+ for (int i = 0; i < spline->tot_point; i++) {
/* watch it! this is intentionally not the deform array, only check for sel */
MaskSplinePoint *point = &spline->points[i];
@@ -339,7 +292,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
mask_point_undistort_pos(sc, handle, handle);
}
draw_single_handle(masklay, point, MASK_WHICH_HANDLE_STICK,
- draw_type, handle_size, xscale, yscale, vert, handle);
+ draw_type, handle_size, vert, handle);
}
else {
float handle_left[2], handle_right[2];
@@ -350,53 +303,62 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
mask_point_undistort_pos(sc, handle_left, handle_left);
}
draw_single_handle(masklay, point, MASK_WHICH_HANDLE_LEFT,
- draw_type, handle_size, xscale, yscale, vert, handle_left);
+ draw_type, handle_size, vert, handle_left);
draw_single_handle(masklay, point, MASK_WHICH_HANDLE_RIGHT,
- draw_type, handle_size, xscale, yscale, vert, handle_right);
+ draw_type, handle_size, vert, handle_right);
}
+ /* bind program in loop so it does not interfere with draw_single_handle */
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+
/* draw CV point */
if (MASKPOINT_ISSEL_KNOT(point)) {
if (point == masklay->act_point)
- glColor3f(1.0f, 1.0f, 1.0f);
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
else
- UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
+ immUniformThemeColor(TH_HANDLE_VERTEX_SELECT);
}
else
- UI_ThemeColor(TH_HANDLE_VERTEX);
+ immUniformThemeColor(TH_HANDLE_VERTEX);
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2fv(pos, vert);
+ immEnd();
- glBegin(GL_POINTS);
- glVertex2fv(vert);
- glEnd();
+ immUnbindProgram();
minmax_v2v2_v2(min, max, vert);
}
+ if (is_smooth) {
+ GPU_line_smooth(false);
+ }
+
if (is_spline_sel) {
- float x = (min[0] + max[0]) / 2.0f;
- float y = (min[1] + max[1]) / 2.0f;
- /* TODO(sergey): Remove hardcoded colors. */
+ float x = (min[0] + max[0]) * 0.5f;
+ float y = (min[1] + max[1]) * 0.5f;
+
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+ immUniform1f("outlineWidth", 1.5f);
+
if (masklay->act_spline == spline) {
- glColor3ub(255, 255, 255);
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
}
else {
- glColor3ub(255, 255, 0);
+ immUniformColor3f(1.0f, 1.0f, 0.0f);
}
- draw_circle(x, y, 6.0f, true, xscale, yscale);
+ immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ immUniform1f("size", 12.0f);
- glColor3ub(0, 0, 0);
- draw_circle(x, y, 6.0f, false, xscale, yscale);
- }
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2f(pos, x, y);
+ immEnd();
- if (is_smooth) {
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ immUnbindProgram();
}
}
-/* #define USE_XOR */
-
static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char rgb[4], const bool is_active)
{
if (!is_active) {
@@ -410,13 +372,21 @@ static void mask_color_active_tint(unsigned char r_rgb[4], const unsigned char r
}
}
+static void mask_draw_array(unsigned int pos, GPUPrimType prim_type, const float (*points)[2], unsigned int vertex_len)
+{
+ immBegin(prim_type, vertex_len);
+ for (unsigned int i = 0; i < vertex_len; ++i) {
+ immVertex2fv(pos, points[i]);
+ }
+ immEnd();
+}
+
static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*orig_points)[2], int tot_point,
- const bool is_feather, const bool is_smooth, const bool is_active,
+ const bool is_feather, const bool is_active,
const unsigned char rgb_spline[4], const char draw_type)
{
- const int draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GL_LINE_LOOP : GL_LINE_STRIP;
+ const GPUPrimType draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GPU_PRIM_LINE_LOOP : GPU_PRIM_LINE_STRIP;
const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
-// const unsigned char rgb_white[4] = {0xff, 0xff, 0xff, 0xff};
unsigned char rgb_tmp[4];
SpaceClip *sc = CTX_wm_space_clip(C);
float (*points)[2] = orig_points;
@@ -425,65 +395,45 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
const bool undistort = sc->clip && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT);
if (undistort) {
- int i;
-
points = MEM_callocN(2 * tot_point * sizeof(float), "undistorthed mask curve");
- for (i = 0; i < tot_point; i++) {
+ for (int i = 0; i < tot_point; i++) {
mask_point_undistort_pos(sc, points[i], orig_points[i]);
}
}
}
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, points);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
switch (draw_type) {
case MASK_DT_OUTLINE:
- glLineWidth(3);
+ /* TODO(merwin): use fancy line shader here
+ * probably better with geometry shader (after core profile switch)
+ */
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- mask_color_active_tint(rgb_tmp, rgb_black, is_active);
- glColor4ubv(rgb_tmp);
+ GPU_line_width(3.0f);
- glDrawArrays(draw_method, 0, tot_point);
-
- glLineWidth(1);
- mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
- glColor4ubv(rgb_tmp);
- glDrawArrays(draw_method, 0, tot_point);
-
- break;
+ mask_color_active_tint(rgb_tmp, rgb_black, is_active);
+ immUniformColor4ubv(rgb_tmp);
+ mask_draw_array(pos, draw_method, points, tot_point);
- case MASK_DT_DASH:
- default:
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(3, 0xAAAA);
+ GPU_line_width(1.0f);
-#ifdef USE_XOR
- glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(GL_OR);
-#endif
mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
- glColor4ubv(rgb_tmp);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, points);
- glDrawArrays(draw_method, 0, tot_point);
-
-#ifdef USE_XOR
- glDisable(GL_COLOR_LOGIC_OP);
-#endif
- mask_color_active_tint(rgb_tmp, rgb_black, is_active);
- glColor4ubv(rgb_tmp);
- GPU_basic_shader_line_stipple(3, 0x5555);
- glDrawArrays(draw_method, 0, tot_point);
+ immUniformColor4ubv(rgb_tmp);
+ mask_draw_array(pos, draw_method, points, tot_point);
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ immUnbindProgram();
break;
-
case MASK_DT_BLACK:
case MASK_DT_WHITE:
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_line_width(1.0f);
+
if (draw_type == MASK_DT_BLACK) { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 0; }
else { rgb_tmp[0] = rgb_tmp[1] = rgb_tmp[2] = 255; }
/* alpha values seem too low but gl draws many points that compensate for it */
@@ -496,26 +446,42 @@ static void mask_draw_curve_type(const bContext *C, MaskSpline *spline, float (*
rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
}
- if (is_smooth == false && is_feather) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
-
mask_color_active_tint(rgb_tmp, rgb_tmp, is_active);
- glColor4ubv(rgb_tmp);
+ immUniformColor4ubv(rgb_tmp);
+ mask_draw_array(pos, draw_method, points, tot_point);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, points);
- glDrawArrays(draw_method, 0, tot_point);
+ immUnbindProgram();
+ break;
- if (is_smooth == false && is_feather) {
- glDisable(GL_BLEND);
- }
+ case MASK_DT_DASH:
+ {
+ float colors[8];
+
+ mask_color_active_tint(rgb_tmp, rgb_spline, is_active);
+ rgba_uchar_to_float(colors, rgb_tmp);
+ mask_color_active_tint(rgb_tmp, rgb_black, is_active);
+ rgba_uchar_to_float(colors + 4, rgb_tmp);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", colors, 2);
+ immUniform1f("dash_width", 4.0f);
+ GPU_line_width(1.0f);
+
+ mask_draw_array(pos, draw_method, points, tot_point);
+
+ immUnbindProgram();
break;
- }
+ }
- glDisableClientState(GL_VERTEX_ARRAY);
+ default:
+ BLI_assert(false);
+ }
if (points != orig_points)
MEM_freeN(points);
@@ -547,9 +513,7 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline
return;
if (is_smooth) {
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_line_smooth(true);
}
feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(spline, &tot_feather_point, resol, (is_fill != false));
@@ -557,26 +521,24 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline
/* draw feather */
mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
- true, is_smooth, is_active,
+ true, is_active,
rgb_tmp, draw_type);
if (!is_fill) {
-
const float *fp = &diff_points[0][0];
float *fp_feather = &feather_points[0][0];
- float tvec[2];
- int i;
BLI_assert(tot_diff_point == tot_feather_point);
- for (i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) {
+ for (int i = 0; i < tot_diff_point; i++, fp += 2, fp_feather += 2) {
+ float tvec[2];
sub_v2_v2v2(tvec, fp, fp_feather);
add_v2_v2v2(fp_feather, fp, tvec);
}
/* same as above */
mask_draw_curve_type(C, spline, feather_points, tot_feather_point,
- true, is_smooth, is_active,
+ true, is_active,
rgb_tmp, draw_type);
}
@@ -585,21 +547,22 @@ static void draw_spline_curve(const bContext *C, MaskLayer *masklay, MaskSpline
/* draw main curve */
mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
mask_draw_curve_type(C, spline, diff_points, tot_diff_point,
- false, is_smooth, is_active,
+ false, is_active,
rgb_tmp, draw_type);
MEM_freeN(diff_points);
- if (draw_flag & MASK_DRAWFLAG_SMOOTH) {
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ if (is_smooth) {
+ GPU_line_smooth(false);
}
-
- (void)draw_type;
}
static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, const char draw_type,
- const int width, const int height, const float xscale, const float yscale)
+ const int width, const int height)
{
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_enable_program_point_size();
+
MaskLayer *masklay;
int i;
@@ -616,11 +579,9 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c
/* draw curve itself first... */
draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
-// draw_spline_parents(masklay, spline);
-
if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
/* ...and then handles over the curve so they're nicely visible */
- draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale);
+ draw_spline_points(C, masklay, spline, draw_flag, draw_type);
}
/* show undeform for testing */
@@ -629,33 +590,29 @@ static void draw_masklays(const bContext *C, Mask *mask, const char draw_flag, c
spline->points_deform = NULL;
draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
-// draw_spline_parents(masklay, spline);
- draw_spline_points(C, masklay, spline, draw_flag, draw_type, xscale, yscale);
+ draw_spline_points(C, masklay, spline, draw_flag, draw_type);
spline->points_deform = back;
}
}
}
+
+ GPU_disable_program_point_size();
+ GPU_blend(false);
}
void ED_mask_draw(const bContext *C,
const char draw_flag, const char draw_type)
{
ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
-
Mask *mask = CTX_data_edit_mask(C);
int width, height;
- float aspx, aspy;
- float xscale, yscale;
if (!mask)
return;
ED_mask_get_size(sa, &width, &height);
- ED_mask_get_aspect(sa, ar, &aspx, &aspy);
- UI_view2d_scale_get(&ar->v2d, &xscale, &yscale);
- draw_masklays(C, mask, draw_flag, draw_type, width, height, xscale * aspx, yscale * aspy);
+ draw_masklays(C, mask, draw_flag, draw_type, width, height);
}
static float *mask_rasterize(Mask *mask, const int width, const int height)
@@ -733,57 +690,55 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar,
}
if (draw_flag & MASK_DRAWFLAG_OVERLAY) {
+ float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
float *buffer = mask_rasterize(mask, width, height);
- int format;
- if (overlay_mode == MASK_OVERLAY_ALPHACHANNEL) {
- glColor3f(1.0f, 1.0f, 1.0f);
- format = GL_LUMINANCE;
- }
- else {
+ if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
/* More blending types could be supported in the future. */
- glEnable(GL_BLEND);
- glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
- format = GL_ALPHA;
+ GPU_blend(true);
+ GPU_blend_set_func(GPU_DST_COLOR, GPU_ZERO);
}
- glPushMatrix();
- glTranslatef(x, y, 0);
- glScalef(zoomx, zoomy, 0);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_scale_2f(zoomx, zoomy);
if (stabmat) {
- glMultMatrixf(stabmat);
+ GPU_matrix_mul(stabmat);
}
- glaDrawPixelsTex(0.0f, 0.0f, width, height, format, GL_FLOAT, GL_NEAREST, buffer);
- glPopMatrix();
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
+ GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
+ immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GL_RED, GL_FLOAT, GL_NEAREST, buffer, 1.0f, 1.0f, NULL);
+
+ GPU_matrix_pop();
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
MEM_freeN(buffer);
}
/* apply transformation so mask editing tools will assume drawing from the origin in normalized space */
- glPushMatrix();
- glTranslatef(x + xofs, y + yofs, 0);
- glScalef(zoomx, zoomy, 0);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(x + xofs, y + yofs);
+ GPU_matrix_scale_2f(zoomx, zoomy);
if (stabmat) {
- glMultMatrixf(stabmat);
+ GPU_matrix_mul(stabmat);
}
- glScalef(maxdim, maxdim, 0);
+ GPU_matrix_scale_2f(maxdim, maxdim);
if (do_draw_cb) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
}
/* draw! */
- draw_masklays(C, mask, draw_flag, draw_type, width, height, maxdim * zoomx, maxdim * zoomy);
+ draw_masklays(C, mask, draw_flag, draw_type, width, height);
if (do_draw_cb) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
}
- glPopMatrix();
+ GPU_matrix_pop();
}
void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra, const int efra)
@@ -792,25 +747,31 @@ void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra
MaskLayer *masklay = BKE_mask_layer_active(mask);
- glBegin(GL_LINES);
- glColor4ub(255, 175, 0, 255);
-
if (masklay) {
- MaskLayerShape *masklay_shape;
+ unsigned int num_lines = BLI_listbase_count(&masklay->splines_shapes);
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- int frame = masklay_shape->frame;
+ if (num_lines > 0) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ub(255, 175, 0, 255);
+
+ immBegin(GPU_PRIM_LINES, 2 * num_lines);
- /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
- int height = (frame == cfra) ? 22 : 10;
- int x = (frame - sfra) * framelen;
- glVertex2i(x, 0);
- glVertex2i(x, height);
+ for (MaskLayerShape *masklay_shape = masklay->splines_shapes.first;
+ masklay_shape;
+ masklay_shape = masklay_shape->next)
+ {
+ int frame = masklay_shape->frame;
+
+ /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
+ int height = (frame == cfra) ? 22 : 10;
+ int x = (frame - sfra) * framelen;
+ immVertex2i(pos, x, 0);
+ immVertex2i(pos, x, height);
+ }
+ immEnd();
+ immUnbindProgram();
}
}
-
- glEnd();
}
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index 540101ba401..03fc7252ea6 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -42,6 +42,7 @@
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_mask.h" /* own include */
#include "ED_image.h"
#include "ED_object.h" /* ED_keymap_proportional_maskmode only */
@@ -478,7 +479,7 @@ void ED_operatortypes_mask(void)
/* select */
WM_operatortype_append(MASK_OT_select);
WM_operatortype_append(MASK_OT_select_all);
- WM_operatortype_append(MASK_OT_select_border);
+ WM_operatortype_append(MASK_OT_select_box);
WM_operatortype_append(MASK_OT_select_lasso);
WM_operatortype_append(MASK_OT_select_circle);
WM_operatortype_append(MASK_OT_select_linked_pick);
@@ -522,104 +523,8 @@ void ED_operatortypes_mask(void)
void ED_keymap_mask(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
- keymap = WM_keymap_ensure(keyconf, "Mask Editing", 0, 0);
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Mask Editing", 0, 0);
keymap->poll = ED_maskedit_poll;
-
- WM_keymap_add_item(keymap, "MASK_OT_new", NKEY, KM_PRESS, KM_ALT, 0);
-
- /* add menu */
- WM_keymap_add_menu(keymap, "MASK_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* mask mode supports PET now */
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_maskmode(keyconf, keymap);
-
- /* geometry */
- WM_keymap_add_item(keymap, "MASK_OT_add_vertex_slide", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "MASK_OT_add_feather_vertex_slide", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "MASK_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MASK_OT_delete", DELKEY, KM_PRESS, 0, 0);
-
- /* selection */
- kmi = WM_keymap_add_item(keymap, "MASK_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", false);
- kmi = WM_keymap_add_item(keymap, "MASK_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- kmi = WM_keymap_add_item(keymap, "MASK_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "MASK_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "MASK_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
- kmi = WM_keymap_add_item(keymap, "MASK_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "MASK_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- WM_keymap_add_item(keymap, "MASK_OT_select_border", BKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MASK_OT_select_circle", CKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "MASK_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "MASK_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- WM_keymap_add_item(keymap, "MASK_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "MASK_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- /* hide/reveal */
- WM_keymap_add_item(keymap, "MASK_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "MASK_OT_hide_view_set", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
-
- kmi = WM_keymap_add_item(keymap, "MASK_OT_hide_view_set", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- /* select clip while in maker view,
- * this matches View3D functionality where you can select an
- * object while in editmode to allow vertex parenting */
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
-
- /* shape */
- WM_keymap_add_item(keymap, "MASK_OT_cyclic_toggle", CKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "MASK_OT_slide_point", ACTIONMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MASK_OT_slide_spline_curvature", ACTIONMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MASK_OT_handle_type_set", VKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MASK_OT_normals_make_consistent", NKEY, KM_PRESS, KM_CTRL, 0);
- // WM_keymap_add_item(keymap, "MASK_OT_feather_weight_clear", SKEY, KM_PRESS, KM_ALT, 0);
- /* ... matches curve editmode */
-
- /* relationships */
- WM_keymap_add_item(keymap, "MASK_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "MASK_OT_parent_clear", PKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "MASK_OT_shape_key_insert", IKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MASK_OT_shape_key_clear", IKEY, KM_PRESS, KM_ALT, 0);
-
- /* duplicate */
- WM_keymap_add_item(keymap, "MASK_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "MASK_OT_copy_splines", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "MASK_OT_paste_splines", VKEY, KM_PRESS, KM_CTRL, 0);
-
- /* for image editor only */
- WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
-
- /* Transform (don't use transform_keymap_for_space() since this maps to different spaces) */
- WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0);
- WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_MASK_SHRINKFATTEN);
}
void ED_operatormacros_mask(void)
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index 21f406c7657..00db3c6e659 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -187,7 +187,7 @@ void ED_mask_select_frame(MaskLayer *masklay, int selx, short select_mode)
}
/* select the frames in this layer that occur within the bounds specified */
-void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max, short select_mode)
+void ED_masklayer_frames_select_box(MaskLayer *masklay, float min, float max, short select_mode)
{
MaskLayerShape *masklay_shape;
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index e9ef06a368f..cb2bb953994 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -103,7 +103,7 @@ void MASK_OT_parent_clear(struct wmOperatorType *ot);
void MASK_OT_select(struct wmOperatorType *ot);
void MASK_OT_select_all(struct wmOperatorType *ot);
-void MASK_OT_select_border(struct wmOperatorType *ot);
+void MASK_OT_select_box(struct wmOperatorType *ot);
void MASK_OT_select_lasso(struct wmOperatorType *ot);
void MASK_OT_select_circle(struct wmOperatorType *ot);
void MASK_OT_select_linked_pick(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index cf67a9715a8..cb90d0a4888 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -35,10 +35,11 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_mask.h"
+#include "DEG_depsgraph.h"
+
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h" /* SELECT */
@@ -51,6 +52,7 @@
#include "ED_keyframing.h"
#include "ED_mask.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -1062,7 +1064,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
- DAG_id_tag_update(&data->mask->id, 0);
+ DEG_id_tag_update(&data->mask->id, 0);
break;
}
@@ -1089,7 +1091,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
- DAG_id_tag_update(&data->mask->id, 0);
+ DEG_id_tag_update(&data->mask->id, 0);
free_slide_point_data(op->customdata); /* keep this last! */
return OPERATOR_FINISHED;
@@ -1105,7 +1107,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
cancel_slide_point(op->customdata);
WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
- DAG_id_tag_update(&data->mask->id, 0);
+ DEG_id_tag_update(&data->mask->id, 0);
free_slide_point_data(op->customdata); /* keep this last! */
return OPERATOR_CANCELLED;
@@ -1469,7 +1471,7 @@ static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEve
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
- DAG_id_tag_update(&slide_data->mask->id, 0);
+ DEG_id_tag_update(&slide_data->mask->id, 0);
break;
}
@@ -1483,7 +1485,7 @@ static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEve
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
- DAG_id_tag_update(&slide_data->mask->id, 0);
+ DEG_id_tag_update(&slide_data->mask->id, 0);
free_slide_spline_curvature_data(slide_data); /* keep this last! */
return OPERATOR_FINISHED;
@@ -1495,7 +1497,7 @@ static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEve
cancel_slide_spline_curvature(slide_data);
WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
- DAG_id_tag_update(&slide_data->mask->id, 0);
+ DEG_id_tag_update(&slide_data->mask->id, 0);
free_slide_spline_curvature_data(op->customdata); /* keep this last! */
return OPERATOR_CANCELLED;
@@ -1541,7 +1543,7 @@ static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
return OPERATOR_FINISHED;
@@ -1900,7 +1902,7 @@ static int set_handle_type_exec(bContext *C, wmOperator *op)
if (changed) {
WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
@@ -1955,7 +1957,7 @@ static int mask_hide_view_clear_exec(bContext *C, wmOperator *op)
if (changed) {
WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
@@ -2019,7 +2021,7 @@ static int mask_hide_view_set_exec(bContext *C, wmOperator *op)
if (changed) {
WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
@@ -2079,7 +2081,7 @@ static int mask_feather_weight_clear_exec(bContext *C, wmOperator *UNUSED(op))
BKE_mask_update_display(mask, CFRA);
WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 4e0aa8f84ae..c500ec75aee 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -34,10 +34,11 @@
#include "BLI_string.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_mask.h"
#include "BKE_tracking.h"
+#include "DEG_depsgraph.h"
+
#include "DNA_mask_types.h"
#include "WM_api.h"
@@ -73,7 +74,7 @@ static int mask_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
}
WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
@@ -176,7 +177,7 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
}
WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 8559be67ece..a5daa7b4565 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -45,6 +45,7 @@
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_mask.h" /* own include */
#include "RNA_access.h"
@@ -395,9 +396,9 @@ void MASK_OT_select(wmOperatorType *ot)
-/********************** border select operator *********************/
+/********************** box select operator *********************/
-static int border_select_exec(bContext *C, wmOperator *op)
+static int box_select_exec(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -461,24 +462,24 @@ static int border_select_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-void MASK_OT_select_border(wmOperatorType *ot)
+void MASK_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->description = "Select curve points using border selection";
- ot->idname = "MASK_OT_select_border";
+ ot->name = "Box Select";
+ ot->description = "Select curve points using box selection";
+ ot->idname = "MASK_OT_select_box";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = border_select_exec;
- ot->modal = WM_gesture_border_modal;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = box_select_exec;
+ ot->modal = WM_gesture_box_modal;
ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
static bool do_lasso_select_mask(bContext *C, const int mcords[][2], short moves, bool select, bool extend)
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index 5df0b80ad2a..4337ff705b6 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -36,13 +36,14 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_mask.h"
#include "DNA_object_types.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -75,7 +76,7 @@ static int mask_shape_key_insert_exec(bContext *C, wmOperator *UNUSED(op))
if (changed) {
WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
@@ -123,7 +124,7 @@ static int mask_shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
if (changed) {
WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&mask->id, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
@@ -214,7 +215,7 @@ static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op)
if (changed) {
WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
@@ -384,7 +385,7 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
if (changed) {
WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index f1f0de3777e..4cefbf21c24 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../bmesh
../../gpu
../../imbuf
@@ -31,6 +32,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
../../../../intern/glew-mx
)
@@ -42,20 +44,26 @@ set(INC_SYS
set(SRC
editface.c
editmesh_add.c
+ editmesh_add_gizmo.c
editmesh_bevel.c
editmesh_bisect.c
editmesh_extrude.c
editmesh_extrude_screw.c
editmesh_extrude_spin.c
+ editmesh_extrude_spin_gizmo.c
editmesh_inset.c
editmesh_intersect.c
editmesh_knife.c
editmesh_knife_project.c
editmesh_loopcut.c
editmesh_path.c
+ editmesh_polybuild.c
+ editmesh_preselect_edgering.c
+ editmesh_preselect_elem.c
editmesh_rip.c
editmesh_rip_edge.c
editmesh_select.c
+ editmesh_select_similar.c
editmesh_tools.c
editmesh_undo.c
editmesh_utils.c
@@ -67,18 +75,6 @@ set(SRC
mesh_intern.h
)
-if(WITH_GAMEENGINE)
- add_definitions(-DWITH_GAMEENGINE)
-
- list(APPEND INC
- ../../../../extern/recastnavigation
- )
-
- list(APPEND SRC
- mesh_navmesh.c
- )
-endif()
-
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index d497a073f77..2beb9303a2e 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -33,25 +33,28 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
-#include "BKE_context.h"
#include "BIF_gl.h"
#include "ED_mesh.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_view3d.h"
#include "WM_api.h"
#include "WM_types.h"
#include "GPU_draw.h"
-#include "GPU_buffers.h"
+
+#include "DEG_depsgraph.h"
/* own include */
@@ -60,7 +63,7 @@
void paintface_flush_flags(Object *ob, short flag)
{
Mesh *me = BKE_mesh_from_object(ob);
- DerivedMesh *dm = ob->derivedFinal;
+ Mesh *me_eval = ob->runtime.mesh_eval;
MPoly *polys, *mp_orig;
const int *index_array = NULL;
int totpoly;
@@ -79,14 +82,14 @@ void paintface_flush_flags(Object *ob, short flag)
BKE_mesh_flush_select_from_polys(me);
}
- if (dm == NULL)
+ if (me_eval == NULL)
return;
/* Mesh polys => Final derived polys */
- if ((index_array = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX))) {
- polys = dm->getPolyArray(dm);
- totpoly = dm->getNumPolys(dm);
+ if ((index_array = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX))) {
+ polys = me_eval->mpoly;
+ totpoly = me_eval->totpoly;
/* loop over final derived polys */
for (i = 0; i < totpoly; i++) {
@@ -99,10 +102,13 @@ void paintface_flush_flags(Object *ob, short flag)
}
}
- if (flag & ME_HIDE) {
- /* draw-object caches hidden faces, force re-generation T46867 */
- GPU_drawobject_free(dm);
- }
+ BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
+}
+
+void paintface_tag_select_update(struct bContext *C, struct Object *ob)
+{
+ DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
void paintface_hide(Object *ob, const bool unselected)
@@ -252,6 +258,7 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b
select_linked_tfaces_with_seams(me, index, select);
paintface_flush_flags(ob, SELECT);
+ paintface_tag_select_update(C, ob);
}
void paintface_deselect_all_visible(Object *ob, int action, bool flush_flags)
@@ -386,12 +393,12 @@ bool paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], b
/* image window redraw */
paintface_flush_flags(ob, SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ paintface_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
return true;
}
-int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
+int do_paintface_box_select(ViewContext *vc, rcti *rect, int sel_op)
{
Object *ob = vc->obact;
Mesh *me;
@@ -412,7 +419,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
selar = MEM_callocN(me->totpoly + 1, "selar");
- if (extend == false && select) {
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
paintface_deselect_all_visible(vc->obact, SEL_DESELECT, false);
}
@@ -439,13 +446,12 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
mpoly = me->mpoly;
for (a = 1; a <= me->totpoly; a++, mpoly++) {
- if (selar[a]) {
- if (mpoly->flag & ME_HIDE) {
- /* pass */
- }
- else {
- if (select) mpoly->flag |= ME_FACE_SEL;
- else mpoly->flag &= ~ME_FACE_SEL;
+ if ((mpoly->flag & ME_HIDE) == 0) {
+ const bool is_select = mpoly->flag & ME_FACE_SEL;
+ const bool is_inside = (selar[a] != 0);
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL);
}
}
}
@@ -458,6 +464,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
#endif
paintface_flush_flags(vc->obact, SELECT);
+ paintface_tag_select_update(vc->C, vc->obact);
return OPERATOR_FINISHED;
}
@@ -469,8 +476,8 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
void paintvert_flush_flags(Object *ob)
{
Mesh *me = BKE_mesh_from_object(ob);
- DerivedMesh *dm = ob->derivedFinal;
- MVert *dm_mvert, *dm_mv;
+ Mesh *me_eval = ob->runtime.mesh_eval;
+ MVert *mvert_eval, *mv;
const int *index_array = NULL;
int totvert;
int i;
@@ -482,31 +489,40 @@ void paintvert_flush_flags(Object *ob)
* since this could become slow for realtime updates (circle-select for eg) */
BKE_mesh_flush_select_from_verts(me);
- if (dm == NULL)
+ if (me_eval == NULL)
return;
- index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ index_array = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
- dm_mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
+ mvert_eval = me_eval->mvert;
+ totvert = me_eval->totvert;
- dm_mv = dm_mvert;
+ mv = mvert_eval;
if (index_array) {
int orig_index;
- for (i = 0; i < totvert; i++, dm_mv++) {
+ for (i = 0; i < totvert; i++, mv++) {
orig_index = index_array[i];
if (orig_index != ORIGINDEX_NONE) {
- dm_mv->flag = me->mvert[index_array[i]].flag;
+ mv->flag = me->mvert[index_array[i]].flag;
}
}
}
else {
- for (i = 0; i < totvert; i++, dm_mv++) {
- dm_mv->flag = me->mvert[i].flag;
+ for (i = 0; i < totvert; i++, mv++) {
+ mv->flag = me->mvert[i].flag;
}
}
+
+ BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
}
+
+void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
+{
+ DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+}
+
/* note: if the caller passes false to flush_flags, then they will need to run paintvert_flush_flags(ob) themselves */
void paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 9bea203e67b..dd16cb9e4ec 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -38,7 +38,6 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_library.h"
#include "BKE_editmesh.h"
#include "RNA_define.h"
@@ -60,31 +59,36 @@
/* ********* add primitive operators ************* */
+typedef struct MakePrimitiveData {
+ float mat[4][4];
+ bool was_editmode;
+} MakePrimitiveData;
+
static Object *make_prim_init(
bContext *C, const char *idname,
- float *dia, float mat[4][4],
- bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer)
+ const float loc[3], const float rot[3],
+ MakePrimitiveData *r_creation_data)
{
Object *obedit = CTX_data_edit_object(C);
- *was_editmode = false;
+ r_creation_data->was_editmode = false;
if (obedit == NULL || obedit->type != OB_MESH) {
- obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer);
+ obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false);
/* create editmode */
ED_object_editmode_enter(C, EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
- *was_editmode = true;
+ r_creation_data->was_editmode = true;
}
- *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
return obedit;
}
-static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int enter_editmode)
+static void make_prim_finish(bContext *C, Object *obedit, const MakePrimitiveData *creation_data, int enter_editmode)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const bool exit_editmode = ((was_editmode == true) && (enter_editmode == false));
+ const bool exit_editmode = ((creation_data->was_editmode == true) && (enter_editmode == false));
/* Primitive has all verts selected, use vert select flush
* to push this up to edges & faces. */
@@ -102,17 +106,16 @@ static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int
static int add_primitive_plane_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
- unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer);
+ ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -122,12 +125,12 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
"create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
- 1, 1, RNA_float_get(op->ptr, "radius"), mat, calc_uvs))
+ 1, 1, RNA_float_get(op->ptr, "size") / 2.0f, creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -146,24 +149,23 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_size(ot);
ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
static int add_primitive_cube_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
- unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer);
+ ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -173,13 +175,13 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
"create_cube matrix=%m4 size=%f calc_uvs=%b",
- mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs))
+ creation_data.mat, RNA_float_get(op->ptr, "size"), calc_uvs))
{
return OPERATOR_CANCELLED;
}
/* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -198,7 +200,7 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_size(ot);
ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -211,21 +213,20 @@ static const EnumPropertyItem fill_type_items[] = {
static int add_primitive_circle_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
int cap_end, cap_tri;
- unsigned int layer;
- bool was_editmode;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
cap_end = RNA_enum_get(op->ptr, "fill_type");
cap_tri = (cap_end == 2);
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer);
+ ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -236,12 +237,12 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
em, op, "verts.out", false,
"create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
- cap_end, cap_tri, mat, calc_uvs))
+ cap_end, cap_tri, creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -262,7 +263,7 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", "");
ED_object_add_mesh_props(ot);
@@ -271,20 +272,19 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot)
static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- unsigned int layer;
- bool was_editmode;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
const bool cap_end = (end_fill_type != 0);
const bool cap_tri = (end_fill_type == 2);
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer);
+ ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), loc, rot, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -298,12 +298,12 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
RNA_float_get(op->ptr, "radius"),
RNA_float_get(op->ptr, "radius"),
cap_end, cap_tri,
- RNA_float_get(op->ptr, "depth"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "depth"), creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -324,7 +324,7 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", "");
@@ -334,20 +334,19 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
static int add_primitive_cone_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- unsigned int layer;
- bool was_editmode;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
const bool cap_end = (end_fill_type != 0);
const bool cap_tri = (end_fill_type == 2);
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer);
+ ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -358,12 +357,13 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
em, op, "verts.out", false,
"create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"),
- RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"),
+ creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -395,17 +395,16 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
static int add_primitive_grid_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
- unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer);
+ ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -417,12 +416,12 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
"create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "x_subdivisions"),
RNA_int_get(op->ptr, "y_subdivisions"),
- RNA_float_get(op->ptr, "radius"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "size") / 2.0f, creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -446,30 +445,28 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot)
* impossible values (10^12 vertices or so...). */
RNA_def_int(ot->srna, "x_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "X Subdivisions", "", 2, 1000);
RNA_def_int(ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000);
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_size(ot);
ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float mat[4][4];
float loc[3], rot[3];
float dia;
bool enter_editmode;
- unsigned int layer;
- bool was_editmode;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &layer, NULL);
+ ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer);
- dia = RNA_float_get(op->ptr, "radius");
- mul_mat3_m4_fl(mat, dia);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, &creation_data);
+ dia = RNA_float_get(op->ptr, "size") / 2.0f;
+ mul_mat3_m4_fl(creation_data.mat, dia);
em = BKE_editmesh_from_object(obedit);
@@ -479,12 +476,12 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_monkey matrix=%m4 calc_uvs=%b", mat, calc_uvs))
+ "create_monkey matrix=%m4 calc_uvs=%b", creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -501,27 +498,26 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
ot->poll = ED_operator_scene_editable;
/* flags */
- ED_object_add_unit_props(ot);
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
+ ED_object_add_unit_props_size(ot);
ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
- unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer);
+ ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -532,12 +528,12 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
em, op, "verts.out", false,
"create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"),
- RNA_float_get(op->ptr, "size"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -559,25 +555,24 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "segments", 32, 3, MESH_ADD_VERTS_MAXI / 100, "Segments", "", 3, 500);
RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500);
- RNA_def_float_distance(ot->srna, "size", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
{
+ MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float loc[3], rot[3];
bool enter_editmode;
- bool was_editmode;
- unsigned int layer;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
- obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer);
+ ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL);
+ obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), loc, rot, &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -588,12 +583,12 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
em, op, "verts.out", false,
"create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "subdivisions"),
- RNA_float_get(op->ptr, "size"), mat, calc_uvs))
+ RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
- make_prim_finish(C, obedit, was_editmode, enter_editmode);
+ make_prim_finish(C, obedit, &creation_data, enter_editmode);
return OPERATOR_FINISHED;
}
@@ -614,8 +609,8 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8);
- RNA_def_float_distance(ot->srna, "size", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001f, 100.00);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c
new file mode 100644
index 00000000000..d3a81a3f9ed
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_add_gizmo.c
@@ -0,0 +1,405 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_add_gizmo.c
+ * \ingroup edmesh
+ *
+ * Creation gizmos.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
+#include "ED_mesh.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_undo.h"
+#include "ED_view3d.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_resources.h"
+
+#include "BLT_translation.h"
+
+#include "mesh_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper Functions
+ * \{ */
+
+/**
+ * When we place a shape, pick a plane.
+ *
+ * We may base this choice on context,
+ * for now pick the "ground" based on the 3D cursor's dominant plane pointing down relative to the view.
+ */
+static void calc_initial_placement_point_from_view(
+ bContext *C, const float mval[2],
+ float r_location[3], float r_rotation[3][3])
+{
+
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ bool use_mouse_project = true; /* TODO: make optional */
+
+ float cursor_matrix[4][4];
+ float orient_matrix[3][3];
+ ED_view3d_cursor3d_calc_mat4(scene, cursor_matrix);
+
+ float dots[3] = {
+ dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]),
+ dot_v3v3(rv3d->viewinv[2], cursor_matrix[1]),
+ dot_v3v3(rv3d->viewinv[2], cursor_matrix[2]),
+ };
+ const int axis = axis_dominant_v3_single(dots);
+
+ copy_v3_v3(orient_matrix[0], cursor_matrix[(axis + 1) % 3]);
+ copy_v3_v3(orient_matrix[1], cursor_matrix[(axis + 2) % 3]);
+ copy_v3_v3(orient_matrix[2], cursor_matrix[axis]);
+
+ if (dot_v3v3(rv3d->viewinv[2], orient_matrix[2]) < 0.0f) {
+ negate_v3(orient_matrix[2]);
+ }
+ if (is_negative_m3(orient_matrix)) {
+ swap_v3_v3(orient_matrix[0], orient_matrix[1]);
+ }
+
+ if (use_mouse_project) {
+ float plane[4];
+ plane_from_point_normal_v3(plane, cursor_matrix[3], orient_matrix[2]);
+ if (ED_view3d_win_to_3d_on_plane(ar, plane, mval, true, r_location)) {
+ copy_m3_m3(r_rotation, orient_matrix);
+ return;
+ }
+ }
+
+ /* fallback */
+ copy_v3_v3(r_location, cursor_matrix[3]);
+ copy_m3_m3(r_rotation, orient_matrix);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Placement Gizmo
+ * \{ */
+
+typedef struct GizmoPlacementGroup {
+ struct wmGizmo *cage;
+ struct {
+ bContext *context;
+ wmOperator *op;
+ PropertyRNA *prop_matrix;
+ } data;
+} GizmoPlacementGroup;
+
+/**
+ * \warning Calling redo from property updates is not great.
+ * This is needed because changing the RNA doesn't cause a redo
+ * and we're not using operator UI which does just this.
+ */
+static void gizmo_placement_exec(GizmoPlacementGroup *ggd)
+{
+ wmOperator *op = ggd->data.op;
+ if (op == WM_operator_last_redo((bContext *)ggd->data.context)) {
+ ED_undo_operator_repeat((bContext *)ggd->data.context, op);
+ }
+}
+
+static void gizmo_mesh_placement_update_from_op(GizmoPlacementGroup *ggd)
+{
+ wmOperator *op = ggd->data.op;
+ UNUSED_VARS(op);
+ /* For now don't read back from the operator. */
+#if 0
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_matrix, &ggd->cage->matrix_offset[0][0]);
+#endif
+}
+
+/* translate callbacks */
+static void gizmo_placement_prop_matrix_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ GizmoPlacementGroup *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ float *value = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ if (value_p != ggd->cage->matrix_offset) {
+ mul_m4_m4m4(value_p, ggd->cage->matrix_basis, ggd->cage->matrix_offset);
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_matrix, value);
+ }
+}
+
+static void gizmo_placement_prop_matrix_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value)
+{
+ GizmoPlacementGroup *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+
+ BLI_assert(gz_prop->type->array_length == 16);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ float mat[4][4];
+ mul_m4_m4m4(mat, ggd->cage->matrix_basis, value);
+
+ if (is_negative_m4(mat)) {
+ negate_mat3_m4(mat);
+ }
+
+ RNA_property_float_set_array(op->ptr, ggd->data.prop_matrix, &mat[0][0]);
+
+ gizmo_placement_exec(ggd);
+}
+
+static bool gizmo_mesh_placement_poll(const bContext *C, wmGizmoGroupType *gzgt)
+{
+ return ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_primitive_cube_add_gizmo");
+}
+
+static void gizmo_mesh_placement_modal_from_setup(
+ const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoPlacementGroup *ggd = gzgroup->customdata;
+
+ /* Initial size. */
+ {
+ wmGizmo *gz = ggd->cage;
+ zero_m4(gz->matrix_offset);
+
+ /* TODO: support zero scaled matrix in 'GIZMO_GT_cage_3d'. */
+ gz->matrix_offset[0][0] = 0.01;
+ gz->matrix_offset[1][1] = 0.01;
+ gz->matrix_offset[2][2] = 0.01;
+ gz->matrix_offset[3][3] = 1.0f;
+ }
+
+ /* Start off dragging. */
+ {
+ wmWindow *win = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmo *gz = ggd->cage;
+
+ {
+ float mat3[3][3];
+ float location[3];
+ calc_initial_placement_point_from_view(
+ (bContext *)C, (float[2]){
+ win->eventstate->x - ar->winrct.xmin,
+ win->eventstate->y - ar->winrct.ymin,
+ },
+ location, mat3);
+ copy_m4_m3(gz->matrix_basis, mat3);
+ copy_v3_v3(gz->matrix_basis[3], location);
+ }
+
+ if (1) {
+ wmGizmoMap *gzmap = gzgroup->parent_gzmap;
+ WM_gizmo_modal_set_from_setup(
+ gzmap, (bContext *)C, ggd->cage, ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, win->eventstate);
+ }
+ }
+}
+
+static void gizmo_mesh_placement_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+
+ if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_gizmo")) {
+ return;
+ }
+
+ struct GizmoPlacementGroup *ggd = MEM_callocN(sizeof(GizmoPlacementGroup), __func__);
+ gzgroup->customdata = ggd;
+
+ const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true);
+
+ ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL);
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->cage->color);
+
+ RNA_enum_set(ggd->cage->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE |
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE |
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_SIGNED);
+
+ WM_gizmo_set_flag(ggd->cage, WM_GIZMO_DRAW_VALUE, true);
+
+ ggd->data.context = (bContext *)C;
+ ggd->data.op = op;
+ ggd->data.prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
+
+ gizmo_mesh_placement_update_from_op(ggd);
+
+ /* Setup property callbacks */
+ {
+ WM_gizmo_target_property_def_func(
+ ggd->cage, "matrix",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_placement_prop_matrix_get,
+ .value_set_fn = gizmo_placement_prop_matrix_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+ }
+
+ gizmo_mesh_placement_modal_from_setup(C, gzgroup);
+}
+
+static void gizmo_mesh_placement_draw_prepare(
+ const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ GizmoPlacementGroup *ggd = gzgroup->customdata;
+ if (ggd->data.op->next) {
+ ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context);
+ }
+ gizmo_mesh_placement_update_from_op(ggd);
+}
+
+static void MESH_GGT_add_bounds(struct wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Mesh Add Bounds";
+ gzgt->idname = "MESH_GGT_add_bounds";
+
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = gizmo_mesh_placement_poll;
+ gzgt->setup = gizmo_mesh_placement_setup;
+ gzgt->draw_prepare = gizmo_mesh_placement_draw_prepare;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Cube Gizmo-Operator
+ *
+ * For now we use a separate operator to add a cube,
+ * we can try to merge then however they are invoked differently
+ * and share the same BMesh creation code.
+ * \{ */
+
+
+static int add_primitive_cube_gizmo_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ float matrix[4][4];
+
+ /* Get the matrix that defines the cube bounds (as set by the gizmo cage). */
+ {
+ PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
+ if (RNA_property_is_set(op->ptr, prop_matrix)) {
+ RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]);
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_m4_m4m4(matrix, obedit->imat, matrix);
+ }
+ else {
+ /* For the first update the widget may not set the matrix. */
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
+
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
+ if (!EDBM_op_call_and_selectf(
+ em, op, "verts.out", false,
+ "create_cube matrix=%m4 size=%f calc_uvs=%b",
+ matrix, 1.0f, calc_uvs))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
+ EDBM_update_generic(em, true, true);
+
+ return OPERATOR_FINISHED;
+}
+
+static int add_primitive_cube_gizmo_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+
+ int ret = add_primitive_cube_gizmo_exec(C, op);
+ if (ret & OPERATOR_FINISHED) {
+ /* Setup gizmos */
+ if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) {
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find("MESH_GGT_add_bounds", false);
+ if (!WM_gizmo_group_type_ensure_ptr(gzgt)) {
+ struct Main *bmain = CTX_data_main(C);
+ WM_gizmo_group_type_reinit_ptr(bmain, gzgt);
+ }
+ }
+ }
+
+ return ret;
+}
+
+void MESH_OT_primitive_cube_add_gizmo(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Cube";
+ ot->description = "Construct a cube mesh";
+ ot->idname = "MESH_OT_primitive_cube_add_gizmo";
+
+ /* api callbacks */
+ ot->invoke = add_primitive_cube_gizmo_invoke;
+ ot->exec = add_primitive_cube_gizmo_exec;
+ ot->poll = ED_operator_editmesh_view3d;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ED_object_add_mesh_props(ot);
+ ED_object_add_generic_props(ot, true);
+
+ /* hidden props */
+ PropertyRNA *prop = RNA_def_float_matrix(ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ WM_gizmogrouptype_append(MESH_GGT_add_bounds);
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index e44a43c4c3a..0202d52a263 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -30,6 +30,7 @@
#include "BLI_string.h"
#include "BLI_math.h"
+#include "BLI_linklist_stack.h"
#include "BLT_translation.h"
@@ -37,6 +38,8 @@
#include "BKE_global.h"
#include "BKE_editmesh.h"
#include "BKE_unit.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -77,17 +80,24 @@ static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f,
typedef struct {
BMEditMesh *em;
+ BMBackup mesh_backup;
+} BevelObjectStore;
+
+
+typedef struct {
float initial_length[NUM_VALUE_KINDS];
float scale[NUM_VALUE_KINDS];
NumInput num_input[NUM_VALUE_KINDS];
float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */
bool is_modal;
+ BevelObjectStore *ob_store;
+ uint ob_store_len;
+
/* modal only */
float mcenter[2];
- BMBackup mesh_backup;
void *draw_handle_pixel;
- short twtype;
+ short gizmo_flag;
short value_mode; /* Which value does mouse movement and numeric input affect? */
float segments; /* Segments as float so smooth mouse pan works in small increments */
} BevelData;
@@ -122,30 +132,133 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
WM_bool_as_string(opdata->value_mode == PROFILE_VALUE),
offset_str, RNA_int_get(op->ptr, "segments"), RNA_float_get(op->ptr, "profile"));
- ED_area_headerprint(sa, msg);
+ ED_area_status_text(sa, msg);
+ }
+}
+
+static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_strength)
+{
+ BKE_editmesh_lnorspace_update(em);
+ BM_normals_loops_edges_tag(em->bm, true);
+ const int cd_clnors_offset = CustomData_get_offset(&em->bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l, *l_cur, *l_first;
+ BMIter fiter;
+
+ BMOpSlot *nslot = BMO_slot_get(bmop->slots_out, "normals.out"); /* Per vertex normals depending on hn_mode */
+
+ /* Similar functionality to bm_mesh_loops_calc_normals... Edges that can be smoothed are tagged */
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ l_cur = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if ((BM_elem_flag_test(l_cur->v, BM_ELEM_SELECT)) &&
+ ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG)) ||
+ (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur))))
+ {
+ /* Both adjacent loops are sharp, set clnor to face normal */
+ if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) {
+ const int loop_index = BM_elem_index_get(l_cur);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
+ }
+ else {
+ /* Find next corresponding sharp edge in this smooth fan */
+ BMVert *v_pivot = l_cur->v;
+ float *calc_n = BLI_ghash_lookup(nslot->data.ghash, v_pivot);
+
+ BMEdge *e_next;
+ const BMEdge *e_org = l_cur->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+
+ lfan_pivot = l_cur;
+ e_next = lfan_pivot->e;
+ BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
+ float cn_wght[3] = { 0.0f, 0.0f, 0.0f }, cn_unwght[3] = { 0.0f, 0.0f, 0.0f };
+
+ /* Fan through current vert and accumulate normals and loops */
+ while (true) {
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
+
+ BLI_SMALLSTACK_PUSH(loops, lfan_pivot);
+ float cur[3];
+ mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
+ add_v3_v3(cn_wght, cur);
+
+ if (BM_elem_flag_test(lfan_pivot->f, BM_ELEM_SELECT))
+ add_v3_v3(cn_unwght, cur);
+
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ break;
+ }
+ lfan_pivot = lfan_pivot_next;
+ }
+
+ normalize_v3(cn_wght);
+ normalize_v3(cn_unwght);
+ if (calc_n) {
+ mul_v3_fl(cn_wght, face_strength);
+ mul_v3_fl(calc_n, 1.0f - face_strength);
+ add_v3_v3(calc_n, cn_wght);
+ normalize_v3(calc_n);
+ }
+ while ((l = BLI_SMALLSTACK_POP(loops))) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ if (calc_n) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], calc_n, clnors);
+ }
+ else {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], cn_unwght, clnors);
+ }
+ }
+ BLI_ghash_remove(nslot->data.ghash, v_pivot, NULL, MEM_freeN);
+ }
+ }
+ } while ((l_cur = l_cur->next) != l_first);
}
}
static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
{
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BevelData *opdata;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
float pixels_per_inch;
int i;
- if (em->bm->totvertsel == 0) {
- return false;
- }
-
if (is_modal) {
RNA_float_set(op->ptr, "offset", 0.0f);
}
op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator");
+ uint objects_used_len = 0;
+
+ {
+ uint ob_store_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &ob_store_len);
+ opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__);
+ for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totvertsel > 0) {
+ opdata->ob_store[objects_used_len].em = em;
+ objects_used_len++;
+ }
+ }
+ MEM_freeN(objects);
+ opdata->ob_store_len = objects_used_len;
+ }
- opdata->em = em;
opdata->is_modal = is_modal;
opdata->value_mode = OFFSET_VALUE;
opdata->segments = (float) RNA_int_get(op->ptr, "segments");
@@ -174,14 +287,16 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
- opdata->mesh_backup = EDBM_redo_state_store(em);
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(opdata->ob_store[ob_index].em);
+ }
opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb,
opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
if (v3d) {
- opdata->twtype = v3d->twtype;
- v3d->twtype = 0;
+ opdata->gizmo_flag = v3d->gizmo_flag;
+ v3d->gizmo_flag = V3D_GIZMO_HIDE;
}
}
@@ -191,8 +306,10 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
static bool edbm_bevel_calc(wmOperator *op)
{
BevelData *opdata = op->customdata;
- BMEditMesh *em = opdata->em;
+ BMEditMesh *em;
BMOperator bmop;
+ bool changed = false;
+
const float offset = RNA_float_get(op->ptr, "offset");
const int offset_type = RNA_enum_get(op->ptr, "offset_type");
const int segments = RNA_int_get(op->ptr, "segments");
@@ -201,41 +318,55 @@ static bool edbm_bevel_calc(wmOperator *op)
const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap");
int material = RNA_int_get(op->ptr, "material");
const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide");
+ const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam");
+ const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
+ const float hn_strength = RNA_float_get(op->ptr, "strength");
+ const int hnmode = RNA_enum_get(op->ptr, "hnmode");
- /* revert to original mesh */
- if (opdata->is_modal) {
- EDBM_redo_state_restore(opdata->mesh_backup, em, false);
- }
- if (em->ob) {
- material = CLAMPIS(material, -1, em->ob->totcol - 1);
- }
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ em = opdata->ob_store[ob_index].em;
+
+ /* revert to original mesh */
+ if (opdata->is_modal) {
+ EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false);
+ }
- EDBM_op_init(em, &bmop, op,
- "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
- "material=%i loop_slide=%b",
- BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
- clamp_overlap, material, loop_slide);
+ if (em->ob) {
+ material = CLAMPIS(material, -1, em->ob->totcol - 1);
+ }
- BMO_op_exec(em->bm, &bmop);
+ EDBM_op_init(
+ em, &bmop, op,
+ "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
+ "material=%i loop_slide=%b mark_seam=%b mark_sharp=%b strength=%f hnmode=%i",
+ BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
+ clamp_overlap, material, loop_slide, mark_seam, mark_sharp, hn_strength, hnmode);
- if (offset != 0.0f) {
- /* not essential, but we may have some loose geometry that
- * won't get bevel'd and better not leave it selected */
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
- }
+ BMO_op_exec(em->bm, &bmop);
- /* no need to de-select existing geometry */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return false;
- }
+ if (offset != 0.0f) {
+ /* not essential, but we may have some loose geometry that
+ * won't get bevel'd and better not leave it selected */
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ }
- EDBM_mesh_normals_update(opdata->em);
+ if (hnmode != BEVEL_HN_NONE) {
+ bevel_harden_normals(em, &bmop, hn_strength);
+ }
- EDBM_update_generic(opdata->em, true, true);
+ /* no need to de-select existing geometry */
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
- return true;
+ EDBM_mesh_normals_update(em);
+
+ EDBM_update_generic(em, true, true);
+ changed = true;
+ }
+ return changed;
}
static void edbm_bevel_exit(bContext *C, wmOperator *op)
@@ -245,20 +376,23 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op)
ScrArea *sa = CTX_wm_area(C);
if (sa) {
- ED_area_headerprint(sa, NULL);
+ ED_area_status_text(sa, NULL);
}
if (opdata->is_modal) {
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
- EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false);
+ }
ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel);
if (v3d) {
- v3d->twtype = opdata->twtype;
+ v3d->gizmo_flag = opdata->gizmo_flag;
}
G.moving = 0;
}
- MEM_freeN(opdata);
+ MEM_SAFE_FREE(opdata->ob_store);
+ MEM_SAFE_FREE(op->customdata);
op->customdata = NULL;
}
@@ -266,8 +400,10 @@ static void edbm_bevel_cancel(bContext *C, wmOperator *op)
{
BevelData *opdata = op->customdata;
if (opdata->is_modal) {
- EDBM_redo_state_free(&opdata->mesh_backup, opdata->em, true);
- EDBM_update_generic(opdata->em, false, true);
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true);
+ EDBM_update_generic(opdata->ob_store[ob_index].em, false, true);
+ }
}
edbm_bevel_exit(C, op);
@@ -446,7 +582,9 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
case LEFTMOUSE:
case PADENTER:
case RETKEY:
- if (event->val == KM_PRESS) {
+ if ((event->val == KM_PRESS) ||
+ ((event->val == KM_RELEASE) && RNA_boolean_get(op->ptr, "release_confirm")))
+ {
edbm_bevel_calc(op);
edbm_bevel_exit(C, op);
return OPERATOR_FINISHED;
@@ -570,6 +708,26 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_update_header(C, op);
handled = true;
break;
+ case UKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ else {
+ bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam");
+ RNA_boolean_set(op->ptr, "mark_seam", !mark_seam);
+ edbm_bevel_calc(op);
+ handled = true;
+ break;
+ }
+ case KKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ else {
+ bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
+ RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp);
+ edbm_bevel_calc(op);
+ handled = true;
+ break;
+ }
}
@@ -608,6 +766,13 @@ void MESH_OT_bevel(wmOperatorType *ot)
{0, NULL, 0, NULL, NULL},
};
+ static EnumPropertyItem harden_normals_items[] = {
+ { BEVEL_HN_NONE, "HN_NONE", 0, "Off", "Do not use Harden Normals" },
+ { BEVEL_HN_FACE, "HN_FACE", 0, "Face Area", "Use faces as weight" },
+ { BEVEL_HN_ADJ, "HN_ADJ", 0, "Vertex average", "Use adjacent vertices as weight" },
+ { 0, NULL, 0, NULL, NULL },
+ };
+
/* identifiers */
ot->name = "Bevel";
ot->description = "Edge Bevel";
@@ -633,6 +798,15 @@ void MESH_OT_bevel(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
"Do not allow beveled edges/vertices to overlap each other");
RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths");
+ RNA_def_boolean(ot->srna, "mark_seam", false, "Mark Seams", "Mark Seams along beveled edges");
+ RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp");
RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material",
"Material for bevel faces (-1 means use adjacent faces)", -1, 100);
+ RNA_def_float(ot->srna, "strength", 0.5f, 0.0f, 1.0f, "Normal Strength",
+ "Strength of calculated normal", 0.0f, 1.0f);
+ RNA_def_enum(ot->srna, "hnmode", harden_normals_items, BEVEL_HN_NONE, "Normal Mode",
+ "Weighting mode for Harden Normals");
+ prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
}
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 783fe931670..5b59f1aa5f9 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -38,6 +38,7 @@
#include "BKE_global.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_report.h"
#include "RNA_define.h"
@@ -49,10 +50,19 @@
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_gizmo_utils.h"
+#include "UI_resources.h"
#include "mesh_intern.h" /* own include */
+#define USE_GIZMO
+
+#ifdef USE_GIZMO
+#include "ED_gizmo_library.h"
+#include "ED_undo.h"
+#endif
+
static int mesh_bisect_exec(bContext *C, wmOperator *op);
/* -------------------------------------------------------------------- */
@@ -60,19 +70,21 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op);
typedef struct {
/* modal only */
- BMBackup mesh_backup;
- bool is_first;
- short twtype;
+
+ /* Aligned with objects array. */
+ struct {
+ BMBackup mesh;
+ bool is_valid;
+ bool is_dirty;
+ } *backup;
+ int backup_len;
+ short gizmo_flag;
} BisectData;
-static bool mesh_bisect_interactive_calc(
+static void mesh_bisect_interactive_calc(
bContext *C, wmOperator *op,
- BMEditMesh *em,
float plane_co[3], float plane_no[3])
{
- wmGesture *gesture = op->customdata;
- BisectData *opdata;
-
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
@@ -88,8 +100,6 @@ static bool mesh_bisect_interactive_calc(
float co_a[3], co_b[3];
const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL);
- opdata = gesture->userdata;
-
/* view vector */
ED_view3d_win_to_vector(ar, co_a_ss, co_a);
@@ -103,29 +113,15 @@ static bool mesh_bisect_interactive_calc(
/* point on plane, can use either start or endpoint */
ED_view3d_win_to_3d(v3d, ar, co_ref, co_a_ss, plane_co);
-
- if (opdata->is_first == false)
- EDBM_redo_state_restore(opdata->mesh_backup, em, false);
-
- opdata->is_first = false;
-
- return true;
}
static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int ret;
-
- if (em->bm->totedgesel == 0) {
- BKE_report(op->reports, RPT_ERROR, "Selected edges/faces required");
- return OPERATOR_CANCELLED;
- }
-
- /* if the properties are set or there is no rv3d,
- * skip model and exec immediately */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int valid_objects = 0;
+ /* If the properties are set or there is no rv3d,
+ * skip model and exec immediately. */
if ((CTX_wm_region_view3d(C) == NULL) ||
(RNA_struct_property_is_set(op->ptr, "plane_co") &&
RNA_struct_property_is_set(op->ptr, "plane_no")))
@@ -133,36 +129,71 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return mesh_bisect_exec(C, op);
}
- ret = WM_gesture_straightline_invoke(C, op, event);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totedgesel != 0) {
+ valid_objects++;
+ }
+ }
+
+ if (valid_objects == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Selected edges/faces required");
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+
+ int ret = WM_gesture_straightline_invoke(C, op, event);
if (ret & OPERATOR_RUNNING_MODAL) {
View3D *v3d = CTX_wm_view3d(C);
wmGesture *gesture = op->customdata;
BisectData *opdata;
-
opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data");
- opdata->mesh_backup = EDBM_redo_state_store(em);
- opdata->is_first = true;
gesture->userdata = opdata;
- /* misc other vars */
+ opdata->backup_len = objects_len;
+ opdata->backup = MEM_callocN(sizeof(*opdata->backup) * objects_len, __func__);
+
+ /* Store the mesh backups. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totedgesel != 0) {
+ opdata->backup[ob_index].is_valid = true;
+ opdata->backup[ob_index].mesh = EDBM_redo_state_store(em);
+ }
+ }
+
+ /* Misc other vars. */
G.moving = G_TRANSFORM_EDIT;
- opdata->twtype = v3d->twtype;
- v3d->twtype = 0;
+ opdata->gizmo_flag = v3d->gizmo_flag;
+ v3d->gizmo_flag = V3D_GIZMO_HIDE;
- /* initialize modal callout */
- ED_area_headerprint(CTX_wm_area(C), IFACE_("LMB: Click and drag to draw cut line"));
+ /* Initialize modal callout. */
+ ED_workspace_status_text(C, IFACE_("LMB: Click and drag to draw cut line"));
}
+ MEM_freeN(objects);
return ret;
}
static void edbm_bisect_exit(bContext *C, BisectData *opdata)
{
View3D *v3d = CTX_wm_view3d(C);
- EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
- v3d->twtype = opdata->twtype;
+ v3d->gizmo_flag = opdata->gizmo_flag;
G.moving = 0;
+
+ for (int ob_index = 0; ob_index < opdata->backup_len; ob_index++) {
+ if (opdata->backup[ob_index].is_valid) {
+ EDBM_redo_state_free(&opdata->backup[ob_index].mesh, NULL, false);
+ }
+ }
+ MEM_freeN(opdata->backup);
}
static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -177,15 +208,25 @@ static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* update or clear modal callout */
if (event->type == EVT_MODAL_MAP) {
if (event->val == GESTURE_MODAL_BEGIN) {
- ED_area_headerprint(CTX_wm_area(C), IFACE_("LMB: Release to confirm cut line"));
+ ED_workspace_status_text(C, IFACE_("LMB: Release to confirm cut line"));
}
else {
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
}
}
if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
edbm_bisect_exit(C, &opdata_back);
+
+#ifdef USE_GIZMO
+ /* Setup gizmos */
+ {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d && (v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) {
+ WM_gizmo_group_type_ensure("MESH_GGT_bisect");
+ }
+ }
+#endif
}
return ret;
@@ -201,13 +242,10 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
/* both can be NULL, fallbacks values are used */
- View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm;
- BMOperator bmop;
+ int ret = OPERATOR_CANCELLED;
+
float plane_co[3];
float plane_no[3];
float imat[4][4];
@@ -225,7 +263,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co);
}
else {
- copy_v3_v3(plane_co, ED_view3d_cursor3d_get(scene, v3d));
+ copy_v3_v3(plane_co, scene->cursor.location);
RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co);
}
@@ -244,77 +282,107 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no);
}
-
+ wmGesture *gesture = op->customdata;
+ BisectData *opdata = (gesture != NULL) ? gesture->userdata : NULL;
/* -------------------------------------------------------------------- */
/* Modal support */
- /* Note: keep this isolated, exec can work wihout this */
- if ((op->customdata != NULL) &&
- mesh_bisect_interactive_calc(C, op, em, plane_co, plane_no))
- {
- /* write back to the props */
+ /* Note: keep this isolated, exec can work without this */
+ if (opdata != NULL) {
+ mesh_bisect_interactive_calc(C, op, plane_co, plane_no);
+ /* Write back to the props. */
RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no);
RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co);
}
/* End Modal */
/* -------------------------------------------------------------------- */
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(CTX_data_view_layer(C), CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- bm = em->bm;
-
- invert_m4_m4(imat, obedit->obmat);
- mul_m4_v3(imat, plane_co);
- mul_transposed_mat3_m4_v3(obedit->obmat, plane_no);
-
- EDBM_op_init(em, &bmop, op,
- "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b",
- BM_ELEM_SELECT, plane_co, plane_no, thresh, clear_inner, clear_outer);
- BMO_op_exec(bm, &bmop);
-
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-
- if (use_fill) {
- float normal_fill[3];
- BMOperator bmop_fill;
- BMOperator bmop_attr;
-
- normalize_v3_v3(normal_fill, plane_no);
- if (clear_outer == true && clear_inner == false) {
- negate_v3(normal_fill);
+ if (opdata != NULL) {
+ if (opdata->backup[ob_index].is_dirty) {
+ EDBM_redo_state_restore(opdata->backup[ob_index].mesh, em, false);
+ opdata->backup[ob_index].is_dirty = false;
+ }
}
- /* Fill */
- BMO_op_initf(
- bm, &bmop_fill, 0,
- "triangle_fill edges=%S normal=%v use_dissolve=%b",
- &bmop, "geom_cut.out", normal_fill, true);
- BMO_op_exec(bm, &bmop_fill);
-
- /* Copy Attributes */
- BMO_op_initf(bm, &bmop_attr, 0,
- "face_attribute_fill faces=%S use_normals=%b use_data=%b",
- &bmop_fill, "geom.out", false, true);
- BMO_op_exec(bm, &bmop_attr);
+ if (bm->totedgesel == 0) {
+ continue;
+ }
- BMO_slot_buffer_hflag_enable(bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
+ if (opdata != NULL) {
+ if (opdata->backup[ob_index].is_valid) {
+ opdata->backup[ob_index].is_dirty = true;
+ }
+ }
- BMO_op_finish(bm, &bmop_attr);
- BMO_op_finish(bm, &bmop_fill);
- }
+ float plane_co_local[3];
+ float plane_no_local[3];
+ copy_v3_v3(plane_co_local, plane_co);
+ copy_v3_v3(plane_no_local, plane_no);
+
+ invert_m4_m4(imat, obedit->obmat);
+ mul_m4_v3(imat, plane_co_local);
+ mul_transposed_mat3_m4_v3(obedit->obmat, plane_no_local);
+
+ BMOperator bmop;
+ EDBM_op_init(em, &bmop, op,
+ "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b",
+ BM_ELEM_SELECT, plane_co_local, plane_no_local, thresh, clear_inner, clear_outer);
+ BMO_op_exec(bm, &bmop);
+
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ if (use_fill) {
+ float normal_fill[3];
+ BMOperator bmop_fill;
+ BMOperator bmop_attr;
+
+ normalize_v3_v3(normal_fill, plane_no_local);
+ if (clear_outer == true && clear_inner == false) {
+ negate_v3(normal_fill);
+ }
+
+ /* Fill */
+ BMO_op_initf(
+ bm, &bmop_fill, 0,
+ "triangle_fill edges=%S normal=%v use_dissolve=%b",
+ &bmop, "geom_cut.out", normal_fill, true);
+ BMO_op_exec(bm, &bmop_fill);
+
+ /* Copy Attributes */
+ BMO_op_initf(bm, &bmop_attr, 0,
+ "face_attribute_fill faces=%S use_normals=%b use_data=%b",
+ &bmop_fill, "geom.out", false, true);
+ BMO_op_exec(bm, &bmop_attr);
+
+ BMO_slot_buffer_hflag_enable(bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
+
+ BMO_op_finish(bm, &bmop_attr);
+ BMO_op_finish(bm, &bmop_fill);
+ }
- BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
+ BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
- else {
- EDBM_update_generic(em, true, true);
- EDBM_selectmode_flush(em);
- return OPERATOR_FINISHED;
+ if (EDBM_op_finish(em, &bmop, op, true)) {
+ EDBM_update_generic(em, true, true);
+ EDBM_selectmode_flush(em);
+ ret = OPERATOR_FINISHED;
+ }
}
+ MEM_freeN(objects);
+ return ret;
}
+#ifdef USE_GIZMO
+static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt);
+#endif
void MESH_OT_bisect(struct wmOperatorType *ot)
{
@@ -351,4 +419,326 @@ void MESH_OT_bisect(struct wmOperatorType *ot)
"Preserves the existing geometry along the cut plane", 0.00001, 0.1);
WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+
+#ifdef USE_GIZMO
+ WM_gizmogrouptype_append(MESH_GGT_bisect);
+#endif
}
+
+
+#ifdef USE_GIZMO
+
+/* -------------------------------------------------------------------- */
+
+/** \name Bisect Gizmo
+ * \{ */
+
+typedef struct GizmoGroup {
+ /* Arrow to change plane depth. */
+ struct wmGizmo *translate_z;
+ /* Translate XYZ */
+ struct wmGizmo *translate_c;
+ /* For grabbing the gizmo and moving freely. */
+ struct wmGizmo *rotate_c;
+
+ /* We could store more vars here! */
+ struct {
+ bContext *context;
+ wmOperator *op;
+ PropertyRNA *prop_plane_co;
+ PropertyRNA *prop_plane_no;
+
+ float rotate_axis[3];
+ float rotate_up[3];
+ } data;
+} GizmoGroup;
+
+/**
+ * XXX. calling redo from property updates is not great.
+ * This is needed because changing the RNA doesn't cause a redo
+ * and we're not using operator UI which does just this.
+ */
+static void gizmo_bisect_exec(GizmoGroup *ggd)
+{
+ wmOperator *op = ggd->data.op;
+ if (op == WM_operator_last_redo((bContext *)ggd->data.context)) {
+ ED_undo_operator_repeat((bContext *)ggd->data.context, op);
+ }
+}
+
+static void gizmo_mesh_bisect_update_from_op(GizmoGroup *ggd)
+{
+ wmOperator *op = ggd->data.op;
+
+ float plane_co[3], plane_no[3];
+
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co);
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no);
+
+ WM_gizmo_set_matrix_location(ggd->translate_z, plane_co);
+ WM_gizmo_set_matrix_location(ggd->rotate_c, plane_co);
+ /* translate_c location comes from the property. */
+
+ WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_z, plane_no);
+
+ WM_gizmo_set_scale(ggd->translate_c, 0.2);
+
+ RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context);
+ if (rv3d) {
+ normalize_v3_v3(ggd->data.rotate_axis, rv3d->viewinv[2]);
+ normalize_v3_v3(ggd->data.rotate_up, rv3d->viewinv[1]);
+
+ /* ensure its orthogonal */
+ project_plane_normalized_v3_v3v3(ggd->data.rotate_up, ggd->data.rotate_up, ggd->data.rotate_axis);
+ normalize_v3(ggd->data.rotate_up);
+
+ WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, plane_no);
+
+ float plane_no_cross[3];
+ cross_v3_v3v3(plane_no_cross, plane_no, ggd->data.rotate_axis);
+
+ WM_gizmo_set_matrix_offset_rotation_from_yz_axis(ggd->rotate_c, plane_no_cross, ggd->data.rotate_axis);
+ RNA_enum_set(ggd->rotate_c->ptr, "draw_options",
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR |
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y);
+ }
+}
+
+/* depth callbacks */
+static void gizmo_bisect_prop_depth_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ GizmoGroup *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ float plane_co[3], plane_no[3];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co);
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no);
+
+ value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]);
+}
+
+static void gizmo_bisect_prop_depth_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ GizmoGroup *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ const float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ float plane_co[3], plane[4];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, plane_co);
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane);
+ normalize_v3(plane);
+
+ plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]);
+
+ /* Keep our location, may be offset simply to be inside the viewport. */
+ closest_to_plane_normalized_v3(plane_co, plane, plane_co);
+
+ RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_co, plane_co);
+
+ gizmo_bisect_exec(ggd);
+}
+
+/* translate callbacks */
+static void gizmo_bisect_prop_translate_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ GizmoGroup *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+
+ BLI_assert(gz_prop->type->array_length == 3);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_co, value_p);
+}
+
+static void gizmo_bisect_prop_translate_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ GizmoGroup *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+
+ BLI_assert(gz_prop->type->array_length == 3);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_co, value_p);
+
+ gizmo_bisect_exec(ggd);
+}
+
+/* angle callbacks */
+static void gizmo_bisect_prop_angle_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ GizmoGroup *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ float plane_no[4];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no);
+ normalize_v3(plane_no);
+
+ float plane_no_proj[3];
+ project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis);
+
+ if (!is_zero_v3(plane_no_proj)) {
+ const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis);
+ value[0] = angle;
+ }
+ else {
+ value[0] = 0.0f;
+ }
+}
+
+static void gizmo_bisect_prop_angle_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ GizmoGroup *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ const float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ float plane_no[4];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_plane_no, plane_no);
+ normalize_v3(plane_no);
+
+ float plane_no_proj[3];
+ project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, ggd->data.rotate_axis);
+
+ if (!is_zero_v3(plane_no_proj)) {
+ const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, ggd->data.rotate_up, ggd->data.rotate_axis);
+ const float angle_delta = angle - angle_compat_rad(value[0], angle);
+ if (angle_delta != 0.0f) {
+ float mat[3][3];
+ axis_angle_normalized_to_mat3(mat, ggd->data.rotate_axis, angle_delta);
+ mul_m3_v3(mat, plane_no);
+
+ /* re-normalize - seems acceptable */
+ RNA_property_float_set_array(op->ptr, ggd->data.prop_plane_no, plane_no);
+
+ gizmo_bisect_exec(ggd);
+ }
+ }
+}
+
+static bool gizmo_mesh_bisect_poll(const bContext *C, wmGizmoGroupType *gzgt)
+{
+ return ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_bisect");
+}
+
+static void gizmo_mesh_bisect_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmOperator *op = WM_operator_last_redo(C);
+
+ if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) {
+ return;
+ }
+
+ struct GizmoGroup *ggd = MEM_callocN(sizeof(GizmoGroup), __func__);
+ gzgroup->customdata = ggd;
+
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
+ const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
+ const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
+
+ ggd->translate_z = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->translate_c = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
+ ggd->rotate_c = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_z->color);
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->translate_c->color);
+ UI_GetThemeColor3fv(TH_GIZMO_SECONDARY, ggd->rotate_c->color);
+
+ RNA_enum_set(ggd->translate_z->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL);
+ RNA_enum_set(ggd->translate_c->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D);
+
+ WM_gizmo_set_flag(ggd->translate_c, WM_GIZMO_DRAW_VALUE, true);
+ WM_gizmo_set_flag(ggd->rotate_c, WM_GIZMO_DRAW_VALUE, true);
+
+ {
+ ggd->data.context = (bContext *)C;
+ ggd->data.op = op;
+ ggd->data.prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co");
+ ggd->data.prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no");
+ }
+
+ gizmo_mesh_bisect_update_from_op(ggd);
+
+ /* Setup property callbacks */
+ {
+ WM_gizmo_target_property_def_func(
+ ggd->translate_z, "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_bisect_prop_depth_get,
+ .value_set_fn = gizmo_bisect_prop_depth_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ WM_gizmo_target_property_def_func(
+ ggd->translate_c, "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_bisect_prop_translate_get,
+ .value_set_fn = gizmo_bisect_prop_translate_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ WM_gizmo_target_property_def_func(
+ ggd->rotate_c, "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_bisect_prop_angle_get,
+ .value_set_fn = gizmo_bisect_prop_angle_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+ }
+}
+
+static void gizmo_mesh_bisect_draw_prepare(
+ const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ GizmoGroup *ggd = gzgroup->customdata;
+ if (ggd->data.op->next) {
+ ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context);
+ }
+ gizmo_mesh_bisect_update_from_op(ggd);
+}
+
+static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Mesh Bisect";
+ gzgt->idname = "MESH_GGT_bisect";
+
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = gizmo_mesh_bisect_poll;
+ gzgt->setup = gizmo_mesh_bisect_setup;
+ gzgt->draw_prepare = gizmo_mesh_bisect_draw_prepare;
+}
+
+/** \} */
+
+#endif /* USE_GIZMO */
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 1e5e279ef35..fad8d39e665 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -35,6 +35,7 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BKE_layer.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
@@ -49,6 +50,8 @@
#include "ED_transform.h"
#include "ED_view3d.h"
+#include "MEM_guardedalloc.h"
+
#include "mesh_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -285,36 +288,44 @@ static bool edbm_extrude_ex(
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
-
const int steps = RNA_int_get(op->ptr, "steps");
-
const float offs = RNA_float_get(op->ptr, "offset");
float dvec[3], tmat[3][3], bmat[3][3];
short a;
- /* dvec */
- normalize_v3_v3_length(dvec, rv3d->persinv[2], offs);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* base correction */
- copy_m3_m4(bmat, obedit->obmat);
- invert_m3_m3(tmat, bmat);
- mul_m3_v3(tmat, dvec);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- for (a = 0; a < steps; a++) {
- edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false);
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMO_op_callf(
- em->bm, BMO_FLAG_DEFAULTS,
- "translate vec=%v verts=%hv",
- dvec, BM_ELEM_SELECT);
- }
+ /* dvec */
+ normalize_v3_v3_length(dvec, rv3d->persinv[2], offs);
+
+ /* base correction */
+ copy_m3_m4(bmat, obedit->obmat);
+ invert_m3_m3(tmat, bmat);
+ mul_m3_v3(tmat, dvec);
+
+ for (a = 0; a < steps; a++) {
+ edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false);
- EDBM_mesh_normals_update(em);
+ BMO_op_callf(
+ em->bm, BMO_FLAG_DEFAULTS,
+ "translate vec=%v verts=%hv",
+ dvec, BM_ELEM_SELECT);
+ }
+
+ EDBM_mesh_normals_update(em);
+
+ EDBM_update_generic(em, true, true);
+ }
- EDBM_update_generic(em, true, true);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -394,18 +405,28 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
/* extrude without transform */
static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- edbm_extrude_mesh(obedit, em, op);
-
- /* This normally happens when pushing undo but modal operators
- * like this one don't push undo data until after modal mode is
- * done.*/
- EDBM_mesh_normals_update(em);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
- EDBM_update_generic(em, true, true);
+ if (!edbm_extrude_mesh(obedit, em, op)) {
+ continue;
+ }
+ /* This normally happens when pushing undo but modal operators
+ * like this one don't push undo data until after modal mode is
+ * done.*/
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -431,17 +452,80 @@ void MESH_OT_extrude_region(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Extrude Context Operator
+ *
+ * Guess what to do based on selection.
+ * \{ */
+
+/* extrude without transform */
+static int edbm_extrude_context_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+
+ edbm_extrude_mesh(obedit, em, op);
+ /* This normally happens when pushing undo but modal operators
+ * like this one don't push undo data until after modal mode is
+ * done.*/
+
+ EDBM_mesh_normals_update(em);
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_context(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Extrude Context";
+ ot->idname = "MESH_OT_extrude_context";
+ ot->description = "Extrude selection";
+
+ /* api callbacks */
+ ot->exec = edbm_extrude_context_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
+ Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Extrude Verts Operator
* \{ */
static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
- edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
+ edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -472,13 +556,23 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
- edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip);
+ edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, use_normal_flip);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -510,12 +604,22 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT);
+ edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -552,161 +656,206 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
BMIter iter;
float center[3];
uint verts_len;
- bool use_proj;
em_setup_viewcontext(C, &vc);
+ const Object *object_active = vc.obact;
- invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
-
- ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
-
- use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
- (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
+ const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source");
+ const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
+ (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
+ /* First calculate the center of transformation. */
zero_v3(center);
verts_len = 0;
- BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) {
- add_v3_v3(center, v1->co);
- verts_len += 1;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ED_view3d_viewcontext_init_object(&vc, obedit);
+ const int local_verts_len = vc.em->bm->totvertsel;
+
+ if (vc.em->bm->totvertsel == 0) {
+ continue;
+ }
+
+ float local_center[3];
+ zero_v3(local_center);
+
+ BM_ITER_MESH(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) {
+ add_v3_v3(local_center, v1->co);
+ }
}
+
+ mul_v3_fl(local_center, 1.0f / (float)local_verts_len);
+ mul_m4_v3(vc.obedit->obmat, local_center);
+ mul_v3_fl(local_center, (float)local_verts_len);
+
+ add_v3_v3(center, local_center);
+ verts_len += local_verts_len;
}
- /* call extrude? */
if (verts_len != 0) {
- const char extrude_htype = edbm_extrude_htype_from_em_select(vc.em);
- const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source");
- BMEdge *eed;
- float mat[3][3];
- float vec[3], ofs[3];
- float nor[3] = {0.0, 0.0, 0.0};
+ mul_v3_fl(center, 1.0f / (float)verts_len);
+ }
- /* 2D normal calc */
- const float mval_f[2] = {(float)event->mval[0],
- (float)event->mval[1]};
+ /* Then we process the meshes. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ED_view3d_viewcontext_init_object(&vc, obedit);
- mul_v3_fl(center, 1.0f / (float)verts_len);
+ if (verts_len != 0) {
+ if (vc.em->bm->totvertsel == 0) {
+ continue;
+ }
+ }
+ else if (obedit != object_active) {
+ continue;
+ }
- /* check for edges that are half selected, use for rotation */
- bool done = false;
- BM_ITER_MESH (eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- float co1[2], co2[2];
-
- if ((ED_view3d_project_float_object(vc.ar, eed->v1->co, co1, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
- (ED_view3d_project_float_object(vc.ar, eed->v2->co, co2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
- {
- /* 2D rotate by 90d while adding.
- * (x, y) = (y, -x)
- *
- * accumulate the screenspace normal in 2D,
- * with screenspace edge length weighting the result. */
- if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
- nor[0] += (co1[1] - co2[1]);
- nor[1] += -(co1[0] - co2[0]);
- }
- else {
- nor[0] += (co2[1] - co1[1]);
- nor[1] += -(co2[0] - co1[0]);
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ float local_center[3];
+ mul_v3_m4v3(local_center, vc.obedit->imat, center);
+
+ /* call extrude? */
+ if (verts_len != 0) {
+ const char extrude_htype = edbm_extrude_htype_from_em_select(vc.em);
+ BMEdge *eed;
+ float mat[3][3];
+ float vec[3], ofs[3];
+ float nor[3] = { 0.0, 0.0, 0.0 };
+
+ /* 2D normal calc */
+ const float mval_f[2] = { (float)event->mval[0],
+ (float)event->mval[1] };
+
+ /* check for edges that are half selected, use for rotation */
+ bool done = false;
+ BM_ITER_MESH(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ float co1[2], co2[2];
+
+ if ((ED_view3d_project_float_object(vc.ar, eed->v1->co, co1, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
+ (ED_view3d_project_float_object(vc.ar, eed->v2->co, co2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
+ {
+ /* 2D rotate by 90d while adding.
+ * (x, y) = (y, -x)
+ *
+ * accumulate the screenspace normal in 2D,
+ * with screenspace edge length weighting the result. */
+ if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
+ nor[0] += (co1[1] - co2[1]);
+ nor[1] += -(co1[0] - co2[0]);
+ }
+ else {
+ nor[0] += (co2[1] - co1[1]);
+ nor[1] += -(co2[0] - co1[0]);
+ }
+ done = true;
}
- done = true;
}
}
- }
- if (done) {
- float view_vec[3], cross[3];
+ if (done) {
+ float view_vec[3], cross[3];
- /* convert the 2D nomal into 3D */
- mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
- mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
+ /* convert the 2D normal into 3D */
+ mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
+ mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
- /* correct the normal to be aligned on the view plane */
- mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]);
- cross_v3_v3v3(cross, nor, view_vec);
- cross_v3_v3v3(nor, view_vec, cross);
- normalize_v3(nor);
- }
+ /* correct the normal to be aligned on the view plane */
+ mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]);
+ cross_v3_v3v3(cross, nor, view_vec);
+ cross_v3_v3v3(nor, view_vec, cross);
+ normalize_v3(nor);
+ }
- /* center */
- copy_v3_v3(ofs, center);
+ /* center */
+ copy_v3_v3(ofs, local_center);
- mul_m4_v3(vc.obedit->obmat, ofs); /* view space */
- ED_view3d_win_to_3d_int(vc.v3d, vc.ar, ofs, event->mval, ofs);
- mul_m4_v3(vc.obedit->imat, ofs); // back in object space
+ mul_m4_v3(vc.obedit->obmat, ofs); /* view space */
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, ofs, event->mval, ofs);
+ mul_m4_v3(vc.obedit->imat, ofs); // back in object space
- sub_v3_v3(ofs, center);
+ sub_v3_v3(ofs, local_center);
- /* calculate rotation */
- unit_m3(mat);
- if (done) {
- float angle;
+ /* calculate rotation */
+ unit_m3(mat);
+ if (done) {
+ float angle;
- normalize_v3_v3(vec, ofs);
+ normalize_v3_v3(vec, ofs);
- angle = angle_normalized_v3v3(vec, nor);
+ angle = angle_normalized_v3v3(vec, nor);
- if (angle != 0.0f) {
- float axis[3];
+ if (angle != 0.0f) {
+ float axis[3];
- cross_v3_v3v3(axis, nor, vec);
+ cross_v3_v3v3(axis, nor, vec);
- /* halve the rotation if its applied twice */
- if (rot_src) {
- angle *= 0.5f;
+ /* halve the rotation if its applied twice */
+ if (rot_src) {
+ angle *= 0.5f;
+ }
+
+ axis_angle_to_mat3(mat, axis, angle);
}
+ }
- axis_angle_to_mat3(mat, axis, angle);
+ if (rot_src) {
+ EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
+ BM_ELEM_SELECT, local_center, mat);
+
+ /* also project the source, for retopo workflow */
+ if (use_proj) {
+ EDBM_project_snap_verts(C, vc.ar, vc.em);
+ }
}
- }
- if (rot_src) {
+ edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, true, true);
EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
- BM_ELEM_SELECT, center, mat);
-
- /* also project the source, for retopo workflow */
- if (use_proj)
- EDBM_project_snap_verts(C, vc.ar, vc.em);
+ BM_ELEM_SELECT, local_center, mat);
+ EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v",
+ BM_ELEM_SELECT, ofs);
}
+ else {
+ /* This only runs for the active object. */
+ const float *cursor = vc.scene->cursor.location;
+ BMOperator bmop;
+ BMOIter oiter;
- edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, true, true);
- EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
- BM_ELEM_SELECT, center, mat);
- EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v",
- BM_ELEM_SELECT, ofs);
- }
- else {
- const float *cursor = ED_view3d_cursor3d_get(vc.scene, vc.v3d);
- BMOperator bmop;
- BMOIter oiter;
+ copy_v3_v3(local_center, cursor);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, local_center, event->mval, local_center);
- copy_v3_v3(center, cursor);
- ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
+ mul_m4_v3(vc.obedit->imat, local_center); // back in object space
- mul_m4_v3(vc.obedit->imat, center); // back in object space
+ EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", local_center);
+ BMO_op_exec(vc.em->bm, &bmop);
- EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", center);
- BMO_op_exec(vc.em->bm, &bmop);
+ BMO_ITER(v1, &oiter, bmop.slots_out, "vert.out", BM_VERT) {
+ BM_vert_select_set(vc.em->bm, v1, true);
+ }
- BMO_ITER (v1, &oiter, bmop.slots_out, "vert.out", BM_VERT) {
- BM_vert_select_set(vc.em->bm, v1, true);
+ if (!EDBM_op_finish(vc.em, &bmop, op, true)) {
+ continue;
+ }
}
- if (!EDBM_op_finish(vc.em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ if (use_proj) {
+ EDBM_project_snap_verts(C, vc.ar, vc.em);
}
- }
- if (use_proj)
- EDBM_project_snap_verts(C, vc.ar, vc.em);
+ /* This normally happens when pushing undo but modal operators
+ * like this one don't push undo data until after modal mode is
+ * done. */
+ EDBM_mesh_normals_update(vc.em);
- /* This normally happens when pushing undo but modal operators
- * like this one don't push undo data until after modal mode is
- * done. */
- EDBM_mesh_normals_update(vc.em);
-
- EDBM_update_generic(vc.em, true, true);
+ EDBM_update_generic(vc.em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_extrude_screw.c b/source/blender/editors/mesh/editmesh_extrude_screw.c
index de9f714dfe8..589e3987050 100644
--- a/source/blender/editors/mesh/editmesh_extrude_screw.c
+++ b/source/blender/editors/mesh/editmesh_extrude_screw.c
@@ -29,13 +29,16 @@
* \ingroup edmesh
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_object_types.h"
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_report.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_report.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -46,6 +49,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+
+
#include "mesh_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -54,84 +59,110 @@
static int edbm_screw_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
BMEdge *eed;
BMVert *eve, *v1, *v2;
BMIter iter, eiter;
- BMOperator spinop;
float dvec[3], nor[3], cent[3], axis[3], v1_co_global[3], v2_co_global[3];
int steps, turns;
int valence;
-
+ uint objects_empty_len = 0;
+ uint failed_axis_len = 0;
+ uint failed_vertices_len = 0;
turns = RNA_int_get(op->ptr, "turns");
steps = RNA_int_get(op->ptr, "steps");
RNA_float_get_array(op->ptr, "center", cent);
RNA_float_get_array(op->ptr, "axis", axis);
- if (is_zero_v3(axis)) {
- BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis");
- return OPERATOR_CANCELLED;
- }
+ uint objects_len = 0;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* find two vertices with valence count == 1, more or less is wrong */
- v1 = NULL;
- v2 = NULL;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- valence = 0;
- BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- valence++;
+ if (bm->totvertsel < 2) {
+ if (bm->totvertsel == 0) {
+ objects_empty_len++;
}
+ continue;
}
- if (valence == 1) {
- if (v1 == NULL) {
- v1 = eve;
- }
- else if (v2 == NULL) {
- v2 = eve;
+ if (is_zero_v3(axis)) {
+ failed_axis_len++;
+ continue;
+ }
+
+ /* find two vertices with valence count == 1, more or less is wrong */
+ v1 = NULL;
+ v2 = NULL;
+
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ valence = 0;
+ BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ valence++;
+ }
}
- else {
- v1 = NULL;
- break;
+
+ if (valence == 1) {
+ if (v1 == NULL) {
+ v1 = eve;
+ }
+ else if (v2 == NULL) {
+ v2 = eve;
+ }
+ else {
+ v1 = NULL;
+ break;
+ }
}
}
- }
- if (v1 == NULL || v2 == NULL) {
- BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too");
- return OPERATOR_CANCELLED;
- }
+ if (v1 == NULL || v2 == NULL) {
+ failed_vertices_len++;
+ continue;
+ }
- copy_v3_v3(nor, obedit->obmat[2]);
+ copy_v3_v3(nor, obedit->obmat[2]);
- /* calculate dvec */
- mul_v3_m4v3(v1_co_global, obedit->obmat, v1->co);
- mul_v3_m4v3(v2_co_global, obedit->obmat, v2->co);
- sub_v3_v3v3(dvec, v1_co_global, v2_co_global);
- mul_v3_fl(dvec, 1.0f / steps);
+ /* calculate dvec */
+ mul_v3_m4v3(v1_co_global, obedit->obmat, v1->co);
+ mul_v3_m4v3(v2_co_global, obedit->obmat, v2->co);
+ sub_v3_v3v3(dvec, v1_co_global, v2_co_global);
+ mul_v3_fl(dvec, 1.0f / steps);
- if (dot_v3v3(nor, dvec) > 0.0f)
- negate_v3(dvec);
+ if (dot_v3v3(nor, dvec) > 0.0f)
+ negate_v3(dvec);
- if (!EDBM_op_init(em, &spinop, op,
- "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 use_duplicate=%b",
- BM_ELEM_SELECT, cent, axis, dvec, turns * steps, DEG2RADF(360.0f * turns), obedit->obmat, false))
- {
- return OPERATOR_CANCELLED;
- }
- BMO_op_exec(bm, &spinop);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
- if (!EDBM_op_finish(em, &spinop, op, true)) {
- return OPERATOR_CANCELLED;
+ BMOperator spinop;
+ if (!EDBM_op_init(em, &spinop, op,
+ "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 use_duplicate=%b",
+ BM_ELEM_SELECT, cent, axis, dvec, turns * steps, DEG2RADF(360.0f * turns), obedit->obmat, false))
+ {
+ continue;
+ }
+
+ BMO_op_exec(bm, &spinop);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &spinop, op, true)) {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
}
+ MEM_freeN(objects);
- EDBM_update_generic(em, true, true);
+ if (failed_axis_len == objects_len - objects_empty_len) {
+ BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis");
+ }
+ else if (failed_vertices_len == objects_len - objects_empty_len) {
+ BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too");
+ }
return OPERATOR_FINISHED;
}
@@ -140,13 +171,12 @@ static int edbm_screw_exec(bContext *C, wmOperator *op)
static int edbm_screw_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
PropertyRNA *prop;
prop = RNA_struct_find_property(op->ptr, "center");
if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_float_set_array(op->ptr, prop, ED_view3d_cursor3d_get(scene, v3d));
+ RNA_property_float_set_array(op->ptr, prop, scene->cursor.location);
}
if (rv3d) {
prop = RNA_struct_find_property(op->ptr, "axis");
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index a9e78f74012..e9758cb1a5a 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -36,18 +36,26 @@
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "RNA_define.h"
#include "RNA_access.h"
+#include "RNA_enum_types.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
#include "mesh_intern.h" /* own include */
+#define USE_GIZMO
/* -------------------------------------------------------------------- */
/** \name Spin Operator
@@ -55,10 +63,7 @@
static int edbm_spin_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMOperator spinop;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
float cent[3], axis[3];
float d[3] = {0.0f, 0.0f, 0.0f};
@@ -72,33 +77,45 @@ static int edbm_spin_exec(bContext *C, wmOperator *op)
RNA_boolean_get(op->ptr, "use_auto_merge") &&
(dupli == false) &&
(steps >= 3) &&
- fabsf((fabsf(angle) - (M_PI * 2))) <= 1e-6f);
+ fabsf((fabsf(angle) - (float)(M_PI * 2))) <= 1e-6f);
if (is_zero_v3(axis)) {
BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis");
return OPERATOR_CANCELLED;
}
- /* keep the values in worldspace since we're passing the obmat */
- if (!EDBM_op_init(
- em, &spinop, op,
- "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 "
- "use_normal_flip=%b use_duplicate=%b use_merge=%b",
- BM_ELEM_SELECT, cent, axis, d, steps, -angle, obedit->obmat,
- use_normal_flip, dupli, use_auto_merge))
- {
- return OPERATOR_CANCELLED;
- }
- BMO_op_exec(bm, &spinop);
- if (use_auto_merge == false) {
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
- }
- if (!EDBM_op_finish(em, &spinop, op, true)) {
- return OPERATOR_CANCELLED;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMOperator spinop;
+
+ /* keep the values in worldspace since we're passing the obmat */
+ if (!EDBM_op_init(
+ em, &spinop, op,
+ "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 "
+ "use_normal_flip=%b use_duplicate=%b use_merge=%b",
+ BM_ELEM_SELECT, cent, axis, d, steps, -angle, obedit->obmat,
+ use_normal_flip, dupli, use_auto_merge))
+ {
+ continue;
+ }
+ BMO_op_exec(bm, &spinop);
+ if (use_auto_merge == false) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
+ }
+ if (!EDBM_op_finish(em, &spinop, op, true)) {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
}
- EDBM_update_generic(em, true, true);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -113,7 +130,7 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
PropertyRNA *prop;
prop = RNA_struct_find_property(op->ptr, "center");
if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_float_set_array(op->ptr, prop, ED_view3d_cursor3d_get(scene, v3d));
+ RNA_property_float_set_array(op->ptr, prop, scene->cursor.location);
}
if (rv3d) {
prop = RNA_struct_find_property(op->ptr, "axis");
@@ -122,7 +139,31 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
}
}
- return edbm_spin_exec(C, op);
+
+#ifdef USE_GIZMO
+ /* Start with zero angle, drag out the value. */
+ prop = RNA_struct_find_property(op->ptr, "angle");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set(op->ptr, prop, 0.0f);
+ }
+#endif
+
+ int ret = edbm_spin_exec(C, op);
+
+#ifdef USE_GIZMO
+ if (ret & OPERATOR_FINISHED) {
+ /* Setup gizmos */
+ if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) {
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find("MESH_GGT_spin_redo", false);
+ if (!WM_gizmo_group_type_ensure_ptr(gzgt)) {
+ struct Main *bmain = CTX_data_main(C);
+ WM_gizmo_group_type_reinit_ptr(bmain, gzgt);
+ }
+ }
+ }
+#endif
+
+ return ret;
}
static bool edbm_spin_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop)
@@ -171,6 +212,10 @@ void MESH_OT_spin(wmOperatorType *ot)
"Center", "Center in global view space", -1e4f, 1e4f);
RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
+ WM_gizmogrouptype_append(MESH_GGT_spin);
+#ifdef USE_GIZMO
+ WM_gizmogrouptype_append(MESH_GGT_spin_redo);
+#endif
}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
new file mode 100644
index 00000000000..92b655b6d8d
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
@@ -0,0 +1,1079 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_extrude_spin_gizmo.c
+ * \ingroup edmesh
+ */
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+
+#include "ED_gizmo_utils.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "mesh_intern.h" /* own include */
+
+#include "ED_transform.h"
+
+#include "ED_gizmo_library.h"
+#include "ED_undo.h"
+
+/**
+ * Orient the handles towards the selection (can be slow with high-poly mesh!).
+ */
+// Disable for now, issues w/ refresh and '+' icons overlap.
+// #define USE_SELECT_CENTER
+
+#ifdef USE_SELECT_CENTER
+# include "BKE_editmesh.h"
+#endif
+
+static const float dial_angle_partial = M_PI / 2;
+static const float dial_angle_partial_margin = 0.92f;
+
+#define ORTHO_AXIS_OFFSET 2
+
+/* -------------------------------------------------------------------- */
+/** \name Spin Tool Gizmo
+ * \{ */
+
+typedef struct GizmoGroupData_SpinInit {
+ struct {
+ wmGizmo *xyz_view[4];
+ wmGizmo *icon_button[3][2];
+ } gizmos;
+
+ /* Only for view orientation. */
+ struct {
+ float viewinv_m3[3][3];
+ } prev;
+
+ /* We could store more vars here! */
+ struct {
+ wmOperatorType *ot_spin;
+ PropertyRNA *gzgt_axis_prop;
+ float orient_mat[3][3];
+#ifdef USE_SELECT_CENTER
+ float select_center[3];
+ float select_center_ortho_axis[3][3];
+ bool use_select_center;
+#endif
+ } data;
+
+ /* Store data for invoke. */
+ struct {
+ int ortho_axis_active;
+ } invoke;
+
+} GizmoGroupData_SpinInit;
+
+/* Use dials only as a visualization when hovering over the icons. */
+#define USE_DIAL_HOVER
+
+#define INIT_SCALE_BASE 2.3f
+#define INIT_SCALE_BUTTON 0.15f
+
+static const uchar shape_plus[] = {
+ 0x5f, 0xfb, 0x40, 0xee, 0x25, 0xda, 0x11, 0xbf, 0x4, 0xa0, 0x0, 0x80, 0x4, 0x5f, 0x11,
+ 0x40, 0x25, 0x25, 0x40, 0x11, 0x5f, 0x4, 0x7f, 0x0, 0xa0, 0x4, 0xbf, 0x11, 0xda, 0x25,
+ 0xee, 0x40, 0xfb, 0x5f, 0xff, 0x7f, 0xfb, 0xa0, 0xee, 0xbf, 0xda, 0xda, 0xbf, 0xee,
+ 0xa0, 0xfb, 0x80, 0xff, 0x6e, 0xd7, 0x92, 0xd7, 0x92, 0x90, 0xd8, 0x90, 0xd8, 0x6d,
+ 0x92, 0x6d, 0x92, 0x27, 0x6e, 0x27, 0x6e, 0x6d, 0x28, 0x6d, 0x28, 0x90, 0x6e,
+ 0x90, 0x6e, 0xd7, 0x80, 0xff, 0x5f, 0xfb, 0x5f, 0xfb,
+};
+
+static void gizmo_mesh_spin_init_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ /* alpha values for normal/highlighted states */
+ const float alpha = 0.6f;
+ const float alpha_hi = 1.0f;
+ const float scale_base = INIT_SCALE_BASE;
+ const float scale_button = INIT_SCALE_BUTTON;
+
+ GizmoGroupData_SpinInit *ggd = MEM_callocN(sizeof(*ggd), __func__);
+ gzgroup->customdata = ggd;
+ const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
+ const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 2; j++) {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "shape");
+ RNA_property_string_set_bytes(
+ gz->ptr, prop,
+ (const char *)shape_plus, ARRAY_SIZE(shape_plus));
+
+ float color[4];
+ UI_GetThemeColor3fv(TH_AXIS_X + i, color);
+ color[3] = alpha;
+ WM_gizmo_set_color(gz, color);
+
+ WM_gizmo_set_scale(gz, scale_button);
+ gz->color[3] = 0.6f;
+
+ gz->flag |= WM_GIZMO_DRAW_OFFSET_SCALE;
+
+ ggd->gizmos.icon_button[i][j] = gz;
+ }
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.xyz_view); i++) {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE | WM_GIZMO_HIDDEN_SELECT, true);
+ ggd->gizmos.xyz_view[i] = gz;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ wmGizmo *gz = ggd->gizmos.xyz_view[i];
+#ifndef USE_DIAL_HOVER
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
+#endif
+ WM_gizmo_set_line_width(gz, 2.0f);
+ float color[4];
+ UI_GetThemeColor3fv(TH_AXIS_X + i, color);
+ color[3] = alpha;
+ WM_gizmo_set_color(gz, color);
+ color[3] = alpha_hi;
+ WM_gizmo_set_color_highlight(gz, color);
+ WM_gizmo_set_scale(gz, INIT_SCALE_BASE);
+ RNA_float_set(gz->ptr, "arc_partial_angle", (M_PI * 2) - (dial_angle_partial * dial_angle_partial_margin));
+ }
+
+ {
+ wmGizmo *gz = ggd->gizmos.xyz_view[3];
+ WM_gizmo_set_line_width(gz, 2.0f);
+ float color[4];
+ copy_v3_fl(color, 1.0f);
+ color[3] = alpha;
+ WM_gizmo_set_color(gz, color);
+ color[3] = alpha_hi;
+ WM_gizmo_set_color_highlight(gz, color);
+ WM_gizmo_set_scale(gz, scale_base);
+ }
+
+
+#ifdef USE_DIAL_HOVER
+ for (int i = 0; i < 4; i++) {
+ wmGizmo *gz = ggd->gizmos.xyz_view[i];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
+#endif
+
+ ggd->data.ot_spin = WM_operatortype_find("MESH_OT_spin", true);
+ ggd->data.gzgt_axis_prop = RNA_struct_type_find_property(gzgroup->type->srna, "axis");
+}
+
+static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgroup);
+
+static void gizmo_mesh_spin_init_refresh_axis_orientation(
+ wmGizmoGroup *gzgroup,
+ int axis_index, const float axis_vec[3], const float axis_tan[3])
+{
+ GizmoGroupData_SpinInit *ggd = gzgroup->customdata;
+ wmGizmo *gz = ggd->gizmos.xyz_view[axis_index];
+ if (axis_tan != NULL) {
+ WM_gizmo_set_matrix_rotation_from_yz_axis(gz, axis_tan, axis_vec);
+ }
+ else {
+ WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis_vec);
+ }
+
+ /* Only for display, use icons to access. */
+#ifndef USE_DIAL_HOVER
+ {
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ggd->data.ot_spin, NULL);
+ RNA_float_set_array(ptr, "axis", axis_vec);
+ }
+#endif
+ if (axis_index < 3) {
+ for (int j = 0; j < 2; j++) {
+ gz = ggd->gizmos.icon_button[axis_index][j];
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ggd->data.ot_spin, NULL);
+ float axis_vec_flip[3];
+ if (0 == j) {
+ negate_v3_v3(axis_vec_flip, axis_vec);
+ }
+ else {
+ copy_v3_v3(axis_vec_flip, axis_vec);
+ }
+ RNA_float_set_array(ptr, "axis", axis_vec_flip);
+ }
+ }
+}
+
+static void gizmo_mesh_spin_init_draw_prepare(
+ const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroupData_SpinInit *ggd = gzgroup->customdata;
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ float viewinv_m3[3][3];
+ copy_m3_m4(viewinv_m3, rv3d->viewinv);
+
+ {
+ Scene *scene = CTX_data_scene(C);
+ switch (scene->orientation_type) {
+ case V3D_MANIP_VIEW:
+ {
+ if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) {
+ /* Take care calling refresh from draw_prepare,
+ * this should be OK because it's only adjusting the cage orientation. */
+ gizmo_mesh_spin_init_refresh(C, gzgroup);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Refresh handled above when using view orientation. */
+ if (!equals_m3m3(viewinv_m3, ggd->prev.viewinv_m3)) {
+ gizmo_mesh_spin_init_refresh_axis_orientation(gzgroup, 3, rv3d->viewinv[2], NULL);
+ copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv);
+ }
+
+ /* Hack! highlight XYZ dials based on buttons */
+#ifdef USE_DIAL_HOVER
+ {
+ PointerRNA ptr;
+ bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C);
+ WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &ptr);
+ const int axis_flag = RNA_property_enum_get(&ptr, ggd->data.gzgt_axis_prop);
+ for (int i = 0; i < 4; i++) {
+ bool hide = (axis_flag & (1 << i)) == 0;
+ wmGizmo *gz = ggd->gizmos.xyz_view[i];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, hide);
+ if (!hide) {
+ RNA_float_set(gz->ptr, "arc_partial_angle", (M_PI * 2) - (dial_angle_partial * dial_angle_partial_margin));
+ }
+ }
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 2; j++) {
+ wmGizmo *gz = ggd->gizmos.icon_button[i][j];
+ if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
+ WM_gizmo_set_flag(ggd->gizmos.xyz_view[i], WM_GIZMO_HIDDEN, false);
+ RNA_float_set(ggd->gizmos.xyz_view[i]->ptr, "arc_partial_angle", 0.0f);
+ i = 3;
+ break;
+ }
+ }
+ }
+ }
+#endif
+
+}
+
+static void gizmo_mesh_spin_init_invoke_prepare(
+ const bContext *UNUSED(C), wmGizmoGroup *gzgroup, wmGizmo *gz)
+{
+ /* Set the initial ortho axis. */
+ GizmoGroupData_SpinInit *ggd = gzgroup->customdata;
+ ggd->invoke.ortho_axis_active = -1;
+ for (int i = 0; i < 3; i++) {
+ if (ELEM(gz, UNPACK2(ggd->gizmos.icon_button[i]))) {
+ ggd->invoke.ortho_axis_active = i;
+ break;
+ }
+ }
+}
+
+static void gizmo_mesh_spin_init_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroupData_SpinInit *ggd = gzgroup->customdata;
+ RegionView3D *rv3d = ED_view3d_context_rv3d((bContext *)C);
+ const float *gizmo_center = NULL;
+ {
+ Scene *scene = CTX_data_scene(C);
+ const View3DCursor *cursor = &scene->cursor;
+ gizmo_center = cursor->location;
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.xyz_view); i++) {
+ wmGizmo *gz = ggd->gizmos.xyz_view[i];
+ WM_gizmo_set_matrix_location(gz, gizmo_center);
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) {
+ for (int j = 0; j < 2; j++) {
+ wmGizmo *gz = ggd->gizmos.icon_button[i][j];
+ WM_gizmo_set_matrix_location(gz, gizmo_center);
+ }
+ }
+
+ ED_transform_calc_orientation_from_type(C, ggd->data.orient_mat);
+ for (int i = 0; i < 3; i++) {
+ const int axis_ortho = (i + ORTHO_AXIS_OFFSET) % 3;
+ const float *axis_ortho_vec = ggd->data.orient_mat[axis_ortho];
+#ifdef USE_SELECT_CENTER
+ if (ggd->data.use_select_center) {
+ float delta[3];
+ sub_v3_v3v3(delta, ggd->data.select_center, gizmo_center);
+ project_plane_normalized_v3_v3v3(ggd->data.select_center_ortho_axis[i], delta, ggd->data.orient_mat[i]);
+ if (normalize_v3(ggd->data.select_center_ortho_axis[i]) != 0.0f) {
+ axis_ortho_vec = ggd->data.select_center_ortho_axis[i];
+ }
+ }
+#endif
+ gizmo_mesh_spin_init_refresh_axis_orientation(
+ gzgroup, i, ggd->data.orient_mat[i], axis_ortho_vec);
+ }
+
+ {
+ gizmo_mesh_spin_init_refresh_axis_orientation(
+ gzgroup, 3, rv3d->viewinv[2], NULL);
+ }
+
+
+#ifdef USE_SELECT_CENTER
+ {
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ float select_center[3] = {0};
+ int totsel = 0;
+
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
+
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ totsel++;
+ add_v3_v3(select_center, eve->co);
+ }
+ }
+ }
+ if (totsel) {
+ mul_v3_fl(select_center, 1.0f / totsel);
+ mul_m4_v3(obedit->obmat, select_center);
+ copy_v3_v3(ggd->data.select_center, select_center);
+ ggd->data.use_select_center = true;
+ }
+ else {
+ ggd->data.use_select_center = false;
+ }
+ }
+#endif
+
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) {
+ const int axis_ortho = (i + ORTHO_AXIS_OFFSET) % 3;
+ const float *axis_ortho_vec = ggd->data.orient_mat[axis_ortho];
+ float offset = INIT_SCALE_BASE / INIT_SCALE_BUTTON;
+ float offset_vec[3];
+
+#ifdef USE_SELECT_CENTER
+ if (ggd->data.use_select_center && !is_zero_v3(ggd->data.select_center_ortho_axis[i])) {
+ axis_ortho_vec = ggd->data.select_center_ortho_axis[i];
+ }
+#endif
+
+ mul_v3_v3fl(offset_vec, axis_ortho_vec, offset);
+ for (int j = 0; j < 2; j++) {
+ wmGizmo *gz = ggd->gizmos.icon_button[i][j];
+ float mat3[3][3];
+ axis_angle_to_mat3(mat3, ggd->data.orient_mat[i], dial_angle_partial * (j ? -0.5f : 0.5f));
+ mul_v3_m3v3(gz->matrix_offset[3], mat3, offset_vec);
+ }
+ }
+
+ {
+ PointerRNA ptr;
+ bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C);
+ WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &ptr);
+ const int axis_flag = RNA_property_enum_get(&ptr, ggd->data.gzgt_axis_prop);
+ for (int i = 0; i < ARRAY_SIZE(ggd->gizmos.icon_button); i++) {
+ for (int j = 0; j < 2; j++) {
+ wmGizmo *gz = ggd->gizmos.icon_button[i][j];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, (axis_flag & (1 << i)) == 0);
+ }
+ }
+ }
+
+ /* Needed to test view orientation changes. */
+ copy_m3_m4(ggd->prev.viewinv_m3, rv3d->viewinv);
+}
+
+
+static void gizmo_mesh_spin_init_message_subscribe(
+ const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus)
+{
+ GizmoGroupData_SpinInit *ggd = gzgroup->customdata;
+ Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ /* Subscribe to view properties */
+ wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
+ .owner = ar,
+ .user_data = gzgroup->parent_gzmap,
+ .notify = WM_gizmo_do_msg_notify_tag_refresh,
+ };
+
+ PointerRNA scene_ptr;
+ RNA_id_pointer_create(&scene->id, &scene_ptr);
+
+ {
+ extern PropertyRNA rna_Scene_transform_orientation;
+ extern PropertyRNA rna_Scene_cursor_location;
+ const PropertyRNA *props[] = {
+ &rna_Scene_transform_orientation,
+ &rna_Scene_cursor_location,
+ };
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &scene_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
+ }
+ }
+
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &(const wmMsgParams_RNA){
+ .ptr = (PointerRNA){.type = gzgroup->type->srna},
+ .prop = ggd->data.gzgt_axis_prop,
+ },
+ &msg_sub_value_gz_tag_refresh, __func__);
+
+}
+
+void MESH_GGT_spin(struct wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Mesh Spin Init";
+ gzgt->idname = "MESH_GGT_spin";
+
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
+ gzgt->setup = gizmo_mesh_spin_init_setup;
+ gzgt->refresh = gizmo_mesh_spin_init_refresh;
+ gzgt->message_subscribe = gizmo_mesh_spin_init_message_subscribe;
+ gzgt->draw_prepare = gizmo_mesh_spin_init_draw_prepare;
+ gzgt->invoke_prepare = gizmo_mesh_spin_init_invoke_prepare;
+
+ RNA_def_enum_flag(gzgt->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 2), "Axis", "");
+}
+
+#undef INIT_SCALE_BASE
+#undef INIT_SCALE_BUTTON
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Spin Redo Gizmo
+ * \{ */
+
+/**
+ * Orient the dial so the 'arc' starts where the mouse cursor is,
+ * this is simply to keep the gizmo displaying where the cursor starts.
+ * It's not needed for practical functionality.
+ */
+#define USE_ANGLE_Z_ORIENT
+
+typedef struct GizmoGroupData_SpinRedo {
+ /* Translate XYZ. */
+ struct wmGizmo *translate_c;
+ /* Spin angle */
+ struct wmGizmo *angle_z;
+
+ /* Translate XY constrained ('orient_mat'). */
+ struct wmGizmo *translate_xy[2];
+ /* Rotate XY constrained ('orient_mat'). */
+ struct wmGizmo *rotate_xy[2];
+
+ /* Rotate on view axis. */
+ struct wmGizmo *rotate_view;
+
+ struct {
+ float plane_co[3];
+ float plane_no[3];
+ } prev;
+
+ bool is_init;
+
+ /* We could store more vars here! */
+ struct {
+ bContext *context;
+ wmOperatorType *ot;
+ wmOperator *op;
+ PropertyRNA *prop_axis_co;
+ PropertyRNA *prop_axis_no;
+ PropertyRNA *prop_angle;
+
+ float rotate_axis[3];
+#ifdef USE_ANGLE_Z_ORIENT
+ /* Apply 'orient_mat' for the final value. */
+ float orient_axis_relative[3];
+#endif
+ /* The orientation, since the operator doesn't store this, we store our own.
+ * this is kept in sync with the operator,
+ * rotating the orientation when it doesn't match.
+ *
+ * Initialize to a sensible value where possible.
+ */
+ float orient_mat[3][3];
+
+ } data;
+} GizmoGroupData_SpinRedo;
+
+/**
+ * XXX. calling redo from property updates is not great.
+ * This is needed because changing the RNA doesn't cause a redo
+ * and we're not using operator UI which does just this.
+ */
+static void gizmo_spin_exec(GizmoGroupData_SpinRedo *ggd)
+{
+ if (ggd->is_init) {
+ wmGizmo *gz = ggd->angle_z;
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value");
+ RNA_property_unset(gz->ptr, prop);
+ ggd->is_init = false;
+ }
+
+ wmOperator *op = ggd->data.op;
+ if (op == WM_operator_last_redo((bContext *)ggd->data.context)) {
+ ED_undo_operator_repeat((bContext *)ggd->data.context, op);
+ }
+}
+
+static void gizmo_mesh_spin_redo_update_orient_axis(GizmoGroupData_SpinRedo *ggd, const float plane_no[3])
+{
+ float mat[3][3];
+ rotation_between_vecs_to_mat3(mat, ggd->data.orient_mat[2], plane_no);
+ mul_m3_m3m3(ggd->data.orient_mat, mat, ggd->data.orient_mat);
+ /* Not needed, just set for numeric stability. */
+ copy_v3_v3(ggd->data.orient_mat[2], plane_no);
+}
+
+static void gizmo_mesh_spin_redo_update_from_op(GizmoGroupData_SpinRedo *ggd)
+{
+ wmOperator *op = ggd->data.op;
+ float plane_co[3], plane_no[3];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co);
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
+ if (UNLIKELY(normalize_v3(plane_no) == 0.0f)) {
+ return;
+ }
+ const bool is_plane_co_eq = equals_v3v3(plane_co, ggd->prev.plane_co);
+ const bool is_plane_no_eq = equals_v3v3(plane_no, ggd->prev.plane_no);
+ if (is_plane_co_eq && is_plane_no_eq) {
+ return;
+ }
+ copy_v3_v3(ggd->prev.plane_co, plane_co);
+ copy_v3_v3(ggd->prev.plane_no, plane_no);
+
+ if (is_plane_no_eq == false) {
+ gizmo_mesh_spin_redo_update_orient_axis(ggd, plane_no);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ WM_gizmo_set_matrix_location(ggd->rotate_xy[i], plane_co);
+ WM_gizmo_set_matrix_location(ggd->translate_xy[i], plane_co);
+ }
+ WM_gizmo_set_matrix_location(ggd->angle_z, plane_co);
+ WM_gizmo_set_matrix_location(ggd->rotate_view, plane_co);
+ /* translate_c location comes from the property. */
+
+ for (int i = 0; i < 2; i++) {
+ WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_xy[i], ggd->data.orient_mat[i]);
+ WM_gizmo_set_matrix_rotation_from_z_axis(ggd->rotate_xy[i], ggd->data.orient_mat[i]);
+ }
+#ifdef USE_ANGLE_Z_ORIENT
+ {
+ float plane_tan[3];
+ float orient_axis[3];
+ mul_v3_m3v3(orient_axis, ggd->data.orient_mat, ggd->data.orient_axis_relative);
+ project_plane_normalized_v3_v3v3(plane_tan, orient_axis, plane_no);
+ if (normalize_v3(plane_tan) != 0.0f) {
+ WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->angle_z, plane_tan, plane_no);
+ }
+ else {
+ WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no);
+ }
+ }
+#else
+ WM_gizmo_set_matrix_rotation_from_z_axis(ggd->angle_z, plane_no);
+#endif
+}
+
+/* depth callbacks */
+static void gizmo_spin_prop_depth_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ const float *plane_no = gz->matrix_basis[2];
+ float plane_co[3];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co);
+
+ value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]);
+}
+
+static void gizmo_spin_prop_depth_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ const float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ float plane_co[3], plane[4];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co);
+ normalize_v3_v3(plane, gz->matrix_basis[2]);
+
+ plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]);
+
+ /* Keep our location, may be offset simply to be inside the viewport. */
+ closest_to_plane_normalized_v3(plane_co, plane, plane_co);
+
+ RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_co, plane_co);
+
+ gizmo_spin_exec(ggd);
+}
+
+/* translate callbacks */
+static void gizmo_spin_prop_translate_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 3);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, value);
+}
+
+static void gizmo_spin_prop_translate_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value)
+{
+ GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+
+ BLI_assert(gz_prop->type->array_length == 3);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_co, value);
+
+ gizmo_spin_exec(ggd);
+}
+
+/* angle callbacks */
+static void gizmo_spin_prop_axis_angle_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ float plane_no[4];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
+ normalize_v3(plane_no);
+
+ const float *rotate_axis = gz->matrix_basis[2];
+ float rotate_up[3];
+ ortho_v3_v3(rotate_up, rotate_axis);
+
+ float plane_no_proj[3];
+ project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, rotate_axis);
+
+ if (!is_zero_v3(plane_no_proj)) {
+ const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, rotate_up, rotate_axis);
+ value[0] = angle;
+ }
+ else {
+ value[0] = 0.0f;
+ }
+}
+
+static void gizmo_spin_prop_axis_angle_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ const float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+
+ float plane_no[4];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
+ normalize_v3(plane_no);
+
+ const float *rotate_axis = gz->matrix_basis[2];
+ float rotate_up[3];
+ ortho_v3_v3(rotate_up, rotate_axis);
+
+ float plane_no_proj[3];
+ project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, rotate_axis);
+
+ if (!is_zero_v3(plane_no_proj)) {
+ const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, rotate_up, rotate_axis);
+ const float angle_delta = angle - angle_compat_rad(value[0], angle);
+ if (angle_delta != 0.0f) {
+ float mat[3][3];
+ axis_angle_normalized_to_mat3(mat, rotate_axis, angle_delta);
+ mul_m3_v3(mat, plane_no);
+
+ /* re-normalize - seems acceptable */
+ RNA_property_float_set_array(op->ptr, ggd->data.prop_axis_no, plane_no);
+
+ gizmo_spin_exec(ggd);
+ }
+ }
+}
+
+/* angle callbacks */
+static void gizmo_spin_prop_angle_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+ value[0] = RNA_property_float_get(op->ptr, ggd->data.prop_angle);
+}
+
+static void gizmo_spin_prop_angle_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ GizmoGroupData_SpinRedo *ggd = gz->parent_gzgroup->customdata;
+ wmOperator *op = ggd->data.op;
+ BLI_assert(gz_prop->type->array_length == 1);
+ UNUSED_VARS_NDEBUG(gz_prop);
+ const float *value = value_p;
+ RNA_property_float_set(op->ptr, ggd->data.prop_angle, value[0]);
+
+ gizmo_spin_exec(ggd);
+}
+
+static bool gizmo_mesh_spin_redo_poll(const bContext *C, wmGizmoGroupType *gzgt)
+{
+ if (ED_gizmo_poll_or_unlink_delayed_from_operator(C, gzgt, "MESH_OT_spin")) {
+ if (ED_gizmo_poll_or_unlink_delayed_from_tool_ex(C, gzgt, "MESH_GGT_spin")) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void gizmo_mesh_spin_redo_modal_from_setup(
+ const bContext *C, wmGizmoGroup *gzgroup)
+{
+ /* Start off dragging. */
+ GizmoGroupData_SpinRedo *ggd = gzgroup->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ wmGizmo *gz = ggd->angle_z;
+ wmGizmoMap *gzmap = gzgroup->parent_gzmap;
+
+ ggd->is_init = true;
+
+ WM_gizmo_modal_set_from_setup(
+ gzmap, (bContext *)C, gz, 0, win->eventstate);
+}
+
+static void gizmo_mesh_spin_redo_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmOperatorType *ot = WM_operatortype_find("MESH_OT_spin", true);
+ wmOperator *op = WM_operator_last_redo(C);
+
+ if ((op == NULL) || (op->type != ot)) {
+ return;
+ }
+
+ GizmoGroupData_SpinRedo *ggd = MEM_callocN(sizeof(*ggd), __func__);
+ gzgroup->customdata = ggd;
+
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
+ const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
+ const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
+
+ /* Rotate View Axis (rotate_view) */
+ {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ zero_v4(gz->color);
+ copy_v3_fl(gz->color_hi, 1.0f);
+ gz->color_hi[3] = 0.1f;
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true);
+ RNA_enum_set(gz->ptr, "draw_options",
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR |
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y |
+ ED_GIZMO_DIAL_DRAW_FLAG_FILL);
+ ggd->rotate_view = gz;
+ }
+
+ /* Translate Center (translate_c) */
+ {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ gz->color[3] = 0.6f;
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D);
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true);
+ WM_gizmo_set_scale(gz, 0.15);
+ WM_gizmo_set_line_width(gz, 2.0f);
+ ggd->translate_c = gz;
+ }
+
+ /* Spin Angle (angle_z) */
+ {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
+ copy_v3_v3(gz->color, gz->color_hi);
+ gz->color[3] = 0.5f;
+ RNA_boolean_set(gz->ptr, "wrap_angle", false);
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
+ RNA_float_set(gz->ptr, "arc_inner_factor", 0.9f);
+ RNA_float_set(gz->ptr, "click_value", M_PI * 2);
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true);
+ WM_gizmo_set_scale(gz, 2.0f);
+ WM_gizmo_set_line_width(gz, 1.0f);
+ ggd->angle_z = gz;
+ }
+
+ /* Translate X/Y Tangents (translate_xy) */
+ for (int i = 0; i < 2; i++) {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ UI_GetThemeColor3fv(TH_AXIS_X + i, gz->color);
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_NORMAL);
+ RNA_enum_set(gz->ptr, "draw_options", 0);
+ WM_gizmo_set_scale(gz, 1.2f);
+ ggd->translate_xy[i] = gz;
+ }
+
+ /* Rotate X/Y Tangents (rotate_xy) */
+ for (int i = 0; i < 2; i++) {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
+ UI_GetThemeColor3fv(TH_AXIS_X + i, gz->color);
+ gz->color[3] = 0.6f;
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true);
+ WM_gizmo_set_line_width(gz, 3.0f);
+ /* show the axis instead of mouse cursor */
+ RNA_enum_set(gz->ptr, "draw_options",
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_MIRROR |
+ ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_START_Y |
+ ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
+ ggd->rotate_xy[i] = gz;
+ }
+
+ {
+ ggd->data.context = (bContext *)C;
+ ggd->data.ot = ot;
+ ggd->data.op = op;
+ ggd->data.prop_axis_co = RNA_struct_type_find_property(ot->srna, "center");
+ ggd->data.prop_axis_no = RNA_struct_type_find_property(ot->srna, "axis");
+ ggd->data.prop_angle = RNA_struct_type_find_property(ot->srna, "angle");
+ }
+
+ /* The spin operator only knows about an axis,
+ * while the manipulator has X/Y orientation for the gizmos.
+ * Initialize the orientation from the spin gizmo if possible.
+ */
+ {
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ wmGizmoGroup *gzgroup_init = WM_gizmomap_group_find(gzmap, "MESH_GGT_spin");
+ if (gzgroup_init) {
+ GizmoGroupData_SpinInit *ggd_init = gzgroup_init->customdata;
+ copy_m3_m3(ggd->data.orient_mat, ggd_init->data.orient_mat);
+ if (ggd_init->invoke.ortho_axis_active != -1) {
+ copy_v3_v3(ggd->data.orient_axis_relative,
+ ggd_init->gizmos.xyz_view[ggd_init->invoke.ortho_axis_active]->matrix_basis[1]);
+ ggd_init->invoke.ortho_axis_active = -1;
+ }
+ }
+ else {
+ unit_m3(ggd->data.orient_mat);
+ }
+ }
+
+#ifdef USE_ANGLE_Z_ORIENT
+ {
+ wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ const wmEvent *event = win->eventstate;
+ float plane_co[3], plane_no[3];
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_co, plane_co);
+ RNA_property_float_get_array(op->ptr, ggd->data.prop_axis_no, plane_no);
+
+ gizmo_mesh_spin_redo_update_orient_axis(ggd, plane_no);
+
+ /* Use cursor as fallback if it's not set by the 'ortho_axis_active'. */
+ if (is_zero_v3(ggd->data.orient_axis_relative)) {
+ float cursor_co[3];
+ const int mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin};
+ float plane[4];
+ plane_from_point_normal_v3(plane, plane_co, plane_no);
+ if (UNLIKELY(!ED_view3d_win_to_3d_on_plane_int(ar, plane, mval, false, cursor_co))) {
+ ED_view3d_win_to_3d_int(v3d, ar, plane, mval, cursor_co);
+ }
+ sub_v3_v3v3(ggd->data.orient_axis_relative, cursor_co, plane_co);
+ }
+
+ if (!is_zero_v3(ggd->data.orient_axis_relative)) {
+ normalize_v3(ggd->data.orient_axis_relative);
+ float imat3[3][3];
+ invert_m3_m3(imat3, ggd->data.orient_mat);
+ mul_m3_v3(imat3, ggd->data.orient_axis_relative);
+ }
+ }
+#endif
+
+ gizmo_mesh_spin_redo_update_from_op(ggd);
+
+ /* Setup property callbacks */
+ {
+ WM_gizmo_target_property_def_func(
+ ggd->translate_c, "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_spin_prop_translate_get,
+ .value_set_fn = gizmo_spin_prop_translate_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ WM_gizmo_target_property_def_func(
+ ggd->rotate_view, "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_spin_prop_axis_angle_get,
+ .value_set_fn = gizmo_spin_prop_axis_angle_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+
+ for (int i = 0; i < 2; i++) {
+ WM_gizmo_target_property_def_func(
+ ggd->rotate_xy[i], "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_spin_prop_axis_angle_get,
+ .value_set_fn = gizmo_spin_prop_axis_angle_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+ WM_gizmo_target_property_def_func(
+ ggd->translate_xy[i], "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_spin_prop_depth_get,
+ .value_set_fn = gizmo_spin_prop_depth_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+ }
+
+ WM_gizmo_target_property_def_func(
+ ggd->angle_z, "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_spin_prop_angle_get,
+ .value_set_fn = gizmo_spin_prop_angle_set,
+ .range_get_fn = NULL,
+ .user_data = NULL,
+ });
+ }
+
+ /* Become modal as soon as it's started. */
+ gizmo_mesh_spin_redo_modal_from_setup(C, gzgroup);
+}
+
+static void gizmo_mesh_spin_redo_draw_prepare(
+ const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ GizmoGroupData_SpinRedo *ggd = gzgroup->customdata;
+ if (ggd->data.op->next) {
+ ggd->data.op = WM_operator_last_redo((bContext *)ggd->data.context);
+ }
+
+ /* Not essential, just avoids feedback loop where matrices could shift because of float precision.
+ * Updates in this case are also redundant. */
+ bool is_modal = false;
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ if (gz->state & WM_GIZMO_STATE_MODAL) {
+ is_modal = true;
+ break;
+ }
+ }
+ if (!is_modal) {
+ gizmo_mesh_spin_redo_update_from_op(ggd);
+ }
+
+ RegionView3D *rv3d = ED_view3d_context_rv3d(ggd->data.context);
+ WM_gizmo_set_matrix_rotation_from_z_axis(ggd->translate_c, rv3d->viewinv[2]);
+ {
+ float view_up[3];
+ project_plane_normalized_v3_v3v3(view_up, ggd->data.orient_mat[2], rv3d->viewinv[2]);
+ if (normalize_v3(view_up) != 0.0f) {
+ WM_gizmo_set_matrix_rotation_from_yz_axis(ggd->rotate_view, view_up, rv3d->viewinv[2]);
+ }
+ else {
+ WM_gizmo_set_matrix_rotation_from_z_axis(ggd->rotate_view, rv3d->viewinv[2]);
+ }
+ }
+}
+
+void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Mesh Spin Redo";
+ gzgt->idname = "MESH_GGT_spin_redo";
+
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = gizmo_mesh_spin_redo_poll;
+ gzgt->setup = gizmo_mesh_spin_redo_setup;
+ gzgt->draw_prepare = gizmo_mesh_spin_redo_draw_prepare;
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 3833b84b5d2..78c0c45576d 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -37,6 +37,7 @@
#include "BKE_global.h"
#include "BKE_editmesh.h"
#include "BKE_unit.h"
+#include "BKE_layer.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -55,6 +56,10 @@
#include "mesh_intern.h" /* own include */
+typedef struct {
+ BMEditMesh *em;
+ BMBackup mesh_backup;
+} InsetObjectStore;
typedef struct {
float old_thickness;
@@ -65,14 +70,15 @@ typedef struct {
bool is_modal;
bool shift;
float shift_amount;
- BMEditMesh *em;
NumInput num_input;
+ InsetObjectStore *ob_store;
+ uint ob_store_len;
+
/* modal only */
float mcenter[2];
- BMBackup mesh_backup;
void *draw_handle_pixel;
- short twtype;
+ short gizmo_flag;
} InsetData;
@@ -106,7 +112,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
WM_bool_as_string(RNA_boolean_get(op->ptr, "use_individual"))
);
- ED_area_headerprint(sa, msg);
+ ED_area_status_text(sa, msg);
}
}
@@ -115,12 +121,7 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
{
InsetData *opdata;
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- if (em->bm->totvertsel == 0) {
- return false;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
if (is_modal) {
RNA_float_set(op->ptr, "thickness", 0.01f);
@@ -129,13 +130,30 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
op->customdata = opdata = MEM_mallocN(sizeof(InsetData), "inset_operator_data");
+ uint objects_used_len = 0;
+
+ {
+ uint ob_store_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &ob_store_len);
+ opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__);
+ for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totvertsel > 0) {
+ opdata->ob_store[objects_used_len].em = em;
+ objects_used_len++;
+ }
+ }
+ MEM_freeN(objects);
+ opdata->ob_store_len = objects_used_len;
+ }
+
opdata->old_thickness = 0.01;
opdata->old_depth = 0.0;
opdata->modify_depth = false;
opdata->shift = false;
opdata->shift_amount = 0.0f;
opdata->is_modal = is_modal;
- opdata->em = em;
initNumInput(&opdata->num_input);
opdata->num_input.idx_max = 1; /* Two elements. */
@@ -147,13 +165,16 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
- opdata->mesh_backup = EDBM_redo_state_store(em);
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(opdata->ob_store[ob_index].em);
+ }
+
opdata->draw_handle_pixel = ED_region_draw_cb_activate(
ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
if (v3d) {
- opdata->twtype = v3d->twtype;
- v3d->twtype = 0;
+ opdata->gizmo_flag = v3d->gizmo_flag;
+ v3d->gizmo_flag = V3D_GIZMO_HIDE;
}
}
@@ -170,18 +191,22 @@ static void edbm_inset_exit(bContext *C, wmOperator *op)
if (opdata->is_modal) {
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
- EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false);
+ }
ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel);
if (v3d) {
- v3d->twtype = opdata->twtype;
+ v3d->gizmo_flag = opdata->gizmo_flag;
}
G.moving = 0;
}
if (sa) {
- ED_area_headerprint(sa, NULL);
+ ED_area_status_text(sa, NULL);
}
- MEM_freeN(op->customdata);
+
+ MEM_SAFE_FREE(opdata->ob_store);
+ MEM_SAFE_FREE(op->customdata);
}
static void edbm_inset_cancel(bContext *C, wmOperator *op)
@@ -190,8 +215,10 @@ static void edbm_inset_cancel(bContext *C, wmOperator *op)
opdata = op->customdata;
if (opdata->is_modal) {
- EDBM_redo_state_free(&opdata->mesh_backup, opdata->em, true);
- EDBM_update_generic(opdata->em, false, true);
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true);
+ EDBM_update_generic(opdata->ob_store[ob_index].em, false, true);
+ }
}
edbm_inset_exit(C, op);
@@ -205,6 +232,7 @@ static bool edbm_inset_calc(wmOperator *op)
InsetData *opdata;
BMEditMesh *em;
BMOperator bmop;
+ bool changed = false;
const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
const bool use_even_offset = RNA_boolean_get(op->ptr, "use_even_offset");
@@ -218,49 +246,55 @@ static bool edbm_inset_calc(wmOperator *op)
const bool use_interpolate = RNA_boolean_get(op->ptr, "use_interpolate");
opdata = op->customdata;
- em = opdata->em;
- if (opdata->is_modal) {
- EDBM_redo_state_restore(opdata->mesh_backup, em, false);
- }
+ for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
+ em = opdata->ob_store[ob_index].em;
- if (use_individual) {
- EDBM_op_init(em, &bmop, op,
- "inset_individual faces=%hf use_even_offset=%b use_relative_offset=%b "
- "use_interpolate=%b thickness=%f depth=%f",
- BM_ELEM_SELECT, use_even_offset, use_relative_offset, use_interpolate,
- thickness, depth);
- }
- else {
- EDBM_op_init(em, &bmop, op,
- "inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b "
- "use_interpolate=%b thickness=%f depth=%f use_outset=%b use_edge_rail=%b",
- BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset, use_interpolate,
- thickness, depth, use_outset, use_edge_rail);
-
- if (use_outset) {
- BMO_slot_buffer_from_enabled_hflag(em->bm, &bmop, bmop.slots_in, "faces_exclude", BM_FACE, BM_ELEM_HIDDEN);
+ if (opdata->is_modal) {
+ EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false);
}
- }
- BMO_op_exec(em->bm, &bmop);
- if (use_select_inset) {
- /* deselect original faces/verts */
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
- }
- else {
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_in, "faces", BM_FACE, BM_ELEM_SELECT, true);
- }
+ if (use_individual) {
+ EDBM_op_init(
+ em, &bmop, op,
+ "inset_individual faces=%hf use_even_offset=%b use_relative_offset=%b "
+ "use_interpolate=%b thickness=%f depth=%f",
+ BM_ELEM_SELECT, use_even_offset, use_relative_offset, use_interpolate,
+ thickness, depth);
+ }
+ else {
+ EDBM_op_init(
+ em, &bmop, op,
+ "inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b "
+ "use_interpolate=%b thickness=%f depth=%f use_outset=%b use_edge_rail=%b",
+ BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset, use_interpolate,
+ thickness, depth, use_outset, use_edge_rail);
+
+ if (use_outset) {
+ BMO_slot_buffer_from_enabled_hflag(em->bm, &bmop, bmop.slots_in, "faces_exclude", BM_FACE, BM_ELEM_HIDDEN);
+ }
+ }
+ BMO_op_exec(em->bm, &bmop);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return false;
- }
- else {
- EDBM_update_generic(em, true, true);
- return true;
+ if (use_select_inset) {
+ /* deselect original faces/verts */
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ }
+ else {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_in, "faces", BM_FACE, BM_ELEM_SELECT, true);
+ }
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+ else {
+ EDBM_update_generic(em, true, true);
+ changed = true;
+ }
}
+ return changed;
}
static int edbm_inset_exec(bContext *C, wmOperator *op)
@@ -378,7 +412,9 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event)
case LEFTMOUSE:
case PADENTER:
case RETKEY:
- if (event->val == KM_PRESS) {
+ if ((event->val == KM_PRESS) ||
+ ((event->val == KM_RELEASE) && RNA_boolean_get(op->ptr, "release_confirm")))
+ {
edbm_inset_calc(op);
edbm_inset_exit(C, op);
return OPERATOR_FINISHED;
@@ -540,4 +576,7 @@ void MESH_OT_inset(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces");
RNA_def_boolean(ot->srna, "use_individual", false, "Individual", "Individual Face Inset");
RNA_def_boolean(ot->srna, "use_interpolate", true, "Interpolate", "Blend face data across the inset");
+
+ prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 86b1a58dd1e..a625d8949a6 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -33,6 +33,7 @@
#include "BLI_kdopbvh.h"
#include "BLI_linklist_stack.h"
+#include "BKE_layer.h"
#include "BKE_editmesh_bvh.h"
#include "BKE_context.h"
#include "BKE_report.h"
@@ -146,9 +147,6 @@ enum {
static int edbm_intersect_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
const int mode = RNA_enum_get(op->ptr, "mode");
int (*test_fn)(BMFace *, void *);
bool use_separate_all = false;
@@ -186,29 +184,45 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
default: /* ISECT_SEPARATE_NONE */
break;
}
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ uint isect_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- has_isect = BM_mesh_intersect(
- bm,
- em->looptris, em->tottri,
- test_fn, NULL,
- use_self, use_separate_all, true, true, true, true,
- -1,
- eps);
-
- if (use_separate_cut) {
- /* detach selected/un-selected faces */
- BM_mesh_separate_faces(
- bm,
- BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+
+ has_isect = BM_mesh_intersect(
+ em->bm,
+ em->looptris, em->tottri,
+ test_fn, NULL,
+ use_self, use_separate_all, true, true, true, true,
+ -1,
+ eps);
+
+ if (use_separate_cut) {
+ /* detach selected/un-selected faces */
+ BM_mesh_separate_faces(
+ em->bm,
+ BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
+ }
- if (has_isect) {
- edbm_intersect_select(em);
+ if (has_isect) {
+ edbm_intersect_select(em);
+ }
+ else {
+ isect_len++;
+ }
}
- else {
+ MEM_freeN(objects);
+
+ if (isect_len == objects_len) {
BKE_report(op->reports, RPT_WARNING, "No intersections found");
}
-
return OPERATOR_FINISHED;
}
@@ -266,9 +280,6 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
const int boolean_operation = RNA_enum_get(op->ptr, "operation");
bool use_swap = RNA_boolean_get(op->ptr, "use_swap");
const float eps = RNA_float_get(op->ptr, "threshold");
@@ -276,23 +287,39 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
bool has_isect;
test_fn = use_swap ? bm_face_isect_pair_swap : bm_face_isect_pair;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ uint isect_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- has_isect = BM_mesh_intersect(
- bm,
- em->looptris, em->tottri,
- test_fn, NULL,
- false, false, true, true, false, true,
- boolean_operation,
- eps);
+ has_isect = BM_mesh_intersect(
+ em->bm,
+ em->looptris, em->tottri,
+ test_fn, NULL,
+ false, false, true, true, false, true,
+ boolean_operation,
+ eps);
- if (has_isect) {
- edbm_intersect_select(em);
+ if (has_isect) {
+ edbm_intersect_select(em);
+ }
+ else {
+ isect_len++;
+ }
}
- else {
+ MEM_freeN(objects);
+
+ if (isect_len == objects_len) {
BKE_report(op->reports, RPT_WARNING, "No intersections found");
}
-
return OPERATOR_FINISHED;
}
@@ -652,257 +679,270 @@ static BMEdge *bm_face_split_edge_find(
static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
const char hflag = BM_ELEM_TAG;
BMEdge *e;
BMIter iter;
- BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- {
- BMVert *v;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_disable(v, hflag);
+ if ((bm->totedgesel == 0) ||
+ (bm->totfacesel == 0))
+ {
+ continue;
}
- }
-
- /* edge index is set to -1 then used to assosiate them with faces */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) {
- BM_elem_flag_enable(e, hflag);
- BM_elem_flag_enable(e->v1, hflag);
- BM_elem_flag_enable(e->v2, hflag);
+ BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+ {
+ BMVert *v;
+ BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_disable(v, hflag);
+ }
}
- else {
- BM_elem_flag_disable(e, hflag);
- }
- BM_elem_index_set(e, -1); /* set_dirty */
- }
- bm->elem_index_dirty |= BM_EDGE;
- {
- BMFace *f;
- int i;
- BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- BM_elem_flag_enable(f, hflag);
+ /* edge index is set to -1 then used to associate them with faces */
+ BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) {
+ BM_elem_flag_enable(e, hflag);
+
+ BM_elem_flag_enable(e->v1, hflag);
+ BM_elem_flag_enable(e->v2, hflag);
+
}
else {
- BM_elem_flag_disable(f, hflag);
+ BM_elem_flag_disable(e, hflag);
}
- BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG);
- BM_elem_index_set(f, i); /* set_ok */
+ BM_elem_index_set(e, -1); /* set_dirty */
}
- }
- bm->elem_index_dirty &= ~BM_FACE;
-
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, hflag)) {
- BMIter viter;
- BMVert *v;
- BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
- BMIter liter;
- BMLoop *l;
-
- unsigned int loop_stack_len;
- BMLoop *l_best = NULL;
-
- BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
- loop_stack_len = 0;
-
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- if (BM_elem_flag_test(l->f, hflag)) {
- BLI_SMALLSTACK_PUSH(loop_stack, l);
- loop_stack_len++;
- }
- }
+ bm->elem_index_dirty |= BM_EDGE;
- if (loop_stack_len == 0) {
- /* pass */
- }
- else if (loop_stack_len == 1) {
- l_best = BLI_SMALLSTACK_POP(loop_stack);
+ {
+ BMFace *f;
+ int i;
+ BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(f, hflag);
}
else {
- /* complicated case, match the edge with a face-loop */
+ BM_elem_flag_disable(f, hflag);
+ }
+ BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG);
+ BM_elem_index_set(f, i); /* set_ok */
+ }
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+
+ BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, hflag)) {
+ BMIter viter;
+ BMVert *v;
+ BM_ITER_ELEM(v, &viter, e, BM_VERTS_OF_EDGE) {
+ BMIter liter;
+ BMLoop *l;
+
+ unsigned int loop_stack_len;
+ BMLoop *l_best = NULL;
+
+ BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
+ loop_stack_len = 0;
+
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+ if (BM_elem_flag_test(l->f, hflag)) {
+ BLI_SMALLSTACK_PUSH(loop_stack, l);
+ loop_stack_len++;
+ }
+ }
+
+ if (loop_stack_len == 0) {
+ /* pass */
+ }
+ else if (loop_stack_len == 1) {
+ l_best = BLI_SMALLSTACK_POP(loop_stack);
+ }
+ else {
+ /* complicated case, match the edge with a face-loop */
- BMVert *v_other = BM_edge_other_vert(e, v);
- float e_dir[3];
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ float e_dir[3];
- /* we want closest to zero */
- float dot_best = FLT_MAX;
+ /* we want closest to zero */
+ float dot_best = FLT_MAX;
- sub_v3_v3v3(e_dir, v_other->co, v->co);
- normalize_v3(e_dir);
+ sub_v3_v3v3(e_dir, v_other->co, v->co);
+ normalize_v3(e_dir);
- while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
- float dot_test;
+ while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
+ float dot_test;
- /* Check dot first to save on expensive angle-comparison.
- * ideal case is 90d difference == 0.0 dot */
- dot_test = fabsf(dot_v3v3(e_dir, l->f->no));
- if (dot_test < dot_best) {
+ /* Check dot first to save on expensive angle-comparison.
+ * ideal case is 90d difference == 0.0 dot */
+ dot_test = fabsf(dot_v3v3(e_dir, l->f->no));
+ if (dot_test < dot_best) {
- /* check we're in the correct corner (works with convex loops too) */
- if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) <
- angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no))
- {
- dot_best = dot_test;
- l_best = l;
+ /* check we're in the correct corner (works with convex loops too) */
+ if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) <
+ angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no))
+ {
+ dot_best = dot_test;
+ l_best = l;
+ }
}
}
}
- }
- if (l_best) {
- BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */
+ if (l_best) {
+ BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */
+ }
}
}
}
- }
- {
- BMFace *f;
- BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128);
+ {
+ BMFace *f;
+ BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128);
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, hflag)) {
- bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf);
+ BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, hflag)) {
+ bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf);
+ }
}
+ BLI_buffer_free(&edge_net_temp_buf);
}
- BLI_buffer_free(&edge_net_temp_buf);
- }
#ifdef USE_NET_ISLAND_CONNECT
- /* before overwriting edge index values, collect edges left untouched */
- BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge * ), __func__);
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) {
- BLI_stack_push(edges_loose, &e);
+ /* before overwriting edge index values, collect edges left untouched */
+ BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge *), __func__);
+ BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) {
+ BLI_stack_push(edges_loose, &e);
+ }
}
- }
#endif
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
#ifdef USE_NET_ISLAND_CONNECT
- /* we may have remaining isolated regions remaining,
- * these will need to have connecting edges created */
- if (!BLI_stack_is_empty(edges_loose)) {
- GHash *face_edge_map = BLI_ghash_ptr_new(__func__);
+ /* we may have remaining isolated regions remaining,
+ * these will need to have connecting edges created */
+ if (!BLI_stack_is_empty(edges_loose)) {
+ GHash *face_edge_map = BLI_ghash_ptr_new(__func__);
- MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- BM_mesh_elem_index_ensure(bm, BM_FACE);
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
- {
- BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false);
+ {
+ BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false);
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_index_set(e, -1); /* set_dirty */
- }
+ BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_index_set(e, -1); /* set_dirty */
+ }
- while (!BLI_stack_is_empty(edges_loose)) {
- BLI_stack_pop(edges_loose, &e);
- float e_center[3];
- mid_v3_v3v3(e_center, e->v1->co, e->v2->co);
+ while (!BLI_stack_is_empty(edges_loose)) {
+ BLI_stack_pop(edges_loose, &e);
+ float e_center[3];
+ mid_v3_v3v3(e_center, e->v1->co, e->v2->co);
- BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX);
- if (f) {
- ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena);
- BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */
+ BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX);
+ if (f) {
+ ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena);
+ BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */
+ }
}
- }
- BKE_bmbvh_free(bmbvh);
- }
+ BKE_bmbvh_free(bmbvh);
+ }
- bm->elem_index_dirty |= BM_EDGE;
+ bm->elem_index_dirty |= BM_EDGE;
- BM_mesh_elem_table_ensure(bm, BM_FACE);
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
- /* detect edges chains that span faces
- * and splice vertices into the closest edges */
- {
- GHashIterator gh_iter;
-
- GHASH_ITER(gh_iter, face_edge_map) {
- BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
- struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
- LinkNode *e_link = e_ls_base->list;
-
- do {
- e = e_link->link;
-
- for (int j = 0; j < 2; j++) {
- BMVert *v_pivot = (&e->v1)[j];
- /* checking that \a v_pivot isn't in the face
- * prevents attempting to splice the same vertex into an edge from multiple faces */
- if (!BM_vert_in_face(v_pivot, f)) {
- float v_pivot_co[3];
- float v_pivot_fac;
- BMEdge *e_split = bm_face_split_edge_find(
- e, f, v_pivot, bm->ftable, bm->totface,
- v_pivot_co, &v_pivot_fac);
-
- if (e_split) {
- /* for degenerate cases this vertex may be in one of this edges radial faces */
- if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) {
- BMEdge *e_new;
- BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac);
- if (v_new) {
- /* we _know_ these don't share an edge */
- BM_vert_splice(bm, v_pivot, v_new);
- BM_elem_index_set(e_new, BM_elem_index_get(e_split));
+ /* detect edges chains that span faces
+ * and splice vertices into the closest edges */
+ {
+ GHashIterator gh_iter;
+
+ GHASH_ITER(gh_iter, face_edge_map) {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+ struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+ LinkNode *e_link = e_ls_base->list;
+
+ do {
+ e = e_link->link;
+
+ for (int j = 0; j < 2; j++) {
+ BMVert *v_pivot = (&e->v1)[j];
+ /* checking that \a v_pivot isn't in the face
+ * prevents attempting to splice the same vertex into an edge from multiple faces */
+ if (!BM_vert_in_face(v_pivot, f)) {
+ float v_pivot_co[3];
+ float v_pivot_fac;
+ BMEdge *e_split = bm_face_split_edge_find(
+ e, f, v_pivot, bm->ftable, bm->totface,
+ v_pivot_co, &v_pivot_fac);
+
+ if (e_split) {
+ /* for degenerate cases this vertex may be in one of this edges radial faces */
+ if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) {
+ BMEdge *e_new;
+ BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac);
+ if (v_new) {
+ /* we _know_ these don't share an edge */
+ BM_vert_splice(bm, v_pivot, v_new);
+ BM_elem_index_set(e_new, BM_elem_index_get(e_split));
+ }
}
}
}
}
- }
- } while ((e_link = e_link->next));
+ } while ((e_link = e_link->next));
+ }
}
- }
- {
- MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ {
+ MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- GHashIterator gh_iter;
+ GHashIterator gh_iter;
- GHASH_ITER(gh_iter, face_edge_map) {
- BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
- struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+ GHASH_ITER(gh_iter, face_edge_map) {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+ struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
- bm_face_split_by_edges_island_connect(
- bm, f,
- e_ls_base->list, e_ls_base->list_len,
- mem_arena_edgenet);
+ bm_face_split_by_edges_island_connect(
+ bm, f,
+ e_ls_base->list, e_ls_base->list_len,
+ mem_arena_edgenet);
- BLI_memarena_clear(mem_arena_edgenet);
- }
+ BLI_memarena_clear(mem_arena_edgenet);
+ }
- BLI_memarena_free(mem_arena_edgenet);
- }
+ BLI_memarena_free(mem_arena_edgenet);
+ }
- BLI_memarena_free(mem_arena);
+ BLI_memarena_free(mem_arena);
- BLI_ghash_free(face_edge_map, NULL, NULL);
+ BLI_ghash_free(face_edge_map, NULL, NULL);
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
- }
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ }
- BLI_stack_free(edges_loose);
+ BLI_stack_free(edges_loose);
#endif /* USE_NET_ISLAND_CONNECT */
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 9cc19d5194e..2e442d97fad 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -48,14 +48,17 @@
#include "BLT_translation.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
#include "BKE_report.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h" /* for paint cursor */
+#include "DEG_depsgraph.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -299,7 +302,7 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
#undef WM_MODALKEY
- ED_area_headerprint(CTX_wm_area(C), header);
+ ED_workspace_status_text(C, header);
}
static void knife_project_v2(const KnifeTool_OpData *kcd, const float co[3], float sco[2])
@@ -1004,12 +1007,18 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
copy_v3_v3(v2, ray_hit_best[1]);
}
- UI_ThemeColor(TH_TRANSFORM);
- glLineWidth(2.0);
- glBegin(GL_LINES);
- glVertex3fv(v1);
- glVertex3fv(v2);
- glEnd();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_TRANSFORM);
+ GPU_line_width(2.0);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ immUnbindProgram();
}
static void knife_init_colors(KnifeColors *colors)
@@ -1028,152 +1037,176 @@ static void knife_init_colors(KnifeColors *colors)
}
/* modal loop selection drawing callback */
-static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
+static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
{
- View3D *v3d = CTX_wm_view3d(C);
const KnifeTool_OpData *kcd = arg;
-
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
+ GPU_depth_test(false);
glPolygonOffset(1.0f, 1.0f);
- glPushMatrix();
- glMultMatrixf(kcd->ob->obmat);
+ GPU_matrix_push();
+ GPU_matrix_mul(kcd->ob->obmat);
- if (kcd->mode == MODE_DRAGGING) {
- if (kcd->is_angle_snapping)
- knifetool_draw_angle_snapping(kcd);
+ if (kcd->mode == MODE_DRAGGING && kcd->is_angle_snapping) {
+ knifetool_draw_angle_snapping(kcd);
+ }
- glColor3ubv(kcd->colors.line);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- glLineWidth(2.0);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (kcd->mode == MODE_DRAGGING) {
+ immUniformColor3ubv(kcd->colors.line);
+ GPU_line_width(2.0);
- glBegin(GL_LINES);
- glVertex3fv(kcd->prev.cage);
- glVertex3fv(kcd->curr.cage);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, kcd->prev.cage);
+ immVertex3fv(pos, kcd->curr.cage);
+ immEnd();
}
if (kcd->prev.vert) {
- glColor3ubv(kcd->colors.point);
- glPointSize(11);
+ immUniformColor3ubv(kcd->colors.point);
+ GPU_point_size(11);
- glBegin(GL_POINTS);
- glVertex3fv(kcd->prev.cage);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, kcd->prev.cage);
+ immEnd();
}
if (kcd->prev.bmface) {
- glColor3ubv(kcd->colors.curpoint);
- glPointSize(9);
+ immUniformColor3ubv(kcd->colors.curpoint);
+ GPU_point_size(9);
- glBegin(GL_POINTS);
- glVertex3fv(kcd->prev.cage);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, kcd->prev.cage);
+ immEnd();
}
if (kcd->curr.edge) {
- glColor3ubv(kcd->colors.edge);
- glLineWidth(2.0);
+ immUniformColor3ubv(kcd->colors.edge);
+ GPU_line_width(2.0);
- glBegin(GL_LINES);
- glVertex3fv(kcd->curr.edge->v1->cageco);
- glVertex3fv(kcd->curr.edge->v2->cageco);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, kcd->curr.edge->v1->cageco);
+ immVertex3fv(pos, kcd->curr.edge->v2->cageco);
+ immEnd();
}
else if (kcd->curr.vert) {
- glColor3ubv(kcd->colors.point);
- glPointSize(11);
+ immUniformColor3ubv(kcd->colors.point);
+ GPU_point_size(11);
- glBegin(GL_POINTS);
- glVertex3fv(kcd->curr.cage);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, kcd->curr.cage);
+ immEnd();
}
if (kcd->curr.bmface) {
- glColor3ubv(kcd->colors.curpoint);
- glPointSize(9);
+ immUniformColor3ubv(kcd->colors.curpoint);
+ GPU_point_size(9);
- glBegin(GL_POINTS);
- glVertex3fv(kcd->curr.cage);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, kcd->curr.cage);
+ immEnd();
}
if (kcd->totlinehit > 0) {
KnifeLineHit *lh;
- int i;
+ int i, v, vs;
+ float fcol[4];
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, kcd->totlinehit);
- /* draw any snapped verts first */
- glColor4ubv(kcd->colors.point_a);
- glPointSize(11);
- glBegin(GL_POINTS);
lh = kcd->linehits;
- for (i = 0; i < kcd->totlinehit; i++, lh++) {
- if (lh->v)
- glVertex3fv(lh->cagehit);
+ for (i = 0, v = 0, vs = kcd->totlinehit - 1; i < kcd->totlinehit; i++, lh++) {
+ if (lh->v) {
+ GPU_vertbuf_attr_set(vert, pos, v++, lh->cagehit);
+ }
+ else {
+ GPU_vertbuf_attr_set(vert, pos, vs--, lh->cagehit);
+ }
}
- glEnd();
+
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* draw any snapped verts first */
+ rgba_uchar_to_float(fcol, kcd->colors.point_a);
+ GPU_batch_uniform_4fv(batch, "color", fcol);
+ GPU_matrix_bind(batch->interface);
+ GPU_point_size(11);
+ GPU_batch_draw_range_ex(batch, 0, v - 1, false);
/* now draw the rest */
- glColor4ubv(kcd->colors.curpoint_a);
- glPointSize(7);
- glBegin(GL_POINTS);
- lh = kcd->linehits;
- for (i = 0; i < kcd->totlinehit; i++, lh++) {
- if (!lh->v)
- glVertex3fv(lh->cagehit);
- }
- glEnd();
- glDisable(GL_BLEND);
+ rgba_uchar_to_float(fcol, kcd->colors.curpoint_a);
+ GPU_batch_uniform_4fv(batch, "color", fcol);
+ GPU_point_size(7);
+ GPU_batch_draw_range_ex(batch, vs + 1, kcd->totlinehit - (vs + 1), false);
+
+ GPU_batch_program_use_end(batch);
+ GPU_batch_discard(batch);
+
+ GPU_blend(false);
}
if (kcd->totkedge > 0) {
BLI_mempool_iter iter;
KnifeEdge *kfe;
- glLineWidth(1.0);
- glBegin(GL_LINES);
+ immUniformColor3ubv(kcd->colors.line);
+ GPU_line_width(1.0);
+
+ GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2);
BLI_mempool_iternew(kcd->kedges, &iter);
for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
if (!kfe->is_cut)
continue;
- glColor3ubv(kcd->colors.line);
-
- glVertex3fv(kfe->v1->cageco);
- glVertex3fv(kfe->v2->cageco);
+ immVertex3fv(pos, kfe->v1->cageco);
+ immVertex3fv(pos, kfe->v2->cageco);
}
- glEnd();
+ immEnd();
+
+ GPU_batch_draw(batch);
+ GPU_batch_discard(batch);
}
if (kcd->totkvert > 0) {
BLI_mempool_iter iter;
KnifeVert *kfv;
- glPointSize(5.0);
+ immUniformColor3ubv(kcd->colors.point);
+ GPU_point_size(5.0);
+
+ GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts));
- glBegin(GL_POINTS);
BLI_mempool_iternew(kcd->kverts, &iter);
for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
if (!kfv->is_cut)
continue;
- glColor3ubv(kcd->colors.point);
-
- glVertex3fv(kfv->cageco);
+ immVertex3fv(pos, kfv->cageco);
}
- glEnd();
+ immEnd();
+
+ GPU_batch_draw(batch);
+ GPU_batch_discard(batch);
}
- glPopMatrix();
+ immUnbindProgram();
+
+ GPU_matrix_pop();
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+ /* Reset default */
+ GPU_depth_test(true);
}
/**
@@ -1394,7 +1427,7 @@ static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data)
* intersecting faces matching this face (or connected when an vert/edge) will be ignored.
*/
static bool point_is_visible(
- KnifeTool_OpData *kcd, const float p[3], const float s[2], bglMats *mats,
+ KnifeTool_OpData *kcd, const float p[3], const float s[2],
BMElem *ele_test)
{
BMFace *f_hit;
@@ -1412,7 +1445,7 @@ static bool point_is_visible(
float view[3], p_ofs[3];
/* TODO: I think there's a simpler way to get the required raycast ray */
- ED_view3d_unproject(mats, view, s[0], s[1], 0.0f);
+ ED_view3d_unproject(kcd->vc.ar, s[0], s[1], 0.0f, view);
mul_m4_v3(kcd->ob->imat, view);
@@ -1485,7 +1518,6 @@ static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh)
/* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */
static void knife_find_line_hits(KnifeTool_OpData *kcd)
{
- bglMats mats;
SmallHash faces, kfes, kfvs;
float v1[3], v2[3], v3[3], v4[3], s1[2], s2[2];
BVHTree *planetree, *tree;
@@ -1515,8 +1547,6 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
const bool use_hit_prev = true;
const bool use_hit_curr = (kcd->is_drag_hold == false);
- bgl_get_mats(&mats);
-
if (kcd->linehits) {
MEM_freeN(kcd->linehits);
kcd->linehits = NULL;
@@ -1542,8 +1572,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
/* unproject screen line */
- ED_view3d_win_to_segment_clipped(kcd->ar, kcd->vc.v3d, s1, v1, v3, true);
- ED_view3d_win_to_segment_clipped(kcd->ar, kcd->vc.v3d, s2, v2, v4, true);
+ ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s1, v1, v3, true);
+ ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->ar, kcd->vc.v3d, s2, v2, v4, true);
mul_m4_v3(kcd->ob->imat, v1);
mul_m4_v3(kcd->ob->imat, v2);
@@ -1645,7 +1675,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
knife_project_v2(kcd, v->cageco, s);
d = dist_squared_to_line_segment_v2(s, s1, s2);
if ((d <= vert_tol_sq) &&
- (point_is_visible(kcd, v->cageco, s, &mats, bm_elem_from_knife_vert(v, &kfe_hit))))
+ (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit))))
{
memset(&hit, 0, sizeof(hit));
hit.v = v;
@@ -1708,7 +1738,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
* Need to find 3d intersection of ray through sint */
knife_input_ray_segment(kcd, sint, 1.0f, r1, r2);
isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp);
- if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats, bm_elem_from_knife_edge(kfe))) {
+ if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, bm_elem_from_knife_edge(kfe))) {
memset(&hit, 0, sizeof(hit));
if (kcd->snap_midpoints) {
/* choose intermediate point snap too */
@@ -1737,7 +1767,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
float p[3], p_cage[3];
if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) {
- if (point_is_visible(kcd, p_cage, s1, &mats, (BMElem *)f)) {
+ if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
copy_v3_v3(hit.hit, p);
@@ -1749,7 +1779,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
}
if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) {
- if (point_is_visible(kcd, p_cage, s2, &mats, (BMElem *)f)) {
+ if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
copy_v3_v3(hit.hit, p);
@@ -1782,13 +1812,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs,
float r_origin[3], float r_origin_ofs[3])
{
- bglMats mats;
-
- bgl_get_mats(&mats);
-
/* unproject to find view ray */
- ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f);
- ED_view3d_unproject(&mats, r_origin_ofs, mval[0], mval[1], ofs);
+ ED_view3d_unproject(kcd->vc.ar, mval[0], mval[1], 0.0f, r_origin);
+ ED_view3d_unproject(kcd->vc.ar, mval[0], mval[1], ofs, r_origin_ofs);
/* transform into object space */
invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
@@ -2503,7 +2529,8 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd)
mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]);
normalize_v3(kcd->proj_zaxis);
- kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
+ kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.depsgraph,
+ kcd->vc.v3d, kcd->vc.rv3d,
&kcd->clipsta, &kcd->clipend, true);
}
@@ -2574,7 +2601,7 @@ static void knifetool_init_bmbvh(KnifeTool_OpData *kcd)
{
BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT);
- kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->em, kcd->scene, NULL);
+ kcd->cagecos = (const float (*)[3])BKE_editmesh_vertexCos_get(kcd->vc.depsgraph, kcd->em, kcd->scene, NULL);
kcd->bmbvh = BKE_bmbvh_new_from_editmesh(
kcd->em,
@@ -2734,30 +2761,6 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "Knife Tool Modal Map", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_ANY, KM_ANY, 0, KNF_MODAL_PANNING);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_DBL_CLICK, KM_ANY, 0, KNF_MODAL_ADD_CUT_CLOSED);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KNF_MODAL_ADD_CUT);
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, SPACEKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, 0, 0, KNF_MODAL_NEW_CUT);
-
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_MIDPOINT_ON);
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KNF_MODAL_MIDPOINT_OFF);
- WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_MIDPOINT_ON);
- WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, KNF_MODAL_MIDPOINT_OFF);
-
- WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON);
- WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF);
- WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON);
- WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF);
-
- WM_modalkeymap_add_item(keymap, CKEY, KM_PRESS, 0, 0, KNF_MODAL_ANGLE_SNAP_TOGGLE);
- WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, KNF_MODAL_CUT_THROUGH_TOGGLE);
-
WM_modalkeymap_assign(keymap, "MESH_OT_knife_tool");
return keymap;
@@ -2771,7 +2774,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (!obedit || obedit->type != OB_MESH || BKE_editmesh_from_object(obedit) != kcd->em) {
knifetool_exit(C, op);
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
return OPERATOR_FINISHED;
}
@@ -2792,7 +2795,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_region_tag_redraw(kcd->ar);
knifetool_exit(C, op);
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
return OPERATOR_CANCELLED;
case KNF_MODAL_CONFIRM:
@@ -2801,7 +2804,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
knifetool_finish(op);
knifetool_exit(C, op);
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
return OPERATOR_FINISHED;
case KNF_MODAL_MIDPOINT_ON:
@@ -3008,7 +3011,6 @@ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_through)
{
KnifeTool_OpData *kcd;
- bglMats mats;
view3d_operator_needs_opengl(C);
@@ -3027,10 +3029,6 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
if (use_tag) {
BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false);
}
-
- if (kcd->cut_through == false) {
- bgl_get_mats(&mats);
- }
}
/* execute */
@@ -3139,7 +3137,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
float cent[3], cent_ss[2];
BM_face_calc_point_in_face(f, cent);
knife_project_v2(kcd, cent, cent_ss);
- if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats, (BMElem *)f)) &&
+ if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) &&
edbm_mesh_knife_point_isect(polys, cent_ss))
{
BM_elem_flag_enable(f, BM_ELEM_TAG);
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 0d3cc07589b..da8b8d217d7 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -40,8 +40,11 @@
#include "BKE_curve.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_define.h"
#include "RNA_access.h"
@@ -56,29 +59,32 @@
#include "mesh_intern.h" /* own include */
-static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object *ob, LinkNode *polys)
+static LinkNode *knifeproject_poly_from_object(const bContext *C, Scene *scene, Object *ob, LinkNode *polys)
{
- DerivedMesh *dm;
- bool dm_needsFree;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ARegion *ar = CTX_wm_region(C);
+ struct Mesh *me_eval;
+ bool me_eval_needs_free;
- if (ob->type == OB_MESH || ob->derivedFinal) {
- dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- dm_needsFree = false;
+ if (ob->type == OB_MESH || ob->runtime.mesh_eval) {
+ me_eval = (ob->runtime.mesh_eval ?
+ ob->runtime.mesh_eval : mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH));
+ me_eval_needs_free = false;
}
else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
- dm = CDDM_from_curve(ob);
- dm_needsFree = true;
+ me_eval = BKE_mesh_new_nomain_from_curve(ob);
+ me_eval_needs_free = true;
}
else {
- dm = NULL;
+ me_eval = NULL;
}
- if (dm) {
+ if (me_eval) {
ListBase nurbslist = {NULL, NULL};
float projmat[4][4];
- BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0); /* wire */
- BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1); /* boundary */
+ BKE_mesh_to_curve_nurblist(me_eval, &nurbslist, 0); /* wire */
+ BKE_mesh_to_curve_nurblist(me_eval, &nurbslist, 1); /* boundary */
ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat);
@@ -105,18 +111,16 @@ static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object
BKE_nurbList_free(&nurbslist);
- if (dm_needsFree) {
- dm->release(dm);
+ if (me_eval_needs_free) {
+ BKE_mesh_free(me_eval);
}
}
-
return polys;
}
static int knifeproject_exec(bContext *C, wmOperator *op)
{
- ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -127,7 +131,7 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
if (ob != obedit) {
- polys = knifeproject_poly_from_object(ar, scene, ob, polys);
+ polys = knifeproject_poly_from_object(C, scene, ob, polys);
}
}
CTX_DATA_END;
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 34951a24805..8efec7f4b68 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -38,14 +38,18 @@
#include "BLT_translation.h"
+#include "DNA_mesh_types.h"
+
#include "BKE_context.h"
#include "BKE_modifier.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_unit.h"
+#include "BKE_layer.h"
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "UI_interface.h"
@@ -62,6 +66,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "mesh_intern.h" /* own include */
#define SUBD_SMOOTH_MAX 4.0f
@@ -74,17 +81,21 @@ typedef struct RingSelOpData {
ARegion *ar; /* region that ringsel was activated in */
void *draw_handle; /* for drawing preview loop */
- float (*edges)[2][3];
- int totedge;
-
- float (*points)[3];
- int totpoint;
+ struct EditMesh_PreSelEdgeRing *presel_edgering;
ViewContext vc;
+ Depsgraph *depsgraph;
+
+ Object **objects;
+ uint objects_len;
+
+ /* These values switch objects based on the object under the cursor. */
+ uint ob_index;
Object *ob;
BMEditMesh *em;
BMEdge *eed;
+
NumInput num;
bool extend;
@@ -95,290 +106,32 @@ typedef struct RingSelOpData {
} RingSelOpData;
/* modal loop selection drawing callback */
-static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
+static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
{
- View3D *v3d = CTX_wm_view3d(C);
RingSelOpData *lcd = arg;
-
- if ((lcd->totedge > 0) || (lcd->totpoint > 0)) {
- if (v3d && v3d->zbuf)
- glDisable(GL_DEPTH_TEST);
-
- glPushMatrix();
- glMultMatrixf(lcd->ob->obmat);
-
- glColor3ub(255, 0, 255);
- if (lcd->totedge > 0) {
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, lcd->edges);
- glDrawArrays(GL_LINES, 0, lcd->totedge * 2);
- glDisableClientState(GL_VERTEX_ARRAY);
- }
-
- if (lcd->totpoint > 0) {
- glPointSize(3.0f);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, lcd->points);
- glDrawArrays(GL_POINTS, 0, lcd->totpoint);
- glDisableClientState(GL_VERTEX_ARRAY);
- }
-
- glPopMatrix();
- if (v3d && v3d->zbuf)
- glEnable(GL_DEPTH_TEST);
- }
+ EDBM_preselect_edgering_draw(lcd->presel_edgering, lcd->ob->obmat);
}
-/* given two opposite edges in a face, finds the ordering of their vertices so
- * that cut preview lines won't cross each other */
-static void edgering_find_order(BMEdge *lasteed, BMEdge *eed,
- BMVert *lastv1, BMVert *v[2][2])
+static void edgering_select(RingSelOpData *lcd)
{
- BMIter liter;
- BMLoop *l, *l2;
- int rev;
-
- l = eed->l;
-
- /* find correct order for v[1] */
- if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(lasteed, l->f))) {
- BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) {
- if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(lasteed, l->f))
- break;
- }
- }
-
- /* this should never happen */
- if (!l) {
- v[0][0] = eed->v1;
- v[0][1] = eed->v2;
- v[1][0] = lasteed->v1;
- v[1][1] = lasteed->v2;
+ if (!lcd->eed) {
return;
}
- l2 = BM_loop_other_edge_loop(l, eed->v1);
- rev = (l2 == l->prev);
- while (l2->v != lasteed->v1 && l2->v != lasteed->v2) {
- l2 = rev ? l2->prev : l2->next;
- }
-
- if (l2->v == lastv1) {
- v[0][0] = eed->v1;
- v[0][1] = eed->v2;
- }
- else {
- v[0][0] = eed->v2;
- v[0][1] = eed->v1;
- }
-}
-
-static void edgering_vcos_get(DerivedMesh *dm, BMVert *v[2][2], float r_cos[2][2][3])
-{
- if (dm) {
- int j, k;
- for (j = 0; j < 2; j++) {
- for (k = 0; k < 2; k++) {
- dm->getVertCo(dm, BM_elem_index_get(v[j][k]), r_cos[j][k]);
- }
- }
- }
- else {
- int j, k;
- for (j = 0; j < 2; j++) {
- for (k = 0; k < 2; k++) {
- copy_v3_v3(r_cos[j][k], v[j][k]->co);
- }
- }
- }
-}
-
-static void edgering_vcos_get_pair(DerivedMesh *dm, BMVert *v[2], float r_cos[2][3])
-{
- if (dm) {
- int j;
- for (j = 0; j < 2; j++) {
- dm->getVertCo(dm, BM_elem_index_get(v[j]), r_cos[j]);
- }
- }
- else {
- int j;
- for (j = 0; j < 2; j++) {
- copy_v3_v3(r_cos[j], v[j]->co);
- }
- }
-}
-
-static void edgering_preview_free(RingSelOpData *lcd)
-{
- MEM_SAFE_FREE(lcd->edges);
- lcd->totedge = 0;
-
- MEM_SAFE_FREE(lcd->points);
- lcd->totpoint = 0;
-}
-
-static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, const int previewlines)
-{
- BMesh *bm = lcd->em->bm;
- BMWalker walker;
- BMEdge *eed_start = lcd->eed;
- BMEdge *eed, *eed_last;
- BMVert *v[2][2] = {{NULL}}, *v_last;
- float (*edges)[2][3] = NULL;
- BLI_Stack *edge_stack;
-
- int i, tot = 0;
-
- BMW_init(&walker, bm, BMW_EDGERING,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
-
-
- edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
-
- eed_last = NULL;
- for (eed = eed_last = BMW_begin(&walker, lcd->eed); eed; eed = BMW_step(&walker)) {
- BLI_stack_push(edge_stack, &eed);
- }
- BMW_end(&walker);
-
-
- eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
-
- edges = MEM_mallocN(
- (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines, __func__);
-
- v_last = NULL;
- eed_last = NULL;
-
- while (!BLI_stack_is_empty(edge_stack)) {
- BLI_stack_pop(edge_stack, &eed);
-
- if (eed_last) {
- if (v_last) {
- v[1][0] = v[0][0];
- v[1][1] = v[0][1];
- }
- else {
- v[1][0] = eed_last->v1;
- v[1][1] = eed_last->v2;
- v_last = eed_last->v1;
- }
-
- edgering_find_order(eed_last, eed, v_last, v);
- v_last = v[0][0];
-
- for (i = 1; i <= previewlines; i++) {
- const float fac = (i / ((float)previewlines + 1));
- float v_cos[2][2][3];
-
- edgering_vcos_get(dm, v, v_cos);
-
- interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
- interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
- tot++;
- }
- }
- eed_last = eed;
- }
-
- if ((eed_last != eed_start) &&
-#ifdef BMW_EDGERING_NGON
- BM_edge_share_face_check(eed_last, eed_start)
-#else
- BM_edge_share_quad_check(eed_last, eed_start)
-#endif
- )
- {
- v[1][0] = v[0][0];
- v[1][1] = v[0][1];
-
- edgering_find_order(eed_last, eed_start, v_last, v);
-
- for (i = 1; i <= previewlines; i++) {
- const float fac = (i / ((float)previewlines + 1));
- float v_cos[2][2][3];
-
- if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) {
- continue;
- }
-
- edgering_vcos_get(dm, v, v_cos);
-
- interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
- interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
- tot++;
+ if (!lcd->extend) {
+ for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) {
+ Object *ob_iter = lcd->objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob_iter);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ DEG_id_tag_update(ob_iter->data, DEG_TAG_SELECT_UPDATE);
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, ob_iter->data);
}
}
- BLI_stack_free(edge_stack);
-
- lcd->edges = edges;
- lcd->totedge = tot;
-}
-
-static void edgering_preview_calc_points(RingSelOpData *lcd, DerivedMesh *dm, const int previewlines)
-{
- float v_cos[2][3];
- float (*points)[3];
- int i, tot = 0;
-
- if (dm) {
- BM_mesh_elem_table_ensure(lcd->em->bm, BM_VERT);
- }
-
- points = MEM_mallocN(sizeof(*lcd->points) * previewlines, __func__);
-
- edgering_vcos_get_pair(dm, &lcd->eed->v1, v_cos);
-
- for (i = 1; i <= previewlines; i++) {
- const float fac = (i / ((float)previewlines + 1));
- interp_v3_v3v3(points[tot], v_cos[0], v_cos[1], fac);
- tot++;
- }
-
- lcd->points = points;
- lcd->totpoint = previewlines;
-}
-
-static void edgering_preview_calc(RingSelOpData *lcd, const int previewlines)
-{
- DerivedMesh *dm;
-
- BLI_assert(lcd->eed != NULL);
-
- edgering_preview_free(lcd);
-
- dm = EDBM_mesh_deform_dm_get(lcd->em);
- if (dm) {
- BM_mesh_elem_table_ensure(lcd->em->bm, BM_VERT);
- }
-
- if (BM_edge_is_wire(lcd->eed)) {
- edgering_preview_calc_points(lcd, dm, previewlines);
- }
- else {
- edgering_preview_calc_edges(lcd, dm, previewlines);
- }
-}
-
-static void edgering_select(RingSelOpData *lcd)
-{
BMEditMesh *em = lcd->em;
BMEdge *eed_start = lcd->eed;
BMWalker walker;
BMEdge *eed;
-
- if (!eed_start)
- return;
-
- if (!lcd->extend) {
- EDBM_flag_disable_all(lcd->em, BM_ELEM_SELECT);
- }
-
BMW_init(&walker, em->bm, BMW_EDGERING,
BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
@@ -393,10 +146,17 @@ static void edgering_select(RingSelOpData *lcd)
static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
{
if (lcd->eed) {
- edgering_preview_calc(lcd, previewlines);
+ const float (*coords)[3] = NULL;
+ {
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(lcd->depsgraph, lcd->ob->data);
+ if (me_eval->runtime.edit_data) {
+ coords = me_eval->runtime.edit_data->vertexCos;
+ }
+ }
+ EDBM_preselect_edgering_update_from_edge(lcd->presel_edgering, lcd->em->bm, lcd->eed, previewlines, coords);
}
else {
- edgering_preview_free(lcd);
+ EDBM_preselect_edgering_clear(lcd->presel_edgering);
}
}
@@ -467,6 +227,7 @@ static void ringsel_finish(bContext *C, wmOperator *op)
BM_select_history_store(em->bm, lcd->eed);
EDBM_selectmode_flush(lcd->em);
+ DEG_id_tag_update(lcd->ob->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, lcd->ob->data);
}
}
@@ -480,7 +241,9 @@ static void ringsel_exit(bContext *UNUSED(C), wmOperator *op)
/* deactivate the extra drawing stuff in 3D-View */
ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle);
- edgering_preview_free(lcd);
+ EDBM_preselect_edgering_destroy(lcd->presel_edgering);
+
+ MEM_freeN(lcd->objects);
ED_region_tag_redraw(lcd->ar);
@@ -499,11 +262,17 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
/* alloc new customdata */
lcd = op->customdata = MEM_callocN(sizeof(RingSelOpData), "ringsel Modal Op Data");
+ em_setup_viewcontext(C, &lcd->vc);
+
+ lcd->depsgraph = CTX_data_depsgraph(C);
+
/* assign the drawing handle for drawing preview line... */
lcd->ar = CTX_wm_region(C);
lcd->draw_handle = ED_region_draw_cb_activate(lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST_VIEW);
- lcd->ob = CTX_data_edit_object(C);
- lcd->em = BKE_editmesh_from_object(lcd->ob);
+ lcd->presel_edgering = EDBM_preselect_edgering_create();
+ /* Initialize once the cursor is over a mesh. */
+ lcd->ob = NULL;
+ lcd->em = NULL;
lcd->extend = do_cut ? false : RNA_boolean_get(op->ptr, "extend");
lcd->do_cut = do_cut;
lcd->cuts = RNA_int_get(op->ptr, "number_cuts");
@@ -517,8 +286,6 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
lcd->num.unit_type[0] = B_UNIT_NONE;
lcd->num.unit_type[1] = B_UNIT_NONE;
- em_setup_viewcontext(C, &lcd->vc);
-
ED_region_tag_redraw(lcd->ar);
return 1;
@@ -530,44 +297,102 @@ static void ringcut_cancel(bContext *C, wmOperator *op)
ringsel_exit(C, op);
}
-static void loopcut_update_edge(RingSelOpData *lcd, BMEdge *e, const int previewlines)
+static void loopcut_update_edge(RingSelOpData *lcd, uint ob_index, BMEdge *e, const int previewlines)
{
if (e != lcd->eed) {
lcd->eed = e;
+ lcd->ob = lcd->vc.obedit;
+ lcd->ob_index = ob_index;
+ lcd->em = lcd->vc.em;
ringsel_find_edge(lcd, previewlines);
}
+ else if (e == NULL) {
+ lcd->ob = NULL;
+ lcd->em = NULL;
+ lcd->ob_index = UINT_MAX;
+ }
}
static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines)
{
- float dist = ED_view3d_select_dist_px();
- BMEdge *e = EDBM_edge_find_nearest(&lcd->vc, &dist);
- loopcut_update_edge(lcd, e, previewlines);
+ struct {
+ Object *ob;
+ BMEdge *eed;
+ float dist;
+ int ob_index;
+ } best = {
+ .dist = ED_view3d_select_dist_px(),
+ };
+
+ for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) {
+ Object *ob_iter = lcd->objects[ob_index];
+ ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter);
+ BMEdge *eed_test = EDBM_edge_find_nearest_ex(&lcd->vc, &best.dist, NULL, false, false, NULL);
+ if (eed_test) {
+ best.ob = ob_iter;
+ best.eed = eed_test;
+ best.ob_index = ob_index;
+ }
+ }
+
+ if (best.eed) {
+ ED_view3d_viewcontext_init_object(&lcd->vc, best.ob);
+ }
+
+ loopcut_update_edge(lcd, best.ob_index, best.eed, previewlines);
}
/* called by both init() and exec() */
static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
{
const bool is_interactive = (event != NULL);
- Object *obedit = CTX_data_edit_object(C);
- RingSelOpData *lcd;
- if (modifiers_isDeformedByLattice(obedit) || modifiers_isDeformedByArmature(obedit))
- BKE_report(op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display");
+ /* Use for redo - intentionally wrap int to uint. */
+ const struct {
+ uint ob_index;
+ uint e_index;
+ } exec_data = {
+ .ob_index = (uint)RNA_int_get(op->ptr, "object_index"),
+ .e_index = (uint)RNA_int_get(op->ptr, "edge_index"),
+ };
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ if (is_interactive) {
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) {
+ BKE_report(op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display");
+ break;
+ }
+ }
+ }
view3d_operator_needs_opengl(C);
/* for re-execution, check edge index is in range before we setup ringsel */
+ bool ok = true;
if (is_interactive == false) {
- const int e_index = RNA_int_get(op->ptr, "edge_index");
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (UNLIKELY((e_index == -1) || (e_index >= em->bm->totedge))) {
+ if (exec_data.ob_index >= objects_len) {
return OPERATOR_CANCELLED;
+ ok = false;
+ }
+ else {
+ Object *ob_iter = objects[exec_data.ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob_iter);
+ if (exec_data.e_index >= em->bm->totedge) {
+ ok = false;
+ }
}
}
- if (!ringsel_init(C, op, true))
+ if (!ok || !ringsel_init(C, op, true)) {
+ MEM_freeN(objects);
return OPERATOR_CANCELLED;
+ }
/* add a modal handler for this operator - handles loop selection */
if (is_interactive) {
@@ -575,18 +400,24 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
WM_event_add_modal_handler(C, op);
}
- lcd = op->customdata;
+ RingSelOpData *lcd = op->customdata;
+
+ lcd->objects = objects;
+ lcd->objects_len = objects_len;
if (is_interactive) {
copy_v2_v2_int(lcd->vc.mval, event->mval);
loopcut_mouse_move(lcd, is_interactive ? 1 : 0);
}
else {
- const int e_index = RNA_int_get(op->ptr, "edge_index");
+
+ Object *ob_iter = objects[exec_data.ob_index];
+ ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter);
+
BMEdge *e;
- BM_mesh_elem_table_ensure(lcd->em->bm, BM_EDGE);
- e = BM_edge_at_index(lcd->em->bm, e_index);
- loopcut_update_edge(lcd, e, 0);
+ BM_mesh_elem_table_ensure(lcd->vc.em->bm, BM_EDGE);
+ e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index);
+ loopcut_update_edge(lcd, exec_data.ob_index, e, 0);
}
#ifdef USE_LOOPSLIDE_HACK
@@ -605,8 +436,7 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
#endif
if (is_interactive) {
- ScrArea *sa = CTX_wm_area(C);
- ED_area_headerprint(sa, IFACE_("Select a ring to be cut, use mouse-wheel or page-up/down for number of cuts, "
+ ED_workspace_status_text(C, IFACE_("Select a ring to be cut, use mouse-wheel or page-up/down for number of cuts, "
"hold Alt for smooth"));
return OPERATOR_RUNNING_MODAL;
}
@@ -619,6 +449,25 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ /* When accessed as a tool, get the active edge from the preselection gizmo. */
+ {
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_mesh_preselect_edgering") : NULL;
+ if ((gzgroup != NULL) && gzgroup->gizmos.first) {
+ wmGizmo *gz = gzgroup->gizmos.first;
+ const int object_index = RNA_int_get(gz->ptr, "object_index");
+ const int edge_index = RNA_int_get(gz->ptr, "edge_index");
+
+ if (object_index != -1 && edge_index != -1) {
+ RNA_int_set(op->ptr, "object_index", object_index);
+ RNA_int_set(op->ptr, "edge_index", edge_index);
+ return loopcut_init(C, op, NULL);
+ }
+ return OPERATOR_CANCELLED;
+ }
+ }
+
return loopcut_init(C, op, event);
}
@@ -631,11 +480,12 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op)
{
/* finish */
ED_region_tag_redraw(lcd->ar);
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
if (lcd->eed) {
/* set for redo */
BM_mesh_elem_index_ensure(lcd->em->bm, BM_EDGE);
+ RNA_int_set(op->ptr, "object_index", lcd->ob_index);
RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed));
/* execute */
@@ -686,14 +536,14 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE: /* abort */ // XXX hardcoded
ED_region_tag_redraw(lcd->ar);
ringsel_exit(C, op);
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
return OPERATOR_CANCELLED;
case ESCKEY:
if (event->val == KM_RELEASE) {
/* cancel */
ED_region_tag_redraw(lcd->ar);
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
ringcut_cancel(C, op);
return OPERATOR_CANCELLED;
@@ -798,7 +648,7 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
BLI_snprintf(buf, sizeof(buf), IFACE_("Number of Cuts: %s, Smooth: %s (Alt)"),
str_rep, str_rep + NUM_STR_REP_LEN);
- ED_area_headerprint(CTX_wm_area(C), buf);
+ ED_workspace_status_text(C, buf);
}
/* keep going until the user confirms */
@@ -855,12 +705,17 @@ void MESH_OT_loopcut(wmOperatorType *ot)
"Smoothness", "Smoothness factor", -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ WM_operatortype_props_advanced_begin(ot);
+
prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items);
RNA_def_property_enum_default(prop, PROP_INVSQUARE);
RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ /* For redo only. */
+ prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_int(ot->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index eccc15bf83f..7f47d1b3dcc 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -29,6 +29,8 @@
* \ingroup edmesh
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
@@ -41,10 +43,12 @@
#include "BLI_math.h"
#include "BLI_linklist.h"
+#include "BKE_layer.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_report.h"
+#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_uvedit.h"
@@ -59,6 +63,8 @@
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "DEG_depsgraph.h"
+
#include "mesh_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -126,10 +132,9 @@ static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
}
static void mouse_mesh_shortest_path_vert(
- Scene *scene, const struct PathSelectParams *op_params,
+ Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params,
BMVert *v_act, BMVert *v_dst)
{
- Object *obedit = scene->obedit;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
@@ -287,11 +292,11 @@ static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
}
}
-static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
+static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
{
BMesh *bm = me->edit_btmesh->bm;
- switch (scene->toolsettings->edge_mode) {
+ switch (edge_mode) {
case EDGE_MODE_TAG_CREASE:
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
break;
@@ -314,19 +319,17 @@ static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
/* since you want to create paths with multiple selects, it doesn't have extend option */
static void mouse_mesh_shortest_path_edge(
- Scene *scene, const struct PathSelectParams *op_params,
+ Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params,
BMEdge *e_act, BMEdge *e_dst)
{
- Object *obedit = scene->obedit;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
struct UserData user_data = {bm, obedit->data, op_params};
LinkNode *path = NULL;
- Mesh *me = obedit->data;
bool is_path_ordered = false;
- edgetag_ensure_cd_flag(scene, obedit->data);
+ edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode);
if (e_act && (e_act != e_dst)) {
if (op_params->use_fill) {
@@ -385,7 +388,7 @@ static void mouse_mesh_shortest_path_edge(
}
else {
const bool is_act = !edgetag_test_cb(e_dst, &user_data);
- edgetag_ensure_cd_flag(scene, obedit->data);
+ edgetag_ensure_cd_flag(obedit->data, op_params->edge_mode);
edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
}
@@ -411,29 +414,6 @@ static void mouse_mesh_shortest_path_edge(
}
}
- /* force drawmode for mesh */
- switch (op_params->edge_mode) {
-
- case EDGE_MODE_TAG_SEAM:
- me->drawflag |= ME_DRAWSEAMS;
- ED_uvedit_live_unwrap(scene, obedit);
- break;
- case EDGE_MODE_TAG_SHARP:
- me->drawflag |= ME_DRAWSHARP;
- break;
- case EDGE_MODE_TAG_CREASE:
- me->drawflag |= ME_DRAWCREASES;
- break;
- case EDGE_MODE_TAG_BEVEL:
- me->drawflag |= ME_DRAWBWEIGHTS;
- break;
-#ifdef WITH_FREESTYLE
- case EDGE_MODE_TAG_FREESTYLE:
- me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
- break;
-#endif
- }
-
EDBM_update_generic(em, false, false);
}
@@ -461,10 +441,9 @@ static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
}
static void mouse_mesh_shortest_path_face(
- Scene *scene, const struct PathSelectParams *op_params,
+ Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params,
BMFace *f_act, BMFace *f_dst)
{
- Object *obedit = scene->obedit;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
@@ -557,23 +536,23 @@ static void mouse_mesh_shortest_path_face(
* \{ */
static bool edbm_shortest_path_pick_ex(
- Scene *scene, const struct PathSelectParams *op_params,
+ Scene *scene, Object *obedit, const struct PathSelectParams *op_params,
BMElem *ele_src, BMElem *ele_dst)
{
- if (ELEM(NULL, ele_src, ele_dst) && (ele_src->head.htype != ele_dst->head.htype)) {
+ if (ELEM(NULL, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) {
/* pass */
}
else if (ele_src->head.htype == BM_VERT) {
- mouse_mesh_shortest_path_vert(scene, op_params, (BMVert *)ele_src, (BMVert *)ele_dst);
+ mouse_mesh_shortest_path_vert(scene, obedit, op_params, (BMVert *)ele_src, (BMVert *)ele_dst);
return true;
}
else if (ele_src->head.htype == BM_EDGE) {
- mouse_mesh_shortest_path_edge(scene, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst);
+ mouse_mesh_shortest_path_edge(scene, obedit, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst);
return true;
}
else if (ele_src->head.htype == BM_FACE) {
- mouse_mesh_shortest_path_face(scene, op_params, (BMFace *)ele_src, (BMFace *)ele_dst);
+ mouse_mesh_shortest_path_face(scene, obedit, op_params, (BMFace *)ele_src, (BMFace *)ele_dst);
return true;
}
@@ -617,6 +596,11 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
return edbm_shortest_path_pick_exec(C, op);
}
+ Base *basact = NULL;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+
ViewContext vc;
BMEditMesh *em;
bool track_active = true;
@@ -627,6 +611,28 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
view3d_operator_needs_opengl(C);
+ {
+ int base_index = -1;
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
+ if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) {
+ basact = bases[base_index];
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ em = vc.em;
+ }
+ MEM_freeN(bases);
+ }
+
+ /* If nothing is selected, let's select the picked vertex/edge/face. */
+ if ((vc.em->bm->totvertsel == 0) && (eve || eed || efa)) {
+ /* TODO (dfelinto) right now we try to find the closest element twice.
+ * The ideal is to refactor EDBM_select_pick so it doesn't
+ * have to pick the nearest vert/edge/face again.
+ */
+ EDBM_select_pick(C, event->mval, true, false, false);
+ return OPERATOR_FINISHED;
+ }
+
BMElem *ele_src, *ele_dst;
if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
!(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype)))
@@ -652,10 +658,14 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
op_params.track_active = track_active;
op_params.edge_mode = vc.scene->toolsettings->edge_mode;
- if (!edbm_shortest_path_pick_ex(vc.scene, &op_params, ele_src, ele_dst)) {
+ if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) {
return OPERATOR_PASS_THROUGH;
}
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
/* to support redo */
BM_mesh_elem_index_ensure(em->bm, ele_dst->head.htype);
int index = EDBM_elem_to_index_any(em, ele_dst);
@@ -689,7 +699,7 @@ static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op)
op_params.track_active = true;
op_params.edge_mode = scene->toolsettings->edge_mode;
- if (!edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst)) {
+ if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) {
return OPERATOR_CANCELLED;
}
@@ -730,67 +740,87 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMesh *bm = em->bm;
- BMIter iter;
- BMEditSelection *ese_src, *ese_dst;
- BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
+ bool found_valid_elements = false;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEditSelection *ese_src, *ese_dst;
+ BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
+
+ if ((em->bm->totvertsel == 0) &&
+ (em->bm->totedgesel == 0) &&
+ (em->bm->totfacesel == 0))
+ {
+ continue;
+ }
- /* first try to find vertices in edit selection */
- ese_src = bm->selected.last;
- if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
- ele_src = ese_src->ele;
- ele_dst = ese_dst->ele;
- }
- else {
- /* if selection history isn't available, find two selected elements */
- ele_src = ele_dst = NULL;
- if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) {
- BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
- if (ele_src == NULL) ele_src = ele;
- else if (ele_dst == NULL) ele_dst = ele;
- else break;
+ /* first try to find vertices in edit selection */
+ ese_src = bm->selected.last;
+ if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
+ ele_src = ese_src->ele;
+ ele_dst = ese_dst->ele;
+ }
+ else {
+ /* if selection history isn't available, find two selected elements */
+ ele_src = ele_dst = NULL;
+ if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) {
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+ if (ele_src == NULL) ele_src = ele;
+ else if (ele_dst == NULL) ele_dst = ele;
+ else break;
+ }
}
}
- }
- if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) {
- ele_src = NULL;
- BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
- if (ele_src == NULL) ele_src = ele;
- else if (ele_dst == NULL) ele_dst = ele;
- else break;
+ if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) {
+ ele_src = NULL;
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+ if (ele_src == NULL) ele_src = ele;
+ else if (ele_dst == NULL) ele_dst = ele;
+ else break;
+ }
}
}
- }
- if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) {
- ele_src = NULL;
- BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
- if (ele_src == NULL) ele_src = ele;
- else if (ele_dst == NULL) ele_dst = ele;
- else break;
+ if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) {
+ ele_src = NULL;
+ BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+ if (ele_src == NULL) ele_src = ele;
+ else if (ele_dst == NULL) ele_dst = ele;
+ else break;
+ }
}
}
}
- }
- if (ele_src && ele_dst) {
- struct PathSelectParams op_params;
- path_select_params_from_op(op, &op_params);
+ if (ele_src && ele_dst) {
+ struct PathSelectParams op_params;
+ path_select_params_from_op(op, &op_params);
- edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst);
+ edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst);
- return OPERATOR_FINISHED;
+ found_valid_elements = true;
+ }
}
- else {
- BKE_report(op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
+ MEM_freeN(objects);
+
+ if (!found_valid_elements) {
+ BKE_report(op->reports,
+ RPT_WARNING,
+ "Path selection requires two matching elements to be selected");
return OPERATOR_CANCELLED;
}
+
+ return OPERATOR_FINISHED;
}
void MESH_OT_shortest_path_select(wmOperatorType *ot)
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
new file mode 100644
index 00000000000..292799e618f
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -0,0 +1,499 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_polybuild.c
+ * \ingroup edmesh
+ *
+ * Tools to implement polygon building tool,
+ * an experimental tool for quickly constructing/manipulating faces.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_layer.h"
+
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_mesh.h"
+#include "ED_scene.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_view3d.h"
+
+#include "bmesh.h"
+
+#include "mesh_intern.h" /* own include */
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+
+#include "DEG_depsgraph.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Local Utilities
+ * \{ */
+
+static void edbm_selectmode_ensure(Scene *scene, BMEditMesh *em, short selectmode)
+{
+ if ((scene->toolsettings->selectmode & selectmode) == 0) {
+ scene->toolsettings->selectmode |= selectmode;
+ em->selectmode = scene->toolsettings->selectmode;
+ EDBM_selectmode_set(em);
+ }
+}
+
+/* Could make public, for now just keep here. */
+static void edbm_flag_disable_all_multi(ViewLayer *view_layer, View3D *v3d, const char hflag)
+{
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ BMesh *bm_iter = em_iter->bm;
+ if (bm_iter->totvertsel) {
+ EDBM_flag_disable_all(em_iter, hflag);
+ DEG_id_tag_update(ob_iter->data, DEG_TAG_SELECT_UPDATE);
+ }
+ }
+ MEM_freeN(objects);
+}
+
+/* When accessed as a tool, get the active edge from the preselection gizmo. */
+static bool edbm_preselect_or_active(
+ bContext *C,
+ Base **r_base,
+ BMElem **r_ele)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_mesh_preselect_elem") : NULL;
+ if (gzgroup != NULL) {
+ wmGizmo *gz = gzgroup->gizmos.first;
+ const int object_index = RNA_int_get(gz->ptr, "object_index");
+
+ /* weak, allocate an array just to access the index. */
+ Base *base = NULL;
+ Object *obedit = NULL;
+ {
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(view_layer, CTX_wm_view3d(C), &bases_len);
+ if (object_index < bases_len) {
+ base = bases[object_index];
+ obedit = base->object;
+ }
+ MEM_freeN(bases);
+ }
+
+ *r_base = base;
+ *r_ele = NULL;
+
+ if (obedit) {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const int vert_index = RNA_int_get(gz->ptr, "vert_index");
+ const int edge_index = RNA_int_get(gz->ptr, "edge_index");
+ const int face_index = RNA_int_get(gz->ptr, "face_index");
+ if (vert_index != -1) {
+ *r_ele = (BMElem *)BM_vert_at_index_find(bm, vert_index);
+ }
+ else if (edge_index != -1) {
+ *r_ele = (BMElem *)BM_edge_at_index_find(bm, edge_index);
+ }
+ else if (face_index != -1) {
+ *r_ele = (BMElem *)BM_face_at_index_find(bm, face_index);
+ }
+ }
+ }
+ else {
+ Base *base = view_layer->basact;
+ Object *obedit = base->object;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ *r_base = base;
+ *r_ele = BM_mesh_active_elem_get(bm);
+ }
+ return (*r_ele != NULL);
+}
+
+static bool edbm_preselect_or_active_init_viewcontext(
+ bContext *C,
+ ViewContext *vc,
+ Base **r_base,
+ BMElem **r_ele)
+{
+ em_setup_viewcontext(C, vc);
+ bool ok = edbm_preselect_or_active(C, r_base, r_ele);
+ if (ok) {
+ ED_view3d_viewcontext_init_object(vc, (*r_base)->object);
+ }
+ return ok;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Face at Cursor
+ * \{ */
+
+static int edbm_polybuild_face_at_cursor_invoke(
+ bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ float center[3];
+ bool changed = false;
+
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ if (ele_act == NULL || ele_act->head.htype == BM_FACE) {
+ /* Just add vert */
+ copy_v3_v3(center, vc.scene->cursor.location);
+ mul_v3_m4v3(center, vc.obedit->obmat, center);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
+ mul_m4_v3(vc.obedit->imat, center);
+
+ BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_new, true);
+ BM_select_history_store(bm, v_new);
+ changed = true;
+ }
+ else if (ele_act->head.htype == BM_EDGE) {
+ BMEdge *e_act = (BMEdge *)ele_act;
+ BMFace *f_reference = e_act->l ? e_act->l->f : NULL;
+
+ mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co);
+ mul_m4_v3(vc.obedit->obmat, center);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
+ mul_m4_v3(vc.obedit->imat, center);
+
+ BMVert *v_tri[3];
+ v_tri[0] = e_act->v1;
+ v_tri[1] = e_act->v2;
+ v_tri[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
+ if (e_act->l && e_act->l->v == v_tri[0]) {
+ SWAP(BMVert *, v_tri[0], v_tri[1]);
+ }
+ // BMFace *f_new =
+ BM_face_create_verts(bm, v_tri, 3, f_reference, BM_CREATE_NOP, true);
+
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_tri[2], true);
+ BM_select_history_store(bm, v_tri[2]);
+ changed = true;
+ }
+ else if (ele_act->head.htype == BM_VERT) {
+ BMVert *v_act = (BMVert *)ele_act;
+ BMEdge *e_pair[2] = {NULL};
+
+ if (v_act->e != NULL) {
+ for (uint allow_wire = 0; allow_wire < 2 && (e_pair[1] == NULL); allow_wire++) {
+ int i = 0;
+ BMEdge *e_iter = v_act->e;
+ do {
+ if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) &&
+ (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter)))
+ {
+ if (i == 2) {
+ e_pair[0] = e_pair[1] = NULL;
+ break;
+ }
+ e_pair[i++] = e_iter;
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_act)) != v_act->e);
+ }
+ }
+
+ if (e_pair[1] != NULL) {
+ /* Quad from edge pair. */
+ if (BM_edge_calc_length_squared(e_pair[0]) <
+ BM_edge_calc_length_squared(e_pair[1]))
+ {
+ SWAP(BMEdge *, e_pair[0], e_pair[1]);
+ }
+
+ BMFace *f_reference = e_pair[0]->l ? e_pair[0]->l->f : NULL;
+
+ mul_v3_m4v3(center, vc.obedit->obmat, v_act->co);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
+ mul_m4_v3(vc.obedit->imat, center);
+
+ BMVert *v_quad[4];
+ v_quad[0] = v_act;
+ v_quad[1] = BM_edge_other_vert(e_pair[0], v_act);
+ v_quad[2] = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
+ v_quad[3] = BM_edge_other_vert(e_pair[1], v_act);
+ if (e_pair[0]->l && e_pair[0]->l->v == v_quad[0]) {
+ SWAP(BMVert *, v_quad[1], v_quad[3]);
+ }
+ // BMFace *f_new =
+ BM_face_create_verts(bm, v_quad, 4, f_reference, BM_CREATE_NOP, true);
+
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_quad[2], true);
+ BM_select_history_store(bm, v_quad[2]);
+ changed = true;
+ }
+ else {
+ /* Just add edge */
+ mul_m4_v3(vc.obedit->obmat, center);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, v_act->co, event->mval, center);
+ mul_m4_v3(vc.obedit->imat, center);
+
+ BMVert *v_new = BM_vert_create(bm, center, NULL, BM_CREATE_NOP);
+
+ BM_edge_create(bm, v_act, v_new, NULL, BM_CREATE_NOP);
+
+ BM_vert_select_set(bm, v_new, true);
+ BM_select_history_store(bm, v_new);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+
+ if (basact != NULL) {
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
+
+ WM_event_add_mousemove(C);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_polybuild_face_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Face at Cursor";
+ ot->idname = "MESH_OT_polybuild_face_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_face_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split at Cursor
+ * \{ */
+
+static int edbm_polybuild_split_at_cursor_invoke(
+ bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ float center[3];
+ bool changed = false;
+
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+
+ edbm_selectmode_ensure(vc.scene, vc.em, SCE_SELECT_VERTEX);
+
+ if (ele_act == NULL || ele_act->head.hflag == BM_FACE) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ else if (ele_act->head.htype == BM_EDGE) {
+ BMEdge *e_act = (BMEdge *)ele_act;
+ mid_v3_v3v3(center, e_act->v1->co, e_act->v2->co);
+ mul_m4_v3(vc.obedit->obmat, center);
+ ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
+ mul_m4_v3(vc.obedit->imat, center);
+
+ const float fac = line_point_factor_v3(center, e_act->v1->co, e_act->v2->co);
+ BMVert *v_new = BM_edge_split(bm, e_act, e_act->v1, NULL, CLAMPIS(fac, 0.0f, 1.0f));
+ copy_v3_v3(v_new->co, center);
+
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+ BM_vert_select_set(bm, v_new, true);
+ BM_select_history_store(bm, v_new);
+ changed = true;
+ }
+ else if (ele_act->head.htype == BM_VERT) {
+ /* Just do nothing, allow dragging. */
+ return OPERATOR_FINISHED;
+ }
+
+ if (changed) {
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+
+ WM_event_add_mousemove(C);
+
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_polybuild_split_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Split at Cursor";
+ ot->idname = "MESH_OT_polybuild_split_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_split_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve at Cursor
+ *
+ * \{ */
+
+static int edbm_polybuild_dissolve_at_cursor_invoke(
+ bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ bool changed = false;
+
+ ViewContext vc;
+ Base *basact = NULL;
+ BMElem *ele_act = NULL;
+ edbm_preselect_or_active_init_viewcontext(C, &vc, &basact, &ele_act);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
+ if (ele_act == NULL) {
+ /* pass */
+ }
+ else if (ele_act->head.htype == BM_EDGE) {
+ BMEdge *e_act = (BMEdge *)ele_act;
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(e_act, &l_a, &l_b)) {
+ BMFace *f_new = BM_faces_join_pair(bm, l_a, l_b, true);
+ if (f_new) {
+ changed = true;
+ }
+ }
+ }
+ else if (ele_act->head.htype == BM_VERT) {
+ BMVert *v_act = (BMVert *)ele_act;
+ if (BM_vert_is_edge_pair(v_act)) {
+ BM_edge_collapse(
+ bm, v_act->e, v_act,
+ true, true);
+ }
+ else {
+ /* too involved to do inline */
+
+ /* Avoid using selection so failure wont leave modified state. */
+ EDBM_flag_disable_all(em, BM_ELEM_TAG);
+ BM_elem_flag_enable(v_act, BM_ELEM_TAG);
+
+ if (!EDBM_op_callf(em, op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG, false, false))
+ {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ changed = true;
+ }
+
+ if (changed) {
+ edbm_flag_disable_all_multi(vc.view_layer, vc.v3d, BM_ELEM_SELECT);
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+
+ WM_event_add_mousemove(C);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_polybuild_dissolve_at_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Poly Build Dissolve at Cursor";
+ ot->idname = "MESH_OT_polybuild_dissolve_at_cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_polybuild_dissolve_at_cursor_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_preselect_edgering.c b/source/blender/editors/mesh/editmesh_preselect_edgering.c
new file mode 100644
index 00000000000..3b31b9c15f6
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_preselect_edgering.c
@@ -0,0 +1,354 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_preselect_edgering.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_stack.h"
+#include "BLI_math.h"
+
+#include "BKE_editmesh.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "ED_mesh.h"
+
+#include "UI_resources.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Edge Ring Pre-Select
+ * Public API:
+ *
+ * #EDBM_preselect_edgering_create
+ * #EDBM_preselect_edgering_destroy
+ * #EDBM_preselect_edgering_clear
+ * #EDBM_preselect_edgering_draw
+ * #EDBM_preselect_edgering_update_from_edge
+ *
+ * \{ */
+
+static void edgering_vcos_get(BMVert *v[2][2], float r_cos[2][2][3], const float (*coords)[3])
+{
+ if (coords) {
+ int j, k;
+ for (j = 0; j < 2; j++) {
+ for (k = 0; k < 2; k++) {
+ copy_v3_v3(r_cos[j][k], coords[BM_elem_index_get(v[j][k])]);
+ }
+ }
+ }
+ else {
+ int j, k;
+ for (j = 0; j < 2; j++) {
+ for (k = 0; k < 2; k++) {
+ copy_v3_v3(r_cos[j][k], v[j][k]->co);
+ }
+ }
+ }
+}
+
+static void edgering_vcos_get_pair(BMVert *v[2], float r_cos[2][3], const float (*coords)[3])
+{
+ if (coords) {
+ int j;
+ for (j = 0; j < 2; j++) {
+ copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]);
+ }
+ }
+ else {
+ int j;
+ for (j = 0; j < 2; j++) {
+ copy_v3_v3(r_cos[j], v[j]->co);
+ }
+ }
+}
+
+
+/**
+ * Given two opposite edges in a face, finds the ordering of their vertices so
+ * that cut preview lines won't cross each other.
+ */
+static void edgering_find_order(
+ BMEdge *eed_last, BMEdge *eed,
+ BMVert *eve_last, BMVert *v[2][2])
+{
+ BMLoop *l = eed->l;
+
+ /* find correct order for v[1] */
+ if (!(BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))) {
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, l, BM_LOOPS_OF_LOOP) {
+ if (BM_edge_in_face(eed, l->f) && BM_edge_in_face(eed_last, l->f))
+ break;
+ }
+ }
+
+ /* this should never happen */
+ if (!l) {
+ v[0][0] = eed->v1;
+ v[0][1] = eed->v2;
+ v[1][0] = eed_last->v1;
+ v[1][1] = eed_last->v2;
+ return;
+ }
+
+ BMLoop *l_other = BM_loop_other_edge_loop(l, eed->v1);
+ const bool rev = (l_other == l->prev);
+ while (l_other->v != eed_last->v1 && l_other->v != eed_last->v2) {
+ l_other = rev ? l_other->prev : l_other->next;
+ }
+
+ if (l_other->v == eve_last) {
+ v[0][0] = eed->v1;
+ v[0][1] = eed->v2;
+ }
+ else {
+ v[0][0] = eed->v2;
+ v[0][1] = eed->v1;
+ }
+}
+
+struct EditMesh_PreSelEdgeRing {
+ float (*edges)[2][3];
+ int edges_len;
+
+ float (*verts)[3];
+ int verts_len;
+};
+
+struct EditMesh_PreSelEdgeRing *EDBM_preselect_edgering_create(void)
+{
+ struct EditMesh_PreSelEdgeRing *psel = MEM_callocN(sizeof(*psel), __func__);
+ return psel;
+}
+
+void EDBM_preselect_edgering_destroy(
+ struct EditMesh_PreSelEdgeRing *psel)
+{
+ EDBM_preselect_edgering_clear(psel);
+ MEM_freeN(psel);
+}
+
+void EDBM_preselect_edgering_clear(
+ struct EditMesh_PreSelEdgeRing *psel)
+{
+ MEM_SAFE_FREE(psel->edges);
+ psel->edges_len = 0;
+
+ MEM_SAFE_FREE(psel->verts);
+ psel->verts_len = 0;
+}
+
+void EDBM_preselect_edgering_draw(
+ struct EditMesh_PreSelEdgeRing *psel, const float matrix[4][4])
+{
+ if ((psel->edges_len == 0) && (psel->verts_len == 0)) {
+ return;
+ }
+
+ GPU_depth_test(false);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor3(TH_GIZMO_PRIMARY);
+
+ if (psel->edges_len > 0) {
+ immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
+
+ for (int i = 0; i < psel->edges_len; i++) {
+ immVertex3fv(pos, psel->edges[i][0]);
+ immVertex3fv(pos, psel->edges[i][1]);
+ }
+
+ immEnd();
+ }
+
+ if (psel->verts_len > 0) {
+ GPU_point_size(3.0f);
+
+ immBegin(GPU_PRIM_POINTS, psel->verts_len);
+
+ for (int i = 0; i < psel->verts_len; i++) {
+ immVertex3fv(pos, psel->verts[i]);
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+
+ /* Reset default */
+ GPU_depth_test(true);
+}
+
+static void view3d_preselect_mesh_edgering_update_verts_from_edge(
+ struct EditMesh_PreSelEdgeRing *psel,
+ BMesh *UNUSED(bm), BMEdge *eed_start, int previewlines, const float (*coords)[3])
+{
+ float v_cos[2][3];
+ float (*verts)[3];
+ int i, tot = 0;
+
+ verts = MEM_mallocN(sizeof(*psel->verts) * previewlines, __func__);
+
+ edgering_vcos_get_pair(&eed_start->v1, v_cos, coords);
+
+ for (i = 1; i <= previewlines; i++) {
+ const float fac = (i / ((float)previewlines + 1));
+ interp_v3_v3v3(verts[tot], v_cos[0], v_cos[1], fac);
+ tot++;
+ }
+
+ psel->verts = verts;
+ psel->verts_len = previewlines;
+}
+
+static void view3d_preselect_mesh_edgering_update_edges_from_edge(
+ struct EditMesh_PreSelEdgeRing *psel,
+ BMesh *bm, BMEdge *eed_start, int previewlines, const float (*coords)[3])
+{
+ BMWalker walker;
+ BMEdge *eed, *eed_last;
+ BMVert *v[2][2] = {{NULL}}, *eve_last;
+ float (*edges)[2][3] = NULL;
+ BLI_Stack *edge_stack;
+
+ int i, tot = 0;
+
+ BMW_init(&walker, bm, BMW_EDGERING,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+
+ edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
+
+ eed_last = NULL;
+ for (eed = eed_last = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
+ BLI_stack_push(edge_stack, &eed);
+ }
+ BMW_end(&walker);
+
+
+ eed_start = *(BMEdge **)BLI_stack_peek(edge_stack);
+
+ edges = MEM_mallocN(
+ (sizeof(*edges) * (BLI_stack_count(edge_stack) + (eed_last != eed_start))) * previewlines, __func__);
+
+ eve_last = NULL;
+ eed_last = NULL;
+
+ while (!BLI_stack_is_empty(edge_stack)) {
+ BLI_stack_pop(edge_stack, &eed);
+
+ if (eed_last) {
+ if (eve_last) {
+ v[1][0] = v[0][0];
+ v[1][1] = v[0][1];
+ }
+ else {
+ v[1][0] = eed_last->v1;
+ v[1][1] = eed_last->v2;
+ eve_last = eed_last->v1;
+ }
+
+ edgering_find_order(eed_last, eed, eve_last, v);
+ eve_last = v[0][0];
+
+ for (i = 1; i <= previewlines; i++) {
+ const float fac = (i / ((float)previewlines + 1));
+ float v_cos[2][2][3];
+
+ edgering_vcos_get(v, v_cos, coords);
+
+ interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
+ interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
+ tot++;
+ }
+ }
+ eed_last = eed;
+ }
+
+ if ((eed_last != eed_start) &&
+#ifdef BMW_EDGERING_NGON
+ BM_edge_share_face_check(eed_last, eed_start)
+#else
+ BM_edge_share_quad_check(eed_last, eed_start)
+#endif
+ )
+ {
+ v[1][0] = v[0][0];
+ v[1][1] = v[0][1];
+
+ edgering_find_order(eed_last, eed_start, eve_last, v);
+
+ for (i = 1; i <= previewlines; i++) {
+ const float fac = (i / ((float)previewlines + 1));
+ float v_cos[2][2][3];
+
+ if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) {
+ continue;
+ }
+
+ edgering_vcos_get(v, v_cos, coords);
+
+ interp_v3_v3v3(edges[tot][0], v_cos[0][0], v_cos[0][1], fac);
+ interp_v3_v3v3(edges[tot][1], v_cos[1][0], v_cos[1][1], fac);
+ tot++;
+ }
+ }
+
+ BLI_stack_free(edge_stack);
+
+ psel->edges = edges;
+ psel->edges_len = tot;
+}
+
+void EDBM_preselect_edgering_update_from_edge(
+ struct EditMesh_PreSelEdgeRing *psel,
+ BMesh *bm, BMEdge *eed_start, int previewlines, const float (*coords)[3])
+{
+ EDBM_preselect_edgering_clear(psel);
+
+ if (coords) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ }
+
+ if (BM_edge_is_wire(eed_start)) {
+ view3d_preselect_mesh_edgering_update_verts_from_edge(psel, bm, eed_start, previewlines, coords);
+ }
+ else {
+ view3d_preselect_mesh_edgering_update_edges_from_edge(psel, bm, eed_start, previewlines, coords);
+ }
+
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
new file mode 100644
index 00000000000..e0b06019de1
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -0,0 +1,218 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_preselect_elem.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_stack.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "DNA_object_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Element Pre-Select
+ * Public API:
+ *
+ * #EDBM_preselect_elem_create
+ * #EDBM_preselect_elem_destroy
+ * #EDBM_preselect_elem_clear
+ * #EDBM_preselect_elem_draw
+ * #EDBM_preselect_elem_update_from_single
+ *
+ * \{ */
+
+static void vcos_get(BMVert *v, float r_co[3], const float (*coords)[3])
+{
+ if (coords) {
+ copy_v3_v3(r_co, coords[BM_elem_index_get(v)]);
+ }
+ else {
+ copy_v3_v3(r_co, v->co);
+ }
+}
+
+static void vcos_get_pair(BMVert *v[2], float r_cos[2][3], const float (*coords)[3])
+{
+ if (coords) {
+ for (int j = 0; j < 2; j++) {
+ copy_v3_v3(r_cos[j], coords[BM_elem_index_get(v[j])]);
+ }
+ }
+ else {
+ for (int j = 0; j < 2; j++) {
+ copy_v3_v3(r_cos[j], v[j]->co);
+ }
+ }
+}
+
+struct EditMesh_PreSelElem {
+ float (*edges)[2][3];
+ int edges_len;
+
+ float (*verts)[3];
+ int verts_len;
+};
+
+struct EditMesh_PreSelElem *EDBM_preselect_elem_create(void)
+{
+ struct EditMesh_PreSelElem *psel = MEM_callocN(sizeof(*psel), __func__);
+ return psel;
+}
+
+void EDBM_preselect_elem_destroy(
+ struct EditMesh_PreSelElem *psel)
+{
+ EDBM_preselect_elem_clear(psel);
+ MEM_freeN(psel);
+}
+
+void EDBM_preselect_elem_clear(
+ struct EditMesh_PreSelElem *psel)
+{
+ MEM_SAFE_FREE(psel->edges);
+ psel->edges_len = 0;
+
+ MEM_SAFE_FREE(psel->verts);
+ psel->verts_len = 0;
+}
+
+void EDBM_preselect_elem_draw(
+ struct EditMesh_PreSelElem *psel, const float matrix[4][4])
+{
+ if ((psel->edges_len == 0) && (psel->verts_len == 0)) {
+ return;
+ }
+
+ GPU_depth_test(false);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ub(255, 0, 255);
+
+ if (psel->edges_len > 0) {
+ immBegin(GPU_PRIM_LINES, psel->edges_len * 2);
+
+ for (int i = 0; i < psel->edges_len; i++) {
+ immVertex3fv(pos, psel->edges[i][0]);
+ immVertex3fv(pos, psel->edges[i][1]);
+ }
+
+ immEnd();
+ }
+
+ if (psel->verts_len > 0) {
+ GPU_point_size(3.0f);
+
+ immBegin(GPU_PRIM_POINTS, psel->verts_len);
+
+ for (int i = 0; i < psel->verts_len; i++) {
+ immVertex3fv(pos, psel->verts[i]);
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+
+ /* Reset default */
+ GPU_depth_test(true);
+}
+
+static void view3d_preselect_mesh_elem_update_from_vert(
+ struct EditMesh_PreSelElem *psel,
+ BMesh *UNUSED(bm), BMVert *eve, const float (*coords)[3])
+{
+ float (*verts)[3] = MEM_mallocN(sizeof(*psel->verts), __func__);
+ vcos_get(eve, verts[0], coords);
+ psel->verts = verts;
+ psel->verts_len = 1;
+}
+
+static void view3d_preselect_mesh_elem_update_from_edge(
+ struct EditMesh_PreSelElem *psel,
+ BMesh *UNUSED(bm), BMEdge *eed, const float (*coords)[3])
+{
+ float (*edges)[2][3] = MEM_mallocN(sizeof(*psel->edges), __func__);
+ vcos_get_pair(&eed->v1, edges[0], coords);
+ psel->edges = edges;
+ psel->edges_len = 1;
+}
+
+static void view3d_preselect_mesh_elem_update_from_face(
+ struct EditMesh_PreSelElem *psel,
+ BMesh *UNUSED(bm), BMFace *efa, const float (*coords)[3])
+{
+ float (*edges)[2][3] = MEM_mallocN(sizeof(*psel->edges) * efa->len, __func__);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ int i = 0;
+ do {
+ vcos_get_pair(&l_iter->e->v1, edges[i++], coords);
+ } while ((l_iter = l_iter->next) != l_first);
+ psel->edges = edges;
+ psel->edges_len = efa->len;
+}
+
+void EDBM_preselect_elem_update_from_single(
+ struct EditMesh_PreSelElem *psel,
+ BMesh *bm, BMElem *ele,
+ const float (*coords)[3])
+{
+ EDBM_preselect_elem_clear(psel);
+
+ if (coords) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ }
+
+ switch (ele->head.htype) {
+ case BM_VERT:
+ view3d_preselect_mesh_elem_update_from_vert(psel, bm, (BMVert *)ele, coords);
+ break;
+ case BM_EDGE:
+ view3d_preselect_mesh_elem_update_from_edge(psel, bm, (BMEdge *)ele, coords);
+ break;
+ case BM_FACE:
+ view3d_preselect_mesh_elem_update_from_face(psel, bm, (BMFace *)ele, coords);
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 0c8bd560bb2..fb380dfaaa9 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -523,11 +524,9 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
/**
* This is the main vert ripping function (rip when one vertex is selected)
*/
-static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *event)
+static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obedit, bool do_fill)
{
- const bool do_fill = RNA_boolean_get(op->ptr, "use_fill");
UnorderedLoopPair *fill_uloop_pairs = NULL;
- Object *obedit = CTX_data_edit_object(C);
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -672,7 +671,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/* set selection back to avoid active-unselected vertex */
BM_vert_select_set(bm, v, true);
/* should never happen */
- BKE_report(op->reports, RPT_ERROR, "Error ripping vertex from faces");
return OPERATOR_CANCELLED;
}
else {
@@ -759,7 +757,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
if (!e_best) {
- BKE_report(op->reports, RPT_ERROR, "Selected vertex has no edge/face pairs attached");
return OPERATOR_CANCELLED;
}
@@ -875,7 +872,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
if (totvert_orig == bm->totvert) {
- BKE_report(op->reports, RPT_ERROR, "No vertices could be ripped");
return OPERATOR_CANCELLED;
}
@@ -885,11 +881,9 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
/**
* This is the main edge ripping function
*/
-static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *event)
+static int edbm_rip_invoke__edge(bContext *C, const wmEvent *event, Object *obedit, bool do_fill)
{
- const bool do_fill = RNA_boolean_get(op->ptr, "use_fill");
UnorderedLoopPair *fill_uloop_pairs = NULL;
- Object *obedit = CTX_data_edit_object(C);
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -1004,7 +998,6 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
}
if (totedge_orig == bm->totedge) {
- BKE_report(op->reports, RPT_ERROR, "No edges could be ripped");
return OPERATOR_CANCELLED;
}
@@ -1016,65 +1009,102 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *eve
/* based on mouse cursor position, it defines how is being ripped */
static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMIter iter;
- BMEdge *e;
- const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0);
- int ret;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ const bool do_fill = RNA_boolean_get(op->ptr, "use_fill");
- /* running in face mode hardly makes sense, so convert to region loop and rip */
- if (bm->totfacesel) {
- /* highly nifty but hard to support since the operator can fail and we're left
- * with modified selection */
- // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL);
+ bool no_vertex_selected = true;
+ bool error_face_selected = true;
+ bool error_disconnected_vertices = true;
+ bool error_rip_failed = true;
- BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces");
- return OPERATOR_CANCELLED;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* we could support this, but not for now */
- if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices");
- return OPERATOR_CANCELLED;
- }
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEdge *e;
+ const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0);
+ int ret;
- /* note on selection:
- * When calling edge split we operate on tagged edges rather then selected
- * this is important because the edges to operate on are extended by one,
- * but the selection is left alone.
- *
- * After calling edge split - the duplicated edges have the same selection state as the
- * original, so all we do is de-select the far side from the mouse and we have a
- * useful selection for grabbing.
- */
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+ no_vertex_selected = false;
+
+ /* running in face mode hardly makes sense, so convert to region loop and rip */
+ if (bm->totfacesel) {
+ /* highly nifty but hard to support since the operator can fail and we're left
+ * with modified selection */
+ // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL);
+ continue;
+ }
+ error_face_selected = false;
- /* BM_ELEM_SELECT --> BM_ELEM_TAG */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ /* we could support this, but not for now */
+ if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) {
+ continue;
+ }
+ error_disconnected_vertices = false;
+
+ /* note on selection:
+ * When calling edge split we operate on tagged edges rather then selected
+ * this is important because the edges to operate on are extended by one,
+ * but the selection is left alone.
+ *
+ * After calling edge split - the duplicated edges have the same selection state as the
+ * original, so all we do is de-select the far side from the mouse and we have a
+ * useful selection for grabbing.
+ */
+
+ /* BM_ELEM_SELECT --> BM_ELEM_TAG */
+ BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
+
+ /* split 2 main parts of this operator out into vertex and edge ripping */
+ if (singlesel) {
+ ret = edbm_rip_invoke__vert(C, event, obedit, do_fill);
+ }
+ else {
+ ret = edbm_rip_invoke__edge(C, event, obedit, do_fill);
+ }
+
+ if (ret != OPERATOR_FINISHED) {
+ continue;
+ }
+
+ BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0));
+
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+ error_rip_failed = false;
+
+ EDBM_update_generic(em, true, true);
}
- /* split 2 main parts of this operator out into vertex and edge ripping */
- if (singlesel) {
- ret = edbm_rip_invoke__vert(C, op, event);
+ MEM_freeN(objects);
+
+ if (no_vertex_selected) {
+ /* Ignore it. */
+ return OPERATOR_CANCELLED;
}
- else {
- ret = edbm_rip_invoke__edge(C, op, event);
+ else if (error_face_selected) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces");
+ return OPERATOR_CANCELLED;
}
-
- if (ret == OPERATOR_CANCELLED) {
+ else if (error_disconnected_vertices) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices");
return OPERATOR_CANCELLED;
}
-
- BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0));
-
- if (bm->totvertsel == 0) {
+ else if (error_rip_failed) {
+ BKE_report(op->reports, RPT_ERROR, "Rip failed");
return OPERATOR_CANCELLED;
}
-
- EDBM_update_generic(em, true, true);
-
+ /* No errors, everything went fine. */
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c
index a501dfc8c2c..ef07aac0ab2 100644
--- a/source/blender/editors/mesh/editmesh_rip_edge.c
+++ b/source/blender/editors/mesh/editmesh_rip_edge.c
@@ -24,6 +24,8 @@
* based on mouse cursor position, split of vertices along the closest edge.
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -31,6 +33,7 @@
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "WM_types.h"
@@ -50,181 +53,187 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
{
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMIter viter;
- BMVert *v;
- const float mval_fl[2] = {UNPACK2(event->mval)};
- float cent_sco[2];
- int cent_tot;
- bool changed = false;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* mouse direction to view center */
- float mval_dir[2];
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- float projectMat[4][4];
+ BMIter viter;
+ BMVert *v;
+ const float mval_fl[2] = { UNPACK2(event->mval) };
+ float cent_sco[2];
+ int cent_tot;
+ bool changed = false;
- if (bm->totvertsel == 0)
- return OPERATOR_CANCELLED;
+ /* mouse direction to view center */
+ float mval_dir[2];
- ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
+ float projectMat[4][4];
- zero_v2(cent_sco);
- cent_tot = 0;
+ if (bm->totvertsel == 0)
+ continue;
- /* clear tags and calc screen center */
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
+ ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- float v_sco[2];
- ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
+ zero_v2(cent_sco);
+ cent_tot = 0;
+
+ /* clear tags and calc screen center */
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ float v_sco[2];
+ ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
- add_v2_v2(cent_sco, v_sco);
- cent_tot += 1;
+ add_v2_v2(cent_sco, v_sco);
+ cent_tot += 1;
+ }
}
- }
- mul_v2_fl(cent_sco, 1.0f / (float)cent_tot);
-
- /* not essential, but gives more expected results with edge selection */
- if (bm->totedgesel) {
- /* angle against center can give odd result,
- * try re-position the center to the closest edge */
- BMIter eiter;
- BMEdge *e;
- float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl);
-
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- float e_sco[2][2];
- float cent_sco_test[2];
- float dist_sq_test;
-
- ED_view3d_project_float_v2_m4(ar, e->v1->co, e_sco[0], projectMat);
- ED_view3d_project_float_v2_m4(ar, e->v2->co, e_sco[1], projectMat);
-
- closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]);
- dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl);
- if (dist_sq_test < dist_sq_best) {
- dist_sq_best = dist_sq_test;
-
- /* we have a new screen center */
- copy_v2_v2(cent_sco, cent_sco_test);
+ mul_v2_fl(cent_sco, 1.0f / (float)cent_tot);
+
+ /* not essential, but gives more expected results with edge selection */
+ if (bm->totedgesel) {
+ /* angle against center can give odd result,
+ * try re-position the center to the closest edge */
+ BMIter eiter;
+ BMEdge *e;
+ float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl);
+
+ BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float e_sco[2][2];
+ float cent_sco_test[2];
+ float dist_sq_test;
+
+ ED_view3d_project_float_v2_m4(ar, e->v1->co, e_sco[0], projectMat);
+ ED_view3d_project_float_v2_m4(ar, e->v2->co, e_sco[1], projectMat);
+
+ closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]);
+ dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+
+ /* we have a new screen center */
+ copy_v2_v2(cent_sco, cent_sco_test);
+ }
}
}
}
- }
- sub_v2_v2v2(mval_dir, mval_fl, cent_sco);
- normalize_v2(mval_dir);
+ sub_v2_v2v2(mval_dir, mval_fl, cent_sco);
+ normalize_v2(mval_dir);
- /* operate on selected verts */
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- BMIter eiter;
- BMEdge *e;
- float v_sco[2];
+ /* operate on selected verts */
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ BMIter eiter;
+ BMEdge *e;
+ float v_sco[2];
- if (BM_elem_flag_test(v, BM_ELEM_SELECT) &&
- BM_elem_flag_test(v, BM_ELEM_TAG) == false)
- {
- /* Rules for */
- float angle_best = FLT_MAX;
- BMEdge *e_best = NULL;
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(v, BM_ELEM_TAG) == false)
+ {
+ /* Rules for */
+ float angle_best = FLT_MAX;
+ BMEdge *e_best = NULL;
#ifdef USE_TRICKY_EXTEND
- /* first check if we can select the edge to split based on selection-only */
- int tot_sel = 0, tot = 0;
-
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- e_best = e;
- tot_sel += 1;
+ /* first check if we can select the edge to split based on selection-only */
+ int tot_sel = 0, tot = 0;
+
+ BM_ITER_ELEM(e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ e_best = e;
+ tot_sel += 1;
+ }
+ tot += 1;
}
- tot += 1;
}
- }
- if (tot_sel != 1) {
- e_best = NULL;
- }
+ if (tot_sel != 1) {
+ e_best = NULL;
+ }
- /* only one edge selected, operate on that */
- if (e_best) {
- goto found_edge;
- }
- /* none selected, fall through and find one */
- else if (tot_sel == 0) {
- /* pass */
- }
- /* selection not 0 or 1, do nothing */
- else {
- goto found_edge;
- }
+ /* only one edge selected, operate on that */
+ if (e_best) {
+ goto found_edge;
+ }
+ /* none selected, fall through and find one */
+ else if (tot_sel == 0) {
+ /* pass */
+ }
+ /* selection not 0 or 1, do nothing */
+ else {
+ goto found_edge;
+ }
#endif
- ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
+ ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- BMVert *v_other = BM_edge_other_vert(e, v);
- float v_other_sco[2];
- float angle_test;
+ BM_ITER_ELEM(e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ float v_other_sco[2];
+ float angle_test;
- ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat);
+ ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat);
- /* avoid comparing with view-axis aligned edges (less than a pixel) */
- if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) {
- float v_dir[2];
+ /* avoid comparing with view-axis aligned edges (less than a pixel) */
+ if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) {
+ float v_dir[2];
- sub_v2_v2v2(v_dir, v_other_sco, v_sco);
- normalize_v2(v_dir);
+ sub_v2_v2v2(v_dir, v_other_sco, v_sco);
+ normalize_v2(v_dir);
- angle_test = angle_normalized_v2v2(mval_dir, v_dir);
+ angle_test = angle_normalized_v2v2(mval_dir, v_dir);
- if (angle_test < angle_best) {
- angle_best = angle_test;
- e_best = e;
+ if (angle_test < angle_best) {
+ angle_best = angle_test;
+ e_best = e;
+ }
}
}
}
- }
#ifdef USE_TRICKY_EXTEND
-found_edge:
+found_edge :
#endif
- if (e_best) {
- const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT);
- BMVert *v_new;
- BMEdge *e_new;
+ if (e_best) {
+ const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT);
+ BMVert *v_new;
+ BMEdge *e_new;
- v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f);
+ v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f);
- BM_vert_select_set(bm, v, false);
- BM_edge_select_set(bm, e_new, false);
+ BM_vert_select_set(bm, v, false);
+ BM_edge_select_set(bm, e_new, false);
- BM_vert_select_set(bm, v_new, true);
- if (e_select) {
- BM_edge_select_set(bm, e_best, true);
- }
- BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */
+ BM_vert_select_set(bm, v_new, true);
+ if (e_select) {
+ BM_edge_select_set(bm, e_best, true);
+ }
+ BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */
- changed = true;
+ changed = true;
+ }
}
}
- }
-
- if (changed) {
- BM_select_history_clear(bm);
- BM_mesh_select_mode_flush(bm);
+ if (changed) {
+ BM_select_history_clear(bm);
- EDBM_update_generic(em, true, true);
+ BM_mesh_select_mode_flush(bm);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
+ EDBM_update_generic(em, true, true);
+ }
}
+
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 968c276c8bd..1191874b9a7 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -45,6 +45,7 @@
#include "BKE_report.h"
#include "BKE_paint.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -56,8 +57,11 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_select_utils.h"
#include "ED_view3d.h"
#include "DNA_mesh_types.h"
@@ -68,6 +72,9 @@
#include "bmesh_tools.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "mesh_intern.h" /* own include */
/* use bmesh operator flags for a few operators */
@@ -199,7 +206,7 @@ void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; /* set in drawobject.c ... for colorindices */
-/* facilities for border select and circle select */
+/* facilities for box select and circle select */
static BLI_bitmap *selbuf = NULL;
static BLI_bitmap *edbm_backbuf_alloc(const int size)
@@ -209,7 +216,9 @@ static BLI_bitmap *edbm_backbuf_alloc(const int size)
/* reads rect, and builds selection array for quick lookup */
/* returns if all is OK */
-bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
+bool EDBM_backbuf_border_init(
+ ViewContext *vc, short xmin,
+ short ymin, short xmax, short ymax)
{
struct ImBuf *buf;
unsigned int *dr;
@@ -332,7 +341,9 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
}
/* circle shaped sample area */
-bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
+bool EDBM_backbuf_circle_init(
+ ViewContext *vc,
+ short xs, short ys, short rads)
{
struct ImBuf *buf;
unsigned int *dr;
@@ -389,6 +400,18 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
* to avoid the bias interfering with distance comparisons when mixing types.
* \{ */
+#define FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, select_mode_required) \
+ short select_mode = select_mode_required; \
+ bool fake_select_mode = (select_mode & (vc)->scene->toolsettings->selectmode) == 0; \
+ if (fake_select_mode) { \
+ (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \
+ } ((void)0)
+
+#define FAKE_SELECT_MODE_END(vc, fake_select_mode) \
+ if (fake_select_mode) { \
+ (vc)->v3d->flag |= V3D_INVALID_BACKBUF; \
+ } ((void)0)
+
#define FIND_NEAR_SELECT_BIAS 5
#define FIND_NEAR_CYCLE_THRESHOLD_MIN 3
@@ -462,11 +485,16 @@ BMVert *EDBM_vert_find_nearest_ex(
BMVert *eve;
/* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
- ED_view3d_backbuf_validate(vc);
+ {
+ FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_VERTEX);
+ ED_view3d_backbuf_validate_with_select_mode(vc, select_mode);
- index = ED_view3d_backbuf_sample_rect(
- vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
- eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
+ index = ED_view3d_backbuf_sample_rect(
+ vc, vc->mval, dist_px, bm_wireoffs, 0xFFFFFF, &dist_test);
+ eve = index ? BM_vert_at_index_find_or_table(bm, index - 1) : NULL;
+
+ FAKE_SELECT_MODE_END(vc, fake_select_mode);
+ }
if (eve) {
if (dist_test < *r_dist) {
@@ -649,19 +677,16 @@ BMEdge *EDBM_edge_find_nearest_ex(
unsigned int index;
BMEdge *eed;
- /* Make sure that the edges are considered for selection.
- * TODO: cleanup: add `selectmode` as a parameter */
- const short ts_selectmode = vc->scene->toolsettings->selectmode;
- vc->scene->toolsettings->selectmode |= SCE_SELECT_EDGE;
-
/* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
- ED_view3d_backbuf_validate(vc);
+ {
+ FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_EDGE);
+ ED_view3d_backbuf_validate_with_select_mode(vc, select_mode);
- /* restore `selectmode` */
- vc->scene->toolsettings->selectmode = ts_selectmode;
+ index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
+ eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL;
- index = ED_view3d_backbuf_sample_rect(vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
- eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL;
+ FAKE_SELECT_MODE_END(vc, fake_select_mode);
+ }
if (r_eed_zbuf) {
*r_eed_zbuf = eed;
@@ -822,10 +847,15 @@ BMFace *EDBM_face_find_nearest_ex(
unsigned int index;
BMFace *efa;
- ED_view3d_backbuf_validate(vc);
+ {
+ FAKE_SELECT_MODE_BEGIN(vc, fake_select_mode, select_mode, SCE_SELECT_FACE);
+ ED_view3d_backbuf_validate_with_select_mode(vc, select_mode);
+
+ index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]);
+ efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
- index = ED_view3d_backbuf_sample(vc, vc->mval[0], vc->mval[1]);
- efa = index ? BM_face_at_index_find_or_table(bm, index - 1) : NULL;
+ FAKE_SELECT_MODE_END(vc, fake_select_mode);
+ }
if (r_efa_zbuf) {
*r_efa_zbuf = efa;
@@ -909,7 +939,9 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
* selected vertices and edges get disadvantage
* return 1 if found one
*/
-static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
+static bool unified_findnearest(
+ ViewContext *vc, Base **bases, const uint bases_len,
+ int *r_base_index, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
{
BMEditMesh *em = vc->em;
static short mval_prev[2] = {-1, -1};
@@ -919,326 +951,365 @@ static int unified_findnearest(ViewContext *vc, BMVert **r_eve, BMEdge **r_eed,
/* since edges select lines, we give dots advantage of ~20 pix */
const float dist_margin = (dist_init / 2);
float dist = dist_init;
- BMFace *efa_zbuf = NULL;
- BMEdge *eed_zbuf = NULL;
-
- BMVert *eve = NULL;
- BMEdge *eed = NULL;
- BMFace *efa = NULL;
+ struct {
+ struct {
+ BMVert *ele;
+ int base_index;
+ } v;
+ struct {
+ BMEdge *ele;
+ int base_index;
+ } e, e_zbuf;
+ struct {
+ BMFace *ele;
+ int base_index;
+ } f, f_zbuf;
+ } hit = {{NULL}};
+
+ /* TODO(campbell): perform selection as one pass
+ * instead of many smaller passes (which doesn't work for zbuf occlusion). */
/* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- ED_view3d_backbuf_validate(vc);
if ((dist > 0.0f) && em->selectmode & SCE_SELECT_FACE) {
float dist_center = 0.0f;
float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : NULL;
- efa = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
- if (efa && dist_center_p) {
- dist = min_ff(dist_margin, dist_center);
- }
+
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
+ ED_view3d_viewcontext_init_object(vc, obedit);
+ BLI_assert(vc->em->selectmode == em->selectmode);
+ ED_view3d_backbuf_validate(vc);
+ BMFace *efa_zbuf = NULL;
+ BMFace *efa_test = EDBM_face_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf);
+ if (hit.f.ele && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ if (efa_test) {
+ hit.f.base_index = base_index;
+ hit.f.ele = efa_test;
+ }
+ if (efa_zbuf) {
+ hit.f_zbuf.base_index = base_index;
+ hit.f_zbuf.ele = efa_zbuf;
+ }
+ } /* bases */
}
if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) {
float dist_center = 0.0f;
float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL;
- eed = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
- if (eed && dist_center_p) {
- dist = min_ff(dist_margin, dist_center);
- }
+
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
+ ED_view3d_viewcontext_init_object(vc, obedit);
+ ED_view3d_backbuf_validate(vc);
+ BMEdge *eed_zbuf = NULL;
+ BMEdge *eed_test = EDBM_edge_find_nearest_ex(vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf);
+ if (hit.e.ele && dist_center_p) {
+ dist = min_ff(dist_margin, dist_center);
+ }
+ if (eed_test) {
+ hit.e.base_index = base_index;
+ hit.e.ele = eed_test;
+ }
+ if (eed_zbuf) {
+ hit.e_zbuf.base_index = base_index;
+ hit.e_zbuf.ele = eed_zbuf;
+ }
+ } /* bases */
}
if ((dist > 0.0f) && em->selectmode & SCE_SELECT_VERTEX) {
- eve = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
+ ED_view3d_viewcontext_init_object(vc, obedit);
+ ED_view3d_backbuf_validate(vc);
+ BMVert *eve_test = EDBM_vert_find_nearest_ex(vc, &dist, true, use_cycle);
+ if (eve_test) {
+ hit.v.base_index = base_index;
+ hit.v.ele = eve_test;
+ }
+ } /* bases */
}
/* return only one of 3 pointers, for frontbuffer redraws */
- if (eve) {
- efa = NULL; eed = NULL;
+ if (hit.v.ele) {
+ hit.f.ele = NULL;
+ hit.e.ele = NULL;
}
- else if (eed) {
- efa = NULL;
+ else if (hit.e.ele) {
+ hit.f.ele = NULL;
}
/* there may be a face under the cursor, who's center if too far away
* use this if all else fails, it makes sense to select this */
- if ((eve || eed || efa) == 0) {
- if (eed_zbuf) {
- eed = eed_zbuf;
+ if ((hit.v.ele || hit.e.ele || hit.f.ele) == 0) {
+ if (hit.e_zbuf.ele) {
+ hit.e.base_index = hit.e_zbuf.base_index;
+ hit.e.ele = hit.e_zbuf.ele;
}
- else if (efa_zbuf) {
- efa = efa_zbuf;
+ else if (hit.f_zbuf.ele) {
+ hit.f.base_index = hit.f_zbuf.base_index;
+ hit.f.ele = hit.f_zbuf.ele;
}
}
mval_prev[0] = vc->mval[0];
mval_prev[1] = vc->mval[1];
- *r_eve = eve;
- *r_eed = eed;
- *r_efa = efa;
-
- return (eve || eed || efa);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Similar (Vert/Edge/Face) Operator
- * \{ */
-
-static const EnumPropertyItem prop_similar_compare_types[] = {
- {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
- {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
- {SIM_CMP_LT, "LESS", 0, "Less", ""},
-
- {0, NULL, 0, NULL, NULL}
-};
-
-static const EnumPropertyItem prop_similar_types[] = {
- {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
- {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
- {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
- {SIMVERT_EDGE, "EDGE", 0, "Amount of connecting edges", ""},
-
- {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
- {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
- {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
- {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
- {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
- {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""},
- {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
- {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
-#ifdef WITH_FREESTYLE
- {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""},
-#endif
-
- {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
- {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
- {SIMFACE_AREA, "AREA", 0, "Area", ""},
- {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""},
- {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
- {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
- {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
- {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""},
-#ifdef WITH_FREESTYLE
- {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
-#endif
-
- {0, NULL, 0, NULL, NULL}
-};
-
-/* selects new faces/edges/verts based on the existing selection */
-
-static int similar_face_select_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMOperator bmop;
-
- /* get the type from RNA */
- const int type = RNA_enum_get(op->ptr, "type");
- const float thresh = RNA_float_get(op->ptr, "threshold");
- const int compare = RNA_enum_get(op->ptr, "compare");
-
- /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
- EDBM_op_init(em, &bmop, op,
- "similar_faces faces=%hf type=%i thresh=%f compare=%i",
- BM_ELEM_SELECT, type, thresh, compare);
+ /* Only one element type will be non-null. */
+ BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1);
- /* execute the operator */
- BMO_op_exec(em->bm, &bmop);
-
- /* clear the existing selection */
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-
- /* select the output */
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
-
- /* finish the operator */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ if (hit.v.ele) {
+ *r_base_index = hit.v.base_index;
}
-
- EDBM_update_generic(em, false, false);
-
- return OPERATOR_FINISHED;
-}
-
-/* ***************************************************** */
-
-/* EDGE GROUP */
-
-/* wrap the above function but do selection flushing edge to face */
-static int similar_edge_select_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMOperator bmop;
-
- /* get the type from RNA */
- const int type = RNA_enum_get(op->ptr, "type");
- const float thresh = RNA_float_get(op->ptr, "threshold");
- const int compare = RNA_enum_get(op->ptr, "compare");
-
- /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
- EDBM_op_init(em, &bmop, op,
- "similar_edges edges=%he type=%i thresh=%f compare=%i",
- BM_ELEM_SELECT, type, thresh, compare);
-
- /* execute the operator */
- BMO_op_exec(em->bm, &bmop);
-
- /* clear the existing selection */
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-
- /* select the output */
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
- EDBM_selectmode_flush(em);
-
- /* finish the operator */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ if (hit.e.ele) {
+ *r_base_index = hit.e.base_index;
+ }
+ if (hit.f.ele) {
+ *r_base_index = hit.f.base_index;
}
- EDBM_update_generic(em, false, false);
+ *r_eve = hit.v.ele;
+ *r_eed = hit.e.ele;
+ *r_efa = hit.f.ele;
- return OPERATOR_FINISHED;
+ return (hit.v.ele || hit.e.ele || hit.f.ele);
}
-/* ********************************* */
+#undef FAKE_SELECT_MODE_BEGIN
+#undef FAKE_SELECT_MODE_END
-/*
- * VERT GROUP
- * mode 1: same normal
- * mode 2: same number of face users
- * mode 3: same vertex groups
- */
-static int similar_vert_select_exec(bContext *C, wmOperator *op)
+bool EDBM_unified_findnearest(
+ ViewContext *vc, Base **bases, const uint bases_len,
+ int *r_base_index, BMVert **r_eve, BMEdge **r_eed, BMFace **r_efa)
{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMOperator bmop;
- /* get the type from RNA */
- const int type = RNA_enum_get(op->ptr, "type");
- const float thresh = RNA_float_get(op->ptr, "threshold");
- const int compare = RNA_enum_get(op->ptr, "compare");
-
- /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
- EDBM_op_init(em, &bmop, op,
- "similar_verts verts=%hv type=%i thresh=%f compare=%i",
- BM_ELEM_SELECT, type, thresh, compare);
-
- /* execute the operator */
- BMO_op_exec(em->bm, &bmop);
-
- /* clear the existing selection */
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
-
- /* select the output */
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
-
- /* finish the operator */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
-
- EDBM_selectmode_flush(em);
+ return unified_findnearest(vc, bases, bases_len, r_base_index, r_eve, r_eed, r_efa);
+}
- EDBM_update_generic(em, false, false);
+/** \} */
- return OPERATOR_FINISHED;
-}
+/* -------------------------------------------------------------------- */
+/** \name Alternate Find Nearest Vert/Edge (optional boundary)
+ *
+ * \note This uses ray-cast method instead of backbuffer,
+ * currently used for poly-build.
+ * \{ */
-static int edbm_select_similar_exec(bContext *C, wmOperator *op)
+bool EDBM_unified_findnearest_from_raycast(
+ ViewContext *vc,
+ Base **bases, const uint bases_len,
+ bool use_boundary,
+ int *r_base_index,
+ struct BMVert **r_eve,
+ struct BMEdge **r_eed,
+ struct BMFace **r_efa)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
- const int type = RNA_enum_get(op->ptr, "type");
+ const float mval_fl[2] = {UNPACK2(vc->mval)};
+ float ray_origin[3], ray_direction[3];
- if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_float_set(op->ptr, prop, ts->select_thresh);
- }
- else {
- ts->select_thresh = RNA_property_float_get(op->ptr, prop);
- }
+ struct {
+ uint base_index;
+ BMElem *ele;
+ } best = {0, NULL};
- if (type < 100) return similar_vert_select_exec(C, op);
- else if (type < 200) return similar_edge_select_exec(C, op);
- else return similar_face_select_exec(C, op);
-}
+ if (ED_view3d_win_to_ray_clipped(
+ vc->depsgraph,
+ vc->ar, vc->v3d, mval_fl,
+ ray_origin, ray_direction, true))
+ {
+ float dist_sq_best = FLT_MAX;
-static const EnumPropertyItem *select_similar_type_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
- bool *r_free)
-{
- Object *obedit;
+ const bool use_vert = (r_eve != NULL);
+ const bool use_edge = (r_eed != NULL);
+ const bool use_face = (r_efa != NULL);
- if (!C) /* needed for docs and i18n tools */
- return prop_similar_types;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *obedit = base_iter->object;
- obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ float imat3[3][3];
- if (obedit && obedit->type == OB_MESH) {
- EnumPropertyItem *item = NULL;
- int a, totitem = 0;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ED_view3d_viewcontext_init_object(vc, obedit);
+ copy_m3_m4(imat3, obedit->obmat);
+ invert_m3(imat3);
- if (em->selectmode & SCE_SELECT_VERTEX) {
- for (a = SIMVERT_NORMAL; a < SIMEDGE_LENGTH; a++) {
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ const float (*coords)[3] = NULL;
+ {
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data);
+ if (me_eval->runtime.edit_data) {
+ coords = me_eval->runtime.edit_data->vertexCos;
+ }
}
- }
- else if (em->selectmode & SCE_SELECT_EDGE) {
- for (a = SIMEDGE_LENGTH; a < SIMFACE_MATERIAL; a++) {
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+
+ if (coords != NULL) {
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
}
- }
- else if (em->selectmode & SCE_SELECT_FACE) {
-#ifdef WITH_FREESTYLE
- const int a_end = SIMFACE_FREESTYLE;
+
+ if (use_boundary && (use_vert || use_edge)) {
+ BMEdge *e;
+ BMIter eiter;
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if ((BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) &&
+ (BM_edge_is_boundary(e)))
+ {
+ float depth;
+
+ if (use_vert) {
+ for (uint j = 0; j < 2; j++) {
+ BMVert *v = *((&e->v1) + j);
+ float point[3];
+ mul_v3_m4v3(point, obedit->obmat, coords ? coords[BM_elem_index_get(v)] : v->co);
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ point, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)v;
+ }
+ }
+ }
+
+ if (use_edge) {
+ float point[3];
+#if 0
+ const float dist_sq_test = dist_squared_ray_to_seg_v3(
+ ray_origin, ray_direction,
+ e->v1->co, e->v2->co,
+ point, &depth);
#else
- const int a_end = SIMFACE_SMOOTH;
+ if (coords) {
+ mid_v3_v3v3(point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
+ }
+ else {
+ mid_v3_v3v3(point, e->v1->co, e->v2->co);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ point, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)e;
+ }
#endif
- for (a = SIMFACE_MATERIAL; a <= a_end; a++) {
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ }
+ }
+ }
+ else {
+ /* Non boundary case. */
+ if (use_vert) {
+ BMVert *v;
+ BMIter viter;
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ mul_v3_m4v3(point, obedit->obmat, v->co);
+ float depth;
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ v->co, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)v;
+ }
+ }
+ }
+ }
+ if (use_edge) {
+ BMEdge *e;
+ BMIter eiter;
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ if (coords) {
+ mid_v3_v3v3(point, coords[BM_elem_index_get(e->v1)], coords[BM_elem_index_get(e->v2)]);
+ }
+ else {
+ mid_v3_v3v3(point, e->v1->co, e->v2->co);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ float depth;
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ point, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)e;
+ }
+ }
+ }
+ }
}
- }
- RNA_enum_item_end(&item, &totitem);
-
- *r_free = true;
- return item;
+ if (use_face) {
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == false) {
+ float point[3];
+ if (coords) {
+ BM_face_calc_center_mean_vcos(bm, f, point, coords);
+ }
+ else {
+ BM_face_calc_center_mean(f, point);
+ }
+ mul_m4_v3(obedit->obmat, point);
+ float depth;
+ const float dist_sq_test = dist_squared_to_ray_v3(
+ ray_origin, ray_direction,
+ point, &depth);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+ best.base_index = base_index;
+ best.ele = (BMElem *)f;
+ }
+ }
+ }
+ }
+ }
}
- return prop_similar_types;
-}
-
-void MESH_OT_select_similar(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Select Similar";
- ot->idname = "MESH_OT_select_similar";
- ot->description = "Select similar vertices, edges or faces by property types";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = edbm_select_similar_exec;
- ot->poll = ED_operator_editmesh;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
- RNA_def_enum_funcs(prop, select_similar_type_itemf);
-
- RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
+ *r_base_index = best.base_index;
+ if (r_eve) {
+ *r_eve = NULL;
+ }
+ if (r_eed) {
+ *r_eed = NULL;
+ }
+ if (r_efa) {
+ *r_efa = NULL;
+ }
- RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+ if (best.ele) {
+ switch (best.ele->head.htype) {
+ case BM_VERT:
+ *r_eve = (BMVert *)best.ele;
+ break;
+ case BM_EDGE:
+ *r_eed = (BMEdge *)best.ele;
+ break;
+ case BM_FACE:
+ *r_efa = (BMFace *)best.ele;
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ return (best.ele != NULL);
}
/** \} */
@@ -1310,6 +1381,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
MEM_freeN(group_index);
if (changed) {
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
else {
@@ -1357,6 +1429,18 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op)
static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ /* Bypass when in UV non sync-select mode, fall through to keymap that edits. */
+ if (CTX_wm_space_image(C)) {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ /* Bypass when no action is needed. */
+ if (!RNA_struct_property_is_set(op->ptr, "type")) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
/* detecting these options based on shift/ctrl here is weak, but it's done
* to make this work when clicking buttons or menus */
if (!RNA_struct_property_is_set(op->ptr, "use_extend"))
@@ -1399,14 +1483,16 @@ void MESH_OT_select_mode(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
+ /* Hide all, not to show redo panel. */
prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
ot->prop = prop = RNA_def_enum(ot->srna, "type", elem_items, 0, "Type", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
+ prop = RNA_def_enum(ot->srna, "action", actions_items, 2, "Action", "Selection action to execute");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/** \} */
@@ -1466,50 +1552,61 @@ static void walker_select(BMEditMesh *em, int walkercode, void *start, const boo
static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMEdge *eed;
- BMEdge **edarray;
- int edindex;
const bool is_ring = RNA_boolean_get(op->ptr, "ring");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter;
- int totedgesel = 0;
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
+
+ BMEdge *eed;
+ BMEdge **edarray;
+ int edindex;
+ BMIter iter;
+ int totedgesel = 0;
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- totedgesel++;
+ BM_ITER_MESH(eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ totedgesel++;
+ }
}
- }
- edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
- edindex = 0;
+ edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array");
+ edindex = 0;
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- edarray[edindex] = eed;
- edindex++;
+ BM_ITER_MESH(eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ edarray[edindex] = eed;
+ edindex++;
+ }
}
- }
- if (is_ring) {
- for (edindex = 0; edindex < totedgesel; edindex += 1) {
- eed = edarray[edindex];
- walker_select(em, BMW_EDGERING, eed, true);
+ if (is_ring) {
+ for (edindex = 0; edindex < totedgesel; edindex += 1) {
+ eed = edarray[edindex];
+ walker_select(em, BMW_EDGERING, eed, true);
+ }
+ EDBM_selectmode_flush(em);
}
- EDBM_selectmode_flush(em);
- }
- else {
- for (edindex = 0; edindex < totedgesel; edindex += 1) {
- eed = edarray[edindex];
- walker_select(em, BMW_EDGELOOP, eed, true);
+ else {
+ for (edindex = 0; edindex < totedgesel; edindex += 1) {
+ eed = edarray[edindex];
+ walker_select(em, BMW_EDGELOOP, eed, true);
+ }
+ EDBM_selectmode_flush(em);
}
- EDBM_selectmode_flush(em);
- }
- MEM_freeN(edarray);
-// if (EM_texFaceCheck())
+ MEM_freeN(edarray);
+ // if (EM_texFaceCheck())
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1593,33 +1690,45 @@ static void mouse_mesh_loop_edge(BMEditMesh *em, BMEdge *eed, bool select, bool
static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring)
{
+ Base *basact = NULL;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+
ViewContext vc;
BMEditMesh *em;
- BMEdge *eed;
bool select = true;
bool select_clear = false;
bool select_cycle = true;
- float dist = ED_view3d_select_dist_px() * 0.6666f;
float mvalf[2];
em_setup_viewcontext(C, &vc);
mvalf[0] = (float)(vc.mval[0] = mval[0]);
mvalf[1] = (float)(vc.mval[1] = mval[1]);
- em = vc.em;
- /* Make sure that the edges are also considered for selection.
- * TODO: cleanup: add `selectmode` as a parameter */
- const short ts_selectmode = vc.scene->toolsettings->selectmode;
- vc.scene->toolsettings->selectmode |= SCE_SELECT_EDGE;
+ BMEditMesh *em_original = vc.em;
+ const short selectmode = em_original->selectmode;
+ em_original->selectmode = SCE_SELECT_EDGE;
- /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
- ED_view3d_backbuf_validate(&vc);
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
- /* restore `selectmode` */
- vc.scene->toolsettings->selectmode = ts_selectmode;
+ {
+ int base_index = -1;
+ if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) {
+ basact = bases[base_index];
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ em = vc.em;
+ }
+ else {
+ em = NULL;
+ }
+ }
- eed = EDBM_edge_find_nearest_ex(&vc, &dist, NULL, true, true, NULL);
- if (eed == NULL) {
+ em_original->selectmode = selectmode;
+
+ if (em == NULL || eed == NULL) {
+ MEM_freeN(bases);
return false;
}
@@ -1641,6 +1750,25 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
select_cycle = false;
}
+ if (select_clear) {
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *ob_iter = base_iter->object;
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+
+ if (em_iter->bm->totvertsel == 0) {
+ continue;
+ }
+
+ if (em_iter == em) {
+ continue;
+ }
+
+ EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT);
+ DEG_id_tag_update(ob_iter->data, DEG_TAG_SELECT_UPDATE);
+ }
+ }
+
if (em->selectmode & SCE_SELECT_FACE) {
mouse_mesh_loop_face(em, eed, select, select_clear);
}
@@ -1689,9 +1817,10 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
}
else if (em->selectmode & SCE_SELECT_FACE) {
/* Select the face of eed which is the nearest of mouse. */
- BMFace *f, *efa = NULL;
+ BMFace *f;
BMIter iterf;
float best_dist = FLT_MAX;
+ efa = NULL;
/* We can't be sure this has already been set... */
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
@@ -1721,6 +1850,9 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
}
}
+ MEM_freeN(bases);
+
+ DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
return true;
@@ -1794,27 +1926,44 @@ void MESH_OT_edgering_select(wmOperatorType *ot)
static int edbm_select_all_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int action = RNA_enum_get(op->ptr, "action");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int action = RNA_enum_get(op->ptr, "action");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) {
+ action = SEL_DESELECT;
+ break;
+ }
+ }
+ }
- switch (action) {
- case SEL_TOGGLE:
- EDBM_select_toggle_all(em);
- break;
- case SEL_SELECT:
- EDBM_flag_enable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_DESELECT:
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_INVERT:
- EDBM_select_swap(em);
- EDBM_selectmode_flush(em);
- break;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ switch (action) {
+ case SEL_SELECT:
+ EDBM_flag_enable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_DESELECT:
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_INVERT:
+ EDBM_select_swap(em);
+ EDBM_selectmode_flush(em);
+ break;
+ }
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1844,18 +1993,24 @@ void MESH_OT_select_all(wmOperatorType *ot)
static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (EDBM_select_interior_faces(em)) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
+ if (!EDBM_select_interior_faces(em)) {
+ continue;
+ }
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void MESH_OT_select_interior_faces(wmOperatorType *ot)
@@ -1885,6 +2040,8 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot)
bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
ViewContext vc;
+
+ int base_index_active = -1;
BMVert *eve = NULL;
BMEdge *eed = NULL;
BMFace *efa = NULL;
@@ -1894,11 +2051,27 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
- if (unified_findnearest(&vc, &eve, &eed, &efa)) {
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
+
+ bool ok = false;
+
+ if (unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa)) {
+ Base *basact = bases[base_index_active];
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
/* Deselect everything */
- if (extend == false && deselect == false && toggle == false)
- EDBM_flag_disable_all(vc.em, BM_ELEM_SELECT);
+ if (extend == false && deselect == false && toggle == false) {
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base_iter = bases[base_index];
+ Object *ob_iter = base_iter->object;
+ EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT);
+ if (basact->object != ob_iter) {
+ DEG_id_tag_update(ob_iter->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
+ }
+ }
+ }
if (efa) {
if (extend) {
@@ -1981,20 +2154,48 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
EDBM_selectmode_flush(vc.em);
- /* change active material on object */
- if (efa && efa->mat_nr != vc.obedit->actcol - 1) {
- vc.obedit->actcol = efa->mat_nr + 1;
- vc.em->mat_nr = efa->mat_nr;
+ if (efa) {
+ /* Change active material on object. */
+ if (efa->mat_nr != vc.obedit->actcol - 1) {
+ vc.obedit->actcol = efa->mat_nr + 1;
+ vc.em->mat_nr = efa->mat_nr;
+ WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ }
+
+ /* Change active face-map on object. */
+ if (!BLI_listbase_is_empty(&vc.obedit->fmaps)) {
+ const int cd_fmap_offset = CustomData_get_offset(&vc.em->bm->pdata, CD_FACEMAP);
+ if (cd_fmap_offset != -1) {
+ int map = *((int *)BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset));
+ if ((map < -1) || (map > BLI_listbase_count_at_most(&vc.obedit->fmaps, map))) {
+ map = -1;
+ }
+ map += 1;
+ if (map != vc.obedit->actfmap) {
+ /* We may want to add notifiers later,
+ * currently select update handles redraw. */
+ vc.obedit->actfmap = map;
+ }
+ }
+ }
- WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ }
+ /* Changing active object is handy since it allows us to
+ * switch UV layers, vgroups for eg. */
+ if (vc.view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
}
+ DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
- return true;
+
+ ok = true;
}
- return false;
+ MEM_freeN(bases);
+
+ return ok;
}
/** \} */
@@ -2212,6 +2413,8 @@ bool EDBM_selectmode_toggle(
bContext *C, const short selectmode_new,
const int action, const bool use_extend, const bool use_expand)
{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = NULL;
@@ -2225,6 +2428,7 @@ bool EDBM_selectmode_toggle(
return ret;
}
+ bool only_update = false;
switch (action) {
case -1:
/* already set */
@@ -2232,21 +2436,24 @@ bool EDBM_selectmode_toggle(
case 0: /* disable */
/* check we have something to do */
if ((em->selectmode & selectmode_new) == 0) {
- return false;
+ only_update = true;
+ break;
}
em->selectmode &= ~selectmode_new;
break;
case 1: /* enable */
/* check we have something to do */
if ((em->selectmode & selectmode_new) != 0) {
- return false;
+ only_update = true;
+ break;
}
em->selectmode |= selectmode_new;
break;
case 2: /* toggle */
/* can't disable this flag if its the only one set */
if (em->selectmode == selectmode_new) {
- return false;
+ only_update = true;
+ break;
}
em->selectmode ^= selectmode_new;
break;
@@ -2255,10 +2462,30 @@ bool EDBM_selectmode_toggle(
break;
}
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ if (em_iter != em) {
+ em_iter->selectmode = em->selectmode;
+ }
+ }
+
+ if (only_update) {
+ MEM_freeN(objects);
+ return false;
+ }
+
if (use_extend == 0 || em->selectmode == 0) {
if (use_expand) {
const short selmode_max = highest_order_bit_s(ts->selectmode);
- EDBM_selectmode_convert(em, selmode_max, selectmode_new);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ EDBM_selectmode_convert(em_iter, selmode_max, selectmode_new);
+ }
}
}
@@ -2267,24 +2494,18 @@ bool EDBM_selectmode_toggle(
if (use_extend == 0 || em->selectmode == 0) {
em->selectmode = SCE_SELECT_VERTEX;
}
- ts->selectmode = em->selectmode;
- EDBM_selectmode_set(em);
ret = true;
break;
case SCE_SELECT_EDGE:
if (use_extend == 0 || em->selectmode == 0) {
em->selectmode = SCE_SELECT_EDGE;
}
- ts->selectmode = em->selectmode;
- EDBM_selectmode_set(em);
ret = true;
break;
case SCE_SELECT_FACE:
if (use_extend == 0 || em->selectmode == 0) {
em->selectmode = SCE_SELECT_FACE;
}
- ts->selectmode = em->selectmode;
- EDBM_selectmode_set(em);
ret = true;
break;
default:
@@ -2293,10 +2514,21 @@ bool EDBM_selectmode_toggle(
}
if (ret == true) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ ts->selectmode = em->selectmode;
+ em = NULL;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ em_iter->selectmode = ts->selectmode;
+ EDBM_selectmode_set(em_iter);
+ DEG_id_tag_update(ob_iter->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
+ }
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
}
+ MEM_freeN(objects);
return ret;
}
@@ -2498,7 +2730,7 @@ static bool select_linked_delimit_test(
* Gets the default from the operator fallback to own last-used value
* (selected based on mode)
*/
-static int select_linked_delimit_default_from_op(wmOperator *op, int select_mode)
+static int select_linked_delimit_default_from_op(wmOperator *op, const int select_mode)
{
static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
int delimit_last_index = (select_mode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
@@ -2564,172 +2796,187 @@ static void select_linked_delimit_end(BMEditMesh *em)
static int edbm_select_linked_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMIter iter;
- BMWalker walker;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
#ifdef USE_LINKED_SELECT_DEFAULT_HACK
- int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
+ const int delimit_init = select_linked_delimit_default_from_op(op, scene->toolsettings->selectmode);
#else
- int delimit = RNA_enum_get(op->ptr, "delimit");
+ const int delimit_init = RNA_enum_get(op->ptr, "delimit");
#endif
- select_linked_delimit_validate(bm, &delimit);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (delimit) {
- select_linked_delimit_begin(em->bm, delimit);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
- if (em->selectmode & SCE_SELECT_VERTEX) {
- BMVert *v;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMWalker walker;
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
- }
+ int delimit = delimit_init;
+
+ select_linked_delimit_validate(bm, &delimit);
- /* exclude all delimited verts */
if (delimit) {
- BMEdge *e;
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
- BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
- }
- }
+ select_linked_delimit_begin(em->bm, delimit);
}
- BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
- BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *v;
- if (delimit) {
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- BMElem *ele_walk;
- BMW_ITER (ele_walk, &walker, v) {
- if (ele_walk->head.htype == BM_LOOP) {
- BMVert *v_step = ((BMLoop *)ele_walk)->v;
- BM_vert_select_set(em->bm, v_step, true);
- BM_elem_flag_disable(v_step, BM_ELEM_TAG);
- }
- else {
- BMEdge *e_step = (BMEdge *)ele_walk;
- BLI_assert(ele_walk->head.htype == BM_EDGE);
- BM_edge_select_set(em->bm, e_step, true);
- BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG);
- BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG);
+ BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
+ }
+
+ /* exclude all delimited verts */
+ if (delimit) {
+ BMEdge *e;
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
+ BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, v) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMVert *v_step = ((BMLoop *)ele_walk)->v;
+ BM_vert_select_set(em->bm, v_step, true);
+ BM_elem_flag_disable(v_step, BM_ELEM_TAG);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(em->bm, e_step, true);
+ BM_elem_flag_disable(e_step->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e_step->v2, BM_ELEM_TAG);
+ }
}
}
}
}
- }
- else {
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- BMEdge *e_walk;
- BMW_ITER (e_walk, &walker, v) {
- BM_edge_select_set(em->bm, e_walk, true);
- BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ else {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, v) {
+ BM_edge_select_set(em->bm, e_walk, true);
+ BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ }
}
}
}
- }
- BMW_end(&walker);
+ BMW_end(&walker);
- EDBM_selectmode_flush(em);
- }
- else if (em->selectmode & SCE_SELECT_EDGE) {
- BMEdge *e;
+ EDBM_selectmode_flush(em);
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *e;
- if (delimit) {
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(
- e, BM_ELEM_TAG,
- (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
+ if (delimit) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(
+ e, BM_ELEM_TAG,
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
+ }
}
- }
- else {
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ else {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
}
- }
-
- BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
- BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
- if (delimit) {
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BMElem *ele_walk;
- BMW_ITER (ele_walk, &walker, e) {
- if (ele_walk->head.htype == BM_LOOP) {
- BMLoop *l_step = (BMLoop *)ele_walk;
- BM_edge_select_set(em->bm, l_step->e, true);
- BM_edge_select_set(em->bm, l_step->prev->e, true);
- BM_elem_flag_disable(l_step->e, BM_ELEM_TAG);
- }
- else {
- BMEdge *e_step = (BMEdge *)ele_walk;
- BLI_assert(ele_walk->head.htype == BM_EDGE);
- BM_edge_select_set(em->bm, e_step, true);
- BM_elem_flag_disable(e_step, BM_ELEM_TAG);
+ BMW_init(&walker, em->bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ if (delimit) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMElem *ele_walk;
+ BMW_ITER (ele_walk, &walker, e) {
+ if (ele_walk->head.htype == BM_LOOP) {
+ BMLoop *l_step = (BMLoop *)ele_walk;
+ BM_edge_select_set(em->bm, l_step->e, true);
+ BM_edge_select_set(em->bm, l_step->prev->e, true);
+ BM_elem_flag_disable(l_step->e, BM_ELEM_TAG);
+ }
+ else {
+ BMEdge *e_step = (BMEdge *)ele_walk;
+ BLI_assert(ele_walk->head.htype == BM_EDGE);
+ BM_edge_select_set(em->bm, e_step, true);
+ BM_elem_flag_disable(e_step, BM_ELEM_TAG);
+ }
}
}
}
}
- }
- else {
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BMEdge *e_walk;
- BMW_ITER (e_walk, &walker, e) {
- BM_edge_select_set(em->bm, e_walk, true);
- BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ else {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMEdge *e_walk;
+ BMW_ITER (e_walk, &walker, e) {
+ BM_edge_select_set(em->bm, e_walk, true);
+ BM_elem_flag_disable(e_walk, BM_ELEM_TAG);
+ }
}
}
}
- }
-
- BMW_end(&walker);
- EDBM_selectmode_flush(em);
- }
- else {
- BMFace *f;
+ BMW_end(&walker);
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
+ EDBM_selectmode_flush(em);
}
+ else {
+ BMFace *f;
- BMW_init(&walker, bm, BMW_ISLAND,
- BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_set(f, BM_ELEM_TAG, BM_elem_flag_test(f, BM_ELEM_SELECT));
+ }
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
- BMFace *f_walk;
- BMW_ITER (f_walk, &walker, f) {
- BM_face_select_set(bm, f_walk, true);
- BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
+ BMW_init(&walker, bm, BMW_ISLAND,
+ BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ BMFace *f_walk;
+ BMW_ITER (f_walk, &walker, f) {
+ BM_face_select_set(bm, f_walk, true);
+ BM_elem_flag_disable(f_walk, BM_ELEM_TAG);
+ }
}
}
+
+ BMW_end(&walker);
}
- BMW_end(&walker);
- }
+ if (delimit) {
+ select_linked_delimit_end(em);
+ }
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- if (delimit) {
- select_linked_delimit_end(em);
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -2872,10 +3119,8 @@ static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, in
static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
- BMEditMesh *em;
- BMesh *bm;
+ Base *basact = NULL;
BMVert *eve;
BMEdge *eed;
BMFace *efa;
@@ -2891,25 +3136,45 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
/* setup view context for argument to callbacks */
em_setup_viewcontext(C, &vc);
- em = vc.em;
- bm = em->bm;
- if (bm->totedge == 0) {
- return OPERATOR_CANCELLED;
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
+
+ {
+ bool has_edges = false;
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *ob_iter = bases[base_index]->object;
+ ED_view3d_viewcontext_init_object(&vc, ob_iter);
+ if (vc.em->bm->totedge) {
+ has_edges = true;
+ }
+ }
+ if (has_edges == false) {
+ MEM_freeN(bases);
+ return OPERATOR_CANCELLED;
+ }
}
vc.mval[0] = event->mval[0];
vc.mval[1] = event->mval[1];
/* return warning! */
- if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
-
- return OPERATOR_CANCELLED;
+ {
+ int base_index = -1;
+ const bool ok = unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa);
+ if (!ok) {
+ MEM_freeN(bases);
+ return OPERATOR_CANCELLED;
+ }
+ basact = bases[base_index];
}
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ BMEditMesh *em = vc.em;
+ BMesh *bm = em->bm;
+
#ifdef USE_LINKED_SELECT_DEFAULT_HACK
- int delimit = select_linked_delimit_default_from_op(op, em->selectmode);
+ int delimit = select_linked_delimit_default_from_op(op, vc.scene->toolsettings->selectmode);
#else
int delimit = RNA_enum_get(op->ptr, "delimit");
#endif
@@ -2922,10 +3187,14 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
BM_mesh_elem_index_ensure(bm, ele->head.htype);
index = EDBM_elem_to_index_any(em, ele);
+ /* TODO(MULTI_EDIT), index doesn't know which object,
+ * index selections isn't very common. */
RNA_int_set(op->ptr, "index", index);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(basact->object->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data);
+ MEM_freeN(bases);
return OPERATOR_FINISHED;
}
@@ -2953,6 +3222,7 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
edbm_select_linked_pick_ex(em, ele, sel, delimit);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -2995,47 +3265,57 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
const int numverts = RNA_int_get(op->ptr, "number");
const int type = RNA_enum_get(op->ptr, "type");
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (!RNA_boolean_get(op->ptr, "extend"))
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!extend) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ }
- bool select;
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ bool select;
- switch (type) {
- case 0:
- select = (efa->len < numverts);
- break;
- case 1:
- select = (efa->len == numverts);
- break;
- case 2:
- select = (efa->len > numverts);
- break;
- case 3:
- select = (efa->len != numverts);
- break;
- default:
- BLI_assert(0);
- select = false;
- break;
- }
+ switch (type) {
+ case 0:
+ select = (efa->len < numverts);
+ break;
+ case 1:
+ select = (efa->len == numverts);
+ break;
+ case 2:
+ select = (efa->len > numverts);
+ break;
+ case 3:
+ select = (efa->len != numverts);
+ break;
+ default:
+ BLI_assert(0);
+ select = false;
+ break;
+ }
- if (select) {
- BM_face_select_set(em->bm, efa, true);
+ if (select) {
+ BM_face_select_set(em->bm, efa, true);
+ }
}
- }
- EDBM_selectmode_flush(em);
+ EDBM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3075,53 +3355,66 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot)
static int edbm_select_loose_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMIter iter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
- if (!RNA_boolean_get(op->ptr, "extend"))
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (em->selectmode & SCE_SELECT_VERTEX) {
- BMVert *eve;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!eve->e) {
- BM_vert_select_set(bm, eve, true);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
+
+ if (!extend) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
}
- }
- if (em->selectmode & SCE_SELECT_EDGE) {
- BMEdge *eed;
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_edge_is_wire(eed)) {
- BM_edge_select_set(bm, eed, true);
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *eve;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!eve->e) {
+ BM_vert_select_set(bm, eve, true);
+ }
}
}
- }
- if (em->selectmode & SCE_SELECT_FACE) {
- BMFace *efa;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BMIter liter;
- BMLoop *l;
- bool is_loose = true;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (!BM_edge_is_boundary(l->e)) {
- is_loose = false;
- break;
+ if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *eed;
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_edge_is_wire(eed)) {
+ BM_edge_select_set(bm, eed, true);
}
}
- if (is_loose) {
- BM_face_select_set(bm, efa, true);
+ }
+
+ if (em->selectmode & SCE_SELECT_FACE) {
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BMIter liter;
+ BMLoop *l;
+ bool is_loose = true;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (!BM_edge_is_boundary(l->e)) {
+ is_loose = false;
+ break;
+ }
+ }
+ if (is_loose) {
+ BM_face_select_set(bm, efa, true);
+ }
}
}
+
+ EDBM_selectmode_flush(em);
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
- EDBM_selectmode_flush(em);
+ MEM_freeN(objects);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
@@ -3151,28 +3444,48 @@ void MESH_OT_select_loose(wmOperatorType *ot)
static int edbm_select_mirror_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const int axis_flag = RNA_enum_get(op->ptr, "axis");
const bool extend = RNA_boolean_get(op->ptr, "extend");
+ Object *obedit_active = CTX_data_edit_object(C);
+ BMEditMesh *em_active = BKE_editmesh_from_object(obedit_active);
+ const int select_mode = em_active->bm->selectmode;
+ int tot_mirr = 0, tot_fail = 0;
- if (em->bm->totvert && em->bm->totvertsel) {
- int totmirr, totfail;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+
+ int tot_mirr_iter = 0, tot_fail_iter = 0;
for (int axis = 0; axis < 3; axis++) {
if ((1 << axis) & axis_flag) {
- EDBM_select_mirrored(em, axis, extend, &totmirr, &totfail);
+ EDBM_select_mirrored(em, axis, extend, &tot_mirr_iter, &tot_fail_iter);
}
}
- if (totmirr) {
+ if (tot_mirr_iter) {
EDBM_selectmode_flush(em);
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
- ED_mesh_report_mirror_ex(op, totmirr, totfail, em->bm->selectmode);
+ tot_fail += tot_fail_iter;
+ tot_mirr += tot_mirr_iter;
}
+ MEM_freeN(objects);
+ if (tot_mirr || tot_fail) {
+ ED_mesh_report_mirror_ex(op, tot_mirr, tot_fail, select_mode);
+ }
return OPERATOR_FINISHED;
}
@@ -3204,13 +3517,29 @@ void MESH_OT_select_mirror(wmOperatorType *ot)
static int edbm_select_more_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
- EDBM_select_more(em, use_face_step);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ if ((bm->totvertsel == 0) &&
+ (bm->totedgesel == 0) &&
+ (bm->totfacesel == 0))
+ {
+ continue;
+ }
+
+ EDBM_select_more(em, use_face_step);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3239,13 +3568,29 @@ void MESH_OT_select_more(wmOperatorType *ot)
static int edbm_select_less_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
- EDBM_select_less(em, use_face_step);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ if ((bm->totvertsel == 0) &&
+ (bm->totedgesel == 0) &&
+ (bm->totfacesel == 0))
+ {
+ continue;
+ }
+
+ EDBM_select_less(em, use_face_step);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3458,18 +3803,39 @@ static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams
static int edbm_select_nth_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
struct CheckerIntervalParams op_params;
-
WM_operator_properties_checker_interval_from_op(op, &op_params);
+ bool found_active_elt = false;
- if (edbm_deselect_nth(em, &op_params) == false) {
- BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
- return OPERATOR_CANCELLED;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if ((em->bm->totvertsel == 0) &&
+ (em->bm->totedgesel == 0) &&
+ (em->bm->totfacesel == 0))
+ {
+ continue;
+ }
+
+ if (edbm_deselect_nth(em, &op_params) == true) {
+ found_active_elt = true;
+ EDBM_update_generic(em, false, false);
+ }
}
+ MEM_freeN(objects);
- EDBM_update_generic(em, false, false);
+ if (!found_active_elt) {
+ BKE_report(op->reports, RPT_ERROR,
+ (objects_len == 1 ?
+ "Mesh has no active vert/edge/face" :
+ "Meshes have no active vert/edge/face"));
+ return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
@@ -3513,34 +3879,43 @@ static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op)
* check the angle between those faces, and if angle is
* small enough, select the edge
*/
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter;
- BMEdge *e;
- BMLoop *l1, *l2;
const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false &&
- BM_edge_loop_pair(e, &l1, &l2))
- {
- /* edge has exactly two neighboring faces, check angle */
- const float angle_cos = dot_v3v3(l1->f->no, l2->f->no);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (angle_cos < angle_limit_cos) {
- BM_edge_select_set(em->bm, e, true);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter;
+ BMEdge *e;
+ BMLoop *l1, *l2;
+
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false &&
+ BM_edge_loop_pair(e, &l1, &l2))
+ {
+ /* edge has exactly two neighboring faces, check angle */
+ const float angle_cos = dot_v3v3(l1->f->no, l2->f->no);
+
+ if (angle_cos < angle_limit_cos) {
+ BM_edge_select_set(em->bm, e, true);
+ }
}
}
- }
- if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
- /* Since we can't select individual edges, select faces connected to them. */
- EDBM_selectmode_convert(em, SCE_SELECT_EDGE, SCE_SELECT_FACE);
- }
- else {
- EDBM_selectmode_flush(em);
+ if ((em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
+ /* Since we can't select individual edges, select faces connected to them. */
+ EDBM_selectmode_convert(em, SCE_SELECT_EDGE, SCE_SELECT_FACE);
+ }
+ else {
+ EDBM_selectmode_flush(em);
+ }
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3575,59 +3950,71 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot)
static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
-
- BLI_LINKSTACK_DECLARE(stack, BMFace *);
-
- BMIter iter, liter, liter2;
- BMFace *f;
- BMLoop *l, *l2;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
- BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
-
- BLI_LINKSTACK_INIT(stack);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) ||
- (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) ||
- (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0))
- {
+ if (bm->totfacesel == 0) {
continue;
}
- BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0);
+ BLI_LINKSTACK_DECLARE(stack, BMFace *);
- do {
- BM_face_select_set(bm, f, true);
+ BMIter iter, liter, liter2;
+ BMFace *f;
+ BMLoop *l, *l2;
- BM_elem_flag_enable(f, BM_ELEM_TAG);
+ BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) {
- float angle_cos;
+ BLI_LINKSTACK_INIT(stack);
- if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) ||
- BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN))
- {
- continue;
- }
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) ||
+ (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) ||
+ (BM_elem_flag_test(f, BM_ELEM_SELECT) == 0))
+ {
+ continue;
+ }
+
+ BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0);
+
+ do {
+ BM_face_select_set(bm, f, true);
- angle_cos = dot_v3v3(f->no, l2->f->no);
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
- if (angle_cos > angle_limit_cos) {
- BLI_LINKSTACK_PUSH(stack, l2->f);
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) {
+ float angle_cos;
+
+ if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) ||
+ BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN))
+ {
+ continue;
+ }
+
+ angle_cos = dot_v3v3(f->no, l2->f->no);
+
+ if (angle_cos > angle_limit_cos) {
+ BLI_LINKSTACK_PUSH(stack, l2->f);
+ }
}
}
- }
- } while ((f = BLI_LINKSTACK_POP(stack)));
- }
+ } while ((f = BLI_LINKSTACK_POP(stack)));
+ }
- BLI_LINKSTACK_FREE(stack);
+ BLI_LINKSTACK_FREE(stack);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3662,61 +4049,71 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMVert *v;
- BMEdge *e;
- BMIter iter;
-
+ const bool use_extend = RNA_boolean_get(op->ptr, "extend");
const bool use_wire = RNA_boolean_get(op->ptr, "use_wire");
const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face");
const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous");
const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (!RNA_boolean_get(op->ptr, "extend"))
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMVert *v;
+ BMEdge *e;
+ BMIter iter;
- /* Selects isolated verts, and edges that do not have 2 neighboring
- * faces
- */
+ if (!use_extend) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ }
- if (em->selectmode == SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode");
- return OPERATOR_CANCELLED;
- }
+ /* Selects isolated verts, and edges that do not have 2 neighboring
+ * faces
+ */
- if (use_verts) {
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- if (!BM_vert_is_manifold(v)) {
- BM_vert_select_set(em->bm, v, true);
+ if (em->selectmode == SCE_SELECT_FACE) {
+ BKE_report(op->reports, RPT_ERROR, "Does not work in face selection mode");
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (use_verts) {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ if (!BM_vert_is_manifold(v)) {
+ BM_vert_select_set(em->bm, v, true);
+ }
}
}
}
- }
- if (use_wire || use_boundary || use_multi_face || use_non_contiguous) {
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- if ((use_wire && BM_edge_is_wire(e)) ||
- (use_boundary && BM_edge_is_boundary(e)) ||
- (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
- (use_multi_face && (BM_edge_face_count_is_over(e, 2))))
- {
- /* check we never select perfect edge (in test above) */
- BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e)));
+ if (use_wire || use_boundary || use_multi_face || use_non_contiguous) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if ((use_wire && BM_edge_is_wire(e)) ||
+ (use_boundary && BM_edge_is_boundary(e)) ||
+ (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) ||
+ (use_multi_face && (BM_edge_face_count_is_over(e, 2))))
+ {
+ /* check we never select perfect edge (in test above) */
+ BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e)));
- BM_edge_select_set(em->bm, e, true);
+ BM_edge_select_set(em->bm, e, true);
+ }
}
}
}
- }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- EDBM_selectmode_flush(em);
+ EDBM_selectmode_flush(em);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3759,53 +4156,67 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
static int edbm_select_random_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
- BMIter iter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter;
+ int seed_iter = seed;
- RNG *rng = BLI_rng_new_srandom(seed);
+ /* This gives a consistent result regardless of object order. */
+ if (ob_index) {
+ seed_iter += BLI_ghashutil_strhash_p(obedit->id.name);
+ }
- if (em->selectmode & SCE_SELECT_VERTEX) {
- BMVert *eve;
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
- BM_vert_select_set(em->bm, eve, select);
+ RNG *rng = BLI_rng_new_srandom(seed_iter);
+
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *eve;
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
+ BM_vert_select_set(em->bm, eve, select);
+ }
}
}
- }
- else if (em->selectmode & SCE_SELECT_EDGE) {
- BMEdge *eed;
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
- BM_edge_select_set(em->bm, eed, select);
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *eed;
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
+ BM_edge_select_set(em->bm, eed, select);
+ }
}
}
- }
- else {
- BMFace *efa;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
- BM_face_select_set(em->bm, efa, select);
+ else {
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
+ BM_face_select_set(em->bm, efa, select);
+ }
}
}
- }
- BLI_rng_free(rng);
+ BLI_rng_free(rng);
- if (select) {
- /* was EDBM_select_flush, but it over select in edge/face mode */
- EDBM_selectmode_flush(em);
- }
- else {
- EDBM_deselect_flush(em);
- }
+ if (select) {
+ /* was EDBM_select_flush, but it over select in edge/face mode */
+ EDBM_selectmode_flush(em);
+ }
+ else {
+ EDBM_deselect_flush(em);
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3855,30 +4266,52 @@ static bool edbm_select_ungrouped_poll(bContext *C)
static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- BMVert *eve;
- BMIter iter;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (!RNA_boolean_get(op->ptr, "extend")) {
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+
+ if (cd_dvert_offset == -1) {
+ continue;
+ }
+
+ BMVert *eve;
+ BMIter iter;
+
+ bool changed = false;
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- /* no dv or dv set with no weight */
- if (ELEM(NULL, dv, dv->dw)) {
- BM_vert_select_set(em->bm, eve, true);
+ if (!extend) {
+ if (em->bm->totvertsel) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ changed = true;
}
}
- }
- EDBM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
+ /* no dv or dv set with no weight */
+ if (ELEM(NULL, dv, dv->dw)) {
+ BM_vert_select_set(em->bm, eve, true);
+ changed = true;
+ }
+ }
+ }
+ if (changed) {
+ EDBM_selectmode_flush(em);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3905,70 +4338,112 @@ void MESH_OT_select_ungrouped(wmOperatorType *ot)
/** \name Select Axis Operator
* \{ */
-/* BMESH_TODO - some way to select on an arbitrary axis */
+enum {
+ SELECT_AXIS_POS = 0,
+ SELECT_AXIS_NEG = 1,
+ SELECT_AXIS_ALIGN = 2,
+};
+
static int edbm_select_axis_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMVert *v_act = BM_mesh_active_vert_get(bm);
+ BMVert *v_act = BM_mesh_active_vert_get(em->bm);
+ const int orientation = RNA_enum_get(op->ptr, "orientation");
const int axis = RNA_enum_get(op->ptr, "axis");
- const int mode = RNA_enum_get(op->ptr, "mode"); /* -1 == aligned, 0 == neg, 1 == pos */
+ const int sign = RNA_enum_get(op->ptr, "sign");
if (v_act == NULL) {
BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)");
return OPERATOR_CANCELLED;
}
- else {
- BMVert *v;
- BMIter iter;
- const float limit = RNA_float_get(op->ptr, "threshold");
- float value = v_act->co[axis];
- if (mode == 0)
- value -= limit;
- else if (mode == 1)
- value += limit;
+ const float limit = RNA_float_get(op->ptr, "threshold");
+
+ float value;
+ float axis_mat[3][3];
+
+ /* 3D view variables may be NULL, (no need to check in poll function). */
+ ED_transform_calc_orientation_from_type_ex(
+ C, axis_mat,
+ scene, CTX_wm_region_view3d(C), obedit, obedit,
+ orientation, V3D_AROUND_ACTIVE);
+
+ const float *axis_vector = axis_mat[axis];
+
+ {
+ float vertex_world[3];
+ mul_v3_m4v3(vertex_world, obedit->obmat, v_act->co);
+ value = dot_v3v3(axis_vector, vertex_world);
+ }
+
+ if (sign == SELECT_AXIS_NEG) {
+ value += limit;
+ }
+ else if (sign == SELECT_AXIS_POS) {
+ value -= limit;
+ }
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit_iter = objects[ob_index];
+ BMEditMesh *em_iter = BKE_editmesh_from_object(obedit_iter);
+ BMesh *bm = em_iter->bm;
+
+ if (bm->totvert == bm->totvertsel) {
+ continue;
+ }
+
+ BMIter iter;
+ BMVert *v;
+ bool changed = false;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- switch (mode) {
- case -1: /* aligned */
- if (fabsf(v->co[axis] - value) < limit)
+ if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN | BM_ELEM_SELECT)) {
+ float v_iter_world[3];
+ mul_v3_m4v3(v_iter_world, obedit_iter->obmat, v->co);
+ const float value_iter = dot_v3v3(axis_vector, v_iter_world);
+ switch (sign) {
+ case SELECT_AXIS_ALIGN:
+ if (fabsf(value_iter - value) < limit) {
BM_vert_select_set(bm, v, true);
+ changed = true;
+ }
break;
- case 0: /* neg */
- if (v->co[axis] > value)
+ case SELECT_AXIS_NEG:
+ if (value_iter < value) {
BM_vert_select_set(bm, v, true);
+ changed = true;
+ }
break;
- case 1: /* pos */
- if (v->co[axis] < value)
+ case SELECT_AXIS_POS:
+ if (value_iter > value) {
BM_vert_select_set(bm, v, true);
+ changed = true;
+ }
break;
}
}
}
+ if (changed) {
+ EDBM_selectmode_flush(em_iter);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit_iter->data);
+ DEG_id_tag_update(obedit_iter->data, DEG_TAG_SELECT_UPDATE);
+ }
}
-
- EDBM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
void MESH_OT_select_axis(wmOperatorType *ot)
{
- static const EnumPropertyItem axis_mode_items[] = {
- {0, "POSITIVE", 0, "Positive Axis", ""},
- {1, "NEGATIVE", 0, "Negative Axis", ""},
- {-1, "ALIGNED", 0, "Aligned Axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem axis_items_xyz[] = {
- {0, "X_AXIS", 0, "X Axis", ""},
- {1, "Y_AXIS", 0, "Y Axis", ""},
- {2, "Z_AXIS", 0, "Z Axis", ""},
+ static const EnumPropertyItem axis_sign_items[] = {
+ {SELECT_AXIS_POS, "POS", 0, "Positive Axis", ""},
+ {SELECT_AXIS_NEG, "NEG", 0, "Negative Axis", ""},
+ {SELECT_AXIS_ALIGN, "ALIGN", 0, "Aligned Axis", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3985,8 +4460,9 @@ void MESH_OT_select_axis(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
- RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
+ RNA_def_enum(ot->srna, "orientation", rna_enum_transform_orientation_items, V3D_MANIP_LOCAL, "Axis Mode", "Axis orientation");
+ RNA_def_enum(ot->srna, "sign", axis_sign_items, SELECT_AXIS_POS, "Axis Sign", "Side to select");
+ RNA_def_enum(ot->srna, "axis", rna_enum_axis_xyz_items, 0, "Axis", "Select the axis to compare each vertex on");
RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f);
}
@@ -3998,48 +4474,59 @@ void MESH_OT_select_axis(wmOperatorType *ot)
static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *f;
- BMEdge *e;
- BMIter iter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+ BMFace *f;
+ BMEdge *e;
+ BMIter iter;
- BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false);
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false);
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- BMLoop *l1, *l2;
- BMIter liter1, liter2;
+ BM_ITER_MESH(f, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l1, *l2;
+ BMIter liter1, liter2;
- BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
- int tot = 0, totsel = 0;
+ BM_ITER_ELEM(l1, &liter1, f, BM_LOOPS_OF_FACE) {
+ int tot = 0, totsel = 0;
- BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
- tot++;
- totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
- }
+ BM_ITER_ELEM(l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
+ tot++;
+ totsel += BM_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0;
+ }
- if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
- BM_elem_flag_enable(l1->e, BM_ELEM_TAG);
+ if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
+ BM_elem_flag_enable(l1->e, BM_ELEM_TAG);
+ }
}
- }
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_edge_select_set(em->bm, e, true);
+ BM_ITER_MESH(e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_edge_select_set(em->bm, e, true);
+ }
}
- }
- /* If in face-only select mode, switch to edge select mode so that
- * an edge-only selection is not inconsistent state */
- if (em->selectmode == SCE_SELECT_FACE) {
- em->selectmode = SCE_SELECT_EDGE;
- EDBM_selectmode_set(em);
- EDBM_selectmode_to_scene(C);
- }
+ /* If in face-only select mode, switch to edge select mode so that
+ * an edge-only selection is not inconsistent state */
+ if (em->selectmode == SCE_SELECT_FACE) {
+ em->selectmode = SCE_SELECT_EDGE;
+ EDBM_selectmode_set(em);
+ EDBM_selectmode_to_scene(C);
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4210,31 +4697,45 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
static int edbm_loop_to_region_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter;
- BMFace *f;
const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger");
- /* find the set of regions with smallest number of total faces */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
- const int a = loop_find_regions(em, select_bigger);
- const int b = loop_find_regions(em, !select_bigger);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
+
+ BMIter iter;
+ BMFace *f;
+
+ /* find the set of regions with smallest number of total faces */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ const int a = loop_find_regions(em, select_bigger);
+ const int b = loop_find_regions(em, !select_bigger);
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
- loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger);
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BM_face_select_set(em->bm, f, true);
+ BM_ITER_MESH(f, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ BM_face_select_set(em->bm, f, true);
+ }
}
- }
- EDBM_selectmode_flush(em);
+ EDBM_selectmode_flush(em);
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ MEM_freeN(objects);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
new file mode 100644
index 00000000000..89e821c52d8
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -0,0 +1,1376 @@
+/*
+ * ***** 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) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_select_similar.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_kdtree.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_material.h"
+#include "BKE_report.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_select_utils.h"
+
+#include "mesh_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Similar (Vert/Edge/Face) Operator - common
+ * \{ */
+
+static const EnumPropertyItem prop_similar_compare_types[] = {
+ {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
+ {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
+ {SIM_CMP_LT, "LESS", 0, "Less", ""},
+
+ {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem prop_similar_types[] = {
+ {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
+ {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
+ {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
+ {SIMVERT_EDGE, "EDGE", 0, "Amount of connecting edges", ""},
+
+ {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
+ {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
+ {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
+ {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
+ {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
+ {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""},
+ {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
+ {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
+#ifdef WITH_FREESTYLE
+ {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""},
+#endif
+
+ {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
+ {SIMFACE_AREA, "AREA", 0, "Area", ""},
+ {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""},
+ {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
+ {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
+ {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
+ {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""},
+ {SIMFACE_FACEMAP, "FACE_MAP", 0, "Face-Map", ""},
+#ifdef WITH_FREESTYLE
+ {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
+#endif
+
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int mesh_select_similar_compare_int(const int delta, const int compare)
+{
+ switch (compare) {
+ case SIM_CMP_EQ:
+ return (delta == 0);
+ case SIM_CMP_GT:
+ return (delta > 0);
+ case SIM_CMP_LT:
+ return (delta < 0);
+ default:
+ BLI_assert(0);
+ return 0;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Similar Face
+ * \{ */
+
+enum {
+ SIMFACE_DATA_NONE = 0,
+ SIMFACE_DATA_TRUE = (1 << 0),
+ SIMFACE_DATA_FALSE = (1 << 1),
+ SIMFACE_DATA_ALL = (SIMFACE_DATA_TRUE | SIMFACE_DATA_FALSE),
+};
+
+/**
+ * Return true if we still don't know the final value for this edge data.
+ * In other words, if we need to keep iterating over the objects or we can
+ * just go ahead and select all the objects.
+ */
+static bool face_data_value_set(BMFace *face, const int hflag, int *r_value)
+{
+ if (BM_elem_flag_test(face, hflag)) {
+ *r_value |= SIMFACE_DATA_TRUE;
+ }
+ else {
+ *r_value |= SIMFACE_DATA_FALSE;
+ }
+
+ return *r_value != SIMFACE_DATA_ALL;
+}
+
+/**
+ * Note: This is not normal, but the face direction itself and always in
+ * a positive quadrant (tries z, y then x).
+ * Also, unlike edge_pos_direction_worldspace_get we don't normalize the direction.
+ * In fact we scale the direction by the distance of the face center to the origin.
+ */
+static void face_pos_direction_worldspace_scaled_get(Object *ob, BMFace *face, float *r_dir)
+{
+ float distance;
+ float center[3];
+
+ copy_v3_v3(r_dir, face->no);
+ normalize_v3(r_dir);
+
+ BM_face_calc_center_mean(face, center);
+ mul_m4_v3(ob->obmat, center);
+
+ distance = dot_v3v3(r_dir, center);
+ mul_v3_fl(r_dir, distance);
+
+ /* Make sure we have a consistent direction regardless of the face orientation.
+ * This spares us from storing dir and -dir in the tree. */
+ if (fabs(r_dir[2]) < FLT_EPSILON) {
+ if (fabs(r_dir[1]) < FLT_EPSILON) {
+ if (r_dir[0] < 0.0f) {
+ mul_v3_fl(r_dir, -1.0f);
+ }
+ }
+ else if (r_dir[1] < 0.0f) {
+ mul_v3_fl(r_dir, -1.0f);
+ }
+ }
+ else if (r_dir[2] < 0.0f) {
+ mul_v3_fl(r_dir, -1.0f);
+ }
+}
+
+/* TODO(dfelinto): `types` that should technically be compared in world space but are not:
+ * -SIMFACE_AREA
+ * -SIMFACE_PERIMETER
+ */
+static int similar_face_select_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ const int type = RNA_enum_get(op->ptr, "type");
+ const float thresh = RNA_float_get(op->ptr, "threshold");
+ const float thresh_radians = thresh * (float)M_PI;
+ const int compare = RNA_enum_get(op->ptr, "compare");
+
+ int tot_faces_selected_all = 0;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ tot_faces_selected_all += em->bm->totfacesel;
+ }
+
+ if (tot_faces_selected_all == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No face selected");
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+
+ KDTree *tree = NULL;
+ GSet *gset = NULL;
+ GSet **gset_array = NULL;
+ int face_data_value = SIMFACE_DATA_NONE;
+
+ switch (type) {
+ case SIMFACE_AREA:
+ case SIMFACE_PERIMETER:
+ case SIMFACE_NORMAL:
+ case SIMFACE_COPLANAR:
+ tree = BLI_kdtree_new(tot_faces_selected_all);
+ break;
+ case SIMFACE_SIDES:
+ case SIMFACE_MATERIAL:
+ gset = BLI_gset_ptr_new("Select similar face");
+ break;
+ case SIMFACE_FACEMAP:
+ gset_array = MEM_callocN(sizeof(GSet *) * objects_len, "Select similar face: facemap gset array");
+ break;
+ }
+
+ int tree_index = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ Material ***material_array = NULL;
+ invert_m4_m4(ob->imat, ob->obmat);
+ int custom_data_offset = 0;
+
+ if (bm->totfacesel == 0) {
+ continue;
+ }
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ switch (type) {
+ case SIMFACE_MATERIAL:
+ {
+ if (ob->totcol == 0) {
+ continue;
+ }
+ material_array = give_matarar(ob);
+ break;
+ }
+ case SIMFACE_FREESTYLE:
+ {
+ if (!CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) {
+ face_data_value |= SIMFACE_DATA_FALSE;
+ continue;
+ }
+ break;
+ }
+ case SIMFACE_FACEMAP:
+ {
+ custom_data_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
+ if (custom_data_offset == -1) {
+ continue;
+ }
+ else {
+ gset_array[ob_index] = BLI_gset_ptr_new("Select similar face: facemap gset");
+ }
+ }
+ }
+
+ BMFace *face; /* Mesh face. */
+ BMIter iter; /* Selected faces iterator. */
+
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(face, BM_ELEM_SELECT)) {
+ switch (type) {
+ case SIMFACE_SIDES:
+ BLI_gset_add(gset, POINTER_FROM_INT(face->len));
+ break;
+ case SIMFACE_MATERIAL:
+ {
+ Material *material = (*material_array)[face->mat_nr];
+ if (material != NULL) {
+ BLI_gset_add(gset, material);
+ }
+ break;
+ }
+ case SIMFACE_AREA:
+ {
+ float area = BM_face_calc_area_with_mat3(face, ob_m3);
+ float dummy[3] = {area, 0.0f, 0.0f};
+ BLI_kdtree_insert(tree, tree_index++, dummy);
+ break;
+ }
+ case SIMFACE_PERIMETER:
+ {
+ float perimeter = BM_face_calc_perimeter_with_mat3(face, ob_m3);
+ float dummy[3] = {perimeter, 0.0f, 0.0f};
+ BLI_kdtree_insert(tree, tree_index++, dummy);
+ break;
+ break;
+ }
+ case SIMFACE_NORMAL:
+ {
+ float normal[3];
+ copy_v3_v3(normal, face->no);
+ mul_transposed_mat3_m4_v3(ob->imat, normal);
+ normalize_v3(normal);
+
+ BLI_kdtree_insert(tree, tree_index++, normal);
+ break;
+ }
+ case SIMFACE_COPLANAR:
+ {
+ float dir[3];
+ face_pos_direction_worldspace_scaled_get(ob, face, dir);
+ BLI_kdtree_insert(tree, tree_index++, dir);
+ break;
+ }
+ case SIMFACE_SMOOTH:
+ {
+ if (!face_data_value_set(face, BM_ELEM_SMOOTH, &face_data_value)) {
+ goto face_select_all;
+ }
+ break;
+ }
+ case SIMFACE_FREESTYLE:
+ {
+ FreestyleFace *fface;
+ fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_FREESTYLE_FACE);
+ if ((fface == NULL) || ((fface->flag & FREESTYLE_FACE_MARK) == 0)) {
+ face_data_value |= SIMFACE_DATA_FALSE;
+ }
+ else {
+ face_data_value |= SIMFACE_DATA_TRUE;
+ }
+ if (face_data_value == SIMFACE_DATA_ALL) {
+ goto face_select_all;
+ }
+ break;
+ }
+ case SIMFACE_FACEMAP:
+ {
+ BLI_assert(custom_data_offset != -1);
+ int *face_map = BM_ELEM_CD_GET_VOID_P(face, custom_data_offset);
+ BLI_gset_add(gset_array[ob_index], face_map);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ BLI_assert((type != SIMFACE_FREESTYLE) || (face_data_value != SIMFACE_DATA_NONE));
+
+ if (tree != NULL) {
+ BLI_kdtree_balance(tree);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ bool changed = false;
+ Material ***material_array = NULL;
+ int custom_data_offset;
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ bool has_custom_data_layer = false;
+ switch (type) {
+ case SIMFACE_MATERIAL:
+ {
+ if (ob->totcol == 0) {
+ continue;
+ }
+ material_array = give_matarar(ob);
+ break;
+ }
+ case SIMFACE_FREESTYLE:
+ {
+ has_custom_data_layer = CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE);
+ if ((face_data_value == SIMFACE_DATA_TRUE) && !has_custom_data_layer) {
+ continue;
+ }
+ break;
+ }
+ case SIMFACE_FACEMAP:
+ {
+ custom_data_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
+ if (custom_data_offset == -1) {
+ continue;
+ }
+ }
+ }
+
+ BMFace *face; /* Mesh face. */
+ BMIter iter; /* Selected faces iterator. */
+
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(face, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(face, BM_ELEM_HIDDEN))
+ {
+ bool select = false;
+ switch (type) {
+ case SIMFACE_SIDES:
+ {
+ const int num_sides = face->len;
+ GSetIterator gs_iter;
+ GSET_ITER(gs_iter, gset) {
+ const int num_sides_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
+ const int delta_i = num_sides - num_sides_iter;
+ if (mesh_select_similar_compare_int(delta_i, compare)) {
+ select = true;
+ break;
+ }
+ }
+ break;
+ }
+ case SIMFACE_MATERIAL:
+ {
+ const Material *material = (*material_array)[face->mat_nr];
+ if (material == NULL) {
+ continue;
+ }
+
+ GSetIterator gs_iter;
+ GSET_ITER(gs_iter, gset) {
+ const Material *material_iter = BLI_gsetIterator_getKey(&gs_iter);
+ if (material == material_iter) {
+ select = true;
+ break;
+ }
+ }
+ break;
+ }
+ case SIMFACE_AREA:
+ {
+ float area = BM_face_calc_area_with_mat3(face, ob_m3);
+ if (ED_select_similar_compare_float_tree(tree, area, thresh, compare)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMFACE_PERIMETER:
+ {
+ float perimeter = BM_face_calc_perimeter_with_mat3(face, ob_m3);
+ if (ED_select_similar_compare_float_tree(tree, perimeter, thresh, compare)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMFACE_NORMAL:
+ {
+ float normal[3];
+ copy_v3_v3(normal, face->no);
+ mul_transposed_mat3_m4_v3(ob->imat, normal);
+ normalize_v3(normal);
+
+ /* We are treating the normals as coordinates, the "nearest" one will
+ * also be the one closest to the angle. */
+ KDTreeNearest nearest;
+ if (BLI_kdtree_find_nearest(tree, normal, &nearest) != -1) {
+ if (angle_normalized_v3v3(normal, nearest.co) <= thresh_radians) {
+ select = true;
+ }
+ }
+ break;
+ }
+ case SIMFACE_COPLANAR:
+ {
+ float diff[3];
+ float dir[3];
+ face_pos_direction_worldspace_scaled_get(ob, face, dir);
+
+ /* We are treating the direction as coordinates, the "nearest" one will
+ * also be the one closest to the angle.
+ * And since the direction is scaled by the face center distance to the origin,
+ * the nearest point will also be the closest between the planes. */
+ KDTreeNearest nearest;
+ if (BLI_kdtree_find_nearest(tree, dir, &nearest) != -1) {
+ sub_v3_v3v3(diff, dir, nearest.co);
+ if (len_v3(diff) <= thresh) {
+ if (angle_v3v3(dir, nearest.co) <= thresh_radians) {
+ select = true;
+ }
+ }
+ }
+ break;
+ }
+ case SIMFACE_SMOOTH:
+ if ((BM_elem_flag_test(face, BM_ELEM_SMOOTH) != 0) ==
+ ((face_data_value & SIMFACE_DATA_TRUE) != 0))
+ {
+ select = true;
+ }
+ break;
+ case SIMFACE_FREESTYLE:
+ {
+ FreestyleFace *fface;
+
+ if (!has_custom_data_layer) {
+ BLI_assert(face_data_value == SIMFACE_DATA_FALSE);
+ select = true;
+ break;
+ }
+
+ fface = CustomData_bmesh_get(&bm->pdata, face->head.data, CD_FREESTYLE_FACE);
+ if (((fface != NULL) && (fface->flag & FREESTYLE_FACE_MARK)) ==
+ ((face_data_value & SIMFACE_DATA_TRUE) != 0))
+ {
+ select = true;
+ }
+ break;
+ }
+ case SIMFACE_FACEMAP:
+ {
+ const int *face_map = BM_ELEM_CD_GET_VOID_P(face, custom_data_offset);
+ GSetIterator gs_iter;
+ GSET_ITER(gs_iter, gset_array[ob_index]) {
+ const int *face_map_iter = BLI_gsetIterator_getKey(&gs_iter);
+ if (*face_map == *face_map_iter) {
+ select = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (select) {
+ BM_face_select_set(bm, face, true);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ EDBM_selectmode_flush(em);
+ EDBM_update_generic(em, false, false);
+ }
+ }
+
+ if (false) {
+face_select_all:
+ BLI_assert(ELEM(type,
+ SIMFACE_SMOOTH,
+ SIMFACE_FREESTYLE
+ ));
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+
+ BMFace *face; /* Mesh face. */
+ BMIter iter; /* Selected faces iterator. */
+
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(face, BM_ELEM_SELECT)) {
+ BM_face_select_set(bm, face, true);
+ }
+ }
+ EDBM_selectmode_flush(em);
+ EDBM_update_generic(em, false, false);
+ }
+ }
+
+ MEM_freeN(objects);
+ BLI_kdtree_free(tree);
+ if (gset != NULL) {
+ BLI_gset_free(gset, NULL);
+ }
+ if (gset_array != NULL) {
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (gset_array[ob_index] != NULL) {
+ BLI_gset_free(gset_array[ob_index], NULL);
+ }
+ }
+ MEM_freeN(gset_array);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Similar Edge
+ * \{ */
+
+
+/**
+ * Note: This is not normal, but the edge direction itself and always in
+ * a positive quadrant (tries z, y then x).
+ * Therefore we need to use the entire object transformation matrix.
+ */
+static void edge_pos_direction_worldspace_get(Object *ob, BMEdge *edge, float *r_dir)
+{
+ float v1[3], v2[3];
+ copy_v3_v3(v1, edge->v1->co);
+ copy_v3_v3(v2, edge->v2->co);
+
+ mul_m4_v3(ob->obmat, v1);
+ mul_m4_v3(ob->obmat, v2);
+
+ sub_v3_v3v3(r_dir, v1, v2);
+ normalize_v3(r_dir);
+
+ /* Make sure we have a consistent direction that can be checked regardless of
+ * the verts order of the edges. This spares us from storing dir and -dir in the tree. */
+ if (fabs(r_dir[2]) < FLT_EPSILON) {
+ if (fabs(r_dir[1]) < FLT_EPSILON) {
+ if (r_dir[0] < 0.0f) {
+ mul_v3_fl(r_dir, -1.0f);
+ }
+ }
+ else if (r_dir[1] < 0.0f) {
+ mul_v3_fl(r_dir, -1.0f);
+ }
+ }
+ else if (r_dir[2] < 0.0f) {
+ mul_v3_fl(r_dir, -1.0f);
+ }
+}
+
+static float edge_length_squared_worldspace_get(Object *ob, BMEdge *edge)
+{
+ float v1[3], v2[3];
+
+ mul_v3_mat3_m4v3(v1, ob->obmat, edge->v1->co);
+ mul_v3_mat3_m4v3(v2, ob->obmat, edge->v2->co);
+
+ return len_squared_v3v3(v1, v2);
+}
+
+enum {
+ SIMEDGE_DATA_NONE = 0,
+ SIMEDGE_DATA_TRUE = (1 << 0),
+ SIMEDGE_DATA_FALSE = (1 << 1),
+ SIMEDGE_DATA_ALL = (SIMEDGE_DATA_TRUE | SIMEDGE_DATA_FALSE),
+};
+
+/**
+ * Return true if we still don't know the final value for this edge data.
+ * In other words, if we need to keep iterating over the objects or we can
+ * just go ahead and select all the objects.
+ */
+static bool edge_data_value_set(BMEdge *edge, const int hflag, int *r_value)
+{
+ if (BM_elem_flag_test(edge, hflag)) {
+ *r_value |= SIMEDGE_DATA_TRUE;
+ }
+ else {
+ *r_value |= SIMEDGE_DATA_FALSE;
+ }
+
+ return *r_value != SIMEDGE_DATA_ALL;
+}
+
+/* TODO(dfelinto): `types` that should technically be compared in world space but are not:
+ * -SIMEDGE_FACE_ANGLE
+ */
+static int similar_edge_select_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ const int type = RNA_enum_get(op->ptr, "type");
+ const float thresh = RNA_float_get(op->ptr, "threshold");
+ const float thresh_radians = thresh * (float)M_PI + FLT_EPSILON;
+ const int compare = RNA_enum_get(op->ptr, "compare");
+ int custom_data_type = -1;
+
+ int tot_edges_selected_all = 0;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ tot_edges_selected_all += em->bm->totedgesel;
+ }
+
+ if (tot_edges_selected_all == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No edge selected");
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+
+ KDTree *tree = NULL;
+ GSet *gset = NULL;
+ int edge_data_value = SIMEDGE_DATA_NONE;
+
+ switch (type) {
+ case SIMEDGE_CREASE:
+ case SIMEDGE_BEVEL:
+ case SIMEDGE_FACE_ANGLE:
+ case SIMEDGE_LENGTH:
+ case SIMEDGE_DIR:
+ tree = BLI_kdtree_new(tot_edges_selected_all);
+ break;
+ case SIMEDGE_FACE:
+ gset = BLI_gset_ptr_new("Select similar edge: face");
+ break;
+ }
+
+ switch (type) {
+ case SIMEDGE_CREASE:
+ custom_data_type = CD_CREASE;
+ break;
+ case SIMEDGE_BEVEL:
+ custom_data_type = CD_BWEIGHT;
+ break;
+ }
+
+ int tree_index = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+
+ if (bm->totedgesel == 0) {
+ continue;
+ }
+
+ switch (type) {
+ case SIMEDGE_FREESTYLE:
+ {
+ if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
+ edge_data_value |= SIMEDGE_DATA_FALSE;
+ continue;
+ }
+ break;
+ }
+ case SIMEDGE_CREASE:
+ case SIMEDGE_BEVEL:
+ {
+ if (!CustomData_has_layer(&bm->edata, custom_data_type)) {
+ float dummy[3] = {0.0f, 0.0f, 0.0f};
+ BLI_kdtree_insert(tree, tree_index++, dummy);
+ continue;
+ }
+ break;
+ }
+ }
+
+ float ob_m3[3][3], ob_m3_inv[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+ invert_m3_m3(ob_m3_inv, ob_m3);
+
+ BMEdge *edge; /* Mesh edge. */
+ BMIter iter; /* Selected edges iterator. */
+
+ BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(edge, BM_ELEM_SELECT)) {
+ switch (type) {
+ case SIMEDGE_FACE:
+ BLI_gset_add(gset, POINTER_FROM_INT(BM_edge_face_count(edge)));
+ break;
+ case SIMEDGE_DIR:
+ {
+ float dir[3];
+ edge_pos_direction_worldspace_get(ob, edge, dir);
+ BLI_kdtree_insert(tree, tree_index++, dir);
+ break;
+ }
+ case SIMEDGE_LENGTH:
+ {
+ float length = edge_length_squared_worldspace_get(ob, edge);
+ float dummy[3] = {length, 0.0f, 0.0f};
+ BLI_kdtree_insert(tree, tree_index++, dummy);
+ break;
+ }
+ case SIMEDGE_FACE_ANGLE:
+ {
+ if (BM_edge_face_count_at_most(edge, 2) == 2) {
+ float angle = BM_edge_calc_face_angle_with_imat3(edge, ob_m3_inv);
+ float dummy[3] = {angle, 0.0f, 0.0f};
+ BLI_kdtree_insert(tree, tree_index++, dummy);
+ }
+ break;
+ }
+ case SIMEDGE_SEAM:
+ if (!edge_data_value_set(edge, BM_ELEM_SEAM, &edge_data_value)) {
+ goto edge_select_all;
+ }
+ break;
+ case SIMEDGE_SHARP:
+ if (!edge_data_value_set(edge, BM_ELEM_SMOOTH, &edge_data_value)) {
+ goto edge_select_all;
+ }
+ break;
+ case SIMEDGE_FREESTYLE:
+ {
+ FreestyleEdge *fedge;
+ fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE);
+ if ((fedge == NULL) || ((fedge->flag & FREESTYLE_EDGE_MARK) == 0)) {
+ edge_data_value |= SIMEDGE_DATA_FALSE;
+ }
+ else {
+ edge_data_value |= SIMEDGE_DATA_TRUE;
+ }
+ if (edge_data_value == SIMEDGE_DATA_ALL) {
+ goto edge_select_all;
+ }
+ break;
+ }
+ case SIMEDGE_CREASE:
+ case SIMEDGE_BEVEL:
+ {
+ const float *value = CustomData_bmesh_get(&bm->edata, edge->head.data, custom_data_type);
+ float dummy[3] = {*value, 0.0f, 0.0f};
+ BLI_kdtree_insert(tree, tree_index++, dummy);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ BLI_assert((type != SIMEDGE_FREESTYLE) || (edge_data_value != SIMEDGE_DATA_NONE));
+
+ if (tree != NULL) {
+ BLI_kdtree_balance(tree);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ bool changed = false;
+
+ bool has_custom_data_layer = false;
+ switch (type) {
+ case SIMEDGE_FREESTYLE:
+ {
+ has_custom_data_layer = CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE);
+ if ((edge_data_value == SIMEDGE_DATA_TRUE) && !has_custom_data_layer) {
+ continue;
+ }
+ break;
+ }
+ case SIMEDGE_CREASE:
+ case SIMEDGE_BEVEL:
+ {
+ has_custom_data_layer = CustomData_has_layer(&bm->edata, custom_data_type);
+ if (!has_custom_data_layer) {
+ /* Proceed only if we have to select all the edges that have custom data value of 0.0f.
+ * In this case we will just select all the edges.
+ * Otherwise continue the for loop. */
+ if (!ED_select_similar_compare_float_tree(tree, 0.0f, thresh, compare)) {
+ continue;
+ }
+ }
+ }
+ }
+
+ float ob_m3[3][3], ob_m3_inv[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+ invert_m3_m3(ob_m3_inv, ob_m3);
+
+ BMEdge *edge; /* Mesh edge. */
+ BMIter iter; /* Selected edges iterator. */
+
+ BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(edge, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(edge, BM_ELEM_HIDDEN))
+ {
+ bool select = false;
+ switch (type) {
+ case SIMEDGE_FACE:
+ {
+ const int num_faces = BM_edge_face_count(edge);
+ GSetIterator gs_iter;
+ GSET_ITER(gs_iter, gset) {
+ const int num_faces_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
+ const int delta_i = num_faces - num_faces_iter;
+ if (mesh_select_similar_compare_int(delta_i, compare)) {
+ select = true;
+ break;
+ }
+ }
+ break;
+ }
+ case SIMEDGE_DIR:
+ {
+ float dir[3];
+ edge_pos_direction_worldspace_get(ob, edge, dir);
+
+ /* We are treating the direction as coordinates, the "nearest" one will
+ * also be the one closest to the intended direction. */
+ KDTreeNearest nearest;
+ if (BLI_kdtree_find_nearest(tree, dir, &nearest) != -1) {
+ if (angle_normalized_v3v3(dir, nearest.co) <= thresh_radians) {
+ select = true;
+ }
+ }
+ break;
+ }
+ case SIMEDGE_LENGTH:
+ {
+ float length = edge_length_squared_worldspace_get(ob, edge);
+ if (ED_select_similar_compare_float_tree(tree, length, thresh, compare)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMEDGE_FACE_ANGLE:
+ {
+ if (BM_edge_face_count_at_most(edge, 2) == 2) {
+ float angle = BM_edge_calc_face_angle_with_imat3(edge, ob_m3_inv);
+ if (ED_select_similar_compare_float_tree(tree, angle, thresh, SIM_CMP_EQ)) {
+ select = true;
+ }
+ }
+ break;
+ }
+ case SIMEDGE_SEAM:
+ if ((BM_elem_flag_test(edge, BM_ELEM_SEAM) != 0) ==
+ ((edge_data_value & SIMEDGE_DATA_TRUE) != 0))
+ {
+ select = true;
+ }
+ break;
+ case SIMEDGE_SHARP:
+ if ((BM_elem_flag_test(edge, BM_ELEM_SMOOTH) != 0) ==
+ ((edge_data_value & SIMEDGE_DATA_TRUE) != 0))
+ {
+ select = true;
+ }
+ break;
+ case SIMEDGE_FREESTYLE:
+ {
+ FreestyleEdge *fedge;
+
+ if (!has_custom_data_layer) {
+ BLI_assert(edge_data_value == SIMEDGE_DATA_FALSE);
+ select = true;
+ break;
+ }
+
+ fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE);
+ if (((fedge != NULL) && (fedge->flag & FREESTYLE_EDGE_MARK)) ==
+ ((edge_data_value & SIMEDGE_DATA_TRUE) != 0))
+ {
+ select = true;
+ }
+ break;
+ }
+ case SIMEDGE_CREASE:
+ case SIMEDGE_BEVEL:
+ {
+ if (!has_custom_data_layer) {
+ select = true;
+ break;
+ }
+
+ const float *value = CustomData_bmesh_get(&bm->edata, edge->head.data, custom_data_type);
+ if (ED_select_similar_compare_float_tree(tree, *value, thresh, compare)) {
+ select = true;
+ }
+ break;
+ }
+ }
+
+ if (select) {
+ BM_edge_select_set(bm, edge, true);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ EDBM_selectmode_flush(em);
+ EDBM_update_generic(em, false, false);
+ }
+ }
+
+ if (false) {
+edge_select_all:
+ BLI_assert(ELEM(type,
+ SIMEDGE_SEAM,
+ SIMEDGE_SHARP,
+ SIMEDGE_FREESTYLE
+ ));
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+
+ BMEdge *edge; /* Mesh edge. */
+ BMIter iter; /* Selected edges iterator. */
+
+ BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(edge, BM_ELEM_SELECT)) {
+ BM_edge_select_set(bm, edge, true);
+ }
+ }
+ EDBM_selectmode_flush(em);
+ EDBM_update_generic(em, false, false);
+ }
+ }
+
+ MEM_freeN(objects);
+ BLI_kdtree_free(tree);
+ if (gset != NULL) {
+ BLI_gset_free(gset, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Similar Vert
+ * \{ */
+
+static int similar_vert_select_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ /* get the type from RNA */
+ const int type = RNA_enum_get(op->ptr, "type");
+ const float thresh = RNA_float_get(op->ptr, "threshold");
+ const float thresh_radians = thresh * (float)M_PI + FLT_EPSILON;
+ const int compare = RNA_enum_get(op->ptr, "compare");
+
+ int tot_verts_selected_all = 0;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ tot_verts_selected_all += em->bm->totvertsel;
+ }
+
+ if (tot_verts_selected_all == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No vertex selected");
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+
+ KDTree *tree = NULL;
+ GSet *gset = NULL;
+
+ switch (type) {
+ case SIMVERT_NORMAL:
+ tree = BLI_kdtree_new(tot_verts_selected_all);
+ break;
+ case SIMVERT_EDGE:
+ case SIMVERT_FACE:
+ gset = BLI_gset_ptr_new("Select similar vertex: edge/face");
+ break;
+ case SIMVERT_VGROUP:
+ gset = BLI_gset_str_new("Select similar vertex: vertex groups");
+ break;
+ }
+
+ int normal_tree_index = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ int cd_dvert_offset = -1;
+ int dvert_selected = 0;
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ if (type == SIMVERT_VGROUP) {
+ cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
+ if (cd_dvert_offset == -1) {
+ continue;
+ }
+ }
+
+ BMVert *vert; /* Mesh vertex. */
+ BMIter iter; /* Selected verts iterator. */
+
+ BM_ITER_MESH (vert, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(vert, BM_ELEM_SELECT)) {
+ switch (type) {
+ case SIMVERT_FACE:
+ BLI_gset_add(gset, POINTER_FROM_INT(BM_vert_face_count(vert)));
+ break;
+ case SIMVERT_EDGE:
+ BLI_gset_add(gset, POINTER_FROM_INT(BM_vert_edge_count(vert)));
+ break;
+ case SIMVERT_NORMAL:
+ {
+ float normal[3];
+ copy_v3_v3(normal, vert->no);
+ mul_transposed_mat3_m4_v3(ob->imat, normal);
+ normalize_v3(normal);
+
+ BLI_kdtree_insert(tree, normal_tree_index++, normal);
+ break;
+ }
+ case SIMVERT_VGROUP:
+ {
+ MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, cd_dvert_offset);
+ MDeformWeight *dw = dvert->dw;
+
+ for (int i = 0; i < dvert->totweight; i++, dw++) {
+ if (dw->weight > 0.0f) {
+ dvert_selected |= (1 << dw->def_nr);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if (type == SIMVERT_VGROUP) {
+ /* We store the names of the vertex groups, so we can select
+ * vertex groups with the same name in different objects. */
+ const int dvert_tot = BLI_listbase_count(&ob->defbase);
+ for (int i = 0; i < dvert_tot; i++) {
+ if (dvert_selected & (1 << i)) {
+ bDeformGroup *dg = BLI_findlink(&ob->defbase, i);
+ BLI_gset_add(gset, dg->name);
+ }
+ }
+ }
+ }
+
+ if (type == SIMVERT_VGROUP) {
+ if (BLI_gset_len(gset) == 0) {
+ BKE_report(op->reports,
+ RPT_INFO,
+ "No vertex group among the selected vertices");
+ }
+ }
+
+ /* Remove duplicated entries. */
+ if (tree != NULL) {
+ BLI_kdtree_balance(tree);
+ }
+
+ /* Run .the BM operators. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ bool changed = false;
+ int cd_dvert_offset = -1;
+ int dvert_selected = 0;
+
+ if (type == SIMVERT_VGROUP) {
+ cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
+ if (cd_dvert_offset == -1) {
+ continue;
+ }
+
+ /* We map back the names of the vertex groups to their corresponsing indices
+ * for this object. This is fast, and keep the logic for each vertex very simple. */
+ GSetIterator gs_iter;
+ GSET_ITER(gs_iter, gset) {
+ const char *name = BLI_gsetIterator_getKey(&gs_iter);
+ int vgroup_id = BLI_findstringindex(&ob->defbase,
+ name,
+ offsetof(bDeformGroup, name));
+ if (vgroup_id != -1) {
+ dvert_selected |= (1 << vgroup_id);
+ }
+ }
+ if (dvert_selected == 0) {
+ continue;
+ }
+ }
+
+ BMVert *vert; /* Mesh vertex. */
+ BMIter iter; /* Selected verts iterator. */
+
+ BM_ITER_MESH (vert, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(vert, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(vert, BM_ELEM_HIDDEN))
+ {
+ bool select = false;
+ switch (type) {
+ case SIMVERT_EDGE:
+ {
+ const int num_edges = BM_vert_edge_count(vert);
+ GSetIterator gs_iter;
+ GSET_ITER(gs_iter, gset) {
+ const int num_edges_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
+ const int delta_i = num_edges - num_edges_iter;
+ if (mesh_select_similar_compare_int(delta_i, compare)) {
+ select = true;
+ break;
+ }
+ }
+ break;
+ }
+ case SIMVERT_FACE:
+ {
+ const int num_faces = BM_vert_face_count(vert);
+ GSetIterator gs_iter;
+ GSET_ITER(gs_iter, gset) {
+ const int num_faces_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
+ const int delta_i = num_faces - num_faces_iter;
+ if (mesh_select_similar_compare_int(delta_i, compare)) {
+ select = true;
+ break;
+ }
+ }
+ break;
+ }
+ case SIMVERT_NORMAL:
+ {
+ float normal[3];
+ copy_v3_v3(normal, vert->no);
+ mul_transposed_mat3_m4_v3(ob->imat, normal);
+ normalize_v3(normal);
+
+ /* We are treating the normals as coordinates, the "nearest" one will
+ * also be the one closest to the angle. */
+ KDTreeNearest nearest;
+ if (BLI_kdtree_find_nearest(tree, normal, &nearest) != -1) {
+ if (angle_normalized_v3v3(normal, nearest.co) <= thresh_radians) {
+ select = true;
+ }
+ }
+ break;
+ }
+ case SIMVERT_VGROUP:
+ {
+ MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, cd_dvert_offset);
+ MDeformWeight *dw = dvert->dw;
+
+ for (int i = 0; i < dvert->totweight; i++, dw++) {
+ if (dw->weight > 0.0f) {
+ if (dvert_selected & (1 << dw->def_nr)) {
+ select = true;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (select) {
+ BM_vert_select_set(bm, vert, true);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ EDBM_selectmode_flush(em);
+ EDBM_update_generic(em, false, false);
+ }
+ }
+
+ MEM_freeN(objects);
+ BLI_kdtree_free(tree);
+ if (gset != NULL) {
+ BLI_gset_free(gset, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Similar Operator
+ * \{ */
+
+static int edbm_select_similar_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
+
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set(op->ptr, prop, ts->select_thresh);
+ }
+ else {
+ ts->select_thresh = RNA_property_float_get(op->ptr, prop);
+ }
+
+ if (type < 100) return similar_vert_select_exec(C, op);
+ else if (type < 200) return similar_edge_select_exec(C, op);
+ else return similar_face_select_exec(C, op);
+}
+
+static const EnumPropertyItem *select_similar_type_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ Object *obedit;
+
+ if (!C) /* needed for docs and i18n tools */
+ return prop_similar_types;
+
+ obedit = CTX_data_edit_object(C);
+
+ if (obedit && obedit->type == OB_MESH) {
+ EnumPropertyItem *item = NULL;
+ int a, totitem = 0;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ for (a = SIMVERT_NORMAL; a < SIMEDGE_LENGTH; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ }
+ else if (em->selectmode & SCE_SELECT_EDGE) {
+ for (a = SIMEDGE_LENGTH; a < SIMFACE_MATERIAL; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ }
+ else if (em->selectmode & SCE_SELECT_FACE) {
+#ifdef WITH_FREESTYLE
+ const int a_end = SIMFACE_FREESTYLE;
+#else
+ const int a_end = SIMFACE_FACEMAP;
+#endif
+ for (a = SIMFACE_MATERIAL; a <= a_end; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ }
+ RNA_enum_item_end(&item, &totitem);
+
+ *r_free = true;
+
+ return item;
+ }
+
+ return prop_similar_types;
+}
+
+void MESH_OT_select_similar(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Similar";
+ ot->idname = "MESH_OT_select_similar";
+ ot->description = "Select similar vertices, edges or faces by property types";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = edbm_select_similar_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
+ RNA_def_enum_funcs(prop, select_similar_type_itemf);
+
+ RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
+
+ RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 5f49e30a191..c9fc54fd794 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -41,20 +41,31 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_bitmap.h"
+#include "BLI_heap_simple.h"
#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_linklist_stack.h"
#include "BLI_noise.h"
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_sort_utils.h"
+#include "BLI_string.h"
-#include "BKE_material.h"
+#include "BKE_editmesh.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
+#include "BKE_key.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_report.h"
#include "BKE_texture.h"
-#include "BKE_main.h"
-#include "BKE_editmesh.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "BLT_translation.h"
@@ -90,29 +101,45 @@
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cuts = RNA_int_get(op->ptr, "number_cuts");
- float smooth = RNA_float_get(op->ptr, "smoothness");
+ const float smooth = RNA_float_get(op->ptr, "smoothness");
const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
- if (RNA_boolean_get(op->ptr, "quadtri") &&
+ if (RNA_boolean_get(op->ptr, "ngon") &&
RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT)
{
RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
}
+ const int quad_corner_type = RNA_enum_get(op->ptr, "quadcorner");
+ const bool use_quad_tri = !RNA_boolean_get(op->ptr, "ngon");
+ const int seed = RNA_int_get(op->ptr, "seed");
- BM_mesh_esubdivide(
- em->bm, BM_ELEM_SELECT,
- smooth, SUBD_FALLOFF_LIN, false,
- fractal, along_normal,
- cuts,
- SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
- RNA_boolean_get(op->ptr, "quadtri"), true, false,
- RNA_int_get(op->ptr, "seed"));
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- EDBM_update_generic(em, true, true);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (!(em->bm->totedgesel || em->bm->totfacesel)) {
+ continue;
+ }
+
+ BM_mesh_esubdivide(
+ em->bm, BM_ELEM_SELECT,
+ smooth, SUBD_FALLOFF_LIN, false,
+ fractal, along_normal,
+ cuts,
+ SUBDIV_SELECT_ORIG, quad_corner_type,
+ use_quad_tri, true, false,
+ seed);
+
+ EDBM_update_generic(em, true, true);
+ }
+
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -149,7 +176,9 @@ void MESH_OT_subdivide(wmOperatorType *ot)
RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
- RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
+ WM_operatortype_props_advanced_begin(ot);
+
+ RNA_def_boolean(ot->srna, "ngon", true, "Create N-Gons", "When disabled, newly created faces are limited to 3-4 sided faces");
RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_CORNER_STRAIGHT_CUT,
"Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)");
@@ -222,24 +251,36 @@ static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSu
static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
struct EdgeRingOpSubdProps op_props;
mesh_operator_edgering_props_get(op, &op_props);
- if (!EDBM_op_callf(
- em, op,
- "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
- "profile_shape=%i profile_shape_factor=%f",
- BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
- op_props.profile_shape, op_props.profile_shape_factor))
- {
- return OPERATOR_CANCELLED;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_update_generic(em, true, true);
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
+
+ if (!EDBM_op_callf(
+ em, op,
+ "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
+ "profile_shape=%i profile_shape_factor=%f",
+ BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
+ op_props.profile_shape, op_props.profile_shape_factor))
+ {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -268,27 +309,39 @@ void MESH_OT_subdivide_edgering(wmOperatorType *ot)
static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
-
const int iterations = RNA_int_get(op->ptr, "iterations");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_op_init(em, &bmop, op,
- "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations);
+ if ((em->bm->totvertsel == 0) &&
+ (em->bm->totedgesel == 0) &&
+ (em->bm->totfacesel == 0))
+ {
+ continue;
+ }
- BMO_op_exec(em->bm, &bmop);
+ BMOperator bmop;
+ EDBM_op_init(em, &bmop, op,
+ "unsubdivide verts=%hv iterations=%i", BM_ELEM_SELECT, iterations);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return 0;
- }
+ BMO_op_exec(em->bm, &bmop);
- if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
- EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); /* need to flush vert->face first */
- }
- EDBM_selectmode_flush(em);
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
- EDBM_update_generic(em, true, true);
+ if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); /* need to flush vert->face first */
+ }
+ EDBM_selectmode_flush(em);
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -313,6 +366,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot)
void EDBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
{
+ Main *bmain = CTX_data_main(C);
Object *obedit = em->ob;
BMIter iter;
BMVert *eve;
@@ -320,21 +374,22 @@ void EDBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), 0,
+ bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0,
ar, CTX_wm_view3d(C));
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float mval[2], co_proj[3];
if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- if (ED_transform_snap_object_project_view3d_mixed(
+ if (ED_transform_snap_object_project_view3d(
snap_context,
- SCE_SELECT_FACE,
+ SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_NOT_ACTIVE,
.use_object_edit_cage = false,
+ .use_occlusion_test = true,
},
- mval, NULL, true,
+ mval, NULL,
co_proj, NULL))
{
mul_v3_m4v3(eve->co, obedit->imat, co_proj);
@@ -361,52 +416,79 @@ enum {
MESH_DELETE_ONLY_FACE = 4,
};
-static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[3])
+static void edbm_report_delete_info(ReportList *reports, const int totelem_old[3], const int totelem_new[3])
{
BKE_reportf(reports, RPT_INFO,
"Removed: %d vertices, %d edges, %d faces",
- totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
+ totelem_old[0] - totelem_new[0], totelem_old[1] - totelem_new[1], totelem_old[2] - totelem_new[2]);
}
static int edbm_delete_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int type = RNA_enum_get(op->ptr, "type");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- switch (type) {
- case MESH_DELETE_VERT:
- if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
- return OPERATOR_CANCELLED;
- break;
- case MESH_DELETE_EDGE:
- if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
- return OPERATOR_CANCELLED;
- break;
- case MESH_DELETE_FACE:
- if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
- return OPERATOR_CANCELLED;
- break;
- case MESH_DELETE_EDGE_FACE:
- /* Edges and Faces */
- if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))
- return OPERATOR_CANCELLED;
- break;
- case MESH_DELETE_ONLY_FACE:
- /* Only faces. */
- if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))
- return OPERATOR_CANCELLED;
- break;
- default:
- BLI_assert(0);
- break;
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ bool changed_multi = false;
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int type = RNA_enum_get(op->ptr, "type");
- EDBM_update_generic(em, true, true);
+ switch (type) {
+ case MESH_DELETE_VERT: /* Erase Vertices */
+ if (!(em->bm->totvertsel &&
+ EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)))
+ {
+ continue;
+ }
+ break;
+ case MESH_DELETE_EDGE: /* Erase Edges */
+ if (!(em->bm->totedgesel &&
+ EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)))
+ {
+ continue;
+ }
+ break;
+ case MESH_DELETE_FACE: /* Erase Faces */
+ if (!(em->bm->totfacesel &&
+ EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)))
+ {
+ continue;
+ }
+ break;
+ case MESH_DELETE_EDGE_FACE:
+ /* Edges and Faces */
+ if (!((em->bm->totedgesel || em->bm->totfacesel) &&
+ EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)))
+ {
+ continue;
+ }
+ break;
+ case MESH_DELETE_ONLY_FACE:
+ /* Only faces. */
+ if (!(em->bm->totfacesel &&
+ EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES)))
+ {
+ continue;
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
- return OPERATOR_FINISHED;
+ changed_multi = true;
+
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ EDBM_update_generic(em, true, true);
+ }
+
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void MESH_OT_delete(wmOperatorType *ot)
@@ -437,6 +519,7 @@ void MESH_OT_delete(wmOperatorType *ot)
/* props */
ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, MESH_DELETE_VERT,
"Type", "Method used for deleting mesh data");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/** \} */
@@ -461,61 +544,75 @@ static bool bm_face_is_loose(BMFace *f)
static int edbm_delete_loose_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMIter iter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int totelem_old_sel[3];
+ int totelem_old[3];
- const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && bm->totvertsel);
- const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && bm->totedgesel);
- const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && bm->totfacesel);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- const int totelem[3] = {bm->totvert, bm->totedge, bm->totface};
+ EDBM_mesh_stats_multi(objects, objects_len, totelem_old, totelem_old_sel);
+ const bool use_verts = (RNA_boolean_get(op->ptr, "use_verts") && totelem_old_sel[0]);
+ const bool use_edges = (RNA_boolean_get(op->ptr, "use_edges") && totelem_old_sel[1]);
+ const bool use_faces = (RNA_boolean_get(op->ptr, "use_faces") && totelem_old_sel[2]);
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
- if (use_faces) {
- BMFace *f;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- BM_elem_flag_set(f, BM_ELEM_TAG, bm_face_is_loose(f));
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ if (use_faces) {
+ BMFace *f;
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_elem_flag_set(f, BM_ELEM_TAG, bm_face_is_loose(f));
+ }
}
- }
- BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
- }
+ BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
+ }
- if (use_edges) {
- BMEdge *e;
+ if (use_edges) {
+ BMEdge *e;
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- BM_elem_flag_set(e, BM_ELEM_TAG, BM_edge_is_wire(e));
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, BM_edge_is_wire(e));
+ }
}
- }
- BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_EDGES);
- }
+ BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_EDGES);
+ }
- if (use_verts) {
- BMVert *v;
+ if (use_verts) {
+ BMVert *v;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- BM_elem_flag_set(v, BM_ELEM_TAG, (v->e == NULL));
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, (v->e == NULL));
+ }
}
+
+ BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS);
}
- BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_VERTS);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ EDBM_update_generic(em, true, true);
}
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ int totelem_new[3];
+ EDBM_mesh_stats_multi(objects, objects_len, totelem_new, NULL);
- EDBM_update_generic(em, true, true);
+ edbm_report_delete_info(op->reports, totelem_old, totelem_new);
- edbm_report_delete_info(op->reports, bm, totelem);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -550,13 +647,24 @@ void MESH_OT_delete_loose(wmOperatorType *ot)
static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true))
- return OPERATOR_CANCELLED;
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
- EDBM_update_generic(em, true, true);
+ if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true)) {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -759,70 +867,83 @@ static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_
static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
{
- BMOperator bmop;
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
- const int totedge_orig = em->bm->totedge;
- const int totface_orig = em->bm->totface;
/* when this is used to dissolve we could avoid this, but checking isnt too slow */
-#ifdef USE_FACE_CREATE_SEL_EXTEND
- BMElem *ele_desel;
- BMFace *ele_desel_face;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* be extra clever, figure out if a partial selection should be extended so we can create geometry
- * with single vert or single edge selection */
- ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm);
-#endif
+ if ((em->bm->totvertsel == 0) &&
+ (em->bm->totedgesel == 0) &&
+ (em->bm->totvertsel == 0))
+ {
+ continue;
+ }
- if (!EDBM_op_init(
- em, &bmop, op,
- "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
- BM_ELEM_SELECT, em->mat_nr, use_smooth))
- {
- return OPERATOR_CANCELLED;
- }
+ bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
+ int totedge_orig = em->bm->totedge;
+ int totface_orig = em->bm->totface;
- BMO_op_exec(em->bm, &bmop);
+ BMOperator bmop;
+#ifdef USE_FACE_CREATE_SEL_EXTEND
+ BMElem *ele_desel;
+ BMFace *ele_desel_face;
- /* cancel if nothing was done */
- if ((totedge_orig == em->bm->totedge) &&
- (totface_orig == em->bm->totface))
- {
- EDBM_op_finish(em, &bmop, op, true);
- return OPERATOR_CANCELLED;
- }
+ /* be extra clever, figure out if a partial selection should be extended so we can create geometry
+ * with single vert or single edge selection */
+ ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm);
+#endif
+ if (!EDBM_op_init(
+ em, &bmop, op,
+ "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
+ BM_ELEM_SELECT, em->mat_nr, use_smooth))
+ {
+ continue;
+ }
+ BMO_op_exec(em->bm, &bmop);
+
+ /* cancel if nothing was done */
+ if ((totedge_orig == em->bm->totedge) &&
+ (totface_orig == em->bm->totface))
+ {
+ EDBM_op_finish(em, &bmop, op, true);
+ continue;
+ }
#ifdef USE_FACE_CREATE_SEL_EXTEND
- /* normally we would want to leave the new geometry selected,
- * but being able to press F many times to add geometry is too useful! */
- if (ele_desel &&
- (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) &&
- (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out")))
- {
- edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
- }
- else
+ /* normally we would want to leave the new geometry selected,
+ * but being able to press F many times to add geometry is too useful! */
+ if (ele_desel &&
+ (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) &&
+ (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out")))
+ {
+ edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
+ }
+ else
#endif
- {
- /* Newly created faces may include existing hidden edges,
- * copying face data from surrounding, may have copied hidden face flag too.
- *
- * Important that faces use flushing since 'edges.out' wont include hidden edges that already existed.
- */
- BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true);
- BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false);
+ {
+ /* Newly created faces may include existing hidden edges,
+ * copying face data from surrounding, may have copied hidden face flag too.
+ *
+ * Important that faces use flushing since 'edges.out' wont include hidden edges that already existed.
+ */
+ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true);
+ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
- }
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+ }
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -851,37 +972,44 @@ void MESH_OT_edge_face_add(wmOperatorType *ot)
static int edbm_mark_seam_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = ((Mesh *)obedit->data);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
BMEdge *eed;
BMIter iter;
const bool clear = RNA_boolean_get(op->ptr, "clear");
- /* auto-enable seams drawing */
- if (clear == 0) {
- me->drawflag |= ME_DRAWSEAMS;
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- if (clear) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
- continue;
+ if (bm->totedgesel == 0) {
+ continue;
+ }
+
+ if (clear) {
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ continue;
+ }
- BM_elem_flag_disable(eed, BM_ELEM_SEAM);
+ BM_elem_flag_disable(eed, BM_ELEM_SEAM);
+ }
}
- }
- else {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
- continue;
- BM_elem_flag_enable(eed, BM_ELEM_SEAM);
+ else {
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+ BM_elem_flag_enable(eed, BM_ELEM_SEAM);
+ }
}
- }
- ED_uvedit_live_unwrap(scene, obedit);
- EDBM_update_generic(em, true, false);
+ ED_uvedit_live_unwrap(scene, obedit);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -903,7 +1031,9 @@ void MESH_OT_mark_seam(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ WM_operatortype_props_advanced_begin(ot);
}
/** \} */
@@ -914,34 +1044,39 @@ void MESH_OT_mark_seam(wmOperatorType *ot)
static int edbm_mark_sharp_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = ((Mesh *)obedit->data);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
BMEdge *eed;
BMIter iter;
const bool clear = RNA_boolean_get(op->ptr, "clear");
const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- /* auto-enable sharp edge drawing */
- if (clear == 0) {
- me->drawflag |= ME_DRAWSHARP;
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (use_verts) {
- if (!(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) {
+ if (bm->totedgesel == 0) {
+ continue;
+ }
+
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (use_verts) {
+ if (!(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) {
+ continue;
+ }
+ }
+ else if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
continue;
}
- }
- else if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- continue;
+
+ BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear);
}
- BM_elem_flag_set(eed, BM_ELEM_SMOOTH, clear);
+ EDBM_update_generic(em, true, false);
}
-
- EDBM_update_generic(em, true, false);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -963,23 +1098,28 @@ void MESH_OT_mark_sharp(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "use_verts", false, "Vertices",
"Consider vertices instead of edges to select which edges to (un)tag as sharp");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
+static bool edbm_connect_vert_pair(BMEditMesh *em, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMOperator bmop;
- bool is_pair = (bm->totvertsel == 2);
+ const int verts_len = bm->totvertsel;
+ bool is_pair = (verts_len == 2);
int len = 0;
bool check_degenerate = true;
- const int verts_len = bm->totvertsel;
+
BMVert **verts;
+ bool checks_succeded = true;
+
+ /* sanity check */
+ if (verts_len < 2) {
+ return false;
+ }
verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__);
{
@@ -987,20 +1127,18 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
BMVert *v;
int i = 0;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
verts[i++] = v;
}
}
- if (is_pair) {
- if (BM_vert_pair_share_face_check_cb(
- verts[0], verts[1],
- BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN)))
- {
- check_degenerate = false;
- is_pair = false;
- }
+ if (BM_vert_pair_share_face_check_cb(
+ verts[0], verts[1],
+ BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN)))
+ {
+ check_degenerate = false;
+ is_pair = false;
}
}
@@ -1010,7 +1148,7 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
"connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
{
- goto finally;
+ checks_succeded = false;
}
}
else {
@@ -1019,33 +1157,49 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
"connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
verts, verts_len, BM_ELEM_HIDDEN, check_degenerate))
{
- goto finally;
+ checks_succeded = false;
}
}
+ if (checks_succeded) {
+ BMO_op_exec(bm, &bmop);
+ len = BMO_slot_get(bmop.slots_out, "edges.out")->len;
- BMO_op_exec(bm, &bmop);
- len = BMO_slot_get(bmop.slots_out, "edges.out")->len;
-
- if (len) {
- if (is_pair) {
+ if (len && is_pair) {
/* new verts have been added, we have to select the edges, not just flush */
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
}
- }
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- len = 0;
- }
- else {
- EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ len = 0;
+ }
+ else {
+ EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
}
+ MEM_freeN(verts);
+ return len;
+}
-finally:
- MEM_freeN(verts);
- return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ uint failed_objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (!edbm_connect_vert_pair(em, op)) {
+ failed_objects_len++;
+ }
+ }
+ MEM_freeN(objects);
+ return failed_objects_len == objects_len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void MESH_OT_vert_connect(wmOperatorType *ot)
@@ -1284,43 +1438,66 @@ static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase
static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- bool is_pair = (em->bm->totvertsel == 2);
- ListBase selected_orig = {NULL, NULL};
- int retval;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ uint failed_selection_order_len = 0;
+ uint failed_connect_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* when there is only 2 vertices, we can ignore selection order */
- if (is_pair) {
- return edbm_vert_connect_exec(C, op);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const bool is_pair = (em->bm->totvertsel == 2);
+ ListBase selected_orig = {NULL, NULL};
- if (bm->selected.first) {
- BMEditSelection *ese = bm->selected.first;
- if (ese->htype == BM_EDGE) {
- if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) {
- SWAP(ListBase, bm->selected, selected_orig);
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ /* when there is only 2 vertices, we can ignore selection order */
+ if (is_pair) {
+ if (!edbm_connect_vert_pair(em, op)) {
+ failed_connect_len++;
}
+ continue;
}
- }
- if (bm_vert_connect_select_history(bm)) {
- EDBM_selectmode_flush(em);
- EDBM_update_generic(em, true, true);
- retval = OPERATOR_FINISHED;
+ if (bm->selected.first) {
+ BMEditSelection *ese = bm->selected.first;
+ if (ese->htype == BM_EDGE) {
+ if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) {
+ SWAP(ListBase, bm->selected, selected_orig);
+ }
+ }
+ }
+
+ if (bm_vert_connect_select_history(bm)) {
+ EDBM_selectmode_flush(em);
+ EDBM_update_generic(em, true, true);
+ }
+ else {
+ failed_selection_order_len++;
+ }
+
+ if (!BLI_listbase_is_empty(&selected_orig)) {
+ BM_select_history_clear(bm);
+ bm->selected = selected_orig;
+ }
}
- else {
+
+ MEM_freeN(objects);
+
+ if (failed_selection_order_len == objects_len) {
BKE_report(op->reports, RPT_ERROR, "Invalid selection order");
- retval = OPERATOR_CANCELLED;
+ return OPERATOR_CANCELLED;
}
-
- if (!BLI_listbase_is_empty(&selected_orig)) {
- BM_select_history_clear(bm);
- bm->selected = selected_orig;
+ else if (failed_connect_len == objects_len) {
+ BKE_report(op->reports, RPT_ERROR, "Could not connect vertices");
+ return OPERATOR_CANCELLED;
}
- return retval;
+ return OPERATOR_FINISHED;
}
void MESH_OT_vert_connect_path(wmOperatorType *ot)
@@ -1340,20 +1517,29 @@ void MESH_OT_vert_connect_path(wmOperatorType *ot)
static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!EDBM_op_call_and_selectf(
- em, op,
- "faces.out", true,
- "connect_verts_concave faces=%hf",
- BM_ELEM_SELECT))
- {
- return OPERATOR_CANCELLED;
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "connect_verts_concave faces=%hf",
+ BM_ELEM_SELECT))
+ {
+ continue;
+ }
+ EDBM_update_generic(em, true, true);
+ }
- EDBM_update_generic(em, true, true);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1380,22 +1566,32 @@ void MESH_OT_vert_connect_concave(wmOperatorType *ot)
static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (!EDBM_op_call_and_selectf(
- em, op,
- "faces.out", true,
- "connect_verts_nonplanar faces=%hf angle_limit=%f",
- BM_ELEM_SELECT, angle_limit))
- {
- return OPERATOR_CANCELLED;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "connect_verts_nonplanar faces=%hf angle_limit=%f",
+ BM_ELEM_SELECT, angle_limit))
+ {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
- EDBM_update_generic(em, true, true);
return OPERATOR_FINISHED;
}
@@ -1429,19 +1625,31 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
const int repeat = RNA_int_get(op->ptr, "repeat");
const float fac = RNA_float_get(op->ptr, "factor");
- if (!EDBM_op_callf(
- em, op, "planar_faces faces=%hf iterations=%i factor=%f",
- BM_ELEM_SELECT, repeat, fac))
- {
- return OPERATOR_CANCELLED;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+
+ if (!EDBM_op_callf(
+ em, op, "planar_faces faces=%hf iterations=%i factor=%f",
+ BM_ELEM_SELECT, repeat, fac))
+ {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
}
+ MEM_freeN(objects);
- EDBM_update_generic(em, true, true);
return OPERATOR_FINISHED;
}
@@ -1472,23 +1680,32 @@ void MESH_OT_face_make_planar(wmOperatorType *ot)
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
- if (!EDBM_op_call_and_selectf(
- em, op,
- "edges.out", false,
- "split_edges edges=%he",
- BM_ELEM_SELECT))
- {
- return OPERATOR_CANCELLED;
- }
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "edges.out", false,
+ "split_edges edges=%he",
+ BM_ELEM_SELECT))
+ {
+ continue;
+ }
- if (em->selectmode == SCE_SELECT_FACE) {
- EDBM_select_flush(em);
- }
+ if (em->selectmode == SCE_SELECT_FACE) {
+ EDBM_select_flush(em);
+ }
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1516,33 +1733,43 @@ void MESH_OT_edge_split(wmOperatorType *ot)
static int edbm_duplicate_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMesh *bm = em->bm;
- BMOperator bmop;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- EDBM_op_init(
- em, &bmop, op,
- "duplicate geom=%hvef use_select_history=%b",
- BM_ELEM_SELECT, true);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
- BMO_op_exec(bm, &bmop);
+ BMOperator bmop;
+ BMesh *bm = em->bm;
+
+ EDBM_op_init(
+ em, &bmop, op,
+ "duplicate geom=%hvef use_select_history=%b",
+ BM_ELEM_SELECT, true);
- /* de-select all would clear otherwise */
- BM_SELECT_HISTORY_BACKUP(bm);
+ BMO_op_exec(bm, &bmop);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ /* de-select all would clear otherwise */
+ BM_SELECT_HISTORY_BACKUP(bm);
- BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- /* rebuild editselection */
- BM_SELECT_HISTORY_RESTORE(bm);
+ BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
+ /* rebuild editselection */
+ BM_SELECT_HISTORY_RESTORE(bm);
- EDBM_update_generic(em, true, true);
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1580,18 +1807,29 @@ void MESH_OT_duplicate(wmOperatorType *ot)
* \{ */
static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (!EDBM_op_callf(
- em, op, "reverse_faces faces=%hf flip_multires=%b",
- BM_ELEM_SELECT, true))
- {
- return OPERATOR_CANCELLED;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_update_generic(em, true, false);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+ if (!EDBM_op_callf(
+ em, op, "reverse_faces faces=%hf flip_multires=%b",
+ BM_ELEM_SELECT, true))
+ {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, false);
+ }
+
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1621,71 +1859,99 @@ void MESH_OT_flip_normals(wmOperatorType *ot)
*/
static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
BMEdge *eed;
BMIter iter;
const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
- int tot = 0;
- if (em->bm->totedgesel == 0) {
- BKE_report(op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about");
- return OPERATOR_CANCELLED;
- }
+ int tot_rotate_all = 0, tot_failed_all = 0;
+ bool no_selected_edges = true, invalid_selected_edges = true;
- /* first see if we have two adjacent faces */
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_disable(eed, BM_ELEM_TAG);
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- BMFace *fa, *fb;
- if (BM_edge_face_pair(eed, &fa, &fb)) {
- /* if both faces are selected we rotate between them,
- * otherwise - rotate between 2 unselected - but not mixed */
- if (BM_elem_flag_test(fa, BM_ELEM_SELECT) == BM_elem_flag_test(fb, BM_ELEM_SELECT)) {
- BM_elem_flag_enable(eed, BM_ELEM_TAG);
- tot++;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ int tot = 0;
+
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
+ no_selected_edges = false;
+
+ /* first see if we have two adjacent faces */
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_disable(eed, BM_ELEM_TAG);
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ BMFace *fa, *fb;
+ if (BM_edge_face_pair(eed, &fa, &fb)) {
+ /* if both faces are selected we rotate between them,
+ * otherwise - rotate between 2 unselected - but not mixed */
+ if (BM_elem_flag_test(fa, BM_ELEM_SELECT) == BM_elem_flag_test(fb, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(eed, BM_ELEM_TAG);
+ tot++;
+ }
}
}
}
- }
- /* ok, we don't have two adjacent faces, but we do have two selected ones.
- * that's an error condition.*/
- if (tot == 0) {
- BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated");
- return OPERATOR_CANCELLED;
- }
+ /* ok, we don't have two adjacent faces, but we do have two selected ones.
+ * that's an error condition.*/
+ if (tot == 0) {
+ continue;
+ }
+ invalid_selected_edges = false;
- EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw);
+ BMOperator bmop;
+ EDBM_op_init(em, &bmop, op, "rotate_edges edges=%he use_ccw=%b", BM_ELEM_TAG, use_ccw);
- /* avoids leaving old verts selected which can be a problem running multiple times,
- * since this means the edges become selected around the face which then attempt to rotate */
- BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "edges", BM_EDGE, BM_ELEM_SELECT, true);
+ /* avoids leaving old verts selected which can be a problem running multiple times,
+ * since this means the edges become selected around the face which then attempt to rotate */
+ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "edges", BM_EDGE, BM_ELEM_SELECT, true);
- BMO_op_exec(em->bm, &bmop);
- /* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical state */
- BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+ BMO_op_exec(em->bm, &bmop);
+ /* edges may rotate into hidden vertices, if this does _not_ run we get an illogical state */
+ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+
+ const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out");
+ const int tot_failed = tot - tot_rotate;
- const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out");
- const int tot_failed = tot - tot_rotate;
- if (tot_failed != 0) {
- /* If some edges fail to rotate, we need to re-select them,
- * otherwise we can end up with invalid selection
- * (unselected edge between 2 selected faces). */
- BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ tot_rotate_all += tot_rotate;
+ tot_failed_all += tot_failed;
- BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed);
+ if (tot_failed != 0) {
+ /* If some edges fail to rotate, we need to re-select them,
+ * otherwise we can end up with invalid selection
+ * (unselected edge between 2 selected faces). */
+ BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ }
+
+ EDBM_selectmode_flush(em);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
}
+ MEM_freeN(objects);
- EDBM_selectmode_flush(em);
+ if (no_selected_edges) {
+ BKE_report(op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about");
+ return OPERATOR_CANCELLED;
+ }
- if (!EDBM_op_finish(em, &bmop, op, true)) {
+ /* Ok, we don't have two adjacent faces, but we do have two selected ones.
+ * that's an error condition. */
+ if (invalid_selected_edges) {
+ BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated");
return OPERATOR_CANCELLED;
}
- EDBM_update_generic(em, true, true);
+ if (tot_failed_all != 0) {
+ BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all);
+ }
return OPERATOR_FINISHED;
}
@@ -1716,13 +1982,28 @@ void MESH_OT_edge_rotate(wmOperatorType *ot)
static int edbm_hide_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const bool unselected = RNA_boolean_get(op->ptr, "unselected");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected"));
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- EDBM_update_generic(em, true, false);
+ if ((bm->totvertsel == 0) &&
+ (bm->totedgesel == 0) &&
+ (bm->totfacesel == 0))
+ {
+ continue;
+ }
+
+ EDBM_mesh_hide(em, unselected);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1752,13 +2033,19 @@ void MESH_OT_hide(wmOperatorType *ot)
static int edbm_reveal_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool select = RNA_boolean_get(op->ptr, "select");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- EDBM_mesh_reveal(em, select);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_update_generic(em, true, false);
+ EDBM_mesh_reveal(em, select);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1788,19 +2075,28 @@ void MESH_OT_reveal(wmOperatorType *ot)
static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- /* doflip has to do with bmesh_rationalize_normals, it's an internal
- * thing */
- if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT))
- return OPERATOR_CANCELLED;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (RNA_boolean_get(op->ptr, "inside")) {
- EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- EDBM_update_generic(em, true, false);
+ if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) {
+ continue;
+ }
+ if (RNA_boolean_get(op->ptr, "inside")) {
+ EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
+ }
+
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1830,72 +2126,83 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot)
static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = obedit->data;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- ModifierData *md;
- bool mirrx = false, mirry = false, mirrz = false;
- int i, repeat;
- float clip_dist = 0.0f;
const float fac = RNA_float_get(op->ptr, "factor");
- const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
const bool xaxis = RNA_boolean_get(op->ptr, "xaxis");
const bool yaxis = RNA_boolean_get(op->ptr, "yaxis");
const bool zaxis = RNA_boolean_get(op->ptr, "zaxis");
+ int repeat = RNA_int_get(op->ptr, "repeat");
- /* mirror before smooth */
- if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
- EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
+ if (!repeat) {
+ repeat = 1;
}
- /* if there is a mirror modifier with clipping, flag the verts that
- * are within tolerance of the plane(s) of reflection
- */
- for (md = obedit->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData *)md;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Mesh *me = obedit->data;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ModifierData *md;
+ bool mirrx = false, mirry = false, mirrz = false;
+ int i;
+ float clip_dist = 0.0f;
+ const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
- if (mmd->flag & MOD_MIR_CLIPPING) {
- if (mmd->flag & MOD_MIR_AXIS_X)
- mirrx = true;
- if (mmd->flag & MOD_MIR_AXIS_Y)
- mirry = true;
- if (mmd->flag & MOD_MIR_AXIS_Z)
- mirrz = true;
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
- clip_dist = mmd->tolerance;
+ /* mirror before smooth */
+ if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
+ EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
+ }
+
+ /* if there is a mirror modifier with clipping, flag the verts that
+ * are within tolerance of the plane(s) of reflection
+ */
+ for (md = obedit->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+
+ if (mmd->flag & MOD_MIR_CLIPPING) {
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ mirrx = true;
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ mirry = true;
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ mirrz = true;
+
+ clip_dist = mmd->tolerance;
+ }
}
}
- }
- repeat = RNA_int_get(op->ptr, "repeat");
- if (!repeat)
- repeat = 1;
+ for (i = 0; i < repeat; i++) {
+ if (!EDBM_op_callf(
+ em, op,
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
+ {
+ continue;
+ }
+ }
- for (i = 0; i < repeat; i++) {
- if (!EDBM_op_callf(
- em, op,
- "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
- "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
- BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
- {
- return OPERATOR_CANCELLED;
+ /* apply mirror */
+ if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
+ EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
+ EDBM_verts_mirror_cache_end(em);
}
- }
- /* apply mirror */
- if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
- EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
- EDBM_verts_mirror_cache_end(em);
+ EDBM_update_generic(em, true, false);
}
-
- EDBM_update_generic(em, true, false);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
-
void MESH_OT_vertices_smooth(wmOperatorType *ot)
{
/* identifiers */
@@ -1910,8 +2217,11 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
+ ot->prop = RNA_def_float(ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
+
+ WM_operatortype_props_advanced_begin(ot);
+
RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis");
RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis");
RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
@@ -1925,59 +2235,91 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- Mesh *me = obedit->data;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
- bool usex = true, usey = true, usez = true, preserve_volume = true;
- int i, repeat;
- float lambda_factor;
- float lambda_border;
BMIter fiter;
BMFace *f;
+ int tot_invalid = 0;
+ int tot_unselected = 0;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ const float lambda_factor = RNA_float_get(op->ptr, "lambda_factor");
+ const float lambda_border = RNA_float_get(op->ptr, "lambda_border");
+ const bool usex = RNA_boolean_get(op->ptr, "use_x");
+ const bool usey = RNA_boolean_get(op->ptr, "use_y");
+ const bool usez = RNA_boolean_get(op->ptr, "use_z");
+ const bool preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume");
+ int repeat = RNA_int_get(op->ptr, "repeat");
+
+ if (!repeat) {
+ repeat = 1;
+ }
- /* Check if select faces are triangles */
- BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- if (f->len > 4) {
- BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads");
- return OPERATOR_CANCELLED;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ Mesh *me = obedit->data;
+ bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+
+ if (em->bm->totvertsel == 0) {
+ tot_unselected++;
+ tot_invalid++;
+ continue;
+ }
+
+ bool is_invalid = false;
+ /* Check if select faces are triangles. */
+ BM_ITER_MESH (f, &fiter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ if (f->len > 4) {
+ tot_invalid++;
+ is_invalid = true;
+ break;
+ }
}
}
- }
+ if (is_invalid) {
+ continue;
+ }
- /* mirror before smooth */
- if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
- EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
- }
+ /* Mirror before smooth. */
+ if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
+ EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
+ }
- repeat = RNA_int_get(op->ptr, "repeat");
- lambda_factor = RNA_float_get(op->ptr, "lambda_factor");
- lambda_border = RNA_float_get(op->ptr, "lambda_border");
- usex = RNA_boolean_get(op->ptr, "use_x");
- usey = RNA_boolean_get(op->ptr, "use_y");
- usez = RNA_boolean_get(op->ptr, "use_z");
- preserve_volume = RNA_boolean_get(op->ptr, "preserve_volume");
- if (!repeat)
- repeat = 1;
+ bool failed_repeat_loop = false;
+ for (int i = 0; i < repeat; i++) {
+ if (!EDBM_op_callf(
+ em, op,
+ "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
+ BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
+ {
+ failed_repeat_loop = true;
+ break;
+ }
+ }
+ if (failed_repeat_loop) {
+ continue;
+ }
- for (i = 0; i < repeat; i++) {
- if (!EDBM_op_callf(
- em, op,
- "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
- BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
- {
- return OPERATOR_CANCELLED;
+ /* Apply mirror. */
+ if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
+ EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
+ EDBM_verts_mirror_cache_end(em);
}
- }
- /* apply mirror */
- if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
- EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
- EDBM_verts_mirror_cache_end(em);
+ EDBM_update_generic(em, true, false);
}
+ MEM_freeN(objects);
- EDBM_update_generic(em, true, false);
+ if (tot_unselected == objects_len) {
+ BKE_report(op->reports, RPT_WARNING, "No selected vertex");
+ return OPERATOR_CANCELLED;
+ }
+ else if (tot_invalid == objects_len) {
+ BKE_report(op->reports, RPT_WARNING, "Selected faces must be triangles or quads");
+ return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
@@ -1998,10 +2340,13 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
RNA_def_int(ot->srna, "repeat", 1, 1, 1000,
"Number of iterations to smooth the mesh", "", 1, 200);
- RNA_def_float(ot->srna, "lambda_factor", 5e-5f, 1e-7f, 1000.0f,
+ RNA_def_float(ot->srna, "lambda_factor", 1.0f, 1e-7f, 1000.0f,
"Lambda factor", "", 1e-7f, 1000.0f);
RNA_def_float(ot->srna, "lambda_border", 5e-5f, 1e-7f, 1000.0f,
"Lambda factor in border", "", 1e-7f, 1000.0f);
+
+ WM_operatortype_props_advanced_begin(ot);
+
RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis");
RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis");
RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis");
@@ -2030,12 +2375,21 @@ static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- mesh_set_smooth_faces(em, 1);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- EDBM_update_generic(em, false, false);
+ mesh_set_smooth_faces(em, 1);
+ EDBM_update_generic(em, false, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -2063,12 +2417,21 @@ void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- mesh_set_smooth_faces(em, 0);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- EDBM_update_generic(em, false, false);
+ mesh_set_smooth_faces(em, 0);
+ EDBM_update_generic(em, false, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -2096,73 +2459,105 @@ void MESH_OT_faces_shade_flat(wmOperatorType *ot)
static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMOperator bmop;
-
/* get the direction from RNA */
const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
- /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
- EDBM_op_init(em, &bmop, op, "rotate_uvs faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* execute the operator */
- BMO_op_exec(em->bm, &bmop);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- /* finish the operator */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
+ BMOperator bmop;
- EDBM_update_generic(em, false, false);
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_op_init(em, &bmop, op, "rotate_uvs faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+
+ EDBM_update_generic(em, false, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMOperator bmop;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
- EDBM_op_init(em, &bmop, op, "reverse_uvs faces=%hf", BM_ELEM_SELECT);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- /* execute the operator */
- BMO_op_exec(em->bm, &bmop);
+ BMOperator bmop;
- /* finish the operator */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_op_init(em, &bmop, op, "reverse_uvs faces=%hf", BM_ELEM_SELECT);
- EDBM_update_generic(em, false, false);
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* finish the operator */
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+ EDBM_update_generic(em, false, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMOperator bmop;
-
- /* get the direction from RNA */
+ /* get the direction from RNA */
const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
- /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
- EDBM_op_init(em, &bmop, op, "rotate_colors faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* execute the operator */
- BMO_op_exec(em->bm, &bmop);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- /* finish the operator */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ BMOperator bmop;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_op_init(em, &bmop, op, "rotate_colors faces=%hf use_ccw=%b", BM_ELEM_SELECT, use_ccw);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* finish the operator */
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+
+ /* dependencies graph and notification stuff */
+ EDBM_update_generic(em, false, false);
}
- /* dependencies graph and notification stuff */
- EDBM_update_generic(em, false, false);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -2170,22 +2565,34 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMOperator bmop;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
- EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf", BM_ELEM_SELECT);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
- /* execute the operator */
- BMO_op_exec(em->bm, &bmop);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- /* finish the operator */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
+ BMOperator bmop;
- EDBM_update_generic(em, false, false);
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_op_init(em, &bmop, op, "reverse_colors faces=%hf", BM_ELEM_SELECT);
+
+ /* execute the operator */
+ BMO_op_exec(em->bm, &bmop);
+
+ /* finish the operator */
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ EDBM_update_generic(em, false, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -2316,7 +2723,7 @@ static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use
}
static bool merge_target(
- BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
+ BMEditMesh *em, Scene *scene, Object *ob,
const bool use_cursor, const bool use_uvmerge, wmOperator *wmop)
{
BMIter iter;
@@ -2325,7 +2732,7 @@ static bool merge_target(
const float *vco = NULL;
if (use_cursor) {
- vco = ED_view3d_cursor3d_get(scene, v3d);
+ vco = scene->cursor.location;
copy_v3_v3(co, vco);
invert_m4_m4(ob->imat, ob->obmat);
mul_m4_v3(ob->imat, co);
@@ -2366,45 +2773,60 @@ static bool merge_target(
static int edbm_merge_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
const int type = RNA_enum_get(op->ptr, "type");
const bool uvs = RNA_boolean_get(op->ptr, "uvs");
- bool ok = false;
- switch (type) {
- case MESH_MERGE_CENTER:
- ok = merge_target(em, scene, v3d, obedit, false, uvs, op);
- break;
- case MESH_MERGE_CURSOR:
- ok = merge_target(em, scene, v3d, obedit, true, uvs, op);
- break;
- case MESH_MERGE_LAST:
- ok = merge_firstlast(em, false, uvs, op);
- break;
- case MESH_MERGE_FIRST:
- ok = merge_firstlast(em, true, uvs, op);
- break;
- case MESH_MERGE_COLLAPSE:
- ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
- break;
- default:
- BLI_assert(0);
- break;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!ok) {
- return OPERATOR_CANCELLED;
- }
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
- EDBM_update_generic(em, true, true);
+ bool ok = false;
+ switch (type) {
+ case MESH_MERGE_CENTER:
+ ok = merge_target(em, scene, obedit, false, uvs, op);
+ break;
+ case MESH_MERGE_CURSOR:
+ ok = merge_target(em, scene, obedit, true, uvs, op);
+ break;
+ case MESH_MERGE_LAST:
+ ok = merge_firstlast(em, false, uvs, op);
+ break;
+ case MESH_MERGE_FIRST:
+ ok = merge_firstlast(em, true, uvs, op);
+ break;
+ case MESH_MERGE_COLLAPSE:
+ ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
- /* once collapsed, we can't have edge/face selection */
- if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ if (!ok) {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
+
+ /* once collapsed, we can't have edge/face selection */
+ if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ }
+ /* Only active object supported, see comment below. */
+ if (ELEM(type, MESH_MERGE_FIRST, MESH_MERGE_LAST)) {
+ break;
+ }
}
+ MEM_freeN(objects);
+
return OPERATOR_FINISHED;
}
@@ -2430,6 +2852,10 @@ static const EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(
if (obedit && obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ /* Only active object supported:
+ * In practice it doesn't make sense to run this operation on non-active meshes
+ * since selecting will activate - we could have own code-path for these but it's a hassle
+ * for now just apply to the active (first) object. */
if (em->selectmode & SCE_SELECT_VERTEX) {
if (em->bm->selected.first && em->bm->selected.last &&
((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
@@ -2477,6 +2903,9 @@ void MESH_OT_merge(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use");
RNA_def_enum_funcs(ot->prop, merge_type_itemf);
+
+ WM_operatortype_props_advanced_begin(ot);
+
RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
}
@@ -2488,60 +2917,79 @@ void MESH_OT_merge(wmOperatorType *ot)
static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
const float threshold = RNA_float_get(op->ptr, "threshold");
const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected");
- const int totvert_orig = em->bm->totvert;
- int count;
- char htype_select;
+ int count_multi = 0;
- /* avoid loosing selection state (select -> tags) */
- if (em->selectmode & SCE_SELECT_VERTEX) htype_select = BM_VERT;
- else if (em->selectmode & SCE_SELECT_EDGE) htype_select = BM_EDGE;
- else htype_select = BM_FACE;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- /* store selection as tags */
- BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ /* Selection used as target with 'use_unselected'. */
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
- if (use_unselected) {
- EDBM_op_init(
- em, &bmop, op,
- "automerge verts=%hv dist=%f",
- BM_ELEM_SELECT, threshold);
- BMO_op_exec(em->bm, &bmop);
+ BMOperator bmop;
+ const int totvert_orig = em->bm->totvert;
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
- }
- else {
- EDBM_op_init(
- em, &bmop, op,
- "find_doubles verts=%hv dist=%f",
- BM_ELEM_SELECT, threshold);
- BMO_op_exec(em->bm, &bmop);
+ /* avoid losing selection state (select -> tags) */
+ char htype_select;
+ if (em->selectmode & SCE_SELECT_VERTEX) htype_select = BM_VERT;
+ else if (em->selectmode & SCE_SELECT_EDGE) htype_select = BM_EDGE;
+ else htype_select = BM_FACE;
- if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) {
- BMO_op_finish(em->bm, &bmop);
- return OPERATOR_CANCELLED;
+ /* store selection as tags */
+ BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_TAG, true, true, BM_ELEM_SELECT);
+
+
+ if (use_unselected) {
+ EDBM_op_init(
+ em, &bmop, op,
+ "automerge verts=%hv dist=%f",
+ BM_ELEM_SELECT, threshold);
+ BMO_op_exec(em->bm, &bmop);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
}
+ else {
+ EDBM_op_init(
+ em, &bmop, op,
+ "find_doubles verts=%hv dist=%f",
+ BM_ELEM_SELECT, threshold);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ BMO_op_exec(em->bm, &bmop);
+
+ if (!EDBM_op_callf(em, op, "weld_verts targetmap=%S", &bmop, "targetmap.out")) {
+ BMO_op_finish(em->bm, &bmop);
+ continue;
+ }
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
}
- }
- count = totvert_orig - em->bm->totvert;
- BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count);
+ const int count = (totvert_orig - em->bm->totvert);
- /* restore selection from tags */
- BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_SELECT, true, true, BM_ELEM_TAG);
- EDBM_selectmode_flush(em);
+ /* restore selection from tags */
+ BM_mesh_elem_hflag_enable_test(em->bm, htype_select, BM_ELEM_SELECT, true, true, BM_ELEM_TAG);
+ EDBM_selectmode_flush(em);
- EDBM_update_generic(em, true, true);
+ if (count) {
+ count_multi += count;
+ EDBM_update_generic(em, true, true);
+ }
+ }
+ MEM_freeN(objects);
+
+ BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count_multi);
return OPERATOR_FINISHED;
}
@@ -2572,48 +3020,69 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
* \{ */
/* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
-static void shape_propagate(BMEditMesh *em, wmOperator *op)
+static bool shape_propagate(BMEditMesh *em)
{
BMIter iter;
BMVert *eve = NULL;
float *co;
- int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
+ int totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
- BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
- return;
+ return false;
}
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
+ if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
continue;
+ }
- for (i = 0; i < totshape; i++) {
+ for (int i = 0; i < totshape; i++) {
co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
copy_v3_v3(co, eve->co);
}
}
-
-#if 0
- //TAG Mesh Objects that share this data
- for (base = scene->base.first; base; base = base->next) {
- if (base->object && base->object->data == me) {
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
- }
- }
-#endif
+ return true;
}
-
static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = obedit->data;
- BMEditMesh *em = me->edit_btmesh;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int tot_shapekeys = 0;
+ int tot_selected_verts_objects = 0;
- shape_propagate(em, op);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Mesh *me = obedit->data;
+ BMEditMesh *em = me->edit_btmesh;
- EDBM_update_generic(em, false, false);
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+ tot_selected_verts_objects++;
+
+ if (shape_propagate(em)) {
+ tot_shapekeys++;
+ }
+
+ EDBM_update_generic(em, false, false);
+ }
+ MEM_freeN(objects);
+
+ if (tot_selected_verts_objects == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No selected vertex");
+ return OPERATOR_CANCELLED;
+ }
+ else if (tot_shapekeys == 0) {
+ BKE_report(
+ op->reports,
+ RPT_ERROR,
+ objects_len > 1 ?
+ "Meshes do not have shape keys" :
+ "Mesh does not have shape keys");
+ return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
@@ -2643,55 +3112,95 @@ void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
/* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = obedit->data;
- Key *key = me->key;
- KeyBlock *kb = NULL;
- BMEditMesh *em = me->edit_btmesh;
+ Object *obedit_ref = CTX_data_edit_object(C);
+ Mesh *me_ref = obedit_ref->data;
+ Key *key_ref = me_ref->key;
+ KeyBlock *kb_ref = NULL;
+ BMEditMesh *em_ref = me_ref->edit_btmesh;
BMVert *eve;
BMIter iter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
float co[3], *sco;
- int totshape;
+ int totshape_ref = 0;
const float blend = RNA_float_get(op->ptr, "blend");
- const int shape = RNA_enum_get(op->ptr, "shape");
+ int shape_ref = RNA_enum_get(op->ptr, "shape");
const bool use_add = RNA_boolean_get(op->ptr, "add");
- /* sanity check */
- totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
- if (totshape == 0 || shape < 0 || shape >= totshape)
- return OPERATOR_CANCELLED;
+ /* Sanity check. */
+ totshape_ref = CustomData_number_of_layers(&em_ref->bm->vdata, CD_SHAPEKEY);
- /* get shape key - needed for finding reference shape (for add mode only) */
- if (key) {
- kb = BLI_findlink(&key->block, shape);
+ if (totshape_ref == 0 || shape_ref < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Active mesh does not have shape keys");
+ return OPERATOR_CANCELLED;
+ }
+ else if (shape_ref >= totshape_ref) {
+ /* This case occurs if operator was used before on object with more keys than current one. */
+ shape_ref = 0; /* default to basis */
}
- /* perform blending on selected vertices*/
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
- continue;
+ /* Get shape key - needed for finding reference shape (for add mode only). */
+ if (key_ref) {
+ kb_ref = BLI_findlink(&key_ref->block, shape_ref);
+ }
- /* get coordinates of shapekey we're blending from */
- sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
- copy_v3_v3(co, sco);
+ int tot_selected_verts_objects = 0;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Mesh *me = obedit->data;
+ Key *key = me->key;
+ KeyBlock *kb = NULL;
+ BMEditMesh *em = me->edit_btmesh;
+ int shape;
- if (use_add) {
- /* in add mode, we add relative shape key offset */
- if (kb) {
- const float *rco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative);
- sub_v3_v3v3(co, co, rco);
- }
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+ tot_selected_verts_objects++;
- madd_v3_v3fl(eve->co, co, blend);
+ if (!key) {
+ continue;
}
else {
- /* in blend mode, we interpolate to the shape key */
- interp_v3_v3v3(eve->co, eve->co, co, blend);
+ kb = BKE_keyblock_find_name(key, kb_ref->name);
+ shape = BLI_findindex(&key->block, kb);
+ }
+
+ if (kb) {
+ /* Perform blending on selected vertices. */
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
+ continue;
+
+ /* Get coordinates of shapekey we're blending from. */
+ sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
+ copy_v3_v3(co, sco);
+
+ if (use_add) {
+ /* In add mode, we add relative shape key offset. */
+ if (kb) {
+ const float *rco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, kb->relative);
+ sub_v3_v3v3(co, co, rco);
+ }
+
+ madd_v3_v3fl(eve->co, co, blend);
+ }
+ else {
+ /* In blend mode, we interpolate to the shape key. */
+ interp_v3_v3v3(eve->co, eve->co, co, blend);
+ }
+ }
+ EDBM_update_generic(em, true, false);
}
}
+ MEM_freeN(objects);
- EDBM_update_generic(em, true, false);
+ if (tot_selected_verts_objects == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No selected vertex");
+ return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
@@ -2778,39 +3287,48 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
static int edbm_solidify_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = obedit->data;
- BMEditMesh *em = me->edit_btmesh;
- BMesh *bm = em->bm;
- BMOperator bmop;
-
const float thickness = RNA_float_get(op->ptr, "thickness");
- if (!EDBM_op_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- /* deselect only the faces in the region to be solidified (leave wire
- * edges and loose verts selected, as there will be no corresponding
- * geometry selected below) */
- BMO_slot_buffer_hflag_disable(bm, bmop.slots_in, "geom", BM_FACE, BM_ELEM_SELECT, true);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- /* run the solidify operator */
- BMO_op_exec(bm, &bmop);
+ BMOperator bmop;
- /* select the newly generated faces */
- BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
+ if (!EDBM_op_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
+ continue;
+ }
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
+ /* deselect only the faces in the region to be solidified (leave wire
+ * edges and loose verts selected, as there will be no corresponding
+ * geometry selected below) */
+ BMO_slot_buffer_hflag_disable(bm, bmop.slots_in, "geom", BM_FACE, BM_ELEM_SELECT, true);
- EDBM_update_generic(em, true, true);
+ /* run the solidify operator */
+ BMO_op_exec(bm, &bmop);
+
+ /* select the newly generated faces */
+ BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
-
void MESH_OT_solidify(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -3183,7 +3701,7 @@ enum {
MESH_SEPARATE_LOOSE = 2,
};
-static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
+static Base *mesh_separate_tagged(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
{
Base *base_new;
Object *obedit = base_old->object;
@@ -3204,11 +3722,11 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE);
- base_new = ED_object_add_duplicate(bmain, scene, base_old, USER_DUP_MESH);
+ base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, USER_DUP_MESH);
/* DAG_relations_tag_update(bmain); */ /* normally would call directly after but in this case delay recalc */
assign_matarar(bmain, base_new->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
- ED_base_object_select(base_new, BA_SELECT);
+ ED_object_base_select(base_new, BA_SELECT);
BMO_op_callf(bm_old, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
"duplicate geom=%hvef dest=%p", BM_ELEM_TAG, bm_new);
@@ -3230,7 +3748,7 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe
return base_new;
}
-static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
+static bool mesh_separate_selected(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
{
/* we may have tags from previous operators */
BM_mesh_elem_hflag_disable_all(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, false);
@@ -3238,7 +3756,7 @@ static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BM
/* sel -> tag */
BM_mesh_elem_hflag_enable_test(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, false, BM_ELEM_SELECT);
- return (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL);
+ return (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL);
}
/* flush a hflag to from verts to edges/faces */
@@ -3337,7 +3855,7 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const
}
}
-static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
+static bool mesh_separate_material(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
{
BMFace *f_cmp, *f;
BMIter iter;
@@ -3378,7 +3896,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM
}
/* Move selection into a separate object */
- base_new = mesh_separate_tagged(bmain, scene, base_old, bm_old);
+ base_new = mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old);
if (base_new) {
mesh_separate_material_assign_mat_nr(bmain, base_new->object, mat_nr);
}
@@ -3389,7 +3907,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM
return result;
}
-static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
+static bool mesh_separate_loose(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
{
int i;
BMEdge *e;
@@ -3442,7 +3960,7 @@ static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh
bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG);
/* Move selection into a separate object */
- result |= (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL);
+ result |= (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL);
}
return result;
@@ -3452,42 +3970,52 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const int type = RNA_enum_get(op->ptr, "type");
int retval = 0;
if (ED_operator_editmesh(C)) {
- Base *base = CTX_data_active_base(C);
- BMEditMesh *em = BKE_editmesh_from_object(base->object);
-
- if (type == 0) {
- if ((em->bm->totvertsel == 0) &&
- (em->bm->totedgesel == 0) &&
- (em->bm->totfacesel == 0))
- {
- BKE_report(op->reports, RPT_ERROR, "Nothing selected");
- return OPERATOR_CANCELLED;
+ uint bases_len = 0;
+ uint empty_selection_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &bases_len);
+ for (uint bs_index = 0; bs_index < bases_len; bs_index++) {
+ Base *base = bases[bs_index];
+ BMEditMesh *em = BKE_editmesh_from_object(base->object);
+
+ if (type == 0) {
+ if ((em->bm->totvertsel == 0) &&
+ (em->bm->totedgesel == 0) &&
+ (em->bm->totfacesel == 0))
+ {
+ /* when all objects has no selection */
+ if (++empty_selection_len == bases_len) {
+ BKE_report(op->reports, RPT_ERROR, "Nothing selected");
+ }
+ continue;
+ }
}
- }
- /* editmode separate */
- switch (type) {
- case MESH_SEPARATE_SELECTED:
- retval = mesh_separate_selected(bmain, scene, base, em->bm);
- break;
- case MESH_SEPARATE_MATERIAL:
- retval = mesh_separate_material(bmain, scene, base, em->bm);
- break;
- case MESH_SEPARATE_LOOSE:
- retval = mesh_separate_loose(bmain, scene, base, em->bm);
- break;
- default:
- BLI_assert(0);
- break;
- }
+ /* editmode separate */
+ switch (type) {
+ case MESH_SEPARATE_SELECTED:
+ retval = mesh_separate_selected(bmain, scene, view_layer, base, em->bm);
+ break;
+ case MESH_SEPARATE_MATERIAL:
+ retval = mesh_separate_material(bmain, scene, view_layer, base, em->bm);
+ break;
+ case MESH_SEPARATE_LOOSE:
+ retval = mesh_separate_loose(bmain, scene, view_layer, base, em->bm);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
- if (retval) {
- EDBM_update_generic(em, true, true);
+ if (retval) {
+ EDBM_update_generic(em, true, true);
+ }
}
+ MEM_freeN(bases);
}
else {
if (type == MESH_SEPARATE_SELECTED) {
@@ -3513,10 +4041,10 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
switch (type) {
case MESH_SEPARATE_MATERIAL:
- retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old);
+ retval_iter = mesh_separate_material(bmain, scene, view_layer, base_iter, bm_old);
break;
case MESH_SEPARATE_LOOSE:
- retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old);
+ retval_iter = mesh_separate_loose(bmain, scene, view_layer, base_iter, bm_old);
break;
default:
BLI_assert(0);
@@ -3530,7 +4058,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
.calc_object_remap = true,
}));
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
}
@@ -3545,7 +4073,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
if (retval) {
/* delay depsgraph recalc until all objects are duplicated */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
return OPERATOR_FINISHED;
@@ -3587,45 +4115,64 @@ void MESH_OT_separate(wmOperatorType *ot)
static int edbm_fill_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty");
- BMOperator bmop;
- const int totface_orig = em->bm->totface;
- int ret;
- if (em->bm->totedgesel == 0) {
- BKE_report(op->reports, RPT_WARNING, "No edges selected");
- return OPERATOR_CANCELLED;
- }
+ bool has_selected_edges = false, has_faces_filled = false;
- if (!EDBM_op_init(em, &bmop, op,
- "triangle_fill edges=%he use_beauty=%b",
- BM_ELEM_SELECT, use_beauty))
- {
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMO_op_exec(em->bm, &bmop);
+ const int totface_orig = em->bm->totface;
+
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
+ has_selected_edges = true;
+
+ BMOperator bmop;
+ if (!EDBM_op_init(
+ em, &bmop, op,
+ "triangle_fill edges=%he use_beauty=%b",
+ BM_ELEM_SELECT, use_beauty))
+ {
+ continue;
+ }
+
+ BMO_op_exec(em->bm, &bmop);
+
+ /* cancel if nothing was done */
+ if (totface_orig == em->bm->totface) {
+ EDBM_op_finish(em, &bmop, op, true);
+ continue;
+ }
+ has_faces_filled = true;
- if (totface_orig != em->bm->totface) {
/* select new geometry */
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
- EDBM_update_generic(em, true, true);
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
- ret = OPERATOR_FINISHED;
+ EDBM_update_generic(em, true, true);
}
- else {
- BKE_report(op->reports, RPT_WARNING, "No faces filled");
- ret = OPERATOR_CANCELLED;
+ MEM_freeN(objects);
+
+ if (!has_selected_edges) {
+ BKE_report(op->reports, RPT_ERROR, "No edges selected");
+ return OPERATOR_CANCELLED;
}
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- ret = OPERATOR_CANCELLED;
+ if (!has_faces_filled) {
+ BKE_report(op->reports, RPT_WARNING, "No faces filled");
+ return OPERATOR_CANCELLED;
}
- return ret;
+ return OPERATOR_FINISHED;
}
void MESH_OT_fill(wmOperatorType *ot)
@@ -3799,73 +4346,91 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
{
- BMOperator bmop;
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
- const int totedge_orig = em->bm->totedge;
- const int totface_orig = em->bm->totface;
- const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple");
const bool use_prepare = true;
+ const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- if (use_prepare) {
- /* use when we have a single loop selected */
- PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span");
- PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset");
- bool calc_span;
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int clamp = em->bm->totvertsel;
- int span;
- int offset;
+ const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
+ const int totedge_orig = em->bm->totedge;
+ const int totface_orig = em->bm->totface;
- if (RNA_property_is_set(op->ptr, prop_span)) {
- span = RNA_property_int_get(op->ptr, prop_span);
- span = min_ii(span, (clamp / 2) - 1);
- calc_span = false;
- }
- else {
- span = clamp / 4;
- calc_span = true;
+ if (em->bm->totedgesel == 0) {
+ continue;
}
- offset = RNA_property_int_get(op->ptr, prop_offset);
- offset = clamp ? mod_i(offset, clamp) : 0;
+ if (use_prepare) {
+ /* use when we have a single loop selected */
+ PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span");
+ PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset");
+ bool calc_span;
- /* in simple cases, move selection for tags, but also support more advanced cases */
- edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
+ const int clamp = em->bm->totvertsel;
+ int span;
+ int offset;
- RNA_property_int_set(op->ptr, prop_span, span);
- }
- /* end tricky prepare code */
+ if (RNA_property_is_set(op->ptr, prop_span)) {
+ span = RNA_property_int_get(op->ptr, prop_span);
+ span = min_ii(span, (clamp / 2) - 1);
+ calc_span = false;
+ }
+ else {
+ span = clamp / 4;
+ calc_span = true;
+ }
+ offset = RNA_property_int_get(op->ptr, prop_offset);
+ offset = clamp ? mod_i(offset, clamp) : 0;
- if (!EDBM_op_init(
- em, &bmop, op,
- "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
- use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
- em->mat_nr, use_smooth, use_interp_simple))
- {
- return OPERATOR_CANCELLED;
- }
+ /* in simple cases, move selection for tags, but also support more advanced cases */
+ edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
- BMO_op_exec(em->bm, &bmop);
+ RNA_property_int_set(op->ptr, prop_span, span);
+ }
+ /* end tricky prepare code */
- /* cancel if nothing was done */
- if ((totedge_orig == em->bm->totedge) &&
- (totface_orig == em->bm->totface))
- {
- EDBM_op_finish(em, &bmop, op, true);
- return OPERATOR_CANCELLED;
- }
+ BMOperator bmop;
+ if (!EDBM_op_init(
+ em, &bmop, op,
+ "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
+ use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT,
+ em->mat_nr, use_smooth, use_interp_simple))
+ {
+ continue;
+ }
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ BMO_op_exec(em->bm, &bmop);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ /* NOTE: EDBM_op_finish() will change bmesh pointer inside of edit mesh,
+ * so need to tell evaluated objects to sync new bmesh pointer to their
+ * edit mesh structures.
+ */
+ DEG_id_tag_update(&obedit->id, 0);
+
+ /* cancel if nothing was done */
+ if ((totedge_orig == em->bm->totedge) &&
+ (totface_orig == em->bm->totface))
+ {
+ EDBM_op_finish(em, &bmop, op, true);
+ continue;
+ }
+
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
}
- EDBM_update_generic(em, true, true);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3904,20 +4469,32 @@ void MESH_OT_fill_grid(wmOperatorType *ot)
static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int sides = RNA_int_get(op->ptr, "sides");
- if (!EDBM_op_call_and_selectf(
- em, op,
- "faces.out", true,
- "holes_fill edges=%he sides=%i",
- BM_ELEM_SELECT, sides))
- {
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- EDBM_update_generic(em, true, true);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "holes_fill edges=%he sides=%i",
+ BM_ELEM_SELECT, sides))
+ {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
@@ -3949,40 +4526,51 @@ void MESH_OT_fill_holes(wmOperatorType *ot)
static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
const float angle_max = M_PI;
const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
char hflag;
- if (angle_limit >= angle_max) {
- hflag = BM_ELEM_SELECT;
- }
- else {
- BMIter iter;
- BMEdge *e;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(
- e, BM_ELEM_TAG,
- (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
- BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
+ if (angle_limit >= angle_max) {
+ hflag = BM_ELEM_SELECT;
+ }
+ else {
+ BMIter iter;
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(
+ e, BM_ELEM_TAG,
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
+ BM_edge_calc_face_angle_ex(e, angle_max) < angle_limit));
+ }
+ hflag = BM_ELEM_TAG;
}
- hflag = BM_ELEM_TAG;
- }
+ if (!EDBM_op_call_and_selectf(
+ em, op, "geom.out", true,
+ "beautify_fill faces=%hf edges=%he",
+ BM_ELEM_SELECT, hflag))
+ {
+ continue;
+ }
- if (!EDBM_op_call_and_selectf(
- em, op, "geom.out", true,
- "beautify_fill faces=%hf edges=%he",
- BM_ELEM_SELECT, hflag))
- {
- return OPERATOR_CANCELLED;
+ EDBM_update_generic(em, true, true);
}
- EDBM_update_generic(em, true, true);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4017,30 +4605,40 @@ void MESH_OT_beautify_fill(wmOperatorType *ot)
static int edbm_poke_face_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
-
const float offset = RNA_float_get(op->ptr, "offset");
const bool use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset");
const int center_mode = RNA_enum_get(op->ptr, "center_mode");
- EDBM_op_init(em, &bmop, op, "poke faces=%hf offset=%f use_relative_offset=%b center_mode=%i",
- BM_ELEM_SELECT, offset, use_relative_offset, center_mode);
- BMO_op_exec(em->bm, &bmop);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ BMOperator bmop;
+ EDBM_op_init(em, &bmop, op, "poke faces=%hf offset=%f use_relative_offset=%b center_mode=%i",
+ BM_ELEM_SELECT, offset, use_relative_offset, center_mode);
+ BMO_op_exec(em->bm, &bmop);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- EDBM_mesh_normals_update(em);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "verts.out", BM_VERT, BM_ELEM_SELECT, true);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
- EDBM_update_generic(em, true, true);
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+
+ EDBM_mesh_normals_update(em);
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
@@ -4081,32 +4679,48 @@ void MESH_OT_poke(wmOperatorType *ot)
static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
const int quad_method = RNA_enum_get(op->ptr, "quad_method");
const int ngon_method = RNA_enum_get(op->ptr, "ngon_method");
- BMOIter oiter;
- BMFace *f;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- EDBM_op_init(em, &bmop, op, "triangulate faces=%hf quad_method=%i ngon_method=%i", BM_ELEM_SELECT, quad_method, ngon_method);
- BMO_op_exec(em->bm, &bmop);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* select the output */
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- /* remove the doubles */
- BMO_ITER (f, &oiter, bmop.slots_out, "face_map_double.out", BM_FACE) {
- BM_face_kill(em->bm, f);
- }
+ BMOperator bmop;
+ BMOIter oiter;
+ BMFace *f;
- EDBM_selectmode_flush(em);
+ EDBM_op_init(
+ em, &bmop, op,
+ "triangulate faces=%hf quad_method=%i ngon_method=%i",
+ BM_ELEM_SELECT, quad_method, ngon_method);
+ BMO_op_exec(em->bm, &bmop);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ /* select the output */
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+
+ /* remove the doubles */
+ BMO_ITER (f, &oiter, bmop.slots_out, "face_map_double.out", BM_FACE) {
+ BM_face_kill(em->bm, f);
+ }
+
+ EDBM_selectmode_flush(em);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
}
- EDBM_update_generic(em, true, true);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4140,52 +4754,69 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
- float angle_face_threshold, angle_shape_threshold;
- PropertyRNA *prop;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- /* When joining exactly 2 faces, no limit.
- * this is useful for one off joins while editing. */
- prop = RNA_struct_find_property(op->ptr, "face_threshold");
- if ((em->bm->totfacesel == 2) &&
- (RNA_property_is_set(op->ptr, prop) == false))
- {
- angle_face_threshold = DEG2RADF(180.0f);
- }
- else {
- angle_face_threshold = RNA_property_float_get(op->ptr, prop);
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ bool is_face_pair;
- prop = RNA_struct_find_property(op->ptr, "shape_threshold");
- if ((em->bm->totfacesel == 2) &&
- (RNA_property_is_set(op->ptr, prop) == false))
- {
- angle_shape_threshold = DEG2RADF(180.0f);
- }
- else {
- angle_shape_threshold = RNA_property_float_get(op->ptr, prop);
- }
-
- do_seam = RNA_boolean_get(op->ptr, "seam");
- do_sharp = RNA_boolean_get(op->ptr, "sharp");
- do_uvs = RNA_boolean_get(op->ptr, "uvs");
- do_vcols = RNA_boolean_get(op->ptr, "vcols");
- do_materials = RNA_boolean_get(op->ptr, "materials");
-
- if (!EDBM_op_call_and_selectf(
- em, op,
- "faces.out", true,
- "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
- "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
- BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold,
- do_seam, do_sharp, do_uvs, do_vcols, do_materials))
{
- return OPERATOR_CANCELLED;
+ int totelem_sel[3];
+ EDBM_mesh_stats_multi(objects, objects_len, NULL, totelem_sel);
+ is_face_pair = (totelem_sel[2] == 2);
}
- EDBM_update_generic(em, true, true);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
+ float angle_face_threshold, angle_shape_threshold;
+ PropertyRNA *prop;
+
+ /* When joining exactly 2 faces, no limit.
+ * this is useful for one off joins while editing. */
+ prop = RNA_struct_find_property(op->ptr, "face_threshold");
+ if (is_face_pair &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_face_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_face_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "shape_threshold");
+ if (is_face_pair &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_shape_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_shape_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ do_seam = RNA_boolean_get(op->ptr, "seam");
+ do_sharp = RNA_boolean_get(op->ptr, "sharp");
+ do_uvs = RNA_boolean_get(op->ptr, "uvs");
+ do_vcols = RNA_boolean_get(op->ptr, "vcols");
+ do_materials = RNA_boolean_get(op->ptr, "materials");
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
+ "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
+ BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold,
+ do_seam, do_sharp, do_uvs, do_vcols, do_materials))
+ {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4241,10 +4872,6 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
static int edbm_decimate_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
-
const float ratio = RNA_float_get(op->ptr, "ratio");
bool use_vertex_group = RNA_boolean_get(op->ptr, "use_vertex_group");
const float vertex_group_factor = RNA_float_get(op->ptr, "vertex_group_factor");
@@ -4258,95 +4885,108 @@ static int edbm_decimate_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__);
- {
- const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
- const int defbase_act = obedit->actdef - 1;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (use_vertex_group && (cd_dvert_offset == -1)) {
- BKE_report(op->reports, RPT_WARNING, "No active vertex group");
- use_vertex_group = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ if (bm->totedgesel == 0) {
+ continue;
}
- BMIter iter;
- BMVert *v;
- int i;
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- float weight = 0.0f;
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- if (use_vertex_group) {
- const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
- weight = defvert_find_weight(dv, defbase_act);
- if (invert_vertex_group) {
- weight = 1.0f - weight;
+ float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__);
+ {
+ const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
+ const int defbase_act = obedit->actdef - 1;
+
+ if (use_vertex_group && (cd_dvert_offset == -1)) {
+ BKE_report(op->reports, RPT_WARNING, "No active vertex group");
+ use_vertex_group = false;
+ }
+
+ BMIter iter;
+ BMVert *v;
+ int i;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ float weight = 0.0f;
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ if (use_vertex_group) {
+ const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
+ weight = defvert_find_weight(dv, defbase_act);
+ if (invert_vertex_group) {
+ weight = 1.0f - weight;
+ }
+ }
+ else {
+ weight = 1.0f;
}
}
- else {
- weight = 1.0f;
- }
- }
- vweights[i] = weight;
- BM_elem_index_set(v, i); /* set_inline */
+ vweights[i] = weight;
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
}
- bm->elem_index_dirty &= ~BM_VERT;
- }
-
- float ratio_adjust;
-
- if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) {
- ratio_adjust = ratio;
- }
- else {
- /**
- * Calculate a new ratio based on faces that could be remoevd during decimation.
- * needed so 0..1 has a meaningful range when operating on the selection.
- *
- * This doesn't have to be totally accurate,
- * but needs to be greater than the number of selected faces
- */
- int totface_basis = 0;
- int totface_adjacent = 0;
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- /* count faces during decimation, ngons are triangulated */
- const int f_len = f->len > 4 ? (f->len - 2) : 1;
- totface_basis += f_len;
+ float ratio_adjust;
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) {
- totface_adjacent += f_len;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
+ if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) {
+ ratio_adjust = ratio;
}
+ else {
+ /**
+ * Calculate a new ratio based on faces that could be remoevd during decimation.
+ * needed so 0..1 has a meaningful range when operating on the selection.
+ *
+ * This doesn't have to be totally accurate,
+ * but needs to be greater than the number of selected faces
+ */
+
+ int totface_basis = 0;
+ int totface_adjacent = 0;
+ BMIter iter;
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ /* count faces during decimation, ngons are triangulated */
+ const int f_len = f->len > 4 ? (f->len - 2) : 1;
+ totface_basis += f_len;
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) {
+ totface_adjacent += f_len;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
- ratio_adjust = ratio;
- ratio_adjust = 1.0f - ratio_adjust;
- ratio_adjust *= (float)totface_adjacent / (float)totface_basis;
- ratio_adjust = 1.0f - ratio_adjust;
- }
+ ratio_adjust = ratio;
+ ratio_adjust = 1.0f - ratio_adjust;
+ ratio_adjust *= (float)totface_adjacent / (float)totface_basis;
+ ratio_adjust = 1.0f - ratio_adjust;
+ }
- BM_mesh_decimate_collapse(
- em->bm, ratio_adjust, vweights, vertex_group_factor, false,
- symmetry_axis, symmetry_eps);
+ BM_mesh_decimate_collapse(
+ em->bm, ratio_adjust, vweights, vertex_group_factor, false,
+ symmetry_axis, symmetry_eps);
- MEM_freeN(vweights);
+ MEM_freeN(vweights);
- {
- short selectmode = em->selectmode;
- if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
- /* ensure we flush edges -> faces */
- selectmode |= SCE_SELECT_EDGE;
+ {
+ short selectmode = em->selectmode;
+ if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) {
+ /* ensure we flush edges -> faces */
+ selectmode |= SCE_SELECT_EDGE;
+ }
+ EDBM_selectmode_flush_ex(em, selectmode);
}
- EDBM_selectmode_flush_ex(em, selectmode);
+ EDBM_update_generic(em, true, true);
}
-
- EDBM_update_generic(em, true, true);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4445,22 +5085,32 @@ static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot)
static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
- if (!EDBM_op_callf(
- em, op,
- "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
- BM_ELEM_SELECT, use_face_split, use_boundary_tear))
- {
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- EDBM_update_generic(em, true, true);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+
+ if (!EDBM_op_callf(
+ em, op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_SELECT, use_face_split, use_boundary_tear))
+ {
+ continue;
+ }
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4490,21 +5140,32 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot)
static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
- if (!EDBM_op_callf(
- em, op,
- "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
- BM_ELEM_SELECT, use_verts, use_face_split))
- {
- return OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
+
+ if (!EDBM_op_callf(
+ em, op,
+ "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
+ BM_ELEM_SELECT, use_verts, use_face_split))
+ {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
}
- EDBM_update_generic(em, true, true);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4535,21 +5196,30 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot)
static int edbm_dissolve_faces_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!EDBM_op_call_and_selectf(
- em, op,
- "region.out", true,
- "dissolve_faces faces=%hf use_verts=%b",
- BM_ELEM_SELECT, use_verts))
- {
- return OPERATOR_CANCELLED;
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- EDBM_update_generic(em, true, true);
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "region.out", true,
+ "dissolve_faces faces=%hf use_verts=%b",
+ BM_ELEM_SELECT, use_verts))
+ {
+ continue;
+ }
+
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4629,52 +5299,65 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot)
static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
const float angle_limit = RNA_float_get(op->ptr, "angle_limit");
const bool use_dissolve_boundaries = RNA_boolean_get(op->ptr, "use_dissolve_boundaries");
const int delimit = RNA_enum_get(op->ptr, "delimit");
-
char dissolve_flag;
- if (em->selectmode == SCE_SELECT_FACE) {
- /* flush selection to tags and untag edges/verts with partially selected faces */
- BMIter iter;
- BMIter liter;
-
- BMElem *ele;
- BMFace *f;
- BMLoop *l;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_set(ele, BM_ELEM_TAG, BM_elem_flag_test(ele, BM_ELEM_SELECT));
- }
- BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(ele, BM_ELEM_TAG, BM_elem_flag_test(ele, BM_ELEM_SELECT));
+ if ((bm->totvertsel == 0) &&
+ (bm->totedgesel == 0) &&
+ (bm->totfacesel == 0))
+ {
+ continue;
}
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- BM_elem_flag_disable(l->v, BM_ELEM_TAG);
- BM_elem_flag_disable(l->e, BM_ELEM_TAG);
+ if (em->selectmode == SCE_SELECT_FACE) {
+ /* flush selection to tags and untag edges/verts with partially selected faces */
+ BMIter iter;
+ BMIter liter;
+
+ BMElem *ele;
+ BMFace *f;
+ BMLoop *l;
+
+ BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(ele, BM_ELEM_TAG, BM_elem_flag_test(ele, BM_ELEM_SELECT));
+ }
+ BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(ele, BM_ELEM_TAG, BM_elem_flag_test(ele, BM_ELEM_SELECT));
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_disable(l->e, BM_ELEM_TAG);
+ }
}
}
- }
- dissolve_flag = BM_ELEM_TAG;
- }
- else {
- dissolve_flag = BM_ELEM_SELECT;
- }
+ dissolve_flag = BM_ELEM_TAG;
+ }
+ else {
+ dissolve_flag = BM_ELEM_SELECT;
+ }
- EDBM_op_call_and_selectf(
- em, op, "region.out", true,
- "dissolve_limit edges=%he verts=%hv angle_limit=%f use_dissolve_boundaries=%b delimit=%i",
- dissolve_flag, dissolve_flag, angle_limit, use_dissolve_boundaries, delimit);
+ EDBM_op_call_and_selectf(
+ em, op, "region.out", true,
+ "dissolve_limit edges=%he verts=%hv angle_limit=%f use_dissolve_boundaries=%b delimit=%i",
+ dissolve_flag, dissolve_flag, angle_limit, use_dissolve_boundaries, delimit);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4712,26 +5395,49 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
static int edbm_dissolve_degenerate_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int totelem_old[3] = {0, 0, 0};
+ int totelem_new[3] = {0, 0, 0};
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ totelem_old[0] += bm->totvert;
+ totelem_old[1] += bm->totedge;
+ totelem_old[2] += bm->totface;
+ } /* objects */
+
const float thresh = RNA_float_get(op->ptr, "threshold");
- BMesh *bm = em->bm;
- const int totelem[3] = {bm->totvert, bm->totedge, bm->totface};
- if (!EDBM_op_callf(
- em, op,
- "dissolve_degenerate edges=%he dist=%f",
- BM_ELEM_SELECT, thresh))
- {
- return OPERATOR_CANCELLED;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- /* tricky to maintain correct selection here, so just flush up from verts */
- EDBM_select_flush(em);
+ if (!EDBM_op_callf(
+ em, op,
+ "dissolve_degenerate edges=%he dist=%f",
+ BM_ELEM_SELECT, thresh))
+ {
+ return OPERATOR_CANCELLED;
+ }
- EDBM_update_generic(em, true, true);
+ /* tricky to maintain correct selection here, so just flush up from verts */
+ EDBM_select_flush(em);
+
+ EDBM_update_generic(em, true, true);
- edbm_report_delete_info(op->reports, bm, totelem);
+ totelem_new[0] += bm->totvert;
+ totelem_new[1] += bm->totedge;
+ totelem_new[2] += bm->totface;
+ }
+ MEM_freeN(objects);
+
+ edbm_report_delete_info(op->reports, totelem_old, totelem_new);
return OPERATOR_FINISHED;
}
@@ -4763,42 +5469,52 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
/* internally uses dissolve */
static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- /* deal with selection */
- {
- BMEdge *e;
- BMIter iter;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
- BMLoop *l_iter = e->l;
- do {
- BM_elem_flag_enable(l_iter->f, BM_ELEM_TAG);
- } while ((l_iter = l_iter->radial_next) != e->l);
+ /* deal with selection */
+ {
+ BMEdge *e;
+ BMIter iter;
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
+ BMLoop *l_iter = e->l;
+ do {
+ BM_elem_flag_enable(l_iter->f, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
}
}
- }
- if (!EDBM_op_callf(
- em, op,
- "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
- BM_ELEM_SELECT, true, use_face_split))
- {
- return OPERATOR_CANCELLED;
- }
+ if (!EDBM_op_callf(
+ em, op,
+ "dissolve_edges edges=%he use_verts=%b use_face_split=%b",
+ BM_ELEM_SELECT, true, use_face_split))
+ {
+ continue;
+ }
- BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
- EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4828,22 +5544,34 @@ void MESH_OT_delete_edgeloop(wmOperatorType *ot)
static int edbm_split_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMOperator bmop;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if ((em->bm->totvertsel == 0) &&
+ (em->bm->totedgesel == 0) &&
+ (em->bm->totfacesel == 0))
+ {
+ continue;
+ }
+ BMOperator bmop;
+ EDBM_op_init(em, &bmop, op, "split geom=%hvef use_only_faces=%b", BM_ELEM_SELECT, false);
+ BMO_op_exec(em->bm, &bmop);
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
- EDBM_op_init(em, &bmop, op, "split geom=%hvef use_only_faces=%b", BM_ELEM_SELECT, false);
- BMO_op_exec(em->bm, &bmop);
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
- /* Geometry has changed, need to recalc normals and looptris */
- EDBM_mesh_normals_update(em);
+ /* Geometry has changed, need to recalc normals and looptris */
+ EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ EDBM_update_generic(em, true, true);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4897,8 +5625,9 @@ static int bmelemsort_comp(const void *v1, const void *v2)
/* Reorders vertices/edges/faces using a given methods. Loops are not supported. */
static void sort_bmelem_flag(
+ bContext *C,
Scene *scene, Object *ob,
- View3D *v3d, RegionView3D *rv3d,
+ RegionView3D *rv3d,
const int types, const int flag, const int action,
const int reverse, const unsigned int seed)
{
@@ -5000,10 +5729,8 @@ static void sort_bmelem_flag(
float mat[4][4];
float fact = reverse ? -1.0 : 1.0;
- if (v3d && v3d->localvd)
- copy_v3_v3(cur, v3d->cursor);
- else
- copy_v3_v3(cur, scene->cursor);
+ copy_v3_v3(cur, scene->cursor.location);
+
invert_m4_m4(mat, ob->obmat);
mul_m4_v3(mat, cur);
@@ -5321,7 +6048,8 @@ static void sort_bmelem_flag(
}
BM_mesh_remap(em->bm, map[0], map[1], map[2]);
-/* DAG_id_tag_update(ob->data, 0);*/
+ DEG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
for (j = 3; j--; ) {
if (map[j])
@@ -5332,10 +6060,10 @@ static void sort_bmelem_flag(
static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_edit_object(C);
/* may be NULL */
- View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
const int action = RNA_enum_get(op->ptr, "type");
@@ -5356,7 +6084,7 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
elem_types = RNA_property_enum_get(op->ptr, prop_elem_types);
}
else {
- BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMEditMesh *em = BKE_editmesh_from_object(ob_active);
if (em->selectmode & SCE_SELECT_VERTEX)
elem_types |= BM_VERT;
if (em->selectmode & SCE_SELECT_EDGE)
@@ -5366,9 +6094,33 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
RNA_enum_set(op->ptr, "elements", elem_types);
}
- sort_bmelem_flag(
- scene, ob, v3d, rv3d,
- elem_types, BM_ELEM_SELECT, action, use_reverse, seed);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+
+ if (!((elem_types & BM_VERT && bm->totvertsel > 0) ||
+ (elem_types & BM_EDGE && bm->totedgesel > 0) ||
+ (elem_types & BM_FACE && bm->totfacesel > 0)))
+ {
+ continue;
+ }
+
+ int seed_iter = seed;
+
+ /* This gives a consistent result regardless of object order */
+ if (ob_index) {
+ seed_iter += BLI_ghashutil_strhash_p(ob->id.name);
+ }
+
+ sort_bmelem_flag(
+ C, scene, ob, rv3d,
+ elem_types, BM_ELEM_SELECT, action, use_reverse, seed_iter);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -5448,84 +6200,6 @@ void MESH_OT_sort_elements(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Noise (Deform Vertices) Operator
- * \{ */
-
-static int edbm_noise_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- Material *ma;
- Tex *tex;
- BMVert *eve;
- BMIter iter;
- const float fac = RNA_float_get(op->ptr, "factor");
-
- if (em == NULL) {
- return OPERATOR_FINISHED;
- }
-
- if ((ma = give_current_material(obedit, obedit->actcol)) == NULL ||
- (tex = give_current_material_texture(ma)) == NULL)
- {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned");
- return OPERATOR_FINISHED;
- }
-
- if (tex->type == TEX_STUCCI) {
- float b2, vec[3];
- float ofs = tex->turbul / 200.0f;
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- b2 = BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
- if (tex->stype) ofs *= (b2 * b2);
- vec[0] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0] + ofs, eve->co[1], eve->co[2]));
- vec[1] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1] + ofs, eve->co[2]));
- vec[2] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2] + ofs));
-
- add_v3_v3(eve->co, vec);
- }
- }
- }
- else {
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- float tin = 0.0f, dum;
- if (ma->mtex[ma->texact] != NULL) {
- externtex(ma->mtex[ma->texact], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false, false);
- }
- eve->co[2] += fac * tin;
- }
- }
- }
-
- EDBM_mesh_normals_update(em);
-
- EDBM_update_generic(em, true, false);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_noise(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Noise";
- ot->description = "Use vertex coordinate as texture coordinate";
- ot->idname = "MESH_OT_noise";
-
- /* api callbacks */
- ot->exec = edbm_noise_exec;
- ot->poll = ED_operator_editmesh;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_float(ot->srna, "factor", 0.1f, -1e4f, 1e4f, "Factor", "", 0.0f, 1.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Bridge Operator
* \{ */
@@ -5577,22 +6251,20 @@ static int edbm_bridge_tag_boundary_edges(BMesh *bm)
return totface_del;
}
-static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
+static int edbm_bridge_edge_loops_for_single_editmesh(
+ wmOperator *op,
+ BMEditMesh *em,
+ const bool use_pairs,
+ const bool use_cyclic,
+ const bool use_merge,
+ const float merge_factor,
+ const int twist_offset)
{
BMOperator bmop;
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int type = RNA_enum_get(op->ptr, "type");
- const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS);
- const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED);
- const bool use_merge = RNA_boolean_get(op->ptr, "use_merge");
- const float merge_factor = RNA_float_get(op->ptr, "merge_factor");
- const int twist_offset = RNA_int_get(op->ptr, "twist_offset");
- const bool use_faces = (em->bm->totfacesel != 0);
char edge_hflag;
-
int totface_del = 0;
BMFace **totface_del_arr = NULL;
+ const bool use_faces = (em->bm->totfacesel != 0);
if (use_faces) {
BMIter iter;
@@ -5615,9 +6287,9 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
}
EDBM_op_init(
- em, &bmop, op,
- "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i",
- edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
+ em, &bmop, op,
+ "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f twist_offset=%i",
+ edge_hflag, use_pairs, use_cyclic, use_merge, merge_factor, twist_offset);
if (use_faces && totface_del) {
int i;
@@ -5626,9 +6298,9 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
BM_elem_flag_enable(totface_del_arr[i], BM_ELEM_TAG);
}
BMO_op_callf(
- em->bm, BMO_FLAG_DEFAULTS,
- "delete geom=%hf context=%i",
- BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY);
+ em->bm, BMO_FLAG_DEFAULTS,
+ "delete geom=%hf context=%i",
+ BM_ELEM_TAG, DEL_FACES_KEEP_BOUNDARY);
}
BMO_op_exec(em->bm, &bmop);
@@ -5650,18 +6322,15 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
EDBM_mesh_normals_update(em);
BMO_op_initf(
- em->bm, &bmop_subd, 0,
- "subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f "
- "profile_shape=%i profile_shape_factor=%f",
- &bmop, "edges.out", op_props.interp_mode, op_props.cuts, op_props.smooth,
- op_props.profile_shape, op_props.profile_shape_factor
- );
+ em->bm, &bmop_subd, 0,
+ "subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f "
+ "profile_shape=%i profile_shape_factor=%f",
+ &bmop, "edges.out", op_props.interp_mode, op_props.cuts, op_props.smooth,
+ op_props.profile_shape, op_props.profile_shape_factor
+ );
BMO_op_exec(em->bm, &bmop_subd);
-
BMO_slot_buffer_hflag_enable(em->bm, bmop_subd.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
-
BMO_op_finish(em->bm, &bmop_subd);
-
}
}
}
@@ -5670,15 +6339,44 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
MEM_freeN(totface_del_arr);
}
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- /* grr, need to return finished so the user can select different options */
- //return OPERATOR_CANCELLED;
- return OPERATOR_FINISHED;
- }
- else {
+ if (EDBM_op_finish(em, &bmop, op, true)) {
EDBM_update_generic(em, true, true);
- return OPERATOR_FINISHED;
}
+
+ /* Always return finished so the user can select different options. */
+ return OPERATOR_FINISHED;
+}
+
+static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
+{
+ const int type = RNA_enum_get(op->ptr, "type");
+ const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS);
+ const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED);
+ const bool use_merge = RNA_boolean_get(op->ptr, "use_merge");
+ const float merge_factor = RNA_float_get(op->ptr, "merge_factor");
+ const int twist_offset = RNA_int_get(op->ptr, "twist_offset");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+
+ edbm_bridge_edge_loops_for_single_editmesh(op,
+ em,
+ use_pairs,
+ use_cyclic,
+ use_merge,
+ merge_factor,
+ twist_offset);
+ }
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
@@ -5720,9 +6418,6 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
static int edbm_wireframe_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
const bool use_even_offset = RNA_boolean_get(op->ptr, "use_even_offset");
const bool use_replace = RNA_boolean_get(op->ptr, "use_replace");
@@ -5732,25 +6427,41 @@ static int edbm_wireframe_exec(bContext *C, wmOperator *op)
const float thickness = RNA_float_get(op->ptr, "thickness");
const float offset = RNA_float_get(op->ptr, "offset");
- EDBM_op_init(
- em, &bmop, op,
- "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b "
- "use_crease=%b crease_weight=%f thickness=%f offset=%f",
- BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset,
- use_crease, crease_weight, thickness, offset);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMO_op_exec(em->bm, &bmop);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ BMOperator bmop;
+
+ EDBM_op_init(
+ em, &bmop, op,
+ "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b use_relative_offset=%b "
+ "use_crease=%b crease_weight=%f thickness=%f offset=%f",
+ BM_ELEM_SELECT, use_replace, use_boundary, use_even_offset, use_relative_offset,
+ use_crease, crease_weight, thickness, offset);
+
+ BMO_op_exec(em->bm, &bmop);
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
- else {
EDBM_update_generic(em, true, true);
- return OPERATOR_FINISHED;
}
+
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void MESH_OT_wireframe(wmOperatorType *ot)
@@ -5791,37 +6502,62 @@ void MESH_OT_wireframe(wmOperatorType *ot)
static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
+ bool mode_change = false;
const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint");
+ int ret = OPERATOR_CANCELLED;
- EDBM_op_init(
- em, &bmop, op,
- "offset_edgeloops edges=%he use_cap_endpoint=%b",
- BM_ELEM_SELECT, use_cap_endpoint);
+ {
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (em->selectmode == SCE_SELECT_FACE) {
+ EDBM_selectmode_to_scene(C);
+ mode_change = true;
+ }
+ }
- BMO_op_exec(em->bm, &bmop);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ /** If in face-only select mode, switch to edge select mode so that
+ * an edge-only selection is not inconsistent state.
+ *
+ * We need to run this for all objects, even when nothing is selected.
+ * This way we keep them in sync. */
+ if (mode_change) {
+ em->selectmode = SCE_SELECT_EDGE;
+ EDBM_selectmode_set(em);
+ }
- /* If in face-only select mode, switch to edge select mode so that
- * an edge-only selection is not inconsistent state */
- if (em->selectmode == SCE_SELECT_FACE) {
- em->selectmode = SCE_SELECT_EDGE;
- EDBM_selectmode_set(em);
- EDBM_selectmode_to_scene(C);
- }
+ if (em->bm->totedgesel == 0) {
+ continue;
+ }
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+ BMOperator bmop;
+ EDBM_op_init(
+ em, &bmop, op,
+ "offset_edgeloops edges=%he use_cap_endpoint=%b",
+ BM_ELEM_SELECT, use_cap_endpoint);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
- else {
- EDBM_update_generic(em, true, true);
- return OPERATOR_FINISHED;
+ BMO_op_exec(em->bm, &bmop);
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+ else {
+ EDBM_update_generic(em, true, true);
+ ret = OPERATOR_FINISHED;
+ }
}
+ MEM_freeN(objects);
+ return ret;
}
void MESH_OT_offset_edge_loops(wmOperatorType *ot)
@@ -5852,73 +6588,89 @@ void MESH_OT_offset_edge_loops(wmOperatorType *ot)
#ifdef WITH_BULLET
static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
+ const bool use_existing_faces = RNA_boolean_get(op->ptr, "use_existing_faces");
+ const bool delete_unused = RNA_boolean_get(op->ptr, "delete_unused");
+ const bool make_holes = RNA_boolean_get(op->ptr, "make_holes");
+ const bool join_triangles = RNA_boolean_get(op->ptr, "join_triangles");
- EDBM_op_init(
- em, &bmop, op, "convex_hull input=%hvef "
- "use_existing_faces=%b",
- BM_ELEM_SELECT,
- RNA_boolean_get(op->ptr, "use_existing_faces"));
- BMO_op_exec(em->bm, &bmop);
+ float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold");
+ float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold");
- /* Hull fails if input is coplanar */
- if (BMO_error_occurred(em->bm)) {
- EDBM_op_finish(em, &bmop, op, true);
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
- /* Delete unused vertices, edges, and faces */
- if (RNA_boolean_get(op->ptr, "delete_unused")) {
- if (!EDBM_op_callf(
- em, op, "delete geom=%S context=%i",
- &bmop, "geom_unused.out", DEL_ONLYTAGGED))
- {
+ BMOperator bmop;
+
+ EDBM_op_init(
+ em, &bmop, op, "convex_hull input=%hvef "
+ "use_existing_faces=%b",
+ BM_ELEM_SELECT,
+ use_existing_faces);
+ BMO_op_exec(em->bm, &bmop);
+
+ /* Hull fails if input is coplanar */
+ if (BMO_error_occurred(em->bm)) {
EDBM_op_finish(em, &bmop, op, true);
- return OPERATOR_CANCELLED;
+ continue;
}
- }
- /* Delete hole edges/faces */
- if (RNA_boolean_get(op->ptr, "make_holes")) {
- if (!EDBM_op_callf(
- em, op, "delete geom=%S context=%i",
- &bmop, "geom_holes.out", DEL_ONLYTAGGED))
- {
- EDBM_op_finish(em, &bmop, op, true);
- return OPERATOR_CANCELLED;
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
+
+ /* Delete unused vertices, edges, and faces */
+ if (delete_unused) {
+ if (!EDBM_op_callf(
+ em, op, "delete geom=%S context=%i",
+ &bmop, "geom_unused.out", DEL_ONLYTAGGED))
+ {
+ EDBM_op_finish(em, &bmop, op, true);
+ continue;
+ }
}
- }
- /* Merge adjacent triangles */
- if (RNA_boolean_get(op->ptr, "join_triangles")) {
- float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold");
- float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold");
+ /* Delete hole edges/faces */
+ if (make_holes) {
+ if (!EDBM_op_callf(
+ em, op, "delete geom=%S context=%i",
+ &bmop, "geom_holes.out", DEL_ONLYTAGGED))
+ {
+ EDBM_op_finish(em, &bmop, op, true);
+ continue;
+ }
+ }
- if (!EDBM_op_call_and_selectf(
- em, op,
- "faces.out", true,
- "join_triangles faces=%S "
- "angle_face_threshold=%f angle_shape_threshold=%f",
- &bmop, "geom.out",
- angle_face_threshold, angle_shape_threshold))
- {
- EDBM_op_finish(em, &bmop, op, true);
- return OPERATOR_CANCELLED;
+ /* Merge adjacent triangles */
+ if (join_triangles) {
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "join_triangles faces=%S "
+ "angle_face_threshold=%f angle_shape_threshold=%f",
+ &bmop, "geom.out",
+ angle_face_threshold, angle_shape_threshold))
+ {
+ EDBM_op_finish(em, &bmop, op, true);
+ continue;
+ }
+ }
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
}
- }
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
- else {
EDBM_update_generic(em, true, true);
EDBM_selectmode_flush(em);
- return OPERATOR_FINISHED;
}
+
+ MEM_freeN(objects);
+ return OPERATOR_FINISHED;
}
void MESH_OT_convex_hull(wmOperatorType *ot)
@@ -5964,30 +6716,41 @@ void MESH_OT_convex_hull(wmOperatorType *ot)
static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMOperator bmop;
-
const float thresh = RNA_float_get(op->ptr, "threshold");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- EDBM_op_init(
- em, &bmop, op,
- "symmetrize input=%hvef direction=%i dist=%f",
- BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh);
- BMO_op_exec(em->bm, &bmop);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ if (em->bm->totvertsel == 0 ) {
+ continue;
+ }
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
+ BMOperator bmop;
+ EDBM_op_init(
+ em, &bmop, op,
+ "symmetrize input=%hvef direction=%i dist=%f",
+ BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh);
+ BMO_op_exec(em->bm, &bmop);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
- }
- else {
- EDBM_update_generic(em, true, true);
- EDBM_selectmode_flush(em);
- return OPERATOR_FINISHED;
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
+ else {
+ EDBM_update_generic(em, true, true);
+ EDBM_selectmode_flush(em);
+ }
}
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
}
void MESH_OT_symmetrize(struct wmOperatorType *ot)
@@ -6022,103 +6785,114 @@ static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
{
const float eps = 0.00001f;
const float eps_sq = eps * eps;
-
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- int *index = MEM_mallocN(bm->totvert * sizeof(*index), __func__);
const bool use_topology = false;
const float thresh = RNA_float_get(op->ptr, "threshold");
const float fac = RNA_float_get(op->ptr, "factor");
const bool use_center = RNA_boolean_get(op->ptr, "use_center");
+ const int axis_dir = RNA_enum_get(op->ptr, "direction");
- /* stats */
- int totmirr = 0, totfail = 0, totfound = 0;
+ /* Vertices stats (total over all selected objects). */
+ int totvertfound = 0, totvertmirr = 0, totvertfail = 0;
- /* axix */
- const int axis_dir = RNA_enum_get(op->ptr, "direction");
+ /* Axis. */
int axis = axis_dir % 3;
bool axis_sign = axis != axis_dir;
- /* vertex iter */
- BMIter iter;
- BMVert *v;
- int i;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, use_topology, thresh, index);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- BM_mesh_elem_table_ensure(bm, BM_VERT);
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+ /* Only allocate memory after checking whether to skip object. */
+ int *index = MEM_mallocN(bm->totvert * sizeof(*index), __func__);
+ /* Vertex iter. */
+ BMIter iter;
+ BMVert *v;
+ int i;
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- if ((BM_elem_flag_test(v, BM_ELEM_SELECT) != false) &&
- (BM_elem_flag_test(v, BM_ELEM_TAG) == false))
- {
- int i_mirr = index[i];
- if (i_mirr != -1) {
+ EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, use_topology, thresh, index);
- BMVert *v_mirr = BM_vert_at_index(bm, index[i]);
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
- if (v != v_mirr) {
- float co[3], co_mirr[3];
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
- if ((v->co[axis] > v_mirr->co[axis]) == axis_sign) {
- SWAP(BMVert *, v, v_mirr);
- }
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if ((BM_elem_flag_test(v, BM_ELEM_SELECT) != false) &&
+ (BM_elem_flag_test(v, BM_ELEM_TAG) == false))
+ {
+ int i_mirr = index[i];
+ if (i_mirr != -1) {
- copy_v3_v3(co_mirr, v_mirr->co);
- co_mirr[axis] *= -1.0f;
+ BMVert *v_mirr = BM_vert_at_index(bm, index[i]);
- if (len_squared_v3v3(v->co, co_mirr) > eps_sq) {
- totmirr++;
- }
+ if (v != v_mirr) {
+ float co[3], co_mirr[3];
- interp_v3_v3v3(co, v->co, co_mirr, fac);
+ if ((v->co[axis] > v_mirr->co[axis]) == axis_sign) {
+ SWAP(BMVert *, v, v_mirr);
+ }
- copy_v3_v3(v->co, co);
+ copy_v3_v3(co_mirr, v_mirr->co);
+ co_mirr[axis] *= -1.0f;
- co[axis] *= -1.0f;
- copy_v3_v3(v_mirr->co, co);
+ if (len_squared_v3v3(v->co, co_mirr) > eps_sq) {
+ totvertmirr++;
+ }
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- BM_elem_flag_enable(v_mirr, BM_ELEM_TAG);
- totfound++;
- }
- else {
- if (use_center) {
+ interp_v3_v3v3(co, v->co, co_mirr, fac);
- if (fabsf(v->co[axis]) > eps) {
- totmirr++;
- }
+ copy_v3_v3(v->co, co);
- v->co[axis] = 0.0f;
+ co[axis] *= -1.0f;
+ copy_v3_v3(v_mirr->co, co);
+
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ BM_elem_flag_enable(v_mirr, BM_ELEM_TAG);
+ totvertfound++;
+ }
+ else {
+ if (use_center) {
+
+ if (fabsf(v->co[axis]) > eps) {
+ totvertmirr++;
+ }
+
+ v->co[axis] = 0.0f;
+ }
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ totvertfound++;
}
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- totfound++;
}
- }
- else {
- totfail++;
+ else {
+ totvertfail++;
+ }
}
}
- }
+ /* No need to end cache, just free the array. */
+ MEM_freeN(index);
+ }
+ MEM_freeN(objects);
- if (totfail) {
+ if (totvertfail) {
BKE_reportf(op->reports, RPT_WARNING, "%d already symmetrical, %d pairs mirrored, %d failed",
- totfound - totmirr, totmirr, totfail);
+ totvertfound - totvertmirr, totvertmirr, totvertfail);
}
else {
BKE_reportf(op->reports, RPT_INFO, "%d already symmetrical, %d pairs mirrored",
- totfound - totmirr, totmirr);
+ totvertfound - totvertmirr, totvertmirr);
}
- /* no need to end cache, just free the array */
- MEM_freeN(index);
-
return OPERATOR_FINISHED;
}
@@ -6157,45 +6931,53 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = (Mesh *)obedit->data;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMEdge *eed;
BMIter iter;
FreestyleEdge *fed;
const bool clear = RNA_boolean_get(op->ptr, "clear");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- if (em == NULL)
- return OPERATOR_FINISHED;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* auto-enable Freestyle edge mark drawing */
- if (clear == 0) {
- me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
- }
+ if (em == NULL) {
+ continue;
+ }
- if (!CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
- BM_data_layer_add(em->bm, &em->bm->edata, CD_FREESTYLE_EDGE);
- }
+ BMesh *bm = em->bm;
- if (clear) {
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
- fed->flag &= ~FREESTYLE_EDGE_MARK;
+ if (bm->totedgesel == 0) {
+ continue;
+ }
+
+ if (!CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
+ BM_data_layer_add(em->bm, &em->bm->edata, CD_FREESTYLE_EDGE);
+ }
+
+ if (clear) {
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
+ fed->flag &= ~FREESTYLE_EDGE_MARK;
+ }
}
}
- }
- else {
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
- fed->flag |= FREESTYLE_EDGE_MARK;
+ else {
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ fed = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
+ fed->flag |= FREESTYLE_EDGE_MARK;
+ }
}
}
- }
- DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -6217,7 +6999,7 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/** \} */
@@ -6228,44 +7010,51 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = (Mesh *)obedit->data;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter;
FreestyleFace *ffa;
const bool clear = RNA_boolean_get(op->ptr, "clear");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- if (em == NULL) return OPERATOR_FINISHED;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* auto-enable Freestyle face mark drawing */
- if (!clear) {
- me->drawflag |= ME_DRAW_FREESTYLE_FACE;
- }
+ if (em == NULL) {
+ continue;
+ }
- if (!CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE)) {
- BM_data_layer_add(em->bm, &em->bm->pdata, CD_FREESTYLE_FACE);
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+
+ if (!CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE)) {
+ BM_data_layer_add(em->bm, &em->bm->pdata, CD_FREESTYLE_FACE);
+ }
- if (clear) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
- ffa->flag &= ~FREESTYLE_FACE_MARK;
+ if (clear) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
+ ffa->flag &= ~FREESTYLE_FACE_MARK;
+ }
}
}
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
- ffa->flag |= FREESTYLE_FACE_MARK;
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ ffa = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
+ ffa->flag |= FREESTYLE_FACE_MARK;
+ }
}
}
- }
- DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DEG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -6287,9 +7076,1323 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/** \} */
#endif /* WITH_FREESTYLE */
+
+/********************** Loop normals editing tools modal map. **********************/
+
+/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
+/* NOTE: We could add more here, like e.g. a switch between local or global coordinates of target,
+ * use numinput to type in explicit vector values... */
+enum {
+ /* Generic commands. */
+ EDBM_CLNOR_MODAL_CANCEL = 1,
+ EDBM_CLNOR_MODAL_CONFIRM = 2,
+
+ /* Point To operator. */
+ EDBM_CLNOR_MODAL_POINTTO_RESET = 101,
+ EDBM_CLNOR_MODAL_POINTTO_INVERT = 102,
+ EDBM_CLNOR_MODAL_POINTTO_SPHERIZE = 103,
+ EDBM_CLNOR_MODAL_POINTTO_ALIGN = 104,
+
+ EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE = 110,
+ EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT = 111,
+ EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT = 112,
+ EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR = 113,
+ EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED = 114,
+};
+
+/* called in transform_ops.c, on each regeneration of keymaps */
+wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf)
+{
+ static const EnumPropertyItem modal_items[] = {
+ {EDBM_CLNOR_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {EDBM_CLNOR_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
+
+ /* Point To operator. */
+ {EDBM_CLNOR_MODAL_POINTTO_RESET, "RESET", 0, "Reset", "Reset normals to initial ones"},
+ {EDBM_CLNOR_MODAL_POINTTO_INVERT, "INVERT", 0, "Invert", "Toggle inversion of affected normals"},
+ {EDBM_CLNOR_MODAL_POINTTO_SPHERIZE, "SPHERIZE", 0, "Spherize", "Interpolate between new and original normals"},
+ {EDBM_CLNOR_MODAL_POINTTO_ALIGN, "ALIGN", 0, "Align", "Make all affected normals parallel"},
+
+ {EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE, "USE_MOUSE", 0, "Use Mouse", "Follow mouse cursor position"},
+ {EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT, "USE_PIVOT", 0, "Use Pivot",
+ "Use current rotation/scaling pivot point coordinates"},
+ {EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT, "USE_OBJECT", 0, "Use Object", "Use current edited object's location"},
+ {EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR, "SET_USE_3DCURSOR", 0, "Set and Use 3D Cursor",
+ "Set new 3D cursor position and use it"},
+ {EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED, "SET_USE_SELECTED", 0, "Select and Use Mesh Item",
+ "Select new active mesh element and use its location"},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static const char *keymap_name = "Custom Normals Modal Map";
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, keymap_name);
+
+ /* We only need to add map once */
+ if (keymap && keymap->modal_items)
+ return NULL;
+
+ keymap = WM_modalkeymap_add(keyconf, keymap_name, modal_items);
+
+ WM_modalkeymap_assign(keymap, "MESH_OT_point_normals");
+
+ return keymap;
+}
+
+#define CLNORS_VALID_VEC_LEN (1e-4f)
+
+/********************** 'Point to' Loop Normals **********************/
+
+enum {
+ EDBM_CLNOR_POINTTO_MODE_COORDINATES = 1,
+ EDBM_CLNOR_POINTTO_MODE_MOUSE = 2,
+};
+
+static EnumPropertyItem clnors_pointto_mode_items[] = {
+ {EDBM_CLNOR_POINTTO_MODE_COORDINATES, "COORDINATES", 0, "Coordinates",
+ "Use static coordinates (defined by various means)"},
+ {EDBM_CLNOR_POINTTO_MODE_MOUSE, "MOUSE", 0, "Mouse", "Follow mouse cursor"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* Initialize loop normal data */
+static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ BKE_editmesh_lnorspace_update(em);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
+
+ op->customdata = lnors_ed_arr;
+
+ return lnors_ed_arr->totloop;
+}
+
+static void point_normals_free(bContext *C, wmOperator *op)
+{
+ BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ op->customdata = NULL;
+ ED_area_status_text(CTX_wm_area(C), NULL);
+}
+
+static void point_normals_update_header(bContext *C, wmOperator *op)
+{
+ char header[UI_MAX_DRAW_STR];
+ char buf[UI_MAX_DRAW_STR];
+
+ char *p = buf;
+ int available_len = sizeof(buf);
+
+#define WM_MODALKEY(_id) \
+ WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p)
+
+ BLI_snprintf(header, sizeof(header), IFACE_("%s: confirm, %s: cancel, "
+ "%s: point to mouse (%s), %s: point to Pivot, "
+ "%s: point to object origin, %s: reset normals, "
+ "%s: set & point to 3D cursor, %s: select & point to mesh item, "
+ "%s: invert normals (%s), %s: spherize (%s), %s: align (%s)"),
+ WM_MODALKEY(EDBM_CLNOR_MODAL_CONFIRM), WM_MODALKEY(EDBM_CLNOR_MODAL_CANCEL),
+ WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE),
+ WM_bool_as_string(RNA_enum_get(op->ptr, "mode") == EDBM_CLNOR_POINTTO_MODE_MOUSE),
+ WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT),
+ WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_RESET), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR),
+ WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED),
+ WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_INVERT), WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")),
+ WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE),
+ WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")),
+ WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_ALIGN), WM_bool_as_string(RNA_boolean_get(op->ptr, "align")));
+
+#undef WM_MODALKEY
+
+ ED_area_status_text(CTX_wm_area(C), header);
+}
+
+/* TODO move that to generic function in BMesh? */
+static void bmesh_selected_verts_center_calc(BMesh *bm, float *r_center)
+{
+ BMVert *v;
+ BMIter viter;
+ int i = 0;
+
+ zero_v3(r_center);
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ add_v3_v3(r_center, v->co);
+ i++;
+ }
+ }
+ mul_v3_fl(r_center, 1.0f / (float)i);
+}
+
+static void point_normals_apply(bContext *C, wmOperator *op, float target[3], const bool do_reset)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
+ BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
+
+ const bool do_invert = RNA_boolean_get(op->ptr, "invert");
+ const bool do_spherize = RNA_boolean_get(op->ptr, "spherize");
+ const bool do_align = RNA_boolean_get(op->ptr, "align");
+ float center[3];
+
+ if (do_align && !do_reset) {
+ bmesh_selected_verts_center_calc(bm, center);
+ }
+
+ sub_v3_v3(target, obedit->loc); /* Move target to local coordinates. */
+
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ if (do_reset) {
+ copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ }
+ else if (do_spherize) {
+ /* Note that this is *not* real spherical interpolation. Probably good enough in this case though? */
+ const float strength = RNA_float_get(op->ptr, "spherize_strength");
+ float spherized_normal[3];
+
+ sub_v3_v3v3(spherized_normal, target, lnor_ed->loc);
+ normalize_v3(spherized_normal); /* otherwise, multiplication by strength is meaningless... */
+ mul_v3_fl(spherized_normal, strength);
+ mul_v3_v3fl(lnor_ed->nloc, lnor_ed->niloc, 1.0f - strength);
+ add_v3_v3(lnor_ed->nloc, spherized_normal);
+ }
+ else if (do_align) {
+ sub_v3_v3v3(lnor_ed->nloc, target, center);
+ }
+ else {
+ sub_v3_v3v3(lnor_ed->nloc, target, lnor_ed->loc);
+ }
+
+ if (do_invert && !do_reset) {
+ negate_v3(lnor_ed->nloc);
+ }
+ if (normalize_v3(lnor_ed->nloc) >= CLNORS_VALID_VEC_LEN) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
+ }
+ }
+}
+
+static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ float target[3];
+
+ int ret = OPERATOR_PASS_THROUGH;
+ int mode = RNA_enum_get(op->ptr, "mode");
+ int new_mode = mode;
+ bool force_mousemove = false;
+ bool do_reset = false;
+
+ PropertyRNA *prop_target = RNA_struct_find_property(op->ptr, "target_location");
+
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EDBM_CLNOR_MODAL_CONFIRM:
+ RNA_property_float_get_array(op->ptr, prop_target, target);
+ ret = OPERATOR_FINISHED;
+ break;
+
+ case EDBM_CLNOR_MODAL_CANCEL:
+ do_reset = true;
+ ret = OPERATOR_CANCELLED;
+ break;
+
+ case EDBM_CLNOR_MODAL_POINTTO_RESET:
+ do_reset = true;
+ ret = OPERATOR_RUNNING_MODAL;
+ break;
+
+ case EDBM_CLNOR_MODAL_POINTTO_INVERT:
+ {
+ PropertyRNA *prop_invert = RNA_struct_find_property(op->ptr, "invert");
+ RNA_property_boolean_set(op->ptr, prop_invert, !RNA_property_boolean_get(op->ptr, prop_invert));
+ RNA_property_float_get_array(op->ptr, prop_target, target);
+ ret = OPERATOR_RUNNING_MODAL;
+ break;
+ }
+
+ case EDBM_CLNOR_MODAL_POINTTO_SPHERIZE:
+ {
+ PropertyRNA *prop_spherize = RNA_struct_find_property(op->ptr, "spherize");
+ RNA_property_boolean_set(op->ptr, prop_spherize, !RNA_property_boolean_get(op->ptr, prop_spherize));
+ RNA_property_float_get_array(op->ptr, prop_target, target);
+ ret = OPERATOR_RUNNING_MODAL;
+ break;
+ }
+
+ case EDBM_CLNOR_MODAL_POINTTO_ALIGN:
+ {
+ PropertyRNA *prop_align = RNA_struct_find_property(op->ptr, "align");
+ RNA_property_boolean_set(op->ptr, prop_align, !RNA_property_boolean_get(op->ptr, prop_align));
+ RNA_property_float_get_array(op->ptr, prop_target, target);
+ ret = OPERATOR_RUNNING_MODAL;
+ break;
+ }
+
+ case EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE:
+ new_mode = EDBM_CLNOR_POINTTO_MODE_MOUSE;
+ force_mousemove = true; /* We want to immediately update to mouse cursor position... */
+ ret = OPERATOR_RUNNING_MODAL;
+ break;
+
+ case EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT:
+ new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES;
+ copy_v3_v3(target, obedit->loc);
+ ret = OPERATOR_RUNNING_MODAL;
+ break;
+
+ case EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR:
+ new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES;
+ ED_view3d_cursor3d_update(C, event->mval, false, V3D_CURSOR_ORIENT_NONE);
+ copy_v3_v3(target, scene->cursor.location);
+ ret = OPERATOR_RUNNING_MODAL;
+ break;
+
+ case EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED:
+ new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES;
+ view3d_operator_needs_opengl(C);
+ if (EDBM_select_pick(C, event->mval, false, false, false)) {
+ ED_object_editmode_calc_active_center(obedit, false, target); /* Point to newly selected active. */
+ add_v3_v3(target, obedit->loc);
+ ret = OPERATOR_RUNNING_MODAL;
+ }
+ break;
+
+ case EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT:
+ new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES;
+ switch (scene->toolsettings->transform_pivot_point) {
+ case V3D_AROUND_CENTER_BOUNDS: /* calculateCenterBound */
+ {
+ BMVert *v;
+ BMIter viter;
+ float min[3], max[3];
+ int i = 0;
+
+ BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ if (i) {
+ minmax_v3v3_v3(min, max, v->co);
+ }
+ else {
+ copy_v3_v3(min, v->co);
+ copy_v3_v3(max, v->co);
+ }
+ i++;
+ }
+ }
+ mid_v3_v3v3(target, min, max);
+ add_v3_v3(target, obedit->loc);
+ break;
+ }
+
+ case V3D_AROUND_CENTER_MEAN:
+ {
+ bmesh_selected_verts_center_calc(bm, target);
+ add_v3_v3(target, obedit->loc);
+ break;
+ }
+
+ case V3D_AROUND_CURSOR:
+ copy_v3_v3(target, scene->cursor.location);
+ break;
+
+ case V3D_AROUND_ACTIVE:
+ if (!ED_object_editmode_calc_active_center(obedit, false, target)) {
+ zero_v3(target);
+ }
+ add_v3_v3(target, obedit->loc);
+ break;
+
+ default:
+ BKE_report(op->reports, RPT_WARNING, "Does not support Individual Origin as pivot");
+ copy_v3_v3(target, obedit->loc);
+ }
+ ret = OPERATOR_RUNNING_MODAL;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (new_mode != mode) {
+ mode = new_mode;
+ RNA_enum_set(op->ptr, "mode", mode);
+ }
+
+ /* Only handle mousemove event in case we are in mouse mode. */
+ if (event->type == MOUSEMOVE || force_mousemove) {
+ if (mode == EDBM_CLNOR_POINTTO_MODE_MOUSE) {
+ ARegion *ar = CTX_wm_region(C);
+ float center[3];
+
+ bmesh_selected_verts_center_calc(bm, center);
+
+ ED_view3d_win_to_3d_int(v3d, ar, center, event->mval, target);
+
+ ret = OPERATOR_RUNNING_MODAL;
+ }
+ }
+
+ if (ret != OPERATOR_PASS_THROUGH) {
+ if (!ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) {
+ RNA_property_float_set_array(op->ptr, prop_target, target);
+ }
+ point_normals_apply(C, op, target, do_reset);
+ EDBM_update_generic(em, true, false); /* Recheck bools. */
+
+ point_normals_update_header(C, op);
+ }
+
+ if (ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) {
+ point_normals_free(C, op);
+ }
+
+ return ret;
+}
+
+static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!point_normals_init(C, op, event)) {
+ point_normals_free(C, op);
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_modal_handler(C, op);
+
+ point_normals_update_header(C, op);
+
+ op->flag |= OP_IS_MODAL_GRAB_CURSOR;
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int edbm_point_normals_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (!point_normals_init(C, op, NULL)) {
+ point_normals_free(C, op);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Note that 'mode' is ignored in exec case, we directly use vector stored in target_location, whatever that is. */
+
+ float target[3];
+ RNA_float_get_array(op->ptr, "target_location", target);
+
+ point_normals_apply(C, op, target, false);
+
+ EDBM_update_generic(em, true, false);
+ point_normals_free(C, op);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool point_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data))
+{
+ const char *prop_id = RNA_property_identifier(prop);
+
+ /* Only show strength option if spherize is enabled. */
+ if (STREQ(prop_id, "spherize_strength")) {
+ return (bool)RNA_boolean_get(ptr, "spherize");
+ }
+
+ /* Else, show it! */
+ return true;
+}
+
+static void edbm_point_normals_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ /* Main auto-draw call */
+ uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, NULL, '\0', false);
+}
+
+void MESH_OT_point_normals(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Point Normals to Target";
+ ot->description = "Point selected custom normals to specified Target";
+ ot->idname = "MESH_OT_point_normals";
+
+ /* api callbacks */
+ ot->exec = edbm_point_normals_exec;
+ ot->invoke = edbm_point_normals_invoke;
+ ot->modal = edbm_point_normals_modal;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+ ot->ui = edbm_point_normals_ui;
+ ot->cancel = point_normals_free;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", clnors_pointto_mode_items, EDBM_CLNOR_POINTTO_MODE_COORDINATES,
+ "Mode", "How to define coordinates to point custom normals to");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN);
+
+ RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert affected normals");
+
+ RNA_def_boolean(ot->srna, "align", false, "Align", "Make all affected normals parallel");
+
+ RNA_def_float_vector(ot->srna, "target_location", 3, NULL, -FLT_MAX, FLT_MAX,
+ "Target", "Target location to which normals will point", -1000.0f, 1000.0f);
+
+ RNA_def_boolean(ot->srna, "spherize", false,
+ "Spherize", "Interpolate between original and new normals");
+
+ RNA_def_float(ot->srna, "spherize_strength", 0.1, 0.0f, 1.0f,
+ "Spherize Strength", "Ratio of spherized normal to original normal", 0.0f, 1.0f);
+}
+
+/********************** Split/Merge Loop Normals **********************/
+
+static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
+{
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ BLI_SMALLSTACK_DECLARE(clnors, short *);
+
+ BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR);
+
+ BM_normals_loops_edges_tag(bm, false);
+
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ MLoopNorSpace *lnor_space = bm->lnor_spacearr->lspacearr[lnor_ed->loop_index];
+
+ if ((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0) {
+ LinkNode *loops = lnor_space->loops;
+ float avg_normal[3] = {0.0f, 0.0f, 0.0f};
+ short *clnors_data;
+
+ for (; loops; loops = loops->next) {
+ BMLoop *l = loops->link;
+ const int loop_index = BM_elem_index_get(l);
+
+ BMLoopNorEditData *lnor_ed_tmp = lnors_ed_arr->lidx_to_lnor_editdata[loop_index];
+ BLI_assert(lnor_ed_tmp->loop_index == loop_index && lnor_ed_tmp->loop == l);
+ add_v3_v3(avg_normal, lnor_ed_tmp->nloc);
+ BLI_SMALLSTACK_PUSH(clnors, lnor_ed_tmp->clnors_data);
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
+ }
+ if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
+ /* If avg normal is nearly 0, set clnor to default value. */
+ zero_v3(avg_normal);
+ }
+ while ((clnors_data = BLI_SMALLSTACK_POP(clnors))) {
+ BKE_lnor_space_custom_normal_to_data(lnor_space, avg_normal, clnors_data);
+ }
+ }
+ }
+}
+
+static void normals_split(BMesh *bm)
+{
+ BMFace *f;
+ BMLoop *l, *l_curr, *l_first;
+ BMIter fiter;
+
+ BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR);
+
+ BM_normals_loops_edges_tag(bm, true);
+
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
+ (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr))))
+ {
+ if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
+ const int loop_index = BM_elem_index_get(l_curr);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
+ }
+ else {
+ BMVert *v_pivot = l_curr->v;
+ UNUSED_VARS_NDEBUG(v_pivot);
+ BMEdge *e_next;
+ const BMEdge *e_org = l_curr->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+
+ lfan_pivot = l_curr;
+ e_next = lfan_pivot->e;
+ BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
+ float avg_normal[3] = { 0.0f };
+
+ while (true) {
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
+
+ BLI_SMALLSTACK_PUSH(loops, lfan_pivot);
+ add_v3_v3(avg_normal, lfan_pivot->f->no);
+
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ break;
+ }
+ lfan_pivot = lfan_pivot_next;
+ }
+ if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
+ /* If avg normal is nearly 0, set clnor to default value. */
+ zero_v3(avg_normal);
+ }
+ while ((l = BLI_SMALLSTACK_POP(loops))) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
+ }
+ }
+ }
+ } while ((l_curr = l_curr->next) != l_first);
+ }
+}
+
+static int normals_split_merge(bContext *C, const bool do_merge)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMEdge *e;
+ BMIter eiter;
+
+ BKE_editmesh_lnorspace_update(em);
+
+ BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm) : NULL;
+
+ mesh_set_smooth_faces(em, do_merge);
+
+ BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge);
+ }
+ }
+
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BKE_editmesh_lnorspace_update(em);
+
+ if (do_merge) {
+ normals_merge(bm, lnors_ed_arr);
+ }
+ else {
+ normals_split(bm);
+ }
+
+ if (lnors_ed_arr) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ }
+
+ EDBM_update_generic(em, true, false);
+
+ return OPERATOR_FINISHED;
+}
+
+static int edbm_merge_normals_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return normals_split_merge(C, true);
+}
+
+void MESH_OT_merge_normals(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Merge Normals";
+ ot->description = "Merge custom normals of selected vertices";
+ ot->idname = "MESH_OT_merge_normals";
+
+ /* api callbacks */
+ ot->exec = edbm_merge_normals_exec;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int edbm_split_normals_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return normals_split_merge(C, false);
+}
+
+void MESH_OT_split_normals(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Split Normals";
+ ot->description = "Split custom normals of selected vertices";
+ ot->idname = "MESH_OT_split_normals";
+
+ /* api callbacks */
+ ot->exec = edbm_split_normals_exec;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** Average Loop Normals **********************/
+
+enum {
+ EDBM_CLNOR_AVERAGE_LOOP = 1,
+ EDBM_CLNOR_AVERAGE_FACE_AREA = 2,
+ EDBM_CLNOR_AVERAGE_ANGLE = 3,
+};
+
+static EnumPropertyItem average_method_items[] = {
+ {EDBM_CLNOR_AVERAGE_LOOP, "CUSTOM_NORMAL", 0, "Custom Normal", "Take Average of vert Normals"},
+ {EDBM_CLNOR_AVERAGE_FACE_AREA, "FACE_AREA", 0, "Face Area", "Set all vert normals by Face Area"},
+ {EDBM_CLNOR_AVERAGE_ANGLE, "CORNER_ANGLE", 0, "Corner Angle", "Set all vert normals by Corner Angle"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int edbm_average_normals_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l, *l_curr, *l_first;
+ BMIter fiter;
+
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BKE_editmesh_lnorspace_update(em);
+
+ const int average_type = RNA_enum_get(op->ptr, "average_type");
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ const float absweight = (float) RNA_int_get(op->ptr, "weight");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+
+ float weight = absweight / 50.0f;
+ if (absweight == 100.0f) {
+ weight = (float)SHRT_MAX;
+ }
+ else if (absweight == 1.0f) {
+ weight = 1 / (float)SHRT_MAX;
+ }
+ else if ((weight - 1) * 25 > 1) {
+ weight = (weight - 1) * 25;
+ }
+
+ BM_normals_loops_edges_tag(bm, true);
+
+ HeapSimple *loop_weight = BLI_heapsimple_new();
+
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
+ (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr))))
+ {
+ if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
+ const int loop_index = BM_elem_index_get(l_curr);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
+ }
+ else {
+ BMVert *v_pivot = l_curr->v;
+ UNUSED_VARS_NDEBUG(v_pivot);
+ BMEdge *e_next;
+ const BMEdge *e_org = l_curr->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+
+ lfan_pivot = l_curr;
+ e_next = lfan_pivot->e;
+
+ while (true) {
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
+
+ float val = 1.0f;
+ if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) {
+ val = 1.0f / BM_face_calc_area(lfan_pivot->f);
+ }
+ else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) {
+ val = 1.0f / BM_loop_calc_face_angle(lfan_pivot);
+ }
+
+ BLI_heapsimple_insert(loop_weight, val, lfan_pivot);
+
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ break;
+ }
+ lfan_pivot = lfan_pivot_next;
+ }
+
+ BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
+ float wnor[3], avg_normal[3] = { 0.0f }, count = 0;
+ float val = BLI_heapsimple_top_value(loop_weight);
+
+ while (!BLI_heapsimple_is_empty(loop_weight)) {
+ const float cur_val = BLI_heapsimple_top_value(loop_weight);
+ if (!compare_ff(val, cur_val, threshold)) {
+ count++;
+ val = cur_val;
+ }
+ l = BLI_heapsimple_pop_min(loop_weight);
+ BLI_SMALLSTACK_PUSH(loops, l);
+
+ const float n_weight = pow(weight, count);
+
+ if (average_type == EDBM_CLNOR_AVERAGE_LOOP) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], clnors, wnor);
+ }
+ else {
+ copy_v3_v3(wnor, l->f->no);
+ }
+ mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight));
+ add_v3_v3(avg_normal, wnor);
+ }
+
+ if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
+ /* If avg normal is nearly 0, set clnor to default value. */
+ zero_v3(avg_normal);
+ }
+ while ((l = BLI_SMALLSTACK_POP(loops))) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
+ }
+ }
+ }
+ } while ((l_curr = l_curr->next) != l_first);
+ }
+
+ BLI_heapsimple_free(loop_weight, NULL);
+ EDBM_update_generic(em, true, false);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool average_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data))
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const int average_type = RNA_enum_get(ptr, "average_type");
+
+ /* Only show weight/threshold options in loop average type. */
+ if (STREQ(prop_id, "weight")) {
+ return (average_type == EDBM_CLNOR_AVERAGE_LOOP);
+ }
+ else if (STREQ(prop_id, "threshold")) {
+ return (average_type == EDBM_CLNOR_AVERAGE_LOOP);
+ }
+
+ /* Else, show it! */
+ return true;
+}
+
+static void edbm_average_normals_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ /* Main auto-draw call */
+ uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, NULL, '\0', false);
+}
+
+void MESH_OT_average_normals(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Average Normals";
+ ot->description = "Average custom normals of selected vertices";
+ ot->idname = "MESH_OT_average_normals";
+
+ /* api callbacks */
+ ot->exec = edbm_average_normals_exec;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+ ot->ui = edbm_average_normals_ui;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "average_type", average_method_items, EDBM_CLNOR_AVERAGE_LOOP,
+ "Type", "Averaging method");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN);
+
+ RNA_def_int(ot->srna, "weight", 50, 1, 100, "Weight", "Weight applied per face", 1, 100);
+
+ RNA_def_float(ot->srna, "threshold", 0.01f, 0, 10, "Threshold",
+ "Threshold value for different weights to be considered equal", 0, 5);
+}
+
+/********************** Custom Normal Interface Tools **********************/
+
+enum {
+ EDBM_CLNOR_TOOLS_COPY = 1,
+ EDBM_CLNOR_TOOLS_PASTE = 2,
+ EDBM_CLNOR_TOOLS_MULTIPLY = 3,
+ EDBM_CLNOR_TOOLS_ADD = 4,
+ EDBM_CLNOR_TOOLS_RESET = 5,
+};
+
+static EnumPropertyItem normal_vector_tool_items[] = {
+ {EDBM_CLNOR_TOOLS_COPY, "COPY", 0, "Copy Normal", "Copy normal to buffer"},
+ {EDBM_CLNOR_TOOLS_PASTE, "PASTE", 0, "Paste Normal", "Paste normal from buffer"},
+ {EDBM_CLNOR_TOOLS_ADD, "ADD", 0, "Add Normal", "Add normal vector with selection"},
+ {EDBM_CLNOR_TOOLS_MULTIPLY, "MULTIPLY", 0, "Multiply Normal", "Multiply normal vector with selection"},
+ {EDBM_CLNOR_TOOLS_RESET, "RESET", 0, "Reset Normal", "Reset buffer and/or normal of selected element"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ const bool absolute = RNA_boolean_get(op->ptr, "absolute");
+
+ BKE_editmesh_lnorspace_update(em);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ float *normal_vector = scene->toolsettings->normal_vector;
+
+ switch (mode) {
+ case EDBM_CLNOR_TOOLS_COPY:
+ if (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1) {
+ BKE_report(op->reports, RPT_ERROR, "Can only copy custom normal, vertex normal or face normal");
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ return OPERATOR_CANCELLED;
+ }
+ bool join = true;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) {
+ join = false;
+ }
+ }
+ if (lnors_ed_arr->totloop == 1) {
+ copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc);
+ }
+ else if (bm->totfacesel == 1) {
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ copy_v3_v3(scene->toolsettings->normal_vector, f->no);
+ }
+ }
+ }
+ else if (join) {
+ copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc);
+ }
+ break;
+
+ case EDBM_CLNOR_TOOLS_PASTE:
+ if (!absolute) {
+ if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) {
+ /* If normal is nearly 0, do nothing. */
+ break;
+ }
+ }
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ if (absolute) {
+ float abs_normal[3];
+ copy_v3_v3(abs_normal, lnor_ed->loc);
+ negate_v3(abs_normal);
+ add_v3_v3(abs_normal, normal_vector);
+
+ if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) {
+ /* If abs normal is nearly 0, set clnor to initial value. */
+ copy_v3_v3(abs_normal, lnor_ed->niloc);
+ }
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], abs_normal, lnor_ed->clnors_data);
+ }
+ else {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], normal_vector, lnor_ed->clnors_data);
+ }
+ }
+ break;
+
+ case EDBM_CLNOR_TOOLS_MULTIPLY:
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ mul_v3_v3(lnor_ed->nloc, normal_vector);
+
+ if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
+ /* If abs normal is nearly 0, set clnor to initial value. */
+ copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ }
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
+ }
+ break;
+
+ case EDBM_CLNOR_TOOLS_ADD:
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ add_v3_v3(lnor_ed->nloc, normal_vector);
+
+ if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
+ /* If abs normal is nearly 0, set clnor to initial value. */
+ copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ }
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
+ }
+ break;
+
+ case EDBM_CLNOR_TOOLS_RESET:
+ zero_v3(normal_vector);
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], normal_vector, lnor_ed->clnors_data);
+ }
+ break;
+
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+
+ EDBM_update_generic(em, true, false);
+ return OPERATOR_FINISHED;
+}
+
+static bool normals_tools_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data))
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const int mode = RNA_enum_get(ptr, "mode");
+
+ /* Only show absolute option in paste mode. */
+ if (STREQ(prop_id, "absolute")) {
+ return (mode == EDBM_CLNOR_TOOLS_PASTE);
+ }
+
+ /* Else, show it! */
+ return true;
+}
+
+static void edbm_normals_tools_ui(bContext *C, wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ /* Main auto-draw call */
+ uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, NULL, '\0', false);
+}
+
+void MESH_OT_normals_tools(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Normals Vector Tools";
+ ot->description = "Custom normals tools using Normal Vector of UI";
+ ot->idname = "MESH_OT_normals_tools";
+
+ /* api callbacks */
+ ot->exec = edbm_normals_tools_exec;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+ ot->ui = edbm_normals_tools_ui;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "mode", normal_vector_tool_items, EDBM_CLNOR_TOOLS_COPY,
+ "Mode", "Mode of tools taking input from Interface");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN);
+
+ RNA_def_boolean(ot->srna, "absolute", false, "Absolute Coordinates", "Copy Absolute coordinates or Normal vector");
+}
+
+static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMVert *v;
+ BMEdge *e;
+ BMLoop *l;
+ BMIter fiter, viter, eiter, liter;
+
+ const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp");
+
+ BKE_editmesh_lnorspace_update(em);
+
+ float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__);
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM(v, &viter, f, BM_VERTS_OF_FACE) {
+ const int v_index = BM_elem_index_get(v);
+ add_v3_v3(vnors[v_index], f->no);
+ }
+ }
+ }
+ for (int i = 0; i < bm->totvert; i++) {
+ if (!is_zero_v3(vnors[i]) && normalize_v3(vnors[i]) < CLNORS_VALID_VEC_LEN) {
+ zero_v3(vnors[i]);
+ }
+ }
+
+ BLI_bitmap *loop_set = BLI_BITMAP_NEW(bm->totloop, __func__);
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM(e, &eiter, f, BM_EDGES_OF_FACE) {
+ if (!keep_sharp || (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && BM_elem_flag_test(e, BM_ELEM_SELECT))) {
+ BM_ITER_ELEM(v, &viter, e, BM_VERTS_OF_EDGE) {
+ l = BM_face_vert_share_loop(f, v);
+ const int l_index = BM_elem_index_get(l);
+ const int v_index = BM_elem_index_get(l->v);
+
+ if (!is_zero_v3(vnors[v_index])) {
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], vnors[v_index], clnors);
+
+ if (bm->lnor_spacearr->lspacearr[l_index]->flags & MLNOR_SPACE_IS_SINGLE) {
+ BLI_BITMAP_ENABLE(loop_set, l_index);
+ }
+ else {
+ LinkNode *loops = bm->lnor_spacearr->lspacearr[l_index]->loops;
+ for (; loops; loops = loops->next) {
+ BLI_BITMAP_ENABLE(loop_set, BM_elem_index_get((BMLoop *)loops->link));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ int v_index;
+ BM_ITER_MESH_INDEX(v, &viter, bm, BM_VERTS_OF_MESH, v_index) {
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+ if (BLI_BITMAP_TEST(loop_set, BM_elem_index_get(l))) {
+ const int loop_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], clnors);
+ }
+ }
+ }
+
+ MEM_freeN(loop_set);
+ MEM_freeN(vnors);
+ EDBM_update_generic(em, true, false);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Normals From Faces";
+ ot->description = "Set the custom normals from the selected faces ones";
+ ot->idname = "MESH_OT_set_normals_from_faces";
+
+ /* api callbacks */
+ ot->exec = edbm_set_normals_from_faces_exec;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face");
+}
+
+static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+
+ BKE_editmesh_lnorspace_update(em);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
+
+ float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__);
+
+ /* This is weird choice of operation, taking all loops of faces of current vertex... Could lead to some rather
+ * far away loops weighting as much as very close ones (topologically speaking), with complex polygons.
+ * Using topological distance here (rather than geometrical one) makes sense imho, but would rather go with
+ * a more consistent and flexible code, we could even add max topological distance to take into account,
+ * and a weighting curve...
+ * Would do that later though, think for now we can live with that choice. --mont29 */
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ l = lnor_ed->loop;
+ float loop_normal[3];
+
+ BM_ITER_ELEM(f, &fiter, l->v, BM_FACES_OF_VERT) {
+ BMLoop *l_other;
+ BM_ITER_ELEM(l_other, &liter, f, BM_LOOPS_OF_FACE) {
+ const int l_index_other = BM_elem_index_get(l_other);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset);
+ BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal);
+ add_v3_v3(smooth_normal[i], loop_normal);
+ }
+ }
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ float current_normal[3];
+
+ if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
+ /* Skip in case smoothen normal is invalid... */
+ continue;
+ }
+
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal);
+
+ /* Note: again, this is not true spherical interpolation that normals would need...
+ * But it's probably good enough for now. */
+ mul_v3_fl(current_normal, 1.0f - factor);
+ mul_v3_fl(smooth_normal[i], factor);
+ add_v3_v3(current_normal, smooth_normal[i]);
+
+ if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
+ /* Skip in case smoothen normal is invalid... */
+ continue;
+ }
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data);
+ }
+
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ MEM_freeN(smooth_normal);
+
+ EDBM_update_generic(em, true, false);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_smoothen_normals(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Smoothen Normals";
+ ot->description = "Smoothen custom normals based on adjacent vertex normals";
+ ot->idname = "MESH_OT_smoothen_normals";
+
+ /* api callbacks */
+ ot->exec = edbm_smoothen_normals_exec;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor",
+ "Specifies weight of smooth vs original normal", 0.0f, 1.0f);
+}
+
+/********************** Weighted Normal Modifier Face Strength **********************/
+
+static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMIter fiter;
+
+ BM_select_history_clear(bm);
+
+ const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
+ int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
+ if (cd_prop_int_index == -1) {
+ BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id);
+ cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
+ }
+ cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
+ const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_index);
+
+ const int face_strength = scene->toolsettings->face_strength;
+ const bool set = RNA_boolean_get(op->ptr, "set");
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ if (set) {
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ *strength = face_strength;
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ if (*strength == face_strength) {
+ BM_face_select_set(bm, f, true);
+ BM_select_history_store(bm, f);
+ }
+ else {
+ BM_face_select_set(bm, f, false);
+ }
+ }
+ }
+
+ EDBM_update_generic(em, false, false);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Face Strength";
+ ot->description = "Set/Get strength of face (used in Weighted Normal modifier)";
+ ot->idname = "MESH_OT_mod_weighted_strength";
+
+ /* api callbacks */
+ ot->exec = edbm_mod_weighted_strength_exec;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set value", "Set Value of faces");
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN);
+}
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 18c383deff0..b4f3ebfe637 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -24,25 +24,31 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_key_types.h"
+#include "DNA_layer_types.h"
#include "BLI_listbase.h"
#include "BLI_array_utils.h"
#include "BLI_alloca.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
-#include "BKE_depsgraph.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_util.h"
+#include "ED_undo.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -68,6 +74,9 @@
# include "BLI_task.h"
#endif
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.mesh"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -589,6 +598,8 @@ static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh)
bm->selectmode = um->selectmode;
em->ob = ob;
+ bm->spacearr_dirty = BM_SPACEARR_DIRTY_ALL;
+
/* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
* if the active is a basis for any other. */
if (key && (key->type == KEY_RELATIVE)) {
@@ -667,80 +678,23 @@ static Object *editmesh_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
+typedef struct MeshUndoStep_Elem {
+ struct MeshUndoStep_Elem *next, *prev;
+ UndoRefID_Object obedit_ref;
+ UndoMesh data;
+} MeshUndoStep_Elem;
+
typedef struct MeshUndoStep {
UndoStep step;
- /* Use for all ID lookups (can be NULL). */
struct UndoIDPtrMap *id_map;
-
- /* note: will split out into list for multi-object-editmode. */
- UndoRefID_Object obedit_ref;
- /* Needed for MTexPoly's image use. */
- UndoRefID_Object *image_array_ref;
- UndoMesh data;
+ MeshUndoStep_Elem *elems;
+ uint elems_len;
} MeshUndoStep;
-static void mesh_undosys_step_encode_store_ids(MeshUndoStep *us)
-{
- Mesh *me = us->obedit_ref.ptr->data;
- BMesh *bm = me->edit_btmesh->bm;
- const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
- if (mtex_len != 0) {
- ID **id_prev_array = BLI_array_alloca(id_prev_array, mtex_len);
- memset(id_prev_array, 0x0, sizeof(*id_prev_array) * mtex_len);
-
- BMIter iter;
- BMFace *efa;
-
- if (us->id_map == NULL) {
- us->id_map = BKE_undosys_ID_map_create();
- }
-
- uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0);
- uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len);
- BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
- for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0;
- cd_poly_tex_offset < cd_poly_tex_offset_end;
- cd_poly_tex_offset += sizeof(MTexPoly), i++)
- {
- const MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (tf->tpage != NULL) {
- BKE_undosys_ID_map_add_with_prev(us->id_map, (ID *)tf->tpage, &id_prev_array[i]);
- }
- }
- }
- }
-}
-
-static void mesh_undosys_step_decode_restore_ids(MeshUndoStep *us)
-{
- Mesh *me = us->obedit_ref.ptr->data;
- BMesh *bm = me->edit_btmesh->bm;
- const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
- if (mtex_len != 0 && us->id_map) {
- BMIter iter;
- BMFace *efa;
-
- ID *(*id_prev_array)[2] = BLI_array_alloca(id_prev_array, mtex_len);
- memset(id_prev_array, 0x0, sizeof(*id_prev_array) * mtex_len);
-
- uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0);
- uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len);
- BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
- for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0;
- cd_poly_tex_offset < cd_poly_tex_offset_end;
- cd_poly_tex_offset += sizeof(MTexPoly), i++)
- {
- MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (tf->tpage != NULL) {
- tf->tpage = (Image *)BKE_undosys_ID_map_lookup_with_prev(us->id_map, (ID *)tf->tpage, id_prev_array[i]);
- }
- }
- }
- }
-}
-
static bool mesh_undosys_poll(bContext *C)
{
return editmesh_object_from_context(C) != NULL;
@@ -749,11 +703,24 @@ static bool mesh_undosys_poll(bContext *C)
static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
MeshUndoStep *us = (MeshUndoStep *)us_p;
- us->obedit_ref.ptr = editmesh_object_from_context(C);
- Mesh *me = us->obedit_ref.ptr->data;
- undomesh_from_editmesh(&us->data, me->edit_btmesh, me->key);
- mesh_undosys_step_encode_store_ids(us);
- us->step.data_size = us->data.undo_size;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
+ us->elems_len = objects_len;
+
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ MeshUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ Mesh *me = elem->obedit_ref.ptr->data;
+ undomesh_from_editmesh(&elem->data, me->edit_btmesh, me->key);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
@@ -764,19 +731,37 @@ static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNU
BLI_assert(mesh_undosys_poll(C));
MeshUndoStep *us = (MeshUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- Mesh *me = obedit->data;
- BMEditMesh *em = me->edit_btmesh;
- undomesh_to_editmesh(&us->data, em, obedit->data);
- mesh_undosys_step_decode_restore_ids(us);
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MeshUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ Mesh *me = obedit->data;
+ if (me->edit_btmesh == NULL) {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid",
+ us_p->name, obedit->id.name);
+ continue;
+ }
+ BMEditMesh *em = me->edit_btmesh;
+ undomesh_to_editmesh(&elem->data, em, obedit->data);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
+
+ /* The first element is always active */
+ ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
+
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
static void mesh_undosys_step_free(UndoStep *us_p)
{
MeshUndoStep *us = (MeshUndoStep *)us_p;
- undomesh_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MeshUndoStep_Elem *elem = &us->elems[i];
+ undomesh_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
if (us->id_map != NULL) {
BKE_undosys_ID_map_destroy(us->id_map);
@@ -787,7 +772,12 @@ static void mesh_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
MeshUndoStep *us = (MeshUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MeshUndoStep_Elem *elem = &us->elems[i];
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
+ }
+
if (us->id_map != NULL) {
BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 65b42571bbc..7fdef86f7e5 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -43,7 +43,6 @@
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -51,6 +50,8 @@
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
+#include "DEG_depsgraph.h"
+
#include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */
#include "WM_api.h"
@@ -172,6 +173,10 @@ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool
BKE_editmesh_tessface_calc(em);
}
+ if (em->ob) {
+ DEG_id_tag_update(&((Mesh *)em->ob->data)->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
return false;
}
else {
@@ -323,8 +328,8 @@ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
}
/**
- * \warning This can invalidate the #DerivedMesh cache of other objects (for linked duplicates).
- * Most callers should run #DAG_id_tag_update on \a ob->data, see: T46738, T46913
+ * \warning This can invalidate the #Mesh runtime cache of other objects (for linked duplicates).
+ * Most callers should run #DEG_id_tag_update on \a ob->data, see: T46738, T46913
*/
void EDBM_mesh_load(Main *bmain, Object *ob)
{
@@ -512,7 +517,6 @@ UvVertMap *BM_uv_vert_map_create(
/* vars from original func */
UvVertMap *vmap;
UvMapVert *buf;
- /* MTexPoly *tf; */ /* UNUSED */
MLoopUV *luv;
unsigned int a;
int totverts, i, totuv, totfaces;
@@ -554,7 +558,7 @@ UvVertMap *BM_uv_vert_map_create(
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- float (*tf_uv)[2];
+ float (*tf_uv)[2] = NULL;
if (use_winding) {
tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
@@ -594,7 +598,6 @@ UvVertMap *BM_uv_vert_map_create(
newvlist = v;
efa = BM_face_at_index(bm, v->poly_index);
- /* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->loop_of_poly_index);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
@@ -606,8 +609,6 @@ UvVertMap *BM_uv_vert_map_create(
while (iterv) {
next = iterv->next;
efa = BM_face_at_index(bm, iterv->poly_index);
- /* tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
-
l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->loop_of_poly_index);
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
uv2 = luv->uv;
@@ -661,7 +662,7 @@ UvElementMap *BM_uv_element_map_create(
/* vars from original func */
UvElementMap *element_map;
UvElement *buf;
- bool *winding;
+ bool *winding = NULL;
BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
MLoopUV *luv;
@@ -702,7 +703,7 @@ UvElementMap *BM_uv_element_map_create(
}
if (!selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- float (*tf_uv)[2];
+ float (*tf_uv)[2] = NULL;
if (use_winding) {
tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
@@ -926,7 +927,7 @@ UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
/* last_sel, use em->act_face otherwise get the last selected face in the editselections
* at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */
-BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected, MTexPoly **r_tf)
+BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
{
BMFace *efa = NULL;
@@ -937,11 +938,9 @@ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool se
efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
if (efa) {
- if (r_tf) *r_tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
return efa;
}
- if (r_tf) *r_tf = NULL;
return NULL;
}
@@ -950,7 +949,6 @@ bool EDBM_uv_check(BMEditMesh *em)
{
/* some of these checks could be a touch overkill */
return em && em->bm->totface &&
- CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY) &&
CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
}
@@ -1009,7 +1007,7 @@ void EDBM_verts_mirror_cache_begin_ex(
BMesh *bm = em->bm;
BMIter iter;
BMVert *v;
- int cd_vmirr_offset;
+ int cd_vmirr_offset = 0;
int i;
const float maxdist_sq = SQUARE(maxdist);
@@ -1037,7 +1035,7 @@ void EDBM_verts_mirror_cache_begin_ex(
BM_mesh_elem_index_ensure(bm, BM_VERT);
if (use_topology) {
- ED_mesh_mirrtopo_init(me, NULL, -1, &mesh_topo_store, true);
+ ED_mesh_mirrtopo_init(me, NULL, &mesh_topo_store, true);
}
else {
tree = BLI_kdtree_new(bm->totvert);
@@ -1335,7 +1333,7 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d
{
Object *ob = em->ob;
/* order of calling isn't important */
- DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ DEG_id_tag_update(ob->data, OB_RECALC_DATA);
WM_main_add_notifier(NC_GEOM | ND_DATA, ob->data);
if (do_tessface) {
@@ -1350,7 +1348,10 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d
/* in debug mode double check we didn't need to recalculate */
BLI_assert(BM_mesh_elem_table_check(em->bm) == true);
}
-
+ if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) {
+ BM_lnorspace_invalidate(em->bm, false);
+ em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET;
+ }
/* don't keep stale derivedMesh data around, see: [#38872] */
BKE_editmesh_free_derivedmesh(em);
@@ -1367,19 +1368,6 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Data Access
- * \{ */
-
-DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em)
-{
- return ((em->derivedFinal != NULL) &&
- (em->derivedFinal->type == DM_TYPE_EDITBMESH) &&
- (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Operator Helpers
* \{ */
@@ -1487,7 +1475,9 @@ static void scale_point(float c1[3], const float p[3], const float s)
add_v3_v3(c1, p);
}
-bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v3d, Object *obedit)
+bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e,
+ struct Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d, Object *obedit)
{
BMFace *f;
float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3];
@@ -1499,7 +1489,7 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v
ar->winy / 2.0f,
};
- ED_view3d_win_to_segment_clipped(ar, v3d, mval_f, origin, end, false);
+ ED_view3d_win_to_segment_clipped(depsgraph, ar, v3d, mval_f, origin, end, false);
invert_m4_m4(invmat, obedit->obmat);
mul_m4_v3(invmat, origin);
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 37d3eb22e19..fef4314019f 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -42,13 +42,12 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
+#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_report.h"
-#include "BKE_editmesh.h"
+
+#include "DEG_depsgraph.h"
#include "RNA_define.h"
@@ -245,14 +244,14 @@ void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum)
}
}
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
}
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
{
/* could be ldata or pdata */
- CustomData *pdata = GET_CD_DATA(me, pdata);
- const int layernum = CustomData_get_active_layer(pdata, CD_MTEXPOLY);
+ CustomData *ldata = GET_CD_DATA(me, ldata);
+ const int layernum = CustomData_get_active_layer(ldata, CD_MLOOPUV);
ED_mesh_uv_loop_reset_ex(me, layernum);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
@@ -269,21 +268,10 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set)
if (me->edit_btmesh) {
em = me->edit_btmesh;
- layernum_dst = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
+ layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV);
if (layernum_dst >= MAX_MTFACE)
return -1;
- /* CD_MTEXPOLY */
- BM_data_layer_add_named(em->bm, &em->bm->pdata, CD_MTEXPOLY, name);
- /* copy data from active UV */
- if (layernum_dst) {
- const int layernum_src = CustomData_get_active_layer(&em->bm->pdata, CD_MTEXPOLY);
- BM_data_layer_copy(em->bm, &em->bm->pdata, CD_MTEXPOLY, layernum_src, layernum_dst);
- }
- if (active_set || layernum_dst == 0) {
- CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum_dst);
- }
-
/* CD_MLOOPUV */
BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPUV, name);
/* copy data from active UV */
@@ -298,26 +286,22 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set)
}
}
else {
- layernum_dst = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum_dst >= MAX_MTFACE)
return -1;
- if (me->mtpoly) {
- CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DUPLICATE, me->mtpoly, me->totpoly, name);
+ if (me->mloopuv) {
CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DUPLICATE, me->mloopuv, me->totloop, name);
CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name);
is_init = true;
}
else {
- CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, name);
CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, name);
CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name);
}
if (active_set || layernum_dst == 0) {
- CustomData_set_layer_active(&me->pdata, CD_MTEXPOLY, layernum_dst);
CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum_dst);
-
CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum_dst);
}
@@ -329,7 +313,7 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set)
ED_mesh_uv_loop_reset_ex(me, layernum_dst);
}
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, me);
return layernum_dst;
@@ -343,12 +327,12 @@ void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name)
if (me->edit_btmesh) {
em = me->edit_btmesh;
- layernum_dst = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
+ layernum_dst = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPUV);
if (layernum_dst == 0)
ED_mesh_uv_texture_add(me, name, true);
}
else {
- layernum_dst = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ layernum_dst = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum_dst == 0)
ED_mesh_uv_texture_add(me, name, true);
}
@@ -357,23 +341,19 @@ void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name)
bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n)
{
- CustomData *pdata = GET_CD_DATA(me, pdata), *ldata = GET_CD_DATA(me, ldata);
- CustomDataLayer *cdlp, *cdlu;
+ CustomData *ldata = GET_CD_DATA(me, ldata);
+ CustomDataLayer *cdlu;
int index;
- index = CustomData_get_layer_index_n(pdata, CD_MTEXPOLY, n);
- cdlp = (index == -1) ? NULL : &pdata->layers[index];
-
index = CustomData_get_layer_index_n(ldata, CD_MLOOPUV, n);
cdlu = (index == -1) ? NULL : &ldata->layers[index];
- if (!cdlp || !cdlu)
+ if (!cdlu)
return false;
- delete_customdata_layer(me, cdlp);
delete_customdata_layer(me, cdlu);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, me);
return true;
@@ -381,14 +361,8 @@ bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n)
bool ED_mesh_uv_texture_remove_active(Mesh *me)
{
/* texpoly/uv are assumed to be in sync */
- CustomData *pdata = GET_CD_DATA(me, pdata);
- const int n = CustomData_get_active_layer(pdata, CD_MTEXPOLY);
-
- /* double check active layers align! */
-#ifdef DEBUG
CustomData *ldata = GET_CD_DATA(me, ldata);
- BLI_assert(CustomData_get_active_layer(ldata, CD_MLOOPUV) == n);
-#endif
+ const int n = CustomData_get_active_layer(ldata, CD_MLOOPUV);
if (n != -1) {
return ED_mesh_uv_texture_remove_index(me, n);
@@ -400,8 +374,8 @@ bool ED_mesh_uv_texture_remove_active(Mesh *me)
bool ED_mesh_uv_texture_remove_named(Mesh *me, const char *name)
{
/* texpoly/uv are assumed to be in sync */
- CustomData *pdata = GET_CD_DATA(me, pdata);
- const int n = CustomData_get_named_layer(pdata, CD_MTEXPOLY, name);
+ CustomData *ldata = GET_CD_DATA(me, ldata);
+ const int n = CustomData_get_named_layer(ldata, CD_MLOOPUV, name);
if (n != -1) {
return ED_mesh_uv_texture_remove_index(me, n);
}
@@ -458,7 +432,7 @@ int ED_mesh_color_add(Mesh *me, const char *name, const bool active_set)
BKE_mesh_update_customdata_pointers(me, true);
}
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, me);
return layernum;
@@ -473,7 +447,7 @@ bool ED_mesh_color_ensure(struct Mesh *me, const char *name)
BKE_mesh_update_customdata_pointers(me, true);
}
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
return (me->mloopcol != NULL);
}
@@ -491,7 +465,7 @@ bool ED_mesh_color_remove_index(Mesh *me, const int n)
return false;
delete_customdata_layer(me, cdl);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, me);
return true;
@@ -560,90 +534,6 @@ void MESH_OT_uv_texture_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- Base *base;
- Image *ima = NULL;
- Mesh *me;
- Object *obedit;
- int exitmode = 0;
-
- if (v3d == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No 3D View Available");
- return OPERATOR_CANCELLED;
- }
-
- base = ED_view3d_give_base_under_cursor(C, event->mval);
-
- /* Check context */
- if (base == NULL || base->object->type != OB_MESH) {
- BKE_report(op->reports, RPT_ERROR, "Not an object or mesh");
- return OPERATOR_CANCELLED;
- }
-
- ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
- if (!ima) {
- return OPERATOR_CANCELLED;
- }
- /* handled below */
- id_us_min((ID *)ima);
-
- /* put mesh in editmode */
-
- obedit = base->object;
- me = obedit->data;
- if (me->edit_btmesh == NULL) {
- EDBM_mesh_make(obedit, scene->toolsettings->selectmode, false);
- exitmode = 1;
- }
- if (me->edit_btmesh == NULL)
- return OPERATOR_CANCELLED;
-
- ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL);
-
- if (exitmode) {
- EDBM_mesh_load(bmain, obedit);
- EDBM_mesh_free(me->edit_btmesh);
- MEM_freeN(me->edit_btmesh);
- me->edit_btmesh = NULL;
-
- /* load_editMesh free's pointers used by CustomData layers which might be used by DerivedMesh too,
- * so signal to re-create DerivedMesh here (sergey) */
- DAG_id_tag_update(&me->id, 0);
- }
-
- /* dummie drop support; ensure view shows a result :) */
- if (v3d)
- v3d->flag2 |= V3D_SOLID_TEX;
-
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_drop_named_image(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Drop Image to Mesh UV Map";
- ot->description = "Assign Image to active UV Map, or create an UV Map";
- ot->idname = "MESH_OT_drop_named_image";
-
- /* api callbacks */
- ot->poll = layers_poll;
- ot->invoke = drop_named_image_invoke;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
- RNA_def_string(ot->srna, "filepath", "Path", FILE_MAX, "Filepath", "Path to image file");
- RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file");
-}
-
static int mesh_uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
@@ -751,7 +641,7 @@ static int mesh_customdata_clear_exec__internal(bContext *C,
CustomData_free_layers(data, type, tot);
}
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
return OPERATOR_FINISHED;
@@ -847,7 +737,7 @@ static int mesh_customdata_skin_add_exec(bContext *C, wmOperator *UNUSED(op))
BKE_mesh_ensure_skin_customdata(me);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
return OPERATOR_FINISHED;
@@ -906,8 +796,6 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
/* Tag edges as sharp according to smooth threshold if needed, to preserve autosmooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
BM_edges_sharp_from_angle_set(me->edit_btmesh->bm, me->smoothresh);
-
- me->drawflag |= ME_DRAWSHARP;
}
BM_data_layer_add(me->edit_btmesh->bm, data, CD_CUSTOMLOOPNORMAL);
@@ -931,14 +819,12 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
me->smoothresh);
MEM_freeN(polynors);
-
- me->drawflag |= ME_DRAWSHARP;
}
CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
}
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
return OPERATOR_FINISHED;
@@ -989,7 +875,7 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot)
/************************** Add Geometry Layers *************************/
-void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_tessface)
+void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose, bool calc_tessface)
{
bool tessface_input = false;
@@ -1000,6 +886,10 @@ void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_tessface
tessface_input = true;
}
+ if (calc_edges_loose && mesh->totedge) {
+ BKE_mesh_calc_edges_loose(mesh);
+ }
+
if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0))
BKE_mesh_calc_edges(mesh, calc_edges, true);
@@ -1015,7 +905,7 @@ void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_tessface
BKE_mesh_calc_normals(mesh);
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh);
}
@@ -1335,7 +1225,6 @@ void ED_mesh_calc_tessface(Mesh *mesh, bool free_mpoly)
mesh->mloopcol = NULL;
mesh->mloopuv = NULL;
mesh->mpoly = NULL;
- mesh->mtpoly = NULL;
}
}
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 593e6b59d85..9c70fdceb8d 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -92,6 +92,8 @@ void MESH_OT_primitive_monkey_add(struct wmOperatorType *ot);
void MESH_OT_primitive_uv_sphere_add(struct wmOperatorType *ot);
void MESH_OT_primitive_ico_sphere_add(struct wmOperatorType *ot);
+/* *** editmesh_add_gizmo.c *** */
+void MESH_OT_primitive_cube_add_gizmo(struct wmOperatorType *ot);
/* *** editmesh_bevel.c *** */
void MESH_OT_bevel(struct wmOperatorType *ot);
@@ -102,6 +104,7 @@ void MESH_OT_bisect(struct wmOperatorType *ot);
/* *** editmesh_extrude.c *** */
void MESH_OT_extrude_repeat(struct wmOperatorType *ot);
void MESH_OT_extrude_region(struct wmOperatorType *ot);
+void MESH_OT_extrude_context(struct wmOperatorType *ot);
void MESH_OT_extrude_verts_indiv(struct wmOperatorType *ot);
void MESH_OT_extrude_edges_indiv(struct wmOperatorType *ot);
void MESH_OT_extrude_faces_indiv(struct wmOperatorType *ot);
@@ -112,6 +115,15 @@ void MESH_OT_screw(struct wmOperatorType *ot);
/* *** editmesh_extrude_spin.c *** */
void MESH_OT_spin(struct wmOperatorType *ot);
+/* *** editmesh_extrude_spin_gizmo.c *** */
+void MESH_GGT_spin(struct wmGizmoGroupType *gzgt);
+void MESH_GGT_spin_redo(struct wmGizmoGroupType *gzgt);
+
+/* *** editmesh_polybuild.c *** */
+void MESH_OT_polybuild_face_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_split_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_dissolve_at_cursor(struct wmOperatorType *ot);
+void MESH_OT_polybuild_hover(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
void MESH_OT_inset(struct wmOperatorType *ot);
@@ -208,7 +220,6 @@ void MESH_OT_hide(struct wmOperatorType *ot);
void MESH_OT_reveal(struct wmOperatorType *ot);
void MESH_OT_mark_seam(struct wmOperatorType *ot);
void MESH_OT_mark_sharp(struct wmOperatorType *ot);
-void MESH_OT_noise(struct wmOperatorType *ot);
void MESH_OT_flip_normals(struct wmOperatorType *ot);
void MESH_OT_solidify(struct wmOperatorType *ot);
void MESH_OT_knife_cut(struct wmOperatorType *ot);
@@ -232,6 +243,16 @@ void MESH_OT_duplicate(struct wmOperatorType *ot);
void MESH_OT_merge(struct wmOperatorType *ot);
void MESH_OT_remove_doubles(struct wmOperatorType *ot);
void MESH_OT_poke(struct wmOperatorType *ot);
+void MESH_OT_point_normals(struct wmOperatorType *ot);
+void MESH_OT_merge_normals(struct wmOperatorType *ot);
+void MESH_OT_split_normals(struct wmOperatorType *ot);
+void MESH_OT_normals_tools(struct wmOperatorType *ot);
+void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot);
+void MESH_OT_average_normals(struct wmOperatorType *ot);
+void MESH_OT_smoothen_normals(struct wmOperatorType *ot);
+void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
+
+struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf);
#ifdef WITH_FREESTYLE
void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
@@ -249,15 +270,6 @@ void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot);
-void MESH_OT_drop_named_image(struct wmOperatorType *ot);
-
-
-/* *** mesh_navmesh.c *** */
-void MESH_OT_navmesh_make(struct wmOperatorType *ot);
-void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot);
-void MESH_OT_navmesh_face_add(struct wmOperatorType *ot);
-void MESH_OT_navmesh_reset(struct wmOperatorType *ot);
-void MESH_OT_navmesh_clear(struct wmOperatorType *ot);
#endif /* __MESH_INTERN_H__ */
diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c
index 1615ec75565..b9479a660f9 100644
--- a/source/blender/editors/mesh/mesh_mirror.c
+++ b/source/blender/editors/mesh/mesh_mirror.c
@@ -32,11 +32,12 @@
#include "BLI_bitmap.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "BKE_DerivedMesh.h"
-#include "BLI_kdtree.h"
#include "BKE_editmesh.h"
+#include "BLI_kdtree.h"
+#include "BKE_mesh.h"
#include "ED_mesh.h"
@@ -50,11 +51,11 @@ static struct { void *tree; } MirrKdStore = {NULL};
/* mode is 's' start, or 'e' end, or 'u' use */
/* if end, ob can be NULL */
-int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
+int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, Mesh *me_eval, const float co[3], char mode)
{
if (mode == 'u') { /* use table */
if (MirrKdStore.tree == NULL)
- ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
+ ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's');
if (MirrKdStore.tree) {
KDTreeNearest nearest;
@@ -70,11 +71,11 @@ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, co
}
else if (mode == 's') { /* start table */
Mesh *me = ob->data;
- const bool use_em = (!dm && em && me->edit_btmesh == em);
- const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
+ const bool use_em = (!me_eval && em && me->edit_btmesh == em);
+ const int totvert = use_em ? em->bm->totvert : me_eval ? me_eval->totvert : me->totvert;
if (MirrKdStore.tree) /* happens when entering this call without ending it */
- ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
+ ED_mesh_mirror_spatial_table(ob, em, me_eval, co, 'e');
MirrKdStore.tree = BLI_kdtree_new(totvert);
@@ -91,7 +92,7 @@ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, co
}
}
else {
- MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
+ MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
int i;
for (i = 0; i < totvert; i++, mvert++) {
@@ -141,14 +142,15 @@ static int mirrtopo_vert_sort(const void *v1, const void *v2)
return 0;
}
-bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store)
+bool ED_mesh_mirrtopo_recalc_check(Mesh *me, Mesh *me_eval, MirrTopoStore_t *mesh_topo_store)
{
+ const bool is_editmode = (me->edit_btmesh != NULL);
int totvert;
int totedge;
- if (dm) {
- totvert = dm->getNumVerts(dm);
- totedge = dm->getNumEdges(dm);
+ if (me_eval) {
+ totvert = me_eval->totvert;
+ totedge = me_eval->totedge;
}
else if (me->edit_btmesh) {
totvert = me->edit_btmesh->bm->totvert;
@@ -160,7 +162,7 @@ bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode,
}
if ((mesh_topo_store->index_lookup == NULL) ||
- (mesh_topo_store->prev_ob_mode != ob_mode) ||
+ (mesh_topo_store->prev_is_editmode != is_editmode) ||
(totvert != mesh_topo_store->prev_vert_tot) ||
(totedge != mesh_topo_store->prev_edge_tot))
{
@@ -172,11 +174,13 @@ bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode,
}
-void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
- const bool skip_em_vert_array_init)
+void ED_mesh_mirrtopo_init(
+ Mesh *me, Mesh *me_eval, MirrTopoStore_t *mesh_topo_store,
+ const bool skip_em_vert_array_init)
{
+ const bool is_editmode = (me->edit_btmesh != NULL);
MEdge *medge = NULL, *med;
- BMEditMesh *em = dm ? NULL : me->edit_btmesh;
+ BMEditMesh *em = me_eval ? NULL : me->edit_btmesh;
/* editmode*/
BMEdge *eed;
@@ -197,7 +201,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop
/* reallocate if needed */
ED_mesh_mirrtopo_free(mesh_topo_store);
- mesh_topo_store->prev_ob_mode = ob_mode;
+ mesh_topo_store->prev_is_editmode = is_editmode;
if (em) {
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
@@ -205,7 +209,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop
totvert = em->bm->totvert;
}
else {
- totvert = dm ? dm->getNumVerts(dm) : me->totvert;
+ totvert = me_eval ? me_eval->totvert : me->totvert;
}
topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
@@ -221,8 +225,8 @@ void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTop
}
}
else {
- totedge = dm ? dm->getNumEdges(dm) : me->totedge;
- medge = dm ? dm->getEdgeArray(dm) : me->medge;
+ totedge = me_eval ? me_eval->totedge : me->totedge;
+ medge = me_eval ? me_eval->medge : me->medge;
for (a = 0, med = medge; a < totedge; a++, med++) {
const unsigned int i1 = med->v1, i2 = med->v2;
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
deleted file mode 100644
index b18b6bcb7e7..00000000000
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ /dev/null
@@ -1,732 +0,0 @@
-/*
- * ***** 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) 2011 by Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Benoit Bolsee,
- * Nick Samarin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/mesh_navmesh.c
- * \ingroup edmesh
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_mesh_types.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math_vector.h"
-#include "BLI_linklist.h"
-
-#include "BKE_library.h"
-#include "BKE_depsgraph.h"
-#include "BKE_context.h"
-#include "BKE_mesh.h"
-#include "BKE_scene.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_report.h"
-#include "BKE_editmesh.h"
-
-#include "ED_object.h"
-#include "ED_mesh.h"
-#include "ED_screen.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "recast-capi.h"
-
-#include "mesh_intern.h" /* own include */
-
-
-static void createVertsTrisData(bContext *C, LinkNode *obs,
- int *nverts_r, float **verts_r, int *ntris_r, int **tris_r, unsigned int *r_lay)
-{
- MVert *mvert;
- int nfaces = 0, *tri, i, curnverts, basenverts, curnfaces;
- MFace *mface;
- float co[3], wco[3];
- Object *ob;
- LinkNode *oblink, *dmlink;
- DerivedMesh *dm;
- Scene *scene = CTX_data_scene(C);
- LinkNodePair dms_pair = {NULL, NULL};
-
- int nverts, ntris, *tris;
- float *verts;
-
- nverts = 0;
- ntris = 0;
-
- /* calculate number of verts and tris */
- for (oblink = obs; oblink; oblink = oblink->next) {
- ob = (Object *) oblink->link;
- dm = mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH);
- DM_ensure_tessface(dm);
- BLI_linklist_append(&dms_pair, dm);
-
- nverts += dm->getNumVerts(dm);
- nfaces = dm->getNumTessFaces(dm);
- ntris += nfaces;
-
- /* resolve quad faces */
- mface = dm->getTessFaceArray(dm);
- for (i = 0; i < nfaces; i++) {
- MFace *mf = &mface[i];
- if (mf->v4)
- ntris += 1;
- }
-
- *r_lay |= ob->lay;
- }
- LinkNode *dms = dms_pair.list;
-
- /* create data */
- verts = MEM_mallocN(sizeof(float) * 3 * nverts, "createVertsTrisData verts");
- tris = MEM_mallocN(sizeof(int) * 3 * ntris, "createVertsTrisData faces");
-
- basenverts = 0;
- tri = tris;
- for (oblink = obs, dmlink = dms; oblink && dmlink;
- oblink = oblink->next, dmlink = dmlink->next)
- {
- ob = (Object *) oblink->link;
- dm = (DerivedMesh *) dmlink->link;
-
- curnverts = dm->getNumVerts(dm);
- mvert = dm->getVertArray(dm);
-
- /* copy verts */
- for (i = 0; i < curnverts; i++) {
- MVert *v = &mvert[i];
-
- copy_v3_v3(co, v->co);
- mul_v3_m4v3(wco, ob->obmat, co);
-
- verts[3 * (basenverts + i) + 0] = wco[0];
- verts[3 * (basenverts + i) + 1] = wco[2];
- verts[3 * (basenverts + i) + 2] = wco[1];
- }
-
- /* create tris */
- curnfaces = dm->getNumTessFaces(dm);
- mface = dm->getTessFaceArray(dm);
-
- for (i = 0; i < curnfaces; i++) {
- MFace *mf = &mface[i];
-
- tri[0] = basenverts + mf->v1;
- tri[1] = basenverts + mf->v3;
- tri[2] = basenverts + mf->v2;
- tri += 3;
-
- if (mf->v4) {
- tri[0] = basenverts + mf->v1;
- tri[1] = basenverts + mf->v4;
- tri[2] = basenverts + mf->v3;
- tri += 3;
- }
- }
-
- basenverts += curnverts;
- }
-
- /* release derived mesh */
- for (dmlink = dms; dmlink; dmlink = dmlink->next) {
- dm = (DerivedMesh *) dmlink->link;
- dm->release(dm);
- }
-
- BLI_linklist_free(dms, NULL);
-
- *nverts_r = nverts;
- *verts_r = verts;
- *ntris_r = ntris;
- *tris_r = tris;
-}
-
-static bool buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris,
- struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh,
- ReportList *reports)
-{
- float bmin[3], bmax[3];
- struct recast_heightfield *solid;
- unsigned char *triflags;
- struct recast_compactHeightfield *chf;
- struct recast_contourSet *cset;
- int width, height, walkableHeight, walkableClimb, walkableRadius;
- int minRegionArea, mergeRegionArea, maxEdgeLen;
- float detailSampleDist, detailSampleMaxError;
-
- recast_calcBounds(verts, nverts, bmin, bmax);
-
- /* ** Step 1. Initialize build config ** */
- walkableHeight = (int)ceilf(recastParams->agentheight / recastParams->cellheight);
- walkableClimb = (int)floorf(recastParams->agentmaxclimb / recastParams->cellheight);
- walkableRadius = (int)ceilf(recastParams->agentradius / recastParams->cellsize);
- minRegionArea = (int)(recastParams->regionminsize * recastParams->regionminsize);
- mergeRegionArea = (int)(recastParams->regionmergesize * recastParams->regionmergesize);
- maxEdgeLen = (int)(recastParams->edgemaxlen / recastParams->cellsize);
- detailSampleDist = recastParams->detailsampledist < 0.9f ? 0 :
- recastParams->cellsize * recastParams->detailsampledist;
- detailSampleMaxError = recastParams->cellheight * recastParams->detailsamplemaxerror;
-
- /* Set the area where the navigation will be build. */
- recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height);
-
- /* zero dimensions cause zero alloc later on [#33758] */
- if (width <= 0 || height <= 0) {
- BKE_report(reports, RPT_ERROR, "Object has a width or height of zero");
- return false;
- }
-
- /* ** Step 2: Rasterize input polygon soup ** */
- /* Allocate voxel heightfield where we rasterize our input data to */
- solid = recast_newHeightfield();
-
- if (!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) {
- recast_destroyHeightfield(solid);
- BKE_report(reports, RPT_ERROR, "Failed to create height field");
- return false;
- }
-
- /* Allocate array that can hold triangle flags */
- triflags = MEM_callocN(sizeof(unsigned char) * ntris, "buildNavMesh triflags");
-
- /* Find triangles which are walkable based on their slope and rasterize them */
- recast_markWalkableTriangles(RAD2DEGF(recastParams->agentmaxslope), verts, nverts, tris, ntris, triflags);
- recast_rasterizeTriangles(verts, nverts, tris, triflags, ntris, solid, 1);
- MEM_freeN(triflags);
-
- /* ** Step 3: Filter walkables surfaces ** */
- recast_filterLowHangingWalkableObstacles(walkableClimb, solid);
- recast_filterLedgeSpans(walkableHeight, walkableClimb, solid);
- recast_filterWalkableLowHeightSpans(walkableHeight, solid);
-
- /* ** Step 4: Partition walkable surface to simple regions ** */
-
- chf = recast_newCompactHeightfield();
- if (!recast_buildCompactHeightfield(walkableHeight, walkableClimb, solid, chf)) {
- recast_destroyHeightfield(solid);
- recast_destroyCompactHeightfield(chf);
-
- BKE_report(reports, RPT_ERROR, "Failed to create compact height field");
- return false;
- }
-
- recast_destroyHeightfield(solid);
- solid = NULL;
-
- if (!recast_erodeWalkableArea(walkableRadius, chf)) {
- recast_destroyCompactHeightfield(chf);
-
- BKE_report(reports, RPT_ERROR, "Failed to erode walkable area");
- return false;
- }
-
- if (recastParams->partitioning == RC_PARTITION_WATERSHED) {
- /* Prepare for region partitioning, by calculating distance field along the walkable surface */
- if (!recast_buildDistanceField(chf)) {
- recast_destroyCompactHeightfield(chf);
-
- BKE_report(reports, RPT_ERROR, "Failed to build distance field");
- return false;
- }
-
- /* Partition the walkable surface into simple regions without holes */
- if (!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
- recast_destroyCompactHeightfield(chf);
-
- BKE_report(reports, RPT_ERROR, "Failed to build watershed regions");
- return false;
- }
- }
- else if (recastParams->partitioning == RC_PARTITION_MONOTONE) {
- /* Partition the walkable surface into simple regions without holes */
- /* Monotone partitioning does not need distancefield. */
- if (!recast_buildRegionsMonotone(chf, 0, minRegionArea, mergeRegionArea)) {
- recast_destroyCompactHeightfield(chf);
-
- BKE_report(reports, RPT_ERROR, "Failed to build monotone regions");
- return false;
- }
- }
- else { /* RC_PARTITION_LAYERS */
- /* Partition the walkable surface into simple regions without holes */
- if (!recast_buildLayerRegions(chf, 0, minRegionArea)) {
- recast_destroyCompactHeightfield(chf);
-
- BKE_report(reports, RPT_ERROR, "Failed to build layer regions");
- return false;
- }
- }
-
- /* ** Step 5: Trace and simplify region contours ** */
- /* Create contours */
- cset = recast_newContourSet();
-
- if (!recast_buildContours(chf, recastParams->edgemaxerror, maxEdgeLen, cset, RECAST_CONTOUR_TESS_WALL_EDGES)) {
- recast_destroyCompactHeightfield(chf);
- recast_destroyContourSet(cset);
-
- BKE_report(reports, RPT_ERROR, "Failed to build contours");
- return false;
- }
-
- /* ** Step 6: Build polygons mesh from contours ** */
- *pmesh = recast_newPolyMesh();
- if (!recast_buildPolyMesh(cset, recastParams->vertsperpoly, *pmesh)) {
- recast_destroyCompactHeightfield(chf);
- recast_destroyContourSet(cset);
- recast_destroyPolyMesh(*pmesh);
-
- BKE_report(reports, RPT_ERROR, "Failed to build poly mesh");
- return false;
- }
-
-
- /* ** Step 7: Create detail mesh which allows to access approximate height on each polygon ** */
-
- *dmesh = recast_newPolyMeshDetail();
- if (!recast_buildPolyMeshDetail(*pmesh, chf, detailSampleDist, detailSampleMaxError, *dmesh)) {
- recast_destroyCompactHeightfield(chf);
- recast_destroyContourSet(cset);
- recast_destroyPolyMesh(*pmesh);
- recast_destroyPolyMeshDetail(*dmesh);
-
- BKE_report(reports, RPT_ERROR, "Failed to build poly mesh detail");
- return false;
- }
-
- recast_destroyCompactHeightfield(chf);
- recast_destroyContourSet(cset);
-
- return true;
-}
-
-static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh,
- Base *base, unsigned int lay)
-{
- float co[3], rot[3];
- BMEditMesh *em;
- int i, j, k;
- unsigned short *v;
- int face[3];
- Scene *scene = CTX_data_scene(C);
- Object *obedit;
- int createob = base == NULL;
- int nverts, nmeshes, nvp;
- unsigned short *verts, *polys;
- unsigned int *meshes;
- float bmin[3], cs, ch, *dverts;
- unsigned char *tris;
-
- zero_v3(co);
- zero_v3(rot);
-
- if (createob) {
- /* create new object */
- obedit = ED_object_add_type(C, OB_MESH, "Navmesh", co, rot, false, lay);
- }
- else {
- obedit = base->object;
- BKE_scene_base_deselect_all(scene);
- BKE_scene_base_select(scene, base);
- copy_v3_v3(obedit->loc, co);
- copy_v3_v3(obedit->rot, rot);
- }
-
- ED_object_editmode_enter(C, EM_IGNORE_LAYER);
- em = BKE_editmesh_from_object(obedit);
-
- if (!createob) {
- /* clear */
- EDBM_mesh_clear(em);
- }
-
- /* create verts for polygon mesh */
- verts = recast_polyMeshGetVerts(pmesh, &nverts);
- recast_polyMeshGetBoundbox(pmesh, bmin, NULL);
- recast_polyMeshGetCell(pmesh, &cs, &ch);
-
- for (i = 0; i < nverts; i++) {
- v = &verts[3 * i];
- co[0] = bmin[0] + v[0] * cs;
- co[1] = bmin[1] + v[1] * ch;
- co[2] = bmin[2] + v[2] * cs;
- SWAP(float, co[1], co[2]);
- BM_vert_create(em->bm, co, NULL, BM_CREATE_NOP);
- }
-
- /* create custom data layer to save polygon idx */
- CustomData_add_layer_named(&em->bm->pdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData");
- CustomData_bmesh_init_pool(&em->bm->pdata, 0, BM_FACE);
-
- /* create verts and faces for detailed mesh */
- meshes = recast_polyMeshDetailGetMeshes(dmesh, &nmeshes);
- polys = recast_polyMeshGetPolys(pmesh, NULL, &nvp);
- dverts = recast_polyMeshDetailGetVerts(dmesh, NULL);
- tris = recast_polyMeshDetailGetTris(dmesh, NULL);
-
- for (i = 0; i < nmeshes; i++) {
- int uniquevbase = em->bm->totvert;
- unsigned int vbase = meshes[4 * i + 0];
- unsigned short ndv = meshes[4 * i + 1];
- unsigned short tribase = meshes[4 * i + 2];
- unsigned short trinum = meshes[4 * i + 3];
- const unsigned short *p = &polys[i * nvp * 2];
- int nv = 0;
-
- for (j = 0; j < nvp; ++j) {
- if (p[j] == 0xffff) break;
- nv++;
- }
-
- /* create unique verts */
- for (j = nv; j < ndv; j++) {
- copy_v3_v3(co, &dverts[3 * (vbase + j)]);
- SWAP(float, co[1], co[2]);
- BM_vert_create(em->bm, co, NULL, BM_CREATE_NOP);
- }
-
- /* need to rebuild entirely because array size changes */
- BM_mesh_elem_table_init(em->bm, BM_VERT);
-
- /* create faces */
- for (j = 0; j < trinum; j++) {
- unsigned char *tri = &tris[4 * (tribase + j)];
- BMFace *newFace;
- int *polygonIdx;
-
- for (k = 0; k < 3; k++) {
- if (tri[k] < nv)
- face[k] = p[tri[k]]; /* shared vertex */
- else
- face[k] = uniquevbase + tri[k] - nv; /* unique vertex */
- }
- newFace = BM_face_create_quad_tri(em->bm,
- BM_vert_at_index(em->bm, face[0]),
- BM_vert_at_index(em->bm, face[2]),
- BM_vert_at_index(em->bm, face[1]), NULL,
- NULL, BM_CREATE_NOP);
-
- /* set navigation polygon idx to the custom layer */
- polygonIdx = (int *)CustomData_bmesh_get(&em->bm->pdata, newFace->head.data, CD_RECAST);
- *polygonIdx = i + 1; /* add 1 to avoid zero idx */
- }
- }
-
- recast_destroyPolyMesh(pmesh);
- recast_destroyPolyMeshDetail(dmesh);
-
- DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
-
- ED_object_editmode_exit(C, EM_FREEDATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
-
- if (createob) {
- obedit->gameflag &= ~OB_COLLISION;
- obedit->gameflag |= OB_NAVMESH;
- obedit->body_type = OB_BODY_TYPE_NAVMESH;
- }
-
- BKE_mesh_ensure_navmesh(obedit->data);
-
- return obedit;
-}
-
-static int navmesh_create_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- LinkNode *obs = NULL;
- Base *navmeshBase = NULL;
-
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
- {
- if (base->object->type == OB_MESH) {
- if (base->object->body_type == OB_BODY_TYPE_NAVMESH) {
- if (!navmeshBase || base == scene->basact) {
- navmeshBase = base;
- }
- }
- else {
- BLI_linklist_prepend(&obs, base->object);
- }
- }
- }
- CTX_DATA_END;
-
- if (obs) {
- struct recast_polyMesh *pmesh = NULL;
- struct recast_polyMeshDetail *dmesh = NULL;
- bool ok;
- unsigned int lay = 0;
-
- int nverts = 0, ntris = 0;
- int *tris = NULL;
- float *verts = NULL;
-
- createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris, &lay);
- BLI_linklist_free(obs, NULL);
- if ((ok = buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh, op->reports))) {
- createRepresentation(C, pmesh, dmesh, navmeshBase, lay);
- }
-
- MEM_freeN(verts);
- MEM_freeN(tris);
-
- return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "No mesh objects found");
-
- return OPERATOR_CANCELLED;
- }
-}
-
-void MESH_OT_navmesh_make(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Create Navigation Mesh";
- ot->description = "Create navigation mesh for selected objects";
- ot->idname = "MESH_OT_navmesh_make";
-
- /* api callbacks */
- ot->exec = navmesh_create_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int navmesh_face_copy_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- /* do work here */
- BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, false);
-
- if (efa_act) {
- if (CustomData_has_layer(&em->bm->pdata, CD_RECAST)) {
- BMFace *efa;
- BMIter iter;
- int targetPolyIdx = *(int *)CustomData_bmesh_get(&em->bm->pdata, efa_act->head.data, CD_RECAST);
- targetPolyIdx = targetPolyIdx >= 0 ? targetPolyIdx : -targetPolyIdx;
-
- if (targetPolyIdx > 0) {
- /* set target poly idx to other selected faces */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && efa != efa_act) {
- int *recastDataBlock = (int *)CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_RECAST);
- *recastDataBlock = targetPolyIdx;
- }
- }
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "Active face has no index set");
- }
- }
- }
-
- DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "NavMesh Copy Face Index";
- ot->description = "Copy the index from the active face";
- ot->idname = "MESH_OT_navmesh_face_copy";
-
- /* api callbacks */
- ot->poll = ED_operator_editmesh;
- ot->exec = navmesh_face_copy_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int compare(const void *a, const void *b)
-{
- return (*(int *)a - *(int *)b);
-}
-
-static int findFreeNavPolyIndex(BMEditMesh *em)
-{
- /* construct vector of indices */
- int numfaces = em->bm->totface;
- int *indices = MEM_callocN(sizeof(int) * numfaces, "findFreeNavPolyIndex(indices)");
- BMFace *ef;
- BMIter iter;
- int i, idx = em->bm->totface - 1, freeIdx = 1;
-
- /*XXX this originally went last to first, but that isn't possible anymore*/
- BM_ITER_MESH (ef, &iter, em->bm, BM_FACES_OF_MESH) {
- int polyIdx = *(int *)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST);
- indices[idx] = polyIdx;
- idx--;
- }
-
- qsort(indices, numfaces, sizeof(int), compare);
-
- /* search first free index */
- freeIdx = 1;
- for (i = 0; i < numfaces; i++) {
- if (indices[i] == freeIdx)
- freeIdx++;
- else if (indices[i] > freeIdx)
- break;
- }
-
- MEM_freeN(indices);
-
- return freeIdx;
-}
-
-static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *ef;
- BMIter iter;
-
- if (CustomData_has_layer(&em->bm->pdata, CD_RECAST)) {
- int targetPolyIdx = findFreeNavPolyIndex(em);
-
- if (targetPolyIdx > 0) {
- /* set target poly idx to selected faces */
- /*XXX this originally went last to first, but that isn't possible anymore*/
-
- BM_ITER_MESH (ef, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(ef, BM_ELEM_SELECT)) {
- int *recastDataBlock = (int *)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST);
- *recastDataBlock = targetPolyIdx;
- }
- }
- }
- }
-
- DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_navmesh_face_add(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "NavMesh New Face Index";
- ot->description = "Add a new index and assign it to selected faces";
- ot->idname = "MESH_OT_navmesh_face_add";
-
- /* api callbacks */
- ot->poll = ED_operator_editmesh;
- ot->exec = navmesh_face_add_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static bool navmesh_obmode_data_poll(bContext *C)
-{
- Object *ob = ED_object_active_context(C);
- if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
- Mesh *me = ob->data;
- return CustomData_has_layer(&me->pdata, CD_RECAST);
- }
- return false;
-}
-
-static bool navmesh_obmode_poll(bContext *C)
-{
- Object *ob = ED_object_active_context(C);
- if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
- return true;
- }
- return false;
-}
-
-static int navmesh_reset_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_object_active_context(C);
- Mesh *me = ob->data;
-
- CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly);
-
- BKE_mesh_ensure_navmesh(me);
-
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, &me->id);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_navmesh_reset(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "NavMesh Reset Index Values";
- ot->description = "Assign a new index to every face";
- ot->idname = "MESH_OT_navmesh_reset";
-
- /* api callbacks */
- ot->poll = navmesh_obmode_poll;
- ot->exec = navmesh_reset_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_object_active_context(C);
- Mesh *me = ob->data;
-
- CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly);
-
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, &me->id);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_navmesh_clear(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "NavMesh Clear Data";
- ot->description = "Remove navmesh data from this mesh";
- ot->idname = "MESH_OT_navmesh_clear";
-
- /* api callbacks */
- ot->poll = navmesh_obmode_data_poll;
- ot->exec = navmesh_clear_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index f3f7338716c..a517f41d1fe 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -40,6 +40,7 @@
#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "mesh_intern.h" /* own include */
@@ -77,12 +78,16 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_primitive_monkey_add);
WM_operatortype_append(MESH_OT_primitive_uv_sphere_add);
WM_operatortype_append(MESH_OT_primitive_ico_sphere_add);
+
+ WM_operatortype_append(MESH_OT_primitive_cube_add_gizmo);
+
WM_operatortype_append(MESH_OT_duplicate);
WM_operatortype_append(MESH_OT_remove_doubles);
WM_operatortype_append(MESH_OT_spin);
WM_operatortype_append(MESH_OT_screw);
WM_operatortype_append(MESH_OT_extrude_region);
+ WM_operatortype_append(MESH_OT_extrude_context);
WM_operatortype_append(MESH_OT_extrude_faces_indiv);
WM_operatortype_append(MESH_OT_extrude_edges_indiv);
WM_operatortype_append(MESH_OT_extrude_verts_indiv);
@@ -141,13 +146,17 @@ void ED_operatortypes_mesh(void)
#endif
WM_operatortype_append(MESH_OT_vertices_smooth);
WM_operatortype_append(MESH_OT_vertices_smooth_laplacian);
- WM_operatortype_append(MESH_OT_noise);
WM_operatortype_append(MESH_OT_flip_normals);
WM_operatortype_append(MESH_OT_rip);
WM_operatortype_append(MESH_OT_rip_edge);
WM_operatortype_append(MESH_OT_blend_from_shape);
WM_operatortype_append(MESH_OT_shape_propagate_to_all);
+ /* editmesh_polybuild */
+ WM_operatortype_append(MESH_OT_polybuild_face_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_split_at_cursor);
+ WM_operatortype_append(MESH_OT_polybuild_dissolve_at_cursor);
+
WM_operatortype_append(MESH_OT_uv_texture_add);
WM_operatortype_append(MESH_OT_uv_texture_remove);
WM_operatortype_append(MESH_OT_vertex_color_add);
@@ -157,7 +166,6 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_customdata_skin_clear);
WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add);
WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear);
- WM_operatortype_append(MESH_OT_drop_named_image);
WM_operatortype_append(MESH_OT_edgering_select);
WM_operatortype_append(MESH_OT_loopcut);
@@ -192,13 +200,14 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_symmetrize);
WM_operatortype_append(MESH_OT_symmetry_snap);
-#ifdef WITH_GAMEENGINE
- WM_operatortype_append(MESH_OT_navmesh_make);
- WM_operatortype_append(MESH_OT_navmesh_face_copy);
- WM_operatortype_append(MESH_OT_navmesh_face_add);
- WM_operatortype_append(MESH_OT_navmesh_reset);
- WM_operatortype_append(MESH_OT_navmesh_clear);
-#endif
+ WM_operatortype_append(MESH_OT_point_normals);
+ WM_operatortype_append(MESH_OT_merge_normals);
+ WM_operatortype_append(MESH_OT_split_normals);
+ WM_operatortype_append(MESH_OT_normals_tools);
+ WM_operatortype_append(MESH_OT_set_normals_from_faces);
+ WM_operatortype_append(MESH_OT_average_normals);
+ WM_operatortype_append(MESH_OT_smoothen_normals);
+ WM_operatortype_append(MESH_OT_mod_weighted_strength);
}
#if 0 /* UNUSED, remove? */
@@ -223,14 +232,12 @@ void ED_operatormacros_mesh(void)
ot = WM_operatortype_append_macro("MESH_OT_loopcut_slide", "Loop Cut and Slide", "Cut mesh loop and slide it",
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MESH_OT_loopcut");
- otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
- RNA_boolean_set(otmacro->ptr, "release_confirm", false);
+ WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
ot = WM_operatortype_append_macro("MESH_OT_offset_edge_loops_slide", "Offset Edge Slide", "Offset edge loop slide",
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "MESH_OT_offset_edge_loops");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_edge_slide");
- RNA_boolean_set(otmacro->ptr, "release_confirm", false);
RNA_boolean_set(otmacro->ptr, "single_side", true);
ot = WM_operatortype_append_macro("MESH_OT_duplicate_move", "Add Duplicate", "Duplicate mesh and move",
@@ -261,6 +268,13 @@ void ED_operatormacros_mesh(void)
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+ ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move", "Extrude Region and Move",
+ "Extrude context and move result", OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_context");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+
ot = WM_operatortype_append_macro("MESH_OT_extrude_region_shrink_fatten", "Extrude Region and Shrink/Fatten",
"Extrude along normals and move result", OPTYPE_UNDO | OPTYPE_REGISTER);
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region");
@@ -288,180 +302,31 @@ void ED_operatormacros_mesh(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+
+ ot = WM_operatortype_append_macro(
+ "MESH_OT_polybuild_face_at_cursor_move", "Face at Cursor Move", "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_face_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+
+ ot = WM_operatortype_append_macro(
+ "MESH_OT_polybuild_split_at_cursor_move", "Split at Cursor Move", "",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_polybuild_split_at_cursor");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
}
/* note mesh keymap also for other space? */
void ED_keymap_mesh(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
- int i;
-
- keymap = WM_keymap_ensure(keyconf, "Mesh", 0, 0);
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Mesh", 0, 0);
keymap->poll = ED_operator_editmesh;
- WM_keymap_add_item(keymap, "MESH_OT_loopcut_slide", RKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "MESH_OT_offset_edge_loops_slide", RKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "MESH_OT_inset", IKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MESH_OT_poke", PKEY, KM_PRESS, KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_bevel", BKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "vertex_only", false);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_bevel", BKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "vertex_only", true);
-
- /* selecting */
- /* standard mouse selection goes via space_view3d */
- kmi = WM_keymap_add_item(keymap, "MESH_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", false);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- kmi = WM_keymap_add_item(keymap, "MESH_OT_edgering_select", SELECTMOUSE, KM_PRESS, KM_ALT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", false);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_edgering_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- kmi = WM_keymap_add_item(keymap, "MESH_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "use_fill", false);
-
- kmi = WM_keymap_add_item(keymap, "MESH_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "use_fill", true);
-
- kmi = WM_keymap_add_item(keymap, "MESH_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "MESH_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "MESH_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "MESH_OT_select_next_item", PADPLUSKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "MESH_OT_select_prev_item", PADMINUS, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "MESH_OT_select_non_manifold", MKEY, KM_PRESS, (KM_CTRL | KM_SHIFT | KM_ALT), 0);
-
- WM_keymap_add_item(keymap, "MESH_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- WM_keymap_add_item(keymap, "MESH_OT_faces_select_linked_flat", FKEY, KM_PRESS, (KM_CTRL | KM_SHIFT | KM_ALT), 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* selection mode */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0);
-
- /* hide */
- kmi = WM_keymap_add_item(keymap, "MESH_OT_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
- WM_keymap_add_item(keymap, "MESH_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
-
- /* tools */
- kmi = WM_keymap_add_item(keymap, "MESH_OT_normals_make_consistent", NKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "inside", false);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_normals_make_consistent", NKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "inside", true);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_edit_mesh_extrude_move_normal", EKEY, KM_PRESS, 0, 0); /* python operator */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_extrude", EKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "TRANSFORM_OT_edge_crease", EKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "MESH_OT_spin", RKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "MESH_OT_fill", FKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "MESH_OT_beautify_fill", FKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0);
-
- kmi = WM_keymap_add_item(keymap, "MESH_OT_quads_convert_to_tris", TKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "quad_method", MOD_TRIANGULATE_QUAD_BEAUTY);
- RNA_enum_set(kmi->ptr, "ngon_method", MOD_TRIANGULATE_NGON_BEAUTY);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_quads_convert_to_tris", TKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "quad_method", MOD_TRIANGULATE_QUAD_FIXED);
- RNA_enum_set(kmi->ptr, "ngon_method", MOD_TRIANGULATE_NGON_EARCLIP);
-
- WM_keymap_add_item(keymap, "MESH_OT_tris_convert_to_quads", JKEY, KM_PRESS, KM_ALT, 0);
-
- kmi = WM_keymap_add_item(keymap, "MESH_OT_rip_move", VKEY, KM_PRESS, 0, 0);
- {
- PointerRNA macro_ptr = RNA_pointer_get(kmi->ptr, "MESH_OT_rip");
- RNA_boolean_set(&macro_ptr, "use_fill", false);
- }
- kmi = WM_keymap_add_item(keymap, "MESH_OT_rip_move", VKEY, KM_PRESS, KM_ALT, 0);
- {
- PointerRNA macro_ptr = RNA_pointer_get(kmi->ptr, "MESH_OT_rip");
- RNA_boolean_set(&macro_ptr, "use_fill", true);
- }
-
- WM_keymap_add_item(keymap, "MESH_OT_rip_edge_move", DKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "MESH_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "TRANSFORM_OT_shrink_fatten", SKEY, KM_PRESS, KM_ALT, 0);
-
- /* add/remove */
- WM_keymap_add_item(keymap, "MESH_OT_edge_face_add", FKEY, KM_PRESS, 0, 0);
-// WM_keymap_add_item(keymap, "MESH_OT_skin", FKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); /* python, removed */
- WM_keymap_add_item(keymap, "MESH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_menu(keymap, "INFO_MT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MESH_OT_vert_connect_path", JKEY, KM_PRESS, 0, 0);
-
- /* Vertex Slide */
- WM_keymap_add_item(keymap, "TRANSFORM_OT_vert_slide", VKEY, KM_PRESS, KM_SHIFT, 0);
- /* use KM_CLICK because same key is used for tweaks */
- kmi = WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "rotate_source", true);
- kmi = WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", ACTIONMOUSE, KM_CLICK, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "rotate_source", false);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_delete", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "MESH_OT_dissolve_mode", XKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "MESH_OT_dissolve_mode", DELKEY, KM_PRESS, KM_CTRL, 0);
-
- kmi = WM_keymap_add_item(keymap, "MESH_OT_knife_tool", KKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_occlude_geometry", true);
- RNA_boolean_set(kmi->ptr, "only_selected", false);
-
- kmi = WM_keymap_add_item(keymap, "MESH_OT_knife_tool", KKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "use_occlude_geometry", false);
- RNA_boolean_set(kmi->ptr, "only_selected", true);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
-
- /* menus */
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_specials", WKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_faces", FKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_edges", EKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_vertices", VKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_hook", HKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_uv_map", UKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_vertex_group", GKEY, KM_PRESS, KM_CTRL, 0);
-
- /* useful stuff from object-mode */
- for (i = 0; i <= 5; i++) {
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY + i, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "level", i);
- }
-
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_editmode(keyconf, keymap, true);
-
knifetool_modal_keymap(keyconf);
+ point_normals_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 311f13b3ef7..c9ce8ed54fc 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -34,32 +34,38 @@
#include "MEM_guardedalloc.h"
-#include "DNA_mesh_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_editmesh.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_mesh.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
-#include "BKE_editmesh.h"
-#include "BKE_multires.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_mesh.h"
#include "ED_object.h"
@@ -76,7 +82,7 @@
* return 0 if no join is made (error) and 1 if the join is done */
static void join_mesh_single(
- Main *bmain, Scene *scene,
+ Depsgraph *depsgraph, Main *bmain, Scene *scene,
Object *ob_dst, Object *ob_src, float imat[4][4],
MVert **mvert_pp, MEdge **medge_pp, MLoop **mloop_pp, MPoly **mpoly_pp,
CustomData *vdata, CustomData *edata, CustomData *ldata, CustomData *pdata,
@@ -204,7 +210,7 @@ static void join_mesh_single(
if (ob_src != ob_dst) {
MultiresModifierData *mmd;
- multiresModifier_prepare_join(scene, ob_src, ob_dst);
+ multiresModifier_prepare_join(depsgraph, scene, ob_src, ob_dst);
if ((mmd = get_multires_modifier(scene, ob_src, true))) {
ED_object_iter_other(bmain, ob_src, true,
@@ -278,7 +284,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
bDeformGroup *dg, *odg;
CustomData vdata, edata, fdata, ldata, pdata;
- if (scene->obedit) {
+ if (ob->mode & OB_MODE_EDIT) {
BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode");
return OPERATOR_CANCELLED;
}
@@ -289,19 +295,21 @@ int join_mesh_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
/* count & check */
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects)
{
- if (base->object->type == OB_MESH) {
- me = base->object->data;
+ if (ob_iter->type == OB_MESH) {
+ me = ob_iter->data;
totvert += me->totvert;
totedge += me->totedge;
totloop += me->totloop;
totpoly += me->totpoly;
- totmat += base->object->totcol;
+ totmat += ob_iter->totcol;
- if (base->object == ob)
+ if (ob_iter == ob)
ok = true;
/* check for shapekeys */
@@ -371,14 +379,14 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
/* first pass over objects - copying materials and vertexgroups across */
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects)
{
/* only act if a mesh, and not the one we're joining to */
- if ((ob != base->object) && (base->object->type == OB_MESH)) {
- me = base->object->data;
+ if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
+ me = ob_iter->data;
/* Join this object's vertex groups to the base one's */
- for (dg = base->object->defbase.first; dg; dg = dg->next) {
+ for (dg = ob_iter->defbase.first; dg; dg = dg->next) {
/* See if this group exists in the object (if it doesn't, add it to the end) */
if (!defgroup_find_name(ob, dg->name)) {
odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup");
@@ -393,8 +401,8 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (me->totvert) {
/* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */
if (totcol < MAXMAT) {
- for (a = 1; a <= base->object->totcol; a++) {
- ma = give_current_material(base->object, a);
+ for (a = 1; a <= ob_iter->totcol; a++) {
+ ma = give_current_material(ob_iter, a);
for (b = 0; b < totcol; b++) {
if (ma == matar[b]) {
@@ -483,7 +491,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
* active mesh will remain first ones in new result of the merge, in same order for CD layers, etc. See also T50084.
*/
join_mesh_single(
- bmain, scene,
+ depsgraph, bmain, scene,
ob, ob, imat,
&mvert, &medge, &mloop, &mpoly,
&vdata, &edata, &ldata, &pdata,
@@ -492,16 +500,16 @@ int join_mesh_exec(bContext *C, wmOperator *op)
matar, matmap, totcol,
&vertofs, &edgeofs, &loopofs, &polyofs);
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects)
{
- if (base->object == ob) {
+ if (ob_iter == ob) {
continue;
}
/* only join if this is a mesh */
- if (base->object->type == OB_MESH) {
+ if (ob_iter->type == OB_MESH) {
join_mesh_single(
- bmain, scene,
- ob, base->object, imat,
+ depsgraph, bmain, scene,
+ ob, ob_iter, imat,
&mvert, &medge, &mloop, &mpoly,
&vdata, &edata, &ldata, &pdata,
totvert, totedge, totloop, totpoly,
@@ -510,8 +518,8 @@ int join_mesh_exec(bContext *C, wmOperator *op)
&vertofs, &edgeofs, &loopofs, &polyofs);
/* free base, now that data is merged */
- if (base->object != ob) {
- ED_base_object_free_and_unlink(bmain, scene, base);
+ if (ob_iter != ob) {
+ ED_object_base_free_and_unlink(bmain, scene, ob_iter);
}
}
}
@@ -582,10 +590,11 @@ int join_mesh_exec(bContext *C, wmOperator *op)
/* Due to dependnecy cycle some other object might access old derived data. */
BKE_object_free_derived_caches(ob);
- DAG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */
+ DEG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
@@ -600,20 +609,23 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Mesh *me = (Mesh *)ob->data;
+ Object *ob_active = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Mesh *me = (Mesh *)ob_active->data;
Mesh *selme = NULL;
- DerivedMesh *dm = NULL;
+ Mesh *me_deformed = NULL;
Key *key = me->key;
KeyBlock *kb;
bool ok = false, nonequal_verts = false;
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects)
{
- if (base->object == ob) continue;
+ if (ob_iter == ob_active) {
+ continue;
+ }
- if (base->object->type == OB_MESH) {
- selme = (Mesh *)base->object->data;
+ if (ob_iter->type == OB_MESH) {
+ selme = (Mesh *)ob_iter->data;
if (selme->totvert == me->totvert)
ok = true;
@@ -637,32 +649,35 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
/* first key added, so it was the basis. initialize it with the existing mesh */
kb = BKE_keyblock_add(key, NULL);
- BKE_keyblock_convert_from_mesh(me, kb);
+ BKE_keyblock_convert_from_mesh(me, key, kb);
}
/* now ready to add new keys from selected meshes */
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects)
{
- if (base->object == ob) continue;
+ if (ob_iter == ob_active) {
+ continue;
+ }
- if (base->object->type == OB_MESH) {
- selme = (Mesh *)base->object->data;
+ if (ob_iter->type == OB_MESH) {
+ selme = (Mesh *)ob_iter->data;
if (selme->totvert == me->totvert) {
- dm = mesh_get_derived_deform(scene, base->object, CD_MASK_BAREMESH);
-
- if (!dm) continue;
+ me_deformed = mesh_get_eval_deform(depsgraph, scene, ob_iter, CD_MASK_BAREMESH);
- kb = BKE_keyblock_add(key, base->object->id.name + 2);
+ if (!me_deformed) {
+ continue;
+ }
- DM_to_meshkey(dm, me, kb);
+ kb = BKE_keyblock_add(key, ob_iter->id.name + 2);
- dm->release(dm);
+ BKE_mesh_runtime_eval_to_meshkey(me_deformed, me, kb);
}
}
}
CTX_DATA_END;
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
@@ -680,15 +695,15 @@ static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1};
/* mode is 's' start, or 'e' end, or 'u' use */
/* if end, ob can be NULL */
/* note, is supposed return -1 on error, which callers are currently checking for, but is not used so far */
-int ED_mesh_mirror_topo_table(Object *ob, DerivedMesh *dm, char mode)
+int ED_mesh_mirror_topo_table(Object *ob, Mesh *me_eval, char mode)
{
if (mode == 'u') { /* use table */
- if (ED_mesh_mirrtopo_recalc_check(ob->data, dm, ob->mode, &mesh_topo_store)) {
- ED_mesh_mirror_topo_table(ob, dm, 's');
+ if (ED_mesh_mirrtopo_recalc_check(ob->data, me_eval, &mesh_topo_store)) {
+ ED_mesh_mirror_topo_table(ob, me_eval, 's');
}
}
else if (mode == 's') { /* start table */
- ED_mesh_mirrtopo_init(ob->data, dm, ob->mode, &mesh_topo_store, false);
+ ED_mesh_mirrtopo_init(ob->data, me_eval, &mesh_topo_store, false);
}
else if (mode == 'e') { /* end table */
ED_mesh_mirrtopo_free(&mesh_topo_store);
@@ -703,10 +718,10 @@ int ED_mesh_mirror_topo_table(Object *ob, DerivedMesh *dm, char mode)
/** \} */
-static int mesh_get_x_mirror_vert_spatial(Object *ob, DerivedMesh *dm, int index)
+static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh, int index)
{
Mesh *me = ob->data;
- MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
+ MVert *mvert = mesh ? mesh->mvert : me->mvert;
float vec[3];
mvert = &mvert[index];
@@ -714,24 +729,24 @@ static int mesh_get_x_mirror_vert_spatial(Object *ob, DerivedMesh *dm, int index
vec[1] = mvert->co[1];
vec[2] = mvert->co[2];
- return ED_mesh_mirror_spatial_table(ob, NULL, dm, vec, 'u');
+ return ED_mesh_mirror_spatial_table(ob, NULL, mesh, vec, 'u');
}
-static int mesh_get_x_mirror_vert_topo(Object *ob, DerivedMesh *dm, int index)
+static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
{
- if (ED_mesh_mirror_topo_table(ob, dm, 'u') == -1)
+ if (ED_mesh_mirror_topo_table(ob, mesh, 'u') == -1)
return -1;
return mesh_topo_store.index_lookup[index];
}
-int mesh_get_x_mirror_vert(Object *ob, DerivedMesh *dm, int index, const bool use_topology)
+int mesh_get_x_mirror_vert(Object *ob, Mesh *me_eval, int index, const bool use_topology)
{
if (use_topology) {
- return mesh_get_x_mirror_vert_topo(ob, dm, index);
+ return mesh_get_x_mirror_vert_topo(ob, me_eval, index);
}
else {
- return mesh_get_x_mirror_vert_spatial(ob, dm, index);
+ return mesh_get_x_mirror_vert_spatial(ob, me_eval, index);
}
}
@@ -928,8 +943,8 @@ static bool mirror_facecmp(const void *a, const void *b)
return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
}
-/* BMESH_TODO, convert to MPoly (functions above also) */
-int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, DerivedMesh *dm)
+/* This is a Mesh-based copy of mesh_get_x_mirror_faces() */
+int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
{
Mesh *me = ob->data;
MVert *mv, *mvert;
@@ -940,22 +955,22 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, DerivedMesh *dm)
BLI_assert(em == NULL); /* Does not work otherwise, currently... */
const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
- const int totvert = dm ? dm->getNumVerts(dm) : me->totvert;
- const int totface = dm ? dm->getNumTessFaces(dm) : me->totface;
+ const int totvert = me_eval ? me_eval->totvert : me->totvert;
+ const int totface = me_eval ? me_eval->totface : me->totface;
int a;
mirrorverts = MEM_callocN(sizeof(int) * totvert, "MirrorVerts");
mirrorfaces = MEM_callocN(sizeof(int) * 2 * totface, "MirrorFaces");
- mvert = dm ? dm->getVertArray(dm) : me->mvert;
- mface = dm ? dm->getTessFaceArray(dm) : me->mface;
+ mvert = me_eval ? me_eval->mvert : me->mvert;
+ mface = me_eval ? me_eval->mface : me->mface;
- ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
+ ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's');
for (a = 0, mv = mvert; a < totvert; a++, mv++)
- mirrorverts[a] = mesh_get_x_mirror_vert(ob, dm, a, use_topology);
+ mirrorverts[a] = mesh_get_x_mirror_vert(ob, me_eval, a, use_topology);
- ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 'e');
+ ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 'e');
fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface);
for (a = 0, mf = mface; a < totface; a++, mf++)
@@ -1031,21 +1046,22 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int
static void ed_mesh_pick_face_vert__mpoly_find(
/* context */
struct ARegion *ar, const float mval[2],
- /* mesh data */
- DerivedMesh *dm, MPoly *mp, MLoop *mloop,
+ /* mesh data (evaluated) */
+ const MPoly *mp,
+ const MVert *mvert, const MLoop *mloop,
/* return values */
float *r_len_best, int *r_v_idx_best)
{
const MLoop *ml;
int j = mp->totloop;
for (ml = &mloop[mp->loopstart]; j--; ml++) {
- float co[3], sco[2], len;
+ float sco[2];
const int v_idx = ml->v;
- dm->getVertCo(dm, v_idx, co);
+ const float *co = mvert[v_idx].co;
if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- len = len_manhattan_v2v2(mval, sco);
- if (len < *r_len_best) {
- *r_len_best = len;
+ const float len_test = len_manhattan_v2v2(mval, sco);
+ if (len_test < *r_len_best) {
+ *r_len_best = len_test;
*r_v_idx_best = v_idx;
}
}
@@ -1057,6 +1073,7 @@ static void ed_mesh_pick_face_vert__mpoly_find(
*/
bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
unsigned int poly_index;
Mesh *me = ob->data;
@@ -1067,7 +1084,7 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned
struct ARegion *ar = CTX_wm_region(C);
/* derived mesh to find deformed locations */
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
int v_idx_best = ORIGINDEX_NONE;
@@ -1075,36 +1092,38 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned
const float mval_f[2] = {UNPACK2(mval)};
float len_best = FLT_MAX;
- MPoly *dm_mpoly;
- MLoop *dm_mloop;
- unsigned int dm_mpoly_tot;
+ MPoly *me_eval_mpoly;
+ MLoop *me_eval_mloop;
+ MVert *me_eval_mvert;
+ unsigned int me_eval_mpoly_len;
const int *index_mp_to_orig;
- dm_mpoly = dm->getPolyArray(dm);
- dm_mloop = dm->getLoopArray(dm);
+ me_eval_mpoly = me_eval->mpoly;
+ me_eval_mloop = me_eval->mloop;
+ me_eval_mvert = me_eval->mvert;
- dm_mpoly_tot = dm->getNumPolys(dm);
+ me_eval_mpoly_len = me_eval->totpoly;
- index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
/* tag all verts using this face */
if (index_mp_to_orig) {
unsigned int i;
- for (i = 0; i < dm_mpoly_tot; i++) {
+ for (i = 0; i < me_eval_mpoly_len; i++) {
if (index_mp_to_orig[i] == poly_index) {
ed_mesh_pick_face_vert__mpoly_find(
ar, mval_f,
- dm, &dm_mpoly[i], dm_mloop,
+ &me_eval_mpoly[i], me_eval_mvert, me_eval_mloop,
&len_best, &v_idx_best);
}
}
}
else {
- if (poly_index < dm_mpoly_tot) {
+ if (poly_index < me_eval_mpoly_len) {
ed_mesh_pick_face_vert__mpoly_find(
ar, mval_f,
- dm, &dm_mpoly[poly_index], dm_mloop,
+ &me_eval_mpoly[poly_index], me_eval_mvert, me_eval_mloop,
&len_best, &v_idx_best);
}
}
@@ -1112,15 +1131,12 @@ bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned
/* map 'dm -> me' index if possible */
if (v_idx_best != ORIGINDEX_NONE) {
const int *index_mv_to_orig;
-
- index_mv_to_orig = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ index_mv_to_orig = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
if (index_mv_to_orig) {
v_idx_best = index_mv_to_orig[v_idx_best];
}
}
- dm->release(dm);
-
if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < me->totvert)) {
*index = v_idx_best;
return true;
@@ -1194,7 +1210,7 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int
}
else {
/* derived mesh to find deformed locations */
- DerivedMesh *dm = mesh_get_derived_final(vc.scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_eval = mesh_get_eval_final(vc.depsgraph, vc.scene, ob, CD_MASK_BAREMESH);
ARegion *ar = vc.ar;
RegionView3D *rv3d = ar->regiondata;
@@ -1206,7 +1222,7 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int
ED_view3d_init_mats_rv3d(ob, rv3d);
- if (dm == NULL) {
+ if (me_eval == NULL) {
return false;
}
@@ -1217,9 +1233,7 @@ bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int
data.len_best = FLT_MAX;
data.v_idx_best = -1;
- dm->foreachMappedVert(dm, ed_mesh_pick_vert__mapFunc, &data, DM_FOREACH_NOP);
-
- dm->release(dm);
+ BKE_mesh_foreach_mapped_vert(me_eval, ed_mesh_pick_vert__mapFunc, &data, MESH_FOREACH_NOP);
if (data.v_idx_best == -1) {
return false;
@@ -1280,3 +1294,47 @@ MDeformVert *ED_mesh_active_dvert_get_only(Object *ob)
return NULL;
}
}
+
+void EDBM_mesh_stats_multi(
+ struct Object **objects, const uint objects_len,
+ int totelem[3], int totelem_sel[3])
+{
+ if (totelem) {
+ totelem[0] = 0;
+ totelem[1] = 0;
+ totelem[2] = 0;
+ }
+ if (totelem_sel) {
+ totelem_sel[0] = 0;
+ totelem_sel[1] = 0;
+ totelem_sel[2] = 0;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ if (totelem) {
+ totelem[0] += bm->totvert;
+ totelem[1] += bm->totedge;
+ totelem[2] += bm->totface;
+ }
+ if (totelem_sel) {
+ totelem_sel[0] += bm->totvertsel;
+ totelem_sel[1] += bm->totedgesel;
+ totelem_sel[2] += bm->totfacesel;
+ }
+ }
+}
+
+
+void EDBM_mesh_elem_index_ensure_multi(Object **objects, const uint objects_len, const char htype)
+{
+ int elem_offset[4] = {0, 0, 0, 0};
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BM_mesh_elem_index_ensure_ex(bm, htype, elem_offset);
+ }
+}
diff --git a/source/blender/editors/metaball/CMakeLists.txt b/source/blender/editors/metaball/CMakeLists.txt
index 7815240b7a4..b0ae3122727 100644
--- a/source/blender/editors/metaball/CMakeLists.txt
+++ b/source/blender/editors/metaball/CMakeLists.txt
@@ -22,10 +22,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../depsgraph
../../makesdna
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index dc64f61a916..c85f046ce71 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -27,6 +27,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_array_utils.h"
@@ -36,16 +38,22 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "ED_object.h"
#include "ED_mball.h"
+#include "ED_undo.h"
#include "ED_util.h"
#include "WM_types.h"
#include "WM_api.h"
+/** We only need this locally. */
+static CLG_LogRef LOG = {"ed.undo.mball"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -129,13 +137,19 @@ static Object *editmball_object_from_context(bContext *C)
/* -------------------------------------------------------------------- */
/** \name Implements ED Undo System
+ *
+ * \note This is similar for all edit-mode types.
* \{ */
-typedef struct MBallUndoStep {
- UndoStep step;
- /* note: will split out into list for multi-object-editmode. */
+typedef struct MBallUndoStep_Elem {
UndoRefID_Object obedit_ref;
UndoMBall data;
+} MBallUndoStep_Elem;
+
+typedef struct MBallUndoStep {
+ UndoStep step;
+ MBallUndoStep_Elem *elems;
+ uint elems_len;
} MBallUndoStep;
static bool mball_undosys_poll(bContext *C)
@@ -146,36 +160,74 @@ static bool mball_undosys_poll(bContext *C)
static bool mball_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
MBallUndoStep *us = (MBallUndoStep *)us_p;
- us->obedit_ref.ptr = editmball_object_from_context(C);
- MetaBall *mb = us->obedit_ref.ptr->data;
- editmball_from_undomball(&us->data, mb);
- us->step.data_size = us->data.undo_size;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__);
+ us->elems_len = objects_len;
+
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ MBallUndoStep_Elem *elem = &us->elems[i];
+
+ elem->obedit_ref.ptr = ob;
+ MetaBall *mb = ob->data;
+ editmball_from_undomball(&elem->data, mb);
+ us->step.data_size += elem->data.undo_size;
+ }
+ MEM_freeN(objects);
return true;
}
static void mball_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
ED_object_mode_set(C, OB_MODE_EDIT);
+ BLI_assert(mball_undosys_poll(C));
MBallUndoStep *us = (MBallUndoStep *)us_p;
- Object *obedit = us->obedit_ref.ptr;
- MetaBall *mb = obedit->data;
- undomball_to_editmball(&us->data, mb);
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MBallUndoStep_Elem *elem = &us->elems[i];
+ Object *obedit = elem->obedit_ref.ptr;
+ MetaBall *mb = obedit->data;
+ if (mb->editelems == NULL) {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_ERROR(&LOG, "name='%s', failed to enter edit-mode for object '%s', undo state invalid", us_p->name, obedit->id.name);
+ continue;
+ }
+ undomball_to_editmball(&elem->data, mb);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ }
+
+ /* The first element is always active */
+ ED_undo_object_set_active_or_warn(CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
+
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
static void mball_undosys_step_free(UndoStep *us_p)
{
MBallUndoStep *us = (MBallUndoStep *)us_p;
- undomball_free_data(&us->data);
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MBallUndoStep_Elem *elem = &us->elems[i];
+ undomball_free_data(&elem->data);
+ }
+ MEM_freeN(us->elems);
}
static void mball_undosys_foreach_ID_ref(
UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
{
MBallUndoStep *us = (MBallUndoStep *)us_p;
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+
+ for (uint i = 0; i < us->elems_len; i++) {
+ MBallUndoStep_Elem *elem = &us->elems[i];
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&elem->obedit_ref));
+ }
}
/* Export for ED_undo_sys. */
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 84301a22fa0..07a41bd385e 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -38,6 +38,7 @@
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+#include "BLI_kdtree.h"
#include "DNA_defs.h"
#include "DNA_meta_types.h"
@@ -47,12 +48,17 @@
#include "RNA_define.h"
#include "RNA_access.h"
-#include "BKE_depsgraph.h"
#include "BKE_context.h"
#include "BKE_mball.h"
+#include "BKE_layer.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
#include "ED_mball.h"
+#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_view3d.h"
#include "WM_api.h"
@@ -122,37 +128,38 @@ MetaElem *ED_mball_add_primitive(bContext *UNUSED(C), Object *obedit, float mat[
/* Select or deselect all MetaElements */
static int mball_select_all_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- MetaBall *mb = (MetaBall *)obedit->data;
- MetaElem *ml;
int action = RNA_enum_get(op->ptr, "action");
- if (BLI_listbase_is_empty(mb->editelems))
- return OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) {
- action = SEL_DESELECT;
- break;
- }
- }
+ action = BKE_mball_is_any_selected_multi(objects, objects_len) ?
+ SEL_DESELECT :
+ SEL_SELECT;
}
switch (action) {
case SEL_SELECT:
- BKE_mball_select_all(mb);
+ BKE_mball_select_all_multi(objects, objects_len);
break;
case SEL_DESELECT:
- BKE_mball_deselect_all(mb);
+ BKE_mball_deselect_all_multi(objects, objects_len);
break;
case SEL_INVERT:
- BKE_mball_select_swap(mb);
+ BKE_mball_select_swap_multi(objects, objects_len);
break;
}
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ DEG_id_tag_update(&mb->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ }
+
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -193,149 +200,199 @@ static const EnumPropertyItem prop_similar_types[] = {
{0, NULL, 0, NULL, NULL}
};
-static bool mball_select_similar_type(MetaBall *mb)
+static void mball_select_similar_type_get(Object *obedit, MetaBall *mb, int type, KDTree *r_tree)
{
+ float tree_entry[3] = {0.0f, 0.0f, 0.0f};
MetaElem *ml;
- bool changed = false;
-
+ int tree_index = 0;
for (ml = mb->editelems->first; ml; ml = ml->next) {
if (ml->flag & SELECT) {
- MetaElem *ml_iter;
-
- for (ml_iter = mb->editelems->first; ml_iter; ml_iter = ml_iter->next) {
- if ((ml_iter->flag & SELECT) == 0) {
- if (ml->type == ml_iter->type) {
- ml_iter->flag |= SELECT;
- changed = true;
- }
+ switch (type) {
+ case SIMMBALL_RADIUS:
+ {
+ float radius = ml->rad;
+ /* Radius in world space. */
+ float smat[3][3];
+ float radius_vec[3] = {radius, radius, radius};
+ BKE_object_scale_to_mat3(obedit, smat);
+ mul_m3_v3(smat, radius_vec);
+ radius = (radius_vec[0] + radius_vec[1] + radius_vec[2]) / 3;
+ tree_entry[0] = radius;
+ break;
+ }
+ case SIMMBALL_STIFFNESS:
+ {
+ tree_entry[0] = ml->s;
+ break;
+ }
+ break;
+ case SIMMBALL_ROTATION:
+ {
+ float dir[3] = {1.0f, 0.0f, 0.0f};
+ float rmat[3][3];
+ mul_qt_v3(ml->quat, dir);
+ BKE_object_rot_to_mat3(obedit, rmat, true);
+ mul_m3_v3(rmat, dir);
+ copy_v3_v3(tree_entry, dir);
+ break;
}
}
+ BLI_kdtree_insert(r_tree, tree_index++, tree_entry);
}
}
-
- return changed;
}
-static bool mball_select_similar_radius(MetaBall *mb, const float thresh)
+static bool mball_select_similar_type(Object *obedit, MetaBall *mb, int type, const KDTree *tree, const float thresh)
{
MetaElem *ml;
bool changed = false;
-
for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) {
- MetaElem *ml_iter;
-
- for (ml_iter = mb->editelems->first; ml_iter; ml_iter = ml_iter->next) {
- if ((ml_iter->flag & SELECT) == 0) {
- if (fabsf(ml_iter->rad - ml->rad) <= (thresh * ml->rad)) {
- ml_iter->flag |= SELECT;
- changed = true;
+ bool select = false;
+ switch (type) {
+ case SIMMBALL_RADIUS:
+ {
+ float radius = ml->rad;
+ /* Radius in world space is the average of the
+ * scaled radius in x, y and z directions. */
+ float smat[3][3];
+ float radius_vec[3] = {radius, radius, radius};
+ BKE_object_scale_to_mat3(obedit, smat);
+ mul_m3_v3(smat, radius_vec);
+ radius = (radius_vec[0] + radius_vec[1] + radius_vec[2]) / 3;
+
+ if (ED_select_similar_compare_float_tree(tree, radius, thresh, SIM_CMP_EQ)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMMBALL_STIFFNESS:
+ {
+ float s = ml->s;
+ if (ED_select_similar_compare_float_tree(tree, s, thresh, SIM_CMP_EQ)) {
+ select = true;
+ }
+ break;
+ }
+ case SIMMBALL_ROTATION:
+ {
+ float dir[3] = {1.0f, 0.0f, 0.0f};
+ float rmat[3][3];
+ mul_qt_v3(ml->quat, dir);
+ BKE_object_rot_to_mat3(obedit, rmat, true);
+ mul_m3_v3(rmat, dir);
+
+ float thresh_cos = cosf(thresh * (float)M_PI_2);
+
+ KDTreeNearest nearest;
+ if (BLI_kdtree_find_nearest(tree, dir, &nearest) != -1) {
+ float orient = angle_normalized_v3v3(dir, nearest.co);
+ /* Map to 0-1 to compare orientation. */
+ float delta = thresh_cos - fabsf(cosf(orient));
+ if (ED_select_similar_compare_float(delta, thresh, SIM_CMP_EQ)) {
+ select = true;
}
}
+ break;
}
}
- }
+ if (select) {
+ changed = true;
+ ml->flag |= SELECT;
+ }
+ }
return changed;
}
-static bool mball_select_similar_stiffness(MetaBall *mb, const float thresh)
+static int mball_select_similar_exec(bContext *C, wmOperator *op)
{
- MetaElem *ml;
- bool changed = false;
+ const int type = RNA_enum_get(op->ptr, "type");
+ const float thresh = RNA_float_get(op->ptr, "threshold");
+ int tot_mball_selected_all = 0;
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) {
- MetaElem *ml_iter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- for (ml_iter = mb->editelems->first; ml_iter; ml_iter = ml_iter->next) {
- if ((ml_iter->flag & SELECT) == 0) {
- if (fabsf(ml_iter->s - ml->s) <= thresh) {
- ml_iter->flag |= SELECT;
- changed = true;
+ tot_mball_selected_all = BKE_mball_select_count_multi(objects, objects_len);
+
+ short type_ref = 0;
+ KDTree *tree = NULL;
+
+ if (type != SIMMBALL_TYPE) {
+ tree = BLI_kdtree_new(tot_mball_selected_all);
+ }
+
+ /* Get type of selected MetaBall */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+
+ switch (type) {
+ case SIMMBALL_TYPE:
+ {
+ MetaElem *ml;
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ short mball_type = 1 << (ml->type + 1);
+ type_ref |= mball_type;
}
}
+ break;
}
+ case SIMMBALL_RADIUS:
+ case SIMMBALL_STIFFNESS:
+ case SIMMBALL_ROTATION:
+ mball_select_similar_type_get(obedit, mb, type, tree);
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
}
- return changed;
-}
-
-static bool mball_select_similar_rotation(MetaBall *mb, const float thresh)
-{
- const float thresh_rad = thresh * (float)M_PI_2;
- MetaElem *ml;
- bool changed = false;
-
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) {
- MetaElem *ml_iter;
-
- float ml_mat[3][3];
-
- unit_m3(ml_mat);
- mul_qt_v3(ml->quat, ml_mat[0]);
- mul_qt_v3(ml->quat, ml_mat[1]);
- mul_qt_v3(ml->quat, ml_mat[2]);
- normalize_m3(ml_mat);
-
- for (ml_iter = mb->editelems->first; ml_iter; ml_iter = ml_iter->next) {
- if ((ml_iter->flag & SELECT) == 0) {
- float ml_iter_mat[3][3];
-
- unit_m3(ml_iter_mat);
- mul_qt_v3(ml_iter->quat, ml_iter_mat[0]);
- mul_qt_v3(ml_iter->quat, ml_iter_mat[1]);
- mul_qt_v3(ml_iter->quat, ml_iter_mat[2]);
- normalize_m3(ml_iter_mat);
-
- if ((angle_normalized_v3v3(ml_mat[0], ml_iter_mat[0]) +
- angle_normalized_v3v3(ml_mat[1], ml_iter_mat[1]) +
- angle_normalized_v3v3(ml_mat[2], ml_iter_mat[2])) < thresh_rad)
- {
- ml_iter->flag |= SELECT;
+ if (tree != NULL) {
+ BLI_kdtree_balance(tree);
+ }
+ /* Select MetaBalls with desired type. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ bool changed = false;
+
+ switch (type) {
+ case SIMMBALL_TYPE:
+ {
+ MetaElem *ml;
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ short mball_type = 1 << (ml->type + 1);
+ if (mball_type & type_ref) {
+ ml->flag |= SELECT;
changed = true;
}
}
+ break;
}
+ case SIMMBALL_RADIUS:
+ case SIMMBALL_STIFFNESS:
+ case SIMMBALL_ROTATION:
+ changed = mball_select_similar_type(obedit, mb, type, tree, thresh);
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- }
-
- return changed;
-}
-
-static int mball_select_similar_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- MetaBall *mb = (MetaBall *)obedit->data;
- int type = RNA_enum_get(op->ptr, "type");
- float thresh = RNA_float_get(op->ptr, "threshold");
- bool changed = false;
-
- switch (type) {
- case SIMMBALL_TYPE:
- changed = mball_select_similar_type(mb);
- break;
- case SIMMBALL_RADIUS:
- changed = mball_select_similar_radius(mb, thresh);
- break;
- case SIMMBALL_STIFFNESS:
- changed = mball_select_similar_stiffness(mb, thresh);
- break;
- case SIMMBALL_ROTATION:
- changed = mball_select_similar_rotation(mb, thresh);
- break;
- default:
- BLI_assert(0);
- break;
+ if (changed) {
+ DEG_id_tag_update(&mb->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ }
}
- if (changed) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ MEM_freeN(objects);
+ if (tree != NULL) {
+ BLI_kdtree_free(tree);
}
-
return OPERATOR_FINISHED;
}
@@ -357,7 +414,7 @@ void MBALL_OT_select_similar(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, 0, "Type", "");
- RNA_def_float(ot->srna, "threshold", 0.1, 0.0, 1.0, "Threshold", "", 0.01, 1.0);
+ RNA_def_float(ot->srna, "threshold", 0.1, 0.0, FLT_MAX, "Threshold", "", 0.01, 1.0);
}
@@ -366,32 +423,48 @@ void MBALL_OT_select_similar(wmOperatorType *ot)
/* Random metaball selection */
static int select_random_metaelems_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- MetaBall *mb = (MetaBall *)obedit->data;
- MetaElem *ml;
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
- RNG *rng = BLI_rng_new_srandom(seed);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ if (!BKE_mball_is_any_unselected(mb)) {
+ continue;
+ }
+ int seed_iter = seed;
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (BLI_rng_get_float(rng) < randfac) {
- if (select)
- ml->flag |= SELECT;
- else
- ml->flag &= ~SELECT;
+ /* This gives a consistent result regardless of object order. */
+ if (ob_index) {
+ seed_iter += BLI_ghashutil_strhash_p(obedit->id.name);
}
- }
- BLI_rng_free(rng);
+ RNG *rng = BLI_rng_new_srandom(seed_iter);
+
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ if (BLI_rng_get_float(rng) < randfac) {
+ if (select) {
+ ml->flag |= SELECT;
+ }
+ else {
+ ml->flag &= ~SELECT;
+ }
+ }
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ BLI_rng_free(rng);
+ DEG_id_tag_update(&mb->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
-
void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
{
/* identifiers */
@@ -415,25 +488,34 @@ void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
/* Duplicate selected MetaElements */
static int duplicate_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- MetaBall *mb = (MetaBall *)obedit->data;
- MetaElem *ml, *newml;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ MetaElem *ml, *newml;
+
+ if (!BKE_mball_is_any_selected(mb)) {
+ continue;
+ }
- ml = mb->editelems->last;
- if (ml) {
- while (ml) {
- if (ml->flag & SELECT) {
- newml = MEM_dupallocN(ml);
- BLI_addtail(mb->editelems, newml);
- mb->lastelem = newml;
- ml->flag &= ~SELECT;
+ ml = mb->editelems->last;
+ if (ml) {
+ while (ml) {
+ if (ml->flag & SELECT) {
+ newml = MEM_dupallocN(ml);
+ BLI_addtail(mb->editelems, newml);
+ mb->lastelem = newml;
+ ml->flag &= ~SELECT;
+ }
+ ml = ml->prev;
}
- ml = ml->prev;
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, mb);
+ DEG_id_tag_update(obedit->data, 0);
}
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, mb);
- DAG_id_tag_update(obedit->data, 0);
}
-
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -457,25 +539,34 @@ void MBALL_OT_duplicate_metaelems(wmOperatorType *ot)
/* Delete all selected MetaElems (not MetaBall) */
static int delete_metaelems_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *obedit = CTX_data_edit_object(C);
- MetaBall *mb = (MetaBall *)obedit->data;
- MetaElem *ml, *next;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ MetaElem *ml, *next;
+
+ if (!BKE_mball_is_any_selected(mb)) {
+ continue;
+ }
- ml = mb->editelems->first;
- if (ml) {
- while (ml) {
- next = ml->next;
- if (ml->flag & SELECT) {
- if (mb->lastelem == ml) mb->lastelem = NULL;
- BLI_remlink(mb->editelems, ml);
- MEM_freeN(ml);
+ ml = mb->editelems->first;
+ if (ml) {
+ while (ml) {
+ next = ml->next;
+ if (ml->flag & SELECT) {
+ if (mb->lastelem == ml) mb->lastelem = NULL;
+ BLI_remlink(mb->editelems, ml);
+ MEM_freeN(ml);
+ }
+ ml = next;
}
- ml = next;
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, mb);
+ DEG_id_tag_update(obedit->data, 0);
}
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, mb);
- DAG_id_tag_update(obedit->data, 0);
}
-
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -487,6 +578,7 @@ void MBALL_OT_delete_metaelems(wmOperatorType *ot)
ot->idname = "MBALL_OT_delete_metaelems";
/* callback functions */
+ ot->invoke = WM_operator_confirm;
ot->exec = delete_metaelems_exec;
ot->poll = ED_operator_editmball;
@@ -513,7 +605,7 @@ static int hide_metaelems_exec(bContext *C, wmOperator *op)
ml = ml->next;
}
WM_event_add_notifier(C, NC_GEOM | ND_DATA, mb);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
}
return OPERATOR_FINISHED;
@@ -556,7 +648,7 @@ static int reveal_metaelems_exec(bContext *C, wmOperator *op)
}
if (changed) {
WM_event_add_notifier(C, NC_GEOM | ND_DATA, mb);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
}
return OPERATOR_FINISHED;
@@ -585,10 +677,7 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
static MetaElem *startelem = NULL;
- Object *obedit = CTX_data_edit_object(C);
ViewContext vc;
- MetaBall *mb = (MetaBall *)obedit->data;
- MetaElem *ml, *ml_act = NULL;
int a, hits;
unsigned int buffer[MAXPICKBUF];
rcti rect;
@@ -597,67 +686,120 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
BLI_rcti_init_pt_radius(&rect, mval, 12);
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
+ hits = view3d_opengl_select(
+ &vc, buffer, MAXPICKBUF, &rect,
+ VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
- /* does startelem exist? */
- ml = mb->editelems->first;
- while (ml) {
- if (ml == startelem) break;
- ml = ml->next;
- }
-
- if (ml == NULL) startelem = mb->editelems->first;
+ FOREACH_BASE_IN_EDIT_MODE_BEGIN (vc.view_layer, vc.v3d, base) {
+ ED_view3d_viewcontext_init_object(&vc, base->object);
+ MetaBall *mb = (MetaBall *)base->object->data;
+ MetaElem *ml, *ml_act = NULL;
- if (hits > 0) {
- ml = startelem;
+ /* does startelem exist? */
+ ml = mb->editelems->first;
while (ml) {
- for (a = 0; a < hits; a++) {
- /* index converted for gl stuff */
- if (ml->selcol1 == buffer[4 * a + 3]) {
- ml->flag |= MB_SCALE_RAD;
- ml_act = ml;
- }
- if (ml->selcol2 == buffer[4 * a + 3]) {
- ml->flag &= ~MB_SCALE_RAD;
- ml_act = ml;
- }
- }
- if (ml_act) break;
- ml = ml->next;
- if (ml == NULL) ml = mb->editelems->first;
if (ml == startelem) break;
+ ml = ml->next;
}
- /* When some metaelem was found, then it is necessary to select or
- * deselect it. */
- if (ml_act) {
- if (extend) {
- ml_act->flag |= SELECT;
- }
- else if (deselect) {
- ml_act->flag &= ~SELECT;
+ if (ml == NULL) startelem = mb->editelems->first;
+
+ if (hits > 0) {
+ int metaelem_id = 0;
+ ml = startelem;
+ while (ml) {
+ for (a = 0; a < hits; a++) {
+ int hitresult = buffer[(4 * a) + 3];
+ if (hitresult == -1) {
+ continue;
+ }
+ else if (hitresult & MBALL_NOSEL) {
+ continue;
+ }
+
+ const uint hit_object = hitresult & 0xFFFF;
+ if (vc.obedit->select_color != hit_object) {
+ continue;
+ }
+
+ if (metaelem_id != (hitresult & 0xFFFF0000 & ~(MBALLSEL_ANY))) {
+ continue;
+ }
+
+ if (hitresult & MBALLSEL_RADIUS) {
+ ml->flag |= MB_SCALE_RAD;
+ ml_act = ml;
+ break;
+ }
+
+ if (hitresult & MBALLSEL_STIFF) {
+ ml->flag &= ~MB_SCALE_RAD;
+ ml_act = ml;
+ break;
+ }
+ }
+
+ if (ml_act) break;
+ ml = ml->next;
+ if (ml == NULL) ml = mb->editelems->first;
+ if (ml == startelem) break;
+
+ metaelem_id += 0x10000;
}
- else if (toggle) {
- if (ml_act->flag & SELECT)
+
+ /* When some metaelem was found, then it is necessary to select or
+ * deselect it. */
+ if (ml_act) {
+ if (!extend && !deselect && !toggle) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc.view_layer, vc.v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+
+ if (ob_iter == base->object) {
+ continue;
+ }
+
+ BKE_mball_deselect_all((MetaBall *)ob_iter->data);
+ DEG_id_tag_update(ob_iter->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
+ }
+ MEM_freeN(objects);
+ }
+
+ if (extend) {
+ ml_act->flag |= SELECT;
+ }
+ else if (deselect) {
ml_act->flag &= ~SELECT;
- else
+ }
+ else if (toggle) {
+ if (ml_act->flag & SELECT)
+ ml_act->flag &= ~SELECT;
+ else
+ ml_act->flag |= SELECT;
+ }
+ else {
+ /* Deselect all existing metaelems */
+ BKE_mball_deselect_all(mb);
+
+ /* Select only metaelem clicked on */
ml_act->flag |= SELECT;
- }
- else {
- /* Deselect all existing metaelems */
- BKE_mball_deselect_all(mb);
+ }
- /* Select only metaelem clicked on */
- ml_act->flag |= SELECT;
- }
+ mb->lastelem = ml_act;
- mb->lastelem = ml_act;
+ DEG_id_tag_update(&mb->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ if (vc.view_layer->basact != base) {
+ ED_object_base_activate(C, base);
+ }
- return true;
+ return true;
+ }
}
- }
+ } FOREACH_BASE_IN_EDIT_MODE_END;
return false;
}
diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c
index b277584ab9e..0e029e36e0e 100644
--- a/source/blender/editors/metaball/mball_ops.c
+++ b/source/blender/editors/metaball/mball_ops.c
@@ -37,6 +37,7 @@
#include "ED_mball.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_object.h"
#include "mball_intern.h"
@@ -69,31 +70,6 @@ void ED_operatormacros_metaball(void)
void ED_keymap_metaball(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
- keymap = WM_keymap_ensure(keyconf, "Metaball", 0, 0);
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Metaball", 0, 0);
keymap->poll = ED_operator_editmball;
-
- WM_keymap_add_item(keymap, "OBJECT_OT_metaball_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "MBALL_OT_reveal_metaelems", HKEY, KM_PRESS, KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "MBALL_OT_hide_metaelems", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "MBALL_OT_hide_metaelems", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- WM_keymap_add_item(keymap, "MBALL_OT_delete_metaelems", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MBALL_OT_delete_metaelems", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MBALL_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
-
- kmi = WM_keymap_add_item(keymap, "MBALL_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "MBALL_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "MBALL_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
-
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_editmode(keyconf, keymap, true);
}
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 24740a3372b..17359934c6e 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -24,11 +24,15 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../depsgraph
../../gpu
../../ikplugin
../../imbuf
../../makesdna
../../makesrna
+ ../../modifiers
+ ../../gpencil_modifiers
+ ../../shader_fx
../../python
../../render/extern/include
../../windowmanager
@@ -44,13 +48,15 @@ set(SRC
object_add.c
object_bake.c
object_bake_api.c
+ object_collection.c
object_constraint.c
object_edit.c
- object_group.c
+ object_facemap_ops.c
object_hook.c
- object_lod.c
object_modes.c
object_modifier.c
+ object_gpencil_modifier.c
+ object_shader_fx.c
object_ops.c
object_random.c
object_relations.c
@@ -70,10 +76,6 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
-if(WITH_GAMEENGINE)
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index efc69c36cc3..8abef6f6793 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -30,13 +30,14 @@
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
@@ -45,9 +46,9 @@
#include "DNA_object_fluidsim_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_gpencil_types.h"
#include "BLI_utildefines.h"
@@ -63,34 +64,38 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_camera.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_font.h"
-#include "BKE_group.h"
+#include "BKE_gpencil.h"
+#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
-#include "BKE_key.h"
+#include "BKE_lightprobe.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_report.h"
-#include "BKE_sca.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_speaker.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -100,6 +105,7 @@
#include "ED_armature.h"
#include "ED_curve.h"
+#include "ED_gpencil.h"
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_node.h"
@@ -112,19 +118,16 @@
#include "UI_resources.h"
-#include "GPU_material.h"
-
#include "object_intern.h"
/* this is an exact copy of the define in rna_lamp.c
* kept here because of linking order.
* Icons are only defined here */
-const EnumPropertyItem rna_enum_lamp_type_items[] = {
- {LA_LOCAL, "POINT", ICON_LAMP_POINT, "Point", "Omnidirectional point light source"},
- {LA_SUN, "SUN", ICON_LAMP_SUN, "Sun", "Constant direction parallel ray light source"},
- {LA_SPOT, "SPOT", ICON_LAMP_SPOT, "Spot", "Directional cone light source"},
- {LA_HEMI, "HEMI", ICON_LAMP_HEMI, "Hemi", "180 degree constant light source"},
- {LA_AREA, "AREA", ICON_LAMP_AREA, "Area", "Directional area light source"},
+const EnumPropertyItem rna_enum_light_type_items[] = {
+ {LA_LOCAL, "POINT", ICON_LIGHT_POINT, "Point", "Omnidirectional point light source"},
+ {LA_SUN, "SUN", ICON_LIGHT_SUN, "Sun", "Constant direction parallel ray light source"},
+ {LA_SPOT, "SPOT", ICON_LIGHT_SPOT, "Spot", "Directional cone light source"},
+ {LA_AREA, "AREA", ICON_LIGHT_AREA, "Area", "Directional area light source"},
{0, NULL, 0, NULL, NULL}
};
@@ -146,17 +149,22 @@ static const EnumPropertyItem field_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static EnumPropertyItem lightprobe_type_items[] = {
+ {LIGHTPROBE_TYPE_CUBE, "CUBEMAP", ICON_LIGHTPROBE_CUBEMAP, "Reflection Cubemap",
+ "Reflection probe with spherical or cubic attenuation"},
+ {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_LIGHTPROBE_PLANAR, "Reflection Plane",
+ "Planar reflection probe"},
+ {LIGHTPROBE_TYPE_GRID, "GRID", ICON_LIGHTPROBE_GRID, "Irradiance Volume",
+ "Irradiance probe to capture diffuse indirect lighting"},
+ {0, NULL, 0, NULL, NULL}
+};
+
/************************** Exported *****************************/
void ED_object_location_from_view(bContext *C, float loc[3])
{
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const float *cursor;
-
- cursor = ED_view3d_cursor3d_get(scene, v3d);
-
- copy_v3_v3(loc, cursor);
+ const Scene *scene = CTX_data_scene(C);
+ copy_v3_v3(loc, scene->cursor.location);
}
void ED_object_rotation_from_quat(float rot[3], const float viewquat[4], const char align_axis)
@@ -207,6 +215,7 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3],
{
Object *ob = base->object;
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
if (!scene) return;
@@ -216,7 +225,7 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3],
if (rot)
copy_v3_v3(ob->rot, rot);
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
}
/* Uses context to figure out transform for primitive.
@@ -261,7 +270,12 @@ static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(sc
RNA_struct_idprops_unset(ptr, "rotation");
}
-void ED_object_add_unit_props(wmOperatorType *ot)
+void ED_object_add_unit_props_size(wmOperatorType *ot)
+{
+ RNA_def_float_distance(ot->srna, "size", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
+}
+
+void ED_object_add_unit_props_radius(wmOperatorType *ot)
{
RNA_def_float_distance(ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
}
@@ -287,22 +301,17 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
"Rotation", "Rotation for the newly added object",
DEG2RADF(-360.0f), DEG2RADF(360.0f));
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void ED_object_add_mesh_props(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "calc_uvs", false, "Generate UVs", "Generate a default UV map");
+ RNA_def_boolean(ot->srna, "calc_uvs", true, "Generate UVs", "Generate a default UV map");
}
bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view_align_axis,
float loc[3], float rot[3],
- bool *enter_editmode, unsigned int *layer, bool *is_view_aligned)
+ bool *enter_editmode, bool *is_view_aligned)
{
- View3D *v3d = CTX_wm_view3d(C);
- unsigned int _layer;
PropertyRNA *prop;
/* Switch to Edit mode? optional prop */
@@ -319,37 +328,6 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
}
}
- /* Get layers! */
- {
- int a;
- bool layer_values[20];
- if (!layer)
- layer = &_layer;
-
- prop = RNA_struct_find_property(op->ptr, "layers");
- if (RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_get_array(op->ptr, prop, layer_values);
- *layer = 0;
- for (a = 0; a < 20; a++) {
- if (layer_values[a])
- *layer |= (1 << a);
- }
- }
- else {
- Scene *scene = CTX_data_scene(C);
- *layer = BKE_screen_view3d_layer_active_ex(v3d, scene, false);
- for (a = 0; a < 20; a++) {
- layer_values[a] = (*layer & (1 << a)) != 0;
- }
- RNA_property_boolean_set_array(op->ptr, prop, layer_values);
- }
-
- /* in local view we additionally add local view layers,
- * not part of operator properties */
- if (v3d && v3d->localvd)
- *layer |= v3d->lay;
- }
-
/* Location! */
{
float _loc[3];
@@ -391,11 +369,6 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
RNA_float_get_array(op->ptr, "rotation", rot);
}
- if (layer && *layer == 0) {
- BKE_report(op->reports, RPT_ERROR, "Property 'layer' has no values set");
- return false;
- }
-
return true;
}
@@ -405,10 +378,11 @@ Object *ED_object_add_type(
bContext *C,
int type, const char *name,
const float loc[3], const float rot[3],
- bool enter_editmode, unsigned int layer)
+ bool enter_editmode)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob;
/* for as long scene has editmode... */
@@ -416,25 +390,21 @@ Object *ED_object_add_type(
ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
}
- /* deselects all, sets scene->basact */
- ob = BKE_object_add(bmain, scene, type, name);
- BASACT->lay = ob->lay = layer;
+ /* deselects all, sets active object */
+ ob = BKE_object_add(bmain, scene, view_layer, type, name);
/* editor level activate, notifiers */
- ED_base_object_activate(C, BASACT);
+ ED_object_base_activate(C, view_layer->basact);
/* more editor stuff */
- ED_object_base_init_transform(C, BASACT, loc, rot);
-
- /* Ignore collisions by default for non-mesh objects */
- if (type != OB_MESH) {
- ob->body_type = OB_BODY_TYPE_NO_COLLISION;
- ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH); /* copied from rna_object.c */
- }
+ ED_object_base_init_transform(C, view_layer->basact, loc, rot);
- DAG_id_type_tag(bmain, ID_OB);
- DAG_relations_tag_update(bmain);
- if (ob->data) {
- ED_render_id_flush_update(bmain, ob->data);
+ /* TODO(sergey): This is weird to manually tag objects for update, better to
+ * use DEG_id_tag_update here perhaps.
+ */
+ DEG_id_type_tag(bmain, ID_OB);
+ DEG_relations_tag_update(bmain);
+ if (ob->data != NULL) {
+ DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE);
}
if (enter_editmode)
@@ -442,6 +412,9 @@ Object *ED_object_add_type(
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+
return ob;
}
@@ -450,15 +423,14 @@ static int object_add_exec(bContext *C, wmOperator *op)
{
Object *ob;
bool enter_editmode;
- unsigned int layer;
float loc[3], rot[3], radius;
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL))
return OPERATOR_CANCELLED;
radius = RNA_float_get(op->ptr, "radius");
- ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), NULL, loc, rot, enter_editmode, layer);
+ ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), NULL, loc, rot, enter_editmode);
if (ob->type == OB_LATTICE) {
/* lattice is a special case!
@@ -487,12 +459,94 @@ void OBJECT_OT_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 0, "Type", "");
ED_object_add_generic_props(ot, true);
}
+/********************** Add Probe Operator **********************/
+
+/* for object add operator */
+static const char *get_lightprobe_defname(int type)
+{
+ switch (type) {
+ case LIGHTPROBE_TYPE_GRID: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "IrradianceVolume");
+ case LIGHTPROBE_TYPE_PLANAR: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "ReflectionPlane");
+ case LIGHTPROBE_TYPE_CUBE: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "ReflectionCubemap");
+ default:
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "LightProbe");
+ }
+}
+
+static int lightprobe_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob;
+ LightProbe *probe;
+ int type;
+ bool enter_editmode;
+ float loc[3], rot[3];
+ float radius;
+
+ WM_operator_view3d_unit_defaults(C, op);
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL))
+ return OPERATOR_CANCELLED;
+
+ type = RNA_enum_get(op->ptr, "type");
+ radius = RNA_float_get(op->ptr, "radius");
+
+ ob = ED_object_add_type(C, OB_LIGHTPROBE, get_lightprobe_defname(type), loc, rot, false);
+ BKE_object_obdata_size_init(ob, radius);
+
+ probe = (LightProbe *)ob->data;
+ probe->type = type;
+
+ switch (type) {
+ case LIGHTPROBE_TYPE_GRID:
+ probe->distinf = 0.3f;
+ probe->falloff = 1.0f;
+ probe->clipsta = 0.01f;
+ break;
+ case LIGHTPROBE_TYPE_PLANAR:
+ probe->distinf = 0.1f;
+ probe->falloff = 0.5f;
+ probe->clipsta = 0.001f;
+ ob->empty_drawsize = 0.5f;
+ break;
+ case LIGHTPROBE_TYPE_CUBE:
+ probe->attenuation_type = LIGHTPROBE_SHAPE_ELIPSOID;
+ break;
+ default:
+ BLI_assert(!"LightProbe type not configured.");
+ break;
+ }
+
+ DEG_relations_tag_update(CTX_data_main(C));
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_lightprobe_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Light Probe";
+ ot->description = "Add a light probe object";
+ ot->idname = "OBJECT_OT_lightprobe_add";
+
+ /* api callbacks */
+ ot->exec = lightprobe_add_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", lightprobe_type_items, 0, "Type", "");
+
+ ED_object_add_unit_props_radius(ot);
+ ED_object_add_generic_props(ot, true);
+}
+
/********************* Add Effector Operator ********************/
/* for object add operator */
@@ -501,13 +555,12 @@ static int effector_add_exec(bContext *C, wmOperator *op)
Object *ob;
int type;
bool enter_editmode;
- unsigned int layer;
float loc[3], rot[3];
float mat[4][4];
float dia;
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL))
return OPERATOR_CANCELLED;
type = RNA_enum_get(op->ptr, "type");
@@ -516,7 +569,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
if (type == PFIELD_GUIDE) {
Curve *cu;
const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "CurveGuide");
- ob = ED_object_add_type(C, OB_CURVE, name, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_CURVE, name, loc, rot, false);
cu = ob->data;
cu->flag |= CU_PATH | CU_3D;
@@ -528,7 +581,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
}
else {
const char *name = CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Field");
- ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_EMPTY, name, loc, rot, false);
BKE_object_obdata_size_init(ob, dia);
if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX))
ob->empty_drawtype = OB_SINGLE_ARROW;
@@ -536,7 +589,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
ob->pd = object_add_collision_fields(type);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
return OPERATOR_FINISHED;
}
@@ -558,7 +611,7 @@ void OBJECT_OT_effector_add(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", field_type_items, 0, "Type", "");
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -571,16 +624,15 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
Object *ob;
Camera *cam;
bool enter_editmode;
- unsigned int layer;
float loc[3], rot[3];
/* force view align for cameras */
RNA_boolean_set(op->ptr, "view_align", true);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false);
if (v3d) {
if (v3d->camera == NULL)
@@ -627,21 +679,20 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
bool newob = false;
bool enter_editmode;
- unsigned int layer;
float loc[3], rot[3];
float mat[4][4];
float dia;
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL))
return OPERATOR_CANCELLED;
if (obedit == NULL || obedit->type != OB_MBALL) {
- obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_MBALL, NULL, loc, rot, true);
newob = true;
}
else {
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
@@ -676,7 +727,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", "");
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -686,17 +737,16 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
bool enter_editmode;
- unsigned int layer;
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL))
return OPERATOR_CANCELLED;
if (obedit && obedit->type == OB_FONT)
return OPERATOR_CANCELLED;
- obedit = ED_object_add_type(C, OB_FONT, NULL, loc, rot, enter_editmode, layer);
+ obedit = ED_object_add_type(C, OB_FONT, NULL, loc, rot, enter_editmode);
BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius"));
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
@@ -719,7 +769,7 @@ void OBJECT_OT_text_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -731,21 +781,20 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
RegionView3D *rv3d = CTX_wm_region_view3d(C);
bool newob = false;
bool enter_editmode;
- unsigned int layer;
float loc[3], rot[3], dia;
bool view_aligned = rv3d && (U.flag & USER_ADD_VIEWALIGNED);
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, NULL))
return OPERATOR_CANCELLED;
if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) {
- obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true, layer);
+ obedit = ED_object_add_type(C, OB_ARMATURE, NULL, loc, rot, true);
ED_object_editmode_enter(C, 0);
newob = true;
}
else {
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
if (obedit == NULL) {
@@ -780,7 +829,7 @@ void OBJECT_OT_armature_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, true);
}
@@ -790,14 +839,13 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
{
Object *ob;
int type = RNA_enum_get(op->ptr, "type");
- unsigned int layer;
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false);
BKE_object_empty_draw_type_set(ob, type);
BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
@@ -823,7 +871,7 @@ void OBJECT_OT_empty_add(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_empty_drawtype_items, 0, "Type", "");
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, false);
}
@@ -831,9 +879,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
{
Scene *scene = CTX_data_scene(C);
- Base *base = NULL;
Image *ima = NULL;
- Object *ob = NULL;
ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
if (!ima) {
@@ -842,26 +888,22 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
/* handled below */
id_us_min((ID *)ima);
- base = ED_view3d_give_base_under_cursor(C, event->mval);
+ Object *ob = NULL;
+ Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval);
- /* if empty under cursor, then set object */
- if (base && base->object->type == OB_EMPTY) {
- ob = base->object;
+ /* either change empty under cursor or create a new empty */
+ if (ob_cursor && ob_cursor->type == OB_EMPTY) {
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ DEG_id_tag_update((ID *)ob_cursor, DEG_TAG_TRANSFORM);
+ ob = ob_cursor;
}
else {
- /* add new empty */
- unsigned int layer;
- float rot[3];
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, NULL, false);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &layer, NULL))
- return OPERATOR_CANCELLED;
-
- ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, layer);
-
- /* add under the mouse */
ED_object_location_from_view(C, ob->loc);
- ED_view3d_cursor3d_position(C, event->mval, ob->loc);
+ ED_view3d_cursor3d_position(C, event->mval, false, ob->loc);
+ ED_object_rotation_from_view(C, ob->rot, 'Z');
+ ob->empty_drawsize = 5.0f;
}
BKE_object_empty_draw_type_set(ob, OB_EMPTY_IMAGE);
@@ -899,41 +941,171 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
ED_object_add_generic_props(ot, false);
}
-/********************* Add Lamp Operator ********************/
+/********************* Add Gpencil Operator ********************/
+
+static int object_gpencil_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL;
+
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ float loc[3], rot[3];
+ bool newob = false;
+
+ /* Note: We use 'Y' here (not 'Z'), as */
+ WM_operator_view3d_unit_defaults(C, op);
+ if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, NULL))
+ return OPERATOR_CANCELLED;
+
+ /* add new object if not currently editing a GP object,
+ * or if "empty" was chosen (i.e. user wants a blank GP canvas)
+ */
+ if ((gpd == NULL) || (GPENCIL_ANY_MODE(gpd) == false) || (type == GP_EMPTY)) {
+ const char *ob_name = NULL;
+ switch (type) {
+ case GP_MONKEY:
+ {
+ ob_name = "Suzanne";
+ break;
+ }
+ case GP_STROKE:
+ {
+ ob_name = "Stroke";
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ float radius = RNA_float_get(op->ptr, "radius");
+ ob = ED_object_add_type(C, OB_GPENCIL, ob_name, loc, rot, true);
+ gpd = ob->data;
+ newob = true;
+
+ BKE_object_obdata_size_init(ob, GP_OBGPENCIL_DEFAULT_SIZE * radius);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_ADDED, NULL);
+ }
+
+ /* create relevant geometry */
+ switch (type) {
+ case GP_STROKE:
+ {
+ float radius = RNA_float_get(op->ptr, "radius");
+ float mat[4][4];
+
+ ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
+ mul_v3_fl(mat[0], radius);
+ mul_v3_fl(mat[1], radius);
+ mul_v3_fl(mat[2], radius);
+
+ ED_gpencil_create_stroke(C, mat);
+ break;
+ }
+ case GP_MONKEY:
+ {
+ float radius = RNA_float_get(op->ptr, "radius");
+ float mat[4][4];
+
+ ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
+ mul_v3_fl(mat[0], radius);
+ mul_v3_fl(mat[1], radius);
+ mul_v3_fl(mat[2], radius);
+
+ ED_gpencil_create_monkey(C, mat);
+ break;
+ }
+ case GP_EMPTY:
+ /* do nothing */
+ break;
+
+ default:
+ BKE_report(op->reports, RPT_WARNING, "Not implemented");
+ break;
+ }
+
+ /* if this is a new object, initialise default stuff (colors, etc.) */
+ if (newob) {
+ ED_gpencil_add_defaults(C);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_gpencil_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Grease Pencil";
+ ot->description = "Add a Grease Pencil object to the scene";
+ ot->idname = "OBJECT_OT_gpencil_add";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = object_gpencil_add_exec;
+ ot->poll = ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ED_object_add_unit_props_radius(ot);
+ ED_object_add_generic_props(ot, false);
+
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
+}
+
+/********************* Add Light Operator ********************/
-static const char *get_lamp_defname(int type)
+static const char *get_light_defname(int type)
{
switch (type) {
case LA_LOCAL: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Point");
case LA_SUN: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Sun");
case LA_SPOT: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Spot");
- case LA_HEMI: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Hemi");
case LA_AREA: return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Area");
default:
- return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Lamp");
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_LAMP, "Light");
}
}
-static int object_lamp_add_exec(bContext *C, wmOperator *op)
+static int object_light_add_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *ob;
Lamp *la;
int type = RNA_enum_get(op->ptr, "type");
- unsigned int layer;
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_LAMP, get_lamp_defname(type), loc, rot, false, layer);
- BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
+ ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false);
+
+ float size = RNA_float_get(op->ptr, "radius");
+ /* Better defaults for light size. */
+ switch (type) {
+ case LA_LOCAL:
+ case LA_SPOT:
+ break;
+ case LA_AREA:
+ size *= 4.0f;
+ break;
+ default:
+ size *= 0.5f;
+ break;
+ }
+ BKE_object_obdata_size_init(ob, size);
la = (Lamp *)ob->data;
la->type = type;
- if (BKE_scene_use_new_shading_nodes(scene)) {
+ if (BKE_scene_uses_cycles(scene)) {
ED_node_shader_default(C, &la->id);
la->use_nodes = true;
}
@@ -941,43 +1113,42 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void OBJECT_OT_lamp_add(wmOperatorType *ot)
+void OBJECT_OT_light_add(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Lamp";
- ot->description = "Add a lamp object to the scene";
- ot->idname = "OBJECT_OT_lamp_add";
+ ot->name = "Add Light";
+ ot->description = "Add a light object to the scene";
+ ot->idname = "OBJECT_OT_light_add";
/* api callbacks */
ot->invoke = WM_menu_invoke;
- ot->exec = object_lamp_add_exec;
+ ot->exec = object_light_add_exec;
ot->poll = ED_operator_objectmode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_lamp_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_light_type_items, 0, "Type", "");
RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_LAMP);
- ED_object_add_unit_props(ot);
+ ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, false);
}
-/********************* Add Group Instance Operator ********************/
+/********************* Add Collection Instance Operator ********************/
-static int group_instance_add_exec(bContext *C, wmOperator *op)
+static int collection_instance_add_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Group *group;
- unsigned int layer;
+ Collection *collection;
float loc[3], rot[3];
if (RNA_struct_property_is_set(op->ptr, "name")) {
char name[MAX_ID_NAME - 2];
RNA_string_get(op->ptr, "name", name);
- group = (Group *)BKE_libblock_find_name(bmain, ID_GR, name);
+ collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
if (0 == RNA_struct_property_is_set(op->ptr, "location")) {
const wmEvent *event = CTX_wm_window(C)->eventstate;
@@ -985,26 +1156,34 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
const int mval[2] = {event->x - ar->winrct.xmin,
event->y - ar->winrct.ymin};
ED_object_location_from_view(C, loc);
- ED_view3d_cursor3d_position(C, mval, loc);
+ ED_view3d_cursor3d_position(C, mval, false, loc);
RNA_float_set_array(op->ptr, "location", loc);
}
}
else
- group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group"));
+ collection = BLI_findlink(&CTX_data_main(C)->collection, RNA_enum_get(op->ptr, "collection"));
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL))
return OPERATOR_CANCELLED;
- if (group) {
+ if (collection) {
Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer);
- ob->dup_group = group;
- ob->transflag |= OB_DUPLIGROUP;
- id_us_plus(&group->id);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- /* works without this except if you try render right after, see: 22027 */
- DAG_relations_tag_update(bmain);
+ /* Avoid dependency cycles. */
+ LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
+ while (BKE_collection_find_cycle(active_lc->collection, collection)) {
+ active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
+ }
+ Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, loc, rot, false);
+ ob->dup_group = collection;
+ ob->transflag |= OB_DUPLICOLLECTION;
+ id_us_plus(&collection->id);
+
+ /* works without this except if you try render right after, see: 22027 */
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
return OPERATOR_FINISHED;
@@ -1014,27 +1193,27 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
}
/* only used as menu */
-void OBJECT_OT_group_instance_add(wmOperatorType *ot)
+void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Group Instance";
- ot->description = "Add a dupligroup instance";
- ot->idname = "OBJECT_OT_group_instance_add";
+ ot->name = "Add Collection Instance";
+ ot->description = "Add a collection instance";
+ ot->idname = "OBJECT_OT_collection_instance_add";
/* api callbacks */
ot->invoke = WM_enum_search_invoke;
- ot->exec = group_instance_add_exec;
+ ot->exec = collection_instance_add_exec;
ot->poll = ED_operator_objectmode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Group name to add");
- prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "");
- RNA_def_enum_funcs(prop, RNA_group_itemf);
+ RNA_def_string(ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Collection name to add");
+ prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "");
+ RNA_def_enum_funcs(prop, RNA_collection_itemf);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
ED_object_add_generic_props(ot, false);
@@ -1045,14 +1224,13 @@ void OBJECT_OT_group_instance_add(wmOperatorType *ot)
static int object_speaker_add_exec(bContext *C, wmOperator *op)
{
Object *ob;
- unsigned int layer;
float loc[3], rot[3];
Scene *scene = CTX_data_scene(C);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL))
return OPERATOR_CANCELLED;
- ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, layer);
+ ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false);
/* to make it easier to start using this immediately in NLA, a default sound clip is created
* ready to be moved around to retime the sound and/or make new sound clips
@@ -1097,35 +1275,22 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot)
/**************************** Delete Object *************************/
-static void object_delete_check_glsl_update(Object *ob)
-{
- /* some objects could affect on GLSL shading, make sure GLSL settings
- * are being tagged to be updated when object is removing from scene
- */
- if (ob->type == OB_LAMP) {
- if (ob->gpulamp.first)
- GPU_lamp_free(ob);
- }
-}
-
/* remove base from a specific scene */
/* note: now unlinks constraints as well */
-void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base)
+void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
{
- if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
- ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
+ if (BKE_library_ID_is_indirectly_used(bmain, ob) &&
+ ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0)
{
/* We cannot delete indirectly used object... */
printf("WARNING, undeletable object '%s', should have been catched before reaching this function!",
- base->object->id.name + 2);
+ ob->id.name + 2);
return;
}
- BKE_scene_base_unlink(scene, base);
- object_delete_check_glsl_update(base->object);
- BKE_libblock_free_us(bmain, base->object);
- MEM_freeN(base);
- DAG_id_type_tag(bmain, ID_OB);
+ DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_BASE_FLAGS_UPDATE);
+
+ BKE_scene_collections_object_remove(bmain, scene, ob, true);
}
static int object_delete_exec(bContext *C, wmOperator *op)
@@ -1135,34 +1300,40 @@ static int object_delete_exec(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win;
const bool use_global = RNA_boolean_get(op->ptr, "use_global");
- bool changed = false;
+ uint changed_count = 0;
if (CTX_data_edit_object(C))
return OPERATOR_CANCELLED;
- CTX_DATA_BEGIN (C, Base *, base, selected_bases)
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
- const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object);
- if (base->object->id.tag & LIB_TAG_INDIRECT) {
+ const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, ob);
+ if (ob->id.tag & LIB_TAG_INDIRECT) {
/* Can this case ever happen? */
- BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2);
continue;
}
- else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) {
+ else if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) {
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);
+ ob->id.name + 2, scene->id.name + 2);
continue;
}
+ /* if grease pencil object, set cache as dirty */
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+
/* This is sort of a quick hack to address T51243 - Proper thing to do here would be to nuke most of all this
* custom scene/object/base handling, and use generic lib remap/query for that.
* But this is for later (aka 2.8, once layers & co are settled and working).
*/
- if (use_global && base->object->id.lib == NULL) {
+ if (use_global && ob->id.lib == NULL) {
/* We want to nuke the object, let's nuke it the easy way (not for linked data though)... */
- BKE_libblock_delete(bmain, &base->object->id);
- changed = true;
+ BKE_libblock_delete(bmain, &ob->id);
+ changed_count += 1;
continue;
}
@@ -1172,38 +1343,28 @@ static int object_delete_exec(bContext *C, wmOperator *op)
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) {
+ if (gpl->parent == ob) {
gpl->parent = NULL;
}
}
}
}
- /* deselect object -- it could be used in other scenes */
- base->object->flag &= ~SELECT;
-
/* remove from current scene only */
- ED_base_object_free_and_unlink(bmain, scene, base);
- changed = true;
+ ED_object_base_free_and_unlink(bmain, scene, ob);
+ changed_count += 1;
if (use_global) {
Scene *scene_iter;
- Base *base_other;
-
for (scene_iter = bmain->scene.first; scene_iter; scene_iter = scene_iter->id.next) {
if (scene_iter != scene && !ID_IS_LINKED(scene_iter)) {
- base_other = BKE_scene_base_find(scene_iter, base->object);
- if (base_other) {
- if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) {
- 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_iter->id.name + 2);
- break;
- }
- ED_base_object_free_and_unlink(bmain, scene_iter, base_other);
+ if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user",
+ ob->id.name + 2, scene_iter->id.name + 2);
+ break;
}
+ ED_object_base_free_and_unlink(bmain, scene_iter, ob);
}
}
}
@@ -1211,19 +1372,23 @@ static int object_delete_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- if (!changed)
+ BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", changed_count);
+
+ if (changed_count == 0) {
return OPERATOR_CANCELLED;
+ }
/* delete has to handle all open scenes */
BKE_main_id_tag_listbase(&bmain->scene, LIB_TAG_DOIT, true);
for (win = wm->windows.first; win; win = win->next) {
- scene = win->screen->scene;
+ scene = WM_window_get_active_scene(win);
if (scene->id.tag & LIB_TAG_DOIT) {
scene->id.tag &= ~LIB_TAG_DOIT;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
}
@@ -1240,14 +1405,17 @@ void OBJECT_OT_delete(wmOperatorType *ot)
ot->idname = "OBJECT_OT_delete";
/* api callbacks */
- ot->invoke = WM_operator_confirm;
+ ot->invoke = WM_operator_confirm_or_exec;
ot->exec = object_delete_exec;
ot->poll = ED_operator_objectmode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "use_global", 0, "Delete Globally", "Remove object from all scenes");
+ PropertyRNA *prop;
+ prop = RNA_def_boolean(ot->srna, "use_global", 0, "Delete Globally", "Remove object from all scenes");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ WM_operator_properties_confirm_or_exec(ot);
}
/**************************** Copy Utilities ******************************/
@@ -1263,15 +1431,13 @@ static void copy_object_set_idnew(bContext *C)
}
CTX_DATA_END;
- set_sca_new_poins();
-
BKE_main_id_clear_newpoins(bmain);
}
/********************* Make Duplicates Real ************************/
/**
- * \note regarding hashing dupli-objects when using OB_DUPLIGROUP, skip the first member of #DupliObject.persistent_id
+ * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, skip the first member of #DupliObject.persistent_id
* since its a unique index and we only want to know if the group objects are from the same dupli-group instance.
*/
static unsigned int dupliobject_group_hash(const void *ptr)
@@ -1286,7 +1452,7 @@ static unsigned int dupliobject_group_hash(const void *ptr)
}
/**
- * \note regarding hashing dupli-objects when NOT using OB_DUPLIGROUP, include the first member of #DupliObject.persistent_id
+ * \note regarding hashing dupli-objects when NOT using OB_DUPLICOLLECTION, include the first member of #DupliObject.persistent_id
* since its the index of the vertex/face the object is instantiated on and we want to identify objects on the same vertex/face.
*/
static unsigned int dupliobject_hash(const void *ptr)
@@ -1344,6 +1510,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
const bool use_hierarchy)
{
Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ListBase *lb_duplis;
DupliObject *dob;
GHash *dupli_gh, *parent_gh = NULL;
@@ -1352,11 +1520,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
return;
}
- lb_duplis = object_duplilist(bmain, bmain->eval_ctx, scene, base->object);
+ lb_duplis = object_duplilist(depsgraph, scene, base->object);
dupli_gh = BLI_ghash_ptr_new(__func__);
if (use_hierarchy) {
- if (base->object->transflag & OB_DUPLIGROUP) {
+ if (base->object->transflag & OB_DUPLICOLLECTION) {
parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__);
}
else {
@@ -1376,12 +1544,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
ob_dst->totcol = 0;
}
- base_dst = MEM_dupallocN(base);
- base_dst->flag &= ~(OB_FROMDUPLI | OB_FROMGROUP);
- ob_dst->flag = base_dst->flag;
- base_dst->lay = base->lay;
- BLI_addhead(&scene->base, base_dst); /* addhead: othwise eternal loop */
- base_dst->object = ob_dst;
+ BKE_collection_object_add_from(bmain, scene, base->object, ob_dst);
+ base_dst = BKE_view_layer_base_find(view_layer, ob_dst);
+ BLI_assert(base_dst != NULL);
+
+ BKE_scene_object_base_flag_sync_from_base(base_dst);
/* make sure apply works */
BKE_animdata_free(&ob_dst->id, true);
@@ -1394,9 +1561,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
ob_dst->parent = NULL;
BKE_constraints_free(&ob_dst->constraints);
- ob_dst->curve_cache = NULL;
+ ob_dst->runtime.curve_cache = NULL;
ob_dst->transflag &= ~OB_DUPLI;
- ob_dst->lay = base->lay;
copy_m4_m4(ob_dst->obmat, dob->mat);
BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false);
@@ -1418,9 +1584,8 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
/* Remap new object to itself, and clear again newid pointer of orig object. */
BKE_libblock_relink_to_newid(&ob_dst->id);
- set_sca_new_poins_ob(ob_dst);
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
if (use_hierarchy) {
/* original parents */
@@ -1433,7 +1598,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
* they won't be read, this is simply for a hash lookup. */
DupliObject dob_key;
dob_key.ob = ob_src_par;
- if (base->object->transflag & OB_DUPLIGROUP) {
+ if (base->object->transflag & OB_DUPLICOLLECTION) {
memcpy(&dob_key.persistent_id[1],
&dob->persistent_id[1],
sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
@@ -1473,17 +1638,17 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
* still work out ok */
BKE_object_apply_mat4(ob_dst, dob->mat, false, true);
- /* to set ob_dst->orig and in case theres any other discrepicies */
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
+ /* to set ob_dst->orig and in case there's any other discrepancies */
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB);
}
}
- if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) {
+ if (base->object->transflag & OB_DUPLICOLLECTION && base->object->dup_group) {
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->proxy_group == base->object) {
ob->proxy = NULL;
ob->proxy_from = NULL;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
}
@@ -1519,7 +1684,7 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE, scene);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
@@ -1553,46 +1718,46 @@ static const EnumPropertyItem convert_target_items[] = {
{0, NULL, 0, NULL, NULL}
};
-static void convert_ensure_curve_cache(Main *bmain, Scene *scene, Object *ob)
+static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- if (ob->curve_cache == NULL) {
+ if (ob->runtime.curve_cache == NULL) {
/* Force creation. This is normally not needed but on operator
* redo we might end up with an object which isn't evaluated yet.
+ * Also happens in case we are working on a copy of the object (all its caches have been nuked then).
*/
if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
- BKE_displist_make_curveTypes(scene, ob, false);
+ /* We need 'for render' ON here, to enable computing bevel dipslist if needed.
+ * Also makes sense anyway, we would not want e.g. to loose hidden parts etc. */
+ BKE_displist_make_curveTypes(depsgraph, scene, ob, true, false);
}
else if (ob->type == OB_MBALL) {
- BKE_displist_make_mball(bmain, bmain->eval_ctx, scene, ob);
+ BKE_displist_make_mball(depsgraph, scene, ob);
}
}
}
-static void curvetomesh(Main *bmain, Scene *scene, Object *ob)
+static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- convert_ensure_curve_cache(bmain, scene, ob);
+ convert_ensure_curve_cache(depsgraph, scene, ob);
BKE_mesh_from_nurbs(bmain, ob); /* also does users */
if (ob->type == OB_MESH) {
BKE_object_free_modifiers(ob, 0);
-
- /* Game engine defaults for mesh objects */
- ob->body_type = OB_BODY_TYPE_STATIC;
- ob->gameflag = OB_PROP | OB_COLLISION;
}
}
static bool convert_poll(bContext *C)
{
- Object *obact = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
+ Base *base_act = CTX_data_active_base(C);
+ Object *obact = base_act ? base_act->object : NULL;
- return (!ID_IS_LINKED(scene) && obact && scene->obedit != obact &&
- (obact->flag & SELECT) && !ID_IS_LINKED(obact));
+ return (!ID_IS_LINKED(scene) && obact && (BKE_object_is_in_editmode(obact) == false) &&
+ (base_act->flag & BASE_SELECTED) && !ID_IS_LINKED(obact));
}
/* Helper for convert_exec */
-static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object *ob)
+static Base *duplibase_for_convert(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob)
{
Object *obn;
Base *basen;
@@ -1602,27 +1767,23 @@ static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object
}
obn = BKE_object_copy(bmain, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
- basen = MEM_mallocN(sizeof(Base), "duplibase");
- *basen = *base;
- BLI_addhead(&scene->base, basen); /* addhead: otherwise eternal loop */
- basen->object = obn;
- basen->flag |= SELECT;
- obn->flag |= SELECT;
- base->flag &= ~SELECT;
- ob->flag &= ~SELECT;
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ BKE_collection_object_add_from(bmain, scene, ob, obn);
+ basen = BKE_view_layer_base_find(view_layer, obn);
+ ED_object_base_select(basen, BA_SELECT);
+ ED_object_base_select(basen, BA_DESELECT);
return basen;
}
static int convert_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Base *basen = NULL, *basact = NULL;
- Object *ob, *ob1, *obact = CTX_data_active_object(C);
- DerivedMesh *dm;
+ Object *ob1, *obact = CTX_data_active_object(C);
Curve *cu;
Nurb *nu;
MetaBall *mb;
@@ -1634,13 +1795,11 @@ static int convert_exec(bContext *C, wmOperator *op)
/* don't forget multiple users! */
{
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- ob = base->object;
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
+ {
ob->flag &= ~OB_DONE;
- /* flag data thats not been edited (only needed for !keep_original) */
+ /* flag data that's not been edited (only needed for !keep_original) */
if (ob->data) {
((ID *)ob->data)->tag |= LIB_TAG_DOIT;
}
@@ -1649,13 +1808,14 @@ static int convert_exec(bContext *C, wmOperator *op)
if (ob->type == OB_MBALL && target == OB_MESH) {
if (BKE_mball_is_basis(ob) == false) {
Object *ob_basis;
- ob_basis = BKE_mball_basis_find(bmain, bmain->eval_ctx, scene, ob);
+ ob_basis = BKE_mball_basis_find(scene, ob);
if (ob_basis) {
ob_basis->flag &= ~OB_DONE;
}
}
}
}
+ FOREACH_SCENE_OBJECT_END;
}
ListBase selected_editable_bases = CTX_data_collection_get(C, "selected_editable_bases");
@@ -1666,9 +1826,9 @@ static int convert_exec(bContext *C, wmOperator *op)
{
for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
Base *base = link->ptr.data;
- ob = base->object;
+ Object *ob = base->object;
- /* The way object type conversion works currently (enforcing conversion of *all* objetcs using converted
+ /* The way object type conversion works currently (enforcing conversion of *all* objects using converted
* obdata, even some un-selected/hidden/inother scene ones, sounds totally bad to me.
* However, changing this is more design than bugfix, not to mention convoluted code below,
* so that will be for later.
@@ -1679,19 +1839,19 @@ static int convert_exec(bContext *C, wmOperator *op)
"Converting some linked object/object data, enforcing 'Keep Original' option to True");
}
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
}
uint64_t customdata_mask_prev = scene->customdata_mask;
scene->customdata_mask |= CD_MASK_MESH;
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
scene->customdata_mask = customdata_mask_prev;
}
for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
Object *newob = NULL;
Base *base = link->ptr.data;
- ob = base->object;
+ Object *ob = base->object;
if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) {
if (ob->type != target) {
@@ -1706,13 +1866,17 @@ static int convert_exec(bContext *C, wmOperator *op)
if (ob->type == OB_MESH) {
BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */
}
+ if (ob->type == OB_GPENCIL) {
+ BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */
+ BKE_object_free_shaderfx(ob, 0);
+ }
}
}
else if (ob->type == OB_MESH && target == OB_CURVE) {
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(bmain, scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL);
newob = basen->object;
/* decrement original mesh's usage count */
@@ -1726,7 +1890,7 @@ static int convert_exec(bContext *C, wmOperator *op)
newob = ob;
}
- BKE_mesh_to_curve(bmain, scene, newob);
+ BKE_mesh_to_curve(bmain, depsgraph, scene, newob);
if (newob->type == OB_CURVE) {
BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
@@ -1737,7 +1901,7 @@ static int convert_exec(bContext *C, wmOperator *op)
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(bmain, scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL);
newob = basen->object;
/* decrement original mesh's usage count */
@@ -1749,26 +1913,25 @@ static int convert_exec(bContext *C, wmOperator *op)
}
else {
newob = ob;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
/* make new mesh data from the original copy */
/* note: get the mesh from the original, not from the copy in some
- * cases this doesnt give correct results (when MDEF is used for eg)
+ * cases this doesn't give correct results (when MDEF is used for eg)
*/
- dm = mesh_get_derived_final(scene, newob, CD_MASK_MESH);
-
- DM_to_mesh(dm, newob->data, newob, CD_MASK_MESH, true);
-
- /* re-tessellation is called by DM_to_mesh */
-
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, newob, CD_MASK_MESH);
+ if (newob->runtime.mesh_eval == me_eval) {
+ newob->runtime.mesh_eval = NULL;
+ }
+ BKE_mesh_nomain_to_mesh(me_eval, newob->data, newob, CD_MASK_MESH, true);
BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
}
else if (ob->type == OB_FONT) {
ob->flag |= OB_DONE;
if (keep_original) {
- basen = duplibase_for_convert(bmain, scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL);
newob = basen->object;
/* decrement original curve's usage count */
@@ -1787,6 +1950,7 @@ static int convert_exec(bContext *C, wmOperator *op)
* datablock, but for until we've got granular update
* lets take care by selves.
*/
+ /* XXX This may fail/crash, since BKE_vfont_to_curve() accesses evaluated data in some cases (bastien). */
BKE_vfont_to_curve(newob, FO_EDIT);
newob->type = OB_CURVE;
@@ -1815,7 +1979,7 @@ static int convert_exec(bContext *C, wmOperator *op)
for (ob1 = bmain->object.first; ob1; ob1 = ob1->id.next) {
if (ob1->data == ob->data) {
ob1->type = OB_CURVE;
- DAG_id_tag_update(&ob1->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob1->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
}
}
@@ -1828,7 +1992,7 @@ static int convert_exec(bContext *C, wmOperator *op)
BKE_curve_curve_dimension_update(cu);
if (target == OB_MESH) {
- curvetomesh(bmain, scene, newob);
+ curvetomesh(bmain, depsgraph, scene, newob);
/* meshes doesn't use displist */
BKE_object_free_curve_cache(newob);
@@ -1839,7 +2003,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (target == OB_MESH) {
if (keep_original) {
- basen = duplibase_for_convert(bmain, scene, base, NULL);
+ basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL);
newob = basen->object;
/* decrement original curve's usage count */
@@ -1852,7 +2016,7 @@ static int convert_exec(bContext *C, wmOperator *op)
newob = ob;
}
- curvetomesh(bmain, scene, newob);
+ curvetomesh(bmain, depsgraph, scene, newob);
/* meshes doesn't use displist */
BKE_object_free_curve_cache(newob);
@@ -1861,10 +2025,10 @@ static int convert_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_MBALL && target == OB_MESH) {
Object *baseob;
- base->flag &= ~SELECT;
- ob->flag &= ~SELECT;
+ base->flag &= ~BASE_SELECTED;
+ ob->base_flag &= ~BASE_SELECTED;
- baseob = BKE_mball_basis_find(bmain, bmain->eval_ctx, scene, ob);
+ baseob = BKE_mball_basis_find(scene, ob);
if (ob != baseob) {
/* if motherball is converting it would be marked as done later */
@@ -1874,7 +2038,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (!(baseob->flag & OB_DONE)) {
baseob->flag |= OB_DONE;
- basen = duplibase_for_convert(bmain, scene, base, baseob);
+ basen = duplibase_for_convert(bmain, scene, view_layer, base, baseob);
newob = basen->object;
mb = newob->data;
@@ -1890,8 +2054,8 @@ static int convert_exec(bContext *C, wmOperator *op)
for (a = 0; a < newob->totcol; a++) id_us_plus((ID *)me->mat[a]);
}
- convert_ensure_curve_cache(bmain, scene, baseob);
- BKE_mesh_from_metaball(&baseob->curve_cache->disp, newob->data);
+ convert_ensure_curve_cache(depsgraph, scene, baseob);
+ BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp, newob->data);
if (obact->type == OB_MBALL) {
basact = basen;
@@ -1922,7 +2086,7 @@ static int convert_exec(bContext *C, wmOperator *op)
}
if (!keep_original && (ob->flag & OB_DONE)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */
}
}
@@ -1930,27 +2094,21 @@ static int convert_exec(bContext *C, wmOperator *op)
if (!keep_original) {
if (mballConverted) {
- Base *base, *base_next;
-
- for (base = scene->base.first; base; base = base_next) {
- base_next = base->next;
-
- ob = base->object;
- if (ob->type == OB_MBALL) {
- if (ob->flag & OB_DONE) {
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob_mball)
+ {
+ if (ob_mball->type == OB_MBALL) {
+ if (ob_mball->flag & OB_DONE) {
Object *ob_basis = NULL;
- if (BKE_mball_is_basis(ob) ||
- ((ob_basis = BKE_mball_basis_find(bmain, bmain->eval_ctx, scene, ob)) && (ob_basis->flag & OB_DONE)))
+ if (BKE_mball_is_basis(ob_mball) ||
+ ((ob_basis = BKE_mball_basis_find(scene, ob_mball)) && (ob_basis->flag & OB_DONE)))
{
- ED_base_object_free_and_unlink(bmain, scene, base);
+ ED_object_base_free_and_unlink(bmain, scene, ob_mball);
}
}
}
}
+ FOREACH_SCENE_OBJECT_END;
}
-
- /* delete object should renew depsgraph */
- DAG_relations_tag_update(bmain);
}
// XXX ED_object_editmode_enter(C, 0);
@@ -1958,15 +2116,16 @@ static int convert_exec(bContext *C, wmOperator *op)
if (basact) {
/* active base was changed */
- ED_base_object_activate(C, basact);
- BASACT = basact;
+ ED_object_base_activate(C, basact);
+ BASACT(view_layer) = basact;
}
- else if (BASACT->object->flag & OB_DONE) {
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT->object);
- WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT->object);
+ else if (BASACT(view_layer)->object->flag & OB_DONE) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, BASACT(view_layer)->object);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DATA, BASACT(view_layer)->object);
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -2005,39 +2164,44 @@ void OBJECT_OT_convert(wmOperatorType *ot)
/* used below, assumes id.new is correct */
/* leaves selection of base/object unaltered */
/* Does set ID->newid pointers. */
-static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base, int dupflag)
+static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob, int dupflag)
{
#define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
#define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
- Base *basen = NULL;
+ Base *base, *basen = NULL;
Material ***matarar;
- Object *ob, *obn;
+ Object *obn;
ID *id;
int a, didit;
- ob = base->object;
if (ob->mode & OB_MODE_POSE) {
; /* nothing? */
}
else {
obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
- DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA);
- basen = MEM_mallocN(sizeof(Base), "duplibase");
- *basen = *base;
- BLI_addhead(&scene->base, basen); /* addhead: prevent eternal loop */
- basen->object = obn;
+ base = BKE_view_layer_base_find(view_layer, ob);
+ if ((base != NULL) && (base->flag & BASE_VISIBLE)) {
+ BKE_collection_object_add_from(bmain, scene, ob, obn);
+ }
+ else {
+ LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, obn);
+ }
+ basen = BKE_view_layer_base_find(view_layer, obn);
+ basen->local_view_bits = base->local_view_bits;
- /* 1) duplis should end up in same group as the original
- * 2) Rigid Body sim participants MUST always be part of a group...
+ /* 1) duplis should end up in same collection as the original
+ * 2) Rigid Body sim participants MUST always be part of a collection...
*/
// XXX: is 2) really a good measure here?
- if ((basen->flag & OB_FROMGROUP) || ob->rigidbody_object || ob->rigidbody_constraint) {
- Group *group;
- for (group = bmain->group.first; group; group = group->id.next) {
- if (BKE_group_object_exists(group, ob))
- BKE_group_object_add(group, obn, scene, basen);
+ if (ob->rigidbody_object || ob->rigidbody_constraint) {
+ Collection *collection;
+ for (collection = bmain->collection.first; collection; collection = collection->id.next) {
+ if (BKE_collection_has_object(collection, ob))
+ BKE_collection_object_add(bmain, collection, obn);
}
}
@@ -2053,6 +2217,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
ID_NEW_REMAP_US(obn->mat[a])
else {
obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a]));
+ /* duplicate grease pencil settings */
+ if (ob->mat[a]->gp_style) {
+ obn->mat[a]->gp_style = MEM_dupallocN(ob->mat[a]->gp_style);
+ }
}
id_us_min(id);
@@ -2146,14 +2314,14 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
}
break;
case OB_ARMATURE:
- DAG_id_tag_update(&obn->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obn->id, OB_RECALC_DATA);
if (obn->pose)
BKE_pose_tag_recalc(bmain, obn->pose);
if (dupflag & USER_DUP_ARM) {
ID_NEW_REMAP_US2(obn->data)
else {
obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data));
- BKE_pose_rebuild(obn, obn->data);
+ BKE_pose_rebuild(bmain, obn, obn->data, true);
didit = 1;
}
id_us_min(id);
@@ -2179,6 +2347,16 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
id_us_min(id);
}
break;
+ case OB_LIGHTPROBE:
+ if (dupflag != 0) {
+ ID_NEW_REMAP_US2(obn->data)
+ else {
+ obn->data = ID_NEW_SET(obn->data, BKE_lightprobe_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
case OB_SPEAKER:
if (dupflag != 0) {
ID_NEW_REMAP_US2(obn->data)
@@ -2189,6 +2367,16 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
id_us_min(id);
}
break;
+ case OB_GPENCIL:
+ if (dupflag != 0) {
+ ID_NEW_REMAP_US2(obn->data)
+ else {
+ obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data));
+ didit = 1;
+ }
+ id_us_min(id);
+ }
+ break;
}
/* check if obdata is copied */
@@ -2201,25 +2389,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
}
if (dupflag & USER_DUP_ACT) {
- bActuator *act;
-
BKE_animdata_copy_id_action(bmain, (ID *)obn->data, true);
if (key) {
BKE_animdata_copy_id_action(bmain, (ID *)key, true);
}
-
- /* Update the duplicated action in the action actuators */
- /* XXX TODO this code is all wrong! actact->act is user-refcounted (see readfile.c),
- * and what about other ID pointers of other BGE logic bricks,
- * and since this is object-level, why is it only ran if obdata was duplicated??? -mont29 */
- for (act = obn->actuators.first; act; act = act->next) {
- if (act->type == ACT_ACTION) {
- bActionActuator *actact = (bActionActuator *) act->data;
- if (ob->adt && actact->act == ob->adt->action) {
- actact->act = obn->adt->action;
- }
- }
- }
}
if (dupflag & USER_DUP_MAT) {
@@ -2250,14 +2423,12 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
* note: don't call this within a loop since clear_* funcs loop over the entire database.
* note: caller must do DAG_relations_tag_update(bmain);
* this is not done automatic since we may duplicate many objects in a batch */
-Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag)
+Base *ED_object_add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, int dupflag)
{
Base *basen;
Object *ob;
- clear_sca_new_poins(); /* BGE logic */
-
- basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
+ basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag);
if (basen == NULL) {
return NULL;
}
@@ -2266,12 +2437,11 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag
/* link own references to the newly duplicated data [#26816] */
BKE_libblock_relink_to_newid(&ob->id);
- set_sca_new_poins_ob(ob);
/* DAG_relations_tag_update(bmain); */ /* caller must do */
- if (ob->data) {
- ED_render_id_flush_update(bmain, ob->data);
+ if (ob->data != NULL) {
+ DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE);
}
BKE_main_id_clear_newpoins(bmain);
@@ -2284,29 +2454,29 @@ static int duplicate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool linked = RNA_boolean_get(op->ptr, "linked");
int dupflag = (linked) ? 0 : U.dupflag;
- clear_sca_new_poins(); /* BGE logic */
-
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
- Base *basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
+ Base *basen = object_add_duplicate_internal(bmain, scene, view_layer, base->object, dupflag);
/* note that this is safe to do with this context iterator,
* the list is made in advance */
- ED_base_object_select(base, BA_DESELECT);
+ ED_object_base_select(base, BA_DESELECT);
+ ED_object_base_select(basen, BA_SELECT);
if (basen == NULL) {
continue;
}
/* new object becomes active */
- if (BASACT == base)
- ED_base_object_activate(C, basen);
+ if (BASACT(view_layer) == base)
+ ED_object_base_activate(C, basen);
if (basen->object->data) {
- DAG_id_tag_update(basen->object->data, 0);
+ DEG_id_tag_update(basen->object->data, 0);
}
}
CTX_DATA_END;
@@ -2315,7 +2485,8 @@ static int duplicate_exec(bContext *C, wmOperator *op)
BKE_main_id_clear_newpoins(bmain);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -2351,9 +2522,9 @@ static int add_named_exec(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
const wmEvent *event = win ? win->eventstate : NULL;
Main *bmain = CTX_data_main(C);
- View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
Scene *scene = CTX_data_scene(C);
- Base *basen, *base;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Base *basen;
Object *ob;
const bool linked = RNA_boolean_get(op->ptr, "linked");
int dupflag = (linked) ? 0 : U.dupflag;
@@ -2368,22 +2539,15 @@ static int add_named_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- base = MEM_callocN(sizeof(Base), "duplibase");
- base->object = ob;
- base->flag = ob->flag;
-
/* prepare dupli */
- clear_sca_new_poins(); /* BGE logic */
-
- basen = object_add_duplicate_internal(bmain, scene, base, dupflag);
+ basen = object_add_duplicate_internal(bmain, scene, view_layer, ob, dupflag);
if (basen == NULL) {
- MEM_freeN(base);
BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
return OPERATOR_CANCELLED;
}
- basen->lay = basen->object->lay = BKE_screen_view3d_layer_active(v3d, scene);
+ BKE_scene_object_base_flag_sync_from_object(basen);
basen->object->restrictflag &= ~OB_RESTRICT_VIEW;
if (event) {
@@ -2391,20 +2555,20 @@ static int add_named_exec(bContext *C, wmOperator *op)
const int mval[2] = {event->x - ar->winrct.xmin,
event->y - ar->winrct.ymin};
ED_object_location_from_view(C, basen->object->loc);
- ED_view3d_cursor3d_position(C, mval, basen->object->loc);
+ ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
}
- ED_base_object_select(basen, BA_SELECT);
- ED_base_object_activate(C, basen);
+ ED_object_base_select(basen, BA_SELECT);
+ ED_object_base_activate(C, basen);
copy_object_set_idnew(C);
BKE_main_id_clear_newpoins(bmain);
- DAG_relations_tag_update(bmain);
-
- MEM_freeN(base);
+ /* TODO(sergey): Only update relations for the current scene. */
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -2437,7 +2601,7 @@ static bool join_poll(bContext *C)
if (!ob || ID_IS_LINKED(ob)) return 0;
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE, OB_GPENCIL))
return ED_operator_screenactive(C);
else
return 0;
@@ -2445,10 +2609,9 @@ static bool join_poll(bContext *C)
static int join_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- if (scene->obedit) {
+ if (ob->mode & OB_MODE_EDIT) {
BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode");
return OPERATOR_CANCELLED;
}
@@ -2456,6 +2619,13 @@ static int join_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata");
return OPERATOR_CANCELLED;
}
+ else if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if ((!gpd) || GPENCIL_ANY_MODE(gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "This data does not support joining in this mode");
+ return OPERATOR_CANCELLED;
+ }
+ }
if (ob->type == OB_MESH)
return join_mesh_exec(C, op);
@@ -2463,6 +2633,8 @@ static int join_exec(bContext *C, wmOperator *op)
return join_curve_exec(C, op);
else if (ob->type == OB_ARMATURE)
return join_armature_exec(C, op);
+ else if (ob->type == OB_GPENCIL)
+ return ED_gpencil_join_objects_exec(C, op);
return OPERATOR_CANCELLED;
}
@@ -2499,10 +2671,9 @@ static bool join_shapes_poll(bContext *C)
static int join_shapes_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- if (scene->obedit) {
+ if (ob->mode & OB_MODE_EDIT) {
BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index ee0dfe14cd3..5a650d9dc05 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -52,15 +52,17 @@
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_multires.h"
#include "BKE_report.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_modifier.h"
#include "BKE_DerivedMesh.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
#include "RE_pipeline.h"
#include "RE_shader_ext.h"
#include "RE_multires_bake.h"
@@ -77,15 +79,37 @@
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_uvedit.h"
#include "object_intern.h"
+static Image *bake_object_image_get(Object *ob, int mat_nr)
+{
+ Image *image = NULL;
+ ED_object_get_active_image(ob, mat_nr + 1, &image, NULL, NULL, NULL);
+ return image;
+}
+
+static Image **bake_object_image_get_array(Object *ob)
+{
+ Image **image_array = MEM_mallocN(sizeof(Material *) * ob->totcol, __func__);
+ for (int i = 0; i < ob->totcol; i++) {
+ image_array[i] = bake_object_image_get(ob, i);
+ }
+ return image_array;
+}
+
/* ****************** multires BAKING ********************** */
/* holder of per-object data needed for bake job
* needed to make job totally thread-safe */
typedef struct MultiresBakerJobData {
struct MultiresBakerJobData *next, *prev;
+ /* material aligned image array (for per-face bake image) */
+ struct {
+ Image **array;
+ int len;
+ } ob_image;
DerivedMesh *lores_dm, *hires_dm;
bool simple;
int lvl, tot_lvl;
@@ -94,6 +118,7 @@ typedef struct MultiresBakerJobData {
/* data passing to multires-baker job */
typedef struct {
+ Scene *scene;
ListBase data;
bool bake_clear; /* Clear the images before baking */
int bake_filter; /* Bake-filter, aka margin */
@@ -101,8 +126,6 @@ typedef struct {
bool use_lores_mesh; /* Use low-resolution mesh when baking displacement maps */
int number_of_rays; /* Number of rays to be cast when doing AO baking */
float bias; /* Bias between object and start ray point when doing AO baking */
- int raytrace_structure; /* Optimization structure to be used for AO baking */
- int octree_resolution; /* Reslution of octotree when using octotree optimization structure */
int threads; /* Number of threads to be used for baking */
float user_scale; /* User scale used to scale displacement when baking derivative map. */
} MultiresBakeJob;
@@ -152,7 +175,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
break;
}
- if (!me->mtpoly) {
+ if (!me->mloopuv) {
BKE_report(op->reports, RPT_ERROR, "Mesh should be unwrapped before multires data baking");
ok = false;
@@ -160,7 +183,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
else {
a = me->totpoly;
while (ok && a--) {
- Image *ima = me->mtpoly[a].tpage;
+ Image *ima = bake_object_image_get(ob, me->mpoly[a].mat_nr);
if (!ima) {
BKE_report(op->reports, RPT_ERROR, "You should have active texture to use multires baker");
@@ -207,21 +230,21 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
MultiresModifierData tmp_mmd = *mmd;
DerivedMesh *cddm = CDDM_from_mesh(me);
- if (mmd->lvl > 0) {
- *lvl = mmd->lvl;
+ DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+
+ if (mmd->lvl == 0) {
+ dm = CDDM_copy(cddm);
}
else {
- *lvl = 1;
- tmp_mmd.simple = true;
+ tmp_mmd.lvl = mmd->lvl;
+ tmp_mmd.sculptlvl = mmd->lvl;
+ dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0);
}
- DM_set_only_copy(cddm, CD_MASK_BAREMESH);
-
- tmp_mmd.lvl = *lvl;
- tmp_mmd.sculptlvl = *lvl;
- dm = multires_make_derived_from_derived(cddm, &tmp_mmd, ob, 0);
cddm->release(cddm);
+ *lvl = mmd->lvl;
+
return dm;
}
@@ -246,7 +269,7 @@ static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *l
tmp_mmd.lvl = mmd->totlvl;
tmp_mmd.sculptlvl = mmd->totlvl;
- dm = multires_make_derived_from_derived(cddm, &tmp_mmd, ob, 0);
+ dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0);
cddm->release(cddm);
return dm;
@@ -283,20 +306,27 @@ static void clear_single_image(Image *image, ClearFlag flag)
}
}
-static void clear_images_poly(MTexPoly *mtpoly, int totpoly, ClearFlag flag)
+static void clear_images_poly(Image **ob_image_array, int ob_image_array_len, ClearFlag flag)
{
- int a;
-
- for (a = 0; a < totpoly; a++) {
- mtpoly[a].tpage->id.tag &= ~LIB_TAG_DOIT;
+ for (int i = 0; i < ob_image_array_len; i++) {
+ Image *image = ob_image_array[i];
+ if (image) {
+ image->id.tag &= ~LIB_TAG_DOIT;
+ }
}
- for (a = 0; a < totpoly; a++) {
- clear_single_image(mtpoly[a].tpage, flag);
+ for (int i = 0; i < ob_image_array_len; i++) {
+ Image *image = ob_image_array[i];
+ if (image) {
+ clear_single_image(image, flag);
+ }
}
- for (a = 0; a < totpoly; a++) {
- mtpoly[a].tpage->id.tag &= ~LIB_TAG_DOIT;
+ for (int i = 0; i < ob_image_array_len; i++) {
+ Image *image = ob_image_array[i];
+ if (image) {
+ image->id.tag &= ~LIB_TAG_DOIT;
+ }
}
}
@@ -312,20 +342,23 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
if (scene->r.bake_flag & R_BAKE_CLEAR) { /* clear images */
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
- Mesh *me;
ClearFlag clear_flag = 0;
ob = base->object;
- me = (Mesh *)ob->data;
+ // me = (Mesh *)ob->data;
if (scene->r.bake_mode == RE_BAKE_NORMALS) {
clear_flag = CLEAR_TANGENT_NORMAL;
}
- else if (ELEM(scene->r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
+ else if (scene->r.bake_mode == RE_BAKE_DISPLACEMENT) {
clear_flag = CLEAR_DISPLACEMENT;
}
- clear_images_poly(me->mtpoly, me->totpoly, clear_flag);
+ {
+ Image **ob_image_array = bake_object_image_get_array(ob);
+ clear_images_poly(ob_image_array, ob->totcol, clear_flag);
+ MEM_freeN(ob_image_array);
+ }
}
CTX_DATA_END;
}
@@ -339,23 +372,27 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
multires_force_update(ob);
/* copy data stored in job descriptor */
+ bkr.scene = scene;
bkr.bake_filter = scene->r.bake_filter;
bkr.mode = scene->r.bake_mode;
bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkr.bias = scene->r.bake_biasdist;
bkr.number_of_rays = scene->r.bake_samples;
- bkr.raytrace_structure = scene->r.raytrace_structure;
- bkr.octree_resolution = scene->r.ocres;
bkr.threads = BKE_scene_num_threads(scene);
bkr.user_scale = (scene->r.bake_flag & R_BAKE_USERSCALE) ? scene->r.bake_user_scale : -1.0f;
//bkr.reports= op->reports;
/* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
+ bkr.ob_image.array = bake_object_image_get_array(ob);
+ bkr.ob_image.len = ob->totcol;
+
bkr.hires_dm = multiresbake_create_hiresdm(scene, ob, &bkr.tot_lvl, &bkr.simple);
bkr.lores_dm = multiresbake_create_loresdm(scene, ob, &bkr.lvl);
RE_multires_bake_images(&bkr);
+ MEM_freeN(bkr.ob_image.array);
+
BLI_freelistN(&bkr.image);
bkr.lores_dm->release(bkr.lores_dm);
@@ -378,14 +415,13 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
Object *ob;
/* backup scene settings, so their changing in UI would take no effect on baker */
+ bkj->scene = scene;
bkj->bake_filter = scene->r.bake_filter;
bkj->mode = scene->r.bake_mode;
bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR;
bkj->bias = scene->r.bake_biasdist;
bkj->number_of_rays = scene->r.bake_samples;
- bkj->raytrace_structure = scene->r.raytrace_structure;
- bkj->octree_resolution = scene->r.ocres;
bkj->threads = BKE_scene_num_threads(scene);
bkj->user_scale = (scene->r.bake_flag & R_BAKE_USERSCALE) ? scene->r.bake_user_scale : -1.0f;
//bkj->reports = op->reports;
@@ -401,6 +437,9 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data");
+ data->ob_image.array = bake_object_image_get_array(ob);
+ data->ob_image.len = ob->totcol;
+
/* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
data->hires_dm = multiresbake_create_hiresdm(scene, ob, &data->tot_lvl, &data->simple);
data->lores_dm = multiresbake_create_loresdm(scene, ob, &lvl);
@@ -421,18 +460,16 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
if (bkj->bake_clear) { /* clear images */
for (data = bkj->data.first; data; data = data->next) {
- DerivedMesh *dm = data->lores_dm;
- MTexPoly *mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY);
ClearFlag clear_flag = 0;
if (bkj->mode == RE_BAKE_NORMALS) {
clear_flag = CLEAR_TANGENT_NORMAL;
}
- else if (ELEM(bkj->mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
+ else if (bkj->mode == RE_BAKE_DISPLACEMENT) {
clear_flag = CLEAR_DISPLACEMENT;
}
- clear_images_poly(mtexpoly, dm->getNumPolys(dm), clear_flag);
+ clear_images_poly(data->ob_image.array, data->ob_image.len, clear_flag);
}
}
@@ -440,11 +477,14 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
MultiresBakeRender bkr = {NULL};
/* copy data stored in job descriptor */
+ bkr.scene = bkj->scene;
bkr.bake_filter = bkj->bake_filter;
bkr.mode = bkj->mode;
bkr.use_lores_mesh = bkj->use_lores_mesh;
bkr.user_scale = bkj->user_scale;
//bkr.reports = bkj->reports;
+ bkr.ob_image.array = data->ob_image.array;
+ bkr.ob_image.len = data->ob_image.len;
/* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
bkr.lores_dm = data->lores_dm;
@@ -463,8 +503,6 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
bkr.bias = bkj->bias;
bkr.number_of_rays = bkj->number_of_rays;
- bkr.raytrace_structure = bkj->raytrace_structure;
- bkr.octree_resolution = bkj->octree_resolution;
bkr.threads = bkj->threads;
RE_multires_bake_images(&bkr);
@@ -493,6 +531,8 @@ static void multiresbake_freejob(void *bkv)
GPU_free_image(ima);
}
+ MEM_freeN(data->ob_image.array);
+
BLI_freelistN(&data->images);
MEM_freeN(data);
@@ -539,201 +579,6 @@ static int multiresbake_image_exec(bContext *C, wmOperator *op)
/* ****************** render BAKING ********************** */
-/* threaded break test */
-static int thread_break(void *UNUSED(arg))
-{
- return G.is_break;
-}
-
-typedef struct BakeRender {
- Render *re;
- Main *main;
- Scene *scene;
- struct Object *actob;
- int result, ready;
-
- ReportList *reports;
-
- short *stop;
- short *do_update;
- float *progress;
-
- ListBase threads;
-
- /* backup */
- short prev_wo_amb_occ;
- short prev_r_raytrace;
-
- /* for redrawing */
- ScrArea *sa;
-} BakeRender;
-
-/* use by exec and invoke */
-static int test_bake_internal(bContext *C, ReportList *reports)
-{
- Scene *scene = CTX_data_scene(C);
-
- if ((scene->r.bake_flag & R_BAKE_TO_ACTIVE) && CTX_data_active_object(C) == NULL) {
- BKE_report(reports, RPT_ERROR, "No active object");
- }
- else if (scene->r.bake_mode == RE_BAKE_AO && scene->world == NULL) {
- BKE_report(reports, RPT_ERROR, "No world set up");
- }
- else {
- return 1;
- }
-
- return 0;
-}
-
-static void init_bake_internal(BakeRender *bkr, bContext *C)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- bScreen *sc = CTX_wm_screen(C);
-
- /* get editmode results */
- ED_object_editmode_load(bmain, CTX_data_edit_object(C));
-
- bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL; /* can be NULL */
- bkr->main = bmain;
- bkr->scene = scene;
- bkr->actob = (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT : NULL;
- bkr->re = RE_NewRender("_Bake View_");
-
- if (scene->r.bake_mode == RE_BAKE_AO) {
- /* If raytracing or AO is disabled, switch it on temporarily for baking. */
- bkr->prev_wo_amb_occ = (scene->world->mode & WO_AMB_OCC) != 0;
- scene->world->mode |= WO_AMB_OCC;
- }
- if (scene->r.bake_mode == RE_BAKE_AO || bkr->actob) {
- bkr->prev_r_raytrace = (scene->r.mode & R_RAYTRACE) != 0;
- scene->r.mode |= R_RAYTRACE;
- }
-}
-
-static void finish_bake_internal(BakeRender *bkr)
-{
- Image *ima;
-
- RE_Database_Free(bkr->re);
-
- /* restore raytrace and AO */
- if (bkr->scene->r.bake_mode == RE_BAKE_AO)
- if (bkr->prev_wo_amb_occ == 0)
- bkr->scene->world->mode &= ~WO_AMB_OCC;
-
- if (bkr->scene->r.bake_mode == RE_BAKE_AO || bkr->actob)
- if (bkr->prev_r_raytrace == 0)
- bkr->scene->r.mode &= ~R_RAYTRACE;
-
- /* force OpenGL reload and mipmap recalc */
- if ((bkr->scene->r.bake_flag & R_BAKE_VCOL) == 0) {
- for (ima = bkr->main->image.first; ima; ima = ima->id.next) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- /* some of the images could have been changed during bake,
- * so recreate mipmaps regardless bake result status
- */
- if (ima->ok == IMA_OK_LOADED) {
- if (ibuf) {
- if (ibuf->userflags & IB_BITMAPDIRTY) {
- GPU_free_image(ima);
- imb_freemipmapImBuf(ibuf);
- }
-
- /* invalidate display buffers for changed images */
- if (ibuf->userflags & IB_BITMAPDIRTY)
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- }
- }
-
- /* freed when baking is done, but if its canceled we need to free here */
- if (ibuf) {
- if (ibuf->userdata) {
- BakeImBufuserData *userdata = (BakeImBufuserData *) ibuf->userdata;
- if (userdata->mask_buffer)
- MEM_freeN(userdata->mask_buffer);
- if (userdata->displacement_buffer)
- MEM_freeN(userdata->displacement_buffer);
- MEM_freeN(userdata);
- ibuf->userdata = NULL;
- }
- }
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- DAG_id_tag_update(&ima->id, 0);
- }
- }
-
- if (bkr->scene->r.bake_flag & R_BAKE_VCOL) {
- /* update all tagged meshes */
- Mesh *me;
- BLI_assert(BLI_thread_is_main());
- for (me = bkr->main->mesh.first; me; me = me->id.next) {
- if (me->id.tag & LIB_TAG_DOIT) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
- BKE_mesh_tessface_clear(me);
- }
- }
- }
-
-}
-
-static void *do_bake_render(void *bake_v)
-{
- BakeRender *bkr = bake_v;
-
- bkr->result = RE_bake_shade_all_selected(bkr->re, bkr->scene->r.bake_mode, bkr->actob, NULL, bkr->progress);
- bkr->ready = 1;
-
- return NULL;
-}
-
-static void bake_startjob(void *bkv, short *stop, short *do_update, float *progress)
-{
- BakeRender *bkr = bkv;
- Scene *scene = bkr->scene;
- Main *bmain = bkr->main;
-
- bkr->stop = stop;
- bkr->do_update = do_update;
- bkr->progress = progress;
-
- RE_test_break_cb(bkr->re, NULL, thread_break);
- G.is_break = false; /* BKE_blender_test_break uses this global */
-
- RE_Database_Baking(bkr->re, bmain, scene, scene->lay, scene->r.bake_mode, bkr->actob);
-
- /* baking itself is threaded, cannot use test_break in threads. we also update optional imagewindow */
- bkr->result = RE_bake_shade_all_selected(bkr->re, scene->r.bake_mode, bkr->actob, bkr->do_update, bkr->progress);
-}
-
-static void bake_update(void *bkv)
-{
- BakeRender *bkr = bkv;
-
- if (bkr->sa && bkr->sa->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */
- SpaceImage *sima = bkr->sa->spacedata.first;
- if (sima)
- sima->image = RE_bake_shade_get_image();
- }
-}
-
-static void bake_freejob(void *bkv)
-{
- BakeRender *bkr = bkv;
- finish_bake_internal(bkr);
-
- if (bkr->result == BAKE_RESULT_NO_OBJECTS)
- BKE_report(bkr->reports, RPT_ERROR, "No objects or images found to bake to");
- else if (bkr->result == BAKE_RESULT_FEEDBACK_LOOP)
- BKE_report(bkr->reports, RPT_WARNING, "Circular reference in texture stack");
-
- MEM_freeN(bkr);
- G.is_rendering = false;
-}
-
/* catch esc */
static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -751,7 +596,7 @@ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const
static bool is_multires_bake(Scene *scene)
{
- if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO))
+ if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_AO))
return scene->r.bake_flag & R_BAKE_MULTIRES;
return 0;
@@ -762,44 +607,7 @@ static int objects_bake_render_invoke(bContext *C, wmOperator *op, const wmEvent
Scene *scene = CTX_data_scene(C);
int result = OPERATOR_CANCELLED;
- if (is_multires_bake(scene)) {
- result = multiresbake_image_exec(C, op);
- }
- else {
- /* only one render job at a time */
- if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_OBJECT_BAKE_TEXTURE))
- return OPERATOR_CANCELLED;
-
- if (test_bake_internal(C, op->reports) == 0) {
- return OPERATOR_CANCELLED;
- }
- else {
- BakeRender *bkr = MEM_callocN(sizeof(BakeRender), "render bake");
- wmJob *wm_job;
-
- init_bake_internal(bkr, C);
- bkr->reports = op->reports;
-
- /* setup job */
- wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Texture Bake",
- WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_BAKE_TEXTURE);
- WM_jobs_customdata_set(wm_job, bkr, bake_freejob);
- WM_jobs_timer(wm_job, 0.5, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */
- WM_jobs_callbacks(wm_job, bake_startjob, NULL, bake_update, NULL);
-
- G.is_break = false;
- G.is_rendering = true;
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
-
- WM_cursor_wait(0);
-
- /* add modal handler for ESC */
- WM_event_add_modal_handler(C, op);
- }
-
- result = OPERATOR_RUNNING_MODAL;
- }
+ result = multiresbake_image_exec(C, op);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
@@ -809,55 +617,15 @@ static int objects_bake_render_invoke(bContext *C, wmOperator *op, const wmEvent
static int bake_image_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
int result = OPERATOR_CANCELLED;
- if (is_multires_bake(scene)) {
- result = multiresbake_image_exec_locked(C, op);
+ if (!is_multires_bake(scene)) {
+ BLI_assert(0);
+ return result;
}
- else {
- if (test_bake_internal(C, op->reports) == 0) {
- return OPERATOR_CANCELLED;
- }
- else {
- ListBase threads;
- BakeRender bkr = {NULL};
-
- init_bake_internal(&bkr, C);
- bkr.reports = op->reports;
-
- RE_test_break_cb(bkr.re, NULL, thread_break);
- G.is_break = false; /* BKE_blender_test_break uses this global */
-
- RE_Database_Baking(bkr.re, bmain, scene, scene->lay, scene->r.bake_mode, (scene->r.bake_flag & R_BAKE_TO_ACTIVE) ? OBACT : NULL);
-
- /* baking itself is threaded, cannot use test_break in threads */
- BLI_threadpool_init(&threads, do_bake_render, 1);
- bkr.ready = 0;
- BLI_threadpool_insert(&threads, &bkr);
- while (bkr.ready == 0) {
- PIL_sleep_ms(50);
- if (bkr.ready)
- break;
-
- /* used to redraw in 2.4x but this is just for exec in 2.5 */
- if (!G.background)
- BKE_blender_test_break();
- }
- BLI_threadpool_end(&threads);
-
- if (bkr.result == BAKE_RESULT_NO_OBJECTS)
- BKE_report(op->reports, RPT_ERROR, "No valid images found to bake to");
- else if (bkr.result == BAKE_RESULT_FEEDBACK_LOOP)
- BKE_report(op->reports, RPT_ERROR, "Circular reference in texture stack");
-
- finish_bake_internal(&bkr);
-
- result = OPERATOR_FINISHED;
- }
- }
+ result = multiresbake_image_exec_locked(C, op);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index c9be331b6d5..2f879937f7a 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -49,15 +49,19 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_report.h"
-#include "BKE_modifier.h"
-#include "BKE_mesh.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -84,6 +88,7 @@ typedef struct BakeAPIRender {
Object *ob;
Main *main;
Scene *scene;
+ ViewLayer *view_layer;
ReportList *reports;
ListBase selected_objects;
@@ -272,7 +277,7 @@ static void refresh_images(BakeImages *bake_images)
Image *ima = bake_images->data[i].image;
if (ima->ok == IMA_OK_LOADED) {
GPU_free_image(ima);
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
}
}
}
@@ -353,17 +358,24 @@ static bool is_noncolor_pass(eScenePassType pass_type)
}
/* if all is good tag image and return true */
-static bool bake_object_check(Scene *scene, Object *ob, ReportList *reports)
+static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *reports)
{
Image *image;
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
void *lock;
int i;
- if ((ob->lay & scene->lay) == 0) {
- BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not on a scene layer", ob->id.name + 2);
+ if (base == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not in view layer", ob->id.name + 2);
+ return false;
+ }
+
+ if (!(base->flag & BASE_ENABLED_RENDER)) {
+ BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not enabled for rendering", ob->id.name + 2);
return false;
}
+
if (ob->type != OB_MESH) {
BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2);
return false;
@@ -493,7 +505,7 @@ static bool bake_pass_filter_check(eScenePassType pass_type, const int pass_filt
}
/* before even getting in the bake function we check for some basic errors */
-static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase *selected_objects,
+static bool bake_objects_check(Main *bmain, ViewLayer *view_layer, Object *ob, ListBase *selected_objects,
ReportList *reports, const bool is_selected_to_active)
{
CollectionPointerLink *link;
@@ -504,7 +516,7 @@ static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase *
if (is_selected_to_active) {
int tot_objects = 0;
- if (!bake_object_check(scene, ob, reports))
+ if (!bake_object_check(view_layer, ob, reports))
return false;
for (link = selected_objects->first; link; link = link->next) {
@@ -532,7 +544,7 @@ static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase *
}
for (link = selected_objects->first; link; link = link->next) {
- if (!bake_object_check(scene, link->ptr.data, reports))
+ if (!bake_object_check(view_layer, link->ptr.data, reports))
return false;
}
}
@@ -619,11 +631,11 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re
}
/* create new mesh with edit mode changes and modifiers applied */
-static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob)
+static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *ob)
{
ED_object_editmode_load(bmain, ob);
- Mesh *me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0);
+ Mesh *me = BKE_mesh_new_from_object(depsgraph, bmain, scene, ob, 1, 0);
if (me->flag & ME_AUTOSMOOTH) {
BKE_mesh_split_faces(me, true);
}
@@ -632,7 +644,8 @@ static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob)
}
static int bake(
- Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
+ Render *re, Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob_low, ListBase *selected_objects,
+ ReportList *reports,
const eScenePassType pass_type, const int pass_filter, const int margin,
const eBakeSaveMode save_mode, const bool is_clear, const bool is_split_materials,
const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage,
@@ -640,6 +653,8 @@ static int bake(
const char *custom_cage, const char *filepath, const int width, const int height,
const char *identifier, ScrArea *sa, const char *uv_layer)
{
+ Depsgraph *depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+
int op_result = OPERATOR_CANCELLED;
bool ok = false;
@@ -777,12 +792,16 @@ static int bake(
mmd_low = (MultiresModifierData *) modifiers_findByType(ob_low, eModifierType_Multires);
if (mmd_low) {
mmd_flags_low = mmd_low->flags;
- mmd_low->flags |= eMultiresModifierFlag_PlainUv;
+ mmd_low->uv_smooth = SUBSURF_UV_SMOOTH_NONE;
}
}
+ /* Make sure depsgraph is up to date. */
+ DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+
/* get the mesh as it arrives in the renderer */
- me_low = bake_mesh_new_from_object(bmain, scene, ob_low);
+ me_low = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low);
/* populate the pixel array with the face data */
if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
@@ -797,7 +816,7 @@ static int bake(
/* prepare cage mesh */
if (ob_cage) {
- me_cage = bake_mesh_new_from_object(bmain, scene, ob_cage);
+ me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_cage);
if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) {
BKE_report(reports, RPT_ERROR,
"Invalid cage object, the cage mesh must have the same number "
@@ -829,7 +848,7 @@ static int bake(
ob_low->modifiers = modifiers_tmp;
/* get the cage mesh as it arrives in the renderer */
- me_cage = bake_mesh_new_from_object(bmain, scene, ob_low);
+ me_cage = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low);
RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
}
@@ -855,7 +874,7 @@ static int bake(
tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;
- highpoly[i].me = bake_mesh_new_from_object(bmain, scene, highpoly[i].ob);
+ highpoly[i].me = bake_mesh_new_from_object(depsgraph, bmain, scene, highpoly[i].ob);
highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
/* lowpoly to highpoly transformation matrix */
@@ -882,7 +901,7 @@ static int bake(
/* the baking itself */
for (i = 0; i < tot_highpoly; i++) {
- ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high,
+ ok = RE_bake_engine(re, depsgraph, highpoly[i].ob, i, pixel_array_high,
num_pixels, depth, pass_type, pass_filter, result);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2);
@@ -909,7 +928,7 @@ cage_cleanup:
ob_low->restrictflag &= ~OB_RESTRICT_RENDER;
if (RE_bake_has_engine(re)) {
- ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, pass_filter, result);
+ ok = RE_bake_engine(re, depsgraph, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, pass_filter, result);
}
else {
BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
@@ -958,7 +977,7 @@ cage_cleanup:
md->mode &= ~eModifierMode_Render;
}
- me_nores = bake_mesh_new_from_object(bmain, scene, ob_low);
+ me_nores = bake_mesh_new_from_object(depsgraph, bmain, scene, ob_low);
RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);
RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
@@ -1110,6 +1129,8 @@ cleanup:
if (me_cage)
BKE_libblock_free(bmain, me_cage);
+ DEG_graph_free(depsgraph);
+
return op_result;
}
@@ -1120,6 +1141,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->ob = CTX_data_active_object(C);
bkr->main = CTX_data_main(C);
+ bkr->view_layer = CTX_data_view_layer(C);
bkr->scene = CTX_data_scene(C);
bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL;
@@ -1190,7 +1212,7 @@ static int bake_exec(bContext *C, wmOperator *op)
goto finally;
}
- if (!bake_objects_check(bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
+ if (!bake_objects_check(bkr.main, bkr.view_layer, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
goto finally;
}
@@ -1203,7 +1225,7 @@ static int bake_exec(bContext *C, wmOperator *op)
if (bkr.is_selected_to_active) {
result = bake(
- bkr.render, bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports,
+ bkr.render, bkr.main, bkr.scene, bkr.view_layer, bkr.ob, &bkr.selected_objects, bkr.reports,
bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode,
bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage,
bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
@@ -1216,7 +1238,7 @@ static int bake_exec(bContext *C, wmOperator *op)
for (link = bkr.selected_objects.first; link; link = link->next) {
Object *ob_iter = link->ptr.data;
result = bake(
- bkr.render, bkr.main, bkr.scene, ob_iter, NULL, bkr.reports,
+ bkr.render, bkr.main, bkr.scene, bkr.view_layer, ob_iter, NULL, bkr.reports,
bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode,
is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage,
bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
@@ -1249,7 +1271,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
return;
}
- if (!bake_objects_check(bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
+ if (!bake_objects_check(bkr->main, bkr->view_layer, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
bkr->result = OPERATOR_CANCELLED;
return;
}
@@ -1261,7 +1283,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
if (bkr->is_selected_to_active) {
bkr->result = bake(
- bkr->render, bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports,
+ bkr->render, bkr->main, bkr->scene, bkr->view_layer, bkr->ob, &bkr->selected_objects, bkr->reports,
bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage,
bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
@@ -1274,7 +1296,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
for (link = bkr->selected_objects.first; link; link = link->next) {
Object *ob_iter = link->ptr.data;
bkr->result = bake(
- bkr->render, bkr->main, bkr->scene, ob_iter, NULL, bkr->reports,
+ bkr->render, bkr->main, bkr->scene, bkr->view_layer, ob_iter, NULL, bkr->reports,
bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage,
bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
new file mode 100644
index 00000000000..57f1ad7dea1
--- /dev/null
+++ b/source/blender/editors/object/object_collection.c
@@ -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.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_collection.c
+ * \ingroup edobj
+ */
+
+
+#include <string.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_collection.h"
+#include "BKE_context.h"
+#include "BKE_library.h"
+#include "BKE_library_remap.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "ED_screen.h"
+#include "ED_object.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "object_intern.h"
+
+/********************* 3d view operators ***********************/
+
+/* can be called with C == NULL */
+static const EnumPropertyItem *collection_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob;
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+
+ if (C == NULL) {
+ return DummyRNA_NULL_items;
+ }
+
+ ob = ED_object_context(C);
+
+ /* check that the object exists */
+ if (ob) {
+ Collection *collection;
+ int i = 0, count = 0;
+
+ /* if 2 or more collections, add option to add to all collections */
+ collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob)))
+ count++;
+
+ if (count >= 2) {
+ item_tmp.identifier = item_tmp.name = "All Collections";
+ item_tmp.value = INT_MAX; /* this will give NULL on lookup */
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
+
+ /* add collections */
+ collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob))) {
+ item_tmp.identifier = item_tmp.name = collection->id.name + 2;
+ /* item_tmp.icon = ICON_ARMATURE_DATA; */
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ i++;
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+/* get the collection back from the enum index, quite awkward and UI specific */
+static Collection *collection_object_active_find_index(Main *bmain, Object *ob, const int collection_object_index)
+{
+ Collection *collection = NULL;
+ int i = 0;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob))) {
+ if (i == collection_object_index) {
+ break;
+ }
+ i++;
+ }
+
+ return collection;
+}
+
+static int objects_add_active_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ Main *bmain = CTX_data_main(C);
+ int single_collection_index = RNA_enum_get(op->ptr, "collection");
+ Collection *single_collection = collection_object_active_find_index(bmain, ob, single_collection_index);
+ Collection *collection;
+ bool is_cycle = false;
+ bool updated = false;
+
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* now add all selected objects to the collection(s) */
+ for (collection = bmain->collection.first; collection; collection = collection->id.next) {
+ if (single_collection && collection != single_collection)
+ continue;
+ if (!BKE_collection_has_object(collection, ob))
+ continue;
+
+ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ {
+ if (BKE_collection_has_object(collection, base->object))
+ continue;
+
+ if (!BKE_collection_object_cyclic_check(bmain, base->object, collection)) {
+ BKE_collection_object_add(bmain, collection, base->object);
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ updated = true;
+ }
+ else {
+ is_cycle = true;
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ if (is_cycle)
+ BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected");
+
+ if (!updated)
+ return OPERATOR_CANCELLED;
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void COLLECTION_OT_objects_add_active(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Selected To Active Collection";
+ ot->description = "Add the object to an object collection that contains the active object";
+ ot->idname = "COLLECTION_OT_objects_add_active";
+
+ /* api callbacks */
+ ot->exec = objects_add_active_exec;
+ ot->invoke = WM_menu_invoke;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to add other selected objects to");
+ RNA_def_enum_funcs(prop, collection_object_active_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+}
+
+static int objects_remove_active_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ int single_collection_index = RNA_enum_get(op->ptr, "collection");
+ Collection *single_collection = collection_object_active_find_index(bmain, ob, single_collection_index);
+ Collection *collection;
+ bool ok = false;
+
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* linking to same collection requires its own loop so we can avoid
+ * looking up the active objects collections each time */
+
+ for (collection = bmain->collection.first; collection; collection = collection->id.next) {
+ if (single_collection && collection != single_collection)
+ continue;
+
+ if (BKE_collection_has_object(collection, ob)) {
+ /* Remove collections from selected objects */
+ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ {
+ BKE_collection_object_remove(bmain, collection, base->object, false);
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ ok = 1;
+ }
+ CTX_DATA_END;
+ }
+ }
+
+ if (!ok)
+ BKE_report(op->reports, RPT_ERROR, "Active object contains no collections");
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void COLLECTION_OT_objects_remove_active(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Remove Selected From Active Collection";
+ ot->description = "Remove the object from an object collection that contains the active object";
+ ot->idname = "COLLECTION_OT_objects_remove_active";
+
+ /* api callbacks */
+ ot->exec = objects_remove_active_exec;
+ ot->invoke = WM_menu_invoke;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to remove other selected objects from");
+ RNA_def_enum_funcs(prop, collection_object_active_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+}
+
+static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+
+ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ {
+ BKE_object_groups_clear(bmain, base->object);
+ }
+ CTX_DATA_END;
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void COLLECTION_OT_objects_remove_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove From All Unlinked Collections";
+ ot->description = "Remove selected objects from all collections not used in a scene";
+ ot->idname = "COLLECTION_OT_objects_remove_all";
+
+ /* api callbacks */
+ ot->exec = collection_objects_remove_all_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int collection_objects_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ Main *bmain = CTX_data_main(C);
+ int single_collection_index = RNA_enum_get(op->ptr, "collection");
+ Collection *single_collection = collection_object_active_find_index(bmain, ob, single_collection_index);
+ Collection *collection;
+ bool updated = false;
+
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ for (collection = bmain->collection.first; collection; collection = collection->id.next) {
+ if (single_collection && collection != single_collection)
+ continue;
+ if (!BKE_collection_has_object(collection, ob))
+ continue;
+
+ /* now remove all selected objects from the collection */
+ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ {
+ BKE_collection_object_remove(bmain, collection, base->object, false);
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ updated = true;
+ }
+ CTX_DATA_END;
+ }
+
+ if (!updated)
+ return OPERATOR_CANCELLED;
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void COLLECTION_OT_objects_remove(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Remove From Collection";
+ ot->description = "Remove selected objects from a collection";
+ ot->idname = "COLLECTION_OT_objects_remove";
+
+ /* api callbacks */
+ ot->exec = collection_objects_remove_exec;
+ ot->invoke = WM_menu_invoke;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "The collection to remove this object from");
+ RNA_def_enum_funcs(prop, collection_object_active_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+}
+
+static int collection_create_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ char name[MAX_ID_NAME - 2]; /* id name */
+
+ RNA_string_get(op->ptr, "name", name);
+
+ Collection *collection = BKE_collection_add(bmain, NULL, name);
+ id_fake_user_set(&collection->id);
+
+ CTX_DATA_BEGIN (C, Base *, base, selected_bases)
+ {
+ BKE_collection_object_add(bmain, collection, base->object);
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ CTX_DATA_END;
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void COLLECTION_OT_create(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create New Collection";
+ ot->description = "Create an object collection from selected objects";
+ ot->idname = "COLLECTION_OT_create";
+
+ /* api callbacks */
+ ot->exec = collection_create_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_string(ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Name of the new collection");
+}
+
+/****************** properties window operators *********************/
+
+static int collection_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ Main *bmain = CTX_data_main(C);
+
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ Collection *collection = BKE_collection_add(bmain, NULL, "Collection");
+ id_fake_user_set(&collection->id);
+ BKE_collection_object_add(bmain, collection, ob);
+
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_collection_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add to Collection";
+ ot->idname = "OBJECT_OT_collection_add";
+ ot->description = "Add an object to a new collection";
+
+ /* api callbacks */
+ ot->exec = collection_add_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int collection_link_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = ED_object_context(C);
+ Collection *collection = BLI_findlink(&bmain->collection, RNA_enum_get(op->ptr, "collection"));
+
+ if (ELEM(NULL, ob, collection))
+ return OPERATOR_CANCELLED;
+
+ /* Early return check, if the object is already in collection
+ * we could skip all the dependency check and just consider
+ * operator is finished.
+ */
+ if (BKE_collection_has_object(collection, ob)) {
+ return OPERATOR_FINISHED;
+ }
+
+ /* Adding object to collection which is used as duplicollection for self is bad idea.
+ *
+ * It is also bad idea to add object to collection which is in collection which
+ * contains our current object.
+ */
+ if (BKE_collection_object_cyclic_check(bmain, ob, collection)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not add the collection because of dependency cycle detected");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_collection_object_add(bmain, collection, ob);
+
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_collection_link(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Link to Collection";
+ ot->idname = "OBJECT_OT_collection_link";
+ ot->description = "Add an object to an existing collection";
+
+ /* api callbacks */
+ ot->exec = collection_link_exec;
+ ot->invoke = WM_enum_search_invoke;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "collection", DummyRNA_NULL_items, 0, "Collection", "");
+ RNA_def_enum_funcs(prop, RNA_collection_local_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+}
+
+static int collection_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = ED_object_context(C);
+ Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data;
+
+ if (!ob || !collection)
+ return OPERATOR_CANCELLED;
+
+ BKE_collection_object_remove(bmain, collection, ob, false);
+
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_collection_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Collection";
+ ot->idname = "OBJECT_OT_collection_remove";
+ ot->description = "Remove the active object from this collection";
+
+ /* api callbacks */
+ ot->exec = collection_remove_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int collection_unlink_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data;
+
+ if (!collection)
+ return OPERATOR_CANCELLED;
+
+ BKE_libblock_delete(bmain, collection);
+
+ DEG_relations_tag_update(bmain);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_collection_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlink Collection";
+ ot->idname = "OBJECT_OT_collection_unlink";
+ ot->description = "Unlink the collection from all objects";
+
+ /* api callbacks */
+ ot->exec = collection_unlink_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same collection as the active */
+{
+ Collection *collection = CTX_data_pointer_get_type(C, "collection", &RNA_Collection).data;
+
+ if (!collection)
+ return OPERATOR_CANCELLED;
+
+ CTX_DATA_BEGIN (C, Base *, base, visible_bases)
+ {
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
+ if (BKE_collection_has_object_recursive(collection, base->object)) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_collection_objects_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Objects in Collection";
+ ot->idname = "OBJECT_OT_collection_objects_select";
+ ot->description = "Select all objects in collection";
+
+ /* api callbacks */
+ ot->exec = select_grouped_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 70d3d856599..4aedd6a55d4 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -53,7 +53,6 @@
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -62,6 +61,9 @@
#include "BKE_tracking.h"
#include "BIK_api.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -428,6 +430,11 @@ static void test_constraint(Main *bmain, Object *owner, bPoseChannel *pchan, bCo
if (check_targets && cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
+ /* constraints with empty target list that actually require targets */
+ if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+
/* disable and clear constraints targets that are incorrect */
for (ct = targets.first; ct; ct = ct->next) {
/* general validity checks (for those constraints that need this) */
@@ -471,6 +478,18 @@ static void test_constraint(Main *bmain, Object *owner, bPoseChannel *pchan, bCo
}
}
}
+ else if (con->type == CONSTRAINT_TYPE_ARMATURE) {
+ if (ct->tar) {
+ if (ct->tar->type != OB_ARMATURE) {
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ else if (!BKE_armature_find_bone_name(BKE_armature_from_object(ct->tar), ct->subtarget)) {
+ /* bone must exist in armature... */
+ con->flag |= CONSTRAINT_DISABLE;
+ }
+ }
+ }
}
/* free any temporary targets */
@@ -596,6 +615,11 @@ static bool edit_constraint_poll_generic(bContext *C, StructRNA *rna_type)
return 0;
}
+ if (ID_IS_STATIC_OVERRIDE(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints coming from static override");
+ return (((bConstraint *)ptr.data)->flag & CONSTRAINT_STATICOVERRIDE_LOCAL) != 0;
+ }
+
return 1;
}
@@ -606,8 +630,11 @@ static bool edit_constraint_poll(bContext *C)
static void edit_constraint_properties(wmOperatorType *ot)
{
- RNA_def_string(ot->srna, "constraint", NULL, MAX_NAME, "Constraint", "Name of the constraint to edit");
- RNA_def_enum(ot->srna, "owner", constraint_owner_items, 0, "Owner", "The owner of this constraint");
+ PropertyRNA *prop;
+ prop = RNA_def_string(ot->srna, "constraint", NULL, MAX_NAME, "Constraint", "Name of the constraint to edit");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_enum(ot->srna, "owner", constraint_owner_items, 0, "Owner", "The owner of this constraint");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int edit_constraint_invoke_properties(bContext *C, wmOperator *op)
@@ -775,8 +802,10 @@ void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot)
/* ------------- Child-Of Constraint ------------------ */
-static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con, float invmat[4][4], const int owner)
+static void child_get_inverse_matrix(const bContext *C, Scene *scene, Object *ob, bConstraint *con, float invmat[4][4], const int owner)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
/* nullify inverse matrix first */
unit_m4(invmat);
@@ -802,7 +831,7 @@ static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con,
* to use as baseline ("pmat") to derive delta from. This extra calc saves users
* from having pressing "Clear Inverse" first
*/
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob);
copy_m4_m4(pmat, pchan->pose_mat);
/* 2. knock out constraints starting from this one */
@@ -819,7 +848,7 @@ static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con,
}
/* 3. solve pose without disabled constraints */
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob);
/* 4. determine effect of constraint by removing the newly calculated
* pchan->pose_mat from the original pchan->pose_mat, thus determining
@@ -842,7 +871,7 @@ static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con,
}
/* 6. recalculate pose with new inv-mat applied */
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob);
}
}
if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) {
@@ -853,7 +882,7 @@ static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con,
BLI_assert(BLI_findindex(&ob->constraints, con) != -1);
/* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */
- BKE_object_workob_calc_parent(scene, ob, &workob);
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
invert_m4_m4(invmat, workob.obmat);
}
}
@@ -875,7 +904,7 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- child_get_inverse_matrix(scene, ob, con, data->invmat, owner);
+ child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
@@ -986,7 +1015,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
{
/* create F-Curve for path animation */
act = verify_adt_action(bmain, &cu->id, 1);
- fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1);
+ fcu = verify_fcurve(bmain, act, NULL, NULL, "eval_time", 0, 1);
/* standard vertical range - 1:1 = 100 frames */
standardRange = 100.0f;
@@ -1011,7 +1040,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
/* create F-Curve for constraint */
act = verify_adt_action(bmain, &ob->id, 1);
- fcu = verify_fcurve(act, NULL, NULL, path, 0, 1);
+ fcu = verify_fcurve(bmain, act, NULL, NULL, path, 0, 1);
/* standard vertical range - 0.0 to 1.0 */
standardRange = 1.0f;
@@ -1098,7 +1127,7 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- child_get_inverse_matrix(scene, ob, con, data->invmat, owner);
+ child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
@@ -1199,9 +1228,9 @@ void ED_object_constraint_update(Main *bmain, Object *ob)
object_test_constraints(bmain, ob);
if (ob->type == OB_ARMATURE)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
else
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
static void object_pose_tag_update(Main *bmain, Object *ob)
@@ -1224,7 +1253,7 @@ void ED_object_constraint_dependency_update(Main *bmain, Object *ob)
if (ob->pose) {
object_pose_tag_update(bmain, ob);
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
void ED_object_constraint_tag_update(Main *bmain, Object *ob, bConstraint *con)
@@ -1233,12 +1262,19 @@ void ED_object_constraint_tag_update(Main *bmain, Object *ob, bConstraint *con)
BKE_pose_tag_update_constraint_flags(ob->pose);
}
- object_test_constraint(bmain, ob, con);
+ if (con) {
+ object_test_constraint(bmain, ob, con);
+ }
if (ob->type == OB_ARMATURE)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
else
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
+
+ /* Do Copy-on-Write tag here too, otherwise constraint
+ * influence/mute buttons in UI have no effect
+ */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstraint *con)
@@ -1248,7 +1284,7 @@ void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstr
if (ob->pose) {
object_pose_tag_update(bmain, ob);
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
static bool constraint_poll(bContext *C)
@@ -1273,7 +1309,7 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op))
ED_object_constraint_update(bmain, ob); /* needed to set the flags on posebones correctly */
/* relatiols */
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
/* notifiers */
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
@@ -1404,25 +1440,27 @@ void CONSTRAINT_OT_move_up(wmOperatorType *ot)
static int pose_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Object *prev_ob = NULL;
/* free constraints for all selected bones */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
{
BKE_constraints_free(&pchan->constraints);
pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK | PCHAN_HAS_CONST);
+
+ if (prev_ob != ob) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
+ prev_ob = ob;
+ }
}
CTX_DATA_END;
/* force depsgraph to get recalculated since relationships removed */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
/* note, calling BIK_clear_data() isn't needed here */
- /* do updates */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
-
return OPERATOR_FINISHED;
}
@@ -1447,12 +1485,12 @@ static int object_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
BKE_constraints_free(&ob->constraints);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
CTX_DATA_END;
/* force depsgraph to get recalculated since relationships removed */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
/* do updates */
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, NULL);
@@ -1478,8 +1516,6 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
bPoseChannel *pchan = CTX_data_active_pose_bone(C);
- ListBase lb;
- CollectionPointerLink *link;
/* don't do anything if bone doesn't exist or doesn't have any constraints */
if (ELEM(NULL, pchan, pchan->constraints.first)) {
@@ -1487,26 +1523,28 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* copy all constraints from active posebone to all selected posebones */
- CTX_data_selected_pose_bones(C, &lb);
- for (link = lb.first; link; link = link->next) {
- Object *ob = link->ptr.id.data;
- bPoseChannel *chan = link->ptr.data;
+ Object *prev_ob = NULL;
+ /* copy all constraints from active posebone to all selected posebones */
+ CTX_DATA_BEGIN_WITH_ID(C, bPoseChannel *, chan, selected_pose_bones, Object *, ob)
+ {
/* if we're not handling the object we're copying from, copy all constraints over */
if (pchan != chan) {
BKE_constraints_copy(&chan->constraints, &pchan->constraints, true);
/* update flags (need to add here, not just copy) */
chan->constflag |= pchan->constflag;
- BKE_pose_tag_recalc(bmain, ob->pose);
- DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+ if (prev_ob != ob) {
+ BKE_pose_tag_recalc(bmain, ob->pose);
+ DEG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+ prev_ob = ob;
+ }
}
}
- BLI_freelistN(&lb);
+ CTX_DATA_END;
/* force depsgraph to get recalculated since new relationships added */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, NULL);
@@ -1539,13 +1577,13 @@ static int object_constraint_copy_exec(bContext *C, wmOperator *UNUSED(op))
/* if we're not handling the object we're copying from, copy all constraints over */
if (obact != ob) {
BKE_constraints_copy(&ob->constraints, &obact->constraints, true);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
CTX_DATA_END;
/* force depsgraph to get recalculated since new relationships added */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, NULL);
@@ -1615,17 +1653,12 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob
only_ob = true;
add = false;
break;
-
- /* object only - add here is ok? */
- case CONSTRAINT_TYPE_RIGIDBODYJOINT:
- only_ob = true;
- break;
}
/* if the active Object is Armature, and we can search for bones, do so... */
if ((obact->type == OB_ARMATURE) && (only_ob == false)) {
/* search in list of selected Pose-Channels for target */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones_from_active_object)
{
/* just use the first one that we encounter, as long as it is not the active one */
if (pchan != pchanact) {
@@ -1686,16 +1719,12 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob
if ((found == false) && (add)) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Base *base = BASACT, *newbase = NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Base *base = BASACT(view_layer);
Object *obt;
/* add new target object */
- obt = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
-
- /* set layers OK */
- newbase = BASACT;
- newbase->lay = base->lay;
- obt->lay = newbase->lay;
+ obt = BKE_object_add(bmain, scene, view_layer, OB_EMPTY, NULL);
/* transform cent to global coords for loc */
if (pchanact) {
@@ -1712,8 +1741,8 @@ static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob
}
/* restore, BKE_object_add sets active */
- BASACT = base;
- base->flag |= SELECT;
+ BASACT(view_layer) = base;
+ base->flag |= BASE_SELECTED;
/* make our new target the new object */
*tar_ob = obt;
@@ -1747,10 +1776,6 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase
if (type == CONSTRAINT_TYPE_NULL) {
return OPERATOR_CANCELLED;
}
- if ((type == CONSTRAINT_TYPE_RIGIDBODYJOINT) && (list != &ob->constraints)) {
- BKE_report(op->reports, RPT_ERROR, "Rigid Body Joint constraint can only be added to objects");
- return OPERATOR_CANCELLED;
- }
if ((type == CONSTRAINT_TYPE_KINEMATIC) && ((!pchan) || (list != &pchan->constraints))) {
BKE_report(op->reports, RPT_ERROR, "IK constraint can only be added to bones");
return OPERATOR_CANCELLED;
@@ -1821,7 +1846,7 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase
/* force depsgraph to get recalculated since new relationships added */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
if ((ob->type == OB_ARMATURE) && (pchan)) {
BKE_pose_tag_recalc(bmain, ob->pose); /* sort pose channels */
@@ -1831,10 +1856,10 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase
* XXX Temp hack until new depsgraph hopefully solves this. */
ob->adt->recalc |= ADT_RECALC_ANIM;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
}
else
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob);
@@ -2055,10 +2080,10 @@ void POSE_OT_ik_add(wmOperatorType *ot)
/* remove IK constraints from selected bones */
static int pose_ik_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Object *prev_ob = NULL;
/* only remove IK Constraints */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob)
{
bConstraint *con, *next;
@@ -2070,14 +2095,18 @@ static int pose_ik_clear_exec(bContext *C, wmOperator *UNUSED(op))
}
}
pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET);
- }
- CTX_DATA_END;
- /* refresh depsgraph */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ if (prev_ob != ob) {
+ prev_ob = ob;
+
+ /* Refresh depsgraph. */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
+ /* Note, notifier might evolve. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
+ }
+ }
+ CTX_DATA_END;
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 91081345069..7b65d4c4f47 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -40,13 +40,14 @@
#include "BKE_context.h"
#include "BKE_data_transfer.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -95,13 +96,14 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(
{
EnumPropertyItem *item = NULL, tmp_item = {0};
int totitem = 0;
-
const int data_type = RNA_enum_get(ptr, "data_type");
if (!C) { /* needed for docs and i18n tools */
return rna_enum_dt_layers_select_src_items;
}
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC);
RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC);
@@ -134,20 +136,17 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(
Scene *scene = CTX_data_scene(C);
if (ob_src) {
- DerivedMesh *dm_src;
- CustomData *pdata;
+ Mesh *me_eval;
int num_data, i;
- /* XXX Is this OK? */
- dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY);
- pdata = dm_src->getPolyDataLayout(dm_src);
- num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ me_eval = mesh_get_eval_final(depsgraph, scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPUV);
+ num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPUV);
RNA_enum_item_add_separator(&item, &totitem);
for (i = 0; i < num_data; i++) {
tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i);
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(&me_eval->ldata, CD_MLOOPUV, i);
RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
@@ -157,20 +156,17 @@ static const EnumPropertyItem *dt_layers_select_src_itemf(
Scene *scene = CTX_data_scene(C);
if (ob_src) {
- DerivedMesh *dm_src;
- CustomData *ldata;
+ Mesh *me_eval;
int num_data, i;
- /* XXX Is this OK? */
- dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL);
- ldata = dm_src->getLoopDataLayout(dm_src);
- num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ me_eval = mesh_get_eval_final(depsgraph, scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL);
+ num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL);
RNA_enum_item_add_separator(&item, &totitem);
for (i = 0; i < num_data; i++) {
tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i);
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(&me_eval->ldata, CD_MLOOPCOL, i);
RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
@@ -344,6 +340,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *ob_src = ED_object_active_context(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ListBase ctx_objects;
CollectionPointerLink *ctx_ob_dst;
@@ -412,7 +409,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
}
if (BKE_object_data_transfer_mesh(
- scene, ob_src, ob_dst, data_type, use_create,
+ depsgraph, scene, ob_src, ob_dst, data_type, use_create,
map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode,
space_transform, use_auto_transform,
max_distance, ray_radius, islands_precision,
@@ -423,7 +420,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
if (reverse_transfer) {
SWAP(Object *, ob_src, ob_dst);
@@ -534,7 +531,7 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot)
ot->check = data_transfer_check;
/* Flags.*/
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* Properties.*/
prop = RNA_def_boolean(ot->srna, "use_reverse_transfer", false, "Reverse Transfer",
@@ -610,6 +607,7 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *ob_act = ED_object_active_context(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
DataTransferModifierData *dtmd;
dtmd = (DataTransferModifierData *)edit_modifier_property_get(op, ob_act, eModifierType_DataTransfer);
@@ -626,10 +624,10 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_object_data_transfer_layout(scene, ob_src, ob_dst, dtmd->data_types, use_delete,
+ BKE_object_data_transfer_layout(depsgraph, scene, ob_src, ob_dst, dtmd->data_types, use_delete,
dtmd->layers_select_src, dtmd->layers_select_dst);
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
}
else {
Object *ob_src = ob_act;
@@ -656,11 +654,11 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op)
for (ctx_ob_dst = ctx_objects.first; ctx_ob_dst; ctx_ob_dst = ctx_ob_dst->next) {
Object *ob_dst = ctx_ob_dst->ptr.data;
if (data_transfer_exec_is_object_valid(op, ob_src, ob_dst, false)) {
- BKE_object_data_transfer_layout(scene, ob_src, ob_dst, data_type, use_delete,
+ BKE_object_data_transfer_layout(depsgraph, scene, ob_src, ob_dst, data_type, use_delete,
layers_select_src, layers_select_dst);
}
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
}
BLI_freelistN(&ctx_objects);
@@ -696,7 +694,7 @@ void OBJECT_OT_datalayout_transfer(wmOperatorType *ot)
ot->check = data_transfer_check;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* Properties.*/
edit_modifier_properties(ot);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index fc967dc424e..2723198b279 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -46,12 +46,11 @@
#include "BLT_translation.h"
#include "DNA_armature_types.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
-#include "DNA_property_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
@@ -59,33 +58,37 @@
#include "DNA_vfont_types.h"
#include "DNA_mesh_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_workspace_types.h"
#include "IMB_imbuf_types.h"
#include "BKE_anim.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
+#include "BKE_editlattice.h"
#include "BKE_effect.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_pointcache.h"
-#include "BKE_property.h"
-#include "BKE_sca.h"
#include "BKE_softbody.h"
-#include "BKE_modifier.h"
-#include "BKE_editlattice.h"
#include "BKE_editmesh.h"
#include "BKE_report.h"
-#include "BKE_undo_system.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
#include "ED_curve.h"
@@ -93,9 +96,11 @@
#include "ED_mball.h"
#include "ED_lattice.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "ED_image.h"
+#include "ED_gpencil.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -104,11 +109,19 @@
/* for menu/popup icons etc etc*/
#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
#include "object_intern.h" // own include
+/* prototypes */
+typedef struct MoveToCollectionData MoveToCollectionData;
+static void move_to_collection_menus_items(struct uiLayout *layout, struct MoveToCollectionData *menu);
+
/* ************* XXX **************** */
static void error(const char *UNUSED(arg)) {}
static void waitcursor(int UNUSED(val)) {}
@@ -134,95 +147,109 @@ Object *ED_object_active_context(bContext *C)
return ob;
}
+/* ********************** object hiding *************************** */
+
+static bool object_hide_poll(bContext *C)
+{
+ if (CTX_wm_space_outliner(C) != NULL) {
+ return ED_outliner_collections_editor_poll(C);
+ }
+ else {
+ return ED_operator_view3d_active(C);
+ }
+}
-/* ********* clear/set restrict view *********/
static int object_hide_view_clear_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
Scene *scene = CTX_data_scene(C);
- Base *base;
- bool changed = false;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool select = RNA_boolean_get(op->ptr, "select");
+ bool changed = false;
- /* XXX need a context loop to handle such cases */
- for (base = FIRSTBASE; base; base = base->next) {
- if ((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) {
- if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) {
- SET_FLAG_FROM_TEST(base->flag, select, SELECT);
- }
- base->object->flag = base->flag;
- base->object->restrictflag &= ~OB_RESTRICT_VIEW;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->flag & BASE_HIDDEN) {
+ base->flag &= ~BASE_HIDDEN;
changed = true;
+
+ if (select) {
+ ED_object_base_select(base, BA_SELECT);
+ }
}
}
- if (changed) {
- DAG_id_type_tag(bmain, ID_OB);
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+
+ if (!changed) {
+ return OPERATOR_CANCELLED;
}
+ BKE_layer_collection_sync(scene, view_layer);
+ DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+
return OPERATOR_FINISHED;
}
void OBJECT_OT_hide_view_clear(wmOperatorType *ot)
{
-
/* identifiers */
- ot->name = "Clear Restrict View";
- ot->description = "Reveal the object by setting the hide flag";
+ ot->name = "Show Hidden Objects";
+ ot->description = "Reveal temporarily hidden objects";
ot->idname = "OBJECT_OT_hide_view_clear";
/* api callbacks */
ot->exec = object_hide_view_clear_exec;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = object_hide_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ PropertyRNA *prop = RNA_def_boolean(ot->srna, "select", false, "Select", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
static int object_hide_view_set_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- bool changed = false;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool unselected = RNA_boolean_get(op->ptr, "unselected");
- CTX_DATA_BEGIN(C, Base *, base, visible_bases)
- {
+ /* Do nothing if no objects was selected. */
+ bool have_selected = false;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->flag & BASE_VISIBLE) {
+ if (base->flag & BASE_SELECTED) {
+ have_selected = true;
+ break;
+ }
+ }
+ }
+
+ if (!have_selected) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Hide selected or unselected objects. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (!(base->flag & BASE_VISIBLE)) {
+ continue;
+ }
+
if (!unselected) {
- if (base->flag & SELECT) {
- base->flag &= ~SELECT;
- base->object->flag = base->flag;
- base->object->restrictflag |= OB_RESTRICT_VIEW;
- changed = true;
- if (base == BASACT) {
- ED_base_object_activate(C, NULL);
- }
+ if (base->flag & BASE_SELECTED) {
+ ED_object_base_select(base, BA_DESELECT);
+ base->flag |= BASE_HIDDEN;
}
}
else {
- if (!(base->flag & SELECT)) {
- base->object->restrictflag |= OB_RESTRICT_VIEW;
- changed = true;
- if (base == BASACT) {
- ED_base_object_activate(C, NULL);
- }
+ if (!(base->flag & BASE_SELECTED)) {
+ ED_object_base_select(base, BA_DESELECT);
+ base->flag |= BASE_HIDDEN;
}
}
}
- CTX_DATA_END;
- if (changed) {
- DAG_id_type_tag(bmain, ID_OB);
- DAG_relations_tag_update(bmain);
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
-
- }
+ BKE_layer_collection_sync(scene, view_layer);
+ DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
@@ -230,95 +257,136 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op)
void OBJECT_OT_hide_view_set(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Set Restrict View";
- ot->description = "Hide the object by setting the hide flag";
+ ot->name = "Hide Objects";
+ ot->description = "Temporarily hide objects from the viewport";
ot->idname = "OBJECT_OT_hide_view_set";
/* api callbacks */
ot->exec = object_hide_view_set_exec;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = object_hide_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
-
+ PropertyRNA *prop;
+ prop = RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
-/* 99% same as above except no need for scene refreshing (TODO, update render preview) */
-static int object_hide_render_clear_exec(bContext *C, wmOperator *UNUSED(op))
+static int object_hide_collection_exec(bContext *C, wmOperator *op)
{
- bool changed = false;
+ wmWindow *win = CTX_wm_window(C);
- /* XXX need a context loop to handle such cases */
- CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects)
- {
- if (ob->restrictflag & OB_RESTRICT_RENDER) {
- ob->restrictflag &= ~OB_RESTRICT_RENDER;
- changed = true;
- }
+ int index = RNA_int_get(op->ptr, "collection_index");
+ const bool extend = (win->eventstate->shift != 0) ||
+ RNA_boolean_get(op->ptr, "toggle");
+
+ if (win->eventstate->alt != 0) {
+ index += 10;
}
- CTX_DATA_END;
- if (changed)
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *lc = BKE_layer_collection_from_index(view_layer, index);
+
+ if (!lc) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_layer_collection_set_visible(scene, view_layer, lc, extend);
+
+ DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
-void OBJECT_OT_hide_render_clear(wmOperatorType *ot)
+#define COLLECTION_INVALID_INDEX -1
+
+void ED_hide_collections_menu_draw(const bContext *C, uiLayout *layout)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *lc_scene = view_layer->layer_collections.first;
- /* identifiers */
- ot->name = "Clear Restrict Render";
- ot->description = "Reveal the render object by setting the hide render flag";
- ot->idname = "OBJECT_OT_hide_render_clear";
+ uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
- /* api callbacks */
- ot->exec = object_hide_render_clear_exec;
- ot->poll = ED_operator_view3d_active;
+ for (LayerCollection *lc = lc_scene->layer_collections.first; lc; lc = lc->next) {
+ int index = BKE_layer_collection_findindex(view_layer, lc);
+ uiLayout *row = uiLayoutRow(layout, false);
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ continue;
+ }
-static int object_hide_render_set_exec(bContext *C, wmOperator *op)
-{
- const bool unselected = RNA_boolean_get(op->ptr, "unselected");
+ if (lc->collection->flag & COLLECTION_RESTRICT_VIEW) {
+ continue;
+ }
- CTX_DATA_BEGIN(C, Base *, base, visible_bases)
- {
- if (!unselected) {
- if (base->flag & SELECT) {
- base->object->restrictflag |= OB_RESTRICT_RENDER;
- }
+ if ((view_layer->runtime_flag & VIEW_LAYER_HAS_HIDE) &&
+ !(lc->runtime_flag & LAYER_COLLECTION_HAS_VISIBLE_OBJECTS))
+ {
+ uiLayoutSetActive(row, false);
}
- else {
- if (!(base->flag & SELECT)) {
- base->object->restrictflag |= OB_RESTRICT_RENDER;
- }
+
+ int icon = ICON_NONE;
+ if (BKE_layer_collection_has_selected_objects(view_layer, lc)) {
+ icon = ICON_LAYER_ACTIVE;
+ }
+ else if (lc->runtime_flag & LAYER_COLLECTION_HAS_OBJECTS) {
+ icon = ICON_LAYER_USED;
}
+
+ uiItemIntO(row,
+ lc->collection->id.name + 2,
+ icon,
+ "OBJECT_OT_hide_collection",
+ "collection_index",
+ index);
}
- CTX_DATA_END;
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
- return OPERATOR_FINISHED;
}
-void OBJECT_OT_hide_render_set(wmOperatorType *ot)
+static int object_hide_collection_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* Immediately execute if collection index was specified. */
+ int index = RNA_int_get(op->ptr, "collection_index");
+ if (index != COLLECTION_INVALID_INDEX) {
+ return object_hide_collection_exec(C, op);
+ }
+
+ /* Open popup menu. */
+ const char *title = CTX_IFACE_(op->type->translation_context, op->type->name);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, title, ICON_GROUP);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ ED_hide_collections_menu_draw(C, layout);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+void OBJECT_OT_hide_collection(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Set Restrict Render";
- ot->description = "Hide the render object by setting the hide render flag";
- ot->idname = "OBJECT_OT_hide_render_set";
+ ot->name = "Hide Objects By Collection";
+ ot->description = "Show only objects in collection (Shift to extend)";
+ ot->idname = "OBJECT_OT_hide_collection";
/* api callbacks */
- ot->exec = object_hide_render_set_exec;
+ ot->exec = object_hide_collection_exec;
+ ot->invoke = object_hide_collection_invoke;
ot->poll = ED_operator_view3d_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
+ /* Properties. */
+ PropertyRNA *prop;
+ prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX,
+ "Collection Index", "Index of the collection to change visibility", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle visibility");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
/* ******************* toggle editmode operator ***************** */
@@ -391,7 +459,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
* to inform dependency graph about this. But is it really the
* best place to do this?
*/
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
const Curve *cu = obedit->data;
@@ -455,8 +523,8 @@ bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int f
if (ED_object_editmode_load_ex(bmain, obedit, freedata) == false) {
/* in rare cases (background mode) its possible active object
* is flagged for editmode, without 'obedit' being set [#35489] */
- if (UNLIKELY(scene->basact && (scene->basact->object->mode & OB_MODE_EDIT))) {
- scene->basact->object->mode &= ~OB_MODE_EDIT;
+ if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) {
+ obedit->mode &= ~OB_MODE_EDIT;
}
if (flag & EM_WAITCURSOR) waitcursor(0);
return true;
@@ -467,11 +535,8 @@ bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int f
ListBase pidlist;
PTCacheID *pid;
- /* for example; displist make is different in editmode */
- scene->obedit = NULL; // XXX for context
-
/* flag object caches as outdated */
- BKE_ptcache_ids_from_object(bmain, &pidlist, obedit, scene, 0);
+ BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->type != PTCACHE_TYPE_PARTICLES) /* particles don't need reset on geometry change */
pid->cache->flag |= PTCACHE_OUTDATED;
@@ -481,7 +546,7 @@ bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int f
BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_OUTDATED);
/* also flush ob recalc, doesn't take much overhead, but used for particles */
- DAG_id_tag_update(&obedit->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_OB | OB_RECALC_DATA);
WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
@@ -501,43 +566,14 @@ bool ED_object_editmode_exit(bContext *C, int flag)
return ED_object_editmode_exit_ex(bmain, scene, obedit, flag);
}
-bool ED_object_editmode_enter(bContext *C, int flag)
+bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Base *base = NULL;
- Object *ob;
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = NULL;
bool ok = false;
- if (ID_IS_LINKED(scene)) {
+ if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED(ob)) {
return false;
}
- if (sa && sa->spacetype == SPACE_VIEW3D)
- v3d = sa->spacedata.first;
-
- if ((flag & EM_IGNORE_LAYER) == 0) {
- base = CTX_data_active_base(C); /* active layer checked here for view3d */
-
- if ((base == NULL) ||
- (v3d && (base->lay & v3d->lay) == 0) ||
- (!v3d && (base->lay & scene->lay) == 0))
- {
- return false;
- }
- }
- else {
- base = scene->basact;
- }
-
- if (ELEM(NULL, base, base->object, base->object->data)) {
- return false;
- }
-
- ob = base->object;
-
/* this checks actual object->data, for cases when other scenes have it in editmode context */
if (BKE_object_is_in_editmode(ob)) {
return true;
@@ -552,17 +588,11 @@ bool ED_object_editmode_enter(bContext *C, int flag)
ob->restore_mode = ob->mode;
- /* note, when switching scenes the object can have editmode data but
- * not be scene->obedit: bug 22954, this avoids calling self eternally */
- if ((ob->restore_mode & OB_MODE_EDIT) == 0)
- ED_object_mode_toggle(C, ob->mode);
-
ob->mode = OB_MODE_EDIT;
if (ob->type == OB_MESH) {
BMEditMesh *em;
ok = 1;
- scene->obedit = ob; /* context sees this */
const bool use_key_index = mesh_needs_keyindex(bmain, ob->data);
@@ -575,53 +605,49 @@ bool ED_object_editmode_enter(bContext *C, int flag)
BKE_editmesh_tessface_calc(em);
}
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MESH, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL);
}
else if (ob->type == OB_ARMATURE) {
ok = 1;
- scene->obedit = ob;
ED_armature_to_edit(ob->data);
/* to ensure all goes in restposition and without striding */
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* XXX: should this be OB_RECALC_DATA? */
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* XXX: should this be OB_RECALC_DATA? */
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_ARMATURE, scene);
}
else if (ob->type == OB_FONT) {
- scene->obedit = ob; /* XXX for context */
ok = 1;
ED_curve_editfont_make(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene);
}
else if (ob->type == OB_MBALL) {
- scene->obedit = ob; /* XXX for context */
ok = 1;
ED_mball_editmball_make(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene);
}
else if (ob->type == OB_LATTICE) {
- scene->obedit = ob; /* XXX for context */
ok = 1;
BKE_editlattice_make(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene);
}
else if (ob->type == OB_SURF || ob->type == OB_CURVE) {
ok = 1;
- scene->obedit = ob; /* XXX for context */
ED_curve_editnurb_make(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene);
}
if (ok) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else {
- scene->obedit = NULL; /* XXX for context */
- ob->mode &= ~OB_MODE_EDIT;
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
+ if ((flag & EM_NO_CONTEXT) == 0) {
+ ob->mode &= ~OB_MODE_EDIT;
+ }
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
}
if (flag & EM_WAITCURSOR) waitcursor(0);
@@ -629,28 +655,75 @@ bool ED_object_editmode_enter(bContext *C, int flag)
return (ob->mode & OB_MODE_EDIT) != 0;
}
-static int editmode_toggle_exec(bContext *C, wmOperator *op)
+bool ED_object_editmode_enter(bContext *C, int flag)
{
Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob;
+
+ if ((flag & EM_IGNORE_LAYER) == 0) {
+ ob = CTX_data_active_object(C); /* active layer checked here for view3d */
+ }
+ else {
+ ob = view_layer->basact->object;
+ }
+ if ((ob == NULL) || ID_IS_LINKED(ob)) {
+ return false;
+ }
+ return ED_object_editmode_enter_ex(bmain, scene, ob, flag);
+}
+
+static int editmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
const int mode_flag = OB_MODE_EDIT;
const bool is_mode_set = (CTX_data_edit_object(C) != NULL);
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Object *obact = OBACT(view_layer);
if (!is_mode_set) {
- Object *ob = CTX_data_active_object(C);
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
}
}
if (!is_mode_set) {
ED_object_editmode_enter(C, EM_WAITCURSOR);
+ if (obact->mode & mode_flag) {
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, v3d, ob)
+ {
+ if ((ob != obact) && (ob->type == obact->type)) {
+ ED_object_editmode_enter_ex(bmain, scene, ob, EM_WAITCURSOR | EM_NO_CONTEXT);
+ }
+ }
+ FOREACH_SELECTED_OBJECT_END;
+ }
}
else {
ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
+ if ((obact->mode & mode_flag) == 0) {
+ FOREACH_OBJECT_BEGIN(view_layer, ob)
+ {
+ if ((ob != obact) && (ob->type == obact->type)) {
+ ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA | EM_WAITCURSOR);
+ }
+ }
+ FOREACH_OBJECT_END;
+ }
}
+
ED_space_image_uv_sculpt_update(bmain, CTX_wm_manager(C), scene);
+ WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode);
+
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
return OPERATOR_FINISHED;
}
@@ -663,8 +736,9 @@ static bool editmode_toggle_poll(bContext *C)
return 0;
/* if hidden but in edit mode, we still display */
- if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT))
+ if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) {
return 0;
+ }
return OB_TYPE_SUPPORT_EDITMODE(ob->type);
}
@@ -689,34 +763,71 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
static int posemode_exec(bContext *C, wmOperator *op)
{
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
Base *base = CTX_data_active_base(C);
- Object *ob = base->object;
+ Object *obact = base->object;
const int mode_flag = OB_MODE_POSE;
- bool is_mode_set = (ob->mode & mode_flag) != 0;
+ bool is_mode_set = (obact->mode & mode_flag) != 0;
if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ if (!ED_object_mode_compat_set(C, obact, mode_flag, op->reports)) {
return OPERATOR_CANCELLED;
}
}
- if (ob->type == OB_ARMATURE) {
- if (ob == CTX_data_edit_object(C)) {
- ED_object_editmode_exit(C, EM_FREEDATA);
- is_mode_set = false;
- }
+ if (obact->type != OB_ARMATURE) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ if (obact == CTX_data_edit_object(C)) {
+ ED_object_editmode_exit(C, EM_FREEDATA);
+ is_mode_set = false;
+ }
- if (is_mode_set) {
- ED_object_posemode_exit(C, ob);
+ if (is_mode_set) {
+ bool ok = ED_object_posemode_exit(C, obact);
+ if (ok) {
+ struct Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_OBJECT_BEGIN(view_layer, ob)
+ {
+ if ((ob != obact) &&
+ (ob->type == OB_ARMATURE) &&
+ (ob->mode & mode_flag))
+ {
+ ED_object_posemode_exit_ex(bmain, ob);
+ }
+ }
+ FOREACH_OBJECT_END;
}
- else {
- ED_object_posemode_enter(C, ob);
+ }
+ else {
+ bool ok = ED_object_posemode_enter(C, obact);
+ if (ok) {
+ struct Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, v3d, ob)
+ {
+ if ((ob != obact) &&
+ (ob->type == OB_ARMATURE) &&
+ (ob->mode == OB_MODE_OBJECT) &&
+ (!ID_IS_LINKED(ob)))
+ {
+ ED_object_posemode_enter_ex(bmain, ob);
+ }
+ }
+ FOREACH_SELECTED_OBJECT_END;
}
+ }
- return OPERATOR_FINISHED;
+ WM_msg_publish_rna_prop(mbus, &obact->id, obact, Object, mode);
+
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
}
- return OPERATOR_PASS_THROUGH;
+ return OPERATOR_FINISHED;
}
void OBJECT_OT_posemode_toggle(wmOperatorType *ot)
@@ -734,102 +845,6 @@ void OBJECT_OT_posemode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob)
-{
-//XXX no longer used - to be removed - replaced by game_properties_copy_exec
- bProperty *prop;
- Base *base;
- int nr, tot = 0;
- char *str;
-
- prop = ob->prop.first;
- while (prop) {
- tot++;
- prop = prop->next;
- }
-
- str = MEM_callocN(50 + 33 * tot, "copymenu prop");
-
- if (tot)
- strcpy(str, "Copy Property %t|Replace All|Merge All|%l");
- else
- strcpy(str, "Copy Property %t|Clear All (no properties on active)");
-
- tot = 0;
- prop = ob->prop.first;
- while (prop) {
- tot++;
- strcat(str, "|");
- strcat(str, prop->name);
- prop = prop->next;
- }
-
- nr = pupmenu(str);
-
- if (nr == 1 || nr == 2) {
- for (base = FIRSTBASE; base; base = base->next) {
- if ((base != BASACT) && (TESTBASELIB(v3d, base))) {
- if (nr == 1) { /* replace */
- BKE_bproperty_copy_list(&base->object->prop, &ob->prop);
- }
- else {
- for (prop = ob->prop.first; prop; prop = prop->next) {
- BKE_bproperty_object_set(base->object, prop);
- }
- }
- }
- }
- }
- else if (nr > 0) {
- prop = BLI_findlink(&ob->prop, nr - 4); /* account for first 3 menu items & menu index starting at 1*/
-
- if (prop) {
- for (base = FIRSTBASE; base; base = base->next) {
- if ((base != BASACT) && (TESTBASELIB(v3d, base))) {
- BKE_bproperty_object_set(base->object, prop);
- }
- }
- }
- }
- MEM_freeN(str);
-
-}
-
-static void copymenu_logicbricks(Scene *scene, View3D *v3d, Object *ob)
-{
-//XXX no longer used - to be removed - replaced by logicbricks_copy_exec
- Base *base;
-
- for (base = FIRSTBASE; base; base = base->next) {
- if (base->object != ob) {
- if (TESTBASELIB(v3d, base)) {
-
- /* first: free all logic */
- free_sensors(&base->object->sensors);
- unlink_controllers(&base->object->controllers);
- free_controllers(&base->object->controllers);
- unlink_actuators(&base->object->actuators);
- free_actuators(&base->object->actuators);
-
- /* now copy it, this also works without logicbricks! */
- clear_sca_new_poins_ob(ob);
- copy_sensors(&base->object->sensors, &ob->sensors, 0);
- copy_controllers(&base->object->controllers, &ob->controllers, 0);
- copy_actuators(&base->object->actuators, &ob->actuators, 0);
- set_sca_new_poins_ob(base->object);
-
- /* some menu settings */
- base->object->scavisflag = ob->scavisflag;
- base->object->scaflag = ob->scaflag;
-
- /* set the initial state */
- base->object->state = ob->state;
- base->object->init_state = ob->init_state;
- }
- }
- }
-}
-
/* both pointers should exist */
static void copy_texture_space(Object *to, Object *ob)
{
@@ -881,40 +896,32 @@ static void copy_texture_space(Object *to, Object *ob)
}
/* UNUSED, keep in case we want to copy functionality for use elsewhere */
-static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
+static void copy_attr(Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, short event)
{
Object *ob;
Base *base;
Curve *cu, *cu1;
Nurb *nu;
- bool do_depgraph_update = false;
if (ID_IS_LINKED(scene)) return;
- if (!(ob = OBACT)) return;
+ if (!(ob = OBACT(view_layer))) return;
- if (scene->obedit) { // XXX get from context
+ if (BKE_object_is_in_editmode(ob)) {
/* obedit_copymenu(); */
return;
}
- if (event == 9) {
- copymenu_properties(scene, v3d, ob);
- return;
- }
- else if (event == 10) {
- copymenu_logicbricks(scene, v3d, ob);
- return;
- }
- else if (event == 24) {
+
+ if (event == 24) {
/* moved to BKE_object_link_modifiers */
/* copymenu_modifiers(bmain, scene, v3d, ob); */
return;
}
- for (base = FIRSTBASE; base; base = base->next) {
- if (base != BASACT) {
+ for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ if (base != BASACT(view_layer)) {
if (TESTBASELIB(v3d, base)) {
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
if (event == 1) { /* loc */
copy_v3_v3(base->object->loc, ob->loc);
@@ -953,30 +960,6 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
if (ob->dup_group)
id_us_plus(&ob->dup_group->id);
}
- else if (event == 7) { /* mass */
- base->object->mass = ob->mass;
- }
- else if (event == 8) { /* damping */
- base->object->damping = ob->damping;
- base->object->rdamping = ob->rdamping;
- }
- else if (event == 11) { /* all physical attributes */
- base->object->gameflag = ob->gameflag;
- base->object->inertia = ob->inertia;
- base->object->formfactor = ob->formfactor;
- base->object->damping = ob->damping;
- base->object->rdamping = ob->rdamping;
- base->object->min_vel = ob->min_vel;
- base->object->max_vel = ob->max_vel;
- base->object->min_angvel = ob->min_angvel;
- base->object->max_angvel = ob->max_angvel;
- if (ob->gameflag & OB_BOUNDS) {
- base->object->collision_boundtype = ob->collision_boundtype;
- }
- base->object->margin = ob->margin;
- base->object->bsoft = copy_bulletsoftbody(ob->bsoft, 0);
-
- }
else if (event == 17) { /* tex space */
copy_texture_space(base->object, ob);
}
@@ -1017,7 +1000,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
BLI_strncpy(cu1->family, cu->family, sizeof(cu1->family));
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
}
}
else if (event == 19) { /* bevel settings */
@@ -1033,7 +1016,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
cu1->ext1 = cu->ext1;
cu1->ext2 = cu->ext2;
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
}
}
else if (event == 25) { /* curve resolution */
@@ -1052,7 +1035,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
nu = nu->next;
}
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
}
}
else if (event == 21) {
@@ -1068,25 +1051,26 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
}
modifier_copyData(md, tmd);
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_DATA);
}
}
}
else if (event == 22) {
/* Copy the constraint channels over */
BKE_constraints_copy(&base->object->constraints, &ob->constraints, true);
-
- do_depgraph_update = true;
+ DEG_id_tag_update(&base->object->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
else if (event == 23) {
- base->object->softflag = ob->softflag;
- if (base->object->soft) sbFree(base->object->soft);
-
- base->object->soft = copy_softbody(ob->soft, 0);
+ sbFree(base->object);
+ BKE_object_copy_softbody(base->object, ob, 0);
if (!modifiers_findByType(base->object, eModifierType_Softbody)) {
BLI_addhead(&base->object->modifiers, modifier_new(eModifierType_Softbody));
}
+
+ DEG_id_tag_update(&base->object->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
else if (event == 26) {
#if 0 // XXX old animation system
@@ -1127,20 +1111,17 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
}
}
}
-
- if (do_depgraph_update)
- DAG_relations_tag_update(bmain);
}
-static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, View3D *v3d)
+static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d, Object *obedit)
{
Object *ob;
short event;
char str[512];
- if (!(ob = OBACT)) return;
+ if (!(ob = OBACT(view_layer))) return;
- if (scene->obedit) { /* XXX get from context */
+ if (obedit) {
/* if (ob->type == OB_MESH) */
/* XXX mesh_copy_menu(); */
return;
@@ -1186,7 +1167,7 @@ static void UNUSED_FUNCTION(copy_attr_menu) (Main *bmain, Scene *scene, View3D *
event = pupmenu(str);
if (event <= 0) return;
- copy_attr(bmain, scene, v3d, event);
+ copy_attr(bmain, scene, view_layer, v3d, event);
}
/* ******************* force field toggle operator ***************** */
@@ -1253,9 +1234,15 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot)
*
* To be called from various tools that do incremental updates
*/
-void ED_objects_recalculate_paths(bContext *C, Scene *scene)
+void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_only)
{
+ /* Transform doesn't always have context available to do update. */
+ if (C == NULL) {
+ return;
+ }
+
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ListBase targets = {NULL, NULL};
/* loop over objects in scene */
@@ -1268,8 +1255,20 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene)
CTX_DATA_END;
/* recalculate paths, then free */
- animviz_calc_motionpaths(bmain, scene, &targets);
+ animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, true, current_frame_only);
BLI_freelistN(&targets);
+
+ if (!current_frame_only) {
+ /* Tag objects for copy on write - so paths will draw/redraw
+ * For currently frame only we update evaluated object directly. */
+ CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects)
+ {
+ if (ob->mpath) {
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+ CTX_DATA_END;
+ }
}
@@ -1291,7 +1290,7 @@ static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEv
/* show popup dialog to allow editing of range... */
/* FIXME: hardcoded dimensions here are just arbitrary */
- return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 10 * UI_UNIT_Y);
+ return WM_operator_props_dialog_popup(C, op, 200, 200);
}
/* Calculate/recalculate whole paths (avs.path_sf to avs.path_ef) */
@@ -1316,7 +1315,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene);
+ ED_objects_recalculate_paths(C, scene, false);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1366,7 +1365,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene);
+ ED_objects_recalculate_paths(C, scene, false);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1398,6 +1397,9 @@ static void object_clear_mpath(Object *ob)
animviz_free_motionpath(ob->mpath);
ob->mpath = NULL;
ob->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
+
+ /* tag object for copy on write - so removed paths don't still show */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -1466,6 +1468,43 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
+/* --------- */
+
+static int object_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* loop over all edtiable objects in scene */
+ CTX_DATA_BEGIN(C, Object *, ob, editable_objects)
+ {
+ /* use Preview Range or Full Frame Range - whichever is in use */
+ ob->avs.path_sf = PSFRA;
+ ob->avs.path_ef = PEFRA;
+
+ /* tag for updates */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ }
+ CTX_DATA_END;
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_paths_range_update(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Range from Scene";
+ ot->idname = "OBJECT_OT_paths_range_update";
+ ot->description = "Update frame range for motion paths from the Scene's current frame range";
+
+ /* callbacks */
+ ot->exec = object_update_paths_range_exec;
+ ot->poll = ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/********************** Smooth/Flat *********************/
@@ -1489,7 +1528,8 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
if (ob->type == OB_MESH) {
BKE_mesh_smooth_flag_set(ob, !clear);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
done = true;
@@ -1502,7 +1542,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
else nu->flag &= ~ME_SMOOTH;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
done = true;
@@ -1553,75 +1593,12 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/* ********************** */
-static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
-{
- /* all selected objects with an image map: scale in image aspect */
- Base *base;
- Object *ob;
- Material *ma;
- Tex *tex;
- float x, y, space;
- int a, b, done;
-
- if (scene->obedit) return; // XXX get from context
- if (ID_IS_LINKED(scene)) return;
-
- for (base = FIRSTBASE; base; base = base->next) {
- if (TESTBASELIB(v3d, base)) {
- ob = base->object;
- done = false;
-
- for (a = 1; a <= ob->totcol; a++) {
- ma = give_current_material(ob, a);
- if (ma) {
- for (b = 0; b < MAX_MTEX; b++) {
- if (ma->mtex[b] && ma->mtex[b]->tex) {
- tex = ma->mtex[b]->tex;
- if (tex->type == TEX_IMAGE && tex->ima) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, NULL, NULL);
-
- /* texturespace */
- space = 1.0;
- if (ob->type == OB_MESH) {
- float size[3];
- BKE_mesh_texspace_get(ob->data, NULL, NULL, size);
- space = size[0] / size[1];
- }
- else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
- float size[3];
- BKE_curve_texspace_get(ob->data, NULL, NULL, size);
- space = size[0] / size[1];
- }
-
- x = ibuf->x / space;
- y = ibuf->y;
-
- if (x > y) ob->size[0] = ob->size[1] * x / y;
- else ob->size[1] = ob->size[0] * y / x;
-
- done = true;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
-
- BKE_image_release_ibuf(tex->ima, ibuf, NULL);
- }
- }
- if (done) break;
- }
- }
- if (done) break;
- }
- }
- }
-
-}
-
static const EnumPropertyItem *object_mode_set_itemsf(
bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
const EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
Object *ob;
- bGPdata *gpd;
int totitem = 0;
if (!C) /* needed for docs */
@@ -1637,7 +1614,9 @@ static const EnumPropertyItem *object_mode_set_itemsf(
(input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) ||
(input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) ||
(ELEM(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT,
- OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) ||
+ OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) ||
+ (ELEM(input->value, OB_MODE_GPENCIL_EDIT, OB_MODE_GPENCIL_PAINT,
+ OB_MODE_GPENCIL_SCULPT, OB_MODE_GPENCIL_WEIGHT) && (ob->type == OB_GPENCIL)) ||
(input->value == OB_MODE_OBJECT))
{
RNA_enum_item_add(&item, &totitem, input);
@@ -1650,14 +1629,6 @@ static const EnumPropertyItem *object_mode_set_itemsf(
RNA_enum_items_add_value(&item, &totitem, input, OB_MODE_OBJECT);
}
- /* On top of all the rest, GPencil Stroke Edit Mode
- * is available if there's a valid gp datablock...
- */
- gpd = CTX_data_gpencil_data(C);
- if (gpd) {
- RNA_enum_items_add_value(&item, &totitem, rna_enum_object_mode_items, OB_MODE_GPENCIL);
- }
-
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1680,30 +1651,32 @@ static bool object_mode_set_poll(bContext *C)
static int object_mode_set_exec(bContext *C, wmOperator *op)
{
+ bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_or_submode");
Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
eObjectMode mode = RNA_enum_get(op->ptr, "mode");
eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT;
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
- if (gpd) {
- /* GP Mode is not bound to a specific object. Therefore,
- * we don't want it to be actually saved on any objects,
- * as weirdness can happen if you select other objects,
- * or load old files.
- *
- * Instead, we use the following 2 rules to ensure that
- * the mode selector works as expected:
- * 1) If there's no object, we want to enter editmode.
- * (i.e. with no object, we're in object mode)
- * 2) Otherwise, exit stroke editmode, so that we can
- * enter another mode...
- */
- if (!ob || (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
- WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
+ if (use_submode) {
+ /* When not changing modes use submodes, see: T55162. */
+ if (toggle == false) {
+ if (mode == restore_mode) {
+ switch (mode) {
+ case OB_MODE_EDIT:
+ WM_menu_name_call(C, "VIEW3D_MT_edit_mesh_select_mode", WM_OP_INVOKE_REGION_WIN);
+ return OPERATOR_INTERFACE;
+ default:
+ break;
+ }
+ }
}
}
+ /* by default the operator assume is a mesh, but if gp object change mode */
+ if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
+ mode = OB_MODE_GPENCIL_EDIT;
+ }
+
if (!ob || !ED_object_mode_compat_test(ob, mode))
return OPERATOR_PASS_THROUGH;
@@ -1732,6 +1705,14 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
}
}
+ /* if type is OB_GPENCIL, set cursor mode */
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ if (ob->data) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ ED_gpencil_setup_modes(C, gpd, ob->mode);
+ }
+ }
+
return OPERATOR_FINISHED;
}
@@ -1760,453 +1741,408 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/************************ Game Properties ***********************/
-
-static int game_property_new_exec(bContext *C, wmOperator *op)
+void OBJECT_OT_mode_set_or_submode(wmOperatorType *ot)
{
- Object *ob = CTX_data_active_object(C);
- bProperty *prop;
- char name[MAX_NAME];
- int type = RNA_enum_get(op->ptr, "type");
-
- prop = BKE_bproperty_new(type);
- BLI_addtail(&ob->prop, prop);
-
- RNA_string_get(op->ptr, "name", name);
- if (name[0] != '\0') {
- BLI_strncpy(prop->name, name, sizeof(prop->name));
- }
-
- BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name));
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
- return OPERATOR_FINISHED;
-}
-
+ PropertyRNA *prop;
-void OBJECT_OT_game_property_new(wmOperatorType *ot)
-{
/* identifiers */
- ot->name = "New Game Property";
- ot->description = "Create a new property available to the game engine";
- ot->idname = "OBJECT_OT_game_property_new";
+ ot->name = "Set Object Mode or Submode";
+ ot->description = "Sets the object interaction mode";
+ ot->idname = "OBJECT_OT_mode_set_or_submode";
/* api callbacks */
- ot->exec = game_property_new_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->exec = object_mode_set_exec;
+
+ ot->poll = object_mode_set_poll; //ED_operator_object_active_editable;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = 0; /* no register/undo here, leave it to operators being called */
- RNA_def_enum(ot->srna, "type", rna_enum_gameproperty_type_items, GPROP_FLOAT, "Type", "Type of game property to add");
- RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the game property to add");
+ ot->prop = RNA_def_enum(ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
+ RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-static int game_property_remove_exec(bContext *C, wmOperator *op)
+bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_only, float r_center[3])
{
- Object *ob = CTX_data_active_object(C);
- bProperty *prop;
- int index = RNA_int_get(op->ptr, "index");
+ switch (obedit->type) {
+ case OB_MESH:
+ {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMEditSelection ese;
- if (!ob)
- return OPERATOR_CANCELLED;
+ if (BM_select_history_active_get(em->bm, &ese)) {
+ BM_editselection_center(&ese, r_center);
+ return true;
+ }
+ break;
+ }
+ case OB_ARMATURE:
+ {
+ bArmature *arm = obedit->data;
+ EditBone *ebo = arm->act_edbone;
+
+ if (ebo && (!select_only || (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL)))) {
+ copy_v3_v3(r_center, ebo->head);
+ return true;
+ }
- prop = BLI_findlink(&ob->prop, index);
+ break;
+ }
+ case OB_CURVE:
+ case OB_SURF:
+ {
+ Curve *cu = obedit->data;
- if (prop) {
- BLI_remlink(&ob->prop, prop);
- BKE_bproperty_free(prop);
+ if (ED_curve_active_center(cu, r_center)) {
+ return true;
+ }
+ break;
+ }
+ case OB_MBALL:
+ {
+ MetaBall *mb = obedit->data;
+ MetaElem *ml_act = mb->lastelem;
- WM_event_add_notifier(C, NC_LOGIC, NULL);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
+ if (ml_act && (!select_only || (ml_act->flag & SELECT))) {
+ copy_v3_v3(r_center, &ml_act->x);
+ return true;
+ }
+ break;
+ }
+ case OB_LATTICE:
+ {
+ BPoint *actbp = BKE_lattice_active_point_get(obedit->data);
+
+ if (actbp) {
+ copy_v3_v3(r_center, actbp->vec);
+ return true;
+ }
+ break;
+ }
}
+
+ return false;
}
-void OBJECT_OT_game_property_remove(wmOperatorType *ot)
+static bool move_to_collection_poll(bContext *C)
{
- /* identifiers */
- ot->name = "Remove Game Property";
- ot->description = "Remove game property";
- ot->idname = "OBJECT_OT_game_property_remove";
-
- /* api callbacks */
- ot->exec = game_property_remove_exec;
- ot->poll = ED_operator_object_active_editable;
+ if (CTX_wm_space_outliner(C) != NULL) {
+ return ED_outliner_collections_editor_poll(C);
+ }
+ else {
+ View3D *v3d = CTX_wm_view3d(C);
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ if (v3d && v3d->localvd) {
+ return false;
+ }
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to remove ", 0, INT_MAX);
+ return ED_operator_object_active_editable(C);
+ }
}
-#define GAME_PROPERTY_MOVE_UP 1
-#define GAME_PROPERTY_MOVE_DOWN -1
-
-static int game_property_move(bContext *C, wmOperator *op)
+static int move_to_collection_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- bProperty *prop;
- bProperty *otherprop = NULL;
- const int index = RNA_int_get(op->ptr, "index");
- const int dir = RNA_enum_get(op->ptr, "direction");
-
- if (ob == NULL)
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "collection_index");
+ const bool is_link = STREQ(op->idname, "OBJECT_OT_link_to_collection");
+ const bool is_new = RNA_boolean_get(op->ptr, "is_new");
+ Collection *collection;
+ ListBase objects = {NULL};
+
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ BKE_report(op->reports, RPT_ERROR, "No collection selected");
return OPERATOR_CANCELLED;
+ }
- prop = BLI_findlink(&ob->prop, index);
- /* invalid index */
- if (prop == NULL)
+ int collection_index = RNA_property_int_get(op->ptr, prop);
+ collection = BKE_collection_from_index(CTX_data_scene(C), collection_index);
+ if (collection == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found");
return OPERATOR_CANCELLED;
-
- if (dir == GAME_PROPERTY_MOVE_UP) {
- otherprop = prop->prev;
}
- else if (dir == GAME_PROPERTY_MOVE_DOWN) {
- otherprop = prop->next;
+
+ if (CTX_wm_space_outliner(C) != NULL) {
+ ED_outliner_selected_objects_get(C, &objects);
}
else {
- BLI_assert(0);
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
+ {
+ BLI_addtail(&objects, BLI_genericNodeN(ob));
+ }
+ CTX_DATA_END;
}
- if (prop && otherprop) {
- BLI_listbase_swaplinks(&ob->prop, prop, otherprop);
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
- return OPERATOR_FINISHED;
+ if (is_new) {
+ char new_collection_name[MAX_NAME];
+ RNA_string_get(op->ptr, "new_collection_name", new_collection_name);
+ collection = BKE_collection_add(bmain, collection, new_collection_name);
}
- else {
+
+ Object *single_object = BLI_listbase_is_single(&objects) ?
+ ((LinkData *)objects.first)->data : NULL;
+
+ if ((single_object != NULL) &&
+ is_link &&
+ BLI_findptr(&collection->gobject, single_object, offsetof(CollectionObject, ob)))
+ {
+ BKE_reportf(op->reports, RPT_ERROR, "%s already in %s", single_object->id.name + 2, collection->id.name + 2);
+ BLI_freelistN(&objects);
return OPERATOR_CANCELLED;
}
-}
-
-void OBJECT_OT_game_property_move(wmOperatorType *ot)
-{
- static const EnumPropertyItem direction_property_move[] = {
- {GAME_PROPERTY_MOVE_UP, "UP", 0, "Up", ""},
- {GAME_PROPERTY_MOVE_DOWN, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
- };
- PropertyRNA *prop;
- /* identifiers */
- ot->name = "Move Game Property";
- ot->description = "Move game property";
- ot->idname = "OBJECT_OT_game_property_move";
+ for (LinkData *link = objects.first; link; link = link->next) {
+ Object *ob = link->data;
- /* api callbacks */
- ot->exec = game_property_move;
- ot->poll = ED_operator_object_active_editable;
+ if (!is_link) {
+ BKE_collection_object_move(bmain, scene, collection, NULL, ob);
+ }
+ else {
+ BKE_collection_object_add(bmain, collection, ob);
+ }
+ }
+ BLI_freelistN(&objects);
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ BKE_reportf(op->reports,
+ RPT_INFO,
+ "%s %s to %s",
+ (single_object != NULL) ? single_object->id.name + 2 : "Objects",
+ is_link ? "linked" : "moved",
+ collection->id.name + 2);
- /* properties */
- prop = RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to move", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN);
- RNA_def_enum(ot->srna, "direction", direction_property_move, 0, "Direction",
- "Direction for moving the property");
-}
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
-#undef GAME_PROPERTY_MOVE_UP
-#undef GAME_PROPERTY_MOVE_DOWN
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
-#define COPY_PROPERTIES_REPLACE 1
-#define COPY_PROPERTIES_MERGE 2
-#define COPY_PROPERTIES_COPY 3
+ return OPERATOR_FINISHED;
+}
-static const EnumPropertyItem game_properties_copy_operations[] = {
- {COPY_PROPERTIES_REPLACE, "REPLACE", 0, "Replace Properties", ""},
- {COPY_PROPERTIES_MERGE, "MERGE", 0, "Merge Properties", ""},
- {COPY_PROPERTIES_COPY, "COPY", 0, "Copy a Property", ""},
- {0, NULL, 0, NULL, NULL}
+struct MoveToCollectionData {
+ struct MoveToCollectionData *next, *prev;
+ int index;
+ struct Collection *collection;
+ struct ListBase submenus;
+ PointerRNA ptr;
+ struct wmOperatorType *ot;
};
-static const EnumPropertyItem *gameprops_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static int move_to_collection_menus_create(wmOperator *op, MoveToCollectionData *menu)
{
- Object *ob = ED_object_active_context(C);
- EnumPropertyItem tmp = {0, "", 0, "", ""};
- EnumPropertyItem *item = NULL;
- bProperty *prop;
- int a, totitem = 0;
-
- if (!ob)
- return DummyRNA_NULL_items;
-
- for (a = 1, prop = ob->prop.first; prop; prop = prop->next, a++) {
- tmp.value = a;
- tmp.identifier = prop->name;
- tmp.name = prop->name;
- RNA_enum_item_add(&item, &totitem, &tmp);
+ int index = menu->index;
+ for (CollectionChild *child = menu->collection->children.first;
+ child != NULL;
+ child = child->next)
+ {
+ Collection *collection = child->collection;
+ MoveToCollectionData *submenu = MEM_callocN(sizeof(MoveToCollectionData),
+ "MoveToCollectionData submenu - expected memleak");
+ BLI_addtail(&menu->submenus, submenu);
+ submenu->collection = collection;
+ submenu->index = ++index;
+ index = move_to_collection_menus_create(op, submenu);
+ submenu->ot = op->type;
}
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
+ return index;
}
-static int game_property_copy_exec(bContext *C, wmOperator *op)
+static void move_to_collection_menus_free_recursive(MoveToCollectionData *menu)
{
- Object *ob = ED_object_active_context(C);
- bProperty *prop;
- int type = RNA_enum_get(op->ptr, "operation");
- int propid = RNA_enum_get(op->ptr, "property");
-
- if (propid > 0) { /* copy */
- prop = BLI_findlink(&ob->prop, propid - 1);
-
- if (prop) {
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if (ob != ob_iter)
- BKE_bproperty_object_set(ob_iter, prop);
- } CTX_DATA_END;
- }
+ for (MoveToCollectionData *submenu = menu->submenus.first;
+ submenu != NULL;
+ submenu = submenu->next)
+ {
+ move_to_collection_menus_free_recursive(submenu);
}
+ BLI_freelistN(&menu->submenus);
+}
- else {
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if (ob != ob_iter) {
- if (type == COPY_PROPERTIES_REPLACE) {
- BKE_bproperty_copy_list(&ob_iter->prop, &ob->prop);
- }
- else {
- /* merge - the default when calling with no argument */
- for (prop = ob->prop.first; prop; prop = prop->next) {
- BKE_bproperty_object_set(ob_iter, prop);
- }
- }
- }
- }
- CTX_DATA_END;
+static void move_to_collection_menus_free(MoveToCollectionData **menu)
+{
+ if (*menu == NULL) {
+ return;
}
- return OPERATOR_FINISHED;
+ move_to_collection_menus_free_recursive(*menu);
+ MEM_freeN(*menu);
+ *menu = NULL;
}
-void OBJECT_OT_game_property_copy(wmOperatorType *ot)
+static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v)
{
- PropertyRNA *prop;
- /* identifiers */
- ot->name = "Copy Game Property";
- ot->idname = "OBJECT_OT_game_property_copy";
- ot->description = "Copy/merge/replace a game property from active object to all selected objects";
+ MoveToCollectionData *menu = menu_v;
+ const char *name = BKE_collection_ui_name_get(menu->collection);
- /* api callbacks */
- ot->exec = game_property_copy_exec;
- ot->poll = ED_operator_object_active_editable;
+ uiItemIntO(layout,
+ name,
+ ICON_NONE,
+ menu->ot->idname,
+ "collection_index",
+ menu->index);
+ uiItemS(layout);
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ for (MoveToCollectionData *submenu = menu->submenus.first;
+ submenu != NULL;
+ submenu = submenu->next)
+ {
+ move_to_collection_menus_items(layout, submenu);
+ }
+
+ uiItemS(layout);
- RNA_def_enum(ot->srna, "operation", game_properties_copy_operations, 3, "Operation", "");
- prop = RNA_def_enum(ot->srna, "property", DummyRNA_NULL_items, 0, "Property", "Properties to copy");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_ENUM_NO_TRANSLATE);
- RNA_def_enum_funcs(prop, gameprops_itemf);
- ot->prop = prop;
+ WM_operator_properties_create_ptr(&menu->ptr, menu->ot);
+ RNA_int_set(&menu->ptr, "collection_index", menu->index);
+ RNA_boolean_set(&menu->ptr, "is_new", true);
+
+ uiItemFullO_ptr(layout,
+ menu->ot,
+ "New Collection",
+ ICON_ADD,
+ menu->ptr.data,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ NULL);
}
-static int game_property_clear_exec(bContext *C, wmOperator *UNUSED(op))
+static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionData *menu)
{
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- BKE_bproperty_free_list(&ob_iter->prop);
+ if (BLI_listbase_is_empty(&menu->submenus)) {
+ uiItemIntO(layout,
+ menu->collection->id.name + 2,
+ ICON_NONE,
+ menu->ot->idname,
+ "collection_index",
+ menu->index);
+ }
+ else {
+ uiItemMenuF(layout,
+ menu->collection->id.name + 2,
+ ICON_NONE,
+ move_to_collection_menu_create,
+ menu);
}
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
- return OPERATOR_FINISHED;
}
-void OBJECT_OT_game_property_clear(wmOperatorType *ot)
+
+/* This is allocated statically because we need this available for the menus creation callback. */
+static MoveToCollectionData *master_collection_menu = NULL;
+
+static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- /* identifiers */
- ot->name = "Clear Game Properties";
- ot->idname = "OBJECT_OT_game_property_clear";
- ot->description = "Remove all game properties from all selected objects";
+ Scene *scene = CTX_data_scene(C);
- /* api callbacks */
- ot->exec = game_property_clear_exec;
- ot->poll = ED_operator_object_active_editable;
+ /* Reset the menus data for the current master collection, and free previously allocated data. */
+ move_to_collection_menus_free(&master_collection_menu);
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
+ PropertyRNA *prop;
+ prop = RNA_struct_find_property(op->ptr, "collection_index");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ int collection_index = RNA_property_int_get(op->ptr, prop);
-/************************ Copy Logic Bricks ***********************/
+ if (RNA_boolean_get(op->ptr, "is_new")) {
+ prop = RNA_struct_find_property(op->ptr, "new_collection_name");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ char name[MAX_NAME];
+ Collection *collection;
-static int logicbricks_copy_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_object_active_context(C);
+ collection = BKE_collection_from_index(scene, collection_index);
+ BKE_collection_new_name_get(collection, name);
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if (ob != ob_iter) {
- /* first: free all logic */
- free_sensors(&ob_iter->sensors);
- unlink_controllers(&ob_iter->controllers);
- free_controllers(&ob_iter->controllers);
- unlink_actuators(&ob_iter->actuators);
- free_actuators(&ob_iter->actuators);
-
- /* now copy it, this also works without logicbricks! */
- clear_sca_new_poins_ob(ob);
- copy_sensors(&ob_iter->sensors, &ob->sensors, 0);
- copy_controllers(&ob_iter->controllers, &ob->controllers, 0);
- copy_actuators(&ob_iter->actuators, &ob->actuators, 0);
- set_sca_new_poins_ob(ob_iter);
-
- /* some menu settings */
- ob_iter->scavisflag = ob->scavisflag;
- ob_iter->scaflag = ob->scaflag;
-
- /* set the initial state */
- ob_iter->state = ob->state;
- ob_iter->init_state = ob->init_state;
-
- if (ob_iter->totcol == ob->totcol) {
- ob_iter->actcol = ob->actcol;
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter);
+ RNA_property_string_set(op->ptr, prop, name);
+ return WM_operator_props_dialog_popup(C, op, 200, 100);
}
}
+ return move_to_collection_exec(C, op);
}
- CTX_DATA_END;
- WM_event_add_notifier(C, NC_LOGIC, NULL);
+ Collection *master_collection = BKE_collection_master(scene);
- return OPERATOR_FINISHED;
-}
+ /* We need the data to be allocated so it's available during menu drawing.
+ * Technically we could use wmOperator->customdata. However there is no free callback
+ * called to an operator that exit with OPERATOR_INTERFACE to launch a menu.
+ *
+ * So we are left with a memory that will necessarily leak. It's a small leak though.*/
+ if (master_collection_menu == NULL) {
+ master_collection_menu = MEM_callocN(sizeof(MoveToCollectionData),
+ "MoveToCollectionData menu - expected eventual memleak");
+ }
-void OBJECT_OT_logic_bricks_copy(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Copy Logic Bricks to Selected";
- ot->description = "Copy logic bricks to other selected objects";
- ot->idname = "OBJECT_OT_logic_bricks_copy";
+ master_collection_menu->collection = master_collection;
+ master_collection_menu->ot = op->type;
+ move_to_collection_menus_create(op, master_collection_menu);
- /* api callbacks */
- ot->exec = logicbricks_copy_exec;
- ot->poll = ED_operator_object_active_editable;
+ uiPopupMenu *pup;
+ uiLayout *layout;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
+ /* Build the menus. */
+ const char *title = CTX_IFACE_(op->type->translation_context, op->type->name);
+ pup = UI_popup_menu_begin(C, title, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
-static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_object_active_context(C);
+ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
- CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
- {
- if (ob != ob_iter) {
- ob_iter->gameflag = ob->gameflag;
- ob_iter->gameflag2 = ob->gameflag2;
- ob_iter->inertia = ob->inertia;
- ob_iter->formfactor = ob->formfactor;
- ob_iter->damping = ob->damping;
- ob_iter->rdamping = ob->rdamping;
- ob_iter->min_vel = ob->min_vel;
- ob_iter->max_vel = ob->max_vel;
- ob_iter->min_angvel = ob->min_angvel;
- ob_iter->max_angvel = ob->max_angvel;
- ob_iter->obstacleRad = ob->obstacleRad;
- ob_iter->mass = ob->mass;
- copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction);
- ob_iter->collision_boundtype = ob->collision_boundtype;
- ob_iter->margin = ob->margin;
- ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft, 0);
- if (ob->restrictflag & OB_RESTRICT_RENDER)
- ob_iter->restrictflag |= OB_RESTRICT_RENDER;
- else
- ob_iter->restrictflag &= ~OB_RESTRICT_RENDER;
-
- ob_iter->col_group = ob->col_group;
- ob_iter->col_mask = ob->col_mask;
- }
- }
- CTX_DATA_END;
+ move_to_collection_menu_create(C, layout, master_collection_menu);
- return OPERATOR_FINISHED;
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
}
-void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot)
+void OBJECT_OT_move_to_collection(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
- ot->name = "Copy Game Physics Properties to Selected";
- ot->description = "Copy game physics properties to other selected objects";
- ot->idname = "OBJECT_OT_game_physics_copy";
+ ot->name = "Move to Collection";
+ ot->description = "Move objects to a scene collection";
+ ot->idname = "OBJECT_OT_move_to_collection";
/* api callbacks */
- ot->exec = game_physics_copy_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->exec = move_to_collection_exec;
+ ot->invoke = move_to_collection_invoke;
+ ot->poll = move_to_collection_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-/* generic utility function */
+ prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX,
+ "Collection Index", "Index of the collection to move to", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_string(ot->srna, "new_collection_name", NULL, MAX_NAME, "Name",
+ "Name of the newly added collection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
-bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_only, float r_center[3])
+void OBJECT_OT_link_to_collection(wmOperatorType *ot)
{
- switch (obedit->type) {
- case OB_MESH:
- {
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMEditSelection ese;
-
- if (BM_select_history_active_get(em->bm, &ese)) {
- BM_editselection_center(&ese, r_center);
- return true;
- }
- break;
- }
- case OB_ARMATURE:
- {
- bArmature *arm = obedit->data;
- EditBone *ebo = arm->act_edbone;
-
- if (ebo && (!select_only || (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL)))) {
- copy_v3_v3(r_center, ebo->head);
- return true;
- }
-
- break;
- }
- case OB_CURVE:
- case OB_SURF:
- {
- Curve *cu = obedit->data;
+ PropertyRNA *prop;
- if (ED_curve_active_center(cu, r_center)) {
- return true;
- }
- break;
- }
- case OB_MBALL:
- {
- MetaBall *mb = obedit->data;
- MetaElem *ml_act = mb->lastelem;
+ /* identifiers */
+ ot->name = "Link to Collection";
+ ot->description = "Link objects to a collection";
+ ot->idname = "OBJECT_OT_link_to_collection";
- if (ml_act && (!select_only || (ml_act->flag & SELECT))) {
- copy_v3_v3(r_center, &ml_act->x);
- return true;
- }
- break;
- }
- case OB_LATTICE:
- {
- BPoint *actbp = BKE_lattice_active_point_get(obedit->data);
+ /* api callbacks */
+ ot->exec = move_to_collection_exec;
+ ot->invoke = move_to_collection_invoke;
+ ot->poll = move_to_collection_poll;
- if (actbp) {
- copy_v3_v3(r_center, actbp->vec);
- return true;
- }
- break;
- }
- }
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- return false;
+ prop = RNA_def_int(ot->srna, "collection_index", COLLECTION_INVALID_INDEX, COLLECTION_INVALID_INDEX, INT_MAX,
+ "Collection Index", "Index of the collection to move to", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "is_new", false, "New", "Move objects to a new collection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_string(ot->srna, "new_collection_name", NULL, MAX_NAME, "Name",
+ "Name of the newly added collection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c
new file mode 100644
index 00000000000..ab710b21817
--- /dev/null
+++ b/source/blender/editors/object/object_facemap_ops.c
@@ -0,0 +1,501 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_facemap_ops.c
+ * \ingroup edobj
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_listbase.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_workspace_types.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_object.h"
+#include "BKE_object_facemap.h"
+#include "BKE_object_deform.h"
+
+#include "DEG_depsgraph.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "ED_mesh.h"
+#include "ED_object.h"
+
+#include "object_intern.h"
+
+/* called while not in editmode */
+void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
+{
+ int fmap_nr;
+ if (GS(((ID *)ob->data)->name) != ID_ME)
+ return;
+
+ /* get the face map number, exit if it can't be found */
+ fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (fmap_nr != -1) {
+ int *facemap;
+ Mesh *me = ob->data;
+
+ /* if there's is no facemap layer then create one */
+ if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL)
+ facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly);
+
+ facemap[facenum] = fmap_nr;
+ }
+}
+
+/* called while not in editmode */
+void ED_object_facemap_face_remove(Object *ob, bFaceMap *fmap, int facenum)
+{
+ int fmap_nr;
+ if (GS(((ID *)ob->data)->name) != ID_ME)
+ return;
+
+ /* get the face map number, exit if it can't be found */
+ fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (fmap_nr != -1) {
+ int *facemap;
+ Mesh *me = ob->data;
+
+ if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL)
+ return;
+
+ facemap[facenum] = -1;
+ }
+}
+
+static void object_fmap_swap_edit_mode(Object *ob, int num1, int num2)
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
+
+ if (cd_fmap_offset != -1) {
+ BMFace *efa;
+ BMIter iter;
+ int *map;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map) {
+ if (num1 != -1) {
+ if (*map == num1)
+ *map = num2;
+ else if (*map == num2)
+ *map = num1;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void object_fmap_swap_object_mode(Object *ob, int num1, int num2)
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
+ int i;
+
+ if (map) {
+ for (i = 0; i < me->totpoly; i++) {
+ if (num1 != -1) {
+ if (map[i] == num1)
+ map[i] = num2;
+ else if (map[i] == num2)
+ map[i] = num1;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void object_facemap_swap(Object *ob, int num1, int num2)
+{
+ if (BKE_object_is_in_editmode(ob))
+ object_fmap_swap_edit_mode(ob, num1, num2);
+ else
+ object_fmap_swap_object_mode(ob, num1, num2);
+}
+
+static bool face_map_supported_poll(bContext *C)
+{
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? ob->data : NULL;
+ return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib);
+}
+
+static bool face_map_supported_edit_mode_poll(bContext *C)
+{
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? ob->data : NULL;
+ if (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib) {
+ if (ob->mode == OB_MODE_EDIT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int face_map_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+
+ BKE_object_facemap_add(ob);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_face_map_add(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Face Map";
+ ot->idname = "OBJECT_OT_face_map_add";
+ ot->description = "Add a new face map to the active object";
+
+ /* api callbacks */
+ ot->poll = face_map_supported_poll;
+ ot->exec = face_map_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int face_map_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
+
+ if (fmap) {
+ BKE_object_facemap_remove(ob, fmap);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_face_map_remove(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Face Map";
+ ot->idname = "OBJECT_OT_face_map_remove";
+ ot->description = "Remove a face map from the active object";
+
+ /* api callbacks */
+ ot->poll = face_map_supported_poll;
+ ot->exec = face_map_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int face_map_assign_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
+
+ if (fmap) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
+ int *map;
+ int cd_fmap_offset;
+
+ if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP))
+ BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP);
+
+ cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ *map = ob->actfmap - 1;
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_face_map_assign(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Assign Face Map";
+ ot->idname = "OBJECT_OT_face_map_assign";
+ ot->description = "Assign faces to a face map";
+
+ /* api callbacks */
+ ot->poll = face_map_supported_edit_mode_poll;
+ ot->exec = face_map_assign_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int face_map_remove_from_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
+
+ if (fmap) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
+ int *map;
+ int cd_fmap_offset;
+ int mapindex = ob->actfmap - 1;
+
+ if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP))
+ return OPERATOR_CANCELLED;
+
+ cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && *map == mapindex) {
+ *map = -1;
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_face_map_remove_from(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove From Face Map";
+ ot->idname = "OBJECT_OT_face_map_remove_from";
+ ot->description = "Remove faces from a face map";
+
+ /* api callbacks */
+ ot->poll = face_map_supported_edit_mode_poll;
+ ot->exec = face_map_remove_from_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static void fmap_select(Object *ob, bool select)
+{
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
+ int *map;
+ int cd_fmap_offset;
+ int mapindex = ob->actfmap - 1;
+
+ if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP))
+ BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP);
+
+ cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (*map == mapindex) {
+ BM_face_select_set(em->bm, efa, select);
+ }
+ }
+}
+
+static int face_map_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
+
+ if (fmap) {
+ fmap_select(ob, true);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_face_map_select(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Face Map Faces";
+ ot->idname = "OBJECT_OT_face_map_select";
+ ot->description = "Select faces belonging to a face map";
+
+ /* api callbacks */
+ ot->poll = face_map_supported_edit_mode_poll;
+ ot->exec = face_map_select_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int face_map_deselect_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
+
+ if (fmap) {
+ fmap_select(ob, false);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Deselect Face Map Faces";
+ ot->idname = "OBJECT_OT_face_map_deselect";
+ ot->description = "Deselect faces belonging to a face map";
+
+ /* api callbacks */
+ ot->poll = face_map_supported_edit_mode_poll;
+ ot->exec = face_map_deselect_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int face_map_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ bFaceMap *fmap;
+ int dir = RNA_enum_get(op->ptr, "direction");
+ int pos1, pos2 = -1, count;
+
+ fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
+ if (!fmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ count = BLI_listbase_count(&ob->fmaps);
+ pos1 = BLI_findindex(&ob->fmaps, fmap);
+
+ if (dir == 1) { /*up*/
+ void *prev = fmap->prev;
+
+ if (prev) {
+ pos2 = pos1 - 1;
+ }
+ else {
+ pos2 = count - 1;
+ }
+
+ BLI_remlink(&ob->fmaps, fmap);
+ BLI_insertlinkbefore(&ob->fmaps, prev, fmap);
+ }
+ else { /*down*/
+ void *next = fmap->next;
+
+ if (next) {
+ pos2 = pos1 + 1;
+ }
+ else {
+ pos2 = 0;
+ }
+
+ BLI_remlink(&ob->fmaps, fmap);
+ BLI_insertlinkafter(&ob->fmaps, next, fmap);
+ }
+
+ /* iterate through mesh and substitute the indices as necessary */
+ object_facemap_swap(ob, pos2, pos1);
+
+ ob->actfmap = pos2 + 1;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void OBJECT_OT_face_map_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem fmap_slot_move[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Face Map";
+ ot->idname = "OBJECT_OT_face_map_move";
+ ot->description = "Move the active face map up/down in the list";
+
+ /* api callbacks */
+ ot->poll = face_map_supported_poll;
+ ot->exec = face_map_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "direction", fmap_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
new file mode 100644
index 00000000000..d67b79375e2
--- /dev/null
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -0,0 +1,647 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2018
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_gpencil_modifier.c
+ * \ingroup edobj
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_report.h"
+#include "BKE_object.h"
+#include "BKE_gpencil.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "object_intern.h"
+
+/******************************** API ****************************/
+
+GpencilModifierData *ED_object_gpencil_modifier_add(
+ ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
+{
+ GpencilModifierData *new_md = NULL;
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+
+ if (ob->type != OB_GPENCIL) {
+ BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
+ return NULL;
+ }
+
+ if (mti->flags & eGpencilModifierTypeFlag_Single) {
+ if (BKE_gpencil_modifiers_findByType(ob, type)) {
+ BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
+ return NULL;
+ }
+ }
+
+ /* get new modifier data to add */
+ new_md = BKE_gpencil_modifier_new(type);
+
+ BLI_addtail(&ob->greasepencil_modifiers, new_md);
+
+ if (name) {
+ BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name));
+ }
+
+ /* make sure modifier data has unique name */
+ BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md);
+
+
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+
+ return new_md;
+}
+
+/* Return true if the object has a modifier of type 'type' other than
+ * the modifier pointed to be 'exclude', otherwise returns false. */
+static bool UNUSED_FUNCTION(gpencil_object_has_modifier)(
+ const Object *ob, const GpencilModifierData *exclude,
+ GpencilModifierType type)
+{
+ GpencilModifierData *md;
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if ((md != exclude) && (md->type == type))
+ return true;
+ }
+
+ return false;
+}
+
+static bool gpencil_object_modifier_remove(
+ Main *bmain, Object *ob, GpencilModifierData *md,
+ bool *UNUSED(r_sort_depsgraph))
+{
+ /* It seems on rapid delete it is possible to
+ * get called twice on same modifier, so make
+ * sure it is in list. */
+ if (BLI_findindex(&ob->greasepencil_modifiers, md) == -1) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+
+ BLI_remlink(&ob->greasepencil_modifiers, md);
+ BKE_gpencil_modifier_free(md);
+ BKE_object_free_derived_caches(ob);
+
+ return 1;
+}
+
+bool ED_object_gpencil_modifier_remove(ReportList *reports, Main *bmain, Object *ob, GpencilModifierData *md)
+{
+ bool sort_depsgraph = false;
+ bool ok;
+
+ ok = gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
+
+ if (!ok) {
+ BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name);
+ return 0;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+
+ return 1;
+}
+
+void ED_object_gpencil_modifier_clear(Main *bmain, Object *ob)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+ bool sort_depsgraph = false;
+
+ if (!md)
+ return;
+
+ while (md) {
+ GpencilModifierData *next_md;
+
+ next_md = md->next;
+
+ gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
+
+ md = next_md;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+}
+
+int ED_object_gpencil_modifier_move_up(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md)
+{
+ if (md->prev) {
+ BLI_remlink(&ob->greasepencil_modifiers, md);
+ BLI_insertlinkbefore(&ob->greasepencil_modifiers, md->prev, md);
+ }
+
+ return 1;
+}
+
+int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md)
+{
+ if (md->next) {
+ BLI_remlink(&ob->greasepencil_modifiers, md);
+ BLI_insertlinkafter(&ob->greasepencil_modifiers, md->next, md);
+ }
+
+ return 1;
+}
+
+static int gpencil_modifier_apply_obdata(
+ ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
+ return 0;
+ }
+
+ if (ob->type == OB_GPENCIL) {
+ if (ELEM(NULL, ob, ob->data)) {
+ return 0;
+ }
+ else if (mti->bakeModifier == NULL) {
+ BKE_report(reports, RPT_ERROR, "Not implemented");
+ return 0;
+ }
+ mti->bakeModifier(bmain, depsgraph, md, ob);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else {
+ BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
+ return 0;
+ }
+
+ return 1;
+}
+
+int ED_object_gpencil_modifier_apply(
+ Main *bmain, ReportList *reports, Depsgraph *depsgraph,
+ Object *ob, GpencilModifierData *md, int UNUSED(mode))
+{
+
+ if (ob->type == OB_GPENCIL) {
+ if (ob->mode != OB_MODE_OBJECT) {
+ BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode");
+ return 0;
+ }
+
+ if (((ID *)ob->data)->us > 1) {
+ BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
+ return 0;
+ }
+ }
+ else if (((ID *)ob->data)->us > 1) {
+ BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
+ return 0;
+ }
+
+ if (md != ob->greasepencil_modifiers.first)
+ BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected");
+
+ if (!gpencil_modifier_apply_obdata(reports, bmain, depsgraph, ob, md)) {
+ return 0;
+ }
+
+ BLI_remlink(&ob->greasepencil_modifiers, md);
+ BKE_gpencil_modifier_free(md);
+
+ return 1;
+}
+
+int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModifierData *md)
+{
+ GpencilModifierData *nmd;
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ GpencilModifierType type = md->type;
+
+ if (mti->flags & eGpencilModifierTypeFlag_Single) {
+ if (BKE_gpencil_modifiers_findByType(ob, type)) {
+ BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
+ return 0;
+ }
+ }
+
+ nmd = BKE_gpencil_modifier_new(md->type);
+ BKE_gpencil_modifier_copyData(md, nmd);
+ BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd);
+ BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd);
+
+ return 1;
+}
+
+/************************ add modifier operator *********************/
+
+static int gpencil_modifier_add_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!ED_object_gpencil_modifier_add(op->reports, bmain, scene, ob, NULL, type))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static const EnumPropertyItem *gpencil_modifier_add_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ Object *ob = ED_object_active_context(C);
+ EnumPropertyItem *item = NULL;
+ const EnumPropertyItem *md_item, *group_item = NULL;
+ const GpencilModifierTypeInfo *mti;
+ int totitem = 0, a;
+
+ if (!ob)
+ return rna_enum_object_greasepencil_modifier_type_items;
+
+ for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) {
+ md_item = &rna_enum_object_greasepencil_modifier_type_items[a];
+ if (md_item->identifier[0]) {
+ mti = BKE_gpencil_modifierType_getInfo(md_item->value);
+
+ if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd)
+ continue;
+ }
+ else {
+ group_item = md_item;
+ md_item = NULL;
+
+ continue;
+ }
+
+ if (group_item) {
+ RNA_enum_item_add(&item, &totitem, group_item);
+ group_item = NULL;
+ }
+
+ RNA_enum_item_add(&item, &totitem, md_item);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Grease Pencil Modifier";
+ ot->description = "Add a procedural operation/effect to the active grease pencil object";
+ ot->idname = "OBJECT_OT_gpencil_modifier_add";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = gpencil_modifier_add_exec;
+ ot->poll = ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "type", rna_enum_object_modifier_type_items, eGpencilModifierType_Thick, "Type", "");
+ RNA_def_enum_funcs(prop, gpencil_modifier_add_itemf);
+ ot->prop = prop;
+}
+
+/************************ generic functions for operators using mod names and data context *********************/
+
+static int gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
+{
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
+ Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
+
+ if (!ptr.data) {
+ CTX_wm_operator_poll_msg_set(C, "Context missing 'modifier'");
+ return 0;
+ }
+
+ if (!ob || ID_IS_LINKED(ob)) return 0;
+ if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0;
+ if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0;
+
+ if (ID_IS_STATIC_OVERRIDE(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from static override");
+ return (((GpencilModifierData *)ptr.data)->flag & eGpencilModifierFlag_StaticOverride_Local) != 0;
+ }
+
+ return 1;
+}
+
+static bool gpencil_edit_modifier_poll(bContext *C)
+{
+ return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0);
+}
+
+static void gpencil_edit_modifier_properties(wmOperatorType *ot)
+{
+ PropertyRNA *prop = RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+static int gpencil_edit_modifier_invoke_properties(bContext *C, wmOperator *op)
+{
+ GpencilModifierData *md;
+
+ if (RNA_struct_property_is_set(op->ptr, "modifier")) {
+ return true;
+ }
+ else {
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier);
+ if (ptr.data) {
+ md = ptr.data;
+ RNA_string_set(op->ptr, "modifier", md->name);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op, Object *ob, int type)
+{
+ char modifier_name[MAX_NAME];
+ GpencilModifierData *md;
+ RNA_string_get(op->ptr, "modifier", modifier_name);
+
+ md = BKE_gpencil_modifiers_findByName(ob, modifier_name);
+
+ if (md && type != 0 && md->type != type)
+ md = NULL;
+
+ return md;
+}
+
+/************************ remove modifier operator *********************/
+
+static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+
+ if (!md || !ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_remove_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_gpencil_modifier_remove(wmOperatorType *ot)
+{
+ ot->name = "Remove Grease Pencil Modifier";
+ ot->description = "Remove a modifier from the active grease pencil object";
+ ot->idname = "OBJECT_OT_gpencil_modifier_remove";
+
+ ot->invoke = gpencil_modifier_remove_invoke;
+ ot->exec = gpencil_modifier_remove_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
+
+/************************ move up modifier operator *********************/
+
+static int gpencil_modifier_move_up_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+
+ if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_move_up_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_gpencil_modifier_move_up(wmOperatorType *ot)
+{
+ ot->name = "Move Up Modifier";
+ ot->description = "Move modifier up in the stack";
+ ot->idname = "OBJECT_OT_gpencil_modifier_move_up";
+
+ ot->invoke = gpencil_modifier_move_up_invoke;
+ ot->exec = gpencil_modifier_move_up_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
+
+/************************ move down modifier operator *********************/
+
+static int gpencil_modifier_move_down_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+
+ if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_move_down_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot)
+{
+ ot->name = "Move Down Modifier";
+ ot->description = "Move modifier down in the stack";
+ ot->idname = "OBJECT_OT_gpencil_modifier_move_down";
+
+ ot->invoke = gpencil_modifier_move_down_invoke;
+ ot->exec = gpencil_modifier_move_down_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
+
+/************************ apply modifier operator *********************/
+
+static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+ int apply_as = RNA_enum_get(op->ptr, "apply_as");
+
+ if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_apply_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+static const EnumPropertyItem gpencil_modifier_apply_as_items[] = {
+ {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"},
+ {MODIFIER_APPLY_SHAPE, "SHAPE", 0, "New Shape", "Apply deform-only modifier to a new shape on this object"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot)
+{
+ ot->name = "Apply Modifier";
+ ot->description = "Apply modifier and remove from the stack";
+ ot->idname = "OBJECT_OT_gpencil_modifier_apply";
+
+ ot->invoke = gpencil_modifier_apply_invoke;
+ ot->exec = gpencil_modifier_apply_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_enum(ot->srna, "apply_as", gpencil_modifier_apply_as_items, MODIFIER_APPLY_DATA, "Apply as", "How to apply the modifier to the geometry");
+ gpencil_edit_modifier_properties(ot);
+}
+
+/************************ copy modifier operator *********************/
+
+static int gpencil_modifier_copy_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
+
+ if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op))
+ return gpencil_modifier_copy_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot)
+{
+ ot->name = "Copy Modifier";
+ ot->description = "Duplicate modifier at the same position in the stack";
+ ot->idname = "OBJECT_OT_gpencil_modifier_copy";
+
+ ot->invoke = gpencil_modifier_copy_invoke;
+ ot->exec = gpencil_modifier_copy_exec;
+ ot->poll = gpencil_edit_modifier_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ gpencil_edit_modifier_properties(ot);
+}
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
deleted file mode 100644
index c764ee22162..00000000000
--- a/source/blender/editors/object/object_group.c
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/object/object_group.c
- * \ingroup edobj
- */
-
-
-#include <string.h>
-
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_group_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_group.h"
-#include "BKE_library.h"
-#include "BKE_library_remap.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_object.h"
-
-#include "ED_screen.h"
-#include "ED_object.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "object_intern.h"
-
-/********************* 3d view operators ***********************/
-
-/* can be called with C == NULL */
-static const EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- Main *bmain = CTX_data_main(C);
- Object *ob;
- EnumPropertyItem *item = NULL, item_tmp = {0};
- int totitem = 0;
-
- if (C == NULL) {
- return DummyRNA_NULL_items;
- }
-
- ob = ED_object_context(C);
-
- /* check that the object exists */
- if (ob) {
- Group *group;
- int i = 0, count = 0;
-
- /* if 2 or more groups, add option to add to all groups */
- group = NULL;
- while ((group = BKE_group_object_find(bmain, group, ob)))
- count++;
-
- if (count >= 2) {
- item_tmp.identifier = item_tmp.name = "All Groups";
- item_tmp.value = INT_MAX; /* this will give NULL on lookup */
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- RNA_enum_item_add_separator(&item, &totitem);
- }
-
- /* add groups */
- group = NULL;
- while ((group = BKE_group_object_find(bmain, group, ob))) {
- item_tmp.identifier = item_tmp.name = group->id.name + 2;
- /* item_tmp.icon = ICON_ARMATURE_DATA; */
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- i++;
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-/* get the group back from the enum index, quite awkward and UI specific */
-static Group *group_object_active_find_index(Main *bmain, Object *ob, const int group_object_index)
-{
- Group *group = NULL;
- int i = 0;
- while ((group = BKE_group_object_find(bmain, group, ob))) {
- if (i == group_object_index) {
- break;
- }
- i++;
- }
-
- return group;
-}
-
-static int objects_add_active_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- int single_group_index = RNA_enum_get(op->ptr, "group");
- Group *single_group = group_object_active_find_index(bmain, ob, single_group_index);
- Group *group;
- bool is_cycle = false;
- bool updated = false;
-
- if (ob == NULL)
- return OPERATOR_CANCELLED;
-
- /* now add all selected objects to the group(s) */
- for (group = bmain->group.first; group; group = group->id.next) {
- if (single_group && group != single_group)
- continue;
- if (!BKE_group_object_exists(group, ob))
- continue;
-
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
- {
- if (BKE_group_object_exists(group, base->object))
- continue;
-
- if (!BKE_group_object_cyclic_check(bmain, base->object, group)) {
- BKE_group_object_add(group, base->object, scene, base);
- updated = true;
- }
- else {
- is_cycle = true;
- }
- }
- CTX_DATA_END;
- }
-
- if (is_cycle)
- BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected");
-
- if (!updated)
- return OPERATOR_CANCELLED;
-
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GROUP_OT_objects_add_active(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Add Selected To Active Group";
- ot->description = "Add the object to an object group that contains the active object";
- ot->idname = "GROUP_OT_objects_add_active";
-
- /* api callbacks */
- ot->exec = objects_add_active_exec;
- ot->invoke = WM_menu_invoke;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to add other selected objects to");
- RNA_def_enum_funcs(prop, group_object_active_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
-}
-
-static int objects_remove_active_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = OBACT;
- int single_group_index = RNA_enum_get(op->ptr, "group");
- Group *single_group = group_object_active_find_index(bmain, ob, single_group_index);
- Group *group;
- bool ok = false;
-
- if (ob == NULL)
- return OPERATOR_CANCELLED;
-
- /* linking to same group requires its own loop so we can avoid
- * looking up the active objects groups each time */
-
- for (group = bmain->group.first; group; group = group->id.next) {
- if (single_group && group != single_group)
- continue;
-
- if (BKE_group_object_exists(group, ob)) {
- /* Remove groups from selected objects */
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
- {
- BKE_group_object_unlink(bmain, group, base->object, scene, base);
- ok = 1;
- }
- CTX_DATA_END;
- }
- }
-
- if (!ok)
- BKE_report(op->reports, RPT_ERROR, "Active object contains no groups");
-
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GROUP_OT_objects_remove_active(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Remove Selected From Active Group";
- ot->description = "Remove the object from an object group that contains the active object";
- ot->idname = "GROUP_OT_objects_remove_active";
-
- /* api callbacks */
- ot->exec = objects_remove_active_exec;
- ot->invoke = WM_menu_invoke;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove other selected objects from");
- RNA_def_enum_funcs(prop, group_object_active_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
-}
-
-static int group_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
-
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
- {
- BKE_object_groups_clear(bmain, scene, base, base->object);
- }
- CTX_DATA_END;
-
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GROUP_OT_objects_remove_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove From All Groups";
- ot->description = "Remove selected objects from all groups";
- ot->idname = "GROUP_OT_objects_remove_all";
-
- /* api callbacks */
- ot->exec = group_objects_remove_all_exec;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int group_objects_remove_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- int single_group_index = RNA_enum_get(op->ptr, "group");
- Group *single_group = group_object_active_find_index(bmain, ob, single_group_index);
- Group *group;
- bool updated = false;
-
- if (ob == NULL)
- return OPERATOR_CANCELLED;
-
- for (group = bmain->group.first; group; group = group->id.next) {
- if (single_group && group != single_group)
- continue;
- if (!BKE_group_object_exists(group, ob))
- continue;
-
- /* now remove all selected objects from the group */
- CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
- {
- BKE_group_object_unlink(bmain, group, base->object, scene, base);
- updated = true;
- }
- CTX_DATA_END;
- }
-
- if (!updated)
- return OPERATOR_CANCELLED;
-
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GROUP_OT_objects_remove(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Remove From Group";
- ot->description = "Remove selected objects from a group";
- ot->idname = "GROUP_OT_objects_remove";
-
- /* api callbacks */
- ot->exec = group_objects_remove_exec;
- ot->invoke = WM_menu_invoke;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "The group to remove this object from");
- RNA_def_enum_funcs(prop, group_object_active_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
-}
-
-static int group_create_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Group *group = NULL;
- char name[MAX_ID_NAME - 2]; /* id name */
-
- RNA_string_get(op->ptr, "name", name);
-
- group = BKE_group_add(bmain, name);
-
- CTX_DATA_BEGIN (C, Base *, base, selected_bases)
- {
- BKE_group_object_add(group, base->object, scene, base);
- }
- CTX_DATA_END;
-
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GROUP_OT_create(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Create New Group";
- ot->description = "Create an object group from selected objects";
- ot->idname = "GROUP_OT_create";
-
- /* api callbacks */
- ot->exec = group_create_exec;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_string(ot->srna, "name", "Group", MAX_ID_NAME - 2, "Name", "Name of the new group");
-}
-
-/****************** properties window operators *********************/
-
-static int group_add_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_context(C);
- Main *bmain = CTX_data_main(C);
- Group *group;
-
- if (ob == NULL)
- return OPERATOR_CANCELLED;
-
- group = BKE_group_add(bmain, "Group");
- BKE_group_object_add(group, ob, scene, NULL);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_group_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add to Group";
- ot->idname = "OBJECT_OT_group_add";
- ot->description = "Add an object to a new group";
-
- /* api callbacks */
- ot->exec = group_add_exec;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int group_link_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_context(C);
- Group *group = BLI_findlink(&bmain->group, RNA_enum_get(op->ptr, "group"));
-
- if (ELEM(NULL, ob, group))
- return OPERATOR_CANCELLED;
-
- /* Early return check, if the object is already in group
- * we could skip all the dependency check and just consider
- * operator is finished.
- */
- if (BKE_group_object_exists(group, ob)) {
- return OPERATOR_FINISHED;
- }
-
- /* Adding object to group which is used as dupligroup for self is bad idea.
- *
- * It is also bad idea to add object to group which is in group which
- * contains our current object.
- */
- if (BKE_group_object_cyclic_check(bmain, ob, group)) {
- BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
- return OPERATOR_CANCELLED;
- }
-
- BKE_group_object_add(group, ob, scene, NULL);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_group_link(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Link to Group";
- ot->idname = "OBJECT_OT_group_link";
- ot->description = "Add an object to an existing group";
-
- /* api callbacks */
- ot->exec = group_link_exec;
- ot->invoke = WM_enum_search_invoke;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_enum(ot->srna, "group", DummyRNA_NULL_items, 0, "Group", "");
- RNA_def_enum_funcs(prop, RNA_group_local_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
-}
-
-static int group_remove_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_context(C);
- Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
-
- if (!ob || !group)
- return OPERATOR_CANCELLED;
-
- BKE_group_object_unlink(bmain, group, ob, scene, NULL); /* base will be used if found */
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_group_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Group";
- ot->idname = "OBJECT_OT_group_remove";
- ot->description = "Remove the active object from this group";
-
- /* api callbacks */
- ot->exec = group_remove_exec;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
-
- if (!group)
- return OPERATOR_CANCELLED;
-
- BKE_libblock_delete(bmain, group);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_group_unlink(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Unlink Group";
- ot->idname = "OBJECT_OT_group_unlink";
- ot->description = "Unlink the group from all objects";
-
- /* api callbacks */
- ot->exec = group_unlink_exec;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same group as the active */
-{
- Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
-
- if (!group)
- return OPERATOR_CANCELLED;
-
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) {
- ED_base_object_select(base, BA_SELECT);
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_grouped_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Grouped";
- ot->idname = "OBJECT_OT_grouped_select";
- ot->description = "Select all objects in group";
-
- /* api callbacks */
- ot->exec = select_grouped_exec;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index bfc24d4f325..ff9cc65180b 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -48,7 +48,7 @@
#include "BKE_action.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -57,6 +57,9 @@
#include "BKE_deform.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_define.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -318,7 +321,7 @@ static bool object_hook_index_array(Main *bmain, Scene *scene, Object *obedit,
EDBM_mesh_load(bmain, obedit);
EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
em = me->edit_btmesh;
@@ -445,26 +448,24 @@ static bool hook_op_edit_poll(bContext *C)
return 0;
}
-static Object *add_hook_object_new(Main *bmain, Scene *scene, Object *obedit)
+static Object *add_hook_object_new(Main *bmain, Scene *scene, ViewLayer *view_layer, Object *obedit)
{
- Base *base, *basedit;
+ Base *basedit;
Object *ob;
- ob = BKE_object_add(bmain, scene, OB_EMPTY, NULL);
+ ob = BKE_object_add(bmain, scene, view_layer, OB_EMPTY, NULL);
- basedit = BKE_scene_base_find(scene, obedit);
- base = scene->basact;
- base->lay = ob->lay = obedit->lay;
- BLI_assert(scene->basact->object == ob);
+ basedit = BKE_view_layer_base_find(view_layer, obedit);
+ BLI_assert(view_layer->basact->object == ob);
/* icky, BKE_object_add sets new base as active.
* so set it back to the original edit object */
- scene->basact = basedit;
+ view_layer->basact = basedit;
return ob;
}
-static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob, int mode, ReportList *reports)
+static int add_hook_object(const bContext *C, Main *bmain, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *ob, int mode, ReportList *reports)
{
ModifierData *md = NULL;
HookModifierData *hmd = NULL;
@@ -482,7 +483,7 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
if (mode == OBJECT_ADDHOOK_NEWOB && !ob) {
- ob = add_hook_object_new(bmain, scene, obedit);
+ ob = add_hook_object_new(bmain, scene, view_layer, obedit);
/* transform cent to global coords for loc */
mul_v3_m4v3(ob->loc, obedit->obmat, cent);
@@ -541,13 +542,13 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
/* matrix calculus */
/* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
/* (parentinv ) */
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(CTX_data_depsgraph(C), scene, ob);
invert_m4_m4(ob->imat, ob->obmat);
/* apparently this call goes from right to left... */
mul_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
return true;
}
@@ -556,6 +557,7 @@ static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
Object *obsel = NULL;
const bool use_bone = RNA_boolean_get(op->ptr, "use_bone");
@@ -580,7 +582,7 @@ static int object_add_hook_selob_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (add_hook_object(bmain, scene, obedit, obsel, mode, op->reports)) {
+ if (add_hook_object(C, bmain, scene, view_layer, obedit, obsel, mode, op->reports)) {
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
return OPERATOR_FINISHED;
}
@@ -611,9 +613,11 @@ static int object_add_hook_newob_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
- if (add_hook_object(bmain, scene, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) {
+ if (add_hook_object(C, bmain, scene, view_layer, obedit, NULL, OBJECT_ADDHOOK_NEWOB, op->reports)) {
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obedit);
return OPERATOR_FINISHED;
@@ -655,7 +659,7 @@ static int object_hook_remove_exec(bContext *C, wmOperator *op)
BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
modifier_free((ModifierData *)hmd);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -729,7 +733,7 @@ static int object_hook_reset_exec(bContext *C, wmOperator *op)
BKE_object_modifier_hook_reset(ob, hmd);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -776,10 +780,10 @@ static int object_hook_recenter_exec(bContext *C, wmOperator *op)
copy_m3_m4(bmat, ob->obmat);
invert_m3_m3(imat, bmat);
- sub_v3_v3v3(hmd->cent, scene->cursor, ob->obmat[3]);
+ sub_v3_v3v3(hmd->cent, scene->cursor.location, ob->obmat[3]);
mul_m3_v3(imat, hmd->cent);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -838,7 +842,7 @@ static int object_hook_assign_exec(bContext *C, wmOperator *op)
hmd->indexar = indexar;
hmd->totindex = tot;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -884,6 +888,7 @@ static int object_hook_select_exec(bContext *C, wmOperator *op)
/* select functionality */
object_hook_select(ob, hmd);
+ DEG_id_tag_update(ob->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index f962f83844b..c750a3fb2bd 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -55,6 +55,7 @@ void OBJECT_OT_scale_clear(struct wmOperatorType *ot);
void OBJECT_OT_origin_clear(struct wmOperatorType *ot);
void OBJECT_OT_visual_transform_apply(struct wmOperatorType *ot);
void OBJECT_OT_transform_apply(struct wmOperatorType *ot);
+void OBJECT_OT_transform_axis_target(struct wmOperatorType *ot);
void OBJECT_OT_origin_set(struct wmOperatorType *ot);
/* object_relations.c */
@@ -67,36 +68,32 @@ void OBJECT_OT_track_clear(struct wmOperatorType *ot);
void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot);
void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot);
void OBJECT_OT_make_local(struct wmOperatorType *ot);
+void OBJECT_OT_make_override_static(struct wmOperatorType *ot);
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
-void OBJECT_OT_move_to_layer(struct wmOperatorType *ot);
void OBJECT_OT_drop_named_material(struct wmOperatorType *ot);
void OBJECT_OT_unlink_data(struct wmOperatorType *ot);
/* object_edit.c */
+void OBJECT_OT_hide_view_set(struct wmOperatorType *ot);
+void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot);
+void OBJECT_OT_hide_collection(struct wmOperatorType *ot);
void OBJECT_OT_mode_set(struct wmOperatorType *ot);
+void OBJECT_OT_mode_set_or_submode(struct wmOperatorType *ot);
void OBJECT_OT_editmode_toggle(struct wmOperatorType *ot);
void OBJECT_OT_posemode_toggle(struct wmOperatorType *ot);
-void OBJECT_OT_hide_view_set(struct wmOperatorType *ot);
-void OBJECT_OT_hide_view_clear(struct wmOperatorType *ot);
-void OBJECT_OT_hide_render_set(struct wmOperatorType *ot);
-void OBJECT_OT_hide_render_clear(struct wmOperatorType *ot);
void OBJECT_OT_proxy_make(struct wmOperatorType *ot);
void OBJECT_OT_shade_smooth(struct wmOperatorType *ot);
void OBJECT_OT_shade_flat(struct wmOperatorType *ot);
void OBJECT_OT_paths_calculate(struct wmOperatorType *ot);
void OBJECT_OT_paths_update(struct wmOperatorType *ot);
void OBJECT_OT_paths_clear(struct wmOperatorType *ot);
+void OBJECT_OT_paths_range_update(struct wmOperatorType *ot);
void OBJECT_OT_forcefield_toggle(struct wmOperatorType *ot);
-void OBJECT_OT_game_property_new(struct wmOperatorType *ot);
-void OBJECT_OT_game_property_remove(struct wmOperatorType *ot);
-void OBJECT_OT_game_property_copy(struct wmOperatorType *ot);
-void OBJECT_OT_game_property_clear(struct wmOperatorType *ot);
-void OBJECT_OT_game_property_move(struct wmOperatorType *ot);
-void OBJECT_OT_logic_bricks_copy(struct wmOperatorType *ot);
-void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot);
+void OBJECT_OT_move_to_collection(struct wmOperatorType *ot);
+void OBJECT_OT_link_to_collection(struct wmOperatorType *ot);
/* object_select.c */
void OBJECT_OT_select_all(struct wmOperatorType *ot);
@@ -108,7 +105,7 @@ void OBJECT_OT_select_grouped(struct wmOperatorType *ot);
void OBJECT_OT_select_mirror(struct wmOperatorType *ot);
void OBJECT_OT_select_more(struct wmOperatorType *ot);
void OBJECT_OT_select_less(struct wmOperatorType *ot);
-void OBJECT_OT_select_same_group(struct wmOperatorType *ot);
+void OBJECT_OT_select_same_collection(struct wmOperatorType *ot);
/* object_add.c */
void OBJECT_OT_add(struct wmOperatorType *ot);
@@ -117,12 +114,14 @@ void OBJECT_OT_metaball_add(struct wmOperatorType *ot);
void OBJECT_OT_text_add(struct wmOperatorType *ot);
void OBJECT_OT_armature_add(struct wmOperatorType *ot);
void OBJECT_OT_empty_add(struct wmOperatorType *ot);
+void OBJECT_OT_lightprobe_add(struct wmOperatorType *ot);
void OBJECT_OT_drop_named_image(struct wmOperatorType *ot);
-void OBJECT_OT_lamp_add(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_add(struct wmOperatorType *ot);
+void OBJECT_OT_light_add(struct wmOperatorType *ot);
void OBJECT_OT_effector_add(struct wmOperatorType *ot);
void OBJECT_OT_camera_add(struct wmOperatorType *ot);
void OBJECT_OT_speaker_add(struct wmOperatorType *ot);
-void OBJECT_OT_group_instance_add(struct wmOperatorType *ot);
+void OBJECT_OT_collection_instance_add(struct wmOperatorType *ot);
void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot);
void OBJECT_OT_duplicate(struct wmOperatorType *ot);
@@ -141,11 +140,11 @@ void OBJECT_OT_hook_reset(struct wmOperatorType *ot);
void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
/* object_group.c */
-void GROUP_OT_create(struct wmOperatorType *ot);
-void GROUP_OT_objects_remove_all(struct wmOperatorType *ot);
-void GROUP_OT_objects_remove(struct wmOperatorType *ot);
-void GROUP_OT_objects_add_active(struct wmOperatorType *ot);
-void GROUP_OT_objects_remove_active(struct wmOperatorType *ot);
+void COLLECTION_OT_create(struct wmOperatorType *ot);
+void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot);
+void COLLECTION_OT_objects_remove(struct wmOperatorType *ot);
+void COLLECTION_OT_objects_add_active(struct wmOperatorType *ot);
+void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot);
/* object_modifier.c */
bool edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag);
@@ -178,6 +177,20 @@ void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot);
+/* grease pencil modifiers */
+void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_remove(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_move_up(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_move_down(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot);
+void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot);
+
+/* shader fx */
+void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot);
+void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot);
+void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot);
+void OBJECT_OT_shaderfx_move_down(struct wmOperatorType *ot);
+
/* object_constraint.c */
void OBJECT_OT_constraint_add(struct wmOperatorType *ot);
void OBJECT_OT_constraint_add_with_targets(struct wmOperatorType *ot);
@@ -237,6 +250,15 @@ void OBJECT_OT_vertex_weight_set_active(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_normalize_active_vertex(struct wmOperatorType *ot);
void OBJECT_OT_vertex_weight_copy(struct wmOperatorType *ot);
+/* object_facemap_ops.c */
+void OBJECT_OT_face_map_add(struct wmOperatorType *ot);
+void OBJECT_OT_face_map_remove(struct wmOperatorType *ot);
+void OBJECT_OT_face_map_assign(struct wmOperatorType *ot);
+void OBJECT_OT_face_map_remove_from(struct wmOperatorType *ot);
+void OBJECT_OT_face_map_select(struct wmOperatorType *ot);
+void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot);
+void OBJECT_OT_face_map_move(struct wmOperatorType *ot);
+
/* object_warp.c */
void TRANSFORM_OT_vertex_warp(struct wmOperatorType *ot);
@@ -249,20 +271,16 @@ void OBJECT_OT_shape_key_mirror(struct wmOperatorType *ot);
void OBJECT_OT_shape_key_move(struct wmOperatorType *ot);
/* object_group.c */
-void OBJECT_OT_group_add(struct wmOperatorType *ot);
-void OBJECT_OT_group_link(struct wmOperatorType *ot);
-void OBJECT_OT_group_remove(struct wmOperatorType *ot);
-void OBJECT_OT_group_unlink(struct wmOperatorType *ot);
-void OBJECT_OT_grouped_select(struct wmOperatorType *ot);
+void OBJECT_OT_collection_add(struct wmOperatorType *ot);
+void OBJECT_OT_collection_link(struct wmOperatorType *ot);
+void OBJECT_OT_collection_remove(struct wmOperatorType *ot);
+void OBJECT_OT_collection_unlink(struct wmOperatorType *ot);
+void OBJECT_OT_collection_objects_select(struct wmOperatorType *ot);
/* object_bake.c */
void OBJECT_OT_bake_image(wmOperatorType *ot);
void OBJECT_OT_bake(wmOperatorType *ot);
-/* object_lod.c */
-void OBJECT_OT_lod_add(struct wmOperatorType *ot);
-void OBJECT_OT_lod_remove(struct wmOperatorType *ot);
-
/* object_random.c */
void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_lod.c b/source/blender/editors/object/object_lod.c
deleted file mode 100644
index ced306178b8..00000000000
--- a/source/blender/editors/object/object_lod.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/object/object_lod.c
- * \ingroup edobj
- */
-
-#include "DNA_object_types.h"
-
-#include "BKE_context.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "ED_screen.h"
-#include "ED_object.h"
-
-#ifdef WITH_GAMEENGINE
-# include "BKE_object.h"
-
-# include "RNA_enum_types.h"
-#endif
-
-#include "object_intern.h"
-
-static int object_lod_add_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_object_context(C);
-
-#ifdef WITH_GAMEENGINE
- BKE_object_lod_add(ob);
-#else
- (void)ob;
-#endif
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_lod_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Level of Detail";
- ot->description = "Add a level of detail to this object";
- ot->idname = "OBJECT_OT_lod_add";
-
- /* api callbacks */
- ot->exec = object_lod_add_exec;
- ot->poll = ED_operator_object_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int object_lod_remove_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- int index = RNA_int_get(op->ptr, "index");
-
-#ifdef WITH_GAMEENGINE
- if (!BKE_object_lod_remove(ob, index))
- return OPERATOR_CANCELLED;
-#else
- (void)ob;
- (void)index;
-#endif
-
- WM_event_add_notifier(C, NC_OBJECT | ND_LOD, CTX_wm_view3d(C));
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_lod_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Level of Detail";
- ot->description = "Remove a level of detail from this object";
- ot->idname = "OBJECT_OT_lod_remove";
-
- /* api callbacks */
- ot->exec = object_lod_remove_exec;
- ot->poll = ED_operator_object_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_int(ot->srna, "index", 1, 1, INT_MAX, "Index", "", 1, INT_MAX);
-}
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index d70a69e30f8..10c7fcfeba1 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -27,18 +27,36 @@
* actual mode switching logic is per-object type.
*/
+#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_object.h"
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+
+#include "ED_object.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name High Level Mode Operations
+ *
+ * \{ */
static const char *object_mode_op_string(eObjectMode mode)
{
@@ -56,8 +74,14 @@ static const char *object_mode_op_string(eObjectMode mode)
return "PARTICLE_OT_particle_edit_toggle";
if (mode == OB_MODE_POSE)
return "OBJECT_OT_posemode_toggle";
- if (mode == OB_MODE_GPENCIL)
+ if (mode == OB_MODE_GPENCIL_EDIT)
return "GPENCIL_OT_editmode_toggle";
+ if (mode == OB_MODE_GPENCIL_PAINT)
+ return "GPENCIL_OT_paintmode_toggle";
+ if (mode == OB_MODE_GPENCIL_SCULPT)
+ return "GPENCIL_OT_sculptmode_toggle";
+ if (mode == OB_MODE_GPENCIL_WEIGHT)
+ return "GPENCIL_OT_weightmode_toggle";
return NULL;
}
@@ -70,8 +94,6 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
if (ob) {
if (mode == OB_MODE_OBJECT)
return true;
- else if (mode == OB_MODE_GPENCIL)
- return true; /* XXX: assume this is the case for now... */
switch (ob->type) {
case OB_MESH:
@@ -96,13 +118,19 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
if (mode & (OB_MODE_EDIT | OB_MODE_POSE))
return true;
break;
+ case OB_GPENCIL:
+ if (mode & (OB_MODE_EDIT | OB_MODE_GPENCIL_EDIT | OB_MODE_GPENCIL_PAINT |
+ OB_MODE_GPENCIL_SCULPT | OB_MODE_GPENCIL_WEIGHT))
+ {
+ return true;
+ }
+ break;
}
}
return false;
}
-
/**
* Sets the mode to a compatible state (use before entering the mode).
*
@@ -113,6 +141,7 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, Report
bool ok;
if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) {
const char *opstring = object_mode_op_string(ob->mode);
+
WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
ok = ELEM(ob->mode, mode, OB_MODE_OBJECT);
if (!ok) {
@@ -131,48 +160,151 @@ void ED_object_mode_toggle(bContext *C, eObjectMode mode)
{
if (mode != OB_MODE_OBJECT) {
const char *opstring = object_mode_op_string(mode);
+
if (opstring) {
- WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
+ if (ot->flag & OPTYPE_USE_EVAL_DATA) {
+ /* We need to force refresh of depsgraph after undo step,
+ * redoing the operator *may* rely on some valid evaluated data. */
+ struct Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BKE_scene_view_layer_graph_evaluated_ensure(bmain, scene, view_layer);
+ }
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL);
}
}
}
+
/* Wrapper for operator */
void ED_object_mode_set(bContext *C, eObjectMode mode)
{
-#if 0
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm->op_undo_depth++;
+ /* needed so we don't do undo pushes. */
+ ED_object_mode_generic_enter(C, mode);
+ wm->op_undo_depth--;
+}
+
+void ED_object_mode_exit(bContext *C)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ struct Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FOREACH_OBJECT_BEGIN(view_layer, ob)
+ {
+ if (ob->mode & OB_MODE_ALL_MODE_DATA) {
+ ED_object_mode_generic_exit(bmain, depsgraph, scene, ob);
+ }
+ }
+ FOREACH_OBJECT_END;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Mode Enter/Exit
+ *
+ * Supports exiting a mode without it being in the current context.
+ * This could be done for entering modes too if it's needed.
+ *
+ * \{ */
+
+bool ED_object_mode_generic_enter(
+ struct bContext *C, eObjectMode object_mode)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return (object_mode == OB_MODE_OBJECT);
+ }
+ if (ob->mode == object_mode) {
+ return true;
+ }
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
PointerRNA ptr;
-
WM_operator_properties_create_ptr(&ptr, ot);
- RNA_enum_set(&ptr, "mode", mode);
- RNA_boolean_set(&ptr, "toggle", false);
- WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &ptr);
+ RNA_enum_set(&ptr, "mode", object_mode);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
WM_operator_properties_free(&ptr);
-#else
- Object *ob = CTX_data_active_object(C);
- if (ob == NULL) {
- return;
+ return (ob->mode == object_mode);
+}
+
+/**
+ * Use for changing works-paces or changing active object.
+ * Caller can check #OB_MODE_ALL_MODE_DATA to test if this needs to be run.
+ */
+static bool ed_object_mode_generic_exit_ex(
+ struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *ob,
+ bool only_test)
+{
+ BLI_assert((bmain == NULL) == only_test);
+ if (ob->mode & OB_MODE_EDIT) {
+ if (BKE_object_is_in_editmode(ob)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
+ }
}
- if (ob->mode == mode) {
- /* pass */
+ else if (ob->mode & OB_MODE_VERTEX_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_vpaintmode_exit_ex(ob);
+ }
+ }
+ else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_wpaintmode_exit_ex(ob);
+ }
}
- else if (mode != OB_MODE_OBJECT) {
- if (ob && (ob->mode & mode) == 0) {
- /* needed so we don't do undo pushes. */
- wmWindowManager *wm = CTX_wm_manager(C);
- wm->op_undo_depth++;
- ED_object_mode_toggle(C, mode);
- wm->op_undo_depth--;
+ else if (ob->mode & OB_MODE_SCULPT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
+ }
+ }
+ else if (ob->mode & OB_MODE_POSE) {
+ if (ob->pose != NULL) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_posemode_exit_ex(bmain, ob);
}
}
else {
- /* needed so we don't do undo pushes. */
- wmWindowManager *wm = CTX_wm_manager(C);
- wm->op_undo_depth++;
- ED_object_mode_toggle(C, ob->mode);
- wm->op_undo_depth--;
-
+ if (only_test) {
+ return false;
+ }
+ BLI_assert((ob->mode & OB_MODE_ALL_MODE_DATA) == 0);
}
-#endif
+
+ return false;
}
+
+void ED_object_mode_generic_exit(
+ struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *ob)
+{
+ ed_object_mode_generic_exit_ex(bmain, depsgraph, scene, ob, false);
+}
+
+bool ED_object_mode_generic_has_data(
+ struct Depsgraph *depsgraph,
+ struct Object *ob)
+{
+ return ed_object_mode_generic_exit_ex(NULL, depsgraph, NULL, ob, true);
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 5f3a6d0ac94..7923e300377 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -54,26 +54,32 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_displist.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_editmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
-#include "BKE_report.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_ocean.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_softbody.h"
-#include "BKE_editmesh.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -93,6 +99,23 @@ static void modifier_skin_customdata_delete(struct Object *ob);
/******************************** API ****************************/
+static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me_eval = mesh_create_eval_final_view(depsgraph, scene, ob, 0);
+ BKE_id_free(NULL, me_eval);
+ }
+ else if (ob->type == OB_LATTICE) {
+ BKE_lattice_modifiers_calc(depsgraph, scene, ob);
+ }
+ else if (ob->type == OB_MBALL) {
+ BKE_displist_make_mball(depsgraph, scene, ob);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ BKE_displist_make_curveTypes(depsgraph, scene, ob, false, false);
+ }
+}
+
ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
ModifierData *md = NULL, *new_md = NULL;
@@ -171,8 +194,8 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
}
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
return new_md;
}
@@ -180,7 +203,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
/* Return true if the object has a modifier of type 'type' other than
* the modifier pointed to be 'exclude', otherwise returns false. */
static bool object_has_modifier(const Object *ob, const ModifierData *exclude,
- ModifierType type)
+ ModifierType type)
{
ModifierData *md;
@@ -200,9 +223,10 @@ static bool object_has_modifier(const Object *ob, const ModifierData *exclude,
* If the callback ever returns true, iteration will stop and the
* function value will be true. Otherwise the function returns false.
*/
-bool ED_object_iter_other(Main *bmain, Object *orig_ob, const bool include_orig,
- bool (*callback)(Object *ob, void *callback_data),
- void *callback_data)
+bool ED_object_iter_other(
+ Main *bmain, Object *orig_ob, const bool include_orig,
+ bool (*callback)(Object *ob, void *callback_data),
+ void *callback_data)
{
ID *ob_data_id = orig_ob->data;
int users = ob_data_id->us;
@@ -243,8 +267,8 @@ static bool object_has_modifier_cb(Object *ob, void *data)
}
/* Use with ED_object_iter_other(). Sets the total number of levels
- * for any multires modifiers on the object to the int pointed to by
- * callback_data. */
+* for any multires modifiers on the object to the int pointed to by
+* callback_data. */
bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
{
ModifierData *md;
@@ -253,7 +277,7 @@ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Multires) {
multires_set_tot_level(ob, (MultiresModifierData *)md, totlevel);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
return false;
@@ -261,16 +285,16 @@ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v)
/* Return true if no modifier of type 'type' other than 'exclude' */
static bool object_modifier_safe_to_delete(Main *bmain, Object *ob,
- ModifierData *exclude,
- ModifierType type)
+ ModifierData *exclude,
+ ModifierType type)
{
return (!object_has_modifier(ob, exclude, type) &&
- !ED_object_iter_other(bmain, ob, false,
- object_has_modifier_cb, &type));
+ !ED_object_iter_other(bmain, ob, false,
+ object_has_modifier_cb, &type));
}
static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
- bool *r_sort_depsgraph)
+ bool *r_sort_depsgraph)
{
/* It seems on rapid delete it is possible to
* get called twice on same modifier, so make
@@ -289,9 +313,8 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
}
else if (md->type == eModifierType_Softbody) {
if (ob->soft) {
- sbFree(ob->soft);
- ob->soft = NULL;
- ob->softflag = 0;
+ sbFree(ob);
+ ob->softflag = 0; /* TODO(Sybren): this should probably be moved into sbFree() */
}
}
else if (md->type == eModifierType_Collision) {
@@ -320,8 +343,6 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
}
- DAG_relations_tag_update(bmain);
-
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
BKE_object_free_derived_caches(ob);
@@ -341,8 +362,8 @@ bool ED_object_modifier_remove(ReportList *reports, Main *bmain, Object *ob, Mod
return 0;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
return 1;
}
@@ -365,8 +386,8 @@ void ED_object_modifier_clear(Main *bmain, Object *ob)
md = next_md;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
}
int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md)
@@ -411,7 +432,7 @@ int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *
return 1;
}
-int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *scene, Object *ob, ModifierData *md)
+int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *scene, ViewLayer *view_layer, Object *ob, ModifierData *md)
{
Object *obn;
ParticleSystem *psys;
@@ -463,7 +484,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
if (totvert == 0) return 0;
/* add new mesh */
- obn = BKE_object_add(bmain, scene, OB_MESH, NULL);
+ obn = BKE_object_add(bmain, scene, view_layer, OB_MESH, NULL);
me = obn->data;
me->totvert = totvert;
@@ -515,18 +536,17 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
}
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
return 1;
}
-static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
+static int modifier_apply_shape(
+ Main *bmain, ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
- if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
return 0;
}
@@ -543,7 +563,7 @@ static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene,
*/
if (ob->type == OB_MESH) {
- DerivedMesh *dm;
+ Mesh *mesh_applied;
Mesh *me = ob->data;
Key *key = me->key;
KeyBlock *kb;
@@ -553,8 +573,8 @@ static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene,
return 0;
}
- dm = mesh_create_derived_for_modifier(scene, ob, md, 0);
- if (!dm) {
+ mesh_applied = BKE_mesh_create_derived_for_modifier(depsgraph, scene, ob, md, 0);
+ if (!mesh_applied) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
return 0;
}
@@ -565,13 +585,13 @@ static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene,
/* if that was the first key block added, then it was the basis.
* Initialize it with the mesh, and add another for the modifier */
kb = BKE_keyblock_add(key, NULL);
- BKE_keyblock_convert_from_mesh(me, kb);
+ BKE_keyblock_convert_from_mesh(me, key, kb);
}
kb = BKE_keyblock_add(key, md->name);
- DM_to_meshkey(dm, me, kb);
+ BKE_mesh_nomain_to_meshkey(mesh_applied, me, kb);
- dm->release(dm);
+ BKE_id_free(NULL, mesh_applied);
}
else {
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
@@ -580,19 +600,17 @@ static int modifier_apply_shape(Main *bmain, ReportList *reports, Scene *scene,
return 1;
}
-static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
+static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
- if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
return 0;
}
if (ob->type == OB_MESH) {
- DerivedMesh *dm;
+ Mesh *mesh_applied;
Mesh *me = ob->data;
MultiresModifierData *mmd = find_multires_modifier_before(scene, md);
@@ -606,19 +624,19 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob,
multires_force_update(ob);
if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) {
- if (!multiresModifier_reshapeFromDeformMod(scene, mmd, ob, md)) {
+ if (!multiresModifier_reshapeFromDeformModifier(depsgraph, mmd, ob, md)) {
BKE_report(reports, RPT_ERROR, "Multires modifier returned error, skipping apply");
return 0;
}
}
else {
- dm = mesh_create_derived_for_modifier(scene, ob, md, 1);
- if (!dm) {
+ mesh_applied = BKE_mesh_create_derived_for_modifier(depsgraph, scene, ob, md, 1);
+ if (!mesh_applied) {
BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply");
return 0;
}
- DM_to_mesh(dm, me, ob, CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, CD_MASK_MESH, true);
if (md->type == eModifierType_Multires)
multires_customdata_delete(me);
@@ -628,9 +646,10 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob,
Curve *cu;
int numVerts;
float (*vertexCos)[3];
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
if (ELEM(mti->type, eModifierTypeType_Constructive, eModifierTypeType_Nonconstructive)) {
- BKE_report(reports, RPT_ERROR, "Cannot apply constructive modifiers on curve");
+ BKE_report(reports, RPT_ERROR, "Transform curve to mesh in order to apply constructive modifiers");
return 0;
}
@@ -638,12 +657,12 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob,
BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tessellated/bevel vertices");
vertexCos = BKE_curve_nurbs_vertexCos_get(&cu->nurb, &numVerts);
- mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0);
+ mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts);
BK_curve_nurbs_vertexCos_apply(&cu->nurb, vertexCos);
MEM_freeN(vertexCos);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else {
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
@@ -660,18 +679,20 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob,
if (psys->part->type != PART_HAIR)
continue;
- psys_apply_hair_lattice(scene, ob, psys);
+ psys_apply_hair_lattice(depsgraph, scene, ob, psys);
}
}
return 1;
}
-int ED_object_modifier_apply(Main *bmain, ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode)
+int ED_object_modifier_apply(
+ Main *bmain, ReportList *reports, Depsgraph *depsgraph,
+ Scene *scene, Object *ob, ModifierData *md, int mode)
{
int prev_mode;
- if (scene->obedit) {
+ if (BKE_object_is_in_editmode(ob)) {
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode");
return 0;
}
@@ -690,23 +711,29 @@ int ED_object_modifier_apply(Main *bmain, ReportList *reports, Scene *scene, Obj
if (md != ob->modifiers.first)
BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected");
+ /* Get evaluated modifier, so object links pointer to evaluated data,
+ * but still use original object it is applied to the original mesh. */
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ ModifierData *md_eval = (ob_eval) ? modifiers_findByName(ob_eval, md->name) : md;
+
/* allow apply of a not-realtime modifier, by first re-enabling realtime. */
- prev_mode = md->mode;
- md->mode |= eModifierMode_Realtime;
+ prev_mode = md_eval->mode;
+ md_eval->mode |= eModifierMode_Realtime;
if (mode == MODIFIER_APPLY_SHAPE) {
- if (!modifier_apply_shape(bmain, reports, scene, ob, md)) {
- md->mode = prev_mode;
+ if (!modifier_apply_shape(bmain, reports, depsgraph, scene, ob, md_eval)) {
+ md_eval->mode = prev_mode;
return 0;
}
}
else {
- if (!modifier_apply_obdata(reports, scene, ob, md)) {
- md->mode = prev_mode;
+ if (!modifier_apply_obdata(reports, depsgraph, scene, ob, md_eval)) {
+ md_eval->mode = prev_mode;
return 0;
}
}
+ md_eval->mode = prev_mode;
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
@@ -745,7 +772,7 @@ static int modifier_add_exec(bContext *C, wmOperator *op)
}
static const EnumPropertyItem *modifier_add_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
Object *ob = ED_object_active_context(C);
EnumPropertyItem *item = NULL;
@@ -823,6 +850,11 @@ bool edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_fla
if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0;
if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0;
+ if (ID_IS_STATIC_OVERRIDE(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from static override");
+ return (((ModifierData *)ptr.data)->flag & eModifierFlag_StaticOverride_Local) != 0;
+ }
+
return 1;
}
@@ -833,7 +865,8 @@ bool edit_modifier_poll(bContext *C)
void edit_modifier_properties(wmOperatorType *ot)
{
- RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit");
+ PropertyRNA *prop = RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
int edit_modifier_invoke_properties(bContext *C, wmOperator *op)
@@ -874,7 +907,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type)
static int modifier_remove_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
int mode_orig = ob->mode;
@@ -885,11 +918,13 @@ static int modifier_remove_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
/* if cloth/softbody was removed, particle mode could be cleared */
- if (mode_orig & OB_MODE_PARTICLE_EDIT)
- if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0)
- if (scene->basact && scene->basact->object == ob)
+ if (mode_orig & OB_MODE_PARTICLE_EDIT) {
+ if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) {
+ if (ob == OBACT(view_layer)) {
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
-
+ }
+ }
+ }
return OPERATOR_FINISHED;
}
@@ -926,7 +961,7 @@ static int modifier_move_up_exec(bContext *C, wmOperator *op)
if (!md || !ED_object_modifier_move_up(op->reports, ob, md))
return OPERATOR_CANCELLED;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -965,7 +1000,7 @@ static int modifier_move_down_exec(bContext *C, wmOperator *op)
if (!md || !ED_object_modifier_move_down(op->reports, ob, md))
return OPERATOR_CANCELLED;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -999,16 +1034,17 @@ void OBJECT_OT_modifier_move_down(wmOperatorType *ot)
static int modifier_apply_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
int apply_as = RNA_enum_get(op->ptr, "apply_as");
- if (!md || !ED_object_modifier_apply(bmain, op->reports, scene, ob, md, apply_as)) {
+ if (!md || !ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) {
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1051,13 +1087,14 @@ static int modifier_convert_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
- if (!md || !ED_object_modifier_convert(op->reports, bmain, scene, ob, md))
+ if (!md || !ED_object_modifier_convert(op->reports, bmain, scene, view_layer, ob, md))
return OPERATOR_CANCELLED;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1096,7 +1133,7 @@ static int modifier_copy_exec(bContext *C, wmOperator *op)
if (!md || !ED_object_modifier_copy(op->reports, ob, md))
return OPERATOR_CANCELLED;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1134,17 +1171,18 @@ static bool multires_poll(bContext *C)
static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires);
if (!mmd)
return OPERATOR_CANCELLED;
- multiresModifier_del_levels(mmd, ob, 1);
+ multiresModifier_del_levels(mmd, scene, ob, 1);
ED_object_iter_other(CTX_data_main(C), ob, true,
- ED_object_multires_update_totlevels_cb,
- &mmd->totlvl);
+ ED_object_multires_update_totlevels_cb,
+ &mmd->totlvl);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
@@ -1178,19 +1216,20 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot)
static int multires_subdivide_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires);
if (!mmd)
return OPERATOR_CANCELLED;
- multiresModifier_subdivide(mmd, ob, 0, mmd->simple);
+ multiresModifier_subdivide(mmd, scene, ob, 0, mmd->simple);
ED_object_iter_other(CTX_data_main(C), ob, true,
- ED_object_multires_update_totlevels_cb,
- &mmd->totlvl);
+ ED_object_multires_update_totlevels_cb,
+ &mmd->totlvl);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
if (ob->mode & OB_MODE_SCULPT) {
@@ -1228,8 +1267,8 @@ void OBJECT_OT_multires_subdivide(wmOperatorType *ot)
static int multires_reshape_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *ob = ED_object_active_context(C), *secondob = NULL;
- Scene *scene = CTX_data_scene(C);
MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires);
if (!mmd)
@@ -1254,12 +1293,12 @@ static int multires_reshape_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (!multiresModifier_reshape(scene, mmd, ob, secondob)) {
+ if (!multiresModifier_reshapeFromObject(depsgraph, mmd, ob, secondob)) {
BKE_report(op->reports, RPT_ERROR, "Objects do not have the same number of vertices");
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1363,8 +1402,8 @@ void OBJECT_OT_multires_external_save(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
edit_modifier_properties(ot);
}
@@ -1400,15 +1439,16 @@ void OBJECT_OT_multires_external_pack(wmOperatorType *ot)
/********************* multires apply base ***********************/
static int multires_base_apply_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires);
if (!mmd)
return OPERATOR_CANCELLED;
- multiresModifier_base_apply(mmd, ob);
+ multiresModifier_base_apply(mmd, scene, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1455,13 +1495,13 @@ static void modifier_skin_customdata_delete(Object *ob)
static bool skin_poll(bContext *C)
{
return (!CTX_data_edit_object(C) &&
- edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
+ edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
}
static bool skin_edit_poll(bContext *C)
{
return (CTX_data_edit_object(C) &&
- edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
+ edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
}
static void skin_root_clear(BMVert *bm_vert, GSet *visited, const int cd_vert_skin_offset)
@@ -1514,7 +1554,7 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
BLI_gset_free(visited, NULL);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1554,8 +1594,8 @@ static int skin_loose_mark_clear_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) {
MVertSkin *vs = CustomData_bmesh_get(&bm->vdata,
- bm_vert->head.data,
- CD_MVERT_SKIN);
+ bm_vert->head.data,
+ CD_MVERT_SKIN);
switch (action) {
@@ -1569,7 +1609,7 @@ static int skin_loose_mark_clear_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1611,15 +1651,15 @@ static int skin_radii_equalize_exec(bContext *C, wmOperator *UNUSED(op))
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) {
MVertSkin *vs = CustomData_bmesh_get(&bm->vdata,
- bm_vert->head.data,
- CD_MVERT_SKIN);
+ bm_vert->head.data,
+ CD_MVERT_SKIN);
float avg = (vs->radius[0] + vs->radius[1]) * 0.5f;
vs->radius[0] = vs->radius[1] = avg;
}
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1639,12 +1679,12 @@ void OBJECT_OT_skin_radii_equalize(wmOperatorType *ot)
}
static void skin_armature_bone_create(Object *skin_ob,
- MVert *mvert, MEdge *medge,
- bArmature *arm,
- BLI_bitmap *edges_visited,
- const MeshElemMap *emap,
- EditBone *parent_bone,
- int parent_v)
+ MVert *mvert, MEdge *medge,
+ bArmature *arm,
+ BLI_bitmap *edges_visited,
+ const MeshElemMap *emap,
+ EditBone *parent_bone,
+ int parent_v)
{
int i;
@@ -1679,19 +1719,19 @@ static void skin_armature_bone_create(Object *skin_ob,
}
skin_armature_bone_create(skin_ob,
- mvert, medge,
- arm,
- edges_visited,
- emap,
- bone,
- v);
+ mvert, medge,
+ arm,
+ edges_visited,
+ emap,
+ bone,
+ v);
}
}
-static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *skin_ob)
+static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *skin_ob)
{
BLI_bitmap *edges_visited;
- DerivedMesh *deform_dm;
+ Mesh *me_eval_deform;
MVert *mvert;
Mesh *me = skin_ob->data;
Object *arm_ob;
@@ -1701,17 +1741,18 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *
int *emap_mem;
int v;
- deform_dm = mesh_get_derived_deform(scene, skin_ob, CD_MASK_BAREMESH);
- mvert = deform_dm->getVertArray(deform_dm);
+ me_eval_deform = mesh_get_eval_deform(depsgraph, scene, skin_ob, CD_MASK_BAREMESH);
+ mvert = me_eval_deform->mvert;
/* add vertex weights to original mesh */
CustomData_add_layer(&me->vdata,
- CD_MDEFORMVERT,
- CD_CALLOC,
- NULL,
- me->totvert);
+ CD_MDEFORMVERT,
+ CD_CALLOC,
+ NULL,
+ me->totvert);
- arm_ob = BKE_object_add(bmain, scene, OB_ARMATURE, NULL);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ arm_ob = BKE_object_add(bmain, scene, view_layer, OB_ARMATURE, NULL);
BKE_object_transform_copy(arm_ob, skin_ob);
arm = arm_ob->data;
arm->layer = 1;
@@ -1721,7 +1762,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *
mvert_skin = CustomData_get_layer(&me->vdata, CD_MVERT_SKIN);
BKE_mesh_vert_edge_map_create(&emap, &emap_mem,
- me->medge, me->totvert, me->totedge);
+ me->medge, me->totvert, me->totedge);
edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited");
@@ -1746,12 +1787,12 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *
if (emap[v].count >= 1) {
skin_armature_bone_create(skin_ob,
- mvert, me->medge,
- arm,
- edges_visited,
- emap,
- bone,
- v);
+ mvert, me->medge,
+ arm,
+ edges_visited,
+ emap,
+ bone,
+ v);
}
}
}
@@ -1769,6 +1810,7 @@ static Object *modifier_skin_armature_create(Main *bmain, Scene *scene, Object *
static int skin_armature_create_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C), *arm_ob;
Mesh *me = ob->data;
@@ -1781,7 +1823,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op)
}
/* create new armature */
- arm_ob = modifier_skin_armature_create(bmain, scene, ob);
+ arm_ob = modifier_skin_armature_create(depsgraph, bmain, scene, ob);
/* add a modifier to connect the new armature to the mesh */
arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature);
@@ -1791,8 +1833,8 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op)
arm_md->object = arm_ob;
arm_md->deformflag = ARM_DEF_VGROUP | ARM_DEF_QUATERNION;
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
@@ -1859,7 +1901,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
csmd->bind_coords_num = (unsigned int)-1;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -1900,7 +1942,7 @@ static bool meshdeform_poll(bContext *C)
static int meshdeform_bind_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *ob = ED_object_active_context(C);
MeshDeformModifierData *mmd = (MeshDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_MeshDeform);
@@ -1928,36 +1970,23 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op)
mmd->totvert = 0;
mmd->totcagevert = 0;
mmd->totinfluence = 0;
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
else {
- DerivedMesh *dm;
int mode = mmd->modifier.mode;
-
- /* force modifier to run, it will call binding routine */
mmd->bindfunc = ED_mesh_deform_bind_callback;
mmd->modifier.mode |= eModifierMode_Realtime;
- if (ob->type == OB_MESH) {
- dm = mesh_create_derived_view(scene, ob, 0);
- dm->release(dm);
- }
- else if (ob->type == OB_LATTICE) {
- BKE_lattice_modifiers_calc(scene, ob);
- }
- else if (ob->type == OB_MBALL) {
- BKE_displist_make_mball(bmain, bmain->eval_ctx, scene, ob);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
- BKE_displist_make_curveTypes(scene, ob, 0);
- }
+ /* Force depsgraph update, this will do binding. */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
mmd->bindfunc = NULL;
mmd->modifier.mode = mode;
}
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
return OPERATOR_FINISHED;
}
@@ -2003,7 +2032,7 @@ static int explode_refresh_exec(bContext *C, wmOperator *op)
emd->flag |= eExplodeFlag_CalcFaces;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
@@ -2041,28 +2070,9 @@ static bool ocean_bake_poll(bContext *C)
return edit_modifier_poll_generic(C, &RNA_OceanModifier, 0);
}
-/* copied from init_ocean_modifier, MOD_ocean.c */
-static void init_ocean_modifier_bake(struct Ocean *oc, struct OceanModifierData *omd)
-{
- int do_heightfield, do_chop, do_normals, do_jacobian;
-
- if (!omd || !oc) return;
-
- do_heightfield = true;
- do_chop = (omd->chop_amount > 0);
- do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
- do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
-
- BKE_ocean_init(oc, omd->resolution * omd->resolution, omd->resolution * omd->resolution, omd->spatial_size, omd->spatial_size,
- omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
- omd->depth, omd->time,
- do_heightfield, do_chop, do_normals, do_jacobian,
- omd->seed);
-}
-
typedef struct OceanBakeJob {
/* from wmJob */
- void *owner;
+ struct Object *owner;
short *stop, *do_update;
float *progress;
int current_frame;
@@ -2128,6 +2138,9 @@ static void oceanbake_endjob(void *customdata)
oj->omd->oceancache = oj->och;
oj->omd->cached = true;
+
+ Object *ob = oj->owner;
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
static int ocean_bake_exec(bContext *C, wmOperator *op)
@@ -2148,15 +2161,15 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if (free) {
- omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_CACHE;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ BKE_ocean_free_modifier_cache(omd);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
och = BKE_ocean_init_cache(omd->cachepath, modifier_path_relbase(bmain, ob),
- omd->bakestart, omd->bakeend, omd->wave_scale,
- omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
+ omd->bakestart, omd->bakeend, omd->wave_scale,
+ omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
och->time = MEM_mallocN(och->duration * sizeof(float), "foam bake time");
@@ -2177,11 +2190,11 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
* this part of the process before a threaded job is created */
//scene->r.cfra = f;
- //ED_update_for_newframe(bmain, scene, 1);
+ //ED_update_for_newframe(bmain, scene);
/* ok, this doesn't work with drivers, but is way faster.
* let's use this for now and hope nobody wants to drive the time value... */
- BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(CTX_data_depsgraph(C), scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM);
och->time[i] = omd->time;
i++;
@@ -2189,7 +2202,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
/* make a copy of ocean to use for baking - threadsafety */
ocean = BKE_ocean_add();
- init_ocean_modifier_bake(ocean, omd);
+ BKE_ocean_init_from_modifier(ocean, omd);
#if 0
BKE_ocean_bake(ocean, och);
@@ -2199,7 +2212,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
scene->r.cfra = cfra;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
#endif
@@ -2209,8 +2222,9 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
/* setup job */
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Ocean Simulation",
- WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_OCEAN);
+ WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_OCEAN);
oj = MEM_callocN(sizeof(OceanBakeJob), "ocean bake job");
+ oj->owner = ob;
oj->ocean = ocean;
oj->och = och;
oj->omd = omd;
@@ -2261,18 +2275,30 @@ static bool laplaciandeform_poll(bContext *C)
static int laplaciandeform_bind_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_LaplacianDeform);
if (!lmd)
return OPERATOR_CANCELLED;
if (lmd->flag & MOD_LAPLACIANDEFORM_BIND) {
+ /* Un-binding happens inside the modifier when it's evaluated. */
lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND;
}
else {
+ int mode = lmd->modifier.mode;
+
+ /* Force modifier to run, it will call binding routine. */
+ lmd->modifier.mode |= eModifierMode_Realtime;
lmd->flag |= MOD_LAPLACIANDEFORM_BIND;
+
+ object_force_modifier_update_for_bind(depsgraph, scene, ob);
+
+ lmd->modifier.mode = mode;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
@@ -2311,22 +2337,31 @@ static bool surfacedeform_bind_poll(bContext *C)
static int surfacedeform_bind_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_SurfaceDeform);
if (!smd)
return OPERATOR_CANCELLED;
-
if (smd->flags & MOD_SDEF_BIND) {
+ /* Un-binding happens inside the modifier when it's evaluated. */
smd->flags &= ~MOD_SDEF_BIND;
}
else if (smd->target) {
+ int mode = smd->modifier.mode;
+
+ /* Force modifier to run, it will call binding routine. */
+ smd->modifier.mode |= eModifierMode_Realtime;
smd->flags |= MOD_SDEF_BIND;
+
+ object_force_modifier_update_for_bind(depsgraph, scene, ob);
+
+ smd->modifier.mode = mode;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
-
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index f6db6d1f5fc..eb9dd0bbe28 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -40,13 +40,17 @@
#include "BKE_context.h"
#include "RNA_access.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_object.h"
+#include "DEG_depsgraph.h"
+
#include "object_intern.h"
@@ -61,21 +65,20 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_origin_clear);
WM_operatortype_append(OBJECT_OT_visual_transform_apply);
WM_operatortype_append(OBJECT_OT_transform_apply);
+ WM_operatortype_append(OBJECT_OT_transform_axis_target);
WM_operatortype_append(OBJECT_OT_origin_set);
WM_operatortype_append(OBJECT_OT_mode_set);
+ WM_operatortype_append(OBJECT_OT_mode_set_or_submode);
WM_operatortype_append(OBJECT_OT_editmode_toggle);
WM_operatortype_append(OBJECT_OT_posemode_toggle);
WM_operatortype_append(OBJECT_OT_proxy_make);
- WM_operatortype_append(OBJECT_OT_hide_view_clear);
- WM_operatortype_append(OBJECT_OT_hide_view_set);
- WM_operatortype_append(OBJECT_OT_hide_render_clear);
- WM_operatortype_append(OBJECT_OT_hide_render_set);
WM_operatortype_append(OBJECT_OT_shade_smooth);
WM_operatortype_append(OBJECT_OT_shade_flat);
WM_operatortype_append(OBJECT_OT_paths_calculate);
WM_operatortype_append(OBJECT_OT_paths_update);
WM_operatortype_append(OBJECT_OT_paths_clear);
+ WM_operatortype_append(OBJECT_OT_paths_range_update);
WM_operatortype_append(OBJECT_OT_forcefield_toggle);
WM_operatortype_append(OBJECT_OT_parent_set);
@@ -87,40 +90,41 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_slow_parent_set);
WM_operatortype_append(OBJECT_OT_slow_parent_clear);
WM_operatortype_append(OBJECT_OT_make_local);
+ WM_operatortype_append(OBJECT_OT_make_override_static);
WM_operatortype_append(OBJECT_OT_make_single_user);
WM_operatortype_append(OBJECT_OT_make_links_scene);
WM_operatortype_append(OBJECT_OT_make_links_data);
- WM_operatortype_append(OBJECT_OT_move_to_layer);
WM_operatortype_append(OBJECT_OT_select_random);
WM_operatortype_append(OBJECT_OT_select_all);
- WM_operatortype_append(OBJECT_OT_select_same_group);
+ WM_operatortype_append(OBJECT_OT_select_same_collection);
WM_operatortype_append(OBJECT_OT_select_by_type);
- WM_operatortype_append(OBJECT_OT_select_by_layer);
WM_operatortype_append(OBJECT_OT_select_linked);
WM_operatortype_append(OBJECT_OT_select_grouped);
WM_operatortype_append(OBJECT_OT_select_mirror);
WM_operatortype_append(OBJECT_OT_select_more);
WM_operatortype_append(OBJECT_OT_select_less);
- WM_operatortype_append(GROUP_OT_create);
- WM_operatortype_append(GROUP_OT_objects_remove_all);
- WM_operatortype_append(GROUP_OT_objects_remove);
- WM_operatortype_append(GROUP_OT_objects_add_active);
- WM_operatortype_append(GROUP_OT_objects_remove_active);
+ WM_operatortype_append(COLLECTION_OT_create);
+ WM_operatortype_append(COLLECTION_OT_objects_remove_all);
+ WM_operatortype_append(COLLECTION_OT_objects_remove);
+ WM_operatortype_append(COLLECTION_OT_objects_add_active);
+ WM_operatortype_append(COLLECTION_OT_objects_remove_active);
WM_operatortype_append(OBJECT_OT_delete);
WM_operatortype_append(OBJECT_OT_text_add);
WM_operatortype_append(OBJECT_OT_armature_add);
WM_operatortype_append(OBJECT_OT_empty_add);
+ WM_operatortype_append(OBJECT_OT_lightprobe_add);
WM_operatortype_append(OBJECT_OT_drop_named_image);
- WM_operatortype_append(OBJECT_OT_lamp_add);
+ WM_operatortype_append(OBJECT_OT_gpencil_add);
+ WM_operatortype_append(OBJECT_OT_light_add);
WM_operatortype_append(OBJECT_OT_camera_add);
WM_operatortype_append(OBJECT_OT_speaker_add);
WM_operatortype_append(OBJECT_OT_add);
WM_operatortype_append(OBJECT_OT_add_named);
WM_operatortype_append(OBJECT_OT_effector_add);
- WM_operatortype_append(OBJECT_OT_group_instance_add);
+ WM_operatortype_append(OBJECT_OT_collection_instance_add);
WM_operatortype_append(OBJECT_OT_metaball_add);
WM_operatortype_append(OBJECT_OT_duplicates_make_real);
WM_operatortype_append(OBJECT_OT_duplicate);
@@ -146,6 +150,20 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
WM_operatortype_append(OBJECT_OT_skin_armature_create);
+ /* grease pencil modifiers */
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_add);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_remove);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_up);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_down);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_apply);
+ WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy);
+
+ /* shader fx */
+ WM_operatortype_append(OBJECT_OT_shaderfx_add);
+ WM_operatortype_append(OBJECT_OT_shaderfx_remove);
+ WM_operatortype_append(OBJECT_OT_shaderfx_move_up);
+ WM_operatortype_append(OBJECT_OT_shaderfx_move_down);
+
WM_operatortype_append(OBJECT_OT_correctivesmooth_bind);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);
@@ -202,15 +220,18 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_weight_normalize_active_vertex);
WM_operatortype_append(OBJECT_OT_vertex_weight_copy);
+ WM_operatortype_append(OBJECT_OT_face_map_add);
+ WM_operatortype_append(OBJECT_OT_face_map_remove);
+ WM_operatortype_append(OBJECT_OT_face_map_assign);
+ WM_operatortype_append(OBJECT_OT_face_map_remove_from);
+ WM_operatortype_append(OBJECT_OT_face_map_select);
+ WM_operatortype_append(OBJECT_OT_face_map_deselect);
+ WM_operatortype_append(OBJECT_OT_face_map_move);
+
WM_operatortype_append(TRANSFORM_OT_vertex_warp);
- WM_operatortype_append(OBJECT_OT_game_property_new);
- WM_operatortype_append(OBJECT_OT_game_property_remove);
- WM_operatortype_append(OBJECT_OT_game_property_copy);
- WM_operatortype_append(OBJECT_OT_game_property_clear);
- WM_operatortype_append(OBJECT_OT_game_property_move);
- WM_operatortype_append(OBJECT_OT_logic_bricks_copy);
- WM_operatortype_append(OBJECT_OT_game_physics_copy);
+ WM_operatortype_append(OBJECT_OT_move_to_collection);
+ WM_operatortype_append(OBJECT_OT_link_to_collection);
WM_operatortype_append(OBJECT_OT_shape_key_add);
WM_operatortype_append(OBJECT_OT_shape_key_remove);
@@ -219,11 +240,11 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_shape_key_mirror);
WM_operatortype_append(OBJECT_OT_shape_key_move);
- WM_operatortype_append(OBJECT_OT_group_add);
- WM_operatortype_append(OBJECT_OT_group_link);
- WM_operatortype_append(OBJECT_OT_group_remove);
- WM_operatortype_append(OBJECT_OT_group_unlink);
- WM_operatortype_append(OBJECT_OT_grouped_select);
+ WM_operatortype_append(OBJECT_OT_collection_add);
+ WM_operatortype_append(OBJECT_OT_collection_link);
+ WM_operatortype_append(OBJECT_OT_collection_remove);
+ WM_operatortype_append(OBJECT_OT_collection_unlink);
+ WM_operatortype_append(OBJECT_OT_collection_objects_select);
WM_operatortype_append(OBJECT_OT_hook_add_selob);
WM_operatortype_append(OBJECT_OT_hook_add_newob);
@@ -239,14 +260,15 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_unlink_data);
WM_operatortype_append(OBJECT_OT_laplaciandeform_bind);
- WM_operatortype_append(OBJECT_OT_lod_add);
- WM_operatortype_append(OBJECT_OT_lod_remove);
-
WM_operatortype_append(TRANSFORM_OT_vertex_random);
WM_operatortype_append(OBJECT_OT_data_transfer);
WM_operatortype_append(OBJECT_OT_datalayout_transfer);
WM_operatortype_append(OBJECT_OT_surfacedeform_bind);
+
+ WM_operatortype_append(OBJECT_OT_hide_view_clear);
+ WM_operatortype_append(OBJECT_OT_hide_view_set);
+ WM_operatortype_append(OBJECT_OT_hide_collection);
}
void ED_operatormacros_object(void)
@@ -283,199 +305,12 @@ static bool object_mode_poll(bContext *C)
void ED_keymap_object(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
- wmKeyMapItem *kmi;
- int i;
/* Objects, Regardless of Mode -------------------------------------------------- */
keymap = WM_keymap_ensure(keyconf, "Object Non-modal", 0, 0);
- /* Note: this keymap works disregarding mode */
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", OB_MODE_EDIT);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "mode", OB_MODE_POSE);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", VKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", OB_MODE_VERTEX_PAINT);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "mode", OB_MODE_WEIGHT_PAINT);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_origin_set", CKEY, KM_PRESS, KM_ALT | KM_SHIFT | KM_CTRL, 0);
-
/* Object Mode ---------------------------------------------------------------- */
/* Note: this keymap gets disabled in non-objectmode, */
keymap = WM_keymap_ensure(keyconf, "Object Mode", 0, 0);
keymap->poll = object_mode_poll;
-
- /* object mode supports PET now */
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_obmode(keyconf, keymap);
-
- /* game-engine only, leave free for users to define */
- WM_keymap_add_item(keymap, "VIEW3D_OT_game_start", PKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "OBJECT_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_select_linked", LKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "OBJECT_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "OBJECT_OT_select_mirror", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "PARENT");
- RNA_boolean_set(kmi->ptr, "extend", false);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "PARENT");
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "CHILD");
- RNA_boolean_set(kmi->ptr, "extend", false);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "CHILD");
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- WM_keymap_verify_item(keymap, "OBJECT_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_parent_no_inverse_set", PKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_parent_clear", PKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_track_set", TKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_track_clear", TKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_verify_item(keymap, "OBJECT_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_verify_item(keymap, "OBJECT_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
-
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "clear_delta", false);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "clear_delta", false);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "clear_delta", false);
-
- WM_keymap_verify_item(keymap, "OBJECT_OT_origin_clear", OKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- /* same as above but for rendering */
- WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_clear", HKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
- WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_set", HKEY, KM_PRESS, KM_CTRL, 0);
-
- /* conflicts, removing */
-#if 0
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_render_set", HKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)
- RNA_boolean_set(kmi->ptr, "unselected", true);
-#endif
-
- WM_keymap_add_item(keymap, "OBJECT_OT_move_to_layer", MKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_global", false);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "use_global", true);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_global", false);
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "use_global", true);
-
- WM_keymap_add_menu(keymap, "INFO_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_duplicates_make_real", AKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_object_apply", AKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_make_single_user", UKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "VIEW3D_MT_make_links", LKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move_linked", DKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "OBJECT_OT_join", JKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "OBJECT_OT_convert", CKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "OBJECT_OT_proxy_make", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_add_item(keymap, "OBJECT_OT_make_local", LKEY, KM_PRESS, 0, 0);
-
- /* XXX this should probably be in screen instead... here for testing purposes in the meantime... - Aligorith */
- WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_insert_menu", IKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_delete_v3d", IKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_verify_item(keymap, "ANIM_OT_keying_set_active_set", IKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0);
-
- WM_keymap_verify_item(keymap, "GROUP_OT_create", GKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove", GKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_all", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL | KM_ALT, 0);
- WM_keymap_verify_item(keymap, "GROUP_OT_objects_add_active", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_object_specials", WKEY, KM_PRESS, 0, 0);
-
- WM_keymap_verify_item(keymap, "OBJECT_OT_data_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- /* XXX No more available 'T' shortcuts... :/ */
- /* WM_keymap_verify_item(keymap, "OBJECT_OT_datalayout_transfer", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); */
-
- for (i = 0; i <= 5; i++) {
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY + i, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "level", i);
- }
-}
-
-void ED_keymap_proportional_cycle(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_enum", OKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.proportional_edit_falloff");
- RNA_boolean_set(kmi->ptr, "wrap", true);
-}
-
-void ED_keymap_proportional_obmode(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_edit_objects");
-}
-
-void ED_keymap_proportional_maskmode(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_edit_mask");
-}
-
-void ED_keymap_proportional_editmode(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap,
- const bool do_connected)
-{
- wmKeyMapItem *kmi;
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", OKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.proportional_edit");
- RNA_string_set(kmi->ptr, "value_1", "DISABLED");
- RNA_string_set(kmi->ptr, "value_2", "ENABLED");
-
- /* for modes/object types that allow 'connected' mode, add the Alt O key */
- if (do_connected) {
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", OKEY, KM_PRESS, KM_ALT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.proportional_edit");
- RNA_string_set(kmi->ptr, "value_1", "DISABLED");
- RNA_string_set(kmi->ptr, "value_2", "CONNECTED");
- }
}
diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c
index 05726e5be2d..8291b68f15f 100644
--- a/source/blender/editors/object/object_random.c
+++ b/source/blender/editors/object/object_random.c
@@ -25,6 +25,9 @@
* \ingroup edobj
*/
+#include "MEM_guardedalloc.h"
+
+#include "DNA_layer_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -32,6 +35,7 @@
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -94,34 +98,53 @@ static bool object_rand_transverts(
static int object_rand_verts_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob_active = CTX_data_edit_object(C);
+ const int ob_mode = ob_active->mode;
+
const float offset = RNA_float_get(op->ptr, "offset");
const float uniform = RNA_float_get(op->ptr, "uniform");
const float normal_factor = RNA_float_get(op->ptr, "normal");
const unsigned int seed = RNA_int_get(op->ptr, "seed");
- TransVertStore tvs = {NULL};
- Object *obedit = CTX_data_edit_object(C);
+ bool changed_multi = false;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len, ob_mode);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
- if (obedit) {
- int mode = TM_ALL_JOINTS;
+ TransVertStore tvs = { NULL };
- if (normal_factor != 0.0f) {
- mode |= TX_VERT_USE_NORMAL;
- }
+ if (ob_iter) {
+ int mode = TM_ALL_JOINTS;
- ED_transverts_create_from_obedit(&tvs, obedit, mode);
- if (tvs.transverts_tot == 0)
- return OPERATOR_CANCELLED;
+ if (normal_factor != 0.0f) {
+ mode |= TX_VERT_USE_NORMAL;
+ }
- object_rand_transverts(&tvs, offset, uniform, normal_factor, seed);
+ ED_transverts_create_from_obedit(&tvs, ob_iter, mode);
+ if (tvs.transverts_tot == 0) {
+ continue;
+ }
- ED_transverts_update_obedit(&tvs, obedit);
- ED_transverts_free(&tvs);
- }
+ int seed_iter = seed;
+ /* This gives a consistent result regardless of object order. */
+ if (ob_index) {
+ seed_iter += BLI_ghashutil_strhash_p(ob_iter->id.name);
+ }
+
+ object_rand_transverts(&tvs, offset, uniform, normal_factor, seed_iter);
+
+ ED_transverts_update_obedit(&tvs, ob_iter);
+ ED_transverts_free(&tvs);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter);
+ changed_multi = true;
+ }
+ }
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot)
@@ -139,10 +162,12 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float(ot->srna, "offset", 0.1f, -FLT_MAX, FLT_MAX, "Amount", "Distance to offset", -10.0f, 10.0f);
+ ot->prop = RNA_def_float(
+ ot->srna, "offset", 0.1f, -FLT_MAX, FLT_MAX,
+ "Amount", "Distance to offset", -10.0f, 10.0f);
RNA_def_float(ot->srna, "uniform", 0.0f, 0.0f, 1.0f, "Uniform",
"Increase for uniform offset distance", 0.0f, 1.0f);
- RNA_def_float(ot->srna, "normal", 0.0f, 0.0f, 1.0f, "normal",
+ RNA_def_float(ot->srna, "normal", 0.0f, 0.0f, 1.0f, "Normal",
"Align offset direction to normals", 0.0f, 1.0f);
RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
}
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d27edb5a9e4..5121f1534bd 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -37,8 +37,8 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
#include "DNA_material_types.h"
@@ -63,21 +63,25 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_camera.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
-#include "BKE_group.h"
+#include "BKE_gpencil.h"
#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
+#include "BKE_lightprobe.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
@@ -86,11 +90,12 @@
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_sca.h"
#include "BKE_scene.h"
#include "BKE_speaker.h"
#include "BKE_texture.h"
-#include "BKE_editmesh.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -104,6 +109,7 @@
#include "ED_armature.h"
#include "ED_curve.h"
+#include "ED_gpencil.h"
#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_mesh.h"
@@ -123,10 +129,12 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
BMVert *eve;
BMIter iter;
- Curve *cu;
Nurb *nu;
BezTriple *bezt;
BPoint *bp;
@@ -142,7 +150,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
EDBM_mesh_load(bmain, obedit);
EDBM_mesh_make(obedit, scene->toolsettings->selectmode, true);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
em = me->edit_btmesh;
@@ -151,7 +159,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
/* derivedMesh might be needed for solving parenting,
* so re-create it here */
- makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX, false);
+ makeDerivedMesh(depsgraph, scene, obedit, em, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX, false);
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
@@ -167,15 +175,13 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
else if (ELEM(obedit->type, OB_SURF, OB_CURVE)) {
ListBase *editnurb = object_editcurve_get(obedit);
- cu = obedit->data;
-
nu = editnurb->first;
while (nu) {
if (nu->type == CU_BEZIER) {
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt)) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
if (v1 == 0) v1 = nr;
else if (v2 == 0) v2 = nr;
else if (v3 == 0) v3 = nr;
@@ -230,7 +236,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
if (ob != obedit) {
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
par = obedit->parent;
if (BKE_object_parent_loop_check(par, ob)) {
@@ -239,7 +245,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
else {
Object workob;
- ob->parent = BASACT->object;
+ ob->parent = BASACT(view_layer)->object;
if (v3) {
ob->partype = PARVERT3;
ob->par1 = v1 - 1;
@@ -247,7 +253,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
ob->par3 = v3 - 1;
/* inverse parent matrix */
- BKE_object_workob_calc_parent(scene, ob, &workob);
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
}
else {
@@ -255,7 +261,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
ob->par1 = v1 - 1;
/* inverse parent matrix */
- BKE_object_workob_calc_parent(scene, ob, &workob);
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
}
}
@@ -263,7 +269,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT, NULL);
@@ -322,7 +328,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
/* error.. cannot continue */
- BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or group");
+ BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or collection");
return OPERATOR_CANCELLED;
}
@@ -332,44 +338,42 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob, *gob = ED_object_active_context(C);
- GroupObject *go;
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
if (gob->dup_group != NULL) {
- go = BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "object"));
- ob = go->ob;
+ const ListBase dup_group_objects = BKE_collection_object_cache_get(gob->dup_group);
+ Base *base = BLI_findlink(&dup_group_objects, RNA_enum_get(op->ptr, "object"));
+ ob = base->object;
}
else {
ob = gob;
- gob = NULL;
}
if (ob) {
Object *newob;
- Base *newbase, *oldbase = BASACT;
char name[MAX_ID_NAME + 4];
BLI_snprintf(name, sizeof(name), "%s_proxy", ((ID *)(gob ? gob : ob))->name + 2);
/* Add new object for the proxy */
- newob = BKE_object_add(bmain, scene, OB_EMPTY, name);
+ newob = BKE_object_add_from(bmain, scene, view_layer, OB_EMPTY, name, gob ? gob : ob);
/* set layers OK */
- newbase = BASACT; /* BKE_object_add sets active... */
- newbase->lay = oldbase->lay;
- newob->lay = newbase->lay;
-
- /* remove base, leave user count of object, it gets linked in BKE_object_make_proxy */
- if (gob == NULL) {
- BKE_scene_base_unlink(scene, oldbase);
- MEM_freeN(oldbase);
- }
-
- BKE_object_make_proxy(newob, ob, gob);
+ BKE_object_make_proxy(bmain, newob, ob, gob);
+
+ /* Set back pointer immediately so dependency graph knows that this is
+ * is a proxy and will act accordingly. Otherwise correctness of graph
+ * will depend on order of bases.
+ *
+ * TODO(sergey): We really need to get rid of this bi-directional links
+ * in proxies with something like static overrides.
+ */
+ newob->proxy->proxy_from = newob;
/* depsgraph flushes are needed for the new data */
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, newob);
}
else {
@@ -381,24 +385,25 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
}
/* Generic itemf's for operators that take library args */
-static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *proxy_collection_object_itemf(bContext *C, PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem item_tmp = {0}, *item = NULL;
int totitem = 0;
int i = 0;
Object *ob = ED_object_active_context(C);
- GroupObject *go;
if (!ob || !ob->dup_group)
return DummyRNA_DEFAULT_items;
/* find the object to affect */
- for (go = ob->dup_group->gobject.first; go; go = go->next) {
- item_tmp.identifier = item_tmp.name = go->ob->id.name + 2;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(ob->dup_group, object)
+ {
+ item_tmp.identifier = item_tmp.name = object->id.name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -426,8 +431,8 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot)
/* properties */
/* XXX, relies on hard coded ID at the moment */
prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object",
- "Name of lib-linked/grouped object to make a proxy for");
- RNA_def_enum_funcs(prop, proxy_group_object_itemf);
+ "Name of lib-linked/collection object to make a proxy for");
+ RNA_def_enum_funcs(prop, proxy_collection_object_itemf);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
}
@@ -524,7 +529,7 @@ void ED_object_parent_clear(Object *ob, const int type)
/* Always clear parentinv matrix for sake of consistency, see T41950. */
unit_m4(ob->parentinv);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
/* note, poll should check for editable scene */
@@ -539,7 +544,7 @@ static int parent_clear_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
return OPERATOR_FINISHED;
@@ -607,13 +612,15 @@ EnumPropertyItem prop_make_parent_types[] = {
{0, NULL, 0, NULL, NULL}
};
-bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par,
+bool ED_object_parent_set(ReportList *reports, const bContext *C, Scene *scene, Object *ob, Object *par,
int partype, const bool xmirror, const bool keep_transform, const int vert_par[3])
{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
bPoseChannel *pchan = NULL;
const bool pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
- DAG_id_tag_update(&par->id, OB_RECALC_OB);
+ DEG_id_tag_update(&par->id, OB_RECALC_OB);
/* preconditions */
if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) {
@@ -624,7 +631,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
if ((cu->flag & CU_PATH) == 0) {
cu->flag |= CU_PATH | CU_FOLLOW;
- BKE_displist_make_curveTypes(scene, par, 0); /* force creation of path data */
+ BKE_displist_make_curveTypes(depsgraph, scene, par, false, false); /* force creation of path data */
}
else {
cu->flag |= CU_FOLLOW;
@@ -634,7 +641,7 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
if (partype == PAR_FOLLOW) {
/* get or create F-Curve */
bAction *act = verify_adt_action(bmain, &cu->id, 1);
- FCurve *fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1);
+ FCurve *fcu = verify_fcurve(bmain, act, NULL, NULL, "eval_time", 0, 1);
/* setup dummy 'generator' modifier here to get 1-1 correspondence still working */
if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first)
@@ -709,8 +716,8 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
if (md) {
((CurveModifierData *)md)->object = par;
}
- if (par->curve_cache && par->curve_cache->path == NULL) {
- DAG_id_tag_update(&par->id, OB_RECALC_DATA);
+ if (par->runtime.curve_cache && par->runtime.curve_cache->path == NULL) {
+ DEG_id_tag_update(&par->id, OB_RECALC_DATA);
}
}
break;
@@ -766,34 +773,53 @@ bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
data = con->data;
data->tar = par;
- BKE_constraint_target_matrix_get(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
+ BKE_constraint_target_matrix_get(depsgraph, scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
sub_v3_v3v3(vec, ob->obmat[3], cmat[3]);
copy_v3_v3(ob->loc, vec);
}
else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) {
- if (partype == PAR_ARMATURE_NAME)
- ED_object_vgroup_calc_from_armature(reports, scene, ob, par, ARM_GROUPS_NAME, false);
- else if (partype == PAR_ARMATURE_ENVELOPE)
- ED_object_vgroup_calc_from_armature(reports, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror);
+ if (partype == PAR_ARMATURE_NAME) {
+ ED_object_vgroup_calc_from_armature(reports, depsgraph, scene, ob, par, ARM_GROUPS_NAME, false);
+ }
+ else if (partype == PAR_ARMATURE_ENVELOPE) {
+ ED_object_vgroup_calc_from_armature(reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror);
+ }
else if (partype == PAR_ARMATURE_AUTO) {
WM_cursor_wait(1);
- ED_object_vgroup_calc_from_armature(reports, scene, ob, par, ARM_GROUPS_AUTO, xmirror);
+ ED_object_vgroup_calc_from_armature(reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror);
WM_cursor_wait(0);
}
/* get corrected inverse */
ob->partype = PAROBJECT;
- BKE_object_workob_calc_parent(scene, ob, &workob);
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
+
+ invert_m4_m4(ob->parentinv, workob.obmat);
+ }
+ else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) {
+ if (partype == PAR_ARMATURE_NAME) {
+ ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME);
+ }
+ else if ((partype == PAR_ARMATURE_AUTO) ||
+ (partype == PAR_ARMATURE_ENVELOPE))
+ {
+ WM_cursor_wait(1);
+ ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO);
+ WM_cursor_wait(0);
+ }
+ /* get corrected inverse */
+ ob->partype = PAROBJECT;
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
}
else {
/* calculate inverse parent matrix */
- BKE_object_workob_calc_parent(scene, ob, &workob);
+ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
}
}
@@ -864,7 +890,7 @@ static int parent_set_exec(bContext *C, wmOperator *op)
parent_set_vert_find(tree, ob, vert_par, is_tri);
}
- if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) {
+ if (!ED_object_parent_set(op->reports, C, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) {
ok = false;
break;
}
@@ -879,7 +905,7 @@ static int parent_set_exec(bContext *C, wmOperator *op)
if (!ok)
return OPERATOR_CANCELLED;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
@@ -984,7 +1010,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Object *par = ED_object_active_context(C);
- DAG_id_tag_update(&par->id, OB_RECALC_OB);
+ DEG_id_tag_update(&par->id, OB_RECALC_OB);
/* context iterator */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
@@ -999,7 +1025,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
memset(ob->loc, 0, 3 * sizeof(float));
/* set recalc flags */
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
/* set parenting type for object - object only... */
ob->parent = par;
@@ -1009,7 +1035,7 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
return OPERATOR_FINISHED;
@@ -1035,6 +1061,7 @@ void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot)
static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
@@ -1042,9 +1069,9 @@ static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
if (ob->parent) {
if (ob->partype & PARSLOW) {
ob->partype -= PARSLOW;
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
ob->partype |= PARSLOW;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
}
@@ -1082,7 +1109,7 @@ static int object_slow_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
if (ob->parent)
ob->partype |= PARSLOW;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
CTX_DATA_END;
@@ -1136,7 +1163,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
/* remove track-object for old track */
ob->track = NULL;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* also remove all tracking constraints */
for (con = ob->constraints.last; con; con = pcon) {
@@ -1150,7 +1177,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
return OPERATOR_FINISHED;
@@ -1210,7 +1237,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
data = con->data;
data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* Lamp, Camera and Speaker track differently by default */
if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
@@ -1233,7 +1260,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
data = con->data;
data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* Lamp, Camera and Speaker track differently by default */
if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
@@ -1257,7 +1284,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
data = con->data;
data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* Lamp, Camera and Speaker track differently by default */
if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
@@ -1271,7 +1298,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
}
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
return OPERATOR_FINISHED;
@@ -1297,120 +1324,6 @@ void OBJECT_OT_track_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", "");
}
-/************************** Move to Layer Operator *****************************/
-
-static unsigned int move_to_layer_init(bContext *C, wmOperator *op)
-{
- int a;
- bool values[20];
- unsigned int lay = 0;
-
- if (!RNA_struct_property_is_set(op->ptr, "layers")) {
- /* note: layers are set in bases, library objects work for this */
- CTX_DATA_BEGIN (C, Base *, base, selected_bases)
- {
- lay |= base->lay;
- }
- CTX_DATA_END;
-
- for (a = 0; a < 20; a++)
- values[a] = (lay & (1 << a)) != 0;
-
- RNA_boolean_set_array(op->ptr, "layers", values);
- }
- else {
- RNA_boolean_get_array(op->ptr, "layers", values);
-
- for (a = 0; a < 20; a++)
- if (values[a])
- lay |= (1 << a);
- }
-
- return lay;
-}
-
-static int move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- View3D *v3d = CTX_wm_view3d(C);
- if (v3d && v3d->localvd) {
- return WM_operator_confirm_message(C, op, "Move out of Local View");
- }
- else {
- move_to_layer_init(C, op);
- return WM_operator_props_popup(C, op, event);
- }
-}
-
-static int move_to_layer_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- unsigned int lay, local;
- /* bool is_lamp = false; */ /* UNUSED */
-
- lay = move_to_layer_init(C, op);
- lay &= 0xFFFFFF;
-
- if (lay == 0) return OPERATOR_CANCELLED;
-
- if (v3d && v3d->localvd) {
- /* now we can move out of localview. */
- /* note: layers are set in bases, library objects work for this */
- CTX_DATA_BEGIN (C, Base *, base, selected_bases)
- {
- lay = base->lay & ~v3d->lay;
- base->lay = lay;
- base->object->lay = lay;
- base->object->flag &= ~SELECT;
- base->flag &= ~SELECT;
- /* if (base->object->type == OB_LAMP) is_lamp = true; */
- }
- CTX_DATA_END;
- }
- else {
- /* normal non localview operation */
- /* note: layers are set in bases, library objects work for this */
- CTX_DATA_BEGIN (C, Base *, base, selected_bases)
- {
- /* upper byte is used for local view */
- local = base->lay & 0xFF000000;
- base->lay = lay + local;
- base->object->lay = base->lay;
- /* if (base->object->type == OB_LAMP) is_lamp = true; */
- }
- CTX_DATA_END;
- }
-
- /* warning, active object may be hidden now */
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
-
- DAG_relations_tag_update(bmain);
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_move_to_layer(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Move to Layer";
- ot->description = "Move the object to different layers";
- ot->idname = "OBJECT_OT_move_to_layer";
-
- /* api callbacks */
- ot->invoke = move_to_layer_invoke;
- ot->exec = move_to_layer_exec;
- ot->poll = ED_operator_objectmode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", "");
-}
-
/************************** Link to Scene Operator *****************************/
#if 0
@@ -1433,23 +1346,10 @@ static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr))
}
#endif
-Base *ED_object_scene_link(Scene *scene, Object *ob)
-{
- Base *base;
-
- if (BKE_scene_base_find(scene, ob)) {
- return NULL;
- }
-
- base = BKE_scene_base_add(scene, ob);
- id_us_plus(&ob->id);
-
- return base;
-}
-
static int make_links_scene_exec(bContext *C, wmOperator *op)
{
- Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
+ Main *bmain = CTX_data_main(C);
+ Scene *scene_to = BLI_findlink(&bmain->scene, RNA_enum_get(op->ptr, "scene"));
if (scene_to == NULL) {
BKE_report(op->reports, RPT_ERROR, "Could not find scene");
@@ -1466,9 +1366,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ Collection *collection_to = BKE_collection_master(scene_to);
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
- ED_object_scene_link(scene_to, base->object);
+ BKE_collection_object_add(bmain, collection_to, base->object);
}
CTX_DATA_END;
@@ -1484,7 +1385,7 @@ enum {
MAKE_LINKS_MATERIALS = 2,
MAKE_LINKS_ANIMDATA = 3,
MAKE_LINKS_GROUP = 4,
- MAKE_LINKS_DUPLIGROUP = 5,
+ MAKE_LINKS_DUPLICOLLECTION = 5,
MAKE_LINKS_MODIFIERS = 6,
MAKE_LINKS_FONTS = 7,
};
@@ -1505,7 +1406,7 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst
break;
case MAKE_LINKS_ANIMDATA:
case MAKE_LINKS_GROUP:
- case MAKE_LINKS_DUPLIGROUP:
+ case MAKE_LINKS_DUPLICOLLECTION:
return true;
case MAKE_LINKS_MODIFIERS:
if (!ELEM(OB_EMPTY, ob_src->type, ob_dst->type)) {
@@ -1523,23 +1424,23 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst
static int make_links_data_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ Main *bmain = CTX_data_main(C);
const int type = RNA_enum_get(op->ptr, "type");
Object *ob_src;
ID *obdata_id;
int a;
- /* group */
- LinkNode *ob_groups = NULL;
+ /* collection */
+ LinkNode *ob_collections = NULL;
bool is_cycle = false;
bool is_lib = false;
ob_src = ED_object_active_context(C);
- /* avoid searching all groups in source object each time */
+ /* avoid searching all collections in source object each time */
if (type == MAKE_LINKS_GROUP) {
- ob_groups = BKE_object_groups(bmain, ob_src);
+ ob_collections = BKE_object_groups(bmain, ob_src);
}
CTX_DATA_BEGIN (C, Base *, base_dst, selected_editable_bases)
@@ -1561,7 +1462,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
/* if amount of material indices changed: */
test_object_materials(bmain, ob_dst, ob_dst->data);
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
break;
case MAKE_LINKS_MATERIALS:
/* new approach, using functions from kernel */
@@ -1569,30 +1470,30 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
Material *ma = give_current_material(ob_src, a + 1);
assign_material(bmain, ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); /* also works with ma==NULL */
}
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
break;
case MAKE_LINKS_ANIMDATA:
- BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, false);
+ BKE_animdata_copy_id(bmain, (ID *)ob_dst, (ID *)ob_src, 0);
if (ob_dst->data && ob_src->data) {
if (ID_IS_LINKED(obdata_id)) {
is_lib = true;
break;
}
- BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, false);
+ BKE_animdata_copy_id(bmain, (ID *)ob_dst->data, (ID *)ob_src->data, 0);
}
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
break;
case MAKE_LINKS_GROUP:
{
- LinkNode *group_node;
+ LinkNode *collection_node;
- /* first clear groups */
- BKE_object_groups_clear(bmain, scene, base_dst, ob_dst);
+ /* first clear collections */
+ BKE_object_groups_clear(bmain, ob_dst);
- /* now add in the groups from the link nodes */
- for (group_node = ob_groups; group_node; group_node = group_node->next) {
- if (ob_dst->dup_group != group_node->link) {
- BKE_group_object_add(group_node->link, ob_dst, scene, base_dst);
+ /* now add in the collections from the link nodes */
+ for (collection_node = ob_collections; collection_node; collection_node = collection_node->next) {
+ if (ob_dst->dup_group != collection_node->link) {
+ BKE_collection_object_add(bmain, collection_node->link, ob_dst);
}
else {
is_cycle = true;
@@ -1600,16 +1501,16 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
}
break;
}
- case MAKE_LINKS_DUPLIGROUP:
+ case MAKE_LINKS_DUPLICOLLECTION:
ob_dst->dup_group = ob_src->dup_group;
if (ob_dst->dup_group) {
id_us_plus(&ob_dst->dup_group->id);
- ob_dst->transflag |= OB_DUPLIGROUP;
+ ob_dst->transflag |= OB_DUPLICOLLECTION;
}
break;
case MAKE_LINKS_MODIFIERS:
- BKE_object_link_modifiers(ob_dst, ob_src);
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ BKE_object_link_modifiers(scene, ob_dst, ob_src);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
break;
case MAKE_LINKS_FONTS:
{
@@ -1638,7 +1539,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
cu_dst->vfontbi = cu_src->vfontbi;
id_us_plus((ID *)cu_dst->vfontbi);
- DAG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob_dst->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
break;
}
}
@@ -1648,12 +1549,12 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
if (type == MAKE_LINKS_GROUP) {
- if (ob_groups) {
- BLI_linklist_free(ob_groups, NULL);
+ if (ob_collections) {
+ BLI_linklist_free(ob_collections, NULL);
}
if (is_cycle) {
- BKE_report(op->reports, RPT_WARNING, "Skipped some groups because of cycle detected");
+ BKE_report(op->reports, RPT_WARNING, "Skipped some collections because of cycle detected");
}
}
@@ -1661,7 +1562,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_WARNING, "Skipped editing library object data");
}
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, CTX_wm_view3d(C));
WM_event_add_notifier(C, NC_OBJECT, NULL);
@@ -1701,7 +1602,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
{MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Materials", ""},
{MAKE_LINKS_ANIMDATA, "ANIMATION", 0, "Animation Data", ""},
{MAKE_LINKS_GROUP, "GROUPS", 0, "Group", ""},
- {MAKE_LINKS_DUPLIGROUP, "DUPLIGROUP", 0, "DupliGroup", ""},
+ {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "DupliGroup", ""},
{MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""},
{MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""},
{0, NULL, 0, NULL, NULL}};
@@ -1725,101 +1626,110 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/**************************** Make Single User ********************************/
-/* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */
-static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups)
+static void libblock_relink_collection(Collection *collection)
{
- Base *base;
- Object *ob, *obn;
- Group *group, *groupn;
- GroupObject *go;
-
- clear_sca_new_poins(); /* BGE logic */
-
- /* duplicate (must set newid) */
- for (base = FIRSTBASE; base; base = base->next) {
- ob = base->object;
+ BKE_libblock_relink_to_newid(&collection->id);
- if ((base->flag & flag) == flag) {
- if (!ID_IS_LINKED(ob) && ob->id.us > 1) {
- /* base gets copy of object */
- base->object = obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
-
- if (copy_groups) {
- if (ob->flag & OB_FROMGROUP) {
- obn->flag |= OB_FROMGROUP;
- }
- }
- else {
- /* copy already clears */
- }
- /* remap gpencil parenting */
+ for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) {
+ BKE_libblock_relink_to_newid(&cob->ob->id);
+ }
- if (scene->gpd) {
- bGPdata *gpd = scene->gpd;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->parent == ob) {
- gpl->parent = obn;
- }
- }
- }
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ libblock_relink_collection(child->collection);
+ }
+}
- base->flag = obn->flag;
+static void single_object_users_collection(
+ Main *bmain, Scene *scene, Collection *collection,
+ const int flag, const bool copy_collections, const bool is_master_collection)
+{
+ /* Generate new copies for objects in given collection and all its children,
+ * and optionnaly also copy collections themselves. */
+ if (copy_collections && !is_master_collection) {
+ collection = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection));
+ }
- id_us_min(&ob->id);
+ /* We do not remap to new objects here, this is done in separate step. */
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Object *ob = cob->ob;
+ /* an object may be in more than one collection */
+ if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) {
+ if (!ID_IS_LINKED(ob) && ob->id.us > 1) {
+ ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
}
}
}
- /* duplicate groups that consist entirely of duplicated objects */
- for (group = bmain->group.first; group; group = group->id.next) {
- if (copy_groups && group->gobject.first) {
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ single_object_users_collection(bmain, scene, child->collection, flag, copy_collections, false);
+ }
+}
+
+/* Warning, sets ID->newid pointers of objects and collections, but does not clear them. */
+static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_collections)
+{
+ /* duplicate all the objects of the scene (and matching collections, if required). */
+ Collection *master_collection = BKE_collection_master(scene);
+ single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true);
+
+ /* duplicate collections that consist entirely of duplicated objects */
+ /* XXX I guess that was designed for calls from 'make single user' operator... But since copy_collection is
+ * always false then, was not doing anything. And that kind of behavior should be added at operator level,
+ * not in a utility function also used by rather different code... */
+#if 0
+ if (copy_collections) {
+ Collection *collection, *collectionn;
+ for (collection = bmain->collection.first; collection; collection = collection->id.next) {
bool all_duplicated = true;
+ bool any_duplicated = false;
- for (go = group->gobject.first; go; go = go->next) {
- if (!(go->ob && (go->ob->id.newid))) {
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ any_duplicated = true;
+ if (cob->ob->id.newid == NULL) {
all_duplicated = false;
break;
}
}
- if (all_duplicated) {
- groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group));
+ if (any_duplicated && all_duplicated) {
+ // TODO: test if this works, with child collections ..
+ collectionn = ID_NEW_SET(collection, BKE_collection_copy(bmain, NULL, collection));
- for (go = groupn->gobject.first; go; go = go->next) {
- go->ob = (Object *)go->ob->id.newid;
+ for (CollectionObject *cob = collectionn->gobject.first; cob; cob = cob->next) {
+ cob->ob = (Object *)cob->ob->id.newid;
}
}
}
}
+#endif
+
+ /* Collection and object pointers in collections */
+ libblock_relink_collection(master_collection);
- /* group pointers in scene */
+ /* collection pointers in scene */
BKE_scene_groups_relink(scene);
+ /* active camera */
ID_NEW_REMAP(scene->camera);
if (v3d) ID_NEW_REMAP(v3d->camera);
- /* object and group pointers */
- for (base = FIRSTBASE; base; base = base->next) {
- BKE_libblock_relink_to_newid(&base->object->id);
- }
-
- set_sca_new_poins();
+ BKE_scene_collection_sync(scene);
}
/* not an especially efficient function, only added so the single user
* button can be functional.*/
void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
{
- Base *base;
- const bool copy_groups = false;
-
- for (base = FIRSTBASE; base; base = base->next) {
- if (base->object == ob) base->flag |= OB_DONE;
- else base->flag &= ~OB_DONE;
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter)
+ {
+ ob_iter->flag &= ~OB_DONE;
}
+ FOREACH_SCENE_OBJECT_END;
- single_object_users(bmain, scene, NULL, OB_DONE, copy_groups);
+ /* tag only the one object */
+ ob->flag |= OB_DONE;
+ single_object_users(bmain, scene, NULL, OB_DONE, false);
BKE_main_id_clear_newpoins(bmain);
}
@@ -1844,34 +1754,26 @@ static void new_id_matar(Main *bmain, Material **matar, const int totcol)
}
}
-static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
+static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag)
{
- Object *ob;
Lamp *la;
Curve *cu;
/* Camera *cam; */
- Base *base;
Mesh *me;
Lattice *lat;
ID *id;
- int a;
- for (base = FIRSTBASE; base; base = base->next) {
- ob = base->object;
- if (!ID_IS_LINKED(ob) && (base->flag & flag) == flag) {
+ FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob)
+ {
+ if (!ID_IS_LINKED(ob)) {
id = ob->data;
if (id && id->us > 1 && !ID_IS_LINKED(id)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
switch (ob->type) {
case OB_LAMP:
ob->data = la = ID_NEW_SET(ob->data, BKE_lamp_copy(bmain, ob->data));
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a]) {
- ID_NEW_REMAP(la->mtex[a]->object);
- }
- }
break;
case OB_CAMERA:
ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data));
@@ -1900,16 +1802,25 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
BKE_animdata_copy_id_action(bmain, (ID *)lat->key, false);
break;
case OB_ARMATURE:
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data));
- BKE_pose_rebuild(ob, ob->data);
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
break;
case OB_SPEAKER:
ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data));
break;
+ case OB_LIGHTPROBE:
+ ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data));
+ break;
+ case OB_GPENCIL:
+ ob->data = ID_NEW_SET(ob->data, BKE_gpencil_copy(bmain, ob->data));
+ break;
default:
- if (G.debug & G_DEBUG)
- printf("ERROR %s: can't copy %s\n", __func__, id->name);
+ printf("ERROR %s: can't copy %s\n", __func__, id->name);
+ BLI_assert(!"This should never happen.");
+
+ /* We need to end the FOREACH_OBJECT_FLAG_BEGIN iterator to prevent memory leak. */
+ BKE_scene_objects_iterator_end(&iter_macro);
return;
}
@@ -1924,6 +1835,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
}
}
}
+ FOREACH_OBJECT_FLAG_END;
me = bmain->mesh.first;
while (me) {
@@ -1932,31 +1844,26 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
}
}
-static void single_object_action_users(Main *bmain, Scene *scene, const int flag)
+static void single_object_action_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag)
{
- Object *ob;
- Base *base;
-
- for (base = FIRSTBASE; base; base = base->next) {
- ob = base->object;
- if (!ID_IS_LINKED(ob) && (flag == 0 || (base->flag & SELECT)) ) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob)
+ {
+ if (!ID_IS_LINKED(ob)) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
BKE_animdata_copy_id_action(bmain, &ob->id, false);
}
}
+ FOREACH_OBJECT_FLAG_END;
}
-static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bool do_textures)
+static void single_mat_users(Main *bmain, Scene *scene, ViewLayer *view_layer, const int flag)
{
- Object *ob;
- Base *base;
Material *ma, *man;
- Tex *tex;
- int a, b;
+ int a;
- for (base = FIRSTBASE; base; base = base->next) {
- ob = base->object;
- if (!ID_IS_LINKED(ob) && (flag == 0 || (base->flag & SELECT)) ) {
+ FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, ob)
+ {
+ if (!ID_IS_LINKED(ob)) {
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
@@ -1968,84 +1875,12 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo
man->id.us = 0;
assign_material(bmain, ob, man, a, BKE_MAT_ASSIGN_USERPREF);
-
- if (do_textures) {
- for (b = 0; b < MAX_MTEX; b++) {
- if (ma->mtex[b] && (tex = ma->mtex[b]->tex)) {
- if (tex->id.us > 1) {
- id_us_min(&tex->id);
- tex = BKE_texture_copy(bmain, tex);
- BKE_animdata_copy_id_action(bmain, &tex->id, false);
- man->mtex[b]->tex = tex;
- }
- }
- }
- }
}
}
}
}
}
-}
-
-static void do_single_tex_user(Main *bmain, Tex **from)
-{
- Tex *tex, *texn;
-
- tex = *from;
- if (tex == NULL) return;
-
- if (tex->id.newid) {
- *from = (Tex *)tex->id.newid;
- id_us_plus(tex->id.newid);
- id_us_min(&tex->id);
- }
- else if (tex->id.us > 1) {
- texn = ID_NEW_SET(tex, BKE_texture_copy(bmain, tex));
- BKE_animdata_copy_id_action(bmain, &texn->id, false);
- tex->id.newid = (ID *)texn;
- id_us_min(&tex->id);
- *from = texn;
- }
-}
-
-static void single_tex_users_expand(Main *bmain)
-{
- /* only when 'parent' blocks are LIB_TAG_NEW */
- Material *ma;
- Lamp *la;
- World *wo;
- int b;
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->id.tag & LIB_TAG_NEW) {
- for (b = 0; b < MAX_MTEX; b++) {
- if (ma->mtex[b] && ma->mtex[b]->tex) {
- do_single_tex_user(bmain, &(ma->mtex[b]->tex));
- }
- }
- }
- }
-
- for (la = bmain->lamp.first; la; la = la->id.next) {
- if (la->id.tag & LIB_TAG_NEW) {
- for (b = 0; b < MAX_MTEX; b++) {
- if (la->mtex[b] && la->mtex[b]->tex) {
- do_single_tex_user(bmain, &(la->mtex[b]->tex));
- }
- }
- }
- }
-
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- if (wo->id.tag & LIB_TAG_NEW) {
- for (b = 0; b < MAX_MTEX; b++) {
- if (wo->mtex[b] && wo->mtex[b]->tex) {
- do_single_tex_user(bmain, &(wo->mtex[b]->tex));
- }
- }
- }
- }
+ FOREACH_OBJECT_FLAG_END;
}
static void single_mat_users_expand(Main *bmain)
@@ -2055,8 +1890,7 @@ static void single_mat_users_expand(Main *bmain)
Mesh *me;
Curve *cu;
MetaBall *mb;
- Material *ma;
- int a;
+ bGPdata *gpd;
for (ob = bmain->object.first; ob; ob = ob->id.next)
if (ob->id.tag & LIB_TAG_NEW)
@@ -2074,24 +1908,20 @@ static void single_mat_users_expand(Main *bmain)
if (mb->id.tag & LIB_TAG_NEW)
new_id_matar(bmain, mb->mat, mb->totcol);
- /* material imats */
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->id.tag & LIB_TAG_NEW)
- for (a = 0; a < MAX_MTEX; a++)
- if (ma->mtex[a])
- ID_NEW_REMAP(ma->mtex[a]->object);
+ for (gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next)
+ if (gpd->id.tag & LIB_TAG_NEW)
+ new_id_matar(bmain, gpd->mat, gpd->totcol);
}
/* used for copying scenes */
-void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_groups)
+void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_collections)
{
- single_object_users(bmain, scene, NULL, 0, copy_groups);
+ single_object_users(bmain, scene, NULL, 0, copy_collections);
if (full) {
- single_obdata_users(bmain, scene, 0);
- single_object_action_users(bmain, scene, 0);
+ single_obdata_users(bmain, scene, NULL, 0);
+ single_object_action_users(bmain, scene, NULL, 0);
single_mat_users_expand(bmain);
- single_tex_users_expand(bmain);
}
/* Relink nodetrees' pointers that have been duplicated. */
@@ -2110,12 +1940,13 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
{
IDP_RelinkProperty(scene->id.properties);
- for (Base *base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
+ {
if (!ID_IS_LINKED(ob)) {
IDP_RelinkProperty(ob->id.properties);
}
}
+ FOREACH_SCENE_OBJECT_END;
if (scene->nodetree) {
IDP_RelinkProperty(scene->nodetree->id.properties);
@@ -2124,10 +1955,6 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
}
}
- if (scene->gpd) {
- IDP_RelinkProperty(scene->gpd->id.properties);
- }
-
if (scene->world) {
IDP_RelinkProperty(scene->world->id.properties);
}
@@ -2137,7 +1964,7 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo
}
}
BKE_main_id_clear_newpoins(bmain);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
/******************************* Make Local ***********************************/
@@ -2204,7 +2031,7 @@ static void tag_localizable_objects(bContext *C, const int mode)
* Instance indirectly referenced zero user objects,
* otherwise they're lost on reload, see T40595.
*/
-static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
+static bool make_local_all__instance_indirect_unused(Main *bmain, ViewLayer *view_layer, Collection *collection)
{
Object *ob;
bool changed = false;
@@ -2215,10 +2042,11 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
id_us_plus(&ob->id);
- base = BKE_scene_base_add(scene, ob);
- base->flag |= SELECT;
- base->object->flag = base->flag;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ BKE_collection_object_add(bmain, collection, ob);
+ base = BKE_view_layer_base_find(view_layer, ob);
+ base->flag |= BASE_SELECTED;
+ BKE_scene_object_base_flag_sync_from_base(base);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
changed = true;
}
@@ -2235,9 +2063,6 @@ static void make_local_animdata_tag_strips(ListBase *strips)
if (strip->act) {
strip->act->id.tag &= ~LIB_TAG_PRE_EXISTING;
}
- if (strip->remap && strip->remap->target) {
- strip->remap->target->id.tag &= ~LIB_TAG_PRE_EXISTING;
- }
make_local_animdata_tag_strips(&strip->strips);
}
@@ -2254,10 +2079,6 @@ static void make_local_animdata_tag(AnimData *adt)
if (adt->tmpact) {
adt->tmpact->id.tag &= ~LIB_TAG_PRE_EXISTING;
}
- /* Remaps */
- if (adt->remap && adt->remap->target) {
- adt->remap->target->id.tag &= ~LIB_TAG_PRE_EXISTING;
- }
/* Drivers */
/* TODO: need to handle the ID-targets too? */
@@ -2276,33 +2097,28 @@ static void make_local_material_tag(Material *ma)
make_local_animdata_tag(BKE_animdata_from_id(&ma->id));
/* About nodetrees: root one is made local together with material, others we keep linked for now... */
-
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex) {
- ma->mtex[a]->tex->id.tag &= ~LIB_TAG_PRE_EXISTING;
- }
- }
}
}
static int make_local_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
ParticleSystem *psys;
Material *ma, ***matarar;
- Lamp *la;
const int mode = RNA_enum_get(op->ptr, "type");
int a;
/* Note: we (ab)use LIB_TAG_PRE_EXISTING to cherry pick which ID to make local... */
if (mode == MAKE_LOCAL_ALL) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Collection *collection = CTX_data_collection(C);
+
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- /* de-select so the user can differentiate newly instanced from existing objects */
- BKE_scene_base_deselect_all(scene);
+ /* De-select so the user can differentiate newly instanced from existing objects. */
+ BKE_view_layer_base_deselect_all(view_layer);
- if (make_local_all__instance_indirect_unused(bmain, scene)) {
+ if (make_local_all__instance_indirect_unused(bmain, view_layer, collection)) {
BKE_report(op->reports, RPT_INFO, "Orphan library objects added to the current scene to avoid loss");
}
}
@@ -2339,16 +2155,6 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
}
}
-
- if (ob->type == OB_LAMP) {
- BLI_assert(ob->data != NULL);
- la = ob->data;
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a] && la->mtex[a]->tex) {
- la->id.tag &= ~LIB_TAG_PRE_EXISTING;
- }
- }
- }
}
if (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL) && ob->data != NULL) {
@@ -2393,6 +2199,234 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
}
+
+static void make_override_static_tag_object(Object *obact, Object *ob)
+{
+ if (ob == obact) {
+ return;
+ }
+
+ if (!ID_IS_LINKED(ob)) {
+ return;
+ }
+
+ /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full 'automatic', generic
+ * handling of all this, will probably require adding some override-aware stuff to library_query code... */
+
+ if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) {
+ for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) {
+ if (md->type == eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData *)md;
+ if (amd->object == obact) {
+ ob->id.tag |= LIB_TAG_DOIT;
+ break;
+ }
+ }
+ }
+ }
+ else if (ob->parent == obact) {
+ ob->id.tag |= LIB_TAG_DOIT;
+ }
+
+ if (ob->id.tag & LIB_TAG_DOIT) {
+ printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name);
+ }
+}
+
+static void make_override_static_tag_collections(Collection *collection)
+{
+ collection->id.tag |= LIB_TAG_DOIT;
+ for (CollectionChild *coll_child = collection->children.first; coll_child != NULL; coll_child = coll_child->next) {
+ make_override_static_tag_collections(coll_child->collection);
+ }
+}
+
+/* Set the object to override. */
+static int make_override_static_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obact = ED_object_active_context(C);
+
+ /* Sanity checks. */
+ if (!scene || ID_IS_LINKED(scene) || !obact) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get object to work on - use a menu if we need to... */
+ if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) {
+ /* Gives menu with list of objects in group. */
+ WM_enum_search_invoke(C, op, event);
+ return OPERATOR_CANCELLED;
+ }
+ else if (ID_IS_LINKED(obact)) {
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ /* Create operator menu item with relevant properties filled in. */
+ PointerRNA opptr_dummy;
+ uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL,
+ WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy);
+
+ /* Present the menu and be done... */
+ UI_popup_menu_end(C, pup);
+
+ /* This invoke just calls another instance of this operator... */
+ return OPERATOR_INTERFACE;
+ }
+ else {
+ /* Error.. cannot continue. */
+ BKE_report(op->reports, RPT_ERROR, "Can only make static override for a referenced object or collection");
+ return OPERATOR_CANCELLED;
+ }
+
+}
+
+static int make_override_static_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *obact = CTX_data_active_object(C);
+
+ bool success = false;
+
+ if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) {
+ Object *obcollection = obact;
+ Collection *collection = obcollection->dup_group;
+
+ const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection);
+ Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object"));
+ obact = base->object;
+
+ /* First, we make a static override of the linked collection itself, and all its children. */
+ make_override_static_tag_collections(collection);
+
+ /* Then, we make static override of the whole set of objects in the Collection. */
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob)
+ {
+ ob->id.tag |= LIB_TAG_DOIT;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ /* Then, we remove (untag) bone shape objects, you shall never want to override those (hopefully)... */
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob)
+ {
+ if (ob->type == OB_ARMATURE && ob->pose != NULL) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ if (pchan->custom != NULL) {
+ pchan->custom->id.tag &= ~ LIB_TAG_DOIT;
+ }
+ }
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ success = BKE_override_static_create_from_tag(bmain);
+
+ /* Instantiate our newly overridden objects in scene, if not yet done. */
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Collection *new_collection = (Collection *)collection->id.newid;
+
+ BKE_collection_child_add(bmain, scene->master_collection, new_collection);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(new_collection, new_ob)
+ {
+ if (new_ob != NULL && new_ob->id.override_static != NULL) {
+ if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) {
+ BKE_collection_object_add_from(bmain, scene, obcollection, new_ob);
+ base = BKE_view_layer_base_find(view_layer, new_ob);
+ DEG_id_tag_update_ex(bmain, &new_ob->id, DEG_TAG_TRANSFORM | DEG_TAG_BASE_FLAGS_UPDATE);
+ }
+ /* parent to 'collection' empty */
+ if (new_ob->parent == NULL) {
+ new_ob->parent = obcollection;
+ }
+ if (new_ob == (Object *)obact->id.newid) {
+ /* TODO: is setting active needed? */
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+ }
+ else {
+ /* Disable auto-override tags for non-active objects, will help with performaces... */
+ new_ob->id.override_static->flag &= ~STATICOVERRIDE_AUTO;
+ }
+ /* We still want to store all objects' current override status (i.e. change of parent). */
+ BKE_override_static_operations_create(bmain, &new_ob->id, true);
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ /* obcollection is no more duplicollection-ing, it merely parents whole collection of overriding instantiated objects. */
+ obcollection->dup_group = NULL;
+
+ /* Also, we'd likely want to lock by default things like transformations of implicitly overridden objects? */
+
+ DEG_id_tag_update(&scene->id, 0);
+
+ /* Cleanup. */
+ BKE_main_id_clear_newpoins(bmain);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false);
+ }
+ /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
+ else if (obact->type == OB_ARMATURE) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+ obact->id.tag |= LIB_TAG_DOIT;
+
+ for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) {
+ make_override_static_tag_object(obact, ob);
+ }
+
+ success = BKE_override_static_create_from_tag(bmain);
+
+ /* Also, we'd likely want to lock by default things like transformations of implicitly overridden objects? */
+
+ /* Cleanup. */
+ BKE_main_id_clear_newpoins(bmain);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false);
+ }
+ /* TODO: probably more cases where we want to do automated smart things in the future! */
+ else {
+ success = (BKE_override_static_create_from_id(bmain, &obact->id) != NULL);
+ }
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+static bool make_override_static_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ /* Object must be directly linked to be overridable. */
+ return (BKE_override_static_is_enabled() &&
+ ED_operator_objectmode(C) && obact != NULL &&
+ ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) ||
+ (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group))));
+}
+
+void OBJECT_OT_make_override_static(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Static Override";
+ ot->description = "Make local override of this library linked data-block";
+ ot->idname = "OBJECT_OT_make_override_static";
+
+ /* api callbacks */
+ ot->invoke = make_override_static_invoke;
+ ot->exec = make_override_static_exec;
+ ot->poll = make_override_static_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Override Object",
+ "Name of lib-linked/collection object to make an override from");
+ RNA_def_enum_funcs(prop, proxy_collection_object_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
+}
+
enum {
MAKE_SINGLE_USER_ALL = 1,
MAKE_SINGLE_USER_SELECTED = 2,
@@ -2402,32 +2436,35 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */
const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0;
- const bool copy_groups = false;
+ const bool copy_collections = false;
bool update_deps = false;
if (RNA_boolean_get(op->ptr, "object")) {
- single_object_users(bmain, scene, v3d, flag, copy_groups);
+ if (flag == SELECT) {
+ BKE_view_layer_selected_objects_tag(view_layer, OB_DONE);
+ single_object_users(bmain, scene, v3d, OB_DONE, copy_collections);
+ }
+ else {
+ single_object_users(bmain, scene, v3d, 0, copy_collections);
+ }
/* needed since object relationships may have changed */
update_deps = true;
}
if (RNA_boolean_get(op->ptr, "obdata")) {
- single_obdata_users(bmain, scene, flag);
+ single_obdata_users(bmain, scene, view_layer, flag);
}
if (RNA_boolean_get(op->ptr, "material")) {
- single_mat_users(bmain, scene, flag, RNA_boolean_get(op->ptr, "texture"));
+ single_mat_users(bmain, scene, view_layer, flag);
}
-#if 0 /* can't do this separate from materials */
- if (RNA_boolean_get(op->ptr, "texture"))
- single_mat_users(scene, flag, true);
-#endif
if (RNA_boolean_get(op->ptr, "animation")) {
- single_object_action_users(bmain, scene, flag);
+ single_object_action_users(bmain, scene, view_layer, flag);
}
BKE_main_id_clear_newpoins(bmain);
@@ -2435,7 +2472,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
if (update_deps) {
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
return OPERATOR_FINISHED;
@@ -2467,8 +2504,6 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects");
RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data");
RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each data-block");
- RNA_def_boolean(ot->srna, "texture", 0, "Textures",
- "Make textures local to each material (needs 'Materials' to be set too)");
RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
}
@@ -2486,7 +2521,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
assign_material(CTX_data_main(C), base->object, ma, 1, BKE_MAT_ASSIGN_USERPREF);
- DAG_id_tag_update(&base->object->id, OB_RECALC_OB);
+ DEG_id_tag_update(&base->object->id, OB_RECALC_OB);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, base->object);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 2fc6207d6c1..7c03e93f4b2 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -34,15 +34,17 @@
#include <string.h>
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
-#include "DNA_property_types.h"
#include "DNA_scene_types.h"
#include "DNA_armature_types.h"
#include "DNA_lamp_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
+#include "BLI_math_bits.h"
#include "BLI_listbase.h"
#include "BLI_rand.h"
#include "BLI_string_utils.h"
@@ -50,22 +52,31 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_group.h"
+#include "BKE_deform.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_particle.h"
-#include "BKE_property.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_library.h"
-#include "BKE_deform.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_armature.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_keyframing.h"
#include "UI_interface.h"
@@ -83,40 +94,280 @@
* this takes into account the 'restrict selection in 3d view' flag.
* deselect works always, the restriction just prevents selection */
-/* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or
- * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */
+ /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or
+ * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */
-void ED_base_object_select(Base *base, short mode)
+void ED_object_base_select(Base *base, eObjectSelect_Mode mode)
{
+ if (mode == BA_INVERT) {
+ mode = (base->flag & BASE_SELECTED) != 0 ? BA_DESELECT : BA_SELECT;
+ }
+
if (base) {
- if (mode == BA_SELECT) {
- if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
- base->flag |= SELECT;
- }
- else if (mode == BA_DESELECT) {
- base->flag &= ~SELECT;
+ switch (mode) {
+ case BA_SELECT:
+ if ((base->flag & BASE_SELECTABLE) != 0) {
+ base->flag |= BASE_SELECTED;
+ }
+ break;
+ case BA_DESELECT:
+ base->flag &= ~BASE_SELECTED;
+ break;
+ case BA_INVERT:
+ /* Never happens. */
+ break;
}
- base->object->flag = base->flag;
+ BKE_scene_object_base_flag_sync_from_base(base);
}
}
-/* also to set active NULL */
-void ED_base_object_activate(bContext *C, Base *base)
+/**
+ * Change active base, it includes the notifier
+ */
+void ED_object_base_activate(bContext *C, Base *base)
{
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ view_layer->basact = base;
- /* sets scene->basact */
- BASACT = base;
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_SELECT_UPDATE);
+}
- if (base) {
+bool ED_object_base_deselect_all_ex(ViewLayer *view_layer, View3D *v3d, int action, bool *r_any_visible)
+{
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+ FOREACH_VISIBLE_BASE_BEGIN(view_layer, v3d, base) {
+ if (v3d && ((v3d->object_type_exclude_select & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ if ((base->flag & BASE_SELECTED) != 0) {
+ action = SEL_DESELECT;
+ break;
+ }
+ }
+ FOREACH_VISIBLE_BASE_END;
+ }
+
+ bool any_visible = false;
+ bool changed = false;
+ FOREACH_VISIBLE_BASE_BEGIN(view_layer, v3d, base) {
+ if (v3d && ((v3d->object_type_exclude_select & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ switch (action) {
+ case SEL_SELECT:
+ if ((base->flag & BASE_SELECTED) == 0) {
+ ED_object_base_select(base, BA_SELECT);
+ changed = true;
+ }
+ break;
+ case SEL_DESELECT:
+ if ((base->flag & BASE_SELECTED) != 0) {
+ ED_object_base_select(base, BA_DESELECT);
+ changed = true;
+ }
+ break;
+ case SEL_INVERT:
+ if ((base->flag & BASE_SELECTED) != 0) {
+ ED_object_base_select(base, BA_DESELECT);
+ changed = true;
+ }
+ else {
+ ED_object_base_select(base, BA_SELECT);
+ changed = true;
+ }
+ break;
+ }
+ any_visible = true;
+ }
+ FOREACH_VISIBLE_BASE_END;
+ if (r_any_visible) {
+ *r_any_visible = any_visible;
+ }
+ return changed;
+}
- /* XXX old signals, remember to handle notifiers now! */
- // select_actionchannel_by_name(base->object->action, "Object", 1);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+bool ED_object_base_deselect_all(ViewLayer *view_layer, View3D *v3d, int action)
+{
+ return ED_object_base_deselect_all_ex(view_layer, v3d, action, NULL);
+}
+
+/********************** Jump To Object Utilities **********************/
+
+static int get_base_select_priority(Base *base)
+{
+ if (base->flag & BASE_VISIBLE) {
+ if (base->flag & BASE_SELECTABLE) {
+ return 3;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
}
- else
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, NULL);
+}
+
+/**
+ * If id is not already an Object, try to find an object that uses it as data.
+ * Prefers active, then selected, then visible/selectable.
+ */
+Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
+{
+ BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
+
+ /* Try active object. */
+ Base *basact = view_layer->basact;
+
+ if (basact && basact->object && basact->object->data == id) {
+ return basact;
+ }
+
+ /* Try all objects. */
+ Base *base_best = NULL;
+ int priority_best = 0;
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object && base->object->data == id) {
+ if (base->flag & BASE_SELECTED) {
+ return base;
+ }
+ else {
+ int priority_test = get_base_select_priority(base);
+
+ if (priority_test > priority_best) {
+ priority_best = priority_test;
+ base_best = base;
+ }
+ }
+ }
+ }
+
+ return base_best;
+}
+
+/**
+ * Select and make the target object active in the view layer.
+ * If already selected, selection isn't changed.
+ *
+ * \returns false if not found in current view layer
+ */
+bool ED_object_jump_to_object(
+ bContext *C, Object *ob, const bool UNUSED(reveal_hidden))
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (base == NULL) {
+ return false;
+ }
+
+ /* TODO, use 'reveal_hidden', as is done with bones. */
+
+ if (view_layer->basact != base || !(base->flag & BASE_SELECTED)) {
+ /* Select if not selected. */
+ if (!(base->flag & BASE_SELECTED)) {
+ ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT);
+
+ if (base->flag & BASE_VISIBLE) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ }
+
+ /* Make active if not active. */
+ ED_object_base_activate(C, base);
+ }
+
+ return true;
+}
+
+/**
+ * Select and make the target object and bone active.
+ * Switches to Pose mode if in Object mode so the selection is visible.
+ * Unhides the target bone and bone layer if necessary.
+ *
+ * \returns false if object not in layer, bone not found, or other error
+ */
+bool ED_object_jump_to_bone(
+ bContext *C, Object *ob, const char *bone_name,
+ const bool reveal_hidden)
+{
+ /* Verify it's a valid armature object. */
+ if (ob == NULL || ob->type != OB_ARMATURE) {
+ return false;
+ }
+
+ bArmature *arm = ob->data;
+
+ /* Activate the armature object. */
+ if (!ED_object_jump_to_object(C, ob, reveal_hidden)) {
+ return false;
+ }
+
+ /* Switch to pose mode from object mode. */
+ if (!ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_POSE)) {
+ ED_object_mode_set(C, OB_MODE_POSE);
+ }
+
+ if (ob->mode == OB_MODE_EDIT && arm->edbo != NULL) {
+ /* In Edit mode select and activate the target Edit-Bone. */
+ EditBone *ebone = ED_armature_ebone_find_name(arm->edbo, bone_name);
+ if (ebone != NULL) {
+ if (reveal_hidden) {
+ /* Unhide the bone. */
+ ebone->flag &= ~BONE_HIDDEN_A;
+
+ if ((arm->layer & ebone->layer) == 0) {
+ arm->layer |= 1U << bitscan_forward_uint(ebone->layer);
+ }
+ }
+
+ /* Select it. */
+ ED_armature_edit_deselect_all(ob);
+
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ ED_armature_ebone_select_set(ebone, true);
+ ED_armature_edit_sync_selection(arm->edbo);
+ }
+
+ arm->act_edbone = ebone;
+
+ ED_pose_bone_select_tag_update(ob);
+ return true;
+ }
+ }
+ else if (ob->mode == OB_MODE_POSE && ob->pose != NULL) {
+ /* In Pose mode select and activate the target Bone/Pose-Channel. */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (pchan != NULL) {
+ if (reveal_hidden) {
+ /* Unhide the bone. */
+ pchan->bone->flag &= ~BONE_HIDDEN_P;
+
+ if ((arm->layer & pchan->bone->layer) == 0) {
+ arm->layer |= 1U << bitscan_forward_uint(pchan->bone->layer);
+ }
+ }
+
+ /* Select it. */
+ ED_pose_deselect_all(ob, SEL_DESELECT, true);
+ ED_pose_bone_select(ob, pchan, true);
+
+ arm->act_bone = pchan->bone;
+
+ ED_pose_bone_select_tag_update(ob);
+ return true;
+ }
+ }
+
+ return false;
}
/********************** Selection Operators **********************/
@@ -139,28 +390,28 @@ static bool objects_selectable_poll(bContext *C)
static int object_select_by_type_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
short obtype, extend;
obtype = RNA_enum_get(op->ptr, "type");
extend = RNA_boolean_get(op->ptr, "extend");
if (extend == 0) {
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- ED_base_object_select(base, BA_DESELECT);
- }
- CTX_DATA_END;
+ ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT);
}
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
if (base->object->type == obtype) {
- ED_base_object_select(base, BA_SELECT);
+ ED_object_base_select(base, BA_SELECT);
}
}
CTX_DATA_END;
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
@@ -191,7 +442,6 @@ enum {
OBJECT_SELECT_LINKED_IPO = 1,
OBJECT_SELECT_LINKED_OBDATA,
OBJECT_SELECT_LINKED_MATERIAL,
- OBJECT_SELECT_LINKED_TEXTURE,
OBJECT_SELECT_LINKED_DUPGROUP,
OBJECT_SELECT_LINKED_PARTICLE,
OBJECT_SELECT_LINKED_LIBRARY,
@@ -202,7 +452,6 @@ static const EnumPropertyItem prop_select_linked_types[] = {
//{OBJECT_SELECT_LINKED_IPO, "IPO", 0, "Object IPO", ""}, // XXX deprecated animation system stuff...
{OBJECT_SELECT_LINKED_OBDATA, "OBDATA", 0, "Object Data", ""},
{OBJECT_SELECT_LINKED_MATERIAL, "MATERIAL", 0, "Material", ""},
- {OBJECT_SELECT_LINKED_TEXTURE, "TEXTURE", 0, "Texture", ""},
{OBJECT_SELECT_LINKED_DUPGROUP, "DUPGROUP", 0, "Dupligroup", ""},
{OBJECT_SELECT_LINKED_PARTICLE, "PARTICLE", 0, "Particle System", ""},
{OBJECT_SELECT_LINKED_LIBRARY, "LIBRARY", 0, "Library", ""},
@@ -210,38 +459,15 @@ static const EnumPropertyItem prop_select_linked_types[] = {
{0, NULL, 0, NULL, NULL}
};
-// XXX old animation system
-#if 0
-static int object_select_all_by_ipo(bContext *C, Ipo *ipo)
-{
- bool changed = false;
-
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- if (base->object->ipo == ipo) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
-
- changed = true;
- }
- }
- CTX_DATA_END;
-
- return changed;
-}
-#endif
-
static bool object_select_all_by_obdata(bContext *C, void *obdata)
{
bool changed = false;
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if ((base->flag & SELECT) == 0) {
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
if (base->object->data == obdata) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
-
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -251,40 +477,25 @@ static bool object_select_all_by_obdata(bContext *C, void *obdata)
return changed;
}
-static bool object_select_all_by_material_texture(bContext *C, int use_texture, Material *mat, Tex *tex)
+static bool object_select_all_by_material(bContext *C, Material *mat)
{
bool changed = false;
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if ((base->flag & SELECT) == 0) {
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
Object *ob = base->object;
Material *mat1;
- int a, b;
+ int a;
for (a = 1; a <= ob->totcol; a++) {
mat1 = give_current_material(ob, a);
- if (!use_texture) {
- if (mat1 == mat) {
- base->flag |= SELECT;
- changed = true;
- }
- }
- else if (mat1 && use_texture) {
- for (b = 0; b < MAX_MTEX; b++) {
- if (mat1->mtex[b]) {
- if (tex == mat1->mtex[b]->tex) {
- base->flag |= SELECT;
- changed = true;
- break;
- }
- }
- }
+ if (mat1 == mat) {
+ ED_object_base_select(base, BA_SELECT);
+ changed = true;
}
}
-
- base->object->flag = base->flag;
}
}
CTX_DATA_END;
@@ -295,16 +506,14 @@ static bool object_select_all_by_material_texture(bContext *C, int use_texture,
static bool object_select_all_by_dup_group(bContext *C, Object *ob)
{
bool changed = false;
- Group *dup_group = (ob->transflag & OB_DUPLIGROUP) ? ob->dup_group : NULL;
+ Collection *dup_group = (ob->transflag & OB_DUPLICOLLECTION) ? ob->dup_group : NULL;
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if ((base->flag & SELECT) == 0) {
- Group *dup_group_other = (base->object->transflag & OB_DUPLIGROUP) ? base->object->dup_group : NULL;
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
+ Collection *dup_group_other = (base->object->transflag & OB_DUPLICOLLECTION) ? base->object->dup_group : NULL;
if (dup_group == dup_group_other) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
-
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -321,23 +530,21 @@ static bool object_select_all_by_particle(bContext *C, Object *ob)
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if ((base->flag & SELECT) == 0) {
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
/* loop through other particles*/
ParticleSystem *psys;
for (psys = base->object->particlesystem.first; psys; psys = psys->next) {
if (psys->part == psys_act->part) {
- base->flag |= SELECT;
+ ED_object_base_select(base, BA_SELECT);
changed = true;
break;
}
- if (base->flag & SELECT) {
+ if (base->flag & BASE_SELECTED) {
break;
}
}
-
- base->object->flag = base->flag;
}
}
CTX_DATA_END;
@@ -351,11 +558,9 @@ static bool object_select_all_by_library(bContext *C, Library *lib)
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if ((base->flag & SELECT) == 0) {
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
if (lib == base->object->id.lib) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
-
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -371,11 +576,9 @@ static bool object_select_all_by_library_obdata(bContext *C, Library *lib)
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if ((base->flag & SELECT) == 0) {
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
if (base->object->data && lib == ((ID *)base->object->data)->lib) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
-
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -394,20 +597,24 @@ void ED_object_select_linked_by_id(bContext *C, ID *id)
changed = object_select_all_by_obdata(C, id);
}
else if (idtype == ID_MA) {
- changed = object_select_all_by_material_texture(C, false, (Material *)id, NULL);
+ changed = object_select_all_by_material(C, (Material *)id);
}
else if (idtype == ID_LI) {
changed = object_select_all_by_library(C, (Library *) id);
}
if (changed) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
}
static int object_select_linked_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
Object *ob;
int nr = RNA_enum_get(op->ptr, "type");
bool changed = false, extend;
@@ -415,14 +622,10 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
extend = RNA_boolean_get(op->ptr, "extend");
if (extend == 0) {
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- ED_base_object_select(base, BA_DESELECT);
- }
- CTX_DATA_END;
+ ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT);
}
- ob = OBACT;
+ ob = OBACT(view_layer);
if (ob == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active object");
return OPERATOR_CANCELLED;
@@ -440,21 +643,13 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
changed = object_select_all_by_obdata(C, ob->data);
}
- else if (nr == OBJECT_SELECT_LINKED_MATERIAL || nr == OBJECT_SELECT_LINKED_TEXTURE) {
+ else if (nr == OBJECT_SELECT_LINKED_MATERIAL) {
Material *mat = NULL;
- Tex *tex = NULL;
- bool use_texture = false;
mat = give_current_material(ob, ob->actcol);
if (mat == NULL) return OPERATOR_CANCELLED;
- if (nr == OBJECT_SELECT_LINKED_TEXTURE) {
- use_texture = true;
- if (mat->mtex[(int)mat->texact]) tex = mat->mtex[(int)mat->texact]->tex;
- if (tex == NULL) return OPERATOR_CANCELLED;
- }
-
- changed = object_select_all_by_material_texture(C, use_texture, mat, tex);
+ changed = object_select_all_by_material(C, mat);
}
else if (nr == OBJECT_SELECT_LINKED_DUPGROUP) {
if (ob->dup_group == NULL)
@@ -482,6 +677,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
if (changed) {
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
@@ -517,14 +713,12 @@ enum {
OBJECT_GRPSEL_PARENT = 2,
OBJECT_GRPSEL_SIBLINGS = 3,
OBJECT_GRPSEL_TYPE = 4,
- OBJECT_GRPSEL_LAYER = 5,
- OBJECT_GRPSEL_GROUP = 6,
+ OBJECT_GRPSEL_COLLECTION = 5,
OBJECT_GRPSEL_HOOK = 7,
OBJECT_GRPSEL_PASS = 8,
OBJECT_GRPSEL_COLOR = 9,
- OBJECT_GRPSEL_PROPERTIES = 10,
- OBJECT_GRPSEL_KEYINGSET = 11,
- OBJECT_GRPSEL_LAMP_TYPE = 12,
+ OBJECT_GRPSEL_KEYINGSET = 10,
+ OBJECT_GRPSEL_LIGHT_TYPE = 11,
};
static const EnumPropertyItem prop_select_grouped_types[] = {
@@ -533,14 +727,12 @@ static const EnumPropertyItem prop_select_grouped_types[] = {
{OBJECT_GRPSEL_PARENT, "PARENT", 0, "Parent", ""},
{OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"},
{OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"},
- {OBJECT_GRPSEL_LAYER, "LAYER", 0, "Layer", "Shared layers"},
- {OBJECT_GRPSEL_GROUP, "GROUP", 0, "Group", "Shared group"},
+ {OBJECT_GRPSEL_COLLECTION, "COLLECTION", 0, "Collection", "Shared collection"},
{OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""},
{OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"},
{OBJECT_GRPSEL_COLOR, "COLOR", 0, "Color", "Object Color"},
- {OBJECT_GRPSEL_PROPERTIES, "PROPERTIES", 0, "Properties", "Game Properties"},
{OBJECT_GRPSEL_KEYINGSET, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"},
- {OBJECT_GRPSEL_LAMP_TYPE, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"},
+ {OBJECT_GRPSEL_LIGHT_TYPE, "LIGHT_TYPE", 0, "Light Type", "Matching light types"},
{0, NULL, 0, NULL, NULL}
};
@@ -551,13 +743,14 @@ static bool select_grouped_children(bContext *C, Object *ob, const bool recursiv
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
if (ob == base->object->parent) {
- if (!(base->flag & SELECT)) {
- ED_base_object_select(base, BA_SELECT);
+ if ((base->flag & BASE_SELECTED) == 0) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
- if (recursive)
+ if (recursive) {
changed |= select_grouped_children(C, base->object, 1);
+ }
}
}
CTX_DATA_END;
@@ -566,51 +759,54 @@ static bool select_grouped_children(bContext *C, Object *ob, const bool recursiv
static bool select_grouped_parent(bContext *C) /* Makes parent active and de-selected OBACT */
{
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
-
- bool changed = false;
Base *baspar, *basact = CTX_data_active_base(C);
+ bool changed = false;
- if (!basact || !(basact->object->parent)) return 0; /* we know OBACT is valid */
+ if (!basact || !(basact->object->parent)) {
+ return 0; /* we know OBACT is valid */
+ }
- baspar = BKE_scene_base_find(scene, basact->object->parent);
+ baspar = BKE_view_layer_base_find(view_layer, basact->object->parent);
/* can be NULL if parent in other scene */
if (baspar && BASE_SELECTABLE(v3d, baspar)) {
- ED_base_object_select(baspar, BA_SELECT);
- ED_base_object_activate(C, baspar);
+ ED_object_base_select(baspar, BA_SELECT);
+ ED_object_base_activate(C, baspar);
changed = true;
}
return changed;
}
-#define GROUP_MENU_MAX 24
-static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in the same group as the active */
+#define COLLECTION_MENU_MAX 24
+static bool select_grouped_collection(bContext *C, Object *ob) /* Select objects in the same group as the active */
{
bool changed = false;
- Group *group, *ob_groups[GROUP_MENU_MAX];
- int group_count = 0, i;
+ Collection *collection, *ob_collections[COLLECTION_MENU_MAX];
+ int collection_count = 0, i;
uiPopupMenu *pup;
uiLayout *layout;
- for (group = CTX_data_main(C)->group.first; group && group_count < GROUP_MENU_MAX; group = group->id.next) {
- if (BKE_group_object_exists(group, ob)) {
- ob_groups[group_count] = group;
- group_count++;
+ for (collection = CTX_data_main(C)->collection.first; collection && collection_count < COLLECTION_MENU_MAX; collection = collection->id.next) {
+ if (BKE_collection_has_object(collection, ob)) {
+ ob_collections[collection_count] = collection;
+ collection_count++;
}
}
- if (!group_count)
+ if (!collection_count)
return 0;
- else if (group_count == 1) {
- group = ob_groups[0];
+ else if (collection_count == 1) {
+ collection = ob_collections[0];
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) {
- ED_base_object_select(base, BA_SELECT);
- changed = true;
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
+ if (BKE_collection_has_object(collection, base->object)) {
+ ED_object_base_select(base, BA_SELECT);
+ changed = true;
+ }
}
}
CTX_DATA_END;
@@ -618,12 +814,12 @@ static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in
}
/* build the menu. */
- pup = UI_popup_menu_begin(C, IFACE_("Select Group"), ICON_NONE);
+ pup = UI_popup_menu_begin(C, IFACE_("Select Collection"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
- for (i = 0; i < group_count; i++) {
- group = ob_groups[i];
- uiItemStringO(layout, group->id.name + 2, 0, "OBJECT_OT_select_same_group", "group", group->id.name + 2);
+ for (i = 0; i < collection_count; i++) {
+ collection = ob_collections[i];
+ uiItemStringO(layout, collection->id.name + 2, 0, "OBJECT_OT_select_same_collection", "collection", collection->id.name + 2);
}
UI_popup_menu_end(C, pup);
@@ -632,7 +828,7 @@ static bool select_grouped_group(bContext *C, Object *ob) /* Select objects in
static bool select_grouped_object_hooks(bContext *C, Object *ob)
{
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
bool changed = false;
@@ -643,10 +839,10 @@ static bool select_grouped_object_hooks(bContext *C, Object *ob)
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Hook) {
hmd = (HookModifierData *) md;
- if (hmd->object && !(hmd->object->flag & SELECT)) {
- base = BKE_scene_base_find(scene, hmd->object);
- if (base && (BASE_SELECTABLE(v3d, base))) {
- ED_base_object_select(base, BA_SELECT);
+ if (hmd->object) {
+ base = BKE_view_layer_base_find(view_layer, hmd->object);
+ if (base && ((base->flag & BASE_SELECTED) == 0) && (BASE_SELECTABLE(v3d, base))) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -663,8 +859,8 @@ static bool select_grouped_siblings(bContext *C, Object *ob)
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
- if ((base->object->parent == ob->parent) && !(base->flag & SELECT)) {
- ED_base_object_select(base, BA_SELECT);
+ if ((base->object->parent == ob->parent) && ((base->flag & BASE_SELECTED) == 0)) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -681,8 +877,8 @@ static bool select_grouped_lamptype(bContext *C, Object *ob)
{
if (base->object->type == OB_LAMP) {
Lamp *la_test = base->object->data;
- if ((la->type == la_test->type) && !(base->flag & SELECT)) {
- ED_base_object_select(base, BA_SELECT);
+ if ((la->type == la_test->type) && ((base->flag & BASE_SELECTED) == 0)) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -696,23 +892,8 @@ static bool select_grouped_type(bContext *C, Object *ob)
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
- if ((base->object->type == ob->type) && !(base->flag & SELECT)) {
- ED_base_object_select(base, BA_SELECT);
- changed = true;
- }
- }
- CTX_DATA_END;
- return changed;
-}
-
-static bool select_grouped_layer(bContext *C, Object *ob)
-{
- bool changed = false;
-
- CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
- {
- if ((base->lay & ob->lay) && !(base->flag & SELECT)) {
- ED_base_object_select(base, BA_SELECT);
+ if ((base->object->type == ob->type) && ((base->flag & BASE_SELECTED) == 0)) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -726,8 +907,8 @@ static bool select_grouped_index_object(bContext *C, Object *ob)
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
- if ((base->object->index == ob->index) && !(base->flag & SELECT)) {
- ED_base_object_select(base, BA_SELECT);
+ if ((base->object->index == ob->index) && ((base->flag & BASE_SELECTED) == 0)) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -741,35 +922,8 @@ static bool select_grouped_color(bContext *C, Object *ob)
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
- if (!(base->flag & SELECT) && (compare_v3v3(base->object->col, ob->col, 0.005f))) {
- ED_base_object_select(base, BA_SELECT);
- changed = true;
- }
- }
- CTX_DATA_END;
- return changed;
-}
-
-static bool objects_share_gameprop(Object *a, Object *b)
-{
- bProperty *prop;
-
- for (prop = a->prop.first; prop; prop = prop->next) {
- if (BKE_bproperty_object_get(b, prop->name)) {
- return 1;
- }
- }
- return 0;
-}
-
-static bool select_grouped_gameprops(bContext *C, Object *ob)
-{
- bool changed = false;
-
- CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
- {
- if (!(base->flag & SELECT) && (objects_share_gameprop(base->object, ob))) {
- ED_base_object_select(base, BA_SELECT);
+ if (((base->flag & BASE_SELECTED) == 0) && (compare_v3v3(base->object->col, ob->col, 0.005f))) {
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -807,7 +961,7 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
/* only check for this object if it isn't selected already, to limit time wasted */
- if ((base->flag & SELECT) == 0) {
+ if ((base->flag & BASE_SELECTED) == 0) {
KS_Path *ksp;
/* this is the slow way... we could end up with > 500 items here,
@@ -816,7 +970,7 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList
for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
/* if id matches, select then stop looping (match found) */
if (ksp->id == (ID *)base->object) {
- ED_base_object_select(base, BA_SELECT);
+ ED_object_base_select(base, BA_SELECT);
changed = true;
break;
}
@@ -831,6 +985,8 @@ static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList
static int object_select_grouped_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
Object *ob;
const int type = RNA_enum_get(op->ptr, "type");
bool changed = false, extend;
@@ -838,15 +994,10 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
extend = RNA_boolean_get(op->ptr, "extend");
if (extend == 0) {
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- ED_base_object_select(base, BA_DESELECT);
- changed = true;
- }
- CTX_DATA_END;
+ changed = ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT);
}
- ob = OBACT;
+ ob = OBACT(view_layer);
if (ob == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active object");
return OPERATOR_CANCELLED;
@@ -868,11 +1019,8 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
case OBJECT_GRPSEL_TYPE:
changed |= select_grouped_type(C, ob);
break;
- case OBJECT_GRPSEL_LAYER:
- changed |= select_grouped_layer(C, ob);
- break;
- case OBJECT_GRPSEL_GROUP:
- changed |= select_grouped_group(C, ob);
+ case OBJECT_GRPSEL_COLLECTION:
+ changed |= select_grouped_collection(C, ob);
break;
case OBJECT_GRPSEL_HOOK:
changed |= select_grouped_object_hooks(C, ob);
@@ -883,15 +1031,12 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
case OBJECT_GRPSEL_COLOR:
changed |= select_grouped_color(C, ob);
break;
- case OBJECT_GRPSEL_PROPERTIES:
- changed |= select_grouped_gameprops(C, ob);
- break;
case OBJECT_GRPSEL_KEYINGSET:
changed |= select_grouped_keyingset(C, ob, op->reports);
break;
- case OBJECT_GRPSEL_LAMP_TYPE:
+ case OBJECT_GRPSEL_LIGHT_TYPE:
if (ob->type != OB_LAMP) {
- BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp");
+ BKE_report(op->reports, RPT_ERROR, "Active object must be a light");
break;
}
changed |= select_grouped_lamptype(C, ob);
@@ -901,6 +1046,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
}
if (changed) {
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
@@ -928,130 +1074,32 @@ void OBJECT_OT_select_grouped(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
}
-/************************* Select by Layer **********************/
-enum {
- OB_SEL_LAYERMATCH_EXACT = 1,
- OB_SEL_LAYERMATCH_SHARED = 2,
-};
-
-static int object_select_by_layer_exec(bContext *C, wmOperator *op)
-{
- unsigned int layernum;
- bool extend;
- int match;
-
- extend = RNA_boolean_get(op->ptr, "extend");
- layernum = RNA_int_get(op->ptr, "layers");
- match = RNA_enum_get(op->ptr, "match");
-
- if (extend == false) {
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- ED_base_object_select(base, BA_DESELECT);
- }
- CTX_DATA_END;
- }
-
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- bool ok = false;
-
- switch (match) {
- case OB_SEL_LAYERMATCH_EXACT:
- /* Mask out bits used for local view, only work on real layer ones, see T45783. */
- ok = ((base->lay & ((1 << 20) - 1)) == (1 << (layernum - 1)));
- break;
- case OB_SEL_LAYERMATCH_SHARED:
- ok = (base->lay & (1 << (layernum - 1))) != 0;
- break;
- default:
- break;
- }
-
- if (ok) {
- ED_base_object_select(base, BA_SELECT);
- }
- }
- CTX_DATA_END;
-
- /* undo? */
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
-
- return OPERATOR_FINISHED;
-}
-
-void OBJECT_OT_select_by_layer(wmOperatorType *ot)
-{
- static const EnumPropertyItem match_items[] = {
- {OB_SEL_LAYERMATCH_EXACT, "EXACT", 0, "Exact Match", ""},
- {OB_SEL_LAYERMATCH_SHARED, "SHARED", 0, "Shared Layers", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Select by Layer";
- ot->description = "Select all visible objects on a layer";
- ot->idname = "OBJECT_OT_select_by_layer";
-
- /* api callbacks */
- /*ot->invoke = XXX - need a int grid popup*/
- ot->exec = object_select_by_layer_exec;
- ot->poll = objects_selectable_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "match", match_items, OB_SEL_LAYERMATCH_EXACT, "Match", "");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
- RNA_def_int(ot->srna, "layers", 1, 1, 20, "Layer", "", 1, 20);
-}
-
/**************************** (De)select All ****************************/
static int object_select_all_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
int action = RNA_enum_get(op->ptr, "action");
+ bool any_visible = false;
- /* passthrough if no objects are visible */
- if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
+ bool changed = ED_object_base_deselect_all_ex(view_layer, v3d, action, &any_visible);
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- if (base->flag & SELECT) {
- action = SEL_DESELECT;
- break;
- }
- }
- CTX_DATA_END;
- }
+ if (changed) {
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- CTX_DATA_BEGIN (C, Base *, base, visible_bases)
- {
- switch (action) {
- case SEL_SELECT:
- ED_base_object_select(base, BA_SELECT);
- break;
- case SEL_DESELECT:
- ED_base_object_select(base, BA_DESELECT);
- break;
- case SEL_INVERT:
- if (base->flag & SELECT) {
- ED_base_object_select(base, BA_DESELECT);
- }
- else {
- ED_base_object_select(base, BA_SELECT);
- }
- break;
- }
+ return OPERATOR_FINISHED;
+ }
+ else if (any_visible == false) {
+ /* TODO(campbell): Looks like we could remove this,
+ * if not comment should say why its needed. */
+ return OPERATOR_PASS_THROUGH;
+ }
+ else {
+ return OPERATOR_CANCELLED;
}
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
-
- return OPERATOR_FINISHED;
}
void OBJECT_OT_select_all(wmOperatorType *ot)
@@ -1072,53 +1120,58 @@ void OBJECT_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/**************************** Select In The Same Group ****************************/
+/**************************** Select In The Same Collection ****************************/
-static int object_select_same_group_exec(bContext *C, wmOperator *op)
+static int object_select_same_collection_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Group *group;
- char group_name[MAX_ID_NAME];
+ Collection *collection;
+ char collection_name[MAX_ID_NAME];
/* passthrough if no objects are visible */
if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
- RNA_string_get(op->ptr, "group", group_name);
+ RNA_string_get(op->ptr, "collection", collection_name);
- group = (Group *)BKE_libblock_find_name(bmain, ID_GR, group_name);
+ collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, collection_name);
- if (!group) {
+ if (!collection) {
return OPERATOR_PASS_THROUGH;
}
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
- if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object))
- ED_base_object_select(base, BA_SELECT);
+ if (((base->flag & BASE_SELECTED) == 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
+ if (BKE_collection_has_object(collection, base->object)) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+ }
}
CTX_DATA_END;
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
-void OBJECT_OT_select_same_group(wmOperatorType *ot)
+void OBJECT_OT_select_same_collection(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select Same Group";
- ot->description = "Select object in the same group";
- ot->idname = "OBJECT_OT_select_same_group";
+ ot->name = "Select Same Collection";
+ ot->description = "Select object in the same collection";
+ ot->idname = "OBJECT_OT_select_same_collection";
/* api callbacks */
- ot->exec = object_select_same_group_exec;
+ ot->exec = object_select_same_collection_exec;
ot->poll = objects_selectable_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_string(ot->srna, "group", NULL, MAX_ID_NAME, "Group", "Name of the group to select");
+ RNA_def_string(ot->srna, "collection", NULL, MAX_ID_NAME, "Collection", "Name of the collection to select");
}
/**************************** Select Mirror ****************************/
@@ -1126,6 +1179,7 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
bool extend;
extend = RNA_boolean_get(op->ptr, "extend");
@@ -1139,20 +1193,21 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op)
if (!STREQ(name_flip, primbase->object->id.name + 2)) {
Object *ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip);
if (ob) {
- Base *secbase = BKE_scene_base_find(scene, ob);
+ Base *secbase = BKE_view_layer_base_find(view_layer, ob);
if (secbase) {
- ED_base_object_select(secbase, BA_SELECT);
+ ED_object_base_select(secbase, BA_SELECT);
}
}
}
- if (extend == false) ED_base_object_select(primbase, BA_DESELECT);
+ if (extend == false) ED_object_base_select(primbase, BA_DESELECT);
}
CTX_DATA_END;
/* undo? */
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
@@ -1182,9 +1237,9 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot)
static bool object_select_more_less(bContext *C, const bool select)
{
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- for (Base *base = scene->base.first; base; base = base->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
Object *ob = base->object;
ob->flag &= ~OB_DONE;
ob->id.tag &= ~LIB_TAG_DOIT;
@@ -1219,13 +1274,13 @@ static bool object_select_more_less(bContext *C, const bool select)
bool changed = false;
const short select_mode = select ? BA_SELECT : BA_DESELECT;
- const short select_flag = select ? SELECT : 0;
+ const short select_flag = select ? BASE_SELECTED : 0;
for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) {
Base *base = ctx_base->ptr.data;
Object *ob = base->object;
- if ((ob->id.tag & LIB_TAG_DOIT) && ((ob->flag & SELECT) != select_flag)) {
- ED_base_object_select(base, select_mode);
+ if ((ob->id.tag & LIB_TAG_DOIT) && ((base->flag & BASE_SELECTED) != select_flag)) {
+ ED_object_base_select(base, select_mode);
changed = true;
}
}
@@ -1240,7 +1295,9 @@ static int object_select_more_exec(bContext *C, wmOperator *UNUSED(op))
bool changed = object_select_more_less(C, true);
if (changed) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
else {
@@ -1268,7 +1325,9 @@ static int object_select_less_exec(bContext *C, wmOperator *UNUSED(op))
bool changed = object_select_more_less(C, false);
if (changed) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
else {
@@ -1307,14 +1366,16 @@ static int object_select_random_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
if (BLI_rng_get_float(rng) < randfac) {
- ED_base_object_select(base, select);
+ ED_object_base_select(base, select);
}
}
CTX_DATA_END;
BLI_rng_free(rng);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
new file mode 100644
index 00000000000..47cf9f6c20b
--- /dev/null
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -0,0 +1,470 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2018
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/object/object_shader_fx.c
+ * \ingroup edobj
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_shader_fx_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_shader_fx.h"
+#include "BKE_report.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "object_intern.h"
+
+/******************************** API ****************************/
+
+ShaderFxData *ED_object_shaderfx_add(ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
+{
+ ShaderFxData *new_fx = NULL;
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+
+ if (ob->type != OB_GPENCIL) {
+ BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2);
+ return NULL;
+ }
+
+ if (fxi->flags & eShaderFxTypeFlag_Single) {
+ if (BKE_shaderfx_findByType(ob, type)) {
+ BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed");
+ return NULL;
+ }
+ }
+
+ /* get new effect data to add */
+ new_fx = BKE_shaderfx_new(type);
+
+ BLI_addtail(&ob->shader_fx, new_fx);
+
+ if (name) {
+ BLI_strncpy_utf8(new_fx->name, name, sizeof(new_fx->name));
+ }
+
+ /* make sure effect data has unique name */
+ BKE_shaderfx_unique_name(&ob->shader_fx, new_fx);
+
+ bGPdata *gpd = ob->data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+
+ return new_fx;
+}
+
+/* Return true if the object has a effect of type 'type' other than
+ * the shaderfx pointed to be 'exclude', otherwise returns false. */
+static bool UNUSED_FUNCTION(object_has_shaderfx)(
+ const Object *ob, const ShaderFxData *exclude,
+ ShaderFxType type)
+{
+ ShaderFxData *fx;
+
+ for (fx = ob->shader_fx.first; fx; fx = fx->next) {
+ if ((fx != exclude) && (fx->type == type))
+ return true;
+ }
+
+ return false;
+}
+
+static bool object_shaderfx_remove(
+ Main *bmain, Object *ob, ShaderFxData *fx,
+ bool *UNUSED(r_sort_depsgraph))
+{
+ /* It seems on rapid delete it is possible to
+ * get called twice on same effect, so make
+ * sure it is in list. */
+ if (BLI_findindex(&ob->shader_fx, fx) == -1) {
+ return 0;
+ }
+
+ DEG_relations_tag_update(bmain);
+
+ BLI_remlink(&ob->shader_fx, fx);
+ BKE_shaderfx_free(fx);
+ BKE_object_free_derived_caches(ob);
+
+ return 1;
+}
+
+bool ED_object_shaderfx_remove(ReportList *reports, Main *bmain, Object *ob, ShaderFxData *fx)
+{
+ bool sort_depsgraph = false;
+ bool ok;
+
+ ok = object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph);
+
+ if (!ok) {
+ BKE_reportf(reports, RPT_ERROR, "Effect '%s' not in object '%s'", fx->name, ob->id.name);
+ return 0;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+
+ return 1;
+}
+
+void ED_object_shaderfx_clear(Main *bmain, Object *ob)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+ bool sort_depsgraph = false;
+
+ if (!fx)
+ return;
+
+ while (fx) {
+ ShaderFxData *next_fx;
+
+ next_fx = fx->next;
+
+ object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph);
+
+ fx = next_fx;
+ }
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+}
+
+int ED_object_shaderfx_move_up(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx)
+{
+ if (fx->prev) {
+ BLI_remlink(&ob->shader_fx, fx);
+ BLI_insertlinkbefore(&ob->shader_fx, fx->prev, fx);
+ }
+
+ return 1;
+}
+
+int ED_object_shaderfx_move_down(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx)
+{
+ if (fx->next) {
+ BLI_remlink(&ob->shader_fx, fx);
+ BLI_insertlinkafter(&ob->shader_fx, fx->next, fx);
+ }
+
+ return 1;
+}
+
+/************************ add effect operator *********************/
+
+static int shaderfx_add_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_active_context(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!ED_object_shaderfx_add(op->reports, bmain, scene, ob, NULL, type))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static const EnumPropertyItem *shaderfx_add_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ Object *ob = ED_object_active_context(C);
+ EnumPropertyItem *item = NULL;
+ const EnumPropertyItem *fx_item, *group_item = NULL;
+ const ShaderFxTypeInfo *mti;
+ int totitem = 0, a;
+
+ if (!ob)
+ return rna_enum_object_shaderfx_type_items;
+
+ for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) {
+ fx_item = &rna_enum_object_shaderfx_type_items[a];
+ if (fx_item->identifier[0]) {
+ mti = BKE_shaderfxType_getInfo(fx_item->value);
+
+ if (mti->flags & eShaderFxTypeFlag_NoUserAdd)
+ continue;
+ }
+ else {
+ group_item = fx_item;
+ fx_item = NULL;
+
+ continue;
+ }
+
+ if (group_item) {
+ RNA_enum_item_add(&item, &totitem, group_item);
+ group_item = NULL;
+ }
+
+ RNA_enum_item_add(&item, &totitem, fx_item);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Effect";
+ ot->description = "Add a visual effect to the active object";
+ ot->idname = "OBJECT_OT_shaderfx_add";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = shaderfx_add_exec;
+ ot->poll = ED_operator_object_active_editable;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", "");
+ RNA_def_enum_funcs(prop, shaderfx_add_itemf);
+ ot->prop = prop;
+}
+
+/************************ generic functions for operators using names and data context *********************/
+
+static bool edit_shaderfx_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
+{
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type);
+ Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
+
+ if (!ptr.data) {
+ CTX_wm_operator_poll_msg_set(C, "Context missing 'shaderfx'");
+ return 0;
+ }
+
+ if (!ob || ID_IS_LINKED(ob)) return 0;
+ if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0;
+ if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0;
+
+ if (ID_IS_STATIC_OVERRIDE(ob)) {
+ CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs coming from static override");
+ return (((ShaderFxData *)ptr.data)->flag & eShaderFxFlag_StaticOverride_Local) != 0;
+ }
+
+ return 1;
+}
+
+static bool edit_shaderfx_poll(bContext *C)
+{
+ return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0);
+}
+
+static void edit_shaderfx_properties(wmOperatorType *ot)
+{
+ PropertyRNA *prop = RNA_def_string(ot->srna, "shaderfx", NULL, MAX_NAME, "Shader", "Name of the shaderfx to edit");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+static int edit_shaderfx_invoke_properties(bContext *C, wmOperator *op)
+{
+ ShaderFxData *fx;
+
+ if (RNA_struct_property_is_set(op->ptr, "shaderfx")) {
+ return true;
+ }
+ else {
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx);
+ if (ptr.data) {
+ fx = ptr.data;
+ RNA_string_set(op->ptr, "shaderfx", fx->name);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int type)
+{
+ char shaderfx_name[MAX_NAME];
+ ShaderFxData *fx;
+ RNA_string_get(op->ptr, "shaderfx", shaderfx_name);
+
+ fx = BKE_shaderfx_findByName(ob, shaderfx_name);
+
+ if (fx && type != 0 && fx->type != type)
+ fx = NULL;
+
+ return fx;
+}
+
+/************************ remove shaderfx operator *********************/
+
+static int shaderfx_remove_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = ED_object_active_context(C);
+ ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
+
+ if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_shaderfx_invoke_properties(C, op))
+ return shaderfx_remove_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_shaderfx_remove(wmOperatorType *ot)
+{
+ ot->name = "Remove Grease Pencil Modifier";
+ ot->description = "Remove a shaderfx from the active grease pencil object";
+ ot->idname = "OBJECT_OT_shaderfx_remove";
+
+ ot->invoke = shaderfx_remove_invoke;
+ ot->exec = shaderfx_remove_exec;
+ ot->poll = edit_shaderfx_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_shaderfx_properties(ot);
+}
+
+/************************ move up shaderfx operator *********************/
+
+static int shaderfx_move_up_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
+
+ if (!fx || !ED_object_shaderfx_move_up(op->reports, ob, fx))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_shaderfx_invoke_properties(C, op))
+ return shaderfx_move_up_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot)
+{
+ ot->name = "Move Up Modifier";
+ ot->description = "Move shaderfx up in the stack";
+ ot->idname = "OBJECT_OT_shaderfx_move_up";
+
+ ot->invoke = shaderfx_move_up_invoke;
+ ot->exec = shaderfx_move_up_exec;
+ ot->poll = edit_shaderfx_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_shaderfx_properties(ot);
+}
+
+/************************ move down shaderfx operator *********************/
+
+static int shaderfx_move_down_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
+
+ if (!fx || !ED_object_shaderfx_move_down(op->reports, ob, fx))
+ return OPERATOR_CANCELLED;
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_shaderfx_invoke_properties(C, op))
+ return shaderfx_move_down_exec(C, op);
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot)
+{
+ ot->name = "Move Down Modifier";
+ ot->description = "Move shaderfx down in the stack";
+ ot->idname = "OBJECT_OT_shaderfx_move_down";
+
+ ot->invoke = shaderfx_move_down_invoke;
+ ot->exec = shaderfx_move_down_exec;
+ ot->poll = edit_shaderfx_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_shaderfx_properties(ot);
+}
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index e67b62ea624..7d16898c2a2 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -51,13 +51,14 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_curve.h"
#include "BKE_key.h"
-#include "BKE_library.h"
+#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
-#include "BKE_lattice.h"
-#include "BKE_curve.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "BLI_sys_types.h" // for intptr_t support
@@ -214,7 +215,7 @@ static bool object_shape_key_mirror(bContext *C, Object *ob,
*r_totmirr = totmirr;
*r_totfail = totfail;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return 1;
@@ -265,8 +266,8 @@ static int shape_key_add_exec(bContext *C, wmOperator *op)
ED_object_shape_key_add(C, ob, from_mix);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(CTX_data_main(C));
return OPERATOR_FINISHED;
}
@@ -303,8 +304,8 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op)
}
if (changed) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -344,7 +345,7 @@ static int shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
for (kb = key->block.first; kb; kb = kb->next)
kb->curval = 0.0f;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -381,7 +382,7 @@ static int shape_key_retime_exec(bContext *C, wmOperator *UNUSED(op))
cfra += 0.1f;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -472,7 +473,7 @@ static int shape_key_move_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index fab2396b05a..e2574cf3813 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -38,16 +38,17 @@
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_group_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_collection_types.h"
#include "DNA_lattice_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
+#include "BLI_array.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_idcode.h"
#include "BKE_mball.h"
@@ -59,6 +60,9 @@
#include "BKE_armature.h"
#include "BKE_lattice.h"
#include "BKE_tracking.h"
+#include "BKE_gpencil.h"
+
+#include "DEG_depsgraph.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -71,6 +75,9 @@
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_gpencil.h"
+
+#include "MEM_guardedalloc.h"
#include "object_intern.h"
@@ -266,7 +273,7 @@ static int object_clear_transform_generic_exec(bContext *C, wmOperator *op,
ED_autokeyframe_object(C, scene, ob, ks);
/* tag for updates */
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
CTX_DATA_END;
@@ -372,7 +379,7 @@ static int object_origin_clear_exec(bContext *C, wmOperator *UNUSED(op))
mul_m3_v3(mat, v3);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
CTX_DATA_END;
@@ -400,16 +407,17 @@ void OBJECT_OT_origin_clear(wmOperatorType *ot)
/* use this when the loc/size/rot of the parent has changed but the children
* should stay in the same place, e.g. for apply-size-rot or object center */
-static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob)
+static void ignore_parent_tx(const bContext *C, Main *bmain, Scene *scene, Object *ob)
{
Object workob;
Object *ob_child;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
/* a change was made, adjust the children to compensate */
for (ob_child = bmain->object.first; ob_child; ob_child = ob_child->id.next) {
if (ob_child->parent == ob) {
BKE_object_apply_mat4(ob_child, ob_child->obmat, true, false);
- BKE_object_workob_calc_parent(scene, ob_child, &workob);
+ BKE_object_workob_calc_parent(depsgraph, scene, ob_child, &workob);
invert_m4_m4(ob_child->parentinv, workob.obmat);
}
}
@@ -422,13 +430,14 @@ static int apply_objects_internal(
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
bool changed = true;
/* first check if we can execute */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) {
+ if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
ID *obdata = ob->data;
if (ID_REAL_USERS(obdata) > 1) {
BKE_reportf(reports, RPT_ERROR,
@@ -474,12 +483,43 @@ static int apply_objects_internal(
}
}
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ if (gpd) {
+ if (gpd->layers.first) {
+ /* Unsupported configuration */
+ bool has_unparented_layers = false;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Parented layers aren't supported as we can't easily re-evaluate the scene to sample parent movement */
+ if (gpl->parent == NULL) {
+ has_unparented_layers = true;
+ break;
+ }
+ }
+
+ if (has_unparented_layers == false) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Can't apply to a GP datablock where all layers are parented: Object \"%s\", %s \"%s\", aborting",
+ ob->id.name + 2, BKE_idcode_to_name(ID_GD), gpd->id.name + 2);
+ changed = false;
+ }
+ }
+ else {
+ /* No layers/data */
+ BKE_reportf(reports, RPT_ERROR,
+ "Can't apply to GP datablock with no layers: Object \"%s\", %s \"%s\", aborting",
+ ob->id.name + 2, BKE_idcode_to_name(ID_GD), gpd->id.name + 2);
+ }
+ }
+ }
+
if (ob->type == OB_LAMP) {
Lamp *la = ob->data;
if (la->type == LA_AREA) {
if (apply_rot || apply_loc) {
BKE_reportf(reports, RPT_ERROR,
- "Area Lamps can only have scale applied: \"%s\"",
+ "Area Lights can only have scale applied: \"%s\"",
ob->id.name + 2);
changed = false;
}
@@ -538,7 +578,7 @@ static int apply_objects_internal(
Mesh *me = ob->data;
if (apply_scale)
- multiresModifier_scale_disp(scene, ob);
+ multiresModifier_scale_disp(depsgraph, scene, ob);
/* adjust data */
BKE_mesh_transform(me, mat, true);
@@ -581,6 +621,10 @@ static int apply_objects_internal(
cu->fsize *= scale;
}
}
+ else if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ BKE_gpencil_transform(gpd, mat);
+ }
else if (ob->type == OB_CAMERA) {
MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
@@ -625,6 +669,10 @@ static int apply_objects_internal(
la->area_shape = LA_AREA_RECT;
la->area_sizey = la->area_size;
}
+ else if ((la->area_shape == LA_AREA_DISK) && !keeps_aspect_ratio) {
+ la->area_shape = LA_AREA_ELLIPSE;
+ la->area_sizey = la->area_size;
+ }
la->area_size *= rsmat[0][0];
la->area_sizey *= rsmat[1][1];
@@ -644,14 +692,14 @@ static int apply_objects_internal(
unit_axis_angle(ob->rotAxis, &ob->rotAngle);
}
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
if (ob->type == OB_ARMATURE) {
- BKE_pose_where_is(scene, ob); /* needed for bone parents */
+ BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */
}
- ignore_parent_tx(bmain, scene, ob);
+ ignore_parent_tx(C, bmain, scene, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
changed = true;
}
@@ -669,16 +717,17 @@ static int apply_objects_internal(
static int visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
bool changed = false;
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
BKE_object_apply_mat4(ob, ob->obmat, true, true);
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
/* update for any children that may get moved */
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
changed = true;
}
@@ -759,6 +808,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *tob;
float cursor[3], cent[3], cent_neg[3], centn[3];
int centermode = RNA_enum_get(op->ptr, "type");
@@ -778,9 +828,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
else {
/* get the view settings if 'around' isn't set and the view is available */
View3D *v3d = CTX_wm_view3d(C);
- copy_v3_v3(cursor, ED_view3d_cursor3d_get(scene, v3d));
+ copy_v3_v3(cursor, scene->cursor.location);
if (v3d && !RNA_struct_property_is_set(op->ptr, "center"))
- around = v3d->around;
+ around = scene->toolsettings->transform_pivot_point;
}
zero_v3(cent);
@@ -822,7 +872,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
EDBM_mesh_normals_update(em);
tot_change++;
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
}
@@ -871,7 +921,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (ob->data == NULL) {
/* special support for dupligroups */
- if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) {
+ if ((ob->transflag & OB_DUPLICOLLECTION) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) {
if (ID_IS_LINKED(ob->dup_group)) {
tot_lib_error++;
}
@@ -883,7 +933,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
float min[3], max[3];
/* only bounds support */
INIT_MINMAX(min, max);
- BKE_object_minmax_dupli(bmain, scene, ob, min, max, true);
+ BKE_object_minmax_dupli(depsgraph, scene, ob, min, max, true);
mid_v3_v3v3(cent, min, max);
invert_m4_m4(ob->imat, ob->obmat);
mul_m4_v3(ob->imat, cent);
@@ -947,7 +997,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (obedit) {
if (centermode == GEOMETRY_TO_ORIGIN) {
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
break;
}
@@ -994,16 +1044,16 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* Function to recenter armatures in editarmature.c
* Bone + object locations are handled there.
*/
- ED_armature_origin_set(bmain, scene, ob, cursor, centermode, around);
+ ED_armature_origin_set(bmain, ob, cursor, centermode, around);
tot_change++;
arm->id.tag |= LIB_TAG_DOIT;
/* do_inverse_offset = true; */ /* docenter_armature() handles this */
- BKE_object_where_is_calc(scene, ob);
- BKE_pose_where_is(scene, ob); /* needed for bone parents */
+ BKE_object_where_is_calc(depsgraph, scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */
- ignore_parent_tx(bmain, scene, ob);
+ ignore_parent_tx(C, bmain, scene, ob);
if (obedit)
break;
@@ -1025,7 +1075,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (obedit) {
if (centermode == GEOMETRY_TO_ORIGIN) {
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
break;
}
@@ -1044,6 +1094,69 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
lt->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
+ else if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = ob->data;
+ float gpcenter[3];
+ if (gpd) {
+ if (centermode == ORIGIN_TO_GEOMETRY) {
+ zero_v3(gpcenter);
+ BKE_gpencil_centroid_3d(gpd, gpcenter);
+ add_v3_v3(gpcenter, ob->obmat[3]);
+ }
+ if (centermode == ORIGIN_TO_CURSOR) {
+ copy_v3_v3(gpcenter, cursor);
+ }
+ if ((centermode == ORIGIN_TO_GEOMETRY) || (centermode == ORIGIN_TO_CURSOR)) {
+ bGPDspoint *pt;
+ float imat[3][3], bmat[3][3];
+ float offset_global[3];
+ float offset_local[3];
+ int i;
+
+ sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]);
+ copy_m3_m4(bmat, obact->obmat);
+ invert_m3_m3(imat, bmat);
+ mul_m3_v3(imat, offset_global);
+ mul_v3_m3v3(offset_local, imat, offset_global);
+
+ float diff_mat[4][4];
+ float inverse_diff_mat[4][4];
+
+ /* recalculate all strokes (all layers are considered without evaluating lock attributtes) */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ /* undo matrix */
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(&pt->x, diff_mat, mpt);
+ }
+ }
+ }
+ }
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ tot_change++;
+ if (centermode == ORIGIN_TO_GEOMETRY) {
+ copy_v3_v3(ob->loc, gpcenter);
+ }
+ ob->id.tag |= LIB_TAG_DOIT;
+ do_inverse_offset = true;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Grease Pencil Object does not support this set origin option");
+ }
+ }
+ }
/* offset other selected objects */
if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
@@ -1059,12 +1172,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
add_v3_v3(ob->loc, centn);
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
if (ob->type == OB_ARMATURE) {
- BKE_pose_where_is(scene, ob); /* needed for bone parents */
+ BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */
}
- ignore_parent_tx(bmain, scene, ob);
+ ignore_parent_tx(C, bmain, scene, ob);
/* other users? */
//CTX_DATA_BEGIN (C, Object *, ob_other, selected_editable_objects)
@@ -1080,19 +1193,19 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if ((ob_other->flag & OB_DONE) == 0 &&
((ob->data && (ob->data == ob_other->data)) ||
(ob->dup_group == ob_other->dup_group &&
- (ob->transflag | ob_other->transflag) & OB_DUPLIGROUP)))
+ (ob->transflag | ob_other->transflag) & OB_DUPLICOLLECTION)))
{
ob_other->flag |= OB_DONE;
- DAG_id_tag_update(&ob_other->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_other->id, OB_RECALC_OB | OB_RECALC_DATA);
mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */
add_v3_v3(ob_other->loc, centn);
- BKE_object_where_is_calc(scene, ob_other);
+ BKE_object_where_is_calc(depsgraph, scene, ob_other);
if (ob_other->type == OB_ARMATURE) {
- BKE_pose_where_is(scene, ob_other); /* needed for bone parents */
+ BKE_pose_where_is(depsgraph, scene, ob_other); /* needed for bone parents */
}
- ignore_parent_tx(bmain, scene, ob_other);
+ ignore_parent_tx(C, bmain, scene, ob_other);
}
}
//CTX_DATA_END;
@@ -1101,9 +1214,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
BLI_freelistN(&ctx_data_list);
- for (tob = bmain->object.first; tob; tob = tob->id.next)
- if (tob->data && (((ID *)tob->data)->tag & LIB_TAG_DOIT))
- DAG_id_tag_update(&tob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ for (tob = bmain->object.first; tob; tob = tob->id.next) {
+ if (tob->data && (((ID *)tob->data)->tag & LIB_TAG_DOIT)) {
+ BKE_object_batch_cache_dirty_tag(tob);
+ DEG_id_tag_update(&tob->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+ }
if (tot_change) {
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1160,3 +1276,385 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", "");
RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_AROUND_CENTER_MEAN, "Center", "");
}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Transform Axis Target
+ *
+ * Note this is an experemental operator to point lamps/cameras at objects.
+ * We may re-work how this behaves based on user feedback.
+ * - campbell.
+ * \{ */
+
+/* When using multiple objects, apply their relative rotational offset to the active object. */
+#define USE_RELATIVE_ROTATION
+
+struct XFormAxisItem {
+ Object *ob;
+ float rot_mat[3][3];
+ void *obtfm;
+ float xform_dist;
+
+#ifdef USE_RELATIVE_ROTATION
+ /* use when translating multiple */
+ float xform_rot_offset[3][3];
+#endif
+};
+
+struct XFormAxisData {
+ ViewContext vc;
+ struct {
+ float depth;
+ float normal[3];
+ bool is_depth_valid;
+ bool is_normal_valid;
+ } prev;
+
+ struct XFormAxisItem *object_data;
+ uint object_data_len;
+ bool is_translate;
+
+ int init_event;
+};
+
+static bool object_is_target_compat(const Object *ob)
+{
+ if (ob->type == OB_LAMP) {
+ const Lamp *la = ob->data;
+ if (ELEM(la->type, LA_SUN, LA_SPOT, LA_AREA)) {
+ return true;
+ }
+ }
+ /* We might want to enable this later, for now just lamps */
+#if 0
+ else if (ob->type == OB_CAMERA) {
+ return true;
+ }
+#endif
+ return false;
+}
+
+static void object_transform_axis_target_free_data(wmOperator *op)
+{
+ struct XFormAxisData *xfd = op->customdata;
+ struct XFormAxisItem *item = xfd->object_data;
+ for (int i = 0; i < xfd->object_data_len; i++, item++) {
+ MEM_freeN(item->obtfm);
+ }
+ MEM_freeN(xfd->object_data);
+ MEM_freeN(xfd);
+ op->customdata = NULL;
+}
+
+/* We may want to expose as alternative to: BKE_object_apply_rotation */
+static void object_apply_rotation(Object *ob, const float rmat[3][3])
+{
+ float size[3];
+ float loc[3];
+ float rmat4[4][4];
+ copy_m4_m3(rmat4, rmat);
+
+ copy_v3_v3(size, ob->size);
+ copy_v3_v3(loc, ob->loc);
+ BKE_object_apply_mat4(ob, rmat4, true, true);
+ copy_v3_v3(ob->size, size);
+ copy_v3_v3(ob->loc, loc);
+}
+/* We may want to extract this to: BKE_object_apply_location */
+static void object_apply_location(Object *ob, const float loc[3])
+{
+ /* quick but weak */
+ Object ob_prev = *ob;
+ float mat[4][4];
+ copy_m4_m4(mat, ob->obmat);
+ copy_v3_v3(mat[3], loc);
+ BKE_object_apply_mat4(ob, mat, true, true);
+ copy_v3_v3(mat[3], ob->loc);
+ *ob = ob_prev;
+ copy_v3_v3(ob->loc, mat[3]);
+}
+
+static void object_orient_to_location(
+ Object *ob, float rot_orig[3][3], const float axis[3], const float location[3])
+{
+ float delta[3];
+ sub_v3_v3v3(delta, ob->obmat[3], location);
+ if (normalize_v3(delta) != 0.0f) {
+ if (len_squared_v3v3(delta, axis) > FLT_EPSILON) {
+ float delta_rot[3][3];
+ float final_rot[3][3];
+ rotation_between_vecs_to_mat3(delta_rot, axis, delta);
+
+ mul_m3_m3m3(final_rot, delta_rot, rot_orig);
+
+ object_apply_rotation(ob, final_rot);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
+ }
+ }
+}
+
+static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
+{
+ struct XFormAxisData *xfd = op->customdata;
+ struct XFormAxisItem *item = xfd->object_data;
+ for (int i = 0; i < xfd->object_data_len; i++, item++) {
+ BKE_object_tfm_restore(item->ob, item->obtfm);
+ DEG_id_tag_update(&item->ob->id, OB_RECALC_OB);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ }
+
+ object_transform_axis_target_free_data(op);
+}
+
+static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc);
+
+ if (!object_is_target_compat(vc.obact)) {
+ /* Falls back to texture space transform. */
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ ED_view3d_autodist_init(vc.depsgraph, vc.ar, vc.v3d, 0);
+
+ if (vc.rv3d->depths != NULL) {
+ vc.rv3d->depths->damaged = true;
+ }
+ ED_view3d_depth_update(vc.ar);
+
+ if (vc.rv3d->depths == NULL) {
+ BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane");
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_region_tag_redraw(vc.ar);
+
+ struct XFormAxisData *xfd;
+ xfd = op->customdata = MEM_callocN(sizeof(struct XFormAxisData), __func__);
+
+ /* Don't change this at runtime. */
+ xfd->vc = vc;
+ xfd->vc.mval[0] = event->mval[0];
+ xfd->vc.mval[1] = event->mval[1];
+
+ xfd->prev.depth = 1.0f;
+ xfd->prev.is_depth_valid = false;
+ xfd->prev.is_normal_valid = false;
+ xfd->is_translate = false;
+
+ xfd->init_event = WM_userdef_event_type_from_keymap_type(event->type);
+
+ {
+ struct XFormAxisItem *object_data = NULL;
+ BLI_array_declare(object_data);
+
+ struct XFormAxisItem *item = BLI_array_append_ret(object_data);
+ item->ob = xfd->vc.obact;
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if ((ob != xfd->vc.obact) && object_is_target_compat(ob)) {
+ item = BLI_array_append_ret(object_data);
+ item->ob = ob;
+ }
+ }
+ CTX_DATA_END;
+
+ xfd->object_data = object_data;
+ xfd->object_data_len = BLI_array_len(object_data);
+
+ if (xfd->object_data_len != BLI_array_len(object_data)) {
+ xfd->object_data = MEM_reallocN(xfd->object_data, xfd->object_data_len * sizeof(*xfd->object_data));
+ }
+ }
+
+ {
+ struct XFormAxisItem *item = xfd->object_data;
+ for (int i = 0; i < xfd->object_data_len; i++, item++) {
+ item->obtfm = BKE_object_tfm_backup(item->ob);
+ BKE_object_rot_to_mat3(item->ob, item->rot_mat, true);
+ }
+ }
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ struct XFormAxisData *xfd = op->customdata;
+ ARegion *ar = xfd->vc.ar;
+
+ view3d_operator_needs_opengl(C);
+
+ const bool is_translate = (event->ctrl != 0);
+ const bool is_translate_init = is_translate && (xfd->is_translate != is_translate);
+
+ if (event->type == MOUSEMOVE || is_translate_init) {
+ const ViewDepths *depths = xfd->vc.rv3d->depths;
+ if (depths &&
+ ((unsigned int)event->mval[0] < depths->w) &&
+ ((unsigned int)event->mval[1] < depths->h))
+ {
+ double depth = (double)ED_view3d_depth_read_cached(&xfd->vc, event->mval);
+ float location_world[3];
+ if (depth == 1.0f) {
+ if (xfd->prev.is_depth_valid) {
+ depth = (double)xfd->prev.depth;
+ }
+ }
+ if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
+ xfd->prev.depth = depth;
+ xfd->prev.is_depth_valid = true;
+ if (ED_view3d_depth_unproject(ar, event->mval, depth, location_world)) {
+ if (is_translate) {
+
+ float normal[3];
+ bool normal_found = false;
+ if (ED_view3d_depth_read_cached_normal(&xfd->vc, event->mval, normal)) {
+ normal_found = true;
+
+ /* cheap attempt to smooth normals out a bit! */
+ const uint ofs = 2;
+ for (uint x = -ofs; x <= ofs; x += ofs / 2) {
+ for (uint y = -ofs; y <= ofs; y += ofs / 2) {
+ if (x != 0 && y != 0) {
+ int mval_ofs[2] = {event->mval[0] + x, event->mval[1] + y};
+ float n[3];
+ if (ED_view3d_depth_read_cached_normal(
+ &xfd->vc, mval_ofs, n))
+ {
+ add_v3_v3(normal, n);
+ }
+ }
+ }
+ }
+ normalize_v3(normal);
+ }
+ else if (xfd->prev.is_normal_valid) {
+ copy_v3_v3(normal, xfd->prev.normal);
+ normal_found = true;
+ }
+
+ if (normal_found) {
+#ifdef USE_RELATIVE_ROTATION
+ if (is_translate_init && xfd->object_data_len > 1) {
+ float xform_rot_offset_inv_first[3][3];
+ struct XFormAxisItem *item = xfd->object_data;
+ for (int i = 0; i < xfd->object_data_len; i++, item++) {
+ copy_m3_m4(item->xform_rot_offset, item->ob->obmat);
+ normalize_m3(item->xform_rot_offset);
+
+ if (i == 0) {
+ invert_m3_m3(xform_rot_offset_inv_first, xfd->object_data[0].xform_rot_offset);
+ }
+ else {
+ mul_m3_m3m3(item->xform_rot_offset,
+ item->xform_rot_offset,
+ xform_rot_offset_inv_first);
+ }
+ }
+ }
+
+#endif
+
+ struct XFormAxisItem *item = xfd->object_data;
+ for (int i = 0; i < xfd->object_data_len; i++, item++) {
+ if (is_translate_init) {
+ float ob_axis[3];
+ item->xform_dist = len_v3v3(item->ob->obmat[3], location_world);
+ normalize_v3_v3(ob_axis, item->ob->obmat[2]);
+ /* Scale to avoid adding distance when moving between surfaces. */
+ float scale = fabsf(dot_v3v3(ob_axis, normal));
+ item->xform_dist *= scale;
+ }
+
+ float target_normal[3];
+ copy_v3_v3(target_normal, normal);
+
+#ifdef USE_RELATIVE_ROTATION
+ if (i != 0) {
+ mul_m3_v3(item->xform_rot_offset, target_normal);
+ }
+#endif
+ {
+ float loc[3];
+
+ copy_v3_v3(loc, location_world);
+ madd_v3_v3fl(loc, target_normal, item->xform_dist);
+ object_apply_location(item->ob, loc);
+ copy_v3_v3(item->ob->obmat[3], loc); /* so orient behaves as expected */
+ }
+
+ object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ }
+ copy_v3_v3(xfd->prev.normal, normal);
+ xfd->prev.is_normal_valid = true;
+ }
+ }
+ else {
+ struct XFormAxisItem *item = xfd->object_data;
+ for (int i = 0; i < xfd->object_data_len; i++, item++) {
+ object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ }
+ xfd->prev.is_normal_valid = false;
+ }
+ }
+ }
+ }
+ xfd->is_translate = is_translate;
+
+ ED_region_tag_redraw(xfd->vc.ar);
+ }
+
+ bool is_finished = false;
+
+ if (ISMOUSE(xfd->init_event)) {
+ if ((event->type == xfd->init_event) && (event->val == KM_RELEASE)) {
+ is_finished = true;
+ }
+ }
+ else {
+ if (ELEM(event->type, LEFTMOUSE, RETKEY, PADENTER)) {
+ is_finished = true;
+ }
+ }
+
+ if (is_finished) {
+ object_transform_axis_target_free_data(op);
+ return OPERATOR_FINISHED;
+ }
+ else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) {
+ object_transform_axis_target_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void OBJECT_OT_transform_axis_target(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Interactive Light Track to Cursor";
+ ot->description = "Interactively point cameras and lights to a location (Ctrl translates)";
+ ot->idname = "OBJECT_OT_transform_axis_target";
+
+ /* api callbacks */
+ ot->invoke = object_transform_axis_target_invoke;
+ ot->cancel = object_transform_axis_target_cancel;
+ ot->modal = object_transform_axis_target_modal;
+ ot->poll = ED_operator_region_view3d_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+}
+
+#undef USE_RELATIVE_ROTATION
+
+/** \} */
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index e11782cd4b3..1a0c129e23a 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -43,6 +43,7 @@
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
@@ -56,16 +57,18 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_report.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_object_deform.h"
#include "BKE_object.h"
#include "BKE_lattice.h"
+#include "DEG_depsgraph.h"
+
#include "DNA_armature_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -1254,27 +1257,6 @@ static void getVerticalAndHorizontalChange(
changes[index][1] = len_v3v3(projA, projB);
}
-/* I need the derived mesh to be forgotten so the positions are recalculated
- * with weight changes (see dm_deform_recalc) */
-static void dm_deform_clear(DerivedMesh *dm, Object *ob)
-{
- if (ob->derivedDeform && (ob->derivedDeform) == dm) {
- ob->derivedDeform->needsFree = 1;
- ob->derivedDeform->release(ob->derivedDeform);
- ob->derivedDeform = NULL;
- }
- else if (dm) {
- dm->needsFree = 1;
- dm->release(dm);
- }
-}
-
-/* recalculate the deformation */
-static DerivedMesh *dm_deform_recalc(Scene *scene, Object *ob)
-{
- return mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
-}
-
/* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to
* distToBe distance away from the provided plane strength can change distToBe so that it moves
* towards distToBe by that percentage cp changes how much the weights are adjusted
@@ -1285,10 +1267,10 @@ static DerivedMesh *dm_deform_recalc(Scene *scene, Object *ob)
* coord is a point on the plane
*/
static void moveCloserToDistanceFromPlane(
- Scene *scene, Object *ob, Mesh *me, int index, float norm[3],
+ Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, int index, float norm[3],
float coord[3], float d, float distToBe, float strength, float cp)
{
- DerivedMesh *dm;
+ Mesh *me_deform;
MDeformWeight *dw;
MVert m;
MDeformVert *dvert = me->dvert + index;
@@ -1312,8 +1294,8 @@ static void moveCloserToDistanceFromPlane(
float originalDistToBe = distToBe;
do {
wasChange = false;
- dm = dm_deform_recalc(scene, ob);
- dm->getVert(dm, index, &m);
+ me_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
+ m = me_deform->mvert[index];
copy_v3_v3(oldPos, m.co);
distToStart = dot_v3v3(norm, oldPos) + d;
@@ -1331,8 +1313,10 @@ static void moveCloserToDistanceFromPlane(
continue;
}
for (k = 0; k < 2; k++) {
- if (dm) {
- dm_deform_clear(dm, ob); dm = NULL;
+ if (me_deform) {
+ /* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs!
+ * Better to over-free and recompute a bit. */
+ BKE_object_free_derived_caches(ob);
}
oldw = dw->weight;
if (k) {
@@ -1350,8 +1334,8 @@ static void moveCloserToDistanceFromPlane(
if (dw->weight > 1) {
dw->weight = 1;
}
- dm = dm_deform_recalc(scene, ob);
- dm->getVert(dm, index, &m);
+ me_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
+ m = me_deform->mvert[index];
getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m.co, changes, dists, i);
dw->weight = oldw;
if (!k) {
@@ -1445,8 +1429,10 @@ static void moveCloserToDistanceFromPlane(
if (oldw == dw->weight) {
wasChange = false;
}
- if (dm) {
- dm_deform_clear(dm, ob); dm = NULL;
+ if (me_deform) {
+ /* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs!
+ * Better to over-free and recompute a bit. */
+ BKE_object_free_derived_caches(ob);
}
}
} while (wasChange && ((distToStart - distToBe) / fabsf(distToStart - distToBe) ==
@@ -1460,8 +1446,9 @@ static void moveCloserToDistanceFromPlane(
/* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex
* but it could be used to raise or lower an existing 'bump.' */
-static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, float cp)
+static void vgroup_fix(const bContext *C, Scene *scene, Object *ob, float distToBe, float strength, float cp)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
int i;
Mesh *me = ob->data;
@@ -1477,11 +1464,10 @@ static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength,
MVert *p = MEM_callocN(sizeof(MVert) * (count), "deformedPoints");
int k;
- DerivedMesh *dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
k = count;
while (k--) {
- dm->getVert(dm, verts[k], &m);
- p[k] = m;
+ p[k] = me_deform->mvert[verts[k]];
}
if (count >= 3) {
@@ -1489,13 +1475,13 @@ static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength,
float coord[3];
float norm[3];
getSingleCoordinate(p, count, coord);
- dm->getVert(dm, i, &m);
+ m = me_deform->mvert[i];
sub_v3_v3v3(norm, m.co, coord);
mag = normalize_v3(norm);
if (mag) { /* zeros fix */
d = -dot_v3v3(norm, coord);
/* dist = (dot_v3v3(norm, m.co) + d); */ /* UNUSED */
- moveCloserToDistanceFromPlane(scene, ob, me, i, norm, coord, d, distToBe, strength, cp);
+ moveCloserToDistanceFromPlane(depsgraph, scene, ob, me, i, norm, coord, d, distToBe, strength, cp);
}
}
@@ -2635,7 +2621,7 @@ static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_context(C);
BKE_object_defgroup_add(ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -2668,7 +2654,7 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op)
else
vgroup_delete_active(ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -2703,7 +2689,7 @@ static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_context(C);
vgroup_assign_verts(ob, ts->vgroup_weight);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
@@ -2776,7 +2762,7 @@ static int vertex_group_remove_from_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
@@ -2815,6 +2801,7 @@ static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
vgroup_select_verts(ob, 1);
+ DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
return OPERATOR_FINISHED;
@@ -2840,6 +2827,7 @@ static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_context(C);
vgroup_select_verts(ob, 0);
+ DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
return OPERATOR_FINISHED;
@@ -2865,7 +2853,7 @@ static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = ED_object_context(C);
vgroup_duplicate(ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob->data);
@@ -2901,7 +2889,7 @@ static int vertex_group_levels_exec(bContext *C, wmOperator *op)
vgroup_levels_subset(ob, vgroup_validmap, vgroup_tot, subset_count, offset, gain);
MEM_freeN((void *)vgroup_validmap);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -2935,7 +2923,7 @@ static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
changed = vgroup_normalize(ob);
if (changed) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -2974,7 +2962,7 @@ static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
MEM_freeN((void *)vgroup_validmap);
if (changed) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -3027,9 +3015,9 @@ static int vertex_group_fix_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier");
return OPERATOR_CANCELLED;
}
- vgroup_fix(scene, ob, distToBe, strength, cp);
+ vgroup_fix(C, scene, ob, distToBe, strength, cp);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -3101,7 +3089,7 @@ static int vertex_group_invert_exec(bContext *C, wmOperator *op)
vgroup_invert_subset(ob, vgroup_validmap, vgroup_tot, subset_count, auto_assign, auto_remove);
MEM_freeN((void *)vgroup_validmap);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -3131,21 +3119,32 @@ void OBJECT_OT_vertex_group_invert(wmOperatorType *ot)
static int vertex_group_smooth_exec(bContext *C, wmOperator *op)
{
- Object *ob = ED_object_context(C);
const float fac = RNA_float_get(op->ptr, "factor");
const int repeat = RNA_int_get(op->ptr, "repeat");
eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
const float fac_expand = RNA_float_get(op->ptr, "expand");
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- int subset_count, vgroup_tot;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
- const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
- vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand);
- MEM_freeN((void *)vgroup_validmap);
+ int subset_count, vgroup_tot;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob,
+ subset_type,
+ &vgroup_tot,
+ &subset_count);
+
+ vgroup_smooth_subset(ob, vgroup_validmap, vgroup_tot, subset_count, fac, repeat, fac_expand);
+ MEM_freeN((void *)vgroup_validmap);
+
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3185,7 +3184,7 @@ static int vertex_group_clean_exec(bContext *C, wmOperator *op)
vgroup_clean_subset(ob, vgroup_validmap, vgroup_tot, subset_count, limit, keep_single);
MEM_freeN((void *)vgroup_validmap);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -3226,7 +3225,7 @@ static int vertex_group_quantize_exec(bContext *C, wmOperator *op)
vgroup_quantize_subset(ob, vgroup_validmap, vgroup_tot, subset_count, steps);
MEM_freeN((void *)vgroup_validmap);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -3267,7 +3266,7 @@ static int vertex_group_limit_total_exec(bContext *C, wmOperator *op)
BKE_reportf(op->reports, remove_tot ? RPT_INFO : RPT_WARNING, "%d vertex weights limited", remove_tot);
if (remove_tot) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -3313,7 +3312,7 @@ static int vertex_group_mirror_exec(bContext *C, wmOperator *op)
ED_mesh_report_mirror(op, totmirr, totfail);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
@@ -3346,25 +3345,26 @@ void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot)
static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_context(C);
- Base *base;
+ Object *ob_active = ED_object_context(C);
int retval = OPERATOR_CANCELLED;
- for (base = scene->base.first; base; base = base->next) {
- if (base->object->type == ob->type) {
- if (base->object != ob && base->object->data == ob->data) {
- BLI_freelistN(&base->object->defbase);
- BLI_duplicatelist(&base->object->defbase, &ob->defbase);
- base->object->actdef = ob->actdef;
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob_iter)
+ {
+ if (ob_iter->type == ob_active->type) {
+ if (ob_iter != ob_active && ob_iter->data == ob_active->data) {
+ BLI_freelistN(&ob_iter->defbase);
+ BLI_duplicatelist(&ob_iter->defbase, &ob_active->defbase);
+ ob_iter->actdef = ob_active->actdef;
- DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, base->object);
- WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, base->object->data);
+ DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter);
+ WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_iter->data);
retval = OPERATOR_FINISHED;
}
}
}
+ FOREACH_SCENE_OBJECT_END;
return retval;
}
@@ -3394,7 +3394,7 @@ static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
{
if (obact != ob) {
if (ED_vgroup_array_copy(ob, obact)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
changed_tot++;
}
@@ -3437,7 +3437,7 @@ static int set_active_group_exec(bContext *C, wmOperator *op)
BLI_assert(nr + 1 >= 0);
ob->actdef = nr + 1;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
return OPERATOR_FINISHED;
@@ -3651,7 +3651,7 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op)
ret = vgroup_do_remap(ob, name_array, op);
if (ret != OPERATOR_CANCELLED) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
}
@@ -3701,7 +3701,7 @@ static int vgroup_move_exec(bContext *C, wmOperator *op)
ret = vgroup_do_remap(ob, name_array, op);
if (ret != OPERATOR_CANCELLED) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
}
}
@@ -3830,7 +3830,7 @@ static int vertex_weight_paste_exec(bContext *C, wmOperator *op)
vgroup_copy_active_to_sel_single(ob, def_nr);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -3867,7 +3867,7 @@ static int vertex_weight_delete_exec(bContext *C, wmOperator *op)
vgroup_remove_weight(ob, def_nr);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -3900,7 +3900,7 @@ static int vertex_weight_set_active_exec(bContext *C, wmOperator *op)
if (wg_index != -1) {
ob->actdef = wg_index + 1;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
@@ -3937,7 +3937,7 @@ static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *U
changed = vgroup_normalize_active_vertex(ob, subset_type);
if (changed) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -3970,7 +3970,7 @@ static int vertex_weight_copy_exec(bContext *C, wmOperator *UNUSED(op))
vgroup_copy_active_to_sel(ob, subset_type);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c
index 92b82e2a31b..d28ed71c382 100644
--- a/source/blender/editors/object/object_warp.c
+++ b/source/blender/editors/object/object_warp.c
@@ -223,12 +223,8 @@ static int object_warp_verts_exec(bContext *C, wmOperator *op)
RNA_property_float_get_array(op->ptr, prop_center, center);
}
else {
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- const float *cursor;
-
- cursor = ED_view3d_cursor3d_get(scene, v3d);
- copy_v3_v3(center, cursor);
+ const Scene *scene = CTX_data_scene(C);
+ copy_v3_v3(center, scene->cursor.location);
RNA_property_float_set_array(op->ptr, prop_center, center);
}
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index a04ebb24d2c..3705ff9d41a 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index dc94cab0733..5fb03b628b2 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -42,7 +42,6 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_object_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -50,6 +49,9 @@
#include "BKE_report.h"
#include "BKE_screen.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_object.h"
@@ -128,14 +130,14 @@ static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
for (; surface; surface = surface->next) {
if (id == canvas->active_sur) {
canvas->active_sur -= 1;
- dynamicPaint_freeSurface(surface);
+ dynamicPaint_freeSurface(pmd, surface);
break;
}
id++;
}
dynamicPaint_resetPreview(canvas);
- DAG_id_tag_update(&obj_ctx->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&obj_ctx->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, obj_ctx);
return OPERATOR_FINISHED;
@@ -181,8 +183,8 @@ static int type_toggle_exec(bContext *C, wmOperator *op)
}
/* update dependency */
- DAG_id_tag_update(&cObject->id, OB_RECALC_DATA);
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_id_tag_update(&cObject->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, cObject);
return OPERATOR_FINISHED;
@@ -286,6 +288,7 @@ typedef struct DynamicPaintBakeJob {
struct Main *bmain;
Scene *scene;
+ Depsgraph *depsgraph;
Object *ob;
DynamicPaintSurface *surface;
@@ -357,7 +360,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
frame = surface->start_frame;
orig_frame = scene->r.cfra;
scene->r.cfra = (int)frame;
- ED_update_for_newframe(job->bmain, scene, 1);
+ ED_update_for_newframe(job->bmain, job->depsgraph);
/* Init surface */
if (!dynamicPaint_createUVSurface(scene, surface, job->progress, job->do_update)) {
@@ -383,8 +386,8 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
/* calculate a frame */
scene->r.cfra = (int)frame;
- ED_update_for_newframe(job->bmain, scene, 1);
- if (!dynamicPaint_calculateFrame(job->bmain, job->bmain->eval_ctx, surface, scene, cObject, frame)) {
+ ED_update_for_newframe(job->bmain, job->depsgraph);
+ if (!dynamicPaint_calculateFrame(surface, job->depsgraph, scene, cObject, frame)) {
job->success = 0;
return;
}
@@ -479,6 +482,7 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op)
DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob");
job->bmain = CTX_data_main(C);
job->scene = scene;
+ job->depsgraph = CTX_data_depsgraph(C);
job->ob = ob;
job->canvas = canvas;
job->surface = surface;
diff --git a/source/blender/editors/physics/particle_boids.c b/source/blender/editors/physics/particle_boids.c
index bb7dd64fb47..f1e0fd39014 100644
--- a/source/blender/editors/physics/particle_boids.c
+++ b/source/blender/editors/physics/particle_boids.c
@@ -39,10 +39,12 @@
#include "BKE_boids.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_particle.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_enum_types.h"
#include "RNA_define.h"
@@ -75,7 +77,7 @@ static int rule_add_exec(bContext *C, wmOperator *op)
BLI_addtail(&state->rules, rule);
- DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
return OPERATOR_FINISHED;
}
@@ -121,8 +123,8 @@ static int rule_del_exec(bContext *C, wmOperator *UNUSED(op))
if (rule)
rule->flag |= BOIDRULE_CURRENT;
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
return OPERATOR_FINISHED;
}
@@ -158,7 +160,7 @@ static int rule_move_up_exec(bContext *C, wmOperator *UNUSED(op))
BLI_remlink(&state->rules, rule);
BLI_insertlinkbefore(&state->rules, rule->prev, rule);
- DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
break;
}
}
@@ -194,7 +196,7 @@ static int rule_move_down_exec(bContext *C, wmOperator *UNUSED(op))
BLI_remlink(&state->rules, rule);
BLI_insertlinkafter(&state->rules, rule->next, rule);
- DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
break;
}
}
@@ -277,8 +279,8 @@ static int state_del_exec(bContext *C, wmOperator *UNUSED(op))
state->flag |= BOIDSTATE_CURRENT;
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
return OPERATOR_FINISHED;
}
@@ -349,7 +351,7 @@ static int state_move_down_exec(bContext *C, wmOperator *UNUSED(op))
if (state->flag & BOIDSTATE_CURRENT && state->next) {
BLI_remlink(&boids->states, state);
BLI_insertlinkafter(&boids->states, state->next, state);
- DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_RESET);
break;
}
}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 181c42a4072..09d3beadb2a 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -46,40 +46,55 @@
#include "BLI_math.h"
#include "BLI_lasso_2d.h"
#include "BLI_listbase.h"
+#include "BLI_string.h"
#include "BLI_kdtree.h"
#include "BLI_rand.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
+#include "BKE_bvhutils.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
-#include "BKE_object.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_particle.h"
-#include "BKE_report.h"
-#include "BKE_bvhutils.h"
#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "ED_object.h"
#include "ED_physics.h"
#include "ED_mesh.h"
#include "ED_particle.h"
+#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_view3d.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_state.h"
+
#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "DEG_depsgraph_query.h"
+
+#include "PIL_time_utildefines.h"
+
#include "physics_intern.h"
#include "particle_edit_utildefines.h"
@@ -88,27 +103,25 @@
bool PE_poll(bContext *C)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
+ if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
return 0;
-
- return (PE_get_current(bmain, scene, ob) != NULL);
+ }
+ return (PE_get_current(scene, ob) != NULL);
}
bool PE_hair_poll(bContext *C)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
PTCacheEdit *edit;
- if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
+ if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
return 0;
-
- edit = PE_get_current(bmain, scene, ob);
+ }
+ edit = PE_get_current(scene, ob);
return (edit && edit->psys);
}
@@ -186,12 +199,55 @@ static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *br
return brush->size * U.pixelsize;
}
+PTCacheEdit *PE_get_current_from_psys(ParticleSystem *psys)
+{
+ if (psys->part && psys->part->type == PART_HAIR) {
+ if ((psys->flag & PSYS_HAIR_DYNAMICS) != 0 &&
+ (psys->pointcache->flag & PTCACHE_BAKED) != 0)
+ {
+ return psys->pointcache->edit;
+ }
+ else {
+ return psys->edit;
+ }
+ }
+ else if (psys->pointcache->flag & PTCACHE_BAKED) {
+ return psys->pointcache->edit;
+ }
+ return NULL;
+}
+
+/* NOTE: Similar to creation of edit, but only updates pointers in the
+ * existing struct.
+ */
+static void pe_update_hair_particle_edit_pointers(PTCacheEdit *edit)
+{
+ ParticleSystem *psys = edit->psys;
+ ParticleData *pa = psys->particles;
+ for (int p = 0; p < edit->totpoint; p++) {
+ PTCacheEditPoint *point = &edit->points[p];
+ HairKey *hair_key = pa->hair;
+ for (int k = 0; k < point->totkey; k++) {
+ PTCacheEditKey *key = &point->keys[k];
+ key->co = hair_key->co;
+ key->time = &hair_key->time;
+ key->flag = hair_key->editflag;
+ if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
+ key->flag |= PEK_USE_WCO;
+ hair_key->editflag |= PEK_USE_WCO;
+ }
+ hair_key++;
+ }
+ pa++;
+ }
+}
/* always gets at least the first particlesystem even if PSYS_CURRENT flag is not set
*
* note: this function runs on poll, therefor it can runs many times a second
* keep it fast! */
-static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int create)
+static PTCacheEdit *pe_get_current(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, int create)
{
ParticleEditSettings *pset = PE_settings(scene);
PTCacheEdit *edit = NULL;
@@ -204,7 +260,7 @@ static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int cr
pset->scene = scene;
pset->object = ob;
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0);
+ BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
/* in the case of only one editable thing, set pset->edittype accordingly */
if (BLI_listbase_is_single(&pidlist)) {
@@ -230,18 +286,21 @@ static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int cr
if (psys->part && psys->part->type == PART_HAIR) {
if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
if (create && !psys->pointcache->edit)
- PE_create_particle_edit(bmain, scene, ob, pid->cache, NULL);
+ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
edit = pid->cache->edit;
}
else {
- if (create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
- PE_create_particle_edit(bmain, scene, ob, NULL, psys);
+ if (create && !psys->edit) {
+ if (psys->flag & PSYS_HAIR_DONE) {
+ PE_create_particle_edit(depsgraph, scene, ob, NULL, psys);
+ }
+ }
edit = psys->edit;
}
}
else {
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
- PE_create_particle_edit(bmain, scene, ob, pid->cache, psys);
+ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, psys);
edit = pid->cache->edit;
}
@@ -252,7 +311,7 @@ static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int cr
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
pset->flag |= PE_FADE_TIME;
// NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
- PE_create_particle_edit(bmain, scene, ob, pid->cache, NULL);
+ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
}
edit = pid->cache->edit;
break;
@@ -261,35 +320,44 @@ static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int cr
if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
pset->flag |= PE_FADE_TIME;
// NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
- PE_create_particle_edit(bmain, scene, ob, pid->cache, NULL);
+ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
}
edit = pid->cache->edit;
break;
}
}
- if (edit)
+ if (edit) {
edit->pid = *pid;
+ if (edit->flags & PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL) {
+ if (edit->psys != NULL) {
+ psys_copy_particles(edit->psys, edit->psys_eval);
+ pe_update_hair_particle_edit_pointers(edit);
+ }
+ edit->flags &= ~PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL;
+ }
+ }
BLI_freelistN(&pidlist);
return edit;
}
-PTCacheEdit *PE_get_current(Main *bmain, Scene *scene, Object *ob)
+PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
{
- return pe_get_current(bmain, scene, ob, 0);
+ return pe_get_current(NULL, scene, ob, 0);
}
-PTCacheEdit *PE_create_current(Main *bmain, Scene *scene, Object *ob)
+PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- return pe_get_current(bmain, scene, ob, 1);
+ return pe_get_current(depsgraph, scene, ob, 1);
}
-void PE_current_changed(Main *bmain, Scene *scene, Object *ob)
+void PE_current_changed(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- if (ob->mode == OB_MODE_PARTICLE_EDIT)
- PE_create_current(bmain, scene, ob);
+ if (ob->mode == OB_MODE_PARTICLE_EDIT) {
+ PE_create_current(depsgraph, scene, ob);
+ }
}
void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
@@ -331,14 +399,18 @@ static int pe_x_mirror(Object *ob)
typedef struct PEData {
ViewContext vc;
- bglMats mats;
+ const bContext *context;
Main *bmain;
Scene *scene;
+ ViewLayer *view_layer;
Object *ob;
- DerivedMesh *dm;
+ Mesh *mesh;
PTCacheEdit *edit;
BVHTreeFromMesh shape_bvh;
+ Depsgraph *depsgraph;
+
+ RNG *rng;
const int *mval;
const rcti *rect;
@@ -346,6 +418,7 @@ typedef struct PEData {
float dist;
float dval;
int select;
+ eSelectOp sel_op;
float *dvec;
float combfac;
@@ -370,8 +443,10 @@ static void PE_set_data(bContext *C, PEData *data)
data->bmain = CTX_data_main(C);
data->scene = CTX_data_scene(C);
+ data->view_layer = CTX_data_view_layer(C);
data->ob = CTX_data_active_object(C);
- data->edit = PE_get_current(data->bmain, data->scene, data->ob);
+ data->depsgraph = CTX_data_depsgraph(C);
+ data->edit = PE_get_current(data->scene, data->ob);
}
static void PE_set_view3d_data(bContext *C, PEData *data)
@@ -379,8 +454,6 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
PE_set_data(C, data);
ED_view3d_viewcontext_init(C, &data->vc);
- /* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather than (obmat * viewmat) */
- view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
if (V3D_IS_ZBUF(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
@@ -398,15 +471,15 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
static bool PE_create_shape_tree(PEData *data, Object *shapeob)
{
- DerivedMesh *dm = shapeob->derivedFinal;
+ Mesh *mesh = BKE_object_get_evaluated_mesh(data->depsgraph, shapeob);
memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
- if (!dm) {
+ if (!mesh) {
return false;
}
- return (bvhtree_from_mesh_get(&data->shape_bvh, dm, BVHTREE_FROM_LOOPTRI, 4) != NULL);
+ return (BKE_bvhtree_from_mesh_get(&data->shape_bvh, mesh, BVHTREE_FROM_LOOPTRI, 4) != NULL);
}
static void PE_free_shape_tree(PEData *data)
@@ -414,13 +487,28 @@ static void PE_free_shape_tree(PEData *data)
free_bvhtree_from_mesh(&data->shape_bvh);
}
+static void PE_create_random_generator(PEData *data)
+{
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= POINTER_AS_UINT(data->ob);
+ rng_seed ^= POINTER_AS_UINT(data->edit);
+ data->rng = BLI_rng_new(rng_seed);
+}
+
+static void PE_free_random_generator(PEData *data)
+{
+ if (data->rng != NULL) {
+ BLI_rng_free(data->rng);
+ data->rng = NULL;
+ }
+}
+
/*************************** selection utilities *******************************/
static bool key_test_depth(PEData *data, const float co[3], const int screen_co[2])
{
View3D *v3d = data->vc.v3d;
ViewDepths *vd = data->vc.rv3d->depths;
- double ux, uy, uz;
float depth;
/* nothing to do */
@@ -436,9 +524,6 @@ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[
}
#endif
- gluProject(co[0], co[1], co[2], data->mats.modelview, data->mats.projection,
- (GLint *)data->mats.viewport, &ux, &uy, &uz);
-
/* check if screen_co is within bounds because brush_cut uses out of screen coords */
if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
BLI_assert(vd && vd->depths);
@@ -448,7 +533,10 @@ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[
else
return 0;
- if ((float)uz - 0.00001f > depth)
+ float win[3];
+ ED_view3d_project(data->vc.ar, co, win);
+
+ if (win[2] - 0.00001f > depth)
return 0;
else
return 1;
@@ -523,10 +611,15 @@ static bool point_is_selected(PTCacheEditPoint *point)
/*************************** iterators *******************************/
typedef void (*ForPointFunc)(PEData *data, int point_index);
-typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index);
+typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index, bool is_inside);
typedef void (*ForKeyMatFunc)(PEData *data, float mat[4][4], float imat[4][4], int point_index, int key_index, PTCacheEditKey *key);
-static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, bool nearest)
+enum eParticleSelectFlag {
+ PSEL_NEAREST = (1 << 0),
+ PSEL_ALL_KEYS = (1 << 1),
+};
+
+static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum eParticleSelectFlag flag)
{
ParticleEditSettings *pset = PE_settings(data->scene);
PTCacheEdit *edit = data->edit;
@@ -547,34 +640,45 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, bool nearest)
/* only do end keys */
key = point->keys + point->totkey - 1;
- if (nearest) {
+ if (flag & PSEL_NEAREST) {
if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
nearest_point = p;
nearest_key = point->totkey - 1;
}
}
- else if (key_inside_test(data, KEY_WCO))
- func(data, p, point->totkey - 1);
+ else {
+ const bool is_inside = key_inside_test(data, KEY_WCO);
+ if (is_inside || (flag & PSEL_ALL_KEYS)) {
+ func(data, p, point->totkey - 1, is_inside);
+ }
+ }
}
}
else {
/* do all keys */
LOOP_VISIBLE_KEYS {
- if (nearest) {
+ if (flag & PSEL_NEAREST) {
if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
nearest_point = p;
nearest_key = k;
}
}
- else if (key_inside_test(data, KEY_WCO))
- func(data, p, k);
+ else {
+ const bool is_inside = key_inside_test(data, KEY_WCO);
+ if (is_inside || (flag & PSEL_ALL_KEYS)) {
+ func(data, p, k, is_inside);
+ }
+ }
}
}
}
/* do nearest only */
- if (nearest && nearest_point > -1)
- func(data, nearest_point, nearest_key);
+ if (flag & PSEL_NEAREST) {
+ if (nearest_point != -1) {
+ func(data, nearest_point, nearest_key, true);
+ }
+ }
}
static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected)
@@ -612,61 +716,87 @@ static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selecte
}
}
-static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
+typedef struct KeyIterData {
+ PEData *data;
+ PTCacheEdit *edit;
+ int selected;
+ ForKeyMatFunc func;
+} KeyIterData;
+
+static void foreach_mouse_hit_key_iter(
+ void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
+ KeyIterData *iter_data = (KeyIterData *)iter_data_v;
+ PEData *data = iter_data->data;
PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if (point->flag & PEP_HIDE) {
+ return;
+ }
ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd = NULL;
+ ParticleSystemModifierData *psmd_eval = iter_data->edit->psmd_eval;
ParticleEditSettings *pset = PE_settings(data->scene);
- POINT_P; KEY_K;
+ const int selected = iter_data->selected;
float mat[4][4], imat[4][4];
-
unit_m4(mat);
unit_m4(imat);
-
- if (edit->psys)
- psmd = psys_get_modifier(data->ob, edit->psys);
-
- /* all is selected in path mode */
- if (pset->selectmode == SCE_SELECT_PATH)
- selected = 0;
-
- LOOP_VISIBLE_POINTS {
- if (pset->selectmode == SCE_SELECT_END) {
- if (point->totkey) {
- /* only do end keys */
- key = point->keys + point->totkey - 1;
-
- if (selected == 0 || key->flag & PEK_SELECT) {
- if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
- if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
- invert_m4_m4(imat, mat);
- }
-
- func(data, mat, imat, p, point->totkey - 1, key);
+ if (pset->selectmode == SCE_SELECT_END) {
+ if (point->totkey) {
+ /* only do end keys */
+ PTCacheEditKey *key = point->keys + point->totkey - 1;
+
+ if (selected == 0 || key->flag & PEK_SELECT) {
+ if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
+ if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
+ psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, mat);
+ invert_m4_m4(imat, mat);
}
+ iter_data->func(data, mat, imat, iter, point->totkey - 1, key);
}
}
}
- else {
- /* do all keys */
- LOOP_VISIBLE_KEYS {
- if (selected == 0 || key->flag & PEK_SELECT) {
- if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
- if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
- invert_m4_m4(imat, mat);
- }
-
- func(data, mat, imat, p, k, key);
+ }
+ else {
+ /* do all keys */
+ PTCacheEditKey *key;
+ int k;
+ LOOP_VISIBLE_KEYS {
+ if (selected == 0 || key->flag & PEK_SELECT) {
+ if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
+ if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
+ psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, mat);
+ invert_m4_m4(imat, mat);
}
+ iter_data->func(data, mat, imat, iter, k, key);
}
}
}
}
}
+static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
+{
+ PTCacheEdit *edit = data->edit;
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ /* all is selected in path mode */
+ if (pset->selectmode == SCE_SELECT_PATH) {
+ selected = 0;
+ }
+
+ KeyIterData iter_data;
+ iter_data.data = data;
+ iter_data.edit = edit;
+ iter_data.selected = selected;
+ iter_data.func = func;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings);
+}
+
static void foreach_selected_point(PEData *data, ForPointFunc func)
{
PTCacheEdit *edit = data->edit;
@@ -684,7 +814,7 @@ static void foreach_selected_key(PEData *data, ForKeyFunc func)
LOOP_VISIBLE_POINTS {
LOOP_SELECTED_KEYS {
- func(data, p, k);
+ func(data, p, k, true);
}
}
}
@@ -730,7 +860,7 @@ static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
{
PTCacheEdit *edit;
- ParticleSystemModifierData *psmd;
+ ParticleSystemModifierData *psmd_eval;
KDTree *tree;
KDTreeNearest nearest;
HairKey *key;
@@ -739,10 +869,10 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
int index, totpart;
edit = psys->edit;
- psmd = psys_get_modifier(ob, psys);
+ psmd_eval = edit->psmd_eval;
totpart = psys->totpart;
- if (!psmd->dm_final)
+ if (!psmd_eval->mesh_final)
return;
tree = BLI_kdtree_new(totpart);
@@ -750,7 +880,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
/* insert particles into kd tree */
LOOP_PARTICLES {
key = pa->hair;
- psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat);
+ psys_mat_hair_to_orco(ob, psmd_eval->mesh_final, psys->part->from, pa, mat);
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
BLI_kdtree_insert(tree, p, co);
@@ -764,7 +894,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
LOOP_PARTICLES {
key = pa->hair;
- psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat);
+ psys_mat_hair_to_orco(ob, psmd_eval->mesh_final, psys->part->from, pa, mat);
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
co[0] = -co[0];
@@ -790,7 +920,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
BLI_kdtree_free(tree);
}
-static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
+static void PE_mirror_particle(Object *ob, Mesh *mesh, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
{
HairKey *hkey, *mhkey;
PTCacheEditPoint *point, *mpoint;
@@ -841,8 +971,8 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys
}
/* mirror positions and tags */
- psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
- psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
+ psys_mat_hair_to_orco(ob, mesh, psys->part->from, pa, mat);
+ psys_mat_hair_to_orco(ob, mesh, psys->part->from, mpa, mmat);
invert_m4_m4(immat, mmat);
hkey = pa->hair;
@@ -870,16 +1000,16 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys
static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
{
PTCacheEdit *edit;
- ParticleSystemModifierData *psmd;
+ ParticleSystemModifierData *psmd_eval;
POINT_P;
if (!psys)
return;
edit = psys->edit;
- psmd = psys_get_modifier(ob, psys);
+ psmd_eval = edit->psmd_eval;
- if (!psmd->dm_final)
+ if (!psmd_eval->mesh_final)
return;
if (!edit->mirror_cache)
@@ -892,7 +1022,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
* to avoid doing mirror twice */
LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
- PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
if (edit->mirror_cache[p] != -1)
edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
@@ -909,110 +1039,152 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
/************************************************/
/* Edit Calculation */
/************************************************/
-/* tries to stop edited particles from going through the emitter's surface */
-static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
-{
- ParticleEditSettings *pset = PE_settings(scene);
+
+typedef struct DeflectEmitterIter {
+ Object *object;
ParticleSystem *psys;
- ParticleSystemModifierData *psmd;
- POINT_P; KEY_K;
+ PTCacheEdit *edit;
+ float dist;
+ float emitterdist;
+} DeflectEmitterIter;
+
+static void deflect_emitter_iter(
+ void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ DeflectEmitterIter *iter_data = (DeflectEmitterIter *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if ((point->flag & PEP_EDIT_RECALC) == 0) {
+ return;
+ }
+ Object *object = iter_data->object;
+ ParticleSystem *psys = iter_data->psys;
+ ParticleSystemModifierData *psmd_eval = iter_data->edit->psmd_eval;
+ PTCacheEditKey *key;
+ int k;
+ float hairimat[4][4], hairmat[4][4];
int index;
float *vec, *nor, dvec[3], dot, dist_1st = 0.0f;
- float hairimat[4][4], hairmat[4][4];
- const float dist = ED_view3d_select_dist_px() * 0.01f;
-
- if (edit == NULL || edit->psys == NULL || (pset->flag & PE_DEFLECT_EMITTER) == 0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
- return;
-
- psys = edit->psys;
- psmd = psys_get_modifier(ob, psys);
+ const float dist = iter_data->dist;
+ const float emitterdist = iter_data->emitterdist;
+ psys_mat_hair_to_object(object,
+ psmd_eval->mesh_final,
+ psys->part->from,
+ psys->particles + iter,
+ hairmat);
- if (!psmd->dm_final)
- return;
-
- LOOP_EDITED_POINTS {
- psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles + p, hairmat);
+ LOOP_KEYS {
+ mul_m4_v3(hairmat, key->co);
+ }
- LOOP_KEYS {
- mul_m4_v3(hairmat, key->co);
+ LOOP_KEYS {
+ if (k == 0) {
+ dist_1st = len_v3v3((key + 1)->co, key->co);
+ dist_1st *= dist * emitterdist;
}
+ else {
+ index = BLI_kdtree_find_nearest(edit->emitter_field, key->co, NULL);
- LOOP_KEYS {
- if (k == 0) {
- dist_1st = len_v3v3((key + 1)->co, key->co);
- dist_1st *= dist * pset->emitterdist;
- }
- else {
- index = BLI_kdtree_find_nearest(edit->emitter_field, key->co, NULL);
-
- vec = edit->emitter_cosnos + index * 6;
- nor = vec + 3;
+ vec = edit->emitter_cosnos + index * 6;
+ nor = vec + 3;
- sub_v3_v3v3(dvec, key->co, vec);
+ sub_v3_v3v3(dvec, key->co, vec);
- dot = dot_v3v3(dvec, nor);
- copy_v3_v3(dvec, nor);
+ dot = dot_v3v3(dvec, nor);
+ copy_v3_v3(dvec, nor);
- if (dot > 0.0f) {
- if (dot < dist_1st) {
- normalize_v3(dvec);
- mul_v3_fl(dvec, dist_1st - dot);
- add_v3_v3(key->co, dvec);
- }
- }
- else {
+ if (dot > 0.0f) {
+ if (dot < dist_1st) {
normalize_v3(dvec);
mul_v3_fl(dvec, dist_1st - dot);
add_v3_v3(key->co, dvec);
}
- if (k == 1)
- dist_1st *= 1.3333f;
+ }
+ else {
+ normalize_v3(dvec);
+ mul_v3_fl(dvec, dist_1st - dot);
+ add_v3_v3(key->co, dvec);
+ }
+ if (k == 1) {
+ dist_1st *= 1.3333f;
}
}
+ }
- invert_m4_m4(hairimat, hairmat);
+ invert_m4_m4(hairimat, hairmat);
- LOOP_KEYS {
- mul_m4_v3(hairimat, key->co);
- }
+ LOOP_KEYS {
+ mul_m4_v3(hairimat, key->co);
}
}
-/* force set distances between neighboring keys */
-static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
-{
+/* tries to stop edited particles from going through the emitter's surface */
+static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
+{
ParticleEditSettings *pset = PE_settings(scene);
- POINT_P; KEY_K;
- float dv1[3];
+ ParticleSystem *psys;
+ const float dist = ED_view3d_select_dist_px() * 0.01f;
- if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0)
+ if (edit == NULL || edit->psys == NULL ||
+ (pset->flag & PE_DEFLECT_EMITTER) == 0 ||
+ (edit->psys->flag & PSYS_GLOBAL_HAIR))
+ {
return;
+ }
- if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
+ psys = edit->psys;
+
+ if (!edit->psmd_eval->mesh_final) {
return;
+ }
- LOOP_EDITED_POINTS {
- LOOP_KEYS {
- if (k) {
- sub_v3_v3v3(dv1, key->co, (key - 1)->co);
- normalize_v3(dv1);
- mul_v3_fl(dv1, (key - 1)->length);
- add_v3_v3v3(key->co, (key - 1)->co, dv1);
- }
+ DeflectEmitterIter iter_data;
+ iter_data.object = ob;
+ iter_data.psys = psys;
+ iter_data.edit = edit;
+ iter_data.dist = dist;
+ iter_data.emitterdist = pset->emitterdist;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings);
+}
+
+typedef struct ApplyLengthsIterData {
+ PTCacheEdit *edit;
+} ApplyLengthsIterData;
+
+static void apply_lengths_iter(
+ void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ ApplyLengthsIterData *iter_data = (ApplyLengthsIterData *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if ((point->flag & PEP_EDIT_RECALC) == 0) {
+ return;
+ }
+ PTCacheEditKey *key;
+ int k;
+ LOOP_KEYS {
+ if (k) {
+ float dv1[3];
+ sub_v3_v3v3(dv1, key->co, (key - 1)->co);
+ normalize_v3(dv1);
+ mul_v3_fl(dv1, (key - 1)->length);
+ add_v3_v3v3(key->co, (key - 1)->co, dv1);
}
}
}
-/* try to find a nice solution to keep distances between neighboring keys */
-static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
+
+/* force set distances between neighboring keys */
+static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
{
ParticleEditSettings *pset = PE_settings(scene);
- POINT_P;
- PTCacheEditKey *key;
- int j, k;
- float tlen;
- float dv0[3] = {0.0f, 0.0f, 0.0f};
- float dv1[3] = {0.0f, 0.0f, 0.0f};
- float dv2[3] = {0.0f, 0.0f, 0.0f};
if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0)
return;
@@ -1020,43 +1192,91 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
return;
- LOOP_EDITED_POINTS {
- for (j = 1; j < point->totkey; j++) {
- float mul = 1.0f / (float)point->totkey;
-
- if (pset->flag & PE_LOCK_FIRST) {
- key = point->keys + 1;
- k = 1;
- dv1[0] = dv1[1] = dv1[2] = 0.0;
- }
- else {
- key = point->keys;
- k = 0;
- dv0[0] = dv0[1] = dv0[2] = 0.0;
- }
+ ApplyLengthsIterData iter_data;
+ iter_data.edit = edit;
- for (; k < point->totkey; k++, key++) {
- if (k) {
- sub_v3_v3v3(dv0, (key - 1)->co, key->co);
- tlen = normalize_v3(dv0);
- mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
- }
-
- if (k < point->totkey - 1) {
- sub_v3_v3v3(dv2, (key + 1)->co, key->co);
- tlen = normalize_v3(dv2);
- mul_v3_fl(dv2, mul * (tlen - key->length));
- }
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings);
+}
- if (k) {
- add_v3_v3((key - 1)->co, dv1);
- }
+typedef struct IterateLengthsIterData {
+ PTCacheEdit *edit;
+ ParticleEditSettings *pset;
+} IterateLengthsIterData;
+
+static void iterate_lengths_iter(
+ void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ IterateLengthsIterData *iter_data = (IterateLengthsIterData *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if ((point->flag & PEP_EDIT_RECALC) == 0) {
+ return;
+ }
+ ParticleEditSettings *pset = iter_data->pset;
+ float tlen;
+ float dv0[3] = {0.0f, 0.0f, 0.0f};
+ float dv1[3] = {0.0f, 0.0f, 0.0f};
+ float dv2[3] = {0.0f, 0.0f, 0.0f};
+ for (int j = 1; j < point->totkey; j++) {
+ PTCacheEditKey *key;
+ int k;
+ float mul = 1.0f / (float)point->totkey;
+ if (pset->flag & PE_LOCK_FIRST) {
+ key = point->keys + 1;
+ k = 1;
+ dv1[0] = dv1[1] = dv1[2] = 0.0;
+ }
+ else {
+ key = point->keys;
+ k = 0;
+ dv0[0] = dv0[1] = dv0[2] = 0.0;
+ }
- add_v3_v3v3(dv1, dv0, dv2);
+ for (; k < point->totkey; k++, key++) {
+ if (k) {
+ sub_v3_v3v3(dv0, (key - 1)->co, key->co);
+ tlen = normalize_v3(dv0);
+ mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
+ }
+ if (k < point->totkey - 1) {
+ sub_v3_v3v3(dv2, (key + 1)->co, key->co);
+ tlen = normalize_v3(dv2);
+ mul_v3_fl(dv2, mul * (tlen - key->length));
}
+ if (k) {
+ add_v3_v3((key - 1)->co, dv1);
+ }
+ add_v3_v3v3(dv1, dv0, dv2);
}
}
}
+
+/* try to find a nice solution to keep distances between neighboring keys */
+static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
+{
+ ParticleEditSettings *pset = PE_settings(scene);
+ if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0) {
+ return;
+ }
+ if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) {
+ return;
+ }
+
+ IterateLengthsIterData iter_data;
+ iter_data.edit = edit;
+ iter_data.pset = pset;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
+}
+
/* set current distances to be kept between neighbouting keys */
void recalc_lengths(PTCacheEdit *edit)
{
@@ -1074,14 +1294,14 @@ void recalc_lengths(PTCacheEdit *edit)
}
/* calculate a tree for finding nearest emitter's vertice */
-void recalc_emitter_field(Object *ob, ParticleSystem *psys)
+void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), ParticleSystem *psys)
{
- DerivedMesh *dm = psys_get_modifier(ob, psys)->dm_final;
PTCacheEdit *edit = psys->edit;
+ Mesh *mesh = edit->psmd_eval->mesh_final;
float *vec, *nor;
int i, totface /*, totvert*/;
- if (!dm)
+ if (!mesh)
return;
if (edit->emitter_cosnos)
@@ -1089,8 +1309,8 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys)
BLI_kdtree_free(edit->emitter_field);
- totface = dm->getNumTessFaces(dm);
- /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/
+ totface = mesh->totface;
+ /*totvert=dm->getNumVerts(dm);*/ /*UNUSED*/
edit->emitter_cosnos = MEM_callocN(totface * 6 * sizeof(float), "emitter cosnos");
@@ -1100,23 +1320,23 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys)
nor = vec + 3;
for (i = 0; i < totface; i++, vec += 6, nor += 6) {
- MFace *mface = dm->getTessFaceData(dm, i, CD_MFACE);
+ MFace *mface = &mesh->mface[i];
MVert *mvert;
- mvert = dm->getVertData(dm, mface->v1, CD_MVERT);
+ mvert = &mesh->mvert[mface->v1];
copy_v3_v3(vec, mvert->co);
VECCOPY(nor, mvert->no);
- mvert = dm->getVertData(dm, mface->v2, CD_MVERT);
+ mvert = &mesh->mvert[mface->v2];
add_v3_v3v3(vec, vec, mvert->co);
VECADD(nor, nor, mvert->no);
- mvert = dm->getVertData(dm, mface->v3, CD_MVERT);
+ mvert = &mesh->mvert[mface->v3];
add_v3_v3v3(vec, vec, mvert->co);
VECADD(nor, nor, mvert->no);
if (mface->v4) {
- mvert = dm->getVertData(dm, mface->v4, CD_MVERT);
+ mvert = &mesh->mvert[mface->v4];
add_v3_v3v3(vec, vec, mvert->co);
VECADD(nor, nor, mvert->no);
@@ -1133,9 +1353,9 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys)
BLI_kdtree_balance(edit->emitter_field);
}
-static void PE_update_selection(Main *bmain, Scene *scene, Object *ob, int useflag)
+static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
{
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
HairKey *hkey;
POINT_P; KEY_K;
@@ -1157,28 +1377,30 @@ static void PE_update_selection(Main *bmain, Scene *scene, Object *ob, int usefl
}
}
- psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
+ psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
+
+ DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE);
}
-void update_world_cos(Object *ob, PTCacheEdit *edit)
+void update_world_cos(Depsgraph *UNUSED(depsgraph), Object *ob, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
POINT_P; KEY_K;
float hairmat[4][4];
- if (psys == 0 || psys->edit == 0 || psmd->dm_final == NULL)
+ if (psys == 0 || psys->edit == 0 || psmd_eval->mesh_final == NULL)
return;
LOOP_POINTS {
if (!(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + p, hairmat);
+ psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat);
LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
@@ -1244,12 +1466,12 @@ static void update_velocities(PTCacheEdit *edit)
}
}
-void PE_update_object(Main *bmain, Scene *scene, Object *ob, int useflag)
+void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
{
/* use this to do partial particle updates, not usable when adding or
* removing, then a full redo is necessary and calling this may crash */
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
POINT_P;
if (!edit)
@@ -1268,13 +1490,13 @@ void PE_update_object(Main *bmain, Scene *scene, Object *ob, int useflag)
if (pe_x_mirror(ob))
PE_apply_mirror(ob, edit->psys);
if (edit->psys)
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
if (pset->flag & PE_AUTO_VELOCITY)
update_velocities(edit);
PE_hide_keys_time(scene, edit, CFRA);
/* regenerate path caches */
- psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
+ psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
@@ -1291,7 +1513,7 @@ void PE_update_object(Main *bmain, Scene *scene, Object *ob, int useflag)
/*-----selection callbacks-----*/
-static void select_key(PEData *data, int point_index, int key_index)
+static void select_key(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
{
PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index;
@@ -1305,7 +1527,20 @@ static void select_key(PEData *data, int point_index, int key_index)
point->flag |= PEP_EDIT_RECALC;
}
-static void select_keys(PEData *data, int point_index, int UNUSED(key_index))
+static void select_key_op(PEData *data, int point_index, int key_index, bool is_inside)
+{
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ PTCacheEditKey *key = point->keys + key_index;
+ const bool is_select = key->flag & PEK_SELECT;
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
+ point->flag |= PEP_EDIT_RECALC;
+ }
+}
+
+static void select_keys(PEData *data, int point_index, int UNUSED(key_index), bool UNUSED(is_inside))
{
PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index;
@@ -1321,7 +1556,7 @@ static void select_keys(PEData *data, int point_index, int UNUSED(key_index))
point->flag |= PEP_EDIT_RECALC;
}
-static void extend_key_select(PEData *data, int point_index, int key_index)
+static void extend_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
{
PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index;
@@ -1331,7 +1566,7 @@ static void extend_key_select(PEData *data, int point_index, int key_index)
point->flag |= PEP_EDIT_RECALC;
}
-static void deselect_key_select(PEData *data, int point_index, int key_index)
+static void deselect_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
{
PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index;
@@ -1341,7 +1576,7 @@ static void deselect_key_select(PEData *data, int point_index, int key_index)
point->flag |= PEP_EDIT_RECALC;
}
-static void toggle_key_select(PEData *data, int point_index, int key_index)
+static void toggle_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
{
PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index;
@@ -1383,10 +1618,10 @@ static void select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, in
static int pe_select_all_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
POINT_P; KEY_K;
int action = RNA_enum_get(op->ptr, "action");
@@ -1409,7 +1644,7 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
}
}
- PE_update_selection(bmain, scene, ob, 1);
+ PE_update_selection(depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1436,11 +1671,10 @@ void PARTICLE_OT_select_all(wmOperatorType *ot)
int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
- Main *bmain = CTX_data_main(C);
PEData data;
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
POINT_P; KEY_K;
if (!PE_start_edit(edit))
@@ -1460,14 +1694,17 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec
data.rad = ED_view3d_select_dist_px();
/* 1 = nearest only */
- if (extend)
- for_mouse_hit_keys(&data, extend_key_select, true);
- else if (deselect)
- for_mouse_hit_keys(&data, deselect_key_select, true);
- else
- for_mouse_hit_keys(&data, toggle_key_select, true);
+ if (extend) {
+ for_mouse_hit_keys(&data, extend_key_select, PSEL_NEAREST);
+ }
+ else if (deselect) {
+ for_mouse_hit_keys(&data, deselect_key_select, PSEL_NEAREST);
+ }
+ else {
+ for_mouse_hit_keys(&data, toggle_key_select, PSEL_NEAREST);
+ }
- PE_update_selection(bmain, scene, ob, 1);
+ PE_update_selection(data.depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1508,7 +1745,7 @@ static int select_roots_exec(bContext *C, wmOperator *op)
data.select_action = action;
foreach_point(&data, select_root);
- PE_update_selection(data.bmain, data.scene, data.ob, 1);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1573,7 +1810,7 @@ static int select_tips_exec(bContext *C, wmOperator *op)
data.select_action = action;
foreach_point(&data, select_tip);
- PE_update_selection(data.bmain, data.scene, data.ob, 1);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1628,7 +1865,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
PE_set_data(C, &data);
data.select_action = SEL_SELECT;
- edit = PE_get_current(data.bmain, data.scene, data.ob);
+ edit = PE_get_current(data.scene, data.ob);
rng = BLI_rng_new_srandom(seed);
@@ -1653,7 +1890,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
BLI_rng_free(rng);
- PE_update_selection(data.bmain, data.scene, data.ob, 1);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1696,8 +1933,8 @@ static int select_linked_exec(bContext *C, wmOperator *op)
data.rad = 75.0f;
data.select = !RNA_boolean_get(op->ptr, "deselect");
- for_mouse_hit_keys(&data, select_keys, true);
- PE_update_selection(data.bmain, data.scene, data.ob, 1);
+ for_mouse_hit_keys(&data, select_keys, PSEL_NEAREST);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -1729,7 +1966,7 @@ void PARTICLE_OT_select_linked(wmOperatorType *ot)
RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
}
-/************************ border select operator ************************/
+/************************ box select operator ************************/
void PE_deselect_all_visible(PTCacheEdit *edit)
{
POINT_P; KEY_K;
@@ -1742,27 +1979,27 @@ void PE_deselect_all_visible(PTCacheEdit *edit)
}
}
-int PE_border_select(bContext *C, const rcti *rect, bool select, bool extend)
+int PE_box_select(bContext *C, const rcti *rect, const int sel_op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
PEData data;
if (!PE_start_edit(edit))
return OPERATOR_CANCELLED;
- if (extend == 0 && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
PE_deselect_all_visible(edit);
+ }
PE_set_view3d_data(C, &data);
data.rect = rect;
- data.select = select;
+ data.sel_op = sel_op;
- for_mouse_hit_keys(&data, select_key, false);
+ for_mouse_hit_keys(&data, select_key_op, PSEL_ALL_KEYS);
- PE_update_selection(bmain, scene, ob, 1);
+ PE_update_selection(data.depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1772,10 +2009,9 @@ int PE_border_select(bContext *C, const rcti *rect, bool select, bool extend)
int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
PEData data;
if (!PE_start_edit(edit))
@@ -1786,9 +2022,9 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
data.rad = rad;
data.select = selecting;
- for_mouse_hit_keys(&data, select_key, false);
+ for_mouse_hit_keys(&data, select_key, 0);
- PE_update_selection(bmain, scene, ob, 1);
+ PE_update_selection(data.depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1796,16 +2032,15 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
/************************ lasso select operator ************************/
-int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool extend, bool select)
+int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ARegion *ar = CTX_wm_region(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
POINT_P; KEY_K;
float co[3], mat[4][4];
int screen_co[2];
@@ -1817,67 +2052,53 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool
if (!PE_start_edit(edit))
return OPERATOR_CANCELLED;
- if (extend == 0 && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
PE_deselect_all_visible(edit);
+ }
/* only for depths */
PE_set_view3d_data(C, &data);
LOOP_VISIBLE_POINTS {
if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
if (pset->selectmode == SCE_SELECT_POINT) {
LOOP_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
- if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
- key_test_depth(&data, co, screen_co))
- {
- if (select) {
- if (!(key->flag & PEK_SELECT)) {
- key->flag |= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- }
- }
- else {
- if (key->flag & PEK_SELECT) {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- }
- }
+ const bool is_select = key->flag & PEK_SELECT;
+ const bool is_inside = (
+ (ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
+ BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ key_test_depth(&data, co, screen_co));
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
+ point->flag |= PEP_EDIT_RECALC;
}
}
}
else if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
key = point->keys + point->totkey - 1;
-
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
- if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
- key_test_depth(&data, co, screen_co))
- {
- if (select) {
- if (!(key->flag & PEK_SELECT)) {
- key->flag |= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- }
- }
- else {
- if (key->flag & PEK_SELECT) {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- }
- }
+ const bool is_select = key->flag & PEK_SELECT;
+ const bool is_inside = (
+ (ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
+ BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ key_test_depth(&data, co, screen_co));
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
+ point->flag |= PEP_EDIT_RECALC;
}
}
}
}
- PE_update_selection(bmain, scene, ob, 1);
+ PE_update_selection(data.depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1887,12 +2108,14 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool
static int hide_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ PTCacheEdit *edit = PE_get_current(scene, ob);
POINT_P; KEY_K;
+
if (RNA_enum_get(op->ptr, "unselected")) {
LOOP_UNSELECTED_POINTS {
point->flag |= PEP_HIDE;
@@ -1914,7 +2137,7 @@ static int hide_exec(bContext *C, wmOperator *op)
}
}
- PE_update_selection(bmain, scene, ob, 1);
+ PE_update_selection(depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -1942,10 +2165,10 @@ void PARTICLE_OT_hide(wmOperatorType *ot)
static int reveal_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
const bool select = RNA_boolean_get(op->ptr, "select");
POINT_P; KEY_K;
@@ -1960,7 +2183,7 @@ static int reveal_exec(bContext *C, wmOperator *op)
}
}
- PE_update_selection(bmain, scene, ob, 1);
+ PE_update_selection(depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
return OPERATOR_FINISHED;
@@ -2022,7 +2245,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
PE_set_data(C, &data);
foreach_point(&data, select_less_keys);
- PE_update_selection(data.bmain, data.scene, data.ob, 1);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -2084,7 +2307,7 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
PE_set_data(C, &data);
foreach_point(&data, select_more_keys);
- PE_update_selection(data.bmain, data.scene, data.ob, 1);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
return OPERATOR_FINISHED;
@@ -2120,6 +2343,7 @@ static void rekey_particle(PEData *data, int pa_index)
float dval, sta, end;
int k;
+ sim.depsgraph = data->depsgraph;
sim.scene = data->scene;
sim.ob = data->ob;
sim.psys = edit->psys;
@@ -2181,7 +2405,7 @@ static int rekey_exec(bContext *C, wmOperator *op)
foreach_selected_point(&data, rekey_particle);
recalc_lengths(data.edit);
- PE_update_object(data.bmain, data.scene, data.ob, 1);
+ PE_update_object(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -2206,9 +2430,9 @@ void PARTICLE_OT_rekey(wmOperatorType *ot)
RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
}
-static void rekey_particle_to_time(Main *bmain, Scene *scene, Object *ob, int pa_index, float path_time)
+static void rekey_particle_to_time(const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
{
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys;
ParticleSimulationData sim = {0};
ParticleData *pa;
@@ -2221,6 +2445,7 @@ static void rekey_particle_to_time(Main *bmain, Scene *scene, Object *ob, int pa
psys = edit->psys;
+ sim.depsgraph = CTX_data_depsgraph(C);
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -2260,15 +2485,15 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
ParticleData *pa, *npa = 0, *new_pars = 0;
POINT_P;
PTCacheEditPoint *npoint = 0, *new_points = 0;
- ParticleSystemModifierData *psmd;
+ ParticleSystemModifierData *psmd_eval;
int i, new_totpart = psys->totpart, removed = 0;
if (mirror) {
/* mirror tags */
- psmd = psys_get_modifier(ob, psys);
+ psmd_eval = edit->psmd_eval;
LOOP_TAGGED_POINTS {
- PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
}
}
@@ -2339,16 +2564,16 @@ static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
HairKey *hkey, *nhkey, *new_hkeys = 0;
POINT_P; KEY_K;
PTCacheEditKey *nkey, *new_keys;
- ParticleSystemModifierData *psmd;
+ ParticleSystemModifierData *psmd_eval;
short new_totkey;
if (pe_x_mirror(ob)) {
/* mirror key tags */
- psmd = psys_get_modifier(ob, psys);
+ psmd_eval = psys_get_modifier(ob, psys);
LOOP_POINTS {
LOOP_TAGGED_KEYS {
- PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
break;
}
}
@@ -2438,6 +2663,7 @@ static void subdivide_particle(PEData *data, int pa_index)
short totnewkey = 0;
float endtime;
+ sim.depsgraph = data->depsgraph;
sim.scene = data->scene;
sim.ob = data->ob;
sim.psys = edit->psys;
@@ -2512,7 +2738,7 @@ static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
foreach_point(&data, subdivide_particle);
recalc_lengths(data.edit);
- PE_update_object(data.bmain, data.scene, data.ob, 1);
+ PE_update_object(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -2537,12 +2763,11 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot)
static int remove_doubles_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd;
+ ParticleSystemModifierData *psmd_eval;
KDTree *tree;
KDTreeNearest nearest[10];
POINT_P;
@@ -2553,7 +2778,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
edit = psys->edit;
- psmd = psys_get_modifier(ob, psys);
+ psmd_eval = edit->psmd_eval;
totremoved = 0;
do {
@@ -2563,7 +2788,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
/* insert particles into kd tree */
LOOP_SELECTED_POINTS {
- psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_object(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
mul_m4_v3(mat, co);
BLI_kdtree_insert(tree, p, co);
@@ -2573,7 +2798,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
/* tag particles to be removed */
LOOP_SELECTED_POINTS {
- psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_object(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
mul_m4_v3(mat, co);
@@ -2602,7 +2827,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
return OPERATOR_FINISHED;
@@ -2630,11 +2855,10 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
static int weight_set_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ParticleEditSettings *pset = PE_settings(scene);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
POINT_P;
KEY_K;
@@ -2655,7 +2879,7 @@ static int weight_set_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
return OPERATOR_FINISHED;
@@ -2687,24 +2911,27 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)
ParticleEditSettings *pset = PE_settings(scene);
ParticleBrushData *brush;
- if (pset->brushtype < 0)
+ if (pset->brushtype < 0) {
return;
+ }
brush = &pset->brush[pset->brushtype];
if (brush) {
- glPushMatrix();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glTranslatef((float)x, (float)y, 0.0f);
+ immUniformColor4ub(255, 255, 255, 128);
- glColor4ub(255, 255, 255, 128);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, pe_brush_size_get(scene, brush), 40);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ GPU_line_smooth(true);
+ GPU_blend(true);
- glPopMatrix();
+ imm_draw_circle_wire_2d(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40);
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+
+ immUnbindProgram();
}
}
@@ -2717,7 +2944,12 @@ static void toggle_particle_cursor(bContext *C, int enable)
pset->paintcursor = NULL;
}
else if (enable)
- pset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_view3d, brush_drawcursor, NULL);
+ pset->paintcursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_VIEW3D, RGN_TYPE_WINDOW,
+ PE_poll_view3d,
+ brush_drawcursor,
+ NULL);
}
/*************************** delete operator **************************/
@@ -2737,7 +2969,7 @@ static void set_delete_particle(PEData *data, int pa_index)
edit->points[pa_index].flag |= PEP_TAG;
}
-static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
+static void set_delete_particle_key(PEData *data, int pa_index, int key_index, bool UNUSED(is_inside))
{
PTCacheEdit *edit = data->edit;
@@ -2762,7 +2994,7 @@ static int delete_exec(bContext *C, wmOperator *op)
recalc_lengths(data.edit);
}
- DAG_id_tag_update(&data.ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&data.ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -2789,11 +3021,12 @@ void PARTICLE_OT_delete(wmOperatorType *ot)
/*************************** mirror operator **************************/
-static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged)
+static void PE_mirror_x(
+ Scene *scene, Object *ob, int tagged)
{
Mesh *me = (Mesh *)(ob->data);
- ParticleSystemModifierData *psmd;
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ ParticleSystemModifierData *psmd_eval;
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit->psys;
ParticleData *pa, *newpa, *new_pars;
PTCacheEditPoint *newpoint, *new_points;
@@ -2805,18 +3038,18 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged)
if (psys->flag & PSYS_GLOBAL_HAIR)
return;
- psmd = psys_get_modifier(ob, psys);
- if (!psmd->dm_final)
+ psmd_eval = edit->psmd_eval;
+ if (!psmd_eval->mesh_final)
return;
- const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly);
+ const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only);
/* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
BKE_mesh_tessface_ensure(me);
- /* Note: In case psys uses DM tessface indices, we mirror final DM itself, not orig mesh. Avoids an (impossible)
- * dm -> orig -> dm tessface indices conversion... */
- mirrorfaces = mesh_get_x_mirror_faces(ob, NULL, use_dm_final_indices ? psmd->dm_final : NULL);
+ /* Note: In case psys uses Mesh tessface indices, we mirror final Mesh itself, not orig mesh. Avoids an (impossible)
+ * mesh -> orig -> mesh tessface indices conversion... */
+ mirrorfaces = mesh_get_x_mirror_faces(ob, NULL, use_dm_final_indices ? psmd_eval->mesh_final : NULL);
if (!edit->mirror_cache)
PE_update_mirror_cache(ob, psys);
@@ -2830,7 +3063,7 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged)
if (point_is_selected(point)) {
if (edit->mirror_cache[p] != -1) {
/* already has a mirror, don't need to duplicate */
- PE_mirror_particle(ob, psmd->dm_final, psys, pa, NULL);
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, NULL);
continue;
}
else
@@ -2843,7 +3076,7 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged)
}
if (newtotpart != psys->totpart) {
- MFace *mtessface = use_dm_final_indices ? psmd->dm_final->getTessFaceArray(psmd->dm_final) : me->mface;
+ MFace *mtessface = use_dm_final_indices ? psmd_eval->mesh_final->mface : me->mface;
/* allocate new arrays and copy existing */
new_pars = MEM_callocN(newtotpart * sizeof(ParticleData), "ParticleData new");
@@ -2912,7 +3145,7 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged)
}
else {
newpa->num_dmcache = psys_particle_dm_face_lookup(
- psmd->dm_final, psmd->dm_deformed, newpa->num, newpa->fuv, NULL);
+ psmd_eval->mesh_final, psmd_eval->mesh_original, newpa->num, newpa->fuv, NULL);
}
/* update edit key pointers */
@@ -2923,7 +3156,7 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged)
}
/* map key positions as mirror over x axis */
- PE_mirror_particle(ob, psmd->dm_final, psys, pa, newpa);
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, newpa);
newpa++;
newpoint++;
@@ -2939,16 +3172,15 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged)
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
- PE_mirror_x(bmain, scene, ob, 0);
+ PE_mirror_x(scene, ob, 0);
- update_world_cos(ob, edit);
+ update_world_cos(CTX_data_depsgraph(C), ob, edit);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
@@ -2999,8 +3231,11 @@ static void brush_cut(PEData *data, int pa_index)
int k, cut, keys = (int)pow(2.0, (double)pset->draw_step);
int screen_co[2];
+ BLI_assert(data->rng != NULL);
/* blunt scissors */
- if (BLI_frand() > data->cutfac) return;
+ if (BLI_rng_get_float(data->rng) > data->cutfac) {
+ return;
+ }
/* don't cut hidden */
if (edit->points[pa_index].flag & PEP_HIDE)
@@ -3081,7 +3316,7 @@ static void brush_cut(PEData *data, int pa_index)
edit->points[pa_index].flag |= PEP_TAG;
}
else {
- rekey_particle_to_time(data->bmain, data->scene, ob, pa_index, cut_time);
+ rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
edit->points[pa_index].flag |= PEP_EDIT_RECALC;
}
}
@@ -3134,7 +3369,7 @@ static void brush_puff(PEData *data, int point_index)
}
if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
+ psys_mat_hair_to_global(data->ob, data->mesh, psys->part->from, psys->particles + point_index, mat);
invert_m4_m4(imat, mat);
}
else {
@@ -3328,13 +3563,13 @@ static void intersect_dm_quad_weights(const float v1[3], const float v2[3], cons
interp_weights_poly_v3(w, vert, 4, co);
}
-/* check intersection with a derivedmesh */
-static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
- float *vert_cos,
- const float co1[3], const float co2[3],
- float *min_d, int *min_face, float *min_w,
- float *face_minmax, float *pa_minmax,
- float radius, float *ipoint)
+/** Check intersection with an evaluated mesh. */
+static int particle_intersect_mesh(Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh,
+ float *vert_cos,
+ const float co1[3], const float co2[3],
+ float *min_d, int *min_face, float *min_w,
+ float *face_minmax, float *pa_minmax,
+ float radius, float *ipoint)
{
MFace *mface = NULL;
MVert *mvert = NULL;
@@ -3342,21 +3577,23 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
float cur_d, cur_uv[2], v1[3], v2[3], v3[3], v4[3], min[3], max[3], p_min[3], p_max[3];
float cur_ipoint[3];
- if (dm == NULL) {
+ if (mesh == NULL) {
psys_disable_all(ob);
- dm = mesh_get_derived_final(scene, ob, 0);
- if (dm == NULL)
- dm = mesh_get_derived_deform(scene, ob, 0);
+ mesh = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH);
+ if (mesh == NULL) {
+ mesh = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
+ }
psys_enable_all(ob);
- if (dm == NULL)
+ if (mesh == NULL) {
return 0;
+ }
}
/* BMESH_ONLY, deform dm may not have tessface */
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
if (pa_minmax == 0) {
@@ -3369,9 +3606,9 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
copy_v3_v3(p_max, pa_minmax + 3);
}
- totface = dm->getNumTessFaces(dm);
- mface = dm->getTessFaceDataArray(dm, CD_MFACE);
- mvert = dm->getVertDataArray(dm, CD_MVERT);
+ totface = mesh->totface;
+ mface = mesh->mface;
+ mvert = mesh->mvert;
/* lets intersect the faces */
for (i = 0; i < totface; i++, mface++) {
@@ -3460,24 +3697,126 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
return intersect;
}
-static int brush_add(PEData *data, short number)
+typedef struct BrushAddCountIterData {
+ Depsgraph *depsgraph;
+ Scene *scene;
+ Object *object;
+ Mesh *mesh;
+ PEData *data;
+ int number;
+ short size;
+ float imat[4][4];
+ ParticleData *add_pars;
+ int num_added;
+} BrushAddCountIterData;
+
+typedef struct BrushAddCountIterTLSData {
+ RNG *rng;
+ int num_added;
+} BrushAddCountIterTLSData;
+
+static void brush_add_count_iter(
+ void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict tls_v)
+{
+ BrushAddCountIterData *iter_data = (BrushAddCountIterData *)iter_data_v;
+ Depsgraph *depsgraph = iter_data->depsgraph;
+ PEData *data = iter_data->data;
+ PTCacheEdit *edit = data->edit;
+ ParticleSystem *psys = edit->psys;
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ ParticleData *add_pars = iter_data->add_pars;
+ BrushAddCountIterTLSData *tls = tls_v->userdata_chunk;
+ const int number = iter_data->number;
+ const short size = iter_data->size;
+ const short size2 = size * size;
+ float dmx, dmy;
+ if (number > 1) {
+ dmx = size;
+ dmy = size;
+ if (tls->rng == NULL) {
+ tls->rng = BLI_rng_new_srandom(
+ psys->seed + data->mval[0] + data->mval[1] + tls_v->thread_id);
+ }
+ /* rejection sampling to get points in circle */
+ while (dmx * dmx + dmy * dmy > size2) {
+ dmx = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
+ dmy = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
+ }
+ }
+ else {
+ dmx = 0.0f;
+ dmy = 0.0f;
+ }
+
+ float mco[2];
+ mco[0] = data->mval[0] + dmx;
+ mco[1] = data->mval[1] + dmy;
+
+ float co1[3], co2[3];
+ ED_view3d_win_to_segment_clipped(depsgraph, data->vc.ar, data->vc.v3d, mco, co1, co2, true);
+
+ mul_m4_v3(iter_data->imat, co1);
+ mul_m4_v3(iter_data->imat, co2);
+ float min_d = 2.0;
+
+ /* warning, returns the derived mesh face */
+ BLI_assert(iter_data->mesh != NULL);
+ if (particle_intersect_mesh(depsgraph, iter_data->scene, iter_data->object, iter_data->mesh,
+ 0, co1, co2,
+ &min_d,
+ &add_pars[iter].num_dmcache,
+ add_pars[iter].fuv,
+ 0, 0, 0, 0))
+ {
+ if (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only) {
+ add_pars[iter].num = add_pars[iter].num_dmcache;
+ add_pars[iter].num_dmcache = DMCACHE_ISCHILD;
+ }
+ else if (iter_data->mesh == psmd_eval->mesh_original) {
+ /* Final DM is not same topology as orig mesh, we have to map num_dmcache to real final dm. */
+ add_pars[iter].num = add_pars[iter].num_dmcache;
+ add_pars[iter].num_dmcache = psys_particle_dm_face_lookup(
+ psmd_eval->mesh_final, psmd_eval->mesh_original,
+ add_pars[iter].num, add_pars[iter].fuv, NULL);
+ }
+ else {
+ add_pars[iter].num = add_pars[iter].num_dmcache;
+ }
+ if (add_pars[iter].num != DMCACHE_NOTFOUND) {
+ tls->num_added++;
+ }
+ }
+}
+
+static void brush_add_count_iter_finalize(void *__restrict userdata_v,
+ void *__restrict userdata_chunk_v)
{
+ BrushAddCountIterData *iter_data = (BrushAddCountIterData *)userdata_v;
+ BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)userdata_chunk_v;
+ iter_data->num_added += tls->num_added;
+ if (tls->rng != NULL) {
+ BLI_rng_free(tls->rng);
+ }
+}
+
+static int brush_add(const bContext *C, PEData *data, short number)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = data->scene;
Object *ob = data->ob;
- DerivedMesh *dm;
+ Mesh *mesh;
PTCacheEdit *edit = data->edit;
ParticleSystem *psys = edit->psys;
ParticleData *add_pars;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
ParticleSimulationData sim = {0};
ParticleEditSettings *pset = PE_settings(scene);
int i, k, n = 0, totpart = psys->totpart;
- float mco[2];
- float dmx, dmy;
- float co1[3], co2[3], min_d, imat[4][4];
+ float co1[3], imat[4][4];
float framestep, timestep;
short size = pset->brush[PE_BRUSH_ADD].size;
- short size2 = size * size;
RNG *rng;
invert_m4_m4(imat, ob->obmat);
@@ -3489,67 +3828,66 @@ static int brush_add(PEData *data, short number)
rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1]);
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
- sim.psmd = psmd;
+ sim.psmd = psmd_eval;
timestep = psys_get_timestep(&sim);
- if (psys->part->use_modifier_stack || psmd->dm_final->deformedOnly) {
- dm = psmd->dm_final;
+ if (psys->part->use_modifier_stack || psmd_eval->mesh_final->runtime.deformed_only) {
+ mesh = psmd_eval->mesh_final;
}
else {
- dm = psmd->dm_deformed;
+ mesh = psmd_eval->mesh_original;
}
- BLI_assert(dm);
-
- for (i = 0; i < number; i++) {
- if (number > 1) {
- dmx = size;
- dmy = size;
-
- /* rejection sampling to get points in circle */
- while (dmx * dmx + dmy * dmy > size2) {
- dmx = (2.0f * BLI_rng_get_float(rng) - 1.0f) * size;
- dmy = (2.0f * BLI_rng_get_float(rng) - 1.0f) * size;
- }
+ BLI_assert(mesh);
+
+ /* Calculate positions of new particles to add, based on brush interseciton
+ * with object. New particle data is assigned to a corresponding to check
+ * index element of add_pars array. This means, that add_pars is a sparse
+ * array.
+ */
+ BrushAddCountIterData iter_data;
+ iter_data.depsgraph = depsgraph;
+ iter_data.scene = scene;
+ iter_data.object = ob;
+ iter_data.mesh = mesh;
+ iter_data.data = data;
+ iter_data.number = number;
+ iter_data.size = size;
+ iter_data.add_pars = add_pars;
+ iter_data.num_added = 0;
+ copy_m4_m4(iter_data.imat, imat);
+
+ BrushAddCountIterTLSData tls = {NULL};
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ settings.userdata_chunk = &tls;
+ settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData);
+ settings.func_finalize = brush_add_count_iter_finalize;
+ BLI_task_parallel_range(0, number, &iter_data, brush_add_count_iter, &settings);
+
+ /* Convert add_parse to a dense array, where all new particles are in the
+ * beginnign of the array.
+ */
+ n = iter_data.num_added;
+ for (int current_iter = 0, new_index = 0; current_iter < number; current_iter++) {
+ if (add_pars[current_iter].num == DMCACHE_NOTFOUND) {
+ continue;
}
- else {
- dmx = 0.0f;
- dmy = 0.0f;
- }
-
- mco[0] = data->mval[0] + dmx;
- mco[1] = data->mval[1] + dmy;
- ED_view3d_win_to_segment_clipped(data->vc.ar, data->vc.v3d, mco, co1, co2, true);
-
- mul_m4_v3(imat, co1);
- mul_m4_v3(imat, co2);
- min_d = 2.0;
-
- /* warning, returns the derived mesh face */
- if (particle_intersect_dm(scene, ob, dm, 0, co1, co2, &min_d, &add_pars[n].num_dmcache, add_pars[n].fuv, 0, 0, 0, 0)) {
- if (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly) {
- add_pars[n].num = add_pars[n].num_dmcache;
- add_pars[n].num_dmcache = DMCACHE_ISCHILD;
- }
- else if (dm == psmd->dm_deformed) {
- /* Final DM is not same topology as orig mesh, we have to map num_dmcache to real final dm. */
- add_pars[n].num = add_pars[n].num_dmcache;
- add_pars[n].num_dmcache = psys_particle_dm_face_lookup(
- psmd->dm_final, psmd->dm_deformed,
- add_pars[n].num, add_pars[n].fuv, NULL);
- }
- else {
- add_pars[n].num = add_pars[n].num_dmcache;
- }
-
- if (add_pars[n].num != DMCACHE_NOTFOUND) {
- n++;
- }
+ if (new_index != current_iter) {
+ new_index++;
+ continue;
}
+ memcpy(add_pars + new_index, add_pars + current_iter, sizeof(ParticleData));
+ new_index++;
}
+
+ /* TODO(sergey): Consider multi-threading this part as well. */
if (n) {
int newtotpart = totpart + n;
float hairmat[4][4], cur_co[3];
@@ -3580,7 +3918,7 @@ static int brush_add(PEData *data, short number)
tree = BLI_kdtree_new(psys->totpart);
for (i = 0, pa = psys->particles; i < totpart; i++, pa++) {
- psys_particle_on_dm(psmd->dm_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, cur_co, 0, 0, 0, 0, 0);
+ psys_particle_on_dm(psmd_eval->mesh_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, cur_co, 0, 0, 0, 0);
BLI_kdtree_insert(tree, i, cur_co);
}
@@ -3624,7 +3962,7 @@ static int brush_add(PEData *data, short number)
int w, maxw;
float maxd, totw = 0.0, weight[3];
- psys_particle_on_dm(psmd->dm_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0, 0);
+ psys_particle_on_dm(psmd_eval->mesh_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0);
maxw = BLI_kdtree_find_nearest_n(tree, co1, ptn, 3);
maxd = ptn[maxw - 1].dist;
@@ -3689,7 +4027,7 @@ static int brush_add(PEData *data, short number)
}
}
for (k = 0, hkey = pa->hair; k < pset->totaddkey; k++, hkey++) {
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
mul_m4_v3(imat, hkey->co);
}
@@ -3710,6 +4048,7 @@ static int brush_add(PEData *data, short number)
typedef struct BrushEdit {
Scene *scene;
+ ViewLayer *view_layer;
Object *ob;
PTCacheEdit *edit;
@@ -3723,11 +4062,11 @@ typedef struct BrushEdit {
static int brush_edit_init(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ARegion *ar = CTX_wm_region(C);
BrushEdit *bedit;
float min[3], max[3];
@@ -3737,7 +4076,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
/* set the 'distance factor' for grabbing (used in comb etc) */
INIT_MINMAX(min, max);
- PE_minmax(bmain, scene, min, max);
+ PE_minmax(scene, view_layer, min, max);
mid_v3_v3v3(min, min, max);
bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit");
@@ -3745,6 +4084,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
op->customdata = bedit;
bedit->scene = scene;
+ bedit->view_layer = view_layer;
bedit->ob = ob;
bedit->edit = edit;
@@ -3752,19 +4092,20 @@ static int brush_edit_init(bContext *C, wmOperator *op)
/* cache view depths and settings for re-use */
PE_set_view3d_data(C, &bedit->data);
+ PE_create_random_generator(&bedit->data);
return 1;
}
static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
- Main *bmain = CTX_data_main(C);
BrushEdit *bedit = op->customdata;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = bedit->scene;
Object *ob = bedit->ob;
PTCacheEdit *edit = bedit->edit;
ParticleEditSettings *pset = PE_settings(scene);
- ParticleSystemModifierData *psmd = edit->psys ? psys_get_modifier(ob, edit->psys) : NULL;
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
ParticleBrushData *brush = &pset->brush[pset->brushtype];
ARegion *ar = CTX_wm_region(C);
float vec[3], mousef[2];
@@ -3801,6 +4142,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
(sqrtf(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0)) || bedit->first)
{
PEData data = bedit->data;
+ data.context = C; // TODO(mai): why isnt this set in bedit->data?
view3d_operator_needs_opengl(C);
selected = (short)count_selected_keys(scene, edit);
@@ -3878,7 +4220,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
case PE_BRUSH_PUFF:
{
if (edit->psys) {
- data.dm = psmd->dm_final;
+ data.mesh = psmd_eval->mesh_final;
data.mval = mval;
data.rad = pe_brush_size_get(scene, brush);
data.select = selected;
@@ -3901,7 +4243,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (edit->psys && edit->psys->part->from == PART_FROM_FACE) {
data.mval = mval;
- added = brush_add(&data, brush->count);
+ added = brush_add(C, &data, brush->count);
if (pset->flag & PE_KEEP_LENGTHS)
recalc_lengths(edit);
@@ -3934,7 +4276,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
case PE_BRUSH_WEIGHT:
{
if (edit->psys) {
- data.dm = psmd->dm_final;
+ data.mesh = psmd_eval->mesh_final;
data.mval = mval;
data.rad = pe_brush_size_get(scene, brush);
@@ -3951,21 +4293,24 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob))
- PE_mirror_x(bmain, scene, ob, 1);
+ PE_mirror_x(scene, ob, 1);
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
psys_free_path_cache(NULL, edit);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else {
+ PE_update_object(depsgraph, scene, ob, 1);
}
- else
- PE_update_object(bmain, scene, ob, 1);
}
if (edit->psys) {
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE);
}
else {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
@@ -3981,6 +4326,7 @@ static void brush_edit_exit(wmOperator *op)
{
BrushEdit *bedit = op->customdata;
+ PE_free_random_generator(&bedit->data);
MEM_freeN(bedit);
}
@@ -4176,7 +4522,7 @@ static void shape_cut(PEData *data, int pa_index)
edit->points[pa_index].flag |= PEP_TAG;
}
else {
- rekey_particle_to_time(data->bmain, data->scene, ob, pa_index, cut_time);
+ rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
edit->points[pa_index].flag |= PEP_EDIT_RECALC;
}
}
@@ -4184,11 +4530,11 @@ static void shape_cut(PEData *data, int pa_index)
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
Object *shapeob = pset->shape_object;
int selected = count_selected_keys(scene, edit);
int lock_root = pset->flag & PE_LOCK_FIRST;
@@ -4219,18 +4565,21 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
recalc_lengths(edit);
if (removed) {
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
psys_free_path_cache(NULL, edit);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else {
+ PE_update_object(data.depsgraph, scene, ob, 1);
}
- else
- PE_update_object(bmain, scene, ob, 1);
if (edit->psys) {
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE);
}
else {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
@@ -4259,12 +4608,12 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
/************************ utilities ******************************/
-int PE_minmax(Main *bmain, Scene *scene, float min[3], float max[3])
+int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
{
- Object *ob = OBACT;
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ Object *ob = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys;
- ParticleSystemModifierData *psmd = NULL;
+ ParticleSystemModifierData *psmd_eval = NULL;
POINT_P; KEY_K;
float co[3], mat[4][4];
int ok = 0;
@@ -4272,13 +4621,13 @@ int PE_minmax(Main *bmain, Scene *scene, float min[3], float max[3])
if (!edit) return ok;
if ((psys = edit->psys))
- psmd = psys_get_modifier(ob, psys);
+ psmd_eval = edit->psmd_eval;
else
unit_m4(mat);
LOOP_VISIBLE_POINTS {
if (psys)
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
LOOP_SELECTED_KEYS {
copy_v3_v3(co, key->co);
@@ -4298,18 +4647,44 @@ int PE_minmax(Main *bmain, Scene *scene, float min[3], float max[3])
/************************ particle edit toggle operator ************************/
+static struct ParticleSystem *psys_eval_get(
+ Depsgraph *depsgraph,
+ Object *object,
+ ParticleSystem *psys)
+{
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
+ if (object_eval == object) {
+ return psys;
+ }
+ ParticleSystem *psys_eval = object_eval->particlesystem.first;
+ while (psys_eval != NULL) {
+ if (psys_eval->orig_psys == psys) {
+ return psys_eval;
+ }
+ psys_eval = psys_eval->next;
+ }
+ return psys_eval;
+}
+
/* initialize needed data for bake edit */
-void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
+void PE_create_particle_edit(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
PTCacheEdit *edit;
ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
+ ParticleSystemModifierData *psmd_eval = NULL;
POINT_P; KEY_K;
ParticleData *pa = NULL;
HairKey *hkey;
int totpoint;
+ if (psmd != NULL) {
+ psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
+ }
+
/* no psmd->dm happens in case particle system modifier is not enabled */
- if (!(psys && psmd && psmd->dm_final) && !cache)
+ if (!(psys && psmd && psmd_eval->mesh_final) && !cache)
return;
if (cache && cache->flag & PTCACHE_DISK_CACHE)
@@ -4321,6 +4696,9 @@ void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache *
edit = (psys) ? psys->edit : cache->edit;
if (!edit) {
+ ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
+ psys_copy_particles(psys, psys_eval);
+
totpoint = psys ? psys->totpart : (int)((PTCacheMem *)cache->mem_cache.first)->totpoint;
edit = MEM_callocN(sizeof(PTCacheEdit), "PE_create_particle_edit");
@@ -4328,8 +4706,11 @@ void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache *
edit->totpoint = totpoint;
if (psys && !cache) {
+ edit->psmd = psmd;
+ edit->psmd_eval = psmd_eval;
psys->edit = edit;
edit->psys = psys;
+ edit->psys_eval = psys_eval;
psys->free_edit = PE_free_ptcache_edit;
@@ -4356,7 +4737,7 @@ void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache *
}
pa++;
}
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
}
else {
PTCacheMem *pm;
@@ -4394,13 +4775,19 @@ void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache *
psys = NULL;
}
+ /* Causes assert on startup. */
+#if 0
UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
-
+#else
+ memset(edit->sel_col, 0xff, sizeof(edit->sel_col));
+ memset(edit->nosel_col, 0x00, sizeof(edit->nosel_col));
+#endif
recalc_lengths(edit);
if (psys && !cache)
- recalc_emitter_field(ob, psys);
- PE_update_object(bmain, scene, ob, 1);
+ recalc_emitter_field(depsgraph, ob, psys);
+
+ PE_update_object(depsgraph, scene, ob, 1);
}
}
@@ -4422,7 +4809,8 @@ static bool particle_edit_toggle_poll(bContext *C)
static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_PARTICLE_EDIT;
@@ -4436,13 +4824,23 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
if (!is_mode_set) {
PTCacheEdit *edit;
+
ob->mode |= mode_flag;
- edit = PE_create_current(bmain, scene, ob);
- /* mesh may have changed since last entering editmode.
- * note, this may have run before if the edit data was just created, so could avoid this and speed up a little */
- if (edit && edit->psys)
- recalc_emitter_field(ob, edit->psys);
+ edit = PE_create_current(depsgraph, scene, ob);
+
+ /* Mesh may have changed since last entering editmode.
+ * note, this may have run before if the edit data was just created,
+ * so could avoid this and speed up a little. */
+ if (edit && edit->psys) {
+ /* Make sure pointer to the evaluated modifier data is up to date,
+ * with possible changes applied when object was outside of the
+ * edit mode. */
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ edit->psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(
+ object_eval, edit->psmd->modifier.name);
+ recalc_emitter_field(depsgraph, ob, edit->psys);
+ }
toggle_particle_cursor(C, 1);
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL);
@@ -4453,7 +4851,11 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE);
+
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
return OPERATOR_FINISHED;
}
@@ -4494,7 +4896,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
psys_reset(psys, PSYS_RESET_DEPSGRAPH);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
else { /* some operation might have protected hair from editing so let's clear the flag */
@@ -4502,7 +4904,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
psys->flag &= ~PSYS_GLOBAL_HAIR;
psys->flag &= ~PSYS_EDITED;
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
return OPERATOR_FINISHED;
@@ -4603,22 +5005,24 @@ static void scale_points_to_length(PTCacheEdit *edit, float length)
static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ PTCacheEdit *edit = PE_get_current(scene, ob);
float average_length = calculate_average_length(edit);
+
if (average_length == 0.0f) {
return OPERATOR_CANCELLED;
}
scale_points_to_length(edit, average_length);
- PE_update_object(bmain, scene, ob, 1);
+ PE_update_object(depsgraph, scene, ob, 1);
if (edit->psys) {
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
}
else {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 1b4aeabc71b..56b683e1ab8 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -45,12 +45,12 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_main.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "ED_object.h"
#include "ED_particle.h"
#include "ED_physics.h"
@@ -229,27 +229,27 @@ typedef struct ParticleUndoStep {
static bool particle_undosys_poll(struct bContext *C)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = OBACT;
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+
return (edit != NULL);
}
static bool particle_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
- Main *bmain = CTX_data_main(C);
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
us->scene_ref.ptr = CTX_data_scene(C);
- us->object_ref.ptr = us->scene_ref.ptr->basact->object;
- PTCacheEdit *edit = PE_get_current(bmain, us->scene_ref.ptr, us->object_ref.ptr);
+ us->object_ref.ptr = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
undoptcache_from_editcache(&us->data, edit);
return true;
}
static void particle_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
{
- Main *bmain = CTX_data_main(C);
/* TODO(campbell): undo_system: use low-level API to set mode. */
ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
BLI_assert(particle_undosys_poll(C));
@@ -257,10 +257,10 @@ static void particle_undosys_step_decode(struct bContext *C, UndoStep *us_p, int
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
Scene *scene = us->scene_ref.ptr;
Object *ob = us->object_ref.ptr;
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
if (edit) {
undoptcache_to_editcache(&us->data, edit);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else {
BLI_assert(0);
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index e6b8ac596e9..228bf2c648f 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
@@ -42,19 +43,22 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BKE_bvhutils.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -112,6 +116,7 @@ static int particle_system_remove_exec(bContext *C, wmOperator *UNUSED(op))
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_context(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
int mode_orig;
if (!scene || !ob)
@@ -125,7 +130,7 @@ static int particle_system_remove_exec(bContext *C, wmOperator *UNUSED(op))
*/
if (mode_orig & OB_MODE_PARTICLE_EDIT) {
if ((ob->mode & OB_MODE_PARTICLE_EDIT) == 0) {
- if (scene->basact && scene->basact->object == ob) {
+ if (view_layer->basact && view_layer->basact->object == ob) {
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
}
}
@@ -187,8 +192,8 @@ static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op))
psys_check_boid_data(psys);
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, ob);
@@ -235,8 +240,8 @@ static int new_particle_target_exec(bContext *C, wmOperator *UNUSED(op))
BLI_addtail(&psys->targets, pt);
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, ob);
@@ -283,8 +288,8 @@ static int remove_particle_target_exec(bContext *C, wmOperator *UNUSED(op))
if (pt)
pt->flag |= PTARGET_CURRENT;
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, ob);
@@ -323,7 +328,7 @@ static int target_move_up_exec(bContext *C, wmOperator *UNUSED(op))
BLI_remlink(&psys->targets, pt);
BLI_insertlinkbefore(&psys->targets, pt->prev, pt);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, ob);
break;
}
@@ -361,7 +366,7 @@ static int target_move_down_exec(bContext *C, wmOperator *UNUSED(op))
BLI_remlink(&psys->targets, pt);
BLI_insertlinkafter(&psys->targets, pt->next, pt);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, ob);
break;
}
@@ -382,6 +387,35 @@ void PARTICLE_OT_target_move_down(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/************************ refresh dupli objects *********************/
+
+static int dupliob_refresh_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
+ ParticleSystem *psys = ptr.data;
+
+ if (!psys)
+ return OPERATOR_CANCELLED;
+
+ psys_check_group_weights(psys->part);
+ DEG_id_tag_update(&psys->part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_dupliob_refresh(wmOperatorType *ot)
+{
+ ot->name = "Refresh Dupli Objects";
+ ot->idname = "PARTICLE_OT_dupliob_refresh";
+ ot->description = "Refresh list of dupli objects and their weights";
+
+ ot->exec = dupliob_refresh_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/************************ move up particle dupliweight operator *********************/
static int dupliob_move_up_exec(bContext *C, wmOperator *UNUSED(op))
@@ -400,6 +434,7 @@ static int dupliob_move_up_exec(bContext *C, wmOperator *UNUSED(op))
BLI_remlink(&part->dupliweights, dw);
BLI_insertlinkbefore(&part->dupliweights, dw->prev, dw);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, NULL);
break;
}
@@ -439,6 +474,7 @@ static int copy_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
dw->flag |= PART_DUPLIW_CURRENT;
BLI_addhead(&part->dupliweights, dw);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, NULL);
break;
}
@@ -485,6 +521,7 @@ static int remove_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
if (dw)
dw->flag |= PART_DUPLIW_CURRENT;
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, NULL);
return OPERATOR_FINISHED;
@@ -522,6 +559,7 @@ static int dupliob_move_down_exec(bContext *C, wmOperator *UNUSED(op))
BLI_remlink(&part->dupliweights, dw);
BLI_insertlinkafter(&part->dupliweights, dw->next, dw);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, NULL);
break;
}
@@ -544,7 +582,9 @@ void PARTICLE_OT_dupliob_move_down(wmOperatorType *ot)
/************************ connect/disconnect hair operators *********************/
-static void disconnect_hair(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys)
+static void disconnect_hair(
+ Depsgraph *depsgraph, Scene *scene,
+ Object *ob, ParticleSystem *psys)
{
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
ParticleEditSettings *pset = PE_settings(scene);
@@ -571,7 +611,7 @@ static void disconnect_hair(Main *bmain, Scene *scene, Object *ob, ParticleSyste
point++;
}
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat);
for (k = 0, key = pa->hair; k < pa->totkey; k++, key++) {
mul_m4_v3(hairmat, key->co);
@@ -590,12 +630,12 @@ static void disconnect_hair(Main *bmain, Scene *scene, Object *ob, ParticleSyste
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_PUFF))
pset->brushtype = PE_BRUSH_NONE;
- PE_update_object(bmain, scene, ob, 0);
+ PE_update_object(depsgraph, scene, ob, 0);
}
static int disconnect_hair_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_context(C);
ParticleSystem *psys = NULL;
@@ -606,15 +646,15 @@ static int disconnect_hair_exec(bContext *C, wmOperator *op)
if (all) {
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- disconnect_hair(bmain, scene, ob, psys);
+ disconnect_hair(depsgraph, scene, ob, psys);
}
}
else {
psys = psys_get_current(ob);
- disconnect_hair(bmain, scene, ob, psys);
+ disconnect_hair(depsgraph, scene, ob, psys);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, ob);
return OPERATOR_FINISHED;
@@ -637,9 +677,10 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
/* from/to_world_space : whether from/to particles are in world or hair space
* from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
*/
-static bool remap_hair_emitter(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys,
- Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit,
- float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
+static bool remap_hair_emitter(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys,
+ Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit,
+ float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
{
ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys);
ParticleData *pa, *tpa;
@@ -649,13 +690,13 @@ static bool remap_hair_emitter(Main *bmain, Scene *scene, Object *ob, ParticleSy
MFace *mface = NULL, *mf;
MEdge *medge = NULL, *me;
MVert *mvert;
- DerivedMesh *dm, *target_dm;
+ Mesh *mesh, *target_mesh;
int numverts;
int i, k;
float from_ob_imat[4][4], to_ob_imat[4][4];
float from_imat[4][4], to_imat[4][4];
- if (!target_psmd->dm_final)
+ if (!target_psmd->mesh_final)
return false;
if (!psys->part || psys->part->type != PART_HAIR)
return false;
@@ -669,40 +710,46 @@ static bool remap_hair_emitter(Main *bmain, Scene *scene, Object *ob, ParticleSy
invert_m4_m4(from_imat, from_mat);
invert_m4_m4(to_imat, to_mat);
- if (target_psmd->dm_final->deformedOnly) {
+ if (target_psmd->mesh_final->runtime.deformed_only) {
/* we don't want to mess up target_psmd->dm when converting to global coordinates below */
- dm = target_psmd->dm_final;
+ mesh = target_psmd->mesh_final;
}
else {
- dm = target_psmd->dm_deformed;
+ mesh = target_psmd->mesh_original;
}
- target_dm = target_psmd->dm_final;
- if (dm == NULL) {
+ target_mesh = target_psmd->mesh_final;
+ if (mesh == NULL) {
return false;
}
/* don't modify the original vertices */
- dm = CDDM_copy(dm);
+ BKE_id_copy_ex(
+ NULL, &mesh->id, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
/* BMESH_ONLY, deform dm may not have tessface */
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
- numverts = dm->getNumVerts(dm);
- mvert = dm->getVertArray(dm);
+ numverts = mesh->totvert;
+ mvert = mesh->mvert;
/* convert to global coordinates */
for (i = 0; i < numverts; i++)
mul_m4_v3(to_mat, mvert[i].co);
- if (dm->getNumTessFaces(dm) != 0) {
- mface = dm->getTessFaceArray(dm);
- bvhtree_from_mesh_get(&bvhtree, dm, BVHTREE_FROM_FACES, 2);
+ if (mesh->totface != 0) {
+ mface = mesh->mface;
+ BKE_bvhtree_from_mesh_get(&bvhtree, mesh, BVHTREE_FROM_FACES, 2);
}
- else if (dm->getNumEdges(dm) != 0) {
- medge = dm->getEdgeArray(dm);
- bvhtree_from_mesh_get(&bvhtree, dm, BVHTREE_FROM_EDGES, 2);
+ else if (mesh->totedge != 0) {
+ medge = mesh->medge;
+ BKE_bvhtree_from_mesh_get(&bvhtree, mesh, BVHTREE_FROM_EDGES, 2);
}
else {
- dm->release(dm);
+ BKE_id_free(NULL, mesh);
return false;
}
@@ -747,7 +794,7 @@ static bool remap_hair_emitter(Main *bmain, Scene *scene, Object *ob, ParticleSy
tpa->foffset = 0.0f;
tpa->num = nearest.index;
- tpa->num_dmcache = psys_particle_dm_face_lookup(target_dm, dm, tpa->num, tpa->fuv, NULL);
+ tpa->num_dmcache = psys_particle_dm_face_lookup(target_mesh, mesh, tpa->num, tpa->fuv, NULL);
}
else {
me = &medge[nearest.index];
@@ -773,7 +820,7 @@ static bool remap_hair_emitter(Main *bmain, Scene *scene, Object *ob, ParticleSy
copy_m4_m4(imat, target_ob->obmat);
else {
/* note: using target_dm here, which is in target_ob object space and has full modifiers */
- psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat);
+ psys_mat_hair_to_object(target_ob, target_mesh, target_psys->part->from, tpa, hairmat);
invert_m4_m4(imat, hairmat);
}
mul_m4_m4m4(imat, imat, to_imat);
@@ -819,24 +866,27 @@ static bool remap_hair_emitter(Main *bmain, Scene *scene, Object *ob, ParticleSy
}
free_bvhtree_from_mesh(&bvhtree);
- dm->release(dm);
+ BKE_id_free(NULL, mesh);
psys_free_path_cache(target_psys, target_edit);
- PE_update_object(bmain, scene, target_ob, 0);
+ PE_update_object(depsgraph, scene, target_ob, 0);
return true;
}
-static bool connect_hair(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys)
+static bool connect_hair(
+ Depsgraph *depsgraph, Scene *scene,
+ Object *ob, ParticleSystem *psys)
{
bool ok;
if (!psys)
return false;
- ok = remap_hair_emitter(bmain, scene, ob, psys, ob, psys, psys->edit,
- ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false);
+ ok = remap_hair_emitter(
+ depsgraph, scene, ob, psys, ob, psys, psys->edit,
+ ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false);
psys->flag &= ~PSYS_GLOBAL_HAIR;
return ok;
@@ -844,7 +894,7 @@ static bool connect_hair(Main *bmain, Scene *scene, Object *ob, ParticleSystem *
static int connect_hair_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_context(C);
ParticleSystem *psys = NULL;
@@ -856,12 +906,12 @@ static int connect_hair_exec(bContext *C, wmOperator *op)
if (all) {
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- any_connected |= connect_hair(bmain, scene, ob, psys);
+ any_connected |= connect_hair(depsgraph, scene, ob, psys);
}
}
else {
psys = psys_get_current(ob);
- any_connected |= connect_hair(bmain, scene, ob, psys);
+ any_connected |= connect_hair(depsgraph, scene, ob, psys);
}
if (!any_connected) {
@@ -870,7 +920,7 @@ static int connect_hair_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE, ob);
return OPERATOR_FINISHED;
@@ -897,7 +947,9 @@ typedef enum eCopyParticlesSpace {
PAR_COPY_SPACE_WORLD = 1,
} eCopyParticlesSpace;
-static void copy_particle_edit(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
+static void copy_particle_edit(
+ Depsgraph *depsgraph, Scene *scene,
+ Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
{
PTCacheEdit *edit_from = psys_from->edit, *edit;
ParticleData *pa;
@@ -937,14 +989,14 @@ static void copy_particle_edit(Main *bmain, Scene *scene, Object *ob, ParticleSy
pa++;
}
- update_world_cos(ob, edit);
+ update_world_cos(depsgraph, ob, edit);
UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
recalc_lengths(edit);
- recalc_emitter_field(ob, psys);
- PE_update_object(bmain, scene, ob, true);
+ recalc_emitter_field(depsgraph, ob, psys);
+ PE_update_object(depsgraph, scene, ob, true);
}
static void remove_particle_systems_from_object(Object *ob_to)
@@ -972,7 +1024,7 @@ static void remove_particle_systems_from_object(Object *ob_to)
}
/* single_psys_from is optional, if NULL all psys of ob_from are copied */
-static bool copy_particle_systems_to_object(Main *bmain,
+static bool copy_particle_systems_to_object(const bContext *C,
Scene *scene,
Object *ob_from,
ParticleSystem *single_psys_from,
@@ -980,10 +1032,12 @@ static bool copy_particle_systems_to_object(Main *bmain,
int space,
bool duplicate_settings)
{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ModifierData *md;
ParticleSystem *psys_start = NULL, *psys, *psys_from;
ParticleSystem **tmp_psys;
- DerivedMesh *final_dm;
+ Mesh *final_mesh;
CustomDataMask cdmask;
int i, totpsys;
@@ -1024,8 +1078,8 @@ static bool copy_particle_systems_to_object(Main *bmain,
*/
psys_start = totpsys > 0 ? tmp_psys[0] : NULL;
- /* get the DM (psys and their modifiers have not been appended yet) */
- final_dm = mesh_get_derived_final(scene, ob_to, cdmask);
+ /* Get the evaluated mesh (psys and their modifiers have not been appended yet) */
+ final_mesh = mesh_get_eval_final(depsgraph, scene, ob_to, cdmask);
/* now append psys to the object and make modifiers */
for (i = 0, psys_from = PSYS_FROM_FIRST;
@@ -1049,12 +1103,20 @@ static bool copy_particle_systems_to_object(Main *bmain,
modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
psmd->psys = psys;
- psmd->dm_final = CDDM_copy(final_dm);
- CDDM_calc_normals(psmd->dm_final);
- DM_ensure_tessface(psmd->dm_final);
-
- if (psys_from->edit)
- copy_particle_edit(bmain, scene, ob_to, psys, psys_from);
+ BKE_id_copy_ex(
+ NULL, &final_mesh->id, (ID **)&psmd->mesh_final,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+
+ BKE_mesh_calc_normals(psmd->mesh_final);
+ BKE_mesh_tessface_ensure(psmd->mesh_final);
+
+ if (psys_from->edit) {
+ copy_particle_edit(depsgraph, scene, ob_to, psys, psys_from);
+ }
if (duplicate_settings) {
id_us_min(&psys->part->id);
@@ -1089,7 +1151,7 @@ static bool copy_particle_systems_to_object(Main *bmain,
}
if (ob_from != ob_to) {
remap_hair_emitter(
- bmain, scene, ob_from, psys_from, ob_to, psys, psys->edit,
+ depsgraph, scene, ob_from, psys_from, ob_to, psys, psys->edit,
from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR);
}
@@ -1100,7 +1162,7 @@ static bool copy_particle_systems_to_object(Main *bmain,
#undef PSYS_FROM_FIRST
#undef PSYS_FROM_NEXT
- DAG_id_tag_update(&ob_to->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_to->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to);
return true;
}
@@ -1123,7 +1185,6 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
const int space = RNA_enum_get(op->ptr, "space");
const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
const bool use_active = RNA_boolean_get(op->ptr, "use_active");
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob_from = ED_object_active_context(C);
ParticleSystem *psys_from = use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data : NULL;
@@ -1139,7 +1200,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op)
remove_particle_systems_from_object(ob_to);
changed = true;
}
- if (copy_particle_systems_to_object(bmain, scene, ob_from, psys_from, ob_to, space, false))
+ if (copy_particle_systems_to_object(C, scene, ob_from, psys_from, ob_to, space, false))
changed = true;
else
fail++;
@@ -1200,14 +1261,14 @@ static int duplicate_particle_systems_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
ParticleSystem *psys = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
- copy_particle_systems_to_object(CTX_data_main(C), scene, ob, psys, ob,
+ copy_particle_systems_to_object(C, scene, ob, psys, ob,
PAR_COPY_SPACE_OBJECT, duplicate_settings);
return OPERATOR_FINISHED;
}
void PARTICLE_OT_duplicate_particle_system(wmOperatorType *ot)
{
- ot->name = "Duplicate Particle Systems";
+ ot->name = "Duplicate Particle System";
ot->description = "Duplicate particle system within the active object";
ot->idname = "PARTICLE_OT_duplicate_particle_system";
@@ -1218,5 +1279,5 @@ void PARTICLE_OT_duplicate_particle_system(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_duplicate_settings", false, "Duplicate Settings",
- "Duplicate settings as well, so new particle system uses own settings");
+ "Duplicate settings as well, so the new particle system uses its own settings");
}
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index f960d6ed97b..4279cfd5101 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -55,6 +55,8 @@
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
#include "LBM_fluidsim.h"
#include "ED_screen.h"
@@ -246,7 +248,7 @@ static void set_channel(float *channel, float time, float *value, int i, int siz
}
}
-static void set_vertex_channel(float *channel, float time, struct Scene *scene, struct FluidObject *fobj, int i)
+static void set_vertex_channel(Depsgraph *depsgraph, float *channel, float time, struct Scene *scene, struct FluidObject *fobj, int i)
{
Object *ob = fobj->object;
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
@@ -259,7 +261,7 @@ static void set_vertex_channel(float *channel, float time, struct Scene *scene,
if (channel == NULL)
return;
- initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex);
+ initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex);
/* don't allow mesh to change number of verts in anim sequence */
if (numVerts != fobj->numVerts) {
@@ -331,6 +333,8 @@ static void free_all_fluidobject_channels(ListBase *fobjects)
static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), FluidsimSettings *domainSettings, FluidAnimChannels *channels, ListBase *fobjects)
{
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Base *base;
int i;
int length = channels->length;
@@ -345,7 +349,7 @@ static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), Fluid
channels->DomainTime = MEM_callocN(length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainTime");
/* allocate fluid objects */
- for (base=scene->base.first; base; base= base->next) {
+ for (base = FIRSTBASE(view_layer); base; base = base->next) {
Object *ob = base->object;
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
@@ -375,7 +379,7 @@ static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), Fluid
float *verts=NULL;
int *tris=NULL, modifierIndex = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd);
- initElbeemMesh(scene, ob, &fobj->numVerts, &verts, &fobj->numTris, &tris, 0, modifierIndex);
+ initElbeemMesh(depsgraph, scene, ob, &fobj->numVerts, &verts, &fobj->numTris, &tris, 0, modifierIndex);
fobj->VertexCache = MEM_callocN(length *((fobj->numVerts*CHANNEL_VEC)+1) * sizeof(float), "fluidobject VertexCache");
MEM_freeN(verts);
@@ -404,7 +408,7 @@ static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), Fluid
/* Modifying the global scene isn't nice, but we can do it in
* this part of the process before a threaded job is created */
scene->r.cfra = (int)eval_time;
- ED_update_for_newframe(CTX_data_main(C), scene, 1);
+ ED_update_for_newframe(CTX_data_main(C), depsgraph);
/* now scene data should be current according to animation system, so we fill the channels */
@@ -463,14 +467,15 @@ static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), Fluid
}
if (fluid_is_animated_mesh(fluidmd->fss)) {
- set_vertex_channel(fobj->VertexCache, timeAtFrame, scene, fobj, i);
+ set_vertex_channel(depsgraph, fobj->VertexCache, timeAtFrame, scene, fobj, i);
}
}
}
}
-static void export_fluid_objects(ListBase *fobjects, Scene *scene, int length)
+static void export_fluid_objects(const bContext *C, ListBase *fobjects, Scene *scene, int length)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
FluidObject *fobj;
for (fobj=fobjects->first; fobj; fobj=fobj->next) {
@@ -493,7 +498,7 @@ static void export_fluid_objects(ListBase *fobjects, Scene *scene, int length)
fsmesh.type = fluidmd->fss->type;
fsmesh.name = ob->id.name;
- initElbeemMesh(scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex);
+ initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex);
fsmesh.numVertices = numVerts;
fsmesh.numTriangles = numTris;
@@ -572,14 +577,14 @@ static void export_fluid_objects(ListBase *fobjects, Scene *scene, int length)
}
}
-static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDomain)
+static int fluid_validate_scene(ReportList *reports, ViewLayer *view_layer, Object *fsDomain)
{
Base *base;
Object *newdomain = NULL;
int channelObjCount = 0;
int fluidInputCount = 0;
- for (base=scene->base.first; base; base= base->next) {
+ for (base = FIRSTBASE(view_layer); base; base = base->next) {
Object *ob = base->object;
FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
@@ -838,7 +843,9 @@ static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *r
static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
{
Main *bmain = CTX_data_main(C);
- Scene *scene= CTX_data_scene(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
int i;
FluidsimSettings *domainSettings;
@@ -885,7 +892,7 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
}
/* check scene for sane object/modifier settings */
- if (!fluid_validate_scene(reports, scene, fsDomain)) {
+ if (!fluid_validate_scene(reports, view_layer, fsDomain)) {
fluidbake_free_data(channels, fobjects, fsset, fb);
return 0;
}
@@ -950,7 +957,7 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* reset to original current frame */
scene->r.cfra = origFrame;
- ED_update_for_newframe(CTX_data_main(C), scene, 1);
+ ED_update_for_newframe(CTX_data_main(C), depsgraph);
/* ******** init domain object's matrix ******** */
copy_m4_m4(domainMat, fsDomain->obmat);
@@ -1037,7 +1044,7 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
elbeemAddDomain(fsset);
/* ******** export all fluid objects to elbeem ******** */
- export_fluid_objects(fobjects, scene, channels->length);
+ export_fluid_objects(C, fobjects, scene, channels->length);
/* custom data for fluid bake job */
fb->settings = fsset;
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 3f958f363b6..df688d90e44 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -33,11 +33,13 @@
#ifndef __PHYSICS_INTERN_H__
#define __PHYSICS_INTERN_H__
+struct Depsgraph;
struct Object;
struct PTCacheEdit;
struct ParticleSystem;
struct PointCache;
struct Scene;
+struct ViewLayer;
struct wmOperatorType;
/* particle_edit.c */
@@ -69,10 +71,11 @@ void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
void PE_create_particle_edit(
- struct Main *bmain, struct Scene *scene, struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys);
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys);
void recalc_lengths(struct PTCacheEdit *edit);
-void recalc_emitter_field(struct Object *ob, struct ParticleSystem *psys);
-void update_world_cos(struct Object *ob, struct PTCacheEdit *edit);
+void recalc_emitter_field(struct Depsgraph *depsgraph, struct Object *ob, struct ParticleSystem *psys);
+void update_world_cos(struct Depsgraph *depsgraph, struct Object *ob, struct PTCacheEdit *edit);
/* particle_object.c */
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);
@@ -92,6 +95,7 @@ void PARTICLE_OT_dupliob_copy(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_remove(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_move_up(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_move_down(struct wmOperatorType *ot);
+void PARTICLE_OT_dupliob_refresh(struct wmOperatorType *ot);
/* particle_boids.c */
void BOID_OT_rule_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index 910e461435c..06b0d557d86 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -34,6 +34,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_select_utils.h"
#include "ED_physics.h"
#include "ED_object.h"
@@ -85,6 +86,7 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_copy_particle_systems);
WM_operatortype_append(PARTICLE_OT_duplicate_particle_system);
+ WM_operatortype_append(PARTICLE_OT_dupliob_refresh);
WM_operatortype_append(PARTICLE_OT_dupliob_copy);
WM_operatortype_append(PARTICLE_OT_dupliob_remove);
WM_operatortype_append(PARTICLE_OT_dupliob_move_up);
@@ -109,68 +111,8 @@ static void operatortypes_particle(void)
static void keymap_particle(wmKeyConfig *keyconf)
{
- wmKeyMapItem *kmi;
- wmKeyMap *keymap;
-
- keymap = WM_keymap_ensure(keyconf, "Particle", 0, 0);
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Particle", 0, 0);
keymap->poll = PE_poll;
-
- kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "PARTICLE_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "PARTICLE_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_select_linked", LKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_select_linked", LKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- WM_keymap_add_item(keymap, "PARTICLE_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PARTICLE_OT_delete", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "PARTICLE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- /* Shift+LMB behavior first, so it has priority over KM_ANY item below. */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- RNA_boolean_set(kmi->ptr, "use_planar_constraint", true);
- RNA_boolean_set(kmi->ptr, "use_accurate", false);
-
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- RNA_boolean_set(kmi->ptr, "use_planar_constraint", false);
- RNA_boolean_set(kmi->ptr, "use_accurate", true);
-
- /* Using KM_ANY here to allow holding modifiers before starting to transform. */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- RNA_boolean_set(kmi->ptr, "use_planar_constraint", false);
- RNA_boolean_set(kmi->ptr, "use_accurate", false);
-
- WM_keymap_add_item(keymap, "PARTICLE_OT_brush_edit", LEFTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PARTICLE_OT_brush_edit", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
-
- /* size radial control */
- 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.particle_edit.brush.size");
-
- /* size radial control */
- 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.particle_edit.brush.strength");
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_particle_specials", WKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "PARTICLE_OT_weight_set", KKEY, KM_PRESS, KM_SHIFT, 0);
-
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_editmode(keyconf, keymap, false);
}
/******************************* boids *************************************/
@@ -219,16 +161,6 @@ static void operatortypes_dynamicpaint(void)
WM_operatortype_append(DPAINT_OT_output_toggle);
}
-//static void keymap_pointcache(wmWindowManager *wm)
-//{
-// wmKeyMap *keymap = WM_keymap_ensure(wm, "Pointcache", 0, 0);
-//
-// WM_keymap_add_item(keymap, "PHYSICS_OT_bake_all", AKEY, KM_PRESS, 0, 0);
-// WM_keymap_add_item(keymap, "PHYSICS_OT_free_all", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
-// WM_keymap_add_item(keymap, "PHYSICS_OT_bake_particle_system", PADMINUS, KM_PRESS, KM_CTRL, 0);
-// WM_keymap_add_item(keymap, "PHYSICS_OT_free_particle_system", LKEY, KM_PRESS, 0, 0);
-//}
-
/****************************** general ************************************/
void ED_operatortypes_physics(void)
@@ -243,5 +175,4 @@ void ED_operatortypes_physics(void)
void ED_keymap_physics(wmKeyConfig *keyconf)
{
keymap_particle(keyconf);
- //keymap_pointcache(keyconf);
}
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index 51c5955d507..58bd761a2a9 100644
--- a/source/blender/editors/physics/physics_pointcache.c
+++ b/source/blender/editors/physics/physics_pointcache.c
@@ -42,6 +42,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -68,6 +69,7 @@ static bool ptcache_poll(bContext *C)
}
typedef struct PointCacheJob {
+ wmWindowManager *wm;
void *owner;
short *stop, *do_update;
float *progress;
@@ -122,8 +124,7 @@ static void ptcache_job_startjob(void *customdata, short *stop, short *do_update
/* XXX annoying hack: needed to prevent data corruption when changing
* scene frame in separate threads
*/
- G.is_rendering = true;
- BKE_spacedata_draw_locks(true);
+ WM_set_locked_interface(job->wm, true);
BKE_ptcache_bake(job->baker);
@@ -136,10 +137,7 @@ static void ptcache_job_endjob(void *customdata)
PointCacheJob *job = customdata;
Scene *scene = job->baker->scene;
- G.is_rendering = false;
- BKE_spacedata_draw_locks(false);
-
- WM_set_locked_interface(G_MAIN->wm.first, false);
+ WM_set_locked_interface(job->wm, false);
WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.ob);
@@ -165,6 +163,8 @@ static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all)
baker->bmain = CTX_data_main(C);
baker->scene = CTX_data_scene(C);
+ baker->view_layer = CTX_data_view_layer(C);
+ baker->depsgraph = CTX_data_depsgraph(C);
baker->bake = RNA_boolean_get(op->ptr, "bake");
baker->render = 0;
baker->anim_init = 0;
@@ -174,18 +174,7 @@ static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all)
PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
Object *ob = ptr.id.data;
PointCache *cache = ptr.data;
-
- ListBase pidlist;
- BKE_ptcache_ids_from_object(baker->bmain, &pidlist, ob, baker->scene, MAX_DUPLI_RECUR);
-
- for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache) {
- baker->pid = *pid;
- break;
- }
- }
-
- BLI_freelistN(&pidlist);
+ baker->pid = BKE_ptcache_id_find(ob, baker->scene, cache);
}
return baker;
@@ -207,6 +196,7 @@ static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob");
+ job->wm = CTX_wm_manager(C);
job->baker = ptcache_baker_create(C, op, all);
job->baker->bake_job = job;
job->baker->update_progress = ptcache_job_update;
@@ -253,23 +243,23 @@ static void ptcache_bake_cancel(bContext *C, wmOperator *op)
static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Base *base;
PTCacheID *pid;
ListBase pidlist;
- for (base = scene->base.first; base; base = base->next) {
- BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR);
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
+ {
+ BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
- for (pid=pidlist.first; pid; pid=pid->next) {
+ for (pid = pidlist.first; pid; pid = pid->next) {
ptcache_free_bake(pid->cache);
}
BLI_freelistN(&pidlist);
- WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, base->object);
+ WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
}
+ FOREACH_SCENE_OBJECT_END;
WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
@@ -384,27 +374,18 @@ void PTCACHE_OT_bake_from_cache(wmOperatorType *ot)
static int ptcache_add_new_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
Object *ob= ptr.id.data;
PointCache *cache= ptr.data;
- PTCacheID *pid;
- ListBase pidlist;
-
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, scene, MAX_DUPLI_RECUR);
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
- for (pid=pidlist.first; pid; pid=pid->next) {
- if (pid->cache == cache) {
- PointCache *cache_new = BKE_ptcache_add(pid->ptcaches);
- cache_new->step = pid->default_step;
- *(pid->cache_ptr) = cache_new;
- break;
- }
+ if (pid.cache) {
+ PointCache *cache_new = BKE_ptcache_add(pid.ptcaches);
+ cache_new->step = pid.default_step;
+ *(pid.cache_ptr) = cache_new;
}
- BLI_freelistN(&pidlist);
-
WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
@@ -412,31 +393,19 @@ static int ptcache_add_new_exec(bContext *C, wmOperator *UNUSED(op))
}
static int ptcache_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
- Main *bmain = CTX_data_main(C);
PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
Scene *scene= CTX_data_scene(C);
Object *ob= ptr.id.data;
PointCache *cache= ptr.data;
- PTCacheID *pid;
- ListBase pidlist;
-
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, scene, MAX_DUPLI_RECUR);
+ PTCacheID pid = BKE_ptcache_id_find(ob, scene, cache);
- for (pid=pidlist.first; pid; pid=pid->next) {
- if (pid->cache == cache) {
- if (pid->ptcaches->first == pid->ptcaches->last)
- continue; /* don't delete last cache */
-
- BLI_remlink(pid->ptcaches, pid->cache);
- BKE_ptcache_free(pid->cache);
- *(pid->cache_ptr) = pid->ptcaches->first;
-
- break;
- }
+ /* don't delete last cache */
+ if (pid.cache && pid.ptcaches->first != pid.ptcaches->last) {
+ BLI_remlink(pid.ptcaches, pid.cache);
+ BKE_ptcache_free(pid.cache);
+ *(pid.cache_ptr) = pid.ptcaches->first;
}
- BLI_freelistN(&pidlist);
-
WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index 0c612cc5855..6589e8e1fea 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -37,13 +37,16 @@
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_group.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -81,17 +84,20 @@ bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type
}
/* create constraint group if it doesn't already exits */
if (rbw->constraints == NULL) {
- rbw->constraints = BKE_group_add(bmain, "RigidBodyConstraints");
+ rbw->constraints = BKE_collection_add(bmain, NULL, "RigidBodyConstraints");
+ id_fake_user_set(&rbw->constraints->id);
}
/* make rigidbody constraint settings */
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type);
ob->rigidbody_constraint->flag |= RBC_FLAG_NEEDS_VALIDATE;
/* add constraint to rigid body constraint group */
- BKE_group_object_add(rbw->constraints, ob, scene, NULL);
+ BKE_collection_object_add(bmain, rbw->constraints, ob);
+
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&rbw->constraints->id, DEG_TAG_COPY_ON_WRITE);
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
@@ -100,11 +106,13 @@ void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
BKE_rigidbody_remove_constraint(scene, ob);
- if (rbw)
- BKE_group_object_unlink(bmain, rbw->constraints, ob, scene, NULL);
+ if (rbw) {
+ BKE_collection_object_remove(bmain, rbw->constraints, ob, false);
+ DEG_id_tag_update(&rbw->constraints->id, DEG_TAG_COPY_ON_WRITE);
+ }
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
/* ********************************************** */
@@ -116,8 +124,9 @@ static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
- Object *ob = (scene) ? OBACT : NULL;
+ Object *ob = OBACT(view_layer);
int type = RNA_enum_get(op->ptr, "type");
bool changed;
@@ -165,11 +174,8 @@ static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = (scene) ? OBACT : NULL;
-
- /* sanity checks */
- if (scene == NULL)
- return OPERATOR_CANCELLED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
/* apply to active object */
if (ELEM(NULL, ob, ob->rigidbody_constraint)) {
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index ec6de52ebc1..1b7f426ac5f 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -42,13 +42,16 @@
#include "BLT_translation.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_group.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -107,7 +110,8 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re
scene->rigidbody_world = rbw;
}
if (rbw->group == NULL) {
- rbw->group = BKE_group_add(bmain, "RigidBodyWorld");
+ rbw->group = BKE_collection_add(bmain, NULL, "RigidBodyWorld");
+ id_fake_user_set(&rbw->group->id);
}
/* make rigidbody object settings */
@@ -118,24 +122,21 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re
ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_VALIDATE;
/* add object to rigid body group */
- BKE_group_object_add(rbw->group, ob, scene, NULL);
+ BKE_collection_object_add(bmain, rbw->group, ob);
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&rbw->group->id, DEG_TAG_COPY_ON_WRITE);
return true;
}
void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
{
- RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
-
- BKE_rigidbody_remove_object(scene, ob);
- if (rbw)
- BKE_group_object_unlink(bmain, rbw->group, ob, scene, NULL);
+ BKE_rigidbody_remove_object(bmain, scene, ob);
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
/* ********************************************** */
@@ -344,7 +345,7 @@ static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object, &ptr);
RNA_enum_set(&ptr, "collision_shape", shape);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
changed = true;
}
@@ -526,7 +527,7 @@ static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op)
RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object, &ptr);
RNA_float_set(&ptr, "mass", mass);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
changed = true;
}
diff --git a/source/blender/editors/physics/rigidbody_world.c b/source/blender/editors/physics/rigidbody_world.c
index fe2be86dd98..6ef3e03f8da 100644
--- a/source/blender/editors/physics/rigidbody_world.c
+++ b/source/blender/editors/physics/rigidbody_world.c
@@ -42,9 +42,13 @@
#endif
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RNA_access.h"
#include "WM_api.h"
@@ -76,6 +80,7 @@ static bool ED_rigidbody_world_add_poll(bContext *C)
static int rigidbody_world_add_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
RigidBodyWorld *rbw;
@@ -83,6 +88,10 @@ static int rigidbody_world_add_exec(bContext *C, wmOperator *UNUSED(op))
// BKE_rigidbody_validate_sim_world(scene, rbw, false);
scene->rigidbody_world = rbw;
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update_ex(bmain, &scene->id, DEG_TAG_TIME);
+
return OPERATOR_FINISHED;
}
@@ -105,6 +114,7 @@ void RIGIDBODY_OT_world_add(wmOperatorType *ot)
static int rigidbody_world_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -114,8 +124,11 @@ static int rigidbody_world_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_rigidbody_free_world(rbw);
- scene->rigidbody_world = NULL;
+ BKE_rigidbody_free_world(scene);
+
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update_ex(bmain, &scene->id, DEG_TAG_TIME);
/* done */
return OPERATOR_FINISHED;
@@ -152,14 +165,14 @@ static int rigidbody_world_export_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No Rigid Body World to export");
return OPERATOR_CANCELLED;
}
- if (rbw->physics_world == NULL) {
+ if (rbw->shared->physics_world == NULL) {
BKE_report(op->reports, RPT_ERROR, "Rigid Body World has no associated physics data to export");
return OPERATOR_CANCELLED;
}
RNA_string_get(op->ptr, "filepath", path);
#ifdef WITH_BULLET
- RB_dworld_export(rbw->physics_world, path);
+ RB_dworld_export(rbw->shared->physics_world, path);
#endif
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index ec8bf3e955d..ed2e9747d1c 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -24,6 +24,8 @@ set(INC
../../blenlib
../../blenloader
../../blentranslation
+ ../../depsgraph
+ ../../draw
../../gpu
../../imbuf
../../bmesh
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index a00ab742386..585a7999290 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -53,8 +53,11 @@ void WORLD_OT_new(struct wmOperatorType *ot);
void MATERIAL_OT_copy(struct wmOperatorType *ot);
void MATERIAL_OT_paste(struct wmOperatorType *ot);
-void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
-void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
+void SCENE_OT_view_layer_add(struct wmOperatorType *ot);
+void SCENE_OT_view_layer_remove(struct wmOperatorType *ot);
+
+void SCENE_OT_light_cache_bake(struct wmOperatorType *ot);
+void SCENE_OT_light_cache_free(struct wmOperatorType *ot);
void SCENE_OT_render_view_add(struct wmOperatorType *ot);
void SCENE_OT_render_view_remove(struct wmOperatorType *ot);
@@ -83,15 +86,10 @@ void SCENE_OT_freestyle_stroke_material_create(struct wmOperatorType *ot);
void TEXTURE_OT_slot_copy(struct wmOperatorType *ot);
void TEXTURE_OT_slot_paste(struct wmOperatorType *ot);
void TEXTURE_OT_slot_move(struct wmOperatorType *ot);
-void TEXTURE_OT_envmap_save(struct wmOperatorType *ot);
-void TEXTURE_OT_envmap_clear(struct wmOperatorType *ot);
-void TEXTURE_OT_envmap_clear_all(struct wmOperatorType *ot);
/* render_internal.c */
void RENDER_OT_render(struct wmOperatorType *ot);
void RENDER_OT_shutter_curve_preset(struct wmOperatorType *ot);
-void render_view3d_update(struct RenderEngine *engine, const struct bContext *C);
-void render_view3d_draw(struct RenderEngine *engine, const struct bContext *C);
/* render_view.c */
struct ScrArea *render_view_open(struct bContext *C, int mx, int my, struct ReportList *reports);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index d94776d126f..1ca06beefad 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -54,9 +54,9 @@
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -67,6 +67,8 @@
#include "BKE_scene.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -83,6 +85,7 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
+#include "GPU_shader.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -100,11 +103,14 @@ static int render_break(void *rjv);
typedef struct RenderJob {
Main *main;
Scene *scene;
+ ViewLayer *single_layer;
Scene *current_scene;
+ /* TODO(sergey): Should not be needed once engine will have own
+ * depsgraph and copy-on-write will be implemented.
+ */
+ Depsgraph *depsgraph;
Render *re;
- SceneRenderLayer *srl;
struct Object *camera_override;
- int lay_override;
bool v3d_override;
bool anim, write_still;
Image *image;
@@ -255,7 +261,7 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
/* set callbacks, exported to sequence render too.
* Only call in foreground (UI) renders. */
-static void screen_render_scene_layer_set(wmOperator *op, Main *mainp, Scene **scene, SceneRenderLayer **srl)
+static void screen_render_single_layer_set(wmOperator *op, Main *mainp, ViewLayer *active_layer, Scene **scene, ViewLayer **single_layer)
{
/* single layer re-render */
if (RNA_struct_property_is_set(op->ptr, "scene")) {
@@ -275,14 +281,17 @@ static void screen_render_scene_layer_set(wmOperator *op, Main *mainp, Scene **s
}
if (RNA_struct_property_is_set(op->ptr, "layer")) {
- SceneRenderLayer *rl;
+ ViewLayer *rl;
char rl_name[RE_MAXNAME];
RNA_string_get(op->ptr, "layer", rl_name);
- rl = (SceneRenderLayer *)BLI_findstring(&(*scene)->r.layers, rl_name, offsetof(SceneRenderLayer, name));
+ rl = (ViewLayer *)BLI_findstring(&(*scene)->view_layers, rl_name, offsetof(ViewLayer, name));
if (rl)
- *srl = rl;
+ *single_layer = rl;
+ }
+ else if (((*scene)->r.scemode & R_SINGLE_LAYER) && active_layer) {
+ *single_layer = active_layer;
}
}
@@ -290,18 +299,24 @@ static void screen_render_scene_layer_set(wmOperator *op, Main *mainp, Scene **s
static int screen_render_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = NULL;
+ RenderEngineType *re_type = RE_engines_find(scene->r.engine);
+ ViewLayer *active_layer = CTX_data_view_layer(C);
+ ViewLayer *single_layer = NULL;
Render *re;
Image *ima;
View3D *v3d = CTX_wm_view3d(C);
Main *mainp = CTX_data_main(C);
- unsigned int lay_override;
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ /* Cannot do render if there is not this function. */
+ if (re_type->render == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
/* custom scene and single layer re-render */
- screen_render_scene_layer_set(op, mainp, &scene, &srl);
+ screen_render_single_layer_set(op, mainp, active_layer, &scene, &single_layer);
if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
@@ -309,7 +324,6 @@ static int screen_render_exec(bContext *C, wmOperator *op)
}
re = RE_NewSceneRender(scene);
- lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0;
G.is_break = false;
RE_test_break_cb(re, NULL, render_break);
@@ -328,15 +342,15 @@ static int screen_render_exec(bContext *C, wmOperator *op)
BLI_threaded_malloc_begin();
if (is_animation)
- RE_BlenderAnim(re, mainp, scene, camera_override, lay_override, scene->r.sfra, scene->r.efra, scene->r.frame_step);
+ RE_BlenderAnim(re, mainp, scene, single_layer, camera_override, scene->r.sfra, scene->r.efra, scene->r.frame_step);
else
- RE_BlenderFrame(re, mainp, scene, srl, camera_override, lay_override, scene->r.cfra, is_write_still);
+ RE_BlenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
BLI_threaded_malloc_end();
RE_SetReports(re, NULL);
// no redraw needed, we leave state as we entered it
- ED_update_for_newframe(mainp, scene, 1);
+ ED_update_for_newframe(mainp, CTX_data_depsgraph(C));
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene);
@@ -410,7 +424,7 @@ static void make_renderinfo_string(const RenderStats *rs,
if (rs->totface) spos += sprintf(spos, IFACE_("Fa:%d "), rs->totface);
if (rs->tothalo) spos += sprintf(spos, IFACE_("Ha:%d "), rs->tothalo);
if (rs->totstrand) spos += sprintf(spos, IFACE_("St:%d "), rs->totstrand);
- if (rs->totlamp) spos += sprintf(spos, IFACE_("La:%d "), rs->totlamp);
+ if (rs->totlamp) spos += sprintf(spos, IFACE_("Li:%d "), rs->totlamp);
if (rs->mem_peak == 0.0f)
spos += sprintf(spos, IFACE_("| Mem:%.2fM (%.2fM, Peak %.2fM) "),
@@ -492,8 +506,9 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
for (wm = rj->main->wm.first; wm && matched_sa == NULL; wm = wm->id.next) { /* only 1 wm */
wmWindow *win;
for (win = wm->windows.first; win && matched_sa == NULL; win = win->next) {
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
// sa->spacedata might be empty when toggling fullscreen mode.
@@ -602,9 +617,9 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro
RE_SetReports(rj->re, rj->reports);
if (rj->anim)
- RE_BlenderAnim(rj->re, rj->main, rj->scene, rj->camera_override, rj->lay_override, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step);
+ RE_BlenderAnim(rj->re, rj->main, rj->scene, rj->single_layer, rj->camera_override, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step);
else
- RE_BlenderFrame(rj->re, rj->main, rj->scene, rj->srl, rj->camera_override, rj->lay_override, rj->scene->r.cfra, rj->write_still);
+ RE_BlenderFrame(rj->re, rj->main, rj->scene, rj->single_layer, rj->camera_override, rj->scene->r.cfra, rj->write_still);
RE_SetReports(rj->re, NULL);
}
@@ -617,8 +632,9 @@ static void render_image_restore_layer(RenderJob *rj)
for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
if (sa == rj->sa) {
if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
@@ -653,14 +669,14 @@ static void render_endjob(void *rjv)
* would be re-assigned. assign dummy callbacks to avoid referencing freed renderjobs bug [#24508] */
RE_InitRenderCB(rj->re);
- if (rj->main != G.main)
+ if (rj->main != G_MAIN)
BKE_main_free(rj->main);
/* else the frame will not update for the original value */
if (rj->anim && !(rj->scene->r.scemode & R_NO_FRAME_UPDATE)) {
/* possible this fails of loading new file while rendering */
- if (G.main->wm.first) {
- ED_update_for_newframe(G.main, rj->scene, 1);
+ if (G_MAIN->wm.first) {
+ ED_update_for_newframe(G_MAIN, rj->depsgraph);
}
}
@@ -670,7 +686,7 @@ static void render_endjob(void *rjv)
/* potentially set by caller */
rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE;
- if (rj->srl) {
+ if (rj->single_layer) {
nodeUpdateID(rj->scene->nodetree, &rj->scene->id);
WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
}
@@ -700,7 +716,7 @@ static void render_endjob(void *rjv)
* engine API, so lets use simple and robust way for now
* - sergey -
*/
- if (rj->scene->r.layers.first != rj->scene->r.layers.last ||
+ if (rj->scene->view_layers.first != rj->scene->view_layers.last ||
rj->image_outdated)
{
void *lock;
@@ -715,25 +731,12 @@ static void render_endjob(void *rjv)
/* Finally unlock the user interface (if it was locked). */
if (rj->interface_locked) {
- Scene *scene;
-
/* Interface was locked, so window manager couldn't have been changed
* and using one from Global will unlock exactly the same manager as
* was locked before running the job.
*/
- WM_set_locked_interface(G.main->wm.first, false);
-
- /* We've freed all the derived caches before rendering, which is
- * effectively the same as if we re-loaded the file.
- *
- * So let's not try being smart here and just reset all updated
- * scene layers and use generic DAG_on_visible_update.
- */
- for (scene = G.main->scene.first; scene; scene = scene->id.next) {
- scene->lay_updated = 0;
- }
-
- DAG_on_visible_update(G.main, false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+ DEG_on_visible_update(G_MAIN, false);
}
}
@@ -797,33 +800,45 @@ static void screen_render_cancel(bContext *C, wmOperator *op)
WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_RENDER);
}
-static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay)
+static void clean_viewport_memory_base(Base *base)
{
- Object *object;
- Scene *sce_iter;
- Base *base;
+ if ((base->flag & BASE_VISIBLE) == 0) {
+ return;
+ }
- for (object = bmain->object.first; object; object = object->id.next) {
- object->id.tag |= LIB_TAG_DOIT;
+ Object *object = base->object;
+
+ if (object->id.tag & LIB_TAG_DOIT) {
+ return;
}
- for (SETLOOPER(scene, sce_iter, base)) {
- if ((base->lay & renderlay) == 0) {
- continue;
- }
- if (RE_allow_render_generic_object(base->object)) {
- base->object->id.tag &= ~LIB_TAG_DOIT;
- }
+ object->id.tag &= ~LIB_TAG_DOIT;
+ if (RE_allow_render_generic_object(object)) {
+ BKE_object_free_derived_caches(object);
}
+}
- for (SETLOOPER(scene, sce_iter, base)) {
- object = base->object;
- if ((object->id.tag & LIB_TAG_DOIT) == 0) {
- continue;
+static void clean_viewport_memory(Main *bmain, Scene *scene)
+{
+ Scene *sce_iter;
+ Base *base;
+
+ /* Tag all the available objects. */
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
+
+ /* Go over all the visible objects. */
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ clean_viewport_memory_base(base);
+ }
}
- object->id.tag &= ~LIB_TAG_DOIT;
+ }
- BKE_object_free_derived_caches(object);
+ for (SETLOOPER_SET_ONLY(scene, sce_iter, base)) {
+ clean_viewport_memory_base(base);
}
}
@@ -831,9 +846,11 @@ static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay)
static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* new render clears all callbacks */
- Main *mainp;
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = NULL;
+ ViewLayer *active_layer = CTX_data_view_layer(C);
+ ViewLayer *single_layer = NULL;
+ RenderEngineType *re_type = RE_engines_find(scene->r.engine);
Render *re;
wmJob *wm_job;
RenderJob *rj;
@@ -847,14 +864,19 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
const char *name;
ScrArea *sa;
+ /* Cannot do render if there is not this function. */
+ if (re_type->render == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* custom scene and single layer re-render */
+ screen_render_single_layer_set(op, bmain, active_layer, &scene, &single_layer);
+
/* only one render job at a time */
if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER))
return OPERATOR_CANCELLED;
- if (RE_force_single_renderlayer(scene))
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- if (!RE_is_rendering_allowed(scene, camera_override, op->reports)) {
+ if (!RE_is_rendering_allowed(scene, single_layer, camera_override, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -866,15 +888,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
/* stop all running jobs, except screen one. currently previews frustrate Render */
WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
- /* get main */
- if (G.debug_value == 101) {
- /* thread-safety experiment, copy main from the undo buffer */
- struct MemFile *memfile = ED_undosys_stack_memfile_get_active(CTX_wm_manager(C)->undo_stack);
- mainp = BLO_memfile_main_get(memfile, CTX_data_main(C), &scene);
- }
- else
- mainp = CTX_data_main(C);
-
/* cancel animation playback */
if (ED_screen_animation_playing(CTX_wm_manager(C)))
ED_screen_animation_play(C, 0, 0);
@@ -900,20 +913,18 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS;
- /* custom scene and single layer re-render */
- screen_render_scene_layer_set(op, mainp, &scene, &srl);
-
if (RNA_struct_property_is_set(op->ptr, "layer"))
jobflag |= WM_JOB_SUSPEND;
/* job custom data */
rj = MEM_callocN(sizeof(RenderJob), "render job");
- rj->main = mainp;
+ rj->main = bmain;
rj->scene = scene;
rj->current_scene = rj->scene;
- rj->srl = srl;
+ rj->single_layer = single_layer;
+ /* TODO(sergey): Render engine should be using own depsgraph. */
+ rj->depsgraph = CTX_data_depsgraph(C);
rj->camera_override = camera_override;
- rj->lay_override = 0;
rj->anim = is_animation;
rj->write_still = is_write_still && !is_animation;
rj->iuser.scene = scene;
@@ -933,21 +944,12 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
}
if (v3d) {
- if (scene->lay != v3d->lay) {
- rj->lay_override = v3d->lay;
- rj->v3d_override = true;
- }
- else if (camera_override && camera_override != scene->camera)
+ if (camera_override && camera_override != scene->camera)
rj->v3d_override = true;
-
- if (v3d->localvd)
- rj->lay_override |= v3d->localvd->lay;
}
/* Lock the user interface depending on render settings. */
if (scene->r.use_lock_interface) {
- int renderlay = rj->lay_override ? rj->lay_override : scene->lay;
-
WM_set_locked_interface(CTX_wm_manager(C), true);
/* Set flag interface need to be unlocked.
@@ -961,7 +963,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->interface_locked = true;
/* Clean memory used by viewport? */
- clean_viewport_memory(rj->main, scene, renderlay);
+ clean_viewport_memory(rj->main, scene);
}
/* setup job */
@@ -974,7 +976,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob);
/* get a render result image, and make sure it is empty */
- ima = BKE_image_verify_viewer(mainp, IMA_TYPE_R_RESULT, "Render Result");
+ ima = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE);
BKE_image_backup_render(rj->scene, ima, true);
rj->image = ima;
@@ -987,6 +989,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
RE_current_scene_update_cb(re, rj, current_scene_update);
RE_stats_draw_cb(re, rj, image_renderinfo_cb);
RE_progress_cb(re, rj, render_progress_update);
+ RE_gl_context_create(re);
rj->re = re;
G.is_break = false;
@@ -1043,615 +1046,6 @@ void RENDER_OT_render(wmOperatorType *ot)
}
-/* ************** preview for 3d viewport ***************** */
-
-#define PR_UPDATE_VIEW 1
-#define PR_UPDATE_RENDERSIZE 2
-#define PR_UPDATE_MATERIAL 4
-#define PR_UPDATE_DATABASE 8
-
-typedef struct RenderPreview {
- /* from wmJob */
- void *owner;
- short *stop, *do_update;
- wmJob *job;
-
- Scene *scene;
- ScrArea *sa;
- ARegion *ar;
- View3D *v3d;
- RegionView3D *rv3d;
- Main *bmain;
- RenderEngine *engine;
-
- float viewmat[4][4];
-
- int start_resolution_divider;
- int resolution_divider;
- bool has_freestyle;
-} RenderPreview;
-
-static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect)
-{
- /* copied code from view3d_draw.c */
- rctf viewborder;
- int draw_border;
-
- if (rv3d->persp == RV3D_CAMOB)
- draw_border = (scene->r.mode & R_BORDER) != 0;
- else
- draw_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0;
-
- if (draw_border) {
- if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
-
- disprect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
- disprect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
- disprect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder);
- disprect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder);
- }
- else {
- disprect->xmin = v3d->render_border.xmin * ar->winx;
- disprect->xmax = v3d->render_border.xmax * ar->winx;
- disprect->ymin = v3d->render_border.ymin * ar->winy;
- disprect->ymax = v3d->render_border.ymax * ar->winy;
- }
-
- return 1;
- }
-
- BLI_rcti_init(disprect, 0, 0, 0, 0);
- return 0;
-}
-
-/* returns true if OK */
-static bool render_view3d_get_rects(ARegion *ar, View3D *v3d, RegionView3D *rv3d, rctf *viewplane, RenderEngine *engine,
- float *r_clipsta, float *r_clipend, float *r_pixsize, bool *r_ortho)
-{
-
- if (ar->winx < 4 || ar->winy < 4) return false;
-
- *r_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, viewplane, r_clipsta, r_clipend, r_pixsize);
-
- engine->resolution_x = ar->winx;
- engine->resolution_y = ar->winy;
-
- return true;
-}
-
-static bool render_view3d_is_valid(RenderPreview *rp)
-{
- return (rp->rv3d->render_engine != NULL);
-}
-
-/* called by renderer, checks job value */
-static int render_view3d_break(void *rpv)
-{
- RenderPreview *rp = rpv;
-
- if (G.is_break)
- return 1;
-
- /* during render, rv3d->engine can get freed */
- if (render_view3d_is_valid(rp) == false) {
- *rp->stop = 1;
- }
-
- return *(rp->stop);
-}
-
-static void render_view3d_display_update(void *rpv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect))
-{
- RenderPreview *rp = rpv;
-
- *(rp->do_update) = true;
-}
-
-static void render_view3d_renderinfo_cb(void *rjp, RenderStats *rs)
-{
- RenderPreview *rp = rjp;
-
- /* during render, rv3d->engine can get freed */
- if (rp->rv3d->render_engine == NULL) {
- *rp->stop = 1;
- }
- else {
- make_renderinfo_string(rs, rp->scene, false, NULL, rp->engine->text);
-
- /* make jobs timer to send notifier */
- *(rp->do_update) = true;
- }
-}
-
-BLI_INLINE void rcti_scale_coords(rcti *scaled_rect, const rcti *rect,
- const float scale)
-{
- scaled_rect->xmin = rect->xmin * scale;
- scaled_rect->ymin = rect->ymin * scale;
- scaled_rect->xmax = rect->xmax * scale;
- scaled_rect->ymax = rect->ymax * scale;
-}
-
-static void render_update_resolution(Render *re, const RenderPreview *rp,
- bool use_border, const rcti *clip_rect)
-{
- int winx = rp->ar->winx / rp->resolution_divider;
- int winy = rp->ar->winy / rp->resolution_divider;
- if (use_border) {
- rcti scaled_cliprct;
- rcti_scale_coords(&scaled_cliprct, clip_rect,
- 1.0f / rp->resolution_divider);
- RE_ChangeResolution(re, winx, winy, &scaled_cliprct);
- }
- else {
- RE_ChangeResolution(re, winx, winy, NULL);
- }
-
- if (rp->has_freestyle) {
- if (rp->resolution_divider == BKE_render_preview_pixel_size(&rp->scene->r)) {
- RE_ChangeModeFlag(re, R_EDGE_FRS, false);
- }
- else {
- RE_ChangeModeFlag(re, R_EDGE_FRS, true);
- }
- }
-}
-
-static void render_view3d_startjob(void *customdata, short *stop, short *do_update, float *UNUSED(progress))
-{
- RenderPreview *rp = customdata;
- Render *re;
- RenderStats *rstats;
- rctf viewplane;
- rcti cliprct;
- float clipsta, clipend, pixsize;
- bool orth, restore = 0;
- char name[32];
- int update_flag;
- bool use_border;
- int ob_inst_update_flag = 0;
-
- update_flag = rp->engine->job_update_flag;
- rp->engine->job_update_flag = 0;
-
- //printf("ma %d res %d view %d db %d\n", update_flag & PR_UPDATE_MATERIAL, update_flag & PR_UPDATE_RENDERSIZE, update_flag & PR_UPDATE_VIEW, update_flag & PR_UPDATE_DATABASE);
-
- G.is_break = false;
-
- if (false == render_view3d_get_rects(rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth))
- return;
-
- rp->stop = stop;
- rp->do_update = do_update;
-
- // printf("Enter previewrender\n");
-
- /* ok, are we rendering all over? */
- sprintf(name, "View3dPreview %p", (void *)rp->ar);
- re = rp->engine->re = RE_GetRender(name);
-
- /* set this always, rp is different for each job */
- RE_test_break_cb(re, rp, render_view3d_break);
- RE_display_update_cb(re, rp, render_view3d_display_update);
- RE_stats_draw_cb(re, rp, render_view3d_renderinfo_cb);
-
- rstats = RE_GetStats(re);
-
- if (update_flag & PR_UPDATE_VIEW) {
- Object *object;
- rp->resolution_divider = rp->start_resolution_divider;
-
- /* Same as database_init_objects(), loop over all objects.
- * We might consider de-duplicating the code between this two cases.
- */
- for (object = rp->bmain->object.first; object; object = object->id.next) {
- float mat[4][4];
- mul_m4_m4m4(mat, rp->viewmat, object->obmat);
- invert_m4_m4(object->imat_ren, mat);
- }
- }
-
- use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d,
- rp->rv3d, &cliprct);
-
- if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE | PR_UPDATE_VIEW)) || rstats->convertdone == 0) {
- RenderData rdata;
-
- /* no osa, blur, seq, layers, savebuffer etc for preview render */
- rdata = rp->scene->r;
- rdata.mode &= ~(R_OSA | R_MBLUR | R_BORDER | R_PANORAMA);
- rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE | R_EXR_TILE_FILE | R_FULL_SAMPLE);
- rdata.scemode |= R_VIEWPORT_PREVIEW;
-
- /* we do use layers, but only active */
- rdata.scemode |= R_SINGLE_LAYER;
-
- /* initalize always */
- if (use_border) {
- rdata.mode |= R_BORDER;
- RE_InitState(re, NULL, &rdata, NULL, rp->ar->winx, rp->ar->winy, &cliprct);
- }
- else
- RE_InitState(re, NULL, &rdata, NULL, rp->ar->winx, rp->ar->winy, NULL);
- }
-
- if (orth)
- RE_SetOrtho(re, &viewplane, clipsta, clipend);
- else
- RE_SetWindow(re, &viewplane, clipsta, clipend);
-
- RE_SetPixelSize(re, pixsize);
-
- if ((update_flag & PR_UPDATE_DATABASE) || rstats->convertdone == 0) {
- unsigned int lay = rp->scene->lay;
-
- /* allow localview render for objects with lights in normal layers */
- if (rp->v3d->lay & 0xFF000000)
- lay |= rp->v3d->lay;
- else lay = rp->v3d->lay;
-
- RE_SetView(re, rp->viewmat);
-
- /* copying blender data while main thread is locked, to avoid crashes */
- WM_job_main_thread_lock_acquire(rp->job);
- RE_Database_Free(re);
- RE_Database_FromScene(re, rp->bmain, rp->scene, lay, 0); // 0= dont use camera view
- WM_job_main_thread_lock_release(rp->job);
-
- /* do preprocessing like building raytree, shadows, volumes, SSS */
- RE_Database_Preprocess(re);
-
- /* conversion not completed, need to do it again */
- if (!rstats->convertdone) {
- if (render_view3d_is_valid(rp)) {
- rp->engine->job_update_flag |= PR_UPDATE_DATABASE;
- }
- }
-
- // printf("dbase update\n");
- }
- else {
- // printf("dbase rotate\n");
- RE_DataBase_IncrementalView(re, rp->viewmat, 0);
- restore = 1;
- }
-
- RE_DataBase_ApplyWindow(re);
-
- /* OK, can we enter render code? */
- if (rstats->convertdone) {
- bool first_time = true;
-
- if (update_flag & PR_UPDATE_VIEW) {
- ob_inst_update_flag |= RE_OBJECT_INSTANCES_UPDATE_VIEW;
- }
-
- RE_updateRenderInstances(re, ob_inst_update_flag);
-
- for (;;) {
- int pixel_size = BKE_render_preview_pixel_size(&rp->scene->r);
- if (first_time == false) {
- if (restore)
- RE_DataBase_IncrementalView(re, rp->viewmat, 1);
-
- rp->resolution_divider = MAX2(rp->resolution_divider / 2, pixel_size);
- *do_update = 1;
-
- render_update_resolution(re, rp, use_border, &cliprct);
-
- RE_DataBase_IncrementalView(re, rp->viewmat, 0);
- RE_DataBase_ApplyWindow(re);
- restore = 1;
- }
- else {
- render_update_resolution(re, rp, use_border, &cliprct);
- }
-
- RE_TileProcessor(re);
-
- first_time = false;
-
- if (*stop || rp->resolution_divider == pixel_size) {
- break;
- }
- }
-
- /* always rotate back */
- if (restore)
- RE_DataBase_IncrementalView(re, rp->viewmat, 1);
- }
-}
-
-static void render_view3d_free(void *customdata)
-{
- RenderPreview *rp = customdata;
-
- MEM_freeN(rp);
-}
-
-static bool render_view3d_flag_changed(RenderEngine *engine, const bContext *C)
-{
- Main *bmain = CTX_data_main(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- Render *re;
- rctf viewplane;
- rcti disprect;
- float clipsta, clipend;
- bool orth;
- int job_update_flag = 0;
- char name[32];
-
- /* ensure render engine exists */
- re = engine->re;
-
- if (!re) {
- sprintf(name, "View3dPreview %p", (void *)ar);
- re = engine->re = RE_GetRender(name);
- if (!re)
- re = engine->re = RE_NewRender(name);
-
- engine->update_flag |= RE_ENGINE_UPDATE_DATABASE;
- }
-
- /* check update_flag */
- if (engine->update_flag & RE_ENGINE_UPDATE_MA)
- job_update_flag |= PR_UPDATE_MATERIAL;
-
- if (engine->update_flag & RE_ENGINE_UPDATE_OTHER)
- job_update_flag |= PR_UPDATE_MATERIAL;
-
- if (engine->update_flag & RE_ENGINE_UPDATE_DATABASE) {
- job_update_flag |= PR_UPDATE_DATABASE;
-
- /* load editmesh */
- if (scene->obedit)
- ED_object_editmode_load(bmain, scene->obedit);
- }
-
- engine->update_flag = 0;
-
- /* check if viewport changed */
- if (engine->last_winx != ar->winx || engine->last_winy != ar->winy) {
- engine->last_winx = ar->winx;
- engine->last_winy = ar->winy;
- job_update_flag |= PR_UPDATE_RENDERSIZE;
- }
-
- if (compare_m4m4(engine->last_viewmat, rv3d->viewmat, 0.00001f) == 0) {
- copy_m4_m4(engine->last_viewmat, rv3d->viewmat);
- job_update_flag |= PR_UPDATE_VIEW;
- }
-
- render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, NULL, &orth);
-
- if (BLI_rctf_compare(&viewplane, &engine->last_viewplane, 0.00001f) == 0) {
- engine->last_viewplane = viewplane;
- job_update_flag |= PR_UPDATE_VIEW;
- }
-
- render_view3d_disprect(scene, ar, v3d, rv3d, &disprect);
- if (BLI_rcti_compare(&disprect, &engine->last_disprect) == 0) {
- engine->last_disprect = disprect;
- job_update_flag |= PR_UPDATE_RENDERSIZE;
- }
-
- /* any changes? go ahead and rerender */
- if (job_update_flag) {
- engine->job_update_flag |= job_update_flag;
- return true;
- }
-
- return false;
-}
-
-static void render_view3d_do(RenderEngine *engine, const bContext *C)
-{
- wmJob *wm_job;
- RenderPreview *rp;
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- int width = ar->winx, height = ar->winy;
- int divider = BKE_render_preview_pixel_size(&scene->r);
- int resolution_threshold = scene->r.preview_start_resolution *
- scene->r.preview_start_resolution;
-
- if (CTX_wm_window(C) == NULL)
- return;
- if (!render_view3d_flag_changed(engine, C))
- return;
-
- wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview",
- WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW);
- rp = MEM_callocN(sizeof(RenderPreview), "render preview");
- rp->job = wm_job;
-
- while (width * height > resolution_threshold) {
- width = max_ii(1, width / 2);
- height = max_ii(1, height / 2);
- divider *= 2;
- }
-
- /* customdata for preview thread */
- rp->scene = scene;
- rp->engine = engine;
- rp->sa = CTX_wm_area(C);
- rp->ar = CTX_wm_region(C);
- rp->v3d = rp->sa->spacedata.first;
- rp->rv3d = CTX_wm_region_view3d(C);
- rp->bmain = CTX_data_main(C);
- rp->resolution_divider = divider;
- rp->start_resolution_divider = divider;
- rp->has_freestyle = (scene->r.mode & R_EDGE_FRS) != 0;
- copy_m4_m4(rp->viewmat, rp->rv3d->viewmat);
-
- /* clear info text */
- engine->text[0] = '\0';
-
- /* setup job */
- WM_jobs_customdata_set(wm_job, rp, render_view3d_free);
- WM_jobs_timer(wm_job, 0.1, NC_SPACE | ND_SPACE_VIEW3D, NC_SPACE | ND_SPACE_VIEW3D);
- WM_jobs_callbacks(wm_job, render_view3d_startjob, NULL, NULL, NULL);
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
-
- engine->flag &= ~RE_ENGINE_DO_UPDATE;
-}
-
-/* callback for render engine, on changes */
-void render_view3d_update(RenderEngine *engine, const bContext *C)
-{
- /* this shouldn't be needed and causes too many database rebuilds, but we
- * aren't actually tracking updates for all relevant datablocks so this is
- * a catch-all for updates */
- engine->update_flag |= RE_ENGINE_UPDATE_DATABASE;
-
- render_view3d_do(engine, C);
-}
-
-void render_view3d_draw(RenderEngine *engine, const bContext *C)
-{
- Render *re = engine->re;
- RenderResult rres;
- char name[32];
-
- render_view3d_do(engine, C);
-
- if (re == NULL) {
- sprintf(name, "View3dPreview %p", (void *)CTX_wm_region(C));
- re = RE_GetRender(name);
-
- if (re == NULL) return;
- }
-
- /* Viewport render preview doesn't support multiview, view hardcoded to 0 */
- RE_AcquireResultImage(re, &rres, 0);
-
- if (rres.rectf) {
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- bool force_fallback = false;
- bool need_fallback = true;
- float dither = scene->r.dither_intensity;
- float scale_x, scale_y;
- rcti clip_rect;
- int xof, yof;
-
- if (render_view3d_disprect(scene, ar, v3d, rv3d, &clip_rect)) {
- scale_x = (float) BLI_rcti_size_x(&clip_rect) / rres.rectx;
- scale_y = (float) BLI_rcti_size_y(&clip_rect) / rres.recty;
- xof = clip_rect.xmin;
- yof = clip_rect.ymin;
- }
- else {
- scale_x = (float) ar->winx / rres.rectx;
- scale_y = (float) ar->winy / rres.recty;
- xof = rres.xof;
- yof = rres.yof;
- }
-
- /* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */
- force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL);
-
- /* Try using GLSL display transform. */
- if (force_fallback == false) {
- if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, dither, true)) {
- glEnable(GL_BLEND);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glPixelZoom(scale_x, scale_y);
- glaDrawPixelsTex(xof, yof, rres.rectx, rres.recty,
- GL_RGBA, GL_FLOAT, GL_NEAREST, rres.rectf);
- glPixelZoom(1.0f, 1.0f);
- glDisable(GL_BLEND);
-
- IMB_colormanagement_finish_glsl_draw();
- need_fallback = false;
- }
- }
-
- /* If GLSL failed, use old-school CPU-based transform. */
- if (need_fallback) {
- unsigned char *display_buffer = MEM_mallocN(4 * rres.rectx * rres.recty * sizeof(char),
- "render_view3d_draw");
-
- IMB_colormanagement_buffer_make_display_space(rres.rectf, display_buffer, rres.rectx, rres.recty,
- 4, dither, &scene->view_settings, &scene->display_settings);
-
- glEnable(GL_BLEND);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glPixelZoom(scale_x, scale_y);
- glaDrawPixelsAuto(xof, yof, rres.rectx, rres.recty,
- GL_RGBA, GL_UNSIGNED_BYTE,
- GL_NEAREST, display_buffer);
- glPixelZoom(1.0f, 1.0f);
- glDisable(GL_BLEND);
-
- MEM_freeN(display_buffer);
- }
- }
-
- RE_ReleaseResultImage(re);
-}
-
-void ED_viewport_render_kill_jobs(wmWindowManager *wm,
- Main *bmain,
- bool free_database)
-{
- bScreen *sc;
- ScrArea *sa;
- ARegion *ar;
-
- if (!wm)
- return;
-
- /* kill all actively running jobs */
- WM_jobs_kill(wm, NULL, render_view3d_startjob);
-
- /* loop over 3D view render engines */
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype != SPACE_VIEW3D)
- continue;
-
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- RegionView3D *rv3d;
-
- if (ar->regiontype != RGN_TYPE_WINDOW)
- continue;
-
- rv3d = ar->regiondata;
-
- if (rv3d->render_engine) {
- /* free render database now before we change data, because
- * RE_Database_Free will also loop over blender data */
- if (free_database) {
- char name[32];
- Render *re;
-
- sprintf(name, "View3dPreview %p", (void *)ar);
- re = RE_GetRender(name);
-
- if (re)
- RE_Database_Free(re);
-
- /* tag render engine to update entire database */
- rv3d->render_engine->update_flag |= RE_ENGINE_UPDATE_DATABASE;
- }
- else {
- /* quick shader update */
- rv3d->render_engine->update_flag |= RE_ENGINE_UPDATE_MA;
- }
- }
- }
- }
- }
-}
-
Scene *ED_render_job_get_scene(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1673,6 +1067,7 @@ Scene *ED_render_job_get_current_scene(const bContext *C)
return NULL;
}
+
/* Motion blur curve preset */
static int render_shutter_curve_preset_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 78cedf099a1..8006f5071d1 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -55,6 +55,10 @@
#include "BKE_sequencer.h"
#include "BKE_writeavi.h"
+#include "DEG_depsgraph.h"
+
+#include "DRW_engine.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -70,9 +74,9 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "GPU_glew.h"
-#include "GPU_compositing.h"
#include "GPU_framebuffer.h"
+#include "GPU_glew.h"
+#include "GPU_matrix.h"
#include "render_intern.h"
@@ -91,6 +95,9 @@ typedef struct OGLRender {
Main *bmain;
Render *re;
Scene *scene;
+ WorkSpace *workspace;
+ ViewLayer *view_layer;
+ Depsgraph *depsgraph;
View3D *v3d;
RegionView3D *rv3d;
@@ -114,7 +121,6 @@ typedef struct OGLRender {
GPUOffScreen *ofs;
int ofs_samples;
bool ofs_full_samples;
- GPUFX *fx;
int sizex, sizey;
int write_still;
@@ -148,17 +154,6 @@ typedef struct OGLRender {
#endif
} OGLRender;
-/* added because v3d is not always valid */
-static unsigned int screen_opengl_layers(OGLRender *oglrender)
-{
- if (oglrender->v3d) {
- return oglrender->scene->lay | oglrender->v3d->lay;
- }
- else {
- return oglrender->scene->lay;
- }
-}
-
static bool screen_opengl_is_multiview(OGLRender *oglrender)
{
View3D *v3d = oglrender->v3d;
@@ -271,8 +266,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
RE_ReleaseResult(oglrender->re);
}
-static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
+static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, RenderResult *rr)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = oglrender->scene;
ARegion *ar = oglrender->ar;
View3D *v3d = oglrender->v3d;
@@ -281,9 +278,8 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
const short view_context = (v3d != NULL);
- bool draw_bgpic = true;
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
- unsigned char *rect = NULL;
+ float *rectf = NULL;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
ImBuf *ibuf_result = NULL;
@@ -324,16 +320,18 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
unsigned char *gp_rect;
unsigned char *render_rect = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
+ DRW_opengl_context_enable();
GPU_offscreen_bind(oglrender->ofs, true);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
+ GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT);
wmOrtho2(0, sizex, 0, sizey);
- glTranslatef(sizex / 2, sizey / 2, 0.0f);
+ GPU_matrix_translate_2f(sizex / 2, sizey / 2);
G.f |= G_RENDER_OGL;
- ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
+ ED_gpencil_draw_ex(
+ view_layer, rv3d, scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
G.f &= ~G_RENDER_OGL;
gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
@@ -343,6 +341,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
}
GPU_offscreen_unbind(oglrender->ofs, true);
+ DRW_opengl_context_disable();
MEM_freeN(gp_rect);
}
@@ -357,12 +356,11 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
draw_flags |= (oglrender->ofs_full_samples) ? V3D_OFSDRAW_USE_FULL_SAMPLE : 0;
if (view_context) {
- draw_flags |= (draw_bgpic) ? V3D_OFSDRAW_USE_BACKGROUND : 0;
-
ibuf_view = ED_view3d_draw_offscreen_imbuf(
- oglrender->bmain, scene, v3d, ar, sizex, sizey,
- IB_rect, draw_flags, alpha_mode, oglrender->ofs_samples, viewname,
- oglrender->fx, oglrender->ofs, err_out);
+ depsgraph, scene, v3d->shading.type,
+ v3d, ar, sizex, sizey,
+ IB_rectfloat, draw_flags, alpha_mode, oglrender->ofs_samples, viewname,
+ oglrender->ofs, err_out);
/* for stamp only */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
@@ -370,18 +368,19 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
}
}
else {
- draw_flags |= (V3D_OFSDRAW_USE_GPENCIL | V3D_OFSDRAW_USE_BACKGROUND);
+ draw_flags |= V3D_OFSDRAW_USE_GPENCIL;
ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(
- oglrender->bmain, scene, scene->camera, oglrender->sizex, oglrender->sizey,
- IB_rect, draw_flags, OB_SOLID,
+ depsgraph, scene, OB_SOLID,
+ scene->camera, oglrender->sizex, oglrender->sizey,
+ IB_rectfloat, draw_flags,
alpha_mode, oglrender->ofs_samples, viewname,
- oglrender->fx, oglrender->ofs, err_out);
+ oglrender->ofs, err_out);
camera = scene->camera;
}
if (ibuf_view) {
ibuf_result = ibuf_view;
- rect = (unsigned char *)ibuf_view->rect;
+ rectf = (float *)ibuf_view->rect_float;
}
else {
fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
@@ -390,7 +389,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
if (ibuf_result != NULL) {
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, NULL, rect, NULL, rr->rectx, rr->recty, 4);
+ BKE_image_stamp_buf(scene, camera, NULL, NULL, rectf, rr->rectx, rr->recty, 4);
}
RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
IMB_freeImBuf(ibuf_result);
@@ -420,7 +419,7 @@ static void screen_opengl_render_write(OGLRender *oglrender)
else printf("OpenGL Render failed to write '%s'\n", name);
}
-static void addAlphaOverFloat(float dest[4], const float source[4])
+static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
{
/* d = s + (1-alpha_s)d*/
float mul;
@@ -434,92 +433,7 @@ static void addAlphaOverFloat(float dest[4], const float source[4])
}
-/* add renderlayer and renderpass for each grease pencil layer for using in composition */
-static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, RenderView *rv)
-{
- bGPdata *gpd = oglrender->scene->gpd;
- Scene *scene = oglrender->scene;
-
- /* sanity checks */
- if (gpd == NULL) {
- return;
- }
- if (scene == NULL) {
- return;
- }
- if (BLI_listbase_is_empty(&gpd->layers)) {
- return;
- }
- if (oglrender->v3d != NULL && (oglrender->v3d->flag2 & V3D_SHOW_GPENCIL) == 0) {
- return;
- }
-
- /* save old alpha mode */
- short oldalphamode = scene->r.alphamode;
- /* set alpha transparent for gp */
- scene->r.alphamode = R_ALPHAPREMUL;
-
- /* saves layer status */
- short *oldsts = MEM_mallocN(BLI_listbase_count(&gpd->layers) * sizeof(short), "temp_gplayers_flag");
- int i = 0;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- oldsts[i] = gpl->flag;
- ++i;
- }
- /* loop all layers to create separate render */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* dont draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE)
- continue;
- /* hide all layer except current */
- for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
- if (gpl != gph) {
- gph->flag |= GP_LAYER_HIDE;
- }
- }
-
- /* render this gp layer */
- screen_opengl_render_doit(oglrender, rr);
-
- /* add RendePass composite */
- RenderPass *rp = RE_create_gp_pass(rr, gpl->info, rv->name);
-
- /* copy image data from rectf */
- // XXX: Needs conversion.
- unsigned char *src = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
- if (src != NULL) {
- float *dest = rp->rect;
-
- int x, y, rectx, recty;
- rectx = rr->rectx;
- recty = rr->recty;
- for (y = 0; y < recty; y++) {
- for (x = 0; x < rectx; x++) {
- unsigned char *pixSrc = src + 4 * (rectx * y + x);
- if (pixSrc[3] > 0) {
- float *pixDest = dest + 4 * (rectx * y + x);
- float float_src[4];
- srgb_to_linearrgb_uchar4(float_src, pixSrc);
- addAlphaOverFloat(pixDest, float_src);
- }
- }
- }
- }
- /* back layer status */
- i = 0;
- for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) {
- gph->flag = oldsts[i];
- ++i;
- }
- }
- /* free memory */
- MEM_freeN(oldsts);
-
- /* back default alpha mode */
- scene->r.alphamode = oldalphamode;
-}
-
-static void screen_opengl_render_apply(OGLRender *oglrender)
+static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
{
RenderResult *rr;
RenderView *rv;
@@ -535,14 +449,13 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
int chanshown = sseq ? sseq->chanshown : 0;
BKE_sequencer_new_render_data(
- oglrender->bmain->eval_ctx, oglrender->bmain, scene,
- oglrender->sizex, oglrender->sizey, 100.0f,
+ oglrender->bmain, oglrender->depsgraph, scene,
+ oglrender->sizex, oglrender->sizey, 100.0f, false,
&context);
for (view_id = 0; view_id < oglrender->views_len; view_id++) {
context.view_id = view_id;
context.gpu_offscreen = oglrender->ofs;
- context.gpu_fx = oglrender->fx;
context.gpu_full_samples = oglrender->ofs_full_samples;
oglrender->seq_data.ibufs_arr[view_id] = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
@@ -554,13 +467,8 @@ 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. For sequencer, the render does not include renderpasses
- * TODO: The sequencer render of grease pencil should be rethought */
- if (!oglrender->is_sequencer) {
- add_gpencil_renderpass(oglrender, rr, rv);
- }
/* render composite */
- screen_opengl_render_doit(oglrender, rr);
+ screen_opengl_render_doit(C, oglrender, rr);
}
RE_ReleaseResult(oglrender->re);
@@ -576,11 +484,30 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
}
}
+static bool screen_opengl_fullsample_enabled(Scene *scene)
+{
+ if (scene->r.scemode & R_FULL_SAMPLE) {
+ return true;
+ }
+ else {
+ /* XXX TODO:
+ * Technically if the hardware supports MSAA we could keep using Blender 2.7x approach.
+ * However anti-aliasing without full_sample is not playing well even in 2.7x.
+ *
+ * For example, if you enable depth of field, there is aliasing, even if the viewport is fine.
+ * For 2.8x this is more complicated because so many things rely on shader.
+ * So until we fix the gpu_framebuffer anti-aliasing suupport we need to force full sample.
+ */
+ return true;
+ }
+}
+
static bool screen_opengl_render_init(bContext *C, wmOperator *op)
{
/* new render clears all callbacks */
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = CTX_wm_workspace(C);
Scene *scene = CTX_data_scene(C);
ScrArea *prevsa = CTX_wm_area(C);
@@ -589,7 +516,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
OGLRender *oglrender;
int sizex, sizey;
const int samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0;
- const bool full_samples = (samples != 0) && (scene->r.scemode & R_FULL_SAMPLE);
+ const bool full_samples = (samples != 0) && screen_opengl_fullsample_enabled(scene);
bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
@@ -634,7 +561,9 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
sizey = (scene->r.size * scene->r.ysch) / 100;
/* corrects render size with actual size, not every card supports non-power-of-two dimensions */
- ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out);
+ DRW_opengl_context_enable(); /* Offscreen creation needs to be done in DRW context. */
+ ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, true, true, err_out);
+ DRW_opengl_context_disable();
if (!ofs) {
BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
@@ -652,6 +581,9 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->sizey = sizey;
oglrender->bmain = CTX_data_main(C);
oglrender->scene = scene;
+ oglrender->workspace = workspace;
+ oglrender->view_layer = CTX_data_view_layer(C);
+ oglrender->depsgraph = CTX_data_depsgraph(C);
oglrender->cfrao = scene->r.cfra;
oglrender->write_still = is_write_still && !is_animation;
@@ -679,19 +611,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* apply immediately in case we're rendering from a script,
* running notifiers again will overwrite */
oglrender->scene->customdata_mask |= oglrender->scene->customdata_mask_modal;
-
- if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO)) {
- oglrender->fx = GPU_fx_compositor_create();
- }
- }
- else if (is_sequencer) {
- /* NOTE: We allow animation of DoF setting for flexibility in edits, so
- * we can't check in advance whether we need FX compositor or not.
- * We just always allocated it and make sure it doesn't add extra
- * overhead rather than memory allocation here if it's not really
- * needed.
- */
- oglrender->fx = GPU_fx_compositor_create();
}
/* create render */
@@ -706,7 +625,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->iuser.ok = 1;
/* create render result */
- RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL);
+ RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL);
/* create render views */
screen_opengl_views_setup(oglrender);
@@ -803,8 +722,9 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
}
if (oglrender->timer) { /* exec will not have a timer */
+ Depsgraph *depsgraph = oglrender->depsgraph;
scene->r.cfra = oglrender->cfrao;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, screen_opengl_layers(oglrender));
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer);
}
@@ -813,10 +733,9 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
- if (oglrender->fx)
- GPU_fx_compositor_destroy(oglrender->fx);
-
+ DRW_opengl_context_enable();
GPU_offscreen_free(oglrender->ofs);
+ DRW_opengl_context_disable();
if (oglrender->is_sequencer) {
MEM_freeN(oglrender->seq_data.ibufs_arr);
@@ -1004,6 +923,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
OGLRender *oglrender = op->customdata;
Scene *scene = oglrender->scene;
+ Depsgraph *depsgraph = oglrender->depsgraph;
char name[FILE_MAX];
bool ok = false;
const bool view_context = (oglrender->v3d != NULL);
@@ -1014,12 +934,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
if (CFRA < oglrender->nfra)
CFRA++;
while (CFRA < oglrender->nfra) {
- unsigned int lay = screen_opengl_layers(oglrender);
-
- if (lay & 0xFF000000)
- lay &= 0xFF000000;
-
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
CFRA++;
}
@@ -1041,11 +956,11 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
WM_cursor_time(oglrender->win, scene->r.cfra);
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, screen_opengl_layers(oglrender));
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
if (view_context) {
if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) {
- /* since BKE_scene_update_for_newframe() is used rather
+ /* since BKE_scene_graph_update_for_newframe() is used rather
* then ED_update_for_newframe() the camera needs to be set */
if (BKE_scene_camera_switch_update(scene)) {
oglrender->v3d->camera = scene->camera;
@@ -1057,7 +972,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
}
/* render into offscreen buffer */
- screen_opengl_render_apply(oglrender);
+ screen_opengl_render_apply(C, oglrender);
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
@@ -1107,7 +1022,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
if (anim == 0) {
- screen_opengl_render_apply(op->customdata);
+ screen_opengl_render_apply(C, op->customdata);
screen_opengl_render_end(C, op->customdata);
return OPERATOR_FINISHED;
}
@@ -1158,7 +1073,7 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op)
if (!is_animation) { /* same as invoke */
/* render image */
- screen_opengl_render_apply(op->customdata);
+ screen_opengl_render_apply(C, op->customdata);
screen_opengl_render_end(C, op->customdata);
return OPERATOR_FINISHED;
@@ -1175,7 +1090,7 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op)
}
/* no redraw needed, we leave state as we entered it */
-// ED_update_for_newframe(C, 1);
+// ED_update_for_newframe(C);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, CTX_data_scene(C));
return OPERATOR_FINISHED;
@@ -1186,8 +1101,8 @@ void RENDER_OT_opengl(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "OpenGL Render";
- ot->description = "OpenGL render active viewport";
+ ot->name = "Viewport Render";
+ ot->description = "Take a snapshot of the active viewport";
ot->idname = "RENDER_OT_opengl";
/* api callbacks */
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index af3786a73f7..7961ea27fdc 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -56,12 +56,15 @@ void ED_operatortypes_render(void)
WM_operatortype_append(MATERIAL_OT_copy);
WM_operatortype_append(MATERIAL_OT_paste);
- WM_operatortype_append(SCENE_OT_render_layer_add);
- WM_operatortype_append(SCENE_OT_render_layer_remove);
+ WM_operatortype_append(SCENE_OT_view_layer_add);
+ WM_operatortype_append(SCENE_OT_view_layer_remove);
WM_operatortype_append(SCENE_OT_render_view_add);
WM_operatortype_append(SCENE_OT_render_view_remove);
+ WM_operatortype_append(SCENE_OT_light_cache_bake);
+ WM_operatortype_append(SCENE_OT_light_cache_free);
+
#ifdef WITH_FREESTYLE
WM_operatortype_append(SCENE_OT_freestyle_module_add);
WM_operatortype_append(SCENE_OT_freestyle_module_remove);
@@ -85,9 +88,6 @@ void ED_operatortypes_render(void)
WM_operatortype_append(TEXTURE_OT_slot_copy);
WM_operatortype_append(TEXTURE_OT_slot_paste);
WM_operatortype_append(TEXTURE_OT_slot_move);
- WM_operatortype_append(TEXTURE_OT_envmap_save);
- WM_operatortype_append(TEXTURE_OT_envmap_clear);
- WM_operatortype_append(TEXTURE_OT_envmap_clear_all);
/* render_internal.c */
WM_operatortype_append(RENDER_OT_view_show);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index a8069b01026..ad2caead1e6 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -51,6 +51,7 @@
#include "DNA_world_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -69,7 +70,7 @@
#include "BKE_image.h"
#include "BKE_icons.h"
#include "BKE_lamp.h"
-#include "BKE_library.h"
+#include "BKE_layer.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -78,6 +79,10 @@
#include "BKE_texture.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#include "DEG_depsgraph_build.h"
+
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
@@ -85,15 +90,18 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_shader.h"
#include "RE_pipeline.h"
#include "RE_engine.h"
+#include "RE_shader_ext.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_datafiles.h"
#include "ED_render.h"
+#include "ED_screen.h"
#ifndef NDEBUG
/* Used for database init assert(). */
@@ -149,7 +157,8 @@ typedef struct ShaderPreview {
short *stop, *do_update;
Scene *scene;
- ID *id;
+ Depsgraph *depsgraph;
+ ID *id, *id_copy;
ID *parent;
MTex *slot;
@@ -164,6 +173,7 @@ typedef struct ShaderPreview {
int sizex, sizey;
unsigned int *pr_rect;
int pr_method;
+ bool own_id_copy;
Main *bmain;
Main *pr_main;
@@ -178,15 +188,16 @@ typedef struct IconPreviewSize {
typedef struct IconPreview {
Main *bmain;
Scene *scene;
+ Depsgraph *depsgraph;
void *owner;
- ID *id;
+ ID *id, *id_copy;
ListBase sizes;
} IconPreview;
/* *************************** Preview for buttons *********************** */
-static Main *G_pr_main = NULL;
static Main *G_pr_main_cycles = NULL;
+static Main *G_pr_main_grease_pencil = NULL;
#ifndef WITH_HEADLESS
static Main *load_main_from_memory(const void *blend, int blend_size)
@@ -214,8 +225,8 @@ void ED_preview_ensure_dbase(void)
static bool base_initialized = false;
BLI_assert(BLI_thread_is_main());
if (!base_initialized) {
- G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size);
G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size);
+ G_pr_main_grease_pencil = load_main_from_memory(datatoc_preview_grease_pencil_blend, datatoc_preview_grease_pencil_blend_size);
base_initialized = true;
}
#endif
@@ -224,64 +235,134 @@ void ED_preview_ensure_dbase(void)
static bool check_engine_supports_textures(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
- return type->flag & RE_USE_TEXTURE_PREVIEW;
+ return (type->flag & RE_USE_TEXTURE_PREVIEW) != 0;
}
-void ED_preview_free_dbase(void)
+static bool check_engine_supports_preview(Scene *scene)
{
- if (G_pr_main)
- BKE_main_free(G_pr_main);
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type->flag & RE_USE_PREVIEW) != 0;
+}
+void ED_preview_free_dbase(void)
+{
if (G_pr_main_cycles)
BKE_main_free(G_pr_main_cycles);
+
+ if (G_pr_main_grease_pencil)
+ BKE_main_free(G_pr_main_grease_pencil);
+}
+
+static Scene *preview_get_scene(Main *pr_main)
+{
+ if (pr_main == NULL) return NULL;
+
+ return pr_main->scene.first;
}
-static int preview_mat_has_sss(Material *mat, bNodeTree *ntree)
+static const char *preview_collection_name(const char pr_type)
{
- if (mat) {
- if (mat->sss_flag & MA_DIFF_SSS)
- return 1;
- if (mat->nodetree)
- if (preview_mat_has_sss(NULL, mat->nodetree))
- return 1;
+ switch (pr_type) {
+ case MA_FLAT:
+ return "Flat";
+ case MA_SPHERE:
+ return "Sphere";
+ case MA_CUBE:
+ return "Cube";
+ case MA_MONKEY:
+ return "Monkey";
+ case MA_SPHERE_A:
+ return "World Sphere";
+ case MA_TEXTURE:
+ return "Texture";
+ case MA_LAMP:
+ return "Lamp";
+ case MA_SKY:
+ return "Sky";
+ case MA_HAIR:
+ return "Hair";
+ case MA_ATMOS:
+ return "Atmosphere";
+ default:
+ BLI_assert(!"Unknown preview type");
+ return "";
}
- else if (ntree) {
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP && node->id) {
- if (preview_mat_has_sss(NULL, (bNodeTree *)node->id))
- return 1;
- }
- else if (node->id && ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) {
- mat = (Material *)node->id;
- if (mat->sss_flag & MA_DIFF_SSS)
- return 1;
- }
+}
+
+static void set_preview_collection(Scene *scene, ViewLayer *view_layer, char pr_type)
+{
+ LayerCollection *lc = view_layer->layer_collections.first;
+ const char *collection_name = preview_collection_name(pr_type);
+
+ for (lc = lc->layer_collections.first; lc; lc = lc->next) {
+ if (STREQ(lc->collection->id.name + 2, collection_name)) {
+ lc->collection->flag &= ~COLLECTION_RESTRICT_RENDER;
+ }
+ else {
+ lc->collection->flag |= COLLECTION_RESTRICT_RENDER;
}
}
- return 0;
+
+ BKE_layer_collection_sync(scene, view_layer);
}
-static Scene *preview_get_scene(Main *pr_main)
+static World *preview_get_localized_world(ShaderPreview *sp, World *world)
{
- if (pr_main == NULL) return NULL;
-
- return pr_main->scene.first;
+ if (world == NULL) {
+ return NULL;
+ }
+ if (sp->worldcopy != NULL) {
+ return sp->worldcopy;
+ }
+ sp->worldcopy = BKE_world_localize(world);
+ BLI_addtail(&sp->pr_main->world, sp->worldcopy);
+ return sp->worldcopy;
}
+static ID *duplicate_ids(ID *id, Depsgraph *depsgraph)
+{
+ if (id == NULL) {
+ /* Non-ID preview render. */
+ return NULL;
+ }
+
+ ID *id_eval = id;
+
+ if (depsgraph) {
+ id_eval = DEG_get_evaluated_id(depsgraph, id);
+ }
+
+ switch (GS(id->name)) {
+ case ID_MA:
+ return (ID *)BKE_material_localize((Material *)id_eval);
+ case ID_TE:
+ return (ID *)BKE_texture_localize((Tex *)id_eval);
+ case ID_LA:
+ return (ID *)BKE_lamp_localize((Lamp *)id_eval);
+ case ID_WO:
+ return (ID *)BKE_world_localize((World *)id_eval);
+ case ID_IM:
+ case ID_BR:
+ case ID_SCR:
+ return NULL;
+ default:
+ BLI_assert(!"ID type preview not supported.");
+ return NULL;
+ }
+}
/* call this with a pointer to initialize preview scene */
/* call this with NULL to restore assigned ID pointers in preview scene */
static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
{
Scene *sce;
- Base *base;
Main *pr_main = sp->pr_main;
memcpy(pr_main->name, BKE_main_blendfile_path(bmain), sizeof(pr_main->name));
sce = preview_get_scene(pr_main);
if (sce) {
+ ViewLayer *view_layer = sce->view_layers.first;
/* this flag tells render to not execute depsgraph or ipos etc */
sce->r.scemode |= R_BUTS_PREVIEW;
@@ -320,7 +401,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
* seems commonly used render engines does not support
* such kind of rendering.
*/
- BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_RENDER, sizeof(sce->r.engine));
+ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
}
else {
BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine));
@@ -331,94 +412,44 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
if (origmat) {
/* work on a copy */
- mat = BKE_material_localize(origmat);
- sp->matcopy = mat;
+ BLI_assert(sp->id_copy != NULL);
+ mat = sp->matcopy = (Material *)sp->id_copy;
+ sp->id_copy = NULL;
BLI_addtail(&pr_main->mat, mat);
- if (!BKE_scene_use_new_shading_nodes(scene)) {
- init_render_material(bmain, mat, 0, NULL); /* call that retrieves mode_l */
- end_render_material(mat);
-
- /* un-useful option */
- if (sp->pr_method == PR_ICON_RENDER)
- mat->shade_flag &= ~MA_OBCOLOR;
-
- /* turn on raytracing if needed */
- if (mat->mode_l & MA_RAYMIRROR)
- sce->r.mode |= R_RAYTRACE;
- if (mat->material_type == MA_TYPE_VOLUME)
- sce->r.mode |= R_RAYTRACE;
- if ((mat->mode_l & MA_RAYTRANSP) && (mat->mode_l & MA_TRANSP))
- sce->r.mode |= R_RAYTRACE;
- if (preview_mat_has_sss(mat, NULL))
- sce->r.mode |= R_SSS;
-
- /* turn off fake shadows if needed */
- /* this only works in a specific case where the preview.blend contains
- * an object starting with 'c' which has a material linked to it (not the obdata)
- * and that material has a fake shadow texture in the active texture slot */
- for (base = sce->base.first; base; base = base->next) {
- if (base->object->id.name[2] == 'c') {
- Material *shadmat = give_current_material(base->object, base->object->actcol);
- if (shadmat) {
- if (mat->mode2 & MA_CASTSHADOW) shadmat->septex = 0;
- else shadmat->septex |= 1;
- }
- }
- }
-
- /* turn off bounce lights for volume,
- * doesn't make much visual difference and slows it down too */
- for (base = sce->base.first; base; base = base->next) {
- if (base->object->type == OB_LAMP) {
- /* if doesn't match 'Lamp.002' --> main key light */
- if (!STREQ(base->object->id.name + 2, "Lamp.002")) {
- if (mat->material_type == MA_TYPE_VOLUME)
- base->object->restrictflag |= OB_RESTRICT_RENDER;
- else
- base->object->restrictflag &= ~OB_RESTRICT_RENDER;
- }
- }
- }
+ /* use current scene world to light sphere */
+ if (mat->pr_type == MA_SPHERE_A && sp->pr_method == PR_BUTS_RENDER) {
+ /* Use current scene world to light sphere. */
+ sce->world = preview_get_localized_world(sp, scene->world);
}
- else {
- if (mat->pr_type == MA_SPHERE_A && sp->pr_method == PR_BUTS_RENDER) {
- /* Use current scene world to light sphere. */
- sce->world = scene->world;
- }
- else if (sce->world) {
- /* Use a default world color. Using the current
- * scene world can be slow if it has big textures. */
- sce->world->use_nodes = false;
- sce->world->horr = 0.5f;
- sce->world->horg = 0.5f;
- sce->world->horb = 0.5f;
- }
+ else if (sce->world) {
+ /* Use a default world color. Using the current
+ * scene world can be slow if it has big textures. */
+ sce->world->use_nodes = false;
+ sce->world->horr = 0.5f;
+ sce->world->horg = 0.5f;
+ sce->world->horb = 0.5f;
}
if (sp->pr_method == PR_ICON_RENDER) {
- if (mat->material_type == MA_TYPE_HALO) {
- sce->lay = 1 << MA_FLAT;
- }
- else {
- sce->lay = 1 << MA_SPHERE_A;
- }
+ set_preview_collection(sce, view_layer, MA_SPHERE_A);
}
else {
- sce->lay = 1 << mat->pr_type;
+ set_preview_collection(sce, view_layer, mat->pr_type);
+
if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) {
/* two previews, they get copied by wmJob */
BKE_node_preview_init_tree(mat->nodetree, sp->sizex, sp->sizey, true);
+ /* WATCH: Accessing origmat is not safe! */
BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, true);
}
}
}
else {
- sce->r.mode &= ~(R_OSA | R_RAYTRACE | R_SSS);
-
+ sce->r.mode &= ~(R_OSA);
}
- for (base = sce->base.first; base; base = base->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
if (base->object->id.name[2] == 'p') {
/* copy over object color, in case material uses it */
copy_v4_v4(base->object->col, sp->col);
@@ -432,7 +463,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
(*matar)[actcol] = mat;
}
else if (base->object->type == OB_LAMP) {
- base->object->restrictflag &= ~OB_RESTRICT_RENDER;
+ base->flag |= BASE_VISIBLE;
}
}
}
@@ -441,39 +472,18 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
Tex *tex = NULL, *origtex = (Tex *)id;
if (origtex) {
- tex = BKE_texture_localize(origtex);
- sp->texcopy = tex;
+ BLI_assert(sp->id_copy != NULL);
+ tex = sp->texcopy = (Tex *)sp->id_copy;
+ sp->id_copy = NULL;
BLI_addtail(&pr_main->tex, tex);
}
- sce->lay = 1 << MA_TEXTURE;
-
- for (base = sce->base.first; base; base = base->next) {
- if (base->object->id.name[2] == 't') {
- Material *mat = give_current_material(base->object, base->object->actcol);
- if (mat && mat->mtex[0]) {
- mat->mtex[0]->tex = tex;
-
- if (tex && sp->slot)
- mat->mtex[0]->which_output = sp->slot->which_output;
-
- mat->mtex[0]->mapto &= ~MAP_ALPHA;
- mat->alpha = 1.0f;
-
- /* show alpha in this case */
- if (tex == NULL || (tex->flag & TEX_PRV_ALPHA)) {
- if (!(tex && tex->type == TEX_IMAGE && (tex->imaflag & (TEX_USEALPHA | TEX_CALCALPHA)) == 0)) {
- mat->mtex[0]->mapto |= MAP_ALPHA;
- mat->alpha = 0.0f;
- }
- }
- }
- }
- }
+ set_preview_collection(sce, view_layer, MA_TEXTURE);
if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) {
/* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true);
BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, true);
+ /* WATCH: Accessing origtex is not safe! */
+ BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true);
}
}
else if (id_type == ID_LA) {
@@ -481,35 +491,23 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
/* work on a copy */
if (origla) {
- la = BKE_lamp_localize(origla);
- sp->lampcopy = la;
+ BLI_assert(sp->id_copy != NULL);
+ la = sp->lampcopy = (Lamp *)sp->id_copy;
+ sp->id_copy = NULL;
BLI_addtail(&pr_main->lamp, la);
}
- sce->lay = 1 << MA_LAMP;
+ set_preview_collection(sce, view_layer, MA_LAMP);
- if (!BKE_scene_use_new_shading_nodes(scene)) {
- if (la && la->type == LA_SUN && (la->sun_effect_type & LA_SUN_EFFECT_SKY)) {
- sce->lay = 1 << MA_ATMOS;
- sce->world = scene->world;
- sce->camera = (Object *)BLI_findstring(&pr_main->object, "CameraAtmo", offsetof(ID, name) + 2);
- }
- else {
- sce->world = NULL;
- sce->camera = (Object *)BLI_findstring(&pr_main->object, "Camera", offsetof(ID, name) + 2);
- }
- }
- else {
- if (sce->world) {
- /* Only use lighting from the lamp. */
- sce->world->use_nodes = false;
- sce->world->horr = 0.0f;
- sce->world->horg = 0.0f;
- sce->world->horb = 0.0f;
- }
+ if (sce->world) {
+ /* Only use lighting from the lamp. */
+ sce->world->use_nodes = false;
+ sce->world->horr = 0.0f;
+ sce->world->horg = 0.0f;
+ sce->world->horb = 0.0f;
}
- for (base = sce->base.first; base; base = base->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
if (base->object->id.name[2] == 'p') {
if (base->object->type == OB_LAMP)
base->object->data = la;
@@ -518,25 +516,28 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
if (la && la->nodetree && sp->pr_method == PR_NODE_RENDER) {
/* two previews, they get copied by wmJob */
- BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true);
BKE_node_preview_init_tree(la->nodetree, sp->sizex, sp->sizey, true);
+ /* WATCH: Accessing origla is not safe! */
+ BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true);
}
}
else if (id_type == ID_WO) {
World *wrld = NULL, *origwrld = (World *)id;
if (origwrld) {
- wrld = BKE_world_localize(origwrld);
- sp->worldcopy = wrld;
+ BLI_assert(sp->id_copy != NULL);
+ wrld = sp->worldcopy = (World *)sp->id_copy;
+ sp->id_copy = NULL;
BLI_addtail(&pr_main->world, wrld);
}
- sce->lay = 1 << MA_SKY;
+ set_preview_collection(sce, view_layer, MA_SKY);
sce->world = wrld;
if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) {
/* two previews, they get copied by wmJob */
BKE_node_preview_init_tree(wrld->nodetree, sp->sizex, sp->sizey, true);
+ /* WATCH: Accessing origwrld is not safe! */
BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true);
}
}
@@ -607,7 +608,9 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
if (re)
RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte, 0);
- glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(&state, fx, fy, rres.rectx, rres.recty, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, rect_byte,
+ 1.0f, 1.0f, NULL);
MEM_freeN(rect_byte);
@@ -719,6 +722,61 @@ static void shader_preview_updatejob(void *spv)
}
}
+/* Renders texture directly to render buffer. */
+static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Render *re)
+{
+ /* Setup output buffer. */
+ int width = sp->sizex;
+ int height = sp->sizey;
+
+ /* This is needed otherwise no RenderResult is created. */
+ sce->r.scemode &= ~R_BUTS_PREVIEW;
+ RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, width, height, NULL);
+ RE_SetScene(re, sce);
+
+ /* Create buffer in empty RenderView created in the init step. */
+ RenderResult *rr = RE_AcquireResultWrite(re);
+ RenderView *rv = (RenderView *)rr->views.first;
+ rv->rectf = MEM_callocN(sizeof(float) * 4 * width * height, "texture render result");
+ RE_ReleaseResult(re);
+
+ /* Get texture image pool (if any) */
+ struct ImagePool *img_pool = BKE_image_pool_new();
+ BKE_texture_fetch_images_for_pool(tex, img_pool);
+
+ /* Fill in image buffer. */
+ float *rect_float = rv->rectf;
+ float tex_coord[3] = {0.0f, 0.0f, 0.0f};
+ bool color_manage = true;
+
+ for (int y = 0; y < height; y++) {
+ /* Tex coords between -1.0f and 1.0f. */
+ tex_coord[1] = ((float)y / (float)height) * 2.0f - 1.0f;
+
+ for (int x = 0; x < width; x++) {
+ tex_coord[0] = ((float)x / (float)height) * 2.0f - 1.0f;
+
+ /* Evaluate texture at tex_coord .*/
+ TexResult texres = {0};
+ BKE_texture_get_value_ex(sce, tex, tex_coord, &texres, img_pool, color_manage);
+
+ rect_float[0] = texres.tr;
+ rect_float[1] = texres.tg;
+ rect_float[2] = texres.tb;
+ rect_float[3] = 1.0f;
+
+ rect_float += 4;
+ }
+
+ /* Check if we should cancel texture preview. */
+ if (shader_preview_break(sp)) {
+ break;
+ }
+ }
+
+ BKE_image_pool_free(img_pool);
+}
+
static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int first)
{
Render *re;
@@ -728,6 +786,11 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
char name[32];
int sizex;
Main *pr_main = sp->pr_main;
+ ID *id_eval = id;
+
+ if (sp->depsgraph) {
+ id_eval = DEG_get_evaluated_id(sp->depsgraph, id);
+ }
/* in case of split preview, use border render */
if (split) {
@@ -746,8 +809,9 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
sce->r.size = 100;
}
+
/* get the stuff from the builtin preview dbase */
- sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
+ sce = preview_prepare_scene(sp->bmain, sp->scene, id_eval, idtype, sp);
if (sce == NULL) return;
if (!split || first) sprintf(name, "Preview %p", sp->owner);
@@ -789,7 +853,13 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
((Camera *)sce->camera->data)->lens *= (float)sp->sizey / (float)sizex;
/* entire cycle for render engine */
- RE_PreviewRender(re, pr_main, sce);
+ if (idtype == ID_TE) {
+ shader_preview_texture(sp, (Tex *)id, sce, re);
+ }
+ else {
+ /* Render preview scene */
+ RE_PreviewRender(re, pr_main, sce);
+ }
((Camera *)sce->camera->data)->lens = oldlens;
@@ -837,70 +907,51 @@ static void shader_preview_free(void *customdata)
Main *pr_main = sp->pr_main;
if (sp->matcopy) {
- struct IDProperty *properties;
-
- /* node previews */
- shader_preview_updatejob(sp);
-
- /* get rid of copied material */
+ sp->id_copy = (ID *)sp->matcopy;
BLI_remlink(&pr_main->mat, sp->matcopy);
-
- BKE_material_free(sp->matcopy);
-
- properties = IDP_GetProperties((ID *)sp->matcopy, false);
- if (properties) {
- IDP_FreeProperty(properties);
- MEM_freeN(properties);
- }
- MEM_freeN(sp->matcopy);
}
if (sp->texcopy) {
- struct IDProperty *properties;
- /* node previews */
- shader_preview_updatejob(sp);
-
- /* get rid of copied texture */
+ sp->id_copy = (ID *)sp->texcopy;
BLI_remlink(&pr_main->tex, sp->texcopy);
- BKE_texture_free(sp->texcopy);
-
- properties = IDP_GetProperties((ID *)sp->texcopy, false);
- if (properties) {
- IDP_FreeProperty(properties);
- MEM_freeN(properties);
- }
- MEM_freeN(sp->texcopy);
}
if (sp->worldcopy) {
- struct IDProperty *properties;
- /* node previews */
- shader_preview_updatejob(sp);
-
- /* get rid of copied world */
+ sp->id_copy = (ID *)sp->worldcopy;
BLI_remlink(&pr_main->world, sp->worldcopy);
- BKE_world_free(sp->worldcopy);
-
- properties = IDP_GetProperties((ID *)sp->worldcopy, false);
- if (properties) {
- IDP_FreeProperty(properties);
- MEM_freeN(properties);
- }
- MEM_freeN(sp->worldcopy);
}
if (sp->lampcopy) {
- struct IDProperty *properties;
+ sp->id_copy = (ID *)sp->lampcopy;
+ BLI_remlink(&pr_main->lamp, sp->lampcopy);
+ }
+ if (sp->id_copy) {
/* node previews */
shader_preview_updatejob(sp);
-
- /* get rid of copied lamp */
- BLI_remlink(&pr_main->lamp, sp->lampcopy);
- BKE_lamp_free(sp->lampcopy);
-
- properties = IDP_GetProperties((ID *)sp->lampcopy, false);
+ }
+ if (sp->id_copy && sp->own_id_copy) {
+ struct IDProperty *properties;
+ /* get rid of copied ID */
+ properties = IDP_GetProperties(sp->id_copy, false);
if (properties) {
IDP_FreeProperty(properties);
MEM_freeN(properties);
}
- MEM_freeN(sp->lampcopy);
+ switch (GS(sp->id_copy->name)) {
+ case ID_MA:
+ BKE_material_free((Material *)sp->id_copy);
+ break;
+ case ID_TE:
+ BKE_texture_free((Tex *)sp->id_copy);
+ break;
+ case ID_LA:
+ BKE_lamp_free((Lamp *)sp->id_copy);
+ break;
+ case ID_WO:
+ BKE_world_free((World *)sp->id_copy);
+ break;
+ default:
+ BLI_assert(!"ID type preview not supported.");
+ break;
+ }
+ MEM_freeN(sp->id_copy);
}
MEM_freeN(sp);
@@ -1036,6 +1087,12 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
*do_update = true;
}
+ else if (idtype == ID_SCR) {
+ bScreen *screen = (bScreen *)id;
+
+ ED_screen_preview_render(screen, sp->sizex, sp->sizey, sp->pr_rect);
+ *do_update = true;
+ }
else {
/* re-use shader job */
shader_preview_startjob(customdata, stop, do_update);
@@ -1045,12 +1102,6 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
if (idtype == ID_WO) {
set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
}
- else if (idtype == ID_MA) {
- Material *ma = (Material *)id;
-
- if (ma->material_type == MA_TYPE_HALO)
- set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255);
- }
}
}
}
@@ -1095,7 +1146,6 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
{
IconPreview *ip = (IconPreview *)customdata;
IconPreviewSize *cur_size;
- const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene);
for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
PreviewImage *prv = ip->owner;
@@ -1105,33 +1155,40 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short
continue;
}
+ if (!check_engine_supports_preview(ip->scene)) {
+ continue;
+ }
+
ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
const bool is_render = !(prv->tag & PRV_TAG_DEFFERED);
/* construct shader preview from image size and previewcustomdata */
sp->scene = ip->scene;
+ sp->depsgraph = ip->depsgraph;
sp->owner = ip->owner;
sp->sizex = cur_size->sizex;
sp->sizey = cur_size->sizey;
sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED;
sp->pr_rect = cur_size->rect;
sp->id = ip->id;
+ sp->id_copy = ip->id_copy;
sp->bmain = ip->bmain;
+ sp->own_id_copy = false;
+ Material *ma = NULL;
if (is_render) {
BLI_assert(ip->id);
- if (use_new_shading) {
- /* texture icon rendering is hardcoded to use BI,
- * so don't even think of using cycle's bmain for
- * texture icons
- */
- if (GS(ip->id->name) != ID_TE)
- sp->pr_main = G_pr_main_cycles;
- else
- sp->pr_main = G_pr_main;
+
+ /* grease pencil use its own preview file */
+ if (GS(ip->id->name) == ID_MA) {
+ ma = (Material *)ip->id;
+ }
+
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
+ sp->pr_main = G_pr_main_cycles;
}
else {
- sp->pr_main = G_pr_main;
+ sp->pr_main = G_pr_main_grease_pencil;
}
}
@@ -1180,6 +1237,15 @@ static void icon_preview_free(void *customdata)
{
IconPreview *ip = (IconPreview *)customdata;
+ if (ip->id_copy) {
+ /* Feels a bit hacky just to reuse shader_preview_free() */
+ ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+ sp->id_copy = ip->id_copy;
+ sp->own_id_copy = true;
+ shader_preview_free(sp);
+ ip->id_copy = NULL;
+ }
+
BLI_freelistN(&ip->sizes);
MEM_freeN(ip);
}
@@ -1196,6 +1262,7 @@ void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, unsigned int *rec
ip.scene = scene;
ip.owner = BKE_previewimg_id_ensure(id);
ip.id = id;
+ ip.id_copy = duplicate_ids(id, NULL);
icon_preview_add_size(&ip, rect, sizex, sizey);
@@ -1227,8 +1294,10 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
/* customdata for preview thread */
ip->bmain = CTX_data_main(C);
ip->scene = CTX_data_scene(C);
+ ip->depsgraph = CTX_data_depsgraph(C);
ip->owner = owner;
ip->id = id;
+ ip->id_copy = duplicate_ids(id, ip->depsgraph);
icon_preview_add_size(ip, rect, sizex, sizey);
@@ -1255,10 +1324,15 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
ShaderPreview *sp;
Scene *scene = CTX_data_scene(C);
short id_type = GS(id->name);
- bool use_new_shading = BKE_scene_use_new_shading_nodes(scene);
+
+ /* Use workspace render only for buttons Window, since the other previews are related to the datablock. */
+
+ if (!check_engine_supports_preview(scene)) {
+ return;
+ }
/* Only texture node preview is supported with Cycles. */
- if (use_new_shading && method == PR_NODE_RENDER && id_type != ID_TE) {
+ if (method == PR_NODE_RENDER && id_type != ID_TE) {
return;
}
@@ -1270,22 +1344,32 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
/* customdata for preview thread */
sp->scene = scene;
+ sp->depsgraph = CTX_data_depsgraph(C);
sp->owner = owner;
sp->sizex = sizex;
sp->sizey = sizey;
sp->pr_method = method;
sp->id = id;
+ sp->id_copy = duplicate_ids(id, sp->depsgraph);
+ sp->own_id_copy = true;
sp->parent = parent;
sp->slot = slot;
sp->bmain = CTX_data_main(C);
+ Material *ma = NULL;
- /* hardcoded preview .blend for cycles/internal, this should be solved
+ /* hardcoded preview .blend for Eevee + Cycles, this should be solved
* once with custom preview .blend path for external engines */
- if ((method != PR_NODE_RENDER) && id_type != ID_TE && use_new_shading) {
+
+ /* grease pencil use its own preview file */
+ if (GS(id->name) == ID_MA) {
+ ma = (Material *)id;
+ }
+
+ if ((ma == NULL) || (ma->gp_style == NULL)) {
sp->pr_main = G_pr_main_cycles;
}
else {
- sp->pr_main = G_pr_main;
+ sp->pr_main = G_pr_main_grease_pencil;
}
if (ob && ob->totcol) copy_v4_v4(sp->col, ob->col);
@@ -1299,10 +1383,8 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
-void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
+void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
{
if (wm)
WM_jobs_kill(wm, NULL, common_preview_startjob);
-
- ED_viewport_render_kill_jobs(wm, bmain, false);
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 5b198774b71..99abb8b61c7 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -33,6 +33,7 @@
#include "DNA_curve_types.h"
#include "DNA_lamp_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -50,10 +51,11 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
+#include "BKE_editmesh.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
@@ -62,10 +64,11 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
-#include "BKE_editmesh.h"
-
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#ifdef WITH_FREESTYLE
# include "BKE_freestyle.h"
@@ -83,6 +86,7 @@
#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_render.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "RNA_define.h"
@@ -91,6 +95,8 @@
#include "RE_pipeline.h"
+#include "engines/eevee/eevee_lightcache.h"
+
#include "render_intern.h" // own include
/********************** material slot operators *********************/
@@ -154,7 +160,7 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob);
@@ -180,6 +186,7 @@ void OBJECT_OT_material_slot_remove(wmOperatorType *ot)
static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
+ View3D *v3d = CTX_wm_view3d(C);
if (!ob)
return OPERATOR_CANCELLED;
@@ -203,7 +210,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
if (nurbs) {
for (nu = nurbs->first; nu; nu = nu->next) {
- if (ED_curve_nurb_select_check(ob->data, nu)) {
+ if (ED_curve_nurb_select_check(v3d, nu)) {
nu->mat_nr = ob->actcol - 1;
}
}
@@ -220,7 +227,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
@@ -300,6 +307,7 @@ static int material_slot_de_select(bContext *C, bool select)
}
}
+ DEG_id_tag_update(ob->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
return OPERATOR_FINISHED;
@@ -361,7 +369,7 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
if (ob_iter->totcol == ob->totcol) {
ob_iter->actcol = ob->actcol;
- DAG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob_iter->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter);
}
}
@@ -375,9 +383,9 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
void OBJECT_OT_material_slot_copy(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy Material to Others";
+ ot->name = "Copy Material to Selected";
ot->idname = "OBJECT_OT_material_slot_copy";
- ot->description = "Copies materials to other selected objects";
+ ot->description = "Copy material to selected objects";
/* api callbacks */
ot->exec = material_slot_copy_exec;
@@ -426,7 +434,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
MEM_freeN(slot_remap);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
@@ -460,9 +468,9 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -471,12 +479,14 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
ma = BKE_material_copy(bmain, ma);
}
else {
- ma = BKE_material_add(bmain, DATA_("Material"));
-
- if (BKE_scene_use_new_shading_nodes(scene)) {
- ED_node_shader_default(C, &ma->id);
- ma->use_nodes = true;
+ if ((!ob) || (ob->type != OB_GPENCIL)) {
+ ma = BKE_material_add(bmain, DATA_("Material"));
+ }
+ else {
+ ma = BKE_material_add_gpencil(bmain, DATA_("Material"));
}
+ ED_node_shader_default(C, &ma->id);
+ ma->use_nodes = true;
}
/* hook into UI */
@@ -536,14 +546,6 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
* pointer use also increases user, so this compensates it */
id_us_min(&tex->id);
- if (ptr.id.data && GS(((ID *)ptr.id.data)->name) == ID_MA &&
- RNA_property_pointer_get(&ptr, prop).id.data == NULL)
- {
- /* In case we are assigning new texture to a material, and active slot was empty, reset 'use' flag. */
- Material *ma = (Material *)ptr.id.data;
- ma->septex &= ~(1 << ma->texact);
- }
-
RNA_id_pointer_create(&tex->id, &idptr);
RNA_property_pointer_set(&ptr, prop, idptr);
RNA_property_update(C, &ptr, prop);
@@ -572,7 +574,6 @@ void TEXTURE_OT_new(wmOperatorType *ot)
static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
@@ -584,11 +585,8 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
}
else {
wo = BKE_world_add(bmain, DATA_("World"));
-
- if (BKE_scene_use_new_shading_nodes(scene)) {
- ED_node_shader_default(C, &wo->id);
- wo->use_nodes = true;
- }
+ ED_node_shader_default(C, &wo->id);
+ wo->use_nodes = true;
}
/* hook into UI */
@@ -625,61 +623,248 @@ void WORLD_OT_new(wmOperatorType *ot)
/********************** render layer operators *********************/
-static int render_layer_add_exec(bContext *C, wmOperator *UNUSED(op))
+static int view_layer_add_exec(bContext *C, wmOperator *UNUSED(op))
{
+ wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = BKE_view_layer_add(scene, NULL);
- BKE_scene_add_render_layer(scene, NULL);
- scene->r.actlay = BLI_listbase_count(&scene->r.layers) - 1;
+ if (win) {
+ WM_window_set_active_view_layer(win, view_layer);
+ }
- DAG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DEG_id_tag_update(&scene->id, 0);
+ DEG_relations_tag_update(CTX_data_main(C));
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
return OPERATOR_FINISHED;
}
-void SCENE_OT_render_layer_add(wmOperatorType *ot)
+void SCENE_OT_view_layer_add(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Render Layer";
- ot->idname = "SCENE_OT_render_layer_add";
- ot->description = "Add a render layer";
+ ot->name = "Add View Layer";
+ ot->idname = "SCENE_OT_view_layer_add";
+ ot->description = "Add a view layer";
/* api callbacks */
- ot->exec = render_layer_add_exec;
+ ot->exec = view_layer_add_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
-static int render_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
+static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *rl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- if (!BKE_scene_remove_render_layer(CTX_data_main(C), scene, rl))
+ if (!ED_scene_view_layer_delete(bmain, scene, view_layer, NULL)) {
return OPERATOR_CANCELLED;
+ }
- DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
}
-void SCENE_OT_render_layer_remove(wmOperatorType *ot)
+void SCENE_OT_view_layer_remove(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove Render Layer";
- ot->idname = "SCENE_OT_render_layer_remove";
- ot->description = "Remove the selected render layer";
+ ot->name = "Remove View Layer";
+ ot->idname = "SCENE_OT_view_layer_remove";
+ ot->description = "Remove the selected view layer";
/* api callbacks */
- ot->exec = render_layer_remove_exec;
+ ot->exec = view_layer_remove_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
+/********************** light cache operators *********************/
+enum {
+ LIGHTCACHE_SUBSET_ALL = 0,
+ LIGHTCACHE_SUBSET_DIRTY,
+ LIGHTCACHE_SUBSET_CUBE,
+};
+
+static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
+{
+ if (scene->eevee.light_cache != NULL) {
+ int subset = RNA_enum_get(op->ptr, "subset");
+ switch (subset) {
+ case LIGHTCACHE_SUBSET_ALL:
+ scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE;
+ break;
+ case LIGHTCACHE_SUBSET_CUBE:
+ scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE;
+ break;
+ case LIGHTCACHE_SUBSET_DIRTY:
+ /* Leave tag untouched. */
+ break;
+ }
+ }
+}
+
+/* catch esc */
+static int light_cache_bake_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Scene *scene = (Scene *) op->customdata;
+
+ /* no running blender, remove handler and pass through */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+
+ /* running render */
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
+ }
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void light_cache_bake_cancel(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ Scene *scene = (Scene *) op->customdata;
+
+ /* kill on cancel, because job is using op->reports */
+ WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_RENDER);
+}
+
+/* executes blocking render */
+static int light_cache_bake_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ G.is_break = false;
+
+ /* TODO abort if selected engine is not eevee. */
+ void *rj = EEVEE_lightbake_job_data_alloc(bmain, view_layer, scene, false);
+
+ light_cache_bake_tag_cache(scene, op);
+
+ short stop = 0, do_update; float progress; /* Not actually used. */
+ EEVEE_lightbake_job(rj, &stop, &do_update, &progress);
+ EEVEE_lightbake_job_data_free(rj);
+
+ // no redraw needed, we leave state as we entered it
+ ED_update_for_newframe(bmain, CTX_data_depsgraph(C));
+
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static int light_cache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ int delay = RNA_int_get(op->ptr, "delay");
+
+ wmJob *wm_job = EEVEE_lightbake_job_create(wm, win, bmain, view_layer, scene, delay);
+
+ if (!wm_job) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* add modal handler for ESC */
+ WM_event_add_modal_handler(C, op);
+
+ light_cache_bake_tag_cache(scene, op);
+
+ /* store actual owner of job, so modal operator could check for it,
+ * the reason of this is that active scene could change when rendering
+ * several layers from compositor [#31800]
+ */
+ op->customdata = scene;
+
+ WM_jobs_start(wm, wm_job);
+
+ WM_cursor_wait(0);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCENE_OT_light_cache_bake(wmOperatorType *ot)
+{
+ static const EnumPropertyItem light_cache_subset_items[] = {
+ {LIGHTCACHE_SUBSET_ALL, "ALL", 0, "All LightProbes", "Bake both irradiance grids and reflection cubemaps"},
+ {LIGHTCACHE_SUBSET_DIRTY, "DIRTY", 0, "Dirty Only", "Only bake lightprobes that are marked as dirty"},
+ {LIGHTCACHE_SUBSET_CUBE, "CUBEMAPS", 0, "Cubemaps Only", "Try to only bake reflection cubemaps if irradiance "
+ "grids are up to date"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Bake Light Cache";
+ ot->idname = "SCENE_OT_light_cache_bake";
+ ot->description = "Bake the active view layer lighting";
+
+ /* api callbacks */
+ ot->invoke = light_cache_bake_invoke;
+ ot->modal = light_cache_bake_modal;
+ ot->cancel = light_cache_bake_cancel;
+ ot->exec = light_cache_bake_exec;
+
+ ot->prop = RNA_def_int(ot->srna, "delay", 0, 0, 2000, "Delay", "Delay in millisecond before baking starts", 0, 2000);
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+
+ ot->prop = RNA_def_enum(ot->srna, "subset", light_cache_subset_items, 0, "Subset", "Subset of probes to update");
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+}
+
+static bool light_cache_free_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ return scene->eevee.light_cache;
+}
+
+static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* kill potential bake job first (see T57011) */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE);
+
+ if (!scene->eevee.light_cache) {
+ return OPERATOR_CANCELLED;
+ }
+
+ EEVEE_lightcache_free(scene->eevee.light_cache);
+ scene->eevee.light_cache = NULL;
+
+ EEVEE_lightcache_info_update(&scene->eevee);
+
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_light_cache_free(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Light Cache";
+ ot->idname = "SCENE_OT_light_cache_free";
+ ot->description = "Free cached indirect lighting";
+
+ /* api callbacks */
+ ot->exec = light_cache_free_exec;
+ ot->poll = light_cache_free_poll;
+}
+
/********************** render view operators *********************/
static bool render_view_remove_poll(bContext *C)
@@ -771,9 +956,9 @@ static bool freestyle_active_module_poll(bContext *C)
static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_freestyle_module_add(&srl->freestyleConfig);
+ BKE_freestyle_module_add(&view_layer->freestyle_config);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -797,13 +982,13 @@ void SCENE_OT_freestyle_module_add(wmOperatorType *ot)
static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
FreestyleModuleConfig *module = ptr.data;
- BKE_freestyle_module_delete(&srl->freestyleConfig, module);
+ BKE_freestyle_module_delete(&view_layer->freestyle_config, module);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -827,13 +1012,13 @@ void SCENE_OT_freestyle_module_remove(wmOperatorType *ot)
static int freestyle_module_move_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
FreestyleModuleConfig *module = ptr.data;
int dir = RNA_enum_get(op->ptr, "direction");
- if (BKE_freestyle_module_move(&srl->freestyleConfig, module, dir)) {
- DAG_id_tag_update(&scene->id, 0);
+ if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) {
+ DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
@@ -869,11 +1054,11 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_freestyle_lineset_add(bmain, &srl->freestyleConfig, NULL);
+ BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, NULL);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -895,22 +1080,20 @@ void SCENE_OT_freestyle_lineset_add(wmOperatorType *ot)
static bool freestyle_active_lineset_poll(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- if (!srl) {
+ if (!view_layer) {
return false;
}
- return BKE_freestyle_lineset_get_active(&srl->freestyleConfig) != NULL;
+ return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != NULL;
}
static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- FRS_copy_active_lineset(&srl->freestyleConfig);
+ FRS_copy_active_lineset(&view_layer->freestyle_config);
return OPERATOR_FINISHED;
}
@@ -933,11 +1116,11 @@ void SCENE_OT_freestyle_lineset_copy(wmOperatorType *ot)
static int freestyle_lineset_paste_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- FRS_paste_active_lineset(&srl->freestyleConfig);
+ FRS_paste_active_lineset(&view_layer->freestyle_config);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -961,11 +1144,11 @@ void SCENE_OT_freestyle_lineset_paste(wmOperatorType *ot)
static int freestyle_lineset_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
- FRS_delete_active_lineset(&srl->freestyleConfig);
+ FRS_delete_active_lineset(&view_layer->freestyle_config);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -989,11 +1172,11 @@ void SCENE_OT_freestyle_lineset_remove(wmOperatorType *ot)
static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
int dir = RNA_enum_get(op->ptr, "direction");
- if (FRS_move_active_lineset(&srl->freestyleConfig, dir)) {
- DAG_id_tag_update(&scene->id, 0);
+ if (FRS_move_active_lineset(&view_layer->freestyle_config, dir)) {
+ DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
@@ -1028,9 +1211,8 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
if (!lineset) {
BKE_report(op->reports, RPT_ERROR, "No active lineset to add a new line style to");
@@ -1043,7 +1225,7 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
else {
lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle");
}
- DAG_id_tag_update(&lineset->linestyle->id, 0);
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
@@ -1066,9 +1248,8 @@ void SCENE_OT_freestyle_linestyle_new(wmOperatorType *ot)
static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
int type = RNA_enum_get(op->ptr, "type");
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
@@ -1079,7 +1260,7 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type");
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&lineset->linestyle->id, 0);
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
@@ -1106,9 +1287,8 @@ void SCENE_OT_freestyle_color_modifier_add(wmOperatorType *ot)
static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
int type = RNA_enum_get(op->ptr, "type");
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
@@ -1119,7 +1299,7 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type");
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&lineset->linestyle->id, 0);
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
@@ -1146,9 +1326,8 @@ void SCENE_OT_freestyle_alpha_modifier_add(wmOperatorType *ot)
static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
int type = RNA_enum_get(op->ptr, "type");
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
@@ -1159,7 +1338,7 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type");
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&lineset->linestyle->id, 0);
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
@@ -1186,9 +1365,8 @@ void SCENE_OT_freestyle_thickness_modifier_add(wmOperatorType *ot)
static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
int type = RNA_enum_get(op->ptr, "type");
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
@@ -1199,7 +1377,7 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type");
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&lineset->linestyle->id, 0);
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
@@ -1239,9 +1417,8 @@ static int freestyle_get_modifier_type(PointerRNA *ptr)
static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
LineStyleModifier *modifier = ptr.data;
@@ -1266,7 +1443,7 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&lineset->linestyle->id, 0);
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
@@ -1289,9 +1466,8 @@ void SCENE_OT_freestyle_modifier_remove(wmOperatorType *ot)
static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
LineStyleModifier *modifier = ptr.data;
@@ -1316,7 +1492,7 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
return OPERATOR_CANCELLED;
}
- DAG_id_tag_update(&lineset->linestyle->id, 0);
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
@@ -1339,9 +1515,8 @@ void SCENE_OT_freestyle_modifier_copy(wmOperatorType *ot)
static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
LineStyleModifier *modifier = ptr.data;
int dir = RNA_enum_get(op->ptr, "direction");
@@ -1370,7 +1545,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
}
if (changed) {
- DAG_id_tag_update(&lineset->linestyle->id, 0);
+ DEG_id_tag_update(&lineset->linestyle->id, 0);
WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
}
@@ -1405,8 +1580,8 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
static int freestyle_stroke_material_create_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(view_layer);
if (!linestyle) {
BKE_report(op->reports, RPT_ERROR, "No active line style in the current scene");
@@ -1456,15 +1631,6 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act - 1, 0);
BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
- if (GS(id->name) == ID_MA) {
- Material *ma = (Material *)id;
- int mtexuse = ma->septex & (1 << act);
- ma->septex &= ~(1 << act);
- ma->septex |= (ma->septex & (1 << (act - 1))) << 1;
- ma->septex &= ~(1 << (act - 1));
- ma->septex |= mtexuse >> 1;
- }
-
set_active_mtex(id, act - 1);
}
}
@@ -1478,20 +1644,11 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act + 1, 0);
BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
- if (GS(id->name) == ID_MA) {
- Material *ma = (Material *)id;
- int mtexuse = ma->septex & (1 << act);
- ma->septex &= ~(1 << act);
- ma->septex |= (ma->septex & (1 << (act + 1))) >> 1;
- ma->septex &= ~(1 << (act + 1));
- ma->septex |= mtexuse << 1;
- }
-
set_active_mtex(id, act + 1);
}
}
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C));
}
@@ -1522,181 +1679,6 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
-/********************** environment map operators *********************/
-
-static int save_envmap(wmOperator *op, Scene *scene, EnvMap *env, char *path, const char imtype)
-{
- PropertyRNA *prop;
- float layout[12];
-
- if ((prop = RNA_struct_find_property(op->ptr, "layout"))) {
- RNA_property_float_get_array(op->ptr, prop, layout);
- }
- else {
- memcpy(layout, default_envmap_layout, sizeof(layout));
- }
-
- if (RE_WriteEnvmapResult(op->reports, scene, env, path, imtype, layout)) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-
-}
-
-static int envmap_save_exec(bContext *C, wmOperator *op)
-{
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
- Scene *scene = CTX_data_scene(C);
- //int imtype = RNA_enum_get(op->ptr, "file_type");
- char imtype = scene->r.im_format.imtype;
- char path[FILE_MAX];
-
- RNA_string_get(op->ptr, "filepath", path);
-
- if (scene->r.scemode & R_EXTENSION) {
- BKE_image_path_ensure_ext_from_imformat(path, &scene->r.im_format);
- }
-
- WM_cursor_wait(1);
-
- save_envmap(op, scene, tex->env, path, imtype);
-
- WM_cursor_wait(0);
-
- WM_event_add_notifier(C, NC_TEXTURE, tex);
-
- return OPERATOR_FINISHED;
-}
-
-static int envmap_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- Main *bmain = CTX_data_main(C);
- //Scene *scene= CTX_data_scene(C);
-
- if (RNA_struct_property_is_set(op->ptr, "filepath"))
- return envmap_save_exec(C, op);
-
- //RNA_enum_set(op->ptr, "file_type", scene->r.im_format.imtype);
- RNA_string_set(op->ptr, "filepath", BKE_main_blendfile_path(bmain));
- WM_event_add_fileselect(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static bool envmap_save_poll(bContext *C)
-{
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
-
- if (!tex)
- return 0;
- if (!tex->env || !tex->env->ok)
- return 0;
- if (tex->env->cube[1] == NULL)
- return 0;
-
- return 1;
-}
-
-void TEXTURE_OT_envmap_save(wmOperatorType *ot)
-{
- PropertyRNA *prop;
- /* identifiers */
- ot->name = "Save Environment Map";
- ot->idname = "TEXTURE_OT_envmap_save";
- ot->description = "Save the current generated Environment map to an image file";
-
- /* api callbacks */
- ot->exec = envmap_save_exec;
- ot->invoke = envmap_save_invoke;
- ot->poll = envmap_save_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL; /* no undo since this doesnt modify the env-map */
-
- /* properties */
- prop = RNA_def_float_array(ot->srna, "layout", 12, default_envmap_layout, 0.0f, 0.0f,
- "File layout",
- "Flat array describing the X,Y position of each cube face in the output image, "
- "where 1 is the size of a face - order is [+Z -Z +Y -X -Y +X] "
- "(use -1 to skip a face)", 0.0f, 0.0f);
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-}
-
-static int envmap_clear_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
-
- BKE_texture_envmap_free_data(tex->env);
-
- WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
-
- return OPERATOR_FINISHED;
-}
-
-static bool envmap_clear_poll(bContext *C)
-{
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
-
- if (!tex)
- return 0;
- if (!tex->env || !tex->env->ok)
- return 0;
- if (tex->env->cube[1] == NULL)
- return 0;
-
- return 1;
-}
-
-void TEXTURE_OT_envmap_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Environment Map";
- ot->idname = "TEXTURE_OT_envmap_clear";
- ot->description = "Discard the environment map and free it from memory";
-
- /* api callbacks */
- ot->exec = envmap_clear_exec;
- ot->poll = envmap_clear_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-}
-
-static int envmap_clear_all_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Tex *tex;
-
- for (tex = bmain->tex.first; tex; tex = tex->id.next)
- if (tex->env)
- BKE_texture_envmap_free_data(tex->env);
-
- WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
-
- return OPERATOR_FINISHED;
-}
-
-void TEXTURE_OT_envmap_clear_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear All Environment Maps";
- ot->idname = "TEXTURE_OT_envmap_clear_all";
- ot->description = "Discard all environment maps in the .blend file and free them from memory";
-
- /* api callbacks */
- ot->exec = envmap_clear_all_exec;
- ot->poll = envmap_clear_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/********************** material operators *********************/
/* material copy/paste */
@@ -1768,17 +1750,6 @@ static void copy_mtex_copybuf(ID *id)
MTex **mtex = NULL;
switch (GS(id->name)) {
- case ID_MA:
- mtex = &(((Material *)id)->mtex[(int)((Material *)id)->texact]);
- break;
- case ID_LA:
- mtex = &(((Lamp *)id)->mtex[(int)((Lamp *)id)->texact]);
- // la->mtex[(int)la->texact] // TODO
- break;
- case ID_WO:
- mtex = &(((World *)id)->mtex[(int)((World *)id)->texact]);
- // mtex= wrld->mtex[(int)wrld->texact]; // TODO
- break;
case ID_PA:
mtex = &(((ParticleSettings *)id)->mtex[(int)((ParticleSettings *)id)->texact]);
break;
@@ -1806,17 +1777,6 @@ static void paste_mtex_copybuf(ID *id)
return;
switch (GS(id->name)) {
- case ID_MA:
- mtex = &(((Material *)id)->mtex[(int)((Material *)id)->texact]);
- break;
- case ID_LA:
- mtex = &(((Lamp *)id)->mtex[(int)((Lamp *)id)->texact]);
- // la->mtex[(int)la->texact] // TODO
- break;
- case ID_WO:
- mtex = &(((World *)id)->mtex[(int)((World *)id)->texact]);
- // mtex= wrld->mtex[(int)wrld->texact]; // TODO
- break;
case ID_PA:
mtex = &(((ParticleSettings *)id)->mtex[(int)((ParticleSettings *)id)->texact]);
break;
@@ -1886,7 +1846,7 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
if (id == NULL) {
Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
- Lamp *la = CTX_data_pointer_get_type(C, "lamp", &RNA_Lamp).data;
+ Lamp *la = CTX_data_pointer_get_type(C, "light", &RNA_Light).data;
World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
ParticleSystem *psys = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
FreestyleLineStyle *linestyle = CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data;
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index ceb4c0b27ba..c42eda678ba 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -38,24 +38,25 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "DNA_windowmanager_types.h"
+#include "DRW_engine.h"
+
#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_icons.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
-
-#include "GPU_material.h"
-#include "GPU_buffers.h"
+#include "BKE_workspace.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -64,16 +65,21 @@
#include "ED_render.h"
#include "ED_view3d.h"
-#include "render_intern.h" // own include
+#include "DEG_depsgraph.h"
-extern Material defmaterial;
+#include "WM_api.h"
+
+#include "render_intern.h" // own include
/***************************** Render Engines ********************************/
-void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
+void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int updated)
{
/* viewport rendering update on data changes, happens after depsgraph
* updates if there was any change. context is set to the 3d view */
+ Main *bmain = update_ctx->bmain;
+ Scene *scene = update_ctx->scene;
+ ViewLayer *view_layer = update_ctx->view_layer;
bContext *C;
wmWindowManager *wm;
wmWindow *win;
@@ -102,26 +108,23 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
wm = bmain->wm.first;
for (win = wm->windows.first; win; win = win->next) {
- bScreen *sc = win->screen;
+ bScreen *sc = WM_window_get_active_screen(win);
ScrArea *sa;
ARegion *ar;
CTX_wm_window_set(C, win);
for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype != SPACE_VIEW3D)
+ if (sa->spacetype != SPACE_VIEW3D) {
continue;
-
+ }
+ View3D *v3d = sa->spacedata.first;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- RegionView3D *rv3d;
- RenderEngine *engine;
-
- if (ar->regiontype != RGN_TYPE_WINDOW)
+ if (ar->regiontype != RGN_TYPE_WINDOW) {
continue;
-
- rv3d = ar->regiondata;
- engine = rv3d->render_engine;
-
+ }
+ RegionView3D *rv3d = ar->regiondata;
+ RenderEngine *engine = rv3d->render_engine;
/* call update if the scene changed, or if the render engine
* tagged itself for update (e.g. because it was busy at the
* time of the last update) */
@@ -133,6 +136,23 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
engine->flag &= ~RE_ENGINE_DO_UPDATE;
engine->type->view_update(engine, C);
+
+ }
+ else {
+ RenderEngineType *engine_type =
+ ED_view3d_engine_type(scene, v3d->shading.type);
+ if (updated) {
+ DRW_notify_view_update(
+ (&(DRWUpdateContext){
+ .bmain = bmain,
+ .depsgraph = update_ctx->depsgraph,
+ .scene = scene,
+ .view_layer = view_layer,
+ .ar = ar,
+ .v3d = (View3D *)sa->spacedata.first,
+ .engine_type = engine_type
+ }));
+ }
}
}
}
@@ -143,23 +163,6 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
recursive_check = false;
}
-void ED_render_scene_update_pre(Main *bmain, Scene *scene, bool time)
-{
- /* Blender internal might access to the data which is gonna to be freed
- * by the scene update functions. This applies for example to simulation
- * data like smoke and fire.
- */
- if (time && !BKE_scene_use_new_shading_nodes(scene)) {
- bScreen *sc;
- ScrArea *sa;
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- ED_render_engine_area_exit(bmain, sa);
- }
- }
- }
-}
-
void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
{
/* clear all render engines in this area */
@@ -179,18 +182,23 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
void ED_render_engine_changed(Main *bmain)
{
/* on changing the render engine type, clear all running render engines */
- bScreen *sc;
- ScrArea *sa;
- Scene *scene;
-
- for (sc = bmain->screen.first; sc; sc = sc->id.next)
- for (sa = sc->areabase.first; sa; sa = sa->next)
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
ED_render_engine_area_exit(bmain, sa);
-
+ }
+ }
RE_FreePersistentData();
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- ED_render_id_flush_update(bmain, &scene->id);
+ /* Inform all render engines and draw managers. */
+ DEGEditorUpdateContext update_ctx = {NULL};
+ update_ctx.bmain = bmain;
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ update_ctx.scene = scene;
+ LISTBASE_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
+ /* TDODO(sergey): Iterate over depsgraphs instead? */
+ update_ctx.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ update_ctx.view_layer = view_layer;
+ ED_render_id_flush_update(&update_ctx, &scene->id);
+ }
if (scene->nodetree) {
ntreeCompositUpdateRLayers(scene->nodetree);
}
@@ -198,7 +206,7 @@ void ED_render_engine_changed(Main *bmain)
}
/***************************** Updates ***********************************
- * ED_render_id_flush_update gets called from DAG_id_tag_update, to do *
+ * ED_render_id_flush_update gets called from DEG_id_tag_update, to do *
* editor level updates when the ID changes. when these ID blocks are in *
* the dependency graph, we can get rid of the manual dependency checks */
@@ -228,263 +236,46 @@ static void render_engine_flag_changed(Main *bmain, int update_flag)
}
}
-static int mtex_use_tex(MTex **mtex, int tot, Tex *tex)
-{
- int a;
-
- if (!mtex)
- return 0;
-
- for (a = 0; a < tot; a++)
- if (mtex[a] && mtex[a]->tex == tex)
- return 1;
-
- return 0;
-}
-
-static int nodes_use_tex(bNodeTree *ntree, Tex *tex)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (node->id == (ID *)tex) {
- return 1;
- }
- else if (GS(node->id->name) == ID_MA) {
- if (mtex_use_tex(((Material *)node->id)->mtex, MAX_MTEX, tex))
- return 1;
- }
- else if (node->type == NODE_GROUP) {
- if (nodes_use_tex((bNodeTree *)node->id, tex))
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-static int nodes_use_material(bNodeTree *ntree, Material *ma)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (node->id == (ID *)ma) {
- return 1;
- }
- else if (node->type == NODE_GROUP) {
- if (nodes_use_material((bNodeTree *)node->id, ma))
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-static void material_changed(Main *bmain, Material *ma)
+static void material_changed(Main *UNUSED(bmain), Material *ma)
{
- Material *parent;
- Object *ob;
- Scene *scene;
- int texture_draw = false;
-
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
-
- /* glsl */
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
-
- /* find node materials using this */
- for (parent = bmain->mat.first; parent; parent = parent->id.next) {
- if (parent->use_nodes && parent->nodetree && nodes_use_material(parent->nodetree, ma)) {
- /* pass */
- }
- else {
- continue;
- }
-
- BKE_icon_changed(BKE_icon_id_ensure(&parent->id));
-
- if (parent->gpumaterial.first)
- GPU_material_free(&parent->gpumaterial);
- }
-
- /* find if we have a scene with textured display */
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- if (scene->customdata_mask & CD_MASK_MTFACE) {
- texture_draw = true;
- break;
- }
- }
-
- /* find textured objects */
- if (texture_draw) {
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- DerivedMesh *dm = ob->derivedFinal;
- Material ***material = give_matarar(ob);
- short a, *totmaterial = give_totcolp(ob);
-
- if (dm && totmaterial && material) {
- for (a = 0; a < *totmaterial; a++) {
- if ((*material)[a] == ma) {
- GPU_drawobject_free(dm);
- break;
- }
- }
- }
- }
- }
-
}
-static void lamp_changed(Main *bmain, Lamp *la)
+static void lamp_changed(Main *UNUSED(bmain), Lamp *la)
{
- Object *ob;
- Material *ma;
-
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&la->id));
-
- /* glsl */
- for (ob = bmain->object.first; ob; ob = ob->id.next)
- if (ob->data == la && ob->gpulamp.first)
- GPU_lamp_free(ob);
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
-
- if (defmaterial.gpumaterial.first)
- GPU_material_free(&defmaterial.gpumaterial);
-}
-
-static int material_uses_texture(Material *ma, Tex *tex)
-{
- if (mtex_use_tex(ma->mtex, MAX_MTEX, tex))
- return true;
- else if (ma->use_nodes && ma->nodetree && nodes_use_tex(ma->nodetree, tex))
- return true;
-
- return false;
}
static void texture_changed(Main *bmain, Tex *tex)
{
- Material *ma;
- Lamp *la;
- World *wo;
Scene *scene;
- Object *ob;
+ ViewLayer *view_layer;
bNode *node;
- bool texture_draw = false;
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&tex->id));
- /* paint overlays */
- for (scene = bmain->scene.first; scene; scene = scene->id.next)
- BKE_paint_invalidate_overlay_tex(scene, tex);
-
- /* find materials */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (!material_uses_texture(ma, tex))
- continue;
-
- BKE_icon_changed(BKE_icon_id_ensure(&ma->id));
-
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
- }
-
- /* find lamps */
- for (la = bmain->lamp.first; la; la = la->id.next) {
- if (mtex_use_tex(la->mtex, MAX_MTEX, tex)) {
- lamp_changed(bmain, la);
- }
- else if (la->nodetree && nodes_use_tex(la->nodetree, tex)) {
- lamp_changed(bmain, la);
- }
- else {
- continue;
- }
- }
-
- /* find worlds */
- for (wo = bmain->world.first; wo; wo = wo->id.next) {
- if (mtex_use_tex(wo->mtex, MAX_MTEX, tex)) {
- /* pass */
- }
- else if (wo->nodetree && nodes_use_tex(wo->nodetree, tex)) {
- /* pass */
- }
- else {
- continue;
- }
-
- BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
-
- if (wo->gpumaterial.first)
- GPU_material_free(&wo->gpumaterial);
- }
-
- /* find compositing nodes */
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
+ /* paint overlays */
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ BKE_paint_invalidate_overlay_tex(scene, view_layer, tex);
+ }
+ /* find compositing nodes */
if (scene->use_nodes && scene->nodetree) {
for (node = scene->nodetree->nodes.first; node; node = node->next) {
if (node->id == &tex->id)
ED_node_tag_update_id(&scene->id);
}
}
-
- if (scene->customdata_mask & CD_MASK_MTFACE)
- texture_draw = true;
- }
-
- /* find textured objects */
- if (texture_draw) {
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- DerivedMesh *dm = ob->derivedFinal;
- Material ***material = give_matarar(ob);
- short a, *totmaterial = give_totcolp(ob);
-
- if (dm && totmaterial && material) {
- for (a = 0; a < *totmaterial; a++) {
- if (ob->matbits && ob->matbits[a])
- ma = ob->mat[a];
- else
- ma = (*material)[a];
-
- if (ma && material_uses_texture(ma, tex)) {
- GPU_drawobject_free(dm);
- break;
- }
- }
- }
- }
}
}
-static void world_changed(Main *bmain, World *wo)
+static void world_changed(Main *UNUSED(bmain), World *wo)
{
- Material *ma;
-
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&wo->id));
-
- /* glsl */
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
-
- if (defmaterial.gpumaterial.first)
- GPU_material_free(&defmaterial.gpumaterial);
-
- if (wo->gpumaterial.first)
- GPU_material_free(&wo->gpumaterial);
}
static void image_changed(Main *bmain, Image *ima)
@@ -503,41 +294,26 @@ static void image_changed(Main *bmain, Image *ima)
static void scene_changed(Main *bmain, Scene *scene)
{
Object *ob;
- Material *ma;
- World *wo;
/* glsl */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->gpulamp.first)
- GPU_lamp_free(ob);
-
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
BKE_texpaint_slots_refresh_object(scene, ob);
BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- GPU_drawobject_free(ob->derivedFinal);
}
}
-
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
-
- for (wo = bmain->world.first; wo; wo = wo->id.next)
- if (wo->gpumaterial.first)
- GPU_material_free(&wo->gpumaterial);
-
- if (defmaterial.gpumaterial.first)
- GPU_material_free(&defmaterial.gpumaterial);
}
-void ED_render_id_flush_update(Main *bmain, ID *id)
+void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id)
{
/* this can be called from render or baking thread when a python script makes
* changes, in that case we don't want to do any editor updates, and making
* GPU changes is not possible because OpenGL only works in the main thread */
- if (!BLI_thread_is_main())
+ if (!BLI_thread_is_main()) {
return;
-
+ }
+ Main *bmain = update_ctx->bmain;
+ /* Internal ID update handlers. */
switch (GS(id->name)) {
case ID_MA:
material_changed(bmain, (Material *)id);
@@ -563,15 +339,4 @@ void ED_render_id_flush_update(Main *bmain, ID *id)
render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER);
break;
}
-
-}
-
-
-void ED_render_internal_init(void)
-{
- RenderEngineType *ret = RE_engines_find(RE_engine_id_BLENDER_RENDER);
-
- ret->view_update = render_view3d_update;
- ret->view_draw = render_view3d_draw;
-
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index c43083a1616..12f9c8f40c1 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -91,8 +91,10 @@ static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow *
/* find an imagewindow showing render result */
for (*win = wm->windows.first; *win; *win = (*win)->next) {
- if ((*win)->screen->scene == scene) {
- for (sa = (*win)->screen->areabase.first; sa; sa = sa->next) {
+ if (WM_window_get_active_scene(*win) == scene) {
+ const bScreen *screen = WM_window_get_active_screen(*win);
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_IMAGE) {
sima = sa->spacedata.first;
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT)
@@ -248,7 +250,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
}
/* test if we have a temp screen in front */
- if (win->screen->temp) {
+ if (WM_window_is_temp_screen(win)) {
wm_window_lower(win);
return OPERATOR_FINISHED;
}
@@ -294,7 +296,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
wmWindow *wincur = CTX_wm_window(C);
/* test if we have currently a temp screen active */
- if (wincur->screen->temp) {
+ if (WM_window_is_temp_screen(wincur)) {
wm_window_lower(wincur);
}
else {
@@ -303,8 +305,9 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* is there another window on current scene showing result? */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
- bScreen *sc = win->screen;
- if ((sc->temp && ((ScrArea *)sc->areabase.first)->spacetype == SPACE_IMAGE) ||
+ const bScreen *sc = WM_window_get_active_screen(win);
+
+ if ((WM_window_is_temp_screen(win) && ((ScrArea *)sc->areabase.first)->spacetype == SPACE_IMAGE) ||
(win == winshow && winshow != wincur))
{
wm_window_raise(win);
diff --git a/source/blender/editors/scene/CMakeLists.txt b/source/blender/editors/scene/CMakeLists.txt
new file mode 100644
index 00000000000..9fbebbc58cc
--- /dev/null
+++ b/source/blender/editors/scene/CMakeLists.txt
@@ -0,0 +1,44 @@
+# ***** 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): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ ../include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ scene_edit.c
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+blender_add_lib(bf_editor_scene "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
new file mode 100644
index 00000000000..0553e223c55
--- /dev/null
+++ b/source/blender/editors/scene/scene_edit.c
@@ -0,0 +1,275 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/scene/scene_edit.c
+ * \ingroup edscene
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_library_remap.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_object_types.h"
+#include "DNA_workspace_types.h"
+
+#include "ED_object.h"
+#include "ED_render.h"
+#include "ED_scene.h"
+#include "ED_screen.h"
+#include "ED_util.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+
+Scene *ED_scene_add(Main *bmain, bContext *C, wmWindow *win, eSceneCopyMethod method)
+{
+ Scene *scene_new;
+
+ if (method == SCE_COPY_NEW) {
+ scene_new = BKE_scene_add(bmain, DATA_("Scene"));
+ }
+ else { /* different kinds of copying */
+ Scene *scene_old = WM_window_get_active_scene(win);
+
+ scene_new = BKE_scene_copy(bmain, scene_old, method);
+
+ /* these can't be handled in blenkernel currently, so do them here */
+ if (method == SCE_COPY_LINK_DATA) {
+ ED_object_single_users(bmain, scene_new, false, true);
+ }
+ else if (method == SCE_COPY_FULL) {
+ ED_editors_flush_edits(C, false);
+ ED_object_single_users(bmain, scene_new, true, true);
+ }
+ }
+
+ WM_window_set_active_scene(bmain, C, win, scene_new);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, scene_new);
+
+ return scene_new;
+}
+
+/**
+ * \note Only call outside of area/region loops
+ * \return true if successful
+ */
+bool ED_scene_delete(bContext *C, Main *bmain, wmWindow *win, Scene *scene)
+{
+ Scene *scene_new;
+
+ /* kill running jobs */
+ wmWindowManager *wm = bmain->wm.first;
+ WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_ANY);
+
+ if (scene->id.prev)
+ scene_new = scene->id.prev;
+ else if (scene->id.next)
+ scene_new = scene->id.next;
+ else
+ return false;
+
+ WM_window_set_active_scene(bmain, C, win, scene_new);
+
+ BKE_libblock_remap(bmain, scene, scene_new, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ id_us_clear_real(&scene->id);
+ if (scene->id.us == 0) {
+ BKE_libblock_free(bmain, scene);
+ }
+
+ return true;
+}
+
+/* Depsgraph updates after scene becomes active in a window. */
+void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
+{
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, layer, true);
+
+ BKE_scene_set_background(bmain, scene);
+ DEG_graph_relations_update(depsgraph, bmain, scene, layer);
+ DEG_on_visible_update(bmain, false);
+
+ ED_render_engine_changed(bmain);
+ ED_update_for_newframe(bmain, depsgraph);
+}
+
+static bool view_layer_remove_poll(
+ const Scene *scene, const ViewLayer *layer)
+{
+ const int act = BLI_findindex(&scene->view_layers, layer);
+
+ if (act == -1) {
+ return false;
+ }
+ else if ((scene->view_layers.first == scene->view_layers.last) &&
+ (scene->view_layers.first == layer))
+ {
+ /* ensure 1 layer is kept */
+ return false;
+ }
+
+ return true;
+}
+
+static void view_layer_remove_unset_nodetrees(const Main *bmain, Scene *scene, ViewLayer *layer)
+{
+ int act_layer_index = BLI_findindex(&scene->view_layers, layer);
+
+ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
+ if (sce->nodetree) {
+ BKE_nodetree_remove_layer_n(sce->nodetree, scene, act_layer_index);
+ }
+ }
+}
+
+bool ED_scene_view_layer_delete(
+ Main *bmain, Scene *scene, ViewLayer *layer,
+ ReportList *reports)
+{
+ if (view_layer_remove_poll(scene, layer) == false) {
+ if (reports) {
+ BKE_reportf(reports, RPT_ERROR, "View layer '%s' could not be removed from scene '%s'",
+ layer->name, scene->id.name + 2);
+ }
+
+ return false;
+ }
+
+ /* We need to unset nodetrees before removing the layer, otherwise its index will be -1. */
+ view_layer_remove_unset_nodetrees(bmain, scene, layer);
+
+ BLI_remlink(&scene->view_layers, layer);
+ BLI_assert(BLI_listbase_is_empty(&scene->view_layers) == false);
+
+ /* Remove from windows. */
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene == scene && STREQ(win->view_layer_name, layer->name)) {
+ ViewLayer *first_layer = BKE_view_layer_default_view(scene);
+ STRNCPY(win->view_layer_name, first_layer->name);
+ }
+ }
+
+ BKE_view_layer_free(layer);
+
+ DEG_id_tag_update(&scene->id, 0);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | NA_REMOVED, scene);
+
+ return true;
+}
+
+static int scene_new_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ ED_scene_add(bmain, C, win, type);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCENE_OT_new(wmOperatorType *ot)
+{
+ static EnumPropertyItem type_items[] = {
+ {SCE_COPY_NEW, "NEW", 0, "New", "Add new scene"},
+ {SCE_COPY_EMPTY, "EMPTY", 0, "Copy Settings", "Make a copy without any objects"},
+ {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
+ {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
+ {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "New Scene";
+ ot->description = "Add new scene by type";
+ ot->idname = "SCENE_OT_new";
+
+ /* api callbacks */
+ ot->exec = scene_new_exec;
+ ot->invoke = WM_menu_invoke;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
+}
+
+static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (G.debug & G_DEBUG)
+ printf("scene delete %p\n", scene);
+
+ WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCENE_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Scene";
+ ot->description = "Delete active scene";
+ ot->idname = "SCENE_OT_delete";
+
+ /* api callbacks */
+ ot->exec = scene_delete_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void ED_operatortypes_scene(void)
+{
+ WM_operatortype_append(SCENE_OT_new);
+ WM_operatortype_append(SCENE_OT_delete);
+}
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index 43e044b613a..e01be2ed709 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -23,8 +23,10 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../blenloader
../../blentranslation
../../bmesh
+ ../../depsgraph
../../gpu
../../imbuf
../../makesdna
@@ -40,12 +42,17 @@ set(INC_SYS
set(SRC
area.c
+ area_utils.c
glutil.c
screen_context.c
screen_draw.c
screen_edit.c
+ screen_geometry.c
screen_ops.c
+ screen_user_menu.c
screendump.c
+ workspace_edit.c
+ workspace_layout_edit.c
screen_intern.h
)
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 3ca989c92fe..94b30f8e3b0 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -41,24 +41,30 @@
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
-
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
#include "RNA_types.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "wm_subwindow.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_space_api.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_draw.h"
+#include "GPU_state.h"
+#include "GPU_framebuffer.h"
+
#include "BLF_api.h"
#include "IMB_imbuf.h"
@@ -72,11 +78,17 @@
#include "screen_intern.h"
-extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */
+enum RegionEmbossSide {
+ REGION_EMBOSS_LEFT = (1 << 0),
+ REGION_EMBOSS_TOP = (1 << 1),
+ REGION_EMBOSS_BOTTOM = (1 << 2),
+ REGION_EMBOSS_RIGHT = (1 << 3),
+ REGION_EMBOSS_ALL = REGION_EMBOSS_LEFT | REGION_EMBOSS_TOP | REGION_EMBOSS_RIGHT | REGION_EMBOSS_BOTTOM,
+};
/* general area and region code */
-static void region_draw_emboss(const ARegion *ar, const rcti *scirct)
+static void region_draw_emboss(const ARegion *ar, const rcti *scirct, int sides)
{
rcti rect;
@@ -87,36 +99,58 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct)
rect.ymax = scirct->ymax - ar->winrct.ymin;
/* set transp line */
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ float color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
+ UI_GetThemeColor3fv(TH_EDITOR_OUTLINE, color);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
- /* right */
- glColor4ub(0, 0, 0, 30);
- sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax);
+ immBeginAtMost(GPU_PRIM_LINES, 8);
- /* bottom */
- glColor4ub(0, 0, 0, 30);
- sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin);
+ /* right */
+ if (sides & REGION_EMBOSS_RIGHT) {
+ immVertex2f(pos, rect.xmax, rect.ymax);
+ immVertex2f(pos, rect.xmax, rect.ymin);
+ }
+
+ /* bottom */
+ if (sides & REGION_EMBOSS_BOTTOM) {
+ immVertex2f(pos, rect.xmax, rect.ymin);
+ immVertex2f(pos, rect.xmin, rect.ymin);
+ }
- /* top */
- glColor4ub(255, 255, 255, 30);
- sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax);
+ /* left */
+ if (sides & REGION_EMBOSS_LEFT) {
+ immVertex2f(pos, rect.xmin, rect.ymin);
+ immVertex2f(pos, rect.xmin, rect.ymax);
+ }
+
+ /* top */
+ if (sides & REGION_EMBOSS_TOP) {
+ immVertex2f(pos, rect.xmin, rect.ymax);
+ immVertex2f(pos, rect.xmax, rect.ymax);
+ }
- /* left */
- glColor4ub(255, 255, 255, 30);
- sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax);
+ immEnd();
+ immUnbindProgram();
- glDisable(GL_BLEND);
+ GPU_blend(false);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void ED_region_pixelspace(ARegion *ar)
{
wmOrtho2_region_pixelspace(ar);
- glLoadIdentity();
+ GPU_matrix_identity_set();
}
/* only exported for WM */
-void ED_region_do_listen(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *note)
+void ED_region_do_listen(wmWindow *win, ScrArea *sa, ARegion *ar, wmNotifier *note, const Scene *scene)
{
/* generic notes first */
switch (note->category) {
@@ -130,15 +164,15 @@ void ED_region_do_listen(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *note
}
if (ar->type && ar->type->listener)
- ar->type->listener(sc, sa, ar, note);
+ ar->type->listener(win, sa, ar, note, scene);
}
/* only exported for WM */
-void ED_area_do_listen(bScreen *sc, ScrArea *sa, wmNotifier *note)
+void ED_area_do_listen(wmWindow *win, ScrArea *sa, wmNotifier *note, Scene *scene)
{
/* no generic notes? */
if (sa->type && sa->type->listener) {
- sa->type->listener(sc, sa, note);
+ sa->type->listener(win, sa, note, scene);
}
}
@@ -172,11 +206,29 @@ void ED_area_azones_update(ScrArea *sa, const int mouse_xy[2])
break;
}
}
+ else if (az->type == AZONE_REGION_SCROLL) {
+ /* only if mouse is not hovering the azone */
+ if (BLI_rcti_isect_pt_v(&az->rect, mouse_xy) == false) {
+ View2D *v2d = &az->ar->v2d;
+
+ if (az->direction == AZ_SCROLL_VERT) {
+ az->alpha = v2d->alpha_vert = 0;
+ changed = true;
+ }
+ else if (az->direction == AZ_SCROLL_HOR) {
+ az->alpha = v2d->alpha_hor = 0;
+ changed = true;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ }
}
if (changed) {
sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw_no_rebuild(sa);
}
}
@@ -198,7 +250,7 @@ static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, f
alpha = min_ff(alpha, 0.75f);
- UI_icon_draw_aspect(x, y, ICON_FULLSCREEN_EXIT, 0.7f / UI_DPI_FAC, alpha);
+ UI_icon_draw_aspect(x, y, ICON_FULLSCREEN_EXIT, 0.7f / UI_DPI_FAC, alpha, NULL);
/* debug drawing :
* The click_rect is the same as defined in fullscreen_click_rcti_init
@@ -207,82 +259,35 @@ static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, f
if (G.debug_value == 1) {
rcti click_rect;
float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC;
- char alpha_debug = 255 * alpha;
BLI_rcti_init(&click_rect, x, x + icon_size, y, y + icon_size);
- glColor4ub(255, 0, 0, alpha_debug);
- fdrawbox(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
- glColor4ub(0, 255, 255, alpha_debug);
- fdrawline(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
- fdrawline(click_rect.xmin, click_rect.ymax, click_rect.xmax, click_rect.ymin);
- }
-}
-
-/**
- * \brief Corner widgets use for dragging and splitting the view.
- */
-static void area_draw_azone(short x1, short y1, short x2, short y2)
-{
- int dx = x2 - x1;
- int dy = y2 - y1;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- dx = copysign(ceilf(0.3f * abs(dx)), dx);
- dy = copysign(ceilf(0.3f * abs(dy)), dy);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ immUniformColor4f(1.0f, 0.0f, 0.0f, alpha);
+ imm_draw_box_wire_2d(pos, click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
- glColor4ub(255, 255, 255, 180);
- fdrawline(x1, y2, x2, y1);
- glColor4ub(255, 255, 255, 130);
- fdrawline(x1, y2 - dy, x2 - dx, y1);
- glColor4ub(255, 255, 255, 80);
- fdrawline(x1, y2 - 2 * dy, x2 - 2 * dx, y1);
+ immUniformColor4f(0.0f, 1.0f, 1.0f, alpha);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, click_rect.xmin, click_rect.ymin);
+ immVertex2f(pos, click_rect.xmax, click_rect.ymax);
+ immVertex2f(pos, click_rect.xmin, click_rect.ymax);
+ immVertex2f(pos, click_rect.xmax, click_rect.ymin);
+ immEnd();
- glColor4ub(0, 0, 0, 210);
- fdrawline(x1, y2 + 1, x2 + 1, y1);
- glColor4ub(0, 0, 0, 180);
- fdrawline(x1, y2 - dy + 1, x2 - dx + 1, y1);
- glColor4ub(0, 0, 0, 150);
- fdrawline(x1, y2 - 2 * dy + 1, x2 - 2 * dx + 1, y1);
-
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ immUnbindProgram();
+ }
}
-static void region_draw_azone_icon(AZone *az)
+/**
+ * \brief Corner widgets use for dragging and splitting the view.
+ */
+static void area_draw_azone(short UNUSED(x1), short UNUSED(y1), short UNUSED(x2), short UNUSED(y2))
{
- GLUquadricObj *qobj = NULL;
- short midx = az->x1 + (az->x2 - az->x1) / 2;
- short midy = az->y1 + (az->y2 - az->y1) / 2;
-
- qobj = gluNewQuadric();
-
- glPushMatrix();
- glTranslatef(midx, midy, 0.0);
-
- /* outlined circle */
- glEnable(GL_LINE_SMOOTH);
-
- glColor4f(1.f, 1.f, 1.f, 0.8f);
-
- gluQuadricDrawStyle(qobj, GLU_FILL);
- gluDisk(qobj, 0.0, 4.25f, 16, 1);
-
- glColor4f(0.2f, 0.2f, 0.2f, 0.9f);
-
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
- gluDisk(qobj, 0.0, 4.25f, 16, 1);
-
- glDisable(GL_LINE_SMOOTH);
-
- glPopMatrix();
- gluDeleteQuadric(qobj);
-
- /* + */
- sdrawline(midx, midy - 2, midx, midy + 3);
- sdrawline(midx - 2, midy, midx + 3, midy);
+ /* No drawing needed since all corners are action zone, and visually distinguishable. */
}
static void draw_azone_plus(float x1, float y1, float x2, float y2)
@@ -290,14 +295,24 @@ static void draw_azone_plus(float x1, float y1, float x2, float y2)
float width = 0.1f * U.widget_unit;
float pad = 0.2f * U.widget_unit;
- glRectf((x1 + x2 - width) * 0.5f, y1 + pad, (x1 + x2 + width) * 0.5f, y2 - pad);
- glRectf(x1 + pad, (y1 + y2 - width) * 0.5f, (x1 + x2 - width) * 0.5f, (y1 + y2 + width) * 0.5f);
- glRectf((x1 + x2 + width) * 0.5f, (y1 + y2 - width) * 0.5f, x2 - pad, (y1 + y2 + width) * 0.5f);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPU_blend(true);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(0.8f, 0.8f, 0.8f, 0.4f);
+
+ immRectf(pos, (x1 + x2 - width) * 0.5f, y1 + pad, (x1 + x2 + width) * 0.5f, y2 - pad);
+ immRectf(pos, x1 + pad, (y1 + y2 - width) * 0.5f, (x1 + x2 - width) * 0.5f, (y1 + y2 + width) * 0.5f);
+ immRectf(pos, (x1 + x2 + width) * 0.5f, (y1 + y2 - width) * 0.5f, x2 - pad, (y1 + y2 + width) * 0.5f);
+
+ immUnbindProgram();
+ GPU_blend(false);
}
static void region_draw_azone_tab_plus(AZone *az)
{
- glEnable(GL_BLEND);
+ GPU_blend(true);
/* add code to draw region hidden as 'too small' */
switch (az->edge) {
@@ -315,87 +330,10 @@ static void region_draw_azone_tab_plus(AZone *az)
break;
}
- glColor4f(0.05f, 0.05f, 0.05f, 0.4f);
- UI_draw_roundbox((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
-
- glEnable(GL_BLEND);
+ float color[4] = {0.05f, 0.05f, 0.05f, 0.4f};
+ UI_draw_roundbox_aa(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, color);
- glColor4f(0.8f, 0.8f, 0.8f, 0.4f);
draw_azone_plus((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2);
-
- glDisable(GL_BLEND);
-}
-
-static void region_draw_azone_tab(AZone *az)
-{
- float col[3];
-
- glEnable(GL_BLEND);
- UI_GetThemeColor3fv(TH_HEADER, col);
- glColor4f(col[0], col[1], col[2], 0.5f);
-
- /* add code to draw region hidden as 'too small' */
- switch (az->edge) {
- case AE_TOP_TO_BOTTOMRIGHT:
- UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_RB_ALPHA);
-
- UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
- glColor4ub(0, 0, 0, 255);
- UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f);
- break;
- case AE_BOTTOM_TO_TOPLEFT:
- UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA);
-
- UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
- glColor4ub(0, 0, 0, 255);
- UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f);
- break;
- case AE_LEFT_TO_TOPRIGHT:
- UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA);
-
- UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
- glColor4ub(0, 0, 0, 255);
- UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
- break;
- case AE_RIGHT_TO_TOPLEFT:
- UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT | UI_RB_ALPHA);
-
- UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
- glColor4ub(0, 0, 0, 255);
- UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
- break;
- }
-
- glDisable(GL_BLEND);
-}
-
-static void region_draw_azone_tria(AZone *az)
-{
- glEnable(GL_BLEND);
- //UI_GetThemeColor3fv(TH_HEADER, col);
- glColor4f(0.0f, 0.0f, 0.0f, 0.35f);
-
- /* add code to draw region hidden as 'too small' */
- switch (az->edge) {
- case AE_TOP_TO_BOTTOMRIGHT:
- ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y1, (float)(az->x1 + az->x2) / 2, (float)az->y2);
- break;
-
- case AE_BOTTOM_TO_TOPLEFT:
- ui_draw_anti_tria((float)az->x1, (float)az->y2, (float)az->x2, (float)az->y2, (float)(az->x1 + az->x2) / 2, (float)az->y1);
- break;
-
- case AE_LEFT_TO_TOPRIGHT:
- ui_draw_anti_tria((float)az->x2, (float)az->y1, (float)az->x2, (float)az->y2, (float)az->x1, (float)(az->y1 + az->y2) / 2);
- break;
-
- case AE_RIGHT_TO_TOPLEFT:
- ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x1, (float)az->y2, (float)az->x2, (float)(az->y1 + az->y2) / 2);
- break;
-
- }
-
- glDisable(GL_BLEND);
}
static void area_azone_tag_update(ScrArea *sa)
@@ -410,12 +348,12 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
if (!sa)
return;
- glLineWidth(1.0f);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_line_width(1.0f);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- glPushMatrix();
- glTranslatef(-ar->winrct.xmin, -ar->winrct.ymin, 0.0f);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(-ar->winrct.xmin, -ar->winrct.ymin);
for (az = sa->actionzones.first; az; az = az->next) {
/* test if action zone is over this region */
@@ -427,18 +365,10 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
area_draw_azone(az->x1, az->y1, az->x2, az->y2);
}
else if (az->type == AZONE_REGION) {
-
if (az->ar) {
/* only display tab or icons when the region is hidden */
if (az->ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- if (G.debug_value == 3)
- region_draw_azone_icon(az);
- else if (G.debug_value == 2)
- region_draw_azone_tria(az);
- else if (G.debug_value == 1)
- region_draw_azone_tab(az);
- else
- region_draw_azone_tab_plus(az);
+ region_draw_azone_tab_plus(az);
}
}
}
@@ -449,71 +379,151 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
area_azone_tag_update(sa);
}
}
+ else if (az->type == AZONE_REGION_SCROLL) {
+ if (az->alpha != 0.0f) {
+ area_azone_tag_update(sa);
+ }
+ /* Don't draw this azone. */
+ }
}
}
- glPopMatrix();
+ GPU_matrix_pop();
- glDisable(GL_BLEND);
+ GPU_blend(false);
+}
+
+static void region_draw_status_text(ScrArea *sa, ARegion *ar)
+{
+ bool overlap = ED_region_is_overlap(sa->spacetype, ar->regiontype);
+
+ if (overlap) {
+ GPU_clear_color(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ else {
+ UI_ThemeClearColor(TH_HEADER);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ int fontid = BLF_set_default();
+
+ const float width = BLF_width(fontid, ar->headerstr, BLF_DRAW_STR_DUMMY_MAX);
+ const float x = UI_UNIT_X;
+ const float y = 0.4f * UI_UNIT_Y;
+
+ if (overlap) {
+ const float pad = 2.0f * UI_DPI_FAC;
+ const float x1 = x - (UI_UNIT_X - pad);
+ const float x2 = x + width + (UI_UNIT_X - pad);
+ const float y1 = pad;
+ const float y2 = ar->winy - pad;
+
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ float color[4] = {0.0f, 0.0f, 0.0f, 0.5f};
+ UI_GetThemeColor3fv(TH_BACK, color);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_aa(true, x1, y1, x2, y2, 4.0f, color);
+
+ UI_FontThemeColor(fontid, TH_TEXT);
+ }
+ else {
+ UI_FontThemeColor(fontid, TH_TEXT);
+ }
+
+ BLF_position(fontid, x, y, 0.0f);
+ BLF_draw(fontid, ar->headerstr, BLF_DRAW_STR_DUMMY_MAX);
+}
+
+/* Follow wmMsgNotifyFn spec */
+void ED_region_do_msg_notify_tag_redraw(
+ bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ ARegion *ar = msg_val->owner;
+ ED_region_tag_redraw(ar);
+
+ /* This avoids _many_ situations where header/properties control display settings.
+ * the common case is space properties in the header */
+ if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_UI)) {
+ while (ar && ar->prev) {
+ ar = ar->prev;
+ }
+ for (; ar; ar = ar->next) {
+ if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS)) {
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+}
+/* Follow wmMsgNotifyFn spec */
+void ED_area_do_msg_notify_tag_refresh(
+ bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ ScrArea *sa = msg_val->user_data;
+ ED_area_tag_refresh(sa);
+}
+
+/**
+ * Although there's no general support for minimizing areas, the status-bar can
+ * be snapped to be only a few pixels high. A few pixels rather than 0 so it
+ * can be un-minimized again. We consider it pseudo-minimalized and don't draw
+ * it then.
+ */
+static bool area_is_pseudo_minimized(const ScrArea *area)
+{
+ return (area->winx < 3) || (area->winy < 3);
}
/* only exported for WM */
-/* makes region ready for drawing, sets pixelspace */
-void ED_region_set(const bContext *C, ARegion *ar)
+void ED_region_do_layout(bContext *C, ARegion *ar)
{
- wmWindow *win = CTX_wm_window(C);
+ /* This is optional, only needed for dynamically sized regions. */
ScrArea *sa = CTX_wm_area(C);
+ ARegionType *at = ar->type;
- ar->drawrct = ar->winrct;
+ if (!at->layout) {
+ return;
+ }
- /* note; this sets state, so we can use wmOrtho and friends */
- wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, true);
+ if (at->do_lock || (sa && area_is_pseudo_minimized(sa))) {
+ return;
+ }
- UI_SetTheme(sa ? sa->spacetype : 0, ar->type ? ar->type->regionid : 0);
+ ar->do_draw |= RGN_DRAWING;
- ED_region_pixelspace(ar);
+ UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
+ at->layout(C, ar);
}
-
/* only exported for WM */
void ED_region_do_draw(bContext *C, ARegion *ar)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
ARegionType *at = ar->type;
- bool scissor_pad;
/* see BKE_spacedata_draw_locks() */
if (at->do_lock)
return;
- /* if no partial draw rect set, full rect */
- if (ar->drawrct.xmin == ar->drawrct.xmax) {
- ar->drawrct = ar->winrct;
- scissor_pad = true;
- }
- else {
- /* extra clip for safety */
- BLI_rcti_isect(&ar->winrct, &ar->drawrct, &ar->drawrct);
- scissor_pad = false;
- }
-
ar->do_draw |= RGN_DRAWING;
- /* note; this sets state, so we can use wmOrtho and friends */
- wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, scissor_pad);
+ /* Set viewport, scissor, ortho and ar->drawrct. */
+ wmPartialViewport(&ar->drawrct, &ar->winrct, &ar->drawrct);
wmOrtho2_region_pixelspace(ar);
UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
- /* optional header info instead? */
- if (ar->headerstr) {
- UI_ThemeClearColor(TH_HEADER);
+ if (sa && area_is_pseudo_minimized(sa)) {
+ UI_ThemeClearColor(TH_EDITOR_OUTLINE);
glClear(GL_COLOR_BUFFER_BIT);
-
- UI_ThemeColor(TH_TEXT);
- BLF_draw_default(UI_UNIT_X, 0.4f * UI_UNIT_Y, 0.0f, ar->headerstr, BLF_DRAW_STR_DUMMY_MAX);
+ return;
+ }
+ /* optional header info instead? */
+ else if (ar->headerstr) {
+ region_draw_status_text(sa, ar);
}
else if (at->draw) {
at->draw(C, ar);
@@ -528,11 +538,15 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
/* for debugging unneeded area redraws and partial redraw */
#if 0
- glEnable(GL_BLEND);
- glColor4f(drand48(), drand48(), drand48(), 0.1f);
- glRectf(ar->drawrct.xmin - ar->winrct.xmin, ar->drawrct.ymin - ar->winrct.ymin,
+ GPU_blend(true);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(drand48(), drand48(), drand48(), 0.1f);
+ immRectf(pos, ar->drawrct.xmin - ar->winrct.xmin, ar->drawrct.ymin - ar->winrct.ymin,
ar->drawrct.xmax - ar->winrct.xmin, ar->drawrct.ymax - ar->winrct.ymin);
- glDisable(GL_BLEND);
+ immUnbindProgram();
+ GPU_blend(false);
#endif
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
@@ -540,11 +554,46 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
UI_blocklist_free_inactive(C, &ar->uiblocks);
if (sa) {
- /* disable emboss when the area is full,
- * unless we need to see division between regions (quad-split for eg) */
- if (((win->screen->state == SCREENFULL) && (ar->alignment == RGN_ALIGN_NONE)) == 0) {
- region_draw_emboss(ar, &ar->winrct);
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ /* Only draw region emboss for top-bar and quad-view. */
+ if ((screen->state != SCREENFULL) && ED_area_is_global(sa)) {
+ region_draw_emboss(ar, &ar->winrct, (REGION_EMBOSS_LEFT | REGION_EMBOSS_RIGHT));
+ }
+ else if ((ar->regiontype == RGN_TYPE_WINDOW) && (ar->alignment == RGN_ALIGN_QSPLIT)) {
+ region_draw_emboss(ar, &ar->winrct, REGION_EMBOSS_ALL);
+ }
+ }
+
+ /* We may want to detach message-subscriptions from drawing. */
+ {
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ bScreen *screen = WM_window_get_active_screen(win);
+ Scene *scene = CTX_data_scene(C);
+ struct wmMsgBus *mbus = wm->message_bus;
+ WM_msgbus_clear_by_owner(mbus, ar);
+
+ /* Cheat, always subscribe to this space type properties.
+ *
+ * This covers most cases and avoids copy-paste similar code for each space type.
+ */
+ if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS, RGN_TYPE_UI, RGN_TYPE_TOOLS)) {
+ SpaceLink *sl = sa->spacedata.first;
+
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_Space, sl, &ptr);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+ /* All properties for this space type. */
+ WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_region_tag_redraw, __func__);
}
+
+ ED_region_message_subscribe(C, workspace, scene, screen, sa, ar, mbus);
}
}
@@ -559,7 +608,7 @@ void ED_region_tag_redraw(ARegion *ar)
* but python scripts can cause this to happen indirectly */
if (ar && !(ar->do_draw & RGN_DRAWING)) {
/* zero region means full region redraw */
- ar->do_draw &= ~RGN_DRAW_PARTIAL;
+ ar->do_draw &= ~(RGN_DRAW_PARTIAL | RGN_DRAW_NO_REBUILD);
ar->do_draw |= RGN_DRAW;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
}
@@ -571,6 +620,15 @@ void ED_region_tag_redraw_overlay(ARegion *ar)
ar->do_draw_overlay = RGN_DRAW;
}
+void ED_region_tag_redraw_no_rebuild(ARegion *ar)
+{
+ if (ar && !(ar->do_draw & (RGN_DRAWING | RGN_DRAW))) {
+ ar->do_draw &= ~RGN_DRAW_PARTIAL;
+ ar->do_draw |= RGN_DRAW_NO_REBUILD;
+ memset(&ar->drawrct, 0, sizeof(ar->drawrct));
+ }
+}
+
void ED_region_tag_refresh_ui(ARegion *ar)
{
if (ar) {
@@ -581,7 +639,7 @@ void ED_region_tag_refresh_ui(ARegion *ar)
void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
{
if (ar && !(ar->do_draw & RGN_DRAWING)) {
- if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_PARTIAL))) {
+ if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_NO_REBUILD | RGN_DRAW_PARTIAL))) {
/* no redraw set yet, set partial region */
ar->do_draw |= RGN_DRAW_PARTIAL;
ar->drawrct = *rct;
@@ -592,7 +650,7 @@ void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
BLI_rcti_union(&ar->drawrct, rct);
}
else {
- BLI_assert((ar->do_draw & RGN_DRAW) != 0);
+ BLI_assert((ar->do_draw & (RGN_DRAW | RGN_DRAW_NO_REBUILD)) != 0);
/* Else, full redraw is already requested, nothing to do here. */
}
}
@@ -607,6 +665,15 @@ void ED_area_tag_redraw(ScrArea *sa)
ED_region_tag_redraw(ar);
}
+void ED_area_tag_redraw_no_rebuild(ScrArea *sa)
+{
+ ARegion *ar;
+
+ if (sa)
+ for (ar = sa->regionbase.first; ar; ar = ar->next)
+ ED_region_tag_redraw_no_rebuild(ar);
+}
+
void ED_area_tag_redraw_regiontype(ScrArea *sa, int regiontype)
{
ARegion *ar;
@@ -629,7 +696,7 @@ void ED_area_tag_refresh(ScrArea *sa)
/* *************************************************************** */
/* use NULL to disable it */
-void ED_area_headerprint(ScrArea *sa, const char *str)
+void ED_area_status_text(ScrArea *sa, const char *str)
{
ARegion *ar;
@@ -643,6 +710,7 @@ void ED_area_headerprint(ScrArea *sa, const char *str)
if (ar->headerstr == NULL)
ar->headerstr = MEM_mallocN(UI_MAX_DRAW_STR, "headerprint");
BLI_strncpy(ar->headerstr, str, UI_MAX_DRAW_STR);
+ BLI_str_rstrip(ar->headerstr);
}
else if (ar->headerstr) {
MEM_freeN(ar->headerstr);
@@ -653,10 +721,38 @@ void ED_area_headerprint(ScrArea *sa, const char *str)
}
}
+void ED_workspace_status_text(bContext *C, const char *str)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = CTX_wm_workspace(C);
+
+ /* Can be NULL when running operators in background mode. */
+ if (workspace == NULL)
+ return;
+
+ if (str) {
+ if (workspace->status_text == NULL)
+ workspace->status_text = MEM_mallocN(UI_MAX_DRAW_STR, "headerprint");
+ BLI_strncpy(workspace->status_text, str, UI_MAX_DRAW_STR);
+ }
+ else if (workspace->status_text) {
+ MEM_freeN(workspace->status_text);
+ workspace->status_text = NULL;
+ }
+
+ /* Redraw status bar. */
+ for (ScrArea *sa = win->global_areas.areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_STATUSBAR) {
+ ED_area_tag_redraw(sa);
+ break;
+ }
+ }
+}
+
/* ************************************************************ */
-static void area_azone_initialize(wmWindow *win, bScreen *screen, ScrArea *sa)
+static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea *sa)
{
AZone *az;
@@ -671,39 +767,62 @@ static void area_azone_initialize(wmWindow *win, bScreen *screen, ScrArea *sa)
return;
}
- /* can't click on bottom corners on OS X, already used for resizing */
+ if (ED_area_is_global(sa)) {
+ return;
+ }
+
+ float coords[4][4] = {
+ /* Bottom-left. */
+ {sa->totrct.xmin,
+ sa->totrct.ymin,
+ sa->totrct.xmin + (AZONESPOT - 1),
+ sa->totrct.ymin + (AZONESPOT - 1)},
+ /* Bottom-right. */
+ {sa->totrct.xmax,
+ sa->totrct.ymin,
+ sa->totrct.xmax - (AZONESPOT - 1),
+ sa->totrct.ymin + (AZONESPOT - 1)},
+ /* Top-left. */
+ {sa->totrct.xmin,
+ sa->totrct.ymax,
+ sa->totrct.xmin + (AZONESPOT - 1),
+ sa->totrct.ymax - (AZONESPOT - 1)},
+ /* Top-right. */
+ {sa->totrct.xmax,
+ sa->totrct.ymax,
+ sa->totrct.xmax - (AZONESPOT - 1),
+ sa->totrct.ymax - (AZONESPOT - 1)}};
+
+ for (int i = 0; i < 4; i++) {
+ /* can't click on bottom corners on OS X, already used for resizing */
#ifdef __APPLE__
- if (!(sa->totrct.xmin == 0 && sa->totrct.ymin == 0) || WM_window_is_fullscreen(win))
+ if (!WM_window_is_fullscreen(win) &&
+ ((coords[i][0] == 0 && coords[i][1] == 0) ||
+ (coords[i][0] == WM_window_pixels_x(win) && coords[i][1] == 0)))
+ {
+ continue;
+ }
#else
- (void)win;
+ (void)win;
#endif
- {
+
/* set area action zones */
az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
BLI_addtail(&(sa->actionzones), az);
az->type = AZONE_AREA;
- az->x1 = sa->totrct.xmin;
- az->y1 = sa->totrct.ymin;
- az->x2 = sa->totrct.xmin + (AZONESPOT - 1);
- az->y2 = sa->totrct.ymin + (AZONESPOT - 1);
+ az->x1 = coords[i][0];
+ az->y1 = coords[i][1];
+ az->x2 = coords[i][2];
+ az->y2 = coords[i][3];
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-
- az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
- az->type = AZONE_AREA;
- az->x1 = sa->totrct.xmax;
- az->y1 = sa->totrct.ymax;
- az->x2 = sa->totrct.xmax - (AZONESPOT - 1);
- az->y2 = sa->totrct.ymax - (AZONESPOT - 1);
- BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
static void fullscreen_azone_initialize(ScrArea *sa, ARegion *ar)
{
AZone *az;
- if (ar->regiontype != RGN_TYPE_WINDOW)
+ if (ED_area_is_global(sa) || (ar->regiontype != RGN_TYPE_WINDOW))
return;
az = (AZone *)MEM_callocN(sizeof(AZone), "fullscreen action zone");
@@ -753,73 +872,17 @@ static void region_azone_edge(AZone *az, ARegion *ar)
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-static void region_azone_icon(ScrArea *sa, AZone *az, ARegion *ar)
-{
- AZone *azt;
- int tot = 0;
-
- /* count how many actionzones with along same edge are available.
- * This allows for adding more action zones in the future without
- * having to worry about correct offset */
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
- if (azt->edge == az->edge) tot++;
- }
-
- switch (az->edge) {
- case AE_TOP_TO_BOTTOMRIGHT:
- az->x1 = ar->winrct.xmax - tot * 2 * AZONEPAD_ICON;
- az->y1 = ar->winrct.ymax + AZONEPAD_ICON;
- az->x2 = ar->winrct.xmax - tot * AZONEPAD_ICON;
- az->y2 = ar->winrct.ymax + 2 * AZONEPAD_ICON;
- break;
- case AE_BOTTOM_TO_TOPLEFT:
- az->x1 = ar->winrct.xmin + AZONEPAD_ICON;
- az->y1 = ar->winrct.ymin - 2 * AZONEPAD_ICON;
- az->x2 = ar->winrct.xmin + 2 * AZONEPAD_ICON;
- az->y2 = ar->winrct.ymin - AZONEPAD_ICON;
- break;
- case AE_LEFT_TO_TOPRIGHT:
- az->x1 = ar->winrct.xmin - 2 * AZONEPAD_ICON;
- az->y1 = ar->winrct.ymax - tot * 2 * AZONEPAD_ICON;
- az->x2 = ar->winrct.xmin - AZONEPAD_ICON;
- az->y2 = ar->winrct.ymax - tot * AZONEPAD_ICON;
- break;
- case AE_RIGHT_TO_TOPLEFT:
- az->x1 = ar->winrct.xmax + AZONEPAD_ICON;
- az->y1 = ar->winrct.ymax - tot * 2 * AZONEPAD_ICON;
- az->x2 = ar->winrct.xmax + 2 * AZONEPAD_ICON;
- az->y2 = ar->winrct.ymax - tot * AZONEPAD_ICON;
- break;
- }
-
- BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
-
- /* if more azones on 1 spot, set offset */
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
- if (az != azt) {
- if (ABS(az->x1 - azt->x1) < 2 && ABS(az->y1 - azt->y1) < 2) {
- if (az->edge == AE_TOP_TO_BOTTOMRIGHT || az->edge == AE_BOTTOM_TO_TOPLEFT) {
- az->x1 += AZONESPOT;
- az->x2 += AZONESPOT;
- }
- else {
- az->y1 -= AZONESPOT;
- az->y2 -= AZONESPOT;
- }
- BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
- }
- }
- }
-}
-
-#define AZONEPAD_TAB_PLUSW (0.7f * U.widget_unit)
-#define AZONEPAD_TAB_PLUSH (0.7f * U.widget_unit)
-
/* region already made zero sized, in shape of edge */
static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *ar)
{
AZone *azt;
int tot = 0, add;
+ /* Edge offset multiplied by the */
+
+ float edge_offset = 1.0f;
+ const float tab_size_x = 0.7f * U.widget_unit;
+ const float tab_size_y = 0.7f * U.widget_unit;
+
for (azt = sa->actionzones.first; azt; azt = azt->next) {
if (azt->edge == az->edge) tot++;
@@ -828,171 +891,127 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *ar)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
- az->x1 = ar->winrct.xmax - 2.5f * AZONEPAD_TAB_PLUSW;
+ az->x1 = ar->winrct.xmax - ((edge_offset + 1.0f) * tab_size_x);
az->y1 = ar->winrct.ymax - add;
- az->x2 = ar->winrct.xmax - 1.5f * AZONEPAD_TAB_PLUSW;
- az->y2 = ar->winrct.ymax - add + AZONEPAD_TAB_PLUSH;
+ az->x2 = ar->winrct.xmax - (edge_offset * tab_size_x);
+ az->y2 = ar->winrct.ymax - add + tab_size_y;
break;
case AE_BOTTOM_TO_TOPLEFT:
- az->x1 = ar->winrct.xmax - 2.5f * AZONEPAD_TAB_PLUSW;
- az->y1 = ar->winrct.ymin - AZONEPAD_TAB_PLUSH;
- az->x2 = ar->winrct.xmax - 1.5f * AZONEPAD_TAB_PLUSW;
+ az->x1 = ar->winrct.xmax - ((edge_offset + 1.0f) * tab_size_x);
+ az->y1 = ar->winrct.ymin - tab_size_y;
+ az->x2 = ar->winrct.xmax - (edge_offset * tab_size_x);
az->y2 = ar->winrct.ymin;
break;
case AE_LEFT_TO_TOPRIGHT:
- az->x1 = ar->winrct.xmin - AZONEPAD_TAB_PLUSH;
- az->y1 = ar->winrct.ymax - 2.5f * AZONEPAD_TAB_PLUSW;
+ az->x1 = ar->winrct.xmin - tab_size_y;
+ az->y1 = ar->winrct.ymax - ((edge_offset + 1.0f) * tab_size_x);
az->x2 = ar->winrct.xmin;
- az->y2 = ar->winrct.ymax - 1.5f * AZONEPAD_TAB_PLUSW;
+ az->y2 = ar->winrct.ymax - (edge_offset * tab_size_x);
break;
case AE_RIGHT_TO_TOPLEFT:
az->x1 = ar->winrct.xmax - 1;
- az->y1 = ar->winrct.ymax - 2.5f * AZONEPAD_TAB_PLUSW;
- az->x2 = ar->winrct.xmax - 1 + AZONEPAD_TAB_PLUSH;
- az->y2 = ar->winrct.ymax - 1.5f * AZONEPAD_TAB_PLUSW;
+ az->y1 = ar->winrct.ymax - ((edge_offset + 1.0f) * tab_size_x);
+ az->x2 = ar->winrct.xmax - 1 + tab_size_y;
+ az->y2 = ar->winrct.ymax - (edge_offset * tab_size_x);
break;
}
/* rect needed for mouse pointer test */
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-
-#define AZONEPAD_TABW (0.9f * U.widget_unit)
-#define AZONEPAD_TABH (0.35f * U.widget_unit)
-
-/* region already made zero sized, in shape of edge */
-static void region_azone_tab(ScrArea *sa, AZone *az, ARegion *ar)
+static void region_azone_edge_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const bool is_fullscreen)
{
- AZone *azt;
- int tot = 0, add;
+ AZone *az = NULL;
+ const bool is_hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL));
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
- if (azt->edge == az->edge) tot++;
+ if (is_hidden && is_fullscreen) {
+ return;
}
- switch (az->edge) {
- case AE_TOP_TO_BOTTOMRIGHT:
- add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
- az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TABW;
- az->y1 = ar->winrct.ymax - add;
- az->x2 = ar->winrct.xmax - AZONEPAD_TABW;
- az->y2 = ar->winrct.ymax - add + AZONEPAD_TABH;
- break;
- case AE_BOTTOM_TO_TOPLEFT:
- az->x1 = ar->winrct.xmin + AZONEPAD_TABW;
- az->y1 = ar->winrct.ymin - AZONEPAD_TABH;
- az->x2 = ar->winrct.xmin + 2 * AZONEPAD_TABW;
- az->y2 = ar->winrct.ymin;
- break;
- case AE_LEFT_TO_TOPRIGHT:
- az->x1 = ar->winrct.xmin + 1 - AZONEPAD_TABH;
- az->y1 = ar->winrct.ymax - 2 * AZONEPAD_TABW;
- az->x2 = ar->winrct.xmin + 1;
- az->y2 = ar->winrct.ymax - AZONEPAD_TABW;
- break;
- case AE_RIGHT_TO_TOPLEFT:
- az->x1 = ar->winrct.xmax - 1;
- az->y1 = ar->winrct.ymax - 2 * AZONEPAD_TABW;
- az->x2 = ar->winrct.xmax - 1 + AZONEPAD_TABH;
- az->y2 = ar->winrct.ymax - AZONEPAD_TABW;
- break;
+ az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
+ BLI_addtail(&(sa->actionzones), az);
+ az->type = AZONE_REGION;
+ az->ar = ar;
+ az->edge = edge;
+
+ if (is_hidden) {
+ region_azone_tab_plus(sa, az, ar);
+ }
+ else if (!is_hidden && (ar->regiontype != RGN_TYPE_HEADER)) {
+ region_azone_edge(az, ar);
}
- /* rect needed for mouse pointer test */
- BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-#define AZONEPAD_TRIAW (0.8f * U.widget_unit)
-#define AZONEPAD_TRIAH (0.45f * U.widget_unit)
-
-
-/* region already made zero sized, in shape of edge */
-static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
+static void region_azone_scrollbar_initialize(ScrArea *sa, ARegion *ar, AZScrollDirection direction)
{
- AZone *azt;
- int tot = 0, add;
+ rcti scroller_vert = (direction == AZ_SCROLL_VERT) ? ar->v2d.vert : ar->v2d.hor;
+ AZone *az = MEM_callocN(sizeof(*az), __func__);
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
- if (azt->edge == az->edge) tot++;
- }
+ BLI_addtail(&sa->actionzones, az);
+ az->type = AZONE_REGION_SCROLL;
+ az->ar = ar;
+ az->direction = direction;
- switch (az->edge) {
- case AE_TOP_TO_BOTTOMRIGHT:
- add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
- az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TRIAW;
- az->y1 = ar->winrct.ymax - add;
- az->x2 = ar->winrct.xmax - AZONEPAD_TRIAW;
- az->y2 = ar->winrct.ymax - add + AZONEPAD_TRIAH;
- break;
- case AE_BOTTOM_TO_TOPLEFT:
- az->x1 = ar->winrct.xmin + AZONEPAD_TRIAW;
- az->y1 = ar->winrct.ymin - AZONEPAD_TRIAH;
- az->x2 = ar->winrct.xmin + 2 * AZONEPAD_TRIAW;
- az->y2 = ar->winrct.ymin;
- break;
- case AE_LEFT_TO_TOPRIGHT:
- az->x1 = ar->winrct.xmin + 1 - AZONEPAD_TRIAH;
- az->y1 = ar->winrct.ymax - 2 * AZONEPAD_TRIAW;
- az->x2 = ar->winrct.xmin + 1;
- az->y2 = ar->winrct.ymax - AZONEPAD_TRIAW;
- break;
- case AE_RIGHT_TO_TOPLEFT:
- az->x1 = ar->winrct.xmax - 1;
- az->y1 = ar->winrct.ymax - 2 * AZONEPAD_TRIAW;
- az->x2 = ar->winrct.xmax - 1 + AZONEPAD_TRIAH;
- az->y2 = ar->winrct.ymax - AZONEPAD_TRIAW;
- break;
+ if (direction == AZ_SCROLL_VERT) {
+ az->ar->v2d.alpha_vert = 0;
}
- /* rect needed for mouse pointer test */
+ else if (direction == AZ_SCROLL_HOR) {
+ az->ar->v2d.alpha_hor = 0;
+ }
+
+ BLI_rcti_translate(&scroller_vert, ar->winrct.xmin, ar->winrct.ymin);
+ az->x1 = scroller_vert.xmin - AZONEFADEIN;
+ az->y1 = scroller_vert.ymin - AZONEFADEIN;
+ az->x2 = scroller_vert.xmax + AZONEFADEIN;
+ az->y2 = scroller_vert.ymax + AZONEFADEIN;
+
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-
-static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const bool is_fullscreen)
+static void region_azones_scrollbars_initialize(ScrArea *sa, ARegion *ar)
{
- AZone *az = NULL;
- const bool is_hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) == 0;
+ const View2D *v2d = &ar->v2d;
- if (is_hidden || !is_fullscreen) {
- az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
- az->type = AZONE_REGION;
- az->ar = ar;
- az->edge = edge;
+ if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) == 0)) {
+ region_azone_scrollbar_initialize(sa, ar, AZ_SCROLL_VERT);
}
-
- if (!is_hidden) {
- if (!is_fullscreen) {
- if (G.debug_value == 3)
- region_azone_icon(sa, az, ar);
- else if (G.debug_value == 2)
- region_azone_tria(sa, az, ar);
- else if (G.debug_value == 1)
- region_azone_tab(sa, az, ar);
- else
- region_azone_tab_plus(sa, az, ar);
- }
- }
- else {
- region_azone_edge(az, ar);
+ if ((v2d->scroll & V2D_SCROLL_HORIZONTAL) && ((v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) == 0)) {
+ region_azone_scrollbar_initialize(sa, ar, AZ_SCROLL_HOR);
}
-
}
/* *************************************************************** */
-static void region_azone_add(ScrArea *sa, ARegion *ar, const int alignment, const bool is_fullscreen)
+static void region_azones_add(const bScreen *screen, ScrArea *sa, ARegion *ar, const int alignment)
{
+ const bool is_fullscreen = screen->state == SCREENFULL;
+
/* edge code (t b l r) is along which area edge azone will be drawn */
- if (alignment == RGN_ALIGN_TOP)
- region_azone_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
+ if (ar->regiontype == RGN_TYPE_HEADER && ar->winy + 6 > sa->winy) {
+ /* The logic for this is: when the header takes up the full area,
+ * disallow hiding it to view the main window.
+ *
+ * Without this, you can drag down the file selectors header and hide it
+ * by accident very easily (highly annoying!), the value 6 is arbitrary
+ * but accounts for small common rounding problems when scaling the UI,
+ * must be minimum '4' */
+ }
+ else if (alignment == RGN_ALIGN_TOP)
+ region_azone_edge_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
else if (alignment == RGN_ALIGN_BOTTOM)
- region_azone_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
+ region_azone_edge_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
else if (alignment == RGN_ALIGN_RIGHT)
- region_azone_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
+ region_azone_edge_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
else if (alignment == RGN_ALIGN_LEFT)
- region_azone_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
+ region_azone_edge_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
+
+ if (is_fullscreen) {
+ fullscreen_azone_initialize(sa, ar);
+ }
+
+ region_azones_scrollbars_initialize(sa, ar);
}
/* dir is direction to check, not the splitting edge direction! */
@@ -1018,7 +1037,14 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
/* find overlapping previous region on same place */
for (ar1 = ar->prev; ar1; ar1 = ar1->prev) {
+ if (ar1->flag & (RGN_FLAG_HIDDEN)) {
+ continue;
+ }
+
if (ar1->overlap && ((ar1->alignment & RGN_SPLIT_PREV) == 0)) {
+ if (ELEM(ar1->alignment, RGN_ALIGN_FLOAT)) {
+ continue;
+ }
align1 = ar1->alignment;
if (BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) {
if (align1 != align) {
@@ -1057,6 +1083,13 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
/* At this point, 'ar' is in its final position and still open.
* Make a final check it does not overlap any previous 'other side' region. */
for (ar1 = ar->prev; ar1; ar1 = ar1->prev) {
+ if (ar1->flag & (RGN_FLAG_HIDDEN)) {
+ continue;
+ }
+ if (ELEM(ar1->alignment, RGN_ALIGN_FLOAT)) {
+ continue;
+ }
+
if (ar1->overlap && (ar1->alignment & RGN_SPLIT_PREV) == 0) {
if ((ar1->alignment != align) && BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) {
/* Left overlapping right or vice-versa, forbid this! */
@@ -1068,33 +1101,43 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
}
/* overlapping regions only in the following restricted cases */
-static bool region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar)
+bool ED_region_is_overlap(int spacetype, int regiontype)
{
+ if (regiontype == RGN_TYPE_HUD) {
+ return true;
+ }
if (U.uiflag2 & USER_REGION_OVERLAP) {
- if (WM_is_draw_triple(win)) {
- if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) {
- if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
- return 1;
+ if (spacetype == SPACE_NODE) {
+ if (regiontype == RGN_TYPE_TOOLS) {
+ return true;
+ }
+ }
+ else if (ELEM(spacetype, SPACE_VIEW3D, SPACE_SEQ, SPACE_IMAGE)) {
+ if (ELEM(regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) {
+ return true;
}
- else if (sa->spacetype == SPACE_IMAGE) {
- if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW))
- return 1;
+
+ if (ELEM(spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
+ if (regiontype == RGN_TYPE_HEADER) {
+ return true;
+ }
}
}
}
- return 0;
+ return false;
}
-static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti *remainder, int quad)
+static void region_rect_recursive(ScrArea *sa, ARegion *ar, rcti *remainder, rcti *overlap_remainder, int quad)
{
rcti *remainder_prev = remainder;
- int prefsizex, prefsizey;
- int alignment;
if (ar == NULL)
return;
+ int prev_winx = ar->winx;
+ int prev_winy = ar->winy;
+
/* no returns in function, winrct gets set in the end again */
BLI_rcti_init(&ar->winrct, 0, 0, 0, 0);
@@ -1103,23 +1146,32 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
if (ar->prev)
remainder = &ar->prev->winrct;
- alignment = ar->alignment & ~RGN_SPLIT_PREV;
+ int alignment = ar->alignment & ~RGN_SPLIT_PREV;
/* set here, assuming userpref switching forces to call this again */
- ar->overlap = region_is_overlap(win, sa, ar);
+ ar->overlap = ED_region_is_overlap(sa->spacetype, ar->regiontype);
/* clear state flags first */
ar->flag &= ~RGN_FLAG_TOO_SMALL;
/* user errors */
- if (ar->next == NULL && alignment != RGN_ALIGN_QSPLIT)
+ if ((ar->next == NULL) && !ELEM(alignment, RGN_ALIGN_QSPLIT, RGN_ALIGN_FLOAT)) {
alignment = RGN_ALIGN_NONE;
+ }
- /* prefsize, for header we stick to exception (prevent dpi rounding error) */
- prefsizex = UI_DPI_FAC * (ar->sizex > 1 ? ar->sizex + 0.5f : ar->type->prefsizex);
+ /* prefsize, taking into account DPI */
+ int prefsizex = UI_DPI_FAC * ((ar->sizex > 1) ? ar->sizex + 0.5f : ar->type->prefsizex);
+ int prefsizey;
- if (ar->regiontype == RGN_TYPE_HEADER) {
+ if (ar->flag & RGN_FLAG_PREFSIZE_OR_HIDDEN) {
+ prefsizex = UI_DPI_FAC * ar->type->prefsizex;
+ prefsizey = UI_DPI_FAC * ar->type->prefsizey;
+ }
+ else if (ar->regiontype == RGN_TYPE_HEADER) {
prefsizey = ED_area_headersize();
}
+ else if (ED_area_is_global(sa)) {
+ prefsizey = ED_region_global_size_y();
+ }
else if (ar->regiontype == RGN_TYPE_UI && sa->spacetype == SPACE_FILE) {
prefsizey = UI_UNIT_Y * 2 + (UI_UNIT_Y / 2);
}
@@ -1132,7 +1184,38 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
/* hidden is user flag */
}
else if (alignment == RGN_ALIGN_FLOAT) {
- /* XXX floating area region, not handled yet here */
+ /**
+ * \note Currently this window type is only used for #RGN_TYPE_HUD,
+ * We expect the panel to resize it's self to be larger.
+ *
+ * This aligns to the lower left of the area.
+ */
+ const int size_min[2] = {UI_UNIT_X, UI_UNIT_Y};
+ rcti overlap_remainder_margin = *overlap_remainder;
+ BLI_rcti_resize(
+ &overlap_remainder_margin,
+ max_ii(0, BLI_rcti_size_x(overlap_remainder) - UI_UNIT_X / 2),
+ max_ii(0, BLI_rcti_size_y(overlap_remainder) - UI_UNIT_Y / 2));
+ ar->winrct.xmin = overlap_remainder_margin.xmin;
+ ar->winrct.ymin = overlap_remainder_margin.ymin;
+ ar->winrct.xmax = ar->winrct.xmin + ar->sizex - 1;
+ ar->winrct.ymax = ar->winrct.ymin + ar->sizey - 1;
+
+ BLI_rcti_isect(&ar->winrct, &overlap_remainder_margin, &ar->winrct);
+
+ /* We need to use a test that wont have been previously clamped. */
+ rcti winrct_test = {
+ .xmin = ar->winrct.xmin,
+ .ymin = ar->winrct.ymin,
+ .xmax = ar->winrct.xmin + size_min[0],
+ .ymax = ar->winrct.ymin + size_min[1],
+ };
+ BLI_rcti_isect(&winrct_test, &overlap_remainder_margin, &winrct_test);
+ if (BLI_rcti_size_x(&winrct_test) < size_min[0] ||
+ BLI_rcti_size_y(&winrct_test) < size_min[1])
+ {
+ ar->flag |= RGN_FLAG_TOO_SMALL;
+ }
}
else if (rct_fits(remainder, 'v', 1) < 0 || rct_fits(remainder, 'h', 1) < 0) {
/* remainder is too small for any usage */
@@ -1144,50 +1227,50 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
BLI_rcti_init(remainder, 0, 0, 0, 0);
}
else if (alignment == RGN_ALIGN_TOP || alignment == RGN_ALIGN_BOTTOM) {
+ rcti *winrct = (ar->overlap) ? overlap_remainder : remainder;
- if (rct_fits(remainder, 'v', prefsizey) < 0) {
+ if (rct_fits(winrct, 'v', prefsizey) < 0) {
ar->flag |= RGN_FLAG_TOO_SMALL;
}
else {
- int fac = rct_fits(remainder, 'v', prefsizey);
+ int fac = rct_fits(winrct, 'v', prefsizey);
if (fac < 0)
prefsizey += fac;
- ar->winrct = *remainder;
+ ar->winrct = *winrct;
if (alignment == RGN_ALIGN_TOP) {
ar->winrct.ymin = ar->winrct.ymax - prefsizey + 1;
- remainder->ymax = ar->winrct.ymin - 1;
+ winrct->ymax = ar->winrct.ymin - 1;
}
else {
ar->winrct.ymax = ar->winrct.ymin + prefsizey - 1;
- remainder->ymin = ar->winrct.ymax + 1;
+ winrct->ymin = ar->winrct.ymax + 1;
}
}
}
else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ rcti *winrct = (ar->overlap) ? overlap_remainder : remainder;
- if (rct_fits(remainder, 'h', prefsizex) < 0) {
+ if (rct_fits(winrct, 'h', prefsizex) < 0) {
ar->flag |= RGN_FLAG_TOO_SMALL;
}
else {
- int fac = rct_fits(remainder, 'h', prefsizex);
+ int fac = rct_fits(winrct, 'h', prefsizex);
if (fac < 0)
prefsizex += fac;
- ar->winrct = *remainder;
+ ar->winrct = *winrct;
if (alignment == RGN_ALIGN_RIGHT) {
ar->winrct.xmin = ar->winrct.xmax - prefsizex + 1;
- if (ar->overlap == 0)
- remainder->xmax = ar->winrct.xmin - 1;
+ winrct->xmax = ar->winrct.xmin - 1;
}
else {
ar->winrct.xmax = ar->winrct.xmin + prefsizex - 1;
- if (ar->overlap == 0)
- remainder->xmin = ar->winrct.xmax + 1;
+ winrct->xmin = ar->winrct.xmax + 1;
}
}
}
@@ -1271,12 +1354,13 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
if (ar->winy > 1) ar->sizey = (ar->winy + 0.5f) / UI_DPI_FAC;
/* exception for multiple overlapping regions on same spot */
- if (ar->overlap)
+ if (ar->overlap & (alignment != RGN_ALIGN_FLOAT)) {
region_overlap_fix(sa, ar);
+ }
/* set winrect for azones */
if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- ar->winrct = *remainder;
+ ar->winrct = (ar->overlap) ? *overlap_remainder : *remainder;
switch (alignment) {
case RGN_ALIGN_TOP:
@@ -1305,42 +1389,51 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
}
}
- /* in end, add azones, where appropriate */
- if (ar->regiontype == RGN_TYPE_HEADER && ar->winy + 6 > sa->winy) {
- /* The logic for this is: when the header takes up the full area,
- * disallow hiding it to view the main window.
- *
- * Without this, you can drag down the file selectors header and hide it
- * by accident very easily (highly annoying!), the value 6 is arbitrary
- * but accounts for small common rounding problems when scaling the UI,
- * must be minimum '4' */
- }
- else {
- if (ELEM(win->screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
- region_azone_add(sa, ar, alignment, false);
- }
- else {
- region_azone_add(sa, ar, alignment, true);
- fullscreen_azone_initialize(sa, ar);
- }
+ /* After non-overlapping region, all following overlapping regions
+ * fit within the remaining space again. */
+ if (!ar->overlap) {
+ *overlap_remainder = *remainder;
}
- region_rect_recursive(win, sa, ar->next, remainder, quad);
+ region_rect_recursive(sa, ar->next, remainder, overlap_remainder, quad);
+
+ /* Tag for redraw if size changes. */
+ if (ar->winx != prev_winx || ar->winy != prev_winy) {
+ ED_region_tag_redraw(ar);
+ }
}
-static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
+static void area_calc_totrct(ScrArea *sa, const rcti *window_rect)
{
- short rt = (short) U.pixelsize;
+ short px = (short)U.pixelsize;
- if (sa->v1->vec.x > 0) sa->totrct.xmin = sa->v1->vec.x + rt;
- else sa->totrct.xmin = sa->v1->vec.x;
- if (sa->v4->vec.x < sizex - 1) sa->totrct.xmax = sa->v4->vec.x - rt;
- else sa->totrct.xmax = sa->v4->vec.x;
+ sa->totrct.xmin = sa->v1->vec.x;
+ sa->totrct.xmax = sa->v4->vec.x;
+ sa->totrct.ymin = sa->v1->vec.y;
+ sa->totrct.ymax = sa->v2->vec.y;
- if (sa->v1->vec.y > 0) sa->totrct.ymin = sa->v1->vec.y + rt;
- else sa->totrct.ymin = sa->v1->vec.y;
- if (sa->v2->vec.y < sizey - 1) sa->totrct.ymax = sa->v2->vec.y - rt;
- else sa->totrct.ymax = sa->v2->vec.y;
+ /* scale down totrct by 1 pixel on all sides not matching window borders */
+ if (sa->totrct.xmin > window_rect->xmin) {
+ sa->totrct.xmin += px;
+ }
+ if (sa->totrct.xmax < (window_rect->xmax - 1)) {
+ sa->totrct.xmax -= px;
+ }
+ if (sa->totrct.ymin > window_rect->ymin) {
+ sa->totrct.ymin += px;
+ }
+ if (sa->totrct.ymax < (window_rect->ymax - 1)) {
+ sa->totrct.ymax -= px;
+ }
+ /* Although the following asserts are correct they lead to a very unstable Blender.
+ * And the asserts would fail even in 2.7x (they were added in 2.8x as part of the top-bar commit).
+ * For more details see T54864. */
+#if 0
+ BLI_assert(sa->totrct.xmin >= 0);
+ BLI_assert(sa->totrct.xmax >= 0);
+ BLI_assert(sa->totrct.ymin >= 0);
+ BLI_assert(sa->totrct.ymax >= 0);
+#endif
/* for speedup */
sa->winx = BLI_rcti_size_x(&sa->totrct) + 1;
@@ -1349,28 +1442,23 @@ static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
/* used for area initialize below */
-static void region_subwindow(wmWindow *win, ARegion *ar, bool activate)
+static void region_subwindow(ARegion *ar)
{
bool hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) != 0;
if ((ar->alignment & RGN_SPLIT_PREV) && ar->prev)
hidden = hidden || (ar->prev->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL));
- if (hidden) {
- if (ar->swinid)
- wm_subwindow_close(win, ar->swinid);
- ar->swinid = 0;
- }
- else if (ar->swinid == 0) {
- ar->swinid = wm_subwindow_open(win, &ar->winrct, activate);
- }
- else {
- wm_subwindow_position(win, ar->swinid, &ar->winrct, activate);
- }
+ ar->visible = !hidden;
}
-static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *handlers, int flag)
+/**
+ * \param ar: Region, may be NULL when adding handlers for \a sa.
+ */
+static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ARegion *ar, ListBase *handlers, int flag)
{
+ BLI_assert(ar ? (&ar->handlers == handlers) : (&sa->handlers == handlers));
+
/* note, add-handler checks if it already exists */
/* XXX it would be good to have boundbox checks for some of these... */
@@ -1381,6 +1469,18 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
/* user interface widgets */
UI_region_handlers_add(handlers);
}
+ if (flag & ED_KEYMAP_GIZMO) {
+ BLI_assert(ar && ar->type->regionid == RGN_TYPE_WINDOW);
+ if (ar) {
+ /* Anything else is confusing, only allow this. */
+ BLI_assert(&ar->handlers == handlers);
+ if (ar->gizmo_map == NULL) {
+ ar->gizmo_map = WM_gizmomap_new_from_type(
+ &(const struct wmGizmoMapType_Params){sa->spacetype, ar->type->regionid});
+ }
+ WM_gizmomap_add_handlers(ar, ar->gizmo_map);
+ }
+ }
if (flag & ED_KEYMAP_VIEW2D) {
/* 2d-viewport handling+manipulation */
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D", 0, 0);
@@ -1390,19 +1490,12 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
/* time-markers */
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Markers", 0, 0);
- /* time space only has this keymap, the others get a boundbox restricted map */
- if (sa->spacetype != SPACE_TIME) {
- ARegion *ar;
- /* same local check for all areas */
- static rcti rect = {0, 10000, 0, -1};
- rect.ymax = UI_MARKER_MARGIN_Y;
- ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar) {
- WM_event_add_keymap_handler_bb(handlers, keymap, &rect, &ar->winrct);
- }
- }
- else
- WM_event_add_keymap_handler(handlers, keymap);
+ /* use a boundbox restricted map */
+ /* same local check for all areas */
+ static rcti rect = {0, 10000, 0, -1};
+ rect.ymax = UI_MARKER_MARGIN_Y;
+ BLI_assert(ar->type->regionid == RGN_TYPE_WINDOW);
+ WM_event_add_keymap_handler_bb(handlers, keymap, &rect, &ar->winrct);
}
if (flag & ED_KEYMAP_ANIMATION) {
/* frame changing and timeline operators (for time spaces) */
@@ -1414,40 +1507,93 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Frames", 0, 0);
WM_event_add_keymap_handler(handlers, keymap);
}
+ if (flag & ED_KEYMAP_HEADER) {
+ /* standard keymap for headers regions */
+ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Header", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap);
+ }
+
+ /* Keep last because of LMB/RMB handling, see: T57527. */
if (flag & ED_KEYMAP_GPENCIL) {
/* grease pencil */
- /* NOTE: This is now 2 keymaps - One for basic functionality,
- * and one that only applies when "Edit Mode" is enabled
- * for strokes.
+ /* NOTE: This is now 4 keymaps - One for basic functionality,
+ * and others for special stroke modes (edit, paint and sculpt).
*
- * For now, it's easier to just include both,
- * since you hardly want one without the other.
+ * For now, it's easier to just include all,
+ * since you hardly want one without the others.
*/
wmKeyMap *keymap_general = WM_keymap_ensure(wm->defaultconf, "Grease Pencil", 0, 0);
- wmKeyMap *keymap_edit = WM_keymap_ensure(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0);
-
WM_event_add_keymap_handler(handlers, keymap_general);
+
+ wmKeyMap *keymap_edit = WM_keymap_ensure(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0);
WM_event_add_keymap_handler(handlers, keymap_edit);
- }
- if (flag & ED_KEYMAP_HEADER) {
- /* standard keymap for headers regions */
- wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Header", 0, 0);
- WM_event_add_keymap_handler(handlers, keymap);
+
+ wmKeyMap *keymap_paint = WM_keymap_ensure(wm->defaultconf, "Grease Pencil Stroke Paint Mode", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint);
+
+ wmKeyMap *keymap_paint_draw = WM_keymap_ensure(wm->defaultconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint_draw);
+
+ wmKeyMap *keymap_paint_erase = WM_keymap_ensure(wm->defaultconf, "Grease Pencil Stroke Paint (Erase)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint_erase);
+
+ wmKeyMap *keymap_paint_fill = WM_keymap_ensure(wm->defaultconf, "Grease Pencil Stroke Paint (Fill)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint_fill);
+
+ wmKeyMap *keymap_sculpt = WM_keymap_ensure(wm->defaultconf, "Grease Pencil Stroke Sculpt Mode", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt);
}
}
+void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area)
+{
+ rcti rect, overlap_rect;
+ rcti window_rect;
+
+ if (!(area->flag & AREA_FLAG_REGION_SIZE_UPDATE)) {
+ return;
+ }
+
+ WM_window_rect_calc(win, &window_rect);
+ area_calc_totrct(area, &window_rect);
+
+ /* region rect sizes */
+ rect = area->totrct;
+ overlap_rect = rect;
+ region_rect_recursive(area, area->regionbase.first, &rect, &overlap_rect, 0);
+
+ for (ARegion *ar = area->regionbase.first; ar; ar = ar->next) {
+ region_subwindow(ar);
+
+ /* region size may have changed, init does necessary adjustments */
+ if (ar->type->init) {
+ ar->type->init(wm, ar);
+ }
+ }
+
+ area->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
+}
/* called in screen_refresh, or screens_init, also area size changes */
void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
{
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
ARegion *ar;
- rcti rect;
+ rcti rect, overlap_rect;
+ rcti window_rect;
+
+ if (ED_area_is_global(sa) && (sa->global->flag & GLOBAL_AREA_IS_HIDDEN)) {
+ return;
+ }
+ WM_window_rect_calc(win, &window_rect);
/* set typedefinitions */
sa->type = BKE_spacetype_from_id(sa->spacetype);
if (sa->type == NULL) {
- sa->butspacetype = sa->spacetype = SPACE_VIEW3D;
+ sa->spacetype = SPACE_VIEW3D;
sa->type = BKE_spacetype_from_id(sa->spacetype);
}
@@ -1455,36 +1601,55 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
ar->type = BKE_regiontype_from_id_or_first(sa->type, ar->regiontype);
/* area sizes */
- area_calc_totrct(sa, WM_window_pixels_x(win), WM_window_pixels_y(win));
-
- /* clear all azones, add the area triange widgets */
- area_azone_initialize(win, win->screen, sa);
+ area_calc_totrct(sa, &window_rect);
/* region rect sizes */
rect = sa->totrct;
- region_rect_recursive(win, sa, sa->regionbase.first, &rect, 0);
+ overlap_rect = rect;
+ region_rect_recursive(sa, sa->regionbase.first, &rect, &overlap_rect, 0);
+ sa->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
/* default area handlers */
- ed_default_handlers(wm, sa, &sa->handlers, sa->type->keymapflag);
+ ed_default_handlers(wm, sa, NULL, &sa->handlers, sa->type->keymapflag);
/* checks spacedata, adds own handlers */
if (sa->type->init)
sa->type->init(wm, sa);
+ /* clear all azones, add the area triangle widgets */
+ area_azone_initialize(win, screen, sa);
+
/* region windows, default and own handlers */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- region_subwindow(win, ar, false);
+ region_subwindow(ar);
- if (ar->swinid) {
+ if (ar->visible) {
/* default region handlers */
- ed_default_handlers(wm, sa, &ar->handlers, ar->type->keymapflag);
+ ed_default_handlers(wm, sa, ar, &ar->handlers, ar->type->keymapflag);
/* own handlers */
- if (ar->type->init)
+ if (ar->type->init) {
ar->type->init(wm, ar);
+ }
}
else {
/* prevent uiblocks to run */
UI_blocklist_free(NULL, &ar->uiblocks);
}
+
+ /* Some AZones use View2D data which is only updated in region init, so call that first! */
+ region_azones_add(screen, sa, ar, ar->alignment & ~RGN_SPLIT_PREV);
+ }
+
+
+ /* Avoid re-initializing tools while resizing the window. */
+ if ((G.moving & G_TRANSFORM_WM) == 0) {
+ if ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
+ WM_toolsystem_refresh_screen_area(workspace, view_layer, sa);
+ sa->flag |= AREA_FLAG_ACTIVE_TOOL_UPDATE;
+ }
+ else {
+ sa->runtime.tool = NULL;
+ sa->runtime.is_tool_set = true;
+ }
}
}
@@ -1500,22 +1665,16 @@ static void region_update_rect(ARegion *ar)
/**
* Call to move a popup window (keep OpenGL context free!)
*/
-void ED_region_update_rect(bContext *C, ARegion *ar)
+void ED_region_update_rect(ARegion *ar)
{
- wmWindow *win = CTX_wm_window(C);
-
- wm_subwindow_rect_set(win, ar->swinid, &ar->winrct);
-
region_update_rect(ar);
}
/* externally called for floating regions like menus */
-void ED_region_init(bContext *C, ARegion *ar)
+void ED_region_init(ARegion *ar)
{
-// ARegionType *at = ar->type;
-
/* refresh can be called before window opened */
- region_subwindow(CTX_wm_window(C), ar, false);
+ region_subwindow(ar);
region_update_rect(ar);
}
@@ -1526,10 +1685,25 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
ar->type->cursor(win, sa, ar);
}
else {
+ if (WM_cursor_set_from_tool(win, sa, ar)) {
+ return;
+ }
WM_cursor_set(win, CURSOR_STD);
}
}
+/* for use after changing visibility of regions */
+void ED_region_visibility_change_update(bContext *C, ARegion *ar)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (ar->flag & RGN_FLAG_HIDDEN)
+ WM_event_remove_handlers(C, &ar->handlers);
+
+ ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
+ ED_area_tag_redraw(sa);
+}
+
/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade)
{
@@ -1542,11 +1716,7 @@ void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade)
region_blend_start(C, sa, ar);
}
else {
- if (ar->flag & RGN_FLAG_HIDDEN)
- WM_event_remove_handlers(C, &ar->handlers);
-
- ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
- ED_area_tag_redraw(sa);
+ ED_region_visibility_change_update(C, ar);
}
}
@@ -1566,10 +1736,8 @@ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free)
const char spacetype = sa_dst->spacetype;
const short flag_copy = HEADER_NO_PULLDOWN;
- sa_dst->headertype = sa_src->headertype;
sa_dst->spacetype = sa_src->spacetype;
sa_dst->type = sa_src->type;
- sa_dst->butspacetype = sa_src->butspacetype;
sa_dst->flag = (sa_dst->flag & ~flag_copy) | (sa_src->flag & flag_copy);
@@ -1597,10 +1765,8 @@ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free)
void ED_area_data_swap(ScrArea *sa_dst, ScrArea *sa_src)
{
- SWAP(short, sa_dst->headertype, sa_src->headertype);
SWAP(char, sa_dst->spacetype, sa_src->spacetype);
SWAP(SpaceType *, sa_dst->type, sa_src->type);
- SWAP(char, sa_dst->butspacetype, sa_src->butspacetype);
SWAP(ListBase, sa_dst->spacedata, sa_src->spacedata);
@@ -1639,12 +1805,15 @@ void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
*/
void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exit)
{
+ wmWindow *win = CTX_wm_window(C);
+
if (sa->spacetype != type) {
SpaceType *st;
SpaceLink *slold;
SpaceLink *sl;
/* store sa->type->exit callback */
void *sa_exit = sa->type ? sa->type->exit : NULL;
+ int header_alignment = ED_area_header_alignment(sa);
/* in some cases (opening temp space) we don't want to
* call area exit callback, so we temporarily unset it */
@@ -1663,9 +1832,12 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
slold = sa->spacedata.first;
sa->spacetype = type;
- sa->butspacetype = type;
sa->type = st;
+ /* If st->new may be called, don't use context until then. The
+ * sa->type->context() callback has changed but data may be invalid
+ * (e.g. with properties editor) until space-data is properly created */
+
/* check previously stored space */
for (sl = sa->spacedata.first; sl; sl = sl->next)
if (sl->spacetype == type)
@@ -1690,11 +1862,22 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
/* put in front of list */
BLI_remlink(&sa->spacedata, sl);
BLI_addhead(&sa->spacedata, sl);
+
+
+ /* Sync header alignment. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_HEADER) {
+ ar->alignment = header_alignment;
+ break;
+ }
+ }
}
else {
/* new space */
if (st) {
- sl = st->new(C);
+ /* Don't get scene from context here which may depend on space-data. */
+ Scene *scene = WM_window_get_active_scene(win);
+ sl = st->new(sa, scene);
BLI_addhead(&sa->spacedata, sl);
/* swap regions */
@@ -1705,7 +1888,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
}
}
- ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
+ ED_area_initialize(CTX_wm_manager(C), win, sa);
/* tell WM to refresh, cursor types etc */
WM_event_add_mousemove(C);
@@ -1755,32 +1938,193 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
RNA_pointer_create(&(scr->id), &RNA_Area, sa, &areaptr);
uiDefButR(block, UI_BTYPE_MENU, 0, "", xco, yco, 1.6 * U.widget_unit, U.widget_unit,
- &areaptr, "type", 0, 0.0f, 0.0f, 0.0f, 0.0f, "");
+ &areaptr, "ui_type", 0, 0.0f, 0.0f, 0.0f, 0.0f, "");
return xco + 1.7 * U.widget_unit;
}
/************************ standard UI regions ************************/
-void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int contextnr, const bool vertical)
+static ThemeColorID region_background_color_id(const bContext *C, const ARegion *region)
+{
+ ScrArea *area = CTX_wm_area(C);
+
+ switch (region->regiontype) {
+ case RGN_TYPE_HEADER:
+ if (ED_screen_area_active(C) || ED_area_is_global(area)) {
+ return TH_HEADER;
+ }
+ else {
+ return TH_HEADERDESEL;
+ }
+ case RGN_TYPE_PREVIEW:
+ return TH_PREVIEW_BACK;
+ default:
+ return TH_BACK;
+ }
+}
+
+static void region_clear_color(const bContext *C, const ARegion *ar, ThemeColorID colorid)
+{
+ if (ar->alignment == RGN_ALIGN_FLOAT) {
+ /* handle our own drawing. */
+ }
+ else if (ar->overlap) {
+ /* view should be in pixelspace */
+ UI_view2d_view_restore(C);
+
+ float back[4];
+ UI_GetThemeColor4fv(colorid, back);
+ GPU_clear_color(back[3] * back[0], back[3] * back[1], back[3] * back[2], back[3]);
+ GPU_clear(GPU_COLOR_BIT);
+ }
+ else {
+ UI_ThemeClearColor(colorid);
+ GPU_clear(GPU_COLOR_BIT);
+ }
+}
+
+BLI_INLINE bool streq_array_any(const char *s, const char *arr[])
+{
+ for (uint i = 0; arr[i]; i++) {
+ if (STREQ(arr[i], s)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void ed_panel_draw(
+ const bContext *C,
+ ScrArea *sa,
+ ARegion *ar,
+ ListBase *lb,
+ PanelType *pt,
+ Panel *panel,
+ int w,
+ int em,
+ bool vertical)
{
- ScrArea *sa = CTX_wm_area(C);
uiStyle *style = UI_style_get_dpi();
- uiBlock *block;
+
+ /* draw panel */
+ uiBlock *block = UI_block_begin(C, ar, pt->idname, UI_EMBOSS);
+
+ bool open;
+ panel = UI_panel_begin(sa, ar, lb, block, pt, panel, &open);
+
+ /* bad fixed values */
+ int xco, yco, h = 0;
+
+ if (pt->draw_header_preset && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
+ /* for preset menu */
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
+ 0, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
+
+ pt->draw_header_preset(C, panel);
+
+ int headerend = w - UI_UNIT_X;
+
+ UI_block_layout_resolve(block, &xco, &yco);
+ UI_block_translate(block, headerend - xco, 0);
+ panel->layout = NULL;
+ }
+
+ if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
+ int labelx, labely;
+ UI_panel_label_offset(block, &labelx, &labely);
+
+ /* for enabled buttons */
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
+ labelx, labely, UI_UNIT_Y, 1, 0, style);
+
+ pt->draw_header(C, panel);
+
+ UI_block_layout_resolve(block, &xco, &yco);
+ panel->labelofs = xco - labelx;
+ panel->layout = NULL;
+ }
+ else {
+ panel->labelofs = 0;
+ }
+
+ if (open) {
+ short panelContext;
+
+ /* panel context can either be toolbar region or normal panels region */
+ if (pt->flag & PNL_LAYOUT_VERT_BAR) {
+ panelContext = UI_LAYOUT_VERT_BAR;
+ }
+ else if (ar->regiontype == RGN_TYPE_TOOLS) {
+ panelContext = UI_LAYOUT_TOOLBAR;
+ }
+ else {
+ panelContext = UI_LAYOUT_PANEL;
+ }
+
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, panelContext,
+ (pt->flag & PNL_LAYOUT_VERT_BAR) ? 0 : style->panelspace, 0,
+ (pt->flag & PNL_LAYOUT_VERT_BAR) ? 0 : w - 2 * style->panelspace,
+ em, 0, style);
+
+ pt->draw(C, panel);
+
+ UI_block_layout_resolve(block, &xco, &yco);
+ panel->layout = NULL;
+
+ if (yco != 0) {
+ h = -yco + 2 * style->panelspace;
+ }
+ }
+
+ UI_block_end(C, block);
+
+ /* Draw child panels. */
+ if (open) {
+ for (LinkData *link = pt->children.first; link; link = link->next) {
+ PanelType *child_pt = link->data;
+ Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
+
+ if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) {
+ ed_panel_draw(C, sa, ar, &panel->children, child_pt, child_panel, w, em, vertical);
+ }
+ }
+ }
+
+ UI_panel_end(block, w, h);
+}
+
+/**
+ * \param contexts: A NULL terminated array of context strings to match against.
+ * Matching against any of these strings will draw the panel.
+ * Can be NULL to skip context checks.
+ */
+void ED_region_panels_layout_ex(
+ const bContext *C, ARegion *ar,
+ const char *contexts[], int contextnr, const bool vertical)
+{
+ ar->runtime.category = NULL;
+
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ ScrArea *sa = CTX_wm_area(C);
PanelType *pt;
- Panel *panel;
View2D *v2d = &ar->v2d;
- View2DScrollers *scrollers;
- int x, y, xco, yco, w, em, triangle;
+ int x, y, w, em;
bool is_context_new = 0;
- int redo;
int scroll;
- bool use_category_tabs = (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI)); /* XXX, should use some better check? */
+ /* XXX, should use some better check? */
+ /* For now also has hardcoded check for clip editor until it supports actual toolbar. */
+ bool use_category_tabs = ((1 << ar->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) ||
+ (ar->regiontype == RGN_TYPE_TOOLS && sa->spacetype == SPACE_CLIP);
/* offset panels for small vertical tab area */
const char *category = NULL;
const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH;
int margin_x = 0;
+ const bool region_layout_based = ar->flag & RGN_FLAG_DYNAMIC_SIZE;
BLI_SMALLSTACK_DECLARE(pt_stack, PanelType *);
@@ -1809,8 +2153,18 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
/* collect panels to draw */
for (pt = ar->type->paneltypes.last; pt; pt = pt->prev) {
+ /* Only draw top level panels. */
+ if (pt->parent) {
+ continue;
+ }
+
/* verify context */
- if (context && pt->context[0] && !STREQ(context, pt->context)) {
+ if (contexts && pt->context[0] && !streq_array_any(pt->context, contexts)) {
+ continue;
+ }
+
+ /* If we're tagged, only use compatible. */
+ if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) {
continue;
}
@@ -1846,158 +2200,122 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
}
- /* sortof hack - but we cannot predict the height of panels, until it's being generated */
- /* the layout engine works with fixed width (from v2d->cur), which is being set at end of the loop */
- /* in case scroller settings (hide flags) differ from previous, the whole loop gets done again */
- for (redo = 2; redo > 0; redo--) {
-
- if (vertical) {
- w = BLI_rctf_size_x(&v2d->cur);
- em = (ar->type->prefsizex) ? 10 : 20; /* works out to 10*UI_UNIT_X or 20*UI_UNIT_X */
- }
- else {
- w = UI_PANEL_WIDTH;
- em = (ar->type->prefsizex) ? 10 : 20;
- }
-
- w -= margin_x;
+ if (vertical) {
+ w = BLI_rctf_size_x(&v2d->cur);
+ em = (ar->type->prefsizex) ? 10 : 20; /* works out to 10*UI_UNIT_X or 20*UI_UNIT_X */
+ }
+ else {
+ w = UI_PANEL_WIDTH;
+ em = (ar->type->prefsizex) ? 10 : 20;
+ }
- /* create panels */
- UI_panels_begin(C, ar);
+ w -= margin_x;
- /* set view2d view matrix - UI_block_begin() stores it */
- UI_view2d_view_ortho(v2d);
+ /* create panels */
+ UI_panels_begin(C, ar);
- BLI_SMALLSTACK_ITER_BEGIN(pt_stack, pt)
- {
- bool open;
+ /* set view2d view matrix - UI_block_begin() stores it */
+ UI_view2d_view_ortho(v2d);
- panel = UI_panel_find_by_type(ar, pt);
+ BLI_SMALLSTACK_ITER_BEGIN(pt_stack, pt)
+ {
+ Panel *panel = UI_panel_find_by_type(&ar->panels, pt);
- if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
- if ((panel == NULL) || ((panel->flag & PNL_PIN) == 0)) {
- continue;
- }
+ if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
+ if ((panel == NULL) || ((panel->flag & PNL_PIN) == 0)) {
+ continue;
}
+ }
- /* draw panel */
- block = UI_block_begin(C, ar, pt->idname, UI_EMBOSS);
- panel = UI_panel_begin(sa, ar, block, pt, panel, &open);
-
- /* bad fixed values */
- triangle = (int)(UI_UNIT_Y * 1.1f);
-
- if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
- /* for enabled buttons */
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
- triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
+ ed_panel_draw(C, sa, ar, &ar->panels, pt, panel, w, em, vertical);
+ }
+ BLI_SMALLSTACK_ITER_END;
- pt->draw_header(C, panel);
+ /* align panels and return size */
+ UI_panels_end(C, ar, &x, &y);
- UI_block_layout_resolve(block, &xco, &yco);
- panel->labelofs = xco - triangle;
- panel->layout = NULL;
- }
- else {
- panel->labelofs = 0;
+ /* before setting the view */
+ if (region_layout_based) {
+ /* XXX, only single panel support atm.
+ * Can't use x/y values calculated above because they're not using the real height of panels,
+ * instead they calculate offsets for the next panel to start drawing. */
+ Panel *panel = ar->panels.last;
+ if (panel != NULL) {
+ int size_dyn[2] = {
+ UI_UNIT_X * ((panel->flag & PNL_CLOSED) ? 8 : 14),
+ UI_panel_size_y(panel),
+ };
+ /* region size is layout based and needs to be updated */
+ if ((ar->sizex != size_dyn[0]) ||
+ (ar->sizey != size_dyn[1]))
+ {
+ ar->sizex = size_dyn[0];
+ ar->sizey = size_dyn[1];
+ sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
-
- if (open) {
- short panelContext;
-
- /* panel context can either be toolbar region or normal panels region */
- if (ar->regiontype == RGN_TYPE_TOOLS)
- panelContext = UI_LAYOUT_TOOLBAR;
- else
- panelContext = UI_LAYOUT_PANEL;
-
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_VERTICAL, panelContext,
- style->panelspace, 0, w - 2 * style->panelspace, em, 0, style);
-
- pt->draw(C, panel);
-
- UI_block_layout_resolve(block, &xco, &yco);
- panel->layout = NULL;
-
- yco -= 2 * style->panelspace;
- UI_panel_end(block, w, -yco);
+ y = ABS(ar->sizey - 1);
+ }
+ }
+ else if (vertical) {
+ /* we always keep the scroll offset - so the total view gets increased with the scrolled away part */
+ if (v2d->cur.ymax < -FLT_EPSILON) {
+ /* Clamp to lower view boundary */
+ if (v2d->tot.ymin < -v2d->winy) {
+ y = min_ii(y, 0);
}
else {
- yco = 0;
- UI_panel_end(block, w, 0);
+ y = min_ii(y, v2d->cur.ymin);
}
-
- UI_block_end(C, block);
}
- BLI_SMALLSTACK_ITER_END;
-
- /* align panels and return size */
- UI_panels_end(C, ar, &x, &y);
- /* before setting the view */
- if (vertical) {
- /* we always keep the scroll offset - so the total view gets increased with the scrolled away part */
- if (v2d->cur.ymax < -FLT_EPSILON) {
- /* Clamp to lower view boundary */
- if (v2d->tot.ymin < -v2d->winy) {
- y = min_ii(y, 0);
- }
- else {
- y = min_ii(y, v2d->cur.ymin);
- }
+ y = -y;
+ }
+ else {
+ /* don't jump back when panels close or hide */
+ if (!is_context_new) {
+ if (v2d->tot.xmax > v2d->winx) {
+ x = max_ii(x, 0);
}
-
- y = -y;
- }
- else {
- /* don't jump back when panels close or hide */
- if (!is_context_new) {
- if (v2d->tot.xmax > v2d->winx) {
- x = max_ii(x, 0);
- }
- else {
- x = max_ii(x, v2d->cur.xmax);
- }
+ else {
+ x = max_ii(x, v2d->cur.xmax);
}
-
- y = -y;
}
- /* this also changes the 'cur' */
- UI_view2d_totRect_set(v2d, x, y);
+ y = -y;
+ }
+
+ /* this also changes the 'cur' */
+ UI_view2d_totRect_set(v2d, x, y);
- if (scroll != v2d->scroll) {
- /* Note: this code scales fine, but because of rounding differences, positions of elements
- * flip +1 or -1 pixel compared to redoing the entire layout again.
- * Leaving in commented code for future tests */
+ if (scroll != v2d->scroll) {
+ /* Note: this code scales fine, but because of rounding differences, positions of elements
+ * flip +1 or -1 pixel compared to redoing the entire layout again.
+ * Leaving in commented code for future tests */
#if 0
- UI_panels_scale(ar, BLI_rctf_size_x(&v2d->cur));
- break;
+ UI_panels_scale(ar, BLI_rctf_size_x(&v2d->cur));
+ break;
#endif
- }
- else {
- break;
- }
}
- /* clear */
- if (ar->overlap) {
- /* view should be in pixelspace */
- UI_view2d_view_restore(C);
- glEnable(GL_BLEND);
- UI_ThemeColor4((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK);
- glRecti(0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1);
- glDisable(GL_BLEND);
+ if (use_category_tabs) {
+ ar->runtime.category = category;
}
- else {
- UI_ThemeClearColor((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+}
+void ED_region_panels_layout(const bContext *C, ARegion *ar)
+{
+ ED_region_panels_layout_ex(C, ar, NULL, -1, true);
+}
+
+void ED_region_panels_draw(const bContext *C, ARegion *ar)
+{
+ View2D *v2d = &ar->v2d;
+
+ if (ar->alignment != RGN_ALIGN_FLOAT) {
+ region_clear_color(C, ar, (ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK);
}
/* reset line width for drawing tabs */
- glLineWidth(1.0f);
+ GPU_line_width(1.0f);
/* set the view */
UI_view2d_view_ortho(v2d);
@@ -2008,16 +2326,41 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
/* restore view matrix */
UI_view2d_view_restore(C);
- if (use_category_tabs) {
- UI_panel_category_draw_all(ar, category);
+ /* Set in layout. */
+ if (ar->runtime.category) {
+ UI_panel_category_draw_all(ar, ar->runtime.category);
}
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ const rcti *mask = NULL;
+ rcti mask_buf;
+ if (ar->runtime.category && (ar->alignment == RGN_ALIGN_RIGHT)) {
+ UI_view2d_mask_from_win(v2d, &mask_buf);
+ mask_buf.xmax -= UI_PANEL_CATEGORY_MARGIN_WIDTH;
+ mask = &mask_buf;
+ }
+ View2DScrollers *scrollers = UI_view2d_scrollers_calc(
+ C, v2d, mask, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
+void ED_region_panels_ex(
+ const bContext *C, ARegion *ar,
+ const char *contexts[], int contextnr, const bool vertical)
+{
+ /* TODO: remove? */
+ ED_region_panels_layout_ex(C, ar, contexts, contextnr, vertical);
+ ED_region_panels_draw(C, ar);
+}
+
+void ED_region_panels(const bContext *C, ARegion *ar)
+{
+ /* TODO: remove? */
+ ED_region_panels_layout(C, ar);
+ ED_region_panels_draw(C, ar);
+}
+
void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -2028,35 +2371,52 @@ void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-void ED_region_header(const bContext *C, ARegion *ar)
+void ED_region_header_layout(const bContext *C, ARegion *ar)
{
uiStyle *style = UI_style_get_dpi();
uiBlock *block;
uiLayout *layout;
HeaderType *ht;
Header header = {NULL};
- int maxco, xco, yco;
- int headery = ED_area_headersize();
+ bool region_layout_based = ar->flag & RGN_FLAG_DYNAMIC_SIZE;
- /* clear */
- UI_ThemeClearColor((ED_screen_area_active(C)) ? TH_HEADER : TH_HEADERDESEL);
- glClear(GL_COLOR_BUFFER_BIT);
+ /* Height of buttons and scaling needed to achieve it. */
+ const int buttony = min_ii(UI_UNIT_Y, ar->winy - 2 * UI_DPI_FAC);
+ const float buttony_scale = buttony / (float)UI_UNIT_Y;
+
+ /* Vertically center buttons. */
+ int xco = UI_HEADER_OFFSET;
+ int yco = buttony + (ar->winy - buttony) / 2;
+ int maxco = xco;
+
+ /* XXX workaround for 1 px alignment issue. Not sure what causes it... Would prefer a proper fix - Julian */
+ if (!ELEM(CTX_wm_area(C)->spacetype, SPACE_TOPBAR, SPACE_STATUSBAR)) {
+ yco -= 1;
+ }
/* set view2d view matrix for scrolling (without scrollers) */
UI_view2d_view_ortho(&ar->v2d);
- xco = maxco = 0.4f * UI_UNIT_X;
- yco = headery - floor(0.2f * UI_UNIT_Y);
-
/* draw all headers types */
for (ht = ar->type->headertypes.first; ht; ht = ht->next) {
+ if (ht->poll && !ht->poll(C, ht)) {
+ continue;
+ }
+
block = UI_block_begin(C, ar, ht->idname, UI_EMBOSS);
- layout = UI_block_layout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, UI_UNIT_Y, 1, 0, style);
+ layout = UI_block_layout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, buttony, 1, 0, style);
+
+ if (buttony_scale != 1.0f) {
+ uiLayoutSetScaleY(layout, buttony_scale);
+ }
if (ht->draw) {
header.type = ht;
header.layout = layout;
ht->draw(C, &header);
+ if (ht->next) {
+ uiItemS(layout);
+ }
/* for view2d */
xco = uiLayoutGetWidth(layout);
@@ -2070,17 +2430,54 @@ void ED_region_header(const bContext *C, ARegion *ar)
if (xco > maxco)
maxco = xco;
+ int new_sizex = (maxco + UI_HEADER_OFFSET) / UI_DPI_FAC;
+
+ if (region_layout_based && (ar->sizex != new_sizex)) {
+ /* region size is layout based and needs to be updated */
+ ScrArea *sa = CTX_wm_area(C);
+
+ ar->sizex = new_sizex;
+ sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ }
+
UI_block_end(C, block);
- UI_block_draw(C, block);
+ }
+
+ if (!region_layout_based) {
+ maxco += UI_HEADER_OFFSET;
}
/* always as last */
- UI_view2d_totRect_set(&ar->v2d, maxco + UI_UNIT_X + 80, headery);
+ UI_view2d_totRect_set(&ar->v2d, maxco, ar->winy);
- /* restore view matrix? */
+ /* restore view matrix */
UI_view2d_view_restore(C);
}
+void ED_region_header_draw(const bContext *C, ARegion *ar)
+{
+ /* clear */
+ region_clear_color(C, ar, region_background_color_id(C, ar));
+
+ UI_view2d_view_ortho(&ar->v2d);
+
+ /* View2D matrix might have changed due to dynamic sized regions. */
+ UI_blocklist_update_window_matrix(C, &ar->uiblocks);
+
+ /* draw blocks */
+ UI_blocklist_draw(C, &ar->uiblocks);
+
+ /* restore view matrix */
+ UI_view2d_view_restore(C);
+}
+
+void ED_region_header(const bContext *C, ARegion *ar)
+{
+ /* TODO: remove? */
+ ED_region_header_layout(C, ar);
+ ED_region_header_draw(C, ar);
+}
+
void ED_region_header_init(ARegion *ar)
{
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
@@ -2092,47 +2489,152 @@ int ED_area_headersize(void)
return (int)(HEADERY * UI_DPI_FAC);
}
-void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], const bool full_redraw)
+
+int ED_area_header_alignment(const ScrArea *area)
+{
+ for (ARegion *ar = area->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_HEADER) {
+ return ar->alignment;
+ }
+ }
+
+ return RGN_ALIGN_TOP;
+}
+
+/**
+ * \return the final height of a global \a area, accounting for DPI.
+ */
+int ED_area_global_size_y(const ScrArea *area)
+{
+ BLI_assert(ED_area_is_global(area));
+ return round_fl_to_int(area->global->cur_fixed_height * UI_DPI_FAC);
+}
+int ED_area_global_min_size_y(const ScrArea *area)
+{
+ BLI_assert(ED_area_is_global(area));
+ return round_fl_to_int(area->global->size_min * UI_DPI_FAC);
+}
+int ED_area_global_max_size_y(const ScrArea *area)
+{
+ BLI_assert(ED_area_is_global(area));
+ return round_fl_to_int(area->global->size_max * UI_DPI_FAC);
+}
+
+bool ED_area_is_global(const ScrArea *area)
+{
+ return area->global != NULL;
+}
+
+ScrArea *ED_screen_areas_iter_first(const wmWindow *win, const bScreen *screen)
+{
+ ScrArea *global_area = win->global_areas.areabase.first;
+
+ if (!global_area) {
+ return screen->areabase.first;
+ }
+ else if ((global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) == 0) {
+ return global_area;
+ }
+ /* Find next visible area. */
+ return ED_screen_areas_iter_next(screen, global_area);
+}
+ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area)
+{
+ if (area->global) {
+ for (ScrArea *area_iter = area->next; area_iter; area_iter = area_iter->next) {
+ if ((area_iter->global->flag & GLOBAL_AREA_IS_HIDDEN) == 0) {
+ return area_iter;
+ }
+ }
+ /* No visible next global area found, start iterating over layout areas. */
+ return screen->areabase.first;
+ }
+
+ return area->next;
+}
+
+/**
+ * For now we just assume all global areas are made up out of horizontal bars
+ * with the same size. A fixed size could be stored in ARegion instead if needed.
+ *
+ * \return the DPI aware height of a single bar/region in global areas.
+ */
+int ED_region_global_size_y(void)
+{
+ return ED_area_headersize(); /* same size as header */
+}
+
+void ED_region_info_draw_multiline(ARegion *ar, const char *text_array[], float fill_color[4], const bool full_redraw)
{
const int header_height = UI_UNIT_Y;
uiStyle *style = UI_style_get_dpi();
int fontid = style->widget.uifont_id;
- GLint scissor[4];
+ int scissor[4];
rcti rect;
+ int num_lines = 0;
/* background box */
ED_region_visible_rect(ar, &rect);
- rect.ymin = BLI_rcti_size_y(&ar->winrct) - header_height;
- /* box fill entire width or just around text */
- if (!full_redraw)
- rect.xmax = min_ii(rect.xmax, rect.xmin + BLF_width(fontid, text, BLF_DRAW_STR_DUMMY_MAX) + 1.2f * U.widget_unit);
+ /* Box fill entire width or just around text. */
+ if (!full_redraw) {
+ const char **text = &text_array[0];
+ while (*text) {
+ rect.xmax = min_ii(rect.xmax, rect.xmin + BLF_width(fontid, *text, BLF_DRAW_STR_DUMMY_MAX) + 1.2f * U.widget_unit);
+ text++;
+ num_lines++;
+ }
+ }
+ /* Just count the line number. */
+ else {
+ const char **text = &text_array[0];
+ while (*text) {
+ text++;
+ num_lines++;
+ }
+ }
- rect.ymax = BLI_rcti_size_y(&ar->winrct);
+ rect.ymin = rect.ymax - header_height * num_lines;
/* setup scissor */
- glGetIntegerv(GL_SCISSOR_BOX, scissor);
- glScissor(ar->winrct.xmin + rect.xmin, ar->winrct.ymin + rect.ymin,
+ GPU_scissor_get_i(scissor);
+ GPU_scissor(rect.xmin, rect.ymin,
BLI_rcti_size_x(&rect) + 1, BLI_rcti_size_y(&rect) + 1);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4fv(fill_color);
- glRecti(rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1);
- glDisable(GL_BLEND);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(fill_color);
+ immRecti(pos, rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1);
+ immUnbindProgram();
+ GPU_blend(false);
/* text */
- UI_ThemeColor(TH_TEXT_HI);
+ UI_FontThemeColor(fontid, TH_TEXT_HI);
BLF_clipping(fontid, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
BLF_enable(fontid, BLF_CLIPPING);
- BLF_position(fontid, rect.xmin + 0.6f * U.widget_unit, rect.ymin + 0.3f * U.widget_unit, 0.0f);
-
- BLF_draw(fontid, text, BLF_DRAW_STR_DUMMY_MAX);
+ int offset = num_lines - 1;
+ {
+ const char **text = &text_array[0];
+ while (*text) {
+ BLF_position(fontid, rect.xmin + 0.6f * U.widget_unit, rect.ymin + 0.3f * U.widget_unit + offset * header_height, 0.0f);
+ BLF_draw(fontid, *text, BLF_DRAW_STR_DUMMY_MAX);
+ text++;
+ offset--;
+ }
+ }
BLF_disable(fontid, BLF_CLIPPING);
/* restore scissor as it was before */
- glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+}
+
+void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], const bool full_redraw)
+{
+ ED_region_info_draw_multiline(ar, (const char *[2]){text, NULL}, fill_color, full_redraw);
}
#define MAX_METADATA_STR 1024
@@ -2303,11 +2805,11 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame,
return;
/* find window pixel coordinates of origin */
- glPushMatrix();
+ GPU_matrix_push();
/* offset and zoom using ogl */
- glTranslatef(x, y, 0.0f);
- glScalef(zoomx, zoomy, 1.0f);
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_scale_2f(zoomx, zoomy);
BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f * U.pixelsize, U.dpi);
@@ -2317,17 +2819,20 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame,
box_y = metadata_box_height_get(ibuf, blf_mono_font, true);
if (box_y) {
- UI_ThemeColor(TH_METADATA_BG);
-
/* set up rect */
BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymax, frame->ymax + box_y);
/* draw top box */
- glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_METADATA_BG);
+ immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ immUnbindProgram();
BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
BLF_enable(blf_mono_font, BLF_CLIPPING);
- UI_ThemeColor(TH_METADATA_TEXT);
+ UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT);
metadata_draw_imbuf(ibuf, &rect, blf_mono_font, true);
BLF_disable(blf_mono_font, BLF_CLIPPING);
@@ -2339,23 +2844,26 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame,
box_y = metadata_box_height_get(ibuf, blf_mono_font, false);
if (box_y) {
- UI_ThemeColor(TH_METADATA_BG);
-
/* set up box rect */
BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymin - box_y, frame->ymin);
/* draw top box */
- glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_METADATA_BG);
+ immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ immUnbindProgram();
BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
BLF_enable(blf_mono_font, BLF_CLIPPING);
- UI_ThemeColor(TH_METADATA_TEXT);
+ UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT);
metadata_draw_imbuf(ibuf, &rect, blf_mono_font, false);
BLF_disable(blf_mono_font, BLF_CLIPPING);
}
- glPopMatrix();
+ GPU_matrix_pop();
}
void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
@@ -2365,11 +2873,16 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
int x1, y1, x2, y2;
/* the image is located inside (0, 0), (1, 1) as set by view2d */
- UI_ThemeColorShade(TH_BACK, 20);
-
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x1, &y1);
UI_view2d_view_to_region(&ar->v2d, 1.0f, 1.0f, &x2, &y2);
- glRectf(x1, y1, x2, y2);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, 20);
+ immRectf(pos, x1, y1, x2, y2);
+ immUnbindProgram();
/* gridsize adapted to zoom level */
gridsize = 0.5f * (zoomx + zoomy);
@@ -2389,33 +2902,58 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
}
}
- /* the fine resolution level */
blendfac = 0.25f * gridsize - floorf(0.25f * gridsize);
CLAMP(blendfac, 0.0f, 1.0f);
- UI_ThemeColorShade(TH_BACK, (int)(20.0f * (1.0f - blendfac)));
- fac = 0.0f;
- glBegin(GL_LINES);
- while (fac < 1.0f) {
- glVertex2f(x1, y1 * (1.0f - fac) + y2 * fac);
- glVertex2f(x2, y1 * (1.0f - fac) + y2 * fac);
- glVertex2f(x1 * (1.0f - fac) + x2 * fac, y1);
- glVertex2f(x1 * (1.0f - fac) + x2 * fac, y2);
- fac += gridstep;
- }
+ int count_fine = 1.0f / gridstep;
+ int count_large = 1.0f / (4.0f * gridstep);
+
+ if (count_fine > 0) {
+ GPU_vertformat_clear(format);
+ pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ unsigned color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GPU_PRIM_LINES, 4 * count_fine + 4 * count_large);
+
+ float theme_color[3];
+ UI_GetThemeColorShade3fv(TH_BACK, (int)(20.0f * (1.0f - blendfac)), theme_color);
+ fac = 0.0f;
+
+ /* the fine resolution level */
+ for (int i = 0; i < count_fine; i++) {
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac);
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac);
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1);
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2);
+ fac += gridstep;
+ }
- /* the large resolution level */
- UI_ThemeColor(TH_BACK);
+ if (count_large > 0) {
+ UI_GetThemeColor3fv(TH_BACK, theme_color);
+ fac = 0.0f;
+
+ /* the large resolution level */
+ for (int i = 0; i < count_large; i++) {
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac);
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac);
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1);
+ immAttr3fv(color, theme_color);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2);
+ fac += 4.0f * gridstep;
+ }
+ }
- fac = 0.0f;
- while (fac < 1.0f) {
- glVertex2f(x1, y1 * (1.0f - fac) + y2 * fac);
- glVertex2f(x2, y1 * (1.0f - fac) + y2 * fac);
- glVertex2f(x1 * (1.0f - fac) + x2 * fac, y1);
- glVertex2f(x1 * (1.0f - fac) + x2 * fac, y2);
- fac += 4.0f * gridstep;
+ immEnd();
+ immUnbindProgram();
}
- glEnd();
}
/* If the area has overlapping regions, it returns visible rect for Region *ar */
@@ -2434,14 +2972,32 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect)
for (; arn; arn = arn->next) {
if (ar != arn && arn->overlap) {
if (BLI_rcti_isect(rect, &arn->winrct, NULL)) {
+ if (ELEM(arn->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ /* Overlap left, also check 1 pixel offset (2 regions on one side). */
+ if (ABS(rect->xmin - arn->winrct.xmin) < 2) {
+ rect->xmin = arn->winrct.xmax;
+ }
- /* overlap left, also check 1 pixel offset (2 regions on one side) */
- if (ABS(rect->xmin - arn->winrct.xmin) < 2)
- rect->xmin = arn->winrct.xmax;
-
- /* overlap right */
- if (ABS(rect->xmax - arn->winrct.xmax) < 2)
- rect->xmax = arn->winrct.xmin;
+ /* Overlap right. */
+ if (ABS(rect->xmax - arn->winrct.xmax) < 2) {
+ rect->xmax = arn->winrct.xmin;
+ }
+ }
+ else if (ELEM(arn->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ /* Same logic as above for vertical regions. */
+ if (ABS(rect->ymin - arn->winrct.ymin) < 2) {
+ rect->ymin = arn->winrct.ymax;
+ }
+ if (ABS(rect->ymax - arn->winrct.ymax) < 2) {
+ rect->ymax = arn->winrct.ymin;
+ }
+ }
+ else if (arn->alignment == RGN_ALIGN_FLOAT) {
+ /* Skip floating. */
+ }
+ else {
+ BLI_assert(!"Region overlap with unknown alignment");
+ }
}
}
}
@@ -2452,8 +3008,11 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect)
void ED_region_cache_draw_background(const ARegion *ar)
{
- glColor4ub(128, 128, 255, 64);
- glRecti(0, 0, ar->winx, 8 * UI_DPI_FAC);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ub(128, 128, 255, 64);
+ immRecti(pos, 0, 0, ar->winx, 8 * UI_DPI_FAC);
+ immUnbindProgram();
}
void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y)
@@ -2469,9 +3028,13 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f
BLF_width_and_height(fontid, numstr, sizeof(numstr), &font_dims[0], &font_dims[1]);
- glRecti(x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_CFRAME);
+ immRecti(pos, x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f);
+ immUnbindProgram();
- UI_ThemeColor(TH_TEXT);
+ UI_FontThemeColor(fontid, TH_TEXT);
BLF_position(fontid, x + 2.0f, y + 2.0f, 0.0f);
BLF_draw(fontid, numstr, sizeof(numstr));
}
@@ -2479,17 +3042,73 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f
void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segments, const int *points, const int sfra, const int efra)
{
if (num_segments) {
- int a;
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ub(128, 128, 255, 128);
+
+ for (int a = 0; a < num_segments; a++) {
+ float x1 = (float)(points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx;
+ float x2 = (float)(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx;
+
+ immRecti(pos, x1, 0, x2, 8 * UI_DPI_FAC);
+ /* TODO(merwin): use primitive restart to draw multiple rects more efficiently */
+ }
- glColor4ub(128, 128, 255, 128);
+ immUnbindProgram();
+ }
+}
- for (a = 0; a < num_segments; a++) {
- float x1, x2;
+/**
+ * Generate subscriptions for this region.
+ */
+void ED_region_message_subscribe(
+ bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ if (ar->gizmo_map != NULL) {
+ WM_gizmomap_message_subscribe(C, ar->gizmo_map, ar, mbus);
+ }
+
+ if (!BLI_listbase_is_empty(&ar->uiblocks)) {
+ UI_region_message_subscribe(ar, mbus);
+ }
+
+ if (ar->type->message_subscribe != NULL) {
+ ar->type->message_subscribe(C, workspace, scene, screen, sa, ar, mbus);
+ }
+}
- x1 = (float)(points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx;
- x2 = (float)(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx;
+int ED_region_snap_size_test(const ARegion *ar)
+{
+ /* Use a larger value because toggling scrollbars can jump in size. */
+ const int snap_match_threshold = 16;
+ if (ar->type->snap_size != NULL) {
+ return ((((ar->sizex - ar->type->snap_size(ar, ar->sizex, 0)) <= snap_match_threshold) << 0) |
+ (((ar->sizey - ar->type->snap_size(ar, ar->sizey, 1)) <= snap_match_threshold) << 1));
+ }
+ return 0;
+}
- glRecti(x1, 0, x2, 8 * UI_DPI_FAC);
+bool ED_region_snap_size_apply(ARegion *ar, int snap_flag)
+{
+ bool changed = false;
+ if (ar->type->snap_size != NULL) {
+ if (snap_flag & (1 << 0)) {
+ short snap_size = ar->type->snap_size(ar, ar->sizex, 0);
+ if (snap_size != ar->sizex) {
+ ar->sizex = snap_size;
+ changed = true;
+ }
+ }
+ if (snap_flag & (1 << 1)) {
+ short snap_size = ar->type->snap_size(ar, ar->sizey, 1);
+ if (snap_size != ar->sizey) {
+ ar->sizey = snap_size;
+ changed = true;
+ }
}
}
+ return changed;
}
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
new file mode 100644
index 00000000000..53e2f96d6c4
--- /dev/null
+++ b/source/blender/editors/screen/area_utils.c
@@ -0,0 +1,89 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/screen/area_utils.c
+ * \ingroup edscr
+ *
+ * Helper functions for area/region API.
+ */
+
+#include "DNA_userdef_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Tool System Region Callbacks
+ * \{ */
+
+/**
+ * Callback for #ARegionType.message_subscribe
+ */
+void ED_region_generic_tools_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+ WM_msg_subscribe_rna_anon_prop(mbus, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
+}
+
+/**
+ * Callback for #ARegionType.snap_size
+ */
+int ED_region_generic_tools_region_snap_size(const ARegion *ar, int size, int axis)
+{
+ if (axis == 0) {
+ /* Note, this depends on the icon size: see #ICON_DEFAULT_HEIGHT_TOOLBAR. */
+ const float snap_units[] = {2 + 0.8f, 4 + 0.8f};
+ const float aspect = BLI_rctf_size_x(&ar->v2d.cur) / (BLI_rcti_size_x(&ar->v2d.mask) + 1);
+ int best_diff = INT_MAX;
+ int best_size = size;
+ for (uint i = 0; i < ARRAY_SIZE(snap_units); i += 1) {
+ const int test_size = (snap_units[i] * U.widget_unit) / (UI_DPI_FAC * aspect);
+ const int test_diff = ABS(test_size - size);
+ if (test_diff < best_diff) {
+ best_size = test_size;
+ best_diff = test_diff;
+ }
+ }
+ return best_size;
+ }
+ return size;
+}
+
+/** \} */
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 6e9a580e403..728df79fbbd 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -48,144 +48,22 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "UI_interface.h"
-#ifndef GL_CLAMP_TO_EDGE
-#define GL_CLAMP_TO_EDGE 0x812F
-#endif
-
-/* UNUSED */
-#if 0
-void fdrawbezier(float vec[4][3])
-{
- float dist;
- float curve_res = 24, spline_step = 0.0f;
-
- dist = 0.5f * fabsf(vec[0][0] - vec[3][0]);
-
- /* check direction later, for top sockets */
- vec[1][0] = vec[0][0] + dist;
- vec[1][1] = vec[0][1];
-
- vec[2][0] = vec[3][0] - dist;
- vec[2][1] = vec[3][1];
- /* we can reuse the dist variable here to increment the GL curve eval amount */
- dist = 1.0f / curve_res;
-
- cpack(0x0);
- glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
- glBegin(GL_LINE_STRIP);
- while (spline_step < 1.000001f) {
-#if 0
- if (do_shaded)
- UI_ThemeColorBlend(th_col1, th_col2, spline_step);
-#endif
- glEvalCoord1f(spline_step);
- spline_step += dist;
- }
- glEnd();
-}
-#endif
-
-void fdrawline(float x1, float y1, float x2, float y2)
-{
- glBegin(GL_LINES);
- glVertex2f(x1, y1);
- glVertex2f(x2, y2);
- glEnd();
-}
-
-void fdrawbox(float x1, float y1, float x2, float y2)
-{
- glBegin(GL_LINE_LOOP);
-
- glVertex2f(x1, y1);
- glVertex2f(x1, y2);
- glVertex2f(x2, y2);
- glVertex2f(x2, y1);
-
- glEnd();
-}
-
-void fdrawcheckerboard(float x1, float y1, float x2, float y2)
-{
- unsigned char col1[4] = {40, 40, 40}, col2[4] = {50, 50, 50};
-
- glColor3ubv(col1);
- glRectf(x1, y1, x2, y2);
- glColor3ubv(col2);
-
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX);
- glRectf(x1, y1, x2, y2);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-}
-
-void sdrawline(int x1, int y1, int x2, int y2)
-{
- glBegin(GL_LINES);
- glVertex2i(x1, y1);
- glVertex2i(x2, y2);
- glEnd();
-}
-
-/* UNUSED */
-#if 0
-/*
- * x1,y2
- * | \
- * | \
- * | \
- * x1,y1-- x2,y1
- */
-
-static void sdrawtripoints(int x1, int y1, int x2, int y2)
-{
- glVertex2i(x1, y1);
- glVertex2i(x1, y2);
- glVertex2i(x2, y1);
-}
-
-void sdrawtri(int x1, int y1, int x2, int y2)
-{
- glBegin(GL_LINE_STRIP);
- sdrawtripoints(x1, y1, x2, y2);
- glEnd();
-}
-
-void sdrawtrifill(int x1, int y1, int x2, int y2)
-{
- glBegin(GL_TRIANGLES);
- sdrawtripoints(x1, y1, x2, y2);
- glEnd();
-}
-#endif
-
-void sdrawbox(int x1, int y1, int x2, int y2)
-{
- glBegin(GL_LINE_LOOP);
-
- glVertex2i(x1, y1);
- glVertex2i(x1, y2);
- glVertex2i(x2, y2);
- glVertex2i(x2, y1);
-
- glEnd();
-}
-
-
/* ******************************************** */
void setlinestyle(int nr)
{
if (nr == 0) {
- glDisable(GL_LINE_STIPPLE);
+ GPU_line_stipple(false);
}
else {
- glEnable(GL_LINE_STIPPLE);
+ GPU_line_stipple(true);
if (U.pixelsize > 1.0f)
glLineStipple(nr, 0xCCCC);
else
@@ -204,122 +82,6 @@ void set_inverted_drawing(int enable)
GL_TOGGLE(GL_DITHER, !enable);
}
-/* UNUSED */
-#if 0
-void sdrawXORline(int x0, int y0, int x1, int y1)
-{
- if (x0 == x1 && y0 == y1) return;
-
- set_inverted_drawing(1);
-
- glBegin(GL_LINES);
- glVertex2i(x0, y0);
- glVertex2i(x1, y1);
- glEnd();
-
- set_inverted_drawing(0);
-}
-
-void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
-{
- static int old[4][2][2];
- static char flags[4] = {0, 0, 0, 0};
-
- /* with builtin memory, max 4 lines */
-
- set_inverted_drawing(1);
-
- glBegin(GL_LINES);
- if (nr == -1) { /* flush */
- for (nr = 0; nr < 4; nr++) {
- if (flags[nr]) {
- glVertex2iv(old[nr][0]);
- glVertex2iv(old[nr][1]);
- flags[nr] = 0;
- }
- }
- }
- else {
- if (nr >= 0 && nr < 4) {
- if (flags[nr]) {
- glVertex2iv(old[nr][0]);
- glVertex2iv(old[nr][1]);
- }
-
- old[nr][0][0] = x0;
- old[nr][0][1] = y0;
- old[nr][1][0] = x1;
- old[nr][1][1] = y1;
-
- flags[nr] = 1;
- }
-
- glVertex2i(x0, y0);
- glVertex2i(x1, y1);
- }
- glEnd();
-
- set_inverted_drawing(0);
-}
-
-void fdrawXORellipse(float xofs, float yofs, float hw, float hh)
-{
- if (hw == 0) return;
-
- set_inverted_drawing(1);
-
- glPushMatrix();
- glTranslatef(xofs, yofs, 0.0f);
- glScalef(1.0f, hh / hw, 1.0f);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, hw, 20);
- glPopMatrix();
-
- set_inverted_drawing(0);
-}
-
-#endif
-
-void fdrawXORcirc(float xofs, float yofs, float rad)
-{
- set_inverted_drawing(1);
-
- glPushMatrix();
- glTranslatef(xofs, yofs, 0.0);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, rad, 20);
- glPopMatrix();
-
- set_inverted_drawing(0);
-}
-
-void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments)
-{
- int i;
-
- glBegin(GL_TRIANGLE_FAN);
- glVertex2f(0.0, 0.0);
- for (i = 0; i < nsegments; i++) {
- float t = (float) i / (nsegments - 1);
- float cur = start + t * angle;
-
- glVertex2f(cosf(cur) * radius, sinf(cur) * radius);
- }
- glEnd();
-}
-
-void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments)
-{
- int i;
-
- glBegin(GL_LINE_STRIP);
- for (i = 0; i < nsegments; i++) {
- float t = (float) i / (nsegments - 1);
- float cur = start + t * angle;
-
- glVertex2f(cosf(cur) * radius, sinf(cur) * radius);
- }
- glEnd();
-}
-
float glaGetOneFloat(int param)
{
GLfloat v;
@@ -375,25 +137,68 @@ static int get_cached_work_texture(int *r_w, int *r_h)
return texid;
}
-void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
+static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state)
+{
+ GPUVertFormat *vert_format = immVertexFormat();
+ state->pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ state->texco = GPU_vertformat_attr_add(vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+}
+
+/* To be used before calling immDrawPixelsTex
+ * Default shader is GPU_SHADER_2D_IMAGE_COLOR
+ * You can still set uniforms with :
+ * GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);
+ * */
+IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
+{
+ IMMDrawPixelsTexState state;
+ immDrawPixelsTexSetupAttributes(&state);
+
+ state.shader = GPU_shader_get_builtin_shader(builtin);
+
+ /* Shader will be unbind by immUnbindProgram in immDrawPixelsTexScaled_clipping */
+ immBindBuiltinProgram(builtin);
+ immUniform1i("image", 0);
+ state.do_shader_unbind = true;
+
+ return state;
+}
+
+/* Use the currently bound shader.
+ *
+ * Use immDrawPixelsTexSetup to bind the shader you
+ * want before calling immDrawPixelsTex.
+ *
+ * If using a special shader double check it uses the same
+ * attributes "pos" "texCoord" and uniform "image".
+ *
+ * If color is NULL then use white by default
+ *
+ * Be also aware that this function unbinds the shader when
+ * it's finished.
+ * */
+void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
+ float x, float y, int img_w, int img_h,
int format, int type, int zoomfilter, void *rect,
float scaleX, float scaleY,
float clip_min_x, float clip_min_y,
- float clip_max_x, float clip_max_y)
+ float clip_max_x, float clip_max_y,
+ float xzoom, float yzoom, float color[4])
{
unsigned char *uc_rect = (unsigned char *) rect;
const float *f_rect = (float *)rect;
- float xzoom = glaGetOneFloat(GL_ZOOM_X), yzoom = glaGetOneFloat(GL_ZOOM_Y);
int subpart_x, subpart_y, tex_w, tex_h;
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
int texid = get_cached_work_texture(&tex_w, &tex_h);
int components;
const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y));
+ float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ GLint unpack_row_length;
+ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpack_row_length);
- /* Specify the color outside this function, and tex will modulate it.
- * This is useful for changing alpha without using glPixelTransferf()
- */
glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texid);
/* don't want nasty border artifacts */
@@ -401,12 +206,6 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter);
-#if defined(__APPLE__) && 0
- /* [merwin] disable this workaround and see if anyone is affected. If not scrap it! Also at end of this function */
- /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */
- glPixelZoom(1.0f, 1.0f);
-#endif
-
/* setup seamless 2=on, 0=off */
seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0;
@@ -420,7 +219,7 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
components = 4;
else if (format == GL_RGB)
components = 3;
- else if (ELEM(format, GL_LUMINANCE, GL_ALPHA))
+ else if (format == GL_RED)
components = 1;
else {
BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled");
@@ -429,20 +228,23 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
if (type == GL_FLOAT) {
/* need to set internal format to higher range float */
-
- /* NOTE: this could fail on some drivers, like mesa,
- * but currently this code is only used by color
- * management stuff which already checks on whether
- * it's possible to use GL_RGBA16F_ARB
- */
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
}
else {
/* switch to 8bit RGBA for byte buffer */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL);
}
+ unsigned int pos = state->pos, texco = state->texco;
+
+ /* optional */
+ /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
+ * it does not need color.
+ */
+ if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) {
+ immUniformColor4fv((color) ? color : white);
+ }
+
for (subpart_y = 0; subpart_y < nsubparts_y; subpart_y++) {
for (subpart_x = 0; subpart_x < nsubparts_x; subpart_x++) {
int remainder_x = img_w - subpart_x * offset_x;
@@ -494,325 +296,55 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
}
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
- glBegin(GL_QUADS);
- glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h);
- glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom);
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr2f(texco, (float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h);
+ immVertex2f(pos, rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom);
- glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h);
- glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom);
+ immAttr2f(texco, (float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h);
+ immVertex2f(pos, rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom);
- glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h);
- glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
+ immAttr2f(texco, (float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h);
+ immVertex2f(pos, rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
- glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h);
- glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
- glEnd();
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immAttr2f(texco, (float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h);
+ immVertex2f(pos, rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
+ immEnd();
}
}
- glBindTexture(GL_TEXTURE_2D, 0);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ if (state->do_shader_unbind) {
+ immUnbindProgram();
+ }
-#if defined(__APPLE__) && 0
- /* workaround for os x 10.5/10.6 driver bug (above) */
- glPixelZoom(xzoom, yzoom);
-#endif
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, unpack_row_length);
}
-void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h,
+void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
+ float x, float y, int img_w, int img_h,
int format, int type, int zoomfilter, void *rect,
- float scaleX, float scaleY)
+ float scaleX, float scaleY, float xzoom, float yzoom, float color[4])
{
- glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect,
- scaleX, scaleY, 0.0f, 0.0f, 0.0f, 0.0f);
+ immDrawPixelsTexScaled_clipping(state, x, y, img_w, img_h, format, type, zoomfilter, rect,
+ scaleX, scaleY, 0.0f, 0.0f, 0.0f, 0.0f, xzoom, yzoom, color);
}
-void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect)
+void immDrawPixelsTex(IMMDrawPixelsTexState *state,
+ float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect,
+ float xzoom, float yzoom, float color[4])
{
- glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f,
- 0.0f, 0.0f, 0.0f, 0.0f);
+ immDrawPixelsTexScaled_clipping(state, x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, xzoom, yzoom, color);
}
-void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h,
+void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
+ float x, float y, int img_w, int img_h,
int format, int type, int zoomfilter, void *rect,
- float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y)
-{
- glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f,
- clip_min_x, clip_min_y, clip_max_x, clip_max_y);
-}
-
-void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect)
-{
- float xzoom = glaGetOneFloat(GL_ZOOM_X);
- float yzoom = glaGetOneFloat(GL_ZOOM_Y);
-
- /* The pixel space coordinate of the intersection of
- * the [zoomed] image with the origin.
- */
- float ix = -x / xzoom;
- float iy = -y / yzoom;
-
- /* The maximum pixel amounts the image can be cropped
- * at the lower left without exceeding the origin.
- */
- int off_x = floor(max_ff(ix, 0.0f));
- int off_y = floor(max_ff(iy, 0.0f));
-
- /* The zoomed space coordinate of the raster position
- * (starting at the lower left most unclipped pixel).
- */
- float rast_x = x + off_x * xzoom;
- float rast_y = y + off_y * yzoom;
-
- GLfloat viewport[4];
- int draw_w, draw_h;
-
- /* Determine the smallest number of pixels we need to draw
- * before the image would go off the upper right corner.
- *
- * It may seem this is just an optimization but some graphics
- * cards (ATI) freak out if there is a large zoom factor and
- * a large number of pixels off the screen (probably at some
- * level the number of image pixels to draw is getting multiplied
- * by the zoom and then clamped). Making sure we draw the
- * fewest pixels possible keeps everyone mostly happy (still
- * fails if we zoom in on one really huge pixel so that it
- * covers the entire screen).
- */
- glGetFloatv(GL_VIEWPORT, viewport);
- draw_w = min_ii(img_w - off_x, ceil((viewport[2] - rast_x) / xzoom));
- draw_h = min_ii(img_h - off_y, ceil((viewport[3] - rast_y) / yzoom));
-
- if (draw_w > 0 && draw_h > 0) {
-
- int bound_options;
- GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
-
- /* Don't use safe RasterPos (slower) if we can avoid it. */
- if (rast_x >= 0 && rast_y >= 0) {
- glRasterPos2f(rast_x, rast_y);
- }
- else {
- glaRasterPosSafe2f(rast_x, rast_y, 0, 0);
- }
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, row_w);
- if (format == GL_LUMINANCE || format == GL_RED) {
- if (type == GL_FLOAT) {
- const float *f_rect = (float *)rect;
- glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y * row_w + off_x));
- }
- else if (type == GL_INT || type == GL_UNSIGNED_INT) {
- const int *i_rect = (int *)rect;
- glDrawPixels(draw_w, draw_h, format, type, i_rect + (off_y * row_w + off_x));
- }
- }
- else { /* RGBA */
- if (type == GL_FLOAT) {
- const float *f_rect = (float *)rect;
- glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y * row_w + off_x) * 4);
- }
- else if (type == GL_UNSIGNED_BYTE) {
- unsigned char *uc_rect = (unsigned char *) rect;
- glDrawPixels(draw_w, draw_h, format, type, uc_rect + (off_y * row_w + off_x) * 4);
- }
- }
-
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-
- GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
- }
-}
-
-/* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */
-void glaDrawPixelsAuto_clipping(float x, float y, int img_w, int img_h,
- int format, int type, int zoomfilter, void *rect,
- float clip_min_x, float clip_min_y,
- float clip_max_x, float clip_max_y)
-{
- if (U.image_draw_method != IMAGE_DRAW_METHOD_DRAWPIXELS) {
- glColor4f(1.0, 1.0, 1.0, 1.0);
- glaDrawPixelsTex_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect,
- clip_min_x, clip_min_y, clip_max_x, clip_max_y);
- }
- else {
- glaDrawPixelsSafe(x, y, img_w, img_h, img_w, format, type, rect);
- }
-}
-
-void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect)
-{
- glaDrawPixelsAuto_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect,
- 0.0f, 0.0f, 0.0f, 0.0f);
-}
-
-/* 2D Drawing Assistance */
-
-void glaDefine2DArea(rcti *screen_rect)
-{
- const int sc_w = BLI_rcti_size_x(screen_rect) + 1;
- const int sc_h = BLI_rcti_size_y(screen_rect) + 1;
-
- glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
- glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
-
- /* The GLA_PIXEL_OFS magic number is to shift the matrix so that
- * both raster and vertex integer coordinates fall at pixel
- * centers properly. For a longer discussion see the OpenGL
- * Programming Guide, Appendix H, Correctness Tips.
- */
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1);
- glTranslatef(GLA_PIXEL_OFS, GLA_PIXEL_OFS, 0.0);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-}
-
-#if 0 /* UNUSED */
-
-struct gla2DDrawInfo {
- int orig_vp[4], orig_sc[4];
- float orig_projmat[16], orig_viewmat[16];
-
- rcti screen_rect;
- rctf world_rect;
-
- float wo_to_sc[2];
-};
-
-void gla2DGetMap(gla2DDrawInfo *di, rctf *rect)
-{
- *rect = di->world_rect;
-}
-
-void gla2DSetMap(gla2DDrawInfo *di, rctf *rect)
-{
- int sc_w, sc_h;
- float wo_w, wo_h;
-
- di->world_rect = *rect;
-
- sc_w = BLI_rcti_size_x(&di->screen_rect);
- sc_h = BLI_rcti_size_y(&di->screen_rect);
- wo_w = BLI_rcti_size_x(&di->world_rect);
- wo_h = BLI_rcti_size_y(&di->world_rect);
-
- di->wo_to_sc[0] = sc_w / wo_w;
- di->wo_to_sc[1] = sc_h / wo_h;
-}
-
-/** Save the current OpenGL state and initialize OpenGL for 2D
- * rendering. glaEnd2DDraw should be called on the returned structure
- * to free it and to return OpenGL to its previous state. The
- * scissor rectangle is set to match the viewport.
- *
- * See glaDefine2DArea for an explanation of why this function uses integers.
- *
- * \param screen_rect The screen rectangle to be used for 2D drawing.
- * \param world_rect The world rectangle that the 2D area represented
- * by \a screen_rect is supposed to represent. If NULL it is assumed the
- * world has a 1 to 1 mapping to the screen.
- */
-gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect)
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y,
+ float xzoom, float yzoom, float color[4])
{
- gla2DDrawInfo *di = MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
- int sc_w, sc_h;
- float wo_w, wo_h;
-
- glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp);
- glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc);
- glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat);
- glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat);
-
- di->screen_rect = *screen_rect;
- if (world_rect) {
- di->world_rect = *world_rect;
- }
- else {
- di->world_rect.xmin = di->screen_rect.xmin;
- di->world_rect.ymin = di->screen_rect.ymin;
- di->world_rect.xmax = di->screen_rect.xmax;
- di->world_rect.ymax = di->screen_rect.ymax;
- }
-
- sc_w = BLI_rcti_size_x(&di->screen_rect);
- sc_h = BLI_rcti_size_y(&di->screen_rect);
- wo_w = BLI_rcti_size_x(&di->world_rect);
- wo_h = BLI_rcti_size_y(&di->world_rect);
-
- di->wo_to_sc[0] = sc_w / wo_w;
- di->wo_to_sc[1] = sc_h / wo_h;
-
- glaDefine2DArea(&di->screen_rect);
-
- return di;
-}
-
-/**
- * Translate the (\a wo_x, \a wo_y) point from world coordinates into screen space.
- */
-void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y)
-{
- *r_sc_x = (wo_x - di->world_rect.xmin) * di->wo_to_sc[0];
- *r_sc_y = (wo_y - di->world_rect.ymin) * di->wo_to_sc[1];
-}
-
-/**
- * Translate the \a world point from world coordinates into screen space.
- */
-void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2])
-{
- screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0];
- screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1];
-}
-
-/**
- * Restores the previous OpenGL state and frees the auxiliary gla data.
- */
-void glaEnd2DDraw(gla2DDrawInfo *di)
-{
- glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
- glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(di->orig_projmat);
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(di->orig_viewmat);
-
- MEM_freeN(di);
-}
-#endif
-
-
-/* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
-void bgl_get_mats(bglMats *mats)
-{
- const double badvalue = 1.0e-6;
-
- glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
- glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
- glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
-
- /* Very strange code here - it seems that certain bad values in the
- * modelview matrix can cause gluUnProject to give bad results. */
- if (mats->modelview[0] < badvalue &&
- mats->modelview[0] > -badvalue)
- {
- mats->modelview[0] = 0;
- }
- if (mats->modelview[5] < badvalue &&
- mats->modelview[5] > -badvalue)
- {
- mats->modelview[5] = 0;
- }
-
- /* Set up viewport so that gluUnProject will give correct values */
- mats->viewport[0] = 0;
- mats->viewport[1] = 0;
+ immDrawPixelsTexScaled_clipping(state, x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f,
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y, xzoom, yzoom, color);
}
/* *************** glPolygonOffset hack ************* */
@@ -831,8 +363,7 @@ void bglPolygonOffset(float viewdist, float dist)
// glPolygonOffset(-1.0, -1.0);
/* hack below is to mimic polygon offset */
- glMatrixMode(GL_PROJECTION);
- glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
+ GPU_matrix_projection_get(winmat);
/* dist is from camera to center point */
@@ -863,17 +394,13 @@ void bglPolygonOffset(float viewdist, float dist)
winmat[14] -= offs;
offset += offs;
-
- glLoadMatrixf(winmat);
- glMatrixMode(GL_MODELVIEW);
}
else {
- glMatrixMode(GL_PROJECTION);
winmat[14] += offset;
offset = 0.0;
- glLoadMatrixf(winmat);
- glMatrixMode(GL_MODELVIEW);
}
+
+ GPU_matrix_projection_set(winmat);
}
/* **** Color management helper functions for GLSL display/transform ***** */
@@ -883,7 +410,8 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter,
ColorManagedViewSettings *view_settings,
ColorManagedDisplaySettings *display_settings,
float clip_min_x, float clip_min_y,
- float clip_max_x, float clip_max_y)
+ float clip_max_x, float clip_max_y,
+ float zoom_x, float zoom_y)
{
bool force_fallback = false;
bool need_fallback = true;
@@ -902,6 +430,11 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter,
if (force_fallback == false) {
int ok;
+ IMMDrawPixelsTexState state = {0};
+ /* We want GLSL state to be fully handled by OCIO. */
+ state.do_shader_unbind = false;
+ immDrawPixelsTexSetupAttributes(&state);
+
if (ibuf->rect_float) {
if (ibuf->float_colorspace) {
ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings,
@@ -920,8 +453,6 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter,
}
if (ok) {
- glColor4f(1.0, 1.0, 1.0, 1.0);
-
if (ibuf->rect_float) {
int format = 0;
@@ -933,16 +464,20 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter,
BLI_assert(!"Incompatible number of channels for GLSL display");
if (format != 0) {
- glaDrawPixelsTex_clipping(x, y, ibuf->x, ibuf->y, format, GL_FLOAT,
+ immDrawPixelsTex_clipping(&state,
+ x, y, ibuf->x, ibuf->y, format, GL_FLOAT,
zoomfilter, ibuf->rect_float,
- clip_min_x, clip_min_y, clip_max_x, clip_max_y);
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y,
+ zoom_x, zoom_y, NULL);
}
}
else if (ibuf->rect) {
/* ibuf->rect is always RGBA */
- glaDrawPixelsTex_clipping(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
+ immDrawPixelsTex_clipping(&state,
+ x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
zoomfilter, ibuf->rect,
- clip_min_x, clip_min_y, clip_max_x, clip_max_y);
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y,
+ zoom_x, zoom_y, NULL);
}
IMB_colormanagement_finish_glsl_draw();
@@ -959,9 +494,12 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter,
display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);
if (display_buffer) {
- glaDrawPixelsAuto_clipping(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
- zoomfilter, display_buffer,
- clip_min_x, clip_min_y, clip_max_x, clip_max_y);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex_clipping(&state,
+ x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
+ zoomfilter, display_buffer,
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y,
+ zoom_x, zoom_y, NULL);
}
IMB_display_buffer_release(cache_handle);
@@ -970,10 +508,11 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter,
void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
ColorManagedViewSettings *view_settings,
- ColorManagedDisplaySettings *display_settings)
+ ColorManagedDisplaySettings *display_settings,
+ float zoom_x, float zoom_y)
{
glaDrawImBuf_glsl_clipping(ibuf, x, y, zoomfilter, view_settings, display_settings,
- 0.0f, 0.0f, 0.0f, 0.0f);
+ 0.0f, 0.0f, 0.0f, 0.0f, zoom_x, zoom_y);
}
void glaDrawImBuf_glsl_ctx_clipping(const bContext *C,
@@ -981,7 +520,8 @@ void glaDrawImBuf_glsl_ctx_clipping(const bContext *C,
float x, float y,
int zoomfilter,
float clip_min_x, float clip_min_y,
- float clip_max_x, float clip_max_y)
+ float clip_max_x, float clip_max_y,
+ float zoom_x, float zoom_y)
{
ColorManagedViewSettings *view_settings;
ColorManagedDisplaySettings *display_settings;
@@ -989,22 +529,19 @@ void glaDrawImBuf_glsl_ctx_clipping(const bContext *C,
IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
glaDrawImBuf_glsl_clipping(ibuf, x, y, zoomfilter, view_settings, display_settings,
- clip_min_x, clip_min_y, clip_max_x, clip_max_y);
-}
-
-void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter)
-{
- glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, zoomfilter, 0.0f, 0.0f, 0.0f, 0.0f);
+ clip_min_x, clip_min_y, clip_max_x, clip_max_y,
+ zoom_x, zoom_y);
}
-void cpack(unsigned int x)
+void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter,
+ float zoom_x, float zoom_y)
{
- glColor3ub(( (x) & 0xFF),
- (((x) >> 8) & 0xFF),
- (((x) >> 16) & 0xFF));
+ glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, zoomfilter, 0.0f, 0.0f, 0.0f, 0.0f, zoom_x, zoom_y);
}
-void glaDrawBorderCorners(const rcti *border, float zoomx, float zoomy)
+/* don't move to GPU_immediate_util.h because this uses user-prefs
+ * and isn't very low level */
+void immDrawBorderCorners(unsigned int pos, const rcti *border, float zoomx, float zoomy)
{
float delta_x = 4.0f * UI_DPI_FAC / zoomx;
float delta_y = 4.0f * UI_DPI_FAC / zoomy;
@@ -1013,30 +550,30 @@ void glaDrawBorderCorners(const rcti *border, float zoomx, float zoomy)
delta_y = min_ff(delta_y, border->ymax - border->ymin);
/* left bottom corner */
- glBegin(GL_LINE_STRIP);
- glVertex2f(border->xmin, border->ymin + delta_y);
- glVertex2f(border->xmin, border->ymin);
- glVertex2f(border->xmin + delta_x, border->ymin);
- glEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, border->xmin, border->ymin + delta_y);
+ immVertex2f(pos, border->xmin, border->ymin);
+ immVertex2f(pos, border->xmin + delta_x, border->ymin);
+ immEnd();
/* left top corner */
- glBegin(GL_LINE_STRIP);
- glVertex2f(border->xmin, border->ymax - delta_y);
- glVertex2f(border->xmin, border->ymax);
- glVertex2f(border->xmin + delta_x, border->ymax);
- glEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, border->xmin, border->ymax - delta_y);
+ immVertex2f(pos, border->xmin, border->ymax);
+ immVertex2f(pos, border->xmin + delta_x, border->ymax);
+ immEnd();
/* right bottom corner */
- glBegin(GL_LINE_STRIP);
- glVertex2f(border->xmax - delta_x, border->ymin);
- glVertex2f(border->xmax, border->ymin);
- glVertex2f(border->xmax, border->ymin + delta_y);
- glEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, border->xmax - delta_x, border->ymin);
+ immVertex2f(pos, border->xmax, border->ymin);
+ immVertex2f(pos, border->xmax, border->ymin + delta_y);
+ immEnd();
/* right top corner */
- glBegin(GL_LINE_STRIP);
- glVertex2f(border->xmax - delta_x, border->ymax);
- glVertex2f(border->xmax, border->ymax);
- glVertex2f(border->xmax, border->ymax - delta_y);
- glEnd();
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2f(pos, border->xmax - delta_x, border->ymax);
+ immVertex2f(pos, border->xmax, border->ymax);
+ immVertex2f(pos, border->xmax, border->ymax - delta_y);
+ immEnd();
}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index a61b71beff1..cb7d4f1fee9 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -30,83 +30,76 @@
#include <stdlib.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_utildefines.h"
-
+#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_paint.h"
+#include "BKE_main.h"
#include "BKE_gpencil.h"
+#include "BKE_layer.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "ED_armature.h"
#include "ED_gpencil.h"
#include "ED_anim_api.h"
+#include "ED_uvedit.h"
#include "WM_api.h"
#include "UI_interface.h"
#include "screen_intern.h"
-static unsigned int context_layers(bScreen *sc, Scene *scene, ScrArea *sa_ctx)
-{
- /* needed for 'USE_ALLSELECT' define, otherwise we end up editing off-screen layers. */
- if (sc && sa_ctx && (sa_ctx->spacetype == SPACE_BUTS)) {
- const unsigned int lay = BKE_screen_view3d_layer_all(sc);
- if (lay) {
- return lay;
- }
- }
- return scene->lay;
-}
-
const char *screen_context_dir[] = {
- "scene", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases",
+ "scene", "view_layer", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases",
"selected_objects", "selected_bases",
"editable_objects", "editable_bases",
"selected_editable_objects", "selected_editable_bases",
"visible_bones", "editable_bones", "selected_bones", "selected_editable_bones",
- "visible_pose_bones", "selected_pose_bones", "active_bone", "active_pose_bone",
+ "visible_pose_bones", "selected_pose_bones", "selected_pose_bones_from_active_object",
+ "active_bone", "active_pose_bone",
"active_base", "active_object", "object", "edit_object",
"sculpt_object", "vertex_paint_object", "weight_paint_object",
- "image_paint_object", "particle_edit_object",
+ "image_paint_object", "particle_edit_object", "uv_sculpt_object",
"sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */
"gpencil_data", "gpencil_data_owner", /* grease pencil data */
"visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes",
- "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_palette",
- "active_gpencil_palettecolor", "active_gpencil_brush",
+ "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_brush",
"active_operator", "selected_editable_fcurves",
NULL};
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
{
+ wmWindow *win = CTX_wm_window(C);
+ View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
bScreen *sc = CTX_wm_screen(C);
ScrArea *sa = CTX_wm_area(C);
- Scene *scene = sc->scene;
- Base *base;
-
-#if 0 /* Using the context breaks adding objects in the UI. Need to find out why - campbell */
- Object *obact = CTX_data_active_object(C);
- Object *obedit = CTX_data_edit_object(C);
- base = CTX_data_active_base(C);
-#else
- Object *obedit = scene->obedit;
- Object *obact = OBACT;
- base = BASACT;
-#endif
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL;
+ Object *obedit = view_layer ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL;
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
@@ -116,84 +109,136 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
CTX_data_id_pointer_set(result, &scene->id);
return 1;
}
- else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) {
- const unsigned int lay = context_layers(sc, scene, sa);
- 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)) {
- if (visible_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
+ else if (CTX_data_equals(member, "visible_objects")) {
+ FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, v3d, ob)
+ {
+ CTX_data_id_list_add(result, &ob->id);
+ }
+ FOREACH_VISIBLE_BASE_END;
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ else if (CTX_data_equals(member, "selectable_objects")) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (v3d && v3d->localvd && ((base->local_view_bits & v3d->local_view_uuid) == 0)) {
+ continue;
+ }
+ if (v3d && ((v3d->object_type_exclude_viewport & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ if (v3d && ((v3d->object_type_exclude_select & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ if (((base->flag & BASE_VISIBLE) != 0) && ((base->flag & BASE_SELECTABLE) != 0)) {
+ CTX_data_id_list_add(result, &base->object->id);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
- else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) {
- const unsigned int lay = context_layers(sc, scene, sa);
- const bool selectable_objects = CTX_data_equals(member, "selectable_objects");
-
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & lay) {
- if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0 && (base->object->restrictflag & OB_RESTRICT_SELECT) == 0) {
- if (selectable_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
- }
+ else if (CTX_data_equals(member, "selected_objects")) {
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, v3d, ob)
+ {
+ CTX_data_id_list_add(result, &ob->id);
+ }
+ FOREACH_SELECTED_OBJECT_END;
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ else if (CTX_data_equals(member, "selected_editable_objects")) {
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer, v3d, ob)
+ {
+ if (0 == BKE_object_is_libdata(ob)) {
+ CTX_data_id_list_add(result, &ob->id);
}
}
+ FOREACH_SELECTED_OBJECT_END;
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
- else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) {
- const unsigned int lay = context_layers(sc, scene, sa);
- 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)) {
- if (selected_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
+ else if (CTX_data_equals(member, "editable_objects")) {
+ /* Visible + Editable, but not necessarily selected */
+ FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, v3d, ob)
+ {
+ if (0 == BKE_object_is_libdata(ob)) {
+ CTX_data_id_list_add(result, &ob->id);
}
}
+ FOREACH_VISIBLE_OBJECT_END;
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
- 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);
- 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)) {
- if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) {
- if (0 == BKE_object_is_libdata(base->object)) {
- if (selected_editable_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
- }
+ else if ( CTX_data_equals(member, "visible_bases")) {
+ FOREACH_VISIBLE_BASE_BEGIN(view_layer, v3d, base)
+ {
+ CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
+ }
+ FOREACH_VISIBLE_BASE_END;
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ else if (CTX_data_equals(member, "selectable_bases")) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (v3d && v3d->localvd && ((base->local_view_bits & v3d->local_view_uuid) == 0)) {
+ continue;
+ }
+ if (v3d && ((v3d->object_type_exclude_viewport & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ if (v3d && ((v3d->object_type_exclude_select & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ if ((base->flag & BASE_VISIBLE) && (base->flag & BASE_SELECTABLE) != 0) {
+ CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
+ }
+ }
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ else if (CTX_data_equals(member, "selected_bases")) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (v3d && v3d->localvd && ((base->local_view_bits & v3d->local_view_uuid) == 0)) {
+ continue;
+ }
+ if (v3d && ((v3d->object_type_exclude_viewport & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ if ((base->flag & BASE_SELECTED) != 0) {
+ CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
+ }
+ }
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ else if (CTX_data_equals(member, "selected_editable_bases")) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (v3d && v3d->localvd && ((base->local_view_bits & v3d->local_view_uuid) == 0)) {
+ continue;
+ }
+ if (v3d && ((v3d->object_type_exclude_viewport & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ if ((base->flag & BASE_SELECTED) != 0) {
+ if (0 == BKE_object_is_libdata(base->object)) {
+ CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
}
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
- else if (CTX_data_equals(member, "editable_objects") || CTX_data_equals(member, "editable_bases")) {
- const unsigned int lay = context_layers(sc, scene, sa);
- const bool editable_objects = CTX_data_equals(member, "editable_objects");
-
+ else if (CTX_data_equals(member, "editable_bases")) {
/* Visible + Editable, but not necessarily selected */
- for (base = scene->base.first; base; base = base->next) {
- if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (v3d && v3d->localvd && ((base->local_view_bits & v3d->local_view_uuid) == 0)) {
+ continue;
+ }
+ if (v3d && ((v3d->object_type_exclude_viewport & (1 << base->object->type)) != 0)) {
+ continue;
+ }
+ if ((base->flag & BASE_VISIBLE) != 0) {
if (0 == BKE_object_is_libdata(base->object)) {
- if (editable_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
+ CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
}
}
}
@@ -206,38 +251,47 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
const bool editable_bones = CTX_data_equals(member, "editable_bones");
if (arm && arm->edbo) {
- /* Attention: X-Axis Mirroring is also handled here... */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* first and foremost, bone must be visible and selected */
- if (EBONE_VISIBLE(arm, ebone)) {
- /* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
- * so that most users of this data don't need to explicitly check for it themselves.
- *
- * We need to make sure that these mirrored copies are not selected, otherwise some
- * bones will be operated on twice.
- */
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
-
- /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
- if (editable_bones) {
- /* only selected + editable */
- if (EBONE_EDITABLE(ebone)) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ arm = ob->data;
+
+ /* Attention: X-Axis Mirroring is also handled here... */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* first and foremost, bone must be visible and selected */
+ if (EBONE_VISIBLE(arm, ebone)) {
+ /* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
+ * so that most users of this data don't need to explicitly check for it themselves.
+ *
+ * We need to make sure that these mirrored copies are not selected, otherwise some
+ * bones will be operated on twice.
+ */
+ if (arm->flag & ARM_MIRROR_EDIT)
+ flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+
+ /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
+ if (editable_bones) {
+ /* only selected + editable */
+ if (EBONE_EDITABLE(ebone)) {
+ CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
+
+ if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
+ CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
+ }
+ }
+ else {
+ /* only include bones if visible */
CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
- if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
+ if ((flipbone) && EBONE_VISIBLE(arm, flipbone) == 0)
CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
}
}
- else {
- /* only include bones if visible */
- CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
-
- if ((flipbone) && EBONE_VISIBLE(arm, flipbone) == 0)
- CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
- }
}
}
+ MEM_freeN(objects);
+
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
@@ -248,53 +302,65 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
const bool selected_editable_bones = CTX_data_equals(member, "selected_editable_bones");
if (arm && arm->edbo) {
- /* Attention: X-Axis Mirroring is also handled here... */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* first and foremost, bone must be visible and selected */
- if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_SELECTED)) {
- /* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
- * so that most users of this data don't need to explicitly check for it themselves.
- *
- * We need to make sure that these mirrored copies are not selected, otherwise some
- * bones will be operated on twice.
- */
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
-
- /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
- if (selected_editable_bones) {
- /* only selected + editable */
- if (EBONE_EDITABLE(ebone)) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ arm = ob->data;
+
+ /* Attention: X-Axis Mirroring is also handled here... */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* first and foremost, bone must be visible and selected */
+ if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_SELECTED)) {
+ /* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
+ * so that most users of this data don't need to explicitly check for it themselves.
+ *
+ * We need to make sure that these mirrored copies are not selected, otherwise some
+ * bones will be operated on twice.
+ */
+ if (arm->flag & ARM_MIRROR_EDIT)
+ flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+
+ /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
+ if (selected_editable_bones) {
+ /* only selected + editable */
+ if (EBONE_EDITABLE(ebone)) {
+ CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
+
+ if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
+ CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
+ }
+ }
+ else {
+ /* only include bones if selected */
CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
}
}
- else {
- /* only include bones if selected */
- CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
-
- if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
- CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
- }
}
}
+ MEM_freeN(objects);
+
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
}
else if (CTX_data_equals(member, "visible_pose_bones")) {
Object *obpose = BKE_object_pose_armature_get(obact);
- bArmature *arm = (obpose) ? obpose->data : NULL;
- bPoseChannel *pchan;
-
- if (obpose && obpose->pose && arm) {
- for (pchan = obpose->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
- if (PBONE_VISIBLE(arm, pchan->bone)) {
+ if (obpose && obpose->pose && obpose->data) {
+ if (obpose != obact) {
+ FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (obpose, pchan) {
CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
- }
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+ }
+ else if (obact->mode & OB_MODE_POSE) {
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob_iter) {
+ FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (ob_iter, pchan) {
+ CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
+ } FOREACH_PCHAN_VISIBLE_IN_OBJECT_END;
+ } FOREACH_OBJECT_IN_MODE_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
@@ -302,16 +368,35 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "selected_pose_bones")) {
Object *obpose = BKE_object_pose_armature_get(obact);
- bArmature *arm = (obpose) ? obpose->data : NULL;
- bPoseChannel *pchan;
-
- if (obpose && obpose->pose && arm) {
- for (pchan = obpose->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED)
- CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
- }
+ if (obpose && obpose->pose && obpose->data) {
+ if (obpose != obact) {
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (obpose, pchan) {
+ CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+ }
+ else if (obact->mode & OB_MODE_POSE) {
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_MODE_POSE, ob_iter) {
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
+ CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+ } FOREACH_OBJECT_IN_MODE_END;
+ }
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ }
+ else if (CTX_data_equals(member, "selected_pose_bones_from_active_object")) {
+ Object *obpose = BKE_object_pose_armature_get(obact);
+ if (obpose && obpose->pose && obpose->data) {
+ if (obpose != obact) {
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (obpose, pchan) {
+ CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+ }
+ else if (obact->mode & OB_MODE_POSE) {
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (obact, pchan) {
+ CTX_data_list_add(result, &obact->id, &RNA_PoseBone, pchan);
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
@@ -345,8 +430,8 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_base")) {
- if (base)
- CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, base);
+ if (view_layer->basact)
+ CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact);
return 1;
}
@@ -399,6 +484,23 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
+ else if (CTX_data_equals(member, "uv_sculpt_object")) {
+ /* TODO(campbell): most likely we change rules for uv_sculpt. */
+ if (obact && (obact->mode & OB_MODE_EDIT)) {
+ const ToolSettings *ts = scene->toolsettings;
+ if (ts->use_uv_sculpt) {
+ if (ED_uvedit_test(obedit)) {
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ if ((workspace->tools_space_type == SPACE_IMAGE) &&
+ (workspace->tools_mode == SI_MODE_UV))
+ {
+ CTX_data_id_pointer_set(result, &obact->id);
+ }
+ }
+ }
+ }
+ return 1;
+ }
else if (CTX_data_equals(member, "sequences")) {
Editing *ed = BKE_sequencer_editing_get(scene, false);
if (ed) {
@@ -441,7 +543,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
* (as outlined above - see Campbell's #ifdefs). That causes the get_active function to fail when
* called from context. For that reason, we end up using an alternative where we pass everything in!
*/
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
@@ -456,7 +558,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
PointerRNA ptr;
/* get pointer to Grease Pencil Data */
- gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, scene, sa, obact, &ptr);
+ gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, sa, scene, obact, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set(result, ptr.id.data, ptr.type, ptr.data);
@@ -465,7 +567,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "active_gpencil_layer")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
@@ -476,47 +578,17 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
}
- else if (CTX_data_equals(member, "active_gpencil_palette")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
-
- if (gpd) {
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
-
- if (palette) {
- CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPalette, palette);
- return 1;
- }
- }
- }
- else if (CTX_data_equals(member, "active_gpencil_palettecolor")) {
- /* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
-
- if (gpd) {
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
-
- if (palette) {
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
- if (palcolor) {
- CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPaletteColor, palcolor);
- return 1;
- }
- }
- }
- }
else if (CTX_data_equals(member, "active_gpencil_brush")) {
- /* XXX: see comment for gpencil_data case... */
- bGPDbrush *brush = BKE_gpencil_brush_getactive(scene->toolsettings);
+ Brush *brush = BKE_paint_brush(&scene->toolsettings->gp_paint->paint);
if (brush) {
- CTX_data_pointer_set(result, &scene->id, &RNA_GPencilBrush, brush);
+ CTX_data_pointer_set(result, &scene->id, &RNA_Brush, brush);
return 1;
}
}
else if (CTX_data_equals(member, "active_gpencil_frame")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
@@ -529,7 +601,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "visible_gpencil_layers")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -545,7 +617,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "editable_gpencil_layers")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -561,24 +633,37 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "editable_gpencil_strokes")) {
/* XXX: see comment for gpencil_data case... */
- bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
if (gpd) {
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
if (gpencil_layer_is_editable(gpl) && (gpl->actframe)) {
- bGPDframe *gpf = gpl->actframe;
+ bGPDframe *gpf;
bGPDstroke *gps;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+
+ CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
+ }
}
-
- CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
+ }
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
}
}
}
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 682a7a1f860..af6f9acfa47 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -22,24 +22,35 @@
* \ingroup edscr
*/
-#include "BIF_gl.h"
+#include "ED_screen.h"
+
+#include "GPU_batch_presets.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "BLI_math.h"
+#include "BLI_rect.h"
#include "WM_api.h"
+#include "WM_types.h"
-#include "ED_screen.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "screen_intern.h"
/**
* Draw horizontal shape visualizing future joining (left as well right direction of future joining).
*/
-static void draw_horizontal_join_shape(ScrArea *sa, char dir)
+static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos)
{
+ const float width = screen_geom_area_width(sa) - 1;
+ const float height = screen_geom_area_height(sa) - 1;
vec2f points[10];
short i;
float w, h;
- float width = sa->v3->vec.x - sa->v1->vec.x;
- float height = sa->v3->vec.y - sa->v1->vec.y;
if (height < width) {
h = height / 8;
@@ -90,30 +101,37 @@ static void draw_horizontal_join_shape(ScrArea *sa, char dir)
}
}
- glBegin(GL_POLYGON);
- for (i = 0; i < 5; i++)
- glVertex2f(points[i].x, points[i].y);
- glEnd();
- glBegin(GL_POLYGON);
- for (i = 4; i < 8; i++)
- glVertex2f(points[i].x, points[i].y);
- glVertex2f(points[0].x, points[0].y);
- glEnd();
-
- glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
- glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
+ immBegin(GPU_PRIM_TRI_FAN, 5);
+
+ for (i = 0; i < 5; i++) {
+ immVertex2f(pos, points[i].x, points[i].y);
+ }
+
+ immEnd();
+
+ immBegin(GPU_PRIM_TRI_FAN, 5);
+
+ for (i = 4; i < 8; i++) {
+ immVertex2f(pos, points[i].x, points[i].y);
+ }
+
+ immVertex2f(pos, points[0].x, points[0].y);
+ immEnd();
+
+ immRectf(pos, points[2].x, points[2].y, points[8].x, points[8].y);
+ immRectf(pos, points[6].x, points[6].y, points[9].x, points[9].y);
}
/**
* Draw vertical shape visualizing future joining (up/down direction).
*/
-static void draw_vertical_join_shape(ScrArea *sa, char dir)
+static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos)
{
+ const float width = screen_geom_area_width(sa) - 1;
+ const float height = screen_geom_area_height(sa) - 1;
vec2f points[10];
short i;
float w, h;
- float width = sa->v3->vec.x - sa->v1->vec.x;
- float height = sa->v3->vec.y - sa->v1->vec.y;
if (height < width) {
h = height / 4;
@@ -164,93 +182,186 @@ static void draw_vertical_join_shape(ScrArea *sa, char dir)
}
}
- glBegin(GL_POLYGON);
- for (i = 0; i < 5; i++)
- glVertex2f(points[i].x, points[i].y);
- glEnd();
- glBegin(GL_POLYGON);
- for (i = 4; i < 8; i++)
- glVertex2f(points[i].x, points[i].y);
- glVertex2f(points[0].x, points[0].y);
- glEnd();
-
- glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
- glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
+ immBegin(GPU_PRIM_TRI_FAN, 5);
+
+ for (i = 0; i < 5; i++) {
+ immVertex2f(pos, points[i].x, points[i].y);
+ }
+
+ immEnd();
+
+ immBegin(GPU_PRIM_TRI_FAN, 5);
+
+ for (i = 4; i < 8; i++) {
+ immVertex2f(pos, points[i].x, points[i].y);
+ }
+
+ immVertex2f(pos, points[0].x, points[0].y);
+ immEnd();
+
+ immRectf(pos, points[2].x, points[2].y, points[8].x, points[8].y);
+ immRectf(pos, points[6].x, points[6].y, points[9].x, points[9].y);
}
/**
* Draw join shape due to direction of joining.
*/
-static void draw_join_shape(ScrArea *sa, char dir)
+static void draw_join_shape(ScrArea *sa, char dir, unsigned int pos)
{
if (dir == 'u' || dir == 'd') {
- draw_vertical_join_shape(sa, dir);
+ draw_vertical_join_shape(sa, dir, pos);
}
else {
- draw_horizontal_join_shape(sa, dir);
+ draw_horizontal_join_shape(sa, dir, pos);
+ }
+}
+
+#define CORNER_RESOLUTION 9
+
+static void do_vert_pair(GPUVertBuf *vbo, uint pos, uint *vidx, int corner, int i)
+{
+ float inter[2], exter[2];
+ inter[0] = cosf(corner * M_PI_2 + (i * M_PI_2 / (CORNER_RESOLUTION - 1.0f)));
+ inter[1] = sinf(corner * M_PI_2 + (i * M_PI_2 / (CORNER_RESOLUTION - 1.0f)));
+
+ /* Snap point to edge */
+ float div = 1.0f / max_ff(fabsf(inter[0]), fabsf(inter[1]));
+ mul_v2_v2fl(exter, inter, div);
+ exter[0] = roundf(exter[0]);
+ exter[1] = roundf(exter[1]);
+
+ if (i == 0 || i == (CORNER_RESOLUTION - 1)) {
+ copy_v2_v2(inter, exter);
+ }
+
+ /* Line width is 20% of the entire corner size. */
+ const float line_width = 0.2f;
+ mul_v2_fl(inter, 1.0f - line_width);
+ mul_v2_fl(exter, 1.0f + line_width);
+
+ switch (corner) {
+ case 0:
+ add_v2_v2(inter, (float[2]){-1.0f, -1.0f});
+ add_v2_v2(exter, (float[2]){-1.0f, -1.0f});
+ break;
+ case 1:
+ add_v2_v2(inter, (float[2]){1.0f, -1.0f});
+ add_v2_v2(exter, (float[2]){1.0f, -1.0f});
+ break;
+ case 2:
+ add_v2_v2(inter, (float[2]){1.0f, 1.0f});
+ add_v2_v2(exter, (float[2]){1.0f, 1.0f});
+ break;
+ case 3:
+ add_v2_v2(inter, (float[2]){-1.0f, 1.0f});
+ add_v2_v2(exter, (float[2]){-1.0f, 1.0f});
+ break;
}
+
+ GPU_vertbuf_attr_set(vbo, pos, (*vidx)++, inter);
+ GPU_vertbuf_attr_set(vbo, pos, (*vidx)++, exter);
}
+static GPUBatch *batch_screen_edges_get(int *corner_len)
+{
+ static GPUBatch *screen_edges_batch = NULL;
+
+ if (screen_edges_batch == NULL) {
+ GPUVertFormat format = {0};
+ uint pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, CORNER_RESOLUTION * 2 * 4 * 8 + 2);
+
+ uint vidx = 0;
+ /* Note jitter is applied in the shader. */
+ for (int jit = 0; jit < 8; ++jit) {
+ for (int corner = 0; corner < 4; ++corner) {
+ for (int c = 0; c < CORNER_RESOLUTION; ++c) {
+ do_vert_pair(vbo, pos, &vidx, corner, c);
+ }
+ }
+ }
+ /* close the loop */
+ do_vert_pair(vbo, pos, &vidx, 0, 0);
+
+ screen_edges_batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ gpu_batch_presets_register(screen_edges_batch);
+ }
+
+ if (corner_len) {
+ *corner_len = CORNER_RESOLUTION * 2;
+ }
+ return screen_edges_batch;
+}
+
+#undef CORNER_RESOLUTION
+
/**
* Draw screen area darker with arrow (visualization of future joining).
*/
-static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
+static void scrarea_draw_shape_dark(ScrArea *sa, char dir, unsigned int pos)
{
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4ub(0, 0, 0, 50);
- draw_join_shape(sa, dir);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ immUniformColor4ub(0, 0, 0, 50);
+
+ draw_join_shape(sa, dir, pos);
}
/**
* Draw screen area ligher with arrow shape ("eraser" of previous dark shape).
*/
-static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir))
+static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir), unsigned int pos)
{
- glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
+ GPU_blend_set_func(GPU_DST_COLOR, GPU_SRC_ALPHA);
/* value 181 was hardly computed: 181~105 */
- glColor4ub(255, 255, 255, 50);
+ immUniformColor4ub(255, 255, 255, 50);
/* draw_join_shape(sa, dir); */
- glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
+
+ immRectf(pos, sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
}
-static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2)
+static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2, float edge_thickness)
{
+ rctf rect;
+ BLI_rctf_init(&rect, (float)x1, (float)x2, (float)y1, (float)y2);
+
/* right border area */
- if (x2 < sizex - 1) {
- glVertex2s(x2, y1);
- glVertex2s(x2, y2);
+ if (x2 >= sizex - 1) {
+ rect.xmax += edge_thickness * 0.5f;
}
/* left border area */
- if (x1 > 0) { /* otherwise it draws the emboss of window over */
- glVertex2s(x1, y1);
- glVertex2s(x1, y2);
+ if (x1 <= 0) { /* otherwise it draws the emboss of window over */
+ rect.xmin -= edge_thickness * 0.5f;
}
/* top border area */
- if (y2 < sizey - 1) {
- glVertex2s(x1, y2);
- glVertex2s(x2, y2);
+ if (y2 >= sizey - 1) {
+ rect.ymax += edge_thickness * 0.5f;
}
/* bottom border area */
- if (y1 > 0) {
- glVertex2s(x1, y1);
- glVertex2s(x2, y1);
+ if (y1 <= 0) {
+ rect.ymin -= edge_thickness * 0.5f;
}
+
+ GPUBatch *batch = batch_screen_edges_get(NULL);
+ GPU_batch_uniform_4fv(batch, "rect", (float *)&rect);
+ GPU_batch_draw(batch);
}
/**
* \brief Screen edges drawing.
*/
-static void drawscredge_area(ScrArea *sa, int sizex, int sizey)
+static void drawscredge_area(ScrArea *sa, int sizex, int sizey, float edge_thickness)
{
short x1 = sa->v1->vec.x;
short y1 = sa->v1->vec.y;
short x2 = sa->v3->vec.x;
short y2 = sa->v3->vec.y;
- drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2);
+ drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, edge_thickness);
}
/**
@@ -258,33 +369,64 @@ static void drawscredge_area(ScrArea *sa, int sizex, int sizey)
*/
void ED_screen_draw_edges(wmWindow *win)
{
+ bScreen *screen = WM_window_get_active_screen(win);
+ screen->do_draw = false;
+
+ if (screen->state == SCREENFULL) {
+ return;
+ }
+
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
+ float col[4], corner_scale, edge_thickness;
+ int verts_per_corner = 0;
ScrArea *sa;
- wmSubWindowSet(win, win->screen->mainwin);
-
- /* Note: first loop only draws if U.pixelsize > 1, skip otherwise */
- if (U.pixelsize > 1.0f) {
- /* FIXME: doesn't our glLineWidth already scale by U.pixelsize? */
- glLineWidth((2.0f * U.pixelsize) - 1);
- glColor3ub(0x50, 0x50, 0x50);
- glBegin(GL_LINES);
- for (sa = win->screen->areabase.first; sa; sa = sa->next)
- drawscredge_area(sa, winsize_x, winsize_y);
- glEnd();
+ rcti scissor_rect;
+ BLI_rcti_init_minmax(&scissor_rect);
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){sa->v1->vec.x, sa->v1->vec.y});
+ BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){sa->v3->vec.x, sa->v3->vec.y});
}
- glLineWidth(1);
- glColor3ub(0, 0, 0);
- glBegin(GL_LINES);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- drawscredge_area(sa, winsize_x, winsize_y);
+ GPU_scissor(scissor_rect.xmin,
+ scissor_rect.ymin,
+ BLI_rcti_size_x(&scissor_rect) + 1,
+ BLI_rcti_size_y(&scissor_rect) + 1);
+
+ glEnable(GL_SCISSOR_TEST);
+
+ UI_GetThemeColor4fv(TH_EDITOR_OUTLINE, col);
+ col[3] = 1.0f / 8.0f;
+ corner_scale = U.pixelsize * 8.0f;
+ edge_thickness = corner_scale * 0.21f;
+
+ GPU_blend(true);
+
+ /* Transparent pass (for AA). */
+ GPUBatch *batch = batch_screen_edges_get(&verts_per_corner);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES);
+ GPU_batch_uniform_1i(batch, "cornerLen", verts_per_corner);
+ GPU_batch_uniform_1f(batch, "scale", corner_scale);
+ GPU_batch_uniform_4fv(batch, "color", col);
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ drawscredge_area(sa, winsize_x, winsize_y, edge_thickness);
}
- glEnd();
- win->screen->do_draw = false;
+ GPU_blend(false);
+
+ /* Opaque pass. */
+ corner_scale -= 2.0f;
+ edge_thickness = corner_scale * 0.2f;
+ GPU_batch_uniform_1f(batch, "scale", corner_scale);
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ drawscredge_area(sa, winsize_x, winsize_y, edge_thickness);
+ }
+
+ glDisable(GL_SCISSOR_TEST);
}
/**
@@ -295,7 +437,10 @@ void ED_screen_draw_edges(wmWindow *win)
*/
void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2)
{
- glLineWidth(1);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_line_width(1);
/* blended join arrow */
int dir = area_getorientation(sa1, sa2);
@@ -319,36 +464,155 @@ void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2)
dira = 'd';
break;
}
- glEnable(GL_BLEND);
- scrarea_draw_shape_dark(sa2, dir);
- scrarea_draw_shape_light(sa1, dira);
- glDisable(GL_BLEND);
+
+ GPU_blend(true);
+
+ scrarea_draw_shape_dark(sa2, dir, pos);
+ scrarea_draw_shape_light(sa1, dira, pos);
+
+ GPU_blend(false);
}
+
+ immUnbindProgram();
}
void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* splitpoint */
- glEnable(GL_BLEND);
- glBegin(GL_LINES);
- glColor4ub(255, 255, 255, 100);
+ GPU_blend(true);
+ immUniformColor4ub(255, 255, 255, 100);
+
+ immBegin(GPU_PRIM_LINES, 2);
if (dir == 'h') {
const float y = (1 - fac) * sa->totrct.ymin + fac * sa->totrct.ymax;
- glVertex2s(sa->totrct.xmin, y);
- glVertex2s(sa->totrct.xmax, y);
- glColor4ub(0, 0, 0, 100);
- glVertex2s(sa->totrct.xmin, y + 1);
- glVertex2s(sa->totrct.xmax, y + 1);
+
+ immVertex2f(pos, sa->totrct.xmin, y);
+ immVertex2f(pos, sa->totrct.xmax, y);
+
+ immEnd();
+
+ immUniformColor4ub(0, 0, 0, 100);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ immVertex2f(pos, sa->totrct.xmin, y + 1);
+ immVertex2f(pos, sa->totrct.xmax, y + 1);
+
+ immEnd();
}
else {
+ BLI_assert(dir == 'v');
const float x = (1 - fac) * sa->totrct.xmin + fac * sa->totrct.xmax;
- glVertex2s(x, sa->totrct.ymin);
- glVertex2s(x, sa->totrct.ymax);
- glColor4ub(0, 0, 0, 100);
- glVertex2s(x + 1, sa->totrct.ymin);
- glVertex2s(x + 1, sa->totrct.ymax);
+
+ immVertex2f(pos, x, sa->totrct.ymin);
+ immVertex2f(pos, x, sa->totrct.ymax);
+
+ immEnd();
+
+ immUniformColor4ub(0, 0, 0, 100);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ immVertex2f(pos, x + 1, sa->totrct.ymin);
+ immVertex2f(pos, x + 1, sa->totrct.ymax);
+
+ immEnd();
}
- glEnd();
- glDisable(GL_BLEND);
+
+ GPU_blend(false);
+
+ immUnbindProgram();
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Screen Thumbnail Preview */
+
+/**
+ * Calculates a scale factor to squash the preview for \a screen into a rectangle of given size and aspect.
+ */
+static void screen_preview_scale_get(
+ const bScreen *screen, float size_x, float size_y,
+ const float asp[2],
+ float r_scale[2])
+{
+ float max_x = 0, max_y = 0;
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ max_x = MAX2(max_x, sa->totrct.xmax);
+ max_y = MAX2(max_y, sa->totrct.ymax);
+ }
+ r_scale[0] = (size_x * asp[0]) / max_x;
+ r_scale[1] = (size_y * asp[1]) / max_y;
+}
+
+static void screen_preview_draw_areas(const bScreen *screen, const float scale[2], const float col[4],
+ const float ofs_between_areas)
+{
+ const float ofs_h = ofs_between_areas * 0.5f;
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(col);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ rctf rect = {
+ .xmin = sa->totrct.xmin * scale[0] + ofs_h,
+ .xmax = sa->totrct.xmax * scale[0] - ofs_h,
+ .ymin = sa->totrct.ymin * scale[1] + ofs_h,
+ .ymax = sa->totrct.ymax * scale[1] - ofs_h
+ };
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immVertex2f(pos, rect.xmin, rect.ymin);
+ immVertex2f(pos, rect.xmax, rect.ymin);
+ immVertex2f(pos, rect.xmax, rect.ymax);
+ immVertex2f(pos, rect.xmin, rect.ymax);
+ immEnd();
+ }
+
+ immUnbindProgram();
+}
+
+static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
+{
+ const float asp[2] = {1.0f, 0.8f}; /* square previews look a bit ugly */
+ /* could use theme color (tui.wcol_menu_item.text), but then we'd need to regenerate all previews when changing */
+ const float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ float scale[2];
+
+ wmOrtho2(0.0f, size_x, 0.0f, size_y);
+ /* center */
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+ GPU_matrix_translate_2f(size_x * (1.0f - asp[0]) * 0.5f, size_y * (1.0f - asp[1]) * 0.5f);
+
+ screen_preview_scale_get(screen, size_x, size_y, asp, scale);
+ screen_preview_draw_areas(screen, scale, col, 1.5f);
+
+ GPU_matrix_pop();
+}
+
+/**
+ * Render the preview for a screen layout in \a screen.
+ */
+void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect)
+{
+ char err_out[256] = "unknown";
+ GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, true, false, err_out);
+
+ GPU_offscreen_bind(offscreen, true);
+ GPU_clear_color(0.0, 0.0, 0.0, 0.0);
+ GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT);
+
+ screen_preview_draw(screen, size_x, size_y);
+
+ GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, r_rect);
+ GPU_offscreen_unbind(offscreen, true);
+
+ GPU_offscreen_free(offscreen);
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 2e8c5204b3d..b4c639e51b6 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -33,7 +33,9 @@
#include "MEM_guardedalloc.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_userdef_types.h"
#include "BLI_math.h"
@@ -41,18 +43,17 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_image.h"
#include "BKE_global.h"
+#include "BKE_icons.h"
+#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -66,258 +67,39 @@
#include "UI_interface.h"
-/* XXX actually should be not here... solve later */
-#include "wm_subwindow.h"
-
-#include "screen_intern.h" /* own module include */
-
-
-/* ******************* screen vert, edge, area managing *********************** */
-
-static ScrVert *screen_addvert(bScreen *sc, short x, short y)
-{
- ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert");
- sv->vec.x = x;
- sv->vec.y = y;
-
- BLI_addtail(&sc->vertbase, sv);
- return sv;
-}
-
-static void sortscrvert(ScrVert **v1, ScrVert **v2)
-{
- ScrVert *tmp;
-
- if (*v1 > *v2) {
- tmp = *v1;
- *v1 = *v2;
- *v2 = tmp;
- }
-}
-
-static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
-{
- ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge");
-
- sortscrvert(&v1, &v2);
- se->v1 = v1;
- se->v2 = v2;
-
- BLI_addtail(&sc->edgebase, se);
- return se;
-}
-
-
-ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
-{
- ScrEdge *se;
-
- sortscrvert(&v1, &v2);
- for (se = sc->edgebase.first; se; se = se->next)
- if (se->v1 == v1 && se->v2 == v2)
- return se;
+#include "WM_message.h"
- return NULL;
-}
-
-void removedouble_scrverts(bScreen *sc)
-{
- ScrVert *v1, *verg;
- ScrEdge *se;
- ScrArea *sa;
-
- verg = sc->vertbase.first;
- while (verg) {
- if (verg->newv == NULL) { /* !!! */
- v1 = verg->next;
- while (v1) {
- if (v1->newv == NULL) { /* !?! */
- if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
- /* printf("doublevert\n"); */
- v1->newv = verg;
- }
- }
- v1 = v1->next;
- }
- }
- verg = verg->next;
- }
-
- /* replace pointers in edges and faces */
- se = sc->edgebase.first;
- while (se) {
- if (se->v1->newv) se->v1 = se->v1->newv;
- if (se->v2->newv) se->v2 = se->v2->newv;
- /* edges changed: so.... */
- sortscrvert(&(se->v1), &(se->v2));
- se = se->next;
- }
- sa = sc->areabase.first;
- while (sa) {
- if (sa->v1->newv) sa->v1 = sa->v1->newv;
- if (sa->v2->newv) sa->v2 = sa->v2->newv;
- if (sa->v3->newv) sa->v3 = sa->v3->newv;
- if (sa->v4->newv) sa->v4 = sa->v4->newv;
- sa = sa->next;
- }
-
- /* remove */
- verg = sc->vertbase.first;
- while (verg) {
- v1 = verg->next;
- if (verg->newv) {
- BLI_remlink(&sc->vertbase, verg);
- MEM_freeN(verg);
- }
- verg = v1;
- }
-
-}
-
-void removenotused_scrverts(bScreen *sc)
-{
- ScrVert *sv, *svn;
- ScrEdge *se;
-
- /* we assume edges are ok */
-
- se = sc->edgebase.first;
- while (se) {
- se->v1->flag = 1;
- se->v2->flag = 1;
- se = se->next;
- }
-
- sv = sc->vertbase.first;
- while (sv) {
- svn = sv->next;
- if (sv->flag == 0) {
- BLI_remlink(&sc->vertbase, sv);
- MEM_freeN(sv);
- }
- else {
- sv->flag = 0;
- }
- sv = svn;
- }
-}
-
-void removedouble_scredges(bScreen *sc)
-{
- ScrEdge *verg, *se, *sn;
-
- /* compare */
- verg = sc->edgebase.first;
- while (verg) {
- se = verg->next;
- while (se) {
- sn = se->next;
- if (verg->v1 == se->v1 && verg->v2 == se->v2) {
- BLI_remlink(&sc->edgebase, se);
- MEM_freeN(se);
- }
- se = sn;
- }
- verg = verg->next;
- }
-}
-
-void removenotused_scredges(bScreen *sc)
-{
- ScrEdge *se, *sen;
- ScrArea *sa;
- int a = 0;
-
- /* sets flags when edge is used in area */
- sa = sc->areabase.first;
- while (sa) {
- se = screen_findedge(sc, sa->v1, sa->v2);
- if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
- else se->flag = 1;
- se = screen_findedge(sc, sa->v2, sa->v3);
- if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
- else se->flag = 1;
- se = screen_findedge(sc, sa->v3, sa->v4);
- if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
- else se->flag = 1;
- se = screen_findedge(sc, sa->v4, sa->v1);
- if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
- else se->flag = 1;
- sa = sa->next;
- a++;
- }
- se = sc->edgebase.first;
- while (se) {
- sen = se->next;
- if (se->flag == 0) {
- BLI_remlink(&sc->edgebase, se);
- MEM_freeN(se);
- }
- else {
- se->flag = 0;
- }
- se = sen;
- }
-}
-
-bool scredge_is_horizontal(ScrEdge *se)
-{
- return (se->v1->vec.y == se->v2->vec.y);
-}
-
-/* need win size to make sure not to include edges along screen edge */
-ScrEdge *screen_find_active_scredge(bScreen *sc,
- const int winsize_x, const int winsize_y,
- const int mx, const int my)
-{
- ScrEdge *se;
- int safety = U.widget_unit / 10;
-
- if (safety < 2) safety = 2;
-
- for (se = sc->edgebase.first; se; se = se->next) {
- if (scredge_is_horizontal(se)) {
- if (se->v1->vec.y > 0 && se->v1->vec.y < winsize_y - 1) {
- short min, max;
- min = MIN2(se->v1->vec.x, se->v2->vec.x);
- max = MAX2(se->v1->vec.x, se->v2->vec.x);
-
- if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max)
- return se;
- }
- }
- else {
- if (se->v1->vec.x > 0 && se->v1->vec.x < winsize_x - 1) {
- short min, max;
- min = MIN2(se->v1->vec.y, se->v2->vec.y);
- max = MAX2(se->v1->vec.y, se->v2->vec.y);
-
- if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max)
- return se;
- }
- }
- }
-
- return NULL;
-}
+#include "DEG_depsgraph_query.h"
+#include "screen_intern.h" /* own module include */
/* adds no space data */
-static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
+static ScrArea *screen_addarea_ex(
+ ScrAreaMap *area_map,
+ ScrVert *bottom_left, ScrVert *top_left, ScrVert *top_right, ScrVert *bottom_right,
+ short spacetype)
{
ScrArea *sa = MEM_callocN(sizeof(ScrArea), "addscrarea");
- sa->v1 = v1;
- sa->v2 = v2;
- sa->v3 = v3;
- sa->v4 = v4;
- sa->headertype = headertype;
- sa->spacetype = sa->butspacetype = spacetype;
- BLI_addtail(&sc->areabase, sa);
+ sa->v1 = bottom_left;
+ sa->v2 = top_left;
+ sa->v3 = top_right;
+ sa->v4 = bottom_right;
+ sa->spacetype = spacetype;
+
+ BLI_addtail(&area_map->areabase, sa);
return sa;
}
+static ScrArea *screen_addarea(
+ bScreen *sc,
+ ScrVert *left_bottom, ScrVert *left_top, ScrVert *right_top, ScrVert *right_bottom,
+ short spacetype)
+{
+ return screen_addarea_ex(AREAMAP_FROM_SCREEN(sc), left_bottom, left_top, right_top, right_bottom,
+ spacetype);
+}
static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa)
{
@@ -330,54 +112,18 @@ static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa)
MEM_freeN(sa);
}
-/* return 0: no split possible */
-/* else return (integer) screencoordinate split point */
-static short testsplitpoint(ScrArea *sa, char dir, float fac)
-{
- short x, y;
- const short area_min_x = AREAMINX;
- const short area_min_y = ED_area_headersize();
-
- // area big enough?
- if (dir == 'v' && (sa->v4->vec.x - sa->v1->vec.x <= 2 * area_min_x)) return 0;
- if (dir == 'h' && (sa->v2->vec.y - sa->v1->vec.y <= 2 * area_min_y)) return 0;
-
- // to be sure
- CLAMP(fac, 0.0f, 1.0f);
-
- if (dir == 'h') {
- y = sa->v1->vec.y + fac * (sa->v2->vec.y - sa->v1->vec.y);
-
- if (y - sa->v1->vec.y < area_min_y)
- y = sa->v1->vec.y + area_min_y;
- else if (sa->v2->vec.y - y < area_min_y)
- y = sa->v2->vec.y - area_min_y;
- else y -= (y % AREAGRID);
-
- return y;
- }
- else {
- x = sa->v1->vec.x + fac * (sa->v4->vec.x - sa->v1->vec.x);
-
- if (x - sa->v1->vec.x < area_min_x)
- x = sa->v1->vec.x + area_min_x;
- else if (sa->v4->vec.x - x < area_min_x)
- x = sa->v4->vec.x - area_min_x;
- else x -= (x % AREAGRID);
-
- return x;
- }
-}
-
-ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
+ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
{
ScrArea *newa = NULL;
ScrVert *sv1, *sv2;
short split;
+ rcti window_rect;
if (sa == NULL) return NULL;
- split = testsplitpoint(sa, dir, fac);
+ WM_window_rect_calc(win, &window_rect);
+
+ split = screen_geom_find_area_split_point(sa, &window_rect, dir, fac);
if (split == 0) return NULL;
/* note regarding (fac > 0.5f) checks below.
@@ -386,19 +132,19 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
if (dir == 'h') {
/* new vertices */
- sv1 = screen_addvert(sc, sa->v1->vec.x, split);
- sv2 = screen_addvert(sc, sa->v4->vec.x, split);
+ sv1 = screen_geom_vertex_add(sc, sa->v1->vec.x, split);
+ sv2 = screen_geom_vertex_add(sc, sa->v4->vec.x, split);
/* new edges */
- screen_addedge(sc, sa->v1, sv1);
- screen_addedge(sc, sv1, sa->v2);
- screen_addedge(sc, sa->v3, sv2);
- screen_addedge(sc, sv2, sa->v4);
- screen_addedge(sc, sv1, sv2);
+ screen_geom_edge_add(sc, sa->v1, sv1);
+ screen_geom_edge_add(sc, sv1, sa->v2);
+ screen_geom_edge_add(sc, sa->v3, sv2);
+ screen_geom_edge_add(sc, sv2, sa->v4);
+ screen_geom_edge_add(sc, sv1, sv2);
if (fac > 0.5f) {
/* new areas: top */
- newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
+ newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->spacetype);
/* area below */
sa->v2 = sv1;
@@ -406,7 +152,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
}
else {
/* new areas: bottom */
- newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->headertype, sa->spacetype);
+ newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->spacetype);
/* area above */
sa->v1 = sv1;
@@ -418,19 +164,19 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
}
else {
/* new vertices */
- sv1 = screen_addvert(sc, split, sa->v1->vec.y);
- sv2 = screen_addvert(sc, split, sa->v2->vec.y);
+ sv1 = screen_geom_vertex_add(sc, split, sa->v1->vec.y);
+ sv2 = screen_geom_vertex_add(sc, split, sa->v2->vec.y);
/* new edges */
- screen_addedge(sc, sa->v1, sv1);
- screen_addedge(sc, sv1, sa->v4);
- screen_addedge(sc, sa->v2, sv2);
- screen_addedge(sc, sv2, sa->v3);
- screen_addedge(sc, sv1, sv2);
+ screen_geom_edge_add(sc, sa->v1, sv1);
+ screen_geom_edge_add(sc, sv1, sa->v4);
+ screen_geom_edge_add(sc, sa->v2, sv2);
+ screen_geom_edge_add(sc, sv2, sa->v3);
+ screen_geom_edge_add(sc, sv1, sv2);
if (fac > 0.5f) {
/* new areas: right */
- newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->headertype, sa->spacetype);
+ newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->spacetype);
/* area left */
sa->v3 = sv2;
@@ -438,7 +184,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
}
else {
/* new areas: left */
- newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
+ newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->spacetype);
/* area right */
sa->v1 = sv1;
@@ -450,46 +196,42 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
/* remove double vertices en edges */
if (merge)
- removedouble_scrverts(sc);
- removedouble_scredges(sc);
- removenotused_scredges(sc);
+ BKE_screen_remove_double_scrverts(sc);
+ BKE_screen_remove_double_scredges(sc);
+ BKE_screen_remove_unused_scredges(sc);
return newa;
}
-/* empty screen, with 1 dummy area without spacedata */
-/* uses window size */
-bScreen *ED_screen_add(Main *bmain, wmWindow *win, Scene *scene, const char *name)
+/**
+ * Empty screen, with 1 dummy area without spacedata. Uses window size.
+ */
+bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
bScreen *sc;
ScrVert *sv1, *sv2, *sv3, *sv4;
sc = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
- sc->scene = scene;
sc->do_refresh = true;
sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
- sc->winid = win->winid;
- sv1 = screen_addvert(sc, 0, 0);
- sv2 = screen_addvert(sc, 0, winsize_y - 1);
- sv3 = screen_addvert(sc, winsize_x - 1, winsize_y - 1);
- sv4 = screen_addvert(sc, winsize_x - 1, 0);
+ sv1 = screen_geom_vertex_add(sc, rect->xmin, rect->ymin);
+ sv2 = screen_geom_vertex_add(sc, rect->xmin, rect->ymax - 1);
+ sv3 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymax - 1);
+ sv4 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymin);
- screen_addedge(sc, sv1, sv2);
- screen_addedge(sc, sv2, sv3);
- screen_addedge(sc, sv3, sv4);
- screen_addedge(sc, sv4, sv1);
+ screen_geom_edge_add(sc, sv1, sv2);
+ screen_geom_edge_add(sc, sv2, sv3);
+ screen_geom_edge_add(sc, sv3, sv4);
+ screen_geom_edge_add(sc, sv4, sv1);
/* dummy type, no spacedata */
- screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_EMPTY);
+ screen_addarea(sc, sv1, sv2, sv3, sv4, SPACE_EMPTY);
return sc;
}
-static void screen_copy(bScreen *to, bScreen *from)
+void screen_data_copy(bScreen *to, bScreen *from)
{
ScrVert *s1, *s2;
ScrEdge *se;
@@ -498,6 +240,8 @@ static void screen_copy(bScreen *to, bScreen *from)
/* free contents of 'to', is from blenkernel screen.c */
BKE_screen_free(to);
+ to->flag = from->flag;
+
BLI_duplicatelist(&to->vertbase, &from->vertbase);
BLI_duplicatelist(&to->edgebase, &from->edgebase);
BLI_duplicatelist(&to->areabase, &from->areabase);
@@ -511,7 +255,7 @@ static void screen_copy(bScreen *to, bScreen *from)
for (se = to->edgebase.first; se; se = se->next) {
se->v1 = se->v1->newv;
se->v2 = se->v2->newv;
- sortscrvert(&(se->v1), &(se->v2));
+ BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
}
saf = from->areabase.first;
@@ -532,7 +276,16 @@ static void screen_copy(bScreen *to, bScreen *from)
/* put at zero (needed?) */
for (s1 = from->vertbase.first; s1; s1 = s1->next)
s1->newv = NULL;
+}
+/**
+ * Prepare a newly created screen for initializing it as active screen.
+ */
+void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
+{
+ screen_new->winid = win->winid;
+ screen_new->do_refresh = true;
+ screen_new->do_draw = true;
}
@@ -588,276 +341,53 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
if (dir == 0) {
sa1->v1 = sa2->v1;
sa1->v2 = sa2->v2;
- screen_addedge(scr, sa1->v2, sa1->v3);
- screen_addedge(scr, sa1->v1, sa1->v4);
+ screen_geom_edge_add(scr, sa1->v2, sa1->v3);
+ screen_geom_edge_add(scr, sa1->v1, sa1->v4);
}
else if (dir == 1) {
sa1->v2 = sa2->v2;
sa1->v3 = sa2->v3;
- screen_addedge(scr, sa1->v1, sa1->v2);
- screen_addedge(scr, sa1->v3, sa1->v4);
+ screen_geom_edge_add(scr, sa1->v1, sa1->v2);
+ screen_geom_edge_add(scr, sa1->v3, sa1->v4);
}
else if (dir == 2) {
sa1->v3 = sa2->v3;
sa1->v4 = sa2->v4;
- screen_addedge(scr, sa1->v2, sa1->v3);
- screen_addedge(scr, sa1->v1, sa1->v4);
+ screen_geom_edge_add(scr, sa1->v2, sa1->v3);
+ screen_geom_edge_add(scr, sa1->v1, sa1->v4);
}
else if (dir == 3) {
sa1->v1 = sa2->v1;
sa1->v4 = sa2->v4;
- screen_addedge(scr, sa1->v1, sa1->v2);
- screen_addedge(scr, sa1->v3, sa1->v4);
+ screen_geom_edge_add(scr, sa1->v1, sa1->v2);
+ screen_geom_edge_add(scr, sa1->v3, sa1->v4);
}
screen_delarea(C, scr, sa2);
- removedouble_scrverts(scr);
+ BKE_screen_remove_double_scrverts(scr);
+ /* Update preview thumbnail */
+ BKE_icon_changed(scr->id.icon_id);
return 1;
}
-void select_connected_scredge(bScreen *sc, ScrEdge *edge)
-{
- ScrEdge *se;
- ScrVert *sv;
- int oneselected;
- char dir;
-
- /* select connected, only in the right direction */
- /* 'dir' is the direction of EDGE */
-
- if (edge->v1->vec.x == edge->v2->vec.x) dir = 'v';
- else dir = 'h';
-
- sv = sc->vertbase.first;
- while (sv) {
- sv->flag = 0;
- sv = sv->next;
- }
-
- edge->v1->flag = 1;
- edge->v2->flag = 1;
-
- oneselected = 1;
- while (oneselected) {
- se = sc->edgebase.first;
- oneselected = 0;
- while (se) {
- if (se->v1->flag + se->v2->flag == 1) {
- if (dir == 'h') {
- if (se->v1->vec.y == se->v2->vec.y) {
- se->v1->flag = se->v2->flag = 1;
- oneselected = 1;
- }
- }
- if (dir == 'v') {
- if (se->v1->vec.x == se->v2->vec.x) {
- se->v1->flag = se->v2->flag = 1;
- oneselected = 1;
- }
- }
- }
- se = se->next;
- }
- }
-}
-
-/* test if screen vertices should be scaled */
-static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
-{
- /* clamp Y size of header sized areas when expanding windows
- * avoids annoying empty space around file menu */
-#define USE_HEADER_SIZE_CLAMP
-
- const int headery_init = ED_area_headersize();
- ScrVert *sv = NULL;
- ScrArea *sa;
- int winsize_x_prev, winsize_y_prev;
- float facx, facy, tempf, min[2], max[2];
-
- /* calculate size */
- min[0] = min[1] = 20000.0f;
- max[0] = max[1] = 0.0f;
-
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
- const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y};
- minmax_v2v2_v2(min, max, fv);
- }
-
- /* always make 0.0 left under */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
- sv->vec.x -= min[0];
- sv->vec.y -= min[1];
- }
-
- winsize_x_prev = (max[0] - min[0]) + 1;
- winsize_y_prev = (max[1] - min[1]) + 1;
-
-
-#ifdef USE_HEADER_SIZE_CLAMP
-#define TEMP_BOTTOM 1
-#define TEMP_TOP 2
-
- /* if the window's Y axis grows, clamp header sized areas */
- if (winsize_y_prev < winsize_y) { /* growing? */
- const int headery_margin_max = headery_init + 4;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
- sa->temp = 0;
-
- if (ar && !(ar->flag & RGN_FLAG_HIDDEN)) {
- if (sa->v2->vec.y == winsize_y_prev - 1) {
- if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) {
- sa->temp = TEMP_TOP;
- }
- }
- else if (sa->v1->vec.y == 0) {
- if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) {
- sa->temp = TEMP_BOTTOM;
- }
- }
- }
- }
- }
-#endif
-
-
- if (winsize_x_prev != winsize_x || winsize_y_prev != winsize_y) {
- facx = ((float)winsize_x - 1) / ((float)winsize_x_prev - 1);
- facy = ((float)winsize_y - 1) / ((float)winsize_y_prev - 1);
-
- /* make sure it fits! */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
- /* FIXME, this re-sizing logic is no good when re-sizing the window + redrawing [#24428]
- * need some way to store these as floats internally and re-apply from there. */
- tempf = ((float)sv->vec.x) * facx;
- sv->vec.x = (short)(tempf + 0.5f);
- //sv->vec.x += AREAGRID - 1;
- //sv->vec.x -= (sv->vec.x % AREAGRID);
-
- CLAMP(sv->vec.x, 0, winsize_x - 1);
-
- tempf = ((float)sv->vec.y) * facy;
- sv->vec.y = (short)(tempf + 0.5f);
- //sv->vec.y += AREAGRID - 1;
- //sv->vec.y -= (sv->vec.y % AREAGRID);
-
- CLAMP(sv->vec.y, 0, winsize_y - 1);
- }
- }
-
-
-#ifdef USE_HEADER_SIZE_CLAMP
- if (winsize_y_prev < winsize_y) { /* growing? */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- ScrEdge *se = NULL;
-
- if (sa->temp == 0)
- continue;
-
- if (sa->v1 == sa->v2)
- continue;
-
- /* adjust headery if verts are along the edge of window */
- if (sa->temp == TEMP_TOP) {
- /* lower edge */
- const int yval = sa->v2->vec.y - headery_init;
- se = screen_findedge(sc, sa->v4, sa->v1);
- if (se != NULL) {
- select_connected_scredge(sc, se);
- }
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
- if (sv != sa->v2 && sv != sa->v3) {
- if (sv->flag) {
- sv->vec.y = yval;
- }
- }
- }
- }
- else {
- /* upper edge */
- const int yval = sa->v1->vec.y + headery_init;
- se = screen_findedge(sc, sa->v2, sa->v3);
- if (se != NULL) {
- select_connected_scredge(sc, se);
- }
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
- if (sv != sa->v1 && sv != sa->v4) {
- if (sv->flag) {
- sv->vec.y = yval;
- }
- }
- }
- }
- }
- }
-
-#undef USE_HEADER_SIZE_CLAMP
-#undef TEMP_BOTTOM
-#undef TEMP_TOP
-#endif
-
-
- /* test for collapsed areas. This could happen in some blender version... */
- /* ton: removed option now, it needs Context... */
-
- /* make each window at least ED_area_headersize() high */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- int headery = headery_init;
-
- /* adjust headery if verts are along the edge of window */
- if (sa->v1->vec.y > 0)
- headery += U.pixelsize;
- if (sa->v2->vec.y < winsize_y - 1)
- headery += U.pixelsize;
-
- if (sa->v2->vec.y - sa->v1->vec.y + 1 < headery) {
- /* lower edge */
- ScrEdge *se = screen_findedge(sc, sa->v4, sa->v1);
- if (se && sa->v1 != sa->v2) {
- int yval;
-
- select_connected_scredge(sc, se);
-
- /* all selected vertices get the right offset */
- yval = sa->v2->vec.y - headery + 1;
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
- /* if is a collapsed area */
- if (sv != sa->v2 && sv != sa->v3) {
- if (sv->flag) {
- sv->vec.y = yval;
- }
- }
- }
- }
- }
- }
-
-}
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
-bScreen *ED_screen_duplicate(Main *bmain, wmWindow *win, bScreen *sc)
+/* screen sets cursor based on active region */
+static void region_cursor_set(wmWindow *win, bool swin_changed)
{
- bScreen *newsc;
-
- if (sc->state != SCREENNORMAL) return NULL; /* XXX handle this case! */
+ bScreen *screen = WM_window_get_active_screen(win);
- /* make new empty screen: */
- newsc = ED_screen_add(bmain, win, sc->scene, sc->id.name + 2);
- /* copy all data */
- screen_copy(newsc, sc);
-
- return newsc;
-}
-
-/* screen sets cursor based on swinid */
-static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
-{
- for (ScrArea *sa = win->screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, sa) {
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid == swinid) {
+ if (ar == screen->active_region) {
if (swin_changed || (ar->type && ar->type->event_cursor)) {
+ if (ar->gizmo_map != NULL) {
+ if (WM_gizmomap_cursor_set(ar->gizmo_map, win)) {
+ return;
+ }
+ }
ED_region_cursor_set(win, sa, ar);
}
return;
@@ -869,23 +399,24 @@ static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
void ED_screen_do_listen(bContext *C, wmNotifier *note)
{
wmWindow *win = CTX_wm_window(C);
+ bScreen *screen = CTX_wm_screen(C);
/* generic notes */
switch (note->category) {
case NC_WM:
if (note->data == ND_FILEREAD)
- win->screen->do_draw = true;
+ screen->do_draw = true;
break;
case NC_WINDOW:
- win->screen->do_draw = true;
+ screen->do_draw = true;
break;
case NC_SCREEN:
if (note->action == NA_EDITED)
- win->screen->do_draw = win->screen->do_refresh = true;
+ screen->do_draw = screen->do_refresh = true;
break;
case NC_SCENE:
if (note->data == ND_MODE)
- region_cursor_set(win, note->swinid, true);
+ region_cursor_set(win, true);
break;
}
}
@@ -906,48 +437,37 @@ static void screen_refresh_headersizes(void)
/* for file read and first use, for scaling window, area moves */
void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
{
+ bScreen *screen = WM_window_get_active_screen(win);
+
/* exception for bg mode, we only need the screen context */
if (!G.background) {
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
- ScrArea *sa;
- rcti winrct;
-
- winrct.xmin = 0;
- winrct.xmax = winsize_x - 1;
- winrct.ymin = 0;
- winrct.ymax = winsize_y - 1;
-
/* header size depends on DPI, let's verify */
WM_window_set_dpi(win);
- screen_refresh_headersizes();
- screen_test_scale(win->screen, winsize_x, winsize_y);
+ ED_screen_global_areas_refresh(win);
+ screen_refresh_headersizes();
- if (win->screen->mainwin == 0) {
- win->screen->mainwin = wm_subwindow_open(win, &winrct, false);
- }
- else {
- wm_subwindow_position(win, win->screen->mainwin, &winrct, false);
- }
+ screen_geom_vertices_scale(win, screen);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, area) {
/* set spacetype and region callbacks, calls init() */
/* sets subwindows for regions, adds handlers */
- ED_area_initialize(wm, win, sa);
+ ED_area_initialize(wm, win, area);
}
/* wake up animtimer */
- if (win->screen->animtimer)
- WM_event_timer_sleep(wm, win, win->screen->animtimer, false);
+ if (screen->animtimer)
+ WM_event_timer_sleep(wm, win, screen->animtimer, false);
}
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: set screen\n", __func__);
}
- win->screen->do_refresh = false;
+ screen->do_refresh = false;
+ /* prevent multiwin errors */
+ screen->winid = win->winid;
- win->screen->context = ed_screen_context;
+ screen->context = ed_screen_context;
}
/* file read, set all screens, ... */
@@ -956,10 +476,20 @@ void ED_screens_initialize(Main *bmain, wmWindowManager *wm)
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
+ if (BKE_workspace_active_get(win->workspace_hook) == NULL) {
+ BKE_workspace_active_set(win->workspace_hook, bmain->workspaces.first);
+ }
- if (win->screen == NULL)
- win->screen = bmain->screen.first;
+ ED_screen_refresh(wm, win);
+ if (win->eventstate) {
+ ED_screen_set_active_region(NULL, win, &win->eventstate->x);
+ }
+ }
+}
+void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *screen)
+{
+ if (screen->do_refresh) {
ED_screen_refresh(wm, win);
}
}
@@ -970,17 +500,17 @@ void ED_screens_initialize(Main *bmain, wmWindowManager *wm)
void ED_region_exit(bContext *C, ARegion *ar)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
ARegion *prevar = CTX_wm_region(C);
if (ar->type && ar->type->exit)
ar->type->exit(wm, ar);
CTX_wm_region_set(C, ar);
+
WM_event_remove_handlers(C, &ar->handlers);
- if (ar->swinid) {
- wm_subwindow_close(CTX_wm_window(C), ar->swinid);
- ar->swinid = 0;
- }
+ WM_event_modal_handler_region_replace(win, ar, NULL);
+ WM_draw_region_free(ar);
if (ar->headerstr) {
MEM_freeN(ar->headerstr);
@@ -988,16 +518,19 @@ void ED_region_exit(bContext *C, ARegion *ar)
}
if (ar->regiontimer) {
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ar->regiontimer);
+ WM_event_remove_timer(wm, win, ar->regiontimer);
ar->regiontimer = NULL;
}
+ WM_msgbus_clear_by_owner(wm->message_bus, ar);
+
CTX_wm_region_set(C, prevar);
}
void ED_area_exit(bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *ar;
@@ -1005,10 +538,13 @@ void ED_area_exit(bContext *C, ScrArea *sa)
sa->type->exit(wm, sa);
CTX_wm_area_set(C, sa);
+
for (ar = sa->regionbase.first; ar; ar = ar->next)
ED_region_exit(C, ar);
WM_event_remove_handlers(C, &sa->handlers);
+ WM_event_modal_handler_area_replace(win, sa, NULL);
+
CTX_wm_area_set(C, prevsa);
}
@@ -1016,8 +552,6 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *prevwin = CTX_wm_window(C);
- ScrArea *sa;
- ARegion *ar;
CTX_wm_window_set(C, window);
@@ -1026,21 +560,23 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
screen->animtimer = NULL;
screen->scrubbing = false;
- if (screen->mainwin)
- wm_subwindow_close(window, screen->mainwin);
- screen->mainwin = 0;
- screen->subwinactive = 0;
+ screen->active_region = NULL;
- for (ar = screen->regionbase.first; ar; ar = ar->next)
+ for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) {
ED_region_exit(C, ar);
-
- for (sa = screen->areabase.first; sa; sa = sa->next)
+ }
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ ED_area_exit(C, sa);
+ }
+ /* Don't use ED_screen_areas_iter here, it skips hidden areas. */
+ for (ScrArea *sa = window->global_areas.areabase.first; sa; sa = sa->next) {
ED_area_exit(C, sa);
+ }
/* mark it available for use for other windows */
screen->winid = 0;
- if (prevwin->screen->temp == 0) {
+ if (!WM_window_is_temp_screen(prevwin)) {
/* use previous window if possible */
CTX_wm_window_set(C, prevwin);
}
@@ -1054,16 +590,14 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
/* *********************************** */
/* case when on area-edge or in azones, or outside window */
-static void screen_cursor_set(wmWindow *win, const wmEvent *event)
+static void screen_cursor_set(wmWindow *win, const int xy[2])
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
+ const bScreen *screen = WM_window_get_active_screen(win);
AZone *az = NULL;
ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next)
- if ((az = ED_area_actionzone_find_xy(sa, &event->x)))
+ for (sa = screen->areabase.first; sa; sa = sa->next)
+ if ((az = ED_area_actionzone_find_xy(sa, xy)))
break;
if (sa) {
@@ -1077,10 +611,10 @@ static void screen_cursor_set(wmWindow *win, const wmEvent *event)
}
}
else {
- ScrEdge *actedge = screen_find_active_scredge(win->screen, winsize_x, winsize_y, event->x, event->y);
+ ScrEdge *actedge = screen_geom_find_active_scredge(win, screen, xy[0], xy[1]);
if (actedge) {
- if (scredge_is_horizontal(actedge))
+ if (screen_geom_edge_is_horizontal(actedge))
WM_cursor_set(win, CURSOR_Y_MOVE);
else
WM_cursor_set(win, CURSOR_X_MOVE);
@@ -1093,20 +627,20 @@ static void screen_cursor_set(wmWindow *win, const wmEvent *event)
/* called in wm_event_system.c. sets state vars in screen, cursors */
/* event type is mouse move */
-void ED_screen_set_subwinactive(bContext *C, const wmEvent *event)
+void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
{
- wmWindow *win = CTX_wm_window(C);
+ bScreen *scr = WM_window_get_active_screen(win);
- if (win->screen) {
- bScreen *scr = win->screen;
- ScrArea *sa;
+ if (scr) {
+ ScrArea *sa = NULL;
ARegion *ar;
- int oldswin = scr->subwinactive;
+ ARegion *old_ar = scr->active_region;
- for (sa = scr->areabase.first; sa; sa = sa->next) {
- if (event->x > sa->totrct.xmin && event->x < sa->totrct.xmax) {
- if (event->y > sa->totrct.ymin && event->y < sa->totrct.ymax) {
- if (NULL == ED_area_actionzone_refresh_xy(sa, &event->x)) {
+ ED_screen_areas_iter(win, scr, area_iter) {
+ if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) {
+ if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) {
+ if (ED_area_actionzone_refresh_xy(area_iter, xy) == NULL) {
+ sa = area_iter;
break;
}
}
@@ -1115,49 +649,55 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event)
if (sa) {
/* make overlap active when mouse over */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) {
- scr->subwinactive = ar->swinid;
+ if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) {
+ scr->active_region = ar;
break;
}
}
}
else
- scr->subwinactive = scr->mainwin;
+ scr->active_region = NULL;
/* check for redraw headers */
- if (oldswin != scr->subwinactive) {
+ if (old_ar != scr->active_region) {
- for (sa = scr->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, scr, area_iter) {
bool do_draw = false;
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->swinid == oldswin || ar->swinid == scr->subwinactive)
+ for (ar = area_iter->regionbase.first; ar; ar = ar->next) {
+ if (ar == old_ar || ar == scr->active_region) {
do_draw = true;
+ }
+ }
if (do_draw) {
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->regiontype == RGN_TYPE_HEADER)
- ED_region_tag_redraw(ar);
+ for (ar = area_iter->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_HEADER) {
+ ED_region_tag_redraw_no_rebuild(ar);
+ }
+ }
}
}
}
- /* cursors, for time being set always on edges, otherwise aregion doesnt switch */
- if (scr->subwinactive == scr->mainwin) {
- screen_cursor_set(win, event);
+ /* cursors, for time being set always on edges, otherwise aregion doesn't switch */
+ if (scr->active_region == NULL) {
+ screen_cursor_set(win, xy);
}
else {
/* notifier invokes freeing the buttons... causing a bit too much redraws */
- if (oldswin != scr->subwinactive) {
- region_cursor_set(win, scr->subwinactive, true);
+ if (old_ar != scr->active_region) {
+ region_cursor_set(win, true);
/* this used to be a notifier, but needs to be done immediate
* because it can undo setting the right button as active due
* to delayed notifier handling */
- UI_screen_free_active_but(C, win->screen);
+ if (C) {
+ UI_screen_free_active_but(C, scr);
+ }
}
else
- region_cursor_set(win, scr->subwinactive, false);
+ region_cursor_set(win, false);
}
}
}
@@ -1176,183 +716,261 @@ int ED_screen_area_active(const bContext *C)
return 1;
for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->swinid == sc->subwinactive)
+ if (ar == sc->active_region)
return 1;
}
return 0;
}
/**
- * operator call, WM + Window + screen already existed before
- *
- * \warning Do NOT call in area/region queues!
- * \returns success.
+ * Add an area and geometry (screen-edges and -vertices) for it to \a area_map,
+ * with coordinates/dimensions matching \a rect.
*/
-bool ED_screen_set(bContext *C, bScreen *sc)
+static ScrArea *screen_area_create_with_geometry(
+ ScrAreaMap *area_map, const rcti *rect,
+ short spacetype)
{
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- bScreen *oldscreen = CTX_wm_screen(C);
+ ScrVert *bottom_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymin);
+ ScrVert *top_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymax);
+ ScrVert *top_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymax);
+ ScrVert *bottom_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymin);
- /* validate screen, it's called with notifier reference */
- if (BLI_findindex(&bmain->screen, sc) == -1) {
- return true;
- }
+ screen_geom_edge_add_ex(area_map, bottom_left, top_left);
+ screen_geom_edge_add_ex(area_map, top_left, top_right);
+ screen_geom_edge_add_ex(area_map, top_right, bottom_right);
+ screen_geom_edge_add_ex(area_map, bottom_right, bottom_left);
- if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
- /* find associated full */
- bScreen *sc1;
- for (sc1 = bmain->screen.first; sc1; sc1 = sc1->id.next) {
- ScrArea *sa = sc1->areabase.first;
- if (sa->full == sc) {
- sc = sc1;
- break;
- }
+ return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype);
+}
+
+static void screen_area_set_geometry_rect(ScrArea *sa, const rcti *rect)
+{
+ sa->v1->vec.x = rect->xmin;
+ sa->v1->vec.y = rect->ymin;
+ sa->v2->vec.x = rect->xmin;
+ sa->v2->vec.y = rect->ymax;
+ sa->v3->vec.x = rect->xmax;
+ sa->v3->vec.y = rect->ymax;
+ sa->v4->vec.x = rect->xmax;
+ sa->v4->vec.y = rect->ymin;
+}
+
+static void screen_global_area_refresh(
+ wmWindow *win, bScreen *screen,
+ eSpace_Type space_type, GlobalAreaAlign align, const rcti *rect,
+ const short height_cur, const short height_min, const short height_max)
+{
+ ScrArea *area;
+
+ for (area = win->global_areas.areabase.first; area; area = area->next) {
+ if (area->spacetype == space_type) {
+ break;
}
}
- /* check for valid winid */
- if (sc->winid != 0 && sc->winid != win->winid) {
- return false;
+ if (area) {
+ screen_area_set_geometry_rect(area, rect);
}
+ else {
+ area = screen_area_create_with_geometry(&win->global_areas, rect, space_type);
+ SpaceType *stype = BKE_spacetype_from_id(space_type);
+ SpaceLink *slink = stype->new(area, WM_window_get_active_scene(win));
- if (oldscreen != sc) {
- wmTimer *wt = oldscreen->animtimer;
- ScrArea *sa;
- Scene *oldscene = oldscreen->scene;
+ area->regionbase = slink->regionbase;
- /* remove handlers referencing areas in old screen */
- for (sa = oldscreen->areabase.first; sa; sa = sa->next) {
- WM_event_remove_area_handler(&win->modalhandlers, sa);
- }
+ BLI_addhead(&area->spacedata, slink);
+ BLI_listbase_clear(&slink->regionbase);
- /* we put timer to sleep, so screen_exit has to think there's no timer */
- oldscreen->animtimer = NULL;
- if (wt) {
- WM_event_timer_sleep(wm, win, wt, true);
- }
+ /* Data specific to global areas. */
+ area->global = MEM_callocN(sizeof(*area->global), __func__);
+ area->global->size_max = height_max;
+ area->global->size_min = height_min;
+ area->global->align = align;
+ }
- ED_screen_exit(C, win, oldscreen);
+ if (area->global->cur_fixed_height != height_cur) {
+ /* Refresh layout if size changes. */
+ area->global->cur_fixed_height = height_cur;
+ screen->do_refresh = true;
+ }
+}
- /* Same scene, "transfer" playback to new screen. */
- if (wt) {
- if (oldscene == sc->scene) {
- sc->animtimer = wt;
+static void screen_global_topbar_area_refresh(wmWindow *win, bScreen *screen)
+{
+ const short size_min = HEADERY;
+ const short size_max = 2.25 * HEADERY;
+ const short size = (screen->flag & SCREEN_COLLAPSE_TOPBAR) ? size_min : size_max;
+ rcti rect;
+
+ BLI_rcti_init(&rect, 0, WM_window_pixels_x(win) - 1, 0, WM_window_pixels_y(win) - 1);
+ rect.ymin = rect.ymax - size_max;
+
+ screen_global_area_refresh(win, screen, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size, size_min, size_max);
+}
+
+static void screen_global_statusbar_area_refresh(wmWindow *win, bScreen *screen)
+{
+ const short size_min = 1;
+ const short size_max = 0.8f * HEADERY;
+ const short size = (screen->flag & SCREEN_COLLAPSE_STATUSBAR) ? size_min : size_max;
+ rcti rect;
+
+ BLI_rcti_init(&rect, 0, WM_window_pixels_x(win) - 1, 0, WM_window_pixels_y(win) - 1);
+ rect.ymax = rect.ymin + size_max;
+
+ screen_global_area_refresh(win, screen, SPACE_STATUSBAR, GLOBAL_AREA_ALIGN_BOTTOM, &rect, size, size_min, size_max);
+}
+
+void ED_screen_global_areas_sync(wmWindow *win)
+{
+ /* Update screen flags from height in window, this is weak and perhaps
+ * global areas should just become part of the screen instead. */
+ bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ screen->flag &= ~(SCREEN_COLLAPSE_STATUSBAR | SCREEN_COLLAPSE_TOPBAR);
+
+ for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ if (area->global->cur_fixed_height == area->global->size_min) {
+ if (area->spacetype == SPACE_TOPBAR) {
+ screen->flag |= SCREEN_COLLAPSE_TOPBAR;
}
- /* Else, stop playback. */
- else {
- oldscreen->animtimer = wt;
- ED_screen_animation_play(C, 0, 0);
+ else if (area->spacetype == SPACE_STATUSBAR) {
+ screen->flag |= SCREEN_COLLAPSE_STATUSBAR;
}
}
+ }
+}
- win->screen = sc;
- CTX_wm_window_set(C, win); // stores C->wm.screen... hrmf
-
- /* prevent multiwin errors */
- sc->winid = win->winid;
-
- ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENSET, sc);
-
- /* makes button hilites work */
- WM_event_add_mousemove(C);
-
- /* Needed to make sure all the derivedMeshes are
- * up-to-date before viewport starts acquiring this.
- *
- * This is needed in cases when, for example, boolean
- * modifier uses operant from invisible layer.
- * Without this trick boolean wouldn't apply correct.
- *
- * Quite the same happens when setting screen's scene,
- * so perhaps this is in fact correct thing to do.
- */
- if (oldscene != sc->scene) {
- BKE_scene_set_background(bmain, sc->scene);
+void ED_screen_global_areas_refresh(wmWindow *win)
+{
+ /* Don't create global area for child and temporary windows. */
+ bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ if ((win->parent != NULL) || screen->temp) {
+ if (win->global_areas.areabase.first) {
+ screen->do_refresh = true;
+ BKE_screen_area_map_free(&win->global_areas);
}
+ return;
+ }
+
+ screen_global_topbar_area_refresh(win, screen);
+ screen_global_statusbar_area_refresh(win, screen);
+}
- /* Always do visible update since it's possible new screen will
- * have different layers visible in 3D view-ports.
- * This is possible because of view3d.lock_camera_and_layers option.
- */
- DAG_on_visible_update(bmain, false);
+
+/* -------------------------------------------------------------------- */
+/* Screen changing */
+
+static bScreen *screen_fullscreen_find_associated_normal_screen(const Main *bmain, bScreen *screen)
+{
+ for (bScreen *screen_iter = bmain->screen.first; screen_iter; screen_iter = screen_iter->id.next) {
+ ScrArea *sa = screen_iter->areabase.first;
+ if (sa && sa->full == screen) {
+ return screen_iter;
+ }
}
- return true;
+ return screen;
}
-static bool ed_screen_used(wmWindowManager *wm, bScreen *sc)
+/**
+ * \return the screen to activate.
+ * \warning The returned screen may not always equal \a screen_new!
+ */
+bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
{
- wmWindow *win;
+ /* validate screen, it's called with notifier reference */
+ if (BLI_findindex(&bmain->screen, screen_new) == -1) {
+ return NULL;
+ }
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen == sc) {
- return true;
+ if (ELEM(screen_new->state, SCREENMAXIMIZED, SCREENFULL)) {
+ screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new);
+ }
+
+ /* check for valid winid */
+ if (!(screen_new->winid == 0 || screen_new->winid == win->winid)) {
+ return NULL;
+ }
+
+ if (screen_old != screen_new) {
+ wmTimer *wt = screen_old->animtimer;
+
+ /* remove handlers referencing areas in old screen */
+ for (ScrArea *sa = screen_old->areabase.first; sa; sa = sa->next) {
+ WM_event_remove_area_handler(&win->modalhandlers, sa);
}
- if (ELEM(win->screen->state, SCREENMAXIMIZED, SCREENFULL)) {
- ScrArea *sa = win->screen->areabase.first;
- if (sa->full == sc) {
- return true;
- }
+ /* we put timer to sleep, so screen_exit has to think there's no timer */
+ screen_old->animtimer = NULL;
+ if (wt) {
+ WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true);
+ }
+ ED_screen_exit(C, win, screen_old);
+
+ /* Same scene, "transfer" playback to new screen. */
+ if (wt) {
+ screen_new->animtimer = wt;
}
+
+ return screen_new;
}
- return false;
+ return NULL;
}
-/* only call outside of area/region loops */
-bool ED_screen_delete(bContext *C, bScreen *sc)
+void screen_change_update(bContext *C, wmWindow *win, bScreen *sc)
{
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- bScreen *newsc;
+ Scene *scene = WM_window_get_active_scene(win);
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
- /* don't allow deleting temp fullscreens for now */
- if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
- return false;
- }
+ CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
- /* screen can only be in use by one window at a time, so as
- * long as we are able to find a screen that is unused, we
- * can safely assume ours is not in use anywhere an delete it */
+ ED_screen_refresh(CTX_wm_manager(C), win);
- for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev)
- if (!ed_screen_used(wm, newsc) && !newsc->temp)
- break;
+ BKE_screen_view3d_scene_sync(sc, scene); /* sync new screen with scene data */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTSET, layout);
- if (!newsc) {
- for (newsc = sc->id.next; newsc; newsc = newsc->id.next)
- if (!ed_screen_used(wm, newsc) && !newsc->temp)
- break;
- }
+ /* makes button hilites work */
+ WM_event_add_mousemove(C);
+}
- if (!newsc) {
- return false;
- }
- ED_screen_set(C, newsc);
+/**
+ * \brief Change the active screen.
+ *
+ * Operator call, WM + Window + screen already existed before
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if screen changing was successful.
+ */
+bool ED_screen_change(bContext *C, bScreen *sc)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *screen_old = CTX_wm_screen(C);
+ bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win);
+
+ if (screen_new) {
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WM_window_set_active_screen(win, workspace, sc);
+ screen_change_update(C, win, screen_new);
- if (win->screen != sc) {
- BKE_libblock_free(bmain, sc);
return true;
}
- else {
- return false;
- }
+
+ return false;
}
-static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa, View3D *v3d)
+static void screen_set_3dview_camera(Scene *scene, ViewLayer *view_layer, ScrArea *sa, View3D *v3d)
{
/* fix any cameras that are used in the 3d view but not in the scene */
BKE_screen_view3d_sync(v3d, scene);
- if (!v3d->camera || !BKE_scene_base_find(scene, v3d->camera)) {
- v3d->camera = BKE_scene_camera_find(sc->scene);
+ if (!v3d->camera || !BKE_view_layer_base_find(view_layer, v3d->camera)) {
+ v3d->camera = BKE_view_layer_camera_find(view_layer);
// XXX if (sc == curscreen) handle_view3d_lock();
if (!v3d->camera) {
ARegion *ar;
@@ -1376,104 +994,49 @@ static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa,
}
}
-/* only call outside of area/region loops */
-void ED_screen_set_scene(bContext *C, bScreen *screen, Scene *scene)
+void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene)
{
- Main *bmain = CTX_data_main(C);
- bScreen *sc;
-
- if (screen == NULL)
- return;
+#if 0
+ ViewLayer *view_layer_old = WM_window_get_active_view_layer(win);
+#endif
- if (ed_screen_used(CTX_wm_manager(C), screen)) {
- ED_object_editmode_exit(C, EM_FREEDATA);
+ /* Switch scene. */
+ win->scene = scene;
+ if (CTX_wm_window(C) == win) {
+ CTX_data_scene_set(C, scene);
}
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- if ((U.flag & USER_SCENEGLOBAL) || sc == screen) {
-
- if (scene != sc->scene) {
- /* all areas endlocalview */
- // XXX ScrArea *sa = sc->areabase.first;
- // while (sa) {
- // endlocalview(sa);
- // sa = sa->next;
- // }
- sc->scene = scene;
- }
+ /* Ensure the view layer name is updated. */
+ WM_window_ensure_active_view_layer(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- }
+#if 0
+ /* Mode Syncing. */
+ if (view_layer_old) {
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ Object *obact_new = OBACT(view_layer);
+ UNUSED_VARS(obact_new);
+ eObjectMode object_mode_old = workspace->object_mode;
+ Object *obact_old = OBACT(view_layer_old);
+ UNUSED_VARS(obact_old, object_mode_old);
}
+#endif
- // copy_view3d_lock(0); /* space.c */
-
- /* are there cameras in the views that are not in the scene? */
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- if ((U.flag & USER_SCENEGLOBAL) || sc == screen) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl = sa->spacedata.first;
- while (sl) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
- ed_screen_set_3dview_camera(scene, sc, sa, v3d);
-
- }
- sl = sl->next;
- }
- sa = sa->next;
+ /* Update 3D view cameras. */
+ const bScreen *screen = WM_window_get_active_screen(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ screen_set_3dview_camera(scene, view_layer, sa, v3d);
}
}
}
-
- CTX_data_scene_set(C, scene);
- BKE_scene_set_background(bmain, scene);
- DAG_on_visible_update(bmain, false);
-
- ED_render_engine_changed(bmain);
- ED_update_for_newframe(bmain, scene, 1);
-
- /* complete redraw */
- WM_event_add_notifier(C, NC_WINDOW, NULL);
-
-}
-
-/**
- * \note Only call outside of area/region loops
- * \return true if successful
- */
-bool ED_screen_delete_scene(bContext *C, Scene *scene)
-{
- Main *bmain = CTX_data_main(C);
- Scene *newscene;
-
- /* kill running jobs */
- wmWindowManager *wm = CTX_wm_manager(C);
- WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_ANY);
-
- if (scene->id.prev)
- newscene = scene->id.prev;
- else if (scene->id.next)
- newscene = scene->id.next;
- else
- return false;
-
- ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
-
- BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
-
- id_us_clear_real(&scene->id);
- if (scene->id.us == 0) {
- BKE_libblock_free(bmain, scene);
- }
-
- return true;
}
ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *screen = CTX_wm_screen(C);
ScrArea *newsa = NULL;
if (!sa || sa->full == NULL) {
@@ -1481,18 +1044,7 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
}
if (!newsa) {
- if (sa->full && (screen->state == SCREENMAXIMIZED)) {
- /* if this has been called from the temporary info header generated in
- * temp fullscreen layouts, find the correct fullscreen area to change
- * to create a new space inside */
- for (newsa = screen->areabase.first; newsa; newsa = newsa->next) {
- if (!(sa->flag & AREA_TEMP_INFO))
- break;
- }
- }
- else {
- newsa = sa;
- }
+ newsa = sa;
}
BLI_assert(newsa);
@@ -1575,6 +1127,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
bScreen *sc, *oldscreen;
ARegion *ar;
@@ -1591,16 +1144,19 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
}
- /* prevent hanging header prints */
- ED_area_headerprint(sa, NULL);
+ /* prevent hanging status prints */
+ ED_area_status_text(sa, NULL);
+ ED_workspace_status_text(C, NULL);
}
if (sa && sa->full) {
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
/* restoring back to SCREENNORMAL */
sc = sa->full; /* the old screen to restore */
- oldscreen = win->screen; /* the one disappearing */
+ oldscreen = WM_window_get_active_screen(win); /* the one disappearing */
sc->state = SCREENNORMAL;
+ sc->flag = oldscreen->flag;
/* find old area to restore from */
ScrArea *fullsa = NULL;
@@ -1612,10 +1168,8 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
/* clear full screen state */
old->full = NULL;
- old->flag &= ~AREA_TEMP_INFO;
}
- sa->flag &= ~AREA_TEMP_INFO;
sa->full = NULL;
if (fullsa == NULL) {
@@ -1625,6 +1179,10 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
if (state == SCREENFULL) {
+ /* unhide global areas */
+ for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area; glob_area = glob_area->next) {
+ glob_area->global->flag &= ~GLOBAL_AREA_IS_HIDDEN;
+ }
/* restore the old side panels/header visibility */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
ar->flag = ar->flagfullscreen;
@@ -1637,9 +1195,9 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
sc->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
- ED_screen_set(C, sc);
+ ED_screen_change(C, sc);
- BKE_libblock_free(CTX_data_main(C), oldscreen);
+ BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
/* After we've restored back to SCREENNORMAL, we have to wait with
* screen handling as it uses the area coords which aren't updated yet.
@@ -1649,17 +1207,24 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
else {
/* change from SCREENNORMAL to new state */
+ WorkSpaceLayout *layout_new;
ScrArea *newa;
char newname[MAX_ID_NAME - 2];
- oldscreen = win->screen;
+ BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL));
+
+ oldscreen = WM_window_get_active_screen(win);
oldscreen->state = state;
BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
- sc = ED_screen_add(bmain, win, oldscreen->scene, newname);
+
+ layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
+
+ sc = BKE_workspace_layout_screen_get(layout_new);
sc->state = state;
sc->redraws_flag = oldscreen->redraws_flag;
sc->temp = oldscreen->temp;
+ sc->flag = oldscreen->flag;
/* timer */
sc->animtimer = oldscreen->animtimer;
@@ -1667,51 +1232,35 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
/* use random area when we have no active one, e.g. when the
* mouse is outside of the window and we open a file browser */
- if (!sa)
+ if (!sa || sa->global) {
sa = oldscreen->areabase.first;
-
- if (state == SCREENMAXIMIZED) {
- /* returns the top small area */
- newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
- ED_area_newspace(C, newa, SPACE_INFO, false);
-
- /* copy area */
- newa = newa->prev;
- ED_area_data_swap(newa, sa);
- sa->flag |= AREA_TEMP_INFO;
-
- sa->full = oldscreen;
- newa->full = oldscreen;
- newa->next->full = oldscreen; // XXX
}
- else if (state == SCREENFULL) {
- newa = (ScrArea *)sc->areabase.first;
- /* copy area */
- ED_area_data_swap(newa, sa);
- newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+ newa = (ScrArea *)sc->areabase.first;
+ /* copy area */
+ ED_area_data_swap(newa, sa);
+ newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+
+ if (state == SCREENFULL) {
+ /* temporarily hide global areas */
+ for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area; glob_area = glob_area->next) {
+ glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
+ }
/* temporarily hide the side panels/header */
for (ar = newa->regionbase.first; ar; ar = ar->next) {
ar->flagfullscreen = ar->flag;
- if (ELEM(ar->regiontype,
- RGN_TYPE_UI,
- RGN_TYPE_HEADER,
- RGN_TYPE_TOOLS))
- {
+ if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_HEADER, RGN_TYPE_TOOLS, RGN_TYPE_NAV_BAR)) {
ar->flag |= RGN_FLAG_HIDDEN;
}
}
-
- sa->full = oldscreen;
- newa->full = oldscreen;
- }
- else {
- BLI_assert(false);
}
- ED_screen_set(C, sc);
+ sa->full = oldscreen;
+ newa->full = oldscreen;
+
+ ED_screen_change(C, sc);
}
/* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
@@ -1798,7 +1347,7 @@ void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync,
if (sa)
spacetype = sa->spacetype;
- sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME));
+ sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA));
screen->animtimer->customdata = sad;
@@ -1846,13 +1395,10 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws, int refresh)
}
}
-/* results in fully updated anim system
- * screen can be NULL */
-void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
+/* results in fully updated anim system */
+void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
{
- wmWindowManager *wm = bmain->wm.first;
- wmWindow *window;
- int layers = 0;
+ Scene *scene = DEG_get_input_scene(depsgraph);
#ifdef DURIAN_CAMERA_SWITCH
void *camera = BKE_scene_camera_switch_find(scene);
@@ -1861,19 +1407,16 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
scene->camera = camera;
/* are there cameras in the views that are not in the scene? */
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
}
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
}
#endif
ED_clip_update_frame(bmain, scene->r.cfra);
- /* get layers from all windows */
- for (window = wm->windows.first; window; window = window->next)
- layers |= BKE_screen_visible_layers(window->screen, scene);
-
/* this function applies the changes too */
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, layers);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
/* composite */
if (scene->use_nodes && scene->nodetree)
@@ -1894,11 +1437,10 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
/*
* return true if any active area requires to see in 3D
*/
-bool ED_screen_stereo3d_required(bScreen *screen)
+bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
{
ScrArea *sa;
- Scene *sce = screen->scene;
- const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
for (sa = screen->areabase.first; sa; sa = sa->next) {
switch (sa->spacetype) {
@@ -1973,3 +1515,40 @@ bool ED_screen_stereo3d_required(bScreen *screen)
return false;
}
+
+/**
+ * Find the scene displayed in \a screen.
+ * \note Assumes \a screen to be visible/active!
+ */
+
+Scene *ED_screen_scene_find_with_window(const bScreen *screen, const wmWindowManager *wm, struct wmWindow **r_window)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ if (r_window) {
+ *r_window = win;
+ }
+ return WM_window_get_active_scene(win);
+ }
+ }
+
+ BLI_assert(0);
+ return NULL;
+}
+
+
+Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm)
+{
+ return ED_screen_scene_find_with_window(screen, wm, NULL);
+}
+
+
+wmWindow *ED_screen_window_find(const bScreen *screen, const wmWindowManager *wm)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return win;
+ }
+ }
+ return NULL;
+}
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
new file mode 100644
index 00000000000..5d87479e371
--- /dev/null
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -0,0 +1,462 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/screen/screen_geometry.c
+ * \ingroup edscr
+ * \brief Functions for screen vertices and edges
+ *
+ * Screen geometry refers to the vertices (ScrVert) and edges (ScrEdge) through
+ * which the flexible screen-layout system of Blender is established.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "BKE_screen.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "ED_screen.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_api.h"
+
+#include "screen_intern.h"
+
+
+int screen_geom_area_height(const ScrArea *area)
+{
+ return area->v2->vec.y - area->v1->vec.y + 1;
+}
+int screen_geom_area_width(const ScrArea *area)
+{
+ return area->v4->vec.x - area->v1->vec.x + 1;
+}
+
+ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y)
+{
+ ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert");
+ sv->vec.x = x;
+ sv->vec.y = y;
+
+ BLI_addtail(&area_map->vertbase, sv);
+ return sv;
+}
+ScrVert *screen_geom_vertex_add(bScreen *sc, short x, short y)
+{
+ return screen_geom_vertex_add_ex(AREAMAP_FROM_SCREEN(sc), x, y);
+}
+
+ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
+{
+ ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge");
+
+ BKE_screen_sort_scrvert(&v1, &v2);
+ se->v1 = v1;
+ se->v2 = v2;
+
+ BLI_addtail(&area_map->edgebase, se);
+ return se;
+}
+ScrEdge *screen_geom_edge_add(bScreen *sc, ScrVert *v1, ScrVert *v2)
+{
+ return screen_geom_edge_add_ex(AREAMAP_FROM_SCREEN(sc), v1, v2);
+}
+
+bool screen_geom_edge_is_horizontal(ScrEdge *se)
+{
+ return (se->v1->vec.y == se->v2->vec.y);
+}
+
+/**
+ * \param bounds_rect: Either window or screen bounds. Used to exclude edges along window/screen edges.
+ */
+ScrEdge *screen_geom_area_map_find_active_scredge(
+ const ScrAreaMap *area_map,
+ const rcti *bounds_rect,
+ const int mx, const int my)
+{
+ int safety = U.widget_unit / 10;
+
+ CLAMP_MIN(safety, 2);
+
+ for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) {
+ if (screen_geom_edge_is_horizontal(se)) {
+ if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) {
+ short min, max;
+ min = MIN2(se->v1->vec.x, se->v2->vec.x);
+ max = MAX2(se->v1->vec.x, se->v2->vec.x);
+
+ if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max)
+ return se;
+ }
+ }
+ else {
+ if ((se->v1->vec.x > bounds_rect->xmin) && (se->v1->vec.x < (bounds_rect->xmax - 1))) {
+ short min, max;
+ min = MIN2(se->v1->vec.y, se->v2->vec.y);
+ max = MAX2(se->v1->vec.y, se->v2->vec.y);
+
+ if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max)
+ return se;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* need win size to make sure not to include edges along screen edge */
+ScrEdge *screen_geom_find_active_scredge(
+ const wmWindow *win, const bScreen *screen,
+ const int mx, const int my)
+{
+ /* Use layout size (screen excluding global areas) for screen-layout area edges */
+ rcti screen_rect;
+ ScrEdge *se;
+
+ WM_window_screen_rect_calc(win, &screen_rect);
+ se = screen_geom_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(screen), &screen_rect, mx, my);
+
+ if (!se) {
+ /* Use entire window size (screen including global areas) for global area edges */
+ rcti win_rect;
+ WM_window_rect_calc(win, &win_rect);
+ se = screen_geom_area_map_find_active_scredge(&win->global_areas, &win_rect, mx, my);
+ }
+ return se;
+}
+
+/**
+ * \brief Main screen-layout calculation function.
+ *
+ * * Scale areas nicely on window size and DPI changes.
+ * * Ensure areas have a minimum height.
+ * * Correctly set global areas to their fixed height.
+ */
+void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
+{
+ /* clamp Y size of header sized areas when expanding windows
+ * avoids annoying empty space around file menu */
+#define USE_HEADER_SIZE_CLAMP
+
+ rcti window_rect, screen_rect;
+
+ WM_window_rect_calc(win, &window_rect);
+ WM_window_screen_rect_calc(win, &screen_rect);
+
+ const int headery_init = ED_area_headersize();
+ const int screen_size_x = BLI_rcti_size_x(&screen_rect);
+ const int screen_size_y = BLI_rcti_size_y(&screen_rect);
+ ScrVert *sv = NULL;
+ ScrArea *sa;
+ int screen_size_x_prev, screen_size_y_prev;
+ float min[2], max[2];
+
+ /* calculate size */
+ min[0] = min[1] = 20000.0f;
+ max[0] = max[1] = 0.0f;
+
+ for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y};
+ minmax_v2v2_v2(min, max, fv);
+ }
+
+ screen_size_x_prev = (max[0] - min[0]) + 1;
+ screen_size_y_prev = (max[1] - min[1]) + 1;
+
+
+#ifdef USE_HEADER_SIZE_CLAMP
+#define TEMP_BOTTOM 1
+#define TEMP_TOP 2
+
+ /* if the window's Y axis grows, clamp header sized areas */
+ if (screen_size_y_prev < screen_size_y) { /* growing? */
+ const int headery_margin_max = headery_init + 5;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ sa->temp = 0;
+
+ if (ar && !(ar->flag & RGN_FLAG_HIDDEN)) {
+ if (sa->v2->vec.y == max[1]) {
+ if (screen_geom_area_height(sa) < headery_margin_max) {
+ sa->temp = TEMP_TOP;
+ }
+ }
+ else if (sa->v1->vec.y == min[1]) {
+ if (screen_geom_area_height(sa) < headery_margin_max) {
+ sa->temp = TEMP_BOTTOM;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+
+ if (screen_size_x_prev != screen_size_x || screen_size_y_prev != screen_size_y) {
+ const float facx = ((float)screen_size_x - 1) / ((float)screen_size_x_prev - 1);
+ const float facy = ((float)screen_size_y - 1) / ((float)screen_size_y_prev - 1);
+
+ /* make sure it fits! */
+ for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ sv->vec.x = screen_rect.xmin + round_fl_to_short((sv->vec.x - min[0]) * facx);
+ CLAMP(sv->vec.x, screen_rect.xmin, screen_rect.xmax - 1);
+
+ sv->vec.y = screen_rect.ymin + round_fl_to_short((sv->vec.y - min[1]) * facy);
+ CLAMP(sv->vec.y, screen_rect.ymin, screen_rect.ymax - 1);
+ }
+ }
+
+
+#ifdef USE_HEADER_SIZE_CLAMP
+ if (screen_size_y_prev < screen_size_y) { /* growing? */
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ ScrEdge *se = NULL;
+
+ if (sa->temp == 0)
+ continue;
+
+ if (sa->v1 == sa->v2)
+ continue;
+
+ /* adjust headery if verts are along the edge of window */
+ if (sa->temp == TEMP_TOP) {
+ /* lower edge */
+ const int yval = sa->v2->vec.y - headery_init;
+ se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
+ if (se != NULL) {
+ screen_geom_select_connected_edge(win, se);
+ }
+ for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ if (sv != sa->v2 && sv != sa->v3) {
+ if (sv->flag) {
+ sv->vec.y = yval;
+ }
+ }
+ }
+ }
+ else {
+ /* upper edge */
+ const int yval = sa->v1->vec.y + headery_init;
+ se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ if (se != NULL) {
+ screen_geom_select_connected_edge(win, se);
+ }
+ for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ if (sv != sa->v1 && sv != sa->v4) {
+ if (sv->flag) {
+ sv->vec.y = yval;
+ }
+ }
+ }
+ }
+ }
+ }
+
+#undef USE_HEADER_SIZE_CLAMP
+#undef TEMP_BOTTOM
+#undef TEMP_TOP
+#endif
+
+
+ /* test for collapsed areas. This could happen in some blender version... */
+ /* ton: removed option now, it needs Context... */
+
+ /* make each window at least ED_area_headersize() high */
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ int headery = headery_init;
+
+ /* adjust headery if verts are along the edge of window */
+ if (sa->v1->vec.y > window_rect.ymin)
+ headery += U.pixelsize;
+ if (sa->v2->vec.y < (window_rect.ymax - 1))
+ headery += U.pixelsize;
+
+ if (screen_geom_area_height(sa) < headery) {
+ /* lower edge */
+ ScrEdge *se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
+ if (se && sa->v1 != sa->v2) {
+ const int yval = sa->v2->vec.y - headery + 1;
+
+ screen_geom_select_connected_edge(win, se);
+
+ /* all selected vertices get the right offset */
+ for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ /* if is a collapsed area */
+ if (sv != sa->v2 && sv != sa->v3) {
+ if (sv->flag) {
+ sv->vec.y = yval;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Global areas have a fixed size that only changes with the DPI. Here we ensure that exactly this size is set. */
+ for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
+ continue;
+ }
+
+ int height = ED_area_global_size_y(area) - 1;
+
+ if (area->v1->vec.y > window_rect.ymin) {
+ height += U.pixelsize;
+ }
+ if (area->v2->vec.y < (window_rect.ymax - 1)) {
+ height += U.pixelsize;
+ }
+
+ /* width */
+ area->v1->vec.x = area->v2->vec.x = window_rect.xmin;
+ area->v3->vec.x = area->v4->vec.x = window_rect.xmax - 1;
+ /* height */
+ area->v1->vec.y = area->v4->vec.y = window_rect.ymin;
+ area->v2->vec.y = area->v3->vec.y = window_rect.ymax - 1;
+
+ switch (area->global->align) {
+ case GLOBAL_AREA_ALIGN_TOP:
+ area->v1->vec.y = area->v4->vec.y = area->v2->vec.y - height;
+ break;
+ case GLOBAL_AREA_ALIGN_BOTTOM:
+ area->v2->vec.y = area->v3->vec.y = area->v1->vec.y + height;
+ break;
+ }
+ }
+}
+
+/**
+ * \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
+ */
+short screen_geom_find_area_split_point(const ScrArea *sa, const rcti *window_rect, char dir, float fac)
+{
+ short x, y;
+ const int cur_area_width = screen_geom_area_width(sa);
+ const int cur_area_height = screen_geom_area_height(sa);
+ const short area_min_x = AREAMINX;
+ const short area_min_y = ED_area_headersize();
+ int area_min;
+
+ // area big enough?
+ if ((dir == 'v') && (cur_area_width <= 2 * area_min_x)) {
+ return 0;
+ }
+ if ((dir == 'h') && (cur_area_height <= 2 * area_min_y)) {
+ return 0;
+ }
+
+ // to be sure
+ CLAMP(fac, 0.0f, 1.0f);
+
+ if (dir == 'h') {
+ y = sa->v1->vec.y + round_fl_to_short(fac * cur_area_height);
+
+ area_min = area_min_y;
+
+ if (sa->v1->vec.y > window_rect->ymin) {
+ area_min += U.pixelsize;
+ }
+ if (sa->v2->vec.y < (window_rect->ymax - 1)) {
+ area_min += U.pixelsize;
+ }
+
+ if (y - sa->v1->vec.y < area_min) {
+ y = sa->v1->vec.y + area_min;
+ }
+ else if (sa->v2->vec.y - y < area_min) {
+ y = sa->v2->vec.y - area_min;
+ }
+
+ return y;
+ }
+ else {
+ x = sa->v1->vec.x + round_fl_to_short(fac * cur_area_width);
+
+ area_min = area_min_x;
+
+ if (sa->v1->vec.x > window_rect->xmin) {
+ area_min += U.pixelsize;
+ }
+ if (sa->v4->vec.x < (window_rect->xmax - 1)) {
+ area_min += U.pixelsize;
+ }
+
+ if (x - sa->v1->vec.x < area_min) {
+ x = sa->v1->vec.x + area_min;
+ }
+ else if (sa->v4->vec.x - x < area_min) {
+ x = sa->v4->vec.x - area_min;
+ }
+
+ return x;
+ }
+}
+
+/**
+ * Select all edges that are directly or indirectly connected to \a edge.
+ */
+void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
+{
+ bScreen *sc = WM_window_get_active_screen(win);
+ bool oneselected = true;
+ char dir;
+
+ /* select connected, only in the right direction */
+ /* 'dir' is the direction of EDGE */
+
+ if (edge->v1->vec.x == edge->v2->vec.x) {
+ dir = 'v';
+ }
+ else {
+ dir = 'h';
+ }
+
+ ED_screen_verts_iter(win, sc, sv) {
+ sv->flag = 0;
+ }
+
+ edge->v1->flag = 1;
+ edge->v2->flag = 1;
+
+ while (oneselected) {
+ oneselected = false;
+ for (ScrEdge *se = sc->edgebase.first; se; se = se->next) {
+ if (se->v1->flag + se->v2->flag == 1) {
+ if (dir == 'h') {
+ if (se->v1->vec.y == se->v2->vec.y) {
+ se->v1->flag = se->v2->flag = 1;
+ oneselected = true;
+ }
+ }
+ if (dir == 'v') {
+ if (se->v1->vec.x == se->v2->vec.x) {
+ se->v1->flag = se->v2->flag = 1;
+ oneselected = true;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index a7cd9713973..9f845bf04ba 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -33,37 +33,53 @@
struct bContext;
struct bContextDataResult;
+struct Main;
/* internal exports only */
-#define AZONESPOT (0.6f * U.widget_unit)
+#define AZONESPOT (0.8f * U.widget_unit)
#define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */
#define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the azone */
/* area.c */
void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free);
void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2);
-void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade);
+void screen_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area);
+void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade);
/* screen_edit.c */
-ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2);
-ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge);
+bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
+void screen_data_copy(bScreen *to, bScreen *from);
+void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
+void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc);
+bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, struct Main *bmain, struct bContext *C, wmWindow *win);
+ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge);
int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2);
int area_getorientation(ScrArea *sa, ScrArea *sb);
-void select_connected_scredge(bScreen *sc, ScrEdge *edge);
-
-void removenotused_scrverts(bScreen *sc);
-void removedouble_scrverts(bScreen *sc);
-void removedouble_scredges(bScreen *sc);
-void removenotused_scredges(bScreen *sc);
-bool scredge_is_horizontal(ScrEdge *se);
-ScrEdge *screen_find_active_scredge(bScreen *sc,
- const int winsize_x, const int winsize_y,
- const int mx, const int my);
struct AZone *ED_area_actionzone_find_xy(ScrArea *sa, const int xy[2]);
struct AZone *ED_area_actionzone_refresh_xy(ScrArea *sa, const int xy[2]);
+/* screen_geometry.c */
+int screen_geom_area_height(const ScrArea *area);
+int screen_geom_area_width(const ScrArea *area);
+ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y);
+ScrVert *screen_geom_vertex_add(bScreen *sc, short x, short y);
+ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2);
+ScrEdge *screen_geom_edge_add(bScreen *sc, ScrVert *v1, ScrVert *v2);
+bool screen_geom_edge_is_horizontal(ScrEdge *se);
+ScrEdge *screen_geom_area_map_find_active_scredge(
+ const struct ScrAreaMap *area_map,
+ const rcti *bounds_rect,
+ const int mx, const int my);
+ScrEdge *screen_geom_find_active_scredge(
+ const wmWindow *win, const bScreen *screen,
+ const int mx, const int my);
+void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc);
+short screen_geom_find_area_split_point(const ScrArea *sa, const rcti *window_rect, char dir, float fac);
+void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge);
+
+
/* screen_context.c */
int ed_screen_context(
const struct bContext *C, const char *member, struct bContextDataResult *result);
@@ -76,5 +92,8 @@ void SCREEN_OT_screenshot(struct wmOperatorType *ot);
/* screen_ops.c */
void region_blend_start(struct bContext *C, struct ScrArea *sa, struct ARegion *ar);
+/* workspace_layout_edit.c */
+bool workspace_layout_set_poll(const struct WorkSpaceLayout *layout);
+
#endif /* __SCREEN_INTERN_H__ */
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 4f9cd7a42b6..5df6b0c6f19 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
@@ -46,25 +47,34 @@
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_userdef_types.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_icons.h"
+#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_editmesh.h"
#include "BKE_sound.h"
-#include "BKE_mask.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph.h"
+
+#include "ED_anim_api.h"
#include "ED_armature.h"
#include "ED_clip.h"
#include "ED_image.h"
@@ -79,6 +89,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -134,7 +145,7 @@ bool ED_operator_screen_mainwinactive(bContext *C)
if (CTX_wm_window(C) == NULL) return 0;
screen = CTX_wm_screen(C);
if (screen == NULL) return 0;
- if (screen->subwinactive != screen->mainwin) return 0;
+ if (screen->active_region != NULL) return 0;
return 1;
}
@@ -200,7 +211,7 @@ bool ED_operator_animview_active(bContext *C)
{
if (ED_operator_areaactive(C)) {
SpaceLink *sl = (SpaceLink *)CTX_wm_space_data(C);
- if (sl && (ELEM(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME)))
+ if (sl && (ELEM(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO)))
return true;
}
@@ -208,11 +219,6 @@ bool ED_operator_animview_active(bContext *C)
return 0;
}
-bool ED_operator_timeline_active(bContext *C)
-{
- return ed_spacetype_test(C, SPACE_TIME);
-}
-
bool ED_operator_outliner_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_OUTLINER);
@@ -291,11 +297,6 @@ bool ED_operator_nla_active(bContext *C)
return ed_spacetype_test(C, SPACE_NLA);
}
-bool ED_operator_logic_active(bContext *C)
-{
- return ed_spacetype_test(C, SPACE_LOGIC);
-}
-
bool ED_operator_info_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_INFO);
@@ -361,6 +362,15 @@ bool ED_operator_editmesh_region_view3d(bContext *C)
return 0;
}
+bool ED_operator_editmesh_auto_smooth(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_MESH && (((Mesh *)(obedit->data))->flag & ME_AUTOSMOOTH)) {
+ return NULL != BKE_editmesh_from_object(obedit);
+ }
+ return 0;
+}
+
bool ED_operator_editarmature(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
@@ -552,8 +562,8 @@ bool ED_operator_mask(bContext *C)
case SPACE_IMAGE:
{
SpaceImage *sima = sa->spacedata.first;
- Scene *scene = CTX_data_scene(C);
- return ED_space_image_check_show_maskedit(scene, sima);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return ED_space_image_check_show_maskedit(sima, view_layer);
}
}
}
@@ -561,6 +571,12 @@ bool ED_operator_mask(bContext *C)
return false;
}
+bool ED_operator_camera(bContext *C)
+{
+ struct Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
+ return (cam != NULL);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -723,6 +739,68 @@ static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const boo
break;
}
}
+ else if (az->type == AZONE_REGION_SCROLL) {
+ ARegion *ar = az->ar;
+ View2D *v2d = &ar->v2d;
+ int scroll_flag = 0;
+ const int isect_value = UI_view2d_mouse_in_scrollers_ex(ar, v2d, xy[0], xy[1], &scroll_flag);
+
+ /* Check if we even have scroll bars. */
+ if (((az->direction == AZ_SCROLL_HOR) && !(scroll_flag & V2D_SCROLL_HORIZONTAL)) ||
+ ((az->direction == AZ_SCROLL_VERT) && !(scroll_flag & V2D_SCROLL_VERTICAL)))
+ {
+ /* no scrollbars, do nothing. */
+ }
+ else if (test_only) {
+ if (isect_value != 0) {
+ break;
+ }
+ }
+ else {
+ bool redraw = false;
+
+ if (isect_value == 'h') {
+ if (az->direction == AZ_SCROLL_HOR) {
+ az->alpha = 1.0f;
+ v2d->alpha_hor = 255;
+ redraw = true;
+ }
+ }
+ else if (isect_value == 'v') {
+ if (az->direction == AZ_SCROLL_VERT) {
+ az->alpha = 1.0f;
+ v2d->alpha_vert = 255;
+ redraw = true;
+ }
+ }
+ else {
+ const int local_xy[2] = {xy[0] - ar->winrct.xmin, xy[1] - ar->winrct.ymin};
+ float dist_fac = 0.0f, alpha = 0.0f;
+
+ if (az->direction == AZ_SCROLL_HOR) {
+ dist_fac = BLI_rcti_length_y(&v2d->hor, local_xy[1]) / AZONEFADEIN;
+ CLAMP(dist_fac, 0.0f, 1.0f);
+ alpha = 1.0f - dist_fac;
+
+ v2d->alpha_hor = alpha * 255;
+ }
+ else if (az->direction == AZ_SCROLL_VERT) {
+ dist_fac = BLI_rcti_length_x(&v2d->vert, local_xy[0]) / AZONEFADEIN;
+ CLAMP(dist_fac, 0.0f, 1.0f);
+ alpha = 1.0f - dist_fac;
+
+ v2d->alpha_vert = alpha * 255;
+ }
+ az->alpha = alpha;
+ redraw = true;
+ }
+
+ if (redraw) {
+ ED_area_tag_redraw_no_rebuild(sa);
+ }
+ /* Don't return! */
+ }
+ }
}
}
@@ -778,8 +856,8 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
AZone *az = ED_area_actionzone_find_xy(sa, &event->x);
sActionzoneData *sad;
- /* quick escape */
- if (az == NULL)
+ /* quick escape - Scroll azones only hide/unhide the scroll-bars, they have their own handling. */
+ if (az == NULL || ELEM(az->type, AZONE_REGION_SCROLL))
return OPERATOR_PASS_THROUGH;
/* ok we do the actionzone */
@@ -805,11 +883,8 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
bScreen *sc = CTX_wm_screen(C);
sActionzoneData *sad = op->customdata;
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
switch (event->type) {
case MOUSEMOVE:
@@ -830,10 +905,15 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
sad->gesture_dir = 'w';
if (sad->az->type == AZONE_AREA) {
+ const wmWindow *win = CTX_wm_window(C);
+ rcti screen_rect;
+
+ WM_window_screen_rect_calc(win, &screen_rect);
/* once we drag outside the actionzone, register a gesture
* check we're not on an edge so join finds the other area */
is_gesture = ((ED_area_actionzone_find_xy(sad->sa1, &event->x) != sad->az) &&
- (screen_find_active_scredge(sc, winsize_x, winsize_y, event->x, event->y) == NULL));
+ (screen_geom_area_map_find_active_scredge(
+ AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y) == NULL));
}
else {
const int delta_min = 1;
@@ -1023,13 +1103,17 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot)
static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
- wmWindow *newwin, *win;
- bScreen *newsc, *sc;
+ wmWindow *newwin, *win = CTX_wm_window(C);
+ Scene *scene;
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
+ WorkSpaceLayout *layout_new;
+ bScreen *newsc;
ScrArea *sa;
rcti rect;
win = CTX_wm_window(C);
- sc = CTX_wm_screen(C);
+ scene = CTX_data_scene(C);
sa = CTX_wm_area(C);
/* XXX hrmf! */
@@ -1056,9 +1140,13 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
*newwin->stereo3d_format = *win->stereo3d_format;
+ newwin->scene = scene;
+
+ BKE_workspace_active_set(newwin->workspace_hook, workspace);
/* allocs new screen and adds to newly created window, using window size */
- newsc = ED_screen_add(bmain, newwin, CTX_data_scene(C), sc->id.name + 2);
- newwin->screen = newsc;
+ layout_new = ED_workspace_layout_add(bmain, workspace, newwin, BKE_workspace_layout_name_get(layout_old));
+ newsc = BKE_workspace_layout_screen_get(layout_new);
+ WM_window_set_active_layout(newwin, workspace, layout_new);
/* copy area to new screen */
ED_area_data_copy((ScrArea *)newsc->areabase.first, sa, true);
@@ -1126,35 +1214,90 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot)
*/
typedef struct sAreaMoveData {
- int bigger, smaller, origval;
+ int bigger, smaller, origval, step;
char dir;
- bool do_snap;
+ enum AreaMoveSnapType {
+ /* Snapping disabled */
+ SNAP_NONE = 0,
+ /* Snap to an invisible grid with a unit defined in AREAGRID */
+ SNAP_AREAGRID,
+ /* Snap to fraction (half, third.. etc) and adjacent edges. */
+ SNAP_FRACTION_AND_ADJACENT,
+ /* Snap to either bigger or smaller, nothing in-between (used for
+ * global areas). This has priority over other snap types, if it is
+ * used, toggling SNAP_FRACTION_AND_ADJACENT doesn't work. */
+ SNAP_BIGGER_SMALLER_ONLY,
+ } snap_type;
} sAreaMoveData;
/* helper call to move area-edge, sets limits
- * need window size in order to get correct limits */
-static void area_move_set_limits(bScreen *sc, int dir,
- const int winsize_x, const int winsize_y,
- int *bigger, int *smaller)
+ * need window bounds in order to get correct limits */
+static void area_move_set_limits(
+ wmWindow *win, bScreen *sc, int dir,
+ int *bigger, int *smaller,
+ bool *use_bigger_smaller_snap)
{
- ScrArea *sa;
+ rcti window_rect;
int areaminy = ED_area_headersize();
int areamin;
/* we check all areas and test for free space with MINSIZE */
*bigger = *smaller = 100000;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ if (use_bigger_smaller_snap != NULL) {
+ *use_bigger_smaller_snap = false;
+ for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ int size_min = ED_area_global_min_size_y(area) - 1;
+ int size_max = ED_area_global_max_size_y(area) - 1;
+
+ size_min = MAX2(size_min, 0);
+ BLI_assert(size_min < size_max);
+
+ /* logic here is only tested for lower edge :) */
+ /* left edge */
+ if ((area->v1->editflag && area->v2->editflag)) {
+ *smaller = area->v4->vec.x - size_max;
+ *bigger = area->v4->vec.x - size_min;
+ *use_bigger_smaller_snap = true;
+ return;
+ }
+ /* top edge */
+ else if ((area->v2->editflag && area->v3->editflag)) {
+ *smaller = area->v1->vec.y + size_min;
+ *bigger = area->v1->vec.y + size_max;
+ *use_bigger_smaller_snap = true;
+ return;
+ }
+ /* right edge */
+ else if ((area->v3->editflag && area->v4->editflag)) {
+ *smaller = area->v1->vec.x + size_min;
+ *bigger = area->v1->vec.x + size_max;
+ *use_bigger_smaller_snap = true;
+ return;
+ }
+ /* lower edge */
+ else if ((area->v4->editflag && area->v1->editflag)) {
+ *smaller = area->v2->vec.y - size_max;
+ *bigger = area->v2->vec.y - size_min;
+ *use_bigger_smaller_snap = true;
+ return;
+ }
+ }
+ }
+
+ WM_window_rect_calc(win, &window_rect);
+
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
if (dir == 'h') {
int y1;
areamin = areaminy;
- if (sa->v1->vec.y > 0)
+ if (sa->v1->vec.y > window_rect.ymin)
areamin += U.pixelsize;
- if (sa->v2->vec.y < winsize_y - 1)
+ if (sa->v2->vec.y < (window_rect.ymax - 1))
areamin += U.pixelsize;
- y1 = sa->v2->vec.y - sa->v1->vec.y + 1 - areamin;
+ y1 = screen_geom_area_height(sa) - areamin;
/* if top or down edge selected, test height */
if (sa->v1->editflag && sa->v4->editflag)
@@ -1166,12 +1309,12 @@ static void area_move_set_limits(bScreen *sc, int dir,
int x1;
areamin = AREAMINX;
- if (sa->v1->vec.x > 0)
+ if (sa->v1->vec.x > window_rect.xmin)
areamin += U.pixelsize;
- if (sa->v4->vec.x < winsize_x - 1)
+ if (sa->v4->vec.x < (window_rect.xmax - 1))
areamin += U.pixelsize;
- x1 = sa->v4->vec.x - sa->v1->vec.x + 1 - areamin;
+ x1 = screen_geom_area_width(sa) - areamin;
/* if left or right edge selected, test width */
if (sa->v1->editflag && sa->v2->editflag)
@@ -1190,9 +1333,6 @@ static int area_move_init(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
ScrEdge *actedge;
sAreaMoveData *md;
- ScrVert *v1;
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
int x, y;
/* required properties */
@@ -1200,69 +1340,115 @@ static int area_move_init(bContext *C, wmOperator *op)
y = RNA_int_get(op->ptr, "y");
/* setup */
- actedge = screen_find_active_scredge(sc, winsize_x, winsize_y, x, y);
+ actedge = screen_geom_find_active_scredge(win, sc, x, y);
if (actedge == NULL) return 0;
md = MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
op->customdata = md;
- md->dir = scredge_is_horizontal(actedge) ? 'h' : 'v';
+ md->dir = screen_geom_edge_is_horizontal(actedge) ? 'h' : 'v';
if (md->dir == 'h') md->origval = actedge->v1->vec.y;
else md->origval = actedge->v1->vec.x;
- select_connected_scredge(sc, actedge);
- /* now all vertices with 'flag==1' are the ones that can be moved. Move this to editflag */
- for (v1 = sc->vertbase.first; v1; v1 = v1->next)
+ screen_geom_select_connected_edge(win, actedge);
+ /* now all vertices with 'flag == 1' are the ones that can be moved. Move this to editflag */
+ ED_screen_verts_iter(win, sc, v1) {
v1->editflag = v1->flag;
+ }
+
+ bool use_bigger_smaller_snap = false;
+ area_move_set_limits(win, sc, md->dir, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
- area_move_set_limits(sc, md->dir, winsize_x, winsize_y, &md->bigger, &md->smaller);
+ md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID;
return 1;
}
static int area_snap_calc_location(
- const bScreen *sc, const int delta,
- const int origval, const int dir,
+ const bScreen *sc, const enum AreaMoveSnapType snap_type,
+ const int delta, const int origval, const int dir,
const int bigger, const int smaller)
{
- int final_loc = -1;
+ BLI_assert(snap_type != SNAP_NONE);
+ int m_cursor_final = -1;
+ const int m_cursor = origval + delta;
+ const int m_span = (float)(bigger + smaller);
+ const int m_min = origval - smaller;
+ // const int axis_max = axis_min + m_span;
+
+ switch (snap_type) {
+ case SNAP_AREAGRID:
+ m_cursor_final = m_cursor;
+ if (delta != bigger && delta != -smaller) {
+ m_cursor_final -= (m_cursor % AREAGRID);
+ CLAMP(m_cursor_final, origval - smaller, origval + bigger);
+ }
+ break;
- const int m_loc = origval + delta;
- const int axis = (dir == 'v') ? 0 : 1;
- int snap_dist;
- int dist;
- {
- /* Test the snap to middle. */
- int middle = origval + (bigger - smaller) / 2;
- middle -= (middle % AREAGRID);
+ case SNAP_BIGGER_SMALLER_ONLY:
+ m_cursor_final = (m_cursor >= bigger) ? bigger : smaller;
+ break;
- snap_dist = abs(m_loc - middle);
- final_loc = middle;
- }
+ case SNAP_FRACTION_AND_ADJACENT:
+ {
+ const int axis = (dir == 'v') ? 0 : 1;
+ int snap_dist_best = INT_MAX;
+ {
+ const float div_array[] = {
+ /* Middle. */
+ 1.0f / 2.0f,
+ /* Thirds. */
+ 1.0f / 3.0f, 2.0f / 3.0f,
+ /* Quaters. */
+ 1.0f / 4.0f, 3.0f / 4.0f,
+ /* Eighth. */
+ 1.0f / 8.0f, 3.0f / 8.0f,
+ 5.0f / 8.0f, 7.0f / 8.0f,
+ };
+ /* Test the snap to the best division. */
+ for (int i = 0; i < ARRAY_SIZE(div_array); i++) {
+ const int m_cursor_test = m_min + round_fl_to_int(m_span * div_array[i]);
+ const int snap_dist_test = abs(m_cursor - m_cursor_test);
+ if (snap_dist_best >= snap_dist_test) {
+ snap_dist_best = snap_dist_test;
+ m_cursor_final = m_cursor_test;
+ }
+ }
+ }
- for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) {
- if (v1->editflag) {
- const int v_loc = (&v1->vec.x)[!axis];
+ for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) {
+ if (!v1->editflag) {
+ continue;
+ }
+ const int v_loc = (&v1->vec.x)[!axis];
- for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
- if (!v2->editflag) {
+ for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
+ if (v2->editflag) {
+ continue;
+ }
if (v_loc == (&v2->vec.x)[!axis]) {
const int v_loc2 = (&v2->vec.x)[axis];
/* Do not snap to the vertices at the ends. */
if ((origval - smaller) < v_loc2 && v_loc2 < (origval + bigger)) {
- dist = abs(m_loc - v_loc2);
- if (dist <= snap_dist) {
- snap_dist = dist;
- final_loc = v_loc2;
+ const int snap_dist_test = abs(m_cursor - v_loc2);
+ if (snap_dist_best >= snap_dist_test) {
+ snap_dist_best = snap_dist_test;
+ m_cursor_final = v_loc2;
}
}
}
}
}
+ break;
}
+ case SNAP_NONE:
+ break;
}
- return final_loc;
+ BLI_assert(ELEM(snap_type, SNAP_BIGGER_SMALLER_ONLY) ||
+ IN_RANGE_INCL(m_cursor_final, origval - smaller, origval + bigger));
+
+ return m_cursor_final;
}
/* moves selected screen edge amount of delta, used by split & move */
@@ -1270,29 +1456,28 @@ static void area_move_apply_do(
const bContext *C, int delta,
const int origval, const int dir,
const int bigger, const int smaller,
- const bool do_snap)
+ const enum AreaMoveSnapType snap_type)
{
+ wmWindow *win = CTX_wm_window(C);
bScreen *sc = CTX_wm_screen(C);
- ScrVert *v1;
+ short final_loc = -1;
bool doredraw = false;
- CLAMP(delta, -smaller, bigger);
- short final_loc = -1;
+ if (snap_type != SNAP_BIGGER_SMALLER_ONLY) {
+ CLAMP(delta, -smaller, bigger);
+ }
- if (do_snap) {
- final_loc = area_snap_calc_location(sc, delta, origval, dir, bigger, smaller);
+ if (snap_type == SNAP_NONE) {
+ final_loc = origval + delta;
}
else {
- final_loc = origval + delta;
- if (delta != bigger && delta != -smaller) {
- final_loc -= (final_loc % AREAGRID);
- }
+ final_loc = area_snap_calc_location(sc, snap_type, delta, origval, dir, bigger, smaller);
}
BLI_assert(final_loc != -1);
short axis = (dir == 'v') ? 0 : 1;
- for (v1 = sc->vertbase.first; v1; v1 = v1->next) {
+ ED_screen_verts_iter(win, sc, v1) {
if (v1->editflag) {
short oldval = (&v1->vec.x)[axis];
(&v1->vec.x)[axis] = final_loc;
@@ -1307,12 +1492,36 @@ static void area_move_apply_do(
/* only redraw if we actually moved a screen vert, for AREAGRID */
if (doredraw) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ bool redraw_all = false;
+ ED_screen_areas_iter(win, sc, sa) {
if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) {
+ if (ED_area_is_global(sa)) {
+ /* Snap to minimum or maximum for global areas. */
+ int height = round_fl_to_int(screen_geom_area_height(sa) / UI_DPI_FAC);
+ if (abs(height - sa->global->size_min) < abs(height - sa->global->size_max)) {
+ sa->global->cur_fixed_height = sa->global->size_min;
+ }
+ else {
+ sa->global->cur_fixed_height = sa->global->size_max;
+ }
+
+ sc->do_refresh = true;
+ redraw_all = true;
+ }
+ ED_area_tag_redraw(sa);
+ }
+ }
+ if (redraw_all) {
+ ED_screen_areas_iter(win, sc, sa) {
ED_area_tag_redraw(sa);
}
}
+
+ ED_screen_global_areas_sync(win);
+
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */
+ /* Update preview thumbnail */
+ BKE_icon_changed(sc->id.icon_id);
}
}
@@ -1321,7 +1530,7 @@ static void area_move_apply(bContext *C, wmOperator *op)
sAreaMoveData *md = op->customdata;
int delta = RNA_int_get(op->ptr, "delta");
- area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->do_snap);
+ area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->snap_type);
}
static void area_move_exit(bContext *C, wmOperator *op)
@@ -1331,8 +1540,10 @@ static void area_move_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
/* this makes sure aligned edges will result in aligned grabbing */
- removedouble_scrverts(CTX_wm_screen(C));
- removedouble_scredges(CTX_wm_screen(C));
+ BKE_screen_remove_double_scrverts(CTX_wm_screen(C));
+ BKE_screen_remove_double_scredges(CTX_wm_screen(C));
+
+ G.moving &= ~G_TRANSFORM_WM;
}
static int area_move_exec(bContext *C, wmOperator *op)
@@ -1355,6 +1566,8 @@ static int area_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (!area_move_init(C, op))
return OPERATOR_PASS_THROUGH;
+ G.moving |= G_TRANSFORM_WM;
+
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -1400,10 +1613,15 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case KM_MODAL_SNAP_ON:
- md->do_snap = true;
+ if (md->snap_type != SNAP_BIGGER_SMALLER_ONLY) {
+ md->snap_type = SNAP_FRACTION_AND_ADJACENT;
+ }
break;
+
case KM_MODAL_SNAP_OFF:
- md->do_snap = false;
+ if (md->snap_type != SNAP_BIGGER_SMALLER_ONLY) {
+ md->snap_type = SNAP_AREAGRID;
+ }
break;
}
break;
@@ -1522,7 +1740,7 @@ static int area_split_init(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
sAreaSplitData *sd;
- int areaminy = ED_area_headersize() + 1;
+ int areaminy = ED_area_headersize();
int dir;
/* required context */
@@ -1540,8 +1758,14 @@ static int area_split_init(bContext *C, wmOperator *op)
op->customdata = sd;
sd->sarea = sa;
- sd->origsize = dir == 'v' ? sa->winx : sa->winy;
- sd->origmin = dir == 'v' ? sa->totrct.xmin : sa->totrct.ymin;
+ if (dir == 'v') {
+ sd->origmin = sa->v1->vec.x;
+ sd->origsize = sa->v4->vec.x - sd->origmin;
+ }
+ else {
+ sd->origmin = sa->v1->vec.y;
+ sd->origsize = sa->v2->vec.y - sd->origmin;
+ }
return 1;
}
@@ -1560,16 +1784,16 @@ static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
ScrVert *sbv4 = sb->v4;
if (sav1 == sbv4 && sav2 == sbv3) { /* sa to right of sb = W */
- return screen_findedge(screen, sav1, sav2);
+ return BKE_screen_find_edge(screen, sav1, sav2);
}
else if (sav2 == sbv1 && sav3 == sbv4) { /* sa to bottom of sb = N */
- return screen_findedge(screen, sav2, sav3);
+ return BKE_screen_find_edge(screen, sav2, sav3);
}
else if (sav3 == sbv2 && sav4 == sbv1) { /* sa to left of sb = E */
- return screen_findedge(screen, sav3, sav4);
+ return BKE_screen_find_edge(screen, sav3, sav4);
}
else if (sav1 == sbv2 && sav4 == sbv3) { /* sa on top of sb = S*/
- return screen_findedge(screen, sav1, sav4);
+ return BKE_screen_find_edge(screen, sav1, sav4);
}
return NULL;
@@ -1579,6 +1803,7 @@ static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
/* do the split, return success */
static int area_split_apply(bContext *C, wmOperator *op)
{
+ const wmWindow *win = CTX_wm_window(C);
bScreen *sc = CTX_wm_screen(C);
sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
float fac;
@@ -1587,16 +1812,15 @@ static int area_split_apply(bContext *C, wmOperator *op)
fac = RNA_float_get(op->ptr, "factor");
dir = RNA_enum_get(op->ptr, "direction");
- sd->narea = area_split(sc, sd->sarea, dir, fac, 0); /* 0 = no merge */
+ sd->narea = area_split(win, sc, sd->sarea, dir, fac, 0); /* 0 = no merge */
if (sd->narea) {
- ScrVert *sv;
-
sd->nedge = area_findsharededge(sc, sd->sarea, sd->narea);
/* select newly created edge, prepare for moving edge */
- for (sv = sc->vertbase.first; sv; sv = sv->next)
+ ED_screen_verts_iter(win, sc, sv) {
sv->editflag = 0;
+ }
sd->nedge->v1->editflag = 1;
sd->nedge->v2->editflag = 1;
@@ -1608,6 +1832,8 @@ static int area_split_apply(bContext *C, wmOperator *op)
ED_area_tag_redraw(sd->narea);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+ /* Update preview thumbnail */
+ BKE_icon_changed(sc->id.icon_id);
return 1;
}
@@ -1633,8 +1859,8 @@ static void area_split_exit(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
/* this makes sure aligned edges will result in aligned grabbing */
- removedouble_scrverts(CTX_wm_screen(C));
- removedouble_scredges(CTX_wm_screen(C));
+ BKE_screen_remove_double_scrverts(CTX_wm_screen(C));
+ BKE_screen_remove_double_scredges(CTX_wm_screen(C));
}
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
@@ -1650,8 +1876,6 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmWindow *win = CTX_wm_window(C);
bScreen *sc = CTX_wm_screen(C);
sAreaSplitData *sd;
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
int dir;
/* no full window splitting allowed */
@@ -1719,6 +1943,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
ScrEdge *actedge;
+ rcti window_rect;
int event_co[2];
/* retrieve initial mouse coord, so we can find the active edge */
@@ -1729,12 +1954,15 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
copy_v2_v2_int(event_co, &event->x);
}
- actedge = screen_find_active_scredge(sc, winsize_x, winsize_y, event_co[0], event_co[1]);
+ WM_window_rect_calc(win, &window_rect);
+
+ actedge = screen_geom_area_map_find_active_scredge(
+ AREAMAP_FROM_SCREEN(sc), &window_rect, event_co[0], event_co[1]);
if (actedge == NULL) {
return OPERATOR_CANCELLED;
}
- dir = scredge_is_horizontal(actedge) ? 'v' : 'h';
+ dir = screen_geom_edge_is_horizontal(actedge) ? 'v' : 'h';
RNA_property_enum_set(op->ptr, prop_dir, dir);
@@ -1750,7 +1978,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* do the split */
if (area_split_apply(C, op)) {
- area_move_set_limits(sc, dir, winsize_x, winsize_y, &sd->bigger, &sd->smaller);
+ area_move_set_limits(win, sc, dir, &sd->bigger, &sd->smaller, NULL);
/* add temp handler for edge move or cancel */
WM_event_add_modal_handler(C, op);
@@ -1868,10 +2096,11 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (sd->previewmode == 0) {
if (sd->do_snap) {
const int snap_loc = area_snap_calc_location(
- CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->bigger, sd->smaller);
+ CTX_wm_screen(C), SNAP_FRACTION_AND_ADJACENT, sd->delta, sd->origval, dir,
+ sd->bigger, sd->smaller);
sd->delta = snap_loc - sd->origval;
}
- area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, false);
+ area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, SNAP_NONE);
}
else {
if (sd->sarea) {
@@ -1883,19 +2112,20 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (sd->sarea) {
ScrArea *sa = sd->sarea;
if (dir == 'v') {
- sd->origsize = sa->winx;
- sd->origmin = sa->totrct.xmin;
+ sd->origmin = sa->v1->vec.x;
+ sd->origsize = sa->v4->vec.x - sd->origmin;
}
else {
- sd->origsize = sa->winy;
- sd->origmin = sa->totrct.ymin;
+ sd->origmin = sa->v1->vec.y;
+ sd->origsize = sa->v2->vec.y - sd->origmin;
}
if (sd->do_snap) {
sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1;
const int snap_loc = area_snap_calc_location(
- CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->origmin + sd->origsize, -sd->origmin);
+ CTX_wm_screen(C), SNAP_FRACTION_AND_ADJACENT, sd->delta, sd->origval, dir,
+ sd->origmin + sd->origsize, -sd->origmin);
sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0;
sd->delta = snap_loc - sd->origval;
@@ -1904,7 +2134,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_area_tag_redraw(sd->sarea);
}
- CTX_wm_window(C)->screen->do_draw = true;
+ CTX_wm_screen(C)->do_draw = true;
}
float fac = (float)(sd->delta + sd->origval - sd->origmin) / sd->origsize;
@@ -2072,7 +2302,8 @@ static int region_scale_get_maxsize(RegionMoveData *rmd)
if (rmd->ar->regiontype == RGN_TYPE_TOOL_PROPS) {
/* this calculation seems overly verbose
* can someone explain why this method is necessary? - campbell */
- maxsize = rmd->maxsize - ((rmd->sa->headertype == HEADERTOP) ? UI_UNIT_Y * 2 : UI_UNIT_Y) - (UI_UNIT_Y / 4);
+ const bool top_header = ED_area_header_alignment(rmd->sa) == RGN_ALIGN_TOP;
+ maxsize = rmd->maxsize - ((top_header) ? UI_UNIT_Y * 2 : UI_UNIT_Y) - (UI_UNIT_Y / 4);
}
return maxsize;
@@ -2116,7 +2347,9 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* execute the events */
switch (event->type) {
case MOUSEMOVE:
-
+ {
+ const float aspect = BLI_rctf_size_x(&rmd->ar->v2d.cur) / (BLI_rcti_size_x(&rmd->ar->v2d.mask) + 1);
+ const int snap_size_threshold = (U.widget_unit * 2) / aspect;
if (rmd->edge == AE_LEFT_TO_TOPRIGHT || rmd->edge == AE_RIGHT_TO_TOPLEFT) {
delta = event->x - rmd->origx;
if (rmd->edge == AE_LEFT_TO_TOPRIGHT) delta = -delta;
@@ -2125,6 +2358,13 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
delta /= UI_DPI_FAC;
rmd->ar->sizex = rmd->origval + delta;
+
+ if (rmd->ar->type->snap_size) {
+ short sizex_test = rmd->ar->type->snap_size(rmd->ar, rmd->ar->sizex, 0);
+ if (ABS(rmd->ar->sizex - sizex_test) < snap_size_threshold) {
+ rmd->ar->sizex = sizex_test;
+ }
+ }
CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
if (rmd->ar->sizex < UI_UNIT_X) {
@@ -2144,6 +2384,13 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
delta /= UI_DPI_FAC;
rmd->ar->sizey = rmd->origval + delta;
+
+ if (rmd->ar->type->snap_size) {
+ short sizey_test = rmd->ar->type->snap_size(rmd->ar, rmd->ar->sizey, 1);
+ if (ABS(rmd->ar->sizey - sizey_test) < snap_size_threshold) {
+ rmd->ar->sizey = sizey_test;
+ }
+ }
CLAMP(rmd->ar->sizey, 0, rmd->maxsize);
/* note, 'UI_UNIT_Y/4' means you need to drag the header almost
@@ -2163,7 +2410,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
break;
-
+ }
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
@@ -2226,16 +2473,15 @@ static void areas_do_frame_follow(bContext *C, bool middle)
bScreen *scr = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *window;
- for (window = wm->windows.first; window; window = window->next) {
- ScrArea *sa;
- for (sa = window->screen->areabase.first; sa; sa = sa->next) {
- ARegion *ar;
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ for (wmWindow *window = wm->windows.first; window; window = window->next) {
+ const bScreen *screen = WM_window_get_active_screen(window);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
/* do follow here if editor type supports it */
if ((scr->redraws_flag & TIME_FOLLOW)) {
if ((ar->regiontype == RGN_TYPE_WINDOW &&
- ELEM(sa->spacetype, SPACE_SEQ, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
+ ELEM(sa->spacetype, SPACE_SEQ, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
(sa->spacetype == SPACE_CLIP && ar->regiontype == RGN_TYPE_PREVIEW))
{
float w = BLI_rctf_size_x(&ar->v2d.cur);
@@ -2395,12 +2641,15 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
}
/* populate tree with keyframe nodes */
- scene_to_keylist(&ads, scene, &keys, NULL);
- gpencil_to_keylist(&ads, scene->gpd, &keys);
+ scene_to_keylist(&ads, scene, &keys, 0);
if (ob) {
- ob_to_keylist(&ads, ob, &keys, NULL);
- gpencil_to_keylist(&ads, ob->gpd, &keys);
+ ob_to_keylist(&ads, ob, &keys, 0);
+
+ if (ob->type == OB_GPENCIL) {
+ const bool active = !(scene->flag & SCE_KEYS_NO_SELONLY);
+ gpencil_to_keylist(&ads, ob->data, &keys, active);
+ }
}
{
@@ -2411,9 +2660,6 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
}
}
- /* build linked-list for searching */
- BLI_dlrbTree_linkedlist_sync(&keys);
-
/* find matching keyframe in the right direction */
if (next)
ak = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra);
@@ -2546,64 +2792,16 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
/** \name Set Screen Operator
* \{ */
-static bool screen_set_is_ok(bScreen *screen, bScreen *screen_prev)
-{
- return ((screen->winid == 0) &&
- /* in typical usage these should have a nonzero winid
- * (all temp screens should be used, or closed & freed). */
- (screen->temp == false) &&
- (screen->state == SCREENNORMAL) &&
- (screen != screen_prev) &&
- (screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
-}
-
/* function to be called outside UI context, or for redo */
static int screen_set_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- bScreen *screen = CTX_wm_screen(C);
- bScreen *screen_prev = screen;
-
- ScrArea *sa = CTX_wm_area(C);
- int tot = BLI_listbase_count(&bmain->screen);
+ WorkSpace *workspace = CTX_wm_workspace(C);
int delta = RNA_int_get(op->ptr, "delta");
- /* temp screens are for userpref or render display */
- if (screen->temp || (sa && sa->full && sa->full->temp)) {
- return OPERATOR_CANCELLED;
- }
-
- if (delta == 1) {
- while (tot--) {
- screen = screen->id.next;
- if (screen == NULL) screen = bmain->screen.first;
- if (screen_set_is_ok(screen, screen_prev)) {
- break;
- }
- }
- }
- else if (delta == -1) {
- while (tot--) {
- screen = screen->id.prev;
- if (screen == NULL) screen = bmain->screen.last;
- if (screen_set_is_ok(screen, screen_prev)) {
- break;
- }
- }
- }
- else {
- screen = NULL;
- }
-
- if (screen && screen_prev != screen) {
- /* return to previous state before switching screens */
- if (sa && sa->full) {
- ED_screen_full_restore(C, sa); /* may free 'screen_prev' */
- }
-
- ED_screen_set(C, screen);
+ if (ED_workspace_layout_cycle(workspace, delta, C)) {
return OPERATOR_FINISHED;
}
+
return OPERATOR_CANCELLED;
}
@@ -2659,6 +2857,15 @@ static int screen_maximize_area_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static bool screen_maximize_area_poll(bContext *C)
+{
+ const bScreen *screen = CTX_wm_screen(C);
+ const ScrArea *area = CTX_wm_area(C);
+ return ED_operator_areaactive(C) &&
+ /* Don't allow maximizing global areas but allow minimizing from them. */
+ ((screen->state != SCREENNORMAL) || !ED_area_is_global(area));
+}
+
static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2668,7 +2875,7 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
ot->idname = "SCREEN_OT_screen_full_area";
ot->exec = screen_maximize_area_exec;
- ot->poll = ED_operator_areaactive;
+ ot->poll = screen_maximize_area_poll;
ot->flag = 0;
prop = RNA_def_boolean(ot->srna, "use_hide_panels", false, "Hide Panels", "Hide all the panels");
@@ -2731,6 +2938,8 @@ static void area_join_draw_cb(const struct wmWindow *UNUSED(win), void *userdata
/* XXX todo: find edge based on (x,y) and set other area? */
static int area_join_init(bContext *C, wmOperator *op)
{
+ const wmWindow *win = CTX_wm_window(C);
+ bScreen *screen = CTX_wm_screen(C);
ScrArea *sa1, *sa2;
sAreaJoinData *jd = NULL;
int x1, y1;
@@ -2743,10 +2952,21 @@ static int area_join_init(bContext *C, wmOperator *op)
x2 = RNA_int_get(op->ptr, "max_x");
y2 = RNA_int_get(op->ptr, "max_y");
- sa1 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, x1, y1);
- sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, x2, y2);
- if (sa1 == NULL || sa2 == NULL || sa1 == sa2)
+ sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, x1, y1);
+ if (sa1 == NULL) {
+ sa1 = BKE_screen_area_map_find_area_xy(&win->global_areas, SPACE_TYPE_ANY, x1, y1);
+ }
+ sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, x2, y2);
+ if (sa2 == NULL) {
+ sa2 = BKE_screen_area_map_find_area_xy(&win->global_areas, SPACE_TYPE_ANY, x2, y2);
+ }
+ if ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2))) {
+ BKE_report(op->reports, RPT_ERROR, "Global areas (Top Bar, Status Bar) do not support joining");
return 0;
+ }
+ else if (sa1 == NULL || sa2 == NULL || sa1 == sa2) {
+ return 0;
+ }
/* do areas share an edge? */
if (sa1->v1 == sa2->v1 || sa1->v1 == sa2->v2 || sa1->v1 == sa2->v3 || sa1->v1 == sa2->v4) shared++;
@@ -2801,9 +3021,9 @@ static void area_join_exit(bContext *C, wmOperator *op)
}
/* this makes sure aligned edges will result in aligned grabbing */
- removedouble_scredges(CTX_wm_screen(C));
- removenotused_scredges(CTX_wm_screen(C));
- removenotused_scrverts(CTX_wm_screen(C));
+ BKE_screen_remove_double_scredges(CTX_wm_screen(C));
+ BKE_screen_remove_unused_scredges(CTX_wm_screen(C));
+ BKE_screen_remove_unused_scrverts(CTX_wm_screen(C));
}
static int area_join_exec(bContext *C, wmOperator *op)
@@ -2845,7 +3065,7 @@ static int area_join_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (!area_join_init(C, op))
- return OPERATOR_PASS_THROUGH;
+ return OPERATOR_CANCELLED;
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -2972,16 +3192,16 @@ static void SCREEN_OT_area_join(wmOperatorType *ot)
static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ const wmWindow *win = CTX_wm_window(C);
+ const bScreen *sc = CTX_wm_screen(C);
uiPopupMenu *pup;
uiLayout *layout;
PointerRNA ptr;
ScrEdge *actedge;
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
+ rcti window_rect;
- actedge = screen_find_active_scredge(sc, winsize_x, winsize_y, event->x, event->y);
+ WM_window_rect_calc(win, &window_rect);
+ actedge = screen_geom_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), &window_rect, event->x, event->y);
if (actedge == NULL) return OPERATOR_CANCELLED;
@@ -3379,11 +3599,24 @@ static int region_flip_exec(bContext *C, wmOperator *UNUSED(op))
ar->alignment = RGN_ALIGN_LEFT;
ED_area_tag_redraw(CTX_wm_area(C));
+ WM_event_add_mousemove(C);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
+static bool region_flip_poll(bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+
+ /* don't flip anything around in topbar */
+ if (area && area->spacetype == SPACE_TOPBAR) {
+ CTX_wm_operator_poll_msg_set(C, "Flipping regions in the Top-bar is not allowed");
+ return 0;
+ }
+
+ return ED_operator_areaactive(C);
+}
static void SCREEN_OT_region_flip(wmOperatorType *ot)
{
@@ -3394,7 +3627,7 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot)
/* api callbacks */
ot->exec = region_flip_exec;
- ot->poll = ED_operator_areaactive;
+ ot->poll = region_flip_poll;
ot->flag = 0;
}
@@ -3471,32 +3704,44 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
/** \name Header Tools Operator
* \{ */
+static bool header_context_menu_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ return (sa && sa->spacetype != SPACE_STATUSBAR);
+}
+
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") : IFACE_("Flip to Top");
+ if (!ELEM(sa->spacetype, SPACE_TOPBAR)) {
+ uiItemO(layout, IFACE_("Toggle Header"), ICON_NONE, "SCREEN_OT_header");
+ }
+
/* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
- uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
+ if (!ELEM(sa->spacetype, SPACE_TOPBAR)) {
+ uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
+ }
+
uiItemO(layout, IFACE_("Collapse Menus"),
(sa->flag & HEADER_NO_PULLDOWN) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT,
"SCREEN_OT_header_toggle_menus");
- uiItemS(layout);
+ /* file browser should be fullscreen all the time, topbar should
+ * never be. But other regions can be maximized/restored... */
+ if (!ELEM(sa->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
+ uiItemS(layout);
- /* file browser should be fullscreen all the time, but other regions can be maximized/restored... */
- if (sa->spacetype != SPACE_FILE) {
- if (sa->full)
- uiItemO(layout, IFACE_("Tile Area"), ICON_NONE, "SCREEN_OT_screen_full_area");
- else
- uiItemO(layout, IFACE_("Maximize Area"), ICON_NONE, "SCREEN_OT_screen_full_area");
+ const char *but_str = sa->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
+ uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
}
}
-static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+static int header_context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -3511,15 +3756,33 @@ static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv
return OPERATOR_INTERFACE;
}
-static void SCREEN_OT_header_toolbox(wmOperatorType *ot)
+static void SCREEN_OT_header_context_menu(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Header Toolbox";
- ot->description = "Display header region toolbox";
- ot->idname = "SCREEN_OT_header_toolbox";
+ ot->name = "Header Context Menu";
+ ot->description = "Display header region context menu";
+ ot->idname = "SCREEN_OT_header_context_menu";
/* api callbacks */
- ot->invoke = header_toolbox_invoke;
+ ot->poll = header_context_menu_poll;
+ ot->invoke = header_context_menu_invoke;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Navigation Bar Tools Menu
+ * \{ */
+
+void ED_screens_navigation_bar_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
+{
+ const ARegion *ar = CTX_wm_region(C);
+ const char *but_flip_str = (ar->alignment == RGN_ALIGN_LEFT) ? IFACE_("Flip to Right") : IFACE_("Flip to Left");
+
+ /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
+ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
+
+ uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
}
/** \} */
@@ -3552,13 +3815,14 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws,
return 1;
break;
case SPACE_IPO:
- case SPACE_ACTION:
case SPACE_NLA:
if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit)
return 1;
break;
- case SPACE_TIME:
- /* if only 1 window or 3d windows, we do timeline too */
+ case SPACE_ACTION:
+ /* if only 1 window or 3d windows, we do timeline too
+ * NOTE: Now we do do action editor in all these cases, since timeline is here
+ */
if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit)
return 1;
break;
@@ -3609,7 +3873,7 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws,
return 1;
}
else if (regiontype == RGN_TYPE_HEADER) {
- if (spacetype == SPACE_TIME)
+ if (spacetype == SPACE_ACTION)
return 1;
}
else if (regiontype == RGN_TYPE_PREVIEW) {
@@ -3639,6 +3903,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if (screen->animtimer && screen->animtimer == event->customdata) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
wmTimer *wt = screen->animtimer;
ScreenAnimData *sad = wt->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3749,10 +4014,12 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
/* since we follow drawflags, we can't send notifier but tag regions ourselves */
- ED_update_for_newframe(bmain, scene, 1);
+ ED_update_for_newframe(bmain, depsgraph);
for (window = wm->windows.first; window; window = window->next) {
- for (sa = window->screen->areabase.first; sa; sa = sa->next) {
+ const bScreen *win_screen = WM_window_get_active_screen(window);
+
+ for (sa = win_screen->areabase.first; sa; sa = sa->next) {
ARegion *ar;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
bool redraw = false;
@@ -3768,7 +4035,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
/* do follow here if editor type supports it */
if ((sad->redraws & TIME_FOLLOW)) {
if ((ar->regiontype == RGN_TYPE_WINDOW &&
- ELEM(sa->spacetype, SPACE_SEQ, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
+ ELEM(sa->spacetype, SPACE_SEQ, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
(sa->spacetype == SPACE_CLIP && ar->regiontype == RGN_TYPE_PREVIEW))
{
float w = BLI_rctf_size_x(&ar->v2d.cur);
@@ -3832,11 +4099,11 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
- wmWindow *win;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen->animtimer || win->screen->scrubbing) {
- return win->screen;
+ if (screen->animtimer || screen->scrubbing) {
+ return screen;
}
}
@@ -3845,11 +4112,11 @@ bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
{
- wmWindow *win;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen->animtimer) {
- return win->screen;
+ if (screen->animtimer) {
+ return screen;
}
}
@@ -3871,7 +4138,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
else {
- int refresh = SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
+ int refresh = SPACE_ACTION; /* these settings are currently only available from a menu in the TimeLine */
if (mode == 1) /* XXX only play audio forwards!? */
BKE_sound_play_scene(scene);
@@ -3968,7 +4235,7 @@ static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Border Select Operator (Template)
+/** \name Box Select Operator (Template)
* \{ */
/* operator state vars used: (added by default WM callbacks)
@@ -3990,31 +4257,31 @@ static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
* poll() has to be filled in by user for context
*/
#if 0
-static int border_select_exec(bContext *C, wmOperator *op)
+static int box_select_exec(bContext *C, wmOperator *op)
{
int event_type = RNA_int_get(op->ptr, "event_type");
if (event_type == LEFTMOUSE)
- printf("border select do select\n");
+ printf("box select do select\n");
else if (event_type == RIGHTMOUSE)
- printf("border select deselect\n");
+ printf("box select deselect\n");
else
- printf("border select do something\n");
+ printf("box select do something\n");
return 1;
}
-static void SCREEN_OT_border_select(wmOperatorType *ot)
+static void SCREEN_OT_box_select(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "SCREEN_OT_border_select";
+ ot->name = "Box Select";
+ ot->idname = "SCREEN_OT_box_select";
/* api callbacks */
- ot->exec = border_select_exec;
- ot->invoke = WM_gesture_border_invoke;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->exec = box_select_exec;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_areaactive;
@@ -4072,8 +4339,8 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- int sizex = 800 * UI_DPI_FAC;
- int sizey = 480 * UI_DPI_FAC;
+ int sizex = (800 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC;
+ int sizey = 500 * UI_DPI_FAC;
/* changes context! */
if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) {
@@ -4089,8 +4356,8 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Show User Preferences";
- ot->description = "Show user preferences";
+ ot->name = "Show Preferences";
+ ot->description = "Edit user preferences and system settings";
ot->idname = "SCREEN_OT_userpref_show";
/* api callbacks */
@@ -4101,118 +4368,101 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name New Screen Operator
+/** \name Show Drivers Editor Operator
* \{ */
-static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
+static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Main *bmain = CTX_data_main(C);
- wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index = -1;
+ uiBut *but = NULL;
- sc = ED_screen_duplicate(bmain, win, sc);
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENBROWSE, sc);
+ int sizex = 900 * UI_DPI_FAC;
+ int sizey = 580 * UI_DPI_FAC;
- return OPERATOR_FINISHED;
-}
+ /* Get active property to show driver for
+ * - Need to grab it first, or else this info disappears
+ * after we've created the window
+ */
+ but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
-static void SCREEN_OT_new(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "New Screen";
- ot->description = "Add a new screen";
- ot->idname = "SCREEN_OT_new";
+ /* changes context! */
+ if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_DRIVERS) != NULL) {
+ /* activate driver F-Curve for the property under the cursor */
+ if (but) {
+ FCurve *fcu;
+ bool driven, special;
+
+ fcu = rna_get_fcurve_context_ui(C,
+ &ptr, prop, index,
+ NULL, NULL, &driven, &special);
+ if (fcu) {
+ /* Isolate this F-Curve... */
+ bAnimContext ac;
+ if (ANIM_animdata_get_context(C, &ac)) {
+ int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS;
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_set_active_channel(&ac, ac.data, ac.datatype, filter, fcu, ANIMTYPE_FCURVE);
+ }
+ else {
+ /* Just blindly isolate... This isn't the best, and shouldn't happen, but may be enough... */
+ fcu->flag |= (FCURVE_ACTIVE | FCURVE_SELECTED);
+ }
+ }
+ }
- /* api callbacks */
- ot->exec = screen_new_exec;
- ot->poll = WM_operator_winactive;
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
+ return OPERATOR_CANCELLED;
+ }
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Delete Screen Operator
- * \{ */
-
-static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bScreen *sc = CTX_wm_screen(C);
-
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENDELETE, sc);
-
- return OPERATOR_FINISHED;
-}
-static void SCREEN_OT_delete(wmOperatorType *ot)
+static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete Screen";
- ot->description = "Delete active screen";
- ot->idname = "SCREEN_OT_delete";
+ ot->name = "Show Drivers Editor";
+ ot->description = "Show drivers editor in a separate window";
+ ot->idname = "SCREEN_OT_drivers_editor_show";
/* api callbacks */
- ot->exec = screen_delete_exec;
+ ot->invoke = drivers_editor_show_invoke;
+ ot->poll = ED_operator_screenactive;
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name New Scene Operator
+/** \name New Screen Operator
* \{ */
-static int scene_new_exec(bContext *C, wmOperator *op)
+static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *newscene, *scene = CTX_data_scene(C);
Main *bmain = CTX_data_main(C);
- int type = RNA_enum_get(op->ptr, "type");
-
- if (type == SCE_COPY_NEW) {
- newscene = BKE_scene_add(bmain, DATA_("Scene"));
- }
- else { /* different kinds of copying */
- newscene = BKE_scene_copy(bmain, scene, type);
-
- /* these can't be handled in blenkernel currently, so do them here */
- if (type == SCE_COPY_LINK_DATA) {
- ED_object_single_users(bmain, newscene, false, true);
- }
- else if (type == SCE_COPY_FULL) {
- ED_editors_flush_edits(C, false);
- ED_object_single_users(bmain, newscene, true, true);
- }
- }
-
- ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout_old = BKE_workspace_active_layout_get(win->workspace_hook);
+ WorkSpaceLayout *layout_new;
- WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, newscene);
+ layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new);
return OPERATOR_FINISHED;
}
-static void SCENE_OT_new(wmOperatorType *ot)
+static void SCREEN_OT_new(wmOperatorType *ot)
{
- static const EnumPropertyItem type_items[] = {
- {SCE_COPY_NEW, "NEW", 0, "New", "Add new scene"},
- {SCE_COPY_EMPTY, "EMPTY", 0, "Copy Settings", "Make a copy without any objects"},
- {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
- {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
- {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
- {0, NULL, 0, NULL, NULL}};
-
/* identifiers */
- ot->name = "New Scene";
- ot->description = "Add new scene by type";
- ot->idname = "SCENE_OT_new";
+ ot->name = "New Screen";
+ ot->description = "Add a new screen";
+ ot->idname = "SCREEN_OT_new";
/* api callbacks */
- ot->exec = scene_new_exec;
- ot->invoke = WM_menu_invoke;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
+ ot->exec = screen_new_exec;
+ ot->poll = WM_operator_winactive;
}
/** \} */
@@ -4221,34 +4471,26 @@ static void SCENE_OT_new(wmOperatorType *ot)
/** \name Delete Screen Operator
* \{ */
-static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
+static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
-
- if (ED_screen_delete_scene(C, scene) == false) {
- return OPERATOR_CANCELLED;
- }
-
- if (G.debug & G_DEBUG)
- printf("scene delete %p\n", scene);
+ bScreen *sc = CTX_wm_screen(C);
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
- WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTDELETE, layout);
return OPERATOR_FINISHED;
}
-static void SCENE_OT_delete(wmOperatorType *ot)
+static void SCREEN_OT_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete Scene";
- ot->description = "Delete active scene";
- ot->idname = "SCENE_OT_delete";
+ ot->name = "Delete Screen";
+ ot->description = "Delete active screen";
+ ot->idname = "SCREEN_OT_delete";
/* api callbacks */
- ot->exec = scene_delete_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->exec = screen_delete_exec;
}
/** \} */
@@ -4267,10 +4509,10 @@ typedef struct RegionAlphaInfo {
int hidden;
} RegionAlphaInfo;
-#define TIMEOUT 0.2f
-#define TIMESTEP 0.04f
+#define TIMEOUT 0.1f
+#define TIMESTEP (1.0f / 60.0f)
-float ED_region_blend_factor(ARegion *ar)
+float ED_region_blend_alpha(ARegion *ar)
{
/* check parent too */
if (ar->regiontimer == NULL && (ar->alignment & RGN_SPLIT_PREV) && ar->prev) {
@@ -4399,15 +4641,72 @@ static void SCREEN_OT_region_blend(wmOperatorType *ot)
/** \} */
+
/* -------------------------------------------------------------------- */
-/** \name Space Context Cycle Operator
+/** \name Space Type Set or Cycle Operator
* \{ */
-/* SCREEN_OT_space_context_cycle direction */
-enum {
- SPACE_CONTEXT_CYCLE_PREV,
- SPACE_CONTEXT_CYCLE_NEXT,
-};
+static int space_type_set_or_cycle_exec(bContext *C, wmOperator *op)
+{
+ const int space_type = RNA_enum_get(op->ptr, "space_type");
+
+ PointerRNA ptr;
+ ScrArea *sa = CTX_wm_area(C);
+ RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Area, sa, &ptr);
+ PropertyRNA *prop_type = RNA_struct_find_property(&ptr, "type");
+ PropertyRNA *prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
+
+ if (sa->spacetype != space_type) {
+ /* Set the type. */
+ RNA_property_enum_set(&ptr, prop_type, space_type);
+ RNA_property_update(C, &ptr, prop_type);
+ }
+ else {
+ /* Types match, cycle the subtype. */
+ const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
+ const EnumPropertyItem *item;
+ int item_len;
+ bool free;
+ RNA_property_enum_items(C, &ptr, prop_ui_type, &item, &item_len, &free);
+ int index = RNA_enum_from_value(item, space_type_ui);
+ for (int i = 1; i < item_len; i++) {
+ const EnumPropertyItem *item_test = &item[(index + i) % item_len];
+ if ((item_test->value >> 16) == space_type) {
+ RNA_property_enum_set(&ptr, prop_ui_type, item_test->value);
+ RNA_property_update(C, &ptr, prop_ui_type);
+ break;
+ }
+ }
+ if (free) {
+ MEM_freeN((void *)item);
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCREEN_OT_space_type_set_or_cycle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cycle Space Type Set";
+ ot->description = "Set the space type or cycle subtype";
+ ot->idname = "SCREEN_OT_space_type_set_or_cycle";
+
+ /* api callbacks */
+ ot->exec = space_type_set_or_cycle_exec;
+ ot->poll = ED_operator_areaactive;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Type", "");
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Space Context Cycle Operator
+ * \{ */
static const EnumPropertyItem space_context_cycle_direction[] = {
{SPACE_CONTEXT_CYCLE_PREV, "PREV", 0, "Previous", ""},
@@ -4456,11 +4755,10 @@ static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent
PointerRNA ptr;
PropertyRNA *prop;
context_cycle_prop_get(CTX_wm_screen(C), CTX_wm_area(C), &ptr, &prop);
-
const int old_context = RNA_property_enum_get(&ptr, prop);
const int new_context = RNA_property_enum_step(
- C, &ptr, prop, old_context,
- direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
+ C, &ptr, prop, old_context,
+ direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
RNA_property_enum_set(&ptr, prop, new_context);
RNA_property_update(C, &ptr, prop);
@@ -4487,6 +4785,73 @@ static void SCREEN_OT_space_context_cycle(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Workspace Cycle Operator
+ * \{ */
+
+static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindow *win = CTX_wm_window(C);
+ if (WM_window_is_temp_screen(win)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Main *bmain = CTX_data_main(C);
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ WorkSpace *workspace_src = WM_window_get_active_workspace(win);
+ WorkSpace *workspace_dst = NULL;
+
+ ListBase ordered;
+ BKE_id_ordered_list(&ordered, &bmain->workspaces);
+
+ for (LinkData *link = ordered.first; link; link = link->next) {
+ if (link->data == workspace_src) {
+ if (direction == SPACE_CONTEXT_CYCLE_PREV) {
+ workspace_dst = (link->prev) ? link->prev->data : NULL;
+ }
+ else {
+ workspace_dst = (link->next) ? link->next->data : NULL;
+ }
+ }
+ }
+
+ if (workspace_dst == NULL) {
+ LinkData *link = (direction == SPACE_CONTEXT_CYCLE_PREV) ? ordered.last : ordered.first;
+ workspace_dst = link->data;
+ }
+
+ BLI_freelistN(&ordered);
+
+ if (workspace_src == workspace_dst) {
+ return OPERATOR_CANCELLED;
+ }
+
+ win->workspace_hook->temp_workspace_store = workspace_dst;
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, workspace_dst);
+ win->workspace_hook->temp_workspace_store = NULL;
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCREEN_OT_workspace_cycle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cycle Workspace";
+ ot->description = "Cycle through workspaces";
+ ot->idname = "SCREEN_OT_workspace_cycle";
+
+ /* api callbacks */
+ ot->invoke = space_workspace_cycle_invoke;
+ ot->poll = ED_operator_screenactive;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "direction", space_context_cycle_direction, SPACE_CONTEXT_CYCLE_NEXT, "Direction",
+ "Direction to cycle through");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Assigning Operator Types
* \{ */
@@ -4511,15 +4876,18 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_region_flip);
WM_operatortype_append(SCREEN_OT_header);
WM_operatortype_append(SCREEN_OT_header_toggle_menus);
- WM_operatortype_append(SCREEN_OT_header_toolbox);
+ WM_operatortype_append(SCREEN_OT_header_context_menu);
WM_operatortype_append(SCREEN_OT_screen_set);
WM_operatortype_append(SCREEN_OT_screen_full_area);
WM_operatortype_append(SCREEN_OT_back_to_previous);
WM_operatortype_append(SCREEN_OT_spacedata_cleanup);
WM_operatortype_append(SCREEN_OT_screenshot);
WM_operatortype_append(SCREEN_OT_userpref_show);
+ WM_operatortype_append(SCREEN_OT_drivers_editor_show);
WM_operatortype_append(SCREEN_OT_region_blend);
+ WM_operatortype_append(SCREEN_OT_space_type_set_or_cycle);
WM_operatortype_append(SCREEN_OT_space_context_cycle);
+ WM_operatortype_append(SCREEN_OT_workspace_cycle);
/*frame changes*/
WM_operatortype_append(SCREEN_OT_frame_offset);
@@ -4534,8 +4902,6 @@ void ED_operatortypes_screen(void)
/* new/delete */
WM_operatortype_append(SCREEN_OT_new);
WM_operatortype_append(SCREEN_OT_delete);
- WM_operatortype_append(SCENE_OT_new);
- WM_operatortype_append(SCENE_OT_delete);
/* tools shared by more space types */
WM_operatortype_append(ED_OT_undo);
@@ -4567,19 +4933,11 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
/* Standard Modal keymap ------------------------------------------------ */
keymap = WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items);
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
-
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_SNAP_ON);
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_SNAP_OFF);
-
WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
}
-static bool open_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool blend_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
if (drag->type == WM_DRAG_PATH) {
if (drag->icon == ICON_FILE_BLEND)
@@ -4588,11 +4946,10 @@ static bool open_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
return 0;
}
-static void open_file_drop_copy(wmDrag *drag, wmDropBox *drop)
+static void blend_file_drop_copy(wmDrag *drag, wmDropBox *drop)
{
/* copy drag path to properties */
RNA_string_set(drop->ptr, "filepath", drag->path);
- drop->opcontext = WM_OP_EXEC_DEFAULT;
}
@@ -4600,155 +4957,23 @@ static void open_file_drop_copy(wmDrag *drag, wmDropBox *drop)
void ED_keymap_screen(wmKeyConfig *keyconf)
{
ListBase *lb;
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
/* Screen Editing ------------------------------------------------ */
- keymap = WM_keymap_ensure(keyconf, "Screen Editing", 0, 0);
-
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "modifier", 2);
-
- /* screen tools */
- WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
- WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
- WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
- WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", EVT_ACTIONZONE_FULLSCREEN, 0, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
- /* area move after action zones */
- WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_verify_item(keymap, "SCREEN_OT_area_options", RIGHTMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "SCREEN_OT_header", F9KEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_ensure(keyconf, "Screen Editing", 0, 0);
/* Header Editing ------------------------------------------------ */
/* note: this is only used when the cursor is inside the header */
- keymap = WM_keymap_ensure(keyconf, "Header", 0, 0);
-
- WM_keymap_add_item(keymap, "SCREEN_OT_header_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_ensure(keyconf, "Header", 0, 0);
/* Screen General ------------------------------------------------ */
- keymap = WM_keymap_ensure(keyconf, "Screen", 0, 0);
-
- /* standard timers */
- WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
- WM_keymap_add_item(keymap, "SCREEN_OT_region_blend", TIMERREGION, KM_ANY, KM_ANY, 0);
-
-
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
- WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", F10KEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
-
- WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
-
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_space_context_cycle", TABKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_NEXT);
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_space_context_cycle", TABKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_PREV);
-
- /* tests */
- WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "SCREEN_OT_repeat_last", RKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_verify_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "SCRIPT_OT_reload", F8KEY, KM_PRESS, 0, 0);
-
- /* files */
- WM_keymap_add_item(keymap, "FILE_OT_execute", RETKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_execute", PADENTER, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
-
- /* undo */
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "ED_OT_undo_history", ZKEY, KM_PRESS, KM_ALT | KM_OSKEY, 0);
-#endif
- WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ED_OT_undo_history", ZKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
-
-
- /* render */
- kmi = WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_viewport", true);
- kmi = WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "animation", true);
- RNA_boolean_set(kmi->ptr, "use_viewport", true);
- WM_keymap_add_item(keymap, "RENDER_OT_view_cancel", ESCKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "RENDER_OT_view_show", F11KEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "RENDER_OT_play_rendered_anim", F11KEY, KM_PRESS, KM_CTRL, 0);
-
- /* user prefs */
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", COMMAKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
- WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", UKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
-
+ WM_keymap_ensure(keyconf, "Screen", 0, 0);
/* Anim Playback ------------------------------------------------ */
- keymap = WM_keymap_ensure(keyconf, "Frames", 0, 0);
-
- /* frame offsets */
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "delta", 10);
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "delta", -10);
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
-
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELUPMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", -1);
-
- RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", UPARROWKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "end", true);
- RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", DOWNARROWKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "end", false);
- RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", true);
- RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", false);
-
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", UPARROWKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "next", true);
-
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", DOWNARROWKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "next", false);
-
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", MEDIALAST, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "next", true);
-
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", MEDIAFIRST, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "next", false);
-
-
- /* play (forward and backwards) */
- WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0)->ptr, "reverse", true);
- WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", ESCKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", MEDIAPLAY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", MEDIASTOP, KM_PRESS, 0, 0);
-
- /* Alternative keys for animation and sequencer playing */
-#if 0 /* XXX: disabled for restoring later... bad implementation */
- keymap = WM_keymap_ensure(keyconf, "Frames", 0, 0);
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "cycle_speed", true);
-
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", LEFTARROWKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "reverse", true);
- RNA_boolean_set(kmi->ptr, "cycle_speed", true);
-
- WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", DOWNARROWKEY, KM_PRESS, KM_ALT, 0);
-#endif
+ WM_keymap_ensure(keyconf, "Frames", 0, 0);
/* dropbox for entire window */
lb = WM_dropboxmap_find("Window", 0, 0);
- WM_dropbox_add(lb, "WM_OT_open_mainfile", open_file_drop_poll, open_file_drop_copy);
+ WM_dropbox_add(lb, "WM_OT_drop_blend_file", blend_file_drop_poll, blend_file_drop_copy);
WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy);
keymap_modal_set(keyconf);
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
new file mode 100644
index 00000000000..45f82618d2e
--- /dev/null
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -0,0 +1,278 @@
+/*
+ * ***** 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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/screen/screen_user_menu.c
+ * \ingroup spview3d
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_blender_user_menu.h"
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_idprop.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Type
+ * \{ */
+
+bUserMenu *ED_screen_user_menu_find(bContext *C)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ const char *context = CTX_data_mode_string(C);
+ return BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
+}
+
+bUserMenu *ED_screen_user_menu_ensure(bContext *C)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ const char *context = CTX_data_mode_string(C);
+ return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Item
+ * \{ */
+
+bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(
+ ListBase *lb,
+ const wmOperatorType *ot, IDProperty *prop, short opcontext)
+{
+ for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ if (STREQ(ot->idname, umi_op->op_idname) &&
+ (opcontext == umi_op->opcontext) &&
+ (IDP_EqualsProperties(prop, umi_op->prop)))
+ {
+ return umi_op;
+ }
+ }
+ }
+ return NULL;
+}
+
+struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(
+ struct ListBase *lb,
+ const struct MenuType *mt)
+{
+ for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ if (umi->type == USER_MENU_TYPE_MENU) {
+ bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
+ if (STREQ(mt->idname, umi_mt->mt_idname)) {
+ return umi_mt;
+ }
+ }
+ }
+ return NULL;
+}
+
+struct bUserMenuItem_Prop *ED_screen_user_menu_item_find_prop(
+ struct ListBase *lb,
+ const char *context_data_path, const char *prop_id, int prop_index)
+{
+ for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ if (umi->type == USER_MENU_TYPE_PROP) {
+ bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
+ if (STREQ(context_data_path, umi_pr->context_data_path) &&
+ STREQ(prop_id, umi_pr->prop_id) &&
+ (prop_index == umi_pr->prop_index))
+ {
+ return umi_pr;
+ }
+ }
+ }
+ return NULL;
+}
+
+void ED_screen_user_menu_item_add_operator(
+ ListBase *lb, const char *ui_name,
+ const wmOperatorType *ot, const IDProperty *prop, short opcontext)
+{
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)BKE_blender_user_menu_item_add(lb, USER_MENU_TYPE_OPERATOR);
+ umi_op->opcontext = opcontext;
+ if (!STREQ(ui_name, ot->name)) {
+ STRNCPY(umi_op->item.ui_name, ui_name);
+ }
+ STRNCPY(umi_op->op_idname, ot->idname);
+ umi_op->prop = prop ? IDP_CopyProperty(prop) : NULL;
+}
+
+void ED_screen_user_menu_item_add_menu(
+ ListBase *lb, const char *ui_name,
+ const MenuType *mt)
+{
+ bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)BKE_blender_user_menu_item_add(lb, USER_MENU_TYPE_MENU);
+ if (!STREQ(ui_name, mt->label)) {
+ STRNCPY(umi_mt->item.ui_name, ui_name);
+ }
+ STRNCPY(umi_mt->mt_idname, mt->idname);
+}
+
+void ED_screen_user_menu_item_add_prop(
+ ListBase *lb, const char *ui_name,
+ const char *context_data_path, const char *prop_id, int prop_index)
+{
+ bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)BKE_blender_user_menu_item_add(lb, USER_MENU_TYPE_PROP);
+ STRNCPY(umi_pr->item.ui_name, ui_name);
+ STRNCPY(umi_pr->context_data_path, context_data_path);
+ STRNCPY(umi_pr->prop_id, prop_id);
+ umi_pr->prop_index = prop_index;
+}
+
+void ED_screen_user_menu_item_remove(ListBase *lb, bUserMenuItem *umi)
+{
+ BLI_remlink(lb, umi);
+ BKE_blender_user_menu_item_free(umi);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Definition
+ * \{ */
+
+static void screen_user_menu_draw(const bContext *C, Menu *menu)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ const char *context = CTX_data_mode_string(C);
+ bUserMenu *um_array[] = {
+ BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context),
+ (sl->spacetype != SPACE_TOPBAR) ? BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context) : NULL,
+ (sl->spacetype == SPACE_VIEW3D) ? BKE_blender_user_menu_find(&U.user_menus, SPACE_BUTS, context) : NULL,
+ };
+ bool is_empty = true;
+ for (int um_index = 0; um_index < ARRAY_SIZE(um_array); um_index++) {
+ bUserMenu *um = um_array[um_index];
+ if (um == NULL) {
+ continue;
+ }
+ for (bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
+ const char *ui_name = umi->ui_name[0] ? umi->ui_name : NULL;
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
+ uiItemFullO(
+ menu->layout, umi_op->op_idname, ui_name,
+ ICON_NONE, prop, umi_op->opcontext, 0, NULL);
+ is_empty = false;
+ }
+ else if (umi->type == USER_MENU_TYPE_MENU) {
+ bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
+ uiItemM(menu->layout, umi_mt->mt_idname, ui_name,
+ ICON_NONE);
+ is_empty = false;
+ }
+ else if (umi->type == USER_MENU_TYPE_PROP) {
+ bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
+
+ char *data_path = strchr(umi_pr->context_data_path, '.');
+ if (data_path) {
+ *data_path = '\0';
+ }
+ PointerRNA ptr = CTX_data_pointer_get(C, umi_pr->context_data_path);
+ if (ptr.type == NULL) {
+ PointerRNA ctx_ptr;
+ RNA_pointer_create(NULL, &RNA_Context, (void *)C, &ctx_ptr);
+ if (!RNA_path_resolve_full(&ctx_ptr, umi_pr->context_data_path, &ptr, NULL, NULL)) {
+ ptr.type = NULL;
+ }
+ }
+ if (data_path) {
+ *data_path = '.';
+ data_path += 1;
+ }
+
+ bool ok = false;
+ if (ptr.type != NULL) {
+ PropertyRNA *prop = NULL;
+ PointerRNA prop_ptr = ptr;
+ if ((data_path == NULL) || RNA_path_resolve_full(&ptr, data_path, &prop_ptr, NULL, NULL)) {
+ prop = RNA_struct_find_property(&prop_ptr, umi_pr->prop_id);
+ if (prop) {
+ ok = true;
+ uiItemFullR(
+ menu->layout,
+ &prop_ptr, prop, umi_pr->prop_index,
+ 0, 0, ui_name, ICON_NONE);
+ is_empty = false;
+ }
+ }
+ }
+ if (!ok) {
+ char label[512];
+ SNPRINTF(label, "Missing: %s.%s", umi_pr->context_data_path, umi_pr->prop_id);
+ uiItemL(menu->layout, label, ICON_NONE);
+ }
+ }
+ else if (umi->type == USER_MENU_TYPE_SEP) {
+ uiItemS(menu->layout);
+ }
+ }
+ }
+
+ if (is_empty) {
+ uiItemL(menu->layout, IFACE_("No menu items found."), ICON_NONE);
+ uiItemL(menu->layout, IFACE_("Right click on buttons to add them to this menu."), ICON_NONE);
+ }
+}
+
+void ED_screen_user_menu_register(void)
+{
+ MenuType *mt = MEM_callocN(sizeof(MenuType), __func__);
+ strcpy(mt->idname, "SCREEN_MT_user_menu");
+ strcpy(mt->label, "Quick Favorites");
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = screen_user_menu_draw;
+ WM_menutype_add(mt);
+}
+
+/** \} */
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 3ec2078a4d1..8e3b32941e5 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -46,8 +46,8 @@
#include "BKE_context.h"
#include "BKE_global.h"
-#include "BKE_main.h"
#include "BKE_image.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BIF_gl.h"
@@ -266,7 +266,7 @@ static void screenshot_draw(bContext *UNUSED(C), wmOperator *op)
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
- uiDefAutoButsRNA(layout, &ptr, screenshot_draw_check_prop, NULL, '\0');
+ uiDefAutoButsRNA(layout, &ptr, screenshot_draw_check_prop, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
}
static bool screenshot_poll(bContext *C)
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
new file mode 100644
index 00000000000..d8e0945eb25
--- /dev/null
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -0,0 +1,601 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/screen/workspace_edit.c
+ * \ingroup edscr
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_appdir.h"
+#include "BKE_blendfile.h"
+#include "BKE_context.h"
+#include "BKE_idcode.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
+
+#include "BLO_readfile.h"
+
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
+
+#include "ED_datafiles.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "DEG_depsgraph.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BLT_translation.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_toolsystem.h"
+
+#include "screen_intern.h"
+
+
+/** \name Workspace API
+ *
+ * \brief API for managing workspaces and their data.
+ * \{ */
+
+WorkSpace *ED_workspace_add(Main *bmain, const char *name)
+{
+ return BKE_workspace_add(bmain, name);
+}
+
+/**
+ * Changes the object mode (if needed) to the one set in \a workspace_new.
+ * Object mode is still stored on object level. In future it should all be workspace level instead.
+ */
+static void workspace_change_update(
+ WorkSpace *workspace_new, const WorkSpace *workspace_old,
+ bContext *C, wmWindowManager *wm)
+{
+ /* needs to be done before changing mode! (to ensure right context) */
+ UNUSED_VARS(workspace_old, workspace_new, C, wm);
+#if 0
+ Object *ob_act = CTX_data_active_object(C)
+ eObjectMode mode_old = workspace_old->object_mode;
+ eObjectMode mode_new = workspace_new->object_mode;
+
+ if (mode_old != mode_new) {
+ ED_object_mode_compat_set(C, ob_act, mode_new, &wm->reports);
+ ED_object_mode_toggle(C, mode_new);
+ }
+#endif
+}
+
+static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
+{
+ /* return false to stop the iterator if we've found a layout that can be activated */
+ return workspace_layout_set_poll(layout) ? false : true;
+}
+
+static WorkSpaceLayout *workspace_change_get_new_layout(
+ Main *bmain, WorkSpace *workspace_new, wmWindow *win)
+{
+ /* ED_workspace_duplicate may have stored a layout to activate once the workspace gets activated. */
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
+ WorkSpaceLayout *layout_new;
+ bScreen *screen_new;
+
+ if (win->workspace_hook->temp_workspace_store) {
+ layout_new = win->workspace_hook->temp_layout_store;
+ }
+ else {
+ layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new);
+ if (!layout_new) {
+ layout_new = BKE_workspace_layouts_get(workspace_new)->first;
+ }
+ }
+ screen_new = BKE_workspace_layout_screen_get(layout_new);
+
+ if (screen_new->winid) {
+ /* screen is already used, try to find a free one */
+ WorkSpaceLayout *layout_temp = BKE_workspace_layout_iter_circular(
+ workspace_new, layout_new, workspace_change_find_new_layout_cb,
+ NULL, false);
+ if (!layout_temp) {
+ /* fallback solution: duplicate layout from old workspace */
+ layout_temp = ED_workspace_layout_duplicate(bmain, workspace_new, layout_old, win);
+ }
+ layout_new = layout_temp;
+ }
+
+ return layout_new;
+}
+
+/**
+ * \brief Change the active workspace.
+ *
+ * Operator call, WM + Window + screen already existed before
+ * Pretty similar to #ED_screen_change since changing workspace also changes screen.
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if workspace changing was successful.
+ */
+bool ED_workspace_change(
+ WorkSpace *workspace_new, bContext *C, wmWindowManager *wm, wmWindow *win)
+{
+ Main *bmain = CTX_data_main(C);
+ WorkSpace *workspace_old = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout_new = workspace_change_get_new_layout(bmain, workspace_new, win);
+ bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
+ bScreen *screen_old = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ win->workspace_hook->temp_layout_store = NULL;
+ if (workspace_old == workspace_new) {
+ /* Could also return true, everything that needs to be done was done (nothing :P), but nothing changed */
+ return false;
+ }
+
+ screen_new = screen_change_prepare(screen_old, screen_new, bmain, C, win);
+ BLI_assert(BKE_workspace_layout_screen_get(layout_new) == screen_new);
+
+ if (screen_new == NULL) {
+ return false;
+ }
+
+ BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace_new, layout_new);
+ BKE_workspace_active_set(win->workspace_hook, workspace_new);
+
+ /* update screen *after* changing workspace - which also causes the
+ * actual screen change and updates context (including CTX_wm_workspace) */
+ screen_change_update(C, win, screen_new);
+ workspace_change_update(workspace_new, workspace_old, C, wm);
+
+ BLI_assert(CTX_wm_workspace(C) == workspace_new);
+
+ WM_toolsystem_unlink_all(C, workspace_old);
+ /* Area initialization will initialize based on the new workspace. */
+
+ /* Automatic mode switching. */
+ if (workspace_new->object_mode != workspace_old->object_mode) {
+ ED_object_mode_generic_enter(C, workspace_new->object_mode);
+ }
+
+ return true;
+}
+
+/**
+ * Duplicate a workspace including its layouts. Does not activate the workspace, but
+ * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
+ */
+WorkSpace *ED_workspace_duplicate(
+ WorkSpace *workspace_old, Main *bmain, wmWindow *win)
+{
+ WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
+ ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old);
+ WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2);
+
+ /* TODO(campbell): tools */
+
+ for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) {
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace_new, layout_old, win);
+
+ if (layout_active_old == layout_old) {
+ win->workspace_hook->temp_layout_store = layout_new;
+ }
+ }
+ return workspace_new;
+}
+
+/**
+ * \return if succeeded.
+ */
+bool ED_workspace_delete(
+ WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm)
+{
+ ID *workspace_id = (ID *)workspace;
+
+ if (BLI_listbase_is_single(&bmain->workspaces)) {
+ return false;
+ }
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpace *prev = workspace_id->prev;
+ WorkSpace *next = workspace_id->next;
+
+ ED_workspace_change((prev != NULL) ? prev : next, C, wm, win);
+ }
+ BKE_libblock_free(bmain, workspace_id);
+
+ return true;
+}
+
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors in active layout of \a workspace.
+ */
+void ED_workspace_scene_data_sync(
+ WorkSpaceInstanceHook *hook, Scene *scene)
+{
+ bScreen *screen = BKE_workspace_active_screen_get(hook);
+ BKE_screen_view3d_scene_sync(screen, scene);
+}
+
+/** \} Workspace API */
+
+
+/** \name Workspace Operators
+ *
+ * \{ */
+
+static WorkSpace *workspace_context_get(bContext *C)
+{
+ ID *id = UI_context_active_but_get_tab_ID(C);
+ if (id && GS(id->name) == ID_WS) {
+ return (WorkSpace *)id;
+ }
+
+ wmWindow *win = CTX_wm_window(C);
+ return WM_window_get_active_workspace(win);
+}
+
+static bool workspace_context_poll(bContext *C)
+{
+ return workspace_context_get(C) != NULL;
+}
+
+static int workspace_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = workspace_context_get(C);
+
+ workspace = ED_workspace_duplicate(workspace, bmain, win);
+
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, workspace);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WORKSPACE_OT_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Workspace";
+ ot->description = "Add a new workspace";
+ ot->idname = "WORKSPACE_OT_duplicate";
+
+ /* api callbacks */
+ ot->poll = workspace_context_poll;
+ ot->exec = workspace_new_exec;
+}
+
+static int workspace_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ WorkSpace *workspace = workspace_context_get(C);
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_DELETE, workspace);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WORKSPACE_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Workspace";
+ ot->description = "Delete the active workspace";
+ ot->idname = "WORKSPACE_OT_delete";
+
+ /* api callbacks */
+ ot->poll = workspace_context_poll;
+ ot->exec = workspace_delete_exec;
+}
+
+static bool workspace_append_activate_poll(bContext *C)
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false);
+ return WM_operator_poll(C, ot);
+}
+
+static int workspace_append(bContext *C, const char *directory, const char *idname)
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false);
+ PointerRNA opptr;
+ int retval;
+
+ WM_operator_properties_create_ptr(&opptr, ot);
+ RNA_string_set(&opptr, "directory", directory);
+ RNA_string_set(&opptr, "filename", idname);
+ RNA_boolean_set(&opptr, "autoselect", false);
+
+ retval = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &opptr);
+
+ WM_operator_properties_free(&opptr);
+
+ return retval;
+}
+
+static int workspace_append_activate_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ char idname[MAX_ID_NAME - 2], filepath[FILE_MAX];
+
+ if (!RNA_struct_property_is_set(op->ptr, "idname") ||
+ !RNA_struct_property_is_set(op->ptr, "filepath"))
+ {
+ return OPERATOR_CANCELLED;
+ }
+ RNA_string_get(op->ptr, "idname", idname);
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (workspace_append(C, filepath, idname) != OPERATOR_CANCELLED) {
+ WorkSpace *appended_workspace = BLI_findstring(&bmain->workspaces, idname, offsetof(ID, name) + 2);
+ BLI_assert(appended_workspace != NULL);
+
+ /* Reorder to last position. */
+ BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true);
+
+ /* Changing workspace changes context. Do delayed! */
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static void WORKSPACE_OT_append_activate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Append and Activate Workspace";
+ ot->description = "Append a workspace and make it the active one in the current window";
+ ot->idname = "WORKSPACE_OT_append_activate";
+
+ /* api callbacks */
+ ot->exec = workspace_append_activate_exec;
+ ot->poll = workspace_append_activate_poll;
+
+ RNA_def_string(ot->srna, "idname", NULL, MAX_ID_NAME - 2, "Identifier",
+ "Name of the workspace to append and activate");
+ RNA_def_string(ot->srna, "filepath", NULL, FILE_MAX, "Filepath",
+ "Path to the library");
+}
+
+static WorkspaceConfigFileData *workspace_config_file_read(const char *app_template)
+{
+ const char *cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, app_template);
+ char startup_file_path[FILE_MAX] = {0};
+
+ if (cfgdir) {
+ BLI_join_dirfile(startup_file_path, sizeof(startup_file_path), cfgdir, BLENDER_STARTUP_FILE);
+ }
+
+ bool has_path = BLI_exists(startup_file_path);
+ return (has_path) ? BKE_blendfile_workspace_config_read(startup_file_path, NULL, 0, NULL) : NULL;
+}
+
+static WorkspaceConfigFileData *workspace_system_file_read(const char *app_template)
+{
+ if (app_template == NULL) {
+ return BKE_blendfile_workspace_config_read(NULL, datatoc_startup_blend, datatoc_startup_blend_size, NULL);
+ }
+
+ char template_dir[FILE_MAX];
+ if (!BKE_appdir_app_template_id_search(app_template, template_dir, sizeof(template_dir))) {
+ return NULL;
+ }
+
+ char startup_file_path[FILE_MAX];
+ BLI_join_dirfile(startup_file_path, sizeof(startup_file_path), template_dir, BLENDER_STARTUP_FILE);
+
+ bool has_path = BLI_exists(startup_file_path);
+ return (has_path) ? BKE_blendfile_workspace_config_read(startup_file_path, NULL, 0, NULL) : NULL;
+}
+
+static void workspace_append_button(
+ uiLayout *layout, wmOperatorType *ot_append, const WorkSpace *workspace, const Main *from_main)
+{
+ const ID *id = (ID *)workspace;
+ PointerRNA opptr;
+ char lib_path[FILE_MAX_LIBEXTRA];
+ const char *filepath = from_main->name;
+
+ if (strlen(filepath) == 0) {
+ filepath = BLO_EMBEDDED_STARTUP_BLEND;
+ }
+
+ BLI_path_join(
+ lib_path, sizeof(lib_path), filepath, BKE_idcode_to_name(GS(id->name)), NULL);
+
+ BLI_assert(STREQ(ot_append->idname, "WORKSPACE_OT_append_activate"));
+ uiItemFullO_ptr(
+ layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL,
+ WM_OP_EXEC_DEFAULT, 0, &opptr);
+ RNA_string_set(&opptr, "idname", id->name + 2);
+ RNA_string_set(&opptr, "filepath", lib_path);
+}
+
+static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v)
+{
+ Main *bmain = CTX_data_main(C);
+ const char *app_template = template_v;
+ bool has_startup_items = false;
+
+ wmOperatorType *ot_append = WM_operatortype_find("WORKSPACE_OT_append_activate", true);
+ WorkspaceConfigFileData *startup_config = workspace_config_file_read(app_template);
+ WorkspaceConfigFileData *builtin_config = workspace_system_file_read(app_template);
+
+ if (startup_config) {
+ for (WorkSpace *workspace = startup_config->workspaces.first; workspace; workspace = workspace->id.next) {
+ uiLayout *row = uiLayoutRow(layout, false);
+ if (BLI_findstring(&bmain->workspaces, workspace->id.name, offsetof(ID, name))) {
+ uiLayoutSetActive(row, false);
+ }
+
+ workspace_append_button(row, ot_append, workspace, startup_config->main);
+ has_startup_items = true;
+ }
+ }
+
+ if (builtin_config) {
+ bool has_title = false;
+
+ for (WorkSpace *workspace = builtin_config->workspaces.first; workspace; workspace = workspace->id.next) {
+ if (startup_config && BLI_findstring(&startup_config->workspaces, workspace->id.name, offsetof(ID, name))) {
+ continue;
+ }
+
+ if (!has_title) {
+ if (has_startup_items) {
+ uiItemS(layout);
+ }
+ has_title = true;
+ }
+
+ uiLayout *row = uiLayoutRow(layout, false);
+ if (BLI_findstring(&bmain->workspaces, workspace->id.name, offsetof(ID, name))) {
+ uiLayoutSetActive(row, false);
+ }
+
+ workspace_append_button(row, ot_append, workspace, builtin_config->main);
+ }
+ }
+
+ if (startup_config) {
+ BKE_blendfile_workspace_config_data_free(startup_config);
+ }
+ if (builtin_config) {
+ BKE_blendfile_workspace_config_data_free(builtin_config);
+ }
+}
+
+static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ uiPopupMenu *pup = UI_popup_menu_begin(C, op->type->name, ICON_ADD);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ uiItemMenuF(layout, IFACE_("General"), ICON_NONE, workspace_add_menu, NULL);
+
+ ListBase templates;
+ BKE_appdir_app_templates(&templates);
+
+ for (LinkData *link = templates.first; link; link = link->next) {
+ char *template = link->data;
+ char display_name[FILE_MAX];
+
+ BLI_path_to_display_name(display_name, sizeof(display_name), template);
+
+ /* Steals ownership of link data string. */
+ uiItemMenuFN(layout, display_name, ICON_NONE, workspace_add_menu, template);
+ }
+
+ BLI_freelistN(&templates);
+
+ uiItemS(layout);
+ uiItemO(layout, "Duplicate Current", ICON_DUPLICATE, "WORKSPACE_OT_duplicate");
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+static void WORKSPACE_OT_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Workspace";
+ ot->description = "Add a new workspace by duplicating the current one or appending one "
+ "from the user configuration";
+ ot->idname = "WORKSPACE_OT_add";
+
+ /* api callbacks */
+ ot->invoke = workspace_add_invoke;
+}
+
+static int workspace_reorder_to_back_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ WorkSpace *workspace = workspace_context_get(C);
+
+ BKE_id_reorder(&bmain->workspaces, &workspace->id, NULL, true);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_INTERFACE;
+}
+
+static void WORKSPACE_OT_reorder_to_back(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Workspace Reorder to Back";
+ ot->description = "Reorder workspace to be first in the list";
+ ot->idname = "WORKSPACE_OT_reorder_to_back";
+
+ /* api callbacks */
+ ot->poll = workspace_context_poll;
+ ot->exec = workspace_reorder_to_back_exec;
+}
+
+static int workspace_reorder_to_front_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ WorkSpace *workspace = workspace_context_get(C);
+
+ BKE_id_reorder(&bmain->workspaces, &workspace->id, NULL, false);
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_INTERFACE;
+}
+
+static void WORKSPACE_OT_reorder_to_front(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Workspace Reorder to Front";
+ ot->description = "Reorder workspace to be first in the list";
+ ot->idname = "WORKSPACE_OT_reorder_to_front";
+
+ /* api callbacks */
+ ot->poll = workspace_context_poll;
+ ot->exec = workspace_reorder_to_front_exec;
+}
+
+void ED_operatortypes_workspace(void)
+{
+ WM_operatortype_append(WORKSPACE_OT_duplicate);
+ WM_operatortype_append(WORKSPACE_OT_delete);
+ WM_operatortype_append(WORKSPACE_OT_add);
+ WM_operatortype_append(WORKSPACE_OT_append_activate);
+ WM_operatortype_append(WORKSPACE_OT_reorder_to_back);
+ WM_operatortype_append(WORKSPACE_OT_reorder_to_front);
+}
+
+/** \} Workspace Operators */
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
new file mode 100644
index 00000000000..6d504c05dd1
--- /dev/null
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -0,0 +1,199 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/screen/workspace_layout_edit.c
+ * \ingroup edscr
+ */
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
+
+#include "WM_api.h"
+
+#include "ED_screen.h"
+
+#include "screen_intern.h"
+
+/**
+ * Empty screen, with 1 dummy area without spacedata. Uses window size.
+ */
+WorkSpaceLayout *ED_workspace_layout_add(
+ Main *bmain,
+ WorkSpace *workspace,
+ wmWindow *win,
+ const char *name)
+{
+ bScreen *screen;
+ rcti screen_rect;
+
+ WM_window_screen_rect_calc(win, &screen_rect);
+ screen = screen_add(bmain, name, &screen_rect);
+
+ return BKE_workspace_layout_add(bmain, workspace, screen, name);
+}
+
+WorkSpaceLayout *ED_workspace_layout_duplicate(
+ Main *bmain,
+ WorkSpace *workspace, const WorkSpaceLayout *layout_old,
+ wmWindow *win)
+{
+ bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
+ const char *name = BKE_workspace_layout_name_get(layout_old);
+ bScreen *screen_new;
+ WorkSpaceLayout *layout_new;
+
+ if (BKE_screen_is_fullscreen_area(screen_old)) {
+ return NULL; /* XXX handle this case! */
+ }
+
+ layout_new = ED_workspace_layout_add(bmain, workspace, win, name);
+ screen_new = BKE_workspace_layout_screen_get(layout_new);
+ screen_data_copy(screen_new, screen_old);
+
+ return layout_new;
+}
+
+static bool workspace_layout_delete_doit(
+ WorkSpace *workspace, WorkSpaceLayout *layout_old, WorkSpaceLayout *layout_new,
+ bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
+
+ ED_screen_change(C, screen_new);
+
+ if (BKE_workspace_active_layout_get(win->workspace_hook) != layout_old) {
+ BKE_workspace_layout_remove(bmain, workspace, layout_old);
+ return true;
+ }
+
+ return false;
+}
+
+bool workspace_layout_set_poll(const WorkSpaceLayout *layout)
+{
+ const bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ return ((BKE_screen_is_used(screen) == false) &&
+ /* in typical usage temp screens should have a nonzero winid
+ * (all temp screens should be used, or closed & freed). */
+ (screen->temp == false) &&
+ (BKE_screen_is_fullscreen_area(screen) == false) &&
+ (screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
+}
+
+static WorkSpaceLayout *workspace_layout_delete_find_new(const WorkSpaceLayout *layout_old)
+{
+ for (WorkSpaceLayout *layout_new = layout_old->prev; layout_new; layout_new = layout_new->next) {
+ if (workspace_layout_set_poll(layout_new)) {
+ return layout_new;
+ }
+ }
+
+ for (WorkSpaceLayout *layout_new = layout_old->next; layout_new; layout_new = layout_new->next) {
+ if (workspace_layout_set_poll(layout_new)) {
+ return layout_new;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * \warning Only call outside of area/region loops!
+ * \return true if succeeded.
+ */
+bool ED_workspace_layout_delete(
+ WorkSpace *workspace, WorkSpaceLayout *layout_old,
+ bContext *C)
+{
+ const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
+ WorkSpaceLayout *layout_new;
+
+ BLI_assert(BLI_findindex(BKE_workspace_layouts_get(workspace), layout_old) != -1);
+
+ /* don't allow deleting temp fullscreens for now */
+ if (BKE_screen_is_fullscreen_area(screen_old)) {
+ return false;
+ }
+
+ /* A layout/screen can only be in use by one window at a time, so as
+ * long as we are able to find a layout/screen that is unused, we
+ * can safely assume ours is not in use anywhere an delete it. */
+
+ layout_new = workspace_layout_delete_find_new(layout_old);
+
+ if (layout_new) {
+ return workspace_layout_delete_doit(workspace, layout_old, layout_new, C);
+ }
+
+ return false;
+}
+
+static bool workspace_layout_cycle_iter_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
+{
+ /* return false to stop iterator when we have found a layout to activate */
+ return !workspace_layout_set_poll(layout);
+}
+
+bool ED_workspace_layout_cycle(
+ WorkSpace *workspace, const short direction, bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpaceLayout *old_layout = BKE_workspace_active_layout_get(win->workspace_hook);
+ WorkSpaceLayout *new_layout;
+ const bScreen *old_screen = BKE_workspace_layout_screen_get(old_layout);
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (old_screen->temp || (sa && sa->full && sa->full->temp)) {
+ return false;
+ }
+
+ BLI_assert(ELEM(direction, 1, -1));
+ new_layout = BKE_workspace_layout_iter_circular(workspace, old_layout, workspace_layout_cycle_iter_cb,
+ NULL, (direction == -1) ? true : false);
+
+ if (new_layout && (old_layout != new_layout)) {
+ bScreen *new_screen = BKE_workspace_layout_screen_get(new_layout);
+
+ if (sa && sa->full) {
+ /* return to previous state before switching screens */
+ ED_screen_full_restore(C, sa); /* may free screen of old_layout */
+ }
+
+ ED_screen_change(C, new_screen);
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 9527dc4fe83..80c58e5b91d 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../depsgraph
../../gpu
../../imbuf
../../makesdna
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 90066a20e88..6a2a374f87d 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -41,6 +41,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_view3d_types.h"
@@ -54,14 +55,15 @@
#include "WM_api.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
#include "IMB_imbuf_types.h"
#include "ED_view3d.h"
-#include "GPU_basic_shader.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "UI_resources.h"
@@ -339,11 +341,12 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
size = target->old_size;
}
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, target->overlay_texture);
if (refresh) {
- GLenum format = col ? GL_RGBA : GL_ALPHA;
- GLenum internalformat = col ? GL_RGBA8 : GL_ALPHA8;
+ GLenum format = col ? GL_RGBA : GL_RED;
+ GLenum internalformat = col ? GL_RGBA8 : GL_R8;
if (!init || (target->old_col != col)) {
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, size, size, 0, format, GL_UNSIGNED_BYTE, buffer);
@@ -358,8 +361,6 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
target->old_col = col;
}
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
-
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -467,22 +468,21 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
size = cursor_snap.size;
}
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cursor_snap.overlay_texture);
if (refresh) {
if (!init) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size, size, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
}
else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_RED, GL_UNSIGNED_BYTE, buffer);
}
if (buffer)
MEM_freeN(buffer);
}
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
-
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -612,36 +612,33 @@ static void paint_draw_tex_overlay(
}
if (load_tex(brush, vc, zoom, col, primary)) {
- glEnable(GL_BLEND);
+ GPU_blend(true);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_FALSE);
glDepthFunc(GL_ALWAYS);
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glLoadIdentity();
-
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ GPU_matrix_push();
+
/* brush rotation */
- glTranslatef(0.5, 0.5, 0);
- glRotatef((double)RAD2DEGF((primary) ? ups->brush_rotation : ups->brush_rotation_sec),
- 0.0, 0.0, 1.0);
- glTranslatef(-0.5f, -0.5f, 0);
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_rotate_2d(-RAD2DEGF(primary ? ups->brush_rotation : ups->brush_rotation_sec));
+ GPU_matrix_translate_2f(-x, -y);
/* scale based on tablet pressure */
if (primary && ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
- glTranslatef(0.5f, 0.5f, 0);
- glScalef(1.0f / ups->size_pressure_value, 1.0f / ups->size_pressure_value, 1);
- glTranslatef(-0.5f, -0.5f, 0);
+ const float scale = ups->size_pressure_value;
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_scale_2f(scale, scale);
+ GPU_matrix_translate_2f(-x, -y);
}
if (ups->draw_anchored) {
- const float *aim = ups->anchored_initial_mouse;
- quad.xmin = aim[0] - ups->anchored_size;
- quad.ymin = aim[1] - ups->anchored_size;
- quad.xmax = aim[0] + ups->anchored_size;
- quad.ymax = aim[1] + ups->anchored_size;
+ quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
+ quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
+ quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
+ quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
}
else {
const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
@@ -671,41 +668,48 @@ static void paint_draw_tex_overlay(
quad.xmax = brush->mask_stencil_dimension[0];
quad.ymax = brush->mask_stencil_dimension[1];
}
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
+ GPU_matrix_push();
if (primary)
- glTranslate2fv(brush->stencil_pos);
+ GPU_matrix_translate_2fv(brush->stencil_pos);
else
- glTranslate2fv(brush->mask_stencil_pos);
- glRotatef(RAD2DEGF(mtex->rot), 0, 0, 1);
- glMatrixMode(GL_TEXTURE);
+ GPU_matrix_translate_2fv(brush->mask_stencil_pos);
+ GPU_matrix_rotate_2d(RAD2DEGF(mtex->rot));
}
/* set quad color. Colored overlay does not get blending */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
if (col) {
- glColor4f(1.0, 1.0, 1.0, overlay_alpha / 100.0f);
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, overlay_alpha * 0.01f);
}
else {
- glColor4f(UNPACK3(U.sculpt_paint_overlay_col), overlay_alpha / 100.0f);
+ GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_ALPHA_COLOR);
+ immUniformColor3fvAlpha(U.sculpt_paint_overlay_col, overlay_alpha * 0.01f);
}
/* draw textured quad */
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex2f(quad.xmin, quad.ymin);
- glTexCoord2f(1, 0);
- glVertex2f(quad.xmax, quad.ymin);
- glTexCoord2f(1, 1);
- glVertex2f(quad.xmax, quad.ymax);
- glTexCoord2f(0, 1);
- glVertex2f(quad.xmin, quad.ymax);
- glEnd();
-
- glPopMatrix();
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ immUniform1i("image", GL_TEXTURE0);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, quad.xmin, quad.ymin);
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, quad.xmax, quad.ymin);
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, quad.xmax, quad.ymax);
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, quad.xmin, quad.ymax);
+ immEnd();
+
+ immUnbindProgram();
+ GPU_blend_set_func(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
+
+ if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_VIEW)) {
+ GPU_matrix_pop();
}
}
}
@@ -726,19 +730,18 @@ static void paint_draw_cursor_overlay(
if (load_tex_cursor(brush, vc, zoom)) {
bool do_pop = false;
float center[2];
- glEnable(GL_BLEND);
+ GPU_blend(true);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_FALSE);
glDepthFunc(GL_ALWAYS);
if (ups->draw_anchored) {
- const float *aim = ups->anchored_initial_mouse;
- copy_v2_v2(center, aim);
- quad.xmin = aim[0] - ups->anchored_size;
- quad.ymin = aim[1] - ups->anchored_size;
- quad.xmax = aim[0] + ups->anchored_size;
- quad.ymax = aim[1] + ups->anchored_size;
+ copy_v2_v2(center, ups->anchored_initial_mouse);
+ quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size;
+ quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size;
+ quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size;
+ quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
}
else {
const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
@@ -754,32 +757,43 @@ static void paint_draw_cursor_overlay(
/* scale based on tablet pressure */
if (ups->stroke_active && BKE_brush_use_size_pressure(vc->scene, brush)) {
do_pop = true;
- glPushMatrix();
- glLoadIdentity();
- glTranslate2fv(center);
- glScalef(ups->size_pressure_value, ups->size_pressure_value, 1);
- glTranslatef(-center[0], -center[1], 0);
+ GPU_matrix_push();
+ GPU_matrix_translate_2fv(center);
+ GPU_matrix_scale_1f(ups->size_pressure_value);
+ GPU_matrix_translate_2f(-center[0], -center[1]);
}
- glColor4f(U.sculpt_paint_overlay_col[0],
- U.sculpt_paint_overlay_col[1],
- U.sculpt_paint_overlay_col[2],
- brush->cursor_overlay_alpha / 100.0f);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_ALPHA_COLOR);
+
+ immUniformColor3fvAlpha(U.sculpt_paint_overlay_col, brush->cursor_overlay_alpha * 0.01f);
+
+ /* draw textured quad */
/* draw textured quad */
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex2f(quad.xmin, quad.ymin);
- glTexCoord2f(1, 0);
- glVertex2f(quad.xmax, quad.ymin);
- glTexCoord2f(1, 1);
- glVertex2f(quad.xmax, quad.ymax);
- glTexCoord2f(0, 1);
- glVertex2f(quad.xmin, quad.ymax);
- glEnd();
+ immUniform1i("image", 0);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, quad.xmin, quad.ymin);
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, quad.xmax, quad.ymin);
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, quad.xmax, quad.ymax);
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, quad.xmin, quad.ymax);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_blend_set_func(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
if (do_pop)
- glPopMatrix();
+ GPU_matrix_pop();
}
}
@@ -790,19 +804,13 @@ static void paint_draw_alpha_overlay(
/* color means that primary brush texture is colured and secondary is used for alpha/mask control */
bool col = ELEM(mode, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D, PAINT_MODE_VERTEX) ? true : false;
eOverlayControlFlags flags = BKE_paint_get_overlay_flags();
- /* save lots of GL state
- * TODO: check on whether all of these are needed? */
- glPushAttrib(GL_COLOR_BUFFER_BIT |
- GL_CURRENT_BIT |
- GL_DEPTH_BUFFER_BIT |
- GL_ENABLE_BIT |
- GL_LINE_BIT |
- GL_POLYGON_BIT |
- GL_STENCIL_BUFFER_BIT |
- GL_TRANSFORM_BIT |
- GL_VIEWPORT_BIT |
- GL_TEXTURE_BIT);
+ gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_BLEND_BIT);
+ /* Translate to region. */
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(vc->ar->winrct.xmin, vc->ar->winrct.ymin);
+ x -= vc->ar->winrct.xmin;
+ y -= vc->ar->winrct.ymin;
/* coloured overlay should be drawn separately */
if (col) {
@@ -820,109 +828,133 @@ static void paint_draw_alpha_overlay(
paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom);
}
- glPopAttrib();
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ GPU_matrix_pop();
+ gpuPopAttrib();
}
-BLI_INLINE void draw_tri_point(float *co, float width, bool selected)
+BLI_INLINE void draw_tri_point(
+ unsigned int pos, float sel_col[4], float pivot_col[4],
+ float *co, float width, bool selected)
{
+ immUniformColor4fv(selected ? sel_col : pivot_col);
+
+ GPU_line_width(3.0f);
+
float w = width / 2.0f;
- if (selected)
- UI_ThemeColor4(TH_VERTEX_SELECT);
- else
- UI_ThemeColor4(TH_PAINT_CURVE_PIVOT);
-
- glLineWidth(3.0);
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(co[0], co[1] + w);
- glVertex2f(co[0] - w, co[1] - w);
- glVertex2f(co[0] + w, co[1] - w);
- glEnd();
-
- glColor4f(1.0, 1.0, 1.0, 0.5);
- glLineWidth(1.0);
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(co[0], co[1] + w);
- glVertex2f(co[0] - w, co[1] - w);
- glVertex2f(co[0] + w, co[1] - w);
- glEnd();
+ float tri[3][2] = {
+ {co[0], co[1] + w},
+ {co[0] - w, co[1] - w},
+ {co[0] + w, co[1] - w},
+ };
+
+ immBegin(GPU_PRIM_LINE_LOOP, 3);
+ immVertex2fv(pos, tri[0]);
+ immVertex2fv(pos, tri[1]);
+ immVertex2fv(pos, tri[2]);
+ immEnd();
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ GPU_line_width(1.0f);
+
+ immBegin(GPU_PRIM_LINE_LOOP, 3);
+ immVertex2fv(pos, tri[0]);
+ immVertex2fv(pos, tri[1]);
+ immVertex2fv(pos, tri[2]);
+ immEnd();
}
-BLI_INLINE void draw_rect_point(float *co, float width, bool selected)
+BLI_INLINE void draw_rect_point(
+ unsigned int pos, float sel_col[4], float handle_col[4],
+ float *co, float width, bool selected)
{
+ immUniformColor4fv(selected ? sel_col : handle_col);
+
+ GPU_line_width(3.0f);
+
float w = width / 2.0f;
- if (selected)
- UI_ThemeColor4(TH_VERTEX_SELECT);
- else
- UI_ThemeColor4(TH_PAINT_CURVE_HANDLE);
- glLineWidth(3.0);
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(co[0] + w, co[1] + w);
- glVertex2f(co[0] - w, co[1] + w);
- glVertex2f(co[0] - w, co[1] - w);
- glVertex2f(co[0] + w, co[1] - w);
- glEnd();
-
- glColor4f(1.0, 1.0, 1.0, 0.5);
- glLineWidth(1.0);
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(co[0] + w, co[1] + w);
- glVertex2f(co[0] - w, co[1] + w);
- glVertex2f(co[0] - w, co[1] - w);
- glVertex2f(co[0] + w, co[1] - w);
- glEnd();
+ float minx = co[0] - w;
+ float miny = co[1] - w;
+ float maxx = co[0] + w;
+ float maxy = co[1] + w;
+
+ imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ GPU_line_width(1.0f);
+
+ imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
}
-BLI_INLINE void draw_bezier_handle_lines(BezTriple *bez)
+BLI_INLINE void draw_bezier_handle_lines(unsigned int pos, float sel_col[4], BezTriple *bez)
{
- short line1[] = {0, 1};
- short line2[] = {1, 2};
-
- glVertexPointer(2, GL_FLOAT, 3 * sizeof(float), bez->vec);
- glColor4f(0.0, 0.0, 0.0, 0.5);
- glLineWidth(3.0);
- glDrawArrays(GL_LINE_STRIP, 0, 3);
-
- glLineWidth(1.0);
- if (bez->f1 || bez->f2)
- UI_ThemeColor4(TH_VERTEX_SELECT);
- else
- glColor4f(1.0, 1.0, 1.0, 0.5);
- glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line1);
- if (bez->f3 || bez->f2)
- UI_ThemeColor4(TH_VERTEX_SELECT);
- else
- glColor4f(1.0, 1.0, 1.0, 0.5);
- glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line2);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
+ GPU_line_width(3.0f);
+
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ immVertex2fv(pos, bez->vec[0]);
+ immVertex2fv(pos, bez->vec[1]);
+ immVertex2fv(pos, bez->vec[2]);
+ immEnd();
+
+ GPU_line_width(1.0f);
+
+ if (bez->f1 || bez->f2) {
+ immUniformColor4fv(sel_col);
+ }
+ else {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ }
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(pos, bez->vec[0]);
+ immVertex2fv(pos, bez->vec[1]);
+ immEnd();
+
+ if (bez->f3 || bez->f2) {
+ immUniformColor4fv(sel_col);
+ }
+ else {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+ }
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(pos, bez->vec[1]);
+ immVertex2fv(pos, bez->vec[2]);
+ immEnd();
}
-static void paint_draw_curve_cursor(Brush *brush)
+static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc)
{
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(vc->ar->winrct.xmin, vc->ar->winrct.ymin);
+
if (brush->paint_curve && brush->paint_curve->points) {
int i;
PaintCurve *pc = brush->paint_curve;
PaintCurvePoint *cp = pc->points;
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glEnableClientState(GL_VERTEX_ARRAY);
+ GPU_line_smooth(true);
+ GPU_blend(true);
/* draw the bezier handles and the curve segment between the current and next point */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ float selec_col[4], handle_col[4], pivot_col[4];
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, selec_col);
+ UI_GetThemeColor4fv(TH_PAINT_CURVE_HANDLE, handle_col);
+ UI_GetThemeColor4fv(TH_PAINT_CURVE_PIVOT, pivot_col);
+
for (i = 0; i < pc->tot_points - 1; i++, cp++) {
int j;
PaintCurvePoint *cp_next = cp + 1;
float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
/* use color coding to distinguish handles vs curve segments */
- draw_bezier_handle_lines(&cp->bez);
- draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
- draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
- draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
+ draw_bezier_handle_lines(pos, selec_col, &cp->bez);
+ draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
+ draw_rect_point(pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
+ draw_rect_point(pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
for (j = 0; j < 2; j++)
BKE_curve_forward_diff_bezier(
@@ -932,26 +964,37 @@ static void paint_draw_curve_cursor(Brush *brush)
cp_next->bez.vec[1][j],
data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
- glVertexPointer(2, GL_FLOAT, 0, data);
- glLineWidth(3.0);
- glColor4f(0.0, 0.0, 0.0, 0.5);
- glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
+ float (*v)[2] = (float(*)[2])data;
+
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
+ GPU_line_width(3.0f);
+ immBegin(GPU_PRIM_LINE_STRIP, PAINT_CURVE_NUM_SEGMENTS + 1);
+ for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
+ immVertex2fv(pos, v[j]);
+ }
+ immEnd();
- glLineWidth(1.0);
- glColor4f(0.9, 0.9, 1.0, 0.5);
- glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
+ immUniformColor4f(0.9f, 0.9f, 1.0f, 0.5f);
+ GPU_line_width(1.0f);
+ immBegin(GPU_PRIM_LINE_STRIP, PAINT_CURVE_NUM_SEGMENTS + 1);
+ for (j = 0; j <= PAINT_CURVE_NUM_SEGMENTS; j++) {
+ immVertex2fv(pos, v[j]);
+ }
+ immEnd();
}
/* draw last line segment */
- draw_bezier_handle_lines(&cp->bez);
- draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
- draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
- draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
-
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
- glDisableClientState(GL_VERTEX_ARRAY);
+ draw_bezier_handle_lines(pos, selec_col, &cp->bez);
+ draw_tri_point(pos, selec_col, pivot_col, &cp->bez.vec[1][0], 10.0f, cp->bez.f2);
+ draw_rect_point(pos, selec_col, handle_col, &cp->bez.vec[0][0], 8.0f, cp->bez.f1 || cp->bez.f2);
+ draw_rect_point(pos, selec_col, handle_col, &cp->bez.vec[2][0], 8.0f, cp->bez.f3 || cp->bez.f2);
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+
+ immUnbindProgram();
}
+ GPU_matrix_pop();
}
/* Special actions taken when paint cursor goes over mesh */
@@ -1001,15 +1044,11 @@ static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- ViewContext vc;
- float final_radius;
- float translation[2];
- float outline_alpha, *outline_col;
- float zoomx, zoomy;
/* check that brush drawing is enabled */
if (ommit_cursor_drawing(paint, mode, brush))
@@ -1017,6 +1056,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* can't use stroke vc here because this will be called during
* mouse over too, not just during a stroke */
+ ViewContext vc;
ED_view3d_viewcontext_init(C, &vc);
if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
@@ -1025,19 +1065,19 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* skip everything and draw brush here */
if (brush->flag & BRUSH_CURVE) {
- paint_draw_curve_cursor(brush);
+ paint_draw_curve_cursor(brush, &vc);
return;
}
+ float zoomx, zoomy;
get_imapaint_zoom(C, &zoomx, &zoomy);
zoomx = max_ff(zoomx, zoomy);
/* set various defaults */
- translation[0] = x;
- translation[1] = y;
- outline_alpha = 0.5;
- outline_col = brush->add_col;
- final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
+ const float *outline_col = brush->add_col;
+ const float outline_alpha = 0.5f;
+ float translation[2] = { x, y };
+ float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
/* don't calculate rake angles while a stroke is active because the rake variables are global and
* we may get interference with the stroke itself. For line strokes, such interference is visible */
@@ -1053,10 +1093,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
if ((mode == PAINT_MODE_SCULPT) && vc.obact->sculpt) {
float location[3];
int pixel_radius;
- bool hit;
/* test if brush is over the mesh */
- hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
+ bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
if (BKE_brush_use_locked_size(scene, brush))
BKE_brush_size_set(scene, brush, pixel_radius);
@@ -1077,34 +1116,36 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
if (ups->draw_anchored) {
final_radius = ups->anchored_size;
- translation[0] = ups->anchored_initial_mouse[0];
- translation[1] = ups->anchored_initial_mouse[1];
+ copy_v2_fl2(translation,
+ ups->anchored_initial_mouse[0] + ar->winrct.xmin,
+ ups->anchored_initial_mouse[1] + ar->winrct.ymin);
}
/* make lines pretty */
- glLineWidth(1.0f);
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ GPU_line_width(1.0f);
+ GPU_blend(true); /* TODO: also set blend mode? */
+ GPU_line_smooth(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* set brush color */
- glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
/* draw brush outline */
- glTranslate2fv(translation);
-
- /* draw an inner brush */
if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
/* inner at full alpha */
- glutil_draw_lined_arc(0.0, M_PI * 2.0, final_radius * ups->size_pressure_value, 40);
+ imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
/* outer at half alpha */
- glColor4f(outline_col[0], outline_col[1], outline_col[2], outline_alpha * 0.5f);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
}
- glutil_draw_lined_arc(0.0, M_PI * 2.0, final_radius, 40);
- glTranslatef(-translation[0], -translation[1], 0);
+ imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
+
+ immUnbindProgram();
/* restore GL state */
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ GPU_blend(false);
+ GPU_line_smooth(false);
}
/* Public API */
@@ -1113,8 +1154,14 @@ void paint_cursor_start(bContext *C, bool (*poll)(bContext *C))
{
Paint *p = BKE_paint_get_active_from_context(C);
- if (p && !p->paint_cursor)
- p->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, paint_draw_cursor, NULL);
+ if (p && !p->paint_cursor) {
+ p->paint_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ poll,
+ paint_draw_cursor,
+ NULL);
+ }
/* invalidate the paint cursors */
BKE_paint_invalidate_overlay_all();
@@ -1122,6 +1169,12 @@ void paint_cursor_start(bContext *C, bool (*poll)(bContext *C))
void paint_cursor_start_explicit(Paint *p, wmWindowManager *wm, bool (*poll)(bContext *C))
{
- if (p && !p->paint_cursor)
- p->paint_cursor = WM_paint_cursor_activate(wm, poll, paint_draw_cursor, NULL);
+ if (p && !p->paint_cursor) {
+ p->paint_cursor = WM_paint_cursor_activate(
+ wm,
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ poll,
+ paint_draw_cursor,
+ NULL);
+ }
}
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 55912733dc2..e9918481408 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -39,6 +39,8 @@
#include "BKE_main.h"
#include "BKE_paint.h"
+#include "DEG_depsgraph.h"
+
#include "ED_view3d.h"
#include "ED_paint.h"
@@ -713,7 +715,7 @@ static int paintcurve_cursor_invoke(bContext *C, wmOperator *UNUSED(op), const w
break;
}
default:
- ED_view3d_cursor3d_update(C, event->mval);
+ ED_view3d_cursor3d_update(C, event->mval, true, V3D_CURSOR_ORIENT_VIEW);
break;
}
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 01a54e4360d..6faabe66462 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -46,13 +46,13 @@
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_subsurf.h"
-#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -333,12 +333,10 @@ static void clip_planes_from_rect(
{
ViewContext vc;
BoundBox bb;
- bglMats mats = {{0}};
view3d_operator_needs_opengl(C);
ED_view3d_viewcontext_init(C, &vc);
- view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
- ED_view3d_clipping_calc(&bb, clip_planes, &mats, rect);
+ ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect);
negate_m4(clip_planes);
}
@@ -375,12 +373,12 @@ static int hide_show_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Mesh *me = ob->data;
PartialVisAction action;
PartialVisArea area;
PBVH *pbvh;
PBVHNode **nodes;
- DerivedMesh *dm;
PBVHType pbvh_type;
float clip_planes[4][4];
rcti rect;
@@ -393,9 +391,8 @@ static int hide_show_exec(bContext *C, wmOperator *op)
clip_planes_from_rect(C, clip_planes, &rect);
- dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
- pbvh = dm->getPBVH(ob, dm);
- ob->sculpt->pbvh = pbvh;
+ pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
+ BLI_assert(ob->sculpt->pbvh == pbvh);
get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
pbvh_type = BKE_pbvh_type(pbvh);
@@ -446,7 +443,7 @@ static int hide_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
PartialVisArea area = RNA_enum_get(op->ptr, "area");
if (!ELEM(area, PARTIALVIS_ALL, PARTIALVIS_MASKED))
- return WM_gesture_border_invoke(C, op, event);
+ return WM_gesture_box_invoke(C, op, event);
else
return op->type->exec(C, op);
}
@@ -474,7 +471,7 @@ void PAINT_OT_hide_show(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = hide_show_invoke;
- ot->modal = WM_gesture_border_modal;
+ ot->modal = WM_gesture_box_modal;
ot->exec = hide_show_exec;
/* sculpt-only for now */
ot->poll = sculpt_mode_poll_view3d;
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 59a5a87626c..f9b2e0bbb01 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -46,21 +46,23 @@
#include "IMB_imbuf_types.h"
#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "BKE_colorband.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_brush.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "UI_interface.h"
#include "UI_view2d.h"
@@ -72,15 +74,17 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "GPU_draw.h"
-#include "GPU_buffers.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
#include "BIF_gl.h"
-#include "BIF_glutil.h"
#include "IMB_colormanagement.h"
@@ -265,7 +269,7 @@ static Brush *image_paint_brush(bContext *C)
return BKE_paint_brush(&settings->imapaint.paint);
}
-static bool image_paint_poll(bContext *C)
+static bool image_paint_poll_ex(bContext *C, bool check_tool)
{
Object *obact;
@@ -274,7 +278,9 @@ static bool image_paint_poll(bContext *C)
obact = CTX_data_active_object(C);
if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) {
- return 1;
+ if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
+ return 1;
+ }
}
else {
SpaceImage *sima = CTX_wm_space_image(C);
@@ -291,6 +297,16 @@ static bool image_paint_poll(bContext *C)
return 0;
}
+static bool image_paint_poll(bContext *C)
+{
+ return image_paint_poll_ex(C, true);
+}
+
+static bool image_paint_ignore_tool_poll(bContext *C)
+{
+ return image_paint_poll_ex(C, false);
+}
+
static bool image_paint_2d_clone_poll(bContext *C)
{
Brush *brush = image_paint_brush(C);
@@ -400,18 +416,34 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda
PaintOperation *pop = (PaintOperation *)customdata;
if (pop) {
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
-
- glLineWidth(4.0);
- glColor4ub(0, 0, 0, 255);
- sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
- glLineWidth(2.0);
- glColor4ub(255, 255, 255, 255);
- sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
-
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_line_width(4.0);
+ immUniformColor4ub(0, 0, 0, 255);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2i(pos, x, y);
+ immVertex2i(pos, pop->startmouse[0], pop->startmouse[1]);
+ immEnd();
+
+ GPU_line_width(2.0);
+ immUniformColor4ub(255, 255, 255, 255);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2i(pos, x, y);
+ immVertex2i(pos, pop->startmouse[0], pop->startmouse[1]);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
}
}
@@ -430,7 +462,8 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
/* initialize from context */
if (CTX_wm_region_view3d(C)) {
- Object *ob = OBACT;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
bool uvs, mat, tex, stencil;
if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, &stencil)) {
BKE_paint_data_warning(op->reports, uvs, mat, tex, stencil);
@@ -452,7 +485,11 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
}
if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
- pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, gradient_draw_line, pop);
+ pop->cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ image_paint_poll, gradient_draw_line,
+ pop);
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
@@ -717,16 +754,20 @@ static void toggle_paint_cursor(bContext *C, int enable)
void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
{
ToolSettings *settings = scene->toolsettings;
- wmWindow *win;
- ScrArea *sa;
ImagePaintSettings *imapaint = &settings->imapaint;
bool enabled = false;
- for (win = wm->windows.first; win; win = win->next)
- for (sa = win->screen->areabase.first; sa; sa = sa->next)
- if (sa->spacetype == SPACE_IMAGE)
- if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT)
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_IMAGE) {
+ if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT) {
enabled = true;
+ }
+ }
+ }
+ }
if (enabled) {
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
@@ -857,7 +898,7 @@ static void sample_color_update_header(SampleColorData *data, bContext *C)
!data->sample_palette ?
IFACE_("Brush. Use Left Click to sample for palette instead") :
IFACE_("Palette. Use Left Click to sample more colors"));
- ED_area_headerprint(sa, msg);
+ ED_workspace_status_text(C, msg);
}
}
@@ -936,8 +977,6 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
Brush *brush = BKE_paint_brush(paint);
if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
- ScrArea *sa = CTX_wm_area(C);
-
if (data->show_cursor) {
paint->flags |= PAINT_SHOW_BRUSH;
}
@@ -948,7 +987,7 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
WM_cursor_modal_restore(CTX_wm_window(C));
MEM_freeN(data);
- ED_area_headerprint(sa, NULL);
+ ED_workspace_status_text(C, NULL);
return OPERATOR_FINISHED;
}
@@ -983,11 +1022,6 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static bool sample_color_poll(bContext *C)
-{
- return (image_paint_poll(C) || vertex_paint_poll(C));
-}
-
void PAINT_OT_sample_color(wmOperatorType *ot)
{
/* identifiers */
@@ -999,7 +1033,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
ot->exec = sample_color_exec;
ot->invoke = sample_color_invoke;
ot->modal = sample_color_modal;
- ot->poll = sample_color_poll;
+ ot->poll = image_paint_ignore_tool_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1031,6 +1065,7 @@ static bool texture_paint_toggle_poll(bContext *C)
static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
{
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -1083,8 +1118,10 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
- if (!sima->pin)
- ED_space_image_set(bmain, sima, scene, scene->obedit, ima);
+ if (!sima->pin) {
+ Object *obedit = CTX_data_edit_object(C);
+ ED_space_image_set(bmain, sima, scene, obedit, ima);
+ }
}
}
}
@@ -1095,6 +1132,8 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT);
+ BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
+
if (U.glreslimit != 0)
GPU_free_images(bmain);
GPU_paint_set_mipmap(bmain, 0);
@@ -1102,9 +1141,16 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
toggle_paint_cursor(C, 1);
}
- GPU_drawobject_free(ob->derivedFinal);
+ Mesh *me = BKE_mesh_from_object(ob);
+ BLI_assert(me != NULL);
+ DEG_id_tag_update(&me->id, DEG_TAG_COPY_ON_WRITE);
+
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
return OPERATOR_FINISHED;
}
@@ -1128,8 +1174,8 @@ static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- Brush *br;
Object *ob = CTX_data_active_object(C);
+ Brush *br;
if (!(ob && (ob->mode & OB_MODE_VERTEX_PAINT))) {
br = image_paint_brush(C);
}
@@ -1198,7 +1244,7 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index c5bd88d8047..90aa13ab5c1 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -46,12 +46,13 @@
#include "BKE_colorband.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "ED_paint.h"
#include "ED_screen.h"
@@ -865,8 +866,9 @@ static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb,
out_off[0] = out_off[1] = 0;
if (!tile) {
- IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
- &out_off[1], &dim[0], &dim[1]);
+ IMB_rectclip(
+ ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
+ &out_off[1], &dim[0], &dim[1]);
if ((dim[0] == 0) || (dim[1] == 0))
return;
@@ -1383,7 +1385,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final)
/* compositor listener deals with updating */
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
- DAG_id_tag_update(&s->image->id, 0);
+ DEG_id_tag_update(&s->image->id, 0);
}
else {
if (!s->sima || !s->sima->lock)
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index bfde868c241..7c2660f24f8 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -58,29 +58,32 @@
#include "DNA_brush_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_colorband.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_idprop.h"
-#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "UI_interface.h"
#include "ED_object.h"
@@ -227,6 +230,7 @@ typedef struct ProjPaintState {
View3D *v3d;
RegionView3D *rv3d;
ARegion *ar;
+ Depsgraph *depsgraph;
Scene *scene;
int source; /* PROJ_SRC_**** */
@@ -282,7 +286,6 @@ typedef struct ProjPaintState {
bool do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
bool do_mask_normal; /* mask out pixels based on their normals */
bool do_mask_cavity; /* mask out pixels based on cavity */
- bool do_new_shading_nodes; /* cache BKE_scene_use_new_shading_nodes value */
float normal_angle; /* what angle to mask at */
float normal_angle__cos; /* cos(normal_angle), faster to compare */
float normal_angle_inner;
@@ -351,28 +354,31 @@ typedef struct ProjPaintState {
SpinLock *tile_lock;
- DerivedMesh *dm;
- int dm_totlooptri;
- int dm_totpoly;
- int dm_totedge;
- int dm_totvert;
- bool dm_release;
+ Mesh *me_eval;
+ bool me_eval_free;
+ int totlooptri_eval;
+ int totpoly_eval;
+ int totedge_eval;
+ int totvert_eval;
- const MVert *dm_mvert;
- const MEdge *dm_medge;
- const MPoly *dm_mpoly;
- const MLoop *dm_mloop;
- const MLoopTri *dm_mlooptri;
+ const MVert *mvert_eval;
+ const MEdge *medge_eval;
+ const MPoly *mpoly_eval;
+ const MLoop *mloop_eval;
+ const MLoopTri *mlooptri_eval;
- const MLoopUV *dm_mloopuv_stencil;
+ const MLoopUV *mloopuv_stencil_eval;
/**
- * \note These UV layers are aligned to \a dm_mpoly
+ * \note These UV layers are aligned to \a mpoly_eval
* but each pointer references the start of the layer,
* so a loop indirection is needed as well.
*/
- const MLoopUV **dm_mloopuv;
- const MLoopUV **dm_mloopuv_clone; /* other UV map, use for cloning between layers */
+ const MLoopUV **poly_to_loop_uv;
+ const MLoopUV **poly_to_loop_uv_clone; /* other UV map, use for cloning between layers */
+
+ /* Actual material for each index, either from object or Mesh datablock... */
+ Material **mat_array;
bool use_colormanagement;
} ProjPaintState;
@@ -438,13 +444,13 @@ typedef struct {
BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_index)
{
- return &ps->dm_mpoly[ps->dm_mlooptri[tri_index].poly];
+ return &ps->mpoly_eval[ps->mlooptri_eval[tri_index].poly];
}
#define PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) \
- ps->dm_mloop[lt->tri[0]].v, \
- ps->dm_mloop[lt->tri[1]].v, \
- ps->dm_mloop[lt->tri[2]].v,
+ ps->mloop_eval[lt->tri[0]].v, \
+ ps->mloop_eval[lt->tri[1]].v, \
+ ps->mloop_eval[lt->tri[2]].v,
#define PS_LOOPTRI_AS_UV_3(uvlayer, lt) \
uvlayer[lt->poly][lt->tri[0]].uv, \
@@ -466,7 +472,7 @@ BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->dm->mat[mp->mat_nr];
+ Material *ma = ps->mat_array[mp->mat_nr];
return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
}
@@ -477,7 +483,7 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_i
}
else {
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->dm->mat[mp->mat_nr];
+ Material *ma = ps->mat_array[mp->mat_nr];
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
return slot ? slot->ima : ps->canvas_ima;
}
@@ -486,14 +492,14 @@ static Image *project_paint_face_paint_image(const ProjPaintState *ps, int tri_i
static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->dm->mat[mp->mat_nr];
+ Material *ma = ps->mat_array[mp->mat_nr];
return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
}
static Image *project_paint_face_clone_image(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
- Material *ma = ps->dm->mat[mp->mat_nr];
+ Material *ma = ps->mat_array[mp->mat_nr];
TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
return slot ? slot->ima : ps->clone_ima;
}
@@ -594,11 +600,11 @@ static int project_paint_PickFace(
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
const int tri_index = POINTER_AS_INT(node->link);
- const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const float *vtri_ss[3] = {
- ps->screenCoords[ps->dm_mloop[lt->tri[0]].v],
- ps->screenCoords[ps->dm_mloop[lt->tri[1]].v],
- ps->screenCoords[ps->dm_mloop[lt->tri[2]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[0]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[1]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[2]].v],
};
@@ -653,8 +659,8 @@ static bool project_paint_PickColor(
if (tri_index == -1)
return 0;
- lt = &ps->dm_mlooptri[tri_index];
- PS_LOOPTRI_ASSIGN_UV_3(lt_tri_uv, ps->dm_mloopuv, lt);
+ lt = &ps->mlooptri_eval[tri_index];
+ PS_LOOPTRI_ASSIGN_UV_3(lt_tri_uv, ps->poly_to_loop_uv, lt);
interp_v2_v2v2v2(uv, UNPACK3(lt_tri_uv), w);
@@ -810,19 +816,19 @@ static bool project_bucket_point_occluded(
const int tri_index = POINTER_AS_INT(bucketFace->link);
if (orig_face != tri_index) {
- const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const float *vtri_ss[3] = {
- ps->screenCoords[ps->dm_mloop[lt->tri[0]].v],
- ps->screenCoords[ps->dm_mloop[lt->tri[1]].v],
- ps->screenCoords[ps->dm_mloop[lt->tri[2]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[0]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[1]].v],
+ ps->screenCoords[ps->mloop_eval[lt->tri[2]].v],
};
float w[3];
if (do_clip) {
const float *vtri_co[3] = {
- ps->dm_mvert[ps->dm_mloop[lt->tri[0]].v].co,
- ps->dm_mvert[ps->dm_mloop[lt->tri[1]].v].co,
- ps->dm_mvert[ps->dm_mloop[lt->tri[2]].v].co,
+ ps->mvert_eval[ps->mloop_eval[lt->tri[0]].v].co,
+ ps->mvert_eval[ps->mloop_eval[lt->tri[1]].v].co,
+ ps->mvert_eval[ps->mloop_eval[lt->tri[2]].v].co,
};
isect_ret = project_paint_occlude_ptv_clip(
pixelScreenCo, UNPACK3(vtri_ss), UNPACK3(vtri_co),
@@ -1002,8 +1008,8 @@ static bool pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x
static void project_face_winding_init(const ProjPaintState *ps, const int tri_index)
{
/* detect the winding of faces in uv space */
- const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
- const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, lt) };
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
float winding = cross_tri_v2(lt_tri_uv[0], lt_tri_uv[1], lt_tri_uv[2]);
if (winding > 0)
@@ -1019,11 +1025,11 @@ static bool check_seam(
const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx,
int *other_face, int *orig_fidx)
{
- const MLoopTri *orig_lt = &ps->dm_mlooptri[orig_face];
- const float *orig_lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, orig_lt) };
+ const MLoopTri *orig_lt = &ps->mlooptri_eval[orig_face];
+ const float *orig_lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, orig_lt) };
/* vert indices from face vert order indices */
- const unsigned int i1 = ps->dm_mloop[orig_lt->tri[orig_i1_fidx]].v;
- const unsigned int i2 = ps->dm_mloop[orig_lt->tri[orig_i2_fidx]].v;
+ const unsigned int i1 = ps->mloop_eval[orig_lt->tri[orig_i1_fidx]].v;
+ const unsigned int i2 = ps->mloop_eval[orig_lt->tri[orig_i2_fidx]].v;
LinkNode *node;
int i1_fidx = -1, i2_fidx = -1; /* index in face */
@@ -1031,7 +1037,7 @@ static bool check_seam(
const int tri_index = POINTER_AS_INT(node->link);
if (tri_index != orig_face) {
- const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
/* could check if the 2 faces images match here,
* but then there wouldn't be a way to return the opposite face's info */
@@ -1044,7 +1050,7 @@ static bool check_seam(
/* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
if (i2_fidx != -1) {
- const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, lt) };
+ const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
Image *tpage = project_paint_face_paint_image(ps, tri_index);
Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
@@ -1348,8 +1354,8 @@ static float project_paint_uvpixel_mask(
Image *other_tpage = ps->stencil_ima;
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
- const MLoopTri *lt_other = &ps->dm_mlooptri[tri_index];
- const float *lt_other_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, lt_other) };
+ const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
+ const float *lt_other_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt_other) };
/* BKE_image_acquire_ibuf - TODO - this may be slow */
unsigned char rgba_ub[4];
@@ -1382,7 +1388,7 @@ static float project_paint_uvpixel_mask(
}
if (ps->do_mask_cavity) {
- const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
float ca1, ca2, ca3, ca_mask;
ca1 = ps->cavities[lt_vtri[0]];
@@ -1397,16 +1403,16 @@ static float project_paint_uvpixel_mask(
/* calculate mask */
if (ps->do_mask_normal) {
- const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- const MPoly *mp = &ps->dm_mpoly[lt->poly];
+ const MPoly *mp = &ps->mpoly_eval[lt->poly];
float no[3], angle_cos;
if (mp->flag & ME_SMOOTH) {
const short *no1, *no2, *no3;
- no1 = ps->dm_mvert[lt_vtri[0]].no;
- no2 = ps->dm_mvert[lt_vtri[1]].no;
- no3 = ps->dm_mvert[lt_vtri[2]].no;
+ no1 = ps->mvert_eval[lt_vtri[0]].no;
+ no2 = ps->mvert_eval[lt_vtri[1]].no;
+ no3 = ps->mvert_eval[lt_vtri[2]].no;
no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
@@ -1418,9 +1424,9 @@ static float project_paint_uvpixel_mask(
#if 1
/* normalizing per pixel isn't optimal, we could cache or check ps->*/
normal_tri_v3(no,
- ps->dm_mvert[lt_vtri[0]].co,
- ps->dm_mvert[lt_vtri[1]].co,
- ps->dm_mvert[lt_vtri[2]].co);
+ ps->mvert_eval[lt_vtri[0]].co,
+ ps->mvert_eval[lt_vtri[1]].co,
+ ps->mvert_eval[lt_vtri[2]].co);
#else
/* don't use because some modifiers dont have normal data (subsurf for eg) */
copy_v3_v3(no, (float *)ps->dm->getTessFaceData(ps->dm, tri_index, CD_NORMAL));
@@ -1439,9 +1445,9 @@ static float project_paint_uvpixel_mask(
/* Annoying but for the perspective view we need to get the pixels location in 3D space :/ */
float viewDirPersp[3];
const float *co1, *co2, *co3;
- co1 = ps->dm_mvert[lt_vtri[0]].co;
- co2 = ps->dm_mvert[lt_vtri[1]].co;
- co3 = ps->dm_mvert[lt_vtri[2]].co;
+ co1 = ps->mvert_eval[lt_vtri[0]].co;
+ co2 = ps->mvert_eval[lt_vtri[1]].co;
+ co3 = ps->mvert_eval[lt_vtri[2]].co;
/* Get the direction from the viewPoint to the pixel and normalize */
viewDirPersp[0] = (ps->viewPos[0] - (w[0] * co1[0] + w[1] * co2[0] + w[2] * co3[0]));
@@ -1455,6 +1461,11 @@ static float project_paint_uvpixel_mask(
angle_cos = dot_v3v3(viewDirPersp, no);
}
+ /* If backface culling is disabled, allow painting on back faces. */
+ if (!ps->do_backfacecull) {
+ angle_cos = fabsf(angle_cos);
+ }
+
if (angle_cos <= ps->normal_angle__cos) {
return 0.0f; /* outsize the normal limit*/
}
@@ -1610,13 +1621,13 @@ static ProjPixel *project_paint_uvpixel_init(
/* done with view3d_project_float inline */
if (ps->tool == PAINT_TOOL_CLONE) {
- if (ps->dm_mloopuv_clone) {
+ if (ps->poly_to_loop_uv_clone) {
ImBuf *ibuf_other;
Image *other_tpage = project_paint_face_clone_image(ps, tri_index);
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
- const MLoopTri *lt_other = &ps->dm_mlooptri[tri_index];
- const float *lt_other_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv_clone, lt_other) };
+ const MLoopTri *lt_other = &ps->mlooptri_eval[tri_index];
+ const float *lt_other_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv_clone, lt_other) };
/* BKE_image_acquire_ibuf - TODO - this may be slow */
@@ -2491,8 +2502,7 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
static void project_paint_face_init(
const ProjPaintState *ps,
const int thread_index, const int bucket_index, const int tri_index, const int image_index,
- const rctf *clip_rect, const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf,
- const bool clamp_u, const bool clamp_v)
+ const rctf *clip_rect, const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf)
{
/* Projection vars, to get the 3D locations into screen space */
MemArena *arena = ps->arena_mt[thread_index];
@@ -2508,9 +2518,9 @@ static void project_paint_face_init(
ps->projImages + image_index
};
- const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
- const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->dm_mloopuv, lt) };
+ const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
/* UV/pixel seeking data */
int x; /* Image X-Pixel */
@@ -2544,9 +2554,9 @@ static void project_paint_face_init(
const bool do_backfacecull = ps->do_backfacecull;
const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
- vCo[0] = ps->dm_mvert[lt_vtri[0]].co;
- vCo[1] = ps->dm_mvert[lt_vtri[1]].co;
- vCo[2] = ps->dm_mvert[lt_vtri[2]].co;
+ vCo[0] = ps->mvert_eval[lt_vtri[0]].co;
+ vCo[1] = ps->mvert_eval[lt_vtri[1]].co;
+ vCo[2] = ps->mvert_eval[lt_vtri[2]].co;
/* Use lt_uv_pxoffset instead of lt_tri_uv so we can offset the UV half a pixel
@@ -2599,17 +2609,6 @@ static void project_paint_face_init(
#endif
if (pixel_bounds_array(uv_clip, &bounds_px, ibuf->x, ibuf->y, uv_clip_tot)) {
-
- if (clamp_u) {
- CLAMP(bounds_px.xmin, 0, ibuf->x);
- CLAMP(bounds_px.xmax, 0, ibuf->x);
- }
-
- if (clamp_v) {
- CLAMP(bounds_px.ymin, 0, ibuf->y);
- CLAMP(bounds_px.ymax, 0, ibuf->y);
- }
-
#if 0
project_paint_undo_tiles_init(
&bounds_px, ps->projImages + image_index, tmpibuf,
@@ -2642,9 +2641,9 @@ static void project_paint_face_init(
if (do_clip || do_3d_mapping) {
interp_v3_v3v3v3(
wco,
- ps->dm_mvert[lt_vtri[0]].co,
- ps->dm_mvert[lt_vtri[1]].co,
- ps->dm_mvert[lt_vtri[2]].co,
+ ps->mvert_eval[lt_vtri[0]].co,
+ ps->mvert_eval[lt_vtri[1]].co,
+ ps->mvert_eval[lt_vtri[2]].co,
w);
if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, true)) {
continue; /* Watch out that no code below this needs to run */
@@ -2824,7 +2823,7 @@ static void project_paint_face_init(
!project_bucket_point_occluded(ps, bucketFaceNodes, tri_index, pixelScreenCo))
{
/* Only bother calculating the weights if we intersect */
- if (ps->do_mask_normal || ps->dm_mloopuv_clone) {
+ if (ps->do_mask_normal || ps->poly_to_loop_uv_clone) {
const float uv_fac = fac1 + (fac * (fac2 - fac1));
#if 0
/* get the UV on the line since we want to copy the pixels from there for bleeding */
@@ -2927,19 +2926,16 @@ static void project_bucket_init(
int tri_index, image_index = 0;
ImBuf *ibuf = NULL;
Image *tpage_last = NULL, *tpage;
- Image *ima = NULL;
ImBuf *tmpibuf = NULL;
if (ps->image_tot == 1) {
/* Simple loop, no context switching */
ibuf = ps->projImages[0].ibuf;
- ima = ps->projImages[0].ima;
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
project_paint_face_init(
ps, thread_index, bucket_index, POINTER_AS_INT(node->link), 0,
- clip_rect, bucket_bounds, ibuf, &tmpibuf,
- (ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
+ clip_rect, bucket_bounds, ibuf, &tmpibuf);
}
}
else {
@@ -2956,7 +2952,6 @@ static void project_bucket_init(
for (image_index = 0; image_index < ps->image_tot; image_index++) {
if (ps->projImages[image_index].ima == tpage_last) {
ibuf = ps->projImages[image_index].ibuf;
- ima = ps->projImages[image_index].ima;
break;
}
}
@@ -2965,8 +2960,7 @@ static void project_bucket_init(
project_paint_face_init(
ps, thread_index, bucket_index, tri_index, image_index,
- clip_rect, bucket_bounds, ibuf, &tmpibuf,
- (ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
+ clip_rect, bucket_bounds, ibuf, &tmpibuf);
}
}
@@ -3082,26 +3076,8 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MLoopTri *
#endif
}
-/**
- * \note when using subsurf or multires, some arrays are thrown away, we need to keep a copy
- */
-static void proj_paint_state_non_cddm_init(ProjPaintState *ps)
-{
- if (ps->dm->type != DM_TYPE_CDDM) {
- ps->dm_mvert = MEM_dupallocN(ps->dm_mvert);
- ps->dm_mpoly = MEM_dupallocN(ps->dm_mpoly);
- ps->dm_mloop = MEM_dupallocN(ps->dm_mloop);
- /* looks like these are ok for now.*/
-#if 0
- ps->dm_mloopuv = MEM_dupallocN(ps->dm_mloopuv);
- ps->dm_mloopuv_clone = MEM_dupallocN(ps->dm_mloopuv_clone);
- ps->dm_mloopuv_stencil = MEM_dupallocN(ps->dm_mloopuv_stencil);
-#endif
- }
-}
-
static void proj_paint_state_viewport_init(
- ProjPaintState *ps, const char symmetry_flag)
+ ProjPaintState *ps, const Depsgraph *depsgraph, const char symmetry_flag)
{
float mat[3][3];
float viewmat[4][4];
@@ -3135,7 +3111,7 @@ static void proj_paint_state_viewport_init(
ED_view3d_ob_project_mat_get_from_obmat(ps->rv3d, ps->obmat, ps->projectMat);
- ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
+ ps->is_ortho = ED_view3d_clip_range_get(ps->depsgraph, ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
}
else {
/* re-projection */
@@ -3162,17 +3138,17 @@ static void proj_paint_state_viewport_init(
invert_m4_m4(viewinv, viewmat);
}
else if (ps->source == PROJ_SRC_IMAGE_CAM) {
- Object *cam_ob = ps->scene->camera;
+ Object *cam_ob_eval = DEG_get_evaluated_object(depsgraph, ps->scene->camera);
CameraParams params;
/* viewmat & viewinv */
- copy_m4_m4(viewinv, cam_ob->obmat);
+ copy_m4_m4(viewinv, cam_ob_eval->obmat);
normalize_m4(viewinv);
invert_m4_m4(viewmat, viewinv);
/* window matrix, clipping and ortho */
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, cam_ob);
+ BKE_camera_params_from_object(&params, cam_ob_eval);
BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
BKE_camera_params_compute_matrix(&params);
@@ -3219,11 +3195,11 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di
INIT_MINMAX2(ps->screenMin, ps->screenMax);
- ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts");
+ ps->screenCoords = MEM_mallocN(sizeof(float) * ps->totvert_eval * 4, "ProjectPaint ScreenVerts");
projScreenCo = *ps->screenCoords;
if (ps->is_ortho) {
- for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) {
+ for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
mul_v3_m4v3(projScreenCo, ps->projectMat, mv->co);
/* screen space, not clamped */
@@ -3233,7 +3209,7 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di
}
}
else {
- for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++, projScreenCo += 4) {
+ for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++, projScreenCo += 4) {
copy_v3_v3(projScreenCo, mv->co);
projScreenCo[3] = 1.0f;
@@ -3294,21 +3270,21 @@ static void proj_paint_state_cavity_init(ProjPaintState *ps)
int a;
if (ps->do_mask_cavity) {
- int *counter = MEM_callocN(sizeof(int) * ps->dm_totvert, "counter");
- float (*edges)[3] = MEM_callocN(sizeof(float) * 3 * ps->dm_totvert, "edges");
- ps->cavities = MEM_mallocN(sizeof(float) * ps->dm_totvert, "ProjectPaint Cavities");
+ int *counter = MEM_callocN(sizeof(int) * ps->totvert_eval, "counter");
+ float (*edges)[3] = MEM_callocN(sizeof(float) * 3 * ps->totvert_eval, "edges");
+ ps->cavities = MEM_mallocN(sizeof(float) * ps->totvert_eval, "ProjectPaint Cavities");
cavities = ps->cavities;
- for (a = 0, me = ps->dm_medge; a < ps->dm_totedge; a++, me++) {
+ for (a = 0, me = ps->medge_eval; a < ps->totedge_eval; a++, me++) {
float e[3];
- sub_v3_v3v3(e, ps->dm_mvert[me->v1].co, ps->dm_mvert[me->v2].co);
+ sub_v3_v3v3(e, ps->mvert_eval[me->v1].co, ps->mvert_eval[me->v2].co);
normalize_v3(e);
add_v3_v3(edges[me->v2], e);
counter[me->v2]++;
sub_v3_v3(edges[me->v1], e);
counter[me->v1]++;
}
- for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
+ for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
if (counter[a] > 0) {
float no[3];
mul_v3_fl(edges[a], 1.0f / counter[a]);
@@ -3329,10 +3305,10 @@ static void proj_paint_state_cavity_init(ProjPaintState *ps)
static void proj_paint_state_seam_bleed_init(ProjPaintState *ps)
{
if (ps->seam_bleed_px > 0.0f) {
- ps->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces");
- ps->faceSeamFlags = MEM_callocN(sizeof(char) * ps->dm_totlooptri, "paint-faceSeamFlags");
- ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->dm_totlooptri, "paint-faceWindindFlags");
- ps->faceSeamUVs = MEM_mallocN(sizeof(float[3][2]) * ps->dm_totlooptri, "paint-faceSeamUVs");
+ ps->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->totvert_eval, "paint-vertFaces");
+ ps->faceSeamFlags = MEM_callocN(sizeof(char) * ps->totlooptri_eval, "paint-faceSeamFlags");
+ ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->totlooptri_eval, "paint-faceWindindFlags");
+ ps->faceSeamUVs = MEM_mallocN(sizeof(float[3][2]) * ps->totlooptri_eval, "paint-faceSeamUVs");
}
}
#endif
@@ -3376,9 +3352,9 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
float no[3];
int a;
- ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags");
+ ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
- for (a = 0, mv = ps->dm_mvert; a < ps->dm_totvert; a++, mv++) {
+ for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
normal_short_to_float_v3(no, mv->no);
if (UNLIKELY(ps->is_flip_object)) {
negate_v3(no);
@@ -3423,49 +3399,60 @@ static void project_paint_bleed_add_face_user(
}
#endif
-/* Return true if DM can be painted on, false otherwise */
-static bool proj_paint_state_dm_init(ProjPaintState *ps)
+/* Return true if evaluated mesh can be painted on, false otherwise */
+static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *ps)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = ps->ob;
+
/* Workaround for subsurf selection, try the display mesh first */
if (ps->source == PROJ_SRC_IMAGE_CAM) {
/* using render mesh, assume only camera was rendered from */
- ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MLOOPUV | CD_MASK_MTFACE);
- ps->dm_release = true;
+ ps->me_eval = mesh_create_eval_final_render(
+ depsgraph, ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MLOOPUV | CD_MASK_MTFACE);
+ ps->me_eval_free = true;
}
else {
- ps->dm = mesh_get_derived_final(
- ps->scene, ps->ob,
+ ps->me_eval = mesh_get_eval_final(
+ depsgraph, ps->scene, ps->ob,
ps->scene->customdata_mask | CD_MASK_MLOOPUV | CD_MASK_MTFACE | (ps->do_face_sel ? CD_MASK_ORIGINDEX : 0));
- ps->dm_release = false;
+ ps->me_eval_free = false;
}
- if (!CustomData_has_layer(&ps->dm->loopData, CD_MLOOPUV)) {
-
- if (ps->dm_release)
- ps->dm->release(ps->dm);
-
- ps->dm = NULL;
+ if (!CustomData_has_layer(&ps->me_eval->ldata, CD_MLOOPUV)) {
+ if (ps->me_eval_free) {
+ BKE_id_free(NULL, ps->me_eval);
+ }
+ ps->me_eval = NULL;
return false;
}
- DM_update_materials(ps->dm, ps->ob);
-
- ps->dm_mvert = ps->dm->getVertArray(ps->dm);
-
- if (ps->do_mask_cavity)
- ps->dm_medge = ps->dm->getEdgeArray(ps->dm);
+ /* Build final material array, we use this a lot here. */
+ const int totmat = ob->totcol + 1; /* materials start from 1, default material is 0 */
+ ps->mat_array = MEM_malloc_arrayN(totmat, sizeof(*ps->mat_array), __func__);
+ /* We leave last material as empty - rationale here is being able to index
+ * the materials by using the mf->mat_nr directly and leaving the last
+ * material as NULL in case no materials exist on mesh, so indexing will not fail. */
+ for (int i = 0; i < totmat - 1; i++) {
+ ps->mat_array[i] = give_current_material(ob, i + 1);
+ }
+ ps->mat_array[totmat - 1] = NULL;
- ps->dm_mloop = ps->dm->getLoopArray(ps->dm);
- ps->dm_mpoly = ps->dm->getPolyArray(ps->dm);
+ ps->mvert_eval = ps->me_eval->mvert;
+ if (ps->do_mask_cavity) {
+ ps->medge_eval = ps->me_eval->medge;
+ }
+ ps->mloop_eval = ps->me_eval->mloop;
+ ps->mpoly_eval = ps->me_eval->mpoly;
- ps->dm_mlooptri = ps->dm->getLoopTriArray(ps->dm);
+ ps->totvert_eval = ps->me_eval->totvert;
+ ps->totedge_eval = ps->me_eval->totedge;
+ ps->totpoly_eval = ps->me_eval->totpoly;
- ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
- ps->dm_totedge = ps->dm->getNumEdges(ps->dm);
- ps->dm_totpoly = ps->dm->getNumPolys(ps->dm);
- ps->dm_totlooptri = ps->dm->getNumLoopTri(ps->dm);
+ ps->mlooptri_eval = BKE_mesh_runtime_looptri_ensure(ps->me_eval);
+ ps->totlooptri_eval = ps->me_eval->runtime.looptris.len;
- ps->dm_mloopuv = MEM_mallocN(ps->dm_totpoly * sizeof(MLoopUV *), "proj_paint_mtfaces");
+ ps->poly_to_loop_uv = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
return true;
}
@@ -3484,16 +3471,16 @@ static void proj_paint_layer_clone_init(
/* use clone mtface? */
if (ps->do_layer_clone) {
- const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
+ const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
- ps->dm_mloopuv_clone = MEM_mallocN(ps->dm_totpoly * sizeof(MLoopUV *), "proj_paint_mtfaces");
+ ps->poly_to_loop_uv_clone = MEM_mallocN(ps->totpoly_eval * sizeof(MLoopUV *), "proj_paint_mtfaces");
if (layer_num != -1)
- mloopuv_clone_base = CustomData_get_layer_n(&ps->dm->loopData, CD_MLOOPUV, layer_num);
+ mloopuv_clone_base = CustomData_get_layer_n(&ps->me_eval->ldata, CD_MLOOPUV, layer_num);
if (mloopuv_clone_base == NULL) {
/* get active instead */
- mloopuv_clone_base = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
+ mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
}
}
@@ -3523,17 +3510,17 @@ static bool project_paint_clone_face_skip(
if (lc->slot_clone != lc->slot_last_clone) {
if (!slot->uvname ||
!(lc->mloopuv_clone_base = CustomData_get_layer_named(
- &ps->dm->loopData, CD_MLOOPUV,
+ &ps->me_eval->ldata, CD_MLOOPUV,
lc->slot_clone->uvname)))
{
- lc->mloopuv_clone_base = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
+ lc->mloopuv_clone_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
}
lc->slot_last_clone = lc->slot_clone;
}
}
/* will set multiple times for 4+ sided poly */
- ps->dm_mloopuv_clone[ps->dm_mlooptri[tri_index].poly] = lc->mloopuv_clone_base;
+ ps->poly_to_loop_uv_clone[ps->mlooptri_eval[tri_index].poly] = lc->mloopuv_clone_base;
}
return false;
}
@@ -3550,7 +3537,7 @@ static void proj_paint_face_lookup_init(
{
memset(face_lookup, 0, sizeof(*face_lookup));
if (ps->do_face_sel) {
- face_lookup->index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX);
+ face_lookup->index_mp_to_orig = CustomData_get_layer(&ps->me_eval->pdata, CD_ORIGINDEX);
face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
}
}
@@ -3571,7 +3558,7 @@ static bool project_paint_check_face_sel(
mp = &face_lookup->mpoly_orig[orig_index];
}
else {
- mp = &ps->dm_mpoly[lt->poly];
+ mp = &ps->mpoly_eval[lt->poly];
}
return ((mp->flag & ME_FACE_SEL) != 0);
@@ -3685,7 +3672,7 @@ static void project_paint_prepare_all_faces(
int image_index = -1, tri_index;
int prev_poly = -1;
- for (tri_index = 0, lt = ps->dm_mlooptri; tri_index < ps->dm_totlooptri; tri_index++, lt++) {
+ for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
bool is_face_sel;
#ifndef PROJ_DEBUG_NOSEAMBLEED
@@ -3698,13 +3685,13 @@ static void project_paint_prepare_all_faces(
slot = project_paint_face_paint_slot(ps, tri_index);
/* all faces should have a valid slot, reassert here */
if (slot == NULL) {
- mloopuv_base = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
+ mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
tpage = ps->canvas_ima;
}
else {
if (slot != slot_last) {
- if (!slot->uvname || !(mloopuv_base = CustomData_get_layer_named(&ps->dm->loopData, CD_MLOOPUV, slot->uvname)))
- mloopuv_base = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
+ if (!slot->uvname || !(mloopuv_base = CustomData_get_layer_named(&ps->me_eval->ldata, CD_MLOOPUV, slot->uvname)))
+ mloopuv_base = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
slot_last = slot;
}
@@ -3712,7 +3699,7 @@ static void project_paint_prepare_all_faces(
if (slot->ima == ps->stencil_ima) {
/* While this shouldn't be used, face-winding reads all polys.
* It's less trouble to set all faces to valid UV's, avoiding NULL checks all over. */
- ps->dm_mloopuv[lt->poly] = mloopuv_base;
+ ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
continue;
}
@@ -3723,7 +3710,7 @@ static void project_paint_prepare_all_faces(
tpage = ps->stencil_ima;
}
- ps->dm_mloopuv[lt->poly] = mloopuv_base;
+ ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
if (project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
continue;
@@ -3754,11 +3741,11 @@ static void project_paint_prepare_all_faces(
if (prev_poly != lt->poly) {
int iloop;
bool culled = true;
- const MPoly *poly = ps->dm_mpoly + lt->poly;
+ const MPoly *poly = ps->mpoly_eval + lt->poly;
int poly_loops = poly->totloop;
prev_poly = lt->poly;
for (iloop = 0; iloop < poly_loops; iloop++) {
- if (!(ps->vertFlags[ps->dm_mloop[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) {
+ if (!(ps->vertFlags[ps->mloop_eval[poly->loopstart + iloop].v] & PROJ_VERT_CULL)) {
culled = false;
break;
}
@@ -3814,7 +3801,7 @@ static void project_paint_prepare_all_faces(
/* run once per stroke before projection painting */
static void project_paint_begin(
- ProjPaintState *ps,
+ const bContext *C, ProjPaintState *ps,
const bool is_multi_view, const char symmetry_flag)
{
ProjPaintLayerClone layer_clone;
@@ -3837,7 +3824,7 @@ static void project_paint_begin(
/* paint onto the derived mesh */
if (ps->is_shared_user == false) {
- if (!proj_paint_state_dm_init(ps)) {
+ if (!proj_paint_state_mesh_eval_init(C, ps)) {
return;
}
}
@@ -3846,28 +3833,26 @@ static void project_paint_begin(
proj_paint_layer_clone_init(ps, &layer_clone);
if (ps->do_layer_stencil || ps->do_stencil_brush) {
- //int layer_num = CustomData_get_stencil_layer(&ps->dm->loopData, CD_MLOOPUV);
- int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
+ //int layer_num = CustomData_get_stencil_layer(&ps->me_eval->ldata, CD_MLOOPUV);
+ int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->ldata, CD_MLOOPUV);
if (layer_num != -1)
- ps->dm_mloopuv_stencil = CustomData_get_layer_n(&ps->dm->loopData, CD_MLOOPUV, layer_num);
+ ps->mloopuv_stencil_eval = CustomData_get_layer_n(&ps->me_eval->ldata, CD_MLOOPUV, layer_num);
- if (ps->dm_mloopuv_stencil == NULL) {
+ if (ps->mloopuv_stencil_eval == NULL) {
/* get active instead */
- ps->dm_mloopuv_stencil = CustomData_get_layer(&ps->dm->loopData, CD_MLOOPUV);
+ ps->mloopuv_stencil_eval = CustomData_get_layer(&ps->me_eval->ldata, CD_MLOOPUV);
}
if (ps->do_stencil_brush)
- mloopuv_base = ps->dm_mloopuv_stencil;
+ mloopuv_base = ps->mloopuv_stencil_eval;
}
/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
if (ps->is_shared_user == false) {
- proj_paint_state_non_cddm_init(ps);
-
proj_paint_state_cavity_init(ps);
}
- proj_paint_state_viewport_init(ps, symmetry_flag);
+ proj_paint_state_viewport_init(ps, CTX_data_depsgraph(C), symmetry_flag);
/* calculate vert screen coords
* run this early so we can calculate the x/y resolution of our bucket rect */
@@ -3914,7 +3899,7 @@ static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
/* setup clone offset */
if (ps->tool == PAINT_TOOL_CLONE) {
float projCo[4];
- copy_v3_v3(projCo, ED_view3d_cursor3d_get(ps->scene, ps->v3d));
+ copy_v3_v3(projCo, ps->scene->cursor.location);
mul_m4_v3(ps->obmat_imat, projCo);
projCo[3] = 1.0f;
@@ -3935,7 +3920,7 @@ static void project_paint_end(ProjPaintState *ps)
ProjPaintImage *projIma;
for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) {
BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL);
- DAG_id_tag_update(&projIma->ima->id, 0);
+ DEG_id_tag_update(&projIma->ima->id, 0);
}
}
@@ -3953,14 +3938,17 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN(ps->bucketFlags);
if (ps->is_shared_user == false) {
+ if (ps->mat_array != NULL) {
+ MEM_freeN(ps->mat_array);
+ }
/* must be set for non-shared */
- BLI_assert(ps->dm_mloopuv || ps->is_shared_user);
- if (ps->dm_mloopuv)
- MEM_freeN((void *)ps->dm_mloopuv);
+ BLI_assert(ps->poly_to_loop_uv || ps->is_shared_user);
+ if (ps->poly_to_loop_uv)
+ MEM_freeN((void *)ps->poly_to_loop_uv);
if (ps->do_layer_clone)
- MEM_freeN((void *)ps->dm_mloopuv_clone);
+ MEM_freeN((void *)ps->poly_to_loop_uv_clone);
if (ps->thread_tot > 1) {
BLI_spin_end(ps->tile_lock);
MEM_freeN((void *)ps->tile_lock);
@@ -3981,21 +3969,10 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN(ps->cavities);
}
- /* copy for subsurf/multires, so throw away */
- if (ps->dm->type != DM_TYPE_CDDM) {
- if (ps->dm_mvert) MEM_freeN((void *)ps->dm_mvert);
- if (ps->dm_mpoly) MEM_freeN((void *)ps->dm_mpoly);
- if (ps->dm_mloop) MEM_freeN((void *)ps->dm_mloop);
- /* looks like these don't need copying */
-#if 0
- if (ps->dm_mloopuv) MEM_freeN(ps->dm_mloopuv);
- if (ps->dm_mloopuv_clone) MEM_freeN(ps->dm_mloopuv_clone);
- if (ps->dm_mloopuv_stencil) MEM_freeN(ps->dm_mloopuv_stencil);
-#endif
+ if (ps->me_eval_free) {
+ BKE_id_free(NULL, ps->me_eval);
}
-
- if (ps->dm_release)
- ps->dm->release(ps->dm);
+ ps->me_eval = NULL;
}
if (ps->blurkernel) {
@@ -4702,6 +4679,41 @@ static void *do_projectpaint_thread(void *ph_v)
float texrgb[3];
float mask;
+ /* Extra mask for normal, layer stencil, .. */
+ float custom_mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+
+ /* Mask texture. */
+ if (ps->is_maskbrush) {
+ float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
+ CLAMP(texmask, 0.0f, 1.0f);
+ custom_mask *= texmask;
+ }
+
+ /* Color texture (alpha used as mask). */
+ if (ps->is_texbrush) {
+ MTex *mtex = &brush->mtex;
+ float samplecos[3];
+ float texrgba[4];
+
+ /* taking 3d copy to account for 3D mapping too. It gets concatenated during sampling */
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ copy_v3_v3(samplecos, projPixel->worldCoSS);
+ }
+ else {
+ copy_v2_v2(samplecos, projPixel->projCoSS);
+ samplecos[2] = 0.0f;
+ }
+
+ /* note, for clone and smear, we only use the alpha, could be a special function */
+ BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool);
+
+ copy_v3_v3(texrgb, texrgba);
+ custom_mask *= texrgba[3];
+ }
+ else {
+ zero_v3(texrgb);
+ }
+
if (ps->do_masking) {
/* masking to keep brush contribution to a pixel limited. note we do not do
* a simple max(mask, mask_accum), as this is very sensitive to spacing and
@@ -4710,12 +4722,7 @@ static void *do_projectpaint_thread(void *ph_v)
* Instead we use a formula that adds up but approaches brush_alpha slowly
* and never exceeds it, which gives nice smooth results. */
float mask_accum = *projPixel->mask_accum;
- float max_mask = brush_alpha * falloff * 65535.0f;
-
- if (ps->is_maskbrush) {
- float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
- max_mask *= texmask;
- }
+ float max_mask = brush_alpha * custom_mask * falloff * 65535.0f;
if (brush->flag & BRUSH_ACCUMULATE)
mask = mask_accum + max_mask;
@@ -4735,41 +4742,9 @@ static void *do_projectpaint_thread(void *ph_v)
}
}
else {
- mask = brush_alpha * falloff;
- if (ps->is_maskbrush) {
- float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
- CLAMP(texmask, 0.0f, 1.0f);
- mask *= texmask;
- }
- }
-
- if (ps->is_texbrush) {
- MTex *mtex = &brush->mtex;
- float samplecos[3];
- float texrgba[4];
-
- /* taking 3d copy to account for 3D mapping too. It gets concatenated during sampling */
- if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
- copy_v3_v3(samplecos, projPixel->worldCoSS);
- }
- else {
- copy_v2_v2(samplecos, projPixel->projCoSS);
- samplecos[2] = 0.0f;
- }
-
- /* note, for clone and smear, we only use the alpha, could be a special function */
- BKE_brush_sample_tex_3d(ps->scene, brush, samplecos, texrgba, thread_index, pool);
-
- copy_v3_v3(texrgb, texrgba);
- mask *= texrgba[3];
- }
- else {
- zero_v3(texrgb);
+ mask = brush_alpha * custom_mask * falloff;
}
- /* extra mask for normal, layer stencil, .. */
- mask *= ((float)projPixel->mask) * (1.0f / 65535.0f);
-
if (mask > 0.0f) {
/* copy of code above */
@@ -4882,7 +4857,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
struct ImagePool *pool;
if (!project_bucket_iter_init(ps, pos)) {
- return 0;
+ return touch_any;
}
if (ps->thread_tot > 1)
@@ -4948,16 +4923,16 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
tri_index = project_paint_PickFace(ps, pos, w);
if (tri_index != -1) {
- const MLoopTri *lt = &ps->dm_mlooptri[tri_index];
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const int lt_vtri[3] = { PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt) };
float world[3];
UnifiedPaintSettings *ups = &ps->scene->toolsettings->unified_paint_settings;
interp_v3_v3v3v3(
world,
- ps->dm_mvert[lt_vtri[0]].co,
- ps->dm_mvert[lt_vtri[1]].co,
- ps->dm_mvert[lt_vtri[2]].co,
+ ps->mvert_eval[lt_vtri[0]].co,
+ ps->mvert_eval[lt_vtri[1]].co,
+ ps->mvert_eval[lt_vtri[2]].co,
w);
ups->average_stroke_counter++;
@@ -5032,17 +5007,18 @@ void paint_proj_stroke(
/* clone gets special treatment here to avoid going through image initialization */
if (ps_handle->is_clone_cursor_pick) {
- Main *bmain = CTX_data_main(C);
Scene *scene = ps_handle->scene;
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
- float *cursor = ED_view3d_cursor3d_get(scene, v3d);
+ float *cursor = scene->cursor.location;
int mval_i[2] = {(int)pos[0], (int)pos[1]};
view3d_operator_needs_opengl(C);
- if (!ED_view3d_autodist(bmain, scene, ar, v3d, mval_i, cursor, false, NULL))
+ if (!ED_view3d_autodist(depsgraph, ar, v3d, mval_i, cursor, false, NULL)) {
return;
+ }
ED_region_tag_redraw(ar);
@@ -5098,6 +5074,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->rv3d = CTX_wm_region_view3d(C);
ps->ar = CTX_wm_region(C);
+ ps->depsgraph = CTX_data_depsgraph(C);
ps->scene = scene;
ps->ob = ob; /* allow override of active object */
@@ -5120,7 +5097,6 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
else {
ps->do_backfacecull = ps->do_occlude = ps->do_mask_normal = 0;
}
- ps->do_new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); /* only cache the value */
if (ps->tool == PAINT_TOOL_CLONE)
ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0;
@@ -5220,7 +5196,7 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
project_state_init(C, ob, ps, mode);
- if (ps->ob == NULL || !(ps->ob->lay & ps->v3d->lay)) {
+ if (ps->ob == NULL) {
ps_handle->ps_views_tot = i + 1;
goto fail;
}
@@ -5244,14 +5220,12 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
PROJ_PAINT_STATE_SHARED_MEMCPY(ps, ps_handle->ps_views[0]);
}
- project_paint_begin(ps, is_multi_view, symmetry_flag_views[i]);
-
- paint_proj_begin_clone(ps, mouse);
-
- if (ps->dm == NULL) {
+ project_paint_begin(C, ps, is_multi_view, symmetry_flag_views[i]);
+ if (ps->me_eval == NULL) {
goto fail;
- return NULL;
}
+
+ paint_proj_begin_clone(ps, mouse);
}
paint_brush_init_tex(ps_handle->brush);
@@ -5322,11 +5296,12 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
{
Image *image = BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->ptr, "image"));
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
ProjPaintState ps = {NULL};
int orig_brush_size;
IDProperty *idgroup;
IDProperty *view_data = NULL;
- Object *ob = OBACT;
+ Object *ob = OBACT(view_layer);
bool uvs, mat, tex;
if (ob == NULL || ob->type != OB_MESH) {
@@ -5396,10 +5371,11 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ED_image_undo_push_begin(op->type->name);
/* allocate and initialize spatial data structures */
- project_paint_begin(&ps, false, 0);
+ project_paint_begin(C, &ps, false, 0);
- if (ps.dm == NULL) {
+ if (ps.me_eval == NULL) {
BKE_brush_size_set(scene, ps.brush, orig_brush_size);
+ BKE_report(op->reports, RPT_ERROR, "Could not get valid evaluated mesh");
return OPERATOR_CANCELLED;
}
else {
@@ -5454,8 +5430,11 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
char filename[FILE_MAX];
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
int w = settings->imapaint.screen_grab_size[0];
int h = settings->imapaint.screen_grab_size[1];
int maxsize;
@@ -5469,9 +5448,10 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
if (h > maxsize) h = maxsize;
ibuf = ED_view3d_draw_offscreen_imbuf(
- bmain, scene, CTX_wm_view3d(C), CTX_wm_region(C),
+ depsgraph, scene, v3d->shading.type,
+ v3d, CTX_wm_region(C),
w, h, IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
- NULL, NULL, err_out);
+ NULL, err_out);
if (!ibuf) {
/* Mostly happens when OpenGL offscreen buffer was failed to create, */
/* but could be other reasons. Should be handled in the future. nazgul */
@@ -5487,9 +5467,6 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
if (image) {
/* now for the trickiness. store the view projection here!
* re-projection will reuse this */
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
-
IDPropertyTemplate val;
IDProperty *idgroup = IDP_GetProperties(&image->id, 1);
IDProperty *view_data;
@@ -5503,7 +5480,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
array = (float *)IDP_Array(view_data);
memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float);
memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float);
- is_ortho = ED_view3d_clip_range_get(v3d, rv3d, &array[0], &array[1], true);
+ is_ortho = ED_view3d_clip_range_get(CTX_data_depsgraph(C), v3d, rv3d, &array[0], &array[1], true);
/* using float for a bool is dodgy but since its an extra member in the array...
* easier then adding a single bool prop */
array[2] = is_ortho ? 1.0f : 0.0f;
@@ -5604,7 +5581,7 @@ bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *m
}
me = BKE_mesh_from_object(ob);
- layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ layernum = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
if (layernum == 0) {
hasuvs = false;
@@ -5641,22 +5618,24 @@ bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *m
}
/* Add layer operator */
+enum {
+ LAYER_BASE_COLOR,
+ LAYER_SPECULAR,
+ LAYER_ROUGHNESS,
+ LAYER_METALLIC,
+ LAYER_NORMAL,
+ LAYER_BUMP,
+ LAYER_DISPLACEMENT
+};
static const EnumPropertyItem layer_type_items[] = {
- {MAP_COL, "DIFFUSE_COLOR", 0, "Diffuse Color", ""},
- {MAP_REF, "DIFFUSE_INTENSITY", 0, "Diffuse Intensity", ""},
- {MAP_ALPHA, "ALPHA", 0, "Alpha", ""},
- {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", ""},
- {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specular Color", ""},
- {MAP_SPEC, "SPECULAR_INTENSITY", 0, "Specular Intensity", ""},
- {MAP_HAR, "SPECULAR_HARDNESS", 0, "Specular Hardness", ""},
- {MAP_AMB, "AMBIENT", 0, "Ambient", ""},
- {MAP_EMIT, "EMIT", 0, "Emit", ""},
- {MAP_COLMIR, "MIRROR_COLOR", 0, "Mirror Color", ""},
- {MAP_RAYMIRR, "RAYMIRROR", 0, "Ray Mirror", ""},
- {MAP_NORM, "NORMAL", 0, "Normal", ""},
- {MAP_WARP, "WARP", 0, "Warp", ""},
- {MAP_DISPLACE, "DISPLACE", 0, "Displace", ""},
+ {LAYER_BASE_COLOR, "BASE_COLOR", 0, "Base Color", ""},
+ {LAYER_SPECULAR, "SPECULAR", 0, "Specular", ""},
+ {LAYER_ROUGHNESS, "ROUGHNESS", 0, "Roughness", ""},
+ {LAYER_METALLIC, "METALLIC", 0, "Metallic", ""},
+ {LAYER_NORMAL, "NORMAL", 0, "Normal", ""},
+ {LAYER_BUMP, "BUMP", 0, "Bump", ""},
+ {LAYER_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -5687,12 +5666,62 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
return ima;
}
+static void proj_paint_default_color(wmOperator *op, int type, Material *ma)
+{
+ if (RNA_struct_property_is_set(op->ptr, "color")) {
+ return;
+ }
+
+ bNode *in_node = ntreeFindType(ma->nodetree, SH_NODE_BSDF_PRINCIPLED);
+ if (in_node == NULL) {
+ return;
+ }
+
+ float color[4];
+
+ if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
+ /* Copy color from node, so result is unchanged after assigning textures. */
+ bNodeSocket *in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
+
+ switch (in_sock->type) {
+ case SOCK_FLOAT: {
+ bNodeSocketValueFloat *socket_data = in_sock->default_value;
+ copy_v3_fl(color, socket_data->value);
+ color[3] = 1.0f;
+ break;
+ }
+ case SOCK_VECTOR:
+ case SOCK_RGBA: {
+ bNodeSocketValueRGBA *socket_data = in_sock->default_value;
+ copy_v3_v3(color, socket_data->value);
+ color[3] = 1.0f;
+ break;
+ }
+ default: {
+ return;
+ }
+ }
+ }
+ else if (type == LAYER_NORMAL) {
+ /* Neutral tangent space normal map. */
+ rgba_float_args_set(color, 0.5f, 0.5f, 1.0f, 1.0f);
+ }
+ else if (ELEM(type, LAYER_BUMP, LAYER_DISPLACEMENT)) {
+ /* Neutral displacement and bump map. */
+ rgba_float_args_set(color, 0.5f, 0.5f, 0.5f, 1.0f);
+ }
+ else {
+ return;
+ }
+
+ RNA_float_set_array(op->ptr, "color", color);
+}
+
static bool proj_paint_add_slot(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
Scene *scene = CTX_data_scene(C);
Material *ma;
- bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene);
Image *ima = NULL;
if (!ob)
@@ -5702,59 +5731,97 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
if (ma) {
Main *bmain = CTX_data_main(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ bNode *imanode;
+ bNodeTree *ntree = ma->nodetree;
+
+ if (!ntree) {
+ ED_node_shader_default(C, &ma->id);
+ ntree = ma->nodetree;
+ }
+
+ ma->use_nodes = true;
+
+ /* try to add an image node */
+ imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+
+ ima = proj_paint_image_create(op, bmain);
+ imanode->id = &ima->id;
+
+ nodeSetActive(ntree, imanode);
+
+ /* Connect to first available principled bsdf node. */
+ bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
+ bNode *out_node = imanode;
- if (!is_bi && BKE_scene_use_new_shading_nodes(scene)) {
- bNode *imanode;
- bNodeTree *ntree = ma->nodetree;
+ if (in_node != NULL) {
+ bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color");
+ bNodeSocket *in_sock = NULL;
- if (!ntree) {
- ED_node_shader_default(C, &ma->id);
- ntree = ma->nodetree;
+ if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
+ in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
}
+ else if (type == LAYER_NORMAL) {
+ bNode *nor_node;
+ nor_node = nodeAddStaticNode(C, ntree, SH_NODE_NORMAL_MAP);
- ma->use_nodes = true;
+ in_sock = nodeFindSocket(nor_node, SOCK_IN, "Color");
+ nodeAddLink(ntree, out_node, out_sock, nor_node, in_sock);
- /* try to add an image node */
- imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+ in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
+ out_sock = nodeFindSocket(nor_node, SOCK_OUT, "Normal");
- ima = proj_paint_image_create(op, bmain);
- imanode->id = &ima->id;
+ out_node = nor_node;
+ }
+ else if (type == LAYER_BUMP) {
+ bNode *bump_node;
+ bump_node = nodeAddStaticNode(C, ntree, SH_NODE_BUMP);
- nodeSetActive(ntree, imanode);
+ in_sock = nodeFindSocket(bump_node, SOCK_IN, "Height");
+ nodeAddLink(ntree, out_node, out_sock, bump_node, in_sock);
- ntreeUpdateTree(CTX_data_main(C), ntree);
- }
- else {
- MTex *mtex = BKE_texture_mtex_add_id(&ma->id, -1);
-
- /* successful creation of mtex layer, now create set */
- if (mtex) {
- int type = MAP_COL;
- char imagename_buff[MAX_ID_NAME - 2];
- const char *imagename = DATA_("Diffuse Color");
-
- if (op) {
- type = RNA_enum_get(op->ptr, "type");
- RNA_string_get(op->ptr, "name", imagename_buff);
- imagename = imagename_buff;
- }
+ in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
+ out_sock = nodeFindSocket(bump_node, SOCK_OUT, "Normal");
- mtex->tex = BKE_texture_add(bmain, imagename);
- mtex->mapto = type;
+ out_node = bump_node;
+ }
+ else if (type == LAYER_DISPLACEMENT) {
+ /* Connect to the displacement output socket */
+ in_node = ntreeFindType(ntree, SH_NODE_OUTPUT_MATERIAL);
- if (mtex->tex) {
- ima = mtex->tex->ima = proj_paint_image_create(op, bmain);
+ if (in_node != NULL) {
+ in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
+ }
+ else {
+ in_sock = NULL;
}
+ }
+
+ if (type > LAYER_BASE_COLOR) {
+ /* This is a "non color data" image */
+ NodeTexImage *tex = imanode->storage;
+ tex->color_space = SHD_COLORSPACE_NONE;
+ }
- WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, mtex->tex);
+ /* Check if the socket in already connected to something */
+ bNodeLink *link = in_sock ? in_sock->link : NULL;
+ if (in_sock != NULL && link == NULL) {
+ nodeAddLink(ntree, out_node, out_sock, in_node, in_sock);
+
+ nodePositionRelative(out_node, in_node, out_sock, in_sock);
}
}
+ ntreeUpdateTree(CTX_data_main(C), ntree);
+ /* In case we added more than one node, position them too. */
+ nodePositionPropagate(out_node);
+
if (ima) {
BKE_texpaint_slot_refresh_cache(scene, ma);
BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
- DAG_id_tag_update(&ma->id, 0);
+ DEG_id_tag_update(&ma->id, 0);
ED_area_tag_redraw(CTX_wm_area(C));
BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
@@ -5766,8 +5833,33 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
return false;
}
+static int get_texture_layer_type(wmOperator *op, const char *prop_name)
+{
+ int type_value = RNA_enum_get(op->ptr, prop_name);
+ int type = RNA_enum_from_value(layer_type_items, type_value);
+ BLI_assert(type != -1);
+ return type;
+}
+
+static Material *get_or_create_current_material(bContext *C, Object *ob)
+{
+ Material *ma = give_current_material(ob, ob->actcol);
+ if (!ma) {
+ Main *bmain = CTX_data_main(C);
+ ma = BKE_material_add(bmain, "Material");
+ assign_material(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+ return ma;
+}
+
static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op)
{
+ Object *ob = ED_object_active_context(C);
+ Material *ma = get_or_create_current_material(C, ob);
+
+ int type = get_texture_layer_type(op, "type");
+ proj_paint_default_color(op, type, ma);
+
if (proj_paint_add_slot(C, op)) {
return OPERATOR_FINISHED;
}
@@ -5776,31 +5868,23 @@ static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op
}
}
+static void get_default_texture_layer_name_for_object(Object *ob, int texture_type, char *dst, int dst_length)
+{
+ Material *ma = give_current_material(ob, ob->actcol);
+ const char *base_name = ma ? &ma->id.name[2] : &ob->id.name[2];
+ BLI_snprintf(dst, dst_length, "%s %s", base_name, layer_type_items[texture_type].name);
+}
static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- char imagename[MAX_ID_NAME - 2];
- Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
- Material *ma = give_current_material(ob, ob->actcol);
- int type = RNA_enum_get(op->ptr, "type");
-
- if (!ma) {
- ma = BKE_material_add(bmain, "Material");
- /* no material found, just assign to first slot */
- assign_material(bmain, ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
- }
-
- type = RNA_enum_from_value(layer_type_items, type);
-
- /* get the name of the texture layer type */
- BLI_assert(type != -1);
-
- /* take the second letter to avoid the ID identifier */
- BLI_snprintf(imagename, sizeof(imagename), "%s %s", &ma->id.name[2], layer_type_items[type].name);
+ int type = get_texture_layer_type(op, "type");
+ char imagename[MAX_ID_NAME - 2];
+ get_default_texture_layer_name_for_object(ob, type, (char *)&imagename, sizeof(imagename));
RNA_string_set(op->ptr, "name", imagename);
- return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
+
+ return WM_operator_props_dialog_popup(C, op, 300, 100);
}
#define IMA_DEF_NAME N_("Untitled")
@@ -5841,59 +5925,6 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
}
-static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
- Material *ma;
- bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene);
- TexPaintSlot *slot;
-
- /* not supported for node-based engines */
- if (!ob || !is_bi)
- return OPERATOR_CANCELLED;
-
- ma = give_current_material(ob, ob->actcol);
-
- if (!ma->texpaintslot || ma->use_nodes)
- return OPERATOR_CANCELLED;
-
- slot = ma->texpaintslot + ma->paint_active_slot;
-
- if (ma->mtex[slot->index]->tex) {
- id_us_min(&ma->mtex[slot->index]->tex->id);
-
- if (ma->mtex[slot->index]->tex->ima) {
- id_us_min(&ma->mtex[slot->index]->tex->ima->id);
- }
- }
- MEM_freeN(ma->mtex[slot->index]);
- ma->mtex[slot->index] = NULL;
-
- BKE_texpaint_slot_refresh_cache(scene, ma);
- DAG_id_tag_update(&ma->id, 0);
- WM_event_add_notifier(C, NC_MATERIAL, ma);
- /* we need a notifier for data change since we change the displayed modifier uvs */
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
- return OPERATOR_FINISHED;
-}
-
-
-void PAINT_OT_delete_texture_paint_slot(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Delete Texture Paint Slot";
- ot->description = "Delete selected texture paint slot";
- ot->idname = "PAINT_OT_delete_texture_paint_slot";
-
- /* api callbacks */
- ot->exec = texture_paint_delete_texture_paint_slot_exec;
- ot->poll = ED_operator_region_view3d_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
{
/* no checks here, poll function does them for us */
@@ -5930,7 +5961,7 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- DAG_id_tag_update(ob->data, 0);
+ DEG_id_tag_update(ob->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
return OPERATOR_FINISHED;
@@ -5940,9 +5971,9 @@ static bool add_simple_uvs_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT)
+ if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT) {
return false;
-
+ }
return true;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
index 7ec7dd20dc5..e26a4811afc 100644
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_image_undo.c
@@ -33,16 +33,18 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_workspace_types.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "ED_paint.h"
#include "ED_undo.h"
@@ -334,7 +336,7 @@ static void image_undo_restore_list(ListBase *lb, struct UndoIDPtrMap *id_map)
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
BKE_image_release_ibuf(ima, ibuf, NULL);
}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b782a47192a..b991755325a 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -54,10 +54,14 @@ struct wmEvent;
struct wmOperator;
struct wmOperatorType;
struct wmWindowManager;
-struct DMCoNo;
struct UndoStep;
enum ePaintMode;
+typedef struct CoNo {
+ float co[3];
+ float no[3];
+} CoNo;
+
/* paint_stroke.c */
typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
@@ -65,10 +69,11 @@ typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke,
typedef void (*StrokeRedraw)(const struct bContext *C, struct PaintStroke *stroke, bool final);
typedef void (*StrokeDone)(const struct bContext *C, struct PaintStroke *stroke);
-struct PaintStroke *paint_stroke_new(struct bContext *C, struct wmOperator *op,
- StrokeGetLocation get_location, StrokeTestStart test_start,
- StrokeUpdateStep update_step, StrokeRedraw redraw,
- StrokeDone done, int event_type);
+struct PaintStroke *paint_stroke_new(
+ struct bContext *C, struct wmOperator *op,
+ StrokeGetLocation get_location, StrokeTestStart test_start,
+ StrokeUpdateStep update_step, StrokeRedraw redraw,
+ StrokeDone done, int event_type);
void paint_stroke_data_free(struct wmOperator *op);
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
@@ -94,8 +99,10 @@ void paint_cursor_delete_textures(void);
/* paint_vertex.c */
bool weight_paint_poll(struct bContext *C);
+bool weight_paint_poll_ignore_tool(bContext *C);
bool weight_paint_mode_poll(struct bContext *C);
bool vertex_paint_poll(struct bContext *C);
+bool vertex_paint_poll_ignore_tool(struct bContext *C);
bool vertex_paint_mode_poll(struct bContext *C);
typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]);
@@ -113,7 +120,7 @@ void PAINT_OT_weight_gradient(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
-unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp);
+unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool secondary);
/* paint_vertex_color_utils.c */
unsigned int ED_vpaint_blend_tool(
@@ -157,10 +164,10 @@ void PAINT_OT_weight_sample_group(struct wmOperatorType *ot);
/* paint_vertex_proj.c */
struct VertProjHandle;
struct VertProjHandle *ED_vpaint_proj_handle_create(
- struct Scene *scene, struct Object *ob,
- struct DMCoNo **r_vcosnos);
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ struct CoNo **r_vcosnos);
void ED_vpaint_proj_handle_update(
- struct VertProjHandle *vp_handle,
+ struct Depsgraph *depsgraph, struct VertProjHandle *vp_handle,
/* runtime vars */
struct ARegion *ar, const float mval_fl[2]);
void ED_vpaint_proj_handle_free(
@@ -216,7 +223,6 @@ void PAINT_OT_texture_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_project_image(struct wmOperatorType *ot);
void PAINT_OT_image_from_view(struct wmOperatorType *ot);
void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
-void PAINT_OT_delete_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
@@ -247,21 +253,22 @@ void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
/* Convert the object-space axis-aligned bounding box (expressed as
* its minimum and maximum corners) into a screen-space rectangle,
* returns zero if the result is empty */
-bool paint_convert_bb_to_rect(struct rcti *rect,
- const float bb_min[3],
- const float bb_max[3],
- const struct ARegion *ar,
- struct RegionView3D *rv3d,
- struct Object *ob);
+bool paint_convert_bb_to_rect(
+ struct rcti *rect,
+ const float bb_min[3],
+ const float bb_max[3],
+ const struct ARegion *ar,
+ struct RegionView3D *rv3d,
+ struct Object *ob);
/* Get four planes in object-space that describe the projection of
* screen_rect from screen into object-space (essentially converting a
* 2D screens-space bounding box into four 3D planes) */
-void paint_calc_redraw_planes(float planes[4][4],
- const struct ARegion *ar,
- struct RegionView3D *rv3d,
- struct Object *ob,
- const struct rcti *screen_rect);
+void paint_calc_redraw_planes(
+ float planes[4][4],
+ const struct ARegion *ar,
+ struct Object *ob,
+ const struct rcti *screen_rect);
float paint_calc_object_space_radius(struct ViewContext *vc, const float center[3], float pixel_radius);
float paint_get_tex_pixel(const struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread);
@@ -299,19 +306,6 @@ typedef enum BrushStrokeMode {
BRUSH_STROKE_SMOOTH
} BrushStrokeMode;
-/* paint_ops.c */
-typedef enum {
- RC_COLOR = 1,
- RC_ROTATION = 2,
- RC_ZOOM = 4,
- RC_WEIGHT = 8,
- RC_SECONDARY_ROTATION = 16,
- RC_COLOR_OVERRIDE = 32,
-} RCFlags;
-
-void set_brush_rc_props(struct PointerRNA *ptr, const char *paint, const char *prop, const char *secondary_prop,
- RCFlags flags);
-
/* paint_hide.c */
typedef enum {
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index e0fdcc0c7c8..b8175e3d368 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -35,8 +35,6 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "BIF_glutil.h"
-
#include "BLI_bitmap_draw_2d.h"
#include "BLI_math_matrix.h"
#include "BLI_math_geom.h"
@@ -47,11 +45,12 @@
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -135,6 +134,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
struct Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
PaintMaskFloodMode mode;
float value;
PBVH *pbvh;
@@ -146,7 +146,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
mode = RNA_enum_get(op->ptr, "mode");
value = RNA_float_get(op->ptr, "value");
- BKE_sculpt_update_mesh_elements(scene, sd, ob, false, true);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
pbvh = ob->sculpt->pbvh;
multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
@@ -201,7 +201,7 @@ void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot)
"Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0, 1);
}
-/* Box select, operator is VIEW3D_OT_select_border, defined in view3d_select.c */
+/* Box select, operator is VIEW3D_OT_select_box, defined in view3d_select.c */
static bool is_effected(float planes[4][4], const float co[3])
{
@@ -258,11 +258,11 @@ static void mask_box_select_task_cb(
} BKE_pbvh_vertex_iter_end;
}
-int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select, bool UNUSED(extend))
+int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Sculpt *sd = vc->scene->toolsettings->sculpt;
BoundBox bb;
- bglMats mats = {{0}};
float clip_planes[4][4];
float clip_planes_final[4][4];
ARegion *ar = vc->ar;
@@ -280,11 +280,10 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r
value = select ? 1.0 : 0.0;
/* transform the clip planes in object space */
- view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, &mats);
- ED_view3d_clipping_calc(&bb, clip_planes, &mats, rect);
+ ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect);
negate_m4(clip_planes);
- BKE_sculpt_update_mesh_elements(scene, sd, ob, false, true);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
pbvh = ob->sculpt->pbvh;
multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
@@ -426,9 +425,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
float clip_planes[4][4], clip_planes_final[4][4];
BoundBox bb;
- bglMats mats = {{0}};
Object *ob;
ViewContext vc;
LassoMaskData data;
@@ -446,7 +445,6 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
* calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
* of lasso */
ED_view3d_viewcontext_init(C, &vc);
- view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
/* lasso data calculations */
data.vc = &vc;
@@ -462,10 +460,10 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
mcords, mcords_tot,
mask_lasso_px_cb, &data);
- ED_view3d_clipping_calc(&bb, clip_planes, &mats, &data.rect);
+ ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect);
negate_m4(clip_planes);
- BKE_sculpt_update_mesh_elements(scene, sd, ob, false, true);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true);
pbvh = ob->sculpt->pbvh;
multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 5a7dd0d5f2e..11565d665b1 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -29,24 +29,34 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
#include "DNA_customdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_paint.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
#include "ED_paint.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_image.h"
+#include "ED_gpencil.h"
#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -72,7 +82,7 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op))
br = BKE_brush_copy(bmain, br);
}
else {
- br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode));
+ br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paintmode(mode));
id_us_min(&br->id); /* fake user only */
}
@@ -95,6 +105,43 @@ static void BRUSH_OT_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /*int type = RNA_enum_get(op->ptr, "type");*/
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *br = BKE_paint_brush(paint);
+ Main *bmain = CTX_data_main(C);
+ // ePaintMode mode = PAINT_MODE_GPENCIL;
+
+ if (br) {
+ br = BKE_brush_copy(bmain, br);
+ }
+ else {
+ br = BKE_brush_add(bmain, "Brush", OB_MODE_GPENCIL_PAINT);
+ id_us_min(&br->id); /* fake user only */
+ }
+
+ BKE_paint_brush_set(paint, br);
+
+ /* TODO init grease pencil specific data */
+
+ return OPERATOR_FINISHED;
+}
+
+static void BRUSH_OT_add_gpencil(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Drawing Brush";
+ ot->description = "Add brush for Grease Pencil";
+ ot->idname = "BRUSH_OT_add_gpencil";
+
+ /* api callbacks */
+ ot->exec = brush_add_gpencil_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
static int brush_scale_size_exec(bContext *C, wmOperator *op)
{
@@ -231,7 +278,6 @@ static void PALETTE_OT_color_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -303,8 +349,7 @@ static void brush_tool_set(const Brush *brush, size_t tool_offset, int tool)
*(((char *)brush) + tool_offset) = tool;
}
-/* generic functions for setting the active brush based on the tool */
-static Brush *brush_tool_cycle(Main *bmain, Brush *brush_orig, const int tool, const size_t tool_offset, const int ob_mode)
+static Brush *brush_tool_cycle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool)
{
Brush *brush, *first_brush;
@@ -312,13 +357,18 @@ static Brush *brush_tool_cycle(Main *bmain, Brush *brush_orig, const int tool, c
return NULL;
}
- if (brush_tool(brush_orig, tool_offset) != tool) {
+ if (brush_tool(brush_orig, paint->runtime.tool_offset) != tool) {
/* If current brush's tool is different from what we need,
* start cycling from the beginning of the list.
* Such logic will activate the same exact brush not relating from
* which tool user requests other tool.
*/
- first_brush = bmain->brush.first;
+
+ /* Try to tool-slot first. */
+ first_brush = BKE_paint_toolslots_brush_get(paint, tool);
+ if (first_brush == NULL) {
+ first_brush = bmain->brush.first;
+ }
}
else {
/* If user wants to switch to brush with the same tool as
@@ -331,8 +381,8 @@ static Brush *brush_tool_cycle(Main *bmain, Brush *brush_orig, const int tool, c
/* get the next brush with the active tool */
brush = first_brush;
do {
- if ((brush->ob_mode & ob_mode) &&
- (brush_tool(brush, tool_offset) == tool))
+ if ((brush->ob_mode & paint->runtime.ob_mode) &&
+ (brush_tool(brush, paint->runtime.tool_offset) == tool))
{
return brush;
}
@@ -343,13 +393,13 @@ static Brush *brush_tool_cycle(Main *bmain, Brush *brush_orig, const int tool, c
return NULL;
}
-static Brush *brush_tool_toggle(Main *bmain, Brush *brush_orig, const int tool, const size_t tool_offset, const int ob_mode)
+static Brush *brush_tool_toggle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool)
{
- if (!brush_orig || brush_tool(brush_orig, tool_offset) != tool) {
+ if (!brush_orig || brush_tool(brush_orig, paint->runtime.tool_offset) != tool) {
Brush *br;
/* if the current brush is not using the desired tool, look
* for one that is */
- br = brush_tool_cycle(bmain, brush_orig, tool, tool_offset, ob_mode);
+ br = brush_tool_cycle(bmain, paint, brush_orig, tool);
/* store the previously-selected brush */
if (br)
br->toggle_brush = brush_orig;
@@ -367,21 +417,22 @@ static Brush *brush_tool_toggle(Main *bmain, Brush *brush_orig, const int tool,
static int brush_generic_tool_set(
Main *bmain, Paint *paint, const int tool,
- const size_t tool_offset, const int ob_mode,
const char *tool_name, const bool create_missing,
const bool toggle)
{
Brush *brush, *brush_orig = BKE_paint_brush(paint);
- if (toggle)
- brush = brush_tool_toggle(bmain, brush_orig, tool, tool_offset, ob_mode);
- else
- brush = brush_tool_cycle(bmain, brush_orig, tool, tool_offset, ob_mode);
+ if (toggle) {
+ brush = brush_tool_toggle(bmain, paint, brush_orig, tool);
+ }
+ else {
+ brush = brush_tool_cycle(bmain, paint, brush_orig, tool);
+ }
- if (!brush && brush_tool(brush_orig, tool_offset) != tool && create_missing) {
- brush = BKE_brush_add(bmain, tool_name, ob_mode);
+ if (!brush && brush_tool(brush_orig, paint->runtime.tool_offset) != tool && create_missing) {
+ brush = BKE_brush_add(bmain, tool_name, paint->runtime.ob_mode);
id_us_min(&brush->id); /* fake user only */
- brush_tool_set(brush, tool_offset, tool);
+ brush_tool_set(brush, paint->runtime.tool_offset, tool);
brush->toggle_brush = brush_orig;
}
@@ -397,78 +448,49 @@ static int brush_generic_tool_set(
}
}
-/* used in the PAINT_OT_brush_select operator */
-#define OB_MODE_ACTIVE 0
+static const ePaintMode brush_select_paint_modes[] = {
+ PAINT_MODE_SCULPT,
+ PAINT_MODE_VERTEX,
+ PAINT_MODE_WEIGHT,
+ PAINT_MODE_TEXTURE_3D,
+ PAINT_MODE_GPENCIL,
+};
static int brush_select_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- ToolSettings *toolsettings = CTX_data_tool_settings(C);
- Paint *paint = NULL;
- int tool, paint_mode = RNA_enum_get(op->ptr, "paint_mode");
+ Scene *scene = CTX_data_scene(C);
const bool create_missing = RNA_boolean_get(op->ptr, "create_missing");
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
const char *tool_name = "Brush";
- size_t tool_offset;
-
- if (paint_mode == OB_MODE_ACTIVE) {
- Object *ob = CTX_data_active_object(C);
- if (ob) {
- /* select current paint mode */
- paint_mode = ob->mode & OB_MODE_ALL_PAINT;
- }
- else {
- return OPERATOR_CANCELLED;
+ int tool = 0;
+
+ ePaintMode paint_mode = PAINT_MODE_INVALID;
+ for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) {
+ paint_mode = brush_select_paint_modes[i];
+ const char *op_prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, op_prop_id);
+ if (RNA_property_is_set(op->ptr, prop)) {
+ tool = RNA_property_enum_get(op->ptr, prop);
+ break;
}
}
- switch (paint_mode) {
- case OB_MODE_SCULPT:
- paint = &toolsettings->sculpt->paint;
- tool_offset = offsetof(Brush, sculpt_tool);
- tool = RNA_enum_get(op->ptr, "sculpt_tool");
- RNA_enum_name_from_value(rna_enum_brush_sculpt_tool_items, tool, &tool_name);
- break;
- case OB_MODE_VERTEX_PAINT:
- paint = &toolsettings->vpaint->paint;
- tool_offset = offsetof(Brush, vertexpaint_tool);
- tool = RNA_enum_get(op->ptr, "vertex_paint_tool");
- RNA_enum_name_from_value(rna_enum_brush_vertex_tool_items, tool, &tool_name);
- break;
- case OB_MODE_WEIGHT_PAINT:
- paint = &toolsettings->wpaint->paint;
- /* vertexpaint_tool is used for weight paint mode */
- tool_offset = offsetof(Brush, vertexpaint_tool);
- tool = RNA_enum_get(op->ptr, "weight_paint_tool");
- RNA_enum_name_from_value(rna_enum_brush_vertex_tool_items, tool, &tool_name);
- break;
- case OB_MODE_TEXTURE_PAINT:
- paint = &toolsettings->imapaint.paint;
- tool_offset = offsetof(Brush, imagepaint_tool);
- tool = RNA_enum_get(op->ptr, "texture_paint_tool");
- RNA_enum_name_from_value(rna_enum_brush_image_tool_items, tool, &tool_name);
- break;
- default:
- /* invalid paint mode */
- return OPERATOR_CANCELLED;
+ if (paint_mode == PAINT_MODE_INVALID) {
+ return OPERATOR_CANCELLED;
}
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
+ const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ RNA_enum_name_from_value(items, tool, &tool_name);
return brush_generic_tool_set(
- bmain, paint, tool, tool_offset,
- paint_mode, tool_name, create_missing,
+ bmain, paint, tool,
+ tool_name, create_missing,
toggle);
}
static void PAINT_OT_brush_select(wmOperatorType *ot)
{
- static const EnumPropertyItem paint_mode_items[] = {
- {OB_MODE_ACTIVE, "ACTIVE", 0, "Current", "Set brush for active paint mode"},
- {OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt", ""},
- {OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""},
- {OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
- {OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
- {0, NULL, 0, NULL, NULL}
- };
PropertyRNA *prop;
/* identifiers */
@@ -483,46 +505,18 @@ static void PAINT_OT_brush_select(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_enum(ot->srna, "paint_mode", paint_mode_items, OB_MODE_ACTIVE, "Paint Mode", "");
- RNA_def_enum(ot->srna, "sculpt_tool", rna_enum_brush_sculpt_tool_items, 0, "Sculpt Tool", "");
- RNA_def_enum(ot->srna, "vertex_paint_tool", rna_enum_brush_vertex_tool_items, 0, "Vertex Paint Tool", "");
- RNA_def_enum(ot->srna, "weight_paint_tool", rna_enum_brush_vertex_tool_items, 0, "Weight Paint Tool", "");
- RNA_def_enum(ot->srna, "texture_paint_tool", rna_enum_brush_image_tool_items, 0, "Texture Paint Tool", "");
+ /* All properties are hidden, so as not to show the redo panel. */
+ for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) {
+ const ePaintMode paint_mode = brush_select_paint_modes[i];
+ const char *prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
+ prop = RNA_def_enum(ot->srna, prop_id, BKE_paint_get_tool_enum_from_paintmode(paint_mode), 0, prop_id, "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle between two brushes rather than cycling");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "create_missing", 0, "Create Missing", "If the requested brush type does not exist, create a new brush");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-static wmKeyMapItem *keymap_brush_select(
- wmKeyMap *keymap, int paint_mode,
- int tool, int keymap_type,
- int keymap_modifier)
-{
- wmKeyMapItem *kmi;
- kmi = WM_keymap_add_item(
- keymap, "PAINT_OT_brush_select",
- keymap_type, KM_PRESS, keymap_modifier, 0);
-
- RNA_enum_set(kmi->ptr, "paint_mode", paint_mode);
-
- switch (paint_mode) {
- case OB_MODE_SCULPT:
- RNA_enum_set(kmi->ptr, "sculpt_tool", tool);
- break;
- case OB_MODE_VERTEX_PAINT:
- RNA_enum_set(kmi->ptr, "vertex_paint_tool", tool);
- break;
- case OB_MODE_WEIGHT_PAINT:
- RNA_enum_set(kmi->ptr, "weight_paint_tool", tool);
- break;
- case OB_MODE_TEXTURE_PAINT:
- RNA_enum_set(kmi->ptr, "texture_paint_tool", tool);
- break;
- }
-
- return kmi;
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
static int brush_uv_sculpt_tool_set_exec(bContext *C, wmOperator *op)
@@ -961,28 +955,6 @@ static void BRUSH_OT_stencil_reset_transform(wmOperatorType *ot)
}
-static void ed_keymap_stencil(wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- kmi = WM_keymap_add_item(keymap, "BRUSH_OT_stencil_control", RIGHTMOUSE, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", STENCIL_TRANSLATE);
- kmi = WM_keymap_add_item(keymap, "BRUSH_OT_stencil_control", RIGHTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "mode", STENCIL_SCALE);
- kmi = WM_keymap_add_item(keymap, "BRUSH_OT_stencil_control", RIGHTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "mode", STENCIL_ROTATE);
-
- kmi = WM_keymap_add_item(keymap, "BRUSH_OT_stencil_control", RIGHTMOUSE, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "mode", STENCIL_TRANSLATE);
- RNA_enum_set(kmi->ptr, "texmode", STENCIL_SECONDARY);
- kmi = WM_keymap_add_item(keymap, "BRUSH_OT_stencil_control", RIGHTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "texmode", STENCIL_SECONDARY);
- RNA_enum_set(kmi->ptr, "mode", STENCIL_SCALE);
- kmi = WM_keymap_add_item(keymap, "BRUSH_OT_stencil_control", RIGHTMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "texmode", STENCIL_SECONDARY);
- RNA_enum_set(kmi->ptr, "mode", STENCIL_ROTATE);
-}
-
/**************************** registration **********************************/
void ED_operatormacros_paint(void)
@@ -1019,6 +991,7 @@ void ED_operatortypes_paint(void)
/* brush */
WM_operatortype_append(BRUSH_OT_add);
+ WM_operatortype_append(BRUSH_OT_add_gpencil);
WM_operatortype_append(BRUSH_OT_scale_size);
WM_operatortype_append(BRUSH_OT_curve_preset);
WM_operatortype_append(BRUSH_OT_reset);
@@ -1039,7 +1012,6 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_image_from_view);
WM_operatortype_append(PAINT_OT_brush_colors_flip);
WM_operatortype_append(PAINT_OT_add_texture_paint_slot);
- WM_operatortype_append(PAINT_OT_delete_texture_paint_slot);
WM_operatortype_append(PAINT_OT_add_simple_uvs);
/* weight */
@@ -1085,396 +1057,40 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_mask_lasso_gesture);
}
-
-static void ed_keymap_paint_brush_switch(wmKeyMap *keymap, const char *mode)
-{
- wmKeyMapItem *kmi;
- int i;
- /* index 0-9 (zero key is tenth), shift key for index 10-19 */
- for (i = 0; i < 20; i++) {
- kmi = WM_keymap_add_item(
- keymap, "BRUSH_OT_active_index_set",
- ZEROKEY + ((i + 1) % 10), KM_PRESS, i < 10 ? 0 : KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "mode", mode);
- RNA_int_set(kmi->ptr, "index", i);
- }
-}
-
-static void ed_keymap_paint_brush_size(wmKeyMap *keymap, const char *UNUSED(path))
-{
- wmKeyMapItem *kmi;
-
- kmi = WM_keymap_add_item(keymap, "BRUSH_OT_scale_size", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_float_set(kmi->ptr, "scalar", 0.9);
-
- kmi = WM_keymap_add_item(keymap, "BRUSH_OT_scale_size", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_float_set(kmi->ptr, "scalar", 10.0 / 9.0); // 1.1111....
-}
-
-static void set_brush_rc_path(
- PointerRNA *ptr, const char *brush_path,
- const char *output_name, const char *input_name)
-{
- char *path;
-
- path = BLI_sprintfN("%s.%s", brush_path, input_name);
- RNA_string_set(ptr, output_name, path);
- MEM_freeN(path);
-}
-
-void set_brush_rc_props(
- PointerRNA *ptr, const char *paint,
- const char *prop, const char *secondary_prop,
- RCFlags flags)
-{
- const char *ups_path = "tool_settings.unified_paint_settings";
- char *brush_path;
-
- brush_path = BLI_sprintfN("tool_settings.%s.brush", paint);
-
- set_brush_rc_path(ptr, brush_path, "data_path_primary", prop);
- if (secondary_prop) {
- set_brush_rc_path(ptr, ups_path, "use_secondary", secondary_prop);
- set_brush_rc_path(ptr, ups_path, "data_path_secondary", prop);
- }
- else {
- RNA_string_set(ptr, "use_secondary", "");
- RNA_string_set(ptr, "data_path_secondary", "");
- }
- set_brush_rc_path(ptr, brush_path, "color_path", "cursor_color_add");
- if (flags & RC_SECONDARY_ROTATION)
- set_brush_rc_path(ptr, brush_path, "rotation_path", "mask_texture_slot.angle");
- else
- set_brush_rc_path(ptr, brush_path, "rotation_path", "texture_slot.angle");
- RNA_string_set(ptr, "image_id", brush_path);
-
- if (flags & RC_COLOR) {
- set_brush_rc_path(ptr, brush_path, "fill_color_path", "color");
- }
- else {
- RNA_string_set(ptr, "fill_color_path", "");
- }
-
- if (flags & RC_COLOR_OVERRIDE) {
- RNA_string_set(ptr, "fill_color_override_path", "tool_settings.unified_paint_settings.color");
- RNA_string_set(ptr, "fill_color_override_test_path", "tool_settings.unified_paint_settings.use_unified_color");
- }
- else {
- RNA_string_set(ptr, "fill_color_override_path", "");
- RNA_string_set(ptr, "fill_color_override_test_path", "");
- }
-
- if (flags & RC_ZOOM)
- RNA_string_set(ptr, "zoom_path", "space_data.zoom");
- else
- RNA_string_set(ptr, "zoom_path", "");
-
- RNA_boolean_set(ptr, "secondary_tex", (flags & RC_SECONDARY_ROTATION) != 0);
-
- MEM_freeN(brush_path);
-}
-
-static void ed_keymap_paint_brush_radial_control(
- wmKeyMap *keymap, const char *paint,
- RCFlags flags)
-{
- wmKeyMapItem *kmi;
- /* only size needs to follow zoom, strength shows fixed size circle */
- int flags_nozoom = flags & (~RC_ZOOM);
- int flags_noradial_secondary = flags & (~(RC_SECONDARY_ROTATION | RC_ZOOM));
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0);
- set_brush_rc_props(kmi->ptr, paint, "size", "use_unified_size", flags);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
- set_brush_rc_props(kmi->ptr, paint, "strength", "use_unified_strength", flags_nozoom);
-
- if (flags & RC_WEIGHT) {
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", WKEY, KM_PRESS, 0, 0);
- set_brush_rc_props(kmi->ptr, paint, "weight", "use_unified_weight", flags_nozoom);
- }
-
- if (flags & RC_ROTATION) {
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
- set_brush_rc_props(kmi->ptr, paint, "texture_slot.angle", NULL, flags_noradial_secondary);
- }
-
- if (flags & RC_SECONDARY_ROTATION) {
- kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- set_brush_rc_props(kmi->ptr, paint, "mask_texture_slot.angle", NULL, flags_nozoom);
- }
-}
-
-static void paint_partial_visibility_keys(wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- /* Partial visibility */
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_hide_show", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "action", PARTIALVIS_SHOW);
- RNA_enum_set(kmi->ptr, "area", PARTIALVIS_INSIDE);
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_hide_show", HKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", PARTIALVIS_HIDE);
- RNA_enum_set(kmi->ptr, "area", PARTIALVIS_INSIDE);
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_hide_show", HKEY, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "action", PARTIALVIS_SHOW);
- RNA_enum_set(kmi->ptr, "area", PARTIALVIS_ALL);
-}
-
-
-static void paint_keymap_curve(wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- WM_keymap_add_item(keymap, "PAINTCURVE_OT_add_point_slide", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "align", true);
- kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", AKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- WM_keymap_add_item(keymap, "PAINTCURVE_OT_cursor", ACTIONMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINTCURVE_OT_delete_point", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINTCURVE_OT_delete_point", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", RETKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", PADENTER, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0);
- WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0);
-}
-
void ED_keymap_paint(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
- wmKeyMapItem *kmi;
- int i;
keymap = WM_keymap_ensure(keyconf, "Paint Curve", 0, 0);
keymap->poll = paint_curve_poll;
- paint_keymap_curve(keymap);
-
/* Sculpt mode */
keymap = WM_keymap_ensure(keyconf, "Sculpt", 0, 0);
keymap->poll = sculpt_mode_poll;
- RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", BRUSH_STROKE_NORMAL);
- RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", BRUSH_STROKE_INVERT);
- RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", BRUSH_STROKE_SMOOTH);
-
- /* Partial visibility, sculpt-only for now */
- paint_partial_visibility_keys(keymap);
-
- for (i = 0; i <= 5; i++)
- RNA_int_set(WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY + i, KM_PRESS, KM_CTRL, 0)->ptr, "level", i);
-
- /* Clear mask */
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_mask_flood_fill", MKEY, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "mode", PAINT_MASK_FLOOD_VALUE);
- RNA_float_set(kmi->ptr, "value", 0);
-
- /* Invert mask */
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_mask_flood_fill", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "mode", PAINT_MASK_INVERT);
-
- WM_keymap_add_item(keymap, "PAINT_OT_mask_lasso_gesture", LEFTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
-
- /* Toggle mask visibility */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "scene.tool_settings.sculpt.show_mask");
-
- /* Toggle dynamic topology */
- WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0);
-
- /* Dynamic-topology detail size
- *
- * This should be improved further, perhaps by showing a triangle
- * grid rather than brush alpha */
- kmi = WM_keymap_add_item(keymap, "SCULPT_OT_set_detail_size", DKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* multires switch */
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", PAGEUPKEY, KM_PRESS, 0, 0);
- RNA_int_set(kmi->ptr, "level", 1);
- RNA_boolean_set(kmi->ptr, "relative", true);
-
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", PAGEDOWNKEY, KM_PRESS, 0, 0);
- RNA_int_set(kmi->ptr, "level", -1);
- RNA_boolean_set(kmi->ptr, "relative", true);
-
- ed_keymap_paint_brush_switch(keymap, "sculpt");
- ed_keymap_paint_brush_size(keymap, "tool_settings.sculpt.brush.size");
- ed_keymap_paint_brush_radial_control(keymap, "sculpt", RC_ROTATION);
-
- ed_keymap_stencil(keymap);
-
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_DRAW, XKEY, 0);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_SMOOTH, SKEY, 0);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_PINCH, PKEY, 0);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_INFLATE, IKEY, 0);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_GRAB, GKEY, 0);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_LAYER, LKEY, 0);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_FLATTEN, TKEY, KM_SHIFT);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_CLAY, CKEY, 0);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_CREASE, CKEY, KM_SHIFT);
- keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_SNAKE_HOOK, KKEY, 0);
- kmi = keymap_brush_select(keymap, OB_MODE_SCULPT, SCULPT_TOOL_MASK, MKEY, 0);
- RNA_boolean_set(kmi->ptr, "toggle", 1);
- RNA_boolean_set(kmi->ptr, "create_missing", 1);
-
- /* */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.stroke_method");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.use_smooth_stroke");
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_angle_control", RKEY, KM_PRESS, 0, 0);
-
/* Vertex Paint mode */
keymap = WM_keymap_ensure(keyconf, "Vertex Paint", 0, 0);
keymap->poll = vertex_paint_mode_poll;
- WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "PAINT_OT_vertex_color_set", KKEY, KM_PRESS, KM_SHIFT, 0);
-
- ed_keymap_paint_brush_switch(keymap, "vertex_paint");
- ed_keymap_paint_brush_size(keymap, "tool_settings.vertex_paint.brush.size");
- ed_keymap_paint_brush_radial_control(keymap, "vertex_paint", RC_COLOR | RC_COLOR_OVERRIDE | RC_ROTATION);
-
- ed_keymap_stencil(keymap);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */
- RNA_string_set(kmi->ptr, "data_path", "vertex_paint_object.data.use_paint_mask");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.use_smooth_stroke");
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_angle_control", RKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method");
-
/* Weight Paint mode */
keymap = WM_keymap_ensure(keyconf, "Weight Paint", 0, 0);
keymap->poll = weight_paint_mode_poll;
- WM_keymap_verify_item(keymap, "PAINT_OT_weight_paint", LEFTMOUSE, KM_PRESS, 0, 0);
-
- /* these keys are from 2.4x but could be changed */
- WM_keymap_verify_item(keymap, "PAINT_OT_weight_sample", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "PAINT_OT_weight_sample_group", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_gradient", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "type", WPAINT_GRADIENT_TYPE_LINEAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_gradient", LEFTMOUSE, KM_PRESS, KM_ALT | KM_CTRL, 0)->ptr, "type", WPAINT_GRADIENT_TYPE_RADIAL);
-
- WM_keymap_add_item(keymap, "PAINT_OT_weight_set", KKEY, KM_PRESS, KM_SHIFT, 0);
-
- ed_keymap_paint_brush_switch(keymap, "weight_paint");
- ed_keymap_paint_brush_size(keymap, "tool_settings.weight_paint.brush.size");
- ed_keymap_paint_brush_radial_control(keymap, "weight_paint", RC_WEIGHT);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* face mask toggle */
- RNA_string_set(kmi->ptr, "data_path", "weight_paint_object.data.use_paint_mask");
-
- /* note, conflicts with vertex paint, but this is more useful */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", VKEY, KM_PRESS, 0, 0); /* vert mask toggle */
- RNA_string_set(kmi->ptr, "data_path", "weight_paint_object.data.use_paint_mask_vertex");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.weight_paint.brush.use_smooth_stroke");
-
/*Weight paint's Vertex Selection Mode */
keymap = WM_keymap_ensure(keyconf, "Weight Paint Vertex Selection", 0, 0);
keymap->poll = vert_paint_poll;
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_vert_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_vert_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
- WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
- WM_keymap_add_item(keymap, "VIEW3D_OT_select_circle", CKEY, KM_PRESS, 0, 0);
/* Image/Texture Paint mode */
keymap = WM_keymap_ensure(keyconf, "Image Paint", 0, 0);
keymap->poll = image_texture_paint_poll;
- RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", BRUSH_STROKE_NORMAL);
- RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", BRUSH_STROKE_INVERT);
- WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", RIGHTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0);
-
- ed_keymap_paint_brush_switch(keymap, "image_paint");
- ed_keymap_paint_brush_size(keymap, "tool_settings.image_paint.brush.size");
- ed_keymap_paint_brush_radial_control(
- keymap, "image_paint",
- RC_COLOR | RC_COLOR_OVERRIDE | RC_ZOOM | RC_ROTATION | RC_SECONDARY_ROTATION);
-
- ed_keymap_stencil(keymap);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */
- RNA_string_set(kmi->ptr, "data_path", "image_paint_object.data.use_paint_mask");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.use_smooth_stroke");
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_angle_control", RKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.stroke_method");
-
/* face-mask mode */
keymap = WM_keymap_ensure(keyconf, "Face Mask", 0, 0);
keymap->poll = facemask_paint_poll;
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
- WM_keymap_add_item(keymap, "PAINT_OT_face_select_reveal", HKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "PAINT_OT_face_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_linked_pick", LKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
keymap = WM_keymap_ensure(keyconf, "UV Sculpt", 0, 0);
keymap->poll = uv_sculpt_keymap_poll;
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_uv_sculpt");
-
- RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_uv_sculpt_stroke", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", BRUSH_STROKE_NORMAL);
- RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_uv_sculpt_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", BRUSH_STROKE_INVERT);
- RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_uv_sculpt_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", BRUSH_STROKE_SMOOTH);
-
- ed_keymap_paint_brush_size(keymap, "tool_settings.uv_sculpt.brush.size");
- ed_keymap_paint_brush_radial_control(keymap, "uv_sculpt", 0);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "BRUSH_OT_uv_sculpt_tool_set", SKEY, KM_PRESS, 0, 0)->ptr, "tool", UV_SCULPT_TOOL_RELAX);
- RNA_enum_set(WM_keymap_add_item(keymap, "BRUSH_OT_uv_sculpt_tool_set", PKEY, KM_PRESS, 0, 0)->ptr, "tool", UV_SCULPT_TOOL_PINCH);
- RNA_enum_set(WM_keymap_add_item(keymap, "BRUSH_OT_uv_sculpt_tool_set", GKEY, KM_PRESS, 0, 0)->ptr, "tool", UV_SCULPT_TOOL_GRAB);
-
/* paint stroke */
keymap = paint_stroke_modal_keymap(keyconf);
WM_modalkeymap_assign(keymap, "SCULPT_OT_brush_stroke");
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 1bfa0bef2f2..15dd0438585 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -38,6 +38,8 @@
#include "BLI_rand.h"
#include "BLI_listbase.h"
+#include "PIL_time.h"
+
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
@@ -51,6 +53,7 @@
#include "BKE_curve.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
+#include "BKE_mesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -58,7 +61,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -85,6 +89,7 @@ typedef struct PaintStroke {
void *mode_data;
void *stroke_cursor;
wmTimer *timer;
+ struct RNG *rng;
/* Cached values */
ViewContext vc;
@@ -145,13 +150,27 @@ static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata
PaintStroke *stroke = customdata;
if (stroke && brush) {
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glColor4ubv(paint->paint_cursor_col);
- sdrawline(x, y, (int)stroke->last_mouse_position[0],
- (int)stroke->last_mouse_position[1]);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+
+ ARegion *ar = stroke->vc.ar;
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(paint->paint_cursor_col);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, y);
+ immVertex2f(pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
}
}
@@ -160,38 +179,47 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
Paint *paint = BKE_paint_get_active_from_context(C);
PaintStroke *stroke = customdata;
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ GPU_line_smooth(true);
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(3, 0xAAAA);
- GPU_basic_shader_line_width(3.0);
+ uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- glColor4ub(0, 0, 0, paint->paint_cursor_col[3]);
- if (stroke->constrain_line) {
- sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
- stroke->constrained_pos[0], stroke->constrained_pos[1]);
- }
- else {
- sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
- x, y);
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float alpha = (float)paint->paint_cursor_col[3] / 255.0f;
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.0f, 0.0f, 0.0f, alpha}, {1.0f, 1.0f, 1.0f, alpha}}, 2);
+ immUniform1f("dash_width", 6.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ ARegion *ar = stroke->vc.ar;
- glColor4ub(255, 255, 255, paint->paint_cursor_col[3]);
- GPU_basic_shader_line_width(1.0);
if (stroke->constrain_line) {
- sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
- stroke->constrained_pos[0], stroke->constrained_pos[1]);
+ immVertex2f(shdr_pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
+
+ immVertex2f(shdr_pos,
+ stroke->constrained_pos[0] + ar->winrct.xmin,
+ stroke->constrained_pos[1] + ar->winrct.ymin);
}
else {
- sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
- x, y);
+ immVertex2f(shdr_pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
+
+ immVertex2f(shdr_pos, x, y);
}
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ immEnd();
+
+ immUnbindProgram();
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ GPU_line_smooth(false);
}
static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
@@ -383,19 +411,24 @@ static bool paint_brush_update(
}
}
+ if ((do_random || do_random_mask) && stroke->rng == NULL) {
+ /* Lazy initialization. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= (uint)POINTER_AS_INT(brush);
+ stroke->rng = BLI_rng_new(rng_seed);
+ }
+
if (do_random) {
if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
- ups->brush_rotation += (
- -brush->mtex.random_angle / 2.0f +
- brush->mtex.random_angle * BLI_frand());
+ ups->brush_rotation += -brush->mtex.random_angle / 2.0f +
+ brush->mtex.random_angle * BLI_rng_get_float(stroke->rng);
}
}
if (do_random_mask) {
if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
- ups->brush_rotation_sec += (
- -brush->mask_mtex.random_angle / 2.0f +
- brush->mask_mtex.random_angle * BLI_frand());
+ ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f +
+ brush->mask_mtex.random_angle * BLI_rng_get_float(stroke->rng);
}
}
@@ -788,6 +821,10 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
stroke->timer);
}
+ if (stroke->rng) {
+ BLI_rng_free(stroke->rng);
+ }
+
if (stroke->stroke_cursor)
WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
@@ -901,10 +938,6 @@ struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
/* this function is called for each spacetype, only needs to add map once */
if (!keymap) {
keymap = WM_modalkeymap_add(keyconf, name, modal_items);
-
- /* items for modal map */
- WM_modalkeymap_add_item(
- keymap, ESCKEY, KM_PRESS, KM_ANY, 0, PAINT_STROKE_MODAL_CANCEL);
}
return keymap;
@@ -1164,8 +1197,10 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
if (paint_supports_smooth_stroke(br, mode))
- stroke->stroke_cursor =
- WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_cursor, stroke);
+ stroke->stroke_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ paint_poll, paint_draw_smooth_cursor, stroke);
stroke->stroke_init = true;
first_modal = true;
@@ -1183,8 +1218,10 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
if (br->flag & BRUSH_LINE) {
- stroke->stroke_cursor =
- WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_line_cursor, stroke);
+ stroke->stroke_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ paint_poll, paint_draw_line_cursor, stroke);
}
first_dab = true;
@@ -1353,7 +1390,15 @@ bool paint_poll(bContext *C)
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- return p && ob && BKE_paint_brush(p) &&
- (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
- (ar && ar->regiontype == RGN_TYPE_WINDOW);
+ if (p && ob && BKE_paint_brush(p) &&
+ (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
+ (ar && ar->regiontype == RGN_TYPE_WINDOW))
+ {
+ /* Check the current tool is a brush. */
+ bToolRef *tref = sa->runtime.tool;
+ if (tref && tref->runtime && tref->runtime->data_block[0]) {
+ return true;
+ }
+ }
+ return false;
}
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 71b63ccbdff..45200924790 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -50,17 +50,23 @@
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
#include "BKE_image.h"
#include "BKE_material.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_glew.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
@@ -132,17 +138,12 @@ bool paint_convert_bb_to_rect(
void paint_calc_redraw_planes(
float planes[4][4],
const ARegion *ar,
- RegionView3D *rv3d,
Object *ob,
const rcti *screen_rect)
{
BoundBox bb;
- bglMats mats;
rcti rect;
- memset(&bb, 0, sizeof(BoundBox));
- view3d_get_transformation(ar, rv3d, ob, &mats);
-
/* use some extra space just in case */
rect = *screen_rect;
rect.xmin -= 2;
@@ -150,7 +151,7 @@ void paint_calc_redraw_planes(
rect.ymin -= 2;
rect.ymax += 2;
- ED_view3d_clipping_calc(&bb, planes, &mats, &rect);
+ ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect);
negate_m4(planes);
}
@@ -283,26 +284,28 @@ static void imapaint_tri_weights(
}
/* compute uv coordinates of mouse in face */
-static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
+static void imapaint_pick_uv(Mesh *me_eval, Scene *scene, Object *ob_eval, unsigned int faceindex, const int xy[2], float uv[2])
{
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- const int tottri = dm->getNumLoopTri(dm);
int i, findex;
float p[2], w[3], absw, minabsw;
float matrix[4][4], proj[4][4];
GLint view[4];
const eImagePaintMode mode = scene->toolsettings->imapaint.mode;
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+
+ const MLoopTri *lt = BKE_mesh_runtime_looptri_ensure(me_eval);
+ const int tottri = me_eval->runtime.looptris.len;
+
+ const MVert *mvert = me_eval->mvert;
+ const MPoly *mpoly = me_eval->mpoly;
+ const MLoop *mloop = me_eval->mloop;
+ const int *index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
/* get the needed opengl matrices */
- glGetIntegerv(GL_VIEWPORT, view);
- glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matrix);
- glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj);
+ GPU_viewport_size_get_i(view);
+ GPU_matrix_model_view_get(matrix);
+ GPU_matrix_projection_get(proj);
view[0] = view[1] = 0;
- mul_m4_m4m4(matrix, matrix, ob->obmat);
+ mul_m4_m4m4(matrix, matrix, ob_eval->obmat);
mul_m4_m4m4(matrix, proj, matrix);
minabsw = 1e10;
@@ -319,25 +322,25 @@ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, c
const MLoopUV *tri_uv[3];
float tri_co[3][3];
- dm->getVertCo(dm, mloop[lt->tri[0]].v, tri_co[0]);
- dm->getVertCo(dm, mloop[lt->tri[1]].v, tri_co[1]);
- dm->getVertCo(dm, mloop[lt->tri[2]].v, tri_co[2]);
+ for (int j = 3; j--; ) {
+ copy_v3_v3(tri_co[j], mvert[mloop[lt->tri[j]].v].co);
+ }
if (mode == IMAGEPAINT_MODE_MATERIAL) {
const Material *ma;
const TexPaintSlot *slot;
- ma = dm->mat[mp->mat_nr];
+ ma = give_current_material(ob_eval, mp->mat_nr + 1);
slot = &ma->texpaintslot[ma->paint_active_slot];
if (!(slot && slot->uvname &&
- (mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, slot->uvname))))
+ (mloopuv = CustomData_get_layer_named(&me_eval->ldata, CD_MLOOPUV, slot->uvname))))
{
- mloopuv = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
+ mloopuv = CustomData_get_layer(&me_eval->ldata, CD_MLOOPUV);
}
}
else {
- mloopuv = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
+ mloopuv = CustomData_get_layer(&me_eval->ldata, CD_MLOOPUV);
}
tri_uv[0] = &mloopuv[lt->tri[0]];
@@ -356,12 +359,12 @@ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, c
}
}
}
-
- dm->release(dm);
}
/* returns 0 if not found, otherwise 1 */
-static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totpoly)
+static int imapaint_pick_face(
+ ViewContext *vc, const int mval[2],
+ unsigned int *r_index, unsigned int totpoly)
{
if (totpoly == 0)
return 0;
@@ -433,6 +436,7 @@ void flip_qt_qt(float out[4], const float in[4], const char symm)
void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
{
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Paint *paint = BKE_paint_get_active_from_context(C);
Palette *palette = BKE_paint_palette(paint);
PaletteColor *color = NULL;
@@ -456,21 +460,23 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
if (CTX_wm_view3d(C) && texpaint_proj) {
/* first try getting a colour directly from the mesh faces if possible */
- Object *ob = OBACT;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
bool sample_success = false;
ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
if (ob) {
Mesh *me = (Mesh *)ob->data;
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_eval = ob_eval->runtime.mesh_eval;
ViewContext vc;
const int mval[2] = {x, y};
unsigned int faceindex;
unsigned int totpoly = me->totpoly;
- if (dm->getLoopDataArray(dm, CD_MLOOPUV)) {
+ if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
ED_view3d_viewcontext_init(C, &vc);
view3d_operator_needs_opengl(C);
@@ -479,7 +485,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
Image *image;
if (use_material)
- image = imapaint_face_image(ob, me, faceindex);
+ image = imapaint_face_image(ob_eval, me_eval, faceindex);
else
image = imapaint->canvas;
@@ -488,7 +494,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
if (ibuf && ibuf->rect) {
float uv[2];
float u, v;
- imapaint_pick_uv(scene, ob, faceindex, mval, uv);
+ imapaint_pick_uv(me_eval, scene, ob_eval, faceindex, mval, uv);
sample_success = true;
u = fmodf(uv[0], 1.0f);
@@ -502,10 +508,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
if (ibuf->rect_float) {
float rgba_f[4];
- if (U.gameflags & USER_DISABLE_MIPMAP)
- nearest_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
- else
- bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
+ bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v);
straight_to_premul_v4(rgba_f);
if (use_palette) {
linearrgb_to_srgb_v3_v3(color->rgb, rgba_f);
@@ -517,10 +520,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
}
else {
unsigned char rgba[4];
- if (U.gameflags & USER_DISABLE_MIPMAP)
- nearest_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
- else
- bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
if (use_palette) {
rgb_uchar_to_float(color->rgb, rgba);
}
@@ -536,7 +536,6 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
}
}
}
- dm->release(dm);
}
if (!sample_success) {
@@ -570,8 +569,9 @@ static int brush_curve_preset_exec(bContext *C, wmOperator *op)
if (br) {
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_brush_curve_preset(br, RNA_enum_get(op->ptr, "shape"));
- BKE_paint_invalidate_cursor_overlay(scene, br->curve);
+ BKE_paint_invalidate_cursor_overlay(scene, view_layer, br->curve);
}
return OPERATOR_FINISHED;
@@ -656,6 +656,7 @@ static int face_select_all_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
paintface_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), true);
+ paintface_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
@@ -680,6 +681,7 @@ static int vert_select_all_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
paintvert_deselect_all_visible(ob, RNA_enum_get(op->ptr, "action"), true);
+ paintvert_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
@@ -711,6 +713,7 @@ static int vert_select_ungrouped_exec(bContext *C, wmOperator *op)
}
paintvert_select_ungrouped(ob, RNA_boolean_get(op->ptr, "extend"), true);
+ paintvert_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
@@ -737,6 +740,7 @@ static int face_select_hide_exec(bContext *C, wmOperator *op)
const bool unselected = RNA_boolean_get(op->ptr, "unselected");
Object *ob = CTX_data_active_object(C);
paintface_hide(ob, unselected);
+ paintface_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
@@ -760,6 +764,7 @@ static int face_select_reveal_exec(bContext *C, wmOperator *op)
const bool select = RNA_boolean_get(op->ptr, "select");
Object *ob = CTX_data_active_object(C);
paintface_reveal(ob, select);
+ paintface_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index eb96425ee5b..a00ad59ce7a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -54,24 +54,33 @@
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_deform.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "ED_armature.h"
#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+/* For IMB_BlendMode only. */
+#include "IMB_imbuf.h"
+
#include "bmesh.h"
#include "BKE_ccg.h"
@@ -149,9 +158,17 @@ static bool vwpaint_use_normal(const VPaint *vp)
((vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
}
-static bool brush_use_accumulate(const Brush *brush)
+static bool brush_use_accumulate_ex(const Brush *brush, const int ob_mode)
+{
+ return ((brush->flag & BRUSH_ACCUMULATE) != 0 ||
+ (ob_mode == OB_MODE_VERTEX_PAINT ?
+ (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) :
+ (brush->weightpaint_tool == WPAINT_TOOL_SMEAR)));
+}
+
+static bool brush_use_accumulate(const VPaint *vp)
{
- return (brush->flag & BRUSH_ACCUMULATE) != 0 || brush->vertexpaint_tool == PAINT_BLEND_SMEAR;
+ return brush_use_accumulate_ex(vp->paint.brush, vp->paint.runtime.ob_mode);
}
static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev, MDeformVert *dvert_curr, int index)
@@ -169,12 +186,12 @@ static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev, MDeformVert *dv
* (without rebuilding the 'derivedFinal') */
static bool vertex_paint_use_fast_update_check(Object *ob)
{
- DerivedMesh *dm = ob->derivedFinal;
+ Mesh *me_eval = ob->runtime.mesh_eval;
- if (dm) {
+ if (me_eval != NULL) {
Mesh *me = BKE_mesh_from_object(ob);
if (me && me->mloopcol) {
- return (me->mloopcol == CustomData_get_layer(&dm->loopData, CD_MLOOPCOL));
+ return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_MLOOPCOL));
}
}
@@ -204,7 +221,7 @@ bool vertex_paint_mode_poll(bContext *C)
return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly;
}
-bool vertex_paint_poll(bContext *C)
+static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
{
if (vertex_paint_mode_poll(C) &&
BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint))
@@ -212,13 +229,26 @@ bool vertex_paint_poll(bContext *C)
ScrArea *sa = CTX_wm_area(C);
if (sa && sa->spacetype == SPACE_VIEW3D) {
ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW)
- return 1;
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
+ return 1;
+ }
+ }
}
}
return 0;
}
+bool vertex_paint_poll(bContext *C)
+{
+ return vertex_paint_poll_ex(C, true);
+}
+
+bool vertex_paint_poll_ignore_tool(bContext *C)
+{
+ return vertex_paint_poll_ex(C, true);
+}
+
bool weight_paint_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -226,7 +256,7 @@ bool weight_paint_mode_poll(bContext *C)
return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
}
-bool weight_paint_poll(bContext *C)
+static bool weight_paint_poll_ex(bContext *C, bool check_tool)
{
Object *ob = CTX_data_active_object(C);
ScrArea *sa;
@@ -239,26 +269,29 @@ bool weight_paint_poll(bContext *C)
{
ARegion *ar = CTX_wm_region(C);
if (ar->regiontype == RGN_TYPE_WINDOW) {
- return 1;
+ if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
+ return 1;
+ }
}
}
return 0;
}
-static VPaint *new_vpaint(void)
+bool weight_paint_poll(bContext *C)
{
- VPaint *vp = MEM_callocN(sizeof(VPaint), "VPaint");
-
- vp->paint.flags |= PAINT_SHOW_BRUSH;
+ return weight_paint_poll_ex(C, true);
+}
- return vp;
+bool weight_paint_poll_ignore_tool(bContext *C)
+{
+ return weight_paint_poll_ex(C, false);
}
-uint vpaint_get_current_col(Scene *scene, VPaint *vp)
+uint vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
{
Brush *brush = BKE_paint_brush(&vp->paint);
uchar col[4];
- rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush));
+ rgb_float_to_uchar(col, secondary ? BKE_brush_secondary_color_get(scene, brush) : BKE_brush_color_get(scene, brush));
col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
return *(uint *)col;
}
@@ -271,16 +304,16 @@ static uint vpaint_blend(
const int brush_alpha_value_i)
{
const Brush *brush = vp->paint.brush;
- const int tool = brush->vertexpaint_tool;
+ const IMB_BlendMode blend = brush->blend;
- uint color_blend = ED_vpaint_blend_tool(tool, color_curr, color_paint, alpha_i);
+ uint color_blend = ED_vpaint_blend_tool(blend, color_curr, color_paint, alpha_i);
/* if no accumulate, clip color adding with colorig & orig alpha */
- if (!brush_use_accumulate(brush)) {
+ if (!brush_use_accumulate(vp)) {
uint color_test, a;
char *cp, *ct, *co;
- color_test = ED_vpaint_blend_tool(tool, color_orig, color_paint, brush_alpha_value_i);
+ color_test = ED_vpaint_blend_tool(blend, color_orig, color_paint, brush_alpha_value_i);
cp = (char *)&color_blend;
ct = (char *)&color_test;
@@ -299,7 +332,7 @@ static uint vpaint_blend(
}
if ((brush->flag & BRUSH_LOCK_ALPHA) &&
- !ELEM(tool, PAINT_BLEND_ALPHA_SUB, PAINT_BLEND_ALPHA_ADD))
+ !ELEM(blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA))
{
char *cp, *cc;
cp = (char *)&color_blend;
@@ -343,24 +376,25 @@ static float wpaint_blend(
const short do_flip)
{
const Brush *brush = wp->paint.brush;
- int tool = brush->vertexpaint_tool;
+ IMB_BlendMode blend = brush->blend;
if (do_flip) {
- switch (tool) {
- case PAINT_BLEND_MIX:
+ switch (blend) {
+ case IMB_BLEND_MIX:
paintval = 1.f - paintval; break;
- case PAINT_BLEND_ADD:
- tool = PAINT_BLEND_SUB; break;
- case PAINT_BLEND_SUB:
- tool = PAINT_BLEND_ADD; break;
- case PAINT_BLEND_LIGHTEN:
- tool = PAINT_BLEND_DARKEN; break;
- case PAINT_BLEND_DARKEN:
- tool = PAINT_BLEND_LIGHTEN; break;
+ case IMB_BLEND_ADD:
+ blend = IMB_BLEND_SUB; break;
+ case IMB_BLEND_SUB:
+ blend = IMB_BLEND_ADD; break;
+ case IMB_BLEND_LIGHTEN:
+ blend = IMB_BLEND_DARKEN; break;
+ case IMB_BLEND_DARKEN:
+ blend = IMB_BLEND_LIGHTEN; break;
+ default: break;
}
}
- weight = ED_wpaint_blend_tool(tool, weight, paintval, alpha);
+ weight = ED_wpaint_blend_tool(blend, weight, paintval, alpha);
CLAMP(weight, 0.0f, 1.0f);
@@ -739,7 +773,7 @@ static void do_weight_paint_vertex_single(
dw_mirr = NULL;
}
- if (!brush_use_accumulate(wp->paint.brush)) {
+ if (!brush_use_accumulate(wp)) {
MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
if (index_mirr != -1) {
@@ -855,7 +889,7 @@ static void do_weight_paint_vertex_multi(
return;
}
- if (!brush_use_accumulate(wp->paint.brush)) {
+ if (!brush_use_accumulate(wp)) {
MDeformVert *dvert_prev = ob->sculpt->mode.wpaint.dvert_prev;
MDeformVert *dv_prev = defweight_prev_init(dvert_prev, me->dvert, index);
if (index_mirr != -1) {
@@ -938,7 +972,7 @@ static void do_weight_paint_vertex(
/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */
-static void vertex_paint_init_session(Scene *scene, Object *ob, eObjectMode object_mode)
+static void vertex_paint_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob, eObjectMode object_mode)
{
/* Create persistent sculpt mode data */
BKE_sculpt_toolsettings_data_ensure(scene);
@@ -946,27 +980,24 @@ static void vertex_paint_init_session(Scene *scene, Object *ob, eObjectMode obje
BLI_assert(ob->sculpt == NULL);
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->mode_type = object_mode;
- BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, false, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
-static void vertex_paint_init_stroke(Scene *scene, Object *ob)
+static void vertex_paint_init_stroke(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, false, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
{
/* Create maps */
struct SculptVertexPaintGeomMap *gmap = NULL;
- const Brush *brush = NULL;
if (ob->mode == OB_MODE_VERTEX_PAINT) {
gmap = &ob->sculpt->mode.vpaint.gmap;
- brush = BKE_paint_brush(&ts->vpaint->paint);
BLI_assert(ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT);
}
else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
gmap = &ob->sculpt->mode.wpaint.gmap;
- brush = BKE_paint_brush(&ts->wpaint->paint);
BLI_assert(ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT);
}
else {
@@ -994,7 +1025,7 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
/* Create average brush arrays */
if (ob->mode == OB_MODE_VERTEX_PAINT) {
- if (!brush_use_accumulate(brush)) {
+ if (!brush_use_accumulate(ts->vpaint)) {
if (ob->sculpt->mode.vpaint.previous_color == NULL) {
ob->sculpt->mode.vpaint.previous_color =
MEM_callocN(me->totloop * sizeof(uint), __func__);
@@ -1005,7 +1036,7 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
}
}
else if (ob->mode == OB_MODE_WEIGHT_PAINT) {
- if (!brush_use_accumulate(brush)) {
+ if (!brush_use_accumulate(ts->wpaint)) {
if (ob->sculpt->mode.wpaint.alpha_weight == NULL) {
ob->sculpt->mode.wpaint.alpha_weight =
MEM_callocN(me->totvert * sizeof(float), __func__);
@@ -1037,22 +1068,23 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
* \{ */
static void ed_vwpaintmode_enter_generic(
- Main *bmain,
- wmWindowManager *wm,
- Scene *scene,
+ Main *bmain, Depsgraph *depsgraph,
+ wmWindowManager *wm, Scene *scene,
Object *ob, const eObjectMode mode_flag)
{
ob->mode |= mode_flag;
Mesh *me = BKE_mesh_from_object(ob);
+ /* Same as sculpt mode, make sure we don't have cached derived mesh which
+ * points to freed arrays.
+ */
+ BKE_object_free_derived_caches(ob);
+
if (mode_flag == OB_MODE_VERTEX_PAINT) {
const ePaintMode paint_mode = PAINT_MODE_VERTEX;
ED_mesh_color_ensure(me, NULL);
- if (scene->toolsettings->vpaint == NULL) {
- scene->toolsettings->vpaint = new_vpaint();
- }
-
+ BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
paint_cursor_start_explicit(paint, wm, vertex_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
@@ -1060,10 +1092,7 @@ static void ed_vwpaintmode_enter_generic(
else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
const ePaintMode paint_mode = PAINT_MODE_WEIGHT;
- if (scene->toolsettings->wpaint == NULL) {
- scene->toolsettings->wpaint = new_vpaint();
- }
-
+ BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
paint_cursor_start_explicit(paint, wm, weight_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
@@ -1085,39 +1114,44 @@ static void ed_vwpaintmode_enter_generic(
BKE_sculptsession_free(ob);
}
- vertex_paint_init_session(scene, ob, mode_flag);
+ vertex_paint_init_session(depsgraph, scene, ob, mode_flag);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
void ED_object_vpaintmode_enter_ex(
- Main *bmain, wmWindowManager *wm,
+ Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm,
Scene *scene, Object *ob)
{
ed_vwpaintmode_enter_generic(
- bmain, wm, scene, ob, OB_MODE_VERTEX_PAINT);
+ bmain, depsgraph, wm, scene, ob, OB_MODE_VERTEX_PAINT);
}
void ED_object_vpaintmode_enter(struct bContext *C)
{
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- ED_object_vpaintmode_enter_ex(bmain, wm, scene, ob);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
}
void ED_object_wpaintmode_enter_ex(
- Main *bmain, wmWindowManager *wm,
+ Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm,
Scene *scene, Object *ob)
{
ed_vwpaintmode_enter_generic(
- bmain, wm, scene, ob, OB_MODE_WEIGHT_PAINT);
+ bmain, depsgraph, wm, scene, ob, OB_MODE_WEIGHT_PAINT);
}
void ED_object_wpaintmode_enter(struct bContext *C)
{
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- ED_object_wpaintmode_enter_ex(bmain, wm, scene, ob);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
}
/** \} */
@@ -1166,6 +1200,12 @@ static void ed_vwpaintmode_exit_generic(
ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
ED_mesh_mirror_topo_table(NULL, NULL, 'e');
}
+
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
void ED_object_vpaintmode_exit_ex(Object *ob)
@@ -1198,10 +1238,12 @@ void ED_object_wpaintmode_exit(struct bContext *C)
static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_WEIGHT_PAINT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
if (!is_mode_set) {
if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
@@ -1215,8 +1257,25 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
ED_object_wpaintmode_exit_ex(ob);
}
else {
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
wmWindowManager *wm = CTX_wm_manager(C);
- ED_object_wpaintmode_enter_ex(bmain, wm, scene, ob);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->wpaint->paint);
+ }
+
+ /* When locked, it's almost impossible to select the pose then the object to enter weight paint mode.
+ * In this case move our pose object in/out of pose mode.
+ * This is in fits with the convention of selecting multiple objects and entering a mode. */
+ if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ Object *ob_arm = modifiers_isDeformedByArmature(ob);
+ if (ob_arm && (ob_arm->base_flag & BASE_SELECTED)) {
+ if (ob_arm->mode & OB_MODE_POSE) {
+ ED_object_posemode_exit_ex(bmain, ob_arm);
+ }
+ else {
+ ED_object_posemode_enter_ex(bmain, ob_arm);
+ }
+ }
}
/* Weightpaint works by overriding colors in mesh,
@@ -1224,10 +1283,14 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
* exit (exit needs doing regardless because we
* should redeform).
*/
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
return OPERATOR_FINISHED;
}
@@ -1257,7 +1320,7 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
ot->poll = paint_poll_test;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
/* ************ weight paint operator ********** */
@@ -1407,6 +1470,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
bool *defbase_sel;
SculptSession *ss = ob->sculpt;
VPaint *vp = CTX_data_tool_settings(C)->wpaint;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) {
return false;
@@ -1506,12 +1570,12 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
wpd->mirror.lock = tmpflags;
}
- if (ELEM(vp->paint.brush->vertexpaint_tool, PAINT_BLEND_SMEAR, PAINT_BLEND_BLUR)) {
+ if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
}
/* If not previously created, create vertex/weight paint mode session data */
- vertex_paint_init_stroke(scene, ob);
+ vertex_paint_init_stroke(depsgraph, scene, ob);
vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
vertex_paint_init_session_data(ts, ob);
@@ -1574,7 +1638,7 @@ static void do_wpaint_precompute_weight_cb_ex(
static void precompute_weight_values(
bContext *C, Object *ob, Brush *brush, struct WPaintData *wpd, WeightPaintInfo *wpi, Mesh *me)
{
- if (wpd->precomputed_weight_ready && !brush_use_accumulate(brush))
+ if (wpd->precomputed_weight_ready && !brush_use_accumulate_ex(brush, ob->mode))
return;
/* threaded loop over vertices */
@@ -1956,7 +2020,8 @@ static void wpaint_paint_leaves(
/* threaded loop over nodes */
SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .wpd = wpd, .wpi = wpi, .me = me, .C = C,
+ .C = C, .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .vp = vp, .wpd = wpd, .wpi = wpi, .me = me,
};
/* Use this so average can modify its weight without touching the brush. */
@@ -1967,8 +2032,8 @@ static void wpaint_paint_leaves(
/* NOTE: current mirroring code cannot be run in parallel */
settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
- switch (brush->vertexpaint_tool) {
- case PAINT_BLEND_AVERAGE:
+ switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
+ case WPAINT_TOOL_AVERAGE:
calculate_average_weight(&data, nodes, totnode);
BLI_task_parallel_range(
0, totnode,
@@ -1976,21 +2041,21 @@ static void wpaint_paint_leaves(
do_wpaint_brush_draw_task_cb_ex,
&settings);
break;
- case PAINT_BLEND_SMEAR:
+ case WPAINT_TOOL_SMEAR:
BLI_task_parallel_range(
0, totnode,
&data,
do_wpaint_brush_smear_task_cb_ex,
&settings);
break;
- case PAINT_BLEND_BLUR:
+ case WPAINT_TOOL_BLUR:
BLI_task_parallel_range(
0, totnode,
&data,
do_wpaint_brush_blur_task_cb_ex,
&settings);
break;
- default:
+ case WPAINT_TOOL_DRAW:
BLI_task_parallel_range(
0, totnode,
&data,
@@ -2184,7 +2249,9 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* also needed for "View Selected" on last stroke */
paint_last_stroke_update(scene, vc->ar, mval);
- DAG_id_tag_update(ob->data, 0);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
+ DEG_id_tag_update(ob->data, 0);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
swap_m4m4(wpd->vc.rv3d->persmat, mat);
@@ -2248,7 +2315,7 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
}
}
- DAG_id_tag_update(ob->data, 0);
+ DEG_id_tag_update(ob->data, 0);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -2331,10 +2398,12 @@ void PAINT_OT_weight_paint(wmOperatorType *ot)
static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_VERTEX_PAINT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
if (!is_mode_set) {
if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
@@ -2349,15 +2418,23 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
ED_object_vpaintmode_exit_ex(ob);
}
else {
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
wmWindowManager *wm = CTX_wm_manager(C);
- ED_object_vpaintmode_enter_ex(bmain, wm, scene, ob);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->vpaint->paint);
}
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
/* update modifier stack for mapping requirements */
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
return OPERATOR_FINISHED;
}
@@ -2373,7 +2450,7 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
ot->poll = paint_poll_test;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
@@ -2410,7 +2487,7 @@ struct VPaintData {
uint paintcol;
struct VertProjHandle *vp_handle;
- struct DMCoNo *vertexcosnos;
+ struct CoNo *vertexcosnos;
/* modify 'me->mcol' directly, since the derived mesh is drawing from this
* array, otherwise we need to refresh the modifier stack */
@@ -2440,6 +2517,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
Object *ob = CTX_data_active_object(C);
Mesh *me;
SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
/* context checks could be a poll() */
me = BKE_mesh_from_object(ob);
@@ -2458,9 +2536,9 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
&vpd->normal_angle_precalc, vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
- vpd->paintcol = vpaint_get_current_col(scene, vp);
+ vpd->paintcol = vpaint_get_current_col(scene, vp, (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT));
- vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && brush->mtex.tex;
+ vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex;
/* are we painting onto a modified mesh?,
* if not we can skip face map trickiness */
@@ -2474,11 +2552,11 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
}
/* to keep tracked of modified loops for shared vertex color blending */
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
+ if (brush->vertexpaint_tool == VPAINT_TOOL_BLUR) {
vpd->mlooptag = MEM_mallocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
}
- if (brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
+ if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
vpd->smear.color_prev = MEM_mallocN(sizeof(uint) * me->totloop, __func__);
memcpy(vpd->smear.color_prev, me->mloopcol, sizeof(uint) * me->totloop);
vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev);
@@ -2487,12 +2565,12 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* Create projection handle */
if (vpd->is_texbrush) {
ob->sculpt->building_vp_handle = true;
- vpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &vpd->vertexcosnos);
+ vpd->vp_handle = ED_vpaint_proj_handle_create(depsgraph, scene, ob, &vpd->vertexcosnos);
ob->sculpt->building_vp_handle = false;
}
/* If not previously created, create vertex/weight paint mode session data */
- vertex_paint_init_stroke(scene, ob);
+ vertex_paint_init_stroke(depsgraph, scene, ob);
vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
vertex_paint_init_session_data(ts, ob);
@@ -2952,13 +3030,13 @@ static void vpaint_paint_leaves(
const Brush *brush = ob->sculpt->cache->brush;
SculptThreadedTaskData data = {
- .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd,
- .lcol = (uint *)me->mloopcol, .me = me, .C = C,
+ .C = C, .sd = sd, .ob = ob, .brush = brush, .nodes = nodes, .vp = vp, .vpd = vpd,
+ .lcol = (uint *)me->mloopcol, .me = me,
};
ParallelRangeSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- switch (brush->vertexpaint_tool) {
- case PAINT_BLEND_AVERAGE:
+ switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
+ case VPAINT_TOOL_AVERAGE:
calculate_average_color(&data, nodes, totnode);
BLI_task_parallel_range(
0, totnode,
@@ -2966,21 +3044,21 @@ static void vpaint_paint_leaves(
do_vpaint_brush_draw_task_cb_ex,
&settings);
break;
- case PAINT_BLEND_BLUR:
+ case VPAINT_TOOL_BLUR:
BLI_task_parallel_range(
0, totnode,
&data,
do_vpaint_brush_blur_task_cb_ex,
&settings);
break;
- case PAINT_BLEND_SMEAR:
+ case VPAINT_TOOL_SMEAR:
BLI_task_parallel_range(
0, totnode,
&data,
do_vpaint_brush_smear_task_cb_ex,
&settings);
break;
- default:
+ case VPAINT_TOOL_DRAW:
BLI_task_parallel_range(
0, totnode,
&data,
@@ -3090,7 +3168,9 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
swap_m4m4(vc->rv3d->persmat, mat);
- if (vp->paint.brush->vertexpaint_tool == PAINT_BLEND_SMEAR) {
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
+ if (vp->paint.brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
memcpy(vpd->smear.color_prev, vpd->smear.color_curr, sizeof(uint) * ((Mesh *)ob->data)->totloop);
}
@@ -3103,11 +3183,11 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
if (vpd->use_fast_update == false) {
/* recalculate modifier stack to get new colors, slow,
* avoid this if we can! */
- DAG_id_tag_update(ob->data, 0);
+ DEG_id_tag_update(ob->data, 0);
}
else {
- /* If using new VBO drawing, mark mcol as dirty to force colors gpu buffer refresh! */
- ob->derivedFinal->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW;
+ /* Flush changes through DEG. */
+ DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 4959c40c65e..ba3bc5501e3 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -33,10 +33,11 @@
#include "BLI_math_color.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh.h"
#include "BKE_deform.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -97,7 +98,7 @@ static bool vertex_color_set(Object *ob, uint paintcol)
/* remove stale me->mcol, will be added later */
BKE_mesh_tessface_clear(me);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
return true;
}
@@ -106,7 +107,7 @@ static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
- unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint);
+ unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
if (vertex_color_set(obact, paintcol)) {
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
@@ -151,6 +152,7 @@ static bool vertex_paint_from_weight(Object *ob)
}
/* TODO: respect selection. */
+ /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway... */
mp = me->mpoly;
vgroup_active = ob->actdef - 1;
for (int i = 0; i < me->totpoly; i++, mp++) {
@@ -168,7 +170,7 @@ static bool vertex_paint_from_weight(Object *ob)
} while (j < mp->totloop);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
return true;
}
@@ -304,7 +306,7 @@ static bool vertex_color_smooth(Object *ob)
MEM_freeN(mlooptag);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
return true;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index a0bd5ea2a2d..f78588df0fa 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -36,11 +36,13 @@
#include "BLI_math_color.h"
#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh.h"
+#include "DEG_depsgraph.h"
+
#include "ED_mesh.h"
#include "paint_intern.h" /* own include */
@@ -87,7 +89,7 @@ bool ED_vpaint_color_transform(
/* remove stale me->mcol, will be added later */
BKE_mesh_tessface_clear(me);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
return true;
}
@@ -616,29 +618,26 @@ uint ED_vpaint_blend_tool(
const int tool, const uint col,
const uint paintcol, const int alpha_i)
{
- switch (tool) {
- case PAINT_BLEND_MIX:
- case PAINT_BLEND_BLUR: return mcol_blend(col, paintcol, alpha_i);
- case PAINT_BLEND_AVERAGE: return mcol_blend(col, paintcol, alpha_i);
- case PAINT_BLEND_SMEAR: return mcol_blend(col, paintcol, alpha_i);
- case PAINT_BLEND_ADD: return mcol_add(col, paintcol, alpha_i);
- case PAINT_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i);
- case PAINT_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i);
- case PAINT_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i);
- case PAINT_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i);
- case PAINT_BLEND_COLORDODGE: return mcol_colordodge(col, paintcol, alpha_i);
- case PAINT_BLEND_DIFFERENCE: return mcol_difference(col, paintcol, alpha_i);
- case PAINT_BLEND_SCREEN: return mcol_screen(col, paintcol, alpha_i);
- case PAINT_BLEND_HARDLIGHT: return mcol_hardlight(col, paintcol, alpha_i);
- case PAINT_BLEND_OVERLAY: return mcol_overlay(col, paintcol, alpha_i);
- case PAINT_BLEND_SOFTLIGHT: return mcol_softlight(col, paintcol, alpha_i);
- case PAINT_BLEND_EXCLUSION: return mcol_exclusion(col, paintcol, alpha_i);
- case PAINT_BLEND_LUMINOCITY: return mcol_luminosity(col, paintcol, alpha_i);
- case PAINT_BLEND_SATURATION: return mcol_saturation(col, paintcol, alpha_i);
- case PAINT_BLEND_HUE: return mcol_hue(col, paintcol, alpha_i);
+ switch ((IMB_BlendMode)tool) {
+ case IMB_BLEND_MIX: return mcol_blend(col, paintcol, alpha_i);
+ case IMB_BLEND_ADD: return mcol_add(col, paintcol, alpha_i);
+ case IMB_BLEND_SUB: return mcol_sub(col, paintcol, alpha_i);
+ case IMB_BLEND_MUL: return mcol_mul(col, paintcol, alpha_i);
+ case IMB_BLEND_LIGHTEN: return mcol_lighten(col, paintcol, alpha_i);
+ case IMB_BLEND_DARKEN: return mcol_darken(col, paintcol, alpha_i);
+ case IMB_BLEND_COLORDODGE: return mcol_colordodge(col, paintcol, alpha_i);
+ case IMB_BLEND_DIFFERENCE: return mcol_difference(col, paintcol, alpha_i);
+ case IMB_BLEND_SCREEN: return mcol_screen(col, paintcol, alpha_i);
+ case IMB_BLEND_HARDLIGHT: return mcol_hardlight(col, paintcol, alpha_i);
+ case IMB_BLEND_OVERLAY: return mcol_overlay(col, paintcol, alpha_i);
+ case IMB_BLEND_SOFTLIGHT: return mcol_softlight(col, paintcol, alpha_i);
+ case IMB_BLEND_EXCLUSION: return mcol_exclusion(col, paintcol, alpha_i);
+ case IMB_BLEND_LUMINOSITY: return mcol_luminosity(col, paintcol, alpha_i);
+ case IMB_BLEND_SATURATION: return mcol_saturation(col, paintcol, alpha_i);
+ case IMB_BLEND_HUE: return mcol_hue(col, paintcol, alpha_i);
/* non-color */
- case PAINT_BLEND_ALPHA_SUB: return mcol_alpha_sub(col, alpha_i);
- case PAINT_BLEND_ALPHA_ADD: return mcol_alpha_add(col, alpha_i);
+ case IMB_BLEND_ERASE_ALPHA: return mcol_alpha_sub(col, alpha_i);
+ case IMB_BLEND_ADD_ALPHA: return mcol_alpha_add(col, alpha_i);
default:
BLI_assert(0);
return 0;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index 411a0ca9ec3..31ae12c112a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -28,7 +28,7 @@
* \ingroup edsculpt
*
* Utility functions for getting vertex locations while painting
- * (since they may be instanced multiple times in a DerivedMesh)
+ * (since they may be instanced multiple times in an evaluated mesh)
*/
#include "MEM_guardedalloc.h"
@@ -39,8 +39,11 @@
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
+#include "BKE_mesh_iterators.h"
+#include "BKE_mesh_runtime.h"
+
+#include "DEG_depsgraph.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -52,7 +55,7 @@
/* stored while painting */
struct VertProjHandle {
- DMCoNo *vcosnos;
+ CoNo *vcosnos;
bool use_update;
@@ -81,7 +84,7 @@ static void vpaint_proj_dm_map_cosnos_init__map_cb(
const float no_f[3], const short no_s[3])
{
struct VertProjHandle *vp_handle = userData;
- DMCoNo *co_no = &vp_handle->vcosnos[index];
+ CoNo *co_no = &vp_handle->vcosnos[index];
/* check if we've been here before (normal should not be 0) */
if (!is_zero_v3(co_no->no)) {
@@ -100,28 +103,14 @@ static void vpaint_proj_dm_map_cosnos_init__map_cb(
}
static void vpaint_proj_dm_map_cosnos_init(
- Scene *scene, Object *ob,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
struct VertProjHandle *vp_handle)
{
Mesh *me = ob->data;
- DerivedMesh *dm;
-
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
- if (dm->foreachMappedVert) {
- memset(vp_handle->vcosnos, 0, sizeof(DMCoNo) * me->totvert);
- dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, DM_FOREACH_USE_NORMAL);
- }
- else {
- DMCoNo *v_co_no = vp_handle->vcosnos;
- int a;
- for (a = 0; a < me->totvert; a++, v_co_no++) {
- dm->getVertCo(dm, a, v_co_no->co);
- dm->getVertNo(dm, a, v_co_no->no);
- }
- }
-
- dm->release(dm);
+ memset(vp_handle->vcosnos, 0, sizeof(*vp_handle->vcosnos) * me->totvert);
+ BKE_mesh_foreach_mapped_vert(me_eval, vpaint_proj_dm_map_cosnos_init__map_cb, vp_handle, MESH_FOREACH_USE_NORMAL);
}
@@ -137,7 +126,7 @@ static void vpaint_proj_dm_map_cosnos_update__map_cb(
struct VertProjUpdate *vp_update = userData;
struct VertProjHandle *vp_handle = vp_update->vp_handle;
- DMCoNo *co_no = &vp_handle->vcosnos[index];
+ CoNo *co_no = &vp_handle->vcosnos[index];
/* find closest vertex */
{
@@ -174,7 +163,7 @@ static void vpaint_proj_dm_map_cosnos_update__map_cb(
}
static void vpaint_proj_dm_map_cosnos_update(
- struct VertProjHandle *vp_handle,
+ struct Depsgraph *depsgraph, struct VertProjHandle *vp_handle,
ARegion *ar, const float mval_fl[2])
{
struct VertProjUpdate vp_update = {vp_handle, ar, mval_fl};
@@ -182,21 +171,13 @@ static void vpaint_proj_dm_map_cosnos_update(
Scene *scene = vp_handle->scene;
Object *ob = vp_handle->ob;
Mesh *me = ob->data;
- DerivedMesh *dm;
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
/* quick sanity check - we shouldn't have to run this if there are no modifiers */
BLI_assert(BLI_listbase_is_empty(&ob->modifiers) == false);
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
-
- /* highly unlikely this will become unavailable once painting starts (perhaps with animated modifiers) */
- if (LIKELY(dm->foreachMappedVert)) {
- copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
-
- dm->foreachMappedVert(dm, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, DM_FOREACH_USE_NORMAL);
- }
-
- dm->release(dm);
+ copy_vn_fl(vp_handle->dists_sq, me->totvert, FLT_MAX);
+ BKE_mesh_foreach_mapped_vert(me_eval, vpaint_proj_dm_map_cosnos_update__map_cb, &vp_update, MESH_FOREACH_USE_NORMAL);
}
@@ -204,18 +185,18 @@ static void vpaint_proj_dm_map_cosnos_update(
/* Public Functions */
struct VertProjHandle *ED_vpaint_proj_handle_create(
- Scene *scene, Object *ob,
- DMCoNo **r_vcosnos)
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ CoNo **r_vcosnos)
{
struct VertProjHandle *vp_handle = MEM_mallocN(sizeof(struct VertProjHandle), __func__);
Mesh *me = ob->data;
/* setup the handle */
- vp_handle->vcosnos = MEM_mallocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map");
+ vp_handle->vcosnos = MEM_mallocN(sizeof(CoNo) * me->totvert, "vertexcosnos map");
vp_handle->use_update = false;
/* sets 'use_update' if needed */
- vpaint_proj_dm_map_cosnos_init(scene, ob, vp_handle);
+ vpaint_proj_dm_map_cosnos_init(depsgraph, scene, ob, vp_handle);
if (vp_handle->use_update) {
vp_handle->dists_sq = MEM_mallocN(sizeof(float) * me->totvert, __func__);
@@ -235,11 +216,11 @@ struct VertProjHandle *ED_vpaint_proj_handle_create(
}
void ED_vpaint_proj_handle_update(
- struct VertProjHandle *vp_handle,
+ struct Depsgraph *depsgraph, struct VertProjHandle *vp_handle,
ARegion *ar, const float mval_fl[2])
{
if (vp_handle->use_update) {
- vpaint_proj_dm_map_cosnos_update(vp_handle, ar, mval_fl);
+ vpaint_proj_dm_map_cosnos_update(depsgraph, vp_handle, ar, mval_fl);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 21965bb30d8..46eb3995ea3 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -35,8 +35,8 @@
#include "IMB_imbuf_types.h"
#include "IMB_colormanagement.h"
-//#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_particle_types.h"
#include "DNA_brush_types.h"
#include "DNA_object_types.h"
@@ -46,19 +46,21 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_colortools.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -124,15 +126,16 @@ static bool weight_from_bones_poll(bContext *C)
static int weight_from_bones_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
Object *armob = modifiers_isDeformedByArmature(ob);
Mesh *me = ob->data;
int type = RNA_enum_get(op->ptr, "type");
- ED_object_vgroup_calc_from_armature(op->reports, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
+ ED_object_vgroup_calc_from_armature(op->reports, depsgraph, scene, ob, armob, type, (me->editflag & ME_EDIT_MIRROR_X));
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
return OPERATOR_FINISHED;
@@ -367,7 +370,7 @@ static int weight_sample_group_exec(bContext *C, wmOperator *op)
BLI_assert(type + 1 >= 0);
vc.obact->actdef = type + 1;
- DAG_id_tag_update(&vc.obact->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&vc.obact->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, vc.obact);
return OPERATOR_FINISHED;
}
@@ -483,7 +486,7 @@ static bool weight_paint_set(Object *ob, float paintweight)
wpaint_prev_destroy(&wpp);
- DAG_id_tag_update(&me->id, 0);
+ DEG_id_tag_update(&me->id, 0);
return true;
}
@@ -532,21 +535,21 @@ void PAINT_OT_weight_set(wmOperatorType *ot)
* \{ */
/* *** VGroups Gradient *** */
-typedef struct DMGradient_vertStore {
+typedef struct WPGradient_vertStore {
float sco[2];
float weight_orig;
enum {
VGRAD_STORE_NOP = 0,
VGRAD_STORE_DW_EXIST = (1 << 0)
} flag;
-} DMGradient_vertStore;
+} WPGradient_vertStore;
-typedef struct DMGradient_vertStoreBase {
+typedef struct WPGradient_vertStoreBase {
struct WPaintPrev wpp;
- DMGradient_vertStore elem[0];
-} DMGradient_vertStoreBase;
+ WPGradient_vertStore elem[0];
+} WPGradient_vertStoreBase;
-typedef struct DMGradient_userData {
+typedef struct WPGradient_userData {
struct ARegion *ar;
Scene *scene;
Mesh *me;
@@ -556,7 +559,7 @@ typedef struct DMGradient_userData {
float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
int def_nr;
bool is_init;
- DMGradient_vertStoreBase *vert_cache;
+ WPGradient_vertStoreBase *vert_cache;
/* only for init */
BLI_bitmap *vert_visit;
@@ -564,12 +567,12 @@ typedef struct DMGradient_userData {
short use_select;
short type;
float weightpaint;
-} DMGradient_userData;
+} WPGradient_userData;
-static void gradientVert_update(DMGradient_userData *grad_data, int index)
+static void gradientVert_update(WPGradient_userData *grad_data, int index)
{
Mesh *me = grad_data->me;
- DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+ WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
float alpha;
if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
@@ -588,7 +591,7 @@ static void gradientVert_update(DMGradient_userData *grad_data, int index)
MDeformVert *dv = &me->dvert[index];
MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
// dw->weight = alpha; // testing
- int tool = grad_data->brush->vertexpaint_tool;
+ int tool = grad_data->brush->blend;
float testw;
/* init if we just added */
@@ -617,10 +620,10 @@ static void gradientVertUpdate__mapFunc(
void *userData, int index, const float UNUSED(co[3]),
const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
{
- DMGradient_userData *grad_data = userData;
+ WPGradient_userData *grad_data = userData;
Mesh *me = grad_data->me;
if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) {
- DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+ WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
if (vs->sco[0] != FLT_MAX) {
gradientVert_update(grad_data, index);
}
@@ -631,7 +634,7 @@ static void gradientVertInit__mapFunc(
void *userData, int index, const float co[3],
const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
{
- DMGradient_userData *grad_data = userData;
+ WPGradient_userData *grad_data = userData;
Mesh *me = grad_data->me;
if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) {
@@ -640,10 +643,11 @@ static void gradientVertInit__mapFunc(
* updating the mesh may move them about (entering feedback loop) */
if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) {
- DMGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
- if (ED_view3d_project_float_object(grad_data->ar,
- co, vs->sco,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+ WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
+ if (ED_view3d_project_float_object(
+ grad_data->ar,
+ co, vs->sco,
+ V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{
/* ok */
MDeformVert *dv = &me->dvert[index];
@@ -673,7 +677,7 @@ static void gradientVertInit__mapFunc(
static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
- DMGradient_vertStoreBase *vert_cache = gesture->userdata;
+ WPGradient_vertStoreBase *vert_cache = gesture->userdata;
int ret = WM_gesture_straightline_modal(C, op, event);
if (ret & OPERATOR_RUNNING_MODAL) {
@@ -695,7 +699,7 @@ static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEven
}
MEM_freeN(vert_cache);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
else if (ret & OPERATOR_FINISHED) {
@@ -709,7 +713,7 @@ static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEven
static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
{
wmGesture *gesture = op->customdata;
- DMGradient_vertStoreBase *vert_cache;
+ WPGradient_vertStoreBase *vert_cache;
struct ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -721,20 +725,21 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
float sco_start[2] = {x_start, y_start};
float sco_end[2] = {x_end, y_end};
const bool is_interactive = (gesture != NULL);
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
- DMGradient_userData data = {NULL};
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ WPGradient_userData data = {NULL};
if (is_interactive) {
if (gesture->userdata == NULL) {
gesture->userdata = MEM_mallocN(
- sizeof(DMGradient_vertStoreBase) +
- (sizeof(DMGradient_vertStore) * me->totvert),
+ sizeof(WPGradient_vertStoreBase) +
+ (sizeof(WPGradient_vertStore) * me->totvert),
__func__);
gesture->userdata_free = false;
data.is_init = true;
- wpaint_prev_create(&((DMGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert);
+ wpaint_prev_create(&((WPGradient_vertStoreBase *)gesture->userdata)->wpp, me->dvert, me->totvert);
/* on init only, convert face -> vert sel */
if (me->editflag & ME_EDIT_PAINT_FACE_SEL) {
@@ -751,8 +756,8 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
data.is_init = true;
vert_cache = MEM_mallocN(
- sizeof(DMGradient_vertStoreBase) +
- (sizeof(DMGradient_vertStore) * me->totvert),
+ sizeof(WPGradient_vertStoreBase) +
+ (sizeof(WPGradient_vertStore) * me->totvert),
__func__);
}
@@ -781,19 +786,20 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
ED_view3d_init_mats_rv3d(ob, ar->regiondata);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, scene->customdata_mask | CD_MASK_ORIGINDEX);
if (data.is_init) {
data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__);
- dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(me_eval, gradientVertInit__mapFunc, &data, MESH_FOREACH_NOP);
MEM_freeN(data.vert_visit);
data.vert_visit = NULL;
}
else {
- dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(me_eval, gradientVertUpdate__mapFunc, &data, MESH_FOREACH_NOP);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
if (is_interactive == false) {
@@ -845,7 +851,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot)
ot->invoke = paint_weight_gradient_invoke;
ot->modal = paint_weight_gradient_modal;
ot->exec = paint_weight_gradient_exec;
- ot->poll = weight_paint_poll;
+ ot->poll = weight_paint_poll_ignore_tool;
ot->cancel = WM_gesture_straightline_cancel;
/* flags */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index 197b16ffe6e..0a1fc7c0b4e 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -43,6 +43,10 @@
#include "BKE_modifier.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
+#include "BKE_object.h"
+
+/* Only for blend modes. */
+#include "IMB_imbuf.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -58,7 +62,6 @@ bool ED_wpaint_ensure_data(
bContext *C, struct ReportList *reports,
enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index)
{
- Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
Mesh *me = BKE_mesh_from_object(ob);
@@ -67,7 +70,7 @@ bool ED_wpaint_ensure_data(
vgroup_index->mirror = -1;
}
- if (scene->obedit) {
+ if (BKE_object_is_in_editmode(ob)) {
return false;
}
@@ -280,31 +283,24 @@ float ED_wpaint_blend_tool(
const float weight,
const float paintval, const float alpha)
{
- switch (tool) {
- case PAINT_BLEND_MIX:
- case PAINT_BLEND_AVERAGE:
- case PAINT_BLEND_SMEAR:
- case PAINT_BLEND_BLUR: return wval_blend(weight, paintval, alpha);
- case PAINT_BLEND_ADD: return wval_add(weight, paintval, alpha);
- case PAINT_BLEND_SUB: return wval_sub(weight, paintval, alpha);
- case PAINT_BLEND_MUL: return wval_mul(weight, paintval, alpha);
- case PAINT_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha);
- case PAINT_BLEND_DARKEN: return wval_darken(weight, paintval, alpha);
+ switch ((IMB_BlendMode)tool) {
+ case IMB_BLEND_MIX: return wval_blend(weight, paintval, alpha);
+ case IMB_BLEND_ADD: return wval_add(weight, paintval, alpha);
+ case IMB_BLEND_SUB: return wval_sub(weight, paintval, alpha);
+ case IMB_BLEND_MUL: return wval_mul(weight, paintval, alpha);
+ case IMB_BLEND_LIGHTEN: return wval_lighten(weight, paintval, alpha);
+ case IMB_BLEND_DARKEN: return wval_darken(weight, paintval, alpha);
/* Mostly make sense for color: support anyway. */
- case PAINT_BLEND_COLORDODGE: return wval_colordodge(weight, paintval, alpha);
- case PAINT_BLEND_DIFFERENCE: return wval_difference(weight, paintval, alpha);
- case PAINT_BLEND_SCREEN: return wval_screen(weight, paintval, alpha);
- case PAINT_BLEND_HARDLIGHT: return wval_hardlight(weight, paintval, alpha);
- case PAINT_BLEND_OVERLAY: return wval_overlay(weight, paintval, alpha);
- case PAINT_BLEND_SOFTLIGHT: return wval_softlight(weight, paintval, alpha);
- case PAINT_BLEND_EXCLUSION: return wval_exclusion(weight, paintval, alpha);
+ case IMB_BLEND_COLORDODGE: return wval_colordodge(weight, paintval, alpha);
+ case IMB_BLEND_DIFFERENCE: return wval_difference(weight, paintval, alpha);
+ case IMB_BLEND_SCREEN: return wval_screen(weight, paintval, alpha);
+ case IMB_BLEND_HARDLIGHT: return wval_hardlight(weight, paintval, alpha);
+ case IMB_BLEND_OVERLAY: return wval_overlay(weight, paintval, alpha);
+ case IMB_BLEND_SOFTLIGHT: return wval_softlight(weight, paintval, alpha);
+ case IMB_BLEND_EXCLUSION: return wval_exclusion(weight, paintval, alpha);
/* Only for color: just use blend. */
- case PAINT_BLEND_LUMINOCITY:
- case PAINT_BLEND_SATURATION:
- case PAINT_BLEND_HUE:
- case PAINT_BLEND_ALPHA_SUB:
- case PAINT_BLEND_ALPHA_ADD:
- default: return wval_blend(weight, paintval, alpha);
+ default:
+ return wval_blend(weight, paintval, alpha);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 80e9aef4a40..ef4f9a9c7bf 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -52,11 +52,10 @@
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
-#include "BKE_pbvh.h"
#include "BKE_brush.h"
#include "BKE_ccg.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_key.h"
@@ -66,15 +65,21 @@
#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
-#include "BKE_paint.h"
-#include "BKE_report.h"
#include "BKE_node.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
#include "BKE_subsurf.h"
-#include "BKE_colortools.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
#include "ED_sculpt.h"
#include "ED_object.h"
@@ -86,9 +91,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "GPU_buffers.h"
-#include "GPU_extensions.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
@@ -500,8 +502,7 @@ bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
return 1;
}
-void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar,
- RegionView3D *rv3d, Object *ob)
+void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, Object *ob)
{
PBVH *pbvh = ob->sculpt->pbvh;
/* copy here, original will be used below */
@@ -509,7 +510,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar,
sculpt_extend_redraw_rect_previous(ob, &rect);
- paint_calc_redraw_planes(planes, ar, rv3d, ob, &rect);
+ paint_calc_redraw_planes(planes, ar, ob, &rect);
/* we will draw this rect, so now we can set it as the previous partial rect.
* Note that we don't update with the union of previous/current (rect), only with
@@ -2101,6 +2102,10 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_v3(offset, ss->cache->scale);
mul_v3_fl(offset, bstrength);
+ /* XXX - this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping */
+ curvemapping_initialize(brush->curve);
+
/* threaded loop over nodes */
SculptThreadedTaskData data = {
.sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
@@ -3519,13 +3524,16 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
PBVHTopologyUpdateMode mode = 0;
float location[3];
- if (sd->flags & SCULPT_DYNTOPO_SUBDIVIDE)
- mode |= PBVH_Subdivide;
+ if (!(sd->flags & SCULPT_DYNTOPO_DETAIL_MANUAL)) {
+ if (sd->flags & SCULPT_DYNTOPO_SUBDIVIDE) {
+ mode |= PBVH_Subdivide;
+ }
- if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) ||
- (brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY))
- {
- mode |= PBVH_Collapse;
+ if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) ||
+ (brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY))
+ {
+ mode |= PBVH_Collapse;
+ }
}
for (n = 0; n < totnode; n++) {
@@ -3946,8 +3954,9 @@ static void do_tiled(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
const float radius = cache->radius;
- const float *bbMin = ob->bb->vec[0];
- const float *bbMax = ob->bb->vec[6];
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ const float *bbMin = bb->vec[0];
+ const float *bbMax = bb->vec[6];
const float *step = sd->paint.tile_offset;
int dim;
@@ -4600,10 +4609,11 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const B
SculptSession *ss = ob->sculpt;
if (ss->kb || ss->modifiers_active) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Sculpt *sd = scene->toolsettings->sculpt;
bool need_pmap = sculpt_any_smooth_mode(brush, ss->cache, 0);
- BKE_sculpt_update_mesh_elements(scene, sd, ob, need_pmap, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, need_pmap, false);
}
}
@@ -4688,7 +4698,7 @@ static float sculpt_raycast_init(
RegionView3D *rv3d = vc->ar->regiondata;
/* TODO: what if the segment is totally clipped? (return == 0) */
- ED_view3d_win_to_segment_clipped(vc->ar, vc->v3d, mouse, ray_start, ray_end, true);
+ ED_view3d_win_to_segment_clipped(vc->depsgraph, vc->ar, vc->v3d, mouse, ray_start, ray_end, true);
invert_m4_m4(obimat, ob->obmat);
mul_m4_v3(obimat, ray_start);
@@ -4806,6 +4816,7 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession
static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -4823,7 +4834,7 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
sculpt_brush_init_tex(scene, sd, ss);
is_smooth = sculpt_any_smooth_mode(brush, NULL, mode);
- BKE_sculpt_update_mesh_elements(scene, sd, ob, is_smooth, need_mask);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, is_smooth, need_mask);
}
static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
@@ -4859,13 +4870,17 @@ static void sculpt_flush_update(bContext *C)
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
- if (mmd)
- multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
- if (ob->derivedFinal) /* VBO no longer valid */
- GPU_drawobject_free(ob->derivedFinal);
+ if (mmd != NULL) {
+ /* NOTE: SubdivCCG is living in the evaluated object. */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ multires_mark_as_modified(ob_eval, MULTIRES_COORDS_MODIFIED);
+ }
+
+ DEG_id_tag_update(&ob->id, DEG_TAG_SHADING_UPDATE);
if (ss->kb || ss->modifiers_active) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
ED_region_tag_redraw(ar);
}
else {
@@ -4895,6 +4910,9 @@ static void sculpt_flush_update(bContext *C)
ED_region_tag_redraw_partial(ar, &r);
}
}
+
+ /* 2.8x - avoid full mesh update! */
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS);
}
/* Returns whether the mouse/stylus is over the mesh (1)
@@ -4946,7 +4964,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
sculpt_update_cache_variants(C, sd, ob, itemptr);
sculpt_restore_mesh(sd, ob);
- if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
+ if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail);
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
@@ -4978,7 +4996,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
* Could be optimized later, but currently don't think it's so
* much common scenario.
*
- * Same applies to the DAG_id_tag_update() invoked from
+ * Same applies to the DEG_id_tag_update() invoked from
* sculpt_flush_update().
*/
if (ss->modifiers_active) {
@@ -5053,7 +5071,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* try to avoid calling this, only for e.g. linked duplicates now */
if (((Mesh *)ob->data)->id.us > 1)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
@@ -5200,14 +5218,12 @@ static void sculpt_dynamic_topology_triangulate(BMesh *bm)
void sculpt_pbvh_clear(Object *ob)
{
SculptSession *ss = ob->sculpt;
- DerivedMesh *dm = ob->derivedFinal;
/* Clear out any existing DM and PBVH */
- if (ss->pbvh)
+ if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
+ }
ss->pbvh = NULL;
- if (dm)
- dm->getPBVH(NULL, dm);
BKE_object_free_derived_caches(ob);
}
@@ -5244,16 +5260,18 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss)
void sculpt_update_after_dynamic_topology_toggle(
+ Depsgraph *depsgraph,
Scene *scene, Object *ob)
{
Sculpt *sd = scene->toolsettings->sculpt;
/* Create the PBVH */
- BKE_sculpt_update_mesh_elements(scene, sd, ob, false, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, false);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
void sculpt_dynamic_topology_enable_ex(
+ Depsgraph *depsgraph,
Scene *scene, Object *ob)
{
SculptSession *ss = ob->sculpt;
@@ -5291,7 +5309,7 @@ void sculpt_dynamic_topology_enable_ex(
ss->bm_log = BM_log_create(ss->bm);
/* Refresh */
- sculpt_update_after_dynamic_topology_toggle(scene, ob);
+ sculpt_update_after_dynamic_topology_toggle(depsgraph, scene, ob);
}
/* Free the sculpt BMesh and BMLog
@@ -5299,6 +5317,7 @@ void sculpt_dynamic_topology_enable_ex(
* If 'unode' is given, the BMesh's data is copied out to the unode
* before the BMesh is deleted so that it can be restored from */
void sculpt_dynamic_topology_disable_ex(
+ Depsgraph *depsgraph,
Scene *scene, Object *ob, SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
@@ -5349,35 +5368,37 @@ void sculpt_dynamic_topology_disable_ex(
}
/* Refresh */
- sculpt_update_after_dynamic_topology_toggle(scene, ob);
+ sculpt_update_after_dynamic_topology_toggle(depsgraph, scene, ob);
}
void sculpt_dynamic_topology_disable(bContext *C, SculptUndoNode *unode)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- sculpt_dynamic_topology_disable_ex(scene, ob, unode);
+ sculpt_dynamic_topology_disable_ex(depsgraph, scene, ob, unode);
}
static void sculpt_dynamic_topology_disable_with_undo(
- Scene *scene, Object *ob)
+ Depsgraph *depsgraph, Scene *scene, Object *ob)
{
SculptSession *ss = ob->sculpt;
if (ss->bm) {
sculpt_undo_push_begin("Dynamic topology disable");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
- sculpt_dynamic_topology_disable_ex(scene, ob, NULL);
+ sculpt_dynamic_topology_disable_ex(depsgraph, scene, ob, NULL);
sculpt_undo_push_end();
}
}
static void sculpt_dynamic_topology_enable_with_undo(
+ Depsgraph *depsgraph,
Scene *scene, Object *ob)
{
SculptSession *ss = ob->sculpt;
if (ss->bm == NULL) {
sculpt_undo_push_begin("Dynamic topology enable");
- sculpt_dynamic_topology_enable_ex(scene, ob);
+ sculpt_dynamic_topology_enable_ex(depsgraph, scene, ob);
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
sculpt_undo_push_end();
}
@@ -5385,6 +5406,7 @@ static void sculpt_dynamic_topology_enable_with_undo(
static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
@@ -5392,10 +5414,10 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
WM_cursor_wait(1);
if (ss->bm) {
- sculpt_dynamic_topology_disable_with_undo(scene, ob);
+ sculpt_dynamic_topology_disable_with_undo(depsgraph, scene, ob);
}
else {
- sculpt_dynamic_topology_enable_with_undo(scene, ob);
+ sculpt_dynamic_topology_enable_with_undo(depsgraph, scene, ob);
}
WM_cursor_wait(0);
@@ -5606,13 +5628,14 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot)
/**** Toggle operator for turning sculpt mode on or off ****/
-static void sculpt_init_session(Scene *scene, Object *ob)
+static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
/* Create persistent sculpt mode data */
BKE_sculpt_toolsettings_data_ensure(scene);
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, false, false);
+ ob->sculpt->mode_type = OB_MODE_SCULPT;
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, MultiresModifierData *mmd)
@@ -5626,7 +5649,8 @@ static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, Mult
}
void ED_object_sculptmode_enter_ex(
- Main *bmain, Scene *scene, Object *ob,
+ Main *bmain, Depsgraph *depsgraph,
+ Scene *scene, Object *ob,
ReportList *reports)
{
const int mode_flag = OB_MODE_SCULPT;
@@ -5635,21 +5659,24 @@ void ED_object_sculptmode_enter_ex(
/* Enter sculptmode */
ob->mode |= mode_flag;
-
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
- if (flush_recalc) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
+ if (flush_recalc)
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
/* Create sculpt mode session data */
if (ob->sculpt) {
BKE_sculptsession_free(ob);
}
- sculpt_init_session(scene, ob);
+ /* Make sure derived final from original object does not reference possibly
+ * freed memory.
+ */
+ BKE_object_free_derived_caches(ob);
+
+ sculpt_init_session(depsgraph, scene, ob);
/* Mask layer is required */
if (mmd) {
@@ -5707,7 +5734,7 @@ void ED_object_sculptmode_enter_ex(
if (message_unsupported == NULL) {
/* undo push is needed to prevent memory leak */
sculpt_undo_push_begin("Dynamic topology enable");
- sculpt_dynamic_topology_enable_ex(scene, ob);
+ sculpt_dynamic_topology_enable_ex(depsgraph, scene, ob);
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
}
else {
@@ -5718,10 +5745,8 @@ void ED_object_sculptmode_enter_ex(
}
}
- /* VBO no longer valid */
- if (ob->derivedFinal) {
- GPU_drawobject_free(ob->derivedFinal);
- }
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
void ED_object_sculptmode_enter(struct bContext *C, ReportList *reports)
@@ -5729,10 +5754,12 @@ void ED_object_sculptmode_enter(struct bContext *C, ReportList *reports)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- ED_object_sculptmode_enter_ex(bmain, scene, ob, reports);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, reports);
}
void ED_object_sculptmode_exit_ex(
+ Depsgraph *depsgraph,
Scene *scene, Object *ob)
{
const int mode_flag = OB_MODE_SCULPT;
@@ -5752,14 +5779,14 @@ void ED_object_sculptmode_exit_ex(
* a consistent state.
*/
if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
/* Dynamic topology must be disabled before exiting sculpt
* mode to ensure the undo stack stays in a consistent
* state */
- sculpt_dynamic_topology_disable_with_undo(scene, ob);
+ sculpt_dynamic_topology_disable_with_undo(depsgraph, scene, ob);
/* store so we know to re-enable when entering sculpt mode */
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
@@ -5772,23 +5799,28 @@ void ED_object_sculptmode_exit_ex(
paint_cursor_delete_textures();
- /* VBO no longer valid */
- if (ob->derivedFinal) {
- GPU_drawobject_free(ob->derivedFinal);
- }
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
void ED_object_sculptmode_exit(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- ED_object_sculptmode_exit_ex(scene, ob);
+ ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
}
static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
{
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_SCULPT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
@@ -5800,14 +5832,19 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
}
if (is_mode_set) {
- ED_object_sculptmode_exit_ex(scene, ob);
+ ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
}
else {
- ED_object_sculptmode_enter_ex(bmain, scene, ob, op->reports);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, op->reports);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
}
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
return OPERATOR_FINISHED;
}
@@ -5822,16 +5859,16 @@ static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
ot->exec = sculpt_mode_toggle_exec;
ot->poll = ED_operator_object_active_editable_mesh;
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
-
-static bool sculpt_and_dynamic_topology_constant_detail_poll(bContext *C)
+static bool sculpt_and_constant_or_manual_detail_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- return sculpt_mode_poll(C) && ob->sculpt->bm && (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT);
+ return sculpt_mode_poll(C) && ob->sculpt->bm &&
+ (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL));
}
static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
@@ -5893,30 +5930,42 @@ static void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
/* api callbacks */
ot->exec = sculpt_detail_flood_fill_exec;
- ot->poll = sculpt_and_dynamic_topology_constant_detail_poll;
+ ot->poll = sculpt_and_constant_or_manual_detail_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static void sample_detail(bContext *C, int ss_co[2])
+static void sample_detail(bContext *C, int mx, int my)
{
+ /* Find 3D view to pick from. */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
+ ARegion *ar = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL;
+ if (ar == NULL) {
+ return;
+ }
+
+ /* Set context to 3D view. */
+ ScrArea *prev_sa = CTX_wm_area(C);
+ ARegion *prev_ar = CTX_wm_region(C);
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
ViewContext vc;
- Object *ob;
- Sculpt *sd;
- float ray_start[3], ray_end[3], ray_normal[3], depth;
- SculptDetailRaycastData srd;
- float mouse[2] = {ss_co[0], ss_co[1]};
ED_view3d_viewcontext_init(C, &vc);
- sd = CTX_data_tool_settings(C)->sculpt;
- ob = vc.obact;
-
+ /* Pick sample detail. */
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = vc.obact;
Brush *brush = BKE_paint_brush(&sd->paint);
sculpt_stroke_modifiers_check(C, ob, brush);
- depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false);
+ float mouse[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
+ float ray_start[3], ray_end[3], ray_normal[3];
+ float depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false);
+ SculptDetailRaycastData srd;
srd.hit = 0;
srd.ray_start = ray_start;
srd.ray_normal = ray_normal;
@@ -5930,39 +5979,41 @@ static void sample_detail(bContext *C, int ss_co[2])
/* convert edge length to detail resolution */
sd->constant_detail = 1.0f / srd.detail;
}
+
+ /* Restore context. */
+ CTX_wm_area_set(C, prev_sa);
+ CTX_wm_region_set(C, prev_ar);
}
static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
{
int ss_co[2];
RNA_int_get_array(op->ptr, "location", ss_co);
- sample_detail(C, ss_co);
+ sample_detail(C, ss_co[0], ss_co[1]);
return OPERATOR_FINISHED;
}
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
{
- ScrArea *sa = CTX_wm_area(C);
- ED_area_headerprint(sa, "Click on the mesh to set the detail");
+ ED_workspace_status_text(C, "Click on the mesh to set the detail");
WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
-static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *e)
+static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- switch (e->type) {
+ switch (event->type) {
case LEFTMOUSE:
- if (e->val == KM_PRESS) {
- ScrArea *sa = CTX_wm_area(C);
- int ss_co[2] = {e->mval[0], e->mval[1]};
+ if (event->val == KM_PRESS) {
+ int ss_co[2] = {event->x, event->y};
- sample_detail(C, ss_co);
+ sample_detail(C, ss_co[0], ss_co[1]);
RNA_int_set_array(op->ptr, "location", ss_co);
WM_cursor_modal_restore(CTX_wm_window(C));
- ED_area_headerprint(sa, NULL);
+ ED_workspace_status_text(C, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
return OPERATOR_FINISHED;
@@ -5971,9 +6022,8 @@ static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wm
case RIGHTMOUSE:
{
- ScrArea *sa = CTX_wm_area(C);
WM_cursor_modal_restore(CTX_wm_window(C));
- ED_area_headerprint(sa, NULL);
+ ED_workspace_status_text(C, NULL);
return OPERATOR_CANCELLED;
}
@@ -5994,7 +6044,7 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
ot->invoke = sculpt_sample_detail_size_invoke;
ot->exec = sculpt_sample_detail_size_exec;
ot->modal = sculpt_sample_detail_size_modal;
- ot->poll = sculpt_and_dynamic_topology_constant_detail_poll;
+ ot->poll = sculpt_and_constant_or_manual_detail_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -6003,6 +6053,17 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
}
+/* Dynamic-topology detail size
+ *
+ * This should be improved further, perhaps by showing a triangle
+ * grid rather than brush alpha */
+static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
+{
+ char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
+ RNA_string_set(ptr, "data_path_primary", path);
+ MEM_freeN(path);
+}
+
static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -6012,16 +6073,16 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
WM_operator_properties_create_ptr(&props_ptr, ot);
- if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
- set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0);
+ if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
+ set_brush_rc_props(&props_ptr, "constant_detail_resolution");
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
- set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0);
+ set_brush_rc_props(&props_ptr, "constant_detail_resolution");
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
}
else {
- set_brush_rc_props(&props_ptr, "sculpt", "detail_size", NULL, 0);
+ set_brush_rc_props(&props_ptr, "detail_size");
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 137e957dce6..2154061da1b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -61,12 +61,15 @@ bool sculpt_stroke_get_location(struct bContext *C, float out[3], const float mo
void sculpt_pbvh_clear(Object *ob);
void sculpt_dyntopo_node_layers_add(struct SculptSession *ss);
void sculpt_update_after_dynamic_topology_toggle(
+ struct Depsgraph *depsgraph,
struct Scene *scene, struct Object *ob);
void sculpt_dynamic_topology_enable_ex(
+ struct Depsgraph *depsgraph,
struct Scene *scene, struct Object *ob);
void sculpt_dynamic_topology_enable(bContext *C);
void sculpt_dynamic_topology_disable_ex(
+ struct Depsgraph *depsgraph,
struct Scene *scene, struct Object *ob,
struct SculptUndoNode *unode);
void sculpt_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 62e548f661c..d79c6b81fd7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -50,22 +50,24 @@
#include "DNA_mesh_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_subsurf.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_undo_system.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
-#include "GPU_buffers.h"
-
#include "ED_paint.h"
#include "ED_object.h"
#include "ED_sculpt.h"
@@ -135,12 +137,14 @@ static bool sculpt_undo_restore_deformed(
}
}
-static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNode *unode)
+static bool sculpt_undo_restore_coords(bContext *C, SculptUndoNode *unode)
{
Scene *scene = CTX_data_scene(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
SculptSession *ss = ob->sculpt;
+ SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
MVert *mvert;
int *index;
@@ -156,7 +160,7 @@ static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoN
if (kb) {
ob->shapenr = BLI_findindex(&key->block, kb) + 1;
- BKE_sculpt_update_mesh_elements(scene, sd, ob, false, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, false);
WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
}
else {
@@ -196,7 +200,7 @@ static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoN
/* pbvh uses it's own mvert array, so coords should be */
/* propagated to pbvh here */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, unode->totvert);
MEM_freeN(vertCos);
}
@@ -226,16 +230,16 @@ static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoN
}
}
}
- else if (unode->maxgrid && dm->getGridData) {
+ else if (unode->maxgrid && subdiv_ccg != NULL) {
/* multires restore */
CCGElem **grids, *grid;
CCGKey key;
float (*co)[3];
int gridsize;
- grids = dm->getGridData(dm);
- gridsize = dm->getGridSize(dm);
- dm->getGridKey(dm, &key);
+ grids = subdiv_ccg->grids;
+ gridsize = subdiv_ccg->grid_size;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
co = unode->co;
for (int j = 0; j < unode->totgrid; j++) {
@@ -251,11 +255,12 @@ static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoN
}
static bool sculpt_undo_restore_hidden(
- bContext *C, DerivedMesh *dm,
+ bContext *C,
SculptUndoNode *unode)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
int i;
if (unode->maxvert) {
@@ -270,8 +275,8 @@ static bool sculpt_undo_restore_hidden(
}
}
}
- else if (unode->maxgrid && dm->getGridData) {
- BLI_bitmap **grid_hidden = dm->getGridHidden(dm);
+ else if (unode->maxgrid && subdiv_ccg != NULL) {
+ BLI_bitmap **grid_hidden = subdiv_ccg->grid_hidden;
for (i = 0; i < unode->totgrid; i++) {
SWAP(BLI_bitmap *,
@@ -284,10 +289,11 @@ static bool sculpt_undo_restore_hidden(
return 1;
}
-static bool sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode *unode)
+static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
MVert *mvert;
float *vmask;
int *index, i, j;
@@ -306,16 +312,16 @@ static bool sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNod
}
}
}
- else if (unode->maxgrid && dm->getGridData) {
+ else if (unode->maxgrid && subdiv_ccg != NULL) {
/* multires restore */
CCGElem **grids, *grid;
CCGKey key;
float *mask;
int gridsize;
- grids = dm->getGridData(dm);
- gridsize = dm->getGridSize(dm);
- dm->getGridKey(dm, &key);
+ grids = subdiv_ccg->grids;
+ gridsize = subdiv_ccg->grid_size;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
mask = unode->mask;
for (j = 0; j < unode->totgrid; j++) {
@@ -378,8 +384,8 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
}
/* Create empty sculpt BMesh and enable logging */
-static void sculpt_undo_bmesh_enable(Object *ob,
- SculptUndoNode *unode)
+static void sculpt_undo_bmesh_enable(
+ Object *ob, SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
@@ -472,8 +478,9 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
Scene *scene = CTX_data_scene(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
- DerivedMesh *dm;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
SculptSession *ss = ob->sculpt;
+ SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
SculptUndoNode *unode;
bool update = false, rebuild = false;
bool need_mask = false;
@@ -490,10 +497,9 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
}
}
- BKE_sculpt_update_mesh_elements(scene, sd, ob, false, need_mask);
+ DEG_id_tag_update(&ob->id, DEG_TAG_SHADING_UPDATE);
- /* call _after_ sculpt_update_mesh_elements() which may update 'ob->derivedFinal' */
- dm = mesh_get_derived_final(scene, ob, 0);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, need_mask);
if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss))
return;
@@ -508,9 +514,9 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
if (ss->totvert != unode->maxvert)
continue;
}
- else if (unode->maxgrid && dm->getGridData) {
- if ((dm->getNumGrids(dm) != unode->maxgrid) ||
- (dm->getGridSize(dm) != unode->gridsize))
+ else if (unode->maxgrid && subdiv_ccg != NULL) {
+ if ((subdiv_ccg->num_grids != unode->maxgrid) ||
+ (subdiv_ccg->grid_size != unode->gridsize))
{
continue;
}
@@ -521,15 +527,15 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
switch (unode->type) {
case SCULPT_UNDO_COORDS:
- if (sculpt_undo_restore_coords(C, dm, unode))
+ if (sculpt_undo_restore_coords(C, unode))
update = true;
break;
case SCULPT_UNDO_HIDDEN:
- if (sculpt_undo_restore_hidden(C, dm, unode))
+ if (sculpt_undo_restore_hidden(C, unode))
rebuild = true;
break;
case SCULPT_UNDO_MASK:
- if (sculpt_undo_restore_mask(C, dm, unode))
+ if (sculpt_undo_restore_mask(C, unode))
update = true;
break;
@@ -556,7 +562,7 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
else {
BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
}
- BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL);
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw | PBVH_UpdateNormals, NULL);
if (BKE_sculpt_multires_active(scene, ob)) {
if (rebuild)
@@ -576,14 +582,11 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
}
if (tag_update) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else {
sculpt_update_object_bounding_box(ob);
}
-
- /* for non-PBVH drawing, need to recreate VBOs */
- GPU_drawobject_free(ob->derivedFinal);
}
}
@@ -932,9 +935,10 @@ SculptUndoNode *sculpt_undo_push_node(
unode = sculpt_undo_alloc_node(ob, node, type);
- BLI_thread_unlock(LOCK_CUSTOM1);
-
- /* copy threaded, hopefully this is the performance critical part */
+ /* NOTE: If this ever becomes a bottleneck, make a lock inside of the node.
+ * so we release global lock sooner, but keep data locked for until it is
+ * fully initialized.
+ */
if (unode->grids) {
int totgrid, *grids;
@@ -971,6 +975,8 @@ SculptUndoNode *sculpt_undo_push_node(
if (ss->kb) BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
else unode->shapeName[0] = '\0';
+ BLI_thread_unlock(LOCK_CUSTOM1);
+
return unode;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index a1514a65694..7fa7c7f37b5 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -46,16 +46,21 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
+#include "DEG_depsgraph.h"
+
#include "ED_screen.h"
#include "ED_image.h"
#include "ED_mesh.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_state.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -65,9 +70,6 @@
#include "paint_intern.h"
#include "uvedit_intern.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
#include "UI_view2d.h"
#define MARK_BOUNDARY 1
@@ -213,18 +215,17 @@ static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(cu
alpha *= (size - PX_SIZE_FADE_MIN) / (PX_SIZE_FADE_MAX - PX_SIZE_FADE_MIN);
}
- glPushMatrix();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(brush->add_col, alpha);
- glTranslatef((float)x, (float)y, 0.0f);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ imm_draw_circle_wire_2d(pos, (float)x, (float)y, size, 40);
+ GPU_blend(false);
+ GPU_line_smooth(false);
- glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], alpha);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glutil_draw_lined_arc(0, (float)(M_PI * 2.0), size, 40);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
-
- glPopMatrix();
+ immUnbindProgram();
}
#undef PX_SIZE_FADE_MAX
#undef PX_SIZE_FADE_MIN
@@ -235,19 +236,18 @@ void ED_space_image_uv_sculpt_update(Main *bmain, wmWindowManager *wm, Scene *sc
{
ToolSettings *settings = scene->toolsettings;
if (settings->use_uv_sculpt) {
- if (!settings->uvsculpt) {
- settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint");
+ if (settings->uvsculpt == NULL) {
settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB;
settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS;
settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
- /* Uv sculpting does not include explicit brush view control yet, always enable */
- settings->uvsculpt->paint.flags |= PAINT_SHOW_BRUSH;
}
-
+ BKE_paint_ensure(settings, (Paint **)&settings->uvsculpt);
BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT_UV, PAINT_CURSOR_SCULPT);
settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(
- wm, uv_sculpt_brush_poll,
+ wm,
+ SPACE_IMAGE, RGN_TYPE_WINDOW,
+ uv_sculpt_brush_poll,
brush_drawcursor_uvsculpt, NULL);
}
else {
@@ -654,7 +654,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
UvElement *element;
UvNearestHit hit = UV_NEAREST_HIT_INIT;
Image *ima = CTX_data_edit_image(C);
- uv_find_nearest_vert(scene, ima, em, co, 0.0f, &hit);
+ uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
island_index = element->island;
@@ -901,7 +901,7 @@ static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *ev
ED_region_tag_redraw(CTX_wm_region(C));
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
return OPERATOR_RUNNING_MODAL;
}
diff --git a/source/blender/editors/sound/CMakeLists.txt b/source/blender/editors/sound/CMakeLists.txt
index 535cd579030..9efdf11e8d7 100644
--- a/source/blender/editors/sound/CMakeLists.txt
+++ b/source/blender/editors/sound/CMakeLists.txt
@@ -39,7 +39,7 @@ set(SRC
)
if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+ add_definitions(-DWITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 832505c2281..3ce4965b284 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -49,13 +49,13 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_packedFile.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_sound.h"
#include "BKE_sequencer.h"
+#include "BKE_sound.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -67,7 +67,7 @@
#include "WM_types.h"
#ifdef WITH_AUDASPACE
-# include AUD_SPECIAL_H
+# include <AUD_Special.h>
#endif
#include "ED_sound.h"
@@ -310,6 +310,7 @@ static int sound_bake_animation_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
int oldfra = scene->r.cfra;
int cfra;
@@ -317,11 +318,11 @@ static int sound_bake_animation_exec(bContext *C, wmOperator *UNUSED(op))
for (cfra = (scene->r.sfra > 0) ? (scene->r.sfra - 1) : 0; cfra <= scene->r.efra + 1; cfra++) {
scene->r.cfra = cfra;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
scene->r.cfra = oldfra;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
return OPERATOR_FINISHED;
}
@@ -633,7 +634,7 @@ static void sound_mixdown_draw(bContext *C, wmOperator *op)
RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
/* main draw call */
- uiDefAutoButsRNA(layout, &ptr, sound_mixdown_draw_check_prop, NULL, '\0');
+ uiDefAutoButsRNA(layout, &ptr, sound_mixdown_draw_check_prop, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
}
#endif // WITH_AUDASPACE
diff --git a/source/blender/editors/space_action/action_buttons.c b/source/blender/editors/space_action/action_buttons.c
index b16d0543d0e..55ad773f4df 100644
--- a/source/blender/editors/space_action/action_buttons.c
+++ b/source/blender/editors/space_action/action_buttons.c
@@ -48,7 +48,6 @@
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_screen.h"
#include "BKE_unit.h"
@@ -118,7 +117,7 @@ static int action_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void ACTION_OT_properties(wmOperatorType *ot)
{
- ot->name = "Properties";
+ ot->name = "Toggle Sidebar";
ot->idname = "ACTION_OT_properties";
ot->description = "Toggle the properties region visibility";
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 8d4596a79a7..a3773110d0f 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -53,12 +53,12 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_context.h"
#include "BKE_fcurve.h"
-#include "BKE_library.h"
#include "BKE_key.h"
+#include "BKE_library.h"
#include "BKE_nla.h"
#include "BKE_scene.h"
-#include "BKE_context.h"
#include "BKE_report.h"
#include "UI_view2d.h"
@@ -566,11 +566,11 @@ void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act,
if (strip->act == act) {
/* Remove this strip, and the track too if it doesn't have anything else */
- BKE_nlastrip_free(&nlt->strips, strip);
+ BKE_nlastrip_free(&nlt->strips, strip, true);
if (nlt->strips.first == NULL) {
BLI_assert(nstrip == NULL);
- BKE_nlatrack_free(&adt->nla_tracks, nlt);
+ BKE_nlatrack_free(&adt->nla_tracks, nlt, true);
}
}
}
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 33822e633be..738c5e4d2e2 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -43,16 +43,24 @@
/* Types --------------------------------------------------------------- */
#include "DNA_anim_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_object_types.h"
#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
#include "BKE_action.h"
#include "BKE_context.h"
+#include "BKE_pointcache.h"
/* Everything from source (BIF, BDR, BSE) ------------------------------ */
#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -156,32 +164,29 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- int filter;
View2D *v2d = &ar->v2d;
bDopeSheet *ads = &saction->ads;
AnimData *adt = NULL;
float act_start, act_end, y;
- size_t items;
- int height;
- unsigned char col1[3], col2[3];
- unsigned char col1a[3], col2a[3];
- unsigned char col1b[3], col2b[3];
+ unsigned char col1[4], col2[4];
+ unsigned char col1a[4], col2a[4];
+ unsigned char col1b[4], col2b[4];
const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS);
/* get theme colors */
- UI_GetThemeColor3ubv(TH_BACK, col2);
- UI_GetThemeColor3ubv(TH_HILITE, col1);
+ UI_GetThemeColor4ubv(TH_SHADE2, col2);
+ UI_GetThemeColor4ubv(TH_HILITE, col1);
- UI_GetThemeColor3ubv(TH_GROUP, col2a);
- UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
+ UI_GetThemeColor4ubv(TH_GROUP, col2a);
+ UI_GetThemeColor4ubv(TH_GROUP_ACTIVE, col1a);
- UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELOB, col1b);
- UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
+ UI_GetThemeColor4ubv(TH_DOPESHEET_CHANNELOB, col1b);
+ UI_GetThemeColor4ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
/* set view-mapping rect (only used for x-axis), for NLA-scaling mapping with less calculation */
@@ -194,10 +199,10 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
/* build list of channels to draw */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
- items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
+ int height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac)));
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
@@ -205,7 +210,13 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* first backdrop strips */
y = (float)(-ACHANNEL_HEIGHT(ac));
- glEnable(GL_BLEND);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_blend(true);
for (ale = anim_data.first; ale; ale = ale->next) {
const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
@@ -229,22 +240,20 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
case ANIMTYPE_SUMMARY:
{
/* reddish color from NLA */
- UI_ThemeColor4(TH_ANIM_ACTIVE);
+ immUniformThemeColor(TH_ANIM_ACTIVE);
break;
}
case ANIMTYPE_SCENE:
case ANIMTYPE_OBJECT:
{
- if (sel) glColor4ub(col1b[0], col1b[1], col1b[2], 0x45);
- else glColor4ub(col1b[0], col1b[1], col1b[2], 0x22);
+ immUniformColor3ubvAlpha(col1b, sel ? col1[3] : col1b[3]);
break;
}
case ANIMTYPE_FILLACTD:
case ANIMTYPE_DSSKEY:
case ANIMTYPE_DSWOR:
{
- if (sel) glColor4ub(col2b[0], col2b[1], col2b[2], 0x45);
- else glColor4ub(col2b[0], col2b[1], col2b[2], 0x22);
+ immUniformColor3ubvAlpha(col2b, sel ? col1[3] : col2b[3]);
break;
}
case ANIMTYPE_GROUP:
@@ -252,17 +261,14 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
bActionGroup *agrp = ale->data;
if (show_group_colors && agrp->customCol) {
if (sel) {
- unsigned char *cp = (unsigned char *)agrp->cs.select;
- glColor4ub(cp[0], cp[1], cp[2], 0x45);
+ immUniformColor3ubvAlpha((unsigned char *)agrp->cs.select, col1a[3]);
}
else {
- unsigned char *cp = (unsigned char *)agrp->cs.solid;
- glColor4ub(cp[0], cp[1], cp[2], 0x1D);
+ immUniformColor3ubvAlpha((unsigned char *)agrp->cs.solid, col2a[3]);
}
}
else {
- if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22);
- else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22);
+ immUniformColor4ubv(sel ? col1a : col2a);
}
break;
}
@@ -270,53 +276,45 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
{
FCurve *fcu = ale->data;
if (show_group_colors && fcu->grp && fcu->grp->customCol) {
- unsigned char *cp = (unsigned char *)fcu->grp->cs.active;
-
- if (sel) glColor4ub(cp[0], cp[1], cp[2], 0x65);
- else glColor4ub(cp[0], cp[1], cp[2], 0x0B);
+ immUniformColor3ubvAlpha((unsigned char *)fcu->grp->cs.active, sel ? col1[3] : col2[3]);
}
else {
- if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
- else glColor4ub(col2[0], col2[1], col2[2], 0x22);
+ immUniformColor4ubv(sel ? col1 : col2);
}
break;
}
default:
{
- if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
- else glColor4ub(col2[0], col2[1], col2[2], 0x22);
- break;
+ immUniformColor4ubv(sel ? col1 : col2);
}
}
/* draw region twice: firstly backdrop, then the current range */
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
+ immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
if (ac->datatype == ANIMCONT_ACTION)
- glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac));
+ immRectf(pos, act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
/* frames less than one get less saturated background */
- if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
- else glColor4ub(col2[0], col2[1], col2[2], 0x22);
- glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
+ unsigned char *color = sel ? col1 : col2;
+ immUniformColor4ubv(color);
+ immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
/* frames one and higher get a saturated background */
- if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
- else glColor4ub(col2[0], col2[1], col2[2], 0x44);
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
+ immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2));
+ immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
else if (ac->datatype == ANIMCONT_MASK) {
/* TODO --- this is a copy of gpencil */
/* frames less than one get less saturated background */
- if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
- else glColor4ub(col2[0], col2[1], col2[2], 0x22);
- glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
+ unsigned char *color = sel ? col1 : col2;
+ immUniformColor4ubv(color);
+ immRectf(pos, 0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac));
/* frames one and higher get a saturated background */
- if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44);
- else glColor4ub(col2[0], col2[1], col2[2], 0x44);
- glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
+ immUniformColor3ubvAlpha(color, MIN2(255, color[3] * 2));
+ immRectf(pos, v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac));
}
}
}
@@ -324,7 +322,18 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* Increment the step */
y -= ACHANNEL_STEP(ac);
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
+
+ /* black line marking 'current frame' for Time-Slide transform mode */
+ if (saction->flag & SACTION_MOVING) {
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD);
+ immVertex2f(pos, saction->timeslide, v2d->cur.ymax);
+ immEnd();
+ }
+ immUnbindProgram();
/* Draw keyframes
* 1) Only channels that are visible in the Action Editor get drawn/evaluated.
@@ -348,28 +357,28 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* draw 'keyframes' for each specific datatype */
switch (ale->datatype) {
case ALE_ALL:
- draw_summary_channel(v2d, ale->data, y, ac->yscale_fac);
+ draw_summary_channel(v2d, ale->data, y, ac->yscale_fac, saction->flag);
break;
case ALE_SCE:
- draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
+ draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, saction->flag);
break;
case ALE_OB:
- draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac);
+ draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac, saction->flag);
break;
case ALE_ACT:
- draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
+ draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, saction->flag);
break;
case ALE_GROUP:
- draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac);
+ draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac, saction->flag);
break;
case ALE_FCURVE:
- draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac);
+ draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac, saction->flag);
break;
case ALE_GPFRAME:
- draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac);
+ draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac, saction->flag);
break;
case ALE_MASKLAY:
- draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac);
+ draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac, saction->flag);
break;
}
}
@@ -378,16 +387,157 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
y -= ACHANNEL_STEP(ac);
}
- /* free tempolary channels used for drawing */
+ /* free temporary channels used for drawing */
ANIM_animdata_freelist(&anim_data);
+}
- /* black line marking 'current frame' for Time-Slide transform mode */
- if (saction->flag & SACTION_MOVING) {
- glColor3f(0.0f, 0.0f, 0.0f);
+/* ************************************************************************* */
+/* Timeline - Caches */
+
+void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene)
+{
+ PTCacheID *pid;
+ ListBase pidlist;
+ const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
+ float yoffs = 0.f;
+
+ if (!(saction->cache_display & TIME_CACHE_DISPLAY) || (!ob))
+ return;
+
+ BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* iterate over pointcaches on the active object, and draw each one's range */
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ float col[4];
+
+ switch (pid->type) {
+ case PTCACHE_TYPE_SOFTBODY:
+ if (!(saction->cache_display & TIME_CACHE_SOFTBODY)) continue;
+ break;
+ case PTCACHE_TYPE_PARTICLES:
+ if (!(saction->cache_display & TIME_CACHE_PARTICLES)) continue;
+ break;
+ case PTCACHE_TYPE_CLOTH:
+ if (!(saction->cache_display & TIME_CACHE_CLOTH)) continue;
+ break;
+ case PTCACHE_TYPE_SMOKE_DOMAIN:
+ case PTCACHE_TYPE_SMOKE_HIGHRES:
+ if (!(saction->cache_display & TIME_CACHE_SMOKE)) continue;
+ break;
+ case PTCACHE_TYPE_DYNAMICPAINT:
+ if (!(saction->cache_display & TIME_CACHE_DYNAMICPAINT)) continue;
+ break;
+ case PTCACHE_TYPE_RIGIDBODY:
+ if (!(saction->cache_display & TIME_CACHE_RIGIDBODY)) continue;
+ break;
+ }
+
+ if (pid->cache->cached_frames == NULL)
+ continue;
+
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(0.0, (float)V2D_SCROLL_HEIGHT_TEXT + yoffs);
+ GPU_matrix_scale_2f(1.0, cache_draw_height);
+
+ switch (pid->type) {
+ case PTCACHE_TYPE_SOFTBODY:
+ col[0] = 1.0; col[1] = 0.4; col[2] = 0.02;
+ col[3] = 0.1;
+ break;
+ case PTCACHE_TYPE_PARTICLES:
+ col[0] = 1.0; col[1] = 0.1; col[2] = 0.02;
+ col[3] = 0.1;
+ break;
+ case PTCACHE_TYPE_CLOTH:
+ col[0] = 0.1; col[1] = 0.1; col[2] = 0.75;
+ col[3] = 0.1;
+ break;
+ case PTCACHE_TYPE_SMOKE_DOMAIN:
+ case PTCACHE_TYPE_SMOKE_HIGHRES:
+ col[0] = 0.2; col[1] = 0.2; col[2] = 0.2;
+ col[3] = 0.1;
+ break;
+ case PTCACHE_TYPE_DYNAMICPAINT:
+ col[0] = 1.0; col[1] = 0.1; col[2] = 0.75;
+ col[3] = 0.1;
+ break;
+ case PTCACHE_TYPE_RIGIDBODY:
+ col[0] = 1.0; col[1] = 0.6; col[2] = 0.0;
+ col[3] = 0.1;
+ break;
+ default:
+ col[0] = 1.0; col[1] = 0.0; col[2] = 1.0;
+ col[3] = 0.1;
+ BLI_assert(0);
+ break;
+ }
- glBegin(GL_LINES);
- glVertex2f(saction->timeslide, v2d->cur.ymin - EXTRA_SCROLL_PAD);
- glVertex2f(saction->timeslide, v2d->cur.ymax);
- glEnd();
+ const int sta = pid->cache->startframe, end = pid->cache->endframe;
+
+ GPU_blend(true);
+
+ immUniformColor4fv(col);
+ immRectf(pos, (float)sta, 0.0, (float)end, 1.0);
+
+ col[3] = 0.4f;
+ if (pid->cache->flag & PTCACHE_BAKED) {
+ col[0] -= 0.4f; col[1] -= 0.4f; col[2] -= 0.4f;
+ }
+ else if (pid->cache->flag & PTCACHE_OUTDATED) {
+ col[0] += 0.4f; col[1] += 0.4f; col[2] += 0.4f;
+ }
+
+ immUniformColor4fv(col);
+
+ {
+ /* draw a quad for each chunk of consecutive cached frames */
+ const int chunk_tot = 32;
+ int chunk_len = 0;
+ int ista = 0, iend = -1;
+
+ for (int i = sta; i <= end; i++) {
+ if (pid->cache->cached_frames[i - sta]) {
+ if (chunk_len == 0) {
+ immBeginAtMost(GPU_PRIM_TRIS, chunk_tot * 6);
+ }
+ if (ista > iend) {
+ chunk_len++;
+ ista = i;
+ }
+ iend = i;
+ }
+ else {
+ if (ista <= iend) {
+ immRectf_fast(pos, (float)ista - 0.5f, 0.0f, (float)iend + 0.5f, 1.0f);
+ iend = ista - 1;
+ }
+ if (chunk_len >= chunk_tot) {
+ immEnd();
+ chunk_len = 0;
+ }
+ }
+ }
+ if (ista <= iend) {
+ immRectf_fast(pos, (float)ista - 0.5f, 0.0f, (float)iend + 0.5f, 1.0f);
+ }
+ if (chunk_len != 0) {
+ immEnd();
+ }
+ }
+
+ GPU_blend(false);
+
+ GPU_matrix_pop();
+
+ yoffs += cache_draw_height;
}
+
+ immUnbindProgram();
+
+ BLI_freelistN(&pidlist);
}
+
+/* ************************************************************************* */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 289cf730228..c2376b506d4 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -54,14 +54,12 @@
#include "RNA_enum_types.h"
#include "BKE_action.h"
+#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_global.h"
#include "BKE_key.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
#include "BKE_nla.h"
-#include "BKE_context.h"
#include "BKE_report.h"
#include "UI_view2d.h"
@@ -385,12 +383,22 @@ static int actkeys_viewall(bContext *C, const bool only_sel)
if (only_sel && (found == false))
return OPERATOR_CANCELLED;
- v2d->cur.xmin = min;
- v2d->cur.xmax = max;
+ if (fabsf(max - min) < 1.0f) {
+ /* Exception - center the single keyfrme */
+ float xwidth = BLI_rctf_size_x(&v2d->cur);
+
+ v2d->cur.xmin = min - xwidth / 2.0f;
+ v2d->cur.xmax = max + xwidth / 2.0f;
+ }
+ else {
+ /* Normal case - stretch the two keyframes out to fill the space, with extra spacing */
+ v2d->cur.xmin = min;
+ v2d->cur.xmax = max;
- extra = 0.1f * BLI_rctf_size_x(&v2d->cur);
- v2d->cur.xmin -= extra;
- v2d->cur.xmax += extra;
+ extra = 0.125f * BLI_rctf_size_x(&v2d->cur);
+ v2d->cur.xmin -= extra;
+ v2d->cur.xmax += extra;
+ }
/* set vertical range */
if (only_sel == false) {
@@ -674,6 +682,7 @@ static void insert_action_keys(bAnimContext *ac, short mode)
bAnimListElem *ale;
int filter;
+ struct Depsgraph *depsgraph = ac->depsgraph;
ReportList *reports = ac->reports;
Scene *scene = ac->scene;
ToolSettings *ts = scene->toolsettings;
@@ -691,15 +700,8 @@ static void insert_action_keys(bAnimContext *ac, short mode)
/* insert keyframes */
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- float cfra;
-
- /* adjust current frame for NLA-scaling */
- if (adt)
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- else
- cfra = (float)CFRA;
+ float cfra = (float)CFRA;
/* read value from property the F-Curve represents, or from the curve only?
* - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
@@ -708,10 +710,16 @@ static void insert_action_keys(bAnimContext *ac, short mode)
* (TODO: add the full-blown PointerRNA relative parsing case here...)
*/
if (ale->id && !ale->owner) {
- insert_keyframe(ac->bmain, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
}
else {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* adjust current frame for NLA-scaling */
+ if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+
const float curval = evaluate_fcurve(fcu, cfra);
insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
}
diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h
index 37bef41e4d5..986afe96e11 100644
--- a/source/blender/editors/space_action/action_intern.h
+++ b/source/blender/editors/space_action/action_intern.h
@@ -33,10 +33,13 @@
struct bContext;
struct bAnimContext;
+struct Scene;
+struct Object;
struct SpaceAction;
struct ScrArea;
struct ARegion;
struct ARegionType;
+struct View2D;
struct wmOperatorType;
/* internal exports only */
@@ -54,11 +57,13 @@ void ACTION_OT_properties(struct wmOperatorType *ot);
void draw_channel_names(struct bContext *C, struct bAnimContext *ac, struct ARegion *ar);
void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, struct ARegion *ar);
+void timeline_draw_cache(struct SpaceAction *saction, struct Object *ob, struct Scene *scene);
+
/* ***************************************** */
/* action_select.c */
-void ACTION_OT_select_all_toggle(struct wmOperatorType *ot);
-void ACTION_OT_select_border(struct wmOperatorType *ot);
+void ACTION_OT_select_all(struct wmOperatorType *ot);
+void ACTION_OT_select_box(struct wmOperatorType *ot);
void ACTION_OT_select_lasso(struct wmOperatorType *ot);
void ACTION_OT_select_circle(struct wmOperatorType *ot);
void ACTION_OT_select_column(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index ea7591c36c0..bbcba93370d 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -40,6 +40,7 @@
#include "ED_markers.h"
#include "ED_transform.h"
#include "ED_object.h"
+#include "ED_select_utils.h"
#include "action_intern.h"
@@ -58,8 +59,8 @@ void action_operatortypes(void)
/* keyframes */
/* selection */
WM_operatortype_append(ACTION_OT_clickselect);
- WM_operatortype_append(ACTION_OT_select_all_toggle);
- WM_operatortype_append(ACTION_OT_select_border);
+ WM_operatortype_append(ACTION_OT_select_all);
+ WM_operatortype_append(ACTION_OT_select_box);
WM_operatortype_append(ACTION_OT_select_lasso);
WM_operatortype_append(ACTION_OT_select_circle);
WM_operatortype_append(ACTION_OT_select_column);
@@ -118,168 +119,12 @@ void ED_operatormacros_action(void)
/* ************************** registration - keymaps **********************************/
-static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- /* action_select.c - selection tools */
- /* click-select: keyframe (replace) */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_clickselect", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "column", false);
- RNA_boolean_set(kmi->ptr, "channel", false);
- /* click-select: all on same frame (replace) */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "column", true);
- RNA_boolean_set(kmi->ptr, "channel", false);
- /* click-select: keyframe (add) */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "column", false);
- RNA_boolean_set(kmi->ptr, "channel", false);
- /* click-select: all on same frame (add) */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "column", true);
- RNA_boolean_set(kmi->ptr, "channel", false);
- /* click-select: all on same channel (replace) */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "column", false);
- RNA_boolean_set(kmi->ptr, "channel", true);
- /* click-select: all on same channel (add) */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_ALT | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "column", false);
- RNA_boolean_set(kmi->ptr, "channel", true);
-
- /* click-select: left/right */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_leftright", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", ACTKEYS_LRSEL_TEST);
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_leftright", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_enum_set(kmi->ptr, "mode", ACTKEYS_LRSEL_TEST);
-
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_leftright", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", ACTKEYS_LRSEL_LEFT);
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_leftright", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", ACTKEYS_LRSEL_RIGHT);
-
- /* deselect all */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "invert", false);
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "invert", true);
-
- /* borderselect */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "axis_range", false);
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "axis_range", true);
-
- /* region select */
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0);
-
- /* column select */
- RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
- RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
- RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_COLUMN);
- RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_BETWEEN);
-
- /* select more/less */
- WM_keymap_add_item(keymap, "ACTION_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- /* select linked */
- WM_keymap_add_item(keymap, "ACTION_OT_select_linked", LKEY, KM_PRESS, 0, 0);
-
-
- /* action_edit.c */
- /* jump to selected keyframes */
- WM_keymap_add_item(keymap, "ACTION_OT_frame_jump", GKEY, KM_PRESS, KM_CTRL, 0);
-
- /* menu + single-step transform */
- WM_keymap_add_item(keymap, "ACTION_OT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_mirror", MKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* menu + set setting */
- WM_keymap_add_item(keymap, "ACTION_OT_handle_type", VKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_interpolation_type", TKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_keyframe_type", RKEY, KM_PRESS, 0, 0);
-
- /* destructive */
- WM_keymap_add_item(keymap, "ACTION_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_menu(keymap, "DOPESHEET_MT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "DOPESHEET_MT_delete", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "ACTION_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
-
- /* copy/paste */
- WM_keymap_add_item(keymap, "ACTION_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "flipped", true);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "ACTION_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
- kmi = WM_keymap_add_item(keymap, "ACTION_OT_paste", VKEY, KM_PRESS, KM_OSKEY | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "flipped", true);
-#endif
-
- /* auto-set range */
- WM_keymap_add_item(keymap, "ACTION_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "ACTION_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
- WM_keymap_add_item(keymap, "ACTION_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "ACTION_OT_view_frame", PAD0, KM_PRESS, 0, 0);
-
-
- /* animation module */
- /* channels list
- * NOTE: these operators were originally for the channels list, but are added here too for convenience...
- */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
-
- /* find (i.e. a shortcut for setting the name filter) */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
-
- /* transform system */
- transform_keymap_for_space(keyconf, keymap, SPACE_ACTION);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_action");
- ED_keymap_proportional_cycle(keyconf, keymap);
-
- /* special markers hotkeys for anim editors: see note in definition of this function */
- ED_marker_keymap_animedit_conflictfree(keymap);
-}
-
/* --------------- */
void action_keymap(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
-
/* keymap for all regions */
- keymap = WM_keymap_ensure(keyconf, "Dopesheet Generic", SPACE_ACTION, 0);
-
- /* region management... */
- WM_keymap_add_item(keymap, "ACTION_OT_properties", NKEY, KM_PRESS, 0, 0);
-
+ WM_keymap_ensure(keyconf, "Dopesheet Generic", SPACE_ACTION, 0);
/* channels */
/* Channels are not directly handled by the Action Editor module, but are inherited from the Animation module.
@@ -288,6 +133,5 @@ void action_keymap(wmKeyConfig *keyconf)
*/
/* keyframes */
- keymap = WM_keymap_ensure(keyconf, "Dopesheet", SPACE_ACTION, 0);
- action_keymap_keyframes(keyconf, keymap);
+ WM_keymap_ensure(keyconf, "Dopesheet", SPACE_ACTION, 0);
}
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 581725b7030..0c96560f6d5 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -51,6 +51,7 @@
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_gpencil.h"
#include "UI_view2d.h"
@@ -61,6 +62,7 @@
#include "ED_keyframes_edit.h"
#include "ED_markers.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -134,15 +136,20 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel)
/* Now set the flags */
for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_GPLAYER)
+ if (ale->type == ANIMTYPE_GPLAYER) {
ED_gplayer_frame_select_set(ale->data, sel);
- else if (ale->type == ANIMTYPE_MASKLAYER)
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_masklayer_frame_select_set(ale->data, sel);
- else
+ }
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL);
+ }
}
/* Cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -157,10 +164,24 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* 'standard' behavior - check if selected, then apply relevant selection */
- if (RNA_boolean_get(op->ptr, "invert"))
- deselect_action_keys(&ac, 0, SELECT_INVERT);
- else
- deselect_action_keys(&ac, 1, SELECT_ADD);
+ const int action = RNA_enum_get(op->ptr, "action");
+ switch (action) {
+ case SEL_TOGGLE:
+ deselect_action_keys(&ac, 1, SELECT_ADD);
+ break;
+ case SEL_SELECT:
+ deselect_action_keys(&ac, 0, SELECT_ADD);
+ break;
+ case SEL_DESELECT:
+ deselect_action_keys(&ac, 0, SELECT_SUBTRACT);
+ break;
+ case SEL_INVERT:
+ deselect_action_keys(&ac, 0, SELECT_INVERT);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -168,11 +189,11 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void ACTION_OT_select_all_toggle(wmOperatorType *ot)
+void ACTION_OT_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select All";
- ot->idname = "ACTION_OT_select_all_toggle";
+ ot->idname = "ACTION_OT_select_all";
ot->description = "Toggle selection of all keyframes";
/* api callbacks */
@@ -182,12 +203,11 @@ void ACTION_OT_select_all_toggle(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- ot->prop = RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
- RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+ /* properties */
+ WM_operator_properties_select_all(ot);
}
-/* ******************** Border Select Operator **************************** */
+/* ******************** Box Select Operator **************************** */
/* This operator currently works in one of three ways:
* -> BKEY - 1) all keyframes within region are selected (ACTKEYS_BORDERSEL_ALLKEYS)
* -> ALT-BKEY - depending on which axis of the region was larger...
@@ -195,15 +215,15 @@ void ACTION_OT_select_all_toggle(wmOperatorType *ot)
* -> 3) y-axis, so select all frames within channels that region included (ACTKEYS_BORDERSEL_CHANNELS)
*/
-/* defines for borderselect mode */
+/* defines for box_select mode */
enum {
ACTKEYS_BORDERSEL_ALLKEYS = 0,
ACTKEYS_BORDERSEL_FRAMERANGE,
ACTKEYS_BORDERSEL_CHANNELS,
-} /*eActKeys_BorderSelect_Mode*/;
+} /*eActKeys_BoxSelect_Mode*/;
-static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, short selectmode)
+static void box_select_action(bAnimContext *ac, const rcti rect, short mode, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -234,7 +254,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
/* init editing data */
memset(&ked, 0, sizeof(KeyframeEditData));
- /* loop over data, doing border select */
+ /* loop over data, doing box select */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
@@ -268,25 +288,29 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
bGPdata *gpd = ale->data;
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- ED_gplayer_frames_select_border(gpl, rectf.xmin, rectf.xmax, selectmode);
+ ED_gplayer_frames_select_box(gpl, rectf.xmin, rectf.xmax, selectmode);
}
+ ale->update |= ANIM_UPDATE_DEPS;
break;
}
#endif
case ANIMTYPE_GPLAYER:
- ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode);
+ {
+ ED_gplayer_frames_select_box(ale->data, rectf.xmin, rectf.xmax, selectmode);
+ ale->update |= ANIM_UPDATE_DEPS;
break;
+ }
case ANIMTYPE_MASKDATABLOCK:
{
Mask *mask = ale->data;
MaskLayer *masklay;
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- ED_masklayer_frames_select_border(masklay, rectf.xmin, rectf.xmax, selectmode);
+ ED_masklayer_frames_select_box(masklay, rectf.xmin, rectf.xmax, selectmode);
}
break;
}
case ANIMTYPE_MASKLAYER:
- ED_masklayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode);
+ ED_masklayer_frames_select_box(ale->data, rectf.xmin, rectf.xmax, selectmode);
break;
default:
ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
@@ -299,12 +323,13 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
}
/* cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
-static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
+static int actkeys_box_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
rcti rect;
@@ -331,7 +356,7 @@ static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
selectmode = SELECT_SUBTRACT;
}
- /* selection 'mode' depends on whether borderselect region only matters on one axis */
+ /* selection 'mode' depends on whether box_select region only matters on one axis */
if (RNA_boolean_get(op->ptr, "axis_range")) {
/* mode depends on which axis of the range is larger to determine which axis to use
* - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
@@ -346,8 +371,8 @@ static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
else
mode = ACTKEYS_BORDERSEL_ALLKEYS;
- /* apply borderselect action */
- borderselect_action(&ac, rect, mode, selectmode);
+ /* apply box_select action */
+ box_select_action(&ac, rect, mode, selectmode);
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -355,18 +380,18 @@ static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void ACTION_OT_select_border(wmOperatorType *ot)
+void ACTION_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "ACTION_OT_select_border";
+ ot->name = "Box Select";
+ ot->idname = "ACTION_OT_select_box";
ot->description = "Select all keyframes within the specified region";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = actkeys_borderselect_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = actkeys_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_action_active;
@@ -374,7 +399,7 @@ void ACTION_OT_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
}
@@ -480,6 +505,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
case ANIMTYPE_GPLAYER:
{
ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
+ ale->update |= ANIM_UPDATE_DEPS;
break;
}
case ANIMTYPE_MASKDATABLOCK:
@@ -507,6 +533,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view,
}
/* cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -546,7 +573,7 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
BLI_rctf_rcti_copy(&rect_fl, &rect);
- /* apply borderselect action */
+ /* apply box_select action */
region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
MEM_freeN((void *)data_lasso.mcords);
@@ -693,10 +720,11 @@ static void markers_selectkeys_between(bAnimContext *ac)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gplayer_frames_select_border(ale->data, min, max, SELECT_ADD);
+ ED_gplayer_frames_select_box(ale->data, min, max, SELECT_ADD);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_masklayer_frames_select_border(ale->data, min, max, SELECT_ADD);
+ ED_masklayer_frames_select_box(ale->data, min, max, SELECT_ADD);
}
else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
@@ -704,6 +732,7 @@ static void markers_selectkeys_between(bAnimContext *ac)
}
/* Cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -783,17 +812,23 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
ked.f1 = ce->cfra;
/* select elements with frame number matching cfraelem */
- if (ale->type == ANIMTYPE_GPLAYER)
+ if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->data, ce->cfra, SELECT_ADD);
- else if (ale->type == ANIMTYPE_MASKLAYER)
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->data, ce->cfra, SELECT_ADD);
- else
+ }
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
}
}
/* free elements */
BLI_freelistN(&ked.list);
+
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -1068,12 +1103,16 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
- else if (ale->type == ANIMTYPE_GPLAYER)
- ED_gplayer_frames_select_border(ale->data, ked.f1, ked.f2, select_mode);
- else if (ale->type == ANIMTYPE_MASKLAYER)
- ED_masklayer_frames_select_border(ale->data, ked.f1, ked.f2, select_mode);
- else
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ ED_gplayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ ED_masklayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
+ }
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
}
/* Sync marker support */
@@ -1098,6 +1137,7 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
}
/* Cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -1214,6 +1254,7 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s
/* select the nominated keyframe on the given frame */
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->data, selx, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->data, selx, select_mode);
@@ -1231,12 +1272,14 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s
for (ale = anim_data.first; ale; ale = ale->next) {
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->data, selx, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->data, selx, select_mode);
}
}
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
else {
@@ -1281,16 +1324,22 @@ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float se
ked.f1 = selx;
/* select elements with frame number matching cfra */
- if (ale->type == ANIMTYPE_GPLAYER)
+ if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->key_data, selx, select_mode);
- else if (ale->type == ANIMTYPE_MASKLAYER)
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->key_data, selx, select_mode);
- else
+ }
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
}
/* free elements */
BLI_freelistN(&ked.list);
+
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -1305,6 +1354,7 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
/* select all keyframes in this channel */
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frames(ale->data, select_mode);
+ ale->update = ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frames(ale->data, select_mode);
@@ -1322,12 +1372,14 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
for (ale = anim_data.first; ale; ale = ale->next) {
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frames(ale->data, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frames(ale->data, select_mode);
}
}
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
else {
@@ -1356,7 +1408,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
rctf rectf;
/* get dopesheet info */
- if (ac->datatype == ANIMCONT_DOPESHEET)
+ if (ELEM(ac->datatype, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE))
ads = ac->data;
/* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
@@ -1397,37 +1449,37 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
case ALE_SCE:
{
Scene *scene = (Scene *)ale->key_data;
- scene_to_keylist(ads, scene, &anim_keys, NULL);
+ scene_to_keylist(ads, scene, &anim_keys, 0);
break;
}
case ALE_OB:
{
Object *ob = (Object *)ale->key_data;
- ob_to_keylist(ads, ob, &anim_keys, NULL);
+ ob_to_keylist(ads, ob, &anim_keys, 0);
break;
}
case ALE_ACT:
{
bAction *act = (bAction *)ale->key_data;
- action_to_keylist(adt, act, &anim_keys, NULL);
+ action_to_keylist(adt, act, &anim_keys, 0);
break;
}
case ALE_FCURVE:
{
FCurve *fcu = (FCurve *)ale->key_data;
- fcurve_to_keylist(adt, fcu, &anim_keys, NULL);
+ fcurve_to_keylist(adt, fcu, &anim_keys, 0);
break;
}
}
}
else if (ale->type == ANIMTYPE_SUMMARY) {
/* dopesheet summary covers everything */
- summary_to_keylist(ac, &anim_keys, NULL);
+ summary_to_keylist(ac, &anim_keys, 0);
}
else if (ale->type == ANIMTYPE_GROUP) {
// TODO: why don't we just give groups key_data too?
bActionGroup *agrp = (bActionGroup *)ale->data;
- agroup_to_keylist(adt, agrp, &anim_keys, NULL);
+ agroup_to_keylist(adt, agrp, &anim_keys, 0);
}
else if (ale->type == ANIMTYPE_GPLAYER) {
// TODO: why don't we just give gplayers key_data too?
@@ -1460,6 +1512,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
/* remove active channel from list of channels for separate treatment (since it's needed later on) */
BLI_remlink(&anim_data, ale);
+ ale->next = ale->prev = NULL;
/* cleanup temporary lists */
BLI_dlrbTree_free(&anim_keys);
@@ -1477,7 +1530,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
deselect_action_keys(ac, 0, SELECT_SUBTRACT);
/* highlight channel clicked on */
- if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
+ if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
/* deselect all other channels first */
ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
@@ -1544,6 +1597,12 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
}
}
+ /* flush tagged updates
+ * NOTE: We temporarily add this channel back to the list so that this can happen
+ */
+ anim_data.first = anim_data.last = ale;
+ ANIM_animdata_update(ac, &anim_data);
+
/* free this channel */
MEM_freeN(ale);
}
@@ -1590,7 +1649,7 @@ void ACTION_OT_clickselect(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Mouse Select Keys";
+ ot->name = "Select Keyframes";
ot->idname = "ACTION_OT_clickselect";
ot->description = "Select keyframes by clicking on them";
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index a2fe129c819..15587a5f39d 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -33,7 +33,8 @@
#include <stdio.h>
#include "DNA_action_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -45,10 +46,15 @@
#include "BKE_context.h"
#include "BKE_screen.h"
-#include "BIF_gl.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+
+#include "BIF_gl.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -59,6 +65,7 @@
#include "ED_markers.h"
#include "action_intern.h" /* own include */
+#include "GPU_framebuffer.h"
/* ******************** manage regions ********************* */
@@ -88,10 +95,8 @@ ARegion *action_has_buttons_region(ScrArea *sa)
/* ******************** default callbacks for action space ***************** */
-static SpaceLink *action_new(const bContext *C)
+static SpaceLink *action_new(const ScrArea *sa, const Scene *scene)
{
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
SpaceAction *saction;
ARegion *ar;
@@ -100,15 +105,22 @@ static SpaceLink *action_new(const bContext *C)
saction->autosnap = SACTSNAP_FRAME;
saction->mode = SACTCONT_DOPESHEET;
+ saction->mode_prev = SACTCONT_DOPESHEET;
saction->ads.filterflag |= ADS_FILTER_SUMMARY;
+ /* enable all cache display */
+ saction->cache_display |= TIME_CACHE_DISPLAY;
+ saction->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
+ saction->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
+ saction->cache_display |= TIME_CACHE_RIGIDBODY;
+
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for action");
BLI_addtail(&saction->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* channel list region */
ar = MEM_callocN(sizeof(ARegion), "channel region for action");
@@ -170,6 +182,7 @@ static void action_free(SpaceLink *UNUSED(sl))
static void action_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
{
SpaceAction *saction = sa->spacedata.first;
+
saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
}
@@ -202,15 +215,19 @@ static void action_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceAction *saction = CTX_wm_space_action(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obact = CTX_data_active_object(C);
bAnimContext ac;
View2D *v2d = &ar->v2d;
View2DGrid *grid;
View2DScrollers *scrollers;
- short unit = 0, flag = 0;
+ short marker_flag = 0;
+ short cfra_flag = 0;
+ short unit = 0;
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -222,21 +239,28 @@ static void action_main_region_draw(const bContext *C, ARegion *ar)
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
+ /* start and end frame */
+ ANIM_draw_framerange(scene, v2d);
+
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
draw_channel_strips(&ac, saction, ar);
}
/* current frame */
- if (saction->flag & SACTION_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS;
- if ((saction->flag & SACTION_NODRAWCFRANUM) == 0) flag |= DRAWCFRA_SHOW_NUMBOX;
- ANIM_draw_cfra(C, v2d, flag);
+ if (saction->flag & SACTION_DRAWTIME) cfra_flag |= DRAWCFRA_UNIT_SECONDS;
+ ANIM_draw_cfra(C, v2d, cfra_flag);
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
- flag = ((ac.markers && (ac.markers != &ac.scene->markers)) ? DRAW_MARKERS_LOCAL : 0) | DRAW_MARKERS_MARGIN;
- ED_markers_draw(C, flag);
+ marker_flag = ((ac.markers && (ac.markers != &ac.scene->markers)) ? DRAW_MARKERS_LOCAL : 0) | DRAW_MARKERS_MARGIN;
+ ED_markers_draw(C, marker_flag);
+
+ /* caches */
+ if (saction->mode == SACTCONT_TIMELINE) {
+ timeline_draw_cache(saction, obact, scene);
+ }
/* preview range */
UI_view2d_view_ortho(v2d);
@@ -250,9 +274,15 @@ static void action_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
+
+ /* draw current frame number-indicator on top of scrollers */
+ if ((saction->flag & SACTION_NODRAWCFRANUM) == 0) {
+ UI_view2d_view_orthoSpecial(ar, v2d, 1);
+ ANIM_draw_cfra_number(C, v2d, cfra_flag);
+ }
}
/* add handlers, stuff you only do once or on area/region changes */
@@ -281,7 +311,7 @@ static void action_channel_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -308,7 +338,9 @@ static void action_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-static void action_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void action_channel_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -351,7 +383,55 @@ static void action_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(
}
}
-static void action_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void saction_channel_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* All dopesheet filter settings, etc. affect the drawing of this editor,
+ * also same applies for all animation-related datatypes that may appear here,
+ * so just whitelist the entire structs for updates
+ */
+ {
+ wmMsgParams_RNA msg_key_params = {{{0}}};
+ StructRNA *type_array[] = {
+ &RNA_DopeSheet, /* dopesheet filters */
+
+ &RNA_ActionGroup, /* channel groups */
+
+ &RNA_FCurve, /* F-Curve */
+ &RNA_Keyframe,
+ &RNA_FCurveSample,
+
+ &RNA_GreasePencil, /* Grease Pencil */
+ &RNA_GPencilLayer,
+ &RNA_GPencilFrame,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
+ msg_key_params.ptr.type = type_array[i];
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &msg_key_params,
+ &msg_sub_value_region_tag_redraw,
+ __func__);
+ }
+ }
+}
+
+static void action_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -363,6 +443,7 @@ static void action_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
case ND_RENDER_OPTIONS:
case ND_OB_ACTIVE:
case ND_FRAME:
+ case ND_FRAME_RANGE:
case ND_MARKERS:
ED_region_tag_redraw(ar);
break;
@@ -391,7 +472,11 @@ static void action_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
if (wmn->action == NA_RENAME)
ED_region_tag_redraw(ar);
break;
-
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
default:
if (wmn->data == ND_KEYS)
ED_region_tag_redraw(ar);
@@ -399,8 +484,52 @@ static void action_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
}
}
+static void saction_main_region_message_subscribe(
+ const struct bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* Timeline depends on scene properties. */
+ {
+ bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
+ extern PropertyRNA rna_Scene_frame_start;
+ extern PropertyRNA rna_Scene_frame_end;
+ extern PropertyRNA rna_Scene_frame_preview_start;
+ extern PropertyRNA rna_Scene_frame_preview_end;
+ extern PropertyRNA rna_Scene_use_preview_range;
+ extern PropertyRNA rna_Scene_frame_current;
+ const PropertyRNA *props[] = {
+ use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
+ use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
+ &rna_Scene_use_preview_range,
+ &rna_Scene_frame_current,
+ };
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&scene->id, &idptr);
+
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
+ }
+ }
+
+ /* Now run the general "channels region" one - since channels and main should be in sync */
+ saction_channel_region_message_subscribe(C, workspace, scene, screen, sa, ar, mbus);
+}
+
/* editor level listener */
-static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void action_listener(
+ wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
@@ -440,16 +569,43 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
break;
case NC_SCENE:
- switch (wmn->data) {
- case ND_OB_ACTIVE: /* selection changed, so force refresh to flush (needs flag set to do syncing) */
- case ND_OB_SELECT:
- saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
- ED_area_tag_refresh(sa);
- break;
+ if (saction->mode == SACTCONT_TIMELINE) {
+ switch (wmn->data) {
+ case ND_RENDER_RESULT:
+ ED_area_tag_redraw(sa);
+ break;
+ case ND_OB_ACTIVE:
+ case ND_FRAME:
+ ED_area_tag_refresh(sa);
+ break;
+ case ND_FRAME_RANGE:
+ {
+ ARegion *ar;
+ Scene *scene = wmn->reference;
+
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ ar->v2d.tot.xmin = (float)(SFRA - 4);
+ ar->v2d.tot.xmax = (float)(EFRA + 4);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ else {
+ switch (wmn->data) {
+ case ND_OB_ACTIVE: /* selection changed, so force refresh to flush (needs flag set to do syncing) */
+ case ND_OB_SELECT:
+ saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
+ ED_area_tag_refresh(sa);
+ break;
- default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
- break;
+ default: /* just redrawing the view will do */
+ ED_area_tag_redraw(sa);
+ break;
+ }
}
break;
case NC_OBJECT:
@@ -462,6 +618,15 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case ND_TRANSFORM:
/* moving object shouldn't need to redraw action */
break;
+ case ND_POINTCACHE:
+ case ND_MODIFIER:
+ case ND_PARTICLE:
+ /* only needed in timeline mode */
+ if (saction->mode == SACTCONT_TIMELINE) {
+ ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(sa);
+ }
+ break;
default: /* just redrawing the view will do */
ED_area_tag_redraw(sa);
break;
@@ -492,6 +657,9 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case ND_SPACE_DOPESHEET:
ED_area_tag_redraw(sa);
break;
+ case ND_SPACE_TIME:
+ ED_area_tag_redraw(sa);
+ break;
case ND_SPACE_CHANGED:
saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
ED_area_tag_refresh(sa);
@@ -504,20 +672,49 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
ED_area_tag_refresh(sa);
}
break;
+ case NC_WM:
+ switch (wmn->data) {
+ case ND_FILEREAD:
+ ED_area_tag_refresh(sa);
+ break;
+ }
+ break;
}
}
-static void action_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void action_header_region_listener(
+ wmWindow *UNUSED(win), ScrArea *sa, ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
- // SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
/* context changes */
switch (wmn->category) {
- case NC_SCENE:
- switch (wmn->data) {
- case ND_OB_ACTIVE:
+ case NC_SCREEN:
+ if (saction->mode == SACTCONT_TIMELINE) {
+ if (wmn->data == ND_ANIMPLAY)
ED_region_tag_redraw(ar);
- break;
+ }
+ break;
+ case NC_SCENE:
+ if (saction->mode == SACTCONT_TIMELINE) {
+ switch (wmn->data) {
+ case ND_RENDER_RESULT:
+ case ND_OB_SELECT:
+ case ND_FRAME:
+ case ND_FRAME_RANGE:
+ case ND_KEYINGSET:
+ case ND_RENDER_OPTIONS:
+ ED_region_tag_redraw(ar);
+ break;
+ }
+ }
+ else {
+ switch (wmn->data) {
+ case ND_OB_ACTIVE:
+ ED_region_tag_redraw(ar);
+ break;
+ }
}
break;
case NC_ID:
@@ -556,10 +753,12 @@ static void action_buttons_area_init(wmWindowManager *wm, ARegion *ar)
static void action_buttons_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
-static void action_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void action_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -629,7 +828,7 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I
}
if ((ID *)sact->ads.filter_grp == old_id) {
- sact->ads.filter_grp = (Group *)new_id;
+ sact->ads.filter_grp = (Collection *)new_id;
}
if ((ID *)sact->ads.source == old_id) {
sact->ads.source = new_id;
@@ -637,6 +836,37 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I
}
+/**
+ * \note Used for splitting out a subset of modes is more involved,
+ * The previous non-timeline mode is stored so switching back to the
+ * dope-sheet doesn't always reset the sub-mode.
+ */
+static int action_space_subtype_get(ScrArea *sa)
+{
+ SpaceAction *sact = sa->spacedata.first;
+ return sact->mode == SACTCONT_TIMELINE ? SACTCONT_TIMELINE : SACTCONT_DOPESHEET;
+}
+
+static void action_space_subtype_set(ScrArea *sa, int value)
+{
+ SpaceAction *sact = sa->spacedata.first;
+ if (value == SACTCONT_TIMELINE) {
+ if (sact->mode != SACTCONT_TIMELINE) {
+ sact->mode_prev = sact->mode;
+ }
+ sact->mode = value;
+ }
+ else {
+ sact->mode = sact->mode_prev;
+ }
+}
+
+static void action_space_subtype_item_extend(
+ bContext *UNUSED(C), EnumPropertyItem **item, int *totitem)
+{
+ RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items);
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_action(void)
{
@@ -655,6 +885,9 @@ void ED_spacetype_action(void)
st->listener = action_listener;
st->refresh = action_refresh;
st->id_remap = action_id_remap;
+ st->space_subtype_item_extend = action_space_subtype_item_extend;
+ st->space_subtype_get = action_space_subtype_get;
+ st->space_subtype_set = action_space_subtype_set;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype action region");
@@ -662,6 +895,7 @@ void ED_spacetype_action(void)
art->init = action_main_region_init;
art->draw = action_main_region_draw;
art->listener = action_main_region_listener;
+ art->message_subscribe = saction_main_region_message_subscribe;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
@@ -687,6 +921,7 @@ void ED_spacetype_action(void)
art->init = action_channel_region_init;
art->draw = action_channel_region_draw;
art->listener = action_channel_region_listener;
+ art->message_subscribe = saction_channel_region_message_subscribe;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 45b0fb36ecc..afaa3325f6b 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -55,6 +55,7 @@
#include "ED_paint.h"
#include "ED_physics.h"
#include "ED_render.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_space_api.h"
@@ -66,6 +67,8 @@
#include "ED_clip.h"
#include "ED_mask.h"
#include "ED_sequencer.h"
+#include "ED_gizmo_library.h"
+#include "ED_transform.h"
#include "io_ops.h"
@@ -80,7 +83,6 @@ void ED_spacetypes_init(void)
/* create space types */
ED_spacetype_outliner();
- ED_spacetype_time();
ED_spacetype_view3d();
ED_spacetype_ipo();
ED_spacetype_image();
@@ -93,13 +95,16 @@ void ED_spacetypes_init(void)
ED_spacetype_script();
ED_spacetype_text();
ED_spacetype_sequencer();
- ED_spacetype_logic();
ED_spacetype_console();
ED_spacetype_userpref();
ED_spacetype_clip();
+ ED_spacetype_statusbar();
+ ED_spacetype_topbar();
// ...
/* register operator types for screen and all spaces */
+ ED_operatortypes_workspace();
+ ED_operatortypes_scene();
ED_operatortypes_screen();
ED_operatortypes_anim();
ED_operatortypes_animchannels();
@@ -117,22 +122,41 @@ void ED_spacetypes_init(void)
ED_operatortypes_metaball();
ED_operatortypes_sound();
ED_operatortypes_render();
- ED_operatortypes_logic();
ED_operatortypes_mask();
ED_operatortypes_io();
ED_operatortypes_view2d();
ED_operatortypes_ui();
- /* register operators */
+ ED_screen_user_menu_register();
+
+ /* gizmo types */
+ ED_gizmotypes_button_2d();
+ ED_gizmotypes_dial_3d();
+ ED_gizmotypes_move_3d();
+ ED_gizmotypes_arrow_2d();
+ ED_gizmotypes_arrow_3d();
+ ED_gizmotypes_preselect_3d();
+ ED_gizmotypes_primitive_3d();
+ ED_gizmotypes_blank_3d();
+ ED_gizmotypes_cage_2d();
+ ED_gizmotypes_cage_3d();
+ ED_gizmotypes_value_2d();
+
+ /* gizmo group types */
+ ED_gizmogrouptypes_value_2d();
+
+ /* register types for operators and gizmos */
spacetypes = BKE_spacetypes_list();
for (type = spacetypes->first; type; type = type->next) {
- if (type->operatortypes)
+ /* init gizmo types first, operator-types need them */
+ if (type->gizmos) {
+ type->gizmos();
+ }
+ if (type->operatortypes) {
type->operatortypes();
+ }
}
-
- /* register internal render callbacks */
- ED_render_internal_init();
}
void ED_spacemacros_init(void)
@@ -193,6 +217,8 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf)
ED_keymap_view2d(keyconf);
ED_keymap_ui(keyconf);
+ ED_keymap_transform(keyconf);
+
spacetypes = BKE_spacetypes_list();
for (stype = spacetypes->first; stype; stype = stype->next) {
if (stype->keymap)
@@ -243,18 +269,12 @@ void ED_region_draw_cb_exit(ARegionType *art, void *handle)
}
}
-void *ED_region_draw_cb_customdata(void *handle)
-{
- return ((RegionDrawCB *)handle)->customdata;
-}
-
void ED_region_draw_cb_draw(const bContext *C, ARegion *ar, int type)
{
RegionDrawCB *rdc;
for (rdc = ar->type->drawcalls.first; rdc; rdc = rdc->next) {
if (rdc->type == type) {
- UI_reinit_gl_state();
rdc->draw(C, ar, rdc->customdata);
}
}
@@ -267,7 +287,7 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *ar, int type)
void ED_spacetype_xxx(void);
/* allocate and init some vars */
-static SpaceLink *xxx_new(const bContext *UNUSED(C))
+static SpaceLink *xxx_new(const ScrArea *UNUSED(sa), const Scene *UNUSED(scene))
{
return NULL;
}
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index f5e0ccb60c7..151959a916e 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
#include "DNA_armature_types.h"
+#include "DNA_collection_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -46,9 +47,11 @@
#include "DNA_world_types.h"
#include "DNA_brush_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_windowmanager_types.h"
#include "BKE_context.h"
#include "BKE_action.h"
+#include "BKE_layer.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_paint.h"
@@ -67,6 +70,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "WM_api.h"
+
#include "buttons_intern.h" // own include
static int set_pointer_type(ButsContextPath *path, bContextDataResult *result, StructRNA *type)
@@ -111,6 +116,29 @@ static int buttons_context_path_scene(ButsContextPath *path)
return RNA_struct_is_a(ptr->type, &RNA_Scene);
}
+static int buttons_context_path_view_layer(ButsContextPath *path, wmWindow *win)
+{
+ PointerRNA *ptr = &path->ptr[path->len - 1];
+
+ /* View Layer may have already been resolved in a previous call (e.g. in buttons_context_path_linestyle). */
+ if (RNA_struct_is_a(ptr->type, &RNA_ViewLayer)) {
+ return 1;
+ }
+
+ if (buttons_context_path_scene(path)) {
+ Scene *scene = path->ptr[path->len - 1].data;
+ ViewLayer *view_layer = (win->scene == scene) ?
+ WM_window_get_active_view_layer(win) :
+ BKE_view_layer_default_view(scene);
+
+ RNA_pointer_create(&scene->id, &RNA_ViewLayer, view_layer, &path->ptr[path->len]);
+ path->len++;
+ return 1;
+ }
+
+ return 0;
+}
+
/* note: this function can return 1 without adding a world to the path
* so the buttons stay visible, but be sure to check the ID type if a ID_WO */
static int buttons_context_path_world(ButsContextPath *path)
@@ -142,9 +170,8 @@ static int buttons_context_path_world(ButsContextPath *path)
return 0;
}
-static int buttons_context_path_linestyle(ButsContextPath *path)
+static int buttons_context_path_linestyle(ButsContextPath *path, wmWindow *window)
{
- Scene *scene;
FreestyleLineStyle *linestyle;
PointerRNA *ptr = &path->ptr[path->len - 1];
@@ -152,10 +179,10 @@ static int buttons_context_path_linestyle(ButsContextPath *path)
if (RNA_struct_is_a(ptr->type, &RNA_FreestyleLineStyle)) {
return 1;
}
- /* if we have a scene, use the lineset's linestyle */
- else if (buttons_context_path_scene(path)) {
- scene = path->ptr[path->len - 1].data;
- linestyle = BKE_linestyle_active_from_scene(scene);
+ /* if we have a view layer, use the lineset's linestyle */
+ else if (buttons_context_path_view_layer(path, window)) {
+ ViewLayer *view_layer = path->ptr[path->len - 1].data;
+ linestyle = BKE_linestyle_active_from_view_layer(view_layer);
if (linestyle) {
RNA_id_pointer_create(&linestyle->id, &path->ptr[path->len]);
path->len++;
@@ -169,25 +196,24 @@ static int buttons_context_path_linestyle(ButsContextPath *path)
static int buttons_context_path_object(ButsContextPath *path)
{
- Scene *scene;
- Object *ob;
PointerRNA *ptr = &path->ptr[path->len - 1];
/* if we already have a (pinned) object, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_Object)) {
return 1;
}
- /* if we have a scene, use the scene's active object */
- else if (buttons_context_path_scene(path)) {
- scene = path->ptr[path->len - 1].data;
- ob = (scene->basact) ? scene->basact->object : NULL;
+ if (!RNA_struct_is_a(ptr->type, &RNA_ViewLayer)) {
+ return 0;
+ }
- if (ob) {
- RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
- path->len++;
+ ViewLayer *view_layer = ptr->data;
+ Object *ob = (view_layer->basact) ? view_layer->basact->object : NULL;
- return 1;
- }
+ if (ob) {
+ RNA_id_pointer_create(&ob->id, &path->ptr[path->len]);
+ path->len++;
+
+ return 1;
}
/* no path to a object possible */
@@ -206,8 +232,10 @@ static int buttons_context_path_data(ButsContextPath *path, int type)
else if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_Camera) && (type == -1 || type == OB_CAMERA)) return 1;
- else if (RNA_struct_is_a(ptr->type, &RNA_Lamp) && (type == -1 || type == OB_LAMP)) return 1;
+ else if (RNA_struct_is_a(ptr->type, &RNA_Light) && (type == -1 || type == OB_LAMP)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) return 1;
+ else if (RNA_struct_is_a(ptr->type, &RNA_LightProbe) && (type == -1 || type == OB_LIGHTPROBE)) return 1;
+ else if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (type == -1 || type == OB_GPENCIL)) return 1;
/* try to get an object in the path, no pinning supported here */
else if (buttons_context_path_object(path)) {
ob = path->ptr[path->len - 1].data;
@@ -231,14 +259,28 @@ static int buttons_context_path_modifier(ButsContextPath *path)
if (buttons_context_path_object(path)) {
ob = path->ptr[path->len - 1].data;
- if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
+ if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE, OB_GPENCIL))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int buttons_context_path_shaderfx(ButsContextPath *path)
+{
+ Object *ob;
+
+ if (buttons_context_path_object(path)) {
+ ob = path->ptr[path->len - 1].data;
+
+ if (ob && ELEM(ob->type, OB_GPENCIL))
return 1;
}
return 0;
}
-static int buttons_context_path_material(ButsContextPath *path, bool for_texture, bool new_shading)
+static int buttons_context_path_material(ButsContextPath *path)
{
Object *ob;
PointerRNA *ptr = &path->ptr[path->len - 1];
@@ -256,18 +298,6 @@ static int buttons_context_path_material(ButsContextPath *path, bool for_texture
ma = give_current_material(ob, ob->actcol);
RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
path->len++;
-
- if (for_texture && give_current_material_texture_node(ma))
- return 1;
-
- if (!new_shading) {
- /* Only try to get mat from node in case of old shading system (see T40331). */
- ma = give_node_material(ma);
- if (ma) {
- RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
- path->len++;
- }
- }
return 1;
}
}
@@ -367,7 +397,7 @@ static int buttons_context_path_particle(ButsContextPath *path)
return 0;
}
-static int buttons_context_path_brush(ButsContextPath *path)
+static int buttons_context_path_brush(const bContext *C, ButsContextPath *path)
{
Scene *scene;
Brush *br = NULL;
@@ -381,8 +411,11 @@ static int buttons_context_path_brush(ButsContextPath *path)
else if (buttons_context_path_scene(path)) {
scene = path->ptr[path->len - 1].data;
- if (scene)
- br = BKE_paint_brush(BKE_paint_get_active(scene));
+ if (scene) {
+ wmWindow *window = CTX_wm_window(C);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(window);
+ br = BKE_paint_brush(BKE_paint_get_active(scene, view_layer));
+ }
if (br) {
RNA_id_pointer_create((ID *)br, &path->ptr[path->len]);
@@ -396,141 +429,47 @@ static int buttons_context_path_brush(ButsContextPath *path)
return 0;
}
-static int buttons_context_path_texture(ButsContextPath *path, ButsContextTexture *ct)
+static int buttons_context_path_texture(const bContext *C, ButsContextPath *path, ButsContextTexture *ct)
{
- if (ct) {
- /* new shading system */
- PointerRNA *ptr = &path->ptr[path->len - 1];
- ID *id;
-
- /* if we already have a (pinned) texture, we're done */
- if (RNA_struct_is_a(ptr->type, &RNA_Texture))
- return 1;
-
- if (!ct->user)
- return 0;
-
- id = ct->user->id;
-
- if (id) {
- if (GS(id->name) == ID_BR)
- buttons_context_path_brush(path);
- else if (GS(id->name) == ID_MA)
- buttons_context_path_material(path, false, true);
- else if (GS(id->name) == ID_WO)
- buttons_context_path_world(path);
- else if (GS(id->name) == ID_LA)
- buttons_context_path_data(path, OB_LAMP);
- else if (GS(id->name) == ID_PA)
- buttons_context_path_particle(path);
- else if (GS(id->name) == ID_OB)
- buttons_context_path_object(path);
- else if (GS(id->name) == ID_LS)
- buttons_context_path_linestyle(path);
- }
+ PointerRNA *ptr = &path->ptr[path->len - 1];
+ ID *id;
- if (ct->texture) {
- RNA_id_pointer_create(&ct->texture->id, &path->ptr[path->len]);
- path->len++;
- }
+ if (!ct)
+ return 0;
+ /* if we already have a (pinned) texture, we're done */
+ if (RNA_struct_is_a(ptr->type, &RNA_Texture))
return 1;
- }
- else {
- /* old shading system */
- Material *ma;
- Lamp *la;
- World *wo;
- ParticleSystem *psys;
- FreestyleLineStyle *ls;
- Tex *tex;
- PointerRNA *ptr = &path->ptr[path->len - 1];
-
- /* if we already have a (pinned) texture, we're done */
- if (RNA_struct_is_a(ptr->type, &RNA_Texture)) {
- return 1;
- }
- /* try world */
- else if ((path->tex_ctx == SB_TEXC_WORLD) && buttons_context_path_world(path)) {
- wo = path->ptr[path->len - 1].data;
-
- if (wo && GS(wo->id.name) == ID_WO) {
- tex = give_current_world_texture(wo);
-
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
- }
- }
- /* try particles */
- else if ((path->tex_ctx == SB_TEXC_PARTICLES) && buttons_context_path_particle(path)) {
- if (path->ptr[path->len - 1].type == &RNA_ParticleSettings) {
- ParticleSettings *part = path->ptr[path->len - 1].data;
-
- tex = give_current_particle_texture(part);
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
- }
- else {
- psys = path->ptr[path->len - 1].data;
-
- if (psys && psys->part && GS(psys->part->id.name) == ID_PA) {
- tex = give_current_particle_texture(psys->part);
-
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
- }
- }
- }
- /* try material */
- else if ((path->tex_ctx == SB_TEXC_MATERIAL) && buttons_context_path_material(path, true, false)) {
- ma = path->ptr[path->len - 1].data;
- if (ma) {
- tex = give_current_material_texture(ma);
-
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
- }
- }
- /* try lamp */
- else if ((path->tex_ctx == SB_TEXC_LAMP) && buttons_context_path_data(path, OB_LAMP)) {
- la = path->ptr[path->len - 1].data;
-
- if (la) {
- tex = give_current_lamp_texture(la);
+ if (!ct->user)
+ return 0;
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
- }
- }
- /* try linestyle */
- else if ((path->tex_ctx == SB_TEXC_LINESTYLE) && buttons_context_path_linestyle(path)) {
- ls = path->ptr[path->len - 1].data;
+ id = ct->user->id;
- if (ls) {
- tex = give_current_linestyle_texture(ls);
+ if (id) {
+ if (GS(id->name) == ID_BR)
+ buttons_context_path_brush(C, path);
+ else if (GS(id->name) == ID_PA)
+ buttons_context_path_particle(path);
+ else if (GS(id->name) == ID_OB)
+ buttons_context_path_object(path);
+ else if (GS(id->name) == ID_LS)
+ buttons_context_path_linestyle(path, CTX_wm_window(C));
+ }
- RNA_id_pointer_create(&tex->id, &path->ptr[path->len]);
- path->len++;
- return 1;
- }
- }
+ if (ct->texture) {
+ RNA_id_pointer_create(&ct->texture->id, &path->ptr[path->len]);
+ path->len++;
}
- /* no path to a texture possible */
- return 0;
+ return 1;
}
#ifdef WITH_FREESTYLE
-static bool buttons_context_linestyle_pinnable(const bContext *C)
+static bool buttons_context_linestyle_pinnable(const bContext *C, ViewLayer *view_layer)
{
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *actsrl;
+ wmWindow *window = CTX_wm_window(C);
+ Scene *scene = WM_window_get_active_scene(window);
FreestyleConfig *config;
SpaceButs *sbuts;
@@ -539,8 +478,7 @@ static bool buttons_context_linestyle_pinnable(const bContext *C)
return false;
}
/* if Freestyle is not in the Parameter Editor mode */
- actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- config = &actsrl->freestyleConfig;
+ config = &view_layer->freestyle_config;
if (config->mode != FREESTYLE_CONTROL_EDITOR_MODE) {
return false;
}
@@ -555,27 +493,35 @@ static bool buttons_context_linestyle_pinnable(const bContext *C)
static int buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
{
+ /* Note we don't use CTX_data here, instead we get it from the window.
+ * Otherwise there is a loop reading the context that we are setting. */
SpaceButs *sbuts = CTX_wm_space_buts(C);
+ wmWindow *window = CTX_wm_window(C);
+ Scene *scene = WM_window_get_active_scene(window);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(window);
+ Object *ob = OBACT(view_layer);
ID *id;
int found;
memset(path, 0, sizeof(*path));
path->flag = flag;
- path->tex_ctx = sbuts->texture_context;
- /* if some ID datablock is pinned, set the root pointer */
+ /* If some ID datablock is pinned, set the root pointer. */
if (sbuts->pinid) {
id = sbuts->pinid;
RNA_id_pointer_create(id, &path->ptr[0]);
path->len++;
}
-
- /* no pinned root, use scene as root */
- if (path->len == 0) {
- id = (ID *)CTX_data_scene(C);
- RNA_id_pointer_create(id, &path->ptr[0]);
+ /* No pinned root, use scene as initial root. */
+ else if (mainb != BCONTEXT_TOOL) {
+ RNA_id_pointer_create(&scene->id, &path->ptr[0]);
path->len++;
+
+ if (!ELEM(mainb, BCONTEXT_SCENE, BCONTEXT_RENDER, BCONTEXT_OUTPUT, BCONTEXT_VIEW_LAYER, BCONTEXT_WORLD)) {
+ RNA_pointer_create(NULL, &RNA_ViewLayer, view_layer, &path->ptr[path->len]);
+ path->len++;
+ }
}
/* now for each buttons context type, we try to construct a path,
@@ -583,22 +529,26 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
switch (mainb) {
case BCONTEXT_SCENE:
case BCONTEXT_RENDER:
+ case BCONTEXT_OUTPUT:
found = buttons_context_path_scene(path);
break;
- case BCONTEXT_RENDER_LAYER:
+ case BCONTEXT_VIEW_LAYER:
#ifdef WITH_FREESTYLE
- if (buttons_context_linestyle_pinnable(C)) {
- found = buttons_context_path_linestyle(path);
+ if (buttons_context_linestyle_pinnable(C, view_layer)) {
+ found = buttons_context_path_linestyle(path, window);
if (found) {
break;
}
}
#endif
- found = buttons_context_path_scene(path);
+ found = buttons_context_path_view_layer(path, window);
break;
case BCONTEXT_WORLD:
found = buttons_context_path_world(path);
break;
+ case BCONTEXT_TOOL:
+ found = true;
+ break;
case BCONTEXT_OBJECT:
case BCONTEXT_PHYSICS:
case BCONTEXT_CONSTRAINT:
@@ -607,6 +557,9 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
case BCONTEXT_MODIFIER:
found = buttons_context_path_modifier(path);
break;
+ case BCONTEXT_SHADERFX:
+ found = buttons_context_path_shaderfx(path);
+ break;
case BCONTEXT_DATA:
found = buttons_context_path_data(path, -1);
break;
@@ -614,10 +567,17 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
found = buttons_context_path_particle(path);
break;
case BCONTEXT_MATERIAL:
- found = buttons_context_path_material(path, false, (sbuts->texuser != NULL));
+ /* NOTE: Grease Pencil materials use different panels... */
+ if (ob && ob->type == OB_GPENCIL) {
+ /* XXX: Why path_data? */
+ found = buttons_context_path_data(path, -1);
+ }
+ else {
+ found = buttons_context_path_material(path);
+ }
break;
case BCONTEXT_TEXTURE:
- found = buttons_context_path_texture(path, sbuts->texuser);
+ found = buttons_context_path_texture(C, path, sbuts->texuser);
break;
case BCONTEXT_BONE:
found = buttons_context_path_bone(path);
@@ -637,7 +597,9 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
static int buttons_shading_context(const bContext *C, int mainb)
{
- Object *ob = CTX_data_active_object(C);
+ wmWindow *window = CTX_wm_window(C);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(window);
+ Object *ob = OBACT(view_layer);
if (ELEM(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
return 1;
@@ -649,7 +611,9 @@ static int buttons_shading_context(const bContext *C, int mainb)
static int buttons_shading_new_context(const bContext *C, int flag)
{
- Object *ob = CTX_data_active_object(C);
+ wmWindow *window = CTX_wm_window(C);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(window);
+ Object *ob = OBACT(view_layer);
if (flag & (1 << BCONTEXT_MATERIAL))
return BCONTEXT_MATERIAL;
@@ -672,7 +636,7 @@ void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
path = sbuts->path;
- /* We need to set Scene path now! Else, buttons_texture_context_compute() might not get a valid scene. */
+ /* Set scene path. */
buttons_context_path(C, path, BCONTEXT_SCENE, pflag);
buttons_texture_context_compute(C, sbuts);
@@ -687,10 +651,12 @@ void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
if (a == BCONTEXT_DATA) {
ptr = &path->ptr[path->len - 1];
- if (ptr->type)
+ if (ptr->type) {
sbuts->dataicon = RNA_struct_ui_icon(ptr->type);
- else
+ }
+ else {
sbuts->dataicon = ICON_EMPTY_DATA;
+ }
}
}
}
@@ -740,11 +706,11 @@ void buttons_context_compute(const bContext *C, SpaceButs *sbuts)
const char *buttons_context_dir[] = {
"texture_slot", "scene", "world", "object", "mesh", "armature", "lattice", "curve",
- "meta_ball", "lamp", "speaker", "camera", "material", "material_slot",
+ "meta_ball", "light", "speaker", "lightprobe", "camera", "material", "material_slot",
"texture", "texture_user", "texture_user_property", "bone", "edit_bone",
"pose_bone", "particle_system", "particle_system_editable", "particle_settings",
"cloth", "soft_body", "fluid", "smoke", "collision", "brush", "dynamic_paint",
- "line_style", NULL
+ "line_style", "collection", NULL
};
int buttons_context(const bContext *C, const char *member, bContextDataResult *result)
@@ -797,8 +763,8 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
set_pointer_type(path, result, &RNA_MetaBall);
return 1;
}
- else if (CTX_data_equals(member, "lamp")) {
- set_pointer_type(path, result, &RNA_Lamp);
+ else if (CTX_data_equals(member, "light")) {
+ set_pointer_type(path, result, &RNA_Light);
return 1;
}
else if (CTX_data_equals(member, "camera")) {
@@ -809,6 +775,10 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
set_pointer_type(path, result, &RNA_Speaker);
return 1;
}
+ else if (CTX_data_equals(member, "lightprobe")) {
+ set_pointer_type(path, result, &RNA_LightProbe);
+ return 1;
+ }
else if (CTX_data_equals(member, "material")) {
set_pointer_type(path, result, &RNA_Material);
return 1;
@@ -817,13 +787,8 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
ButsContextTexture *ct = sbuts->texuser;
if (ct) {
- /* new shading system */
CTX_data_pointer_set(result, &ct->texture->id, &RNA_Texture, ct->texture);
}
- else {
- /* old shading system */
- set_pointer_type(path, result, &RNA_Texture);
- }
return 1;
}
@@ -847,7 +812,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
ButsContextTexture *ct = sbuts->texuser;
if (!ct)
- return -1; /* old shading system (found but not available) */
+ return -1;
if (ct->user && ct->user->ptr.data) {
ButsTextureUser *user = ct->user;
@@ -860,7 +825,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
ButsContextTexture *ct = sbuts->texuser;
if (!ct)
- return -1; /* old shading system (found but not available) */
+ return -1;
if (ct->user && ct->user->ptr.data) {
ButsTextureUser *user = ct->user;
@@ -880,21 +845,6 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
return 1;
}
- else {
- /* old shading system */
- PointerRNA *ptr;
-
- if ((ptr = get_pointer_type(path, &RNA_Material))) {
- Material *ma = ptr->data;
-
- if (ma) {
- bNode *node = give_current_material_texture_node(ma);
- CTX_data_pointer_set(result, &ma->nodetree->id, &RNA_Node, node);
- }
- }
-
- return 1;
- }
}
else if (CTX_data_equals(member, "texture_slot")) {
ButsContextTexture *ct = sbuts->texuser;
@@ -910,38 +860,6 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
else if (ct) {
return 0; /* new shading system */
}
- else if ((ptr = get_pointer_type(path, &RNA_Material))) {
- Material *ma = ptr->data;
-
- /* if we have a node material, get slot from material in material node */
- if (ma && ma->use_nodes && ma->nodetree) {
- /* if there's an active texture node in the node tree,
- * then that texture is in context directly, without a texture slot */
- if (give_current_material_texture_node(ma))
- return 0;
-
- ma = give_node_material(ma);
- if (ma)
- CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
- else
- return 0;
- }
- else if (ma) {
- CTX_data_pointer_set(result, &ma->id, &RNA_MaterialTextureSlot, ma->mtex[(int)ma->texact]);
- }
- }
- else if ((ptr = get_pointer_type(path, &RNA_Lamp))) {
- Lamp *la = ptr->data;
-
- if (la)
- CTX_data_pointer_set(result, &la->id, &RNA_LampTextureSlot, la->mtex[(int)la->texact]);
- }
- else if ((ptr = get_pointer_type(path, &RNA_World))) {
- World *wo = ptr->data;
-
- if (wo)
- CTX_data_pointer_set(result, &wo->id, &RNA_WorldTextureSlot, wo->mtex[(int)wo->texact]);
- }
else if ((ptr = get_pointer_type(path, &RNA_FreestyleLineStyle))) {
FreestyleLineStyle *ls = ptr->data;
@@ -1096,6 +1014,7 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
PointerRNA *ptr;
char namebuf[128], *name;
int a, icon;
+ bool first = true;
if (!path)
return;
@@ -1103,54 +1022,95 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
row = uiLayoutRow(layout, true);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
- block = uiLayoutGetBlock(row);
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- but = uiDefIconButBitC(block, UI_BTYPE_ICON_TOGGLE, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag,
- 0, 0, 0, 0, TIP_("Follow context or keep fixed data-block displayed"));
- UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
- UI_but_func_set(but, pin_cb, NULL, NULL);
-
for (a = 0; a < path->len; a++) {
ptr = &path->ptr[a];
- if (a != 0)
- uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC);
+ /* Skip scene and view layer to save space. */
+ if ((!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_OUTPUT, BCONTEXT_SCENE, BCONTEXT_VIEW_LAYER, BCONTEXT_WORLD) && ptr->type == &RNA_Scene)) {
+ continue;
+ }
+ else if ((!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_OUTPUT, BCONTEXT_SCENE, BCONTEXT_VIEW_LAYER, BCONTEXT_WORLD) && ptr->type == &RNA_ViewLayer)) {
+ continue;
+ }
+
+ /* Add > triangle. */
+ if (!first) {
+ uiItemL(row, "", ICON_SMALL_TRI_RIGHT_VEC);
+ }
+ else {
+ first = false;
+ }
+ /* Add icon + name .*/
if (ptr->data) {
icon = RNA_struct_ui_icon(ptr->type);
name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);
if (name) {
- if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene)
- uiItemLDrag(row, ptr, "", icon); /* save some space */
- else
- uiItemLDrag(row, ptr, name, icon);
+ uiItemLDrag(row, ptr, name, icon);
if (name != namebuf)
MEM_freeN(name);
}
- else
+ else {
uiItemL(row, "", icon);
+ }
}
}
+
+ uiItemSpacer(row);
+
+ block = uiLayoutGetBlock(row);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ but = uiDefIconButBitC(block, UI_BTYPE_ICON_TOGGLE, SB_PIN_CONTEXT, 0, ICON_UNPINNED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &sbuts->flag,
+ 0, 0, 0, 0, TIP_("Follow context or keep fixed data-block displayed"));
+ UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
+ UI_but_func_set(but, pin_cb, NULL, NULL);
+}
+
+#ifdef USE_HEADER_CONTEXT_PATH
+static bool buttons_header_context_poll(const bContext *C, HeaderType *UNUSED(ht))
+#else
+static bool buttons_panel_context_poll(const bContext *C, PanelType *UNUSED(pt))
+#endif
+{
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
+ return (sbuts->mainb != BCONTEXT_TOOL);
}
-static void buttons_panel_context(const bContext *C, Panel *pa)
+#ifdef USE_HEADER_CONTEXT_PATH
+static void buttons_header_context_draw(const bContext *C, Header *ptr)
+#else
+static void buttons_panel_context_draw(const bContext *C, Panel *ptr)
+#endif
{
- buttons_context_draw(C, pa->layout);
+ buttons_context_draw(C, ptr->layout);
}
void buttons_context_register(ARegionType *art)
{
+#ifdef USE_HEADER_CONTEXT_PATH
+ HeaderType *ht;
+
+ ht = MEM_callocN(sizeof(HeaderType), "spacetype buttons context header");
+ strcpy(ht->idname, "BUTTONS_HT_context");
+ ht->space_type = SPACE_BUTS;
+ ht->region_type = art->regionid;
+ ht->poll = buttons_header_context_poll;
+ ht->draw = buttons_header_context_draw;
+ BLI_addtail(&art->headertypes, ht);
+#else
PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
strcpy(pt->idname, "BUTTONS_PT_context");
strcpy(pt->label, N_("Context")); /* XXX C panels are not available through RNA (bpy.types)! */
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = buttons_panel_context;
+ pt->poll = buttons_panel_context_poll;
+ pt->draw = buttons_panel_context_draw;
pt->flag = PNL_NO_HEADER;
BLI_addtail(&art->paneltypes, pt);
+#endif
}
ID *buttons_context_id_path(const bContext *C)
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 77623974d0a..65bcf7ef1c8 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -45,18 +45,8 @@ struct bNodeTree;
struct uiLayout;
struct wmOperatorType;
-/* buts->scaflag */
-#define BUTS_SENS_SEL 1
-#define BUTS_SENS_ACT 2
-#define BUTS_SENS_LINK 4
-#define BUTS_CONT_SEL 8
-#define BUTS_CONT_ACT 16
-#define BUTS_CONT_LINK 32
-#define BUTS_ACT_SEL 64
-#define BUTS_ACT_ACT 128
-#define BUTS_ACT_LINK 256
-#define BUTS_SENS_STATE 512
-#define BUTS_ACT_STATE 1024
+/* Display the context path in the header instead of the main window */
+#define USE_HEADER_CONTEXT_PATH
/* context data */
@@ -64,7 +54,7 @@ typedef struct ButsContextPath {
PointerRNA ptr[8];
int len;
int flag;
- int tex_ctx;
+ int collection_ctx;
} ButsContextPath;
typedef struct ButsTextureUser {
@@ -111,6 +101,6 @@ void buttons_texture_context_compute(const struct bContext *C, struct SpaceButs
/* buttons_ops.c */
void BUTTONS_OT_file_browse(struct wmOperatorType *ot);
void BUTTONS_OT_directory_browse(struct wmOperatorType *ot);
-void BUTTONS_OT_toolbox(struct wmOperatorType *ot);
+void BUTTONS_OT_context_menu(struct wmOperatorType *ot);
#endif /* __BUTTONS_INTERN_H__ */
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 47f97b8087f..473deb35aac 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -60,35 +60,33 @@
#include "buttons_intern.h" /* own include */
-/********************** toolbox operator *********************/
+/********************** context_menu operator *********************/
-static int toolbox_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+static int context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
- bScreen *sc = CTX_wm_screen(C);
- SpaceButs *sbuts = CTX_wm_space_buts(C);
- PointerRNA ptr;
- uiPopupMenu *pup;
- uiLayout *layout;
+ const ARegion *ar = CTX_wm_region(C);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Context Menu"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
- RNA_pointer_create(&sc->id, &RNA_SpaceProperties, sbuts, &ptr);
+ uiItemM(layout, "INFO_MT_area", NULL, ICON_NONE);
+ if (ar->regiontype == RGN_TYPE_NAV_BAR) {
+ ED_screens_navigation_bar_tools_menu_create(C, layout, NULL);
+ }
- pup = UI_popup_menu_begin(C, IFACE_("Align"), ICON_NONE);
- layout = UI_popup_menu_layout(pup);
- uiItemsEnumR(layout, &ptr, "align");
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
}
-void BUTTONS_OT_toolbox(wmOperatorType *ot)
+void BUTTONS_OT_context_menu(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Toolbox";
- ot->description = "Display button panel toolbox";
- ot->idname = "BUTTONS_OT_toolbox";
+ ot->name = "Context Menu";
+ ot->description = "Display properties editor context_menu";
+ ot->idname = "BUTTONS_OT_context_menu";
/* api callbacks */
- ot->invoke = toolbox_invoke;
+ ot->invoke = context_menu_invoke;
ot->poll = ED_operator_buttons_active;
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 1d9d5130f98..958b55526c3 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -41,8 +41,6 @@
#include "DNA_brush_types.h"
#include "DNA_ID.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
@@ -50,17 +48,19 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
-#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_windowmanager_types.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_linestyle.h"
-#include "BKE_material.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
+#include "BKE_workspace.h"
#ifdef WITH_FREESTYLE
# include "BKE_freestyle.h"
#endif
@@ -74,176 +74,12 @@
#include "ED_node.h"
#include "ED_screen.h"
+#include "WM_api.h"
+
#include "../interface/interface_intern.h"
#include "buttons_intern.h" // own include
-/****************** "Old Shading" Texture Context ****************/
-
-bool ED_texture_context_check_world(const bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
- return (scene && scene->world);
-}
-
-bool ED_texture_context_check_material(const bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- return (ob && (ob->totcol != 0));
-}
-
-bool ED_texture_context_check_lamp(const bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- return (ob && (ob->type == OB_LAMP));
-}
-
-bool ED_texture_context_check_particles(const bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- return (ob && ob->particlesystem.first);
-}
-
-bool ED_texture_context_check_linestyle(const bContext *C)
-{
-#ifdef WITH_FREESTYLE
- Scene *scene = CTX_data_scene(C);
- SceneRenderLayer *actsrl;
- FreestyleConfig *config;
- FreestyleLineSet *lineset;
- FreestyleLineStyle *linestyle;
-
- if (scene && (scene->r.mode & R_EDGE_FRS)) {
- actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- config = &actsrl->freestyleConfig;
- if (config->mode == FREESTYLE_CONTROL_EDITOR_MODE) {
- lineset = BKE_freestyle_lineset_get_active(config);
- if (lineset) {
- linestyle = lineset->linestyle;
- return linestyle && (linestyle->flag & LS_TEXTURE);
- }
- }
- }
-#else
- (void)C;
-#endif
- return false;
-}
-
-static void texture_context_check_modifier_foreach(void *userData, Object *UNUSED(ob), ModifierData *UNUSED(md),
- const char *UNUSED(propname))
-{
- *((bool *)userData) = true;
-}
-
-bool ED_texture_context_check_others(const bContext *C)
-{
- /* We cannot rely on sbuts->texuser here, as it is NULL when in "old" tex handling, non-OTHERS tex context. */
- Object *ob = CTX_data_active_object(C);
-
- /* object */
- if (ob) {
- /* Tex force field. */
- if (ob->pd && ob->pd->forcefield == PFIELD_TEXTURE) {
- return true;
- }
-
- /* modifiers */
- {
- bool check = false;
- modifiers_foreachTexLink(ob, texture_context_check_modifier_foreach, &check);
- if (check) {
- return true;
- }
- }
- }
-
- /* brush */
- if (BKE_paint_brush(BKE_paint_get_active_from_context(C))) {
- return true;
- }
-
- return false;
-}
-
-static void set_texture_context(const bContext *C, SpaceButs *sbuts)
-{
- Scene *scene = CTX_data_scene(C);
-
- if (BKE_scene_use_new_shading_nodes(scene)) {
- return; /* No texture context in new shading mode */
- }
-
- {
- bool valid_world = ED_texture_context_check_world(C);
- bool valid_material = ED_texture_context_check_material(C);
- bool valid_lamp = ED_texture_context_check_lamp(C);
- bool valid_particles = ED_texture_context_check_particles(C);
- bool valid_linestyle = ED_texture_context_check_linestyle(C);
- bool valid_others = ED_texture_context_check_others(C);
-
- /* this is similar to direct user action, no need to keep "better" ctxt in _prev */
- if ((sbuts->mainb == BCONTEXT_WORLD) && valid_world) {
- sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_WORLD;
- }
- else if ((sbuts->mainb == BCONTEXT_MATERIAL) && valid_material) {
- sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_MATERIAL;
- }
- else if ((sbuts->mainb == BCONTEXT_DATA) && valid_lamp) {
- sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_LAMP;
- }
- else if ((sbuts->mainb == BCONTEXT_PARTICLE) && valid_particles) {
- sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_PARTICLES;
- }
- else if ((sbuts->mainb == BCONTEXT_RENDER_LAYER) && valid_linestyle) {
- sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_LINESTYLE;
- }
- else if ((ELEM(sbuts->mainb, BCONTEXT_MODIFIER, BCONTEXT_PHYSICS)) && valid_others) {
- sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_OTHER;
- }
- /* Else, try to revive a previous "better" ctxt... */
- else if ((sbuts->texture_context_prev != sbuts->texture_context) &&
- (((sbuts->texture_context_prev == SB_TEXC_WORLD) && valid_world) ||
- ((sbuts->texture_context_prev == SB_TEXC_MATERIAL) && valid_material) ||
- ((sbuts->texture_context_prev == SB_TEXC_LAMP) && valid_lamp) ||
- ((sbuts->texture_context_prev == SB_TEXC_PARTICLES) && valid_particles) ||
- ((sbuts->texture_context_prev == SB_TEXC_LINESTYLE) && valid_linestyle) ||
- ((sbuts->texture_context_prev == SB_TEXC_OTHER) && valid_others)))
- {
- sbuts->texture_context = sbuts->texture_context_prev;
- }
- /* Else, just be sure that current context is valid! */
- else if (((sbuts->texture_context == SB_TEXC_WORLD) && !valid_world) ||
- ((sbuts->texture_context == SB_TEXC_MATERIAL) && !valid_material) ||
- ((sbuts->texture_context == SB_TEXC_LAMP) && !valid_lamp) ||
- ((sbuts->texture_context == SB_TEXC_PARTICLES) && !valid_particles) ||
- ((sbuts->texture_context == SB_TEXC_LINESTYLE) && !valid_linestyle) ||
- ((sbuts->texture_context == SB_TEXC_OTHER) && !valid_others))
- {
- /* this is default fallback, do keep "better" ctxt in _prev */
- sbuts->texture_context_prev = sbuts->texture_context;
- if (valid_material) {
- sbuts->texture_context = SB_TEXC_MATERIAL;
- }
- else if (valid_lamp) {
- sbuts->texture_context = SB_TEXC_LAMP;
- }
- else if (valid_particles) {
- sbuts->texture_context = SB_TEXC_PARTICLES;
- }
- else if (valid_linestyle) {
- sbuts->texture_context = SB_TEXC_LINESTYLE;
- }
- else if (valid_world) {
- sbuts->texture_context = SB_TEXC_WORLD;
- }
- else if (valid_others) {
- sbuts->texture_context = SB_TEXC_OTHER;
- }
- }
- }
-}
-
/************************* Texture User **************************/
static void buttons_texture_user_property_add(ListBase *users, ID *id,
@@ -317,13 +153,23 @@ static void buttons_texture_modifier_foreach(void *userData, Object *ob, Modifie
N_("Modifiers"), RNA_struct_ui_icon(ptr.type), md->name);
}
+static void buttons_texture_modifier_gpencil_foreach(void *userData, Object *ob, GpencilModifierData *md, const char *propname)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ListBase *users = userData;
+
+ RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr);
+ prop = RNA_struct_find_property(&ptr, propname);
+
+ buttons_texture_user_property_add(users, &ob->id, ptr, prop,
+ N_("Grease Pencil Modifiers"), RNA_struct_ui_icon(ptr.type), md->name);
+}
+
static void buttons_texture_users_from_context(ListBase *users, const bContext *C, SpaceButs *sbuts)
{
Scene *scene = NULL;
Object *ob = NULL;
- Material *ma = NULL;
- Lamp *la = NULL;
- World *wrld = NULL;
FreestyleLineStyle *linestyle = NULL;
Brush *brush = NULL;
ID *pinid = sbuts->pinid;
@@ -335,42 +181,31 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
scene = (Scene *)pinid;
else if (GS(pinid->name) == ID_OB)
ob = (Object *)pinid;
- else if (GS(pinid->name) == ID_LA)
- la = (Lamp *)pinid;
- else if (GS(pinid->name) == ID_WO)
- wrld = (World *)pinid;
- else if (GS(pinid->name) == ID_MA)
- ma = (Material *)pinid;
else if (GS(pinid->name) == ID_BR)
brush = (Brush *)pinid;
else if (GS(pinid->name) == ID_LS)
linestyle = (FreestyleLineStyle *)pinid;
}
- if (!scene)
+ if (!scene) {
scene = CTX_data_scene(C);
+ }
+
+ const ID_Type id_type = pinid != NULL ? GS(pinid->name) : -1;
+ if (!pinid || id_type == ID_SCE) {
+ wmWindow *win = CTX_wm_window(C);
+ ViewLayer *view_layer = (win->scene == scene) ?
+ WM_window_get_active_view_layer(win) :
+ BKE_view_layer_default_view(scene);
- if (!pinid || GS(pinid->name) == ID_SCE) {
- ob = (scene->basact) ? scene->basact->object : NULL;
- wrld = scene->world;
brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- linestyle = BKE_linestyle_active_from_scene(scene);
+ linestyle = BKE_linestyle_active_from_view_layer(view_layer);
+ ob = OBACT(view_layer);
}
- if (ob && ob->type == OB_LAMP && !la)
- la = ob->data;
- if (ob && !ma)
- ma = give_current_material(ob, ob->actcol);
-
/* fill users */
BLI_listbase_clear(users);
- if (ma && !limited_mode)
- buttons_texture_users_find_nodetree(users, &ma->id, ma->nodetree, N_("Material"));
- if (la && !limited_mode)
- buttons_texture_users_find_nodetree(users, &la->id, la->nodetree, N_("Lamp"));
- if (wrld && !limited_mode)
- buttons_texture_users_find_nodetree(users, &wrld->id, wrld->nodetree, N_("World"));
if (linestyle && !limited_mode)
buttons_texture_users_find_nodetree(users, &linestyle->id, linestyle->nodetree, N_("Line Style"));
@@ -382,6 +217,9 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
/* modifiers */
modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users);
+ /* grease pencil modifiers */
+ BKE_gpencil_modifiers_foreachTexLink(ob, buttons_texture_modifier_gpencil_foreach, users);
+
/* particle systems */
if (psys && !limited_mode) {
for (a = 0; a < MAX_MTEX; a++) {
@@ -439,21 +277,8 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
/* gather available texture users in context. runs on every draw of
* properties editor, before the buttons are created. */
ButsContextTexture *ct = sbuts->texuser;
- Scene *scene = CTX_data_scene(C);
ID *pinid = sbuts->pinid;
- set_texture_context(C, sbuts);
-
- if (!((sbuts->texture_context == SB_TEXC_OTHER) || BKE_scene_use_new_shading_nodes(scene))) {
- if (ct) {
- BLI_freelistN(&ct->users);
- MEM_freeN(ct);
- sbuts->texuser = NULL;
- }
-
- return;
- }
-
if (!ct) {
ct = MEM_callocN(sizeof(ButsContextTexture), "ButsContextTexture");
sbuts->texuser = ct;
@@ -682,7 +507,7 @@ void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, Prope
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
- but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_BUTS, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_PROPERTIES, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Show texture in texture tab"));
UI_but_func_set(but, template_texture_show, user->ptr.data, user->prop);
}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 1ff0cb53f6a..1f1f238daf6 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -44,21 +44,29 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_resources.h"
+
+#include "GPU_glew.h"
#include "buttons_intern.h" /* own include */
/* ******************** default callbacks for buttons space ***************** */
-static SpaceLink *buttons_new(const bContext *UNUSED(C))
+static SpaceLink *buttons_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceButs *sbuts;
sbuts = MEM_callocN(sizeof(SpaceButs), "initbuts");
sbuts->spacetype = SPACE_BUTS;
- sbuts->align = BUT_VERTICAL;
+
+ sbuts->mainb = sbuts->mainbuser = BCONTEXT_OBJECT;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for buts");
@@ -67,6 +75,13 @@ static SpaceLink *buttons_new(const bContext *UNUSED(C))
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_TOP;
+ /* navigation bar */
+ ar = MEM_callocN(sizeof(ARegion), "navigation bar for buts");
+
+ BLI_addtail(&sbuts->regionbase, ar);
+ ar->regiontype = RGN_TYPE_NAV_BAR;
+ ar->alignment = RGN_ALIGN_LEFT;
+
#if 0
/* context region */
ar = MEM_callocN(sizeof(ARegion), "context region for buts");
@@ -100,17 +115,8 @@ static void buttons_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
{
- SpaceButs *sbuts = sa->spacedata.first;
-
- /* auto-align based on size */
- if (sbuts->align == BUT_AUTO || !sbuts->align) {
- if (sa->winx > sa->winy)
- sbuts->align = BUT_HORIZONTAL;
- else
- sbuts->align = BUT_VERTICAL;
- }
}
static SpaceLink *buttons_duplicate(SpaceLink *sl)
@@ -135,64 +141,231 @@ static void buttons_main_region_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void buttons_main_region_draw(const bContext *C, ARegion *ar)
+static void buttons_main_region_layout_properties(const bContext *C, SpaceButs *sbuts, ARegion *ar)
+{
+ buttons_context_compute(C, sbuts);
+
+ const char *contexts[2] = {NULL, NULL};
+
+ switch (sbuts->mainb) {
+ case BCONTEXT_SCENE:
+ contexts[0] = "scene";
+ break;
+ case BCONTEXT_RENDER:
+ contexts[0] = "render";
+ break;
+ case BCONTEXT_OUTPUT:
+ contexts[0] = "output";
+ break;
+ case BCONTEXT_VIEW_LAYER:
+ contexts[0] = "view_layer";
+ break;
+ case BCONTEXT_WORLD:
+ contexts[0] = "world";
+ break;
+ case BCONTEXT_OBJECT:
+ contexts[0] = "object";
+ break;
+ case BCONTEXT_DATA:
+ contexts[0] = "data";
+ break;
+ case BCONTEXT_MATERIAL:
+ contexts[0] = "material";
+ break;
+ case BCONTEXT_TEXTURE:
+ contexts[0] = "texture";
+ break;
+ case BCONTEXT_PARTICLE:
+ contexts[0] = "particle";
+ break;
+ case BCONTEXT_PHYSICS:
+ contexts[0] = "physics";
+ break;
+ case BCONTEXT_BONE:
+ contexts[0] = "bone";
+ break;
+ case BCONTEXT_MODIFIER:
+ contexts[0] = "modifier";
+ break;
+ case BCONTEXT_SHADERFX:
+ contexts[0] = "shaderfx";
+ break;
+ case BCONTEXT_CONSTRAINT:
+ contexts[0] = "constraint";
+ break;
+ case BCONTEXT_BONE_CONSTRAINT:
+ contexts[0] = "bone_constraint";
+ break;
+ case BCONTEXT_TOOL:
+ contexts[0] = "tool";
+ break;
+ }
+
+ const bool vertical = true;
+ ED_region_panels_layout_ex(C, ar, contexts, sbuts->mainb, vertical);
+}
+
+static void buttons_main_region_layout_tool(const bContext *C, ARegion *ar)
+{
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ const int mode = CTX_data_mode_enum(C);
+
+ const char *contexts_base[5] = {NULL};
+ contexts_base[0] = ".active_tool";
+ const char **contexts = &contexts_base[1];
+
+ if (workspace->tools_space_type == SPACE_VIEW3D) {
+ switch (mode) {
+ case CTX_MODE_EDIT_MESH:
+ ARRAY_SET_ITEMS(contexts, ".mesh_edit");
+ break;
+ case CTX_MODE_EDIT_CURVE:
+ ARRAY_SET_ITEMS(contexts, ".curve_edit");
+ break;
+ case CTX_MODE_EDIT_SURFACE:
+ ARRAY_SET_ITEMS(contexts, ".curve_edit");
+ break;
+ case CTX_MODE_EDIT_TEXT:
+ ARRAY_SET_ITEMS(contexts, ".text_edit");
+ break;
+ case CTX_MODE_EDIT_ARMATURE:
+ ARRAY_SET_ITEMS(contexts, ".armature_edit");
+ break;
+ case CTX_MODE_EDIT_METABALL:
+ ARRAY_SET_ITEMS(contexts, ".mball_edit");
+ break;
+ case CTX_MODE_EDIT_LATTICE:
+ ARRAY_SET_ITEMS(contexts, ".lattice_edit");
+ break;
+ case CTX_MODE_POSE:
+ ARRAY_SET_ITEMS(contexts, ".posemode");
+ break;
+ case CTX_MODE_SCULPT:
+ ARRAY_SET_ITEMS(contexts, ".paint_common", ".sculpt_mode");
+ break;
+ case CTX_MODE_PAINT_WEIGHT:
+ ARRAY_SET_ITEMS(contexts, ".paint_common", ".weightpaint");
+ break;
+ case CTX_MODE_PAINT_VERTEX:
+ ARRAY_SET_ITEMS(contexts, ".paint_common", ".vertexpaint");
+ break;
+ case CTX_MODE_PAINT_TEXTURE:
+ ARRAY_SET_ITEMS(contexts, ".paint_common", ".imagepaint");
+ break;
+ case CTX_MODE_PARTICLE:
+ ARRAY_SET_ITEMS(contexts, ".paint_common", ".particlemode");
+ break;
+ case CTX_MODE_OBJECT:
+ ARRAY_SET_ITEMS(contexts, ".objectmode");
+ break;
+ case CTX_MODE_GPENCIL_PAINT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_paint");
+ break;
+ case CTX_MODE_GPENCIL_SCULPT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt");
+ break;
+ case CTX_MODE_GPENCIL_WEIGHT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_weight");
+ break;
+ }
+ }
+ else if (workspace->tools_space_type == SPACE_IMAGE) {
+ switch (workspace->tools_mode) {
+ case SI_MODE_VIEW:
+ break;
+ case SI_MODE_PAINT:
+ ARRAY_SET_ITEMS(contexts, ".paint_common_2d", ".imagepaint_2d");
+ break;
+ case SI_MODE_MASK:
+ break;
+ case SI_MODE_UV:
+ if (mode == CTX_MODE_EDIT_MESH) {
+ ARRAY_SET_ITEMS(contexts, ".uv_sculpt");
+ }
+ break;
+ }
+ }
+
+ /* for grease pencil we don't use tool system yet, so we need check outside
+ * workspace->tools_space_type because this value is not available
+ */
+ switch (mode) {
+ case CTX_MODE_GPENCIL_PAINT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_paint");
+ break;
+ case CTX_MODE_GPENCIL_SCULPT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt");
+ break;
+ case CTX_MODE_GPENCIL_WEIGHT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_weight");
+ break;
+ case CTX_MODE_GPENCIL_EDIT:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_edit");
+ break;
+ }
+
+ int i = 0;
+ while (contexts_base[i]) {
+ i++;
+ }
+ BLI_assert(i < ARRAY_SIZE(contexts_base));
+ contexts_base[i] = ".workspace";
+
+ const bool vertical = true;
+ ED_region_panels_layout_ex(C, ar, contexts_base, -1, vertical);
+}
+
+static void buttons_main_region_layout(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceButs *sbuts = CTX_wm_space_buts(C);
- const bool vertical = (sbuts->align == BUT_VERTICAL);
- buttons_context_compute(C, sbuts);
+ if (sbuts->mainb == BCONTEXT_TOOL) {
+ buttons_main_region_layout_tool(C, ar);
+ }
+ else {
+ buttons_main_region_layout_properties(C, sbuts, ar);
+ }
- if (sbuts->mainb == BCONTEXT_SCENE)
- ED_region_panels(C, ar, "scene", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_RENDER)
- ED_region_panels(C, ar, "render", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_RENDER_LAYER)
- ED_region_panels(C, ar, "render_layer", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_WORLD)
- ED_region_panels(C, ar, "world", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_OBJECT)
- ED_region_panels(C, ar, "object", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_DATA)
- ED_region_panels(C, ar, "data", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_MATERIAL)
- ED_region_panels(C, ar, "material", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_TEXTURE)
- ED_region_panels(C, ar, "texture", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_PARTICLE)
- ED_region_panels(C, ar, "particle", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_PHYSICS)
- ED_region_panels(C, ar, "physics", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_BONE)
- ED_region_panels(C, ar, "bone", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_MODIFIER)
- ED_region_panels(C, ar, "modifier", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_CONSTRAINT)
- ED_region_panels(C, ar, "constraint", sbuts->mainb, vertical);
- else if (sbuts->mainb == BCONTEXT_BONE_CONSTRAINT)
- ED_region_panels(C, ar, "bone_constraint", sbuts->mainb, vertical);
-
- sbuts->re_align = 0;
sbuts->mainbo = sbuts->mainb;
}
+static void buttons_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn,
+ const Scene *UNUSED(scene))
+{
+ /* context changes */
+ switch (wmn->category) {
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
+ }
+}
+
static void buttons_operatortypes(void)
{
- WM_operatortype_append(BUTTONS_OT_toolbox);
+ WM_operatortype_append(BUTTONS_OT_context_menu);
WM_operatortype_append(BUTTONS_OT_file_browse);
WM_operatortype_append(BUTTONS_OT_directory_browse);
}
static void buttons_keymap(struct wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Property Editor", SPACE_BUTS, 0);
-
- WM_keymap_add_item(keymap, "BUTTONS_OT_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_ensure(keyconf, "Property Editor", SPACE_BUTS, 0);
}
/* add handlers, stuff you only do once or on area/region changes */
static void buttons_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
+#ifdef USE_HEADER_CONTEXT_PATH
+ /* Reinsert context buttons header-type at the end of the list so it's drawn last. */
+ HeaderType *context_ht = BLI_findstring(&ar->type->headertypes, "BUTTONS_HT_context", offsetof(HeaderType, idname));
+ BLI_remlink(&ar->type->headertypes, context_ht);
+ BLI_addtail(&ar->type->headertypes, context_ht);
+#endif
+
ED_region_header_init(ar);
}
@@ -206,6 +379,58 @@ static void buttons_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
+static void buttons_header_region_message_subscribe(
+ const bContext *UNUSED(C),
+ WorkSpace *UNUSED(workspace), Scene *UNUSED(scene),
+ bScreen *UNUSED(screen), ScrArea *sa, ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ SpaceButs *sbuts = sa->spacedata.first;
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* Don't check for SpaceButs.mainb here, we may toggle between view-layers
+ * where one has no active object, so that available contexts changes. */
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
+
+ if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_OUTPUT, BCONTEXT_SCENE, BCONTEXT_WORLD)) {
+ WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
+ }
+
+ if (sbuts->mainb == BCONTEXT_TOOL) {
+ WM_msg_subscribe_rna_anon_prop(mbus, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
+ }
+
+#ifdef USE_HEADER_CONTEXT_PATH
+ WM_msg_subscribe_rna_anon_prop(mbus, SpaceProperties, context, &msg_sub_value_region_tag_redraw);
+#endif
+}
+
+static void buttons_navigation_bar_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Property Editor", SPACE_BUTS, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+
+ ar->flag |= RGN_FLAG_PREFSIZE_OR_HIDDEN;
+
+ ED_region_panels_init(wm, ar);
+ ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
+}
+
+static void buttons_navigation_bar_region_draw(const bContext *C, ARegion *ar)
+{
+ for (PanelType *pt = ar->type->paneltypes.first; pt; pt = pt->next) {
+ pt->flag |= PNL_LAYOUT_VERT_BAR;
+ }
+
+ ED_region_panels_layout(C, ar);
+ ar->v2d.scroll &= ~V2D_SCROLL_VERTICAL; /* ED_region_panels_layout adds vertical scrollbars, we don't want them. */
+ ED_region_panels_draw(C, ar);
+}
+
/* draw a certain button set only if properties area is currently
* showing that button set, to reduce unnecessary drawing. */
static void buttons_area_redraw(ScrArea *sa, short buttons)
@@ -218,7 +443,8 @@ static void buttons_area_redraw(ScrArea *sa, short buttons)
}
/* reused! */
-static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void buttons_area_listener(
+ wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
SpaceButs *sbuts = sa->spacedata.first;
@@ -228,7 +454,7 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
switch (wmn->data) {
case ND_RENDER_OPTIONS:
buttons_area_redraw(sa, BCONTEXT_RENDER);
- buttons_area_redraw(sa, BCONTEXT_RENDER_LAYER);
+ buttons_area_redraw(sa, BCONTEXT_VIEW_LAYER);
break;
case ND_WORLD:
buttons_area_redraw(sa, BCONTEXT_WORLD);
@@ -339,6 +565,7 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
break;
case NC_BRUSH:
buttons_area_redraw(sa, BCONTEXT_TEXTURE);
+ buttons_area_redraw(sa, BCONTEXT_TOOL);
sbuts->preview = 1;
break;
case NC_TEXTURE:
@@ -364,6 +591,14 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
break;
}
break;
+ case NC_GPENCIL:
+ switch (wmn->data) {
+ case ND_DATA:
+ if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
+ ED_area_tag_redraw(sa);
+ break;
+ }
+ break;
case NC_NODE:
if (wmn->action == NA_SELECTED) {
ED_area_tag_redraw(sa);
@@ -467,11 +702,14 @@ void ED_spacetype_buttons(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
art->regionid = RGN_TYPE_WINDOW;
art->init = buttons_main_region_init;
- art->draw = buttons_main_region_draw;
+ art->layout = buttons_main_region_layout;
+ art->draw = ED_region_panels_draw;
+ art->listener = buttons_main_region_listener;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- BLI_addhead(&st->regiontypes, art);
-
+#ifndef USE_HEADER_CONTEXT_PATH
buttons_context_register(art);
+#endif
+ BLI_addhead(&st->regiontypes, art);
/* regions: header */
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
@@ -481,6 +719,19 @@ void ED_spacetype_buttons(void)
art->init = buttons_header_region_init;
art->draw = buttons_header_region_draw;
+ art->message_subscribe = buttons_header_region_message_subscribe;
+#ifdef USE_HEADER_CONTEXT_PATH
+ buttons_context_register(art);
+#endif
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: navigation bar */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype nav buttons region");
+ art->regionid = RGN_TYPE_NAV_BAR;
+ art->prefsizex = AREAMINX - 3; /* XXX Works and looks best, should we update AREAMINX accordingly? */
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
+ art->init = buttons_navigation_bar_region_init;
+ art->draw = buttons_navigation_bar_region_draw;
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index 32d48c9c564..8fa4a0de53f 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../imbuf
../../gpu
../../makesdna
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index ce97d87d0c4..a106ab5c465 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -47,11 +47,12 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_screen.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
+#include "DEG_depsgraph.h"
+
#include "ED_gpencil.h"
#include "UI_interface.h"
@@ -106,7 +107,7 @@ void uiTemplateMovieClip(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr);
if (!compact)
- uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (clip) {
uiLayout *col;
@@ -236,7 +237,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event)
marker->pos[1] = cb->marker_pos[1] / height;
/* to update position of "parented" objects */
- DAG_id_tag_update(&cb->clip->id, 0);
+ DEG_id_tag_update(&cb->clip->id, 0);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
ok = true;
@@ -321,7 +322,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event)
sub_v2_v2(cb->track->markers[i].pos, delta);
/* to update position of "parented" objects */
- DAG_id_tag_update(&cb->clip->id, 0);
+ DEG_id_tag_update(&cb->clip->id, 0);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
ok = true;
@@ -386,9 +387,10 @@ void uiTemplateMarker(uiLayout *layout, PointerRNA *ptr, const char *propname, P
else
tip = TIP_("Marker is enabled at current frame");
- bt = uiDefIconButBitI(block, UI_BTYPE_TOGGLE_N, MARKER_DISABLED, 0, ICON_RESTRICT_VIEW_OFF, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ bt = uiDefIconButBitI(block, UI_BTYPE_TOGGLE_N, MARKER_DISABLED, 0, ICON_HIDE_OFF, 0, 0, UI_UNIT_X, UI_UNIT_Y,
&cb->marker_flag, 0, 0, 1, 0, tip);
UI_but_funcN_set(bt, marker_update_cb, cb, NULL);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
else {
int width, height, step, digits;
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index 4bf4c1e7baa..c05a4c1b64c 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_draw.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c
@@ -42,8 +42,6 @@
#include "ED_screen.h"
#include "ED_clip.h"
-#include "BIF_gl.h"
-
#include "WM_types.h"
#include "UI_interface.h"
@@ -54,6 +52,10 @@
#include "RNA_access.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
#include "clip_intern.h" /* own include */
static void track_channel_color(MovieTrackingTrack *track, float default_color[3], float color[3])
@@ -72,72 +74,19 @@ static void track_channel_color(MovieTrackingTrack *track, float default_color[3
}
}
-static void draw_keyframe_shape(float x, float y, float xscale, float yscale, bool sel, float alpha)
+static void draw_keyframe_shape(float x, float y, bool sel, float alpha,
+ unsigned int pos_id, unsigned int color_id)
{
- /* coordinates for diamond shape */
- static const float _unit_diamond_shape[4][2] = {
- {0.0f, 1.0f}, /* top vert */
- {1.0f, 0.0f}, /* mid-right */
- {0.0f, -1.0f}, /* bottom vert */
- {-1.0f, 0.0f} /* mid-left */
- };
- static GLuint displist1 = 0;
- static GLuint displist2 = 0;
- int hsize = STRIP_HEIGHT_HALF;
-
- /* initialize 2 display lists for diamond shape - one empty, one filled */
- if (displist1 == 0) {
- displist1 = glGenLists(1);
- glNewList(displist1, GL_COMPILE);
-
- glBegin(GL_LINE_LOOP);
- glVertex2fv(_unit_diamond_shape[0]);
- glVertex2fv(_unit_diamond_shape[1]);
- glVertex2fv(_unit_diamond_shape[2]);
- glVertex2fv(_unit_diamond_shape[3]);
- glEnd();
- glEndList();
+ float color[4] = { 0.91f, 0.91f, 0.91f, alpha };
+ if (sel) {
+ UI_GetThemeColorShadeAlpha4fv(TH_STRIP_SELECT, 50, -255 * (1.0f - alpha), color);
}
- if (displist2 == 0) {
- displist2 = glGenLists(1);
- glNewList(displist2, GL_COMPILE);
-
- glBegin(GL_QUADS);
- glVertex2fv(_unit_diamond_shape[0]);
- glVertex2fv(_unit_diamond_shape[1]);
- glVertex2fv(_unit_diamond_shape[2]);
- glVertex2fv(_unit_diamond_shape[3]);
- glEnd();
- glEndList();
- }
-
- glPushMatrix();
-
- /* adjust view transform before starting */
- glTranslatef(x, y, 0.0f);
- glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f);
-
- /* anti-aliased lines for more consistent appearance */
- glEnable(GL_LINE_SMOOTH);
-
- if (sel)
- UI_ThemeColorShadeAlpha(TH_STRIP_SELECT, 50, -255 * (1.0f - alpha));
- else
- glColor4f(0.91f, 0.91f, 0.91f, alpha);
- glCallList(displist2);
-
- /* exterior - black frame */
- glColor4f(0.0f, 0.0f, 0.0f, alpha);
- glCallList(displist1);
-
- glDisable(GL_LINE_SMOOTH);
-
- /* restore view transform */
- glPopMatrix();
+ immAttr4fv(color_id, color);
+ immVertex2f(pos_id, x, y);
}
-static void clip_draw_dopesheet_background(ARegion *ar, MovieClip *clip)
+static void clip_draw_dopesheet_background(ARegion *ar, MovieClip *clip, unsigned int pos_id)
{
View2D *v2d = &ar->v2d;
MovieTracking *tracking = &clip->tracking;
@@ -153,12 +102,13 @@ static void clip_draw_dopesheet_background(ARegion *ar, MovieClip *clip)
int end_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, coverage_segment->end_frame);
if (coverage_segment->coverage == TRACKING_COVERAGE_BAD) {
- glColor4f(1.0f, 0.0f, 0.0f, 0.07f);
+ immUniformColor4f(1.0f, 0.0f, 0.0f, 0.07f);
+ }
+ else {
+ immUniformColor4f(1.0f, 1.0f, 0.0f, 0.07f);
}
- else
- glColor4f(1.0f, 1.0f, 0.0f, 0.07f);
- glRectf(start_frame, v2d->cur.ymin, end_frame, v2d->cur.ymax);
+ immRectf(pos_id, start_frame, v2d->cur.ymin, end_frame, v2d->cur.ymax);
}
}
}
@@ -175,18 +125,21 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
MovieTracking *tracking = &clip->tracking;
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
MovieTrackingDopesheetChannel *channel;
- float y, xscale, yscale;
float strip[4], selected_strip[4];
float height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT);
+ uint keyframe_len = 0;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
v2d->tot.ymin = (float)(-height);
- y = (float) CHANNEL_FIRST;
-
- UI_view2d_scale_get(v2d, &xscale, &yscale);
+ float y = (float) CHANNEL_FIRST;
/* setup colors for regular and selected strips */
UI_GetThemeColor3fv(TH_STRIP, strip);
@@ -195,9 +148,9 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
strip[3] = 0.5f;
selected_strip[3] = 1.0f;
- glEnable(GL_BLEND);
+ GPU_blend(true);
- clip_draw_dopesheet_background(ar, clip);
+ clip_draw_dopesheet_background(ar, clip, pos_id);
for (channel = dopesheet->channels.first; channel; channel = channel->next) {
float yminc = (float) (y - CHANNEL_HEIGHT_HALF);
@@ -208,7 +161,6 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax))
{
MovieTrackingTrack *track = channel->track;
- float alpha;
int i;
bool sel = (track->flag & TRACK_DOPE_SEL) != 0;
@@ -218,32 +170,26 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
float default_color[4] = {0.8f, 0.93f, 0.8f, 0.3f};
track_channel_color(track, default_color, color);
- glColor4fv(color);
+ immUniformColor4fv(color);
- glRectf(v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF,
- v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF);
+ immRectf(pos_id, v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF,
+ v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF);
}
- alpha = (track->flag & TRACK_LOCKED) ? 0.5f : 1.0f;
-
/* tracked segments */
for (i = 0; i < channel->tot_segment; i++) {
int start_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, channel->segments[2 * i]);
int end_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, channel->segments[2 * i + 1]);
- if (sel)
- glColor4fv(selected_strip);
- else
- glColor4fv(strip);
+ immUniformColor4fv(sel ? selected_strip : strip);
if (start_frame != end_frame) {
- glRectf(start_frame, (float) y - STRIP_HEIGHT_HALF,
- end_frame, (float) y + STRIP_HEIGHT_HALF);
- draw_keyframe_shape(start_frame, y, xscale, yscale, sel, alpha);
- draw_keyframe_shape(end_frame, y, xscale, yscale, sel, alpha);
+ immRectf(pos_id, start_frame, (float) y - STRIP_HEIGHT_HALF,
+ end_frame, (float) y + STRIP_HEIGHT_HALF);
+ keyframe_len += 2;
}
else {
- draw_keyframe_shape(start_frame, y, xscale, yscale, sel, alpha);
+ keyframe_len++;
}
}
@@ -253,9 +199,7 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
MovieTrackingMarker *marker = &track->markers[i];
if ((marker->flag & (MARKER_DISABLED | MARKER_TRACKED)) == 0) {
- int framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
-
- draw_keyframe_shape(framenr, y, xscale, yscale, sel, alpha);
+ keyframe_len++;
}
i++;
@@ -266,11 +210,81 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
y -= CHANNEL_STEP;
}
- glDisable(GL_BLEND);
- }
+ immUnbindProgram();
+
+ if (keyframe_len > 0) {
+ /* draw keyframe markers */
+ format = immVertexFormat();
+ pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
+
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ GPU_enable_program_point_size();
+ immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
+ immBegin(GPU_PRIM_POINTS, keyframe_len);
+
+ /* all same size with black outline */
+ immAttr1f(size_id, 2.0f * STRIP_HEIGHT_HALF);
+ immAttr4ub(outline_color_id, 0, 0, 0, 255);
+ immAttr1u(flags_id, 0);
+
+ y = (float) CHANNEL_FIRST; /* start again at the top */
+ for (channel = dopesheet->channels.first; channel; channel = channel->next) {
+ float yminc = (float) (y - CHANNEL_HEIGHT_HALF);
+ float ymaxc = (float) (y + CHANNEL_HEIGHT_HALF);
+
+ /* check if visible */
+ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
+ IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax))
+ {
+ MovieTrackingTrack *track = channel->track;
+ int i;
+ bool sel = (track->flag & TRACK_DOPE_SEL) != 0;
+ float alpha = (track->flag & TRACK_LOCKED) ? 0.5f : 1.0f;
+
+ /* tracked segments */
+ for (i = 0; i < channel->tot_segment; i++) {
+ int start_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, channel->segments[2 * i]);
+ int end_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, channel->segments[2 * i + 1]);
+
+ if (start_frame != end_frame) {
+ draw_keyframe_shape(start_frame, y, sel, alpha, pos_id, color_id);
+ draw_keyframe_shape(end_frame, y, sel, alpha, pos_id, color_id);
+ }
+ else {
+ draw_keyframe_shape(start_frame, y, sel, alpha, pos_id, color_id);
+ }
+ }
+
+ /* keyframes */
+ i = 0;
+ while (i < track->markersnr) {
+ MovieTrackingMarker *marker = &track->markers[i];
+
+ if ((marker->flag & (MARKER_DISABLED | MARKER_TRACKED)) == 0) {
+ int framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
+
+ draw_keyframe_shape(framenr, y, sel, alpha, pos_id, color_id);
+ }
+
+ i++;
+ }
+ }
+
+ /* adjust y-position for next one */
+ y -= CHANNEL_STEP;
+ }
+
+ immEnd();
+ GPU_disable_program_point_size();
+ immUnbindProgram();
+ }
- /* current frame */
- clip_draw_cfra(sc, ar, scene);
+ GPU_blend(false);
+ }
}
void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
@@ -279,22 +293,15 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
SpaceClip *sc = CTX_wm_space_clip(C);
View2D *v2d = &ar->v2d;
MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking;
- MovieTrackingDopesheet *dopesheet;
- MovieTrackingDopesheetChannel *channel;
uiStyle *style = UI_style_get();
- uiBlock *block;
int fontid = style->widget.uifont_id;
- int height;
- float y;
- PropertyRNA *chan_prop_lock;
if (!clip)
return;
- tracking = &clip->tracking;
- dopesheet = &tracking->dopesheet;
- height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
+ int height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT);
if (height > BLI_rcti_size_y(&v2d->mask)) {
/* don't use totrect set, as the width stays the same
@@ -309,6 +316,37 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
/* loop through channels, and set up drawing depending on their type
* first pass: just the standard GL-drawing for backdrop + text
*/
+ float y = (float) CHANNEL_FIRST;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ MovieTrackingDopesheetChannel *channel;
+ for (channel = dopesheet->channels.first; channel; channel = channel->next) {
+ float yminc = (float) (y - CHANNEL_HEIGHT_HALF);
+ float ymaxc = (float) (y + CHANNEL_HEIGHT_HALF);
+
+ /* check if visible */
+ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
+ IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax))
+ {
+ MovieTrackingTrack *track = channel->track;
+ float color[3];
+ track_channel_color(track, NULL, color);
+ immUniformColor3fv(color);
+
+ immRectf(pos, v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF,
+ v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF);
+ }
+
+ /* adjust y-position for next one */
+ y -= CHANNEL_STEP;
+ }
+ immUnbindProgram();
+
+ /* second pass: text */
y = (float) CHANNEL_FIRST;
BLF_size(fontid, 11.0f * U.pixelsize, U.dpi);
@@ -322,21 +360,11 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax))
{
MovieTrackingTrack *track = channel->track;
- float font_height, color[3];
bool sel = (track->flag & TRACK_DOPE_SEL) != 0;
- track_channel_color(track, NULL, color);
- glColor3fv(color);
-
- glRectf(v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF,
- v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF);
-
- if (sel)
- UI_ThemeColor(TH_TEXT_HI);
- else
- UI_ThemeColor(TH_TEXT);
+ UI_FontThemeColor(fontid, sel ? TH_TEXT_HI : TH_TEXT);
- font_height = BLF_height(fontid, channel->name, sizeof(channel->name));
+ float font_height = BLF_height(fontid, channel->name, sizeof(channel->name));
BLF_position(fontid, v2d->cur.xmin + CHANNEL_PAD,
y - font_height / 2.0f, 0.0f);
BLF_draw(fontid, channel->name, strlen(channel->name));
@@ -346,15 +374,15 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
y -= CHANNEL_STEP;
}
- /* second pass: widgets */
- block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
+ /* third pass: widgets */
+ uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
y = (float) CHANNEL_FIRST;
/* get RNA properties (once) */
- chan_prop_lock = RNA_struct_type_find_property(&RNA_MovieTrackingTrack, "lock");
+ PropertyRNA *chan_prop_lock = RNA_struct_type_find_property(&RNA_MovieTrackingTrack, "lock");
BLI_assert(chan_prop_lock);
- glEnable(GL_BLEND);
+ GPU_blend(true);
for (channel = dopesheet->channels.first; channel; channel = channel->next) {
float yminc = (float)(y - CHANNEL_HEIGHT_HALF);
float ymaxc = (float)(y + CHANNEL_HEIGHT_HALF);
@@ -379,7 +407,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
/* adjust y-position for next one */
y -= CHANNEL_STEP;
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
UI_block_end(C, block);
UI_block_draw(C, block);
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index a71b2baa96f..9f4983a35b2 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -55,10 +55,12 @@
#include "ED_mask.h"
#include "ED_gpencil.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "WM_types.h"
@@ -66,26 +68,25 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-
#include "BLF_api.h"
#include "clip_intern.h" // own include
/*********************** main area drawing *************************/
-static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int width)
+static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int width, unsigned int pos)
{
int height = (frame == cfra) ? 22 : 10;
int x = (frame - sfra) * framelen;
if (width == 1) {
- glBegin(GL_LINES);
- glVertex2i(x, 0);
- glVertex2i(x, height * UI_DPI_FAC);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2i(pos, x, 0);
+ immVertex2i(pos, x, height * UI_DPI_FAC);
+ immEnd();
}
else {
- glRecti(x, 0, x + width, height * UI_DPI_FAC);
+ immRecti(pos, x, 0, x + width, height * UI_DPI_FAC);
}
}
@@ -156,8 +157,8 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking);
MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* cache background */
ED_region_cache_draw_background(ar);
@@ -166,6 +167,9 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points);
ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* track */
if (act_track || act_plane_track) {
for (i = sfra - clip->start_frame + 1, a = 0; i <= efra - clip->start_frame + 1; i++) {
@@ -189,14 +193,17 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
if (generic_track_is_marker_enabled(act_track, act_plane_track, a)) {
framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a);
- if (framenr != i)
- glColor4ub(128, 128, 0, 96);
- else if (generic_track_is_marker_keyframed(act_track, act_plane_track, a))
- glColor4ub(255, 255, 0, 196);
- else
- glColor4ub(255, 255, 0, 96);
+ if (framenr != i) {
+ immUniformColor4ub(128, 128, 0, 96);
+ }
+ else if (generic_track_is_marker_keyframed(act_track, act_plane_track, a)) {
+ immUniformColor4ub(255, 255, 0, 196);
+ }
+ else {
+ immUniformColor4ub(255, 255, 0, 96);
+ }
- glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 4 * UI_DPI_FAC);
+ immRecti(pos, (i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 4 * UI_DPI_FAC);
}
}
}
@@ -206,7 +213,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
int n = reconstruction->camnr;
MovieReconstructedCamera *cameras = reconstruction->cameras;
- glColor4ub(255, 0, 0, 96);
+ immUniformColor4ub(255, 0, 0, 96);
for (i = sfra, a = 0; i <= efra; i++) {
bool ok = false;
@@ -223,25 +230,33 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
a++;
}
- if (!ok)
- glRecti((i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 8 * UI_DPI_FAC);
+ if (!ok) {
+ immRecti(pos, (i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, 8 * UI_DPI_FAC);
+ }
}
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* current frame */
x = (sc->user.framenr - sfra) / (efra - sfra + 1) * ar->winx;
- UI_ThemeColor(TH_CFRAME);
- glRecti(x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC);
+ immUniformThemeColor(TH_CFRAME);
+ immRecti(pos, x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC);
+
+ immUnbindProgram();
ED_region_cache_draw_curfra_label(sc->user.framenr, x, 8.0f * UI_DPI_FAC);
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* solver keyframes */
- glColor4ub(175, 255, 0, 255);
- draw_keyframe(act_object->keyframe1 + clip->start_frame - 1, CFRA, sfra, framelen, 2);
- draw_keyframe(act_object->keyframe2 + clip->start_frame - 1, CFRA, sfra, framelen, 2);
+ immUniformColor4ub(175, 255, 0, 255);
+ draw_keyframe(act_object->keyframe1 + clip->start_frame - 1, CFRA, sfra, framelen, 2, pos);
+ draw_keyframe(act_object->keyframe2 + clip->start_frame - 1, CFRA, sfra, framelen, 2, pos);
+
+ immUnbindProgram();
/* movie clip animation */
if ((sc->mode == SC_MODE_MASKEDIT) && sc->mask_info.mask) {
@@ -275,11 +290,16 @@ static void draw_movieclip_muted(ARegion *ar, int width, int height, float zoomx
{
int x, y;
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
- glColor3f(0.0f, 0.0f, 0.0f);
- glRectf(x, y, x + zoomx * width, y + zoomy * height);
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+ immRectf(pos, x, y, x + zoomx * width, y + zoomy * height);
+
+ immUnbindProgram();
}
static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, ImBuf *ibuf,
@@ -294,10 +314,10 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
/* checkerboard for case alpha */
if (ibuf->planes == 32) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- fdrawcheckerboard(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y);
+ imm_draw_box_checker_2d(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y);
}
/* non-scaled proxy shouldn't use filtering */
@@ -307,13 +327,7 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
filter = GL_NEAREST;
}
- /* set zoom */
- glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y);
-
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, filter);
- /* reset zoom */
- glPixelZoom(1.0f, 1.0f);
-
+ glaDrawImBuf_glsl_ctx(C, ibuf, x, y, filter, zoomx * width / ibuf->x, zoomy * height / ibuf->y);
if (sc->flag & SC_SHOW_METADATA) {
rctf frame;
@@ -322,7 +336,7 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
}
if (ibuf->planes == 32)
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int height, float zoomx, float zoomy)
@@ -335,31 +349,37 @@ static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int
/* draw boundary border for frame if stabilization is enabled */
if (sc->flag & SC_SHOW_STABLE && clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) {
- glColor3f(0.0f, 0.0f, 0.0f);
-
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(3, 0xAAAA);
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ /* Exclusive OR allows to get orig value when second operand is 0,
+ * and negative of orig value when second operand is 1. */
glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(GL_NOR);
+ glLogicOp(GL_XOR);
+
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(x, y);
+
+ GPU_matrix_scale_2f(zoomx, zoomy);
+ GPU_matrix_mul(sc->stabmat);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- glPushMatrix();
- glTranslatef(x, y, 0.0f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.0f);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- glScalef(zoomx, zoomy, 1.0f);
- glMultMatrixf(sc->stabmat);
+ imm_draw_box_wire_2d(shdr_pos, 0.0f, 0.0f, width, height);
- glBegin(GL_LINE_LOOP);
- glVertex2f(0.0f, 0.0f);
- glVertex2f(width, 0.0f);
- glVertex2f(width, height);
- glVertex2f(0.0f, height);
- glEnd();
+ immUnbindProgram();
- glPopMatrix();
+ GPU_matrix_pop();
glDisable(GL_COLOR_LOGIC_OP);
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
@@ -432,53 +452,97 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
i++;
}
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
if (!tiny) {
- UI_ThemeColor(TH_MARKER_OUTLINE);
+ immUniformThemeColor(TH_MARKER_OUTLINE);
if (TRACK_VIEW_SELECTED(sc, track)) {
- glPointSize(5.0f);
- glBegin(GL_POINTS);
+ if ((b - a - 1) >= 1) {
+ GPU_point_size(5.0f);
+
+ immBegin(GPU_PRIM_POINTS, b - a - 1);
+
+ for (i = a; i < b; i++) {
+ if (i != curindex) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
+ }
+
+ immEnd();
+ }
+ }
+
+ if ((b - a) >= 2) {
+ GPU_line_width(3.0f);
+
+ immBegin(GPU_PRIM_LINE_STRIP, b - a);
+
for (i = a; i < b; i++) {
- if (i != curindex)
- glVertex2f(path[i][0], path[i][1]);
+ immVertex2f(pos, path[i][0], path[i][1]);
}
- glEnd();
+
+ immEnd();
}
+ }
+
+ if (TRACK_VIEW_SELECTED(sc, track)) {
+ GPU_point_size(3.0f);
+
+ if ((curindex - a) >= 1) {
+ immUniformThemeColor(TH_PATH_BEFORE);
- glLineWidth(3.0f);
- glBegin(GL_LINE_STRIP);
- for (i = a; i < b; i++)
- glVertex2f(path[i][0], path[i][1]);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, curindex - a);
+
+ for (i = a; i < curindex; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
+
+ immEnd();
+ }
+
+ if ((b - curindex - 1) >= 1) {
+ immUniformThemeColor(TH_PATH_AFTER);
+
+ immBegin(GPU_PRIM_POINTS, b - curindex - 1);
+
+ for (i = curindex + 1; i < b; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
+
+ immEnd();
+ }
}
- UI_ThemeColor(TH_PATH_BEFORE);
+ GPU_line_width(1);
- if (TRACK_VIEW_SELECTED(sc, track)) {
- glPointSize(3.0f);
- glBegin(GL_POINTS);
- for (i = a; i < b; i++) {
- if (i == count + 1)
- UI_ThemeColor(TH_PATH_AFTER);
-
- if (i != curindex)
- glVertex2f(path[i][0], path[i][1]);
+ if ((curindex - a + 1) >= 2) {
+ immUniformThemeColor(TH_PATH_BEFORE);
+
+ immBegin(GPU_PRIM_LINE_STRIP, curindex - a + 1);
+
+ for (i = a; i <= curindex; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
}
- glEnd();
+
+ immEnd();
}
- UI_ThemeColor(TH_PATH_BEFORE);
+ if ((b - curindex) >= 2) {
+ immUniformThemeColor(TH_PATH_AFTER);
- glLineWidth(1);
+ immBegin(GPU_PRIM_LINE_STRIP, b - curindex);
- glBegin(GL_LINE_STRIP);
- for (i = a; i < b; i++) {
- if (i == count + 1)
- UI_ThemeColor(TH_PATH_AFTER);
+ for (i = curindex; i < b; i++) {
+ immVertex2f(pos, path[i][0], path[i][1]);
+ }
- glVertex2f(path[i][0], path[i][1]);
+ immEnd();
}
- glEnd();
+
+ immUnbindProgram();
if (path != path_static) {
MEM_freeN(path);
@@ -487,18 +551,18 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
}
static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
- const float marker_pos[2], int width, int height)
+ const float marker_pos[2], int width, int height, unsigned int position)
{
int tiny = sc->flag & SC_SHOW_TINY_MARKER;
bool show_search = false;
float px[2];
- UI_ThemeColor(TH_MARKER_OUTLINE);
-
px[0] = 1.0f / width / sc->zoom;
px[1] = 1.0f / height / sc->zoom;
- glLineWidth(tiny ? 1.0f : 3.0f);
+ GPU_line_width(tiny ? 1.0f : 3.0f);
+
+ immUniformThemeColor(TH_MARKER_OUTLINE);
if ((marker->flag & MARKER_DISABLED) == 0) {
float pos[2];
@@ -513,52 +577,55 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT
if (isect_point_quad_v2(p, marker->pattern_corners[0], marker->pattern_corners[1],
marker->pattern_corners[2], marker->pattern_corners[3]))
{
- glPointSize(tiny ? 3.0f : 4.0f);
- glBegin(GL_POINTS);
- glVertex2f(pos[0], pos[1]);
- glEnd();
+ GPU_point_size(tiny ? 3.0f : 4.0f);
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2f(position, pos[0], pos[1]);
+ immEnd();
}
else {
- glBegin(GL_LINES);
- glVertex2f(pos[0] + px[0] * 2, pos[1]);
- glVertex2f(pos[0] + px[0] * 8, pos[1]);
+ immBegin(GPU_PRIM_LINES, 8);
+
+ immVertex2f(position, pos[0] + px[0] * 2, pos[1]);
+ immVertex2f(position, pos[0] + px[0] * 8, pos[1]);
- glVertex2f(pos[0] - px[0] * 2, pos[1]);
- glVertex2f(pos[0] - px[0] * 8, pos[1]);
+ immVertex2f(position, pos[0] - px[0] * 2, pos[1]);
+ immVertex2f(position, pos[0] - px[0] * 8, pos[1]);
- glVertex2f(pos[0], pos[1] - px[1] * 2);
- glVertex2f(pos[0], pos[1] - px[1] * 8);
+ immVertex2f(position, pos[0], pos[1] - px[1] * 2);
+ immVertex2f(position, pos[0], pos[1] - px[1] * 8);
- glVertex2f(pos[0], pos[1] + px[1] * 2);
- glVertex2f(pos[0], pos[1] + px[1] * 8);
- glEnd();
+ immVertex2f(position, pos[0], pos[1] + px[1] * 2);
+ immVertex2f(position, pos[0], pos[1] + px[1] * 8);
+
+ immEnd();
}
}
/* pattern and search outline */
- glPushMatrix();
- glTranslate2fv(marker_pos);
+ GPU_matrix_push();
+ GPU_matrix_translate_2fv(marker_pos);
if (sc->flag & SC_SHOW_MARKER_PATTERN) {
- glBegin(GL_LINE_LOOP);
- glVertex2fv(marker->pattern_corners[0]);
- glVertex2fv(marker->pattern_corners[1]);
- glVertex2fv(marker->pattern_corners[2]);
- glVertex2fv(marker->pattern_corners[3]);
- glEnd();
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2fv(position, marker->pattern_corners[0]);
+ immVertex2fv(position, marker->pattern_corners[1]);
+ immVertex2fv(position, marker->pattern_corners[2]);
+ immVertex2fv(position, marker->pattern_corners[3]);
+ immEnd();
}
show_search = (TRACK_VIEW_SELECTED(sc, track) &&
((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0;
+
if (sc->flag & SC_SHOW_MARKER_SEARCH && show_search) {
- glBegin(GL_LINE_LOOP);
- glVertex2f(marker->search_min[0], marker->search_min[1]);
- glVertex2f(marker->search_max[0], marker->search_min[1]);
- glVertex2f(marker->search_max[0], marker->search_max[1]);
- glVertex2f(marker->search_min[0], marker->search_max[1]);
- glEnd();
- }
- glPopMatrix();
+ imm_draw_box_wire_2d(position, marker->search_min[0],
+ marker->search_min[1],
+ marker->search_max[0],
+ marker->search_max[1]);
+ }
+
+ GPU_matrix_pop();
}
static void track_colors(MovieTrackingTrack *track, int act, float col[3], float scol[3])
@@ -582,36 +649,48 @@ static void track_colors(MovieTrackingTrack *track, int act, float col[3], float
}
static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
- const float marker_pos[2], int width, int height, int act, int sel)
+ const float marker_pos[2], int width, int height, int act, int sel, const uint shdr_pos)
{
int tiny = sc->flag & SC_SHOW_TINY_MARKER;
bool show_search = false;
- float col[3], scol[3], px[2];
+ float col[3], scol[3];
+ float px[2];
track_colors(track, act, col, scol);
px[0] = 1.0f / width / sc->zoom;
px[1] = 1.0f / height / sc->zoom;
- glLineWidth(1.0f);
+ GPU_line_width(1.0f);
+
+ /* Since we are switching solid and dashed lines in rather complex logic here, just always go with dashed shader. */
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
/* marker position and offset position */
if ((track->flag & SELECT) == sel && (marker->flag & MARKER_DISABLED) == 0) {
float pos[2], p[2];
if (track->flag & TRACK_LOCKED) {
- if (act)
- UI_ThemeColor(TH_ACT_MARKER);
- else if (track->flag & SELECT)
- UI_ThemeColorShade(TH_LOCK_MARKER, 64);
- else
- UI_ThemeColor(TH_LOCK_MARKER);
+ if (act) {
+ immUniformThemeColor(TH_ACT_MARKER);
+ }
+ else if (track->flag & SELECT) {
+ immUniformThemeColorShade(TH_LOCK_MARKER, 64);
+ }
+ else {
+ immUniformThemeColor(TH_LOCK_MARKER);
+ }
}
else {
- if (track->flag & SELECT)
- glColor3fv(scol);
- else
- glColor3fv(col);
+ immUniformColor3fv((track->flag & SELECT) ? scol : col);
}
add_v2_v2v2(pos, marker->pos, track->offset);
@@ -622,124 +701,115 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
if (isect_point_quad_v2(p, marker->pattern_corners[0], marker->pattern_corners[1],
marker->pattern_corners[2], marker->pattern_corners[3]))
{
- glPointSize(tiny ? 1.0f : 2.0f);
- glBegin(GL_POINTS);
- glVertex2f(pos[0], pos[1]);
- glEnd();
+ GPU_point_size(tiny ? 1.0f : 2.0f);
+
+ immUniform1f("dash_factor", 2.0f); /* Solid "line" */
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2f(shdr_pos, pos[0], pos[1]);
+ immEnd();
}
else {
- glBegin(GL_LINES);
- glVertex2f(pos[0] + px[0] * 3, pos[1]);
- glVertex2f(pos[0] + px[0] * 7, pos[1]);
+ immUniform1f("dash_factor", 2.0f); /* Solid line */
+
+ immBegin(GPU_PRIM_LINES, 8);
+
+ immVertex2f(shdr_pos, pos[0] + px[0] * 3, pos[1]);
+ immVertex2f(shdr_pos, pos[0] + px[0] * 7, pos[1]);
+
+ immVertex2f(shdr_pos, pos[0] - px[0] * 3, pos[1]);
+ immVertex2f(shdr_pos, pos[0] - px[0] * 7, pos[1]);
+
+ immVertex2f(shdr_pos, pos[0], pos[1] - px[1] * 3);
+ immVertex2f(shdr_pos, pos[0], pos[1] - px[1] * 7);
- glVertex2f(pos[0] - px[0] * 3, pos[1]);
- glVertex2f(pos[0] - px[0] * 7, pos[1]);
+ immVertex2f(shdr_pos, pos[0], pos[1] + px[1] * 3);
+ immVertex2f(shdr_pos, pos[0], pos[1] + px[1] * 7);
- glVertex2f(pos[0], pos[1] - px[1] * 3);
- glVertex2f(pos[0], pos[1] - px[1] * 7);
+ immEnd();
- glVertex2f(pos[0], pos[1] + px[1] * 3);
- glVertex2f(pos[0], pos[1] + px[1] * 7);
- glEnd();
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.0f);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- glColor3f(0.0f, 0.0f, 0.0f);
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(3, 0xAAAA);
glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(GL_NOR);
+ glLogicOp(GL_XOR);
- glBegin(GL_LINES);
- glVertex2fv(pos);
- glVertex2fv(marker_pos);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(shdr_pos, pos);
+ immVertex2fv(shdr_pos, marker_pos);
+ immEnd();
glDisable(GL_COLOR_LOGIC_OP);
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
}
}
/* pattern */
- glPushMatrix();
- glTranslate2fv(marker_pos);
+ GPU_matrix_push();
+ GPU_matrix_translate_2fv(marker_pos);
- if (tiny) {
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(3, 0xAAAA);
- }
- else {
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
- }
-
- if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
- if (track->flag & TRACK_LOCKED) {
- if (act)
- UI_ThemeColor(TH_ACT_MARKER);
- else if (track->pat_flag & SELECT)
- UI_ThemeColorShade(TH_LOCK_MARKER, 64);
- else UI_ThemeColor(TH_LOCK_MARKER);
+ if (track->flag & TRACK_LOCKED) {
+ if (act) {
+ immUniformThemeColor(TH_ACT_MARKER);
}
- else if (marker->flag & MARKER_DISABLED) {
- if (act)
- UI_ThemeColor(TH_ACT_MARKER);
- else if (track->pat_flag & SELECT)
- UI_ThemeColorShade(TH_DIS_MARKER, 128);
- else UI_ThemeColor(TH_DIS_MARKER);
+ else if (track->pat_flag & SELECT) {
+ immUniformThemeColorShade(TH_LOCK_MARKER, 64);
}
else {
- if (track->pat_flag & SELECT)
- glColor3fv(scol);
- else glColor3fv(col);
+ immUniformThemeColor(TH_LOCK_MARKER);
}
-
- glBegin(GL_LINE_LOOP);
- glVertex2fv(marker->pattern_corners[0]);
- glVertex2fv(marker->pattern_corners[1]);
- glVertex2fv(marker->pattern_corners[2]);
- glVertex2fv(marker->pattern_corners[3]);
- glEnd();
}
-
- /* search */
- show_search = (TRACK_VIEW_SELECTED(sc, track) &&
- ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0;
- if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) {
- if (track->flag & TRACK_LOCKED) {
- if (act)
- UI_ThemeColor(TH_ACT_MARKER);
- else if (track->search_flag & SELECT)
- UI_ThemeColorShade(TH_LOCK_MARKER, 64);
- else UI_ThemeColor(TH_LOCK_MARKER);
+ else if (marker->flag & MARKER_DISABLED) {
+ if (act) {
+ immUniformThemeColor(TH_ACT_MARKER);
}
- else if (marker->flag & MARKER_DISABLED) {
- if (act)
- UI_ThemeColor(TH_ACT_MARKER);
- else if (track->search_flag & SELECT)
- UI_ThemeColorShade(TH_DIS_MARKER, 128);
- else UI_ThemeColor(TH_DIS_MARKER);
+ else if (track->pat_flag & SELECT) {
+ immUniformThemeColorShade(TH_DIS_MARKER, 128);
}
else {
- if (track->search_flag & SELECT)
- glColor3fv(scol);
- else
- glColor3fv(col);
+ immUniformThemeColor(TH_DIS_MARKER);
}
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(marker->search_min[0], marker->search_min[1]);
- glVertex2f(marker->search_max[0], marker->search_min[1]);
- glVertex2f(marker->search_max[0], marker->search_max[1]);
- glVertex2f(marker->search_min[0], marker->search_max[1]);
- glEnd();
+ }
+ else {
+ immUniformColor3fv((track->pat_flag & SELECT) ? scol : col);
}
if (tiny) {
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
}
else {
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE);
+ immUniform1f("dash_factor", 2.0f); /* Solid line */
+ }
+
+ if ((track->pat_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2fv(shdr_pos, marker->pattern_corners[0]);
+ immVertex2fv(shdr_pos, marker->pattern_corners[1]);
+ immVertex2fv(shdr_pos, marker->pattern_corners[2]);
+ immVertex2fv(shdr_pos, marker->pattern_corners[3]);
+ immEnd();
+ }
+
+ /* search */
+ show_search = (TRACK_VIEW_SELECTED(sc, track) &&
+ ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0;
+
+ if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) {
+ imm_draw_box_wire_2d(shdr_pos, marker->search_min[0], marker->search_min[1],
+ marker->search_max[0], marker->search_max[1]);
}
- glPopMatrix();
+ GPU_matrix_pop();
+
+ /* Restore default shader */
+ immUnbindProgram();
+
+ const uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ BLI_assert(pos == shdr_pos);
+ UNUSED_VARS_NDEBUG(pos);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
}
static float get_shortest_pattern_side(MovieTrackingMarker *marker)
@@ -760,7 +830,7 @@ static float get_shortest_pattern_side(MovieTrackingMarker *marker)
return sqrtf(len_sq);
}
-static void draw_marker_slide_square(float x, float y, float dx, float dy, int outline, float px[2])
+static void draw_marker_slide_square(float x, float y, float dx, float dy, int outline, float px[2], unsigned int pos)
{
float tdx, tdy;
@@ -772,15 +842,10 @@ static void draw_marker_slide_square(float x, float y, float dx, float dy, int o
tdy += px[1];
}
- glBegin(GL_QUADS);
- glVertex3f(x - tdx, y + tdy, 0.0f);
- glVertex3f(x + tdx, y + tdy, 0.0f);
- glVertex3f(x + tdx, y - tdy, 0.0f);
- glVertex3f(x - tdx, y - tdy, 0.0f);
- glEnd();
+ immRectf(pos, x - tdx, y - tdy, x + tdx, y + tdy);
}
-static void draw_marker_slide_triangle(float x, float y, float dx, float dy, int outline, float px[2])
+static void draw_marker_slide_triangle(float x, float y, float dx, float dy, int outline, float px[2], unsigned int pos)
{
float tdx, tdy;
@@ -792,15 +857,16 @@ static void draw_marker_slide_triangle(float x, float y, float dx, float dy, int
tdy += px[1];
}
- glBegin(GL_TRIANGLES);
- glVertex3f(x, y, 0.0f);
- glVertex3f(x - tdx, y, 0.0f);
- glVertex3f(x, y + tdy, 0.0f);
- glEnd();
+ immBegin(GPU_PRIM_TRIS, 3);
+ immVertex2f(pos, x, y);
+ immVertex2f(pos, x - tdx, y);
+ immVertex2f(pos, x, y + tdy);
+ immEnd();
}
static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
- const float marker_pos[2], int outline, int sel, int act, int width, int height)
+ const float marker_pos[2], int outline, int sel, int act,
+ int width, int height, unsigned int pos)
{
float dx, dy, patdx, patdy, searchdx, searchdy;
int tiny = sc->flag & SC_SHOW_TINY_MARKER;
@@ -815,11 +881,11 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
track_colors(track, act, col, scol);
if (outline) {
- UI_ThemeColor(TH_MARKER_OUTLINE);
+ immUniformThemeColor(TH_MARKER_OUTLINE);
}
- glPushMatrix();
- glTranslate2fv(marker_pos);
+ GPU_matrix_push();
+ GPU_matrix_translate_2fv(marker_pos);
dx = 6.0f / width / sc->zoom;
dy = 6.0f / height / sc->zoom;
@@ -836,17 +902,14 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
if ((sc->flag & SC_SHOW_MARKER_SEARCH) && ((track->search_flag & SELECT) == sel || outline)) {
if (!outline) {
- if (track->search_flag & SELECT)
- glColor3fv(scol);
- else
- glColor3fv(col);
+ immUniformColor3fv((track->search_flag & SELECT) ? scol : col);
}
/* search offset square */
- draw_marker_slide_square(marker->search_min[0], marker->search_max[1], searchdx, searchdy, outline, px);
+ draw_marker_slide_square(marker->search_min[0], marker->search_max[1], searchdx, searchdy, outline, px, pos);
/* search re-sizing triangle */
- draw_marker_slide_triangle(marker->search_max[0], marker->search_min[1], searchdx, searchdy, outline, px);
+ draw_marker_slide_triangle(marker->search_max[0], marker->search_min[1], searchdx, searchdy, outline, px, pos);
}
if ((sc->flag & SC_SHOW_MARKER_PATTERN) && ((track->pat_flag & SELECT) == sel || outline)) {
@@ -856,16 +919,13 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
float tilt_ctrl[2];
if (!outline) {
- if (track->pat_flag & SELECT)
- glColor3fv(scol);
- else
- glColor3fv(col);
+ immUniformColor3fv((track->pat_flag & SELECT) ? scol : col);
}
/* pattern's corners sliding squares */
for (i = 0; i < 4; i++) {
draw_marker_slide_square(marker->pattern_corners[i][0], marker->pattern_corners[i][1],
- patdx / 1.5f, patdy / 1.5f, outline, px);
+ patdx / 1.5f, patdy / 1.5f, outline, px, pos);
}
/* ** sliders to control overall pattern ** */
@@ -873,20 +933,18 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
- glLineWidth(outline ? 3.0f : 1.0f);
-
- glBegin(GL_LINES);
- glVertex2f(0.0f, 0.0f);
- glVertex2fv(tilt_ctrl);
- glEnd();
+ GPU_line_width(outline ? 3.0f : 1.0f);
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, 0.0f, 0.0f);
+ immVertex2fv(pos, tilt_ctrl);
+ immEnd();
/* slider to control pattern tilt */
- draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px);
+ draw_marker_slide_square(tilt_ctrl[0], tilt_ctrl[1], patdx, patdy, outline, px, pos);
}
- glPopMatrix();
+ GPU_matrix_pop();
}
static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
@@ -904,16 +962,17 @@ static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
fontsize = BLF_height_max(fontid);
if (marker->flag & MARKER_DISABLED) {
- if (act)
- UI_ThemeColor(TH_ACT_MARKER);
- else
- UI_ThemeColorShade(TH_DIS_MARKER, 128);
+ if (act) {
+ UI_FontThemeColor(fontid, TH_ACT_MARKER);
+ }
+ else {
+ unsigned char color[4];
+ UI_GetThemeColorShade4ubv(TH_DIS_MARKER, 128, color);
+ BLF_color4ubv(fontid, color);
+ }
}
else {
- if (act)
- UI_ThemeColor(TH_ACT_MARKER);
- else
- UI_ThemeColor(TH_SEL_MARKER);
+ UI_FontThemeColor(fontid, act ? TH_ACT_MARKER : TH_SEL_MARKER);
}
if ((sc->flag & SC_SHOW_MARKER_SEARCH) &&
@@ -974,10 +1033,7 @@ static void plane_track_colors(bool is_active, float color[3], float selected_co
{
UI_GetThemeColor3fv(TH_MARKER, color);
- if (is_active)
- UI_GetThemeColor3fv(TH_ACT_MARKER, selected_color);
- else
- UI_GetThemeColor3fv(TH_SEL_MARKER, selected_color);
+ UI_GetThemeColor3fv(is_active ? TH_ACT_MARKER : TH_SEL_MARKER, selected_color);
}
static void getArrowEndPoint(const int width, const int height, const float zoom,
@@ -1070,15 +1126,13 @@ static void draw_plane_marker_image(Scene *scene,
if (plane_track->image_opacity != 1.0f || ibuf->planes == 32) {
transparent = true;
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
}
- glColor4f(1.0, 1.0, 1.0, plane_track->image_opacity);
-
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
glGenTextures(1, (GLuint *)&texid);
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -1087,23 +1141,41 @@ static void draw_plane_marker_image(Scene *scene,
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, GL_RGBA,
GL_UNSIGNED_BYTE, display_buffer);
- glPushMatrix();
- glMultMatrixf(gl_matrix);
+ GPU_matrix_push();
+ GPU_matrix_mul(gl_matrix);
+
+ GPUVertFormat *imm_format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint texCoord = GPU_vertformat_attr_add(imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, plane_track->image_opacity);
+ immUniform1i("image", 0);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, 0.0f, 0.0f);
+
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, 1.0f, 0.0f);
+
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, 1.0f, 1.0f);
+
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, 0.0f, 1.0f);
+
+ immEnd();
- glBegin(GL_QUADS);
- glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f);
- glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, 0.0f);
- glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
- glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 1.0f);
- glEnd();
+ immUnbindProgram();
- glPopMatrix();
+ GPU_matrix_pop();
glBindTexture(GL_TEXTURE_2D, 0);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
if (transparent) {
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
}
@@ -1123,20 +1195,7 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
BKE_image_has_ibuf(plane_track->image, NULL);
const bool draw_plane_quad = !has_image || plane_track->image_opacity == 0.0f;
float px[2];
-
- if (draw_outline) {
- UI_ThemeColor(TH_MARKER_OUTLINE);
- }
- else {
- float color[3], selected_color[3];
- plane_track_colors(is_active_track, color, selected_color);
- if (is_selected_track) {
- glColor3fv(selected_color);
- }
- else {
- glColor3fv(color);
- }
- }
+ float color[3], selected_color[3];
px[0] = 1.0f / width / sc->zoom;
px[1] = 1.0f / height / sc->zoom;
@@ -1146,66 +1205,92 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
draw_plane_marker_image(scene, plane_track, plane_marker);
}
- if (draw_plane_quad) {
+ if (draw_plane_quad || is_selected_track) {
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- const bool stipple = !draw_outline && tiny;
- const bool thick = draw_outline && !tiny;
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- if (stipple) {
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(3, 0xAAAA);
- }
- else {
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE);
- }
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- GPU_basic_shader_line_width(thick ? 3.0f : 1.0f);
+ immUniform1i("colors_len", 0); /* "simple" mode */
- /* Draw rectangle itself. */
- glBegin(GL_LINE_LOOP);
- glVertex2fv(plane_marker->corners[0]);
- glVertex2fv(plane_marker->corners[1]);
- glVertex2fv(plane_marker->corners[2]);
- glVertex2fv(plane_marker->corners[3]);
- glEnd();
+ if (draw_plane_quad) {
+ const bool stipple = !draw_outline && tiny;
+ const bool thick = draw_outline && !tiny;
- /* Draw axis. */
- if (!draw_outline) {
- float end_point[2];
- glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT);
+ GPU_line_width(thick ? 3.0f : 1.0f);
- glBegin(GL_LINES);
+ if (stipple) {
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+ }
+ else {
+ immUniform1f("dash_factor", 2.0f); /* Solid line */
+ }
- getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[1], end_point);
- glColor3f(1.0, 0.0, 0.0f);
- glVertex2fv(plane_marker->corners[0]);
- glVertex2fv(end_point);
+ if (draw_outline) {
+ immUniformThemeColor(TH_MARKER_OUTLINE);
+ }
+ else {
+ plane_track_colors(is_active_track, color, selected_color);
+ immUniformColor3fv(is_selected_track ? selected_color : color);
+ }
- getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[3], end_point);
- glColor3f(0.0, 1.0, 0.0f);
- glVertex2fv(plane_marker->corners[0]);
- glVertex2fv(end_point);
+ /* Draw rectangle itself. */
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2fv(shdr_pos, plane_marker->corners[0]);
+ immVertex2fv(shdr_pos, plane_marker->corners[1]);
+ immVertex2fv(shdr_pos, plane_marker->corners[2]);
+ immVertex2fv(shdr_pos, plane_marker->corners[3]);
+ immEnd();
- glEnd();
+ /* Draw axis. */
+ if (!draw_outline) {
+ float end_point[2];
- glPopAttrib();
- }
+ immUniformColor3f(1.0f, 0.0f, 0.0f);
- if (stipple) {
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- }
- else {
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE);
+ immBegin(GPU_PRIM_LINES, 2);
+
+ getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[1], end_point);
+ immVertex2fv(shdr_pos, plane_marker->corners[0]);
+ immVertex2fv(shdr_pos, end_point);
+
+ immEnd();
+
+ immUniformColor3f(0.0f, 1.0f, 0.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[3], end_point);
+ immVertex2fv(shdr_pos, plane_marker->corners[0]);
+ immVertex2fv(shdr_pos, end_point);
+
+ immEnd();
+ }
}
- }
- /* Draw sliders. */
- if (is_selected_track) {
- int i;
- for (i = 0; i < 4; i++) {
- draw_marker_slide_square(plane_marker->corners[i][0], plane_marker->corners[i][1],
- 3.0f * px[0], 3.0f * px[1], draw_outline, px);
+ /* Draw sliders. */
+ if (is_selected_track) {
+ immUniform1f("dash_factor", 2.0f); /* Solid line */
+
+ if (draw_outline) {
+ immUniformThemeColor(TH_MARKER_OUTLINE);
+ }
+ else {
+ immUniformColor3fv(selected_color);
+ }
+
+ int i;
+ for (i = 0; i < 4; i++) {
+ draw_marker_slide_square(plane_marker->corners[i][0], plane_marker->corners[i][1],
+ 3.0f * px[0], 3.0f * px[1], draw_outline, px, shdr_pos);
+ }
}
+
+ immUnbindProgram();
}
}
@@ -1257,13 +1342,13 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
UI_view2d_view_to_region_fl(&ar->v2d, 0.0f, 0.0f, &x, &y);
- glPushMatrix();
- glTranslatef(x, y, 0);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(x, y);
- glPushMatrix();
- glScalef(zoomx, zoomy, 0);
- glMultMatrixf(sc->stabmat);
- glScalef(width, height, 0);
+ GPU_matrix_push();
+ GPU_matrix_scale_2f(zoomx, zoomy);
+ GPU_matrix_mul(sc->stabmat);
+ GPU_matrix_scale_2f(width, height);
act_track = BKE_tracking_track_get_active(tracking);
@@ -1329,6 +1414,10 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
}
}
+ uint position = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* markers outline and non-selected areas */
track = tracksbase->first;
fp = marker_pos;
@@ -1339,10 +1428,10 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
if (MARKER_VISIBLE(sc, track, marker)) {
copy_v2_v2(cur_pos, fp ? fp : marker->pos);
- draw_marker_outline(sc, track, marker, cur_pos, width, height);
- draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 0);
- draw_marker_slide_zones(sc, track, marker, cur_pos, 1, 0, 0, width, height);
- draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 0, 0, width, height);
+ draw_marker_outline(sc, track, marker, cur_pos, width, height, position);
+ draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 0, position);
+ draw_marker_slide_zones(sc, track, marker, cur_pos, 1, 0, 0, width, height, position);
+ draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 0, 0, width, height, position);
if (fp)
fp += 2;
@@ -1365,8 +1454,8 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
if (!act) {
copy_v2_v2(cur_pos, fp ? fp : marker->pos);
- draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 1);
- draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 1, 0, width, height);
+ draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 1, position);
+ draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 1, 0, width, height, position);
}
if (fp)
@@ -1385,8 +1474,8 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
if (MARKER_VISIBLE(sc, act_track, marker)) {
copy_v2_v2(cur_pos, active_pos ? active_pos : marker->pos);
- draw_marker_areas(sc, act_track, marker, cur_pos, width, height, 1, 1);
- draw_marker_slide_zones(sc, act_track, marker, cur_pos, 0, 1, 1, width, height);
+ draw_marker_areas(sc, act_track, marker, cur_pos, width, height, 1, 1, position);
+ draw_marker_slide_zones(sc, act_track, marker, cur_pos, 0, 1, 1, width, height, position);
}
}
}
@@ -1395,8 +1484,7 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
float pos[4], vec[4], mat[4][4], aspy;
- glEnable(GL_POINT_SMOOTH);
- glPointSize(3.0f);
+ GPU_point_size(3.0f);
aspy = 1.0f / clip->tracking.camera.pixel_aspect;
BKE_tracking_get_projection_matrix(tracking, object, framenr, width, height, mat);
@@ -1424,28 +1512,34 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
sub_v2_v2(vec, npos);
- if (len_squared_v2(vec) < (3.0f * 3.0f))
- glColor3f(0.0f, 1.0f, 0.0f);
- else
- glColor3f(1.0f, 0.0f, 0.0f);
+ if (len_squared_v2(vec) < (3.0f * 3.0f)) {
+ immUniformColor3f(0.0f, 1.0f, 0.0f);
+ }
+ else {
+ immUniformColor3f(1.0f, 0.0f, 0.0f);
+ }
- glBegin(GL_POINTS);
- if (undistort)
- glVertex3f(pos[0] / width, pos[1] / (height * aspy), 0);
- else
- glVertex3f(npos[0] / width, npos[1] / (height * aspy), 0);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+
+ if (undistort) {
+ immVertex2f(position, pos[0] / width, pos[1] / (height * aspy));
+ }
+ else {
+ immVertex2f(position, npos[0] / width, npos[1] / (height * aspy));
+ }
+
+ immEnd();
}
}
}
track = track->next;
}
-
- glDisable(GL_POINT_SMOOTH);
}
- glPopMatrix();
+ immUnbindProgram();
+
+ GPU_matrix_pop();
if (sc->flag & SC_SHOW_NAMES) {
/* scaling should be cleared before drawing texts, otherwise font would also be scaled */
@@ -1471,7 +1565,7 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
}
}
- glPopMatrix();
+ GPU_matrix_pop();
if (marker_pos)
MEM_freeN(marker_pos);
@@ -1498,11 +1592,15 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
UI_view2d_view_to_region_fl(&ar->v2d, 0.0f, 0.0f, &x, &y);
- glPushMatrix();
- glTranslatef(x, y, 0);
- glScalef(zoomx, zoomy, 0);
- glMultMatrixf(sc->stabmat);
- glScalef(width, height, 0);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_scale_2f(zoomx, zoomy);
+ GPU_matrix_mul(sc->stabmat);
+ GPU_matrix_scale_2f(width, height);
+
+ uint position = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* grid */
if (sc->flag & SC_SHOW_GRID) {
@@ -1574,22 +1672,26 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
pos[1] += dy;
}
- glColor3f(1.0f, 0.0f, 0.0f);
+ immUniformColor3f(1.0f, 0.0f, 0.0f);
for (i = 0; i <= n; i++) {
- glBegin(GL_LINE_STRIP);
+ immBegin(GPU_PRIM_LINE_STRIP, n + 1);
+
for (j = 0; j <= n; j++) {
- glVertex2fv(grid[i][j]);
+ immVertex2fv(position, grid[i][j]);
}
- glEnd();
+
+ immEnd();
}
for (j = 0; j <= n; j++) {
- glBegin(GL_LINE_STRIP);
+ immBegin(GPU_PRIM_LINE_STRIP, n + 1);
+
for (i = 0; i <= n; i++) {
- glVertex2fv(grid[i][j]);
+ immVertex2fv(position, grid[i][j]);
}
- glEnd();
+
+ immEnd();
}
}
@@ -1608,9 +1710,10 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
continue;
}
- glColor4fv(layer->color);
- glLineWidth(layer->thickness);
- glPointSize((float)(layer->thickness + 2));
+ immUniformColor4fv(layer->color);
+
+ GPU_line_width(layer->thickness);
+ GPU_point_size((float)(layer->thickness + 2));
while (frame) {
bGPDstroke *stroke = frame->strokes.first;
@@ -1618,7 +1721,6 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
while (stroke) {
if (stroke->flag & GP_STROKE_2DSPACE) {
if (stroke->totpoints > 1) {
- glBegin(GL_LINE_STRIP);
for (i = 0; i < stroke->totpoints - 1; i++) {
float npos[2], dpos[2], len;
int steps;
@@ -1641,19 +1743,22 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
sub_v2_v2v2(dpos, npos, pos);
mul_v2_fl(dpos, 1.0f / steps);
+ immBegin(GPU_PRIM_LINE_STRIP, steps + 1);
+
for (j = 0; j <= steps; j++) {
BKE_tracking_distort_v2(tracking, pos, tpos);
- glVertex2f(tpos[0] / width, tpos[1] / (height * aspy));
+ immVertex2f(position, tpos[0] / width, tpos[1] / (height * aspy));
add_v2_v2(pos, dpos);
}
+
+ immEnd();
}
- glEnd();
}
else if (stroke->totpoints == 1) {
- glBegin(GL_POINTS);
- glVertex2f(stroke->points[0].x + offsx, stroke->points[0].y + offsy);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2f(position, stroke->points[0].x + offsx, stroke->points[0].y + offsy);
+ immEnd();
}
}
@@ -1667,7 +1772,9 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
}
}
- glPopMatrix();
+ immUnbindProgram();
+
+ GPU_matrix_pop();
}
void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
@@ -1764,8 +1871,8 @@ void clip_draw_grease_pencil(bContext *C, int onlyv2d)
* associated with the clip is already drawn in draw_distortion
*/
if ((sc->flag & SC_MANUAL_CALIBRATION) == 0 || is_track_source) {
- glPushMatrix();
- glMultMatrixf(sc->unistabmat);
+ GPU_matrix_push();
+ GPU_matrix_mul(sc->unistabmat);
if (is_track_source) {
MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking);
@@ -1774,13 +1881,13 @@ void clip_draw_grease_pencil(bContext *C, int onlyv2d)
int framenr = ED_space_clip_get_clip_frame_number(sc);
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- glTranslate2fv(marker->pos);
+ GPU_matrix_translate_2fv(marker->pos);
}
}
ED_gpencil_draw_2dimage(C);
- glPopMatrix();
+ GPU_matrix_pop();
}
}
else {
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 30628b417d4..8308c781902 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -50,13 +50,13 @@
#include "BLI_rect.h"
#include "BLI_task.h"
+#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_movieclip.h"
-#include "BKE_context.h"
#include "BKE_tracking.h"
-#include "BKE_library.h"
#include "IMB_colormanagement.h"
@@ -305,15 +305,12 @@ bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r
void ED_clip_update_frame(const Main *mainp, int cfra)
{
- wmWindowManager *wm;
- wmWindow *win;
-
/* image window, compo node users */
- for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
- for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
+ for (wmWindowManager *wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_CLIP) {
SpaceClip *sc = sa->spacedata.first;
diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c
index 424d25defdd..cc8541d9fd7 100644
--- a/source/blender/editors/space_clip/clip_graph_draw.c
+++ b/source/blender/editors/space_clip/clip_graph_draw.c
@@ -42,7 +42,10 @@
#include "ED_screen.h"
#include "ED_clip.h"
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "WM_types.h"
@@ -53,76 +56,54 @@
#include "clip_intern.h" // own include
-static void draw_curve_knot(float x, float y, float xscale, float yscale, float hsize)
-{
- static GLuint displist = 0;
-
- /* initialize round circle shape */
- if (displist == 0) {
- GLUquadricObj *qobj;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
- gluDisk(qobj, 0, 0.7, 8, 1);
- gluDeleteQuadric(qobj);
-
- glEndList();
- }
-
- glPushMatrix();
-
- glTranslatef(x, y, 0.0f);
- glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f);
- glCallList(displist);
-
- glPopMatrix();
-}
+typedef struct TrackMotionCurveUserData {
+ MovieTrackingTrack *act_track;
+ bool sel;
+ float xscale, yscale, hsize;
+ unsigned int pos;
+} TrackMotionCurveUserData;
-static void tracking_segment_point_cb(void *UNUSED(userdata), MovieTrackingTrack *UNUSED(track),
+static void tracking_segment_point_cb(void *userdata, MovieTrackingTrack *UNUSED(track),
MovieTrackingMarker *UNUSED(marker), int UNUSED(coord),
int scene_framenr, float val)
{
- glVertex2f(scene_framenr, val);
+ TrackMotionCurveUserData *data = (TrackMotionCurveUserData *) userdata;
+
+ immVertex2f(data->pos, scene_framenr, val);
}
-static void tracking_segment_start_cb(void *userdata, MovieTrackingTrack *track, int coord)
+static void tracking_segment_start_cb(void *userdata, MovieTrackingTrack *track, int coord, bool is_point)
{
- const float colors[2][3] = {
- {1.0f, 0.0f, 0.0f},
- {0.0f, 1.0f, 0.0f},
- };
- float col[4];
+ TrackMotionCurveUserData *data = (TrackMotionCurveUserData *) userdata;
+ float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- copy_v3_v3(col, colors[coord]);
+ col[coord] = 1.0f;
- if (track == userdata) {
+ if (track == data->act_track) {
col[3] = 1.0f;
- glLineWidth(2.0f);
+ GPU_line_width(2.0f);
}
else {
col[3] = 0.5f;
- glLineWidth(1.0f);
+ GPU_line_width(1.0f);
}
- glColor4fv(col);
+ immUniformColor4fv(col);
- glBegin(GL_LINE_STRIP);
+ if (is_point) {
+ immBeginAtMost(GPU_PRIM_POINTS, 1);
+ }
+ else {
+ /* Graph can be composed of smaller segments, if any marker is disabled */
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, track->markersnr);
+ }
}
static void tracking_segment_end_cb(void *UNUSED(userdata), int UNUSED(coord))
{
- glEnd();
+ immEnd();
}
-typedef struct TrackMotionCurveUserData {
- MovieTrackingTrack *act_track;
- bool sel;
- float xscale, yscale, hsize;
-} TrackMotionCurveUserData;
-
static void tracking_segment_knot_cb(void *userdata, MovieTrackingTrack *track,
MovieTrackingMarker *marker, int coord, int scene_framenr, float val)
{
@@ -136,16 +117,19 @@ static void tracking_segment_knot_cb(void *userdata, MovieTrackingTrack *track,
sel = (marker->flag & sel_flag) ? 1 : 0;
if (sel == data->sel) {
- if (sel)
- UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
- else
- UI_ThemeColor(TH_HANDLE_VERTEX);
+ immUniformThemeColor(sel ? TH_HANDLE_VERTEX_SELECT : TH_HANDLE_VERTEX);
+
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(scene_framenr, val);
+ GPU_matrix_scale_2f(1.0f / data->xscale * data->hsize, 1.0f / data->yscale * data->hsize);
+
+ imm_draw_circle_wire_2d(data->pos, 0, 0, 0.7, 8);
- draw_curve_knot(scene_framenr, val, data->xscale, data->yscale, data->hsize);
+ GPU_matrix_pop();
}
}
-static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc)
+static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc, unsigned int pos)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
@@ -162,20 +146,20 @@ static void draw_tracks_motion_curves(View2D *v2d, SpaceClip *sc)
userdata.hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE);
userdata.sel = false;
userdata.act_track = act_track;
+ userdata.pos = pos;
UI_view2d_scale_get(v2d, &userdata.xscale, &userdata.yscale);
clip_graph_tracking_values_iterate(sc,
(sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
(sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
&userdata, tracking_segment_knot_cb, NULL, NULL);
-
/* draw graph lines */
- glEnable(GL_BLEND);
+ GPU_blend(true);
clip_graph_tracking_values_iterate(sc,
(sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
(sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
- act_track, tracking_segment_point_cb, tracking_segment_start_cb,
+ &userdata, tracking_segment_point_cb, tracking_segment_start_cb,
tracking_segment_end_cb);
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* selected knot handles on top of curves */
userdata.sel = true;
@@ -195,6 +179,7 @@ typedef struct TrackErrorCurveUserData {
float projection_matrix[4][4];
int width, height;
float aspy;
+ unsigned int pos;
} TrackErrorCurveUserData;
static void tracking_error_segment_point_cb(void *userdata,
@@ -230,11 +215,11 @@ static void tracking_error_segment_point_cb(void *userdata,
sub_v2_v2v2(delta, reprojected_position, marker_position);
reprojection_error = len_v2(delta) * weight;
- glVertex2f(scene_framenr, reprojection_error);
+ immVertex2f(data->pos, scene_framenr, reprojection_error);
}
}
-static void tracking_error_segment_start_cb(void *userdata, MovieTrackingTrack *track, int coord)
+static void tracking_error_segment_start_cb(void *userdata, MovieTrackingTrack *track, int coord, bool is_point)
{
if (coord == 1) {
TrackErrorCurveUserData *data = (TrackErrorCurveUserData *) userdata;
@@ -242,27 +227,33 @@ static void tracking_error_segment_start_cb(void *userdata, MovieTrackingTrack *
if (track == data->active_track) {
col[3] = 1.0f;
- glLineWidth(2.0f);
+ GPU_line_width(2.0f);
}
else {
col[3] = 0.5f;
- glLineWidth(1.0f);
+ GPU_line_width(1.0f);
}
- glColor4fv(col);
+ immUniformColor4fv(col);
- glBegin(GL_LINE_STRIP);
+ if (is_point) { /* This probably never happens here, but just in case... */
+ immBeginAtMost(GPU_PRIM_POINTS, 1);
+ }
+ else {
+ /* Graph can be composed of smaller segments, if any marker is disabled */
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, track->markersnr);
+ }
}
}
static void tracking_error_segment_end_cb(void *UNUSED(userdata), int coord)
{
if (coord == 1) {
- glEnd();
+ immEnd();
}
}
-static void draw_tracks_error_curves(SpaceClip *sc)
+static void draw_tracks_error_curves(SpaceClip *sc, unsigned int pos)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
@@ -273,6 +264,7 @@ static void draw_tracks_error_curves(SpaceClip *sc)
data.tracking_object = BKE_tracking_object_get_active(tracking);
data.active_track = BKE_tracking_track_get_active(tracking);
data.matrix_initialized = false;
+ data.pos = pos;
BKE_movieclip_get_size(clip, &sc->user, &data.width, &data.height);
data.aspy = 1.0f / tracking->camera.pixel_aspect;
@@ -289,37 +281,38 @@ static void draw_tracks_error_curves(SpaceClip *sc)
tracking_error_segment_end_cb);
}
-static void draw_frame_curves(SpaceClip *sc)
+static void draw_frame_curves(SpaceClip *sc, unsigned int pos)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
int i, lines = 0, prevfra = 0;
- glColor3f(0.0f, 0.0f, 1.0f);
+ immUniformColor3f(0.0f, 0.0f, 1.0f);
for (i = 0; i < reconstruction->camnr; i++) {
MovieReconstructedCamera *camera = &reconstruction->cameras[i];
int framenr;
if (lines && camera->framenr != prevfra + 1) {
- glEnd();
+ immEnd();
lines = 0;
}
if (!lines) {
- glBegin(GL_LINE_STRIP);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, reconstruction->camnr);
lines = 1;
}
framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, camera->framenr);
- glVertex2f(framenr, camera->error);
+ immVertex2f(pos, framenr, camera->error);
prevfra = camera->framenr;
}
- if (lines)
- glEnd();
+ if (lines) {
+ immEnd();
+ }
}
void clip_draw_graph(SpaceClip *sc, ARegion *ar, Scene *scene)
@@ -335,19 +328,26 @@ void clip_draw_graph(SpaceClip *sc, ARegion *ar, Scene *scene)
UI_view2d_grid_free(grid);
if (clip) {
- if (sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION)
- draw_tracks_motion_curves(v2d, sc);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ GPU_point_size(3.0f);
+
+ if (sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) {
+ draw_tracks_motion_curves(v2d, sc, pos);
+ }
- if (sc->flag & SC_SHOW_GRAPH_TRACKS_ERROR)
- draw_tracks_error_curves(sc);
+ if (sc->flag & SC_SHOW_GRAPH_TRACKS_ERROR) {
+ draw_tracks_error_curves(sc, pos);
+ }
- if (sc->flag & SC_SHOW_GRAPH_FRAMES)
- draw_frame_curves(sc);
+ if (sc->flag & SC_SHOW_GRAPH_FRAMES) {
+ draw_frame_curves(sc, pos);
+ }
+
+ immUnbindProgram();
}
/* frame range */
clip_draw_sfra_efra(v2d, scene);
-
- /* current frame */
- clip_draw_cfra(sc, ar, scene);
}
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index 2c6aad36b2a..06233d64a36 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -37,12 +37,14 @@
#include "BKE_context.h"
#include "BKE_tracking.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_clip.h"
#include "RNA_access.h"
@@ -327,17 +329,17 @@ void CLIP_OT_graph_select(wmOperatorType *ot)
"Extend", "Extend selection rather than clearing the existing selection");
}
-/********************** border select operator *********************/
+/********************** box select operator *********************/
-typedef struct BorderSelectuserData {
+typedef struct BoxSelectuserData {
rctf rect;
bool select, extend, changed;
-} BorderSelectuserData;
+} BoxSelectuserData;
-static void border_select_cb(void *userdata, MovieTrackingTrack *UNUSED(track),
+static void box_select_cb(void *userdata, MovieTrackingTrack *UNUSED(track),
MovieTrackingMarker *marker, int coord, int scene_framenr, float val)
{
- BorderSelectuserData *data = (BorderSelectuserData *) userdata;
+ BoxSelectuserData *data = (BoxSelectuserData *) userdata;
if (BLI_rctf_isect_pt(&data->rect, scene_framenr, val)) {
int flag = 0;
@@ -360,7 +362,7 @@ static void border_select_cb(void *userdata, MovieTrackingTrack *UNUSED(track),
}
}
-static int border_select_graph_exec(bContext *C, wmOperator *op)
+static int box_select_graph_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -368,7 +370,7 @@ static int border_select_graph_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
- BorderSelectuserData userdata;
+ BoxSelectuserData userdata;
rctf rect;
if (act_track == NULL) {
@@ -383,7 +385,7 @@ static int border_select_graph_exec(bContext *C, wmOperator *op)
userdata.select = !RNA_boolean_get(op->ptr, "deselect");
userdata.extend = RNA_boolean_get(op->ptr, "extend");
- clip_graph_tracking_values_iterate_track(sc, act_track, &userdata, border_select_cb, NULL, NULL);
+ clip_graph_tracking_values_iterate_track(sc, act_track, &userdata, box_select_cb, NULL, NULL);
if (userdata.changed) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
@@ -394,24 +396,24 @@ static int border_select_graph_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-void CLIP_OT_graph_select_border(wmOperatorType *ot)
+void CLIP_OT_graph_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->description = "Select curve points using border selection";
- ot->idname = "CLIP_OT_graph_select_border";
+ ot->name = "Box Select";
+ ot->description = "Select curve points using box selection";
+ ot->idname = "CLIP_OT_graph_select_box";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = border_select_graph_exec;
- ot->modal = WM_gesture_border_modal;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = box_select_graph_exec;
+ ot->modal = WM_gesture_box_modal;
ot->poll = clip_graph_knots_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
/********************** select all operator *********************/
@@ -691,7 +693,7 @@ static int graph_disable_markers_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index ae15834a1d9..b407056ea96 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -84,7 +84,7 @@ void clip_draw_graph(struct SpaceClip *sc, struct ARegion *ar, struct Scene *sce
void ED_clip_graph_center_current_frame(struct Scene *scene, struct ARegion *ar);
void CLIP_OT_graph_select(struct wmOperatorType *ot);
-void CLIP_OT_graph_select_border(struct wmOperatorType *ot);
+void CLIP_OT_graph_select_box(struct wmOperatorType *ot);
void CLIP_OT_graph_select_all_markers(struct wmOperatorType *ot);
void CLIP_OT_graph_delete_curve(struct wmOperatorType *ot);
void CLIP_OT_graph_delete_knot(struct wmOperatorType *ot);
@@ -125,12 +125,12 @@ void ED_clip_tool_props_register(struct ARegionType *art);
/* clip_utils.c */
void clip_graph_tracking_values_iterate_track(struct SpaceClip *sc, struct MovieTrackingTrack *track, void *userdata,
void (*func)(void *userdata, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, int coord, int scene_framenr, float val),
- void (*segment_start)(void *userdata, struct MovieTrackingTrack *track, int coord),
+ void (*segment_start)(void *userdata, struct MovieTrackingTrack *track, int coord, bool is_point),
void (*segment_end)(void *userdata, int coord));
void clip_graph_tracking_values_iterate(struct SpaceClip *sc, bool selected_only, bool include_hidden, void *userdata,
void (*func)(void *userdata, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, int coord, int scene_framenr, float val),
- void (*segment_start)(void *userdata, struct MovieTrackingTrack *track, int coord),
+ void (*segment_start)(void *userdata, struct MovieTrackingTrack *track, int coord, bool is_point),
void (*segment_end)(void *userdata, int coord));
void clip_graph_tracking_iterate(struct SpaceClip *sc, bool selected_only, bool include_hidden, void *userdata,
@@ -143,9 +143,10 @@ void clip_delete_plane_track(struct bContext *C, struct MovieClip *clip, struct
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
-void clip_draw_cfra(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scene);
void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene);
+void clip_on_marker_selection_changed(struct bContext *C);
+
/* tracking_ops.c */
struct MovieTrackingTrack *tracking_marker_check_slide(struct bContext *C, const struct wmEvent *event,
int *area_r, int *action_r, int *corner_r);
@@ -211,7 +212,7 @@ void CLIP_OT_keyframe_delete(struct wmOperatorType *ot);
/* tracking_select.c */
void CLIP_OT_select(struct wmOperatorType *ot);
void CLIP_OT_select_all(struct wmOperatorType *ot);
-void CLIP_OT_select_border(struct wmOperatorType *ot);
+void CLIP_OT_select_box(struct wmOperatorType *ot);
void CLIP_OT_select_lasso(struct wmOperatorType *ot);
void CLIP_OT_select_circle(struct wmOperatorType *ot);
void CLIP_OT_select_grouped(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 1d9669e3e97..e56ec98a232 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -56,11 +56,10 @@
#include "BKE_context.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
-#include "BKE_report.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_movieclip.h"
+#include "BKE_report.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
@@ -83,6 +82,8 @@
#include "PIL_time.h"
+#include "DEG_depsgraph_build.h"
+
#include "clip_intern.h" // own include
/******************** view navigation utilities *********************/
@@ -253,7 +254,7 @@ static int open_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_MOVIECLIP | NA_ADDED, clip);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
MEM_freeN(op->customdata);
return OPERATOR_FINISHED;
@@ -471,7 +472,7 @@ static void view_pan_cancel(bContext *C, wmOperator *op)
void CLIP_OT_view_pan(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Pan";
+ ot->name = "Pan View";
ot->idname = "CLIP_OT_view_pan";
ot->description = "Pan the view";
diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c
index 7d4aa0083f1..304954b56e3 100644
--- a/source/blender/editors/space_clip/clip_toolbar.c
+++ b/source/blender/editors/space_clip/clip_toolbar.c
@@ -32,6 +32,7 @@
#include <string.h>
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
@@ -105,7 +106,7 @@ static int properties_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_properties(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Properties";
+ ot->name = "Toggle Sidebar";
ot->description = "Toggle the properties region visibility";
ot->idname = "CLIP_OT_properties";
@@ -118,19 +119,17 @@ void CLIP_OT_properties(wmOperatorType *ot)
static ARegion *clip_has_tools_region(ScrArea *sa)
{
- ARegion *ar, *artool = NULL, *arprops = NULL, *arhead;
+ ARegion *ar, *artool = NULL, *arhead;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_TOOLS)
artool = ar;
-
- if (ar->regiontype == RGN_TYPE_TOOL_PROPS)
- arprops = ar;
}
/* tool region hide/unhide also hides props */
- if (arprops && artool)
+ if (artool) {
return artool;
+ }
if (artool == NULL) {
/* add subdiv level; after header */
@@ -149,15 +148,6 @@ static ARegion *clip_has_tools_region(ScrArea *sa)
artool->flag = RGN_FLAG_HIDDEN;
}
- if (arprops == NULL) {
- /* add extra subdivided region for tool properties */
- arprops = MEM_callocN(sizeof(ARegion), "tool props for clip");
-
- BLI_insertlinkafter(&sa->regionbase, artool, arprops);
- arprops->regiontype = RGN_TYPE_TOOL_PROPS;
- arprops->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
- }
-
return artool;
}
@@ -180,7 +170,7 @@ static int tools_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_tools(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Tools";
+ ot->name = "Toggle Toolbar";
ot->description = "Toggle clip tools panel";
ot->idname = "CLIP_OT_tools";
@@ -188,78 +178,3 @@ void CLIP_OT_tools(wmOperatorType *ot)
ot->exec = tools_exec;
ot->poll = tools_poll;
}
-
-/************************** redo panel ******************************/
-
-static void clip_panel_operator_redo_buts(const bContext *C, Panel *pa, wmOperator *op)
-{
- uiTemplateOperatorPropertyButs(C, pa->layout, op, 'V', 0);
-}
-
-static void clip_panel_operator_redo_header(const bContext *C, Panel *pa)
-{
- wmOperator *op = WM_operator_last_redo(C);
-
- if (op)
- BLI_strncpy(pa->drawname, RNA_struct_ui_name(op->type->srna), sizeof(pa->drawname));
- else
- BLI_strncpy(pa->drawname, IFACE_("Operator"), sizeof(pa->drawname));
-}
-
-static void clip_panel_operator_redo_operator(const bContext *C, Panel *pa, wmOperator *op)
-{
- if (op->type->flag & OPTYPE_MACRO) {
- for (op = op->macro.first; op; op = op->next) {
- uiItemL(pa->layout, RNA_struct_ui_name(op->type->srna), ICON_NONE);
- clip_panel_operator_redo_operator(C, pa, op);
- }
- }
- else {
- clip_panel_operator_redo_buts(C, pa, op);
- }
-}
-
-/* TODO de-duplicate redo panel functions - campbell */
-static void clip_panel_operator_redo(const bContext *C, Panel *pa)
-{
- wmOperator *op = WM_operator_last_redo(C);
- ARegion *ar;
- ARegion *ar1;
-
- if (op == NULL)
- return;
-
- /* keep in sync with logic in ED_undo_operator_repeat() */
- ar = CTX_wm_region(C);
- ar1 = BKE_area_find_region_type(CTX_wm_area(C), RGN_TYPE_WINDOW);
- if (ar1)
- CTX_wm_region_set((bContext *)C, ar1);
-
- if (WM_operator_poll((bContext *)C, op->type)) {
- uiBlock *block = uiLayoutGetBlock(pa->layout);
-
- if (!WM_operator_check_ui_enabled(C, op->type->name))
- uiLayoutSetEnabled(pa->layout, false);
-
- /* note, blockfunc is a default but->func, use Handle func to allow button callbacks too */
- UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op);
-
- clip_panel_operator_redo_operator(C, pa, op);
- }
-
- /* set region back */
- CTX_wm_region_set((bContext *)C, ar);
-}
-
-void ED_clip_tool_props_register(ARegionType *art)
-{
- PanelType *pt;
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype clip panel last operator");
- strcpy(pt->idname, "CLIP_PT_last_operator");
- strcpy(pt->label, N_("Operator"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = clip_panel_operator_redo_header;
- pt->draw = clip_panel_operator_redo;
- BLI_addtail(&art->paneltypes, pt);
-}
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index b5b193804b1..7dd5816794f 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -41,10 +41,13 @@
#include "BKE_context.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
-#include "BKE_depsgraph.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -52,7 +55,6 @@
#include "ED_screen.h"
#include "ED_clip.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -63,7 +65,7 @@ void clip_graph_tracking_values_iterate_track(
SpaceClip *sc, MovieTrackingTrack *track, void *userdata,
void (*func)(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, int coord,
int scene_framenr, float val),
- void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord),
+ void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord, bool is_point),
void (*segment_end)(void *userdata, int coord))
{
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -92,8 +94,14 @@ void clip_graph_tracking_values_iterate_track(
}
if (!open) {
- if (segment_start)
- segment_start(userdata, track, coord);
+ if (segment_start) {
+ if ((i + 1) == track->markersnr) {
+ segment_start(userdata, track, coord, true);
+ }
+ else {
+ segment_start(userdata, track, coord, (track->markers[i + 1].flag & MARKER_DISABLED));
+ }
+ }
open = true;
prevval = marker->pos[coord];
@@ -124,7 +132,7 @@ void clip_graph_tracking_values_iterate(
SpaceClip *sc, bool selected_only, bool include_hidden, void *userdata,
void (*func)(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker,
int coord, int scene_framenr, float val),
- void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord),
+ void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord, bool is_point),
void (*segment_end)(void *userdata, int coord))
{
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -195,7 +203,9 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
BKE_tracking_get_rna_path_for_track(tracking,
track,
rna_path, sizeof(rna_path));
- BKE_animdata_fix_paths_remove(&clip->id, rna_path);
+ if (BKE_animdata_fix_paths_remove(&clip->id, rna_path)) {
+ DEG_relations_tag_update(CTX_data_main(C));
+ }
/* Delete track itself. */
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
@@ -204,11 +214,11 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track)
if (used_for_stabilization) {
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
+ /* Inform dependency graph. */
+ DEG_id_tag_update(&clip->id, 0);
if (has_bundle) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
- /* Inform dependency graph. */
- DAG_id_tag_update(&clip->id, 0);
}
void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track,
@@ -236,14 +246,16 @@ void clip_delete_plane_track(bContext *C,
BKE_tracking_get_rna_path_for_plane_track(tracking,
plane_track,
rna_path, sizeof(rna_path));
- BKE_animdata_fix_paths_remove(&clip->id, rna_path);
+ if (BKE_animdata_fix_paths_remove(&clip->id, rna_path)) {
+ DEG_relations_tag_update(CTX_data_main(C));
+ }
/* Delete the plane track itself. */
BKE_tracking_plane_track_free(plane_track);
BLI_freelinkN(plane_tracks_base, plane_track);
/* TODO(sergey): Any notifiers to be sent here? */
(void) C;
/* Inform dependency graph. */
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
}
void clip_view_center_to_point(SpaceClip *sc, float x, float y)
@@ -258,51 +270,34 @@ void clip_view_center_to_point(SpaceClip *sc, float x, float y)
sc->yof = (y - 0.5f) * height * aspy;
}
-void clip_draw_cfra(SpaceClip *sc, ARegion *ar, Scene *scene)
-{
- View2D *v2d = &ar->v2d;
- float xscale, yscale;
-
- /* Draw a light green line to indicate current frame */
- UI_ThemeColor(TH_CFRAME);
-
- float x = (float)(sc->user.framenr * scene->r.framelen);
-
- glLineWidth(2.0);
-
- glBegin(GL_LINES);
- glVertex2f(x, v2d->cur.ymin);
- glVertex2f(x, v2d->cur.ymax);
- glEnd();
-
- UI_view2d_view_orthoSpecial(ar, v2d, 1);
-
- /* because the frame number text is subject to the same scaling as the contents of the view */
- UI_view2d_scale_get(v2d, &xscale, &yscale);
- glScalef(1.0f / xscale, 1.0f, 1.0f);
-
- ED_region_cache_draw_curfra_label(sc->user.framenr, (float)sc->user.framenr * xscale, 18);
-
- /* restore view transform */
- glScalef(xscale, 1.0, 1.0);
-}
-
void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
{
UI_view2d_view_ortho(v2d);
/* currently clip editor supposes that editing clip length is equal to scene frame range */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
+ immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
- glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
- glRectf((float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
- glDisable(GL_BLEND);
+ GPU_blend(false);
- UI_ThemeColorShade(TH_BACK, -60);
+ immUniformThemeColorShade(TH_BACK, -60);
/* thin lines where the actual frames are */
- fdrawline((float)SFRA, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
- fdrawline((float)EFRA, v2d->cur.ymin, (float)EFRA, v2d->cur.ymax);
+ GPU_line_width(1.0f);
+
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, (float)SFRA, v2d->cur.ymin);
+ immVertex2f(pos, (float)SFRA, v2d->cur.ymax);
+ immVertex2f(pos, (float)EFRA, v2d->cur.ymin);
+ immVertex2f(pos, (float)EFRA, v2d->cur.ymax);
+ immEnd();
+
+ immUnbindProgram();
}
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 763bb1bcc88..83b4f0aa6ce 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -44,23 +44,27 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_screen.h"
#include "BKE_library.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
+#include "BKE_screen.h"
#include "IMB_imbuf_types.h"
+#include "ED_anim_api.h" /* for timeline cursor drawing */
#include "ED_mask.h"
#include "ED_space_api.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_clip.h"
#include "ED_transform.h"
#include "ED_uvedit.h" /* just for ED_image_draw_cursor */
#include "IMB_imbuf.h"
-#include "BIF_gl.h"
+#include "GPU_glew.h"
+#include "GPU_matrix.h"
+#include "GPU_framebuffer.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -74,12 +78,8 @@
#include "clip_intern.h" /* own include */
-static void init_preview_region(const bContext *C, ARegion *ar)
+static void init_preview_region(const Scene *scene, const ScrArea *sa, const SpaceClip *sc, ARegion *ar)
{
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
-
ar->regiontype = RGN_TYPE_PREVIEW;
ar->alignment = RGN_ALIGN_TOP;
ar->flag |= RGN_FLAG_HIDDEN;
@@ -137,15 +137,17 @@ static void init_preview_region(const bContext *C, ARegion *ar)
static void reinit_preview_region(const bContext *C, ARegion *ar)
{
+ Scene *scene = CTX_data_scene(C);
+ ScrArea *sa = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc->view == SC_VIEW_DOPESHEET) {
if ((ar->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) == 0)
- init_preview_region(C, ar);
+ init_preview_region(scene, sa, sc, ar);
}
else {
if (ar->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL)
- init_preview_region(C, ar);
+ init_preview_region(scene, sa, sc, ar);
}
}
@@ -167,7 +169,7 @@ static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "clip preview region");
BLI_insertlinkbefore(&sa->regionbase, ar, arnew);
- init_preview_region(C, arnew);
+ init_preview_region(CTX_data_scene(C), sa, CTX_wm_space_clip(C), arnew);
return arnew;
}
@@ -227,7 +229,7 @@ static void clip_scopes_check_gpencil_change(ScrArea *sa)
/* ******************** default callbacks for clip space ***************** */
-static SpaceLink *clip_new(const bContext *C)
+static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene)
{
ARegion *ar;
SpaceClip *sc;
@@ -235,7 +237,7 @@ static SpaceLink *clip_new(const bContext *C)
sc = MEM_callocN(sizeof(SpaceClip), "initclip");
sc->spacetype = SPACE_CLIP;
sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH |
- SC_SHOW_GRAPH_TRACKS_MOTION | SC_SHOW_GRAPH_FRAMES | SC_SHOW_GPENCIL;
+ SC_SHOW_GRAPH_TRACKS_MOTION | SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION;
sc->zoom = 1.0f;
sc->path_length = 20;
sc->scopes.track_preview_height = 120;
@@ -246,7 +248,7 @@ static SpaceLink *clip_new(const bContext *C)
BLI_addtail(&sc->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* tools view */
ar = MEM_callocN(sizeof(ARegion), "tools for clip");
@@ -255,13 +257,6 @@ static SpaceLink *clip_new(const bContext *C)
ar->regiontype = RGN_TYPE_TOOLS;
ar->alignment = RGN_ALIGN_LEFT;
- /* tool properties */
- ar = MEM_callocN(sizeof(ARegion), "tool properties for clip");
-
- BLI_addtail(&sc->regionbase, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
-
/* properties view */
ar = MEM_callocN(sizeof(ARegion), "properties for clip");
@@ -283,7 +278,7 @@ static SpaceLink *clip_new(const bContext *C)
ar = MEM_callocN(sizeof(ARegion), "preview for clip");
BLI_addtail(&sc->regionbase, ar);
- init_preview_region(C, ar);
+ init_preview_region(scene, sa, sc, ar);
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for clip");
@@ -329,7 +324,7 @@ static SpaceLink *clip_duplicate(SpaceLink *sl)
return (SpaceLink *)scn;
}
-static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -451,7 +446,7 @@ static void clip_operatortypes(void)
/* selection */
WM_operatortype_append(CLIP_OT_select);
WM_operatortype_append(CLIP_OT_select_all);
- WM_operatortype_append(CLIP_OT_select_border);
+ WM_operatortype_append(CLIP_OT_select_box);
WM_operatortype_append(CLIP_OT_select_lasso);
WM_operatortype_append(CLIP_OT_select_circle);
WM_operatortype_append(CLIP_OT_select_grouped);
@@ -525,7 +520,7 @@ static void clip_operatortypes(void)
/* selection */
WM_operatortype_append(CLIP_OT_graph_select);
- WM_operatortype_append(CLIP_OT_graph_select_border);
+ WM_operatortype_append(CLIP_OT_graph_select_box);
WM_operatortype_append(CLIP_OT_graph_select_all_markers);
WM_operatortype_append(CLIP_OT_graph_delete_curve);
@@ -543,282 +538,18 @@ static void clip_operatortypes(void)
static void clip_keymap(struct wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
/* ******** Global hotkeys avalaible for all regions ******** */
-
- keymap = WM_keymap_ensure(keyconf, "Clip", SPACE_CLIP, 0);
-
- WM_keymap_add_item(keymap, "CLIP_OT_open", OKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "CLIP_OT_tools", TKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_properties", NKEY, KM_PRESS, 0, 0);
-
- /* 2d tracking */
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_track_markers", LEFTARROWKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "backwards", true);
- RNA_boolean_set(kmi->ptr, "sequence", false);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_track_markers", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "backwards", false);
- RNA_boolean_set(kmi->ptr, "sequence", false);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_track_markers", TKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "backwards", false);
- RNA_boolean_set(kmi->ptr, "sequence", true);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_track_markers", TKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "backwards", true);
- RNA_boolean_set(kmi->ptr, "sequence", true);
-
- /* mode */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", TABKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.mode");
- RNA_string_set(kmi->ptr, "value_1", "TRACKING");
- RNA_string_set(kmi->ptr, "value_2", "MASK");
-
- WM_keymap_add_item(keymap, "CLIP_OT_solve_camera", SKEY, KM_PRESS, KM_SHIFT, 0);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_set_solver_keyframe", QKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "keyframe", 0);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_set_solver_keyframe", EKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "keyframe", 1);
-
- /* io/playback */
- WM_keymap_add_item(keymap, "CLIP_OT_prefetch", PKEY, KM_PRESS, 0, 0);
+ WM_keymap_ensure(keyconf, "Clip", SPACE_CLIP, 0);
/* ******** Hotkeys avalaible for main region only ******** */
-
- keymap = WM_keymap_ensure(keyconf, "Clip Editor", SPACE_CLIP, 0);
+ WM_keymap_ensure(keyconf, "Clip Editor", SPACE_CLIP, 0);
// keymap->poll = ED_space_clip_tracking_poll;
- /* ** View/navigation ** */
-
- WM_keymap_add_item(keymap, "CLIP_OT_view_pan", MIDDLEMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_pan", MOUSEPAN, 0, 0, 0);
-
- WM_keymap_add_item(keymap, "CLIP_OT_view_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_zoom", MOUSEZOOM, 0, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_zoom", MOUSEPAN, 0, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_out", PADMINUS, KM_PRESS, 0, 0);
-
- /* ctrl now works as well, shift + numpad works as arrow keys on Windows */
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 8.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD4, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 4.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD2, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 2.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 8.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 4.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD2, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 2.0f);
-
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD1, KM_PRESS, 0, 0)->ptr, "ratio", 1.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD2, KM_PRESS, 0, 0)->ptr, "ratio", 0.5f);
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD4, KM_PRESS, 0, 0)->ptr, "ratio", 0.25f);
- RNA_float_set(WM_keymap_add_item(keymap, "CLIP_OT_view_zoom_ratio", PAD8, KM_PRESS, 0, 0)->ptr, "ratio", 0.125f);
-
- WM_keymap_add_item(keymap, "CLIP_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_view_all", FKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "fit_view", true);
-
- WM_keymap_add_item(keymap, "CLIP_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
-
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "CLIP_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_view_ndof", NDOF_MOTION, 0, 0, 0);
-#endif
-
- /* jump to special frame */
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "position", 0);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_frame_jump", RIGHTARROWKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "position", 1);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "position", 2);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_frame_jump", RIGHTARROWKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "position", 3);
-
- /* "timeline" */
- WM_keymap_add_item(keymap, "CLIP_OT_change_frame", LEFTMOUSE, KM_PRESS, 0, 0);
-
- /* selection */
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
- WM_keymap_add_item(keymap, "CLIP_OT_select_border", BKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_select_circle", CKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "CLIP_MT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- /* marker */
- WM_keymap_add_item(keymap, "CLIP_OT_add_marker_slide", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "CLIP_OT_delete_marker", DELKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_delete_marker", XKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "CLIP_OT_slide_marker", LEFTMOUSE, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_disable_markers", DKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "action", 2); /* toggle */
-
- /* tracks */
- WM_keymap_add_item(keymap, "CLIP_OT_delete_track", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_delete_track", XKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_lock_tracks", LKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", 0); /* lock */
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_lock_tracks", LKEY, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "action", 1); /* unlock */
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_hide_tracks", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_hide_tracks", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- WM_keymap_add_item(keymap, "CLIP_OT_hide_tracks_clear", HKEY, KM_PRESS, KM_ALT, 0);
-
- /* plane tracks */
- WM_keymap_add_item(keymap, "CLIP_OT_slide_plane_marker", ACTIONMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "CLIP_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_keyframe_delete", IKEY, KM_PRESS, KM_ALT, 0);
-
- /* clean-up */
- WM_keymap_add_item(keymap, "CLIP_OT_join_tracks", JKEY, KM_PRESS, KM_CTRL, 0);
-
- /* menus */
- WM_keymap_add_menu(keymap, "CLIP_MT_tracking_specials", WKEY, KM_PRESS, 0, 0);
-
- /* display */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", LKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.lock_selection");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", DKEY, KM_PRESS, KM_ALT, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.show_disabled");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_ALT, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.show_marker_search");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.use_mute_footage");
-
- transform_keymap_for_space(keyconf, keymap, SPACE_CLIP);
-
- /* clean-up */
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_clear_track_path", TKEY, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_REMAINED);
- RNA_boolean_set(kmi->ptr, "clear_active", false);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_clear_track_path", TKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_UPTO);
- RNA_boolean_set(kmi->ptr, "clear_active", false);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_clear_track_path", TKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_ALL);
- RNA_boolean_set(kmi->ptr, "clear_active", false);
-
- /* Cursor */
- WM_keymap_add_item(keymap, "CLIP_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
-
- /* pivot point */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "BOUNDING_BOX_CENTER");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, KM_CTRL, 0); /* 2.4x allowed Comma+Shift too, rather not use both */
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "MEDIAN_POINT");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "CURSOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "INDIVIDUAL_ORIGINS");
-
- /* Copy-paste */
- WM_keymap_add_item(keymap, "CLIP_OT_copy_tracks", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_paste_tracks", VKEY, KM_PRESS, KM_CTRL, 0);
/* ******** Hotkeys avalaible for preview region only ******** */
-
- keymap = WM_keymap_ensure(keyconf, "Clip Graph Editor", SPACE_CLIP, 0);
-
- /* "timeline" */
- WM_keymap_add_item(keymap, "CLIP_OT_change_frame", ACTIONMOUSE, KM_PRESS, 0, 0);
-
- /* selection */
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_graph_select", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_graph_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_graph_select_all_markers", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_graph_select_all_markers", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "CLIP_OT_graph_select_border", BKEY, KM_PRESS, 0, 0);
-
- /* delete */
- WM_keymap_add_item(keymap, "CLIP_OT_graph_delete_curve", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_graph_delete_curve", XKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "CLIP_OT_graph_delete_knot", DELKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "CLIP_OT_graph_delete_knot", XKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* view */
- WM_keymap_add_item(keymap, "CLIP_OT_graph_view_all", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "CLIP_OT_graph_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
- WM_keymap_add_item(keymap, "CLIP_OT_graph_center_current_frame", PADPERIOD, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", LKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.lock_time_cursor");
-
- /* clean-up */
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_clear_track_path", TKEY, KM_PRESS, KM_ALT, 0);
- RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_REMAINED);
- RNA_boolean_set(kmi->ptr, "clear_active", true);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_clear_track_path", TKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_UPTO);
- RNA_boolean_set(kmi->ptr, "clear_active", true);
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_clear_track_path", TKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_ALL);
- RNA_boolean_set(kmi->ptr, "clear_active", true);
-
- /* tracks */
- kmi = WM_keymap_add_item(keymap, "CLIP_OT_graph_disable_markers", DKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "action", 2); /* toggle */
-
- transform_keymap_for_space(keyconf, keymap, SPACE_CLIP);
+ WM_keymap_ensure(keyconf, "Clip Graph Editor", SPACE_CLIP, 0);
/* ******** Hotkeys avalaible for channels region only ******** */
-
- keymap = WM_keymap_ensure(keyconf, "Clip Dopesheet Editor", SPACE_CLIP, 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);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
+ WM_keymap_ensure(keyconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
}
/* DO NOT make this static, this hides the symbol and breaks API generation script. */
@@ -848,7 +579,7 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul
}
/* dropboxes */
-static bool clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
if (drag->type == WM_DRAG_PATH)
if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
@@ -887,12 +618,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
ARegion *ar_tools = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
- ARegion *ar_tool_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS);
ARegion *ar_preview = ED_clip_has_preview_region(C, sa);
ARegion *ar_properties = ED_clip_has_properties_region(sa);
ARegion *ar_channels = ED_clip_has_channels_region(sa);
bool main_visible = false, preview_visible = false, tools_visible = false;
- bool tool_props_visible = false, properties_visible = false, channels_visible = false;
+ bool properties_visible = false, channels_visible = false;
bool view_changed = false;
switch (sc->view) {
@@ -900,7 +630,6 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
main_visible = true;
preview_visible = false;
tools_visible = true;
- tool_props_visible = true;
properties_visible = true;
channels_visible = false;
break;
@@ -908,7 +637,6 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
main_visible = false;
preview_visible = true;
tools_visible = false;
- tool_props_visible = false;
properties_visible = false;
channels_visible = false;
@@ -918,7 +646,6 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
main_visible = false;
preview_visible = true;
tools_visible = false;
- tool_props_visible = false;
properties_visible = false;
channels_visible = true;
@@ -999,30 +726,6 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
}
}
- if (tool_props_visible) {
- if (ar_tool_props && (ar_tool_props->flag & RGN_FLAG_HIDDEN)) {
- ar_tool_props->flag &= ~RGN_FLAG_HIDDEN;
- ar_tool_props->v2d.flag &= ~V2D_IS_INITIALISED;
- view_changed = true;
- }
- if (ar_tool_props && (ar_tool_props->alignment != (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) {
- ar_tool_props->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
- view_changed = true;
- }
- }
- else {
- if (ar_tool_props && !(ar_tool_props->flag & RGN_FLAG_HIDDEN)) {
- ar_tool_props->flag |= RGN_FLAG_HIDDEN;
- ar_tool_props->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_tool_props->handlers);
- view_changed = true;
- }
- if (ar_tool_props && ar_tool_props->alignment != RGN_ALIGN_NONE) {
- ar_tool_props->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- }
-
if (preview_visible) {
if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
ar_preview->flag &= ~RGN_FLAG_HIDDEN;
@@ -1180,7 +883,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
/* data... */
movieclip_main_area_set_view2d(C, ar);
@@ -1217,18 +920,18 @@ static void clip_main_region_draw(const bContext *C, ARegion *ar)
show_cursor |= sc->around == V3D_AROUND_CURSOR;
if (show_cursor) {
- glPushMatrix();
- glTranslatef(x, y, 0);
- glScalef(zoomx, zoomy, 0);
- glMultMatrixf(sc->stabmat);
- glScalef(width, height, 0);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_scale_2f(zoomx, zoomy);
+ GPU_matrix_mul(sc->stabmat);
+ GPU_matrix_scale_2f(width, height);
ED_image_draw_cursor(ar, sc->cursor);
- glPopMatrix();
+ GPU_matrix_pop();
}
clip_draw_cache_and_notes(C, sc, ar);
- if (sc->flag & SC_SHOW_GPENCIL) {
+ if (sc->flag & SC_SHOW_ANNOTATION) {
/* Grease Pencil */
clip_draw_grease_pencil((bContext *)C, true);
}
@@ -1239,13 +942,15 @@ static void clip_main_region_draw(const bContext *C, ARegion *ar)
/* reset view matrix */
UI_view2d_view_restore(C);
- if (sc->flag & SC_SHOW_GPENCIL) {
+ if (sc->flag & SC_SHOW_ANNOTATION) {
/* draw Grease Pencil - screen space only */
clip_draw_grease_pencil((bContext *)C, false);
}
}
-static void clip_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1284,28 +989,38 @@ static void graph_region_draw(const bContext *C, ARegion *ar)
SpaceClip *sc = CTX_wm_space_clip(C);
Scene *scene = CTX_data_scene(C);
short unitx, unity;
+ short cfra_flag = 0;
if (sc->flag & SC_LOCK_TIMECURSOR)
ED_clip_graph_center_current_frame(scene, ar);
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
/* data... */
clip_draw_graph(sc, ar, scene);
+ /* current frame indicator line */
+ if (sc->flag & SC_SHOW_SECONDS) cfra_flag |= DRAWCFRA_UNIT_SECONDS;
+ ANIM_draw_cfra(C, v2d, cfra_flag);
+
/* reset view matrix */
UI_view2d_view_restore(C);
/* scrollers */
unitx = (sc->flag & SC_SHOW_SECONDS) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES;
unity = V2D_UNIT_VALUES;
- scrollers = UI_view2d_scrollers_calc(C, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
+
+ /* current frame indicator */
+ if (sc->flag & SC_SHOW_SECONDS) cfra_flag |= DRAWCFRA_UNIT_SECONDS;
+ UI_view2d_view_orthoSpecial(ar, v2d, 1);
+ ANIM_draw_cfra_number(C, v2d, cfra_flag);
}
static void dopesheet_region_draw(const bContext *C, ARegion *ar)
@@ -1316,14 +1031,14 @@ static void dopesheet_region_draw(const bContext *C, ARegion *ar)
View2D *v2d = &ar->v2d;
View2DGrid *grid;
View2DScrollers *scrollers;
- short unit = 0;
+ short unit = 0, cfra_flag = 0;
if (clip)
BKE_tracking_dopesheet_update(&clip->tracking);
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -1337,13 +1052,21 @@ static void dopesheet_region_draw(const bContext *C, ARegion *ar)
/* data... */
clip_draw_dopesheet_main(sc, ar, scene);
+ /* current frame indicator line */
+ if (sc->flag & SC_SHOW_SECONDS) cfra_flag |= DRAWCFRA_UNIT_SECONDS;
+ ANIM_draw_cfra(C, v2d, cfra_flag);
+
/* reset view matrix */
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
+
+ /* current frame number indicator */
+ UI_view2d_view_orthoSpecial(ar, v2d, 1);
+ ANIM_draw_cfra_number(C, v2d, cfra_flag);
}
static void clip_preview_region_draw(const bContext *C, ARegion *ar)
@@ -1356,7 +1079,9 @@ static void clip_preview_region_draw(const bContext *C, ARegion *ar)
dopesheet_region_draw(C, ar);
}
-static void clip_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void clip_preview_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
}
@@ -1386,7 +1111,7 @@ static void clip_channels_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -1397,7 +1122,9 @@ static void clip_channels_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
}
-static void clip_channels_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void clip_channels_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
}
@@ -1414,7 +1141,9 @@ static void clip_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-static void clip_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_header_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1449,12 +1178,14 @@ static void clip_tools_region_init(wmWindowManager *wm, ARegion *ar)
static void clip_tools_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
/****************** tool properties region ******************/
-static void clip_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_props_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1496,10 +1227,12 @@ static void clip_properties_region_draw(const bContext *C, ARegion *ar)
BKE_movieclip_update_scopes(sc->clip, &sc->user, &sc->scopes);
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
-static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_properties_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1599,19 +1332,6 @@ void ED_spacetype_clip(void)
BLI_addhead(&st->regiontypes, art);
- /* tool properties */
- art = MEM_callocN(sizeof(ARegionType), "spacetype clip tool properties region");
- art->regionid = RGN_TYPE_TOOL_PROPS;
- art->prefsizex = 0;
- art->prefsizey = 120;
- art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI;
- art->listener = clip_props_region_listener;
- art->init = clip_tools_region_init;
- art->draw = clip_tools_region_draw;
- ED_clip_tool_props_register(art);
-
- BLI_addhead(&st->regiontypes, art);
-
/* regions: header */
art = MEM_callocN(sizeof(ARegionType), "spacetype clip region");
art->regionid = RGN_TYPE_HEADER;
@@ -1636,4 +1356,8 @@ void ED_spacetype_clip(void)
art->draw = clip_channels_region_draw;
BLI_addhead(&st->regiontypes, art);
+
+ /* regions: hud */
+ art = ED_area_type_hud(st->spaceid);
+ BLI_addhead(&st->regiontypes, art);
}
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 2a64b476ea4..42077280cca 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -42,10 +42,11 @@
#include "BKE_context.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
-#include "BKE_depsgraph.h"
#include "BKE_report.h"
#include "BKE_sound.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -154,8 +155,8 @@ static int add_marker_at_click_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
- ED_area_headerprint(
- CTX_wm_area(C),
+ ED_workspace_status_text(
+ C,
IFACE_("Use LMB click to define location where place the marker"));
/* Add modal handler for ESC. */
@@ -179,7 +180,7 @@ static int add_marker_at_click_modal(bContext *C,
ARegion *ar = CTX_wm_region(C);
float pos[2];
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
ED_clip_point_stable_pos(sc, ar,
event->x - ar->winrct.xmin,
@@ -195,7 +196,7 @@ static int add_marker_at_click_modal(bContext *C,
}
case ESCKEY:
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
return OPERATOR_CANCELLED;
}
@@ -675,7 +676,7 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C,
* the mouse.
*/
if (sc->flag & SC_SHOW_MARKER_PATTERN) {
- int current_corner;
+ int current_corner = -1;
distance_squared =
mouse_to_closest_pattern_corner_distance_squared(
marker,
@@ -898,7 +899,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- DAG_id_tag_update(&sc->clip->id, 0);
+ DEG_id_tag_update(&sc->clip->id, 0);
}
else if (data->area == TRACK_AREA_PAT) {
if (data->action == SLIDE_ACTION_SIZE) {
@@ -1193,7 +1194,7 @@ static int disable_markers_exec(bContext *C, wmOperator *op)
}
}
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
diff --git a/source/blender/editors/space_clip/tracking_ops_detect.c b/source/blender/editors/space_clip/tracking_ops_detect.c
index 0ee06b305da..77f7e8d112c 100644
--- a/source/blender/editors/space_clip/tracking_ops_detect.c
+++ b/source/blender/editors/space_clip/tracking_ops_detect.c
@@ -131,10 +131,10 @@ void CLIP_OT_detect_features(wmOperatorType *ot)
static const EnumPropertyItem placement_items[] = {
{0, "FRAME", 0, "Whole Frame",
"Place markers across the whole frame"},
- {1, "INSIDE_GPENCIL", 0, "Inside grease pencil",
- "Place markers only inside areas outlined with grease pencil"},
- {2, "OUTSIDE_GPENCIL", 0, "Outside grease pencil",
- "Place markers only outside areas outlined with grease pencil"},
+ {1, "INSIDE_GPENCIL", 0, "Inside Grease Pencil",
+ "Place markers only inside areas outlined with Grease Pencil"},
+ {2, "OUTSIDE_GPENCIL", 0, "Outside Grease Pencil",
+ "Place markers only outside areas outlined with Grease Pencil"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c
index 8ad31fc3b9b..4d1c3e0b137 100644
--- a/source/blender/editors/space_clip/tracking_ops_orient.c
+++ b/source/blender/editors/space_clip/tracking_ops_orient.c
@@ -42,10 +42,12 @@
#include "BKE_context.h"
#include "BKE_constraint.h"
#include "BKE_tracking.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -68,17 +70,16 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
return camera;
}
- for (Base *base = scene->base.first;
- base != NULL;
- base = base->next)
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
{
- if (base->object->type == OB_CAMERA) {
- if (BKE_object_movieclip_get(scene, base->object, false) == clip) {
- camera = base->object;
+ if (ob->type == OB_CAMERA) {
+ if (BKE_object_movieclip_get(scene, ob, false) == clip) {
+ camera = ob;
break;
}
}
}
+ FOREACH_SCENE_OBJECT_END;
return camera;
}
@@ -86,6 +87,7 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
static Object *get_orientation_object(bContext *C)
{
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
@@ -96,7 +98,7 @@ static Object *get_orientation_object(bContext *C)
object = get_camera_with_movieclip(scene, clip);
}
else {
- object = OBACT;
+ object = OBACT(view_layer);
}
if (object != NULL && object->parent != NULL) {
@@ -110,7 +112,7 @@ static bool set_orientation_poll(bContext *C)
{
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc != NULL) {
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
if (clip != NULL) {
MovieTracking *tracking = &clip->tracking;
@@ -119,7 +121,7 @@ static bool set_orientation_poll(bContext *C)
return true;
}
else {
- return OBACT != NULL;
+ return OBACT(view_layer) != NULL;
}
}
}
@@ -143,7 +145,8 @@ static int count_selected_bundles(bContext *C)
return tot;
}
-static void object_solver_inverted_matrix(Scene *scene,
+static void object_solver_inverted_matrix(Depsgraph *depsgraph,
+ Scene *scene,
Object *ob,
float invmat[4][4])
{
@@ -160,7 +163,7 @@ static void object_solver_inverted_matrix(Scene *scene,
bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
if (!found) {
Object *cam = data->camera ? data->camera : scene->camera;
- BKE_object_where_is_calc_mat4(scene, cam, invmat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, cam, invmat);
}
mul_m4_m4m4(invmat, invmat, data->invmat);
found = true;
@@ -198,6 +201,7 @@ static int set_origin_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *camera = get_camera_with_movieclip(scene, clip);
int selected_count = count_selected_bundles(C);
@@ -234,20 +238,20 @@ static int set_origin_exec(bContext *C, wmOperator *op)
mul_v3_fl(median, 1.0f / selected_count);
float mat[4][4], vec[3];
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, scene, camera, mat);
mul_v3_m4v3(vec, mat, median);
if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
sub_v3_v3(object->loc, vec);
}
else {
- object_solver_inverted_matrix(scene, object, mat);
+ object_solver_inverted_matrix(depsgraph, scene, object, mat);
mul_v3_m4v3(vec, mat, vec);
copy_v3_v3(object->loc, vec);
}
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
+ DEG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&object->id, OB_RECALC_OB);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -276,7 +280,8 @@ void CLIP_OT_set_origin(wmOperatorType *ot)
/********************** set floor operator *********************/
-static void set_axis(Scene *scene,
+static void set_axis(Depsgraph *depsgraph,
+ Scene *scene,
Object *ob,
MovieClip *clip,
MovieTrackingObject *tracking_object,
@@ -290,14 +295,14 @@ static void set_axis(Scene *scene,
BKE_object_to_mat4(ob, obmat);
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, scene, camera, mat);
mul_v3_m4v3(vec, mat, track->bundle_pos);
copy_v3_v3(dvec, vec);
if (!is_camera) {
float imat[4][4];
- object_solver_inverted_matrix(scene, ob, imat);
+ object_solver_inverted_matrix(depsgraph, scene, ob, imat);
mul_v3_m4v3(vec, imat, vec);
invert_m4_m4(imat, obmat);
@@ -403,6 +408,7 @@ static int set_plane_exec(bContext *C, wmOperator *op)
ListBase *tracksbase;
Object *object;
Object *camera = get_camera_with_movieclip(scene, clip);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
int tot = 0;
float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
int plane = RNA_enum_get(op->ptr, "plane");
@@ -427,7 +433,7 @@ static int set_plane_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, scene, camera, mat);
/* Get 3 bundles to use as reference. */
track = tracksbase->first;
@@ -489,11 +495,11 @@ static int set_plane_exec(bContext *C, wmOperator *op)
BKE_object_apply_mat4(object, mat, 0, 0);
}
- BKE_object_where_is_calc(scene, object);
- set_axis(scene, object, clip, tracking_object, axis_track, 'X');
+ BKE_object_where_is_calc(depsgraph, scene, object);
+ set_axis(depsgraph, scene, object, clip, tracking_object, axis_track, 'X');
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
+ DEG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&object->id, OB_RECALC_OB);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -536,6 +542,7 @@ static int set_axis_exec(bContext *C, wmOperator *op)
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *object;
int axis = RNA_enum_get(op->ptr, "axis");
@@ -564,10 +571,10 @@ static int set_axis_exec(bContext *C, wmOperator *op)
track = track->next;
}
- set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
+ set_axis(depsgraph, scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
+ DEG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&object->id, OB_RECALC_OB);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -615,6 +622,7 @@ static int do_set_scale(bContext *C,
MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
MovieTrackingTrack *track;
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *object = NULL;
Object *camera = get_camera_with_movieclip(scene, clip);
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
@@ -639,7 +647,7 @@ static int do_set_scale(bContext *C,
}
}
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, scene, camera, mat);
track = tracksbase->first;
while (track) {
@@ -693,10 +701,10 @@ static int do_set_scale(bContext *C,
tracking_object->scale = scale;
}
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
if (object)
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
+ DEG_id_tag_update(&object->id, OB_RECALC_OB);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c
index aa8518befaa..6c85bdfc4ec 100644
--- a/source/blender/editors/space_clip/tracking_ops_plane.c
+++ b/source/blender/editors/space_clip/tracking_ops_plane.c
@@ -39,9 +39,10 @@
#include "BKE_context.h"
#include "BKE_tracking.h"
-#include "BKE_depsgraph.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -372,7 +373,7 @@ static int slide_plane_marker_modal(bContext *C,
data->previous_mval[1] = event->mval[1];
copy_v2_v2(data->previous_corner, data->corner);
- DAG_id_tag_update(&sc->clip->id, 0);
+ DEG_id_tag_update(&sc->clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
@@ -390,7 +391,7 @@ static int slide_plane_marker_modal(bContext *C,
clip_tracking_show_cursor(C);
- DAG_id_tag_update(&sc->clip->id, 0);
+ DEG_id_tag_update(&sc->clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
index 5c74c1947e3..4148b3a0070 100644
--- a/source/blender/editors/space_clip/tracking_ops_solve.c
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -40,12 +40,13 @@
#include "BLI_string.h"
#include "BKE_context.h"
-#include "BKE_movieclip.h"
-#include "BKE_tracking.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
-#include "BKE_report.h"
#include "BKE_library.h"
+#include "BKE_movieclip.h"
+#include "BKE_report.h"
+#include "BKE_tracking.h"
+
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -180,7 +181,7 @@ static void solve_camera_freejob(void *scv)
MEM_freeN(tracking->stats);
tracking->stats = NULL;
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_main_add_notifier(NC_MOVIECLIP | NA_EVALUATED, clip);
WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, NULL);
@@ -327,7 +328,7 @@ static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
reconstruction->camnr = 0;
reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
diff --git a/source/blender/editors/space_clip/tracking_ops_stabilize.c b/source/blender/editors/space_clip/tracking_ops_stabilize.c
index e865ee26b20..2888607a049 100644
--- a/source/blender/editors/space_clip/tracking_ops_stabilize.c
+++ b/source/blender/editors/space_clip/tracking_ops_stabilize.c
@@ -38,7 +38,8 @@
#include "BKE_context.h"
#include "BKE_tracking.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -84,7 +85,7 @@ static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@@ -138,7 +139,7 @@ static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@@ -227,7 +228,7 @@ static int stabilize_2d_rotation_add_exec(bContext *C, wmOperator *UNUSED(op))
}
if (update) {
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
@@ -281,7 +282,7 @@ static int stabilize_2d_rotation_remove_exec(bContext *C, wmOperator *UNUSED(op)
}
if (update) {
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
}
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index 0dd0ee8c7d4..cd8e92c9b9c 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -297,7 +297,8 @@ static void track_markers_endjob(void *tmv)
tmj->scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(tmj->clip,
tmj->lastfra);
if (wm != NULL) {
- ED_update_for_newframe(tmj->main, tmj->scene, 0);
+ // XXX: ...
+ // ED_update_for_newframe(tmj->main, tmj->scene);
}
BKE_autotrack_context_sync(tmj->context);
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index cf4687dca31..162948c8e64 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -46,6 +46,7 @@
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_clip.h"
#include "RNA_access.h"
@@ -53,6 +54,8 @@
#include "UI_view2d.h"
+#include "DEG_depsgraph.h"
+
#include "tracking_ops_intern.h" /* own include */
#include "clip_intern.h" /* own include */
@@ -346,6 +349,7 @@ static int mouse_select(bContext *C, float co[2], int extend)
BKE_tracking_dopesheet_tag_update(tracking);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ DEG_id_tag_update(&clip->id, DEG_TAG_SELECT_UPDATE);
return OPERATOR_FINISHED;
}
@@ -389,6 +393,7 @@ static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
clip->tracking.act_track = track;
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ DEG_id_tag_update(&clip->id, DEG_TAG_SELECT_UPDATE);
return OPERATOR_PASS_THROUGH;
}
@@ -422,9 +427,9 @@ void CLIP_OT_select(wmOperatorType *ot)
"Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
}
-/********************** border select operator *********************/
+/********************** box select operator *********************/
-static int border_select_exec(bContext *C, wmOperator *op)
+static int box_select_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -506,6 +511,7 @@ static int border_select_exec(bContext *C, wmOperator *op)
BKE_tracking_dopesheet_tag_update(tracking);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ DEG_id_tag_update(&clip->id, DEG_TAG_SELECT_UPDATE);
return OPERATOR_FINISHED;
}
@@ -513,24 +519,24 @@ static int border_select_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-void CLIP_OT_select_border(wmOperatorType *ot)
+void CLIP_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->description = "Select markers using border selection";
- ot->idname = "CLIP_OT_select_border";
+ ot->name = "Box Select";
+ ot->description = "Select markers using box selection";
+ ot->idname = "CLIP_OT_select_box";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = border_select_exec;
- ot->modal = WM_gesture_border_modal;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = box_select_exec;
+ ot->modal = WM_gesture_box_modal;
ot->poll = ED_space_clip_tracking_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
/********************** lasso select operator *********************/
@@ -616,6 +622,7 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor
BKE_tracking_dopesheet_tag_update(tracking);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ DEG_id_tag_update(&clip->id, DEG_TAG_SELECT_UPDATE);
}
return changed;
@@ -758,6 +765,7 @@ static int circle_select_exec(bContext *C, wmOperator *op)
BKE_tracking_dopesheet_tag_update(tracking);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ DEG_id_tag_update(&clip->id, DEG_TAG_SELECT_UPDATE);
return OPERATOR_FINISHED;
}
@@ -883,6 +891,7 @@ static int select_all_exec(bContext *C, wmOperator *op)
BKE_tracking_dopesheet_tag_update(tracking);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ DEG_id_tag_update(&clip->id, DEG_TAG_SELECT_UPDATE);
return OPERATOR_FINISHED;
}
@@ -966,6 +975,7 @@ static int select_grouped_exec(bContext *C, wmOperator *op)
BKE_tracking_dopesheet_tag_update(tracking);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ DEG_id_tag_update(&clip->id, DEG_TAG_SELECT_UPDATE);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 6ee658b744c..789194c21b9 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -40,6 +40,7 @@
#include "MEM_guardedalloc.h"
#include "BIF_gl.h"
+#include "GPU_immediate.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -157,6 +158,8 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha
int offl = 0, offc = 0;
int xy[2] = {CONSOLE_DRAW_MARGIN, CONSOLE_DRAW_MARGIN};
int pen[2];
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
xy[1] += tvc->lheight / 6;
console_cursor_wrap_offset(sc->prompt, tvc->console_width, &offl, &offc, NULL);
@@ -168,14 +171,17 @@ static int console_textview_line_color(struct TextViewContext *tvc, unsigned cha
pen[1] += tvc->lheight * offl;
/* cursor */
- UI_GetThemeColor3ubv(TH_CONSOLE_CURSOR, fg);
- glColor3ubv(fg);
-
- glRecti((xy[0] + pen[0]) - 1,
- (xy[1] + pen[1]),
- (xy[0] + pen[0]) + 1,
- (xy[1] + pen[1] + tvc->lheight)
- );
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_CONSOLE_CURSOR);
+
+ immRectf(pos,
+ (xy[0] + pen[0]) - 1,
+ (xy[1] + pen[1]),
+ (xy[0] + pen[0]) + 1,
+ (xy[1] + pen[1] + tvc->lheight)
+ );
+
+ immUnbindProgram();
}
console_line_color(fg, cl_iter->type);
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 919602f7bb5..596d66da9a6 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -49,10 +49,11 @@
#include "UI_view2d.h"
#include "console_intern.h" // own include
+#include "GPU_framebuffer.h"
/* ******************** default callbacks for console space ***************** */
-static SpaceLink *console_new(const bContext *UNUSED(C))
+static SpaceLink *console_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceConsole *sconsole;
@@ -67,7 +68,7 @@ static SpaceLink *console_new(const bContext *UNUSED(C))
BLI_addtail(&sconsole->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* main region */
@@ -169,31 +170,24 @@ static void console_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
/* ************* dropboxes ************* */
-static bool id_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool id_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
-// SpaceConsole *sc = CTX_wm_space_console(C);
- if (drag->type == WM_DRAG_ID)
- return 1;
- return 0;
+ return WM_drag_ID(drag, 0) != NULL;
}
static void id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- char *text;
- ID *id = drag->poin;
+ ID *id = WM_drag_ID(drag, 0);
/* copy drag path to properties */
- text = RNA_path_full_ID_py(id);
+ char *text = RNA_path_full_ID_py(id);
RNA_string_set(drop->ptr, "text", text);
MEM_freeN(text);
}
-static bool path_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool path_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
- // SpaceConsole *sc = CTX_wm_space_console(C);
- if (drag->type == WM_DRAG_PATH)
- return 1;
- return 0;
+ return (drag->type == WM_DRAG_PATH);
}
static void path_drop_copy(wmDrag *drag, wmDropBox *drop)
@@ -227,7 +221,7 @@ static void console_main_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
/* worlks best with no view2d matrix set */
UI_view2d_view_ortho(v2d);
@@ -241,7 +235,7 @@ static void console_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_GRID_CLAMP);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_GRID_CLAMP);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@@ -271,88 +265,7 @@ static void console_operatortypes(void)
static void console_keymap(struct wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Console", SPACE_CONSOLE, 0);
- wmKeyMapItem *kmi;
-
-#ifdef __APPLE__
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_END);
-#endif
-
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
- RNA_boolean_set(kmi->ptr, "reverse", false);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
- RNA_boolean_set(kmi->ptr, "reverse", true);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
- RNA_boolean_set(kmi->ptr, "reverse", false);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADMINUS, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
- RNA_boolean_set(kmi->ptr, "reverse", true);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_CHAR);
-
- RNA_boolean_set(WM_keymap_add_item(keymap, "CONSOLE_OT_history_cycle", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "reverse", true);
- RNA_boolean_set(WM_keymap_add_item(keymap, "CONSOLE_OT_history_cycle", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "reverse", false);
-
-#if 0
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_PAGE);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_PAGE);
-#endif
-
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", DEL_PREV_CHAR); /* same as above [#26623] */
-
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", DELKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD);
-
- WM_keymap_add_item(keymap, "CONSOLE_OT_clear_line", RETKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "CONSOLE_OT_clear_line", PADENTER, KM_PRESS, KM_SHIFT, 0);
-
-#ifdef WITH_PYTHON
- kmi = WM_keymap_add_item(keymap, "CONSOLE_OT_execute", RETKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "interactive", true);
- kmi = WM_keymap_add_item(keymap, "CONSOLE_OT_execute", PADENTER, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "interactive", true);
-
- //WM_keymap_add_item(keymap, "CONSOLE_OT_autocomplete", TABKEY, KM_PRESS, 0, 0); /* python operator - space_text.py */
- WM_keymap_add_item(keymap, "CONSOLE_OT_autocomplete", SPACEKEY, KM_PRESS, KM_CTRL, 0); /* python operator - space_text.py */
-#endif
-
- WM_keymap_add_item(keymap, "CONSOLE_OT_copy_as_script", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "CONSOLE_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "CONSOLE_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "CONSOLE_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "CONSOLE_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
-
- WM_keymap_add_item(keymap, "CONSOLE_OT_select_set", LEFTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CONSOLE_OT_select_word", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
-
- RNA_string_set(WM_keymap_add_item(keymap, "CONSOLE_OT_insert", TABKEY, KM_PRESS, KM_CTRL, 0)->ptr, "text", "\t"); /* fake tabs */
-
- WM_keymap_add_item(keymap, "CONSOLE_OT_indent", TABKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "CONSOLE_OT_unindent", TABKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "CONSOLE_OT_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last!
+ WM_keymap_ensure(keyconf, "Console", SPACE_CONSOLE, 0);
}
/****************** header region ******************/
@@ -368,7 +281,9 @@ static void console_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-static void console_main_region_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar, wmNotifier *wmn)
+static void console_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *sa, ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
// SpaceInfo *sinfo = sa->spacedata.first;
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index f407d82aa5e..2ae432fbc4e 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -42,7 +42,6 @@
# include "BLI_winstuff.h"
#endif
-#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "BKE_context.h"
@@ -53,6 +52,8 @@
#include "BLT_translation.h"
+#include "BLF_api.h"
+
#include "IMB_imbuf_types.h"
#include "DNA_userdef_types.h"
@@ -71,6 +72,10 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_state.h"
+
#include "filelist.h"
#include "file_intern.h" // own include
@@ -216,13 +221,13 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
/* Filename number increment / decrement buttons. */
if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) {
UI_block_align_begin(block);
- but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_ZOOMOUT,
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_REMOVE,
min_x + line2_w + separator - chan_offs, line2_y,
btn_fn_w, btn_h,
TIP_("Decrement the filename number"));
RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1);
- but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_ZOOMIN,
+ but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_filenum", 0, ICON_ADD,
min_x + line2_w + separator + btn_fn_w - chan_offs, line2_y,
btn_fn_w, btn_h,
TIP_("Increment the filename number"));
@@ -258,9 +263,10 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade)
{
- UI_ThemeColorShade(colorid, shade);
+ float color[4];
+ UI_GetThemeColorShade4fv(colorid, shade, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox((float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f);
+ UI_draw_roundbox_aa(true, (float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f, color);
}
@@ -285,7 +291,8 @@ static void file_draw_icon(uiBlock *block, const char *path, int sx, int sy, int
}
-static void file_draw_string(int sx, int sy, const char *string, float width, int height, short align)
+static void file_draw_string(int sx, int sy, const char *string, float width, int height, short align,
+ const unsigned char col[4])
{
uiStyle *style;
uiFontStyle fs;
@@ -310,7 +317,7 @@ static void file_draw_string(int sx, int sy, const char *string, float width, in
rect.ymin = sy - height;
rect.ymax = sy;
- UI_fontstyle_draw(&fs, &rect, fname);
+ UI_fontstyle_draw(&fs, &rect, fname, col);
}
void file_calc_previews(const bContext *C, ARegion *ar)
@@ -335,6 +342,7 @@ static void file_draw_preview(
float scale;
int ex, ey;
bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE);
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
BLI_assert(imb != NULL);
@@ -370,32 +378,37 @@ static void file_draw_preview(
xco = sx + (int)dx;
yco = sy - layout->prv_h + (int)dy;
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* shadow */
if (use_dropshadow) {
UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
}
- glEnable(GL_BLEND);
+ GPU_blend(true);
/* the image */
if (!is_icon && typeflags & FILE_TYPE_FTFONT) {
- UI_ThemeColor(TH_TEXT);
- }
- else {
- glColor4f(1.0, 1.0, 1.0, 1.0);
+ UI_GetThemeColor4fv(TH_TEXT, col);
}
- glaDrawPixelsTexScaled((float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect, scale, scale);
+
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTexScaled(&state, (float)xco, (float)yco, imb->x, imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, imb->rect,
+ scale, scale, 1.0f, 1.0f, col);
if (icon) {
- UI_icon_draw_aspect((float)xco, (float)yco, icon, icon_aspect, 1.0f);
+ UI_icon_draw_aspect((float)xco, (float)yco, icon, icon_aspect, 1.0f, NULL);
}
/* border */
if (use_dropshadow) {
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
- fdrawbox((float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
+ imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey));
+ immUnbindProgram();
}
but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL);
@@ -407,7 +420,7 @@ static void file_draw_preview(
UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true);
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
@@ -453,49 +466,70 @@ static void draw_background(FileLayout *layout, View2D *v2d)
int i;
int sy;
- UI_ThemeColorShade(TH_BACK, -7);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, -7);
/* alternating flat shade background */
for (i = 0; (i <= layout->rows); i += 2) {
sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) - layout->tile_border_y;
- glRectf(v2d->cur.xmin, (float)sy, v2d->cur.xmax, (float)(sy + layout->tile_h + 2 * layout->tile_border_y));
-
+ immRectf(pos, v2d->cur.xmin, (float)sy, v2d->cur.xmax, (float)(sy + layout->tile_h + 2 * layout->tile_border_y));
}
+
+ immUnbindProgram();
}
static void draw_dividers(FileLayout *layout, View2D *v2d)
{
+ /* vertical column dividers */
+
const int step = (layout->tile_w + 2 * layout->tile_border_x);
- int v1[2], v2[2];
- int sx;
- unsigned char col_hi[3], col_lo[3];
- UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi);
- UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo);
+ unsigned int vertex_len = 0;
+ int sx = (int)v2d->tot.xmin;
+ while (sx < v2d->cur.xmax) {
+ sx += step;
+ vertex_len += 4; /* vertex_count = 2 points per line * 2 lines per divider */
+ }
+
+ if (vertex_len > 0) {
+ int v1[2], v2[2];
+ unsigned char col_hi[3], col_lo[3];
- v1[1] = v2d->cur.ymax - layout->tile_border_y;
- v2[1] = v2d->cur.ymin;
+ UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi);
+ UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo);
- glBegin(GL_LINES);
+ v1[1] = v2d->cur.ymax - layout->tile_border_y;
+ v2[1] = v2d->cur.ymin;
- /* vertical column dividers */
- sx = (int)v2d->tot.xmin;
- while (sx < v2d->cur.xmax) {
- sx += step;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- glColor3ubv(col_lo);
- v1[0] = v2[0] = sx;
- glVertex2iv(v1);
- glVertex2iv(v2);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GPU_PRIM_LINES, vertex_len);
- glColor3ubv(col_hi);
- v1[0] = v2[0] = sx + 1;
- glVertex2iv(v1);
- glVertex2iv(v2);
- }
+ sx = (int)v2d->tot.xmin;
+ while (sx < v2d->cur.xmax) {
+ sx += step;
+
+ v1[0] = v2[0] = sx;
+ immAttrSkip(color);
+ immVertex2iv(pos, v1);
+ immAttr3ubv(color, col_lo);
+ immVertex2iv(pos, v2);
- glEnd();
+ v1[0] = v2[0] = sx + 1;
+ immAttrSkip(color);
+ immVertex2iv(pos, v1);
+ immAttr3ubv(color, col_hi);
+ immVertex2iv(pos, v2);
+ }
+
+ immEnd();
+ immUnbindProgram();
+ }
}
void file_draw_list(const bContext *C, ARegion *ar)
@@ -519,6 +553,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
short align;
bool do_drag;
int column_space = 0.6f * UI_UNIT_X;
+ unsigned char text_col[4];
const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size);
const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size);
const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size));
@@ -577,6 +612,8 @@ void file_draw_list(const bContext *C, ARegion *ar)
}
}
+ BLF_batch_draw_begin();
+
for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) {
unsigned int file_selflag;
char path[FILE_MAX_LIBEXTRA];
@@ -589,9 +626,6 @@ void file_draw_list(const bContext *C, ARegion *ar)
BLI_join_dirfile(path, sizeof(path), root, file->relpath);
- UI_ThemeColor4(TH_TEXT);
-
-
if (!(file_selflag & FILE_SEL_EDITING)) {
if ((params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ||
(file_selflag & FILE_SEL_SELECTED))
@@ -627,7 +661,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X;
}
- UI_ThemeColor4(TH_TEXT);
+ UI_GetThemeColor4ubv(TH_TEXT, text_col);
if (file_selflag & FILE_SEL_EDITING) {
uiBut *but;
@@ -658,7 +692,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
if (!(file_selflag& FILE_SEL_EDITING)) {
int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : sy;
- file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align);
+ file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align, text_col);
}
sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
@@ -670,7 +704,8 @@ void file_draw_list(const bContext *C, ARegion *ar)
BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str);
}
file_draw_string(
- sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
+ sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h,
+ align, text_col);
}
sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
@@ -681,10 +716,12 @@ void file_draw_list(const bContext *C, ARegion *ar)
NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str);
}
file_draw_string(
- sx, sy, file->entry->date_str, layout->column_widths[COLUMN_DATE], layout->tile_h, align);
+ sx, sy, file->entry->date_str, layout->column_widths[COLUMN_DATE], layout->tile_h,
+ align, text_col);
sx += (int)layout->column_widths[COLUMN_DATE] + column_space;
file_draw_string(
- sx, sy, file->entry->time_str, layout->column_widths[COLUMN_TIME], layout->tile_h, align);
+ sx, sy, file->entry->time_str, layout->column_widths[COLUMN_TIME], layout->tile_h,
+ align, text_col);
sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
}
else {
@@ -699,12 +736,15 @@ void file_draw_list(const bContext *C, ARegion *ar)
BLI_filelist_entry_size_to_string(NULL, file->entry->size, small_size, file->entry->size_str);
}
file_draw_string(
- sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
+ sx, sy, file->entry->size_str, layout->column_widths[COLUMN_SIZE], layout->tile_h,
+ align, text_col);
}
sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
}
+ BLF_batch_draw_end();
+
UI_block_end(C, block);
UI_block_draw(C, block);
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 6eaf2dda084..710aa472a8b 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -72,8 +72,8 @@ typedef enum WalkSelectDirection {
void FILE_OT_highlight(struct wmOperatorType *ot);
void FILE_OT_select(struct wmOperatorType *ot);
void FILE_OT_select_walk(struct wmOperatorType *ot);
-void FILE_OT_select_all_toggle(struct wmOperatorType *ot);
-void FILE_OT_select_border(struct wmOperatorType *ot);
+void FILE_OT_select_all(struct wmOperatorType *ot);
+void FILE_OT_select_box(struct wmOperatorType *ot);
void FILE_OT_select_bookmark(struct wmOperatorType *ot);
void FILE_OT_bookmark_add(struct wmOperatorType *ot);
void FILE_OT_bookmark_delete(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 429b643a807..ea73026020d 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -37,10 +37,10 @@
#include "BKE_appdir.h"
#include "BKE_context.h"
-#include "BKE_screen.h"
#include "BKE_global.h"
-#include "BKE_report.h"
#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -113,7 +113,7 @@ typedef enum FileSelect {
static void clamp_to_filelist(int numfiles, FileSelection *sel)
{
- /* border select before the first file */
+ /* box select before the first file */
if ( (sel->first < 0) && (sel->last >= 0) ) {
sel->first = 0;
}
@@ -338,7 +338,7 @@ static FileSelect file_select(bContext *C, const rcti *rect, FileSelType select,
return retval;
}
-static int file_border_select_find_last_selected(
+static int file_box_select_find_last_selected(
SpaceFile *sfile, ARegion *ar, const FileSelection *sel,
const int mouse_xy[2])
{
@@ -371,7 +371,7 @@ static int file_border_select_find_last_selected(
return (dist_first < dist_last) ? sel->first : sel->last;
}
-static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
+static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -381,7 +381,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
int result;
- result = WM_gesture_border_modal(C, op, event);
+ result = WM_gesture_box_modal(C, op, event);
if (result == OPERATOR_RUNNING_MODAL) {
WM_operator_properties_border_to_rcti(op, &rect);
@@ -399,7 +399,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
for (idx = sel.last; idx >= 0; idx--) {
const FileDirEntry *file = filelist_file(sfile->files, idx);
- /* dont highlight readonly file (".." or ".") on border select */
+ /* dont highlight readonly file (".." or ".") on box select */
if (FILENAME_IS_CURRPAR(file->relpath)) {
filelist_entry_select_set(sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
}
@@ -411,7 +411,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
}
}
params->sel_first = sel.first; params->sel_last = sel.last;
- params->active_file = file_border_select_find_last_selected(sfile, ar, &sel, event->mval);
+ params->active_file = file_box_select_find_last_selected(sfile, ar, &sel, event->mval);
}
else {
params->highlight_file = -1;
@@ -424,7 +424,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
return result;
}
-static int file_border_select_exec(bContext *C, wmOperator *op)
+static int file_box_select_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -455,22 +455,22 @@ static int file_border_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void FILE_OT_select_border(wmOperatorType *ot)
+void FILE_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Activate/Select File";
+ ot->name = "Box Select";
ot->description = "Activate/select the file(s) contained in the border";
- ot->idname = "FILE_OT_select_border";
+ ot->idname = "FILE_OT_select_box";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = file_border_select_exec;
- ot->modal = file_border_select_modal;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = file_box_select_exec;
+ ot->modal = file_box_select_modal;
ot->poll = ED_operator_file_active;
- ot->cancel = WM_gesture_border_cancel;
+ ot->cancel = WM_gesture_box_cancel;
/* properties */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -527,7 +527,7 @@ void FILE_OT_select(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Activate/Select File";
+ ot->name = "Select";
ot->description = "Activate/select file";
ot->idname = "FILE_OT_select";
@@ -808,12 +808,12 @@ static int file_select_all_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void FILE_OT_select_all_toggle(wmOperatorType *ot)
+void FILE_OT_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "(De)select All Files";
ot->description = "Select or deselect all files";
- ot->idname = "FILE_OT_select_all_toggle";
+ ot->idname = "FILE_OT_select_all";
/* api callbacks */
ot->exec = file_select_all_exec;
@@ -1147,11 +1147,11 @@ static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv
SpaceFile *sfile = CTX_wm_space_file(C);
if (!file_highlight_set(sfile, ar, event->x, event->y))
- return OPERATOR_CANCELLED;
+ return OPERATOR_PASS_THROUGH;
ED_area_tag_redraw(CTX_wm_area(C));
- return OPERATOR_FINISHED;
+ return OPERATOR_PASS_THROUGH;
}
void FILE_OT_highlight(struct wmOperatorType *ot)
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index a40334098d7..cbf685e6ed8 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -80,7 +80,7 @@ static void file_panel_operator(const bContext *C, Panel *pa)
UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL);
/* Hack: temporary hide.*/
- const char *hide[] = {"filepath", "directory", "filename", "files"};
+ const char *hide[] = {"filepath", "files", "directory", "filename"};
for (int i = 0; i < ARRAY_SIZE(hide); i++) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]);
if (prop) {
@@ -88,8 +88,11 @@ static void file_panel_operator(const bContext *C, Panel *pa)
}
}
- uiTemplateOperatorPropertyButs(C, pa->layout, op, '\0', UI_TEMPLATE_OP_PROPS_SHOW_EMPTY);
+ uiTemplateOperatorPropertyButs(
+ C, pa->layout, op, UI_BUT_LABEL_ALIGN_NONE,
+ UI_TEMPLATE_OP_PROPS_SHOW_EMPTY);
+ /* Hack: temporary hide.*/
for (int i = 0; i < ARRAY_SIZE(hide); i++) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]);
if (prop) {
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index c1caf5ae8ac..fc870399696 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -26,6 +26,7 @@
#include "BLI_rect.h"
#include "BLI_fileops.h"
+#include "BLI_listbase.h"
#include "BLO_readfile.h"
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 368fc8be35c..218c7dcdb42 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -65,7 +65,6 @@
#include "BKE_context.h"
#include "BKE_global.h"
-#include "BKE_library.h"
#include "BKE_icons.h"
#include "BKE_idcode.h"
#include "BKE_main.h"
@@ -2357,7 +2356,7 @@ static void filelist_readjob_main_rec(Main *bmain, FileList *filelist)
filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika");
filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave");
filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice");
- filelist->filelist.entries[12].entry->relpath = BLI_strdup("Lamp");
+ filelist->filelist.entries[12].entry->relpath = BLI_strdup("Light");
filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera");
filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo");
filelist->filelist.entries[15].entry->relpath = BLI_strdup("World");
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 1c86ecc327b..cb014f30d95 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -221,7 +221,8 @@ 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_CF;
+ FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS |
+ FILTER_ID_LP;
if (U.uiflag & USER_HIDE_DOT) {
params->flag |= FILE_HIDE_DOT;
@@ -234,7 +235,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
if (params->type == FILE_LOADLIB) {
params->flag |= RNA_boolean_get(op->ptr, "link") ? FILE_LINK : 0;
params->flag |= RNA_boolean_get(op->ptr, "autoselect") ? FILE_AUTOSELECT : 0;
- params->flag |= RNA_boolean_get(op->ptr, "active_layer") ? FILE_ACTIVELAY : 0;
+ params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0;
}
if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 359cce45baa..9b1aae03219 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -42,8 +42,6 @@
#include "BKE_appdir.h"
-#include "DNA_space_types.h"
-
#include "ED_fileselect.h"
#ifdef WIN32
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index b0dea1eb31b..e0413e48346 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -49,6 +49,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -64,10 +65,11 @@
#include "file_intern.h" // own include
#include "fsmenu.h"
#include "filelist.h"
+#include "GPU_framebuffer.h"
/* ******************** default callbacks for file space ***************** */
-static SpaceLink *file_new(const bContext *UNUSED(C))
+static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceFile *sfile;
@@ -291,11 +293,12 @@ static void file_refresh(const bContext *C, ScrArea *sa)
file_tools_region(sa);
ED_area_initialize(wm, CTX_wm_window(C), sa);
- ED_area_tag_redraw(sa);
}
+
+ ED_area_tag_redraw(sa);
}
-static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void file_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
@@ -305,16 +308,13 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
switch (wmn->data) {
case ND_SPACE_FILE_LIST:
ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
break;
case ND_SPACE_FILE_PARAMS:
ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
break;
case ND_SPACE_FILE_PREVIEW:
if (sfile->files && filelist_cache_previews_update(sfile->files)) {
ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
}
break;
}
@@ -337,7 +337,9 @@ static void file_main_region_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void file_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void file_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -354,6 +356,42 @@ static void file_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
}
}
+static void file_main_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ SpaceFile *sfile = sa->spacedata.first;
+ FileSelectParams *params = ED_fileselect_get_params(sfile);
+ /* This is a bit odd that a region owns the subscriber for an area,
+ * keep for now since all subscribers for WM are regions.
+ * May be worth re-visiting later. */
+ wmMsgSubscribeValue msg_sub_value_area_tag_refresh = {
+ .owner = ar,
+ .user_data = sa,
+ .notify = ED_area_do_msg_notify_tag_refresh,
+ };
+
+ /* SpaceFile itself. */
+ {
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceFileBrowser, sfile, &ptr);
+
+ /* All properties for this space type. */
+ WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__);
+ }
+
+ /* FileSelectParams */
+ {
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &ptr);
+
+ /* All properties for this space type. */
+ WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__);
+ }
+}
+
static void file_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
@@ -370,8 +408,8 @@ static void file_main_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
- glClearColor(col[0], col[1], col[2], 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear_color(col[0], col[1], col[2], 0.0);
+ GPU_clear(GPU_COLOR_BIT);
/* Allow dynamically sliders to be set, saves notifiers etc. */
@@ -413,7 +451,7 @@ static void file_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
@@ -423,8 +461,8 @@ static void file_operatortypes(void)
{
WM_operatortype_append(FILE_OT_select);
WM_operatortype_append(FILE_OT_select_walk);
- WM_operatortype_append(FILE_OT_select_all_toggle);
- WM_operatortype_append(FILE_OT_select_border);
+ WM_operatortype_append(FILE_OT_select_all);
+ WM_operatortype_append(FILE_OT_select_box);
WM_operatortype_append(FILE_OT_select_bookmark);
WM_operatortype_append(FILE_OT_highlight);
WM_operatortype_append(FILE_OT_execute);
@@ -451,136 +489,14 @@ static void file_operatortypes(void)
/* NOTE: do not add .blend file reading on this level */
static void file_keymap(struct wmKeyConfig *keyconf)
{
- wmKeyMapItem *kmi;
/* keys for all regions */
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "File Browser", SPACE_FILE, 0);
-
- /* More common 'fliebrowser-like navigation' shortcuts. */
- WM_keymap_add_item(keymap, "FILE_OT_parent", UPARROWKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "FILE_OT_previous", LEFTARROWKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "FILE_OT_next", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "FILE_OT_refresh", RKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "FILE_OT_parent", PKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_previous", BACKSPACEKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_next", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0);
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", HKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.params.show_hidden");
- WM_keymap_add_item(keymap, "FILE_OT_directory_new", IKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_delete", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_verify_item(keymap, "FILE_OT_smoothscroll", TIMER1, KM_ANY, KM_ANY, 0);
-
- WM_keymap_add_item(keymap, "FILE_OT_bookmark_toggle", TKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_bookmark_add", BKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_ensure(keyconf, "File Browser", SPACE_FILE, 0);
/* keys for main region */
- keymap = WM_keymap_ensure(keyconf, "File Browser Main", SPACE_FILE, 0);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_execute", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
- RNA_boolean_set(kmi->ptr, "need_active", true);
-
- WM_keymap_add_item(keymap, "FILE_OT_refresh", PADPERIOD, KM_PRESS, 0, 0);
-
- /* left mouse selects and opens */
- WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, 0, 0);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "fill", true);
-
- /* right mouse selects without opening */
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select", RIGHTMOUSE, KM_CLICK, 0, 0);
- RNA_boolean_set(kmi->ptr, "open", false);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select", RIGHTMOUSE, KM_CLICK, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "open", false);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select", RIGHTMOUSE, KM_CLICK, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "fill", true);
- RNA_boolean_set(kmi->ptr, "open", false);
-
-
- /* arrow keys navigation (walk selecting) */
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
- RNA_boolean_set(kmi->ptr, "extend", true);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", UPARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_UP);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "fill", true);
-
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
- RNA_boolean_set(kmi->ptr, "extend", true);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", DOWNARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_DOWN);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "fill", true);
-
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
- RNA_boolean_set(kmi->ptr, "extend", true);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_LEFT);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "fill", true);
-
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
- RNA_boolean_set(kmi->ptr, "extend", true);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select_walk", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "direction", FILE_SELECT_WALK_RIGHT);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "fill", true);
-
-
- /* front and back mouse folder navigation */
- WM_keymap_add_item(keymap, "FILE_OT_previous", BUTTON4MOUSE, KM_CLICK, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_next", BUTTON5MOUSE, KM_CLICK, 0, 0);
-
- WM_keymap_add_item(keymap, "FILE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_select_border", BKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "FILE_OT_highlight", MOUSEMOVE, KM_ANY, KM_ANY, 0);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0);
- RNA_int_set(kmi->ptr, "increment", 1);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_int_set(kmi->ptr, "increment", 10);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "increment", 100);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, 0, 0);
- RNA_int_set(kmi->ptr, "increment", -1);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, KM_SHIFT, 0);
- RNA_int_set(kmi->ptr, "increment", -10);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "increment", -100);
-
+ WM_keymap_ensure(keyconf, "File Browser Main", SPACE_FILE, 0);
/* keys for button region (top) */
- keymap = WM_keymap_ensure(keyconf, "File Browser Buttons", SPACE_FILE, 0);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0);
- RNA_int_set(kmi->ptr, "increment", 1);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_int_set(kmi->ptr, "increment", 10);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "increment", 100);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, 0, 0);
- RNA_int_set(kmi->ptr, "increment", -1);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, KM_SHIFT, 0);
- RNA_int_set(kmi->ptr, "increment", -10);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADMINUS, KM_PRESS, KM_CTRL, 0);
- RNA_int_set(kmi->ptr, "increment", -100);
+ WM_keymap_ensure(keyconf, "File Browser Buttons", SPACE_FILE, 0);
}
@@ -598,10 +514,12 @@ static void file_tools_region_init(wmWindowManager *wm, ARegion *ar)
static void file_tools_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
-static void file_tools_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void file_tools_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
#if 0
/* context changes */
@@ -647,8 +565,8 @@ static void file_ui_region_draw(const bContext *C, ARegion *ar)
float col[3];
/* clear */
UI_GetThemeColor3fv(TH_BACK, col);
- glClearColor(col[0], col[1], col[2], 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear_color(col[0], col[1], col[2], 0.0);
+ GPU_clear(GPU_COLOR_BIT);
/* scrolling here is just annoying, disable it */
ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur);
@@ -663,7 +581,9 @@ static void file_ui_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
}
-static void file_ui_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void file_ui_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -677,7 +597,7 @@ static void file_ui_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR
}
}
-static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
if (drag->type == WM_DRAG_PATH) {
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -727,6 +647,7 @@ void ED_spacetype_file(void)
art->init = file_main_region_init;
art->draw = file_main_region_draw;
art->listener = file_main_region_listener;
+ art->message_subscribe = file_main_region_message_subscribe;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt
index 40a196fa95b..2840324e65e 100644
--- a/source/blender/editors/space_graph/CMakeLists.txt
+++ b/source/blender/editors/space_graph/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
@@ -48,7 +49,7 @@ set(SRC
)
if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+ add_definitions(-DWITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index d3f3a4e3395..a9e5ee67cc9 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -46,15 +46,17 @@
#include "BLT_translation.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
#include "BKE_global.h"
#include "BKE_screen.h"
#include "BKE_unit.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -154,17 +156,12 @@ static void graph_panel_properties(const bContext *C, Panel *pa)
PointerRNA fcu_ptr;
uiLayout *layout = pa->layout;
uiLayout *col, *row, *sub;
- // uiBlock *block; // UNUSED
char name[256];
int icon = 0;
if (!graph_panel_context(C, &ale, &fcu))
return;
- // UNUSED
- // block = uiLayoutGetBlock(layout);
- // UI_block_func_handle_set(block, do_graph_region_buttons, NULL);
-
/* F-Curve pointer */
RNA_pointer_create(ale->id, &RNA_FCurve, fcu, &fcu_ptr);
@@ -472,7 +469,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
#define B_IPO_DEPCHANGE 10
-static void do_graph_region_driver_buttons(bContext *C, void *UNUSED(arg), int event)
+static void do_graph_region_driver_buttons(bContext *C, void *id_v, int event)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -480,8 +477,34 @@ static void do_graph_region_driver_buttons(bContext *C, void *UNUSED(arg), int e
switch (event) {
case B_IPO_DEPCHANGE:
{
- /* rebuild depsgraph for the new deps */
- DAG_relations_tag_update(bmain);
+ /* Was not actually run ever (NULL always passed as arg to this callback).
+ * If needed again, will need to check how to pass both fcurve and ID... :/ */
+#if 0
+ /* force F-Curve & Driver to get re-evaluated (same as the old Update Dependencies) */
+ FCurve *fcu = (FCurve *)fcu_v;
+ ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
+
+ /* clear invalid flags */
+ if (fcu) {
+ fcu->flag &= ~FCURVE_DISABLED;
+ driver->flag &= ~DRIVER_FLAG_INVALID;
+ }
+#endif
+ ID *id = id_v;
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ /* rebuild depsgraph for the new deps, and ensure COW copies get flushed. */
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update_ex(bmain, id, DEG_TAG_COPY_ON_WRITE);
+ if (adt != NULL) {
+ if (adt->action != NULL) {
+ DEG_id_tag_update_ex(bmain, &adt->action->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ if (adt->tmpact != NULL) {
+ DEG_id_tag_update_ex(bmain, &adt->tmpact->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+
break;
}
}
@@ -490,23 +513,6 @@ static void do_graph_region_driver_buttons(bContext *C, void *UNUSED(arg), int e
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); // XXX could use better notifier
}
-/* callback to remove the active driver */
-static void driver_remove_cb(bContext *C, void *ale_v, void *UNUSED(arg))
-{
- bAnimListElem *ale = (bAnimListElem *)ale_v;
- ID *id = ale->id;
- FCurve *fcu = ale->data;
- ReportList *reports = CTX_wm_reports(C);
-
- /* try to get F-Curve that driver lives on, and ID block which has this AnimData */
- if (ELEM(NULL, id, fcu))
- return;
-
- /* call API method to remove this driver */
- ANIM_remove_driver(reports, id, fcu->rna_path, fcu->array_index, 0);
- ED_undo_push(C, "Remove Driver");
-}
-
/* callback to add a target variable to the active driver */
static void driver_add_var_cb(bContext *C, void *driver_v, void *UNUSED(arg))
{
@@ -728,65 +734,101 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
uiItemR(sub, &dtar_ptr, "transform_space", 0, IFACE_("Space"), ICON_NONE);
}
-/* driver settings for active F-Curve (only for 'Drivers' mode) */
-static void graph_panel_drivers(const bContext *C, Panel *pa)
+/* ----------------------------------------------------------------- */
+
+
+/* property driven by the driver - duplicates Active FCurve, but useful for clarity */
+static void graph_draw_driven_property_panel(uiLayout *layout, ID *id, FCurve *fcu)
{
- bAnimListElem *ale;
- FCurve *fcu;
- ChannelDriver *driver;
+ PointerRNA fcu_ptr;
+ uiLayout *row;
+ char name[256];
+ int icon = 0;
+
+ /* F-Curve pointer */
+ RNA_pointer_create(id, &RNA_FCurve, fcu, &fcu_ptr);
+
+ /* get user-friendly 'name' for F-Curve */
+ icon = getname_anim_fcurve(name, id, fcu);
+
+ /* panel layout... */
+ row = uiLayoutRow(layout, true);
+ uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
+
+ /* -> user friendly 'name' for datablock that owns F-Curve */
+ /* XXX: Actually, we may need the datablock icons only... (e.g. right now will show bone for bone props) */
+ uiItemL(row, id->name + 2, icon);
+
+ /* -> user friendly 'name' for F-Curve/driver target */
+ uiItemL(row, "", ICON_SMALL_TRI_RIGHT_VEC);
+ uiItemL(row, name, ICON_RNA);
+}
+
+/* UI properties panel layout for driver settings - shared for Drivers Editor and for */
+static void graph_draw_driver_settings_panel(uiLayout *layout, ID *id, FCurve *fcu, const bool is_popover)
+{
+ ChannelDriver *driver = fcu->driver;
DriverVar *dvar;
PointerRNA driver_ptr;
- uiLayout *col;
+ uiLayout *col, *row;
uiBlock *block;
uiBut *but;
- /* Get settings from context */
- if (!graph_panel_context(C, &ale, &fcu))
- return;
- driver = fcu->driver;
-
/* set event handler for panel */
- block = uiLayoutGetBlock(pa->layout); // xxx?
- UI_block_func_handle_set(block, do_graph_region_driver_buttons, NULL);
-
- /* general actions - management */
- col = uiLayoutColumn(pa->layout, false);
- block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_FILE_REFRESH, IFACE_("Update Dependencies"),
- 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0, 0,
- TIP_("Force updates of dependencies"));
- UI_but_func_set(but, driver_update_flags_cb, fcu, NULL);
-
- but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMOUT, IFACE_("Remove Driver"),
- 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0, 0,
- TIP_("Remove this driver"));
- UI_but_funcN_set(but, driver_remove_cb, MEM_dupallocN(ale), NULL);
+ block = uiLayoutGetBlock(layout);
+ UI_block_func_handle_set(block, do_graph_region_driver_buttons, id);
/* driver-level settings - type, expressions, and errors */
- RNA_pointer_create(ale->id, &RNA_Driver, driver, &driver_ptr);
+ RNA_pointer_create(id, &RNA_Driver, driver, &driver_ptr);
- col = uiLayoutColumn(pa->layout, true);
+ col = uiLayoutColumn(layout, true);
block = uiLayoutGetBlock(col);
uiItemR(col, &driver_ptr, "type", 0, NULL, ICON_NONE);
+ {
+ char valBuf[32];
+
+ /* value of driver */
+ row = uiLayoutRow(col, true);
+ uiItemL(row, IFACE_("Driver Value:"), ICON_NONE);
+ BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", driver->curval);
+ uiItemL(row, valBuf, ICON_NONE);
+ }
+
+ uiItemS(layout);
+ uiItemS(layout);
+
/* show expression box if doing scripted drivers, and/or error messages when invalid drivers exist */
if (driver->type == DRIVER_TYPE_PYTHON) {
bool bpy_data_expr_error = (strstr(driver->expression, "bpy.data.") != NULL);
bool bpy_ctx_expr_error = (strstr(driver->expression, "bpy.context.") != NULL);
/* expression */
- uiItemR(col, &driver_ptr, "expression", 0, IFACE_("Expr"), ICON_NONE);
+ /* TODO: "Show syntax hints" button */
+ col = uiLayoutColumn(layout, true);
+ block = uiLayoutGetBlock(col);
+
+ uiItemL(col, IFACE_("Expression:"), ICON_NONE);
+ uiItemR(col, &driver_ptr, "expression", 0, "", ICON_NONE);
+ uiItemR(col, &driver_ptr, "use_self", 0, NULL, ICON_NONE);
/* errors? */
- if ((G.f & G_SCRIPT_AUTOEXEC) == 0) {
- uiItemL(col, IFACE_("WARNING: Python expressions limited for security"), ICON_ERROR);
- }
- else if (driver->flag & DRIVER_FLAG_INVALID) {
+ col = uiLayoutColumn(layout, true);
+ block = uiLayoutGetBlock(col);
+
+ if (driver->flag & DRIVER_FLAG_INVALID) {
uiItemL(col, IFACE_("ERROR: Invalid Python expression"), ICON_CANCEL);
}
+ else if (!BKE_driver_has_simple_expression(driver)) {
+ if ((G.f & G_SCRIPT_AUTOEXEC) == 0) {
+ /* TODO: Add button to enable? */
+ uiItemL(col, IFACE_("WARNING: Python expressions limited for security"), ICON_ERROR);
+ }
+ else {
+ uiItemL(col, IFACE_("Slow Python expression"), ICON_INFO);
+ }
+ }
/* Explicit bpy-references are evil. Warn about these to prevent errors */
/* TODO: put these in a box? */
@@ -803,6 +845,9 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
}
else {
/* errors? */
+ col = uiLayoutColumn(layout, true);
+ block = uiLayoutGetBlock(col);
+
if (driver->flag & DRIVER_FLAG_INVALID)
uiItemL(col, IFACE_("ERROR: Invalid target channel(s)"), ICON_ERROR);
@@ -822,37 +867,31 @@ 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);
-
- /* value of driver */
- if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
- uiLayout *row = uiLayoutRow(col, true);
- char valBuf[32];
-
- uiItemL(row, IFACE_("Driver Value:"), ICON_NONE);
-
- BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", driver->curval);
- uiItemL(row, valBuf, ICON_NONE);
- }
+ uiItemS(layout);
/* add/copy/paste driver variables */
- {
- uiLayout *row;
+ if (is_popover) {
+ /* add driver variable - add blank */
+ row = uiLayoutRow(layout, true);
+ block = uiLayoutGetBlock(row);
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ADD, IFACE_("Add Input Variable"),
+ 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0, 0,
+ TIP_("Add a Driver Variable to keep track an input used by the driver"));
+ UI_but_func_set(but, driver_add_var_cb, driver, NULL);
+ /* add driver variable - add using eyedropper */
+ /* XXX: will this operator work like this? */
+ uiItemO(row, "", ICON_EYEDROPPER, "UI_OT_eyedropper_driver");
+ }
+ else {
/* add driver variable */
- row = uiLayoutRow(pa->layout, false);
+ row = uiLayoutRow(layout, false);
block = uiLayoutGetBlock(row);
- but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"),
- 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0, 0,
- TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly"));
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ADD, IFACE_("Add Input Variable"),
+ 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0, 0,
+ TIP_("Driver variables ensure that all dependencies will be accounted for, ensuring that drivers will update correctly"));
UI_but_func_set(but, driver_add_var_cb, driver, NULL);
/* copy/paste (as sub-row) */
@@ -866,15 +905,15 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
/* loop over targets, drawing them */
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
PointerRNA dvar_ptr;
- uiLayout *box, *row;
+ uiLayout *box;
uiLayout *subrow, *sub;
/* sub-layout column for this variable's settings */
- col = uiLayoutColumn(pa->layout, true);
+ col = uiLayoutColumn(layout, true);
/* 1) header panel */
box = uiLayoutBox(col);
- RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
+ RNA_pointer_create(id, &RNA_DriverVariable, dvar, &dvar_ptr);
row = uiLayoutRow(box, false);
block = uiLayoutGetBlock(row);
@@ -915,21 +954,21 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
/* controls to draw depends on the type of variable */
switch (dvar->type) {
case DVAR_TYPE_SINGLE_PROP: /* single property */
- graph_panel_driverVar__singleProp(box, ale->id, dvar);
+ graph_panel_driverVar__singleProp(box, id, dvar);
break;
case DVAR_TYPE_ROT_DIFF: /* rotational difference */
- graph_panel_driverVar__rotDiff(box, ale->id, dvar);
+ graph_panel_driverVar__rotDiff(box, id, dvar);
break;
case DVAR_TYPE_LOC_DIFF: /* location difference */
- graph_panel_driverVar__locDiff(box, ale->id, dvar);
+ graph_panel_driverVar__locDiff(box, id, dvar);
break;
case DVAR_TYPE_TRANSFORM_CHAN: /* transform channel */
- graph_panel_driverVar__transChan(box, ale->id, dvar);
+ graph_panel_driverVar__transChan(box, id, dvar);
break;
}
/* 3) value of variable */
- if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
+ {
char valBuf[32];
box = uiLayoutBox(col);
@@ -951,10 +990,108 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
}
}
+ uiItemS(layout);
+ uiItemS(layout);
+
+ /* XXX: This should become redundant. But sometimes the flushing fails, so keep this around for a while longer as a "last resort" */
+ row = uiLayoutRow(layout, true);
+ block = uiLayoutGetBlock(row);
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_FILE_REFRESH, IFACE_("Update Dependencies"),
+ 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0, 0,
+ TIP_("Force updates of dependencies - Only use this if drivers are not updating correctly"));
+ UI_but_func_set(but, driver_update_flags_cb, fcu, NULL);
+}
+
+/* ----------------------------------------------------------------- */
+
+
+/* panel to show property driven by the driver (in Drivers Editor) - duplicates Active FCurve, but useful for clarity */
+static void graph_panel_driven_property(const bContext *C, Panel *pa)
+{
+ bAnimListElem *ale;
+ FCurve *fcu;
+
+ if (!graph_panel_context(C, &ale, &fcu))
+ return;
+
+ graph_draw_driven_property_panel(pa->layout, ale->id, fcu);
+
+ MEM_freeN(ale);
+}
+
+/* driver settings for active F-Curve (only for 'Drivers' mode in Graph Editor, i.e. the full "Drivers Editor") */
+static void graph_panel_drivers(const bContext *C, Panel *pa)
+{
+ bAnimListElem *ale;
+ FCurve *fcu;
+
+ /* Get settings from context */
+ if (!graph_panel_context(C, &ale, &fcu))
+ return;
+
+ graph_draw_driver_settings_panel(pa->layout, ale->id, fcu, false);
+
/* cleanup */
MEM_freeN(ale);
}
+/* ----------------------------------------------------------------- */
+
+/* poll to make this not show up in the graph editor, as this is only to be used as a popup elsewhere */
+static bool graph_panel_drivers_popover_poll(const bContext *C, PanelType *UNUSED(pt))
+{
+ return ED_operator_graphedit_active((bContext *)C) == false;
+}
+
+/* popover panel for driver editing anywhere in ui */
+static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
+{
+ uiLayout *layout = pa->layout;
+
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index = -1;
+ uiBut *but = NULL;
+
+ /* Get active property to show driver properties for */
+ but = UI_context_active_but_prop_get((bContext *)C, &ptr, &prop, &index);
+ if (but) {
+ FCurve *fcu;
+ bool driven, special;
+
+ fcu = rna_get_fcurve_context_ui((bContext *)C,
+ &ptr, prop, index,
+ NULL, NULL, &driven, &special);
+
+ /* Hack: Force all buttons in this panel to be able to know the driver button
+ * this panel is getting spawned from, so that things like the "Open Drivers Editor"
+ * button will work.
+ */
+ uiLayoutSetContextFromBut(layout, but);
+
+ /* Populate Panel - With a combination of the contents of the Driven and Driver panels */
+ if (fcu) {
+ ID *id = ptr.id.data;
+
+ /* Driven Property Settings */
+ uiItemL(layout, IFACE_("Driven Property:"), ICON_NONE);
+ graph_draw_driven_property_panel(pa->layout, id, fcu);
+ /* TODO: All vs Single */
+
+ uiItemS(layout);
+ uiItemS(layout);
+
+ /* Drivers Settings */
+ uiItemL(layout, IFACE_("Driver Settings:"), ICON_NONE);
+ graph_draw_driver_settings_panel(pa->layout, id, fcu, true);
+ }
+ }
+
+ /* Show drivers editor is always visible */
+ uiItemO(layout, IFACE_("Show in Drivers Editor"), ICON_DRIVER, "SCREEN_OT_drivers_editor_show");
+}
+
/* ******************* F-Modifiers ******************************** */
/* All the drawing code is in editors/animation/fmodifier_ui.c */
@@ -1035,16 +1172,34 @@ void graph_buttons_register(ARegionType *art)
pt->poll = graph_panel_poll;
BLI_addtail(&art->paneltypes, pt);
+ pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers driven");
+ strcpy(pt->idname, "GRAPH_PT_driven_property");
+ strcpy(pt->label, N_("Driven Property"));
+ strcpy(pt->category, "Drivers");
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw = graph_panel_driven_property;
+ pt->poll = graph_panel_drivers_poll;
+ BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
strcpy(pt->idname, "GRAPH_PT_drivers");
- strcpy(pt->label, N_("Drivers"));
+ strcpy(pt->label, N_("Driver"));
strcpy(pt->category, "Drivers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_drivers;
pt->poll = graph_panel_drivers_poll;
BLI_addtail(&art->paneltypes, pt);
+ pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers pover");
+ strcpy(pt->idname, "GRAPH_PT_drivers_popover");
+ strcpy(pt->label, N_("Add/Edit Driver"));
+ strcpy(pt->category, "Drivers");
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw = graph_panel_drivers_popover;
+ pt->poll = graph_panel_drivers_popover_poll;
+ BLI_addtail(&art->paneltypes, pt);
+ WM_paneltype_add(pt); /* This panel isn't used in this region. Add explicitly to global list (so popovers work). */
+
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
strcpy(pt->idname, "GRAPH_PT_modifiers");
strcpy(pt->label, N_("Modifiers"));
@@ -1076,7 +1231,7 @@ static int graph_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void GRAPH_OT_properties(wmOperatorType *ot)
{
- ot->name = "Properties";
+ ot->name = "Toggle Sidebar";
ot->idname = "GRAPH_OT_properties";
ot->description = "Toggle the properties region visibility";
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 6823a4343a7..65bf8af70e8 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -46,10 +46,13 @@
#include "BKE_curve.h"
#include "BKE_fcurve.h"
-
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "ED_anim_api.h"
#include "graph_intern.h"
@@ -83,37 +86,58 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
const float fac = 0.05f * BLI_rctf_size_x(&v2d->cur);
int i;
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* Simple dashes. */
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+ immUniform1f("dash_width", 10.0f);
+ immUniform1f("dash_factor", 0.5f);
+
/* draw two black lines showing the standard reference levels */
- glColor3f(0.0f, 0.0f, 0.0f);
- glLineWidth(1);
- setlinestyle(5);
- glBegin(GL_LINES);
- glVertex2f(v2d->cur.xmin, env->midval + env->min);
- glVertex2f(v2d->cur.xmax, env->midval + env->min);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(shdr_pos, v2d->cur.xmin, env->midval + env->min);
+ immVertex2f(shdr_pos, v2d->cur.xmax, env->midval + env->min);
- glVertex2f(v2d->cur.xmin, env->midval + env->max);
- glVertex2f(v2d->cur.xmax, env->midval + env->max);
- glEnd();
- setlinestyle(0);
+ immVertex2f(shdr_pos, v2d->cur.xmin, env->midval + env->max);
+ immVertex2f(shdr_pos, v2d->cur.xmax, env->midval + env->max);
+ immEnd();
- /* set size of vertices (non-adjustable for now) */
- glPointSize(2.0f);
+ immUnbindProgram();
- /* for now, point color is fixed, and is white */
- glColor3f(1.0f, 1.0f, 1.0f);
+ if (env->totvert > 0) {
+ /* set size of vertices (non-adjustable for now) */
+ GPU_point_size(2.0f);
- glBegin(GL_POINTS);
- for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
- /* only draw if visible
- * - min/max here are fixed, not relative
- */
- if (IN_RANGE(fed->time, (v2d->cur.xmin - fac), (v2d->cur.xmax + fac))) {
- glVertex2f(fed->time, fed->min);
- glVertex2f(fed->time, fed->max);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* for now, point color is fixed, and is white */
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ immBeginAtMost(GPU_PRIM_POINTS, env->totvert * 2);
+
+ for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
+ /* only draw if visible
+ * - min/max here are fixed, not relative
+ */
+ if (IN_RANGE(fed->time, (v2d->cur.xmin - fac), (v2d->cur.xmax + fac))) {
+ immVertex2f(shdr_pos, fed->time, fed->min);
+ immVertex2f(shdr_pos, fed->time, fed->max);
+ }
}
+
+ immEnd();
+
+ immUnbindProgram();
}
- glEnd();
}
/* *************************** */
@@ -121,16 +145,43 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
/* Points ---------------- */
-/* helper func - draw keyframe vertices only for an F-Curve */
-static void draw_fcurve_vertices_keyframes(FCurve *fcu, SpaceIpo *UNUSED(sipo), View2D *v2d, short edit, short sel)
+/* helper func - set color to draw F-Curve data with */
+static void set_fcurve_vertex_color(FCurve *fcu, bool sel)
+{
+ float color[4];
+ float diff;
+
+ /* Set color of curve vertex based on state of curve (i.e. 'Edit' Mode) */
+ if ((fcu->flag & FCURVE_PROTECTED) == 0) {
+ /* Curve's points ARE BEING edited */
+ UI_GetThemeColor3fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, color);
+ }
+ else {
+ /* Curve's points CANNOT BE edited */
+ UI_GetThemeColor3fv(sel ? TH_TEXT_HI : TH_TEXT, color);
+ }
+
+ /* Fade the 'intensity' of the vertices based on the selection of the curves too
+ * - Only fade by 50% the amount the curves were faded by, so that the points
+ * still stand out for easier selection
+ */
+ diff = 1.0f - fcurve_display_alpha(fcu);
+ color[3] = 1.0f - (diff * 0.5f);
+ CLAMP(color[3], 0.2f, 1.0f);
+
+ immUniformColor4fv(color);
+}
+
+static void draw_fcurve_selected_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, bool sel, unsigned pos)
{
- BezTriple *bezt = fcu->bezt;
const float fac = 0.05f * BLI_rctf_size_x(&v2d->cur);
- int i;
- glBegin(GL_POINTS);
+ set_fcurve_vertex_color(fcu, sel);
- for (i = 0; i < fcu->totvert; i++, bezt++) {
+ immBeginAtMost(GPU_PRIM_POINTS, fcu->totvert);
+
+ BezTriple *bezt = fcu->bezt;
+ for (int i = 0; i < fcu->totvert; i++, bezt++) {
/* as an optimization step, only draw those in view
* - we apply a correction factor to ensure that points don't pop in/out due to slight twitches of view size
*/
@@ -141,79 +192,49 @@ static void draw_fcurve_vertices_keyframes(FCurve *fcu, SpaceIpo *UNUSED(sipo),
* -
*/
if ((bezt->f2 & SELECT) == sel)
- glVertex3fv(bezt->vec[1]);
+ immVertex2fv(pos, bezt->vec[1]);
}
else {
/* no check for selection here, as curve is not editable... */
/* XXX perhaps we don't want to even draw points? maybe add an option for that later */
- glVertex3fv(bezt->vec[1]);
+ immVertex2fv(pos, bezt->vec[1]);
}
}
}
- glEnd();
+ immEnd();
}
-
-/* helper func - draw handle vertex for an F-Curve as a round unfilled circle
- * NOTE: the caller MUST HAVE GL_LINE_SMOOTH & GL_BLEND ENABLED, otherwise, the controls don't
- * have a consistent appearance (due to off-pixel alignments)...
- */
-static void draw_fcurve_handle_control(float x, float y, float xscale, float yscale, float hsize)
+/* helper func - draw keyframe vertices only for an F-Curve */
+static void draw_fcurve_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, unsigned pos)
{
- static GLuint displist = 0;
-
- /* initialize round circle shape */
- if (displist == 0) {
- GLUquadricObj *qobj;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
- gluDisk(qobj, 0, 0.7, 8, 1);
- gluDeleteQuadric(qobj);
-
- glEndList();
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- /* adjust view transform before starting */
- glTranslatef(x, y, 0.0f);
- glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f);
+ immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize);
- /* draw! */
- glCallList(displist);
+ draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, false, pos);
+ draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, true, pos);
- /* restore view transform */
- glScalef(xscale / hsize, yscale / hsize, 1.0);
- glTranslatef(-x, -y, 0.0f);
+ immUnbindProgram();
}
+
/* helper func - draw handle vertices only for an F-Curve (if it is not protected) */
-static void draw_fcurve_vertices_handles(FCurve *fcu, SpaceIpo *sipo, View2D *v2d, short sel, short sel_handle_only, float units_scale)
+static void draw_fcurve_selected_handle_vertices(FCurve *fcu, View2D *v2d, bool sel, bool sel_handle_only, unsigned pos)
{
- BezTriple *bezt = fcu->bezt;
- BezTriple *prevbezt = NULL;
- float hsize, xscale, yscale;
- int i;
-
- /* get view settings */
- hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
- UI_view2d_scale_get(v2d, &xscale, &yscale);
-
- /* Compensate OGL scale sued for unit mapping, so circle will be circle, not ellipse */
- yscale *= units_scale;
+ (void) v2d; /* TODO: use this to draw only points in view */
/* set handle color */
- if (sel) UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
- else UI_ThemeColor(TH_HANDLE_VERTEX);
+ float hcolor[3];
+ UI_GetThemeColor3fv(sel ? TH_HANDLE_VERTEX_SELECT : TH_HANDLE_VERTEX, hcolor);
+ immUniform4f("outlineColor", hcolor[0], hcolor[1], hcolor[2], 1.0f);
+ immUniformColor3fvAlpha(hcolor, 0.01f); /* almost invisible - only keep for smoothness */
- /* anti-aliased lines for more consistent appearance */
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ immBeginAtMost(GPU_PRIM_POINTS, fcu->totvert * 2);
- for (i = 0; i < fcu->totvert; i++, prevbezt = bezt, bezt++) {
+ BezTriple *bezt = fcu->bezt;
+ BezTriple *prevbezt = NULL;
+ for (int i = 0; i < fcu->totvert; i++, prevbezt = bezt, bezt++) {
/* Draw the editmode handles for a bezier curve (others don't have handles)
* if their selection status matches the selection status we're drawing for
* - first handle only if previous beztriple was bezier-mode
@@ -225,68 +246,61 @@ static void draw_fcurve_vertices_handles(FCurve *fcu, SpaceIpo *sipo, View2D *v2
if (!sel_handle_only || BEZT_ISSEL_ANY(bezt)) {
if ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) {
if ((bezt->f1 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[0][0] < v2d->cur.xmax)*/
- draw_fcurve_handle_control(bezt->vec[0][0], bezt->vec[0][1], xscale, yscale, hsize);
+ immVertex2fv(pos, bezt->vec[0]);
}
if (bezt->ipo == BEZT_IPO_BEZ) {
if ((bezt->f3 & SELECT) == sel) /* && v2d->cur.xmin < bezt->vec[2][0] < v2d->cur.xmax)*/
- draw_fcurve_handle_control(bezt->vec[2][0], bezt->vec[2][1], xscale, yscale, hsize);
+ immVertex2fv(pos, bezt->vec[2]);
}
}
}
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ immEnd();
}
-/* helper func - set color to draw F-Curve data with */
-static void set_fcurve_vertex_color(FCurve *fcu, short sel)
+/* helper func - draw handle vertices only for an F-Curve (if it is not protected) */
+static void draw_fcurve_handle_vertices(FCurve *fcu, View2D *v2d, bool sel_handle_only, unsigned pos)
{
- /* Fade the 'intensity' of the vertices based on the selection of the curves too */
- int alphaOffset = (int)((fcurve_display_alpha(fcu) - 1.0f) * 255);
+ /* smooth outlines for more consistent appearance */
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
- /* Set color of curve vertex based on state of curve (i.e. 'Edit' Mode) */
- if ((fcu->flag & FCURVE_PROTECTED) == 0) {
- /* Curve's points ARE BEING edited */
- if (sel) UI_ThemeColorShadeAlpha(TH_VERTEX_SELECT, 0, alphaOffset);
- else UI_ThemeColorShadeAlpha(TH_VERTEX, 0, alphaOffset);
- }
- else {
- /* Curve's points CANNOT BE edited */
- if (sel) UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, alphaOffset);
- else UI_ThemeColorShadeAlpha(TH_TEXT, 0, alphaOffset);
- }
+ /* set handle size */
+ immUniform1f("size", (1.4f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE)) * U.pixelsize);
+ immUniform1f("outlineWidth", 1.5f * U.pixelsize);
+
+ draw_fcurve_selected_handle_vertices(fcu, v2d, false, sel_handle_only, pos);
+ draw_fcurve_selected_handle_vertices(fcu, v2d, true, sel_handle_only, pos);
+
+ immUnbindProgram();
}
-static void draw_fcurve_vertices(SpaceIpo *sipo, ARegion *ar, FCurve *fcu, short do_handles, short sel_handle_only, float units_scale)
+static void draw_fcurve_vertices(ARegion *ar, FCurve *fcu, bool do_handles, bool sel_handle_only)
{
View2D *v2d = &ar->v2d;
/* only draw points if curve is visible
- * - draw unselected points before selected points as separate passes to minimize color-changing overhead
- * (XXX dunno if this is faster than drawing all in one pass though)
- * and also to make sure in the case of overlapping points that the selected is always visible
+ * - draw unselected points before selected points as separate passes
+ * to make sure in the case of overlapping points that the selected is always visible
* - draw handles before keyframes, so that keyframes will overlap handles (keyframes are more important for users)
*/
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPU_blend(true);
+ GPU_enable_program_point_size();
/* draw the two handles first (if they're shown, the curve doesn't have just a single keyframe, and the curve is being edited) */
if (do_handles) {
- set_fcurve_vertex_color(fcu, 0);
- draw_fcurve_vertices_handles(fcu, sipo, v2d, 0, sel_handle_only, units_scale);
-
- set_fcurve_vertex_color(fcu, 1);
- draw_fcurve_vertices_handles(fcu, sipo, v2d, 1, sel_handle_only, units_scale);
+ draw_fcurve_handle_vertices(fcu, v2d, sel_handle_only, pos);
}
/* draw keyframes over the handles */
- set_fcurve_vertex_color(fcu, 0);
- draw_fcurve_vertices_keyframes(fcu, sipo, v2d, !(fcu->flag & FCURVE_PROTECTED), 0);
+ draw_fcurve_keyframe_vertices(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), pos);
- set_fcurve_vertex_color(fcu, 1);
- draw_fcurve_vertices_keyframes(fcu, sipo, v2d, !(fcu->flag & FCURVE_PROTECTED), 1);
+ GPU_disable_program_point_size();
+ GPU_blend(false);
}
/* Handles ---------------- */
@@ -303,10 +317,10 @@ static bool draw_fcurve_handles_check(SpaceIpo *sipo, FCurve *fcu)
(fcu->totvert <= 1) /* do not show handles if there is only 1 keyframe, otherwise they all clump together in an ugly ball */
)
{
- return 0;
+ return false;
}
else {
- return 1;
+ return true;
}
}
@@ -316,11 +330,12 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu)
{
int sel, b;
- /* a single call to GL_LINES here around these calls should be sufficient to still
- * get separate line segments, but which aren't wrapped with GL_LINE_STRIP every time we
- * want a single line
- */
- glBegin(GL_LINES);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+
+ immBeginAtMost(GPU_PRIM_LINES, 4 * 2 * fcu->totvert);
/* slightly hacky, but we want to draw unselected points before selected ones
* so that selected points are clearly visible
@@ -348,18 +363,20 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu)
if ((!prevbezt && (bezt->ipo == BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ))) {
UI_GetThemeColor3ubv(basecol + bezt->h1, col);
col[3] = fcurve_display_alpha(fcu) * 255;
- glColor4ubv((GLubyte *)col);
-
- glVertex2fv(fp); glVertex2fv(fp + 3);
+ immAttr4ubv(color, col);
+ immVertex2fv(pos, fp);
+ immAttr4ubv(color, col);
+ immVertex2fv(pos, fp + 3);
}
/* only draw second handle if this segment is bezier */
if (bezt->ipo == BEZT_IPO_BEZ) {
UI_GetThemeColor3ubv(basecol + bezt->h2, col);
col[3] = fcurve_display_alpha(fcu) * 255;
- glColor4ubv((GLubyte *)col);
-
- glVertex2fv(fp + 3); glVertex2fv(fp + 6);
+ immAttr4ubv(color, col);
+ immVertex2fv(pos, fp + 3);
+ immAttr4ubv(color, col);
+ immVertex2fv(pos, fp + 6);
}
}
else {
@@ -370,9 +387,10 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu)
fp = bezt->vec[0];
UI_GetThemeColor3ubv(basecol + bezt->h1, col);
col[3] = fcurve_display_alpha(fcu) * 255;
- glColor4ubv((GLubyte *)col);
-
- glVertex2fv(fp); glVertex2fv(fp + 3);
+ immAttr4ubv(color, col);
+ immVertex2fv(pos, fp);
+ immAttr4ubv(color, col);
+ immVertex2fv(pos, fp + 3);
}
/* only draw second handle if this segment is bezier, and selection is ok */
@@ -382,15 +400,17 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu)
fp = bezt->vec[1];
UI_GetThemeColor3ubv(basecol + bezt->h2, col);
col[3] = fcurve_display_alpha(fcu) * 255;
- glColor4ubv((GLubyte *)col);
-
- glVertex2fv(fp); glVertex2fv(fp + 3);
+ immAttr4ubv(color, col);
+ immVertex2fv(pos, fp);
+ immAttr4ubv(color, col);
+ immVertex2fv(pos, fp + 3);
}
}
}
}
- glEnd(); /* GL_LINES */
+ immEnd();
+ immUnbindProgram();
}
/* Samples ---------------- */
@@ -399,36 +419,24 @@ static void draw_fcurve_handles(SpaceIpo *sipo, FCurve *fcu)
* NOTE: the caller MUST HAVE GL_LINE_SMOOTH & GL_BLEND ENABLED, otherwise, the controls don't
* have a consistent appearance (due to off-pixel alignments)...
*/
-static void draw_fcurve_sample_control(float x, float y, float xscale, float yscale, float hsize)
+static void draw_fcurve_sample_control(float x, float y, float xscale, float yscale, float hsize, unsigned int pos)
{
- static GLuint displist = 0;
-
- /* initialize X shape */
- if (displist == 0) {
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- glBegin(GL_LINES);
- glVertex2f(-0.7f, -0.7f);
- glVertex2f(+0.7f, +0.7f);
-
- glVertex2f(-0.7f, +0.7f);
- glVertex2f(+0.7f, -0.7f);
- glEnd(); /* GL_LINES */
-
- glEndList();
- }
-
/* adjust view transform before starting */
- glTranslatef(x, y, 0.0f);
- glScalef(1.0f / xscale * hsize, 1.0f / yscale * hsize, 1.0f);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_scale_2f(1.0f / xscale * hsize, 1.0f / yscale * hsize);
- /* draw! */
- glCallList(displist);
+ /* draw X shape */
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, -0.7f, -0.7f);
+ immVertex2f(pos, +0.7f, +0.7f);
+
+ immVertex2f(pos, -0.7f, +0.7f);
+ immVertex2f(pos, +0.7f, -0.7f);
+ immEnd();
/* restore view transform */
- glScalef(xscale / hsize, yscale / hsize, 1.0);
- glTranslatef(-x, -y, 0.0f);
+ GPU_matrix_pop();
}
/* helper func - draw keyframe vertices only for an F-Curve */
@@ -441,10 +449,6 @@ static void draw_fcurve_samples(SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
hsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
UI_view2d_scale_get(&ar->v2d, &xscale, &yscale);
- /* set vertex color */
- if (fcu->flag & (FCURVE_ACTIVE | FCURVE_SELECTED)) UI_ThemeColor(TH_TEXT_HI);
- else UI_ThemeColor(TH_TEXT);
-
/* get verts */
first = fcu->fpt;
last = (first) ? (first + (fcu->totvert - 1)) : (NULL);
@@ -452,21 +456,28 @@ static void draw_fcurve_samples(SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
/* draw */
if (first && last) {
/* anti-aliased lines for more consistent appearance */
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) GPU_line_smooth(true);
+ GPU_blend(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor((fcu->flag & FCURVE_SELECTED) ? TH_TEXT_HI : TH_TEXT);
+
+ draw_fcurve_sample_control(first->vec[0], first->vec[1], xscale, yscale, hsize, pos);
+ draw_fcurve_sample_control(last->vec[0], last->vec[1], xscale, yscale, hsize, pos);
- draw_fcurve_sample_control(first->vec[0], first->vec[1], xscale, yscale, hsize);
- draw_fcurve_sample_control(last->vec[0], last->vec[1], xscale, yscale, hsize);
+ immUnbindProgram();
- glDisable(GL_BLEND);
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
+ GPU_blend(false);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) GPU_line_smooth(false);
}
}
/* Curve ---------------- */
/* helper func - just draw the F-Curve by sampling the visible region (for drawing curves with modifiers) */
-static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, View2DGrid *grid)
+static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, View2DGrid *grid, unsigned int pos)
{
SpaceIpo *sipo = (SpaceIpo *)ac->sl;
ChannelDriver *driver;
@@ -536,37 +547,50 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
* - apply the unit correction factor to the calculated values so that
* the displayed values appear correctly in the viewport
*/
- glBegin(GL_LINE_STRIP);
n = (etime - stime) / samplefreq + 0.5f;
- for (i = 0; i <= n; i++) {
- float ctime = stime + i * samplefreq;
- glVertex2f(ctime, (evaluate_fcurve(fcu, ctime) + offset) * unitFac);
- }
- glEnd();
+ if (n > 0) {
+ immBegin(GPU_PRIM_LINE_STRIP, (n + 1));
+
+ for (i = 0; i <= n; i++) {
+ float ctime = stime + i * samplefreq;
+ immVertex2f(pos, ctime, (evaluate_fcurve(fcu, ctime) + offset) * unitFac);
+ }
+
+ immEnd();
+ }
/* restore driver */
fcu->driver = driver;
}
/* helper func - draw a samples-based F-Curve */
-static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d)
+static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, const uint shdr_pos)
{
FPoint *prevfpt = fcu->fpt;
FPoint *fpt = prevfpt + 1;
float fac, v[2];
- int b = fcu->totvert - 1;
+ int b = fcu->totvert;
float unit_scale, offset;
short mapping_flag = ANIM_get_normalization_flags(ac);
+ int count = fcu->totvert;
+
+ if (prevfpt->vec[0] > v2d->cur.xmin) {
+ count++;
+ }
+
+ if ((prevfpt + b - 1)->vec[0] < v2d->cur.xmax) {
+ count++;
+ }
/* apply unit mapping */
- glPushMatrix();
+ GPU_matrix_push();
unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
- glScalef(1.0f, unit_scale, 1.0f);
- glTranslatef(0.0f, offset, 0.0f);
+ GPU_matrix_scale_2f(1.0f, unit_scale);
+ GPU_matrix_translate_2f(0.0f, offset);
- glBegin(GL_LINE_STRIP);
+ immBegin(GPU_PRIM_LINE_STRIP, count);
/* extrapolate to left? - left-side of view comes before first keyframe? */
if (prevfpt->vec[0] > v2d->cur.xmin) {
@@ -584,26 +608,19 @@ static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, Vie
v[1] = prevfpt->vec[1] - fac * (prevfpt->vec[1] - fpt->vec[1]);
}
- glVertex2fv(v);
+ immVertex2fv(shdr_pos, v);
}
- /* if only one sample, add it now */
- if (fcu->totvert == 1)
- glVertex2fv(prevfpt->vec);
-
/* loop over samples, drawing segments */
/* draw curve between first and last keyframe (if there are enough to do so) */
while (b--) {
/* Linear interpolation: just add one point (which should add a new line segment) */
- glVertex2fv(prevfpt->vec);
+ immVertex2fv(shdr_pos, prevfpt->vec);
/* get next pointers */
- prevfpt = fpt;
- fpt++;
-
- /* last point? */
- if (b == 0)
- glVertex2fv(prevfpt->vec);
+ if (b > 0) {
+ prevfpt++;
+ }
}
/* extrapolate to right? (see code for left-extrapolation above too) */
@@ -623,11 +640,12 @@ static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, Vie
v[1] = prevfpt->vec[1] - fac * (prevfpt->vec[1] - fpt->vec[1]);
}
- glVertex2fv(v);
+ immVertex2fv(shdr_pos, v);
}
- glEnd();
- glPopMatrix();
+ immEnd();
+
+ GPU_matrix_pop();
}
/* helper func - check if the F-Curve only contains easily drawable segments
@@ -648,7 +666,7 @@ static bool fcurve_can_use_simple_bezt_drawing(FCurve *fcu)
}
/* helper func - draw one repeat of an F-Curve (using Bezier curve approximations) */
-static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d)
+static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, unsigned int pos)
{
BezTriple *prevbezt = fcu->bezt;
BezTriple *bezt = prevbezt + 1;
@@ -661,12 +679,15 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
short mapping_flag = ANIM_get_normalization_flags(ac);
/* apply unit mapping */
- glPushMatrix();
+ GPU_matrix_push();
unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
- glScalef(1.0f, unit_scale, 1.0f);
- glTranslatef(0.0f, offset, 0.0f);
+ GPU_matrix_scale_2f(1.0f, unit_scale);
+ GPU_matrix_translate_2f(0.0f, offset);
- glBegin(GL_LINE_STRIP);
+ /* For now, this assumes the worst case scenario, where all the keyframes have
+ * bezier interpolation, and are drawn at full res.
+ * This is tricky to optimize, but maybe can be improved at some point... */
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, (b * 32 + 3));
/* extrapolate to left? */
if (prevbezt->vec[1][0] > v2d->cur.xmin) {
@@ -691,14 +712,14 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[0][1] - prevbezt->vec[1][1]);
}
- glVertex2fv(v1);
+ immVertex2fv(pos, v1);
}
/* if only one keyframe, add it now */
if (fcu->totvert == 1) {
v1[0] = prevbezt->vec[1][0];
v1[1] = prevbezt->vec[1][1];
- glVertex2fv(v1);
+ immVertex2fv(pos, v1);
}
/* draw curve between first and last keyframe (if there are enough to do so) */
@@ -708,17 +729,17 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
/* Constant-Interpolation: draw segment between previous keyframe and next, but holding same value */
v1[0] = prevbezt->vec[1][0];
v1[1] = prevbezt->vec[1][1];
- glVertex2fv(v1);
+ immVertex2fv(pos, v1);
v1[0] = bezt->vec[1][0];
v1[1] = prevbezt->vec[1][1];
- glVertex2fv(v1);
+ immVertex2fv(pos, v1);
}
else if (prevbezt->ipo == BEZT_IPO_LIN) {
/* Linear interpolation: just add one point (which should add a new line segment) */
v1[0] = prevbezt->vec[1][0];
v1[1] = prevbezt->vec[1][1];
- glVertex2fv(v1);
+ immVertex2fv(pos, v1);
}
else if (prevbezt->ipo == BEZT_IPO_BEZ) {
/* Bezier-Interpolation: draw curve as series of segments between keyframes
@@ -738,7 +759,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
/* only draw one */
v1[0] = prevbezt->vec[1][0];
v1[1] = prevbezt->vec[1][1];
- glVertex2fv(v1);
+ immVertex2fv(pos, v1);
}
else {
/* clamp resolution to max of 32 */
@@ -760,8 +781,9 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3);
BKE_curve_forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3);
- for (fp = data; resol; resol--, fp += 3)
- glVertex2fv(fp);
+ for (fp = data; resol; resol--, fp += 3) {
+ immVertex2fv(pos, fp);
+ }
}
}
@@ -773,7 +795,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
if (b == 0) {
v1[0] = prevbezt->vec[1][0];
v1[1] = prevbezt->vec[1][1];
- glVertex2fv(v1);
+ immVertex2fv(pos, v1);
}
}
@@ -800,11 +822,12 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[2][1] - prevbezt->vec[1][1]);
}
- glVertex2fv(v1);
+ immVertex2fv(pos, v1);
}
- glEnd();
- glPopMatrix();
+ immEnd();
+
+ GPU_matrix_pop();
}
/* Debugging -------------------------------- */
@@ -826,6 +849,15 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
//if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
// return;
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* Simple dashes. */
+
/* No curve to modify/visualize the result?
* => We still want to show the 1-1 default...
*/
@@ -833,26 +865,24 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
float t;
/* draw with thin dotted lines in style of what curve would have been */
- glColor3fv(fcu->color);
+ immUniformColor3fv(fcu->color);
- setlinestyle(20);
- glLineWidth(2.0f);
+ immUniform1f("dash_width", 40.0f);
+ immUniform1f("dash_factor", 0.5f);
+ GPU_line_width(2.0f);
/* draw 1-1 line, stretching just past the screen limits
* NOTE: we need to scale the y-values to be valid for the units
*/
- glBegin(GL_LINES);
- {
- t = v2d->cur.xmin;
- glVertex2f(t, (t + offset) * unitfac);
+ immBegin(GPU_PRIM_LINES, 2);
- t = v2d->cur.xmax;
- glVertex2f(t, (t + offset) * unitfac);
- }
- glEnd();
+ t = v2d->cur.xmin;
+ immVertex2f(shdr_pos, t, (t + offset) * unitfac);
- /* cleanup line drawing */
- setlinestyle(0);
+ t = v2d->cur.xmax;
+ immVertex2f(shdr_pos, t, (t + offset) * unitfac);
+
+ immEnd();
}
/* draw driver only if actually functional */
@@ -866,53 +896,59 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
float co[2];
/* draw dotted lines leading towards this point from both axes ....... */
- glColor3f(0.9f, 0.9f, 0.9f);
- setlinestyle(5);
+ immUniformColor3f(0.9f, 0.9f, 0.9f);
+ immUniform1f("dash_width", 10.0f);
+ immUniform1f("dash_factor", 0.5f);
- glBegin(GL_LINES);
- {
- /* x-axis lookup */
- co[0] = x;
+ immBegin(GPU_PRIM_LINES, (y >= v2d->cur.ymin) ? 4 : 2);
- if (y >= v2d->cur.ymin) {
- co[1] = v2d->cur.ymin - 1.0f;
- glVertex2fv(co);
+ /* x-axis lookup */
+ co[0] = x;
- co[1] = y;
- glVertex2fv(co);
- }
+ if (y >= v2d->cur.ymin) {
+ co[1] = v2d->cur.ymin - 1.0f;
+ immVertex2fv(shdr_pos, co);
- /* y-axis lookup */
co[1] = y;
+ immVertex2fv(shdr_pos, co);
+ }
- co[0] = v2d->cur.xmin - 1.0f;
- glVertex2fv(co);
+ /* y-axis lookup */
+ co[1] = y;
- co[0] = x;
- glVertex2fv(co);
- }
- glEnd();
+ co[0] = v2d->cur.xmin - 1.0f;
+ immVertex2fv(shdr_pos, co);
+
+ co[0] = x;
+ immVertex2fv(shdr_pos, co);
- setlinestyle(0);
+ immEnd();
+
+ immUnbindProgram();
+
+ /* GPU_PRIM_POINTS do not survive dashed line geometry shader... */
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* x marks the spot .................................................... */
/* -> outer frame */
- glColor3f(0.9f, 0.9f, 0.9f);
- glPointSize(7.0);
+ immUniformColor3f(0.9f, 0.9f, 0.9f);
+ GPU_point_size(7.0);
- glBegin(GL_POINTS);
- glVertex2f(x, y);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2f(shdr_pos, x, y);
+ immEnd();
/* inner frame */
- glColor3f(0.9f, 0.0f, 0.0f);
- glPointSize(3.0);
+ immUniformColor3f(0.9f, 0.0f, 0.0f);
+ GPU_point_size(3.0);
- glBegin(GL_POINTS);
- glVertex2f(x, y);
- glEnd();
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2f(shdr_pos, x, y);
+ immEnd();
}
}
+
+ immUnbindProgram();
}
/* Public Curve-Drawing API ---------------- */
@@ -925,12 +961,25 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar)
FCurve *fcu;
/* draw with thick dotted lines */
- setlinestyle(10);
- glLineWidth(3.0f);
+ GPU_line_width(3.0f);
/* anti-aliased lines for less jagged appearance */
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ GPU_line_smooth(true);
+ }
+ GPU_blend(true);
+
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* Simple dashes. */
+ immUniform1f("dash_width", 20.0f);
+ immUniform1f("dash_factor", 0.5f);
/* the ghost curves are simply sampled F-Curves stored in sipo->ghostCurves */
for (fcu = sipo->ghostCurves.first; fcu; fcu = fcu->next) {
@@ -938,17 +987,18 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar)
* - this is set by the function which creates these
* - draw with a fixed opacity of 2
*/
- glColor4f(fcu->color[0], fcu->color[1], fcu->color[2], 0.5f);
+ immUniformColor3fvAlpha(fcu->color, 0.5f);
/* simply draw the stored samples */
- draw_fcurve_curve_samples(ac, NULL, fcu, &ar->v2d);
+ draw_fcurve_curve_samples(ac, NULL, fcu, &ar->v2d, shdr_pos);
}
- /* restore settings */
- setlinestyle(0);
+ immUnbindProgram();
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ GPU_line_smooth(false);
+ }
+ GPU_blend(false);
}
/* This is called twice from space_graph.c -> graph_main_region_draw()
@@ -975,8 +1025,9 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
/* map keyframes for drawing if scaled F-Curve */
- if (adt)
+ if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
+ }
/* draw curve:
* - curve line may be result of one or more destructive modifiers or just the raw data,
@@ -986,68 +1037,90 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
*/
/* 1) draw curve line */
+ if (((fcu->modifiers.first) || (fcu->flag & FCURVE_INT_VALUES)) ||
+ (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)))
{
/* set color/drawing style for curve itself */
+ /* draw active F-Curve thicker than the rest to make it stand out */
+ if (fcu->flag & FCURVE_ACTIVE) {
+ GPU_line_width(2.5);
+ }
+ else {
+ GPU_line_width(1.0);
+ }
+
+ /* anti-aliased lines for less jagged appearance */
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ GPU_line_smooth(true);
+ }
+ GPU_blend(true);
+
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* Simple dashes. */
+
if (BKE_fcurve_is_protected(fcu)) {
/* protected curves (non editable) are drawn with dotted lines */
- setlinestyle(2);
+ immUniform1f("dash_width", 4.0f);
+ immUniform1f("dash_factor", 0.5f);
}
+ else {
+ immUniform1f("dash_factor", 2.0f); /* solid line */
+ }
+
if (((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) || (fcu->flag & FCURVE_MUTED)) {
/* muted curves are drawn in a grayish hue */
/* XXX should we have some variations? */
- UI_ThemeColorShade(TH_HEADER, 50);
+ immUniformThemeColorShade(TH_HEADER, 50);
}
else {
/* set whatever color the curve has set
* - unselected curves draw less opaque to help distinguish the selected ones
*/
- glColor4f(fcu->color[0], fcu->color[1], fcu->color[2], fcurve_display_alpha(fcu));
+ immUniformColor3fvAlpha(fcu->color, fcurve_display_alpha(fcu));
}
- /* draw active F-Curve thicker than the rest to make it stand out */
- if (fcu->flag & FCURVE_ACTIVE) {
- glLineWidth(2.0);
- }
- else {
- glLineWidth(1.0);
- }
-
- /* anti-aliased lines for less jagged appearance */
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
-
/* draw F-Curve */
if ((fcu->modifiers.first) || (fcu->flag & FCURVE_INT_VALUES)) {
/* draw a curve affected by modifiers or only allowed to have integer values
* by sampling it at various small-intervals over the visible region
*/
- draw_fcurve_curve(ac, ale->id, fcu, &ar->v2d, grid);
+ draw_fcurve_curve(ac, ale->id, fcu, &ar->v2d, grid, shdr_pos);
}
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
/* just draw curve based on defined data (i.e. no modifiers) */
if (fcu->bezt) {
- if (fcurve_can_use_simple_bezt_drawing(fcu))
- draw_fcurve_curve_bezts(ac, ale->id, fcu, &ar->v2d);
- else
- draw_fcurve_curve(ac, ale->id, fcu, &ar->v2d, grid);
+ if (fcurve_can_use_simple_bezt_drawing(fcu)) {
+ draw_fcurve_curve_bezts(ac, ale->id, fcu, &ar->v2d, shdr_pos);
+ }
+ else {
+ draw_fcurve_curve(ac, ale->id, fcu, &ar->v2d, grid, shdr_pos);
+ }
}
else if (fcu->fpt) {
- draw_fcurve_curve_samples(ac, ale->id, fcu, &ar->v2d);
+ draw_fcurve_curve_samples(ac, ale->id, fcu, &ar->v2d, shdr_pos);
}
}
- /* restore settings */
- setlinestyle(0);
+ immUnbindProgram();
- if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ GPU_line_smooth(false);
+ }
+ GPU_blend(false);
}
/* 2) draw handles and vertices as appropriate based on active
* - if the option to only show controls if the F-Curve is selected is enabled, we must obey this
*/
if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) {
- if (fcurve_are_keyframes_usable(fcu) == 0) {
+ if (!fcurve_are_keyframes_usable(fcu) && !(fcu->fpt && fcu->totvert)) {
/* only draw controls if this is the active modifier */
if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) {
switch (fcm->type) {
@@ -1063,31 +1136,31 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
/* apply unit-scaling to all values via OpenGL */
- glPushMatrix();
- glScalef(1.0f, unit_scale, 1.0f);
- glTranslatef(0.0f, offset, 0.0f);
+ GPU_matrix_push();
+ GPU_matrix_scale_2f(1.0f, unit_scale);
+ GPU_matrix_translate_2f(0.0f, offset);
/* set this once and for all - all handles and handle-verts should use the same thickness */
- glLineWidth(1.0);
+ GPU_line_width(1.0);
if (fcu->bezt) {
bool do_handles = draw_fcurve_handles_check(sipo, fcu);
if (do_handles) {
/* only draw handles/vertices on keyframes */
- glEnable(GL_BLEND);
+ GPU_blend(true);
draw_fcurve_handles(sipo, fcu);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
- draw_fcurve_vertices(sipo, ar, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY), unit_scale);
+ draw_fcurve_vertices(ar, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY));
}
else {
/* samples: only draw two indicators at either end as indicators */
draw_fcurve_samples(sipo, ar, fcu);
}
- glPopMatrix();
+ GPU_matrix_pop();
}
}
@@ -1163,8 +1236,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
y = (float)ACHANNEL_FIRST(ac);
/* set blending again, as may not be set in previous step */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) {
const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac));
@@ -1186,7 +1259,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
UI_block_end(C, block);
UI_block_draw(C, block);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
/* free tempolary channels */
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 3086e189a7a..08a5a6aeedd 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -36,7 +36,7 @@
#include <float.h>
#ifdef WITH_AUDASPACE
-# include AUD_SPECIAL_H
+# include <AUD_Special.h>
#endif
#include "MEM_guardedalloc.h"
@@ -55,13 +55,14 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_report.h"
+#include "DEG_depsgraph_build.h"
+
#include "UI_view2d.h"
#include "ED_anim_api.h"
@@ -526,6 +527,7 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
ReportList *reports = ac->reports;
SpaceIpo *sipo = (SpaceIpo *)ac->sl;
+ struct Depsgraph *depsgraph = ac->depsgraph;
Scene *scene = ac->scene;
ToolSettings *ts = scene->toolsettings;
short flag = 0;
@@ -587,17 +589,8 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
}
else {
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- float cfra;
-
- /* adjust current frame for NLA-mapping */
- if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS))
- cfra = sipo->cursorTime;
- else if (adt)
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- else
- cfra = (float)CFRA;
+ float cfra = (float)CFRA;
/* read value from property the F-Curve represents, or from the curve only?
* - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
@@ -608,10 +601,18 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
* up adding the keyframes on a new F-Curve in the action data instead.
*/
if (ale->id && !ale->owner && !fcu->driver) {
- insert_keyframe(ac->bmain, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
}
else {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* adjust current frame for NLA-mapping */
+ if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS))
+ cfra = sipo->cursorTime;
+ else if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+
const float curval = evaluate_fcurve(fcu, cfra);
insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
}
@@ -2716,7 +2717,7 @@ static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op)
/* successful or not? */
if (ok) {
/* rebuild depsgraph, now that there are extra deps here */
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, CTX_data_scene(C));
@@ -2790,7 +2791,7 @@ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
if (deleted > 0) {
/* notify the world of any changes */
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
WM_reportf(RPT_INFO, "Deleted %u drivers", deleted);
}
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index c50e0497519..286d3cea59c 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -58,8 +58,8 @@ void graph_draw_ghost_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, str
void deselect_graph_keys(struct bAnimContext *ac, bool test, short sel, bool do_channels);
-void GRAPH_OT_select_all_toggle(struct wmOperatorType *ot);
-void GRAPH_OT_select_border(struct wmOperatorType *ot);
+void GRAPH_OT_select_all(struct wmOperatorType *ot);
+void GRAPH_OT_select_box(struct wmOperatorType *ot);
void GRAPH_OT_select_lasso(struct wmOperatorType *ot);
void GRAPH_OT_select_circle(struct wmOperatorType *ot);
void GRAPH_OT_select_column(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index aa1d0511e3d..4ed6a980fcb 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -48,7 +48,9 @@
#include "ED_anim_api.h"
#include "ED_markers.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
+#include "ED_object.h"
#include "graph_intern.h"
@@ -194,9 +196,7 @@ static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *ev
case LEFTMOUSE:
case RIGHTMOUSE:
case MIDDLEMOUSE:
- /* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init
- * the modal op) doesn't work for some reason
- */
+ /* We check for either mouse-button to end, to work with all user keymaps. */
if (event->val == KM_RELEASE) {
if (screen)
screen->scrubbing = false;
@@ -427,8 +427,8 @@ void graphedit_operatortypes(void)
/* keyframes */
/* selection */
WM_operatortype_append(GRAPH_OT_clickselect);
- WM_operatortype_append(GRAPH_OT_select_all_toggle);
- WM_operatortype_append(GRAPH_OT_select_border);
+ WM_operatortype_append(GRAPH_OT_select_all);
+ WM_operatortype_append(GRAPH_OT_select_box);
WM_operatortype_append(GRAPH_OT_select_lasso);
WM_operatortype_append(GRAPH_OT_select_circle);
WM_operatortype_append(GRAPH_OT_select_column);
@@ -488,222 +488,10 @@ void ED_operatormacros_graph(void)
/* ************************** registration - keymaps **********************************/
-static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- /* view */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.show_handles");
-
- /* NOTE: 'ACTIONMOUSE' not 'LEFTMOUSE', as user may have swapped mouse-buttons
- * This keymap is supposed to override ANIM_OT_change_frame, which does the same except it doesn't do y-values
- */
- WM_keymap_add_item(keymap, "GRAPH_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
-
-
- /* graph_select.c - selection tools */
- /* click-select: keyframe (replace) */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "curves", false);
- RNA_boolean_set(kmi->ptr, "column", false);
- /* click-select: all keyframes on same frame (replace) */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "curves", false);
- RNA_boolean_set(kmi->ptr, "column", true);
- /* click-select: keyframe (add) */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "curves", false);
- RNA_boolean_set(kmi->ptr, "column", false);
- /* click-select: all keyframes on same frame (add) */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "curves", false);
- RNA_boolean_set(kmi->ptr, "column", true);
- /* click-select: all keyframes in same curve (replace) */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "curves", true);
- RNA_boolean_set(kmi->ptr, "column", false);
- /* click-select: all keyframes in same curve (add) */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_ALT | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "curves", true);
- RNA_boolean_set(kmi->ptr, "column", false);
-
- /* click-select left/right */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_leftright", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", GRAPHKEYS_LRSEL_TEST);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_leftright", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_enum_set(kmi->ptr, "mode", GRAPHKEYS_LRSEL_TEST);
-
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_leftright", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", GRAPHKEYS_LRSEL_LEFT);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_leftright", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", GRAPHKEYS_LRSEL_RIGHT);
-
- /* deselect all */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "invert", false);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "invert", true);
-
- /* borderselect */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "axis_range", false);
- RNA_boolean_set(kmi->ptr, "include_handles", false);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "axis_range", true);
- RNA_boolean_set(kmi->ptr, "include_handles", false);
-
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "axis_range", false);
- RNA_boolean_set(kmi->ptr, "include_handles", true);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "axis_range", true);
- RNA_boolean_set(kmi->ptr, "include_handles", true);
-
- /* region select */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0);
-
- /* column select */
- RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_KEYS);
- RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_CFRA);
- RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN);
- RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_MARKERS_BETWEEN);
-
- /* select more/less */
- WM_keymap_add_item(keymap, "GRAPH_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- /* select linked */
- WM_keymap_add_item(keymap, "GRAPH_OT_select_linked", LKEY, KM_PRESS, 0, 0);
-
-
- /* graph_edit.c */
- /* jump to selected keyframes */
- WM_keymap_add_item(keymap, "GRAPH_OT_frame_jump", GKEY, KM_PRESS, KM_CTRL, 0);
-
- /* menu + single-step transform */
- WM_keymap_add_item(keymap, "GRAPH_OT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_mirror", MKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "GRAPH_OT_handle_type", VKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "GRAPH_OT_interpolation_type", TKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_easing_type", EKEY, KM_PRESS, KM_CTRL, 0);
-
- /* destructive */
- WM_keymap_add_item(keymap, "GRAPH_OT_smooth", OKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "GRAPH_OT_bake", CKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_menu(keymap, "GRAPH_MT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_menu(keymap, "GRAPH_MT_delete", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "GRAPH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* insertkey */
- WM_keymap_add_item(keymap, "GRAPH_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", ACTIONMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- /* copy/paste */
- WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "flipped", true);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_OSKEY | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "flipped", true);
-#endif
-
- /* auto-set range */
- WM_keymap_add_item(keymap, "GRAPH_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "GRAPH_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
- WM_keymap_add_item(keymap, "GRAPH_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_view_frame", PAD0, KM_PRESS, 0, 0);
-
- /* F-Modifiers */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "only_active", false);
-
- /* animation module */
- /* channels list
- * NOTE: these operators were originally for the channels list, but are added here too for convenience...
- */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
-
- /* transform system */
- transform_keymap_for_space(keyconf, keymap, SPACE_IPO);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_proportional_fcurve");
-
- /* pivot point settings */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "BOUNDING_BOX_CENTER");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "CURSOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "INDIVIDUAL_ORIGINS");
-
- /* special markers hotkeys for anim editors: see note in definition of this function */
- ED_marker_keymap_animedit_conflictfree(keymap);
-}
-
-/* --------------- */
-
void graphedit_keymap(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
/* keymap for all regions */
- keymap = WM_keymap_ensure(keyconf, "Graph Editor Generic", SPACE_IPO, 0);
- WM_keymap_add_item(keymap, "GRAPH_OT_properties", NKEY, KM_PRESS, 0, 0);
-
- /* extrapolation works on channels, not keys */
- WM_keymap_add_item(keymap, "GRAPH_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* find (i.e. a shortcut for setting the name filter) */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
-
- /* hide/reveal selected curves */
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
-
- kmi = WM_keymap_add_item(keymap, "GRAPH_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- WM_keymap_add_item(keymap, "GRAPH_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
-
+ WM_keymap_ensure(keyconf, "Graph Editor Generic", SPACE_IPO, 0);
/* channels */
/* Channels are not directly handled by the Graph Editor module, but are inherited from the Animation module.
@@ -712,6 +500,5 @@ void graphedit_keymap(wmKeyConfig *keyconf)
*/
/* keyframes */
- keymap = WM_keymap_ensure(keyconf, "Graph Editor", SPACE_IPO, 0);
- graphedit_keymap_keyframes(keyconf, keymap);
+ WM_keymap_ensure(keyconf, "Graph Editor", SPACE_IPO, 0);
}
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index da44c33104c..cbea292c4ec 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -56,6 +56,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
#include "ED_markers.h"
+#include "ED_select_utils.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -162,10 +163,24 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op)
ale_active = get_active_fcurve_channel(&ac);
/* 'standard' behavior - check if selected, then apply relevant selection */
- if (RNA_boolean_get(op->ptr, "invert"))
- deselect_graph_keys(&ac, 0, SELECT_INVERT, true);
- else
- deselect_graph_keys(&ac, 1, SELECT_ADD, true);
+ const int action = RNA_enum_get(op->ptr, "action");
+ switch (action) {
+ case SEL_TOGGLE:
+ deselect_graph_keys(&ac, 1, SELECT_ADD, true);
+ break;
+ case SEL_SELECT:
+ deselect_graph_keys(&ac, 0, SELECT_ADD, true);
+ break;
+ case SEL_DESELECT:
+ deselect_graph_keys(&ac, 0, SELECT_SUBTRACT, true);
+ break;
+ case SEL_INVERT:
+ deselect_graph_keys(&ac, 0, SELECT_INVERT, true);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
/* restore active F-Curve... */
if (ale_active) {
@@ -186,11 +201,11 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
+void GRAPH_OT_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select All";
- ot->idname = "GRAPH_OT_select_all_toggle";
+ ot->idname = "GRAPH_OT_select_all";
ot->description = "Toggle selection of all keyframes";
/* api callbacks */
@@ -200,11 +215,11 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- ot->prop = RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
+ /* properties */
+ WM_operator_properties_select_all(ot);
}
-/* ******************** Border Select Operator **************************** */
+/* ******************** Box Select Operator **************************** */
/* This operator currently works in one of three ways:
* -> BKEY - 1) all keyframes within region are selected (validation with BEZT_OK_REGION)
* -> ALT-BKEY - depending on which axis of the region was larger...
@@ -214,12 +229,12 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot)
* The selection backend is also reused for the Lasso and Circle select operators.
*/
-/* Borderselect only selects keyframes now, as overshooting handles often get caught too,
+/* Box Select only selects keyframes now, as overshooting handles often get caught too,
* which means that they may be inadvertently moved as well. However, incl_handles overrides
* this, and allow handles to be considered independently too.
* Also, for convenience, handles should get same status as keyframe (if it was within bounds).
*/
-static void borderselect_graphkeys(
+static void box_select_graphkeys(
bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, bool incl_handles,
void *data)
{
@@ -270,7 +285,7 @@ static void borderselect_graphkeys(
mapping_flag |= ANIM_get_normalization_flags(ac);
- /* loop over data, doing border select */
+ /* loop over data, doing box select */
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
@@ -325,7 +340,7 @@ static void borderselect_graphkeys(
/* ------------------- */
-static int graphkeys_borderselect_exec(bContext *C, wmOperator *op)
+static int graphkeys_box_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
rcti rect;
@@ -359,7 +374,7 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op)
/* get settings from operator */
WM_operator_properties_border_to_rcti(op, &rect);
- /* selection 'mode' depends on whether borderselect region only matters on one axis */
+ /* selection 'mode' depends on whether box_select region only matters on one axis */
if (RNA_boolean_get(op->ptr, "axis_range")) {
/* mode depends on which axis of the range is larger to determine which axis to use
* - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
@@ -376,8 +391,8 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op)
BLI_rctf_rcti_copy(&rect_fl, &rect);
- /* apply borderselect action */
- borderselect_graphkeys(&ac, &rect_fl, mode, selectmode, incl_handles, NULL);
+ /* apply box_select action */
+ box_select_graphkeys(&ac, &rect_fl, mode, selectmode, incl_handles, NULL);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -385,18 +400,18 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GRAPH_OT_select_border(wmOperatorType *ot)
+void GRAPH_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "GRAPH_OT_select_border";
+ ot->name = "Box Select";
+ ot->idname = "GRAPH_OT_select_box";
ot->description = "Select all keyframes within the specified region";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = graphkeys_borderselect_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = graphkeys_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = graphop_visible_keyframes_poll;
@@ -404,7 +419,7 @@ void GRAPH_OT_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria");
@@ -459,8 +474,8 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
BLI_rctf_rcti_copy(&rect_fl, &rect);
- /* apply borderselect action */
- borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
+ /* apply box_select action */
+ box_select_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
MEM_freeN((void *)data_lasso.mcords);
@@ -532,8 +547,8 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op)
}
}
- /* apply borderselect action */
- borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
+ /* apply box_select action */
+ box_select_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -1530,7 +1545,7 @@ void GRAPH_OT_clickselect(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Mouse Select Keys";
+ ot->name = "Select Keyframes";
ot->idname = "GRAPH_OT_clickselect";
ot->description = "Select keyframes by clicking on them";
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index d184681f146..912b5ceed58 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -44,17 +44,62 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_screen.h"
#include "WM_api.h"
#include "ED_anim_api.h"
+#include "ED_screen.h"
+#include "UI_interface.h"
#include "graph_intern.h" // own include
/* ************************************************************** */
+/* Set Up Drivers Editor */
+
+/* Set up UI configuration for Drivers Editor */
+/* NOTE: Currently called from windowmanager (new drivers editor window) and RNA (mode switching) */
+void ED_drivers_editor_init(bContext *C, ScrArea *sa)
+{
+ SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first;
+
+ /* Set mode */
+ sipo->mode = SIPO_MODE_DRIVERS;
+
+ /* Show Properties Region (or else the settings can't be edited) */
+ ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ if (ar_props) {
+ UI_panel_category_active_set(ar_props, "Drivers");
+
+ ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ /* XXX: Adjust width of this too? */
+
+ ED_region_visibility_change_update(C, ar_props);
+ }
+ else {
+ printf("%s: Couldn't find properties region for Drivers Editor - %p\n", __func__, sa);
+ }
+
+ /* Adjust framing in graph region */
+ /* TODO: Have a way of not resetting this every time?
+ * (e.g. So that switching back and forth between editors doesn't keep jumping?)
+ */
+ ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ if (ar_main) {
+ /* XXX: Ideally we recenter based on the range instead... */
+ ar_main->v2d.tot.xmin = -2.0f;
+ ar_main->v2d.tot.ymin = -2.0f;
+ ar_main->v2d.tot.xmax = 2.0f;
+ ar_main->v2d.tot.ymax = 2.0f;
+
+ ar_main->v2d.cur = ar_main->v2d.tot;
+ }
+}
+
+/* ************************************************************** */
/* Active F-Curve */
/* Find 'active' F-Curve. It must be editable, since that's the purpose of these buttons (subject to change).
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index cfa42cab3e7..1fa6cb9b3de 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -33,7 +33,7 @@
#include <stdio.h>
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -53,10 +53,17 @@
#include "ED_anim_api.h"
#include "ED_markers.h"
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+#include "GPU_framebuffer.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -92,9 +99,8 @@ ARegion *graph_has_buttons_region(ScrArea *sa)
/* ******************** default callbacks for ipo space ***************** */
-static SpaceLink *graph_new(const bContext *C)
+static SpaceLink *graph_new(const ScrArea *UNUSED(sa), const Scene *scene)
{
- Scene *scene = CTX_data_scene(C);
ARegion *ar;
SpaceIpo *sipo;
@@ -117,7 +123,7 @@ static SpaceLink *graph_new(const bContext *C)
BLI_addtail(&sipo->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* channels */
ar = MEM_callocN(sizeof(ARegion), "channels region for graphedit");
@@ -179,14 +185,14 @@ static void graph_free(SpaceLink *sl)
/* spacetype; init callback */
-static void graph_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void graph_init(struct wmWindowManager *wm, ScrArea *sa)
{
SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first;
/* init dopesheet data if non-existent (i.e. for old files) */
if (sipo->ads == NULL) {
sipo->ads = MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
- sipo->ads->source = (ID *)(G.main->scene.first); // FIXME: this is a really nasty hack here for now...
+ sipo->ads->source = (ID *)WM_window_get_active_scene(wm->winactive);
}
/* force immediate init of any invalid F-Curve colors */
@@ -226,17 +232,18 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceIpo *sipo = CTX_wm_space_graph(C);
+ Scene *scene = CTX_data_scene(C);
bAnimContext ac;
View2D *v2d = &ar->v2d;
View2DGrid *grid;
View2DScrollers *scrollers;
float col[3];
- short unitx = 0, unity = V2D_UNIT_VALUES, flag = 0;
+ short unitx = 0, unity = V2D_UNIT_VALUES, cfra_flag = 0;
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
- glClearColor(col[0], col[1], col[2], 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear_color(col[0], col[1], col[2], 0.0);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -247,6 +254,11 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
+ /* start and end frame (in F-Curve mode only) */
+ if (sipo->mode != SIPO_MODE_DRIVERS) {
+ ANIM_draw_framerange(scene, v2d);
+ }
+
/* draw data */
if (ANIM_animdata_get_context(C, &ac)) {
/* draw ghost curves */
@@ -266,46 +278,53 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
/* only free grid after drawing data, as we need to use it to determine sampling rate */
UI_view2d_grid_free(grid);
- /* horizontal component of value-cursor (value line before the current frame line) */
- if ((sipo->flag & SIPO_NODRAWCURSOR) == 0) {
+ if (((sipo->flag & SIPO_NODRAWCURSOR) == 0) || (sipo->mode == SIPO_MODE_DRIVERS)) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- float y = sipo->cursorVal;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* Draw a green line to indicate the cursor value */
- UI_ThemeColorShadeAlpha(TH_CFRAME, -10, -50);
- glEnable(GL_BLEND);
- glLineWidth(2.0);
+ /* horizontal component of value-cursor (value line before the current frame line) */
+ if ((sipo->flag & SIPO_NODRAWCURSOR) == 0) {
+ float y = sipo->cursorVal;
- glBegin(GL_LINES);
- glVertex2f(v2d->cur.xmin, y);
- glVertex2f(v2d->cur.xmax, y);
- glEnd();
+ /* Draw a green line to indicate the cursor value */
+ immUniformThemeColorShadeAlpha(TH_CFRAME, -10, -50);
+ GPU_blend(true);
+ GPU_line_width(2.0);
- glDisable(GL_BLEND);
- }
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, v2d->cur.xmin, y);
+ immVertex2f(pos, v2d->cur.xmax, y);
+ immEnd();
+
+ GPU_blend(false);
+ }
- /* current frame or vertical component of vertical component of the cursor */
- if (sipo->mode == SIPO_MODE_DRIVERS) {
- /* cursor x-value */
- float x = sipo->cursorTime;
+ /* current frame or vertical component of vertical component of the cursor */
+ if (sipo->mode == SIPO_MODE_DRIVERS) {
+ /* cursor x-value */
+ float x = sipo->cursorTime;
- /* to help differentiate this from the current frame, draw slightly darker like the horizontal one */
- UI_ThemeColorShadeAlpha(TH_CFRAME, -40, -50);
- glEnable(GL_BLEND);
- glLineWidth(2.0);
+ /* to help differentiate this from the current frame, draw slightly darker like the horizontal one */
+ immUniformThemeColorShadeAlpha(TH_CFRAME, -40, -50);
+ GPU_blend(true);
+ GPU_line_width(2.0);
- glBegin(GL_LINES);
- glVertex2f(x, v2d->cur.ymin);
- glVertex2f(x, v2d->cur.ymax);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, v2d->cur.ymin);
+ immVertex2f(pos, x, v2d->cur.ymax);
+ immEnd();
- glDisable(GL_BLEND);
+ GPU_blend(false);
+ }
+
+ immUnbindProgram();
}
- else {
+
+ if (sipo->mode != SIPO_MODE_DRIVERS) {
/* current frame */
- if (sipo->flag & SIPO_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS;
- if ((sipo->flag & SIPO_NODRAWCFRANUM) == 0) flag |= DRAWCFRA_SHOW_NUMBOX;
- ANIM_draw_cfra(C, v2d, flag);
+ if (sipo->flag & SIPO_DRAWTIME) cfra_flag |= DRAWCFRA_UNIT_SECONDS;
+ ANIM_draw_cfra(C, v2d, cfra_flag);
}
/* markers */
@@ -325,9 +344,15 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
/* scrollers */
// FIXME: args for scrollers depend on the type of data being shown...
- scrollers = UI_view2d_scrollers_calc(C, v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
+
+ /* draw current frame number-indicator on top of scrollers */
+ if ((sipo->mode != SIPO_MODE_DRIVERS) && ((sipo->flag & SIPO_NODRAWCFRANUM) == 0)) {
+ UI_view2d_view_orthoSpecial(ar, v2d, 1);
+ ANIM_draw_cfra_number(C, v2d, cfra_flag);
+ }
}
static void graph_channel_region_init(wmWindowManager *wm, ARegion *ar)
@@ -358,8 +383,8 @@ static void graph_channel_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
- glClearColor(col[0], col[1], col[2], 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear_color(col[0], col[1], col[2], 0.0);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -372,7 +397,7 @@ static void graph_channel_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@@ -401,10 +426,12 @@ static void graph_buttons_region_init(wmWindowManager *wm, ARegion *ar)
static void graph_buttons_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
-static void graph_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void graph_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -416,6 +443,7 @@ static void graph_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AReg
case ND_RENDER_OPTIONS:
case ND_OB_ACTIVE:
case ND_FRAME:
+ case ND_FRAME_RANGE:
case ND_MARKERS:
ED_region_tag_redraw(ar);
break;
@@ -450,6 +478,11 @@ static void graph_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AReg
if (wmn->action == NA_RENAME)
ED_region_tag_redraw(ar);
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
default:
if (wmn->data == ND_KEYS)
ED_region_tag_redraw(ar);
@@ -458,8 +491,84 @@ static void graph_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AReg
}
}
+static void graph_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sa->spacedata.first, &ptr);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* Timeline depends on scene properties. */
+ {
+ bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
+ extern PropertyRNA rna_Scene_frame_start;
+ extern PropertyRNA rna_Scene_frame_end;
+ extern PropertyRNA rna_Scene_frame_preview_start;
+ extern PropertyRNA rna_Scene_frame_preview_end;
+ extern PropertyRNA rna_Scene_use_preview_range;
+ extern PropertyRNA rna_Scene_frame_current;
+ const PropertyRNA *props[] = {
+ use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
+ use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
+ &rna_Scene_use_preview_range,
+ &rna_Scene_frame_current,
+ };
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&scene->id, &idptr);
+
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
+ }
+ }
+
+ /* All dopesheet filter settings, etc. affect the drawing of this editor,
+ * also same applies for all animation-related datatypes that may appear here,
+ * so just whitelist the entire structs for updates
+ */
+ {
+ wmMsgParams_RNA msg_key_params = {{{0}}};
+ StructRNA *type_array[] = {
+ &RNA_DopeSheet, /* dopesheet filters */
+
+ &RNA_ActionGroup, /* channel groups */
+ &RNA_FCurve, /* F-Curve */
+ &RNA_Keyframe,
+ &RNA_FCurveSample,
+
+ &RNA_FModifier, /* F-Modifiers (XXX: Why can't we just do all subclasses too?) */
+ &RNA_FModifierCycles,
+ &RNA_FModifierEnvelope,
+ &RNA_FModifierEnvelopeControlPoint,
+ &RNA_FModifierFunctionGenerator,
+ &RNA_FModifierGenerator,
+ &RNA_FModifierLimits,
+ &RNA_FModifierNoise,
+ &RNA_FModifierPython,
+ &RNA_FModifierStepped,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
+ msg_key_params.ptr.type = type_array[i];
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &msg_key_params,
+ &msg_sub_value_region_tag_redraw,
+ __func__);
+ }
+ }
+}
+
/* editor level listener */
-static void graph_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void graph_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first;
@@ -685,7 +794,7 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
if (sgraph->ads) {
if ((ID *)sgraph->ads->filter_grp == old_id) {
- sgraph->ads->filter_grp = (Group *)new_id;
+ sgraph->ads->filter_grp = (Collection *)new_id;
}
if ((ID *)sgraph->ads->source == old_id) {
sgraph->ads->source = new_id;
@@ -693,6 +802,24 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
}
}
+static int graph_space_subtype_get(ScrArea *sa)
+{
+ SpaceIpo *sgraph = sa->spacedata.first;
+ return sgraph->mode;
+}
+
+static void graph_space_subtype_set(ScrArea *sa, int value)
+{
+ SpaceIpo *sgraph = sa->spacedata.first;
+ sgraph->mode = value;
+}
+
+static void graph_space_subtype_item_extend(
+ bContext *UNUSED(C), EnumPropertyItem **item, int *totitem)
+{
+ RNA_enum_items_add(item, totitem, rna_enum_space_graph_mode_items);
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_ipo(void)
{
@@ -711,6 +838,9 @@ void ED_spacetype_ipo(void)
st->listener = graph_listener;
st->refresh = graph_refresh;
st->id_remap = graph_id_remap;
+ st->space_subtype_item_extend = graph_space_subtype_item_extend;
+ st->space_subtype_get = graph_space_subtype_get;
+ st->space_subtype_set = graph_space_subtype_set;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
@@ -718,6 +848,7 @@ void ED_spacetype_ipo(void)
art->init = graph_main_region_init;
art->draw = graph_main_region_draw;
art->listener = graph_region_listener;
+ art->message_subscribe = graph_region_message_subscribe;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
@@ -739,6 +870,7 @@ void ED_spacetype_ipo(void)
art->prefsizex = 200 + V2D_SCROLL_WIDTH; /* 200 is the 'standard', but due to scrollers, we want a bit more to fit the lock icons in */
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
art->listener = graph_region_listener;
+ art->message_subscribe = graph_region_message_subscribe;
art->init = graph_channel_region_init;
art->draw = graph_channel_region_draw;
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index c60d194b620..0bc09981ba5 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../depsgraph
../../imbuf
../../gpu
../../makesdna
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 26bd560b31f..26162266441 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -125,7 +125,7 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
/* the frame number, even if we cant */
if (ima->source == IMA_SRC_SEQUENCE) {
/* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
- const int framenr = BKE_image_user_frame_get(iuser, CFRA, 0, NULL);
+ const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL);
ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(", Frame: %d"), framenr);
}
}
@@ -291,23 +291,24 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *
{
uiBlock *block = uiLayoutGetBlock(layout);
Image *image = image_p;
- int slot;
+ int slot_id;
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Slot"),
0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
uiItemS(layout);
- slot = IMA_MAX_RENDER_SLOT;
- while (slot--) {
+ slot_id = BLI_listbase_count(&image->renderslots) - 1;
+ for (RenderSlot *slot = image->renderslots.last; slot; slot = slot->prev) {
char str[64];
- if (image->render_slots[slot].name[0] != '\0') {
- BLI_strncpy(str, image->render_slots[slot].name, sizeof(str));
+ if (slot->name[0] != '\0') {
+ BLI_strncpy(str, slot->name, sizeof(str));
}
else {
- BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), slot + 1);
+ BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), slot_id + 1);
}
uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, str, 0, 0,
- UI_UNIT_X * 5, UI_UNIT_X, &image->render_slot, (float) slot, 0.0, 0, -1, "");
+ UI_UNIT_X * 5, UI_UNIT_X, &image->render_slot, (float) slot_id, 0.0, 0, -1, "");
+ slot_id--;
}
}
@@ -708,8 +709,9 @@ static void uiblock_layer_pass_buttons(
/* menu buts */
if (render_slot) {
char str[64];
- if (image->render_slots[*render_slot].name[0] != '\0') {
- BLI_strncpy(str, image->render_slots[*render_slot].name, sizeof(str));
+ RenderSlot *slot = BKE_image_get_renderslot(image, *render_slot);
+ if (slot && slot->name[0] != '\0') {
+ BLI_strncpy(str, slot->name, sizeof(str));
}
else {
BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
@@ -861,7 +863,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
ima = imaptr.data;
iuser = userptr->data;
- BKE_image_user_check_frame_calc(iuser, (int)scene->r.cfra, 0);
+ BKE_image_user_check_frame_calc(iuser, (int)scene->r.cfra);
cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
cb->ptr = *ptr;
@@ -874,7 +876,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
if (!compact) {
uiTemplateID(
layout, C, ptr, propname,
- ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
}
if (ima) {
@@ -998,25 +1000,6 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
col = uiLayoutColumn(layout, false);
uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE);
}
-
- split = uiLayoutSplit(layout, 0.0f, false);
-
- col = uiLayoutColumn(split, false);
- /* XXX Why only display fields_per_frame only for video image types?
- * And why allow fields for non-video image types at all??? */
- if (BKE_image_is_animated(ima)) {
- uiLayout *subsplit = uiLayoutSplit(col, 0.0f, false);
- uiLayout *subcol = uiLayoutColumn(subsplit, false);
- uiItemR(subcol, &imaptr, "use_fields", 0, NULL, ICON_NONE);
- subcol = uiLayoutColumn(subsplit, false);
- uiLayoutSetActive(subcol, RNA_boolean_get(&imaptr, "use_fields"));
- uiItemR(subcol, userptr, "fields_per_frame", 0, IFACE_("Fields"), ICON_NONE);
- }
- else
- uiItemR(col, &imaptr, "use_fields", 0, NULL, ICON_NONE);
- row = uiLayoutRow(col, false);
- uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_fields"));
- uiItemR(row, &imaptr, "field_order", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
}
@@ -1068,19 +1051,19 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
PointerRNA display_settings_ptr;
PropertyRNA *prop;
const int depth_ok = BKE_imtype_valid_depths(imf->imtype);
- /* some settings depend on this being a scene thats rendered */
+ /* some settings depend on this being a scene that's rendered */
const bool is_render_out = (id && GS(id->name) == ID_SCE);
- uiLayout *col, *row, *split, *sub;
+ uiLayout *col;
bool show_preview = false;
col = uiLayoutColumn(layout, false);
- split = uiLayoutSplit(col, 0.5f, false);
+ uiLayoutSetPropSep(col, true);
+ uiLayoutSetPropDecorate(col, false);
- uiItemR(split, imfptr, "file_format", 0, "", ICON_NONE);
- sub = uiLayoutRow(split, false);
- uiItemR(sub, imfptr, "color_mode", UI_ITEM_R_EXPAND, IFACE_("Color"), ICON_NONE);
+ uiItemR(col, imfptr, "file_format", 0, NULL, ICON_NONE);
+ uiItemR(uiLayoutRow(col, true), imfptr, "color_mode", UI_ITEM_R_EXPAND, IFACE_("Color"), ICON_NONE);
/* only display depth setting if multiple depths can be used */
if ((ELEM(depth_ok,
@@ -1092,10 +1075,7 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
R_IMF_CHAN_DEPTH_24,
R_IMF_CHAN_DEPTH_32)) == 0)
{
- row = uiLayoutRow(col, false);
-
- uiItemL(row, IFACE_("Color Depth:"), ICON_NONE);
- uiItemR(row, imfptr, "color_depth", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(uiLayoutRow(col, true), imfptr, "color_depth", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
if (BKE_imtype_supports_quality(imf->imtype)) {
@@ -1110,22 +1090,20 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
uiItemR(col, imfptr, "exr_codec", 0, NULL, ICON_NONE);
}
- row = uiLayoutRow(col, false);
if (BKE_imtype_supports_zbuf(imf->imtype)) {
- uiItemR(row, imfptr, "use_zbuffer", 0, NULL, ICON_NONE);
+ uiItemR(col, imfptr, "use_zbuffer", 0, NULL, ICON_NONE);
}
if (is_render_out && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
show_preview = true;
- uiItemR(row, imfptr, "use_preview", 0, NULL, ICON_NONE);
+ uiItemR(col, imfptr, "use_preview", 0, NULL, ICON_NONE);
}
if (imf->imtype == R_IMF_IMTYPE_JP2) {
uiItemR(col, imfptr, "jpeg2k_codec", 0, NULL, ICON_NONE);
- row = uiLayoutRow(col, false);
- uiItemR(row, imfptr, "use_jpeg2k_cinema_preset", 0, NULL, ICON_NONE);
- uiItemR(row, imfptr, "use_jpeg2k_cinema_48", 0, NULL, ICON_NONE);
+ uiItemR(col, imfptr, "use_jpeg2k_cinema_preset", 0, NULL, ICON_NONE);
+ uiItemR(col, imfptr, "use_jpeg2k_cinema_48", 0, NULL, ICON_NONE);
uiItemR(col, imfptr, "use_jpeg2k_ycc", 0, NULL, ICON_NONE);
}
@@ -1201,17 +1179,19 @@ void uiTemplateImageStereo3d(uiLayout *layout, PointerRNA *stereo3d_format_ptr)
static void uiTemplateViewsFormat(uiLayout *layout, PointerRNA *ptr, PointerRNA *stereo3d_format_ptr)
{
- uiLayout *col, *box;
+ uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Views Format:"), ICON_NONE);
- uiItemR(uiLayoutRow(col, false), ptr, "views_format", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiLayoutSetPropSep(col, true);
+ uiLayoutSetPropDecorate(col, false);
+
+ uiItemR(col, ptr, "views_format", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- if (stereo3d_format_ptr) {
- box = uiLayoutBox(col);
- uiLayoutSetActive(box, RNA_enum_get(ptr, "views_format") == R_IMF_VIEWS_STEREO_3D);
- uiTemplateImageStereo3d(box, stereo3d_format_ptr);
+ if (stereo3d_format_ptr &&
+ RNA_enum_get(ptr, "views_format") == R_IMF_VIEWS_STEREO_3D)
+ {
+ uiTemplateImageStereo3d(col, stereo3d_format_ptr);
}
}
@@ -1313,7 +1293,7 @@ static int image_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void IMAGE_OT_properties(wmOperatorType *ot)
{
- ot->name = "Properties";
+ ot->name = "Toggle Sidebar";
ot->idname = "IMAGE_OT_properties";
ot->description = "Toggle the properties region visibility";
@@ -1337,7 +1317,7 @@ static int image_scopes_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void IMAGE_OT_toolshelf(wmOperatorType *ot)
{
- ot->name = "Tool Shelf";
+ ot->name = "Toggle Toolbar";
ot->idname = "IMAGE_OT_toolshelf";
ot->description = "Toggles tool shelf display";
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index c358b38520a..4cbe25462af 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -60,9 +60,13 @@
#include "BKE_image.h"
#include "BKE_paint.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "BLF_api.h"
#include "ED_gpencil.h"
@@ -87,7 +91,6 @@ static void draw_render_info(const bContext *C,
float zoomx,
float zoomy)
{
- RenderResult *rr;
Render *re = RE_GetSceneRender(scene);
RenderData *rd = RE_engine_get_render_data(re);
Scene *stats_scene = ED_render_job_get_scene(C);
@@ -95,7 +98,7 @@ static void draw_render_info(const bContext *C,
stats_scene = CTX_data_scene(C);
}
- rr = BKE_image_acquire_renderresult(stats_scene, ima);
+ RenderResult *rr = BKE_image_acquire_renderresult(stats_scene, ima);
if (rr && rr->text) {
float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
@@ -107,39 +110,41 @@ static void draw_render_info(const bContext *C,
if (re) {
int total_tiles;
bool need_free_tiles;
- rcti *tiles;
-
- tiles = RE_engine_get_current_tiles(re, &total_tiles, &need_free_tiles);
+ rcti *tiles = RE_engine_get_current_tiles(re, &total_tiles, &need_free_tiles);
if (total_tiles) {
- int i, x, y;
- rcti *tile;
-
/* find window pixel coordinates of origin */
+ int x, y;
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
- glPushMatrix();
- glTranslatef(x, y, 0.0f);
- glScalef(zoomx, zoomy, 1.0f);
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(x, y);
+ GPU_matrix_scale_2f(zoomx, zoomy);
if (rd->mode & R_BORDER) {
- glTranslatef((int)(-rd->border.xmin * rd->xsch * rd->size / 100.0f),
- (int)(-rd->border.ymin * rd->ysch * rd->size / 100.0f),
- 0.0f);
+ /* TODO: round or floor instead of casting to int */
+ GPU_matrix_translate_2f((int)(-rd->border.xmin * rd->xsch * rd->size * 0.01f),
+ (int)(-rd->border.ymin * rd->ysch * rd->size * 0.01f));
}
- UI_ThemeColor(TH_FACE_SELECT);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_FACE_SELECT);
- glLineWidth(1.0f);
- for (i = 0, tile = tiles; i < total_tiles; i++, tile++) {
- glaDrawBorderCorners(tile, zoomx, zoomy);
+ GPU_line_width(1.0f);
+
+ rcti *tile = tiles;
+ for (int i = 0; i < total_tiles; i++, tile++) {
+ immDrawBorderCorners(pos, tile, zoomx, zoomy);
}
+ immUnbindProgram();
+
if (need_free_tiles) {
MEM_freeN(tiles);
}
- glPopMatrix();
+ GPU_matrix_pop();
}
}
}
@@ -166,31 +171,37 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
float hue = 0, sat = 0, val = 0, lum = 0, u = 0, v = 0;
float col[4], finalcol[4];
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* noisy, high contrast make impossible to read if lower alpha is used. */
- glColor4ub(0, 0, 0, 190);
- glRecti(0.0, 0.0, BLI_rcti_size_x(&ar->winrct) + 1, UI_UNIT_Y);
- glDisable(GL_BLEND);
+ immUniformColor4ub(0, 0, 0, 190);
+ immRecti(pos, 0, 0, BLI_rcti_size_x(&ar->winrct) + 1, UI_UNIT_Y);
+
+ immUnbindProgram();
+
+ GPU_blend(false);
BLF_size(blf_mono_font, 11 * U.pixelsize, U.dpi);
- glColor3ub(255, 255, 255);
+ BLF_color3ub(blf_mono_font, 255, 255, 255);
BLI_snprintf(str, sizeof(str), "X:%-4d Y:%-4d |", x, y);
BLF_position(blf_mono_font, dx, dy, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str, sizeof(str));
if (zp) {
- glColor3ub(255, 255, 255);
+ BLF_color3ub(blf_mono_font, 255, 255, 255);
BLI_snprintf(str, sizeof(str), " Z:%-.4f |", 0.5f + 0.5f * (((float)*zp) / (float)0x7fffffff));
BLF_position(blf_mono_font, dx, dy, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str, sizeof(str));
}
if (zpf) {
- glColor3ub(255, 255, 255);
+ BLF_color3ub(blf_mono_font, 255, 255, 255);
BLI_snprintf(str, sizeof(str), " Z:%-.3f |", *zpf);
BLF_position(blf_mono_font, dx, dy, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
@@ -204,14 +215,14 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
else if (cp != NULL) {
BLI_snprintf(str, sizeof(str), " Val:%-.3f |", cp[0] / 255.0f);
}
- glColor3ub(255, 255, 255);
+ BLF_color3ub(blf_mono_font, 255, 255, 255);
BLF_position(blf_mono_font, dx, dy, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str, sizeof(str));
}
if (channels >= 3) {
- glColor3ubv(red);
+ BLF_color3ubv(blf_mono_font, red);
if (fp)
BLI_snprintf(str, sizeof(str), " R:%-.5f", fp[0]);
else if (cp)
@@ -222,7 +233,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str, sizeof(str));
- glColor3ubv(green);
+ BLF_color3ubv(blf_mono_font, green);
if (fp)
BLI_snprintf(str, sizeof(str), " G:%-.5f", fp[1]);
else if (cp)
@@ -233,7 +244,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
dx += BLF_width(blf_mono_font, str, sizeof(str));
- glColor3ubv(blue);
+ BLF_color3ubv(blf_mono_font, blue);
if (fp)
BLI_snprintf(str, sizeof(str), " B:%-.5f", fp[2]);
else if (cp)
@@ -245,7 +256,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
dx += BLF_width(blf_mono_font, str, sizeof(str));
if (channels == 4) {
- glColor3ub(255, 255, 255);
+ BLF_color3ub(blf_mono_font, 255, 255, 255);
if (fp)
BLI_snprintf(str, sizeof(str), " A:%-.4f", fp[3]);
else if (cp)
@@ -267,9 +278,9 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
rgba[3] = linearcol[3];
if (use_default_view)
- IMB_colormanagement_pixel_to_display_space_v4(rgba, rgba, NULL, &scene->display_settings);
+ IMB_colormanagement_pixel_to_display_space_v4(rgba, rgba, NULL, &scene->display_settings);
else
- IMB_colormanagement_pixel_to_display_space_v4(rgba, rgba, &scene->view_settings, &scene->display_settings);
+ IMB_colormanagement_pixel_to_display_space_v4(rgba, rgba, &scene->view_settings, &scene->display_settings);
BLI_snprintf(str, sizeof(str), " | CM R:%-.4f G:%-.4f B:%-.4f", rgba[0], rgba[1], rgba[2]);
BLF_position(blf_mono_font, dx, dy, 0);
@@ -305,26 +316,31 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
if (color_manage) {
if (use_default_view)
- IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, NULL, &scene->display_settings);
+ IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, NULL, &scene->display_settings);
else
- IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, &scene->view_settings, &scene->display_settings);
+ IMB_colormanagement_pixel_to_display_space_v4(finalcol, col, &scene->view_settings, &scene->display_settings);
}
else {
copy_v4_v4(finalcol, col);
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
dx += 0.25f * UI_UNIT_X;
BLI_rcti_init(&color_rect, dx, dx + (1.5f * UI_UNIT_X), 0.15f * UI_UNIT_Y, 0.85f * UI_UNIT_Y);
+ /* BLF uses immediate mode too, so we must reset our vertex format */
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
if (channels == 4) {
rcti color_rect_half;
int color_quater_x, color_quater_y;
color_rect_half = color_rect;
color_rect_half.xmax = BLI_rcti_cent_x(&color_rect);
- glRecti(color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
+ /* what color ??? */
+ immRecti(pos, color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
color_rect_half = color_rect;
color_rect_half.xmin = BLI_rcti_cent_x(&color_rect);
@@ -332,31 +348,34 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
color_quater_x = BLI_rcti_cent_x(&color_rect_half);
color_quater_y = BLI_rcti_cent_y(&color_rect_half);
- glColor4ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, 255);
- glRecti(color_rect_half.xmin, color_rect_half.ymin, color_rect_half.xmax, color_rect_half.ymax);
+ immUniformColor3ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK);
+ immRecti(pos, color_rect_half.xmin, color_rect_half.ymin, color_rect_half.xmax, color_rect_half.ymax);
- glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255);
- glRecti(color_quater_x, color_quater_y, color_rect_half.xmax, color_rect_half.ymax);
- glRecti(color_rect_half.xmin, color_rect_half.ymin, color_quater_x, color_quater_y);
+ immUniformColor3ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT);
+ immRecti(pos, color_quater_x, color_quater_y, color_rect_half.xmax, color_rect_half.ymax);
+ immRecti(pos, color_rect_half.xmin, color_rect_half.ymin, color_quater_x, color_quater_y);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4f(UNPACK3(finalcol), fp ? fp[3] : (cp[3] / 255.0f));
- glRecti(color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
- glDisable(GL_BLEND);
+ GPU_blend(true);
+ immUniformColor3fvAlpha(finalcol, fp ? fp[3] : (cp[3] / 255.0f));
+ immRecti(pos, color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
+ GPU_blend(false);
}
else {
- glColor3fv(finalcol);
- glRecti(color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
+ immUniformColor3fv(finalcol);
+ immRecti(pos, color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
}
+ immUnbindProgram();
/* draw outline */
- glColor3ub(128, 128, 128);
- sdrawbox(color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(128, 128, 128);
+ imm_draw_box_wire_2d(pos, color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
+ immUnbindProgram();
dx += 1.75f * UI_UNIT_X;
- glColor3ub(255, 255, 255);
+ BLF_color3ub(blf_mono_font, 255, 255, 255);
if (channels == 1) {
if (fp) {
rgb_to_hsv(fp[0], fp[0], fp[0], &hue, &sat, &val);
@@ -375,7 +394,6 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
BLI_snprintf(str, sizeof(str), " L:%-.4f", lum);
BLF_position(blf_mono_font, dx, dy, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
- dx += BLF_width(blf_mono_font, str, sizeof(str));
}
else if (channels >= 3) {
rgb_to_hsv(finalcol[0], finalcol[1], finalcol[2], &hue, &sat, &val);
@@ -399,69 +417,36 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
BLI_snprintf(str, sizeof(str), " L:%-.4f", lum);
BLF_position(blf_mono_font, dx, dy, 0);
BLF_draw_ascii(blf_mono_font, str, sizeof(str));
- dx += BLF_width(blf_mono_font, str, sizeof(str));
}
-
- (void)dx;
}
/* image drawing */
-
-static void sima_draw_alpha_pixels(float x1, float y1, int rectx, int recty, unsigned int *recti)
+static void sima_draw_zbuf_pixels(float x1, float y1, int rectx, int recty, int *rect,
+ float zoomx, float zoomy)
{
+ float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
- /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
- if (ENDIAN_ORDER == B_ENDIAN)
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+ /* Slowwww */
+ int *recti = MEM_mallocN(rectx * recty * sizeof(int), "temp");
+ for (int a = rectx * recty - 1; a >= 0; a--) {
+ /* zbuffer values are signed, so we need to shift color range */
+ recti[a] = rect[a] * 0.5f + 0.5f;
+ }
- glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_UNSIGNED_INT, recti);
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
-}
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
+ GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
-static void sima_draw_alpha_pixelsf(float x1, float y1, int rectx, int recty, float *rectf)
-{
- float *trectf = MEM_mallocN(rectx * recty * 4, "temp");
- int a, b;
-
- for (a = rectx * recty - 1, b = 4 * a + 3; a >= 0; a--, b -= 4)
- trectf[a] = rectf[b];
-
- glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_FLOAT, trectf);
- MEM_freeN(trectf);
- /* ogl trick below is slower... (on ATI 9600) */
-// glColorMask(1, 0, 0, 0);
-// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf + 3);
-// glColorMask(0, 1, 0, 0);
-// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf + 2);
-// glColorMask(0, 0, 1, 0);
-// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf + 1);
-// glColorMask(1, 1, 1, 1);
-}
+ immDrawPixelsTex(&state, x1, y1, rectx, recty, GL_RED, GL_INT, GL_NEAREST, recti, zoomx, zoomy, NULL);
-static void sima_draw_zbuf_pixels(float x1, float y1, int rectx, int recty, int *recti)
-{
- /* zbuffer values are signed, so we need to shift color range */
- glPixelTransferf(GL_RED_SCALE, 0.5f);
- glPixelTransferf(GL_GREEN_SCALE, 0.5f);
- glPixelTransferf(GL_BLUE_SCALE, 0.5f);
- glPixelTransferf(GL_RED_BIAS, 0.5f);
- glPixelTransferf(GL_GREEN_BIAS, 0.5f);
- glPixelTransferf(GL_BLUE_BIAS, 0.5f);
-
- glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_INT, recti);
-
- glPixelTransferf(GL_RED_SCALE, 1.0f);
- glPixelTransferf(GL_GREEN_SCALE, 1.0f);
- glPixelTransferf(GL_BLUE_SCALE, 1.0f);
- glPixelTransferf(GL_RED_BIAS, 0.0f);
- glPixelTransferf(GL_GREEN_BIAS, 0.0f);
- glPixelTransferf(GL_BLUE_BIAS, 0.0f);
+ MEM_freeN(recti);
}
-static void sima_draw_zbuffloat_pixels(Scene *scene, float x1, float y1, int rectx, int recty, float *rect_float)
+static void sima_draw_zbuffloat_pixels(Scene *scene, float x1, float y1, int rectx, int recty,
+ float *rect_float, float zoomx, float zoomy)
{
float bias, scale, *rectf, clipend;
int a;
+ float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
if (scene->camera && scene->camera->type == OB_CAMERA) {
bias = ((Camera *)scene->camera->data)->clipsta;
@@ -474,7 +459,7 @@ static void sima_draw_zbuffloat_pixels(Scene *scene, float x1, float y1, int rec
clipend = 100.0f;
}
- rectf = MEM_mallocN(rectx * recty * 4, "temp");
+ rectf = MEM_mallocN(rectx * recty * sizeof(float), "temp");
for (a = rectx * recty - 1; a >= 0; a--) {
if (rect_float[a] > clipend)
rectf[a] = 0.0f;
@@ -485,195 +470,82 @@ static void sima_draw_zbuffloat_pixels(Scene *scene, float x1, float y1, int rec
rectf[a] *= rectf[a];
}
}
- glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_FLOAT, rectf);
- MEM_freeN(rectf);
-}
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
+ GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
-static int draw_image_channel_offset(SpaceImage *sima)
-{
-#ifdef __BIG_ENDIAN__
- if (sima->flag & SI_SHOW_R) return 0;
- else if (sima->flag & SI_SHOW_G) return 1;
- else return 2;
-#else
- if (sima->flag & SI_SHOW_R) return 1;
- else if (sima->flag & SI_SHOW_G) return 2;
- else return 3;
-#endif
+ immDrawPixelsTex(&state, x1, y1, rectx, recty, GL_RED, GL_FLOAT, GL_NEAREST, rectf, zoomx, zoomy, NULL);
+
+ MEM_freeN(rectf);
}
static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, Scene *scene, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy)
{
int x, y;
- /* set zoom */
- glPixelZoom(zoomx, zoomy);
-
- glaDefine2DArea(&ar->winrct);
-
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&ar->v2d, fx, fy, &x, &y);
/* this part is generic image display */
- if (sima->flag & SI_SHOW_ALPHA) {
- if (ibuf->rect)
- sima_draw_alpha_pixels(x, y, ibuf->x, ibuf->y, ibuf->rect);
- else if (ibuf->rect_float && ibuf->channels == 4)
- sima_draw_alpha_pixelsf(x, y, ibuf->x, ibuf->y, ibuf->rect_float);
- }
- else if (sima->flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) {
+ if (sima->flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) {
if (ibuf->zbuf)
- sima_draw_zbuf_pixels(x, y, ibuf->x, ibuf->y, ibuf->zbuf);
+ sima_draw_zbuf_pixels(x, y, ibuf->x, ibuf->y, ibuf->zbuf, zoomx, zoomy);
else if (ibuf->zbuf_float)
- sima_draw_zbuffloat_pixels(scene, x, y, ibuf->x, ibuf->y, ibuf->zbuf_float);
+ sima_draw_zbuffloat_pixels(scene, x, y, ibuf->x, ibuf->y, ibuf->zbuf_float, zoomx, zoomy);
else if (ibuf->channels == 1)
- sima_draw_zbuffloat_pixels(scene, x, y, ibuf->x, ibuf->y, ibuf->rect_float);
+ sima_draw_zbuffloat_pixels(scene, x, y, ibuf->x, ibuf->y, ibuf->rect_float, zoomx, zoomy);
}
else {
+ int clip_max_x, clip_max_y;
+ UI_view2d_view_to_region(&ar->v2d,
+ ar->v2d.cur.xmax, ar->v2d.cur.ymax,
+ &clip_max_x, &clip_max_y);
+
if (sima->flag & SI_USE_ALPHA) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ imm_draw_box_checker_2d(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy);
- fdrawcheckerboard(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
}
- if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B)) == 0) {
- int clip_max_x, clip_max_y;
- UI_view2d_view_to_region(&ar->v2d,
- ar->v2d.cur.xmax, ar->v2d.cur.ymax,
- &clip_max_x, &clip_max_y);
+ /* If RGBA display with color management */
+ if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B | SI_SHOW_ALPHA)) == 0) {
+
glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, GL_NEAREST,
- 0, 0, clip_max_x, clip_max_y);
+ 0, 0, clip_max_x, clip_max_y, zoomx, zoomy);
}
else {
+ float shuffle[4] = {0.0f, 0.0f, 0.0f, 0.0f};
unsigned char *display_buffer;
void *cache_handle;
-
- /* TODO(sergey): Ideally GLSL shading should be capable of either
- * disabling some channels or displaying buffer with custom offset.
- */
- display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
-
- if (display_buffer != NULL) {
- int channel_offset = draw_image_channel_offset(sima);
- glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT,
- display_buffer - (4 - channel_offset));
- }
- if (cache_handle != NULL) {
- IMB_display_buffer_release(cache_handle);
+ ColorManagedViewSettings *view_settings;
+ ColorManagedDisplaySettings *display_settings;
+
+ if (sima->flag & SI_SHOW_R)
+ shuffle[0] = 1.0f;
+ else if (sima->flag & SI_SHOW_G)
+ shuffle[1] = 1.0f;
+ else if (sima->flag & SI_SHOW_B)
+ shuffle[2] = 1.0f;
+ else if (sima->flag & SI_SHOW_ALPHA)
+ shuffle[3] = 1.0f;
+
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
+ GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle);
+
+ IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
+ display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);
+
+ if (display_buffer) {
+ immDrawPixelsTex_clipping(&state, x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer,
+ 0, 0, clip_max_x, clip_max_y, zoomx, zoomy, NULL);
}
- }
-
- if (sima->flag & SI_USE_ALPHA)
- glDisable(GL_BLEND);
- }
-
- /* reset zoom */
- glPixelZoom(1.0f, 1.0f);
-}
-
-static unsigned int *get_part_from_buffer(unsigned int *buffer, int width, short startx, short starty, short endx, short endy)
-{
- unsigned int *rt, *rp, *rectmain;
- short y, heigth, len;
-
- /* the right offset in rectot */
-
- rt = buffer + (starty * width + startx);
- len = (endx - startx);
- heigth = (endy - starty);
-
- rp = rectmain = MEM_mallocN(heigth * len * sizeof(int), "rect");
-
- for (y = 0; y < heigth; y++) {
- memcpy(rp, rt, len * 4);
- rt += width;
- rp += len;
- }
- return rectmain;
-}
-
-static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene, Image *ima, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy)
-{
- unsigned char *display_buffer;
- unsigned int *rect;
- int dx, dy, sx, sy, x, y;
- void *cache_handle;
- int channel_offset = -1;
-
- /* verify valid values, just leave this a while */
- if (ima->xrep < 1) return;
- if (ima->yrep < 1) return;
-
- if (ima->flag & IMA_VIEW_AS_RENDER)
- display_buffer = IMB_display_buffer_acquire(ibuf, &scene->view_settings, &scene->display_settings, &cache_handle);
- else
- display_buffer = IMB_display_buffer_acquire(ibuf, NULL, &scene->display_settings, &cache_handle);
-
- if (!display_buffer)
- return;
-
- glPixelZoom(zoomx, zoomy);
-
- if (sima->curtile >= ima->xrep * ima->yrep)
- sima->curtile = ima->xrep * ima->yrep - 1;
-
- /* retrieve part of image buffer */
- dx = max_ii(ibuf->x / ima->xrep, 1);
- dy = max_ii(ibuf->y / ima->yrep, 1);
- sx = (sima->curtile % ima->xrep) * dx;
- sy = (sima->curtile / ima->xrep) * dy;
- rect = get_part_from_buffer((unsigned int *)display_buffer, ibuf->x, sx, sy, sx + dx, sy + dy);
-
- /* draw repeated */
- if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B)) != 0) {
- channel_offset = draw_image_channel_offset(sima);
- }
- for (sy = 0; sy + dy <= ibuf->y; sy += dy) {
- for (sx = 0; sx + dx <= ibuf->x; sx += dx) {
- UI_view2d_view_to_region(&ar->v2d, fx + (float)sx / (float)ibuf->x, fy + (float)sy / (float)ibuf->y, &x, &y);
- if (channel_offset == -1) {
- glaDrawPixelsSafe(x, y, dx, dy, dx, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- }
- else {
- glaDrawPixelsSafe(x, y, dx, dy, dx, GL_LUMINANCE, GL_UNSIGNED_INT,
- (unsigned char *)rect - (4 - channel_offset));
- }
+ IMB_display_buffer_release(cache_handle);
}
- }
-
- glPixelZoom(1.0f, 1.0f);
-
- IMB_display_buffer_release(cache_handle);
-
- MEM_freeN(rect);
-}
-
-static void draw_image_buffer_repeated(const bContext *C, SpaceImage *sima, ARegion *ar, Scene *scene, Image *ima, ImBuf *ibuf, float zoomx, float zoomy)
-{
- const double time_current = PIL_check_seconds_timer();
-
- const int xmax = ceil(ar->v2d.cur.xmax);
- const int ymax = ceil(ar->v2d.cur.ymax);
- const int xmin = floor(ar->v2d.cur.xmin);
- const int ymin = floor(ar->v2d.cur.ymin);
- int x;
-
- for (x = xmin; x < xmax; x++) {
- int y;
- for (y = ymin; y < ymax; y++) {
- if (ima && (ima->tpageflag & IMA_TILES))
- draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, x, y, zoomx, zoomy);
- else
- draw_image_buffer(C, sima, ar, scene, ibuf, x, y, zoomx, zoomy);
-
- /* only draw until running out of time */
- if ((PIL_check_seconds_timer() - time_current) > 0.25)
- return;
- }
+ if (sima->flag & SI_USE_ALPHA)
+ GPU_blend(false);
}
}
@@ -701,134 +573,62 @@ void draw_image_sample_line(SpaceImage *sima)
if (sima->sample_line_hist.flag & HISTO_FLAG_SAMPLELINE) {
Histogram *hist = &sima->sample_line_hist;
- glBegin(GL_LINES);
- glColor3ub(0, 0, 0);
- glVertex2fv(hist->co[0]);
- glVertex2fv(hist->co[1]);
- glEnd();
-
- setlinestyle(1);
- glBegin(GL_LINES);
- glColor3ub(255, 255, 255);
- glVertex2fv(hist->co[0]);
- glVertex2fv(hist->co[1]);
- glEnd();
- setlinestyle(0);
+ GPUVertFormat *format = immVertexFormat();
+ uint shdr_dashed_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
-}
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-/* XXX becomes WM paint cursor */
-#if 0
-static void draw_image_view_tool(Scene *scene)
-{
- ToolSettings *settings = scene->toolsettings;
- Brush *brush = settings->imapaint.brush;
- int mval[2];
- float radius;
- int draw = 0;
-
- if (brush) {
- if (settings->imapaint.flag & IMAGEPAINT_DRAWING) {
- if (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
- draw = 1;
- }
- else if (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL)
- draw = 1;
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- if (draw) {
- getmouseco_areawin(mval);
+ immUniform1i("colors_len", 2); /* Advanced dashes. */
+ immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 2.0f);
- radius = BKE_brush_size_get(brush) * G.sima->zoom;
- fdrawXORcirc(mval[0], mval[1], radius);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(shdr_dashed_pos, hist->co[0]);
+ immVertex2fv(shdr_dashed_pos, hist->co[1]);
+ immEnd();
- if (brush->innerradius != 1.0) {
- radius *= brush->innerradius;
- fdrawXORcirc(mval[0], mval[1], radius);
- }
- }
+ immUnbindProgram();
}
}
-#endif
-
-static unsigned char *get_alpha_clone_image(const bContext *C, Scene *scene, int *width, int *height)
-{
- Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint);
- ImBuf *ibuf;
- unsigned int size, alpha;
- unsigned char *display_buffer;
- unsigned char *rect, *cp;
- void *cache_handle;
-
- if (!brush || !brush->clone.image)
- return NULL;
-
- ibuf = BKE_image_acquire_ibuf(brush->clone.image, NULL, NULL);
-
- if (!ibuf)
- return NULL;
-
- display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
-
- if (!display_buffer) {
- BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
- IMB_display_buffer_release(cache_handle);
-
- return NULL;
- }
-
- rect = MEM_dupallocN(display_buffer);
-
- IMB_display_buffer_release(cache_handle);
-
- if (!rect) {
- BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
- return NULL;
- }
-
- *width = ibuf->x;
- *height = ibuf->y;
-
- size = (*width) * (*height);
- alpha = (unsigned char)255 * brush->clone.alpha;
- cp = rect;
-
- while (size-- > 0) {
- cp[3] = alpha;
- cp += 4;
- }
-
- BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
-
- return rect;
-}
static void draw_image_paint_helpers(const bContext *C, ARegion *ar, Scene *scene, float zoomx, float zoomy)
{
Brush *brush;
- int x, y, w, h;
- unsigned char *clonerect;
+ int x, y;
+ ImBuf *ibuf;
brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint);
- if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) {
- /* this is not very efficient, but glDrawPixels doesn't allow
- * drawing with alpha */
- clonerect = get_alpha_clone_image(C, scene, &w, &h);
+ if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE) && brush->clone.image) {
+ ibuf = BKE_image_acquire_ibuf(brush->clone.image, NULL, NULL);
- if (clonerect) {
+ if (ibuf) {
+ void *cache_handle = NULL;
+ float col[4] = {1.0f, 1.0f, 1.0f, brush->clone.alpha};
UI_view2d_view_to_region(&ar->v2d, brush->clone.offset[0], brush->clone.offset[1], &x, &y);
- glPixelZoom(zoomx, zoomy);
+ unsigned char *display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glaDrawPixelsSafe(x, y, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, clonerect);
- glDisable(GL_BLEND);
+ if (!display_buffer) {
+ BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
+ IMB_display_buffer_release(cache_handle);
+ return;
+ }
- glPixelZoom(1.0, 1.0);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- MEM_freeN(clonerect);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(&state, x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, display_buffer, zoomx, zoomy, col);
+
+ GPU_blend(false);
+
+ BKE_image_release_ibuf(brush->clone.image, ibuf, NULL);
+ IMB_display_buffer_release(cache_handle);
}
}
}
@@ -899,13 +699,7 @@ void draw_image_main(const bContext *C, ARegion *ar)
ED_region_grid_draw(ar, zoomx, zoomy);
}
else {
-
- if (sima->flag & SI_DRAW_TILE)
- draw_image_buffer_repeated(C, sima, ar, scene, ima, ibuf, zoomx, zoomy);
- else if (ima && (ima->tpageflag & IMA_TILES))
- draw_image_buffer_tiled(sima, ar, scene, ima, ibuf, 0.0f, 0.0, zoomx, zoomy);
- else
- draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
+ draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
if (sima->flag & SI_DRAW_METADATA) {
int x, y;
@@ -924,23 +718,6 @@ void draw_image_main(const bContext *C, ARegion *ar)
if (show_paint)
draw_image_paint_helpers(C, ar, scene, zoomx, zoomy);
- /* XXX integrate this code */
-#if 0
- if (ibuf) {
- float xoffs = 0.0f, yoffs = 0.0f;
-
- if (image_preview_active(sa, &xim, &yim)) {
- xoffs = scene->r.disprect.xmin;
- yoffs = scene->r.disprect.ymin;
- glColor3ub(0, 0, 0);
- calc_image_view(sima, 'f');
- myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
- glRectf(0.0f, 0.0f, 1.0f, 1.0f);
- glLoadIdentity();
- }
- }
-#endif
-
if (show_viewer) {
BLI_thread_unlock(LOCK_DRAW_IMAGE);
}
@@ -982,8 +759,8 @@ void draw_image_cache(const bContext *C, ARegion *ar)
mask = ED_space_image_get_mask(sima);
}
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* Draw cache background. */
ED_region_cache_draw_background(ar);
@@ -997,13 +774,17 @@ void draw_image_cache(const bContext *C, ARegion *ar)
ED_region_cache_draw_cached_segments(ar, num_segments, points, sfra + sima->iuser.offset, efra + sima->iuser.offset);
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* Draw current frame. */
x = (cfra - sfra) / (efra - sfra + 1) * ar->winx;
- UI_ThemeColor(TH_CFRAME);
- glRecti(x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_CFRAME);
+ immRecti(pos, x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC);
+ immUnbindProgram();
+
ED_region_cache_draw_curfra_label(cfra, x, 8.0f * UI_DPI_FAC);
if (mask != NULL) {
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 5eaefcc9bb2..96c3f55df92 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -34,17 +34,20 @@
#include "DNA_scene_types.h"
#include "BLI_rect.h"
+#include "BLI_listbase.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_image.h"
-#include "BKE_editmesh.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "IMB_imbuf_types.h"
+#include "DEG_depsgraph.h"
+
#include "ED_image.h" /* own include */
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -62,11 +65,8 @@ Image *ED_space_image(SpaceImage *sima)
}
/* called to assign images to UV faces */
-void ED_space_image_set(Main *bmain, SpaceImage *sima, Scene *scene, Object *obedit, Image *ima)
+void ED_space_image_set(Main *bmain, SpaceImage *sima, Scene *UNUSED(scene), Object *obedit, Image *ima)
{
- /* context may be NULL, so use global */
- ED_uvedit_assign_image(bmain, scene, obedit, ima, sima->image);
-
/* change the space ima after because uvedit_face_visible_test uses the space ima
* to check if the face is displayed in UV-localview */
sima->image = ima;
@@ -303,17 +303,19 @@ bool ED_image_slot_cycle(struct Image *image, int direction)
BLI_assert(ELEM(direction, -1, 1));
- for (i = 1; i < IMA_MAX_RENDER_SLOT; i++) {
- slot = (cur + ((direction == -1) ? -i : i)) % IMA_MAX_RENDER_SLOT;
- if (slot < 0) slot += IMA_MAX_RENDER_SLOT;
+ int num_slots = BLI_listbase_count(&image->renderslots);
+ for (i = 1; i < num_slots; i++) {
+ slot = (cur + ((direction == -1) ? -i : i)) % num_slots;
+ if (slot < 0) slot += num_slots;
- if (image->renders[slot] || slot == image->last_render_slot) {
+ RenderSlot *render_slot = BKE_image_get_renderslot(image, slot);
+ if ((render_slot && render_slot->render) || slot == image->last_render_slot) {
image->render_slot = slot;
break;
}
}
- if (i == IMA_MAX_RENDER_SLOT) {
+ if (i == num_slots) {
image->render_slot = ((cur == 1) ? 0 : 1);
}
@@ -359,8 +361,14 @@ bool ED_space_image_show_paint(SpaceImage *sima)
bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
{
- if (sima && (ED_space_image_show_render(sima) || ED_space_image_show_paint(sima)))
- return false;
+ if (sima) {
+ if (ED_space_image_show_render(sima)) {
+ return false;
+ }
+ if (sima->mode != SI_MODE_UV) {
+ return false;
+ }
+ }
if (obedit && obedit->type == OB_MESH) {
struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -375,10 +383,10 @@ bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
}
/* matches clip function */
-bool ED_space_image_check_show_maskedit(Scene *scene, SpaceImage *sima)
+bool ED_space_image_check_show_maskedit(SpaceImage *sima, ViewLayer *view_layer)
{
/* check editmode - this is reserved for UV editing */
- Object *ob = OBACT;
+ Object *ob = OBACT(view_layer);
if (ob && ob->mode & OB_MODE_EDIT && ED_space_image_show_uvedit(sima, ob)) {
return false;
}
@@ -391,8 +399,8 @@ bool ED_space_image_maskedit_poll(bContext *C)
SpaceImage *sima = CTX_wm_space_image(C);
if (sima) {
- Scene *scene = CTX_data_scene(C);
- return ED_space_image_check_show_maskedit(scene, sima);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return ED_space_image_check_show_maskedit(sima, view_layer);
}
return false;
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index f7fec4ed396..5d9c496d584 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -83,6 +83,9 @@ void IMAGE_OT_unpack(struct wmOperatorType *ot);
void IMAGE_OT_invert(struct wmOperatorType *ot);
void IMAGE_OT_cycle_render_slot(struct wmOperatorType *ot);
+void IMAGE_OT_clear_render_slot(struct wmOperatorType *ot);
+void IMAGE_OT_add_render_slot(struct wmOperatorType *ot);
+void IMAGE_OT_remove_render_slot(struct wmOperatorType *ot);
void IMAGE_OT_sample(struct wmOperatorType *ot);
void IMAGE_OT_sample_line(struct wmOperatorType *ot);
@@ -90,7 +93,7 @@ void IMAGE_OT_curves_point_set(struct wmOperatorType *ot);
void IMAGE_OT_change_frame(struct wmOperatorType *ot);
-void IMAGE_OT_read_renderlayers(struct wmOperatorType *ot);
+void IMAGE_OT_read_viewlayers(struct wmOperatorType *ot);
void IMAGE_OT_render_border(struct wmOperatorType *ot);
void IMAGE_OT_clear_render_border(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index df303a7bf11..67727c661a0 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -48,6 +48,7 @@
#include "BLT_translation.h"
+#include "DNA_camera_types.h"
#include "DNA_object_types.h"
#include "DNA_node_types.h"
#include "DNA_packedFile_types.h"
@@ -56,8 +57,6 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_global.h"
@@ -70,8 +69,9 @@
#include "BKE_sound.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_draw.h"
-#include "GPU_buffers.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -277,8 +277,9 @@ static bool space_image_main_area_not_uv_brush_poll(bContext *C)
Scene *scene = CTX_data_scene(C);
ToolSettings *toolsettings = scene->toolsettings;
- if (sima && !toolsettings->uvsculpt && !scene->obedit)
+ if (sima && !toolsettings->uvsculpt && (CTX_data_edit_object(C) == NULL)) {
return 1;
+ }
return 0;
}
@@ -287,13 +288,12 @@ static bool image_sample_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
if (sima) {
- Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
- ToolSettings *toolsettings = scene->toolsettings;
-
if (obedit) {
- if (ED_space_image_show_uvedit(sima, obedit) && (toolsettings->use_uv_sculpt))
+ /* Disable when UV editing so it doesn't swallow all click events (use for setting cursor). */
+ if (ED_space_image_show_uvedit(sima, obedit)) {
return false;
+ }
}
else if (sima->mode != SI_MODE_VIEW) {
return false;
@@ -421,7 +421,7 @@ static void image_view_pan_cancel(bContext *C, wmOperator *op)
void IMAGE_OT_view_pan(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Pan";
+ ot->name = "Pan View";
ot->idname = "IMAGE_OT_view_pan";
ot->description = "Pan the view";
@@ -637,7 +637,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom";
+ ot->name = "Zoom View";
ot->idname = "IMAGE_OT_view_zoom";
ot->description = "Zoom in/out the image";
@@ -792,6 +792,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
SpaceImage *sima;
ARegion *ar;
Scene *scene;
+ ViewLayer *view_layer;
Object *obedit;
Image *ima;
@@ -799,6 +800,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
sima = CTX_wm_space_image(C);
ar = CTX_wm_region(C);
scene = CTX_data_scene(C);
+ view_layer = CTX_data_view_layer(C);
obedit = CTX_data_edit_object(C);
ima = ED_space_image(sima);
@@ -810,7 +812,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
}
- else if (ED_space_image_check_show_maskedit(scene, sima)) {
+ else if (ED_space_image_check_show_maskedit(sima, view_layer)) {
if (!ED_mask_selected_minmax(C, min, max)) {
return OPERATOR_CANCELLED;
}
@@ -1038,15 +1040,15 @@ void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
ot->idname = "IMAGE_OT_view_zoom_border";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = image_view_zoom_border_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = space_image_main_region_poll;
/* rna */
- WM_operator_properties_gesture_border_zoom(ot);
+ WM_operator_properties_gesture_box_zoom(ot);
}
/**************** load/replace/save callbacks ******************/
@@ -1228,7 +1230,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
ImageOpenData *iod = op->customdata;
- PointerRNA idptr;
Image *ima = NULL;
char filepath[FILE_MAX];
int frame_seq_len = 0;
@@ -1294,8 +1295,9 @@ static int image_open_exec(bContext *C, wmOperator *op)
* pointer use also increases user, so this compensates it */
id_us_min(&ima->id);
- RNA_id_pointer_create(&ima->id, &idptr);
- RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr);
+ PointerRNA imaptr;
+ RNA_id_pointer_create(&ima->id, &imaptr);
+ RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, imaptr);
RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
}
@@ -1307,21 +1309,23 @@ static int image_open_exec(bContext *C, wmOperator *op)
ED_space_image_set(bmain, sima, scene, obedit, ima);
iuser = &sima->iuser;
}
- else if (sa && sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
-
- for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->ima == ima) {
- iuser = &bgpic->iuser;
- break;
- }
- }
- }
else {
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
if (tex && tex->type == TEX_IMAGE) {
iuser = &tex->iuser;
}
+
+ if (iuser == NULL) {
+ Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
+ if (cam) {
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->ima == ima) {
+ iuser = &bgpic->iuser;
+ break;
+ }
+ }
+ }
+ }
}
/* initialize because of new image */
@@ -1335,7 +1339,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
else {
iuser->offset = frame_ofs - 1;
}
- iuser->fie_ima = 2;
iuser->scene = scene;
BKE_image_init_imageuser(ima, iuser);
}
@@ -1425,7 +1428,7 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
- uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, NULL, '\0');
+ uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* image template */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
@@ -1491,7 +1494,7 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
if (!anim)
return OPERATOR_CANCELLED;
iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
- BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
+ BKE_image_user_frame_calc(iuser, scene->r.cfra);
return OPERATOR_FINISHED;
}
@@ -2147,7 +2150,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
- uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, NULL, '\0');
+ uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* multiview template */
if (is_multiview)
@@ -2349,7 +2352,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
// XXX other users?
BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
@@ -2379,6 +2382,30 @@ enum {
GEN_CONTEXT_PAINT_STENCIL = 2
};
+typedef struct ImageNewData {
+ PropertyPointerRNA pprop;
+} ImageNewData;
+
+static ImageNewData *image_new_init(bContext *C, wmOperator *op)
+{
+ if (op->customdata) {
+ return op->customdata;
+ }
+
+ ImageNewData *data = MEM_callocN(sizeof(ImageNewData), __func__);
+ UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
+ op->customdata = data;
+ return data;
+}
+
+static void image_new_free(wmOperator *op)
+{
+ if (op->customdata) {
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+ }
+}
+
static int image_new_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima;
@@ -2386,13 +2413,11 @@ static int image_new_exec(bContext *C, wmOperator *op)
Object *obedit;
Image *ima;
Main *bmain;
- PointerRNA ptr, idptr;
PropertyRNA *prop;
char name_buffer[MAX_ID_NAME - 2];
const char *name;
float color[4];
int width, height, floatbuf, gen_type, alpha;
- int gen_context;
int stereo3d;
/* retrieve state */
@@ -2416,7 +2441,6 @@ static int image_new_exec(bContext *C, wmOperator *op)
gen_type = RNA_enum_get(op->ptr, "generated_type");
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
- gen_context = RNA_enum_get(op->ptr, "gen_context");
stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
if (!alpha)
@@ -2424,83 +2448,47 @@ static int image_new_exec(bContext *C, wmOperator *op)
ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
- if (!ima)
+ if (!ima) {
+ image_new_free(op);
return OPERATOR_CANCELLED;
+ }
/* hook into UI */
- UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
+ ImageNewData *data = image_new_init(C, op);
- if (prop) {
+ if (data->pprop.prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer use also increases user, so this compensates it */
id_us_min(&ima->id);
- RNA_id_pointer_create(&ima->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr);
- RNA_property_update(C, &ptr, prop);
+ PointerRNA imaptr;
+ RNA_id_pointer_create(&ima->id, &imaptr);
+ RNA_property_pointer_set(&data->pprop.ptr, data->pprop.prop, imaptr);
+ RNA_property_update(C, &data->pprop.ptr, data->pprop.prop);
}
else if (sima) {
ED_space_image_set(bmain, sima, scene, obedit, ima);
}
- else if (gen_context == GEN_CONTEXT_PAINT_CANVAS) {
- bScreen *sc;
- Object *ob = CTX_data_active_object(C);
-
- GPU_drawobject_free(ob->derivedFinal);
- if (scene->toolsettings->imapaint.canvas)
- id_us_min(&scene->toolsettings->imapaint.canvas->id);
- scene->toolsettings->imapaint.canvas = ima;
-
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima_other = (SpaceImage *)sl;
-
- if (!sima_other->pin) {
- ED_space_image_set(bmain, sima_other, scene, scene->obedit, ima);
- }
- }
- }
- }
- }
- BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
- }
- else if (gen_context == GEN_CONTEXT_PAINT_STENCIL) {
- Object *ob = CTX_data_active_object(C);
- if (scene->toolsettings->imapaint.stencil)
- id_us_min(&scene->toolsettings->imapaint.stencil->id);
- scene->toolsettings->imapaint.stencil = ima;
- BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
- }
- else {
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
- if (tex && tex->type == TEX_IMAGE) {
- if (tex->ima)
- id_us_min(&tex->ima->id);
- tex->ima = ima;
- ED_area_tag_redraw(CTX_wm_area(C));
- }
- }
BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
+ image_new_free(op);
+
return OPERATOR_FINISHED;
}
-/* XXX, Ton is not a fan of OK buttons but using this function to avoid undo/redo bug while in mesh-editmode, - campbell */
-/* XXX Note: the WM_operator_props_dialog_popup() doesn't work for UI_context_active_but_prop_get_templateID(), image is not being that way */
static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ /* Get property in advance, it doesn't work after WM_operator_props_dialog_popup. */
+ ImageNewData *data;
+ op->customdata = data = MEM_callocN(sizeof(ImageNewData), __func__);
+ UI_context_active_but_prop_get_templateID(C, &data->pprop.ptr, &data->pprop.prop);
+
/* Better for user feedback. */
RNA_string_set(op->ptr, "name", DATA_(IMA_DEF_NAME));
- return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
+ return WM_operator_props_dialog_popup(C, op, 300, 100);
}
static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
@@ -2550,18 +2538,16 @@ static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
#endif
}
+static void image_new_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ image_new_free(op);
+}
+
void IMAGE_OT_new(wmOperatorType *ot)
{
PropertyRNA *prop;
static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- static const EnumPropertyItem gen_context_items[] = {
- {GEN_CONTEXT_NONE, "NONE", 0, "None", ""},
- {GEN_CONTEXT_PAINT_CANVAS, "PAINT_CANVAS", 0, "Paint Canvas", ""},
- {GEN_CONTEXT_PAINT_STENCIL, "PAINT_STENCIL", 0, "Paint Stencil", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
/* identifiers */
ot->name = "New Image";
ot->description = "Create a new image";
@@ -2571,6 +2557,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
ot->exec = image_new_exec;
ot->invoke = image_new_invoke;
ot->ui = image_new_draw;
+ ot->cancel = image_new_cancel;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -2588,7 +2575,6 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_enum(ot->srna, "generated_type", rna_enum_image_generated_type_items, IMA_GENTYPE_BLANK,
"Generated Type", "Fill the image with a grid for UV map testing");
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
- prop = RNA_def_enum(ot->srna, "gen_context", gen_context_items, 0, "Gen Context", "Generation context");
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_boolean(ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
@@ -3461,7 +3447,8 @@ static int image_cycle_render_slot_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
/* no undo push for browsing existing */
- if (ima->renders[ima->render_slot] || ima->render_slot == ima->last_render_slot)
+ RenderSlot *slot = BKE_image_get_renderslot(ima, ima->render_slot);
+ if ((slot && slot->render) || ima->render_slot == ima->last_render_slot)
return OPERATOR_CANCELLED;
return OPERATOR_FINISHED;
@@ -3484,6 +3471,97 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
}
+/********************* clear render slot operator *********************/
+
+static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+
+ if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Render Slot";
+ ot->idname = "IMAGE_OT_clear_render_slot";
+ ot->description = "Clear the currently selected render slot";
+
+ /* api callbacks */
+ ot->exec = image_clear_render_slot_exec;
+ ot->poll = image_cycle_render_slot_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/********************* add render slot operator *********************/
+
+static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Image *ima = CTX_data_edit_image(C);
+
+ RenderSlot *slot = BKE_image_add_renderslot(ima, NULL);
+ ima->render_slot = BLI_findindex(&ima->renderslots, slot);
+
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_add_render_slot(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Render Slot";
+ ot->idname = "IMAGE_OT_add_render_slot";
+ ot->description = "Add a new render slot";
+
+ /* api callbacks */
+ ot->exec = image_add_render_slot_exec;
+ ot->poll = image_cycle_render_slot_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/********************* remove render slot operator *********************/
+
+static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+
+ if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Render Slot";
+ ot->idname = "IMAGE_OT_remove_render_slot";
+ ot->description = "Remove the current render slot";
+
+ /* api callbacks */
+ ot->exec = image_remove_render_slot_exec;
+ ot->poll = image_cycle_render_slot_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
/********************** change frame operator *********************/
static bool change_frame_poll(bContext *C)
@@ -3602,7 +3680,7 @@ void IMAGE_OT_change_frame(wmOperatorType *ot)
/* Reload cached render results... */
/* goes over all scenes, reads render layers */
-static int image_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
+static int image_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -3620,14 +3698,14 @@ static int image_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void IMAGE_OT_read_renderlayers(wmOperatorType *ot)
+void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
{
- ot->name = "Read Render Layers";
- ot->idname = "IMAGE_OT_read_renderlayers";
- ot->description = "Read all the current scene's render layers from cache, as needed";
+ ot->name = "Open Cached Render";
+ ot->idname = "IMAGE_OT_read_viewlayers";
+ ot->description = "Read all the current scene's view layers from cache, as needed";
ot->poll = space_image_main_region_poll;
- ot->exec = image_read_renderlayers_exec;
+ ot->exec = image_read_viewlayers_exec;
/* flags */
ot->flag = 0;
@@ -3691,10 +3769,10 @@ void IMAGE_OT_render_border(wmOperatorType *ot)
ot->idname = "IMAGE_OT_render_border";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = render_border_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = image_cycle_render_slot_poll;
/* flags */
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index fd661883f79..01d2fc28c6b 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -44,10 +44,16 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
+#include "BKE_editmesh.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_material.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
#include "IMB_imbuf_types.h"
@@ -59,6 +65,7 @@
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_uvedit.h"
+#include "ED_transform.h"
#include "BIF_gl.h"
@@ -66,12 +73,14 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "UI_resources.h"
#include "UI_interface.h"
#include "UI_view2d.h"
#include "image_intern.h"
+#include "GPU_framebuffer.h"
/**************************** common state *****************************/
@@ -156,7 +165,7 @@ ARegion *image_has_tools_region(ScrArea *sa)
/* ******************** default callbacks for image space ***************** */
-static SpaceLink *image_new(const bContext *UNUSED(C))
+static SpaceLink *image_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceImage *simage;
@@ -165,12 +174,11 @@ static SpaceLink *image_new(const bContext *UNUSED(C))
simage->spacetype = SPACE_IMAGE;
simage->zoom = 1.0f;
simage->lock = true;
- simage->flag = SI_SHOW_GPENCIL | SI_USE_ALPHA;
+ simage->flag = SI_SHOW_GPENCIL | SI_USE_ALPHA | SI_COORDFLOATS;
simage->iuser.ok = true;
- simage->iuser.fie_ima = 2;
simage->iuser.frames = 100;
- simage->iuser.flag = IMA_SHOW_STEREO;
+ simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS;
scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;
@@ -180,7 +188,7 @@ static SpaceLink *image_new(const bContext *UNUSED(C))
BLI_addtail(&simage->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* buttons/list view */
ar = MEM_callocN(sizeof(ARegion), "buttons for image");
@@ -265,6 +273,9 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_invert);
WM_operatortype_append(IMAGE_OT_cycle_render_slot);
+ WM_operatortype_append(IMAGE_OT_clear_render_slot);
+ WM_operatortype_append(IMAGE_OT_add_render_slot);
+ WM_operatortype_append(IMAGE_OT_remove_render_slot);
WM_operatortype_append(IMAGE_OT_sample);
WM_operatortype_append(IMAGE_OT_sample_line);
@@ -275,106 +286,19 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_change_frame);
- WM_operatortype_append(IMAGE_OT_read_renderlayers);
+ WM_operatortype_append(IMAGE_OT_read_viewlayers);
WM_operatortype_append(IMAGE_OT_render_border);
WM_operatortype_append(IMAGE_OT_clear_render_border);
}
static void image_keymap(struct wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Image Generic", SPACE_IMAGE, 0);
- wmKeyMapItem *kmi;
- int i;
-
- WM_keymap_add_item(keymap, "IMAGE_OT_new", NKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_open", OKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_reload", RKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_read_renderlayers", RKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_save", SKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_save_as", F3KEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_properties", NKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_toolshelf", TKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "IMAGE_OT_cycle_render_slot", JKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "IMAGE_OT_cycle_render_slot", JKEY, KM_PRESS, KM_ALT, 0)->ptr, "reverse", true);
-
- keymap = WM_keymap_ensure(keyconf, "Image", SPACE_IMAGE, 0);
-
- WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "fit_view", true);
-
- WM_keymap_add_item(keymap, "IMAGE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MOUSEPAN, 0, 0, 0);
-
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "IMAGE_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); // or view selected?
- WM_keymap_add_item(keymap, "IMAGE_OT_view_ndof", NDOF_MOTION, 0, 0, 0);
-#endif
-
- WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", PADMINUS, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEZOOM, 0, 0, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEPAN, 0, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_border", BKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* ctrl now works as well, shift + numpad works as arrow keys on Windows */
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 8.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD4, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 4.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD2, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 2.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 8.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 4.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD2, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 2.0f);
-
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD1, KM_PRESS, 0, 0)->ptr, "ratio", 1.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD2, KM_PRESS, 0, 0)->ptr, "ratio", 0.5f);
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD4, KM_PRESS, 0, 0)->ptr, "ratio", 0.25f);
- RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, 0, 0)->ptr, "ratio", 0.125f);
-
- WM_keymap_add_item(keymap, "IMAGE_OT_change_frame", LEFTMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "IMAGE_OT_sample", ACTIONMOUSE, KM_PRESS, 0, 0);
- RNA_enum_set(WM_keymap_add_item(keymap, "IMAGE_OT_curves_point_set", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "point", 0);
- RNA_enum_set(WM_keymap_add_item(keymap, "IMAGE_OT_curves_point_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "point", 1);
-
- /* toggle editmode is handy to have while UV unwrapping */
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", OB_MODE_EDIT);
- RNA_boolean_set(kmi->ptr, "toggle", true);
-
- /* fast switch to render slots */
- for (i = 0; i < MIN2(IMA_MAX_RENDER_SLOT, 9); i++) {
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_int", ONEKEY + i, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.image.render_slots.active_index");
- RNA_int_set(kmi->ptr, "value", i);
- }
-
- /* pivot */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "CENTER");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "MEDIAN");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "CURSOR");
-
- /* render border */
- WM_keymap_add_item(keymap, "IMAGE_OT_render_border", BKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "IMAGE_OT_clear_render_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+ WM_keymap_ensure(keyconf, "Image Generic", SPACE_IMAGE, 0);
+ WM_keymap_ensure(keyconf, "Image", SPACE_IMAGE, 0);
}
/* dropboxes */
-static bool image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
if (drag->type == WM_DRAG_PATH)
if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
@@ -404,12 +328,11 @@ static void image_refresh(const bContext *C, ScrArea *sa)
{
Scene *scene = CTX_data_scene(C);
SpaceImage *sima = sa->spacedata.first;
- Object *obedit = CTX_data_edit_object(C);
Image *ima;
ima = ED_space_image(sima);
- BKE_image_user_check_frame_calc(&sima->iuser, scene->r.cfra, 0);
+ BKE_image_user_check_frame_calc(&sima->iuser, scene->r.cfra);
/* check if we have to set the image from the editmesh */
if (ima && (ima->source == IMA_SRC_VIEWER && sima->mode == SI_MODE_MASK)) {
@@ -420,38 +343,10 @@ static void image_refresh(const bContext *C, ScrArea *sa)
}
}
}
- else if (ima && (ima->source == IMA_SRC_VIEWER || sima->pin)) {
- /* pass */
- }
- else if (obedit && obedit->type == OB_MESH) {
- Mesh *me = (Mesh *)obedit->data;
- struct BMEditMesh *em = me->edit_btmesh;
- bool sloppy = true; /* partially selected face is ok */
- bool selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION); /* only selected active face? */
-
- if (BKE_scene_use_new_shading_nodes(scene)) {
- /* new shading system does not alter image */
- }
- else {
- /* old shading system, we set texface */
- if (em && EDBM_uv_check(em)) {
- MTexPoly *tf;
- if (EDBM_uv_active_face_get(em, sloppy, selected, &tf)) {
- /* don't need to check for pin here, see above */
- sima->image = tf->tpage;
-
- if ((sima->flag & SI_EDITTILE) == 0) {
- sima->curtile = tf->tile;
- }
- }
- }
- }
- }
}
-static void image_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
+static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
- Scene *scene = sc->scene;
SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
/* context changes */
@@ -544,7 +439,8 @@ static void image_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
case ND_TRANSFORM:
case ND_MODIFIER:
{
- Object *ob = OBACT;
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Object *ob = OBACT(view_layer);
if (ob && (ob == wmn->reference) && (ob->mode & OB_MODE_EDIT)) {
if (sima->lock && (sima->flag & SI_DRAWSHADOW)) {
ED_area_tag_refresh(sa);
@@ -596,29 +492,50 @@ static int image_context(const bContext *C, const char *member, bContextDataResu
return 0;
}
+static void IMAGE_GGT_gizmo2d(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "UV Transform Gizmo";
+ gzgt->idname = "IMAGE_GGT_gizmo2d";
+
+ gzgt->gzmap_params.spaceid = SPACE_IMAGE;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_widgetgroup_gizmo2d_poll;
+ gzgt->setup = ED_widgetgroup_gizmo2d_setup;
+ gzgt->refresh = ED_widgetgroup_gizmo2d_refresh;
+ gzgt->draw_prepare = ED_widgetgroup_gizmo2d_draw_prepare;
+}
+
+static void image_widgets(void)
+{
+ WM_gizmogrouptype_append(IMAGE_GGT_gizmo2d);
+}
+
/************************** main region ***************************/
/* sets up the fields of the View2D from zoom and offset */
static void image_main_region_set_view2d(SpaceImage *sima, ARegion *ar)
{
Image *ima = ED_space_image(sima);
- float x1, y1, w, h;
- int width, height, winx, winy;
-#if 0
- if (image_preview_active(curarea, &width, &height)) {}
- else
-#endif
+ int width, height;
ED_space_image_get_size(sima, &width, &height);
- w = width;
- h = height;
+ float w = width;
+ float h = height;
if (ima)
h *= ima->aspy / ima->aspx;
- winx = BLI_rcti_size_x(&ar->winrct) + 1;
- winy = BLI_rcti_size_y(&ar->winrct) + 1;
+ int winx = BLI_rcti_size_x(&ar->winrct) + 1;
+ int winy = BLI_rcti_size_y(&ar->winrct) + 1;
+
+ /* For region overlap, move center so image doesn't overlap header. */
+ rcti visible_rect;
+ ED_region_visible_rect(ar, &visible_rect);
+ const int visible_winy = BLI_rcti_size_y(&visible_rect) + 1;
+ int visible_centerx = 0;
+ int visible_centery = visible_rect.ymin + (visible_winy - winy) / 2;
ar->v2d.tot.xmin = 0;
ar->v2d.tot.ymin = 0;
@@ -630,8 +547,8 @@ static void image_main_region_set_view2d(SpaceImage *sima, ARegion *ar)
ar->v2d.mask.ymax = winy;
/* which part of the image space do we see? */
- x1 = ar->winrct.xmin + (winx - sima->zoom * w) / 2.0f;
- y1 = ar->winrct.ymin + (winy - sima->zoom * h) / 2.0f;
+ float x1 = ar->winrct.xmin + visible_centerx + (winx - sima->zoom * w) / 2.0f;
+ float y1 = ar->winrct.ymin + visible_centery + (winy - sima->zoom * h) / 2.0f;
x1 -= sima->zoom * sima->xof;
y1 -= sima->zoom * sima->yof;
@@ -684,7 +601,6 @@ static void image_main_region_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
keymap = WM_keymap_ensure(wm->defaultconf, "Image", SPACE_IMAGE, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
-
}
static void image_main_region_draw(const bContext *C, ARegion *ar)
@@ -693,9 +609,11 @@ static void image_main_region_draw(const bContext *C, ARegion *ar)
SpaceImage *sima = CTX_wm_space_image(C);
Object *obact = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Mask *mask = NULL;
bool curve = false;
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
View2D *v2d = &ar->v2d;
//View2DScrollers *scrollers;
float col[3];
@@ -705,8 +623,8 @@ static void image_main_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
- glClearColor(col[0], col[1], col[2], 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear_color(col[0], col[1], col[2], 0.0);
+ GPU_clear(GPU_COLOR_BIT);
image_user_refresh_scene(C, sima);
@@ -721,7 +639,7 @@ static void image_main_region_draw(const bContext *C, ARegion *ar)
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
- ED_uvedit_draw_main(sima, ar, scene, obedit, obact);
+ ED_uvedit_draw_main(sima, ar, scene, view_layer, obedit, obact, depsgraph);
/* check for mask (delay draw) */
if (ED_space_image_show_uvedit(sima, obedit)) {
@@ -790,6 +708,8 @@ static void image_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
}
+ WM_gizmomap_draw(ar->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
+
draw_image_cache(C, ar);
/* scrollers? */
@@ -800,10 +720,16 @@ static void image_main_region_draw(const bContext *C, ARegion *ar)
#endif
}
-static void image_main_region_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar, wmNotifier *wmn)
+static void image_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *sa, ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
+ case NC_GEOM:
+ if (ELEM(wmn->data, ND_DATA, ND_SELECT))
+ WM_gizmomap_tag_refresh(ar->gizmo_map);
+ break;
case NC_GPENCIL:
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
ED_region_tag_redraw(ar);
@@ -813,6 +739,7 @@ static void image_main_region_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion
case NC_IMAGE:
if (wmn->action == NA_PAINTING)
ED_region_tag_redraw(ar);
+ WM_gizmomap_tag_refresh(ar->gizmo_map);
break;
case NC_MATERIAL:
if (wmn->data == ND_SHADING_LINKS) {
@@ -822,6 +749,11 @@ static void image_main_region_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion
ED_region_tag_redraw(ar);
}
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
@@ -841,10 +773,12 @@ static void image_buttons_region_init(wmWindowManager *wm, ARegion *ar)
static void image_buttons_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
-static void image_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_buttons_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -914,10 +848,12 @@ static void image_tools_region_draw(const bContext *C, ARegion *ar)
}
ED_space_image_release_buffer(sima, ibuf, lock);
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
-static void image_tools_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_tools_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -968,7 +904,9 @@ static void image_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_header_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1037,16 +975,16 @@ void ED_spacetype_image(void)
st->refresh = image_refresh;
st->listener = image_listener;
st->context = image_context;
+ st->gizmos = image_widgets;
st->id_remap = image_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype image region");
art->regionid = RGN_TYPE_WINDOW;
- art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
+ art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
art->init = image_main_region_init;
art->draw = image_main_region_draw;
art->listener = image_main_region_listener;
-
BLI_addhead(&st->regiontypes, art);
/* regions: listview/buttons */
@@ -1065,9 +1003,12 @@ void ED_spacetype_image(void)
/* regions: statistics/scope buttons */
art = MEM_callocN(sizeof(ARegionType), "spacetype image region");
art->regionid = RGN_TYPE_TOOLS;
- art->prefsizex = 220; // XXX
+ art->prefsizex = 58; /* XXX */
+ art->prefsizey = 50; /* XXX */
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
art->listener = image_tools_region_listener;
+ art->message_subscribe = ED_region_generic_tools_region_message_subscribe;
+ art->snap_size = ED_region_generic_tools_region_snap_size;
art->init = image_tools_region_init;
art->draw = image_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
@@ -1083,5 +1024,9 @@ void ED_spacetype_image(void)
BLI_addhead(&st->regiontypes, art);
+ /* regions: hud */
+ art = ED_area_type_hud(st->spaceid);
+ BLI_addhead(&st->regiontypes, art);
+
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt
index 96fe9322b97..4896515182e 100644
--- a/source/blender/editors/space_info/CMakeLists.txt
+++ b/source/blender/editors/space_info/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenlib
../../blenloader
../../blentranslation
+ ../../depsgraph
../../imbuf
../../bmesh
../../gpu
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 9421567b6ba..ecd0b082df6 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -51,6 +51,7 @@
#include "info_intern.h"
#include "textview.h"
+#include "GPU_framebuffer.h"
/* complicates things a bit, so leaving in old simple code */
#define USE_INFO_NEWLINE
@@ -130,7 +131,7 @@ static int report_textview_begin(TextViewContext *tvc)
tvc->iter = reports->list.last;
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
#ifdef USE_INFO_NEWLINE
tvc->iter_tmp = 0;
diff --git a/source/blender/editors/space_info/info_intern.h b/source/blender/editors/space_info/info_intern.h
index a16acd665b4..37d3c73f705 100644
--- a/source/blender/editors/space_info/info_intern.h
+++ b/source/blender/editors/space_info/info_intern.h
@@ -61,7 +61,7 @@ void info_textview_main(struct SpaceInfo *sinfo, struct ARegion *ar, struct Repo
int info_report_mask(struct SpaceInfo *sinfo);
void INFO_OT_select_pick(struct wmOperatorType *ot); /* report selection */
void INFO_OT_select_all_toggle(struct wmOperatorType *ot);
-void INFO_OT_select_border(struct wmOperatorType *ot);
+void INFO_OT_select_box(struct wmOperatorType *ot);
void INFO_OT_report_replay(struct wmOperatorType *ot);
void INFO_OT_report_delete(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 793b1a79b55..ec0084931eb 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -509,8 +509,7 @@ static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), co
Report *report;
ReportTimerInfo *rti;
float progress = 0.0, color_progress = 0.0;
- float neutral_col[3] = {0.35, 0.35, 0.35};
- float neutral_gray = 0.6;
+ float neutral_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float timeout = 0.0, color_timeout = 0.0;
int send_note = 0;
@@ -541,34 +540,33 @@ static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), co
if (rti->widthfac == 0.0f) {
/* initialize colors based on report type */
if (report->type & RPT_ERROR_ALL) {
- rti->col[0] = 1.0;
- rti->col[1] = 0.2;
- rti->col[2] = 0.0;
+ rti->col[0] = 1.0f;
+ rti->col[1] = 0.2f;
+ rti->col[2] = 0.0f;
}
else if (report->type & RPT_WARNING_ALL) {
- rti->col[0] = 1.0;
- rti->col[1] = 1.0;
- rti->col[2] = 0.0;
+ rti->col[0] = 1.0f;
+ rti->col[1] = 1.0f;
+ rti->col[2] = 0.0f;
}
else if (report->type & RPT_INFO_ALL) {
- rti->col[0] = 0.3;
- rti->col[1] = 0.45;
- rti->col[2] = 0.7;
+ rti->col[0] = 0.3f;
+ rti->col[1] = 0.45f;
+ rti->col[2] = 0.7f;
}
- rti->grayscale = 0.75;
- rti->widthfac = 1.0;
+ rti->col[3] = 0.65f;
+ rti->widthfac = 1.0f;
}
- progress = (float)reports->reporttimer->duration / timeout;
- color_progress = (float)reports->reporttimer->duration / color_timeout;
+ progress = powf((float)reports->reporttimer->duration / timeout, 2.0f);
+ color_progress = powf((float)reports->reporttimer->duration / color_timeout, 2.0);
/* save us from too many draws */
if (color_progress <= 1.0f) {
send_note = 1;
/* fade colors out sharply according to progress through fade-out duration */
- interp_v3_v3v3(rti->col, rti->col, neutral_col, color_progress);
- rti->grayscale = interpf(neutral_gray, rti->grayscale, color_progress);
+ interp_v4_v4v4(rti->col, rti->col, neutral_col, color_progress);
}
/* collapse report at end of timeout */
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 10d92366606..d512ac8b32b 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -133,9 +133,6 @@ static int select_report_pick_invoke(bContext *C, wmOperator *op, const wmEvent
ReportList *reports = CTX_wm_reports(C);
Report *report;
- /* uses opengl */
- wmSubWindowSet(CTX_wm_window(C), ar->swinid);
-
report = info_text_pick(sinfo, ar, reports, event->mval[1]);
RNA_int_set(op->ptr, "report_index", BLI_findindex(&reports->list, report));
@@ -215,8 +212,8 @@ void INFO_OT_select_all_toggle(wmOperatorType *ot)
/* properties */
}
-/* borderselect operator */
-static int borderselect_exec(bContext *C, wmOperator *op)
+/* box_select operator */
+static int box_select_exec(bContext *C, wmOperator *op)
{
SpaceInfo *sinfo = CTX_wm_space_info(C);
ARegion *ar = CTX_wm_region(C);
@@ -289,19 +286,19 @@ static int borderselect_exec(bContext *C, wmOperator *op)
}
-/* ****** Border Select ****** */
-void INFO_OT_select_border(wmOperatorType *ot)
+/* ****** Box Select ****** */
+void INFO_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->description = "Toggle border selection";
- ot->idname = "INFO_OT_select_border";
+ ot->name = "Box Select";
+ ot->description = "Toggle box selection";
+ ot->idname = "INFO_OT_select_box";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = borderselect_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_info_active;
@@ -309,7 +306,7 @@ void INFO_OT_select_border(wmOperatorType *ot)
/* ot->flag = OPTYPE_REGISTER; */
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index b00cb1fc585..2000618a4ad 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -31,12 +31,15 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
#include "DNA_scene_types.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -47,11 +50,16 @@
#include "BKE_blender_version.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_editmesh.h"
+#include "BKE_object.h"
+#include "BKE_gpencil.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
#include "ED_info.h"
#include "ED_armature.h"
@@ -62,13 +70,14 @@
#define MAX_INFO_NUM_LEN 16
typedef struct SceneStats {
- int totvert, totvertsel;
- int totedge, totedgesel;
- int totface, totfacesel;
- int totbone, totbonesel;
- int totobj, totobjsel;
- int totlamp, totlampsel;
- int tottri;
+ uint64_t totvert, totvertsel;
+ uint64_t totedge, totedgesel;
+ uint64_t totface, totfacesel;
+ uint64_t totbone, totbonesel;
+ uint64_t totobj, totobjsel;
+ uint64_t totlamp, totlampsel;
+ uint64_t tottri;
+ uint64_t totgplayer, totgpframe, totgpstroke, totgppoint;
char infostr[MAX_INFO_LEN];
} SceneStats;
@@ -82,33 +91,42 @@ typedef struct SceneStatsFmt {
char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN];
char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN];
char tottri[MAX_INFO_NUM_LEN];
+ char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN];
+ char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN];
} SceneStatsFmt;
+static bool stats_mesheval(Mesh *me_eval, int sel, int totob, SceneStats *stats)
+{
+ int totvert, totedge, totface, totloop;
+
+ if (me_eval) {
+ totvert = me_eval->totvert;
+ totedge = me_eval->totedge;
+ totface = me_eval->totpoly;
+ totloop = me_eval->totloop;
+
+ stats->totvert += totvert * totob;
+ stats->totedge += totedge * totob;
+ stats->totface += totface * totob;
+ stats->tottri += poly_to_tri_count(totface, totloop) * totob;
+
+ if (sel) {
+ stats->totvertsel += totvert;
+ stats->totfacesel += totface;
+ }
+ return true;
+ }
+ return false;
+}
+
static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
{
switch (ob->type) {
case OB_MESH:
{
- /* we assume derivedmesh is already built, this strictly does stats now. */
- DerivedMesh *dm = ob->derivedFinal;
- int totvert, totedge, totface, totloop;
-
- if (dm) {
- totvert = dm->getNumVerts(dm);
- totedge = dm->getNumEdges(dm);
- totface = dm->getNumPolys(dm);
- totloop = dm->getNumLoops(dm);
-
- stats->totvert += totvert * totob;
- stats->totedge += totedge * totob;
- stats->totface += totface * totob;
- stats->tottri += poly_to_tri_count(totface, totloop) * totob;
-
- if (sel) {
- stats->totvertsel += totvert;
- stats->totfacesel += totface;
- }
- }
+ /* we assume evaluated mesh is already built, this strictly does stats now. */
+ Mesh *me_eval = ob->runtime.mesh_eval;
+ stats_mesheval(me_eval, sel, totob, stats);
break;
}
case OB_LAMP:
@@ -120,12 +138,19 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
case OB_SURF:
case OB_CURVE:
case OB_FONT:
+ {
+ Mesh *me_eval = ob->runtime.mesh_eval;
+ if (stats_mesheval(me_eval, sel, totob, stats)) {
+ break;
+ }
+ ATTR_FALLTHROUGH; /* Falltrough to displist. */
+ }
case OB_MBALL:
{
int totv = 0, totf = 0, tottri = 0;
- if (ob->curve_cache && ob->curve_cache->disp.first)
- BKE_displist_count(&ob->curve_cache->disp, &totv, &totf, &tottri);
+ if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first)
+ BKE_displist_count(&ob->runtime.curve_cache->disp, &totv, &totf, &tottri);
totv *= totob;
totf *= totob;
@@ -141,6 +166,22 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
}
break;
}
+ case OB_GPENCIL:
+ {
+ if (sel) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ /* GPXX Review if we can move to other place when object change
+ * maybe to depsgraph evaluation
+ */
+ BKE_gpencil_stats_update(gpd);
+
+ stats->totgplayer += gpd->totlayer;
+ stats->totgpframe += gpd->totframe;
+ stats->totgpstroke += gpd->totstroke;
+ stats->totgppoint += gpd->totpoint;
+ }
+ break;
+ }
}
}
@@ -149,16 +190,16 @@ static void stats_object_edit(Object *obedit, SceneStats *stats)
if (obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- stats->totvert = em->bm->totvert;
- stats->totvertsel = em->bm->totvertsel;
+ stats->totvert += em->bm->totvert;
+ stats->totvertsel += em->bm->totvertsel;
- stats->totedge = em->bm->totedge;
- stats->totedgesel = em->bm->totedgesel;
+ stats->totedge += em->bm->totedge;
+ stats->totedgesel += em->bm->totedgesel;
- stats->totface = em->bm->totface;
- stats->totfacesel = em->bm->totfacesel;
+ stats->totface += em->bm->totface;
+ stats->totfacesel += em->bm->totfacesel;
- stats->tottri = em->tottri;
+ stats->tottri += em->tottri;
}
else if (obedit->type == OB_ARMATURE) {
/* Armature Edit */
@@ -269,9 +310,33 @@ static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
stats->tottri = ob->sculpt->bm->totface;
}
-static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
+static void stats_dupli_object_group_count(Collection *collection, int *count)
+{
+ *count += BLI_listbase_count(&collection->gobject);
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ stats_dupli_object_group_count(child->collection, count);
+ }
+}
+
+static void stats_dupli_object_group_doit(Collection *collection, SceneStats *stats, ParticleSystem *psys,
+ const int totgroup, int *cur)
+{
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ int tot = count_particles_mod(psys, totgroup, *cur);
+ stats_object(cob->ob, 0, tot, stats);
+ (*cur)++;
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ stats_dupli_object_group_doit(child->collection, stats, psys, totgroup, cur);
+ }
+}
+
+static void stats_dupli_object(Object *ob, SceneStats *stats)
{
- if (base->flag & SELECT) stats->totobjsel++;
+ const bool is_selected = (ob->base_flag & BASE_SELECTED) != 0;
+ if (is_selected) stats->totobjsel++;
if (ob->transflag & OB_DUPLIPARTS) {
/* Dupli Particles */
@@ -286,21 +351,15 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
stats_object(part->dup_ob, 0, tot, stats);
}
else if (part->draw_as == PART_DRAW_GR && part->dup_group) {
- GroupObject *go;
- int tot, totgroup = 0, cur = 0;
-
- for (go = part->dup_group->gobject.first; go; go = go->next)
- totgroup++;
+ int totgroup = 0, cur = 0;
- for (go = part->dup_group->gobject.first; go; go = go->next) {
- tot = count_particles_mod(psys, totgroup, cur);
- stats_object(go->ob, 0, tot, stats);
- cur++;
- }
+ Collection *collection = part->dup_group;
+ stats_dupli_object_group_count(collection, &totgroup);
+ stats_dupli_object_group_doit(collection, stats, psys, totgroup, &cur);
}
}
- stats_object(ob, base->flag & SELECT, 1, stats);
+ stats_object(ob, is_selected, 1, stats);
stats->totobj++;
}
else if (ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES))) {
@@ -316,71 +375,82 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
}
stats->totobj += tot;
- stats_object(ob, base->flag & SELECT, tot, stats);
+ stats_object(ob, is_selected, tot, stats);
}
else if (ob->transflag & OB_DUPLIFRAMES) {
/* Dupli Frames */
int tot = count_duplilist(ob);
stats->totobj += tot;
- stats_object(ob, base->flag & SELECT, tot, stats);
+ stats_object(ob, is_selected, tot, stats);
}
- else if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
+ else if ((ob->transflag & OB_DUPLICOLLECTION) && ob->dup_group) {
/* Dupli Group */
int tot = count_duplilist(ob);
stats->totobj += tot;
- stats_object(ob, base->flag & SELECT, tot, stats);
+ stats_object(ob, is_selected, tot, stats);
}
else {
/* No Dupli */
- stats_object(ob, base->flag & SELECT, 1, stats);
+ stats_object(ob, is_selected, 1, stats);
stats->totobj++;
}
}
-static bool stats_is_object_dynamic_topology_sculpt(Object *ob)
+static bool stats_is_object_dynamic_topology_sculpt(Object *ob, const eObjectMode object_mode)
{
- return (ob && (ob->mode & OB_MODE_SCULPT) &&
+ return (ob &&
+ (object_mode & OB_MODE_SCULPT) &&
ob->sculpt && ob->sculpt->bm);
}
/* Statistics displayed in info header. Called regularly on scene changes. */
-static void stats_update(Scene *scene)
+static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
{
SceneStats stats = {0};
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
- Base *base;
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
- if (scene->obedit) {
+ if (obedit) {
/* Edit Mode */
- stats_object_edit(scene->obedit, &stats);
+ FOREACH_OBJECT_IN_MODE_BEGIN(view_layer, ((View3D *)NULL), ob->mode, ob_iter)
+ {
+ stats_object_edit(ob_iter, &stats);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
/* Pose Mode */
stats_object_pose(ob, &stats);
}
- else if (stats_is_object_dynamic_topology_sculpt(ob)) {
+ else if (ob && stats_is_object_dynamic_topology_sculpt(ob, ob->mode)) {
/* Dynamic-topology sculpt mode */
stats_object_sculpt_dynamic_topology(ob, &stats);
}
else {
/* Objects */
- for (base = scene->base.first; base; base = base->next)
- if (scene->lay & base->lay)
- stats_dupli_object(base, base->object, &stats);
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob_iter)
+ {
+ stats_dupli_object(ob_iter, &stats);
+ }
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
}
- if (!scene->stats)
- scene->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
+ if (!view_layer->stats) {
+ view_layer->stats = MEM_callocN(sizeof(SceneStats), "SceneStats");
+ }
- *(scene->stats) = stats;
+ *(view_layer->stats) = stats;
}
-static void stats_string(Scene *scene)
+static void stats_string(ViewLayer *view_layer)
{
#define MAX_INFO_MEM_LEN 64
- SceneStats *stats = scene->stats;
+ SceneStats *stats = view_layer->stats;
SceneStatsFmt stats_fmt;
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ LayerCollection *layer_collection = view_layer->active_collection;
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
+ eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
char gpumemstr[MAX_INFO_MEM_LEN] = "";
@@ -394,7 +464,7 @@ static void stats_string(Scene *scene)
/* Generate formatted numbers */
#define SCENE_STATS_FMT_INT(_id) \
- BLI_str_format_int_grouped(stats_fmt._id, stats->_id)
+ BLI_str_format_uint64_grouped(stats_fmt._id, stats->_id)
SCENE_STATS_FMT_INT(totvert);
SCENE_STATS_FMT_INT(totvertsel);
@@ -416,6 +486,11 @@ static void stats_string(Scene *scene)
SCENE_STATS_FMT_INT(tottri);
+ SCENE_STATS_FMT_INT(totgplayer);
+ SCENE_STATS_FMT_INT(totgpframe);
+ SCENE_STATS_FMT_INT(totgpstroke);
+ SCENE_STATS_FMT_INT(totgppoint);
+
#undef SCENE_STATS_FMT_INT
@@ -445,19 +520,25 @@ static void stats_string(Scene *scene)
s = stats->infostr;
ofs = 0;
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", versionstr);
+ if (object_mode == OB_MODE_OBJECT) {
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", BKE_collection_ui_name_get(layer_collection->collection));
+ }
+
+ if (ob) {
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", ob->id.name + 2);
+ }
- if (scene->obedit) {
- if (BKE_keyblock_from_object(scene->obedit))
+ if (obedit) {
+ if (BKE_keyblock_from_object(obedit))
ofs += BLI_strncpy_rlen(s + ofs, IFACE_("(Key) "), MAX_INFO_LEN - ofs);
- if (scene->obedit->type == OB_MESH) {
+ if (obedit->type == OB_MESH) {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
IFACE_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
stats_fmt.totvertsel, stats_fmt.totvert, stats_fmt.totedgesel, stats_fmt.totedge,
stats_fmt.totfacesel, stats_fmt.totface, stats_fmt.tottri);
}
- else if (scene->obedit->type == OB_ARMATURE) {
+ else if (obedit->type == OB_ARMATURE) {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s | Bones:%s/%s"), stats_fmt.totvertsel,
stats_fmt.totvert, stats_fmt.totbonesel, stats_fmt.totbone);
}
@@ -469,43 +550,51 @@ static void stats_string(Scene *scene)
ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
}
- else if (ob && (ob->mode & OB_MODE_POSE)) {
+ else if (ob && (object_mode & OB_MODE_POSE)) {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s%s"),
stats_fmt.totbonesel, stats_fmt.totbone, memstr, gpumemstr);
}
- else if (stats_is_object_dynamic_topology_sculpt(ob)) {
+ else if ((ob) && (ob->type == OB_GPENCIL)) {
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
+ IFACE_("Layers:%s | Frames:%s | Strokes:%s | Points:%s | Objects:%s/%s"),
+ stats_fmt.totgplayer, stats_fmt.totgpframe, stats_fmt.totgpstroke,
+ stats_fmt.totgppoint, stats_fmt.totobjsel, stats_fmt.totobj);
+
+ ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
+ ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
+ }
+ else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s%s"), stats_fmt.totvert,
stats_fmt.tottri, gpumemstr);
}
else {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
- IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s%s"),
+ IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s%s%s"),
stats_fmt.totvert, stats_fmt.totface,
stats_fmt.tottri, stats_fmt.totobjsel,
- stats_fmt.totobj, stats_fmt.totlampsel,
- stats_fmt.totlamp, memstr, gpumemstr);
+ stats_fmt.totobj, memstr, gpumemstr);
}
- if (ob)
- BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", ob->id.name + 2);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", versionstr);
#undef MAX_INFO_MEM_LEN
}
#undef MAX_INFO_LEN
-void ED_info_stats_clear(Scene *scene)
+void ED_info_stats_clear(ViewLayer *view_layer)
{
- if (scene->stats) {
- MEM_freeN(scene->stats);
- scene->stats = NULL;
+ if (view_layer->stats) {
+ MEM_freeN(view_layer->stats);
+ view_layer->stats = NULL;
}
}
-const char *ED_info_stats_string(Scene *scene)
+const char *ED_info_stats_string(Scene *scene, ViewLayer *view_layer)
{
- if (!scene->stats)
- stats_update(scene);
- stats_string(scene);
-
- return scene->stats->infostr;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ if (!view_layer->stats) {
+ stats_update(depsgraph, view_layer);
+ }
+ stats_string(view_layer);
+ return view_layer->stats->infostr;
}
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index 7e3d57f95ed..d2b6d07541e 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -50,6 +50,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+
+#include "RNA_access.h"
#include "UI_resources.h"
#include "UI_interface.h"
@@ -57,10 +60,11 @@
#include "info_intern.h" /* own include */
#include "BLO_readfile.h"
+#include "GPU_framebuffer.h"
/* ******************** default callbacks for info space ***************** */
-static SpaceLink *info_new(const bContext *UNUSED(C))
+static SpaceLink *info_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceInfo *sinfo;
@@ -75,7 +79,7 @@ static SpaceLink *info_new(const bContext *UNUSED(C))
BLI_addtail(&sinfo->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for info");
@@ -154,7 +158,7 @@ static void info_main_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
/* quick way to avoid drawing if not bug enough */
if (ar->winy < 16)
@@ -171,7 +175,7 @@ static void info_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_GRID_CLAMP);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_GRID_CLAMP);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@@ -194,7 +198,7 @@ static void info_operatortypes(void)
/* info_report.c */
WM_operatortype_append(INFO_OT_select_pick);
WM_operatortype_append(INFO_OT_select_all_toggle);
- WM_operatortype_append(INFO_OT_select_border);
+ WM_operatortype_append(INFO_OT_select_box);
WM_operatortype_append(INFO_OT_report_replay);
WM_operatortype_append(INFO_OT_report_delete);
@@ -203,26 +207,8 @@ static void info_operatortypes(void)
static void info_keymap(struct wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Window", 0, 0);
-
- WM_keymap_verify_item(keymap, "INFO_OT_reports_display_update", TIMERREPORT, KM_ANY, KM_ANY, 0);
-
- /* info space */
- keymap = WM_keymap_ensure(keyconf, "Info", SPACE_INFO, 0);
-
-
- /* report selection */
- WM_keymap_add_item(keymap, "INFO_OT_select_pick", SELECTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "INFO_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "INFO_OT_select_border", BKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "INFO_OT_report_replay", RKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "INFO_OT_report_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "INFO_OT_report_delete", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "INFO_OT_report_copy", CKEY, KM_PRESS, KM_CTRL, 0);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "INFO_OT_report_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
+ WM_keymap_ensure(keyconf, "Window", 0, 0);
+ WM_keymap_ensure(keyconf, "Info", SPACE_INFO, 0);
}
/* add handlers, stuff you only do once or on area/region changes */
@@ -236,7 +222,9 @@ static void info_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-static void info_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void info_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
// SpaceInfo *sinfo = sa->spacedata.first;
@@ -251,13 +239,16 @@ static void info_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
}
}
-static void info_header_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void info_header_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
case NC_SCREEN:
- if (ELEM(wmn->data, ND_ANIMPLAY))
+ if (ELEM(wmn->data, ND_LAYER, ND_ANIMPLAY)) {
ED_region_tag_redraw(ar);
+ }
break;
case NC_WM:
if (wmn->data == ND_JOB)
@@ -279,33 +270,20 @@ static void info_header_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegi
}
-static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu)
+static void info_header_region_message_subscribe(
+ const bContext *UNUSED(C),
+ WorkSpace *UNUSED(workspace), Scene *UNUSED(scene),
+ bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar,
+ struct wmMsgBus *mbus)
{
- struct RecentFile *recent;
- uiLayout *layout = menu->layout;
- uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
- if (!BLI_listbase_is_empty(&G.recent_files)) {
- for (recent = G.recent_files.first; (recent); recent = recent->next) {
- const char *file = BLI_path_basename(recent->filepath);
- const int icon = BLO_has_bfile_extension(file) ? ICON_FILE_BLEND : ICON_FILE_BACKUP;
- uiItemStringO(layout, file, icon, "WM_OT_open_mainfile", "filepath", recent->filepath);
- }
- }
- else {
- uiItemL(layout, IFACE_("No Recent Files"), ICON_NONE);
- }
-}
-
-static void recent_files_menu_register(void)
-{
- MenuType *mt;
-
- mt = MEM_callocN(sizeof(MenuType), "spacetype info menu recent files");
- strcpy(mt->idname, "INFO_MT_file_open_recent");
- strcpy(mt->label, N_("Open Recent..."));
- strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- mt->draw = recent_files_menu_draw;
- WM_menutype_add(mt);
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
}
/* only called once, from space/spacetypes.c */
@@ -342,12 +320,11 @@ void ED_spacetype_info(void)
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
art->listener = info_header_listener;
+ art->message_subscribe = info_header_region_message_subscribe;
art->init = info_header_region_init;
art->draw = info_header_region_draw;
BLI_addhead(&st->regiontypes, art);
- recent_files_menu_register();
-
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index 334106ff08d..c94aaf6e861 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -39,6 +39,9 @@
#include "BLI_utildefines.h"
#include "BLI_string_utf8.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
#include "BIF_gl.h"
#include "BKE_text.h"
@@ -79,13 +82,19 @@ static void console_draw_sel(const char *str, const int sel[2], const int xy[2],
const int sta = txt_utf8_offset_to_column(str, max_ii(sel[0], 0));
const int end = txt_utf8_offset_to_column(str, min_ii(sel[1], str_len_draw));
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glColor4ubv(bg_sel);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4ubv(bg_sel);
+ immRecti(pos, xy[0] + (cwidth * sta), xy[1] - 2 + lheight, xy[0] + (cwidth * end), xy[1] - 2);
- glRecti(xy[0] + (cwidth * sta), xy[1] - 2 + lheight, xy[0] + (cwidth * end), xy[1] - 2);
+ immUnbindProgram();
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
}
@@ -182,21 +191,25 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
cdc->sel[1] = str_len - sel_orig[0];
if (bg) {
- glColor3ubv(bg);
- glRecti(0, cdc->xy[1], cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines)));
- }
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glColor3ubv(fg);
+ immUniformColor3ubv(bg);
+ immRecti(pos, 0, cdc->xy[1], cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines)));
+
+ immUnbindProgram();
+ }
/* last part needs no clipping */
BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
+ BLF_color3ubv(cdc->font_id, fg);
BLF_draw_mono(cdc->font_id, s, len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
console_step_sel(cdc, -initial_offset);
- // glColor4ub(255, 0, 0, 96); // debug
+ /* BLF_color3ub(cdc->font_id, 255, 0, 0); // debug */
console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel);
- glColor3ubv(fg);
}
cdc->xy[1] += cdc->lheight;
@@ -210,9 +223,8 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
if (cdc->sel[0] != cdc->sel[1]) {
console_step_sel(cdc, len);
- // glColor4ub(0, 255, 0, 96); // debug
+ /* BLF_color3ub(cdc->font_id, 0, 255, 0); // debug */
console_draw_sel(s, cdc->sel, cdc->xy, len, cdc->cwidth, cdc->lheight, bg_sel);
- glColor3ubv(fg);
}
cdc->xy[1] += cdc->lheight;
@@ -230,12 +242,17 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
else { /* simple, no wrap */
if (bg) {
- glColor3ubv(bg);
- glRecti(0, cdc->xy[1], cdc->winx, cdc->xy[1] + cdc->lheight);
- }
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- glColor3ubv(fg);
+ immUniformColor3ubv(bg);
+ immRecti(pos, 0, cdc->xy[1], cdc->winx, cdc->xy[1] + cdc->lheight);
+
+ immUnbindProgram();
+ }
+ BLF_color3ubv(cdc->font_id, fg);
BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
BLF_draw_mono(cdc->font_id, str, str_len, cdc->cwidth);
@@ -245,7 +262,7 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
isel[0] = str_len - cdc->sel[1];
isel[1] = str_len - cdc->sel[0];
- // glColor4ub(255, 255, 0, 96); // debug
+ /* BLF_color3ub(cdc->font_id, 255, 255, 0); // debug */
console_draw_sel(str, isel, cdc->xy, str_len, cdc->cwidth, cdc->lheight, bg_sel);
console_step_sel(cdc, -(str_len + 1));
}
diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c
deleted file mode 100644
index 40edb9ca095..00000000000
--- a/source/blender/editors/space_logic/logic_buttons.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * ***** 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) 2009 by Blender Foundation
- * All rights reserved.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_logic/logic_buttons.c
- * \ingroup splogic
- */
-
-
-#include <string.h>
-#include <stdio.h>
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_context.h"
-
-#include "ED_screen.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "UI_interface.h"
-#include "UI_view2d.h"
-
-#include "interface_intern.h"
-#include "logic_intern.h"
-
-static int logic_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
-{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = logic_has_buttons_region(sa);
-
- if (ar)
- ED_region_toggle_hidden(C, ar);
-
- return OPERATOR_FINISHED;
-}
-
-void LOGIC_OT_properties(wmOperatorType *ot)
-{
- ot->name = "Properties";
- ot->description = "Toggle the properties region visibility";
- ot->idname = "LOGIC_OT_properties";
-
- ot->exec = logic_properties_toggle_exec;
- ot->poll = ED_operator_logic_active;
-
- /* flags */
- ot->flag = 0;
-}
-
-/* Remove Logic Bricks Connections */
-/* ********************** Cut Link operator ***************** */
-
-#define LINK_RESOL 12
-static int cut_links_intersect(uiLinkLine *line, float mcoords[][2], int tot)
-{
- float coord_array[LINK_RESOL+1][2];
- int i, b;
- rcti rectlink;
-
- rectlink.xmin = (int)BLI_rctf_cent_x(&line->from->rect);
- rectlink.ymin = (int)BLI_rctf_cent_y(&line->from->rect);
- rectlink.xmax = (int)BLI_rctf_cent_x(&line->to->rect);
- rectlink.ymax = (int)BLI_rctf_cent_y(&line->to->rect);
-
- if (ui_link_bezier_points(&rectlink, coord_array, LINK_RESOL)) {
- for (i=0; i<tot-1; i++)
- for (b=0; b<LINK_RESOL-1; b++)
- if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0)
- return 1;
- }
- return 0;
-}
-
-static int cut_links_exec(bContext *C, wmOperator *op)
-{
- ARegion *ar = CTX_wm_region(C);
- float mcoords[256][2];
- int i = 0;
-
- RNA_BEGIN (op->ptr, itemptr, "path")
- {
- float loc[2];
-
- RNA_float_get_array(&itemptr, "loc", loc);
- UI_view2d_region_to_view(&ar->v2d,
- (int)loc[0], (int)loc[1],
- &mcoords[i][0], &mcoords[i][1]);
- i++;
- if (i >= 256) break;
- }
- RNA_END;
-
- if (i>1) {
- uiBlock *block;
- uiLinkLine *line, *nline;
- uiBut *but;
- for (block = ar->uiblocks.first; block; block = block->next) {
- but = block->buttons.first;
- while (but) {
- if (but->type==UI_BTYPE_LINK && but->link) {
- for (line = but->link->lines.first; line; line = nline) {
- nline = line->next;
-
- if (cut_links_intersect(line, mcoords, i)) {
- ui_linkline_remove(line, but);
- }
- }
- }
- but = but->next;
- }
- }
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
-}
-
-void LOGIC_OT_links_cut(wmOperatorType *ot)
-{
- ot->name = "Cut Links";
- ot->idname = "LOGIC_OT_links_cut";
- ot->description = "Remove logic brick connections";
-
- ot->invoke = WM_gesture_lines_invoke;
- ot->modal = WM_gesture_lines_modal;
- ot->exec = cut_links_exec;
- ot->cancel = WM_gesture_lines_cancel;
-
- ot->poll = ED_operator_logic_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- PropertyRNA *prop;
- prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- /* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
-}
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
deleted file mode 100644
index 837e8995cc2..00000000000
--- a/source/blender/editors/space_logic/logic_ops.c
+++ /dev/null
@@ -1,753 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_logic/logic_ops.c
- * \ingroup splogic
- */
-
-#include <stddef.h>
-
-#include "DNA_object_types.h"
-#include "DNA_sensor_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_string_utils.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "BKE_context.h"
-#include "BKE_main.h"
-#include "BKE_sca.h"
-
-#include "ED_logic.h"
-#include "ED_object.h"
-#include "ED_screen.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "UI_view2d.h"
-
-#include "logic_intern.h"
-
-/* ************* Generic Operator Helpers ************* */
-static bool edit_sensor_poll(bContext *C)
-{
- PointerRNA ptr = CTX_data_pointer_get_type(C, "sensor", &RNA_Sensor);
-
- if (ptr.data && ID_IS_LINKED(ptr.id.data)) return 0;
- return 1;
-}
-
-static bool edit_controller_poll(bContext *C)
-{
- PointerRNA ptr = CTX_data_pointer_get_type(C, "controller", &RNA_Controller);
-
- if (ptr.data && ID_IS_LINKED(ptr.id.data)) return 0;
- return 1;
-}
-
-static bool edit_actuator_poll(bContext *C)
-{
- PointerRNA ptr = CTX_data_pointer_get_type(C, "actuator", &RNA_Actuator);
-
- if (ptr.data && ID_IS_LINKED(ptr.id.data)) return 0;
- return 1;
-}
-
-static void edit_sensor_properties(wmOperatorType *ot)
-{
- RNA_def_string(ot->srna, "sensor", NULL, MAX_NAME, "Sensor", "Name of the sensor to edit");
- RNA_def_string(ot->srna, "object", NULL, MAX_NAME, "Object", "Name of the object the sensor belongs to");
-}
-
-static int edit_sensor_invoke_properties(bContext *C, wmOperator *op)
-{
- PointerRNA ptr = CTX_data_pointer_get_type(C, "sensor", &RNA_Sensor);
-
- if (RNA_struct_property_is_set(op->ptr, "sensor") && RNA_struct_property_is_set(op->ptr, "object") )
- return 1;
-
- if (ptr.data) {
- bSensor *sens = ptr.data;
- Object *ob = ptr.id.data;
-
- RNA_string_set(op->ptr, "sensor", sens->name);
- RNA_string_set(op->ptr, "object", ob->id.name + 2);
- return 1;
- }
-
- return 0;
-}
-
-static Object *edit_object_property_get(bContext *C, wmOperator *op)
-{
- char ob_name[MAX_NAME];
- Object *ob;
-
- RNA_string_get(op->ptr, "object", ob_name);
-
- /* if ob_name is valid try to find the object with this name
- * otherwise gets the active object */
- if (*ob_name)
- ob = BLI_findstring(&(CTX_data_main(C)->object), ob_name, offsetof(ID, name) + 2);
- else
- ob = ED_object_active_context(C);
-
- return ob;
-}
-
-static bSensor *edit_sensor_property_get(bContext *C, wmOperator *op, Object **ob)
-{
- char sensor_name[MAX_NAME];
- bSensor *sens;
-
- RNA_string_get(op->ptr, "sensor", sensor_name);
-
- *ob = edit_object_property_get(C, op);
- if (!*ob) return NULL;
-
- sens = BLI_findstring(&((*ob)->sensors), sensor_name, offsetof(bSensor, name));
- return sens;
-}
-
-static void edit_controller_properties(wmOperatorType *ot)
-{
- RNA_def_string(ot->srna, "controller", NULL, MAX_NAME, "Controller", "Name of the controller to edit");
- RNA_def_string(ot->srna, "object", NULL, MAX_NAME, "Object", "Name of the object the controller belongs to");
-}
-
-static int edit_controller_invoke_properties(bContext *C, wmOperator *op)
-{
- PointerRNA ptr = CTX_data_pointer_get_type(C, "controller", &RNA_Controller);
-
- if (RNA_struct_property_is_set(op->ptr, "controller") && RNA_struct_property_is_set(op->ptr, "object") )
- return 1;
-
- if (ptr.data) {
- bController *cont = ptr.data;
- Object *ob = ptr.id.data;
-
- RNA_string_set(op->ptr, "controller", cont->name);
- RNA_string_set(op->ptr, "object", ob->id.name + 2);
- return 1;
- }
-
- return 0;
-}
-
-static bController *edit_controller_property_get(bContext *C, wmOperator *op, Object **ob)
-{
- char controller_name[MAX_NAME];
- bController *cont;
-
- RNA_string_get(op->ptr, "controller", controller_name);
-
- *ob = edit_object_property_get(C, op);
- if (!*ob) return NULL;
-
- cont = BLI_findstring(&((*ob)->controllers), controller_name, offsetof(bController, name));
- return cont;
-}
-
-static void edit_actuator_properties(wmOperatorType *ot)
-{
- RNA_def_string(ot->srna, "actuator", NULL, MAX_NAME, "Actuator", "Name of the actuator to edit");
- RNA_def_string(ot->srna, "object", NULL, MAX_NAME, "Object", "Name of the object the actuator belongs to");
-}
-
-static int edit_actuator_invoke_properties(bContext *C, wmOperator *op)
-{
- PointerRNA ptr = CTX_data_pointer_get_type(C, "actuator", &RNA_Actuator);
-
- if (RNA_struct_property_is_set(op->ptr, "actuator") && RNA_struct_property_is_set(op->ptr, "object") )
- return 1;
-
- if (ptr.data) {
- bActuator *act = ptr.data;
- Object *ob = ptr.id.data;
-
- RNA_string_set(op->ptr, "actuator", act->name);
- RNA_string_set(op->ptr, "object", ob->id.name + 2);
- return 1;
- }
-
- return 0;
-}
-
-static bActuator *edit_actuator_property_get(bContext *C, wmOperator *op, Object **ob)
-{
- char actuator_name[MAX_NAME];
- bActuator *act;
-
- RNA_string_get(op->ptr, "actuator", actuator_name);
-
- *ob = edit_object_property_get(C, op);
- if (!*ob) return NULL;
-
- act = BLI_findstring(&((*ob)->actuators), actuator_name, offsetof(bActuator, name));
- return act;
-}
-
-static int logicbricks_move_property_get(wmOperator *op)
-{
- int type = RNA_enum_get(op->ptr, "direction");
-
- if (type == 1)
- return true;
- else
- return false;
-}
-
-/* ************* Add/Remove Sensor Operator ************* */
-
-static int sensor_remove_exec(bContext *C, wmOperator *op)
-{
- Object *ob = NULL;
- bSensor *sens = edit_sensor_property_get(C, op, &ob);
-
- if (!sens)
- return OPERATOR_CANCELLED;
-
- BLI_remlink(&(ob->sensors), sens);
- free_sensor(sens);
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static int sensor_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- if (edit_sensor_invoke_properties(C, op))
- return sensor_remove_exec(C, op);
- else
- return OPERATOR_CANCELLED;
-}
-
-static void LOGIC_OT_sensor_remove(wmOperatorType *ot)
-{
- ot->name = "Remove Sensor";
- ot->description = "Remove a sensor from the active object";
- ot->idname = "LOGIC_OT_sensor_remove";
-
- ot->invoke = sensor_remove_invoke;
- ot->exec = sensor_remove_exec;
- ot->poll = edit_sensor_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- edit_sensor_properties(ot);
-}
-
-static int sensor_add_exec(bContext *C, wmOperator *op)
-{
- Object *ob;
- bSensor *sens;
- PointerRNA sens_ptr;
- PropertyRNA *prop;
- const char *sens_name;
- char name[MAX_NAME];
- int type = RNA_enum_get(op->ptr, "type");
-
- ob = edit_object_property_get(C, op);
- if (!ob)
- return OPERATOR_CANCELLED;
-
- sens = new_sensor(type);
- BLI_addtail(&(ob->sensors), sens);
-
- /* set the sensor name based on rna type enum */
- RNA_pointer_create((ID *)ob, &RNA_Sensor, sens, &sens_ptr);
- prop = RNA_struct_find_property(&sens_ptr, "type");
-
- RNA_string_get(op->ptr, "name", name);
- if (*name) {
- BLI_strncpy(sens->name, name, sizeof(sens->name));
- }
- else {
- RNA_property_enum_name(C, &sens_ptr, prop, RNA_property_enum_get(&sens_ptr, prop), &sens_name);
- BLI_strncpy(sens->name, sens_name, sizeof(sens->name));
- }
-
- BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
- ob->scaflag |= OB_SHOWSENS;
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void LOGIC_OT_sensor_add(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Add Sensor";
- ot->description = "Add a sensor to the active object";
- ot->idname = "LOGIC_OT_sensor_add";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = sensor_add_exec;
- ot->poll = ED_operator_object_active_editable;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- ot->prop = prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, SENS_ALWAYS, "Type", "Type of sensor to add");
- RNA_def_enum_funcs(prop, rna_Sensor_type_itemf);
- prop = RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the Sensor to add");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_string(ot->srna, "object", NULL, MAX_NAME, "Object", "Name of the Object to add the Sensor to");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/* ************* Add/Remove Controller Operator ************* */
-
-static int controller_remove_exec(bContext *C, wmOperator *op)
-{
- Object *ob = NULL;
- bController *cont = edit_controller_property_get(C, op, &ob);
-
- if (!cont)
- return OPERATOR_CANCELLED;
-
- BLI_remlink(&(ob->controllers), cont);
- unlink_controller(cont);
- free_controller(cont);
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static int controller_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- if (edit_controller_invoke_properties(C, op))
- return controller_remove_exec(C, op);
- else
- return OPERATOR_CANCELLED;
-}
-
-static void LOGIC_OT_controller_remove(wmOperatorType *ot)
-{
- ot->name = "Remove Controller";
- ot->description = "Remove a controller from the active object";
- ot->idname = "LOGIC_OT_controller_remove";
-
- ot->invoke = controller_remove_invoke;
- ot->exec = controller_remove_exec;
- ot->poll = edit_controller_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- edit_controller_properties(ot);
-}
-
-static int controller_add_exec(bContext *C, wmOperator *op)
-{
- Object *ob;
- bController *cont;
- PointerRNA cont_ptr;
- PropertyRNA *prop;
- const char *cont_name;
- int bit;
- char name[MAX_NAME];
- int type = RNA_enum_get(op->ptr, "type");
-
- ob = edit_object_property_get(C, op);
- if (!ob)
- return OPERATOR_CANCELLED;
-
- cont = new_controller(type);
- BLI_addtail(&(ob->controllers), cont);
-
- /* set the controller name based on rna type enum */
- RNA_pointer_create((ID *)ob, &RNA_Controller, cont, &cont_ptr);
- prop = RNA_struct_find_property(&cont_ptr, "type");
-
- RNA_string_get(op->ptr, "name", name);
- if (*name) {
- BLI_strncpy(cont->name, name, sizeof(cont->name));
- }
- else {
- RNA_property_enum_name(C, &cont_ptr, prop, RNA_property_enum_get(&cont_ptr, prop), &cont_name);
- BLI_strncpy(cont->name, cont_name, sizeof(cont->name));
- }
-
- BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));
-
- /* set the controller state mask from the current object state.
- * A controller is always in a single state, so select the lowest bit set
- * from the object state */
- for (bit = 0; bit < OB_MAX_STATES; bit++) {
- if (ob->state & (1 << bit))
- break;
- }
- cont->state_mask = (1 << bit);
- if (cont->state_mask == 0) {
- /* shouldn't happen, object state is never 0 */
- cont->state_mask = 1;
- }
-
- ob->scaflag |= OB_SHOWCONT;
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void LOGIC_OT_controller_add(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Add Controller";
- ot->description = "Add a controller to the active object";
- ot->idname = "LOGIC_OT_controller_add";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = controller_add_exec;
- ot->poll = ED_operator_object_active_editable;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_controller_type_items, CONT_LOGIC_AND, "Type", "Type of controller to add");
- prop = RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the Controller to add");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_string(ot->srna, "object", NULL, MAX_NAME, "Object", "Name of the Object to add the Controller to");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/* ************* Add/Remove Actuator Operator ************* */
-
-static int actuator_remove_exec(bContext *C, wmOperator *op)
-{
- Object *ob = NULL;
- bActuator *act = edit_actuator_property_get(C, op, &ob);
-
- if (!act)
- return OPERATOR_CANCELLED;
-
- BLI_remlink(&(ob->actuators), act);
- unlink_actuator(act);
- free_actuator(act);
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static int actuator_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- if (edit_actuator_invoke_properties(C, op))
- return actuator_remove_exec(C, op);
- else
- return OPERATOR_CANCELLED;
-}
-
-static void LOGIC_OT_actuator_remove(wmOperatorType *ot)
-{
- ot->name = "Remove Actuator";
- ot->description = "Remove an actuator from the active object";
- ot->idname = "LOGIC_OT_actuator_remove";
-
- ot->invoke = actuator_remove_invoke;
- ot->exec = actuator_remove_exec;
- ot->poll = edit_actuator_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- edit_actuator_properties(ot);
-}
-
-static int actuator_add_exec(bContext *C, wmOperator *op)
-{
- Object *ob;
- bActuator *act;
- PointerRNA act_ptr;
- PropertyRNA *prop;
- const char *act_name;
- char name[MAX_NAME];
- int type = RNA_enum_get(op->ptr, "type");
-
- ob = edit_object_property_get(C, op);
- if (!ob)
- return OPERATOR_CANCELLED;
-
- act = new_actuator(type);
- BLI_addtail(&(ob->actuators), act);
-
- /* set the actuator name based on rna type enum */
- RNA_pointer_create((ID *)ob, &RNA_Actuator, act, &act_ptr);
- prop = RNA_struct_find_property(&act_ptr, "type");
-
- RNA_string_get(op->ptr, "name", name);
- if (*name) {
- BLI_strncpy(act->name, name, sizeof(act->name));
- }
- else {
- RNA_property_enum_name(C, &act_ptr, prop, RNA_property_enum_get(&act_ptr, prop), &act_name);
- BLI_strncpy(act->name, act_name, sizeof(act->name));
- }
-
- BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
- ob->scaflag |= OB_SHOWACT;
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void LOGIC_OT_actuator_add(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Add Actuator";
- ot->description = "Add an actuator to the active object";
- ot->idname = "LOGIC_OT_actuator_add";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = actuator_add_exec;
- ot->poll = ED_operator_object_active_editable;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- ot->prop = prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, CONT_LOGIC_AND, "Type", "Type of actuator to add");
- RNA_def_enum_funcs(prop, rna_Actuator_type_itemf);
- prop = RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the Actuator to add");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_string(ot->srna, "object", NULL, MAX_NAME, "Object", "Name of the Object to add the Actuator to");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/* ************* Move Logic Bricks Operator ************* */
-static const EnumPropertyItem logicbricks_move_direction[] = {
- {1, "UP", 0, "Move Up", ""},
- {2, "DOWN", 0, "Move Down", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-
-static int sensor_move_exec(bContext *C, wmOperator *op)
-{
- Object *ob = NULL;
- bSensor *sens = edit_sensor_property_get(C, op, &ob);
- int move_up = logicbricks_move_property_get(op);
-
- if (!sens)
- return OPERATOR_CANCELLED;
-
- sca_move_sensor(sens, ob, move_up);
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static int sensor_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- if (edit_sensor_invoke_properties(C, op)) {
- return sensor_move_exec(C, op);
- }
- else
- return OPERATOR_CANCELLED;
-}
-
-static void LOGIC_OT_sensor_move(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Move Sensor";
- ot->description = "Move Sensor";
- ot->idname = "LOGIC_OT_sensor_move";
-
- /* api callbacks */
- ot->invoke = sensor_move_invoke;
- ot->exec = sensor_move_exec;
- ot->poll = edit_sensor_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- edit_sensor_properties(ot);
- RNA_def_enum(ot->srna, "direction", logicbricks_move_direction, 1, "Direction", "Move Up or Down");
-}
-
-static int controller_move_exec(bContext *C, wmOperator *op)
-{
- Object *ob = NULL;
- bController *cont = edit_controller_property_get(C, op, &ob);
- int move_up = logicbricks_move_property_get(op);
-
- if (!cont)
- return OPERATOR_CANCELLED;
-
- sca_move_controller(cont, ob, move_up);
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static int controller_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- if (edit_controller_invoke_properties(C, op)) {
- return controller_move_exec(C, op);
- }
- else
- return OPERATOR_CANCELLED;
-}
-
-static void LOGIC_OT_controller_move(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Move Controller";
- ot->description = "Move Controller";
- ot->idname = "LOGIC_OT_controller_move";
-
- /* api callbacks */
- ot->invoke = controller_move_invoke;
- ot->exec = controller_move_exec;
- ot->poll = edit_controller_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- edit_controller_properties(ot);
- RNA_def_enum(ot->srna, "direction", logicbricks_move_direction, 1, "Direction", "Move Up or Down");
-}
-
-static int actuator_move_exec(bContext *C, wmOperator *op)
-{
- Object *ob = NULL;
- bActuator *act = edit_actuator_property_get(C, op, &ob);
- int move_up = logicbricks_move_property_get(op);
-
- if (!act)
- return OPERATOR_CANCELLED;
-
- sca_move_actuator(act, ob, move_up);
-
- WM_event_add_notifier(C, NC_LOGIC, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static int actuator_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- if (edit_actuator_invoke_properties(C, op)) {
- return actuator_move_exec(C, op);
- }
- else
- return OPERATOR_CANCELLED;
-}
-
-static void LOGIC_OT_actuator_move(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Move Actuator";
- ot->description = "Move Actuator";
- ot->idname = "LOGIC_OT_actuator_move";
-
- /* api callbacks */
- ot->invoke = actuator_move_invoke;
- ot->exec = actuator_move_exec;
- ot->poll = edit_actuator_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- edit_actuator_properties(ot);
- RNA_def_enum(ot->srna, "direction", logicbricks_move_direction, 1, "Direction", "Move Up or Down");
-}
-
-/* ************************ view ********************* */
-
-static int logic_view_all_exec(bContext *C, wmOperator *op)
-{
- ARegion *ar = CTX_wm_region(C);
- rctf cur_new = ar->v2d.tot;
- float aspect = BLI_rctf_size_y(&ar->v2d.cur) / BLI_rctf_size_x(&ar->v2d.cur);
- const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
-
- /* force the view2d code to zoom to width, not height */
- cur_new.ymin = cur_new.ymax - BLI_rctf_size_x(&cur_new) * aspect;
-
- UI_view2d_smooth_view(C, ar, &cur_new, smooth_viewtx);
-
- return OPERATOR_FINISHED;
-}
-
-static void LOGIC_OT_view_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "View All";
- ot->idname = "LOGIC_OT_view_all";
- ot->description = "Resize view so you can see all logic bricks";
-
- /* api callbacks */
- ot->exec = logic_view_all_exec;
- ot->poll = ED_operator_logic_active;
-
- /* flags */
- ot->flag = 0;
-}
-
-/* ************************* */
-
-void ED_operatortypes_logic(void)
-{
- WM_operatortype_append(LOGIC_OT_sensor_remove);
- WM_operatortype_append(LOGIC_OT_sensor_add);
- WM_operatortype_append(LOGIC_OT_sensor_move);
- WM_operatortype_append(LOGIC_OT_controller_remove);
- WM_operatortype_append(LOGIC_OT_controller_add);
- WM_operatortype_append(LOGIC_OT_controller_move);
- WM_operatortype_append(LOGIC_OT_actuator_remove);
- WM_operatortype_append(LOGIC_OT_actuator_add);
- WM_operatortype_append(LOGIC_OT_actuator_move);
- WM_operatortype_append(LOGIC_OT_view_all);
-}
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
deleted file mode 100644
index a88d82fa05a..00000000000
--- a/source/blender/editors/space_logic/logic_window.c
+++ /dev/null
@@ -1,2600 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_logic/logic_window.c
- * \ingroup splogic
- */
-
-
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <float.h>
-
-#include "DNA_actuator_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_property_types.h"
-#include "DNA_space_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sensor_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_object_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_string_utils.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_action.h"
-#include "BKE_context.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
-#include "BKE_sca.h"
-
-#include "ED_undo.h"
-
-#include "BLT_translation.h"
-
-#include "UI_interface.h"
-#include "UI_view2d.h"
-
-#include "RNA_access.h"
-
-/* XXX BAD BAD */
-#include "../interface/interface_intern.h"
-
-#include "logic_intern.h"
-
-#define B_REDR 1
-
-#define B_ADD_SENS 2703
-#define B_CHANGE_SENS 2704
-#define B_DEL_SENS 2705
-
-#define B_ADD_CONT 2706
-#define B_CHANGE_CONT 2707
-#define B_DEL_CONT 2708
-
-#define B_ADD_ACT 2709
-#define B_CHANGE_ACT 2710
-#define B_DEL_ACT 2711
-
-#define B_SOUNDACT_BROWSE 2712
-
-#define B_SETPROP 2714
-#define B_SETACTOR 2715
-#define B_SETMAINACTOR 2716
-#define B_SETDYNA 2717
-#define B_SET_STATE_BIT 2718
-#define B_INIT_STATE_BIT 2719
-
-/* proto */
-static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisflag);
-
-static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
-{
- Main *bmain= CTX_data_main(C);
- bSensor *sens;
- bController *cont;
- bActuator *act;
- Object *ob;
- int didit, bit;
-
- ob= CTX_data_active_object(C);
- if (ob==NULL) return;
-
- switch (event) {
-
- case B_SETPROP:
- /* check for inconsistent types */
- ob->gameflag &= ~(OB_SECTOR|OB_MAINACTOR|OB_DYNAMIC|OB_ACTOR);
- break;
-
- case B_SETACTOR:
- case B_SETDYNA:
- case B_SETMAINACTOR:
- ob->gameflag &= ~(OB_SECTOR|OB_PROP);
- break;
-
- case B_ADD_SENS:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- if (ob->scaflag & OB_ADDSENS) {
- ob->scaflag &= ~OB_ADDSENS;
- sens= new_sensor(SENS_ALWAYS);
- BLI_addtail(&(ob->sensors), sens);
- BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
- ob->scaflag |= OB_SHOWSENS;
- }
- }
-
- ED_undo_push(C, "Add sensor");
- break;
-
- case B_CHANGE_SENS:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- sens= ob->sensors.first;
- while (sens) {
- if (sens->type != sens->otype) {
- init_sensor(sens);
- sens->otype= sens->type;
- break;
- }
- sens= sens->next;
- }
- }
- break;
-
- case B_DEL_SENS:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- sens= ob->sensors.first;
- while (sens) {
- if (sens->flag & SENS_DEL) {
- BLI_remlink(&(ob->sensors), sens);
- free_sensor(sens);
- break;
- }
- sens= sens->next;
- }
- }
- ED_undo_push(C, "Delete sensor");
- break;
-
- case B_ADD_CONT:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- if (ob->scaflag & OB_ADDCONT) {
- ob->scaflag &= ~OB_ADDCONT;
- cont= new_controller(CONT_LOGIC_AND);
- BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));
- ob->scaflag |= OB_SHOWCONT;
- BLI_addtail(&(ob->controllers), cont);
- /* set the controller state mask from the current object state.
- * A controller is always in a single state, so select the lowest bit set
- * from the object state */
- for (bit=0; bit<32; bit++) {
- if (ob->state & (1<<bit))
- break;
- }
- cont->state_mask = (1<<bit);
- if (cont->state_mask == 0) {
- /* shouldn't happen, object state is never 0 */
- cont->state_mask = 1;
- }
- }
- }
- ED_undo_push(C, "Add controller");
- break;
-
- case B_SET_STATE_BIT:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- if (ob->scaflag & OB_ALLSTATE) {
- ob->scaflag &= ~OB_ALLSTATE;
- ob->state = 0x3FFFFFFF;
- }
- }
- break;
-
- case B_INIT_STATE_BIT:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- if (ob->scaflag & OB_INITSTBIT) {
- ob->scaflag &= ~OB_INITSTBIT;
- ob->state = ob->init_state;
- if (!ob->state)
- ob->state = 1;
- }
- }
- break;
-
- case B_CHANGE_CONT:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- cont= ob->controllers.first;
- while (cont) {
- if (cont->type != cont->otype) {
- init_controller(cont);
- cont->otype= cont->type;
- break;
- }
- cont= cont->next;
- }
- }
- break;
-
-
- case B_DEL_CONT:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- cont= ob->controllers.first;
- while (cont) {
- if (cont->flag & CONT_DEL) {
- BLI_remlink(&(ob->controllers), cont);
- unlink_controller(cont);
- free_controller(cont);
- break;
- }
- cont= cont->next;
- }
- }
- ED_undo_push(C, "Delete controller");
- break;
-
- case B_ADD_ACT:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- if (ob->scaflag & OB_ADDACT) {
- ob->scaflag &= ~OB_ADDACT;
- act= new_actuator(ACT_OBJECT);
- BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
- BLI_addtail(&(ob->actuators), act);
- ob->scaflag |= OB_SHOWACT;
- }
- }
- ED_undo_push(C, "Add actuator");
- break;
-
- case B_CHANGE_ACT:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- act= ob->actuators.first;
- while (act) {
- if (act->type != act->otype) {
- init_actuator(act);
- act->otype= act->type;
- break;
- }
- act= act->next;
- }
- }
- break;
-
- case B_DEL_ACT:
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- act= ob->actuators.first;
- while (act) {
- if (act->flag & ACT_DEL) {
- BLI_remlink(&(ob->actuators), act);
- unlink_actuator(act);
- free_actuator(act);
- break;
- }
- act= act->next;
- }
- }
- ED_undo_push(C, "Delete actuator");
- break;
-
- case B_SOUNDACT_BROWSE:
- /* since we don't know which... */
- didit= 0;
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- act= ob->actuators.first;
- while (act) {
- if (act->type==ACT_SOUND) {
- bSoundActuator *sa= act->data;
- if (sa->sndnr) {
- ID *sound= bmain->sound.first;
- int nr= 1;
-
- if (sa->sndnr == -2) {
-// XXX activate_databrowse((ID *)bmain->sound.first, ID_SO, 0, B_SOUNDACT_BROWSE,
-// &sa->sndnr, do_logic_buts);
- break;
- }
-
- while (sound) {
- if (nr==sa->sndnr)
- break;
- nr++;
- sound= sound->next;
- }
-
- if (sa->sound)
- id_us_min(((ID *)sa->sound));
-
- sa->sound= (struct bSound *)sound;
-
- if (sound) {
- id_us_plus(sound);
- }
-
- sa->sndnr= 0;
- didit= 1;
- }
- }
- act= act->next;
- }
- if (didit)
- break;
- }
-
- break;
- }
-}
-
-
-static const char *sensor_name(int type)
-{
- switch (type) {
- case SENS_ALWAYS:
- return N_("Always");
- case SENS_NEAR:
- return N_("Near");
- case SENS_KEYBOARD:
- return N_("Keyboard");
- case SENS_PROPERTY:
- return N_("Property");
- case SENS_ARMATURE:
- return N_("Armature");
- case SENS_ACTUATOR:
- return N_("Actuator");
- case SENS_DELAY:
- return N_("Delay");
- case SENS_MOUSE:
- return N_("Mouse");
- case SENS_COLLISION:
- return N_("Collision");
- case SENS_RADAR:
- return N_("Radar");
- case SENS_RANDOM:
- return N_("Random");
- case SENS_RAY:
- return N_("Ray");
- case SENS_MESSAGE:
- return N_("Message");
- case SENS_JOYSTICK:
- return N_("Joystick");
- }
- return N_("Unknown");
-}
-
-static const char *controller_name(int type)
-{
- switch (type) {
- case CONT_LOGIC_AND:
- return N_("And");
- case CONT_LOGIC_OR:
- return N_("Or");
- case CONT_LOGIC_NAND:
- return N_("Nand");
- case CONT_LOGIC_NOR:
- return N_("Nor");
- case CONT_LOGIC_XOR:
- return N_("Xor");
- case CONT_LOGIC_XNOR:
- return N_("Xnor");
- case CONT_EXPRESSION:
- return N_("Expression");
- case CONT_PYTHON:
- return N_("Python");
- }
- return N_("Unknown");
-}
-
-static const char *actuator_name(int type)
-{
- switch (type) {
- case ACT_SHAPEACTION:
- return N_("Shape Action");
- case ACT_ACTION:
- return N_("Action");
- case ACT_OBJECT:
- return N_("Motion");
- case ACT_LAMP:
- return N_("Lamp");
- case ACT_CAMERA:
- return N_("Camera");
- case ACT_MATERIAL:
- return N_("Material");
- case ACT_SOUND:
- return N_("Sound");
- case ACT_PROPERTY:
- return N_("Property");
- case ACT_EDIT_OBJECT:
- return N_("Edit Object");
- case ACT_CONSTRAINT:
- return N_("Constraint");
- case ACT_SCENE:
- return N_("Scene");
- case ACT_GROUP:
- return N_("Group");
- case ACT_RANDOM:
- return N_("Random");
- case ACT_MESSAGE:
- return N_("Message");
- case ACT_GAME:
- return N_("Game");
- case ACT_VISIBILITY:
- return N_("Visibility");
- case ACT_2DFILTER:
- return N_("Filter 2D");
- case ACT_PARENT:
- return N_("Parent");
- case ACT_STATE:
- return N_("State");
- case ACT_ARMATURE:
- return N_("Armature");
- case ACT_STEERING:
- return N_("Steering");
- case ACT_MOUSE:
- return N_("Mouse");
- }
- return N_("Unknown");
-}
-
-static void set_sca_ob(Object *ob)
-{
- bController *cont;
- bActuator *act;
-
- cont= ob->controllers.first;
- while (cont) {
- cont->mynew= (bController *)ob;
- cont= cont->next;
- }
- act= ob->actuators.first;
- while (act) {
- act->mynew= (bActuator *)ob;
- act= act->next;
- }
-}
-
-static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisflag)
-{
- Base *base;
- Main *bmain= CTX_data_main(C);
- Scene *scene= CTX_data_scene(C);
- Object *ob, *obt, *obact= CTX_data_active_object(C);
- ID **idar;
- bSensor *sens;
- bController *cont;
- unsigned int lay;
- int a, nr, do_it;
-
- /* we need a sorted object list */
- /* set scavisflags flags in Objects to indicate these should be evaluated */
- /* also hide ob pointers in ->new entries of controllerss/actuators */
-
- *count= 0;
-
- if (scene==NULL) return NULL;
-
- ob= bmain->object.first;
- while (ob) {
- ob->scavisflag= 0;
- set_sca_ob(ob);
- ob= ob->id.next;
- }
-
- /* XXX here it checked 3d lay */
- lay= scene->lay;
-
- base= FIRSTBASE;
- while (base) {
- if (base->lay & lay) {
- if (base->flag & SELECT) {
- if (scavisflag & BUTS_SENS_SEL) base->object->scavisflag |= OB_VIS_SENS;
- if (scavisflag & BUTS_CONT_SEL) base->object->scavisflag |= OB_VIS_CONT;
- if (scavisflag & BUTS_ACT_SEL) base->object->scavisflag |= OB_VIS_ACT;
- }
- }
- base= base->next;
- }
-
- if (obact) {
- if (scavisflag & BUTS_SENS_ACT) obact->scavisflag |= OB_VIS_SENS;
- if (scavisflag & BUTS_CONT_ACT) obact->scavisflag |= OB_VIS_CONT;
- if (scavisflag & BUTS_ACT_ACT) obact->scavisflag |= OB_VIS_ACT;
- }
-
- /* BUTS_XXX_STATE are similar to BUTS_XXX_LINK for selecting the object */
- if (scavisflag & (BUTS_SENS_LINK|BUTS_CONT_LINK|BUTS_ACT_LINK|BUTS_SENS_STATE|BUTS_ACT_STATE)) {
- do_it = true;
- while (do_it) {
- do_it = false;
-
- ob= bmain->object.first;
- while (ob) {
-
- /* 1st case: select sensor when controller selected */
- if ((scavisflag & (BUTS_SENS_LINK|BUTS_SENS_STATE)) && (ob->scavisflag & OB_VIS_SENS)==0) {
- sens= ob->sensors.first;
- while (sens) {
- for (a=0; a<sens->totlinks; a++) {
- if (sens->links[a]) {
- obt= (Object *)sens->links[a]->mynew;
- if (obt && (obt->scavisflag & OB_VIS_CONT)) {
- do_it = true;
- ob->scavisflag |= OB_VIS_SENS;
- break;
- }
- }
- }
- if (do_it) break;
- sens= sens->next;
- }
- }
-
- /* 2nd case: select cont when act selected */
- if ((scavisflag & BUTS_CONT_LINK) && (ob->scavisflag & OB_VIS_CONT)==0) {
- cont= ob->controllers.first;
- while (cont) {
- for (a=0; a<cont->totlinks; a++) {
- if (cont->links[a]) {
- obt= (Object *)cont->links[a]->mynew;
- if (obt && (obt->scavisflag & OB_VIS_ACT)) {
- do_it = true;
- ob->scavisflag |= OB_VIS_CONT;
- break;
- }
- }
- }
- if (do_it) break;
- cont= cont->next;
- }
- }
-
- /* 3rd case: select controller when sensor selected */
- if ((scavisflag & BUTS_CONT_LINK) && (ob->scavisflag & OB_VIS_SENS)) {
- sens= ob->sensors.first;
- while (sens) {
- for (a=0; a<sens->totlinks; a++) {
- if (sens->links[a]) {
- obt= (Object *)sens->links[a]->mynew;
- if (obt && (obt->scavisflag & OB_VIS_CONT)==0) {
- do_it = true;
- obt->scavisflag |= OB_VIS_CONT;
- }
- }
- }
- sens= sens->next;
- }
- }
-
- /* 4th case: select actuator when controller selected */
- if ((scavisflag & (BUTS_ACT_LINK|BUTS_ACT_STATE)) && (ob->scavisflag & OB_VIS_CONT)) {
- cont= ob->controllers.first;
- while (cont) {
- for (a=0; a<cont->totlinks; a++) {
- if (cont->links[a]) {
- obt= (Object *)cont->links[a]->mynew;
- if (obt && (obt->scavisflag & OB_VIS_ACT)==0) {
- do_it = true;
- obt->scavisflag |= OB_VIS_ACT;
- }
- }
- }
- cont= cont->next;
- }
-
- }
- ob= ob->id.next;
- }
- }
- }
-
- /* now we count */
- ob= bmain->object.first;
- while (ob) {
- if ( ob->scavisflag ) (*count)++;
- ob= ob->id.next;
- }
-
- if (*count == 0) return NULL;
- if (*count > 24) *count = 24; /* temporal */
-
- idar= MEM_callocN((*count)*sizeof(void *), "idar");
-
- ob= bmain->object.first;
- nr= 0;
-
- /* make the active object always the first one of the list */
- if (obact) {
- idar[0] = (ID *)obact;
- nr++;
- }
-
- while (ob) {
- if ((ob->scavisflag) && (ob != obact)) {
- idar[nr] = (ID *)ob;
- nr++;
- }
- if (nr >= 24) break;
- ob= ob->id.next;
- }
-
- /* just to be sure... these were set in set_sca_done_ob() */
- clear_sca_new_poins();
-
- return idar;
-}
-
-static void get_armature_bone_constraint(Object *ob, const char *posechannel, const char *constraint_name, bConstraint **constraint)
-{
- /* check that bone exist in the active object */
- if (ob->type == OB_ARMATURE && ob->pose) {
- bPoseChannel *pchan= BKE_pose_channel_find_name(ob->pose, posechannel);
- if (pchan) {
- bConstraint *con= BLI_findstring(&pchan->constraints, constraint_name, offsetof(bConstraint, name));
- if (con) {
- *constraint= con;
- }
- }
- }
- /* didn't find any */
-}
-
-static void do_sensor_menu(bContext *C, void *UNUSED(arg), int event)
-{
- SpaceLogic *slogic= CTX_wm_space_logic(C);
- ID **idar;
- Object *ob;
- bSensor *sens;
- short count, a;
-
- idar= get_selected_and_linked_obs(C, &count, slogic->scaflag);
-
- for (a=0; a<count; a++) {
- ob= (Object *)idar[a];
- if (event==0 || event==2) ob->scaflag |= OB_SHOWSENS;
- else if (event==1) ob->scaflag &= ~OB_SHOWSENS;
- }
-
- for (a=0; a<count; a++) {
- ob= (Object *)idar[a];
- sens= ob->sensors.first;
- while (sens) {
- if (event==2) sens->flag |= SENS_SHOW;
- else if (event==3) sens->flag &= ~SENS_SHOW;
- sens= sens->next;
- }
- }
-
- if (idar) MEM_freeN(idar);
-}
-
-static uiBlock *sensor_menu(bContext *C, ARegion *ar, void *UNUSED(arg))
-{
- uiBlock *block;
- int yco=0;
-
- block= UI_block_begin(C, ar, __func__, UI_EMBOSS_PULLDOWN);
- UI_block_func_butmenu_set(block, do_sensor_menu, NULL);
-
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
- uiDefBut(block, UI_BTYPE_SEPR_LINE, 0, "", 0, (short)(yco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Sensors"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Sensors"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 3, "");
-
- UI_block_direction_set(block, UI_DIR_UP);
- UI_block_end(C, block);
-
- return block;
-}
-
-static void do_controller_menu(bContext *C, void *UNUSED(arg), int event)
-{
- SpaceLogic *slogic= CTX_wm_space_logic(C);
- ID **idar;
- Object *ob;
- bController *cont;
- short count, a;
-
- idar= get_selected_and_linked_obs(C, &count, slogic->scaflag);
-
- for (a=0; a<count; a++) {
- ob= (Object *)idar[a];
- if (event==0 || event==2) ob->scaflag |= OB_SHOWCONT;
- else if (event==1) ob->scaflag &= ~OB_SHOWCONT;
- }
-
- for (a=0; a<count; a++) {
- ob= (Object *)idar[a];
- cont= ob->controllers.first;
- while (cont) {
- if (event==2) cont->flag |= CONT_SHOW;
- else if (event==3) cont->flag &= ~CONT_SHOW;
- cont= cont->next;
- }
- }
-
- if (idar) MEM_freeN(idar);
-}
-
-static uiBlock *controller_menu(bContext *C, ARegion *ar, void *UNUSED(arg))
-{
- uiBlock *block;
- int yco=0;
-
- block= UI_block_begin(C, ar, __func__, UI_EMBOSS_PULLDOWN);
- UI_block_func_butmenu_set(block, do_controller_menu, NULL);
-
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Objects"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
- uiDefBut(block, UI_BTYPE_SEPR_LINE, 0, "", 0, (short)(yco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Controllers"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 2, 2, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Controllers"), 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 3, 3, "");
-
- UI_block_direction_set(block, UI_DIR_UP);
- UI_block_end(C, block);
-
- return block;
-}
-
-static void do_actuator_menu(bContext *C, void *UNUSED(arg), int event)
-{
- SpaceLogic *slogic= CTX_wm_space_logic(C);
- ID **idar;
- Object *ob;
- bActuator *act;
- short count, a;
-
- idar= get_selected_and_linked_obs(C, &count, slogic->scaflag);
-
- for (a=0; a<count; a++) {
- ob= (Object *)idar[a];
- if (event==0 || event==2) ob->scaflag |= OB_SHOWACT;
- else if (event==1) ob->scaflag &= ~OB_SHOWACT;
- }
-
- for (a=0; a<count; a++) {
- ob= (Object *)idar[a];
- act= ob->actuators.first;
- while (act) {
- if (event==2) act->flag |= ACT_SHOW;
- else if (event==3) act->flag &= ~ACT_SHOW;
- act= act->next;
- }
- }
-
- if (idar) MEM_freeN(idar);
-}
-
-static uiBlock *actuator_menu(bContext *C, ARegion *ar, void *UNUSED(arg))
-{
- uiBlock *block;
- int xco=0;
-
- block= UI_block_begin(C, ar, __func__, UI_EMBOSS_PULLDOWN);
- UI_block_func_butmenu_set(block, do_actuator_menu, NULL);
-
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Objects"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Objects"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
- uiDefBut(block, UI_BTYPE_SEPR_LINE, 0, "", 0, (short)(xco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Show Actuators"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
- uiDefBut(block, UI_BTYPE_BUT_MENU, 1, IFACE_("Hide Actuators"), 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 3, "");
-
- UI_block_direction_set(block, UI_DIR_UP);
- UI_block_end(C, block);
-
- return block;
-}
-
-static void check_controller_state_mask(bContext *UNUSED(C), void *arg1_but, void *arg2_mask)
-{
- unsigned int *cont_mask = arg2_mask;
- uiBut *but = arg1_but;
-
- /* a controller is always in a single state */
- *cont_mask = (1<<but->retval);
- but->retval = B_REDR;
-}
-
-static uiBlock *controller_state_mask_menu(bContext *C, ARegion *ar, void *arg_cont)
-{
- uiBlock *block;
- uiBut *but;
- bController *cont = arg_cont;
-
- short yco = 12, xco = 0, stbit, offset;
-
- block= UI_block_begin(C, ar, __func__, UI_EMBOSS);
-
- /* use this for a fake extra empy space around the buttons */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", -5, -5, 200, 34, NULL, 0, 0, 0, 0, "");
-
- for (offset=0; offset<15; offset += 5) {
- UI_block_align_begin(block);
- for (stbit=0; stbit<5; stbit++) {
- but = uiDefButBitI(block, UI_BTYPE_TOGGLE, (1<<(stbit+offset)), (stbit+offset), "", (short)(xco+12*stbit+13*offset), yco, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, "");
- UI_but_func_set(but, check_controller_state_mask, but, &(cont->state_mask));
- }
- for (stbit=0; stbit<5; stbit++) {
- but = uiDefButBitI(block, UI_BTYPE_TOGGLE, (1<<(stbit+offset+15)), (stbit+offset+15), "", (short)(xco+12*stbit+13*offset), yco-12, 12, 12, (int *)&(cont->state_mask), 0, 0, 0, 0, "");
- UI_but_func_set(but, check_controller_state_mask, but, &(cont->state_mask));
- }
- }
- UI_block_align_end(block);
-
- UI_block_direction_set(block, UI_DIR_UP);
- UI_block_end(C, block);
-
- return block;
-}
-
-static bool is_sensor_linked(uiBlock *block, bSensor *sens)
-{
- bController *cont;
- int i;
-
- for (i=0; i<sens->totlinks; i++) {
- cont = sens->links[i];
- if (UI_block_links_find_inlink(block, cont) != NULL)
- return 1;
- }
- return 0;
-}
-
-/* Sensors code */
-
-static void draw_sensor_header(uiLayout *layout, PointerRNA *ptr, PointerRNA *logic_ptr)
-{
- uiLayout *box, *row, *sub;
- bSensor *sens= (bSensor *)ptr->data;
-
- box = uiLayoutBox(layout);
- row = uiLayoutRow(box, false);
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemR(sub, ptr, "show_expanded", UI_ITEM_R_NO_BG, "", ICON_NONE);
- if (RNA_boolean_get(ptr, "show_expanded")) {
- uiItemR(sub, ptr, "type", 0, "", ICON_NONE);
- uiItemR(sub, ptr, "name", 0, "", ICON_NONE);
- }
- else {
- uiItemL(sub, IFACE_(sensor_name(sens->type)), ICON_NONE);
- uiItemL(sub, sens->name, ICON_NONE);
- }
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, (((RNA_boolean_get(logic_ptr, "show_sensors_active_states") &&
- RNA_boolean_get(ptr, "show_expanded")) || RNA_boolean_get(ptr, "pin")) &&
- RNA_boolean_get(ptr, "active")));
- uiItemR(sub, ptr, "pin", UI_ITEM_R_NO_BG, "", ICON_NONE);
-
- if (RNA_boolean_get(ptr, "show_expanded")==0) {
- sub = uiLayoutRow(row, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemEnumO(sub, "LOGIC_OT_sensor_move", "", ICON_TRIA_UP, "direction", 1); // up
- uiItemEnumO(sub, "LOGIC_OT_sensor_move", "", ICON_TRIA_DOWN, "direction", 2); // down
- }
-
- sub = uiLayoutRow(row, false);
- uiItemR(sub, ptr, "active", 0, "", ICON_NONE);
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemO(sub, "", ICON_X, "LOGIC_OT_sensor_remove");
-}
-
-static void draw_sensor_internal_header(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *box, *split, *sub, *row;
-
- box = uiLayoutBox(layout);
- uiLayoutSetActive(box, RNA_boolean_get(ptr, "active"));
- split = uiLayoutSplit(box, 0.45f, false);
-
- row = uiLayoutRow(split, true);
- uiItemR(row, ptr, "use_pulse_true_level", 0, "", ICON_DOTSUP);
- uiItemR(row, ptr, "use_pulse_false_level", 0, "", ICON_DOTSDOWN);
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, (RNA_boolean_get(ptr, "use_pulse_true_level") ||
- RNA_boolean_get(ptr, "use_pulse_false_level")));
- uiItemR(sub, ptr, "tick_skip", 0, IFACE_("Skip"), ICON_NONE);
-
- row = uiLayoutRow(split, true);
- uiItemR(row, ptr, "use_level", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_tap", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- uiItemR(split, ptr, "invert", UI_ITEM_R_TOGGLE, IFACE_("Invert"), ICON_NONE);
-}
-/* sensors in alphabetical order */
-
-static void draw_sensor_actuator(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- PointerRNA settings_ptr;
-
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
- uiItemPointerR(layout, ptr, "actuator", &settings_ptr, "actuators", NULL, ICON_LOGIC);
-}
-
-static void draw_sensor_armature(uiLayout *layout, PointerRNA *ptr)
-{
- bSensor *sens = (bSensor *)ptr->data;
- bArmatureSensor *as = (bArmatureSensor *) sens->data;
- Object *ob = (Object *)ptr->id.data;
- uiLayout *row;
-
- if (ob->type != OB_ARMATURE) {
- uiItemL(layout, IFACE_("Sensor only available for armatures"), ICON_NONE);
- return;
- }
-
- if (ob->pose) {
- PointerRNA pose_ptr, pchan_ptr;
- PropertyRNA *bones_prop;
-
- RNA_pointer_create((ID *)ob, &RNA_Pose, ob->pose, &pose_ptr);
- bones_prop = RNA_struct_find_property(&pose_ptr, "bones");
-
- uiItemPointerR(layout, ptr, "bone", &pose_ptr, "bones", NULL, ICON_BONE_DATA);
-
- if (RNA_property_collection_lookup_string(&pose_ptr, bones_prop, as->posechannel, &pchan_ptr))
- uiItemPointerR(layout, ptr, "constraint", &pchan_ptr, "constraints", NULL, ICON_CONSTRAINT_BONE);
- }
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "test_type", 0, NULL, ICON_NONE);
- if (RNA_enum_get(ptr, "test_type") != SENS_ARM_STATE_CHANGED)
- uiItemR(row, ptr, "value", 0, NULL, ICON_NONE);
-}
-
-static void draw_sensor_collision(uiLayout *layout, PointerRNA *ptr, bContext *C)
-{
- uiLayout *row, *split;
- PointerRNA main_ptr;
-
- RNA_main_pointer_create(CTX_data_main(C), &main_ptr);
-
- split = uiLayoutSplit(layout, 0.3f, false);
- row = uiLayoutRow(split, true);
- uiItemR(row, ptr, "use_pulse", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_material", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- switch (RNA_enum_get(ptr, "use_material")) {
- case SENS_COLLISION_PROPERTY:
- uiItemR(split, ptr, "property", 0, NULL, ICON_NONE);
- break;
- case SENS_COLLISION_MATERIAL:
- uiItemPointerR(split, ptr, "material", &main_ptr, "materials", NULL, ICON_MATERIAL_DATA);
- break;
- }
-}
-
-static void draw_sensor_delay(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
-
- uiItemR(row, ptr, "delay", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "duration", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_repeat", 0, NULL, ICON_NONE);
-}
-
-static void draw_sensor_joystick(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *col, *row;
-
- uiItemR(layout, ptr, "joystick_index", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "event_type", 0, NULL, ICON_NONE);
-
- switch (RNA_enum_get(ptr, "event_type")) {
- case SENS_JOY_BUTTON:
- uiItemR(layout, ptr, "use_all_events", 0, NULL, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_events") == false);
- uiItemR(col, ptr, "button_number", 0, NULL, ICON_NONE);
- break;
- case SENS_JOY_AXIS:
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "axis_number", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "axis_threshold", 0, NULL, ICON_NONE);
-
- uiItemR(layout, ptr, "use_all_events", 0, NULL, ICON_NONE);
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_events") == false);
- uiItemR(col, ptr, "axis_direction", 0, NULL, ICON_NONE);
- break;
- case SENS_JOY_HAT:
- uiItemR(layout, ptr, "hat_number", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_all_events", 0, NULL, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_events") == false);
- uiItemR(col, ptr, "hat_direction", 0, NULL, ICON_NONE);
- break;
- case SENS_JOY_AXIS_SINGLE:
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "single_axis_number", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "axis_threshold", 0, NULL, ICON_NONE);
- break;
- }
-}
-
-static void draw_sensor_keyboard(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- PointerRNA settings_ptr;
- uiLayout *row, *col;
-
- row = uiLayoutRow(layout, false);
- uiItemL(row, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Key:"), ICON_NONE);
- col = uiLayoutColumn(row, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_keys") == false);
- uiItemR(col, ptr, "key", UI_ITEM_R_EVENT, "", ICON_NONE);
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "use_all_keys", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_keys") == false);
- row = uiLayoutRow(col, false);
- uiItemL(row, IFACE_("First Modifier:"), ICON_NONE);
- uiItemR(row, ptr, "modifier_key_1", UI_ITEM_R_EVENT, "", ICON_NONE);
-
- row = uiLayoutRow(col, false);
- uiItemL(row, IFACE_("Second Modifier:"), ICON_NONE);
- uiItemR(row, ptr, "modifier_key_2", UI_ITEM_R_EVENT, "", ICON_NONE);
-
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
- uiItemPointerR(layout, ptr, "log", &settings_ptr, "properties", NULL, ICON_NONE);
- uiItemPointerR(layout, ptr, "target", &settings_ptr, "properties", NULL, ICON_NONE);
-}
-
-static void draw_sensor_message(uiLayout *layout, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "subject", 0, NULL, ICON_NONE);
-}
-
-static void draw_sensor_mouse(uiLayout *layout, PointerRNA *ptr, bContext *C)
-{
- uiLayout *split, *split2;
- PointerRNA main_ptr;
-
- split = uiLayoutSplit(layout, 0.8f, false);
- uiItemR(split, ptr, "mouse_event", 0, NULL, ICON_NONE);
-
- if (RNA_enum_get(ptr, "mouse_event") == BL_SENS_MOUSE_MOUSEOVER_ANY) {
- uiItemR(split, ptr, "use_pulse", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.3f, false);
- uiItemR(split, ptr, "use_material", 0, "", ICON_NONE);
-
- split2 = uiLayoutSplit(split, 0.7f, false);
- if (RNA_enum_get(ptr, "use_material") == SENS_RAY_PROPERTY) {
- uiItemR(split2, ptr, "property", 0, "", ICON_NONE);
- }
- else {
- RNA_main_pointer_create(CTX_data_main(C), &main_ptr);
- uiItemPointerR(split2, ptr, "material", &main_ptr, "materials", "", ICON_MATERIAL_DATA);
- }
- uiItemR(split2, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- }
-}
-
-static void draw_sensor_near(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row;
-
- uiItemR(layout, ptr, "property", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "distance", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "reset_distance", 0, NULL, ICON_NONE);
-}
-
-static void draw_sensor_property(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- PointerRNA settings_ptr;
-
- uiLayout *row;
- uiItemR(layout, ptr, "evaluation_type", 0, NULL, ICON_NONE);
-
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
- uiItemPointerR(layout, ptr, "property", &settings_ptr, "properties", NULL, ICON_NONE);
-
- switch (RNA_enum_get(ptr, "evaluation_type")) {
- case SENS_PROP_INTERVAL:
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "value_min", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "value_max", 0, NULL, ICON_NONE);
- break;
- case SENS_PROP_EQUAL:
- case SENS_PROP_NEQUAL:
- case SENS_PROP_LESSTHAN:
- case SENS_PROP_GREATERTHAN:
- uiItemR(layout, ptr, "value", 0, NULL, ICON_NONE);
- break;
- case SENS_PROP_CHANGED:
- break;
- }
-}
-
-static void draw_sensor_radar(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row;
-
- uiItemR(layout, ptr, "property", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "axis", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "angle", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "distance", 0, NULL, ICON_NONE);
-}
-
-static void draw_sensor_random(uiLayout *layout, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE);
-}
-
-static void draw_sensor_ray(uiLayout *layout, PointerRNA *ptr, bContext *C)
-{
- uiLayout *split, *row;
- PointerRNA main_ptr;
-
- RNA_main_pointer_create(CTX_data_main(C), &main_ptr);
- split = uiLayoutSplit(layout, 0.3f, false);
- uiItemR(split, ptr, "ray_type", 0, "", ICON_NONE);
- switch (RNA_enum_get(ptr, "ray_type")) {
- case SENS_RAY_PROPERTY:
- uiItemR(split, ptr, "property", 0, "", ICON_NONE);
- break;
- case SENS_RAY_MATERIAL:
- uiItemPointerR(split, ptr, "material", &main_ptr, "materials", "", ICON_MATERIAL_DATA);
- break;
- }
-
- split = uiLayoutSplit(layout, 0.3, false);
- uiItemR(split, ptr, "axis", 0, "", ICON_NONE);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "range", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-}
-
-static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C)
-{
- uiLayout *box;
-
- if (!RNA_boolean_get(ptr, "show_expanded"))
- return;
-
- draw_sensor_internal_header(layout, ptr);
-
- box = uiLayoutBox(layout);
- uiLayoutSetActive(box, RNA_boolean_get(ptr, "active"));
-
- switch (RNA_enum_get(ptr, "type")) {
-
- case SENS_ACTUATOR:
- draw_sensor_actuator(box, ptr);
- break;
- case SENS_ALWAYS:
- break;
- case SENS_ARMATURE:
- draw_sensor_armature(box, ptr);
- break;
- case SENS_COLLISION:
- draw_sensor_collision(box, ptr, C);
- break;
- case SENS_DELAY:
- draw_sensor_delay(box, ptr);
- break;
- case SENS_JOYSTICK:
- draw_sensor_joystick(box, ptr);
- break;
- case SENS_KEYBOARD:
- draw_sensor_keyboard(box, ptr);
- break;
- case SENS_MESSAGE:
- draw_sensor_message(box, ptr);
- break;
- case SENS_MOUSE:
- draw_sensor_mouse(box, ptr, C);
- break;
- case SENS_NEAR:
- draw_sensor_near(box, ptr);
- break;
- case SENS_PROPERTY:
- draw_sensor_property(box, ptr);
- break;
- case SENS_RADAR:
- draw_sensor_radar(box, ptr);
- break;
- case SENS_RANDOM:
- draw_sensor_random(box, ptr);
- break;
- case SENS_RAY:
- draw_sensor_ray(box, ptr, C);
- break;
- }
-}
-
-/* Controller code */
-static void draw_controller_header(uiLayout *layout, PointerRNA *ptr, int xco, int width, int yco)
-{
- uiLayout *box, *row, *sub;
- bController *cont= (bController *)ptr->data;
-
- char state[3];
- BLI_snprintf(state, sizeof(state), "%d", RNA_int_get(ptr, "states"));
-
- box = uiLayoutBox(layout);
- row = uiLayoutRow(box, false);
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemR(sub, ptr, "show_expanded", UI_ITEM_R_NO_BG, "", ICON_NONE);
- if (RNA_boolean_get(ptr, "show_expanded")) {
- uiItemR(sub, ptr, "type", 0, "", ICON_NONE);
- uiItemR(sub, ptr, "name", 0, "", ICON_NONE);
- /* XXX provisory for Blender 2.50Beta */
- uiDefBlockBut(uiLayoutGetBlock(layout), controller_state_mask_menu, cont, state, (short)(xco+width-44), yco, 22+22, UI_UNIT_Y, IFACE_("Set controller state index (from 1 to 30)"));
- }
- else {
- uiItemL(sub, IFACE_(controller_name(cont->type)), ICON_NONE);
- uiItemL(sub, cont->name, ICON_NONE);
- uiItemL(sub, state, ICON_NONE);
- }
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemR(sub, ptr, "use_priority", 0, "", ICON_NONE);
-
- if (RNA_boolean_get(ptr, "show_expanded")==0) {
- sub = uiLayoutRow(row, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemEnumO(sub, "LOGIC_OT_controller_move", "", ICON_TRIA_UP, "direction", 1); // up
- uiItemEnumO(sub, "LOGIC_OT_controller_move", "", ICON_TRIA_DOWN, "direction", 2); // down
- }
-
- sub = uiLayoutRow(row, false);
- uiItemR(sub, ptr, "active", 0, "", ICON_NONE);
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemO(sub, "", ICON_X, "LOGIC_OT_controller_remove");
-}
-
-static void draw_controller_expression(uiLayout *layout, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "expression", 0, "", ICON_NONE);
-}
-
-static void draw_controller_python(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *split, *sub;
-
- split = uiLayoutSplit(layout, 0.3, true);
- uiItemR(split, ptr, "mode", 0, "", ICON_NONE);
- if (RNA_enum_get(ptr, "mode") == CONT_PY_SCRIPT) {
- uiItemR(split, ptr, "text", 0, "", ICON_NONE);
- }
- else {
- sub = uiLayoutSplit(split, 0.8f, false);
- uiItemR(sub, ptr, "module", 0, "", ICON_NONE);
- uiItemR(sub, ptr, "use_debug", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- }
-}
-
-static void draw_controller_state(uiLayout *UNUSED(layout), PointerRNA *UNUSED(ptr))
-{
-
-}
-
-static void draw_brick_controller(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *box;
-
- if (!RNA_boolean_get(ptr, "show_expanded"))
- return;
-
- box = uiLayoutBox(layout);
- uiLayoutSetActive(box, RNA_boolean_get(ptr, "active"));
-
- draw_controller_state(box, ptr);
-
- switch (RNA_enum_get(ptr, "type")) {
- case CONT_LOGIC_AND:
- break;
- case CONT_LOGIC_OR:
- break;
- case CONT_EXPRESSION:
- draw_controller_expression(box, ptr);
- break;
- case CONT_PYTHON:
- draw_controller_python(box, ptr);
- break;
- case CONT_LOGIC_NAND:
- break;
- case CONT_LOGIC_NOR:
- break;
- case CONT_LOGIC_XOR:
- break;
- case CONT_LOGIC_XNOR:
- break;
- }
-}
-
-/* Actuator code */
-static void draw_actuator_header(uiLayout *layout, PointerRNA *ptr, PointerRNA *logic_ptr)
-{
- uiLayout *box, *row, *sub;
- bActuator *act= (bActuator *)ptr->data;
-
- box = uiLayoutBox(layout);
- row = uiLayoutRow(box, false);
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemR(sub, ptr, "show_expanded", UI_ITEM_R_NO_BG, "", ICON_NONE);
- if (RNA_boolean_get(ptr, "show_expanded")) {
- uiItemR(sub, ptr, "type", 0, "", ICON_NONE);
- uiItemR(sub, ptr, "name", 0, "", ICON_NONE);
- }
- else {
- uiItemL(sub, IFACE_(actuator_name(act->type)), ICON_NONE);
- uiItemL(sub, act->name, ICON_NONE);
- }
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, (((RNA_boolean_get(logic_ptr, "show_actuators_active_states") &&
- RNA_boolean_get(ptr, "show_expanded")) || RNA_boolean_get(ptr, "pin")) &&
- RNA_boolean_get(ptr, "active")));
- uiItemR(sub, ptr, "pin", UI_ITEM_R_NO_BG, "", ICON_NONE);
-
- if (RNA_boolean_get(ptr, "show_expanded")==0) {
- sub = uiLayoutRow(row, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemEnumO(sub, "LOGIC_OT_actuator_move", "", ICON_TRIA_UP, "direction", 1); // up
- uiItemEnumO(sub, "LOGIC_OT_actuator_move", "", ICON_TRIA_DOWN, "direction", 2); // down
- }
-
- sub = uiLayoutRow(row, false);
- uiItemR(sub, ptr, "active", 0, "", ICON_NONE);
-
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active"));
- uiItemO(sub, "", ICON_X, "LOGIC_OT_actuator_remove");
-}
-
-static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- PointerRNA settings_ptr;
- uiLayout *row, *sub;
-
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "play_mode", 0, "", ICON_NONE);
-
- sub = uiLayoutRow(row, true);
- uiItemR(sub, ptr, "use_force", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- uiItemR(sub, ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- row = uiLayoutColumn(sub, false);
- uiLayoutSetActive(row, (RNA_boolean_get(ptr, "use_additive") || RNA_boolean_get(ptr, "use_force")));
- uiItemR(row, ptr, "use_local", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "action", 0, "", ICON_NONE);
- uiItemR(row, ptr, "use_continue_last_frame", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- if ((RNA_enum_get(ptr, "play_mode") == ACT_ACTION_FROM_PROP))
- uiItemPointerR(row, ptr, "property", &settings_ptr, "properties", NULL, ICON_NONE);
-
- else {
- uiItemR(row, ptr, "frame_start", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "frame_end", 0, NULL, ICON_NONE);
- }
-
- uiItemR(row, ptr, "apply_to_children", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "frame_blend_in", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "priority", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "layer", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "layer_weight", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "blend_mode", 0, "", ICON_NONE);
-
- uiItemPointerR(layout, ptr, "frame_property", &settings_ptr, "properties", NULL, ICON_NONE);
-
-#ifdef __NLA_ACTION_BY_MOTION_ACTUATOR
- uiItemR(layout, "stride_length", 0, NULL, ICON_NONE);
-#endif
-}
-
-static void draw_actuator_armature(uiLayout *layout, PointerRNA *ptr)
-{
- bActuator *act = (bActuator *)ptr->data;
- bArmatureActuator *aa = (bArmatureActuator *) act->data;
- Object *ob = (Object *)ptr->id.data;
- bConstraint *constraint = NULL;
- PointerRNA pose_ptr, pchan_ptr;
- PropertyRNA *bones_prop = NULL;
-
- if (ob->type != OB_ARMATURE) {
- uiItemL(layout, IFACE_("Actuator only available for armatures"), ICON_NONE);
- return;
- }
-
- if (ob->pose) {
- RNA_pointer_create((ID *)ob, &RNA_Pose, ob->pose, &pose_ptr);
- bones_prop = RNA_struct_find_property(&pose_ptr, "bones");
- }
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
-
- switch (RNA_enum_get(ptr, "mode")) {
- case ACT_ARM_RUN:
- break;
- case ACT_ARM_ENABLE:
- case ACT_ARM_DISABLE:
- if (ob->pose) {
- uiItemPointerR(layout, ptr, "bone", &pose_ptr, "bones", NULL, ICON_BONE_DATA);
-
- if (RNA_property_collection_lookup_string(&pose_ptr, bones_prop, aa->posechannel, &pchan_ptr))
- uiItemPointerR(layout, ptr, "constraint", &pchan_ptr, "constraints", NULL, ICON_CONSTRAINT_BONE);
- }
- break;
- case ACT_ARM_SETTARGET:
- if (ob->pose) {
- uiItemPointerR(layout, ptr, "bone", &pose_ptr, "bones", NULL, ICON_BONE_DATA);
-
- if (RNA_property_collection_lookup_string(&pose_ptr, bones_prop, aa->posechannel, &pchan_ptr))
- uiItemPointerR(layout, ptr, "constraint", &pchan_ptr, "constraints", NULL, ICON_CONSTRAINT_BONE);
- }
-
- uiItemR(layout, ptr, "target", 0, NULL, ICON_NONE);
-
- /* show second target only if the constraint supports it */
- get_armature_bone_constraint(ob, aa->posechannel, aa->constraint, &constraint);
- if (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) {
- uiItemR(layout, ptr, "secondary_target", 0, NULL, ICON_NONE);
- }
- break;
- case ACT_ARM_SETWEIGHT:
- if (ob->pose) {
- uiItemPointerR(layout, ptr, "bone", &pose_ptr, "bones", NULL, ICON_BONE_DATA);
-
- if (RNA_property_collection_lookup_string(&pose_ptr, bones_prop, aa->posechannel, &pchan_ptr))
- uiItemPointerR(layout, ptr, "constraint", &pchan_ptr, "constraints", NULL, ICON_CONSTRAINT_BONE);
- }
-
- uiItemR(layout, ptr, "weight", 0, NULL, ICON_NONE);
- break;
- case ACT_ARM_SETINFLUENCE:
- if (ob->pose) {
- uiItemPointerR(layout, ptr, "bone", &pose_ptr, "bones", NULL, ICON_BONE_DATA);
-
- if (RNA_property_collection_lookup_string(&pose_ptr, bones_prop, aa->posechannel, &pchan_ptr))
- uiItemPointerR(layout, ptr, "constraint", &pchan_ptr, "constraints", NULL, ICON_CONSTRAINT_BONE);
- }
-
- uiItemR(layout, ptr, "influence", 0, NULL, ICON_NONE);
- break;
- }
-}
-
-static void draw_actuator_camera(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row;
- uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "height", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "axis", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "max", 0, NULL, ICON_NONE);
-
- uiItemR(layout, ptr, "damping", 0, NULL, ICON_NONE);
-}
-
-static void draw_actuator_constraint(uiLayout *layout, PointerRNA *ptr, bContext *C)
-{
- uiLayout *row, *col, *sub, *split;
- PointerRNA main_ptr;
-
- RNA_main_pointer_create(CTX_data_main(C), &main_ptr);
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- switch (RNA_enum_get(ptr, "mode")) {
- case ACT_CONST_TYPE_LOC:
- uiItemR(layout, ptr, "limit", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "limit_min", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "limit_max", 0, NULL, ICON_NONE);
-
- uiItemR(layout, ptr, "damping", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- break;
-
- case ACT_CONST_TYPE_DIST:
- split = uiLayoutSplit(layout, 0.8, false);
- uiItemR(split, ptr, "direction", 0, NULL, ICON_NONE);
- row = uiLayoutRow(split, true);
- uiItemR(row, ptr, "use_local", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_normal", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Range:"), ICON_NONE);
- uiItemR(col, ptr, "range", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemR(col, ptr, "use_force_distance", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- sub = uiLayoutColumn(col, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_force_distance") == true);
- uiItemR(sub, ptr, "distance", 0, "", ICON_NONE);
-
- uiItemR(layout, ptr, "damping", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.15f, false);
- uiItemR(split, ptr, "use_material_detect", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- if (RNA_boolean_get(ptr, "use_material_detect"))
- uiItemPointerR(split, ptr, "material", &main_ptr, "materials", NULL, ICON_MATERIAL_DATA);
- else
- uiItemR(split, ptr, "property", 0, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.15, false);
- uiItemR(split, ptr, "use_persistent", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- row = uiLayoutRow(split, true);
- uiItemR(row, ptr, "time", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "damping_rotation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- break;
-
- case ACT_CONST_TYPE_ORI:
- uiItemR(layout, ptr, "direction_axis_pos", 0, NULL, ICON_NONE);
-
- row=uiLayoutRow(layout, true);
- uiItemR(row, ptr, "damping", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "time", 0, NULL, ICON_NONE);
-
- row=uiLayoutRow(layout, false);
- uiItemR(row, ptr, "rotation_max", 0, NULL, ICON_NONE);
-
- row=uiLayoutRow(layout, true);
- uiItemR(row, ptr, "angle_min", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "angle_max", 0, NULL, ICON_NONE);
- break;
-
- case ACT_CONST_TYPE_FH:
- split = uiLayoutSplit(layout, 0.75, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "fh_damping", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-
- uiItemR(row, ptr, "fh_height", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_fh_paralel_axis", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "direction_axis", 0, NULL, ICON_NONE);
- split = uiLayoutSplit(row, 0.9f, false);
- uiItemR(split, ptr, "fh_force", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_fh_normal", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.15, false);
- uiItemR(split, ptr, "use_material_detect", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- if (RNA_boolean_get(ptr, "use_material_detect"))
- uiItemPointerR(split, ptr, "material", &main_ptr, "materials", NULL, ICON_MATERIAL_DATA);
- else
- uiItemR(split, ptr, "property", 0, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.15, false);
- uiItemR(split, ptr, "use_persistent", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "time", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "damping_rotation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- break;
- }
-}
-
-static void draw_actuator_edit_object(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- uiLayout *row, *split, *sub;
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
-
- switch (RNA_enum_get(ptr, "mode")) {
- case ACT_EDOB_ADD_OBJECT:
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "object", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "time", 0, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "linear_velocity", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_linear_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "angular_velocity", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_angular_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- break;
- case ACT_EDOB_END_OBJECT:
- break;
- case ACT_EDOB_REPLACE_MESH:
- if (ob->type != OB_MESH) {
- uiItemL(layout, IFACE_("Mode only available for mesh objects"), ICON_NONE);
- break;
- }
- split = uiLayoutSplit(layout, 0.6, false);
- uiItemR(split, ptr, "mesh", 0, NULL, ICON_NONE);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "use_replace_display_mesh", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_replace_physics_mesh", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- break;
- case ACT_EDOB_TRACK_TO:
- split = uiLayoutSplit(layout, 0.5, false);
- uiItemR(split, ptr, "track_object", 0, NULL, ICON_NONE);
- sub = uiLayoutSplit(split, 0.7f, false);
- uiItemR(sub, ptr, "time", 0, NULL, ICON_NONE);
- uiItemR(sub, ptr, "use_3d_tracking", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "up_axis", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "track_axis", 0, NULL, ICON_NONE);
- break;
- case ACT_EDOB_DYNAMICS:
- if (ob->type != OB_MESH) {
- uiItemL(layout, IFACE_("Mode only available for mesh objects"), ICON_NONE);
- break;
- }
- uiItemR(layout, ptr, "dynamic_operation", 0, NULL, ICON_NONE);
- if (RNA_enum_get(ptr, "dynamic_operation") == ACT_EDOB_SET_MASS)
- uiItemR(layout, ptr, "mass", 0, NULL, ICON_NONE);
- break;
- }
-}
-
-static void draw_actuator_filter_2d(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row, *split;
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- switch (RNA_enum_get(ptr, "mode")) {
- case ACT_2DFILTER_CUSTOMFILTER:
- uiItemR(layout, ptr, "filter_pass", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "glsl_shader", 0, NULL, ICON_NONE);
- break;
- case ACT_2DFILTER_MOTIONBLUR:
- split=uiLayoutSplit(layout, 0.75f, true);
- row = uiLayoutRow(split, false);
- uiLayoutSetActive(row, RNA_boolean_get(ptr, "use_motion_blur") == true);
- uiItemR(row, ptr, "motion_blur_factor", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_motion_blur", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- break;
- default: // all other 2D Filters
- uiItemR(layout, ptr, "filter_pass", 0, NULL, ICON_NONE);
- break;
- }
-}
-
-static void draw_actuator_game(uiLayout *layout, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- if (ELEM(RNA_enum_get(ptr, "mode"), ACT_GAME_LOAD, ACT_GAME_SCREENSHOT))
- uiItemR(layout, ptr, "filename", 0, NULL, ICON_NONE);
-}
-
-static void draw_actuator_message(uiLayout *layout, PointerRNA *ptr, bContext *C)
-{
- Object *ob;
- PointerRNA main_ptr, settings_ptr;
- uiLayout *row;
-
- RNA_main_pointer_create(CTX_data_main(C), &main_ptr);
-
- ob = (Object *)ptr->id.data;
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
-
- uiItemPointerR(layout, ptr, "to_property", &main_ptr, "objects", NULL, ICON_OBJECT_DATA);
- uiItemR(layout, ptr, "subject", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "body_type", 0, NULL, ICON_NONE);
-
- if (RNA_enum_get(ptr, "body_type") == ACT_MESG_MESG)
- uiItemR(row, ptr, "body_message", 0, "", ICON_NONE);
- else // mode == ACT_MESG_PROP
- uiItemPointerR(row, ptr, "body_property", &settings_ptr, "properties", "", ICON_NONE);
-}
-
-static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob;
- PointerRNA settings_ptr;
- uiLayout *split, *row, *col, *sub;
- int physics_type;
-
- ob = (Object *)ptr->id.data;
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
- physics_type = RNA_enum_get(&settings_ptr, "physics_type");
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
-
- switch (RNA_enum_get(ptr, "mode")) {
- case ACT_OBJECT_NORMAL:
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "offset_location", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_location", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "offset_rotation", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_rotation", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- if (ELEM(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) {
- uiItemL(layout, IFACE_("Dynamic Object Settings:"), ICON_NONE);
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "force", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_force", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "torque", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_torque", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "linear_velocity", 0, NULL, ICON_NONE);
- row = uiLayoutRow(split, true);
- uiItemR(row, ptr, "use_local_linear_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_add_linear_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "angular_velocity", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_angular_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- uiItemR(layout, ptr, "damping", 0, NULL, ICON_NONE);
- }
- break;
- case ACT_OBJECT_SERVO:
- uiItemR(layout, ptr, "reference_object", 0, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "linear_velocity", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_linear_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "use_servo_limit_x", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_servo_limit_x") == true);
- uiItemR(sub, ptr, "force_max_x", 0, NULL, ICON_NONE);
- uiItemR(sub, ptr, "force_min_x", 0, NULL, ICON_NONE);
-
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "use_servo_limit_y", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_servo_limit_y") == true);
- uiItemR(sub, ptr, "force_max_y", 0, NULL, ICON_NONE);
- uiItemR(sub, ptr, "force_min_y", 0, NULL, ICON_NONE);
-
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "use_servo_limit_z", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_servo_limit_z") == true);
- uiItemR(sub, ptr, "force_max_z", 0, NULL, ICON_NONE);
- uiItemR(sub, ptr, "force_min_z", 0, NULL, ICON_NONE);
-
- //XXXACTUATOR missing labels from original 2.49 ui (e.g. Servo, Min, Max, Fast)
- //Layout designers willing to help on that, please compare with 2.49 ui
- // (since the old code is going to be deleted ... soon)
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "proportional_coefficient", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "integral_coefficient", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "derivate_coefficient", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- break;
- case ACT_OBJECT_CHARACTER:
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "offset_location", 0, NULL, ICON_NONE);
- row = uiLayoutRow(split, true);
- uiItemR(row, ptr, "use_local_location", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_add_character_location", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- uiItemR(row, ptr, "offset_rotation", 0, NULL, ICON_NONE);
- uiItemR(split, ptr, "use_local_rotation", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
-
- split = uiLayoutSplit(layout, 0.9, false);
- row = uiLayoutRow(split, false);
- split = uiLayoutSplit(row, 0.7, false);
- uiItemL(split, "", ICON_NONE); /*Just use this for some spacing */
- uiItemR(split, ptr, "use_character_jump", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- break;
- }
-}
-
-static void draw_actuator_parent(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row, *sub;
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
-
- if (RNA_enum_get(ptr, "mode") == ACT_PARENT_SET) {
- uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "use_compound", 0, NULL, ICON_NONE);
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_compound") == true);
- uiItemR(sub, ptr, "use_ghost", 0, NULL, ICON_NONE);
- }
-}
-
-static void draw_actuator_property(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- bActuator *act = (bActuator *)ptr->data;
- bPropertyActuator *pa = (bPropertyActuator *) act->data;
- Object *ob_from= pa->ob;
- PointerRNA settings_ptr, obj_settings_ptr;
-
- uiLayout *row, *sub;
-
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- uiItemPointerR(layout, ptr, "property", &settings_ptr, "properties", NULL, ICON_NONE);
-
- switch (RNA_enum_get(ptr, "mode")) {
- case ACT_PROP_TOGGLE:
- case ACT_PROP_LEVEL:
- break;
- case ACT_PROP_ADD:
- uiItemR(layout, ptr, "value", 0, NULL, ICON_NONE);
- break;
- case ACT_PROP_ASSIGN:
- uiItemR(layout, ptr, "value", 0, NULL, ICON_NONE);
- break;
- case ACT_PROP_COPY:
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "object", 0, NULL, ICON_NONE);
- if (ob_from) {
- RNA_pointer_create((ID *)ob_from, &RNA_GameObjectSettings, ob_from, &obj_settings_ptr);
- uiItemPointerR(row, ptr, "object_property", &obj_settings_ptr, "properties", NULL, ICON_NONE);
- }
- else {
- sub = uiLayoutRow(row, false);
- uiLayoutSetActive(sub, false);
- uiItemR(sub, ptr, "object_property", 0, NULL, ICON_NONE);
- }
- break;
- }
-}
-
-static void draw_actuator_random(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob;
- PointerRNA settings_ptr;
- uiLayout *row;
-
- ob = (Object *)ptr->id.data;
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
-
- row = uiLayoutRow(layout, false);
-
- uiItemR(row, ptr, "seed", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "distribution", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemPointerR(row, ptr, "property", &settings_ptr, "properties", NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
-
- switch (RNA_enum_get(ptr, "distribution")) {
- case ACT_RANDOM_BOOL_CONST:
- uiItemR(row, ptr, "use_always_true", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- break;
-
- case ACT_RANDOM_BOOL_UNIFORM:
- uiItemL(row, IFACE_("Choose between true and false, 50% chance each"), ICON_NONE);
- break;
-
- case ACT_RANDOM_BOOL_BERNOUILLI:
- uiItemR(row, ptr, "chance", 0, NULL, ICON_NONE);
- break;
-
- case ACT_RANDOM_INT_CONST:
- uiItemR(row, ptr, "int_value", 0, NULL, ICON_NONE);
- break;
-
- case ACT_RANDOM_INT_UNIFORM:
- uiItemR(row, ptr, "int_min", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "int_max", 0, NULL, ICON_NONE);
- break;
-
- case ACT_RANDOM_INT_POISSON:
- uiItemR(row, ptr, "int_mean", 0, NULL, ICON_NONE);
- break;
-
- case ACT_RANDOM_FLOAT_CONST:
- uiItemR(row, ptr, "float_value", 0, NULL, ICON_NONE);
- break;
-
- case ACT_RANDOM_FLOAT_UNIFORM:
- uiItemR(row, ptr, "float_min", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "float_max", 0, NULL, ICON_NONE);
- break;
-
- case ACT_RANDOM_FLOAT_NORMAL:
- uiItemR(row, ptr, "float_mean", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "standard_derivation", 0, NULL, ICON_NONE);
- break;
-
- case ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL:
- uiItemR(row, ptr, "half_life_time", 0, NULL, ICON_NONE);
- break;
- }
-}
-
-static void draw_actuator_scene(uiLayout *layout, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
-
- switch (RNA_enum_get(ptr, "mode")) {
- case ACT_SCENE_CAMERA:
- uiItemR(layout, ptr, "camera", 0, NULL, ICON_NONE);
- break;
- case ACT_SCENE_RESTART:
- break;
- default: // ACT_SCENE_SET|ACT_SCENE_ADD_FRONT|ACT_SCENE_ADD_BACK|ACT_SCENE_REMOVE|ACT_SCENE_SUSPEND|ACT_SCENE_RESUME
- uiItemR(layout, ptr, "scene", 0, NULL, ICON_NONE);
- break;
- }
-}
-
-static void draw_actuator_shape_action(uiLayout *layout, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- PointerRNA settings_ptr;
- uiLayout *row;
-
- if (ob->type != OB_MESH) {
- uiItemL(layout, IFACE_("Actuator only available for mesh objects"), ICON_NONE);
- return;
- }
-
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", 0, "", ICON_NONE);
- uiItemR(row, ptr, "action", 0, "", ICON_NONE);
- uiItemR(row, ptr, "use_continue_last_frame", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- if ((RNA_enum_get(ptr, "mode") == ACT_ACTION_FROM_PROP))
- uiItemPointerR(row, ptr, "property", &settings_ptr, "properties", NULL, ICON_NONE);
-
- else {
- uiItemR(row, ptr, "frame_start", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "frame_end", 0, NULL, ICON_NONE);
- }
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "frame_blend_in", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "priority", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemPointerR(row, ptr, "frame_property", &settings_ptr, "properties", NULL, ICON_NONE);
-
-#ifdef __NLA_ACTION_BY_MOTION_ACTUATOR
- uiItemR(row, "stride_length", 0, NULL, ICON_NONE);
-#endif
-}
-
-static void draw_actuator_sound(uiLayout *layout, PointerRNA *ptr, bContext *C)
-{
- uiLayout *row, *col;
-
- uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
- if (!RNA_pointer_get(ptr, "sound").data) {
- uiItemL(layout, IFACE_("Select a sound from the list or load a new one"), ICON_NONE);
- return;
- }
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "volume", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "pitch", 0, NULL, ICON_NONE);
-
- uiItemR(layout, ptr, "use_sound_3d", 0, NULL, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_sound_3d") == true);
-
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gain_3d_min", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "gain_3d_max", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "distance_3d_reference", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "distance_3d_max", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "rolloff_factor_3d", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "cone_outer_gain_3d", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "cone_outer_angle_3d", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "cone_inner_angle_3d", 0, NULL, ICON_NONE);
-}
-
-static void draw_actuator_state(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *split;
- Object *ob = (Object *)ptr->id.data;
- PointerRNA settings_ptr;
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
-
- split = uiLayoutSplit(layout, 0.35, false);
- uiItemR(split, ptr, "operation", 0, NULL, ICON_NONE);
-
- uiTemplateLayers(split, ptr, "states", &settings_ptr, "used_states", 0);
-}
-
-static void draw_actuator_visibility(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row;
- row = uiLayoutRow(layout, false);
-
- uiItemR(row, ptr, "use_visible", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "use_occlusion", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "apply_to_children", 0, NULL, ICON_NONE);
-}
-
-static void draw_actuator_steering(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row;
- uiLayout *col;
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "target", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "navmesh", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "distance", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "velocity", 0, NULL, ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "acceleration", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "turn_speed", 0, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "facing", 0, NULL, ICON_NONE);
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "facing_axis", 0, NULL, ICON_NONE);
- if (!RNA_boolean_get(ptr, "facing")) {
- uiLayoutSetActive(col, false);
- }
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "normal_up", 0, NULL, ICON_NONE);
- if (!RNA_pointer_get(ptr, "navmesh").data) {
- uiLayoutSetActive(col, false);
- }
-
- row = uiLayoutRow(layout, false);
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "self_terminated", 0, NULL, ICON_NONE);
- if (RNA_enum_get(ptr, "mode")==ACT_STEERING_PATHFOLLOWING) {
- col = uiLayoutColumn(row, false);
- uiItemR(col, ptr, "update_period", 0, NULL, ICON_NONE);
- }
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "lock_z_velocity", 1, NULL, ICON_NONE);
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "show_visualization", 0, NULL, ICON_NONE);
- if (RNA_enum_get(ptr, "mode") != ACT_STEERING_PATHFOLLOWING) {
- uiLayoutSetActive(row, false);
- }
-}
-
-static void draw_actuator_mouse(uiLayout *layout, PointerRNA *ptr)
-{
- uiLayout *row, *col, *subcol, *split, *subsplit;
-
- uiItemR(layout, ptr, "mode", 0, NULL, 0);
-
- switch (RNA_enum_get(ptr, "mode")) {
- case ACT_MOUSE_VISIBILITY:
- row = uiLayoutRow(layout, 0);
- uiItemR(row, ptr, "visible", UI_ITEM_R_TOGGLE, NULL, 0);
- break;
-
- case ACT_MOUSE_LOOK:
- /* X axis */
- row = uiLayoutRow(layout, 0);
- col = uiLayoutColumn(row, 1);
-
- uiItemR(col, ptr, "use_axis_x", UI_ITEM_R_TOGGLE, NULL, 0);
-
- subcol = uiLayoutColumn(col, 1);
- uiLayoutSetActive(subcol, RNA_boolean_get(ptr, "use_axis_x")==1);
- uiItemR(subcol, ptr, "sensitivity_x", 0, NULL, 0);
- uiItemR(subcol, ptr, "threshold_x", 0, NULL, 0);
-
- uiItemR(subcol, ptr, "min_x", 0, NULL, 0);
- uiItemR(subcol, ptr, "max_x", 0, NULL, 0);
-
- uiItemR(subcol, ptr, "object_axis_x", 0, NULL, 0);
-
- /* Y Axis */
- col = uiLayoutColumn(row, 1);
-
- uiItemR(col, ptr, "use_axis_y", UI_ITEM_R_TOGGLE, NULL, 0);
-
- subcol = uiLayoutColumn(col, 1);
- uiLayoutSetActive(subcol, RNA_boolean_get(ptr, "use_axis_y")==1);
- uiItemR(subcol, ptr, "sensitivity_y", 0, NULL, 0);
- uiItemR(subcol, ptr, "threshold_y", 0, NULL, 0);
-
- uiItemR(subcol, ptr, "min_y", 0, NULL, 0);
- uiItemR(subcol, ptr, "max_y", 0, NULL, 0);
-
- uiItemR(subcol, ptr, "object_axis_y", 0, NULL, 0);
-
- /* Lower options */
- row = uiLayoutRow(layout, 0);
- split = uiLayoutSplit(row, 0.5, 0);
-
- subsplit = uiLayoutSplit(split, 0.5, 1);
- uiLayoutSetActive(subsplit, RNA_boolean_get(ptr, "use_axis_x")==1);
- uiItemR(subsplit, ptr, "local_x", UI_ITEM_R_TOGGLE, NULL, 0);
- uiItemR(subsplit, ptr, "reset_x", UI_ITEM_R_TOGGLE, NULL, 0);
-
- subsplit = uiLayoutSplit(split, 0.5, 1);
- uiLayoutSetActive(subsplit, RNA_boolean_get(ptr, "use_axis_y")==1);
- uiItemR(subsplit, ptr, "local_y", UI_ITEM_R_TOGGLE, NULL, 0);
- uiItemR(subsplit, ptr, "reset_y", UI_ITEM_R_TOGGLE, NULL, 0);
-
- break;
- }
-}
-
-static void draw_brick_actuator(uiLayout *layout, PointerRNA *ptr, bContext *C)
-{
- uiLayout *box;
-
- if (!RNA_boolean_get(ptr, "show_expanded"))
- return;
-
- box = uiLayoutBox(layout);
- uiLayoutSetActive(box, RNA_boolean_get(ptr, "active"));
-
- switch (RNA_enum_get(ptr, "type")) {
- case ACT_ACTION:
- draw_actuator_action(box, ptr);
- break;
- case ACT_ARMATURE:
- draw_actuator_armature(box, ptr);
- break;
- case ACT_CAMERA:
- draw_actuator_camera(box, ptr);
- break;
- case ACT_CONSTRAINT:
- draw_actuator_constraint(box, ptr, C);
- break;
- case ACT_EDIT_OBJECT:
- draw_actuator_edit_object(box, ptr);
- break;
- case ACT_2DFILTER:
- draw_actuator_filter_2d(box, ptr);
- break;
- case ACT_GAME:
- draw_actuator_game(box, ptr);
- break;
- case ACT_MESSAGE:
- draw_actuator_message(box, ptr, C);
- break;
- case ACT_OBJECT:
- draw_actuator_motion(box, ptr);
- break;
- case ACT_PARENT:
- draw_actuator_parent(box, ptr);
- break;
- case ACT_PROPERTY:
- draw_actuator_property(box, ptr);
- break;
- case ACT_RANDOM:
- draw_actuator_random(box, ptr);
- break;
- case ACT_SCENE:
- draw_actuator_scene(box, ptr);
- break;
- case ACT_SHAPEACTION:
- draw_actuator_shape_action(box, ptr);
- break;
- case ACT_SOUND:
- draw_actuator_sound(box, ptr, C);
- break;
- case ACT_STATE:
- draw_actuator_state(box, ptr);
- break;
- case ACT_VISIBILITY:
- draw_actuator_visibility(box, ptr);
- break;
- case ACT_STEERING:
- draw_actuator_steering(box, ptr);
- break;
- case ACT_MOUSE:
- draw_actuator_mouse(box, ptr);
- break;
- }
-}
-
-void logic_buttons(bContext *C, ARegion *ar)
-{
- SpaceLogic *slogic= CTX_wm_space_logic(C);
- Object *ob= CTX_data_active_object(C);
- ID **idar;
- PointerRNA logic_ptr, settings_ptr, object_ptr;
- uiLayout *layout, *row, *box;
- uiBlock *block;
- uiBut *but;
- char uiblockstr[32];
- short a, count;
- int xco, yco, width, height;
-
- if (ob==NULL) return;
-
- RNA_pointer_create(NULL, &RNA_SpaceLogicEditor, slogic, &logic_ptr);
- idar= get_selected_and_linked_obs(C, &count, slogic->scaflag);
-
- BLI_snprintf(uiblockstr, sizeof(uiblockstr), "buttonswin %p", (void *)ar);
- block= UI_block_begin(C, ar, uiblockstr, UI_EMBOSS);
- UI_block_func_handle_set(block, do_logic_buts, NULL);
- UI_block_bounds_set_normal(block, U.widget_unit/2);
-
- /* loop over all objects and set visible/linked flags for the logic bricks */
- for (a=0; a<count; a++) {
- bActuator *act;
- bSensor *sens;
- bController *cont;
- int iact;
- short flag;
-
- ob= (Object *)idar[a];
-
- /* clean ACT_LINKED and ACT_VISIBLE of all potentially visible actuators so that we can determine which is actually linked/visible */
- act = ob->actuators.first;
- while (act) {
- act->flag &= ~(ACT_LINKED|ACT_VISIBLE);
- act = act->next;
- }
- /* same for sensors */
- sens= ob->sensors.first;
- while (sens) {
- sens->flag &= ~(SENS_VISIBLE);
- sens = sens->next;
- }
-
- /* mark the linked and visible actuators */
- cont= ob->controllers.first;
- while (cont) {
- flag = ACT_LINKED;
-
- /* this controller is visible, mark all its actuator */
- if ((ob->scaflag & OB_ALLSTATE) || (ob->state & cont->state_mask))
- flag |= ACT_VISIBLE;
-
- for (iact=0; iact<cont->totlinks; iact++) {
- act = cont->links[iact];
- if (act)
- act->flag |= flag;
- }
- cont = cont->next;
- }
- }
-
- /* ****************** Controllers ****************** */
-
- xco= 21 * U.widget_unit; yco= - U.widget_unit / 2; width= 15 * U.widget_unit;
- layout= UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_style_get());
- row = uiLayoutRow(layout, true);
-
- uiDefBlockBut(block, controller_menu, NULL, IFACE_("Controllers"), xco - U.widget_unit / 2, yco, width, UI_UNIT_Y, ""); /* replace this with uiLayout stuff later */
-
- uiItemR(row, &logic_ptr, "show_controllers_selected_objects", 0, IFACE_("Sel"), ICON_NONE);
- uiItemR(row, &logic_ptr, "show_controllers_active_object", 0, IFACE_("Act"), ICON_NONE);
- uiItemR(row, &logic_ptr, "show_controllers_linked_controller", 0, IFACE_("Link"), ICON_NONE);
-
- for (a=0; a<count; a++) {
- bController *cont;
- PointerRNA ptr;
- uiLayout *split, *subsplit, *col;
-
-
- ob= (Object *)idar[a];
-
- /* only draw the controller common header if "use_visible" */
- if ( (ob->scavisflag & OB_VIS_CONT) == 0) {
- continue;
- }
-
- /* Drawing the Controller Header common to all Selected Objects */
-
- RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr);
-
- split = uiLayoutSplit(layout, 0.05f, false);
- uiItemR(split, &settings_ptr, "show_state_panel", UI_ITEM_R_NO_BG, "", ICON_DISCLOSURE_TRI_RIGHT);
-
- row = uiLayoutRow(split, true);
- uiDefButBitS(block, UI_BTYPE_TOGGLE, OB_SHOWCONT, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide controllers"));
-
- RNA_pointer_create((ID *)ob, &RNA_Object, ob, &object_ptr);
- uiLayoutSetContextPointer(row, "object", &object_ptr);
- uiItemMenuEnumO(row, C, "LOGIC_OT_controller_add", "type", IFACE_("Add Controller"), ICON_NONE);
-
- if (RNA_boolean_get(&settings_ptr, "show_state_panel")) {
-
- box = uiLayoutBox(layout);
- split = uiLayoutSplit(box, 0.2f, false);
-
- col = uiLayoutColumn(split, false);
- uiItemL(col, IFACE_("Visible"), ICON_NONE);
- uiItemL(col, IFACE_("Initial"), ICON_NONE);
-
- subsplit = uiLayoutSplit(split, 0.85f, false);
- col = uiLayoutColumn(subsplit, false);
- row = uiLayoutRow(col, false);
- uiLayoutSetActive(row, RNA_boolean_get(&settings_ptr, "use_all_states") == false);
- uiTemplateGameStates(row, &settings_ptr, "states_visible", &settings_ptr, "used_states", 0);
- row = uiLayoutRow(col, false);
- uiTemplateGameStates(row, &settings_ptr, "states_initial", &settings_ptr, "used_states", 0);
-
- col = uiLayoutColumn(subsplit, false);
- uiItemR(col, &settings_ptr, "use_all_states", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- uiItemR(col, &settings_ptr, "show_debug_state", 0, "", ICON_NONE);
- }
-
- /* End of Drawing the Controller Header common to all Selected Objects */
-
- if ((ob->scaflag & OB_SHOWCONT) == 0) continue;
-
-
- uiItemS(layout);
-
- for (cont= ob->controllers.first; cont; cont=cont->next) {
- RNA_pointer_create((ID *)ob, &RNA_Controller, cont, &ptr);
-
- if (!(ob->scaflag & OB_ALLSTATE) && !(ob->state & cont->state_mask))
- continue;
-
- /* use two nested splits to align inlinks/links properly */
- split = uiLayoutSplit(layout, 0.05f, false);
-
- /* put inlink button to the left */
- col = uiLayoutColumn(split, false);
- uiLayoutSetActive(col, RNA_boolean_get(&ptr, "active"));
- uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_LEFT);
- but = uiDefIconBut(block, UI_BTYPE_INLINK, 0, ICON_INLINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, cont, LINK_CONTROLLER, 0, 0, 0, "");
- if (!RNA_boolean_get(&ptr, "active")) {
- UI_but_flag_enable(but, UI_BUT_SCA_LINK_GREY);
- }
-
- //col = uiLayoutColumn(split, true);
- /* nested split for middle and right columns */
- subsplit = uiLayoutSplit(split, 0.95f, false);
-
- col = uiLayoutColumn(subsplit, true);
- uiLayoutSetContextPointer(col, "controller", &ptr);
-
- /* should make UI template for controller header.. function will do for now */
-// draw_controller_header(col, &ptr);
- draw_controller_header(col, &ptr, xco, width, yco); //provisory for 2.50 beta
-
- /* draw the brick contents */
- draw_brick_controller(col, &ptr);
-
- /* put link button to the right */
- col = uiLayoutColumn(subsplit, false);
- uiLayoutSetActive(col, RNA_boolean_get(&ptr, "active"));
- uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_LEFT);
- but = uiDefIconBut(block, UI_BTYPE_LINK, 0, ICON_LINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- if (!RNA_boolean_get(&ptr, "active")) {
- UI_but_flag_enable(but, UI_BUT_SCA_LINK_GREY);
- }
-
- UI_but_link_set(but, NULL, (void ***)&(cont->links), &cont->totlinks, LINK_CONTROLLER, LINK_ACTUATOR);
-
- }
- }
- UI_block_layout_resolve(block, NULL, &yco); /* stores final height in yco */
- height = yco;
-
- /* ****************** Sensors ****************** */
-
- xco= U.widget_unit / 2; yco= -U.widget_unit / 2; width= 17 * U.widget_unit;
- layout= UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_style_get());
- row = uiLayoutRow(layout, true);
-
- uiDefBlockBut(block, sensor_menu, NULL, IFACE_("Sensors"), xco - U.widget_unit / 2, yco, 15 * U.widget_unit, UI_UNIT_Y, ""); /* replace this with uiLayout stuff later */
-
- uiItemR(row, &logic_ptr, "show_sensors_selected_objects", 0, IFACE_("Sel"), ICON_NONE);
- uiItemR(row, &logic_ptr, "show_sensors_active_object", 0, IFACE_("Act"), ICON_NONE);
- uiItemR(row, &logic_ptr, "show_sensors_linked_controller", 0, IFACE_("Link"), ICON_NONE);
- uiItemR(row, &logic_ptr, "show_sensors_active_states", 0, IFACE_("State"), ICON_NONE);
-
- for (a=0; a<count; a++) {
- bSensor *sens;
- PointerRNA ptr;
-
- ob= (Object *)idar[a];
-
- /* only draw the sensor common header if "use_visible" */
- if ((ob->scavisflag & OB_VIS_SENS) == 0) continue;
-
- row = uiLayoutRow(layout, true);
- uiDefButBitS(block, UI_BTYPE_TOGGLE, OB_SHOWSENS, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide sensors"));
-
- RNA_pointer_create((ID *)ob, &RNA_Object, ob, &object_ptr);
- uiLayoutSetContextPointer(row, "object", &object_ptr);
- uiItemMenuEnumO(row, C, "LOGIC_OT_sensor_add", "type", IFACE_("Add Sensor"), ICON_NONE);
-
- if ((ob->scaflag & OB_SHOWSENS) == 0) continue;
-
- uiItemS(layout);
-
- for (sens= ob->sensors.first; sens; sens=sens->next) {
- RNA_pointer_create((ID *)ob, &RNA_Sensor, sens, &ptr);
-
- if ((ob->scaflag & OB_ALLSTATE) ||
- !(slogic->scaflag & BUTS_SENS_STATE) ||
- (sens->totlinks == 0) || /* always display sensor without links so that is can be edited */
- (sens->flag & SENS_PIN && slogic->scaflag & BUTS_SENS_STATE) || /* states can hide some sensors, pinned sensors ignore the visible state */
- (is_sensor_linked(block, sens))
- )
- { // gotta check if the current state is visible or not
- uiLayout *split, *col;
-
- /* make as visible, for move operator */
- sens->flag |= SENS_VISIBLE;
-
- split = uiLayoutSplit(layout, 0.95f, false);
- col = uiLayoutColumn(split, true);
- uiLayoutSetContextPointer(col, "sensor", &ptr);
-
- /* should make UI template for sensor header.. function will do for now */
- draw_sensor_header(col, &ptr, &logic_ptr);
-
- /* draw the brick contents */
- draw_brick_sensor(col, &ptr, C);
-
- /* put link button to the right */
- col = uiLayoutColumn(split, false);
- uiLayoutSetActive(col, RNA_boolean_get(&ptr, "active"));
- but = uiDefIconBut(block, UI_BTYPE_LINK, 0, ICON_LINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- if (!RNA_boolean_get(&ptr, "active")) {
- UI_but_flag_enable(but, UI_BUT_SCA_LINK_GREY);
- }
-
- /* use old-school uiButtons for links for now */
- UI_but_link_set(but, NULL, (void ***)&sens->links, &sens->totlinks, LINK_SENSOR, LINK_CONTROLLER);
- }
- }
- }
- UI_block_layout_resolve(block, NULL, &yco); /* stores final height in yco */
- height = MIN2(height, yco);
-
- /* ****************** Actuators ****************** */
-
- xco= 40 * U.widget_unit; yco= -U.widget_unit / 2; width= 17 * U.widget_unit;
- layout= UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, xco, yco, width, 20, 0, UI_style_get());
- row = uiLayoutRow(layout, true);
-
- uiDefBlockBut(block, actuator_menu, NULL, IFACE_("Actuators"), xco - U.widget_unit / 2, yco, 15 * U.widget_unit, UI_UNIT_Y, ""); /* replace this with uiLayout stuff later */
-
- uiItemR(row, &logic_ptr, "show_actuators_selected_objects", 0, IFACE_("Sel"), ICON_NONE);
- uiItemR(row, &logic_ptr, "show_actuators_active_object", 0, IFACE_("Act"), ICON_NONE);
- uiItemR(row, &logic_ptr, "show_actuators_linked_controller", 0, IFACE_("Link"), ICON_NONE);
- uiItemR(row, &logic_ptr, "show_actuators_active_states", 0, IFACE_("State"), ICON_NONE);
-
- for (a=0; a<count; a++) {
- bActuator *act;
- PointerRNA ptr;
-
- ob= (Object *)idar[a];
-
- /* only draw the actuator common header if "use_visible" */
- if ((ob->scavisflag & OB_VIS_ACT) == 0) {
- continue;
- }
-
- row = uiLayoutRow(layout, true);
- uiDefButBitS(block, UI_BTYPE_TOGGLE, OB_SHOWACT, B_REDR, ob->id.name + 2, (short)(xco - U.widget_unit / 2), yco, (short)(width - 1.5f * U.widget_unit), UI_UNIT_Y, &ob->scaflag, 0, 31, 0, 0, TIP_("Object name, click to show/hide actuators"));
-
- RNA_pointer_create((ID *)ob, &RNA_Object, ob, &object_ptr);
- uiLayoutSetContextPointer(row, "object", &object_ptr);
- uiItemMenuEnumO(row, C, "LOGIC_OT_actuator_add", "type", IFACE_("Add Actuator"), ICON_NONE);
-
- if ((ob->scaflag & OB_SHOWACT) == 0) continue;
-
- uiItemS(layout);
-
- for (act= ob->actuators.first; act; act=act->next) {
-
- RNA_pointer_create((ID *)ob, &RNA_Actuator, act, &ptr);
-
- if ((ob->scaflag & OB_ALLSTATE) ||
- !(slogic->scaflag & BUTS_ACT_STATE) ||
- !(act->flag & ACT_LINKED) || /* always display actuators without links so that is can be edited */
- (act->flag & ACT_VISIBLE) || /* this actuator has visible connection, display it */
- (act->flag & ACT_PIN && slogic->scaflag & BUTS_ACT_STATE) /* states can hide some sensors, pinned sensors ignore the visible state */
- )
- { // gotta check if the current state is visible or not
- uiLayout *split, *col;
-
- /* make as visible, for move operator */
- act->flag |= ACT_VISIBLE;
-
- split = uiLayoutSplit(layout, 0.05f, false);
-
- /* put inlink button to the left */
- col = uiLayoutColumn(split, false);
- uiLayoutSetActive(col, RNA_boolean_get(&ptr, "active"));
- but = uiDefIconBut(block, UI_BTYPE_INLINK, 0, ICON_INLINK, 0, 0, UI_UNIT_X, UI_UNIT_Y, act, LINK_ACTUATOR, 0, 0, 0, "");
- if (!RNA_boolean_get(&ptr, "active")) {
- UI_but_flag_enable(but, UI_BUT_SCA_LINK_GREY);
- }
-
- col = uiLayoutColumn(split, true);
- uiLayoutSetContextPointer(col, "actuator", &ptr);
-
- /* should make UI template for actuator header.. function will do for now */
- draw_actuator_header(col, &ptr, &logic_ptr);
-
- /* draw the brick contents */
- draw_brick_actuator(col, &ptr, C);
-
- }
- }
- }
- UI_block_layout_resolve(block, NULL, &yco); /* stores final height in yco */
- height = MIN2(height, yco);
-
- UI_view2d_totRect_set(&ar->v2d, 57.5f * U.widget_unit, height - U.widget_unit);
-
- /* set the view */
- UI_view2d_view_ortho(&ar->v2d);
-
- UI_block_links_compose(block);
-
- UI_block_end(C, block);
- UI_block_draw(C, block);
-
- /* restore view matrix */
- UI_view2d_view_restore(C);
-
- if (idar) MEM_freeN(idar);
-}
diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c
deleted file mode 100644
index 6d484b4cb4c..00000000000
--- a/source/blender/editors/space_logic/space_logic.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_logic/space_logic.c
- * \ingroup splogic
- */
-
-
-#include <string.h>
-#include <stdio.h>
-
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_gpencil_types.h"
-
-#include "BKE_context.h"
-#include "BKE_library.h"
-#include "BKE_screen.h"
-
-#include "ED_space_api.h"
-#include "ED_screen.h"
-
-#include "BIF_gl.h"
-
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "UI_resources.h"
-#include "UI_view2d.h"
-
-#include "logic_intern.h"
-
-/* ******************** manage regions ********************* */
-
-ARegion *logic_has_buttons_region(ScrArea *sa)
-{
- ARegion *ar, *arnew;
-
- ar = BKE_area_find_region_type(sa, RGN_TYPE_UI);
- if (ar) return ar;
-
- /* add subdiv level; after header */
- ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
-
- /* is error! */
- if (ar == NULL) return NULL;
-
- arnew= MEM_callocN(sizeof(ARegion), "buttons for image");
-
- BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_UI;
- arnew->alignment = RGN_ALIGN_RIGHT;
-
- arnew->flag = RGN_FLAG_HIDDEN;
-
- return arnew;
-}
-
-/* ******************** default callbacks for image space ***************** */
-
-static SpaceLink *logic_new(const bContext *C)
-{
- ScrArea *sa= CTX_wm_area(C);
- ARegion *ar;
- SpaceLogic *slogic;
-
- slogic= MEM_callocN(sizeof(SpaceLogic), "initlogic");
- slogic->spacetype= SPACE_LOGIC;
-
- /* default options */
- slogic->scaflag = ((BUTS_SENS_SEL|BUTS_SENS_ACT|BUTS_SENS_LINK) |
- (BUTS_CONT_SEL|BUTS_CONT_ACT|BUTS_CONT_LINK) |
- (BUTS_ACT_SEL|BUTS_ACT_ACT|BUTS_ACT_LINK) |
- (BUTS_SENS_STATE|BUTS_ACT_STATE));
-
-
- /* header */
- ar= MEM_callocN(sizeof(ARegion), "header for logic");
-
- BLI_addtail(&slogic->regionbase, ar);
- ar->regiontype= RGN_TYPE_HEADER;
- ar->alignment= RGN_ALIGN_BOTTOM;
-
- /* buttons/list view */
- ar= MEM_callocN(sizeof(ARegion), "buttons for logic");
-
- BLI_addtail(&slogic->regionbase, ar);
- ar->regiontype= RGN_TYPE_UI;
- ar->alignment= RGN_ALIGN_RIGHT;
-
- /* main region */
- ar= MEM_callocN(sizeof(ARegion), "main region for logic");
-
- BLI_addtail(&slogic->regionbase, ar);
- ar->regiontype= RGN_TYPE_WINDOW;
-
- ar->v2d.tot.xmin = 0.0f;
- ar->v2d.tot.ymax = 0.0f;
- ar->v2d.tot.xmax = 1150.0f;
- ar->v2d.tot.ymin = ( 1150.0f/(float)sa->winx ) * (float)-sa->winy;
-
- ar->v2d.cur = ar->v2d.tot;
-
- ar->v2d.min[0] = 1.0f;
- ar->v2d.min[1] = 1.0f;
-
- ar->v2d.max[0] = 32000.0f;
- ar->v2d.max[1] = 32000.0f;
-
- ar->v2d.minzoom = 0.5f;
- ar->v2d.maxzoom = 1.5f;
-
- ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
- ar->v2d.keepzoom = V2D_KEEPZOOM | V2D_LIMITZOOM | V2D_KEEPASPECT;
- ar->v2d.keeptot = V2D_KEEPTOT_BOUNDS;
- ar->v2d.align = V2D_ALIGN_NO_POS_Y | V2D_ALIGN_NO_NEG_X;
- ar->v2d.keepofs = V2D_KEEPOFS_Y;
-
- return (SpaceLink *)slogic;
-}
-
-/* not spacelink itself */
-static void logic_free(SpaceLink *UNUSED(sl))
-{
-// Spacelogic *slogic= (SpaceLogic *) sl;
-
-// if (slogic->gpd)
-// XXX BKE_gpencil_free(slogic->gpd);
-
-}
-
-
-/* spacetype; init callback */
-static void logic_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
-{
-
-}
-
-static SpaceLink *logic_duplicate(SpaceLink *sl)
-{
- SpaceLogic *slogicn= MEM_dupallocN(sl);
-
- return (SpaceLink *)slogicn;
-}
-
-static void logic_operatortypes(void)
-{
- WM_operatortype_append(LOGIC_OT_properties);
- WM_operatortype_append(LOGIC_OT_links_cut);
-}
-
-static void logic_keymap(struct wmKeyConfig *keyconf)
-{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Logic Editor", SPACE_LOGIC, 0);
-
- WM_keymap_add_item(keymap, "LOGIC_OT_properties", NKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "LOGIC_OT_links_cut", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_menu(keymap, "LOGIC_MT_logicbricks_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "LOGIC_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "LOGIC_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
-}
-
-static void logic_refresh(const bContext *UNUSED(C), ScrArea *UNUSED(sa))
-{
-// SpaceLogic *slogic= CTX_wm_space_logic(C);
-// Object *obedit= CTX_data_edit_object(C);
-
-}
-
-static void logic_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
-{
- /* context changes */
- switch (wmn->category) {
- case NC_LOGIC:
- ED_region_tag_redraw(ar);
- break;
- case NC_SCENE:
- switch (wmn->data) {
- case ND_FRAME:
- ED_region_tag_redraw(ar);
- break;
-
- case ND_OB_ACTIVE:
- ED_region_tag_redraw(ar);
- break;
- }
- break;
- case NC_OBJECT:
- break;
- case NC_ID:
- if (wmn->action == NA_RENAME)
- ED_region_tag_redraw(ar);
- break;
- }
-}
-
-static int logic_context(const bContext *UNUSED(C), const char *UNUSED(member), bContextDataResult *UNUSED(result))
-{
-// SpaceLogic *slogic= CTX_wm_space_logic(C);
- return 0;
-}
-
-/************************** main region ***************************/
-
-
-/* add handlers, stuff you only do once or on area/region changes */
-static void logic_main_region_init(wmWindowManager *wm, ARegion *ar)
-{
- wmKeyMap *keymap;
-
- UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
-
- /* own keymaps */
- keymap = WM_keymap_ensure(wm->defaultconf, "Logic Editor", SPACE_LOGIC, 0);
- WM_event_add_keymap_handler(&ar->handlers, keymap);
-}
-
-static void logic_main_region_draw(const bContext *C, ARegion *ar)
-{
- /* draw entirely, view changes should be handled here */
-// SpaceLogic *slogic= CTX_wm_space_logic(C);
- View2D *v2d= &ar->v2d;
- View2DScrollers *scrollers;
-
- /* clear and setup matrix */
- UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
-
- UI_view2d_view_ortho(v2d);
-
- logic_buttons((bContext *)C, ar);
-
- /* reset view matrix */
- UI_view2d_view_restore(C);
-
- /* scrollers */
- scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
- UI_view2d_scrollers_draw(C, v2d, scrollers);
- UI_view2d_scrollers_free(scrollers);
-
-}
-
-
-/* *********************** buttons region ************************ */
-
-/* add handlers, stuff you only do once or on area/region changes */
-static void logic_buttons_region_init(wmWindowManager *wm, ARegion *ar)
-{
- wmKeyMap *keymap;
-
- ED_region_panels_init(wm, ar);
-
- keymap = WM_keymap_ensure(wm->defaultconf, "Logic Editor", SPACE_LOGIC, 0);
- WM_event_add_keymap_handler(&ar->handlers, keymap);
-}
-
-static void logic_buttons_region_draw(const bContext *C, ARegion *ar)
-{
- ED_region_panels(C, ar, NULL, -1, true);
-}
-
-/************************* header region **************************/
-
-/* add handlers, stuff you only do once or on area/region changes */
-static void logic_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
-{
- ED_region_header_init(ar);
-}
-
-static void logic_header_region_draw(const bContext *C, ARegion *ar)
-{
- ED_region_header(C, ar);
-}
-
-/**************************** spacetype *****************************/
-
-static void logic_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
-{
- SpaceLogic *slog = (SpaceLogic *)slink;
-
- if (!ELEM(GS(old_id->name), ID_GD)) {
- return;
- }
-
- if ((ID *)slog->gpd == old_id) {
- slog->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
-}
-
-/* only called once, from space/spacetypes.c */
-void ED_spacetype_logic(void)
-{
- SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype logic");
- ARegionType *art;
-
- st->spaceid = SPACE_LOGIC;
- strncpy(st->name, "Logic", BKE_ST_MAXNAME);
-
- st->new = logic_new;
- st->free = logic_free;
- st->init = logic_init;
- st->duplicate = logic_duplicate;
- st->operatortypes = logic_operatortypes;
- st->keymap = logic_keymap;
- st->refresh = logic_refresh;
- st->context = logic_context;
- st->id_remap = logic_id_remap;
-
- /* regions: main window */
- art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
- art->regionid = RGN_TYPE_WINDOW;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES | ED_KEYMAP_VIEW2D;
- art->init = logic_main_region_init;
- art->draw = logic_main_region_draw;
- art->listener = logic_listener;
-
- BLI_addhead(&st->regiontypes, art);
-
- /* regions: listview/buttons */
- art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
- art->regionid = RGN_TYPE_UI;
- art->prefsizex= 220; // XXX
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- art->listener = logic_listener;
- art->init = logic_buttons_region_init;
- art->draw = logic_buttons_region_draw;
- BLI_addhead(&st->regiontypes, art);
-
- /* regions: header */
- art= MEM_callocN(sizeof(ARegionType), "spacetype logic region");
- art->regionid = RGN_TYPE_HEADER;
- art->prefsizey = HEADERY;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->init = logic_header_region_init;
- art->draw = logic_header_region_draw;
-
- BLI_addhead(&st->regiontypes, art);
-
- BKE_spacetype_register(st);
-}
diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt
index c8c64a79945..a6b80a9a587 100644
--- a/source/blender/editors/space_nla/CMakeLists.txt
+++ b/source/blender/editors/space_nla/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 63eb0e361bf..d5d50c86851 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -145,6 +145,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_PALETTE:
{
/* for these channels, we only do AnimData */
if (ale->adt && adt_ptr) {
@@ -276,7 +277,7 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
uiItemL(row, id->name + 2, RNA_struct_ui_icon(id_ptr.type)); /* id-block (src) */
- uiItemL(row, "", VICO_SMALL_TRI_RIGHT_VEC); /* expander */
+ uiItemL(row, "", ICON_SMALL_TRI_RIGHT_VEC); /* expander */
uiItemL(row, IFACE_("Animation Data"), ICON_ANIM_DATA); /* animdata */
uiItemS(layout);
@@ -287,7 +288,7 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
row = uiLayoutRow(layout, true);
uiTemplateID(
row, (bContext *)C, &adt_ptr, "action",
- "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL);
+ "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL, false);
/* extrapolation */
row = uiLayoutRow(layout, true);
@@ -574,7 +575,7 @@ static int nla_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void NLA_OT_properties(wmOperatorType *ot)
{
- ot->name = "Properties";
+ ot->name = "Toggle Sidebar";
ot->idname = "NLA_OT_properties";
ot->description = "Toggle the properties region visibility";
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 103b0664a23..9f634851c81 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -45,6 +45,7 @@
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_report.h"
@@ -59,6 +60,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "UI_view2d.h"
#include "nla_intern.h" // own include
@@ -123,40 +127,37 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
}
case ANIMTYPE_OBJECT:
{
- bDopeSheet *ads = (bDopeSheet *)ac->data;
- Scene *sce = (Scene *)ads->source;
+ ViewLayer *view_layer = ac->view_layer;
Base *base = (Base *)ale->data;
Object *ob = base->object;
AnimData *adt = ob->adt;
- if (nlaedit_is_tweakmode_on(ac) == 0 && (ob->restrictflag & OB_RESTRICT_SELECT) == 0) {
+ if (nlaedit_is_tweakmode_on(ac) == 0 && (base->flag & BASE_SELECTABLE)) {
/* set selection status */
if (selectmode == SELECT_INVERT) {
/* swap select */
- base->flag ^= SELECT;
- ob->flag = base->flag;
+ ED_object_base_select(base, BA_INVERT);
+ BKE_scene_object_base_flag_sync_from_base(base);
if (adt) adt->flag ^= ADT_UI_SELECTED;
}
else {
- Base *b;
-
/* deselect all */
/* TODO: should this deselect all other types of channels too? */
- for (b = sce->base.first; b; b = b->next) {
- b->flag &= ~SELECT;
- b->object->flag = b->flag;
+ for (Base *b = view_layer->object_bases.first; b; b = b->next) {
+ ED_object_base_select(b, BA_DESELECT);
+ BKE_scene_object_base_flag_sync_from_base(b);
if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE);
}
/* select object now */
- base->flag |= SELECT;
- ob->flag |= SELECT;
+ ED_object_base_select(base, BA_SELECT);
+ BKE_scene_object_base_flag_sync_from_base(base);
if (adt) adt->flag |= ADT_UI_SELECTED;
}
/* change active object - regardless of whether it is now selected [T37883] */
- ED_base_object_activate(C, base); /* adds notifier */
+ ED_object_base_activate(C, base); /* adds notifier */
if ((adt) && (adt->flag & ADT_UI_SELECTED))
adt->flag |= ADT_UI_ACTIVE;
@@ -184,6 +185,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
case ANIMTYPE_DSGPENCIL:
+ case ANIMTYPE_PALETTE:
{
/* sanity checking... */
if (ale->adt) {
@@ -236,6 +238,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
/* notifier flags - channel was edited */
notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (x <= ((NLACHANNEL_BUTTON_WIDTH * 2) + offset)) {
/* toggle 'solo' */
@@ -243,6 +246,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
/* notifier flags - channel was edited */
notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
+ ale->update |= ANIM_UPDATE_DEPS;
}
else if (nlaedit_is_tweakmode_on(ac) == 0) {
/* set selection */
@@ -285,6 +289,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
/* changes to NLA-Action occurred */
notifierFlags |= ND_NLA_ACTCHANGE;
+ ale->update |= ANIM_UPDATE_DEPS;
}
/* OR rest of name... */
else {
@@ -302,6 +307,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
/* changes to NLA-Action occurred */
notifierFlags |= ND_NLA_ACTCHANGE;
+ ale->update |= ANIM_UPDATE_DEPS;
}
else {
/* select/deselect */
@@ -331,6 +337,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
}
/* free channels */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* return the notifier-flags set */
@@ -412,6 +419,7 @@ void NLA_OT_channels_click(wmOperatorType *ot)
static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+ ID *id = NULL;
AnimData *adt = NULL;
int channel_index = RNA_int_get(op->ptr, "channel_index");
@@ -430,6 +438,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
+ id = adt_ptr.id.data;
adt = adt_ptr.data;
}
}
@@ -458,6 +467,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
/* grab AnimData from the channel */
adt = ale->adt;
+ id = ale->id;
/* we don't need anything here anymore, so free it all */
ANIM_animdata_freelist(&anim_data);
@@ -480,6 +490,8 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
else {
/* 'push-down' action - only usable when not in TweakMode */
BKE_nla_action_pushdown(adt);
+
+ DEG_id_tag_update_ex(CTX_data_main(C), id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
}
/* set notifier that things have changed */
@@ -598,18 +610,21 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
if (above_sel) {
/* just add a new one above this one */
BKE_nlatrack_add(adt, nlt);
+ ale->update = ANIM_UPDATE_DEPS;
added = true;
}
else if ((lastAdt == NULL) || (adt != lastAdt)) {
/* add one track to the top of the owning AnimData's stack, then don't add anymore to this stack */
BKE_nlatrack_add(adt, NULL);
lastAdt = adt;
+ ale->update = ANIM_UPDATE_DEPS;
added = true;
}
}
}
/* free temp data */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
return added;
@@ -638,11 +653,13 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac)
if (BLI_listbase_is_empty(&adt->nla_tracks)) {
/* add new track to this AnimData block then */
BKE_nlatrack_add(adt, NULL);
+ ale->update = ANIM_UPDATE_DEPS;
added = true;
}
}
/* cleanup */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
return added;
@@ -666,6 +683,8 @@ static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op)
/* done? */
if (op_done) {
+ DEG_relations_tag_update(CTX_data_main(C));
+
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -732,13 +751,17 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
adt->flag &= ~ADT_NLA_SOLO_TRACK;
/* call delete on this track - deletes all strips too */
- BKE_nlatrack_free(&adt->nla_tracks, nlt);
+ BKE_nlatrack_free(&adt->nla_tracks, nlt, true);
+ ale->update = ANIM_UPDATE_DEPS;
}
}
/* free temp data */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
+ DEG_relations_tag_update(ac.bmain);
+
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index ea35c583913..2cba6cf2fb2 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -53,9 +53,13 @@
#include "ED_anim_api.h"
#include "ED_keyframes_draw.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_draw.h"
+#include "GPU_state.h"
+
#include "WM_types.h"
#include "UI_interface.h"
@@ -97,17 +101,12 @@ void nla_action_get_color(AnimData *adt, bAction *act, float color[4])
}
/* draw the keyframes in the specified Action */
-static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d, float y, float ymin, float ymax)
+static void nla_action_draw_keyframes(View2D *v2d, AnimData *adt, bAction *act, float y, float ymin, float ymax)
{
- DLRBT_Tree keys;
- ActKeyColumn *ak;
- float xscale, f1, f2;
- float color[4];
-
/* get a list of the keyframes with NLA-scaling applied */
+ DLRBT_Tree keys;
BLI_dlrbTree_init(&keys);
- action_to_keylist(adt, act, &keys, NULL);
- BLI_dlrbTree_linkedlist_sync(&keys);
+ action_to_keylist(adt, act, &keys, 0);
if (ELEM(NULL, act, keys.first))
return;
@@ -116,30 +115,55 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d,
* - get and reset the background color, this time without the alpha to stand out better
* (amplified alpha is used instead)
*/
+ float color[4];
nla_action_get_color(adt, act, color);
color[3] *= 2.5f;
- glColor4fv(color);
- /* - draw a rect from the first to the last frame (no extra overlaps for now)
- * that is slightly stumpier than the track background (hardcoded 2-units here)
- */
- f1 = ((ActKeyColumn *)keys.first)->cfra;
- f2 = ((ActKeyColumn *)keys.last)->cfra;
-
- glRectf(f1, ymin + 2, f2, ymax - 2);
-
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- /* get View2D scaling factor */
- UI_view2d_scale_get(v2d, &xscale, NULL);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* for now, color is hardcoded to be black */
- glColor3f(0.0f, 0.0f, 0.0f);
+ immUniformColor4fv(color);
- /* just draw each keyframe as a simple dot (regardless of the selection status)
- * - size is 3.0f which is smaller than the editable keyframes, so that there is a distinction
+ /* - draw a rect from the first to the last frame (no extra overlaps for now)
+ * that is slightly stumpier than the track background (hardcoded 2-units here)
*/
- for (ak = keys.first; ak; ak = ak->next)
- draw_keyframe_shape(ak->cfra, y, xscale, 3.0f, 0, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f);
+ float f1 = ((ActKeyColumn *)keys.first)->cfra;
+ float f2 = ((ActKeyColumn *)keys.last)->cfra;
+
+ immRectf(pos_id, f1, ymin + 2, f2, ymax - 2);
+ immUnbindProgram();
+
+ /* count keys before drawing */
+ /* Note: It's safe to cast DLRBT_Tree, as it's designed to degrade down to a ListBase */
+ uint key_len = BLI_listbase_count((ListBase *)&keys);
+
+ if (key_len > 0) {
+ format = immVertexFormat();
+ pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ GPU_enable_program_point_size();
+ immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1);
+ immBegin(GPU_PRIM_POINTS, key_len);
+
+ /* - disregard the selection status of keyframes so they draw a certain way
+ * - size is 6.0f which is smaller than the editable keyframes, so that there is a distinction
+ */
+ for (ActKeyColumn *ak = keys.first; ak; ak = ak->next) {
+ draw_keyframe_shape(ak->cfra, y, 6.0f, false, ak->key_type, KEYFRAME_SHAPE_FRAME, 1.0f,
+ pos_id, size_id, color_id, outline_color_id,
+ flags_id, KEYFRAME_HANDLE_NONE, KEYFRAME_EXTREME_NONE);
+ }
+
+ immEnd();
+ GPU_disable_program_point_size();
+ immUnbindProgram();
+ }
/* free icons */
BLI_dlrbTree_free(&keys);
@@ -148,57 +172,70 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d,
/* Strip Markers ------------------------ */
/* Markers inside an action strip */
-static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
+static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc, int shade, const bool dashed)
{
- bAction *act = strip->act;
- TimeMarker *marker;
+ const bAction *act = strip->act;
- if (ELEM(NULL, strip->act, strip->act->markers.first))
+ if (ELEM(NULL, act, act->markers.first))
return;
- for (marker = act->markers.first; marker; marker = marker->next) {
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ if (dashed) {
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ }
+ immUniformThemeColorShade(TH_STRIP_SELECT, shade);
+
+ immBeginAtMost(GPU_PRIM_LINES, BLI_listbase_count(&act->markers) * 2);
+ for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);
/* just a simple line for now */
- // XXX: draw a triangle instead...
- fdrawline(frame, yminc + 1, frame, ymaxc - 1);
+ /* XXX: draw a triangle instead... */
+ immVertex2f(shdr_pos, frame, yminc + 1);
+ immVertex2f(shdr_pos, frame, ymaxc - 1);
}
}
+ immEnd();
+
+ immUnbindProgram();
}
/* Markers inside a NLA-Strip */
static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
{
- glLineWidth(2.0);
+ GPU_line_width(2.0f);
if (strip->type == NLASTRIP_TYPE_CLIP) {
/* try not to be too conspicuous, while being visible enough when transforming */
- if (strip->flag & NLASTRIP_FLAG_SELECT)
- UI_ThemeColorShade(TH_STRIP_SELECT, -60);
- else
- UI_ThemeColorShade(TH_STRIP_SELECT, -40);
-
- setlinestyle(3);
+ int shade = (strip->flag & NLASTRIP_FLAG_SELECT) ? -60 : -40;
/* just draw the markers in this clip */
- nla_actionclip_draw_markers(strip, yminc, ymaxc);
-
- setlinestyle(0);
+ nla_actionclip_draw_markers(strip, yminc, ymaxc, shade, true);
}
else if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
/* just a solid color, so that it is very easy to spot */
- UI_ThemeColorShade(TH_STRIP_SELECT, 20);
-
+ int shade = 20;
/* draw the markers in the first level of strips only (if they are actions) */
for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) {
if (nls->type == NLASTRIP_TYPE_CLIP) {
- nla_actionclip_draw_markers(nls, yminc, ymaxc);
+ nla_actionclip_draw_markers(nls, yminc, ymaxc, shade, false);
}
}
}
- glLineWidth(1.0);
+ GPU_line_width(1.0f);
}
/* Strips (Proper) ---------------------- */
@@ -266,18 +303,15 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col
}
/* helper call for drawing influence/time control curves for a given NLA-strip */
-static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
+static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, unsigned int pos)
{
const float yheight = ymaxc - yminc;
- /* drawing color is simply a light-gray */
- // TODO: is this color suitable?
- // XXX nasty hacked color for now... which looks quite bad too...
- glColor3f(0.7f, 0.7f, 0.7f);
+ immUniformColor3f(0.7f, 0.7f, 0.7f);
/* draw with AA'd line */
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+ GPU_line_smooth(true);
+ GPU_blend(true);
/* influence -------------------------- */
if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
@@ -286,67 +320,101 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
/* plot the curve (over the strip's main region) */
if (fcu) {
- glBegin(GL_LINE_STRIP);
+ immBegin(GPU_PRIM_LINE_STRIP, abs((int)(strip->end - strip->start) + 1));
/* sample at 1 frame intervals, and draw
* - min y-val is yminc, max is y-maxc, so clamp in those regions
*/
for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
- float y = evaluate_fcurve(fcu, cfra);
+ float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */
CLAMP(y, 0.0f, 1.0f);
- glVertex2f(cfra, ((y * yheight) + yminc));
+ immVertex2f(pos, cfra, ((y * yheight) + yminc));
}
- glEnd(); // GL_LINE_STRIP
+ immEnd();
}
}
else {
/* use blend in/out values only if both aren't zero */
if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) {
- glBegin(GL_LINE_STRIP);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, 4);
+
/* start of strip - if no blendin, start straight at 1, otherwise from 0 to 1 over blendin frames */
if (IS_EQF(strip->blendin, 0.0f) == 0) {
- glVertex2f(strip->start, yminc);
- glVertex2f(strip->start + strip->blendin, ymaxc);
+ immVertex2f(pos, strip->start, yminc);
+ immVertex2f(pos, strip->start + strip->blendin, ymaxc);
}
else
- glVertex2f(strip->start, ymaxc);
+ immVertex2f(pos, strip->start, ymaxc);
/* end of strip */
if (IS_EQF(strip->blendout, 0.0f) == 0) {
- glVertex2f(strip->end - strip->blendout, ymaxc);
- glVertex2f(strip->end, yminc);
+ immVertex2f(pos, strip->end - strip->blendout, ymaxc);
+ immVertex2f(pos, strip->end, yminc);
}
else
- glVertex2f(strip->end, ymaxc);
- glEnd(); // GL_LINE_STRIP
+ immVertex2f(pos, strip->end, ymaxc);
+
+ immEnd();
}
}
- /* time -------------------------- */
- // XXX do we want to draw this curve? in a different color too?
-
/* turn off AA'd lines */
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ GPU_line_smooth(false);
+ GPU_blend(false);
+}
+
+/* helper call to setup dashed-lines for strip outlines */
+static uint nla_draw_use_dashed_outlines(float color[4], bool muted)
+{
+ /* Note that we use dashed shader here, and make it draw solid lines if not muted... */
+ uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* Simple dashes. */
+ immUniformColor3fv(color);
+
+ /* line style: dotted for muted */
+ if (muted) {
+ /* dotted - and slightly thicker for readability of the dashes */
+ immUniform1f("dash_width", 5.0f);
+ immUniform1f("dash_factor", 0.4f);
+ GPU_line_width(1.5f);
+ }
+ else {
+ /* solid line */
+ immUniform1f("dash_factor", 2.0f);
+ GPU_line_width(1.0f);
+ }
+
+ return shdr_pos;
}
/* main call for drawing a single NLA-strip */
static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
{
const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
- float color[3];
+ const bool muted = ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED));
+ float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ uint shdr_pos;
/* get color of strip */
nla_strip_get_color_inside(adt, strip, color);
+ shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* draw extrapolation info first (as backdrop)
* - but this should only be drawn if track has some contribution
*/
if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (non_solo == 0)) {
/* enable transparency... */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
switch (strip->extendmode) {
/* since this does both sides, only do the 'before' side, and leave the rest to the next case */
@@ -356,15 +424,10 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
*/
if (strip->prev == NULL) {
/* set the drawing color to the color of the strip, but with very faint alpha */
- glColor4f(color[0], color[1], color[2], 0.15f);
+ immUniformColor3fvAlpha(color, 0.15f);
/* draw the rect to the edge of the screen */
- glBegin(GL_QUADS);
- glVertex2f(v2d->cur.xmin, yminc);
- glVertex2f(v2d->cur.xmin, ymaxc);
- glVertex2f(strip->start, ymaxc);
- glVertex2f(strip->start, yminc);
- glEnd();
+ immRectf(shdr_pos, v2d->cur.xmin, yminc, strip->start, ymaxc);
}
ATTR_FALLTHROUGH;
@@ -373,45 +436,38 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
/* only need to try and draw if the next strip doesn't occur immediately after */
if ((strip->next == NULL) || (IS_EQF(strip->next->start, strip->end) == 0)) {
/* set the drawing color to the color of the strip, but this time less faint */
- glColor4f(color[0], color[1], color[2], 0.3f);
+ immUniformColor3fvAlpha(color, 0.3f);
/* draw the rect to the next strip or the edge of the screen */
- glBegin(GL_QUADS);
- glVertex2f(strip->end, yminc);
- glVertex2f(strip->end, ymaxc);
-
- if (strip->next) {
- glVertex2f(strip->next->start, ymaxc);
- glVertex2f(strip->next->start, yminc);
- }
- else {
- glVertex2f(v2d->cur.xmax, ymaxc);
- glVertex2f(v2d->cur.xmax, yminc);
- }
- glEnd();
+ float x2 = strip->next ? strip->next->start : v2d->cur.xmax;
+ immRectf(shdr_pos, strip->end, yminc, x2, ymaxc);
}
break;
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
/* draw 'inside' of strip itself */
if (non_solo == 0) {
+ immUnbindProgram();
+
/* strip is in normal track */
- glColor3fv(color);
UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
+ UI_draw_roundbox_shade_x(true, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1, color);
- UI_draw_roundbox_shade_x(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
+ /* restore current vertex format & program (roundbox trashes it) */
+ shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
}
else {
/* strip is in disabled track - make less visible */
- glColor4f(color[0], color[1], color[2], 0.1f);
+ immUniformColor3fvAlpha(color, 0.1f);
- glEnable(GL_BLEND);
- glRectf(strip->start, yminc, strip->end, ymaxc);
- glDisable(GL_BLEND);
+ GPU_blend(true);
+ immRectf(shdr_pos, strip->start, yminc, strip->end, ymaxc);
+ GPU_blend(false);
}
@@ -419,8 +475,9 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
* - only if user hasn't hidden them...
*/
if ((snla->flag & SNLA_NOSTRIPCURVES) == 0)
- nla_draw_strip_curves(strip, yminc, ymaxc);
+ nla_draw_strip_curves(strip, yminc, ymaxc, shdr_pos);
+ immUnbindProgram();
/* draw markings indicating locations of local markers (useful for lining up different actions) */
if ((snla->flag & SNLA_NOLOCALMARKERS) == 0)
@@ -431,59 +488,79 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri
*/
if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
/* strip should appear 'sunken', so draw a light border around it */
- glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors
+ color[0] = 0.9f; /* FIXME: hardcoded temp-hack colors */
+ color[1] = 1.0f;
+ color[2] = 0.9f;
}
else {
/* strip should appear to stand out, so draw a dark border around it */
- glColor3f(0.0f, 0.0f, 0.0f);
+ color[0] = color[1] = color[2] = 0.0f; /* FIXME: or 1.0f ?? */
}
- /* - line style: dotted for muted */
- if ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED))
- setlinestyle(4);
+ /* draw outline
+ * - dashed-line shader is loaded after this block
+ */
+ if (muted) {
+ /* muted - draw dotted, squarish outline (for simplicity) */
+ shdr_pos = nla_draw_use_dashed_outlines(color, muted);
+ imm_draw_box_wire_2d(shdr_pos, strip->start, yminc, strip->end, ymaxc);
+ }
+ else {
+ /* non-muted - draw solid, rounded outline */
+ UI_draw_roundbox_shade_x(false, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1, color);
- /* draw outline */
- UI_draw_roundbox_shade_x(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
+ /* restore current vertex format & program (roundbox trashes it) */
+ shdr_pos = nla_draw_use_dashed_outlines(color, muted);
+ }
/* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
- if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQF(strip->repeat, 1.0f) == 0) {
+ if ((strip->type == NLASTRIP_TYPE_CLIP) && strip->repeat > 1.0f) {
float repeatLen = (strip->actend - strip->actstart) * strip->scale;
- int i;
/* only draw lines for whole-numbered repeats, starting from the first full-repeat
* up to the last full repeat (but not if it lies on the end of the strip)
*/
- for (i = 1; i < strip->repeat; i++) {
+ immBeginAtMost(GPU_PRIM_LINES, 2 * floorf(strip->repeat));
+ for (int i = 1; i < strip->repeat; i++) {
float repeatPos = strip->start + (repeatLen * i);
/* don't draw if line would end up on or after the end of the strip */
- if (repeatPos < strip->end)
- fdrawline(repeatPos, yminc + 4, repeatPos, ymaxc - 4);
+ if (repeatPos < strip->end) {
+ immVertex2f(shdr_pos, repeatPos, yminc + 4);
+ immVertex2f(shdr_pos, repeatPos, ymaxc - 4);
+ }
}
+ immEnd();
}
/* or if meta-strip, draw lines delimiting extents of sub-strips (in same color as outline, if more than 1 exists) */
else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
- NlaStrip *cs;
- float y = (ymaxc - yminc) / 2.0f + yminc;
+ const float y = (ymaxc - yminc) * 0.5f + yminc;
+
+ immBeginAtMost(GPU_PRIM_LINES, 4 * BLI_listbase_count(&strip->strips)); /* up to 2 lines per strip */
/* only draw first-level of child-strips, but don't draw any lines on the endpoints */
- for (cs = strip->strips.first; cs; cs = cs->next) {
+ for (NlaStrip *cs = strip->strips.first; cs; cs = cs->next) {
/* draw start-line if not same as end of previous (and only if not the first strip)
* - on upper half of strip
*/
- if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0)
- fdrawline(cs->start, y, cs->start, ymaxc);
+ if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0) {
+ immVertex2f(shdr_pos, cs->start, y);
+ immVertex2f(shdr_pos, cs->start, ymaxc);
+ }
/* draw end-line if not the last strip
* - on lower half of strip
*/
- if (cs->next)
- fdrawline(cs->end, yminc, cs->end, y);
+ if (cs->next) {
+ immVertex2f(shdr_pos, cs->end, yminc);
+ immVertex2f(shdr_pos, cs->end, y);
+ }
}
+
+ immEnd();
}
- /* reset linestyle */
- setlinestyle(0);
+ immUnbindProgram();
}
/* add the relevant text to the cache of text-strings to draw in pixelspace */
@@ -495,7 +572,6 @@ static void nla_draw_strip_text(
char str[256];
size_t str_len;
char col[4];
- rctf rect;
/* just print the name and the range */
if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
@@ -522,11 +598,13 @@ static void nla_draw_strip_text(
/* set bounding-box for text
* - padding of 2 'units' on either side
*/
- // TODO: make this centered?
- rect.xmin = xminc;
- rect.ymin = yminc;
- rect.xmax = xmaxc;
- rect.ymax = ymaxc;
+ /* TODO: make this centered? */
+ rctf rect = {
+ .xmin = xminc,
+ .ymin = yminc,
+ .xmax = xmaxc,
+ .ymax = ymaxc
+ };
/* add this string to the cache of texts to draw */
UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
@@ -542,7 +620,6 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V
char numstr[32];
size_t numstr_len;
-
/* Always draw times above the strip, whereas sequencer drew below + above.
* However, we should be fine having everything on top, since these tend to be
* quite spaced out.
@@ -562,20 +639,14 @@ static void nla_draw_strip_frames_text(NlaTrack *UNUSED(nlt), NlaStrip *strip, V
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-
View2D *v2d = &ar->v2d;
- float y = 0.0f;
- size_t items;
- int height;
const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
const float text_margin_x = (8 * UI_DPI_FAC) * pixelx;
/* build list of channels to draw */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
- items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ ListBase anim_data = {NULL, NULL};
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
* - this is done to allow the channel list to be scrollable, but must be done here
@@ -583,16 +654,17 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
* - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
* start of list offset, and the second is as a correction for the scrollers.
*/
- height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
+ int height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
+
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
v2d->tot.ymin = (float)(-height);
/* loop through channels, and set up drawing depending on their type */
- y = (float)(-NLACHANNEL_HEIGHT(snla));
+ float y = (float)(-NLACHANNEL_HEIGHT(snla));
- for (ale = anim_data.first; ale; ale = ale->next) {
+ for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
const float yminc = (float)(y - NLACHANNEL_HEIGHT_HALF(snla));
const float ymaxc = (float)(y + NLACHANNEL_HEIGHT_HALF(snla));
@@ -635,40 +707,55 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
case ANIMTYPE_NLAACTION:
{
AnimData *adt = ale->adt;
- float color[4];
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
* and a second darker rect within which we draw keyframe indicator dots if there's data
*/
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
/* get colors for drawing */
+ float color[4];
nla_action_get_color(adt, ale->data, color);
- glColor4fv(color);
+ immUniformColor4fv(color);
/* draw slightly shifted up for greater separation from standard channels,
* but also slightly shorter for some more contrast when viewing the strips
*/
- glRectf(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
-
- /* draw keyframes in the action */
- nla_action_draw_keyframes(adt, ale->data, v2d, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
+ immRectf(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
/* draw 'embossed' lines above and below the strip for effect */
/* white base-lines */
- glLineWidth(2.0f);
- glColor4f(1.0f, 1.0f, 1.0f, 0.3);
- fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
- fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
+ GPU_line_width(2.0f);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.3f);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP);
+ immVertex2f(pos, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
+ immVertex2f(pos, v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP);
+ immVertex2f(pos, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
+ immEnd();
/* black top-lines */
- glLineWidth(1.0f);
- glColor3f(0.0f, 0.0f, 0.0f);
- fdrawline(v2d->cur.xmin, yminc + NLACHANNEL_SKIP, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
- fdrawline(v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
+ GPU_line_width(1.0f);
+ immUniformColor3f(0.0f, 0.0f, 0.0f);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, v2d->cur.xmin, yminc + NLACHANNEL_SKIP);
+ immVertex2f(pos, v2d->cur.xmax, yminc + NLACHANNEL_SKIP);
+ immVertex2f(pos, v2d->cur.xmin, ymaxc - NLACHANNEL_SKIP);
+ immVertex2f(pos, v2d->cur.xmax, ymaxc - NLACHANNEL_SKIP);
+ immEnd();
+
+ /* TODO: these lines but better --^ */
+
+ immUnbindProgram();
+
+ /* draw keyframes in the action */
+ nla_action_draw_keyframes(v2d, adt, ale->data, y, yminc + NLACHANNEL_SKIP, ymaxc - NLACHANNEL_SKIP);
- glDisable(GL_BLEND);
+ GPU_blend(false);
break;
}
}
@@ -695,7 +782,6 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
View2D *v2d = &ar->v2d;
float y = 0.0f;
size_t items;
- int height;
/* build list of channels to draw */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
@@ -707,7 +793,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
* - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
* start of list offset, and the second is as a correction for the scrollers.
*/
- height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
+ int height = ((items * NLACHANNEL_STEP(snla)) + (NLACHANNEL_HEIGHT(snla) * 2));
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
@@ -745,8 +831,8 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
y = (float)(-NLACHANNEL_HEIGHT(snla));
/* set blending again, as may not be set in previous step */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
/* loop through channels, and set up drawing depending on their type */
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -769,7 +855,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *ar)
UI_block_end(C, block);
UI_block_draw(C, block);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
/* free temporary channels */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 5cf3ace747b..3cab4cfefca 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -46,11 +46,11 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_fcurve.h"
-#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_fcurve.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_nla.h"
#include "BKE_report.h"
#include "BKE_screen.h"
@@ -67,6 +67,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "DEG_depsgraph_build.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -90,9 +92,12 @@ void ED_nla_postop_refresh(bAnimContext *ac)
for (ale = anim_data.first; ale; ale = ale->next) {
/* performing auto-blending, extend-mode validation, etc. */
BKE_nla_validate_state(ale->data);
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
/* free temp memory */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -144,9 +149,12 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
BKE_nlatrack_solo_toggle(adt, nlt);
}
}
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
/* free temp data */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* if we managed to enter tweakmode on at least one AnimData block,
@@ -223,9 +231,12 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
/* to be sure that we're doing everything right, just exit tweakmode... */
BKE_nla_tweakmode_exit(adt);
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
/* free temp data */
+ ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* if we managed to enter tweakmode on at least one AnimData block,
@@ -669,6 +680,8 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
+ DEG_relations_tag_update(ac.bmain);
+
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -939,9 +952,12 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
if (strip->flag & NLASTRIP_FLAG_SELECT)
BKE_nlastrip_validate_name(adt, strip);
}
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
/* free temp data */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
@@ -991,9 +1007,12 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
/* clear all selected meta-strips, regardless of whether they are temporary or not */
BKE_nlastrips_clear_metas(&nlt->strips, 1, 0);
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
/* free temp data */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
@@ -1057,7 +1076,7 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
/* if selected, split the strip at its midpoint */
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* make a copy (assume that this is possible) */
- nstrip = BKE_nlastrip_copy(ac.bmain, strip, linked);
+ nstrip = BKE_nlastrip_copy(ac.bmain, strip, linked, 0);
/* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
@@ -1087,6 +1106,10 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
+ if (!linked) {
+ DEG_relations_tag_update(ac.bmain);
+ }
+
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -1160,14 +1183,14 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* if a strip either side of this was a transition, delete those too */
if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
- BKE_nlastrip_free(&nlt->strips, strip->prev);
+ BKE_nlastrip_free(&nlt->strips, strip->prev, true);
if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
nstrip = nstrip->next;
- BKE_nlastrip_free(&nlt->strips, strip->next);
+ BKE_nlastrip_free(&nlt->strips, strip->next, true);
}
/* finally, delete this strip */
- BKE_nlastrip_free(&nlt->strips, strip);
+ BKE_nlastrip_free(&nlt->strips, strip, true);
}
}
}
@@ -1178,6 +1201,8 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
+ DEG_relations_tag_update(ac.bmain);
+
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -1242,7 +1267,7 @@ static void nlaedit_split_strip_actclip(Main *bmain, AnimData *adt, NlaTrack *nl
/* make a copy (assume that this is possible) and append
* it immediately after the current strip
*/
- nstrip = BKE_nlastrip_copy(bmain, strip, true);
+ nstrip = BKE_nlastrip_copy(bmain, strip, true, 0);
BLI_insertlinkafter(&nlt->strips, strip, nstrip);
/* set the endpoint of the first strip and the start of the new strip
@@ -1345,60 +1370,6 @@ void NLA_OT_split(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************** Bake Strips Operator ***************************** */
-/* Bakes the NLA Strips for the active AnimData blocks */
-
-static int nlaedit_bake_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bAnimContext ac;
-
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
-// int flag = 0;
-
- /* get editor data */
- if (ANIM_animdata_get_context(C, &ac) == 0)
- return OPERATOR_CANCELLED;
-
- /* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
- ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
-
- /* for each AnimData block, bake strips to animdata... */
- for (ale = anim_data.first; ale; ale = ale->next) {
- //BKE_nla_bake(ac.scene, ale->id, ale->data, flag);
- }
-
- /* free temp data */
- ANIM_animdata_freelist(&anim_data);
-
- /* refresh auto strip properties */
- ED_nla_postop_refresh(&ac);
-
- /* set notifier that things have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
-
- /* done */
- return OPERATOR_FINISHED;
-}
-
-/* why isn't this used? */
-static void UNUSED_FUNCTION(NLA_OT_bake)(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Bake Strips";
- ot->idname = "NLA_OT_bake";
- ot->description = "Bake all strips of selected AnimData blocks";
-
- /* api callbacks */
- ot->exec = nlaedit_bake_exec;
- ot->poll = nlaop_poll_tweakmode_off;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* *********************************************** */
/* NLA Editing Operations (Modifying) */
@@ -1819,11 +1790,14 @@ static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op)
/* adjust the strip extents in response to this */
BKE_nlastrip_recalculate_bounds(strip);
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
}
}
/* free temp data */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
@@ -1862,6 +1836,7 @@ static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
+ bool copied = false;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1895,14 +1870,22 @@ static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
/* switch to the new copy */
strip->act = new_action;
+
+ ale->update |= ANIM_UPDATE_DEPS;
+ copied = true;
}
}
}
}
/* free temp data */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
+ if (copied) {
+ DEG_relations_tag_update(ac.bmain);
+ }
+
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -1952,6 +1935,7 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
+ bool copied = false;
KeyframeEditData ked = {{NULL}};
@@ -1981,6 +1965,8 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
/* set this as the new referenced action, decrementing the users of the old one */
id_us_min(&strip->act->id);
strip->act = act;
+
+ copied = true;
}
/* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
@@ -1993,13 +1979,20 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
*/
strip->scale = 1.0f;
calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
}
}
/* free temp data */
+ ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
+ if (copied) {
+ DEG_relations_tag_update(ac.bmain);
+ }
+
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index a00e71a192d..59844f31447 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -65,8 +65,8 @@ enum eNlaEdit_LeftRightSelect_Mode {
/* --- */
-void NLA_OT_select_all_toggle(wmOperatorType *ot);
-void NLA_OT_select_border(wmOperatorType *ot);
+void NLA_OT_select_all(wmOperatorType *ot);
+void NLA_OT_select_box(wmOperatorType *ot);
void NLA_OT_select_leftright(wmOperatorType *ot);
void NLA_OT_click_select(wmOperatorType *ot);
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index bfc6138fb03..0122306f709 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -39,6 +39,7 @@
#include "ED_anim_api.h"
#include "ED_markers.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
#include "WM_api.h"
@@ -123,8 +124,8 @@ void nla_operatortypes(void)
/* select */
WM_operatortype_append(NLA_OT_click_select);
- WM_operatortype_append(NLA_OT_select_border);
- WM_operatortype_append(NLA_OT_select_all_toggle);
+ WM_operatortype_append(NLA_OT_select_box);
+ WM_operatortype_append(NLA_OT_select_all);
WM_operatortype_append(NLA_OT_select_leftright);
/* view */
@@ -171,172 +172,10 @@ void nla_operatortypes(void)
/* ************************** registration - keymaps **********************************/
-static void nla_keymap_channels(wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- /* keymappings here are NLA-specific (different to standard channels keymap) */
-
- /* selection --------------------------------------------------------------------- */
- /* click-select */
- // XXX for now, only leftmouse....
- kmi = WM_keymap_add_item(keymap, "NLA_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "NLA_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- /* channel operations ------------------------------------------------------------ */
- /* add tracks */
- kmi = WM_keymap_add_item(keymap, "NLA_OT_tracks_add", AKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "above_selected", false);
- kmi = WM_keymap_add_item(keymap, "NLA_OT_tracks_add", AKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "above_selected", true);
-
- /* delete tracks */
- WM_keymap_add_item(keymap, "NLA_OT_tracks_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NLA_OT_tracks_delete", DELKEY, KM_PRESS, 0, 0);
-}
-
-static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
-{
- wmKeyMapItem *kmi;
-
- /* selection ------------------------------------------------ */
- /* click select */
- kmi = WM_keymap_add_item(keymap, "NLA_OT_click_select", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "NLA_OT_click_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- /* select left/right */
- kmi = WM_keymap_add_item(keymap, "NLA_OT_select_leftright", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", NLAEDIT_LRSEL_TEST);
- kmi = WM_keymap_add_item(keymap, "NLA_OT_select_leftright", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_enum_set(kmi->ptr, "mode", NLAEDIT_LRSEL_TEST);
-
- kmi = WM_keymap_add_item(keymap, "NLA_OT_select_leftright", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", NLAEDIT_LRSEL_LEFT);
- kmi = WM_keymap_add_item(keymap, "NLA_OT_select_leftright", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_enum_set(kmi->ptr, "mode", NLAEDIT_LRSEL_RIGHT);
-
-
- /* deselect all */
- /* TODO: uniformize with other select_all ops? */
- kmi = WM_keymap_add_item(keymap, "NLA_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "invert", false);
- kmi = WM_keymap_add_item(keymap, "NLA_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "invert", true);
-
- /* borderselect */
- kmi = WM_keymap_add_item(keymap, "NLA_OT_select_border", BKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "axis_range", false);
- kmi = WM_keymap_add_item(keymap, "NLA_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "axis_range", true);
-
- /* view ---------------------------------------------------- */
- /* auto-set range */
- WM_keymap_add_item(keymap, "NLA_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "NLA_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "NLA_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
- WM_keymap_add_item(keymap, "NLA_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NLA_OT_view_frame", PAD0, KM_PRESS, 0, 0);
-
- /* editing ------------------------------------------------ */
-
- /* add strips */
- WM_keymap_add_item(keymap, "NLA_OT_actionclip_add", AKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "NLA_OT_transition_add", TKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "NLA_OT_soundclip_add", KKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* meta-strips */
- WM_keymap_add_item(keymap, "NLA_OT_meta_add", GKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "NLA_OT_meta_remove", GKEY, KM_PRESS, KM_ALT, 0);
-
- /* duplicate */
- kmi = WM_keymap_add_item(keymap, "NLA_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "linked", false);
-
- kmi = WM_keymap_add_item(keymap, "NLA_OT_duplicate", DKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "linked", true);
-
- /* single user */
- WM_keymap_add_item(keymap, "NLA_OT_make_single_user", UKEY, KM_PRESS, 0, 0);
-
- /* delete */
- WM_keymap_add_item(keymap, "NLA_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NLA_OT_delete", DELKEY, KM_PRESS, 0, 0);
-
- /* split */
- WM_keymap_add_item(keymap, "NLA_OT_split", YKEY, KM_PRESS, 0, 0);
-
- /* toggles */
- WM_keymap_add_item(keymap, "NLA_OT_mute_toggle", HKEY, KM_PRESS, 0, 0);
-
- /* swap */
- WM_keymap_add_item(keymap, "NLA_OT_swap", FKEY, KM_PRESS, KM_ALT, 0);
-
- /* move up */
- WM_keymap_add_item(keymap, "NLA_OT_move_up", PAGEUPKEY, KM_PRESS, 0, 0);
- /* move down */
- WM_keymap_add_item(keymap, "NLA_OT_move_down", PAGEDOWNKEY, KM_PRESS, 0, 0);
-
- /* apply scale */
- WM_keymap_add_item(keymap, "NLA_OT_apply_scale", AKEY, KM_PRESS, KM_CTRL, 0);
- /* clear scale */
- WM_keymap_add_item(keymap, "NLA_OT_clear_scale", SKEY, KM_PRESS, KM_ALT, 0);
-
- /* snap */
- WM_keymap_add_item(keymap, "NLA_OT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* add f-modifier */
- WM_keymap_add_item(keymap, "NLA_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
-
- /* transform system */
- transform_keymap_for_space(keyconf, keymap, SPACE_NLA);
-
- /* special markers hotkeys for anim editors: see note in definition of this function */
- ED_marker_keymap_animedit_conflictfree(keymap);
-}
-
-/* --------------- */
-
void nla_keymap(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
/* keymap for all regions ------------------------------------------- */
- keymap = WM_keymap_ensure(keyconf, "NLA Generic", SPACE_NLA, 0);
-
- /* region management */
- WM_keymap_add_item(keymap, "NLA_OT_properties", NKEY, KM_PRESS, 0, 0);
-
- /* tweakmode
- * - enter and exit are separate operators with the same hotkey...
- * This works as they use different poll()'s
- */
- WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, 0, 0);
-
- /* tweakmode for stashed actions
- * - similar to normal tweakmode, except we mark the tracks as being "solo"
- * too so that the action can be edited in isolation
- */
- kmi = WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "isolate_action", true);
-
- kmi = WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "isolate_action", true);
-
- /* find (i.e. a shortcut for setting the name filter) */
- WM_keymap_add_item(keymap, "ANIM_OT_channels_find", FKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_ensure(keyconf, "NLA Generic", SPACE_NLA, 0);
/* channels ---------------------------------------------------------- */
/* Channels are not directly handled by the NLA Editor module, but are inherited from the Animation module.
@@ -346,10 +185,8 @@ void nla_keymap(wmKeyConfig *keyconf)
* However, those operations which involve clicking on channels and/or
* the placement of them in the view are implemented here instead
*/
- keymap = WM_keymap_ensure(keyconf, "NLA Channels", SPACE_NLA, 0);
- nla_keymap_channels(keymap);
+ WM_keymap_ensure(keyconf, "NLA Channels", SPACE_NLA, 0);
/* data ------------------------------------------------------------- */
- keymap = WM_keymap_ensure(keyconf, "NLA Editor", SPACE_NLA, 0);
- nla_keymap_main(keyconf, keymap);
+ WM_keymap_ensure(keyconf, "NLA Editor", SPACE_NLA, 0);
}
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index c1d62a9768d..db7f5d707d2 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -46,6 +46,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -167,10 +168,24 @@ static int nlaedit_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* 'standard' behavior - check if selected, then apply relevant selection */
- if (RNA_boolean_get(op->ptr, "invert"))
- deselect_nla_strips(&ac, DESELECT_STRIPS_NOTEST, SELECT_INVERT);
- else
- deselect_nla_strips(&ac, DESELECT_STRIPS_TEST, SELECT_ADD);
+ const int action = RNA_enum_get(op->ptr, "action");
+ switch (action) {
+ case SEL_TOGGLE:
+ deselect_nla_strips(&ac, DESELECT_STRIPS_TEST, SELECT_ADD);
+ break;
+ case SEL_SELECT:
+ deselect_nla_strips(&ac, DESELECT_STRIPS_NOTEST, SELECT_ADD);
+ break;
+ case SEL_DESELECT:
+ deselect_nla_strips(&ac, DESELECT_STRIPS_NOTEST, SELECT_SUBTRACT);
+ break;
+ case SEL_INVERT:
+ deselect_nla_strips(&ac, DESELECT_STRIPS_NOTEST, SELECT_INVERT);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_SELECTED, NULL);
@@ -178,11 +193,11 @@ static int nlaedit_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void NLA_OT_select_all_toggle(wmOperatorType *ot)
+void NLA_OT_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "(De)select All";
- ot->idname = "NLA_OT_select_all_toggle";
+ ot->idname = "NLA_OT_select_all";
ot->description = "Select or deselect all NLA-Strips";
/* api callbacks */
@@ -192,12 +207,11 @@ void NLA_OT_select_all_toggle(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER /*|OPTYPE_UNDO*/;
- /* props */
- ot->prop = RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
- RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+ /* properties */
+ WM_operator_properties_select_all(ot);
}
-/* ******************** Border Select Operator **************************** */
+/* ******************** Box Select Operator **************************** */
/* This operator currently works in one of three ways:
* -> BKEY - 1) all strips within region are selected (NLAEDIT_BORDERSEL_ALLSTRIPS)
* -> ALT-BKEY - depending on which axis of the region was larger...
@@ -205,15 +219,15 @@ void NLA_OT_select_all_toggle(wmOperatorType *ot)
* -> 3) y-axis, so select all frames within channels that region included (NLAEDIT_BORDERSEL_CHANNELS)
*/
-/* defines for borderselect mode */
+/* defines for box_select mode */
enum {
- NLA_BORDERSEL_ALLSTRIPS = 0,
- NLA_BORDERSEL_FRAMERANGE,
- NLA_BORDERSEL_CHANNELS,
-} /* eNLAEDIT_BorderSelect_Mode */;
+ NLA_BOXSEL_ALLSTRIPS = 0,
+ NLA_BOXSEL_FRAMERANGE,
+ NLA_BOXSEL_CHANNELS,
+} /* eNLAEDIT_BoxSelect_Mode */;
-static void borderselect_nla_strips(bAnimContext *ac, rcti rect, short mode, short selectmode)
+static void box_select_nla_strips(bAnimContext *ac, rcti rect, short mode, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -235,12 +249,12 @@ static void borderselect_nla_strips(bAnimContext *ac, rcti rect, short mode, sho
/* convert selection modes to selection modes */
selectmode = selmodes_to_flagmodes(selectmode);
- /* loop over data, doing border select */
+ /* loop over data, doing box select */
for (ale = anim_data.first; ale; ale = ale->next) {
ymin = ymax - NLACHANNEL_STEP(snla);
/* perform vertical suitability check (if applicable) */
- if ((mode == NLA_BORDERSEL_FRAMERANGE) ||
+ if ((mode == NLA_BOXSEL_FRAMERANGE) ||
!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
{
/* loop over data selecting (only if NLA-Track) */
@@ -250,7 +264,7 @@ static void borderselect_nla_strips(bAnimContext *ac, rcti rect, short mode, sho
/* only select strips if they fall within the required ranges (if applicable) */
for (strip = nlt->strips.first; strip; strip = strip->next) {
- if ((mode == NLA_BORDERSEL_CHANNELS) ||
+ if ((mode == NLA_BOXSEL_CHANNELS) ||
BKE_nlastrip_within_bounds(strip, rectf.xmin, rectf.xmax))
{
/* set selection */
@@ -273,7 +287,7 @@ static void borderselect_nla_strips(bAnimContext *ac, rcti rect, short mode, sho
/* ------------------- */
-static int nlaedit_borderselect_exec(bContext *C, wmOperator *op)
+static int nlaedit_box_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
rcti rect;
@@ -300,7 +314,7 @@ static int nlaedit_borderselect_exec(bContext *C, wmOperator *op)
selectmode = SELECT_SUBTRACT;
}
- /* selection 'mode' depends on whether borderselect region only matters on one axis */
+ /* selection 'mode' depends on whether box_select region only matters on one axis */
if (RNA_boolean_get(op->ptr, "axis_range")) {
/* mode depends on which axis of the range is larger to determine which axis to use
* - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
@@ -308,15 +322,15 @@ static int nlaedit_borderselect_exec(bContext *C, wmOperator *op)
* used for tweaking timing when "blocking", while channels is not that useful...
*/
if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect))
- mode = NLA_BORDERSEL_FRAMERANGE;
+ mode = NLA_BOXSEL_FRAMERANGE;
else
- mode = NLA_BORDERSEL_CHANNELS;
+ mode = NLA_BOXSEL_CHANNELS;
}
else
- mode = NLA_BORDERSEL_ALLSTRIPS;
+ mode = NLA_BOXSEL_ALLSTRIPS;
- /* apply borderselect action */
- borderselect_nla_strips(&ac, rect, mode, selectmode);
+ /* apply box_select action */
+ box_select_nla_strips(&ac, rect, mode, selectmode);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_SELECTED, NULL);
@@ -324,18 +338,18 @@ static int nlaedit_borderselect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void NLA_OT_select_border(wmOperatorType *ot)
+void NLA_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "NLA_OT_select_border";
+ ot->name = "Box Select";
+ ot->idname = "NLA_OT_select_box";
ot->description = "Use box selection to grab NLA-Strips";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = nlaedit_borderselect_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = nlaedit_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = nlaop_poll_tweakmode_off;
@@ -343,7 +357,7 @@ void NLA_OT_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
}
@@ -653,7 +667,7 @@ void NLA_OT_click_select(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Mouse Select";
+ ot->name = "Select";
ot->idname = "NLA_OT_click_select";
ot->description = "Handle clicks to select NLA Strips";
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 1f9ff9aaabd..d72014901a6 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -33,7 +33,7 @@
#include <stdio.h>
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
@@ -55,11 +55,15 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+
+#include "RNA_access.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "nla_intern.h" /* own include */
+#include "GPU_framebuffer.h"
/* ******************** manage regions ********************* */
@@ -91,10 +95,8 @@ ARegion *nla_has_buttons_region(ScrArea *sa)
/* ******************** default callbacks for nla space ***************** */
-static SpaceLink *nla_new(const bContext *C)
+static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene)
{
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
ARegion *ar;
SpaceNla *snla;
@@ -113,7 +115,7 @@ static SpaceLink *nla_new(const bContext *C)
BLI_addtail(&snla->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* channel list region */
ar = MEM_callocN(sizeof(ARegion), "channel list for nla");
@@ -177,14 +179,14 @@ static void nla_free(SpaceLink *sl)
/* spacetype; init callback */
-static void nla_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void nla_init(struct wmWindowManager *wm, ScrArea *sa)
{
SpaceNla *snla = (SpaceNla *)sa->spacedata.first;
/* init dopesheet data if non-existent (i.e. for old files) */
if (snla->ads == NULL) {
snla->ads = MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
- snla->ads->source = (ID *)G.main->scene.first; // XXX this is bad, but we need this to be set correct
+ snla->ads->source = (ID *)WM_window_get_active_scene(wm->winactive);
}
ED_area_tag_refresh(sa);
@@ -231,7 +233,7 @@ static void nla_channel_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -244,7 +246,7 @@ static void nla_channel_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@@ -268,15 +270,16 @@ static void nla_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceNla *snla = CTX_wm_space_nla(C);
+ Scene *scene = CTX_data_scene(C);
bAnimContext ac;
View2D *v2d = &ar->v2d;
View2DGrid *grid;
View2DScrollers *scrollers;
- short unit = 0, flag = 0;
+ short unit = 0, cfra_flag = 0;
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -288,6 +291,9 @@ static void nla_main_region_draw(const bContext *C, ARegion *ar)
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
+ /* start and end frame */
+ ANIM_draw_framerange(scene, v2d);
+
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
/* strips and backdrops */
@@ -300,9 +306,8 @@ static void nla_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_ortho(v2d);
/* current frame */
- if (snla->flag & SNLA_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS;
- if ((snla->flag & SNLA_NODRAWCFRANUM) == 0) flag |= DRAWCFRA_SHOW_NUMBOX;
- ANIM_draw_cfra(C, v2d, flag);
+ if (snla->flag & SNLA_DRAWTIME) cfra_flag |= DRAWCFRA_UNIT_SECONDS;
+ ANIM_draw_cfra(C, v2d, cfra_flag);
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
@@ -320,9 +325,15 @@ static void nla_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
+
+ /* draw current frame number-indicator on top of scrollers */
+ if ((snla->flag & SNLA_NODRAWCFRANUM) == 0) {
+ UI_view2d_view_orthoSpecial(ar, v2d, 1);
+ ANIM_draw_cfra_number(C, v2d, cfra_flag);
+ }
}
@@ -350,10 +361,12 @@ static void nla_buttons_region_init(wmWindowManager *wm, ARegion *ar)
static void nla_buttons_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
-static void nla_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void nla_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -386,7 +399,9 @@ static void nla_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegio
}
-static void nla_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void nla_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -398,6 +413,7 @@ static void nla_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), A
case ND_RENDER_OPTIONS:
case ND_OB_ACTIVE:
case ND_FRAME:
+ case ND_FRAME_RANGE:
case ND_MARKERS:
ED_region_tag_redraw(ar);
break;
@@ -424,6 +440,11 @@ static void nla_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), A
if (wmn->action == NA_RENAME)
ED_region_tag_redraw(ar);
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
default:
if (wmn->data == ND_KEYS)
ED_region_tag_redraw(ar);
@@ -431,7 +452,49 @@ static void nla_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), A
}
}
-static void nla_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void nla_main_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceNLA, sa->spacedata.first, &ptr);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* Timeline depends on scene properties. */
+ {
+ bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
+ extern PropertyRNA rna_Scene_frame_start;
+ extern PropertyRNA rna_Scene_frame_end;
+ extern PropertyRNA rna_Scene_frame_preview_start;
+ extern PropertyRNA rna_Scene_frame_preview_end;
+ extern PropertyRNA rna_Scene_use_preview_range;
+ extern PropertyRNA rna_Scene_frame_current;
+ const PropertyRNA *props[] = {
+ use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
+ use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
+ &rna_Scene_use_preview_range,
+ &rna_Scene_frame_current,
+ };
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&scene->id, &idptr);
+
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
+ }
+ }
+}
+
+static void nla_channel_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -465,8 +528,43 @@ static void nla_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
}
}
+static void nla_channel_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceNLA, sa->spacedata.first, &ptr);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* All dopesheet filter settings, etc. affect the drawing of this editor,
+ * so just whitelist the entire struct for updates
+ */
+ {
+ wmMsgParams_RNA msg_key_params = {{{0}}};
+ StructRNA *type_array[] = {
+ &RNA_DopeSheet,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
+ msg_key_params.ptr.type = type_array[i];
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &msg_key_params,
+ &msg_sub_value_region_tag_redraw,
+ __func__);
+ }
+ }
+}
+
/* editor level listener */
-static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void nla_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -508,7 +606,7 @@ static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *
if (snla->ads) {
if ((ID *)snla->ads->filter_grp == old_id) {
- snla->ads->filter_grp = (Group *)new_id;
+ snla->ads->filter_grp = (Collection *)new_id;
}
if ((ID *)snla->ads->source == old_id) {
snla->ads->source = new_id;
@@ -540,6 +638,7 @@ void ED_spacetype_nla(void)
art->init = nla_main_region_init;
art->draw = nla_main_region_draw;
art->listener = nla_main_region_listener;
+ art->message_subscribe = nla_main_region_message_subscribe;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
@@ -564,6 +663,7 @@ void ED_spacetype_nla(void)
art->init = nla_channel_region_init;
art->draw = nla_channel_region_draw;
art->listener = nla_channel_region_listener;
+ art->message_subscribe = nla_channel_region_message_subscribe;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index cde818333e4..06a00945452 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../imbuf
../../gpu
../../makesdna
@@ -47,6 +48,7 @@ set(SRC
node_draw.c
node_edit.c
node_group.c
+ node_gizmo.c
node_ops.c
node_relationships.c
node_select.c
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 0dc057e754b..10ec293082f 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -50,9 +50,15 @@
#include "BLF_api.h"
#include "BLT_translation.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_draw.h"
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -62,6 +68,7 @@
#include "WM_types.h"
#include "UI_resources.h"
+#include "UI_view2d.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
@@ -80,49 +87,6 @@ static void node_socket_button_label(bContext *UNUSED(C), uiLayout *layout, Poin
uiItemL(layout, text, 0);
}
-
-/* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */
-
-#if 0 /* UNUSED */
-static void node_draw_socket_new(bNodeSocket *sock, float size)
-{
- float x = sock->locx, y = sock->locy;
-
- /* 16 values of sin function */
- static float si[16] = {
- 0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f,
- 0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f,
- -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f,
- -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f
- };
- /* 16 values of cos function */
- static float co[16] = {
- 1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f,
- -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f,
- -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f,
- 0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
- };
- int a;
-
- glColor3ub(180, 180, 180);
-
- glBegin(GL_POLYGON);
- for (a = 0; a < 16; a++)
- glVertex2f(x + size * si[a], y + size * co[a]);
- glEnd();
-
- glColor4ub(0, 0, 0, 150);
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
- glBegin(GL_LINE_LOOP);
- for (a = 0; a < 16; a++)
- glVertex2f(x + size * si[a], y + size * co[a]);
- glEnd();
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
-}
-#endif
-
/* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */
static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -180,7 +144,7 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
}
#endif
- uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false);
+ uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
row = uiLayoutRow(layout, true);
uiItemR(row, ptr, "frame_start", 0, IFACE_("Sta"), ICON_NONE);
@@ -194,7 +158,7 @@ static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRN
static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false);
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false);
}
#define SAMPLE_FLT_ISNONE FLT_MAX
@@ -222,7 +186,7 @@ static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA
cumap->flag &= ~CUMA_DRAW_SAMPLE;
}
- uiTemplateCurveMapping(layout, ptr, "mapping", 'c', false, false, false);
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'c', false, false, false, true);
}
static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -392,6 +356,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
const int font_size = data->label_size / aspect;
const float margin = (float)(NODE_DY / 4);
int label_height;
+ unsigned char color[3];
nodeLabel(ntree, node, label, sizeof(label));
@@ -400,7 +365,8 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
BLF_size(fontid, MIN2(24, font_size), U.dpi); /* clamp otherwise it can suck up a LOT of memory */
/* title color */
- UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
+ UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
+ BLF_color3ubv(fontid, color);
width = BLF_width(fontid, label, sizeof(label));
ascender = BLF_ascender(fontid);
@@ -465,7 +431,7 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode,
{
rctf *rct = &node->totr;
int color_id = node_get_colorid(node);
- unsigned char color[4];
+ float color[4];
float alpha;
/* skip if out of view */
@@ -475,38 +441,30 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode,
return;
}
- UI_GetThemeColor4ubv(TH_NODE_FRAME, color);
- alpha = (float)(color[3]) / 255.0f;
+ UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+ alpha = color[3];
/* shadow */
node_draw_shadow(snode, node, BASIS_RAD, alpha);
/* body */
- if (node->flag & NODE_CUSTOM_COLOR)
- glColor4f(node->color[0], node->color[1], node->color[2], alpha);
+ if (node->flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], alpha);
+ }
else
- UI_ThemeColor4(TH_NODE_FRAME);
- glEnable(GL_BLEND);
+ UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
- glDisable(GL_BLEND);
+ UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
/* outline active and selected emphasis */
if (node->flag & SELECT) {
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
-
if (node->flag & NODE_ACTIVE)
- UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
+ UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color);
else
- UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP,
- rct->xmin, rct->ymin,
- rct->xmax, rct->ymax, BASIS_RAD);
+ UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
}
/* label */
@@ -580,15 +538,9 @@ static void node_draw_reroute_prepare(const bContext *UNUSED(C), bNodeTree *UNUS
static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(snode),
bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key))
{
- bNodeSocket *sock;
char showname[128]; /* 128 used below */
rctf *rct = &node->totr;
-#if 0 /* UNUSED */
- float size = NODE_REROUTE_SIZE;
-#endif
- float socket_size = NODE_SOCKSIZE;
-
/* skip if out of view */
if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax)
@@ -602,26 +554,29 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
* selection state is indicated by socket outline below!
*/
#if 0
+ float size = NODE_REROUTE_SIZE;
+
/* body */
+ float debug_color[4];
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_ThemeColor4(TH_NODE);
- glEnable(GL_BLEND);
- UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, size);
- glDisable(GL_BLEND);
+ UI_GetThemeColor4fv(TH_NODE, debug_color);
+ UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
/* outline active and selected emphasis */
if (node->flag & SELECT) {
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ GPU_blend(true);
+ GPU_line_smooth(true);
/* using different shades of TH_TEXT_HI for the empasis, like triangle */
- if (node->flag & NODE_ACTIVE)
- UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
- else
- UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size);
+ if (node->flag & NODE_ACTIVE) {
+ UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, 0, -40, debug_color);
+ }
+ else {
+ UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, -20, -120, debug_color);
+ }
+ UI_draw_roundbox_4fv(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ GPU_line_smooth(false);
+ GPU_blend(false);
}
#endif
@@ -637,9 +592,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
/* only draw input socket. as they all are placed on the same position.
* highlight also if node itself is selected, since we don't display the node body separately!
*/
- for (sock = node->inputs.first; sock; sock = sock->next) {
- node_socket_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT));
- }
+ node_draw_sockets(&ar->v2d, C, ntree, node, false, node->flag & SELECT);
UI_block_end(C, node->block);
UI_block_draw(C, node->block);
@@ -705,7 +658,7 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
/* Image *ima = imaptr->data; */ /* UNUSED */
char numstr[32];
- const int framenr = BKE_image_user_frame_get(iuser, CFRA, 0, NULL);
+ const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL);
BLI_snprintf(numstr, sizeof(numstr), IFACE_("Frame: %d"), framenr);
uiItemL(layout, numstr, ICON_NONE);
}
@@ -728,21 +681,6 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
}
}
-static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- bNode *node = ptr->data;
- uiLayout *col;
-
- uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
-
- if (!node->id) return;
-
- col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_diffuse", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_specular", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "invert_normal", 0, NULL, ICON_NONE);
-}
-
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *row, *col, *sub;
@@ -790,30 +728,6 @@ static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C
uiItemR(layout, ptr, "convert_to", 0, "", ICON_NONE);
}
-static void node_shader_buts_geometry(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
- uiLayout *col;
-
- col = uiLayoutColumn(layout, false);
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
-
- uiItemPointerR(col, ptr, "uv_layer", &dataptr, "uv_textures", "", ICON_NONE);
- uiItemPointerR(col, ptr, "color_layer", &dataptr, "vertex_colors", "", ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "uv_layer", 0, IFACE_("UV"), ICON_NONE);
- uiItemR(col, ptr, "color_layer", 0, IFACE_("VCol"), ICON_NONE);
- }
-}
-
-static void node_shader_buts_lamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "lamp_object", 0, IFACE_("Lamp Object"), ICON_NONE);
-}
-
static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "attribute_name", 0, IFACE_("Name"), ICON_NONE);
@@ -830,7 +744,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
@@ -861,7 +775,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(
layout, C, ptr, "image",
- NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
@@ -879,7 +793,7 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(
layout, C, ptr, "image",
- ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!ima)
return;
@@ -1007,7 +921,7 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, bContext *UNUSED
static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "object", 0, NULL, 0);
- uiItemR(layout, ptr, "from_dupli", 0, NULL, 0);
+ uiItemR(layout, ptr, "from_instancer", 0, NULL, 0);
}
static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1017,14 +931,14 @@ static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), Pointer
static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiItemR(layout, ptr, "from_dupli", 0, NULL, 0);
+ uiItemR(layout, ptr, "from_instancer", 0, NULL, 0);
- if (!RNA_boolean_get(ptr, "from_dupli")) {
+ if (!RNA_boolean_get(ptr, "from_instancer")) {
PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_textures", "", ICON_NONE);
+ uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
}
}
@@ -1043,7 +957,7 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN
if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_textures", "", ICON_NONE);
+ uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
else
uiItemR(layout, ptr, "uv_map", 0, "", 0);
@@ -1070,7 +984,7 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *
if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_textures", "", ICON_NONE);
+ uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
else
uiItemR(row, ptr, "uv_map", 0, "", 0);
@@ -1160,6 +1074,11 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA
#endif
}
+static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "target", 0, "", ICON_NONE);
+}
+
static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *row, *col;
@@ -1186,13 +1105,6 @@ static void node_shader_buts_ambient_occlusion(uiLayout *layout, bContext *UNUSE
static void node_shader_set_butfunc(bNodeType *ntype)
{
switch (ntype->type) {
- case SH_NODE_MATERIAL:
- case SH_NODE_MATERIAL_EXT:
- ntype->draw_buttons = node_shader_buts_material;
- break;
- case SH_NODE_TEXTURE:
- ntype->draw_buttons = node_buts_texture;
- break;
case SH_NODE_NORMAL:
ntype->draw_buttons = node_buts_normal;
break;
@@ -1226,12 +1138,6 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_VECT_TRANSFORM:
ntype->draw_buttons = node_shader_buts_vect_transform;
break;
- case SH_NODE_GEOMETRY:
- ntype->draw_buttons = node_shader_buts_geometry;
- break;
- case SH_NODE_LAMP:
- ntype->draw_buttons = node_shader_buts_lamp;
- break;
case SH_NODE_ATTRIBUTE:
ntype->draw_buttons = node_shader_buts_attribute;
break;
@@ -1319,6 +1225,11 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_UVALONGSTROKE:
ntype->draw_buttons = node_shader_buts_uvalongstroke;
break;
+ case SH_NODE_OUTPUT_MATERIAL:
+ case SH_NODE_OUTPUT_LIGHT:
+ case SH_NODE_OUTPUT_WORLD:
+ ntype->draw_buttons = node_buts_output_shader;
+ break;
case SH_NODE_OUTPUT_LINESTYLE:
ntype->draw_buttons = node_buts_output_linestyle;
break;
@@ -1363,7 +1274,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(
layout, C, ptr, "image",
- NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id) return;
imaptr = RNA_pointer_get(ptr, "image");
@@ -1383,7 +1294,7 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 1);
}
-static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
+static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
uiLayout *col, *row;
@@ -1393,7 +1304,7 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
const char *layer_name;
char scene_name[MAX_ID_NAME - 2];
- uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id) return;
@@ -1507,7 +1418,7 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE);
- uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE);
@@ -1875,7 +1786,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
uiItemS(layout);
- uiItemO(layout, IFACE_("Add Input"), ICON_ZOOMIN, "NODE_OT_output_file_add_socket");
+ uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket");
row = uiLayoutRow(layout, false);
col = uiLayoutColumn(row, true);
@@ -1884,13 +1795,13 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
/* using different collection properties if multilayer format is enabled */
if (multilayer) {
uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "layer_slots", ptr, "active_input_index",
- NULL, 0, 0, 0, 0);
+ NULL, 0, 0, 0, 0, false);
RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"),
active_index, &active_input_ptr);
}
else {
uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "file_slots", ptr, "active_input_index",
- NULL, 0, 0, 0, 0);
+ NULL, 0, 0, 0, 0, false);
RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"),
active_index, &active_input_ptr);
}
@@ -2064,7 +1975,7 @@ static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C),
cumap->flag &= ~CUMA_DRAW_SAMPLE;
}
- uiTemplateCurveMapping(layout, ptr, "mapping", 'h', false, false, false);
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'h', false, false, false, false);
}
static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2074,7 +1985,7 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
}
static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2082,7 +1993,7 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point
bNode *node = ptr->data;
PointerRNA clipptr;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id)
return;
@@ -2096,7 +2007,7 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id)
return;
@@ -2120,7 +2031,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (!node->id)
return;
@@ -2281,14 +2192,21 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo
const float cy = y + snode->zoom * backdropHeight * node->custom4;
const float cross_size = 12 * U.pixelsize;
- glColor3f(1.0, 1.0, 1.0);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
- glBegin(GL_LINES);
- glVertex2f(cx - cross_size, cy - cross_size);
- glVertex2f(cx + cross_size, cy + cross_size);
- glVertex2f(cx + cross_size, cy - cross_size);
- glVertex2f(cx - cross_size, cy + cross_size);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, cx - cross_size, cy - cross_size);
+ immVertex2f(pos, cx + cross_size, cy + cross_size);
+ immVertex2f(pos, cx + cross_size, cy - cross_size);
+ immVertex2f(pos, cx - cross_size, cy + cross_size);
+ immEnd();
+
+ immUnbindProgram();
}
}
@@ -2307,9 +2225,6 @@ static void node_composit_backdrop_boxmask(SpaceNode *snode, ImBuf *backdrop, bN
float cx, cy, x1, x2, x3, x4;
float y1, y2, y3, y4;
-
- glColor3f(1.0, 1.0, 1.0);
-
cx = x + snode->zoom * backdropWidth * boxmask->x;
cy = y + snode->zoom * backdropHeight * boxmask->y;
@@ -2322,12 +2237,21 @@ static void node_composit_backdrop_boxmask(SpaceNode *snode, ImBuf *backdrop, bN
y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
- glBegin(GL_LINE_LOOP);
- glVertex2f(x1, y1);
- glVertex2f(x2, y2);
- glVertex2f(x3, y3);
- glVertex2f(x4, y4);
- glEnd();
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x3, y3);
+ immVertex2f(pos, x4, y4);
+ immEnd();
+
+ immUnbindProgram();
}
static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
@@ -2345,9 +2269,6 @@ static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop
float cx, cy, x1, x2, x3, x4;
float y1, y2, y3, y4;
-
- glColor3f(1.0, 1.0, 1.0);
-
cx = x + snode->zoom * backdropWidth * ellipsemask->x;
cy = y + snode->zoom * backdropHeight * ellipsemask->y;
@@ -2360,13 +2281,21 @@ static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop
y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
- glBegin(GL_LINE_LOOP);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x3, y3);
+ immVertex2f(pos, x4, y4);
+ immEnd();
- glVertex2f(x1, y1);
- glVertex2f(x2, y2);
- glVertex2f(x3, y3);
- glVertex2f(x4, y4);
- glEnd();
+ immUnbindProgram();
}
static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2410,7 +2339,7 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "size_source", 0, "", ICON_NONE);
@@ -2431,7 +2360,7 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2467,7 +2396,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
{
bNode *node = ptr->data;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2507,7 +2436,7 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
bNode *node = ptr->data;
NodePlaneTrackDeformData *data = node->storage;
- uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
if (node->id) {
MovieClip *clip = (MovieClip *) node->id;
@@ -2566,8 +2495,8 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C)
static void node_composit_buts_cryptomatte_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
{
- uiItemO(layout, IFACE_("Add Crypto Layer"), ICON_ZOOMIN, "NODE_OT_cryptomatte_layer_add");
- uiItemO(layout, IFACE_("Remove Crypto Layer"), ICON_ZOOMOUT, "NODE_OT_cryptomatte_layer_remove");
+ uiItemO(layout, IFACE_("Add Crypto Layer"), ICON_ADD, "NODE_OT_cryptomatte_layer_add");
+ uiItemO(layout, IFACE_("Remove Crypto Layer"), ICON_REMOVE, "NODE_OT_cryptomatte_layer_remove");
}
static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2584,7 +2513,7 @@ static void node_composit_set_butfunc(bNodeType *ntype)
ntype->draw_buttons_ex = node_composit_buts_image_ex;
break;
case CMP_NODE_R_LAYERS:
- ntype->draw_buttons = node_composit_buts_renderlayers;
+ ntype->draw_buttons = node_composit_buts_viewlayers;
break;
case CMP_NODE_NORMAL:
ntype->draw_buttons = node_buts_normal;
@@ -2908,7 +2837,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe
static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
+ uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false);
}
static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -3078,9 +3007,9 @@ void ED_node_init_butfuncs(void)
} NODE_TYPES_END;
/* tree type icons */
- ntreeType_Composite->ui_icon = ICON_RENDERLAYERS;
- ntreeType_Shader->ui_icon = ICON_MATERIAL;
- ntreeType_Texture->ui_icon = ICON_TEXTURE;
+ ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
+ ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
+ ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
}
void ED_init_custom_node_type(bNodeType *ntype)
@@ -3278,6 +3207,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
{
Main *bmain = CTX_data_main(C);
bNodeInstanceKey active_viewer_key = (snode->nodetree ? snode->nodetree->active_viewer_key : NODE_INSTANCE_KEY_NONE);
+ float shuffle[4] = {0.0f, 0.0f, 0.0f, 0.0f};
Image *ima;
void *lock;
ImBuf *ibuf;
@@ -3293,14 +3223,10 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
if (ibuf) {
float x, y;
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
/* somehow the offset has to be calculated inverse */
-
- glaDefine2DArea(&ar->winrct);
wmOrtho2_region_pixelspace(ar);
x = (ar->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
@@ -3310,60 +3236,37 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
unsigned char *display_buffer = NULL;
void *cache_handle = NULL;
- if (snode->flag & (SNODE_SHOW_R | SNODE_SHOW_G | SNODE_SHOW_B)) {
- int ofs;
+ if (snode->flag & (SNODE_SHOW_R | SNODE_SHOW_G | SNODE_SHOW_B | SNODE_SHOW_ALPHA)) {
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
-#ifdef __BIG_ENDIAN__
- if (snode->flag & SNODE_SHOW_R) ofs = 0;
- else if (snode->flag & SNODE_SHOW_G) ofs = 1;
- else ofs = 2;
-#else
- if (snode->flag & SNODE_SHOW_R) ofs = 1;
- else if (snode->flag & SNODE_SHOW_G) ofs = 2;
- else ofs = 3;
-#endif
-
- glPixelZoom(snode->zoom, snode->zoom);
- /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
-
- glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT,
- display_buffer - (4 - ofs));
+ if (snode->flag & SNODE_SHOW_R)
+ shuffle[0] = 1.0f;
+ else if (snode->flag & SNODE_SHOW_G)
+ shuffle[1] = 1.0f;
+ else if (snode->flag & SNODE_SHOW_B)
+ shuffle[2] = 1.0f;
+ else
+ shuffle[3] = 1.0f;
- glPixelZoom(1.0f, 1.0f);
- }
- else if (snode->flag & SNODE_SHOW_ALPHA) {
- display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
+ GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle);
- glPixelZoom(snode->zoom, snode->zoom);
- /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
-#ifdef __BIG_ENDIAN__
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
-#endif
- glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT, display_buffer);
+ immDrawPixelsTex(&state, x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST,
+ display_buffer, snode->zoom, snode->zoom, NULL);
-#ifdef __BIG_ENDIAN__
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
-#endif
- glPixelZoom(1.0f, 1.0f);
+ GPU_shader_unbind();
}
else if (snode->flag & SNODE_USE_ALPHA) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glPixelZoom(snode->zoom, snode->zoom);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
+ glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST, snode->zoom, snode->zoom);
- glPixelZoom(1.0f, 1.0f);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
else {
- glPixelZoom(snode->zoom, snode->zoom);
-
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
-
- glPixelZoom(1.0f, 1.0f);
+ glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST, snode->zoom, snode->zoom);
}
if (cache_handle)
@@ -3388,30 +3291,33 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
viewer_border->ymin < viewer_border->ymax)
{
rcti pixel_border;
- UI_ThemeColor(TH_ACTIVE);
BLI_rcti_init(&pixel_border,
x + snode->zoom * viewer_border->xmin * ibuf->x,
x + snode->zoom * viewer_border->xmax * ibuf->x,
y + snode->zoom * viewer_border->ymin * ibuf->y,
y + snode->zoom * viewer_border->ymax * ibuf->y);
- glaDrawBorderCorners(&pixel_border, 1.0f, 1.0f);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_ACTIVE);
+
+ immDrawBorderCorners(pos, &pixel_border, 1.0f, 1.0f);
+
+ immUnbindProgram();
}
}
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
}
BKE_image_release_ibuf(ima, ibuf, lock);
}
-
-/* if v2d not NULL, it clips and returns 0 if not visible */
-bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
+/* return quadratic beziers points for a given nodelink and clip if v2d is not NULL. */
+static bool node_link_bezier_handles(View2D *v2d, SpaceNode *snode, bNodeLink *link, float vec[4][2])
{
- float dist, vec[4][2];
+ float dist;
float deltax, deltay;
float cursor[2] = {0.0f, 0.0f};
int toreroute, fromreroute;
@@ -3446,7 +3352,16 @@ bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, flo
}
/* may be called outside of drawing (so pass spacetype) */
- dist = UI_GetThemeValueType(TH_NODE_CURVING, SPACE_NODE) * 0.10f * fabsf(vec[0][0] - vec[3][0]);
+ int curving = UI_GetThemeValueType(TH_NODE_CURVING, SPACE_NODE);
+
+ if (curving == 0) {
+ /* Straight line: align all points. */
+ mid_v2_v2v2(vec[1], vec[0], vec[3]);
+ mid_v2_v2v2(vec[2], vec[1], vec[3]);
+ return 1;
+ }
+
+ dist = curving * 0.10f * fabsf(vec[0][0] - vec[3][0]);
deltax = vec[3][0] - vec[0][0];
deltay = vec[3][1] - vec[0][1];
/* check direction later, for top sockets */
@@ -3479,13 +3394,23 @@ bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, flo
vec[2][0] = vec[3][0] - dist;
vec[2][1] = vec[3][1];
}
+
if (v2d && min_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > v2d->cur.xmax) {
- /* clipped */
+ return 0; /* clipped */
}
else if (v2d && max_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < v2d->cur.xmin) {
- /* clipped */
+ return 0; /* clipped */
}
- else {
+
+ return 1;
+}
+
+/* if v2d not NULL, it clips and returns 0 if not visible */
+bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
+{
+ float vec[4][2];
+
+ if (node_link_bezier_handles(v2d, snode, link, vec)) {
/* always do all three, to prevent data hanging around */
BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0],
coord_array[0] + 0, resol, sizeof(float) * 2);
@@ -3497,186 +3422,242 @@ bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, flo
return 0;
}
+#define NODELINK_GROUP_SIZE 256
#define LINK_RESOL 24
-#define LINK_ARROW 12 /* position of arrow on the link, LINK_RESOL/2 */
-#define ARROW_SIZE (7 * UI_DPI_FAC)
-void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
- int th_col1, bool do_shaded, int th_col2, bool do_triple, int th_col3)
-{
- float coord_array[LINK_RESOL + 1][2];
-
- if (node_link_bezier_points(v2d, snode, link, coord_array, LINK_RESOL)) {
- float dist, spline_step = 0.0f;
- int i;
- int drawarrow;
- /* store current linewidth */
- float linew;
- float arrow[2], arrow1[2], arrow2[2];
- glGetFloatv(GL_LINE_WIDTH, &linew);
-
- /* we can reuse the dist variable here to increment the GL curve eval amount*/
- dist = 1.0f / (float)LINK_RESOL;
-
- glEnable(GL_LINE_SMOOTH);
-
- drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
- (link->fromnode && (link->fromnode->type == NODE_REROUTE)));
-
- if (drawarrow) {
- /* draw arrow in line segment LINK_ARROW */
- float d_xy[2], len;
-
- sub_v2_v2v2(d_xy, coord_array[LINK_ARROW], coord_array[LINK_ARROW - 1]);
- len = len_v2(d_xy);
- mul_v2_fl(d_xy, ARROW_SIZE / len);
- arrow1[0] = coord_array[LINK_ARROW][0] - d_xy[0] + d_xy[1];
- arrow1[1] = coord_array[LINK_ARROW][1] - d_xy[1] - d_xy[0];
- arrow2[0] = coord_array[LINK_ARROW][0] - d_xy[0] - d_xy[1];
- arrow2[1] = coord_array[LINK_ARROW][1] - d_xy[1] + d_xy[0];
- arrow[0] = coord_array[LINK_ARROW][0];
- arrow[1] = coord_array[LINK_ARROW][1];
+#define LINK_WIDTH (2.5f * UI_DPI_FAC)
+#define ARROW_SIZE (7 * UI_DPI_FAC)
+
+static float arrow_verts[3][2] = {{-1.0f, 1.0f}, {0.0f, 0.0f}, {-1.0f, -1.0f}};
+static float arrow_expand_axis[3][2] = {{0.7071f, 0.7071f}, {M_SQRT2, 0.0f}, {0.7071f, -0.7071f}};
+
+static struct {
+ GPUBatch *batch; /* for batching line together */
+ GPUBatch *batch_single; /* for single line */
+ GPUVertBuf *inst_vbo;
+ unsigned int p0_id, p1_id, p2_id, p3_id;
+ unsigned int colid_id;
+ GPUVertBufRaw p0_step, p1_step, p2_step, p3_step;
+ GPUVertBufRaw colid_step;
+ unsigned int count;
+ bool enabled;
+} g_batch_link = {0};
+
+static void nodelink_batch_reset(void)
+{
+ GPU_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p0_id, &g_batch_link.p0_step);
+ GPU_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p1_id, &g_batch_link.p1_step);
+ GPU_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p2_id, &g_batch_link.p2_step);
+ GPU_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p3_id, &g_batch_link.p3_step);
+ GPU_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.colid_id, &g_batch_link.colid_step);
+ g_batch_link.count = 0;
+}
+
+static void set_nodelink_vertex(
+ GPUVertBuf *vbo,
+ unsigned int uv_id, unsigned int pos_id, unsigned int exp_id, unsigned int v,
+ const unsigned char uv[2], const float pos[2], const float exp[2])
+{
+ GPU_vertbuf_attr_set(vbo, uv_id, v, uv);
+ GPU_vertbuf_attr_set(vbo, pos_id, v, pos);
+ GPU_vertbuf_attr_set(vbo, exp_id, v, exp);
+}
+
+static void nodelink_batch_init(void)
+{
+ GPUVertFormat format = {0};
+ uint uv_id = GPU_vertformat_attr_add(&format, "uv", GPU_COMP_U8, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ uint pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint expand_id = GPU_vertformat_attr_add(&format, "expand", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC);
+ int vcount = LINK_RESOL * 2; /* curve */
+ vcount += 2; /* restart strip */
+ vcount += 3 * 2; /* arrow */
+ vcount *= 2; /* shadow */
+ vcount += 2; /* restart strip */
+ GPU_vertbuf_data_alloc(vbo, vcount);
+ int v = 0;
+
+ for (int k = 0; k < 2; ++k) {
+ unsigned char uv[2] = {0, 0};
+ float pos[2] = {0.0f, 0.0f};
+ float exp[2] = {0.0f, 1.0f};
+
+ /* restart */
+ if (k == 1)
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+ /* curve strip */
+ for (int i = 0; i < LINK_RESOL; ++i) {
+ uv[0] = 255 * (i / (float)(LINK_RESOL - 1));
+ uv[1] = 0;
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+ uv[1] = 255;
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
}
- if (do_triple) {
- UI_ThemeColorShadeAlpha(th_col3, -80, -120);
- glLineWidth(4.0f);
-
- glBegin(GL_LINE_STRIP);
- for (i = 0; i <= LINK_RESOL; i++) {
- glVertex2fv(coord_array[i]);
- }
- glEnd();
- if (drawarrow) {
- glBegin(GL_LINE_STRIP);
- glVertex2fv(arrow1);
- glVertex2fv(arrow);
- glVertex2fv(arrow2);
- glEnd();
- }
+ /* restart */
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+ uv[0] = 127;
+ uv[1] = 0;
+ copy_v2_v2(pos, arrow_verts[0]);
+ copy_v2_v2(exp, arrow_expand_axis[0]);
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+ /* arrow */
+ for (int i = 0; i < 3; ++i) {
+ uv[1] = 0;
+ copy_v2_v2(pos, arrow_verts[i]);
+ copy_v2_v2(exp, arrow_expand_axis[i]);
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+ uv[1] = 255;
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
}
- /* XXX using GL_LINES for shaded node lines is a workaround
- * for Intel hardware, this breaks with GL_LINE_STRIP and
- * changing color in begin/end blocks.
- */
- glLineWidth(1.5f);
- if (do_shaded) {
- glBegin(GL_LINES);
- for (i = 0; i < LINK_RESOL; i++) {
- UI_ThemeColorBlend(th_col1, th_col2, spline_step);
- glVertex2fv(coord_array[i]);
-
- UI_ThemeColorBlend(th_col1, th_col2, spline_step + dist);
- glVertex2fv(coord_array[i + 1]);
-
- spline_step += dist;
- }
- glEnd();
- }
- else {
- UI_ThemeColor(th_col1);
- glBegin(GL_LINE_STRIP);
- for (i = 0; i <= LINK_RESOL; i++) {
- glVertex2fv(coord_array[i]);
- }
- glEnd();
- }
+ /* restart */
+ if (k == 0)
+ set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+ }
- if (drawarrow) {
- glBegin(GL_LINE_STRIP);
- glVertex2fv(arrow1);
- glVertex2fv(arrow);
- glVertex2fv(arrow2);
- glEnd();
- }
+ g_batch_link.batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ gpu_batch_presets_register(g_batch_link.batch);
- glDisable(GL_LINE_SMOOTH);
- }
+ g_batch_link.batch_single = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, 0);
+ gpu_batch_presets_register(g_batch_link.batch_single);
+
+ /* Instances data */
+ GPUVertFormat format_inst = {0};
+ g_batch_link.p0_id = GPU_vertformat_attr_add(&format_inst, "P0", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ g_batch_link.p1_id = GPU_vertformat_attr_add(&format_inst, "P1", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ g_batch_link.p2_id = GPU_vertformat_attr_add(&format_inst, "P2", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ g_batch_link.p3_id = GPU_vertformat_attr_add(&format_inst, "P3", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ g_batch_link.colid_id = GPU_vertformat_attr_add(&format_inst, "colid_doarrow", GPU_COMP_U8, 4, GPU_FETCH_INT);
+ g_batch_link.inst_vbo = GPU_vertbuf_create_with_format_ex(&format_inst, GPU_USAGE_STREAM);
+ GPU_vertbuf_data_alloc(g_batch_link.inst_vbo, NODELINK_GROUP_SIZE); /* Alloc max count but only draw the range we need. */
+
+ GPU_batch_instbuf_set(g_batch_link.batch, g_batch_link.inst_vbo, true);
+
+ nodelink_batch_reset();
}
-#if 0 /* not used in 2.5x yet */
-static void node_link_straight_points(View2D *UNUSED(v2d), SpaceNode *snode, bNodeLink *link, float coord_array[][2])
+static char nodelink_get_color_id(int th_col)
{
- if (link->fromsock) {
- coord_array[0][0] = link->fromsock->locx;
- coord_array[0][1] = link->fromsock->locy;
- }
- else {
- if (snode == NULL) return;
- coord_array[0][0] = snode->mx;
- coord_array[0][1] = snode->my;
- }
- if (link->tosock) {
- coord_array[1][0] = link->tosock->locx;
- coord_array[1][1] = link->tosock->locy;
- }
- else {
- if (snode == NULL) return;
- coord_array[1][0] = snode->mx;
- coord_array[1][1] = snode->my;
+ switch (th_col) {
+ case TH_WIRE: return 1;
+ case TH_WIRE_INNER: return 2;
+ case TH_ACTIVE: return 3;
+ case TH_EDGE_SELECT: return 4;
+ case TH_REDALERT: return 5;
}
+ return 0;
+}
+
+static void nodelink_batch_draw(SpaceNode *snode)
+{
+ if (g_batch_link.count == 0)
+ return;
+
+ GPU_blend(true);
+
+ float colors[6][4] = {{0.0f}};
+ UI_GetThemeColor4fv(TH_WIRE_INNER, colors[nodelink_get_color_id(TH_WIRE_INNER)]);
+ UI_GetThemeColor4fv(TH_WIRE, colors[nodelink_get_color_id(TH_WIRE)]);
+ UI_GetThemeColor4fv(TH_ACTIVE, colors[nodelink_get_color_id(TH_ACTIVE)]);
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, colors[nodelink_get_color_id(TH_EDGE_SELECT)]);
+ UI_GetThemeColor4fv(TH_REDALERT, colors[nodelink_get_color_id(TH_REDALERT)]);
+
+ GPU_vertbuf_vertex_count_set(g_batch_link.inst_vbo, g_batch_link.count);
+ GPU_vertbuf_use(g_batch_link.inst_vbo); /* force update. */
+
+ GPU_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST);
+ GPU_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, (float *)colors);
+ GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode->aspect * LINK_WIDTH);
+ GPU_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE);
+ GPU_batch_draw(g_batch_link.batch);
+
+ nodelink_batch_reset();
+
+ GPU_blend(false);
}
-void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link,
- int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3)
+void nodelink_batch_start(SpaceNode *UNUSED(snode))
{
- float coord_array[2][2];
- int i;
+ g_batch_link.enabled = true;
+}
- node_link_straight_points(v2d, snode, link, coord_array);
+void nodelink_batch_end(SpaceNode *snode)
+{
+ nodelink_batch_draw(snode);
+ g_batch_link.enabled = false;
+}
- glEnable(GL_LINE_SMOOTH);
+static void nodelink_batch_add_link(
+ SpaceNode *snode,
+ const float p0[2], const float p1[2], const float p2[2], const float p3[2],
+ int th_col1, int th_col2, int th_col3, bool drawarrow)
+{
+ /* Only allow these colors. If more is needed, you need to modify the shader accordingly. */
+ BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
+ BLI_assert(ELEM(th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
+ BLI_assert(ELEM(th_col3, TH_WIRE, -1));
- if (do_triple) {
- UI_ThemeColorShadeAlpha(th_col3, -80, -120);
- glLineWidth(4.0f);
+ g_batch_link.count++;
+ copy_v2_v2(GPU_vertbuf_raw_step(&g_batch_link.p0_step), p0);
+ copy_v2_v2(GPU_vertbuf_raw_step(&g_batch_link.p1_step), p1);
+ copy_v2_v2(GPU_vertbuf_raw_step(&g_batch_link.p2_step), p2);
+ copy_v2_v2(GPU_vertbuf_raw_step(&g_batch_link.p3_step), p3);
+ char *colid = GPU_vertbuf_raw_step(&g_batch_link.colid_step);
+ colid[0] = nodelink_get_color_id(th_col1);
+ colid[1] = nodelink_get_color_id(th_col2);
+ colid[2] = nodelink_get_color_id(th_col3);
+ colid[3] = drawarrow;
- glBegin(GL_LINES);
- glVertex2fv(coord_array[0]);
- glVertex2fv(coord_array[1]);
- glEnd();
+ if (g_batch_link.count == NODELINK_GROUP_SIZE) {
+ nodelink_batch_draw(snode);
}
+}
- UI_ThemeColor(th_col1);
- glLineWidth(1.5f);
+/* don't do shadows if th_col3 is -1. */
+void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
+ int th_col1, int th_col2, int th_col3)
+{
+ float vec[4][2];
- /* XXX using GL_LINES for shaded node lines is a workaround
- * for Intel hardware, this breaks with GL_LINE_STRIP and
- * changing color in begin/end blocks.
- */
- if (do_shaded) {
- glBegin(GL_LINES);
- for (i = 0; i < LINK_RESOL - 1; ++i) {
- float t = (float)i / (float)(LINK_RESOL - 1);
- UI_ThemeColorBlend(th_col1, th_col2, t);
- glVertex2f((1.0f - t) * coord_array[0][0] + t * coord_array[1][0],
- (1.0f - t) * coord_array[0][1] + t * coord_array[1][1]);
-
- t = (float)(i + 1) / (float)(LINK_RESOL - 1);
- UI_ThemeColorBlend(th_col1, th_col2, t);
- glVertex2f((1.0f - t) * coord_array[0][0] + t * coord_array[1][0],
- (1.0f - t) * coord_array[0][1] + t * coord_array[1][1]);
+ if (node_link_bezier_handles(v2d, snode, link, vec)) {
+ int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
+ (link->fromnode && (link->fromnode->type == NODE_REROUTE)));
+
+ if (g_batch_link.batch == NULL) {
+ nodelink_batch_init();
}
- glEnd();
- }
- else {
- glBegin(GL_LINE_STRIP);
- for (i = 0; i < LINK_RESOL; ++i) {
- float t = (float)i / (float)(LINK_RESOL - 1);
- glVertex2f((1.0f - t) * coord_array[0][0] + t * coord_array[1][0],
- (1.0f - t) * coord_array[0][1] + t * coord_array[1][1]);
+
+ if (g_batch_link.enabled) {
+ /* Add link to batch. */
+ nodelink_batch_add_link(snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow);
+ }
+ else {
+ /* Draw single link. */
+ float colors[3][4] = {{0.0f}};
+ if (th_col3 != -1) {
+ UI_GetThemeColor4fv(th_col3, colors[0]);
+ }
+ UI_GetThemeColor4fv(th_col1, colors[1]);
+ UI_GetThemeColor4fv(th_col2, colors[2]);
+
+ GPUBatch *batch = g_batch_link.batch_single;
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
+ GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, (float *)vec);
+ GPU_batch_uniform_4fv_array(batch, "colors", 3, (float *)colors);
+ GPU_batch_uniform_1f(batch, "expandSize", snode->aspect * LINK_WIDTH);
+ GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
+ GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
+ GPU_batch_draw(batch);
}
- glEnd();
}
-
- glDisable(GL_LINE_SMOOTH);
}
-#endif
/* note; this is used for fake links in groups too */
void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
{
- bool do_shaded = false;
- bool do_triple = false;
int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE;
if (link->fromsock == NULL && link->tosock == NULL)
@@ -3684,8 +3665,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
/* new connection */
if (!link->fromsock || !link->tosock) {
- th_col1 = TH_ACTIVE;
- do_triple = true;
+ th_col1 = th_col2 = TH_ACTIVE;
}
else {
/* going to give issues once... */
@@ -3706,39 +3686,38 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
if (link->tonode && link->tonode->flag & SELECT)
th_col2 = TH_EDGE_SELECT;
}
- do_shaded = true;
- do_triple = true;
}
else {
- th_col1 = TH_REDALERT;
+ th_col1 = th_col2 = TH_REDALERT;
+ // th_col3 = -1; /* no shadow */
}
}
- node_draw_link_bezier(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
+ node_draw_link_bezier(v2d, snode, link, th_col1, th_col2, th_col3);
// node_draw_link_straight(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
}
-void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border)
+void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned pos)
{
- glBegin(GL_LINES);
+ immBegin(GPU_PRIM_LINES, 4);
if (border & (NODE_LEFT | NODE_RIGHT)) {
- glVertex2f(cent[0], v2d->cur.ymin);
- glVertex2f(cent[0], v2d->cur.ymax);
+ immVertex2f(pos, cent[0], v2d->cur.ymin);
+ immVertex2f(pos, cent[0], v2d->cur.ymax);
}
else {
- glVertex2f(cent[0], cent[1] - size);
- glVertex2f(cent[0], cent[1] + size);
+ immVertex2f(pos, cent[0], cent[1] - size);
+ immVertex2f(pos, cent[0], cent[1] + size);
}
if (border & (NODE_TOP | NODE_BOTTOM)) {
- glVertex2f(v2d->cur.xmin, cent[1]);
- glVertex2f(v2d->cur.xmax, cent[1]);
+ immVertex2f(pos, v2d->cur.xmin, cent[1]);
+ immVertex2f(pos, v2d->cur.xmax, cent[1]);
}
else {
- glVertex2f(cent[0] - size, cent[1]);
- glVertex2f(cent[0] + size, cent[1]);
+ immVertex2f(pos, cent[0] - size, cent[1]);
+ immVertex2f(pos, cent[0] + size, cent[1]);
}
- glEnd();
+ immEnd();
}
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 3ae909041c2..8f6a0f5c4e2 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -317,10 +317,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
switch (snode->nodetree->type) {
case NTREE_SHADER:
- if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C)))
- type = SH_NODE_TEX_IMAGE;
- else
- type = SH_NODE_TEXTURE;
+ type = SH_NODE_TEX_IMAGE;
break;
case NTREE_TEXTURE:
type = TEX_NODE_IMAGE;
@@ -341,14 +338,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (type == SH_NODE_TEXTURE) {
- Tex *tex = BKE_texture_add(CTX_data_main(C), DATA_(ima->id.name));
- tex->ima = ima;
- node->id = (ID *)tex;
- WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, node->id);
- }
- else
- node->id = (ID *)ima;
+ node->id = (ID *)ima;
/* When adding new image file via drag-drop we need to load imbuf in order
* to get proper image source.
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index 6104761eb49..0a913bcbea8 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -150,14 +150,14 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
ot = WM_operatortype_find("NODE_OT_tree_socket_add", false);
uiItemL(col, IFACE_("Inputs:"), ICON_NONE);
uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input",
- NULL, 0, 0, 0, 0);
+ NULL, 0, 0, 0, 0, false);
uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
RNA_enum_set(&opptr, "in_out", SOCK_IN);
col = uiLayoutColumn(split, true);
uiItemL(col, IFACE_("Outputs:"), ICON_NONE);
uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output",
- NULL, 0, 0, 0, 0);
+ NULL, 0, 0, 0, 0, false);
uiItemFullO_ptr(col, ot, "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr);
RNA_enum_set(&opptr, "in_out", SOCK_OUT);
@@ -224,7 +224,7 @@ static bool node_properties_poll(bContext *C)
void NODE_OT_properties(wmOperatorType *ot)
{
- ot->name = "Properties";
+ ot->name = "Toggle Sidebar";
ot->description = "Toggle the properties region visibility";
ot->idname = "NODE_OT_properties";
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 9a7d913f24e..8ec6d9332d3 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -44,16 +44,23 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "DEG_depsgraph.h"
+
#include "BLF_api.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+#include "GPU_framebuffer.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -128,10 +135,10 @@ void ED_node_tag_update_id(ID *id)
* all the users of this tree will have update
* flushed from the tree,
*/
- DAG_id_tag_update(&ntree->id, 0);
+ DEG_id_tag_update(&ntree->id, 0);
if (ntree->type == NTREE_SHADER) {
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
if (GS(id->name) == ID_MA)
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
@@ -144,12 +151,12 @@ void ED_node_tag_update_id(ID *id)
WM_main_add_notifier(NC_SCENE | ND_NODES, id);
}
else if (ntree->type == NTREE_TEXTURE) {
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
}
else if (id == &ntree->id) {
/* node groups */
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
}
}
@@ -615,113 +622,24 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
{
bNodeLink *link;
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ GPU_blend(true);
for (link = node->internal_links.first; link; link = link->next)
- node_draw_link_bezier(v2d, snode, link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
+ node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+ GPU_blend(false);
}
-static void node_socket_shape_draw(
- float x, float y, float size, const float col[4], bool highlight,
- const float coords[][2], int coords_len)
+static void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, PointerRNA node_ptr, bNodeSocket *sock, unsigned pos, unsigned col)
{
- int a;
-
- glColor4fv(col);
-
- glEnable(GL_BLEND);
- glBegin(GL_POLYGON);
- for (a = 0; a < coords_len; a++) {
- glVertex2f(x + size * coords[a][0], y + size * coords[a][1]);
- }
- glEnd();
- glDisable(GL_BLEND);
-
- if (highlight) {
- UI_ThemeColor(TH_TEXT_HI);
- glLineWidth(1.5f);
- }
- else {
- glColor4ub(0, 0, 0, 150);
- }
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
- glBegin(GL_LINE_LOOP);
- for (a = 0; a < coords_len; a++) {
- glVertex2f(x + size * coords[a][0], y + size * coords[a][1]);
- }
- glEnd();
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
-}
-
-
-void node_socket_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, bool highlight)
-{
- PointerRNA ptr, node_ptr;
+ PointerRNA ptr;
float color[4];
RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
- RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
- /* 16 values of {sin, cos} function */
- const float shape_circle[16][2] = {
- {0.00000000f, 1.00000000f},
- {0.39435585f, 0.91895781f},
- {0.72479278f, 0.68896691f},
- {0.93775213f, 0.34730525f},
- {0.99871650f, -0.05064916f},
- {0.89780453f, -0.44039415f},
- {0.65137248f, -0.75875812f},
- {0.29936312f, -0.95413925f},
- {-0.10116832f, -0.99486932f},
- {-0.48530196f, -0.87434661f},
- {-0.79077573f, -0.61210598f},
- {-0.96807711f, -0.25065253f},
- {-0.98846832f, 0.15142777f},
- {-0.84864425f, 0.52896401f},
- {-0.57126821f, 0.82076344f},
- {-0.20129852f, 0.97952994f }
- };
-
- const float shape_diamond[4][2] = {
- {0.0f, 1.2f},
- {1.2f, 0.0f},
- {0.0f, -1.2f},
- {-1.2f, 0.0f},
- };
-
- const float shape_square[4][2] = {
- {-0.9f, 0.9f},
- {0.9f, 0.9f},
- {0.9f, -0.9f},
- {-0.9f, -0.9f},
- };
-
- const float (*shape)[2];
- int shape_len;
- switch (sock->draw_shape) {
- default:
- case SOCK_DRAW_SHAPE_CIRCLE:
- shape = shape_circle;
- shape_len = ARRAY_SIZE(shape_circle);
- break;
- case SOCK_DRAW_SHAPE_DIAMOND:
- shape = shape_diamond;
- shape_len = ARRAY_SIZE(shape_diamond);
- break;
- case SOCK_DRAW_SHAPE_SQUARE:
- shape = shape_square;
- shape_len = ARRAY_SIZE(shape_square);
- break;
- }
-
- node_socket_shape_draw(sock->locx, sock->locy, size, color, highlight, shape, shape_len);
+ immAttr4fv(col, color);
+ immVertex2f(pos, sock->locx, sock->locy);
}
/* ************** Socket callbacks *********** */
@@ -730,10 +648,15 @@ static void node_draw_preview_background(float tile, rctf *rect)
{
float x, y;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* draw checkerboard backdrop to show alpha */
- glColor3ub(120, 120, 120);
- glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glColor3ub(160, 160, 160);
+ immUniformColor3ub(120, 120, 120);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ immUniformColor3ub(160, 160, 160);
for (y = rect->ymin; y < rect->ymax; y += tile * 2) {
for (x = rect->xmin; x < rect->xmax; x += tile * 2) {
@@ -744,7 +667,7 @@ static void node_draw_preview_background(float tile, rctf *rect)
if (y + tile > rect->ymax)
tiley = rect->ymax - y;
- glRectf(x, y, x + tilex, y + tiley);
+ immRectf(pos, x, y, x + tilex, y + tiley);
}
}
for (y = rect->ymin + tile; y < rect->ymax; y += tile * 2) {
@@ -756,9 +679,10 @@ static void node_draw_preview_background(float tile, rctf *rect)
if (y + tile > rect->ymax)
tiley = rect->ymax - y;
- glRectf(x, y, x + tilex, y + tiley);
+ immRectf(pos, x, y, x + tilex, y + tiley);
}
}
+ immUnbindProgram();
}
/* not a callback */
@@ -788,18 +712,20 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
node_draw_preview_background(BLI_rctf_size_x(prv) / 10.0f, &draw_rect);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* premul graphics */
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); /* premul graphics */
- glColor4f(1.0, 1.0, 1.0, 1.0);
- glPixelZoom(scale, scale);
- glaDrawPixelsTex(draw_rect.xmin, draw_rect.ymin, preview->xsize, preview->ysize, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect);
- glPixelZoom(1.0f, 1.0f);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(&state, draw_rect.xmin, draw_rect.ymin, preview->xsize, preview->ysize, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect,
+ scale, scale, NULL);
- glDisable(GL_BLEND);
+ GPU_blend(false);
- UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
- fdrawbox(draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_BACK, -15, +100);
+ imm_draw_box_wire_2d(pos, draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
+ immUnbindProgram();
}
/* common handle function for operator buttons that need to select the node first */
@@ -824,32 +750,139 @@ void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
else {
const float margin = 3.0f;
- glColor4f(0.0f, 0.0f, 0.0f, 0.33f);
- glEnable(GL_BLEND);
- UI_draw_roundbox(rct->xmin - margin, rct->ymin - margin,
- rct->xmax + margin, rct->ymax + margin, radius + margin);
- glDisable(GL_BLEND);
+ float color[4] = {0.0f, 0.0f, 0.0f, 0.33f};
+ UI_draw_roundbox_aa(true, rct->xmin - margin, rct->ymin - margin,
+ rct->xmax + margin, rct->ymax + margin, radius + margin, color);
+ }
+}
+
+void node_draw_sockets(View2D *v2d, const bContext *C, bNodeTree *ntree, bNode *node, bool draw_outputs, bool select_all)
+{
+ const uint total_input_len = BLI_listbase_count(&node->inputs);
+ const uint total_output_len = BLI_listbase_count(&node->outputs);
+
+ if (total_input_len + total_output_len == 0) {
+ return;
+ }
+
+ PointerRNA node_ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
+
+ float scale;
+ UI_view2d_scale_get(v2d, &scale, NULL);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ GPU_blend(true);
+ GPU_enable_program_point_size();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA);
+
+ /* set handle size */
+ immUniform1f("size", 2.0f * NODE_SOCKSIZE * scale); /* 2 * size to have diameter */
+
+ if (!select_all) {
+ /* outline for unselected sockets */
+ immUniform1f("outlineWidth", 1.0f);
+ immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 0.6f);
+
+ immBeginAtMost(GPU_PRIM_POINTS, total_input_len + total_output_len);
+ }
+
+ /* socket inputs */
+ short selected_input_len = 0;
+ bNodeSocket *sock;
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (nodeSocketIsHidden(sock))
+ continue;
+ if (select_all || (sock->flag & SELECT)) {
+ ++selected_input_len;
+ continue;
+ }
+
+ node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
+ }
+
+ /* socket outputs */
+ short selected_output_len = 0;
+ if (draw_outputs) {
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ if (nodeSocketIsHidden(sock))
+ continue;
+ if (select_all || (sock->flag & SELECT)) {
+ ++selected_output_len;
+ continue;
+ }
+
+ node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
+ }
+ }
+
+ if (!select_all) {
+ immEnd();
}
+
+ /* go back and draw selected sockets */
+ if (selected_input_len + selected_output_len > 0) {
+ /* outline for selected sockets */
+ float c[3];
+ UI_GetThemeColor3fv(TH_TEXT_HI, c);
+ immUniform4f("outlineColor", c[0], c[1], c[2], 1.0f);
+ immUniform1f("outlineWidth", 1.5f);
+
+ immBegin(GPU_PRIM_POINTS, selected_input_len + selected_output_len);
+
+ if (selected_input_len) {
+ /* socket inputs */
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (nodeSocketIsHidden(sock))
+ continue;
+ if (select_all || (sock->flag & SELECT)) {
+ node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
+ if (--selected_input_len == 0)
+ break; /* stop as soon as last one is drawn */
+ }
+ }
+ }
+
+ if (selected_output_len) {
+ /* socket outputs */
+ for (sock = node->outputs.first; sock; sock = sock->next) {
+ if (nodeSocketIsHidden(sock))
+ continue;
+ if (select_all || (sock->flag & SELECT)) {
+ node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
+ if (--selected_output_len == 0)
+ break; /* stop as soon as last one is drawn */
+ }
+ }
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+
+ GPU_disable_program_point_size();
+ GPU_blend(false);
}
static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key)
{
bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data;
- bNodeSocket *sock;
rctf *rct = &node->totr;
float iconofs;
/* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
float iconbutw = 0.8f * UI_UNIT_X;
int color_id = node_get_colorid(node);
+ float color[4];
char showname[128]; /* 128 used below */
View2D *v2d = &ar->v2d;
- /* XXX hack: copy values from linked ID data where displayed as sockets */
- if (node->block)
- nodeSynchronizeID(node, false);
-
/* skip if out of view */
- if (BLI_rctf_isect(&node->totr, &ar->v2d.cur, NULL) == false) {
+ if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) {
UI_block_end(C, node->block);
node->block = NULL;
return;
@@ -858,23 +891,24 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
/* shadow */
node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
- /* header uses color from backdrop, but we make it opaqie */
- if (color_id == TH_NODE) {
- float col[3];
- UI_GetThemeColorShade3fv(color_id, -20, col);
- glColor4f(col[0], col[1], col[2], 1.0f);
+ if (node->flag & NODE_MUTED) {
+ UI_GetThemeColorBlendShade4fv(color_id, TH_REDALERT, 0.5f, 0, color);
+ }
+ else {
+ /* header uses color from backdrop, but we make it opaque */
+ if (color_id == TH_NODE) {
+ UI_GetThemeColorShade3fv(color_id, -20, color);
+ color[3] = 1.0f;
+ }
+ else {
+ UI_GetThemeColor4fv(color_id, color);
+ }
}
- else
- UI_ThemeColor(color_id);
-
- if (node->flag & NODE_MUTED)
- UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
-
- glLineWidth(1.0f);
+ GPU_line_width(1.0f);
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
- UI_draw_roundbox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
+ UI_draw_roundbox_aa(true, rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD, color);
/* show/hide icons */
iconofs = rct->xmax - 0.35f * U.widget_unit;
@@ -907,35 +941,30 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
}
/* title */
- if (node->flag & SELECT)
- UI_ThemeColor(TH_SELECT);
- else
- UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
+ if (node->flag & SELECT) {
+ UI_GetThemeColor4fv(TH_SELECT, color);
+ }
+ else {
+ UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
+ }
/* open/close entirely? */
{
uiBut *but;
- int but_size = UI_UNIT_X * 0.6f;
+ int but_size = UI_UNIT_X * 1.2f;
/* XXX button uses a custom triangle draw below, so make it invisible without icon */
UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
but = uiDefBut(node->block, UI_BTYPE_BUT_TOGGLE, B_REDR, "",
- rct->xmin + 0.5f * U.widget_unit - but_size / 2, rct->ymax - NODE_DY / 2.0f - but_size / 2,
+ rct->xmin + 0.6f * U.widget_unit - but_size / 2, rct->ymax - NODE_DY / 2.2f - but_size / 2,
but_size, but_size, NULL, 0, 0, 0, 0, "");
UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_GetThemeColor4fv(TH_TEXT, color);
/* custom draw function for this button */
- UI_draw_icon_tri(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v');
+ UI_draw_icon_tri(rct->xmin + 0.6f * U.widget_unit, rct->ymax - NODE_DY / 2.2f, 'v', color);
}
- /* this isn't doing anything for the label, so commenting out */
-#if 0
- if (node->flag & SELECT)
- UI_ThemeColor(TH_TEXT_HI);
- else
- UI_ThemeColor(TH_TEXT);
-#endif
-
nodeLabel(ntree, node, showname, sizeof(showname));
//if (node->flag & NODE_MUTED)
@@ -948,54 +977,29 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
/* body */
if (!nodeIsRegistered(node))
- UI_ThemeColor4(TH_REDALERT); /* use warning color to indicate undefined types */
- else if (node->flag & NODE_CUSTOM_COLOR)
- glColor3fv(node->color);
+ UI_GetThemeColor4fv(TH_REDALERT, color); /* use warning color to indicate undefined types */
+ else if (node->flag & NODE_CUSTOM_COLOR) {
+ rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
+ }
else
- UI_ThemeColor4(TH_NODE);
- glEnable(GL_BLEND);
+ UI_GetThemeColor4fv(TH_NODE, color);
+
UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
- UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD);
- glDisable(GL_BLEND);
+ UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD, color);
/* outline active and selected emphasis */
if (node->flag & SELECT) {
-
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
-
- if (node->flag & NODE_ACTIVE)
- UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
- else
- UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
+ UI_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
-
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
}
/* disable lines */
if (node->flag & NODE_MUTED)
node_draw_mute_line(v2d, snode, node);
-
- /* socket inputs, buttons */
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (nodeSocketIsHidden(sock))
- continue;
-
- node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
- }
-
- /* socket outputs */
- for (sock = node->outputs.first; sock; sock = sock->next) {
- if (nodeSocketIsHidden(sock))
- continue;
-
- node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
- }
+ node_draw_sockets(v2d, C, ntree, node, true, false);
/* preview */
if (node->flag & NODE_PREVIEW && previews) {
@@ -1016,61 +1020,58 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key))
{
- bNodeSocket *sock;
rctf *rct = &node->totr;
float dx, centy = BLI_rctf_cent_y(rct);
float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
- float socket_size = NODE_SOCKSIZE;
int color_id = node_get_colorid(node);
+ float color[4];
char showname[128]; /* 128 is used below */
+ View2D *v2d = &ar->v2d;
+ float scale;
+
+ UI_view2d_scale_get(v2d, &scale, NULL);
/* shadow */
node_draw_shadow(snode, node, hiddenrad, 1.0f);
/* body */
- UI_ThemeColor(color_id);
if (node->flag & NODE_MUTED)
- UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
+ UI_GetThemeColorBlendShade4fv(color_id, TH_REDALERT, 0.5f, 0, color);
+ else
+ UI_GetThemeColor4fv(color_id, color);
- UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
+ UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
/* outline active and selected emphasis */
if (node->flag & SELECT) {
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ UI_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
- if (node->flag & NODE_ACTIVE)
- UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
- else
- UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
-
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
}
/* custom color inline */
if (node->flag & NODE_CUSTOM_COLOR) {
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ GPU_blend(true);
+ GPU_line_smooth(true);
- glColor3fv(node->color);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad);
+ UI_draw_roundbox_3fvAlpha(false, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad, node->color, 1.0f);
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ GPU_line_smooth(false);
+ GPU_blend(false);
}
/* title */
- if (node->flag & SELECT)
- UI_ThemeColor(TH_SELECT);
- else
- UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
+ if (node->flag & SELECT) {
+ UI_GetThemeColor4fv(TH_SELECT, color);
+ }
+ else {
+ UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
+ }
/* open entirely icon */
{
uiBut *but;
- int but_size = UI_UNIT_X * 0.6f;
+ int but_size = UI_UNIT_X * 1.2f;
/* XXX button uses a custom triangle draw below, so make it invisible without icon */
UI_block_emboss_set(node->block, UI_EMBOSS_NONE);
but = uiDefBut(node->block, UI_BTYPE_BUT_TOGGLE, B_REDR, "",
@@ -1079,19 +1080,15 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle");
UI_block_emboss_set(node->block, UI_EMBOSS);
+ UI_GetThemeColor4fv(TH_TEXT, color);
/* custom draw function for this button */
- UI_draw_icon_tri(rct->xmin + 10.0f, centy, 'h');
+ UI_draw_icon_tri(rct->xmin + 10.0f, centy, 'h', color);
}
/* disable lines */
if (node->flag & NODE_MUTED)
node_draw_mute_line(&ar->v2d, snode, node);
- if (node->flag & SELECT)
- UI_ThemeColor(TH_SELECT);
- else
- UI_ThemeColor(TH_TEXT);
-
if (node->miniwidth > 0.0f) {
nodeLabel(ntree, node, showname, sizeof(showname));
@@ -1105,28 +1102,34 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
}
/* scale widget thing */
- UI_ThemeColorShade(color_id, -10);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColorShade(color_id, -10);
dx = 10.0f;
- fdrawline(rct->xmax - dx, centy - 4.0f, rct->xmax - dx, centy + 4.0f);
- fdrawline(rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
- UI_ThemeColorShade(color_id, +30);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
+ immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
+
+ immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
+ immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
+ immEnd();
+
+ immUniformThemeColorShade(color_id, 30);
dx -= snode->aspect;
- fdrawline(rct->xmax - dx, centy - 4.0f, rct->xmax - dx, centy + 4.0f);
- fdrawline(rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
- /* sockets */
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock)) {
- node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
- }
- }
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
+ immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
- for (sock = node->outputs.first; sock; sock = sock->next) {
- if (!nodeSocketIsHidden(sock)) {
- node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
- }
- }
+ immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
+ immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+ node_draw_sockets(v2d, C, ntree, node, true, false);
UI_block_end(C, node->block);
UI_block_draw(C, node->block);
@@ -1240,14 +1243,14 @@ void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeT
}
/* node lines */
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ GPU_blend(true);
+ nodelink_batch_start(snode);
for (link = ntree->links.first; link; link = link->next) {
if (!nodeLinkIsHidden(link))
node_draw_link(&ar->v2d, snode, link);
}
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ nodelink_batch_end(snode);
+ GPU_blend(false);
/* draw foreground nodes, last nodes in front */
for (a = 0, node = ntree->nodes.first; node; node = node->next, a++) {
@@ -1268,7 +1271,7 @@ static void draw_tree_path(SpaceNode *snode)
ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info));
- UI_ThemeColor(TH_TEXT_HI);
+ UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
BLF_draw_default(1.5f * UI_UNIT_X, 1.5f * UI_UNIT_Y, 0.0f, info, sizeof(info));
}
@@ -1301,13 +1304,15 @@ static void draw_group_overlay(const bContext *C, ARegion *ar)
View2D *v2d = &ar->v2d;
rctf rect = v2d->cur;
uiBlock *block;
+ float color[4];
/* shade node groups to separate them visually */
- UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
- glEnable(GL_BLEND);
+ GPU_blend(true);
+
+ UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, -70, color);
UI_draw_roundbox_corner_set(UI_CNR_NONE);
- UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0);
- glDisable(GL_BLEND);
+ UI_draw_roundbox_4fv(true, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0, color);
+ GPU_blend(false);
/* set the block bounds to clip mouse events from underlying nodes */
block = UI_block_begin(C, ar, "node tree bounds block", UI_EMBOSS);
@@ -1324,7 +1329,7 @@ void drawnodespace(const bContext *C, ARegion *ar)
View2D *v2d = &ar->v2d;
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -1337,8 +1342,7 @@ void drawnodespace(const bContext *C, ARegion *ar)
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
/* only set once */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_MAP1_VERTEX_3);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
/* nodes */
snode_set_context(C);
@@ -1399,18 +1403,33 @@ void drawnodespace(const bContext *C, ARegion *ar)
/* backdrop */
draw_nodespace_back_pix(C, ar, snode, path->parent_key);
+ {
+ float original_proj[4][4];
+ GPU_matrix_projection_get(original_proj);
+
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+
+ wmOrtho2_pixelspace(ar->winx, ar->winy);
+
+ WM_gizmomap_draw(ar->gizmo_map, C, WM_GIZMOMAP_DRAWSTEP_2D);
+
+ GPU_matrix_pop();
+ GPU_matrix_projection_set(original_proj);
+ }
+
draw_nodetree(C, ar, ntree, path->parent_key);
}
/* temporary links */
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
+ GPU_blend(true);
+ GPU_line_smooth(true);
for (nldrag = snode->linkdrag.first; nldrag; nldrag = nldrag->next) {
for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next)
node_draw_link(v2d, snode, (bNodeLink *)linkdata->data);
}
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
+ GPU_line_smooth(false);
+ GPU_blend(false);
if (snode->flag & SNODE_SHOW_GPENCIL) {
/* draw grease-pencil ('canvas' strokes) */
@@ -1441,7 +1460,7 @@ void drawnodespace(const bContext *C, ARegion *ar)
draw_tree_path(snode);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index c1fd7aa120f..86b7ebf46b4 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -41,7 +41,6 @@
#include "BLI_blenlib.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_library.h"
@@ -50,6 +49,8 @@
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -124,7 +125,7 @@ static int compo_get_recalc_flags(const bContext *C)
int recalc_flags = 0;
for (win = wm->windows.first; win; win = win->next) {
- bScreen *sc = win->screen;
+ const bScreen *sc = WM_window_get_active_screen(win);
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -331,11 +332,11 @@ void snode_dag_update(bContext *C, SpaceNode *snode)
if (snode->edittree != snode->nodetree) {
FOREACH_NODETREE_BEGIN(bmain, tntree, id) {
if (ntreeHasTree(tntree, snode->edittree))
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
} FOREACH_NODETREE_END;
}
- DAG_id_tag_update(snode->id, 0);
+ DEG_id_tag_update(snode->id, 0);
}
void snode_notify(bContext *C, SpaceNode *snode)
@@ -385,7 +386,6 @@ bool ED_node_is_texture(struct SpaceNode *snode)
/* called from shading buttons or header */
void ED_node_shader_default(const bContext *C, ID *id)
{
- Scene *scene = CTX_data_scene(C);
bNode *in, *out;
bNodeSocket *fromsock, *tosock, *sock;
bNodeTree *ntree;
@@ -400,14 +400,8 @@ void ED_node_shader_default(const bContext *C, ID *id)
Material *ma = (Material *)id;
ma->nodetree = ntree;
- if (BKE_scene_use_new_shading_nodes(scene)) {
- output_type = SH_NODE_OUTPUT_MATERIAL;
- shader_type = SH_NODE_BSDF_DIFFUSE;
- }
- else {
- output_type = SH_NODE_OUTPUT;
- shader_type = SH_NODE_MATERIAL;
- }
+ output_type = SH_NODE_OUTPUT_MATERIAL;
+ shader_type = SH_NODE_BSDF_PRINCIPLED;
copy_v3_v3(color, &ma->r);
strength = 0.0f;
@@ -430,7 +424,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
Lamp *la = (Lamp *)id;
la->nodetree = ntree;
- output_type = SH_NODE_OUTPUT_LAMP;
+ output_type = SH_NODE_OUTPUT_LIGHT;
shader_type = SH_NODE_EMISSION;
copy_v3_v3(color, &la->r);
@@ -458,18 +452,16 @@ void ED_node_shader_default(const bContext *C, ID *id)
nodeAddLink(ntree, in, fromsock, out, tosock);
/* default values */
- if (BKE_scene_use_new_shading_nodes(scene)) {
- PointerRNA sockptr;
- sock = in->inputs.first;
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
+ PointerRNA sockptr;
+ sock = in->inputs.first;
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
- RNA_float_set_array(&sockptr, "default_value", color);
+ RNA_float_set_array(&sockptr, "default_value", color);
- if (strength != 0.0f) {
- sock = in->inputs.last;
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
- RNA_float_set(&sockptr, "default_value", strength);
- }
+ if (strength != 0.0f) {
+ sock = in->inputs.last;
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
+ RNA_float_set(&sockptr, "default_value", strength);
}
ntreeUpdateTree(CTX_data_main(C), ntree);
@@ -548,12 +540,6 @@ void snode_set_context(const bContext *C)
bNodeTree *ntree = snode->nodetree;
ID *id = snode->id, *from = snode->from;
- /* we use this to signal warnings, when node shaders are drawn in wrong render engine */
- if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C)))
- snode->flag |= SNODE_NEW_SHADERS;
- else
- snode->flag &= ~SNODE_NEW_SHADERS;
-
/* check the tree type */
if (!treetype ||
(treetype->poll && !treetype->poll(C, treetype)))
@@ -641,8 +627,8 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO))
nodeClearActiveID(ntree, ID_TE);
- if (ELEM(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL,
- SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP, SH_NODE_OUTPUT_LINESTYLE))
+ if (ELEM(node->type, SH_NODE_OUTPUT_MATERIAL,
+ SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT, SH_NODE_OUTPUT_LINESTYLE))
{
bNode *tnode;
@@ -670,6 +656,7 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree))
GPU_material_free(&wo->gpumaterial);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -689,25 +676,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
if (was_output == 0)
ED_node_tag_update_nodetree(bmain, ntree, node);
- /* addnode() doesnt link this yet... */
+ /* addnode() doesn't link this yet... */
node->id = (ID *)BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
}
- else if (node->type == CMP_NODE_R_LAYERS) {
- Scene *scene;
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- if (scene->nodetree && scene->use_nodes && ntreeHasTree(scene->nodetree, ntree)) {
- if (node->id == NULL || node->id == (ID *)scene) {
- int num_layers = BLI_listbase_count(&scene->r.layers);
- scene->r.actlay = node->custom1;
- /* Clamp the value, because it might have come from a different
- * scene which could have more render layers than new one.
- */
- scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1);
- }
- }
- }
- }
else if (node->type == CMP_NODE_COMPOSITE) {
if (was_output == 0) {
bNode *tnode;
@@ -1277,7 +1248,7 @@ bool ED_node_select_check(ListBase *lb)
/* goes over all scenes, reads render layers */
-static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
+static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
@@ -1307,48 +1278,14 @@ static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-void NODE_OT_read_renderlayers(wmOperatorType *ot)
+void NODE_OT_read_viewlayers(wmOperatorType *ot)
{
- ot->name = "Read Render Layers";
- ot->idname = "NODE_OT_read_renderlayers";
+ ot->name = "Read View Layers";
+ ot->idname = "NODE_OT_read_viewlayers";
ot->description = "Read all render layers of all used scenes";
- ot->exec = node_read_renderlayers_exec;
-
- ot->poll = composite_node_active;
-
- /* flags */
- ot->flag = 0;
-}
-
-static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- Scene *curscene = CTX_data_scene(C);
- Render *re = RE_NewSceneRender(curscene);
-
- WM_cursor_wait(1);
- RE_MergeFullSample(re, bmain, curscene, snode->nodetree);
- WM_cursor_wait(0);
-
- /* note we are careful to send the right notifier, as otherwise the
- * compositor would reexecute and overwrite the full sample result */
- WM_event_add_notifier(C, NC_SCENE | ND_COMPO_RESULT, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-
-void NODE_OT_read_fullsamplelayers(wmOperatorType *ot)
-{
-
- ot->name = "Read Full Sample Layers";
- ot->idname = "NODE_OT_read_fullsamplelayers";
- ot->description = "Read all render layers of current scene, in full sample";
-
- ot->exec = node_read_fullsamplelayers_exec;
+ ot->exec = node_read_viewlayers_exec;
ot->poll = composite_node_active;
@@ -1367,13 +1304,13 @@ int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op))
}
}
if (node) {
- SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1);
+ ViewLayer *view_layer = BLI_findlink(&sce->view_layers, node->custom1);
- if (srl) {
+ if (view_layer) {
PointerRNA op_ptr;
WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
- RNA_string_set(&op_ptr, "layer", srl->name);
+ RNA_string_set(&op_ptr, "layer", view_layer->name);
RNA_string_set(&op_ptr, "scene", sce->id.name + 2);
/* to keep keypositions */
@@ -1649,7 +1586,7 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
if (node->id)
id_us_min(node->id);
- nodeFreeNode(snode->edittree, node);
+ nodeDeleteNode(bmain, snode->edittree, node);
}
}
@@ -1729,6 +1666,7 @@ void NODE_OT_switch_view_update(wmOperatorType *ot)
/* ****************** Delete with reconnect ******************* */
static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node, *next;
@@ -1742,7 +1680,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
/* check id user here, nodeFreeNode is called for free dbase too */
if (node->id)
id_us_min(node->id);
- nodeFreeNode(snode->edittree, node);
+ nodeDeleteNode(bmain, snode->edittree, node);
}
}
@@ -2572,17 +2510,17 @@ void NODE_OT_viewer_border(wmOperatorType *ot)
ot->idname = "NODE_OT_viewer_border";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = viewer_border_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = composite_node_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_node/node_gizmo.c b/source/blender/editors/space_node/node_gizmo.c
new file mode 100644
index 00000000000..303962138a8
--- /dev/null
+++ b/source/blender/editors/space_node/node_gizmo.c
@@ -0,0 +1,629 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_node/node_gizmo.c
+ * \ingroup spnode
+ */
+
+#include <math.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_math_matrix.h"
+#include "BLI_math_vector.h"
+#include "BLI_rect.h"
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "node_intern.h"
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Local Utilities
+ * \{ */
+
+static void node_gizmo_calc_matrix_space(
+ const SpaceNode *snode, const ARegion *ar, float matrix_space[4][4])
+{
+ unit_m4(matrix_space);
+ mul_v3_fl(matrix_space[0], snode->zoom);
+ mul_v3_fl(matrix_space[1], snode->zoom);
+ matrix_space[3][0] = (ar->winx / 2) + snode->xof;
+ matrix_space[3][1] = (ar->winy / 2) + snode->yof;
+}
+
+static void node_gizmo_calc_matrix_space_with_image_dims(
+ const SpaceNode *snode, const ARegion *ar, const float image_dims[2], float matrix_space[4][4])
+{
+ unit_m4(matrix_space);
+ mul_v3_fl(matrix_space[0], snode->zoom * image_dims[0]);
+ mul_v3_fl(matrix_space[1], snode->zoom * image_dims[1]);
+ matrix_space[3][0] = ((ar->winx / 2) + snode->xof) - ((image_dims[0] / 2.0f) * snode->zoom);
+ matrix_space[3][1] = ((ar->winy / 2) + snode->yof) - ((image_dims[1] / 2.0f) * snode->zoom);
+}
+
+/** \} */
+
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Backdrop Gizmo
+ * \{ */
+
+static void gizmo_node_backdrop_prop_matrix_get(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ float (*matrix)[4] = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ const SpaceNode *snode = gz_prop->custom_func.user_data;
+ matrix[0][0] = snode->zoom;
+ matrix[1][1] = snode->zoom;
+ matrix[3][0] = snode->xof;
+ matrix[3][1] = snode->yof;
+}
+
+static void gizmo_node_backdrop_prop_matrix_set(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ const float (*matrix)[4] = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ SpaceNode *snode = gz_prop->custom_func.user_data;
+ snode->zoom = matrix[0][0];
+ snode->zoom = matrix[1][1];
+ snode->xof = matrix[3][0];
+ snode->yof = matrix[3][1];
+}
+
+static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ if ((snode->flag & SNODE_BACKDRAW) == 0) {
+ return false;
+ }
+
+ if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
+ bNode *node = nodeGetActive(snode->edittree);
+
+ if (node && ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
+
+ wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
+
+ RNA_enum_set(wwrapper->gizmo->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM);
+
+ gzgroup->customdata = wwrapper;
+}
+
+static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ Main *bmain = CTX_data_main(C);
+ wmGizmo *cage = ((wmGizmoWrapper *)gzgroup->customdata)->gizmo;
+ const ARegion *ar = CTX_wm_region(C);
+ /* center is always at the origin */
+ const float origin[3] = {ar->winx / 2, ar->winy / 2};
+
+ void *lock;
+ Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ const float dims[2] = {
+ (ibuf->x > 0) ? ibuf->x : 64.0f,
+ (ibuf->y > 0) ? ibuf->y : 64.0f,
+ };
+
+ RNA_float_set_array(cage->ptr, "dimensions", dims);
+ WM_gizmo_set_matrix_location(cage, origin);
+ WM_gizmo_set_flag(cage, WM_GIZMO_HIDDEN, false);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ SpaceNode *snode = CTX_wm_space_node(C);
+#if 0
+ PointerRNA nodeptr;
+ RNA_pointer_create(snode->id, &RNA_SpaceNodeEditor, snode, &nodeptr);
+ WM_gizmo_target_property_def_rna(cage, "offset", &nodeptr, "backdrop_offset", -1);
+ WM_gizmo_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1);
+#endif
+
+ WM_gizmo_target_property_def_func(
+ cage, "matrix",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_node_backdrop_prop_matrix_get,
+ .value_set_fn = gizmo_node_backdrop_prop_matrix_set,
+ .range_get_fn = NULL,
+ .user_data = snode,
+ });
+ }
+ else {
+ WM_gizmo_set_flag(cage, WM_GIZMO_HIDDEN, true);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+}
+
+void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Backdrop Transform Widget";
+ gzgt->idname = "NODE_GGT_backdrop_transform";
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_PERSISTENT;
+
+ gzgt->poll = WIDGETGROUP_node_transform_poll;
+ gzgt->setup = WIDGETGROUP_node_transform_setup;
+ gzgt->refresh = WIDGETGROUP_node_transform_refresh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Crop Gizmo
+ * \{ */
+
+struct NodeCropWidgetGroup {
+ wmGizmo *border;
+
+ struct {
+ float dims[2];
+ } state;
+
+ struct {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ bContext *context;
+ } update_data;
+};
+
+static void gizmo_node_crop_update(struct NodeCropWidgetGroup *crop_group)
+{
+ RNA_property_update(crop_group->update_data.context, &crop_group->update_data.ptr, crop_group->update_data.prop);
+}
+
+static void two_xy_to_rect(const NodeTwoXYs *nxy, rctf *rect, const float dims[2], bool is_relative)
+{
+ if (is_relative) {
+ rect->xmin = nxy->fac_x1;
+ rect->xmax = nxy->fac_x2;
+ rect->ymin = nxy->fac_y1;
+ rect->ymax = nxy->fac_y2;
+ }
+ else {
+ rect->xmin = nxy->x1 / dims[0];
+ rect->xmax = nxy->x2 / dims[0];
+ rect->ymin = nxy->y1 / dims[1];
+ rect->ymax = nxy->y2 / dims[1];
+ }
+}
+
+static void two_xy_from_rect(NodeTwoXYs *nxy, const rctf *rect, const float dims[2], bool is_relative)
+{
+ if (is_relative) {
+ nxy->fac_x1 = rect->xmin;
+ nxy->fac_x2 = rect->xmax;
+ nxy->fac_y1 = rect->ymin;
+ nxy->fac_y2 = rect->ymax;
+ }
+ else {
+ nxy->x1 = rect->xmin * dims[0];
+ nxy->x2 = rect->xmax * dims[0];
+ nxy->y1 = rect->ymin * dims[1];
+ nxy->y2 = rect->ymax * dims[1];
+ }
+}
+
+/* scale callbacks */
+static void gizmo_node_crop_prop_matrix_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ float (*matrix)[4] = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata;
+ const float *dims = crop_group->state.dims;
+ const bNode *node = gz_prop->custom_func.user_data;
+ const NodeTwoXYs *nxy = node->storage;
+ bool is_relative = (bool)node->custom2;
+ rctf rct;
+ two_xy_to_rect(nxy, &rct, dims, is_relative);
+ matrix[0][0] = fabsf(BLI_rctf_size_x(&rct));
+ matrix[1][1] = fabsf(BLI_rctf_size_y(&rct));
+ matrix[3][0] = (BLI_rctf_cent_x(&rct) - 0.5f) * dims[0];
+ matrix[3][1] = (BLI_rctf_cent_y(&rct) - 0.5f) * dims[1];
+}
+
+static void gizmo_node_crop_prop_matrix_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ const float (*matrix)[4] = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata;
+ const float *dims = crop_group->state.dims;
+ bNode *node = gz_prop->custom_func.user_data;
+ NodeTwoXYs *nxy = node->storage;
+ bool is_relative = (bool)node->custom2;
+ rctf rct;
+ two_xy_to_rect(nxy, &rct, dims, is_relative);
+ const bool nx = rct.xmin > rct.xmax;
+ const bool ny = rct.ymin > rct.ymax;
+ BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1]));
+ BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f);
+ BLI_rctf_isect(&(rctf){.xmin = 0, .ymin = 0, .xmax = 1, .ymax = 1}, &rct, &rct);
+ if (nx) {
+ SWAP(float, rct.xmin, rct.xmax);
+ }
+ if (ny) {
+ SWAP(float, rct.ymin, rct.ymax);
+ }
+ two_xy_from_rect(nxy, &rct, dims, is_relative);
+ gizmo_node_crop_update(crop_group);
+}
+
+static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ if ((snode->flag & SNODE_BACKDRAW) == 0) {
+ return false;
+ }
+
+ if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
+ bNode *node = nodeGetActive(snode->edittree);
+
+ if (node && ELEM(node->type, CMP_NODE_CROP)) {
+ /* ignore 'use_crop_size', we can't usefully edit the crop in this case. */
+ if ((node->custom1 & (1 << 0)) == 0) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct NodeCropWidgetGroup *crop_group = MEM_mallocN(sizeof(struct NodeCropWidgetGroup), __func__);
+
+ crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
+
+ RNA_enum_set(crop_group->border->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE);
+
+ gzgroup->customdata = crop_group;
+}
+
+static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmo *gz = gzgroup->gizmos.first;
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ node_gizmo_calc_matrix_space(snode, ar, gz->matrix_space);
+}
+
+static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ Main *bmain = CTX_data_main(C);
+ struct NodeCropWidgetGroup *crop_group = gzgroup->customdata;
+ wmGizmo *gz = crop_group->border;
+
+ void *lock;
+ Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
+ crop_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
+
+ RNA_float_set_array(gz->ptr, "dimensions", crop_group->state.dims);
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNode *node = nodeGetActive(snode->edittree);
+
+ crop_group->update_data.context = (bContext *)C;
+ RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeCrop, node, &crop_group->update_data.ptr);
+ crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr, "relative");
+
+ WM_gizmo_target_property_def_func(
+ gz, "matrix",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_node_crop_prop_matrix_get,
+ .value_set_fn = gizmo_node_crop_prop_matrix_set,
+ .range_get_fn = NULL,
+ .user_data = node,
+ });
+ }
+ else {
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+}
+
+void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Backdrop Crop Widget";
+ gzgt->idname = "NODE_GGT_backdrop_crop";
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_PERSISTENT;
+
+ gzgt->poll = WIDGETGROUP_node_crop_poll;
+ gzgt->setup = WIDGETGROUP_node_crop_setup;
+ gzgt->draw_prepare = WIDGETGROUP_node_crop_draw_prepare;
+ gzgt->refresh = WIDGETGROUP_node_crop_refresh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Sun Beams
+ * \{ */
+
+struct NodeSunBeamsWidgetGroup {
+ wmGizmo *gizmo;
+
+ struct {
+ float dims[2];
+ } state;
+};
+
+static bool WIDGETGROUP_node_sbeam_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ if ((snode->flag & SNODE_BACKDRAW) == 0) {
+ return false;
+ }
+
+ if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
+ bNode *node = nodeGetActive(snode->edittree);
+
+ if (node && ELEM(node->type, CMP_NODE_SUNBEAMS)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct NodeSunBeamsWidgetGroup *sbeam_group = MEM_mallocN(sizeof(struct NodeSunBeamsWidgetGroup), __func__);
+
+ sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, NULL);
+ wmGizmo *gz = sbeam_group->gizmo;
+
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D);
+
+ gz->scale_basis = 0.05f;
+
+ gzgroup->customdata = sbeam_group;
+}
+
+static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata;
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmo *gz = gzgroup->gizmos.first;
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ node_gizmo_calc_matrix_space_with_image_dims(snode, ar, sbeam_group->state.dims, gz->matrix_space);
+}
+
+static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ Main *bmain = CTX_data_main(C);
+ struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata;
+ wmGizmo *gz = sbeam_group->gizmo;
+
+ void *lock;
+ Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
+ sbeam_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNode *node = nodeGetActive(snode->edittree);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ PointerRNA nodeptr;
+ RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeSunBeams, node, &nodeptr);
+ WM_gizmo_target_property_def_rna(gz, "offset", &nodeptr, "source", -1);
+
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_MODAL, true);
+ }
+ else {
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+}
+
+void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Sun Beams Widget";
+ gzgt->idname = "NODE_GGT_sbeam";
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_PERSISTENT;
+
+ gzgt->poll = WIDGETGROUP_node_sbeam_poll;
+ gzgt->setup = WIDGETGROUP_node_sbeam_setup;
+ gzgt->draw_prepare = WIDGETGROUP_node_sbeam_draw_prepare;
+ gzgt->refresh = WIDGETGROUP_node_sbeam_refresh;
+}
+
+/** \} */
+
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Corner Pin
+ * \{ */
+
+struct NodeCornerPinWidgetGroup {
+ wmGizmo *gizmos[4];
+
+ struct {
+ float dims[2];
+ } state;
+};
+
+static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ if ((snode->flag & SNODE_BACKDRAW) == 0) {
+ return false;
+ }
+
+ if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) {
+ bNode *node = nodeGetActive(snode->edittree);
+
+ if (node && ELEM(node->type, CMP_NODE_CORNERPIN)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct NodeCornerPinWidgetGroup *cpin_group = MEM_mallocN(sizeof(struct NodeCornerPinWidgetGroup), __func__);
+ const wmGizmoType *gzt_move_3d = WM_gizmotype_find("GIZMO_GT_move_3d", false);
+
+ for (int i = 0; i < 4; i++) {
+ cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, NULL);
+ wmGizmo *gz = cpin_group->gizmos[i];
+
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D);
+
+ gz->scale_basis = 0.01f;
+ }
+
+ gzgroup->customdata = cpin_group;
+}
+
+static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata;
+ ARegion *ar = CTX_wm_region(C);
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ float matrix_space[4][4];
+ node_gizmo_calc_matrix_space_with_image_dims(snode, ar, cpin_group->state.dims, matrix_space);
+
+ for (int i = 0; i < 4; i++) {
+ wmGizmo *gz = cpin_group->gizmos[i];
+ copy_m4_m4(gz->matrix_space, matrix_space);
+ }
+}
+
+static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ Main *bmain = CTX_data_main(C);
+ struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata;
+
+ void *lock;
+ Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+
+ if (ibuf) {
+ cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
+ cpin_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
+
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNode *node = nodeGetActive(snode->edittree);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ int i = 0;
+ for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) {
+ if (sock->type == SOCK_VECTOR) {
+ wmGizmo *gz = cpin_group->gizmos[i++];
+
+ PointerRNA sockptr;
+ RNA_pointer_create((ID *)snode->edittree, &RNA_NodeSocket, sock, &sockptr);
+ WM_gizmo_target_property_def_rna(gz, "offset", &sockptr, "default_value", -1);
+
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_MODAL, true);
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < 4; i++) {
+ wmGizmo *gz = cpin_group->gizmos[i];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+}
+
+void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Corner Pin Widget";
+ gzgt->idname = "NODE_GGT_backdrop_corner_pin";
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_PERSISTENT;
+
+ gzgt->poll = WIDGETGROUP_node_corner_pin_poll;
+ gzgt->setup = WIDGETGROUP_node_corner_pin_setup;
+ gzgt->draw_prepare = WIDGETGROUP_node_corner_pin_draw_prepare;
+ gzgt->refresh = WIDGETGROUP_node_corner_pin_refresh;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index a3294211ff9..c7c856d95c4 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -50,6 +50,8 @@
#include "BKE_main.h"
#include "BKE_report.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_node.h" /* own include */
#include "ED_screen.h"
#include "ED_render.h"
@@ -340,11 +342,11 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
while (nodes_delayed_free) {
node = BLI_linklist_pop(&nodes_delayed_free);
- nodeFreeNode(ntree, node);
+ nodeDeleteNode(bmain, ntree, node);
}
/* delete the group instance */
- nodeFreeNode(ntree, gnode);
+ nodeDeleteNode(bmain, ntree, gnode);
ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
@@ -961,6 +963,7 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
snode_notify(C, snode);
snode_dag_update(C, snode);
+ DEG_relations_tag_update(bmain); /* We broke relations in node tree, need to rebuild them in the grahes. */
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 9b396aa9642..78d01123d0c 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -68,13 +68,11 @@ void snode_group_offset(struct SpaceNode *snode, float *x, float *y); /* transfo
/* node_draw.c */
int node_get_colorid(struct bNode *node);
-void node_socket_draw(
- const struct bContext *C, struct bNodeTree *ntree, struct bNode *node,
- struct bNodeSocket *sock, float size, bool highlight);
int node_get_resize_cursor(int directions);
void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha);
void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode,
struct bNodeTree *ntree, struct bNode *node, bNodeInstanceKey key);
+void node_draw_sockets(struct View2D *v2d, const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, bool draw_outputs, bool select_all);
void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node);
int node_select_area_default(struct bNode *node, int x, int y);
int node_tweak_area_default(struct bNode *node, int x, int y);
@@ -113,7 +111,7 @@ void NODE_OT_select(struct wmOperatorType *ot);
void NODE_OT_select_all(struct wmOperatorType *ot);
void NODE_OT_select_linked_to(struct wmOperatorType *ot);
void NODE_OT_select_linked_from(struct wmOperatorType *ot);
-void NODE_OT_select_border(struct wmOperatorType *ot);
+void NODE_OT_select_box(struct wmOperatorType *ot);
void NODE_OT_select_circle(struct wmOperatorType *ot);
void NODE_OT_select_lasso(struct wmOperatorType *ot);
void NODE_OT_select_grouped(struct wmOperatorType *ot);
@@ -133,8 +131,11 @@ void NODE_OT_backimage_fit(struct wmOperatorType *ot);
void NODE_OT_backimage_sample(struct wmOperatorType *ot);
/* drawnode.c */
+void nodelink_batch_start(struct SpaceNode *snode);
+void nodelink_batch_end(struct SpaceNode *snode);
+
void node_draw_link(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link);
-void node_draw_link_bezier(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, int th_col1, bool do_shaded, int th_col2, bool do_triple, int th_col3);
+void node_draw_link_bezier(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, int th_col1, int th_col2, int th_col3);
bool node_link_bezier_points(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, float coord_array[][2], int resol);
// void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 );
void draw_nodespace_back_pix(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, bNodeInstanceKey parent_key);
@@ -199,8 +200,7 @@ void NODE_OT_preview_toggle(struct wmOperatorType *ot);
void NODE_OT_options_toggle(struct wmOperatorType *ot);
void NODE_OT_node_copy_color(struct wmOperatorType *ot);
-void NODE_OT_read_fullsamplelayers(struct wmOperatorType *ot);
-void NODE_OT_read_renderlayers(struct wmOperatorType *ot);
+void NODE_OT_read_viewlayers(struct wmOperatorType *ot);
void NODE_OT_render_changed(struct wmOperatorType *ot);
void NODE_OT_output_file_add_socket(struct wmOperatorType *ot);
@@ -222,6 +222,12 @@ void NODE_OT_shader_script_update(struct wmOperatorType *ot);
void NODE_OT_viewer_border(struct wmOperatorType *ot);
void NODE_OT_clear_viewer_border(struct wmOperatorType *ot);
+/* node_widgets.c */
+void NODE_GGT_backdrop_transform(struct wmGizmoGroupType *gzgt);
+void NODE_GGT_backdrop_crop(struct wmGizmoGroupType *gzgt);
+void NODE_GGT_backdrop_sun_beams(struct wmGizmoGroupType *gzgt);
+void NODE_GGT_backdrop_corner_pin(struct wmGizmoGroupType *gzgt);
+
void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot);
void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot);
@@ -231,7 +237,7 @@ extern const char *node_context_dir[];
// nodes draw without dpi - the view zoom is flexible
#define HIDDEN_RAD (0.75f * U.widget_unit)
-#define BASIS_RAD (0.4f * U.widget_unit)
+#define BASIS_RAD (0.2f * U.widget_unit)
#define NODE_DYS (U.widget_unit / 2)
#define NODE_DY U.widget_unit
#define NODE_SOCKDY (0.08f * U.widget_unit)
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index d4585c0835d..1eead941c97 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -37,6 +37,7 @@
#include "ED_node.h" /* own include */
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
#include "RNA_access.h"
@@ -55,7 +56,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_select_all);
WM_operatortype_append(NODE_OT_select_linked_to);
WM_operatortype_append(NODE_OT_select_linked_from);
- WM_operatortype_append(NODE_OT_select_border);
+ WM_operatortype_append(NODE_OT_select_box);
WM_operatortype_append(NODE_OT_select_circle);
WM_operatortype_append(NODE_OT_select_lasso);
WM_operatortype_append(NODE_OT_select_grouped);
@@ -94,8 +95,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_insert_offset);
- WM_operatortype_append(NODE_OT_read_renderlayers);
- WM_operatortype_append(NODE_OT_read_fullsamplelayers);
+ WM_operatortype_append(NODE_OT_read_viewlayers);
WM_operatortype_append(NODE_OT_render_changed);
WM_operatortype_append(NODE_OT_backimage_move);
@@ -202,154 +202,11 @@ void ED_operatormacros_node(void)
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
}
-/* helper function for repetitive select operator keymap */
-static void node_select_keymap(wmKeyMap *keymap, int extend)
-{
- /* modifier combinations */
- const int mod_single[] = { 0, KM_CTRL, KM_ALT, KM_CTRL | KM_ALT,
- -1 /* terminator */
- };
- const int mod_extend[] = { KM_SHIFT, KM_SHIFT | KM_CTRL,
- KM_SHIFT | KM_ALT, KM_SHIFT | KM_CTRL | KM_ALT,
- -1 /* terminator */
- };
- const int *mod = (extend ? mod_extend : mod_single);
- wmKeyMapItem *kmi;
- int i;
-
- for (i = 0; mod[i] >= 0; ++i) {
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select", ACTIONMOUSE, KM_PRESS, mod[i], 0);
- RNA_boolean_set(kmi->ptr, "extend", extend);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select", SELECTMOUSE, KM_PRESS, mod[i], 0);
- RNA_boolean_set(kmi->ptr, "extend", extend);
- }
-}
-
void node_keymap(struct wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
/* Entire Editor only ----------------- */
- keymap = WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
-
- WM_keymap_add_item(keymap, "NODE_OT_properties", NKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_toolbar", TKEY, KM_PRESS, 0, 0);
+ WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
/* Main Region only ----------------- */
- keymap = WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0);
-
- /* mouse select in nodes used to be both keys, but perhaps this should be reduced?
- * NOTE: mouse-clicks on left-mouse will fall through to allow transform-tweak, but also link/resize
- * NOTE 2: socket select is part of the node select operator, to handle overlapping cases
- * NOTE 3: select op is registered for various combinations of modifier key, so the specialized
- * grab operators (unlink, attach, etc.) can work easily on single nodes.
- */
- node_select_keymap(keymap, false);
- node_select_keymap(keymap, true);
-
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_border", EVT_TWEAK_S, KM_ANY, 0, 0);
- RNA_boolean_set(kmi->ptr, "tweak", true);
-
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- WM_keymap_add_item(keymap, "NODE_OT_select_circle", CKEY, KM_PRESS, 0, 0);
-
- /* each of these falls through if not handled... */
- kmi = WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "detach", false);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "detach", true);
-
- WM_keymap_add_item(keymap, "NODE_OT_resize", LEFTMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "NODE_OT_add_reroute", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_links_cut", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "NODE_OT_select_link_viewer", LEFTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "NODE_OT_backimage_move", MIDDLEMOUSE, KM_PRESS, KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_backimage_zoom", VKEY, KM_PRESS, 0, 0);
- RNA_float_set(kmi->ptr, "factor", 0.83333f);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_backimage_zoom", VKEY, KM_PRESS, KM_ALT, 0);
- RNA_float_set(kmi->ptr, "factor", 1.2f);
- WM_keymap_add_item(keymap, "NODE_OT_backimage_fit", HOMEKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_backimage_sample", ACTIONMOUSE, KM_PRESS, KM_ALT, 0);
-
- kmi = WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "replace", false);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "replace", true);
-
- WM_keymap_add_menu(keymap, "NODE_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
- /* modified operator call for duplicating with input links */
- WM_keymap_add_item(keymap, "NODE_OT_duplicate_move_keep_inputs", DKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "NODE_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "NODE_OT_detach", PKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_join", JKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "NODE_OT_hide_toggle", HKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_mute_toggle", MKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_preview_toggle", HKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_hide_socket_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "NODE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "NODE_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
- WM_keymap_add_item(keymap, "NODE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_border", BKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "tweak", false);
-
- WM_keymap_add_item(keymap, "NODE_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_delete", DELKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_delete_reconnect", XKEY, KM_PRESS, KM_CTRL, 0);
-
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "NODE_OT_select_linked_to", LKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_select_linked_from", LKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_same_type_step", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "prev", false);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_select_same_type_step", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "prev", true);
-
- WM_keymap_add_item(keymap, "NODE_OT_find_node", FKEY, KM_PRESS, KM_CTRL, 0);
-
- /* node group operators */
- WM_keymap_add_item(keymap, "NODE_OT_group_make", GKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "NODE_OT_group_ungroup", GKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_group_separate", PKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "exit", false);
- kmi = WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "exit", true);
-
- WM_keymap_add_item(keymap, "NODE_OT_read_renderlayers", RKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "NODE_OT_read_fullsamplelayers", RKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_render_changed", ZKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "NODE_OT_clipboard_copy", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "NODE_OT_clipboard_paste", VKEY, KM_PRESS, KM_CTRL, 0);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "NODE_OT_clipboard_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "NODE_OT_clipboard_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
- WM_keymap_add_item(keymap, "NODE_OT_viewer_border", BKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "NODE_OT_clear_viewer_border", BKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
-
- transform_keymap_for_space(keyconf, keymap, SPACE_NODE);
+ WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0);
}
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index efdec512cf7..8f3d3d8a4b3 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -532,7 +532,7 @@ static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
char header[UI_MAX_DRAW_STR];
BLI_strncpy(header, IFACE_("LMB: drag node link, RMB: cancel"), sizeof(header));
- ED_area_headerprint(CTX_wm_area(C), header);
+ ED_workspace_status_text(C, header);
}
static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
@@ -729,7 +729,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_RELEASE) {
node_link_exit(C, op, true);
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
ED_region_tag_redraw(ar);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index e84d38a58ad..eb233f3fea1 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -45,6 +45,7 @@
#include "ED_node.h" /* own include */
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -516,9 +517,9 @@ void NODE_OT_select(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "");
}
-/* ****** Border Select ****** */
+/* ****** Box Select ****** */
-static int node_borderselect_exec(bContext *C, wmOperator *op)
+static int node_box_select_exec(bContext *C, wmOperator *op)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
@@ -554,13 +555,13 @@ static int node_borderselect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int node_border_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int node_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const bool tweak = RNA_boolean_get(op->ptr, "tweak");
if (tweak) {
- /* prevent initiating the border select if the mouse is over a node */
- /* this allows border select on empty space, but drag-translate on nodes */
+ /* prevent initiating the box select if the mouse is over a node */
+ /* this allows box select on empty space, but drag-translate on nodes */
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *ar = CTX_wm_region(C);
float mx, my;
@@ -571,21 +572,21 @@ static int node_border_select_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
- return WM_gesture_border_invoke(C, op, event);
+ return WM_gesture_box_invoke(C, op, event);
}
-void NODE_OT_select_border(wmOperatorType *ot)
+void NODE_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "NODE_OT_select_border";
+ ot->name = "Box Select";
+ ot->idname = "NODE_OT_select_box";
ot->description = "Use box selection to select nodes";
/* api callbacks */
- ot->invoke = node_border_select_invoke;
- ot->exec = node_borderselect_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = node_box_select_invoke;
+ ot->exec = node_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_node_active;
@@ -593,7 +594,7 @@ void NODE_OT_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
RNA_def_boolean(ot->srna, "tweak", 0, "Tweak", "Only activate when mouse is not over a node - useful for tweak gesture");
}
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 6995744f235..e7a9db20103 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -124,7 +124,7 @@ static void node_clear_recursive(bNode *node)
node_clear_recursive(input->link->fromnode);
}
-static void node_remove_linked(bNodeTree *ntree, bNode *rem_node)
+static void node_remove_linked(Main *bmain, bNodeTree *ntree, bNode *rem_node)
{
bNode *node, *next;
bNodeSocket *sock;
@@ -152,7 +152,7 @@ static void node_remove_linked(bNodeTree *ntree, bNode *rem_node)
if (node->flag & NODE_TEST) {
if (node->id)
id_us_min(node->id);
- nodeFreeNode(ntree, node);
+ nodeDeleteNode(bmain, ntree, node);
}
}
}
@@ -178,7 +178,7 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN
if (!sock_to->link)
return;
- node_remove_linked(ntree, sock_to->link->fromnode);
+ node_remove_linked(bmain, ntree, sock_to->link->fromnode);
sock_to->flag |= SOCK_COLLAPSED;
nodeUpdate(ntree, node_to);
@@ -218,20 +218,15 @@ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *
else if (!node_from) {
node_from = nodeAddStaticNode(C, ntree, type);
if (node_prev != NULL) {
- /* If we're replacing existing node, use it's location. */
+ /* If we're replacing existing node, use its location. */
node_from->locx = node_prev->locx;
node_from->locy = node_prev->locy;
node_from->offsetx = node_prev->offsetx;
node_from->offsety = node_prev->offsety;
}
else {
- /* Avoid exact intersection of nodes.
- * TODO(sergey): Still not ideal, but better than nothing.
- */
- int index = BLI_findindex(&node_to->inputs, sock_to);
- BLI_assert(index != -1);
- node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
- node_from->locy = node_to->locy - (node_from->typeinfo->height * index);
+ sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index);
+ nodePositionRelative(node_from, node_to, sock_from_tmp, sock_to);
}
node_link_item_apply(bmain, node_from, item);
@@ -274,7 +269,7 @@ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *
}
/* remove node */
- node_remove_linked(ntree, node_prev);
+ node_remove_linked(bmain, ntree, node_prev);
}
nodeUpdate(ntree, node_from);
@@ -446,21 +441,13 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
uiBut *but;
NodeLinkArg *argN;
int first = 1;
- int compatibility = 0;
-
- if (ntree->type == NTREE_SHADER) {
- if (BKE_scene_use_new_shading_nodes(arg->scene))
- compatibility = NODE_NEW_SHADING;
- else
- compatibility = NODE_OLD_SHADING;
- }
/* generate array of node types sorted by UI name */
bNodeType **sorted_ntypes = NULL;
BLI_array_declare(sorted_ntypes);
NODE_TYPES_BEGIN(ntype) {
- if (compatibility && !(ntype->compatibility & compatibility)) {
+ if (!(ntype->poll && ntype->poll(ntype, ntree))) {
continue;
}
@@ -637,7 +624,7 @@ static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, b
if (node->typeinfo->draw_buttons) {
if (node->type != NODE_GROUP) {
- split = uiLayoutSplit(layout, 0.35f, false);
+ split = uiLayoutSplit(layout, 0.5f, false);
col = uiLayoutColumn(split, false);
col = uiLayoutColumn(split, false);
@@ -680,10 +667,10 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
label[i] = ' ';
}
label[indent] = '\0';
- BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s:", IFACE_(input->name));
+ BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name));
/* split in label and value */
- split = uiLayoutSplit(layout, 0.35f, false);
+ split = uiLayoutSplit(layout, 0.5f, false);
row = uiLayoutRow(split, true);
@@ -705,7 +692,7 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
uiItemL(row, label, ICON_NONE);
bt = block->buttons.last;
- bt->drawflag = UI_BUT_TEXT_LEFT;
+ bt->drawflag = UI_BUT_TEXT_RIGHT;
if (dependency_loop) {
row = uiLayoutRow(split, false);
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index ed228cdaf74..8af5fe1b3a1 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -49,13 +49,16 @@
#include "ED_node.h"
#include "ED_render.h"
#include "ED_screen.h"
-#include "WM_api.h"
-#include "WM_types.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
#include "node_intern.h" /* own include */
@@ -290,7 +293,7 @@ ARegion *node_has_tools_region(ScrArea *sa)
/* ******************** default callbacks for node space ***************** */
-static SpaceLink *node_new(const bContext *UNUSED(C))
+static SpaceLink *node_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceNode *snode;
@@ -316,7 +319,7 @@ static SpaceLink *node_new(const bContext *UNUSED(C))
BLI_addtail(&snode->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* buttons/list view */
ar = MEM_callocN(sizeof(ARegion), "buttons for node");
@@ -381,12 +384,12 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
}
-static void node_area_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
+static void node_area_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
/* note, ED_area_tag_refresh will re-execute compositor */
SpaceNode *snode = sa->spacedata.first;
/* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */
- short shader_type = BKE_scene_use_new_shading_nodes(sc->scene) ? snode->shaderfrom : SNODE_SHADER_OBJECT;
+ short shader_type = snode->shaderfrom;
/* preview renders */
switch (wmn->category) {
@@ -599,7 +602,7 @@ static void node_buttons_region_init(wmWindowManager *wm, ARegion *ar)
static void node_buttons_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
/* add handlers, stuff you only do once or on area/region changes */
@@ -615,7 +618,7 @@ static void node_toolbar_region_init(wmWindowManager *wm, ARegion *ar)
static void node_toolbar_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
@@ -664,40 +667,31 @@ static void node_main_region_draw(const bContext *C, ARegion *ar)
/* ************* dropboxes ************* */
-static bool node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_IM)
- return 1;
+ if (drag->type == WM_DRAG_PATH) {
+ return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); /* rule might not work? */
}
- else if (drag->type == WM_DRAG_PATH) {
- if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)) /* rule might not work? */
- return 1;
+ else {
+ return WM_drag_ID(drag, ID_IM) != NULL;
}
- return 0;
}
-static bool node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_MSK)
- return 1;
- }
- return 0;
+ return WM_drag_ID(drag, ID_MSK) != NULL;
}
static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = drag->poin;
+ ID *id = WM_drag_ID(drag, 0);
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = drag->poin;
+ ID *id = WM_drag_ID(drag, 0);
if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);
@@ -737,17 +731,31 @@ static void node_header_region_draw(const bContext *C, ARegion *ar)
}
/* used for header + main region */
-static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void node_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
+ wmGizmoMap *gzmap = ar->gizmo_map;
+
/* context changes */
switch (wmn->category) {
case NC_SPACE:
- if (wmn->data == ND_SPACE_NODE)
- ED_region_tag_redraw(ar);
+ switch (wmn->data) {
+ case ND_SPACE_NODE:
+ ED_region_tag_redraw(ar);
+ break;
+ case ND_SPACE_NODE_VIEW:
+ WM_gizmomap_tag_refresh(gzmap);
+ break;
+ }
break;
case NC_SCREEN:
+ if (wmn->data == ND_LAYOUTSET || wmn->action == NA_EDITED) {
+ WM_gizmomap_tag_refresh(gzmap);
+ }
switch (wmn->data) {
case ND_ANIMPLAY:
+ case ND_LAYER:
ED_region_tag_redraw(ar);
break;
}
@@ -757,10 +765,20 @@ static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegi
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
+ ED_region_tag_redraw(ar);
+ if (wmn->data == ND_RENDER_RESULT) {
+ WM_gizmomap_tag_refresh(gzmap);
+ }
+ break;
+ case NC_NODE:
+ ED_region_tag_redraw(ar);
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
+ WM_gizmomap_tag_refresh(gzmap);
+ }
+ break;
case NC_MATERIAL:
case NC_TEXTURE:
case NC_WORLD:
- case NC_NODE:
case NC_LINESTYLE:
ED_region_tag_redraw(ar);
break;
@@ -825,6 +843,17 @@ static int node_context(const bContext *C, const char *member, bContextDataResul
return 0;
}
+static void node_widgets(void)
+{
+ /* create the widgetmap for the area here */
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(
+ &(const struct wmGizmoMapType_Params){SPACE_NODE, RGN_TYPE_WINDOW});
+ WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_transform);
+ WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_crop);
+ WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_sun_beams);
+ WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
+}
+
static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceNode *snode = (SpaceNode *)slink;
@@ -896,6 +925,32 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
}
}
+
+static int node_space_subtype_get(ScrArea *sa)
+{
+ SpaceNode *snode = sa->spacedata.first;
+ return rna_node_tree_idname_to_enum(snode->tree_idname);
+}
+
+static void node_space_subtype_set(ScrArea *sa, int value)
+{
+ SpaceNode *snode = sa->spacedata.first;
+ ED_node_set_tree_type(snode, rna_node_tree_type_from_enum(value));
+}
+
+static void node_space_subtype_item_extend(
+ bContext *C, EnumPropertyItem **item, int *totitem)
+{
+ bool free;
+ const EnumPropertyItem *item_src = RNA_enum_node_tree_types_itemf_impl(C, &free);
+ for (const EnumPropertyItem *item_iter = item_src; item_iter->identifier; item_iter++) {
+ RNA_enum_item_add(item, totitem, item_iter);
+ }
+ if (free) {
+ MEM_freeN((void *)item_src);
+ }
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_node(void)
{
@@ -915,17 +970,21 @@ void ED_spacetype_node(void)
st->refresh = node_area_refresh;
st->context = node_context;
st->dropboxes = node_dropboxes;
+ st->gizmos = node_widgets;
st->id_remap = node_id_remap;
+ st->space_subtype_item_extend = node_space_subtype_item_extend;
+ st->space_subtype_get = node_space_subtype_get;
+ st->space_subtype_set = node_space_subtype_set;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
art->regionid = RGN_TYPE_WINDOW;
art->init = node_main_region_init;
art->draw = node_main_region_draw;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
art->listener = node_region_listener;
art->cursor = node_cursor;
art->event_cursor = true;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
@@ -955,10 +1014,12 @@ void ED_spacetype_node(void)
/* regions: toolbar */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
- art->prefsizex = 160; /* XXX */
+ art->prefsizex = 58; /* XXX */
art->prefsizey = 50; /* XXX */
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
art->listener = node_region_listener;
+ art->message_subscribe = ED_region_generic_tools_region_message_subscribe;
+ art->snap_size = ED_region_generic_tools_region_snap_size;
art->init = node_toolbar_region_init;
art->draw = node_toolbar_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index 289d6e715e1..796e8732fca 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../depsgraph
../../imbuf
../../gpu
../../makesdna
@@ -37,12 +38,15 @@ set(INC_SYS
)
set(SRC
+ outliner_collections.c
+ outliner_dragdrop.c
outliner_draw.c
outliner_edit.c
outliner_ops.c
outliner_select.c
outliner_tools.c
outliner_tree.c
+ outliner_utils.c
space_outliner.c
outliner_intern.h
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
new file mode 100644
index 00000000000..460ba8b89fb
--- /dev/null
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -0,0 +1,840 @@
+/*
+ * ***** 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): Blender Foundation, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_outliner/outliner_collections.c
+ * \ingroup spoutliner
+ */
+
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_context.h"
+#include "BKE_collection.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "ED_object.h"
+#include "ED_outliner.h"
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_resources.h"
+
+#include "outliner_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+
+bool outliner_is_collection_tree_element(const TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (!tselem) {
+ return false;
+ }
+
+ if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
+ return true;
+ }
+ else if (tselem->type == 0 && te->idcode == ID_GR) {
+ return true;
+ }
+
+ return false;
+}
+
+Collection *outliner_collection_from_tree_element(const TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (!tselem) {
+ return NULL;
+ }
+
+ if (tselem->type == TSE_LAYER_COLLECTION) {
+ LayerCollection *lc = te->directdata;
+ return lc->collection;
+ }
+ else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
+ Scene *scene = (Scene *)tselem->id;
+ return BKE_collection_master(scene);
+ }
+ else if (tselem->type == 0 && te->idcode == ID_GR) {
+ return (Collection *)tselem->id;
+ }
+
+ return NULL;
+}
+
+TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
+{
+ struct IDsSelectedData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (outliner_is_collection_tree_element(te)) {
+ BLI_addtail(&data->selected_array, BLI_genericNodeN(te));
+ return TRAVERSE_CONTINUE;
+ }
+
+ if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ return TRAVERSE_CONTINUE;
+}
+
+TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
+{
+ struct IDsSelectedData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (outliner_is_collection_tree_element(te)) {
+ return TRAVERSE_CONTINUE;
+ }
+
+ if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ BLI_addtail(&data->selected_array, BLI_genericNodeN(te));
+
+ return TRAVERSE_CONTINUE;
+}
+
+/* -------------------------------------------------------------------- */
+/* Poll functions. */
+
+bool ED_outliner_collections_editor_poll(bContext *C)
+{
+ SpaceOops *so = CTX_wm_space_outliner(C);
+ return (so != NULL) && ELEM(so->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
+}
+
+
+/********************************* New Collection ****************************/
+
+struct CollectionNewData
+{
+ bool error;
+ Collection *collection;
+};
+
+static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
+{
+ struct CollectionNewData *data = customdata;
+ Collection *collection = outliner_collection_from_tree_element(te);
+
+ if (!collection) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ if (data->collection != NULL) {
+ data->error = true;
+ return TRAVERSE_BREAK;
+ }
+
+ data->collection = collection;
+ return TRAVERSE_CONTINUE;
+}
+
+static int collection_new_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ struct CollectionNewData data = {
+ .error = false,
+ .collection = NULL,
+ };
+
+ if (RNA_boolean_get(op->ptr, "nested")) {
+ outliner_build_tree(bmain, scene, view_layer, soops, ar);
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data);
+
+ if (data.error) {
+ BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (!data.collection && (soops->outlinevis == SO_VIEW_LAYER)) {
+ data.collection = BKE_collection_master(scene);
+ }
+
+ BKE_collection_add(
+ bmain,
+ data.collection,
+ NULL);
+
+ DEG_id_tag_update(&data.collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ outliner_cleanup_tree(soops);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Collection";
+ ot->idname = "OUTLINER_OT_collection_new";
+ ot->description = "Add a new collection inside selected collection";
+
+ /* api callbacks */
+ ot->exec = collection_new_exec;
+ ot->poll = ED_outliner_collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop = RNA_def_boolean(ot->srna, "nested", true, "Nested", "Add as child of selected collection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/**************************** Delete Collection ******************************/
+
+struct CollectionEditData {
+ Scene *scene;
+ SpaceOops *soops;
+ GSet *collections_to_edit;
+};
+
+static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
+{
+ struct CollectionEditData *data = customdata;
+ Collection *collection = outliner_collection_from_tree_element(te);
+
+ if (!collection) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ if (collection == BKE_collection_master(data->scene)) {
+ /* skip - showing warning/error message might be misleading
+ * when deleting multiple collections, so just do nothing */
+ }
+ else {
+ /* Delete, duplicate and link don't edit children, those will come along
+ * with the parents. */
+ BLI_gset_add(data->collections_to_edit, collection);
+ return TRAVERSE_SKIP_CHILDS;
+ }
+
+ return TRAVERSE_CONTINUE;
+}
+
+static int collection_delete_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
+ bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
+
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
+
+ /* We first walk over and find the Collections we actually want to delete (ignoring duplicates). */
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
+
+ /* Effectively delete the collections. */
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+
+ /* Test in case collection got deleted as part of another one. */
+ if (BLI_findindex(&bmain->collection, collection) != -1) {
+ BKE_collection_delete(bmain, collection, hierarchy);
+ }
+ }
+
+ BLI_gset_free(data.collections_to_edit, NULL);
+
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Collection";
+ ot->idname = "OUTLINER_OT_collection_delete";
+ ot->description = "Delete selected collections";
+
+ /* api callbacks */
+ ot->exec = collection_delete_exec;
+ ot->poll = ED_outliner_collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop = RNA_def_boolean(ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/****************************** Select Objects *******************************/
+
+struct CollectionObjectsSelectData {
+ bool error;
+ LayerCollection *layer_collection;
+};
+
+static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata)
+{
+ struct CollectionObjectsSelectData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ switch (tselem->type) {
+ case TSE_LAYER_COLLECTION:
+ data->layer_collection = te->directdata;
+ return TRAVERSE_BREAK;
+ case TSE_R_LAYER:
+ case TSE_SCENE_COLLECTION_BASE:
+ case TSE_VIEW_COLLECTION_BASE:
+ return TRAVERSE_CONTINUE;
+ default:
+ return TRAVERSE_SKIP_CHILDS;
+ }
+}
+
+static LayerCollection *outliner_active_layer_collection(bContext *C)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ struct CollectionObjectsSelectData data = {
+ .layer_collection = NULL,
+ };
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data);
+ return data.layer_collection;
+}
+
+static int collection_objects_select_exec(bContext *C, wmOperator *op)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *layer_collection = outliner_active_layer_collection(C);
+ bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect");
+
+ if (layer_collection == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
+
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Objects";
+ ot->idname = "OUTLINER_OT_collection_objects_select";
+ ot->description = "Select objects in collection";
+
+ /* api callbacks */
+ ot->exec = collection_objects_select_exec;
+ ot->poll = ED_outliner_collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Deselect Objects";
+ ot->idname = "OUTLINER_OT_collection_objects_deselect";
+ ot->description = "Deselect objects in collection";
+
+ /* api callbacks */
+ ot->exec = collection_objects_select_exec;
+ ot->poll = ED_outliner_collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************** Duplicate Collection *****************************/
+
+struct CollectionDuplicateData {
+ TreeElement *te;
+};
+
+static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata)
+{
+ struct CollectionDuplicateData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ switch (tselem->type) {
+ case TSE_LAYER_COLLECTION:
+ data->te = te;
+ return TRAVERSE_BREAK;
+ case TSE_R_LAYER:
+ case TSE_SCENE_COLLECTION_BASE:
+ case TSE_VIEW_COLLECTION_BASE:
+ default:
+ return TRAVERSE_CONTINUE;
+ }
+}
+
+static TreeElement *outliner_active_collection(bContext *C)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ struct CollectionDuplicateData data = {
+ .te = NULL,
+ };
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data);
+ return data.te;
+}
+
+static int collection_duplicate_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te = outliner_active_collection(C);
+ BLI_assert(te != NULL);
+
+ Collection *collection = outliner_collection_from_tree_element(te);
+ Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL;
+
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BKE_report(op->reports, RPT_ERROR, "Can't duplicate the master collection");
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (soops->outlinevis) {
+ case SO_SCENES:
+ case SO_VIEW_LAYER:
+ case SO_LIBRARIES:
+ BKE_collection_copy(bmain, parent, collection);
+ break;
+ }
+
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C));
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Collection";
+ ot->idname = "OUTLINER_OT_collection_duplicate";
+ ot->description = "Duplicate selected collections";
+
+ /* api callbacks */
+ ot->exec = collection_duplicate_exec;
+ ot->poll = ED_outliner_collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/**************************** Link Collection ******************************/
+
+static int collection_link_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Collection *active_collection = CTX_data_layer_collection(C)->collection;
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
+
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
+
+ /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
+
+ /* Effectively link the collections. */
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ BKE_collection_child_add(bmain, active_collection, collection);
+ id_fake_user_clear(&collection->id);
+ }
+
+ BLI_gset_free(data.collections_to_edit, NULL);
+
+ DEG_id_tag_update(&active_collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_link(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Link Collection";
+ ot->idname = "OUTLINER_OT_collection_link";
+ ot->description = "Link selected collections to active scene";
+
+ /* api callbacks */
+ ot->exec = collection_link_exec;
+ ot->poll = ED_outliner_collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************** Instance Collection ******************************/
+
+static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
+
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
+
+ /* We first walk over and find the Collections we actually want to instance (ignoring duplicates). */
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
+
+ /* Find an active collection to add to, that doesn't give dependency cycles. */
+ LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
+
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+
+ while (BKE_collection_find_cycle(active_lc->collection, collection)) {
+ active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
+ }
+ }
+
+ /* Effectively instance the collections. */
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false);
+ ob->dup_group = collection;
+ ob->transflag |= OB_DUPLICOLLECTION;
+ id_lib_extern(&collection->id);
+ }
+
+ BLI_gset_free(data.collections_to_edit, NULL);
+
+ DEG_relations_tag_update(bmain);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_instance(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Instance Collection";
+ ot->idname = "OUTLINER_OT_collection_instance";
+ ot->description = "Instance selected collections to active scene";
+
+ /* api callbacks */
+ ot->exec = collection_instance_exec;
+ ot->poll = ED_outliner_collections_editor_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************** Exclude Collection ******************************/
+
+static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
+{
+ struct CollectionEditData *data = customdata;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
+ return TRAVERSE_CONTINUE;
+ }
+
+ LayerCollection *lc = te->directdata;
+
+ if (lc->collection->flag & COLLECTION_IS_MASTER) {
+ /* skip - showing warning/error message might be misleading
+ * when deleting multiple collections, so just do nothing */
+ }
+ else {
+ /* Delete, duplicate and link don't edit children, those will come along
+ * with the parents. */
+ BLI_gset_add(data->collections_to_edit, lc);
+ }
+
+ return TRAVERSE_CONTINUE;
+}
+
+static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
+{
+ /* Poll function so the right click menu show current state of selected collections. */
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ if (!(soops && soops->outlinevis == SO_VIEW_LAYER)) {
+ return false;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
+ bool result = false;
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
+
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+
+ if (clear && (lc->flag & flag)) {
+ result = true;
+ }
+ else if (!clear && !(lc->flag & flag)) {
+ result = true;
+ }
+ }
+
+ BLI_gset_free(data.collections_to_edit, NULL);
+ return result;
+}
+
+static bool collections_exclude_set_poll(bContext *C)
+{
+ return collections_view_layer_poll(C, false, LAYER_COLLECTION_EXCLUDE);
+}
+
+static bool collections_exclude_clear_poll(bContext *C)
+{
+ return collections_view_layer_poll(C, true, LAYER_COLLECTION_EXCLUDE);
+}
+
+static bool collections_holdout_set_poll(bContext *C)
+{
+ return collections_view_layer_poll(C, false, LAYER_COLLECTION_HOLDOUT);
+}
+
+static bool collections_holdout_clear_poll(bContext *C)
+{
+ return collections_view_layer_poll(C, true, LAYER_COLLECTION_HOLDOUT);
+}
+
+static bool collections_indirect_only_set_poll(bContext *C)
+{
+ return collections_view_layer_poll(C, false, LAYER_COLLECTION_INDIRECT_ONLY);
+}
+
+static bool collections_indirect_only_clear_poll(bContext *C)
+{
+ return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY);
+}
+
+static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag)
+{
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ if (lc->flag & flag) {
+ nlc->flag |= flag;
+ }
+ else {
+ nlc->flag &= ~flag;
+ }
+
+ layer_collection_flag_recursive_set(nlc, flag);
+ }
+}
+
+static int collection_view_layer_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct CollectionEditData data = {.scene = scene, .soops = soops};
+ bool clear = strstr(op->idname, "clear") != NULL;
+ int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT :
+ strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY :
+ LAYER_COLLECTION_EXCLUDE;
+
+ data.collections_to_edit = BLI_gset_ptr_new(__func__);
+
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
+
+ GSetIterator collections_to_edit_iter;
+ GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
+ LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+
+ if (!(lc->collection->flag & COLLECTION_IS_MASTER)) {
+ if (clear) {
+ lc->flag &= ~flag;
+ }
+ else {
+ lc->flag |= flag;
+ }
+
+ layer_collection_flag_recursive_set(lc, flag);
+ }
+ }
+
+ BLI_gset_free(data.collections_to_edit, NULL);
+
+ BKE_layer_collection_sync(scene, view_layer);
+ DEG_relations_tag_update(bmain);
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Exclude";
+ ot->idname = "OUTLINER_OT_collection_exclude_set";
+ ot->description = "Exclude collection from the active view layer";
+
+ /* api callbacks */
+ ot->exec = collection_view_layer_exec;
+ ot->poll = collections_exclude_set_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void OUTLINER_OT_collection_exclude_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Exclude";
+ ot->idname = "OUTLINER_OT_collection_exclude_clear";
+ ot->description = "Include collection in the active view layer";
+
+ /* api callbacks */
+ ot->exec = collection_view_layer_exec;
+ ot->poll = collections_exclude_clear_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void OUTLINER_OT_collection_holdout_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Holdout";
+ ot->idname = "OUTLINER_OT_collection_holdout_set";
+ ot->description = "Mask collection in the active view layer";
+
+ /* api callbacks */
+ ot->exec = collection_view_layer_exec;
+ ot->poll = collections_holdout_set_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void OUTLINER_OT_collection_holdout_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Holdout";
+ ot->idname = "OUTLINER_OT_collection_holdout_clear";
+ ot->description = "Clear masking of collection in the active view layer";
+
+ /* api callbacks */
+ ot->exec = collection_view_layer_exec;
+ ot->poll = collections_holdout_clear_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void OUTLINER_OT_collection_indirect_only_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Indirect Only";
+ ot->idname = "OUTLINER_OT_collection_indirect_only_set";
+ ot->description = "Set collection to only contribute indirectly (through shadows and reflections) in the view layer";
+
+ /* api callbacks */
+ ot->exec = collection_view_layer_exec;
+ ot->poll = collections_indirect_only_set_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void OUTLINER_OT_collection_indirect_only_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Indirect Only";
+ ot->idname = "OUTLINER_OT_collection_indirect_only_clear";
+ ot->description = "Clear collection contributing only indirectly in the view layer";
+
+ /* api callbacks */
+ ot->exec = collection_view_layer_exec;
+ ot->poll = collections_indirect_only_clear_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/**
+ * Populates the \param objects ListBase with all the outliner selected objects
+ * We store it as (Object *)LinkData->data
+ * \param objects expected to be empty
+ */
+void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ struct IDsSelectedData data = {{NULL}};
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
+ LISTBASE_FOREACH (LinkData *, link, &data.selected_array) {
+ TreeElement *ten_selected = (TreeElement *)link->data;
+ Object *ob = (Object *)TREESTORE(ten_selected)->id;
+ BLI_addtail(objects, BLI_genericNodeN(ob));
+ }
+ BLI_freelistN(&data.selected_array);
+}
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
new file mode 100644
index 00000000000..2217048aca7
--- /dev/null
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -0,0 +1,1013 @@
+/*
+ * ***** 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) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_outliner/outliner_dragdrop.c
+ * \ingroup spoutliner
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_collection.h"
+#include "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "ED_object.h"
+#include "ED_outliner.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "GPU_state.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "outliner_intern.h"
+
+/* ******************** Drop Target Find *********************** */
+
+static TreeElement *outliner_dropzone_element(TreeElement *te, const float fmval[2], const bool children)
+{
+ if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
+ /* name and first icon */
+ if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend))
+ return te;
+ }
+ /* Not it. Let's look at its children. */
+ if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) {
+ for (te = te->subtree.first; te; te = te->next) {
+ TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
+ if (te_valid)
+ return te_valid;
+ }
+ }
+ return NULL;
+}
+
+/* Find tree element to drop into. */
+static TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const bool children)
+{
+ TreeElement *te;
+
+ for (te = soops->tree.first; te; te = te->next) {
+ TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
+ if (te_valid)
+ return te_valid;
+ }
+ return NULL;
+}
+
+static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ float fmval[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ return outliner_dropzone_find(soops, fmval, true);
+}
+
+static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode)
+{
+ TreeElement *te = outliner_drop_find(C, event);
+ TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL;
+
+ if (te && te->idcode == idcode && tselem->type == 0) {
+ return tselem->id;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/* Find tree element to drop into, with additional before and after reorder support. */
+static TreeElement *outliner_drop_insert_find(
+ bContext *C, const wmEvent *event,
+ TreeElementInsertType *r_insert_type)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ TreeElement *te_hovered;
+ float view_mval[2];
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+ te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
+
+ if (te_hovered) {
+ /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */
+ const float margin = UI_UNIT_Y * (1.0f / 4);
+
+ if (view_mval[1] < (te_hovered->ys + margin)) {
+ if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) {
+ /* inserting after a open item means we insert into it, but as first child */
+ if (BLI_listbase_is_empty(&te_hovered->subtree)) {
+ *r_insert_type = TE_INSERT_INTO;
+ return te_hovered;
+ }
+ else {
+ *r_insert_type = TE_INSERT_BEFORE;
+ return te_hovered->subtree.first;
+ }
+ }
+ else {
+ *r_insert_type = TE_INSERT_AFTER;
+ return te_hovered;
+ }
+ }
+ else if (view_mval[1] > (te_hovered->ys + (3 * margin))) {
+ *r_insert_type = TE_INSERT_BEFORE;
+ return te_hovered;
+ }
+ else {
+ *r_insert_type = TE_INSERT_INTO;
+ return te_hovered;
+ }
+ }
+ else {
+ /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */
+ TreeElement *first = soops->tree.first;
+ TreeElement *last = soops->tree.last;
+
+ if (view_mval[1] < last->ys) {
+ *r_insert_type = TE_INSERT_AFTER;
+ return last;
+ }
+ else if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
+ *r_insert_type = TE_INSERT_BEFORE;
+ return first;
+ }
+ else {
+ BLI_assert(0);
+ return NULL;
+ }
+ }
+}
+
+static Collection *outliner_collection_from_tree_element_and_parents(TreeElement *te, TreeElement **r_te)
+{
+ while (te != NULL) {
+ Collection *collection = outliner_collection_from_tree_element(te);
+ if (collection) {
+ *r_te = te;
+ return collection;
+ }
+ te = te->parent;
+ }
+ return NULL;
+}
+
+static TreeElement *outliner_drop_insert_collection_find(
+ bContext *C, const wmEvent *event,
+ TreeElementInsertType *r_insert_type)
+{
+ TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type);
+ if (!te) return NULL;
+
+ TreeElement *collection_te;
+ Collection *collection = outliner_collection_from_tree_element_and_parents(te, &collection_te);
+ if (!collection) return NULL;
+
+ if (collection_te != te) {
+ *r_insert_type = TE_INSERT_INTO;
+ }
+
+ /* We can't insert before/after master collection. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ *r_insert_type = TE_INSERT_INTO;
+ }
+
+ return collection_te;
+}
+
+/* ******************** Parent Drop Operator *********************** */
+
+static bool parent_drop_allowed(SpaceOops *soops, TreeElement *te, Object *potential_child)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (te->idcode != ID_OB || tselem->type != 0) {
+ return false;
+ }
+
+ Object *potential_parent = (Object *)tselem->id;
+
+ if (potential_parent == potential_child) return false;
+ if (BKE_object_is_child_recursive(potential_child, potential_parent)) return false;
+ if (potential_parent == potential_child->parent) return false;
+
+ /* check that parent/child are both in the same scene */
+ Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
+
+ /* currently outliner organized in a way that if there's no parent scene
+ * element for object it means that all displayed objects belong to
+ * active scene and parenting them is allowed (sergey)
+ */
+ if (scene) {
+ for (ViewLayer *view_layer = scene->view_layers.first;
+ view_layer;
+ view_layer = view_layer->next)
+ {
+ if (BKE_view_layer_base_find(view_layer, potential_child)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+static bool allow_parenting_without_modifier_key(SpaceOops *soops)
+{
+ switch (soops->outlinevis) {
+ case SO_VIEW_LAYER:
+ return soops->filter & SO_FILTER_NO_COLLECTION;
+ case SO_SCENES:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ bool changed = outliner_flag_set(&soops->tree, TSE_DRAG_ANY, false);
+ if (changed) ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
+
+ Object *potential_child = (Object *)WM_drag_ID(drag, ID_OB);
+ if (!potential_child) return false;
+
+ if (!allow_parenting_without_modifier_key(soops)) {
+ if (!event->shift) return false;
+ }
+
+ TreeElement *te = outliner_drop_find(C, event);
+ if (!te) return false;
+
+ if (parent_drop_allowed(soops, te, potential_child)) {
+ TREESTORE(te)->flag |= TSE_DRAG_INTO;
+ ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
+ return true;
+ }
+
+ return false;
+}
+
+static int parent_drop_exec(bContext *C, wmOperator *op)
+{
+ Object *par = NULL, *ob = NULL;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ int partype = -1;
+ char parname[MAX_NAME], childname[MAX_NAME];
+
+ partype = RNA_enum_get(op->ptr, "type");
+ RNA_string_get(op->ptr, "parent", parname);
+ par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname);
+ RNA_string_get(op->ptr, "child", childname);
+ ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname);
+
+ if (ID_IS_LINKED(ob)) {
+ BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL);
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te = outliner_drop_find(C, event);
+ TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
+
+ if (!(te && te->idcode == ID_OB && tselem->type == 0)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *par = (Object *)tselem->id;
+ Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
+
+ if (ELEM(NULL, ob, par)) {
+ return OPERATOR_CANCELLED;
+ }
+ if (ob == par) {
+ return OPERATOR_CANCELLED;
+ }
+ if (ID_IS_LINKED(ob)) {
+ BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
+ return OPERATOR_CANCELLED;
+ }
+
+ char childname[MAX_NAME];
+ char parname[MAX_NAME];
+ STRNCPY(childname, ob->id.name + 2);
+ STRNCPY(parname, par->id.name + 2);
+ RNA_string_set(op->ptr, "child", childname);
+ RNA_string_set(op->ptr, "parent", parname);
+
+ Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
+
+ if (scene == NULL) {
+ /* currently outlier organized in a way, that if there's no parent scene
+ * element for object it means that all displayed objects belong to
+ * active scene and parenting them is allowed (sergey)
+ */
+
+ scene = CTX_data_scene(C);
+ }
+
+ if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) {
+ int partype = 0;
+ if (ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL)) {
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ }
+ }
+ else {
+ /* Menu creation */
+ wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+ PointerRNA ptr;
+
+ /* Cannot use uiItemEnumO()... have multiple properties to set. */
+ uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_OBJECT);
+
+ /* par becomes parent, make the associated menus */
+ if (par->type == OB_ARMATURE) {
+ uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_ARMATURE);
+
+ uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
+
+ uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
+
+ uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
+
+ uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_BONE);
+ }
+ else if (par->type == OB_CURVE) {
+ uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_CURVE);
+
+ uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_FOLLOW);
+
+ uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
+ }
+ else if (par->type == OB_LATTICE) {
+ uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
+ RNA_string_set(&ptr, "parent", parname);
+ RNA_string_set(&ptr, "child", childname);
+ RNA_enum_set(&ptr, "type", PAR_LATTICE);
+ }
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_parent_drop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Drop to Set Parent";
+ ot->description = "Drag to parent in Outliner";
+ ot->idname = "OUTLINER_OT_parent_drop";
+
+ /* api callbacks */
+ ot->invoke = parent_drop_invoke;
+ ot->exec = parent_drop_exec;
+
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ /* properties */
+ RNA_def_string(ot->srna, "child", "Object", MAX_NAME, "Child", "Child Object");
+ RNA_def_string(ot->srna, "parent", "Object", MAX_NAME, "Parent", "Parent Object");
+ RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
+}
+
+/* ******************** Parent Clear Operator *********************** */
+
+static bool parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ if (!allow_parenting_without_modifier_key(soops)) {
+ if (!event->shift) return false;
+ }
+
+ Object *ob = (Object *)WM_drag_ID(drag, ID_OB);
+ if (!ob) return false;
+ if (!ob->parent) return false;
+
+ TreeElement *te = outliner_drop_find(C, event);
+ if (te) {
+ TreeStoreElem *tselem = TREESTORE(te);
+ ID *id = tselem->id;
+ if (!id) return true;
+
+ switch (GS(id->name)) {
+ case ID_OB:
+ return ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE);
+ case ID_GR:
+ return event->shift;
+ default:
+ return true;
+ }
+ }
+ else {
+ return true;
+ }
+}
+
+static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
+
+ if (ob == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_object_parent_clear(ob, 0);
+
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_parent_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Drop to Clear Parent";
+ ot->description = "Drag to clear parent in Outliner";
+ ot->idname = "OUTLINER_OT_parent_clear";
+
+ /* api callbacks */
+ ot->invoke = parent_clear_invoke;
+
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/* ******************** Scene Drop Operator *********************** */
+
+static bool scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
+{
+ /* Ensure item under cursor is valid drop target */
+ Object *ob = (Object *)WM_drag_ID(drag, ID_OB);
+ return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL));
+}
+
+static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE);
+ Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
+
+ if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (BKE_scene_has_object(scene, ob)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Collection *collection;
+ if (scene != CTX_data_scene(C)) {
+ /* when linking to an inactive scene link to the master collection */
+ collection = BKE_collection_master(scene);
+ }
+ else {
+ collection = CTX_data_collection(C);
+ }
+
+ BKE_collection_object_add(bmain, collection, ob);
+
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+ }
+
+ DEG_relations_tag_update(bmain);
+
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_scene_drop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Drop Object to Scene";
+ ot->description = "Drag object to scene in Outliner";
+ ot->idname = "OUTLINER_OT_scene_drop";
+
+ /* api callbacks */
+ ot->invoke = scene_drop_invoke;
+
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/* ******************** Material Drop Operator *********************** */
+
+static bool material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
+{
+ /* Ensure item under cursor is valid drop target */
+ Material *ma = (Material *)WM_drag_ID(drag, ID_MA);
+ return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL));
+}
+
+static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB);
+ Material *ma = (Material *)WM_drag_ID_from_event(event, ID_MA);
+
+ if (ELEM(NULL, ob, ma)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ assign_material(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+ WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_material_drop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Drop Material on Object";
+ ot->description = "Drag material to object in Outliner";
+ ot->idname = "OUTLINER_OT_material_drop";
+
+ /* api callbacks */
+ ot->invoke = material_drop_invoke;
+
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/* ******************** Collection Drop Operator *********************** */
+
+typedef struct CollectionDrop {
+ Collection *from;
+ Collection *to;
+
+ TreeElement *te;
+ TreeElementInsertType insert_type;
+} CollectionDrop;
+
+static Collection *collection_parent_from_ID(ID *id)
+{
+ /* Can't change linked parent collections. */
+ if (!id || ID_IS_LINKED(id)) {
+ return NULL;
+ }
+
+ /* Also support dropping into/from scene collection. */
+ if (GS(id->name) == ID_SCE) {
+ return ((Scene *)id)->master_collection;
+ }
+ else if (GS(id->name) == ID_GR) {
+ return (Collection *)id;
+ }
+
+ return NULL;
+}
+
+static bool collection_drop_init(bContext *C, wmDrag *drag, const wmEvent *event, CollectionDrop *data)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ /* Get collection to drop into. */
+ TreeElementInsertType insert_type;
+ TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type);
+ if (!te) {
+ return false;
+ }
+
+ Collection *to_collection = outliner_collection_from_tree_element(te);
+ if (ID_IS_LINKED(to_collection)) {
+ return false;
+ }
+
+ /* Get drag datablocks. */
+ if (drag->type != WM_DRAG_ID) {
+ return false;
+ }
+
+ wmDragID *drag_id = drag->ids.first;
+ if (drag_id == NULL) {
+ return false;
+ }
+
+ ID *id = drag_id->id;
+ if (!(id && ELEM(GS(id->name), ID_GR, ID_OB))) {
+ return false;
+ }
+
+ /* Get collection to drag out of. */
+ ID *parent = drag_id->from_parent;
+ Collection *from_collection = collection_parent_from_ID(parent);
+ if (event->ctrl || soops->outlinevis == SO_SCENES) {
+ from_collection = NULL;
+ }
+
+ /* Get collections. */
+ if (GS(id->name) == ID_GR) {
+ if (id == &to_collection->id) {
+ return false;
+ }
+ }
+ else {
+ insert_type = TE_INSERT_INTO;
+ }
+
+ data->from = from_collection;
+ data->to = to_collection;
+ data->te = te;
+ data->insert_type = insert_type;
+
+ return true;
+}
+
+static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ bool changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false);
+
+ CollectionDrop data;
+ if (!event->shift && collection_drop_init(C, drag, event, &data)) {
+ TreeElement *te = data.te;
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (!data.from || event->ctrl) {
+ tselem->flag |= TSE_DRAG_INTO;
+ changed = true;
+ *tooltip = IFACE_("Link inside Collection");
+ }
+ else {
+ switch (data.insert_type) {
+ case TE_INSERT_BEFORE:
+ tselem->flag |= TSE_DRAG_BEFORE;
+ changed = true;
+ if (te->prev && outliner_is_collection_tree_element(te->prev)) {
+ *tooltip = TIP_("Move between collections");
+ }
+ else {
+ *tooltip = TIP_("Move before collection");
+ }
+ break;
+ case TE_INSERT_AFTER:
+ tselem->flag |= TSE_DRAG_AFTER;
+ changed = true;
+ if (te->next && outliner_is_collection_tree_element(te->next)) {
+ *tooltip = TIP_("Move between collections");
+ }
+ else {
+ *tooltip = TIP_("Move after collection");
+ }
+ break;
+ case TE_INSERT_INTO:
+ tselem->flag |= TSE_DRAG_INTO;
+ changed = true;
+ *tooltip = TIP_("Move inside collection (Ctrl to link, Shift to parent)");
+ break;
+ }
+ }
+ if (changed) ED_region_tag_redraw_no_rebuild(ar);
+ return true;
+ }
+ else {
+ if (changed) ED_region_tag_redraw_no_rebuild(ar);
+ return false;
+ }
+}
+
+static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ if (event->custom != EVT_DATA_DRAGDROP) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ListBase *lb = event->customdata;
+ wmDrag *drag = lb->first;
+
+ CollectionDrop data;
+ if (!collection_drop_init(C, drag, event, &data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Before/after insert handling. */
+ Collection *relative = NULL;
+ bool relative_after = false;
+
+ if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ relative = data.to;
+ relative_after = (data.insert_type == TE_INSERT_AFTER);
+
+ TreeElement *parent_te = outliner_find_parent_element(&soops->tree, NULL, data.te);
+ data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL;
+ }
+
+ if (!data.to) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (BKE_collection_is_empty(data.to)) {
+ TREESTORE(data.te)->flag &= ~TSE_CLOSED;
+ }
+
+ for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
+ /* Ctrl enables linking, so we don't need a from collection then. */
+ Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent);
+
+ if (GS(drag_id->id->name) == ID_OB) {
+ /* Move/link object into collection. */
+ Object *object = (Object *)drag_id->id;
+
+ if (from) {
+ BKE_collection_object_move(bmain, scene, data.to, from, object);
+ }
+ else {
+ BKE_collection_object_add(bmain, data.to, object);
+ }
+ }
+ else if (GS(drag_id->id->name) == ID_GR) {
+ /* Move/link collection into collection. */
+ Collection *collection = (Collection *)drag_id->id;
+
+ if (collection != from) {
+ BKE_collection_move(bmain, data.to, from, relative, relative_after, collection);
+ }
+ }
+
+ if (from) {
+ DEG_id_tag_update(&from->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+
+ /* Update dependency graph. */
+ DEG_id_tag_update(&data.to->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_collection_drop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Move to Collection";
+ ot->description = "Drag to move to collection in Outliner";
+ ot->idname = "OUTLINER_OT_collection_drop";
+
+ /* api callbacks */
+ ot->invoke = collection_drop_invoke;
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/* ********************* Outliner Drag Operator ******************** */
+
+static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event)
+{
+ /* note: using EVT_TWEAK_ events to trigger dragging is fine,
+ * it sends coordinates from where dragging was started */
+ const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
+ return outliner_find_item_at_y(soops, &soops->tree, my);
+}
+
+static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te = outliner_item_drag_element_find(soops, ar, event);
+
+ if (!te) {
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
+ TreeElementIcon data = tree_element_get_icon(TREESTORE(te), te);
+ if (!data.drag_id) {
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
+ wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP);
+
+ if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) {
+ /* For collections and objects we cheat and drag all selected. */
+
+ /* Only drag element under mouse if it was not selected before. */
+ if ((TREESTORE(te)->flag & TSE_SELECTED) == 0) {
+ outliner_flag_set(&soops->tree, TSE_SELECTED, 0);
+ TREESTORE(te)->flag |= TSE_SELECTED;
+ }
+
+ /* Gather all selected elements. */
+ struct IDsSelectedData selected = {
+ .selected_array = {NULL, NULL},
+ };
+
+ if (GS(data.drag_id->name) == ID_OB) {
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &selected);
+ }
+ else {
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_collections, &selected);
+ }
+
+ LISTBASE_FOREACH (LinkData *, link, &selected.selected_array) {
+ TreeElement *te_selected = (TreeElement *)link->data;
+ ID *id;
+
+ if (GS(data.drag_id->name) == ID_OB) {
+ id = TREESTORE(te_selected)->id;
+ }
+ else {
+ /* Keep collection hierarchies intact when dragging. */
+ bool parent_selected = false;
+ for (TreeElement *te_parent = te_selected->parent; te_parent; te_parent = te_parent->parent) {
+ if (outliner_is_collection_tree_element(te_parent)) {
+ if (TREESTORE(te_parent)->flag & TSE_SELECTED) {
+ parent_selected = true;
+ break;
+ }
+ }
+ }
+
+ if (parent_selected) {
+ continue;
+ }
+
+ id = &outliner_collection_from_tree_element(te_selected)->id;
+ }
+
+ /* Find parent collection. */
+ Collection *parent = NULL;
+
+ if (te_selected->parent) {
+ for (TreeElement *te_parent = te_selected->parent; te_parent; te_parent = te_parent->parent) {
+ if (outliner_is_collection_tree_element(te_parent)) {
+ parent = outliner_collection_from_tree_element(te_parent);
+ break;
+ }
+ }
+ }
+ else {
+ Scene *scene = CTX_data_scene(C);
+ parent = BKE_collection_master(scene);
+ }
+
+ WM_drag_add_ID(drag, id, &parent->id);
+ }
+
+ BLI_freelistN(&selected.selected_array);
+ }
+ else {
+ /* Add single ID. */
+ WM_drag_add_ID(drag, data.drag_id, data.drag_parent);
+ }
+
+ return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
+}
+
+/* Outliner drag and drop. This operator mostly exists to support dragging
+ * from outliner text instead of only from the icon, and also to show a
+ * hint in the statusbar keymap. */
+
+void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
+{
+ ot->name = "Drag and Drop";
+ ot->idname = "OUTLINER_OT_item_drag_drop";
+ ot->description = "Drag and drop element to another place";
+
+ ot->invoke = outliner_item_drag_drop_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
+/* *************************** Drop Boxes ************************** */
+
+/* region dropbox definition */
+void outliner_dropboxes(void)
+{
+ ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
+
+ WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL);
+ WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL);
+ WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL);
+ WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL);
+ WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, NULL);
+}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 3f3e3c89103..722ed393492 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -31,9 +31,11 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_group_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_lamp_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
@@ -48,15 +50,20 @@
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_idcode.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
#include "ED_keyframing.h"
@@ -66,8 +73,8 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
@@ -89,8 +96,9 @@ static void outliner_height(SpaceOops *soops, ListBase *lb, int *h)
TreeElement *te = lb->first;
while (te) {
TreeStoreElem *tselem = TREESTORE(te);
- if (TSELEM_OPEN(tselem, soops))
+ if (TSELEM_OPEN(tselem, soops)) {
outliner_height(soops, &te->subtree, h);
+ }
(*h) += UI_UNIT_Y;
te = te->next;
}
@@ -129,12 +137,27 @@ static void outliner_rna_width(SpaceOops *soops, ListBase *lb, int *w, int start
if (startx + 100 > *w)
*w = startx + 100;
- if (TSELEM_OPEN(tselem, soops))
+ if (TSELEM_OPEN(tselem, soops)) {
outliner_rna_width(soops, &te->subtree, w, startx + UI_UNIT_X);
+ }
te = te->next;
}
}
+/**
+ * The active object is only needed for reference.
+ */
+static bool is_object_data_in_editmode(const ID *id, const Object *obact)
+{
+ const short id_type = GS(id->name);
+ return (
+ (obact && (obact->mode & OB_MODE_EDIT)) &&
+ (id && OB_DATA_SUPPORT_EDITMODE(id_type)) &&
+ (GS(((ID *)obact->data)->name) == id_type) &&
+ BKE_object_data_is_in_editmode(id)
+ );
+}
+
/* ****************************************************** */
static void restrictbutton_recursive_ebone(bContext *C, EditBone *ebone_parent, int flag, bool set_flag)
@@ -172,129 +195,11 @@ static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_
}
-static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob_parent, char flag,
- bool state, bool deselect, const char *rnapropname)
-{
- Main *bmain = CTX_data_main(C);
- Object *ob;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (BKE_object_is_child_recursive(ob_parent, ob)) {
- /* only do if child object is selectable */
- if ((flag == OB_RESTRICT_SELECT) || (ob->restrictflag & OB_RESTRICT_SELECT) == 0) {
- if (state) {
- ob->restrictflag |= flag;
- if (deselect) {
- ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
- }
- }
- else {
- ob->restrictflag &= ~flag;
- }
- }
-
- if (rnapropname) {
- PointerRNA ptr;
- PropertyRNA *prop;
- ID *id;
- bAction *action;
- FCurve *fcu;
- bool driven, special;
-
- RNA_id_pointer_create(&ob->id, &ptr);
- prop = RNA_struct_find_property(&ptr, rnapropname);
- fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, NULL, &action, &driven, &special);
-
- if (fcu && !driven) {
- id = ptr.id.data;
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- eInsertKeyFlags key_flag = ANIM_get_keyframing_flags(scene, 1);
-
- fcu->flag &= ~FCURVE_SELECTED;
- insert_keyframe(bmain, reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path, fcu->array_index, CFRA, ts->keyframe_type, key_flag);
- /* Assuming this is not necessary here, since 'ancestor' object button will do it anyway. */
- /* WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); */
- }
- }
- }
- }
- }
-}
-
-static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2)
-{
- Scene *scene = (Scene *)poin;
- Object *ob = (Object *)poin2;
-
- if (!common_restrict_check(C, ob)) return;
-
- /* deselect objects that are invisible */
- if (ob->restrictflag & OB_RESTRICT_VIEW) {
- /* Ouch! There is no backwards pointer from Object to Base,
- * so have to do loop to find it. */
- ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
- }
-
- if (CTX_wm_window(C)->eventstate->ctrl) {
- restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_VIEW,
- (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true, "hide");
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
-
-}
-
-static void restrictbutton_sel_cb(bContext *C, void *poin, void *poin2)
-{
- Scene *scene = (Scene *)poin;
- Object *ob = (Object *)poin2;
-
- if (!common_restrict_check(C, ob)) return;
-
- /* if select restriction has just been turned on */
- if (ob->restrictflag & OB_RESTRICT_SELECT) {
- /* Ouch! There is no backwards pointer from Object to Base,
- * so have to do loop to find it. */
- ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
- }
-
- if (CTX_wm_window(C)->eventstate->ctrl) {
- restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_SELECT,
- (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true, NULL);
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
-
-}
-
-static void restrictbutton_rend_cb(bContext *C, void *poin, void *poin2)
-{
- Object *ob = (Object *)poin2;
-
- if (CTX_wm_window(C)->eventstate->ctrl) {
- restrictbutton_recursive_child(C, (Scene *)poin, ob, OB_RESTRICT_RENDER,
- (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false, "hide_render");
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, poin);
-}
-
static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2))
{
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin);
}
-static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *poin2)
-{
- Object *ob = (Object *)poin2;
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
-}
-
static void restrictbutton_bone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2)
{
Bone *bone = (Bone *)poin2;
@@ -355,118 +260,62 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-static int group_restrict_flag(Group *gr, int flag)
+static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
{
- GroupObject *gob;
+ ID *id = (ID *)poin;
-#ifdef USE_GROUP_SELECT
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if ((gob->ob->restrictflag & flag) == 0)
- return 0;
- }
- return 1;
-#else
- /* weak but fast */
- if ((gob = gr->gobject.first))
- if ((gob->ob->restrictflag & flag) == 0)
- return 0;
- return 1;
-#endif
-}
+ BLI_assert(id != NULL);
-static int group_select_flag(Group *gr)
-{
- GroupObject *gob;
-
-#ifdef USE_GROUP_SELECT
- for (gob = gr->gobject.first; gob; gob = gob->next)
- if ((gob->ob->flag & SELECT))
- return 1;
-
- return 0;
-#else
- /* weak but fast */
- if ((gob = gr->gobject.first))
- if (gob->ob->flag & SELECT)
- return 1;
- return 0;
-#endif
+ if (id->flag & LIB_FAKEUSER) {
+ id_us_plus(id);
+ }
+ else {
+ id_us_min(id);
+ }
}
-void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag)
+static void hidebutton_base_flag_cb(bContext *C, void *poin, void *poin2)
{
- Scene *scene = (Scene *)poin;
- GroupObject *gob;
- Group *gr = (Group *)poin2;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = poin;
+ Base *base = poin2;
+ bool extend = (CTX_wm_window(C)->eventstate->ctrl == 0);
- if (group_restrict_flag(gr, flag)) {
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (ID_IS_LINKED(gob->ob))
- continue;
+ /* Undo button toggle, let function do it. */
+ base->flag ^= BASE_HIDDEN;
- gob->ob->restrictflag &= ~flag;
+ BKE_base_set_visible(scene, view_layer, base, extend);
- if (flag == OB_RESTRICT_VIEW)
- if (gob->ob->flag & SELECT)
- ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_DESELECT);
- }
+ if (!extend && (base->flag & BASE_VISIBLE)) {
+ /* Auto select solo-ed object. */
+ ED_object_base_select(base, BA_SELECT);
+ view_layer->basact = base;
}
- else {
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (ID_IS_LINKED(gob->ob))
- continue;
- /* not in editmode */
- if (scene->obedit != gob->ob) {
- gob->ob->restrictflag |= flag;
-
- if (ELEM(flag, OB_RESTRICT_SELECT, OB_RESTRICT_VIEW)) {
- if ((gob->ob->flag & SELECT)) {
- ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_DESELECT);
- }
- }
- }
- }
- }
+ DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
-static void restrictbutton_gr_restrict_view(bContext *C, void *poin, void *poin2)
-{
- restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_VIEW);
- WM_event_add_notifier(C, NC_GROUP, NULL);
- DAG_id_type_tag(CTX_data_main(C), ID_OB);
-}
-static void restrictbutton_gr_restrict_select(bContext *C, void *poin, void *poin2)
-{
- restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_SELECT);
- WM_event_add_notifier(C, NC_GROUP, NULL);
-}
-static void restrictbutton_gr_restrict_render(bContext *C, void *poin, void *poin2)
+static void hidebutton_layer_collection_flag_cb(bContext *C, void *poin, void *poin2)
{
- restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_RENDER);
- WM_event_add_notifier(C, NC_GROUP, NULL);
-}
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = poin;
+ LayerCollection *lc = poin2;
+ bool extend = (CTX_wm_window(C)->eventstate->ctrl == 0);
-static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
-{
- ID *id = (ID *)poin;
+ /* Undo button toggle, let function do it. */
+ lc->runtime_flag ^= LAYER_COLLECTION_HAS_VISIBLE_OBJECTS;
- BLI_assert(id != NULL);
+ BKE_layer_collection_set_visible(scene, view_layer, lc, extend);
- if (id->flag & LIB_FAKEUSER) {
- id_us_plus(id);
- }
- else {
- id_us_min(id);
- }
+ DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
-
static void namebutton_cb(bContext *C, void *tsep, char *oldname)
{
Main *bmain = CTX_data_main(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
- Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
BLI_mempool *ts = soops->treestore;
TreeStoreElem *tselem = tsep;
@@ -486,6 +335,14 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
WM_event_add_notifier(C, NC_IMAGE, NULL); break;
case ID_SCE:
WM_event_add_notifier(C, NC_SCENE, NULL); break;
+ case ID_OB:
+ {
+ Object *ob = (Object *)tselem->id;
+ if (ob->type == OB_MBALL) {
+ DEG_id_tag_update(&ob->id, DEG_TAG_GEOMETRY);
+ }
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break;
+ }
default:
WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break;
}
@@ -528,37 +385,39 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
BLI_strncpy(newname, ebone->name, sizeof(ebone->name));
BLI_strncpy(ebone->name, oldname, sizeof(ebone->name));
ED_armature_bone_rename(bmain, obedit->data, oldname, newname);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, OBACT);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
break;
}
case TSE_BONE:
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+ bArmature *arm = (bArmature *)tselem->id;
Bone *bone = te->directdata;
- Object *ob;
char newname[sizeof(bone->name)];
/* always make current object active */
- tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, true);
- ob = OBACT;
+ tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true);
/* restore bone name */
BLI_strncpy(newname, bone->name, sizeof(bone->name));
BLI_strncpy(bone->name, oldname, sizeof(bone->name));
- ED_armature_bone_rename(bmain, ob->data, oldname, newname);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_armature_bone_rename(bmain, arm, oldname, newname);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
break;
}
case TSE_POSE_CHANNEL:
{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = (Object *)tselem->id;
bPoseChannel *pchan = te->directdata;
- Object *ob;
char newname[sizeof(pchan->name)];
/* always make current pose-bone active */
- tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, true);
- ob = OBACT;
+ tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true);
BLI_assert(ob->type == OB_ARMATURE);
@@ -566,7 +425,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
BLI_strncpy(newname, pchan->name, sizeof(pchan->name));
BLI_strncpy(pchan->name, oldname, sizeof(pchan->name));
ED_armature_bone_rename(bmain, ob->data, oldname, newname);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
break;
}
case TSE_POSEGRP:
@@ -581,247 +440,263 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
}
case TSE_GP_LAYER:
{
- bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock
+ bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
bGPDlayer *gpl = te->directdata;
+ /* always make layer active */
+ BKE_gpencil_layer_setactive(gpd, gpl);
+
// XXX: name needs translation stuff
BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.',
offsetof(bGPDlayer, info), sizeof(gpl->info));
+
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd);
break;
}
case TSE_R_LAYER:
+ {
+ Scene *scene = (Scene *)tselem->id;
+ ViewLayer *view_layer = te->directdata;
+
+ /* Restore old name. */
+ char newname[sizeof(view_layer->name)];
+ BLI_strncpy(newname, view_layer->name, sizeof(view_layer->name));
+ BLI_strncpy(view_layer->name, oldname, sizeof(view_layer->name));
+
+ /* Rename, preserving animation and compositing data. */
+ BKE_view_layer_rename(bmain, scene, view_layer, newname);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
break;
+ }
+ case TSE_LAYER_COLLECTION:
+ {
+ BLI_libblock_ensure_unique_name(bmain, tselem->id->name);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ break;
+ }
}
}
tselem->flag &= ~TSE_TEXTBUT;
}
}
-static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, ListBase *lb)
+static void outliner_draw_restrictbuts(
+ uiBlock *block, Scene *scene, ViewLayer *view_layer, ARegion *ar, SpaceOops *soops, ListBase *lb)
{
- uiBut *bt;
- TreeElement *te;
- TreeStoreElem *tselem;
- Object *ob = NULL;
- Group *gr = NULL;
-
- PropertyRNA *object_prop_hide, *object_prop_hide_select, *object_prop_hide_render;
-
- /* get RNA properties (once) */
- object_prop_hide = RNA_struct_type_find_property(&RNA_Object, "hide");
- object_prop_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select");
- object_prop_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render");
- BLI_assert(object_prop_hide && object_prop_hide_select && object_prop_hide_render);
+ /* Get RNA properties (once for speed). */
+ static struct RestrictProperties {
+ bool initialized;
+
+ PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render;
+ PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render;
+ PropertyRNA *modifier_show_viewport, *modifier_show_render;
+ } props = {false};
+
+ if (!props.initialized) {
+ props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport");
+ props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select");
+ props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render");
+ props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select");
+ props.collection_hide_viewport = RNA_struct_type_find_property(&RNA_Collection, "hide_viewport");
+ props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render");
+ props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport");
+ props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render");
+
+ props.initialized = true;
+ }
+ /* Create buttons. */
+ uiBut *bt;
- for (te = lb->first; te; te = te->next) {
- tselem = TREESTORE(te);
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
- /* objects have toggle-able restriction flags */
- if (tselem->type == 0 && te->idcode == ID_OB) {
- PointerRNA ptr;
+ if (tselem->type == TSE_R_LAYER && (soops->outlinevis == SO_SCENES)) {
+ /* View layer render toggle. */
+ ViewLayer *layer = te->directdata;
+
+ bt = uiDefIconButBitS(
+ block, UI_BTYPE_ICON_TOGGLE_N, VIEW_LAYER_RENDER, 0, ICON_RESTRICT_RENDER_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &layer->flag, 0, 0, 0, 0, TIP_("Use view layer for rendering"));
+ UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
+ }
+ else if (tselem->type == 0 && te->idcode == ID_OB) {
+ Object *ob = (Object *)tselem->id;
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (base) {
+ bt = uiDefIconButBitS(
+ block, UI_BTYPE_ICON_TOGGLE, BASE_HIDDEN, 0, ICON_HIDE_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &base->flag, 0, 0, 0, 0,
+ TIP_("Hide object in viewport (Ctrl to isolate)"));
+ UI_but_func_set(bt, hidebutton_base_flag_cb, view_layer, base);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
+ }
- ob = (Object *)tselem->id;
- RNA_pointer_create((ID *)ob, &RNA_Object, ob, &ptr);
+ PointerRNA ptr;
+ RNA_pointer_create(&ob->id, &RNA_Object, ob, &ptr);
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_VIEW_OFF,
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
- &ptr, object_prop_hide, -1, 0, 0, -1, -1,
- TIP_("Restrict viewport visibility (Ctrl - Recursive)"));
- UI_but_func_set(bt, restrictbutton_view_cb, scene, ob);
+ &ptr, props.object_hide_viewport, -1, 0, 0, -1, -1, NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y,
- &ptr, object_prop_hide_select, -1, 0, 0, -1, -1,
- TIP_("Restrict viewport selection (Ctrl - Recursive)"));
- UI_but_func_set(bt, restrictbutton_sel_cb, scene, ob);
+ &ptr, props.object_hide_select, -1, 0, 0, -1, -1, NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_RENDER_OFF,
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
- &ptr, object_prop_hide_render, -1, 0, 0, -1, -1,
- TIP_("Restrict rendering (Ctrl - Recursive)"));
- UI_but_func_set(bt, restrictbutton_rend_cb, scene, ob);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
-
- UI_block_emboss_set(block, UI_EMBOSS);
-
- }
- if (tselem->type == 0 && te->idcode == ID_GR) {
- int restrict_bool;
- int but_flag = UI_BUT_DRAG_LOCK;
- gr = (Group *)tselem->id;
-
- if (ID_IS_LINKED(gr))
- but_flag |= UI_BUT_DISABLED;
-
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
-
- restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW);
- bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Restrict/Allow visibility in the 3D View"));
- UI_but_func_set(bt, restrictbutton_gr_restrict_view, scene, gr);
- UI_but_flag_enable(bt, but_flag);
-
- restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT);
- bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Restrict/Allow selection in the 3D View"));
- UI_but_func_set(bt, restrictbutton_gr_restrict_select, scene, gr);
- UI_but_flag_enable(bt, but_flag);
-
- restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER);
- bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
- UI_but_func_set(bt, restrictbutton_gr_restrict_render, scene, gr);
- UI_but_flag_enable(bt, but_flag);
-
- UI_block_emboss_set(block, UI_EMBOSS);
- }
- /* scene render layers and passes have toggle-able flags too! */
- else if (tselem->type == TSE_R_LAYER) {
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
-
- bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, te->directdata, 0, 0, 0, 0, TIP_("Render this RenderLayer"));
- UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
-
- UI_block_emboss_set(block, UI_EMBOSS);
- }
- else if (tselem->type == TSE_R_PASS) {
- int *layflag = te->directdata;
- int passflag = 1 << tselem->nr;
-
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
-
-
- bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, passflag, 0, ICON_CHECKBOX_HLT - 1,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Render this Pass"));
- UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
+ &ptr, props.object_hide_render, -1, 0, 0, -1, -1, NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- layflag++; /* is lay_xor */
- if (ELEM(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
- SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
- {
- bt = uiDefIconButBitI(block, UI_BTYPE_TOGGLE, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Exclude this Pass from Combined"));
- UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- }
-
- UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_MODIFIER) {
ModifierData *md = (ModifierData *)te->directdata;
- ob = (Object *)tselem->id;
-
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &(md->mode), 0, 0, 0, 0,
- TIP_("Restrict/Allow visibility in the 3D View"));
- UI_but_func_set(bt, restrictbutton_modifier_cb, scene, ob);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
- UI_but_func_set(bt, restrictbutton_modifier_cb, scene, ob);
+ PointerRNA ptr;
+ RNA_pointer_create(tselem->id, &RNA_Modifier, md, &ptr);
+
+ bt = uiDefIconButR_prop(
+ block, UI_BTYPE_ICON_TOGGLE, 0, 0,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
+ &ptr, props.modifier_show_viewport, -1, 0, 0, -1, -1, NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- UI_block_emboss_set(block, UI_EMBOSS);
+ bt = uiDefIconButR_prop(
+ block, UI_BTYPE_ICON_TOGGLE, 0, 0,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
+ &ptr, props.modifier_show_render, -1, 0, 0, -1, -1, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
}
else if (tselem->type == TSE_POSE_CHANNEL) {
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
- ob = (Object *)tselem->id;
+ Object *ob = (Object *)tselem->id;
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
- TIP_("Restrict/Allow visibility in the 3D View"));
+ bt = uiDefIconButBitI(
+ block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_P, 0, ICON_HIDE_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
- bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
- TIP_("Restrict/Allow selection in the 3D View"));
+ bt = uiDefIconButBitI(
+ block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
+ TIP_("Restrict/Allow selection in the 3D View"));
UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
-
- UI_block_emboss_set(block, UI_EMBOSS);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
else if (tselem->type == TSE_EBONE) {
EditBone *ebone = (EditBone *)te->directdata;
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
- TIP_("Restrict/Allow visibility in the 3D View"));
+ bt = uiDefIconButBitI(
+ block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
- bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
- TIP_("Restrict/Allow selection in the 3D View"));
+ bt = uiDefIconButBitI(
+ block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
+ TIP_("Restrict/Allow selection in the 3D View"));
UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
-
- UI_block_emboss_set(block, UI_EMBOSS);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
else if (tselem->type == TSE_GP_LAYER) {
bGPDlayer *gpl = (bGPDlayer *)te->directdata;
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
-
- bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_HIDE, 0, ICON_RESTRICT_VIEW_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
- TIP_("Restrict/Allow visibility in the 3D View"));
+ bt = uiDefIconButBitS(
+ block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_HIDE, 0, ICON_HIDE_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
- bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_LOCKED, 0, ICON_UNLOCKED,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
- TIP_("Restrict/Allow editing of strokes and keyframes in this layer"));
+ bt = uiDefIconButBitS(
+ block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_LOCKED, 0, ICON_UNLOCKED,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow editing of strokes and keyframes in this layer"));
UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
/* TODO: visibility in renders */
+ }
+ else if (outliner_is_collection_tree_element(te)) {
+ LayerCollection *lc = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : NULL;
+ Collection *collection = outliner_collection_from_tree_element(te);
+
+ if ((!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) &&
+ !(collection->flag & COLLECTION_IS_MASTER))
+ {
+ if (lc && (lc->runtime_flag & LAYER_COLLECTION_HAS_ENABLED_OBJECTS)) {
+ bt = uiDefIconButBitS(
+ block, UI_BTYPE_ICON_TOGGLE_N, LAYER_COLLECTION_HAS_VISIBLE_OBJECTS, 0, ICON_HIDE_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &lc->runtime_flag, 0, 0, 0, 0,
+ TIP_("Hide collection in viewport (Ctrl to isolate)"));
+ UI_but_func_set(bt, hidebutton_layer_collection_flag_cb, view_layer, lc);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
+ }
+
+ PointerRNA collection_ptr;
+ RNA_id_pointer_create(&collection->id, &collection_ptr);
+
+ bt = uiDefIconButR_prop(
+ block, UI_BTYPE_ICON_TOGGLE, 0, 0,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection_ptr, props.collection_hide_viewport, -1, 0, 0, 0, 0, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ bt = uiDefIconButR_prop(
+ block, UI_BTYPE_ICON_TOGGLE, 0, 0,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection_ptr, props.collection_hide_render, -1, 0, 0, 0, 0, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- UI_block_emboss_set(block, UI_EMBOSS);
+ bt = uiDefIconButR_prop(
+ block, UI_BTYPE_ICON_TOGGLE, 0, 0,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection_ptr, props.collection_hide_select, -1, 0, 0, 0, 0, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ }
}
}
- if (TSELEM_OPEN(tselem, soops)) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree);
+ if (TSELEM_OPEN(tselem, soops)) {
+ outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree);
+ }
}
}
static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops, ListBase *lb)
{
- uiBut *bt;
- TreeElement *te;
- TreeStoreElem *tselem;
- for (te = lb->first; te; te = te->next) {
- tselem = TREESTORE(te);
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
if (tselem->type == 0) {
+ uiBut *bt;
ID *id = tselem->id;
const char *tip = NULL;
int icon = ICON_NONE;
@@ -831,8 +706,6 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops
if (ID_IS_LINKED(id))
but_flag |= UI_BUT_DISABLED;
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
-
if (id->flag & LIB_FAKEUSER) {
icon = ICON_FILE_TICK;
tip = TIP_("Data-block will be retained using a fake user");
@@ -841,34 +714,37 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops
icon = ICON_X;
tip = TIP_("Data-block has no users and will be deleted");
}
- bt = uiDefIconButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, icon,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
- &id->flag, 0, 0, 0, 0, tip);
+ bt = uiDefIconButBitS(
+ block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, icon,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
+ &id->flag, 0, 0, 0, 0, tip);
UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
UI_but_flag_enable(bt, but_flag);
BLI_str_format_int_grouped(buf, id->us);
- bt = uiDefBut(block, UI_BTYPE_BUT, 1, buf,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys,
- UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0,
- TIP_("Number of users of this data-block"));
+ bt = uiDefBut(
+ block, UI_BTYPE_BUT, 1, buf,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys,
+ UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0,
+ TIP_("Number of users of this data-block"));
UI_but_flag_enable(bt, but_flag);
- bt = uiDefButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ",
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
- &id->flag, 0, 0, 0, 0,
- TIP_("Data-block has a 'fake' user which will keep it in the file "
- "even if nothing else uses it"));
+ bt = uiDefButBitS(
+ block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ",
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
+ &id->flag, 0, 0, 0, 0,
+ TIP_("Data-block has a 'fake' user which will keep it in the file "
+ "even if nothing else uses it"));
UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
UI_but_flag_enable(bt, but_flag);
-
- UI_block_emboss_set(block, UI_EMBOSS);
}
}
- if (TSELEM_OPEN(tselem, soops)) outliner_draw_userbuts(block, ar, soops, &te->subtree);
+ if (TSELEM_OPEN(tselem, soops)) {
+ outliner_draw_userbuts(block, ar, soops, &te->subtree);
+ }
}
}
@@ -879,29 +755,32 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex)
float miny = v2d->cur.ymin;
if (miny < v2d->tot.ymin) miny = v2d->tot.ymin;
- UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
+ GPU_line_width(1.0f);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
+
+ immBegin(GPU_PRIM_LINES, 4);
- /* draw column separator lines */
- fdrawline((float)sizex,
- v2d->cur.ymax,
- (float)sizex,
- miny);
+ immVertex2f(pos, sizex, v2d->cur.ymax);
+ immVertex2f(pos, sizex, miny);
- fdrawline((float)sizex + OL_RNA_COL_SIZEX,
- v2d->cur.ymax,
- (float)sizex + OL_RNA_COL_SIZEX,
- miny);
+ immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, v2d->cur.ymax);
+ immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, miny);
+
+ immEnd();
+
+ immUnbindProgram();
}
static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
{
- TreeElement *te;
- TreeStoreElem *tselem;
PointerRNA *ptr;
PropertyRNA *prop;
- for (te = lb->first; te; te = te->next) {
- tselem = TREESTORE(te);
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
if (tselem->type == TSE_RNA_PROPERTY) {
ptr = &te->rnaptr;
@@ -909,17 +788,20 @@ static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops,
if (!TSELEM_OPEN(tselem, soops)) {
if (RNA_property_type(prop) == PROP_POINTER) {
- uiBut *but = uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys,
- OL_RNA_COL_SIZEX, UI_UNIT_Y - 1);
+ uiBut *but = uiDefAutoButR(
+ block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys,
+ OL_RNA_COL_SIZEX, UI_UNIT_Y - 1);
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else if (RNA_property_type(prop) == PROP_ENUM) {
- uiDefAutoButR(block, ptr, prop, -1, NULL, ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
+ uiDefAutoButR(
+ block, ptr, prop, -1, NULL, ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
}
else {
- uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
+ uiDefAutoButR(
+ block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
}
}
}
@@ -927,15 +809,16 @@ static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops,
ptr = &te->rnaptr;
prop = te->directdata;
- uiDefAutoButR(block, ptr, prop, te->index, "", ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
- UI_UNIT_Y - 1);
+ uiDefAutoButR(
+ block, ptr, prop, te->index, "", ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
+ UI_UNIT_Y - 1);
}
}
- if (TSELEM_OPEN(tselem, soops)) outliner_draw_rnabuts(block, ar, soops, sizex, &te->subtree);
+ if (TSELEM_OPEN(tselem, soops)) {
+ outliner_draw_rnabuts(block, ar, soops, sizex, &te->subtree);
+ }
}
-
- UI_block_emboss_set(block, UI_EMBOSS);
}
static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te)
@@ -959,8 +842,9 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Tre
spx = te->xs + 1.8f * UI_UNIT_X;
dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X);
- bt = uiDefBut(block, UI_BTYPE_TEXT, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name,
- 1.0, (float)len, 0, 0, "");
+ bt = uiDefBut(
+ block, UI_BTYPE_TEXT, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name,
+ 1.0, (float)len, 0, 0, "");
UI_but_func_rename_set(bt, namebutton_cb, tselem);
/* returns false if button got removed */
@@ -975,302 +859,392 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Tre
/* ****************************************************** */
/* Normal Drawing... */
-/* make function calls a bit compacter */
-struct DrawIconArg {
- uiBlock *block;
- ID *id;
- float xmax, x, y, xb, yb;
- float alpha;
-};
-
-static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
+TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
{
- /* restrict column clip... it has been coded by simply overdrawing, doesnt work for buttons */
- if (arg->x >= arg->xmax) {
- glEnable(GL_BLEND);
- UI_icon_draw_aspect(arg->x, arg->y, icon, 1.0f / UI_DPI_FAC, arg->alpha);
- glDisable(GL_BLEND);
- }
- else {
- uiBut *but = uiDefIconBut(arg->block, UI_BTYPE_LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
- 0.0, 0.0, 1.0, arg->alpha,
- (arg->id && ID_IS_LINKED(arg->id)) ? arg->id->lib->name : "");
-
- if (arg->id)
- UI_but_drag_set_id(but, arg->id);
- }
-
-}
-
-static void UNUSED_FUNCTION(tselem_draw_gp_icon_uibut)(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
-{
- /* restrict column clip - skip it for now... */
- if (arg->x >= arg->xmax) {
- /* pass */
- }
- else {
- PointerRNA ptr;
- const float eps = 0.001f;
- const bool is_stroke_visible = (gpl->color[3] > eps);
- const bool is_fill_visible = (gpl->fill[3] > eps);
- float w = 0.5f * UI_UNIT_X;
- float h = 0.85f * UI_UNIT_Y;
-
- RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr);
-
- UI_block_align_begin(arg->block);
-
- UI_block_emboss_set(arg->block, is_stroke_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
- uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h,
- &ptr, "color", -1,
- 0, 0, 0, 0, NULL);
-
- UI_block_emboss_set(arg->block, is_fill_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
- uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb + w, arg->yb, w, h,
- &ptr, "fill_color", -1,
- 0, 0, 0, 0, NULL);
-
- UI_block_emboss_set(arg->block, UI_EMBOSS_NONE);
- UI_block_align_end(arg->block);
- }
-}
-
-static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
- float alpha)
-{
- struct DrawIconArg arg;
- float aspect;
-
- /* make function calls a bit compacter */
- arg.block = block;
- arg.id = tselem->id;
- arg.xmax = xmax;
- arg.xb = x; /* for ui buttons */
- arg.yb = y;
- arg.alpha = alpha;
-
- /* placement of icons, copied from interface_widgets.c */
- aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
- x += 2.0f * aspect;
- y += 2.0f * aspect;
- arg.x = x;
- arg.y = y;
+ TreeElementIcon data = {0};
if (tselem->type) {
switch (tselem->type) {
case TSE_ANIM_DATA:
- UI_icon_draw(x, y, ICON_ANIM_DATA); break; // xxx
+ data.icon = ICON_ANIM_DATA; /* XXX */
+ break;
case TSE_NLA:
- UI_icon_draw(x, y, ICON_NLA); break;
+ data.icon = ICON_NLA;
+ break;
case TSE_NLA_TRACK:
- UI_icon_draw(x, y, ICON_NLA); break; // XXX
+ data.icon = ICON_NLA; /* XXX */
+ break;
case TSE_NLA_ACTION:
- UI_icon_draw(x, y, ICON_ACTION); break;
+ data.icon = ICON_ACTION;
+ break;
case TSE_DRIVER_BASE:
- UI_icon_draw(x, y, ICON_DRIVER); break;
+ data.icon = ICON_DRIVER;
+ break;
case TSE_DEFGROUP_BASE:
- UI_icon_draw(x, y, ICON_GROUP_VERTEX); break;
+ data.icon = ICON_GROUP_VERTEX;
+ break;
case TSE_BONE:
case TSE_EBONE:
- UI_icon_draw(x, y, ICON_BONE_DATA); break;
+ data.icon = ICON_BONE_DATA;
+ break;
case TSE_CONSTRAINT_BASE:
- UI_icon_draw(x, y, ICON_CONSTRAINT); break;
+ data.icon = ICON_CONSTRAINT;
+ break;
case TSE_MODIFIER_BASE:
- UI_icon_draw(x, y, ICON_MODIFIER); break;
+ data.icon = ICON_MODIFIER;
+ break;
case TSE_LINKED_OB:
- UI_icon_draw(x, y, ICON_OBJECT_DATA); break;
+ data.icon = ICON_OBJECT_DATA;
+ break;
case TSE_LINKED_PSYS:
- UI_icon_draw(x, y, ICON_PARTICLES); break;
+ data.icon = ICON_PARTICLES;
+ break;
case TSE_MODIFIER:
{
Object *ob = (Object *)tselem->id;
- ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
- switch ((ModifierType)md->type) {
- case eModifierType_Subsurf:
- UI_icon_draw(x, y, ICON_MOD_SUBSURF); break;
- case eModifierType_Armature:
- UI_icon_draw(x, y, ICON_MOD_ARMATURE); break;
- case eModifierType_Lattice:
- UI_icon_draw(x, y, ICON_MOD_LATTICE); break;
- case eModifierType_Curve:
- UI_icon_draw(x, y, ICON_MOD_CURVE); break;
- case eModifierType_Build:
- UI_icon_draw(x, y, ICON_MOD_BUILD); break;
- case eModifierType_Mirror:
- UI_icon_draw(x, y, ICON_MOD_MIRROR); break;
- case eModifierType_Decimate:
- UI_icon_draw(x, y, ICON_MOD_DECIM); break;
- case eModifierType_Wave:
- UI_icon_draw(x, y, ICON_MOD_WAVE); break;
- case eModifierType_Hook:
- UI_icon_draw(x, y, ICON_HOOK); break;
- case eModifierType_Softbody:
- UI_icon_draw(x, y, ICON_MOD_SOFT); break;
- case eModifierType_Boolean:
- UI_icon_draw(x, y, ICON_MOD_BOOLEAN); break;
- case eModifierType_ParticleSystem:
- UI_icon_draw(x, y, ICON_MOD_PARTICLES); break;
- case eModifierType_ParticleInstance:
- UI_icon_draw(x, y, ICON_MOD_PARTICLES); break;
- case eModifierType_EdgeSplit:
- UI_icon_draw(x, y, ICON_MOD_EDGESPLIT); break;
- case eModifierType_Array:
- UI_icon_draw(x, y, ICON_MOD_ARRAY); break;
- case eModifierType_UVProject:
- case eModifierType_UVWarp: /* TODO, get own icon */
- UI_icon_draw(x, y, ICON_MOD_UVPROJECT); break;
- case eModifierType_Displace:
- UI_icon_draw(x, y, ICON_MOD_DISPLACE); break;
- case eModifierType_Shrinkwrap:
- UI_icon_draw(x, y, ICON_MOD_SHRINKWRAP); break;
- case eModifierType_Cast:
- UI_icon_draw(x, y, ICON_MOD_CAST); break;
- case eModifierType_MeshDeform:
- case eModifierType_SurfaceDeform:
- UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break;
- case eModifierType_Bevel:
- UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
- case eModifierType_Smooth:
- case eModifierType_LaplacianSmooth:
- case eModifierType_CorrectiveSmooth:
- UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
- case eModifierType_SimpleDeform:
- UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
- case eModifierType_Mask:
- UI_icon_draw(x, y, ICON_MOD_MASK); break;
- case eModifierType_Cloth:
- UI_icon_draw(x, y, ICON_MOD_CLOTH); break;
- case eModifierType_Explode:
- UI_icon_draw(x, y, ICON_MOD_EXPLODE); break;
- case eModifierType_Collision:
- case eModifierType_Surface:
- UI_icon_draw(x, y, ICON_MOD_PHYSICS); break;
- case eModifierType_Fluidsim:
- UI_icon_draw(x, y, ICON_MOD_FLUIDSIM); break;
- case eModifierType_Multires:
- UI_icon_draw(x, y, ICON_MOD_MULTIRES); break;
- case eModifierType_Smoke:
- UI_icon_draw(x, y, ICON_MOD_SMOKE); break;
- case eModifierType_Solidify:
- UI_icon_draw(x, y, ICON_MOD_SOLIDIFY); break;
- case eModifierType_Screw:
- UI_icon_draw(x, y, ICON_MOD_SCREW); break;
- case eModifierType_Remesh:
- UI_icon_draw(x, y, ICON_MOD_REMESH); break;
- case eModifierType_WeightVGEdit:
- case eModifierType_WeightVGMix:
- case eModifierType_WeightVGProximity:
- UI_icon_draw(x, y, ICON_MOD_VERTEX_WEIGHT); break;
- case eModifierType_DynamicPaint:
- UI_icon_draw(x, y, ICON_MOD_DYNAMICPAINT); break;
- case eModifierType_Ocean:
- UI_icon_draw(x, y, ICON_MOD_OCEAN); break;
- case eModifierType_Warp:
- UI_icon_draw(x, y, ICON_MOD_WARP); break;
- case eModifierType_Skin:
- UI_icon_draw(x, y, ICON_MOD_SKIN); break;
- case eModifierType_Triangulate:
- 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:
- UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
- case eModifierType_DataTransfer:
- UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break;
- case eModifierType_NormalEdit:
- UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break;
- /* Default */
- case eModifierType_None:
- case eModifierType_ShapeKey:
- case NUM_MODIFIER_TYPES:
- UI_icon_draw(x, y, ICON_DOT); break;
+ if (ob->type != OB_GPENCIL) {
+ ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
+ switch ((ModifierType)md->type) {
+ case eModifierType_Subsurf:
+ data.icon = ICON_MOD_SUBSURF;
+ break;
+ case eModifierType_Armature:
+ data.icon = ICON_MOD_ARMATURE;
+ break;
+ case eModifierType_Lattice:
+ data.icon = ICON_MOD_LATTICE;
+ break;
+ case eModifierType_Curve:
+ data.icon = ICON_MOD_CURVE;
+ break;
+ case eModifierType_Build:
+ data.icon = ICON_MOD_BUILD;
+ break;
+ case eModifierType_Mirror:
+ data.icon = ICON_MOD_MIRROR;
+ break;
+ case eModifierType_Decimate:
+ data.icon = ICON_MOD_DECIM;
+ break;
+ case eModifierType_Wave:
+ data.icon = ICON_MOD_WAVE;
+ break;
+ case eModifierType_Hook:
+ data.icon = ICON_HOOK;
+ break;
+ case eModifierType_Softbody:
+ data.icon = ICON_MOD_SOFT;
+ break;
+ case eModifierType_Boolean:
+ data.icon = ICON_MOD_BOOLEAN;
+ break;
+ case eModifierType_ParticleSystem:
+ data.icon = ICON_MOD_PARTICLES;
+ break;
+ case eModifierType_ParticleInstance:
+ data.icon = ICON_MOD_PARTICLES;
+ break;
+ case eModifierType_EdgeSplit:
+ data.icon = ICON_MOD_EDGESPLIT;
+ break;
+ case eModifierType_Array:
+ data.icon = ICON_MOD_ARRAY;
+ break;
+ case eModifierType_UVProject:
+ case eModifierType_UVWarp: /* TODO, get own icon */
+ data.icon = ICON_MOD_UVPROJECT;
+ break;
+ case eModifierType_Displace:
+ data.icon = ICON_MOD_DISPLACE;
+ break;
+ case eModifierType_Shrinkwrap:
+ data.icon = ICON_MOD_SHRINKWRAP;
+ break;
+ case eModifierType_Cast:
+ data.icon = ICON_MOD_CAST;
+ break;
+ case eModifierType_MeshDeform:
+ case eModifierType_SurfaceDeform:
+ data.icon = ICON_MOD_MESHDEFORM;
+ break;
+ case eModifierType_Bevel:
+ data.icon = ICON_MOD_BEVEL;
+ break;
+ case eModifierType_Smooth:
+ case eModifierType_LaplacianSmooth:
+ case eModifierType_CorrectiveSmooth:
+ data.icon = ICON_MOD_SMOOTH;
+ break;
+ case eModifierType_SimpleDeform:
+ data.icon = ICON_MOD_SIMPLEDEFORM;
+ break;
+ case eModifierType_Mask:
+ data.icon = ICON_MOD_MASK;
+ break;
+ case eModifierType_Cloth:
+ data.icon = ICON_MOD_CLOTH;
+ break;
+ case eModifierType_Explode:
+ data.icon = ICON_MOD_EXPLODE;
+ break;
+ case eModifierType_Collision:
+ case eModifierType_Surface:
+ data.icon = ICON_MOD_PHYSICS;
+ break;
+ case eModifierType_Fluidsim:
+ data.icon = ICON_MOD_FLUIDSIM;
+ break;
+ case eModifierType_Multires:
+ data.icon = ICON_MOD_MULTIRES;
+ break;
+ case eModifierType_Smoke:
+ data.icon = ICON_MOD_SMOKE;
+ break;
+ case eModifierType_Solidify:
+ data.icon = ICON_MOD_SOLIDIFY;
+ break;
+ case eModifierType_Screw:
+ data.icon = ICON_MOD_SCREW;
+ break;
+ case eModifierType_Remesh:
+ data.icon = ICON_MOD_REMESH;
+ break;
+ case eModifierType_WeightVGEdit:
+ case eModifierType_WeightVGMix:
+ case eModifierType_WeightVGProximity:
+ data.icon = ICON_MOD_VERTEX_WEIGHT;
+ break;
+ case eModifierType_DynamicPaint:
+ data.icon = ICON_MOD_DYNAMICPAINT;
+ break;
+ case eModifierType_Ocean:
+ data.icon = ICON_MOD_OCEAN;
+ break;
+ case eModifierType_Warp:
+ data.icon = ICON_MOD_WARP;
+ break;
+ case eModifierType_Skin:
+ data.icon = ICON_MOD_SKIN;
+ break;
+ case eModifierType_Triangulate:
+ data.icon = ICON_MOD_TRIANGULATE;
+ break;
+ case eModifierType_MeshCache:
+ data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */
+ break;
+ case eModifierType_MeshSequenceCache:
+ data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */
+ break;
+ case eModifierType_Wireframe:
+ data.icon = ICON_MOD_WIREFRAME;
+ break;
+ case eModifierType_LaplacianDeform:
+ data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */
+ break;
+ case eModifierType_DataTransfer:
+ data.icon = ICON_MOD_DATA_TRANSFER;
+ break;
+ case eModifierType_NormalEdit:
+ case eModifierType_WeightedNormal:
+ data.icon = ICON_MOD_NORMALEDIT;
+ break;
+ /* Default */
+ case eModifierType_None:
+ case eModifierType_ShapeKey:
+
+ case NUM_MODIFIER_TYPES:
+ data.icon = ICON_DOT;
+ break;
+ }
+ }
+ else {
+ /* grease pencil modifiers */
+ GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr);
+ switch ((GpencilModifierType)md->type) {
+ case eGpencilModifierType_Noise:
+ data.icon = ICON_RNDCURVE;
+ break;
+ case eGpencilModifierType_Subdiv:
+ data.icon = ICON_MOD_SUBSURF;
+ break;
+ case eGpencilModifierType_Thick:
+ data.icon = ICON_MOD_THICKNESS;
+ break;
+ case eGpencilModifierType_Tint:
+ data.icon = ICON_MOD_TINT;
+ break;
+ case eGpencilModifierType_Array:
+ data.icon = ICON_MOD_ARRAY;
+ break;
+ case eGpencilModifierType_Build:
+ data.icon = ICON_MOD_BUILD;
+ break;
+ case eGpencilModifierType_Opacity:
+ data.icon = ICON_MOD_MASK;
+ break;
+ case eGpencilModifierType_Color:
+ data.icon = ICON_MOD_HUE_SATURATION;
+ break;
+ case eGpencilModifierType_Lattice:
+ data.icon = ICON_MOD_LATTICE;
+ break;
+ case eGpencilModifierType_Mirror:
+ data.icon = ICON_MOD_MIRROR;
+ break;
+ case eGpencilModifierType_Simplify:
+ data.icon = ICON_MOD_SIMPLIFY;
+ break;
+ case eGpencilModifierType_Smooth:
+ data.icon = ICON_MOD_SMOOTH;
+ break;
+ case eGpencilModifierType_Hook:
+ data.icon = ICON_HOOK;
+ break;
+ case eGpencilModifierType_Offset:
+ data.icon = ICON_MOD_OFFSET;
+ break;
+ case eGpencilModifierType_Armature:
+ data.icon = ICON_MOD_ARMATURE;
+ break;
+
+ /* Default */
+ default:
+ data.icon = ICON_DOT;
+ break;
+ }
}
break;
}
case TSE_POSE_BASE:
- UI_icon_draw(x, y, ICON_ARMATURE_DATA); break;
+ data.icon = ICON_ARMATURE_DATA;
+ break;
case TSE_POSE_CHANNEL:
- UI_icon_draw(x, y, ICON_BONE_DATA); break;
+ data.icon = ICON_BONE_DATA;
+ break;
case TSE_PROXY:
- UI_icon_draw(x, y, ICON_GHOST); break;
+ data.icon = ICON_GHOST_ENABLED;
+ break;
case TSE_R_LAYER_BASE:
- UI_icon_draw(x, y, ICON_RENDERLAYERS); break;
+ data.icon = ICON_RENDERLAYERS;
+ break;
+ case TSE_SCENE_OBJECTS_BASE:
+ data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE;
+ break;
case TSE_R_LAYER:
- UI_icon_draw(x, y, ICON_RENDERLAYERS); break;
+ data.icon = ICON_RENDER_RESULT;
+ break;
case TSE_LINKED_LAMP:
- UI_icon_draw(x, y, ICON_LAMP_DATA); break;
+ data.icon = ICON_LIGHT_DATA;
+ break;
case TSE_LINKED_MAT:
- UI_icon_draw(x, y, ICON_MATERIAL_DATA); break;
+ data.icon = ICON_MATERIAL_DATA;
+ break;
case TSE_POSEGRP_BASE:
- UI_icon_draw(x, y, ICON_GROUP_BONE); break;
+ data.icon = ICON_GROUP_BONE;
+ break;
case TSE_SEQUENCE:
if (te->idcode == SEQ_TYPE_MOVIE)
- UI_icon_draw(x, y, ICON_SEQUENCE);
+ data.icon = ICON_SEQUENCE;
else if (te->idcode == SEQ_TYPE_META)
- UI_icon_draw(x, y, ICON_DOT);
+ data.icon = ICON_DOT;
else if (te->idcode == SEQ_TYPE_SCENE)
- UI_icon_draw(x, y, ICON_SCENE);
+ data.icon = ICON_SCENE;
else if (te->idcode == SEQ_TYPE_SOUND_RAM)
- UI_icon_draw(x, y, ICON_SOUND);
+ data.icon = ICON_SOUND;
else if (te->idcode == SEQ_TYPE_IMAGE)
- UI_icon_draw(x, y, ICON_IMAGE_COL);
+ data.icon = ICON_IMAGE;
else
- UI_icon_draw(x, y, ICON_PARTICLES);
+ data.icon = ICON_PARTICLES;
break;
case TSE_SEQ_STRIP:
- UI_icon_draw(x, y, ICON_LIBRARY_DATA_DIRECT);
+ data.icon = ICON_LIBRARY_DATA_DIRECT;
break;
case TSE_SEQUENCE_DUP:
- UI_icon_draw(x, y, ICON_OBJECT_DATA);
+ data.icon = ICON_OBJECT_DATA;
break;
case TSE_RNA_STRUCT:
if (RNA_struct_is_ID(te->rnaptr.type)) {
- arg.id = (ID *)te->rnaptr.data;
- tselem_draw_icon_uibut(&arg, RNA_struct_ui_icon(te->rnaptr.type));
+ data.drag_id = (ID *)te->rnaptr.data;
+ data.icon = RNA_struct_ui_icon(te->rnaptr.type);
}
- else
- UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
+ else {
+ data.icon = RNA_struct_ui_icon(te->rnaptr.type);
+ }
+ break;
+ case TSE_LAYER_COLLECTION:
+ case TSE_SCENE_COLLECTION_BASE:
+ case TSE_VIEW_COLLECTION_BASE:
+ {
+ Collection *collection = outliner_collection_from_tree_element(te);
+ if (collection && !(collection->flag & COLLECTION_IS_MASTER)) {
+ data.drag_id = tselem->id;
+ data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
+ }
+
+ data.icon = ICON_GROUP;
break;
+ }
/* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */
-#if 0
case TSE_GP_LAYER:
- tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata);
+ {
+ /* indicate whether layer is active */
+ bGPDlayer *gpl = te->directdata;
+ if (gpl->flag & GP_LAYER_ACTIVE) {
+ data.icon = ICON_GREASEPENCIL;
+ }
+ else {
+ data.icon = ICON_DOT;
+ }
break;
-#endif
+ }
default:
- UI_icon_draw(x, y, ICON_DOT); break;
+ data.icon = ICON_DOT;
+ break;
}
}
else if (tselem->id) {
+ data.drag_id = tselem->id;
+ data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
+
if (GS(tselem->id->name) == ID_OB) {
Object *ob = (Object *)tselem->id;
switch (ob->type) {
case OB_LAMP:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break;
+ data.icon = ICON_OUTLINER_OB_LIGHT; break;
case OB_MESH:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break;
+ data.icon = ICON_OUTLINER_OB_MESH; break;
case OB_CAMERA:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break;
+ data.icon = ICON_OUTLINER_OB_CAMERA; break;
case OB_CURVE:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break;
+ data.icon = ICON_OUTLINER_OB_CURVE; break;
case OB_MBALL:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break;
+ data.icon = ICON_OUTLINER_OB_META; break;
case OB_LATTICE:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break;
+ data.icon = ICON_OUTLINER_OB_LATTICE; break;
case OB_ARMATURE:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break;
+ data.icon = ICON_OUTLINER_OB_ARMATURE; break;
case OB_FONT:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break;
+ data.icon = ICON_OUTLINER_OB_FONT; break;
case OB_SURF:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break;
+ data.icon = ICON_OUTLINER_OB_SURFACE; break;
case OB_SPEAKER:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break;
+ data.icon = ICON_OUTLINER_OB_SPEAKER; break;
+ case OB_LIGHTPROBE:
+ data.icon = ICON_OUTLINER_OB_LIGHTPROBE; break;
case OB_EMPTY:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break;
+ if (ob->dup_group) {
+ data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE;
+ }
+ else if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
+ data.icon = ICON_OUTLINER_OB_IMAGE;
+ }
+ else {
+ data.icon = ICON_OUTLINER_OB_EMPTY;
+ }
+ break;
+ case OB_GPENCIL:
+ data.icon = ICON_OUTLINER_OB_GREASEPENCIL; break;
+ break;
}
}
else {
@@ -1279,143 +1253,318 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
*/
switch ((short)GS(tselem->id->name)) {
case ID_SCE:
- tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break;
+ data.icon = ICON_SCENE_DATA; break;
case ID_ME:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break;
+ data.icon = ICON_OUTLINER_DATA_MESH; break;
case ID_CU:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break;
+ data.icon = ICON_OUTLINER_DATA_CURVE; break;
case ID_MB:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break;
+ data.icon = ICON_OUTLINER_DATA_META; break;
case ID_LT:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break;
+ data.icon = ICON_OUTLINER_DATA_LATTICE; break;
case ID_LA:
{
Lamp *la = (Lamp *)tselem->id;
switch (la->type) {
case LA_LOCAL:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break;
+ data.icon = ICON_LIGHT_POINT; break;
case LA_SUN:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break;
+ data.icon = ICON_LIGHT_SUN; break;
case LA_SPOT:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break;
- case LA_HEMI:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break;
+ data.icon = ICON_LIGHT_SPOT; break;
case LA_AREA:
- tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break;
+ data.icon = ICON_LIGHT_AREA; break;
default:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break;
+ data.icon = ICON_OUTLINER_DATA_LIGHT; break;
}
break;
}
case ID_MA:
- tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break;
+ data.icon = ICON_MATERIAL_DATA; break;
case ID_TE:
- tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break;
+ data.icon = ICON_TEXTURE_DATA; break;
case ID_IM:
- tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break;
+ data.icon = ICON_IMAGE_DATA; break;
case ID_SPK:
case ID_SO:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break;
+ data.icon = ICON_OUTLINER_DATA_SPEAKER; break;
case ID_AR:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break;
+ data.icon = ICON_OUTLINER_DATA_ARMATURE; break;
case ID_CA:
- tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break;
+ data.icon = ICON_OUTLINER_DATA_CAMERA; break;
case ID_KE:
- tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break;
+ data.icon = ICON_SHAPEKEY_DATA; break;
case ID_WO:
- tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break;
+ data.icon = ICON_WORLD_DATA; break;
case ID_AC:
- tselem_draw_icon_uibut(&arg, ICON_ACTION); break;
+ data.icon = ICON_ACTION; break;
case ID_NLA:
- tselem_draw_icon_uibut(&arg, ICON_NLA); break;
+ data.icon = ICON_NLA; break;
case ID_TXT:
- tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break;
+ data.icon = ICON_SCRIPT; break;
case ID_GR:
- tselem_draw_icon_uibut(&arg, ICON_GROUP); break;
+ data.icon = ICON_GROUP; break;
case ID_LI:
if (tselem->id->tag & LIB_TAG_MISSING) {
- tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN);
+ data.icon = ICON_LIBRARY_DATA_BROKEN;
}
else if (((Library *)tselem->id)->parent) {
- tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT);
+ data.icon = ICON_LIBRARY_DATA_INDIRECT;
}
else {
- tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT);
+ data.icon = ICON_LIBRARY_DATA_DIRECT;
}
break;
case ID_LS:
- tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
+ data.icon = ICON_LINE_DATA; break;
case ID_GD:
- tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
+ data.icon = ICON_OUTLINER_DATA_GREASEPENCIL; break;
+ case ID_LP:
+ {
+ LightProbe *lp = (LightProbe *)tselem->id;
+ switch (lp->type) {
+ case LIGHTPROBE_TYPE_CUBE:
+ data.icon = ICON_LIGHTPROBE_CUBEMAP; break;
+ case LIGHTPROBE_TYPE_PLANAR:
+ data.icon = ICON_LIGHTPROBE_PLANAR; break;
+ case LIGHTPROBE_TYPE_GRID:
+ data.icon = ICON_LIGHTPROBE_GRID; break;
+ default:
+ data.icon = ICON_LIGHTPROBE_CUBEMAP; break;
+ }
+ break;
+ }
+ case ID_BR:
+ data.icon = ICON_BRUSH_DATA; break;
+ case ID_SCR:
+ case ID_WS:
+ data.icon = ICON_WORKSPACE; break;
default:
break;
}
}
}
+
+ return data;
}
-static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SpaceOops *soops, ListBase *lb, int level,
- int xmax, int *offsx, int ys)
+static void tselem_draw_icon(
+ uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
+ float alpha, const bool is_clickable)
{
- TreeElement *te;
- TreeStoreElem *tselem;
- eOLDrawState active;
+ TreeElementIcon data = tree_element_get_icon(tselem, te);
- for (te = lb->first; te; te = te->next) {
+ if (data.icon == 0) {
+ return;
+ }
+
+ if (!is_clickable || x >= xmax) {
+ /* placement of icons, copied from interface_widgets.c */
+ float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
+ x += 2.0f * aspect;
+ y += 2.0f * aspect;
+
+ /* restrict column clip... it has been coded by simply overdrawing,
+ * doesn't work for buttons */
+ UI_icon_draw_alpha(x, y, data.icon, alpha);
+ }
+ else {
+ uiDefIconBut(
+ block, UI_BTYPE_LABEL, 0, data.icon, x, y, UI_UNIT_X, UI_UNIT_Y, NULL,
+ 0.0, 0.0, 1.0, alpha,
+ (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->name : "");
+ }
+}
+
+/**
+ * For icon-only children of a collapsed tree,
+ * Draw small number over the icon to show how many items of this type are displayed.
+ */
+static void outliner_draw_iconrow_number(
+ const uiFontStyle *fstyle,
+ int offsx, int ys,
+ const int num_elements)
+{
+ float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ float ufac = 0.25f * UI_UNIT_X;
+ float offset_x = (float) offsx + UI_UNIT_X * 0.35f;
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox_aa(true,
+ offset_x + ufac,
+ (float)ys - UI_UNIT_Y * 0.2f + ufac,
+ offset_x + UI_UNIT_X - ufac,
+ (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac,
+ (float)UI_UNIT_Y / 2.0f - ufac,
+ color);
+
+ /* Now the numbers. */
+ unsigned char text_col[4];
+
+ UI_GetThemeColor4ubv(TH_TEXT_HI, text_col);
+ text_col[3] = 255;
+
+ uiFontStyle fstyle_small = *fstyle;
+ fstyle_small.points *= 0.8f;
+
+ /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */
+ int num_digits = 4;
+ char number_text[4] = "+99\0";
+ if (num_elements < 100) {
+ BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements);
+ num_digits = num_elements < 10 ? 1 : 2;
+ }
+ UI_fontstyle_draw_simple(&fstyle_small,
+ (offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f),
+ (float)ys - UI_UNIT_Y * 0.095f + ufac,
+ number_text, text_col);
+ UI_fontstyle_set(fstyle);
+ GPU_blend(true); /* Roundbox and text drawing disables. */
+}
+
+static void outliner_draw_iconrow_doit(
+ uiBlock *block, TreeElement *te,
+ const uiFontStyle *fstyle,
+ int xmax, int *offsx, int ys, float alpha_fac,
+ const eOLDrawState active,
+ const int num_elements)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (active != OL_DRAWSEL_NONE) {
+ float ufac = UI_UNIT_X / 20.0f;
+ float color[4] = {1.0f, 1.0f, 1.0f, 0.2f};
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ color[3] *= alpha_fac;
+
+ UI_draw_roundbox_aa(true,
+ (float) *offsx + 1.0f * ufac,
+ (float)ys + 1.0f * ufac,
+ (float)*offsx + UI_UNIT_X - 1.0f * ufac,
+ (float)ys + UI_UNIT_Y - ufac,
+ (float)UI_UNIT_Y / 2.0f - ufac,
+ color);
+ GPU_blend(true); /* Roundbox disables. */
+ }
+
+ /* No inlined icon should be clickable. */
+ tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.8f * alpha_fac, false);
+ te->xs = *offsx;
+ te->ys = ys;
+ te->xend = (short)*offsx + UI_UNIT_X;
+ if (num_elements > 1) {
+ outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements);
+ }
+ (*offsx) += UI_UNIT_X;
+}
+
+/**
+ * Return the index to use based on the TreeElement ID and object type
+ *
+ * We use a continuum of indices until we get to the object datablocks
+ * and we then make room for the object types.
+ */
+static int tree_element_id_type_to_index(TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ const int id_index = tselem->type == 0 ? BKE_idcode_to_index(te->idcode) : INDEX_ID_GR;
+ if (id_index < INDEX_ID_OB) {
+ return id_index;
+ }
+ else if (id_index == INDEX_ID_OB) {
+ const Object *ob = (Object *)tselem->id;
+ return INDEX_ID_OB + ob->type;
+ }
+ else {
+ return id_index + OB_TYPE_MAX;
+ }
+}
+
+typedef struct MergedIconRow {
+ eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX];
+ int num_elements[INDEX_ID_MAX + OB_TYPE_MAX];
+ TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX];
+} MergedIconRow;
+
+static void outliner_draw_iconrow(
+ bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, SpaceOops *soops,
+ ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac, MergedIconRow *merged)
+{
+ eOLDrawState active;
+ const Object *obact = OBACT(view_layer);
+
+ for (TreeElement *te = lb->first; te; te = te->next) {
/* exit drawing early */
if ((*offsx) - UI_UNIT_X > xmax)
break;
- tselem = TREESTORE(te);
+ TreeStoreElem *tselem = TREESTORE(te);
/* object hierarchy always, further constrained on level */
if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) {
-
/* active blocks get white circle */
if (tselem->type == 0) {
if (te->idcode == ID_OB) {
- active = (OBACT == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
+ active = (OBACT(view_layer) == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
}
- else if (scene->obedit && scene->obedit->data == tselem->id) {
+ else if (is_object_data_in_editmode(tselem->id, obact)) {
active = OL_DRAWSEL_NORMAL;
}
else {
- active = tree_element_active(C, scene, soops, te, OL_SETSEL_NONE, false);
+ active = tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false);
}
}
else {
- active = tree_element_type_active(NULL, scene, soops, te, tselem, OL_SETSEL_NONE, false);
+ active = tree_element_type_active(C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false);
}
- if (active != OL_DRAWSEL_NONE) {
- float ufac = UI_UNIT_X / 20.0f;
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- glColor4ub(255, 255, 255, 100);
- UI_draw_roundbox(
- (float) *offsx + 1.0f * ufac,
- (float)ys + 1.0f * ufac,
- (float)*offsx + UI_UNIT_X - 1.0f * ufac,
- (float)ys + UI_UNIT_Y - ufac,
- (float)UI_UNIT_Y / 2.0f - ufac);
- glEnable(GL_BLEND); /* roundbox disables */
+ if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
+ outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1);
+ }
+ else {
+ const int index = tree_element_id_type_to_index(te);
+ merged->num_elements[index]++;
+ if ((merged->tree_element[index] == NULL) ||
+ (active > merged->active[index]))
+ {
+ merged->tree_element[index] = te;
+ }
+ merged->active[index] = MAX2(active, merged->active[index]);
}
-
- tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f);
- te->xs = *offsx;
- te->ys = ys;
- te->xend = (short)*offsx + UI_UNIT_X;
- te->flag |= TE_ICONROW; // for click
-
- (*offsx) += UI_UNIT_X;
}
/* this tree element always has same amount of branches, so don't draw */
- if (tselem->type != TSE_R_LAYER)
- outliner_draw_iconrow(C, block, scene, soops, &te->subtree, level + 1, xmax, offsx, ys);
+ if (tselem->type != TSE_R_LAYER) {
+ outliner_draw_iconrow(
+ C, block, fstyle, scene, view_layer, soops,
+ &te->subtree, level + 1, xmax, offsx, ys, alpha_fac, merged);
+ }
}
+ if (level == 0) {
+ for (int i = 0; i < INDEX_ID_MAX; i++) {
+ const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1;
+ /* See tree_element_id_type_to_index for the index logic. */
+ int index_base = i;
+ if (i > INDEX_ID_OB) {
+ index_base += OB_TYPE_MAX;
+ }
+ for (int j = 0; j < num_subtypes; j++) {
+ const int index = index_base + j;
+ if (merged->num_elements[index] != 0) {
+ outliner_draw_iconrow_doit(block,
+ merged->tree_element[index],
+ fstyle,
+ xmax, offsx, ys, alpha_fac,
+ merged->active[index],
+ merged->num_elements[index]);
+ }
+ }
+ }
+ }
}
/* closed tree element */
@@ -1423,9 +1572,12 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta
{
TreeElement *ten;
- /* store coord and continue, we need coordinates for elements outside view too */
- te->xs = startx;
- te->ys = starty;
+ /* closed items may be displayed in row of parent, don't change their coordinate! */
+ if ((te->flag & TE_ICONROW) == 0) {
+ /* store coord and continue, we need coordinates for elements outside view too */
+ te->xs = startx;
+ te->ys = starty;
+ }
for (ten = te->subtree.first; ten; ten = ten->next) {
outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty);
@@ -1434,20 +1586,21 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta
static void outliner_draw_tree_element(
- bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, int startx, int *starty, TreeElement **te_edit)
+ bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer,
+ ARegion *ar, SpaceOops *soops, TreeElement *te, bool draw_grayed_out,
+ int startx, int *starty, TreeElement **te_edit)
{
- TreeElement *ten;
TreeStoreElem *tselem;
float ufac = UI_UNIT_X / 20.0f;
int offsx = 0;
eOLDrawState active = OL_DRAWSEL_NONE;
-
+ float color[4];
tselem = TREESTORE(te);
if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) {
+ const float alpha_fac = ((te->flag & TE_DISABLED) || draw_grayed_out) ? 0.5f : 1.0f;
+ const float alpha = 0.5f * alpha_fac;
int xmax = ar->v2d.cur.xmax;
- unsigned char alpha = 128;
if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) {
*te_edit = te;
@@ -1457,153 +1610,147 @@ static void outliner_draw_tree_element(
if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
xmax -= OL_TOGW + UI_UNIT_X;
- glEnable(GL_BLEND);
-
- /* start by highlighting search matches
- * we don't expand items when searching in the datablocks but we
- * still want to highlight any filter matches.
- */
- if ((SEARCHING_OUTLINER(soops) || (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0)) &&
- (tselem->flag & TSE_SEARCHMATCH))
- {
- char col[4];
- UI_GetThemeColorType4ubv(TH_MATCH, SPACE_OUTLINER, col);
- col[3] = alpha;
- glColor4ubv((GLubyte *)col);
- glRecti(startx, *starty + 1, ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
- }
+ GPU_blend(true);
/* colors for active/selected data */
if (tselem->type == 0) {
-
+ const Object *obact = OBACT(view_layer);
if (te->idcode == ID_SCE) {
if (tselem->id == (ID *)scene) {
- glColor4ub(255, 255, 255, alpha);
- active = OL_DRAWSEL_ACTIVE;
- }
- }
- else if (te->idcode == ID_GR) {
- Group *gr = (Group *)tselem->id;
- if (group_select_flag(gr)) {
- char col[4];
- UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col);
- col[3] = alpha;
- glColor4ubv((GLubyte *)col);
-
+ rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha);
active = OL_DRAWSEL_ACTIVE;
}
}
else if (te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
+ Base *base = (Base *)te->directdata;
+ const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
- if (ob == OBACT || (ob->flag & SELECT)) {
+ if (ob == obact || is_selected) {
char col[4] = {0, 0, 0, 0};
/* outliner active ob: always white text, circle color now similar to view3d */
active = OL_DRAWSEL_ACTIVE;
- if (ob == OBACT) {
- if (ob->flag & SELECT) {
+ if (ob == obact) {
+ if (is_selected) {
UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col);
col[3] = alpha;
}
active = OL_DRAWSEL_NORMAL;
}
- else if (ob->flag & SELECT) {
+ else if (is_selected) {
UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col);
col[3] = alpha;
}
-
- glColor4ubv((GLubyte *)col);
+ rgba_float_args_set(color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha);
}
-
}
- else if (scene->obedit && scene->obedit->data == tselem->id) {
- glColor4ub(255, 255, 255, alpha);
+ else if (is_object_data_in_editmode(tselem->id, obact)) {
+ rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha);
active = OL_DRAWSEL_ACTIVE;
}
else {
- if (tree_element_active(C, scene, soops, te, OL_SETSEL_NONE, false)) {
- glColor4ub(220, 220, 255, alpha);
+ if (tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false)) {
+ rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha);
active = OL_DRAWSEL_ACTIVE;
}
}
}
else {
- if (tree_element_type_active(NULL, scene, soops, te, tselem, OL_SETSEL_NONE, false) != OL_DRAWSEL_NONE) {
- active = OL_DRAWSEL_ACTIVE;
- }
- glColor4ub(220, 220, 255, alpha);
+ active = tree_element_type_active(C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false);
+ rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha);
}
/* active circle */
if (active != OL_DRAWSEL_NONE) {
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox(
+ UI_draw_roundbox_aa(
+ true,
(float)startx + UI_UNIT_X + 1.0f * ufac,
(float)*starty + 1.0f * ufac,
(float)startx + 2.0f * UI_UNIT_X - 1.0f * ufac,
(float)*starty + UI_UNIT_Y - 1.0f * ufac,
- UI_UNIT_Y / 2.0f - 1.0f * ufac);
- glEnable(GL_BLEND); /* roundbox disables it */
+ UI_UNIT_Y / 2.0f - 1.0f * ufac, color);
+ GPU_blend(true); /* roundbox disables it */
te->flag |= TE_ACTIVE; // for lookup in display hierarchies
}
- /* open/close icon, only when sublevels, except for scene */
- if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) {
- int icon_x;
- icon_x = startx;
+ if (tselem->type == TSE_VIEW_COLLECTION_BASE) {
+ /* Scene collection in view layer can't expand/collapse. */
+ }
+ else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) {
+ /* open/close icon, only when sublevels, except for scene */
+ int icon_x = startx;
// icons a bit higher
- if (TSELEM_OPEN(tselem, soops))
- UI_icon_draw((float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_DOWN);
- else
- UI_icon_draw((float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_RIGHT);
+ if (TSELEM_OPEN(tselem, soops)) {
+ UI_icon_draw_alpha(
+ (float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_DOWN,
+ alpha_fac);
+ }
+ else {
+ UI_icon_draw_alpha(
+ (float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_RIGHT,
+ alpha_fac);
+ }
}
offsx += UI_UNIT_X;
/* datatype icon */
- if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM))) {
-
- tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, 1.0f);
-
- offsx += UI_UNIT_X + 2 * ufac;
+ if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) {
+ tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac, true);
+ offsx += UI_UNIT_X + 4 * ufac;
}
else
offsx += 2 * ufac;
- if (tselem->type == 0 && ID_IS_LINKED(tselem->id)) {
- glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
+ if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_LINKED(tselem->id)) {
if (tselem->id->tag & LIB_TAG_MISSING) {
- UI_icon_draw((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
+ UI_icon_draw_alpha(
+ (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN,
+ alpha_fac);
}
else if (tselem->id->tag & LIB_TAG_INDIRECT) {
- UI_icon_draw((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT);
+ UI_icon_draw_alpha(
+ (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT,
+ alpha_fac);
}
else {
- UI_icon_draw((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
+ UI_icon_draw_alpha(
+ (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT,
+ alpha_fac);
}
- glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
- offsx += UI_UNIT_X + 2 * ufac;
+ offsx += UI_UNIT_X + 4 * ufac;
+ }
+ else if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_STATIC_OVERRIDE(tselem->id)) {
+ UI_icon_draw_alpha(
+ (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_OVERRIDE,
+ alpha_fac);
+ offsx += UI_UNIT_X + 4 * ufac;
}
- glDisable(GL_BLEND);
+ GPU_blend(false);
/* name */
if ((tselem->flag & TSE_TEXTBUT) == 0) {
+ unsigned char text_col[4];
+
if (active == OL_DRAWSEL_NORMAL) {
- UI_ThemeColor(TH_TEXT_HI);
+ UI_GetThemeColor4ubv(TH_TEXT_HI, text_col);
}
else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
- UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
+ UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_col);
+ text_col[3] = 255;
}
else {
- UI_ThemeColor(TH_TEXT);
+ UI_GetThemeColor4ubv(TH_TEXT, text_col);
}
+ text_col[3] *= alpha_fac;
- UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
+ UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_col);
}
offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
@@ -1614,25 +1761,36 @@ static void outliner_draw_tree_element(
if (tselem->type == 0 && te->idcode == ID_SCE) {
/* pass */
}
+ /* this tree element always has same amount of branches, so don't draw */
else if (tselem->type != TSE_R_LAYER) {
- /* this tree element always has same amount of branches, so don't draw */
-
int tempx = startx + offsx;
- /* divider */
- UI_ThemeColorShade(TH_BACK, -40);
- glRecti(tempx - 10.0f * ufac,
- *starty + 4.0f * ufac,
- tempx - 8.0f * ufac,
- *starty + UI_UNIT_Y - 4.0f * ufac);
+ GPU_blend(true);
- glEnable(GL_BLEND);
- glPixelTransferf(GL_ALPHA_SCALE, 0.5);
+ /* divider */
+ {
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ unsigned char col[4];
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ UI_GetThemeColorShade4ubv(TH_BACK, -40, col);
+ col[3] *= alpha_fac;
+
+ immUniformColor4ubv(col);
+ immRecti(pos, tempx - 10.0f * ufac,
+ *starty + 4.0f * ufac,
+ tempx - 8.0f * ufac,
+ *starty + UI_UNIT_Y - 4.0f * ufac);
+ immUnbindProgram();
+ }
- outliner_draw_iconrow(C, block, scene, soops, &te->subtree, 0, xmax, &tempx, *starty);
+ MergedIconRow merged = {{0}};
+ outliner_draw_iconrow(
+ C, block, fstyle, scene, view_layer, soops, &te->subtree, 0, xmax, &tempx,
+ *starty, alpha_fac, &merged);
- glPixelTransferf(GL_ALPHA_SCALE, 1.0);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
}
}
@@ -1645,12 +1803,18 @@ static void outliner_draw_tree_element(
if (TSELEM_OPEN(tselem, soops)) {
*starty -= UI_UNIT_Y;
- for (ten = te->subtree.first; ten; ten = ten->next) {
- outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit);
+ for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ /* check if element needs to be drawn grayed out, but also gray out
+ * childs of a grayed out parent (pass on draw_grayed_out to childs) */
+ bool draw_childs_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING);
+ outliner_draw_tree_element(
+ C, block, fstyle, scene, view_layer,
+ ar, soops, ten, draw_childs_grayed_out,
+ startx + UI_UNIT_X, starty, te_edit);
}
}
else {
- for (ten = te->subtree.first; ten; ten = ten->next) {
+ for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
outliner_set_coord_tree_element(ten, startx, *starty);
}
@@ -1658,115 +1822,258 @@ static void outliner_draw_tree_element(
}
}
-static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx, int *starty)
+static void outliner_draw_hierarchy_lines_recursive(
+ unsigned pos, SpaceOops *soops, ListBase *lb, int startx,
+ const unsigned char col[4], bool draw_grayed_out,
+ int *starty)
{
- TreeElement *te;
- TreeStoreElem *tselem;
+ TreeElement *te, *te_vertical_line_last = NULL;
int y1, y2;
- if (BLI_listbase_is_empty(lb)) return;
+ if (BLI_listbase_is_empty(lb)) {
+ return;
+ }
+
+ const unsigned char grayed_alpha = col[3] / 2;
- y1 = y2 = *starty; /* for vertical lines between objects */
+ /* For vertical lines between objects. */
+ y1 = y2 = *starty;
for (te = lb->first; te; te = te->next) {
- y2 = *starty;
- tselem = TREESTORE(te);
+ bool draw_childs_grayed_out = draw_grayed_out || (te->flag & TE_DRAGGING);
+ TreeStoreElem *tselem = TREESTORE(te);
- /* horizontal line? */
- if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE))
- glRecti(startx, *starty, startx + UI_UNIT_X, *starty - 1);
+ if (draw_childs_grayed_out) {
+ immUniformColor3ubvAlpha(col, grayed_alpha);
+ }
+ else {
+ immUniformColor4ubv(col);
+ }
+
+ /* Horizontal Line? */
+ if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) {
+ immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1);
+
+ /* Vertical Line? */
+ if (te->idcode == ID_OB) {
+ te_vertical_line_last = te;
+ y2 = *starty;
+ }
+ }
*starty -= UI_UNIT_Y;
if (TSELEM_OPEN(tselem, soops))
- outliner_draw_hierarchy(soops, &te->subtree, startx + UI_UNIT_X, starty);
+ outliner_draw_hierarchy_lines_recursive(
+ pos, soops, &te->subtree, startx + UI_UNIT_X,
+ col, draw_childs_grayed_out, starty);
}
- /* vertical line */
- te = lb->last;
- if (te->parent || lb->first != lb->last) {
- tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == ID_OB) {
+ if (draw_grayed_out) {
+ immUniformColor3ubvAlpha(col, grayed_alpha);
+ }
+ else {
+ immUniformColor4ubv(col);
+ }
- glRecti(startx, y1 + UI_UNIT_Y, startx + 1, y2);
- }
+ /* Vertical line. */
+ te = te_vertical_line_last;
+ if ((te != NULL) && (te->parent || lb->first != lb->last)) {
+ immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2);
}
}
-static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
+static void outliner_draw_hierarchy_lines(SpaceOops *soops, ListBase *lb, int startx, int *starty)
{
- TreeElement *te;
- TreeStoreElem *tselem;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ unsigned char col[4];
- for (te = lb->first; te; te = te->next) {
- tselem = TREESTORE(te);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col);
+ col[3] = 255;
+
+ GPU_blend(true);
+ outliner_draw_hierarchy_lines_recursive(pos, soops, lb, startx, col, false, starty);
+ GPU_blend(false);
+
+ immUnbindProgram();
+}
+
+static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
+{
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
/* selection status */
- if (TSELEM_OPEN(tselem, soops))
- if (tselem->type == TSE_RNA_STRUCT)
- glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
+ if (TSELEM_OPEN(tselem, soops)) {
+ if (tselem->type == TSE_RNA_STRUCT) {
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immThemeColorShadeAlpha(TH_BACK, -15, -200);
+ immRecti(pos, 0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
+ immUnbindProgram();
+ }
+ }
*starty -= UI_UNIT_Y;
if (TSELEM_OPEN(tselem, soops)) {
outliner_draw_struct_marks(ar, soops, &te->subtree, starty);
- if (tselem->type == TSE_RNA_STRUCT)
- fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y);
+ if (tselem->type == TSE_RNA_STRUCT) {
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immThemeColorShadeAlpha(TH_BACK, -15, -200);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, 0, (float)*starty + UI_UNIT_Y);
+ immVertex2f(pos, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y);
+ immEnd();
+
+ immUnbindProgram();
+ }
}
}
}
-static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
+static void outliner_draw_highlights_recursive(
+ unsigned pos, const ARegion *ar, const SpaceOops *soops, const ListBase *lb,
+ const float col_selection[4], const float col_highlight[4], const float col_searchmatch[4],
+ int start_x, int *io_start_y)
{
- TreeElement *te;
- TreeStoreElem *tselem;
+ const bool is_searching = (
+ SEARCHING_OUTLINER(soops) ||
+ (soops->outlinevis == SO_DATA_API &&
+ soops->search_string[0] != 0));
- for (te = lb->first; te; te = te->next) {
- tselem = TREESTORE(te);
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ const TreeStoreElem *tselem = TREESTORE(te);
+ const int start_y = *io_start_y;
/* selection status */
if (tselem->flag & TSE_SELECTED) {
- glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
+ immUniformColor4fv(col_selection);
+ immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1);
+ }
+
+ /* highlights */
+ if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) {
+ const int end_x = (int)ar->v2d.cur.xmax;
+
+ if (tselem->flag & TSE_DRAG_ANY) {
+ /* drag and drop highlight */
+ float col[4];
+ UI_GetThemeColorShade4fv(TH_BACK, -40, col);
+
+ if (tselem->flag & TSE_DRAG_BEFORE) {
+ immUniformColor4fv(col);
+ immRecti(pos, start_x, start_y + UI_UNIT_Y - 1, end_x, start_y + UI_UNIT_Y + 1);
+ }
+ else if (tselem->flag & TSE_DRAG_AFTER) {
+ immUniformColor4fv(col);
+ immRecti(pos, start_x, start_y - 1, end_x, start_y + 1);
+ }
+ else {
+ immUniformColor3fvAlpha(col, col[3] * 0.5f);
+ immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1);
+ }
+ }
+ else {
+ if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) {
+ /* search match highlights
+ * we don't expand items when searching in the datablocks but we
+ * still want to highlight any filter matches. */
+ immUniformColor4fv(col_searchmatch);
+ immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1);
+ }
+ else if (tselem->flag & TSE_HIGHLIGHTED) {
+ /* mouse hover highlight */
+ immUniformColor4fv(col_highlight);
+ immRecti(pos, 0, start_y + 1, end_x, start_y + UI_UNIT_Y - 1);
+ }
+ }
+ }
+
+ *io_start_y -= UI_UNIT_Y;
+ if (TSELEM_OPEN(tselem, soops)) {
+ outliner_draw_highlights_recursive(
+ pos, ar, soops, &te->subtree, col_selection, col_highlight, col_searchmatch,
+ start_x + UI_UNIT_X, io_start_y);
}
- *starty -= UI_UNIT_Y;
- if (TSELEM_OPEN(tselem, soops)) outliner_draw_selection(ar, soops, &te->subtree, starty);
}
}
+static void outliner_draw_highlights(ARegion *ar, SpaceOops *soops, int startx, int *starty)
+{
+ const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
+ float col_selection[4], col_searchmatch[4];
+
+ UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection);
+ col_selection[3] = 1.0f; /* no alpha */
+ UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
+ col_searchmatch[3] = 0.5f;
+
+ GPU_blend(true);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ outliner_draw_highlights_recursive(
+ pos, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch,
+ startx, starty);
+ immUnbindProgram();
+ GPU_blend(false);
+}
-static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar,
- SpaceOops *soops, TreeElement **te_edit)
+static void outliner_draw_tree(
+ bContext *C, uiBlock *block, Scene *scene, ViewLayer *view_layer,
+ ARegion *ar, SpaceOops *soops, const bool has_restrict_icons,
+ TreeElement **te_edit)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- TreeElement *te;
int starty, startx;
- float col[3];
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // only once
- if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
+ if (soops->outlinevis == SO_DATA_API) {
/* struct marks */
- UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
- //UI_ThemeColorShade(TH_BACK, -20);
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
outliner_draw_struct_marks(ar, soops, &soops->tree, &starty);
}
- /* always draw selection fill before hierarchy */
- UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col);
- glColor3fv(col);
+ /* draw highlights before hierarchy */
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
- outliner_draw_selection(ar, soops, &soops->tree, &starty);
+ startx = 0;
+ outliner_draw_highlights(ar, soops, startx, &starty);
+
+ /* set scissor so tree elements or lines can't overlap restriction icons */
+ float scissor[4] = {0};
+ if (has_restrict_icons) {
+ int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)OL_TOGW + 1;
+ CLAMP_MIN(mask_x, 0);
+
+ GPU_scissor_get_f(scissor);
+ GPU_scissor(0, 0, mask_x, ar->winy);
+ }
// gray hierarchy lines
- UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.4f);
+
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET;
startx = UI_UNIT_X / 2 - 1.0f;
- outliner_draw_hierarchy(soops, &soops->tree, startx, &starty);
+ outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty);
// items themselves
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
startx = 0;
- for (te = soops->tree.first; te; te = te->next) {
- outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, te, startx, &starty, te_edit);
+ for (TreeElement *te = soops->tree.first; te; te = te->next) {
+ outliner_draw_tree_element(
+ C, block, fstyle, scene, view_layer,
+ ar, soops, te, (te->flag & TE_DRAGGING) != 0,
+ startx, &starty, te_edit);
+ }
+
+ if (has_restrict_icons) {
+ /* reset scissor */
+ GPU_scissor(UNPACK4(scissor));
}
}
@@ -1775,53 +2082,60 @@ static void outliner_back(ARegion *ar)
{
int ystart;
- UI_ThemeColorShade(TH_BACK, 6);
ystart = (int)ar->v2d.tot.ymax;
ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
- while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) {
- glRecti(0, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y);
- ystart -= 2 * UI_UNIT_Y;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShade(TH_BACK, 6);
+
+ const float x1 = 0.0f, x2 = ar->v2d.cur.xmax;
+ float y1 = ystart, y2;
+ int tot = (int)floor(ystart - ar->v2d.cur.ymin + 2 * UI_UNIT_Y) / (2 * UI_UNIT_Y);
+
+ if (tot > 0) {
+ immBegin(GPU_PRIM_TRIS, 6 * tot);
+ while (tot--) {
+ y1 -= 2 * UI_UNIT_Y;
+ y2 = y1 + UI_UNIT_Y;
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y1);
+ immVertex2f(pos, x2, y2);
+
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x1, y2);
+ }
+ immEnd();
}
+ immUnbindProgram();
}
static void outliner_draw_restrictcols(ARegion *ar)
{
- int ystart;
+ GPU_line_width(1.0f);
- /* background underneath */
- UI_ThemeColor(TH_BACK);
- glRecti((int)(ar->v2d.cur.xmax - OL_TOGW),
- (int)(ar->v2d.cur.ymin - 1), (int)ar->v2d.cur.xmax, (int)ar->v2d.cur.ymax);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
+ immBegin(GPU_PRIM_LINES, 8);
- UI_ThemeColorShade(TH_BACK, 6);
- ystart = (int)ar->v2d.tot.ymax;
- ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
+ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), (int)ar->v2d.cur.ymax);
+ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), (int)ar->v2d.cur.ymin);
- while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) {
- glRecti((int)ar->v2d.cur.xmax - OL_TOGW, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y);
- ystart -= 2 * UI_UNIT_Y;
- }
+ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymax);
+ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymin);
+
+ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymax);
+ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymin);
- UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
-
- /* view */
- sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX),
- (int)ar->v2d.cur.ymax,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX),
- (int)ar->v2d.cur.ymin);
-
- /* render */
- sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX),
- (int)ar->v2d.cur.ymax,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX),
- (int)ar->v2d.cur.ymin);
-
- /* render */
- sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX),
- (int)ar->v2d.cur.ymax,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX),
- (int)ar->v2d.cur.ymin);
+ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymax);
+ immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymin);
+
+ immEnd();
+ immUnbindProgram();
}
/* ****************************************************** */
@@ -1831,19 +2145,21 @@ void draw_outliner(const bContext *C)
{
Main *mainvar = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
SpaceOops *soops = CTX_wm_space_outliner(C);
uiBlock *block;
int sizey = 0, sizex = 0, sizex_rna = 0;
TreeElement *te_edit = NULL;
+ bool has_restrict_icons;
- outliner_build_tree(mainvar, scene, soops); // always
+ outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always
/* get extents of data */
outliner_height(soops, &soops->tree, &sizey);
- if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
+ if (soops->outlinevis == SO_DATA_API) {
/* RNA has two columns:
* - column 1 is (max_width + OL_RNA_COL_SPACEX) or
* (OL_RNA_COL_X), whichever is wider...
@@ -1858,6 +2174,7 @@ void draw_outliner(const bContext *C)
/* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */
sizex = sizex_rna + OL_RNA_COL_SIZEX + 50;
+ has_restrict_icons = false;
}
else {
/* width must take into account restriction columns (if visible) so that entries will still be visible */
@@ -1867,9 +2184,11 @@ void draw_outliner(const bContext *C)
/* constant offset for restriction columns */
// XXX this isn't that great yet...
- if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
+ if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) {
sizex += OL_TOGW * 3;
+ }
+ has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS);
}
/* adds vertical offset */
@@ -1886,24 +2205,35 @@ void draw_outliner(const bContext *C)
/* draw outliner stuff (background, hierarchy lines and names) */
outliner_back(ar);
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
- outliner_draw_tree((bContext *)C, block, scene, ar, soops, &te_edit);
+ outliner_draw_tree(
+ (bContext *)C, block, scene, view_layer,
+ ar, soops, has_restrict_icons, &te_edit);
- if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
+ /* Default to no emboss for outliner UI. */
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ if (soops->outlinevis == SO_DATA_API) {
/* draw rna buttons */
outliner_draw_rnacols(ar, sizex_rna);
+
+ UI_block_emboss_set(block, UI_EMBOSS);
outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
- else if ((soops->outlinevis == SO_ID_ORPHANS) && !(soops->flag & SO_HIDE_RESTRICTCOLS)) {
+ else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) {
/* draw user toggle columns */
outliner_draw_restrictcols(ar);
outliner_draw_userbuts(block, ar, soops, &soops->tree);
}
- else if (!(soops->flag & SO_HIDE_RESTRICTCOLS)) {
+ else if (has_restrict_icons) {
/* draw restriction columns */
outliner_draw_restrictcols(ar);
- outliner_draw_restrictbuts(block, scene, ar, soops, &soops->tree);
+
+ outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree);
}
+ UI_block_emboss_set(block, UI_EMBOSS);
+
/* draw edit buttons if nessecery */
if (te_edit) {
outliner_buttons(C, block, ar, te_edit);
@@ -1911,7 +2241,4 @@ void draw_outliner(const bContext *C)
UI_block_end(C, block);
UI_block_draw(C, block);
-
- /* clear flag that allows quick redraws */
- soops->storeflag &= ~SO_TREESTORE_REDRAW;
}
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 51117eef1dc..9d94947f61e 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -34,7 +34,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_ID.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -50,24 +50,28 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_idcode.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_material.h"
-#include "BKE_group.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "../blenloader/BLO_readfile.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_keyframing.h"
#include "ED_armature.h"
@@ -87,68 +91,49 @@
#include "outliner_intern.h"
/* ************************************************************** */
-/* Unused Utilities */
-// XXX: where to place these?
-/* This is not used anywhere at the moment */
-#if 0
-static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
+/* Highlight --------------------------------------------------- */
+
+static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- TreeElement *te;
- TreeStoreElem *tselem;
+ /* Drag and drop does own highlighting. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->drags.first) {
+ return OPERATOR_PASS_THROUGH;
+ }
- for (te = lb->first; te; te = te->next) {
- /* check if this tree-element was the one we're seeking */
- if (te == teFind) {
- *found = 1;
- return;
- }
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
+
+ TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my);
+ bool changed = false;
- /* try to see if sub-tree contains it then */
- outliner_open_reveal(soops, &te->subtree, teFind, found);
- if (*found) {
- tselem = TREESTORE(te);
- if (tselem->flag & TSE_CLOSED)
- tselem->flag &= ~TSE_CLOSED;
- return;
+ if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) {
+ changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false);
+ if (hovered_te) {
+ hovered_te->store_elem->flag |= TSE_HIGHLIGHTED;
+ changed = true;
}
}
-}
-#endif
-static TreeElement *outliner_dropzone_element(TreeElement *te, const float fmval[2], const bool children)
-{
- if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
- /* name and first icon */
- if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend))
- return te;
+ if (changed) {
+ ED_region_tag_redraw_no_rebuild(ar);
}
- /* Not it. Let's look at its children. */
- if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) {
- for (te = te->subtree.first; te; te = te->next) {
- TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
- if (te_valid)
- return te_valid;
- }
- }
- return NULL;
+
+ return OPERATOR_PASS_THROUGH;
}
-/* Used for drag and drop parenting */
-TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const bool children)
+void OUTLINER_OT_highlight_update(wmOperatorType *ot)
{
- TreeElement *te;
+ ot->name = "Update Highlight";
+ ot->idname = "OUTLINER_OT_highlight_update";
+ ot->description = "Update the item highlight based on the current mouse position";
- for (te = soops->tree.first; te; te = te->next) {
- TreeElement *te_valid = outliner_dropzone_element(te, fmval, children);
- if (te_valid)
- return te_valid;
- }
- return NULL;
-}
+ ot->invoke = outliner_highlight_update;
-/* ************************************************************** */
-/* Click Activated */
+ ot->poll = ED_operator_outliner_active;
+}
/* Toggle Open/Closed ------------------------------------------- */
@@ -202,7 +187,7 @@ static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *e
void OUTLINER_OT_item_openclose(wmOperatorType *ot)
{
- ot->name = "Open/Close Item";
+ ot->name = "Open/Close";
ot->idname = "OUTLINER_OT_item_openclose";
ot->description = "Toggle whether item under cursor is enabled or closed";
@@ -213,22 +198,85 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items");
}
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Enter/Exit
+ * \{ */
+
+static void item_object_mode_enter_exit(
+ bContext *C, ReportList *reports, Object *ob,
+ bool enter)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(view_layer);
+
+ if ((ob->type != obact->type) || ID_IS_LINKED(ob->data)) {
+ return;
+ }
+ if (((ob->mode & obact->mode) != 0) == enter) {
+ return;
+ }
+
+ if (ob == obact) {
+ BKE_report(reports, RPT_WARNING, "Active object mode not changed");
+ return;
+ }
+
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base == NULL) {
+ return;
+ }
+ Scene *scene = CTX_data_scene(C);
+ outliner_object_mode_toggle(C, scene, view_layer, base);
+}
+
+void item_object_mode_enter_cb(
+ bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ Object *ob = (Object *)tselem->id;
+ item_object_mode_enter_exit(C, reports, ob, true);
+}
+
+void item_object_mode_exit_cb(
+ bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ Object *ob = (Object *)tselem->id;
+ item_object_mode_enter_exit(C, reports, ob, false);
+}
+
+/** \} */
+
/* Rename --------------------------------------------------- */
-static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
+static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
+ ReportList *reports)
{
+ bool add_textbut = false;
+
/* can't rename rna datablocks entries or listbases */
- if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) {
+ if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE, TSE_SCENE_OBJECTS_BASE)) {
/* do nothing */;
}
else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE,
- TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS))
+ TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_SCENE_COLLECTION_BASE,
+ TSE_VIEW_COLLECTION_BASE))
{
BKE_report(reports, RPT_WARNING, "Cannot edit builtin name");
}
else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
+ else if (outliner_is_collection_tree_element(te)) {
+ Collection *collection = outliner_collection_from_tree_element(te);
+
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit name of master collection");
+ }
+ else {
+ add_textbut = true;
+ }
+ }
else if (ID_IS_LINKED(tselem->id)) {
BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
}
@@ -236,6 +284,10 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library");
}
else {
+ add_textbut = true;
+ }
+
+ if (add_textbut) {
tselem->flag |= TSE_TEXTBUT;
ED_region_tag_redraw(ar);
}
@@ -249,7 +301,8 @@ void item_rename_cb(
do_item_rename(ar, te, tselem, reports);
}
-static int do_outliner_item_rename(ReportList *reports, ARegion *ar, TreeElement *te, const float mval[2])
+static int do_outliner_item_rename(ReportList *reports, ARegion *ar, TreeElement *te,
+ const float mval[2])
{
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
@@ -291,7 +344,7 @@ static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *even
void OUTLINER_OT_item_rename(wmOperatorType *ot)
{
- ot->name = "Rename Item";
+ ot->name = "Rename";
ot->idname = "OUTLINER_OT_item_rename";
ot->description = "Rename item under cursor";
@@ -402,7 +455,6 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot)
static int outliner_id_remap_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
@@ -432,7 +484,7 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
BKE_main_lib_objects_recalc_all(bmain);
/* recreate dependency graph to include new objects */
- DAG_scene_relations_rebuild(bmain, scene);
+ DEG_relations_tag_update(bmain);
/* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
GPU_materials_free(bmain);
@@ -742,17 +794,49 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
return 0;
}
-void outliner_flag_set(ListBase *lb, short flag, short set)
+/**
+ * Set or unset \a flag for all outliner elements in \a lb and sub-trees.
+ * \return if any flag was modified.
+ */
+bool outliner_flag_set(ListBase *lb, short flag, short set)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ bool changed = false;
+ bool has_flag;
+
+ for (te = lb->first; te; te = te->next) {
+ tselem = TREESTORE(te);
+ has_flag = (tselem->flag & flag);
+ if (set == 0) {
+ if (has_flag) {
+ tselem->flag &= ~flag;
+ changed = true;
+ }
+ }
+ else if (!has_flag) {
+ tselem->flag |= flag;
+ changed = true;
+ }
+ changed |= outliner_flag_set(&te->subtree, flag, set);
+ }
+
+ return changed;
+}
+
+bool outliner_flag_flip(ListBase *lb, short flag)
{
TreeElement *te;
TreeStoreElem *tselem;
+ bool changed = false;
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
- if (set == 0) tselem->flag &= ~flag;
- else tselem->flag |= flag;
- outliner_flag_set(&te->subtree, flag, set);
+ tselem->flag ^= flag;
+ changed |= outliner_flag_flip(&te->subtree, flag);
}
+
+ return changed;
}
/* Restriction Columns ------------------------------- */
@@ -780,181 +864,6 @@ int common_restrict_check(bContext *C, Object *ob)
}
/* =============================================== */
-/* Restriction toggles */
-
-/* Toggle Visibility ---------------------------------------- */
-
-void object_toggle_visibility_cb(
- bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Base *base = (Base *)te->directdata;
- Object *ob = (Object *)tselem->id;
-
- if (ID_IS_LINKED(tselem->id)) {
- BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
- return;
- }
-
- /* add check for edit mode */
- if (!common_restrict_check(C, ob)) return;
-
- if (base || (base = BKE_scene_base_find(scene, ob))) {
- if ((base->object->restrictflag ^= OB_RESTRICT_VIEW)) {
- ED_base_object_select(base, BA_DESELECT);
- }
- }
-}
-
-void group_toggle_visibility_cb(
- bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Group *group = (Group *)tselem->id;
- restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW);
-}
-
-static int outliner_toggle_visibility_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
-
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
-
- DAG_id_type_tag(bmain, ID_OB);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
- ED_region_tag_redraw(ar);
-
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_visibility_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Visibility";
- ot->idname = "OUTLINER_OT_visibility_toggle";
- ot->description = "Toggle the visibility of selected items";
-
- /* callbacks */
- ot->exec = outliner_toggle_visibility_exec;
- ot->poll = ED_operator_outliner_active_no_editobject;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* Toggle Selectability ---------------------------------------- */
-
-void object_toggle_selectability_cb(
- bContext *UNUSED(C), ReportList *reports, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Base *base = (Base *)te->directdata;
-
- if (ID_IS_LINKED(tselem->id)) {
- BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
- return;
- }
-
- if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
- if (base) {
- base->object->restrictflag ^= OB_RESTRICT_SELECT;
- }
-}
-
-void group_toggle_selectability_cb(
- bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Group *group = (Group *)tselem->id;
- restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT);
-}
-
-static int outliner_toggle_selectability_exec(bContext *C, wmOperator *op)
-{
- SpaceOops *soops = CTX_wm_space_outliner(C);
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
-
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- ED_region_tag_redraw(ar);
-
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_selectability_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Selectability";
- ot->idname = "OUTLINER_OT_selectability_toggle";
- ot->description = "Toggle the selectability";
-
- /* callbacks */
- ot->exec = outliner_toggle_selectability_exec;
- ot->poll = ED_operator_outliner_active_no_editobject;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* Toggle Renderability ---------------------------------------- */
-
-void object_toggle_renderability_cb(
- bContext *UNUSED(C), ReportList *reports, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Base *base = (Base *)te->directdata;
-
- if (ID_IS_LINKED(tselem->id)) {
- BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
- return;
- }
-
- if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
- if (base) {
- base->object->restrictflag ^= OB_RESTRICT_RENDER;
- }
-}
-
-void group_toggle_renderability_cb(
- bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Group *group = (Group *)tselem->id;
- restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER);
-}
-
-static int outliner_toggle_renderability_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- Scene *scene = CTX_data_scene(C);
-
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
-
- DAG_id_type_tag(bmain, ID_OB);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
-
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_renderability_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Renderability";
- ot->idname = "OUTLINER_OT_renderability_toggle";
- ot->description = "Toggle the renderability of selected items";
-
- /* callbacks */
- ot->exec = outliner_toggle_renderability_exec;
- ot->poll = ED_operator_outliner_active;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* =============================================== */
/* Outliner setting toggles */
/* Toggle Expanded (Outliner) ---------------------------------------- */
@@ -990,37 +899,50 @@ void OUTLINER_OT_expanded_toggle(wmOperatorType *ot)
/* Toggle Selected (Outliner) ---------------------------------------- */
-static int outliner_toggle_selected_exec(bContext *C, wmOperator *UNUSED(op))
+static int outliner_select_all_exec(bContext *C, wmOperator *op)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
+ int action = RNA_enum_get(op->ptr, "action");
+ if (action == SEL_TOGGLE) {
+ action = outliner_flag_is_any_test(&soops->tree, TSE_SELECTED, 1) ? SEL_DESELECT : SEL_SELECT;
+ }
- if (outliner_flag_is_any_test(&soops->tree, TSE_SELECTED, 1))
- outliner_flag_set(&soops->tree, TSE_SELECTED, 0);
- else
- outliner_flag_set(&soops->tree, TSE_SELECTED, 1);
-
- soops->storeflag |= SO_TREESTORE_REDRAW;
+ switch (action) {
+ case SEL_SELECT:
+ outliner_flag_set(&soops->tree, TSE_SELECTED, 1);
+ break;
+ case SEL_DESELECT:
+ outliner_flag_set(&soops->tree, TSE_SELECTED, 0);
+ break;
+ case SEL_INVERT:
+ outliner_flag_flip(&soops->tree, TSE_SELECTED);
+ break;
+ }
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_no_rebuild(ar);
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_selected_toggle(wmOperatorType *ot)
+void OUTLINER_OT_select_all(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Toggle Selected";
- ot->idname = "OUTLINER_OT_selected_toggle";
+ ot->idname = "OUTLINER_OT_select_all";
ot->description = "Toggle the Outliner selection of items";
/* callbacks */
- ot->exec = outliner_toggle_selected_exec;
+ ot->exec = outliner_select_all_exec;
ot->poll = ED_operator_outliner_active;
- /* no undo or registry, UI option */
+ /* no undo or registry */
+
+ /* rna */
+ WM_operator_properties_select_all(ot);
}
/* ************************************************************** */
@@ -1046,7 +968,7 @@ static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeEle
}
/* to retrieve coordinates with redrawing the entire tree */
-static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
+void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
{
TreeElement *te;
int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
@@ -1075,14 +997,14 @@ static int outliner_open_back(TreeElement *te)
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceOops *so = CTX_wm_space_outliner(C);
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
TreeElement *te;
int xdelta, ytop;
- Object *obact = OBACT;
+ Object *obact = OBACT(view_layer);
if (!obact)
return OPERATOR_CANCELLED;
@@ -1125,11 +1047,9 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
xdelta = (int)(te->xs - v2d->cur.xmin);
v2d->cur.xmin += xdelta;
v2d->cur.xmax += xdelta;
-
- so->storeflag |= SO_TREESTORE_REDRAW;
}
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_no_rebuild(ar);
return OPERATOR_FINISHED;
}
@@ -1161,7 +1081,7 @@ static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
ar->v2d.cur.ymin += dy;
ar->v2d.cur.ymax += dy;
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_no_rebuild(ar);
return OPERATOR_FINISHED;
}
@@ -1285,7 +1205,7 @@ static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *so
soops->search_flags = flags;
/* redraw */
- soops->storeflag |= SO_TREESTORE_REDRAW;
+ ED_region_tag_redraw_no_rebuild(ar);
}
}
else {
@@ -1443,7 +1363,7 @@ static bool ed_operator_outliner_datablocks_active(bContext *C)
ScrArea *sa = CTX_wm_area(C);
if ((sa) && (sa->spacetype == SPACE_OUTLINER)) {
SpaceOops *so = CTX_wm_space_outliner(C);
- return (so->outlinevis == SO_DATABLOCKS);
+ return (so->outlinevis == SO_DATA_API);
}
return 0;
}
@@ -1975,434 +1895,3 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
-/* ************************************************************** */
-/* DRAG AND DROP OPERATORS */
-
-/* ******************** Parent Drop Operator *********************** */
-
-static int parent_drop_exec(bContext *C, wmOperator *op)
-{
- Object *par = NULL, *ob = NULL;
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- int partype = -1;
- char parname[MAX_ID_NAME], childname[MAX_ID_NAME];
-
- partype = RNA_enum_get(op->ptr, "type");
- RNA_string_get(op->ptr, "parent", parname);
- par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname);
- RNA_string_get(op->ptr, "child", childname);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname);
-
- if (ID_IS_LINKED(ob)) {
- BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
- return OPERATOR_CANCELLED;
- }
-
- ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL);
-
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Object *par = NULL;
- Object *ob = NULL;
- SpaceOops *soops = CTX_wm_space_outliner(C);
- ARegion *ar = CTX_wm_region(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = NULL;
- TreeElement *te = NULL;
- char childname[MAX_ID_NAME];
- char parname[MAX_ID_NAME];
- int partype = 0;
- float fmval[2];
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- /* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, true);
-
- if (te) {
- RNA_string_set(op->ptr, "parent", te->name);
- /* Identify parent and child */
- RNA_string_get(op->ptr, "child", childname);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname);
- RNA_string_get(op->ptr, "parent", parname);
- par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname);
-
- if (ELEM(NULL, ob, par)) {
- if (par == NULL) printf("par==NULL\n");
- return OPERATOR_CANCELLED;
- }
- if (ob == par) {
- return OPERATOR_CANCELLED;
- }
- if (ID_IS_LINKED(ob)) {
- BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
- return OPERATOR_CANCELLED;
- }
-
- scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
-
- if (scene == NULL) {
- /* currently outlier organized in a way, that if there's no parent scene
- * element for object it means that all displayed objects belong to
- * active scene and parenting them is allowed (sergey)
- */
-
- scene = CTX_data_scene(C);
- }
-
- if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) {
- if (ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL)) {
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
- }
- }
- else {
- /* Menu creation */
- wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
- uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
- PointerRNA ptr;
-
- /* Cannot use uiItemEnumO()... have multiple properties to set. */
- uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_OBJECT);
-
- /* par becomes parent, make the associated menus */
- if (par->type == OB_ARMATURE) {
- uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_ARMATURE);
-
- uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
-
- uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
-
- uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
-
- uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_BONE);
- }
- else if (par->type == OB_CURVE) {
- uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_CURVE);
-
- uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_FOLLOW);
-
- uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
- }
- else if (par->type == OB_LATTICE) {
- uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
- RNA_string_set(&ptr, "parent", parname);
- RNA_string_set(&ptr, "child", childname);
- RNA_enum_set(&ptr, "type", PAR_LATTICE);
- }
-
- UI_popup_menu_end(C, pup);
-
- return OPERATOR_INTERFACE;
- }
- }
- else {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_parent_drop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Drop to Set Parent";
- ot->description = "Drag to parent in Outliner";
- ot->idname = "OUTLINER_OT_parent_drop";
-
- /* api callbacks */
- ot->invoke = parent_drop_invoke;
- ot->exec = parent_drop_exec;
-
- ot->poll = ED_operator_outliner_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_string(ot->srna, "child", "Object", MAX_ID_NAME, "Child", "Child Object");
- RNA_def_string(ot->srna, "parent", "Object", MAX_ID_NAME, "Parent", "Parent Object");
- RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
-}
-
-static bool outliner_parenting_poll(bContext *C)
-{
- SpaceOops *soops = CTX_wm_space_outliner(C);
-
- if (soops) {
- return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS);
- }
-
- return false;
-}
-
-static int parent_clear_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- Main *bmain = CTX_data_main(C);
- Object *ob = NULL;
- SpaceOops *soops = CTX_wm_space_outliner(C);
- char obname[MAX_ID_NAME];
-
- RNA_string_get(op->ptr, "dragged_obj", obname);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, obname);
-
- /* search forwards to find the object */
- outliner_find_id(soops, &soops->tree, (ID *)ob);
-
- ED_object_parent_clear(ob, RNA_enum_get(op->ptr, "type"));
-
- DAG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
- return OPERATOR_FINISHED;
-}
-
-void OUTLINER_OT_parent_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Drop to Clear Parent";
- ot->description = "Drag to clear parent in Outliner";
- ot->idname = "OUTLINER_OT_parent_clear";
-
- /* api callbacks */
- ot->invoke = parent_clear_invoke;
-
- ot->poll = outliner_parenting_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_string(ot->srna, "dragged_obj", "Object", MAX_ID_NAME, "Child", "Child Object");
- RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", "");
-}
-
-static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Scene *scene = NULL;
- Object *ob = NULL;
- SpaceOops *soops = CTX_wm_space_outliner(C);
- ARegion *ar = CTX_wm_region(C);
- Main *bmain = CTX_data_main(C);
- TreeElement *te = NULL;
- char obname[MAX_ID_NAME];
- float fmval[2];
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- /* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, false);
-
- if (te) {
- Base *base;
-
- RNA_string_set(op->ptr, "scene", te->name);
- scene = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, te->name);
-
- RNA_string_get(op->ptr, "object", obname);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, obname);
-
- if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) {
- return OPERATOR_CANCELLED;
- }
-
- base = ED_object_scene_link(scene, ob);
-
- if (base == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- if (scene == CTX_data_scene(C)) {
- /* when linking to an inactive scene don't touch the layer */
- ob->lay = base->lay;
- ED_base_object_select(base, BA_SELECT);
- }
-
- DAG_relations_tag_update(bmain);
-
- WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
-
- return OPERATOR_FINISHED;
- }
-
- return OPERATOR_CANCELLED;
-}
-
-void OUTLINER_OT_scene_drop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Drop Object to Scene";
- ot->description = "Drag object to scene in Outliner";
- ot->idname = "OUTLINER_OT_scene_drop";
-
- /* api callbacks */
- ot->invoke = scene_drop_invoke;
-
- ot->poll = ED_operator_outliner_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
- RNA_def_string(ot->srna, "scene", "Scene", MAX_ID_NAME, "Scene", "Target Scene");
-}
-
-static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Material *ma = NULL;
- Object *ob = NULL;
- Main *bmain = CTX_data_main(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- ARegion *ar = CTX_wm_region(C);
- TreeElement *te = NULL;
- char mat_name[MAX_ID_NAME - 2];
- float fmval[2];
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- /* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, true);
-
- if (te) {
- RNA_string_set(op->ptr, "object", te->name);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, te->name);
-
- RNA_string_get(op->ptr, "material", mat_name);
- ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, mat_name);
-
- if (ELEM(NULL, ob, ma)) {
- return OPERATOR_CANCELLED;
- }
-
- assign_material(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
-
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
- WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
-
- return OPERATOR_FINISHED;
- }
-
- return OPERATOR_CANCELLED;
-}
-
-void OUTLINER_OT_material_drop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Drop Material on Object";
- ot->description = "Drag material to object in Outliner";
- ot->idname = "OUTLINER_OT_material_drop";
-
- /* api callbacks */
- ot->invoke = material_drop_invoke;
-
- ot->poll = ED_operator_outliner_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
- RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material");
-}
-
-static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Main *bmain = CTX_data_main(C);
- Group *group = NULL;
- Object *ob = NULL;
- Scene *scene = CTX_data_scene(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- ARegion *ar = CTX_wm_region(C);
- TreeElement *te = NULL;
- char ob_name[MAX_ID_NAME - 2];
- float fmval[2];
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- /* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, true);
-
- if (te) {
- group = (Group *)BKE_libblock_find_name(bmain, ID_GR, te->name);
-
- RNA_string_get(op->ptr, "object", ob_name);
- ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, ob_name);
-
- if (ELEM(NULL, group, ob)) {
- return OPERATOR_CANCELLED;
- }
- if (BKE_group_object_exists(group, ob)) {
- return OPERATOR_FINISHED;
- }
-
- if (BKE_group_object_cyclic_check(bmain, ob, group)) {
- BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
- return OPERATOR_CANCELLED;
- }
-
- BKE_group_object_add(group, ob, scene, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
- }
-
- return OPERATOR_CANCELLED;
-}
-
-void OUTLINER_OT_group_link(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Link Object to Group";
- ot->description = "Link Object to Group in Outliner";
- ot->idname = "OUTLINER_OT_group_link";
-
- /* api callbacks */
- ot->invoke = group_link_invoke;
-
- ot->poll = ED_operator_outliner_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
-}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index dabb95e9d2b..41a0dce7a38 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -36,14 +36,39 @@
/* internal exports only */
+struct ARegion;
+struct ListBase;
struct wmOperatorType;
+struct TreeElement;
struct TreeStoreElem;
+struct Main;
struct bContext;
struct Scene;
+struct ViewLayer;
struct ID;
struct Object;
struct bPoseChannel;
struct EditBone;
+struct wmEvent;
+struct wmKeyConfig;
+
+typedef enum TreeElementInsertType {
+ TE_INSERT_BEFORE,
+ TE_INSERT_AFTER,
+ TE_INSERT_INTO,
+} TreeElementInsertType;
+
+typedef enum TreeTraversalAction {
+ /* Continue traversal regularly, don't skip children. */
+ TRAVERSE_CONTINUE = 0,
+ /* Stop traversal */
+ TRAVERSE_BREAK,
+ /* Continue traversal, but skip childs of traversed element */
+ TRAVERSE_SKIP_CHILDS,
+} TreeTraversalAction;
+
+typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata);
+
typedef struct TreeElement {
struct TreeElement *next, *prev, *parent;
@@ -57,18 +82,29 @@ typedef struct TreeElement {
const char *name;
void *directdata; // Armature Bones, Base, Sequence, Strip...
PointerRNA rnaptr; // RNA Pointer
-} TreeElement;
+} TreeElement;
+
+typedef struct TreeElementIcon {
+ struct ID *drag_id, *drag_parent;
+ int icon;
+} TreeElementIcon;
#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, ID_CF, ID_PAL, ID_MC)) /* Only in 'blendfile' mode ... :/ */
+ ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS, ID_LP) || \
+ ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF, ID_PAL, ID_MC, ID_WS)) /* Only in 'blendfile' mode ... :/ */
/* TreeElement->flag */
-#define TE_ACTIVE 1
-#define TE_ICONROW 2
-#define TE_LAZY_CLOSED 4
-#define TE_FREE_NAME 8
+enum {
+ TE_ACTIVE = (1 << 0),
+ /* Closed items display their children as icon within the row. TE_ICONROW is for
+ * these child-items that are visible but only within the row of the closed parent. */
+ TE_ICONROW = (1 << 1),
+ TE_LAZY_CLOSED = (1 << 2),
+ TE_FREE_NAME = (1 << 3),
+ TE_DISABLED = (1 << 4),
+ TE_DRAGGING = (1 << 5),
+};
/* button events */
#define OL_NAMEBUTTON 1
@@ -93,16 +129,20 @@ typedef enum {
/* size constants */
#define OL_Y_OFFSET 2
-#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3.0f)
-#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f)
-#define OL_TOG_RESTRICT_RENDERX UI_UNIT_X
+#define OL_TOG_HIDEX (UI_UNIT_X * 4.0f + V2D_SCROLL_WIDTH)
+#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 3.0f + V2D_SCROLL_WIDTH)
+#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH)
+#define OL_TOG_RESTRICT_RENDERX (UI_UNIT_X + V2D_SCROLL_WIDTH)
-#define OL_TOGW OL_TOG_RESTRICT_VIEWX
+#define OL_TOGW OL_TOG_HIDEX
#define OL_RNA_COLX (UI_UNIT_X * 15)
#define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f)
#define OL_RNA_COL_SPACEX (UI_UNIT_X * 2.5f)
+/* The outliner display modes that support the filter system.
+ * Note: keep it synced with space_outliner.py */
+#define SUPPORT_FILTER_OUTLINER(soops_) (ELEM((soops_)->outlinevis, SO_VIEW_LAYER))
/* Outliner Searching --
*
@@ -127,28 +167,34 @@ typedef enum {
/* outliner_tree.c ----------------------------------------------- */
-void outliner_free_tree(ListBase *lb);
+void outliner_free_tree(ListBase *tree);
void outliner_cleanup_tree(struct SpaceOops *soops);
+void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree);
-TreeElement *outliner_find_tse(struct SpaceOops *soops, const TreeStoreElem *tse);
-TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
-TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, const struct ID *id);
-TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *pchan);
-TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone);
-struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode);
+void outliner_build_tree(
+ struct Main *mainvar,
+ struct Scene *scene, struct ViewLayer *view_layer,
+ struct SpaceOops *soops, struct ARegion *ar);
+
+typedef struct IDsSelectedData {
+ struct ListBase selected_array;
+} IDsSelectedData;
-void outliner_build_tree(struct Main *mainvar, struct Scene *scene, struct SpaceOops *soops);
+TreeTraversalAction outliner_find_selected_collections(struct TreeElement *te, void *customdata);
+TreeTraversalAction outliner_find_selected_objects(struct TreeElement *te, void *customdata);
/* outliner_draw.c ---------------------------------------------- */
void draw_outliner(const struct bContext *C);
void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag);
+TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te);
+
/* outliner_select.c -------------------------------------------- */
eOLDrawState tree_element_type_active(
- struct bContext *C, struct Scene *scene, struct SpaceOops *soops,
+ struct bContext *C, struct Scene *scene, struct ViewLayer *view_layer, struct SpaceOops *soops,
TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive);
-eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, SpaceOops *soops,
+eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, struct ViewLayer *view_layer, SpaceOops *soops,
TreeElement *te, const eOLSetState set, const bool handle_all_types);
void outliner_item_do_activate_from_tree_element(
@@ -158,22 +204,31 @@ int outliner_item_do_activate_from_cursor(
struct bContext *C, const int mval[2],
bool extend, bool recursive);
+void outliner_item_select(
+ struct SpaceOops *soops, const struct TreeElement *te,
+ const bool extend, const bool toggle);
+
+void outliner_object_mode_toggle(
+ struct bContext *C, Scene *scene, ViewLayer *view_layer,
+ Base *base);
+
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_cb)(
struct bContext *C, struct ReportList *, struct Scene *scene,
struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *);
void outliner_do_object_operation_ex(
- struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- outliner_operation_cb operation_cb, bool recurse_selected);
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct SpaceOops *soops,
+ struct ListBase *lb, outliner_operation_cb operation_cb, bool recurse_selected);
void outliner_do_object_operation(
- struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- outliner_operation_cb operation_cb);
+ struct bContext *C, struct ReportList *reports, struct Scene *scene, struct SpaceOops *soops,
+ struct ListBase *lb, outliner_operation_cb operation_cb);
int common_restrict_check(struct bContext *C, struct Object *ob);
int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel);
-void outliner_flag_set(ListBase *lb, short flag, short set);
+bool outliner_flag_set(ListBase *lb, short flag, short set);
+bool outliner_flag_flip(ListBase *lb, short flag);
void object_toggle_visibility_cb(
struct bContext *C, struct ReportList *reports, struct Scene *scene,
@@ -186,16 +241,6 @@ void object_toggle_renderability_cb(
TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_visibility_cb(
- struct bContext *C, struct ReportList *reports, struct Scene *scene,
- TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_selectability_cb(
- struct bContext *C, struct ReportList *reports, struct Scene *scene,
- TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_renderability_cb(
- struct bContext *C, struct ReportList *reports, struct Scene *scene,
- TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-
void item_rename_cb(
struct bContext *C, struct ReportList *reports, struct Scene *scene,
TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
@@ -213,9 +258,29 @@ void id_remap_cb(
struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te,
struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
+void item_object_mode_enter_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void item_object_mode_exit_cb(
+ struct bContext *C, struct ReportList *reports, struct Scene *scene,
+ TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+
+void outliner_set_coordinates(struct ARegion *ar, struct SpaceOops *soops);
+
+/* outliner_dragdrop.c */
+void outliner_dropboxes(void);
+
+void OUTLINER_OT_item_drag_drop(struct wmOperatorType *ot);
+void OUTLINER_OT_parent_drop(struct wmOperatorType *ot);
+void OUTLINER_OT_parent_clear(struct wmOperatorType *ot);
+void OUTLINER_OT_scene_drop(struct wmOperatorType *ot);
+void OUTLINER_OT_material_drop(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_drop(struct wmOperatorType *ot);
+
/* ...................................................... */
+void OUTLINER_OT_highlight_update(struct wmOperatorType *ot);
+
void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
void OUTLINER_OT_item_openclose(struct wmOperatorType *ot);
void OUTLINER_OT_item_rename(struct wmOperatorType *ot);
@@ -228,17 +293,13 @@ void OUTLINER_OT_show_one_level(struct wmOperatorType *ot);
void OUTLINER_OT_show_active(struct wmOperatorType *ot);
void OUTLINER_OT_show_hierarchy(struct wmOperatorType *ot);
-void OUTLINER_OT_select_border(struct wmOperatorType *ot);
+void OUTLINER_OT_select_box(struct wmOperatorType *ot);
-void OUTLINER_OT_selected_toggle(struct wmOperatorType *ot);
+void OUTLINER_OT_select_all(struct wmOperatorType *ot);
void OUTLINER_OT_expanded_toggle(struct wmOperatorType *ot);
void OUTLINER_OT_scroll_page(struct wmOperatorType *ot);
-void OUTLINER_OT_renderability_toggle(struct wmOperatorType *ot);
-void OUTLINER_OT_selectability_toggle(struct wmOperatorType *ot);
-void OUTLINER_OT_visibility_toggle(struct wmOperatorType *ot);
-
void OUTLINER_OT_keyingset_add_selected(struct wmOperatorType *ot);
void OUTLINER_OT_keyingset_remove_selected(struct wmOperatorType *ot);
@@ -247,18 +308,11 @@ void OUTLINER_OT_drivers_delete_selected(struct wmOperatorType *ot);
void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot);
-void OUTLINER_OT_parent_drop(struct wmOperatorType *ot);
-void OUTLINER_OT_parent_clear(struct wmOperatorType *ot);
-void OUTLINER_OT_scene_drop(struct wmOperatorType *ot);
-void OUTLINER_OT_material_drop(struct wmOperatorType *ot);
-void OUTLINER_OT_group_link(struct wmOperatorType *ot);
-
/* outliner_tools.c ---------------------------------------------- */
void OUTLINER_OT_operation(struct wmOperatorType *ot);
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
-void OUTLINER_OT_group_operation(struct wmOperatorType *ot);
void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_remap(struct wmOperatorType *ot);
@@ -267,10 +321,45 @@ void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot);
void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot);
+
/* ---------------------------------------------------------------- */
/* outliner_ops.c */
void outliner_operatortypes(void);
void outliner_keymap(struct wmKeyConfig *keyconf);
+/* outliner_collections.c */
+
+bool outliner_is_collection_tree_element(const TreeElement *te);
+struct Collection *outliner_collection_from_tree_element(const TreeElement *te);
+
+void OUTLINER_OT_collection_new(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_link(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_instance(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_exclude_set(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_exclude_clear(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_holdout_set(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_holdout_clear(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_indirect_only_set(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_indirect_only_clear(struct wmOperatorType *ot);
+
+/* outliner_utils.c ---------------------------------------------- */
+
+TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y);
+TreeElement *outliner_find_item_at_x_in_row(const SpaceOops *soops, const TreeElement *parent_te, float view_co_x);
+TreeElement *outliner_find_tse(struct SpaceOops *soops, const TreeStoreElem *tse);
+TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
+TreeElement *outliner_find_parent_element(ListBase *lb, TreeElement *parent_te, const TreeElement *child_te);
+TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, const struct ID *id);
+TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *pchan);
+TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone);
+struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode);
+bool outliner_tree_traverse(const SpaceOops *soops, ListBase *tree, int filter_te_flag, int filter_tselem_flag,
+ TreeTraversalFunc func, void *customdata);
+
+
#endif /* __OUTLINER_INTERN_H__ */
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 16cd383b5c2..87c9827a15a 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -28,29 +28,47 @@
* \ingroup spoutliner
*/
-#include "DNA_space_types.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_collection_types.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+
+#include "GPU_immediate.h"
+#include "GPU_state.h"
#include "RNA_access.h"
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
#include "WM_api.h"
#include "WM_types.h"
-#include "outliner_intern.h"
+#include "ED_screen.h"
+#include "ED_select_utils.h"
+#include "outliner_intern.h"
/* ************************** registration **********************************/
void outliner_operatortypes(void)
{
+ WM_operatortype_append(OUTLINER_OT_highlight_update);
WM_operatortype_append(OUTLINER_OT_item_activate);
- WM_operatortype_append(OUTLINER_OT_select_border);
+ WM_operatortype_append(OUTLINER_OT_select_box);
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
+ WM_operatortype_append(OUTLINER_OT_item_drag_drop);
WM_operatortype_append(OUTLINER_OT_operation);
WM_operatortype_append(OUTLINER_OT_scene_operation);
WM_operatortype_append(OUTLINER_OT_object_operation);
- WM_operatortype_append(OUTLINER_OT_group_operation);
WM_operatortype_append(OUTLINER_OT_lib_operation);
WM_operatortype_append(OUTLINER_OT_lib_relocate);
WM_operatortype_append(OUTLINER_OT_id_operation);
@@ -67,13 +85,9 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_show_hierarchy);
WM_operatortype_append(OUTLINER_OT_scroll_page);
- WM_operatortype_append(OUTLINER_OT_selected_toggle);
+ WM_operatortype_append(OUTLINER_OT_select_all);
WM_operatortype_append(OUTLINER_OT_expanded_toggle);
- WM_operatortype_append(OUTLINER_OT_renderability_toggle);
- WM_operatortype_append(OUTLINER_OT_selectability_toggle);
- WM_operatortype_append(OUTLINER_OT_visibility_toggle);
-
WM_operatortype_append(OUTLINER_OT_keyingset_add_selected);
WM_operatortype_append(OUTLINER_OT_keyingset_remove_selected);
@@ -86,72 +100,25 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_parent_clear);
WM_operatortype_append(OUTLINER_OT_scene_drop);
WM_operatortype_append(OUTLINER_OT_material_drop);
- WM_operatortype_append(OUTLINER_OT_group_link);
+ WM_operatortype_append(OUTLINER_OT_collection_drop);
+
+ /* collections */
+ WM_operatortype_append(OUTLINER_OT_collection_new);
+ WM_operatortype_append(OUTLINER_OT_collection_duplicate);
+ WM_operatortype_append(OUTLINER_OT_collection_delete);
+ WM_operatortype_append(OUTLINER_OT_collection_objects_select);
+ WM_operatortype_append(OUTLINER_OT_collection_objects_deselect);
+ WM_operatortype_append(OUTLINER_OT_collection_link);
+ WM_operatortype_append(OUTLINER_OT_collection_instance);
+ WM_operatortype_append(OUTLINER_OT_collection_exclude_set);
+ WM_operatortype_append(OUTLINER_OT_collection_exclude_clear);
+ WM_operatortype_append(OUTLINER_OT_collection_holdout_set);
+ WM_operatortype_append(OUTLINER_OT_collection_holdout_clear);
+ WM_operatortype_append(OUTLINER_OT_collection_indirect_only_set);
+ WM_operatortype_append(OUTLINER_OT_collection_indirect_only_clear);
}
void outliner_keymap(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Outliner", SPACE_OUTLINER, 0);
- wmKeyMapItem *kmi;
-
- WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, 0, 0);
- RNA_boolean_set(kmi->ptr, "recursive", false);
- RNA_boolean_set(kmi->ptr, "extend", false);
-
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "recursive", false);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "recursive", true);
- RNA_boolean_set(kmi->ptr, "extend", false);
-
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "recursive", true);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
-
- WM_keymap_add_item(keymap, "OUTLINER_OT_select_border", BKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_openclose", RETKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "all", false);
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_openclose", RETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "all", true);
-
- WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "OUTLINER_OT_operation", RIGHTMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "OUTLINER_OT_show_hierarchy", HOMEKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "OUTLINER_OT_show_active", PERIODKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "OUTLINER_OT_show_active", PADPERIOD, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_scroll_page", PAGEDOWNKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "up", false);
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_scroll_page", PAGEUPKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "up", true);
-
- WM_keymap_add_item(keymap, "OUTLINER_OT_show_one_level", PADPLUSKEY, KM_PRESS, 0, 0); /* open */
- kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_show_one_level", PADMINUS, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "open", false); /* close */
-
- WM_keymap_verify_item(keymap, "OUTLINER_OT_selected_toggle", AKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "OUTLINER_OT_expanded_toggle", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_verify_item(keymap, "OUTLINER_OT_renderability_toggle", RKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "OUTLINER_OT_selectability_toggle", SKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "OUTLINER_OT_visibility_toggle", VKEY, KM_PRESS, 0, 0);
-
-
- /* keying sets - only for databrowse */
- WM_keymap_verify_item(keymap, "OUTLINER_OT_keyingset_add_selected", KKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "OUTLINER_OT_keyingset_remove_selected", KKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_delete", IKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_ensure(keyconf, "Outliner", SPACE_OUTLINER, 0);
}
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index e40ba867049..efe27b5be89 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -32,29 +32,38 @@
#include <stdlib.h>
#include "DNA_armature_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_world_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
+#include "BKE_armature.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_gpencil.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
-#include "BKE_armature.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
#include "ED_armature.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_undo.h"
+#include "ED_gpencil.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -68,75 +77,125 @@
#include "outliner_intern.h"
-/* ****************************************************** */
-/* Outliner Selection (gray-blue highlight for rows) */
-
-static int outliner_select(SpaceOops *soops, ListBase *lb, int *index, short *selecting)
+static void do_outliner_activate_obdata(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base)
{
- TreeElement *te;
- TreeStoreElem *tselem;
- bool changed = false;
-
- for (te = lb->first; te && *index >= 0; te = te->next, (*index)--) {
- tselem = TREESTORE(te);
-
- /* if we've encountered the right item, set its 'Outliner' selection status */
- if (*index == 0) {
- /* this should be the last one, so no need to do anything with index */
- if ((te->flag & TE_ICONROW) == 0) {
- /* -1 value means toggle testing for now... */
- if (*selecting == -1) {
- if (tselem->flag & TSE_SELECTED)
- *selecting = 0;
- else
- *selecting = 1;
- }
+ Main *bmain = CTX_data_main(C);
+ Object *obact = OBACT(view_layer);
+ bool use_all = false;
- /* set selection */
- if (*selecting)
- tselem->flag |= TSE_SELECTED;
- else
- tselem->flag &= ~TSE_SELECTED;
+ if (obact == NULL) {
+ ED_object_base_activate(C, base);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ obact = base->object;
+ use_all = true;
+ }
+ else if (obact->data == base->object->data) {
+ use_all = true;
+ }
- changed |= true;
+ if (use_all) {
+ WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
+ else {
+ Object *ob = base->object;
+ if (ob->type == obact->type) {
+ bool ok;
+ if (BKE_object_is_in_editmode(ob)) {
+ ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA | EM_WAITCURSOR);
+ }
+ else {
+ ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_WAITCURSOR | EM_NO_CONTEXT);
+ }
+ if (ok) {
+ ED_object_base_select(base, (ob->mode & OB_MODE_EDIT) ? BA_SELECT : BA_DESELECT);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
}
- else if (TSELEM_OPEN(tselem, soops)) {
- /* Only try selecting sub-elements if we haven't hit the right element yet
- *
- * Hack warning:
- * Index must be reduced before supplying it to the sub-tree to try to do
- * selection, however, we need to increment it again for the next loop to
- * function correctly
- */
- (*index)--;
- changed |= outliner_select(soops, &te->subtree, index, selecting);
- (*index)++;
+ }
+}
+
+static void do_outliner_activate_pose(bContext *C, ViewLayer *view_layer, Base *base)
+{
+ Object *obact = OBACT(view_layer);
+ bool use_all = false;
+
+ if (obact == NULL) {
+ ED_object_base_activate(C, base);
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ obact = base->object;
+ use_all = true;
+ }
+ else if (obact->data == base->object->data) {
+ use_all = true;
+ }
+
+ if (use_all) {
+ WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
+ else {
+ Object *ob = base->object;
+ if (ob->type == obact->type) {
+ struct Main *bmain = CTX_data_main(C);
+ bool ok = false;
+ if (ob->mode & OB_MODE_POSE) {
+ ok = ED_object_posemode_exit_ex(bmain, ob);
+ }
+ else {
+ ok = ED_object_posemode_enter_ex(bmain, ob);
+ }
+ if (ok) {
+ ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT);
+
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ }
}
}
+}
- return changed;
+/* For draw callback to run mode switching */
+void outliner_object_mode_toggle(
+ bContext *C, Scene *scene, ViewLayer *view_layer,
+ Base *base)
+{
+ Object *obact = OBACT(view_layer);
+ if (obact->mode & OB_MODE_EDIT) {
+ do_outliner_activate_obdata(C, scene, view_layer, base);
+ }
+ else if (obact->mode & OB_MODE_POSE) {
+ do_outliner_activate_pose(C, view_layer, base);
+ }
}
/* ****************************************************** */
/* Outliner Element Selection/Activation on Click */
-static eOLDrawState tree_element_active_renderlayer(
- bContext *C, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
+static eOLDrawState active_viewlayer(
+ bContext *C, Scene *UNUSED(scene), ViewLayer *UNUSED(sl), TreeElement *te, const eOLSetState set)
{
- Scene *sce;
-
/* paranoia check */
if (te->idcode != ID_SCE)
return OL_DRAWSEL_NONE;
- sce = (Scene *)tselem->id;
+
+ ViewLayer *view_layer = te->directdata;
if (set != OL_SETSEL_NONE) {
- sce->r.actlay = tselem->nr;
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, sce);
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = WM_window_get_active_scene(win);
+
+ if (BLI_findindex(&scene->view_layers, view_layer) != -1) {
+ WM_window_set_active_view_layer(win, view_layer);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, NULL);
+ }
}
else {
- return sce->r.actlay == tselem->nr;
+ return CTX_data_view_layer(C) == view_layer;
}
return OL_DRAWSEL_NONE;
}
@@ -146,14 +205,14 @@ static eOLDrawState tree_element_active_renderlayer(
* CTRL+LMB: Select/Deselect object and all children.
* CTRL+SHIFT+LMB: Add/Remove object and all children.
*/
-static void do_outliner_object_select_recursive(Scene *scene, Object *ob_parent, bool select)
+static void do_outliner_object_select_recursive(ViewLayer *view_layer, Object *ob_parent, bool select)
{
Base *base;
- for (base = FIRSTBASE; base; base = base->next) {
+ for (base = FIRSTBASE(view_layer); base; base = base->next) {
Object *ob = base->object;
- if ((((ob->restrictflag & OB_RESTRICT_VIEW) == 0) && BKE_object_is_child_recursive(ob_parent, ob))) {
- ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
+ if ((((base->flag & BASE_VISIBLE) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) {
+ ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
}
}
}
@@ -184,7 +243,7 @@ static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_p
}
static eOLDrawState tree_element_set_active_object(
- bContext *C, Scene *scene, SpaceOops *soops,
+ bContext *C, Scene *scene, ViewLayer *view_layer, SpaceOops *soops,
TreeElement *te, const eOLSetState set, bool recursive)
{
TreeStoreElem *tselem = TREESTORE(te);
@@ -198,7 +257,7 @@ static eOLDrawState tree_element_set_active_object(
}
else {
ob = (Object *)outliner_search_back(soops, te, ID_OB);
- if (ob == OBACT) {
+ if (ob == OBACT(view_layer)) {
return OL_DRAWSEL_NONE;
}
}
@@ -208,46 +267,70 @@ static eOLDrawState tree_element_set_active_object(
sce = (Scene *)outliner_search_back(soops, te, ID_SCE);
if (sce && scene != sce) {
- ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+ WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce);
scene = sce;
}
/* find associated base in current scene */
- base = BKE_scene_base_find(scene, ob);
+ base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ if (base != NULL) {
+ Object *obact = OBACT(view_layer);
+ const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
+ if (base && !BKE_object_is_mode_compat(base->object, object_mode)) {
+ if (object_mode == OB_MODE_OBJECT) {
+ struct Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_object_mode_generic_exit(bmain, depsgraph, scene, base->object);
+ }
+ if (!BKE_object_is_mode_compat(base->object, object_mode)) {
+ base = NULL;
+ }
+ }
+ }
+ }
if (base) {
if (set == OL_SETSEL_EXTEND) {
/* swap select */
- if (base->flag & SELECT)
- ED_base_object_select(base, BA_DESELECT);
+ if (base->flag & BASE_SELECTED)
+ ED_object_base_select(base, BA_DESELECT);
else
- ED_base_object_select(base, BA_SELECT);
+ ED_object_base_select(base, BA_SELECT);
}
else {
/* deleselect all */
- BKE_scene_base_deselect_all(scene);
- ED_base_object_select(base, BA_SELECT);
+
+ /* Only in object mode so we can switch the active object,
+ * keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode.
+ * This keeps the convention that all objects in the current mode are also selected. see T55246. */
+ if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) ? (ob->mode == OB_MODE_OBJECT) : true) {
+ BKE_view_layer_base_deselect_all(view_layer);
+ }
+ ED_object_base_select(base, BA_SELECT);
}
if (recursive) {
/* Recursive select/deselect for Object hierarchies */
- do_outliner_object_select_recursive(scene, ob, (ob->flag & SELECT) != 0);
+ do_outliner_object_select_recursive(view_layer, ob, (base->flag & BASE_SELECTED) != 0);
}
- if (C) {
- ED_base_object_activate(C, base); /* adds notifier */
+ if (set != OL_SETSEL_NONE) {
+ ED_object_base_activate(C, base); /* adds notifier */
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
- }
-
- if (ob != scene->obedit)
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
+ if (ob != OBEDIT_FROM_VIEW_LAYER(view_layer)) {
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
+ }
+ }
return OL_DRAWSEL_NORMAL;
}
static eOLDrawState tree_element_active_material(
- bContext *C, Scene *scene, SpaceOops *soops,
+ bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, SpaceOops *soops,
TreeElement *te, const eOLSetState set)
{
TreeElement *tes;
@@ -256,7 +339,7 @@ static eOLDrawState tree_element_active_material(
/* we search for the object parent */
ob = (Object *)outliner_search_back(soops, te, ID_OB);
// note: ob->matbits can be NULL when a local object points to a library mesh.
- if (ob == NULL || ob != OBACT || ob->matbits == NULL) {
+ if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) {
return OL_DRAWSEL_NONE; /* just paranoia */
}
@@ -293,108 +376,21 @@ static eOLDrawState tree_element_active_material(
/* Tagging object for update seems a bit stupid here, but looks like we have to do it
* for render views to update. See T42973.
* Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */
- DAG_id_tag_update((ID *)ob, OB_RECALC_OB);
+ DEG_id_tag_update((ID *)ob, OB_RECALC_OB);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
}
return OL_DRAWSEL_NONE;
}
-static eOLDrawState tree_element_active_texture(
- bContext *C, Scene *scene, SpaceOops *UNUSED(soops),
- TreeElement *te, const eOLSetState set)
-{
- TreeElement *tep;
- TreeStoreElem /* *tselem,*/ *tselemp;
- Object *ob = OBACT;
- SpaceButs *sbuts = NULL;
-
- if (ob == NULL) {
- /* no active object */
- return OL_DRAWSEL_NONE;
- }
-
- /*tselem = TREESTORE(te);*/ /*UNUSED*/
-
- /* find buttons region (note, this is undefined really still, needs recode in blender) */
- /* XXX removed finding sbuts */
-
- /* where is texture linked to? */
- tep = te->parent;
- tselemp = TREESTORE(tep);
-
- if (tep->idcode == ID_WO) {
- World *wrld = (World *)tselemp->id;
-
- if (set != OL_SETSEL_NONE) {
- if (sbuts) {
- // XXX sbuts->tabo = TAB_SHADING_TEX; // hack from header_buttonswin.c
- // XXX sbuts->texfrom = 1;
- }
-// XXX extern_set_butspace(F6KEY, 0); // force shading buttons texture
- wrld->texact = te->index;
- }
- else if (tselemp->id == (ID *)(scene->world)) {
- if (wrld->texact == te->index) {
- return OL_DRAWSEL_NORMAL;
- }
- }
- }
- else if (tep->idcode == ID_LA) {
- Lamp *la = (Lamp *)tselemp->id;
- if (set != OL_SETSEL_NONE) {
- if (sbuts) {
- // XXX sbuts->tabo = TAB_SHADING_TEX; // hack from header_buttonswin.c
- // XXX sbuts->texfrom = 2;
- }
-// XXX extern_set_butspace(F6KEY, 0); // force shading buttons texture
- la->texact = te->index;
- }
- else {
- if (tselemp->id == ob->data) {
- if (la->texact == te->index) {
- return OL_DRAWSEL_NORMAL;
- }
- }
- }
- }
- else if (tep->idcode == ID_MA) {
- Material *ma = (Material *)tselemp->id;
- if (set != OL_SETSEL_NONE) {
- if (sbuts) {
- //sbuts->tabo = TAB_SHADING_TEX; // hack from header_buttonswin.c
- // XXX sbuts->texfrom = 0;
- }
-// XXX extern_set_butspace(F6KEY, 0); // force shading buttons texture
- ma->texact = (char)te->index;
-
- /* also set active material */
- ob->actcol = tep->index + 1;
- }
- else if (tep->flag & TE_ACTIVE) { // this is active material
- if (ma->texact == te->index) {
- return OL_DRAWSEL_NORMAL;
- }
- }
- }
-
- if (set != OL_SETSEL_NONE) {
- WM_event_add_notifier(C, NC_TEXTURE, NULL);
- }
-
- /* no active object */
- return OL_DRAWSEL_NONE;
-}
-
-
static eOLDrawState tree_element_active_lamp(
- bContext *UNUSED(C), Scene *scene, SpaceOops *soops,
+ bContext *UNUSED(C), Scene *UNUSED(scene), ViewLayer *view_layer, SpaceOops *soops,
TreeElement *te, const eOLSetState set)
{
Object *ob;
/* we search for the object parent */
ob = (Object *)outliner_search_back(soops, te, ID_OB);
- if (ob == NULL || ob != OBACT) {
+ if (ob == NULL || ob != OBACT(view_layer)) {
/* just paranoia */
return OL_DRAWSEL_NONE;
}
@@ -410,7 +406,7 @@ static eOLDrawState tree_element_active_lamp(
}
static eOLDrawState tree_element_active_camera(
- bContext *UNUSED(C), Scene *scene, SpaceOops *soops,
+ bContext *UNUSED(C), Scene *scene, ViewLayer *UNUSED(sl), SpaceOops *soops,
TreeElement *te, const eOLSetState set)
{
Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
@@ -423,7 +419,7 @@ static eOLDrawState tree_element_active_camera(
}
static eOLDrawState tree_element_active_world(
- bContext *C, Scene *scene, SpaceOops *UNUSED(soops),
+ bContext *C, Scene *scene, ViewLayer *UNUSED(sl), SpaceOops *UNUSED(soops),
TreeElement *te, const eOLSetState set)
{
TreeElement *tep;
@@ -440,7 +436,7 @@ static eOLDrawState tree_element_active_world(
if (set != OL_SETSEL_NONE) {
/* make new scene active */
if (sce && scene != sce) {
- ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+ WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce);
}
}
@@ -456,7 +452,7 @@ static eOLDrawState tree_element_active_world(
}
static eOLDrawState tree_element_active_defgroup(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
+ bContext *C, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
{
Object *ob;
@@ -466,21 +462,42 @@ static eOLDrawState tree_element_active_defgroup(
BLI_assert(te->index + 1 >= 0);
ob->actdef = te->index + 1;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
}
else {
- if (ob == OBACT) {
+ if (ob == OBACT(view_layer))
if (ob->actdef == te->index + 1) {
return OL_DRAWSEL_NORMAL;
}
+ }
+ return OL_DRAWSEL_NONE;
+}
+
+static eOLDrawState UNUSED_FUNCTION(tree_element_active_gplayer)(
+ bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
+{
+ bGPdata *gpd = (bGPdata *)tselem->id;
+ bGPDlayer *gpl = te->directdata;
+
+ /* We can only have a single "active" layer at a time
+ * and there must always be an active layer...
+ */
+ if (set != OL_SETSEL_NONE) {
+ if (gpl) {
+ BKE_gpencil_layer_setactive(gpd, gpl);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd);
}
}
+ else {
+ return OL_DRAWSEL_NORMAL;
+ }
+
return OL_DRAWSEL_NONE;
}
static eOLDrawState tree_element_active_posegroup(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
+ bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
{
Object *ob = (Object *)tselem->id;
@@ -491,7 +508,7 @@ static eOLDrawState tree_element_active_posegroup(
}
}
else {
- if (ob == OBACT && ob->pose) {
+ if (ob == OBACT(view_layer) && ob->pose) {
if (ob->pose->active_group == te->index + 1) {
return OL_DRAWSEL_NORMAL;
}
@@ -501,7 +518,7 @@ static eOLDrawState tree_element_active_posegroup(
}
static eOLDrawState tree_element_active_posechannel(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
+ bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
{
Object *ob = (Object *)tselem->id;
bArmature *arm = ob->data;
@@ -535,7 +552,7 @@ static eOLDrawState tree_element_active_posechannel(
}
}
else {
- if (ob == OBACT && ob->pose) {
+ if (ob == OBACT(view_layer) && ob->pose) {
if (pchan->bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
}
@@ -545,14 +562,14 @@ static eOLDrawState tree_element_active_posechannel(
}
static eOLDrawState tree_element_active_bone(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
+ bContext *C, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
Bone *bone = te->directdata;
if (set != OL_SETSEL_NONE) {
if (!(bone->flag & BONE_HIDDEN_P)) {
- Object *ob = OBACT;
+ Object *ob = OBACT(view_layer);
if (ob) {
if (set != OL_SETSEL_EXTEND) {
/* single select forces all other bones to get unselected */
@@ -581,7 +598,7 @@ static eOLDrawState tree_element_active_bone(
}
}
else {
- Object *ob = OBACT;
+ Object *ob = OBACT(view_layer);
if (ob && ob->data == arm) {
if (bone->flag & BONE_SELECTED) {
@@ -594,7 +611,7 @@ static eOLDrawState tree_element_active_bone(
/* ebones only draw in editmode armature */
-static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature *arm, EditBone *ebone, short sel)
+static void tree_element_active_ebone__sel(bContext *C, Object *obedit, bArmature *arm, EditBone *ebone, short sel)
{
if (sel) {
ebone->flag |= BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL;
@@ -608,34 +625,34 @@ static void tree_element_active_ebone__sel(bContext *C, Scene *scene, bArmature
if (ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag &= ~BONE_TIPSEL;
}
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, scene->obedit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, obedit);
}
static eOLDrawState tree_element_active_ebone(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set, bool recursive)
+ bContext *C, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set, bool recursive)
{
- BLI_assert(scene->obedit != NULL);
-
- bArmature *arm = scene->obedit->data;
+ Object *obedit = CTX_data_edit_object(C);
+ BLI_assert(obedit != NULL);
+ bArmature *arm = obedit->data;
EditBone *ebone = te->directdata;
eOLDrawState status = OL_DRAWSEL_NONE;
if (set != OL_SETSEL_NONE) {
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
- ED_armature_edit_deselect_all(scene->obedit);
- tree_element_active_ebone__sel(C, scene, arm, ebone, true);
+ ED_armature_edit_deselect_all(obedit);
+ tree_element_active_ebone__sel(C, obedit, arm, ebone, true);
status = OL_DRAWSEL_NORMAL;
}
}
else if (set == OL_SETSEL_EXTEND) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
if (!(ebone->flag & BONE_SELECTED)) {
- tree_element_active_ebone__sel(C, scene, arm, ebone, true);
+ tree_element_active_ebone__sel(C, obedit, arm, ebone, true);
status = OL_DRAWSEL_NORMAL;
}
else {
/* entirely selected, so de-select */
- tree_element_active_ebone__sel(C, scene, arm, ebone, false);
+ tree_element_active_ebone__sel(C, obedit, arm, ebone, false);
status = OL_DRAWSEL_NONE;
}
}
@@ -654,7 +671,7 @@ static eOLDrawState tree_element_active_ebone(
}
static eOLDrawState tree_element_active_modifier(
- bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
+ bContext *C, Scene *UNUSED(scene), ViewLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
{
if (set != OL_SETSEL_NONE) {
Object *ob = (Object *)tselem->id;
@@ -682,7 +699,7 @@ static eOLDrawState tree_element_active_psys(
}
static int tree_element_active_constraint(
- bContext *C, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
+ bContext *C, Scene *UNUSED(scene), ViewLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
{
if (set != OL_SETSEL_NONE) {
Object *ob = (Object *)tselem->id;
@@ -695,7 +712,7 @@ static int tree_element_active_constraint(
}
static eOLDrawState tree_element_active_text(
- bContext *UNUSED(C), Scene *UNUSED(scene), SpaceOops *UNUSED(soops),
+ bContext *UNUSED(C), Scene *UNUSED(scene), ViewLayer *UNUSED(sl), SpaceOops *UNUSED(soops),
TreeElement *UNUSED(te), int UNUSED(set))
{
// XXX removed
@@ -703,10 +720,10 @@ static eOLDrawState tree_element_active_text(
}
static eOLDrawState tree_element_active_pose(
- bContext *C, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
+ bContext *C, ViewLayer *view_layer, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set)
{
Object *ob = (Object *)tselem->id;
- Base *base = BKE_scene_base_find(scene, ob);
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base == NULL) {
/* Armature not instantiated in current scene (e.g. inside an appended group...). */
@@ -714,16 +731,7 @@ static eOLDrawState tree_element_active_pose(
}
if (set != OL_SETSEL_NONE) {
- if (scene->obedit) {
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
- }
-
- if (ob->mode & OB_MODE_POSE) {
- ED_object_posemode_exit(C, ob);
- }
- else {
- ED_object_posemode_enter(C, ob);
- }
+ do_outliner_activate_pose(C, view_layer, base);
}
else {
if (ob->mode & OB_MODE_POSE) {
@@ -795,7 +803,7 @@ static eOLDrawState tree_element_active_sequence_dup(
}
static eOLDrawState tree_element_active_keymap_item(
- bContext *UNUSED(C), TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set)
+ bContext *UNUSED(C), Scene *UNUSED(scene), ViewLayer *UNUSED(sl), TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set)
{
wmKeyMapItem *kmi = te->directdata;
@@ -811,84 +819,125 @@ static eOLDrawState tree_element_active_keymap_item(
return OL_DRAWSEL_NONE;
}
+static eOLDrawState tree_element_active_master_collection(
+ bContext *C, TreeElement *UNUSED(te), const eOLSetState set)
+{
+ if (set == OL_SETSEL_NONE) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *active = CTX_data_layer_collection(C);
+
+ if (active == view_layer->layer_collections.first) {
+ return OL_DRAWSEL_NORMAL;
+ }
+ }
+ else {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *layer_collection = view_layer->layer_collections.first;
+ BKE_layer_collection_activate(view_layer, layer_collection);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ }
+
+ return OL_DRAWSEL_NONE;
+}
+
+static eOLDrawState tree_element_active_layer_collection(
+ bContext *C, TreeElement *te, const eOLSetState set)
+{
+ if (set == OL_SETSEL_NONE) {
+ LayerCollection *active = CTX_data_layer_collection(C);
+
+ if (active == te->directdata) {
+ return OL_DRAWSEL_NORMAL;
+ }
+ }
+ else {
+ Scene *scene = CTX_data_scene(C);
+ LayerCollection *layer_collection = te->directdata;
+ ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
+ BKE_layer_collection_activate(view_layer, layer_collection);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ }
+
+ return OL_DRAWSEL_NONE;
+}
+
/* ---------------------------------------------- */
/* generic call for ID data check or make/check active in UI */
-eOLDrawState tree_element_active(bContext *C, Scene *scene, SpaceOops *soops, TreeElement *te,
+eOLDrawState tree_element_active(bContext *C, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, TreeElement *te,
const eOLSetState set, const bool handle_all_types)
{
switch (te->idcode) {
/* Note: ID_OB only if handle_all_type is true, else objects are handled specially to allow multiple
- * selection. See do_outliner_item_activate_from_cursor. */
+ * selection. See do_outliner_item_activate. */
case ID_OB:
if (handle_all_types) {
- return tree_element_set_active_object(C, scene, soops, te, set, false);
+ return tree_element_set_active_object(C, scene, view_layer, soops, te, set, false);
}
break;
case ID_MA:
- return tree_element_active_material(C, scene, soops, te, set);
+ return tree_element_active_material(C, scene, view_layer, soops, te, set);
case ID_WO:
- return tree_element_active_world(C, scene, soops, te, set);
+ return tree_element_active_world(C, scene, view_layer, soops, te, set);
case ID_LA:
- return tree_element_active_lamp(C, scene, soops, te, set);
- case ID_TE:
- return tree_element_active_texture(C, scene, soops, te, set);
+ return tree_element_active_lamp(C, scene, view_layer, soops, te, set);
case ID_TXT:
- return tree_element_active_text(C, scene, soops, te, set);
+ return tree_element_active_text(C, scene, view_layer, soops, te, set);
case ID_CA:
- return tree_element_active_camera(C, scene, soops, te, set);
+ return tree_element_active_camera(C, scene, view_layer, soops, te, set);
}
return OL_DRAWSEL_NONE;
}
/**
* Generic call for non-id data to make/check active in UI
- *
- * \note Context can be NULL when ``(set == OL_SETSEL_NONE)``
*/
eOLDrawState tree_element_type_active(
- bContext *C, Scene *scene, SpaceOops *soops,
+ bContext *C, Scene *scene, ViewLayer *view_layer, SpaceOops *soops,
TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
{
switch (tselem->type) {
case TSE_DEFGROUP:
- return tree_element_active_defgroup(C, scene, te, tselem, set);
+ return tree_element_active_defgroup(C, view_layer, te, tselem, set);
case TSE_BONE:
- return tree_element_active_bone(C, scene, te, tselem, set, recursive);
+ return tree_element_active_bone(C, view_layer, te, tselem, set, recursive);
case TSE_EBONE:
- return tree_element_active_ebone(C, scene, te, tselem, set, recursive);
+ return tree_element_active_ebone(C, te, tselem, set, recursive);
case TSE_MODIFIER:
- return tree_element_active_modifier(C, te, tselem, set);
+ return tree_element_active_modifier(C, scene, view_layer, te, tselem, set);
case TSE_LINKED_OB:
if (set != OL_SETSEL_NONE) {
- tree_element_set_active_object(C, scene, soops, te, set, false);
+ tree_element_set_active_object(C, scene, view_layer, soops, te, set, false);
}
- else if (tselem->id == (ID *)OBACT) {
+ else if (tselem->id == (ID *)OBACT(view_layer)) {
return OL_DRAWSEL_NORMAL;
}
break;
case TSE_LINKED_PSYS:
return tree_element_active_psys(C, scene, te, tselem, set);
case TSE_POSE_BASE:
- return tree_element_active_pose(C, scene, te, tselem, set);
+ return tree_element_active_pose(C, view_layer, te, tselem, set);
case TSE_POSE_CHANNEL:
- return tree_element_active_posechannel(C, scene, te, tselem, set, recursive);
+ return tree_element_active_posechannel(C, scene, view_layer, te, tselem, set, recursive);
case TSE_CONSTRAINT:
- return tree_element_active_constraint(C, te, tselem, set);
+ return tree_element_active_constraint(C, scene, view_layer, te, tselem, set);
case TSE_R_LAYER:
- return tree_element_active_renderlayer(C, te, tselem, set);
+ return active_viewlayer(C, scene, view_layer, te, set);
case TSE_POSEGRP:
- return tree_element_active_posegroup(C, scene, te, tselem, set);
+ return tree_element_active_posegroup(C, scene, view_layer, te, tselem, set);
case TSE_SEQUENCE:
return tree_element_active_sequence(C, scene, te, tselem, set);
case TSE_SEQUENCE_DUP:
return tree_element_active_sequence_dup(scene, te, tselem, set);
case TSE_KEYMAP_ITEM:
- return tree_element_active_keymap_item(C, te, tselem, set);
+ return tree_element_active_keymap_item(C, scene, view_layer, te, tselem, set);
case TSE_GP_LAYER:
- //return tree_element_active_gplayer(C, scene, te, tselem, set);
+ //return tree_element_active_gplayer(C, scene, s, te, tselem, set);
break;
-
+ case TSE_VIEW_COLLECTION_BASE:
+ return tree_element_active_master_collection(C, te, set);
+ case TSE_LAYER_COLLECTION:
+ return tree_element_active_layer_collection(C, te, set);
}
return OL_DRAWSEL_NONE;
}
@@ -902,16 +951,24 @@ eOLDrawState tree_element_type_active(
* Needed to run from operators accessed from a menu.
*/
static void do_outliner_item_activate_tree_element(
- bContext *C, Scene *scene, SpaceOops *soops,
+ bContext *C, Scene *scene, ViewLayer *view_layer, SpaceOops *soops,
TreeElement *te, TreeStoreElem *tselem,
- bool extend, bool recursive)
+ const bool extend, const bool recursive)
{
- /* always makes active object, except for some specific types.
- * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want
- * to switch out of edit mode (see T48328 for details). */
- if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) {
+ /* Always makes active object, except for some specific types. */
+ if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE, TSE_LAYER_COLLECTION)) {
+ /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want
+ * to switch out of edit mode (see T48328 for details). */
+ }
+ else if (tselem->id && OB_DATA_SUPPORT_EDITMODE(te->idcode)) {
+ /* Support edit-mode toggle, keeping the active object as is. */
+ }
+ else if (tselem->type == TSE_POSE_BASE) {
+ /* Support pose mode toggle, keeping the active object as is. */
+ }
+ else {
tree_element_set_active_object(
- C, scene, soops, te,
+ C, scene, view_layer, soops, te,
(extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
recursive && tselem->type == 0);
}
@@ -920,100 +977,116 @@ static void do_outliner_item_activate_tree_element(
/* editmode? */
if (te->idcode == ID_SCE) {
if (scene != (Scene *)tselem->id) {
- ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id);
+ WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id);
}
}
else if (te->idcode == ID_GR) {
- Group *gr = (Group *)tselem->id;
- GroupObject *gob;
+ Collection *gr = (Collection *)tselem->id;
if (extend) {
int sel = BA_SELECT;
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (gob->ob->flag & SELECT) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(gr, object)
+ {
+ Base *base = BKE_view_layer_base_find(view_layer, object);
+ if (base && (base->flag & BASE_SELECTED)) {
sel = BA_DESELECT;
break;
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(gr, object)
+ {
+ Base *base = BKE_view_layer_base_find(view_layer, object);
+ if (base) {
+ ED_object_base_select(base, sel);
+ }
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
else {
- BKE_scene_base_deselect_all(scene);
-
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if ((gob->ob->flag & SELECT) == 0)
- ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_SELECT);
+ BKE_view_layer_base_deselect_all(view_layer);
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(gr, object)
+ {
+ Base *base = BKE_view_layer_base_find(view_layer, object);
+ /* Object may not be in this scene */
+ if (base != NULL) {
+ if ((base->flag & BASE_SELECTED) == 0) {
+ ED_object_base_select(base, BA_SELECT);
+ }
+ }
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) {
- WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
+ Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
+ if ((ob != NULL) && (ob->data == tselem->id)) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if ((base != NULL) && (base->flag & BASE_VISIBLE)) {
+ do_outliner_activate_obdata(C, scene, view_layer, base);
+ }
+ }
+ }
+ else if (ELEM(te->idcode, ID_GD)) {
+ /* set grease pencil to object mode */
+ WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
}
else { // rest of types
- tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, false);
+ tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false);
}
}
else {
- tree_element_type_active(
- C, scene, soops, te, tselem,
- extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
- recursive);
+ tree_element_type_active(C, scene, view_layer, soops, te, tselem,
+ extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
+ recursive);
}
}
/**
- * Activates tree items, also handles clicking on arrows.
+ * \param extend: Don't deselect other items, only modify \a te.
+ * \param toggle: Select \a te when not selected, deselect when selected.
*/
-static bool do_outliner_item_activate_from_cursor(
- bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, bool extend, bool recursive, const float mval[2])
+void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle)
{
- if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
- TreeStoreElem *tselem = TREESTORE(te);
- bool openclose = false;
-
- /* open close icon */
- if ((te->flag & TE_ICONROW) == 0) { // hidden icon, no open/close
- if (mval[0] > te->xs && mval[0] < te->xs + UI_UNIT_X)
- openclose = true;
- }
+ TreeStoreElem *tselem = TREESTORE(te);
+ const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED);
- if (openclose) {
- /* all below close/open? */
- if (extend) {
- tselem->flag &= ~TSE_CLOSED;
- outliner_flag_set(&te->subtree, TSE_CLOSED, !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1));
- }
- else {
- if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
- else tselem->flag |= TSE_CLOSED;
+ if (extend == false) {
+ outliner_flag_set(&soops->tree, TSE_SELECTED, false);
+ }
+ tselem->flag = new_flag;
+}
- }
+static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (toggle_children) {
+ tselem->flag &= ~TSE_CLOSED;
- return true;
- }
- /* name and first icon */
- else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) {
- do_outliner_item_activate_tree_element(
- C, scene, soops,
- te, tselem,
- extend, recursive);
- return true;
- }
+ const bool all_opened = !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1);
+ outliner_flag_set(&te->subtree, TSE_CLOSED, all_opened);
}
-
- for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_item_activate_from_cursor(C, scene, ar, soops, te, extend, recursive, mval)) {
- return true;
- }
+ else {
+ tselem->flag ^= TSE_CLOSED;
}
- return false;
+}
+
+static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
+{
+ return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
+}
+
+static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x)
+{
+ return ((soops->outlinevis != SO_DATA_API) &&
+ !(soops->flag & SO_HIDE_RESTRICTCOLS) &&
+ (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX));
}
/**
@@ -1027,10 +1100,11 @@ void outliner_item_do_activate_from_tree_element(
bool extend, bool recursive)
{
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
do_outliner_item_activate_tree_element(
- C, scene, soops,
+ C, scene, view_layer, soops,
te, tselem,
extend, recursive);
}
@@ -1044,56 +1118,53 @@ int outliner_item_do_activate_from_cursor(
bContext *C, const int mval[2],
bool extend, bool recursive)
{
- Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
TreeElement *te;
- float fmval[2];
+ float view_mval[2];
+ bool changed = false, rebuild_tree = false;
- UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fmval[0], &fmval[1]);
+ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
- if (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) &&
- !(soops->flag & SO_HIDE_RESTRICTCOLS) &&
- (fmval[0] > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX))
- {
+ if (outliner_is_co_within_restrict_columns(soops, ar, view_mval[0])) {
return OPERATOR_CANCELLED;
}
- for (te = soops->tree.first; te; te = te->next) {
- if (do_outliner_item_activate_from_cursor(C, scene, ar, soops, te, extend, recursive, fmval)) {
- break;
- }
+ if (!(te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]))) {
+ /* skip */
}
-
- if (te) {
- ED_undo_push(C, "Outliner click event");
+ else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
+ outliner_item_toggle_closed(te, extend);
+ changed = true;
+ rebuild_tree = true;
}
else {
- short selecting = -1;
- int row;
-
- /* get row number - 100 here is just a dummy value since we don't need the column */
- UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET,
- fmval[0], fmval[1], NULL, &row);
-
- /* select relevant row */
- if (outliner_select(soops, &soops->tree, &row, &selecting)) {
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ /* the row may also contain children, if one is hovered we want this instead of current te */
+ TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]);
+ TreeStoreElem *activate_tselem = TREESTORE(activate_te);
- soops->storeflag |= SO_TREESTORE_REDRAW;
+ outliner_item_select(soops, activate_te, extend, extend);
+ do_outliner_item_activate_tree_element(C, scene, view_layer, soops, activate_te, activate_tselem, extend, recursive);
+ changed = true;
+ }
- /* no need for undo push here, only changing outliner data which is
- * scene level - campbell */
- /* ED_undo_push(C, "Outliner selection event"); */
+ if (changed) {
+ if (rebuild_tree) {
+ ED_region_tag_redraw(ar);
+ }
+ else {
+ ED_region_tag_redraw_no_rebuild(ar);
}
+ ED_undo_push(C, "Outliner selection change");
}
- ED_region_tag_redraw(ar);
-
return OPERATOR_FINISHED;
}
/* event can enterkey, then it opens/closes */
-static int outliner_item_activate(bContext *C, wmOperator *op, const wmEvent *event)
+static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bool extend = RNA_boolean_get(op->ptr, "extend");
bool recursive = RNA_boolean_get(op->ptr, "recursive");
@@ -1102,11 +1173,11 @@ static int outliner_item_activate(bContext *C, wmOperator *op, const wmEvent *ev
void OUTLINER_OT_item_activate(wmOperatorType *ot)
{
- ot->name = "Activate Item";
+ ot->name = "Select";
ot->idname = "OUTLINER_OT_item_activate";
- ot->description = "Handle mouse clicks to activate/select items";
+ ot->description = "Handle mouse clicks to select and activate items";
- ot->invoke = outliner_item_activate;
+ ot->invoke = outliner_item_activate_invoke;
ot->poll = ED_operator_outliner_active;
@@ -1116,8 +1187,8 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
/* ****************************************************** */
-/* **************** Border Select Tool ****************** */
-static void outliner_item_border_select(Scene *scene, rctf *rectf, TreeElement *te, bool select)
+/* **************** Box Select Tool ****************** */
+static void outliner_item_box_select(Scene *scene, rctf *rectf, TreeElement *te, bool select)
{
TreeStoreElem *tselem = TREESTORE(te);
@@ -1133,12 +1204,12 @@ static void outliner_item_border_select(Scene *scene, rctf *rectf, TreeElement *
/* Look at its children. */
if ((tselem->flag & TSE_CLOSED) == 0) {
for (te = te->subtree.first; te; te = te->next) {
- outliner_item_border_select(scene, rectf, te, select);
+ outliner_item_box_select(scene, rectf, te, select);
}
}
}
-static int outliner_border_select_exec(bContext *C, wmOperator *op)
+static int outliner_box_select_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -1151,27 +1222,28 @@ static int outliner_border_select_exec(bContext *C, wmOperator *op)
UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
for (te = soops->tree.first; te; te = te->next) {
- outliner_item_border_select(scene, &rectf, te, select);
+ outliner_item_box_select(scene, &rectf, te, select);
}
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(ar);
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_select_border(wmOperatorType *ot)
+void OUTLINER_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "OUTLINER_OT_select_border";
+ ot->name = "Box Select";
+ ot->idname = "OUTLINER_OT_select_box";
ot->description = "Use box selection to select tree elements";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = outliner_border_select_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = outliner_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_outliner_active;
@@ -1179,7 +1251,7 @@ void OUTLINER_OT_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_ex(ot, true, false);
+ WM_operator_properties_gesture_box_ex(ot, true, false);
}
/* ****************************************************** */
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 9c21241cf7b..a9212a99eb8 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -33,8 +33,8 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
@@ -51,21 +51,27 @@
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_constraint.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
-#include "BKE_group.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_undo.h"
@@ -100,7 +106,8 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
- if (tselem->type) {
+ /* Layer collection points to collection ID. */
+ if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
if (*datalevel == 0)
*datalevel = tselem->type;
else if (*datalevel != tselem->type)
@@ -124,6 +131,9 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
case ID_LI:
if (*idlevel == 0) *idlevel = idcode;
else if (*idlevel != idcode) *idlevel = -1;
+ if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) {
+ *datalevel = 0;
+ }
break;
}
}
@@ -191,19 +201,7 @@ static void unlink_texture_cb(
MTex **mtex = NULL;
int a;
- if (GS(tsep->id->name) == ID_MA) {
- Material *ma = (Material *)tsep->id;
- mtex = ma->mtex;
- }
- else if (GS(tsep->id->name) == ID_LA) {
- Lamp *la = (Lamp *)tsep->id;
- mtex = la->mtex;
- }
- else if (GS(tsep->id->name) == ID_WO) {
- World *wrld = (World *)tsep->id;
- mtex = wrld->mtex;
- }
- else if (GS(tsep->id->name) == ID_LS) {
+ if (GS(tsep->id->name) == ID_LS) {
FreestyleLineStyle *ls = (FreestyleLineStyle *)tsep->id;
mtex = ls->mtex;
}
@@ -221,21 +219,59 @@ static void unlink_texture_cb(
}
}
-static void unlink_group_cb(
+static void unlink_collection_cb(
bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
- Group *group = (Group *)tselem->id;
+ Main *bmain = CTX_data_main(C);
+ Collection *collection = (Collection *)tselem->id;
if (tsep) {
if (GS(tsep->id->name) == ID_OB) {
Object *ob = (Object *)tsep->id;
ob->dup_group = NULL;
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_relations_tag_update(bmain);
+ }
+ else if (GS(tsep->id->name) == ID_GR) {
+ Collection *parent = (Collection *)tsep->id;
+ id_fake_user_set(&collection->id);
+ BKE_collection_child_remove(bmain, parent, collection);
+ DEG_id_tag_update(&parent->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ }
+ else if (GS(tsep->id->name) == ID_SCE) {
+ Scene *scene = (Scene *)tsep->id;
+ Collection *parent = BKE_collection_master(scene);
+ id_fake_user_set(&collection->id);
+ BKE_collection_child_remove(bmain, parent, collection);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
- else {
- Main *bmain = CTX_data_main(C);
- BKE_libblock_delete(bmain, group);
+}
+
+static void unlink_object_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = (Object *)tselem->id;
+
+ if (tsep) {
+ if (GS(tsep->id->name) == ID_GR) {
+ Collection *parent = (Collection *)tsep->id;
+ BKE_collection_object_remove(bmain, parent, ob, true);
+ DEG_id_tag_update(&parent->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ }
+ else if (GS(tsep->id->name) == ID_SCE) {
+ Scene *scene = (Scene *)tsep->id;
+ Collection *parent = BKE_collection_master(scene);
+ BKE_collection_object_remove(bmain, parent, ob, true);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ }
}
}
@@ -262,7 +298,7 @@ static void outliner_do_libdata_operation(
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
- if (tselem->type == 0) {
+ if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
operation_cb(C, reports, scene, te, tsep, tselem, user_data);
}
@@ -308,7 +344,7 @@ static bool scene_cb(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNU
Scene *scene = (Scene *)tselem->id;
if (event == OL_SCENE_OP_DELETE) {
- if (ED_screen_delete_scene(C, scene)) {
+ if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene)) {
WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
}
else {
@@ -359,15 +395,15 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
/* ******************************************** */
static void object_select_cb(
- bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- Base *base = (Base *)te->directdata;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = (Object *)tselem->id;
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
- if (base && ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0)) {
- base->flag |= SELECT;
- base->object->flag |= SELECT;
+ if (base && ((base->flag & BASE_VISIBLE) != 0)) {
+ base->flag |= BASE_SELECTED;
}
}
@@ -381,60 +417,49 @@ static void object_select_hierarchy_cb(
}
static void object_deselect_cb(
- bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te,
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- Base *base = (Base *)te->directdata;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = (Object *)tselem->id;
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
- if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
if (base) {
- base->flag &= ~SELECT;
- base->object->flag &= ~SELECT;
+ base->flag &= ~BASE_SELECTED;
}
}
static void object_delete_cb(
- bContext *C, ReportList *reports, Scene *scene, TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *tselem, void *user_data)
+ bContext *C, ReportList *reports, Scene *scene, TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- Base *base = (Base *)te->directdata;
-
- if (base == NULL)
- base = BKE_scene_base_find(scene, (Object *)tselem->id);
- if (base) {
+ Object *ob = (Object *)tselem->id;
+ if (ob) {
Main *bmain = CTX_data_main(C);
- if (base->object->id.tag & LIB_TAG_INDIRECT) {
- BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2);
+ if (ob->id.tag & LIB_TAG_INDIRECT) {
+ BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2);
return;
}
- else if (BKE_library_ID_is_indirectly_used(bmain, base->object) &&
- ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0)
+ else if (BKE_library_ID_is_indirectly_used(bmain, ob) &&
+ ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0)
{
BKE_reportf(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);
+ ob->id.name + 2, scene->id.name + 2);
return;
}
// check also library later
- if (scene->obedit == base->object) {
+ if (ob == CTX_data_edit_object(C)) {
ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
}
-
- ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob);
/* leave for ED_outliner_id_unref to handle */
#if 0
te->directdata = NULL;
tselem->id = NULL;
#endif
}
- else {
- /* No base, means object is no more instantiated in any scene.
- * Should not happen ideally, but does happens, see T51625.
- * Rather than twisting in all kind of ways to address all possible cases leading to that situation, simpler
- * to allow deleting such object as a mere generic data-block. */
- id_delete_cb(C, reports, scene, te, tsep, tselem, user_data);
- }
}
static void id_local_cb(
@@ -454,6 +479,19 @@ static void id_local_cb(
}
}
+static void id_static_override_cb(
+ bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ Main *bmain = CTX_data_main(C);
+ ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id);
+ if (override_id != NULL) {
+ BKE_main_id_clear_newpoins(bmain);
+ }
+ }
+}
+
static void id_fake_user_set_cb(
bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
@@ -518,38 +556,6 @@ static void singleuser_world_cb(
}
}
-static void group_linkobs2scene_cb(
- bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Group *group = (Group *)tselem->id;
- GroupObject *gob;
- Base *base;
-
- for (gob = group->gobject.first; gob; gob = gob->next) {
- base = BKE_scene_base_find(scene, gob->ob);
- if (!base) {
- /* link to scene */
- base = BKE_scene_base_add(scene, gob->ob);
- id_us_plus(&gob->ob->id);
- }
- base->object->flag |= SELECT;
- base->flag |= SELECT;
- }
-}
-
-static void group_instance_cb(
- bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
-{
- Group *group = (Group *)tselem->id;
-
- Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor, NULL, false, scene->layact);
- ob->dup_group = group;
- ob->transflag |= OB_DUPLIGROUP;
- id_lib_extern(&group->id);
-}
-
/**
* \param select_recurse: Set to false for operations which are already recursively operating on their children.
*/
@@ -567,7 +573,7 @@ void outliner_do_object_operation_ex(
// when objects selected in other scenes... dunno if that should be allowed
Scene *scene_owner = (Scene *)outliner_search_back(soops, te, ID_SCE);
if (scene_owner && scene_act != scene_owner) {
- ED_screen_set_scene(C, CTX_wm_screen(C), scene_owner);
+ WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner);
}
/* important to use 'scene_owner' not scene_act else deleting objects can crash.
* only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
@@ -790,12 +796,12 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
if (event == OL_MODIFIER_OP_TOGVIS) {
md->mode ^= eModifierMode_Realtime;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
else if (event == OL_MODIFIER_OP_TOGREN) {
md->mode ^= eModifierMode_Render;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
else if (event == OL_MODIFIER_OP_DELETE) {
@@ -829,12 +835,13 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s
{
Base *child_base, *base_next;
Object *parent;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
if (!base) {
return NULL;
}
- for (child_base = scene->base.first; child_base; child_base = base_next) {
+ for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) {
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
if (parent) {
@@ -857,7 +864,7 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s
base->object->id.name + 2, scene->id.name + 2);
return base_next;
}
- ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ ED_object_base_free_and_unlink(CTX_data_main(C), scene, base->object);
return base_next;
}
@@ -865,11 +872,12 @@ static void object_delete_hierarchy_cb(
bContext *C, ReportList *reports, Scene *scene,
TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Base *base = (Base *)te->directdata;
- Object *obedit = scene->obedit;
+ Object *obedit = CTX_data_edit_object(C);
if (!base) {
- base = BKE_scene_base_find(scene, (Object *)tselem->id);
+ base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id);
}
if (base) {
/* Check also library later. */
@@ -886,6 +894,7 @@ static void object_delete_hierarchy_cb(
#endif
}
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
@@ -903,6 +912,8 @@ enum {
OL_OP_TOGSEL,
OL_OP_TOGREN,
OL_OP_RENAME,
+ OL_OP_OBJECT_MODE_ENTER,
+ OL_OP_OBJECT_MODE_EXIT,
};
static const EnumPropertyItem prop_object_op_types[] = {
@@ -913,10 +924,9 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_REMAP, "REMAP", 0, "Remap Users",
"Make all users of selected data-blocks to use instead a new chosen one"},
- {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
- {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
- {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
+ {OL_OP_OBJECT_MODE_ENTER, "OBJECT_MODE_ENTER", 0, "Enter Mode", ""},
+ {OL_OP_OBJECT_MODE_EXIT, "OBJECT_MODE_EXIT", 0, "Exit Mode", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -924,6 +934,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ wmWindow *win = CTX_wm_window(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
int event;
const char *str = NULL;
@@ -938,24 +949,27 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
Scene *sce = scene; // to be able to delete, scenes are set...
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb);
if (scene != sce) {
- ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+ WM_window_set_active_scene(bmain, C, win, sce);
}
str = "Select Objects";
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_SELECT_HIERARCHY) {
Scene *sce = scene; // to be able to delete, scenes are set...
outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
if (scene != sce) {
- ED_screen_set_scene(C, CTX_wm_screen(C), sce);
+ WM_window_set_active_scene(bmain, C, win, sce);
}
str = "Select Object Hierarchy";
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_DESELECT) {
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb);
str = "Deselect Objects";
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
else if (event == OL_OP_DELETE) {
@@ -968,8 +982,9 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
* cleanup tree here to prevent such cases. */
outliner_cleanup_tree(soops);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
str = "Delete Objects";
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
else if (event == OL_OP_DELETE_HIERARCHY) {
@@ -978,8 +993,9 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
/* XXX: See OL_OP_DELETE comment above. */
outliner_cleanup_tree(soops);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
str = "Delete Object Hierarchy";
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
else if (event == OL_OP_REMAP) {
@@ -990,25 +1006,18 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
}
- else if (event == OL_OP_TOGVIS) {
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb);
- str = "Toggle Visibility";
- WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
- }
- else if (event == OL_OP_TOGSEL) {
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb);
- str = "Toggle Selectability";
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
- else if (event == OL_OP_TOGREN) {
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb);
- str = "Toggle Renderability";
- WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
- }
else if (event == OL_OP_RENAME) {
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb);
str = "Rename Object";
}
+ else if (event == OL_OP_OBJECT_MODE_ENTER) {
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_object_mode_enter_cb);
+ str = "Enter Current Mode";
+ }
+ else if (event == OL_OP_OBJECT_MODE_EXIT) {
+ outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_object_mode_exit_cb);
+ str = "Exit Current Mode";
+ }
else {
BLI_assert(0);
return OPERATOR_CANCELLED;
@@ -1038,113 +1047,12 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
/* **************************************** */
-typedef enum eOutliner_PropGroupOps {
- OL_GROUPOP_UNLINK = 1,
- OL_GROUPOP_LOCAL,
- OL_GROUPOP_LINK,
- OL_GROUPOP_DELETE,
- OL_GROUPOP_REMAP,
- OL_GROUPOP_INSTANCE,
- OL_GROUPOP_TOGVIS,
- OL_GROUPOP_TOGSEL,
- OL_GROUPOP_TOGREN,
- OL_GROUPOP_RENAME,
-} eOutliner_PropGroupOps;
-
-static const EnumPropertyItem prop_group_op_types[] = {
- {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""},
- {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""},
- {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""},
- {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", ""},
- {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users",
- "Make all users of selected data-blocks to use instead current (clicked) one"},
- {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
- {OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""},
- {OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
- {OL_GROUPOP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
- {OL_GROUPOP_RENAME, "RENAME", 0, "Rename", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static int outliner_group_operation_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- int event;
-
- /* check for invalid states */
- if (soops == NULL)
- return OPERATOR_CANCELLED;
-
- event = RNA_enum_get(op->ptr, "type");
-
- switch (event) {
- case OL_GROUPOP_UNLINK:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL);
- break;
- case OL_GROUPOP_LOCAL:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL);
- break;
- case OL_GROUPOP_LINK:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
- break;
- case OL_GROUPOP_INSTANCE:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL);
- /* works without this except if you try render right after, see: 22027 */
- DAG_relations_tag_update(CTX_data_main(C));
- break;
- case OL_GROUPOP_DELETE:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL);
- break;
- case OL_GROUPOP_REMAP:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
- break;
- case OL_GROUPOP_TOGVIS:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
- break;
- case OL_GROUPOP_TOGSEL:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
- break;
- case OL_GROUPOP_TOGREN:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
- break;
- case OL_GROUPOP_RENAME:
- outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
- break;
- default:
- BLI_assert(0);
- }
-
- ED_undo_push(C, prop_group_op_types[event - 1].name);
- WM_event_add_notifier(C, NC_GROUP, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-
-void OUTLINER_OT_group_operation(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Outliner Group Operation";
- ot->idname = "OUTLINER_OT_group_operation";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = outliner_group_operation_exec;
- ot->poll = ED_operator_outliner_active;
-
- ot->flag = 0;
-
- ot->prop = RNA_def_enum(ot->srna, "type", prop_group_op_types, 0, "Group Operation", "");
-}
-
-/* **************************************** */
-
typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_INVALID = 0,
OUTLINER_IDOP_UNLINK,
OUTLINER_IDOP_LOCAL,
+ OUTLINER_IDOP_STATIC_OVERRIDE,
OUTLINER_IDOP_SINGLE,
OUTLINER_IDOP_DELETE,
OUTLINER_IDOP_REMAP,
@@ -1160,6 +1068,8 @@ typedef enum eOutlinerIdOpTypes {
static const EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
{OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
+ {OUTLINER_IDOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", 0, "Add Static Override",
+ "Add a local static override of this data-block"},
{OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
{OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"},
{OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users",
@@ -1172,6 +1082,29 @@ static const EnumPropertyItem prop_id_op_types[] = {
{0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem *outliner_id_operation_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ if (BKE_override_static_is_enabled()) {
+ *r_free = false;
+ return prop_id_op_types;
+ }
+
+ EnumPropertyItem *items = NULL;
+ int totitem = 0;
+
+ for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) {
+ if (it->value == OUTLINER_IDOP_STATIC_OVERRIDE) {
+ continue;
+ }
+ RNA_enum_item_add(&items, &totitem, it);
+ }
+ RNA_enum_item_end(&items, &totitem);
+ *r_free = true;
+
+ return items;
+}
+
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1191,6 +1124,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_UNLINK:
{
/* unlink datablock from its parent */
+ if (objectlevel) {
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_object_cb, NULL);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+ ED_undo_push(C, "Unlink Object");
+ break;
+ }
+
switch (idlevel) {
case ID_AC:
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL);
@@ -1216,6 +1157,12 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Unlink world");
break;
+ case ID_GR:
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_collection_cb, NULL);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+ ED_undo_push(C, "Unlink Collection");
+ break;
default:
BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
break;
@@ -1229,6 +1176,15 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Localized Data");
break;
}
+ case OUTLINER_IDOP_STATIC_OVERRIDE:
+ {
+ if (BKE_override_static_is_enabled()) {
+ /* make local */
+ outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL);
+ ED_undo_push(C, "Overridden Data");
+ }
+ break;
+ }
case OUTLINER_IDOP_SINGLE:
{
/* make single user */
@@ -1330,6 +1286,7 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
ot->flag = 0;
ot->prop = RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID data Operation", "");
+ RNA_def_enum_funcs(ot->prop, outliner_id_operation_itemf);
}
/* **************************************** */
@@ -1626,7 +1583,7 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
/* update dependencies */
if (updateDeps) {
/* rebuild depsgraph for the new deps */
- DAG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(CTX_data_main(C));
}
return OPERATOR_FINISHED;
@@ -1652,8 +1609,8 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
/* **************************************** */
static const EnumPropertyItem prop_constraint_op_types[] = {
- {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_RESTRICT_VIEW_OFF, "Enable", ""},
- {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_RESTRICT_VIEW_ON, "Disable", ""},
+ {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
+ {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""},
{OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1839,6 +1796,26 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
/* ******************** */
+static int outliner_operator_menu(bContext *C, const char *opname)
+{
+ wmOperatorType *ot = WM_operatortype_find(opname, false);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(ot->srna), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ /* set this so the default execution context is the same as submenus */
+ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
+ uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop));
+
+ MenuType *mt = WM_menutype_find("OUTLINER_MT_context", false);
+ if (mt) {
+ uiItemS(layout);
+ UI_menutype_draw(C, mt, layout);
+ }
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soops,
TreeElement *te, const float mval[2])
@@ -1856,9 +1833,10 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
outliner_flag_set(&soops->tree, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
- /* redraw, same as outliner_select function */
- soops->storeflag |= SO_TREESTORE_REDRAW;
- ED_region_tag_redraw(ar);
+
+ /* Only redraw, don't rebuild here because TreeElement pointers will
+ * become invalid and operations will crash. */
+ ED_region_tag_redraw_no_rebuild(ar);
}
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
@@ -1866,28 +1844,32 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
if (scenelevel) {
if (objectlevel || datalevel || idlevel) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
+ return OPERATOR_CANCELLED;
}
else {
- WM_operator_name_call(C, "OUTLINER_OT_scene_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ return outliner_operator_menu(C, "OUTLINER_OT_scene_operation");
}
}
else if (objectlevel) {
- WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
+ return OPERATOR_FINISHED;
}
else if (idlevel) {
if (idlevel == -1 || datalevel) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
+ return OPERATOR_CANCELLED;
}
else {
switch (idlevel) {
case ID_GR:
- WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
+ return OPERATOR_FINISHED;
break;
case ID_LI:
- WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ return outliner_operator_menu(C, "OUTLINER_OT_lib_operation");
break;
default:
- WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ return outliner_operator_menu(C, "OUTLINER_OT_id_operation");
break;
}
}
@@ -1895,38 +1877,49 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
else if (datalevel) {
if (datalevel == -1) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
+ return OPERATOR_CANCELLED;
}
else {
- if (datalevel == TSE_ANIM_DATA)
- WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ if (datalevel == TSE_ANIM_DATA) {
+ return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation");
+ }
else if (datalevel == TSE_DRIVER_BASE) {
/* do nothing... no special ops needed yet */
+ return OPERATOR_CANCELLED;
}
- else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
- /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/
+ else if (datalevel == TSE_LAYER_COLLECTION) {
+ WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
+ return OPERATOR_FINISHED;
+ }
+ else if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
+ WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
+ return OPERATOR_FINISHED;
}
else if (datalevel == TSE_ID_BASE) {
/* do nothing... there are no ops needed here yet */
}
else if (datalevel == TSE_CONSTRAINT) {
- WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation");
}
else if (datalevel == TSE_MODIFIER) {
- WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation");
}
else {
- WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ return outliner_operator_menu(C, "OUTLINER_OT_data_operation");
}
}
}
- return 1;
+ return 0;
}
for (te = te->subtree.first; te; te = te->next) {
- if (do_outliner_operation_event(C, ar, soops, te, mval))
- return 1;
+ int retval = do_outliner_operation_event(C, ar, soops, te, mval);
+ if (retval) {
+ return retval;
+ }
}
+
return 0;
}
@@ -1946,18 +1939,26 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
for (te = soops->tree.first; te; te = te->next) {
- if (do_outliner_operation_event(C, ar, soops, te, fmval)) {
- break;
+ int retval = do_outliner_operation_event(C, ar, soops, te, fmval);
+ if (retval) {
+ return retval;
}
}
+ /* Menus for clicking in empty space. */
+ if (soops->outlinevis == SO_VIEW_LAYER) {
+ WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
+ return OPERATOR_FINISHED;
+ }
+
+ WM_menu_name_call(C, "OUTLINER_MT_context", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
}
/* Menu only! Calls other operators */
void OUTLINER_OT_operation(wmOperatorType *ot)
{
- ot->name = "Execute Operation";
+ ot->name = "Context Menu";
ot->idname = "OUTLINER_OT_operation";
ot->description = "Context menu for item operations";
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index ebd6904fa56..60467854e73 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -39,13 +39,14 @@
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
#include "DNA_cachefile_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
#include "DNA_world_types.h"
@@ -62,12 +63,16 @@
#include "BLT_translation.h"
#include "BKE_fcurve.h"
-#include "BKE_main.h"
+#include "BKE_idcode.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
-#include "BKE_sequencer.h"
-#include "BKE_idcode.h"
#include "BKE_outliner_treehash.h"
+#include "BKE_sequencer.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
#include "ED_screen.h"
@@ -77,12 +82,19 @@
#include "RNA_access.h"
+#include "UI_interface.h"
+
#include "outliner_intern.h"
#ifdef WIN32
# include "BLI_math_base.h" /* M_PI */
#endif
+/* prototypes */
+static TreeElement *outliner_add_collection_recursive(
+ SpaceOops *soops, Collection *collection, TreeElement *ten);
+static void outliner_make_object_parent_hierarchy(ListBase *lb);
+
/* ********************************************************* */
/* Persistent Data */
@@ -141,6 +153,9 @@ static void outliner_storage_cleanup(SpaceOops *soops)
}
}
}
+ else if (soops->treehash) {
+ BKE_outliner_treehash_clear_used(soops->treehash);
+ }
}
}
@@ -180,16 +195,11 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
/* ********************************************************* */
/* Tree Management */
-void outliner_free_tree(ListBase *lb)
+void outliner_free_tree(ListBase *tree)
{
- while (lb->first) {
- TreeElement *te = lb->first;
-
- outliner_free_tree(&te->subtree);
- BLI_remlink(lb, te);
-
- if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
- MEM_freeN(te);
+ for (TreeElement *element = tree->first, *element_next; element; element = element_next) {
+ element_next = element->next;
+ outliner_free_tree_element(element, tree);
}
}
@@ -199,103 +209,23 @@ void outliner_cleanup_tree(SpaceOops *soops)
outliner_storage_cleanup(soops);
}
-/* Find specific item from the treestore */
-TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
-{
- TreeElement *te, *tes;
- for (te = lb->first; te; te = te->next) {
- if (te->store_elem == store_elem) return te;
- tes = outliner_find_tree_element(&te->subtree, store_elem);
- if (tes) return tes;
- }
- return NULL;
-}
-
-/* tse is not in the treestore, we use its contents to find a match */
-TreeElement *outliner_find_tse(SpaceOops *soops, const TreeStoreElem *tse)
-{
- TreeStoreElem *tselem;
-
- if (tse->id == NULL) return NULL;
-
- /* check if 'tse' is in treestore */
- tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
- if (tselem)
- return outliner_find_tree_element(&soops->tree, tselem);
-
- return NULL;
-}
-
-/* Find treestore that refers to given ID */
-TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, const ID *id)
-{
- for (TreeElement *te = lb->first; te; te = te->next) {
- TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0) {
- if (tselem->id == id) {
- return te;
- }
- /* only deeper on scene or object */
- if (ELEM(te->idcode, ID_OB, ID_SCE) ||
- ((soops->outlinevis == SO_GROUPS) && (te->idcode == ID_GR)))
- {
- TreeElement *tes = outliner_find_id(soops, &te->subtree, id);
- if (tes) {
- return tes;
- }
- }
- }
- }
- return NULL;
-}
-
-TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
-{
- for (TreeElement *te = lb->first; te; te = te->next) {
- if (te->directdata == pchan) {
- return te;
- }
-
- TreeStoreElem *tselem = TREESTORE(te);
- if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) {
- TreeElement *tes = outliner_find_posechannel(&te->subtree, pchan);
- if (tes) {
- return tes;
- }
- }
- }
- return NULL;
-}
-
-TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
+/**
+ * Free \a element and its sub-tree and remove its link in \a parent_subtree.
+ *
+ * \note Does not remove the TreeStoreElem of \a element!
+ * \param parent_subtree Subtree of the parent element, so the list containing \a element.
+ */
+void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
- if (te->directdata == ebone) {
- return te;
- }
-
- TreeStoreElem *tselem = TREESTORE(te);
- if (ELEM(tselem->type, 0, TSE_EBONE)) {
- TreeElement *tes = outliner_find_editbone(&te->subtree, ebone);
- if (tes) {
- return tes;
- }
- }
- }
- return NULL;
-}
+ BLI_assert(BLI_findindex(parent_subtree, element) > -1);
+ BLI_remlink(parent_subtree, element);
-ID *outliner_search_back(SpaceOops *UNUSED(soops), TreeElement *te, short idcode)
-{
- TreeStoreElem *tselem;
- te = te->parent;
+ outliner_free_tree(&element->subtree);
- while (te) {
- tselem = TREESTORE(te);
- if (tselem->type == 0 && te->idcode == idcode) return tselem->id;
- te = te->parent;
+ if (element->flag & TE_FREE_NAME) {
+ MEM_freeN((void *)element->name);
}
- return NULL;
+ MEM_freeN(element);
}
@@ -322,98 +252,6 @@ static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curB
}
}
-/* -------------------------------------------------------- */
-
-#define LOG2I(x) (int)(log(x) / M_LN2)
-
-static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, SceneRenderLayer *srl)
-{
- TreeStoreElem *tselem = NULL;
- TreeElement *te = NULL;
-
- /* log stuff is to convert bitflags (powers of 2) to small integers,
- * in order to not overflow short tselem->nr */
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_COMBINED));
- te->name = IFACE_("Combined");
- te->directdata = &srl->passflag;
-
- /* save cpu cycles, but we add the first to invoke an open/close triangle */
- tselem = TREESTORE(tenla);
- if (tselem->flag & TSE_CLOSED)
- return;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_Z));
- te->name = IFACE_("Z");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_VECTOR));
- te->name = IFACE_("Vector");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_NORMAL));
- te->name = IFACE_("Normal");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_UV));
- te->name = IFACE_("UV");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_MIST));
- te->name = IFACE_("Mist");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXOB));
- te->name = IFACE_("Index Object");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDEXMA));
- te->name = IFACE_("Index Material");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_RGBA));
- te->name = IFACE_("Color");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_DIFFUSE));
- te->name = IFACE_("Diffuse");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SPEC));
- te->name = IFACE_("Specular");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_SHADOW));
- te->name = IFACE_("Shadow");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_AO));
- te->name = IFACE_("AO");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFLECT));
- te->name = IFACE_("Reflection");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_REFRACT));
- te->name = IFACE_("Refraction");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_INDIRECT));
- te->name = IFACE_("Indirect");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_ENVIRONMENT));
- te->name = IFACE_("Environment");
- te->directdata = &srl->passflag;
-
- te = outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, LOG2I(SCE_PASS_EMIT));
- te->name = IFACE_("Emit");
- te->directdata = &srl->passflag;
-}
-
-#undef LOG2I
-
static bool outliner_animdata_test(AnimData *adt)
{
if (adt)
@@ -424,19 +262,19 @@ static bool outliner_animdata_test(AnimData *adt)
#ifdef WITH_FREESTYLE
static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
{
- SceneRenderLayer *srl;
+ ViewLayer *view_layer;
FreestyleLineSet *lineset;
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
FreestyleLineStyle *linestyle = lineset->linestyle;
if (linestyle) {
linestyle->id.tag |= LIB_TAG_DOIT;
}
}
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
FreestyleLineStyle *linestyle = lineset->linestyle;
if (linestyle) {
if (!(linestyle->id.tag & LIB_TAG_DOIT))
@@ -451,36 +289,36 @@ static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce,
static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
{
- SceneRenderLayer *srl;
- TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
- int a;
+ /* View layers */
+ TreeElement *ten = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
+ ten->name = IFACE_("View Layers");
- tenla->name = IFACE_("RenderLayers");
- for (a = 0, srl = sce->r.layers.first; srl; srl = srl->next, a++) {
- TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a);
- tenlay->name = srl->name;
- tenlay->directdata = &srl->layflag;
+ ViewLayer *view_layer;
+ for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0);
+ tenlay->name = view_layer->name;
+ tenlay->directdata = view_layer;
+ }
- if (srl->light_override)
- outliner_add_element(soops, &tenlay->subtree, srl->light_override, tenlay, TSE_LINKED_LAMP, 0);
- if (srl->mat_override)
- outliner_add_element(soops, &tenlay->subtree, srl->mat_override, tenlay, TSE_LINKED_MAT, 0);
+ /* Collections */
+ ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0);
+ ten->name = IFACE_("Scene Collection");
+ outliner_add_collection_recursive(soops, sce->master_collection, ten);
- outliner_add_passes(soops, tenlay, &sce->id, srl);
+ /* Objects */
+ ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0);
+ ten->name = IFACE_("Objects");
+ FOREACH_SCENE_OBJECT_BEGIN(sce, ob)
+ {
+ outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0);
}
+ FOREACH_SCENE_OBJECT_END;
+ outliner_make_object_parent_hierarchy(&ten->subtree);
- // TODO: move this to the front?
+ /* Animation Data */
if (outliner_animdata_test(sce->adt))
outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0);
- outliner_add_element(soops, lb, sce->gpd, te, 0, 0);
-
- outliner_add_element(soops, lb, sce->world, te, 0, 0);
-
-#ifdef WITH_FREESTYLE
- if (STREQ(sce->r.engine, RE_engine_id_BLENDER_RENDER) && (sce->r.mode & R_EDGE_FRS))
- outliner_add_line_styles(soops, lb, sce, te);
-#endif
}
// can be inlined if necessary
@@ -719,14 +557,9 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
case ID_MA:
{
Material *ma = (Material *)id;
- int a;
if (outliner_animdata_test(ma->adt))
outliner_add_element(soops, &te->subtree, ma, te, TSE_ANIM_DATA, 0);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a);
- }
break;
}
case ID_TE:
@@ -760,14 +593,9 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
case ID_LA:
{
Lamp *la = (Lamp *)id;
- int a;
if (outliner_animdata_test(la->adt))
outliner_add_element(soops, &te->subtree, la, te, TSE_ANIM_DATA, 0);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a);
- }
break;
}
case ID_SPK:
@@ -778,17 +606,20 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
outliner_add_element(soops, &te->subtree, spk, te, TSE_ANIM_DATA, 0);
break;
}
+ case ID_LP:
+ {
+ LightProbe *prb = (LightProbe *)id;
+
+ if (outliner_animdata_test(prb->adt))
+ outliner_add_element(soops, &te->subtree, prb, te, TSE_ANIM_DATA, 0);
+ break;
+ }
case ID_WO:
{
World *wrld = (World *)id;
- int a;
if (outliner_animdata_test(wrld->adt))
outliner_add_element(soops, &te->subtree, wrld, te, TSE_ANIM_DATA, 0);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a);
- }
break;
}
case ID_KE:
@@ -882,6 +713,14 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
}
break;
}
+ case ID_GR:
+ {
+ /* Don't expand for instances, creates too many elements. */
+ if (!(te->parent && te->parent->idcode == ID_OB)) {
+ Collection *collection = (Collection *)id;
+ outliner_add_collection_recursive(soops, collection, te);
+ }
+ }
default:
break;
}
@@ -905,7 +744,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
id = TREESTORE(parent)->id;
}
- /* One exception */
+ /* exceptions */
if (type == TSE_ID_BASE) {
/* pass */
}
@@ -943,6 +782,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else if (type == TSE_GP_LAYER) {
/* pass */
}
+ else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
+ /* pass */
+ }
else if (type == TSE_ID_BASE) {
/* pass */
}
@@ -959,8 +801,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
/* ID datablock */
- if (tsepar == NULL || tsepar->type != TSE_ID_BASE)
+ if (tsepar == NULL || tsepar->type != TSE_ID_BASE || soops->filter_id_type) {
outliner_add_id_contents(soops, te, tselem, id);
+ }
}
else if (type == TSE_ANIM_DATA) {
IdAdtTemplate *iat = (IdAdtTemplate *)idv;
@@ -1306,16 +1149,56 @@ static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *t
/* ----------------------------------------------- */
+static const char *outliner_idcode_to_plural(short idcode)
+{
+ const char *propname = BKE_idcode_to_name_plural(idcode);
+ PropertyRNA *prop = RNA_struct_type_find_property(&RNA_BlendData, propname);
+ return (prop) ? RNA_property_ui_name(prop) : "UNKNOWN";
+}
-static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib)
+static bool outliner_library_id_show(Library *lib, ID *id, short filter_id_type)
{
- TreeElement *ten;
+ if (id->lib != lib) {
+ return false;
+ }
+
+ if (filter_id_type == ID_GR) {
+ /* Don't show child collections of non-scene master collection,
+ * they are already shown as children. */
+ Collection *collection = (Collection *)id;
+ bool has_non_scene_parent = false;
+
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) {
+ has_non_scene_parent = true;
+ }
+ }
+
+ if (has_non_scene_parent) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static TreeElement *outliner_add_library_contents(Main *mainvar, SpaceOops *soops, ListBase *lb, Library *lib)
+{
+ TreeElement *ten, *tenlib = NULL;
ListBase *lbarray[MAX_LIBARRAY];
int a, tot;
+ short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0;
+
+ if (filter_id_type) {
+ lbarray[0] = which_libbase(mainvar, soops->filter_id_type);
+ tot = 1;
+ }
+ else {
+ tot = set_listbasepointers(mainvar, lbarray);
+ }
- tot = set_listbasepointers(mainvar, lbarray);
for (a = 0; a < tot; a++) {
- if (lbarray[a]->first) {
+ if (lbarray[a] && lbarray[a]->first) {
ID *id = lbarray[a]->first;
/* check if there's data in current lib */
@@ -1324,21 +1207,37 @@ static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeE
break;
if (id) {
- ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
- ten->directdata = lbarray[a];
+ if (!tenlib) {
+ /* Create library tree element on demand, depending if there are any datablocks. */
+ if (lib) {
+ tenlib = outliner_add_element(soops, lb, lib, NULL, 0, 0);
+ }
+ else {
+ tenlib = outliner_add_element(soops, lb, mainvar, NULL, TSE_ID_BASE, 0);
+ tenlib->name = IFACE_("Current File");
+ }
+ }
- ten->name = BKE_idcode_to_name_plural(GS(id->name));
- if (ten->name == NULL)
- ten->name = "UNKNOWN";
+ /* Create datablock list parent element on demand. */
+ if (filter_id_type) {
+ ten = tenlib;
+ }
+ else {
+ ten = outliner_add_element(soops, &tenlib->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+ ten->name = outliner_idcode_to_plural(GS(id->name));
+ }
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->lib == lib)
+ if (outliner_library_id_show(lib, id, filter_id_type)) {
outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
+ }
}
}
}
}
+ return tenlib;
}
static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
@@ -1346,10 +1245,18 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
TreeElement *ten;
ListBase *lbarray[MAX_LIBARRAY];
int a, tot;
+ short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0;
+
+ if (filter_id_type) {
+ lbarray[0] = which_libbase(mainvar, soops->filter_id_type);
+ tot = 1;
+ }
+ else {
+ tot = set_listbasepointers(mainvar, lbarray);
+ }
- tot = set_listbasepointers(mainvar, lbarray);
for (a = 0; a < tot; a++) {
- if (lbarray[a]->first) {
+ if (lbarray[a] && lbarray[a]->first) {
ID *id = lbarray[a]->first;
/* check if there are any datablocks of this type which are orphans */
@@ -1360,34 +1267,119 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
if (id) {
/* header for this type of datablock */
- /* TODO's:
- * - Add a parameter to BKE_idcode_to_name_plural to get a sane "user-visible" name instead?
- * - Ensure that this uses nice icons for the datablock type involved instead of the dot?
- */
- ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
- ten->directdata = lbarray[a];
-
- ten->name = BKE_idcode_to_name_plural(GS(id->name));
- if (ten->name == NULL)
- ten->name = "UNKNOWN";
+ if (filter_id_type) {
+ ten = NULL;
+ }
+ else {
+ ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+ ten->name = outliner_idcode_to_plural(GS(id->name));
+ }
/* add the orphaned datablocks - these will not be added with any subtrees attached */
for (id = lbarray[a]->first; id; id = id->next) {
if (ID_REAL_USERS(id) <= 0)
- outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
+ outliner_add_element(soops, (ten) ? &ten->subtree : &soops->tree, id, ten, 0, 0);
}
}
}
}
}
+static void outliner_add_layer_collection_objects(
+ SpaceOops *soops, ListBase *tree, ViewLayer *layer,
+ LayerCollection *lc, TreeElement *ten)
+{
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(layer, cob->ob);
+ TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0);
+ te_object->directdata = base;
+
+ if (!(base->flag & BASE_VISIBLE)) {
+ te_object->flag |= TE_DISABLED;
+ }
+ }
+}
+
+static void outliner_add_layer_collections_recursive(
+ SpaceOops *soops, ListBase *tree, ViewLayer *layer,
+ ListBase *layer_collections, TreeElement *parent_ten,
+ const bool show_objects)
+{
+ for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) {
+ ID *id = &lc->collection->id;
+ TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0);
+
+ ten->name = id->name + 2;
+ ten->directdata = lc;
+
+ const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
+ if (exclude ||
+ ((layer->runtime_flag & VIEW_LAYER_HAS_HIDE) &&
+ !(lc->runtime_flag & LAYER_COLLECTION_HAS_VISIBLE_OBJECTS)))
+ {
+ ten->flag |= TE_DISABLED;
+ }
+
+ outliner_add_layer_collections_recursive(soops, &ten->subtree, layer, &lc->layer_collections, ten, show_objects);
+ if (!exclude && show_objects) {
+ outliner_add_layer_collection_objects(soops, &ten->subtree, layer, lc, ten);
+ }
+ }
+}
+
+static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElement *parent,
+ ViewLayer *layer, const bool show_objects)
+{
+ /* First layer collection is for master collection, don't show it. */
+ LayerCollection *lc = layer->layer_collections.first;
+ if (lc == NULL) {
+ return;
+ }
+
+ outliner_add_layer_collections_recursive(soops, tree, layer, &lc->layer_collections, parent, show_objects);
+ if (show_objects) {
+ outliner_add_layer_collection_objects(soops, tree, layer, lc, parent);
+ }
+}
+
+BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection)
+{
+ te->name = BKE_collection_ui_name_get(collection);
+ te->directdata = collection;
+}
+
+BLI_INLINE void outliner_add_collection_objects(
+ SpaceOops *soops, ListBase *tree, Collection *collection, TreeElement *parent)
+{
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ outliner_add_element(soops, tree, cob->ob, parent, 0, 0);
+ }
+}
+
+static TreeElement *outliner_add_collection_recursive(
+ SpaceOops *soops, Collection *collection, TreeElement *ten)
+{
+ outliner_add_collection_init(ten, collection);
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ outliner_add_element(soops, &ten->subtree, &child->collection->id, ten, 0, 0);
+ }
+
+ if (soops->outlinevis != SO_SCENES) {
+ outliner_add_collection_objects(soops, &ten->subtree, collection, ten);
+ }
+
+ return ten;
+}
+
/* ======================================================= */
/* Generic Tree Building helpers - order these are called is top to bottom */
/* Hierarchy --------------------------------------------- */
/* make sure elements are correctly nested */
-static void outliner_make_hierarchy(ListBase *lb)
+static void outliner_make_object_parent_hierarchy(ListBase *lb)
{
TreeElement *te, *ten, *tep;
TreeStoreElem *tselem;
@@ -1494,17 +1486,14 @@ static void outliner_sort(ListBase *lb)
{
TreeElement *te;
TreeStoreElem *tselem;
- int totelem = 0;
te = lb->last;
if (te == NULL) return;
tselem = TREESTORE(te);
/* sorting rules; only object lists, ID lists, or deformgroups */
- if ( ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) {
-
- /* count first */
- for (te = lb->first; te; te = te->next) totelem++;
+ if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) {
+ int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
@@ -1555,6 +1544,297 @@ static void outliner_sort(ListBase *lb)
/* Filtering ----------------------------------------------- */
+typedef struct OutlinerTreeElementFocus {
+ TreeStoreElem *tselem;
+ int ys;
+} OutlinerTreeElementFocus;
+
+/**
+ * Bring the outliner scrolling back to where it was in relation to the original focus element
+ * Caller is expected to handle redrawing of ARegion.
+ */
+static void outliner_restore_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus)
+{
+ View2D *v2d = &ar->v2d;
+ int ytop;
+
+ if (focus->tselem != NULL) {
+ outliner_set_coordinates(ar, soops);
+
+ TreeElement *te_new = outliner_find_tree_element(&soops->tree, focus->tselem);
+
+ if (te_new != NULL) {
+ int ys_new, ys_old;
+
+ ys_new = te_new->ys;
+ ys_old = focus->ys;
+
+ ytop = v2d->cur.ymax + (ys_new - ys_old) -1;
+ if (ytop > 0) ytop = 0;
+
+ v2d->cur.ymax = (float)ytop;
+ v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask));
+ }
+ else {
+ return;
+ }
+ }
+}
+
+static bool test_collection_callback(TreeElement *te)
+{
+ return outliner_is_collection_tree_element(te);
+}
+
+static bool test_object_callback(TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+ return ((tselem->type == 0) && (te->idcode == ID_OB));
+}
+
+/**
+ * See if TreeElement or any of its children pass the callback_test.
+ */
+static TreeElement *outliner_find_first_desired_element_at_y_recursive(
+ const SpaceOops *soops,
+ TreeElement *te,
+ const float limit,
+ bool (*callback_test)(TreeElement *))
+{
+ if (callback_test(te)) {
+ return te;
+ }
+
+ if (TSELEM_OPEN(te->store_elem, soops)) {
+ TreeElement *te_iter, *te_sub;
+ for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) {
+ te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te_iter, limit, callback_test);
+ if (te_sub != NULL) {
+ return te_sub;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Find the first element that passes a test starting from a reference vertical coordinate
+ *
+ * If the element that is in the position is not what we are looking for, keep looking for its
+ * children, siblings, and eventually, aunts, cousins, disntant families, ...
+ *
+ * Basically we keep going up and down the outliner tree from that point forward, until we find
+ * what we are looking for. If we are past the visible range and we can't find a valid element
+ * we return NULL.
+ */
+static TreeElement *outliner_find_first_desired_element_at_y(
+ const SpaceOops *soops,
+ const float view_co,
+ const float view_co_limit)
+{
+ TreeElement *te, *te_sub;
+ te = outliner_find_item_at_y(soops, &soops->tree, view_co);
+
+ bool (*callback_test)(TreeElement *);
+ if ((soops->outlinevis == SO_VIEW_LAYER) &&
+ (soops->filter & SO_FILTER_NO_COLLECTION))
+ {
+ callback_test = test_object_callback;
+ }
+ else {
+ callback_test = test_collection_callback;
+ }
+
+ while (te != NULL) {
+ te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test);
+ if (te_sub != NULL) {
+ /* Skip the element if it was not visible to start with. */
+ if (te->ys + UI_UNIT_Y > view_co_limit) {
+ return te_sub;
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ if (te->next) {
+ te = te->next;
+ continue;
+ }
+
+ if (te->parent == NULL) {
+ break;
+ }
+
+ while (te->parent) {
+ if (te->parent->next) {
+ te = te->parent->next;
+ break;
+ }
+ te = te->parent;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Store information of current outliner scrolling status to be restored later
+ *
+ * Finds the top-most collection visible in the outliner and populates the OutlinerTreeElementFocus
+ * struct to retrieve this element later to make sure it is in the same original position as before filtering
+ */
+static void outliner_store_scrolling_position(SpaceOops *soops, ARegion *ar, OutlinerTreeElementFocus *focus)
+{
+ TreeElement *te;
+ float limit = ar->v2d.cur.ymin;
+
+ outliner_set_coordinates(ar, soops);
+
+ te = outliner_find_first_desired_element_at_y(soops, ar->v2d.cur.ymax, limit);
+
+ if (te != NULL) {
+ focus->tselem = TREESTORE(te);
+ focus->ys = te->ys;
+ }
+ else {
+ focus->tselem = NULL;
+ }
+}
+
+static int outliner_exclude_filter_get(SpaceOops *soops)
+{
+ int exclude_filter = soops->filter & ~SO_FILTER_OB_STATE;
+
+ if (soops->search_string[0] != 0) {
+ exclude_filter |= SO_FILTER_SEARCH;
+ }
+ else {
+ exclude_filter &= ~SO_FILTER_SEARCH;
+ }
+
+ /* Let's have this for the collection options at first. */
+ if (!SUPPORT_FILTER_OUTLINER(soops)) {
+ return (exclude_filter & SO_FILTER_SEARCH);
+ }
+
+ if (soops->filter & SO_FILTER_NO_OBJECT) {
+ exclude_filter |= SO_FILTER_OB_TYPE;
+ }
+
+ switch (soops->filter_state) {
+ case SO_FILTER_OB_VISIBLE:
+ exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
+ break;
+ case SO_FILTER_OB_SELECTED:
+ exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
+ break;
+ case SO_FILTER_OB_ACTIVE:
+ exclude_filter |= SO_FILTER_OB_STATE_ACTIVE;
+ break;
+ }
+
+ return exclude_filter;
+}
+
+static bool outliner_element_visible_get(ViewLayer *view_layer, TreeElement *te, const int exclude_filter)
+{
+ if ((exclude_filter & SO_FILTER_ANY) == 0) {
+ return true;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+ if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) {
+ return false;
+ }
+
+ Object *ob = (Object *)tselem->id;
+ Base *base = (Base *)te->directdata;
+ BLI_assert((base == NULL) || (base->object == ob));
+
+ if (exclude_filter & SO_FILTER_OB_TYPE) {
+ switch (ob->type) {
+ case OB_MESH:
+ if (exclude_filter & SO_FILTER_NO_OB_MESH) {
+ return false;
+ }
+ break;
+ case OB_ARMATURE:
+ if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) {
+ return false;
+ }
+ break;
+ case OB_EMPTY:
+ if (exclude_filter & SO_FILTER_NO_OB_EMPTY) {
+ return false;
+ }
+ break;
+ case OB_LAMP:
+ if (exclude_filter & SO_FILTER_NO_OB_LAMP) {
+ return false;
+ }
+ break;
+ case OB_CAMERA:
+ if (exclude_filter & SO_FILTER_NO_OB_CAMERA) {
+ return false;
+ }
+ break;
+ default:
+ if (exclude_filter & SO_FILTER_NO_OB_OTHERS) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (exclude_filter & SO_FILTER_OB_STATE) {
+ if (base == NULL) {
+ base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (base == NULL) {
+ return false;
+ }
+ }
+
+ if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) {
+ if ((base->flag & BASE_VISIBLE) == 0) {
+ return false;
+ }
+ }
+ else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
+ if ((base->flag & BASE_SELECTED) == 0) {
+ return false;
+ }
+ }
+ else {
+ BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE);
+ if (base != BASACT(view_layer)) {
+ return false;
+ }
+ }
+ }
+
+ if ((te->parent != NULL) &&
+ (TREESTORE(te->parent)->type == 0) && (te->parent->idcode == ID_OB))
+ {
+ if (exclude_filter & SO_FILTER_NO_CHILDREN) {
+ return false;
+ }
+ }
+ }
+ else if (te->parent != NULL &&
+ TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB)
+ {
+ if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
{
int fn_flag = 0;
@@ -1565,30 +1845,24 @@ static bool outliner_filter_has_name(TreeElement *te, const char *name, int flag
return fnmatch(name, te->name, fn_flag) == 0;
}
-static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
+static int outliner_filter_subtree(
+ SpaceOops *soops, ViewLayer *view_layer, ListBase *lb, const char *search_string, const int exclude_filter)
{
- TreeElement *te, *ten;
+ TreeElement *te, *te_next;
TreeStoreElem *tselem;
- char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
- char *search_string;
- /* although we don't have any search string, we return true
- * since the entire tree is ok then...
- */
- if (soops->search_string[0] == 0)
- return 1;
+ for (te = lb->first; te; te = te_next) {
+ te_next = te->next;
- if (soops->search_flags & SO_FIND_COMPLETE) {
- search_string = soops->search_string;
- }
- else {
- /* Implicitly add heading/trailing wildcards if needed. */
- BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
- search_string = search_buff;
- }
-
- for (te = lb->first; te; te = ten) {
- ten = te->next;
+ if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
+ outliner_free_tree_element(te, lb);
+ continue;
+ }
+ else if ((exclude_filter & SO_FILTER_SEARCH) == 0) {
+ /* Filter subtree too. */
+ outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
+ continue;
+ }
if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
/* item isn't something we're looking for, but...
@@ -1602,12 +1876,10 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
/* flag as not a found item */
tselem->flag &= ~TSE_SEARCHMATCH;
- if ((!TSELEM_OPEN(tselem, soops)) || outliner_filter_tree(soops, &te->subtree) == 0) {
- outliner_free_tree(&te->subtree);
- BLI_remlink(lb, te);
-
- if (te->flag & TE_FREE_NAME) MEM_freeN((void *)te->name);
- MEM_freeN(te);
+ if ((!TSELEM_OPEN(tselem, soops)) ||
+ outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter) == 0)
+ {
+ outliner_free_tree_element(te, lb);
}
}
else {
@@ -1617,7 +1889,7 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
tselem->flag |= TSE_SEARCHMATCH;
/* filter subtree too */
- outliner_filter_tree(soops, &te->subtree);
+ outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter);
}
}
@@ -1625,14 +1897,36 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
return (BLI_listbase_is_empty(lb) == false);
}
+static void outliner_filter_tree(SpaceOops *soops, ViewLayer *view_layer)
+{
+ char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
+ char *search_string;
+
+ const int exclude_filter = outliner_exclude_filter_get(soops);
+
+ if (exclude_filter == 0) {
+ return;
+ }
+
+ if (soops->search_flags & SO_FIND_COMPLETE) {
+ search_string = soops->search_string;
+ }
+ else {
+ /* Implicitly add heading/trailing wildcards if needed. */
+ BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
+ search_string = search_buff;
+ }
+
+ outliner_filter_subtree(soops, view_layer, &soops->tree, search_string, exclude_filter);
+}
+
/* ======================================================= */
/* Main Tree Building API */
/* Main entry point for building the tree data-structure that the outliner represents */
// TODO: split each mode into its own function?
-void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
+void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, ARegion *ar)
{
- Base *base;
TreeElement *te = NULL, *ten;
TreeStoreElem *tselem;
int show_opened = !soops->treestore || !BLI_mempool_len(soops->treestore); /* on first view, we open scenes */
@@ -1640,18 +1934,22 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
/* Are we looking for something - we want to tag parents to filter child matches
* - NOT in datablocks view - searching all datablocks takes way too long to be useful
* - this variable is only set once per tree build */
- if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATABLOCKS)
+ if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATA_API)
soops->search_flags |= SO_SEARCH_RECURSIVE;
else
soops->search_flags &= ~SO_SEARCH_RECURSIVE;
- if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD)) {
+ if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD) && soops->treestore) {
soops->storeflag &= ~SO_TREESTORE_REBUILD;
BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
}
- if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
+ if (ar->do_draw & RGN_DRAW_NO_REBUILD) {
return;
+ }
+
+ OutlinerTreeElementFocus focus;
+ outliner_store_scrolling_position(soops, ar, &focus);
outliner_free_tree(&soops->tree);
outliner_storage_cleanup(soops);
@@ -1661,126 +1959,65 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
Library *lib;
/* current file first - mainvar provides tselem with unique pointer - not used */
- ten = outliner_add_element(soops, &soops->tree, mainvar, NULL, TSE_ID_BASE, 0);
- ten->name = IFACE_("Current File");
-
- tselem = TREESTORE(ten);
- if (!tselem->used)
- tselem->flag &= ~TSE_CLOSED;
-
- outliner_add_library_contents(mainvar, soops, ten, NULL);
+ ten = outliner_add_library_contents(mainvar, soops, &soops->tree, NULL);
+ if (ten) {
+ tselem = TREESTORE(ten);
+ if (!tselem->used)
+ tselem->flag &= ~TSE_CLOSED;
+ }
for (lib = mainvar->library.first; lib; lib = lib->id.next) {
- ten = outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0);
- lib->id.newid = (ID *)ten;
-
- outliner_add_library_contents(mainvar, soops, ten, lib);
+ ten = outliner_add_library_contents(mainvar, soops, &soops->tree, lib);
+ if (ten) {
+ lib->id.newid = (ID *)ten;
+ }
}
/* make hierarchy */
ten = soops->tree.first;
- ten = ten->next; /* first one is main */
- while (ten) {
- TreeElement *nten = ten->next, *par;
- tselem = TREESTORE(ten);
- lib = (Library *)tselem->id;
- if (lib && lib->parent) {
- par = (TreeElement *)lib->parent->id.newid;
- if (tselem->id->tag & LIB_TAG_INDIRECT) {
- /* Only remove from 'first level' if lib is not also directly used. */
- BLI_remlink(&soops->tree, ten);
- BLI_addtail(&par->subtree, ten);
- ten->parent = par;
- }
- else {
- /* Else, make a new copy of the libtree for our parent. */
- TreeElement *dupten = outliner_add_element(soops, &par->subtree, lib, NULL, 0, 0);
- outliner_add_library_contents(mainvar, soops, dupten, lib);
- dupten->parent = par;
+ if (ten != NULL) {
+ ten = ten->next; /* first one is main */
+ while (ten) {
+ TreeElement *nten = ten->next, *par;
+ tselem = TREESTORE(ten);
+ lib = (Library *)tselem->id;
+ if (lib && lib->parent) {
+ par = (TreeElement *)lib->parent->id.newid;
+ if (tselem->id->tag & LIB_TAG_INDIRECT) {
+ /* Only remove from 'first level' if lib is not also directly used. */
+ BLI_remlink(&soops->tree, ten);
+ BLI_addtail(&par->subtree, ten);
+ ten->parent = par;
+ }
+ else {
+ /* Else, make a new copy of the libtree for our parent. */
+ TreeElement *dupten = outliner_add_library_contents(mainvar, soops, &par->subtree, lib);
+ if (dupten) {
+ dupten->parent = par;
+ }
+ }
}
+ ten = nten;
}
- ten = nten;
}
/* restore newid pointers */
for (lib = mainvar->library.first; lib; lib = lib->id.next)
lib->id.newid = NULL;
}
- else if (soops->outlinevis == SO_ALL_SCENES) {
+ else if (soops->outlinevis == SO_SCENES) {
Scene *sce;
for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
tselem = TREESTORE(te);
- if (sce == scene && show_opened)
- tselem->flag &= ~TSE_CLOSED;
- for (base = sce->base.first; base; base = base->next) {
- ten = outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
- ten->directdata = base;
+ if (sce == scene && show_opened) {
+ tselem->flag &= ~TSE_CLOSED;
}
- outliner_make_hierarchy(&te->subtree);
- /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
- for (base = sce->base.first; base; base = base->next) base->object->id.newid = NULL;
- }
- }
- else if (soops->outlinevis == SO_CUR_SCENE) {
-
- outliner_add_scene_contents(soops, &soops->tree, scene, NULL);
-
- for (base = scene->base.first; base; base = base->next) {
- ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
- ten->directdata = base;
- }
- outliner_make_hierarchy(&soops->tree);
- }
- else if (soops->outlinevis == SO_VISIBLE) {
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & scene->lay)
- outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
- }
- outliner_make_hierarchy(&soops->tree);
- }
- else if (soops->outlinevis == SO_GROUPS) {
- Group *group;
- GroupObject *go;
-
- for (group = mainvar->group.first; group; group = group->id.next) {
- if (group->gobject.first) {
- te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
- for (go = group->gobject.first; go; go = go->next) {
- ten = outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
- ten->directdata = NULL; /* eh, why? */
- }
- outliner_make_hierarchy(&te->subtree);
- /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
- for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL;
- }
+ outliner_make_object_parent_hierarchy(&te->subtree);
}
}
- else if (soops->outlinevis == SO_SAME_TYPE) {
- Object *ob = OBACT;
- if (ob) {
- for (base = scene->base.first; base; base = base->next) {
- if (base->object->type == ob->type) {
- ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
- ten->directdata = base;
- }
- }
- outliner_make_hierarchy(&soops->tree);
- }
- }
- else if (soops->outlinevis == SO_SELECTED) {
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & scene->lay) {
- if (base->flag & SELECT) {
- ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
- ten->directdata = base;
- }
- }
- }
- outliner_make_hierarchy(&soops->tree);
- }
else if (soops->outlinevis == SO_SEQUENCE) {
Sequence *seq;
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -1805,7 +2042,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
seq = seq->next;
}
}
- else if (soops->outlinevis == SO_DATABLOCKS) {
+ else if (soops->outlinevis == SO_DATA_API) {
PointerRNA mainptr;
RNA_main_pointer_create(mainvar, &mainptr);
@@ -1817,30 +2054,36 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
tselem->flag &= ~TSE_CLOSED;
}
}
- else if (soops->outlinevis == SO_USERDEF) {
- PointerRNA userdefptr;
-
- RNA_pointer_create(NULL, &RNA_UserPreferences, &U, &userdefptr);
-
- ten = outliner_add_element(soops, &soops->tree, (void *)&userdefptr, NULL, TSE_RNA_STRUCT, -1);
-
- if (show_opened) {
- tselem = TREESTORE(ten);
- tselem->flag &= ~TSE_CLOSED;
- }
- }
else if (soops->outlinevis == SO_ID_ORPHANS) {
outliner_add_orphaned_datablocks(mainvar, soops);
}
- else {
- ten = outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
- if (ten) ten->directdata = BASACT;
+ else if (soops->outlinevis == SO_VIEW_LAYER) {
+ if (soops->filter & SO_FILTER_NO_COLLECTION) {
+ /* Show objects in the view layer. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
+ te_object->directdata = base;
+ }
+
+ outliner_make_object_parent_hierarchy(&soops->tree);
+ }
+ else {
+ /* Show collections in the view layer. */
+ ten = outliner_add_element(soops, &soops->tree, scene, NULL, TSE_VIEW_COLLECTION_BASE, 0);
+ ten->name = IFACE_("Scene Collection");
+ TREESTORE(ten)->flag &= ~TSE_CLOSED;
+
+ bool show_objects = !(soops->filter & SO_FILTER_NO_OBJECT);
+ outliner_add_view_layer(soops, &ten->subtree, ten, view_layer, show_objects);
+ }
}
if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) {
outliner_sort(&soops->tree);
}
- outliner_filter_tree(soops, &soops->tree);
+
+ outliner_filter_tree(soops, view_layer);
+ outliner_restore_scrolling_position(soops, ar, &focus);
BKE_main_id_clear_newpoins(mainvar);
}
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
new file mode 100644
index 00000000000..6b7035dd326
--- /dev/null
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -0,0 +1,246 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_outliner/outliner_utils.c
+ * \ingroup spoutliner
+ */
+
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_outliner_treehash.h"
+
+#include "ED_armature.h"
+
+#include "UI_interface.h"
+
+#include "outliner_intern.h"
+
+/**
+ * Try to find an item under y-coordinate \a view_co_y (view-space).
+ * \note Recursive
+ */
+TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y)
+{
+ for (TreeElement *te_iter = tree->first; te_iter; te_iter = te_iter->next) {
+ if (view_co_y < (te_iter->ys + UI_UNIT_Y)) {
+ if (view_co_y >= te_iter->ys) {
+ /* co_y is inside this element */
+ return te_iter;
+ }
+ else if (TSELEM_OPEN(te_iter->store_elem, soops)) {
+ /* co_y is lower than current element, possibly inside children */
+ TreeElement *te_sub = outliner_find_item_at_y(soops, &te_iter->subtree, view_co_y);
+ if (te_sub) {
+ return te_sub;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Collapsed items can show their children as click-able icons. This function tries to find
+ * such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
+ *
+ * \return a hovered child item or \a parent_te (if no hovered child found).
+ */
+TreeElement *outliner_find_item_at_x_in_row(const SpaceOops *soops, const TreeElement *parent_te, float view_co_x)
+{
+ if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) { /* if parent_te is opened, it doesn't show childs in row */
+ /* no recursion, items can only display their direct children in the row */
+ for (TreeElement *child_te = parent_te->subtree.first;
+ child_te && view_co_x >= child_te->xs; /* don't look further if co_x is smaller than child position*/
+ child_te = child_te->next)
+ {
+ if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) && (view_co_x < child_te->xend)) {
+ return child_te;
+ }
+ }
+ }
+
+ /* return parent if no child is hovered */
+ return (TreeElement *)parent_te;
+}
+
+/* Find specific item from the treestore */
+TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
+{
+ TreeElement *te, *tes;
+ for (te = lb->first; te; te = te->next) {
+ if (te->store_elem == store_elem) return te;
+ tes = outliner_find_tree_element(&te->subtree, store_elem);
+ if (tes) return tes;
+ }
+ return NULL;
+}
+
+/* Find parent element of te */
+TreeElement *outliner_find_parent_element(ListBase *lb, TreeElement *parent_te, const TreeElement *child_te)
+{
+ TreeElement *te;
+ for (te = lb->first; te; te = te->next) {
+ if (te == child_te) {
+ return parent_te;
+ }
+
+ TreeElement *find_te = outliner_find_parent_element(&te->subtree, te, child_te);
+ if (find_te) {
+ return find_te;
+ }
+ }
+ return NULL;
+}
+
+/* tse is not in the treestore, we use its contents to find a match */
+TreeElement *outliner_find_tse(SpaceOops *soops, const TreeStoreElem *tse)
+{
+ TreeStoreElem *tselem;
+
+ if (tse->id == NULL) return NULL;
+
+ /* check if 'tse' is in treestore */
+ tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
+ if (tselem)
+ return outliner_find_tree_element(&soops->tree, tselem);
+
+ return NULL;
+}
+
+/* Find treestore that refers to given ID */
+TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, const ID *id)
+{
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (tselem->type == 0) {
+ if (tselem->id == id) {
+ return te;
+ }
+ }
+
+ TreeElement *tes = outliner_find_id(soops, &te->subtree, id);
+ if (tes) {
+ return tes;
+ }
+ }
+ return NULL;
+}
+
+TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
+{
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ if (te->directdata == pchan) {
+ return te;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) {
+ TreeElement *tes = outliner_find_posechannel(&te->subtree, pchan);
+ if (tes) {
+ return tes;
+ }
+ }
+ }
+ return NULL;
+}
+
+TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
+{
+ for (TreeElement *te = lb->first; te; te = te->next) {
+ if (te->directdata == ebone) {
+ return te;
+ }
+
+ TreeStoreElem *tselem = TREESTORE(te);
+ if (ELEM(tselem->type, 0, TSE_EBONE)) {
+ TreeElement *tes = outliner_find_editbone(&te->subtree, ebone);
+ if (tes) {
+ return tes;
+ }
+ }
+ }
+ return NULL;
+}
+
+ID *outliner_search_back(SpaceOops *UNUSED(soops), TreeElement *te, short idcode)
+{
+ TreeStoreElem *tselem;
+ te = te->parent;
+
+ while (te) {
+ tselem = TREESTORE(te);
+ if (tselem->type == 0 && te->idcode == idcode) return tselem->id;
+ te = te->parent;
+ }
+ return NULL;
+}
+
+/**
+ * Iterate over all tree elements (pre-order traversal), executing \a func callback for
+ * each tree element matching the optional filters.
+ *
+ * \param filter_te_flag: If not 0, only TreeElements with this flag will be visited.
+ * \param filter_tselem_flag: Same as \a filter_te_flag, but for the TreeStoreElem.
+ * \param func: Custom callback to execute for each visited item.
+ */
+bool outliner_tree_traverse(const SpaceOops *soops, ListBase *tree, int filter_te_flag, int filter_tselem_flag,
+ TreeTraversalFunc func, void *customdata)
+{
+ for (TreeElement *te = tree->first, *te_next; te; te = te_next) {
+ TreeTraversalAction func_retval = TRAVERSE_CONTINUE;
+ /* in case te is freed in callback */
+ TreeStoreElem *tselem = TREESTORE(te);
+ ListBase subtree = te->subtree;
+ te_next = te->next;
+
+ if (filter_te_flag && (te->flag & filter_te_flag) == 0) {
+ /* skip */
+ }
+ else if (filter_tselem_flag && (tselem->flag & filter_tselem_flag) == 0) {
+ /* skip */
+ }
+ else {
+ func_retval = func(te, customdata);
+ }
+ /* Don't access te or tselem from now on! Might've been freed... */
+
+ if (func_retval == TRAVERSE_BREAK) {
+ return false;
+ }
+
+ if (func_retval == TRAVERSE_SKIP_CHILDS) {
+ /* skip */
+ }
+ else if (!outliner_tree_traverse(soops, &subtree, filter_te_flag, filter_tselem_flag, func, customdata)) {
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index c1039927810..57b13749f2b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -39,6 +39,7 @@
#include "BLI_mempool.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
#include "BKE_outliner_treehash.h"
@@ -47,6 +48,7 @@
#include "ED_screen.h"
#include "WM_api.h"
+#include "WM_message.h"
#include "WM_types.h"
#include "BIF_gl.h"
@@ -61,6 +63,7 @@
#include "outliner_intern.h"
+#include "GPU_framebuffer.h"
static void outliner_main_region_init(wmWindowManager *wm, ARegion *ar)
{
@@ -90,182 +93,6 @@ static void outliner_main_region_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_dropbox_handler(&ar->handlers, lb);
}
-static bool outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
-{
- ARegion *ar = CTX_wm_region(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- float fmval[2];
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_OB) {
- /* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, true);
-
- if (te && te->idcode == ID_OB && TREESTORE(te)->type == 0) {
- Scene *scene;
- ID *te_id = TREESTORE(te)->id;
-
- /* check if dropping self or parent */
- if (te_id == id || (Object *)te_id == ((Object *)id)->parent)
- return 0;
-
- /* check that parent/child are both in the same scene */
- scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
-
- /* currently outliner organized in a way that if there's no parent scene
- * element for object it means that all displayed objects belong to
- * active scene and parenting them is allowed (sergey)
- */
- if (!scene || BKE_scene_base_find(scene, (Object *)id)) {
- return 1;
- }
- }
- }
- }
- return 0;
-}
-
-static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop)
-{
- ID *id = drag->poin;
-
- RNA_string_set(drop->ptr, "child", id->name + 2);
-}
-
-static bool outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event)
-{
- ARegion *ar = CTX_wm_region(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- TreeElement *te = NULL;
- float fmval[2];
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) {
- return false;
- }
-
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_OB) {
- if (((Object *)id)->parent) {
- if ((te = outliner_dropzone_find(soops, fmval, true))) {
- TreeStoreElem *tselem = TREESTORE(te);
-
- switch (te->idcode) {
- case ID_SCE:
- return (ELEM(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS));
- case ID_OB:
- return (ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE));
- /* Other codes to ignore? */
- }
- }
- return (te == NULL);
- }
- }
- }
- return 0;
-}
-
-static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop)
-{
- ID *id = drag->poin;
- RNA_string_set(drop->ptr, "dragged_obj", id->name + 2);
-
- /* Set to simple parent clear type. Avoid menus for drag and drop if possible.
- * If desired, user can toggle the different "Clear Parent" types in the operator
- * menu on tool shelf. */
- RNA_enum_set(drop->ptr, "type", 0);
-}
-
-static bool outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
-{
- ARegion *ar = CTX_wm_region(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- float fmval[2];
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_OB) {
- /* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, false);
- return (te && te->idcode == ID_SCE && TREESTORE(te)->type == 0);
- }
- }
- return 0;
-}
-
-static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop)
-{
- ID *id = drag->poin;
-
- RNA_string_set(drop->ptr, "object", id->name + 2);
-}
-
-static bool outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
-{
- ARegion *ar = CTX_wm_region(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- float fmval[2];
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_MA) {
- /* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, true);
- return (te && te->idcode == ID_OB && TREESTORE(te)->type == 0);
- }
- }
- return 0;
-}
-
-static void outliner_material_drop_copy(wmDrag *drag, wmDropBox *drop)
-{
- ID *id = drag->poin;
-
- RNA_string_set(drop->ptr, "material", id->name + 2);
-}
-
-static bool outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *event)
-{
- ARegion *ar = CTX_wm_region(C);
- SpaceOops *soops = CTX_wm_space_outliner(C);
- float fmval[2];
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
-
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_OB) {
- /* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, true);
- return (te && te->idcode == ID_GR && TREESTORE(te)->type == 0);
- }
- }
- return 0;
-}
-
-static void outliner_group_link_copy(wmDrag *drag, wmDropBox *drop)
-{
- ID *id = drag->poin;
- RNA_string_set(drop->ptr, "object", id->name + 2);
-}
-
-/* region dropbox definition */
-static void outliner_dropboxes(void)
-{
- ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
-
- WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", outliner_parent_drop_poll, outliner_parent_drop_copy);
- WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy);
- WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy);
- WM_dropbox_add(lb, "OUTLINER_OT_material_drop", outliner_material_drop_poll, outliner_material_drop_copy);
- WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy);
-}
-
static void outliner_main_region_draw(const bContext *C, ARegion *ar)
{
View2D *v2d = &ar->v2d;
@@ -273,7 +100,7 @@ static void outliner_main_region_draw(const bContext *C, ARegion *ar)
/* clear */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
draw_outliner(C);
@@ -281,7 +108,7 @@ static void outliner_main_region_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@@ -292,7 +119,9 @@ static void outliner_main_region_free(ARegion *UNUSED(ar))
}
-static void outliner_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void outliner_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -308,7 +137,9 @@ static void outliner_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s
case ND_RENDER_OPTIONS:
case ND_SEQUENCER:
case ND_LAYER:
+ case ND_LAYER_CONTENT:
case ND_WORLD:
+ case ND_SCENEBROWSE:
ED_region_tag_redraw(ar);
break;
}
@@ -392,10 +223,33 @@ static void outliner_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
ED_region_tag_redraw(ar);
break;
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
+static void outliner_main_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ SpaceOops *soops = sa->spacedata.first;
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_SCENES)) {
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
+ }
+}
+
/* ************************ header outliner area region *********************** */
@@ -414,7 +268,9 @@ static void outliner_header_region_free(ARegion *UNUSED(ar))
{
}
-static void outliner_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void outliner_header_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -431,20 +287,21 @@ static void outliner_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
/* ******************** default callbacks for outliner space ***************** */
-static SpaceLink *outliner_new(const bContext *UNUSED(C))
+static SpaceLink *outliner_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceOops *soutliner;
soutliner = MEM_callocN(sizeof(SpaceOops), "initoutliner");
soutliner->spacetype = SPACE_OUTLINER;
+ soutliner->filter_id_type = ID_GR;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for outliner");
BLI_addtail(&soutliner->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for outliner");
@@ -547,6 +404,7 @@ void ED_spacetype_outliner(void)
art->draw = outliner_main_region_draw;
art->free = outliner_main_region_free;
art->listener = outliner_main_region_listener;
+ art->message_subscribe = outliner_main_region_message_subscribe;
BLI_addhead(&st->regiontypes, art);
/* regions: header */
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 5a761d1cabf..ee8dcf0ca9a 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -145,23 +145,3 @@ void SCRIPT_OT_reload(wmOperatorType *ot)
/* api callbacks */
ot->exec = script_reload_exec;
}
-
-static int script_autoexec_warn_clear_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
-{
- G.f |= G_SCRIPT_AUTOEXEC_FAIL_QUIET;
- return OPERATOR_FINISHED;
-}
-
-void SCRIPT_OT_autoexec_warn_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Continue Untrusted";
- ot->description = "Ignore autoexec warning";
- ot->idname = "SCRIPT_OT_autoexec_warn_clear";
-
- /* flags */
- ot->flag = OPTYPE_INTERNAL;
-
- /* api callbacks */
- ot->exec = script_autoexec_warn_clear_exec;
-}
diff --git a/source/blender/editors/space_script/script_intern.h b/source/blender/editors/space_script/script_intern.h
index 0e0936cf082..649992fec4f 100644
--- a/source/blender/editors/space_script/script_intern.h
+++ b/source/blender/editors/space_script/script_intern.h
@@ -40,6 +40,5 @@ void script_keymap(struct wmKeyConfig *keyconf);
/* script_edit.c */
void SCRIPT_OT_reload(struct wmOperatorType *ot);
void SCRIPT_OT_python_file_run(struct wmOperatorType *ot);
-void SCRIPT_OT_autoexec_warn_clear(struct wmOperatorType *ot);
#endif /* __SCRIPT_INTERN_H__ */
diff --git a/source/blender/editors/space_script/script_ops.c b/source/blender/editors/space_script/script_ops.c
index 41c07596a3b..90eb38db7f7 100644
--- a/source/blender/editors/space_script/script_ops.c
+++ b/source/blender/editors/space_script/script_ops.c
@@ -44,7 +44,6 @@ void script_operatortypes(void)
{
WM_operatortype_append(SCRIPT_OT_python_file_run);
WM_operatortype_append(SCRIPT_OT_reload);
- WM_operatortype_append(SCRIPT_OT_autoexec_warn_clear);
}
void script_keymap(wmKeyConfig *UNUSED(keyconf))
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index 2adfcc521f5..65c489e8409 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -55,6 +55,7 @@
#endif
#include "script_intern.h" // own include
+#include "GPU_framebuffer.h"
//static script_run_python(char *funcname, )
@@ -62,7 +63,7 @@
/* ******************** default callbacks for script space ***************** */
-static SpaceLink *script_new(const bContext *UNUSED(C))
+static SpaceLink *script_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceScript *sscript;
@@ -76,7 +77,7 @@ static SpaceLink *script_new(const bContext *UNUSED(C))
BLI_addtail(&sscript->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for script");
@@ -144,7 +145,7 @@ static void script_main_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -176,7 +177,9 @@ static void script_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-static void script_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void script_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
/* context changes */
// XXX - Todo, need the ScriptSpace accessible to get the python script to run.
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index 6dce962ee02..6b8108a1265 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -54,7 +54,7 @@ set(SRC
)
if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+ add_definitions(-DWITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 386e66a63e0..a9ae158d162 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -48,10 +48,10 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_sequencer.h"
-#include "BKE_movieclip.h"
#include "BKE_mask.h"
+#include "BKE_movieclip.h"
#include "BKE_report.h"
+#include "BKE_sequencer.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -69,7 +69,7 @@
#include "BKE_sound.h"
#ifdef WITH_AUDASPACE
-# include AUD_SEQUENCE_H
+# include <AUD_Sequence.h>
#endif
/* own include */
@@ -693,7 +693,7 @@ static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
- uiDefAutoButsRNA(layout, &ptr, sequencer_add_draw_check_prop, NULL, '\0');
+ uiDefAutoButsRNA(layout, &ptr, sequencer_add_draw_check_prop, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* image template */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
@@ -879,6 +879,8 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
strip = seq->strip;
se = strip->stripdata;
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+
if (use_placeholders) {
sequencer_image_seq_reserve_frames(op, se, seq_load.len, minframe, numdigits);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 915e2466d54..d91ade75807 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -56,11 +56,13 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
-#include "GPU_basic_shader.h"
-#include "GPU_compositing.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+#include "GPU_framebuffer.h"
#include "ED_anim_api.h"
#include "ED_gpencil.h"
@@ -194,18 +196,24 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
}
}
-static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequence *seq, float x1, float y1, float x2, float y2, float stepsize)
+static void drawseqwave(View2D *v2d, const bContext *C, SpaceSeq *sseq, Scene *scene, Sequence *seq,
+ float x1, float y1, float x2, float y2, float stepsize, unsigned int pos)
{
/*
* x1 is the starting x value to draw the wave,
* x2 the end x value, same for y1 and y2
* stepsize is width of a pixel.
*/
+
+ /* offset x1 and x2 values, to match view min/max, if strip is out of bounds */
+ int x1_offset = max_ff(v2d->cur.xmin, x1);
+ int x2_offset = min_ff(v2d->cur.xmax + 1.0f, x2);
+
if (seq->sound && ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) {
- int i, j, pos;
- int length = floor((x2 - x1) / stepsize) + 1;
- float ymid = (y1 + y2) / 2;
- float yscale = (y2 - y1) / 2;
+ int i, j, p;
+ int length = floor((x2_offset - x1_offset) / stepsize) + 1;
+ float ymid = (y1 + y2) / 2.0f;
+ float yscale = (y2 - y1) / 2.0f;
float samplestep;
float startsample, endsample;
float value1, value2;
@@ -213,6 +221,10 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc
SoundWaveform *waveform;
+ if (length < 2) {
+ return;
+ }
+
if (!sound->spinlock) {
sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
BLI_spin_init(sound->spinlock);
@@ -245,21 +257,27 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc
endsample = ceil((seq->startofs + seq->anim_startofs + seq->enddisp - seq->startdisp) / FPS * SOUND_WAVE_SAMPLES_PER_SECOND);
samplestep = (endsample - startsample) * stepsize / (x2 - x1);
- if (length > floor((waveform->length - startsample) / samplestep))
- length = floor((waveform->length - startsample) / samplestep);
+ length = min_ii(floor((waveform->length - startsample) / samplestep), length);
+
+ if (length < 2) {
+ return;
+ }
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.5f);
+
+ GPU_blend(true);
+
+ immBegin(GPU_PRIM_TRI_STRIP, length * 2);
- glColor4f(1.0f, 1.0f, 1.0f, 0.5);
- glEnable(GL_BLEND);
- glBegin(GL_TRIANGLE_STRIP);
for (i = 0; i < length; i++) {
- float sampleoffset = startsample + i * samplestep;
- pos = sampleoffset;
+ float sampleoffset = startsample + ((x1_offset - x1) / stepsize + i) * samplestep;
+ p = sampleoffset;
- value1 = waveform->data[pos * 3];
- value2 = waveform->data[pos * 3 + 1];
+ value1 = waveform->data[p * 3];
+ value2 = waveform->data[p * 3 + 1];
if (samplestep > 1.0f) {
- for (j = pos + 1; (j < waveform->length) && (j < pos + samplestep); j++) {
+ for (j = p + 1; (j < waveform->length) && (j < p + samplestep); j++) {
if (value1 > waveform->data[j * 3])
value1 = waveform->data[j * 3];
@@ -269,34 +287,20 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc
}
else {
/* use simple linear interpolation */
- float f = sampleoffset - pos;
- value1 = (1.0f - f) * value1 + f * waveform->data[pos * 3 + 3];
- value2 = (1.0f - f) * value2 + f * waveform->data[pos * 3 + 4];
+ float f = sampleoffset - p;
+ value1 = (1.0f - f) * value1 + f * waveform->data[p * 3 + 3];
+ value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4];
}
- glVertex2f(x1 + i * stepsize, ymid + value1 * yscale);
- glVertex2f(x1 + i * stepsize, ymid + value2 * yscale);
+ immVertex2f(pos, x1_offset + i * stepsize, ymid + value1 * yscale);
+ immVertex2f(pos, x1_offset + i * stepsize, ymid + value2 * yscale);
}
- glEnd();
- glDisable(GL_BLEND);
- }
-}
-static void drawmeta_stipple(int value)
-{
- if (value) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_HALFTONE);
+ immEnd();
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0x8888);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glDisable(GL_LINE_STIPPLE);
+ GPU_blend(false);
}
}
-
static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2)
{
/* note: this used to use SEQ_BEGIN/SEQ_END, but it messes up the
@@ -326,11 +330,8 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
offset = 0;
}
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- if (seqm->flag & SEQ_MUTE)
- drawmeta_stipple(1);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
for (seq = seqbase->first; seq; seq = seq->next) {
chan_min = min_ii(chan_min, seq->machine);
@@ -342,6 +343,10 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
col[3] = 196; /* alpha, used for all meta children */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
for (seq = seqbase->first; seq; seq = seq->next) {
const int startdisp = seq->startdisp + offset;
const int enddisp = seq->enddisp + offset;
@@ -352,12 +357,16 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
float x2_chan = enddisp;
float y1_chan, y2_chan;
- if ((seqm->flag & SEQ_MUTE) == 0 && (seq->flag & SEQ_MUTE))
- drawmeta_stipple(1);
-
color3ubv_from_seq(scene, seq, col);
- glColor4ubv(col);
+ if ((seqm->flag & SEQ_MUTE) || (seq->flag & SEQ_MUTE)) {
+ col[3] = 64;
+ }
+ else {
+ col[3] = 196;
+ }
+
+ immUniformColor4ubv(col);
/* clamp within parent sequence strip bounds */
if (x1_chan < x1) x1_chan = x1;
@@ -366,21 +375,13 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
y1_chan = y1 + y_chan + (draw_height * SEQ_STRIP_OFSBOTTOM);
y2_chan = y1 + y_chan + (draw_height * SEQ_STRIP_OFSTOP);
- glRectf(x1_chan, y1_chan, x2_chan, y2_chan);
-
- UI_GetColorPtrShade3ubv(col, col, -30);
- glColor4ubv(col);
- fdrawbox(x1_chan, y1_chan, x2_chan, y2_chan);
-
- if ((seqm->flag & SEQ_MUTE) == 0 && (seq->flag & SEQ_MUTE))
- drawmeta_stipple(0);
+ immRectf(pos, x1_chan, y1_chan, x2_chan, y2_chan);
}
}
- if (seqm->flag & SEQ_MUTE)
- drawmeta_stipple(0);
+ immUnbindProgram();
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
/* clamp handles to defined size in pixel space */
@@ -395,7 +396,7 @@ static float draw_seq_handle_size_get_clamped(Sequence *seq, const float pixelx)
}
/* draw a handle, for each end of a sequence strip */
-static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_clamped, const short direction)
+static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_clamped, const short direction, unsigned int pos)
{
float v1[2], v2[2], v3[2], rx1 = 0, rx2 = 0; //for triangles and rect
float x1, x2, y1, y2;
@@ -433,26 +434,36 @@ static void draw_seq_handle(View2D *v2d, Sequence *seq, const float handsize_cla
if (!(seq->type & SEQ_TYPE_EFFECT) ||
BKE_sequence_effect_get_num_inputs(seq->type) == 0)
{
- glEnable(GL_BLEND);
+ GPU_blend(true);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (seq->flag & whichsel) glColor4ub(0, 0, 0, 80);
- else if (seq->flag & SELECT) glColor4ub(255, 255, 255, 30);
- else glColor4ub(0, 0, 0, 22);
+ if (seq->flag & whichsel) {
+ immUniformColor4ub(0, 0, 0, 80);
+ }
+ else if (seq->flag & SELECT) {
+ immUniformColor4ub(255, 255, 255, 30);
+ }
+ else {
+ immUniformColor4ub(0, 0, 0, 22);
+ }
- glRectf(rx1, y1, rx2, y2);
+ immRectf(pos, rx1, y1, rx2, y2);
- if (seq->flag & whichsel) glColor4ub(255, 255, 255, 200);
- else glColor4ub(0, 0, 0, 50);
+ if (seq->flag & whichsel) {
+ immUniformColor4ub(255, 255, 255, 200);
+ }
+ else {
+ immUniformColor4ub(0, 0, 0, 50);
+ }
- glEnable(GL_POLYGON_SMOOTH);
- glBegin(GL_TRIANGLES);
- glVertex2fv(v1); glVertex2fv(v2); glVertex2fv(v3);
- glEnd();
+ immBegin(GPU_PRIM_TRIS, 3);
+ immVertex2fv(pos, v1);
+ immVertex2fv(pos, v2);
+ immVertex2fv(pos, v3);
+ immEnd();
- glDisable(GL_POLYGON_SMOOTH);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
if ((G.moving & G_TRANSFORM_SEQ) || (seq->flag & whichsel)) {
@@ -590,67 +601,10 @@ static void draw_seq_text(View2D *v2d, SpaceSeq *sseq, Sequence *seq, float x1,
UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
}
-/* draws a shaded strip, made from gradient + flat color + gradient */
-void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2)
-{
- float ymid1, ymid2;
-
- if (seq->flag & SEQ_MUTE) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_HALFTONE);
- }
-
- ymid1 = (y2 - y1) * 0.25f + y1;
- ymid2 = (y2 - y1) * 0.65f + y1;
-
- glBegin(GL_QUADS);
-
- if (seq->flag & SEQ_INVALID_EFFECT) { col[0] = 255; col[1] = 0; col[2] = 255; }
- else if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, -50);
- /* else UI_GetColorPtrShade3ubv(col, col, 0); */ /* DO NOTHING */
-
- glColor3ubv(col);
-
- glVertex2f(x1, y1);
- glVertex2f(x2, y1);
-
- if (seq->flag & SEQ_INVALID_EFFECT) { col[0] = 255; col[1] = 0; col[2] = 255; }
- else if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 5);
- else UI_GetColorPtrShade3ubv(col, col, -5);
-
- glColor3ubv((GLubyte *)col);
-
- glVertex2f(x2, ymid1);
- glVertex2f(x1, ymid1);
-
- glEnd();
-
- glRectf(x1, ymid1, x2, ymid2);
-
- glBegin(GL_QUADS);
-
- glVertex2f(x1, ymid2);
- glVertex2f(x2, ymid2);
-
- if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, -15);
- else UI_GetColorPtrShade3ubv(col, col, 25);
-
- glColor3ubv((GLubyte *)col);
-
- glVertex2f(x2, y2);
- glVertex2f(x1, y2);
-
- glEnd();
-
- if (seq->flag & SEQ_MUTE) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
-}
-
-void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq)
+static void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq, unsigned int pos)
{
- float x1, x2, y1, y2, pixely, a;
- unsigned char col[3], blendcol[3];
+ float x1, x2, y1, y2, pixely;
+ unsigned char col[4], blendcol[3];
View2D *v2d = &ar->v2d;
x1 = seq->startdisp;
@@ -665,89 +619,81 @@ void draw_sequence_extensions(Scene *scene, ARegion *ar, Sequence *seq)
blendcol[0] = blendcol[1] = blendcol[2] = 120;
- if (seq->startofs) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (seq->startofs || seq->endofs) {
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
color3ubv_from_seq(scene, seq, col);
if (seq->flag & SELECT) {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40);
- glColor4ub(col[0], col[1], col[2], 170);
+ UI_GetColorPtrShade3ubv(col, col, -50);
+ }
+
+ if (seq->flag & SEQ_MUTE) {
+ col[3] = 64;
}
else {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
- glColor4ub(col[0], col[1], col[2], 110);
+ if (seq->flag & SELECT) {
+ col[3] = 170;
+ }
+ else {
+ col[3] = 80;
+ }
}
+ }
- glRectf((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1);
-
- if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
- else glColor4ub(col[0], col[1], col[2], 160);
+ if (seq->startofs) {
+ immUniformColor4ubv(col);
+ immRectf(pos, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1);
- fdrawbox((float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); //outline
+ immUniformColor3ubvAlpha(col, col[3] + 50);
- glDisable(GL_BLEND);
+ imm_draw_box_wire_2d(pos, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM, x1, y1); /* outline */
}
if (seq->endofs) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- color3ubv_from_seq(scene, seq, col);
+ immUniformColor4ubv(col);
+ immRectf(pos, x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
- if (seq->flag & SELECT) {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40);
- glColor4ub(col[0], col[1], col[2], 170);
- }
- else {
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
- glColor4ub(col[0], col[1], col[2], 110);
- }
+ immUniformColor3ubvAlpha(col, col[3] + 50);
- glRectf(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
+ imm_draw_box_wire_2d(pos, x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); /* outline */
+ }
- if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
- else glColor4ub(col[0], col[1], col[2], 160);
+ if (seq->startofs || seq->endofs) {
+ GPU_blend(false);
+ }
- fdrawbox(x2, y2, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM); //outline
+ if (seq->startstill || seq->endstill) {
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_BLEND);
- }
- if (seq->startstill) {
color3ubv_from_seq(scene, seq, col);
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
- glColor3ubv((GLubyte *)col);
+ UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5f, 60);
- draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2);
-
- /* feint pinstripes, helps see exactly which is extended and which isn't,
- * especially when the extension is very small */
- if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24);
- else UI_GetColorPtrShade3ubv(col, col, -16);
+ if (seq->flag & SEQ_MUTE) {
+ col[3] = 96;
+ }
+ else {
+ if (seq->flag & SELECT) {
+ col[3] = 255;
+ }
+ else {
+ col[3] = 170;
+ }
+ }
- glColor3ubv((GLubyte *)col);
+ immUniformColor4ubv(col);
+ }
- for (a = y1; a < y2; a += pixely * 2.0f) {
- fdrawline(x1, a, (float)(seq->start), a);
- }
+ if (seq->startstill) {
+ immRectf(pos, x1, y1, (float)(seq->start), y2);
}
if (seq->endstill) {
- color3ubv_from_seq(scene, seq, col);
- UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
- glColor3ubv((GLubyte *)col);
-
- draw_shadedstrip(seq, col, (float)(seq->start + seq->len), y1, x2, y2);
-
- /* feint pinstripes, helps see exactly which is extended and which isn't,
- * especially when the extension is very small */
- if (seq->flag & SELECT) UI_GetColorPtrShade3ubv(col, col, 24);
- else UI_GetColorPtrShade3ubv(col, col, -16);
-
- glColor3ubv((GLubyte *)col);
+ immRectf(pos, (float)(seq->start + seq->len), y1, x2, y2);
+ }
- for (a = y1; a < y2; a += pixely * 2.0f) {
- fdrawline((float)(seq->start + seq->len), a, x2, a);
- }
+ if (seq->startstill || seq->endstill) {
+ GPU_blend(false);
}
}
@@ -761,7 +707,7 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
{
View2D *v2d = &ar->v2d;
float x1, x2, y1, y2;
- unsigned char col[3], background_col[3], is_single_image;
+ unsigned char col[4], background_col[4], is_single_image;
const float handsize_clamped = draw_seq_handle_size_get_clamped(seq, pixelx);
/* we need to know if this is a single image/color or not for drawing */
@@ -773,72 +719,105 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* get the correct color per strip type*/
//color3ubv_from_seq(scene, seq, col);
color3ubv_from_seq(scene, seq, background_col);
+ if (seq->flag & SEQ_MUTE) {
+ background_col[3] = 128;
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ background_col[3] = 255;
+ }
+
+ if (seq->flag & SELECT) {
+ UI_GetColorPtrShade3ubv(background_col, background_col, -50);
+ }
+
+ immUniformColor4ubv(background_col);
+
/* draw the main strip body */
if (is_single_image) { /* single image */
- draw_shadedstrip(seq, background_col,
- BKE_sequence_tx_get_final_left(seq, false), y1,
- BKE_sequence_tx_get_final_right(seq, false), y2);
+ immRectf(pos, BKE_sequence_tx_get_final_left(seq, false), y1,
+ BKE_sequence_tx_get_final_right(seq, false), y2);
}
else { /* normal operation */
- draw_shadedstrip(seq, background_col, x1, y1, x2, y2);
+ immRectf(pos, x1, y1, x2, y2);
+ }
+
+ if (seq->flag & SEQ_MUTE) {
+ GPU_blend(false);
}
if (!is_single_image) {
if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) {
- draw_sequence_extensions(scene, ar, seq);
+ draw_sequence_extensions(scene, ar, seq, pos);
}
}
- draw_seq_handle(v2d, seq, handsize_clamped, SEQ_LEFTHANDLE);
- draw_seq_handle(v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE);
+ draw_seq_handle(v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos);
+ draw_seq_handle(v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE, pos);
- /* draw the strip outline */
x1 = seq->startdisp;
x2 = seq->enddisp;
/* draw sound wave */
if (seq->type == SEQ_TYPE_SOUND_RAM) {
if (!(sseq->flag & SEQ_NO_WAVEFORMS)) {
- drawseqwave(C, sseq, scene, seq, x1, y1, x2, y2, BLI_rctf_size_x(&ar->v2d.cur) / ar->winx);
+ drawseqwave(v2d, C, sseq, scene, seq, x1, y1, x2, y2, BLI_rctf_size_x(&ar->v2d.cur) / ar->winx, pos);
}
}
+ immUnbindProgram();
+
/* draw lock */
if (seq->flag & SEQ_LOCK) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glEnable(GL_BLEND);
+ GPU_blend(true);
+
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES);
- /* light stripes */
- glColor4ub(255, 255, 255, 32);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES);
- glRectf(x1, y1, x2, y2);
+ immUniform4f("color1", 1.0f, 1.0f, 1.0f, 0.125f);
+ immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.125f);
+ immUniform1i("size1", 8);
+ immUniform1i("size2", 8);
- /* dark stripes */
- glColor4ub(0, 0, 0, 32);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP);
- glRectf(x1, y1, x2, y2);
+ immRectf(pos, x1, y1, x2, y2);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glDisable(GL_BLEND);
+ immUnbindProgram();
+
+ GPU_blend(false);
}
if (!BKE_sequence_is_valid_check(seq)) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_blend(true);
+
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES);
+
+ immUniform4f("color1", 1.0f, 0.0f, 0.0f, 1.0f);
+ immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f);
+ immUniform1i("size1", 8);
+ immUniform1i("size2", 8);
- /* panic! */
- glColor4ub(255, 0, 0, 255);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES);
- glRectf(x1, y1, x2, y2);
+ immRectf(pos, x1, y1, x2, y2);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immUnbindProgram();
+
+ GPU_blend(false);
}
color3ubv_from_seq(scene, seq, col);
+
+ /* draw the strip outline */
+ color3ubv_from_seq(scene, seq, col);
if ((G.moving & G_TRANSFORM_SEQ) && (seq->flag & SELECT)) {
if (seq->flag & SEQ_OVERLAP) {
col[0] = 255; col[1] = col[2] = 40;
@@ -855,18 +834,26 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
drawmeta_contents(scene, seq, x1, y1, x2, y2);
}
- if (seq->flag & SEQ_MUTE) {
- glEnable(GL_LINE_STIPPLE);
- glLineStipple(1, 0x8888);
- }
-
- glColor3ubv((GLubyte *)col);
+ pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- UI_draw_roundbox_shade_x(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0);
+ /* TODO: add back stippled line for muted strips? */
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
if (seq->flag & SEQ_MUTE) {
- glDisable(GL_LINE_STIPPLE);
+ col[3] = 96;
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ immUniformColor4ubv(col);
}
+ else {
+ immUniformColor3ubv(col);
+ }
+
+ imm_draw_box_wire_2d(pos, x1, y1, x2, y2); /* outline */
+
+ immUnbindProgram();
/* calculate if seq is long enough to print a name */
x1 = seq->startdisp + handsize_clamped;
@@ -909,7 +896,9 @@ void ED_sequencer_special_preview_clear(void)
sequencer_special_update_set(NULL);
}
-ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname)
+ImBuf *sequencer_ibuf_get(
+ struct Main *bmain, struct Depsgraph *depsgraph, Scene *scene,
+ SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname)
{
SeqRenderData context = {0};
ImBuf *ibuf;
@@ -934,16 +923,10 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int
recty = (render_size * (float)scene->r.ysch) / 100.0f + 0.5f;
BKE_sequencer_new_render_data(
- bmain->eval_ctx, bmain, scene,
- rectx, recty, proxy_size,
+ bmain, depsgraph, scene,
+ rectx, recty, proxy_size, false,
&context);
context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
- if (scene->r.seq_flag & R_SEQ_CAMERA_DOF) {
- if (sseq->compositor == NULL) {
- sseq->compositor = GPU_fx_compositor_create();
- }
- context.gpu_fx = sseq->compositor;
- }
/* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
* by Esc pressed somewhere in the past
@@ -1054,36 +1037,42 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
float x2 = v2d->tot.xmax;
float y2 = v2d->tot.ymax;
- glLineWidth(1.0f);
+ GPU_line_width(1.0f);
/* border */
- setlinestyle(3);
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- glBegin(GL_LINE_LOOP);
- glVertex2f(x1 - 0.5f, y1 - 0.5f);
- glVertex2f(x1 - 0.5f, y2 + 0.5f);
- glVertex2f(x2 + 0.5f, y2 + 0.5f);
- glVertex2f(x2 + 0.5f, y1 - 0.5f);
- glEnd();
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniformThemeColor(TH_BACK);
+ immUniform1i("colors_len", 0); /* Simple dashes. */
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ imm_draw_box_wire_2d(shdr_pos, x1 - 0.5f, y1 - 0.5f, x2 + 0.5f, y2 + 0.5f);
/* safety border */
if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
+ immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f);
+
UI_draw_safe_areas(
- x1, x2, y1, y2,
+ shdr_pos, x1, x2, y1, y2,
scene->safe_areas.title,
scene->safe_areas.action);
if (sseq->flag & SEQ_SHOW_SAFE_CENTER) {
UI_draw_safe_areas(
- x1, x2, y1, y2,
+ shdr_pos, x1, x2, y1, y2,
scene->safe_areas.title_center,
scene->safe_areas.action_center);
}
}
- setlinestyle(0);
+ immUnbindProgram();
}
/* draws checkerboard background for transparent content */
@@ -1098,11 +1087,7 @@ static void sequencer_draw_background(
/* only draw alpha for main buffer */
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
if ((sseq->flag & SEQ_USE_ALPHA) && !draw_overlay) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- fdrawcheckerboard(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
- glColor4f(1.0, 1.0, 1.0, 1.0);
+ imm_draw_box_checker_2d(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
}
}
}
@@ -1110,6 +1095,7 @@ static void sequencer_draw_background(
void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq, int cfra, int frame_ofs, bool draw_overlay, bool draw_backdrop)
{
struct Main *bmain = CTX_data_main(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
struct ImBuf *ibuf = NULL;
struct ImBuf *scope = NULL;
struct View2D *v2d = &ar->v2d;
@@ -1140,13 +1126,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
if ((!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) && !draw_backdrop) {
UI_GetThemeColor3fv(TH_SEQ_PREVIEW, col);
- glClearColor(col[0], col[1], col[2], 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear_color(col[0], col[1], col[2], 0.0);
+ GPU_clear(GPU_COLOR_BIT);
}
- /* without this colors can flicker from previous opengl state */
- glColor4ub(255, 255, 255, 255);
-
/* only initialize the preview if a render is in progress */
if (G.is_rendering)
return;
@@ -1156,20 +1139,21 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
/* for now we only support Left/Right */
- ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs, names[sseq->multiview_eye]);
+ ibuf = sequencer_ibuf_get(bmain, depsgraph, scene, sseq, cfra, frame_ofs, names[sseq->multiview_eye]);
if ((ibuf == NULL) ||
(ibuf->rect == NULL && ibuf->rect_float == NULL))
{
- /* gpencil can also be drawn without a valid imbuf */
- if ((draw_gpencil && is_imbuf) && !draw_overlay) {
- sequencer_display_size(scene, sseq, viewrect);
+ sequencer_display_size(scene, sseq, viewrect);
- sequencer_draw_background(sseq, v2d, viewrect, false);
- sequencer_draw_borders(sseq, v2d, scene);
+ sequencer_draw_background(sseq, v2d, viewrect, false);
+ sequencer_draw_borders(sseq, v2d, scene);
+ /* gpencil can also be drawn without a valid imbuf */
+ if ((draw_gpencil && is_imbuf) && !draw_overlay) {
sequencer_draw_gpencil(C);
}
+
return;
}
@@ -1238,6 +1222,18 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
sequencer_draw_background(sseq, v2d, viewrect, draw_overlay);
}
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) {
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ }
+
+ /* Format needs to be created prior to any immBindProgram call.
+ * Do it here because OCIO binds it's own shader.
+ */
+ GPUVertFormat *imm_format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint texCoord = GPU_vertformat_attr_add(imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
if (scope) {
IMB_freeImBuf(ibuf);
ibuf = scope;
@@ -1310,30 +1306,32 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
}
- glColor4f(1.0, 1.0, 1.0, 1.0);
+ if (draw_backdrop) {
+ /* XXX: need to load identity projection too? */
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+ }
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
glGenTextures(1, (GLuint *)&texid);
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (type == GL_FLOAT)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, ibuf->x, ibuf->y, 0, format, type, display_buffer);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, ibuf->x, ibuf->y, 0, format, type, display_buffer);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, format, type, display_buffer);
- if (draw_backdrop) {
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
+ if (!glsl_used) {
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+ immUniform1i("image", 0);
}
- glBegin(GL_QUADS);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
if (draw_overlay) {
if (sseq->overlay_type == SEQ_DRAW_OVERLAY_RECT) {
@@ -1343,16 +1341,30 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
tot_clip.xmax = v2d->tot.xmin + (fabsf(BLI_rctf_size_x(&v2d->tot)) * scene->ed->over_border.xmax);
tot_clip.ymax = v2d->tot.ymin + (fabsf(BLI_rctf_size_y(&v2d->tot)) * scene->ed->over_border.ymax);
- glTexCoord2f(scene->ed->over_border.xmin, scene->ed->over_border.ymin); glVertex2f(tot_clip.xmin, tot_clip.ymin);
- glTexCoord2f(scene->ed->over_border.xmin, scene->ed->over_border.ymax); glVertex2f(tot_clip.xmin, tot_clip.ymax);
- glTexCoord2f(scene->ed->over_border.xmax, scene->ed->over_border.ymax); glVertex2f(tot_clip.xmax, tot_clip.ymax);
- glTexCoord2f(scene->ed->over_border.xmax, scene->ed->over_border.ymin); glVertex2f(tot_clip.xmax, tot_clip.ymin);
+ immAttr2f(texCoord, scene->ed->over_border.xmin, scene->ed->over_border.ymin);
+ immVertex2f(pos, tot_clip.xmin, tot_clip.ymin);
+
+ immAttr2f(texCoord, scene->ed->over_border.xmin, scene->ed->over_border.ymax);
+ immVertex2f(pos, tot_clip.xmin, tot_clip.ymax);
+
+ immAttr2f(texCoord, scene->ed->over_border.xmax, scene->ed->over_border.ymax);
+ immVertex2f(pos, tot_clip.xmax, tot_clip.ymax);
+
+ immAttr2f(texCoord, scene->ed->over_border.xmax, scene->ed->over_border.ymin);
+ immVertex2f(pos, tot_clip.xmax, tot_clip.ymin);
}
else if (sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE) {
- glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin);
- glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax);
- glTexCoord2f(1.0f, 1.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymax);
- glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin);
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymin);
+
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymax);
+
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymax);
+
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymin);
}
}
else if (draw_backdrop) {
@@ -1371,25 +1383,46 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
imagey = aspect / image_aspect;
}
- glTexCoord2f(0.0f, 0.0f); glVertex2f(-imagex, -imagey);
- glTexCoord2f(0.0f, 1.0f); glVertex2f(-imagex, imagey);
- glTexCoord2f(1.0f, 1.0f); glVertex2f(imagex, imagey);
- glTexCoord2f(1.0f, 0.0f); glVertex2f(imagex, -imagey);
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, -imagex, -imagey);
+
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, -imagex, imagey);
+
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, imagex, imagey);
+
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, imagex, -imagey);
}
else {
draw_metadata = ((sseq->flag & SEQ_SHOW_METADATA) != 0);
- glTexCoord2f(0.0f, 0.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymin);
- glTexCoord2f(0.0f, 1.0f); glVertex2f(v2d->tot.xmin, v2d->tot.ymax);
- glTexCoord2f(1.0f, 1.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymax);
- glTexCoord2f(1.0f, 0.0f); glVertex2f(v2d->tot.xmax, v2d->tot.ymin);
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymin);
+
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex2f(pos, v2d->tot.xmin, v2d->tot.ymax);
+
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymax);
+
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex2f(pos, v2d->tot.xmax, v2d->tot.ymin);
}
- glEnd();
+
+ immEnd();
glBindTexture(GL_TEXTURE_2D, 0);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA)
- glDisable(GL_BLEND);
+
+ if (!glsl_used) {
+ immUnbindProgram();
+ }
+
+ if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) {
+ GPU_blend(false);
+ }
+
glDeleteTextures(1, &texid);
if (glsl_used)
@@ -1406,10 +1439,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
if (draw_backdrop) {
- glPopMatrix();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ GPU_matrix_pop();
return;
}
@@ -1484,41 +1514,41 @@ static void draw_seq_backdrop(View2D *v2d)
{
int i;
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* darker gray overlay over the view backdrop */
- UI_ThemeColorShade(TH_BACK, -20);
- glRectf(v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0);
+ immUniformThemeColorShade(TH_BACK, -20);
+ immRectf(pos, v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0);
/* Alternating horizontal stripes */
i = max_ii(1, ((int)v2d->cur.ymin) - 1);
- glBegin(GL_QUADS);
while (i < v2d->cur.ymax) {
- if (((int)i) & 1)
- UI_ThemeColorShade(TH_BACK, -15);
- else
- UI_ThemeColorShade(TH_BACK, -25);
+ if (i & 1) {
+ immUniformThemeColorShade(TH_BACK, -15);
+ }
+ else {
+ immUniformThemeColorShade(TH_BACK, -25);
+ }
- glVertex2f(v2d->cur.xmax, i);
- glVertex2f(v2d->cur.xmin, i);
- glVertex2f(v2d->cur.xmin, i + 1);
- glVertex2f(v2d->cur.xmax, i + 1);
+ immRectf(pos, v2d->cur.xmin, i, v2d->cur.xmax, i + 1);
- i += 1.0;
+ i++;
}
- glEnd();
/* Darker lines separating the horizontal bands */
i = max_ii(1, ((int)v2d->cur.ymin) - 1);
- UI_ThemeColor(TH_GRID);
-
- glBegin(GL_LINES);
- while (i < v2d->cur.ymax) {
- glVertex2f(v2d->cur.xmax, i);
- glVertex2f(v2d->cur.xmin, i);
-
- i += 1.0;
+ int line_len = (int)v2d->cur.ymax - i + 1;
+ immUniformThemeColor(TH_GRID);
+ immBegin(GPU_PRIM_LINES, line_len * 2);
+ while (line_len--) {
+ immVertex2f(pos, v2d->cur.xmax, i);
+ immVertex2f(pos, v2d->cur.xmin, i);
}
- glEnd();
+ immEnd();
+
+ immUnbindProgram();
}
/* draw the contents of the sequencer strips view */
@@ -1534,7 +1564,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar)
/* loop through twice, first unselected, then selected */
for (j = 0; j < 2; j++) {
Sequence *seq;
- int outline_tint = (j) ? -60 : -150; /* highlighting around strip edges indicating selection */
+ int outline_tint = (j) ? 40 : -40; /* highlighting around strip edges indicating selection */
/* loop through strips, checking for those that are visible */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
@@ -1561,10 +1591,17 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar)
/* draw highlight when previewing a single strip */
if (special_seq_update) {
const Sequence *seq = special_seq_update;
- glEnable(GL_BLEND);
- glColor4ub(255, 255, 255, 48);
- glRectf(seq->startdisp, seq->machine + SEQ_STRIP_OFSBOTTOM, seq->enddisp, seq->machine + SEQ_STRIP_OFSTOP);
- glDisable(GL_BLEND);
+ GPU_blend(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4ub(255, 255, 255, 48);
+ immRectf(pos, seq->startdisp, seq->machine + SEQ_STRIP_OFSBOTTOM, seq->enddisp, seq->machine + SEQ_STRIP_OFSTOP);
+
+ immUnbindProgram();
+
+ GPU_blend(false);
}
}
@@ -1574,38 +1611,58 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
const int frame_sta = PSFRA;
const int frame_end = PEFRA + 1;
- glEnable(GL_BLEND);
+ GPU_blend(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* draw darkened area outside of active timeline
* frame range used is preview range or scene range */
- UI_ThemeColorShadeAlpha(TH_BACK, -25, -100);
+ immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
if (frame_sta < frame_end) {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)frame_sta, v2d->cur.ymax);
- glRectf((float)frame_end, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)frame_sta, v2d->cur.ymax);
+ immRectf(pos, (float)frame_end, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
else {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
- UI_ThemeColorShade(TH_BACK, -60);
+ immUniformThemeColorShade(TH_BACK, -60);
+
/* thin lines where the actual frames are */
- fdrawline(frame_sta, v2d->cur.ymin, frame_sta, v2d->cur.ymax);
- fdrawline(frame_end, v2d->cur.ymin, frame_end, v2d->cur.ymax);
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(pos, frame_sta, v2d->cur.ymin);
+ immVertex2f(pos, frame_sta, v2d->cur.ymax);
+
+ immVertex2f(pos, frame_end, v2d->cur.ymin);
+ immVertex2f(pos, frame_end, v2d->cur.ymax);
+
+ immEnd();
if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
MetaStack *ms = ed->metastack.last;
- glColor4ub(255, 255, 255, 8);
- glRectf(ms->disp_range[0], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax);
+ immUniformColor4ub(255, 255, 255, 8);
+ immRectf(pos, ms->disp_range[0], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax);
+
+ immUniformThemeColorShade(TH_BACK, -40);
+
+ immBegin(GPU_PRIM_LINES, 4);
- UI_ThemeColorShade(TH_BACK, -40);
+ immVertex2f(pos, ms->disp_range[0], v2d->cur.ymin);
+ immVertex2f(pos, ms->disp_range[0], v2d->cur.ymax);
- fdrawline(ms->disp_range[0], v2d->cur.ymin, ms->disp_range[0], v2d->cur.ymax);
- fdrawline(ms->disp_range[1], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax);
+ immVertex2f(pos, ms->disp_range[1], v2d->cur.ymin);
+ immVertex2f(pos, ms->disp_range[1], v2d->cur.ymax);
+
+ immEnd();
}
- glDisable(GL_BLEND);
+ immUnbindProgram();
+
+ GPU_blend(false);
}
/* Draw Timeline/Strip Editor Mode for Sequencer */
@@ -1616,16 +1673,16 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
SpaceSeq *sseq = CTX_wm_space_seq(C);
View2D *v2d = &ar->v2d;
View2DScrollers *scrollers;
- short unit = 0, flag = 0;
+ short unit = 0, cfra_flag = 0;
float col[3];
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
if (ed && ed->metastack.first)
- glClearColor(col[0], col[1], col[2] - 0.1f, 0.0f);
+ GPU_clear_color(col[0], col[1], col[2] - 0.1f, 0.0f);
else
- glClearColor(col[0], col[1], col[2], 0.0f);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear_color(col[0], col[1], col[2], 0.0f);
+ GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
@@ -1663,9 +1720,8 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
/* current frame */
UI_view2d_view_ortho(v2d);
- if ((sseq->flag & SEQ_DRAWFRAMES) == 0) flag |= DRAWCFRA_UNIT_SECONDS;
- if ((sseq->flag & SEQ_NO_DRAW_CFRANUM) == 0) flag |= DRAWCFRA_SHOW_NUMBOX;
- ANIM_draw_cfra(C, v2d, flag);
+ if ((sseq->flag & SEQ_DRAWFRAMES) == 0) cfra_flag |= DRAWCFRA_UNIT_SECONDS;
+ ANIM_draw_cfra(C, v2d, cfra_flag);
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
@@ -1678,14 +1734,18 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
/* overlap playhead */
if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
int cfra_over = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ? scene->ed->over_cfra : scene->r.cfra + scene->ed->over_ofs;
- glColor3f(0.2, 0.2, 0.2);
- // glRectf(cfra_over, v2d->cur.ymin, scene->ed->over_ofs + scene->r.cfra + 1, v2d->cur.ymax);
- glBegin(GL_LINES);
- glVertex2f(cfra_over, v2d->cur.ymin);
- glVertex2f(cfra_over, v2d->cur.ymax);
- glEnd();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3f(0.2f, 0.2f, 0.2f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, cfra_over, v2d->cur.ymin);
+ immVertex2f(pos, cfra_over, v2d->cur.ymax);
+ immEnd();
+
+ immUnbindProgram();
}
/* callback */
@@ -1696,7 +1756,13 @@ void draw_timeline_seq(const bContext *C, ARegion *ar)
/* scrollers */
unit = (sseq->flag & SEQ_DRAWFRAMES) ? V2D_UNIT_FRAMES : V2D_UNIT_SECONDS;
- scrollers = UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_UNIT_VALUES, V2D_GRID_CLAMP);
+ scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, unit, V2D_GRID_CLAMP, V2D_UNIT_VALUES, V2D_GRID_CLAMP);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
+
+ /* draw current frame number-indicator on top of scrollers */
+ if ((sseq->flag & SEQ_NO_DRAW_CFRANUM) == 0) {
+ UI_view2d_view_orthoSpecial(ar, v2d, 1);
+ ANIM_draw_cfra_number(C, v2d, cfra_flag);
+ }
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index d9cc7cb2c36..e55b8d17cd4 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -48,8 +48,8 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
-#include "BKE_sequencer.h"
#include "BKE_report.h"
+#include "BKE_sequencer.h"
#include "BKE_sound.h"
@@ -71,7 +71,6 @@
#include "UI_view2d.h"
#include "UI_interface.h"
-
/* own include */
#include "sequencer_intern.h"
@@ -132,8 +131,9 @@ typedef struct TransSeq {
/* ***************** proxy job manager ********************** */
typedef struct ProxyBuildJob {
- Scene *scene;
struct Main *main;
+ struct Depsgraph *depsgraph;
+ Scene *scene;
ListBase queue;
int stop;
} ProxyJob;
@@ -185,6 +185,7 @@ static void seq_proxy_build_job(const bContext *C)
{
wmJob *wm_job;
ProxyJob *pj;
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
ScrArea *sa = CTX_wm_area(C);
@@ -203,6 +204,7 @@ static void seq_proxy_build_job(const bContext *C)
if (!pj) {
pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
+ pj->depsgraph = depsgraph;
pj->scene = scene;
pj->main = CTX_data_main(C);
@@ -215,7 +217,7 @@ static void seq_proxy_build_job(const bContext *C)
SEQP_BEGIN (ed, seq)
{
if ((seq->flag & SELECT)) {
- BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list, &pj->queue);
+ BKE_sequencer_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
}
} SEQ_END;
@@ -1286,7 +1288,6 @@ typedef struct SlipData {
int num_seq;
bool slow;
int slow_offset; /* offset at the point where offset was turned on */
- void *draw_handle;
NumInput num_input;
} SlipData;
@@ -1321,21 +1322,6 @@ static void transseq_restore(TransSeq *ts, Sequence *seq)
seq->len = ts->len;
}
-static void draw_slip_extensions(const bContext *C, ARegion *ar, void *data)
-{
- Scene *scene = CTX_data_scene(C);
- SlipData *td = data;
- int i;
-
- for (i = 0; i < td->num_seq; i++) {
- Sequence *seq = td->seq_array[i];
-
- if ((seq->type != SEQ_TYPE_META) && td->trim[i]) {
- draw_sequence_extensions(scene, ar, seq);
- }
- }
-}
-
static int slip_add_sequences_rec(ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool do_trim)
{
Sequence *seq;
@@ -1384,7 +1370,6 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
SlipData *data;
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- ARegion *ar = CTX_wm_region(C);
float mouseloc[2];
int num_seq, i;
View2D *v2d = UI_view2d_fromcontext(C);
@@ -1414,8 +1399,6 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
transseq_backup(data->ts + i, data->seq_array[i]);
}
- data->draw_handle = ED_region_draw_cb_activate(ar->type, draw_slip_extensions, data, REGION_DRAW_POST_VIEW);
-
UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
copy_v2_v2_int(data->init_mouse, event->mval);
@@ -1549,7 +1532,7 @@ static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *da
}
}
- ED_area_headerprint(sa, msg);
+ ED_area_status_text(sa, msg);
}
static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1557,7 +1540,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
Scene *scene = CTX_data_scene(C);
SlipData *data = (SlipData *)op->customdata;
ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
const bool has_numInput = hasNumInput(&data->num_input);
bool handled = true;
@@ -1615,14 +1597,13 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
case RETKEY:
case SPACEKEY:
{
- ED_region_draw_cb_exit(ar->type, data->draw_handle);
MEM_freeN(data->seq_array);
MEM_freeN(data->trim);
MEM_freeN(data->ts);
MEM_freeN(data);
op->customdata = NULL;
if (sa) {
- ED_area_headerprint(sa, NULL);
+ ED_area_status_text(sa, NULL);
}
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -1644,8 +1625,6 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
BKE_sequence_calc(scene, seq);
}
- ED_region_draw_cb_exit(ar->type, data->draw_handle);
-
MEM_freeN(data->seq_array);
MEM_freeN(data->ts);
MEM_freeN(data->trim);
@@ -1657,7 +1636,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
if (sa) {
- ED_area_headerprint(sa, NULL);
+ ED_area_status_text(sa, NULL);
}
return OPERATOR_CANCELLED;
@@ -1805,7 +1784,7 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Un-Mute Strips";
+ ot->name = "Unmute Strips";
ot->idname = "SEQUENCER_OT_unmute";
ot->description = "Unmute (un)selected strips";
@@ -1874,7 +1853,7 @@ static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_unlock(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "UnLock Strips";
+ ot->name = "Unlock Strips";
ot->idname = "SEQUENCER_OT_unlock";
ot->description = "Unlock the active strip so that it can't be transformed";
@@ -3415,7 +3394,7 @@ void SEQUENCER_OT_swap_data(wmOperatorType *ot)
/* properties */
}
-/* borderselect operator */
+/* box select operator */
static int view_ghost_border_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -3450,7 +3429,7 @@ static int view_ghost_border_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* ****** Border Select ****** */
+/* ****** Box Select ****** */
void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
{
/* identifiers */
@@ -3459,17 +3438,17 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
ot->description = "Set the boundaries of the border used for offset-view";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = view_ghost_border_exec;
- ot->modal = WM_gesture_border_modal;
+ ot->modal = WM_gesture_box_modal;
ot->poll = sequencer_view_preview_poll;
- ot->cancel = WM_gesture_border_cancel;
+ ot->cancel = WM_gesture_box_cancel;
/* flags */
ot->flag = 0;
/* rna */
- WM_operator_properties_gesture_border(ot);
+ WM_operator_properties_gesture_box(ot);
}
/* rebuild_proxy operator */
@@ -3485,6 +3464,7 @@ static int sequencer_rebuild_proxy_invoke(bContext *C, wmOperator *UNUSED(op),
static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq;
@@ -3504,7 +3484,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
short stop = 0, do_update;
float progress;
- BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list, &queue);
+ BKE_sequencer_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue);
for (link = queue.first; link; link = link->next) {
struct SeqIndexBuildContext *context = link->data;
@@ -3537,7 +3517,7 @@ void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
static int sequencer_enable_proxies_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y);
+ return WM_operator_props_dialog_popup(C, op, 200, 100);
}
static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index e06f4558f00..0d647c883be 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -36,6 +36,7 @@
/* internal exports only */
+struct Depsgraph;
struct Sequence;
struct bContext;
struct rctf;
@@ -56,15 +57,13 @@ struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa);
void draw_timeline_seq(const struct bContext *C, struct ARegion *ar);
void draw_image_seq(const struct bContext *C, struct Scene *scene, struct ARegion *ar, struct SpaceSeq *sseq, int cfra, int offset, bool draw_overlay, bool draw_backdrop);
void color3ubv_from_seq(struct Scene *curscene, struct Sequence *seq, unsigned char col[3]);
-void draw_shadedstrip(struct Sequence *seq, unsigned char col[3], float x1, float y1, float x2, float y2);
-void draw_sequence_extensions(struct Scene *scene, struct ARegion *ar, struct Sequence *seq);
void sequencer_special_update_set(Sequence *seq);
/* UNUSED */
// void seq_reset_imageofs(struct SpaceSeq *sseq);
-struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname);
+struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname);
/* sequencer_edit.c */
struct View2D;
@@ -149,7 +148,7 @@ void SEQUENCER_OT_select_linked(struct wmOperatorType *ot);
void SEQUENCER_OT_select_linked_pick(struct wmOperatorType *ot);
void SEQUENCER_OT_select_handles(struct wmOperatorType *ot);
void SEQUENCER_OT_select_active_side(struct wmOperatorType *ot);
-void SEQUENCER_OT_select_border(struct wmOperatorType *ot);
+void SEQUENCER_OT_select_box(struct wmOperatorType *ot);
void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot);
void SEQUENCER_OT_select_grouped(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 408dc551382..cdba163f574 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -39,6 +39,7 @@
#include "ED_sequencer.h"
#include "ED_markers.h"
#include "ED_transform.h" /* transform keymap */
+#include "ED_select_utils.h"
#include "BKE_sequencer.h"
@@ -105,7 +106,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_select_linked);
WM_operatortype_append(SEQUENCER_OT_select_handles);
WM_operatortype_append(SEQUENCER_OT_select_active_side);
- WM_operatortype_append(SEQUENCER_OT_select_border);
+ WM_operatortype_append(SEQUENCER_OT_select_box);
WM_operatortype_append(SEQUENCER_OT_select_grouped);
/* sequencer_add.c */
@@ -133,237 +134,14 @@ void sequencer_operatortypes(void)
void sequencer_keymap(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
/* Common items ------------------------------------------------------------------ */
- keymap = WM_keymap_ensure(keyconf, "SequencerCommon", SPACE_SEQ, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_properties", NKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", OKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "scene.sequence_editor.show_overlay");
-
- /* operators common to sequence and preview view */
- WM_keymap_add_item(keymap, "SEQUENCER_OT_view_toggle", TABKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_ensure(keyconf, "SequencerCommon", SPACE_SEQ, 0);
/* Strips Region --------------------------------------------------------------- */
- keymap = WM_keymap_ensure(keyconf, "Sequencer", SPACE_SEQ, 0);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_cut", KKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "type", SEQ_CUT_SOFT);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_cut", KKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "type", SEQ_CUT_HARD);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_mute", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_mute", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_unmute", HKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_unmute", HKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_lock", LKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_unlock", LKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_reassign_inputs", RKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_reload", RKEY, KM_PRESS, KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_reload", RKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "adjust_length", true);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_offset_clear", OKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_delete", XKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_delete", DELKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "SEQUENCER_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_images_separate", YKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_toggle", TABKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_make", GKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_separate", GKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
- WM_keymap_add_item(keymap, "SEQUENCER_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_view_frame", PAD0, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_strip_jump", PAGEUPKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "next", true);
- RNA_boolean_set(kmi->ptr, "center", false);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_strip_jump", PAGEDOWNKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "next", false);
- RNA_boolean_set(kmi->ptr, "center", false);
-
- /* alt for center */
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_strip_jump", PAGEUPKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "next", true);
- RNA_boolean_set(kmi->ptr, "center", true);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_strip_jump", PAGEDOWNKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "next", false);
- RNA_boolean_set(kmi->ptr, "center", true);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_swap", LEFTARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "side", SEQ_SIDE_LEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_swap", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "side", SEQ_SIDE_RIGHT);
-
- RNA_boolean_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_gap_remove", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "all", false);
- RNA_boolean_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_gap_remove", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "all", true);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_gap_insert", EQUALKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_swap_inputs", SKEY, KM_PRESS, KM_ALT, 0);
-
- /* multicam editing keyboard layout, switch to camera 1-10 using
- * regular number keys */
- {
- int keys[] = { ONEKEY, TWOKEY, THREEKEY, FOURKEY, FIVEKEY,
- SIXKEY, SEVENKEY, EIGHTKEY, NINEKEY, ZEROKEY };
- int i;
-
- for (i = 1; i <= 10; i++) {
- RNA_int_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_cut_multicam", keys[i - 1], KM_PRESS, 0, 0)->ptr, "camera", i);
- }
- }
-
- /* Mouse selection, a bit verbose :/ */
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "linked_handle", false);
- RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
- RNA_boolean_set(kmi->ptr, "linked_time", false);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "linked_handle", false);
- RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
- RNA_boolean_set(kmi->ptr, "linked_time", false);
-
-
- /* 2.4x method, now use Alt for handles and select the side based on which handle was selected */
-#if 0
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "linked_left", true);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "linked_right", true);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "linked_left", true);
- RNA_boolean_set(kmi->ptr, "linked_right", true);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "linked_left", true);
- RNA_boolean_set(kmi->ptr, "linked_right", true);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "linked_left", true);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "linked_right", true);
-#endif
-
- /* 2.5 method, Alt and use selected handle */
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "linked_handle", true);
- RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
- RNA_boolean_set(kmi->ptr, "linked_time", false);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "linked_handle", true);
- RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
- RNA_boolean_set(kmi->ptr, "linked_time", false);
-
- /* match action editor */
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "linked_handle", false);
- RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_MOUSE); /* grr, these conflict - only use left_right if not over an active seq */
- RNA_boolean_set(kmi->ptr, "linked_time", true);
- /* adjusted since 2.4 */
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "linked_handle", false);
- RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
- RNA_boolean_set(kmi->ptr, "linked_time", true);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_select_border", BKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_menu(keymap, "SEQUENCER_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_menu(keymap, "SEQUENCER_MT_change", CKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_slip", SKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_int", OKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "scene.sequence_editor.overlay_frame");
- RNA_int_set(kmi->ptr, "value", 0);
-
- transform_keymap_for_space(keyconf, keymap, SPACE_SEQ);
-
- /* special markers hotkeys for anim editors: see note in definition of this function */
- ED_marker_keymap_animedit_conflictfree(keymap);
-
+ WM_keymap_ensure(keyconf, "Sequencer", SPACE_SEQ, 0);
/* Preview Region ----------------------------------------------------------- */
- keymap = WM_keymap_ensure(keyconf, "SequencerPreview", SPACE_SEQ, 0);
- WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all_preview", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all_preview", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
-
- WM_keymap_add_item(keymap, "SEQUENCER_OT_view_ghost_border", OKEY, KM_PRESS, 0, 0);
-
- /* would prefer to use numpad keys for job */
- RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD1, KM_PRESS, 0, 0)->ptr, "ratio", 1.0f);
-
- /* Setting zoom levels is not that useful, except for back to zoom level 1, removing keymap because of conflicts for now */
-#if 0
- RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 8.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 4.0f);
- RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD2, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 2.0f);
-
- RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD2, KM_PRESS, 0, 0)->ptr, "ratio", 0.5f);
- RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD4, KM_PRESS, 0, 0)->ptr, "ratio", 0.25f);
- RNA_float_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_view_zoom_ratio", PAD8, KM_PRESS, 0, 0)->ptr, "ratio", 0.125f);
-#endif
-
- /* sample */
- WM_keymap_add_item(keymap, "SEQUENCER_OT_sample", ACTIONMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_ensure(keyconf, "SequencerPreview", SPACE_SEQ, 0);
}
void ED_operatormacros_sequencer(void)
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 1a9ef7970a4..433f1ca8ee5 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -50,6 +50,7 @@
#include "ED_screen.h"
#include "ED_sequencer.h"
+#include "ED_select_utils.h"
#include "UI_view2d.h"
@@ -557,7 +558,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
};
/* identifiers */
- ot->name = "Activate/Select";
+ ot->name = "Select";
ot->idname = "SEQUENCER_OT_select";
ot->description = "Select a strip (last selected becomes the \"active strip\")";
@@ -829,7 +830,7 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot)
/* identifiers */
ot->name = "Select Handles";
ot->idname = "SEQUENCER_OT_select_handles";
- ot->description = "Select manipulator handles on the sides of the selected strip";
+ ot->description = "Select gizmo handles on the sides of the selected strip";
/* api callbacks */
ot->exec = sequencer_select_handles_exec;
@@ -880,8 +881,8 @@ void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
}
-/* borderselect operator */
-static int sequencer_borderselect_exec(bContext *C, wmOperator *op)
+/* box_select operator */
+static int sequencer_box_select_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -918,19 +919,19 @@ static int sequencer_borderselect_exec(bContext *C, wmOperator *op)
}
-/* ****** Border Select ****** */
-void SEQUENCER_OT_select_border(wmOperatorType *ot)
+/* ****** Box Select ****** */
+void SEQUENCER_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->idname = "SEQUENCER_OT_select_border";
- ot->description = "Select strips using border selection";
+ ot->name = "Box Select";
+ ot->idname = "SEQUENCER_OT_select_box";
+ ot->description = "Select strips using box selection";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = sequencer_borderselect_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = sequencer_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_sequencer_active;
@@ -938,7 +939,7 @@ void SEQUENCER_OT_select_border(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box_select(ot);
}
/* ****** Selected Grouped ****** */
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index daf9af7db4b..fb4ef3e51ab 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -91,10 +91,11 @@ static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
SpaceSeq *sseq = (SpaceSeq *) CTX_wm_space_data(C);
ARegion *ar = CTX_wm_region(C);
- ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0, NULL);
+ ImBuf *ibuf = sequencer_ibuf_get(bmain, depsgraph, scene, sseq, CFRA, 0, NULL);
ImageSampleInfo *info = op->customdata;
float fx, fy;
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index b87d878e057..092911cb7c2 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -42,10 +42,10 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
-#include "BKE_global.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -53,6 +53,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+
+#include "RNA_access.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -60,8 +63,6 @@
#include "IMB_imbuf.h"
-#include "GPU_compositing.h"
-
#include "sequencer_intern.h" // own include
/**************************** common state *****************************/
@@ -112,9 +113,8 @@ static ARegion *sequencer_find_region(ScrArea *sa, short type)
/* ******************** default callbacks for sequencer space ***************** */
-static SpaceLink *sequencer_new(const bContext *C)
+static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
{
- Scene *scene = CTX_data_scene(C);
ARegion *ar;
SpaceSeq *sseq;
@@ -130,7 +130,7 @@ static SpaceLink *sequencer_new(const bContext *C)
BLI_addtail(&sseq->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* buttons/list view */
ar = MEM_callocN(sizeof(ARegion), "buttons for sequencer");
@@ -220,11 +220,6 @@ static void sequencer_free(SpaceLink *sl)
if (scopes->histogram_ibuf)
IMB_freeImBuf(scopes->histogram_ibuf);
-
- if (sseq->compositor != NULL) {
- GPU_fx_compositor_destroy(sseq->compositor);
- sseq->compositor = NULL;
- }
}
@@ -344,7 +339,8 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl)
return (SpaceLink *)sseqn;
}
-static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void sequencer_listener(
+ wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -370,7 +366,7 @@ static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn
/* ************* dropboxes ************* */
-static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -384,7 +380,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
return 0;
}
-static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -397,7 +393,7 @@ static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
return 0;
}
-static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip))
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -498,7 +494,9 @@ static void sequencer_main_region_draw(const bContext *C, ARegion *ar)
draw_timeline_seq(C, ar);
}
-static void sequencer_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void sequencer_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -536,6 +534,61 @@ static void sequencer_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(
}
}
+static void sequencer_main_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *scene,
+ struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* Timeline depends on scene properties. */
+ {
+ bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
+ extern PropertyRNA rna_Scene_frame_start;
+ extern PropertyRNA rna_Scene_frame_end;
+ extern PropertyRNA rna_Scene_frame_preview_start;
+ extern PropertyRNA rna_Scene_frame_preview_end;
+ extern PropertyRNA rna_Scene_use_preview_range;
+ extern PropertyRNA rna_Scene_frame_current;
+ const PropertyRNA *props[] = {
+ use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
+ use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
+ &rna_Scene_use_preview_range,
+ &rna_Scene_frame_current,
+ };
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&scene->id, &idptr);
+
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
+ }
+ }
+
+ {
+ StructRNA *type_array[] = {
+ &RNA_SequenceEditor,
+
+ &RNA_Sequence,
+ /* Members of 'Sequence'. */
+ &RNA_SequenceCrop,
+ &RNA_SequenceTransform,
+ &RNA_SequenceModifier,
+ &RNA_SequenceColorBalanceData,
+ };
+ wmMsgParams_RNA msg_key_params = {{{0}}};
+ for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
+ msg_key_params.ptr.type = type_array[i];
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__);
+ }
+ }
+}
+
/* *********************** header region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
static void sequencer_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
@@ -600,11 +653,15 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *ar)
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
rcti rect;
ED_region_visible_rect(ar, &rect);
- ED_scene_draw_fps(scene, &rect);
+ int xoffset = rect.xmin + U.widget_unit;
+ int yoffset = rect.xmax;
+ ED_scene_draw_fps(scene, xoffset, &yoffset);
}
}
-static void sequencer_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void sequencer_preview_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -667,10 +724,12 @@ static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *ar)
static void sequencer_buttons_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
-static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void sequencer_buttons_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -742,6 +801,7 @@ void ED_spacetype_sequencer(void)
art->init = sequencer_main_region_init;
art->draw = sequencer_main_region_draw;
art->listener = sequencer_main_region_listener;
+ art->message_subscribe = sequencer_main_region_message_subscribe;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_logic/CMakeLists.txt b/source/blender/editors/space_statusbar/CMakeLists.txt
index 349c003cf56..31439942397 100644
--- a/source/blender/editors/space_logic/CMakeLists.txt
+++ b/source/blender/editors/space_statusbar/CMakeLists.txt
@@ -20,9 +20,9 @@
set(INC
../include
- ../interface
../../blenkernel
../../blenlib
+ ../../blenloader
../../blentranslation
../../gpu
../../makesdna
@@ -37,22 +37,9 @@ set(INC_SYS
)
set(SRC
- logic_buttons.c
- logic_ops.c
- logic_window.c
- space_logic.c
-
- logic_intern.h
+ space_statusbar.c
)
-if(WITH_GAMEENGINE)
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
add_definitions(${GL_DEFINITIONS})
-if(WITH_INTERNATIONAL)
- add_definitions(-DWITH_INTERNATIONAL)
-endif()
-
-blender_add_lib(bf_editor_space_logic "${SRC}" "${INC}" "${INC_SYS}")
+blender_add_lib(bf_editor_space_statusbar "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
new file mode 100644
index 00000000000..35eb6c69585
--- /dev/null
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -0,0 +1,187 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_statusbar/space_statusbar.c
+ * \ingroup spstatusbar
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+
+
+/* ******************** default callbacks for statusbar space ******************** */
+
+static SpaceLink *statusbar_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
+{
+ ARegion *ar;
+ SpaceStatusBar *sstatusbar;
+
+ sstatusbar = MEM_callocN(sizeof(*sstatusbar), "init statusbar");
+ sstatusbar->spacetype = SPACE_STATUSBAR;
+
+ /* header region */
+ ar = MEM_callocN(sizeof(*ar), "header for statusbar");
+ BLI_addtail(&sstatusbar->regionbase, ar);
+ ar->regiontype = RGN_TYPE_HEADER;
+ ar->alignment = RGN_ALIGN_NONE;
+
+ return (SpaceLink *)sstatusbar;
+}
+
+/* not spacelink itself */
+static void statusbar_free(SpaceLink *UNUSED(sl))
+{
+
+}
+
+
+/* spacetype; init callback */
+static void statusbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+{
+
+}
+
+static SpaceLink *statusbar_duplicate(SpaceLink *sl)
+{
+ SpaceStatusBar *sstatusbarn = MEM_dupallocN(sl);
+
+ /* clear or remove stuff from old */
+
+ return (SpaceLink *)sstatusbarn;
+}
+
+
+
+/* add handlers, stuff you only do once or on area/region changes */
+static void statusbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
+{
+ if (ELEM(region->alignment, RGN_ALIGN_RIGHT)) {
+ region->flag |= RGN_FLAG_DYNAMIC_SIZE;
+ }
+ ED_region_header_init(region);
+}
+
+static void statusbar_operatortypes(void)
+{
+
+}
+
+static void statusbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
+{
+
+}
+
+static void statusbar_header_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
+{
+ /* context changes */
+ switch (wmn->category) {
+ case NC_SCREEN:
+ if (ELEM(wmn->data, ND_LAYER, ND_ANIMPLAY)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
+ case NC_WM:
+ if (wmn->data == ND_JOB)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_SCENE:
+ if (wmn->data == ND_RENDER_RESULT)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_SPACE:
+ if (wmn->data == ND_SPACE_INFO)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_ID:
+ if (wmn->action == NA_RENAME)
+ ED_region_tag_redraw(ar);
+ break;
+ }
+}
+
+static void statusbar_header_region_message_subscribe(
+ const bContext *UNUSED(C),
+ WorkSpace *UNUSED(workspace), Scene *UNUSED(scene),
+ bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
+}
+
+/* only called once, from space/spacetypes.c */
+void ED_spacetype_statusbar(void)
+{
+ SpaceType *st = MEM_callocN(sizeof(*st), "spacetype statusbar");
+ ARegionType *art;
+
+ st->spaceid = SPACE_STATUSBAR;
+ strncpy(st->name, "Status Bar", BKE_ST_MAXNAME);
+
+ st->new = statusbar_new;
+ st->free = statusbar_free;
+ st->init = statusbar_init;
+ st->duplicate = statusbar_duplicate;
+ st->operatortypes = statusbar_operatortypes;
+ st->keymap = statusbar_keymap;
+
+ /* regions: header window */
+ art = MEM_callocN(sizeof(*art), "spacetype statusbar header region");
+ art->regionid = RGN_TYPE_HEADER;
+ art->prefsizey = 0.8f * HEADERY;
+ art->prefsizex = UI_UNIT_X * 5; /* Mainly to avoid glitches */
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+ art->init = statusbar_header_region_init;
+ art->layout = ED_region_header_layout;
+ art->draw = ED_region_header_draw;
+ art->listener = statusbar_header_region_listener;
+ art->message_subscribe = statusbar_header_region_message_subscribe;
+ BLI_addhead(&st->regiontypes, art);
+
+ BKE_spacetype_register(st);
+}
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index fc05fb51c1a..27b75f49b44 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -59,10 +59,11 @@
#include "text_format.h"
#include "text_intern.h" /* own include */
+#include "GPU_framebuffer.h"
/* ******************** default callbacks for text space ***************** */
-static SpaceLink *text_new(const bContext *UNUSED(C))
+static SpaceLink *text_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceText *stext;
@@ -79,7 +80,7 @@ static SpaceLink *text_new(const bContext *UNUSED(C))
BLI_addtail(&stext->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* properties region */
ar = MEM_callocN(sizeof(ARegion), "properties region for text");
@@ -125,7 +126,7 @@ static SpaceLink *text_duplicate(SpaceLink *sl)
return (SpaceLink *)stextn;
}
-static void text_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
+static void text_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
{
SpaceText *st = sa->spacedata.first;
@@ -240,156 +241,8 @@ static void text_operatortypes(void)
static void text_keymap(struct wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
- keymap = WM_keymap_ensure(keyconf, "Text Generic", SPACE_TEXT, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_start_find", FKEY, KM_PRESS, KM_CTRL, 0);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "TEXT_OT_start_find", FKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
- WM_keymap_add_item(keymap, "TEXT_OT_jump", JKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_find", GKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_replace", HKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_properties", TKEY, KM_PRESS, KM_CTRL, 0);
-
- keymap = WM_keymap_ensure(keyconf, "Text", SPACE_TEXT, 0);
-
-#ifdef __APPLE__
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", RIGHTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_END);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "type", PREV_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0)->ptr, "type", NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", UPARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", FILE_TOP);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", DOWNARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", FILE_BOTTOM);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0)->ptr, "type", LINE_BEGIN);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0)->ptr, "type", LINE_END);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", PREV_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", UPARROWKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0)->ptr, "type", FILE_TOP);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", DOWNARROWKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0)->ptr, "type", FILE_BOTTOM);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_ALT, 0)->ptr, "type", DEL_PREV_WORD);
-
- WM_keymap_add_item(keymap, "TEXT_OT_save", SKEY, KM_PRESS, KM_ALT | KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_save_as", SKEY, KM_PRESS, KM_ALT | KM_SHIFT | KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_cut", XKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_find_set_selected", EKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_select_all", AKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_select_line", AKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0);
-#endif
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
- RNA_boolean_set(kmi->ptr, "reverse", false);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
- RNA_boolean_set(kmi->ptr, "reverse", true);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
- RNA_boolean_set(kmi->ptr, "reverse", false);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADMINUS, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
- RNA_boolean_set(kmi->ptr, "reverse", true);
-
- WM_keymap_add_item(keymap, "TEXT_OT_new", NKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_open", OKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_reload", RKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_save", SKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_save_as", SKEY, KM_PRESS, KM_ALT | KM_SHIFT | KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "TEXT_OT_run_script", PKEY, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "TEXT_OT_cut", XKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "TEXT_OT_cut", DELKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_copy", INSERTKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_paste", INSERTKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "TEXT_OT_duplicate_line", DKEY, KM_PRESS, KM_CTRL, 0);
-
- if (U.uiflag & USER_MMB_PASTE) { // XXX not dynamic
- kmi = WM_keymap_add_item(keymap, "TEXT_OT_paste", MIDDLEMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "selection", true);
- }
-
- WM_keymap_add_item(keymap, "TEXT_OT_select_all", AKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_select_line", AKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_select_word", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_lines", UPARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)->ptr, "direction", TXT_MOVE_LINE_UP);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_lines", DOWNARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)->ptr, "direction", TXT_MOVE_LINE_DOWN);
-
- WM_keymap_add_item(keymap, "TEXT_OT_indent", TABKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_unindent", TABKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_uncomment", DKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", EKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", LINE_END);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", EKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", LINE_END);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_PAGE);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_PAGE);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", HOMEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", FILE_TOP);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", ENDKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", FILE_BOTTOM);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", HOMEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", LINE_BEGIN);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", ENDKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", LINE_END);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", LEFTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)->ptr, "type", PREV_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", RIGHTARROWKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)->ptr, "type", NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", UPARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_LINE);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", PREV_PAGE);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", NEXT_PAGE);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", HOMEKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)->ptr, "type", FILE_TOP);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move_select", ENDKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0)->ptr, "type", FILE_BOTTOM);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_CHAR);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", DEL_PREV_CHAR); /* same as above [#26623] */
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", DELKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_WORD);
- RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD);
-
- WM_keymap_add_item(keymap, "TEXT_OT_overwrite_toggle", INSERTKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "TEXT_OT_scroll_bar", LEFTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_scroll_bar", MIDDLEMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "TEXT_OT_scroll", MIDDLEMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_scroll", MOUSEPAN, 0, 0, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_selection_set", EVT_TWEAK_L, KM_ANY, 0, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_cursor_set", LEFTMOUSE, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "TEXT_OT_selection_set", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "select", true);
- RNA_int_set(WM_keymap_add_item(keymap, "TEXT_OT_scroll", WHEELUPMOUSE, KM_PRESS, 0, 0)->ptr, "lines", -1);
- RNA_int_set(WM_keymap_add_item(keymap, "TEXT_OT_scroll", WHEELDOWNMOUSE, KM_PRESS, 0, 0)->ptr, "lines", 1);
-
- WM_keymap_add_item(keymap, "TEXT_OT_line_break", RETKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_line_break", PADENTER, KM_PRESS, 0, 0);
-
- WM_keymap_add_menu(keymap, "TEXT_MT_toolbox", RIGHTMOUSE, KM_PRESS, KM_ANY, 0);
-
- WM_keymap_add_item(keymap, "TEXT_OT_autocomplete", SPACEKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "TEXT_OT_line_number", KM_TEXTINPUT, KM_ANY, KM_ANY, 0);
- WM_keymap_add_item(keymap, "TEXT_OT_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last!
+ WM_keymap_ensure(keyconf, "Text Generic", SPACE_TEXT, 0);
+ WM_keymap_ensure(keyconf, "Text", SPACE_TEXT, 0);
}
const char *text_context_dir[] = {"edit_text", NULL};
@@ -440,7 +293,7 @@ static void text_main_region_draw(const bContext *C, ARegion *ar)
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+ GPU_clear(GPU_COLOR_BIT);
// UI_view2d_view_ortho(v2d);
@@ -469,7 +322,7 @@ static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
/* ************* dropboxes ************* */
-static bool text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
if (drag->type == WM_DRAG_PATH) {
/* rule might not work? */
@@ -486,18 +339,15 @@ static void text_drop_copy(wmDrag *drag, wmDropBox *drop)
RNA_string_set(drop->ptr, "filepath", drag->path);
}
-static bool text_drop_paste_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool text_drop_paste_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
- if (drag->type == WM_DRAG_ID)
- return true;
-
- return false;
+ return (drag->type == WM_DRAG_ID);
}
static void text_drop_paste(wmDrag *drag, wmDropBox *drop)
{
char *text;
- ID *id = drag->poin;
+ ID *id = WM_drag_ID(drag, 0);
/* copy drag path to properties */
text = RNA_path_full_ID_py(id);
@@ -550,7 +400,7 @@ static void text_properties_region_draw(const bContext *C, ARegion *ar)
{
SpaceText *st = CTX_wm_space_text(C);
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
/* this flag trick is make sure buttons have been added already */
if (st->flags & ST_FIND_ACTIVATE) {
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 9a3dcddf804..aa499d52589 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -49,6 +49,9 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -123,38 +126,38 @@ static void txt_format_text(SpaceText *st)
#endif
/* Sets the current drawing color based on the format character specified */
-static void format_draw_color(char formatchar)
+static void format_draw_color(const TextDrawContext *tdc, char formatchar)
{
switch (formatchar) {
case FMT_TYPE_WHITESPACE:
break;
case FMT_TYPE_SYMBOL:
- UI_ThemeColor(TH_SYNTAX_S);
+ UI_FontThemeColor(tdc->font_id, TH_SYNTAX_S);
break;
case FMT_TYPE_COMMENT:
- UI_ThemeColor(TH_SYNTAX_C);
+ UI_FontThemeColor(tdc->font_id, TH_SYNTAX_C);
break;
case FMT_TYPE_NUMERAL:
- UI_ThemeColor(TH_SYNTAX_N);
+ UI_FontThemeColor(tdc->font_id, TH_SYNTAX_N);
break;
case FMT_TYPE_STRING:
- UI_ThemeColor(TH_SYNTAX_L);
+ UI_FontThemeColor(tdc->font_id, TH_SYNTAX_L);
break;
case FMT_TYPE_DIRECTIVE:
- UI_ThemeColor(TH_SYNTAX_D);
+ UI_FontThemeColor(tdc->font_id, TH_SYNTAX_D);
break;
case FMT_TYPE_SPECIAL:
- UI_ThemeColor(TH_SYNTAX_V);
+ UI_FontThemeColor(tdc->font_id, TH_SYNTAX_V);
break;
case FMT_TYPE_RESERVED:
- UI_ThemeColor(TH_SYNTAX_R);
+ UI_FontThemeColor(tdc->font_id, TH_SYNTAX_R);
break;
case FMT_TYPE_KEYWORD:
- UI_ThemeColor(TH_SYNTAX_B);
+ UI_FontThemeColor(tdc->font_id, TH_SYNTAX_B);
break;
case FMT_TYPE_DEFAULT:
default:
- UI_ThemeColor(TH_TEXT);
+ UI_FontThemeColor(tdc->font_id, TH_TEXT);
break;
}
}
@@ -429,7 +432,7 @@ static int text_draw_wrapped(
/* Draw the visible portion of text on the overshot line */
for (a = fstart, ma = mstart; ma < mend; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
if (use_syntax) {
- if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
+ if (fmt_prev != format[a]) format_draw_color(tdc, fmt_prev = format[a]);
}
x += text_font_draw_character_utf8(tdc, x, y, str + ma);
fpos++;
@@ -452,7 +455,7 @@ static int text_draw_wrapped(
/* Draw the remaining text */
for (a = fstart, ma = mstart; str[ma] && y > clip_min_y; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
if (use_syntax) {
- if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
+ if (fmt_prev != format[a]) format_draw_color(tdc, fmt_prev = format[a]);
}
x += text_font_draw_character_utf8(tdc, x, y, str + ma);
@@ -505,7 +508,7 @@ static void text_draw(
char fmt_prev = 0xff;
for (a = 0; a < amount; a++) {
- if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]);
+ if (format[a] != fmt_prev) format_draw_color(tdc, fmt_prev = format[a]);
x += text_font_draw_character_utf8(tdc, x, y, in + str_shift);
str_shift += BLI_str_utf8_size_safe(in + str_shift);
}
@@ -906,22 +909,23 @@ static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back)
{
bTheme *btheme = UI_GetTheme();
uiWidgetColors wcol = btheme->tui.wcol_scroll;
- unsigned char col[4];
+ float col[4];
float rad;
- UI_ThemeColor(TH_BACK);
- glRecti(back->xmin, back->ymin, back->xmax, back->ymax);
+ /* background so highlights don't go behind the scrollbar */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_BACK);
+ immRecti(pos, back->xmin, back->ymin, back->xmax, back->ymax);
+ immUnbindProgram();
UI_draw_widget_scroll(&wcol, scroll, &st->txtbar, (st->flags & ST_SCROLL_SELECT) ? UI_SCROLL_PRESSED : 0);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
rad = 0.4f * min_ii(BLI_rcti_size_x(&st->txtscroll), BLI_rcti_size_y(&st->txtscroll));
- UI_GetThemeColor3ubv(TH_HILITE, col);
- col[3] = 48;
- glColor4ubv(col);
- glEnable(GL_BLEND);
- UI_draw_roundbox(st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad);
- glDisable(GL_BLEND);
+ UI_GetThemeColor3fv(TH_HILITE, col);
+ col[3] = 0.18f;
+ UI_draw_roundbox_aa(true, st->txtscroll.xmin + 1, st->txtscroll.ymin, st->txtscroll.xmax - 1, st->txtscroll.ymax, rad, col);
}
/*********************** draw documentation *******************************/
@@ -963,26 +967,32 @@ static void draw_documentation(const SpaceText *st, ARegion *ar)
boxh = (DOC_HEIGHT + 1) * (st->lheight_dpi + TXT_LINE_SPACING);
/* Draw panel */
- UI_ThemeColor(TH_BACK);
- glRecti(x, y, x + boxw, y - boxh);
- UI_ThemeColor(TH_SHADE1);
- glBegin(GL_LINE_LOOP);
- glVertex2i(x, y);
- glVertex2i(x + boxw, y);
- glVertex2i(x + boxw, y - boxh);
- glVertex2i(x, y - boxh);
- glEnd();
- glBegin(GL_LINE_LOOP);
- glVertex2i(x + boxw - 10, y - 7);
- glVertex2i(x + boxw - 4, y - 7);
- glVertex2i(x + boxw - 7, y - 2);
- glEnd();
- glBegin(GL_LINE_LOOP);
- glVertex2i(x + boxw - 10, y - boxh + 7);
- glVertex2i(x + boxw - 4, y - boxh + 7);
- glVertex2i(x + boxw - 7, y - boxh + 2);
- glEnd();
- UI_ThemeColor(TH_TEXT);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor(TH_BACK);
+ immRecti(pos, x, y, x + boxw, y - boxh);
+ immUniformThemeColor(TH_SHADE1);
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2i(pos, x, y);
+ immVertex2i(pos, x + boxw, y);
+ immVertex2i(pos, x + boxw, y - boxh);
+ immVertex2i(pos, x, y - boxh);
+ immEnd();
+ immBegin(GPU_PRIM_LINE_LOOP, 3);
+ immVertex2i(pos, x + boxw - 10, y - 7);
+ immVertex2i(pos, x + boxw - 4, y - 7);
+ immVertex2i(pos, x + boxw - 7, y - 2);
+ immEnd();
+ immBegin(GPU_PRIM_LINE_LOOP, 3);
+ immVertex2i(pos, x + boxw - 10, y - boxh + 7);
+ immVertex2i(pos, x + boxw - 4, y - boxh + 7);
+ immVertex2i(pos, x + boxw - 7, y - boxh + 2);
+ immEnd();
+
+ immUnbindProgram();
+
+ UI_FontThemeColor(tdc.font_id, TH_TEXT);
i = 0; br = DOC_WIDTH; lines = 0; // XXX -doc_scroll;
for (p = docs; *p; p++) {
@@ -1009,11 +1019,6 @@ static void draw_documentation(const SpaceText *st, ARegion *ar)
}
if (lines >= DOC_HEIGHT) break;
}
-
- if (0 /* XXX doc_scroll*/ /* > 0 && lines < DOC_HEIGHT */) {
- // XXX doc_scroll--;
- draw_documentation(st, ar);
- }
}
#endif
@@ -1061,10 +1066,15 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc
/* not needed but stands out nicer */
UI_draw_box_shadow(220, x, y - boxh, x + boxw, y);
- UI_ThemeColor(TH_SHADE1);
- glRecti(x - 1, y + 1, x + boxw + 1, y - boxh - 1);
- UI_ThemeColorShade(TH_BACK, 16);
- glRecti(x, y, x + boxw, y - boxh);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor(TH_SHADE1);
+ immRecti(pos, x - 1, y + 1, x + boxw + 1, y - boxh - 1);
+ immUniformThemeColorShade(TH_BACK, 16);
+ immRecti(pos, x, y, x + boxw, y - boxh);
+
+ immUnbindProgram();
/* Set the top 'item' of the visible list */
for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ;
@@ -1079,11 +1089,16 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc
w = st->cwidth * text_get_char_pos(st, str, len);
if (item == sel) {
- UI_ThemeColor(TH_SHADE2);
- glRecti(x + margin_x, y - 3, x + margin_x + w, y + lheight - 3);
+ uint posi = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor(TH_SHADE2);
+ immRecti(posi, x + margin_x, y - 3, x + margin_x + w, y + lheight - 3);
+
+ immUnbindProgram();
}
- format_draw_color(item->type);
+ format_draw_color(tdc, item->type);
text_draw(st, tdc, str, 0, 0, x + margin_x, y - 1, NULL);
if (item == last) break;
@@ -1092,42 +1107,57 @@ static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc
/*********************** draw cursor ************************/
-static void draw_cursor(SpaceText *st, ARegion *ar)
+static void draw_text_decoration(SpaceText *st, ARegion *ar)
{
Text *text = st->text;
int vcurl, vcurc, vsell, vselc, hidden = 0;
int x, y, w, i;
+ int offl, offc;
const int lheight = st->lheight_dpi + TXT_LINE_SPACING;
+ /* Convert to view space character coordinates to determine if cursor is hidden */
+ wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
+ vsell = txt_get_span(text->lines.first, text->sell) - st->top + offl;
+ vselc = text_get_char_pos(st, text->sell->line, text->selc) - st->left + offc;
+
+ if (vselc < 0) {
+ vselc = 0;
+ hidden = 1;
+ }
+
+ if (text->curl == text->sell && text->curc == text->selc && !st->line_hlight && hidden) {
+ /* Nothing to draw here */
+ return;
+ }
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
/* Draw the selection */
if (text->curl != text->sell || text->curc != text->selc) {
- int offl, offc;
/* Convert all to view space character coordinates */
wrap_offset(st, ar, text->curl, text->curc, &offl, &offc);
vcurl = txt_get_span(text->lines.first, text->curl) - st->top + offl;
vcurc = text_get_char_pos(st, text->curl->line, text->curc) - st->left + offc;
- wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
- vsell = txt_get_span(text->lines.first, text->sell) - st->top + offl;
- vselc = text_get_char_pos(st, text->sell->line, text->selc) - st->left + offc;
if (vcurc < 0) {
vcurc = 0;
}
- if (vselc < 0) {
- vselc = 0;
- hidden = 1;
- }
- UI_ThemeColor(TH_SHADE2);
+ immUniformThemeColor(TH_SHADE2);
+
x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
y = ar->winy;
if (vcurl == vsell) {
y -= vcurl * lheight;
- if (vcurc < vselc)
- glRecti(x + vcurc * st->cwidth - 1, y, x + vselc * st->cwidth, y - lheight);
- else
- glRecti(x + vselc * st->cwidth - 1, y, x + vcurc * st->cwidth, y - lheight);
+
+ if (vcurc < vselc) {
+ immRecti(pos, x + vcurc * st->cwidth - 1, y, x + vselc * st->cwidth, y - lheight);
+ }
+ else {
+ immRecti(pos, x + vselc * st->cwidth - 1, y, x + vcurc * st->cwidth, y - lheight);
+ }
}
else {
int froml, fromc, tol, toc;
@@ -1143,35 +1173,24 @@ static void draw_cursor(SpaceText *st, ARegion *ar)
y -= froml * lheight;
- glRecti(x + fromc * st->cwidth - 1, y, ar->winx, y - lheight);
+ immRecti(pos, x + fromc * st->cwidth - 1, y, ar->winx, y - lheight);
y -= lheight;
+
for (i = froml + 1; i < tol; i++) {
- glRecti(x - 4, y, ar->winx, y - lheight);
+ immRecti(pos, x - 4, y, ar->winx, y - lheight);
y -= lheight;
}
- glRecti(x - 4, y, x + toc * st->cwidth, y - lheight);
+ immRecti(pos, x - 4, y, x + toc * st->cwidth, y - lheight);
y -= lheight;
}
}
- else {
- int offl, offc;
- wrap_offset(st, ar, text->sell, text->selc, &offl, &offc);
- vsell = txt_get_span(text->lines.first, text->sell) - st->top + offl;
- vselc = text_get_char_pos(st, text->sell->line, text->selc) - st->left + offc;
-
- if (vselc < 0) {
- vselc = 0;
- hidden = 1;
- }
- }
if (st->line_hlight) {
int x1, x2, y1, y2;
if (st->wordwrap) {
int visible_lines = text_get_visible_lines(st, ar, text->sell->line);
- int offl, offc;
wrap_offset_in_line(st, ar, text->sell, text->selc, &offl, &offc);
@@ -1187,12 +1206,12 @@ static void draw_cursor(SpaceText *st, ARegion *ar)
x1 = 0; // st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
x2 = x1 + ar->winx;
- glColor4ub(255, 255, 255, 32);
+ immUniformColor4ub(255, 255, 255, 32);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glRecti(x1 - 4, y1, x2, y2);
- glDisable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ immRecti(pos, x1 - 4, y1, x2, y2);
+ GPU_blend(false);
}
}
@@ -1202,6 +1221,8 @@ static void draw_cursor(SpaceText *st, ARegion *ar)
x += vselc * st->cwidth;
y = ar->winy - vsell * lheight;
+ immUniformThemeColor(TH_HILITE);
+
if (st->overwrite) {
char ch = text->sell->line[text->selc];
@@ -1209,14 +1230,14 @@ static void draw_cursor(SpaceText *st, ARegion *ar)
w = st->cwidth;
if (ch == '\t') w *= st->tabnumber - (vselc + st->left) % st->tabnumber;
- UI_ThemeColor(TH_HILITE);
- glRecti(x, y - lheight - 1, x + w, y - lheight + 1);
+ immRecti(pos, x, y - lheight - 1, x + w, y - lheight + 1);
}
else {
- UI_ThemeColor(TH_HILITE);
- glRecti(x - 1, y, x + 1, y - lheight);
+ immRecti(pos, x - 1, y, x + 1, y - lheight);
}
}
+
+ immUnbindProgram();
}
/******************* draw matching brackets *********************/
@@ -1317,7 +1338,7 @@ static void draw_brackets(const SpaceText *st, const TextDrawContext *tdc, ARegi
if (!endl || endc == -1)
return;
- UI_ThemeColor(TH_HILITE);
+ UI_FontThemeColor(tdc->font_id, TH_HILITE);
x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
y = ar->winy - st->lheight_dpi;
@@ -1422,8 +1443,11 @@ void draw_text_main(SpaceText *st, ARegion *ar)
if (st->showlinenrs) {
x = TXT_OFFSET + TEXTXLOC;
- UI_ThemeColor(TH_GRID);
- glRecti((TXT_OFFSET - 12), 0, (TXT_OFFSET - 5) + TEXTXLOC, ar->winy - 2);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_GRID);
+ immRecti(pos, (TXT_OFFSET - 12), 0, (TXT_OFFSET - 5) + TEXTXLOC, ar->winy - 2);
+ immUnbindProgram();
}
else {
st->linenrs_tot = 0; /* not used */
@@ -1432,11 +1456,11 @@ void draw_text_main(SpaceText *st, ARegion *ar)
y = ar->winy - st->lheight_dpi;
winx = ar->winx - TXT_SCROLL_WIDTH;
- /* draw cursor */
- draw_cursor(st, ar);
+ /* draw cursor, margin, selection and highlight */
+ draw_text_decoration(st, ar);
/* draw the text */
- UI_ThemeColor(TH_TEXT);
+ UI_FontThemeColor(tdc.font_id, TH_TEXT);
for (i = 0; y > clip_min_y && i < st->viewlines && tmp; i++, tmp = tmp->next) {
if (st->showsyntax && !tmp->format)
@@ -1444,16 +1468,20 @@ void draw_text_main(SpaceText *st, ARegion *ar)
if (st->showlinenrs && !wrap_skip) {
/* draw line number */
- if (tmp == text->curl)
- UI_ThemeColor(TH_HILITE);
- else
- UI_ThemeColor(TH_TEXT);
+ if (tmp == text->curl) {
+ UI_FontThemeColor(tdc.font_id, TH_HILITE);
+ }
+ else {
+ UI_FontThemeColor(tdc.font_id, TH_TEXT);
+ }
BLI_snprintf(linenr, sizeof(linenr), "%*d", st->linenrs_tot, i + linecount + 1);
/* itoa(i + linecount + 1, linenr, 10); */ /* not ansi-c :/ */
text_font_draw(&tdc, TXT_OFFSET - 7, y, linenr);
- UI_ThemeColor(TH_TEXT);
+ if (tmp == text->curl) {
+ UI_FontThemeColor(tdc.font_id, TH_TEXT);
+ }
}
if (st->wordwrap) {
@@ -1474,15 +1502,24 @@ void draw_text_main(SpaceText *st, ARegion *ar)
margin_column_x = x + st->cwidth * (st->margin_column - st->left);
if (margin_column_x >= x) {
- /* same color as line number background */
- UI_ThemeColor(TH_GRID);
-
- setlinestyle(1);
- glBegin(GL_LINES);
- glVertex2i(margin_column_x, 0);
- glVertex2i(margin_column_x, ar->winy - 2);
- glEnd();
- setlinestyle(0);
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformThemeColor(TH_GRID); /* same color as line number background */
+ immUniform1f("dash_width", 2.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2i(shdr_pos, margin_column_x, 0);
+ immVertex2i(shdr_pos, margin_column_x, ar->winy - 2);
+ immEnd();
+ immUnbindProgram();
}
}
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index f9bfa45c23a..896b5444a85 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -91,7 +91,7 @@ static int text_properties_exec(bContext *C, wmOperator *UNUSED(op))
void TEXT_OT_properties(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Properties";
+ ot->name = "Toggle Sidebar";
ot->description = "Toggle the properties region visibility";
ot->idname = "TEXT_OT_properties";
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index c483aa180db..61c7b479826 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -698,7 +698,7 @@ static int text_refresh_pyconstraints_exec(bContext *UNUSED(C), wmOperator *UNUS
}
if (update) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
#endif
@@ -1949,7 +1949,7 @@ static int text_jump_exec(bContext *C, wmOperator *op)
static int text_jump_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y);
+ return WM_operator_props_dialog_popup(C, op, 200, 100);
}
@@ -2071,7 +2071,9 @@ void TEXT_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "type", delete_type_items, DEL_NEXT_CHAR, "Type", "Which part of the text to delete");
+ PropertyRNA *prop;
+ prop = RNA_def_enum(ot->srna, "type", delete_type_items, DEL_NEXT_CHAR, "Type", "Which part of the text to delete");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/******************* toggle overwrite operator **********************/
diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c
index 729522cc8f4..b8ae9972eec 100644
--- a/source/blender/editors/space_text/text_undo.c
+++ b/source/blender/editors/space_text/text_undo.c
@@ -37,7 +37,6 @@
#include "PIL_time.h"
#include "BKE_context.h"
-#include "BKE_library.h"
#include "BKE_report.h"
#include "BKE_text.h"
#include "BKE_undo_system.h"
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
deleted file mode 100644
index 29cc5bafb17..00000000000
--- a/source/blender/editors/space_time/space_time.c
+++ /dev/null
@@ -1,834 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_time/space_time.c
- * \ingroup sptime
- */
-
-
-#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"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#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"
-
-#include "ED_anim_api.h"
-#include "ED_keyframes_draw.h"
-#include "ED_screen.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
-#include "UI_resources.h"
-#include "UI_view2d.h"
-#include "UI_interface.h"
-
-#include "ED_space_api.h"
-#include "ED_markers.h"
-
-#include "time_intern.h"
-
-/* ************************ main time area region *********************** */
-
-static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
-{
- /* draw darkened area outside of active timeline
- * frame range used is preview range or scene range
- */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
-
- if (PSFRA < PEFRA) {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
- glRectf((float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
- }
- else {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
- }
- glDisable(GL_BLEND);
-
- UI_ThemeColorShade(TH_BACK, -60);
- /* thin lines where the actual frames are */
- fdrawline((float)PSFRA, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
- fdrawline((float)PEFRA, v2d->cur.ymin, (float)PEFRA, v2d->cur.ymax);
-}
-
-static void time_draw_cache(Main *bmain, SpaceTime *stime, Object *ob, Scene *scene)
-{
- PTCacheID *pid;
- ListBase pidlist;
- SpaceTimeCache *stc = stime->caches.first;
- const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
- float yoffs = 0.f;
-
- if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
- return;
-
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, scene, 0);
-
- /* iterate over pointcaches on the active object,
- * add spacetimecache and vertex array for each */
- for (pid = pidlist.first; pid; pid = pid->next) {
- float col[4], *fp;
- int i, sta = pid->cache->startframe, end = pid->cache->endframe;
- int len = (end - sta + 1) * 4;
-
- switch (pid->type) {
- case PTCACHE_TYPE_SOFTBODY:
- if (!(stime->cache_display & TIME_CACHE_SOFTBODY)) continue;
- break;
- case PTCACHE_TYPE_PARTICLES:
- if (!(stime->cache_display & TIME_CACHE_PARTICLES)) continue;
- break;
- case PTCACHE_TYPE_CLOTH:
- if (!(stime->cache_display & TIME_CACHE_CLOTH)) continue;
- break;
- case PTCACHE_TYPE_SMOKE_DOMAIN:
- case PTCACHE_TYPE_SMOKE_HIGHRES:
- if (!(stime->cache_display & TIME_CACHE_SMOKE)) continue;
- break;
- case PTCACHE_TYPE_DYNAMICPAINT:
- if (!(stime->cache_display & TIME_CACHE_DYNAMICPAINT)) continue;
- break;
- case PTCACHE_TYPE_RIGIDBODY:
- if (!(stime->cache_display & TIME_CACHE_RIGIDBODY)) continue;
- break;
- }
-
- if (pid->cache->cached_frames == NULL)
- continue;
-
- /* make sure we have stc with correct array length */
- if (stc == NULL || MEM_allocN_len(stc->array) != len * 2 * sizeof(float)) {
- if (stc) {
- MEM_freeN(stc->array);
- }
- else {
- stc = MEM_callocN(sizeof(SpaceTimeCache), "spacetimecache");
- BLI_addtail(&stime->caches, stc);
- }
-
- stc->array = MEM_callocN(len * 2 * sizeof(float), "SpaceTimeCache array");
- }
-
- /* fill the vertex array with a quad for each cached frame */
- for (i = sta, fp = stc->array; i <= end; i++) {
- if (pid->cache->cached_frames[i - sta]) {
- fp[0] = (float)i - 0.5f;
- fp[1] = 0.0;
- fp += 2;
-
- fp[0] = (float)i - 0.5f;
- fp[1] = 1.0;
- fp += 2;
-
- fp[0] = (float)i + 0.5f;
- fp[1] = 1.0;
- fp += 2;
-
- fp[0] = (float)i + 0.5f;
- fp[1] = 0.0;
- fp += 2;
- }
- }
-
- glPushMatrix();
- glTranslatef(0.0, (float)V2D_SCROLL_HEIGHT + yoffs, 0.0);
- glScalef(1.0, cache_draw_height, 0.0);
-
- switch (pid->type) {
- case PTCACHE_TYPE_SOFTBODY:
- col[0] = 1.0; col[1] = 0.4; col[2] = 0.02;
- col[3] = 0.1;
- break;
- case PTCACHE_TYPE_PARTICLES:
- col[0] = 1.0; col[1] = 0.1; col[2] = 0.02;
- col[3] = 0.1;
- break;
- case PTCACHE_TYPE_CLOTH:
- col[0] = 0.1; col[1] = 0.1; col[2] = 0.75;
- col[3] = 0.1;
- break;
- case PTCACHE_TYPE_SMOKE_DOMAIN:
- case PTCACHE_TYPE_SMOKE_HIGHRES:
- col[0] = 0.2; col[1] = 0.2; col[2] = 0.2;
- col[3] = 0.1;
- break;
- case PTCACHE_TYPE_DYNAMICPAINT:
- col[0] = 1.0; col[1] = 0.1; col[2] = 0.75;
- col[3] = 0.1;
- break;
- case PTCACHE_TYPE_RIGIDBODY:
- col[0] = 1.0; col[1] = 0.6; col[2] = 0.0;
- col[3] = 0.1;
- break;
- default:
- col[0] = 1.0; col[1] = 0.0; col[2] = 1.0;
- col[3] = 0.1;
- BLI_assert(0);
- break;
- }
- glColor4fv(col);
-
- glEnable(GL_BLEND);
-
- glRectf((float)sta, 0.0, (float)end, 1.0);
-
- col[3] = 0.4f;
- if (pid->cache->flag & PTCACHE_BAKED) {
- col[0] -= 0.4f; col[1] -= 0.4f; col[2] -= 0.4f;
- }
- else if (pid->cache->flag & PTCACHE_OUTDATED) {
- col[0] += 0.4f; col[1] += 0.4f; col[2] += 0.4f;
- }
- glColor4fv(col);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, stc->array);
- glDrawArrays(GL_QUADS, 0, (fp - stc->array) / 2);
- glDisableClientState(GL_VERTEX_ARRAY);
-
- glDisable(GL_BLEND);
-
- glPopMatrix();
-
- yoffs += cache_draw_height;
-
- stc = stc->next;
- }
-
- BLI_freelistN(&pidlist);
-
- /* free excessive caches */
- while (stc) {
- SpaceTimeCache *tmp = stc->next;
- BLI_remlink(&stime->caches, stc);
- MEM_freeN(stc->array);
- MEM_freeN(stc);
- stc = tmp;
- }
-}
-
-static void time_cache_free(SpaceTime *stime)
-{
- SpaceTimeCache *stc;
-
- for (stc = stime->caches.first; stc; stc = stc->next) {
- if (stc->array) {
- MEM_freeN(stc->array);
- stc->array = NULL;
- }
- }
-
- BLI_freelistN(&stime->caches);
-}
-
-static void time_cache_refresh(SpaceTime *stime)
-{
- /* Free previous caches to indicate full refresh */
- time_cache_free(stime);
-}
-
-/* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
-static ActKeyColumn *time_cfra_find_ak(ActKeyColumn *ak, float cframe)
-{
- ActKeyColumn *akn = NULL;
-
- /* sanity checks */
- if (ak == NULL)
- return NULL;
-
- /* check if this is a match, or whether it is in some subtree */
- if (cframe < ak->cfra)
- akn = time_cfra_find_ak(ak->left, cframe);
- else if (cframe > ak->cfra)
- akn = time_cfra_find_ak(ak->right, cframe);
-
- /* if no match found (or found match), just use the current one */
- if (akn == NULL)
- return ak;
- else
- return akn;
-}
-
-/* helper for time_draw_keyframes() */
-static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
-{
- bDopeSheet ads = {NULL};
- DLRBT_Tree keys;
- ActKeyColumn *ak;
-
- float fac1 = (GS(id->name) == ID_GD) ? 0.8f : 0.6f; /* draw GPencil keys taller, to help distinguish them */
- float fac2 = 1.0f - fac1;
-
- float ymin = v2d->tot.ymin;
- float ymax = v2d->tot.ymax * fac1 + ymin * fac2;
-
- /* init binarytree-list for getting keyframes */
- BLI_dlrbTree_init(&keys);
-
- /* init dopesheet settings */
- if (onlysel)
- ads.filterflag |= ADS_FILTER_ONLYSEL;
-
- /* populate tree with keyframe nodes */
- switch (GS(id->name)) {
- case ID_SCE:
- scene_to_keylist(&ads, (Scene *)id, &keys, NULL);
- break;
- case ID_OB:
- ob_to_keylist(&ads, (Object *)id, &keys, NULL);
- break;
- case ID_GD:
- gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
- break;
- case ID_CF:
- cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL);
- break;
- default:
- break;
- }
-
- /* build linked-list for searching */
- BLI_dlrbTree_linkedlist_sync(&keys);
-
- /* start drawing keyframes
- * - we use the binary-search capabilities of the tree to only start from
- * the first visible keyframe (last one can then be easily checked)
- * - draw within a single GL block to be faster
- */
- glBegin(GL_LINES);
- for (ak = time_cfra_find_ak(keys.root, v2d->cur.xmin);
- (ak) && (ak->cfra <= v2d->cur.xmax);
- ak = ak->next)
- {
- glVertex2f(ak->cfra, ymin);
- glVertex2f(ak->cfra, ymax);
- }
- glEnd(); // GL_LINES
-
- /* free temp stuff */
- 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)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- View2D *v2d = &ar->v2d;
- bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0);
-
- /* 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) {
- time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel);
- }
- if (ob && ob->gpd) {
- time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel);
- }
-
- /* draw scene keyframes first
- * - don't try to do this when only drawing active/selected data keyframes,
- * since this can become quite slow
- */
- if (onlysel == 0) {
- /* set draw color */
- UI_ThemeColorShade(TH_TIME_KEYFRAME, -50);
- time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel);
- }
-
- /* draw keyframes from selected objects
- * - only do the active object if in posemode (i.e. showing only keyframes for the bones)
- * OR the onlysel flag was set, which means that only active object's keyframes should
- * be considered
- */
- UI_ThemeColor(TH_TIME_KEYFRAME);
-
- if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) {
- /* draw keyframes for active object only */
- time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel);
- }
- else {
- bool active_done = false;
-
- /* draw keyframes from all selected objects */
- CTX_DATA_BEGIN (C, Object *, obsel, selected_objects)
- {
- /* last arg is 0, since onlysel doesn't apply here... */
- time_draw_idblock_keyframes(v2d, (ID *)obsel, 0);
-
- /* if this object is the active one, set flag so that we don't draw again */
- if (obsel == ob)
- active_done = true;
- }
- CTX_DATA_END;
-
- /* if active object hasn't been done yet, draw it... */
- if (ob && (active_done == 0))
- time_draw_idblock_keyframes(v2d, (ID *)ob, 0);
- }
-}
-
-/* ---------------- */
-
-static void time_refresh(const bContext *UNUSED(C), ScrArea *sa)
-{
- /* find the main timeline region and refresh cache display*/
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar) {
- SpaceTime *stime = (SpaceTime *)sa->spacedata.first;
- time_cache_refresh(stime);
- }
-}
-
-/* editor level listener */
-static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
-{
-
- /* mainly for updating cache display */
- switch (wmn->category) {
- case NC_OBJECT:
- {
- switch (wmn->data) {
- case ND_BONE_SELECT:
- case ND_BONE_ACTIVE:
- case ND_POINTCACHE:
- case ND_MODIFIER:
- case ND_PARTICLE:
- case ND_KEYS:
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
- break;
- }
- break;
- }
- case NC_SCENE:
- {
- switch (wmn->data) {
- case ND_RENDER_RESULT:
- ED_area_tag_redraw(sa);
- break;
- case ND_OB_ACTIVE:
- case ND_FRAME:
- ED_area_tag_refresh(sa);
- break;
- case ND_FRAME_RANGE:
- {
- ARegion *ar;
- Scene *scene = wmn->reference;
-
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_WINDOW) {
- ar->v2d.tot.xmin = (float)(SFRA - 4);
- ar->v2d.tot.xmax = (float)(EFRA + 4);
- break;
- }
- }
- break;
- }
- }
- break;
- }
- case NC_SPACE:
- {
- switch (wmn->data) {
- case ND_SPACE_CHANGED:
- ED_area_tag_refresh(sa);
- break;
- }
- break;
- }
- case NC_WM:
- {
- switch (wmn->data) {
- case ND_FILEREAD:
- ED_area_tag_refresh(sa);
- break;
- }
- break;
- }
- }
-}
-
-/* ---------------- */
-
-/* add handlers, stuff you only do once or on area/region changes */
-static void time_main_region_init(wmWindowManager *wm, ARegion *ar)
-{
- wmKeyMap *keymap;
-
- UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
-
- /* own keymap */
- keymap = WM_keymap_ensure(wm->defaultconf, "Timeline", SPACE_TIME, 0);
- WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
-}
-
-static void time_main_region_draw(const bContext *C, ARegion *ar)
-{
- /* draw entirely, view changes should be handled here */
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- SpaceTime *stime = CTX_wm_space_time(C);
- Object *obact = CTX_data_active_object(C);
- View2D *v2d = &ar->v2d;
- View2DGrid *grid;
- View2DScrollers *scrollers;
- int unit, flag = 0;
-
- /* clear and setup matrix */
- UI_ThemeClearColor(TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
-
- UI_view2d_view_ortho(v2d);
-
- /* grid */
- unit = (stime->flag & TIME_DRAWFRAMES) ? V2D_UNIT_FRAMES : V2D_UNIT_SECONDS;
- grid = UI_view2d_grid_calc(scene, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy);
- UI_view2d_grid_draw(v2d, grid, (V2D_VERTICAL_LINES | V2D_VERTICAL_AXIS));
- UI_view2d_grid_free(grid);
-
- ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
-
- /* start and end frame */
- time_draw_sfra_efra(scene, v2d);
-
- /* current frame */
- flag = DRAWCFRA_WIDE; /* this is only really needed on frames where there's a keyframe, but this will do... */
- if ((stime->flag & TIME_DRAWFRAMES) == 0) flag |= DRAWCFRA_UNIT_SECONDS;
- if (stime->flag & TIME_CFRA_NUM) flag |= DRAWCFRA_SHOW_NUMBOX;
- ANIM_draw_cfra(C, v2d, flag);
-
- UI_view2d_view_ortho(v2d);
-
- /* keyframes */
- time_draw_keyframes(C, ar);
-
- /* markers */
- UI_view2d_view_orthoSpecial(ar, v2d, 1);
- ED_markers_draw(C, 0);
-
- /* caches */
- time_draw_cache(bmain, stime, obact, scene);
-
- /* callback */
- UI_view2d_view_ortho(v2d);
- ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
-
- /* reset view matrix */
- UI_view2d_view_restore(C);
-
- /* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
- UI_view2d_scrollers_draw(C, v2d, scrollers);
- UI_view2d_scrollers_free(scrollers);
-}
-
-static void time_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
-{
- /* context changes */
- switch (wmn->category) {
- case NC_SPACE:
- if (wmn->data == ND_SPACE_TIME)
- ED_region_tag_redraw(ar);
- break;
-
- case NC_ANIMATION:
- ED_region_tag_redraw(ar);
- break;
-
- case NC_SCENE:
- switch (wmn->data) {
- case ND_OB_SELECT:
- case ND_OB_ACTIVE:
- case ND_FRAME:
- case ND_FRAME_RANGE:
- case ND_KEYINGSET:
- case ND_RENDER_OPTIONS:
- ED_region_tag_redraw(ar);
- break;
- }
- break;
- case NC_GPENCIL:
- if (wmn->data == ND_DATA)
- ED_region_tag_redraw(ar);
- break;
- }
-}
-
-/* ************************ header time area region *********************** */
-
-/* add handlers, stuff you only do once or on area/region changes */
-static void time_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
-{
- ED_region_header_init(ar);
-}
-
-static void time_header_region_draw(const bContext *C, ARegion *ar)
-{
- ED_region_header(C, ar);
-}
-
-static void time_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
-{
- /* context changes */
- switch (wmn->category) {
- case NC_SCREEN:
- {
- if (wmn->data == ND_ANIMPLAY)
- ED_region_tag_redraw(ar);
- break;
- }
- case NC_SCENE:
- {
- switch (wmn->data) {
- case ND_RENDER_RESULT:
- case ND_OB_SELECT:
- case ND_FRAME:
- case ND_FRAME_RANGE:
- case ND_KEYINGSET:
- case ND_RENDER_OPTIONS:
- ED_region_tag_redraw(ar);
- break;
- }
- break;
- }
- case NC_SPACE:
- {
- if (wmn->data == ND_SPACE_TIME)
- ED_region_tag_redraw(ar);
- break;
- }
- }
-}
-
-/* ******************** default callbacks for time space ***************** */
-
-static SpaceLink *time_new(const bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
- ARegion *ar;
- SpaceTime *stime;
-
- stime = MEM_callocN(sizeof(SpaceTime), "inittime");
-
- stime->spacetype = SPACE_TIME;
- stime->flag |= TIME_DRAWFRAMES;
-
- /* header */
- ar = MEM_callocN(sizeof(ARegion), "header for time");
-
- BLI_addtail(&stime->regionbase, ar);
- ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
-
- /* main region */
- ar = MEM_callocN(sizeof(ARegion), "main region for time");
-
- BLI_addtail(&stime->regionbase, ar);
- ar->regiontype = RGN_TYPE_WINDOW;
-
- ar->v2d.tot.xmin = (float)(SFRA - 4);
- ar->v2d.tot.ymin = 0.0f;
- ar->v2d.tot.xmax = (float)(EFRA + 4);
- ar->v2d.tot.ymax = 50.0f;
-
- ar->v2d.cur = ar->v2d.tot;
-
- ar->v2d.min[0] = 1.0f;
- ar->v2d.min[1] = 50.0f;
-
- ar->v2d.max[0] = MAXFRAMEF;
- ar->v2d.max[1] = 50.0;
-
- ar->v2d.minzoom = 0.1f;
- ar->v2d.maxzoom = 10.0;
-
- ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL);
- ar->v2d.align |= V2D_ALIGN_NO_NEG_Y;
- ar->v2d.keepofs |= V2D_LOCKOFS_Y;
- ar->v2d.keepzoom |= V2D_LOCKZOOM_Y;
-
-
- return (SpaceLink *)stime;
-}
-
-/* not spacelink itself */
-static void time_free(SpaceLink *sl)
-{
- SpaceTime *stime = (SpaceTime *)sl;
-
- time_cache_free(stime);
-}
-/* spacetype; init callback in ED_area_initialize() */
-/* init is called to (re)initialize an existing editor (file read, screen changes) */
-/* validate spacedata, add own area level handlers */
-static void time_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
-{
- SpaceTime *stime = (SpaceTime *)sa->spacedata.first;
-
- time_cache_free(stime);
-
- /* enable all cache display */
- stime->cache_display |= TIME_CACHE_DISPLAY;
- stime->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
- stime->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
- stime->cache_display |= TIME_CACHE_RIGIDBODY;
-}
-
-static SpaceLink *time_duplicate(SpaceLink *sl)
-{
- SpaceTime *stime = (SpaceTime *)sl;
- SpaceTime *stimen = MEM_dupallocN(stime);
-
- BLI_listbase_clear(&stimen->caches);
-
- return (SpaceLink *)stimen;
-}
-
-/* only called once, from space_api/spacetypes.c */
-/* it defines all callbacks to maintain spaces */
-void ED_spacetype_time(void)
-{
- SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
- ARegionType *art;
-
- st->spaceid = SPACE_TIME;
- strncpy(st->name, "Timeline", BKE_ST_MAXNAME);
-
- st->new = time_new;
- st->free = time_free;
- st->init = time_init;
- st->duplicate = time_duplicate;
- st->operatortypes = time_operatortypes;
- st->keymap = NULL;
- st->listener = time_listener;
- st->refresh = time_refresh;
-
- /* regions: main window */
- art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
- art->regionid = RGN_TYPE_WINDOW;
- art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
-
- art->init = time_main_region_init;
- art->draw = time_main_region_draw;
- art->listener = time_main_region_listener;
- art->keymap = time_keymap;
- art->lock = 1; /* Due to pointcache, see T4960. */
- BLI_addhead(&st->regiontypes, art);
-
- /* regions: header */
- art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
- art->regionid = RGN_TYPE_HEADER;
- art->prefsizey = HEADERY;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
-
- art->init = time_header_region_init;
- art->draw = time_header_region_draw;
- art->listener = time_header_region_listener;
- BLI_addhead(&st->regiontypes, art);
-
- BKE_spacetype_register(st);
-}
diff --git a/source/blender/editors/space_time/time_ops.c b/source/blender/editors/space_time/time_ops.c
deleted file mode 100644
index a68bd2a9fbb..00000000000
--- a/source/blender/editors/space_time/time_ops.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_time/time_ops.c
- * \ingroup sptime
- */
-
-
-#include <stdlib.h>
-#include <math.h>
-
-#include "DNA_scene_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_context.h"
-
-#include "ED_anim_api.h"
-#include "ED_screen.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "time_intern.h"
-
-/* ****************** Start/End Frame Operators *******************************/
-static int time_set_sfra_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- int frame;
-
- if (scene == NULL)
- return OPERATOR_CANCELLED;
-
- frame = CFRA;
-
- /* if Preview Range is defined, set the 'start' frame for that */
- if (PRVRANGEON)
- scene->r.psfra = frame;
- else
- scene->r.sfra = frame;
-
- if (PEFRA < frame) {
- if (PRVRANGEON)
- scene->r.pefra = frame;
- else
- scene->r.efra = frame;
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
-
- return OPERATOR_FINISHED;
-}
-
-static void TIME_OT_start_frame_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Start Frame";
- ot->idname = "TIME_OT_start_frame_set";
- ot->description = "Set the start frame";
-
- /* api callbacks */
- ot->exec = time_set_sfra_exec;
- ot->poll = ED_operator_timeline_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int time_set_efra_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- int frame;
-
- if (scene == NULL)
- return OPERATOR_CANCELLED;
-
- frame = CFRA;
-
- /* if Preview Range is defined, set the 'end' frame for that */
- if (PRVRANGEON)
- scene->r.pefra = frame;
- else
- scene->r.efra = frame;
-
- if (PSFRA > frame) {
- if (PRVRANGEON)
- scene->r.psfra = frame;
- else
- scene->r.sfra = frame;
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
-
- return OPERATOR_FINISHED;
-}
-
-static void TIME_OT_end_frame_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set End Frame";
- ot->idname = "TIME_OT_end_frame_set";
- ot->description = "Set the end frame";
-
- /* api callbacks */
- ot->exec = time_set_efra_exec;
- ot->poll = ED_operator_timeline_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ************************ View All Operator *******************************/
-
-static int time_view_all_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (ELEM(NULL, scene, ar))
- return OPERATOR_CANCELLED;
-
- View2D *v2d = &ar->v2d;
-
- /* set extents of view to start/end frames (Preview Range too) */
- v2d->cur.xmin = (float)PSFRA;
- v2d->cur.xmax = (float)PEFRA;
-
- /* we need an extra "buffer" factor on either side so that the endpoints are visible */
- const float extra = 0.01f * BLI_rctf_size_x(&v2d->cur);
- v2d->cur.xmin -= extra;
- v2d->cur.xmax += extra;
-
- /* this only affects this TimeLine instance, so just force redraw of this region */
- ED_region_tag_redraw(ar);
-
- return OPERATOR_FINISHED;
-}
-
-static void TIME_OT_view_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "View All";
- ot->idname = "TIME_OT_view_all";
- ot->description = "Show the entire playable frame range";
-
- /* api callbacks */
- ot->exec = time_view_all_exec;
- ot->poll = ED_operator_timeline_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ************************ View Frame Operator *******************************/
-
-static int time_view_frame_exec(bContext *C, wmOperator *op)
-{
- const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- ANIM_center_frame(C, smooth_viewtx);
-
- return OPERATOR_FINISHED;
-}
-
-static void TIME_OT_view_frame(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "View Frame";
- ot->idname = "TIME_OT_view_frame";
- ot->description = "Reset viewable area to show range around current frame";
-
- /* api callbacks */
- ot->exec = time_view_frame_exec;
- ot->poll = ED_operator_timeline_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ************************** registration **********************************/
-
-void time_operatortypes(void)
-{
- WM_operatortype_append(TIME_OT_start_frame_set);
- WM_operatortype_append(TIME_OT_end_frame_set);
- WM_operatortype_append(TIME_OT_view_all);
- WM_operatortype_append(TIME_OT_view_frame);
-}
-
-void time_keymap(wmKeyConfig *keyconf)
-{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Timeline", SPACE_TIME, 0);
-
- WM_keymap_add_item(keymap, "TIME_OT_start_frame_set", SKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TIME_OT_end_frame_set", EKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "TIME_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_item(keymap, "TIME_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-#endif
- WM_keymap_add_item(keymap, "TIME_OT_view_frame", PAD0, KM_PRESS, 0, 0);
-}
diff --git a/source/blender/editors/space_time/CMakeLists.txt b/source/blender/editors/space_topbar/CMakeLists.txt
index 90af405eaa8..9559c28de0a 100644
--- a/source/blender/editors/space_time/CMakeLists.txt
+++ b/source/blender/editors/space_topbar/CMakeLists.txt
@@ -22,6 +22,8 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../blenloader
+ ../../blentranslation
../../gpu
../../makesdna
../../makesrna
@@ -35,12 +37,9 @@ set(INC_SYS
)
set(SRC
- space_time.c
- time_ops.c
-
- time_intern.h
+ space_topbar.c
)
add_definitions(${GL_DEFINITIONS})
-blender_add_lib(bf_editor_space_time "${SRC}" "${INC}" "${INC_SYS}")
+blender_add_lib(bf_editor_space_topbar "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
new file mode 100644
index 00000000000..567a733309c
--- /dev/null
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -0,0 +1,294 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_topbar/space_topbar.c
+ * \ingroup sptopbar
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BLO_readfile.h"
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_screen.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_undo.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+
+/* ******************** default callbacks for topbar space ***************** */
+
+static SpaceLink *topbar_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
+{
+ ARegion *ar;
+ SpaceTopBar *stopbar;
+
+ stopbar = MEM_callocN(sizeof(*stopbar), "init topbar");
+ stopbar->spacetype = SPACE_TOPBAR;
+
+ /* header */
+ ar = MEM_callocN(sizeof(ARegion), "left aligned header for topbar");
+ BLI_addtail(&stopbar->regionbase, ar);
+ ar->regiontype = RGN_TYPE_HEADER;
+ ar->alignment = RGN_ALIGN_TOP;
+ ar = MEM_callocN(sizeof(ARegion), "right aligned header for topbar");
+ BLI_addtail(&stopbar->regionbase, ar);
+ ar->regiontype = RGN_TYPE_HEADER;
+ ar->alignment = RGN_ALIGN_RIGHT | RGN_SPLIT_PREV;
+
+ /* main regions */
+ ar = MEM_callocN(sizeof(ARegion), "left aligned main region for topbar");
+ BLI_addtail(&stopbar->regionbase, ar);
+ ar->regiontype = RGN_TYPE_WINDOW;
+ ar->alignment = RGN_ALIGN_LEFT;
+ ar = MEM_callocN(sizeof(ARegion), "right aligned main region for topbar");
+ BLI_addtail(&stopbar->regionbase, ar);
+ ar->regiontype = RGN_TYPE_WINDOW;
+ ar->alignment = RGN_ALIGN_RIGHT;
+ ar = MEM_callocN(sizeof(ARegion), "center main region for topbar");
+ BLI_addtail(&stopbar->regionbase, ar);
+ ar->regiontype = RGN_TYPE_WINDOW;
+
+ return (SpaceLink *)stopbar;
+}
+
+/* not spacelink itself */
+static void topbar_free(SpaceLink *UNUSED(sl))
+{
+
+}
+
+
+/* spacetype; init callback */
+static void topbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+{
+
+}
+
+static SpaceLink *topbar_duplicate(SpaceLink *sl)
+{
+ SpaceTopBar *stopbarn = MEM_dupallocN(sl);
+
+ /* clear or remove stuff from old */
+
+ return (SpaceLink *)stopbarn;
+}
+
+
+
+/* add handlers, stuff you only do once or on area/region changes */
+static void topbar_main_region_init(wmWindowManager *wm, ARegion *region)
+{
+ wmKeyMap *keymap;
+
+ /* force delayed UI_view2d_region_reinit call */
+ if (ELEM(region->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ region->flag |= RGN_FLAG_DYNAMIC_SIZE;
+ }
+ UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_HEADER, region->winx, region->winy);
+
+ keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0);
+ WM_event_add_keymap_handler(&region->handlers, keymap);
+}
+
+static void topbar_operatortypes(void)
+{
+
+}
+
+static void topbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
+{
+
+}
+
+/* add handlers, stuff you only do once or on area/region changes */
+static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+{
+ if ((ar->alignment & ~RGN_SPLIT_PREV) == RGN_ALIGN_RIGHT) {
+ ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
+ }
+ ED_region_header_init(ar);
+}
+
+static void topbar_main_region_listener(wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
+{
+ /* context changes */
+ switch (wmn->category) {
+ case NC_WM:
+ if (wmn->data == ND_HISTORY)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_SCENE:
+ if (wmn->data == ND_MODE)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_SPACE:
+ if (wmn->data == ND_SPACE_VIEW3D)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_GPENCIL:
+ if (wmn->data == ND_DATA)
+ ED_region_tag_redraw(ar);
+ break;
+ }
+}
+
+static void topbar_header_listener(wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
+{
+ /* context changes */
+ switch (wmn->category) {
+ case NC_WM:
+ if (wmn->data == ND_JOB)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_SPACE:
+ if (wmn->data == ND_SPACE_INFO)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_SCREEN:
+ if (wmn->data == ND_LAYER)
+ ED_region_tag_redraw(ar);
+ break;
+ case NC_SCENE:
+ if (wmn->data == ND_SCENEBROWSE)
+ ED_region_tag_redraw(ar);
+ break;
+ }
+}
+
+static void topbar_header_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *workspace, struct Scene *UNUSED(scene),
+ struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ WM_msg_subscribe_rna_prop(
+ mbus, &workspace->id, workspace,
+ WorkSpace, tools, &msg_sub_value_region_tag_redraw);
+}
+
+static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu)
+{
+ struct RecentFile *recent;
+ uiLayout *layout = menu->layout;
+ uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
+ if (!BLI_listbase_is_empty(&G.recent_files)) {
+ for (recent = G.recent_files.first; (recent); recent = recent->next) {
+ const char *file = BLI_path_basename(recent->filepath);
+ const int icon = BLO_has_bfile_extension(file) ? ICON_FILE_BLEND : ICON_FILE_BACKUP;
+ uiItemStringO(layout, file, icon, "WM_OT_open_mainfile", "filepath", recent->filepath);
+ }
+ }
+ else {
+ uiItemL(layout, IFACE_("No Recent Files"), ICON_NONE);
+ }
+}
+
+static void recent_files_menu_register(void)
+{
+ MenuType *mt;
+
+ mt = MEM_callocN(sizeof(MenuType), "spacetype info menu recent files");
+ strcpy(mt->idname, "TOPBAR_MT_file_open_recent");
+ strcpy(mt->label, N_("Open Recent..."));
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = recent_files_menu_draw;
+ WM_menutype_add(mt);
+}
+
+
+/* only called once, from space/spacetypes.c */
+void ED_spacetype_topbar(void)
+{
+ SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar");
+ ARegionType *art;
+
+ st->spaceid = SPACE_TOPBAR;
+ strncpy(st->name, "Top Bar", BKE_ST_MAXNAME);
+
+ st->new = topbar_new;
+ st->free = topbar_free;
+ st->init = topbar_init;
+ st->duplicate = topbar_duplicate;
+ st->operatortypes = topbar_operatortypes;
+ st->keymap = topbar_keymap;
+
+ /* regions: main window */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype topbar main region");
+ art->regionid = RGN_TYPE_WINDOW;
+ art->init = topbar_main_region_init;
+ art->layout = ED_region_header_layout;
+ art->draw = ED_region_header_draw;
+ art->listener = topbar_main_region_listener;
+ art->prefsizex = UI_UNIT_X * 5; /* Mainly to avoid glitches */
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: header */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype topbar header region");
+ art->regionid = RGN_TYPE_HEADER;
+ art->prefsizey = HEADERY;
+ art->prefsizex = UI_UNIT_X * 5; /* Mainly to avoid glitches */
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+ art->listener = topbar_header_listener;
+ art->message_subscribe = topbar_header_region_message_subscribe;
+ art->init = topbar_header_region_init;
+ art->layout = ED_region_header_layout;
+ art->draw = ED_region_header_draw;
+
+ BLI_addhead(&st->regiontypes, art);
+
+ recent_files_menu_register();
+
+ BKE_spacetype_register(st);
+}
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index bf3f1d0dfb3..87da461f269 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -47,11 +47,13 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
/* ******************** default callbacks for userpref space ***************** */
-static SpaceLink *userpref_new(const bContext *UNUSED(C))
+static SpaceLink *userpref_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
ARegion *ar;
SpaceUserPref *spref;
@@ -59,6 +61,13 @@ static SpaceLink *userpref_new(const bContext *UNUSED(C))
spref = MEM_callocN(sizeof(SpaceUserPref), "inituserpref");
spref->spacetype = SPACE_USERPREF;
+ /* navigation region */
+ ar = MEM_callocN(sizeof(ARegion), "navigation region for userpref");
+
+ BLI_addtail(&spref->regionbase, ar);
+ ar->regiontype = RGN_TYPE_NAV_BAR;
+ ar->alignment = RGN_ALIGN_LEFT;
+
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for userpref");
@@ -113,7 +122,7 @@ static void userpref_main_region_init(wmWindowManager *wm, ARegion *ar)
static void userpref_main_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels(C, ar);
}
static void userpref_operatortypes(void)
@@ -136,12 +145,29 @@ static void userpref_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-static void userpref_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+/* add handlers, stuff you only do once or on area/region changes */
+static void userpref_navigation_region_init(wmWindowManager *wm, ARegion *ar)
+{
+ ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
+
+ ED_region_panels_init(wm, ar);
+}
+
+static void userpref_navigation_region_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_panels(C, ar);
+}
+
+static void userpref_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
/* context changes */
}
-static void userpref_header_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void userpref_header_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
{
/* context changes */
#if 0
@@ -152,6 +178,13 @@ static void userpref_header_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), A
#endif
}
+static void userpref_navigation_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
+ wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
+{
+ /* context changes */
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_userpref(void)
{
@@ -189,6 +222,17 @@ void ED_spacetype_userpref(void)
BLI_addhead(&st->regiontypes, art);
+ /* regions: navigation window */
+ art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region");
+ art->regionid = RGN_TYPE_NAV_BAR;
+ art->prefsizex = UI_NAVIGATION_REGION_WIDTH;
+ art->init = userpref_navigation_region_init;
+ art->draw = userpref_navigation_region_draw;
+ art->listener = userpref_navigation_region_listener;
+ art->keymapflag = ED_KEYMAP_UI;
+
+ BLI_addhead(&st->regiontypes, art);
+
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index e25a9c04f15..0d30d623b8d 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../draw
../../gpu
../../imbuf
../../makesdna
@@ -42,21 +43,27 @@ set(INC_SYS
)
set(SRC
- drawanimviz.c
- drawarmature.c
- drawmesh.c
drawobject.c
- drawsimdebug.c
- drawvolume.c
space_view3d.c
view3d_buttons.c
view3d_camera_control.c
view3d_draw.c
+ view3d_draw_legacy.c
view3d_edit.c
view3d_fly.c
view3d_walk.c
view3d_header.c
view3d_iterators.c
+ view3d_gizmo_armature.c
+ view3d_gizmo_camera.c
+ view3d_gizmo_empty.c
+ view3d_gizmo_forcefield.c
+ view3d_gizmo_lamp.c
+ view3d_gizmo_navigate.c
+ view3d_gizmo_navigate_type.c
+ view3d_gizmo_ruler.c
+ view3d_gizmo_preselect.c
+ view3d_gizmo_preselect_type.c
view3d_ops.c
view3d_project.c
view3d_ruler.c
@@ -74,13 +81,6 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
-if(WITH_GAMEENGINE)
- list(APPEND INC
- ../../../gameengine/BlenderRoutines
- )
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
add_definitions(${GL_DEFINITIONS})
if(WITH_INTERNATIONAL)
@@ -95,8 +95,4 @@ if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
endif()
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
-endif()
-
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
deleted file mode 100644
index e2e71207738..00000000000
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * ***** 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) 2009 by the Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Joshua Leung
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_view3d/drawanimviz.c
- * \ingroup spview3d
- */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "BLI_sys_types.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math.h"
-#include "BLI_dlrbTree.h"
-
-#include "BKE_animsys.h"
-#include "BKE_action.h"
-
-#include "BIF_gl.h"
-
-#include "ED_keyframes_draw.h"
-
-
-#include "UI_resources.h"
-
-#include "view3d_intern.h"
-
-/* ************************************ Motion Paths ************************************* */
-
-/* TODO:
- * - options to draw paths with lines
- * - include support for editing the path verts */
-
-/* Set up drawing environment for drawing motion paths */
-void draw_motion_paths_init(View3D *v3d, ARegion *ar)
-{
- RegionView3D *rv3d = ar->regiondata;
-
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
-}
-
-/* set color
- * - more intense for active/selected bones, less intense for unselected bones
- * - black for before current frame, green for current frame, blue for after current frame
- * - intensity decreases as distance from current frame increases
- *
- * If the user select custom color, the color is replaced for the color selected in UI panel
- * - 75% Darker color is used for previous frames
- * - 50% Darker color for current frame
- * - User selected color for next frames
- */
-static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra,
- float prev_color[3], float frame_color[3], float next_color[3])
-{
- int frame = sfra + i;
- int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */
-
-#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min)
- float intensity; /* how faint */
-
- if (frame < CFRA) {
- if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
- /* Custom color: previous frames color is darker than current frame */
- glColor3fv(prev_color);
- }
- else {
- /* black - before cfra */
- if (sel) {
- /* intensity = 0.5f; */
- intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f);
- }
- else {
- /* intensity = 0.8f; */
- intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f);
- }
- UI_ThemeColorBlend(TH_WIRE, blend_base, intensity);
- }
- }
- else if (frame > CFRA) {
- if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
- /* Custom color: next frames color is equal to user selected color */
- glColor3fv(next_color);
- }
- else {
- /* blue - after cfra */
- if (sel) {
- /* intensity = 0.5f; */
- intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f);
- }
- else {
- /* intensity = 0.8f; */
- intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f);
- }
- UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity);
- }
- }
- else {
- if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
- /* Custom color: current frame color is slightly darker than user selected color */
- glColor3fv(frame_color);
- }
- else {
- /* green - on cfra */
- if (sel) {
- intensity = 0.5f;
- }
- else {
- intensity = 0.99f;
- }
- UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10);
- }
- }
-#undef SET_INTENSITY
-}
-
-/* Draw the given motion path for an Object or a Bone
- * - assumes that the viewport has already been initialized properly
- * i.e. draw_motion_paths_init() has been called
- */
-void draw_motion_path_instance(Scene *scene,
- Object *ob, bPoseChannel *pchan, bAnimVizSettings *avs, bMotionPath *mpath)
-{
- //RegionView3D *rv3d = ar->regiondata;
- bMotionPathVert *mpv, *mpv_start;
- int i, stepsize = avs->path_step;
- int sfra, efra, sind, len;
- float prev_color[3];
- float frame_color[3];
- float next_color[3];
-
- /* Custom color - Previous frames: color is darker than current frame */
- prev_color[0] = mpath->color[0] * 0.25f;
- prev_color[1] = mpath->color[1] * 0.25f;
- prev_color[2] = mpath->color[2] * 0.25f;
-
- /* Custom color - Current frame: color is slightly darker than user selected color */
- frame_color[0] = mpath->color[0] * 0.50f;
- frame_color[1] = mpath->color[1] * 0.50f;
- frame_color[2] = mpath->color[2] * 0.50f;
-
- /* Custom color - Next frames: color is equal to user selection */
- next_color[0] = mpath->color[0];
- next_color[1] = mpath->color[1];
- next_color[2] = mpath->color[2];
-
- /* Save old line width */
- GLfloat old_width;
- glGetFloatv(GL_LINE_WIDTH, &old_width);
-
- /* get frame ranges */
- if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
- /* With "Around Current", we only choose frames from around
- * the current frame to draw.
- */
- sfra = CFRA - avs->path_bc;
- efra = CFRA + avs->path_ac;
- }
- else {
- /* Use the current display range */
- sfra = avs->path_sf;
- efra = avs->path_ef;
- }
-
- /* no matter what, we can only show what is in the cache and no more
- * - abort if whole range is past ends of path
- * - otherwise clamp endpoints to extents of path
- */
- if (sfra < mpath->start_frame) {
- /* start clamp */
- sfra = mpath->start_frame;
- }
- if (efra > mpath->end_frame) {
- /* end clamp */
- efra = mpath->end_frame;
- }
-
- if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) {
- /* whole path is out of bounds */
- return;
- }
-
- len = efra - sfra;
-
- if ((len <= 0) || (mpath->points == NULL)) {
- return;
- }
-
- /* get pointers to parts of path */
- sind = sfra - mpath->start_frame;
- mpv_start = (mpath->points + sind);
-
- /* draw curve-line of path */
- /* Draw lines only if line drawing option is enabled */
- if (mpath->flag & MOTIONPATH_FLAG_LINES) {
- /* set line thickness */
- glLineWidth(mpath->line_thickness);
-
- glBegin(GL_LINE_STRIP);
- for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
- short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT);
- /* Set color */
- set_motion_path_color(scene, mpath, i, sel, sfra, efra, prev_color, frame_color, next_color);
- /* draw a vertex with this color */
- glVertex3fv(mpv->co);
- }
-
- glEnd();
- /* back to old line thickness */
- glLineWidth(old_width);
- }
-
- /* Point must be bigger than line thickness */
- glPointSize(mpath->line_thickness + 1.0);
-
- /* draw little black point at each frame
- * NOTE: this is not really visible/noticeable
- */
- glBegin(GL_POINTS);
- for (i = 0, mpv = mpv_start; i < len; i++, mpv++)
- glVertex3fv(mpv->co);
- glEnd();
-
- /* Draw little white dots at each framestep value or replace with custom color */
- if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
- glColor4fv(mpath->color);
- }
- else {
- UI_ThemeColor(TH_TEXT_HI);
- }
- glBegin(GL_POINTS);
- for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize)
- glVertex3fv(mpv->co);
- glEnd();
-
- /* Draw big green dot where the current frame is
- * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter
- */
- if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) &&
- (sfra < CFRA) && (CFRA <= efra))
- {
- UI_ThemeColor(TH_CFRAME);
-
- glPointSize(mpath->line_thickness + 5.0);
- glBegin(GL_POINTS);
- mpv = mpv_start + (CFRA - sfra);
- glVertex3fv(mpv->co);
- glEnd();
-
- UI_ThemeColor(TH_TEXT_HI);
- }
-
- /* XXX, this isn't up to date but probably should be kept so. */
- invert_m4_m4(ob->imat, ob->obmat);
-
- /* Draw frame numbers at each framestep value */
- if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) {
- unsigned char col[4];
- UI_GetThemeColor3ubv(TH_TEXT_HI, col);
- col[3] = 255;
-
- for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) {
- int frame = sfra + i;
- char numstr[32];
- size_t numstr_len;
- float co[3];
-
- /* only draw framenum if several consecutive highlighted points don't occur on same point */
- if (i == 0) {
- numstr_len = sprintf(numstr, " %d", frame);
- mul_v3_m4v3(co, ob->imat, mpv->co);
- view3d_cached_text_draw_add(co, numstr, numstr_len,
- 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col);
- }
- else if ((i >= stepsize) && (i < len - stepsize)) {
- bMotionPathVert *mpvP = (mpv - stepsize);
- bMotionPathVert *mpvN = (mpv + stepsize);
-
- if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
- numstr_len = sprintf(numstr, " %d", frame);
- mul_v3_m4v3(co, ob->imat, mpv->co);
- view3d_cached_text_draw_add(co, numstr, numstr_len,
- 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col);
- }
- }
- }
- }
-
- /* Keyframes - dots and numbers */
- if (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) {
- unsigned char col[4];
-
- AnimData *adt = BKE_animdata_from_id(&ob->id);
- DLRBT_Tree keys;
-
- /* build list of all keyframes in active action for object or pchan */
- BLI_dlrbTree_init(&keys);
-
- if (adt) {
- /* it is assumed that keyframes for bones are all grouped in a single group
- * unless an option is set to always use the whole action
- */
- if ((pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) {
- bActionGroup *agrp = BKE_action_group_find_name(adt->action, pchan->name);
-
- if (agrp) {
- agroup_to_keylist(adt, agrp, &keys, NULL);
- BLI_dlrbTree_linkedlist_sync(&keys);
- }
- }
- else {
- action_to_keylist(adt, adt->action, &keys, NULL);
- BLI_dlrbTree_linkedlist_sync(&keys);
- }
- }
-
- /* Draw slightly-larger yellow dots at each keyframe */
- UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
- col[3] = 255;
-
- /* if custom, point must be bigger than line */
- if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) {
- glPointSize(mpath->line_thickness + 3.0);
- }
- else {
- glPointSize(4.0f);
- }
- glColor3ubv(col);
-
- glBegin(GL_POINTS);
- for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
- int frame = sfra + i;
- float mframe = (float)(frame);
-
- if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe))
- glVertex3fv(mpv->co);
- }
- glEnd();
-
- /* Draw frame numbers of keyframes */
- if (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) {
- float co[3];
- for (i = 0, mpv = mpv_start; i < len; i++, mpv++) {
- float mframe = (float)(sfra + i);
-
- if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) {
- char numstr[32];
- size_t numstr_len;
-
- numstr_len = sprintf(numstr, " %d", (sfra + i));
- mul_v3_m4v3(co, ob->imat, mpv->co);
- view3d_cached_text_draw_add(co, numstr, numstr_len,
- 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col);
- }
- }
- }
-
- BLI_dlrbTree_free(&keys);
- }
-}
-
-/* Clean up drawing environment after drawing motion paths */
-void draw_motion_paths_cleanup(View3D *v3d)
-{
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- glPopMatrix();
-}
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
deleted file mode 100644
index ec15725d635..00000000000
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ /dev/null
@@ -1,2793 +0,0 @@
-/*
- * ***** 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) 2005 by the Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_view3d/drawarmature.c
- * \ingroup spview3d
- */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_dlrbTree.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_animsys.h"
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_global.h"
-#include "BKE_modifier.h"
-#include "BKE_nla.h"
-#include "BKE_curve.h"
-
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
-#include "ED_armature.h"
-#include "ED_keyframes_draw.h"
-
-#include "GPU_basic_shader.h"
-
-#include "UI_resources.h"
-
-#include "view3d_intern.h"
-
-#include "GPU_select.h"
-
-/* *************** Armature Drawing - Coloring API ***************************** */
-
-/* global here is reset before drawing each bone */
-static ThemeWireColor *bcolor = NULL;
-
-/* values of colCode for set_pchan_glcolor */
-enum {
- PCHAN_COLOR_NORMAL = 0, /* normal drawing */
- PCHAN_COLOR_SOLID, /* specific case where "solid" color is needed */
- PCHAN_COLOR_CONSTS, /* "constraint" colors (which may/may-not be suppressed) */
-
- PCHAN_COLOR_SPHEREBONE_BASE, /* for the 'stick' of sphere (envelope) bones */
- PCHAN_COLOR_SPHEREBONE_END, /* for the ends of sphere (envelope) bones */
- PCHAN_COLOR_LINEBONE /* for the middle of line-bones */
-};
-
-/* This function sets the color-set for coloring a certain bone */
-static void set_pchan_colorset(Object *ob, bPoseChannel *pchan)
-{
- bPose *pose = (ob) ? ob->pose : NULL;
- bArmature *arm = (ob) ? ob->data : NULL;
- bActionGroup *grp = NULL;
- short color_index = 0;
-
- /* sanity check */
- if (ELEM(NULL, ob, arm, pose, pchan)) {
- bcolor = NULL;
- return;
- }
-
- /* only try to set custom color if enabled for armature */
- if (arm->flag & ARM_COL_CUSTOM) {
- /* currently, a bone can only use a custom color set if it's group (if it has one),
- * has been set to use one
- */
- if (pchan->agrp_index) {
- grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
- if (grp)
- color_index = grp->customCol;
- }
- }
-
- /* bcolor is a pointer to the color set to use. If NULL, then the default
- * color set (based on the theme colors for 3d-view) is used.
- */
- if (color_index > 0) {
- bTheme *btheme = UI_GetTheme();
- bcolor = &btheme->tarm[(color_index - 1)];
- }
- else if (color_index == -1) {
- /* use the group's own custom color set (grp is always != NULL here) */
- bcolor = &grp->cs;
- }
- else {
- bcolor = NULL;
- }
-}
-
-/* This function is for brightening/darkening a given color (like UI_ThemeColorShade()) */
-static void cp_shade_color3ub(unsigned char cp[3], const int offset)
-{
- int r, g, b;
-
- r = offset + (int) cp[0];
- CLAMP(r, 0, 255);
- g = offset + (int) cp[1];
- CLAMP(g, 0, 255);
- b = offset + (int) cp[2];
- CLAMP(b, 0, 255);
-
- cp[0] = r;
- cp[1] = g;
- cp[2] = b;
-}
-
-/* This function sets the gl-color for coloring a certain bone (based on bcolor) */
-static bool set_pchan_glColor(short colCode, int boneflag, short constflag)
-{
- switch (colCode) {
- case PCHAN_COLOR_NORMAL:
- {
- if (bcolor) {
- unsigned char cp[3];
-
- if (boneflag & BONE_DRAW_ACTIVE) {
- copy_v3_v3_char((char *)cp, bcolor->active);
- if (!(boneflag & BONE_SELECTED)) {
- cp_shade_color3ub(cp, -80);
- }
- }
- else if (boneflag & BONE_SELECTED) {
- copy_v3_v3_char((char *)cp, bcolor->select);
- }
- else {
- /* a bit darker than solid */
- copy_v3_v3_char((char *)cp, bcolor->solid);
- cp_shade_color3ub(cp, -50);
- }
-
- glColor3ubv(cp);
- }
- else {
- if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
- UI_ThemeColor(TH_BONE_POSE_ACTIVE);
- }
- else if (boneflag & BONE_DRAW_ACTIVE) {
- UI_ThemeColorBlend(TH_WIRE, TH_BONE_POSE, 0.15f); /* unselected active */
- }
- else if (boneflag & BONE_SELECTED) {
- UI_ThemeColor(TH_BONE_POSE);
- }
- else {
- UI_ThemeColor(TH_WIRE);
- }
- }
-
- return true;
- }
- case PCHAN_COLOR_SOLID:
- {
- if (bcolor) {
- glColor3ubv((unsigned char *)bcolor->solid);
- }
- else
- UI_ThemeColor(TH_BONE_SOLID);
-
- return true;
- }
- case PCHAN_COLOR_CONSTS:
- {
- if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) {
- if (constflag & PCHAN_HAS_TARGET) glColor4ub(255, 150, 0, 80);
- else if (constflag & PCHAN_HAS_IK) glColor4ub(255, 255, 0, 80);
- else if (constflag & PCHAN_HAS_SPLINEIK) glColor4ub(200, 255, 0, 80);
- else if (constflag & PCHAN_HAS_CONST) glColor4ub(0, 255, 120, 80);
-
- return true;
- }
- return false;
- }
- case PCHAN_COLOR_SPHEREBONE_BASE:
- {
- if (bcolor) {
- unsigned char cp[3];
-
- if (boneflag & BONE_DRAW_ACTIVE) {
- copy_v3_v3_char((char *)cp, bcolor->active);
- }
- else if (boneflag & BONE_SELECTED) {
- copy_v3_v3_char((char *)cp, bcolor->select);
- }
- else {
- copy_v3_v3_char((char *)cp, bcolor->solid);
- }
-
- glColor3ubv(cp);
- }
- else {
- if (boneflag & BONE_DRAW_ACTIVE) UI_ThemeColorShade(TH_BONE_POSE, 40);
- else if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_BONE_POSE);
- else UI_ThemeColor(TH_BONE_SOLID);
- }
-
- return true;
- }
- case PCHAN_COLOR_SPHEREBONE_END:
- {
- if (bcolor) {
- unsigned char cp[3];
-
- if (boneflag & BONE_DRAW_ACTIVE) {
- copy_v3_v3_char((char *)cp, bcolor->active);
- cp_shade_color3ub(cp, 10);
- }
- else if (boneflag & BONE_SELECTED) {
- copy_v3_v3_char((char *)cp, bcolor->select);
- cp_shade_color3ub(cp, -30);
- }
- else {
- copy_v3_v3_char((char *)cp, bcolor->solid);
- cp_shade_color3ub(cp, -30);
- }
-
- glColor3ubv(cp);
- }
- else {
- if (boneflag & BONE_DRAW_ACTIVE) UI_ThemeColorShade(TH_BONE_POSE, 10);
- else if (boneflag & BONE_SELECTED) UI_ThemeColorShade(TH_BONE_POSE, -30);
- else UI_ThemeColorShade(TH_BONE_SOLID, -30);
- }
- break;
- }
- case PCHAN_COLOR_LINEBONE:
- {
- /* inner part in background color or constraint */
- if ((constflag) && ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS))) {
- if (constflag & PCHAN_HAS_TARGET) glColor3ub(255, 150, 0);
- else if (constflag & PCHAN_HAS_IK) glColor3ub(255, 255, 0);
- else if (constflag & PCHAN_HAS_SPLINEIK) glColor3ub(200, 255, 0);
- else if (constflag & PCHAN_HAS_CONST) glColor3ub(0, 255, 120);
- else if (constflag) UI_ThemeColor(TH_BONE_POSE); /* PCHAN_HAS_ACTION */
- }
- else {
- if (bcolor) {
- const char *cp = bcolor->solid;
- glColor4ub(cp[0], cp[1], cp[2], 204);
- }
- else
- UI_ThemeColorShade(TH_BACK, -30);
- }
-
- return true;
- }
- }
-
- return false;
-}
-
-static void set_ebone_glColor(const unsigned int boneflag)
-{
- if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
- UI_ThemeColor(TH_EDGE_SELECT);
- }
- else if (boneflag & BONE_DRAW_ACTIVE) {
- UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f); /* unselected active */
- }
- else if (boneflag & BONE_SELECTED) {
- UI_ThemeColorShade(TH_EDGE_SELECT, -20);
- }
- else {
- UI_ThemeColor(TH_WIRE_EDIT);
- }
-}
-
-/* *************** Armature drawing, helper calls for parts ******************* */
-
-/* half the cube, in Y */
-static const float cube[8][3] = {
- {-1.0, 0.0, -1.0},
- {-1.0, 0.0, 1.0},
- {-1.0, 1.0, 1.0},
- {-1.0, 1.0, -1.0},
- { 1.0, 0.0, -1.0},
- { 1.0, 0.0, 1.0},
- { 1.0, 1.0, 1.0},
- { 1.0, 1.0, -1.0},
-};
-
-static void drawsolidcube_size(float xsize, float ysize, float zsize)
-{
- static GLuint displist = 0;
- float n[3] = {0.0f};
-
- glScalef(xsize, ysize, zsize);
-
- if (displist == 0) {
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- glBegin(GL_QUADS);
- n[0] = -1.0;
- glNormal3fv(n);
- glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
- n[0] = 0;
- n[1] = -1.0;
- glNormal3fv(n);
- glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
- n[1] = 0;
- n[0] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
- n[0] = 0;
- n[1] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
- n[1] = 0;
- n[2] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
- n[2] = -1.0;
- glNormal3fv(n);
- glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
- glEnd();
-
- glEndList();
- }
-
- glCallList(displist);
-}
-
-static void drawcube_size(float xsize, float ysize, float zsize)
-{
- static GLuint displist = 0;
-
- if (displist == 0) {
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- glBegin(GL_LINE_STRIP);
- glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
- glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
- glVertex3fv(cube[7]); glVertex3fv(cube[4]);
- glEnd();
-
- glBegin(GL_LINES);
- glVertex3fv(cube[1]); glVertex3fv(cube[5]);
- glVertex3fv(cube[2]); glVertex3fv(cube[6]);
- glVertex3fv(cube[3]); glVertex3fv(cube[7]);
- glEnd();
-
- glEndList();
- }
-
- glScalef(xsize, ysize, zsize);
- glCallList(displist);
-
-}
-
-
-static void draw_bonevert(void)
-{
- static GLuint displist = 0;
-
- if (displist == 0) {
- GLUquadricObj *qobj;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- glPushMatrix();
-
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
- gluDisk(qobj, 0.0, 0.05, 16, 1);
-
- glRotatef(90, 0, 1, 0);
- gluDisk(qobj, 0.0, 0.05, 16, 1);
-
- glRotatef(90, 1, 0, 0);
- gluDisk(qobj, 0.0, 0.05, 16, 1);
-
- gluDeleteQuadric(qobj);
-
- glPopMatrix();
- glEndList();
- }
-
- glCallList(displist);
-}
-
-static void draw_bonevert_solid(void)
-{
- static GLuint displist = 0;
-
- if (displist == 0) {
- GLUquadricObj *qobj;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
- /* Draw tips of a bone */
- gluSphere(qobj, 0.05, 8, 5);
- gluDeleteQuadric(qobj);
-
- glEndList();
- }
-
- glCallList(displist);
-}
-
-static const float bone_octahedral_verts[6][3] = {
- { 0.0f, 0.0f, 0.0f},
- { 0.1f, 0.1f, 0.1f},
- { 0.1f, 0.1f, -0.1f},
- {-0.1f, 0.1f, -0.1f},
- {-0.1f, 0.1f, 0.1f},
- { 0.0f, 1.0f, 0.0f}
-};
-
-static const unsigned int bone_octahedral_wire_sides[8] = {0, 1, 5, 3, 0, 4, 5, 2};
-static const unsigned int bone_octahedral_wire_square[8] = {1, 2, 3, 4, 1};
-
-static const unsigned int bone_octahedral_solid_tris[8][3] = {
- {2, 1, 0}, /* bottom */
- {3, 2, 0},
- {4, 3, 0},
- {1, 4, 0},
-
- {5, 1, 2}, /* top */
- {5, 2, 3},
- {5, 3, 4},
- {5, 4, 1}
-};
-
-/* aligned with bone_octahedral_solid_tris */
-static const float bone_octahedral_solid_normals[8][3] = {
- { M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
- {-0.00000000f, -M_SQRT1_2, -M_SQRT1_2},
- {-M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
- { 0.00000000f, -M_SQRT1_2, M_SQRT1_2},
- { 0.99388373f, 0.11043154f, -0.00000000f},
- { 0.00000000f, 0.11043154f, -0.99388373f},
- {-0.99388373f, 0.11043154f, 0.00000000f},
- { 0.00000000f, 0.11043154f, 0.99388373f}
-};
-
-static void draw_bone_octahedral(void)
-{
- static GLuint displist = 0;
-
- if (displist == 0) {
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- /* Section 1, sides */
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, bone_octahedral_verts);
- glDrawElements(GL_LINE_LOOP,
- sizeof(bone_octahedral_wire_sides) / sizeof(*bone_octahedral_wire_sides),
- GL_UNSIGNED_INT,
- bone_octahedral_wire_sides);
-
- /* Section 1, square */
- glDrawElements(GL_LINE_LOOP,
- sizeof(bone_octahedral_wire_square) / sizeof(*bone_octahedral_wire_square),
- GL_UNSIGNED_INT,
- bone_octahedral_wire_square);
- glDisableClientState(GL_VERTEX_ARRAY);
-
- glEndList();
- }
-
- glCallList(displist);
-}
-
-static void draw_bone_solid_octahedral(void)
-{
- static GLuint displist = 0;
-
- if (displist == 0) {
- int i;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
-#if 1
- glBegin(GL_TRIANGLES);
- for (i = 0; i < 8; i++) {
- glNormal3fv(bone_octahedral_solid_normals[i]);
- glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][0]]);
- glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][1]]);
- glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][2]]);
- }
-
- glEnd();
-
-#else /* not working because each vert needs a different normal */
- glEnableClientState(GL_NORMAL_ARRAY);
- glEnableClientState(GL_VERTEX_ARRAY);
- glNormalPointer(GL_FLOAT, 0, bone_octahedral_solid_normals);
- glVertexPointer(3, GL_FLOAT, 0, bone_octahedral_verts);
- glDrawElements(GL_TRIANGLES, sizeof(bone_octahedral_solid_tris) / sizeof(unsigned int),
- GL_UNSIGNED_INT, bone_octahedral_solid_tris);
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
-#endif
-
- glEndList();
- }
-
- glCallList(displist);
-}
-
-/* *************** Armature drawing, bones ******************* */
-
-
-static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, int id)
-{
- /* Draw root point if we are not connected */
- if ((boneflag & BONE_CONNECTED) == 0) {
- if (id != -1)
- GPU_select_load_id(id | BONESEL_ROOT);
-
- if (dt <= OB_WIRE) {
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
- }
- }
- else {
- if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, 0);
- else
- UI_ThemeColor(TH_BONE_SOLID);
- }
-
- if (dt > OB_WIRE)
- draw_bonevert_solid();
- else
- draw_bonevert();
- }
-
- /* Draw tip point */
- if (id != -1)
- GPU_select_load_id(id | BONESEL_TIP);
-
- if (dt <= OB_WIRE) {
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
- }
- }
- else {
- if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, 0);
- else
- UI_ThemeColor(TH_BONE_SOLID);
- }
-
- glTranslatef(0.0f, 1.0f, 0.0f);
- if (dt > OB_WIRE)
- draw_bonevert_solid();
- else
- draw_bonevert();
- glTranslatef(0.0f, -1.0f, 0.0f);
-
-}
-
-/* 16 values of sin function (still same result!) */
-static const float si[16] = {
- 0.00000000f,
- 0.20129852f, 0.39435585f,
- 0.57126821f, 0.72479278f,
- 0.84864425f, 0.93775213f,
- 0.98846832f, 0.99871650f,
- 0.96807711f, 0.89780453f,
- 0.79077573f, 0.65137248f,
- 0.48530196f, 0.29936312f,
- 0.10116832f
-};
-/* 16 values of cos function (still same result!) */
-static const float co[16] = {
- 1.00000000f,
- 0.97952994f, 0.91895781f,
- 0.82076344f, 0.68896691f,
- 0.52896401f, 0.34730525f,
- 0.15142777f, -0.05064916f,
- -0.25065253f, -0.44039415f,
- -0.61210598f, -0.75875812f,
- -0.87434661f, -0.95413925f,
- -0.99486932f
-};
-
-
-
-/* smat, imat = mat & imat to draw screenaligned */
-static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChannel *pchan, EditBone *ebone)
-{
- float head, tail, dist /*, length*/;
- float *headvec, *tailvec, dirvec[3];
-
- /* figure out the sizes of spheres */
- if (ebone) {
- /* this routine doesn't call get_matrix_editbone() that calculates it */
- ebone->length = len_v3v3(ebone->head, ebone->tail);
-
- /*length = ebone->length;*/ /*UNUSED*/
- tail = ebone->rad_tail;
- dist = ebone->dist;
- if (ebone->parent && (ebone->flag & BONE_CONNECTED))
- head = ebone->parent->rad_tail;
- else
- head = ebone->rad_head;
- headvec = ebone->head;
- tailvec = ebone->tail;
- }
- else {
- /*length = pchan->bone->length;*/ /*UNUSED*/
- tail = pchan->bone->rad_tail;
- dist = pchan->bone->dist;
- if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED))
- head = pchan->parent->bone->rad_tail;
- else
- head = pchan->bone->rad_head;
- headvec = pchan->pose_head;
- tailvec = pchan->pose_tail;
- }
-
- /* ***** draw it ***** */
-
- /* move vector to viewspace */
- sub_v3_v3v3(dirvec, tailvec, headvec);
- mul_mat3_m4_v3(smat, dirvec);
- /* clear zcomp */
- dirvec[2] = 0.0f;
-
- if (head != tail) {
- /* correction when viewing along the bones axis
- * it pops in and out but better then artifacts, [#23841] */
- float view_dist = len_v2(dirvec);
-
- if (head - view_dist > tail) {
- tailvec = headvec;
- tail = head;
- zero_v3(dirvec);
- dirvec[0] = 0.00001; /* XXX. weak but ok */
- }
- else if (tail - view_dist > head) {
- headvec = tailvec;
- head = tail;
- zero_v3(dirvec);
- dirvec[0] = 0.00001; /* XXX. weak but ok */
- }
- }
-
- /* move vector back */
- mul_mat3_m4_v3(imat, dirvec);
-
- if (0.0f != normalize_v3(dirvec)) {
- float norvec[3], vec1[3], vec2[3], vec[3];
- int a;
-
- //mul_v3_fl(dirvec, head);
- cross_v3_v3v3(norvec, dirvec, imat[2]);
-
- glBegin(GL_QUAD_STRIP);
-
- for (a = 0; a < 16; a++) {
- vec[0] = -si[a] * dirvec[0] + co[a] * norvec[0];
- vec[1] = -si[a] * dirvec[1] + co[a] * norvec[1];
- vec[2] = -si[a] * dirvec[2] + co[a] * norvec[2];
-
- madd_v3_v3v3fl(vec1, headvec, vec, head);
- madd_v3_v3v3fl(vec2, headvec, vec, head + dist);
-
- glColor4ub(255, 255, 255, 50);
- glVertex3fv(vec1);
- //glColor4ub(255, 255, 255, 0);
- glVertex3fv(vec2);
- }
-
- for (a = 15; a >= 0; a--) {
- vec[0] = si[a] * dirvec[0] + co[a] * norvec[0];
- vec[1] = si[a] * dirvec[1] + co[a] * norvec[1];
- vec[2] = si[a] * dirvec[2] + co[a] * norvec[2];
-
- madd_v3_v3v3fl(vec1, tailvec, vec, tail);
- madd_v3_v3v3fl(vec2, tailvec, vec, tail + dist);
-
- //glColor4ub(255, 255, 255, 50);
- glVertex3fv(vec1);
- //glColor4ub(255, 255, 255, 0);
- glVertex3fv(vec2);
- }
- /* make it cyclic... */
-
- vec[0] = -si[0] * dirvec[0] + co[0] * norvec[0];
- vec[1] = -si[0] * dirvec[1] + co[0] * norvec[1];
- vec[2] = -si[0] * dirvec[2] + co[0] * norvec[2];
-
- madd_v3_v3v3fl(vec1, headvec, vec, head);
- madd_v3_v3v3fl(vec2, headvec, vec, head + dist);
-
- //glColor4ub(255, 255, 255, 50);
- glVertex3fv(vec1);
- //glColor4ub(255, 255, 255, 0);
- glVertex3fv(vec2);
-
- glEnd();
- }
-}
-
-
-/* smat, imat = mat & imat to draw screenaligned */
-static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
- int armflag, int boneflag, short constflag, unsigned int id,
- bPoseChannel *pchan, EditBone *ebone)
-{
- float head, tail /*, length*/;
- float *headvec, *tailvec, dirvec[3];
-
- /* figure out the sizes of spheres */
- if (ebone) {
- /* this routine doesn't call get_matrix_editbone() that calculates it */
- ebone->length = len_v3v3(ebone->head, ebone->tail);
-
- /*length = ebone->length;*/ /*UNUSED*/
- tail = ebone->rad_tail;
- if (ebone->parent && (boneflag & BONE_CONNECTED))
- head = ebone->parent->rad_tail;
- else
- head = ebone->rad_head;
- headvec = ebone->head;
- tailvec = ebone->tail;
- }
- else {
- /*length = pchan->bone->length;*/ /*UNUSED*/
- tail = pchan->bone->rad_tail;
- if ((pchan->parent) && (boneflag & BONE_CONNECTED))
- head = pchan->parent->bone->rad_tail;
- else
- head = pchan->bone->rad_head;
- headvec = pchan->pose_head;
- tailvec = pchan->pose_tail;
- }
-
- /* sphere root color */
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
- }
- else if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
-
- /* Draw root point if we are not connected */
- if ((boneflag & BONE_CONNECTED) == 0) {
- if (id != -1)
- GPU_select_load_id(id | BONESEL_ROOT);
-
- drawcircball(GL_LINE_LOOP, headvec, head, imat);
- }
-
- /* Draw tip point */
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
- }
-
- if (id != -1)
- GPU_select_load_id(id | BONESEL_TIP);
-
- drawcircball(GL_LINE_LOOP, tailvec, tail, imat);
-
- /* base */
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_SELECT);
- else UI_ThemeColor(TH_WIRE_EDIT);
- }
-
- sub_v3_v3v3(dirvec, tailvec, headvec);
-
- /* move vector to viewspace */
- mul_mat3_m4_v3(smat, dirvec);
- /* clear zcomp */
- dirvec[2] = 0.0f;
- /* move vector back */
- mul_mat3_m4_v3(imat, dirvec);
-
- if (0.0f != normalize_v3(dirvec)) {
- float norvech[3], norvect[3], vec[3];
-
- copy_v3_v3(vec, dirvec);
-
- mul_v3_fl(dirvec, head);
- cross_v3_v3v3(norvech, dirvec, imat[2]);
-
- mul_v3_fl(vec, tail);
- cross_v3_v3v3(norvect, vec, imat[2]);
-
- if (id != -1)
- GPU_select_load_id(id | BONESEL_BONE);
-
- glBegin(GL_LINES);
-
- add_v3_v3v3(vec, headvec, norvech);
- glVertex3fv(vec);
-
- add_v3_v3v3(vec, tailvec, norvect);
- glVertex3fv(vec);
-
- sub_v3_v3v3(vec, headvec, norvech);
- glVertex3fv(vec);
-
- sub_v3_v3v3(vec, tailvec, norvect);
- glVertex3fv(vec);
-
- glEnd();
- }
-}
-
-/* does wire only for outline selecting */
-static void draw_sphere_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id,
- bPoseChannel *pchan, EditBone *ebone)
-{
- GLUquadricObj *qobj;
- float head, tail, length;
- float fac1, fac2;
-
- glPushMatrix();
- qobj = gluNewQuadric();
-
- /* figure out the sizes of spheres */
- if (ebone) {
- length = ebone->length;
- tail = ebone->rad_tail;
- if (ebone->parent && (boneflag & BONE_CONNECTED))
- head = ebone->parent->rad_tail;
- else
- head = ebone->rad_head;
- }
- else {
- length = pchan->bone->length;
- tail = pchan->bone->rad_tail;
- if (pchan->parent && (boneflag & BONE_CONNECTED))
- head = pchan->parent->bone->rad_tail;
- else
- head = pchan->bone->rad_head;
- }
-
- /* move to z-axis space */
- glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
-
- if (dt == OB_SOLID) {
- /* set up solid drawing */
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
-
- gluQuadricDrawStyle(qobj, GLU_FILL);
- }
- else {
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
- }
-
- /* sphere root color */
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColorShade(TH_BONE_SOLID, -30);
- }
- else if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SPHEREBONE_END, boneflag, constflag);
- else if (dt == OB_SOLID)
- UI_ThemeColorShade(TH_BONE_SOLID, -30);
-
- /* Draw root point if we are not connected */
- if ((boneflag & BONE_CONNECTED) == 0) {
- if (id != -1)
- GPU_select_load_id(id | BONESEL_ROOT);
- gluSphere(qobj, head, 16, 10);
- }
-
- /* Draw tip point */
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColorShade(TH_BONE_SOLID, -30);
- }
-
- if (id != -1)
- GPU_select_load_id(id | BONESEL_TIP);
-
- glTranslatef(0.0f, 0.0f, length);
- gluSphere(qobj, tail, 16, 10);
- glTranslatef(0.0f, 0.0f, -length);
-
- /* base */
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_SELECT);
- else UI_ThemeColor(TH_BONE_SOLID);
- }
- else if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SPHEREBONE_BASE, boneflag, constflag);
- else if (dt == OB_SOLID)
- UI_ThemeColor(TH_BONE_SOLID);
-
- fac1 = (length - head) / length;
- fac2 = (length - tail) / length;
-
- if (length > (head + tail)) {
- if (id != -1)
- GPU_select_load_id(id | BONESEL_BONE);
-
- glEnable(GL_POLYGON_OFFSET_FILL);
- glPolygonOffset(-1.0f, -1.0f);
-
- glTranslatef(0.0f, 0.0f, head);
- gluCylinder(qobj, fac1 * head + (1.0f - fac1) * tail, fac2 * tail + (1.0f - fac2) * head, length - head - tail, 16, 1);
- glTranslatef(0.0f, 0.0f, -head);
-
- glDisable(GL_POLYGON_OFFSET_FILL);
-
- /* draw sphere on extrema */
- glTranslatef(0.0f, 0.0f, length - tail);
- gluSphere(qobj, fac2 * tail + (1.0f - fac2) * head, 16, 10);
- glTranslatef(0.0f, 0.0f, -length + tail);
-
- glTranslatef(0.0f, 0.0f, head);
- gluSphere(qobj, fac1 * head + (1.0f - fac1) * tail, 16, 10);
- }
- else {
- /* 1 sphere in center */
- glTranslatef(0.0f, 0.0f, (head + length - tail) / 2.0f);
- gluSphere(qobj, fac1 * head + (1.0f - fac1) * tail, 16, 10);
- }
-
- /* restore */
- if (dt == OB_SOLID) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
-
- glPopMatrix();
- gluDeleteQuadric(qobj);
-}
-
-static GLubyte bm_dot6[] = {0x0, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x0};
-static GLubyte bm_dot8[] = {0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C};
-
-static GLubyte bm_dot5[] = {0x0, 0x0, 0x10, 0x38, 0x7c, 0x38, 0x10, 0x0};
-static GLubyte bm_dot7[] = {0x0, 0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38};
-
-
-static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned int id,
- bPoseChannel *pchan, EditBone *ebone)
-{
- /* call this once, avoid constant changing */
- BLI_assert(glaGetOneInt(GL_UNPACK_ALIGNMENT) == 1);
-
- float length;
-
- if (pchan)
- length = pchan->bone->length;
- else
- length = ebone->length;
-
- glPushMatrix();
- glScalef(length, length, length);
-
- /* this chunk not in object mode */
- if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) {
- glLineWidth(4.0f);
- if (G.f & G_PICKSEL) {
- /* no bitmap in selection mode, crashes 3d cards...
- * instead draw a solid point the same size */
- glPointSize(8.0f);
- }
-
- if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
- else if (armflag & ARM_EDITMODE) {
- UI_ThemeColor(TH_WIRE_EDIT);
- }
-
- /* Draw root point if we are not connected */
- if ((boneflag & BONE_CONNECTED) == 0) {
- if (G.f & G_PICKSEL) {
- GPU_select_load_id(id | BONESEL_ROOT);
- glBegin(GL_POINTS);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glEnd();
- }
- else {
- glRasterPos3f(0.0f, 0.0f, 0.0f);
- glBitmap(8, 8, 4, 4, 0, 0, bm_dot8);
- }
- }
-
- if (id != -1)
- GPU_select_load_id((GLuint) id | BONESEL_BONE);
-
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3f(0.0f, 1.0f, 0.0f);
- glEnd();
-
- /* tip */
- if (G.f & G_PICKSEL) {
- /* no bitmap in selection mode, crashes 3d cards... */
- GPU_select_load_id(id | BONESEL_TIP);
- glBegin(GL_POINTS);
- glVertex3f(0.0f, 1.0f, 0.0f);
- glEnd();
- }
- else {
- glRasterPos3f(0.0f, 1.0f, 0.0f);
- glBitmap(8, 8, 4, 4, 0, 0, bm_dot7);
- }
-
- /* further we send no names */
- if (id != -1)
- GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */
-
- if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_LINEBONE, boneflag, constflag);
- }
-
- glLineWidth(2.0);
-
- /*Draw root point if we are not connected */
- if ((boneflag & BONE_CONNECTED) == 0) {
- if ((G.f & G_PICKSEL) == 0) {
- /* no bitmap in selection mode, crashes 3d cards... */
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
- }
- glRasterPos3f(0.0f, 0.0f, 0.0f);
- glBitmap(8, 8, 4, 4, 0, 0, bm_dot6);
- }
- }
-
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_EDGE_SELECT);
- else UI_ThemeColorShade(TH_BACK, -30);
- }
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3f(0.0f, 1.0f, 0.0f);
- glEnd();
-
- /* tip */
- if ((G.f & G_PICKSEL) == 0) {
- /* no bitmap in selection mode, crashes 3d cards... */
- if (armflag & ARM_EDITMODE) {
- if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT);
- else UI_ThemeColor(TH_VERTEX);
- }
- glRasterPos3f(0.0f, 1.0f, 0.0f);
- glBitmap(8, 8, 4, 4, 0, 0, bm_dot5);
- }
-
- glPopMatrix();
-}
-
-/* A partial copy of b_bone_spline_setup(), with just the parts for previewing editmode curve settings
- *
- * This assumes that prev/next bones don't have any impact (since they should all still be in the "straight"
- * position here anyway), and that we can simply apply the bbone settings to get the desired effect...
- */
-static void ebone_spline_preview(EditBone *ebone, Mat4 result_array[MAX_BBONE_SUBDIV])
-{
- float h1[3], h2[3], length, hlength1, hlength2, roll1 = 0.0f, roll2 = 0.0f;
- float mat3[3][3];
- float data[MAX_BBONE_SUBDIV + 1][4], *fp;
- int a;
-
- length = ebone->length;
-
- hlength1 = ebone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
- hlength2 = ebone->ease2 * length * 0.390464f;
-
- /* find the handle points, since this is inside bone space, the
- * first point = (0, 0, 0)
- * last point = (0, length, 0)
- *
- * we also just apply all the "extra effects", since they're the whole reason we're doing this...
- */
- h1[0] = ebone->curveInX;
- h1[1] = hlength1;
- h1[2] = ebone->curveInY;
- roll1 = ebone->roll1;
-
- h2[0] = ebone->curveOutX;
- h2[1] = -hlength2;
- h2[2] = ebone->curveOutY;
- roll2 = ebone->roll2;
-
- /* make curve */
- if (ebone->segments > MAX_BBONE_SUBDIV)
- ebone->segments = MAX_BBONE_SUBDIV;
-
- BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
- BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
-
- equalize_bbone_bezier(data[0], ebone->segments); /* note: does stride 4! */
-
- /* make transformation matrices for the segments for drawing */
- for (a = 0, fp = data[0]; a < ebone->segments; a++, fp += 4) {
- sub_v3_v3v3(h1, fp + 4, fp);
- vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
-
- copy_m4_m3(result_array[a].mat, mat3);
- copy_v3_v3(result_array[a].mat[3], fp);
-
- /* "extra" scale facs... */
- {
- const int num_segments = ebone->segments;
-
- const float scaleFactorIn = 1.0f + (ebone->scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
- const float scaleFactorOut = 1.0f + (ebone->scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
-
- const float scalefac = scaleFactorIn * scaleFactorOut;
- float bscalemat[4][4], bscale[3];
-
- bscale[0] = scalefac;
- bscale[1] = 1.0f;
- bscale[2] = scalefac;
-
- size_to_mat4(bscalemat, bscale);
-
- /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
- mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
- }
- }
-}
-
-static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, EditBone *ebone, float xwidth, float length, float zwidth)
-{
- int segments = 0;
-
- if (pchan)
- segments = pchan->bone->segments;
- else if (ebone)
- segments = ebone->segments;
-
- if (segments > 1) {
- float dlen = length / (float)segments;
- Mat4 bbone[MAX_BBONE_SUBDIV];
- int a;
-
- if (pchan) {
- b_bone_spline_setup(pchan, 0, bbone);
- }
- else if (ebone) {
- ebone_spline_preview(ebone, bbone);
- }
-
- for (a = 0; a < segments; a++) {
- glPushMatrix();
- glMultMatrixf(bbone[a].mat);
- if (dt == OB_SOLID) drawsolidcube_size(xwidth, dlen, zwidth);
- else drawcube_size(xwidth, dlen, zwidth);
- glPopMatrix();
- }
- }
- else {
- glPushMatrix();
- if (dt == OB_SOLID) drawsolidcube_size(xwidth, length, zwidth);
- else drawcube_size(xwidth, length, zwidth);
- glPopMatrix();
- }
-}
-
-static void draw_b_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id,
- bPoseChannel *pchan, EditBone *ebone)
-{
- float xwidth, length, zwidth;
-
- if (pchan) {
- xwidth = pchan->bone->xwidth;
- length = pchan->bone->length;
- zwidth = pchan->bone->zwidth;
- }
- else {
- xwidth = ebone->xwidth;
- length = ebone->length;
- zwidth = ebone->zwidth;
- }
-
- /* draw points only if... */
- if (armflag & ARM_EDITMODE) {
- /* move to unitspace */
- glPushMatrix();
- glScalef(length, length, length);
- draw_bone_points(dt, armflag, boneflag, id);
- glPopMatrix();
- length *= 0.95f; /* make vertices visible */
- }
-
- /* colors for modes */
- if (armflag & ARM_POSEMODE) {
- if (dt <= OB_WIRE)
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
- else
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag);
- }
- else if (armflag & ARM_EDITMODE) {
- if (dt == OB_WIRE) {
- set_ebone_glColor(boneflag);
- }
- else
- UI_ThemeColor(TH_BONE_SOLID);
- }
-
- if (id != -1) {
- GPU_select_load_id((GLuint) id | BONESEL_BONE);
- }
-
- /* set up solid drawing */
- if (dt > OB_WIRE) {
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
-
- if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag);
- else
- UI_ThemeColor(TH_BONE_SOLID);
-
- draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
-
- /* disable solid drawing */
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- else {
- /* wire */
- if (armflag & ARM_POSEMODE) {
- if (constflag && ((G.f & G_PICKSEL) == 0)) {
- /* set constraint colors */
- if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
- glEnable(GL_BLEND);
-
- draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth);
-
- glDisable(GL_BLEND);
- }
-
- /* restore colors */
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
- }
- }
-
- draw_b_bone_boxes(OB_WIRE, pchan, ebone, xwidth, length, zwidth);
- }
-}
-
-static void draw_wire_bone_segments(bPoseChannel *pchan, Mat4 *bbones, float length, int segments)
-{
- if ((segments > 1) && (pchan)) {
- float dlen = length / (float)segments;
- Mat4 *bbone = bbones;
- int a;
-
- for (a = 0; a < segments; a++, bbone++) {
- glPushMatrix();
- glMultMatrixf(bbone->mat);
-
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3f(0.0f, dlen, 0.0f);
- glEnd(); /* GL_LINES */
-
- glPopMatrix();
- }
- }
- else {
- glPushMatrix();
-
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3f(0.0f, length, 0.0f);
- glEnd();
-
- glPopMatrix();
- }
-}
-
-static void draw_wire_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id,
- bPoseChannel *pchan, EditBone *ebone)
-{
- Mat4 bbones_array[MAX_BBONE_SUBDIV];
- Mat4 *bbones = NULL;
- int segments = 0;
- float length;
-
- if (pchan) {
- segments = pchan->bone->segments;
- length = pchan->bone->length;
-
- if (segments > 1) {
- b_bone_spline_setup(pchan, 0, bbones_array);
- bbones = bbones_array;
- }
- }
- else
- length = ebone->length;
-
- /* draw points only if... */
- if (armflag & ARM_EDITMODE) {
- /* move to unitspace */
- glPushMatrix();
- glScalef(length, length, length);
- draw_bone_points(dt, armflag, boneflag, id);
- glPopMatrix();
- length *= 0.95f; /* make vertices visible */
- }
-
- /* this chunk not in object mode */
- if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) {
- if (id != -1)
- GPU_select_load_id((GLuint) id | BONESEL_BONE);
-
- draw_wire_bone_segments(pchan, bbones, length, segments);
-
- /* further we send no names */
- if (id != -1)
- GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */
- }
-
- /* colors for modes */
- if (armflag & ARM_POSEMODE) {
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
- }
- else if (armflag & ARM_EDITMODE) {
- set_ebone_glColor(boneflag);
- }
-
- /* draw normal */
- draw_wire_bone_segments(pchan, bbones, length, segments);
-}
-
-static void draw_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, float length)
-{
-
- /* Draw a 3d octahedral bone, we use normalized space based on length,
- * for display-lists */
-
- glScalef(length, length, length);
-
- /* set up solid drawing */
- if (dt > OB_WIRE) {
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
- UI_ThemeColor(TH_BONE_SOLID);
- }
-
- /* colors for posemode */
- if (armflag & ARM_POSEMODE) {
- if (dt <= OB_WIRE)
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
- else
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag);
- }
-
-
- draw_bone_points(dt, armflag, boneflag, id);
-
- /* now draw the bone itself */
- if (id != -1) {
- GPU_select_load_id((GLuint) id | BONESEL_BONE);
- }
-
- /* wire? */
- if (dt <= OB_WIRE) {
- /* colors */
- if (armflag & ARM_EDITMODE) {
- set_ebone_glColor(boneflag);
- }
- else if (armflag & ARM_POSEMODE) {
- if (constflag && ((G.f & G_PICKSEL) == 0)) {
- /* draw constraint colors */
- if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) {
- glEnable(GL_BLEND);
-
- draw_bone_solid_octahedral();
-
- glDisable(GL_BLEND);
- }
-
- /* restore colors */
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
- }
- }
- draw_bone_octahedral();
- }
- else {
- /* solid */
- if (armflag & ARM_POSEMODE)
- set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag);
- else
- UI_ThemeColor(TH_BONE_SOLID);
- draw_bone_solid_octahedral();
- }
-
- /* disable solid drawing */
- if (dt > OB_WIRE) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
-}
-
-static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob,
- const short dt, int armflag, int boneflag, unsigned int id, float length)
-{
- if (ob == NULL) return;
-
- glScalef(length, length, length);
-
- /* colors for posemode */
- if (armflag & ARM_POSEMODE) {
- set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, 0);
- }
-
- if (id != -1) {
- GPU_select_load_id((GLuint) id | BONESEL_BONE);
- }
-
- draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE);
-}
-
-
-static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp)
-{
- bConstraint *con;
- bPoseChannel *parchan;
-
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->enforce == 0.0f)
- continue;
-
- switch (con->type) {
- case CONSTRAINT_TYPE_KINEMATIC:
- {
- bKinematicConstraint *data = (bKinematicConstraint *)con->data;
- int segcount = 0;
-
- /* if only_temp, only draw if it is a temporary ik-chain */
- if ((only_temp) && !(data->flag & CONSTRAINT_IK_TEMP))
- continue;
-
- setlinestyle(3);
- glBegin(GL_LINES);
-
- /* exclude tip from chain? */
- if ((data->flag & CONSTRAINT_IK_TIP) == 0)
- parchan = pchan->parent;
- else
- parchan = pchan;
-
- glVertex3fv(parchan->pose_tail);
-
- /* Find the chain's root */
- while (parchan->parent) {
- segcount++;
- if (segcount == data->rootbone || segcount > 255) {
- break; /* 255 is weak */
- }
- parchan = parchan->parent;
- }
- if (parchan)
- glVertex3fv(parchan->pose_head);
-
- glEnd();
- setlinestyle(0);
- break;
- }
- case CONSTRAINT_TYPE_SPLINEIK:
- {
- bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
- int segcount = 0;
-
- setlinestyle(3);
- glBegin(GL_LINES);
-
- parchan = pchan;
- glVertex3fv(parchan->pose_tail);
-
- /* Find the chain's root */
- while (parchan->parent) {
- segcount++;
- /* FIXME: revise the breaking conditions */
- if (segcount == data->chainlen || segcount > 255) break; /* 255 is weak */
- parchan = parchan->parent;
- }
- /* Only draw line in case our chain is more than one bone long! */
- if (parchan != pchan) /* XXX revise the breaking conditions to only stop at the tail? */
- glVertex3fv(parchan->pose_head);
-
- glEnd();
- setlinestyle(0);
- break;
- }
- }
- }
-}
-
-static void bgl_sphere_project(float ax, float az)
-{
- float dir[3], sine, q3;
-
- sine = 1.0f - ax * ax - az * az;
- q3 = (sine < 0.0f) ? 0.0f : (2.0f * sqrtf(sine));
-
- dir[0] = -az * q3;
- dir[1] = 1.0f - 2.0f * sine;
- dir[2] = ax * q3;
-
- glVertex3fv(dir);
-}
-
-static void draw_dof_ellipse(float ax, float az)
-{
- const float staticSine[16] = {
- 0.0f, 0.104528463268f, 0.207911690818f, 0.309016994375f,
- 0.406736643076f, 0.5f, 0.587785252292f, 0.669130606359f,
- 0.743144825477f, 0.809016994375f, 0.866025403784f,
- 0.913545457643f, 0.951056516295f, 0.978147600734f,
- 0.994521895368f, 1.0f
- };
-
- int i, j, n = 16;
- float x, z, px, pz;
-
- glEnable(GL_BLEND);
- glDepthMask(0);
-
- glColor4ub(70, 70, 70, 50);
-
- glBegin(GL_QUADS);
- pz = 0.0f;
- for (i = 1; i < n; i++) {
- z = staticSine[i];
-
- px = 0.0f;
- for (j = 1; j <= (n - i); j++) {
- x = staticSine[j];
-
- if (j == n - i) {
- glEnd();
- glBegin(GL_TRIANGLES);
- bgl_sphere_project(ax * px, az * z);
- bgl_sphere_project(ax * px, az * pz);
- bgl_sphere_project(ax * x, az * pz);
- glEnd();
- glBegin(GL_QUADS);
- }
- else {
- bgl_sphere_project(ax * x, az * z);
- bgl_sphere_project(ax * x, az * pz);
- bgl_sphere_project(ax * px, az * pz);
- bgl_sphere_project(ax * px, az * z);
- }
-
- px = x;
- }
- pz = z;
- }
- glEnd();
-
- glDisable(GL_BLEND);
- glDepthMask(1);
-
- glColor3ub(0, 0, 0);
-
- glBegin(GL_LINE_STRIP);
- for (i = 0; i < n; i++)
- bgl_sphere_project(staticSine[n - i - 1] * ax, staticSine[i] * az);
- glEnd();
-}
-
-static void draw_pose_dofs(Object *ob)
-{
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- Bone *bone;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
-
- if ((bone != NULL) && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
- if (bone->flag & BONE_SELECTED) {
- if (bone->layer & arm->layer) {
- if (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT)) {
- if (BKE_pose_channel_in_IK_chain(ob, pchan)) {
- float corner[4][3], posetrans[3], mat[4][4];
- float phi = 0.0f, theta = 0.0f, scale;
- int a, i;
-
- /* in parent-bone pose, but own restspace */
- glPushMatrix();
-
- copy_v3_v3(posetrans, pchan->pose_mat[3]);
- glTranslate3fv(posetrans);
-
- if (pchan->parent) {
- copy_m4_m4(mat, pchan->parent->pose_mat);
- mat[3][0] = mat[3][1] = mat[3][2] = 0.0f;
- glMultMatrixf(mat);
- }
-
- copy_m4_m3(mat, pchan->bone->bone_mat);
- glMultMatrixf(mat);
-
- scale = bone->length * pchan->size[1];
- glScalef(scale, scale, scale);
-
- if (pchan->ikflag & BONE_IK_XLIMIT) {
- if (pchan->ikflag & BONE_IK_ZLIMIT) {
- float amin[3], amax[3];
-
- for (i = 0; i < 3; i++) {
- /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
- amin[i] = sinf(pchan->limitmin[i] * 0.5f);
- amax[i] = sinf(pchan->limitmax[i] * 0.5f);
- }
-
- glScalef(1.0f, -1.0f, 1.0f);
- if ((amin[0] != 0.0f) && (amin[2] != 0.0f))
- draw_dof_ellipse(amin[0], amin[2]);
- if ((amin[0] != 0.0f) && (amax[2] != 0.0f))
- draw_dof_ellipse(amin[0], amax[2]);
- if ((amax[0] != 0.0f) && (amin[2] != 0.0f))
- draw_dof_ellipse(amax[0], amin[2]);
- if ((amax[0] != 0.0f) && (amax[2] != 0.0f))
- draw_dof_ellipse(amax[0], amax[2]);
- glScalef(1.0f, -1.0f, 1.0f);
- }
- }
-
- /* arcs */
- if (pchan->ikflag & BONE_IK_ZLIMIT) {
- /* OpenGL requires rotations in degrees; so we're taking the average angle here */
- theta = RAD2DEGF(0.5f * (pchan->limitmin[2] + pchan->limitmax[2]));
- glRotatef(theta, 0.0f, 0.0f, 1.0f);
-
- glColor3ub(50, 50, 255); /* blue, Z axis limit */
- glBegin(GL_LINE_STRIP);
- for (a = -16; a <= 16; a++) {
- /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
- float fac = ((float)a) / 16.0f * 0.5f;
-
- phi = fac * (pchan->limitmax[2] - pchan->limitmin[2]);
-
- i = (a == -16) ? 0 : 1;
- corner[i][0] = sinf(phi);
- corner[i][1] = cosf(phi);
- corner[i][2] = 0.0f;
- glVertex3fv(corner[i]);
- }
- glEnd();
-
- glRotatef(-theta, 0.0f, 0.0f, 1.0f);
- }
-
- if (pchan->ikflag & BONE_IK_XLIMIT) {
- /* OpenGL requires rotations in degrees; so we're taking the average angle here */
- theta = RAD2DEGF(0.5f * (pchan->limitmin[0] + pchan->limitmax[0]));
- glRotatef(theta, 1.0f, 0.0f, 0.0f);
-
- glColor3ub(255, 50, 50); /* Red, X axis limit */
- glBegin(GL_LINE_STRIP);
- for (a = -16; a <= 16; a++) {
- /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
- float fac = ((float)a) / 16.0f * 0.5f;
- phi = (float)M_PI_2 + fac * (pchan->limitmax[0] - pchan->limitmin[0]);
-
- i = (a == -16) ? 2 : 3;
- corner[i][0] = 0.0f;
- corner[i][1] = sinf(phi);
- corner[i][2] = cosf(phi);
- glVertex3fv(corner[i]);
- }
- glEnd();
-
- glRotatef(-theta, 1.0f, 0.0f, 0.0f);
- }
-
- /* out of cone, out of bone */
- glPopMatrix();
- }
- }
- }
- }
- }
- }
-}
-
-static void bone_matrix_translate_y(float mat[4][4], float y)
-{
- float trans[3];
-
- copy_v3_v3(trans, mat[1]);
- mul_v3_fl(trans, y);
- add_v3_v3(mat[3], trans);
-}
-
-/* assumes object is Armature with pose */
-static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
- const short dt, const unsigned char ob_wire_col[4],
- const bool do_const_color, const bool is_outline)
-{
- RegionView3D *rv3d = ar->regiondata;
- Object *ob = base->object;
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- Bone *bone;
- float smat[4][4], imat[4][4], bmat[4][4];
- int index = -1;
- const enum {
- DASH_RELATIONSHIP_LINES = 1,
- DASH_HELP_LINES = 2,
- } do_dashed = (
- (is_outline ? 0 : DASH_RELATIONSHIP_LINES) |
- ((v3d->flag & V3D_HIDE_HELPLINES) ? 0 : DASH_HELP_LINES));
- bool draw_wire = false;
- int flag;
- bool is_cull_enabled;
-
- /* being set below */
- arm->layer_used = 0;
-
- /* precalc inverse matrix for drawing screen aligned */
- if (arm->drawtype == ARM_ENVELOPE) {
- /* precalc inverse matrix for drawing screen aligned */
- copy_m4_m4(smat, rv3d->viewmatob);
- mul_mat3_m4_fl(smat, 1.0f / len_v3(ob->obmat[0]));
- invert_m4_m4(imat, smat);
-
- /* and draw blended distances */
- if (arm->flag & ARM_POSEMODE) {
- glEnable(GL_BLEND);
-
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- if (bone) {
- /* 1) bone must be visible, 2) for OpenGL select-drawing cannot have unselectable [#27194]
- * NOTE: this is the only case with (NO_DEFORM == 0) flag, as this is for envelope influence drawing
- */
- if (((bone->flag & (BONE_HIDDEN_P | BONE_NO_DEFORM | BONE_HIDDEN_PG)) == 0) &&
- ((G.f & G_PICKSEL) == 0 || (bone->flag & BONE_UNSELECTABLE) == 0))
- {
- if (bone->flag & (BONE_SELECTED)) {
- if (bone->layer & arm->layer)
- draw_sphere_bone_dist(smat, imat, pchan, NULL);
- }
- }
- }
- }
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
- }
- }
-
- /* little speedup, also make sure transparent only draws once */
- glCullFace(GL_BACK);
- if (v3d->flag2 & V3D_BACKFACE_CULLING) {
- glEnable(GL_CULL_FACE);
- is_cull_enabled = true;
- }
- else {
- is_cull_enabled = false;
- }
-
- /* if solid we draw that first, with selection codes, but without names, axes etc */
- if (dt > OB_WIRE) {
- if (arm->flag & ARM_POSEMODE)
- index = base->selcol;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- arm->layer_used |= bone->layer;
-
- /* 1) bone must be visible, 2) for OpenGL select-drawing cannot have unselectable [#27194] */
- if (((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) &&
- ((G.f & G_PICKSEL) == 0 || (bone->flag & BONE_UNSELECTABLE) == 0))
- {
- if (bone->layer & arm->layer) {
- const bool use_custom = (pchan->custom) && !(arm->flag & ARM_NO_CUSTOM);
- glPushMatrix();
-
- if (use_custom && pchan->custom_tx) {
- glMultMatrixf(pchan->custom_tx->pose_mat);
- }
- else {
- glMultMatrixf(pchan->pose_mat);
- }
-
- /* catch exception for bone with hidden parent */
- flag = bone->flag;
- if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
- flag &= ~BONE_CONNECTED;
- }
-
- /* set temporary flag for drawing bone as active, but only if selected */
- if (bone == arm->act_bone)
- flag |= BONE_DRAW_ACTIVE;
-
- if (do_const_color) {
- /* keep color */
- }
- else {
- /* set color-set to use */
- set_pchan_colorset(ob, pchan);
- }
-
- /* may be 2x width from custom bone's outline option */
- glLineWidth(1.0f);
-
- if (use_custom) {
- /* if drawwire, don't try to draw in solid */
- if (pchan->bone->flag & BONE_DRAWWIRE) {
- draw_wire = true;
- }
- else {
- if (is_cull_enabled && (v3d->flag2 & V3D_BACKFACE_CULLING) == 0) {
- is_cull_enabled = false;
- glDisable(GL_CULL_FACE);
- }
-
- draw_custom_bone(scene, v3d, rv3d, pchan->custom,
- OB_SOLID, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan));
- }
- }
- else {
- if (is_cull_enabled == false) {
- is_cull_enabled = true;
- glEnable(GL_CULL_FACE);
- }
-
- if (arm->drawtype == ARM_LINE) {
- /* nothing in solid */
- }
- else if (arm->drawtype == ARM_WIRE) {
- /* nothing in solid */
- }
- else if (arm->drawtype == ARM_ENVELOPE) {
- draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, pchan, NULL);
- }
- else if (arm->drawtype == ARM_B_BONE) {
- draw_b_bone(OB_SOLID, arm->flag, flag, 0, index, pchan, NULL);
- }
- else {
- draw_bone(OB_SOLID, arm->flag, flag, 0, index, bone->length);
- }
- }
-
- glPopMatrix();
- }
- }
-
- if (index != -1)
- index += 0x10000; /* pose bones count in higher 2 bytes only */
- }
-
- /* very very confusing... but in object mode, solid draw, we cannot do GPU_select_load_id yet,
- * stick bones and/or wire custom-shapes are drawn in next loop
- */
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false) && index != -1) {
- /* object tag, for bordersel optim */
- GPU_select_load_id(index & 0xFFFF);
- index = -1;
- }
- }
-
- /* custom bone may draw outline double-width */
- if (arm->flag & ARM_POSEMODE) {
- glLineWidth(1.0f);
- }
-
- /* draw custom bone shapes as wireframes */
- if (!(arm->flag & ARM_NO_CUSTOM) &&
- (draw_wire || (dt <= OB_WIRE)) )
- {
- if (arm->flag & ARM_POSEMODE)
- index = base->selcol;
-
- /* only draw custom bone shapes that need to be drawn as wires */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
-
- /* 1) bone must be visible, 2) for OpenGL select-drawing cannot have unselectable [#27194] */
- if (((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) &&
- ((G.f & G_PICKSEL) == 0 || (bone->flag & BONE_UNSELECTABLE) == 0) )
- {
- if (bone->layer & arm->layer) {
- if (pchan->custom) {
- if ((dt < OB_SOLID) || (bone->flag & BONE_DRAWWIRE)) {
- glPushMatrix();
-
- if (pchan->custom_tx) {
- glMultMatrixf(pchan->custom_tx->pose_mat);
- }
- else {
- glMultMatrixf(pchan->pose_mat);
- }
-
- /* prepare colors */
- if (do_const_color) {
- /* 13 October 2009, Disabled this to make ghosting show the right colors (Aligorith) */
- }
- else if (arm->flag & ARM_POSEMODE)
- set_pchan_colorset(ob, pchan);
- else {
- glColor3ubv(ob_wire_col);
- }
-
- /* catch exception for bone with hidden parent */
- flag = bone->flag;
- if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))
- flag &= ~BONE_CONNECTED;
-
- /* set temporary flag for drawing bone as active, but only if selected */
- if (bone == arm->act_bone)
- flag |= BONE_DRAW_ACTIVE;
-
- draw_custom_bone(scene, v3d, rv3d, pchan->custom,
- OB_WIRE, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan));
-
- glPopMatrix();
- }
- }
- }
- }
-
- if (index != -1)
- index += 0x10000; /* pose bones count in higher 2 bytes only */
- }
- /* stick or wire bones have not been drawn yet so don't clear object selection in this case */
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire && index != -1) {
- /* object tag, for bordersel optim */
- GPU_select_load_id(index & 0xFFFF);
- index = -1;
- }
- }
-
- /* wire draw over solid only in posemode */
- if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
- /* draw line check first. we do selection indices */
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
- if (arm->flag & ARM_POSEMODE)
- index = base->selcol;
- }
- /* if solid && posemode, we draw again with polygonoffset */
- else if ((dt > OB_WIRE) && (arm->flag & ARM_POSEMODE)) {
- ED_view3d_polygon_offset(rv3d, 1.0);
- }
- else {
- /* and we use selection indices if not done yet */
- if (arm->flag & ARM_POSEMODE)
- index = base->selcol;
- }
-
- if (is_cull_enabled == false) {
- is_cull_enabled = true;
- glEnable(GL_CULL_FACE);
- }
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
- arm->layer_used |= bone->layer;
-
- /* 1) bone must be visible, 2) for OpenGL select-drawing cannot have unselectable [#27194] */
- if (((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) &&
- ((G.f & G_PICKSEL) == 0 || (bone->flag & BONE_UNSELECTABLE) == 0))
- {
- if (bone->layer & arm->layer) {
- const short constflag = pchan->constflag;
- if ((do_dashed & DASH_RELATIONSHIP_LINES) && (pchan->parent)) {
- /* Draw a line from our root to the parent's tip
- * - only if V3D_HIDE_HELPLINES is enabled...
- */
- if ((do_dashed & DASH_HELP_LINES) && ((bone->flag & BONE_CONNECTED) == 0)) {
- if (arm->flag & ARM_POSEMODE) {
- GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */
- UI_ThemeColor(TH_WIRE);
- }
- setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(pchan->pose_head);
- glVertex3fv(pchan->parent->pose_tail);
- glEnd();
- setlinestyle(0);
- }
-
- /* Draw a line to IK root bone
- * - only if temporary chain (i.e. "autoik")
- */
- if (arm->flag & ARM_POSEMODE) {
- if (constflag & PCHAN_HAS_IK) {
- if (bone->flag & BONE_SELECTED) {
- if (constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0);
- else glColor3ub(200, 200, 50); /* add theme! */
-
- GPU_select_load_id(index & 0xFFFF);
- pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES));
- }
- }
- else if (constflag & PCHAN_HAS_SPLINEIK) {
- if (bone->flag & BONE_SELECTED) {
- glColor3ub(150, 200, 50); /* add theme! */
-
- GPU_select_load_id(index & 0xFFFF);
- pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES));
- }
- }
- }
- }
-
- glPushMatrix();
- if (arm->drawtype != ARM_ENVELOPE)
- glMultMatrixf(pchan->pose_mat);
-
- /* catch exception for bone with hidden parent */
- flag = bone->flag;
- if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))
- flag &= ~BONE_CONNECTED;
-
- /* set temporary flag for drawing bone as active, but only if selected */
- if (bone == arm->act_bone)
- flag |= BONE_DRAW_ACTIVE;
-
- /* extra draw service for pose mode */
-
- /* set color-set to use */
- if (do_const_color) {
- /* keep color */
- }
- else {
- set_pchan_colorset(ob, pchan);
- }
-
- if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
- /* custom bone shapes should not be drawn here! */
- }
- else if (arm->drawtype == ARM_ENVELOPE) {
- if (dt < OB_SOLID)
- draw_sphere_bone_wire(smat, imat, arm->flag, flag, constflag, index, pchan, NULL);
- }
- else if (arm->drawtype == ARM_LINE)
- draw_line_bone(arm->flag, flag, constflag, index, pchan, NULL);
- else if (arm->drawtype == ARM_WIRE)
- draw_wire_bone(dt, arm->flag, flag, constflag, index, pchan, NULL);
- else if (arm->drawtype == ARM_B_BONE)
- draw_b_bone(OB_WIRE, arm->flag, flag, constflag, index, pchan, NULL);
- else
- draw_bone(OB_WIRE, arm->flag, flag, constflag, index, bone->length);
-
- glPopMatrix();
- }
- }
-
- /* pose bones count in higher 2 bytes only */
- if (index != -1)
- index += 0x10000;
- }
- /* restore things */
- if (!ELEM(arm->drawtype, ARM_WIRE, ARM_LINE) && (dt > OB_WIRE) && (arm->flag & ARM_POSEMODE))
- ED_view3d_polygon_offset(rv3d, 0.0);
- }
-
- /* restore */
- if (is_cull_enabled) {
- glDisable(GL_CULL_FACE);
- }
-
- /* draw DoFs */
- if (arm->flag & ARM_POSEMODE) {
- if (((base->flag & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) {
- draw_pose_dofs(ob);
- }
- }
-
- /* finally names and axes */
- if ((arm->flag & (ARM_DRAWNAMES | ARM_DRAWAXES)) &&
- (is_outline == 0) &&
- ((base->flag & OB_FROMDUPLI) == 0))
- {
- /* patch for several 3d cards (IBM mostly) that crash on GL_SELECT with text drawing */
- if ((G.f & G_PICKSEL) == 0) {
- float vec[3];
-
- unsigned char col[4];
- if (do_const_color) {
- /* so we can draw bone names in current const color */
- float tcol[4];
- glGetFloatv(GL_CURRENT_COLOR, tcol);
- rgb_float_to_uchar(col, tcol);
- col[3] = 255;
- }
- else {
- col[0] = ob_wire_col[0];
- col[1] = ob_wire_col[1];
- col[2] = ob_wire_col[2];
- col[3] = 255;
- }
-
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) {
- if (pchan->bone->layer & arm->layer) {
- if (arm->flag & (ARM_EDITMODE | ARM_POSEMODE)) {
- bone = pchan->bone;
- UI_GetThemeColor3ubv((bone->flag & BONE_SELECTED) ? TH_TEXT_HI : TH_TEXT, col);
- }
- else if (dt > OB_WIRE) {
- UI_GetThemeColor3ubv(TH_TEXT, col);
- }
-
- /* Draw names of bone */
- if (arm->flag & ARM_DRAWNAMES) {
- mid_v3_v3v3(vec, pchan->pose_head, pchan->pose_tail);
- view3d_cached_text_draw_add(vec, pchan->name, strlen(pchan->name), 10, 0, col);
- }
-
- /* Draw additional axes on the bone tail */
- if ((arm->flag & ARM_DRAWAXES) && (arm->flag & ARM_POSEMODE)) {
- glPushMatrix();
- copy_m4_m4(bmat, pchan->pose_mat);
- bone_matrix_translate_y(bmat, pchan->bone->length);
- glMultMatrixf(bmat);
-
- glColor3ubv(col);
-
- float viewmat_pchan[4][4];
- mul_m4_m4m4(viewmat_pchan, rv3d->viewmatob, bmat);
- drawaxes(viewmat_pchan, pchan->bone->length * 0.25f, OB_ARROWS);
-
- glPopMatrix();
- }
- }
- }
- }
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- }
- }
-
- if (index != -1) {
- GPU_select_load_id(-1);
- }
-}
-
-/* in editmode, we don't store the bone matrix... */
-static void get_matrix_editbone(EditBone *ebone, float bmat[4][4])
-{
- ebone->length = len_v3v3(ebone->tail, ebone->head);
- ED_armature_ebone_to_mat4(ebone, bmat);
-}
-
-static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
-{
- RegionView3D *rv3d = ar->regiondata;
- EditBone *eBone;
- bArmature *arm = ob->data;
- float smat[4][4], imat[4][4], bmat[4][4];
- unsigned int index;
- int flag;
-
- /* being set in code below */
- arm->layer_used = 0;
-
- ED_view3d_check_mats_rv3d(rv3d);
-
- /* envelope (deform distance) */
- if (arm->drawtype == ARM_ENVELOPE) {
- /* precalc inverse matrix for drawing screen aligned */
- copy_m4_m4(smat, rv3d->viewmatob);
- mul_mat3_m4_fl(smat, 1.0f / len_v3(ob->obmat[0]));
- invert_m4_m4(imat, smat);
-
- /* and draw blended distances */
- glEnable(GL_BLEND);
-
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (eBone->layer & arm->layer) {
- if ((eBone->flag & (BONE_HIDDEN_A | BONE_NO_DEFORM)) == 0) {
- if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL))
- draw_sphere_bone_dist(smat, imat, NULL, eBone);
- }
- }
- }
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
- }
-
- /* if solid we draw it first */
- if ((dt > OB_WIRE) && (arm->drawtype != ARM_LINE)) {
- for (eBone = arm->edbo->first, index = 0; eBone; eBone = eBone->next, index++) {
- if (eBone->layer & arm->layer) {
- if ((eBone->flag & BONE_HIDDEN_A) == 0) {
- glPushMatrix();
- get_matrix_editbone(eBone, bmat);
- glMultMatrixf(bmat);
-
- /* catch exception for bone with hidden parent */
- flag = eBone->flag;
- if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) {
- flag &= ~BONE_CONNECTED;
- }
-
- /* set temporary flag for drawing bone as active, but only if selected */
- if (eBone == arm->act_edbone)
- flag |= BONE_DRAW_ACTIVE;
-
- if (arm->drawtype == ARM_ENVELOPE)
- draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone);
- else if (arm->drawtype == ARM_B_BONE)
- draw_b_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone);
- else if (arm->drawtype == ARM_WIRE)
- draw_wire_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone);
- else {
- draw_bone(OB_SOLID, arm->flag, flag, 0, index, eBone->length);
- }
-
- glPopMatrix();
- }
- }
- }
- }
-
- /* if wire over solid, set offset */
- index = -1;
- GPU_select_load_id(-1);
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
- if (G.f & G_PICKSEL)
- index = 0;
- }
- else if (dt > OB_WIRE)
- ED_view3d_polygon_offset(rv3d, 1.0);
- else if (arm->flag & ARM_EDITMODE)
- index = 0; /* do selection codes */
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- arm->layer_used |= eBone->layer;
- if (eBone->layer & arm->layer) {
- if ((eBone->flag & BONE_HIDDEN_A) == 0) {
-
- /* catch exception for bone with hidden parent */
- flag = eBone->flag;
- if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) {
- flag &= ~BONE_CONNECTED;
- }
-
- /* set temporary flag for drawing bone as active, but only if selected */
- if (eBone == arm->act_edbone)
- flag |= BONE_DRAW_ACTIVE;
-
- if (arm->drawtype == ARM_ENVELOPE) {
- if (dt < OB_SOLID)
- draw_sphere_bone_wire(smat, imat, arm->flag, flag, 0, index, NULL, eBone);
- }
- else {
- glPushMatrix();
- get_matrix_editbone(eBone, bmat);
- glMultMatrixf(bmat);
-
- if (arm->drawtype == ARM_LINE)
- draw_line_bone(arm->flag, flag, 0, index, NULL, eBone);
- else if (arm->drawtype == ARM_WIRE)
- draw_wire_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone);
- else if (arm->drawtype == ARM_B_BONE)
- draw_b_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone);
- else
- draw_bone(OB_WIRE, arm->flag, flag, 0, index, eBone->length);
-
- glPopMatrix();
- }
-
- /* offset to parent */
- if (eBone->parent) {
- UI_ThemeColor(TH_WIRE_EDIT);
- GPU_select_load_id(-1); /* -1 here is OK! */
- setlinestyle(3);
-
- glBegin(GL_LINES);
- glVertex3fv(eBone->parent->tail);
- glVertex3fv(eBone->head);
- glEnd();
-
- setlinestyle(0);
- }
- }
- }
- if (index != -1) index++;
- }
-
- /* restore */
- if (index != -1) {
- GPU_select_load_id(-1);
- }
-
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
- /* pass */
- }
- else if (dt > OB_WIRE) {
- ED_view3d_polygon_offset(rv3d, 0.0);
- }
-
- /* finally names and axes */
- if (arm->flag & (ARM_DRAWNAMES | ARM_DRAWAXES)) {
- /* patch for several 3d cards (IBM mostly) that crash on GL_SELECT with text drawing */
- if ((G.f & G_PICKSEL) == 0) {
- float vec[3];
- unsigned char col[4];
- col[3] = 255;
-
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (eBone->layer & arm->layer) {
- if ((eBone->flag & BONE_HIDDEN_A) == 0) {
-
- UI_GetThemeColor3ubv((eBone->flag & BONE_SELECTED) ? TH_TEXT_HI : TH_TEXT, col);
-
- /* Draw name */
- if (arm->flag & ARM_DRAWNAMES) {
- mid_v3_v3v3(vec, eBone->head, eBone->tail);
- view3d_cached_text_draw_add(vec, eBone->name, strlen(eBone->name), 10, 0, col);
- }
- /* Draw additional axes */
- if (arm->flag & ARM_DRAWAXES) {
- glPushMatrix();
- get_matrix_editbone(eBone, bmat);
- bone_matrix_translate_y(bmat, eBone->length);
- glMultMatrixf(bmat);
-
- glColor3ubv(col);
-
- float viewmat_ebone[4][4];
- mul_m4_m4m4(viewmat_ebone, rv3d->viewmatob, bmat);
- drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS);
-
- glPopMatrix();
- }
-
- }
- }
- }
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- }
- }
-}
-
-/* ****************************** Armature Visualization ******************************** */
-
-/* ---------- Paths --------- */
-
-/* draw bone paths
- * - in view space
- */
-static void draw_pose_paths(Scene *scene, View3D *v3d, ARegion *ar, Object *ob)
-{
- bAnimVizSettings *avs = &ob->pose->avs;
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
-
- /* setup drawing environment for paths */
- draw_motion_paths_init(v3d, ar);
-
- /* draw paths where they exist and they releated bone is visible */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->layer & arm->layer) && (pchan->mpath))
- draw_motion_path_instance(scene, ob, pchan, avs, pchan->mpath);
- }
-
- /* cleanup after drawing */
- draw_motion_paths_cleanup(v3d);
-}
-
-
-/* ---------- Ghosts --------- */
-
-/* helper function for ghost drawing - sets/removes flags for temporarily
- * hiding unselected bones while drawing ghosts
- */
-static void ghost_poses_tag_unselected(Object *ob, short unset)
-{
- bArmature *arm = ob->data;
- bPose *pose = ob->pose;
- bPoseChannel *pchan;
-
- /* don't do anything if no hiding any bones */
- if ((arm->flag & ARM_GHOST_ONLYSEL) == 0)
- return;
-
- /* loop over all pchans, adding/removing tags as appropriate */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone) && (arm->layer & pchan->bone->layer)) {
- if (unset) {
- /* remove tags from all pchans if cleaning up */
- pchan->bone->flag &= ~BONE_HIDDEN_PG;
- }
- else {
- /* set tags on unselected pchans only */
- if ((pchan->bone->flag & BONE_SELECTED) == 0)
- pchan->bone->flag |= BONE_HIDDEN_PG;
- }
- }
- }
-}
-
-/* draw ghosts that occur within a frame range
- * note: object should be in posemode
- */
-static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
-{
- Object *ob = base->object;
- AnimData *adt = BKE_animdata_from_id(&ob->id);
- bArmature *arm = ob->data;
- bPose *posen, *poseo;
- float start, end, stepsize, range, colfac;
- int cfrao, flago;
-
- start = (float)arm->ghostsf;
- end = (float)arm->ghostef;
- if (end <= start)
- return;
-
- /* prevent infinite loops if this is set to 0 - T49527 */
- if (arm->ghostsize < 1)
- arm->ghostsize = 1;
-
- stepsize = (float)(arm->ghostsize);
- range = (float)(end - start);
-
- /* store values */
- ob->mode &= ~OB_MODE_POSE;
- cfrao = CFRA;
- flago = arm->flag;
- arm->flag &= ~(ARM_DRAWNAMES | ARM_DRAWAXES);
-
- /* copy the pose */
- poseo = ob->pose;
- BKE_pose_copy_data(&posen, ob->pose, 1);
- ob->pose = posen;
- BKE_pose_rebuild(ob, ob->data); /* child pointers for IK */
- ghost_poses_tag_unselected(ob, 0); /* hide unselected bones if need be */
-
- glEnable(GL_BLEND);
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- /* draw from first frame of range to last */
- for (CFRA = (int)start; CFRA <= end; CFRA += (int)stepsize) {
- colfac = (end - (float)CFRA) / range;
- UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)));
-
- BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL);
- BKE_pose_where_is(scene, ob);
- draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false);
- }
- glDisable(GL_BLEND);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
-
- /* before disposing of temp pose, use it to restore object to a sane state */
- BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)cfrao, ADT_RECALC_ALL);
-
- /* clean up temporary pose */
- ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */
- BKE_pose_free(posen);
-
- /* restore */
- CFRA = cfrao;
- ob->pose = poseo;
- arm->flag = flago;
- ob->mode |= OB_MODE_POSE;
-}
-
-/* draw ghosts on keyframes in action within range
- * - object should be in posemode
- */
-static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
-{
- Object *ob = base->object;
- AnimData *adt = BKE_animdata_from_id(&ob->id);
- bAction *act = (adt) ? adt->action : NULL;
- bArmature *arm = ob->data;
- bPose *posen, *poseo;
- DLRBT_Tree keys;
- ActKeyColumn *ak, *akn;
- float start, end, range, colfac, i;
- int cfrao, flago;
-
- start = (float)arm->ghostsf;
- end = (float)arm->ghostef;
- if (end <= start)
- return;
-
- /* get keyframes - then clip to only within range */
- BLI_dlrbTree_init(&keys);
- action_to_keylist(adt, act, &keys, NULL);
- BLI_dlrbTree_linkedlist_sync(&keys);
-
- range = 0;
- for (ak = keys.first; ak; ak = akn) {
- akn = ak->next;
-
- if ((ak->cfra < start) || (ak->cfra > end))
- BLI_freelinkN((ListBase *)&keys, ak);
- else
- range++;
- }
- if (range == 0) return;
-
- /* store values */
- ob->mode &= ~OB_MODE_POSE;
- cfrao = CFRA;
- flago = arm->flag;
- arm->flag &= ~(ARM_DRAWNAMES | ARM_DRAWAXES);
-
- /* copy the pose */
- poseo = ob->pose;
- BKE_pose_copy_data(&posen, ob->pose, 1);
- ob->pose = posen;
- BKE_pose_rebuild(ob, ob->data); /* child pointers for IK */
- ghost_poses_tag_unselected(ob, 0); /* hide unselected bones if need be */
-
- glEnable(GL_BLEND);
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- /* draw from first frame of range to last */
- for (ak = keys.first, i = 0; ak; ak = ak->next, i++) {
- colfac = i / range;
- UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)));
-
- CFRA = (int)ak->cfra;
-
- BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL);
- BKE_pose_where_is(scene, ob);
- draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false);
- }
- glDisable(GL_BLEND);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
-
- /* before disposing of temp pose, use it to restore object to a sane state */
- BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)cfrao, ADT_RECALC_ALL);
-
- /* clean up temporary pose */
- ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */
- BLI_dlrbTree_free(&keys);
- BKE_pose_free(posen);
-
- /* restore */
- CFRA = cfrao;
- ob->pose = poseo;
- arm->flag = flago;
- ob->mode |= OB_MODE_POSE;
-}
-
-/* draw ghosts around current frame
- * - object is supposed to be armature in posemode
- */
-static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
-{
- Object *ob = base->object;
- AnimData *adt = BKE_animdata_from_id(&ob->id);
- bArmature *arm = ob->data;
- bPose *posen, *poseo;
- float cur, start, end, stepsize, range, colfac, actframe, ctime;
- int cfrao, flago;
-
- /* pre conditions, get an action with sufficient frames */
- if (ELEM(NULL, adt, adt->action))
- return;
-
- calc_action_range(adt->action, &start, &end, 0);
- if (start == end)
- return;
-
- /* prevent infinite loops if this is set to 0 - T49527 */
- if (arm->ghostsize < 1)
- arm->ghostsize = 1;
-
- stepsize = (float)(arm->ghostsize);
- range = (float)(arm->ghostep) * stepsize + 0.5f; /* plus half to make the for loop end correct */
-
- /* store values */
- ob->mode &= ~OB_MODE_POSE;
- cfrao = CFRA;
- actframe = BKE_nla_tweakedit_remap(adt, (float)CFRA, 0);
- flago = arm->flag;
- arm->flag &= ~(ARM_DRAWNAMES | ARM_DRAWAXES);
-
- /* copy the pose */
- poseo = ob->pose;
- BKE_pose_copy_data(&posen, ob->pose, 1);
- ob->pose = posen;
- BKE_pose_rebuild(ob, ob->data); /* child pointers for IK */
- ghost_poses_tag_unselected(ob, 0); /* hide unselected bones if need be */
-
- glEnable(GL_BLEND);
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- /* draw from darkest blend to lowest */
- for (cur = stepsize; cur < range; cur += stepsize) {
- ctime = cur - (float)fmod(cfrao, stepsize); /* ensures consistent stepping */
- colfac = ctime / range;
- UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)));
-
- /* only within action range */
- if (actframe + ctime >= start && actframe + ctime <= end) {
- CFRA = (int)BKE_nla_tweakedit_remap(adt, actframe + ctime, NLATIME_CONVERT_MAP);
-
- if (CFRA != cfrao) {
- BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL);
- BKE_pose_where_is(scene, ob);
- draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false);
- }
- }
-
- ctime = cur + (float)fmod((float)cfrao, stepsize) - stepsize + 1.0f; /* ensures consistent stepping */
- colfac = ctime / range;
- UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac)));
-
- /* only within action range */
- if ((actframe - ctime >= start) && (actframe - ctime <= end)) {
- CFRA = (int)BKE_nla_tweakedit_remap(adt, actframe - ctime, NLATIME_CONVERT_MAP);
-
- if (CFRA != cfrao) {
- BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL);
- BKE_pose_where_is(scene, ob);
- draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false);
- }
- }
- }
- glDisable(GL_BLEND);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
-
- /* before disposing of temp pose, use it to restore object to a sane state */
- BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)cfrao, ADT_RECALC_ALL);
-
- /* clean up temporary pose */
- ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */
- BKE_pose_free(posen);
-
- /* restore */
- CFRA = cfrao;
- ob->pose = poseo;
- arm->flag = flago;
- ob->mode |= OB_MODE_POSE;
-}
-
-/* ********************************** Armature Drawing - Main ************************* */
-
-/* called from drawobject.c, return true if nothing was drawn
- * (ob_wire_col == NULL) when drawing ghost */
-bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
- const short dt, const short dflag, const unsigned char ob_wire_col[4],
- const bool is_outline)
-{
- Object *ob = base->object;
- bArmature *arm = ob->data;
- bool retval = false;
-
- if (v3d->flag2 & V3D_RENDER_OVERRIDE)
- return true;
-
- /* needed for 'draw_line_bone' which draws pixel. */
- if (arm->drawtype == ARM_LINE) {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- }
-
- if (dt > OB_WIRE) {
- /* we use color for solid lighting */
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
- const float diffuse[3] = {0.64f, 0.64f, 0.64f};
- const float specular[3] = {0.5f, 0.5f, 0.5f};
- GPU_basic_shader_colors(diffuse, specular, 35, 1.0f);
- }
- else {
- const float diffuse[3] = {1.0f, 1.0f, 1.0f};
- const float specular[3] = {1.0f, 1.0f, 1.0f};
- GPU_basic_shader_colors(diffuse, specular, 35, 1.0f);
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); /* only for lighting... */
- }
- }
-
- /* arm->flag is being used to detect mode... */
- /* editmode? */
- if (arm->edbo) {
- arm->flag |= ARM_EDITMODE;
- draw_ebones(v3d, ar, ob, dt);
- arm->flag &= ~ARM_EDITMODE;
- }
- else {
- /* Draw Pose */
- if (ob->pose && ob->pose->chanbase.first) {
- /* We can't safely draw non-updated pose, might contain NULL bone pointers... */
- if (ob->pose->flag & POSE_RECALC) {
- BKE_pose_rebuild(ob, arm);
- }
-
- /* drawing posemode selection indices or colors only in these cases */
- if (!(base->flag & OB_FROMDUPLI)) {
- if (G.f & G_PICKSEL) {
-#if 0
- /* nifty but actually confusing to allow bone selection out of posemode */
- if (OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) {
- if (ob == modifiers_isDeformedByArmature(OBACT))
- arm->flag |= ARM_POSEMODE;
- }
- else
-#endif
- if (ob->mode & OB_MODE_POSE) {
- arm->flag |= ARM_POSEMODE;
- }
- }
- else if (ob->mode & OB_MODE_POSE) {
- if (arm->ghosttype == ARM_GHOST_RANGE) {
- draw_ghost_poses_range(scene, v3d, ar, base);
- }
- else if (arm->ghosttype == ARM_GHOST_KEYS) {
- draw_ghost_poses_keys(scene, v3d, ar, base);
- }
- else if (arm->ghosttype == ARM_GHOST_CUR) {
- if (arm->ghostep)
- draw_ghost_poses(scene, v3d, ar, base);
- }
- if ((dflag & DRAW_SCENESET) == 0) {
- if (ob == OBACT)
- arm->flag |= ARM_POSEMODE;
- else if (OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) {
- if (ob == modifiers_isDeformedByArmature(OBACT))
- arm->flag |= ARM_POSEMODE;
- }
- draw_pose_paths(scene, v3d, ar, ob);
- }
- }
- }
- draw_pose_bones(scene, v3d, ar, base, dt, ob_wire_col, (dflag & DRAW_CONSTCOLOR), is_outline);
- arm->flag &= ~ARM_POSEMODE;
-
- if (ob->mode & OB_MODE_POSE)
- UI_ThemeColor(TH_WIRE); /* restore, for extra draw stuff */
- }
- else {
- retval = true;
- }
- }
- /* restore */
- glFrontFace(GL_CCW);
-
- if (arm->drawtype == ARM_LINE) {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- }
-
- return retval;
-}
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
deleted file mode 100644
index 20dbb8df69e..00000000000
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ /dev/null
@@ -1,1405 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation, full update, glsl support
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_view3d/drawmesh.c
- * \ingroup spview3d
- */
-
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_bitmap.h"
-#include "BLI_math.h"
-
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_property_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_view3d_types.h"
-
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_material.h"
-#include "BKE_paint.h"
-#include "BKE_property.h"
-#include "BKE_editmesh.h"
-#include "BKE_scene.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
-
-#include "UI_resources.h"
-
-#include "GPU_draw.h"
-#include "GPU_material.h"
-#include "GPU_basic_shader.h"
-#include "GPU_shader.h"
-
-#include "RE_engine.h"
-
-#include "ED_uvedit.h"
-
-#include "view3d_intern.h" /* own include */
-
-/* user data structures for derived mesh callbacks */
-typedef struct drawMeshFaceSelect_userData {
- Mesh *me;
- BLI_bitmap *edge_flags; /* pairs of edge options (visible, select) */
-} drawMeshFaceSelect_userData;
-
-typedef struct drawEMTFMapped_userData {
- BMEditMesh *em;
- bool has_mcol;
- int cd_poly_tex_offset;
- const MPoly *mpoly;
- const MTexPoly *mtexpoly;
-} drawEMTFMapped_userData;
-
-typedef struct drawTFace_userData {
- const Mesh *me;
- const MPoly *mpoly;
- const MTexPoly *mtexpoly;
-} drawTFace_userData;
-
-/**************************** Face Select Mode *******************************/
-
-/* mainly to be less confusing */
-BLI_INLINE int edge_vis_index(const int index) { return index * 2; }
-BLI_INLINE int edge_sel_index(const int index) { return index * 2 + 1; }
-
-static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me, bool draw_select_edges)
-{
- BLI_bitmap *bitmap_edge_flags = BLI_BITMAP_NEW(me->totedge * 2, __func__);
- MPoly *mp;
- MLoop *ml;
- int i, j;
- bool select_set;
-
- for (i = 0; i < me->totpoly; i++) {
- mp = &me->mpoly[i];
-
- if (!(mp->flag & ME_HIDE)) {
- select_set = (mp->flag & ME_FACE_SEL) != 0;
-
- ml = me->mloop + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++) {
- if ((draw_select_edges == false) &&
- (select_set && BLI_BITMAP_TEST(bitmap_edge_flags, edge_sel_index(ml->e))))
- {
- BLI_BITMAP_DISABLE(bitmap_edge_flags, edge_vis_index(ml->e));
- }
- else {
- BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_vis_index(ml->e));
- if (select_set) {
- BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_sel_index(ml->e));
- }
- }
- }
- }
- }
-
- return bitmap_edge_flags;
-}
-
-
-static DMDrawOption draw_mesh_face_select__setHiddenOpts(void *userData, int index)
-{
- drawMeshFaceSelect_userData *data = userData;
- Mesh *me = data->me;
-
- if (me->drawflag & ME_DRAWEDGES) {
- if ((BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))))
- return DM_DRAW_OPTION_NORMAL;
- else
- return DM_DRAW_OPTION_SKIP;
- }
- else if (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)) &&
- BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index)))
- {
- return DM_DRAW_OPTION_NORMAL;
- }
- else {
- return DM_DRAW_OPTION_SKIP;
- }
-}
-
-static DMDrawOption draw_mesh_face_select__setSelectOpts(void *userData, int index)
-{
- drawMeshFaceSelect_userData *data = userData;
- return (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)) &&
- BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP;
-}
-
-/* draws unselected */
-static DMDrawOption draw_mesh_face_select__drawFaceOptsInv(void *userData, int index)
-{
- Mesh *me = (Mesh *)userData;
-
- MPoly *mpoly = &me->mpoly[index];
- if (!(mpoly->flag & ME_HIDE) && !(mpoly->flag & ME_FACE_SEL))
- return DM_DRAW_OPTION_NORMAL;
- else
- return DM_DRAW_OPTION_SKIP;
-}
-
-void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm, bool draw_select_edges)
-{
- drawMeshFaceSelect_userData data;
-
- data.me = me;
- data.edge_flags = get_tface_mesh_marked_edge_info(me, draw_select_edges);
-
- glEnable(GL_DEPTH_TEST);
- ED_view3d_polygon_offset(rv3d, 1.0);
-
- /* Draw (Hidden) Edges */
- setlinestyle(1);
- UI_ThemeColor(TH_EDGE_FACESEL);
- dm->drawMappedEdges(dm, draw_mesh_face_select__setHiddenOpts, &data);
- setlinestyle(0);
-
- /* Draw Selected Faces */
- if (me->drawflag & ME_DRAWFACES) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- /* dull unselected faces so as not to get in the way of seeing color */
- glColor4ub(96, 96, 96, 64);
- dm->drawMappedFaces(dm, draw_mesh_face_select__drawFaceOptsInv, NULL, NULL, (void *)me, DM_DRAW_SKIP_HIDDEN);
- glDisable(GL_BLEND);
- }
-
- ED_view3d_polygon_offset(rv3d, 1.0);
-
- /* Draw Stippled Outline for selected faces */
- glColor3ub(255, 255, 255);
- setlinestyle(1);
- dm->drawMappedEdges(dm, draw_mesh_face_select__setSelectOpts, &data);
- setlinestyle(0);
-
- ED_view3d_polygon_offset(rv3d, 0.0); /* resets correctly now, even after calling accumulated offsets */
-
- MEM_freeN(data.edge_flags);
-}
-
-/***************************** Texture Drawing ******************************/
-
-static Material *give_current_material_or_def(Object *ob, int matnr)
-{
- extern Material defmaterial; /* render module abuse... */
- Material *ma = give_current_material(ob, matnr);
-
- return ma ? ma : &defmaterial;
-}
-
-/* Icky globals, fix with userdata parameter */
-
-static struct TextureDrawState {
- Object *ob;
- Image *stencil; /* texture painting stencil */
- Image *canvas; /* texture painting canvas, for image mode */
- bool use_game_mat;
- int is_lit, is_tex;
- int color_profile;
- bool use_backface_culling;
- bool two_sided_lighting;
- unsigned char obcol[4];
- bool is_texpaint;
- bool texpaint_material; /* use material slots for texture painting */
-} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, false, {0, 0, 0, 0}, false, false};
-
-static bool set_draw_settings_cached(
- int clearcache, MTexPoly *texface, Material *ma,
- const struct TextureDrawState *gtexdraw)
-{
- static Material *c_ma;
- static int c_textured;
- static MTexPoly c_texface;
- static int c_backculled;
- static bool c_badtex;
- static int c_lit;
- static int c_has_texface;
-
- int backculled = 1;
- int alphablend = GPU_BLEND_SOLID;
- int textured = 0;
- int lit = 0;
- int has_texface = texface != NULL;
- bool need_set_tpage = false;
- bool texpaint = ((gtexdraw->ob->mode & OB_MODE_TEXTURE_PAINT) != 0);
-
- Image *ima = NULL;
-
- if (ma != NULL) {
- if (ma->mode & MA_TRANSP) {
- alphablend = GPU_BLEND_ALPHA;
- }
- }
-
- if (clearcache) {
- c_textured = c_lit = c_backculled = -1;
- memset(&c_texface, 0, sizeof(c_texface));
- c_badtex = false;
- c_has_texface = -1;
- c_ma = NULL;
- }
- else {
- textured = gtexdraw->is_tex;
- }
-
- /* convert number of lights into boolean */
- if (gtexdraw->is_lit) {
- lit = 1;
- }
-
- backculled = gtexdraw->use_backface_culling;
- if (ma) {
- if (ma->mode & MA_SHLESS) lit = 0;
- if (gtexdraw->use_game_mat) {
- backculled = backculled || (ma->game.flag & GEMAT_BACKCULL);
- alphablend = ma->game.alpha_blend;
- }
- }
-
- if (texface && !texpaint) {
- textured = textured && (texface->tpage);
-
- /* no material, render alpha if texture has depth=32 */
- if (!ma && BKE_image_has_alpha(texface->tpage))
- alphablend = GPU_BLEND_ALPHA;
- }
- else if (texpaint) {
- if (gtexdraw->texpaint_material)
- ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
- else
- ima = gtexdraw->canvas;
- }
- else
- textured = 0;
-
- if (backculled != c_backculled) {
- if (backculled) glEnable(GL_CULL_FACE);
- else glDisable(GL_CULL_FACE);
-
- c_backculled = backculled;
- }
-
- /* need to re-set tpage if textured flag changed or existsment of texface changed.. */
- need_set_tpage = textured != c_textured || has_texface != c_has_texface;
- /* ..or if settings inside texface were changed (if texface was used) */
- need_set_tpage |= (texpaint && c_ma != ma) || (texface && memcmp(&c_texface, texface, sizeof(c_texface)));
-
- if (need_set_tpage) {
- if (textured) {
- if (texpaint) {
- c_badtex = false;
- if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, 0, 1, 0, false)) {
- glEnable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
-
- glActiveTexture(GL_TEXTURE1);
- glEnable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
- glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
- glActiveTexture(GL_TEXTURE0);
- }
- else {
- glActiveTexture(GL_TEXTURE1);
- glDisable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glActiveTexture(GL_TEXTURE0);
-
- c_badtex = true;
- GPU_clear_tpage(true);
- glDisable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- }
- }
- else {
- c_badtex = !GPU_set_tpage(texface, !texpaint, alphablend);
- }
- }
- else {
- GPU_set_tpage(NULL, 0, 0);
- c_badtex = false;
- }
- c_textured = textured;
- c_has_texface = has_texface;
- if (texface)
- memcpy(&c_texface, texface, sizeof(c_texface));
- }
-
- if (c_badtex) lit = 0;
- if (lit != c_lit || ma != c_ma || textured != c_textured) {
- int options = GPU_SHADER_USE_COLOR;
-
- if (c_textured && !c_badtex) {
- options |= GPU_SHADER_TEXTURE_2D;
- }
- if (gtexdraw->two_sided_lighting) {
- options |= GPU_SHADER_TWO_SIDED;
- }
-
- if (lit) {
- options |= GPU_SHADER_LIGHTING;
- if (!ma)
- ma = give_current_material_or_def(NULL, 0); /* default material */
-
- float specular[3];
- mul_v3_v3fl(specular, &ma->specr, ma->spec);
-
- GPU_basic_shader_colors(NULL, specular, ma->har, 1.0f);
- }
-
- GPU_basic_shader_bind(options);
-
- c_lit = lit;
- c_ma = ma;
- }
-
- return c_badtex;
-}
-
-static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob)
-{
- unsigned char obcol[4];
- bool is_tex, solidtex;
- Mesh *me = ob->data;
- ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- /* XXX scene->obedit warning */
-
- /* texture draw is abused for mask selection mode, do this so wire draw
- * with face selection in weight paint is not lit. */
- if ((v3d->drawtype <= OB_WIRE) && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT))) {
- solidtex = false;
- Gtexdraw.is_lit = 0;
- }
- else if ((ob->mode & OB_MODE_TEXTURE_PAINT) && BKE_scene_use_new_shading_nodes(scene)) {
- solidtex = true;
- if (v3d->flag2 & V3D_SHADELESS_TEX)
- Gtexdraw.is_lit = 0;
- else
- Gtexdraw.is_lit = -1;
- }
- else if ((v3d->drawtype == OB_SOLID) ||
- ((ob->mode & OB_MODE_EDIT) && (v3d->drawtype != OB_TEXTURE)))
- {
- /* draw with default lights in solid draw mode and edit mode */
- solidtex = true;
- Gtexdraw.is_lit = -1;
- }
- else {
- /* draw with lights in the scene otherwise */
- solidtex = false;
- if (v3d->flag2 & V3D_SHADELESS_TEX) {
- Gtexdraw.is_lit = 0;
- }
- 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;
- else is_tex = false;
-
- Gtexdraw.ob = ob;
- Gtexdraw.stencil = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? imapaint->stencil : NULL;
- Gtexdraw.is_texpaint = (ob->mode == OB_MODE_TEXTURE_PAINT);
- Gtexdraw.texpaint_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
- Gtexdraw.canvas = (Gtexdraw.texpaint_material) ? NULL : imapaint->canvas;
- Gtexdraw.is_tex = is_tex;
-
- /* naughty multitexturing hacks to quickly support stencil + shading + alpha blending
- * in new texpaint code. The better solution here would be to support GLSL */
- if (Gtexdraw.is_texpaint) {
- glActiveTexture(GL_TEXTURE1);
- glEnable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
-
- /* load the stencil texture here */
- if (Gtexdraw.stencil != NULL) {
- glActiveTexture(GL_TEXTURE2);
- if (GPU_verify_image(Gtexdraw.stencil, NULL, GL_TEXTURE_2D, false, false, false, false)) {
- float col[4] = {imapaint->stencil_col[0], imapaint->stencil_col[1], imapaint->stencil_col[2], 1.0f};
- glEnable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
- glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, col);
- if ((imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) == 0) {
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_COLOR);
- }
- else {
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
- }
- }
- }
- glActiveTexture(GL_TEXTURE0);
- }
-
- Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene);
- Gtexdraw.use_game_mat = (RE_engines_find(scene->r.engine)->flag & RE_GAME) != 0;
- Gtexdraw.use_backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0;
- Gtexdraw.two_sided_lighting = (me->flag & ME_TWOSIDED);
-
- memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
- set_draw_settings_cached(1, NULL, NULL, &Gtexdraw);
- glCullFace(GL_BACK);
-}
-
-static void draw_textured_end(void)
-{
- if (Gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) {
- glActiveTexture(GL_TEXTURE1);
- glDisable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- if (Gtexdraw.stencil != NULL) {
- glActiveTexture(GL_TEXTURE2);
- glDisable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glBindTexture(GL_TEXTURE_2D, 0);
- }
- glActiveTexture(GL_TEXTURE0);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- /* manual reset, since we don't use tpage */
- glBindTexture(GL_TEXTURE_2D, 0);
- /* force switch off textures */
- GPU_clear_tpage(true);
- }
- else {
- /* switch off textures */
- GPU_set_tpage(NULL, 0, 0);
- }
-
- glDisable(GL_CULL_FACE);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
- /* XXX, bad patch - GPU_default_lights() calls
- * glLightfv(GL_POSITION, ...) which
- * is transformed by the current matrix... we
- * need to make sure that matrix is identity.
- *
- * It would be better if drawmesh.c kept track
- * of and restored the light settings it changed.
- * - zr
- */
- glPushMatrix();
- glLoadIdentity();
- GPU_default_lights();
- glPopMatrix();
-}
-
-static DMDrawOption draw_tface__set_draw_legacy(MTexPoly *mtexpoly, const bool has_mcol, int matnr)
-{
- Material *ma = give_current_material(Gtexdraw.ob, matnr + 1);
- bool invalidtexture = false;
-
- if (ma && (ma->game.flag & GEMAT_INVISIBLE))
- return DM_DRAW_OPTION_SKIP;
-
- invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw);
-
- if (mtexpoly && invalidtexture) {
- glColor3ub(0xFF, 0x00, 0xFF);
- return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
- }
- else if (!has_mcol) {
- if (mtexpoly) {
- glColor3f(1.0, 1.0, 1.0);
- }
- else {
- if (ma) {
- if (ma->shade_flag & MA_OBCOLOR) {
- glColor3ubv(Gtexdraw.obcol);
- }
- else {
- float col[3];
- if (Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r);
- else copy_v3_v3(col, &ma->r);
-
- glColor3fv(col);
- }
- }
- else {
- glColor3f(1.0, 1.0, 1.0);
- }
- }
- return DM_DRAW_OPTION_NORMAL; /* normal drawing (no mcols anyway, no need to turn off) */
- }
- else {
- return DM_DRAW_OPTION_NORMAL; /* Set color from mcol */
- }
-}
-
-static DMDrawOption draw_tface__set_draw(MTexPoly *mtexpoly, const bool UNUSED(has_mcol), int matnr)
-{
- Material *ma = give_current_material(Gtexdraw.ob, matnr + 1);
-
- if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return DM_DRAW_OPTION_SKIP;
-
- if (mtexpoly || Gtexdraw.is_texpaint)
- set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw);
-
- /* always use color from mcol, as set in update_tface_color_layer */
- return DM_DRAW_OPTION_NORMAL;
-}
-
-static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
-{
- const MPoly *mp = dm->getPolyArray(dm);
- const int mpoly_num = dm->getNumPolys(dm);
- MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- MLoopCol *finalCol;
- int i, j;
- MLoopCol *mloopcol = NULL;
-
- /* cache material values to avoid a lot of lookups */
- Material *ma = NULL;
- short mat_nr_prev = -1;
- enum {
- COPY_CALC,
- COPY_ORIG,
- COPY_PREV,
- } copy_mode = COPY_CALC;
-
- if (use_mcol) {
- mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL);
- if (!mloopcol)
- mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL);
- }
-
- if (CustomData_has_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL)) {
- finalCol = CustomData_get_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL);
- }
- else {
- finalCol = MEM_mallocN(sizeof(MLoopCol) * dm->numLoopData, "add_tface_color_layer");
- CustomData_add_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL, CD_ASSIGN, finalCol, dm->numLoopData);
- }
-
- for (i = mpoly_num; i--; mp++) {
- const short mat_nr = mp->mat_nr;
-
- if (UNLIKELY(mat_nr_prev != mat_nr)) {
- ma = give_current_material(Gtexdraw.ob, mat_nr + 1);
- copy_mode = COPY_CALC;
- mat_nr_prev = mat_nr;
- }
-
- /* avoid lookups */
- if (copy_mode == COPY_ORIG) {
- memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop);
- }
- else if (copy_mode == COPY_PREV) {
- int loop_index = mp->loopstart;
- const MLoopCol *lcol_prev = &finalCol[(mp - 1)->loopstart];
- for (j = 0; j < mp->totloop; j++, loop_index++) {
- finalCol[loop_index] = *lcol_prev;
- }
- }
-
- /* (copy_mode == COPY_CALC) */
- else if (ma && (ma->game.flag & GEMAT_INVISIBLE)) {
- if (mloopcol) {
- memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop);
- copy_mode = COPY_ORIG;
- }
- else {
- memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop);
- copy_mode = COPY_PREV;
- }
- }
- else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw)) {
- int loop_index = mp->loopstart;
- for (j = 0; j < mp->totloop; j++, loop_index++) {
- finalCol[loop_index].r = 255;
- finalCol[loop_index].g = 0;
- finalCol[loop_index].b = 255;
- finalCol[loop_index].a = 255;
- }
- copy_mode = COPY_PREV;
- }
- else if (ma && (ma->shade_flag & MA_OBCOLOR)) {
- int loop_index = mp->loopstart;
- for (j = 0; j < mp->totloop; j++, loop_index++) {
- copy_v3_v3_uchar(&finalCol[loop_index].r, Gtexdraw.obcol);
- finalCol[loop_index].a = 255;
- }
- copy_mode = COPY_PREV;
- }
- else {
- if (mloopcol) {
- memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop);
- copy_mode = COPY_ORIG;
- }
- else if (mtexpoly) {
- memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop);
- copy_mode = COPY_PREV;
- }
- else {
- float col[3];
-
- if (ma) {
- int loop_index = mp->loopstart;
- MLoopCol lcol;
-
- if (Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r);
- else copy_v3_v3(col, &ma->r);
- rgb_float_to_uchar((unsigned char *)&lcol.r, col);
- lcol.a = 255;
-
- for (j = 0; j < mp->totloop; j++, loop_index++) {
- finalCol[loop_index] = lcol;
- }
- }
- else {
- memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop);
- }
- copy_mode = COPY_PREV;
- }
- }
- }
-
- dm->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW;
-}
-
-static DMDrawOption draw_tface_mapped__set_draw(void *userData, int origindex, int UNUSED(mat_nr))
-{
- const Mesh *me = ((drawTFace_userData *)userData)->me;
-
- /* array checked for NULL before calling */
- MPoly *mpoly = &me->mpoly[origindex];
-
- BLI_assert(origindex >= 0 && origindex < me->totpoly);
-
- if (mpoly->flag & ME_HIDE) {
- return DM_DRAW_OPTION_SKIP;
- }
- else {
- MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[origindex] : NULL;
- int matnr = mpoly->mat_nr;
-
- return draw_tface__set_draw(tpoly, (me->mloopcol != NULL), matnr);
- }
-}
-
-static DMDrawOption draw_em_tf_mapped__set_draw(void *userData, int origindex, int mat_nr)
-{
- drawEMTFMapped_userData *data = userData;
- BMEditMesh *em = data->em;
- BMFace *efa;
-
- if (UNLIKELY(origindex >= em->bm->totface))
- return DM_DRAW_OPTION_NORMAL;
-
- efa = BM_face_at_index(em->bm, origindex);
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return DM_DRAW_OPTION_SKIP;
- }
- else {
- MTexPoly *mtexpoly = (data->cd_poly_tex_offset != -1) ?
- BM_ELEM_CD_GET_VOID_P(efa, data->cd_poly_tex_offset) : NULL;
- int matnr = (mat_nr != -1) ? mat_nr : efa->mat_nr;
-
- return draw_tface__set_draw_legacy(mtexpoly, data->has_mcol, matnr);
- }
-}
-
-/* when face select is on, use face hidden flag */
-static DMDrawOption wpaint__setSolidDrawOptions_facemask(void *userData, int index)
-{
- Mesh *me = (Mesh *)userData;
- MPoly *mp = &me->mpoly[index];
- if (mp->flag & ME_HIDE)
- return DM_DRAW_OPTION_SKIP;
- return DM_DRAW_OPTION_NORMAL;
-}
-
-static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
-{
- Mesh *me = ob->data;
- DerivedMesh *ddm;
- MPoly *mp, *mface = me->mpoly;
- MTexPoly *mtpoly = me->mtpoly;
- MLoopUV *mloopuv = me->mloopuv;
- MLoopUV *luv;
- MLoopCol *mloopcol = me->mloopcol; /* why does mcol exist? */
- MLoopCol *lcol;
-
- bProperty *prop = BKE_bproperty_object_get(ob, "Text");
- GPUVertexAttribs gattribs;
- int a, totpoly = me->totpoly;
-
- /* fake values to pass to GPU_render_text() */
- MCol tmp_mcol[4] = {{0}};
- MCol *tmp_mcol_pt = mloopcol ? tmp_mcol : NULL;
-
- /* don't draw without tfaces */
- if (!mtpoly || !mloopuv)
- return;
-
- /* don't draw when editing */
- if (ob->mode & OB_MODE_EDIT)
- return;
- else if (ob == OBACT)
- if (BKE_paint_select_elem_test(ob))
- return;
-
- ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
-
- for (a = 0, mp = mface; a < totpoly; a++, mtpoly++, mp++) {
- short matnr = mp->mat_nr;
- const bool mf_smooth = (mp->flag & ME_SMOOTH) != 0;
- Material *mat = (me->mat) ? me->mat[matnr] : NULL;
- int mode = mat ? mat->game.flag : GEMAT_INVISIBLE;
-
-
- if (!(mode & GEMAT_INVISIBLE) && (mode & GEMAT_TEXT) && mp->totloop >= 3) {
- /* get the polygon as a tri/quad */
- int mp_vi[4];
- float v_quad_data[4][3];
- const float *v_quad[4];
- const float *uv_quad[4];
- char string[MAX_PROPSTRING];
- int characters, i, glattrib = -1, badtex = 0;
-
-
- /* TEXFACE */
- if (glsl) {
- GPU_object_material_bind(matnr + 1, &gattribs);
-
- for (i = 0; i < gattribs.totlayer; i++) {
- if (gattribs.layer[i].type == CD_MTFACE) {
- glattrib = gattribs.layer[i].glindex;
- break;
- }
- }
- }
- else {
- badtex = set_draw_settings_cached(0, mtpoly, mat, &Gtexdraw);
- if (badtex) {
- continue;
- }
- }
-
- mp_vi[0] = me->mloop[mp->loopstart + 0].v;
- mp_vi[1] = me->mloop[mp->loopstart + 1].v;
- mp_vi[2] = me->mloop[mp->loopstart + 2].v;
- mp_vi[3] = (mp->totloop >= 4) ? me->mloop[mp->loopstart + 3].v : 0;
-
- /* UV */
- luv = &mloopuv[mp->loopstart];
- uv_quad[0] = luv->uv; luv++;
- uv_quad[1] = luv->uv; luv++;
- uv_quad[2] = luv->uv; luv++;
- if (mp->totloop >= 4) {
- uv_quad[3] = luv->uv;
- }
- else {
- uv_quad[3] = NULL;
- }
-
-
- /* COLOR */
- if (mloopcol) {
- unsigned int totloop_clamp = min_ii(4, mp->totloop);
- unsigned int j;
- lcol = &mloopcol[mp->loopstart];
-
- for (j = 0; j < totloop_clamp; j++, lcol++) {
- MESH_MLOOPCOL_TO_MCOL(lcol, &tmp_mcol[j]);
- }
- }
-
- /* LOCATION */
- ddm->getVertCo(ddm, mp_vi[0], v_quad_data[0]);
- ddm->getVertCo(ddm, mp_vi[1], v_quad_data[1]);
- ddm->getVertCo(ddm, mp_vi[2], v_quad_data[2]);
- if (mp->totloop >= 4) {
- ddm->getVertCo(ddm, mp_vi[3], v_quad_data[3]);
- }
-
- v_quad[0] = v_quad_data[0];
- v_quad[1] = v_quad_data[1];
- v_quad[2] = v_quad_data[2];
- if (mp->totloop >= 4) {
- v_quad[3] = v_quad_data[2];
- }
- else {
- v_quad[3] = NULL;
- }
-
-
- /* The BM_FONT handling is in the gpu module, shared with the
- * game engine, was duplicated previously */
-
- BKE_bproperty_set_valstr(prop, string);
- characters = strlen(string);
-
- if (!BKE_image_has_ibuf(mtpoly->tpage, NULL))
- characters = 0;
-
- if (!mf_smooth) {
- float nor[3];
-
- normal_tri_v3(nor, v_quad[0], v_quad[1], v_quad[2]);
-
- glNormal3fv(nor);
- }
-
- GPU_render_text(
- mtpoly, mode, string, characters,
- (unsigned int *)tmp_mcol_pt,
- v_quad, uv_quad,
- glattrib);
- }
- }
-
- ddm->release(ddm);
-}
-
-static int compareDrawOptions(void *userData, int cur_index, int next_index)
-{
- drawTFace_userData *data = userData;
-
- if (data->mpoly && data->mpoly[cur_index].mat_nr != data->mpoly[next_index].mat_nr)
- return 0;
-
- if (data->mtexpoly && data->mtexpoly[cur_index].tpage != data->mtexpoly[next_index].tpage)
- return 0;
-
- return 1;
-}
-
-
-static int compareDrawOptionsEm(void *userData, int cur_index, int next_index)
-{
- drawEMTFMapped_userData *data = userData;
-
- if (data->mpoly && data->mpoly[cur_index].mat_nr != data->mpoly[next_index].mat_nr)
- return 0;
-
- if (data->mtexpoly && data->mtexpoly[cur_index].tpage != data->mtexpoly[next_index].tpage)
- return 0;
-
- return 1;
-}
-
-static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d,
- Object *ob, DerivedMesh *dm, const int draw_flags)
-{
- Mesh *me = ob->data;
-
- /* correct for negative scale */
- if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
- else glFrontFace(GL_CCW);
-
- /* draw the textured mesh */
- draw_textured_begin(scene, v3d, rv3d, ob);
-
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
-
- if (ob->mode & OB_MODE_EDIT) {
- drawEMTFMapped_userData data;
-
- data.em = me->edit_btmesh;
- data.has_mcol = CustomData_has_layer(&me->edit_btmesh->bm->ldata, CD_MLOOPCOL);
- data.cd_poly_tex_offset = CustomData_get_offset(&me->edit_btmesh->bm->pdata, CD_MTEXPOLY);
-
- data.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY);
- data.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
-
- dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data, 0);
- }
- else {
- DMDrawFlag dm_draw_flag;
- drawTFace_userData userData;
-
- if (ob->mode & OB_MODE_TEXTURE_PAINT) {
- dm_draw_flag = DM_DRAW_USE_TEXPAINT_UV;
- }
- else {
- dm_draw_flag = DM_DRAW_USE_ACTIVE_UV;
- }
-
- if (ob == OBACT) {
- if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- dm_draw_flag |= DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN;
- }
- else if (ob->mode & OB_MODE_SCULPT) {
- dm_draw_flag |= DM_DRAW_SKIP_HIDDEN | DM_DRAW_USE_COLORS;
- }
- else if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
- dm_draw_flag |= DM_DRAW_USE_COLORS;
- }
- }
- else {
- if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) {
- dm_draw_flag |= DM_DRAW_USE_COLORS;
- }
- }
-
-
- userData.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY);
- userData.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
-
- if (draw_flags & DRAW_FACE_SELECT) {
- userData.me = me;
-
- dm->drawMappedFacesTex(
- dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions,
- &userData, dm_draw_flag);
- }
- else {
- userData.me = NULL;
-
- /* if ((ob->mode & OB_MODE_ALL_PAINT) == 0) */ {
-
- /* Note: this isn't efficient and runs on every redraw,
- * its needed so material colors are used for vertex colors.
- * In the future we will likely remove 'texface' so, just avoid running this where possible,
- * (when vertex paint or weight paint are used).
- *
- * Note 2: We disable optimization for now since it causes T48788
- * and it is now too close to release to do something smarter.
- *
- * TODO(sergey): Find some real solution here.
- */
-
- update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
- }
-
- dm->drawFacesTex(
- dm, draw_tface__set_draw, compareDrawOptions,
- &userData, dm_draw_flag);
- }
- }
-
- /* draw game engine text hack */
- if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
- if (BKE_bproperty_object_get(ob, "Text")) {
- draw_mesh_text(scene, ob, 0);
- }
- }
-
- draw_textured_end();
-
- /* draw edges and selected faces over textured mesh */
- if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) {
- bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0;
- draw_mesh_face_select(rv3d, me, dm, draw_select_edges);
- }
-
- /* reset from negative scale correction */
- glFrontFace(GL_CCW);
-
- /* in editmode, the blend mode needs to be set in case it was ADD */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-}
-
-/************************** NEW SHADING NODES ********************************/
-
-typedef struct TexMatCallback {
- Scene *scene;
- Object *ob;
- Mesh *me;
- DerivedMesh *dm;
- bool shadeless;
- bool two_sided_lighting;
-} TexMatCallback;
-
-static void tex_mat_set_material_cb(void *UNUSED(userData), int mat_nr, void *attribs)
-{
- /* all we have to do here is simply enable the GLSL material, but note
- * that the GLSL code will give different result depending on the drawtype,
- * in texture draw mode it will output the active texture node, in material
- * draw mode it will show the full material. */
- GPU_object_material_bind(mat_nr, attribs);
-}
-
-static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs)
-{
- /* texture draw mode without GLSL */
- TexMatCallback *data = (TexMatCallback *)userData;
- GPUVertexAttribs *gattribs = attribs;
- Image *ima;
- ImageUser *iuser;
- bNode *node;
-
- /* draw image texture if we find one */
- if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node, NULL)) {
- /* get openl texture */
- int mipmap = 1;
- int bindcode = (ima) ? GPU_verify_image(ima, iuser, GL_TEXTURE_2D, 0, 0, mipmap, false) : 0;
-
- if (bindcode) {
- NodeTexBase *texbase = node->storage;
-
- /* disable existing material */
- GPU_object_material_unbind();
-
- /* bind texture */
- glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
-
- glMatrixMode(GL_TEXTURE);
- glLoadMatrixf(texbase->tex_mapping.mat);
- glMatrixMode(GL_MODELVIEW);
-
- /* use active UV texture layer */
- memset(gattribs, 0, sizeof(*gattribs));
-
- gattribs->layer[0].type = CD_MTFACE;
- gattribs->layer[0].name[0] = '\0';
- gattribs->layer[0].gltexco = 1;
- gattribs->layer[0].glinfoindoex = -1;
- gattribs->totlayer = 1;
-
- /* bind material */
- float diffuse[3] = {1.0f, 1.0f, 1.0f};
-
- int options = GPU_SHADER_TEXTURE_2D;
- if (!data->shadeless)
- options |= GPU_SHADER_LIGHTING;
- if (data->two_sided_lighting)
- options |= GPU_SHADER_TWO_SIDED;
-
- GPU_basic_shader_colors(diffuse, NULL, 0, 1.0f);
- GPU_basic_shader_bind(options);
-
- return;
- }
- }
-
- /* disable texture material */
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
- if (data->shadeless) {
- glColor3f(1.0f, 1.0f, 1.0f);
- memset(gattribs, 0, sizeof(*gattribs));
- }
- else {
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
-
- /* enable solid material */
- GPU_object_material_bind(mat_nr, attribs);
- }
-}
-
-static bool tex_mat_set_face_mesh_cb(void *userData, int index)
-{
- /* faceselect mode face hiding */
- TexMatCallback *data = (TexMatCallback *)userData;
- Mesh *me = (Mesh *)data->me;
- MPoly *mp = &me->mpoly[index];
-
- return !(mp->flag & ME_HIDE);
-}
-
-static bool tex_mat_set_face_editmesh_cb(void *userData, int index)
-{
- /* editmode face hiding */
- TexMatCallback *data = (TexMatCallback *)userData;
- Mesh *me = (Mesh *)data->me;
- BMEditMesh *em = me->edit_btmesh;
- BMFace *efa;
-
- if (UNLIKELY(index >= em->bm->totface))
- return DM_DRAW_OPTION_NORMAL;
-
- efa = BM_face_at_index(em->bm, index);
-
- return !BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
-}
-
-void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
- Object *ob, DerivedMesh *dm, const int draw_flags)
-{
- /* if not cycles, or preview-modifiers, or drawing matcaps */
- if ((draw_flags & DRAW_MODIFIERS_PREVIEW) ||
- (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) ||
- (BKE_scene_use_new_shading_nodes(scene) == false) ||
- ((ob->mode & OB_MODE_TEXTURE_PAINT) && ELEM(v3d->drawtype, OB_TEXTURE, OB_SOLID)))
- {
- draw_mesh_textured_old(scene, v3d, rv3d, ob, dm, draw_flags);
- return;
- }
- else if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
- draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags);
- return;
- }
-
- /* set opengl state for negative scale & color */
- if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
- else glFrontFace(GL_CCW);
-
- Mesh *me = ob->data;
-
- bool shadeless = ((v3d->flag2 & V3D_SHADELESS_TEX) &&
- ((v3d->drawtype == OB_TEXTURE) || (ob->mode & OB_MODE_TEXTURE_PAINT)));
- bool two_sided_lighting = (me->flag & ME_TWOSIDED) != 0;
-
- TexMatCallback data = {scene, ob, me, dm, shadeless, two_sided_lighting};
- bool (*set_face_cb)(void *, int);
- bool picking = (G.f & G_PICKSEL) != 0;
-
- /* face hiding callback depending on mode */
- if (ob == scene->obedit)
- set_face_cb = tex_mat_set_face_editmesh_cb;
- else if (draw_flags & DRAW_FACE_SELECT)
- set_face_cb = tex_mat_set_face_mesh_cb;
- else
- set_face_cb = NULL;
-
- /* test if we can use glsl */
- const int drawtype = view3d_effective_drawtype(v3d);
- bool glsl = (drawtype == OB_MATERIAL) && !picking;
-
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
-
- if (glsl || picking) {
- /* draw glsl or solid */
- dm->drawMappedFacesMat(dm,
- tex_mat_set_material_cb,
- set_face_cb, &data);
- }
- else {
- /* draw textured */
- dm->drawMappedFacesMat(dm,
- tex_mat_set_texture_cb,
- set_face_cb, &data);
- }
-
- GPU_end_object_materials();
-
- /* reset opengl state */
- GPU_end_object_materials();
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
- glBindTexture(GL_TEXTURE_2D, 0);
-
- glFrontFace(GL_CCW);
-
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
-
- /* faceselect mode drawing over textured mesh */
- if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) {
- bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0;
- draw_mesh_face_select(rv3d, ob->data, dm, draw_select_edges);
- }
-}
-
-/* Vertex Paint and Weight Paint */
-static void draw_mesh_paint_light_begin(void)
-{
- /* get material diffuse color from vertex colors but set default spec */
- const float specular[3] = {0.47f, 0.47f, 0.47f};
- GPU_basic_shader_colors(NULL, specular, 35, 1.0f);
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
-}
-
-static void draw_mesh_paint_light_end(void)
-{
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-}
-
-void draw_mesh_paint_weight_faces(DerivedMesh *dm, const bool use_light,
- void *facemask_cb, void *user_data)
-{
- DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_object_material_bind : NULL;
- int flags = DM_DRAW_USE_COLORS;
-
- if (use_light) {
- draw_mesh_paint_light_begin();
- flags |= DM_DRAW_NEED_NORMALS;
- }
-
- dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, setMaterial, NULL, user_data, flags);
-
- if (use_light) {
- draw_mesh_paint_light_end();
- }
-}
-
-void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light,
- void *facemask_cb, void *user_data,
- const Mesh *me)
-{
- DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_object_material_bind : NULL;
- int flags = 0;
-
- if (use_light) {
- draw_mesh_paint_light_begin();
- flags |= DM_DRAW_NEED_NORMALS;
- }
-
- /* Don't show alpha in wire mode. */
- const bool show_alpha = use_light;
- if (show_alpha) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
-
- if (me->mloopcol) {
- dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data,
- DM_DRAW_USE_COLORS | flags);
- }
- else {
- glColor3f(1.0f, 1.0f, 1.0f);
- dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, flags);
- }
-
- if (show_alpha) {
- glDisable(GL_BLEND);
- }
-
- if (use_light) {
- draw_mesh_paint_light_end();
- }
-}
-
-void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm,
- const bool use_depth, const bool use_alpha,
- void *edgemask_cb, void *user_data)
-{
- /* weight paint in solid mode, special case. focus on making the weights clear
- * rather than the shading, this is also forced in wire view */
-
- if (use_depth) {
- ED_view3d_polygon_offset(rv3d, 1.0);
- glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
- }
- else {
- glDisable(GL_DEPTH_TEST);
- }
-
- if (use_alpha) {
- glEnable(GL_BLEND);
- }
-
- glColor4ub(255, 255, 255, 96);
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(1, 0xAAAA);
-
- dm->drawMappedEdges(dm, (DMSetDrawOptions)edgemask_cb, user_data);
-
- if (use_depth) {
- ED_view3d_polygon_offset(rv3d, 0.0);
- glDepthMask(1);
- }
- else {
- glEnable(GL_DEPTH_TEST);
- }
-
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
-
- if (use_alpha) {
- glDisable(GL_BLEND);
- }
-}
-
-void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
- Object *ob, DerivedMesh *dm, const int draw_flags)
-{
- DMSetDrawOptions facemask = NULL;
- Mesh *me = ob->data;
- const bool use_light = (v3d->drawtype >= OB_SOLID);
-
- /* hide faces in face select mode */
- if (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL))
- facemask = wpaint__setSolidDrawOptions_facemask;
-
- if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- draw_mesh_paint_weight_faces(dm, use_light, facemask, me);
- }
- else if (ob->mode & OB_MODE_VERTEX_PAINT) {
- draw_mesh_paint_vcolor_faces(dm, use_light, facemask, me, me);
- }
-
- /* draw face selection on top */
- if (draw_flags & DRAW_FACE_SELECT) {
- bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0;
- draw_mesh_face_select(rv3d, me, dm, draw_select_edges);
- }
- else if ((use_light == false) || (ob->dtx & OB_DRAWWIRE)) {
- const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) || !(ob->mode & OB_MODE_WEIGHT_PAINT);
- const bool use_alpha = (ob->mode & OB_MODE_VERTEX_PAINT) == 0;
-
- if (use_alpha == false) {
- set_inverted_drawing(1);
- }
-
- draw_mesh_paint_weight_edges(rv3d, dm, use_depth, use_alpha, NULL, NULL);
-
- if (use_alpha == false) {
- set_inverted_drawing(0);
- }
- }
-}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index c10f8f0ce16..9a73ef25819 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -27,248 +27,42 @@
* \ingroup spview3d
*/
-#include "MEM_guardedalloc.h"
-
-#include "DNA_camera_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_constraint_types.h" /* for drawing constraint */
-#include "DNA_lamp_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_smoke_types.h"
-#include "DNA_world_types.h"
#include "DNA_object_types.h"
-#include "BLI_listbase.h"
-#include "BLI_link_utils.h"
-#include "BLI_string.h"
#include "BLI_math.h"
-#include "BLI_memarena.h"
-#include "BKE_anim.h" /* for the where_on_path function */
-#include "BKE_armature.h"
-#include "BKE_camera.h"
-#include "BKE_colortools.h"
-#include "BKE_constraint.h" /* for the get_constraint_target function */
-#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
-#include "BKE_deform.h"
-#include "BKE_displist.h"
-#include "BKE_font.h"
#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_key.h"
-#include "BKE_lattice.h"
-#include "BKE_main.h"
-#include "BKE_mesh.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_modifier.h"
-#include "BKE_movieclip.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_pointcache.h"
-#include "BKE_scene.h"
-#include "BKE_subsurf.h"
-#include "BKE_unit.h"
-#include "BKE_tracking.h"
#include "BKE_editmesh.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "GPU_draw.h"
-#include "GPU_select.h"
-#include "GPU_basic_shader.h"
#include "GPU_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_batch.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+#include "GPU_framebuffer.h"
#include "ED_mesh.h"
-#include "ED_particle.h"
-#include "ED_screen.h"
-#include "ED_sculpt.h"
-#include "ED_types.h"
#include "UI_resources.h"
-#include "UI_interface_icons.h"
-
-#include "WM_api.h"
-#include "BLF_api.h"
#include "view3d_intern.h" /* bad level include */
-/* Workaround for sequencer scene render mode.
- *
- * Strips doesn't use DAG to update objects or so, which
- * might lead to situations when object is drawing without
- * curve cache ready.
- *
- * Ideally we don't want to evaluate objects from drawing,
- * but it'll require some major sequencer re-design. So
- * for now just fallback to legacy behavior with calling
- * display ist creating from draw().
- */
-#define SEQUENCER_DAG_WORKAROUND
-
-typedef enum eWireDrawMode {
- OBDRAW_WIRE_OFF = 0,
- OBDRAW_WIRE_ON = 1,
- OBDRAW_WIRE_ON_DEPTH = 2
-} eWireDrawMode;
-
-typedef struct drawDMVerts_userData {
- BMesh *bm;
-
- BMVert *eve_act;
- char sel;
-
- /* cached theme values */
- unsigned char th_editmesh_active[4];
- unsigned char th_vertex_select[4];
- unsigned char th_vertex[4];
- unsigned char th_skin_root[4];
-
- /* for skin node drawing */
- int cd_vskin_offset;
- float imat[4][4];
-} drawDMVerts_userData;
-
-typedef struct drawDMEdgesSel_userData {
- BMesh *bm;
-
- unsigned char *baseCol, *selCol, *actCol;
- BMEdge *eed_act;
-} drawDMEdgesSel_userData;
-
-typedef struct drawDMEdgesSelInterp_userData {
- BMesh *bm;
-
- unsigned char *baseCol, *selCol;
- unsigned char *lastCol;
-} drawDMEdgesSelInterp_userData;
-
-typedef struct drawDMEdgesWeightInterp_userData {
- BMesh *bm;
-
- int cd_dvert_offset;
- int defgroup_tot;
- int vgroup_index;
- char weight_user;
- float alert_color[3];
-
-} drawDMEdgesWeightInterp_userData;
-
-typedef struct drawDMFacesSel_userData {
-#ifdef WITH_FREESTYLE
- unsigned char *cols[4];
-#else
- unsigned char *cols[3];
-#endif
-
- DerivedMesh *dm;
- BMesh *bm;
-
- BMFace *efa_act;
- const int *orig_index_mp_to_orig;
-} drawDMFacesSel_userData;
-
-typedef struct drawDMNormal_userData {
- BMesh *bm;
- int uniform_scale;
- float normalsize;
- float tmat[3][3];
- float imat[3][3];
-} drawDMNormal_userData;
-
-typedef struct drawMVertOffset_userData {
- MVert *mvert;
- int offset;
-} drawMVertOffset_userData;
-
-typedef struct drawDMLayer_userData {
- BMesh *bm;
- int cd_layer_offset;
-} drawDMLayer_userData;
-
-typedef struct drawBMOffset_userData {
- BMesh *bm;
- int offset;
-} drawBMOffset_userData;
-
-typedef struct drawBMSelect_userData {
- BMesh *bm;
- bool select;
-} drawBMSelect_userData;
-
-static void draw_bounding_volume(Object *ob, char type);
-
-static void drawcube_size(float size);
-static void drawcircle_size(float size);
-static void draw_empty_sphere(float size);
-static void draw_empty_cone(float size);
-static void draw_box(const float vec[8][3], bool solid);
-
-static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
-{
- float col_wire[3], col_bg[3], col[3];
-
- rgb_uchar_to_float(col_wire, ob_wire_col);
-
- UI_GetThemeColor3fv(theme_id, col_bg);
- interp_v3_v3v3(col, col_bg, col_wire, fac);
- glColor3fv(col);
-}
+#include "../../draw/intern/draw_cache_impl.h" /* bad level include (temporary) */
int view3d_effective_drawtype(const struct View3D *v3d)
{
- if (v3d->drawtype == OB_RENDER) {
- return v3d->prev_drawtype;
+ if (v3d->shading.type == OB_RENDER) {
+ return v3d->shading.prev_type;
}
- return v3d->drawtype;
-}
-
-/* this condition has been made more complex since editmode can draw textures */
-bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype)
-{
- const int v3d_drawtype = view3d_effective_drawtype(v3d);
- /* texture and material draw modes */
- if (ELEM(v3d_drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) {
- return true;
- }
-
- /* textured solid */
- if ((v3d_drawtype == OB_SOLID) &&
- (v3d->flag2 & V3D_SOLID_TEX) &&
- (BKE_scene_use_new_shading_nodes(scene) == false))
- {
- return true;
- }
-
- if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) {
- return true;
- }
-
- return false;
-}
-
-static bool check_object_draw_editweight(Mesh *me, DerivedMesh *finalDM)
-{
- if (me->drawflag & ME_DRAWEIGHT) {
- /* editmesh handles its own weight drawing */
- if (finalDM->type != DM_TYPE_EDITBMESH) {
- return true;
- }
- }
-
- return false;
+ return v3d->shading.type;
}
static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
@@ -283,58 +77,15 @@ static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
return true;
/* if its drawing textures with zbuf sel, then don't draw dots */
- if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE)
+ if (dt == OB_TEXTURE && vd->shading.type == OB_TEXTURE)
return false;
- if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
+ if ((vd->shading.type >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX))
return false;
return true;
}
-/* ************************ */
-
-/* check for glsl drawing */
-
-bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
-{
- if (G.f & G_PICKSEL)
- return false;
- if (!check_object_draw_texture(scene, v3d, dt))
- return false;
- if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
- return false;
-
- if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
- return true;
-
- if (v3d->drawtype == OB_TEXTURE)
- return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene));
- else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID)
- return true;
- else
- return false;
-}
-
-static bool check_alpha_pass(Base *base)
-{
- if (base->flag & OB_FROMDUPLI)
- return false;
-
- if (G.f & G_PICKSEL)
- return false;
-
- if (base->object->mode & OB_MODE_ALL_PAINT)
- return false;
-
- return (base->object->dtx & OB_DRAWTRANSP);
-}
-
-/***/
-static const unsigned int colortab[] = {
- 0x0, 0x403000, 0xFFFF88
-};
-
/* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */
/* 32 values of sin function (still same result!) */
#define CIRCLE_RESOL 32
@@ -410,328 +161,6 @@ static const float cosval[CIRCLE_RESOL] = {
1.00000000
};
-/**
- * \param viewmat_local_unit is typically the 'rv3d->viewmatob'
- * copied into a 3x3 matrix and normalized.
- */
-static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis)
-{
- int line_type;
- float buffer[4][3];
- int n = 0;
-
- float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
- float dim = size * 0.1f;
- float dx[3], dy[3];
-
- dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f;
- dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f;
-
- switch (axis) {
- case 0: /* x axis */
- line_type = GL_LINES;
-
- /* bottom left to top right */
- negate_v3_v3(v1, dx);
- sub_v3_v3(v1, dy);
- copy_v3_v3(v2, dx);
- add_v3_v3(v2, dy);
-
- copy_v3_v3(buffer[n++], v1);
- copy_v3_v3(buffer[n++], v2);
-
- /* top left to bottom right */
- mul_v3_fl(dy, 2.0f);
- add_v3_v3(v1, dy);
- sub_v3_v3(v2, dy);
-
- copy_v3_v3(buffer[n++], v1);
- copy_v3_v3(buffer[n++], v2);
-
- break;
- case 1: /* y axis */
- line_type = GL_LINES;
-
- /* bottom left to top right */
- mul_v3_fl(dx, 0.75f);
- negate_v3_v3(v1, dx);
- sub_v3_v3(v1, dy);
- copy_v3_v3(v2, dx);
- add_v3_v3(v2, dy);
-
- copy_v3_v3(buffer[n++], v1);
- copy_v3_v3(buffer[n++], v2);
-
- /* top left to center */
- mul_v3_fl(dy, 2.0f);
- add_v3_v3(v1, dy);
- zero_v3(v2);
-
- copy_v3_v3(buffer[n++], v1);
- copy_v3_v3(buffer[n++], v2);
-
- break;
- case 2: /* z axis */
- line_type = GL_LINE_STRIP;
-
- /* start at top left */
- negate_v3_v3(v1, dx);
- add_v3_v3(v1, dy);
-
- copy_v3_v3(buffer[n++], v1);
-
- mul_v3_fl(dx, 2.0f);
- add_v3_v3(v1, dx);
-
- copy_v3_v3(buffer[n++], v1);
-
- mul_v3_fl(dy, 2.0f);
- sub_v3_v3(v1, dx);
- sub_v3_v3(v1, dy);
-
- copy_v3_v3(buffer[n++], v1);
-
- add_v3_v3(v1, dx);
-
- copy_v3_v3(buffer[n++], v1);
-
- break;
- default:
- BLI_assert(0);
- return;
- }
-
- for (int i = 0; i < n; i++) {
- mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
- add_v3_v3(buffer[i], c);
- }
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, buffer);
- glDrawArrays(line_type, 0, n);
- glDisableClientState(GL_VERTEX_ARRAY);
-}
-
-void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
-{
- int axis;
- float v1[3] = {0.0, 0.0, 0.0};
- float v2[3] = {0.0, 0.0, 0.0};
- float v3[3] = {0.0, 0.0, 0.0};
-
- glLineWidth(1);
-
- switch (drawtype) {
-
- case OB_PLAINAXES:
- for (axis = 0; axis < 3; axis++) {
- glBegin(GL_LINES);
-
- v1[axis] = size;
- v2[axis] = -size;
- glVertex3fv(v1);
- glVertex3fv(v2);
-
- /* reset v1 & v2 to zero */
- v1[axis] = v2[axis] = 0.0f;
-
- glEnd();
- }
- break;
- case OB_SINGLE_ARROW:
-
- glBegin(GL_LINES);
- /* in positive z direction only */
- v1[2] = size;
- glVertex3fv(v1);
- glVertex3fv(v2);
- glEnd();
-
- /* square pyramid */
- glBegin(GL_TRIANGLES);
-
- v2[0] = size * 0.035f; v2[1] = size * 0.035f;
- v3[0] = size * -0.035f; v3[1] = size * 0.035f;
- v2[2] = v3[2] = size * 0.75f;
-
- for (axis = 0; axis < 4; axis++) {
- if (axis % 2 == 1) {
- v2[0] = -v2[0];
- v3[1] = -v3[1];
- }
- else {
- v2[1] = -v2[1];
- v3[0] = -v3[0];
- }
-
- glVertex3fv(v1);
- glVertex3fv(v2);
- glVertex3fv(v3);
-
- }
- glEnd();
-
- break;
- case OB_CUBE:
- drawcube_size(size);
- break;
-
- case OB_CIRCLE:
- drawcircle_size(size);
- break;
-
- case OB_EMPTY_SPHERE:
- draw_empty_sphere(size);
- break;
-
- case OB_EMPTY_CONE:
- draw_empty_cone(size);
- break;
-
- case OB_ARROWS:
- default:
- {
- float viewmat_local_unit[3][3];
-
- copy_m3_m4(viewmat_local_unit, (float (*)[4])viewmat_local);
- normalize_m3(viewmat_local_unit);
-
- for (axis = 0; axis < 3; axis++) {
- const int arrow_axis = (axis == 0) ? 1 : 0;
-
- glBegin(GL_LINES);
-
- v2[axis] = size;
- glVertex3fv(v1);
- glVertex3fv(v2);
-
- v1[axis] = size * 0.85f;
- v1[arrow_axis] = -size * 0.08f;
- glVertex3fv(v1);
- glVertex3fv(v2);
-
- v1[arrow_axis] = size * 0.08f;
- glVertex3fv(v1);
- glVertex3fv(v2);
-
- glEnd();
-
- v2[axis] += size * 0.125f;
-
- draw_xyz_wire(viewmat_local_unit, v2, size, axis);
-
-
- /* reset v1 & v2 to zero */
- v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
- }
- break;
- }
- }
-}
-
-
-/* Function to draw an Image on an empty Object */
-static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], eStereoViews sview)
-{
- Image *ima = ob->data;
- ImBuf *ibuf;
- ImageUser iuser = *ob->iuser;
-
- /* Support multi-view */
- if (ima && (sview == STEREO_RIGHT_ID)) {
- iuser.multiview_eye = sview;
- iuser.flag |= IMA_SHOW_STEREO;
- BKE_image_multiview_index(ima, &iuser);
- }
-
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
-
- if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
- IMB_rect_from_float(ibuf);
- }
-
- int ima_x, ima_y;
-
- /* Get the buffer dimensions so we can fallback to fake ones */
- if (ibuf && ibuf->rect) {
- ima_x = ibuf->x;
- ima_y = ibuf->y;
- }
- else {
- ima_x = 1;
- ima_y = 1;
- }
-
- float sca_x = 1.0f;
- float sca_y = 1.0f;
-
- /* Get the image aspect even if the buffer is invalid */
- if (ima) {
- if (ima->aspx > ima->aspy) {
- sca_y = ima->aspy / ima->aspx;
- }
- else if (ima->aspx < ima->aspy) {
- sca_x = ima->aspx / ima->aspy;
- }
- }
-
- /* Calculate the scale center based on object's origin */
- float ofs_x = ob->ima_ofs[0] * ima_x;
- float ofs_y = ob->ima_ofs[1] * ima_y;
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
-
- /* Calculate Image scale */
- float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y);
-
- /* Set the object scale */
- glScalef(scale * sca_x, scale * sca_y, 1.0f);
-
- if (ibuf && ibuf->rect) {
- const bool use_clip = (U.glalphaclip != 1.0f);
- int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP) ? GL_NEAREST : GL_LINEAR;
- /* Setup GL params */
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- if (use_clip) {
- glEnable(GL_ALPHA_TEST);
- glAlphaFunc(GL_GREATER, U.glalphaclip);
- }
-
- /* Use the object color and alpha */
- glColor4fv(ob->col);
-
- /* Draw the Image on the screen */
- glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
-
- glDisable(GL_BLEND);
-
- if (use_clip) {
- glDisable(GL_ALPHA_TEST);
- glAlphaFunc(GL_ALWAYS, 0.0f);
- }
- }
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
- }
-
- /* Calculate the outline vertex positions */
- glBegin(GL_LINE_LOOP);
- glVertex2f(ofs_x, ofs_y);
- glVertex2f(ofs_x + ima_x, ofs_y);
- glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
- glVertex2f(ofs_x, ofs_y + ima_y);
- glEnd();
-
- /* Reset GL settings */
- glPopMatrix();
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-}
-
static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4])
{
float vx[3], vy[3];
@@ -747,838 +176,17 @@ static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3
}
}
-void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4])
+void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos)
{
float verts[CIRCLE_RESOL][3];
circball_array_fill(verts, cent, rad, tmat);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, verts);
- glDrawArrays(mode, 0, CIRCLE_RESOL);
- glDisableClientState(GL_VERTEX_ARRAY);
-}
-
-/* circle for object centers, special_color is for library or ob users */
-static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color)
-{
- const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
- float verts[CIRCLE_RESOL][3];
-
- /* using glDepthFunc guarantees that it does write z values,
- * but not checks for it, so centers remain visible independent of draw order */
- if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
- /* write to near buffer always */
- glDepthRange(0.0, 0.0);
- glEnable(GL_BLEND);
-
- if (special_color) {
- if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
- else glColor4ub(0x55, 0xCC, 0xCC, 155);
- }
- else {
- if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
- else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
- else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
- }
-
- circball_array_fill(verts, co, size, rv3d->viewinv);
-
- /* enable vertex array */
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, verts);
-
- /* 1. draw filled, blended polygon */
- glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
-
- /* 2. draw outline */
- glLineWidth(1);
- UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
- glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
-
- /* finish up */
- glDisableClientState(GL_VERTEX_ARRAY);
-
- glDepthRange(0.0, 1.0);
- glDisable(GL_BLEND);
-
- if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
-}
-
-/* *********** text drawing for object/particles/armature ************* */
-
-typedef struct ViewCachedString {
- struct ViewCachedString *next;
- float vec[3];
- union {
- unsigned char ub[4];
- int pack;
- } col;
- short sco[2];
- short xoffs;
- short flag;
- int str_len;
-
- /* str is allocated past the end */
- char str[0];
-} ViewCachedString;
-
-/* one arena for all 3 string lists */
-static MemArena *g_v3d_strings_arena = NULL;
-static ViewCachedString *g_v3d_strings[3] = {NULL, NULL, NULL};
-static int g_v3d_string_level = -1;
-
-void view3d_cached_text_draw_begin(void)
-{
- g_v3d_string_level++;
-
- BLI_assert(g_v3d_string_level >= 0);
-
- if (g_v3d_string_level == 0) {
- BLI_assert(g_v3d_strings_arena == NULL);
- }
-}
-
-void view3d_cached_text_draw_add(const float co[3],
- const char *str, const size_t str_len,
- short xoffs, short flag,
- const unsigned char col[4])
-{
- int alloc_len = str_len + 1;
- ViewCachedString *vos;
-
- BLI_assert(str_len == strlen(str));
-
- if (g_v3d_strings_arena == NULL) {
- g_v3d_strings_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 14), __func__);
- }
-
- vos = BLI_memarena_alloc(g_v3d_strings_arena, sizeof(ViewCachedString) + alloc_len);
-
- BLI_LINKS_PREPEND(g_v3d_strings[g_v3d_string_level], vos);
-
- copy_v3_v3(vos->vec, co);
- copy_v4_v4_uchar(vos->col.ub, col);
- vos->xoffs = xoffs;
- vos->flag = flag;
- vos->str_len = str_len;
-
- /* allocate past the end */
- memcpy(vos->str, str, alloc_len);
-}
-
-void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write)
-{
- RegionView3D *rv3d = ar->regiondata;
- ViewCachedString *vos;
- int tot = 0;
-
- BLI_assert(g_v3d_string_level >= 0 && g_v3d_string_level <= 2);
-
- /* project first and test */
- for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
- if (ED_view3d_project_short_ex(ar,
- (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob,
- (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0,
- vos->vec, vos->sco,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
- {
- tot++;
- }
- else {
- vos->sco[0] = IS_CLIPPED;
- }
- }
-
- if (tot) {
- int col_pack_prev = 0;
-
-#if 0
- bglMats mats; /* ZBuffer depth vars */
- double ux, uy, uz;
- float depth;
-
- if (v3d->zbuf)
- bgl_get_mats(&mats);
-#endif
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_disable();
- }
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- wmOrtho2_region_pixelspace(ar);
- glLoadIdentity();
-
- if (depth_write) {
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
- }
- else {
- glDepthMask(0);
- }
-
- for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
- if (vos->sco[0] != IS_CLIPPED) {
- if (col_pack_prev != vos->col.pack) {
- glColor3ubv(vos->col.ub);
- col_pack_prev = vos->col.pack;
- }
-
- ((vos->flag & V3D_CACHE_TEXT_ASCII) ? BLF_draw_default_ascii : BLF_draw_default)(
- (float)(vos->sco[0] + vos->xoffs),
- (float)(vos->sco[1]),
- (depth_write) ? 0.0f : 2.0f,
- vos->str,
- vos->str_len);
- }
- }
-
- if (depth_write) {
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- }
- else {
- glDepthMask(1);
- }
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_enable();
- }
- }
-
- g_v3d_strings[g_v3d_string_level] = NULL;
-
- if (g_v3d_string_level == 0) {
- if (g_v3d_strings_arena) {
- BLI_memarena_free(g_v3d_strings_arena);
- g_v3d_strings_arena = NULL;
- }
- }
-
- g_v3d_string_level--;
-}
-
-/* ******************** primitive drawing ******************* */
-
-/* draws a cube given the scaling of the cube, assuming that
- * all required matrices have been set (used for drawing empties)
- */
-static void drawcube_size(float size)
-{
- const GLfloat pos[8][3] = {
- {-size, -size, -size},
- {-size, -size, size},
- {-size, size, -size},
- {-size, size, size},
- { size, -size, -size},
- { size, -size, size},
- { size, size, -size},
- { size, size, size}
- };
-
- const GLubyte indices[24] = {0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6};
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, pos);
- glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
- glDisableClientState(GL_VERTEX_ARRAY);
-}
-
-static void drawshadbuflimits(Lamp *la, float mat[4][4])
-{
- float sta[3], end[3], lavec[3];
-
- negate_v3_v3(lavec, mat[2]);
- normalize_v3(lavec);
-
- madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
- madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
-
- glBegin(GL_LINES);
- glVertex3fv(sta);
- glVertex3fv(end);
- glEnd();
-
- glPointSize(3.0);
- glBegin(GL_POINTS);
- glVertex3fv(sta);
- glVertex3fv(end);
- glEnd();
-}
-
-static void spotvolume(float lvec[3], float vvec[3], const float inp)
-{
- /* camera is at 0,0,0 */
- float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle;
-
- normalize_v3(lvec);
- normalize_v3(vvec); /* is this the correct vector ? */
-
- cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec and lvec */
- cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parallel with lvec */
-
- /* vectors are exactly aligned, use the X axis, this is arbitrary */
- if (normalize_v3(plane) == 0.0f)
- plane[1] = 1.0f;
-
- /* now we've got two equations: one of a cone and one of a plane, but we have
- * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */
-
- /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
- /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
-
- /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
-
- q[1] = plane[1];
- q[2] = -plane[0];
- q[3] = 0;
- normalize_v3(&q[1]);
-
- angle = saacos(plane[2]) / 2.0f;
- co = cosf(angle);
- si = sqrtf(1 - co * co);
-
- q[0] = co;
- q[1] *= si;
- q[2] *= si;
- q[3] = 0;
-
- quat_to_mat3(mat1, q);
-
- /* rotate lamp vector now over acos(inp) degrees */
- copy_v3_v3(vvec, lvec);
-
- unit_m3(mat2);
- co = inp;
- si = sqrtf(1.0f - inp * inp);
-
- mat2[0][0] = co;
- mat2[1][0] = -si;
- mat2[0][1] = si;
- mat2[1][1] = co;
- mul_m3_m3m3(mat3, mat2, mat1);
-
- mat2[1][0] = si;
- mat2[0][1] = -si;
- mul_m3_m3m3(mat4, mat2, mat1);
- transpose_m3(mat1);
-
- mul_m3_m3m3(mat2, mat1, mat3);
- mul_m3_v3(mat2, lvec);
- mul_m3_m3m3(mat2, mat1, mat4);
- mul_m3_v3(mat2, vvec);
-}
-
-static void draw_spot_cone(Lamp *la, float x, float z)
-{
- z = fabsf(z);
-
- glBegin(GL_TRIANGLE_FAN);
- glVertex3f(0.0f, 0.0f, -x);
-
- if (la->mode & LA_SQUARE) {
- glVertex3f(z, z, 0);
- glVertex3f(-z, z, 0);
- glVertex3f(-z, -z, 0);
- glVertex3f(z, -z, 0);
- glVertex3f(z, z, 0);
- }
- else {
- for (int a = 0; a < 33; a++) {
- float angle = a * M_PI * 2 / (33 - 1);
- glVertex3f(z * cosf(angle), z * sinf(angle), 0);
- }
- }
-
- glEnd();
-}
-
-static void draw_transp_spot_volume(Lamp *la, float x, float z)
-{
- glEnable(GL_CULL_FACE);
- glEnable(GL_BLEND);
- glDepthMask(0);
-
- /* draw backside darkening */
- glCullFace(GL_FRONT);
-
- glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
-
- draw_spot_cone(la, x, z);
-
- /* draw front side lighting */
- glCullFace(GL_BACK);
-
- glBlendFunc(GL_ONE, GL_ONE);
- glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
-
- draw_spot_cone(la, x, z);
-
- /* restore state */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_BLEND);
- glDepthMask(1);
- glDisable(GL_CULL_FACE);
- glCullFace(GL_BACK);
-}
-
-#ifdef WITH_GAMEENGINE
-static void draw_transp_sun_volume(Lamp *la)
-{
- float box[8][3];
-
- /* construct box */
- box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size;
- box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size;
- box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size;
- box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size;
- box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend;
- box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
-
- /* draw edges */
- draw_box(box, false);
-
- /* draw faces */
- glEnable(GL_CULL_FACE);
- glEnable(GL_BLEND);
- glDepthMask(0);
-
- /* draw backside darkening */
- glCullFace(GL_FRONT);
-
- glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
- glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
-
- draw_box(box, true);
-
- /* draw front side lighting */
- glCullFace(GL_BACK);
-
- glBlendFunc(GL_ONE, GL_ONE);
- glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
-
- draw_box(box, true);
-
- /* restore state */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_BLEND);
- glDepthMask(1);
- glDisable(GL_CULL_FACE);
- glCullFace(GL_BACK);
-}
-#endif
-
-static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
- const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
-{
- Object *ob = base->object;
- const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
- Lamp *la = ob->data;
- float vec[3], lvec[3], vvec[3], circrad;
- float lampsize;
- float imat[4][4];
-
- unsigned char curcol[4];
- unsigned char col[4];
- /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
- /* the moment of view3d_draw_transp() call */
- const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
- const bool drawcone = ((dt > OB_WIRE) &&
- !(G.f & G_PICKSEL) &&
- (la->type == LA_SPOT) &&
- (la->mode & LA_SHOW_CONE) &&
- !(base->flag & OB_FROMDUPLI) &&
- !is_view);
-
-#ifdef WITH_GAMEENGINE
- const bool drawshadowbox = (
- (rv3d->rflag & RV3D_IS_GAME_ENGINE) &&
- (dt > OB_WIRE) &&
- !(G.f & G_PICKSEL) &&
- (la->type == LA_SUN) &&
- ((la->mode & LA_SHAD_BUF) ||
- (la->mode & LA_SHAD_RAY)) &&
- (la->mode & LA_SHOW_SHADOW_BOX) &&
- !(base->flag & OB_FROMDUPLI) &&
- !is_view);
-#else
- const bool drawshadowbox = false;
-#endif
-
- if ((drawcone || drawshadowbox) && !v3d->transp) {
- /* in this case we need to draw delayed */
- ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag);
- return;
- }
-
- /* we first draw only the screen aligned & fixed scale stuff */
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
-
- /* lets calculate the scale: */
- lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
-
- /* and view aligned matrix: */
- copy_m4_m4(imat, rv3d->viewinv);
- normalize_v3(imat[0]);
- normalize_v3(imat[1]);
-
- /* lamp center */
- copy_v3_v3(vec, ob->obmat[3]);
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- /* for AA effects */
- curcol[0] = ob_wire_col[0];
- curcol[1] = ob_wire_col[1];
- curcol[2] = ob_wire_col[2];
- curcol[3] = 154;
- glColor4ubv(curcol);
- }
-
- glLineWidth(1);
-
- if (lampsize > 0.0f) {
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (ob->id.us > 1) {
- if (is_obact || (ob->flag & SELECT)) {
- glColor4ub(0x88, 0xFF, 0xFF, 155);
- }
- else {
- glColor4ub(0x77, 0xCC, 0xCC, 155);
- }
- }
- }
-
- /* Inner Circle */
- glEnable(GL_BLEND);
- drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
- glDisable(GL_BLEND);
- drawcircball(GL_POLYGON, vec, lampsize, imat);
-
- /* restore */
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (ob->id.us > 1)
- glColor4ubv(curcol);
- }
-
- /* Outer circle */
- circrad = 3.0f * lampsize;
- setlinestyle(3);
-
- drawcircball(GL_LINE_LOOP, vec, circrad, imat);
-
- /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
- if (la->type != LA_HEMI) {
- if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
- drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
- }
- }
+ immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL);
+ for (int i = 0; i < CIRCLE_RESOL; ++i) {
+ immVertex3fv(pos, verts[i]);
}
- else {
- setlinestyle(3);
- circrad = 0.0f;
- }
-
- /* draw the pretty sun rays */
- if (la->type == LA_SUN) {
- float v1[3], v2[3], mat[3][3];
- short axis;
-
- /* setup a 45 degree rotation matrix */
- axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2);
-
- /* vectors */
- mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
- mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
-
- /* center */
- glTranslate3fv(vec);
-
- setlinestyle(3);
-
- glBegin(GL_LINES);
- for (axis = 0; axis < 8; axis++) {
- glVertex3fv(v1);
- glVertex3fv(v2);
- mul_m3_v3(mat, v1);
- mul_m3_v3(mat, v2);
- }
- glEnd();
-
- glTranslatef(-vec[0], -vec[1], -vec[2]);
-
- }
-
- if (la->type == LA_LOCAL) {
- if (la->mode & LA_SPHERE) {
- drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
- }
- }
-
- glPopMatrix(); /* back in object space */
- zero_v3(vec);
-
- if (is_view) {
- /* skip drawing extra info */
- }
- else if (la->type == LA_SPOT) {
- float x, y, z, z_abs;
- copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f);
- copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]);
- mul_transposed_mat3_m4_v3(ob->obmat, vvec);
-
- x = -la->dist;
- y = cosf(la->spotsize * 0.5f);
- z = x * sqrtf(1.0f - y * y);
-
- spotvolume(lvec, vvec, y);
- mul_v3_fl(lvec, x);
- mul_v3_fl(vvec, x);
-
- x *= y;
-
- z_abs = fabsf(z);
-
- if (la->mode & LA_SQUARE) {
- /* draw pyramid */
- const float vertices[5][3] = {
- /* 5 of vertex coords of pyramid */
- {0.0f, 0.0f, 0.0f},
- {z_abs, z_abs, x},
- {-z_abs, -z_abs, x},
- {z_abs, -z_abs, x},
- {-z_abs, z_abs, x},
- };
- const unsigned char indices[] = {
- 0, 1, 3,
- 0, 3, 2,
- 0, 2, 4,
- 0, 1, 4,
- };
-
- /* Draw call:
- * activate and specify pointer to vertex array */
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, vertices);
- /* draw the pyramid */
- glDrawElements(GL_LINE_STRIP, 12, GL_UNSIGNED_BYTE, indices);
-
- /* deactivate vertex arrays after drawing */
- glDisableClientState(GL_VERTEX_ARRAY);
-
- glTranslatef(0.0f, 0.0f, x);
-
- /* draw the square representing spotbl */
- if (la->type == LA_SPOT) {
- float blend = z_abs * (1.0f - pow2f(la->spotblend));
-
- /* hide line if it is zero size or overlaps with outer border,
- * previously it adjusted to always to show it but that seems
- * confusing because it doesn't show the actual blend size */
- if (blend != 0.0f && blend != z_abs) {
- fdrawbox(blend, -blend, -blend, blend);
- }
- }
- }
- else {
-
- /* draw the angled sides of the cone */
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vvec);
- glVertex3fv(vec);
- glVertex3fv(lvec);
- glEnd();
-
- /* draw the circle at the end of the cone */
- glTranslatef(0.0f, 0.0f, x);
- circ(0.0f, 0.0f, z_abs);
-
- /* draw the circle representing spotbl */
- if (la->type == LA_SPOT) {
- float blend = z_abs * (1.0f - pow2f(la->spotblend));
-
- /* hide line if it is zero size or overlaps with outer border,
- * previously it adjusted to always to show it but that seems
- * confusing because it doesn't show the actual blend size */
- if (blend != 0.0f && blend != z_abs) {
- circ(0.0f, 0.0f, blend);
- }
- }
- }
-
- if (drawcone)
- draw_transp_spot_volume(la, x, z);
-
- /* draw clip start, useful for wide cones where its not obvious where the start is */
- glTranslatef(0.0, 0.0, -x); /* reverse translation above */
- glBegin(GL_LINES);
- if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
- float lvec_clip[3];
- float vvec_clip[3];
- float clipsta_fac = la->clipsta / -x;
-
- interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
- interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
-
- glVertex3fv(lvec_clip);
- glVertex3fv(vvec_clip);
- }
- /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
- else {
- glVertex3f(0.0, 0.0, -circrad);
- glVertex3f(0.0, 0.0, -la->dist);
- }
- glEnd();
- }
- else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
-
- /* draw the line from the circle along the dist */
- glBegin(GL_LINES);
- vec[2] = -circrad;
- glVertex3fv(vec);
- vec[2] = -la->dist;
- glVertex3fv(vec);
- glEnd();
-
- if (la->type == LA_HEMI) {
- /* draw the hemisphere curves */
- short axis, steps, dir;
- float outdist, zdist, mul;
- zero_v3(vec);
- outdist = 0.14; mul = 1.4; dir = 1;
-
- setlinestyle(4);
- /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
- for (axis = 0; axis < 4; axis++) {
- float v[3] = {0.0, 0.0, 0.0};
- zdist = 0.02;
-
- glBegin(GL_LINE_STRIP);
-
- for (steps = 0; steps < 6; steps++) {
- if (axis == 0 || axis == 1) { /* x axis up, x axis down */
- /* make the arcs start at the edge of the energy circle */
- if (steps == 0) v[0] = dir * circrad;
- else v[0] = v[0] + dir * (steps * outdist);
- }
- else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
- /* make the arcs start at the edge of the energy circle */
- v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist));
- }
-
- v[2] = v[2] - steps * zdist;
-
- glVertex3fv(v);
-
- zdist = zdist * mul;
- }
-
- glEnd();
- /* flip the direction */
- dir = -dir;
- }
- }
-
-#ifdef WITH_GAMEENGINE
- if (drawshadowbox) {
- draw_transp_sun_volume(la);
- }
-#endif
-
- }
- else if (la->type == LA_AREA) {
- setlinestyle(3);
- if (la->area_shape == LA_AREA_SQUARE)
- fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
- else if (la->area_shape == LA_AREA_RECT)
- fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
-
- glBegin(GL_LINES);
- glVertex3f(0.0, 0.0, -circrad);
- glVertex3f(0.0, 0.0, -la->dist);
- glEnd();
- }
-
- /* and back to viewspace */
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
- copy_v3_v3(vec, ob->obmat[3]);
-
- setlinestyle(0);
-
- if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) {
- drawshadbuflimits(la, ob->obmat);
- }
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- UI_GetThemeColor4ubv(TH_LAMP, col);
- glColor4ubv(col);
- }
-
- glEnable(GL_BLEND);
-
- if (vec[2] > 0) vec[2] -= circrad;
- else vec[2] += circrad;
-
- glBegin(GL_LINES);
- glVertex3fv(vec);
- vec[2] = 0;
- glVertex3fv(vec);
- glEnd();
-
- glPointSize(2.0);
- glBegin(GL_POINTS);
- glVertex3fv(vec);
- glEnd();
-
- glDisable(GL_BLEND);
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- /* restore for drawing extra stuff */
- glColor3ubv(ob_wire_col);
- }
- /* and finally back to org object space! */
- glPopMatrix();
-}
-
-static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3])
-{
- glBegin(GL_LINES);
- glVertex3f(0.0, 0.0, -sta);
- glVertex3f(0.0, 0.0, -end);
- glEnd();
-
- if (!(dflag & DRAW_PICKING)) {
- glPointSize(3.0);
- glBegin(GL_POINTS);
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(col);
- }
- glVertex3f(0.0, 0.0, -sta);
- glVertex3f(0.0, 0.0, -end);
- glEnd();
- }
-}
-
-
-/* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
-/* qdn: now also enabled for Blender to set focus point for defocus composite node */
-static void draw_focus_cross(float dist, float size)
-{
- glBegin(GL_LINES);
- glVertex3f(-size, 0.0f, -dist);
- glVertex3f(size, 0.0f, -dist);
- glVertex3f(0.0f, -size, -dist);
- glVertex3f(0.0f, size, -dist);
- glEnd();
+ immEnd();
}
#ifdef VIEW3D_CAMERA_BORDER_HACK
@@ -1586,6840 +194,131 @@ unsigned char view3d_camera_border_hack_col[3];
bool view3d_camera_border_hack_test = false;
#endif
-/* ****************** draw clip data *************** */
-
-static void draw_bundle_sphere(void)
-{
- static GLuint displist = 0;
-
- if (displist == 0) {
- GLUquadricObj *qobj;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
- gluSphere(qobj, 0.05, 8, 8);
- gluDeleteQuadric(qobj);
-
- glEndList();
- }
-
- glCallList(displist);
-}
-
-static void draw_viewport_object_reconstruction(
- Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d,
- MovieClip *clip, MovieTrackingObject *tracking_object,
- const short dflag, const unsigned char ob_wire_col[4],
- int *global_track_index, bool draw_selected)
-{
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingTrack *track;
- float mat[4][4], imat[4][4];
- unsigned char col_unsel[4], col_sel[4];
- int tracknr = *global_track_index;
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
- float camera_size[3];
-
- UI_GetThemeColor4ubv(TH_TEXT, col_unsel);
- UI_GetThemeColor4ubv(TH_SELECT, col_sel);
-
- BKE_tracking_get_camera_object_matrix(scene, base->object, mat);
-
- /* we're compensating camera size for bundles size,
- * to make it so bundles are always displayed with the same size */
- copy_v3_v3(camera_size, base->object->size);
- if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
- mul_v3_fl(camera_size, tracking_object->scale);
-
- glPushMatrix();
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- /* current ogl matrix is translated in camera space, bundles should
- * be rendered in world space, so camera matrix should be "removed"
- * from current ogl matrix */
- invert_m4_m4(imat, base->object->obmat);
-
- glMultMatrixf(imat);
- glMultMatrixf(mat);
- }
- else {
- float obmat[4][4];
- int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra);
-
- BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat);
-
- invert_m4_m4(imat, obmat);
- glMultMatrixf(imat);
- }
-
- for (track = tracksbase->first; track; track = track->next) {
- bool selected = TRACK_SELECTED(track);
-
- if (draw_selected && !selected)
- continue;
-
- if ((track->flag & TRACK_HAS_BUNDLE) == 0)
- continue;
-
- if (dflag & DRAW_PICKING)
- GPU_select_load_id(base->selcol + (tracknr << 16));
-
- glPushMatrix();
- glTranslate3fv(track->bundle_pos);
- glScalef(v3d->bundle_size / 0.05f / camera_size[0],
- v3d->bundle_size / 0.05f / camera_size[1],
- v3d->bundle_size / 0.05f / camera_size[2]);
-
- const int v3d_drawtype = view3d_effective_drawtype(v3d);
- if (v3d_drawtype == OB_WIRE) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
- }
- else {
- glColor3fv(track->color);
- }
- }
-
- drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
- }
- else if (v3d_drawtype > OB_WIRE) {
- if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
- /* selection outline */
- if (selected) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
- }
-
- glLineWidth(2.0f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
- draw_bundle_sphere();
-
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- }
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
- else UI_ThemeColor(TH_BUNDLE_SOLID);
- }
-
- draw_bundle_sphere();
- }
- else {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (selected) {
- glColor3ubv(ob_wire_col);
- }
- else {
- if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
- else UI_ThemeColor(TH_WIRE);
- }
- }
-
- drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
- }
- }
-
- glPopMatrix();
-
- if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
- float pos[3];
-
- mul_v3_m4v3(pos, mat, track->bundle_pos);
- view3d_cached_text_draw_add(pos,
- track->name, strlen(track->name),
- 10, V3D_CACHE_TEXT_GLOBALSPACE,
- selected ? col_sel : col_unsel);
- }
-
- tracknr++;
- }
-
- if ((dflag & DRAW_PICKING) == 0) {
- if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) {
- MovieTrackingReconstruction *reconstruction;
- reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
-
- if (reconstruction->camnr) {
- MovieReconstructedCamera *camera = reconstruction->cameras;
-
- UI_ThemeColor(TH_CAMERA_PATH);
- glLineWidth(2.0f);
-
- glBegin(GL_LINE_STRIP);
- for (int a = 0; a < reconstruction->camnr; a++, camera++) {
- glVertex3fv(camera->mat[3]);
- }
- glEnd();
- }
- }
- }
-
- glPopMatrix();
-
- *global_track_index = tracknr;
-}
-
-static void draw_viewport_reconstruction(
- Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
- const short dflag, const unsigned char ob_wire_col[4],
- const bool draw_selected)
-{
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object;
- int global_track_index = 1;
-
- if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0)
- return;
-
- if (v3d->flag2 & V3D_RENDER_OVERRIDE)
- return;
-
- GPU_basic_shader_colors(NULL, NULL, 0, 1.0f);
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
-
- tracking_object = tracking->objects.first;
- while (tracking_object) {
- draw_viewport_object_reconstruction(
- scene, base, v3d, rv3d, clip, tracking_object,
- dflag, ob_wire_col, &global_track_index, draw_selected);
-
- tracking_object = tracking_object->next;
- }
-
- /* restore */
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
- }
-
- if (dflag & DRAW_PICKING)
- GPU_select_load_id(base->selcol);
-}
-
-static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
-{
- glBegin(mode);
- glVertex3fv(near_plane[0]);
- glVertex3fv(far_plane[0]);
- glVertex3fv(far_plane[1]);
- glVertex3fv(near_plane[1]);
- glEnd();
-
- glBegin(mode);
- glVertex3fv(near_plane[1]);
- glVertex3fv(far_plane[1]);
- glVertex3fv(far_plane[2]);
- glVertex3fv(near_plane[2]);
- glEnd();
-
- glBegin(mode);
- glVertex3fv(near_plane[2]);
- glVertex3fv(far_plane[2]);
- glVertex3fv(far_plane[3]);
- glVertex3fv(near_plane[3]);
- glEnd();
-
- glBegin(mode);
- glVertex3fv(far_plane[3]);
- glVertex3fv(near_plane[3]);
- glVertex3fv(near_plane[0]);
- glVertex3fv(far_plane[0]);
- glEnd();
-}
-
-/* camera frame */
-static void drawcamera_frame(float vec[4][3], const GLenum mode)
-{
- glBegin(mode);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[1]);
- glVertex3fv(vec[2]);
- glVertex3fv(vec[3]);
- glEnd();
-}
-
-/* center point to camera frame */
-static void drawcamera_framelines(float vec[4][3], float origin[3])
-{
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[1]);
- glVertex3fv(origin);
- glVertex3fv(vec[0]);
- glVertex3fv(vec[3]);
- glVertex3fv(origin);
- glVertex3fv(vec[2]);
- glEnd();
-}
-
-static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
-{
- return (ob == v3d->camera) &&
- (scene->r.scemode & R_MULTIVIEW) != 0 &&
- (v3d->stereo3d_flag);
-}
-
-static void drawcamera_stereo3d(
- Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
- float vec[4][3], float drawsize, const float scale[3])
-{
- float obmat[4][4];
- float vec_lr[2][4][3];
- const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
- float origin[2][3] = {{0}};
- float tvec[3];
- const Camera *cam_lr[2];
- const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
-
- const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
- const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
- const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME);
-
- zero_v3(tvec);
-
- glPushMatrix();
-
- for (int i = 0; i < 2; i++) {
- ob = BKE_camera_multiview_render(scene, ob, names[i]);
- cam_lr[i] = ob->data;
-
- glLoadMatrixf(rv3d->viewmat);
- BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
- glMultMatrixf(obmat);
-
- copy_m3_m3(vec_lr[i], vec);
- copy_v3_v3(vec_lr[i][3], vec[3]);
-
- if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
- const float shift_x =
- ((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) *
- (drawsize * scale[0] * fac));
-
- for (int j = 0; j < 4; j++) {
- vec_lr[i][j][0] += shift_x;
- }
- }
-
- if (is_stereo3d_cameras) {
- /* camera frame */
- drawcamera_frame(vec_lr[i], GL_LINE_LOOP);
-
- /* center point to camera frame */
- drawcamera_framelines(vec_lr[i], tvec);
- }
-
- /* connecting line */
- mul_m4_v3(obmat, origin[i]);
-
- /* convergence plane */
- if (is_stereo3d_plane || is_stereo3d_volume) {
- for (int j = 0; j < 4; j++) {
- mul_m4_v3(obmat, vec_lr[i][j]);
- }
- }
- }
-
-
- /* the remaining drawing takes place in the view space */
- glLoadMatrixf(rv3d->viewmat);
-
- if (is_stereo3d_cameras) {
- /* draw connecting lines */
- GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- GPU_basic_shader_line_stipple(2, 0xAAAA);
-
- glBegin(GL_LINES);
- glVertex3fv(origin[0]);
- glVertex3fv(origin[1]);
- glEnd();
-
- GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- }
-
- /* draw convergence plane */
- if (is_stereo3d_plane) {
- float axis_center[3], screen_center[3];
- float world_plane[4][3];
- float local_plane[4][3];
- float offset;
-
- mid_v3_v3v3(axis_center, origin[0], origin[1]);
-
- for (int i = 0; i < 4; i++) {
- mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]);
- sub_v3_v3v3(local_plane[i], world_plane[i], axis_center);
- }
-
- mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]);
- offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center);
-
- for (int i = 0; i < 4; i++) {
- mul_v3_fl(local_plane[i], offset);
- add_v3_v3(local_plane[i], axis_center);
- }
-
- glColor3f(0.0f, 0.0f, 0.0f);
-
- /* camera frame */
- drawcamera_frame(local_plane, GL_LINE_LOOP);
-
- if (v3d->stereo3d_convergence_alpha > 0.0f) {
- glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
-
- glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
-
- drawcamera_frame(local_plane, GL_QUADS);
-
- glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
- }
- }
-
- /* draw convergence plane */
- if (is_stereo3d_volume) {
- float screen_center[3];
- float near_plane[4][3], far_plane[4][3];
-
- for (int i = 0; i < 2; i++) {
- mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]);
-
- float offset = len_v3v3(screen_center, origin[i]);
-
- for (int j = 0; j < 4; j++) {
- sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]);
- mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset);
- add_v3_v3(near_plane[j], origin[i]);
-
- sub_v3_v3v3(far_plane[j], vec_lr[i][j], origin[i]);
- mul_v3_fl(far_plane[j], cam_lr[i]->clipend / offset);
- add_v3_v3(far_plane[j], origin[i]);
- }
-
- /* camera frame */
- glColor3f(0.0f, 0.0f, 0.0f);
-
- drawcamera_frame(near_plane, GL_LINE_LOOP);
- drawcamera_frame(far_plane, GL_LINE_LOOP);
- drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP);
-
- if (v3d->stereo3d_volume_alpha > 0.0f) {
- glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
-
- if (i == 0)
- glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
- else
- glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
-
- drawcamera_frame(near_plane, GL_QUADS);
- drawcamera_frame(far_plane, GL_QUADS);
- drawcamera_volume(near_plane, far_plane, GL_QUADS);
-
- glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
- }
- }
- }
-
- glPopMatrix();
-}
-
-/* flag similar to draw_object() */
-static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
- const short dflag, const unsigned char ob_wire_col[4])
-{
- /* a standing up pyramid with (0,0,0) as top */
- Camera *cam;
- Object *ob = base->object;
- float tvec[3];
- float vec[4][3], asp[2], shift[2], scale[3];
- MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
-
- const bool is_active = (ob == v3d->camera);
- const bool is_view = (rv3d->persp == RV3D_CAMOB && is_active);
- const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
- const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
- const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
- const bool is_stereo3d_cameras = (ob == scene->camera) &&
- is_multiview &&
- is_stereo3d_view &&
- (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS);
- const bool is_selection_camera_stereo = (G.f & G_PICKSEL) &&
- is_view && is_multiview &&
- is_stereo3d_view;
-
- /* draw data for movie clip set as active for scene */
- if (clip) {
- draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, false);
- draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, true);
- }
-
-#ifdef VIEW3D_CAMERA_BORDER_HACK
- if (is_view && !(G.f & G_PICKSEL)) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- view3d_camera_border_hack_col[0] = ob_wire_col[0];
- view3d_camera_border_hack_col[1] = ob_wire_col[1];
- view3d_camera_border_hack_col[2] = ob_wire_col[2];
- }
- else {
- float col[4];
- glGetFloatv(GL_CURRENT_COLOR, col);
- rgb_float_to_uchar(view3d_camera_border_hack_col, col);
- }
- view3d_camera_border_hack_test = true;
- return;
- }
-#endif
-
- cam = ob->data;
-
- /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here */
- if (is_selection_camera_stereo) {
- scale[0] = 1.0f;
- scale[1] = 1.0f;
- scale[2] = 1.0f;
- }
- else {
- scale[0] = 1.0f / len_v3(ob->obmat[0]);
- scale[1] = 1.0f / len_v3(ob->obmat[1]);
- scale[2] = 1.0f / len_v3(ob->obmat[2]);
- }
-
- float drawsize;
- BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
- asp, shift, &drawsize, vec);
-
- glDisable(GL_CULL_FACE);
- glLineWidth(1);
-
- /* camera frame */
- if (!is_stereo3d_cameras) {
- /* make sure selection uses the same matrix for camera as the one used while viewing */
- if (is_selection_camera_stereo) {
- float obmat[4][4];
- bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
-
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
- BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
- glMultMatrixf(obmat);
-
- drawcamera_frame(vec, GL_LINE_LOOP);
- glPopMatrix();
- }
- else {
- drawcamera_frame(vec, GL_LINE_LOOP);
- }
- }
-
- if (is_view)
- return;
-
- zero_v3(tvec);
-
- /* center point to camera frame */
- if (!is_stereo3d_cameras)
- drawcamera_framelines(vec, tvec);
-
- /* arrow on top */
- tvec[2] = vec[1][2]; /* copy the depth */
-
- /* draw an outline arrow for inactive cameras and filled
- * for active cameras. We actually draw both outline+filled
- * for active cameras so the wire can be seen side-on */
- for (int i = 0; i < 2; i++) {
- if (i == 0) glBegin(GL_LINE_LOOP);
- else if (i == 1 && is_active) glBegin(GL_TRIANGLES);
- else break;
-
- tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
- tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
- glVertex3fv(tvec); /* left */
-
- tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
- glVertex3fv(tvec); /* right */
-
- tvec[0] = shift[0];
- tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
- glVertex3fv(tvec); /* top */
-
- glEnd();
- }
-
- if ((dflag & DRAW_SCENESET) == 0) {
- if (cam->flag & (CAM_SHOWLIMITS | CAM_SHOWMIST)) {
- float nobmat[4][4];
-
- /* draw in normalized object matrix space */
- copy_m4_m4(nobmat, ob->obmat);
- normalize_m4(nobmat);
-
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
- glMultMatrixf(nobmat);
-
- if (cam->flag & CAM_SHOWLIMITS) {
- const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120};
-
- draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col));
- /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
- draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
- }
-
- if (cam->flag & CAM_SHOWMIST) {
- World *world = scene->world;
- const unsigned char col[3] = {128, 128, 128}, col_hi[3] = {255, 255, 255};
-
- if (world) {
- draw_limit_line(world->miststa, world->miststa + world->mistdist,
- dflag, (is_active ? col_hi : col));
- }
- }
- glPopMatrix();
- }
- }
-
- /* stereo cameras drawing */
- if (is_stereo3d) {
- drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
- }
-}
-
-/* flag similar to draw_object() */
-static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
- Object *UNUSED(ob), int UNUSED(flag))
-{
- float vec[3];
-
- glEnable(GL_BLEND);
- glLineWidth(1);
-
- for (int j = 0; j < 3; j++) {
- vec[2] = 0.25f * j - 0.125f;
-
- glBegin(GL_LINE_LOOP);
- for (int i = 0; i < 16; i++) {
- vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
- vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
- glVertex3fv(vec);
- }
- glEnd();
- }
-
- for (int j = 0; j < 4; j++) {
- vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
- vec[1] = ((j % 2) * (j - 2)) * 0.5f;
- glBegin(GL_LINE_STRIP);
- for (int i = 0; i < 3; i++) {
- if (i == 1) {
- vec[0] *= 0.5f;
- vec[1] *= 0.5f;
- }
-
- vec[2] = 0.25f * i - 0.125f;
- glVertex3fv(vec);
- }
- glEnd();
- }
-
- glDisable(GL_BLEND);
-}
-
-static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel)
-{
- BPoint *bp = lt->def;
- const float *co = dl ? dl->verts : NULL;
-
- const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
- UI_ThemeColor(color);
-
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- glBegin(GL_POINTS);
-
- for (int w = 0; w < lt->pntsw; w++) {
- int wxt = (w == 0 || w == lt->pntsw - 1);
- for (int v = 0; v < lt->pntsv; v++) {
- int vxt = (v == 0 || v == lt->pntsv - 1);
- for (int u = 0; u < lt->pntsu; u++, bp++, co += 3) {
- int uxt = (u == 0 || u == lt->pntsu - 1);
- if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
- if (bp->hide == 0) {
- /* check for active BPoint and ensure selected */
- if ((bp == actbp) && (bp->f1 & SELECT)) {
- UI_ThemeColor(TH_ACTIVE_VERT);
- glVertex3fv(dl ? co : bp->vec);
- UI_ThemeColor(color);
- }
- else if ((bp->f1 & SELECT) == sel) {
- glVertex3fv(dl ? co : bp->vec);
- }
- }
- }
- }
- }
- }
-
- glEnd();
-}
-
-static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
-{
- int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
-
- if (actdef_wcol) {
- float col[3];
- MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
-
- weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
- glColor3fv(col);
-
- }
-
- if (dl) {
- glVertex3fv(&dl->verts[index * 3]);
- }
- else {
- glVertex3fv(lt->def[index].vec);
- }
-}
-
-#ifdef SEQUENCER_DAG_WORKAROUND
-static void ensure_curve_cache(Main *bmain, Scene *scene, Object *object)
-{
- bool need_recalc = object->curve_cache == NULL;
- /* Render thread might have freed the curve cache if the
- * object is not visible. If the object is also used for
- * particles duplication, then render thread might have
- * also created curve_cache with only bevel and path
- * filled in.
- *
- * So check for curve_cache != NULL is not fully correct
- * here, we also need to check whether display list is
- * empty or not.
- *
- * The trick below tries to optimize calls to displist
- * creation for cases curve is empty. Meaning, if the curve
- * is empty (without splines) bevel list would also be empty.
- * And the thing is, render thread always leaves bevel list
- * in a proper state. So if bevel list is here and display
- * list is not we need to make display list.
- */
- if (need_recalc == false) {
- need_recalc = object->curve_cache->disp.first == NULL &&
- object->curve_cache->bev.first != NULL;
- }
- if (need_recalc) {
- switch (object->type) {
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
- BKE_displist_make_curveTypes(scene, object, false);
- break;
- case OB_MBALL:
- BKE_displist_make_mball(bmain, bmain->eval_ctx, scene, object);
- break;
- case OB_LATTICE:
- BKE_lattice_modifiers_calc(scene, object);
- break;
- }
- }
-}
-#endif
-
-/* lattice color is hardcoded, now also shows weightgroup values in edit mode */
-static void drawlattice(View3D *v3d, Object *ob)
-{
- Lattice *lt = ob->data;
- DispList *dl;
- int u, v, w;
- int actdef_wcol = 0;
- const bool is_edit = (lt->editlatt != NULL);
-
- dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS);
-
- if (is_edit) {
- lt = lt->editlatt->latt;
-
- UI_ThemeColor(TH_WIRE_EDIT);
-
- if (ob->defbase.first && lt->dvert) {
- actdef_wcol = ob->actdef;
- }
- }
-
- glLineWidth(1);
- glBegin(GL_LINES);
- for (w = 0; w < lt->pntsw; w++) {
- int wxt = (w == 0 || w == lt->pntsw - 1);
- for (v = 0; v < lt->pntsv; v++) {
- int vxt = (v == 0 || v == lt->pntsv - 1);
- for (u = 0; u < lt->pntsu; u++) {
- int uxt = (u == 0 || u == lt->pntsu - 1);
-
- if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
- drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol);
- drawlattice__point(lt, dl, u, v, w, actdef_wcol);
- }
- if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
- drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol);
- drawlattice__point(lt, dl, u, v, w, actdef_wcol);
- }
- if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
- drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol);
- drawlattice__point(lt, dl, u, v, w, actdef_wcol);
- }
- }
- }
- }
- glEnd();
-
- if (is_edit) {
- BPoint *actbp = BKE_lattice_active_point_get(lt);
-
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- lattice_draw_verts(lt, dl, actbp, 0);
- lattice_draw_verts(lt, dl, actbp, 1);
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- }
-}
-
-/* ***************** ******************** */
-
-/* draw callback */
-
-typedef struct drawDMVertSel_userData {
- MVert *mvert;
- int active;
- unsigned char *col[3]; /* (base, sel, act) */
- char sel_prev;
-} drawDMVertSel_userData;
-
-static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- drawDMVertSel_userData *data = userData;
- MVert *mv = &data->mvert[index];
-
- if (!(mv->flag & ME_HIDE)) {
- const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
- if (sel != data->sel_prev) {
- glColor3ubv(data->col[sel]);
- data->sel_prev = sel;
- }
-
- glVertex3fv(co);
- }
-}
-
-static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
-{
- drawDMVertSel_userData data;
-
- /* TODO define selected color */
- unsigned char base_col[3] = {0x0, 0x0, 0x0};
- unsigned char sel_col[3] = {0xd8, 0xb8, 0x0};
- unsigned char act_col[3] = {0xff, 0xff, 0xff};
-
- data.mvert = me->mvert;
- data.active = BKE_mesh_mselect_active_get(me, ME_VSEL);
- data.sel_prev = 0xff;
-
- data.col[0] = base_col;
- data.col[1] = sel_col;
- data.col[2] = act_col;
-
- glBegin(GL_POINTS);
- dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
-}
-
-/* ************** DRAW MESH ****************** */
-
-/* First section is all the "simple" draw routines,
- * ones that just pass some sort of primitive to GL,
- * with perhaps various options to control lighting,
- * color, etc.
- *
- * These routines should not have user interface related
- * logic!!!
- */
-
-static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data)
-{
- float obmat[3][3];
-
- copy_m3_m4(obmat, ob->obmat);
-
- data->uniform_scale = is_uniform_scaled_m3(obmat);
-
- if (!data->uniform_scale) {
- /* inverted matrix */
- invert_m3_m3(data->imat, obmat);
-
- /* transposed inverted matrix */
- transpose_m3_m3(data->tmat, data->imat);
- }
-}
-
-static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3])
-{
- drawDMNormal_userData *data = userData;
- BMFace *efa = BM_face_at_index(data->bm, index);
- float n[3];
-
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- if (!data->uniform_scale) {
- mul_v3_m3v3(n, data->tmat, no);
- normalize_v3(n);
- mul_m3_v3(data->imat, n);
- }
- else {
- copy_v3_v3(n, no);
- }
-
- glVertex3fv(cent);
- glVertex3f(cent[0] + n[0] * data->normalsize,
- cent[1] + n[1] * data->normalsize,
- cent[2] + n[2] * data->normalsize);
- }
-}
-
-static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
-{
- drawDMNormal_userData data;
-
- data.bm = em->bm;
- data.normalsize = scene->toolsettings->normalsize;
-
- calcDrawDMNormalScale(ob, &data);
-
- glBegin(GL_LINES);
- dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
- glEnd();
-}
-
-static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
-{
- drawBMSelect_userData *data = userData;
- BMFace *efa = BM_face_at_index(data->bm, index);
-
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
- (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
- {
- glVertex3fv(cent);
- }
-}
-static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select)
-{
- drawBMSelect_userData data = {em->bm, select};
-
- glBegin(GL_POINTS);
- dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
-}
-
-static void draw_dm_vert_normals__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
-{
- drawDMNormal_userData *data = userData;
- BMVert *eve = BM_vert_at_index(data->bm, index);
-
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- float no[3], n[3];
-
- if (no_f) {
- copy_v3_v3(no, no_f);
- }
- else {
- normal_short_to_float_v3(no, no_s);
- }
-
- if (!data->uniform_scale) {
- mul_v3_m3v3(n, data->tmat, no);
- normalize_v3(n);
- mul_m3_v3(data->imat, n);
- }
- else {
- copy_v3_v3(n, no);
- }
-
- glVertex3fv(co);
- glVertex3f(co[0] + n[0] * data->normalsize,
- co[1] + n[1] * data->normalsize,
- co[2] + n[2] * data->normalsize);
- }
-}
-
-static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
-{
- drawDMNormal_userData data;
-
- data.bm = em->bm;
- data.normalsize = scene->toolsettings->normalsize;
-
- calcDrawDMNormalScale(ob, &data);
-
- glBegin(GL_LINES);
- dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
- glEnd();
-}
-
-/* Draw verts with color set based on selection */
-static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- drawDMVerts_userData *data = userData;
- BMVert *eve = BM_vert_at_index(data->bm, index);
-
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
- /* skin nodes: draw a red circle around the root node(s) */
- if (data->cd_vskin_offset != -1) {
- const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
- if (vs->flag & MVERT_SKIN_ROOT) {
- float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
- glEnd();
-
- glColor4ubv(data->th_skin_root);
- drawcircball(GL_LINES, co, radius, data->imat);
-
- glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
- glBegin(GL_POINTS);
- }
- }
-
- /* draw active in a different color - no need to stop/start point drawing for this :D */
- if (eve == data->eve_act) {
- glColor4ubv(data->th_editmesh_active);
- glVertex3fv(co);
-
- /* back to regular vertex color */
- glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
- }
- else {
- glVertex3fv(co);
- }
- }
-}
-
-static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
- RegionView3D *rv3d)
-{
- drawDMVerts_userData data;
- data.sel = sel;
- data.eve_act = eve_act;
- data.bm = em->bm;
-
- /* Cache theme values */
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
- UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
- UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
- UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
-
- /* For skin root drawing */
- data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
- /* view-aligned matrix */
- mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
- invert_m4(data.imat);
-
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- glBegin(GL_POINTS);
- dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
-}
-
-/* Draw edges with color set based on selection */
-static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
-{
- BMEdge *eed;
- drawDMEdgesSel_userData *data = userData;
- unsigned char *col;
-
- eed = BM_edge_at_index(data->bm, index);
-
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- if (eed == data->eed_act) {
- glColor4ubv(data->actCol);
- }
- else {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- col = data->selCol;
- }
- else {
- col = data->baseCol;
- }
- /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
- if (col[3] == 0)
- return DM_DRAW_OPTION_SKIP;
-
- glColor4ubv(col);
- }
- return DM_DRAW_OPTION_NORMAL;
- }
- else {
- return DM_DRAW_OPTION_SKIP;
- }
-}
-
-static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
- unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
-{
- drawDMEdgesSel_userData data;
-
- data.baseCol = baseCol;
- data.selCol = selCol;
- data.actCol = actCol;
- data.bm = em->bm;
- data.eed_act = eed_act;
- dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
-}
-
-/* Draw edges */
-static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index)
-{
- if (BM_elem_flag_test(BM_edge_at_index(userData, index), BM_ELEM_HIDDEN))
- return DM_DRAW_OPTION_SKIP;
- else
- return DM_DRAW_OPTION_NORMAL;
-}
-
-static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
-{
- dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em->bm);
-}
-
-/* Draw edges with color interpolated based on selection */
-static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
-{
- drawDMEdgesSelInterp_userData *data = userData;
- if (BM_elem_flag_test(BM_edge_at_index(data->bm, index), BM_ELEM_HIDDEN))
- return DM_DRAW_OPTION_SKIP;
- else
- return DM_DRAW_OPTION_NORMAL;
-}
-static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
-{
- drawDMEdgesSelInterp_userData *data = userData;
- BMEdge *eed = BM_edge_at_index(data->bm, index);
- unsigned char **cols = userData;
- unsigned int col0_id = (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1;
- unsigned int col1_id = (BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1;
- unsigned char *col0 = cols[col0_id];
- unsigned char *col1 = cols[col1_id];
- unsigned char *col_pt;
-
- if (col0_id == col1_id) {
- col_pt = col0;
- }
- else if (t == 0.0f) {
- col_pt = col0;
- }
- else if (t == 1.0f) {
- col_pt = col1;
- }
- else {
- unsigned char col_blend[4];
- interp_v4_v4v4_uchar(col_blend, col0, col1, t);
- glColor4ubv(col_blend);
- data->lastCol = NULL;
- return;
- }
-
- if (data->lastCol != col_pt) {
- data->lastCol = col_pt;
- glColor4ubv(col_pt);
- }
-}
-
-static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
-{
- drawDMEdgesSelInterp_userData data;
- data.bm = em->bm;
- data.baseCol = baseCol;
- data.selCol = selCol;
- data.lastCol = NULL;
-
- dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, &data);
-}
-
-static void bm_color_from_weight(float col[3], BMVert *vert, drawDMEdgesWeightInterp_userData *data)
-{
- MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, data->cd_dvert_offset);
- float weight = defvert_find_weight(dvert, data->vgroup_index);
-
- if ((weight == 0.0f) &&
- ((data->weight_user == OB_DRAW_GROUPUSER_ACTIVE) ||
- ((data->weight_user == OB_DRAW_GROUPUSER_ALL) && defvert_is_weight_zero(dvert, data->defgroup_tot))))
- {
- copy_v3_v3(col, data->alert_color);
- }
- else {
- weight_to_rgb(col, weight);
- }
-}
-
-static void draw_dm_edges_nop_interp__setDrawInterpOptions(void *UNUSED(userData), int UNUSED(index), float UNUSED(t))
-{
- /* pass */
-}
-
-static void draw_dm_edges_weight_interp__setDrawInterpOptions(void *userData, int index, float t)
-{
- drawDMEdgesWeightInterp_userData *data = userData;
- BMEdge *eed = BM_edge_at_index(data->bm, index);
- float col[3];
-
- if (t == 0.0f) {
- bm_color_from_weight(col, eed->v1, data);
- }
- else if (t == 1.0f) {
- bm_color_from_weight(col, eed->v2, data);
- }
- else {
- float col_v1[3];
- float col_v2[3];
-
- bm_color_from_weight(col_v1, eed->v1, data);
- bm_color_from_weight(col_v2, eed->v2, data);
- interp_v3_v3v3(col, col_v1, col_v2, t);
- }
-
- glColor3fv(col);
-}
-
-static void draw_dm_edges_weight_interp(BMEditMesh *em, DerivedMesh *dm, const char weight_user)
-{
- drawDMEdgesWeightInterp_userData data;
- Object *ob = em->ob;
-
- data.bm = em->bm;
- data.cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
- data.defgroup_tot = BLI_listbase_count(&ob->defbase);
- data.vgroup_index = ob->actdef - 1;
- data.weight_user = weight_user;
- UI_GetThemeColor3fv(TH_VERTEX_UNREFERENCED, data.alert_color);
-
- if ((data.vgroup_index != -1) && (data.cd_dvert_offset != -1)) {
- glEnable(GL_BLEND);
- dm->drawMappedEdgesInterp(
- dm,
- draw_dm_edges_sel_interp__setDrawOptions,
- draw_dm_edges_weight_interp__setDrawInterpOptions,
- &data);
- glDisable(GL_BLEND);
- }
- else {
- float col[3];
-
- if (data.weight_user == OB_DRAW_GROUPUSER_NONE) {
- weight_to_rgb(col, 0.0f);
- }
- else {
- copy_v3_v3(col, data.alert_color);
- }
- glColor3fv(col);
-
- dm->drawMappedEdgesInterp(
- dm,
- draw_dm_edges_sel_interp__setDrawOptions,
- draw_dm_edges_nop_interp__setDrawInterpOptions,
- &data);
- }
-
-}
-
-static bool draw_dm_edges_weight_check(Mesh *me, View3D *v3d)
-{
- if (me->drawflag & ME_DRAWEIGHT) {
- if ((v3d->drawtype == OB_WIRE) ||
- (v3d->flag2 & V3D_SOLID_MATCAP) ||
- ((v3d->flag2 & V3D_OCCLUDE_WIRE) && (v3d->drawtype > OB_WIRE)))
- {
- return true;
- }
- }
-
- return false;
-}
-
-/* Draw only seam edges */
-static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index)
-{
- BMEdge *eed = BM_edge_at_index(userData, index);
-
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM))
- return DM_DRAW_OPTION_NORMAL;
- else
- return DM_DRAW_OPTION_SKIP;
-}
-
-static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
-{
- dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em->bm);
-}
-
-/* Draw only sharp edges */
-static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
-{
- BMEdge *eed = BM_edge_at_index(userData, index);
-
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH))
- return DM_DRAW_OPTION_NORMAL;
- else
- return DM_DRAW_OPTION_SKIP;
-}
-
-static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
-{
- dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em->bm);
-}
-
-#ifdef WITH_FREESTYLE
-
-static bool draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed)
-{
- FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
- if (!fed)
- return false;
- return (fed->flag & FREESTYLE_EDGE_MARK) != 0;
-}
-
-/* Draw only Freestyle feature edges */
-static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
-{
- BMEdge *eed = BM_edge_at_index(userData, index);
-
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && draw_dm_test_freestyle_edge_mark(userData, eed))
- return DM_DRAW_OPTION_NORMAL;
- else
- return DM_DRAW_OPTION_SKIP;
-}
-
-static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
-{
- dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em->bm);
-}
-
-static bool draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa)
-{
- FreestyleFace *ffa = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
- if (!ffa)
- return false;
- return (ffa->flag & FREESTYLE_FACE_MARK) != 0;
-}
-
-#endif
-
-/* Draw loop normals. */
-static void draw_dm_loop_normals__mapFunc(void *userData, int vertex_index, int face_index,
- const float co[3], const float no[3])
-{
- if (no) {
- const drawDMNormal_userData *data = userData;
- const BMVert *eve = BM_vert_at_index(data->bm, vertex_index);
- const BMFace *efa = BM_face_at_index(data->bm, face_index);
- float vec[3];
-
- if (!(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) || BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) {
- if (!data->uniform_scale) {
- mul_v3_m3v3(vec, (float(*)[3])data->tmat, no);
- normalize_v3(vec);
- mul_m3_v3((float(*)[3])data->imat, vec);
- }
- else {
- copy_v3_v3(vec, no);
- }
- mul_v3_fl(vec, data->normalsize);
- add_v3_v3(vec, co);
- glVertex3fv(co);
- glVertex3fv(vec);
- }
- }
-}
-
-static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
-{
- drawDMNormal_userData data;
-
- data.bm = em->bm;
- data.normalsize = scene->toolsettings->normalsize;
-
- calcDrawDMNormalScale(ob, &data);
-
- glBegin(GL_LINES);
- dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
- glEnd();
-}
-
-/* Draw faces with color set based on selection
- * return 2 for the active face so it renders with stipple enabled */
-static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
-{
- drawDMFacesSel_userData *data = userData;
- BMFace *efa = BM_face_at_index(data->bm, index);
- unsigned char *col;
-
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- if (efa == data->efa_act) {
- glColor4ubv(data->cols[2]);
- return DM_DRAW_OPTION_STIPPLE;
- }
- else {
-#ifdef WITH_FREESTYLE
- col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
-#else
- col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
-#endif
- if (col[3] == 0)
- return DM_DRAW_OPTION_SKIP;
- glColor4ubv(col);
- return DM_DRAW_OPTION_NORMAL;
- }
- }
- return DM_DRAW_OPTION_SKIP;
-}
-
-static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
-{
-
- drawDMFacesSel_userData *data = userData;
- int i;
- BMFace *efa;
- BMFace *next_efa;
-
- unsigned char *col, *next_col;
-
- i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[index] : index;
- efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
- i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[next_index] : next_index;
- next_efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL;
-
- if (ELEM(NULL, efa, next_efa))
- return 0;
-
- if (efa == next_efa)
- return 1;
-
- if (efa == data->efa_act || next_efa == data->efa_act)
- return 0;
-
-#ifdef WITH_FREESTYLE
- col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
- next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0];
-#else
- col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
- next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
-#endif
-
- if (col[3] == 0 || next_col[3] == 0)
- return 0;
-
- return col == next_col;
-}
-
-/* also draws the active face */
-#ifdef WITH_FREESTYLE
-static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
- unsigned char *selCol, unsigned char *actCol, unsigned char *markCol, BMFace *efa_act)
-#else
-static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
- unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
-#endif
-{
- drawDMFacesSel_userData data;
- data.dm = dm;
- data.cols[0] = baseCol;
- data.bm = em->bm;
- data.cols[1] = selCol;
- data.cols[2] = actCol;
-#ifdef WITH_FREESTYLE
- data.cols[3] = markCol;
-#endif
- data.efa_act = efa_act;
- /* double lookup */
- data.orig_index_mp_to_orig = DM_get_poly_data_layer(dm, CD_ORIGINDEX);
-
- dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, NULL, draw_dm_faces_sel__compareDrawOptions, &data, DM_DRAW_SKIP_HIDDEN);
-}
-
-static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index)
-{
- drawDMLayer_userData *data = userData;
- BMesh *bm = data->bm;
- BMEdge *eed = BM_edge_at_index(bm, index);
-
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- const float crease = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
- if (crease != 0.0f) {
- UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_CREASE, crease);
- return DM_DRAW_OPTION_NORMAL;
- }
- }
- return DM_DRAW_OPTION_SKIP;
-}
-static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
-{
- drawDMLayer_userData data;
-
- data.bm = em->bm;
- data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
-
- if (data.cd_layer_offset != -1) {
- glLineWidth(3.0);
- dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
- }
-}
-
-static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index)
-{
- drawDMLayer_userData *data = userData;
- BMesh *bm = data->bm;
- BMEdge *eed = BM_edge_at_index(bm, index);
-
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- const float bweight = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset);
- if (bweight != 0.0f) {
- UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_BEVEL, bweight);
- return DM_DRAW_OPTION_NORMAL;
- }
- }
- return DM_DRAW_OPTION_SKIP;
-}
-static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- drawDMLayer_userData *data = userData;
- BMesh *bm = data->bm;
- BMVert *eve = BM_vert_at_index(bm, index);
-
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
- if (bweight != 0.0f) {
- UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_BEVEL, bweight);
- glVertex3fv(co);
- }
- }
-}
-static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
-{
- ToolSettings *ts = scene->toolsettings;
-
- if (ts->selectmode & SCE_SELECT_VERTEX) {
- drawDMLayer_userData data;
-
- data.bm = em->bm;
- data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT);
-
- if (data.cd_layer_offset != -1) {
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
- glBegin(GL_POINTS);
- dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
- }
- }
- else {
- drawDMLayer_userData data;
-
- data.bm = em->bm;
- data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
-
- if (data.cd_layer_offset != -1) {
- glLineWidth(3.0);
- dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
- }
- }
-}
-
-/* Second section of routines: Combine first sets to form fancy
- * drawing routines (for example rendering twice to get overlays).
- *
- * Also includes routines that are basic drawing but are too
- * specialized to be split out (like drawing creases or measurements).
- */
-
-/* EditMesh drawing routines */
-
-static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
- BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act,
- RegionView3D *rv3d)
-{
- ToolSettings *ts = scene->toolsettings;
-
- if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */
-
- for (int sel = 0; sel < 2; sel++) {
- unsigned char col[4], fcol[4];
-
- UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
- UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE_EDIT, fcol);
-
- for (int pass = 0; pass < 2; pass++) {
- float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
- float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
-
- if (pass == 0) {
- if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- }
- else {
- continue;
- }
-
- size = (size > 2.1f ? size / 2.0f : size);
- fsize = (fsize > 2.1f ? fsize / 2.0f : fsize);
- col[3] = fcol[3] = 100;
- }
- else {
- col[3] = fcol[3] = 255;
- }
-
- if (ts->selectmode & SCE_SELECT_VERTEX) {
- glPointSize(size);
- glColor4ubv(col);
- draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
- }
-
- if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
- glPointSize(fsize);
- glColor4ubv(fcol);
- draw_dm_face_centers(em, cageDM, sel);
- }
-
- if (pass == 0) {
- glDisable(GL_BLEND);
- glEnable(GL_DEPTH_TEST);
- }
- }
- }
-
- if (v3d->zbuf) glDepthMask(1);
-}
-
-static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
- Mesh *me, DerivedMesh *cageDM, short sel_only,
- BMEdge *eed_act)
-{
- ToolSettings *ts = scene->toolsettings;
- unsigned char wireCol[4], selCol[4], actCol[4];
-
- /* since this function does transparent... */
- UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol);
- UI_GetThemeColor4ubv(TH_WIRE_EDIT, wireCol);
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol);
-
- /* when sel only is used, don't render wire, only selected, this is used for
- * textured draw mode when the 'edges' option is disabled */
- if (sel_only)
- wireCol[3] = 0;
-
- for (int pass = 0; pass < 2; pass++) {
- /* show wires in transparent when no zbuf clipping for select */
- if (pass == 0) {
- if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) {
- glEnable(GL_BLEND);
- glDisable(GL_DEPTH_TEST);
- selCol[3] = 85;
- if (!sel_only) wireCol[3] = 85;
- }
- else {
- continue;
- }
- }
- else {
- selCol[3] = 255;
- if (!sel_only) wireCol[3] = 255;
- }
-
- if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) {
- if (cageDM->drawMappedEdgesInterp &&
- ((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT)))
- {
- if (draw_dm_edges_weight_check(me, v3d)) {
- // Interpolate vertex weights
- draw_dm_edges_weight_interp(em, cageDM, ts->weightuser);
- }
- else if (ts->selectmode == SCE_SELECT_FACE) {
- draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
- }
- else {
- // Interpolate vertex selection
- draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
- }
- }
- else {
- draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
- }
- }
- else {
- if (!sel_only) {
- glColor4ubv(wireCol);
- draw_dm_edges(em, cageDM);
- }
- }
-
- if (pass == 0) {
- glDisable(GL_BLEND);
- glEnable(GL_DEPTH_TEST);
- }
- }
-}
-
-static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit)
-{
- /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square, etc.).
- * See bug #36090.
- */
- const short txt_flag = V3D_CACHE_TEXT_LOCALCLIP | (unit->system ? 0 : V3D_CACHE_TEXT_ASCII);
- Mesh *me = ob->data;
- float v1[3], v2[3], v3[3], vmid[3], fvec[3];
- char numstr[32]; /* Stores the measurement display text here */
- size_t numstr_len;
- const char *conv_float; /* Use a float conversion matching the grid size */
- unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */
- float area; /* area of the face */
- float grid = unit->system ? unit->scale_length : v3d->grid;
- const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
- const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0;
- const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0;
- /* when 2 edge-info options are enabled, space apart */
- const bool do_edge_textpair = (me->drawflag & ME_DRAWEXTRA_EDGELEN) && (me->drawflag & ME_DRAWEXTRA_EDGEANG);
- const float edge_texpair_sep = 0.4f;
- float clip_planes[4][4];
- /* allow for displaying shape keys and deform mods */
- DerivedMesh *dm = EDBM_mesh_deform_dm_get(em);
- BMIter iter;
-
- /* make the precision of the display value proportionate to the gridsize */
-
- if (grid <= 0.01f) conv_float = "%.6g";
- else if (grid <= 0.1f) conv_float = "%.5g";
- else if (grid <= 1.0f) conv_float = "%.4g";
- else if (grid <= 10.0f) conv_float = "%.3g";
- else conv_float = "%.2g";
-
- if (me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_EDGEANG)) {
- BoundBox bb;
- bglMats mats = {{0}};
- const rcti rect = {0, ar->winx, 0, ar->winy};
-
- view3d_get_transformation(ar, ar->regiondata, em->ob, &mats);
- ED_view3d_clipping_calc(&bb, clip_planes, &mats, &rect);
- }
-
- if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
- BMEdge *eed;
-
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
-
- if (dm) {
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- }
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- /* draw selected edges, or edges next to selected verts while dragging */
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
- (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
- BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
- {
- float v1_clip[3], v2_clip[3];
-
- if (dm) {
- dm->getVertCo(dm, BM_elem_index_get(eed->v1), v1);
- dm->getVertCo(dm, BM_elem_index_get(eed->v2), v2);
- }
- else {
- copy_v3_v3(v1, eed->v1->co);
- copy_v3_v3(v2, eed->v2->co);
- }
-
- if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
-
- if (do_edge_textpair) {
- interp_v3_v3v3(vmid, v1, v2, edge_texpair_sep);
- }
- else {
- mid_v3_v3v3(vmid, v1_clip, v2_clip);
- }
-
- if (do_global) {
- mul_mat3_m4_v3(ob->obmat, v1);
- mul_mat3_m4_v3(ob->obmat, v2);
- }
-
- if (unit->system) {
- numstr_len = bUnit_AsString(numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
- unit->system, B_UNIT_LENGTH, do_split, false);
- }
- else {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
- }
-
- view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
- }
- }
- }
- }
-
- if (me->drawflag & ME_DRAWEXTRA_EDGEANG) {
- const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
- BMEdge *eed;
-
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
-
- if (dm) {
- BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
- }
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- BMLoop *l_a, *l_b;
- if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
- /* draw selected edges, or edges next to selected verts while dragging */
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
- (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
- BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
- /* special case, this is useful to show when verts connected to
- * this edge via a face are being transformed */
- BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)
- )))
- {
- float v1_clip[3], v2_clip[3];
-
- if (dm) {
- dm->getVertCo(dm, BM_elem_index_get(eed->v1), v1);
- dm->getVertCo(dm, BM_elem_index_get(eed->v2), v2);
- }
- else {
- copy_v3_v3(v1, eed->v1->co);
- copy_v3_v3(v2, eed->v2->co);
- }
-
- if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
- float no_a[3], no_b[3];
- float angle;
-
- if (do_edge_textpair) {
- interp_v3_v3v3(vmid, v2_clip, v1_clip, edge_texpair_sep);
- }
- else {
- mid_v3_v3v3(vmid, v1_clip, v2_clip);
- }
-
- if (dm) {
- dm->getPolyNo(dm, BM_elem_index_get(l_a->f), no_a);
- dm->getPolyNo(dm, BM_elem_index_get(l_b->f), no_b);
- }
- else {
- copy_v3_v3(no_a, l_a->f->no);
- copy_v3_v3(no_b, l_b->f->no);
- }
-
- if (do_global) {
- mul_mat3_m4_v3(ob->imat, no_a);
- mul_mat3_m4_v3(ob->imat, no_b);
- normalize_v3(no_a);
- normalize_v3(no_b);
- }
-
- angle = angle_normalized_v3v3(no_a, no_b);
-
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
-
- view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col);
- }
- }
- }
- }
- }
-
- if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
- /* would be nice to use BM_face_calc_area, but that is for 2d faces
- * so instead add up tessellation triangle areas */
- BMFace *f = NULL;
-
-#define DRAW_EM_MEASURE_STATS_FACEAREA() \
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \
- mul_v3_fl(vmid, 1.0f / (float)n); \
- if (unit->system) { \
- numstr_len = bUnit_AsString( \
- numstr, sizeof(numstr), \
- (double)(area * unit->scale_length * unit->scale_length), \
- 3, unit->system, B_UNIT_AREA, do_split, false); \
- } \
- else { \
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area); \
- } \
- view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col); \
- } (void)0
-
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
-
- if (dm) {
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- }
-
- area = 0.0;
- zero_v3(vmid);
- int n = 0;
- for (int i = 0; i < em->tottri; i++) {
- BMLoop **l = em->looptris[i];
- if (f && l[0]->f != f) {
- DRAW_EM_MEASURE_STATS_FACEAREA();
- zero_v3(vmid);
- area = 0.0;
- n = 0;
- }
-
- f = l[0]->f;
-
- if (dm) {
- dm->getVertCo(dm, BM_elem_index_get(l[0]->v), v1);
- dm->getVertCo(dm, BM_elem_index_get(l[1]->v), v2);
- dm->getVertCo(dm, BM_elem_index_get(l[2]->v), v3);
- }
- else {
- copy_v3_v3(v1, l[0]->v->co);
- copy_v3_v3(v2, l[1]->v->co);
- copy_v3_v3(v3, l[2]->v->co);
- }
-
- add_v3_v3(vmid, v1);
- add_v3_v3(vmid, v2);
- add_v3_v3(vmid, v3);
- n += 3;
- if (do_global) {
- mul_mat3_m4_v3(ob->obmat, v1);
- mul_mat3_m4_v3(ob->obmat, v2);
- mul_mat3_m4_v3(ob->obmat, v3);
- }
- area += area_tri_v3(v1, v2, v3);
- }
-
- if (f) {
- DRAW_EM_MEASURE_STATS_FACEAREA();
- }
-#undef DRAW_EM_MEASURE_STATS_FACEAREA
- }
-
- if (me->drawflag & ME_DRAWEXTRA_FACEANG) {
- BMFace *efa;
- const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
-
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
-
- if (dm) {
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT);
-
- if (is_face_sel || do_moving) {
- BMIter liter;
- BMLoop *loop;
- bool is_first = true;
-
- BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
- if (is_face_sel ||
- (do_moving &&
- (BM_elem_flag_test(loop->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) ||
- BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT))))
- {
- float v2_local[3];
-
- /* lazy init center calc */
- if (is_first) {
- if (dm) {
- BMLoop *l_iter, *l_first;
- float tvec[3];
- zero_v3(vmid);
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- dm->getVertCo(dm, BM_elem_index_get(l_iter->v), tvec);
- add_v3_v3(vmid, tvec);
- } while ((l_iter = l_iter->next) != l_first);
- mul_v3_fl(vmid, 1.0f / (float)efa->len);
- }
- else {
- BM_face_calc_center_bounds(efa, vmid);
- }
- is_first = false;
- }
-
- if (dm) {
- dm->getVertCo(dm, BM_elem_index_get(loop->prev->v), v1);
- dm->getVertCo(dm, BM_elem_index_get(loop->v), v2);
- dm->getVertCo(dm, BM_elem_index_get(loop->next->v), v3);
- }
- else {
- copy_v3_v3(v1, loop->prev->v->co);
- copy_v3_v3(v2, loop->v->co);
- copy_v3_v3(v3, loop->next->v->co);
- }
-
- copy_v3_v3(v2_local, v2);
-
- if (do_global) {
- mul_mat3_m4_v3(ob->obmat, v1);
- mul_mat3_m4_v3(ob->obmat, v2);
- mul_mat3_m4_v3(ob->obmat, v3);
- }
-
- float angle = angle_v3v3v3(v1, v2, v3);
-
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
- interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
- view3d_cached_text_draw_add(fvec, numstr, numstr_len, 0, txt_flag, col);
- }
- }
- }
- }
- }
-}
-
-static void draw_em_indices(BMEditMesh *em)
-{
- const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP;
- BMEdge *e;
- BMFace *f;
- BMVert *v;
- char numstr[32];
- size_t numstr_len;
- float pos[3];
- unsigned char col[4];
-
- BMIter iter;
- BMesh *bm = em->bm;
-
- /* For now, reuse appropriate theme colors from stats text colors */
- int i = 0;
- if (em->selectmode & SCE_SELECT_VERTEX) {
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
- view3d_cached_text_draw_add(v->co, numstr, numstr_len, 0, txt_flag, col);
- }
- i++;
- }
- }
-
- if (em->selectmode & SCE_SELECT_EDGE) {
- i = 0;
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
- mid_v3_v3v3(pos, e->v1->co, e->v2->co);
- view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col);
- }
- i++;
- }
- }
-
- if (em->selectmode & SCE_SELECT_FACE) {
- i = 0;
- UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- BM_face_calc_center_mean(f, pos);
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
- view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col);
- }
- i++;
- }
- }
-}
-
-static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
-{
- BMEditMesh *em = userData;
-
- if (UNLIKELY(index >= em->bm->totface))
- return DM_DRAW_OPTION_NORMAL;
-
- BMFace *efa = BM_face_at_index(em->bm, index);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return DM_DRAW_OPTION_NORMAL;
- }
- else {
- return DM_DRAW_OPTION_SKIP;
- }
-}
-
-static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
-{
- BMEditMesh *em = userData;
-
- if (UNLIKELY(index >= em->bm->totface))
- return DM_DRAW_OPTION_NORMAL;
-
- BMFace *efa = BM_face_at_index(em->bm, index);
-
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return DM_DRAW_OPTION_NORMAL;
- }
- else {
- return DM_DRAW_OPTION_SKIP;
- }
-}
-
-static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
- Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt)
-
-{
- RegionView3D *rv3d = ar->regiondata;
- Mesh *me = ob->data;
- const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE);
- bool use_depth_offset = false;
-
- glLineWidth(1);
-
- BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
-
- if (check_object_draw_editweight(me, finalDM)) {
- if (dt > OB_WIRE) {
- draw_mesh_paint_weight_faces(finalDM, true, draw_em_fancy__setFaceOpts, me->edit_btmesh);
-
- ED_view3d_polygon_offset(rv3d, 1.0);
- glDepthMask(0);
- use_depth_offset = true;
- }
- else {
- glEnable(GL_DEPTH_TEST);
- draw_mesh_paint_weight_faces(finalDM, false, draw_em_fancy__setFaceOpts, me->edit_btmesh);
- draw_mesh_paint_weight_edges(rv3d, finalDM, true, true, draw_dm_edges__setDrawOptions, me->edit_btmesh->bm);
- glDisable(GL_DEPTH_TEST);
- }
- }
- else if (dt > OB_WIRE) {
- if (use_occlude_wire) {
- /* use the cageDM since it always overlaps the editmesh faces */
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- cageDM->drawMappedFaces(cageDM, draw_em_fancy__setFaceOpts,
- GPU_object_material_bind, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN | DM_DRAW_NEED_NORMALS);
- GPU_object_material_unbind();
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- }
- else if (check_object_draw_texture(scene, v3d, dt)) {
- if (draw_glsl_material(scene, ob, v3d, dt)) {
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
-
- finalDM->drawMappedFacesGLSL(finalDM, GPU_object_material_bind,
- draw_em_fancy__setGLSLFaceOpts, em);
- GPU_object_material_unbind();
-
- glFrontFace(GL_CCW);
- }
- else {
- draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
- }
- }
- else {
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_object_material_bind, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN | DM_DRAW_NEED_NORMALS);
-
- glFrontFace(GL_CCW);
-
- GPU_object_material_unbind();
- }
-
- /* Setup for drawing wire over, disable zbuffer
- * write to show selected edge wires better */
- UI_ThemeColor(TH_WIRE_EDIT);
-
- ED_view3d_polygon_offset(rv3d, 1.0);
- glDepthMask(0);
- use_depth_offset = true;
- }
- else {
- if (cageDM != finalDM) {
- UI_ThemeColorBlend(TH_WIRE_EDIT, TH_BACK, 0.7);
- finalDM->drawEdges(finalDM, 1, 0);
- }
- }
-
- if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) {
- /* pass */
- }
- else {
- /* annoying but active faces is stored differently */
- BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, true);
- BMEdge *eed_act = NULL;
- BMVert *eve_act = NULL;
-
- if (em->bm->selected.last) {
- BMEditSelection *ese = em->bm->selected.last;
- /* face is handled above */
-#if 0
- if (ese->type == BM_FACE) {
- efa_act = (BMFace *)ese->data;
- }
- else
-#endif
- if (ese->htype == BM_EDGE) {
- eed_act = (BMEdge *)ese->ele;
- }
- else if (ese->htype == BM_VERT) {
- eve_act = (BMVert *)ese->ele;
- }
- }
-
- if ((me->drawflag & ME_DRAWFACES) && (use_occlude_wire == false)) { /* transp faces */
- unsigned char col1[4], col2[4], col3[4];
-#ifdef WITH_FREESTYLE
- unsigned char col4[4];
-#endif
-
- UI_GetThemeColor4ubv(TH_FACE, col1);
- UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
-#ifdef WITH_FREESTYLE
- UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col4);
-#endif
-
- glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
-
- /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
- if (check_object_draw_texture(scene, v3d, dt))
- col1[3] = 0;
-
-#ifdef WITH_FREESTYLE
- if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE) || !CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE))
- col4[3] = 0;
-
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
-#else
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
-#endif
-
- glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
- }
- else if (efa_act) {
- /* even if draw faces is off it would be nice to draw the stipple face
- * Make all other faces zero alpha except for the active */
- unsigned char col1[4], col2[4], col3[4];
-#ifdef WITH_FREESTYLE
- unsigned char col4[4];
- col4[3] = 0; /* don't draw */
-#endif
- col1[3] = col2[3] = 0; /* don't draw */
-
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
-
- glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
-
-#ifdef WITH_FREESTYLE
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
-#else
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
-#endif
-
- glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
- }
-
- /* here starts all fancy draw-extra over */
- if ((me->drawflag & ME_DRAWEDGES) == 0 && check_object_draw_texture(scene, v3d, dt)) {
- /* we are drawing textures and 'ME_DRAWEDGES' is disabled, don't draw any edges */
-
- /* only draw selected edges otherwise there is no way of telling if a face is selected */
- draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
-
- }
- else {
- if (me->drawflag & ME_DRAWSEAMS) {
- UI_ThemeColor(TH_EDGE_SEAM);
- glLineWidth(2);
-
- draw_dm_edges_seams(em, cageDM);
-
- glColor3ub(0, 0, 0);
- }
-
- if (me->drawflag & ME_DRAWSHARP) {
- UI_ThemeColor(TH_EDGE_SHARP);
- glLineWidth(2);
-
- draw_dm_edges_sharp(em, cageDM);
-
- glColor3ub(0, 0, 0);
- }
-
-#ifdef WITH_FREESTYLE
- if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
- UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
- glLineWidth(2);
-
- draw_dm_edges_freestyle(em, cageDM);
-
- glColor3ub(0, 0, 0);
- }
-#endif
-
- if (me->drawflag & ME_DRAWCREASES) {
- draw_dm_creases(em, cageDM);
- }
- if (me->drawflag & ME_DRAWBWEIGHTS) {
- draw_dm_bweights(em, scene, cageDM);
- }
-
- glLineWidth(1);
- draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
- }
-
- {
- draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d);
-
- if (me->drawflag & ME_DRAWNORMALS) {
- UI_ThemeColor(TH_NORMAL);
- draw_dm_face_normals(em, scene, ob, cageDM);
- }
- if (me->drawflag & ME_DRAW_VNORMALS) {
- UI_ThemeColor(TH_VNORMAL);
- draw_dm_vert_normals(em, scene, ob, cageDM);
- }
- if (me->drawflag & ME_DRAW_LNORMALS) {
- UI_ThemeColor(TH_LNORMAL);
- draw_dm_loop_normals(em, scene, ob, cageDM);
- }
-
- if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN |
- ME_DRAWEXTRA_FACEAREA |
- ME_DRAWEXTRA_FACEANG |
- ME_DRAWEXTRA_EDGEANG)) &&
- !(v3d->flag2 & V3D_RENDER_OVERRIDE))
- {
- draw_em_measure_stats(ar, v3d, ob, em, &scene->unit);
- }
-
- if ((G.debug & G_DEBUG) && (me->drawflag & ME_DRAWEXTRA_INDICES) &&
- !(v3d->flag2 & V3D_RENDER_OVERRIDE))
- {
- draw_em_indices(em);
- }
- }
- }
-
- if (use_depth_offset) {
- glDepthMask(1);
- ED_view3d_polygon_offset(rv3d, 0.0);
- GPU_object_material_unbind();
- }
-#if 0 /* currently not needed */
- else if (use_occlude_wire) {
- ED_view3d_polygon_offset(rv3d, 0.0);
- }
-#endif
-}
-
-/* Mesh drawing routines */
-
-static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
-{
- if ((v3d->transp == false) && /* not when we draw the transparent pass */
- (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */
- {
- glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
- glDepthMask(0);
-
- /* if transparent, we cannot draw the edges for solid select... edges
- * have no material info. GPU_object_material_visible will skip the
- * transparent faces */
- if (ob->dtx & OB_DRAWTRANSP) {
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_visible);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- }
- else {
- dm->drawEdges(dm, 0, 1);
- }
-
- glDepthMask(1);
- }
-}
-
-static bool object_is_halo(Scene *scene, Object *ob)
-{
- const Material *ma = give_current_material(ob, 1);
- return (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene));
-}
-
-static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
- const char dt, const unsigned char ob_wire_col[4], const short dflag)
-{
-#ifdef WITH_GAMEENGINE
- Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, scene) : base->object;
-#else
- Object *ob = base->object;
-#endif
- Mesh *me = ob->data;
- eWireDrawMode draw_wire = OBDRAW_WIRE_OFF;
- bool /* no_verts,*/ no_edges, no_faces;
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
- const bool is_obact = (ob == OBACT);
- int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
-
- if (!dm)
- return;
-
- DM_update_materials(dm, ob);
-
- /* Check to draw dynamic paint colors (or weights from WeightVG modifiers).
- * Note: Last "preview-active" modifier in stack will win! */
- if (DM_get_loop_data_layer(dm, CD_PREVIEW_MLOOPCOL) && modifiers_isPreview(ob))
- draw_flags |= DRAW_MODIFIERS_PREVIEW;
-
- /* Unwanted combination */
- if (draw_flags & DRAW_FACE_SELECT) {
- draw_wire = OBDRAW_WIRE_OFF;
- }
- else if (ob->dtx & OB_DRAWWIRE) {
- draw_wire = OBDRAW_WIRE_ON_DEPTH; /* draw wire after solid using zoffset and depth buffer adjusment */
- }
-
- /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */
- if (dm->type == DM_TYPE_CCGDM) {
- no_edges = !subsurf_has_edges(dm);
- no_faces = !subsurf_has_faces(dm);
- }
- else {
- no_edges = (dm->getNumEdges(dm) == 0);
- no_faces = (dm->getNumPolys(dm) == 0);
- }
-
- /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
-
- if (dt == OB_BOUNDBOX) {
- if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
- draw_bounding_volume(ob, ob->boundtype);
- }
- else if ((no_faces && no_edges) ||
- ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
- {
- glPointSize(1.5);
- dm->drawVerts(dm);
- }
- else if ((dt == OB_WIRE) || no_faces) {
- draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
- }
- else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
- check_object_draw_texture(scene, v3d, dt))
- {
- bool draw_loose = true;
-
- if ((v3d->flag & V3D_SELECT_OUTLINE) &&
- ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
- (base->flag & SELECT) &&
- !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
- (draw_wire == OBDRAW_WIRE_OFF))
- {
- draw_mesh_object_outline(v3d, ob, dm);
- }
-
- if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
- Paint *p;
-
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
-
- if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene))) {
- GPUVertexAttribs gattribs;
- float planes[4][4];
- float (*fpl)[4] = NULL;
- const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
-
- if (ob->sculpt->partial_redraw) {
- if (ar->do_draw & RGN_DRAW_PARTIAL) {
- ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
- fpl = planes;
- ob->sculpt->partial_redraw = 0;
- }
- }
-
- GPU_object_material_bind(1, &gattribs);
- dm->drawFacesSolid(dm, fpl, fast, NULL);
- draw_loose = false;
- }
- else
- dm->drawFacesGLSL(dm, GPU_object_material_bind);
-
-#if 0 /* XXX */
- if (BKE_bproperty_object_get(ob, "Text"))
- draw_mesh_text(ob, 1);
-#endif
- GPU_object_material_unbind();
-
- glFrontFace(GL_CCW);
-
- if (draw_flags & DRAW_FACE_SELECT)
- draw_mesh_face_select(rv3d, me, dm, false);
- }
- else {
- draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags);
- }
-
- if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) {
- if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
- }
- glLineWidth(1.0f);
- dm->drawLooseEdges(dm);
- }
- }
- }
- else if (dt == OB_SOLID) {
- if (draw_flags & DRAW_MODIFIERS_PREVIEW) {
- /* for object selection draws no shade */
- if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) {
- dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
- GPU_object_material_unbind();
- }
- else {
- const float specular[3] = {0.47f, 0.47f, 0.47f};
-
- /* draw outline */
- if ((v3d->flag & V3D_SELECT_OUTLINE) &&
- ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
- (base->flag & SELECT) &&
- (draw_wire == OBDRAW_WIRE_OFF) &&
- (ob->sculpt == NULL))
- {
- draw_mesh_object_outline(v3d, ob, dm);
- }
-
- /* materials arent compatible with vertex colors */
- GPU_end_object_materials();
-
- /* set default specular */
- GPU_basic_shader_colors(NULL, specular, 35, 1.0f);
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
-
- dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS);
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- }
- else {
- Paint *p;
-
- if ((v3d->flag & V3D_SELECT_OUTLINE) &&
- ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
- (base->flag & SELECT) &&
- (draw_wire == OBDRAW_WIRE_OFF) &&
- (ob->sculpt == NULL))
- {
- draw_mesh_object_outline(v3d, ob, dm);
- }
-
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
-
- if (ob->sculpt && (p = BKE_paint_get_active(scene))) {
- float planes[4][4];
- float (*fpl)[4] = NULL;
- const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
-
- if (ob->sculpt->partial_redraw) {
- if (ar->do_draw & RGN_DRAW_PARTIAL) {
- ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
- fpl = planes;
- ob->sculpt->partial_redraw = 0;
- }
- }
-
- dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind);
- }
- else
- dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
-
- glFrontFace(GL_CCW);
-
- GPU_object_material_unbind();
-
- if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
- }
- glLineWidth(1.0f);
- dm->drawLooseEdges(dm);
- }
- }
- }
- else if (dt == OB_PAINT) {
- draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags);
-
- /* since we already draw wire as wp guide, don't draw over the top */
- draw_wire = OBDRAW_WIRE_OFF;
- }
-
- if ((draw_wire != OBDRAW_WIRE_OFF) && /* draw extra wire */
- /* when overriding with render only, don't bother */
- (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0))
- {
- /* When using wireframe object draw in particle edit mode
- * the mesh gets in the way of seeing the particles, fade the wire color
- * with the background. */
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (is_obact && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
- ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f);
- }
- else {
- glColor3ubv(ob_wire_col);
- }
- }
-
- /* If drawing wire and drawtype is not OB_WIRE then we are
- * overlaying the wires.
- *
- * UPDATE bug #10290 - With this wire-only objects can draw
- * behind other objects depending on their order in the scene. 2x if 0's below. undo'ing zr's commit: r4059
- *
- * if draw wire is 1 then just drawing wire, no need for depth buffer stuff,
- * otherwise this wire is to overlay solid mode faces so do some depth buffer tricks.
- */
- if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
- ED_view3d_polygon_offset(rv3d, 1.0);
- glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
- }
-
- glLineWidth(1.0f);
- dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
-
- if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
- glDepthMask(1);
- ED_view3d_polygon_offset(rv3d, 0.0);
- }
- }
-
- if (is_obact && BKE_paint_select_vert_test(ob)) {
- const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
-
- if (!use_depth) glDisable(GL_DEPTH_TEST);
- else ED_view3d_polygon_offset(rv3d, 1.0);
- drawSelectedVertices(dm, ob->data);
- if (!use_depth) glEnable(GL_DEPTH_TEST);
- else ED_view3d_polygon_offset(rv3d, 0.0);
- }
- dm->release(dm);
-}
-
-/* returns true if nothing was drawn, for detecting to draw an object center */
-static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
- const char dt, const unsigned char ob_wire_col[4], const short dflag)
-{
- Object *ob = base->object;
- Object *obedit = scene->obedit;
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
- bool do_alpha_after = false, drawlinked = false, retval = false;
-
- /* If we are drawing shadows and any of the materials don't cast a shadow,
- * then don't draw the object */
- if (v3d->flag2 & V3D_RENDER_SHADOW) {
- for (int i = 1; i <= ob->totcol; ++i) {
- Material *ma = give_current_material(ob, i);
- if (ma && !(ma->mode2 & MA_CASTSHADOW)) {
- return true;
- }
- }
- }
-
- if (obedit && ob != obedit && ob->data == obedit->data) {
- if (BKE_key_from_object(ob) || BKE_key_from_object(obedit)) {}
- else if (ob->modifiers.first || obedit->modifiers.first) {}
- else drawlinked = true;
- }
-
- /* backface culling */
- if (v3d->flag2 & V3D_BACKFACE_CULLING) {
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
- }
-
- if (ob == obedit || drawlinked) {
- DerivedMesh *finalDM, *cageDM;
-
- if (obedit != ob) {
- finalDM = cageDM = editbmesh_get_derived_base(
- ob, em, scene->customdata_mask);
- }
- else {
- cageDM = editbmesh_get_derived_cage_and_final(
- scene, ob, em, scene->customdata_mask,
- &finalDM);
- }
-
- const bool use_material = ((me->drawflag & ME_DRAWEIGHT) == 0);
-
- DM_update_materials(finalDM, ob);
- if (cageDM != finalDM) {
- DM_update_materials(cageDM, ob);
- }
-
- if (use_material) {
- if (dt > OB_WIRE) {
- const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
-
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
- }
- }
-
- draw_em_fancy(scene, ar, v3d, ob, em, cageDM, finalDM, dt);
-
- if (use_material) {
- GPU_end_object_materials();
- }
-
- if (obedit != ob)
- finalDM->release(finalDM);
- }
- else {
- /* ob->bb was set by derived mesh system, do NULL check just to be sure */
- if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) {
- if (dt > OB_WIRE) {
- const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
-
- if (dt == OB_SOLID || glsl) {
- const bool check_alpha = check_alpha_pass(base);
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl,
- (check_alpha) ? &do_alpha_after : NULL);
- }
- }
-
- draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
-
- GPU_end_object_materials();
-
- if (me->totvert == 0) retval = true;
- }
- }
-
- if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
- /* GPU_begin_object_materials checked if this is needed */
- if (do_alpha_after) {
- if (ob->dtx & OB_DRAWXRAY) {
- ED_view3d_after_add(&v3d->afterdraw_xraytransp, base, dflag);
- }
- else {
- ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
- }
- }
- else if (ob->dtx & OB_DRAWXRAY && ob->dtx & OB_DRAWTRANSP) {
- /* special case xray+transp when alpha is 1.0, without this the object vanishes */
- if (v3d->xray == 0 && v3d->transp == 0) {
- ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag);
- }
- }
- }
-
- if (v3d->flag2 & V3D_BACKFACE_CULLING)
- glDisable(GL_CULL_FACE);
-
- return retval;
-}
-
-/* ************** DRAW DISPLIST ****************** */
-
-
-/**
- * \param dl_type_mask Only draw types matching this mask.
- * \return true when nothing was drawn
- */
-static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask)
-{
- if (dlbase == NULL) return true;
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
- for (DispList *dl = dlbase->first; dl; dl = dl->next) {
- if (dl->parts == 0 || dl->nr == 0) {
- continue;
- }
-
- if ((dl_type_mask & (1 << dl->type)) == 0) {
- continue;
- }
-
- const float *data = dl->verts;
- int parts;
-
- switch (dl->type) {
- case DL_SEGM:
-
- glVertexPointer(3, GL_FLOAT, 0, data);
-
- for (parts = 0; parts < dl->parts; parts++)
- glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
-
- break;
- case DL_POLY:
-
- glVertexPointer(3, GL_FLOAT, 0, data);
-
- for (parts = 0; parts < dl->parts; parts++)
- glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
-
- break;
- case DL_SURF:
-
- glVertexPointer(3, GL_FLOAT, 0, data);
-
- for (parts = 0; parts < dl->parts; parts++) {
- if (dl->flag & DL_CYCL_U)
- glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
- else
- glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
- }
-
- for (int nr = 0; nr < dl->nr; nr++) {
- int ofs = 3 * dl->nr;
-
- data = (dl->verts) + 3 * nr;
- parts = dl->parts;
-
- if (dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP);
- else glBegin(GL_LINE_STRIP);
-
- while (parts--) {
- glVertex3fv(data);
- data += ofs;
- }
- glEnd();
-
-#if 0
- /* (ton) this code crashes for me when resolv is 86 or higher... no clue */
- glVertexPointer(3, GL_FLOAT, sizeof(float) * 3 * dl->nr, data + 3 * nr);
- if (dl->flag & DL_CYCL_V)
- glDrawArrays(GL_LINE_LOOP, 0, dl->parts);
- else
- glDrawArrays(GL_LINE_STRIP, 0, dl->parts);
-#endif
- }
- break;
-
- case DL_INDEX3:
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
- break;
-
- case DL_INDEX4:
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
- break;
- }
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
- return false;
-}
-
-static bool drawDispListwire(ListBase *dlbase, const short ob_type)
-{
- unsigned int dl_mask = 0xffffffff;
-
- /* skip fill-faces for curves & fonts */
- if (ELEM(ob_type, OB_FONT, OB_CURVE)) {
- dl_mask &= ~((1 << DL_INDEX3) | (1 << DL_INDEX4));
- }
-
- return drawDispListwire_ex(dlbase, dl_mask);
-}
-
-static bool index3_nors_incr = true;
-
-static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
- const unsigned char ob_wire_col[4], const bool use_glsl)
-{
- GPUVertexAttribs gattribs;
-
- if (lb == NULL) return;
-
- glEnableClientState(GL_VERTEX_ARRAY);
-
- /* track current material, -1 for none (needed for lines) */
- short col = -1;
-
- DispList *dl = lb->first;
- while (dl) {
- const float *data = dl->verts;
- const float *ndata = dl->nors;
-
- switch (dl->type) {
- case DL_SEGM:
- if (ob->type == OB_SURF) {
- if (col != -1) {
- GPU_object_material_unbind();
- col = -1;
- }
-
- if ((dflag & DRAW_CONSTCOLOR) == 0)
- glColor3ubv(ob_wire_col);
-
- // glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- // glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
- glBegin(GL_LINE_STRIP);
- for (int nr = dl->nr; nr; nr--, data += 3)
- glVertex3fv(data);
- glEnd();
- }
- break;
- case DL_POLY:
- if (ob->type == OB_SURF) {
- if (col != -1) {
- GPU_object_material_unbind();
- col = -1;
- }
-
- /* for some reason glDrawArrays crashes here in half of the platforms (not osx) */
- //glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- //glDrawArrays(GL_LINE_LOOP, 0, dl->nr);
-
- glBegin(GL_LINE_LOOP);
- for (int nr = dl->nr; nr; nr--, data += 3)
- glVertex3fv(data);
- glEnd();
- }
- break;
- case DL_SURF:
-
- if (dl->index) {
- if (col != dl->col) {
- GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
- col = dl->col;
- }
- /* FLAT/SMOOTH shading for surfaces */
- glShadeModel((dl->rt & CU_SMOOTH) ? GL_SMOOTH : GL_FLAT);
-
- glEnableClientState(GL_NORMAL_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- glNormalPointer(GL_FLOAT, 0, dl->nors);
- glDrawElements(GL_QUADS, 4 * dl->totindex, GL_UNSIGNED_INT, dl->index);
- glDisableClientState(GL_NORMAL_ARRAY);
- glShadeModel(GL_SMOOTH);
- }
- break;
-
- case DL_INDEX3:
- if (col != dl->col) {
- GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
- col = dl->col;
- }
-
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
-
- /* for polys only one normal needed */
- if (index3_nors_incr) {
- glEnableClientState(GL_NORMAL_ARRAY);
- glNormalPointer(GL_FLOAT, 0, dl->nors);
- }
- else
- glNormal3fv(ndata);
-
- glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
-
- if (index3_nors_incr)
- glDisableClientState(GL_NORMAL_ARRAY);
-
- break;
-
- case DL_INDEX4:
- if (col != dl->col) {
- GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
- col = dl->col;
- }
-
- glEnableClientState(GL_NORMAL_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- glNormalPointer(GL_FLOAT, 0, dl->nors);
- glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
- glDisableClientState(GL_NORMAL_ARRAY);
-
- break;
- }
- dl = dl->next;
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glFrontFace(GL_CCW);
-
- if (col != -1) {
- GPU_object_material_unbind();
- }
-}
-
-static void drawCurveDMWired(Object *ob)
-{
- DerivedMesh *dm = ob->derivedFinal;
- dm->drawEdges(dm, 1, 0);
-}
-
-/* return true when nothing was drawn */
-static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt)
-{
- Object *ob = base->object;
- DerivedMesh *dm = ob->derivedFinal;
-
- if (!dm) {
- return true;
- }
-
- DM_update_materials(dm, ob);
-
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
-
- if (dt > OB_WIRE && dm->getNumPolys(dm)) {
- bool glsl = draw_glsl_material(scene, ob, v3d, dt);
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
-
- if (!glsl)
- dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
- else
- dm->drawFacesGLSL(dm, GPU_object_material_bind);
-
- GPU_end_object_materials();
- }
- else {
- if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0)
- drawCurveDMWired(ob);
- }
-
- return false;
-}
-
-/**
- * Only called by #drawDispList
- * \return true when nothing was drawn
- */
-static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
- const char dt, const short dflag, const unsigned char ob_wire_col[4])
-{
- Object *ob = base->object;
- ListBase *lb = NULL;
- DispList *dl;
- Curve *cu;
- const bool render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0;
- const bool solid = (dt > OB_WIRE);
-
- switch (ob->type) {
- case OB_FONT:
- case OB_CURVE:
- cu = ob->data;
-
- lb = &ob->curve_cache->disp;
-
- if (solid) {
- const bool has_faces = BKE_displist_has_faces(lb);
- dl = lb->first;
- if (dl == NULL) {
- return true;
- }
-
- if (dl->nors == NULL) BKE_displist_normals_add(lb);
- index3_nors_incr = false;
-
- if (!render_only) {
- /* when we have faces, only draw loose-wire */
- if (has_faces) {
- drawDispListwire_ex(lb, (1 << DL_SEGM));
- }
- else {
- drawDispListwire(lb, ob->type);
- }
- }
-
- if (has_faces == false) {
- /* pass */
- }
- else {
- if (draw_glsl_material(scene, ob, v3d, dt)) {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
- drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
- GPU_end_object_materials();
- }
- else {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
- drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
- GPU_end_object_materials();
- }
- if (cu->editnurb && cu->bevobj == NULL && cu->taperobj == NULL && cu->ext1 == 0.0f && cu->ext2 == 0.0f) {
- cpack(0);
- drawDispListwire(lb, ob->type);
- }
- }
- index3_nors_incr = true;
- }
- else {
- if (!render_only || BKE_displist_has_faces(lb)) {
- return drawDispListwire(lb, ob->type);
- }
- }
- break;
- case OB_SURF:
-
- lb = &ob->curve_cache->disp;
-
- if (solid) {
- dl = lb->first;
- if (dl == NULL) {
- return true;
- }
-
- if (dl->nors == NULL) BKE_displist_normals_add(lb);
-
- if (draw_glsl_material(scene, ob, v3d, dt)) {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
- drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
- GPU_end_object_materials();
- }
- else {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
- drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
- GPU_end_object_materials();
- }
- }
- else {
- return drawDispListwire(lb, ob->type);
- }
- break;
- case OB_MBALL:
-
- if (BKE_mball_is_basis(ob)) {
- lb = &ob->curve_cache->disp;
- if (BLI_listbase_is_empty(lb)) {
- return true;
- }
-
- if (solid) {
-
- if (draw_glsl_material(scene, ob, v3d, dt)) {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
- drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
- GPU_end_object_materials();
- }
- else {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
- drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
- GPU_end_object_materials();
- }
- }
- else {
- return drawDispListwire(lb, ob->type);
- }
- }
- break;
- }
-
- return false;
-}
-static bool drawDispList(Main *bmain, Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
- const char dt, const short dflag, const unsigned char ob_wire_col[4])
-{
- bool retval;
-
- /* backface culling */
- if (v3d->flag2 & V3D_BACKFACE_CULLING) {
- /* not all displists use same in/out normal direction convention */
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
- }
-
-#ifdef SEQUENCER_DAG_WORKAROUND
- ensure_curve_cache(bmain, scene, base->object);
-#endif
-
- if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
- retval = false;
- }
- else {
- Object *ob = base->object;
- GLenum mode;
-
- if (ob->type == OB_MBALL) {
- mode = (ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW;
- }
- else {
- mode = (ob->transflag & OB_NEG_SCALE) ? GL_CCW : GL_CW;
- }
-
- glFrontFace(mode);
-
- retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
-
- if (mode != GL_CCW) {
- glFrontFace(GL_CCW);
- }
- }
-
- if (v3d->flag2 & V3D_BACKFACE_CULLING) {
- glDisable(GL_CULL_FACE);
- }
-
- return retval;
-}
-
-/* *********** drawing for particles ************* */
-static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select)
-{
- /* draw created data arrays */
- switch (draw_as) {
- case PART_DRAW_AXIS:
- case PART_DRAW_CROSS:
- glDrawArrays(GL_LINES, 0, 6 * totpoint);
- break;
- case PART_DRAW_LINE:
- glDrawArrays(GL_LINES, 0, 2 * totpoint);
- break;
- case PART_DRAW_BB:
- if (ob_dt <= OB_WIRE || select)
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- else
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
- glDrawArrays(GL_QUADS, 0, 4 * totpoint);
- break;
- default:
- glDrawArrays(GL_POINTS, 0, totpoint);
- break;
- }
-}
-static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize,
- float imat[4][4], const float draw_line[2], ParticleBillboardData *bb, ParticleDrawData *pdd)
-{
- float vec[3], vec2[3];
- float *vd = NULL;
- float *cd = NULL;
- float ma_col[3] = {0.0f, 0.0f, 0.0f};
-
- /* null only for PART_DRAW_CIRC */
- if (pdd) {
- vd = pdd->vd;
- cd = pdd->cd;
-
- if (pdd->ma_col) {
- copy_v3_v3(ma_col, pdd->ma_col);
- }
- }
-
- switch (draw_as) {
- case PART_DRAW_DOT:
- {
- if (vd) {
- copy_v3_v3(vd, state->co); pdd->vd += 3;
- }
- if (cd) {
- copy_v3_v3(cd, pdd->ma_col);
- pdd->cd += 3;
- }
- break;
- }
- case PART_DRAW_CROSS:
- case PART_DRAW_AXIS:
- {
- vec[0] = 2.0f * pixsize;
- vec[1] = vec[2] = 0.0;
- mul_qt_v3(state->rot, vec);
- if (draw_as == PART_DRAW_AXIS) {
- if (cd) {
- cd[1] = cd[2] = cd[4] = cd[5] = 0.0;
- cd[0] = cd[3] = 1.0;
- cd[6] = cd[8] = cd[9] = cd[11] = 0.0;
- cd[7] = cd[10] = 1.0;
- cd[13] = cd[12] = cd[15] = cd[16] = 0.0;
- cd[14] = cd[17] = 1.0;
- pdd->cd += 18;
- }
-
- copy_v3_v3(vec2, state->co);
- }
- else {
- if (cd) {
- cd[0] = cd[3] = cd[6] = cd[9] = cd[12] = cd[15] = ma_col[0];
- cd[1] = cd[4] = cd[7] = cd[10] = cd[13] = cd[16] = ma_col[1];
- cd[2] = cd[5] = cd[8] = cd[11] = cd[14] = cd[17] = ma_col[2];
- pdd->cd += 18;
- }
- sub_v3_v3v3(vec2, state->co, vec);
- }
-
- add_v3_v3(vec, state->co);
- copy_v3_v3(pdd->vd, vec); pdd->vd += 3;
- copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
-
- vec[1] = 2.0f * pixsize;
- vec[0] = vec[2] = 0.0;
- mul_qt_v3(state->rot, vec);
- if (draw_as == PART_DRAW_AXIS) {
- copy_v3_v3(vec2, state->co);
- }
- else {
- sub_v3_v3v3(vec2, state->co, vec);
- }
-
- add_v3_v3(vec, state->co);
- copy_v3_v3(pdd->vd, vec); pdd->vd += 3;
- copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
-
- vec[2] = 2.0f * pixsize;
- vec[0] = vec[1] = 0.0f;
- mul_qt_v3(state->rot, vec);
- if (draw_as == PART_DRAW_AXIS) {
- copy_v3_v3(vec2, state->co);
- }
- else {
- sub_v3_v3v3(vec2, state->co, vec);
- }
-
- add_v3_v3(vec, state->co);
-
- copy_v3_v3(pdd->vd, vec); pdd->vd += 3;
- copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
- break;
- }
- case PART_DRAW_LINE:
- {
- copy_v3_v3(vec, state->vel);
- normalize_v3(vec);
- if (draw & PART_DRAW_VEL_LENGTH)
- mul_v3_fl(vec, len_v3(state->vel));
- madd_v3_v3v3fl(pdd->vd, state->co, vec, -draw_line[0]); pdd->vd += 3;
- madd_v3_v3v3fl(pdd->vd, state->co, vec, draw_line[1]); pdd->vd += 3;
- if (cd) {
- cd[0] = cd[3] = ma_col[0];
- cd[1] = cd[4] = ma_col[1];
- cd[2] = cd[5] = ma_col[2];
- pdd->cd += 6;
- }
- break;
- }
- case PART_DRAW_CIRC:
- {
- drawcircball(GL_LINE_LOOP, state->co, pixsize, imat);
- break;
- }
- case PART_DRAW_BB:
- {
- float xvec[3], yvec[3], zvec[3], bb_center[3];
- if (cd) {
- cd[0] = cd[3] = cd[6] = cd[9] = ma_col[0];
- cd[1] = cd[4] = cd[7] = cd[10] = ma_col[1];
- cd[2] = cd[5] = cd[8] = cd[11] = ma_col[2];
- pdd->cd += 12;
- }
-
- copy_v3_v3(bb->vec, state->co);
- copy_v3_v3(bb->vel, state->vel);
-
- psys_make_billboard(bb, xvec, yvec, zvec, bb_center);
-
- add_v3_v3v3(pdd->vd, bb_center, xvec);
- add_v3_v3(pdd->vd, yvec); pdd->vd += 3;
-
- sub_v3_v3v3(pdd->vd, bb_center, xvec);
- add_v3_v3(pdd->vd, yvec); pdd->vd += 3;
-
- sub_v3_v3v3(pdd->vd, bb_center, xvec);
- sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
-
- add_v3_v3v3(pdd->vd, bb_center, xvec);
- sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
-
- copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
- copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
- copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
- copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
- break;
- }
- }
-}
-static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
- ParticleKey *state, int draw_as,
- float imat[4][4], ParticleBillboardData *bb, ParticleDrawData *pdd,
- const float ct, const float pa_size, const float r_tilt, const float pixsize_scale)
-{
- ParticleSettings *part = psys->part;
- float pixsize;
-
- if (psys->parent)
- mul_m4_v3(psys->parent->obmat, state->co);
-
- /* create actual particle data */
- if (draw_as == PART_DRAW_BB) {
- bb->offset[0] = part->bb_offset[0];
- bb->offset[1] = part->bb_offset[1];
- bb->size[0] = part->bb_size[0] * pa_size;
- if (part->bb_align == PART_BB_VEL) {
- float pa_vel = len_v3(state->vel);
- float head = part->bb_vel_head * pa_vel;
- float tail = part->bb_vel_tail * pa_vel;
- bb->size[1] = part->bb_size[1] * pa_size + head + tail;
- /* use offset to adjust the particle center. this is relative to size, so need to divide! */
- if (bb->size[1] > 0.0f)
- bb->offset[1] += (head - tail) / bb->size[1];
- }
- else {
- bb->size[1] = part->bb_size[1] * pa_size;
- }
- bb->tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
- bb->time = ct;
- }
-
- pixsize = ED_view3d_pixel_size(rv3d, state->co) * pixsize_scale;
-
- draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd);
-}
-/* unified drawing of all new particle systems draw types except dupli ob & group
- * mostly tries to use vertex arrays for speed
- *
- * 1. check that everything is ok & updated
- * 2. start initializing things
- * 3. initialize according to draw type
- * 4. allocate drawing data arrays
- * 5. start filling the arrays
- * 6. draw the arrays
- * 7. clean up
- */
-static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d,
- Base *base, ParticleSystem *psys,
- const char ob_dt, const short dflag)
-{
- Object *ob = base->object;
- ParticleEditSettings *pset = PE_settings(scene);
- ParticleSettings *part = psys->part;
- ParticleData *pars = psys->particles;
- ParticleData *pa;
- ParticleKey state, *states = NULL;
- ParticleBillboardData bb;
- ParticleSimulationData sim = {NULL};
- ParticleDrawData *pdd = psys->pdd;
- Material *ma;
- float vel[3], imat[4][4];
- float timestep, pixsize_scale = 1.0f, pa_size, r_tilt, r_length;
- float pa_time, pa_birthtime, pa_dietime, pa_health, intensity;
- float cfra;
- float ma_col[3] = {0.0f, 0.0f, 0.0f};
- int a, totpart, totpoint = 0, totve = 0, drawn, draw_as, totchild = 0;
- bool select = (ob->flag & SELECT) != 0, create_cdata = false, need_v = false;
- GLint polygonmode[2];
- char numstr[32];
- unsigned char tcol[4] = {0, 0, 0, 255};
-
-/* 1. */
- if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering))
- return;
-
- if (pars == NULL) return;
-
- /* don't draw normal paths in edit mode */
- if (psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART) == 0)
- return;
-
- if (part->draw_as == PART_DRAW_REND)
- draw_as = part->ren_as;
- else
- draw_as = part->draw_as;
-
- if (draw_as == PART_DRAW_NOT)
- return;
-
- /* prepare curvemapping tables */
- if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
- curvemapping_changed_all(psys->part->clumpcurve);
- if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
- curvemapping_changed_all(psys->part->roughcurve);
- if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve)
- curvemapping_changed_all(psys->part->twistcurve);
-
-/* 2. */
- sim.scene = scene;
- sim.ob = ob;
- sim.psys = psys;
- sim.psmd = psys_get_modifier(ob, psys);
-
- if (part->phystype == PART_PHYS_KEYED) {
- if (psys->flag & PSYS_KEYED) {
- psys_count_keyed_targets(&sim);
- if (psys->totkeyed == 0)
- return;
- }
- }
-
- if (select) {
- select = false;
- if (psys_get_current(ob) == psys)
- select = true;
- }
-
- psys->flag |= PSYS_DRAWING;
-
- if (part->type == PART_HAIR && !psys->childcache)
- totchild = 0;
- else
- totchild = psys->totchild * part->disp / 100;
-
- ma = give_current_material(ob, part->omat);
-
- if (v3d->zbuf) glDepthMask(1);
-
- if ((ma) && (part->draw_col == PART_DRAW_COL_MAT)) {
- rgb_float_to_uchar(tcol, &(ma->r));
- copy_v3_v3(ma_col, &ma->r);
- }
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(tcol);
- }
-
- timestep = psys_get_timestep(&sim);
-
- if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) {
- float mat[4][4];
- mul_m4_m4m4(mat, ob->obmat, psys->imat);
- glMultMatrixf(mat);
- }
-
- /* needed for text display */
- invert_m4_m4(ob->imat, ob->obmat);
-
- totpart = psys->totpart;
-
- cfra = BKE_scene_frame_get(scene);
-
- if (draw_as == PART_DRAW_PATH && psys->pathcache == NULL && psys->childcache == NULL)
- draw_as = PART_DRAW_DOT;
-
-/* 3. */
- glLineWidth(1.0f);
-
- switch (draw_as) {
- case PART_DRAW_DOT:
- if (part->draw_size)
- glPointSize(part->draw_size);
- else
- glPointSize(2.0); /* default dot size */
- break;
- case PART_DRAW_CIRC:
- /* calculate view aligned matrix: */
- copy_m4_m4(imat, rv3d->viewinv);
- normalize_v3(imat[0]);
- normalize_v3(imat[1]);
- ATTR_FALLTHROUGH;
- case PART_DRAW_CROSS:
- case PART_DRAW_AXIS:
- /* lets calculate the scale: */
-
- if (part->draw_size == 0.0)
- pixsize_scale = 2.0f;
- else
- pixsize_scale = part->draw_size;
-
- if (draw_as == PART_DRAW_AXIS)
- create_cdata = 1;
- break;
- case PART_DRAW_OB:
- if (part->dup_ob == NULL)
- draw_as = PART_DRAW_DOT;
- else
- draw_as = 0;
- break;
- case PART_DRAW_GR:
- if (part->dup_group == NULL)
- draw_as = PART_DRAW_DOT;
- else
- draw_as = 0;
- break;
- case PART_DRAW_BB:
- if (v3d->camera == NULL && part->bb_ob == NULL) {
- printf("Billboards need an active camera or a target object!\n");
-
- draw_as = part->draw_as = PART_DRAW_DOT;
-
- if (part->draw_size)
- glPointSize(part->draw_size);
- else
- glPointSize(2.0); /* default dot size */
- }
- else if (part->bb_ob)
- bb.ob = part->bb_ob;
- else
- bb.ob = v3d->camera;
-
- bb.align = part->bb_align;
- bb.anim = part->bb_anim;
- bb.lock = part->draw & PART_DRAW_BB_LOCK;
- break;
- case PART_DRAW_PATH:
- break;
- case PART_DRAW_LINE:
- need_v = 1;
- break;
- }
- if (part->draw & PART_DRAW_SIZE && part->draw_as != PART_DRAW_CIRC) {
- copy_m4_m4(imat, rv3d->viewinv);
- normalize_v3(imat[0]);
- normalize_v3(imat[1]);
- }
-
- if (ELEM(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) &&
- (part->draw_col > PART_DRAW_COL_MAT))
- {
- create_cdata = 1;
- }
-
- if (!create_cdata && pdd && pdd->cdata) {
- MEM_freeN(pdd->cdata);
- pdd->cdata = pdd->cd = NULL;
- }
-
-/* 4. */
- if (draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC) == 0) {
- int partsize = 3 * sizeof(float);
- int create_ndata = 0;
-
- if (!pdd)
- pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData");
-
- if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
- partsize *= part->trail_count;
- psys_make_temp_pointcache(ob, psys);
- }
-
- switch (draw_as) {
- case PART_DRAW_AXIS:
- case PART_DRAW_CROSS:
- partsize *= 6;
- if (draw_as != PART_DRAW_CROSS)
- create_cdata = 1;
- break;
- case PART_DRAW_LINE:
- partsize *= 2;
- break;
- case PART_DRAW_BB:
- partsize *= 4;
- create_ndata = 1;
- break;
- }
-
- if (pdd->totpart != totpart + totchild || pdd->partsize != partsize)
- psys_free_pdd(psys);
-
- if (!pdd->vdata)
- pdd->vdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_vdata");
- if (create_cdata && !pdd->cdata)
- pdd->cdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_cdata");
- if (create_ndata && !pdd->ndata)
- pdd->ndata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_ndata");
-
- if (part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) {
- if (!pdd->vedata)
- pdd->vedata = MEM_calloc_arrayN(totpart + totchild, 2 * 3 * sizeof(float), "particle_vedata");
-
- need_v = 1;
- }
- else if (pdd->vedata) {
- /* velocity data not needed, so free it */
- MEM_freeN(pdd->vedata);
- pdd->vedata = NULL;
- }
-
- pdd->vd = pdd->vdata;
- pdd->ved = pdd->vedata;
- pdd->cd = pdd->cdata;
- pdd->nd = pdd->ndata;
- pdd->totpart = totpart + totchild;
- pdd->partsize = partsize;
- }
- else if (psys->pdd) {
- psys_free_pdd(psys);
- MEM_freeN(psys->pdd);
- pdd = psys->pdd = NULL;
- }
-
- if (pdd) {
- pdd->ma_col = ma_col;
- }
-
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
- /* circles don't use drawdata, so have to add a special case here */
- if ((pdd || draw_as == PART_DRAW_CIRC) && draw_as != PART_DRAW_PATH) {
- /* 5. */
- if (pdd && (pdd->flag & PARTICLE_DRAW_DATA_UPDATED) &&
- (pdd->vedata || part->draw & (PART_DRAW_SIZE | PART_DRAW_NUM | PART_DRAW_HEALTH)) == 0)
- {
- totpoint = pdd->totpoint; /* draw data is up to date */
- }
- else {
- for (a = 0, pa = pars; a < totpart + totchild; a++, pa++) {
- /* setup per particle individual stuff */
- if (a < totpart) {
- if (totchild && (part->draw & PART_DRAW_PARENT) == 0) continue;
- if (pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue;
-
- pa_time = (cfra - pa->time) / pa->lifetime;
- pa_birthtime = pa->time;
- pa_dietime = pa->dietime;
- pa_size = pa->size;
- if (part->phystype == PART_PHYS_BOIDS)
- pa_health = pa->boid->data.health;
- else
- pa_health = -1.0;
-
- r_tilt = 2.0f * (psys_frand(psys, a + 21) - 0.5f);
- r_length = psys_frand(psys, a + 22);
-
- if (part->draw_col > PART_DRAW_COL_MAT) {
- switch (part->draw_col) {
- case PART_DRAW_COL_VEL:
- intensity = len_v3(pa->state.vel) / part->color_vec_max;
- break;
- case PART_DRAW_COL_ACC:
- intensity = len_v3v3(pa->state.vel, pa->prev_state.vel) / ((pa->state.time - pa->prev_state.time) * part->color_vec_max);
- break;
- default:
- intensity = 1.0f; /* should never happen */
- BLI_assert(0);
- break;
- }
- CLAMP(intensity, 0.0f, 1.0f);
- weight_to_rgb(ma_col, intensity);
- }
- }
- else {
- ChildParticle *cpa = &psys->child[a - totpart];
-
- pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
- pa_size = psys_get_child_size(psys, cpa, cfra, NULL);
-
- pa_health = -1.0;
-
- r_tilt = 2.0f * (psys_frand(psys, a + 21) - 0.5f);
- r_length = psys_frand(psys, a + 22);
- }
-
- drawn = 0;
- if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
- float length = part->path_end * (1.0f - part->randlength * r_length);
- int trail_count = part->trail_count * (1.0f - part->randlength * r_length);
- float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length;
- float dt = length / (trail_count ? (float)trail_count : 1.0f);
- int i = 0;
-
- ct += dt;
- for (i = 0; i < trail_count; i++, ct += dt) {
-
- if (part->draw & PART_ABS_PATH_TIME) {
- if (ct < pa_birthtime || ct > pa_dietime)
- continue;
- }
- else if (ct < 0.0f || ct > 1.0f)
- continue;
-
- state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime));
- psys_get_particle_on_path(&sim, a, &state, need_v);
-
- draw_particle_data(psys, rv3d,
- &state, draw_as, imat, &bb, psys->pdd,
- ct, pa_size, r_tilt, pixsize_scale);
-
- totpoint++;
- drawn = 1;
- }
- }
- else {
- state.time = cfra;
- if (psys_get_particle_state(&sim, a, &state, 0)) {
-
- draw_particle_data(psys, rv3d,
- &state, draw_as, imat, &bb, psys->pdd,
- pa_time, pa_size, r_tilt, pixsize_scale);
-
- totpoint++;
- drawn = 1;
- }
- }
-
- if (drawn) {
- /* additional things to draw for each particle
- * (velocity, size and number) */
- if ((part->draw & PART_DRAW_VEL) && pdd && pdd->vedata) {
- copy_v3_v3(pdd->ved, state.co);
- pdd->ved += 3;
- mul_v3_v3fl(vel, state.vel, timestep);
- add_v3_v3v3(pdd->ved, state.co, vel);
- pdd->ved += 3;
-
- totve++;
- }
-
- if (part->draw & PART_DRAW_SIZE) {
- setlinestyle(3);
- drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
- setlinestyle(0);
- }
-
-
- if ((part->draw & PART_DRAW_NUM || part->draw & PART_DRAW_HEALTH) &&
- (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0)
- {
- size_t numstr_len;
- float vec_txt[3];
- char *val_pos = numstr;
- numstr[0] = '\0';
-
- if (part->draw & PART_DRAW_NUM) {
- if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
- numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health);
- }
- else {
- numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d", a);
- }
- }
- else {
- if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
- numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%.2f", pa_health);
- }
- }
-
- if (numstr[0]) {
- /* in path drawing state.co is the end point
- * use worldspace because object matrix is already applied */
- mul_v3_m4v3(vec_txt, ob->imat, state.co);
- view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
- 10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
- }
- }
- }
- }
- }
- }
-/* 6. */
-
- glGetIntegerv(GL_POLYGON_MODE, polygonmode);
- glEnableClientState(GL_VERTEX_ARRAY);
-
- if (draw_as == PART_DRAW_PATH) {
- ParticleCacheKey **cache, *path;
- float *cdata2 = NULL;
-
- /* setup gl flags */
- if (1) { //ob_dt > OB_WIRE) {
- glEnableClientState(GL_NORMAL_ARRAY);
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (part->draw_col == PART_DRAW_COL_MAT)
- glEnableClientState(GL_COLOR_ARRAY);
- }
-
- // XXX test
- GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
- }
-
- if (totchild && (part->draw & PART_DRAW_PARENT) == 0)
- totpart = 0;
- else if (psys->pathcache == NULL)
- totpart = 0;
-
- /* draw actual/parent particles */
- cache = psys->pathcache;
- for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
- path = cache[a];
- if (path->segments > 0) {
- glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
-
- if (1) { //ob_dt > OB_WIRE) {
- glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (part->draw_col == PART_DRAW_COL_MAT) {
- glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
- }
- }
- }
-
- glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
- }
- }
-
- if (part->type == PART_HAIR) {
- if (part->draw & PART_DRAW_GUIDE_HAIRS) {
- DerivedMesh *hair_dm = psys->hair_out_dm;
-
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
-
- for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
- if (pa->totkey > 1) {
- HairKey *hkey = pa->hair;
-
- glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co);
-
-#if 0 /* XXX use proper theme color here */
- UI_ThemeColor(TH_NORMAL);
-#else
- glColor3f(0.58f, 0.67f, 1.0f);
-#endif
-
- glDrawArrays(GL_LINE_STRIP, 0, pa->totkey);
- }
- }
-
- if (hair_dm) {
- MVert *mvert = hair_dm->getVertArray(hair_dm);
- int i;
-
- glColor3f(0.9f, 0.4f, 0.4f);
-
- glBegin(GL_LINES);
- for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
- for (i = 1; i < pa->totkey; ++i) {
- float v1[3], v2[3];
-
- copy_v3_v3(v1, mvert[pa->hair_index + i - 1].co);
- copy_v3_v3(v2, mvert[pa->hair_index + i].co);
-
- mul_m4_v3(ob->obmat, v1);
- mul_m4_v3(ob->obmat, v2);
-
- glVertex3fv(v1);
- glVertex3fv(v2);
- }
- }
- glEnd();
- }
-
- glEnableClientState(GL_NORMAL_ARRAY);
- if ((dflag & DRAW_CONSTCOLOR) == 0)
- if (part->draw_col == PART_DRAW_COL_MAT)
- glEnableClientState(GL_COLOR_ARRAY);
- }
-
- if (part->draw & PART_DRAW_HAIR_GRID) {
- ClothModifierData *clmd = psys->clmd;
- if (clmd) {
- float *gmin = clmd->hair_grid_min;
- float *gmax = clmd->hair_grid_max;
- int *res = clmd->hair_grid_res;
- int i;
-
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
-
- if (select)
- UI_ThemeColor(TH_ACTIVE);
- else
- UI_ThemeColor(TH_WIRE);
- glBegin(GL_LINES);
- glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmin[2]);
- glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmin[2]);
- glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmin[2]);
- glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmin[2]);
-
- glVertex3f(gmin[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmin[1], gmax[2]);
- glVertex3f(gmax[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmax[1], gmax[2]);
- glVertex3f(gmax[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmax[1], gmax[2]);
- glVertex3f(gmin[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmin[1], gmax[2]);
-
- glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmax[2]);
- glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmax[2]);
- glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmax[2]);
- glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmax[2]);
- glEnd();
-
- if (select)
- UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -100);
- else
- UI_ThemeColorShadeAlpha(TH_WIRE, 0, -100);
- glEnable(GL_BLEND);
- glBegin(GL_LINES);
- for (i = 1; i < res[0] - 1; ++i) {
- float f = interpf(gmax[0], gmin[0], (float)i / (float)(res[0] - 1));
- glVertex3f(f, gmin[1], gmin[2]); glVertex3f(f, gmax[1], gmin[2]);
- glVertex3f(f, gmax[1], gmin[2]); glVertex3f(f, gmax[1], gmax[2]);
- glVertex3f(f, gmax[1], gmax[2]); glVertex3f(f, gmin[1], gmax[2]);
- glVertex3f(f, gmin[1], gmax[2]); glVertex3f(f, gmin[1], gmin[2]);
- }
- for (i = 1; i < res[1] - 1; ++i) {
- float f = interpf(gmax[1], gmin[1], (float)i / (float)(res[1] - 1));
- glVertex3f(gmin[0], f, gmin[2]); glVertex3f(gmax[0], f, gmin[2]);
- glVertex3f(gmax[0], f, gmin[2]); glVertex3f(gmax[0], f, gmax[2]);
- glVertex3f(gmax[0], f, gmax[2]); glVertex3f(gmin[0], f, gmax[2]);
- glVertex3f(gmin[0], f, gmax[2]); glVertex3f(gmin[0], f, gmin[2]);
- }
- for (i = 1; i < res[2] - 1; ++i) {
- float f = interpf(gmax[2], gmin[2], (float)i / (float)(res[2] - 1));
- glVertex3f(gmin[0], gmin[1], f); glVertex3f(gmax[0], gmin[1], f);
- glVertex3f(gmax[0], gmin[1], f); glVertex3f(gmax[0], gmax[1], f);
- glVertex3f(gmax[0], gmax[1], f); glVertex3f(gmin[0], gmax[1], f);
- glVertex3f(gmin[0], gmax[1], f); glVertex3f(gmin[0], gmin[1], f);
- }
- glEnd();
- glDisable(GL_BLEND);
-
- glEnableClientState(GL_NORMAL_ARRAY);
- if ((dflag & DRAW_CONSTCOLOR) == 0)
- if (part->draw_col == PART_DRAW_COL_MAT)
- glEnableClientState(GL_COLOR_ARRAY);
- }
- }
- }
-
- /* draw child particles */
- cache = psys->childcache;
- for (a = 0; a < totchild; a++) {
- path = cache[a];
- glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
-
- if (1) { //ob_dt > OB_WIRE) {
- glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (part->draw_col == PART_DRAW_COL_MAT) {
- glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
- }
- }
- }
-
- glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
- }
-
- /* restore & clean up */
- if (1) { //ob_dt > OB_WIRE) {
- if (part->draw_col == PART_DRAW_COL_MAT)
- glDisableClientState(GL_COLOR_ARRAY);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
-
- if (cdata2) {
- MEM_freeN(cdata2);
- cdata2 = NULL;
- }
-
- if ((part->draw & PART_DRAW_NUM) && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- cache = psys->pathcache;
-
- for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
- float vec_txt[3];
- size_t numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%i", a);
- /* use worldspace because object matrix is already applied */
- mul_v3_m4v3(vec_txt, ob->imat, cache[a]->co);
- view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
- 10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
- }
- }
- }
- else if (pdd && ELEM(draw_as, 0, PART_DRAW_CIRC) == 0) {
- glDisableClientState(GL_COLOR_ARRAY);
-
- /* enable point data array */
- if (pdd->vdata) {
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, pdd->vdata);
- }
- else
- glDisableClientState(GL_VERTEX_ARRAY);
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (select) {
- UI_ThemeColor(TH_ACTIVE);
-
- if (part->draw_size)
- glPointSize(part->draw_size + 2);
- else
- glPointSize(4.0);
-
- glLineWidth(3.0);
-
- draw_particle_arrays(draw_as, totpoint, ob_dt, 1);
- }
-
- /* restore from select */
- glColor3fv(ma_col);
- }
-
- glPointSize(part->draw_size ? part->draw_size : 2.0);
- glLineWidth(1.0);
-
- /* enable other data arrays */
-
- /* billboards are drawn this way */
- if (pdd->ndata && ob_dt > OB_WIRE) {
- glEnableClientState(GL_NORMAL_ARRAY);
- glNormalPointer(GL_FLOAT, 0, pdd->ndata);
- GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
- }
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if (pdd->cdata) {
- glEnableClientState(GL_COLOR_ARRAY);
- glColorPointer(3, GL_FLOAT, 0, pdd->cdata);
- }
- }
-
- draw_particle_arrays(draw_as, totpoint, ob_dt, 0);
-
- pdd->flag |= PARTICLE_DRAW_DATA_UPDATED;
- pdd->totpoint = totpoint;
- }
-
- if (pdd && pdd->vedata) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glDisableClientState(GL_COLOR_ARRAY);
- cpack(0xC0C0C0);
- }
-
- glVertexPointer(3, GL_FLOAT, 0, pdd->vedata);
-
- glDrawArrays(GL_LINES, 0, 2 * totve);
- }
-
- glPolygonMode(GL_FRONT, polygonmode[0]);
- glPolygonMode(GL_BACK, polygonmode[1]);
-
-/* 7. */
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_NORMAL_ARRAY);
-
- if (states)
- MEM_freeN(states);
-
- psys->flag &= ~PSYS_DRAWING;
-
- /* draw data can't be saved for billboards as they must update to target changes */
- if (draw_as == PART_DRAW_BB) {
- psys_free_pdd(psys);
- pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
- }
-
- if (psys->lattice_deform_data) {
- end_latt_deform(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
-
- if (pdd) {
- /* drop references to stack memory */
- pdd->ma_col = NULL;
- }
-
- if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) {
- glLoadMatrixf(rv3d->viewmat);
- }
-}
-
-static void draw_update_ptcache_edit(Main *bmain, Scene *scene, Object *ob, PTCacheEdit *edit)
-{
- if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED)
- PE_update_object(bmain, scene, ob, 0);
-
- /* create path and child path cache if it doesn't exist already */
- if (edit->pathcache == NULL)
- psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
-}
-
-static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
-{
- ParticleCacheKey **cache, *path, *pkey;
- PTCacheEditPoint *point;
- PTCacheEditKey *key;
- ParticleEditSettings *pset = PE_settings(scene);
- int i, k, totpoint = edit->totpoint, timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : 0;
- int totkeys = 1;
- float sel_col[3];
- float nosel_col[3];
- float *pathcol = NULL, *pcol;
-
- if (edit->pathcache == NULL)
- return;
-
- PE_hide_keys_time(scene, edit, CFRA);
-
- /* opengl setup */
- if ((v3d->flag & V3D_ZBUF_SELECT) == 0)
- glDisable(GL_DEPTH_TEST);
-
- /* get selection theme colors */
- UI_GetThemeColor3fv(TH_VERTEX_SELECT, sel_col);
- UI_GetThemeColor3fv(TH_VERTEX, nosel_col);
-
- /* draw paths */
- totkeys = (*edit->pathcache)->segments + 1;
-
- glEnable(GL_BLEND);
- pathcol = MEM_calloc_arrayN(totkeys, 4 * sizeof(float), "particle path color data");
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
-
- if (pset->brushtype == PE_BRUSH_WEIGHT)
- glLineWidth(2.0f);
-
- cache = edit->pathcache;
- for (i = 0, point = edit->points; i < totpoint; i++, point++) {
- path = cache[i];
- glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
-
- if (point->flag & PEP_HIDE) {
- for (k = 0, pcol = pathcol; k < totkeys; k++, pcol += 4) {
- copy_v3_v3(pcol, path->col);
- pcol[3] = 0.25f;
- }
-
- glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol);
- }
- else if (timed) {
- for (k = 0, pcol = pathcol, pkey = path; k < totkeys; k++, pkey++, pcol += 4) {
- copy_v3_v3(pcol, pkey->col);
- pcol[3] = 1.0f - fabsf((float)(CFRA) -pkey->time) / (float)pset->fade_frames;
- }
-
- glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol);
- }
- else
- glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
-
- glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
- }
-
- if (pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; }
-
-
- /* draw edit vertices */
- if (pset->selectmode != SCE_SELECT_PATH) {
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
-
- if (pset->selectmode == SCE_SELECT_POINT) {
- float *pd = NULL, *pdata = NULL;
- float *cd = NULL, *cdata = NULL;
- int totkeys_visible = 0;
-
- for (i = 0, point = edit->points; i < totpoint; i++, point++)
- if (!(point->flag & PEP_HIDE))
- totkeys_visible += point->totkey;
-
- if (totkeys_visible) {
- if (edit->points && !(edit->points->keys->flag & PEK_USE_WCO))
- pd = pdata = MEM_calloc_arrayN(totkeys_visible, 3 * sizeof(float), "particle edit point data");
- cd = cdata = MEM_calloc_arrayN(totkeys_visible, (timed ? 4 : 3) * sizeof(float), "particle edit color data");
- }
-
- for (i = 0, point = edit->points; i < totpoint; i++, point++) {
- if (point->flag & PEP_HIDE)
- continue;
-
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- if (pd) {
- copy_v3_v3(pd, key->co);
- pd += 3;
- }
-
- if (key->flag & PEK_SELECT) {
- copy_v3_v3(cd, sel_col);
- }
- else {
- copy_v3_v3(cd, nosel_col);
- }
-
- if (timed)
- *(cd + 3) = 1.0f - fabsf((float)CFRA - *key->time) / (float)pset->fade_frames;
-
- cd += (timed ? 4 : 3);
- }
- }
- cd = cdata;
- pd = pdata;
- for (i = 0, point = edit->points; i < totpoint; i++, point++) {
- if (point->flag & PEP_HIDE || point->totkey == 0)
- continue;
-
- if (point->keys->flag & PEK_USE_WCO)
- glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co);
- else
- glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), pd);
-
- glColorPointer((timed ? 4 : 3), GL_FLOAT, (timed ? 4 : 3) * sizeof(float), cd);
-
- glDrawArrays(GL_POINTS, 0, point->totkey);
-
- pd += pd ? 3 * point->totkey : 0;
- cd += (timed ? 4 : 3) * point->totkey;
- }
- if (pdata) { MEM_freeN(pdata); pd = pdata = NULL; }
- if (cdata) { MEM_freeN(cdata); cd = cdata = NULL; }
- }
- else if (pset->selectmode == SCE_SELECT_END) {
- glBegin(GL_POINTS);
- for (i = 0, point = edit->points; i < totpoint; i++, point++) {
- if ((point->flag & PEP_HIDE) == 0 && point->totkey) {
- key = point->keys + point->totkey - 1;
- glColor3fv((key->flag & PEK_SELECT) ? sel_col : nosel_col);
- /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/
- glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co);
- }
- }
- glEnd();
- }
- }
-
- glDisable(GL_BLEND);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
-}
-
-static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, float ith, float drw_size)
-{
- float tr[3][3];
- float root[3], tip[3];
- /* take a copy for not spoiling original */
- copy_m3_m3(tr, rotscale);
- float tw = itw * drw_size;
- float th = ith * drw_size;
-
- glBegin(GL_LINES);
-
- glColor4ub(0x7F, 0x00, 0x00, 155);
- root[1] = root[2] = 0.0f;
- root[0] = -drw_size;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- tip[1] = tip[2] = 0.0f;
- tip[0] = drw_size;
- mul_m3_v3(tr, tip);
- add_v3_v3(tip, com);
- glVertex3fv(tip);
-
- root[1] = 0.0f; root[2] = tw;
- root[0] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[1] = 0.0f; root[2] = -tw;
- root[0] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[1] = tw; root[2] = 0.0f;
- root[0] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[1] = -tw; root[2] = 0.0f;
- root[0] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- glColor4ub(0x00, 0x7F, 0x00, 155);
-
- root[0] = root[2] = 0.0f;
- root[1] = -drw_size;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- tip[0] = tip[2] = 0.0f;
- tip[1] = drw_size;
- mul_m3_v3(tr, tip);
- add_v3_v3(tip, com);
- glVertex3fv(tip);
-
- root[0] = 0.0f; root[2] = tw;
- root[1] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[0] = 0.0f; root[2] = -tw;
- root[1] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[0] = tw; root[2] = 0.0f;
- root[1] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[0] = -tw; root[2] = 0.0f;
- root[1] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- glColor4ub(0x00, 0x00, 0x7F, 155);
- root[0] = root[1] = 0.0f;
- root[2] = -drw_size;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- tip[0] = tip[1] = 0.0f;
- tip[2] = drw_size;
- mul_m3_v3(tr, tip);
- add_v3_v3(tip, com);
- glVertex3fv(tip);
-
- root[0] = 0.0f; root[1] = tw;
- root[2] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[0] = 0.0f; root[1] = -tw;
- root[2] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[0] = tw; root[1] = 0.0f;
- root[2] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- root[0] = -tw; root[1] = 0.0f;
- root[2] = th;
- mul_m3_v3(tr, root);
- add_v3_v3(root, com);
- glVertex3fv(root);
- glVertex3fv(tip);
-
- glEnd();
-}
-
-/* place to add drawers */
-
-static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
-{
- if (nu->hide || hide_handles) return;
-
- if (nu->type == CU_BEZIER) {
-
- const float *fp;
-
-#define TH_HANDLE_COL_TOT ((TH_HANDLE_SEL_FREE - TH_HANDLE_FREE) + 1)
- /* use MIN2 when indexing to ensure newer files don't read outside the array */
- unsigned char handle_cols[TH_HANDLE_COL_TOT][3];
- const int basecol = sel ? TH_HANDLE_SEL_FREE : TH_HANDLE_FREE;
-
- for (int a = 0; a < TH_HANDLE_COL_TOT; a++) {
- UI_GetThemeColor3ubv(basecol + a, handle_cols[a]);
- }
-
- glLineWidth(1.0f);
-
- glBegin(GL_LINES);
-
- BezTriple *bezt = nu->bezt;
- int a = nu->pntsu;
- while (a--) {
- if (bezt->hide == 0) {
- if ((bezt->f2 & SELECT) == sel) {
- fp = bezt->vec[0];
-
- glColor3ubv(handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]);
- glVertex3fv(fp);
- glVertex3fv(fp + 3);
-
- glColor3ubv(handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
- glVertex3fv(fp + 3);
- glVertex3fv(fp + 6);
- }
- else if ((bezt->f1 & SELECT) == sel) {
- fp = bezt->vec[0];
-
- glColor3ubv(handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]);
- glVertex3fv(fp);
- glVertex3fv(fp + 3);
- }
- else if ((bezt->f3 & SELECT) == sel) {
- fp = bezt->vec[1];
-
- glColor3ubv(handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
- glVertex3fv(fp);
- glVertex3fv(fp + 3);
- }
- }
- bezt++;
- }
-
- glEnd();
-
-#undef TH_HANDLE_COL_TOT
-
- }
-}
-
-static void drawhandlesN_active(Nurb *nu)
-{
- if (nu->hide) return;
-
- UI_ThemeColor(TH_ACTIVE_SPLINE);
- glLineWidth(2);
-
- glBegin(GL_LINES);
-
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt = nu->bezt;
- int a = nu->pntsu;
- while (a--) {
- if (bezt->hide == 0) {
- const float *fp = bezt->vec[0];
-
- glVertex3fv(fp);
- glVertex3fv(fp + 3);
-
- glVertex3fv(fp + 3);
- glVertex3fv(fp + 6);
- }
- bezt++;
- }
- }
- glEnd();
-
- glColor3ub(0, 0, 0);
-}
-
-static void drawvertsN(Nurb *nu, const char sel, const bool hide_handles, const void *vert)
-{
- if (nu->hide) return;
-
- const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
-
- UI_ThemeColor(color);
-
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
-
- glBegin(GL_POINTS);
-
- if (nu->type == CU_BEZIER) {
-
- BezTriple *bezt = nu->bezt;
- int a = nu->pntsu;
- while (a--) {
- if (bezt->hide == 0) {
- if (sel == 1 && bezt == vert) {
- UI_ThemeColor(TH_ACTIVE_VERT);
-
- if (bezt->f2 & SELECT) glVertex3fv(bezt->vec[1]);
- if (!hide_handles) {
- if (bezt->f1 & SELECT) glVertex3fv(bezt->vec[0]);
- if (bezt->f3 & SELECT) glVertex3fv(bezt->vec[2]);
- }
-
- UI_ThemeColor(color);
- }
- else if (hide_handles) {
- if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]);
- }
- else {
- if ((bezt->f1 & SELECT) == sel) glVertex3fv(bezt->vec[0]);
- if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]);
- if ((bezt->f3 & SELECT) == sel) glVertex3fv(bezt->vec[2]);
- }
- }
- bezt++;
- }
- }
- else {
- BPoint *bp = nu->bp;
- int a = nu->pntsu * nu->pntsv;
- while (a--) {
- if (bp->hide == 0) {
- if (bp == vert) {
- UI_ThemeColor(TH_ACTIVE_VERT);
- glVertex3fv(bp->vec);
- UI_ThemeColor(color);
- }
- else {
- if ((bp->f1 & SELECT) == sel) glVertex3fv(bp->vec);
- }
- }
- bp++;
- }
- }
-
- glEnd();
-}
-
-static void editnurb_draw_active_poly(Nurb *nu)
-{
- UI_ThemeColor(TH_ACTIVE_SPLINE);
- glLineWidth(2);
-
- BPoint *bp = nu->bp;
- for (int b = 0; b < nu->pntsv; b++) {
- if (nu->flagu & 1) glBegin(GL_LINE_LOOP);
- else glBegin(GL_LINE_STRIP);
-
- for (int a = 0; a < nu->pntsu; a++, bp++) {
- glVertex3fv(bp->vec);
- }
-
- glEnd();
- }
-
- glColor3ub(0, 0, 0);
-}
-
-static void editnurb_draw_active_nurbs(Nurb *nu)
-{
- UI_ThemeColor(TH_ACTIVE_SPLINE);
- glLineWidth(2);
-
- glBegin(GL_LINES);
- BPoint *bp = nu->bp;
- for (int b = 0; b < nu->pntsv; b++) {
- BPoint *bp1 = bp;
- bp++;
-
- for (int a = nu->pntsu - 1; a > 0; a--, bp++) {
- if (bp->hide == 0 && bp1->hide == 0) {
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
- }
- bp1 = bp;
- }
- }
-
- if (nu->pntsv > 1) { /* surface */
-
- int ofs = nu->pntsu;
- for (int b = 0; b < nu->pntsu; b++) {
- BPoint *bp1 = nu->bp + b;
- bp = bp1 + ofs;
- for (int a = nu->pntsv - 1; a > 0; a--, bp += ofs) {
- if (bp->hide == 0 && bp1->hide == 0) {
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
- }
- bp1 = bp;
- }
- }
- }
-
- glEnd();
-
- glColor3ub(0, 0, 0);
-}
-
-static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
-{
- BPoint *bp, *bp1;
- int a, b;
- Curve *cu = ob->data;
-
- int index = 0;
- Nurb *nu = nurb;
- while (nu) {
- if (nu->hide == 0) {
- switch (nu->type) {
- case CU_POLY:
- if (!sel && index == cu->actnu) {
- /* we should draw active spline highlight below everything */
- editnurb_draw_active_poly(nu);
- }
-
- glLineWidth(1);
-
- UI_ThemeColor(TH_NURB_ULINE);
- bp = nu->bp;
- for (b = 0; b < nu->pntsv; b++) {
- if (nu->flagu & 1) glBegin(GL_LINE_LOOP);
- else glBegin(GL_LINE_STRIP);
-
- for (a = 0; a < nu->pntsu; a++, bp++) {
- glVertex3fv(bp->vec);
- }
-
- glEnd();
- }
- break;
- case CU_NURBS:
- if (!sel && index == cu->actnu) {
- /* we should draw active spline highlight below everything */
- editnurb_draw_active_nurbs(nu);
- }
-
- glLineWidth(1);
-
- glBegin(GL_LINES);
-
- bp = nu->bp;
- for (b = 0; b < nu->pntsv; b++) {
- bp1 = bp;
- bp++;
- for (a = nu->pntsu - 1; a > 0; a--, bp++) {
- if (bp->hide == 0 && bp1->hide == 0) {
- if (sel) {
- if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) {
- UI_ThemeColor(TH_NURB_SEL_ULINE);
-
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
- }
- }
- else {
- if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) {
- /* pass */
- }
- else {
- UI_ThemeColor(TH_NURB_ULINE);
-
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
- }
- }
- }
- bp1 = bp;
- }
- }
-
- if (nu->pntsv > 1) { /* surface */
- int ofs = nu->pntsu;
- for (b = 0; b < nu->pntsu; b++) {
- bp1 = nu->bp + b;
- bp = bp1 + ofs;
- for (a = nu->pntsv - 1; a > 0; a--, bp += ofs) {
- if (bp->hide == 0 && bp1->hide == 0) {
- if (sel) {
- if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) {
- UI_ThemeColor(TH_NURB_SEL_VLINE);
-
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
- }
- }
- else {
- if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) {
- /* pass */
- }
- else {
- UI_ThemeColor(TH_NURB_VLINE);
-
- glVertex3fv(bp->vec);
- glVertex3fv(bp1->vec);
- }
- }
- }
- bp1 = bp;
- }
- }
- }
-
- glEnd();
- break;
- }
- }
-
- index++;
- nu = nu->next;
- }
-}
-
-static void draw_editnurb(
- Main *bmain, Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb,
- const char dt, const short dflag, const unsigned char ob_wire_col[4])
-{
- ToolSettings *ts = scene->toolsettings;
- Object *ob = base->object;
- Curve *cu = ob->data;
- Nurb *nu;
- const void *vert = BKE_curve_vert_active_get(cu);
- const bool hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0;
- unsigned char wire_col[3];
-
- /* DispList */
- UI_GetThemeColor3ubv(TH_WIRE_EDIT, wire_col);
- glColor3ubv(wire_col);
-
- drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
-
- /* for shadows only show solid faces */
- if (v3d->flag2 & V3D_RENDER_SHADOW)
- return;
-
- if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
-
- /* first non-selected and active handles */
- int index = 0;
- for (nu = nurb; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- if (index == cu->actnu && !hide_handles)
- drawhandlesN_active(nu);
- drawhandlesN(nu, 0, hide_handles);
- }
- index++;
- }
- draw_editnurb_splines(ob, nurb, false);
- draw_editnurb_splines(ob, nurb, true);
- /* selected handles */
- for (nu = nurb; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER && (cu->drawflag & CU_HIDE_HANDLES) == 0)
- drawhandlesN(nu, 1, hide_handles);
- drawvertsN(nu, 0, hide_handles, NULL);
- }
-
- if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
-
- glColor3ubv(wire_col);
-
- /* direction vectors for 3d curve paths
- * when at its lowest, don't render normals */
- if ((cu->flag & CU_3D) && (ts->normalsize > 0.0015f) && (cu->drawflag & CU_HIDE_NORMALS) == 0) {
- BevList *bl;
- glLineWidth(1.0f);
- for (bl = ob->curve_cache->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) {
- BevPoint *bevp = bl->bevpoints;
- int nr = bl->nr;
- int skip = nu->resolu / 16;
-
- while (nr-- > 0) { /* accounts for empty bevel lists */
- const float fac = bevp->radius * ts->normalsize;
- float vec_a[3]; /* Offset perpendicular to the curve */
- float vec_b[3]; /* Delta along the curve */
-
- vec_a[0] = fac;
- vec_a[1] = 0.0f;
- vec_a[2] = 0.0f;
-
- mul_qt_v3(bevp->quat, vec_a);
- madd_v3_v3fl(vec_a, bevp->dir, -fac);
-
- reflect_v3_v3v3(vec_b, vec_a, bevp->dir);
- negate_v3(vec_b);
-
- add_v3_v3(vec_a, bevp->vec);
- add_v3_v3(vec_b, bevp->vec);
-
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec_a);
- glVertex3fv(bevp->vec);
- glVertex3fv(vec_b);
- glEnd();
-
- bevp += skip + 1;
- nr -= skip;
- }
- }
- }
-
- if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
-
- for (nu = nurb; nu; nu = nu->next) {
- drawvertsN(nu, 1, hide_handles, vert);
- }
-
- if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
-}
-
-static void draw_editfont_textcurs(RegionView3D *rv3d, float textcurs[4][2])
-{
- cpack(0);
- ED_view3d_polygon_offset(rv3d, -1.0);
- set_inverted_drawing(1);
- glBegin(GL_QUADS);
- glVertex2fv(textcurs[0]);
- glVertex2fv(textcurs[1]);
- glVertex2fv(textcurs[2]);
- glVertex2fv(textcurs[3]);
- glEnd();
- set_inverted_drawing(0);
- ED_view3d_polygon_offset(rv3d, 0.0);
-}
-
-static void draw_editfont(
- Main *bmain, Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
- const char dt, const short dflag, const unsigned char ob_wire_col[4])
-{
- Object *ob = base->object;
- Curve *cu = ob->data;
- EditFont *ef = cu->editfont;
- float vec1[3], vec2[3];
-
- draw_editfont_textcurs(rv3d, ef->textcurs);
-
- if (cu->flag & CU_FAST) {
- cpack(0xFFFFFF);
- set_inverted_drawing(1);
- drawDispList(bmain, scene, v3d, rv3d, base, OB_WIRE, dflag, ob_wire_col);
- set_inverted_drawing(0);
- }
- else {
- drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
- }
-
- if (cu->linewidth != 0.0f) {
- UI_ThemeColor(TH_WIRE_EDIT);
- copy_v3_v3(vec1, ob->orig);
- copy_v3_v3(vec2, ob->orig);
- vec1[0] += cu->linewidth;
- vec2[0] += cu->linewidth;
- vec1[1] += cu->linedist * cu->fsize;
- vec2[1] -= cu->lines * cu->linedist * cu->fsize;
- setlinestyle(3);
- glBegin(GL_LINES);
- glVertex2fv(vec1);
- glVertex2fv(vec2);
- glEnd();
- setlinestyle(0);
- }
-
- setlinestyle(3);
- for (int i = 0; i < cu->totbox; i++) {
- if (cu->tb[i].w != 0.0f) {
- UI_ThemeColor(i == (cu->actbox - 1) ? TH_ACTIVE : TH_WIRE);
- vec1[0] = cu->xof + cu->tb[i].x;
- vec1[1] = cu->yof + cu->tb[i].y + cu->fsize;
- vec1[2] = 0.001;
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec1);
- vec1[0] += cu->tb[i].w;
- glVertex3fv(vec1);
- vec1[1] -= cu->tb[i].h;
- glVertex3fv(vec1);
- vec1[0] -= cu->tb[i].w;
- glVertex3fv(vec1);
- vec1[1] += cu->tb[i].h;
- glVertex3fv(vec1);
- glEnd();
- }
- }
- setlinestyle(0);
-
-
- if (ef->selboxes && ef->selboxes_len) {
- float selboxw;
-
- cpack(0xffffff);
- set_inverted_drawing(1);
- for (int i = 0; i < ef->selboxes_len; i++) {
- EditFontSelBox *sb = &ef->selboxes[i];
- float tvec[3];
-
- if (i + 1 != ef->selboxes_len) {
- if (ef->selboxes[i + 1].y == sb->y)
- selboxw = ef->selboxes[i + 1].x - sb->x;
- else
- selboxw = sb->w;
- }
- else {
- selboxw = sb->w;
- }
-
- /* fill in xy below */
- tvec[2] = 0.001;
-
- glBegin(GL_QUADS);
-
- if (sb->rot == 0.0f) {
- copy_v2_fl2(tvec, sb->x, sb->y);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, sb->x + selboxw, sb->y);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, sb->x + selboxw, sb->y + sb->h);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, sb->x, sb->y + sb->h);
- glVertex3fv(tvec);
- }
- else {
- float mat[2][2];
-
- angle_to_mat2(mat, sb->rot);
-
- copy_v2_fl2(tvec, sb->x, sb->y);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, selboxw, 0.0f);
- mul_m2v2(mat, tvec);
- add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, selboxw, sb->h);
- mul_m2v2(mat, tvec);
- add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, 0.0f, sb->h);
- mul_m2v2(mat, tvec);
- add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
- }
-
- glEnd();
- }
- set_inverted_drawing(0);
- }
-}
-
-/* draw a sphere for use as an empty drawtype */
-static void draw_empty_sphere(float size)
-{
- static GLuint displist = 0;
-
- if (displist == 0) {
- GLUquadricObj *qobj;
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
-
- glPushMatrix();
-
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
- gluDisk(qobj, 0.0, 1, 16, 1);
-
- glRotatef(90, 0, 1, 0);
- gluDisk(qobj, 0.0, 1, 16, 1);
-
- glRotatef(90, 1, 0, 0);
- gluDisk(qobj, 0.0, 1, 16, 1);
-
- gluDeleteQuadric(qobj);
-
- glPopMatrix();
- glEndList();
- }
-
- glScalef(size, size, size);
- glCallList(displist);
- glScalef(1.0f / size, 1.0f / size, 1.0f / size);
-}
-
-/* draw a cone for use as an empty drawtype */
-static void draw_empty_cone(float size)
-{
- const float radius = size;
-
- GLUquadricObj *qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
-
- glPushMatrix();
-
- glScalef(radius, size * 2.0f, radius);
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1);
-
- glPopMatrix();
-
- gluDeleteQuadric(qobj);
-}
-
-static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start)
-{
- float vec[3], vx[3], vy[3];
- const float tot_inv = 1.0f / (float)CIRCLE_RESOL;
- int a;
- bool inverse = false;
- float x, y, fac;
-
- if (start < 0) {
- inverse = true;
- start = -start;
- }
-
- mul_v3_v3fl(vx, tmat[0], rad);
- mul_v3_v3fl(vy, tmat[1], rad);
-
- glBegin(GL_LINE_STRIP);
-
- if (inverse == 0) {
- copy_v3_v3(vec, cent);
- glVertex3fv(vec);
-
- for (a = 0; a < CIRCLE_RESOL; a++) {
- if (a + start >= CIRCLE_RESOL)
- start = -a + 1;
-
- fac = (float)a * tot_inv;
- x = sinval[a + start] * fac;
- y = cosval[a + start] * fac;
-
- vec[0] = cent[0] + (x * vx[0] + y * vy[0]);
- vec[1] = cent[1] + (x * vx[1] + y * vy[1]);
- vec[2] = cent[2] + (x * vx[2] + y * vy[2]);
-
- glVertex3fv(vec);
- }
- }
- else {
- fac = (float)(CIRCLE_RESOL - 1) * tot_inv;
- x = sinval[start] * fac;
- y = cosval[start] * fac;
-
- vec[0] = cent[0] + (x * vx[0] + y * vy[0]);
- vec[1] = cent[1] + (x * vx[1] + y * vy[1]);
- vec[2] = cent[2] + (x * vx[2] + y * vy[2]);
-
- glVertex3fv(vec);
-
- for (a = 0; a < CIRCLE_RESOL; a++) {
- if (a + start >= CIRCLE_RESOL)
- start = -a + 1;
-
- fac = (float)(-a + (CIRCLE_RESOL - 1)) * tot_inv;
- x = sinval[a + start] * fac;
- y = cosval[a + start] * fac;
-
- vec[0] = cent[0] + (x * vx[0] + y * vy[0]);
- vec[1] = cent[1] + (x * vx[1] + y * vy[1]);
- vec[2] = cent[2] + (x * vx[2] + y * vy[2]);
- glVertex3fv(vec);
- }
- }
-
- glEnd();
-}
-
-/* draws a circle on x-z plane given the scaling of the circle, assuming that
- * all required matrices have been set (used for drawing empties) */
-static void drawcircle_size(float size)
-{
- glBegin(GL_LINE_LOOP);
-
- /* coordinates are: cos(degrees * 11.25) = x, sin(degrees * 11.25) = y, 0.0f = z */
- for (short degrees = 0; degrees < CIRCLE_RESOL; degrees++) {
- float x = cosval[degrees];
- float y = sinval[degrees];
-
- glVertex3f(x * size, 0.0f, y * size);
- }
-
- glEnd();
-
-}
-
-/* needs fixing if non-identity matrix used */
-static void drawtube(const float vec[3], float radius, float height, float tmat[4][4])
-{
- float cur[3];
- drawcircball(GL_LINE_LOOP, vec, radius, tmat);
-
- copy_v3_v3(cur, vec);
- cur[2] += height;
-
- drawcircball(GL_LINE_LOOP, cur, radius, tmat);
-
- glBegin(GL_LINES);
- glVertex3f(vec[0] + radius, vec[1], vec[2]);
- glVertex3f(cur[0] + radius, cur[1], cur[2]);
- glVertex3f(vec[0] - radius, vec[1], vec[2]);
- glVertex3f(cur[0] - radius, cur[1], cur[2]);
- glVertex3f(vec[0], vec[1] + radius, vec[2]);
- glVertex3f(cur[0], cur[1] + radius, cur[2]);
- glVertex3f(vec[0], vec[1] - radius, vec[2]);
- glVertex3f(cur[0], cur[1] - radius, cur[2]);
- glEnd();
-}
-
-/* needs fixing if non-identity matrix used */
-static void drawcone(const float vec[3], float radius, float height, float tmat[4][4])
-{
- float cur[3];
-
- copy_v3_v3(cur, vec);
- cur[2] += height;
-
- drawcircball(GL_LINE_LOOP, cur, radius, tmat);
-
- glBegin(GL_LINES);
- glVertex3f(vec[0], vec[1], vec[2]);
- glVertex3f(cur[0] + radius, cur[1], cur[2]);
- glVertex3f(vec[0], vec[1], vec[2]);
- glVertex3f(cur[0] - radius, cur[1], cur[2]);
- glVertex3f(vec[0], vec[1], vec[2]);
- glVertex3f(cur[0], cur[1] + radius, cur[2]);
- glVertex3f(vec[0], vec[1], vec[2]);
- glVertex3f(cur[0], cur[1] - radius, cur[2]);
- glEnd();
-}
-
-/* return true if nothing was drawn */
-static bool drawmball(
- Main *bmain, Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
- const char dt, const short dflag, const unsigned char ob_wire_col[4])
-{
- Object *ob = base->object;
- MetaElem *ml;
- float imat[4][4];
- int code = 1;
-
- MetaBall *mb = ob->data;
-
- if (mb->editelems) {
- if ((G.f & G_PICKSEL) == 0) {
- unsigned char wire_col[4];
- UI_GetThemeColor4ubv(TH_WIRE_EDIT, wire_col);
- glColor3ubv(wire_col);
-
- drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, wire_col);
- }
- ml = mb->editelems->first;
- }
- else {
- if ((base->flag & OB_FROMDUPLI) == 0) {
- drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
- }
- ml = mb->elems.first;
- }
-
- if (ml == NULL) {
- return true;
- }
-
- if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
- return false;
- }
-
- invert_m4_m4(imat, rv3d->viewmatob);
- normalize_v3(imat[0]);
- normalize_v3(imat[1]);
-
- if (mb->editelems == NULL) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(ob_wire_col);
- }
- }
-
- glLineWidth(1.0f);
-
- while (ml) {
- /* draw radius */
- if (mb->editelems) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if ((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) cpack(0xA0A0F0);
- else cpack(0x3030A0);
- }
-
- if (G.f & G_PICKSEL) {
- ml->selcol1 = code;
- GPU_select_load_id(code++);
- }
- }
- drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat);
-
- /* draw stiffness */
- if (mb->editelems) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- if ((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) cpack(0xA0F0A0);
- else cpack(0x30A030);
- }
-
- if (G.f & G_PICKSEL) {
- ml->selcol2 = code;
- GPU_select_load_id(code++);
- }
- drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad * atanf(ml->s) / (float)M_PI_2, imat);
- }
-
- ml = ml->next;
- }
- return false;
-}
-
-static void draw_forcefield(Object *ob, RegionView3D *rv3d,
- const short dflag, const unsigned char ob_wire_col[4])
-{
- PartDeflect *pd = ob->pd;
- float imat[4][4], tmat[4][4];
- float vec[3] = {0.0, 0.0, 0.0};
- /* scale size of circle etc with the empty drawsize */
- const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f;
-
- /* calculus here, is reused in PFIELD_FORCE */
- invert_m4_m4(imat, rv3d->viewmatob);
-#if 0
- normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */
- normalize_v3(imat[1]);
-#endif
-
- if (pd->forcefield == PFIELD_WIND) {
- float force_val = pd->f_strength;
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
- }
-
- unit_m4(tmat);
- force_val *= 0.1f;
- drawcircball(GL_LINE_LOOP, vec, size, tmat);
- vec[2] = 0.5f * force_val;
- drawcircball(GL_LINE_LOOP, vec, size, tmat);
- vec[2] = 1.0f * force_val;
- drawcircball(GL_LINE_LOOP, vec, size, tmat);
- vec[2] = 1.5f * force_val;
- drawcircball(GL_LINE_LOOP, vec, size, tmat);
- vec[2] = 0.0f; /* reset vec for max dist circle */
-
- }
- else if (pd->forcefield == PFIELD_FORCE) {
- float ffall_val = pd->f_power;
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
- drawcircball(GL_LINE_LOOP, vec, size, imat);
- if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.9f - 0.4f / powf(1.5f, ffall_val));
- drawcircball(GL_LINE_LOOP, vec, size * 1.5f, imat);
- if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.9f - 0.4f / powf(2.0f, ffall_val));
- drawcircball(GL_LINE_LOOP, vec, size * 2.0f, imat);
- }
- else if (pd->forcefield == PFIELD_VORTEX) {
- float force_val = pd->f_strength;
-
- unit_m4(tmat);
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.7f);
- }
-
- if (force_val < 0) {
- drawspiral(vec, size, tmat, 1);
- drawspiral(vec, size, tmat, 16);
- }
- else {
- drawspiral(vec, size, tmat, -1);
- drawspiral(vec, size, tmat, -16);
- }
- }
- else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) {
- Curve *cu = ob->data;
- if ((cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) {
- float guidevec1[4], guidevec2[3];
- float mindist = pd->f_strength;
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
- }
-
- /* path end */
- setlinestyle(3);
- where_on_path(ob, 1.0f, guidevec1, guidevec2, NULL, NULL, NULL);
- drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
-
- /* path beginning */
- setlinestyle(0);
- where_on_path(ob, 0.0f, guidevec1, guidevec2, NULL, NULL, NULL);
- drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
-
- copy_v3_v3(vec, guidevec1); /* max center */
- }
- }
-
- setlinestyle(3);
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f);
- }
-
- if (pd->falloff == PFIELD_FALL_SPHERE) {
- /* as last, guide curve alters it */
- if (pd->flag & PFIELD_USEMAX)
- drawcircball(GL_LINE_LOOP, vec, pd->maxdist, imat);
-
- if (pd->flag & PFIELD_USEMIN)
- drawcircball(GL_LINE_LOOP, vec, pd->mindist, imat);
- }
- else if (pd->falloff == PFIELD_FALL_TUBE) {
- float radius, distance;
-
- unit_m4(tmat);
-
- vec[0] = vec[1] = 0.0f;
- radius = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f;
- distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
- vec[2] = distance;
- distance = (pd->flag & PFIELD_POSZ) ? -distance : -2.0f * distance;
-
- if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR))
- drawtube(vec, radius, distance, tmat);
-
- radius = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f;
- distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
- vec[2] = distance;
- distance = (pd->flag & PFIELD_POSZ) ? -distance : -2.0f * distance;
-
- if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR))
- drawtube(vec, radius, distance, tmat);
- }
- else if (pd->falloff == PFIELD_FALL_CONE) {
- float radius, distance;
-
- unit_m4(tmat);
-
- radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
- distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
-
- if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
- drawcone(vec, distance * sinf(radius), distance * cosf(radius), tmat);
- if ((pd->flag & PFIELD_POSZ) == 0)
- drawcone(vec, distance * sinf(radius), -distance * cosf(radius), tmat);
- }
-
- radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
- distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
-
- if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
- drawcone(vec, distance * sinf(radius), distance * cosf(radius), tmat);
- if ((pd->flag & PFIELD_POSZ) == 0)
- drawcone(vec, distance * sinf(radius), -distance * cosf(radius), tmat);
- }
- }
- setlinestyle(0);
-}
-
-static void draw_box(const float vec[8][3], bool solid)
-{
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, vec);
-
- if (solid) {
- const GLubyte indices[24] = {0, 1, 2, 3, 7, 6, 5, 4, 4, 5, 1, 0, 3, 2, 6, 7, 3, 7, 4, 0, 1, 5, 6, 2};
- glDrawRangeElements(GL_QUADS, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
- }
- else {
- const GLubyte indices[24] = {0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 4, 5, 5, 6, 6, 7, 7, 4, 1, 5, 2, 6, 3, 7};
- glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
-}
-
-static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
-{
- float size[3], cent[3];
- GLUquadricObj *qobj = gluNewQuadric();
-
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
-
- BKE_boundbox_calc_size_aabb(bb, size);
-
- if (around_origin) {
- zero_v3(cent);
- }
- else {
- BKE_boundbox_calc_center_aabb(bb, cent);
- }
-
- glPushMatrix();
- if (type == OB_BOUND_SPHERE) {
- float scale = MAX3(size[0], size[1], size[2]);
- glTranslate3fv(cent);
- glScalef(scale, scale, scale);
- gluSphere(qobj, 1.0, 8, 5);
- }
- else if (type == OB_BOUND_CYLINDER) {
- float radius = size[0] > size[1] ? size[0] : size[1];
- glTranslatef(cent[0], cent[1], cent[2] - size[2]);
- glScalef(radius, radius, 2.0f * size[2]);
- gluCylinder(qobj, 1.0, 1.0, 1.0, 8, 1);
- }
- else if (type == OB_BOUND_CONE) {
- float radius = size[0] > size[1] ? size[0] : size[1];
- glTranslatef(cent[0], cent[1], cent[2] - size[2]);
- glScalef(radius, radius, 2.0f * size[2]);
- gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1);
- }
- else if (type == OB_BOUND_CAPSULE) {
- float radius = size[0] > size[1] ? size[0] : size[1];
- float length = size[2] > radius ? 2.0f * (size[2] - radius) : 0.0f;
- glTranslatef(cent[0], cent[1], cent[2] - length * 0.5f);
- gluCylinder(qobj, radius, radius, length, 8, 1);
- gluSphere(qobj, radius, 8, 4);
- glTranslatef(0.0, 0.0, length);
- gluSphere(qobj, radius, 8, 4);
- }
- glPopMatrix();
-
- gluDeleteQuadric(qobj);
-}
-
-static void draw_bounding_volume(Object *ob, char type)
-{
- BoundBox bb_local;
- BoundBox *bb = NULL;
-
- if (ob->type == OB_MESH) {
- bb = BKE_mesh_boundbox_get(ob);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
- bb = BKE_curve_boundbox_get(ob);
- }
- else if (ob->type == OB_MBALL) {
- if (BKE_mball_is_basis(ob)) {
- bb = ob->bb;
- }
- }
- else if (ob->type == OB_ARMATURE) {
- bb = BKE_armature_boundbox_get(ob);
- }
- else if (ob->type == OB_LATTICE) {
- bb = BKE_lattice_boundbox_get(ob);
- }
- else {
- const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
- bb = &bb_local;
- BKE_boundbox_init_from_minmax(bb, min, max);
- }
-
- if (bb == NULL)
- return;
-
- if (ob->gameflag & OB_BOUNDS) { /* bounds need to be drawn around origin for game engine */
-
- if (type == OB_BOUND_BOX) {
- float vec[8][3], size[3];
-
- BKE_boundbox_calc_size_aabb(bb, size);
-
- vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0];
- vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = +size[0];
- vec[0][1] = vec[1][1] = vec[4][1] = vec[5][1] = -size[1];
- vec[2][1] = vec[3][1] = vec[6][1] = vec[7][1] = +size[1];
- vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2];
- vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2];
-
- draw_box(vec, false);
- }
- else {
- draw_bb_quadric(bb, type, true);
- }
- }
- else {
- if (type == OB_BOUND_BOX)
- draw_box(bb->vec, false);
- else
- draw_bb_quadric(bb, type, false);
- }
-}
-
-static void drawtexspace(Object *ob)
-{
- float vec[8][3], loc[3], size[3];
-
- if (ob->type == OB_MESH) {
- BKE_mesh_texspace_get(ob->data, loc, NULL, size);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
- BKE_curve_texspace_get(ob->data, loc, NULL, size);
- }
- else if (ob->type == OB_MBALL) {
- MetaBall *mb = ob->data;
- copy_v3_v3(size, mb->size);
- copy_v3_v3(loc, mb->loc);
- }
- else {
- return;
- }
-
- vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = loc[0] - size[0];
- vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = loc[0] + size[0];
-
- vec[0][1] = vec[1][1] = vec[4][1] = vec[5][1] = loc[1] - size[1];
- vec[2][1] = vec[3][1] = vec[6][1] = vec[7][1] = loc[1] + size[1];
-
- vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = loc[2] - size[2];
- vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = loc[2] + size[2];
-
- setlinestyle(2);
-
- draw_box(vec, false);
-
- setlinestyle(0);
-}
-
-/* draws wire outline */
-static void draw_object_selected_outline(
- Main *bmain, Scene *scene, View3D *v3d, ARegion *ar, Base *base,
- const unsigned char ob_wire_col[4])
-{
- RegionView3D *rv3d = ar->regiondata;
- Object *ob = base->object;
-
- glDepthMask(0);
-
- if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
- bool has_faces = false;
-
-#ifdef SEQUENCER_DAG_WORKAROUND
- ensure_curve_cache(bmain, scene, ob);
-#endif
-
- DerivedMesh *dm = ob->derivedFinal;
- if (dm) {
- DM_update_materials(dm, ob);
- }
-
- if (dm) {
- has_faces = (dm->getNumPolys(dm) != 0);
- }
- else {
- has_faces = BKE_displist_has_faces(&ob->curve_cache->disp);
- }
-
- if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->bb)) {
- glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
- if (dm) {
- draw_mesh_object_outline(v3d, ob, dm);
- }
- else {
- /* only draw 'solid' parts of the display list as wire. */
- drawDispListwire_ex(&ob->curve_cache->disp, (DL_INDEX3 | DL_INDEX4 | DL_SURF));
- }
- }
- }
- else if (ob->type == OB_MBALL) {
- if (BKE_mball_is_basis(ob)) {
- if ((base->flag & OB_FROMDUPLI) == 0) {
- glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
- drawDispListwire(&ob->curve_cache->disp, ob->type);
- }
- }
- }
- else if (ob->type == OB_ARMATURE) {
- if (!(ob->mode & OB_MODE_POSE && base == scene->basact)) {
- glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
- draw_armature(scene, v3d, ar, base, OB_WIRE, 0, ob_wire_col, true);
- }
- }
-
- glDepthMask(1);
-}
-
-static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4])
-{
- if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) {
-
- if (scene->obedit == ob) {
- UI_ThemeColor(TH_WIRE_EDIT);
- }
- else {
- glColor3ubv(ob_wire_col);
- }
-
- ED_view3d_polygon_offset(rv3d, 1.0);
- glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
- glLineWidth(1);
-
- if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
- if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
-
- if (ob->derivedFinal) {
- drawCurveDMWired(ob);
- }
- else {
- drawDispListwire(&ob->curve_cache->disp, ob->type);
- }
- }
- }
- else if (ob->type == OB_MBALL) {
- if (BKE_mball_is_basis(ob)) {
- drawDispListwire(&ob->curve_cache->disp, ob->type);
- }
- }
-
- glDepthMask(1);
- ED_view3d_polygon_offset(rv3d, 0.0);
- }
-}
-
-/* should be called in view space */
-static void draw_hooks(Object *ob)
-{
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Hook) {
- HookModifierData *hmd = (HookModifierData *) md;
- float vec[3];
-
- mul_v3_m4v3(vec, ob->obmat, hmd->cent);
-
- if (hmd->object) {
- setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(hmd->object->obmat[3]);
- glVertex3fv(vec);
- glEnd();
- setlinestyle(0);
- }
-
- glPointSize(3.0);
- glBegin(GL_POINTS);
- glVertex3fv(vec);
- glEnd();
- }
- }
-}
-
-static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data,
- const short dflag, const unsigned char ob_wire_col[4])
-{
- const char *axis_str[3] = {"px", "py", "pz"};
- float mat[4][4];
-
- eul_to_mat4(mat, &data->axX);
- glLineWidth(4.0f);
- setlinestyle(2);
- for (int axis = 0; axis < 3; axis++) {
- float dir[3] = {0, 0, 0};
- float v[3];
-
- copy_v3_v3(v, &data->pivX);
-
- dir[axis] = 1.0f;
- glBegin(GL_LINES);
- mul_m4_v3(mat, dir);
- add_v3_v3(v, dir);
- glVertex3fv(&data->pivX);
- glVertex3fv(v);
- glEnd();
-
- /* when const color is set wirecolor is NULL - we could get the current color but
- * with selection and group instancing its not needed to draw the text */
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- view3d_cached_text_draw_add(v, axis_str[axis], 2, 0, V3D_CACHE_TEXT_ASCII, ob_wire_col);
- }
- }
-
- setlinestyle(0);
-}
-
-static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_wire_col[4])
-{
- Object *ob = base->object;
- int colindex = 0;
- const bool is_edit = (ob->mode & OB_MODE_EDIT) != 0;
- /* confusing logic here, there are 2 methods of setting the color
- * 'colortab[colindex]' and 'theme_id', colindex overrides theme_id.
- *
- * note: no theme yet for 'colindex' */
- int theme_id = is_edit ? TH_WIRE_EDIT : TH_WIRE;
- int theme_shade = 0;
-
- if ((scene->obedit == NULL) &&
- (G.moving & G_TRANSFORM_OBJ) &&
- (base->flag & (SELECT + BA_WAS_SEL)))
- {
- theme_id = TH_TRANSFORM;
- }
- else {
- /* Sets the 'colindex' */
- if (ID_IS_LINKED(ob)) {
- colindex = (base->flag & (SELECT + BA_WAS_SEL)) ? 2 : 1;
- }
- /* Sets the 'theme_id' or fallback to wire */
- else {
- if (ob->flag & OB_FROMGROUP) {
- if (base->flag & (SELECT + BA_WAS_SEL)) {
- /* uses darker active color for non-active + selected */
- theme_id = TH_GROUP_ACTIVE;
-
- if (scene->basact != base) {
- theme_shade = -32;
- }
- }
- else {
- theme_id = TH_GROUP;
- }
- }
- else {
- if (base->flag & (SELECT + BA_WAS_SEL)) {
- theme_id = scene->basact == base ? TH_ACTIVE : TH_SELECT;
- }
- else {
- if (ob->type == OB_LAMP) theme_id = TH_LAMP;
- else if (ob->type == OB_SPEAKER) theme_id = TH_SPEAKER;
- else if (ob->type == OB_CAMERA) theme_id = TH_CAMERA;
- else if (ob->type == OB_EMPTY) theme_id = TH_EMPTY;
- /* fallback to TH_WIRE */
- }
- }
- }
- }
-
- /* finally set the color */
- if (colindex == 0) {
- if (theme_shade == 0) UI_GetThemeColor3ubv(theme_id, r_ob_wire_col);
- else UI_GetThemeColorShade3ubv(theme_id, theme_shade, r_ob_wire_col);
- }
- else {
- cpack_cpy_3ub(r_ob_wire_col, colortab[colindex]);
- }
-
- /* no reason to use this but some functions take col[4] */
- r_ob_wire_col[3] = 255;
-}
-
-static void draw_object_matcap_check(View3D *v3d, Object *ob)
-{
- /* fixed rule, active object draws as matcap */
- BLI_assert((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) == 0);
- (void)ob;
-
- if (v3d->defmaterial == NULL) {
- extern Material defmaterial;
-
- v3d->defmaterial = MEM_mallocN(sizeof(Material), "matcap material");
- *(v3d->defmaterial) = defmaterial;
- BLI_listbase_clear(&v3d->defmaterial->gpumaterial);
- v3d->defmaterial->preview = NULL;
- }
- /* first time users */
- if (v3d->matcap_icon < ICON_MATCAP_01 ||
- v3d->matcap_icon > ICON_MATCAP_24)
- {
- v3d->matcap_icon = ICON_MATCAP_01;
- }
-
- if (v3d->defmaterial->preview == NULL)
- v3d->defmaterial->preview = UI_icon_to_preview(v3d->matcap_icon);
-
- /* signal to all material checks, gets cleared below */
- v3d->flag2 |= V3D_SHOW_SOLID_MATCAP;
-}
-
-static void draw_rigidbody_shape(Object *ob)
-{
- BoundBox *bb = NULL;
- float size[3], vec[8][3];
-
- if (ob->type == OB_MESH) {
- bb = BKE_mesh_boundbox_get(ob);
- }
-
- if (bb == NULL)
- return;
-
- switch (ob->rigidbody_object->shape) {
- case RB_SHAPE_BOX:
- BKE_boundbox_calc_size_aabb(bb, size);
-
- vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0];
- vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = +size[0];
- vec[0][1] = vec[1][1] = vec[4][1] = vec[5][1] = -size[1];
- vec[2][1] = vec[3][1] = vec[6][1] = vec[7][1] = +size[1];
- vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2];
- vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2];
-
- draw_box(vec, false);
- break;
- case RB_SHAPE_SPHERE:
- draw_bb_quadric(bb, OB_BOUND_SPHERE, true);
- break;
- case RB_SHAPE_CONE:
- draw_bb_quadric(bb, OB_BOUND_CONE, true);
- break;
- case RB_SHAPE_CYLINDER:
- draw_bb_quadric(bb, OB_BOUND_CYLINDER, true);
- break;
- case RB_SHAPE_CAPSULE:
- draw_bb_quadric(bb, OB_BOUND_CAPSULE, true);
- break;
- }
-}
-
-/**
- * main object drawing function, draws in selection
- * \param dflag (draw flag) can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET
- */
-void draw_object(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag)
-{
- ModifierData *md = NULL;
- Object *ob = base->object;
- Curve *cu;
- RegionView3D *rv3d = ar->regiondata;
- unsigned int col = 0;
- unsigned char _ob_wire_col[4]; /* dont initialize this */
- const unsigned char *ob_wire_col = NULL; /* dont initialize this, use NULL crashes as a way to find invalid use */
- bool zbufoff = false, is_paint = false, empty_object = false;
- const bool is_obact = (ob == OBACT);
- const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0;
- const bool is_picking = (G.f & G_PICKSEL) != 0;
- const bool has_particles = (ob->particlesystem.first != NULL);
- bool skip_object = false; /* Draw particles but not their emitter object. */
- SmokeModifierData *smd = NULL;
-
- if (ob != scene->obedit) {
- if (ob->restrictflag & OB_RESTRICT_VIEW)
- return;
-
- if (render_override) {
- if (ob->restrictflag & OB_RESTRICT_RENDER)
- return;
-
- if (!has_particles && (ob->transflag & (OB_DUPLI & ~OB_DUPLIFRAMES)))
- return;
- }
- }
-
- if (has_particles) {
- /* XXX particles are not safe for simultaneous threaded render */
- if (G.is_rendering) {
- return;
- }
-
- if (ob->mode == OB_MODE_OBJECT) {
- ParticleSystem *psys;
-
- skip_object = render_override;
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- /* Once we have found a psys which renders its emitter object, we are done. */
- if (psys->part->draw & PART_DRAW_EMITTER) {
- skip_object = false;
- break;
- }
- }
- }
- }
-
- if (((base->flag & OB_FROMDUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime)))
- {
- smd = (SmokeModifierData *)md;
-
- if (smd->domain) {
- if (!v3d->transp && (dflag & DRAW_PICKING) == 0) {
- if (!v3d->xray && !(ob->dtx & OB_DRAWXRAY)) {
- /* object has already been drawn so skip drawing it */
- ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
- return;
- }
- else if (v3d->xray) {
- /* object has already been drawn so skip drawing it */
- ED_view3d_after_add(&v3d->afterdraw_xraytransp, base, dflag);
- return;
- }
- }
- }
- }
-
-
- /* xray delay? */
- if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
- /* don't do xray in particle mode, need the z-buffer */
- if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
- /* xray and transp are set when it is drawing the 2nd/3rd pass */
- if (!v3d->xray && !v3d->transp && (ob->dtx & OB_DRAWXRAY) && !(ob->dtx & OB_DRAWTRANSP)) {
- ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag);
- return;
- }
-
- /* allow transp option for empty images */
- if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
- if (!v3d->xray && !v3d->transp && !(ob->dtx & OB_DRAWXRAY) && (ob->dtx & OB_DRAWTRANSP)) {
- ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
- return;
- }
- }
- }
- }
-
-
- /* -------------------------------------------------------------------- */
- /* no return after this point, otherwise leaks */
-
- /* only once set now, will be removed too, should become a global standard */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- /* reset here to avoid having to call all over */
- glLineWidth(1.0f);
-
- view3d_cached_text_draw_begin();
-
- /* draw motion paths (in view space) */
- if (ob->mpath && !render_override) {
- bAnimVizSettings *avs = &ob->avs;
-
- /* setup drawing environment for paths */
- draw_motion_paths_init(v3d, ar);
-
- /* draw motion path for object */
- draw_motion_path_instance(scene, ob, NULL, avs, ob->mpath);
-
- /* cleanup after drawing */
- draw_motion_paths_cleanup(v3d);
- }
-
- /* multiply view with object matrix.
- * local viewmat and persmat, to calculate projections */
- ED_view3d_init_mats_rv3d_gl(ob, rv3d);
-
- /* which wire color */
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
-
- ED_view3d_project_base(ar, base);
-
- draw_object_wire_color(scene, base, _ob_wire_col);
- ob_wire_col = _ob_wire_col;
-
- glColor3ubv(ob_wire_col);
- }
-
- /* maximum drawtype */
- char dt = v3d->drawtype;
- if (dt == OB_RENDER) dt = v3d->prev_drawtype;
- dt = MIN2(dt, ob->dt);
- if (v3d->zbuf == 0 && dt > OB_WIRE) dt = OB_WIRE;
- short dtx = 0;
-
-
- /* faceselect exception: also draw solid when (dt == wire), except in editmode */
- if (is_obact) {
- if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) {
- if (ob->type == OB_MESH) {
- if (dt < OB_SOLID) {
- zbufoff = true;
- dt = OB_SOLID;
- }
-
- if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
- dt = OB_PAINT;
- }
-
- is_paint = true;
- glEnable(GL_DEPTH_TEST);
- }
- }
- }
-
- /* matcap check - only when not painting color */
- if ((v3d->flag2 & V3D_SOLID_MATCAP) &&
- (dt == OB_SOLID) &&
- (is_paint == false && is_picking == false) &&
- ((v3d->flag2 & V3D_RENDER_SHADOW) == 0))
- {
- draw_object_matcap_check(v3d, ob);
- }
-
- /* draw-extra supported for boundbox drawmode too */
- if (dt >= OB_BOUNDBOX) {
- dtx = ob->dtx;
- if (ob->mode & OB_MODE_EDIT) {
- /* the only 2 extra drawtypes alowed in editmode */
- dtx = dtx & (OB_DRAWWIRE | OB_TEXSPACE);
- }
- }
-
- if (!skip_object) {
- /* draw outline for selected objects, mesh does itself */
- if ((v3d->flag & V3D_SELECT_OUTLINE) && !render_override && ob->type != OB_MESH) {
- if (dt > OB_WIRE && (ob->mode & OB_MODE_EDIT) == 0 && (dflag & DRAW_SCENESET) == 0) {
- if (!(ob->dtx & OB_DRAWWIRE) && (ob->flag & SELECT) && !(dflag & (DRAW_PICKING | DRAW_CONSTCOLOR))) {
- draw_object_selected_outline(bmain, scene, v3d, ar, base, ob_wire_col);
- }
- }
- }
-
- switch (ob->type) {
- case OB_MESH:
- empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- /* mesh draws wire itself */
- dtx &= ~OB_DRAWWIRE;
- }
-
- break;
- case OB_FONT:
- cu = ob->data;
- if (cu->editfont) {
- draw_editfont(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
- }
- else if (dt == OB_BOUNDBOX) {
- if ((render_override && v3d->drawtype >= OB_WIRE) == 0) {
-#ifdef SEQUENCER_DAG_WORKAROUND
- ensure_curve_cache(bmain, scene, base->object);
-#endif
- draw_bounding_volume(ob, ob->boundtype);
- }
- }
- else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
- empty_object = drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
- }
-
- break;
- case OB_CURVE:
- case OB_SURF:
- cu = ob->data;
-
- if (cu->editnurb) {
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- draw_editnurb(bmain, scene, v3d, rv3d, base, nurbs->first, dt, dflag, ob_wire_col);
- }
- else if (dt == OB_BOUNDBOX) {
- if ((render_override && (v3d->drawtype >= OB_WIRE)) == 0) {
-#ifdef SEQUENCER_DAG_WORKAROUND
- ensure_curve_cache(bmain, scene, base->object);
-#endif
- draw_bounding_volume(ob, ob->boundtype);
- }
- }
- else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
- empty_object = drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
- }
- break;
- case OB_MBALL:
- {
- MetaBall *mb = ob->data;
-
- if (mb->editelems)
- drawmball(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
- else if (dt == OB_BOUNDBOX) {
- if ((render_override && (v3d->drawtype >= OB_WIRE)) == 0) {
-#ifdef SEQUENCER_DAG_WORKAROUND
- ensure_curve_cache(bmain, scene, base->object);
-#endif
- draw_bounding_volume(ob, ob->boundtype);
- }
- }
- else
- empty_object = drawmball(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
- break;
- }
- case OB_EMPTY:
- if (!render_override) {
- if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
- draw_empty_image(ob, dflag, ob_wire_col, v3d->multiview_eye);
- }
- else {
- drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype);
- }
- }
- break;
- case OB_LAMP:
- if (!render_override) {
- drawlamp(v3d, rv3d, base, dt, dflag, ob_wire_col, is_obact);
- }
- break;
- case OB_CAMERA:
- if (!render_override ||
- (rv3d->persp == RV3D_CAMOB && v3d->camera == ob)) /* special exception for active camera */
- {
- drawcamera(scene, v3d, rv3d, base, dflag, ob_wire_col);
- }
- break;
- case OB_SPEAKER:
- if (!render_override)
- drawspeaker(scene, v3d, rv3d, ob, dflag);
- break;
- case OB_LATTICE:
- if (!render_override) {
- /* Do not allow boundbox in edit nor pose mode! */
- if ((dt == OB_BOUNDBOX) && (ob->mode & OB_MODE_EDIT))
- dt = OB_WIRE;
- if (dt == OB_BOUNDBOX) {
- draw_bounding_volume(ob, ob->boundtype);
- }
- else {
-#ifdef SEQUENCER_DAG_WORKAROUND
- ensure_curve_cache(bmain, scene, ob);
-#endif
- drawlattice(v3d, ob);
- }
- }
- break;
- case OB_ARMATURE:
- if (!render_override) {
- /* Do not allow boundbox in edit nor pose mode! */
- if ((dt == OB_BOUNDBOX) && (ob->mode & (OB_MODE_EDIT | OB_MODE_POSE)))
- dt = OB_WIRE;
- if (dt == OB_BOUNDBOX) {
- draw_bounding_volume(ob, ob->boundtype);
- }
- else {
- glLineWidth(1.0f);
- empty_object = draw_armature(scene, v3d, ar, base, dt, dflag, ob_wire_col, false);
- }
- }
- break;
- default:
- if (!render_override) {
- drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS);
- }
- break;
- }
-
- if (!render_override) {
- if (ob->soft /*&& dflag & OB_SBMOTION*/) {
- float mrt[3][3], msc[3][3], mtr[3][3];
- SoftBody *sb = NULL;
- float tipw = 0.5f, tiph = 0.5f, drawsize = 4.0f;
- if ((sb = ob->soft)) {
- if (sb->solverflags & SBSO_ESTIMATEIPO) {
-
- glLoadMatrixf(rv3d->viewmat);
- copy_m3_m3(msc, sb->lscale);
- copy_m3_m3(mrt, sb->lrot);
- mul_m3_m3m3(mtr, mrt, msc);
- ob_draw_RE_motion(sb->lcom, mtr, tipw, tiph, drawsize);
- glMultMatrixf(ob->obmat);
- }
- }
- }
-
- if (ob->pd && ob->pd->forcefield) {
- draw_forcefield(ob, rv3d, dflag, ob_wire_col);
- }
- }
- }
-
- /* code for new particle system */
- if ((ob->particlesystem.first) &&
- (ob != scene->obedit))
- {
- ParticleSystem *psys;
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- /* for visibility, also while wpaint */
- if (col || (ob->flag & SELECT)) {
- cpack(0xFFFFFF);
- }
- }
- //glDepthMask(GL_FALSE);
-
- glLoadMatrixf(rv3d->viewmat);
-
- view3d_cached_text_draw_begin();
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- /* run this so that possible child particles get cached */
- if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) {
- PTCacheEdit *edit = PE_create_current(bmain, scene, ob);
- if (edit && edit->psys == psys)
- draw_update_ptcache_edit(bmain, scene, ob, edit);
- }
-
- draw_new_particle_system(scene, v3d, rv3d, base, psys, dt, dflag);
- }
- invert_m4_m4(ob->imat, ob->obmat);
- view3d_cached_text_draw_end(v3d, ar, 0);
-
- glMultMatrixf(ob->obmat);
-
- //glDepthMask(GL_TRUE);
- if (col) cpack(col);
- }
-
- /* draw edit particles last so that they can draw over child particles */
- if ((dflag & DRAW_PICKING) == 0 &&
- (!scene->obedit))
- {
-
- if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) {
- PTCacheEdit *edit = PE_create_current(bmain, scene, ob);
- if (edit) {
- glLoadMatrixf(rv3d->viewmat);
- draw_update_ptcache_edit(bmain, scene, ob, edit);
- draw_ptcache_edit(scene, v3d, edit);
- glMultMatrixf(ob->obmat);
- }
- }
- }
-
- /* draw code for smoke, only draw domains */
- if (smd && smd->domain) {
- SmokeDomainSettings *sds = smd->domain;
- float viewnormal[3];
-
- glLoadMatrixf(rv3d->viewmat);
- glMultMatrixf(ob->obmat);
-
- if (!render_override) {
- BoundBox bb;
- float p0[3], p1[3];
-
- /* draw max domain bounds */
- if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)) {
- VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
- VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
- BKE_boundbox_init_from_minmax(&bb, p0, p1);
- draw_box(bb.vec, false);
- }
-
- /* draw a single voxel to hint the user about the resolution of the fluid */
- copy_v3_v3(p0, sds->p0);
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- madd_v3_v3v3fl(p1, p0, sds->cell_size, 1.0f / (sds->amplify + 1));
- }
- else {
- add_v3_v3v3(p1, p0, sds->cell_size);
- }
-
- BKE_boundbox_init_from_minmax(&bb, p0, p1);
- draw_box(bb.vec, false);
- }
-
- /* don't show smoke before simulation starts, this could be made an option in the future */
- if (sds->fluid && CFRA >= sds->point_cache[0]->startframe) {
- float p0[3], p1[3];
-
- /* get view vector */
- invert_m4_m4(ob->imat, ob->obmat);
- mul_v3_mat3_m4v3(viewnormal, ob->imat, rv3d->viewinv[2]);
- normalize_v3(viewnormal);
-
- /* set dynamic boundaries to draw the volume
- * also scale cube to global space to equalize volume slicing on all axes
- * (it's scaled back before drawing) */
- p0[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_min[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
- p0[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_min[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
- p0[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_min[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
- p1[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_max[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]);
- p1[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_max[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]);
- p1[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_max[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
-
- if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
- sds->tex = NULL;
- GPU_create_smoke(smd, 0);
- draw_smoke_volume(sds, ob, p0, p1, viewnormal);
- GPU_free_smoke(smd);
- }
- else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
- sds->tex = NULL;
- GPU_create_smoke(smd, 1);
- draw_smoke_volume(sds, ob, p0, p1, viewnormal);
- GPU_free_smoke(smd);
- }
-
- /* smoke debug render */
- if (!render_override && sds->draw_velocity) {
- draw_smoke_velocity(sds, viewnormal);
- }
- }
- }
-
- if (!render_override) {
- bConstraint *con;
-
- for (con = ob->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_RIGIDBODYJOINT) {
- bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)con->data;
- if (data->flag & CONSTRAINT_DRAW_PIVOT)
- draw_rigid_body_pivot(data, dflag, ob_wire_col);
- }
- }
-
- if ((ob->gameflag & OB_BOUNDS) && (ob->mode == OB_MODE_OBJECT)) {
- if (ob->boundtype != ob->collision_boundtype || (dtx & OB_DRAWBOUNDOX) == 0) {
- setlinestyle(2);
- draw_bounding_volume(ob, ob->collision_boundtype);
- setlinestyle(0);
- }
- }
- if (ob->rigidbody_object) {
- draw_rigidbody_shape(ob);
- }
-
- /* draw extra: after normal draw because of makeDispList */
- if (dtx && (G.f & G_RENDER_OGL) == 0) {
-
- if (dtx & OB_AXIS) {
- drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS);
- }
- if (dtx & OB_DRAWBOUNDOX) {
- draw_bounding_volume(ob, ob->boundtype);
- }
- if (dtx & OB_TEXSPACE) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- /* prevent random colors being used */
- glColor3ubv(ob_wire_col);
- }
- drawtexspace(ob);
- }
- if (dtx & OB_DRAWNAME) {
- /* patch for several 3d cards (IBM mostly) that crash on GL_SELECT with text drawing */
- /* but, we also don't draw names for sets or duplicators */
- if (dflag == 0) {
- const float zero[3] = {0, 0, 0};
- view3d_cached_text_draw_add(zero, ob->id.name + 2, strlen(ob->id.name + 2), 10, 0, ob_wire_col);
- }
- }
- if ((dtx & OB_DRAWWIRE) && dt >= OB_SOLID) {
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- draw_wire_extra(scene, rv3d, ob, ob_wire_col);
- }
- }
- }
- }
-
- if ((dt <= OB_SOLID) && !render_override) {
- if (((ob->gameflag & OB_DYNAMIC) &&
- ((ob->gameflag & OB_BOUNDS) == 0)) ||
-
- ((ob->gameflag & OB_BOUNDS) &&
- (ob->collision_boundtype == OB_BOUND_SPHERE)))
- {
- float imat[4][4], vec[3] = {0.0f, 0.0f, 0.0f};
-
- invert_m4_m4(imat, rv3d->viewmatob);
-
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- /* prevent random colors being used */
- glColor3ubv(ob_wire_col);
- }
-
- setlinestyle(2);
- drawcircball(GL_LINE_LOOP, vec, ob->inertia, imat);
- setlinestyle(0);
- }
- }
-
- /* return warning, this is cached text draw */
- invert_m4_m4(ob->imat, ob->obmat);
- view3d_cached_text_draw_end(v3d, ar, 1);
- /* return warning, clear temp flag */
- v3d->flag2 &= ~V3D_SHOW_SOLID_MATCAP;
-
- glLoadMatrixf(rv3d->viewmat);
-
- if (zbufoff) {
- glDisable(GL_DEPTH_TEST);
- }
-
- if ((base->flag & OB_FROMDUPLI) || render_override) {
- ED_view3d_clear_mats_rv3d(rv3d);
- return;
- }
-
- /* object centers, need to be drawn in viewmat space for speed, but OK for picking select */
- if (!is_obact || !(ob->mode & OB_MODE_ALL_PAINT)) {
- int do_draw_center = -1; /* defines below are zero or positive... */
-
- if (render_override) {
- /* don't draw */
- }
- else if (is_obact)
- do_draw_center = ACTIVE;
- else if (base->flag & SELECT)
- do_draw_center = SELECT;
- else if (empty_object || (v3d->flag & V3D_DRAW_CENTERS))
- do_draw_center = DESELECT;
-
- if (do_draw_center != -1) {
- if (dflag & DRAW_PICKING) {
- /* draw a single point for opengl selection */
- if ((base->sx != IS_CLIPPED) &&
- (U.obcenter_dia != 0.0))
- {
- glPointSize(U.obcenter_dia);
- glBegin(GL_POINTS);
- glVertex3fv(ob->obmat[3]);
- glEnd();
- }
- }
- else if ((dflag & DRAW_CONSTCOLOR) == 0) {
- /* we don't draw centers for duplicators and sets */
- if ((base->sx != IS_CLIPPED) &&
- (U.obcenter_dia != 0.0) &&
- !(G.f & G_RENDER_OGL))
- {
- /* check > 0 otherwise grease pencil can draw into the circle select which is annoying. */
- drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ID_IS_LINKED(ob) || ob->id.us > 1);
- }
- }
- }
- }
-
- /* not for sets, duplicators or picking */
- if (dflag == 0 && (v3d->flag & V3D_HIDE_HELPLINES) == 0 && !render_override) {
- ListBase *list;
- RigidBodyCon *rbc = ob->rigidbody_constraint;
-
- /* draw hook center and offset line */
- if (ob != scene->obedit)
- draw_hooks(ob);
-
- /* help lines and so */
- if (ob != scene->obedit && ob->parent && (ob->parent->lay & v3d->lay)) {
- setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(ob->obmat[3]);
- glVertex3fv(ob->orig);
- glEnd();
- setlinestyle(0);
- }
-
- /* Drawing the constraint lines */
- if (ob->constraints.first) {
- bConstraint *curcon;
- bConstraintOb *cob;
- unsigned char col1[4], col2[4];
-
- list = &ob->constraints;
-
- UI_GetThemeColor3ubv(TH_GRID, col1);
- UI_make_axis_color(col1, col2, 'Z');
- glColor3ubv(col2);
-
- cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
-
- for (curcon = list->first; curcon; curcon = curcon->next) {
- if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
- /* special case for object solver and follow track constraints because they don't fill
- * constraint targets properly (design limitation -- scene is needed for their target
- * but it can't be accessed from get_targets callback) */
-
- Object *camob = NULL;
-
- if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = (bFollowTrackConstraint *)curcon->data;
-
- camob = data->camera ? data->camera : scene->camera;
- }
- else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *)curcon->data;
-
- camob = data->camera ? data->camera : scene->camera;
- }
-
- if (camob) {
- setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(camob->obmat[3]);
- glVertex3fv(ob->obmat[3]);
- glEnd();
- setlinestyle(0);
- }
- }
- else {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
-
- if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- /* calculate target's matrix */
- if (cti->get_target_matrix)
- cti->get_target_matrix(curcon, cob, ct, BKE_scene_frame_get(scene));
- else
- unit_m4(ct->matrix);
-
- setlinestyle(3);
- glBegin(GL_LINES);
- glVertex3fv(ct->matrix[3]);
- glVertex3fv(ob->obmat[3]);
- glEnd();
- setlinestyle(0);
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 1);
- }
- }
- }
-
- BKE_constraints_clear_evalob(cob);
- }
- /* draw rigid body constraint lines */
- if (rbc) {
- UI_ThemeColor(TH_WIRE);
- setlinestyle(3);
- glBegin(GL_LINES);
- if (rbc->ob1) {
- glVertex3fv(ob->obmat[3]);
- glVertex3fv(rbc->ob1->obmat[3]);
- }
- if (rbc->ob2) {
- glVertex3fv(ob->obmat[3]);
- glVertex3fv(rbc->ob2->obmat[3]);
- }
- glEnd();
- setlinestyle(0);
- }
- }
-
- ED_view3d_clear_mats_rv3d(rv3d);
-}
-
-
-/**
- * Drawing for selection picking,
- * caller must have called 'GPU_select_load_id(base->selcode)' first.
- */
-void draw_object_select(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag)
-{
- BLI_assert(dflag & DRAW_PICKING && dflag & DRAW_CONSTCOLOR);
- draw_object(bmain, scene, ar, v3d, base, dflag);
-
- /* we draw duplicators for selection too */
- if ((base->object->transflag & OB_DUPLI)) {
- ListBase *lb;
- DupliObject *dob;
- Base tbase;
-
- tbase.flag = OB_FROMDUPLI;
- lb = object_duplilist(bmain, bmain->eval_ctx, scene, base->object);
-
- for (dob = lb->first; dob; dob = dob->next) {
- float omat[4][4];
- char dt;
- short dtx;
-
- tbase.object = dob->ob;
- copy_m4_m4(omat, dob->ob->obmat);
- copy_m4_m4(dob->ob->obmat, dob->mat);
-
- /* extra service: draw the duplicator in drawtype of parent */
- /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
- dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
- dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
-
- draw_object(bmain, scene, ar, v3d, &tbase, dflag);
-
- tbase.object->dt = dt;
- tbase.object->dtx = dtx;
-
- copy_m4_m4(dob->ob->obmat, omat);
- }
- free_object_duplilist(lb);
- }
-}
-
/* ***************** BACKBUF SEL (BBS) ********* */
-static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+static void bbs_obmode_mesh_verts(Object *ob, int offset)
{
- drawMVertOffset_userData *data = userData;
- MVert *mv = &data->mvert[index];
-
- if (!(mv->flag & ME_HIDE)) {
- GPU_select_index_set(data->offset + index);
- glVertex3fv(co);
- }
-}
-
-static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset)
-{
- drawMVertOffset_userData data;
Mesh *me = ob->data;
- MVert *mvert = me->mvert;
- data.mvert = mvert;
- data.offset = offset;
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- glBegin(GL_POINTS);
- dm->foreachMappedVert(dm, bbs_obmode_mesh_verts__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
-}
-
-static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- drawBMOffset_userData *data = userData;
- BMVert *eve = BM_vert_at_index(data->bm, index);
-
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- GPU_select_index_set(data->offset + index);
- glVertex3fv(co);
- }
-}
-static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset)
-{
- drawBMOffset_userData data = {em->bm, offset};
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- glBegin(GL_POINTS);
- dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, &data, DM_FOREACH_NOP);
- glEnd();
+ GPUBatch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32);
+ GPU_batch_draw(batch);
}
-static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
+static void bbs_mesh_verts(BMEditMesh *em, int offset)
{
- drawBMOffset_userData *data = userData;
- BMEdge *eed = BM_edge_at_index(data->bm, index);
+ GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE));
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- GPU_select_index_set(data->offset + index);
- return DM_DRAW_OPTION_NORMAL;
- }
- else {
- return DM_DRAW_OPTION_SKIP;
- }
-}
-static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
-{
- drawBMOffset_userData data = {em->bm, offset};
- glLineWidth(1);
- dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, &data);
+ Mesh *me = em->ob->data;
+ GPUBatch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32);
+ GPU_batch_draw(batch);
}
-/**
- * dont set #GPU_framebuffer_index_set. just use to mask other
- */
-static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index)
+static void bbs_mesh_wire(BMEditMesh *em, int offset)
{
- BMFace *efa = BM_face_at_index(userData, index);
+ GPU_line_width(1.0f);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- return DM_DRAW_OPTION_NORMAL;
- }
- else {
- return DM_DRAW_OPTION_SKIP;
- }
+ Mesh *me = em->ob->data;
+ GPUBatch *batch = DRW_mesh_batch_cache_get_edges_with_select_id(me, offset);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32);
+ GPU_batch_draw(batch);
}
-static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int index)
+static void bbs_mesh_face(BMEditMesh *em, const bool use_select)
{
- BMFace *efa = BM_face_at_index(userData, index);
+ Mesh *me = em->ob->data;
+ GPUBatch *batch;
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_select_index_set(index + 1);
- return DM_DRAW_OPTION_NORMAL;
+ if (use_select) {
+ batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, true, 1);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32);
+ GPU_batch_draw(batch);
}
else {
- return DM_DRAW_OPTION_SKIP;
+ int selcol;
+ GPU_select_index_get(0, &selcol);
+ batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32);
+ GPU_batch_uniform_1ui(batch, "color", selcol);
+ GPU_batch_draw(batch);
}
}
-static void bbs_mesh_solid__drawCenter(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
+static void bbs_mesh_face_dot(BMEditMesh *em)
{
- BMFace *efa = BM_face_at_index(userData, index);
-
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- GPU_select_index_set(index + 1);
-
- glVertex3fv(cent);
- }
+ Mesh *me = em->ob->data;
+ GPUBatch *batch = DRW_mesh_batch_cache_get_facedots_with_select_id(me, 1);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32);
+ GPU_batch_draw(batch);
}
/* two options, facecolors or black */
static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
- Object *ob, DerivedMesh *dm, bool use_faceselect)
+ Object *ob, bool use_faceselect)
{
- cpack(0);
-
if (use_faceselect) {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, NULL, NULL, em->bm, DM_DRAW_SKIP_HIDDEN | DM_DRAW_SELECT_USE_EDITMODE);
+ bbs_mesh_face(em, true);
if (check_ob_drawface_dot(scene, v3d, ob->dt)) {
- glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
-
- glBegin(GL_POINTS);
- dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, em->bm, DM_FOREACH_NOP);
- glEnd();
+ bbs_mesh_face_dot(em);
}
-
- }
- else {
- dm->drawMappedFaces(dm, bbs_mesh_mask__setSolidDrawOptions, NULL, NULL, em->bm, DM_DRAW_SKIP_SELECT | DM_DRAW_SKIP_HIDDEN | DM_DRAW_SELECT_USE_EDITMODE);
- }
-}
-
-static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index)
-{
- GPU_select_index_set(index + 1);
- return DM_DRAW_OPTION_NORMAL;
-}
-
-static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index)
-{
- Mesh *me = userData;
-
- if (!(me->mpoly[index].flag & ME_HIDE)) {
- GPU_select_index_set(index + 1);
- return DM_DRAW_OPTION_NORMAL;
- }
- else {
- return DM_DRAW_OPTION_SKIP;
- }
-}
-
-/* must have called GPU_framebuffer_index_set beforehand */
-static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index)
-{
- Mesh *me = userData;
-
- if (!(me->mpoly[index].flag & ME_HIDE)) {
- return DM_DRAW_OPTION_NORMAL;
}
else {
- return DM_DRAW_OPTION_SKIP;
+ bbs_mesh_face(em, false);
}
}
-static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
+static void bbs_mesh_solid_verts(Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *ob)
{
Mesh *me = ob->data;
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
- glColor3ub(0, 0, 0);
-
- DM_update_materials(dm, ob);
/* Only draw faces to mask out verts, we don't want their selection ID's. */
const int G_f_orig = G.f;
G.f &= ~G_BACKBUFSEL;
- dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN);
+ {
+ int selcol;
+ GPUBatch *batch;
+ GPU_select_index_get(0, &selcol);
+ batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32);
+ GPU_batch_uniform_1ui(batch, "color", selcol);
+ GPU_batch_draw(batch);
+ }
G.f |= (G_f_orig & G_BACKBUFSEL);
- bbs_obmode_mesh_verts(ob, dm, 1);
+ bbs_obmode_mesh_verts(ob, 1);
bm_vertoffs = me->totvert + 1;
- dm->release(dm);
}
-static void bbs_mesh_solid_faces(Scene *scene, Object *ob)
+static void bbs_mesh_solid_faces(Scene *UNUSED(scene), Object *ob)
{
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
Mesh *me = ob->data;
-
- glColor3ub(0, 0, 0);
-
- DM_update_materials(dm, ob);
-
- if ((me->editflag & ME_EDIT_PAINT_FACE_SEL))
- dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN);
- else
- dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, NULL, NULL, me, 0);
-
- dm->release(dm);
+ GPUBatch *batch;
+ if ((me->editflag & ME_EDIT_PAINT_FACE_SEL)) {
+ batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, true, 1);
+ }
+ else {
+ batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, false, 1);
+ }
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32);
+ GPU_batch_draw(batch);
}
-void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob)
+void draw_object_backbufsel(
+ Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob,
+ short select_mode)
{
ToolSettings *ts = scene->toolsettings;
+ if (select_mode == -1) {
+ select_mode = ts->selectmode;
+ }
- glMultMatrixf(ob->obmat);
+ GPU_matrix_mul(ob->obmat);
- glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT);
- glEnable(GL_DEPTH_TEST);
+ glClearDepth(1.0); GPU_clear(GPU_DEPTH_BIT);
+ GPU_depth_test(true);
switch (ob->type) {
case OB_MESH:
@@ -8427,14 +326,10 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
- DerivedMesh *dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
-
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
- DM_update_materials(dm, ob);
-
- bbs_mesh_solid_EM(em, scene, v3d, ob, dm, (ts->selectmode & SCE_SELECT_FACE) != 0);
- if (ts->selectmode & SCE_SELECT_FACE)
+ bbs_mesh_solid_EM(em, scene, v3d, ob, (select_mode & SCE_SELECT_FACE) != 0);
+ if (select_mode & SCE_SELECT_FACE)
bm_solidoffs = 1 + em->bm->totface;
else {
bm_solidoffs = 1;
@@ -8443,8 +338,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
ED_view3d_polygon_offset(rv3d, 1.0);
/* we draw edges if edge select mode */
- if (ts->selectmode & SCE_SELECT_EDGE) {
- bbs_mesh_wire(em, dm, bm_solidoffs);
+ if (select_mode & SCE_SELECT_EDGE) {
+ bbs_mesh_wire(em, bm_solidoffs);
bm_wireoffs = bm_solidoffs + em->bm->totedge;
}
else {
@@ -8453,8 +348,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
}
/* we draw verts if vert select mode. */
- if (ts->selectmode & SCE_SELECT_VERTEX) {
- bbs_mesh_verts(em, dm, bm_wireoffs);
+ if (select_mode & SCE_SELECT_VERTEX) {
+ bbs_mesh_verts(em, bm_wireoffs);
bm_vertoffs = bm_wireoffs + em->bm->totvert;
}
else {
@@ -8462,8 +357,6 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
}
ED_view3d_polygon_offset(rv3d, 0.0);
-
- dm->release(dm);
}
else {
Mesh *me = ob->data;
@@ -8471,7 +364,7 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
/* currently vertex select supports weight paint and vertex paint*/
((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT)))
{
- bbs_mesh_solid_verts(scene, ob);
+ bbs_mesh_solid_verts(depsgraph, scene, ob);
}
else {
bbs_mesh_solid_faces(scene, ob);
@@ -8483,77 +376,107 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
break;
}
- glLoadMatrixf(rv3d->viewmat);
+ GPU_matrix_set(rv3d->viewmat);
}
-/* ************* draw object instances for bones, for example ****************** */
-/* assumes all matrices/etc set OK */
-
-/* helper function for drawing object instances - meshes */
-static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d,
- Object *ob, const short dt, int outline)
+void ED_draw_object_facemap(
+ Depsgraph *depsgraph, Object *ob, const float col[4], const int facemap)
{
- Mesh *me = ob->data;
- DerivedMesh *dm = NULL, *edm = NULL;
-
- if (ob->mode & OB_MODE_EDIT) {
- edm = editbmesh_get_derived_base(ob, me->edit_btmesh, CD_MASK_BAREMESH);
- DM_update_materials(edm, ob);
- }
- else {
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- DM_update_materials(dm, ob);
+ /* happens on undo */
+ if (ob->type != OB_MESH || !ob->data) {
+ return;
}
- if (dt <= OB_WIRE) {
- if (dm)
- dm->drawEdges(dm, 1, 0);
- else if (edm)
- edm->drawEdges(edm, 1, 0);
+ Mesh *me = ob->data;
+ {
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ if (ob_eval->runtime.mesh_eval) {
+ me = ob_eval->runtime.mesh_eval;
+ }
}
- else {
- if (outline)
- draw_mesh_object_outline(v3d, ob, dm ? dm : edm);
- if (dm) {
- bool glsl = draw_glsl_material(scene, ob, v3d, dt);
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
- }
+ glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
+ /* Just to create the data to pass to immediate mode, grr! */
+ const int *facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP);
+ if (facemap_data) {
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
- if (dm) {
- dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
- GPU_end_object_materials();
- }
- else if (edm)
- edm->drawMappedFaces(edm, NULL, GPU_object_material_bind, NULL, NULL, DM_DRAW_NEED_NORMALS);
+ const MVert *mvert = me->mvert;
+ const MPoly *mpoly = me->mpoly;
+ const MLoop *mloop = me->mloop;
- GPU_object_material_unbind();
- }
+ int mpoly_len = me->totpoly;
+ int mloop_len = me->totloop;
- if (edm) edm->release(edm);
- if (dm) dm->release(dm);
-}
+ facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP);
-void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const char dt, int outline)
-{
- if (ob == NULL)
- return;
+ /* use gawain immediate mode fore now */
+ const int looptris_len = poly_to_tri_count(mpoly_len, mloop_len);
+ const int vbo_len_capacity = looptris_len * 3;
+ int vbo_len_used = 0;
- switch (ob->type) {
- case OB_MESH:
- draw_object_mesh_instance(scene, v3d, rv3d, ob, dt, outline);
- break;
- case OB_EMPTY:
- if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
- /* CONSTCOLOR == no wire outline */
- draw_empty_image(ob, DRAW_CONSTCOLOR, NULL, v3d->multiview_eye);
+ GPUVertFormat format_pos = { 0 };
+ const uint pos_id = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vbo_pos = GPU_vertbuf_create_with_format(&format_pos);
+ GPU_vertbuf_data_alloc(vbo_pos, vbo_len_capacity);
+
+ GPUVertBufRaw pos_step;
+ GPU_vertbuf_attr_get_raw_data(vbo_pos, pos_id, &pos_step);
+
+ const MPoly *mp;
+ int i;
+ if (me->runtime.looptris.array) {
+ MLoopTri *mlt = me->runtime.looptris.array;
+ for (mp = mpoly, i = 0; i < mpoly_len; i++, mp++) {
+ if (facemap_data[i] == facemap) {
+ for (int j = 2; j < mp->totloop; j++) {
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[0]].v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[1]].v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[2]].v].co);
+ vbo_len_used += 3;
+ mlt++;
+ }
+ }
+ else {
+ mlt += mp->totloop - 2;
+ }
}
- else {
- drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype);
+ }
+ else {
+ /* No tessellation data, fan-fill. */
+ for (mp = mpoly, i = 0; i < mpoly_len; i++, mp++) {
+ if (facemap_data[i] == facemap) {
+ const MLoop *ml_start = &mloop[mp->loopstart];
+ const MLoop *ml_a = ml_start + 1;
+ const MLoop *ml_b = ml_start + 2;
+ for (int j = 2; j < mp->totloop; j++) {
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_start->v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_a->v].co);
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_b->v].co);
+ vbo_len_used += 3;
+
+ ml_a++;
+ ml_b++;
+ }
+ }
}
- break;
+ }
+
+ if (vbo_len_capacity != vbo_len_used) {
+ GPU_vertbuf_data_resize(vbo_pos, vbo_len_used);
+ }
+
+ GPUBatch *draw_batch = GPU_batch_create(GPU_PRIM_TRIS, vbo_pos, NULL);
+ GPU_batch_program_set_builtin(draw_batch, GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(draw_batch, "color", col);
+ GPU_batch_draw(draw_batch);
+ GPU_batch_discard(draw_batch);
+ GPU_vertbuf_discard(vbo_pos);
+
+ GPU_blend(false);
}
}
diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c
deleted file mode 100644
index 9165147736a..00000000000
--- a/source/blender/editors/space_view3d/drawsimdebug.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * ***** 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) 2014 by the Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_view3d/drawsimdebug.c
- * \ingroup spview3d
- */
-
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-
-#include "BKE_effect.h"
-
-#include "view3d_intern.h"
-
-#include "BIF_gl.h"
-
-
-static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
-{
- GHashIterator iter;
-
- /**** dots ****/
-
- glPointSize(3.0f);
- glBegin(GL_POINTS);
- for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
- if (elem->type != SIM_DEBUG_ELEM_DOT)
- continue;
-
- glColor3f(elem->color[0], elem->color[1], elem->color[2]);
- glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
- }
- glEnd();
-
- /**** circles ****/
-
- {
- float circle[16][2] = {
- {0.000000, 1.000000}, {0.382683, 0.923880}, {0.707107, 0.707107}, {0.923880, 0.382683},
- {1.000000, -0.000000}, {0.923880, -0.382683}, {0.707107, -0.707107}, {0.382683, -0.923880},
- {-0.000000, -1.000000}, {-0.382683, -0.923880}, {-0.707107, -0.707107}, {-0.923879, -0.382684},
- {-1.000000, 0.000000}, {-0.923879, 0.382684}, {-0.707107, 0.707107}, {-0.382683, 0.923880} };
- for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
- float radius = elem->v2[0];
- float co[3];
- int i;
-
- if (elem->type != SIM_DEBUG_ELEM_CIRCLE)
- continue;
-
- glColor3f(elem->color[0], elem->color[1], elem->color[2]);
- glBegin(GL_LINE_LOOP);
- for (i = 0; i < 16; ++i) {
- co[0] = radius * circle[i][0];
- co[1] = radius * circle[i][1];
- co[2] = 0.0f;
- mul_mat3_m4_v3(imat, co);
- add_v3_v3(co, elem->v1);
-
- glVertex3f(co[0], co[1], co[2]);
- }
- glEnd();
- }
- }
-
- /**** lines ****/
-
- glBegin(GL_LINES);
- for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
- if (elem->type != SIM_DEBUG_ELEM_LINE)
- continue;
-
- glColor3f(elem->color[0], elem->color[1], elem->color[2]);
- glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
- glVertex3f(elem->v2[0], elem->v2[1], elem->v2[2]);
- }
- glEnd();
-
- /**** vectors ****/
-
- glPointSize(2.0f);
- glBegin(GL_POINTS);
- for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
- if (elem->type != SIM_DEBUG_ELEM_VECTOR)
- continue;
-
- glColor3f(elem->color[0], elem->color[1], elem->color[2]);
- glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
- }
- glEnd();
-
- glBegin(GL_LINES);
- for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
- float t[3];
- if (elem->type != SIM_DEBUG_ELEM_VECTOR)
- continue;
-
- glColor3f(elem->color[0], elem->color[1], elem->color[2]);
- glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
- add_v3_v3v3(t, elem->v1, elem->v2);
- glVertex3f(t[0], t[1], t[2]);
- }
- glEnd();
-
- /**** strings ****/
-
- for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
- SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
- if (elem->type != SIM_DEBUG_ELEM_STRING)
- continue;
-
- unsigned char col[4];
- rgb_float_to_uchar(col, elem->color);
- col[3] = 255;
- view3d_cached_text_draw_add(elem->v1, elem->str, strlen(elem->str),
- 0, V3D_CACHE_TEXT_GLOBALSPACE, col);
- }
-}
-
-void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar)
-{
- RegionView3D *rv3d = ar->regiondata;
- /*Object *ob = base->object;*/
- float imat[4][4];
-
- if (!_sim_debug_data)
- return;
-
- invert_m4_m4(imat, rv3d->viewmatob);
-
-// glDepthMask(GL_FALSE);
-// glEnable(GL_BLEND);
-
- glPushMatrix();
- glLoadMatrixf(rv3d->viewmat);
-
- view3d_cached_text_draw_begin();
- draw_sim_debug_elements(_sim_debug_data, imat);
- view3d_cached_text_draw_end(v3d, ar, false);
-
- glPopMatrix();
-
-// glDepthMask(GL_TRUE);
-// glDisable(GL_BLEND);
-}
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
deleted file mode 100644
index b230a5e193c..00000000000
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Daniel Genrich
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_view3d/drawvolume.c
- * \ingroup spview3d
- */
-
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_smoke_types.h"
-#include "DNA_view3d_types.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_math.h"
-
-#include "BKE_DerivedMesh.h"
-#include "BKE_colorband.h"
-#include "BKE_particle.h"
-
-#include "smoke_API.h"
-
-#include "BIF_gl.h"
-
-#include "GPU_debug.h"
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-
-#include "view3d_intern.h" // own include
-
-struct GPUTexture;
-
-// #define DEBUG_DRAW_TIME
-
-#ifdef DEBUG_DRAW_TIME
-# include "PIL_time.h"
-# include "PIL_time_utildefines.h"
-#endif
-
-/* *************************** Transfer functions *************************** */
-
-enum {
- TFUNC_FLAME_SPECTRUM = 0,
- TFUNC_COLOR_RAMP = 1,
-};
-
-#define TFUNC_WIDTH 256
-
-static void create_flame_spectrum_texture(float *data)
-{
-#define FIRE_THRESH 7
-#define MAX_FIRE_ALPHA 0.06f
-#define FULL_ON_FIRE 100
-
- float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
-
- blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
-
- for (int i = 0; i < 16; i++) {
- for (int j = 0; j < 16; j++) {
- for (int k = 0; k < TFUNC_WIDTH; k++) {
- int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
- if (k >= FIRE_THRESH) {
- spec_pixels[index] = (data[k * 4]);
- spec_pixels[index + 1] = (data[k * 4 + 1]);
- spec_pixels[index + 2] = (data[k * 4 + 2]);
- spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
- (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
- }
- else {
- zero_v4(&spec_pixels[index]);
- }
- }
- }
- }
-
- memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
-
- MEM_freeN(spec_pixels);
-
-#undef FIRE_THRESH
-#undef MAX_FIRE_ALPHA
-#undef FULL_ON_FIRE
-}
-
-static void create_color_ramp(const ColorBand *coba, float *data)
-{
- for (int i = 0; i < TFUNC_WIDTH; i++) {
- BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
- }
-}
-
-static GPUTexture *create_transfer_function(int type, const ColorBand *coba)
-{
- float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
-
- switch (type) {
- case TFUNC_FLAME_SPECTRUM:
- create_flame_spectrum_texture(data);
- break;
- case TFUNC_COLOR_RAMP:
- create_color_ramp(coba, data);
- break;
- }
-
- GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, data, NULL);
-
- MEM_freeN(data);
-
- return tex;
-}
-
-static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
-{
- float *field = NULL;
-
- switch (sds->coba_field) {
-#ifdef WITH_SMOKE
- case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break;
- case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break;
- case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break;
- case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break;
- case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break;
- case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break;
- case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break;
- case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break;
- case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break;
- case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break;
- case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break;
- case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break;
- case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break;
- case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break;
-#endif
- default: return NULL;
- }
-
- return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field);
-}
-
-typedef struct VolumeSlicer {
- float size[3];
- float min[3];
- float max[3];
- float (*verts)[3];
-} VolumeSlicer;
-
-/* *************************** Axis Aligned Slicing ************************** */
-
-static void create_single_slice(VolumeSlicer *slicer, const float depth,
- const int axis, const int idx)
-{
- const float vertices[3][4][3] = {
- {
- { depth, slicer->min[1], slicer->min[2] },
- { depth, slicer->max[1], slicer->min[2] },
- { depth, slicer->max[1], slicer->max[2] },
- { depth, slicer->min[1], slicer->max[2] }
- },
- {
- { slicer->min[0], depth, slicer->min[2] },
- { slicer->min[0], depth, slicer->max[2] },
- { slicer->max[0], depth, slicer->max[2] },
- { slicer->max[0], depth, slicer->min[2] }
- },
- {
- { slicer->min[0], slicer->min[1], depth },
- { slicer->min[0], slicer->max[1], depth },
- { slicer->max[0], slicer->max[1], depth },
- { slicer->max[0], slicer->min[1], depth }
- }
- };
-
- copy_v3_v3(slicer->verts[idx + 0], vertices[axis][0]);
- copy_v3_v3(slicer->verts[idx + 1], vertices[axis][1]);
- copy_v3_v3(slicer->verts[idx + 2], vertices[axis][2]);
- copy_v3_v3(slicer->verts[idx + 3], vertices[axis][0]);
- copy_v3_v3(slicer->verts[idx + 4], vertices[axis][2]);
- copy_v3_v3(slicer->verts[idx + 5], vertices[axis][3]);
-}
-
-static void create_axis_aligned_slices(VolumeSlicer *slicer, const int num_slices,
- const float view_dir[3], const int axis)
-{
- float depth, slice_size = slicer->size[axis] / num_slices;
-
- /* always process slices in back to front order! */
- if (view_dir[axis] > 0.0f) {
- depth = slicer->min[axis];
- }
- else {
- depth = slicer->max[axis];
- slice_size = -slice_size;
- }
-
- int count = 0;
- for (int slice = 0; slice < num_slices; slice++) {
- create_single_slice(slicer, depth, axis, count);
-
- count += 6;
- depth += slice_size;
- }
-}
-
-/* *************************** View Aligned Slicing ************************** */
-
-/* Code adapted from:
- * "GPU-based Volume Rendering, Real-time Volume Graphics", AK Peters/CRC Press
- */
-static int create_view_aligned_slices(VolumeSlicer *slicer,
- const int num_slices,
- const float view_dir[3])
-{
- const int indices[] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5 };
-
- const float vertices[8][3] = {
- { slicer->min[0], slicer->min[1], slicer->min[2] },
- { slicer->max[0], slicer->min[1], slicer->min[2] },
- { slicer->max[0], slicer->max[1], slicer->min[2] },
- { slicer->min[0], slicer->max[1], slicer->min[2] },
- { slicer->min[0], slicer->min[1], slicer->max[2] },
- { slicer->max[0], slicer->min[1], slicer->max[2] },
- { slicer->max[0], slicer->max[1], slicer->max[2] },
- { slicer->min[0], slicer->max[1], slicer->max[2] }
- };
-
- const int edges[12][2] = {
- { 0, 1 }, { 1, 2 }, { 2, 3 },
- { 3, 0 }, { 0, 4 }, { 1, 5 },
- { 2, 6 }, { 3, 7 }, { 4, 5 },
- { 5, 6 }, { 6, 7 }, { 7, 4 }
- };
-
- const int edge_list[8][12] = {
- { 0, 1, 5, 6, 4, 8, 11, 9, 3, 7, 2, 10 },
- { 0, 4, 3, 11, 1, 2, 6, 7, 5, 9, 8, 10 },
- { 1, 5, 0, 8, 2, 3, 7, 4, 6, 10, 9, 11 },
- { 7, 11, 10, 8, 2, 6, 1, 9, 3, 0, 4, 5 },
- { 8, 5, 9, 1, 11, 10, 7, 6, 4, 3, 0, 2 },
- { 9, 6, 10, 2, 8, 11, 4, 7, 5, 0, 1, 3 },
- { 9, 8, 5, 4, 6, 1, 2, 0, 10, 7, 11, 3 },
- { 10, 9, 6, 5, 7, 2, 3, 1, 11, 4, 8, 0 }
- };
-
- /* find vertex that is the furthest from the view plane */
- int max_index = 0;
- float max_dist, min_dist;
- min_dist = max_dist = dot_v3v3(view_dir, vertices[0]);
-
- for (int i = 1; i < 8; i++) {
- float dist = dot_v3v3(view_dir, vertices[i]);
-
- if (dist > max_dist) {
- max_dist = dist;
- max_index = i;
- }
-
- if (dist < min_dist) {
- min_dist = dist;
- }
- }
-
- max_dist -= FLT_EPSILON;
- min_dist += FLT_EPSILON;
-
- /* start and direction vectors */
- float vec_start[12][3], vec_dir[12][3];
- /* lambda intersection values */
- float lambda[12], lambda_inc[12];
- float denom = 0.0f;
-
- float plane_dist = min_dist;
- float plane_dist_inc = (max_dist - min_dist) / (float)num_slices;
-
- /* for all edges */
- for (int i = 0; i < 12; i++) {
- copy_v3_v3(vec_start[i], vertices[edges[edge_list[max_index][i]][0]]);
- copy_v3_v3(vec_dir[i], vertices[edges[edge_list[max_index][i]][1]]);
- sub_v3_v3(vec_dir[i], vec_start[i]);
-
- denom = dot_v3v3(vec_dir[i], view_dir);
-
- if (1.0f + denom != 1.0f) {
- lambda_inc[i] = plane_dist_inc / denom;
- lambda[i] = (plane_dist - dot_v3v3(vec_start[i], view_dir)) / denom;
- }
- else {
- lambda[i] = -1.0f;
- lambda_inc[i] = 0.0f;
- }
- }
-
- float intersections[6][3];
- float dL[12];
- int num_points = 0;
- /* find intersections for each slice, process them in back to front order */
- for (int i = 0; i < num_slices; i++) {
- for (int e = 0; e < 12; e++) {
- dL[e] = lambda[e] + i * lambda_inc[e];
- }
-
- if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) {
- madd_v3_v3v3fl(intersections[0], vec_start[0], vec_dir[0], dL[0]);
- }
- else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) {
- madd_v3_v3v3fl(intersections[0], vec_start[1], vec_dir[1], dL[1]);
- }
- else if ((dL[3] >= 0.0f) && (dL[3] < 1.0f)) {
- madd_v3_v3v3fl(intersections[0], vec_start[3], vec_dir[3], dL[3]);
- }
- else continue;
-
- if ((dL[2] >= 0.0f) && (dL[2] < 1.0f)) {
- madd_v3_v3v3fl(intersections[1], vec_start[2], vec_dir[2], dL[2]);
- }
- else if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) {
- madd_v3_v3v3fl(intersections[1], vec_start[0], vec_dir[0], dL[0]);
- }
- else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) {
- madd_v3_v3v3fl(intersections[1], vec_start[1], vec_dir[1], dL[1]);
- }
- else {
- madd_v3_v3v3fl(intersections[1], vec_start[3], vec_dir[3], dL[3]);
- }
-
- if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) {
- madd_v3_v3v3fl(intersections[2], vec_start[4], vec_dir[4], dL[4]);
- }
- else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) {
- madd_v3_v3v3fl(intersections[2], vec_start[5], vec_dir[5], dL[5]);
- }
- else {
- madd_v3_v3v3fl(intersections[2], vec_start[7], vec_dir[7], dL[7]);
- }
-
- if ((dL[6] >= 0.0f) && (dL[6] < 1.0f)) {
- madd_v3_v3v3fl(intersections[3], vec_start[6], vec_dir[6], dL[6]);
- }
- else if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) {
- madd_v3_v3v3fl(intersections[3], vec_start[4], vec_dir[4], dL[4]);
- }
- else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) {
- madd_v3_v3v3fl(intersections[3], vec_start[5], vec_dir[5], dL[5]);
- }
- else {
- madd_v3_v3v3fl(intersections[3], vec_start[7], vec_dir[7], dL[7]);
- }
-
- if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) {
- madd_v3_v3v3fl(intersections[4], vec_start[8], vec_dir[8], dL[8]);
- }
- else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) {
- madd_v3_v3v3fl(intersections[4], vec_start[9], vec_dir[9], dL[9]);
- }
- else {
- madd_v3_v3v3fl(intersections[4], vec_start[11], vec_dir[11], dL[11]);
- }
-
- if ((dL[10] >= 0.0f) && (dL[10] < 1.0f)) {
- madd_v3_v3v3fl(intersections[5], vec_start[10], vec_dir[10], dL[10]);
- }
- else if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) {
- madd_v3_v3v3fl(intersections[5], vec_start[8], vec_dir[8], dL[8]);
- }
- else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) {
- madd_v3_v3v3fl(intersections[5], vec_start[9], vec_dir[9], dL[9]);
- }
- else {
- madd_v3_v3v3fl(intersections[5], vec_start[11], vec_dir[11], dL[11]);
- }
-
- for (int e = 0; e < 12; e++) {
- copy_v3_v3(slicer->verts[num_points++], intersections[indices[e]]);
- }
- }
-
- return num_points;
-}
-
-static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec,
- GPUTexture *tex_tfunc, GPUTexture *tex_coba,
- bool use_fire, const float min[3],
- const float ob_sizei[3], const float invsize[3])
-{
- int invsize_location = GPU_shader_get_uniform(shader, "invsize");
- int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
- int min_location = GPU_shader_get_uniform(shader, "min_location");
-
- int soot_location;
- int stepsize_location;
- int densityscale_location;
- int spec_location, flame_location;
- int shadow_location, actcol_location;
- int tfunc_location = 0;
- int coba_location = 0;
-
- if (use_fire) {
- spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
- flame_location = GPU_shader_get_uniform(shader, "flame_texture");
- }
- else {
- shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
- actcol_location = GPU_shader_get_uniform(shader, "active_color");
- soot_location = GPU_shader_get_uniform(shader, "soot_texture");
- stepsize_location = GPU_shader_get_uniform(shader, "step_size");
- densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
-
- if (sds->use_coba) {
- tfunc_location = GPU_shader_get_uniform(shader, "transfer_texture");
- coba_location = GPU_shader_get_uniform(shader, "color_band_texture");
- }
- }
-
- GPU_shader_bind(shader);
-
- if (use_fire) {
- GPU_texture_bind(sds->tex_flame, 2);
- GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
-
- GPU_texture_bind(tex_spec, 3);
- GPU_shader_uniform_texture(shader, spec_location, tex_spec);
- }
- else {
- float density_scale = 10.0f * sds->display_thickness;
-
- GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
- GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
-
- GPU_texture_bind(sds->tex, 0);
- GPU_shader_uniform_texture(shader, soot_location, sds->tex);
-
- GPU_texture_bind(sds->tex_shadow, 1);
- GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
-
- float active_color[3] = { 0.9, 0.9, 0.9 };
- if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
- mul_v3_v3(active_color, sds->active_color);
- GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
-
- if (sds->use_coba) {
- GPU_texture_bind(tex_tfunc, 4);
- GPU_shader_uniform_texture(shader, tfunc_location, tex_tfunc);
-
- GPU_texture_bind(tex_coba, 5);
- GPU_shader_uniform_texture(shader, coba_location, tex_coba);
- }
- }
-
- GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
- GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
- GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
-}
-
-static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec,
- GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire)
-{
- GPU_shader_unbind();
-
- GPU_texture_unbind(sds->tex);
-
- if (use_fire) {
- GPU_texture_unbind(sds->tex_flame);
- GPU_texture_unbind(tex_spec);
- GPU_texture_free(tex_spec);
- }
- else {
- GPU_texture_unbind(sds->tex_shadow);
-
- if (sds->use_coba) {
- GPU_texture_unbind(tex_tfunc);
- GPU_texture_free(tex_tfunc);
-
- GPU_texture_unbind(tex_coba);
- GPU_texture_free(tex_coba);
- }
- }
-}
-
-static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer,
- const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire)
-{
- GPUTexture *tex_spec = (do_fire) ? create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL) : NULL;
- GPUTexture *tex_tfunc = (sds->use_coba) ? create_transfer_function(TFUNC_COLOR_RAMP, sds->coba) : NULL;
- GPUTexture *tex_coba = (sds->use_coba) ? create_field_texture(sds) : NULL;
-
- GLuint vertex_buffer;
- glGenBuffers(1, &vertex_buffer);
- glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW);
-
- bind_shader(sds, shader, tex_spec, tex_tfunc, tex_coba, do_fire, slicer->min, ob_sizei, invsize);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, NULL);
-
- glDrawArrays(GL_TRIANGLES, 0, num_points);
-
- glDisableClientState(GL_VERTEX_ARRAY);
-
- unbind_shader(sds, tex_spec, tex_tfunc, tex_coba, do_fire);
-
- /* cleanup */
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- glDeleteBuffers(1, &vertex_buffer);
-}
-
-void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
- const float min[3], const float max[3],
- const float viewnormal[3])
-{
- if (!sds->tex || !sds->tex_shadow) {
- fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n");
- return;
- }
-
- const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;
-
- GPUBuiltinShader builtin_shader;
-
- if (sds->use_coba) {
- builtin_shader = GPU_SHADER_SMOKE_COBA;
- }
- else {
- builtin_shader = GPU_SHADER_SMOKE;
- }
-
- GPUShader *shader = GPU_shader_get_builtin_shader(builtin_shader);
-
- if (!shader) {
- fprintf(stderr, "Unable to create GLSL smoke shader.\n");
- return;
- }
-
- GPUShader *fire_shader = NULL;
- if (use_fire) {
- fire_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE_FIRE);
-
- if (!fire_shader) {
- fprintf(stderr, "Unable to create GLSL fire shader.\n");
- return;
- }
- }
-
- const float ob_sizei[3] = {
- 1.0f / fabsf(ob->size[0]),
- 1.0f / fabsf(ob->size[1]),
- 1.0f / fabsf(ob->size[2])
- };
-
- const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] };
- const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] };
-
-#ifdef DEBUG_DRAW_TIME
- TIMEIT_START(draw);
-#endif
-
- /* setup slicing information */
-
- const bool view_aligned = (sds->slice_method == MOD_SMOKE_SLICE_VIEW_ALIGNED);
- int max_slices, max_points, axis = 0;
-
- if (view_aligned) {
- max_slices = max_iii(sds->res[0], sds->res[1], sds->res[2]) * sds->slice_per_voxel;
- max_points = max_slices * 12;
- }
- else {
- if (sds->axis_slice_method == AXIS_SLICE_FULL) {
- axis = axis_dominant_v3_single(viewnormal);
- max_slices = sds->res[axis] * sds->slice_per_voxel;
- }
- else {
- axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewnormal) : sds->slice_axis - 1;
- max_slices = 1;
- }
-
- max_points = max_slices * 6;
- }
-
- VolumeSlicer slicer;
- copy_v3_v3(slicer.min, min);
- copy_v3_v3(slicer.max, max);
- copy_v3_v3(slicer.size, size);
- slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices");
-
- int num_points;
-
- if (view_aligned) {
- num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);
- }
- else {
- num_points = max_points;
-
- if (sds->axis_slice_method == AXIS_SLICE_FULL) {
- create_axis_aligned_slices(&slicer, max_slices, viewnormal, axis);
- }
- else {
- const float depth = (sds->slice_depth - 0.5f) * size[axis];
- create_single_slice(&slicer, depth, axis, 0);
- }
- }
-
- /* setup buffer and draw */
-
- 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);
- draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);
-
- /* Draw fire separately (T47639). */
- if (use_fire && !sds->use_coba) {
- glBlendFunc(GL_ONE, GL_ONE);
- draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true);
- }
-
-#ifdef DEBUG_DRAW_TIME
- printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
- TIMEIT_END(draw);
-#endif
-
- MEM_freeN(slicer.verts);
-
- glDepthMask(gl_depth_write);
-
- if (!gl_blend) {
- glDisable(GL_BLEND);
- }
-
- if (gl_depth) {
- glEnable(GL_DEPTH_TEST);
- }
-}
-
-#ifdef WITH_SMOKE
-static void add_tri(float (*verts)[3], float(*colors)[3], int *offset,
- float p1[3], float p2[3], float p3[3], float rgb[3])
-{
- copy_v3_v3(verts[*offset + 0], p1);
- copy_v3_v3(verts[*offset + 1], p2);
- copy_v3_v3(verts[*offset + 2], p3);
-
- copy_v3_v3(colors[*offset + 0], rgb);
- copy_v3_v3(colors[*offset + 1], rgb);
- copy_v3_v3(colors[*offset + 2], rgb);
-
- *offset += 3;
-}
-
-static void add_needle(float (*verts)[3], float (*colors)[3], float center[3],
- float dir[3], float scale, float voxel_size, int *offset)
-{
- float len = len_v3(dir);
-
- float rgb[3];
- weight_to_rgb(rgb, len);
-
- if (len != 0.0f) {
- mul_v3_fl(dir, 1.0f / len);
- len *= scale;
- }
-
- len *= voxel_size;
-
- float corners[4][3] = {
- { 0.0f, 0.2f, -0.5f },
- { -0.2f * 0.866f, -0.2f * 0.5f, -0.5f },
- { 0.2f * 0.866f, -0.2f * 0.5f, -0.5f },
- { 0.0f, 0.0f, 0.5f }
- };
-
- const float up[3] = { 0.0f, 0.0f, 1.0f };
- float rot[3][3];
-
- rotation_between_vecs_to_mat3(rot, up, dir);
- transpose_m3(rot);
-
- for (int i = 0; i < 4; i++) {
- mul_m3_v3(rot, corners[i]);
- mul_v3_fl(corners[i], len);
- add_v3_v3(corners[i], center);
- }
-
- add_tri(verts, colors, offset, corners[0], corners[1], corners[2], rgb);
- add_tri(verts, colors, offset, corners[0], corners[1], corners[3], rgb);
- add_tri(verts, colors, offset, corners[1], corners[2], corners[3], rgb);
- add_tri(verts, colors, offset, corners[2], corners[0], corners[3], rgb);
-}
-
-static void add_streamline(float (*verts)[3], float(*colors)[3], float center[3],
- float dir[3], float scale, float voxel_size, int *offset)
-{
- const float len = len_v3(dir);
-
- float rgb[3];
- weight_to_rgb(rgb, len);
-
- copy_v3_v3(colors[(*offset)], rgb);
- copy_v3_v3(verts[(*offset)++], center);
-
- mul_v3_fl(dir, scale * voxel_size);
- add_v3_v3(center, dir);
-
- copy_v3_v3(colors[(*offset)], rgb);
- copy_v3_v3(verts[(*offset)++], center);
-}
-
-typedef void (*vector_draw_func)(float(*)[3], float(*)[3], float *, float *, float, float, int *);
-#endif /* WITH_SMOKE */
-
-void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3])
-{
-#ifdef WITH_SMOKE
- const float *vel_x = smoke_get_velocity_x(domain->fluid);
- const float *vel_y = smoke_get_velocity_y(domain->fluid);
- const float *vel_z = smoke_get_velocity_z(domain->fluid);
-
- if (ELEM(NULL, vel_x, vel_y, vel_z)) {
- return;
- }
-
- const int *base_res = domain->base_res;
- const int *res = domain->res;
- const int *res_min = domain->res_min;
-
- int res_max[3];
- copy_v3_v3_int(res_max, domain->res_max);
-
- const float *cell_size = domain->cell_size;
- const float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.0f;
-
- /* set first position so that it doesn't jump when domain moves */
- float xyz[3] = {
- res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size),
- res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size),
- res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size)
- };
-
- if (xyz[0] < res_min[0]) xyz[0] += step_size;
- if (xyz[1] < res_min[1]) xyz[1] += step_size;
- if (xyz[2] < res_min[2]) xyz[2] += step_size;
-
- float min[3] = {
- domain->p0[0] - domain->cell_size[0] * domain->adapt_res,
- domain->p0[1] - domain->cell_size[1] * domain->adapt_res,
- domain->p0[2] - domain->cell_size[2] * domain->adapt_res,
- };
-
- int num_points_v[3] = {
- ((float)(res_max[0] - floor(xyz[0])) / step_size) + 0.5f,
- ((float)(res_max[1] - floor(xyz[1])) / step_size) + 0.5f,
- ((float)(res_max[2] - floor(xyz[2])) / step_size) + 0.5f
- };
-
- if (domain->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
- domain->axis_slice_method == AXIS_SLICE_SINGLE)
- {
- const int axis = (domain->slice_axis == SLICE_AXIS_AUTO) ?
- axis_dominant_v3_single(viewnormal) : domain->slice_axis - 1;
-
- xyz[axis] = (float)base_res[axis] * domain->slice_depth;
- num_points_v[axis] = 1;
- res_max[axis] = xyz[axis] + 1;
- }
-
- vector_draw_func func;
- int max_points;
-
- if (domain->vector_draw_type == VECTOR_DRAW_NEEDLE) {
- func = add_needle;
- max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 4 * 3;
- }
- else {
- func = add_streamline;
- max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 2;
- }
-
- float (*verts)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, "");
- float (*colors)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, "");
-
- int num_points = 0;
-
- for (float x = floor(xyz[0]); x < res_max[0]; x += step_size) {
- for (float y = floor(xyz[1]); y < res_max[1]; y += step_size) {
- for (float z = floor(xyz[2]); z < res_max[2]; z += step_size) {
- int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1];
-
- float pos[3] = {
- min[0] + ((float)x + 0.5f) * cell_size[0],
- min[1] + ((float)y + 0.5f) * cell_size[1],
- min[2] + ((float)z + 0.5f) * cell_size[2]
- };
-
- float vel[3] = {
- vel_x[index], vel_y[index], vel_z[index]
- };
-
- func(verts, colors, pos, vel, domain->vector_scale, cell_size[0], &num_points);
- }
- }
- }
-
- glLineWidth(1.0f);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, verts);
-
- glEnableClientState(GL_COLOR_ARRAY);
- glColorPointer(3, GL_FLOAT, 0, colors);
-
- glDrawArrays(GL_LINES, 0, num_points);
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
-
- MEM_freeN(verts);
- MEM_freeN(colors);
-#else
- UNUSED_VARS(domain, viewnormal);
-#endif
-}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index fed056333c0..0e8e5e1ee22 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -32,9 +32,11 @@
#include <string.h>
#include <stdio.h>
+#include "DNA_lightprobe_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_gpencil_types.h"
#include "MEM_guardedalloc.h"
@@ -43,31 +45,39 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_curve.h"
#include "BKE_icons.h"
-#include "BKE_library.h"
+#include "BKE_lattice.h"
#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "ED_space_api.h"
#include "ED_screen.h"
+#include "ED_transform.h"
-#include "GPU_compositing.h"
#include "GPU_framebuffer.h"
#include "GPU_material.h"
+#include "GPU_viewport.h"
+#include "GPU_matrix.h"
-#include "BIF_gl.h"
+#include "DRW_engine.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
#include "RNA_access.h"
+#include "UI_interface.h"
#include "UI_resources.h"
#ifdef WITH_PYTHON
@@ -106,17 +116,17 @@ ARegion *view3d_has_buttons_region(ScrArea *sa)
ARegion *view3d_has_tools_region(ScrArea *sa)
{
- ARegion *ar, *artool = NULL, *arprops = NULL, *arhead;
+ ARegion *ar, *artool = NULL, *arhead;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_TOOLS)
artool = ar;
- if (ar->regiontype == RGN_TYPE_TOOL_PROPS)
- arprops = ar;
}
/* tool region hide/unhide also hides props */
- if (arprops && artool) return artool;
+ if (artool) {
+ return artool;
+ }
if (artool == NULL) {
/* add subdiv level; after header */
@@ -135,15 +145,6 @@ ARegion *view3d_has_tools_region(ScrArea *sa)
artool->flag = RGN_FLAG_HIDDEN;
}
- if (arprops == NULL) {
- /* add extra subdivided region for tool properties */
- arprops = MEM_callocN(sizeof(ARegion), "tool props for view3d");
-
- BLI_insertlinkafter(&sa->regionbase, artool, arprops);
- arprops->regiontype = RGN_TYPE_TOOL_PROPS;
- arprops->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
- }
-
return artool;
}
@@ -250,7 +251,7 @@ void ED_view3d_init_mats_rv3d_gl(struct Object *ob, struct RegionView3D *rv3d)
/* we have to multiply instead of loading viewmatob to make
* it work with duplis using displists, otherwise it will
* override the dupli-matrix */
- glMultMatrixf(ob->obmat);
+ GPU_matrix_mul(ob->obmat);
}
#ifdef DEBUG
@@ -283,8 +284,6 @@ void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
BPy_END_ALLOW_THREADS;
#endif
- if (rv3d->render_engine->re)
- RE_Database_Free(rv3d->render_engine->re);
RE_engine_free(rv3d->render_engine);
rv3d->render_engine = NULL;
}
@@ -294,50 +293,64 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
{
wmWindowManager *wm = bmain->wm.first;
- if (v3d->drawtype != OB_RENDER) {
+ if (v3d->shading.type != OB_RENDER) {
ARegion *ar;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->regiondata)
+ if ((ar->regiontype == RGN_TYPE_WINDOW) && ar->regiondata) {
ED_view3d_stop_render_preview(wm, ar);
+ break;
+ }
}
}
}
/* ******************** default callbacks for view3d space ***************** */
-static SpaceLink *view3d_new(const bContext *C)
+static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
{
- Scene *scene = CTX_data_scene(C);
ARegion *ar;
View3D *v3d;
RegionView3D *rv3d;
v3d = MEM_callocN(sizeof(View3D), "initview3d");
v3d->spacetype = SPACE_VIEW3D;
- v3d->lay = v3d->layact = 1;
if (scene) {
- v3d->lay = v3d->layact = scene->lay;
v3d->camera = scene->camera;
}
v3d->scenelock = true;
v3d->grid = 1.0f;
v3d->gridlines = 16;
v3d->gridsubdiv = 10;
- v3d->drawtype = OB_SOLID;
+ BKE_screen_view3d_shading_init(&v3d->shading);
+
+ v3d->overlay.wireframe_threshold = 0.5f;
+ v3d->overlay.xray_alpha_bone = 0.5f;
+ v3d->overlay.texture_paint_mode_opacity = 0.8;
+ v3d->overlay.weight_paint_mode_opacity = 1.0f;
+ v3d->overlay.vertex_paint_mode_opacity = 0.8;
+ v3d->overlay.edit_flag = V3D_OVERLAY_EDIT_FACES |
+ V3D_OVERLAY_EDIT_SEAMS |
+ V3D_OVERLAY_EDIT_SHARP |
+ V3D_OVERLAY_EDIT_FREESTYLE_EDGE |
+ V3D_OVERLAY_EDIT_FREESTYLE_FACE |
+ V3D_OVERLAY_EDIT_EDGES |
+ V3D_OVERLAY_EDIT_CREASES |
+ V3D_OVERLAY_EDIT_BWEIGHTS |
+ V3D_OVERLAY_EDIT_CU_HANDLES |
+ V3D_OVERLAY_EDIT_CU_NORMALS;
v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR;
v3d->flag = V3D_SELECT_OUTLINE;
- v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_GPENCIL;
+ v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION;
- v3d->lens = 35.0f;
+ v3d->lens = 50.0f;
v3d->near = 0.01f;
v3d->far = 1000.0f;
- v3d->twflag |= U.tw_flag & V3D_USE_MANIPULATOR;
- v3d->twtype = V3D_MANIP_TRANSLATE;
- v3d->around = V3D_AROUND_CENTER_MEAN;
+ v3d->overlay.gpencil_paper_opacity = 0.5f;
+ v3d->overlay.gpencil_grid_opacity = 0.9f;
v3d->bundle_size = 0.2f;
v3d->bundle_drawtype = OB_PLAINAXES;
@@ -348,12 +361,16 @@ static SpaceLink *view3d_new(const bContext *C)
v3d->stereo3d_convergence_alpha = 0.15f;
v3d->stereo3d_volume_alpha = 0.05f;
+ /* grease pencil settings */
+ v3d->vertex_opacity = 1.0f;
+ v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
+
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for view3d");
BLI_addtail(&v3d->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->alignment = RGN_ALIGN_TOP;
/* tool shelf */
ar = MEM_callocN(sizeof(ARegion), "toolshelf for view3d");
@@ -363,14 +380,6 @@ static SpaceLink *view3d_new(const bContext *C)
ar->alignment = RGN_ALIGN_LEFT;
ar->flag = RGN_FLAG_HIDDEN;
- /* tool properties */
- ar = MEM_callocN(sizeof(ARegion), "tool properties for view3d");
-
- BLI_addtail(&v3d->regionbase, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
- ar->flag = RGN_FLAG_HIDDEN;
-
/* buttons/list view */
ar = MEM_callocN(sizeof(ARegion), "buttons for view3d");
@@ -399,30 +408,11 @@ static SpaceLink *view3d_new(const bContext *C)
static void view3d_free(SpaceLink *sl)
{
View3D *vd = (View3D *) sl;
- BGpic *bgpic;
-
- for (bgpic = vd->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->source == V3D_BGPIC_IMAGE) {
- id_us_min((ID *)bgpic->ima);
- }
- else if (bgpic->source == V3D_BGPIC_MOVIE) {
- id_us_min((ID *)bgpic->clip);
- }
- }
- BLI_freelistN(&vd->bgpicbase);
if (vd->localvd) MEM_freeN(vd->localvd);
if (vd->properties_storage) MEM_freeN(vd->properties_storage);
- /* matcap material, its preview rect gets freed via icons */
- if (vd->defmaterial) {
- if (vd->defmaterial->gpumaterial.first)
- GPU_material_free(&vd->defmaterial->gpumaterial);
- BKE_previewimg_free(&vd->defmaterial->preview);
- MEM_freeN(vd->defmaterial);
- }
-
if (vd->fx_settings.ssao)
MEM_freeN(vd->fx_settings.ssao);
if (vd->fx_settings.dof)
@@ -440,33 +430,19 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
{
View3D *v3do = (View3D *)sl;
View3D *v3dn = MEM_dupallocN(sl);
- BGpic *bgpic;
/* clear or remove stuff from old */
if (v3dn->localvd) {
v3dn->localvd = NULL;
v3dn->properties_storage = NULL;
- v3dn->lay = v3do->localvd->lay & 0xFFFFFF;
}
- if (v3dn->drawtype == OB_RENDER)
- v3dn->drawtype = OB_SOLID;
+ if (v3dn->shading.type == OB_RENDER)
+ v3dn->shading.type = OB_SOLID;
/* copy or clear inside new stuff */
- v3dn->defmaterial = NULL;
-
- BLI_duplicatelist(&v3dn->bgpicbase, &v3do->bgpicbase);
- for (bgpic = v3dn->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->source == V3D_BGPIC_IMAGE) {
- id_us_plus((ID *)bgpic->ima);
- }
- else if (bgpic->source == V3D_BGPIC_MOVIE) {
- id_us_plus((ID *)bgpic->clip);
- }
- }
-
v3dn->properties_storage = NULL;
if (v3dn->fx_settings.dof)
v3dn->fx_settings.dof = MEM_dupallocN(v3do->fx_settings.dof);
@@ -572,101 +548,87 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar)
GPU_offscreen_free(rv3d->gpuoffscreen);
rv3d->gpuoffscreen = NULL;
}
-
- if (rv3d->compositor) {
- GPU_fx_compositor_destroy(rv3d->compositor);
- rv3d->compositor = NULL;
- }
}
-static bool view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_OB)
- return 1;
- }
- return 0;
+ return WM_drag_ID(drag, ID_OB) != NULL;
}
-static bool view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool view3d_collection_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_GR)
- return 1;
- }
- return 0;
+ return WM_drag_ID(drag, ID_GR) != NULL;
}
-static bool view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_MA)
- return 1;
- }
- return 0;
+ return WM_drag_ID(drag, ID_MA) != NULL;
}
-static bool view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+static bool view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
{
- if (drag->type == WM_DRAG_ID) {
- ID *id = drag->poin;
- if (GS(id->name) == ID_IM)
- return 1;
+ if (drag->type == WM_DRAG_PATH) {
+ return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); /* rule might not work? */
}
- else if (drag->type == WM_DRAG_PATH) {
- if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)) /* rule might not work? */
- return 1;
+ else {
+ return WM_drag_ID(drag, ID_IM) != NULL;
}
- return 0;
}
-static bool view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+static bool view3d_ima_bg_is_camera_view(bContext *C)
{
- if (event->ctrl)
- return false;
-
- if (!ED_view3d_give_base_under_cursor(C, event->mval)) {
- return view3d_ima_drop_poll(C, drag, event);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if ((rv3d && (rv3d->persp == RV3D_CAMOB))) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d && v3d->camera && v3d->camera->type == OB_CAMERA) {
+ return true;
+ }
}
- return 0;
+ return false;
}
-static bool view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+static bool view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip)
{
- Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+ if (!view3d_ima_drop_poll(C, drag, event, tooltip)) {
+ return false;
+ }
- /* either holding and ctrl and no object, or dropping to empty */
- if (((base == NULL) && event->ctrl) ||
- ((base != NULL) && base->object->type == OB_EMPTY))
- {
- return view3d_ima_drop_poll(C, drag, event);
+ if (ED_view3d_is_object_under_cursor(C, event->mval)) {
+ return false;
}
- return 0;
+ return view3d_ima_bg_is_camera_view(C);
}
-static bool view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+static bool view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip)
{
- Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+ if (!view3d_ima_drop_poll(C, drag, event, tooltip)) {
+ return false;
+ }
+
+ Object *ob = ED_view3d_give_object_under_cursor(C, event->mval);
+
+ if (ob == NULL) {
+ return true;
+ }
- if (base && base->object->type == OB_MESH)
- return view3d_ima_drop_poll(C, drag, event);
- return 0;
+ if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
+ return true;
+ }
+
+ return false;
}
static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = drag->poin;
+ ID *id = WM_drag_ID(drag, ID_OB);
RNA_string_set(drop->ptr, "name", id->name + 2);
}
-static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop)
+static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = drag->poin;
+ ID *id = WM_drag_ID(drag, ID_GR);
drop->opcontext = WM_OP_EXEC_DEFAULT;
RNA_string_set(drop->ptr, "name", id->name + 2);
@@ -674,14 +636,14 @@ static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop)
static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = drag->poin;
+ ID *id = WM_drag_ID(drag, 0);
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = drag->poin;
+ ID *id = WM_drag_ID(drag, 0);
if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);
@@ -693,6 +655,25 @@ static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
}
}
+static void view3d_lightcache_update(bContext *C)
+{
+ PointerRNA op_ptr;
+
+ Scene *scene = CTX_data_scene(C);
+
+ if (strcmp(scene->r.engine, RE_engine_id_BLENDER_EEVEE) != 0) {
+ /* Only do auto bake if eevee is the active engine */
+ return;
+ }
+
+ WM_operator_properties_create(&op_ptr, "SCENE_OT_light_cache_bake");
+ RNA_int_set(&op_ptr, "delay", 200);
+ RNA_enum_set_identifier(C, &op_ptr, "subset", "DIRTY");
+
+ WM_operator_name_call(C, "SCENE_OT_light_cache_bake", WM_OP_INVOKE_DEFAULT, &op_ptr);
+
+ WM_operator_properties_free(&op_ptr);
+}
/* region dropbox definition */
static void view3d_dropboxes(void)
@@ -701,12 +682,38 @@ static void view3d_dropboxes(void)
WM_dropbox_add(lb, "OBJECT_OT_add_named", view3d_ob_drop_poll, view3d_ob_drop_copy);
WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy);
- WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy);
- WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy);
- WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
+ WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy);
+ WM_dropbox_add(lb, "OBJECT_OT_collection_instance_add", view3d_collection_drop_poll, view3d_collection_drop_copy);
}
+static void view3d_widgets(void)
+{
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(
+ &(const struct wmGizmoMapType_Params){SPACE_VIEW3D, RGN_TYPE_WINDOW});
+
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_spot);
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_area);
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_target);
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_force_field);
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera);
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera_view);
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_empty_image);
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_armature_spline);
+
+ WM_gizmogrouptype_append(TRANSFORM_GGT_gizmo);
+ WM_gizmogrouptype_append(VIEW3D_GGT_xform_cage);
+ WM_gizmogrouptype_append(VIEW3D_GGT_xform_shear);
+ WM_gizmogrouptype_append(VIEW3D_GGT_xform_extrude);
+ WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_elem);
+ WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_edgering);
+
+ WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
+ WM_gizmotype_append(VIEW3D_GT_ruler_item);
+
+ WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate);
+ WM_gizmotype_append(VIEW3D_GT_navigate_rotate);
+}
/* type callback, not region itself */
@@ -731,9 +738,6 @@ static void view3d_main_region_free(ARegion *ar)
if (rv3d->gpuoffscreen) {
GPU_offscreen_free(rv3d->gpuoffscreen);
}
- if (rv3d->compositor) {
- GPU_fx_compositor_destroy(rv3d->compositor);
- }
MEM_freeN(rv3d);
ar->regiondata = NULL;
@@ -757,50 +761,27 @@ static void *view3d_main_region_duplicate(void *poin)
new->render_engine = NULL;
new->sms = NULL;
new->smooth_timer = NULL;
- new->compositor = NULL;
return new;
}
return NULL;
}
-static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene)
+static void view3d_main_region_listener(
+ wmWindow *UNUSED(win), ScrArea *sa, ARegion *ar,
+ wmNotifier *wmn, const Scene *scene)
{
- wmWindow *win = wmn->wm->winactive;
- ScrArea *sa;
- unsigned int lay_used = 0;
- Base *base;
-
- if (!win) return;
-
- base = scene->base.first;
- while (base) {
- lay_used |= base->lay & ((1 << 20) - 1); /* ignore localview */
-
- if (lay_used == (1 << 20) - 1)
- break;
-
- base = base->next;
- }
-
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- if (BLI_findindex(&sa->regionbase, ar) != -1) {
- View3D *v3d = sa->spacedata.first;
- v3d->lay_used = lay_used;
- break;
- }
- }
- }
-}
-
-static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *wmn)
-{
- Scene *scene = sc->scene;
View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
+ wmGizmoMap *gzmap = ar->gizmo_map;
/* context changes */
switch (wmn->category) {
+ case NC_WM:
+ if (ELEM(wmn->data, ND_UNDO)) {
+ WM_gizmomap_tag_refresh(gzmap);
+ }
+ break;
case NC_ANIMATION:
switch (wmn->data) {
case ND_KEYFRAME_PROP:
@@ -820,21 +801,29 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
break;
case NC_SCENE:
switch (wmn->data) {
+ case ND_SCENEBROWSE:
case ND_LAYER_CONTENT:
- if (wmn->reference)
- view3d_recalc_used_layers(ar, wmn, wmn->reference);
ED_region_tag_redraw(ar);
+ WM_gizmomap_tag_refresh(gzmap);
+ break;
+ case ND_LAYER:
+ if (wmn->reference) {
+ BKE_screen_view3d_sync(v3d, wmn->reference);
+ }
+ ED_region_tag_redraw(ar);
+ WM_gizmomap_tag_refresh(gzmap);
break;
- case ND_FRAME:
- case ND_TRANSFORM:
case ND_OB_ACTIVE:
case ND_OB_SELECT:
+ ATTR_FALLTHROUGH;
+ case ND_FRAME:
+ case ND_TRANSFORM:
case ND_OB_VISIBLE:
- case ND_LAYER:
case ND_RENDER_OPTIONS:
case ND_MARKERS:
case ND_MODE:
ED_region_tag_redraw(ar);
+ WM_gizmomap_tag_refresh(gzmap);
break;
case ND_WORLD:
/* handled by space_view3d_listener() for v3d access */
@@ -842,7 +831,6 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
case ND_DRAW_RENDER_VIEWPORT:
{
if (v3d->camera && (scene == wmn->reference)) {
- RegionView3D *rv3d = ar->regiondata;
if (rv3d->persp == RV3D_CAMOB) {
ED_region_tag_redraw(ar);
}
@@ -867,6 +855,7 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
case ND_POINTCACHE:
case ND_LOD:
ED_region_tag_redraw(ar);
+ WM_gizmomap_tag_refresh(gzmap);
break;
}
switch (wmn->action) {
@@ -877,9 +866,13 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
break;
case NC_GEOM:
switch (wmn->data) {
+ case ND_SELECT:
+ {
+ WM_gizmomap_tag_refresh(gzmap);
+ ATTR_FALLTHROUGH;
+ }
case ND_DATA:
case ND_VERTEX_GROUP:
- case ND_SELECT:
ED_region_tag_redraw(ar);
break;
}
@@ -894,7 +887,6 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
case ND_DRAW_RENDER_VIEWPORT:
{
if (v3d->camera && (v3d->camera->data == wmn->reference)) {
- RegionView3D *rv3d = ar->regiondata;
if (rv3d->persp == RV3D_CAMOB) {
ED_region_tag_redraw(ar);
}
@@ -923,21 +915,13 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
switch (wmn->data) {
case ND_SHADING:
case ND_NODES:
- {
-#ifdef WITH_LEGACY_DEPSGRAPH
- Object *ob = OBACT;
- if ((v3d->drawtype == OB_MATERIAL) ||
- (ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) ||
- (v3d->drawtype == OB_TEXTURE &&
- (scene->gm.matmode == GAME_MAT_GLSL ||
- BKE_scene_use_new_shading_nodes(scene))) ||
- !DEG_depsgraph_use_legacy())
-#endif
- {
- ED_region_tag_redraw(ar);
- }
+ /* TODO(sergey) This is a bit too much updates, but needed to
+ * have proper material drivers update in the viewport.
+ *
+ * How to solve?
+ */
+ ED_region_tag_redraw(ar);
break;
- }
case ND_SHADING_DRAW:
case ND_SHADING_LINKS:
ED_region_tag_redraw(ar);
@@ -949,23 +933,29 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
case ND_WORLD_DRAW:
/* handled by space_view3d_listener() for v3d access */
break;
+ case ND_WORLD:
+ /* Needed for updating world materials */
+ ED_region_tag_redraw(ar);
+ break;
}
break;
case NC_LAMP:
switch (wmn->data) {
case ND_LIGHTING:
- if ((v3d->drawtype == OB_MATERIAL) ||
- (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) ||
- !DEG_depsgraph_use_legacy())
- {
- ED_region_tag_redraw(ar);
- }
+ /* TODO(sergey): This is a bit too much, but needed to
+ * handle updates from new depsgraph.
+ */
+ ED_region_tag_redraw(ar);
break;
case ND_LIGHTING_DRAW:
ED_region_tag_redraw(ar);
+ WM_gizmomap_tag_refresh(gzmap);
break;
}
break;
+ case NC_LIGHTPROBE:
+ ED_area_tag_refresh(sa);
+ break;
case NC_IMAGE:
/* this could be more fine grained checks if we had
* more context than just the region */
@@ -982,10 +972,10 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
case NC_SPACE:
if (wmn->data == ND_SPACE_VIEW3D) {
if (wmn->subtype == NS_VIEW3D_GPU) {
- RegionView3D *rv3d = ar->regiondata;
rv3d->rflag |= RV3D_GPULIGHT_UPDATE;
}
ED_region_tag_redraw(ar);
+ WM_gizmomap_tag_refresh(gzmap);
}
break;
case NC_ID:
@@ -998,15 +988,13 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
case ND_SKETCH:
ED_region_tag_redraw(ar);
break;
- case ND_SCREENBROWSE:
- case ND_SCREENDELETE:
- case ND_SCREENSET:
- /* screen was changed, need to update used layers due to NC_SCENE|ND_LAYER_CONTENT */
- /* updates used layers only for View3D in active screen */
- if (wmn->reference) {
- bScreen *sc_ref = wmn->reference;
- view3d_recalc_used_layers(ar, wmn, sc_ref->scene);
- }
+ case ND_LAYOUTBROWSE:
+ case ND_LAYOUTDELETE:
+ case ND_LAYOUTSET:
+ WM_gizmomap_tag_refresh(gzmap);
+ ED_region_tag_redraw(ar);
+ break;
+ case ND_LAYER:
ED_region_tag_redraw(ar);
break;
}
@@ -1020,12 +1008,104 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w
}
}
+static void view3d_main_region_message_subscribe(
+ const struct bContext *C,
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ /* Developer note: there are many properties that impact 3D view drawing,
+ * so instead of subscribing to individual properties, just subscribe to types
+ * accepting some redundant redraws.
+ *
+ * For other space types we might try avoid this, keep the 3D view as an exceptional case! */
+ wmMsgParams_RNA msg_key_params = {{{0}}};
+
+ /* Only subscribe to types. */
+ StructRNA *type_array[] = {
+ &RNA_Window,
+
+ /* These object have properties that impact drawing. */
+ &RNA_AreaLight,
+ &RNA_Camera,
+ &RNA_Light,
+ &RNA_Speaker,
+ &RNA_SunLight,
+
+ /* General types the 3D view depends on. */
+ &RNA_Object,
+ &RNA_UnitSettings, /* grid-floor */
+
+ &RNA_View3DOverlay,
+ &RNA_View3DShading,
+ &RNA_World,
+ };
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
+ msg_key_params.ptr.type = type_array[i];
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &msg_key_params,
+ &msg_sub_value_region_tag_redraw,
+ __func__);
+ }
+
+ /* Subscribe to a handful of other properties. */
+ RegionView3D *rv3d = ar->regiondata;
+
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, engine, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_region_tag_redraw);
+ if (rv3d->persp == RV3D_CAMOB) {
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, use_border, &msg_sub_value_region_tag_redraw);
+ }
+
+ WM_msg_subscribe_rna_anon_type(mbus, SceneEEVEE, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_type(mbus, SceneDisplay, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_type(mbus, ObjectDisplay, &msg_sub_value_region_tag_redraw);
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(view_layer);
+ if (obact != NULL) {
+ switch (obact->mode) {
+ case OB_MODE_PARTICLE_EDIT:
+ WM_msg_subscribe_rna_anon_type(mbus, ParticleEdit, &msg_sub_value_region_tag_redraw);
+ break;
+ default:
+ break;
+ }
+ }
+
+ {
+ wmMsgSubscribeValue msg_sub_value_region_tag_refresh = {
+ .owner = ar,
+ .user_data = sa,
+ .notify = WM_toolsystem_do_msg_notify_tag_refresh,
+ };
+ WM_msg_subscribe_rna_anon_prop(
+ mbus, Object, mode,
+ &msg_sub_value_region_tag_refresh);
+ }
+}
+
/* concept is to retrieve cursor type context-less */
-static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar))
+static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
- Scene *scene = win->screen->scene;
+ if (WM_cursor_set_from_tool(win, sa, ar)) {
+ return;
+ }
- if (scene->obedit) {
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ if (obedit) {
WM_cursor_set(win, CURSOR_EDIT);
}
else {
@@ -1048,7 +1128,9 @@ static void view3d_header_region_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-static void view3d_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void view3d_header_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1078,6 +1160,36 @@ static void view3d_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s
}
}
+static void view3d_header_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ wmMsgParams_RNA msg_key_params = {{{0}}};
+
+ /* Only subscribe to types. */
+ StructRNA *type_array[] = {
+ &RNA_View3DShading,
+ };
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
+ msg_key_params.ptr.type = type_array[i];
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &msg_key_params,
+ &msg_sub_value_region_tag_redraw,
+ __func__);
+ }
+}
+
+
/* add handlers, stuff you only do once or on area/region changes */
static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar)
{
@@ -1091,10 +1203,12 @@ static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar)
static void view3d_buttons_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, NULL, -1, true);
+ ED_region_panels_ex(C, ar, (const char * []){CTX_data_mode_string(C), NULL}, -1, true);
}
-static void view3d_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void view3d_buttons_region_listener(
+ wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar,
+ wmNotifier *wmn, const Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
@@ -1197,30 +1311,12 @@ static void view3d_tools_region_init(wmWindowManager *wm, ARegion *ar)
static void view3d_tools_region_draw(const bContext *C, ARegion *ar)
{
- ED_region_panels(C, ar, CTX_data_mode_string(C), -1, true);
-}
-
-static void view3d_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
-{
- /* context changes */
- switch (wmn->category) {
- case NC_WM:
- if (wmn->data == ND_HISTORY)
- ED_region_tag_redraw(ar);
- break;
- case NC_SCENE:
- if (wmn->data == ND_MODE)
- ED_region_tag_redraw(ar);
- break;
- case NC_SPACE:
- if (wmn->data == ND_SPACE_VIEW3D)
- ED_region_tag_redraw(ar);
- break;
- }
+ ED_region_panels_ex(C, ar, (const char * []){CTX_data_mode_string(C), NULL}, -1, true);
}
/* area (not region) level listener */
-static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNotifier *wmn)
+static void space_view3d_listener(
+ wmWindow *UNUSED(win), ScrArea *sa, struct wmNotifier *wmn, Scene *UNUSED(scene))
{
View3D *v3d = sa->spacedata.first;
@@ -1238,15 +1334,16 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot
switch (wmn->data) {
case ND_WORLD_DRAW:
case ND_WORLD:
- if (v3d->flag2 & V3D_SHOW_WORLD)
+ if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) {
ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
+ }
break;
}
break;
case NC_MATERIAL:
switch (wmn->data) {
case ND_NODES:
- if (v3d->drawtype == OB_TEXTURE)
+ if (v3d->shading.type == OB_TEXTURE)
ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
break;
}
@@ -1254,9 +1351,18 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot
}
}
+static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa))
+{
+ Scene *scene = CTX_data_scene(C);
+ LightCache *lcache = scene->eevee.light_cache;
+
+ if (lcache && (lcache->flag & LIGHTCACHE_UPDATE_AUTO) != 0) {
+ lcache->flag &= ~LIGHTCACHE_UPDATE_AUTO;
+ view3d_lightcache_update((bContext *)C);
+ }
+}
+
const char *view3d_context_dir[] = {
- "selected_objects", "selected_bases", "selected_editable_objects",
- "selected_editable_bases", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases",
"active_base", "active_object", NULL
};
@@ -1267,109 +1373,27 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, view3d_context_dir);
}
- else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) {
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const unsigned int lay = v3d ? v3d->lay : scene->lay;
- Base *base;
- 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)) {
- if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) {
- if (selected_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
- }
- }
- }
- CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
- return 1;
- }
- else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) {
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const unsigned int lay = v3d ? v3d->lay : scene->lay;
- Base *base;
- 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)) {
- if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) {
- if (0 == BKE_object_is_libdata(base->object)) {
- if (selected_editable_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
- }
- }
- }
- }
- CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
- return 1;
- }
- else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) {
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const unsigned int lay = v3d ? v3d->lay : scene->lay;
- Base *base;
- const bool visible_objects = CTX_data_equals(member, "visible_objects");
-
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & lay) {
- if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) {
- if (visible_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
- }
- }
- }
- CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
- return 1;
- }
- else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) {
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const unsigned int lay = v3d ? v3d->lay : scene->lay;
- Base *base;
- const bool selectable_objects = CTX_data_equals(member, "selectable_objects");
-
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & lay) {
- if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0 && (base->object->restrictflag & OB_RESTRICT_SELECT) == 0) {
- if (selectable_objects)
- CTX_data_id_list_add(result, &base->object->id);
- else
- CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
- }
- }
- }
- CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
- return 1;
- }
else if (CTX_data_equals(member, "active_base")) {
- View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
- const unsigned int lay = v3d ? v3d->lay : scene->lay;
- if (scene->basact && (scene->basact->lay & lay)) {
- Object *ob = scene->basact->object;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ if (view_layer->basact) {
+ Object *ob = view_layer->basact->object;
/* if hidden but in edit mode, we still display, can happen with animation */
- if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0 || (ob->mode & OB_MODE_EDIT))
- CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, scene->basact);
+ if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT)) {
+ CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact);
+ }
}
return 1;
}
else if (CTX_data_equals(member, "active_object")) {
- View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const unsigned int lay = v3d ? v3d->lay : scene->lay;
- if (scene->basact && (scene->basact->lay & lay)) {
- Object *ob = scene->basact->object;
- if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0 || (ob->mode & OB_MODE_EDIT))
- CTX_data_id_pointer_set(result, &scene->basact->object->id);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ if (view_layer->basact) {
+ Object *ob = view_layer->basact->object;
+ /* if hidden but in edit mode, we still display, can happen with animation */
+ if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT) != 0) {
+ CTX_data_id_pointer_set(result, &ob->id);
+ }
}
return 1;
@@ -1410,8 +1434,6 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i
/* Values in local-view aren't used, see: T52663 */
if (is_local == false) {
- /* Skip 'v3d->defmaterial', it's not library data. */
-
if ((ID *)v3d->ob_centre == old_id) {
v3d->ob_centre = (Object *)new_id;
/* Otherwise, bonename may remain valid... We could be smart and check this, too? */
@@ -1419,21 +1441,6 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i
v3d->ob_centre_bone[0] = '\0';
}
}
-
- if (ELEM(GS(old_id->name), ID_IM, ID_MC)) {
- for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- if ((ID *)bgpic->ima == old_id) {
- bgpic->ima = (Image *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
- if ((ID *)bgpic->clip == old_id) {
- bgpic->clip = (MovieClip *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
- }
- }
}
if (is_local) {
@@ -1455,23 +1462,26 @@ void ED_spacetype_view3d(void)
st->free = view3d_free;
st->init = view3d_init;
st->listener = space_view3d_listener;
+ st->refresh = space_view3d_refresh;
st->duplicate = view3d_duplicate;
st->operatortypes = view3d_operatortypes;
st->keymap = view3d_keymap;
st->dropboxes = view3d_dropboxes;
+ st->gizmos = view3d_widgets;
st->context = view3d_context;
st->id_remap = view3d_id_remap;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region");
art->regionid = RGN_TYPE_WINDOW;
- art->keymapflag = ED_KEYMAP_GPENCIL;
+ art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_GPENCIL;
art->draw = view3d_main_region_draw;
art->init = view3d_main_region_init;
art->exit = view3d_main_region_exit;
art->free = view3d_main_region_free;
art->duplicate = view3d_main_region_duplicate;
art->listener = view3d_main_region_listener;
+ art->message_subscribe = view3d_main_region_message_subscribe;
art->cursor = view3d_main_region_cursor;
art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */
BLI_addhead(&st->regiontypes, art);
@@ -1491,33 +1501,16 @@ void ED_spacetype_view3d(void)
/* regions: tool(bar) */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
- art->prefsizex = 160; /* XXX */
+ art->prefsizex = 58; /* XXX */
art->prefsizey = 50; /* XXX */
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
art->listener = view3d_buttons_region_listener;
+ art->message_subscribe = ED_region_generic_tools_region_message_subscribe;
+ art->snap_size = ED_region_generic_tools_region_snap_size;
art->init = view3d_tools_region_init;
art->draw = view3d_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
-#if 0
- /* unfinished still */
- view3d_toolshelf_register(art);
-#endif
-
- /* regions: tool properties */
- art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tool properties region");
- art->regionid = RGN_TYPE_TOOL_PROPS;
- art->prefsizex = 0;
- art->prefsizey = 120;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- art->listener = view3d_props_region_listener;
- art->init = view3d_tools_region_init;
- art->draw = view3d_tools_region_draw;
- BLI_addhead(&st->regiontypes, art);
-
- view3d_tool_props_register(art);
-
-
/* regions: header */
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d header region");
art->regionid = RGN_TYPE_HEADER;
@@ -1526,6 +1519,11 @@ void ED_spacetype_view3d(void)
art->listener = view3d_header_region_listener;
art->init = view3d_header_region_init;
art->draw = view3d_header_region_draw;
+ art->message_subscribe = view3d_header_region_message_subscribe;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* regions: hud */
+ art = ED_area_type_hud(st->spaceid);
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 05e9a34f492..0c4e370ef8c 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -55,12 +55,14 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_screen.h"
#include "BKE_editmesh.h"
#include "BKE_deform.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -68,6 +70,7 @@
#include "RNA_access.h"
#include "ED_armature.h"
+#include "ED_object.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -776,18 +779,18 @@ static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event)
return;
}
else {
- Scene *scene = CTX_data_scene(C);
- Object *ob = scene->basact->object;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = view_layer->basact->object;
ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
}
}
static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = OBACT;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
if (ob && (BKE_object_is_in_editmode_vgroup(ob) ||
BKE_object_is_in_wpaint_select_vert(ob)))
{
@@ -805,7 +808,8 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
{
uiBlock *block = uiLayoutAbsoluteBlock(pa->layout);
Scene *scene = CTX_data_scene(C);
- Object *ob = scene->basact->object;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = view_layer->basact->object;
MDeformVert *dv;
@@ -934,8 +938,9 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr)
colsub = uiLayoutColumn(split, true);
uiItemR(colsub, ptr, "location", 0, NULL, ICON_NONE);
colsub = uiLayoutColumn(split, true);
+ uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
uiItemL(colsub, "", ICON_NONE);
- uiItemR(colsub, ptr, "lock_location", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(colsub, ptr, "lock_location", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
split = uiLayoutSplit(layout, 0.8f, false);
@@ -944,30 +949,33 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr)
colsub = uiLayoutColumn(split, true);
uiItemR(colsub, ptr, "rotation_quaternion", 0, IFACE_("Rotation"), ICON_NONE);
colsub = uiLayoutColumn(split, true);
+ uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE);
if (RNA_boolean_get(ptr, "lock_rotations_4d"))
- uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE + UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE + UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
else
uiItemL(colsub, "", ICON_NONE);
- uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
break;
case ROT_MODE_AXISANGLE: /* axis angle */
colsub = uiLayoutColumn(split, true);
uiItemR(colsub, ptr, "rotation_axis_angle", 0, IFACE_("Rotation"), ICON_NONE);
colsub = uiLayoutColumn(split, true);
+ uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE);
if (RNA_boolean_get(ptr, "lock_rotations_4d"))
- uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
else
uiItemL(colsub, "", ICON_NONE);
- uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
break;
default: /* euler rotations */
colsub = uiLayoutColumn(split, true);
uiItemR(colsub, ptr, "rotation_euler", 0, IFACE_("Rotation"), ICON_NONE);
colsub = uiLayoutColumn(split, true);
+ uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
uiItemL(colsub, "", ICON_NONE);
- uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
break;
}
uiItemR(layout, ptr, "rotation_mode", 0, "", ICON_NONE);
@@ -976,8 +984,9 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr)
colsub = uiLayoutColumn(split, true);
uiItemR(colsub, ptr, "scale", 0, NULL, ICON_NONE);
colsub = uiLayoutColumn(split, true);
+ uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE);
uiItemL(colsub, "", ICON_NONE);
- uiItemR(colsub, ptr, "lock_scale", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(colsub, ptr, "lock_scale", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
if (ptr->type == &RNA_Object) {
Object *ob = ptr->data;
@@ -1095,9 +1104,9 @@ static void v3d_editmetaball_buts(uiLayout *layout, Object *ob)
static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event)
{
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
- Object *ob = OBACT;
+ Object *ob = OBACT(view_layer);
switch (event) {
@@ -1108,7 +1117,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
case B_OBJECTPANELMEDIAN:
if (ob) {
v3d_editvertex_buts(NULL, v3d, ob, 1.0);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
break;
}
@@ -1119,16 +1128,17 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event
static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt))
{
- Scene *scene = CTX_data_scene(C);
- return (scene->basact != NULL);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return (view_layer->basact != NULL);
}
static void view3d_panel_transform(const bContext *C, Panel *pa)
{
uiBlock *block;
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
- Object *ob = scene->basact->object;
+ Object *ob = view_layer->basact->object;
uiLayout *col;
block = uiLayoutGetBlock(pa->layout);
@@ -1160,6 +1170,11 @@ static void view3d_panel_transform(const bContext *C, Panel *pa)
}
}
+static void hide_collections_menu_draw(const bContext *C, Menu *menu)
+{
+ ED_hide_collections_menu_draw(C, menu->layout);
+}
+
void view3d_buttons_register(ARegionType *art)
{
PanelType *pt;
@@ -1167,6 +1182,7 @@ void view3d_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel object");
strcpy(pt->idname, "VIEW3D_PT_transform");
strcpy(pt->label, N_("Transform")); /* XXX C panels not available through RNA (bpy.types)! */
+ strcpy(pt->category, "View");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = view3d_panel_transform;
pt->poll = view3d_panel_transform_poll;
@@ -1175,10 +1191,20 @@ void view3d_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup");
strcpy(pt->idname, "VIEW3D_PT_vgroup");
strcpy(pt->label, N_("Vertex Weights")); /* XXX C panels are not available through RNA (bpy.types)! */
+ strcpy(pt->category, "View");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = view3d_panel_vgroup;
pt->poll = view3d_panel_vgroup_poll;
BLI_addtail(&art->paneltypes, pt);
+
+ MenuType *mt;
+
+ mt = MEM_callocN(sizeof(MenuType), "spacetype view3d menu collections");
+ strcpy(mt->idname, "VIEW3D_MT_collection");
+ strcpy(mt->label, N_("Collection"));
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = hide_collections_menu_draw;
+ WM_menutype_add(mt);
}
static int view3d_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1194,7 +1220,7 @@ static int view3d_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void VIEW3D_OT_properties(wmOperatorType *ot)
{
- ot->name = "Properties";
+ ot->name = "Toggle Sidebar";
ot->description = "Toggle the properties region visibility";
ot->idname = "VIEW3D_OT_properties";
@@ -1204,3 +1230,32 @@ void VIEW3D_OT_properties(wmOperatorType *ot)
/* flags */
ot->flag = 0;
}
+
+static int view3d_object_mode_menu(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ BKE_report(op->reports, RPT_WARNING, "No active object found");
+ return OPERATOR_CANCELLED;
+ }
+ else if (((ob->mode & OB_MODE_EDIT) == 0) && (ELEM(ob->type, OB_ARMATURE))) {
+ ED_object_mode_toggle(C, OB_MODE_POSE);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ UI_pie_menu_invoke(C, "VIEW3D_MT_object_mode_pie", CTX_wm_window(C)->eventstate);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void VIEW3D_OT_object_mode_pie_or_toggle(wmOperatorType *ot)
+{
+ ot->name = "Object Mode Menu";
+ ot->idname = "VIEW3D_OT_object_mode_pie_or_toggle";
+
+ ot->exec = view3d_object_mode_menu;
+ ot->poll = ED_operator_view3d_active;
+
+ /* flags */
+ ot->flag = 0;
+}
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 31956ee5f86..24871e16db6 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -54,8 +54,9 @@
#include "BLI_utildefines.h"
#include "BKE_object.h"
+#include "BKE_context.h"
-#include "BKE_depsgraph.h" /* for object updating */
+#include "DEG_depsgraph.h"
#include "ED_screen.h"
@@ -137,7 +138,7 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
* the view for first-person style navigation.
*/
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
- Scene *scene, View3D *v3d, RegionView3D *rv3d,
+ Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d,
const bool use_parent_root)
{
View3DCameraControl *vctrl;
@@ -177,7 +178,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
/* store the original camera loc and rot */
vctrl->obtfm = BKE_object_tfm_backup(ob_back);
- BKE_object_where_is_calc(scene, v3d->camera);
+ BKE_object_where_is_calc(depsgraph, scene, v3d->camera);
negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]);
rv3d->dist = 0.0;
@@ -242,7 +243,7 @@ void ED_view3d_cameracontrol_update(
ob_update = v3d->camera->parent;
while (ob_update) {
- DAG_id_tag_update(&ob_update->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob_update->id, OB_RECALC_OB);
ob_update = ob_update->parent;
}
@@ -264,7 +265,7 @@ void ED_view3d_cameracontrol_update(
BKE_object_apply_mat4(v3d->camera, view_mat, true, true);
- DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
+ DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
copy_v3_v3(v3d->camera->size, size_back);
@@ -299,10 +300,10 @@ void ED_view3d_cameracontrol_release(
/* store the original camera loc and rot */
BKE_object_tfm_restore(ob_back, vctrl->obtfm);
- DAG_id_tag_update(&ob_back->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob_back->id, OB_RECALC_OB);
}
else {
- /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
+ /* Non Camera we need to reset the view back to the original location because the user canceled*/
copy_qt_qt(rv3d->viewquat, vctrl->rot_backup);
rv3d->persp = vctrl->persp_backup;
}
@@ -311,7 +312,7 @@ void ED_view3d_cameracontrol_release(
rv3d->dist = vctrl->dist_backup;
}
else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */
- DAG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), OB_RECALC_OB);
+ DEG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), OB_RECALC_OB);
/* always, is set to zero otherwise */
copy_v3_v3(rv3d->ofs, vctrl->ofs_backup);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 1cf2e71f2bf..4f572e3a337 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -28,958 +28,290 @@
* \ingroup spview3d
*/
-#include <string.h>
-#include <stdio.h>
#include <math.h>
-#include "DNA_armature_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_customdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_group_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_world_types.h"
-#include "DNA_brush_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_jitter_2d.h"
-#include "BLI_utildefines.h"
-#include "BLI_endian_switch.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
#include "BLI_threads.h"
+#include "BLI_jitter_2d.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
-#include "BKE_anim.h"
#include "BKE_camera.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_image.h"
+#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "BKE_object.h"
-#include "BKE_global.h"
#include "BKE_paint.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
#include "BKE_unit.h"
-#include "BKE_movieclip.h"
-#include "RE_engine.h"
-
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-#include "IMB_colormanagement.h"
+#include "BLF_api.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "BLT_translation.h"
-#include "WM_api.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_windowmanager_types.h"
-#include "BLF_api.h"
-#include "BLT_translation.h"
+#include "DRW_engine.h"
#include "ED_armature.h"
#include "ED_keyframing.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
-#include "ED_space_api.h"
-#include "ED_screen_types.h"
#include "ED_transform.h"
-#include "UI_interface.h"
-#include "UI_interface_icons.h"
-#include "UI_resources.h"
+#include "DEG_depsgraph_query.h"
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
#include "GPU_draw.h"
-#include "GPU_framebuffer.h"
+#include "GPU_matrix.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
#include "GPU_material.h"
-#include "GPU_compositing.h"
-#include "GPU_extensions.h"
-#include "GPU_select.h"
-
-#include "view3d_intern.h" /* own include */
-
-/* prototypes */
-static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d);
-static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect);
-static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
- float winmat[4][4], const char *viewname);
-
-/* handy utility for drawing shapes in the viewport for arbitrary code.
- * could add lines and points too */
-// #define DEBUG_DRAW
-#ifdef DEBUG_DRAW
-static void bl_debug_draw(void);
-/* add these locally when using these functions for testing */
-extern void bl_debug_draw_quad_clear(void);
-extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]);
-extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]);
-extern void bl_debug_color_set(const unsigned int col);
-#endif
-
-void circf(float x, float y, float rad)
-{
- GLUquadricObj *qobj = gluNewQuadric();
-
- gluQuadricDrawStyle(qobj, GLU_FILL);
-
- glPushMatrix();
-
- glTranslatef(x, y, 0.0);
-
- gluDisk(qobj, 0.0, rad, 32, 1);
-
- glPopMatrix();
-
- gluDeleteQuadric(qobj);
-}
-
-void circ(float x, float y, float rad)
-{
- GLUquadricObj *qobj = gluNewQuadric();
-
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
-
- glPushMatrix();
-
- glTranslatef(x, y, 0.0);
-
- gluDisk(qobj, 0.0, rad, 32, 1);
-
- glPopMatrix();
-
- gluDeleteQuadric(qobj);
-}
-
-
-/* ********* custom clipping *********** */
-
-static void view3d_draw_clipping(RegionView3D *rv3d)
-{
- BoundBox *bb = rv3d->clipbb;
-
- if (bb) {
- const unsigned int clipping_index[6][4] = {
- {0, 1, 2, 3},
- {0, 4, 5, 1},
- {4, 7, 6, 5},
- {7, 3, 2, 6},
- {1, 5, 6, 2},
- {7, 4, 0, 3}
- };
-
- /* fill in zero alpha for rendering & re-projection [#31530] */
- unsigned char col[4];
- UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col);
- glColor4ubv(col);
-
- glEnable(GL_BLEND);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, bb->vec);
- glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisable(GL_BLEND);
- }
-}
-
-void ED_view3d_clipping_set(RegionView3D *rv3d)
-{
- double plane[4];
- const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
- unsigned int a;
-
- for (a = 0; a < tot; a++) {
- copy_v4db_v4fl(plane, rv3d->clip[a]);
- glClipPlane(GL_CLIP_PLANE0 + a, plane);
- glEnable(GL_CLIP_PLANE0 + a);
- }
-}
-
-/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */
-void ED_view3d_clipping_disable(void)
-{
- unsigned int a;
-
- for (a = 0; a < 6; a++) {
- glDisable(GL_CLIP_PLANE0 + a);
- }
-}
-void ED_view3d_clipping_enable(void)
-{
- unsigned int a;
-
- for (a = 0; a < 6; a++) {
- glEnable(GL_CLIP_PLANE0 + a);
- }
-}
-
-static bool view3d_clipping_test(const float co[3], const float clip[6][4])
-{
- if (plane_point_side_v3(clip[0], co) > 0.0f)
- if (plane_point_side_v3(clip[1], co) > 0.0f)
- if (plane_point_side_v3(clip[2], co) > 0.0f)
- if (plane_point_side_v3(clip[3], co) > 0.0f)
- return false;
-
- return true;
-}
-
-/* for 'local' ED_view3d_clipping_local must run first
- * then all comparisons can be done in localspace */
-bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
-{
- return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
-}
-
-/* ********* end custom clipping *********** */
-
-
-static void drawgrid_draw(ARegion *ar, double wx, double wy, double x, double y, double dx)
-{
- double verts[2][2];
+#include "GPU_viewport.h"
+#include "GPU_state.h"
+#include "GPU_framebuffer.h"
- x += (wx);
- y += (wy);
+#include "MEM_guardedalloc.h"
- /* set fixed 'Y' */
- verts[0][1] = 0.0f;
- verts[1][1] = (double)ar->winy;
+#include "UI_interface.h"
+#include "UI_resources.h"
- /* iter over 'X' */
- verts[0][0] = verts[1][0] = x - dx * floor(x / dx);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_DOUBLE, 0, verts);
+#include "RE_engine.h"
- while (verts[0][0] < ar->winx) {
- glDrawArrays(GL_LINES, 0, 2);
- verts[0][0] = verts[1][0] = verts[0][0] + dx;
- }
+#include "WM_api.h"
+#include "WM_types.h"
- /* set fixed 'X' */
- verts[0][0] = 0.0f;
- verts[1][0] = (double)ar->winx;
+#include "RNA_access.h"
- /* iter over 'Y' */
- verts[0][1] = verts[1][1] = y - dx * floor(y / dx);
- while (verts[0][1] < ar->winy) {
- glDrawArrays(GL_LINES, 0, 2);
- verts[0][1] = verts[1][1] = verts[0][1] + dx;
- }
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
- glDisableClientState(GL_VERTEX_ARRAY);
-}
+#include "view3d_intern.h" /* own include */
-#define GRID_MIN_PX_D 6.0
-#define GRID_MIN_PX_F 6.0f
+/* ******************** general functions ***************** */
-static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit)
+/**
+ * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
+ */
+void ED_view3d_update_viewmat(
+ Depsgraph *depsgraph, Scene *scene, View3D *v3d, ARegion *ar,
+ float viewmat[4][4], float winmat[4][4], const rcti *rect)
{
- /* extern short bgpicmode; */
RegionView3D *rv3d = ar->regiondata;
- double wx, wy, x, y, fw, fx, fy, dx;
- double vec4[4];
- unsigned char col[3], col2[3];
- fx = rv3d->persmat[3][0];
- fy = rv3d->persmat[3][1];
- fw = rv3d->persmat[3][3];
-
- wx = (ar->winx / 2.0); /* because of rounding errors, grid at wrong location */
- wy = (ar->winy / 2.0);
-
- x = (wx) * fx / fw;
- y = (wy) * fy / fw;
-
- vec4[0] = vec4[1] = v3d->grid;
-
- vec4[2] = 0.0;
- vec4[3] = 1.0;
- mul_m4_v4d(rv3d->persmat, vec4);
- fx = vec4[0];
- fy = vec4[1];
- fw = vec4[3];
-
- dx = fabs(x - (wx) * fx / fw);
- if (dx == 0) dx = fabs(y - (wy) * fy / fw);
-
- glLineWidth(1.0f);
-
- glDepthMask(GL_FALSE); /* disable write in zbuffer */
-
- /* check zoom out */
- UI_ThemeColor(TH_GRID);
-
- if (unit->system) {
- /* Use GRID_MIN_PX * 2 for units because very very small grid
- * items are less useful when dealing with units */
- const void *usys;
- int len, i;
- double dx_scalar;
- float blend_fac;
-
- bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len);
-
- if (usys) {
- i = len;
- while (i--) {
- double scalar = bUnit_GetScaler(usys, i);
-
- dx_scalar = dx * scalar / (double)unit->scale_length;
- if (dx_scalar < (GRID_MIN_PX_D * 2.0))
- continue;
-
- /* Store the smallest drawn grid size units name so users know how big each grid cell is */
- if (*grid_unit == NULL) {
- *grid_unit = bUnit_GetNameDisplay(usys, i);
- rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length);
- }
- blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar);
-
- /* tweak to have the fade a bit nicer */
- blend_fac = (blend_fac * blend_fac) * 2.0f;
- CLAMP(blend_fac, 0.3f, 1.0f);
-
-
- UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, blend_fac);
+ /* setup window matrices */
+ if (winmat)
+ copy_m4_m4(rv3d->winmat, winmat);
+ else
+ view3d_winmatrix_set(depsgraph, ar, v3d, rect);
- drawgrid_draw(ar, wx, wy, x, y, dx_scalar);
- }
- }
+ /* setup view matrix */
+ if (viewmat) {
+ copy_m4_m4(rv3d->viewmat, viewmat);
}
else {
- const double sublines = v3d->gridsubdiv;
- const float sublines_fl = v3d->gridsubdiv;
-
- if (dx < GRID_MIN_PX_D) {
- rv3d->gridview *= sublines_fl;
- dx *= sublines;
-
- if (dx < GRID_MIN_PX_D) {
- rv3d->gridview *= sublines_fl;
- dx *= sublines;
-
- if (dx < GRID_MIN_PX_D) {
- rv3d->gridview *= sublines_fl;
- dx *= sublines;
- if (dx < GRID_MIN_PX_D) {
- /* pass */
- }
- else {
- UI_ThemeColor(TH_GRID);
- drawgrid_draw(ar, wx, wy, x, y, dx);
- }
- }
- else { /* start blending out */
- UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
- drawgrid_draw(ar, wx, wy, x, y, dx);
-
- UI_ThemeColor(TH_GRID);
- drawgrid_draw(ar, wx, wy, x, y, sublines * dx);
- }
- }
- else { /* start blending out (GRID_MIN_PX < dx < (GRID_MIN_PX * 10)) */
- UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
- drawgrid_draw(ar, wx, wy, x, y, dx);
-
- UI_ThemeColor(TH_GRID);
- drawgrid_draw(ar, wx, wy, x, y, sublines * dx);
- }
- }
- else {
- if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */
- rv3d->gridview /= sublines_fl;
- dx /= sublines;
- if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */
- rv3d->gridview /= sublines_fl;
- dx /= sublines;
- if (dx > (GRID_MIN_PX_D * 10.0)) {
- UI_ThemeColor(TH_GRID);
- drawgrid_draw(ar, wx, wy, x, y, dx);
- }
- else {
- UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
- drawgrid_draw(ar, wx, wy, x, y, dx);
- UI_ThemeColor(TH_GRID);
- drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
- }
- }
- else {
- UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
- drawgrid_draw(ar, wx, wy, x, y, dx);
- UI_ThemeColor(TH_GRID);
- drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
- }
- }
- else {
- UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
- drawgrid_draw(ar, wx, wy, x, y, dx);
- UI_ThemeColor(TH_GRID);
- drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
- }
+ float rect_scale[2];
+ if (rect) {
+ rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx;
+ rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy;
}
+ /* note: calls BKE_object_where_is_calc for camera... */
+ view3d_viewmatrix_set(depsgraph, scene, v3d, rv3d, rect ? rect_scale : NULL);
}
+ /* update utility matrices */
+ mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
+ invert_m4_m4(rv3d->persinv, rv3d->persmat);
+ invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
+ /* calculate GLSL view dependent values */
- x += (wx);
- y += (wy);
- UI_GetThemeColor3ubv(TH_GRID, col);
-
- setlinestyle(0);
-
- /* center cross */
- /* horizontal line */
- if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
- UI_make_axis_color(col, col2, 'Y');
- else UI_make_axis_color(col, col2, 'X');
- glColor3ubv(col2);
-
- fdrawline(0.0, y, (float)ar->winx, y);
+ /* store window coordinates scaling/offset */
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ rctf cameraborder;
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &cameraborder, false);
+ rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder);
+ rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder);
- /* vertical line */
- if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
- UI_make_axis_color(col, col2, 'Y');
- else UI_make_axis_color(col, col2, 'Z');
- glColor3ubv(col2);
+ rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx;
+ rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy;
+ }
+ else {
+ rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
+ rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
+ }
- fdrawline(x, 0.0, x, (float)ar->winy);
+ /* calculate pixelsize factor once, is used for lamps and obcenters */
+ {
+ /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])'
+ * because of float point precision problems at large values [#23908] */
+ float v1[3], v2[3];
+ float len_px, len_sc;
- glDepthMask(GL_TRUE); /* enable write in zbuffer */
-}
-#undef GRID_MIN_PX
+ v1[0] = rv3d->persmat[0][0];
+ v1[1] = rv3d->persmat[1][0];
+ v1[2] = rv3d->persmat[2][0];
-/** could move this elsewhere, but tied into #ED_view3d_grid_scale */
-float ED_scene_grid_scale(Scene *scene, const char **grid_unit)
-{
- /* apply units */
- if (scene->unit.system) {
- const void *usys;
- int len;
+ v2[0] = rv3d->persmat[0][1];
+ v2[1] = rv3d->persmat[1][1];
+ v2[2] = rv3d->persmat[2][1];
- bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
+ len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
+ len_sc = (float)MAX2(ar->winx, ar->winy);
- if (usys) {
- int i = bUnit_GetBaseUnit(usys);
- if (grid_unit)
- *grid_unit = bUnit_GetNameDisplay(usys, i);
- return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length;
- }
+ rv3d->pixsize = len_px / len_sc;
}
-
- return 1.0f;
-}
-
-float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
-{
- return v3d->grid * ED_scene_grid_scale(scene, grid_unit);
}
-static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth)
+static void view3d_main_region_setup_view(
+ Depsgraph *depsgraph, Scene *scene,
+ View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect)
{
- float grid, grid_scale;
- unsigned char col_grid[3];
- const int gridlines = v3d->gridlines / 2;
-
- if (v3d->gridlines < 3) return;
-
- /* use 'grid_scale' instead of 'v3d->grid' from now on */
- grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
- grid = gridlines * grid_scale;
-
- if (!write_depth)
- glDepthMask(GL_FALSE);
-
- UI_GetThemeColor3ubv(TH_GRID, col_grid);
-
- glLineWidth(1);
-
- /* draw the Y axis and/or grid lines */
- if (v3d->gridflag & V3D_SHOW_FLOOR) {
- const int sublines = v3d->gridsubdiv;
- float vert[4][3] = {{0.0f}};
- unsigned char col_bg[3];
- unsigned char col_grid_emphasise[3], col_grid_light[3];
- int a;
- int prev_emphasise = -1;
-
- UI_GetThemeColor3ubv(TH_BACK, col_bg);
-
- /* emphasise division lines lighter instead of darker, if background is darker than grid */
- UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10);
- UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise,
- (((col_grid[0] + col_grid[1] + col_grid[2]) + 30) >
- (col_bg[0] + col_bg[1] + col_bg[2])) ? 20 : -10);
-
- /* set fixed axis */
- vert[0][0] = vert[2][1] = grid;
- vert[1][0] = vert[3][1] = -grid;
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, vert);
-
- for (a = -gridlines; a <= gridlines; a++) {
- const float line = a * grid_scale;
- const int is_emphasise = (a % sublines) == 0;
-
- if (is_emphasise != prev_emphasise) {
- glColor3ubv(is_emphasise ? col_grid_emphasise : col_grid_light);
- prev_emphasise = is_emphasise;
- }
-
- /* set variable axis */
- vert[0][1] = vert[1][1] = vert[2][0] = vert[3][0] = line;
-
- glDrawArrays(GL_LINES, 0, 4);
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- }
+ RegionView3D *rv3d = ar->regiondata;
- /* draw the Z axis line */
- /* check for the 'show Z axis' preference */
- if (v3d->gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
- glBegin(GL_LINES);
- int axis;
- for (axis = 0; axis < 3; axis++) {
- if (v3d->gridflag & (V3D_SHOW_X << axis)) {
- float vert[3];
- unsigned char tcol[3];
-
- UI_make_axis_color(col_grid, tcol, 'X' + axis);
- glColor3ubv(tcol);
-
- zero_v3(vert);
- vert[axis] = grid;
- glVertex3fv(vert);
- vert[axis] = -grid;
- glVertex3fv(vert);
- }
- }
- glEnd();
- }
+ ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, rect);
- glDepthMask(GL_TRUE);
+ /* set for opengl */
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
}
-
-static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d)
+static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d)
{
- int co[2];
-
- /* we don't want the clipping for cursor */
- if (ED_view3d_project_int_global(ar, ED_view3d_cursor3d_get(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- const float f5 = 0.25f * U.widget_unit;
- const float f10 = 0.5f * U.widget_unit;
- const float f20 = U.widget_unit;
-
- glLineWidth(1);
- setlinestyle(0);
- cpack(0xFF);
- circ((float)co[0], (float)co[1], f10);
- setlinestyle(4);
- cpack(0xFFFFFF);
- circ((float)co[0], (float)co[1], f10);
- setlinestyle(0);
-
- UI_ThemeColor(TH_VIEW_OVERLAY);
- sdrawline(co[0] - f20, co[1], co[0] - f5, co[1]);
- sdrawline(co[0] + f5, co[1], co[0] + f20, co[1]);
- sdrawline(co[0], co[1] - f20, co[0], co[1] - f5);
- sdrawline(co[0], co[1] + f5, co[0], co[1] + f20);
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ return false;
}
-}
-
-/* Draw a live substitute of the view icon, which is always shown
- * colors copied from transform_manipulator.c, we should keep these matching. */
-static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
-{
- const float k = U.rvisize * U.pixelsize; /* axis size */
- const float toll = 0.5; /* used to see when view is quasi-orthogonal */
- float startx = k + 1.0f; /* axis center in screen coordinates, x=y */
- float starty = k + 1.0f;
- float ydisp = 0.0; /* vertical displacement to allow obj info text */
- int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */
- float vec[3];
- float dx, dy;
-
- int axis_order[3] = {0, 1, 2};
- int axis_i;
-
- startx += rect->xmin;
- starty += rect->ymin;
-
- axis_sort_v3(rv3d->viewinv[2], axis_order);
-
- /* thickness of lines is proportional to k */
- glLineWidth(2);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- for (axis_i = 0; axis_i < 3; axis_i++) {
- int i = axis_order[axis_i];
- const char axis_text[2] = {'x' + i, '\0'};
-
- zero_v3(vec);
- vec[i] = 1.0f;
- mul_qt_v3(rv3d->viewquat, vec);
- dx = vec[0] * k;
- dy = vec[1] * k;
-
- UI_ThemeColorShadeAlpha(TH_AXIS_X + i, 0, bright);
- glBegin(GL_LINES);
- glVertex2f(startx, starty + ydisp);
- glVertex2f(startx + dx, starty + dy + ydisp);
- glEnd();
-
- if (fabsf(dx) > toll || fabsf(dy) > toll) {
- BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1);
-
- /* BLF_draw_default disables blending */
- glEnable(GL_BLEND);
- }
+ if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) {
+ return false;
}
- glDisable(GL_BLEND);
-}
-
-#ifdef WITH_INPUT_NDOF
-/* draw center and axis of rotation for ongoing 3D mouse navigation */
-static void draw_rotation_guide(RegionView3D *rv3d)
-{
- float o[3]; /* center of rotation */
- float end[3]; /* endpoints for drawing */
-
- float color[4] = {0.0f, 0.4235f, 1.0f, 1.0f}; /* bright blue so it matches device LEDs */
-
- negate_v3_v3(o, rv3d->ofs);
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glPointSize(5);
- glEnable(GL_POINT_SMOOTH);
- glDepthMask(0); /* don't overwrite zbuf */
-
- if (rv3d->rot_angle != 0.0f) {
- /* -- draw rotation axis -- */
- float scaled_axis[3];
- const float scale = rv3d->dist;
- mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale);
-
-
- glBegin(GL_LINE_STRIP);
- color[3] = 0.0f; /* more transparent toward the ends */
- glColor4fv(color);
- add_v3_v3v3(end, o, scaled_axis);
- glVertex3fv(end);
-
-#if 0
- color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
- /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */
-#endif
-
- color[3] = 0.5f; /* more opaque toward the center */
- glColor4fv(color);
- glVertex3fv(o);
-
- color[3] = 0.0f;
- glColor4fv(color);
- sub_v3_v3v3(end, o, scaled_axis);
- glVertex3fv(end);
- glEnd();
-
- /* -- draw ring around rotation center -- */
- {
-#define ROT_AXIS_DETAIL 13
-
- const float s = 0.05f * scale;
- const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL);
- float angle;
- int i;
-
- float q[4]; /* rotate ring so it's perpendicular to axis */
- const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
- if (!upright) {
- const float up[3] = {0.0f, 0.0f, 1.0f};
- float vis_angle, vis_axis[3];
-
- cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
- vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis));
- axis_angle_to_quat(q, vis_axis, vis_angle);
+ switch (v3d->stereo3d_camera) {
+ case STEREO_MONO_ID:
+ return false;
+ break;
+ case STEREO_3D_ID:
+ /* win will be NULL when calling this from the selection or draw loop. */
+ if ((win == NULL) || (WM_stereo3d_enabled(win, true) == false)) {
+ return false;
}
-
- color[3] = 0.25f; /* somewhat faint */
- glColor4fv(color);
- glBegin(GL_LINE_LOOP);
- for (i = 0, angle = 0.0f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
- float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
-
- if (!upright) {
- mul_qt_v3(q, p);
- }
-
- add_v3_v3(p, o);
- glVertex3fv(p);
+ if (((scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) != 0) &&
+ !BKE_scene_multiview_is_stereo3d(&scene->r))
+ {
+ return false;
}
- glEnd();
-
-#undef ROT_AXIS_DETAIL
- }
-
- color[3] = 1.0f; /* solid dot */
- }
- else
- color[3] = 0.5f; /* see-through dot */
-
- /* -- draw rotation center -- */
- glColor4fv(color);
- glBegin(GL_POINTS);
- glVertex3fv(o);
- glEnd();
-
-#if 0
- /* find screen coordinates for rotation center, then draw pretty icon */
- mul_m4_v3(rv3d->persinv, rot_center);
- UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
- /* ^^ just playing around, does not work */
-#endif
-
- glDisable(GL_BLEND);
- glDisable(GL_POINT_SMOOTH);
- glDepthMask(1);
-}
-#endif /* WITH_INPUT_NDOF */
-
-static void draw_view_icon(RegionView3D *rv3d, rcti *rect)
-{
- BIFIconID icon;
-
- if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
- icon = ICON_AXIS_TOP;
- else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
- icon = ICON_AXIS_FRONT;
- else if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
- icon = ICON_AXIS_SIDE;
- else return;
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon);
-
- glDisable(GL_BLEND);
-}
-
-static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d)
-{
- const char *name = NULL;
-
- switch (rv3d->view) {
- case RV3D_VIEW_FRONT:
- if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho");
- else name = IFACE_("Front Persp");
- break;
- case RV3D_VIEW_BACK:
- if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho");
- else name = IFACE_("Back Persp");
- break;
- case RV3D_VIEW_TOP:
- if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Ortho");
- else name = IFACE_("Top Persp");
- break;
- case RV3D_VIEW_BOTTOM:
- if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Ortho");
- else name = IFACE_("Bottom Persp");
- break;
- case RV3D_VIEW_RIGHT:
- if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Ortho");
- else name = IFACE_("Right Persp");
- break;
- case RV3D_VIEW_LEFT:
- if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Ortho");
- else name = IFACE_("Left Persp");
break;
-
+ /* We always need the stereo calculation for left and right cameras. */
+ case STEREO_LEFT_ID:
+ case STEREO_RIGHT_ID:
default:
- if (rv3d->persp == RV3D_CAMOB) {
- if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) {
- Camera *cam;
- cam = v3d->camera->data;
- if (cam->type == CAM_PERSP) {
- name = IFACE_("Camera Persp");
- }
- else if (cam->type == CAM_ORTHO) {
- name = IFACE_("Camera Ortho");
- }
- else {
- BLI_assert(cam->type == CAM_PANO);
- name = IFACE_("Camera Pano");
- }
- }
- else {
- name = IFACE_("Object as Camera");
- }
- }
- else {
- name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Ortho") : IFACE_("User Persp");
- }
break;
}
-
- return name;
+ return true;
}
-static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect)
-{
- RegionView3D *rv3d = ar->regiondata;
- const char *name = view3d_get_name(v3d, rv3d);
- /* increase size for unicode languages (Chinese in utf-8...) */
-#ifdef WITH_INTERNATIONAL
- char tmpstr[96];
-#else
- char tmpstr[32];
-#endif
-
- if (v3d->localvd) {
- BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name);
- name = tmpstr;
- }
-
- UI_ThemeColor(TH_TEXT_HI);
-#ifdef WITH_INTERNATIONAL
- BLF_draw_default(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr));
-#else
- BLF_draw_default_ascii(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr));
-#endif
-}
-/* draw info beside axes in bottom left-corner:
- * framenum, object name, bone name (if available), marker name (if available)
+/* setup the view and win matrices for the multiview cameras
+ *
+ * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called
+ * we have no winmatrix (i.e., projection matrix) defined at that time.
+ * Since the camera and the camera shift are needed for the winmat calculation
+ * we do a small hack to replace it temporarily so we don't need to change the
+ * view3d)main_region_setup_view() code to account for that.
*/
-
-static void draw_selected_name(Scene *scene, Object *ob, const rcti *rect)
+static void view3d_stereo3d_setup(
+ Depsgraph *depsgraph, Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect)
{
- const int cfra = CFRA;
- const char *msg_pin = " (Pinned)";
- const char *msg_sep = " : ";
+ bool is_left;
+ const char *names[2] = { STEREO_LEFT_NAME, STEREO_RIGHT_NAME };
+ const char *viewname;
- char info[300];
- const char *markern;
- char *s = info;
- short offset = 1.5f * UI_UNIT_X + rect->xmin;
+ /* show only left or right camera */
+ if (v3d->stereo3d_camera != STEREO_3D_ID)
+ v3d->multiview_eye = v3d->stereo3d_camera;
- s += sprintf(s, "(%d)", cfra);
+ is_left = v3d->multiview_eye == STEREO_LEFT_ID;
+ viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
- /*
- * info can contain:
- * - a frame (7 + 2)
- * - 3 object names (MAX_NAME)
- * - 2 BREAD_CRUMB_SEPARATORs (6)
- * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room!
- * - a marker name (MAX_NAME + 3)
- */
+ /* update the viewport matrices with the new camera */
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ Camera *data;
+ float viewmat[4][4];
+ float shiftx;
- /* get name of marker on current frame (if available) */
- markern = BKE_scene_find_marker_name(scene, cfra);
+ data = (Camera *)v3d->camera->data;
+ shiftx = data->shiftx;
- /* check if there is an object */
- if (ob) {
- *s++ = ' ';
- s += BLI_strcpy_rlen(s, ob->id.name + 2);
+ BLI_thread_lock(LOCK_VIEW3D);
+ data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
- /* name(s) to display depends on type of object */
- if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
+ BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
+ view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, NULL, rect);
- /* show name of active bone too (if possible) */
- if (arm->edbo) {
- if (arm->act_edbone) {
- s += BLI_strcpy_rlen(s, msg_sep);
- s += BLI_strcpy_rlen(s, arm->act_edbone->name);
- }
- }
- else if (ob->mode & OB_MODE_POSE) {
- if (arm->act_bone) {
+ data->shiftx = shiftx;
+ BLI_thread_unlock(LOCK_VIEW3D);
+ }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ float viewmat[4][4];
+ Object *view_ob = v3d->camera;
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
- if (arm->act_bone->layer & arm->layer) {
- s += BLI_strcpy_rlen(s, msg_sep);
- s += BLI_strcpy_rlen(s, arm->act_bone->name);
- }
- }
- }
- }
- else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
- Key *key = NULL;
- KeyBlock *kb = NULL;
+ BLI_thread_lock(LOCK_VIEW3D);
+ v3d->camera = camera;
- /* try to display active bone and active shapekey too (if they exist) */
+ BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
+ view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, NULL, rect);
- if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) {
- Object *armobj = BKE_object_pose_armature_get(ob);
- if (armobj && armobj->mode & OB_MODE_POSE) {
- bArmature *arm = armobj->data;
- if (arm->act_bone) {
- if (arm->act_bone->layer & arm->layer) {
- s += BLI_strcpy_rlen(s, msg_sep);
- s += BLI_strcpy_rlen(s, arm->act_bone->name);
- }
- }
- }
- }
+ v3d->camera = view_ob;
+ BLI_thread_unlock(LOCK_VIEW3D);
+ }
+}
- key = BKE_key_from_object(ob);
- if (key) {
- kb = BLI_findlink(&key->block, ob->shapenr - 1);
- if (kb) {
- s += BLI_strcpy_rlen(s, msg_sep);
- s += BLI_strcpy_rlen(s, kb->name);
- if (ob->shapeflag & OB_SHAPE_LOCK) {
- s += BLI_strcpy_rlen(s, IFACE_(msg_pin));
- }
- }
- }
- }
+/**
+ * Set the correct matrices
+ */
+void ED_view3d_draw_setup_view(
+ wmWindow *win, Depsgraph *depsgraph, Scene *scene, ARegion *ar, View3D *v3d,
+ float viewmat[4][4], float winmat[4][4], const rcti *rect)
+{
+ RegionView3D *rv3d = ar->regiondata;
- /* color depends on whether there is a keyframe */
- if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL))
- UI_ThemeColor(TH_TIME_KEYFRAME);
- else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra))
- UI_ThemeColor(TH_TIME_GP_KEYFRAME);
- else
- UI_ThemeColor(TH_TEXT_HI);
+ /* Setup the view matrix. */
+ if (view3d_stereo3d_active(win, scene, v3d, rv3d)) {
+ view3d_stereo3d_setup(depsgraph, scene, v3d, ar, rect);
}
else {
- /* no object */
- if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra))
- UI_ThemeColor(TH_TIME_GP_KEYFRAME);
- else
- UI_ThemeColor(TH_TEXT_HI);
+ view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, rect);
}
-
- if (markern) {
- s += sprintf(s, " <%s>", markern);
- }
-
- if (U.uiflag & USER_SHOW_ROTVIEWICON)
- offset = U.widget_unit + (U.rvisize * 2) + rect->xmin;
-
- BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info));
}
+/* ******************** view border ***************** */
+
static void view3d_camera_border(
- const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ const Scene *scene, struct Depsgraph *depsgraph,
+ const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
rctf *r_viewborder, const bool no_shift, const bool no_zoom)
{
CameraParams params;
rctf rect_view, rect_camera;
+ Object *camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
/* get viewport viewplane */
BKE_camera_params_init(&params);
- BKE_camera_params_from_view3d(&params, v3d, rv3d);
+ BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
if (no_zoom)
params.zoom = 1.0f;
BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
@@ -990,7 +322,7 @@ static void view3d_camera_border(
/* fallback for non camera objects */
params.clipsta = v3d->near;
params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
+ BKE_camera_params_from_object(&params, camera_eval);
if (no_shift) {
params.shiftx = 0.0f;
params.shifty = 0.0f;
@@ -1006,24 +338,26 @@ static void view3d_camera_border(
}
void ED_view3d_calc_camera_border_size(
- const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ const Scene *scene, Depsgraph *depsgraph,
+ const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
float r_size[2])
{
rctf viewborder;
- view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, true, true);
+ view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, true, true);
r_size[0] = BLI_rctf_size_x(&viewborder);
r_size[1] = BLI_rctf_size_y(&viewborder);
}
void ED_view3d_calc_camera_border(
- const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
+ const Scene *scene, Depsgraph *depsgraph,
+ const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
rctf *r_viewborder, const bool no_shift)
{
- view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false);
+ view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, r_viewborder, no_shift, false);
}
-static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float fac)
+static void drawviewborder_grid3(uint shdr_pos, float x1, float x2, float y1, float y2, float fac)
{
float x3, y3, x4, y4;
@@ -1032,29 +366,33 @@ static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float f
x4 = x1 + (1.0f - fac) * (x2 - x1);
y4 = y1 + (1.0f - fac) * (y2 - y1);
- glBegin(GL_LINES);
- glVertex2f(x1, y3);
- glVertex2f(x2, y3);
+ immBegin(GPU_PRIM_LINES, 8);
- glVertex2f(x1, y4);
- glVertex2f(x2, y4);
+ immVertex2f(shdr_pos, x1, y3);
+ immVertex2f(shdr_pos, x2, y3);
- glVertex2f(x3, y1);
- glVertex2f(x3, y2);
+ immVertex2f(shdr_pos, x1, y4);
+ immVertex2f(shdr_pos, x2, y4);
- glVertex2f(x4, y1);
- glVertex2f(x4, y2);
- glEnd();
+ immVertex2f(shdr_pos, x3, y1);
+ immVertex2f(shdr_pos, x3, y2);
+
+ immVertex2f(shdr_pos, x4, y1);
+ immVertex2f(shdr_pos, x4, y2);
+
+ immEnd();
}
/* harmonious triangle */
-static void drawviewborder_triangle(float x1, float x2, float y1, float y2, const char golden, const char dir)
+static void drawviewborder_triangle(
+ uint shdr_pos, float x1, float x2, float y1, float y2, const char golden, const char dir)
{
float ofs;
float w = x2 - x1;
float h = y2 - y1;
- glBegin(GL_LINES);
+ immBegin(GPU_PRIM_LINES, 6);
+
if (w > h) {
if (golden) {
ofs = w * (1.0f - (1.0f / 1.61803399f));
@@ -1064,14 +402,14 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons
}
if (dir == 'B') SWAP(float, y1, y2);
- glVertex2f(x1, y1);
- glVertex2f(x2, y2);
+ immVertex2f(shdr_pos, x1, y1);
+ immVertex2f(shdr_pos, x2, y2);
- glVertex2f(x2, y1);
- glVertex2f(x1 + (w - ofs), y2);
+ immVertex2f(shdr_pos, x2, y1);
+ immVertex2f(shdr_pos, x1 + (w - ofs), y2);
- glVertex2f(x1, y2);
- glVertex2f(x1 + ofs, y1);
+ immVertex2f(shdr_pos, x1, y2);
+ immVertex2f(shdr_pos, x1 + ofs, y1);
}
else {
if (golden) {
@@ -1082,19 +420,20 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons
}
if (dir == 'B') SWAP(float, x1, x2);
- glVertex2f(x1, y1);
- glVertex2f(x2, y2);
+ immVertex2f(shdr_pos, x1, y1);
+ immVertex2f(shdr_pos, x2, y2);
- glVertex2f(x2, y1);
- glVertex2f(x1, y1 + ofs);
+ immVertex2f(shdr_pos, x2, y1);
+ immVertex2f(shdr_pos, x1, y1 + ofs);
- glVertex2f(x1, y2);
- glVertex2f(x2, y1 + (h - ofs));
+ immVertex2f(shdr_pos, x1, y2);
+ immVertex2f(shdr_pos, x2, y1 + (h - ofs));
}
- glEnd();
+
+ immEnd();
}
-static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
+static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *ar, View3D *v3d)
{
float x1, x2, y1, y2;
float x1i, x2i, y1i, y2i;
@@ -1108,14 +447,14 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
if (v3d->camera->type == OB_CAMERA)
ca = v3d->camera->data;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false);
/* the offsets */
x1 = viewborder.xmin;
y1 = viewborder.ymin;
x2 = viewborder.xmax;
y2 = viewborder.ymax;
- glLineWidth(1.0f);
+ GPU_line_width(1.0f);
/* apply offsets so the real 3D camera shows through */
@@ -1129,56 +468,74 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
x2i = (int)(x2 + (1.0f - 0.0001f));
y2i = (int)(y2 + (1.0f - 0.0001f));
- /* passepartout, specified in camera edit buttons */
- if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
- const float winx = (ar->winx + 1);
- const float winy = (ar->winy + 1);
+ uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- if (ca->passepartalpha == 1.0f) {
- glColor3f(0, 0, 0);
- }
- else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glColor4f(0, 0, 0, ca->passepartalpha);
- }
+ /* First, solid lines. */
+ {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- if (x1i > 0.0f)
- glRectf(0.0, winy, x1i, 0.0);
- if (x2i < winx)
- glRectf(x2i, winy, winx, 0.0);
- if (y2i < winy)
- glRectf(x1i, winy, x2i, y2i);
- if (y2i > 0.0f)
- glRectf(x1i, y1i, x2i, 0.0);
+ /* passepartout, specified in camera edit buttons */
+ if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
+ const float winx = (ar->winx + 1);
+ const float winy = (ar->winy + 1);
- glDisable(GL_BLEND);
- }
+ float alpha = 1.0f;
- setlinestyle(0);
+ if (ca->passepartalpha != 1.0f) {
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
+ alpha = ca->passepartalpha;
+ }
- UI_ThemeColor(TH_BACK);
+ immUniformColor4f(0.0f, 0.0f, 0.0f, alpha);
- fdrawbox(x1i, y1i, x2i, y2i);
+ if (x1i > 0.0f)
+ immRectf(shdr_pos, 0.0f, winy, x1i, 0.0f);
+ if (x2i < winx)
+ immRectf(shdr_pos, x2i, winy, winx, 0.0f);
+ if (y2i < winy)
+ immRectf(shdr_pos, x1i, winy, x2i, y2i);
+ if (y2i > 0.0f)
+ immRectf(shdr_pos, x1i, y1i, x2i, 0.0f);
+
+ GPU_blend(false);
+ }
+
+ immUniformThemeColor(TH_BACK);
+ imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i);
#ifdef VIEW3D_CAMERA_BORDER_HACK
- if (view3d_camera_border_hack_test == true) {
- glColor3ubv(view3d_camera_border_hack_col);
- fdrawbox(x1i + 1, y1i + 1, x2i - 1, y2i - 1);
- view3d_camera_border_hack_test = false;
- }
+ if (view3d_camera_border_hack_test == true) {
+ immUniformColor3ubv(view3d_camera_border_hack_col);
+ imm_draw_box_wire_2d(shdr_pos, x1i + 1, y1i + 1, x2i - 1, y2i - 1);
+ view3d_camera_border_hack_test = false;
+ }
#endif
- setlinestyle(3);
-
- /* outer line not to confuse with object selecton */
- if (v3d->flag2 & V3D_LOCK_CAMERA) {
- UI_ThemeColor(TH_REDALERT);
- fdrawbox(x1i - 1, y1i - 1, x2i + 1, y2i + 1);
+ immUnbindProgram();
}
- UI_ThemeColor(TH_VIEW_OVERLAY);
- fdrawbox(x1i, y1i, x2i, y2i);
+ /* And now, the dashed lines! */
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ {
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ /* outer line not to confuse with object selection */
+ if (v3d->flag2 & V3D_LOCK_CAMERA) {
+ immUniformThemeColor(TH_REDALERT);
+ imm_draw_box_wire_2d(shdr_pos, x1i - 1, y1i - 1, x2i + 1, y2i + 1);
+ }
+
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+ imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i);
+ }
/* border */
if (scene->r.mode & R_BORDER) {
@@ -1189,82 +546,76 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1);
y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1);
- cpack(0x4040FF);
- sdrawbox(x3, y3, x4, y4);
+ immUniformColor3f(1.0f, 0.25f, 0.25f);
+ imm_draw_box_wire_2d(shdr_pos, x3, y3, x4, y4);
}
/* safety border */
if (ca) {
+ immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f);
+
if (ca->dtx & CAM_DTX_CENTER) {
float x3, y3;
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
-
x3 = x1 + 0.5f * (x2 - x1);
y3 = y1 + 0.5f * (y2 - y1);
- glBegin(GL_LINES);
- glVertex2f(x1, y3);
- glVertex2f(x2, y3);
+ immBegin(GPU_PRIM_LINES, 4);
+
+ immVertex2f(shdr_pos, x1, y3);
+ immVertex2f(shdr_pos, x2, y3);
+
+ immVertex2f(shdr_pos, x3, y1);
+ immVertex2f(shdr_pos, x3, y2);
- glVertex2f(x3, y1);
- glVertex2f(x3, y2);
- glEnd();
+ immEnd();
}
if (ca->dtx & CAM_DTX_CENTER_DIAG) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
+ immBegin(GPU_PRIM_LINES, 4);
- glBegin(GL_LINES);
- glVertex2f(x1, y1);
- glVertex2f(x2, y2);
+ immVertex2f(shdr_pos, x1, y1);
+ immVertex2f(shdr_pos, x2, y2);
- glVertex2f(x1, y2);
- glVertex2f(x2, y1);
- glEnd();
+ immVertex2f(shdr_pos, x1, y2);
+ immVertex2f(shdr_pos, x2, y1);
+
+ immEnd();
}
if (ca->dtx & CAM_DTX_THIRDS) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
- drawviewborder_grid3(x1, x2, y1, y2, 1.0f / 3.0f);
+ drawviewborder_grid3(shdr_pos, x1, x2, y1, y2, 1.0f / 3.0f);
}
if (ca->dtx & CAM_DTX_GOLDEN) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
- drawviewborder_grid3(x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f));
+ drawviewborder_grid3(shdr_pos, x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f));
}
if (ca->dtx & CAM_DTX_GOLDEN_TRI_A) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
- drawviewborder_triangle(x1, x2, y1, y2, 0, 'A');
+ drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 0, 'A');
}
if (ca->dtx & CAM_DTX_GOLDEN_TRI_B) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
- drawviewborder_triangle(x1, x2, y1, y2, 0, 'B');
+ drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 0, 'B');
}
if (ca->dtx & CAM_DTX_HARMONY_TRI_A) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
- drawviewborder_triangle(x1, x2, y1, y2, 1, 'A');
+ drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 1, 'A');
}
if (ca->dtx & CAM_DTX_HARMONY_TRI_B) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
- drawviewborder_triangle(x1, x2, y1, y2, 1, 'B');
+ drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 1, 'B');
}
if (ca->flag & CAM_SHOW_SAFE_MARGINS) {
UI_draw_safe_areas(
- x1, x2, y1, y2,
- scene->safe_areas.title,
- scene->safe_areas.action);
+ shdr_pos, x1, x2, y1, y2,
+ scene->safe_areas.title, scene->safe_areas.action);
if (ca->flag & CAM_SHOW_SAFE_CENTER) {
UI_draw_safe_areas(
- x1, x2, y1, y2,
- scene->safe_areas.title_center,
- scene->safe_areas.action_center);
+ shdr_pos, x1, x2, y1, y2,
+ scene->safe_areas.title_center, scene->safe_areas.action_center);
}
}
@@ -1300,1895 +651,749 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
}
/* draw */
- UI_ThemeColorShade(TH_VIEW_OVERLAY, 100);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f);
+ immUniformThemeColorShade(TH_VIEW_OVERLAY, 100);
+
+ /* TODO Was using UI_draw_roundbox_4fv(false, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f, color).
+ * We'll probably need a new imm_draw_line_roundbox_dashed dor that - though in practice the
+ * 2.0f round corner effect was nearly not visible anyway... */
+ imm_draw_box_wire_2d(shdr_pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
}
}
- setlinestyle(0);
+ immUnbindProgram();
+ /* end dashed lines */
/* camera name - draw in highlighted text color */
if (ca && (ca->flag & CAM_SHOWNAME)) {
- UI_ThemeColor(TH_TEXT_HI);
+ UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
BLF_draw_default(
x1i, y1i - (0.7f * U.widget_unit), 0.0f,
v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2);
}
}
-/* *********************** backdraw for selection *************** */
-
-static void backdrawview3d(Scene *scene, wmWindow *win, ARegion *ar, View3D *v3d, Object *obact, Object *obedit)
+static void drawrenderborder(ARegion *ar, View3D *v3d)
{
- RegionView3D *rv3d = ar->regiondata;
- int multisample_enabled;
-
- BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
-
- if (obact && (obact->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
- BKE_paint_select_face_test(obact)))
- {
- /* do nothing */
- }
- /* texture paint mode sampling */
- else if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT) &&
- (v3d->drawtype > OB_WIRE))
- {
- /* do nothing */
- }
- else if ((obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) &&
- V3D_IS_ZBUF(v3d))
- {
- /* do nothing */
- }
- else if (obedit &&
- V3D_IS_ZBUF(v3d))
- {
- /* do nothing */
- }
- else {
- v3d->flag &= ~V3D_INVALID_BACKBUF;
- return;
- }
+ /* use the same program for everything */
+ uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- if (!(v3d->flag & V3D_INVALID_BACKBUF))
- return;
+ GPU_line_width(1.0f);
-#if 0
- if (test) {
- if (qtest()) {
- addafterqueue(ar->win, BACKBUFDRAW, 1);
- return;
- }
- }
-#endif
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- if (v3d->drawtype > OB_WIRE) v3d->zbuf = true;
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- /* dithering and AA break color coding, so disable */
- glDisable(GL_DITHER);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniform4f("color", 1.0f, 0.25f, 0.25f, 1.0f);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
- if (multisample_enabled)
- glDisable(GL_MULTISAMPLE);
+ imm_draw_box_wire_2d(shdr_pos,
+ v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy,
+ v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy);
- if (win->multisamples != USER_MULTISAMPLE_NONE) {
- /* for multisample we use an offscreen FBO. multisample drawing can fail
- * with color coded selection drawing, and reading back depths from such
- * a buffer can also cause a few seconds freeze on OS X / NVidia. */
- int w = BLI_rcti_size_x(&ar->winrct);
- int h = BLI_rcti_size_y(&ar->winrct);
- char error[256];
+ immUnbindProgram();
+}
- if (rv3d->gpuoffscreen) {
- if (GPU_offscreen_width(rv3d->gpuoffscreen) != w ||
- GPU_offscreen_height(rv3d->gpuoffscreen) != h)
- {
- GPU_offscreen_free(rv3d->gpuoffscreen);
- rv3d->gpuoffscreen = NULL;
- }
- }
+void ED_view3d_draw_depth(
+ Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d, bool alphaoverride)
+{
+ struct bThemeState theme_state;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ RegionView3D *rv3d = ar->regiondata;
- if (!rv3d->gpuoffscreen) {
- rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error);
+ short flag = v3d->flag;
+ float glalphaclip = U.glalphaclip;
+ int obcenter_dia = U.obcenter_dia;
+ /* temp set drawtype to solid */
+ /* Setting these temporarily is not nice */
+ v3d->flag &= ~V3D_SELECT_OUTLINE;
+ U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */
+ U.obcenter_dia = 0;
- if (!rv3d->gpuoffscreen)
- fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
- }
- }
+ /* Tools may request depth outside of regular drawing code. */
+ UI_Theme_Store(&theme_state);
+ UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
- if (rv3d->gpuoffscreen)
- GPU_offscreen_bind(rv3d->gpuoffscreen, true);
- else
- glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
+ ED_view3d_draw_setup_view(NULL, depsgraph, scene, ar, v3d, NULL, NULL, NULL);
- glClearColor(0.0, 0.0, 0.0, 0.0);
- if (v3d->zbuf) {
- glEnable(GL_DEPTH_TEST);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
- else {
- glClear(GL_COLOR_BUFFER_BIT);
- glDisable(GL_DEPTH_TEST);
- }
+ GPU_clear(GPU_DEPTH_BIT);
- if (rv3d->rflag & RV3D_CLIPPING)
+ if (rv3d->rflag & RV3D_CLIPPING) {
ED_view3d_clipping_set(rv3d);
-
- G.f |= G_BACKBUFSEL;
-
- if (obact && (obact->lay & v3d->lay)) {
- draw_object_backbufsel(scene, v3d, rv3d, obact);
}
+ /* get surface depth without bias */
+ rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
- if (rv3d->gpuoffscreen)
- GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
- else
- ar->swap = 0; /* mark invalid backbuf for wm draw */
-
- v3d->flag &= ~V3D_INVALID_BACKBUF;
+ GPU_depth_test(true);
- G.f &= ~G_BACKBUFSEL;
- v3d->zbuf = false;
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_DITHER);
- if (multisample_enabled)
- glEnable(GL_MULTISAMPLE);
+ DRW_draw_depth_loop(depsgraph, ar, v3d);
- if (rv3d->rflag & RV3D_CLIPPING)
+ if (rv3d->rflag & RV3D_CLIPPING) {
ED_view3d_clipping_disable();
-}
-
-void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
-{
- RegionView3D *rv3d = ar->regiondata;
-
- if (rv3d->gpuoffscreen) {
- GPU_offscreen_bind(rv3d->gpuoffscreen, true);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
- glReadPixels(x, y, w, h, format, type, data);
- GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
}
- else {
- glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
- }
-}
+ rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
-/* XXX depth reading exception, for code not using gpu offscreen */
-static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
-{
+ /* Reset default for UI */
+ GPU_depth_test(false);
- glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
-}
+ U.glalphaclip = glalphaclip;
+ v3d->flag = flag;
+ U.obcenter_dia = obcenter_dia;
-void ED_view3d_backbuf_validate(ViewContext *vc)
-{
- if (vc->v3d->flag & V3D_INVALID_BACKBUF) {
- backdrawview3d(vc->scene, vc->win, vc->ar, vc->v3d, vc->obact, vc->obedit);
- }
+ UI_Theme_Restore(&theme_state);
}
-/**
- * allow for small values [0.5 - 2.5],
- * and large values, FLT_MAX by clamping by the area size
- */
-int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
-{
- return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
-}
+/* ******************** other elements ***************** */
-/* samples a single pixel (copied from vpaint) */
-unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
+/** could move this elsewhere, but tied into #ED_view3d_grid_scale */
+float ED_scene_grid_scale(Scene *scene, const char **grid_unit)
{
- unsigned int col;
-
- if (x >= vc->ar->winx || y >= vc->ar->winy) {
- return 0;
- }
-
- ED_view3d_backbuf_validate(vc);
+ /* apply units */
+ if (scene->unit.system) {
+ const void *usys;
+ int len;
- view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
- glReadBuffer(GL_BACK);
+ bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
- if (ENDIAN_ORDER == B_ENDIAN) {
- BLI_endian_switch_uint32(&col);
+ if (usys) {
+ int i = bUnit_GetBaseUnit(usys);
+ if (grid_unit)
+ *grid_unit = bUnit_GetNameDisplay(usys, i);
+ return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length;
+ }
}
- return GPU_select_to_index(col);
+ return 1.0f;
}
-/* reads full rect, converts indices */
-ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax)
+float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
{
- struct ImBuf *ibuf_clip;
- /* clip */
- const rcti clip = {
- max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1),
- max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)};
- const int size_clip[2] = {
- BLI_rcti_size_x(&clip) + 1,
- BLI_rcti_size_y(&clip) + 1};
-
- if (UNLIKELY((clip.xmin > clip.xmax) ||
- (clip.ymin > clip.ymax)))
- {
- return NULL;
- }
-
- ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect);
-
- ED_view3d_backbuf_validate(vc);
-
- view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect);
-
- glReadBuffer(GL_BACK);
-
- if (ENDIAN_ORDER == B_ENDIAN) {
- IMB_convert_rgba_to_abgr(ibuf_clip);
- }
-
- GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
-
- if ((clip.xmin == xmin) &&
- (clip.xmax == xmax) &&
- (clip.ymin == ymin) &&
- (clip.ymax == ymax))
- {
- return ibuf_clip;
- }
- else {
- /* put clipped result into a non-clipped buffer */
- struct ImBuf *ibuf_full;
- const int size[2] = {
- (xmax - xmin + 1),
- (ymax - ymin + 1)};
-
- ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect);
-
- IMB_rectcpy(
- ibuf_full, ibuf_clip,
- clip.xmin - xmin, clip.ymin - ymin,
- 0, 0,
- size_clip[0], size_clip[1]);
- IMB_freeImBuf(ibuf_clip);
- return ibuf_full;
- }
+ return v3d->grid * ED_scene_grid_scale(scene, grid_unit);
}
-/**
- * Smart function to sample a rectangle spiral ling outside, nice for backbuf selection
- */
-uint ED_view3d_backbuf_sample_rect(
- ViewContext *vc, const int mval[2], int size,
- unsigned int min, unsigned int max, float *r_dist)
-{
- struct ImBuf *buf;
- const unsigned int *bufmin, *bufmax, *tbuf;
- int minx, miny;
- int a, b, rc, nr, amount, dirvec[4][2];
- unsigned int index = 0;
-
- amount = (size - 1) / 2;
-
- minx = mval[0] - (amount + 1);
- miny = mval[1] - (amount + 1);
- buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1);
- if (!buf) return 0;
-
- rc = 0;
-
- dirvec[0][0] = 1; dirvec[0][1] = 0;
- dirvec[1][0] = 0; dirvec[1][1] = -size;
- dirvec[2][0] = -1; dirvec[2][1] = 0;
- dirvec[3][0] = 0; dirvec[3][1] = size;
-
- bufmin = buf->rect;
- tbuf = buf->rect;
- bufmax = buf->rect + size * size;
- tbuf += amount * size + amount;
-
- for (nr = 1; nr <= size; nr++) {
-
- for (a = 0; a < 2; a++) {
- for (b = 0; b < nr; b++) {
- if (*tbuf && *tbuf >= min && *tbuf < max) {
- /* we got a hit */
-
- /* get x,y pixel coords from the offset
- * (manhatten distance in keeping with other screen-based selection) */
- *r_dist = (float)(
- abs(((int)(tbuf - buf->rect) % size) - (size / 2)) +
- abs(((int)(tbuf - buf->rect) / size) - (size / 2)));
-
- /* indices start at 1 here */
- index = (*tbuf - min) + 1;
- goto exit;
+/* Simulates the grid scale that is visualized by the shaders drawing functions.
+ * The actual code is seen in `object_grid_frag.glsl` when you get the `grid_res` value.
+ * Currently the simulation is done only when RV3D_VIEW_IS_AXIS. */
+float ED_view3d_grid_view_scale(
+ Scene *scene, View3D *v3d, RegionView3D *rv3d, const char **grid_unit)
+{
+ float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
+ if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
+ /* Decrease the distance between grid snap points depending on zoom. */
+ float grid_subdiv = v3d->gridsubdiv;
+ if (grid_subdiv > 1) {
+ float grid_distance = rv3d->dist;
+ float lvl = (logf(grid_distance / grid_scale) / logf(grid_subdiv));
+ if (lvl < 0.0f) {
+ /* Negative values need an offset for correct casting.
+ * By convention, the minimum lvl is limited to -2 (see `objec_mode.c`) */
+ if (lvl > -2.0f) {
+ lvl -= 1.0f;
}
-
- tbuf += (dirvec[rc][0] + dirvec[rc][1]);
-
- if (tbuf < bufmin || tbuf >= bufmax) {
- goto exit;
+ else {
+ lvl = -2.0f;
}
}
- rc++;
- rc &= 3;
+ grid_scale *= pow(grid_subdiv, (int)lvl - 1);
}
}
-exit:
- IMB_freeImBuf(buf);
- return index;
+ return v3d->grid * grid_scale;
}
-
-/* ************************************************************* */
-
-static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
+static void draw_view_axis(RegionView3D *rv3d, const rcti *rect)
{
- if (BKE_image_is_stereo(ima)) {
- iuser->flag |= IMA_SHOW_STEREO;
+ const float k = U.rvisize * U.pixelsize; /* axis size */
+ const int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */
- if ((scene->r.scemode & R_MULTIVIEW) == 0) {
- iuser->multiview_eye = STEREO_LEFT_ID;
- }
- else if (v3d->stereo3d_camera != STEREO_3D_ID) {
- /* show only left or right camera */
- iuser->multiview_eye = v3d->stereo3d_camera;
- }
+ /* Axis center in screen coordinates.
+ *
+ * - Unit size offset so small text doesn't draw outside the screen
+ * - Extra X offset because of the panel expander.
+ */
+ const float startx = rect->xmax - (k + UI_UNIT_X * 1.5);
+ const float starty = rect->ymax - (k + UI_UNIT_Y);
- BKE_image_multiview_index(ima, iuser);
- }
- else {
- iuser->flag &= ~IMA_SHOW_STEREO;
- }
-}
+ float axis_pos[3][2];
+ unsigned char axis_col[3][4];
-static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
- const bool do_foreground, const bool do_camera_frame)
-{
- RegionView3D *rv3d = ar->regiondata;
- BGpic *bgpic;
- int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0;
+ int axis_order[3] = {0, 1, 2};
+ axis_sort_v3(rv3d->viewinv[2], axis_order);
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- bgpic->iuser.scene = scene; /* Needed for render results. */
+ for (int axis_i = 0; axis_i < 3; axis_i++) {
+ int i = axis_order[axis_i];
- if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag)
- continue;
+ /* get position of each axis tip on screen */
+ float vec[3] = { 0.0f };
+ vec[i] = 1.0f;
+ mul_qt_v3(rv3d->viewquat, vec);
+ axis_pos[i][0] = startx + vec[0] * k;
+ axis_pos[i][1] = starty + vec[1] * k;
- if ((bgpic->view == 0) || /* zero for any */
- (bgpic->view & (1 << rv3d->view)) || /* check agaist flags */
- (rv3d->persp == RV3D_CAMOB && bgpic->view == (1 << RV3D_VIEW_CAMERA)))
- {
- float image_aspect[2];
- float fac, asp, zoomx, zoomy;
- float x1, y1, x2, y2, centx, centy;
-
- ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
- void *lock;
- rctf clip_rect;
-
- Image *ima = NULL;
- MovieClip *clip = NULL;
-
- /* disable individual images */
- if ((bgpic->flag & V3D_BGPIC_DISABLED))
- continue;
-
- freeibuf = NULL;
- releaseibuf = NULL;
- if (bgpic->source == V3D_BGPIC_IMAGE) {
- ima = bgpic->ima;
- if (ima == NULL)
- continue;
- BKE_image_user_frame_calc(&bgpic->iuser, CFRA, 0);
- if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) {
- ibuf = NULL; /* frame is out of range, dont show */
- }
- else {
- view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser);
- ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock);
- releaseibuf = ibuf;
- }
+ /* get color of each axis */
+ UI_GetThemeColorShade3ubv(TH_AXIS_X + i, bright, axis_col[i]); /* rgb */
+ axis_col[i][3] = 255 * hypotf(vec[0], vec[1]); /* alpha */
+ }
- image_aspect[0] = ima->aspx;
- image_aspect[1] = ima->aspy;
- }
- else if (bgpic->source == V3D_BGPIC_MOVIE) {
- /* TODO: skip drawing when out of frame range (as image sequences do above) */
+ /* draw axis lines */
+ GPU_line_width(2.0f);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (bgpic->flag & V3D_BGPIC_CAMERACLIP) {
- if (scene->camera)
- clip = BKE_object_movieclip_get(scene, scene->camera, true);
- }
- else {
- clip = bgpic->clip;
- }
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- if (clip == NULL)
- continue;
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(GPU_PRIM_LINES, 6);
- BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA);
- ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);
+ for (int axis_i = 0; axis_i < 3; axis_i++) {
+ int i = axis_order[axis_i];
- image_aspect[0] = clip->aspx;
- image_aspect[1] = clip->aspy;
+ immAttr4ubv(col, axis_col[i]);
+ immVertex2f(pos, startx, starty);
+ immAttr4ubv(col, axis_col[i]);
+ immVertex2fv(pos, axis_pos[i]);
+ }
- /* working with ibuf from image and clip has got different workflow now.
- * ibuf acquired from clip is referenced by cache system and should
- * be dereferenced after usage. */
- freeibuf = ibuf;
- }
- else {
- /* perhaps when loading future files... */
- BLI_assert(0);
- copy_v2_fl(image_aspect, 1.0f);
- }
+ immEnd();
+ immUnbindProgram();
+ GPU_line_smooth(false);
- if (ibuf == NULL)
- continue;
+ /* draw axis names */
+ for (int axis_i = 0; axis_i < 3; axis_i++) {
+ int i = axis_order[axis_i];
- if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */
- if (freeibuf)
- IMB_freeImBuf(freeibuf);
- if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, lock);
+ const char axis_text[2] = {'x' + i, '\0'};
+ BLF_color4ubv(BLF_default(), axis_col[i]);
+ BLF_draw_default_ascii(axis_pos[i][0] + 2, axis_pos[i][1] + 2, 0.0f, axis_text, 1);
+ }
+}
- continue;
- }
+#ifdef WITH_INPUT_NDOF
+/* draw center and axis of rotation for ongoing 3D mouse navigation */
+static void UNUSED_FUNCTION(draw_rotation_guide)(RegionView3D *rv3d)
+{
+ float o[3]; /* center of rotation */
+ float end[3]; /* endpoints for drawing */
- if (ibuf->rect == NULL)
- IMB_rect_from_float(ibuf);
+ GLubyte color[4] = {0, 108, 255, 255}; /* bright blue so it matches device LEDs */
- if (rv3d->persp == RV3D_CAMOB) {
+ negate_v3_v3(o, rv3d->ofs);
- if (do_camera_frame) {
- rctf vb;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false);
- x1 = vb.xmin;
- y1 = vb.ymin;
- x2 = vb.xmax;
- y2 = vb.ymax;
- }
- else {
- x1 = ar->winrct.xmin;
- y1 = ar->winrct.ymin;
- x2 = ar->winrct.xmax;
- y2 = ar->winrct.ymax;
- }
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ glDepthMask(GL_FALSE); /* don't overwrite zbuf */
- /* apply offset last - camera offset is different to offset in blender units */
- /* so this has some sane way of working - this matches camera's shift _exactly_ */
- {
- const float max_dim = max_ff(x2 - x1, y2 - y1);
- const float xof_scale = bgpic->xof * max_dim;
- const float yof_scale = bgpic->yof * max_dim;
-
- x1 += xof_scale;
- y1 += yof_scale;
- x2 += xof_scale;
- y2 += yof_scale;
- }
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- centx = (x1 + x2) / 2.0f;
- centy = (y1 + y2) / 2.0f;
+ immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
- /* aspect correction */
- if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) {
- /* apply aspect from clip */
- const float w_src = ibuf->x * image_aspect[0];
- const float h_src = ibuf->y * image_aspect[1];
+ if (rv3d->rot_angle != 0.0f) {
+ /* -- draw rotation axis -- */
+ float scaled_axis[3];
+ const float scale = rv3d->dist;
+ mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale);
- /* destination aspect is already applied from the camera frame */
- const float w_dst = x1 - x2;
- const float h_dst = y1 - y2;
- const float asp_src = w_src / h_src;
- const float asp_dst = w_dst / h_dst;
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+ color[3] = 0; /* more transparent toward the ends */
+ immAttr4ubv(col, color);
+ add_v3_v3v3(end, o, scaled_axis);
+ immVertex3fv(pos, end);
- if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
- if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) {
- /* fit X */
- const float div = asp_src / asp_dst;
- x1 = ((x1 - centx) * div) + centx;
- x2 = ((x2 - centx) * div) + centx;
- }
- else {
- /* fit Y */
- const float div = asp_dst / asp_src;
- y1 = ((y1 - centy) * div) + centy;
- y2 = ((y2 - centy) * div) + centy;
- }
- }
- }
- }
- else {
- float tvec[3];
- float sco[2];
- const float mval_f[2] = {1.0f, 0.0f};
- const float co_zero[3] = {0};
- float zfac;
-
- /* calc window coord */
- zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
- ED_view3d_win_to_delta(ar, mval_f, tvec, zfac);
- fac = max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */
- fac = 1.0f / fac;
-
- asp = (float)ibuf->y / (float)ibuf->x;
-
- zero_v3(tvec);
- ED_view3d_project_float_v2_m4(ar, tvec, sco, rv3d->persmat);
-
- x1 = sco[0] + fac * (bgpic->xof - bgpic->size);
- y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size);
- x2 = sco[0] + fac * (bgpic->xof + bgpic->size);
- y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size);
-
- centx = (x1 + x2) / 2.0f;
- centy = (y1 + y2) / 2.0f;
- }
+#if 0
+ color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
+ /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */
+#endif
- /* complete clip? */
- BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
- if (bgpic->rotation) {
- BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
- }
+ color[3] = 127; /* more opaque toward the center */
+ immAttr4ubv(col, color);
+ immVertex3fv(pos, o);
- if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) {
- if (freeibuf)
- IMB_freeImBuf(freeibuf);
- if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, lock);
+ color[3] = 0;
+ immAttr4ubv(col, color);
+ sub_v3_v3v3(end, o, scaled_axis);
+ immVertex3fv(pos, end);
+ immEnd();
- continue;
- }
+ /* -- draw ring around rotation center -- */
+ {
+#define ROT_AXIS_DETAIL 13
- zoomx = (x2 - x1) / ibuf->x;
- zoomy = (y2 - y1) / ibuf->y;
+ const float s = 0.05f * scale;
+ const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL);
- /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */
- if (zoomx < 1.0f || zoomy < 1.0f) {
- float tzoom = min_ff(zoomx, zoomy);
- int mip = 0;
+ float q[4]; /* rotate ring so it's perpendicular to axis */
+ const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
+ if (!upright) {
+ const float up[3] = {0.0f, 0.0f, 1.0f};
+ float vis_angle, vis_axis[3];
- if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) {
- IMB_remakemipmap(ibuf, 0);
- ibuf->userflags &= ~IB_MIPMAP_INVALID;
- }
- else if (ibuf->mipmap[0] == NULL)
- IMB_makemipmap(ibuf, 0);
-
- while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) {
- tzoom *= 2.0f;
- zoomx *= 2.0f;
- zoomy *= 2.0f;
- mip++;
- }
- if (mip > 0)
- ibuf = ibuf->mipmap[mip - 1];
+ cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
+ vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis));
+ axis_angle_to_quat(q, vis_axis, vis_angle);
}
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
- glDepthMask(0);
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- ED_region_pixelspace(ar);
+ immBegin(GPU_PRIM_LINE_LOOP, ROT_AXIS_DETAIL);
+ color[3] = 63; /* somewhat faint */
+ immAttr4ubv(col, color);
+ float angle = 0.0f;
+ for (int i = 0; i < ROT_AXIS_DETAIL; ++i, angle += step) {
+ float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
- glTranslatef(centx, centy, 0.0);
- glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
+ if (!upright) {
+ mul_qt_v3(q, p);
+ }
- if (bgpic->flag & V3D_BGPIC_FLIP_X) {
- zoomx *= -1.0f;
- x1 = x2;
- }
- if (bgpic->flag & V3D_BGPIC_FLIP_Y) {
- zoomy *= -1.0f;
- y1 = y2;
+ add_v3_v3(p, o);
+ immVertex3fv(pos, p);
}
- glPixelZoom(zoomx, zoomy);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend);
-
- /* could not use glaDrawPixelsAuto because it could fallback to
- * glaDrawPixelsSafe in some cases, which will end up in missing
- * alpha transparency for the background image (sergey)
- */
- glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
+ immEnd();
- glPixelZoom(1.0, 1.0);
- glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- glDisable(GL_BLEND);
-
- glDepthMask(1);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
-
- if (freeibuf)
- IMB_freeImBuf(freeibuf);
- if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, lock);
+#undef ROT_AXIS_DETAIL
}
+
+ color[3] = 255; /* solid dot */
}
-}
+ else
+ color[3] = 127; /* see-through dot */
-static void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d,
- const bool do_foreground, const bool do_camera_frame)
-{
- RegionView3D *rv3d = ar->regiondata;
+ immUnbindProgram();
- if ((v3d->flag & V3D_DISPBGPICS) == 0)
- return;
+ /* -- draw rotation center -- */
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
+ GPU_point_size(5.0f);
+ immBegin(GPU_PRIM_POINTS, 1);
+ immAttr4ubv(col, color);
+ immVertex3fv(pos, o);
+ immEnd();
+ immUnbindProgram();
- /* disabled - mango request, since footage /w only render is quite useful
- * and this option is easy to disable all background images at once */
#if 0
- if (v3d->flag2 & V3D_RENDER_OVERRIDE)
- return;
+ /* find screen coordinates for rotation center, then draw pretty icon */
+ mul_m4_v3(rv3d->persinv, rot_center);
+ UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
+ /* ^^ just playing around, does not work */
#endif
- if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
- if (rv3d->persp == RV3D_CAMOB) {
- view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame);
- }
- }
- else {
- view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame);
- }
-}
-
-/* ****************** View3d afterdraw *************** */
-
-typedef struct View3DAfter {
- struct View3DAfter *next, *prev;
- struct Base *base;
- short dflag;
-} View3DAfter;
-
-/* temp storage of Objects that need to be drawn as last */
-void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag)
-{
- View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after");
- BLI_assert((base->flag & OB_FROMDUPLI) == 0);
- BLI_addtail(lb, v3da);
- v3da->base = base;
- v3da->dflag = dflag;
-}
-
-/* disables write in zbuffer and draws it over */
-static void view3d_draw_transp(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d)
-{
- View3DAfter *v3da;
-
- glDepthMask(GL_FALSE);
- v3d->transp = true;
-
- while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
- draw_object(bmain, scene, ar, v3d, v3da->base, v3da->dflag);
- MEM_freeN(v3da);
- }
- v3d->transp = false;
-
+ GPU_blend(false);
glDepthMask(GL_TRUE);
-
}
+#endif /* WITH_INPUT_NDOF */
-/* clears zbuffer and draws it over */
-static void view3d_draw_xray(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, bool *clear)
-{
- View3DAfter *v3da;
-
- if (*clear && v3d->zbuf) {
- glClear(GL_DEPTH_BUFFER_BIT);
- *clear = false;
- }
-
- v3d->xray = true;
- while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
- draw_object(bmain, scene, ar, v3d, v3da->base, v3da->dflag);
- MEM_freeN(v3da);
- }
- v3d->xray = false;
-}
-
-
-/* clears zbuffer and draws it over */
-static void view3d_draw_xraytransp(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, const bool clear)
-{
- View3DAfter *v3da;
-
- if (clear && v3d->zbuf)
- glClear(GL_DEPTH_BUFFER_BIT);
-
- v3d->xray = true;
- v3d->transp = true;
-
- glDepthMask(GL_FALSE);
-
- while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
- draw_object(bmain, scene, ar, v3d, v3da->base, v3da->dflag);
- MEM_freeN(v3da);
- }
-
- v3d->transp = false;
- v3d->xray = false;
-
- glDepthMask(GL_TRUE);
-}
+/* ******************** info ***************** */
-/* clears zbuffer and draws it over,
- * note that in the select version we don't care about transparent flag as with regular drawing */
-static void view3d_draw_xray_select(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, bool *clear)
+/**
+ * Render and camera border
+ */
+static void view3d_draw_border(const bContext *C, ARegion *ar)
{
- /* Not ideal, but we need to read from the previous depths before clearing
- * otherwise we could have a function to load the depths after drawing.
- *
- * Clearing the depth buffer isn't all that common between drawing objects so accept this for now.
- */
- if (U.gpu_select_pick_deph) {
- GPU_select_load_id(-1);
- }
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ RegionView3D *rv3d = ar->regiondata;
+ View3D *v3d = CTX_wm_view3d(C);
- View3DAfter *v3da;
- if (*clear && v3d->zbuf) {
- glClear(GL_DEPTH_BUFFER_BIT);
- *clear = false;
+ if (rv3d->persp == RV3D_CAMOB) {
+ drawviewborder(scene, depsgraph, ar, v3d);
}
-
- v3d->xray = true;
- while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
- if (GPU_select_load_id(v3da->base->selcol)) {
- draw_object_select(bmain, scene, ar, v3d, v3da->base, v3da->dflag);
- }
- MEM_freeN(v3da);
+ else if (v3d->flag2 & V3D_RENDER_BORDER) {
+ drawrenderborder(ar, v3d);
}
- v3d->xray = false;
}
-/* *********************** */
-
-/*
- * In most cases call draw_dupli_objects,
- * draw_dupli_objects_color was added because when drawing set dupli's
- * we need to force the color
+/**
+ * Grease Pencil
*/
-
-#if 0
-int dupli_ob_sort(void *arg1, void *arg2)
+static void view3d_draw_grease_pencil(const bContext *UNUSED(C))
{
- void *p1 = ((DupliObject *)arg1)->ob;
- void *p2 = ((DupliObject *)arg2)->ob;
- int val = 0;
- if (p1 < p2) val = -1;
- else if (p1 > p2) val = 1;
- return val;
+ /* TODO viewport */
}
-#endif
-
-static DupliObject *dupli_step(DupliObject *dob)
-{
- while (dob && dob->no_draw)
- dob = dob->next;
- return dob;
-}
-
-static void draw_dupli_objects_color(
- Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, Base *base,
- const short dflag, const int color)
+/**
+ * Viewport Name
+ */
+static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d)
{
- RegionView3D *rv3d = ar->regiondata;
- ListBase *lb;
- LodLevel *savedlod;
- DupliObject *dob_prev = NULL, *dob, *dob_next = NULL;
- Base tbase = {NULL};
- BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */
- GLuint displist = 0;
- unsigned char color_rgb[3];
- const short dflag_dupli = dflag | DRAW_CONSTCOLOR;
- short transflag;
- bool use_displist = false; /* -1 is initialize */
- char dt;
- short dtx;
- DupliApplyData *apply_data;
-
- if (base->object->restrictflag & OB_RESTRICT_VIEW) return;
- if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return;
-
- if (dflag & DRAW_CONSTCOLOR) {
- BLI_assert(color == TH_UNDEFINED);
- }
- else {
- UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb);
- }
-
- tbase.flag = OB_FROMDUPLI | base->flag;
- lb = object_duplilist(bmain, bmain->eval_ctx, scene, base->object);
- // BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
-
- apply_data = duplilist_apply(base->object, scene, lb);
-
- dob = dupli_step(lb->first);
- if (dob) dob_next = dupli_step(dob->next);
-
- for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) {
- bool testbb = false;
-
- tbase.object = dob->ob;
-
- /* Make sure lod is updated from dupli's position */
- savedlod = dob->ob->currentlod;
-
-#ifdef WITH_GAMEENGINE
- if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
- BKE_object_lod_update(dob->ob, rv3d->viewinv[3]);
- }
-#endif
-
- /* extra service: draw the duplicator in drawtype of parent, minimum taken
- * to allow e.g. boundbox box objects in groups for LOD */
- dt = tbase.object->dt;
- tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
-
- /* inherit draw extra, but not if a boundbox under the assumption that this
- * is intended to speed up drawing, and drawing extra (especially wire) can
- * slow it down too much */
- dtx = tbase.object->dtx;
- if (tbase.object->dt != OB_BOUNDBOX)
- tbase.object->dtx = base->object->dtx;
-
- /* negative scale flag has to propagate */
- transflag = tbase.object->transflag;
-
- if (is_negative_m4(dob->mat))
- tbase.object->transflag |= OB_NEG_SCALE;
- else
- tbase.object->transflag &= ~OB_NEG_SCALE;
-
- /* should move outside the loop but possible color is set in draw_object still */
- if ((dflag & DRAW_CONSTCOLOR) == 0) {
- glColor3ubv(color_rgb);
- }
-
- /* generate displist, test for new object */
- if (dob_prev && dob_prev->ob != dob->ob) {
- if (use_displist == true)
- glDeleteLists(displist, 1);
-
- use_displist = false;
- }
+ const char *name = NULL;
- if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) {
- bb = *bb_tmp; /* must make a copy */
- testbb = true;
- }
+ switch (rv3d->view) {
+ case RV3D_VIEW_FRONT:
+ if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Orthographic");
+ else name = IFACE_("Front Perspective");
+ break;
+ case RV3D_VIEW_BACK:
+ if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Orthographic");
+ else name = IFACE_("Back Perspective");
+ break;
+ case RV3D_VIEW_TOP:
+ if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Orthographic");
+ else name = IFACE_("Top Perspective");
+ break;
+ case RV3D_VIEW_BOTTOM:
+ if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Orthographic");
+ else name = IFACE_("Bottom Perspective");
+ break;
+ case RV3D_VIEW_RIGHT:
+ if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Orthographic");
+ else name = IFACE_("Right Perspective");
+ break;
+ case RV3D_VIEW_LEFT:
+ if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Orthographic");
+ else name = IFACE_("Left Perspective");
+ break;
- if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) {
- /* generate displist */
- if (use_displist == false) {
-
- /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP)
- * however this is very slow, it was probably needed for the NLA
- * offset feature (used in group-duplicate.blend but no longer works in 2.5)
- * so for now it should be ok to - campbell */
-
- if ( /* if this is the last no need to make a displist */
- (dob_next == NULL || dob_next->ob != dob->ob) ||
- /* lamp drawing messes with matrices, could be handled smarter... but this works */
- (dob->ob->type == OB_LAMP) ||
- (dob->type == OB_DUPLIGROUP && dob->animated) ||
- !bb_tmp ||
- draw_glsl_material(scene, dob->ob, v3d, dt) ||
- check_object_draw_texture(scene, v3d, dt) ||
- (v3d->flag2 & V3D_SOLID_MATCAP) != 0)
- {
- // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2);
- use_displist = false;
+ default:
+ if (rv3d->persp == RV3D_CAMOB) {
+ if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) {
+ Camera *cam;
+ cam = v3d->camera->data;
+ if (cam->type == CAM_PERSP) {
+ name = IFACE_("Camera Perspective");
+ }
+ else if (cam->type == CAM_ORTHO) {
+ name = IFACE_("Camera Orthographic");
+ }
+ else {
+ BLI_assert(cam->type == CAM_PANO);
+ name = IFACE_("Camera Panoramic");
+ }
}
else {
- // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2);
-
- /* disable boundbox check for list creation */
- BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1);
- /* need this for next part of code */
- unit_m4(dob->ob->obmat); /* obmat gets restored */
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
- draw_object(bmain, scene, ar, v3d, &tbase, dflag_dupli);
- glEndList();
-
- use_displist = true;
- BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0);
+ name = IFACE_("Object as Camera");
}
}
-
- if (use_displist) {
- glPushMatrix();
- glMultMatrixf(dob->mat);
- glCallList(displist);
- glPopMatrix();
- }
else {
- copy_m4_m4(dob->ob->obmat, dob->mat);
- GPU_begin_dupli_object(dob);
- draw_object(bmain, scene, ar, v3d, &tbase, dflag_dupli);
- GPU_end_dupli_object();
+ name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Orthographic") : IFACE_("User Perspective");
}
- }
-
- tbase.object->dt = dt;
- tbase.object->dtx = dtx;
- tbase.object->transflag = transflag;
- tbase.object->currentlod = savedlod;
}
- if (apply_data) {
- duplilist_restore(lb, apply_data);
- duplilist_free_apply_data(apply_data);
- }
-
- free_object_duplilist(lb);
-
- if (use_displist)
- glDeleteLists(displist, 1);
-}
-
-static void draw_dupli_objects(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, Base *base)
-{
- /* define the color here so draw_dupli_objects_color can be called
- * from the set loop */
-
- int color = (base->flag & SELECT) ? TH_SELECT : TH_WIRE;
- /* debug */
- if (base->object->dup_group && base->object->dup_group->id.us < 1)
- color = TH_REDALERT;
-
- draw_dupli_objects_color(bmain, scene, ar, v3d, base, 0, color);
+ return name;
}
-/* XXX warning, not using gpu offscreen here */
-void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
+static void draw_viewport_name(ARegion *ar, View3D *v3d, int xoffset, int *yoffset)
{
- int x, y, w, h;
- rcti r;
- /* clamp rect by region */
-
- r.xmin = 0;
- r.xmax = ar->winx - 1;
- r.ymin = 0;
- r.ymax = ar->winy - 1;
-
- /* Constrain rect to depth bounds */
- BLI_rcti_isect(&r, rect, rect);
-
- /* assign values to compare with the ViewDepths */
- x = rect->xmin;
- y = rect->ymin;
+ RegionView3D *rv3d = ar->regiondata;
+ const char *name = view3d_get_name(v3d, rv3d);
+ const int font_id = BLF_default();
- w = BLI_rcti_size_x(rect);
- h = BLI_rcti_size_y(rect);
+ /* increase size for unicode languages (Chinese in utf-8...) */
+#ifdef WITH_INTERNATIONAL
+ char tmpstr[96];
+#else
+ char tmpstr[32];
+#endif
- if (w <= 0 || h <= 0) {
- if (d->depths)
- MEM_freeN(d->depths);
- d->depths = NULL;
+ BLF_enable(font_id, BLF_SHADOW);
+ BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ BLF_shadow_offset(font_id, 1, -1);
- d->damaged = false;
+ if (v3d->localvd) {
+ BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name);
+ name = tmpstr;
}
- else if (d->w != w ||
- d->h != h ||
- d->x != x ||
- d->y != y ||
- d->depths == NULL
- )
- {
- d->x = x;
- d->y = y;
- d->w = w;
- d->h = h;
- if (d->depths)
- MEM_freeN(d->depths);
+ UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
- d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
+ *yoffset -= U.widget_unit;
- d->damaged = true;
- }
+#ifdef WITH_INTERNATIONAL
+ BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr));
+#else
+ BLF_draw_default_ascii(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr));
+#endif
- if (d->damaged) {
- /* XXX using special function here, it doesn't use the gpu offscreen system */
- view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
- glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
- d->damaged = false;
- }
+ BLF_disable(font_id, BLF_SHADOW);
}
-/* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */
-void ED_view3d_depth_update(ARegion *ar)
+/**
+ * draw info beside axes in bottom left-corner:
+ * framenum, collection, object name, bone name (if available), marker name (if available)
+ */
+
+static void draw_selected_name(Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset)
{
- RegionView3D *rv3d = ar->regiondata;
+ const int cfra = CFRA;
+ const char *msg_pin = " (Pinned)";
+ const char *msg_sep = " : ";
- /* Create storage for, and, if necessary, copy depth buffer */
- if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
- if (rv3d->depths) {
- ViewDepths *d = rv3d->depths;
- if (d->w != ar->winx ||
- d->h != ar->winy ||
- !d->depths)
- {
- d->w = ar->winx;
- d->h = ar->winy;
- if (d->depths)
- MEM_freeN(d->depths);
- d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
- d->damaged = true;
- }
+ const int font_id = BLF_default();
- if (d->damaged) {
- view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
- glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
+ char info[300];
+ char *s = info;
- d->damaged = false;
- }
- }
-}
+ s += sprintf(s, "(%d)", cfra);
-/* utility function to find the closest Z value, use for autodepth */
-float view3d_depth_near(ViewDepths *d)
-{
- /* convert to float for comparisons */
- const float near = (float)d->depth_range[0];
- const float far_real = (float)d->depth_range[1];
- float far = far_real;
-
- const float *depths = d->depths;
- float depth = FLT_MAX;
- int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */
-
- /* far is both the starting 'far' value
- * and the closest value found. */
- while (i--) {
- depth = *depths++;
- if ((depth < far) && (depth > near)) {
- far = depth;
- }
+ if ((ob == NULL) || (ob->mode == OB_MODE_OBJECT)) {
+ LayerCollection *layer_collection = view_layer->active_collection;
+ s += sprintf(s, " %s%s", BKE_collection_ui_name_get(layer_collection->collection), (ob == NULL) ? "" : " |");
}
- return far == far_real ? FLT_MAX : far;
-}
-
-void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
-{
- short zbuf = v3d->zbuf;
- RegionView3D *rv3d = ar->regiondata;
-
- /* Setup view matrix. */
- ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat, NULL);
-
- glClear(GL_DEPTH_BUFFER_BIT);
+ /*
+ * info can contain:
+ * - a frame (7 + 2)
+ * - a collection name (MAX_NAME + 3)
+ * - 3 object names (MAX_NAME)
+ * - 2 BREAD_CRUMB_SEPARATORs (6)
+ * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room!
+ * - a marker name (MAX_NAME + 3)
+ */
- v3d->zbuf = true;
- glEnable(GL_DEPTH_TEST);
+ /* get name of marker on current frame (if available) */
+ const char *markern = BKE_scene_find_marker_name(scene, cfra);
- if (v3d->flag2 & V3D_SHOW_GPENCIL) {
- ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true);
- }
+ /* check if there is an object */
+ if (ob) {
+ *s++ = ' ';
+ s += BLI_strcpy_rlen(s, ob->id.name + 2);
- v3d->zbuf = zbuf;
-}
+ /* name(s) to display depends on type of object */
+ if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
-static void view3d_draw_depth_loop(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d)
-{
- Base *base;
-
- /* no need for color when drawing depth buffer */
- const short dflag_depth = DRAW_CONSTCOLOR;
-
- /* draw set first */
- if (scene->set) {
- Scene *sce_iter;
- for (SETLOOPER(scene->set, sce_iter, base)) {
- if (v3d->lay & base->lay) {
- draw_object(bmain, scene, ar, v3d, base, 0);
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects_color(bmain, scene, ar, v3d, base, dflag_depth, TH_UNDEFINED);
+ /* show name of active bone too (if possible) */
+ if (arm->edbo) {
+ if (arm->act_edbone) {
+ s += BLI_strcpy_rlen(s, msg_sep);
+ s += BLI_strcpy_rlen(s, arm->act_edbone->name);
}
}
- }
- }
-
- for (base = scene->base.first; base; base = base->next) {
- if (v3d->lay & base->lay) {
- /* dupli drawing */
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects_color(bmain, scene, ar, v3d, base, dflag_depth, TH_UNDEFINED);
- }
- draw_object(bmain, scene, ar, v3d, base, dflag_depth);
- }
- }
-
- /* this isn't that nice, draw xray objects as if they are normal */
- if (v3d->afterdraw_transp.first ||
- v3d->afterdraw_xray.first ||
- v3d->afterdraw_xraytransp.first)
- {
- View3DAfter *v3da;
- int mask_orig;
-
- v3d->xray = true;
-
- /* transp materials can change the depth mask, see #21388 */
- glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
-
+ else if (ob->mode & OB_MODE_POSE) {
+ if (arm->act_bone) {
- if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) {
- glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */
- for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) {
- draw_object(bmain, scene, ar, v3d, v3da->base, dflag_depth);
+ if (arm->act_bone->layer & arm->layer) {
+ s += BLI_strcpy_rlen(s, msg_sep);
+ s += BLI_strcpy_rlen(s, arm->act_bone->name);
+ }
+ }
}
- glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */
- }
-
- /* draw 3 passes, transp/xray/xraytransp */
- v3d->xray = false;
- v3d->transp = true;
- while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
- draw_object(bmain, scene, ar, v3d, v3da->base, dflag_depth);
- MEM_freeN(v3da);
- }
-
- v3d->xray = true;
- v3d->transp = false;
- while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
- draw_object(bmain, scene, ar, v3d, v3da->base, dflag_depth);
- MEM_freeN(v3da);
- }
-
- v3d->xray = true;
- v3d->transp = true;
- while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
- draw_object(bmain, scene, ar, v3d, v3da->base, dflag_depth);
- MEM_freeN(v3da);
- }
-
-
- v3d->xray = false;
- v3d->transp = false;
-
- glDepthMask(mask_orig);
- }
-}
-
-void ED_view3d_draw_depth(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride)
-{
- struct bThemeState theme_state;
- RegionView3D *rv3d = ar->regiondata;
- short zbuf = v3d->zbuf;
- short flag = v3d->flag;
- float glalphaclip = U.glalphaclip;
- int obcenter_dia = U.obcenter_dia;
- /* temp set drawtype to solid */
-
- /* Setting these temporarily is not nice */
- v3d->flag &= ~V3D_SELECT_OUTLINE;
- U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */
- U.obcenter_dia = 0;
-
- /* Tools may request depth outside of regular drawing code. */
- UI_Theme_Store(&theme_state);
- UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
-
- /* Setup view matrix. */
- ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat, NULL);
-
- glClear(GL_DEPTH_BUFFER_BIT);
-
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_set(rv3d);
- }
- /* get surface depth without bias */
- rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
-
- v3d->zbuf = true;
- glEnable(GL_DEPTH_TEST);
-
- view3d_draw_depth_loop(bmain, scene, ar, v3d);
-
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_disable();
- }
- rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
-
- v3d->zbuf = zbuf;
- if (!v3d->zbuf) glDisable(GL_DEPTH_TEST);
-
- U.glalphaclip = glalphaclip;
- v3d->flag = flag;
- U.obcenter_dia = obcenter_dia;
-
- UI_Theme_Restore(&theme_state);
-}
-
-void ED_view3d_draw_select_loop(
- ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar,
- bool use_obedit_skip, bool use_nearest)
-{
- short code = 1;
- const short dflag = DRAW_PICKING | DRAW_CONSTCOLOR;
-
- if (vc->obedit && vc->obedit->type == OB_MBALL) {
- draw_object(vc->bmain, scene, ar, v3d, BASACT, dflag);
- }
- else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
- /* if not drawing sketch, draw bones */
- if (!BDR_drawSketchNames(vc)) {
- draw_object(vc->bmain, scene, ar, v3d, BASACT, dflag);
}
- }
- else {
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & v3d->lay) {
-
- if ((base->object->restrictflag & OB_RESTRICT_SELECT) ||
- (use_obedit_skip && (scene->obedit->data == base->object->data)))
- {
- base->selcol = 0;
- }
- else {
- base->selcol = code;
+ else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
+ /* try to display active bone and active shapekey too (if they exist) */
- if (use_nearest && (base->object->dtx & OB_DRAWXRAY)) {
- ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag);
- }
- else {
- if (GPU_select_load_id(code)) {
- draw_object_select(vc->bmain, scene, ar, v3d, base, dflag);
+ if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) {
+ Object *armobj = BKE_object_pose_armature_get(ob);
+ if (armobj && armobj->mode & OB_MODE_POSE) {
+ bArmature *arm = armobj->data;
+ if (arm->act_bone) {
+ if (arm->act_bone->layer & arm->layer) {
+ s += BLI_strcpy_rlen(s, msg_sep);
+ s += BLI_strcpy_rlen(s, arm->act_bone->name);
}
}
- code++;
}
}
- }
- if (use_nearest) {
- bool xrayclear = true;
- if (v3d->afterdraw_xray.first) {
- view3d_draw_xray_select(vc->bmain, scene, ar, v3d, &xrayclear);
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1);
+ if (kb) {
+ s += BLI_strcpy_rlen(s, msg_sep);
+ s += BLI_strcpy_rlen(s, kb->name);
+ if (ob->shapeflag & OB_SHAPE_LOCK) {
+ s += BLI_strcpy_rlen(s, IFACE_(msg_pin));
+ }
+ }
}
}
- }
-}
-
-typedef struct View3DShadow {
- struct View3DShadow *next, *prev;
- GPULamp *lamp;
-} View3DShadow;
-
-static void gpu_render_lamp_update(Scene *scene, View3D *v3d,
- Object *ob, Object *par,
- float obmat[4][4], unsigned int lay,
- ListBase *shadows, SceneRenderLayer *srl)
-{
- GPULamp *lamp;
- Lamp *la = (Lamp *)ob->data;
- View3DShadow *shadow;
- unsigned int layers;
-
- lamp = GPU_lamp_from_blender(scene, ob, par);
- if (lamp) {
- GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat);
- GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy);
-
- layers = lay & v3d->lay;
- if (srl)
- layers &= srl->lay;
-
- if (layers &&
- GPU_lamp_has_shadow_buffer(lamp) &&
- /* keep last, may do string lookup */
- GPU_lamp_visible(lamp, srl, NULL))
- {
- shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow");
- shadow->lamp = lamp;
- BLI_addtail(shadows, shadow);
- }
- }
-}
-
-static void gpu_update_lamps_shadows_world(Main *bmain, Scene *scene, View3D *v3d)
-{
- ListBase shadows;
- View3DShadow *shadow;
- Scene *sce_iter;
- Base *base;
- Object *ob;
- World *world = scene->world;
- SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL;
-
- BLI_listbase_clear(&shadows);
-
- /* update lamp transform and gather shadow lamps */
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
-
- if (ob->type == OB_LAMP)
- gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, ob->lay, &shadows, srl);
-
- if (ob->transflag & OB_DUPLI) {
- DupliObject *dob;
- ListBase *lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob);
-
- for (dob = lb->first; dob; dob = dob->next)
- if (dob->ob->type == OB_LAMP)
- gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, ob->lay, &shadows, srl);
-
- free_object_duplilist(lb);
- }
+ /* color depends on whether there is a keyframe */
+ if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL))
+ UI_FontThemeColor(font_id, TH_TIME_KEYFRAME);
+ else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra))
+ UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME);
+ else
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
}
-
- /* render shadows after updating all lamps, nested object_duplilist
- * don't work correct since it's replacing object matrices */
- for (shadow = shadows.first; shadow; shadow = shadow->next) {
- /* this needs to be done better .. */
- float viewmat[4][4], winmat[4][4];
- int drawtype, lay, winsize, flag2 = v3d->flag2;
- ARegion ar = {NULL};
- RegionView3D rv3d = {{{0}}};
-
- drawtype = v3d->drawtype;
- lay = v3d->lay;
-
- v3d->drawtype = OB_SOLID;
- v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp);
- v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP);
- v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW;
-
- GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat);
-
- ar.regiondata = &rv3d;
- ar.regiontype = RGN_TYPE_WINDOW;
- rv3d.persp = RV3D_CAMOB;
- copy_m4_m4(rv3d.winmat, winmat);
- copy_m4_m4(rv3d.viewmat, viewmat);
- invert_m4_m4(rv3d.viewinv, rv3d.viewmat);
- mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
- invert_m4_m4(rv3d.persinv, rv3d.viewinv);
-
- /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */
- ED_view3d_draw_offscreen(
- bmain, scene, v3d, &ar, winsize, winsize, viewmat, winmat,
- false, false, true,
- NULL, NULL, NULL, NULL);
- GPU_lamp_shadow_buffer_unbind(shadow->lamp);
-
- v3d->drawtype = drawtype;
- v3d->lay = lay;
- v3d->flag2 = flag2;
+ else {
+ /* no object */
+ if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra))
+ UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME);
+ else
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
}
- BLI_freelistN(&shadows);
-
- /* update world values */
- if (world) {
- GPU_mist_update_enable(world->mode & WO_MIST);
- GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr);
- GPU_horizon_update_color(&world->horr);
- GPU_ambient_update_color(&world->ambr);
- GPU_zenith_update_color(&world->zenr);
+ if (markern) {
+ s += sprintf(s, " <%s>", markern);
}
-}
-
-/* *********************** customdata **************** */
-CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
-{
- CustomDataMask mask = 0;
- const int drawtype = view3d_effective_drawtype(v3d);
-
- if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) ||
- ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
- {
- mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
+ BLF_enable(font_id, BLF_SHADOW);
+ BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ BLF_shadow_offset(font_id, 1, -1);
- if (BKE_scene_use_new_shading_nodes(scene)) {
- if (drawtype == OB_MATERIAL)
- mask |= CD_MASK_ORCO;
- }
- else {
- if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) ||
- (drawtype == OB_MATERIAL))
- {
- mask |= CD_MASK_ORCO;
- }
- }
- }
+ *yoffset -= U.widget_unit;
+ BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
- return mask;
+ BLF_disable(font_id, BLF_SHADOW);
}
-/* goes over all modes and view3d settings */
-CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
-{
- const Scene *scene = screen->scene;
- CustomDataMask mask = CD_MASK_BAREMESH;
- const ScrArea *sa;
-
- /* check if we need tfaces & mcols due to view mode */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- mask |= ED_view3d_datamask(scene, sa->spacedata.first);
- }
- }
-
- return mask;
-}
+/* ******************** view loop ***************** */
/**
- * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
+ * Information drawn on top of the solid plates and composed data
*/
-void ED_view3d_update_viewmat(
- Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect)
+void view3d_draw_region_info(const bContext *C, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
- /* setup window matrices */
- if (winmat)
- copy_m4_m4(rv3d->winmat, winmat);
- else
- view3d_winmatrix_set(ar, v3d, rect);
-
- /* setup view matrix */
- if (viewmat) {
- copy_m4_m4(rv3d->viewmat, viewmat);
- }
- else {
- float rect_scale[2];
- if (rect) {
- rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx;
- rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy;
- }
- view3d_viewmatrix_set(scene, v3d, rv3d, rect ? rect_scale : NULL); /* note: calls BKE_object_where_is_calc for camera... */
- }
+ /* correct projection matrix */
+ ED_region_pixelspace(ar);
- /* update utility matrices */
- mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
- invert_m4_m4(rv3d->persinv, rv3d->persmat);
- invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
+ /* local coordinate visible rect inside region, to accommodate overlapping ui */
+ rcti rect;
+ ED_region_visible_rect(ar, &rect);
- /* calculate GLSL view dependent values */
- /* store window coordinates scaling/offset */
- if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
- rctf cameraborder;
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false);
- rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder);
- rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder);
+ view3d_draw_border(C, ar);
+ view3d_draw_grease_pencil(C);
- rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx;
- rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy;
- }
- else {
- rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
- rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
- }
+ BLF_batch_draw_begin();
- /**
- * Calculate pixel-size factor once, is used for lamps and object centers.
- * Used by #ED_view3d_pixel_size and typically not accessed directly.
- *
- * \note #BKE_camera_params_compute_viewplane' also calculates a pixel-size value,
- * passed to #RE_SetPixelSize, in ortho mode this is compatible with this value,
- * but in perspective mode its offset by the near-clip.
- *
- * 'RegionView3D.pixsize' is used for viewport drawing, not rendering.
- */
+ if ((U.uiflag & USER_SHOW_GIZMO_AXIS) ||
+ (v3d->flag2 & V3D_RENDER_OVERRIDE) ||
+ /* No need to display gizmo and this info. */
+ (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_NAVIGATE)))
{
- /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])'
- * because of float point precision problems at large values [#23908] */
- float v1[3], v2[3];
- float len_px, len_sc;
-
- v1[0] = rv3d->persmat[0][0];
- v1[1] = rv3d->persmat[1][0];
- v1[2] = rv3d->persmat[2][0];
-
- v2[0] = rv3d->persmat[0][1];
- v2[1] = rv3d->persmat[1][1];
- v2[2] = rv3d->persmat[2][1];
-
- len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
- len_sc = (float)MAX2(ar->winx, ar->winy);
-
- rv3d->pixsize = len_px / len_sc;
- }
-}
-
-/**
- * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects
- *
- * \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set.
- * \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here.
- */
-static void view3d_draw_objects(
- const bContext *C,
- Main *bmain,
- Scene *scene, View3D *v3d, ARegion *ar,
- const char **grid_unit,
- const bool do_bgpic, const bool draw_offscreen, GPUFX *fx)
-{
- if (bmain == NULL) {
- bmain = CTX_data_main(C);
- }
- RegionView3D *rv3d = ar->regiondata;
- Base *base;
- const bool do_camera_frame = !draw_offscreen;
- const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0;
- const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO);
- /* only draw grids after in solid modes, else it hovers over mesh wires */
- const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx;
- bool do_composite_xray = false;
- bool xrayclear = true;
-
- if (!draw_offscreen) {
- ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
- }
-
- if (rv3d->rflag & RV3D_CLIPPING)
- view3d_draw_clipping(rv3d);
-
- /* set zbuffer after we draw clipping region */
- if (v3d->drawtype > OB_WIRE) {
- v3d->zbuf = true;
+ /* pass */
}
else {
- v3d->zbuf = false;
- }
-
- /* special case (depth for wire color) */
- if (v3d->drawtype <= OB_WIRE) {
- if (scene->obedit && scene->obedit->type == OB_MESH) {
- Mesh *me = scene->obedit->data;
- if (me->drawflag & ME_DRAWEIGHT) {
- v3d->zbuf = true;
- }
- }
+ draw_view_axis(rv3d, &rect);
}
- if (v3d->zbuf) {
- glEnable(GL_DEPTH_TEST);
- }
+ int xoffset = rect.xmin + U.widget_unit;
+ int yoffset = rect.ymax;
- /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override
- * objects if done last */
- if (draw_grids) {
- /* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */
- rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit);
-
- if (!draw_floor) {
- ED_region_pixelspace(ar);
- *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */
- drawgrid(&scene->unit, ar, v3d, grid_unit);
- /* XXX make function? replaces persp(1) */
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(rv3d->winmat);
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(rv3d->viewmat);
- }
- else if (!draw_grids_after) {
- drawfloor(scene, v3d, grid_unit, true);
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0 &&
+ (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0)
+ {
+ if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
+ ED_scene_draw_fps(scene, xoffset, &yoffset);
}
- }
-
- /* important to do before clipping */
- if (do_bgpic) {
- view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame);
- }
-
- if (rv3d->rflag & RV3D_CLIPPING) {
- ED_view3d_clipping_set(rv3d);
- }
-
- /* draw set first */
- if (scene->set) {
- const short dflag = DRAW_CONSTCOLOR | DRAW_SCENESET;
- Scene *sce_iter;
- for (SETLOOPER(scene->set, sce_iter, base)) {
- if (v3d->lay & base->lay) {
- UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f);
- draw_object(bmain, scene, ar, v3d, base, dflag);
-
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects_color(bmain, scene, ar, v3d, base, dflag, TH_UNDEFINED);
- }
- }
+ else if (U.uiflag & USER_SHOW_VIEWPORTNAME) {
+ draw_viewport_name(ar, v3d, xoffset, &yoffset);
}
- /* Transp and X-ray afterdraw stuff for sets is done later */
- }
-
-
- if (draw_offscreen) {
- for (base = scene->base.first; base; base = base->next) {
- if (v3d->lay & base->lay) {
- /* dupli drawing */
- if (base->object->transflag & OB_DUPLI)
- draw_dupli_objects(bmain, scene, ar, v3d, base);
-
- draw_object(bmain, scene, ar, v3d, base, 0);
- }
+ if (U.uiflag & USER_DRAWVIEWINFO) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ draw_selected_name(scene, view_layer, ob, xoffset, &yoffset);
}
- }
- else {
- unsigned int lay_used = 0;
- /* then draw not selected and the duplis, but skip editmode object */
- for (base = scene->base.first; base; base = base->next) {
- lay_used |= base->lay;
-
- if (v3d->lay & base->lay) {
+#if 0 /* TODO */
+ if (grid_unit) { /* draw below the viewport name */
+ char numstr[32] = "";
- /* dupli drawing */
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects(bmain, scene, ar, v3d, base);
- }
- if ((base->flag & SELECT) == 0) {
- if (base->object != scene->obedit)
- draw_object(bmain, scene, ar, v3d, base, 0);
- }
+ UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
+ if (v3d->grid != 1.0f) {
+ BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
}
- }
-
- /* mask out localview */
- v3d->lay_used = lay_used & ((1 << 20) - 1);
- /* draw selected and editmode */
- for (base = scene->base.first; base; base = base->next) {
- if (v3d->lay & base->lay) {
- if (base->object == scene->obedit || (base->flag & SELECT)) {
- draw_object(bmain, scene, ar, v3d, base, 0);
- }
- }
+ *yoffset -= U.widget_unit;
+ BLF_draw_default_ascii(xoffset, *yoffset, numstr[0] ? numstr : grid_unit, sizeof(numstr));
}
+#endif
}
- /* perspective floor goes last to use scene depth and avoid writing to depth buffer */
- if (draw_grids_after) {
- drawfloor(scene, v3d, grid_unit, false);
- }
-
- /* must be before xray draw which clears the depth buffer */
- if (v3d->flag2 & V3D_SHOW_GPENCIL) {
- wmWindowManager *wm = (C != NULL) ? CTX_wm_manager(C) : NULL;
-
- /* must be before xray draw which clears the depth buffer */
- if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
- ED_gpencil_draw_view3d(wm, scene, v3d, ar, true);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- }
-
- /* transp and X-ray afterdraw stuff */
- if (v3d->afterdraw_transp.first) view3d_draw_transp(bmain, scene, ar, v3d);
-
- /* always do that here to cleanup depth buffers if none needed */
- if (fx) {
- do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first);
- GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray);
- }
-
- if (v3d->afterdraw_xray.first) view3d_draw_xray(bmain, scene, ar, v3d, &xrayclear);
- if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(bmain, scene, ar, v3d, xrayclear);
-
- if (fx && do_composite_xray) {
- GPU_fx_compositor_XRay_resolve(fx);
- }
-
- if (!draw_offscreen) {
- ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
+ if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
+ DRW_draw_region_engine_info(xoffset, yoffset);
}
- if (rv3d->rflag & RV3D_CLIPPING)
- ED_view3d_clipping_disable();
-
- /* important to do after clipping */
- if (do_bgpic) {
- view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame);
- }
+ BLF_batch_draw_end();
+}
- if (!draw_offscreen) {
- BIF_draw_manipulator(C);
- }
+static void view3d_draw_view(const bContext *C, ARegion *ar)
+{
+ ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, CTX_wm_view3d(C), NULL, NULL, NULL);
- /* cleanup */
- if (v3d->zbuf) {
- v3d->zbuf = false;
- glDisable(GL_DEPTH_TEST);
- }
+ /* Only 100% compliant on new spec goes below */
+ DRW_draw_view(C);
+}
- if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
- GPU_free_images_old(bmain);
+RenderEngineType *ED_view3d_engine_type(Scene *scene, int drawtype)
+{
+ /*
+ * Temporary viewport draw modes until we have a proper system.
+ * all modes are done in the draw manager, except
+ * cycles material as it is an external render engine.
+ */
+ if (strcmp(scene->r.engine, RE_engine_id_CYCLES) == 0 && drawtype == OB_MATERIAL) {
+ return RE_engines_find(RE_engine_id_BLENDER_EEVEE);
}
+ return RE_engines_find(scene->r.engine);
}
-static void view3d_main_region_setup_view(
- Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect)
+void view3d_main_region_draw(const bContext *C, ARegion *ar)
{
- RegionView3D *rv3d = ar->regiondata;
+ Main *bmain = CTX_data_main(C);
+ View3D *v3d = CTX_wm_view3d(C);
- ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat, rect);
+ view3d_draw_view(C, ar);
- /* set for opengl */
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(rv3d->winmat);
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(rv3d->viewmat);
-}
+ GPU_free_images_old(bmain);
+ GPU_pass_cache_garbage_collect();
-/**
- * Store values from #RegionView3D, set when drawing.
- * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example).
- *
- * Values set by #ED_view3d_update_viewmat should be handled here.
- */
-struct RV3DMatrixStore {
- float winmat[4][4];
- float viewmat[4][4];
- float viewinv[4][4];
- float persmat[4][4];
- float persinv[4][4];
- float viewcamtexcofac[4];
- float pixsize;
-};
-
-struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
-{
- struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__);
- copy_m4_m4(rv3dmat->winmat, rv3d->winmat);
- copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat);
- copy_m4_m4(rv3dmat->persmat, rv3d->persmat);
- copy_m4_m4(rv3dmat->persinv, rv3d->persinv);
- copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv);
- copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac);
- rv3dmat->pixsize = rv3d->pixsize;
- return (void *)rv3dmat;
-}
+ /* XXX This is in order to draw UI batches with the DRW
+ * olg context since we now use it for drawing the entire area */
+ gpu_batch_presets_reset();
-void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat)
-{
- copy_m4_m4(rv3d->winmat, rv3dmat->winmat);
- copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat);
- copy_m4_m4(rv3d->persmat, rv3dmat->persmat);
- copy_m4_m4(rv3d->persinv, rv3dmat->persinv);
- copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv);
- copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac);
- rv3d->pixsize = rv3dmat->pixsize;
-}
+ /* No depth test for drawing action zones afterwards. */
+ GPU_depth_test(false);
-void ED_view3d_draw_offscreen_init(Main *bmain, Scene *scene, View3D *v3d)
-{
- /* shadow buffers, before we setup matrices */
- if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows_world(bmain, scene, v3d);
+ v3d->flag |= V3D_INVALID_BACKBUF;
}
-/*
- * Function to clear the view
- */
-static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
-{
- if (scene->world && (v3d->flag2 & V3D_SHOW_WORLD)) {
- RegionView3D *rv3d = ar->regiondata;
- GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
-
- /* calculate full shader for background */
- GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
-
- bool material_not_bound = !GPU_material_bound(gpumat);
-
- if (material_not_bound) {
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
- }
+/* -------------------------------------------------------------------- */
- /* Draw world */
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
- glBegin(GL_TRIANGLE_STRIP);
- glVertex3f(-1.0, -1.0, 1.0);
- glVertex3f(1.0, -1.0, 1.0);
- glVertex3f(-1.0, 1.0, 1.0);
- glVertex3f(1.0, 1.0, 1.0);
- glEnd();
-
- if (material_not_bound) {
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
+/** \name Offscreen Drawing
+ * \{ */
- GPU_material_unbind(gpumat);
+static void view3d_stereo3d_setup_offscreen(
+ Depsgraph *depsgraph, Scene *scene, View3D *v3d, ARegion *ar,
+ float winmat[4][4], const char *viewname)
+{
+ /* update the viewport matrices with the new camera */
+ if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
+ float viewmat[4][4];
+ const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
- glDepthFunc(GL_LEQUAL);
- glDisable(GL_DEPTH_TEST);
+ BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
+ view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL);
}
- else {
- if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) {
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
- glBegin(GL_QUADS);
- UI_ThemeColor(TH_LOW_GRAD);
- glVertex3f(-1.0, -1.0, 1.0);
- glVertex3f(1.0, -1.0, 1.0);
- UI_ThemeColor(TH_HIGH_GRAD);
- glVertex3f(1.0, 1.0, 1.0);
- glVertex3f(-1.0, 1.0, 1.0);
- glEnd();
- glDepthFunc(GL_LEQUAL);
- glDisable(GL_DEPTH_TEST);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
-
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- else {
- UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
+ else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
+ float viewmat[4][4];
+ Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
+
+ BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
+ view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL);
}
}
-/* ED_view3d_draw_offscreen_init should be called before this to initialize
- * stuff like shadow buffers
- */
void ED_view3d_draw_offscreen(
- Main *bmain, Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
+ Depsgraph *depsgraph, Scene *scene,
+ int drawtype,
+ View3D *v3d, ARegion *ar, int winx, int winy,
float viewmat[4][4], float winmat[4][4],
- bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
- GPUFX *fx, GPUFXSettings *fx_settings,
- GPUOffScreen *ofs)
+ bool do_sky, bool UNUSED(is_persp), const char *viewname,
+ GPUFXSettings *UNUSED(fx_settings),
+ GPUOffScreen *ofs, GPUViewport *viewport)
{
- struct bThemeState theme_state;
- int bwinx, bwiny;
- rcti brect;
- bool do_compositing = false;
RegionView3D *rv3d = ar->regiondata;
-
- glPushMatrix();
+ RenderEngineType *engine_type = ED_view3d_engine_type(scene, drawtype);
/* set temporary new size */
- bwinx = ar->winx;
- bwiny = ar->winy;
- brect = ar->winrct;
+ int bwinx = ar->winx;
+ int bwiny = ar->winy;
+ rcti brect = ar->winrct;
ar->winx = winx;
ar->winy = winy;
@@ -3197,6 +1402,7 @@ void ED_view3d_draw_offscreen(
ar->winrct.xmax = winx;
ar->winrct.ymax = winy;
+ struct bThemeState theme_state;
UI_Theme_Store(&theme_state);
UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
@@ -3206,69 +1412,31 @@ void ED_view3d_draw_offscreen(
if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
/* free images which can have changed on frame-change
* warning! can be slow so only free animated images - campbell */
- GPU_free_images_anim(bmain);
+ GPU_free_images_anim(G.main); /* XXX :((( */
}
- /* setup view matrices before fx or unbinding the offscreen buffers will cause issues */
+ GPU_matrix_push_projection();
+ GPU_matrix_identity_set();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+
if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
- view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
+ view3d_stereo3d_setup_offscreen(depsgraph, scene, v3d, ar, winmat, viewname);
else
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL);
-
- /* framebuffer fx needed, we need to draw offscreen first */
- if (v3d->fx_settings.fx_flag && fx) {
- GPUSSAOSettings *ssao = NULL;
-
- if (v3d->drawtype < OB_SOLID) {
- ssao = v3d->fx_settings.ssao;
- v3d->fx_settings.ssao = NULL;
- }
-
- do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings);
-
- if (ssao)
- v3d->fx_settings.ssao = ssao;
- }
-
- /* clear opengl buffers */
- if (do_sky) {
- view3d_main_region_clear(scene, v3d, ar);
- }
- else {
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
+ view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL);
/* main drawing call */
- view3d_draw_objects(NULL, bmain, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL);
-
- /* post process */
- if (do_compositing) {
- if (!winmat)
- is_persp = rv3d->is_persp;
- GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs);
- }
-
- if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
- /* draw grease-pencil stuff */
- ED_region_pixelspace(ar);
-
-
- if (v3d->flag2 & V3D_SHOW_GPENCIL) {
- /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
- ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false);
- }
-
- /* freeing the images again here could be done after the operator runs, leaving for now */
- GPU_free_images_anim(bmain);
- }
+ DRW_draw_render_loop_offscreen(
+ depsgraph, engine_type, ar, v3d,
+ do_sky, ofs, viewport);
/* restore size */
ar->winx = bwinx;
ar->winy = bwiny;
ar->winrct = brect;
- glPopMatrix();
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
UI_Theme_Restore(&theme_state);
@@ -3276,40 +1444,22 @@ void ED_view3d_draw_offscreen(
}
/**
- * Set the correct matrices
- */
-void ED_view3d_draw_setup_view(
- wmWindow *win, Scene *scene, ARegion *ar, View3D *v3d, float viewmat[4][4], float winmat[4][4], const rcti *rect)
-{
- RegionView3D *rv3d = ar->regiondata;
-
- /* Setup the view matrix. */
- if (view3d_stereo3d_active(win, scene, v3d, rv3d)) {
- view3d_stereo3d_setup(scene, v3d, ar, rect);
- }
- else {
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, rect);
- }
-}
-
-/**
* Utility func for ED_view3d_draw_offscreen
*
* \param ofs: Optional off-screen buffer, can be NULL.
* (avoids re-creating when doing multiple GL renders).
*/
ImBuf *ED_view3d_draw_offscreen_imbuf(
- Main *bmain, Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
+ int drawtype,
View3D *v3d, ARegion *ar, int sizex, int sizey,
unsigned int flag, unsigned int draw_flags,
int alpha_mode, int samples, const char *viewname,
/* output vars */
- GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
+ GPUOffScreen *ofs, char err_out[256])
{
RegionView3D *rv3d = ar->regiondata;
- ImBuf *ibuf;
const bool draw_sky = (alpha_mode == R_ADDSKY);
- const bool draw_background = (draw_flags & V3D_OFSDRAW_USE_BACKGROUND);
const bool use_full_sample = (draw_flags & V3D_OFSDRAW_USE_FULL_SAMPLE);
/* view state */
@@ -3322,34 +1472,43 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
ofs = NULL;
}
+ GPUFrameBuffer *old_fb = GPU_framebuffer_active_get();
+
+ if (old_fb) {
+ GPU_framebuffer_restore();
+ }
+
const bool own_ofs = (ofs == NULL);
+ DRW_opengl_context_enable();
if (own_ofs) {
/* bind */
- ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, err_out);
+ ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, true, false, err_out);
if (ofs == NULL) {
+ DRW_opengl_context_disable();
return NULL;
}
}
- ED_view3d_draw_offscreen_init(bmain, scene, v3d);
-
GPU_offscreen_bind(ofs, true);
/* read in pixels & stamp */
- ibuf = IMB_allocImBuf(sizex, sizey, 32, flag);
+ ImBuf *ibuf = IMB_allocImBuf(sizex, sizey, 32, flag);
/* render 3d view */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
CameraParams params;
Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
+ const Object *camera_eval = DEG_get_evaluated_object(
+ depsgraph,
+ camera);
BKE_camera_params_init(&params);
/* fallback for non camera objects */
params.clipsta = v3d->near;
params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, camera);
- BKE_camera_multiview_params(&scene->r, &params, camera, viewname);
+ BKE_camera_params_from_object(&params, camera_eval);
+ BKE_camera_multiview_params(&scene->r, &params, camera_eval, viewname);
BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -3362,7 +1521,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
rctf viewplane;
float clipsta, clipend;
- is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
+ is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
if (is_ortho) {
orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
}
@@ -3374,9 +1533,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
if ((samples && use_full_sample) == 0) {
/* Single-pass render, common case */
ED_view3d_draw_offscreen(
- bmain, scene, v3d, ar, sizex, sizey, NULL, winmat,
- draw_background, draw_sky, !is_ortho, viewname,
- fx, &fx_settings, ofs);
+ depsgraph, scene, drawtype,
+ v3d, ar, sizex, sizey, NULL, winmat,
+ draw_sky, !is_ortho, viewname,
+ &fx_settings, ofs, NULL);
if (ibuf->rect_float) {
GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
@@ -3390,28 +1550,22 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
* Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */
static float jit_ofs[32][2];
float winmat_jitter[4][4];
- /* use imbuf as temp storage, before writing into it from accumulation buffer */
- unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float;
- unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1");
- unsigned int i;
- int j;
+ float *rect_temp = (ibuf->rect_float) ? ibuf->rect_float : MEM_mallocN(sizex * sizey * sizeof(float[4]), "rect_temp");
+ float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float[4]), "accum_buffer");
+ GPUViewport *viewport = GPU_viewport_create_from_offscreen(ofs);
BLI_jitter_init(jit_ofs, samples);
/* first sample buffer, also initializes 'rv3d->persmat' */
ED_view3d_draw_offscreen(
- bmain, scene, v3d, ar, sizex, sizey, NULL, winmat,
- draw_background, draw_sky, !is_ortho, viewname,
- fx, &fx_settings, ofs);
- GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
-
- i = sizex * sizey * 4;
- while (i--) {
- accum_buffer[i] = rect_temp[i];
- }
+ depsgraph, scene, drawtype,
+ v3d, ar, sizex, sizey, NULL, winmat,
+ draw_sky, !is_ortho, viewname,
+ &fx_settings, ofs, viewport);
+ GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer);
/* skip the first sample */
- for (j = 1; j < samples; j++) {
+ for (int j = 1; j < samples; j++) {
copy_m4_m4(winmat_jitter, winmat);
window_translate_m4(
winmat_jitter, rv3d->persmat,
@@ -3419,29 +1573,40 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
(jit_ofs[j][1] * 2.0f) / sizey);
ED_view3d_draw_offscreen(
- bmain, scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
- draw_background, draw_sky, !is_ortho, viewname,
- fx, &fx_settings, ofs);
- GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
+ depsgraph, scene, drawtype,
+ v3d, ar, sizex, sizey, NULL, winmat_jitter,
+ draw_sky, !is_ortho, viewname,
+ &fx_settings, ofs, viewport);
+ GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp);
- i = sizex * sizey * 4;
+ unsigned int i = sizex * sizey * 4;
while (i--) {
accum_buffer[i] += rect_temp[i];
}
}
+ {
+ /* don't free data owned by 'ofs' */
+ GPU_viewport_clear_from_offscreen(viewport);
+ GPU_viewport_free(viewport);
+ }
+
+ if (ibuf->rect_float == NULL) {
+ MEM_freeN(rect_temp);
+ }
+
if (ibuf->rect_float) {
float *rect_float = ibuf->rect_float;
- i = sizex * sizey * 4;
+ unsigned int i = sizex * sizey * 4;
while (i--) {
- rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f);
+ rect_float[i] = accum_buffer[i] / samples;
}
}
else {
unsigned char *rect_ub = (unsigned char *)ibuf->rect;
- i = sizex * sizey * 4;
+ unsigned int i = sizex * sizey * 4;
while (i--) {
- rect_ub[i] = accum_buffer[i] / samples;
+ rect_ub[i] = (unsigned char)(255.0f * accum_buffer[i] / samples);
}
}
@@ -3455,6 +1620,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
GPU_offscreen_free(ofs);
}
+ DRW_opengl_context_disable();
+
+ if (old_fb) {
+ GPU_framebuffer_bind(old_fb);
+ }
+
if (ibuf->rect_float && ibuf->rect)
IMB_rect_from_float(ibuf);
@@ -3470,11 +1641,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(
* \note used by the sequencer
*/
ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
- Main *bmain, Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
+ int drawtype,
Object *camera, int width, int height,
- unsigned int flag, unsigned int draw_flags, int drawtype,
+ unsigned int flag, unsigned int draw_flags,
int alpha_mode, int samples, const char *viewname,
- GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
+ GPUOffScreen *ofs, char err_out[256])
{
View3D v3d = {NULL};
ARegion ar = {NULL};
@@ -3486,19 +1658,18 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
ar.regiontype = RGN_TYPE_WINDOW;
v3d.camera = camera;
- v3d.lay = scene->lay;
- v3d.drawtype = drawtype;
+ v3d.shading.type = drawtype;
v3d.flag2 = V3D_RENDER_OVERRIDE;
if (draw_flags & V3D_OFSDRAW_USE_GPENCIL) {
- v3d.flag2 |= V3D_SHOW_GPENCIL;
+ v3d.flag2 |= V3D_SHOW_ANNOTATION;
}
if (draw_flags & V3D_OFSDRAW_USE_SOLID_TEX) {
v3d.flag2 |= V3D_SOLID_TEX;
}
- if (draw_flags & V3D_OFSDRAW_USE_BACKGROUND) {
- v3d.flag2 |= V3D_SHOW_WORLD;
- }
+
+ v3d.shading.background_type = V3D_SHADING_BACKGROUND_WORLD;
+
if (draw_flags & V3D_OFSDRAW_USE_CAMERA_DOF) {
if (camera->type == OB_CAMERA) {
v3d.fx_settings.dof = &((Camera *)camera->data)->gpu_dof;
@@ -3514,11 +1685,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
{
CameraParams params;
- Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname);
+ const Object *view_camera_eval = DEG_get_evaluated_object(
+ depsgraph,
+ BKE_camera_multiview_render(scene, v3d.camera, viewname));
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, view_camera);
- BKE_camera_multiview_params(&scene->r, &params, view_camera, viewname);
+ BKE_camera_params_from_object(&params, view_camera_eval);
+ BKE_camera_multiview_params(&scene->r, &params, view_camera_eval, viewname);
BKE_camera_params_compute_viewplane(&params, width, height, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -3532,671 +1705,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
return ED_view3d_draw_offscreen_imbuf(
- bmain, scene, &v3d, &ar, width, height, flag, draw_flags,
- alpha_mode, samples, viewname, fx, ofs, err_out);
-}
-
-
-/**
- * \note The info that this uses is updated in #ED_refresh_viewport_fps,
- * which currently gets called during #SCREEN_OT_animation_step.
- */
-void ED_scene_draw_fps(Scene *scene, const rcti *rect)
-{
- ScreenFrameRateInfo *fpsi = scene->fps_info;
- float fps;
- char printable[16];
- int i, tot;
-
- if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime)
- return;
-
- printable[0] = '\0';
-
-#if 0
- /* this is too simple, better do an average */
- fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime))
-#else
- fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime));
-
- for (i = 0, tot = 0, fps = 0.0f; i < REDRAW_FRAME_AVERAGE; i++) {
- if (fpsi->redrawtimes_fps[i]) {
- fps += fpsi->redrawtimes_fps[i];
- tot++;
- }
- }
- if (tot) {
- fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
-
- //fpsi->redrawtime_index++;
- //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE)
- // fpsi->redrawtime = 0;
-
- fps = fps / tot;
- }
-#endif
-
- /* is this more than half a frame behind? */
- if (fps + 0.5f < (float)(FPS)) {
- UI_ThemeColor(TH_REDALERT);
- BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps);
- }
- else {
- UI_ThemeColor(TH_TEXT_HI);
- BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f));
- }
-
-#ifdef WITH_INTERNATIONAL
- BLF_draw_default(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable));
-#else
- BLF_draw_default_ascii(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable));
-#endif
-}
-
-static bool view3d_main_region_do_render_draw(const Scene *scene)
-{
- RenderEngineType *type = RE_engines_find(scene->r.engine);
-
- return (type && type->view_update && type->view_draw);
-}
-
-bool ED_view3d_calc_render_border(
- const Scene *scene, const View3D *v3d, const ARegion *ar,
- rcti *rect)
-{
- RegionView3D *rv3d = ar->regiondata;
- rctf viewborder;
- bool use_border;
-
- /* test if there is a 3d view rendering */
- if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene))
- return false;
-
- /* test if there is a border render */
- if (rv3d->persp == RV3D_CAMOB)
- use_border = (scene->r.mode & R_BORDER) != 0;
- else
- use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0;
-
- if (!use_border)
- return false;
-
- /* compute border */
- if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
-
- rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
- rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
- rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder);
- rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder);
- }
- else {
- rect->xmin = v3d->render_border.xmin * ar->winx;
- rect->xmax = v3d->render_border.xmax * ar->winx;
- rect->ymin = v3d->render_border.ymin * ar->winy;
- rect->ymax = v3d->render_border.ymax * ar->winy;
- }
-
- BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin);
- BLI_rcti_isect(&ar->winrct, rect, rect);
-
- return true;
-}
-
-static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene,
- ARegion *ar, View3D *v3d,
- bool clip_border, const rcti *border_rect)
-{
- RegionView3D *rv3d = ar->regiondata;
- RenderEngineType *type;
- GLint scissor[4];
-
- /* create render engine */
- if (!rv3d->render_engine) {
- RenderEngine *engine;
-
- type = RE_engines_find(scene->r.engine);
-
- if (!(type->view_update && type->view_draw))
- return false;
-
- engine = RE_engine_create_ex(type, true);
-
- engine->tile_x = scene->r.tilex;
- engine->tile_y = scene->r.tiley;
-
- type->view_update(engine, C);
-
- rv3d->render_engine = engine;
- }
-
- /* setup view matrices */
- view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL, NULL);
-
- /* background draw */
- ED_region_pixelspace(ar);
-
- if (clip_border) {
- /* for border draw, we only need to clear a subset of the 3d view */
- if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) {
- glGetIntegerv(GL_SCISSOR_BOX, scissor);
- glScissor(border_rect->xmin, border_rect->ymin,
- BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect));
- }
- else {
- return false;
- }
- }
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- if (v3d->flag & V3D_DISPBGPICS)
- view3d_draw_bgpic_test(scene, ar, v3d, false, true);
- else
- fdrawcheckerboard(0, 0, ar->winx, ar->winy);
-
- /* render result draw */
- type = rv3d->render_engine->type;
- type->view_draw(rv3d->render_engine, C);
-
- if (v3d->flag & V3D_DISPBGPICS)
- view3d_draw_bgpic_test(scene, ar, v3d, true, true);
-
- if (clip_border) {
- /* restore scissor as it was before */
- glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
- }
-
- return true;
-}
-
-static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border)
-{
- float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
-
- if (!rv3d->render_engine || !rv3d->render_engine->text[0])
- return;
-
- if (render_border) {
- /* draw darkened background color. no alpha because border render does
- * partial redraw and will not redraw the region behind this info bar */
- float alpha = 1.0f - fill_color[3];
- Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
-
- if (camera) {
- if (camera->flag & CAM_SHOWPASSEPARTOUT) {
- alpha *= (1.0f - camera->passepartalpha);
- }
- }
-
- UI_GetThemeColor3fv(TH_HIGH_GRAD, fill_color);
- mul_v3_fl(fill_color, alpha);
- fill_color[3] = 1.0f;
- }
-
- ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true);
-}
-
-static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d)
-{
- if ((scene->r.scemode & R_MULTIVIEW) == 0) {
- return false;
- }
-
- if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) {
- return false;
- }
-
- switch (v3d->stereo3d_camera) {
- case STEREO_MONO_ID:
- return false;
- break;
- case STEREO_3D_ID:
- /* win will be NULL when calling this from the selection or draw loop. */
- if ((win == NULL) || (WM_stereo3d_enabled(win, true) == false)) {
- return false;
- }
- if (((scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) != 0) &&
- !BKE_scene_multiview_is_stereo3d(&scene->r))
- {
- return false;
- }
- break;
- /* We always need the stereo calculation for left and right cameras. */
- case STEREO_LEFT_ID:
- case STEREO_RIGHT_ID:
- default:
- break;
- }
- return true;
+ depsgraph, scene, drawtype,
+ &v3d, &ar, width, height, flag,
+ draw_flags, alpha_mode, samples, viewname, ofs, err_out);
}
-/* setup the view and win matrices for the multiview cameras
- *
- * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called
- * we have no winmatrix (i.e., projection matrix) defined at that time.
- * Since the camera and the camera shift are needed for the winmat calculation
- * we do a small hack to replace it temporarily so we don't need to change the
- * view3d)main_region_setup_view() code to account for that.
- */
-static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect)
-{
- bool is_left;
- const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
- const char *viewname;
-
- /* show only left or right camera */
- if (v3d->stereo3d_camera != STEREO_3D_ID)
- v3d->multiview_eye = v3d->stereo3d_camera;
-
- is_left = v3d->multiview_eye == STEREO_LEFT_ID;
- viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
-
- /* update the viewport matrices with the new camera */
- if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
- Camera *data;
- float viewmat[4][4];
- float shiftx;
-
- data = (Camera *)v3d->camera->data;
- shiftx = data->shiftx;
-
- BLI_thread_lock(LOCK_VIEW3D);
- data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
-
- BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect);
-
- data->shiftx = shiftx;
- BLI_thread_unlock(LOCK_VIEW3D);
- }
- else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
- float viewmat[4][4];
- Object *view_ob = v3d->camera;
- Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
-
- BLI_thread_lock(LOCK_VIEW3D);
- v3d->camera = camera;
-
- BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect);
-
- v3d->camera = view_ob;
- BLI_thread_unlock(LOCK_VIEW3D);
- }
-}
-
-static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
- float winmat[4][4], const char *viewname)
-{
- /* update the viewport matrices with the new camera */
- if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
- float viewmat[4][4];
- const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
-
- BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL);
- }
- else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
- float viewmat[4][4];
- Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
-
- BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
- view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL);
- }
-}
-
-#ifdef WITH_GAMEENGINE
-static void update_lods(Scene *scene, float camera_pos[3])
-{
- Scene *sce_iter;
- Base *base;
- Object *ob;
-
- for (SETLOOPER(scene, sce_iter, base)) {
- ob = base->object;
- BKE_object_lod_update(ob, camera_pos);
- }
-}
-#endif
-
-static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d,
- ARegion *ar, const char **grid_unit)
-{
- Main *bmain = CTX_data_main(C);
- wmWindow *win = CTX_wm_window(C);
- RegionView3D *rv3d = ar->regiondata;
- unsigned int lay_used = v3d->lay_used;
-
- /* post processing */
- bool do_compositing = false;
-
- /* shadow buffers, before we setup matrices */
- if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
- gpu_update_lamps_shadows_world(bmain, scene, v3d);
-
- /* reset default OpenGL lights if needed (i.e. after preferences have been altered) */
- if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) {
- rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE;
- GPU_default_lights();
- }
-
- /* Setup the view matrix. */
- ED_view3d_draw_setup_view(CTX_wm_window(C), scene, ar, v3d, NULL, NULL, NULL);
-
- rv3d->rflag &= ~RV3D_IS_GAME_ENGINE;
-#ifdef WITH_GAMEENGINE
- if (STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)) {
- rv3d->rflag |= RV3D_IS_GAME_ENGINE;
-
- /* Make sure LoDs are up to date */
- update_lods(scene, rv3d->viewinv[3]);
- }
-#endif
-
- /* framebuffer fx needed, we need to draw offscreen first */
- if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) {
- GPUFXSettings fx_settings;
- BKE_screen_gpu_fx_validate(&v3d->fx_settings);
- fx_settings = v3d->fx_settings;
- if (!rv3d->compositor)
- rv3d->compositor = GPU_fx_compositor_create();
-
- if (rv3d->persp == RV3D_CAMOB && v3d->camera)
- BKE_camera_to_gpu_dof(v3d->camera, &fx_settings);
- else {
- fx_settings.dof = NULL;
- }
-
- do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings);
- }
-
- /* clear the background */
- view3d_main_region_clear(scene, v3d, ar);
-
- /* enables anti-aliasing for 3D view drawing */
- if (win->multisamples != USER_MULTISAMPLE_NONE) {
- glEnable(GL_MULTISAMPLE);
- }
-
- /* main drawing call */
- view3d_draw_objects(C, bmain, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL);
-
- /* post process */
- if (do_compositing) {
- GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL);
- }
-
- /* Disable back anti-aliasing */
- if (win->multisamples != USER_MULTISAMPLE_NONE) {
- glDisable(GL_MULTISAMPLE);
- }
-
- if (v3d->lay_used != lay_used) { /* happens when loading old files or loading with UI load */
- /* find header and force tag redraw */
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
- ED_region_tag_redraw(ar_header); /* can be NULL */
- }
-
- if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- BDR_drawSketch(C);
- }
-
-#ifdef WITH_INPUT_NDOF
- if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((rv3d->viewlock & RV3D_LOCKED) == 0) && (rv3d->persp != RV3D_CAMOB))
- /* TODO: draw something else (but not this) during fly mode */
- draw_rotation_guide(rv3d);
-#endif
-}
-
-static bool is_cursor_visible(Scene *scene)
-{
- if (U.app_flag & USER_APP_VIEW3D_HIDE_CURSOR) {
- return false;
- }
-
- Object *ob = OBACT;
-
- /* don't draw cursor in paint modes, but with a few exceptions */
- if (ob && ob->mode & OB_MODE_ALL_PAINT) {
- /* exception: object is in weight paint and has deforming armature in pose mode */
- if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- if (BKE_object_pose_armature_get(ob) != NULL) {
- return true;
- }
- }
- /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */
- else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
- const Paint *p = BKE_paint_get_active(scene);
-
- if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) {
- if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) {
- return true;
- }
- }
- }
-
- /* no exception met? then don't draw cursor! */
- return false;
- }
-
- return true;
-}
-
-static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
- ARegion *ar, View3D *v3d,
- const char *grid_unit, bool render_border)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- RegionView3D *rv3d = ar->regiondata;
- rcti rect;
-
- /* local coordinate visible rect inside region, to accomodate overlapping ui */
- ED_region_visible_rect(ar, &rect);
-
- if (rv3d->persp == RV3D_CAMOB) {
- drawviewborder(scene, ar, v3d);
- }
- else if (v3d->flag2 & V3D_RENDER_BORDER) {
- glLineWidth(1.0f);
- setlinestyle(3);
- cpack(0x4040FF);
-
- sdrawbox(v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy,
- v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy);
-
- setlinestyle(0);
- }
-
- if (v3d->flag2 & V3D_SHOW_GPENCIL) {
- /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
- ED_gpencil_draw_view3d(wm, scene, v3d, ar, false);
- }
-
- if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- Object *ob;
-
- /* 3d cursor */
- if (is_cursor_visible(scene)) {
- drawcursor(scene, ar, v3d);
- }
-
- if (U.uiflag & USER_SHOW_ROTVIEWICON)
- draw_view_axis(rv3d, &rect);
- else
- draw_view_icon(rv3d, &rect);
-
- ob = OBACT;
- if (U.uiflag & USER_DRAWVIEWINFO)
- draw_selected_name(scene, ob, &rect);
- }
-
- if (rv3d->render_engine) {
- view3d_main_region_draw_engine_info(v3d, rv3d, ar, render_border);
- return;
- }
-
- if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
- ED_scene_draw_fps(scene, &rect);
- }
- else if (U.uiflag & USER_SHOW_VIEWPORTNAME) {
- draw_viewport_name(ar, v3d, &rect);
- }
-
- if (grid_unit) { /* draw below the viewport name */
- char numstr[32] = "";
-
- UI_ThemeColor(TH_TEXT_HI);
- if (v3d->grid != 1.0f) {
- BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
- }
-
- BLF_draw_default_ascii(rect.xmin + U.widget_unit,
- rect.ymax - (USER_SHOW_VIEWPORTNAME ? 2 * U.widget_unit : U.widget_unit), 0.0f,
- numstr[0] ? numstr : grid_unit, sizeof(numstr));
- }
- }
-}
-
-void view3d_main_region_draw(const bContext *C, ARegion *ar)
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- const char *grid_unit = NULL;
- rcti border_rect;
- bool render_border, clip_border;
-
- /* if we only redraw render border area, skip opengl draw and also
- * don't do scissor because it's already set */
- render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect);
- clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect));
-
- /* draw viewport using opengl */
- if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) {
- view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit);
-
-#ifdef DEBUG_DRAW
- bl_debug_draw();
-#endif
- if (G.debug & G_DEBUG_SIMDATA)
- draw_sim_debug_data(scene, v3d, ar);
-
- ED_region_pixelspace(ar);
- }
-
- /* draw viewport using external renderer */
- if (v3d->drawtype == OB_RENDER)
- view3d_main_region_draw_engine(C, scene, ar, v3d, clip_border, &border_rect);
-
- view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border);
-
- v3d->flag |= V3D_INVALID_BACKBUF;
-
- BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp));
- BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray));
- BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp));
-}
-
-#ifdef DEBUG_DRAW
-/* debug drawing */
-#define _DEBUG_DRAW_QUAD_TOT 1024
-#define _DEBUG_DRAW_EDGE_TOT 1024
-static float _bl_debug_draw_quads[_DEBUG_DRAW_QUAD_TOT][4][3];
-static int _bl_debug_draw_quads_tot = 0;
-static float _bl_debug_draw_edges[_DEBUG_DRAW_QUAD_TOT][2][3];
-static int _bl_debug_draw_edges_tot = 0;
-static unsigned int _bl_debug_draw_quads_color[_DEBUG_DRAW_QUAD_TOT];
-static unsigned int _bl_debug_draw_edges_color[_DEBUG_DRAW_EDGE_TOT];
-static unsigned int _bl_debug_draw_color;
-
-void bl_debug_draw_quad_clear(void)
-{
- _bl_debug_draw_quads_tot = 0;
- _bl_debug_draw_edges_tot = 0;
- _bl_debug_draw_color = 0x00FF0000;
-}
-void bl_debug_color_set(const unsigned int color)
-{
- _bl_debug_draw_color = color;
-}
-void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3])
-{
- if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_QUAD_TOT) {
- printf("%s: max quad count hit %d!", __func__, _bl_debug_draw_quads_tot);
- }
- else {
- float *pt = &_bl_debug_draw_quads[_bl_debug_draw_quads_tot][0][0];
- copy_v3_v3(pt, v0); pt += 3;
- copy_v3_v3(pt, v1); pt += 3;
- copy_v3_v3(pt, v2); pt += 3;
- copy_v3_v3(pt, v3); pt += 3;
- _bl_debug_draw_quads_color[_bl_debug_draw_quads_tot] = _bl_debug_draw_color;
- _bl_debug_draw_quads_tot++;
- }
-}
-void bl_debug_draw_edge_add(const float v0[3], const float v1[3])
-{
- if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_EDGE_TOT) {
- printf("%s: max edge count hit %d!", __func__, _bl_debug_draw_edges_tot);
- }
- else {
- float *pt = &_bl_debug_draw_edges[_bl_debug_draw_edges_tot][0][0];
- copy_v3_v3(pt, v0); pt += 3;
- copy_v3_v3(pt, v1); pt += 3;
- _bl_debug_draw_edges_color[_bl_debug_draw_edges_tot] = _bl_debug_draw_color;
- _bl_debug_draw_edges_tot++;
- }
-}
-static void bl_debug_draw(void)
-{
- unsigned int color;
- if (_bl_debug_draw_quads_tot) {
- int i;
- color = _bl_debug_draw_quads_color[0];
- cpack(color);
- for (i = 0; i < _bl_debug_draw_quads_tot; i ++) {
- if (_bl_debug_draw_quads_color[i] != color) {
- color = _bl_debug_draw_quads_color[i];
- cpack(color);
- }
- glBegin(GL_LINE_LOOP);
- glVertex3fv(_bl_debug_draw_quads[i][0]);
- glVertex3fv(_bl_debug_draw_quads[i][1]);
- glVertex3fv(_bl_debug_draw_quads[i][2]);
- glVertex3fv(_bl_debug_draw_quads[i][3]);
- glEnd();
- }
- }
- if (_bl_debug_draw_edges_tot) {
- int i;
- color = _bl_debug_draw_edges_color[0];
- cpack(color);
- glBegin(GL_LINES);
- for (i = 0; i < _bl_debug_draw_edges_tot; i ++) {
- if (_bl_debug_draw_edges_color[i] != color) {
- color = _bl_debug_draw_edges_color[i];
- cpack(color);
- }
- glVertex3fv(_bl_debug_draw_edges[i][0]);
- glVertex3fv(_bl_debug_draw_edges[i][1]);
- }
- glEnd();
- color = _bl_debug_draw_edges_color[0];
- cpack(color);
- glPointSize(4.0);
- glBegin(GL_POINTS);
- for (i = 0; i < _bl_debug_draw_edges_tot; i ++) {
- if (_bl_debug_draw_edges_color[i] != color) {
- color = _bl_debug_draw_edges_color[i];
- cpack(color);
- }
- glVertex3fv(_bl_debug_draw_edges[i][0]);
- glVertex3fv(_bl_debug_draw_edges[i][1]);
- }
- glEnd();
- }
-}
-#endif
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
new file mode 100644
index 00000000000..f51a46cd95f
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -0,0 +1,1075 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_draw_legacy.c
+ * \ingroup spview3d
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
+#include "DNA_brush_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_jitter_2d.h"
+#include "BLI_utildefines.h"
+#include "BLI_endian_switch.h"
+#include "BLI_threads.h"
+
+#include "BKE_anim.h"
+#include "BKE_camera.h"
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_image.h"
+#include "BKE_key.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_global.h"
+#include "BKE_paint.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_unit.h"
+#include "BKE_movieclip.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
+
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "BLF_api.h"
+#include "BLT_translation.h"
+
+#include "ED_armature.h"
+#include "ED_keyframing.h"
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_screen_types.h"
+#include "ED_transform.h"
+
+#include "UI_interface.h"
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
+
+#include "GPU_draw.h"
+#include "GPU_framebuffer.h"
+#include "GPU_material.h"
+#include "GPU_extensions.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_select.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "RE_engine.h"
+
+#include "DRW_engine.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* ********* custom clipping *********** */
+
+void ED_view3d_clipping_set(RegionView3D *rv3d)
+{
+ double plane[4];
+ const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
+
+ for (unsigned a = 0; a < tot; a++) {
+ copy_v4db_v4fl(plane, rv3d->clip[a]);
+ glClipPlane(GL_CLIP_PLANE0 + a, plane);
+ glEnable(GL_CLIP_PLANE0 + a);
+ }
+}
+
+/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */
+void ED_view3d_clipping_disable(void)
+{
+ for (unsigned a = 0; a < 6; a++) {
+ glDisable(GL_CLIP_PLANE0 + a);
+ }
+}
+void ED_view3d_clipping_enable(void)
+{
+ for (unsigned a = 0; a < 6; a++) {
+ glEnable(GL_CLIP_PLANE0 + a);
+ }
+}
+
+static bool view3d_clipping_test(const float co[3], const float clip[6][4])
+{
+ if (plane_point_side_v3(clip[0], co) > 0.0f)
+ if (plane_point_side_v3(clip[1], co) > 0.0f)
+ if (plane_point_side_v3(clip[2], co) > 0.0f)
+ if (plane_point_side_v3(clip[3], co) > 0.0f)
+ return false;
+
+ return true;
+}
+
+/* for 'local' ED_view3d_clipping_local must run first
+ * then all comparisons can be done in localspace */
+bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
+{
+ return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
+}
+
+/* *********************** backdraw for selection *************** */
+
+static void backdrawview3d(
+ struct Depsgraph *depsgraph, Scene *scene,
+ ARegion *ar, View3D *v3d,
+ Object *obact, Object *obedit,
+ short select_mode)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
+ Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
+
+ BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
+
+ if (obact_eval && (obact_eval->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
+ BKE_paint_select_face_test(obact_eval)))
+ {
+ /* do nothing */
+ }
+ /* texture paint mode sampling */
+ else if (obact_eval && (obact_eval->mode & OB_MODE_TEXTURE_PAINT) &&
+ (v3d->shading.type > OB_WIRE))
+ {
+ /* do nothing */
+ }
+ else if ((obact_eval && (obact_eval->mode & OB_MODE_PARTICLE_EDIT)) &&
+ V3D_IS_ZBUF(v3d))
+ {
+ /* do nothing */
+ }
+ else if ((obedit && (obedit->mode & OB_MODE_EDIT)) &&
+ V3D_IS_ZBUF(v3d))
+ {
+ /* do nothing */
+ }
+ else {
+ v3d->flag &= ~V3D_INVALID_BACKBUF;
+ return;
+ }
+
+ if (!(v3d->flag & V3D_INVALID_BACKBUF))
+ return;
+
+#if 0
+ if (test) {
+ if (qtest()) {
+ addafterqueue(ar->win, BACKBUFDRAW, 1);
+ return;
+ }
+ }
+#endif
+
+#if 0 /* v3d->zbuf deprecated */
+ if (v3d->shading.type > OB_WIRE) v3d->zbuf = true;
+#endif
+
+ /* dithering and AA break color coding, so disable */
+ glDisable(GL_DITHER);
+
+ if (false) {
+ /* for multisample we use an offscreen FBO. multisample drawing can fail
+ * with color coded selection drawing, and reading back depths from such
+ * a buffer can also cause a few seconds freeze on OS X / NVidia.
+ *
+ * NOTE: code is no longer used now, but offscreen drawing is likely
+ * what we will always want to do for the new viewport. */
+ int w = BLI_rcti_size_x(&ar->winrct);
+ int h = BLI_rcti_size_y(&ar->winrct);
+ char error[256];
+
+ if (rv3d->gpuoffscreen) {
+ if (GPU_offscreen_width(rv3d->gpuoffscreen) != w ||
+ GPU_offscreen_height(rv3d->gpuoffscreen) != h)
+ {
+ GPU_offscreen_free(rv3d->gpuoffscreen);
+ rv3d->gpuoffscreen = NULL;
+ }
+ }
+
+ if (!rv3d->gpuoffscreen) {
+ rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, true, false, error);
+
+ if (!rv3d->gpuoffscreen)
+ fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
+ }
+ }
+
+ if (rv3d->gpuoffscreen)
+ GPU_offscreen_bind(rv3d->gpuoffscreen, true);
+ else
+ GPU_scissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
+
+ GPU_clear_color(0.0, 0.0, 0.0, 0.0);
+ GPU_depth_test(true);
+ GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT);
+
+ if (rv3d->rflag & RV3D_CLIPPING)
+ ED_view3d_clipping_set(rv3d);
+
+ G.f |= G_BACKBUFSEL;
+
+ if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
+ draw_object_backbufsel(depsgraph, scene_eval, v3d, rv3d, obact_eval, select_mode);
+ }
+
+ if (rv3d->gpuoffscreen)
+ GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
+
+ v3d->flag &= ~V3D_INVALID_BACKBUF;
+
+ G.f &= ~G_BACKBUFSEL;
+ GPU_depth_test(false);
+ glEnable(GL_DITHER);
+
+ if (rv3d->rflag & RV3D_CLIPPING)
+ ED_view3d_clipping_disable();
+}
+
+void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (rv3d->gpuoffscreen) {
+ GPU_offscreen_bind(rv3d->gpuoffscreen, true);
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glReadPixels(x, y, w, h, format, type, data);
+ GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
+ }
+ else {
+ glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
+ }
+}
+
+/* XXX depth reading exception, for code not using gpu offscreen */
+static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
+{
+ glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
+}
+
+void ED_view3d_backbuf_validate_with_select_mode(ViewContext *vc, short select_mode)
+{
+ if (vc->v3d->flag & V3D_INVALID_BACKBUF) {
+ backdrawview3d(vc->depsgraph, vc->scene, vc->ar, vc->v3d, vc->obact, vc->obedit, select_mode);
+ }
+}
+
+void ED_view3d_backbuf_validate(ViewContext *vc)
+{
+ ED_view3d_backbuf_validate_with_select_mode(vc, -1);
+}
+
+/**
+ * allow for small values [0.5 - 2.5],
+ * and large values, FLT_MAX by clamping by the area size
+ */
+int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
+{
+ return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
+}
+
+/* samples a single pixel (copied from vpaint) */
+unsigned int ED_view3d_backbuf_sample(
+ ViewContext *vc, int x, int y)
+{
+ if (x >= vc->ar->winx || y >= vc->ar->winy) {
+ return 0;
+ }
+
+ ED_view3d_backbuf_validate(vc);
+
+ unsigned int col;
+ view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+
+ if (ENDIAN_ORDER == B_ENDIAN) {
+ BLI_endian_switch_uint32(&col);
+ }
+
+ return GPU_select_to_index(col);
+}
+
+/* reads full rect, converts indices */
+ImBuf *ED_view3d_backbuf_read(
+ ViewContext *vc, int xmin, int ymin, int xmax, int ymax)
+{
+ /* clip */
+ const rcti clip = {
+ max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1),
+ max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)};
+ const int size_clip[2] = {
+ BLI_rcti_size_x(&clip) + 1,
+ BLI_rcti_size_y(&clip) + 1};
+
+ if (UNLIKELY((clip.xmin > clip.xmax) ||
+ (clip.ymin > clip.ymax)))
+ {
+ return NULL;
+ }
+
+ ImBuf *ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect);
+
+ ED_view3d_backbuf_validate(vc);
+
+ view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect);
+
+ glReadBuffer(GL_BACK);
+
+ if (ENDIAN_ORDER == B_ENDIAN) {
+ IMB_convert_rgba_to_abgr(ibuf_clip);
+ }
+
+ GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
+
+ if ((clip.xmin == xmin) &&
+ (clip.xmax == xmax) &&
+ (clip.ymin == ymin) &&
+ (clip.ymax == ymax))
+ {
+ return ibuf_clip;
+ }
+ else {
+ /* put clipped result into a non-clipped buffer */
+ const int size[2] = {
+ (xmax - xmin + 1),
+ (ymax - ymin + 1)};
+
+ ImBuf *ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect);
+
+ IMB_rectcpy(
+ ibuf_full, ibuf_clip,
+ clip.xmin - xmin, clip.ymin - ymin,
+ 0, 0,
+ size_clip[0], size_clip[1]);
+ IMB_freeImBuf(ibuf_clip);
+ return ibuf_full;
+ }
+}
+
+/* smart function to sample a rect spiralling outside, nice for backbuf selection */
+unsigned int ED_view3d_backbuf_sample_rect(
+ ViewContext *vc, const int mval[2], int size,
+ unsigned int min, unsigned int max, float *r_dist)
+{
+ int dirvec[4][2];
+
+ const int amount = (size - 1) / 2;
+
+ const int minx = mval[0] - (amount + 1);
+ const int miny = mval[1] - (amount + 1);
+ ImBuf *buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1);
+ if (!buf) return 0;
+
+ unsigned index = 0;
+ int rc = 0;
+
+ dirvec[0][0] = 1; dirvec[0][1] = 0;
+ dirvec[1][0] = 0; dirvec[1][1] = -size;
+ dirvec[2][0] = -1; dirvec[2][1] = 0;
+ dirvec[3][0] = 0; dirvec[3][1] = size;
+
+ const unsigned *bufmin = buf->rect;
+ const unsigned *tbuf = buf->rect;
+ const unsigned *bufmax = buf->rect + size * size;
+ tbuf += amount * size + amount;
+
+ for (int nr = 1; nr <= size; nr++) {
+ for (int a = 0; a < 2; a++) {
+ for (int b = 0; b < nr; b++) {
+ if (*tbuf && *tbuf >= min && *tbuf < max) {
+ /* we got a hit */
+
+ /* get x,y pixel coords from the offset
+ * (manhatten distance in keeping with other screen-based selection) */
+ *r_dist = (float)(
+ abs(((int)(tbuf - buf->rect) % size) - (size / 2)) +
+ abs(((int)(tbuf - buf->rect) / size) - (size / 2)));
+
+ /* indices start at 1 here */
+ index = (*tbuf - min) + 1;
+ goto exit;
+ }
+
+ tbuf += (dirvec[rc][0] + dirvec[rc][1]);
+
+ if (tbuf < bufmin || tbuf >= bufmax) {
+ goto exit;
+ }
+ }
+ rc++;
+ rc &= 3;
+ }
+ }
+
+exit:
+ IMB_freeImBuf(buf);
+ return index;
+}
+
+
+/* ************************************************************* */
+
+static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
+{
+ if (BKE_image_is_stereo(ima)) {
+ iuser->flag |= IMA_SHOW_STEREO;
+
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ iuser->multiview_eye = STEREO_LEFT_ID;
+ }
+ else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+ /* show only left or right camera */
+ iuser->multiview_eye = v3d->stereo3d_camera;
+ }
+
+ BKE_image_multiview_index(ima, iuser);
+ }
+ else {
+ iuser->flag &= ~IMA_SHOW_STEREO;
+ }
+}
+
+static void view3d_draw_bgpic(Scene *scene, Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d,
+ const bool do_foreground, const bool do_camera_frame)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ int fg_flag = do_foreground ? CAM_BGIMG_FLAG_FOREGROUND : 0;
+ if (v3d->camera == NULL || v3d->camera->type != OB_CAMERA) {
+ return;
+ }
+ Camera *cam = v3d->camera->data;
+
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ bgpic->iuser.scene = scene; /* Needed for render results. */
+
+ if ((bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != fg_flag)
+ continue;
+
+ {
+ float image_aspect[2];
+ float x1, y1, x2, y2, centx, centy;
+
+ void *lock;
+
+ Image *ima = NULL;
+
+ /* disable individual images */
+ if ((bgpic->flag & CAM_BGIMG_FLAG_DISABLED))
+ continue;
+
+ ImBuf *ibuf = NULL;
+ ImBuf *freeibuf = NULL;
+ ImBuf *releaseibuf = NULL;
+ if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+ ima = bgpic->ima;
+ if (ima == NULL)
+ continue;
+ BKE_image_user_frame_calc(&bgpic->iuser, (int)DEG_get_ctime(depsgraph));
+ if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) {
+ ibuf = NULL; /* frame is out of range, dont show */
+ }
+ else {
+ view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser);
+ ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock);
+ releaseibuf = ibuf;
+ }
+
+ image_aspect[0] = ima->aspx;
+ image_aspect[1] = ima->aspy;
+ }
+ else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+ /* TODO: skip drawing when out of frame range (as image sequences do above) */
+ MovieClip *clip = NULL;
+
+ if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
+ if (scene->camera)
+ clip = BKE_object_movieclip_get(scene, scene->camera, true);
+ }
+ else {
+ clip = bgpic->clip;
+ }
+
+ if (clip == NULL)
+ continue;
+
+ BKE_movieclip_user_set_frame(&bgpic->cuser, (int)DEG_get_ctime(depsgraph));
+ ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);
+
+ image_aspect[0] = clip->aspx;
+ image_aspect[1] = clip->aspy;
+
+ /* working with ibuf from image and clip has got different workflow now.
+ * ibuf acquired from clip is referenced by cache system and should
+ * be dereferenced after usage. */
+ freeibuf = ibuf;
+ }
+ else {
+ /* perhaps when loading future files... */
+ BLI_assert(0);
+ copy_v2_fl(image_aspect, 1.0f);
+ }
+
+ if (ibuf == NULL)
+ continue;
+
+ if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */
+ if (freeibuf)
+ IMB_freeImBuf(freeibuf);
+ if (releaseibuf)
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
+
+ continue;
+ }
+
+ if (ibuf->rect == NULL)
+ IMB_rect_from_float(ibuf);
+
+ BLI_assert(rv3d->persp == RV3D_CAMOB);
+ {
+ if (do_camera_frame) {
+ rctf vb;
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false);
+ x1 = vb.xmin;
+ y1 = vb.ymin;
+ x2 = vb.xmax;
+ y2 = vb.ymax;
+ }
+ else {
+ x1 = ar->winrct.xmin;
+ y1 = ar->winrct.ymin;
+ x2 = ar->winrct.xmax;
+ y2 = ar->winrct.ymax;
+ }
+
+ /* apply offset last - camera offset is different to offset in blender units */
+ /* so this has some sane way of working - this matches camera's shift _exactly_ */
+ {
+ const float max_dim = max_ff(x2 - x1, y2 - y1);
+ const float xof_scale = bgpic->offset[0] * max_dim;
+ const float yof_scale = bgpic->offset[1] * max_dim;
+
+ x1 += xof_scale;
+ y1 += yof_scale;
+ x2 += xof_scale;
+ y2 += yof_scale;
+ }
+
+ centx = (x1 + x2) * 0.5f;
+ centy = (y1 + y2) * 0.5f;
+
+ /* aspect correction */
+ if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
+ /* apply aspect from clip */
+ const float w_src = ibuf->x * image_aspect[0];
+ const float h_src = ibuf->y * image_aspect[1];
+
+ /* destination aspect is already applied from the camera frame */
+ const float w_dst = x1 - x2;
+ const float h_dst = y1 - y2;
+
+ const float asp_src = w_src / h_src;
+ const float asp_dst = w_dst / h_dst;
+
+ if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
+ if ((asp_src > asp_dst) == ((bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) != 0)) {
+ /* fit X */
+ const float div = asp_src / asp_dst;
+ x1 = ((x1 - centx) * div) + centx;
+ x2 = ((x2 - centx) * div) + centx;
+ }
+ else {
+ /* fit Y */
+ const float div = asp_dst / asp_src;
+ y1 = ((y1 - centy) * div) + centy;
+ y2 = ((y2 - centy) * div) + centy;
+ }
+ }
+ }
+ }
+
+ /* complete clip? */
+ rctf clip_rect;
+ BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
+ if (bgpic->rotation) {
+ BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
+ }
+
+ if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) {
+ if (freeibuf)
+ IMB_freeImBuf(freeibuf);
+ if (releaseibuf)
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
+
+ continue;
+ }
+
+ float zoomx = (x2 - x1) / ibuf->x;
+ float zoomy = (y2 - y1) / ibuf->y;
+
+ /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */
+ if (zoomx < 1.0f || zoomy < 1.0f) {
+ float tzoom = min_ff(zoomx, zoomy);
+ int mip = 0;
+
+ if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) {
+ IMB_remakemipmap(ibuf, 0);
+ ibuf->userflags &= ~IB_MIPMAP_INVALID;
+ }
+ else if (ibuf->mipmap[0] == NULL)
+ IMB_makemipmap(ibuf, 0);
+
+ while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) {
+ tzoom *= 2.0f;
+ zoomx *= 2.0f;
+ zoomy *= 2.0f;
+ mip++;
+ }
+ if (mip > 0)
+ ibuf = ibuf->mipmap[mip - 1];
+ }
+
+ GPU_depth_test(!do_foreground);
+ glDepthMask(GL_FALSE);
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
+ ED_region_pixelspace(ar);
+
+ GPU_matrix_translate_2f(centx, centy);
+ GPU_matrix_scale_1f(bgpic->scale);
+ GPU_matrix_rotate_2d(RAD2DEGF(-bgpic->rotation));
+
+ if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) {
+ zoomx *= -1.0f;
+ x1 = x2;
+ }
+ if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) {
+ zoomy *= -1.0f;
+ y1 = y2;
+ }
+
+ float col[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTex(&state, x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect,
+ zoomx, zoomy, col);
+
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
+
+ GPU_blend(false);
+
+ glDepthMask(GL_TRUE);
+ GPU_depth_test(true);
+
+ if (freeibuf)
+ IMB_freeImBuf(freeibuf);
+ if (releaseibuf)
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
+ }
+ }
+}
+
+void ED_view3d_draw_bgpic_test(
+ Scene *scene, Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d,
+ const bool do_foreground, const bool do_camera_frame)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
+ Camera *cam = v3d->camera->data;
+ if ((cam->flag & CAM_SHOW_BG_IMAGE) == 0) {
+ return;
+ }
+ }
+ else {
+ return;
+ }
+
+ /* disabled - mango request, since footage /w only render is quite useful
+ * and this option is easy to disable all background images at once */
+#if 0
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE)
+ return;
+#endif
+
+ if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
+ if (rv3d->persp == RV3D_CAMOB) {
+ view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
+ }
+ }
+ else {
+ view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
+ }
+}
+
+/* *********************** */
+
+/* XXX warning, not using gpu offscreen here */
+void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
+{
+ /* clamp rect by region */
+ rcti r = {
+ .xmin = 0,
+ .xmax = ar->winx - 1,
+ .ymin = 0,
+ .ymax = ar->winy - 1
+ };
+
+ /* Constrain rect to depth bounds */
+ BLI_rcti_isect(&r, rect, rect);
+
+ /* assign values to compare with the ViewDepths */
+ int x = rect->xmin;
+ int y = rect->ymin;
+
+ int w = BLI_rcti_size_x(rect);
+ int h = BLI_rcti_size_y(rect);
+
+ if (w <= 0 || h <= 0) {
+ if (d->depths)
+ MEM_freeN(d->depths);
+ d->depths = NULL;
+
+ d->damaged = false;
+ }
+ else if (d->w != w ||
+ d->h != h ||
+ d->x != x ||
+ d->y != y ||
+ d->depths == NULL
+ )
+ {
+ d->x = x;
+ d->y = y;
+ d->w = w;
+ d->h = h;
+
+ if (d->depths)
+ MEM_freeN(d->depths);
+
+ d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
+
+ d->damaged = true;
+ }
+
+ if (d->damaged) {
+ /* XXX using special function here, it doesn't use the gpu offscreen system */
+ view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
+ glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
+ d->damaged = false;
+ }
+}
+
+/* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */
+void ED_view3d_depth_update(ARegion *ar)
+{
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* Create storage for, and, if necessary, copy depth buffer */
+ if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
+ if (rv3d->depths) {
+ ViewDepths *d = rv3d->depths;
+ if (d->w != ar->winx ||
+ d->h != ar->winy ||
+ !d->depths)
+ {
+ d->w = ar->winx;
+ d->h = ar->winy;
+ if (d->depths)
+ MEM_freeN(d->depths);
+ d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
+ d->damaged = true;
+ }
+
+ if (d->damaged) {
+ view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
+ glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
+
+ d->damaged = false;
+ }
+ }
+}
+
+/* utility function to find the closest Z value, use for autodepth */
+float view3d_depth_near(ViewDepths *d)
+{
+ /* convert to float for comparisons */
+ const float near = (float)d->depth_range[0];
+ const float far_real = (float)d->depth_range[1];
+ float far = far_real;
+
+ const float *depths = d->depths;
+ float depth = FLT_MAX;
+ int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */
+
+ /* far is both the starting 'far' value
+ * and the closest value found. */
+ while (i--) {
+ depth = *depths++;
+ if ((depth < far) && (depth > near)) {
+ far = depth;
+ }
+ }
+
+ return far == far_real ? FLT_MAX : far;
+}
+
+void ED_view3d_draw_depth_gpencil(
+ Depsgraph *depsgraph, Scene *scene, ARegion *ar, View3D *v3d)
+{
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+
+ /* Setup view matrix. */
+ ED_view3d_draw_setup_view(NULL, depsgraph, scene, ar, v3d, NULL, NULL, NULL);
+
+ GPU_clear(GPU_DEPTH_BIT);
+
+ GPU_depth_test(true);
+
+ ED_gpencil_draw_view3d(NULL, scene, view_layer, depsgraph, v3d, ar, true);
+
+ GPU_depth_test(false);
+}
+
+/* *********************** customdata **************** */
+
+CustomDataMask ED_view3d_datamask(const Scene *UNUSED(scene), const View3D *v3d)
+{
+ CustomDataMask mask = 0;
+ const int drawtype = view3d_effective_drawtype(v3d);
+
+ if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) ||
+ ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
+ {
+ mask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
+
+ if (drawtype == OB_MATERIAL)
+ mask |= CD_MASK_ORCO;
+ }
+
+ return mask;
+}
+
+/* goes over all modes and view3d settings */
+CustomDataMask ED_view3d_screen_datamask(const Scene *scene, const bScreen *screen)
+{
+ CustomDataMask mask = CD_MASK_BAREMESH;
+
+ /* check if we need tfaces & mcols due to view mode */
+ for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ mask |= ED_view3d_datamask(scene, sa->spacedata.first);
+ }
+ }
+
+ return mask;
+}
+
+/**
+ * Store values from #RegionView3D, set when drawing.
+ * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example).
+ *
+ * Values set by #ED_view3d_update_viewmat should be handled here.
+ */
+struct RV3DMatrixStore {
+ float winmat[4][4];
+ float viewmat[4][4];
+ float viewinv[4][4];
+ float persmat[4][4];
+ float persinv[4][4];
+ float viewcamtexcofac[4];
+ float pixsize;
+};
+
+struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
+{
+ struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__);
+ copy_m4_m4(rv3dmat->winmat, rv3d->winmat);
+ copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat);
+ copy_m4_m4(rv3dmat->persmat, rv3d->persmat);
+ copy_m4_m4(rv3dmat->persinv, rv3d->persinv);
+ copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv);
+ copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac);
+ rv3dmat->pixsize = rv3d->pixsize;
+ return (void *)rv3dmat;
+}
+
+void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat_pt)
+{
+ struct RV3DMatrixStore *rv3dmat = rv3dmat_pt;
+ copy_m4_m4(rv3d->winmat, rv3dmat->winmat);
+ copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat);
+ copy_m4_m4(rv3d->persmat, rv3dmat->persmat);
+ copy_m4_m4(rv3d->persinv, rv3dmat->persinv);
+ copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv);
+ copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac);
+ rv3d->pixsize = rv3dmat->pixsize;
+}
+
+/**
+ * \note The info that this uses is updated in #ED_refresh_viewport_fps,
+ * which currently gets called during #SCREEN_OT_animation_step.
+ */
+void ED_scene_draw_fps(Scene *scene, int xoffset, int *yoffset)
+{
+ ScreenFrameRateInfo *fpsi = scene->fps_info;
+ char printable[16];
+
+ if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime)
+ return;
+
+ printable[0] = '\0';
+
+#if 0
+ /* this is too simple, better do an average */
+ fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime))
+#else
+ fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime));
+
+ float fps = 0.0f;
+ int tot = 0;
+ for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) {
+ if (fpsi->redrawtimes_fps[i]) {
+ fps += fpsi->redrawtimes_fps[i];
+ tot++;
+ }
+ }
+ if (tot) {
+ fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
+
+ //fpsi->redrawtime_index++;
+ //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE)
+ // fpsi->redrawtime = 0;
+
+ fps = fps / tot;
+ }
+#endif
+
+ const int font_id = BLF_default();
+
+ /* is this more than half a frame behind? */
+ if (fps + 0.5f < (float)(FPS)) {
+ UI_FontThemeColor(font_id, TH_REDALERT);
+ BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps);
+ }
+ else {
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
+ BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f));
+ }
+
+ BLF_enable(font_id, BLF_SHADOW);
+ BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ BLF_shadow_offset(font_id, 1, -1);
+
+ *yoffset -= U.widget_unit;
+
+#ifdef WITH_INTERNATIONAL
+ BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
+#else
+ BLF_draw_default_ascii(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
+#endif
+
+ BLF_disable(font_id, BLF_SHADOW);
+}
+
+static bool view3d_main_region_do_render_draw(const Scene *scene)
+{
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type && type->view_update && type->view_draw);
+}
+
+bool ED_view3d_calc_render_border(const Scene *scene, Depsgraph *depsgraph, View3D *v3d, ARegion *ar, rcti *rect)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ bool use_border;
+
+ /* test if there is a 3d view rendering */
+ if (v3d->shading.type != OB_RENDER || !view3d_main_region_do_render_draw(scene))
+ return false;
+
+ /* test if there is a border render */
+ if (rv3d->persp == RV3D_CAMOB)
+ use_border = (scene->r.mode & R_BORDER) != 0;
+ else
+ use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0;
+
+ if (!use_border)
+ return false;
+
+ /* compute border */
+ if (rv3d->persp == RV3D_CAMOB) {
+ rctf viewborder;
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false);
+
+ rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
+ rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
+ rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder);
+ rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder);
+ }
+ else {
+ rect->xmin = v3d->render_border.xmin * ar->winx;
+ rect->xmax = v3d->render_border.xmax * ar->winx;
+ rect->ymin = v3d->render_border.ymin * ar->winy;
+ rect->ymax = v3d->render_border.ymax * ar->winy;
+ }
+
+ BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin);
+ BLI_rcti_isect(&ar->winrct, rect, rect);
+
+ return true;
+}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 679498ab16d..ae093b2f9e2 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -36,6 +36,7 @@
#include <float.h>
#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -47,9 +48,13 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
+#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_font.h"
+#include "BKE_gpencil.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -57,14 +62,13 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_action.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -74,8 +78,8 @@
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_mesh.h"
-#include "ED_gpencil.h"
#include "ED_view3d.h"
+#include "ED_transform_snap_object_context.h"
#include "UI_resources.h"
@@ -133,6 +137,7 @@ typedef struct ViewOpsData {
ARegion *ar;
View3D *v3d;
RegionView3D *rv3d;
+ Depsgraph *depsgraph;
/** Needed for continuous zoom. */
wmTimer *timer;
@@ -218,6 +223,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
/* store data */
op->customdata = vod;
vod->bmain = CTX_data_main(C);
+ vod->depsgraph = CTX_data_depsgraph(C);
vod->scene = CTX_data_scene(C);
vod->sa = CTX_wm_area(C);
vod->ar = CTX_wm_region(C);
@@ -245,8 +251,12 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
static float lastofs[3] = {0, 0, 0};
bool is_set = false;
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- Object *ob_act = OBACT;
+ ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
+ View3D *v3d = CTX_wm_view3d(C);
+ Object *ob_act_eval = OBACT(view_layer_eval);
+ Object *ob_act = DEG_get_original_object(ob_act_eval);
if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) &&
/* with weight-paint + pose-mode, fall through to using calculateTransformCenter */
@@ -258,16 +268,16 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
*/
if (ob_act->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
float stroke[3];
- BKE_paint_stroke_get_average(scene, ob_act, stroke);
+ BKE_paint_stroke_get_average(scene, ob_act_eval, stroke);
copy_v3_v3(lastofs, stroke);
}
else {
- copy_v3_v3(lastofs, ob_act->obmat[3]);
+ copy_v3_v3(lastofs, ob_act_eval->obmat[3]);
}
is_set = true;
}
else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) {
- Curve *cu = ob_act->data;
+ Curve *cu = ob_act_eval->data;
EditFont *ef = cu->editfont;
int i;
@@ -277,33 +287,32 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
}
mul_v2_fl(lastofs, 1.0f / 4.0f);
- mul_m4_v3(ob_act->obmat, lastofs);
+ mul_m4_v3(ob_act_eval->obmat, lastofs);
is_set = true;
}
else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) {
/* object mode use boundbox centers */
- View3D *v3d = CTX_wm_view3d(C);
- Base *base;
+ Base *base_eval;
unsigned int tot = 0;
float select_center[3];
zero_v3(select_center);
- for (base = FIRSTBASE; base; base = base->next) {
- if (TESTBASE(v3d, base)) {
+ for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) {
+ if (TESTBASE(v3d, base_eval)) {
/* use the boundbox if we can */
- Object *ob = base->object;
+ Object *ob_eval = base_eval->object;
- if (ob->bb && !(ob->bb->flag & BOUNDBOX_DIRTY)) {
+ if (ob_eval->bb && !(ob_eval->bb->flag & BOUNDBOX_DIRTY)) {
float cent[3];
- BKE_boundbox_calc_center_aabb(ob->bb, cent);
+ BKE_boundbox_calc_center_aabb(ob_eval->bb, cent);
- mul_m4_v3(ob->obmat, cent);
+ mul_m4_v3(ob_eval->obmat, cent);
add_v3_v3(select_center, cent);
}
else {
- add_v3_v3(select_center, ob->obmat[3]);
+ add_v3_v3(select_center, ob_eval->obmat[3]);
}
tot++;
}
@@ -366,6 +375,7 @@ static void viewops_data_create(
bContext *C, wmOperator *op, const wmEvent *event,
enum eViewOpsFlag viewops_flag)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ViewOpsData *vod = op->customdata;
RegionView3D *rv3d = vod->rv3d;
@@ -383,7 +393,7 @@ static void viewops_data_create(
negate_v3_v3(fallback_depth_pt, rv3d->ofs);
vod->use_dyn_ofs = ED_view3d_autodist(
- vod->bmain, vod->scene, vod->ar, vod->v3d,
+ depsgraph, vod->ar, vod->v3d,
event->mval, vod->dyn_ofs, true, fallback_depth_pt);
}
else {
@@ -391,7 +401,7 @@ static void viewops_data_create(
}
if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) {
- if (ED_view3d_persp_ensure(vod->v3d, vod->ar)) {
+ if (ED_view3d_persp_ensure(depsgraph, vod->v3d, vod->ar)) {
/* If we're switching from camera view to the perspective one,
* need to tag viewport update, so camera vuew and borders
* are properly updated.
@@ -402,7 +412,7 @@ static void viewops_data_create(
/* set the view from the camera, if view locking is enabled.
* we may want to make this optional but for now its needed always */
- ED_view3d_camera_lock_init(vod->v3d, vod->rv3d);
+ ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d);
vod->init.dist = rv3d->dist;
vod->init.camzoom = rv3d->camzoom;
@@ -506,8 +516,9 @@ static void viewops_data_create(
static void viewops_data_free(bContext *C, wmOperator *op)
{
ARegion *ar;
+#if 0
Paint *p = BKE_paint_get_active_from_context(C);
-
+#endif
if (op->customdata) {
ViewOpsData *vod = op->customdata;
ar = vod->ar;
@@ -523,7 +534,9 @@ static void viewops_data_free(bContext *C, wmOperator *op)
ar = CTX_wm_region(C);
}
+#if 0
if (p && (p->flags & PAINT_FAST_NAVIGATE))
+#endif
ED_region_tag_redraw(ar);
}
@@ -571,13 +584,6 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
-
- WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE);
- WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE);
-
/* disabled mode switching for now, can re-implement better, later on */
#if 0
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
@@ -802,7 +808,7 @@ static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2])
vod->prev.event_xy[0] = event_xy[0];
vod->prev.event_xy[1] = event_xy[1];
- ED_view3d_camera_lock_sync(vod->v3d, rv3d);
+ ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, rv3d);
ED_region_tag_redraw(vod->ar);
}
@@ -1100,7 +1106,6 @@ static void view3d_ndof_pan_zoom(
static void view3d_ndof_orbit(
const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar,
- /* optional, can be NULL*/
ViewOpsData *vod, const bool apply_dyn_ofs)
{
View3D *v3d = sa->spacedata.first;
@@ -1110,7 +1115,7 @@ static void view3d_ndof_orbit(
BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
- ED_view3d_persp_ensure(v3d, ar);
+ ED_view3d_persp_ensure(vod->depsgraph, v3d, ar);
rv3d->view = RV3D_VIEW_USER;
@@ -1299,6 +1304,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
else {
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
ViewOpsData *vod;
View3D *v3d;
RegionView3D *rv3d;
@@ -1319,7 +1325,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* off by default, until changed later this function */
rv3d->rot_angle = 0.0f;
- ED_view3d_camera_lock_init_ex(v3d, rv3d, false);
+ ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
if (ndof->progress != P_FINISHING) {
const bool has_rotation = NDOF_HAS_ROTATE;
@@ -1336,7 +1342,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
ED_region_tag_redraw(vod->ar);
@@ -1367,6 +1373,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_CANCELLED;
}
else {
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
ViewOpsData *vod;
View3D *v3d;
RegionView3D *rv3d;
@@ -1388,7 +1395,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
/* off by default, until changed later this function */
rv3d->rot_angle = 0.0f;
- ED_view3d_camera_lock_init_ex(v3d, rv3d, false);
+ ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
if (ndof->progress == P_FINISHING) {
/* pass */
@@ -1431,13 +1438,13 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
ED_view3d_distance_set(rv3d, 0.0f);
if (has_rotation) {
- view3d_ndof_orbit(ndof, vod->sa, vod->ar, NULL, false);
+ view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod, false);
}
ED_view3d_distance_set(rv3d, dist_backup);
}
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
ED_region_tag_redraw(vod->ar);
@@ -1471,6 +1478,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e
return OPERATOR_CANCELLED;
}
else {
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
const wmNDOFMotionData *ndof = event->customdata;
@@ -1484,7 +1492,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e
if (!(has_translate || has_zoom))
return OPERATOR_CANCELLED;
- ED_view3d_camera_lock_init_ex(v3d, rv3d, false);
+ ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
if (ndof->progress != P_FINISHING) {
ScrArea *sa = CTX_wm_area(C);
@@ -1495,7 +1503,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e
}
}
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
ED_region_tag_redraw(CTX_wm_region(C));
@@ -1540,7 +1548,7 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void VIEW3D_OT_ndof_all(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "NDOF Move View";
+ ot->name = "NDOF Pan View";
ot->description = "Pan and rotate the view with the 3D mouse";
ot->idname = "VIEW3D_OT_ndof_all";
@@ -1628,7 +1636,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
vod->prev.event_xy[0] = x;
vod->prev.event_xy[1] = y;
- ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
+ ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
ED_region_tag_redraw(vod->ar);
}
@@ -1730,7 +1738,7 @@ void VIEW3D_OT_move(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Move View";
+ ot->name = "Pan View";
ot->description = "Move the view";
ot->idname = "VIEW3D_OT_move";
@@ -1773,10 +1781,6 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
-
/* disabled mode switching for now, can re-implement better, later on */
#if 0
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
@@ -1792,7 +1796,7 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
* \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL.
*/
static void view_zoom_to_window_xy_camera(
- Scene *scene, View3D *v3d,
+ Scene *scene, Depsgraph *depsgraph, View3D *v3d,
ARegion *ar, float dfac, const int zoom_xy[2])
{
RegionView3D *rv3d = ar->regiondata;
@@ -1810,13 +1814,13 @@ static void view_zoom_to_window_xy_camera(
float pt_dst[2];
float delta_px[2];
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_old, false);
BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin);
rv3d->camzoom = camzoom_new;
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_new, false);
BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin);
BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src);
@@ -1989,7 +1993,7 @@ static void viewzoom_apply_camera(
/* calculate inverted, then invert again (needed because of camera zoom scaling) */
zfac = 1.0f / zfac;
view_zoom_to_window_xy_camera(
- vod->scene, vod->v3d,
+ vod->scene, vod->depsgraph, vod->v3d,
vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL);
}
@@ -2027,7 +2031,7 @@ static void viewzoom_apply_3d(
view3d_boxview_sync(vod->sa, vod->ar);
}
- ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
+ ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
ED_region_tag_redraw(vod->ar);
}
@@ -2109,6 +2113,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int viewzoom_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d;
RegionView3D *rv3d;
@@ -2151,7 +2156,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
const float step = 1.2f;
/* this min and max is also in viewmove() */
if (use_cam_zoom) {
- view_zoom_to_window_xy_camera(scene, v3d, ar, step, zoom_xy);
+ view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy);
}
else {
if (rv3d->dist < dist_range[1]) {
@@ -2162,7 +2167,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
else {
const float step = 1.0f / 1.2f;
if (use_cam_zoom) {
- view_zoom_to_window_xy_camera(scene, v3d, ar, step, zoom_xy);
+ view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy);
}
else {
if (rv3d->dist > dist_range[0]) {
@@ -2177,7 +2182,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
ED_view3d_depth_tag_update(rv3d);
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
ED_region_tag_redraw(ar);
@@ -2307,10 +2312,6 @@ void viewdolly_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
-
/* disabled mode switching for now, can re-implement better, later on */
#if 0
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
@@ -2371,7 +2372,7 @@ static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_
view3d_boxview_sync(vod->sa, vod->ar);
}
- ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
+ ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
ED_region_tag_redraw(vod->ar);
}
@@ -2472,7 +2473,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
ED_view3d_depth_tag_update(rv3d);
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_sync(CTX_data_depsgraph(C), v3d, rv3d);
ED_region_tag_redraw(ar);
@@ -2506,7 +2507,8 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (vod->rv3d->persp != RV3D_PERSP) {
if (vod->rv3d->persp == RV3D_CAMOB) {
/* ignore rv3d->lpersp because dolly only makes sense in perspective mode */
- ED_view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP);
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_view3d_persp_switch_from_camera(depsgraph, vod->v3d, vod->rv3d, RV3D_PERSP);
}
else {
vod->rv3d->persp = RV3D_PERSP;
@@ -2640,7 +2642,7 @@ static void view3d_from_minmax(
}
if (ok_dist) {
- new_dist = ED_view3d_radius_to_dist(v3d, ar, persp, true, (size / 2) * VIEW3D_MARGIN);
+ new_dist = ED_view3d_radius_to_dist(v3d, ar, CTX_data_depsgraph(C), persp, true, (size / 2) * VIEW3D_MARGIN);
if (rv3d->is_persp) {
/* don't zoom closer than the near clipping plane */
new_dist = max_ff(new_dist, v3d->near * 1.5f);
@@ -2695,8 +2697,9 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
- Base *base;
- float *curs;
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
+ Base *base_eval;
const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
const bool skip_camera = (ED_view3d_camera_lock_check(v3d, ar->regiondata) ||
/* any one of the regions may be locked */
@@ -2709,24 +2712,26 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
if (center) {
/* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
- curs = ED_view3d_cursor3d_get(scene, v3d);
+ View3DCursor *cursor = &scene->cursor;
zero_v3(min);
zero_v3(max);
- zero_v3(curs);
+ zero_v3(cursor->location);
+ unit_qt(cursor->rotation);
}
else {
INIT_MINMAX(min, max);
}
- for (base = scene->base.first; base; base = base->next) {
- if (BASE_VISIBLE(v3d, base)) {
+ for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) {
+ if (BASE_VISIBLE(v3d, base_eval)) {
changed = true;
- if (skip_camera && base->object == v3d->camera) {
+ Object *ob = DEG_get_original_object(base_eval->object);
+ if (skip_camera && ob == v3d->camera) {
continue;
}
- BKE_object_minmax(base->object, min, max, false);
+ BKE_object_minmax(base_eval->object, min, max, false);
}
}
if (!changed) {
@@ -2748,6 +2753,10 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
view3d_from_minmax(C, v3d, ar, min, max, true, smooth_viewtx);
}
+ if (center) {
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
return OPERATOR_FINISHED;
}
@@ -2782,13 +2791,16 @@ void VIEW3D_OT_view_all(wmOperatorType *ot)
/* like a localview without local!, was centerview() in 2.4x */
static int viewselected_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
bGPdata *gpd = CTX_data_gpencil_data(C);
- const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
- Object *ob = OBACT;
+ const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
+ const bool is_face_map = ((is_gp_edit == false) && ar->gizmo_map &&
+ WM_gizmomap_is_any_selected(ar->gizmo_map));
+ Object *ob_eval = OBACT(view_layer_eval);
Object *obedit = CTX_data_edit_object(C);
float min[3], max[3];
bool ok = false, ok_dist = true;
@@ -2799,71 +2811,85 @@ static int viewselected_exec(bContext *C, wmOperator *op)
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
INIT_MINMAX(min, max);
-
- if (is_gp_edit) {
- ob = NULL;
+ if (is_face_map) {
+ ob_eval = NULL;
}
- if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) {
+ if (ob_eval && (ob_eval->mode & OB_MODE_WEIGHT_PAINT)) {
/* hard-coded exception, we look for the one selected armature */
/* this is weak code this way, we should make a generic active/selection callback interface once... */
- Base *base;
- for (base = scene->base.first; base; base = base->next) {
- if (TESTBASELIB(v3d, base)) {
- if (base->object->type == OB_ARMATURE)
- if (base->object->mode & OB_MODE_POSE)
+ Base *base_eval;
+ for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) {
+ if (TESTBASELIB(v3d, base_eval)) {
+ if (base_eval->object->type == OB_ARMATURE)
+ if (base_eval->object->mode & OB_MODE_POSE)
break;
}
}
- if (base)
- ob = base->object;
+ if (base_eval)
+ ob_eval = base_eval->object;
}
-
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) && (gps->flag & GP_STROKE_3DSPACE)) {
- if (ED_gpencil_stroke_minmax(gps, true, min, max)) {
- ok = true;
- }
+ ok |= BKE_gpencil_stroke_minmax(gps, true, min, max);
}
}
CTX_DATA_END;
+
+ if ((ob_eval) && (ok)) {
+ add_v3_v3(min, ob_eval->obmat[3]);
+ add_v3_v3(max, ob_eval->obmat[3]);
+ }
+ }
+ else if (ob_eval && (ob_eval->type == OB_GPENCIL)) {
+ ok |= BKE_gpencil_data_minmax(ob_eval, gpd, min, max);
+ }
+ else if (is_face_map) {
+ ok = WM_gizmomap_minmax(ar->gizmo_map, true, true, min, max);
}
else if (obedit) {
- ok = ED_view3d_minmax_verts(obedit, min, max); /* only selected */
+ /* only selected */
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, obedit->mode, ob_eval_iter) {
+ ok |= ED_view3d_minmax_verts(ob_eval_iter, min, max);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
}
- else if (ob && (ob->mode & OB_MODE_POSE)) {
- ok = BKE_pose_minmax(ob, min, max, true, true);
+ else if (ob_eval && (ob_eval->mode & OB_MODE_POSE)) {
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, ob_eval->mode, ob_eval_iter) {
+ ok |= BKE_pose_minmax(ob_eval_iter, min, max, true, true);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
}
- else if (BKE_paint_select_face_test(ob)) {
- ok = paintface_minmax(ob, min, max);
+ else if (BKE_paint_select_face_test(ob_eval)) {
+ ok = paintface_minmax(ob_eval, min, max);
}
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
- ok = PE_minmax(bmain, scene, min, max);
+ else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) {
+ ok = PE_minmax(scene, view_layer_eval, min, max);
}
- else if (ob &&
- (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)))
+ else if (ob_eval &&
+ (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)))
{
- BKE_paint_stroke_get_average(scene, ob, min);
+ BKE_paint_stroke_get_average(scene, ob_eval, min);
copy_v3_v3(max, min);
ok = true;
ok_dist = 0; /* don't zoom */
}
else {
- Base *base;
- for (base = FIRSTBASE; base; base = base->next) {
- if (TESTBASE(v3d, base)) {
+ Base *base_eval;
+ for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) {
+ if (TESTBASE(v3d, base_eval)) {
- if (skip_camera && base->object == v3d->camera) {
+ if (skip_camera && base_eval->object == v3d->camera) {
continue;
}
/* account for duplis */
- if (BKE_object_minmax_dupli(bmain, scene, base->object, min, max, false) == 0)
- BKE_object_minmax(base->object, min, max, false); /* use if duplis not found */
+ if (BKE_object_minmax_dupli(depsgraph, scene, base_eval->object, min, max, false) == 0)
+ BKE_object_minmax(base_eval->object, min, max, false); /* use if duplis not found */
ok = 1;
}
@@ -2952,14 +2978,14 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op))
Object *obact = CTX_data_active_object(C);
if (v3d) {
-
ED_view3d_lock_clear(v3d);
v3d->ob_centre = obact; /* can be NULL */
if (obact && obact->type == OB_ARMATURE) {
if (obact->mode & OB_MODE_POSE) {
- bPoseChannel *pcham_act = BKE_pose_channel_active(obact);
+ Object *obact_eval = DEG_get_evaluated_object(CTX_data_depsgraph(C), obact);
+ bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval);
if (pcham_act) {
BLI_strncpy(v3d->ob_centre_bone, pcham_act->name, sizeof(v3d->ob_centre_bone));
}
@@ -3017,7 +3043,7 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
/* non camera center */
float new_ofs[3];
- negate_v3_v3(new_ofs, ED_view3d_cursor3d_get(scene, v3d));
+ negate_v3_v3(new_ofs, scene->cursor.location);
ED_view3d_smooth_view(
C, v3d, ar, smooth_viewtx,
&(const V3D_SmoothParams) {.ofs = new_ofs});
@@ -3051,13 +3077,12 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Main *bmain = CTX_data_main(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
- Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
if (rv3d) {
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
float new_ofs[3];
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
@@ -3065,7 +3090,7 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
view3d_operator_needs_opengl(C);
- if (ED_view3d_autodist(bmain, scene, ar, v3d, event->mval, new_ofs, false, NULL)) {
+ if (ED_view3d_autodist(depsgraph, ar, v3d, event->mval, new_ofs, false, NULL)) {
/* pass */
}
else {
@@ -3105,6 +3130,7 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot)
static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
float xfac, yfac;
float size[2];
@@ -3119,7 +3145,7 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was
rv3d->camdx = rv3d->camdy = 0.0f;
- ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size);
+ ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size);
/* 4px is just a little room from the edge of the area */
xfac = (float)ar->winx / (float)(size[0] + 4);
@@ -3197,18 +3223,14 @@ static int render_border_exec(bContext *C, wmOperator *op)
rcti rect;
rctf vb, border;
- const bool camera_only = RNA_boolean_get(op->ptr, "camera_only");
-
- if (camera_only && rv3d->persp != RV3D_CAMOB)
- return OPERATOR_PASS_THROUGH;
-
- /* get border select values using rna */
+ /* get box select values using rna */
WM_operator_properties_border_to_rcti(op, &rect);
/* calculate range */
if (rv3d->persp == RV3D_CAMOB) {
- ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false);
}
else {
vb.xmin = 0;
@@ -3253,23 +3275,24 @@ static int render_border_exec(bContext *C, wmOperator *op)
v3d->flag2 |= V3D_RENDER_BORDER;
}
+ if (rv3d->persp == RV3D_CAMOB) {
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ }
return OPERATOR_FINISHED;
}
void VIEW3D_OT_render_border(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Set Render Border";
ot->description = "Set the boundaries of the border render and enable border render";
ot->idname = "VIEW3D_OT_render_border";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = render_border_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_view3d_active;
@@ -3278,10 +3301,6 @@ void VIEW3D_OT_render_border(wmOperatorType *ot)
/* properties */
WM_operator_properties_border(ot);
-
- prop = RNA_def_boolean(ot->srna, "camera_only", false, "Camera Only",
- "Set render border for camera view and final render only");
- RNA_def_property_flag(prop, PROP_HIDDEN);
}
/** \} */
@@ -3316,6 +3335,9 @@ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
border->xmax = 1.0f;
border->ymax = 1.0f;
+ if (rv3d->persp == RV3D_CAMOB) {
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ }
return OPERATOR_FINISHED;
}
@@ -3342,11 +3364,9 @@ void VIEW3D_OT_clear_render_border(wmOperatorType *ot)
static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
- Scene *scene = CTX_data_scene(C);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
/* Zooms in on a border drawn by the user */
@@ -3359,14 +3379,13 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
float new_ofs[3];
/* ZBuffer depth vars */
- bglMats mats;
float depth_close = FLT_MAX;
- double cent[2], p[3];
+ float cent[2], p[3];
/* note; otherwise opengl won't work */
view3d_operator_needs_opengl(C);
- /* get border select values using rna */
+ /* get box select values using rna */
WM_operator_properties_border_to_rcti(op, &rect);
/* check if zooming in/out view */
@@ -3375,8 +3394,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
ED_view3d_dist_range_get(v3d, dist_range);
/* Get Z Depths, needed for perspective, nice for ortho */
- bgl_get_mats(&mats);
- ED_view3d_draw_depth(bmain, scene, ar, v3d, true);
+ ED_view3d_draw_depth(CTX_data_depsgraph(C), ar, v3d, true);
{
/* avoid allocating the whole depth buffer */
@@ -3391,11 +3409,11 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
MEM_SAFE_FREE(depth_temp.depths);
}
- cent[0] = (((double)rect.xmin) + ((double)rect.xmax)) / 2;
- cent[1] = (((double)rect.ymin) + ((double)rect.ymax)) / 2;
+ cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2;
+ cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2;
if (rv3d->is_persp) {
- double p_corner[3];
+ float p_corner[3];
/* no depths to use, we cant do anything! */
if (depth_close == FLT_MAX) {
@@ -3403,23 +3421,14 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* convert border to 3d coordinates */
- if ((!gluUnProject(cent[0], cent[1], depth_close,
- mats.modelview, mats.projection, (GLint *)mats.viewport,
- &p[0], &p[1], &p[2])) ||
- (!gluUnProject((double)rect.xmin, (double)rect.ymin, depth_close,
- mats.modelview, mats.projection, (GLint *)mats.viewport,
- &p_corner[0], &p_corner[1], &p_corner[2])))
+ if ((!ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) ||
+ (!ED_view3d_unproject(ar, rect.xmin, rect.ymin, depth_close, p_corner)))
{
return OPERATOR_CANCELLED;
}
- dvec[0] = p[0] - p_corner[0];
- dvec[1] = p[1] - p_corner[1];
- dvec[2] = p[2] - p_corner[2];
-
- new_ofs[0] = -p[0];
- new_ofs[1] = -p[1];
- new_ofs[2] = -p[2];
+ sub_v3_v3v3(dvec, p, p_corner);
+ negate_v3_v3(new_ofs, p);
new_dist = len_v3(dvec);
@@ -3434,13 +3443,8 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
new_dist = rv3d->dist;
/* convert the drawn rectangle into 3d space */
- if (depth_close != FLT_MAX && gluUnProject(cent[0], cent[1], depth_close,
- mats.modelview, mats.projection, (GLint *)mats.viewport,
- &p[0], &p[1], &p[2]))
- {
- new_ofs[0] = -p[0];
- new_ofs[1] = -p[1];
- new_ofs[2] = -p[2];
+ if (depth_close != FLT_MAX && ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) {
+ negate_v3_v3(new_ofs, p);
}
else {
float mval_f[2];
@@ -3477,6 +3481,13 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* clamp after because we may have been zooming out */
CLAMP(new_dist, dist_range[0], dist_range[1]);
+ /* TODO(campbell): 'is_camera_lock' not currently working well. */
+ const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d);
+ if ((rv3d->persp == RV3D_CAMOB) && (is_camera_lock == false)) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, RV3D_PERSP);
+ }
+
ED_view3d_smooth_view(
C, v3d, ar, smooth_viewtx,
&(const V3D_SmoothParams) {.ofs = new_ofs, .dist = &new_dist});
@@ -3488,18 +3499,6 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
-
- /* if in camera view do not exec the operator so we do not conflict with set render border*/
- if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d))
- return WM_gesture_border_invoke(C, op, event);
- else
- return OPERATOR_PASS_THROUGH;
-}
-
void VIEW3D_OT_zoom_border(wmOperatorType *ot)
{
/* identifiers */
@@ -3508,10 +3507,10 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot)
ot->idname = "VIEW3D_OT_zoom_border";
/* api callbacks */
- ot->invoke = view3d_zoom_border_invoke;
+ ot->invoke = WM_gesture_box_invoke;
ot->exec = view3d_zoom_border_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_region_view3d_active;
@@ -3519,7 +3518,7 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot)
ot->flag = 0;
/* properties */
- WM_operator_properties_gesture_border_zoom(ot);
+ WM_operator_properties_gesture_box_zoom(ot);
}
/** \} */
@@ -3530,13 +3529,13 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot)
* Sets the view to 1:1 camera/render-pixel.
* \{ */
-static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d)
+static void view3d_set_1_to_1_viewborder(Scene *scene, Depsgraph *depsgraph, ARegion *ar, View3D *v3d)
{
RegionView3D *rv3d = ar->regiondata;
float size[2];
int im_width = (scene->r.size * scene->r.xsch) / 100;
- ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size);
+ ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size);
rv3d->camzoom = BKE_screen_view3d_zoom_from_fac((float)im_width / size[0]);
CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
@@ -3544,6 +3543,7 @@ static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d)
static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d;
@@ -3552,7 +3552,7 @@ static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op))
/* no NULL check is needed, poll checks */
ED_view3d_context_user_region(C, &v3d, &ar);
- view3d_set_1_to_1_viewborder(scene, ar, v3d);
+ view3d_set_1_to_1_viewborder(scene, depsgraph, ar, v3d);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
@@ -3577,7 +3577,7 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name View Axis/Type Operator
+/** \name View Axis Operator
* \{ */
static const EnumPropertyItem prop_view_items[] = {
@@ -3587,17 +3587,20 @@ static const EnumPropertyItem prop_view_items[] = {
{RV3D_VIEW_TOP, "TOP", ICON_TRIA_UP, "Top", "View From the Top"},
{RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
{RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
- {RV3D_VIEW_CAMERA, "CAMERA", ICON_CAMERA_DATA, "Camera", "View From the Active Camera"},
{0, NULL, 0, NULL, NULL}
};
/* would like to make this a generic function - outside of transform */
+/**
+ * \param align_to_quat: When not NULL, set the axis relative to this rotation.
+ */
static void axis_set_view(
bContext *C, View3D *v3d, ARegion *ar,
const float quat_[4],
- short view, int perspo, bool align_active,
+ short view, int perspo,
+ const float *align_to_quat,
const int smooth_viewtx)
{
RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */
@@ -3607,29 +3610,12 @@ static void axis_set_view(
normalize_qt_qt(quat, quat_);
- if (align_active) {
- /* align to active object */
- Object *obact = CTX_data_active_object(C);
- if (obact == NULL) {
- /* no active object, ignore this option */
- align_active = false;
- }
- else {
- float obact_quat[4];
- float twmat[3][3];
-
- /* same as transform manipulator when normal is set */
- ED_getTransformOrientationMatrix(C, twmat, V3D_AROUND_ACTIVE);
-
- mat3_to_quat(obact_quat, twmat);
- invert_qt_normalized(obact_quat);
- mul_qt_qtqt(quat, quat, obact_quat);
-
- rv3d->view = view = RV3D_VIEW_USER;
- }
+ if (align_to_quat) {
+ mul_qt_qtqt(quat, quat, align_to_quat);
+ rv3d->view = view = RV3D_VIEW_USER;
}
- if (align_active == false) {
+ if (align_to_quat == NULL) {
rv3d->view = view;
}
@@ -3659,7 +3645,8 @@ static void axis_set_view(
dist = rv3d->dist;
/* so we animate _from_ the camera location */
- ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, &rv3d->dist, NULL);
+ Object *camera_eval = DEG_get_evaluated_object(CTX_data_depsgraph(C), v3d->camera);
+ ED_view3d_from_object(camera_eval, rv3d->ofs, NULL, &rv3d->dist, NULL);
ED_view3d_smooth_view(
C, v3d, ar, smooth_viewtx,
@@ -3684,15 +3671,13 @@ static void axis_set_view(
}
}
-static int viewnumpad_exec(bContext *C, wmOperator *op)
+static int view_axis_exec(bContext *C, wmOperator *op)
{
View3D *v3d;
ARegion *ar;
RegionView3D *rv3d;
- Scene *scene = CTX_data_scene(C);
static int perspo = RV3D_PERSP;
- int viewnum, nextperspo;
- bool align_active;
+ int viewnum;
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
/* no NULL check is needed, poll checks */
@@ -3702,118 +3687,209 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
ED_view3d_smooth_view_force_finish(C, v3d, ar);
viewnum = RNA_enum_get(op->ptr, "type");
- align_active = RNA_boolean_get(op->ptr, "align_active");
- /* Use this to test if we started out with a camera */
+ float align_quat_buf[4];
+ float *align_quat = NULL;
- if (rv3d->persp == RV3D_CAMOB) {
- nextperspo = rv3d->lpersp;
- }
- else {
- nextperspo = perspo;
+ if (RNA_boolean_get(op->ptr, "align_active")) {
+ /* align to active object */
+ Object *obact = CTX_data_active_object(C);
+ if (obact != NULL) {
+ float twmat[3][3];
+ /* same as transform gizmo when normal is set */
+ ED_getTransformOrientationMatrix(C, twmat, V3D_AROUND_ACTIVE);
+ align_quat = align_quat_buf;
+ mat3_to_quat(align_quat, twmat);
+ invert_qt_normalized(align_quat);
+ }
}
- if (RV3D_VIEW_IS_AXIS(viewnum)) {
- float quat[4];
+ if (RNA_boolean_get(op->ptr, "relative")) {
+ float z_rel[3];
- ED_view3d_quat_from_axis_view(viewnum, quat);
- axis_set_view(C, v3d, ar, quat, viewnum, nextperspo, align_active, smooth_viewtx);
+ if (viewnum == RV3D_VIEW_RIGHT) {
+ negate_v3_v3(z_rel, rv3d->viewinv[0]);
+ }
+ else if (viewnum == RV3D_VIEW_LEFT) {
+ copy_v3_v3(z_rel, rv3d->viewinv[0]);
+ }
+ else if (viewnum == RV3D_VIEW_TOP) {
+ negate_v3_v3(z_rel, rv3d->viewinv[1]);
+ }
+ else if (viewnum == RV3D_VIEW_BOTTOM) {
+ copy_v3_v3(z_rel, rv3d->viewinv[1]);
+ }
+ else if (viewnum == RV3D_VIEW_FRONT) {
+ negate_v3_v3(z_rel, rv3d->viewinv[2]);
+ }
+ else if (viewnum == RV3D_VIEW_BACK) {
+ copy_v3_v3(z_rel, rv3d->viewinv[2]);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ float angle_max = FLT_MAX;
+ int view_closest = -1;
+ for (int i = RV3D_VIEW_FRONT; i <= RV3D_VIEW_BOTTOM; i++) {
+ float quat[4];
+ float mat[3][3];
+ ED_view3d_quat_from_axis_view(i, quat);
+ quat[0] *= -1.0f;
+ quat_to_mat3(mat, quat);
+ if (align_quat) {
+ mul_qt_qtqt(quat, quat, align_quat);
+ }
+ const float angle_test = angle_normalized_v3v3(z_rel, mat[2]);
+ if (angle_max > angle_test) {
+ angle_max = angle_test;
+ view_closest = i;
+ }
+ }
+ if (view_closest == -1) {
+ view_closest = RV3D_VIEW_FRONT;
+ }
+ viewnum = view_closest;
}
- else if (viewnum == RV3D_VIEW_CAMERA) {
- if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
- /* lastview - */
- if (rv3d->persp != RV3D_CAMOB) {
- Object *ob = OBACT;
+ /* Use this to test if we started out with a camera */
+ const int nextperspo = (rv3d->persp == RV3D_CAMOB) ? rv3d->lpersp : perspo;
+ float quat[4];
+ ED_view3d_quat_from_axis_view(viewnum, quat);
+ axis_set_view(C, v3d, ar, quat, viewnum, nextperspo, align_quat, smooth_viewtx);
+
+ perspo = rv3d->persp;
- if (!rv3d->smooth_timer) {
- /* store settings of current view before allowing overwriting with camera view
- * only if we're not currently in a view transition */
+ return OPERATOR_FINISHED;
+}
- ED_view3d_lastview_store(rv3d);
- }
+
+void VIEW3D_OT_view_axis(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "View Axis";
+ ot->description = "Use a preset viewpoint";
+ ot->idname = "VIEW3D_OT_view_axis";
+
+ /* api callbacks */
+ ot->exec = view_axis_exec;
+ ot->poll = ED_operator_rv3d_user_region_poll;
+
+ /* flags */
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "Preset viewpoint to use");
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active object's axis");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "relative", 0, "Relative", "Rotate relative to the current orientation");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Camera Operator
+ * \{ */
+
+static int view_camera_exec(bContext *C, wmOperator *op)
+{
+ View3D *v3d;
+ ARegion *ar;
+ RegionView3D *rv3d;
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+
+ /* no NULL check is needed, poll checks */
+ ED_view3d_context_user_region(C, &v3d, &ar);
+ rv3d = ar->regiondata;
+
+ ED_view3d_smooth_view_force_finish(C, v3d, ar);
+
+ if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
+ /* lastview - */
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = CTX_data_scene(C);
+
+ if (rv3d->persp != RV3D_CAMOB) {
+ Object *ob = OBACT(view_layer);
+
+ if (!rv3d->smooth_timer) {
+ /* store settings of current view before allowing overwriting with camera view
+ * only if we're not currently in a view transition */
+
+ ED_view3d_lastview_store(rv3d);
+ }
#if 0
- if (G.qual == LR_ALTKEY) {
- if (oldcamera && is_an_active_object(oldcamera)) {
- v3d->camera = oldcamera;
- }
- handle_view3d_lock();
+ if (G.qual == LR_ALTKEY) {
+ if (oldcamera && is_an_active_object(oldcamera)) {
+ v3d->camera = oldcamera;
}
+ handle_view3d_lock();
+ }
#endif
- /* first get the default camera for the view lock type */
- if (v3d->scenelock) {
- /* sets the camera view if available */
+ /* first get the default camera for the view lock type */
+ if (v3d->scenelock) {
+ /* sets the camera view if available */
+ v3d->camera = scene->camera;
+ }
+ else {
+ /* use scene camera if one is not set (even though we're unlocked) */
+ if (v3d->camera == NULL) {
v3d->camera = scene->camera;
}
- else {
- /* use scene camera if one is not set (even though we're unlocked) */
- if (v3d->camera == NULL) {
- v3d->camera = scene->camera;
- }
- }
+ }
- /* if the camera isn't found, check a number of options */
- if (v3d->camera == NULL && ob && ob->type == OB_CAMERA)
- v3d->camera = ob;
+ /* if the camera isn't found, check a number of options */
+ if (v3d->camera == NULL && ob && ob->type == OB_CAMERA)
+ v3d->camera = ob;
- if (v3d->camera == NULL)
- v3d->camera = BKE_scene_camera_find(scene);
+ if (v3d->camera == NULL)
+ v3d->camera = BKE_view_layer_camera_find(view_layer);
- /* couldnt find any useful camera, bail out */
- if (v3d->camera == NULL)
- return OPERATOR_CANCELLED;
+ /* couldn't find any useful camera, bail out */
+ if (v3d->camera == NULL)
+ return OPERATOR_CANCELLED;
- /* important these don't get out of sync for locked scenes */
- if (v3d->scenelock)
- scene->camera = v3d->camera;
+ /* important these don't get out of sync for locked scenes */
+ if (v3d->scenelock)
+ scene->camera = v3d->camera;
- /* finally do snazzy view zooming */
- rv3d->persp = RV3D_CAMOB;
- ED_view3d_smooth_view(
- C, v3d, ar, smooth_viewtx,
- &(const V3D_SmoothParams) {
- .camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat,
- .dist = &rv3d->dist, .lens = &v3d->lens});
- }
- else {
- /* return to settings of last view */
- /* does view3d_smooth_view too */
- axis_set_view(C, v3d, ar,
- rv3d->lviewquat,
- rv3d->lview, rv3d->lpersp, 0,
- smooth_viewtx);
- }
+ /* finally do snazzy view zooming */
+ rv3d->persp = RV3D_CAMOB;
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {
+ .camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat,
+ .dist = &rv3d->dist, .lens = &v3d->lens});
+ }
+ else {
+ /* return to settings of last view */
+ /* does view3d_smooth_view too */
+ axis_set_view(C, v3d, ar, rv3d->lviewquat, rv3d->lview, rv3d->lpersp, NULL, smooth_viewtx);
}
}
- if (rv3d->persp != RV3D_CAMOB) perspo = rv3d->persp;
-
return OPERATOR_FINISHED;
}
-
-void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
+void VIEW3D_OT_view_camera(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
- ot->name = "View Numpad";
- ot->description = "Use a preset viewpoint";
- ot->idname = "VIEW3D_OT_viewnumpad";
+ ot->name = "View Camera";
+ ot->description = "Toggle the camera view";
+ ot->idname = "VIEW3D_OT_view_camera";
/* api callbacks */
- ot->exec = viewnumpad_exec;
+ ot->exec = view_camera_exec;
ot->poll = ED_operator_rv3d_user_region_poll;
/* flags */
ot->flag = 0;
-
- ot->prop = RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "Preset viewpoint to use");
- RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active object's axis");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -3867,7 +3943,8 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
float quat_new[4];
if (view_opposite == RV3D_VIEW_USER) {
- ED_view3d_persp_ensure(v3d, ar);
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_view3d_persp_ensure(depsgraph, v3d, ar);
}
if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) {
@@ -3992,7 +4069,7 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y))
view3d_boxview_sync(vod->sa, vod->ar);
}
- ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d);
+ ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
ED_region_tag_redraw(vod->ar);
}
@@ -4226,8 +4303,8 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void VIEW3D_OT_view_pan(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Pan";
- ot->description = "Pan the view";
+ ot->name = "Pan View Direction";
+ ot->description = "Pan the view in a given direction";
ot->idname = "VIEW3D_OT_view_pan";
/* api callbacks */
@@ -4325,52 +4402,67 @@ void VIEW3D_OT_navigate(wmOperatorType *ot)
/** \name Background Image Add Operator
* \{ */
-static BGpic *background_image_add(bContext *C)
+
+static Camera *background_image_camera_from_context(bContext *C)
{
+ /* Needed to support drag-and-drop & camera buttons context. */
View3D *v3d = CTX_wm_view3d(C);
-
- return ED_view3d_background_image_new(v3d);
+ if (v3d != NULL) {
+ if (v3d->camera && v3d->camera->data && v3d->camera->type == OB_CAMERA) {
+ return v3d->camera->data;
+ }
+ return NULL;
+ }
+ else {
+ return CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
+ }
}
static int background_image_add_exec(bContext *C, wmOperator *UNUSED(op))
{
- background_image_add(C);
+ Camera *cam = background_image_camera_from_context(C);
+ BKE_camera_background_image_new(cam);
return OPERATOR_FINISHED;
}
static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- View3D *v3d = CTX_wm_view3d(C);
+ Camera *cam = background_image_camera_from_context(C);
Image *ima;
- BGpic *bgpic;
+ CameraBGImage *bgpic;
ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
/* may be NULL, continue anyway */
- bgpic = background_image_add(C);
+ bgpic = BKE_camera_background_image_new(cam);
bgpic->ima = ima;
- v3d->flag |= V3D_DISPBGPICS;
+ cam->flag |= CAM_SHOW_BG_IMAGE;
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
return OPERATOR_FINISHED;
}
+static bool background_image_add_poll(bContext *C)
+{
+ return background_image_camera_from_context(C) != NULL;
+}
+
void VIEW3D_OT_background_image_add(wmOperatorType *ot)
{
/* identifiers */
/* 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 (Ctrl for Empty Object)";
+ ot->name = "Add Background Image";
+ ot->description = "Add a new background image";
ot->idname = "VIEW3D_OT_background_image_add";
/* api callbacks */
ot->invoke = background_image_add_invoke;
ot->exec = background_image_add_exec;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = background_image_add_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -4390,21 +4482,21 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
static int background_image_remove_exec(bContext *C, wmOperator *op)
{
- View3D *v3d = CTX_wm_view3d(C);
+ Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
const int index = RNA_int_get(op->ptr, "index");
- BGpic *bgpic_rem = BLI_findlink(&v3d->bgpicbase, index);
+ CameraBGImage *bgpic_rem = BLI_findlink(&cam->bg_images, index);
if (bgpic_rem) {
- if (bgpic_rem->source == V3D_BGPIC_IMAGE) {
+ if (bgpic_rem->source == CAM_BGIMG_SOURCE_IMAGE) {
id_us_min((ID *)bgpic_rem->ima);
}
- else if (bgpic_rem->source == V3D_BGPIC_MOVIE) {
+ else if (bgpic_rem->source == CAM_BGIMG_SOURCE_MOVIE) {
id_us_min((ID *)bgpic_rem->clip);
}
- ED_view3d_background_image_remove(v3d, bgpic_rem);
+ BKE_camera_background_image_remove(cam, bgpic_rem);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
return OPERATOR_FINISHED;
}
else {
@@ -4421,7 +4513,7 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = background_image_remove_exec;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = ED_operator_camera;
/* flags */
ot->flag = 0;
@@ -4459,11 +4551,12 @@ void ED_view3d_clipping_local(RegionView3D *rv3d, float mat[4][4])
calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
}
+#if 0 /* TODO Missing from 2.8 drawing code. Find a solution to support clip border then uncomment it. */
+
static int view3d_clipping_exec(bContext *C, wmOperator *op)
{
+ ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
- ViewContext vc;
- bglMats mats;
rcti rect;
WM_operator_properties_border_to_rcti(op, &rect);
@@ -4471,12 +4564,8 @@ static int view3d_clipping_exec(bContext *C, wmOperator *op)
rv3d->rflag |= RV3D_CLIPPING;
rv3d->clipbb = MEM_callocN(sizeof(BoundBox), "clipbb");
- /* note; otherwise opengl won't work */
- view3d_operator_needs_opengl(C);
-
- ED_view3d_viewcontext_init(C, &vc);
- view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */
- ED_view3d_clipping_calc(rv3d->clipbb, rv3d->clip, &mats, &rect);
+ /* NULL object because we don't want it in object space */
+ ED_view3d_clipping_calc(rv3d->clipbb, rv3d->clip, ar, NULL, &rect);
return OPERATOR_FINISHED;
}
@@ -4494,7 +4583,7 @@ static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_FINISHED;
}
else {
- return WM_gesture_border_invoke(C, op, event);
+ return WM_gesture_box_invoke(C, op, event);
}
}
@@ -4509,8 +4598,8 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
/* api callbacks */
ot->invoke = view3d_clipping_invoke;
ot->exec = view3d_clipping_exec;
- ot->modal = WM_gesture_border_modal;
- ot->cancel = WM_gesture_border_cancel;
+ ot->modal = WM_gesture_box_modal;
+ ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_region_view3d_active;
@@ -4520,6 +4609,7 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
/* properties */
WM_operator_properties_border(ot);
}
+#endif
/** \} */
@@ -4529,10 +4619,8 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
/* cursor position in vec, result in vec, mval in region coords */
/* note: cannot use event->mval here (called by object_add() */
-void ED_view3d_cursor3d_position(bContext *C, const int mval[2], float cursor_co[3])
+void ED_view3d_cursor3d_position(bContext *C, const int mval[2], const bool use_depth, float cursor_co[3])
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ar->regiondata;
@@ -4553,10 +4641,13 @@ void ED_view3d_cursor3d_position(bContext *C, const int mval[2], float cursor_co
ED_view3d_calc_zfac(rv3d, cursor_co, NULL /* &flip */ );
}
- if (U.uiflag & USER_DEPTH_CURSOR) { /* maybe this should be accessed some other way */
+ if (use_depth) { /* maybe this should be accessed some other way */
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
view3d_operator_needs_opengl(C);
- if (ED_view3d_autodist(bmain, scene, ar, v3d, mval, cursor_co, true, NULL))
+ if (ED_view3d_autodist(depsgraph, ar, v3d, mval, cursor_co, true, NULL)) {
depth_used = true;
+ }
}
if (depth_used == false) {
@@ -4566,31 +4657,122 @@ void ED_view3d_cursor3d_position(bContext *C, const int mval[2], float cursor_co
}
}
-void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
+void ED_view3d_cursor3d_position_rotation(
+ bContext *C, const int mval[2],
+ const bool use_depth, enum eV3DCursorOrient orientation,
+ float cursor_co[3], float cursor_quat[4])
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* XXX, caller should check. */
+ if (rv3d == NULL)
+ return;
- float *cursor_co_curr = ED_view3d_cursor3d_get(scene, v3d);
- float cursor_co_prev[3];
+ ED_view3d_cursor3d_position(C, mval, use_depth, cursor_co);
+
+ if (orientation == V3D_CURSOR_ORIENT_NONE) {
+ /* pass */
+ }
+ else if (orientation == V3D_CURSOR_ORIENT_VIEW) {
+ copy_qt_qt(cursor_quat, rv3d->viewquat);
+ cursor_quat[0] *= -1.0f;
+ }
+ else if (orientation == V3D_CURSOR_ORIENT_XFORM) {
+ float mat[3][3];
+ ED_transform_calc_orientation_from_type(C, mat);
+ mat3_to_quat(cursor_quat, mat);
+ }
+ else if (orientation == V3D_CURSOR_ORIENT_GEOM) {
+ copy_qt_qt(cursor_quat, rv3d->viewquat);
+ cursor_quat[0] *= -1.0f;
+
+ const float mval_fl[2] = {UNPACK2(mval)};
+ float ray_no[3];
+ float ray_co[3];
+
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
+ bmain, scene, CTX_data_depsgraph(C), 0, ar, v3d);
+
+ float obmat[4][4];
+ Object *ob_dummy = NULL;
+ float dist_px = 0;
+ if (ED_transform_snap_object_project_view3d_ex(
+ snap_context,
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = false,
+ },
+ mval_fl, &dist_px,
+ ray_co, ray_no, NULL,
+ &ob_dummy, obmat))
+ {
+ if (use_depth) {
+ copy_v3_v3(cursor_co, ray_co);
+ }
+
+ float tquat[4];
+
+ /* Math normal (Z). */
+ {
+ float z_src[3] = {0, 0, 1};
+ mul_qt_v3(cursor_quat, z_src);
+ rotation_between_vecs_to_quat(tquat, z_src, ray_no);
+ mul_qt_qtqt(cursor_quat, tquat, cursor_quat);
+ }
+
+ /* Match object matrix (X). */
+ {
+ const float ortho_axis_dot[3] = {
+ dot_v3v3(ray_no, obmat[0]),
+ dot_v3v3(ray_no, obmat[1]),
+ dot_v3v3(ray_no, obmat[2]),
+ };
+ const int ortho_axis = axis_dominant_v3_ortho_single(ortho_axis_dot);
+ float x_src[3] = {1, 0, 0};
+ float x_dst[3];
+ mul_qt_v3(cursor_quat, x_src);
+ project_plane_v3_v3v3(x_dst, obmat[ortho_axis], ray_no);
+ normalize_v3(x_dst);
+ rotation_between_vecs_to_quat(tquat, x_src, x_dst);
+ mul_qt_qtqt(cursor_quat, tquat, cursor_quat);
+ }
+ }
+ ED_transform_snap_object_context_destroy(snap_context);
+ }
+}
+
+void ED_view3d_cursor3d_update(
+ bContext *C, const int mval[2],
+ const bool use_depth, enum eV3DCursorOrient orientation)
+{
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
- copy_v3_v3(cursor_co_prev, cursor_co_curr);
+ View3DCursor *cursor_curr = &scene->cursor;
+ View3DCursor cursor_prev = *cursor_curr;
- ED_view3d_cursor3d_position(C, mval, cursor_co_curr);
+ ED_view3d_cursor3d_position_rotation(
+ C, mval,
+ use_depth, orientation,
+ cursor_curr->location, cursor_curr->rotation);
/* offset the cursor lock to avoid jumping to new offset */
if (v3d->ob_centre_cursor) {
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
-
if (U.uiflag & USER_LOCK_CURSOR_ADJUST) {
float co_2d_curr[2], co_2d_prev[2];
if ((ED_view3d_project_float_global(
- ar, cursor_co_prev, co_2d_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
+ ar, cursor_prev.location, co_2d_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
(ED_view3d_project_float_global(
- ar, cursor_co_curr, co_2d_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
+ ar, cursor_curr->location, co_2d_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
{
rv3d->ofs_lock[0] += (co_2d_curr[0] - co_2d_prev[0]) / (ar->winx * 0.5f);
rv3d->ofs_lock[1] += (co_2d_curr[1] - co_2d_prev[1]) / (ar->winy * 0.5f);
@@ -4606,11 +4788,30 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
else
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
+
+ {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(
+ mbus, &scene->id, scene, Scene, cursor_location);
+ }
+
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
}
-static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int view3d_cursor3d_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ED_view3d_cursor3d_update(C, event->mval);
+ bool use_depth = (U.uiflag & USER_DEPTH_CURSOR);
+ {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_depth");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ use_depth = RNA_property_boolean_get(op->ptr, prop);
+ }
+ else {
+ RNA_property_boolean_set(op->ptr, prop, use_depth);
+ }
+ }
+ const enum eV3DCursorOrient orientation = RNA_enum_get(op->ptr, "orientation");
+ ED_view3d_cursor3d_update(C, event->mval, use_depth, orientation);
return OPERATOR_FINISHED;
}
@@ -4630,128 +4831,147 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot)
/* flags */
// ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Transform Manipulator Operator
- * \{ */
-
-static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- View3D *v3d = CTX_wm_view3d(C);
-
- if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
- if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
-
- /* note; otherwise opengl won't work */
- view3d_operator_needs_opengl(C);
-
- if (BIF_do_manipulator(C, event, op) == 0)
- return OPERATOR_PASS_THROUGH;
-
- return OPERATOR_FINISHED;
-}
-
-void VIEW3D_OT_manipulator(wmOperatorType *ot)
-{
PropertyRNA *prop;
+ static const EnumPropertyItem orientation_items[] = {
+ {V3D_CURSOR_ORIENT_NONE, "NONE", 0, "None", "Leave orientation unchanged"},
+ {V3D_CURSOR_ORIENT_VIEW, "VIEW", 0, "View", "Orient to the viewport"},
+ {V3D_CURSOR_ORIENT_XFORM, "XFORM", 0, "Transform", "Orient to the current transform setting"},
+ {V3D_CURSOR_ORIENT_GEOM, "GEOM", 0, "Geometry", "Match the surface normal"},
+ {0, NULL, 0, NULL, NULL}
+ };
- /* identifiers */
- ot->name = "3D Manipulator";
- ot->description = "Manipulate selected item by axis";
- ot->idname = "VIEW3D_OT_manipulator";
-
- /* api callbacks */
- ot->invoke = manipulator_invoke;
-
- ot->poll = ED_operator_view3d_active;
-
- /* properties to pass to transform */
- Transform_Properties(ot, P_CONSTRAINT);
+ prop = RNA_def_boolean(
+ ot->srna, "use_depth", true, "Surface Project",
+ "Project onto the surface");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "use_planar_constraint", false, "Planar Constraint", "Limit the transformation to the "
- "two axes that have not been clicked (translate/scale only)");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_enum(
+ ot->srna, "orientation", orientation_items, V3D_CURSOR_ORIENT_VIEW,
+ "Orientation", "Preset viewpoint to use");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Enable Transform Manipulator Operator
+/** \name Toggle Shading Operator
* \{ */
-static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static const EnumPropertyItem prop_shading_type_items[] = {
+ {OB_WIRE, "WIREFRAME", 0, "Wireframe", "Toggle wireframe shading"},
+ {OB_SOLID, "SOLID", 0, "Solid", "Toggle solid shading"},
+ {OB_MATERIAL, "MATERIAL", 0, "LookDev", "Toggle lookdev shading"},
+ {OB_RENDER, "RENDERED", 0, "Rendered", "Toggle rendered shading"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int toggle_shading_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
View3D *v3d = CTX_wm_view3d(C);
+ ScrArea *sa = CTX_wm_area(C);
+ int type = RNA_enum_get(op->ptr, "type");
- v3d->twtype = 0;
-
- if (RNA_boolean_get(op->ptr, "translate"))
- v3d->twtype |= V3D_MANIP_TRANSLATE;
- if (RNA_boolean_get(op->ptr, "rotate"))
- v3d->twtype |= V3D_MANIP_ROTATE;
- if (RNA_boolean_get(op->ptr, "scale"))
- v3d->twtype |= V3D_MANIP_SCALE;
+ if (type == OB_SOLID) {
+ if (v3d->shading.type != type) {
+ v3d->shading.type = type;
+ }
+ else if (v3d->shading.type == OB_WIRE) {
+ v3d->shading.type = OB_SOLID;
+ }
+ else {
+ v3d->shading.type = OB_WIRE;
+ }
+ }
+ else {
+ char *prev_type = (
+ (type == OB_WIRE) ?
+ &v3d->shading.prev_type_wire :
+ &v3d->shading.prev_type);
+ if (v3d->shading.type == type) {
+ if (*prev_type == type || !ELEM(*prev_type, OB_WIRE, OB_SOLID, OB_MATERIAL, OB_RENDER)) {
+ *prev_type = OB_SOLID;
+ }
+ v3d->shading.type = *prev_type;
+ }
+ else {
+ *prev_type = v3d->shading.type;
+ v3d->shading.type = type;
+ }
+ }
+ ED_view3d_shade_update(bmain, v3d, sa);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
return OPERATOR_FINISHED;
}
-void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
+void VIEW3D_OT_toggle_shading(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
- ot->name = "Enable 3D Manipulator";
- ot->description = "Enable the transform manipulator for use";
- ot->idname = "VIEW3D_OT_enable_manipulator";
+ ot->name = "Toggle Shading Type";
+ ot->description = "Toggle shading type in 3D viewport";
+ ot->idname = "VIEW3D_OT_toggle_shading";
/* api callbacks */
- ot->invoke = enable_manipulator_invoke;
+ ot->exec = toggle_shading_exec;
ot->poll = ED_operator_view3d_active;
- /* properties */
- prop = RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "scale", 0, "Scale", "Enable the scale manipulator");
+ prop = RNA_def_enum(ot->srna, "type", prop_shading_type_items, 0, "Type", "Shading type to toggle");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
+
/* -------------------------------------------------------------------- */
-/** \name Toggle Render Shading Operator
+/** \name Toggle XRay
* \{ */
-static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op))
+static int toggle_xray_exec(bContext *C, wmOperator *op)
{
View3D *v3d = CTX_wm_view3d(C);
- if (v3d->drawtype == OB_RENDER) {
- v3d->drawtype = v3d->prev_drawtype;
+ ScrArea *sa = CTX_wm_area(C);
+ Object *obact = CTX_data_active_object(C);
+
+ if (obact &&
+ ((obact->mode & OB_MODE_POSE) ||
+ ((obact->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(obact))))
+ {
+ v3d->overlay.flag ^= V3D_OVERLAY_BONE_SELECT;
}
else {
- v3d->prev_drawtype = v3d->drawtype;
- v3d->drawtype = OB_RENDER;
+ const bool xray_active = (
+ (obact && (obact->mode & OB_MODE_EDIT)) ||
+ ELEM(v3d->shading.type, OB_WIRE, OB_SOLID));
+
+ if (v3d->shading.type == OB_WIRE) {
+ v3d->shading.flag ^= V3D_SHADING_XRAY_BONE;
+ }
+ else {
+ v3d->shading.flag ^= V3D_SHADING_XRAY;
+ }
+ if (!xray_active) {
+ BKE_report(op->reports, RPT_INFO, "X-Ray not available in current mode");
+ }
}
- ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C));
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+
+ ED_area_tag_redraw(sa);
+
return OPERATOR_FINISHED;
}
-void VIEW3D_OT_toggle_render(wmOperatorType *ot)
+void VIEW3D_OT_toggle_xray(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Toggle Rendered Shading";
- ot->description = "Toggle rendered shading mode of the viewport";
- ot->idname = "VIEW3D_OT_toggle_render";
+ ot->name = "Toggle X-Ray";
+ ot->idname = "VIEW3D_OT_toggle_xray";
/* api callbacks */
- ot->exec = toggle_render_exec;
+ ot->exec = toggle_xray_exec;
ot->poll = ED_operator_view3d_active;
}
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 320c00240c1..345d9fe39de 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -56,6 +56,10 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_immediate.h"
+
+#include "DEG_depsgraph.h"
+
#include "view3d_intern.h" /* own include */
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
@@ -133,56 +137,6 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL);
-
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, SPACEKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
-
- WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_ACCELERATE);
- WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, KM_ANY, 0, FLY_MODAL_DECELERATE);
- WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_ACCELERATE);
- WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_DECELERATE);
-
- WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, FLY_MODAL_SPEED);
-
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_PAN_ENABLE);
- /* XXX - Bug in the event system, middle mouse release doesn't work */
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PAN_DISABLE);
-
- /* WASD */
- WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD);
- WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD);
- WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT);
- WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT);
- WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP);
- WM_modalkeymap_add_item(keymap, QKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN);
-
- /* for legacy reasons, leave R/F working */
- WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP);
- WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN);
-
- WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD);
- WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD);
- WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT);
- WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT);
-
- WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X);
- WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z);
-
- WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE);
- WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE);
-
- /* for legacy reasons, leave shift working */
- WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE);
- WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE);
-
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_FREELOOK_ENABLE);
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_FREELOOK_DISABLE);
-
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly");
}
@@ -192,6 +146,7 @@ typedef struct FlyInfo {
RegionView3D *rv3d;
View3D *v3d;
ARegion *ar;
+ struct Depsgraph *depsgraph;
Scene *scene;
wmTimer *timer; /* needed for redraws */
@@ -241,7 +196,7 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar),
float x1, x2, y1, y2;
if (fly->scene->camera) {
- ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false);
xoff = viewborder.xmin;
yoff = viewborder.ymin;
}
@@ -258,36 +213,45 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar),
x2 = xoff + 0.55f * fly->width;
y2 = yoff + 0.55f * fly->height;
- UI_ThemeColor(TH_VIEW_OVERLAY);
- glBegin(GL_LINES);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+
+ immBegin(GPU_PRIM_LINES, 16);
+
/* bottom left */
- glVertex2f(x1, y1);
- glVertex2f(x1, y1 + 5);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x1, y1 + 5);
- glVertex2f(x1, y1);
- glVertex2f(x1 + 5, y1);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x1 + 5, y1);
/* top right */
- glVertex2f(x2, y2);
- glVertex2f(x2, y2 - 5);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x2, y2 - 5);
- glVertex2f(x2, y2);
- glVertex2f(x2 - 5, y2);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x2 - 5, y2);
/* top left */
- glVertex2f(x1, y2);
- glVertex2f(x1, y2 - 5);
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x1, y2 - 5);
- glVertex2f(x1, y2);
- glVertex2f(x1 + 5, y2);
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x1 + 5, y2);
/* bottom right */
- glVertex2f(x2, y1);
- glVertex2f(x2, y1 + 5);
+ immVertex2f(pos, x2, y1);
+ immVertex2f(pos, x2, y1 + 5);
- glVertex2f(x2, y1);
- glVertex2f(x2 - 5, y1);
- glEnd();
+ immVertex2f(pos, x2, y1);
+ immVertex2f(pos, x2 - 5, y1);
+
+ immEnd();
+ immUnbindProgram();
}
static void fly_update_header(bContext *C, wmOperator *op, FlyInfo *fly)
@@ -320,7 +284,7 @@ static void fly_update_header(bContext *C, wmOperator *op, FlyInfo *fly)
#undef WM_MODALKEY
- ED_area_headerprint(CTX_wm_area(C), header);
+ ED_workspace_status_text(C, header);
}
/* FlyInfo->state */
@@ -333,6 +297,7 @@ enum {
static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
+
rctf viewborder;
float upvec[3]; /* tmp */
@@ -341,6 +306,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
fly->rv3d = CTX_wm_region_view3d(C);
fly->v3d = CTX_wm_view3d(C);
fly->ar = CTX_wm_region(C);
+ fly->depsgraph = CTX_data_depsgraph(C);
fly->scene = CTX_data_scene(C);
#ifdef NDOF_FLY_DEBUG
@@ -407,12 +373,12 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
}
fly->v3d_camera_control = ED_view3d_cameracontrol_acquire(
- fly->scene, fly->v3d, fly->rv3d,
+ CTX_data_depsgraph(C), fly->scene, fly->v3d, fly->rv3d,
(U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0);
/* calculate center */
if (fly->scene->camera) {
- ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false);
fly->width = BLI_rctf_size_x(&viewborder);
fly->height = BLI_rctf_size_y(&viewborder);
@@ -1067,7 +1033,7 @@ static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED))
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
return exit_code;
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
new file mode 100644
index 00000000000..4e91712491f
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -0,0 +1,229 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_gizmo_armature.c
+ * \ingroup spview3d
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_context.h"
+#include "BKE_object.h"
+
+#include "DNA_object_types.h"
+#include "DNA_armature_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "view3d_intern.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Armature Spline Gizmo
+ *
+ * \{ */
+
+/*
+ * TODO(campbell): Current conversion is a approximation (usable not correct),
+ * we'll need to take the next/previous bones into account to get the tangent directions.
+ * First last matrices from 'b_bone_spline_setup' are close but also not quite accurate
+ * since they're not at either end-points on the curve.
+ *
+ * Likely we'll need a function especially to get the first/last orientations.
+ */
+
+#define BBONE_SCALE_Y 3.0f
+
+struct BoneSplineHandle {
+ wmGizmo *gizmo;
+ bPoseChannel *pchan;
+ /* We could remove, keep since at the moment for checking the conversion. */
+ float co[3];
+ int index;
+};
+
+struct BoneSplineWidgetGroup {
+ struct BoneSplineHandle handles[2];
+};
+
+static void gizmo_bbone_offset_get(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ struct BoneSplineHandle *bh = gz_prop->custom_func.user_data;
+ bPoseChannel *pchan = bh->pchan;
+
+ float *value = value_p;
+ BLI_assert(gz_prop->type->array_length == 3);
+
+ if (bh->index == 0) {
+ bh->co[1] = pchan->bone->ease1 / BBONE_SCALE_Y;
+ bh->co[0] = pchan->curveInX;
+ bh->co[2] = pchan->curveInY;
+ }
+ else {
+ bh->co[1] = -pchan->bone->ease2 / BBONE_SCALE_Y;
+ bh->co[0] = pchan->curveOutX;
+ bh->co[2] = pchan->curveOutY;
+ }
+ copy_v3_v3(value, bh->co);
+}
+
+static void gizmo_bbone_offset_set(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ struct BoneSplineHandle *bh = gz_prop->custom_func.user_data;
+ bPoseChannel *pchan = bh->pchan;
+
+ const float *value = value_p;
+
+ BLI_assert(gz_prop->type->array_length == 3);
+ copy_v3_v3(bh->co, value);
+
+ if (bh->index == 0) {
+ pchan->bone->ease1 = max_ff(0.0f, bh->co[1] * BBONE_SCALE_Y);
+ pchan->curveInX = bh->co[0];
+ pchan->curveInY = bh->co[2];
+ }
+ else {
+ pchan->bone->ease2 = max_ff(0.0f, -bh->co[1] * BBONE_SCALE_Y);
+ pchan->curveOutX = bh->co[0];
+ pchan->curveOutY = bh->co[2];
+ }
+
+}
+
+static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ if (ob != NULL) {
+ const bArmature *arm = ob->data;
+ if (arm->drawtype == ARM_B_BONE) {
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ if (pchan && pchan->bone->segments > 1) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
+ (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
+ {
+ /* pass */
+ }
+ else {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
+
+ const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
+
+ struct BoneSplineWidgetGroup *bspline_group = MEM_callocN(sizeof(struct BoneSplineWidgetGroup), __func__);
+ gzgroup->customdata = bspline_group;
+
+ /* Handles */
+ for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
+ wmGizmo *gz;
+ gz = bspline_group->handles[i].gizmo = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D);
+ RNA_enum_set(gz->ptr, "draw_options",
+ ED_GIZMO_MOVE_DRAW_FLAG_FILL | ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW);
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true);
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+
+ gz->scale_basis = 0.06f;
+
+ if (i == 0) {
+ copy_v3_v3(gz->matrix_basis[3], pchan->loc);
+ }
+ }
+}
+
+static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+
+ if (!gzgroup->customdata)
+ return;
+
+ struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata;
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
+
+ /* Handles */
+ for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
+ wmGizmo *gz = bspline_group->handles[i].gizmo;
+ bspline_group->handles[i].pchan = pchan;
+ bspline_group->handles[i].index = i;
+
+ float mat[4][4];
+ mul_m4_m4m4(mat, ob->obmat, (i == 0) ? pchan->disp_mat : pchan->disp_tail_mat);
+ copy_m4_m4(gz->matrix_space, mat);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ WM_gizmo_target_property_def_func(
+ gz, "offset",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_bbone_offset_get,
+ .value_set_fn = gizmo_bbone_offset_set,
+ .range_get_fn = NULL,
+ .user_data = &bspline_group->handles[i],
+ });
+ }
+}
+
+void VIEW3D_GGT_armature_spline(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Armature Spline Widgets";
+ gzgt->idname = "VIEW3D_GGT_armature_spline";
+
+ gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_3D);
+
+ gzgt->poll = WIDGETGROUP_armature_spline_poll;
+ gzgt->setup = WIDGETGROUP_armature_spline_setup;
+ gzgt->refresh = WIDGETGROUP_armature_spline_refresh;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c
new file mode 100644
index 00000000000..0878bef98f2
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c
@@ -0,0 +1,473 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_gizmo_camera.c
+ * \ingroup spview3d
+ */
+
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_camera.h"
+#include "BKE_context.h"
+
+#include "DNA_object_types.h"
+#include "DNA_camera_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+
+#include "view3d_intern.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Camera Gizmos
+ * \{ */
+
+struct CameraWidgetGroup {
+ wmGizmo *dop_dist;
+ wmGizmo *focal_len;
+ wmGizmo *ortho_scale;
+};
+
+static bool WIDGETGROUP_camera_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
+ (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
+ {
+ return false;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->type == OB_CAMERA) {
+ Camera *camera = ob->data;
+ /* TODO: support overrides. */
+ if (camera->id.lib == NULL) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void WIDGETGROUP_camera_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ Object *ob = CTX_data_active_object(C);
+ float dir[3];
+
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
+
+ struct CameraWidgetGroup *cagzgroup = MEM_callocN(sizeof(struct CameraWidgetGroup), __func__);
+ gzgroup->customdata = cagzgroup;
+
+ negate_v3_v3(dir, ob->obmat[2]);
+
+ /* dof distance */
+ {
+ wmGizmo *gz;
+ gz = cagzgroup->dop_dist = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_CROSS);
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_HOVER, true);
+
+ UI_GetThemeColor3fv(TH_GIZMO_A, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+ }
+
+ /* focal length
+ * - logic/calculations are similar to BKE_camera_view_frame_ex, better keep in sync */
+ {
+ wmGizmo *gz;
+ gz = cagzgroup->focal_len = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ gz->flag |= WM_GIZMO_DRAW_NO_SCALE;
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_CONE);
+ RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED);
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+
+ gz = cagzgroup->ortho_scale = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ gz->flag |= WM_GIZMO_DRAW_NO_SCALE;
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_CONE);
+ RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED);
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+ }
+}
+
+static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ if (!gzgroup->customdata)
+ return;
+
+ struct CameraWidgetGroup *cagzgroup = gzgroup->customdata;
+ Object *ob = CTX_data_active_object(C);
+ Camera *ca = ob->data;
+ PointerRNA camera_ptr;
+ float dir[3];
+
+ const float ob_scale_inv[3] = {
+ 1.0f / len_v3(ob->obmat[0]),
+ 1.0f / len_v3(ob->obmat[1]),
+ 1.0f / len_v3(ob->obmat[2]),
+ };
+ const float ob_scale_uniform_inv = (ob_scale_inv[0] + ob_scale_inv[1] + ob_scale_inv[2]) / 3.0f;
+
+ RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr);
+
+ negate_v3_v3(dir, ob->obmat[2]);
+
+ if (ca->flag & CAM_SHOWLIMITS) {
+ WM_gizmo_set_matrix_location(cagzgroup->dop_dist, ob->obmat[3]);
+ WM_gizmo_set_matrix_rotation_from_yz_axis(cagzgroup->dop_dist, ob->obmat[1], dir);
+ WM_gizmo_set_scale(cagzgroup->dop_dist, ca->drawsize);
+ WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, false);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ WM_gizmo_target_property_def_rna(cagzgroup->dop_dist, "offset", &camera_ptr, "dof_distance", -1);
+ }
+ else {
+ WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, true);
+ }
+
+ /* TODO - make focal length/ortho ob_scale_inv widget optional */
+ const Scene *scene = CTX_data_scene(C);
+ const float aspx = (float)scene->r.xsch * scene->r.xasp;
+ const float aspy = (float)scene->r.ysch * scene->r.yasp;
+ const bool is_ortho = (ca->type == CAM_ORTHO);
+ const int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, aspx, aspy);
+ wmGizmo *widget = is_ortho ? cagzgroup->ortho_scale : cagzgroup->focal_len;
+ float scale_matrix;
+ if (true) {
+ float offset[3];
+ float aspect[2];
+
+ WM_gizmo_set_flag(widget, WM_GIZMO_HIDDEN, false);
+ WM_gizmo_set_flag(is_ortho ? cagzgroup->focal_len : cagzgroup->ortho_scale, WM_GIZMO_HIDDEN, true);
+
+
+ /* account for lens shifting */
+ offset[0] = ((ob->size[0] > 0.0f) ? -2.0f : 2.0f) * ca->shiftx;
+ offset[1] = 2.0f * ca->shifty;
+ offset[2] = 0.0f;
+
+ /* get aspect */
+ aspect[0] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? 1.0f : aspx / aspy;
+ aspect[1] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? aspy / aspx : 1.0f;
+
+ unit_m4(widget->matrix_basis);
+ WM_gizmo_set_matrix_location(widget, ob->obmat[3]);
+ WM_gizmo_set_matrix_rotation_from_yz_axis(widget, ob->obmat[1], dir);
+
+ if (is_ortho) {
+ scale_matrix = ca->ortho_scale * 0.5f;
+ }
+ else {
+ scale_matrix = ca->drawsize / ob_scale_uniform_inv;
+ }
+ mul_v3_fl(widget->matrix_basis[0], scale_matrix);
+ mul_v3_fl(widget->matrix_basis[1], scale_matrix);
+
+ RNA_float_set_array(widget->ptr, "aspect", aspect);
+
+ WM_gizmo_set_matrix_offset_location(widget, offset);
+ }
+
+ /* define & update properties */
+ {
+ const char *propname = is_ortho ? "ortho_scale" : "lens";
+ PropertyRNA *prop = RNA_struct_find_property(&camera_ptr, propname);
+ const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(widget->type, "offset");
+
+ WM_gizmo_target_property_clear_rna_ptr(widget, gz_prop_type);
+
+ float min, max, range;
+ float step, precision;
+
+ /* get property range */
+ RNA_property_float_ui_range(&camera_ptr, prop, &min, &max, &step, &precision);
+ range = max - min;
+
+ ED_gizmo_arrow3d_set_range_fac(
+ widget, is_ortho ?
+ (ca->drawsize * range) :
+ (scale_matrix * range /
+ /* Half sensor, intentionally use sensor from camera and not calculated above. */
+ (0.5f * ((ca->sensor_fit == CAMERA_SENSOR_FIT_HOR) ? ca->sensor_x : ca->sensor_x))));
+
+ WM_gizmo_target_property_def_rna_ptr(widget, gz_prop_type, &camera_ptr, prop, -1);
+ }
+
+}
+
+static void WIDGETGROUP_camera_message_subscribe(
+ const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ Camera *ca = ob->data;
+
+ wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
+ .owner = ar,
+ .user_data = gzgroup->parent_gzmap,
+ .notify = WM_gizmo_do_msg_notify_tag_refresh,
+ };
+
+ {
+ extern PropertyRNA rna_Camera_dof_distance;
+ extern PropertyRNA rna_Camera_display_size;
+ extern PropertyRNA rna_Camera_ortho_scale;
+ extern PropertyRNA rna_Camera_sensor_fit;
+ extern PropertyRNA rna_Camera_sensor_width;
+ extern PropertyRNA rna_Camera_shift_x;
+ extern PropertyRNA rna_Camera_shift_y;
+ extern PropertyRNA rna_Camera_type;
+ extern PropertyRNA rna_Camera_lens;
+ const PropertyRNA *props[] = {
+ &rna_Camera_dof_distance,
+ &rna_Camera_display_size,
+ &rna_Camera_ortho_scale,
+ &rna_Camera_sensor_fit,
+ &rna_Camera_sensor_width,
+ &rna_Camera_shift_x,
+ &rna_Camera_shift_y,
+ &rna_Camera_type,
+ &rna_Camera_lens,
+ };
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&ca->id, &idptr);
+
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
+ }
+ }
+
+ /* Subscribe to render settings */
+ {
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_gz_tag_refresh);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_gz_tag_refresh);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_gz_tag_refresh);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_gz_tag_refresh);
+ }
+}
+
+void VIEW3D_GGT_camera(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Camera Widgets";
+ gzgt->idname = "VIEW3D_GGT_camera";
+
+ gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_3D |
+ WM_GIZMOGROUPTYPE_DEPTH_3D);
+
+ gzgt->poll = WIDGETGROUP_camera_poll;
+ gzgt->setup = WIDGETGROUP_camera_setup;
+ gzgt->refresh = WIDGETGROUP_camera_refresh;
+ gzgt->message_subscribe = WIDGETGROUP_camera_message_subscribe;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name CameraView Gizmos
+ * \{ */
+
+struct CameraViewWidgetGroup {
+ wmGizmo *border;
+
+ struct {
+ rctf *edit_border;
+ rctf view_border;
+ } state;
+};
+
+/* scale callbacks */
+static void gizmo_render_border_prop_matrix_get(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ float (*matrix)[4] = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ struct CameraViewWidgetGroup *viewgroup = gz_prop->custom_func.user_data;
+ const rctf *border = viewgroup->state.edit_border;
+
+ unit_m4(matrix);
+ matrix[0][0] = BLI_rctf_size_x(border);
+ matrix[1][1] = BLI_rctf_size_y(border);
+ matrix[3][0] = BLI_rctf_cent_x(border);
+ matrix[3][1] = BLI_rctf_cent_y(border);
+}
+
+static void gizmo_render_border_prop_matrix_set(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ const float (*matrix)[4] = value_p;
+ struct CameraViewWidgetGroup *viewgroup = gz_prop->custom_func.user_data;
+ rctf *border = viewgroup->state.edit_border;
+ BLI_assert(gz_prop->type->array_length == 16);
+
+ BLI_rctf_resize(border, len_v3(matrix[0]), len_v3(matrix[1]));
+ BLI_rctf_recenter(border, matrix[3][0], matrix[3][1]);
+ BLI_rctf_isect(&(rctf){.xmin = 0, .ymin = 0, .xmax = 1, .ymax = 1}, border, border);
+}
+
+static bool WIDGETGROUP_camera_view_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ Scene *scene = CTX_data_scene(C);
+
+ /* This is just so the border isn't always in the way,
+ * stealing mouse clicks from regular usage.
+ * We could change the rules for when to show. */
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ if (scene->camera != OBACT(view_layer)) {
+ return false;
+ }
+ }
+
+ View3D *v3d = CTX_wm_view3d(C);
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
+ (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
+ {
+ return false;
+ }
+
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ if (scene->r.mode & R_BORDER) {
+ /* TODO: support overrides. */
+ if (scene->id.lib == NULL) {
+ return true;
+ }
+ }
+ }
+ else if (v3d->flag2 & V3D_RENDER_BORDER) {
+ return true;
+ }
+ return false;
+}
+
+static void WIDGETGROUP_camera_view_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct CameraViewWidgetGroup *viewgroup = MEM_mallocN(sizeof(struct CameraViewWidgetGroup), __func__);
+
+ viewgroup->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
+
+ RNA_enum_set(viewgroup->border->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE);
+ /* Box style is more subtle in this case. */
+ RNA_enum_set(viewgroup->border->ptr, "draw_style", ED_GIZMO_CAGE2D_STYLE_BOX);
+
+
+ gzgroup->customdata = viewgroup;
+}
+
+static void WIDGETGROUP_camera_view_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct CameraViewWidgetGroup *viewgroup = gzgroup->customdata;
+
+ ARegion *ar = CTX_wm_region(C);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewgroup->state.view_border, false);
+ }
+ else {
+ viewgroup->state.view_border = (rctf){.xmin = 0, .ymin = 0, .xmax = ar->winx, .ymax = ar->winy};
+ }
+
+ wmGizmo *gz = viewgroup->border;
+ unit_m4(gz->matrix_space);
+ mul_v3_fl(gz->matrix_space[0], BLI_rctf_size_x(&viewgroup->state.view_border));
+ mul_v3_fl(gz->matrix_space[1], BLI_rctf_size_y(&viewgroup->state.view_border));
+ gz->matrix_space[3][0] = viewgroup->state.view_border.xmin;
+ gz->matrix_space[3][1] = viewgroup->state.view_border.ymin;
+}
+
+static void WIDGETGROUP_camera_view_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct CameraViewWidgetGroup *viewgroup = gzgroup->customdata;
+
+ View3D *v3d = CTX_wm_view3d(C);
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ Scene *scene = CTX_data_scene(C);
+
+ {
+ wmGizmo *gz = viewgroup->border;
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+
+ RNA_enum_set(viewgroup->border->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE);
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ viewgroup->state.edit_border = &scene->r.border;
+ }
+ else {
+ viewgroup->state.edit_border = &v3d->render_border;
+ }
+
+ WM_gizmo_target_property_def_func(
+ gz, "matrix",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_render_border_prop_matrix_get,
+ .value_set_fn = gizmo_render_border_prop_matrix_set,
+ .range_get_fn = NULL,
+ .user_data = viewgroup,
+ });
+ }
+
+}
+
+void VIEW3D_GGT_camera_view(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Camera View Widgets";
+ gzgt->idname = "VIEW3D_GGT_camera_view";
+
+ gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_SCALE);
+
+ gzgt->poll = WIDGETGROUP_camera_view_poll;
+ gzgt->setup = WIDGETGROUP_camera_view_setup;
+ gzgt->draw_prepare = WIDGETGROUP_camera_view_draw_prepare;
+ gzgt->refresh = WIDGETGROUP_camera_view_refresh;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c
new file mode 100644
index 00000000000..9ce0041c76c
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c
@@ -0,0 +1,210 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_gizmo_empty.c
+ * \ingroup spview3d
+ */
+
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_object.h"
+#include "BKE_image.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Empty Image Gizmos
+ * \{ */
+
+struct EmptyImageWidgetGroup {
+ wmGizmo *gizmo;
+ struct {
+ Object *ob;
+ float dims[2];
+ } state;
+};
+
+/* translate callbacks */
+static void gizmo_empty_image_prop_matrix_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ float (*matrix)[4] = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ struct EmptyImageWidgetGroup *igzgroup = gz_prop->custom_func.user_data;
+ const Object *ob = igzgroup->state.ob;
+
+ unit_m4(matrix);
+ matrix[0][0] = ob->empty_drawsize;
+ matrix[1][1] = ob->empty_drawsize;
+
+ float dims[2] = {0.0f, 0.0f};
+ RNA_float_get_array(gz->ptr, "dimensions", dims);
+ dims[0] *= ob->empty_drawsize;
+ dims[1] *= ob->empty_drawsize;
+
+ matrix[3][0] = (ob->ima_ofs[0] * dims[0]) + (0.5f * dims[0]);
+ matrix[3][1] = (ob->ima_ofs[1] * dims[1]) + (0.5f * dims[1]);
+}
+
+static void gizmo_empty_image_prop_matrix_set(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ const float (*matrix)[4] = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ struct EmptyImageWidgetGroup *igzgroup = gz_prop->custom_func.user_data;
+ Object *ob = igzgroup->state.ob;
+
+ ob->empty_drawsize = matrix[0][0];
+ DEG_id_tag_update(&ob->id, DEG_TAG_TRANSFORM);
+
+ float dims[2];
+ RNA_float_get_array(gz->ptr, "dimensions", dims);
+ dims[0] *= ob->empty_drawsize;
+ dims[1] *= ob->empty_drawsize;
+
+ ob->ima_ofs[0] = (matrix[3][0] - (0.5f * dims[0])) / dims[0];
+ ob->ima_ofs[1] = (matrix[3][1] - (0.5f * dims[1])) / dims[1];
+}
+
+static bool WIDGETGROUP_empty_image_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
+ (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
+ {
+ return false;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob && ob->type == OB_EMPTY) {
+ if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
+ return BKE_image_empty_visible_in_view3d(ob, rv3d);
+ }
+ }
+ return false;
+}
+
+static void WIDGETGROUP_empty_image_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct EmptyImageWidgetGroup *igzgroup = MEM_mallocN(sizeof(struct EmptyImageWidgetGroup), __func__);
+ igzgroup->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
+ wmGizmo *gz = igzgroup->gizmo;
+ RNA_enum_set(gz->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE);
+
+ gzgroup->customdata = igzgroup;
+
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_HOVER, true);
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+}
+
+static void WIDGETGROUP_empty_image_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct EmptyImageWidgetGroup *igzgroup = gzgroup->customdata;
+ Object *ob = CTX_data_active_object(C);
+ wmGizmo *gz = igzgroup->gizmo;
+
+ copy_m4_m4(gz->matrix_basis, ob->obmat);
+
+ RNA_enum_set(gz->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE |
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE |
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM);
+
+ igzgroup->state.ob = ob;
+
+ /* Use dimensions for aspect. */
+ if (ob->data != NULL) {
+ const Image *image = ob->data;
+ ImageUser iuser = *ob->iuser;
+ float size[2];
+ BKE_image_get_size_fl(ob->data, &iuser, size);
+
+ /* Get the image aspect even if the buffer is invalid */
+ if (image->aspx > image->aspy) {
+ size[1] *= image->aspy / image->aspx;
+ }
+ else if (image->aspx < image->aspy) {
+ size[0] *= image->aspx / image->aspy;
+ }
+
+ const float dims_max = max_ff(size[0], size[1]);
+ igzgroup->state.dims[0] = size[0] / dims_max;
+ igzgroup->state.dims[1] = size[1] / dims_max;
+ }
+ else {
+ copy_v2_fl(igzgroup->state.dims, 1.0f);
+ }
+ RNA_float_set_array(gz->ptr, "dimensions", igzgroup->state.dims);
+
+ WM_gizmo_target_property_def_func(
+ gz, "matrix",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_empty_image_prop_matrix_get,
+ .value_set_fn = gizmo_empty_image_prop_matrix_set,
+ .range_get_fn = NULL,
+ .user_data = igzgroup,
+ });
+}
+
+void VIEW3D_GGT_empty_image(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Area Light Widgets";
+ gzgt->idname = "VIEW3D_GGT_empty_image";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_3D |
+ WM_GIZMOGROUPTYPE_DEPTH_3D);
+
+ gzgt->poll = WIDGETGROUP_empty_image_poll;
+ gzgt->setup = WIDGETGROUP_empty_image_setup;
+ gzgt->refresh = WIDGETGROUP_empty_image_refresh;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
new file mode 100644
index 00000000000..e2a8d2802e7
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
@@ -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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_gizmo_forcefield.c
+ * \ingroup spview3d
+ */
+
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_object.h"
+
+#include "DNA_object_types.h"
+#include "DNA_object_force_types.h"
+
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Force Field Gizmos
+ * \{ */
+
+static bool WIDGETGROUP_forcefield_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
+ (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
+ {
+ return false;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+
+ return (ob && ob->pd && ob->pd->forcefield);
+}
+
+static void WIDGETGROUP_forcefield_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ /* only wind effector for now */
+ wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
+ gzgroup->customdata = wwrapper;
+
+ wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_arrow_3d", gzgroup, NULL);
+ wmGizmo *gz = wwrapper->gizmo;
+ RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED);
+ ED_gizmo_arrow3d_set_ui_range(gz, -200.0f, 200.0f);
+ ED_gizmo_arrow3d_set_range_fac(gz, 6.0f);
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+}
+
+static void WIDGETGROUP_forcefield_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = gzgroup->customdata;
+ wmGizmo *gz = wwrapper->gizmo;
+ Object *ob = CTX_data_active_object(C);
+ PartDeflect *pd = ob->pd;
+
+ if (pd->forcefield == PFIELD_WIND) {
+ const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f;
+ const float ofs[3] = {0.0f, -size, 0.0f};
+ PointerRNA field_ptr;
+
+ RNA_pointer_create(&ob->id, &RNA_FieldSettings, pd, &field_ptr);
+ WM_gizmo_set_matrix_location(gz, ob->obmat[3]);
+ WM_gizmo_set_matrix_rotation_from_z_axis(gz, ob->obmat[2]);
+ WM_gizmo_set_matrix_offset_location(gz, ofs);
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+ WM_gizmo_target_property_def_rna(gz, "offset", &field_ptr, "strength", -1);
+ }
+ else {
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
+}
+
+void VIEW3D_GGT_force_field(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Force Field Widgets";
+ gzgt->idname = "VIEW3D_GGT_force_field";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_3D |
+ WM_GIZMOGROUPTYPE_SCALE |
+ WM_GIZMOGROUPTYPE_DEPTH_3D);
+
+ gzgt->poll = WIDGETGROUP_forcefield_poll;
+ gzgt->setup = WIDGETGROUP_forcefield_setup;
+ gzgt->refresh = WIDGETGROUP_forcefield_refresh;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_lamp.c b/source/blender/editors/space_view3d/view3d_gizmo_lamp.c
new file mode 100644
index 00000000000..3eaddce582b
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_lamp.c
@@ -0,0 +1,307 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_gizmo_lamp.c
+ * \ingroup spview3d
+ */
+
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_object.h"
+
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Spot Lamp Gizmos
+ * \{ */
+
+static bool WIDGETGROUP_lamp_spot_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
+ (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
+ {
+ return false;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob && ob->type == OB_LAMP) {
+ Lamp *la = ob->data;
+ return (la->type == LA_SPOT);
+ }
+ return false;
+}
+
+static void WIDGETGROUP_lamp_spot_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
+
+ wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_arrow_3d", gzgroup, NULL);
+ wmGizmo *gz = wwrapper->gizmo;
+ RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_INVERTED);
+
+ gzgroup->customdata = wwrapper;
+
+ ED_gizmo_arrow3d_set_range_fac(gz, 4.0f);
+
+ UI_GetThemeColor3fv(TH_GIZMO_SECONDARY, gz->color);
+}
+
+static void WIDGETGROUP_lamp_spot_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = gzgroup->customdata;
+ wmGizmo *gz = wwrapper->gizmo;
+ Object *ob = CTX_data_active_object(C);
+ Lamp *la = ob->data;
+ float dir[3];
+
+ negate_v3_v3(dir, ob->obmat[2]);
+
+ WM_gizmo_set_matrix_rotation_from_z_axis(gz, dir);
+ WM_gizmo_set_matrix_location(gz, ob->obmat[3]);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ PointerRNA lamp_ptr;
+ const char *propname = "spot_size";
+ RNA_pointer_create(&la->id, &RNA_Light, la, &lamp_ptr);
+ WM_gizmo_target_property_def_rna(gz, "offset", &lamp_ptr, propname, -1);
+}
+
+void VIEW3D_GGT_lamp_spot(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Spot Light Widgets";
+ gzgt->idname = "VIEW3D_GGT_lamp_spot";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_3D |
+ WM_GIZMOGROUPTYPE_DEPTH_3D);
+
+ gzgt->poll = WIDGETGROUP_lamp_spot_poll;
+ gzgt->setup = WIDGETGROUP_lamp_spot_setup;
+ gzgt->refresh = WIDGETGROUP_lamp_spot_refresh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Area Lamp Gizmos
+ * \{ */
+
+/* scale callbacks */
+static void gizmo_area_lamp_prop_matrix_get(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ BLI_assert(gz_prop->type->array_length == 16);
+ float (*matrix)[4] = value_p;
+ const Lamp *la = gz_prop->custom_func.user_data;
+
+ matrix[0][0] = la->area_size;
+ matrix[1][1] = ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE) ? la->area_sizey : la->area_size;
+}
+
+static void gizmo_area_lamp_prop_matrix_set(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ const float (*matrix)[4] = value_p;
+ BLI_assert(gz_prop->type->array_length == 16);
+ Lamp *la = gz_prop->custom_func.user_data;
+
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
+ la->area_size = len_v3(matrix[0]);
+ la->area_sizey = len_v3(matrix[1]);
+ }
+ else {
+ la->area_size = len_v3(matrix[0]);
+ }
+}
+
+static bool WIDGETGROUP_lamp_area_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->type == OB_LAMP) {
+ Lamp *la = ob->data;
+ return (la->type == LA_AREA);
+ }
+ return false;
+}
+
+static void WIDGETGROUP_lamp_area_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
+ wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL);
+ wmGizmo *gz = wwrapper->gizmo;
+ RNA_enum_set(gz->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE);
+
+ gzgroup->customdata = wwrapper;
+
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_HOVER, true);
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+}
+
+static void WIDGETGROUP_lamp_area_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = gzgroup->customdata;
+ Object *ob = CTX_data_active_object(C);
+ Lamp *la = ob->data;
+ wmGizmo *gz = wwrapper->gizmo;
+
+ copy_m4_m4(gz->matrix_basis, ob->obmat);
+
+ int flag = ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE;
+ if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_DISK)) {
+ flag |= ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM;
+ }
+ RNA_enum_set(gz->ptr, "transform", flag);
+
+ /* need to set property here for undo. TODO would prefer to do this in _init */
+ WM_gizmo_target_property_def_func(
+ gz, "matrix",
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = gizmo_area_lamp_prop_matrix_get,
+ .value_set_fn = gizmo_area_lamp_prop_matrix_set,
+ .range_get_fn = NULL,
+ .user_data = la,
+ });
+}
+
+void VIEW3D_GGT_lamp_area(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Area Light Widgets";
+ gzgt->idname = "VIEW3D_GGT_lamp_area";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_3D |
+ WM_GIZMOGROUPTYPE_DEPTH_3D);
+
+ gzgt->poll = WIDGETGROUP_lamp_area_poll;
+ gzgt->setup = WIDGETGROUP_lamp_area_setup;
+ gzgt->refresh = WIDGETGROUP_lamp_area_refresh;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Lamp Target Gizmo
+ * \{ */
+
+static bool WIDGETGROUP_lamp_target_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob != NULL) {
+ if (ob->type == OB_LAMP) {
+ Lamp *la = ob->data;
+ return (ELEM(la->type, LA_SUN, LA_SPOT, LA_AREA));
+ }
+#if 0
+ else if (ob->type == OB_CAMERA) {
+ return true;
+ }
+#endif
+ }
+ return false;
+}
+
+static void WIDGETGROUP_lamp_target_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__);
+ wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, NULL);
+ wmGizmo *gz = wwrapper->gizmo;
+
+ gzgroup->customdata = wwrapper;
+
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+
+ gz->scale_basis = 0.06f;
+
+ wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_transform_axis_target", true);
+
+ RNA_enum_set(gz->ptr, "draw_options",
+ ED_GIZMO_MOVE_DRAW_FLAG_FILL | ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW);
+
+ WM_gizmo_operator_set(gz, 0, ot, NULL);
+}
+
+static void WIDGETGROUP_lamp_target_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmGizmoWrapper *wwrapper = gzgroup->customdata;
+ Object *ob = CTX_data_active_object(C);
+ wmGizmo *gz = wwrapper->gizmo;
+
+ copy_m4_m4(gz->matrix_basis, ob->obmat);
+ unit_m4(gz->matrix_offset);
+ gz->matrix_offset[3][2] = -2.4f / gz->scale_basis;
+ WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true);
+}
+
+void VIEW3D_GGT_lamp_target(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Target Light Widgets";
+ gzgt->idname = "VIEW3D_GGT_lamp_target";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_3D);
+
+ gzgt->poll = WIDGETGROUP_lamp_target_poll;
+ gzgt->setup = WIDGETGROUP_lamp_target_setup;
+ gzgt->draw_prepare = WIDGETGROUP_lamp_target_draw_prepare;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
new file mode 100644
index 00000000000..d45da76a477
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
@@ -0,0 +1,325 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_gizmo_navigate.c
+ * \ingroup spview3d
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_object.h"
+
+#include "DNA_object_types.h"
+
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name View3D Navigation Gizmo Group
+ * \{ */
+
+/* Offset from screen edge. */
+#define GIZMO_OFFSET_FAC 1.2f
+/* Size of main icon. */
+#define GIZMO_SIZE 80
+/* Factor for size of smaller button. */
+#define GIZMO_MINI_FAC 0.35f
+/* How much mini buttons offset from the primary. */
+#define GIZMO_MINI_OFFSET_FAC 0.38f
+
+
+enum {
+ MPR_MOVE = 0,
+ MPR_ROTATE = 1,
+ MPR_ZOOM = 2,
+
+ /* just buttons */
+ /* overlaps MPR_ORTHO (switch between) */
+ MPR_PERSP = 3,
+ MPR_ORTHO = 4,
+ MPR_CAMERA = 5,
+
+ MPR_TOTAL = 6,
+};
+
+struct NavigateGizmoInfo {
+ const char *opname;
+ const char *gizmo;
+ uint icon;
+};
+
+static struct NavigateGizmoInfo g_navigate_params[MPR_TOTAL] = {
+ {
+ .opname = "VIEW3D_OT_move",
+ .gizmo = "GIZMO_GT_button_2d",
+ ICON_VIEW_PAN,
+ }, {
+ .opname = "VIEW3D_OT_rotate",
+ .gizmo = "VIEW3D_GT_navigate_rotate",
+ 0,
+ }, {
+ .opname = "VIEW3D_OT_zoom",
+ .gizmo = "GIZMO_GT_button_2d",
+ ICON_VIEW_ZOOM,
+ }, {
+ .opname = "VIEW3D_OT_view_persportho",
+ .gizmo = "GIZMO_GT_button_2d",
+ ICON_VIEW_PERSPECTIVE,
+ }, {
+ .opname = "VIEW3D_OT_view_persportho",
+ .gizmo = "GIZMO_GT_button_2d",
+ ICON_VIEW_ORTHO,
+ }, {
+ .opname = "VIEW3D_OT_view_camera",
+ .gizmo = "GIZMO_GT_button_2d",
+ ICON_VIEW_CAMERA,
+ },
+};
+
+struct NavigateWidgetGroup {
+ wmGizmo *gz_array[MPR_TOTAL];
+ /* Store the view state to check for changes. */
+ struct {
+ rcti rect_visible;
+ struct {
+ char is_persp;
+ char is_camera;
+ char viewlock;
+ } rv3d;
+ } state;
+ int region_size[2];
+};
+
+static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (((U.uiflag & USER_SHOW_GIZMO_AXIS) == 0) ||
+ (v3d->flag2 & V3D_RENDER_OVERRIDE) ||
+ (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_NAVIGATE)))
+ {
+ return false;
+ }
+ return true;
+
+}
+
+static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct NavigateWidgetGroup *navgroup = MEM_callocN(sizeof(struct NavigateWidgetGroup), __func__);
+
+ navgroup->region_size[0] = -1;
+ navgroup->region_size[1] = -1;
+
+ wmOperatorType *ot_view_axis = WM_operatortype_find("VIEW3D_OT_view_axis", true);
+ wmOperatorType *ot_view_camera = WM_operatortype_find("VIEW3D_OT_view_camera", true);
+
+ for (int i = 0; i < MPR_TOTAL; i++) {
+ const struct NavigateGizmoInfo *info = &g_navigate_params[i];
+ navgroup->gz_array[i] = WM_gizmo_new(info->gizmo, gzgroup, NULL);
+ wmGizmo *gz = navgroup->gz_array[i];
+ gz->flag |= WM_GIZMO_MOVE_CURSOR | WM_GIZMO_DRAW_MODAL;
+
+ if (i == MPR_ROTATE) {
+ gz->color[3] = 0.0f;
+ gz->color_hi[3] = 0.1f;
+ }
+ else {
+ UI_GetThemeColorShade3fv(TH_HEADER, -40, gz->color);
+ UI_GetThemeColorShade3fv(TH_HEADER, 160, gz->color_hi);
+ gz->color[3] = 0.4f;
+ gz->color_hi[3] = 0.2f;
+ }
+
+
+ /* may be overwritten later */
+ gz->scale_basis = (GIZMO_SIZE * GIZMO_MINI_FAC) / 2;
+ if (info->icon != 0) {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
+ RNA_property_enum_set(gz->ptr, prop, info->icon);
+ RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_OUTLINE | ED_GIZMO_BUTTON_SHOW_BACKDROP);
+ }
+
+ wmOperatorType *ot = WM_operatortype_find(info->opname, true);
+ WM_gizmo_operator_set(gz, 0, ot, NULL);
+ }
+
+ {
+ wmGizmo *gz = navgroup->gz_array[MPR_CAMERA];
+ WM_gizmo_operator_set(gz, 0, ot_view_camera, NULL);
+ }
+
+ /* Click only buttons (not modal). */
+ {
+ int gz_ids[] = {MPR_PERSP, MPR_ORTHO, MPR_CAMERA};
+ for (int i = 0; i < ARRAY_SIZE(gz_ids); i++) {
+ wmGizmo *gz = navgroup->gz_array[gz_ids[i]];
+ RNA_boolean_set(gz->ptr, "show_drag", false);
+ }
+ }
+
+ /* Modal operators, don't use initial mouse location since we're clicking on a button. */
+ {
+ int gz_ids[] = {MPR_MOVE, MPR_ROTATE, MPR_ZOOM};
+ for (int i = 0; i < ARRAY_SIZE(gz_ids); i++) {
+ wmGizmo *gz = navgroup->gz_array[gz_ids[i]];
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
+ RNA_boolean_set(&gzop->ptr, "use_mouse_init", false);
+ }
+ }
+
+ {
+ wmGizmo *gz = navgroup->gz_array[MPR_ROTATE];
+ gz->scale_basis = GIZMO_SIZE / 2;
+ char mapping[6] = {
+ RV3D_VIEW_LEFT,
+ RV3D_VIEW_RIGHT,
+ RV3D_VIEW_FRONT,
+ RV3D_VIEW_BACK,
+ RV3D_VIEW_BOTTOM,
+ RV3D_VIEW_TOP,
+ };
+
+ for (int part_index = 0; part_index < 6; part_index += 1) {
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, part_index + 1, ot_view_axis, NULL);
+ RNA_enum_set(ptr, "type", mapping[part_index]);
+ }
+
+ /* When dragging an axis, use this instead. */
+ gz->drag_part = 0;
+ }
+
+ gzgroup->customdata = navgroup;
+}
+
+static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct NavigateWidgetGroup *navgroup = gzgroup->customdata;
+ ARegion *ar = CTX_wm_region(C);
+ const RegionView3D *rv3d = ar->regiondata;
+
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(navgroup->gz_array[MPR_ROTATE]->matrix_offset[i], rv3d->viewmat[i]);
+ }
+
+ rcti rect_visible;
+ ED_region_visible_rect(ar, &rect_visible);
+
+ if ((navgroup->state.rect_visible.xmax == rect_visible.xmax) &&
+ (navgroup->state.rect_visible.ymax == rect_visible.ymax) &&
+ (navgroup->state.rv3d.is_persp == rv3d->is_persp) &&
+ (navgroup->state.rv3d.is_camera == (rv3d->persp == RV3D_CAMOB)) &&
+ (navgroup->state.rv3d.viewlock == rv3d->viewlock))
+ {
+ return;
+ }
+
+ navgroup->state.rect_visible = rect_visible;
+ navgroup->state.rv3d.is_persp = rv3d->is_persp;
+ navgroup->state.rv3d.is_camera = (rv3d->persp == RV3D_CAMOB);
+ navgroup->state.rv3d.viewlock = rv3d->viewlock;
+
+ const bool show_rotate = (
+ ((rv3d->viewlock & RV3D_LOCKED) == 0) &&
+ (navgroup->state.rv3d.is_camera == false));
+ const bool show_fixed_offset = navgroup->state.rv3d.is_camera;
+ const float icon_size = GIZMO_SIZE;
+ const float icon_offset = (icon_size * 0.52f) * GIZMO_OFFSET_FAC * UI_DPI_FAC;
+ const float icon_offset_mini = icon_size * GIZMO_MINI_OFFSET_FAC * UI_DPI_FAC;
+ const float co_rotate[2] = {
+ rect_visible.xmax - icon_offset,
+ rect_visible.ymax - icon_offset,
+ };
+ const float co[2] = {
+ rect_visible.xmax - ((show_rotate || show_fixed_offset) ? (icon_offset * 2.0f) : (icon_offset_mini * 0.75f)),
+ rect_visible.ymax - icon_offset_mini * 0.75f,
+ };
+
+ wmGizmo *gz;
+
+ for (uint i = 0; i < ARRAY_SIZE(navgroup->gz_array); i++) {
+ gz = navgroup->gz_array[i];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
+
+ /* RV3D_LOCKED or Camera: only show supported buttons. */
+ if (show_rotate) {
+ gz = navgroup->gz_array[MPR_ROTATE];
+ gz->matrix_basis[3][0] = co_rotate[0];
+ gz->matrix_basis[3][1] = co_rotate[1];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+ }
+
+ int icon_mini_slot = 0;
+
+ gz = navgroup->gz_array[MPR_ZOOM];
+ gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
+ gz->matrix_basis[3][1] = co[1];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+
+ gz = navgroup->gz_array[MPR_MOVE];
+ gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
+ gz->matrix_basis[3][1] = co[1];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+
+ if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
+ gz = navgroup->gz_array[MPR_CAMERA];
+ gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
+ gz->matrix_basis[3][1] = co[1];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+
+ if (navgroup->state.rv3d.is_camera == false) {
+ gz = navgroup->gz_array[rv3d->is_persp ? MPR_PERSP : MPR_ORTHO];
+ gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++);
+ gz->matrix_basis[3][1] = co[1];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+ }
+ }
+}
+
+void VIEW3D_GGT_navigate(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "View3D Navigate";
+ gzgt->idname = "VIEW3D_GGT_navigate";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT |
+ WM_GIZMOGROUPTYPE_SCALE |
+ WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL);
+
+ gzgt->poll = WIDGETGROUP_navigate_poll;
+ gzgt->setup = WIDGETGROUP_navigate_setup;
+ gzgt->draw_prepare = WIDGETGROUP_navigate_draw_prepare;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
new file mode 100644
index 00000000000..1358204a3a4
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -0,0 +1,535 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file view3d_gizmo_navigate_type.c
+ * \ingroup wm
+ *
+ * \name Custom Orientation/Navigation Gizmo for the 3D View
+ *
+ * \brief Simple gizmo to axis and translate.
+ *
+ * - scale_basis: used for the size.
+ * - matrix_basis: used for the location.
+ * - matrix_offset: used to store the orientation.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_sort_utils.h"
+
+#include "BKE_context.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+
+#include "view3d_intern.h"
+
+#define USE_AXIS_FONT
+#define USE_FADE_BACKGROUND
+
+#ifdef USE_AXIS_FONT
+# include "BLF_api.h"
+#endif
+
+#define DIAL_RESOLUTION 32
+
+/* Sizes of axis spheres containing XYZ characters. */
+#define AXIS_HANDLE_SIZE_FG 0.19f
+/* When pointing away from the view. */
+#define AXIS_HANDLE_SIZE_BG 0.15f
+/* How far axis handles are away from the center. */
+#define AXIS_HANDLE_OFFSET (1.0f - AXIS_HANDLE_SIZE_FG)
+
+struct AxisDrawInfo {
+ /* Matrix is needed for screen-aligned font drawing. */
+#ifdef USE_AXIS_FONT
+ float matrix_final[4][4];
+#endif
+#ifdef USE_FADE_BACKGROUND
+ float color_bg[3];
+#endif
+};
+
+#ifndef USE_AXIS_FONT
+/**
+ * \param viewmat_local_unit is typically the 'rv3d->viewmatob'
+ * copied into a 3x3 matrix and normalized.
+ */
+static void draw_xyz_wire(
+ uint pos_id, const float viewmat_local_unit[3][3], const float c[3], float size, int axis)
+{
+ int line_type;
+ float buffer[4][3];
+ int n = 0;
+
+ float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
+ float dim = size * 0.1f;
+ float dx[3], dy[3];
+
+ dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f;
+ dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f;
+
+ switch (axis) {
+ case 0: /* x axis */
+ line_type = GPU_PRIM_LINES;
+
+ /* bottom left to top right */
+ negate_v3_v3(v1, dx);
+ sub_v3_v3(v1, dy);
+ copy_v3_v3(v2, dx);
+ add_v3_v3(v2, dy);
+
+ copy_v3_v3(buffer[n++], v1);
+ copy_v3_v3(buffer[n++], v2);
+
+ /* top left to bottom right */
+ mul_v3_fl(dy, 2.0f);
+ add_v3_v3(v1, dy);
+ sub_v3_v3(v2, dy);
+
+ copy_v3_v3(buffer[n++], v1);
+ copy_v3_v3(buffer[n++], v2);
+
+ break;
+ case 1: /* y axis */
+ line_type = GPU_PRIM_LINES;
+
+ /* bottom left to top right */
+ mul_v3_fl(dx, 0.75f);
+ negate_v3_v3(v1, dx);
+ sub_v3_v3(v1, dy);
+ copy_v3_v3(v2, dx);
+ add_v3_v3(v2, dy);
+
+ copy_v3_v3(buffer[n++], v1);
+ copy_v3_v3(buffer[n++], v2);
+
+ /* top left to center */
+ mul_v3_fl(dy, 2.0f);
+ add_v3_v3(v1, dy);
+ zero_v3(v2);
+
+ copy_v3_v3(buffer[n++], v1);
+ copy_v3_v3(buffer[n++], v2);
+
+ break;
+ case 2: /* z axis */
+ line_type = GPU_PRIM_LINE_STRIP;
+
+ /* start at top left */
+ negate_v3_v3(v1, dx);
+ add_v3_v3(v1, dy);
+
+ copy_v3_v3(buffer[n++], v1);
+
+ mul_v3_fl(dx, 2.0f);
+ add_v3_v3(v1, dx);
+
+ copy_v3_v3(buffer[n++], v1);
+
+ mul_v3_fl(dy, 2.0f);
+ sub_v3_v3(v1, dx);
+ sub_v3_v3(v1, dy);
+
+ copy_v3_v3(buffer[n++], v1);
+
+ add_v3_v3(v1, dx);
+
+ copy_v3_v3(buffer[n++], v1);
+
+ break;
+ default:
+ BLI_assert(0);
+ return;
+ }
+
+ for (int i = 0; i < n; i++) {
+ mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
+ add_v3_v3(buffer[i], c);
+ }
+
+ immBegin(line_type, n);
+ for (int i = 0; i < n; i++) {
+ immVertex3fv(pos_id, buffer[i]);
+ }
+ immEnd();
+}
+#endif /* !USE_AXIS_FONT */
+
+/**
+ * \param draw_info: Extra data needed for drawing.
+ */
+static void axis_geom_draw(
+ const wmGizmo *gz, const float color[4], const bool select,
+ const struct AxisDrawInfo *draw_info)
+{
+ GPU_line_width(gz->line_width);
+
+ GPUVertFormat *format = immVertexFormat();
+ const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ struct {
+ float depth;
+ char index;
+ char axis;
+ bool is_pos;
+ } axis_order[6] = {
+ {-gz->matrix_offset[0][2], 0, 0, false},
+ {+gz->matrix_offset[0][2], 1, 0, true},
+ {-gz->matrix_offset[1][2], 2, 1, false},
+ {+gz->matrix_offset[1][2], 3, 1, true},
+ {-gz->matrix_offset[2][2], 4, 2, false},
+ {+gz->matrix_offset[2][2], 5, 2, true},
+ };
+
+ int axis_align = -1;
+ for (int axis = 0; axis < 3; axis++) {
+ if (len_squared_v2(gz->matrix_offset[axis]) < 1e-6f) {
+ axis_align = axis;
+ break;
+ }
+ }
+
+ /* Show backwards pointing highlight on-top (else we can't see it at all). */
+ if ((select == false) && (gz->highlight_part > 0) && (axis_align != -1)) {
+ if (axis_order[gz->highlight_part - 1].is_pos == false) {
+ axis_order[gz->highlight_part - 1].depth = FLT_MAX;
+ }
+ }
+
+ qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float);
+
+ static const float axis_highlight[4] = {1, 1, 1, 1};
+ static const float axis_black[4] = {0, 0, 0, 1};
+ static float axis_color[3][4];
+
+ const float axis_depth_bias = 0.01f;
+
+#ifdef USE_AXIS_FONT
+ struct {
+ float matrix[4][4];
+ int id;
+ } font;
+
+ if (select == false) {
+ font.id = blf_mono_font;
+ BLF_disable(font.id, BLF_ROTATION | BLF_SHADOW | BLF_MATRIX | BLF_ASPECT | BLF_WORD_WRAP);
+ BLF_color4fv(font.id, axis_black);
+ BLF_size(font.id, 11 * U.dpi_fac, 72);
+
+ /* Calculate the inverse of the (matrix_final * matrix_offset).
+ * This allows us to use the final location, while reversing the rotation so fonts
+ * show without any rotation. */
+ float m3[3][3];
+ float m3_offset[3][3];
+ copy_m3_m4(m3, draw_info->matrix_final);
+ copy_m3_m4(m3_offset, gz->matrix_offset);
+ mul_m3_m3m3(m3, m3, m3_offset);
+ invert_m3(m3);
+ copy_m4_m3(font.matrix, m3);
+ }
+#endif
+
+ GPU_matrix_push();
+ GPU_matrix_mul(gz->matrix_offset);
+
+ bool draw_center_done = false;
+
+ for (int axis_index = 0; axis_index < ARRAY_SIZE(axis_order); axis_index++) {
+ const int index = axis_order[axis_index].index;
+ const int axis = axis_order[axis_index].axis;
+ const bool is_pos = axis_order[axis_index].is_pos;
+ const bool is_highlight = index + 1 == gz->highlight_part;
+
+ /* Draw slightly before, so axis aligned arrows draw ontop. */
+ if ((draw_center_done == false) && (axis_order[axis_index].depth > -axis_depth_bias)) {
+
+ /* Circle defining active area (revert back to 2D space). */
+ if (color[3] != 0.0f) {
+ GPU_matrix_pop();
+ immUniformColor4fv(color);
+ imm_draw_circle_fill_3d(pos_id, 0, 0, 1.0f, DIAL_RESOLUTION);
+ GPU_matrix_push();
+ GPU_matrix_mul(gz->matrix_offset);
+ }
+ draw_center_done = true;
+ }
+ UI_GetThemeColor3fv(TH_AXIS_X + axis, axis_color[axis]);
+ axis_color[axis][3] = 1.0f;
+
+ const int index_z = axis;
+ const int index_y = (axis + 1) % 3;
+ const int index_x = (axis + 2) % 3;
+
+ bool ok = true;
+
+ /* Skip view align axis when selecting (allows to switch to opposite side). */
+ if (select && ((axis_align == axis) && (gz->matrix_offset[axis][2] > 0.0f) == is_pos)) {
+ ok = false;
+ }
+ if (ok) {
+ /* Check aligned, since the front axis won't display in this case,
+ * and we want to make sure all 3 axes have a character at all times. */
+ const bool show_axis_char = (is_pos || (axis == axis_align));
+ const float v[3] = {0, 0, AXIS_HANDLE_OFFSET * (is_pos ? 1 : -1)};
+ const float v_final[3] = {v[index_x], v[index_y], v[index_z]};
+ const float *color_current = is_highlight ? axis_highlight : axis_color[axis];
+ float color_current_fade[4];
+
+ /* Flip the faded state when axis aligned, since we're hiding the front-mode axis
+ * otherwise we see the color for the back-most axis, which is useful for
+ * click-to-rotate 180d but not useful to visualize.
+ *
+ * Use depth bias so axis-aligned views show the positive axis as being in-front.
+ * This is a detail so primary axes show as dominant.
+ */
+ const bool is_pos_color = (
+ axis_order[axis_index].depth > (axis_depth_bias * (is_pos ? -1 : 1)));
+
+
+ if (select == false) {
+#ifdef USE_FADE_BACKGROUND
+ interp_v3_v3v3(color_current_fade, draw_info->color_bg, color_current, is_highlight ? 1.0 : 0.5f);
+ color_current_fade[3] = color_current[3];
+#else
+ copy_v4_v4(color_current_fade, color_current);
+ color_current_fade[3] *= 0.2;
+#endif
+ }
+ else {
+ copy_v4_fl(color_current_fade, 1.0f);
+ }
+
+ /* Axis Line. */
+ if (is_pos) {
+ float v_start[3];
+ GPU_line_width(2.0f);
+ immUniformColor4fv(is_pos_color ? color_current : color_current_fade);
+ immBegin(GPU_PRIM_LINES, 2);
+ if (axis_align == -1) {
+ zero_v3(v_start);
+ }
+ else {
+ /* When axis aligned we don't draw the front most axis
+ * (allowing us to switch to the opposite side).
+ * In this case don't draw lines over axis pointing away from us
+ * because it obscures character and looks noisy.
+ */
+ mul_v3_v3fl(v_start, v_final, 0.3f);
+ }
+ immVertex3fv(pos_id, v_start);
+ immVertex3fv(pos_id, v_final);
+ immEnd();
+ }
+
+ /* Axis Ball. */
+ {
+ GPU_matrix_push();
+ GPU_matrix_translate_3fv(v_final);
+ GPU_matrix_scale_1f(is_pos ? AXIS_HANDLE_SIZE_FG : AXIS_HANDLE_SIZE_BG);
+
+ GPUBatch *sphere = GPU_batch_preset_sphere(0);
+ GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(sphere, "color", is_pos_color ? color_current : color_current_fade);
+ GPU_batch_draw(sphere);
+ GPU_matrix_pop();
+ }
+
+ /* Axis XYZ Character. */
+ if (show_axis_char && (select == false)) {
+#ifdef USE_AXIS_FONT
+ immUnbindProgram();
+
+ GPU_matrix_push();
+ GPU_matrix_translate_3fv(v_final);
+ GPU_matrix_mul(font.matrix);
+
+ const char axis_str[2] = {'X' + axis, 0};
+ float offset[2] = {0};
+ BLF_width_and_height(font.id, axis_str, 2, &offset[0], &offset[1]);
+ BLF_position(font.id, roundf(offset[0] * -0.5f), roundf(offset[1] * -0.5f), 0);
+ BLF_draw_ascii(font.id, axis_str, 2);
+ GPU_blend(true); /* XXX, blf disables */
+ GPU_matrix_pop();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+#else
+ GPU_line_width(1.0f);
+ float m3[3][3];
+ copy_m3_m4(m3, gz->matrix_offset);
+ immUniformColor4fv(axis_black);
+ draw_xyz_wire(pos_id, m3, v_final, 1.0, axis);
+#endif
+ }
+ }
+ }
+
+ GPU_matrix_pop();
+ immUnbindProgram();
+}
+
+static void axis3d_draw_intern(
+ const bContext *C, wmGizmo *gz,
+ const bool select, const bool highlight)
+{
+ const float *color = highlight ? gz->color_hi : gz->color;
+ float matrix_final[4][4];
+ float matrix_unit[4][4];
+
+ unit_m4(matrix_unit);
+
+ WM_gizmo_calc_matrix_final_params(
+ gz,
+ &((struct WM_GizmoMatrixParams) {
+ .matrix_offset = matrix_unit,
+ }), matrix_final);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(matrix_final);
+
+
+ struct AxisDrawInfo draw_info;
+#ifdef USE_AXIS_FONT
+ if (select == false) {
+ copy_m4_m4(draw_info.matrix_final, matrix_final);
+ }
+#endif
+
+#ifdef USE_FADE_BACKGROUND
+ if (select == false) {
+ ED_view3d_background_color_get(CTX_data_scene(C), CTX_wm_view3d(C), draw_info.color_bg);
+ }
+#else
+ UNUSED_VARS(C);
+#endif
+
+ GPU_blend(true);
+ axis_geom_draw(
+ gz, color, select,
+ &draw_info);
+ GPU_blend(false);
+ GPU_matrix_pop();
+}
+
+static void gizmo_axis_draw(const bContext *C, wmGizmo *gz)
+{
+ const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL;
+ const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
+
+ (void)is_modal;
+
+ GPU_blend(true);
+ axis3d_draw_intern(C, gz, false, is_highlight);
+ GPU_blend(false);
+}
+
+static int gizmo_axis_test_select(
+ bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
+{
+ float point_local[2] = {UNPACK2(mval)};
+ sub_v2_v2(point_local, gz->matrix_basis[3]);
+ mul_v2_fl(point_local, 1.0f / (gz->scale_basis * UI_DPI_FAC));
+
+ const float len_sq = len_squared_v2(point_local);
+ if (len_sq > 1.0) {
+ return -1;
+ }
+
+ int part_best = -1;
+ int part_index = 1;
+ /* Use 'SQUARE(HANDLE_SIZE)' if we want to be able to _not_ focus on one of the axis. */
+ float i_best_len_sq = FLT_MAX;
+ for (int i = 0; i < 3; i++) {
+ for (int is_pos = 0; is_pos < 2; is_pos++) {
+ float co[2] = {
+ gz->matrix_offset[i][0] * (is_pos ? 1 : -1),
+ gz->matrix_offset[i][1] * (is_pos ? 1 : -1),
+ };
+
+ bool ok = true;
+
+ /* Check if we're viewing on an axis, there is no point to clicking on the current axis so show the reverse. */
+ if (len_squared_v2(co) < 1e-6f && (gz->matrix_offset[i][2] > 0.0f) == is_pos) {
+ ok = false;
+ }
+
+ if (ok) {
+ const float len_axis_sq = len_squared_v2v2(co, point_local);
+ if (len_axis_sq < i_best_len_sq) {
+ part_best = part_index;
+ i_best_len_sq = len_axis_sq;
+ }
+ }
+ part_index += 1;
+ }
+ }
+
+ if (part_best != -1) {
+ return part_best;
+ }
+
+ /* The 'gz->scale_final' is already applied when projecting. */
+ if (len_sq < 1.0f) {
+ return 0;
+ }
+
+ return -1;
+}
+
+static int gizmo_axis_cursor_get(wmGizmo *gz)
+{
+ if (gz->highlight_part > 0) {
+ return CURSOR_EDIT;
+ }
+ return BC_NSEW_SCROLLCURSOR;
+}
+
+void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "VIEW3D_GT_navigate_rotate";
+
+ /* api callbacks */
+ gzt->draw = gizmo_axis_draw;
+ gzt->test_select = gizmo_axis_test_select;
+ gzt->cursor_get = gizmo_axis_cursor_get;
+
+ gzt->struct_size = sizeof(wmGizmo);
+}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect.c
new file mode 100644
index 00000000000..7b8e3a76c85
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect.c
@@ -0,0 +1,114 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_gizmo_preselect.c
+ * \ingroup spview3d
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "ED_gizmo_utils.h"
+#include "ED_screen.h"
+
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_toolsystem.h"
+
+#include "view3d_intern.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Pre-Select Element Gizmo
+ *
+ * \{ */
+
+struct GizmoGroupPreSelElem {
+ wmGizmo *gizmo;
+};
+
+static void WIDGETGROUP_mesh_preselect_elem_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ const wmGizmoType *gzt_presel = WM_gizmotype_find("GIZMO_GT_mesh_preselect_elem_3d", true);
+ struct GizmoGroupPreSelElem *ggd = MEM_callocN(sizeof(struct GizmoGroupPreSelElem), __func__);
+ gzgroup->customdata = ggd;
+
+ wmGizmo *gz = ggd->gizmo = WM_gizmo_new_ptr(gzt_presel, gzgroup, NULL);
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+}
+
+void VIEW3D_GGT_mesh_preselect_elem(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Mesh Preselect Element";
+ gzgt->idname = "VIEW3D_GGT_mesh_preselect_elem";
+
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
+ gzgt->setup = WIDGETGROUP_mesh_preselect_elem_setup;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Pre-Select Edge Ring Gizmo
+ *
+ * \{ */
+
+struct GizmoGroupPreSelEdgeRing {
+ wmGizmo *gizmo;
+};
+
+static void WIDGETGROUP_mesh_preselect_edgering_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ const wmGizmoType *gzt_presel = WM_gizmotype_find("GIZMO_GT_mesh_preselect_edgering_3d", true);
+ struct GizmoGroupPreSelEdgeRing *ggd = MEM_callocN(sizeof(struct GizmoGroupPreSelEdgeRing), __func__);
+ gzgroup->customdata = ggd;
+
+ wmGizmo *gz = ggd->gizmo = WM_gizmo_new_ptr(gzt_presel, gzgroup, NULL);
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
+ UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
+}
+
+void VIEW3D_GGT_mesh_preselect_edgering(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Mesh Preselect Edge Ring";
+ gzgt->idname = "VIEW3D_GGT_mesh_preselect_edgering";
+
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
+ gzgt->setup = WIDGETGROUP_mesh_preselect_edgering_setup;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
new file mode 100644
index 00000000000..be07928d5fc
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c
@@ -0,0 +1,429 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file view3d_gizmo_preselect_type.c
+ * \ingroup wm
+ *
+ * \name Preselection Gizmo
+ *
+ * Use for tools to hover over data before activation.
+ *
+ * \note This is a slight mis-use of gizmo's, since clicking performs no action.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+
+#include "BKE_context.h"
+#include "BKE_layer.h"
+#include "BKE_editmesh.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "bmesh.h"
+
+#include "ED_screen.h"
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_gizmo_library.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Element (Vert/Edge/Face) Pre-Select Gizmo API
+ *
+ * \{ */
+
+
+typedef struct MeshElemGizmo3D {
+ wmGizmo gizmo;
+ Base **bases;
+ uint bases_len;
+ int base_index;
+ int vert_index;
+ int edge_index;
+ int face_index;
+ struct EditMesh_PreSelElem *psel;
+} MeshElemGizmo3D;
+
+static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz)
+{
+ MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
+ if (gz_ele->base_index != -1) {
+ Object *ob = gz_ele->bases[gz_ele->base_index]->object;
+ EDBM_preselect_elem_draw(gz_ele->psel, ob->obmat);
+ }
+}
+
+static int gizmo_preselect_elem_test_select(
+ bContext *C, wmGizmo *gz, const int mval[2])
+{
+ MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
+ struct {
+ Object *ob;
+ BMElem *ele;
+ float dist;
+ int base_index;
+ } best = {
+ .dist = ED_view3d_select_dist_px(),
+ };
+
+ struct {
+ int base_index;
+ int vert_index;
+ int edge_index;
+ int face_index;
+ } prev = {
+ .base_index = gz_ele->base_index,
+ .vert_index = gz_ele->vert_index,
+ .edge_index = gz_ele->edge_index,
+ .face_index = gz_ele->face_index,
+ };
+
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ if (((gz_ele->bases)) == NULL ||
+ (gz_ele->bases[0] != view_layer->basact))
+ {
+ MEM_SAFE_FREE(gz_ele->bases);
+ gz_ele->bases = BKE_view_layer_array_from_bases_in_edit_mode(
+ view_layer, v3d, &gz_ele->bases_len);
+ }
+ }
+
+ ViewContext vc;
+ em_setup_viewcontext(C, &vc);
+ copy_v2_v2_int(vc.mval, mval);
+
+ {
+ /* TODO: support faces. */
+ int base_index = -1;
+ BMVert *eve_test;
+ BMEdge *eed_test;
+
+ if (EDBM_unified_findnearest_from_raycast(
+ &vc, gz_ele->bases, gz_ele->bases_len,
+ true, &base_index, &eve_test, &eed_test, NULL))
+ {
+ Base *base = gz_ele->bases[base_index];
+ best.ob = base->object;
+ if (eve_test) {
+ best.ele = (BMElem *)eve_test;
+ }
+ else if (eed_test) {
+ best.ele = (BMElem *)eed_test;
+ }
+ else {
+ BLI_assert(0);
+ }
+ best.base_index = base_index;
+ /* Check above should never fail, if it does it's an internal error. */
+ BLI_assert(best.base_index != -1);
+ }
+ }
+
+ BMesh *bm = NULL;
+
+ gz_ele->base_index = -1;
+ gz_ele->vert_index = -1;
+ gz_ele->edge_index = -1;
+ gz_ele->face_index = -1;
+
+ if (best.ele) {
+ gz_ele->base_index = best.base_index;
+ bm = BKE_editmesh_from_object(gz_ele->bases[gz_ele->base_index]->object)->bm;
+ BM_mesh_elem_index_ensure(bm, best.ele->head.htype);
+
+ if (best.ele->head.htype == BM_VERT) {
+ gz_ele->vert_index = BM_elem_index_get(best.ele);
+ }
+ else if (best.ele->head.htype == BM_EDGE) {
+ gz_ele->edge_index = BM_elem_index_get(best.ele);
+ }
+ else if (best.ele->head.htype == BM_FACE) {
+ gz_ele->face_index = BM_elem_index_get(best.ele);
+ }
+ }
+
+ if ((prev.base_index == gz_ele->base_index) &&
+ (prev.vert_index == gz_ele->vert_index) &&
+ (prev.edge_index == gz_ele->edge_index) &&
+ (prev.face_index == gz_ele->face_index))
+ {
+ /* pass (only recalculate on change) */
+ }
+ else {
+ if (best.ele) {
+ const float (*coords)[3] = NULL;
+ {
+ Object *ob = gz_ele->bases[gz_ele->base_index]->object;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
+ if (me_eval->runtime.edit_data) {
+ coords = me_eval->runtime.edit_data->vertexCos;
+ }
+ }
+ EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
+ }
+ else {
+ EDBM_preselect_elem_clear(gz_ele->psel);
+ }
+
+ RNA_int_set(gz->ptr, "object_index", gz_ele->base_index);
+ RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
+ RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
+ RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);
+
+ ARegion *ar = CTX_wm_region(C);
+ ED_region_tag_redraw(ar);
+ }
+
+ // return best.eed ? 0 : -1;
+ return -1;
+}
+
+static void gizmo_preselect_elem_setup(wmGizmo *gz)
+{
+ MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
+ if (gz_ele->psel == NULL) {
+ gz_ele->psel = EDBM_preselect_elem_create();
+ }
+ gz_ele->base_index = -1;
+}
+
+static void gizmo_preselect_elem_free(wmGizmo *gz)
+{
+ MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
+ EDBM_preselect_elem_destroy(gz_ele->psel);
+ gz_ele->psel = NULL;
+ MEM_SAFE_FREE(gz_ele->bases);
+}
+
+static int gizmo_preselect_elem_invoke(
+ bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event))
+{
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void GIZMO_GT_mesh_preselect_elem_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_mesh_preselect_elem_3d";
+
+ /* api callbacks */
+ gzt->invoke = gizmo_preselect_elem_invoke;
+ gzt->draw = gizmo_preselect_elem_draw;
+ gzt->test_select = gizmo_preselect_elem_test_select;
+ gzt->setup = gizmo_preselect_elem_setup;
+ gzt->free = gizmo_preselect_elem_free;
+
+ gzt->struct_size = sizeof(MeshElemGizmo3D);
+
+ RNA_def_int(gzt->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", -1, INT_MAX);
+ RNA_def_int(gzt->srna, "vert_index", -1, -1, INT_MAX, "Vert Index", "", -1, INT_MAX);
+ RNA_def_int(gzt->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", -1, INT_MAX);
+ RNA_def_int(gzt->srna, "face_index", -1, -1, INT_MAX, "Face Index", "", -1, INT_MAX);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Edge-Ring Pre-Select Gizmo API
+ *
+ * \{ */
+
+typedef struct MeshEdgeRingGizmo3D {
+ wmGizmo gizmo;
+ Base **bases;
+ uint bases_len;
+ int base_index;
+ int edge_index;
+ struct EditMesh_PreSelEdgeRing *psel;
+} MeshEdgeRingGizmo3D;
+
+static void gizmo_preselect_edgering_draw(const bContext *UNUSED(C), wmGizmo *gz)
+{
+ MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
+ if (gz_ring->base_index != -1) {
+ Object *ob = gz_ring->bases[gz_ring->base_index]->object;
+ EDBM_preselect_edgering_draw(gz_ring->psel, ob->obmat);
+ }
+}
+
+static int gizmo_preselect_edgering_test_select(
+ bContext *C, wmGizmo *gz, const int mval[2])
+{
+ MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
+ struct {
+ Object *ob;
+ BMEdge *eed;
+ float dist;
+ int base_index;
+ } best = {
+ .dist = ED_view3d_select_dist_px(),
+ };
+
+ struct {
+ int base_index;
+ int edge_index;
+ } prev = {
+ .base_index = gz_ring->base_index,
+ .edge_index = gz_ring->edge_index,
+ };
+
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ if (((gz_ring->bases)) == NULL ||
+ (gz_ring->bases[0] != view_layer->basact))
+ {
+ MEM_SAFE_FREE(gz_ring->bases);
+ gz_ring->bases = BKE_view_layer_array_from_bases_in_edit_mode(
+ view_layer, v3d, &gz_ring->bases_len);
+ }
+ }
+
+ ViewContext vc;
+ em_setup_viewcontext(C, &vc);
+ copy_v2_v2_int(vc.mval, mval);
+
+ for (uint base_index = 0; base_index < gz_ring->bases_len; base_index++) {
+ Object *ob_iter = gz_ring->bases[base_index]->object;
+ ED_view3d_viewcontext_init_object(&vc, ob_iter);
+ BMEdge *eed_test = EDBM_edge_find_nearest_ex(&vc, &best.dist, NULL, false, false, NULL);
+ if (eed_test) {
+ best.ob = ob_iter;
+ best.eed = eed_test;
+ best.base_index = base_index;
+ }
+ }
+
+ BMesh *bm = NULL;
+ if (best.eed) {
+ gz_ring->base_index = best.base_index;
+ bm = BKE_editmesh_from_object(gz_ring->bases[gz_ring->base_index]->object)->bm;
+ BM_mesh_elem_index_ensure(bm, BM_EDGE);
+ gz_ring->edge_index = BM_elem_index_get(best.eed);
+ }
+ else {
+ gz_ring->base_index = -1;
+ gz_ring->edge_index = -1;
+ }
+
+
+ if ((prev.base_index == gz_ring->base_index) &&
+ (prev.edge_index == gz_ring->edge_index))
+ {
+ /* pass (only recalculate on change) */
+ }
+ else {
+ if (best.eed) {
+ const float (*coords)[3] = NULL;
+ {
+ Object *ob = gz_ring->bases[gz_ring->base_index]->object;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
+ if (me_eval->runtime.edit_data) {
+ coords = me_eval->runtime.edit_data->vertexCos;
+ }
+ }
+ EDBM_preselect_edgering_update_from_edge(gz_ring->psel, bm, best.eed, 1, coords);
+ }
+ else {
+ EDBM_preselect_edgering_clear(gz_ring->psel);
+ }
+
+ RNA_int_set(gz->ptr, "object_index", gz_ring->base_index);
+ RNA_int_set(gz->ptr, "edge_index", gz_ring->edge_index);
+
+ ARegion *ar = CTX_wm_region(C);
+ ED_region_tag_redraw(ar);
+ }
+
+ // return best.eed ? 0 : -1;
+ return -1;
+}
+
+static void gizmo_preselect_edgering_setup(wmGizmo *gz)
+{
+ MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
+ if (gz_ring->psel == NULL) {
+ gz_ring->psel = EDBM_preselect_edgering_create();
+ }
+ gz_ring->base_index = -1;
+}
+
+static void gizmo_preselect_edgering_free(wmGizmo *gz)
+{
+ MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
+ EDBM_preselect_edgering_destroy(gz_ring->psel);
+ gz_ring->psel = NULL;
+ MEM_SAFE_FREE(gz_ring->bases);
+}
+
+static int gizmo_preselect_edgering_invoke(
+ bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event))
+{
+ return OPERATOR_PASS_THROUGH;
+}
+
+
+static void GIZMO_GT_mesh_preselect_edgering_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_mesh_preselect_edgering_3d";
+
+ /* api callbacks */
+ gzt->invoke = gizmo_preselect_edgering_invoke;
+ gzt->draw = gizmo_preselect_edgering_draw;
+ gzt->test_select = gizmo_preselect_edgering_test_select;
+ gzt->setup = gizmo_preselect_edgering_setup;
+ gzt->free = gizmo_preselect_edgering_free;
+
+ gzt->struct_size = sizeof(MeshEdgeRingGizmo3D);
+
+ RNA_def_int(gzt->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", -1, INT_MAX);
+ RNA_def_int(gzt->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", -1, INT_MAX);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Gizmo API
+ *
+ * \{ */
+
+void ED_gizmotypes_preselect_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_mesh_preselect_elem_3d);
+ WM_gizmotype_append(GIZMO_GT_mesh_preselect_edgering_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
new file mode 100644
index 00000000000..96fbe1d48a6
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -0,0 +1,1090 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/view3d_gizmo_ruler.c
+ * \ingroup spview3d
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_rect.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+
+#include "BKE_object.h"
+#include "BKE_unit.h"
+#include "BKE_material.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BIF_gl.h"
+
+#include "ED_gizmo_utils.h"
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+#include "UI_interface.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_toolsystem.h"
+
+#include "view3d_intern.h" /* own include */
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_select.h"
+#include "GPU_state.h"
+
+#include "BLF_api.h"
+
+
+static const char *view3d_gzgt_ruler_id = "VIEW3D_GGT_ruler";
+
+
+#define MVAL_MAX_PX_DIST 12.0f
+
+/* -------------------------------------------------------------------- */
+/* Ruler Item (we can have many) */
+enum {
+ RULERITEM_USE_ANGLE = (1 << 0), /* use protractor */
+ RULERITEM_USE_RAYCAST = (1 << 1)
+};
+
+enum {
+ RULERITEM_DIRECTION_IN = 0,
+ RULERITEM_DIRECTION_OUT
+};
+
+/* keep smaller then selection, since we may want click elsewhere without selecting a ruler */
+#define RULER_PICK_DIST 12.0f
+#define RULER_PICK_DIST_SQ (RULER_PICK_DIST * RULER_PICK_DIST)
+
+/* not clicking on a point */
+#define PART_LINE 0xff
+
+/* -------------------------------------------------------------------- */
+/* Ruler Info (wmGizmoGroup customdata) */
+
+enum {
+ RULER_STATE_NORMAL = 0,
+ RULER_STATE_DRAG
+};
+
+enum {
+ RULER_SNAP_OK = (1 << 0),
+};
+
+typedef struct RulerInfo {
+ // ListBase items;
+ int item_active;
+ int flag;
+ int snap_flag;
+ int state;
+
+ struct SnapObjectContext *snap_context;
+
+ /* wm state */
+ wmWindow *win;
+ ScrArea *sa;
+ ARegion *ar; /* re-assigned every modal update */
+} RulerInfo;
+
+/* -------------------------------------------------------------------- */
+/* Ruler Item (two or three points) */
+
+typedef struct RulerItem {
+ wmGizmo gz;
+
+ /* worldspace coords, middle being optional */
+ float co[3][3];
+
+ int flag;
+ int raycast_dir; /* RULER_DIRECTION_* */
+} RulerItem;
+
+typedef struct RulerInteraction {
+ /* selected coord */
+ char co_index; /* 0 -> 2 */
+ float drag_start_co[3];
+ uint inside_region : 1;
+} RulerInteraction;
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Ruler Utilities
+ * \{ */
+
+static RulerItem *ruler_item_add(wmGizmoGroup *gzgroup)
+{
+ /* could pass this as an arg */
+ const wmGizmoType *gzt_ruler = WM_gizmotype_find("VIEW3D_GT_ruler_item", true);
+ RulerItem *ruler_item = (RulerItem *)WM_gizmo_new_ptr(gzt_ruler, gzgroup, NULL);
+ WM_gizmo_set_flag(&ruler_item->gz, WM_GIZMO_DRAW_MODAL, true);
+ return ruler_item;
+}
+
+static void ruler_item_remove(bContext *C, wmGizmoGroup *gzgroup, RulerItem *ruler_item)
+{
+ WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, &ruler_item->gz, C);
+}
+
+static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit,
+ char *numstr, size_t numstr_size, int prec)
+{
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ const float ruler_angle = angle_v3v3v3(ruler_item->co[0],
+ ruler_item->co[1],
+ ruler_item->co[2]);
+
+ if (unit->system == USER_UNIT_NONE) {
+ BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle));
+ }
+ else {
+ bUnit_AsString2(
+ numstr, numstr_size, (double)ruler_angle,
+ prec, B_UNIT_ROTATION, unit, false);
+ }
+ }
+ else {
+ const float ruler_len = len_v3v3(ruler_item->co[0],
+ ruler_item->co[2]);
+
+ if (unit->system == USER_UNIT_NONE) {
+ BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len);
+ }
+ else {
+ bUnit_AsString2(
+ numstr, numstr_size, (double)(ruler_len * unit->scale_length),
+ prec, B_UNIT_LENGTH, unit, false);
+ }
+ }
+}
+
+static bool view3d_ruler_pick(
+ wmGizmoGroup *gzgroup, RulerItem *ruler_item, const float mval[2],
+ int *r_co_index)
+{
+ RulerInfo *ruler_info = gzgroup->customdata;
+ ARegion *ar = ruler_info->ar;
+ bool found = false;
+
+ float dist_best = RULER_PICK_DIST_SQ;
+ int co_index_best = -1;
+
+ {
+ float co_ss[3][2];
+ float dist;
+ int j;
+
+ /* should these be checked? - ok for now not to */
+ for (j = 0; j < 3; j++) {
+ ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
+ }
+
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]),
+ dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2]));
+ if (dist < dist_best) {
+ dist_best = dist;
+ found = true;
+
+ {
+ const float dist_points[3] = {
+ len_squared_v2v2(co_ss[0], mval),
+ len_squared_v2v2(co_ss[1], mval),
+ len_squared_v2v2(co_ss[2], mval),
+ };
+ if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) {
+ co_index_best = min_axis_v3(dist_points);
+ }
+ else {
+ co_index_best = -1;
+ }
+ }
+ }
+ }
+ else {
+ dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]);
+ if (dist < dist_best) {
+ dist_best = dist;
+ found = true;
+
+ {
+ const float dist_points[2] = {
+ len_squared_v2v2(co_ss[0], mval),
+ len_squared_v2v2(co_ss[2], mval),
+ };
+ if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) {
+ co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2;
+ }
+ else {
+ co_index_best = -1;
+ }
+ }
+ }
+ }
+ }
+
+ *r_co_index = co_index_best;
+ return found;
+}
+
+/**
+ * Ensure the 'snap_context' is only cached while dragging,
+ * needed since the user may toggle modes between tool use.
+ */
+static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
+{
+ Main *bmain = CTX_data_main(C);
+ if (state == ruler_info->state) {
+ return;
+ }
+
+ /* always remove */
+ if (ruler_info->snap_context) {
+ ED_transform_snap_object_context_destroy(ruler_info->snap_context);
+ ruler_info->snap_context = NULL;
+ }
+
+ if (state == RULER_STATE_NORMAL) {
+ /* pass */
+ }
+ else if (state == RULER_STATE_DRAG) {
+ ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
+ bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0,
+ ruler_info->ar, CTX_wm_view3d(C));
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ ruler_info->state = state;
+}
+
+static void view3d_ruler_item_project(
+ RulerInfo *ruler_info, float r_co[3],
+ const int xy[2])
+{
+ ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->ar, r_co, xy, r_co);
+}
+
+/* use for mousemove events */
+static bool view3d_ruler_item_mousemove(
+ RulerInfo *ruler_info, RulerItem *ruler_item, const int mval[2],
+ const bool do_thickness, const bool do_snap)
+{
+ RulerInteraction *inter = ruler_item->gz.interaction_data;
+ const float eps_bias = 0.0002f;
+ float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
+
+ ruler_info->snap_flag &= ~RULER_SNAP_OK;
+
+ if (ruler_item) {
+ float *co = ruler_item->co[inter->co_index];
+ /* restore the initial depth */
+ copy_v3_v3(co, inter->drag_start_co);
+ view3d_ruler_item_project(ruler_info, co, mval);
+ if (do_thickness && inter->co_index != 1) {
+ // Scene *scene = CTX_data_scene(C);
+ // View3D *v3d = ruler_info->sa->spacedata.first;
+ const float mval_fl[2] = {UNPACK2(mval)};
+ float ray_normal[3];
+ float ray_start[3];
+ float *co_other;
+
+ co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0];
+
+ if (ED_transform_snap_object_project_view3d(
+ ruler_info->snap_context,
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ },
+ mval_fl, &dist_px,
+ co, ray_normal))
+ {
+ negate_v3(ray_normal);
+ /* add some bias */
+ madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
+ ED_transform_snap_object_project_ray(
+ ruler_info->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ },
+ ray_start, ray_normal, NULL,
+ co_other, NULL);
+ }
+ }
+ else if (do_snap) {
+ const float mval_fl[2] = {UNPACK2(mval)};
+
+ if (ED_transform_snap_object_project_view3d(
+ ruler_info->snap_context,
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ .use_occlusion_test = true,
+ },
+ mval_fl, &dist_px,
+ co, NULL))
+ {
+ ruler_info->snap_flag |= RULER_SNAP_OK;
+ }
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ruler/Grease Pencil Conversion
+ * \{ */
+
+#define RULER_ID "RulerData3D"
+static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
+{
+ // RulerInfo *ruler_info = gzgroup->customdata;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ bGPdata *gpd;
+ bGPDlayer *gpl;
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+ RulerItem *ruler_item;
+ const char *ruler_name = RULER_ID;
+ bool changed = false;
+
+ if (scene->gpd == NULL) {
+ scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
+ }
+ gpd = scene->gpd;
+
+ gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false);
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
+ gpl->thickness = 1;
+ gpl->flag |= GP_LAYER_HIDE;
+ }
+
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ BKE_gpencil_free_strokes(gpf);
+
+ for (ruler_item = gzgroup->gizmos.first; ruler_item; ruler_item = (RulerItem *)ruler_item->gz.next) {
+ bGPDspoint *pt;
+ int j;
+
+ /* allocate memory for a new stroke */
+ gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ gps->totpoints = 3;
+ pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ for (j = 0; j < 3; j++) {
+ copy_v3_v3(&pt->x, ruler_item->co[j]);
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt++;
+ }
+ }
+ else {
+ gps->totpoints = 2;
+ pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ 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++;
+ }
+ }
+ gps->flag = GP_STROKE_3DSPACE;
+ gps->thickness = 3;
+
+ BLI_addtail(&gpf->strokes, gps);
+ changed = true;
+ }
+
+ return changed;
+}
+
+static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ Scene *scene = CTX_data_scene(C);
+ bool changed = false;
+
+ if (scene->gpd) {
+ bGPDlayer *gpl;
+ const char *ruler_name = RULER_ID;
+ gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ if (gpl) {
+ bGPDframe *gpf;
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ if (gpf) {
+ bGPDstroke *gps;
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt = gps->points;
+ int j;
+ RulerItem *ruler_item = NULL;
+ if (gps->totpoints == 3) {
+ ruler_item = ruler_item_add(gzgroup);
+ for (j = 0; j < 3; j++) {
+ copy_v3_v3(ruler_item->co[j], &pt->x);
+ pt++;
+ }
+ ruler_item->flag |= RULERITEM_USE_ANGLE;
+ changed = true;
+ }
+ else if (gps->totpoints == 2) {
+ ruler_item = ruler_item_add(gzgroup);
+ for (j = 0; j < 3; j += 2) {
+ copy_v3_v3(ruler_item->co[j], &pt->x);
+ pt++;
+ }
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ return changed;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ruler Item Gizmo Type
+ * \{ */
+
+static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
+{
+ Scene *scene = CTX_data_scene(C);
+ UnitSettings *unit = &scene->unit;
+ RulerInfo *ruler_info = gz->parent_gzgroup->customdata;
+ RulerItem *ruler_item = (RulerItem *)gz;
+ ARegion *ar = ruler_info->ar;
+ RegionView3D *rv3d = ar->regiondata;
+ const float cap_size = 4.0f;
+ const float bg_margin = 4.0f * U.pixelsize;
+ const float arc_size = 64.0f * U.pixelsize;
+#define ARC_STEPS 24
+ const int arc_steps = ARC_STEPS;
+ const float color_act[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float color_base[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ unsigned char color_text[3];
+ unsigned char color_wire[3];
+ float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f};
+
+ /* anti-aliased lines for more consistent appearance */
+ GPU_line_smooth(true);
+ GPU_line_width(1.0f);
+
+ BLF_enable(blf_mono_font, BLF_ROTATION);
+ BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi);
+ BLF_rotation(blf_mono_font, 0.0f);
+
+ UI_GetThemeColor3ubv(TH_TEXT, color_text);
+ UI_GetThemeColor3ubv(TH_WIRE, color_wire);
+
+ /* Avoid white on white text. (TODO Fix by using theme) */
+ if ((int)color_text[0] + (int)color_text[1] + (int)color_text[2] > 127 * 3 * 0.6f) {
+ copy_v3_fl(color_back, 0.0f);
+ }
+
+ const bool is_act = (gz->flag & WM_GIZMO_DRAW_HOVER);
+ float dir_ruler[2];
+ float co_ss[3][2];
+ int j;
+
+ /* should these be checked? - ok for now not to */
+ for (j = 0; j < 3; j++) {
+ ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
+ }
+
+ GPU_blend(true);
+
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float *col = is_act ? color_act : color_base;
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, 2);
+ immUniform1f("dash_width", 6.0f);
+
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+
+ immVertex2fv(shdr_pos, co_ss[0]);
+ immVertex2fv(shdr_pos, co_ss[1]);
+ immVertex2fv(shdr_pos, co_ss[2]);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ /* arc */
+ {
+ float dir_tmp[3];
+ float co_tmp[3];
+ float arc_ss_coord[2];
+
+ float dir_a[3];
+ float dir_b[3];
+ float quat[4];
+ float axis[3];
+ float angle;
+ const float px_scale = (ED_view3d_pixel_size_no_ui_scale(rv3d, ruler_item->co[1]) *
+ min_fff(arc_size,
+ len_v2v2(co_ss[0], co_ss[1]) / 2.0f,
+ len_v2v2(co_ss[2], co_ss[1]) / 2.0f));
+
+ sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]);
+ sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]);
+ normalize_v3(dir_a);
+ normalize_v3(dir_b);
+
+ cross_v3_v3v3(axis, dir_a, dir_b);
+ angle = angle_normalized_v3v3(dir_a, dir_b);
+
+ axis_angle_to_quat(quat, axis, angle / arc_steps);
+
+ copy_v3_v3(dir_tmp, dir_a);
+
+ immUniformColor3ubv(color_wire);
+
+ immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1);
+
+ for (j = 0; j <= arc_steps; j++) {
+ madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
+ ED_view3d_project_float_global(ar, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP);
+ mul_qt_v3(quat, dir_tmp);
+
+ immVertex2fv(shdr_pos, arc_ss_coord);
+ }
+
+ immEnd();
+ }
+
+ /* capping */
+ {
+ float rot_90_vec_a[2];
+ float rot_90_vec_b[2];
+ float cap[2];
+
+ sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]);
+ rot_90_vec_a[0] = -dir_ruler[1];
+ rot_90_vec_a[1] = dir_ruler[0];
+ normalize_v2(rot_90_vec_a);
+
+ sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]);
+ rot_90_vec_b[0] = -dir_ruler[1];
+ rot_90_vec_b[1] = dir_ruler[0];
+ normalize_v2(rot_90_vec_b);
+
+ GPU_blend(true);
+
+ immUniformColor3ubv(color_wire);
+
+ immBegin(GPU_PRIM_LINES, 8);
+
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
+ immVertex2fv(shdr_pos, cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
+ immVertex2fv(shdr_pos, cap);
+
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
+ immVertex2fv(shdr_pos, cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
+ immVertex2fv(shdr_pos, cap);
+
+ /* angle vertex */
+ immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+
+ immEnd();
+
+ GPU_blend(false);
+ }
+
+ /* text */
+ char numstr[256];
+ float numstr_size[2];
+ float posit[2];
+ const int prec = 2; /* XXX, todo, make optional */
+
+ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
+
+ BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
+
+ posit[0] = co_ss[1][0] + (cap_size * 2.0f);
+ posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
+
+ /* draw text (bg) */
+ {
+ immUniformColor4fv(color_back);
+ GPU_blend(true);
+ immRectf(shdr_pos,
+ posit[0] - bg_margin, posit[1] - bg_margin,
+ posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1]);
+ GPU_blend(false);
+ }
+
+ immUnbindProgram();
+
+ /* draw text */
+ {
+ BLF_color3ubv(blf_mono_font, color_text);
+ BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
+ BLF_rotation(blf_mono_font, 0.0f);
+ BLF_draw(blf_mono_font, numstr, sizeof(numstr));
+ }
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float *col = is_act ? color_act : color_base;
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, 2);
+ immUniform1f("dash_width", 6.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ immVertex2fv(shdr_pos, co_ss[0]);
+ immVertex2fv(shdr_pos, co_ss[2]);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
+
+ /* capping */
+ {
+ float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
+ float cap[2];
+
+ normalize_v2(rot_90_vec);
+
+ GPU_blend(true);
+
+ immUniformColor3ubv(color_wire);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
+ immVertex2fv(shdr_pos, cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
+ immVertex2fv(shdr_pos, cap);
+
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
+ immVertex2fv(shdr_pos, cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
+ immVertex2fv(shdr_pos, cap);
+
+ immEnd();
+
+ GPU_blend(false);
+ }
+
+ /* text */
+ char numstr[256];
+ float numstr_size[2];
+ const int prec = 6; /* XXX, todo, make optional */
+ float posit[2];
+
+ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
+
+ BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
+
+ mid_v2_v2v2(posit, co_ss[0], co_ss[2]);
+
+ /* center text */
+ posit[0] -= numstr_size[0] / 2.0f;
+ posit[1] -= numstr_size[1] / 2.0f;
+
+ /* draw text (bg) */
+ {
+ immUniformColor4fv(color_back);
+ GPU_blend(true);
+ immRectf(shdr_pos,
+ posit[0] - bg_margin, posit[1] - bg_margin,
+ posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1]);
+ GPU_blend(false);
+ }
+
+ immUnbindProgram();
+
+ /* draw text */
+ {
+ BLF_color3ubv(blf_mono_font, color_text);
+ BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
+ BLF_draw(blf_mono_font, numstr, sizeof(numstr));
+ }
+ }
+
+ GPU_line_smooth(false);
+
+ BLF_disable(blf_mono_font, BLF_ROTATION);
+
+#undef ARC_STEPS
+
+ /* draw snap */
+ if ((ruler_info->snap_flag & RULER_SNAP_OK) &&
+ (ruler_info->state == RULER_STATE_DRAG) &&
+ (ruler_item->gz.interaction_data != NULL))
+ {
+ RulerInteraction *inter = ruler_item->gz.interaction_data;
+ /* size from drawSnapping */
+ const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ float co_ss_snap[3];
+ ED_view3d_project_float_global(ar, ruler_item->co[inter->co_index], co_ss_snap, V3D_PROJ_TEST_NOP);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color_act);
+
+ imm_draw_circle_wire_2d(pos, co_ss_snap[0], co_ss_snap[1], size * U.pixelsize, 32);
+
+ immUnbindProgram();
+ }
+}
+
+static int gizmo_ruler_test_select(
+ bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
+{
+ RulerItem *ruler_item_pick = (RulerItem *)gz;
+ float mval_fl[2] = {UNPACK2(mval)};
+ int co_index;
+
+ /* select and drag */
+ if (view3d_ruler_pick(gz->parent_gzgroup, ruler_item_pick, mval_fl, &co_index)) {
+ if (co_index == -1) {
+ if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
+ return PART_LINE;
+ }
+ }
+ else {
+ return co_index;
+ }
+ }
+ return -1;
+}
+
+static int gizmo_ruler_modal(
+ bContext *C, wmGizmo *gz, const wmEvent *event,
+ eWM_GizmoFlagTweak UNUSED(tweak_flag))
+{
+ bool do_draw = false;
+ int exit_code = OPERATOR_RUNNING_MODAL;
+ RulerInfo *ruler_info = gz->parent_gzgroup->customdata;
+ RulerItem *ruler_item = (RulerItem *)gz;
+ RulerInteraction *inter = ruler_item->gz.interaction_data;
+ ARegion *ar = CTX_wm_region(C);
+
+ ruler_info->ar = ar;
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ {
+ if (ruler_info->state == RULER_STATE_DRAG) {
+ if (view3d_ruler_item_mousemove(
+ ruler_info, ruler_item, event->mval,
+ event->shift != 0, event->ctrl != 0))
+ {
+ do_draw = true;
+ }
+ inter->inside_region = BLI_rcti_isect_pt_v(&ar->winrct, &event->x);
+ }
+ break;
+ }
+ }
+ if (do_draw) {
+ ED_region_tag_redraw(ar);
+ }
+ return exit_code;
+}
+
+static int gizmo_ruler_invoke(
+ bContext *C, wmGizmo *gz, const wmEvent *event)
+{
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ RulerInfo *ruler_info = gzgroup->customdata;
+ RulerItem *ruler_item_pick = (RulerItem *)gz;
+ RulerInteraction *inter = MEM_callocN(sizeof(RulerInteraction), __func__);
+ gz->interaction_data = inter;
+
+ ARegion *ar = ruler_info->ar;
+
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ /* select and drag */
+ if (gz->highlight_part == PART_LINE) {
+ if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
+ /* Add Center Point */
+ ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
+ inter->co_index = 1;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
+
+ /* find the factor */
+ {
+ float co_ss[2][2];
+ float fac;
+
+ ED_view3d_project_float_global(ar, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP);
+ ED_view3d_project_float_global(ar, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP);
+
+ fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]);
+ CLAMP(fac, 0.0f, 1.0f);
+
+ interp_v3_v3v3(ruler_item_pick->co[1],
+ ruler_item_pick->co[0],
+ ruler_item_pick->co[2], fac);
+ }
+
+ /* update the new location */
+ view3d_ruler_item_mousemove(
+ ruler_info, ruler_item_pick, event->mval,
+ event->shift != 0, event->ctrl != 0);
+ }
+ }
+ else {
+ inter->co_index = gz->highlight_part;
+ ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
+
+ /* store the initial depth */
+ copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
+{
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ RulerInfo *ruler_info = gzgroup->customdata;
+
+ if (!cancel) {
+ if (ruler_info->state == RULER_STATE_DRAG) {
+ RulerItem *ruler_item = (RulerItem *)gz;
+ RulerInteraction *inter = gz->interaction_data;
+ /* rubber-band angle removal */
+ if (!inter->inside_region) {
+ if ((inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) {
+ ruler_item->flag &= ~RULERITEM_USE_ANGLE;
+ }
+ else {
+ /* Not ideal, since the ruler isn't a mode and we don't want to override delete key
+ * use dragging out of the view for removal. */
+ ruler_item_remove(C, gzgroup, ruler_item);
+ ruler_item = NULL;
+ gz = NULL;
+ inter = NULL;
+ }
+ }
+ if (ruler_info->snap_flag & RULER_SNAP_OK) {
+ ruler_info->snap_flag &= ~RULER_SNAP_OK;
+ }
+ ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
+ }
+ /* We could convert only the current gizmo, for now just re-generate. */
+ view3d_ruler_to_gpencil(C, gzgroup);
+ }
+
+ if (gz) {
+ MEM_SAFE_FREE(gz->interaction_data);
+ }
+
+ ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
+}
+
+static int gizmo_ruler_cursor_get(wmGizmo *gz)
+{
+ if (gz->highlight_part == PART_LINE) {
+ return BC_CROSSCURSOR;
+ }
+ return BC_NSEW_SCROLLCURSOR;
+}
+
+void VIEW3D_GT_ruler_item(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "VIEW3D_GT_ruler_item";
+
+ /* api callbacks */
+ gzt->draw = gizmo_ruler_draw;
+ gzt->test_select = gizmo_ruler_test_select;
+ gzt->modal = gizmo_ruler_modal;
+ gzt->invoke = gizmo_ruler_invoke;
+ gzt->exit = gizmo_ruler_exit;
+ gzt->cursor_get = gizmo_ruler_cursor_get;
+
+ gzt->struct_size = sizeof(RulerItem);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ruler Gizmo Group
+ * \{ */
+
+static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__);
+
+ if (view3d_ruler_from_gpencil(C, gzgroup)) {
+ /* nop */
+ }
+
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ ruler_info->win = win;
+ ruler_info->sa = sa;
+ ruler_info->ar = ar;
+
+ gzgroup->customdata = ruler_info;
+}
+
+void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Ruler Widgets";
+ gzgt->idname = view3d_gzgt_ruler_id;
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
+ gzgt->setup = WIDGETGROUP_ruler_setup;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Ruler Operator
+ * \{ */
+
+static bool view3d_ruler_poll(bContext *C)
+{
+ bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
+ if ((tref_rt == NULL) ||
+ !STREQ(view3d_gzgt_ruler_id, tref_rt->gizmo_group) ||
+ CTX_wm_region_view3d(C) == NULL)
+ {
+ return false;
+ }
+ return true;
+}
+
+static int view3d_ruler_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ wmGizmoGroup *gzgroup = WM_gizmomap_group_find(gzmap, view3d_gzgt_ruler_id);
+ const bool use_depth = (v3d->shading.type >= OB_SOLID);
+
+ /* Create new line */
+ RulerItem *ruler_item;
+ ruler_item = ruler_item_add(gzgroup);
+
+ /* This is a little weak, but there is no real good way to tweak directly. */
+ WM_gizmo_highlight_set(gzmap, &ruler_item->gz);
+ if (WM_operator_name_call(
+ C, "GIZMOGROUP_OT_gizmo_tweak",
+ WM_OP_INVOKE_REGION_WIN, NULL) == OPERATOR_RUNNING_MODAL)
+ {
+ RulerInfo *ruler_info = gzgroup->customdata;
+ RulerInteraction *inter = ruler_item->gz.interaction_data;
+ if (use_depth) {
+ /* snap the first point added, not essential but handy */
+ inter->co_index = 0;
+ view3d_ruler_item_mousemove(ruler_info, ruler_item, event->mval, false, true);
+ copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]);
+ }
+ else {
+ negate_v3_v3(inter->drag_start_co, rv3d->ofs);
+ copy_v3_v3(ruler_item->co[0], inter->drag_start_co);
+ view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval);
+ }
+
+ copy_v3_v3(ruler_item->co[2], ruler_item->co[0]);
+ ruler_item->gz.highlight_part = inter->co_index = 2;
+ }
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_ruler_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Ruler Add";
+ ot->idname = "VIEW3D_OT_ruler_add";
+
+ ot->invoke = view3d_ruler_add_invoke;
+ ot->poll = view3d_ruler_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 27dda99e715..854bf01b158 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -41,11 +41,12 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_screen.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -68,162 +69,33 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event);
#define B_SEL_EDGE 111
#define B_SEL_FACE 112
-/* XXX quickly ported across */
-static void handle_view3d_lock(bContext *C)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = CTX_wm_view3d(C);
-
- if (v3d != NULL && sa != NULL) {
- if (v3d->localvd == NULL && v3d->scenelock && sa->spacetype == SPACE_VIEW3D) {
- /* copy to scene */
- scene->lay = v3d->lay;
- scene->layact = v3d->layact;
- scene->camera = v3d->camera;
-
- /* not through notifier, listener don't have context
- * and non-open screens or spaces need to be updated too */
- BKE_screen_view3d_main_sync(&bmain->screen, scene);
-
- /* notifiers for scene update */
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
- }
- }
-}
-
-/**
- * layer code is on three levels actually:
- * - here for operator
- * - uiTemplateLayers in interface/ code for buttons
- * - ED_view3d_scene_layer_set for RNA
- */
-static void view3d_layers_editmode_ensure(Scene *scene, View3D *v3d)
-{
- /* sanity check - when in editmode disallow switching the editmode layer off since its confusing
- * an alternative would be to always draw the editmode object. */
- if (scene->obedit && (scene->obedit->lay & v3d->lay) == 0) {
- int bit;
- for (bit = 0; bit < 32; bit++) {
- if (scene->obedit->lay & (1u << bit)) {
- v3d->lay |= (1u << bit);
- break;
- }
- }
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Toggle Matcap Flip Operator
+ * \{ */
-static int view3d_layers_exec(bContext *C, wmOperator *op)
+static int toggle_matcap_flip(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- int nr = RNA_int_get(op->ptr, "nr");
- const bool toggle = RNA_boolean_get(op->ptr, "toggle");
-
- if (nr < 0)
- return OPERATOR_CANCELLED;
-
- if (nr == 0) {
- /* all layers */
- if (!v3d->lay_prev)
- v3d->lay_prev = 1;
-
- if (toggle && v3d->lay == ((1 << 20) - 1)) {
- /* return to active layer only */
- v3d->lay = v3d->lay_prev;
-
- view3d_layers_editmode_ensure(scene, v3d);
- }
- else {
- v3d->lay_prev = v3d->lay;
- v3d->lay |= (1 << 20) - 1;
- }
- }
- else {
- int bit;
- nr--;
-
- if (RNA_boolean_get(op->ptr, "extend")) {
- if (toggle && v3d->lay & (1 << nr) && (v3d->lay & ~(1 << nr)))
- v3d->lay &= ~(1 << nr);
- else
- v3d->lay |= (1 << nr);
- }
- else {
- v3d->lay = (1 << nr);
- }
-
- view3d_layers_editmode_ensure(scene, v3d);
-
- /* set active layer, ensure to always have one */
- if (v3d->lay & (1 << nr))
- v3d->layact = 1 << nr;
- else if ((v3d->lay & v3d->layact) == 0) {
- for (bit = 0; bit < 32; bit++) {
- if (v3d->lay & (1u << bit)) {
- v3d->layact = (1u << bit);
- break;
- }
- }
- }
- }
-
- if (v3d->scenelock) handle_view3d_lock(C);
-
- DAG_on_visible_update(CTX_data_main(C), false);
-
- ED_area_tag_redraw(sa);
-
- return OPERATOR_FINISHED;
-}
-
-/* applies shift and alt, lazy coding or ok? :) */
-/* the local per-keymap-entry keymap will solve it */
-static int view3d_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- if (event->ctrl || event->oskey)
- return OPERATOR_PASS_THROUGH;
-
- if (event->shift)
- RNA_boolean_set(op->ptr, "extend", true);
- else
- RNA_boolean_set(op->ptr, "extend", false);
-
- if (event->alt) {
- const int nr = RNA_int_get(op->ptr, "nr") + 10;
- RNA_int_set(op->ptr, "nr", nr);
- }
- view3d_layers_exec(C, op);
-
+ View3D *v3d = CTX_wm_view3d(C);
+ v3d->shading.flag ^= V3D_SHADING_MATCAP_FLIP_X;
+ ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C));
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
return OPERATOR_FINISHED;
}
-static bool view3d_layers_poll(bContext *C)
-{
- return (ED_operator_view3d_active(C) && CTX_wm_view3d(C)->localvd == NULL);
-}
-
-void VIEW3D_OT_layers(wmOperatorType *ot)
+void VIEW3D_OT_toggle_matcap_flip(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Layers";
- ot->description = "Toggle layer(s) visibility";
- ot->idname = "VIEW3D_OT_layers";
+ ot->name = "Flip MatCap";
+ ot->description = "Flip MatCap";
+ ot->idname = "VIEW3D_OT_toggle_matcap_flip";
/* api callbacks */
- ot->invoke = view3d_layers_invoke;
- ot->exec = view3d_layers_exec;
- ot->poll = view3d_layers_poll;
+ ot->exec = toggle_matcap_flip;
+ ot->poll = ED_operator_view3d_active;
+}
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+/** \} */
- RNA_def_int(ot->srna, "nr", 1, 0, 20, "Number", "The layer number to set, zero for all layers", 0, 20);
- RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Add this layer to the current view layers");
- RNA_def_boolean(ot->srna, "toggle", 1, "Toggle", "Toggle the layer");
-}
static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
{
@@ -278,21 +150,66 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
}
}
+static void uiTemplatePaintModeSelection(uiLayout *layout, struct bContext *C)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+
+ /* Gizmos aren't used in paint modes */
+ if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {
+ /* masks aren't used for sculpt and particle painting */
+ PointerRNA meshptr;
+
+ RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr);
+ if (ob->mode & (OB_MODE_TEXTURE_PAINT)) {
+ uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ }
+ else {
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiItemR(row, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ uiItemR(row, &meshptr, "use_paint_mask_vertex", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ }
+ }
+ }
+}
+
+void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C)
+{
+ /* Extracted from: uiTemplateHeader3D */
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ Object *obedit = CTX_data_edit_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+
+ bool is_paint = (
+ ob && !(gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
+ ELEM(ob->mode,
+ OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT));
+
+ uiTemplateEditModeSelection(layout, C);
+ if ((obedit == NULL) && is_paint) {
+ uiTemplatePaintModeSelection(layout, C);
+ }
+}
+
void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = sa->spacedata.first;
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
ToolSettings *ts = CTX_data_tool_settings(C);
PointerRNA v3dptr, toolsptr, sceneptr;
- Object *ob = OBACT;
+ Object *ob = OBACT(view_layer);
Object *obedit = CTX_data_edit_object(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
uiBlock *block;
- uiLayout *row;
- bool is_paint = false;
- int modeselect;
+ bool is_paint = (
+ ob && !(gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
+ ELEM(ob->mode,
+ OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT));
RNA_pointer_create(&screen->id, &RNA_SpaceView3D, v3d, &v3dptr);
RNA_pointer_create(&scene->id, &RNA_ToolSettings, ts, &toolsptr);
@@ -304,81 +221,39 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
/* other buttons: */
UI_block_emboss_set(block, UI_EMBOSS);
- /* mode */
- if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
- modeselect = OB_MODE_GPENCIL;
- }
- else if (ob) {
- modeselect = ob->mode;
- is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
- }
- else {
- modeselect = OB_MODE_OBJECT;
- }
-
- row = uiLayoutRow(layout, false);
- {
- const EnumPropertyItem *item = rna_enum_object_mode_items;
- const char *name = "";
- int icon = ICON_OBJECT_DATAMODE;
-
- while (item->identifier) {
- if (item->value == modeselect && item->identifier[0]) {
- name = IFACE_(item->name);
- icon = item->icon;
- break;
- }
- item++;
- }
-
- uiItemMenuEnumO(row, C, "OBJECT_OT_mode_set", "mode", name, icon);
- }
-
- /* Draw type */
- uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
-
- row = uiLayoutRow(layout, true);
+ /* moved to topbar */
+#if 0
+ uiLayout *row = uiLayoutRow(layout, true);
uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
if (!ob || ELEM(ob->mode, OB_MODE_OBJECT, OB_MODE_POSE, OB_MODE_WEIGHT_PAINT)) {
uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
}
+#endif
if (obedit == NULL && is_paint) {
- /* Manipulators aren't used in paint modes */
- if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {
- /* masks aren't used for sculpt and particle painting */
- PointerRNA meshptr;
-
- RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr);
- if (ob->mode & (OB_MODE_TEXTURE_PAINT)) {
- uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- }
- else {
- row = uiLayoutRow(layout, true);
- uiItemR(row, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- uiItemR(row, &meshptr, "use_paint_mask_vertex", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- }
- }
+ /* Currently Python calls this directly. */
+#if 0
+ uiTemplatePaintModeSelection(layout, C);
+#endif
+
}
else {
- /* Transform widget / manipulators */
+ /* Moved to popover and topbar. */
+#if 0
+ /* Transform widget / gizmos */
row = uiLayoutRow(layout, true);
- uiItemR(row, &v3dptr, "show_manipulator", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- if (v3d->twflag & V3D_USE_MANIPULATOR) {
- uiItemR(row, &v3dptr, "transform_manipulators", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
- }
- uiItemR(row, &v3dptr, "transform_orientation", 0, "", ICON_NONE);
+ uiItemR(row, &v3dptr, "show_gizmo", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ uiItemR(row, &sceneptr, "transform_orientation", 0, "", ICON_NONE);
+#endif
}
if (obedit == NULL && v3d->localvd == NULL) {
- unsigned int ob_lay = ob ? ob->lay : 0;
-
- /* Layers */
- uiTemplateLayers(layout, v3d->scenelock ? &sceneptr : &v3dptr, "layers", &v3dptr, "layers_used", ob_lay);
-
/* Scene lock */
uiItemR(layout, &v3dptr, "lock_camera_and_layers", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
}
+ /* Currently Python calls this directly. */
+#if 0
uiTemplateEditModeSelection(layout, C);
+#endif
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index be444ce27cd..164c444d9a5 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -37,8 +37,10 @@
struct ARegion;
struct ARegionType;
+struct Base;
struct BoundBox;
-struct DerivedMesh;
+struct GPUBatch;
+struct Depsgraph;
struct Object;
struct SmokeDomainSettings;
struct bAnimVizSettings;
@@ -46,9 +48,12 @@ struct bContext;
struct bMotionPath;
struct bPoseChannel;
struct Mesh;
+struct ViewLayer;
struct wmOperatorType;
-struct wmWindowManager;
struct wmKeyConfig;
+struct wmGizmoGroupType;
+struct wmGizmoType;
+struct wmWindowManager;
/* drawing flags: */
enum {
@@ -57,14 +62,9 @@ enum {
DRAW_SCENESET = (1 << 2)
};
-/* draw_mesh_fancy/draw_mesh_textured draw_flags */
-enum {
- DRAW_MODIFIERS_PREVIEW = (1 << 0),
- DRAW_FACE_SELECT = (1 << 1)
-};
-
/* view3d_header.c */
void VIEW3D_OT_layers(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_matcap_flip(struct wmOperatorType *ot);
/* view3d_ops.c */
void view3d_operatortypes(void);
@@ -82,7 +82,8 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot);
void VIEW3D_OT_ndof_all(struct wmOperatorType *ot);
#endif /* WITH_INPUT_NDOF */
void VIEW3D_OT_view_all(struct wmOperatorType *ot);
-void VIEW3D_OT_viewnumpad(struct wmOperatorType *ot);
+void VIEW3D_OT_view_axis(struct wmOperatorType *ot);
+void VIEW3D_OT_view_camera(struct wmOperatorType *ot);
void VIEW3D_OT_view_selected(struct wmOperatorType *ot);
void VIEW3D_OT_view_lock_clear(struct wmOperatorType *ot);
void VIEW3D_OT_view_lock_to_active(struct wmOperatorType *ot);
@@ -97,17 +98,16 @@ void VIEW3D_OT_background_image_add(struct wmOperatorType *ot);
void VIEW3D_OT_background_image_remove(struct wmOperatorType *ot);
void VIEW3D_OT_view_orbit(struct wmOperatorType *ot);
void VIEW3D_OT_view_roll(struct wmOperatorType *ot);
-void VIEW3D_OT_clip_border(struct wmOperatorType *ot);
+// void VIEW3D_OT_clip_border(struct wmOperatorType *ot);
void VIEW3D_OT_cursor3d(struct wmOperatorType *ot);
-void VIEW3D_OT_manipulator(struct wmOperatorType *ot);
-void VIEW3D_OT_enable_manipulator(struct wmOperatorType *ot);
void VIEW3D_OT_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
-void VIEW3D_OT_toggle_render(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot);
-void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
-void view3d_boxview_sync(ScrArea *sa, ARegion *ar);
+void view3d_boxview_copy(struct ScrArea *sa, struct ARegion *ar);
+void view3d_boxview_sync(struct ScrArea *sa, struct ARegion *ar);
void view3d_orbit_apply_dyn_ofs(
float r_ofs[3], const float ofs_old[3], const float viewquat_old[4],
@@ -133,104 +133,51 @@ void VIEW3D_OT_walk(struct wmOperatorType *ot);
/* view3d_ruler.c */
void VIEW3D_OT_ruler(struct wmOperatorType *ot);
-/* drawanim.c */
-void draw_motion_paths_init(View3D *v3d, struct ARegion *ar);
-void draw_motion_path_instance(Scene *scene,
- struct Object *ob, struct bPoseChannel *pchan,
- struct bAnimVizSettings *avs, struct bMotionPath *mpath);
-void draw_motion_paths_cleanup(View3D *v3d);
-
-
-
/* drawobject.c */
-void draw_object(
- struct Main *bmain, Scene *scene, struct ARegion *ar, View3D *v3d,
- Base *base, const short dflag);
-void draw_object_select(
- struct Main *bmain, Scene *scene, ARegion *ar, View3D *v3d,
- Base *base, const short dflag);
-
-bool draw_glsl_material(Scene *scene, struct Object *ob, View3D *v3d, const char dt);
-void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline);
-void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob);
-void drawaxes(const float viewmat_local[4][4], float size, char drawtype);
-
-void view3d_cached_text_draw_begin(void);
-void view3d_cached_text_draw_add(const float co[3],
- const char *str, const size_t str_len,
- short xoffs, short flag, const unsigned char col[4]);
-void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write);
-
-bool check_object_draw_texture(struct Scene *scene, struct View3D *v3d, const char drawtype);
-
-enum {
- V3D_CACHE_TEXT_ZBUF = (1 << 0),
- V3D_CACHE_TEXT_WORLDSPACE = (1 << 1),
- V3D_CACHE_TEXT_ASCII = (1 << 2),
- V3D_CACHE_TEXT_GLOBALSPACE = (1 << 3),
- V3D_CACHE_TEXT_LOCALCLIP = (1 << 4)
-};
+void draw_object_backbufsel(
+ struct Depsgraph *depsgraph, Scene *scene,
+ View3D *v3d, RegionView3D *rv3d, struct Object *ob,
+ short select_mode);
int view3d_effective_drawtype(const struct View3D *v3d);
-/* drawarmature.c */
-bool draw_armature(
- Scene *scene, View3D *v3d, ARegion *ar, Base *base,
- const short dt, const short dflag, const unsigned char ob_wire_col[4],
- const bool is_outline);
-
-/* drawmesh.c */
-void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
- struct Object *ob, struct DerivedMesh *dm, const int draw_flags);
-void draw_mesh_face_select(
- struct RegionView3D *rv3d, struct Mesh *me, struct DerivedMesh *dm,
- bool draw_select_edges);
-void draw_mesh_paint_weight_faces(struct DerivedMesh *dm, const bool do_light,
- void *facemask_cb, void *user_data);
-void draw_mesh_paint_vcolor_faces(struct DerivedMesh *dm, const bool use_light,
- void *facemask_cb, void *user_data,
- const struct Mesh *me);
-void draw_mesh_paint_weight_edges(RegionView3D *rv3d, struct DerivedMesh *dm,
- const bool use_depth, const bool use_alpha,
- void *edgemask_cb, void *user_data);
-void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
- struct Object *ob, struct DerivedMesh *dm, const int draw_flags);
-
-/* drawsimdebug.c */
-void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar);
-
/* view3d_draw.c */
void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar);
+void view3d_draw_region_info(const struct bContext *C, struct ARegion *ar);
void ED_view3d_draw_depth(
- struct Main *bmain, struct Scene *scene,
+ struct Depsgraph *depsgraph,
struct ARegion *ar, View3D *v3d, bool alphaoverride);
-void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d);
+
+/* view3d_draw_legacy.c */
+void ED_view3d_draw_depth_gpencil(struct Depsgraph *depsgraph, Scene *scene, struct ARegion *ar, View3D *v3d);
+
void ED_view3d_draw_select_loop(
- ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar,
+ struct Depsgraph *depsgraph, ViewContext *vc, Scene *scene, struct ViewLayer *view_layer, View3D *v3d, struct ARegion *ar,
bool use_obedit_skip, bool use_nearest);
-void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);\
+void ED_view3d_draw_depth_loop(
+ struct Depsgraph *depsgraph, Scene *scene, struct ARegion *ar, View3D *v3d);
+
+void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);
-void circf(float x, float y, float rad);
-void circ(float x, float y, float rad);
void view3d_update_depths_rect(struct ARegion *ar, struct ViewDepths *d, struct rcti *rect);
float view3d_depth_near(struct ViewDepths *d);
/* view3d_select.c */
void VIEW3D_OT_select(struct wmOperatorType *ot);
void VIEW3D_OT_select_circle(struct wmOperatorType *ot);
-void VIEW3D_OT_select_border(struct wmOperatorType *ot);
+void VIEW3D_OT_select_box(struct wmOperatorType *ot);
void VIEW3D_OT_select_lasso(struct wmOperatorType *ot);
void VIEW3D_OT_select_menu(struct wmOperatorType *ot);
+/* view3d_view.c */
void VIEW3D_OT_smoothview(struct wmOperatorType *ot);
void VIEW3D_OT_camera_to_view(struct wmOperatorType *ot);
void VIEW3D_OT_camera_to_view_selected(struct wmOperatorType *ot);
void VIEW3D_OT_object_as_camera(struct wmOperatorType *ot);
void VIEW3D_OT_localview(struct wmOperatorType *ot);
-void VIEW3D_OT_game_start(struct wmOperatorType *ot);
-
+void VIEW3D_OT_localview_remove_from(struct wmOperatorType *ot);
bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]);
bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb);
@@ -243,6 +190,7 @@ typedef struct V3D_SmoothParams {
} V3D_SmoothParams;
void ED_view3d_smooth_view_ex(
+ const struct Depsgraph *depsgraph,
struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa,
struct View3D *v3d, struct ARegion *ar, const int smooth_viewtx,
const V3D_SmoothParams *sview);
@@ -257,9 +205,10 @@ void ED_view3d_smooth_view_force_finish(
struct View3D *v3d, struct ARegion *ar);
void view3d_winmatrix_set(
- ARegion *ar, const View3D *v3d, const rcti *rect);
+ struct Depsgraph *depsgraph,
+ struct ARegion *ar, const View3D *v3d, const rcti *rect);
void view3d_viewmatrix_set(
- Scene *scene,
+ struct Depsgraph *depsgraph, Scene *scene,
const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
@@ -271,11 +220,12 @@ void viewdolly_modal_keymap(struct wmKeyConfig *keyconf);
/* view3d_buttons.c */
void VIEW3D_OT_properties(struct wmOperatorType *ot);
+void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot);
void view3d_buttons_register(struct ARegionType *art);
/* view3d_camera_control.c */
struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
- Scene *scene, View3D *v3d, RegionView3D *rv3d,
+ struct Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d,
const bool use_parent_root);
void ED_view3d_cameracontrol_update(
struct View3DCameraControl *vctrl,
@@ -284,13 +234,11 @@ void ED_view3d_cameracontrol_update(
void ED_view3d_cameracontrol_release(
struct View3DCameraControl *vctrl,
const bool restore);
-Object *ED_view3d_cameracontrol_object_get(
+struct Object *ED_view3d_cameracontrol_object_get(
struct View3DCameraControl *vctrl);
/* view3d_toolbar.c */
void VIEW3D_OT_toolshelf(struct wmOperatorType *ot);
-void view3d_toolshelf_register(struct ARegionType *art);
-void view3d_tool_props_register(struct ARegionType *art);
/* view3d_snap.c */
bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]);
@@ -304,11 +252,30 @@ void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot);
/* space_view3d.c */
-ARegion *view3d_has_buttons_region(ScrArea *sa);
-ARegion *view3d_has_tools_region(ScrArea *sa);
+struct ARegion *view3d_has_buttons_region(struct ScrArea *sa);
+struct ARegion *view3d_has_tools_region(struct ScrArea *sa);
extern const char *view3d_context_dir[]; /* doc access */
+/* view3d_widgets.c */
+void VIEW3D_GGT_lamp_spot(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_lamp_area(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_lamp_target(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_camera(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_camera_view(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_force_field(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_empty_image(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_armature_spline(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_navigate(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_mesh_preselect_elem(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GGT_mesh_preselect_edgering(struct wmGizmoGroupType *gzgt);
+
+void VIEW3D_GGT_ruler(struct wmGizmoGroupType *gzgt);
+void VIEW3D_GT_ruler_item(struct wmGizmoType *gzt);
+void VIEW3D_OT_ruler_add(struct wmOperatorType *ot);
+
+void VIEW3D_GT_navigate_rotate(struct wmGizmoType *gzt);
+
/* draw_volume.c */
void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob,
const float min[3], const float max[3],
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index ef7b01f7a21..3d0b0a7a348 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -28,6 +28,7 @@
#include "DNA_lattice_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -35,11 +36,18 @@
#include "BLI_utildefines.h"
#include "BLI_rect.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
+#include "BKE_context.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_iterators.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "bmesh.h"
@@ -109,7 +117,9 @@ void meshobject_foreachScreenVert(
void *userData, eV3DProjTest clip_flag)
{
foreachScreenObjectVert_userData data;
- DerivedMesh *dm = mesh_get_derived_deform(vc->scene, vc->obact, CD_MASK_BAREMESH);
+ Mesh *me;
+
+ me = mesh_get_eval_deform(vc->depsgraph, vc->scene, vc->obact, CD_MASK_BAREMESH);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -122,9 +132,7 @@ void meshobject_foreachScreenVert(
ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat);
}
- dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data, DM_FOREACH_NOP);
-
- dm->release(dm);
+ BKE_mesh_foreach_mapped_vert(me, meshobject_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP);
}
static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3],
@@ -150,7 +158,8 @@ void mesh_foreachScreenVert(
void *userData, eV3DProjTest clip_flag)
{
foreachScreenVert_userData data;
- DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+
+ Mesh *me = editbmesh_get_eval_cage(vc->depsgraph, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -164,9 +173,7 @@ void mesh_foreachScreenVert(
}
BM_mesh_elem_table_ensure(vc->em->bm, BM_VERT);
- dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data, DM_FOREACH_NOP);
-
- dm->release(dm);
+ BKE_mesh_foreach_mapped_vert(me, mesh_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP);
}
/* ------------------------------------------------------------------------ */
@@ -204,7 +211,8 @@ void mesh_foreachScreenEdge(
void *userData, eV3DProjTest clip_flag)
{
foreachScreenEdge_userData data;
- DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+
+ Mesh *me = editbmesh_get_eval_cage(vc->depsgraph, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -224,9 +232,7 @@ void mesh_foreachScreenEdge(
}
BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE);
- dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
-
- dm->release(dm);
+ BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data);
}
/* ------------------------------------------------------------------------ */
@@ -250,8 +256,8 @@ void mesh_foreachScreenFace(
void *userData, const eV3DProjTest clip_flag)
{
foreachScreenFace_userData data;
- DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ Mesh *me = editbmesh_get_eval_cage(vc->depsgraph, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
ED_view3d_check_mats_rv3d(vc->rv3d);
data.vc = *vc;
@@ -260,9 +266,7 @@ void mesh_foreachScreenFace(
data.clip_flag = clip_flag;
BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
- dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data, DM_FOREACH_NOP);
-
- dm->release(dm);
+ BKE_mesh_foreach_mapped_face_center(me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
}
/* ------------------------------------------------------------------------ */
@@ -291,7 +295,7 @@ void nurbs_foreachScreenVert(
if (bezt->hide == 0) {
float screen_co[2];
- if (cu->drawflag & CU_HIDE_HANDLES) {
+ if ((vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
if (ED_view3d_project_float_object(vc->ar, bezt->vec[1], screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK)
{
@@ -366,7 +370,7 @@ void lattice_foreachScreenVert(
Object *obedit = vc->obedit;
Lattice *lt = obedit->data;
BPoint *bp = lt->editlatt->latt->def;
- DispList *dl = obedit->curve_cache ? BKE_displist_find(&obedit->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = obedit->runtime.curve_cache ? BKE_displist_find(&obedit->runtime.curve_cache->disp, DL_VERTS) : NULL;
const float *co = dl ? dl->verts : NULL;
int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
@@ -438,19 +442,21 @@ void pose_foreachScreenBone(
void (*func)(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]),
void *userData, const eV3DProjTest clip_flag)
{
- bArmature *arm = vc->obact->data;
+ const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
+ const bArmature *arm_eval = ob_eval->data;
bPose *pose = vc->obact->pose;
bPoseChannel *pchan;
ED_view3d_check_mats_rv3d(vc->rv3d);
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_VISIBLE(arm, pchan->bone)) {
+ if (PBONE_VISIBLE(arm_eval, pchan->bone)) {
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
float screen_co_a[2], screen_co_b[2];
int points_proj_tot = 0;
/* project head location to screenspace */
- if (ED_view3d_project_float_object(vc->ar, pchan->pose_head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_object(vc->ar, pchan_eval->pose_head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) {
points_proj_tot++;
}
else {
@@ -459,7 +465,7 @@ void pose_foreachScreenBone(
}
/* project tail location to screenspace */
- if (ED_view3d_project_float_object(vc->ar, pchan->pose_tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_object(vc->ar, pchan_eval->pose_tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) {
points_proj_tot++;
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 5d662282e56..7e4f04feaef 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -33,8 +33,8 @@
#include <math.h>
+#include "DNA_collection_types.h"
#include "DNA_object_types.h"
-#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -45,6 +45,7 @@
#include "BKE_appdir.h"
#include "BKE_blender_copybuffer.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -56,6 +57,7 @@
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
#include "view3d_intern.h"
@@ -80,12 +82,14 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- for (Group *group = bmain->group.first; group; group = group->id.next) {
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- if (go->ob && (go->ob->id.tag & LIB_TAG_DOIT)) {
- BKE_copybuffer_tag_ID(&group->id);
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Object *object = cob->ob;
+
+ if (object && (object->id.tag & LIB_TAG_DOIT)) {
+ BKE_copybuffer_tag_ID(&collection->id);
/* don't expand out to all other objects */
- group->id.tag &= ~LIB_TAG_NEED_EXPAND;
+ collection->id.tag &= ~LIB_TAG_NEED_EXPAND;
break;
}
}
@@ -119,8 +123,8 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "autoselect"))
flag |= FILE_AUTOSELECT;
- if (RNA_boolean_get(op->ptr, "active_layer"))
- flag |= FILE_ACTIVELAY;
+ if (RNA_boolean_get(op->ptr, "active_collection"))
+ flag |= FILE_ACTIVE_COLLECTION;
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
if (BKE_copybuffer_paste(C, str, flag, op->reports)) {
@@ -152,7 +156,7 @@ static void VIEW3D_OT_pastebuffer(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "autoselect", true, "Select", "Select pasted objects");
- RNA_def_boolean(ot->srna, "active_layer", true, "Active Layer", "Put pasted objects on the active layer");
+ RNA_def_boolean(ot->srna, "active_collection", true, "Active Collection", "Put pasted objects on the active collection");
}
/* ************************** registration **********************************/
@@ -171,7 +175,8 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_ndof_all);
#endif /* WITH_INPUT_NDOF */
WM_operatortype_append(VIEW3D_OT_view_all);
- WM_operatortype_append(VIEW3D_OT_viewnumpad);
+ WM_operatortype_append(VIEW3D_OT_view_axis);
+ WM_operatortype_append(VIEW3D_OT_view_camera);
WM_operatortype_append(VIEW3D_OT_view_orbit);
WM_operatortype_append(VIEW3D_OT_view_roll);
WM_operatortype_append(VIEW3D_OT_view_pan);
@@ -186,15 +191,13 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_view_center_camera);
WM_operatortype_append(VIEW3D_OT_view_center_lock);
WM_operatortype_append(VIEW3D_OT_select);
- WM_operatortype_append(VIEW3D_OT_select_border);
- WM_operatortype_append(VIEW3D_OT_clip_border);
+ WM_operatortype_append(VIEW3D_OT_select_box);
+ // WM_operatortype_append(VIEW3D_OT_clip_border);
WM_operatortype_append(VIEW3D_OT_select_circle);
WM_operatortype_append(VIEW3D_OT_smoothview);
WM_operatortype_append(VIEW3D_OT_render_border);
WM_operatortype_append(VIEW3D_OT_clear_render_border);
WM_operatortype_append(VIEW3D_OT_zoom_border);
- WM_operatortype_append(VIEW3D_OT_manipulator);
- WM_operatortype_append(VIEW3D_OT_enable_manipulator);
WM_operatortype_append(VIEW3D_OT_cursor3d);
WM_operatortype_append(VIEW3D_OT_select_lasso);
WM_operatortype_append(VIEW3D_OT_select_menu);
@@ -202,16 +205,16 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_camera_to_view_selected);
WM_operatortype_append(VIEW3D_OT_object_as_camera);
WM_operatortype_append(VIEW3D_OT_localview);
- WM_operatortype_append(VIEW3D_OT_game_start);
+ WM_operatortype_append(VIEW3D_OT_localview_remove_from);
WM_operatortype_append(VIEW3D_OT_fly);
WM_operatortype_append(VIEW3D_OT_walk);
WM_operatortype_append(VIEW3D_OT_navigate);
WM_operatortype_append(VIEW3D_OT_ruler);
- WM_operatortype_append(VIEW3D_OT_layers);
WM_operatortype_append(VIEW3D_OT_copybuffer);
WM_operatortype_append(VIEW3D_OT_pastebuffer);
WM_operatortype_append(VIEW3D_OT_properties);
+ WM_operatortype_append(VIEW3D_OT_object_mode_pie_or_toggle);
WM_operatortype_append(VIEW3D_OT_toolshelf);
WM_operatortype_append(VIEW3D_OT_snap_selected_to_grid);
@@ -222,334 +225,21 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active);
- WM_operatortype_append(VIEW3D_OT_toggle_render);
+ WM_operatortype_append(VIEW3D_OT_toggle_shading);
+ WM_operatortype_append(VIEW3D_OT_toggle_xray);
+ WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip);
+
+ WM_operatortype_append(VIEW3D_OT_ruler_add);
transform_operatortypes();
}
void view3d_keymap(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap;
- wmKeyMapItem *kmi;
-
- keymap = WM_keymap_ensure(keyconf, "3D View Generic", SPACE_VIEW3D, 0);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_properties", NKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_toolshelf", TKEY, KM_PRESS, 0, 0);
+ WM_keymap_ensure(keyconf, "3D View Generic", SPACE_VIEW3D, 0);
/* only for region 3D window */
- keymap = WM_keymap_ensure(keyconf, "3D View", SPACE_VIEW3D, 0);
-
- /* Shift+LMB behavior first, so it has priority over KM_ANY item below. */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- RNA_boolean_set(kmi->ptr, "use_planar_constraint", true);
- RNA_boolean_set(kmi->ptr, "use_accurate", false);
-
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- RNA_boolean_set(kmi->ptr, "use_planar_constraint", false);
- RNA_boolean_set(kmi->ptr, "use_accurate", true);
-
- /* Using KM_ANY here to allow holding modifiers before starting to transform. */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- RNA_boolean_set(kmi->ptr, "use_planar_constraint", false);
- RNA_boolean_set(kmi->ptr, "use_accurate", false);
-
- WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_PRESS, 0, 0);
-
- WM_keymap_verify_item(keymap, "VIEW3D_OT_rotate", MIDDLEMOUSE, KM_PRESS, 0, 0);
- WM_keymap_verify_item(keymap, "VIEW3D_OT_move", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_verify_item(keymap, "VIEW3D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "VIEW3D_OT_dolly", MIDDLEMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", PADPERIOD, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "use_all_regions", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_all_regions", false);
-
- WM_keymap_verify_item(keymap, "VIEW3D_OT_view_lock_to_active", PADPERIOD, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_verify_item(keymap, "VIEW3D_OT_view_lock_clear", PADPERIOD, KM_PRESS, KM_ALT, 0);
-
- WM_keymap_verify_item(keymap, "VIEW3D_OT_navigate", FKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, 0, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEROTATE, 0, 0, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEZOOM, 0, 0, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0);
-
- /*numpad +/-*/
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADPLUSKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADMINUS, KM_PRESS, 0, 0)->ptr, "delta", -1);
- /*ctrl +/-*/
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", EQUALKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MINUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
-
- /*wheel mouse forward/back*/
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", WHEELINMOUSE, KM_PRESS, 0, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", WHEELOUTMOUSE, KM_PRESS, 0, 0)->ptr, "delta", -1);
-
- /* ... and for dolly */
- /*numpad +/-*/
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_dolly", PADPLUSKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_dolly", PADMINUS, KM_PRESS, KM_SHIFT, 0)->ptr, "delta", -1);
- /*ctrl +/-*/
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_dolly", EQUALKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "delta", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_dolly", MINUSKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "delta", -1);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_zoom_camera_1_to_1", PADENTER, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_view_center_camera", HOMEKEY, KM_PRESS, 0, 0); /* only with camera view */
- WM_keymap_add_item(keymap, "VIEW3D_OT_view_center_lock", HOMEKEY, KM_PRESS, 0, 0); /* only with lock view */
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_view_center_cursor", HOMEKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_view_center_pick", FKEY, KM_PRESS, KM_ALT, 0);
-
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "center", false); /* only without camera view */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", HOMEKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "use_all_regions", true);
- RNA_boolean_set(kmi->ptr, "center", false); /* only without camera view */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", CKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "center", true);
-
- /* numpad view hotkeys*/
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD0, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_CAMERA);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD2, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPDOWN);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD3, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD4, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
- WM_keymap_add_item(keymap, "VIEW3D_OT_view_persportho", PAD5, KM_PRESS, 0, 0);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD6, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD7, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD8, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPUP);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_CTRL, 0)->ptr, "type", RV3D_VIEW_BACK);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD3, KM_PRESS, KM_CTRL, 0)->ptr, "type", RV3D_VIEW_LEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD7, KM_PRESS, KM_CTRL, 0)->ptr, "type", RV3D_VIEW_BOTTOM);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD2, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANDOWN);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD4, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD6, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANUP);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD9, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "type", V3D_VIEW_STEPRIGHT);
- RNA_float_set(kmi->ptr, "angle", (float)M_PI);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_PANUP);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_PANDOWN);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELUPMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPUP);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPDOWN);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
-
- /* active aligned, replaces '*' key in 2.4x */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT);
- RNA_boolean_set(kmi->ptr, "align_active", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD3, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT);
- RNA_boolean_set(kmi->ptr, "align_active", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD7, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP);
- RNA_boolean_set(kmi->ptr, "align_active", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_BACK);
- RNA_boolean_set(kmi->ptr, "align_active", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD3, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_LEFT);
- RNA_boolean_set(kmi->ptr, "align_active", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD7, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_BOTTOM);
- RNA_boolean_set(kmi->ptr, "align_active", true);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_localview", PADSLASHKEY, KM_PRESS, 0, 0);
-
-#ifdef WITH_INPUT_NDOF
- /* note: positioned here so keymaps show keyboard keys if assigned */
- /* 3D mouse */
- WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit_zoom", NDOF_MOTION, 0, 0, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "use_all_regions", false);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
-
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP);
- RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM);
-
- /* 3D mouse align */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT);
- RNA_boolean_set(kmi->ptr, "align_active", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT);
- RNA_boolean_set(kmi->ptr, "align_active", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP);
- RNA_boolean_set(kmi->ptr, "align_active", true);
-#endif /* WITH_INPUT_NDOF */
-
- /* layers, shift + alt are properties set in invoke() */
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ACCENTGRAVEKEY, KM_PRESS, 0, 0)->ptr, "nr", 0);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ONEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 1);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", TWOKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 2);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", THREEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 3);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", FOURKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 4);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", FIVEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 5);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", SIXKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 6);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", SEVENKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 7);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", EIGHTKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 8);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", NINEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 9);
- RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ZEROKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 10);
-
- /* drawtype */
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.viewport_shade");
- RNA_string_set(kmi->ptr, "value_1", "SOLID");
- RNA_string_set(kmi->ptr, "value_2", "WIREFRAME");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, KM_ALT, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.viewport_shade");
- RNA_string_set(kmi->ptr, "value_1", "SOLID");
- RNA_string_set(kmi->ptr, "value_2", "TEXTURED");
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_toggle_render", ZKEY, KM_PRESS, KM_SHIFT, 0);
-
- /* selection*/
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", false);
- RNA_boolean_set(kmi->ptr, "center", false);
- RNA_boolean_set(kmi->ptr, "object", false);
- RNA_boolean_set(kmi->ptr, "enumerate", false);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", true);
- RNA_boolean_set(kmi->ptr, "center", false);
- RNA_boolean_set(kmi->ptr, "object", false);
- RNA_boolean_set(kmi->ptr, "enumerate", false);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", false);
- RNA_boolean_set(kmi->ptr, "center", true);
- RNA_boolean_set(kmi->ptr, "object", true); /* use Ctrl+Select for 2 purposes */
- RNA_boolean_set(kmi->ptr, "enumerate", false);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", false);
- RNA_boolean_set(kmi->ptr, "center", false);
- RNA_boolean_set(kmi->ptr, "object", false);
- RNA_boolean_set(kmi->ptr, "enumerate", true);
-
- /* selection key-combinations */
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", true);
- RNA_boolean_set(kmi->ptr, "center", true);
- RNA_boolean_set(kmi->ptr, "object", false);
- RNA_boolean_set(kmi->ptr, "enumerate", false);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", false);
- RNA_boolean_set(kmi->ptr, "center", true);
- RNA_boolean_set(kmi->ptr, "object", false);
- RNA_boolean_set(kmi->ptr, "enumerate", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", true);
- RNA_boolean_set(kmi->ptr, "center", false);
- RNA_boolean_set(kmi->ptr, "object", false);
- RNA_boolean_set(kmi->ptr, "enumerate", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- RNA_boolean_set(kmi->ptr, "toggle", true);
- RNA_boolean_set(kmi->ptr, "center", true);
- RNA_boolean_set(kmi->ptr, "object", false);
- RNA_boolean_set(kmi->ptr, "enumerate", true);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
- WM_keymap_add_item(keymap, "VIEW3D_OT_select_circle", CKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_clip_border", BKEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_zoom_border", BKEY, KM_PRESS, KM_SHIFT, 0);
-
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_render_border", BKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "camera_only", true);
- kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_render_border", BKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "camera_only", false);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_clear_render_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
-
- WM_keymap_add_item(keymap, "VIEW3D_OT_camera_to_view", PAD0, KM_PRESS, KM_ALT | KM_CTRL, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_object_as_camera", PAD0, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_menu(keymap, "VIEW3D_MT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
-
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "VIEW3D_OT_copybuffer", CKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_pastebuffer", VKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
- WM_keymap_add_item(keymap, "VIEW3D_OT_copybuffer", CKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "VIEW3D_OT_pastebuffer", VKEY, KM_PRESS, KM_CTRL, 0);
-
- /* context ops */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "BOUNDING_BOX_CENTER");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, KM_CTRL, 0); /* 2.4x allowed Comma+Shift too, rather not use both */
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "MEDIAN_POINT");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", COMMAKEY, KM_PRESS, KM_ALT, 0); /* new in 2.5 */
- RNA_string_set(kmi->ptr, "data_path", "space_data.use_pivot_point_align");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SPACEKEY, KM_PRESS, KM_CTRL, 0); /* new in 2.5 */
- RNA_string_set(kmi->ptr, "data_path", "space_data.show_manipulator");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "CURSOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "INDIVIDUAL_ORIGINS");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, KM_ALT, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
- RNA_string_set(kmi->ptr, "value", "ACTIVE_ELEMENT");
-
- transform_keymap_for_space(keyconf, keymap, SPACE_VIEW3D);
+ WM_keymap_ensure(keyconf, "3D View", SPACE_VIEW3D, 0);
fly_modal_keymap(keyconf);
walk_modal_keymap(keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 3cc0857c8a7..116f4af34e5 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -36,14 +36,13 @@
#include "BLI_sys_types.h" /* int64_t */
-#include "BIF_gl.h" /* bglMats */
-#include "BIF_glutil.h" /* bglMats */
-
#include "BLI_math_vector.h"
#include "BKE_camera.h"
#include "BKE_screen.h"
+#include "GPU_matrix.h"
+
#include "ED_view3d.h" /* own include */
#define BL_NEAR_CLIP 0.001
@@ -315,6 +314,7 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
}
static void view3d_win_to_ray_segment(
+ struct Depsgraph *depsgraph,
const ARegion *ar, const View3D *v3d, const float mval[2],
float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
{
@@ -332,7 +332,7 @@ static void view3d_win_to_ray_segment(
start_offset = -end_offset;
}
else {
- ED_view3d_clip_range_get(v3d, rv3d, &start_offset, &end_offset, false);
+ ED_view3d_clip_range_get(depsgraph, v3d, rv3d, &start_offset, &end_offset, false);
}
if (r_ray_start) {
@@ -371,12 +371,13 @@ bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float
* \return success, false if the ray is totally clipped.
*/
bool ED_view3d_win_to_ray_clipped_ex(
+ struct Depsgraph *depsgraph,
const ARegion *ar, const View3D *v3d, const float mval[2],
float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip_planes)
{
float ray_end[3];
- view3d_win_to_ray_segment(ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end);
+ view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end);
/* bounds clipping */
if (do_clip_planes) {
@@ -400,10 +401,11 @@ bool ED_view3d_win_to_ray_clipped_ex(
* \return success, false if the ray is totally clipped.
*/
bool ED_view3d_win_to_ray_clipped(
+ struct Depsgraph *depsgraph,
const ARegion *ar, const View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_normal[3], const bool do_clip_planes)
{
- return ED_view3d_win_to_ray_clipped_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes);
+ return ED_view3d_win_to_ray_clipped_ex(depsgraph, ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes);
}
/**
@@ -677,10 +679,11 @@ void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3
* \return success, false if the segment is totally clipped.
*/
bool ED_view3d_win_to_segment_clipped(
+ struct Depsgraph *depsgraph,
const ARegion *ar, View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_end[3], const bool do_clip_planes)
{
- view3d_win_to_ray_segment(ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end);
+ view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end);
/* bounds clipping */
if (do_clip_planes) {
@@ -710,16 +713,22 @@ void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d, float obm
}
/**
- * Uses window coordinates (x,y) and depth component z to find a point in
- * modelspace */
-void ED_view3d_unproject(bglMats *mats, float out[3], const float x, const float y, const float z)
+ * Convert between region relative coordinates (x,y) and depth component z and
+ * a point in world space. */
+void ED_view3d_project(const struct ARegion *ar, const float world[3], float region[3])
{
- double ux, uy, uz;
+ // viewport is set up to make coordinates relative to the region, not window
+ RegionView3D *rv3d = ar->regiondata;
+ int viewport[4] = {0, 0, ar->winx, ar->winy};
- gluUnProject(x, y, z, mats->modelview, mats->projection,
- (GLint *)mats->viewport, &ux, &uy, &uz);
+ GPU_matrix_project(world, rv3d->viewmat, rv3d->winmat, viewport, region);
+}
+
+bool ED_view3d_unproject(const struct ARegion *ar, float regionx, float regiony, float regionz, float world[3])
+{
+ RegionView3D *rv3d = ar->regiondata;
+ int viewport[4] = {0, 0, ar->winx, ar->winy};
+ float region[3] = {regionx, regiony, regionz};
- out[0] = ux;
- out[1] = uy;
- out[2] = uz;
+ return GPU_matrix_unproject(region, rv3d->viewmat, rv3d->winmat, viewport, world);
}
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index f51b47032aa..208f147f943 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -26,9 +26,11 @@
/* defines VIEW3D_OT_ruler modal operator */
+#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_brush_types.h"
#include "MEM_guardedalloc.h"
@@ -40,13 +42,19 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_unit.h"
#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_state.h"
+
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_gpencil.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_transform_snap_object_context.h"
@@ -151,7 +159,6 @@ static void ruler_item_active_set(RulerInfo *ruler_info, RulerItem *ruler_item)
static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit,
char *numstr, size_t numstr_size, int prec)
{
- const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
if (ruler_item->flag & RULERITEM_USE_ANGLE) {
const float ruler_angle = angle_v3v3v3(ruler_item->co[0],
@@ -162,9 +169,9 @@ static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit,
BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle));
}
else {
- bUnit_AsString(numstr, numstr_size,
- (double)ruler_angle,
- prec, unit->system, B_UNIT_ROTATION, do_split, false);
+ bUnit_AsString2(
+ numstr, numstr_size, (double)ruler_angle,
+ prec, B_UNIT_ROTATION, unit, false);
}
}
else {
@@ -175,9 +182,9 @@ static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit,
BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len);
}
else {
- bUnit_AsString(numstr, numstr_size,
- (double)(ruler_len * unit->scale_length),
- prec, unit->system, B_UNIT_LENGTH, do_split, false);
+ bUnit_AsString2(
+ numstr, numstr_size, (double)(ruler_len * unit->scale_length),
+ prec, B_UNIT_LENGTH, unit, false);
}
}
@@ -265,6 +272,7 @@ static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2],
*/
static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
{
+ Main *bmain = CTX_data_main(C);
if (state == ruler_info->state) {
return;
}
@@ -280,7 +288,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
}
else if (state == RULER_STATE_DRAG) {
ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), 0,
+ bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0,
ruler_info->ar, CTX_wm_view3d(C));
}
else {
@@ -295,38 +303,29 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+
bGPDlayer *gpl;
bGPDframe *gpf;
bGPDstroke *gps;
- bGPDpalette *palette;
- bGPDpalettecolor *palcolor;
RulerItem *ruler_item;
const char *ruler_name = RULER_ID;
bool changed = false;
+ /* FIXME: This needs to be reviewed. Should it keep being done like this? */
if (scene->gpd == NULL) {
- scene->gpd = BKE_gpencil_data_addnew(bmain, "GPencil");
+ scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
}
+ bGPdata *gpd = scene->gpd;
- gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info));
if (gpl == NULL) {
- gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false);
+ gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false);
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
gpl->thickness = 1;
gpl->flag |= GP_LAYER_HIDE;
}
- /* try to get active palette or create a new one */
- palette = BKE_gpencil_palette_getactive(scene->gpd);
- if (palette == NULL) {
- palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true);
- }
- /* try to get color with the ruler name or create a new one */
- palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name);
- if (palcolor == NULL) {
- palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true);
- }
-
- gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
BKE_gpencil_free_strokes(gpf);
for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) {
@@ -357,9 +356,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
}
gps->flag = GP_STROKE_3DSPACE;
gps->thickness = 3;
- /* assign color to stroke */
- BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
- gps->palcolor = palcolor;
+
BLI_addtail(&gpf->strokes, gps);
changed = true;
}
@@ -378,7 +375,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 = BKE_gpencil_layer_getframe(gpl, CFRA, false);
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
if (gpf) {
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
@@ -422,20 +419,19 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
// ARegion *ar = ruler_info->ar;
const float cap_size = 4.0f;
const float bg_margin = 4.0f * U.pixelsize;
- const float bg_radius = 4.0f * U.pixelsize;
const float arc_size = 64.0f * U.pixelsize;
#define ARC_STEPS 24
const int arc_steps = ARC_STEPS;
int i;
- //unsigned int color_act = 0x666600;
- unsigned int color_act = 0xffffff;
- unsigned int color_base = 0x0;
- unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80};
+ const float color_act[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float color_base[4] = {0.0f, 0.0f, 0.0f, 1.0f};
unsigned char color_text[3];
unsigned char color_wire[3];
+ float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f};
/* anti-aliased lines for more consistent appearance */
- glEnable(GL_LINE_SMOOTH);
+ GPU_line_smooth(true);
+ GPU_line_width(1.0f);
BLF_enable(blf_mono_font, BLF_ROTATION);
BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi);
@@ -444,6 +440,11 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
UI_GetThemeColor3ubv(TH_TEXT, color_text);
UI_GetThemeColor3ubv(TH_WIRE, color_wire);
+ /* Avoid white on white text. (TODO Fix by using theme) */
+ if ((int)color_text[0] + (int)color_text[1] + (int)color_text[2] > 127 * 3 * 0.6f) {
+ copy_v3_fl(color_back, 0.0f);
+ }
+
for (ruler_item = ruler_info->items.first, i = 0; ruler_item; ruler_item = ruler_item->next, i++) {
const bool is_act = (i == ruler_info->item_active);
float dir_ruler[2];
@@ -455,30 +456,39 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
}
- glEnable(GL_BLEND);
+ GPU_blend(true);
- cpack(is_act ? color_act : color_base);
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (ruler_item->flag & RULERITEM_USE_ANGLE) {
- glBegin(GL_LINE_STRIP);
- for (j = 0; j < 3; j++) {
- glVertex2fv(co_ss[j]);
- }
- glEnd();
- cpack(0xaaaaaa);
- setlinestyle(3);
- glBegin(GL_LINE_STRIP);
- for (j = 0; j < 3; j++) {
- glVertex2fv(co_ss[j]);
- }
- glEnd();
- setlinestyle(0);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float *col = is_act ? color_act : color_base;
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, 2);
+ immUniform1f("dash_width", 6.0f);
+
+ immBegin(GPU_PRIM_LINE_STRIP, 3);
+
+ immVertex2fv(shdr_pos, co_ss[0]);
+ immVertex2fv(shdr_pos, co_ss[1]);
+ immVertex2fv(shdr_pos, co_ss[2]);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* arc */
{
float dir_tmp[3];
float co_tmp[3];
- float arc_ss_coords[ARC_STEPS + 1][2];
+ float arc_ss_coord[2];
float dir_a[3];
float dir_b[3];
@@ -502,46 +512,19 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
copy_v3_v3(dir_tmp, dir_a);
- glColor3ubv(color_wire);
+ immUniformColor3ubv(color_wire);
+
+ immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1);
for (j = 0; j <= arc_steps; j++) {
madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
- ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP);
+ ED_view3d_project_float_global(ar, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP);
mul_qt_v3(quat, dir_tmp);
- }
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords);
- glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1);
- glDisableClientState(GL_VERTEX_ARRAY);
- }
-
- /* text */
- {
- char numstr[256];
- float numstr_size[2];
- float pos[2];
- const int prec = 2; /* XXX, todo, make optional */
-
- ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
-
- BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
- pos[0] = co_ss[1][0] + (cap_size * 2.0f);
- pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
+ immVertex2fv(shdr_pos, arc_ss_coord);
+ }
- /* draw text (bg) */
- glColor4ubv(color_back);
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox(
- pos[0] - bg_margin, pos[1] - bg_margin,
- pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
- bg_radius);
- /* draw text */
- glColor3ubv(color_text);
- BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
- BLF_rotation(blf_mono_font, 0.0f);
- BLF_draw(blf_mono_font, numstr, sizeof(numstr));
+ immEnd();
}
/* capping */
@@ -560,77 +543,90 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
rot_90_vec_b[1] = dir_ruler[0];
normalize_v2(rot_90_vec_b);
- glEnable(GL_BLEND);
+ GPU_blend(true);
- glColor3ubv(color_wire);
+ immUniformColor3ubv(color_wire);
- glBegin(GL_LINES);
+ immBegin(GPU_PRIM_LINES, 8);
madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
- glVertex2fv(cap);
+ immVertex2fv(shdr_pos, cap);
madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
- glVertex2fv(cap);
+ immVertex2fv(shdr_pos, cap);
madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
- glVertex2fv(cap);
+ immVertex2fv(shdr_pos, cap);
madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
- glVertex2fv(cap);
+ immVertex2fv(shdr_pos, cap);
/* angle vertex */
- glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
- glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
- glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
- glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
- glEnd();
+ immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
- glDisable(GL_BLEND);
- }
- }
- else {
- glBegin(GL_LINE_STRIP);
- for (j = 0; j < 3; j += 2) {
- glVertex2fv(co_ss[j]);
- }
- glEnd();
- cpack(0xaaaaaa);
- setlinestyle(3);
- glBegin(GL_LINE_STRIP);
- for (j = 0; j < 3; j += 2) {
- glVertex2fv(co_ss[j]);
+ immEnd();
+
+ GPU_blend(false);
}
- glEnd();
- setlinestyle(0);
- sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
+ char numstr[256];
+ float numstr_size[2];
+ float posit[2];
+ const int prec = 2; /* XXX, todo, make optional */
- /* text */
- {
- char numstr[256];
- float numstr_size[2];
- const int prec = 6; /* XXX, todo, make optional */
- float pos[2];
+ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
- ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
+ BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
- BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
+ posit[0] = co_ss[1][0] + (cap_size * 2.0f);
+ posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
- mid_v2_v2v2(pos, co_ss[0], co_ss[2]);
+ /* draw text (bg) */
+ {
+ immUniformColor4fv(color_back);
+ GPU_blend(true);
+ immRectf(shdr_pos,
+ posit[0] - bg_margin, posit[1] - bg_margin,
+ posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1]);
+ GPU_blend(false);
+ }
- /* center text */
- pos[0] -= numstr_size[0] / 2.0f;
- pos[1] -= numstr_size[1] / 2.0f;
+ immUnbindProgram();
- /* draw text (bg) */
- glColor4ubv(color_back);
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox(pos[0] - bg_margin, pos[1] - bg_margin,
- pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
- bg_radius);
+ /* text */
+ {
/* draw text */
- glColor3ubv(color_text);
- BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
+ BLF_color3ubv(blf_mono_font, color_text);
+ BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
+ BLF_rotation(blf_mono_font, 0.0f);
BLF_draw(blf_mono_font, numstr, sizeof(numstr));
}
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float *col = is_act ? color_act : color_base;
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, 2);
+ immUniform1f("dash_width", 6.0f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ immVertex2fv(shdr_pos, co_ss[0]);
+ immVertex2fv(shdr_pos, co_ss[2]);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
/* capping */
{
@@ -639,27 +635,65 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
normalize_v2(rot_90_vec);
- glEnable(GL_BLEND);
- glColor3ubv(color_wire);
+ GPU_blend(true);
+
+ immUniformColor3ubv(color_wire);
+
+ immBegin(GPU_PRIM_LINES, 4);
- glBegin(GL_LINES);
madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
- glVertex2fv(cap);
+ immVertex2fv(shdr_pos, cap);
madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
- glVertex2fv(cap);
+ immVertex2fv(shdr_pos, cap);
madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
- glVertex2fv(cap);
+ immVertex2fv(shdr_pos, cap);
madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
- glVertex2fv(cap);
- glEnd();
+ immVertex2fv(shdr_pos, cap);
- glDisable(GL_BLEND);
+ immEnd();
+
+ GPU_blend(false);
+ }
+
+ char numstr[256];
+ float numstr_size[2];
+ const int prec = 6; /* XXX, todo, make optional */
+ float posit[2];
+
+ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
+
+ BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
+
+ mid_v2_v2v2(posit, co_ss[0], co_ss[2]);
+
+ /* center text */
+ posit[0] -= numstr_size[0] / 2.0f;
+ posit[1] -= numstr_size[1] / 2.0f;
+
+ /* draw text (bg) */
+ {
+ immUniformColor4fv(color_back);
+ GPU_blend(true);
+ immRectf(shdr_pos,
+ posit[0] - bg_margin, posit[1] - bg_margin,
+ posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1]);
+ GPU_blend(false);
+ }
+
+ immUnbindProgram();
+
+ /* text */
+ {
+ /* draw text */
+ BLF_color3ubv(blf_mono_font, color_text);
+ BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
+ BLF_draw(blf_mono_font, numstr, sizeof(numstr));
}
}
}
- glDisable(GL_LINE_SMOOTH);
+ GPU_line_smooth(false);
BLF_disable(blf_mono_font, BLF_ROTATION);
@@ -674,8 +708,14 @@ static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *a
float co_ss[3];
ED_view3d_project_float_global(ar, ruler_item->co[ruler_item->co_index], co_ss, V3D_PROJ_TEST_NOP);
- cpack(color_act);
- circ(co_ss[0], co_ss[1], size * U.pixelsize);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color_act);
+
+ imm_draw_circle_wire_2d(pos, co_ss[0], co_ss[1], size * U.pixelsize, 32);
+
+ immUnbindProgram();
}
}
@@ -730,14 +770,14 @@ static bool view3d_ruler_item_mousemove(
co_other = ruler_item->co[ruler_item->co_index == 0 ? 2 : 0];
- if (ED_transform_snap_object_project_view3d_mixed(
+ if (ED_transform_snap_object_project_view3d(
ruler_info->snap_context,
- SCE_SELECT_FACE,
+ SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
.use_object_edit_cage = true,
},
- mval_fl, &dist_px, true,
+ mval_fl, &dist_px,
co, ray_normal))
{
negate_v3(ray_normal);
@@ -754,19 +794,17 @@ static bool view3d_ruler_item_mousemove(
}
}
else if (do_snap) {
- // Scene *scene = CTX_data_scene(C);
- View3D *v3d = ruler_info->sa->spacedata.first;
const float mval_fl[2] = {UNPACK2(mval)};
- bool use_depth = (v3d->drawtype >= OB_SOLID);
- if (ED_transform_snap_object_project_view3d_mixed(
+ if (ED_transform_snap_object_project_view3d(
ruler_info->snap_context,
- (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0),
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
.use_object_edit_cage = true,
+ .use_occlusion_test = true,
},
- mval_fl, &dist_px, use_depth,
+ mval_fl, &dist_px,
co, NULL))
{
ruler_info->snap_flag |= RULER_SNAP_OK;
@@ -779,7 +817,7 @@ static bool view3d_ruler_item_mousemove(
}
}
-static void view3d_ruler_header_update(ScrArea *sa)
+static void view3d_ruler_header_update(bContext *C)
{
const char *text = IFACE_("Ctrl+LMB: Add, "
"Del: Remove, "
@@ -789,7 +827,7 @@ static void view3d_ruler_header_update(ScrArea *sa)
"Enter: Store, "
"Esc: Cancel");
- ED_area_headerprint(sa, text);
+ ED_workspace_status_text(C, text);
}
/* -------------------------------------------------------------------- */
@@ -815,7 +853,7 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel,
ruler_info, REGION_DRAW_POST_PIXEL);
- view3d_ruler_header_update(sa);
+ view3d_ruler_header_update(C);
op->flag |= OP_IS_MODAL_CURSOR_REGION;
@@ -878,7 +916,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
BLI_listbase_is_empty(&ruler_info->items))
{
View3D *v3d = CTX_wm_view3d(C);
- const bool use_depth = (v3d->drawtype >= OB_SOLID);
+ const bool use_depth = (v3d->shading.type >= OB_SOLID);
/* Create new line */
RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info);
@@ -1047,7 +1085,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (do_draw) {
- view3d_ruler_header_update(sa);
+ view3d_ruler_header_update(C);
/* all 3d views draw rulers */
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -1061,7 +1099,7 @@ exit:
view3d_ruler_free(ruler_info);
op->customdata = NULL;
- ED_area_headerprint(sa, NULL);
+ ED_workspace_status_text(C, NULL);
}
return exit_code;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index d8c21da48a4..30dbaed1d0f 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -44,9 +44,11 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_tracking_types.h"
+#include "DNA_gpencil_types.h"
#include "MEM_guardedalloc.h"
+#include "BLI_array.h"
#include "BLI_math.h"
#include "BLI_lasso_2d.h"
#include "BLI_rect.h"
@@ -55,6 +57,10 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#ifdef __BIG_ENDIAN__
+# include "BLI_endian_switch.h"
+#endif
+
/* vertex box select */
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -63,16 +69,17 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_editmesh.h"
+#include "BKE_scene.h"
#include "BKE_tracking.h"
+#include "BKE_workspace.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -88,12 +95,16 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_sculpt.h"
#include "ED_mball.h"
+#include "ED_gpencil.h"
#include "UI_interface.h"
#include "GPU_draw.h"
+#include "GPU_glew.h"
+#include "GPU_matrix.h"
#include "view3d_intern.h" /* own include */
@@ -108,9 +119,12 @@ float ED_view3d_select_dist_px(void)
void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
{
memset(vc, 0, sizeof(ViewContext));
+ vc->C = C;
vc->ar = CTX_wm_region(C);
vc->bmain = CTX_data_main(C);
+ vc->depsgraph = CTX_data_depsgraph(C);
vc->scene = CTX_data_scene(C);
+ vc->view_layer = CTX_data_view_layer(C);
vc->v3d = CTX_wm_view3d(C);
vc->win = CTX_wm_window(C);
vc->rv3d = CTX_wm_region_view3d(C);
@@ -118,39 +132,26 @@ void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
vc->obedit = CTX_data_edit_object(C);
}
-/*
- * ob == NULL if you want global matrices
- * */
-void view3d_get_transformation(const ARegion *ar, RegionView3D *rv3d, Object *ob, bglMats *mats)
+void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
{
- float cpy[4][4];
- int i, j;
-
- if (ob) {
- mul_m4_m4m4(cpy, rv3d->viewmat, ob->obmat);
- }
- else {
- copy_m4_m4(cpy, rv3d->viewmat);
- }
+ vc->obact = obact;
+ if (vc->obedit) {
+ BLI_assert(BKE_object_is_in_editmode(obact));
+ vc->obedit = obact;
+ /* previous selections are now invalid. */
+ vc->v3d->flag |= V3D_INVALID_BACKBUF;
- for (i = 0; i < 4; ++i) {
- for (j = 0; j < 4; ++j) {
- mats->projection[i * 4 + j] = rv3d->winmat[i][j];
- mats->modelview[i * 4 + j] = cpy[i][j];
+ if (vc->em) {
+ vc->em = BKE_editmesh_from_object(vc->obedit);
}
}
-
- mats->viewport[0] = ar->winrct.xmin;
- mats->viewport[1] = ar->winrct.ymin;
- mats->viewport[2] = ar->winx;
- mats->viewport[3] = ar->winy;
}
/* ********************** view3d_select: selection manipulations ********************* */
/* local prototypes */
-static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool select)
+static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp sel_op)
{
BMVert *eve;
BMIter iter;
@@ -158,15 +159,18 @@ static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool selec
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (EDBM_backbuf_check(index)) {
- BM_vert_select_set(em->bm, eve, select);
+ const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
+ const bool is_inside = EDBM_backbuf_check(index);
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_vert_select_set(em->bm, eve, sel_op_result);
}
}
index++;
}
}
-static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const bool select)
+static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp sel_op)
{
BMEdge *eed;
BMIter iter;
@@ -174,15 +178,18 @@ static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const bool selec
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- if (EDBM_backbuf_check(index)) {
- BM_edge_select_set(em->bm, eed, select);
+ const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
+ const bool is_inside = EDBM_backbuf_check(index);
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_edge_select_set(em->bm, eed, sel_op_result);
}
}
index++;
}
}
-static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const bool select)
+static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const eSelectOp sel_op)
{
BMFace *efa;
BMIter iter;
@@ -190,26 +197,31 @@ static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const bool selec
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- if (EDBM_backbuf_check(index)) {
- BM_face_select_set(em->bm, efa, select);
+ const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
+ const bool is_inside = EDBM_backbuf_check(index);
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_face_select_set(em->bm, efa, sel_op_result);
}
}
index++;
}
}
-
/* object mode, edbm_ prefix is confusing here, rename? */
-static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const bool select)
+static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const eSelectOp sel_op)
{
MVert *mv = me->mvert;
unsigned int index;
if (mv) {
for (index = 1; index <= me->totvert; index++, mv++) {
- if (EDBM_backbuf_check(index)) {
- if (!(mv->flag & ME_HIDE)) {
- mv->flag = select ? (mv->flag | SELECT) : (mv->flag & ~SELECT);
+ if (!(mv->flag & ME_HIDE)) {
+ const bool is_select = mv->flag & SELECT;
+ const bool is_inside = EDBM_backbuf_check(index);
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
}
}
}
@@ -217,15 +229,20 @@ static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const bool sele
}
/* object mode, edbm_ prefix is confusing here, rename? */
-static void edbm_backbuf_check_and_select_tfaces(Mesh *me, const bool select)
+static void edbm_backbuf_check_and_select_tfaces(Mesh *me, const eSelectOp sel_op)
{
MPoly *mpoly = me->mpoly;
unsigned int index;
if (mpoly) {
for (index = 1; index <= me->totpoly; index++, mpoly++) {
- if (EDBM_backbuf_check(index)) {
- mpoly->flag = select ? (mpoly->flag | ME_FACE_SEL) : (mpoly->flag & ~ME_FACE_SEL);
+ if (!(mpoly->flag & ME_HIDE)) {
+ const bool is_select = mpoly->flag & ME_FACE_SEL;
+ const bool is_inside = EDBM_backbuf_check(index);
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL);
+ }
}
}
}
@@ -240,7 +257,7 @@ typedef struct LassoSelectUserData {
rctf _rect_fl;
const int (*mcords)[2];
int moves;
- bool select;
+ eSelectOp sel_op;
/* runtime */
int pass;
@@ -251,7 +268,7 @@ typedef struct LassoSelectUserData {
static void view3d_userdata_lassoselect_init(
LassoSelectUserData *r_data,
ViewContext *vc, const rcti *rect, const int (*mcords)[2],
- const int moves, const bool select)
+ const int moves, const eSelectOp sel_op)
{
r_data->vc = vc;
@@ -261,7 +278,7 @@ static void view3d_userdata_lassoselect_init(
r_data->mcords = mcords;
r_data->moves = moves;
- r_data->select = select;
+ r_data->sel_op = sel_op;
/* runtime */
r_data->pass = 0;
@@ -295,7 +312,7 @@ static bool view3d_selectable_data(bContext *C)
}
-/* helper also for borderselect */
+/* helper also for box_select */
static bool edge_fully_inside_rect(const rctf *rect, const float v1[2], const float v2[2])
{
return BLI_rctf_isect_pt_v(rect, v1) && BLI_rctf_isect_pt_v(rect, v2);
@@ -326,7 +343,7 @@ static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2
return 1;
}
-static void do_lasso_select_pose__doSelectBone(
+static void do_lasso_select_pose__do_tag(
void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2])
{
LassoSelectUserData *data = userData;
@@ -336,26 +353,21 @@ static void do_lasso_select_pose__doSelectBone(
bool is_point_done = false;
int points_proj_tot = 0;
- const int x0 = screen_co_a[0];
- const int y0 = screen_co_a[1];
- const int x1 = screen_co_b[0];
- const int y1 = screen_co_b[1];
-
/* project head location to screenspace */
- if (x0 != IS_CLIPPED) {
+ if (screen_co_a[0] != IS_CLIPPED) {
points_proj_tot++;
- if (BLI_rcti_isect_pt(data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX))
+ if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX))
{
is_point_done = true;
}
}
/* project tail location to screenspace */
- if (x1 != IS_CLIPPED) {
+ if (screen_co_b[0] != IS_CLIPPED) {
points_proj_tot++;
- if (BLI_rcti_isect_pt(data->rect, x1, y1) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX))
+ if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX))
{
is_point_done = true;
}
@@ -364,16 +376,14 @@ static void do_lasso_select_pose__doSelectBone(
/* if one of points selected, we skip the bone itself */
if ((is_point_done == true) ||
((is_point_done == false) && (points_proj_tot == 2) &&
- BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX)))
+ BLI_lasso_is_edge_inside(data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)))
{
- if (data->select) pchan->bone->flag |= BONE_SELECTED;
- else pchan->bone->flag &= ~BONE_SELECTED;
- data->is_changed = true;
+ pchan->bone->flag |= BONE_DONE;
}
data->is_changed |= is_point_done;
}
}
-static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves, const bool select)
+static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves)
{
ViewContext vc_tmp;
LassoSelectUserData data;
@@ -388,106 +398,218 @@ static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[]
BLI_lasso_boundbox(&rect, mcords, moves);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, 0);
- ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
+ ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
- pose_foreachScreenBone(&vc_tmp, do_lasso_select_pose__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
-
- if (data.is_changed) {
- bArmature *arm = ob->data;
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
- }
+ pose_foreachScreenBone(&vc_tmp, do_lasso_select_pose__do_tag, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
-static void object_deselect_all_visible(Scene *scene, View3D *v3d)
+static void object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
{
Base *base;
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
if (BASE_SELECTABLE(v3d, base)) {
- ED_base_object_select(base, BA_DESELECT);
+ ED_object_base_select(base, BA_DESELECT);
}
}
}
static void do_lasso_select_objects(
ViewContext *vc, const int mcords[][2], const short moves,
- const bool extend, const bool select)
+ const eSelectOp sel_op)
{
+ View3D *v3d = vc->v3d;
Base *base;
- if (extend == false && select)
- object_deselect_all_visible(vc->scene, vc->v3d);
-
- for (base = vc->scene->base.first; base; base = base->next) {
- if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */
- if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) {
- if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) {
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ object_deselect_all_visible(vc->view_layer, vc->v3d);
+ }
- ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
- base->object->flag = base->flag;
- }
- }
- if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) {
- do_lasso_select_pose(vc, base->object, mcords, moves, select);
+ bool changed = false;
+ for (base = vc->view_layer->object_bases.first; base; base = base->next) {
+ if (BASE_SELECTABLE(v3d, base)) { /* use this to avoid un-needed lasso lookups */
+ const bool is_select = base->flag & BASE_SELECTED;
+ const bool is_inside = (
+ (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) &&
+ BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED));
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
+ changed = true;
}
}
}
+
+ if (changed) {
+ DEG_id_tag_update(&vc->scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene);
+ }
}
-static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
-{
- LassoSelectUserData *data = userData;
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
- {
- BM_vert_select_set(data->vc->em->bm, eve, data->select);
+/**
+ * Use for lasso & box select.
+ */
+static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len)
+{
+ Base **bases = NULL;
+ BLI_array_declare(bases);
+ FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_MODE_POSE, base_iter) {
+ Object *ob_iter = base_iter->object;
+ bArmature *arm = ob_iter->data;
+ for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ Bone *bone = pchan->bone;
+ bone->flag &= ~BONE_DONE;
+ }
+ arm->id.tag |= LIB_TAG_DOIT;
+ ob_iter->id.tag &= ~LIB_TAG_DOIT;
+ BLI_array_append(bases, base_iter);
}
+ FOREACH_BASE_IN_MODE_END;
+ *r_bases_len = BLI_array_len(bases);
+ return bases;
}
-static void do_lasso_select_mesh__doSelectEdge(
- void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
-{
- LassoSelectUserData *data = userData;
- if (EDBM_backbuf_check(bm_solidoffs + index)) {
- const int x0 = screen_co_a[0];
- const int y0 = screen_co_a[1];
- const int x1 = screen_co_b[0];
- const int y1 = screen_co_b[1];
+static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const eSelectOp sel_op)
+{
+ bool changed_multi = false;
- if (data->pass == 0) {
- if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, IS_CLIPPED) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, IS_CLIPPED))
- {
- BM_edge_select_set(data->vc->em->bm, eed, data->select);
- data->is_done = true;
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ for (int i = 0; i < bases_len; i++) {
+ Base *base_iter = bases[i];
+ Object *ob_iter = base_iter->object;
+ if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, false)) {
+ ED_pose_bone_select_tag_update(ob_iter);
+ changed_multi = true;
}
}
+ }
+
+ for (int i = 0; i < bases_len; i++) {
+ Base *base_iter = bases[i];
+ Object *ob_iter = base_iter->object;
+ bArmature *arm = ob_iter->data;
+
+ /* Don't handle twice. */
+ if (arm->id.tag & LIB_TAG_DOIT) {
+ arm->id.tag &= ~LIB_TAG_DOIT;
+ }
else {
- if (BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, IS_CLIPPED)) {
- BM_edge_select_set(data->vc->em->bm, eed, data->select);
+ continue;
+ }
+
+ bool changed = true;
+ for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ Bone *bone = pchan->bone;
+ if ((bone->flag & BONE_UNSELECTABLE) == 0) {
+ const bool is_select = bone->flag & BONE_SELECTED;
+ const bool is_inside = bone->flag & BONE_DONE;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(bone->flag, sel_op_result, BONE_SELECTED);
+ if (sel_op_result == 0) {
+ if (arm->act_bone == bone) {
+ arm->act_bone = NULL;
+ }
+ }
+ changed = true;
+ }
}
}
+ if (changed) {
+ ED_pose_bone_select_tag_update(ob_iter);
+ changed_multi = true;
+ }
}
+ return changed_multi;
}
-static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
+
+static void do_lasso_select_pose(
+ ViewContext *vc, const int mcords[][2], const short moves,
+ const eSelectOp sel_op)
+{
+ uint bases_len;
+ Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len);
+
+ for (int i = 0; i < bases_len; i++) {
+ Base *base_iter = bases[i];
+ Object *ob_iter = base_iter->object;
+ do_lasso_tag_pose(vc, ob_iter, mcords, moves);
+ }
+
+ const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
+ if (changed_multi) {
+ DEG_id_tag_update(&vc->scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene);
+ }
+
+ if (bases != NULL) {
+ MEM_freeN(bases);
+ }
+}
+
+static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
{
LassoSelectUserData *data = userData;
+ const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
+ const bool is_inside = (
+ BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
+ }
+}
+static void do_lasso_select_mesh__doSelectEdge_pass0(
+ void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
+{
+ LassoSelectUserData *data = userData;
+ const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
+ const bool is_inside = (
+ EDBM_backbuf_check(bm_solidoffs + index) &&
+ edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
+ data->is_done = true;
+ }
+}
+static void do_lasso_select_mesh__doSelectEdge_pass1(
+ void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
+{
+ LassoSelectUserData *data = userData;
+ const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
+ const bool is_inside = (
+ EDBM_backbuf_check(bm_solidoffs + index) &&
+ BLI_lasso_is_edge_inside(
+ data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), IS_CLIPPED));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
+ }
+}
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
- {
- BM_face_select_set(data->vc->em->bm, efa, data->select);
+static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
+{
+ LassoSelectUserData *data = userData;
+ const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
+ const bool is_inside = (
+ BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
}
}
-static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_mesh(
+ ViewContext *vc,
+ const int mcords[][2], short moves, const eSelectOp sel_op)
{
LassoSelectUserData data;
ToolSettings *ts = vc->scene->toolsettings;
@@ -499,20 +621,21 @@ static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short m
BLI_lasso_boundbox(&rect, mcords, moves);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
+ }
/* for non zbuf projections, don't change the GL state */
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- glLoadMatrixf(vc->rv3d->viewmat);
+ GPU_matrix_set(vc->rv3d->viewmat);
bbsel = EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) {
- edbm_backbuf_check_and_select_verts(vc->em, select);
+ edbm_backbuf_check_and_select_verts(vc->em, sel_op);
}
else {
mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -520,18 +643,15 @@ static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short m
}
if (ts->selectmode & SCE_SELECT_EDGE) {
/* Does both bbsel and non-bbsel versions (need screen cos for both) */
- data.pass = 0;
- mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
-
+ mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR);
if (data.is_done == false) {
- data.pass = 1;
- mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
+ mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR);
}
}
if (ts->selectmode & SCE_SELECT_FACE) {
if (bbsel) {
- edbm_backbuf_check_and_select_faces(vc->em, select);
+ edbm_backbuf_check_and_select_faces(vc->em, sel_op);
}
else {
mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -546,43 +666,46 @@ static void do_lasso_select_curve__doSelect(
void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
{
LassoSelectUserData *data = userData;
- Object *obedit = data->vc->obedit;
- Curve *cu = (Curve *)obedit->data;
- if (BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) {
- if (bp) {
- bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
+ const bool is_inside = BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED);
+ if (bp) {
+ const bool is_select = bp->f1 & SELECT;
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
}
- else {
- if (cu->drawflag & CU_HIDE_HANDLES) {
- /* can only be (beztindex == 0) here since handles are hidden */
- bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
+ }
+ else {
+ if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ /* can only be (beztindex == 0) here since handles are hidden */
+ const bool is_select = bezt->f2 & SELECT;
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT);
}
- else {
- if (beztindex == 0) {
- bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
- }
- else if (beztindex == 1) {
- bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
- }
- else {
- bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
- }
+ bezt->f1 = bezt->f3 = bezt->f2;
+ }
+ else {
+ char *flag_p = (&bezt->f1) + beztindex;
+ const bool is_select = *flag_p & SELECT;
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
}
}
}
}
-static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
- if (extend == false && select) {
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
Curve *curve = (Curve *) vc->obedit->data;
ED_curve_deselect_all(curve->editnurb);
}
@@ -595,74 +718,83 @@ static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short
static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2])
{
LassoSelectUserData *data = userData;
-
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
- {
- bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
+ const bool is_select = bp->f1 & SELECT;
+ const bool is_inside = (
+ BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
}
}
-static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
ED_lattice_flags_set(vc->obedit, 0);
+ }
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
-static void do_lasso_select_armature__doSelectBone(
- void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
+static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2])
{
LassoSelectUserData *data = userData;
bArmature *arm = data->vc->obedit->data;
-
- if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) {
+ if (EBONE_VISIBLE(arm, ebone)) {
bool is_point_done = false;
int points_proj_tot = 0;
- const int x0 = screen_co_a[0];
- const int y0 = screen_co_a[1];
- const int x1 = screen_co_b[0];
- const int y1 = screen_co_b[1];
-
/* project head location to screenspace */
- if (x0 != IS_CLIPPED) {
+ if (screen_co_a[0] != IS_CLIPPED) {
points_proj_tot++;
- if (BLI_rcti_isect_pt(data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX))
- {
- is_point_done = true;
- if (data->select) ebone->flag |= BONE_ROOTSEL;
- else ebone->flag &= ~BONE_ROOTSEL;
+ const bool is_select = ebone->flag & BONE_ROOTSEL;
+ const bool is_inside = (
+ BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL);
+ }
}
+ is_point_done |= is_inside;
}
/* project tail location to screenspace */
- if (x1 != IS_CLIPPED) {
+ if (screen_co_b[0] != IS_CLIPPED) {
points_proj_tot++;
- if (BLI_rcti_isect_pt(data->rect, x1, y1) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX))
- {
- is_point_done = true;
- if (data->select) ebone->flag |= BONE_TIPSEL;
- else ebone->flag &= ~BONE_TIPSEL;
+ const bool is_select = ebone->flag & BONE_TIPSEL;
+ const bool is_inside = (
+ BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL);
+ }
}
+ is_point_done |= is_inside;
}
/* if one of points selected, we skip the bone itself */
- if ((is_point_done == false) && (points_proj_tot == 2) &&
- BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX))
- {
- if (data->select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if ((is_point_done == false) && (points_proj_tot == 2)) {
+ const bool is_select = ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ const bool is_inside = BLI_lasso_is_edge_inside(
+ data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX);
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) {
+ SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL));
+ }
+ }
data->is_changed = true;
}
@@ -670,19 +802,20 @@ static void do_lasso_select_armature__doSelectBone(
}
}
-static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
ED_armature_edit_deselect_all_visible(vc->obedit);
+ }
armature_foreachScreenBone(vc, do_lasso_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -697,48 +830,52 @@ static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], sho
static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2])
{
LassoSelectUserData *data = userData;
-
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX))
- {
- if (data->select) ml->flag |= SELECT;
- else ml->flag &= ~SELECT;
+ const bool is_select = ml->flag & SELECT;
+ const bool is_inside = (
+ BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
data->is_changed = true;
}
}
-static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
MetaBall *mb = (MetaBall *)vc->obedit->data;
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
BKE_mball_deselect_all(mb);
+ }
BLI_lasso_boundbox(&rect, mcords, moves);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
-static void do_lasso_select_meshobject__doSelectVert(
- void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
{
LassoSelectUserData *data = userData;
-
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
- {
- SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
+ const bool is_select = mv->flag & SELECT;
+ const bool is_inside = (
+ BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
+ data->is_changed = true;
}
}
-static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
{
- const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
+ const bool use_zbuf = V3D_IS_ZBUF(vc->v3d);
Object *ob = vc->obact;
Mesh *me = ob->data;
rcti rect;
@@ -746,8 +883,9 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh
if (me == NULL || me->totvert == 0)
return;
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
paintvert_deselect_all_visible(ob, SEL_DESELECT, false); /* flush selection at the end */
+ }
BLI_lasso_boundbox(&rect, mcords, moves);
@@ -756,14 +894,14 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh
EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
- edbm_backbuf_check_and_select_verts_obmode(me, select);
+ edbm_backbuf_check_and_select_verts_obmode(me, sel_op);
EDBM_backbuf_free();
}
else {
LassoSelectUserData data;
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
@@ -771,12 +909,13 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh
}
- if (select == false) {
+ if (SEL_OP_CAN_DESELECT(sel_op)) {
BKE_mesh_mselect_validate(me);
}
paintvert_flush_flags(ob);
+ paintvert_tag_select_update(vc->C, ob);
}
-static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select)
+static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
{
Object *ob = vc->obact;
Mesh *me = ob->data;
@@ -785,23 +924,25 @@ static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], sh
if (me == NULL || me->totpoly == 0)
return;
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
paintface_deselect_all_visible(ob, SEL_DESELECT, false); /* flush selection at the end */
+ }
bm_vertoffs = me->totpoly + 1; /* max index array */
BLI_lasso_boundbox(&rect, mcords, moves);
EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
- edbm_backbuf_check_and_select_tfaces(me, select);
+ edbm_backbuf_check_and_select_tfaces(me, sel_op);
EDBM_backbuf_free();
paintface_flush_flags(ob, SELECT);
+ paintface_tag_select_update(vc->C, ob);
}
#if 0
-static void do_lasso_select_node(int mcords[][2], short moves, const bool select)
+static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op)
{
SpaceNode *snode = sa->spacedata.first;
@@ -818,13 +959,13 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select
node_centf[1] = BLI_RCT_CENTER_Y(&node->totr);
ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
- if (BLI_rcti_isect_pt_v(&rect, node_cent) && BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])) {
- if (select) {
- node->flag |= SELECT;
- }
- else {
- node->flag &= ~SELECT;
- }
+ const bool is_select = node->flag & SELECT;
+ const bool is_inside = (
+ BLI_rcti_isect_pt_v(&rect, node_cent) &&
+ BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1]));
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT);
}
}
BIF_undo_push("Lasso select nodes");
@@ -834,49 +975,61 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select
static void view3d_lasso_select(
bContext *C, ViewContext *vc,
const int mcords[][2], short moves,
- bool extend, bool select)
+ const eSelectOp sel_op)
{
Object *ob = CTX_data_active_object(C);
if (vc->obedit == NULL) { /* Object Mode */
- if (BKE_paint_select_face_test(ob))
- do_lasso_select_paintface(vc, mcords, moves, extend, select);
- else if (BKE_paint_select_vert_test(ob))
- do_lasso_select_paintvert(vc, mcords, moves, extend, select);
+ if (BKE_paint_select_face_test(ob)) {
+ do_lasso_select_paintface(vc, mcords, moves, sel_op);
+ }
+ else if (BKE_paint_select_vert_test(ob)) {
+ do_lasso_select_paintvert(vc, mcords, moves, sel_op);
+ }
else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
/* pass */
}
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT))
- PE_lasso_select(C, mcords, moves, extend, select);
+ else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
+ PE_lasso_select(C, mcords, moves, sel_op);
+ }
+ else if (ob && (ob->mode & OB_MODE_POSE)) {
+ do_lasso_select_pose(vc, mcords, moves, sel_op);
+ }
else {
- do_lasso_select_objects(vc, mcords, moves, extend, select);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
+ do_lasso_select_objects(vc, mcords, moves, sel_op);
}
}
else { /* Edit Mode */
- switch (vc->obedit->type) {
- case OB_MESH:
- do_lasso_select_mesh(vc, mcords, moves, extend, select);
- break;
- case OB_CURVE:
- case OB_SURF:
- do_lasso_select_curve(vc, mcords, moves, extend, select);
- break;
- case OB_LATTICE:
- do_lasso_select_lattice(vc, mcords, moves, extend, select);
- break;
- case OB_ARMATURE:
- do_lasso_select_armature(vc, mcords, moves, extend, select);
- break;
- case OB_MBALL:
- do_lasso_select_meta(vc, mcords, moves, extend, select);
- break;
- default:
- assert(!"lasso select on incorrect object type");
- break;
- }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data);
+ FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->mode, ob_iter) {
+ ED_view3d_viewcontext_init_object(vc, ob_iter);
+
+ switch (vc->obedit->type) {
+ case OB_MESH:
+ do_lasso_select_mesh(vc, mcords, moves, sel_op);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ do_lasso_select_curve(vc, mcords, moves, sel_op);
+ break;
+ case OB_LATTICE:
+ do_lasso_select_lattice(vc, mcords, moves, sel_op);
+ break;
+ case OB_ARMATURE:
+ do_lasso_select_armature(vc, mcords, moves, sel_op);
+ break;
+ case OB_MBALL:
+ do_lasso_select_meta(vc, mcords, moves, sel_op);
+ break;
+ default:
+ assert(!"lasso select on incorrect object type");
+ break;
+ }
+
+ DEG_id_tag_update(vc->obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data);
+ }
+ FOREACH_OBJECT_IN_MODE_END;
}
}
@@ -890,15 +1043,13 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
- bool extend, select;
view3d_operator_needs_opengl(C);
/* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc);
- extend = RNA_boolean_get(op->ptr, "extend");
- select = !RNA_boolean_get(op->ptr, "deselect");
- view3d_lasso_select(C, &vc, mcords, mcords_tot, extend, select);
+ eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op);
MEM_freeN((void *)mcords);
@@ -923,7 +1074,8 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- WM_operator_properties_gesture_lasso_select(ot);
+ WM_operator_properties_gesture_lasso(ot);
+ WM_operator_properties_select_operation(ot);
}
/* ************************** mouse select ************************* */
@@ -974,8 +1126,8 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
if (!toggle) {
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
- if (base->flag & SELECT) {
- ED_base_object_select(base, BA_DESELECT);
+ if ((base->flag & BASE_SELECTED) != 0) {
+ ED_object_base_select(base, BA_DESELECT);
changed = true;
}
}
@@ -986,8 +1138,8 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
{
/* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */
if (STREQ(name, base->object->id.name + 2)) {
- ED_base_object_activate(C, base);
- ED_base_object_select(base, BA_SELECT);
+ ED_object_base_activate(C, base);
+ ED_object_base_select(base, BA_SELECT);
changed = true;
}
}
@@ -998,7 +1150,9 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
/* undo? */
if (changed) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
else {
@@ -1031,14 +1185,12 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle selection instead of deselecting everything first");
}
-static void deselectall_except(Scene *scene, Base *b) /* deselect all except b */
+static void deselectall_except(ViewLayer *view_layer, Base *b) /* deselect all except b */
{
- Base *base;
-
- for (base = FIRSTBASE; base; base = base->next) {
- if (base->flag & SELECT) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->flag & BASE_SELECTED) {
if (b != base) {
- ED_base_object_select(base, BA_DESELECT);
+ ED_object_base_select(base, BA_DESELECT);
}
}
}
@@ -1052,6 +1204,7 @@ static Base *object_mouse_select_menu(
bool ok;
LinkNode *linklist = NULL;
+ /* handle base->object->select_color */
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
ok = false;
@@ -1060,7 +1213,7 @@ static Base *object_mouse_select_menu(
if (buffer) {
for (int a = 0; a < hits; a++) {
/* index was converted */
- if (base->selcol == (buffer[(4 * a) + 3] & ~0xFFFF0000)) {
+ if (base->object->select_color == (buffer[(4 * a) + 3] & ~0xFFFF0000)) {
ok = true;
break;
}
@@ -1160,7 +1313,7 @@ static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits15, const
/* so check three selection levels and compare */
static int mixed_bones_object_selectbuffer(
ViewContext *vc, unsigned int *buffer, const int mval[2],
- bool use_cycle, bool enumerate,
+ bool use_cycle, bool enumerate, eV3DSelectObjectFilter select_filter,
bool *r_do_nearest)
{
rcti rect;
@@ -1172,7 +1325,7 @@ static int mixed_bones_object_selectbuffer(
/* define if we use solid nearest select or not */
if (use_cycle) {
- if (v3d->drawtype > OB_WIRE) {
+ if (v3d->shading.type > OB_WIRE) {
do_nearest = true;
if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
do_nearest = false;
@@ -1181,7 +1334,7 @@ static int mixed_bones_object_selectbuffer(
copy_v2_v2_int(last_mval, mval);
}
else {
- if (v3d->drawtype > OB_WIRE) {
+ if (v3d->shading.type > OB_WIRE) {
do_nearest = true;
}
}
@@ -1199,7 +1352,7 @@ static int mixed_bones_object_selectbuffer(
view3d_opengl_select_cache_begin();
BLI_rcti_init_pt_radius(&rect, mval, 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
+ hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
if (hits15 == 1) {
hits = selectbuffer_ret_hits_15(buffer, hits15);
goto finally;
@@ -1210,7 +1363,7 @@ static int mixed_bones_object_selectbuffer(
offs = 4 * hits15;
BLI_rcti_init_pt_radius(&rect, mval, 9);
- hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
+ hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
if (hits9 == 1) {
hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
goto finally;
@@ -1220,7 +1373,7 @@ static int mixed_bones_object_selectbuffer(
offs += 4 * hits9;
BLI_rcti_init_pt_radius(&rect, mval, 5);
- hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
+ hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter);
if (hits5 == 1) {
hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
goto finally;
@@ -1242,6 +1395,25 @@ static int mixed_bones_object_selectbuffer(
finally:
view3d_opengl_select_cache_end();
+ if (vc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ const bool is_pose_mode = (
+ (vc->obact && vc->obact->mode & OB_MODE_POSE) ||
+ (select_filter == VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK));
+ struct {
+ uint data[4];
+ } *buffer4 = (void *)buffer;
+ uint j = 0;
+ for (uint i = 0; i < hits; i++) {
+ if (((buffer4[i].data[3] & 0xFFFF0000) != 0) == is_pose_mode) {
+ if (i != j) {
+ buffer4[j] = buffer4[i];
+ }
+ j++;
+ }
+ }
+ hits = j;
+ }
+
return hits;
}
@@ -1250,7 +1422,7 @@ static Base *mouse_select_eval_buffer(
ViewContext *vc, const uint *buffer, int hits,
Base *startbase, bool has_bones, bool do_nearest)
{
- Scene *scene = vc->scene;
+ ViewLayer *view_layer = vc->view_layer;
View3D *v3d = vc->v3d;
Base *base, *basact = NULL;
int a;
@@ -1271,7 +1443,9 @@ static Base *mouse_select_eval_buffer(
}
else {
/* only exclude active object when it is selected... */
- if (BASACT && (BASACT->flag & SELECT) && hits > 1) notcol = BASACT->selcol;
+ if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED) && hits > 1) {
+ notcol = BASACT(view_layer)->object->select_color;
+ }
for (a = 0; a < hits; a++) {
if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
@@ -1281,10 +1455,10 @@ static Base *mouse_select_eval_buffer(
}
}
- base = FIRSTBASE;
+ base = FIRSTBASE(view_layer);
while (base) {
if (BASE_SELECTABLE(v3d, base)) {
- if (base->selcol == selcol) break;
+ if (base->object->select_color == selcol) break;
}
base = base->next;
}
@@ -1296,9 +1470,9 @@ static Base *mouse_select_eval_buffer(
while (base) {
/* skip objects with select restriction, to prevent prematurely ending this loop
* with an un-selectable choice */
- if (base->object->restrictflag & OB_RESTRICT_SELECT) {
+ if ((base->flag & BASE_SELECTABLE) == 0) {
base = base->next;
- if (base == NULL) base = FIRSTBASE;
+ if (base == NULL) base = FIRSTBASE(view_layer);
if (base == startbase) break;
}
@@ -1307,12 +1481,12 @@ static Base *mouse_select_eval_buffer(
if (has_bones) {
/* skip non-bone objects */
if ((buffer[4 * a + 3] & 0xFFFF0000)) {
- if (base->selcol == (buffer[(4 * a) + 3] & 0xFFFF))
+ if (base->object->select_color == (buffer[(4 * a) + 3] & 0xFFFF))
basact = base;
}
}
else {
- if (base->selcol == (buffer[(4 * a) + 3] & 0xFFFF))
+ if (base->object->select_color == (buffer[(4 * a) + 3] & 0xFFFF))
basact = base;
}
}
@@ -1321,7 +1495,7 @@ static Base *mouse_select_eval_buffer(
if (basact) break;
base = base->next;
- if (base == NULL) base = FIRSTBASE;
+ if (base == NULL) base = FIRSTBASE(view_layer);
if (base == startbase) break;
}
}
@@ -1340,18 +1514,34 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
/* setup view context for argument to callbacks */
view3d_operator_needs_opengl(C);
+
ED_view3d_viewcontext_init(C, &vc);
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, false, false, &do_nearest);
+ hits = mixed_bones_object_selectbuffer(
+ &vc, buffer, mval,
+ false, false, VIEW3D_SELECT_FILTER_NOP,
+ &do_nearest);
if (hits > 0) {
const bool has_bones = selectbuffer_has_bones(buffer, hits);
- basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.view_layer->object_bases.first, has_bones, do_nearest);
}
return basact;
}
+Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
+{
+ Base *base = ED_view3d_give_base_under_cursor(C, mval);
+ if (base) return base->object;
+ return NULL;
+}
+
+bool ED_view3d_is_object_under_cursor(bContext *C, const int mval[2])
+{
+ return ED_view3d_give_object_under_cursor(C, mval) != NULL;
+}
+
static void deselect_all_tracks(MovieTracking *tracking)
{
MovieTrackingObject *object;
@@ -1378,16 +1568,17 @@ static bool ed_object_select_pick(
{
ViewContext vc;
ARegion *ar = CTX_wm_region(C);
- View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
- Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Base *base, *startbase = NULL, *basact = NULL, *oldbasact = BASACT(view_layer);
+ const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
bool is_obedit;
float dist = ED_view3d_select_dist_px() * 1.3333f;
bool retval = false;
int hits;
const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
-
/* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc);
@@ -1397,9 +1588,12 @@ static bool ed_object_select_pick(
vc.obedit = NULL;
}
+ /* In pose mode we don't want to mess with object selection. */
+ const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE);
+
/* always start list from basact in wire mode */
- startbase = FIRSTBASE;
- if (BASACT && BASACT->next) startbase = BASACT->next;
+ startbase = FIRSTBASE(view_layer);
+ if (BASACT(view_layer) && BASACT(view_layer)->next) startbase = BASACT(view_layer)->next;
/* This block uses the control key to make the object selected by its center point rather than its contents */
/* in editmode do not activate */
@@ -1419,7 +1613,7 @@ static bool ed_object_select_pick(
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{
float dist_temp = len_manhattan_v2v2(mval_fl, screen_co);
- if (base == BASACT) dist_temp += 10.0f;
+ if (base == BASACT(view_layer)) dist_temp += 10.0f;
if (dist_temp < dist) {
dist = dist_temp;
basact = base;
@@ -1428,10 +1622,23 @@ static bool ed_object_select_pick(
}
base = base->next;
- if (base == NULL) base = FIRSTBASE;
+ if (base == NULL) base = FIRSTBASE(view_layer);
if (base == startbase) break;
}
}
+ if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ if (is_obedit == false) {
+ if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
+ if (object_mode == OB_MODE_OBJECT) {
+ struct Main *bmain = CTX_data_main(C);
+ ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
+ }
+ if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
+ basact = NULL;
+ }
+ }
+ }
+ }
}
else {
unsigned int buffer[MAXPICKBUF];
@@ -1440,7 +1647,12 @@ static bool ed_object_select_pick(
// TIMEIT_START(select_time);
/* if objects have posemode set, the bones are in the same selection buffer */
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest);
+ const eV3DSelectObjectFilter select_filter = (
+ (object == false) ? ED_view3d_select_filter_from_mode(scene, vc.obact) : VIEW3D_SELECT_FILTER_NOP);
+ hits = mixed_bones_object_selectbuffer(
+ &vc, buffer, mval,
+ true, enumerate, select_filter,
+ &do_nearest);
// TIMEIT_END(select_time);
@@ -1458,7 +1670,7 @@ static bool ed_object_select_pick(
if (has_bones && basact) {
if (basact->object->type == OB_CAMERA) {
- if (BASACT == basact) {
+ if (BASACT(view_layer) == basact) {
int i, hitresult;
bool changed = false;
@@ -1467,7 +1679,7 @@ static bool ed_object_select_pick(
/* if there's bundles in buffer select bundles first,
* so non-camera elements should be ignored in buffer */
- if (basact->selcol != (hitresult & 0xFFFF)) {
+ if (basact->object->select_color != (hitresult & 0xFFFF)) {
continue;
}
@@ -1496,11 +1708,13 @@ static bool ed_object_select_pick(
changed = true;
}
- basact->flag |= SELECT;
- basact->object->flag = basact->flag;
+ basact->flag |= BASE_SELECTED;
+ BKE_scene_object_base_flag_sync_from_base(basact);
retval = true;
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ DEG_id_tag_update(&clip->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, track);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -1516,30 +1730,58 @@ static bool ed_object_select_pick(
}
}
else if (ED_armature_pose_select_pick_with_buffer(
- scene, basact, buffer, hits, extend, deselect, toggle, do_nearest))
+ view_layer, v3d, basact, buffer, hits, extend, deselect, toggle, do_nearest))
{
/* then bone is found */
/* we make the armature selected:
* not-selected active object in posemode won't work well for tools */
- basact->flag |= SELECT;
- basact->object->flag = basact->flag;
+ basact->flag |= BASE_SELECTED;
+ BKE_scene_object_base_flag_sync_from_base(basact);
retval = true;
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object);
/* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
- if (BASACT && (BASACT->object->mode & OB_MODE_WEIGHT_PAINT)) {
+ if (BASACT(view_layer) && (BASACT(view_layer)->object->mode & OB_MODE_WEIGHT_PAINT)) {
/* prevent activating */
basact = NULL;
}
}
/* prevent bone selecting to pass on to object selecting */
- if (basact == BASACT)
+ if (basact == BASACT(view_layer))
basact = NULL;
}
+
+ if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ if (is_obedit == false) {
+ if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
+ if (object_mode == OB_MODE_OBJECT) {
+ struct Main *bmain = CTX_data_main(C);
+ ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
+ }
+ if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
+ basact = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ /* Disallow switching modes,
+ * special exception for edit-mode - vertex-parent operator. */
+ if (is_obedit == false) {
+ if (oldbasact && basact) {
+ if ((oldbasact->object->mode != basact->object->mode) &&
+ (oldbasact->object->mode & basact->object->mode) == 0)
+ {
+ basact = NULL;
+ }
+ }
}
}
@@ -1549,40 +1791,63 @@ static bool ed_object_select_pick(
if (vc.obedit) {
/* only do select */
- deselectall_except(scene, basact);
- ED_base_object_select(basact, BA_SELECT);
+ deselectall_except(view_layer, basact);
+ ED_object_base_select(basact, BA_SELECT);
}
/* also prevent making it active on mouse selection */
else if (BASE_SELECTABLE(v3d, basact)) {
-
- oldbasact = BASACT;
-
if (extend) {
- ED_base_object_select(basact, BA_SELECT);
+ ED_object_base_select(basact, BA_SELECT);
}
else if (deselect) {
- ED_base_object_select(basact, BA_DESELECT);
+ ED_object_base_select(basact, BA_DESELECT);
}
else if (toggle) {
- if (basact->flag & SELECT) {
+ if (basact->flag & BASE_SELECTED) {
if (basact == oldbasact) {
- ED_base_object_select(basact, BA_DESELECT);
+ ED_object_base_select(basact, BA_DESELECT);
}
}
else {
- ED_base_object_select(basact, BA_SELECT);
+ ED_object_base_select(basact, BA_SELECT);
}
}
else {
- deselectall_except(scene, basact);
- ED_base_object_select(basact, BA_SELECT);
+ /* When enabled, this puts other objects out of multi pose-mode. */
+ if (is_pose_mode == false) {
+ deselectall_except(view_layer, basact);
+ ED_object_base_select(basact, BA_SELECT);
+ }
}
if ((oldbasact != basact) && (is_obedit == false)) {
- ED_base_object_activate(C, basact); /* adds notifier */
+ ED_object_base_activate(C, basact); /* adds notifier */
+ }
+
+ /* Set special modes for grease pencil
+ The grease pencil modes are not real modes, but a hack to make the interface
+ consistent, so need some tricks to keep UI synchronized */
+ // XXX: This stuff needs reviewing (Aligorith)
+ if (false &&
+ (((oldbasact) && oldbasact->object->type == OB_GPENCIL) ||
+ (basact->object->type == OB_GPENCIL)))
+ {
+ /* set cursor */
+ if (ELEM(basact->object->mode,
+ OB_MODE_GPENCIL_PAINT,
+ OB_MODE_GPENCIL_SCULPT,
+ OB_MODE_GPENCIL_WEIGHT))
+ {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
+ else {
+ /* TODO: maybe is better use restore */
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
}
}
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
@@ -1596,17 +1861,16 @@ typedef struct BoxSelectUserData {
const rcti *rect;
const rctf *rect_fl;
rctf _rect_fl;
- bool select;
+ eSelectOp sel_op;
/* runtime */
- int pass;
bool is_done;
bool is_changed;
} BoxSelectUserData;
static void view3d_userdata_boxselect_init(
BoxSelectUserData *r_data,
- ViewContext *vc, const rcti *rect, const bool select)
+ ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
{
r_data->vc = vc;
@@ -1614,10 +1878,9 @@ static void view3d_userdata_boxselect_init(
r_data->rect_fl = &r_data->_rect_fl;
BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
- r_data->select = select;
+ r_data->sel_op = sel_op;
/* runtime */
- r_data->pass = 0;
r_data->is_done = false;
r_data->is_changed = false;
}
@@ -1631,14 +1894,17 @@ bool edge_inside_circle(const float cent[2], float radius, const float screen_co
static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
{
BoxSelectUserData *data = userData;
-
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
- SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT);
+ const bool is_select = mv->flag & SELECT;
+ const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
}
}
-static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
+static int do_paintvert_box_select(
+ ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{
- const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
+ const bool use_zbuf = V3D_IS_ZBUF(vc->v3d);
Mesh *me;
MVert *mvert;
struct ImBuf *ibuf;
@@ -1655,8 +1921,9 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
return OPERATOR_CANCELLED;
}
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false);
+ }
if (use_zbuf) {
selar = MEM_callocN(me->totvert + 1, "selar");
@@ -1686,10 +1953,12 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
mvert = me->mvert;
for (a = 1; a <= me->totvert; a++, mvert++) {
- if (selar[a]) {
- if ((mvert->flag & ME_HIDE) == 0) {
- if (select) mvert->flag |= SELECT;
- else mvert->flag &= ~SELECT;
+ if ((mvert->flag & ME_HIDE) == 0) {
+ const bool is_select = mvert->flag & SELECT;
+ const bool is_inside = (selar[a] != 0);
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(mvert->flag, sel_op_result, SELECT);
}
}
}
@@ -1704,17 +1973,18 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo
else {
BoxSelectUserData data;
- view3d_userdata_boxselect_init(&data, vc, rect, select);
+ view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
meshobject_foreachScreenVert(vc, do_paintvert_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
}
- if (select == false) {
+ if (SEL_OP_CAN_DESELECT(sel_op)) {
BKE_mesh_mselect_validate(me);
}
paintvert_flush_flags(vc->obact);
+ paintvert_tag_select_update(vc->C, vc->obact);
return OPERATOR_FINISHED;
}
@@ -1723,39 +1993,42 @@ static void do_nurbs_box_select__doSelect(
void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
{
BoxSelectUserData *data = userData;
- Object *obedit = data->vc->obedit;
- Curve *cu = (Curve *)obedit->data;
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
- if (bp) {
- bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
+ const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
+ if (bp) {
+ const bool is_select = bp->f1 & SELECT;
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
}
- else {
- if (cu->drawflag & CU_HIDE_HANDLES) {
- /* can only be (beztindex == 0) here since handles are hidden */
- bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
+ }
+ else {
+ if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ /* can only be (beztindex == 0) here since handles are hidden */
+ const bool is_select = bezt->f2 & SELECT;
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT);
}
- else {
- if (beztindex == 0) {
- bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
- }
- else if (beztindex == 1) {
- bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
- }
- else {
- bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
- }
+ bezt->f1 = bezt->f3 = bezt->f2;
+ }
+ else {
+ char *flag_p = (&bezt->f1) + beztindex;
+ const bool is_select = *flag_p & SELECT;
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
}
}
}
}
-static int do_nurbs_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
+static int do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{
BoxSelectUserData data;
- view3d_userdata_boxselect_init(&data, vc, rect, select);
+ view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
- if (extend == false && select) {
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
Curve *curve = (Curve *) vc->obedit->data;
ED_curve_deselect_all(curve->editnurb);
}
@@ -1770,19 +2043,22 @@ static int do_nurbs_box_select(ViewContext *vc, rcti *rect, bool select, bool ex
static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2])
{
BoxSelectUserData *data = userData;
-
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
- bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
+ const bool is_select = bp->f1 & SELECT;
+ const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
}
}
-static int do_lattice_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
+static int do_lattice_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{
BoxSelectUserData data;
- view3d_userdata_boxselect_init(&data, vc, rect, select);
+ view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
ED_lattice_flags_set(vc->obedit, 0);
+ }
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -1793,58 +2069,72 @@ static int do_lattice_box_select(ViewContext *vc, rcti *rect, bool select, bool
static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
{
BoxSelectUserData *data = userData;
-
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
- BM_vert_select_set(data->vc->em->bm, eve, data->select);
+ const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
+ const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
}
}
-static void do_mesh_box_select__doSelectEdge(
+static void do_mesh_box_select__doSelectEdge_pass0(
void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{
BoxSelectUserData *data = userData;
-
- if (EDBM_backbuf_check(bm_solidoffs + index)) {
- if (data->pass == 0) {
- if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) {
- BM_edge_select_set(data->vc->em->bm, eed, data->select);
- data->is_done = true;
- }
- }
- else {
- if (edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) {
- BM_edge_select_set(data->vc->em->bm, eed, data->select);
- }
- }
+ const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
+ const bool is_inside = (
+ EDBM_backbuf_check(bm_solidoffs + index) &&
+ edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
+ data->is_done = true;
+ }
+}
+static void do_mesh_box_select__doSelectEdge_pass1(
+ void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
+{
+ BoxSelectUserData *data = userData;
+ const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
+ const bool is_inside = (
+ EDBM_backbuf_check(bm_solidoffs + index) &&
+ edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
}
}
static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
{
BoxSelectUserData *data = userData;
-
- if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
- BM_face_select_set(data->vc->em->bm, efa, data->select);
+ const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
+ const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
}
}
-static int do_mesh_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
+static int do_mesh_box_select(
+ ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{
BoxSelectUserData data;
ToolSettings *ts = vc->scene->toolsettings;
int bbsel;
- view3d_userdata_boxselect_init(&data, vc, rect, select);
+ view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
+ }
/* for non zbuf projections, don't change the GL state */
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- glLoadMatrixf(vc->rv3d->viewmat);
+ GPU_matrix_set(vc->rv3d->viewmat);
bbsel = EDBM_backbuf_border_init(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) {
- edbm_backbuf_check_and_select_verts(vc->em, select);
+ edbm_backbuf_check_and_select_verts(vc->em, sel_op);
}
else {
mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -1852,19 +2142,15 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
}
if (ts->selectmode & SCE_SELECT_EDGE) {
/* Does both bbsel and non-bbsel versions (need screen cos for both) */
-
- data.pass = 0;
- mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
-
- if (data.is_done == 0) {
- data.pass = 1;
- mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
+ mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR);
+ if (data.is_done == false) {
+ mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR);
}
}
if (ts->selectmode & SCE_SELECT_FACE) {
if (bbsel) {
- edbm_backbuf_check_and_select_faces(vc->em, select);
+ edbm_backbuf_check_and_select_faces(vc->em, sel_op);
}
else {
mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -1878,56 +2164,109 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
return OPERATOR_FINISHED;
}
-static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
+static int do_meta_box_select(
+ ViewContext *vc,
+ const rcti *rect, const eSelectOp sel_op)
{
- MetaBall *mb = (MetaBall *)vc->obedit->data;
+ Object *ob = vc->obedit;
+ MetaBall *mb = (MetaBall *)ob->data;
MetaElem *ml;
int a;
unsigned int buffer[MAXPICKBUF];
int hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
+ hits = view3d_opengl_select(
+ vc, buffer, MAXPICKBUF, rect,
+ VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
- if (extend == false && select)
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
BKE_mball_deselect_all(mb);
+ }
+
+ int metaelem_id = 0;
+ for (ml = mb->editelems->first; ml; ml = ml->next, metaelem_id += 0x10000) {
+ bool is_inside_radius = false;
+ bool is_inside_stiff = false;
- for (ml = mb->editelems->first; ml; ml = ml->next) {
for (a = 0; a < hits; a++) {
- if (ml->selcol1 == buffer[(4 * a) + 3]) {
- ml->flag |= MB_SCALE_RAD;
- if (select) ml->flag |= SELECT;
- else ml->flag &= ~SELECT;
+ int hitresult = buffer[(4 * a) + 3];
+
+ if (hitresult == -1) {
+ continue;
+ }
+ else if (hitresult & MBALL_NOSEL) {
+ continue;
+ }
+
+ const uint hit_object = hitresult & 0xFFFF;
+ if (vc->obedit->select_color != hit_object) {
+ continue;
+ }
+
+ if (metaelem_id != (hitresult & 0xFFFF0000 & ~(MBALLSEL_ANY))) {
+ continue;
+ }
+
+ if (hitresult & MBALLSEL_RADIUS) {
+ is_inside_radius = true;
break;
}
- if (ml->selcol2 == buffer[(4 * a) + 3]) {
- ml->flag &= ~MB_SCALE_RAD;
- if (select) ml->flag |= SELECT;
- else ml->flag &= ~SELECT;
+
+ if (hitresult & MBALLSEL_STIFF) {
+ is_inside_stiff = true;
break;
}
}
+ if (is_inside_radius) {
+ ml->flag |= MB_SCALE_RAD;
+ }
+ if (is_inside_stiff) {
+ ml->flag &= ~MB_SCALE_RAD;
+ }
+
+ const bool is_select = (ml->flag & SELECT);
+ const bool is_inside = is_inside_radius || is_inside_stiff;
+
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
+ }
}
return OPERATOR_FINISHED;
}
-static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool extend)
+static int do_armature_box_select(
+ ViewContext *vc,
+ const rcti *rect, const eSelectOp sel_op)
{
- bArmature *arm = vc->obedit->data;
+ /* TODO(campbell): Full support for seleciton operations for edit bones. */
+ const bool select = sel_op == SEL_OP_ADD;
int a;
unsigned int buffer[MAXPICKBUF];
int hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL);
+ hits = view3d_opengl_select(
+ vc, buffer, MAXPICKBUF, rect,
+ VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc->view_layer, vc->v3d, &objects_len);
/* clear flag we use to detect point was affected */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next)
- ebone->flag &= ~BONE_DONE;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
- if (extend == false && select)
- ED_armature_edit_deselect_all_visible(vc->obedit);
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ ED_armature_edit_deselect_all_visible_multi(objects, objects_len);
+ }
/* first we only check points inside the border */
for (a = 0; a < hits; a++) {
@@ -1936,7 +2275,9 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
if ((index & 0xFFFF0000) == 0) {
continue;
}
- EditBone *ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
+
+ EditBone *ebone;
+ ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone);
if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
if (index & BONESEL_TIP) {
ebone->flag |= BONE_DONE;
@@ -1954,10 +2295,14 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
}
/* now we have to flush tag from parents... */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- if (ebone->parent->flag & BONE_DONE) {
- ebone->flag |= BONE_DONE;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ if (ebone->parent->flag & BONE_DONE) {
+ ebone->flag |= BONE_DONE;
+ }
}
}
}
@@ -1967,7 +2312,8 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
int index = buffer[(4 * a) + 3];
if (index != -1) {
if (index & BONESEL_BONE) {
- EditBone *ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
+ EditBone *ebone;
+ ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone);
if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
if (!(ebone->flag & BONE_DONE)) {
if (select) {
@@ -1982,45 +2328,131 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
}
}
- ED_armature_edit_sync_selection(arm->edbo);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ bArmature *arm = obedit->data;
+ ED_armature_edit_sync_selection(arm->edbo);
+ }
+
+ MEM_freeN(objects);
return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend)
+/**
+ * Compare result of 'GPU_select': 'uint[4]',
+ * needed for when we need to align with object draw-order.
+ */
+static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p)
{
- Bone *bone;
- Object *ob = vc->obact;
- unsigned int *vbuffer = NULL; /* selection buffer */
- unsigned int *col; /* color in buffer */
- int bone_only;
- int bone_selected = 0;
+ /* 4th element is select id */
+ uint sel_a = ((uint *)sel_a_p)[3];
+ uint sel_b = ((uint *)sel_b_p)[3];
+
+#ifdef __BIG_ENDIAN__
+ BLI_endian_switch_uint32(&sel_a);
+ BLI_endian_switch_uint32(&sel_b);
+#endif
+
+ if (sel_a < sel_b) {
+ return -1;
+ }
+ else if (sel_a > sel_b) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
+{
+ View3D *v3d = vc->v3d;
+ bool changed = false;
int totobj = MAXPICKBUF; /* XXX solve later */
- int hits;
- if ((ob) && (ob->mode & OB_MODE_POSE))
- bone_only = 1;
- else
- bone_only = 0;
+ /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
+ uint *vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(uint[4]), "selection buffer");
+ const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact);
+ const int hits = view3d_opengl_select(
+ vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect,
+ VIEW3D_SELECT_ALL, select_filter);
- if (extend == false && select) {
- if (bone_only) {
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((select == false) || ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)) {
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
+ for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.tag &= ~LIB_TAG_DOIT;
+ }
+
+ Base **bases = NULL;
+ BLI_array_declare(bases);
+
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ object_deselect_all_visible(vc->view_layer, vc->v3d);
+ changed = true;
+ }
+
+ if ((hits == -1) && !SEL_OP_USE_OUTSIDE(sel_op)) {
+ goto finally;
+ }
+
+ for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) {
+ if (BASE_SELECTABLE(v3d, base)) {
+ if ((base->object->select_color & 0x0000FFFF) != 0) {
+ BLI_array_append(bases, base);
}
- CTX_DATA_END;
}
- else {
- object_deselect_all_visible(vc->scene, vc->v3d);
+ }
+
+ /* The draw order doesn't always match the order we populate the engine, see: T51695. */
+ qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp);
+
+ for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) {
+ Bone *bone;
+ Base *base = ED_armature_base_and_bone_from_select_buffer(bases, BLI_array_len(bases), *col, &bone);
+ base->object->id.tag |= LIB_TAG_DOIT;
+ }
+
+ for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) {
+ if (BASE_SELECTABLE(v3d, base)) {
+ const bool is_select = base->flag & BASE_SELECTED;
+ const bool is_inside = base->object->id.tag & LIB_TAG_DOIT;
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
+ changed = true;
+ }
}
}
+finally:
+ if (bases != NULL) {
+ MEM_freeN(bases);
+ }
+
+ MEM_freeN(vbuffer);
+
+ if (changed) {
+ DEG_id_tag_update(&vc->scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op)
+{
+ uint bases_len;
+ Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len);
+
+ int totobj = MAXPICKBUF; /* XXX solve later */
+
/* selection buffer now has bones potentially too, so we add MAXPICKBUF */
- vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer");
- hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL);
+ uint *vbuffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(uint[4]), "selection buffer");
+ const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact);
+ const int hits = view3d_opengl_select(
+ vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect,
+ VIEW3D_SELECT_ALL, select_filter);
/*
* LOGIC NOTES (theeth):
* The buffer and ListBase have the same relative order, which makes the selection
@@ -2028,73 +2460,66 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
* is the same as the object, we have a hit and can move to the next color
* and object pair, if not, just move to the next object,
* keeping the same color until we have a hit.
- *
- * The buffer order is defined by OGL standard, hopefully no stupid GFX card
- * does it incorrectly.
*/
- if (hits > 0) { /* no need to loop if there's no hit */
- Base *base;
- col = vbuffer + 3;
-
- for (base = vc->scene->base.first; base && hits; base = base->next) {
- if (BASE_SELECTABLE(vc->v3d, base)) {
- while (base->selcol == (*col & 0xFFFF)) { /* we got an object */
- if (*col & 0xFFFF0000) { /* we got a bone */
- bone = ED_armature_bone_find_index(base->object, *col & ~(BONESEL_ANY));
- if (bone) {
- if (select) {
- if ((bone->flag & BONE_UNSELECTABLE) == 0) {
- bone->flag |= BONE_SELECTED;
- bone_selected = 1;
- }
- }
- else {
- bArmature *arm = base->object->data;
- bone->flag &= ~BONE_SELECTED;
- if (arm->act_bone == bone)
- arm->act_bone = NULL;
- }
- }
- }
- else if (!bone_only) {
- ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
- }
+ if (hits > 0) {
+ /* no need to loop if there's no hit */
- col += 4; /* next color */
- hits--;
- if (hits == 0) break;
- }
- }
+ /* The draw order doesn't always match the order we populate the engine, see: T51695. */
+ qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp);
- if (bone_selected) {
- if (base->object && (base->object->type == OB_ARMATURE)) {
- bArmature *arm = base->object->data;
+ for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) {
+ Bone *bone;
+ Base *base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, *col, &bone);
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
+ if (base == NULL) {
+ continue;
+ }
- if (arm && (arm->flag & ARM_HAS_VIZ_DEPS)) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* Loop over contiguous bone hits for 'base'. */
+ for (; col != col_end; col += 4) {
+ /* should never fail */
+ if (bone != NULL) {
+ base->object->id.tag |= LIB_TAG_DOIT;
+ bone->flag |= BONE_DONE;
+ }
+
+ /* Select the next bone if we're not switching bases. */
+ if (col + 4 != col_end) {
+ if ((base->object->select_color & 0x0000FFFF) != (col[4] & 0x0000FFFF)) {
+ break;
+ }
+ if (base->object->pose != NULL) {
+ const uint hit_bone = (col[4] & ~BONESEL_ANY) >> 16;
+ bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
+ bone = pchan ? pchan->bone : NULL;
+ }
+ else {
+ bone = NULL;
}
}
}
}
+ }
+ const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
+ if (changed_multi) {
+ DEG_id_tag_update(&vc->scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
}
+
+ if (bases != NULL) {
+ MEM_freeN(bases);
+ }
MEM_freeN(vbuffer);
return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-static int view3d_borderselect_exec(bContext *C, wmOperator *op)
+static int view3d_box_select_exec(bContext *C, wmOperator *op)
{
ViewContext vc;
rcti rect;
- bool extend;
- bool select;
-
int ret = OPERATOR_CANCELLED;
view3d_operator_needs_opengl(C);
@@ -2102,94 +2527,115 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
/* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc);
- select = !RNA_boolean_get(op->ptr, "deselect");
- extend = RNA_boolean_get(op->ptr, "extend");
+ eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
WM_operator_properties_border_to_rcti(op, &rect);
if (vc.obedit) {
- switch (vc.obedit->type) {
- case OB_MESH:
- vc.em = BKE_editmesh_from_object(vc.obedit);
- ret = do_mesh_box_select(&vc, &rect, select, extend);
-// if (EM_texFaceCheck())
- if (ret & OPERATOR_FINISHED) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
- }
- break;
- case OB_CURVE:
- case OB_SURF:
- ret = do_nurbs_box_select(&vc, &rect, select, extend);
- if (ret & OPERATOR_FINISHED) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
- }
- break;
- case OB_MBALL:
- ret = do_meta_box_select(&vc, &rect, select, extend);
- if (ret & OPERATOR_FINISHED) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
- }
- break;
- case OB_ARMATURE:
- ret = do_armature_box_select(&vc, &rect, select, extend);
- if (ret & OPERATOR_FINISHED) {
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
- }
- break;
- case OB_LATTICE:
- ret = do_lattice_box_select(&vc, &rect, select, extend);
- if (ret & OPERATOR_FINISHED) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
- }
- break;
- default:
- assert(!"border select on incorrect object type");
- break;
+
+ FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, vc.obedit->mode, ob_iter) {
+ ED_view3d_viewcontext_init_object(&vc, ob_iter);
+
+ switch (vc.obedit->type) {
+ case OB_MESH:
+ vc.em = BKE_editmesh_from_object(vc.obedit);
+ ret |= do_mesh_box_select(&vc, &rect, sel_op);
+ if (ret & OPERATOR_FINISHED) {
+ DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
+ }
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ ret |= do_nurbs_box_select(&vc, &rect, sel_op);
+ if (ret & OPERATOR_FINISHED) {
+ DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
+ }
+ break;
+ case OB_MBALL:
+ ret |= do_meta_box_select(&vc, &rect, sel_op);
+ if (ret & OPERATOR_FINISHED) {
+ DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
+ }
+ break;
+ case OB_ARMATURE:
+ ret |= do_armature_box_select(&vc, &rect, sel_op);
+ if (ret & OPERATOR_FINISHED) {
+ DEG_id_tag_update(&vc.obedit->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
+ }
+ break;
+ case OB_LATTICE:
+ ret |= do_lattice_box_select(&vc, &rect, sel_op);
+ if (ret & OPERATOR_FINISHED) {
+ DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
+ }
+ break;
+ default:
+ assert(!"box select on incorrect object type");
+ break;
+ }
}
+ FOREACH_OBJECT_IN_MODE_END;
}
else { /* no editmode, unified for bones and objects */
if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) {
- ret = ED_sculpt_mask_box_select(C, &vc, &rect, select, extend);
+ /* XXX, this is not selection, could be it's own operator. */
+ ret |= ED_sculpt_mask_box_select(C, &vc, &rect, sel_op == SEL_OP_ADD ? true : false);
}
else if (vc.obact && BKE_paint_select_face_test(vc.obact)) {
- ret = do_paintface_box_select(&vc, &rect, select, extend);
+ ret |= do_paintface_box_select(&vc, &rect, sel_op);
}
else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) {
- ret = do_paintvert_box_select(&vc, &rect, select, extend);
+ ret |= do_paintvert_box_select(&vc, &rect, sel_op);
}
else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) {
- ret = PE_border_select(C, &rect, select, extend);
+ ret |= PE_box_select(C, &rect, sel_op);
+ }
+ else if (vc.obact && vc.obact->mode & OB_MODE_POSE) {
+ ret |= do_pose_box_select(C, &vc, &rect, sel_op);
}
else { /* object mode with none active */
- ret = do_object_pose_box_select(C, &vc, &rect, select, extend);
+ ret |= do_object_box_select(C, &vc, &rect, sel_op);
}
}
+ if (ret & OPERATOR_FINISHED) {
+ ret = OPERATOR_FINISHED;
+ }
+ else {
+ ret = OPERATOR_CANCELLED;
+ }
+
return ret;
}
/* *****************Selection Operators******************* */
-/* ****** Border Select ****** */
-void VIEW3D_OT_select_border(wmOperatorType *ot)
+/* ****** Box Select ****** */
+void VIEW3D_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->description = "Select items using border selection";
- ot->idname = "VIEW3D_OT_select_border";
+ ot->name = "Box Select";
+ ot->description = "Select items using box selection";
+ ot->idname = "VIEW3D_OT_select_box";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = view3d_borderselect_exec;
- ot->modal = WM_gesture_border_modal;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = view3d_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
ot->poll = view3d_selectable_data;
- ot->cancel = WM_gesture_border_cancel;
+ ot->cancel = WM_gesture_box_cancel;
/* flags */
ot->flag = OPTYPE_UNDO;
/* rna */
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box(ot);
+ WM_operator_properties_select_operation(ot);
}
@@ -2200,7 +2646,7 @@ static bool ed_wpaint_vertex_select_pick(
bool extend, bool deselect, bool toggle, Object *obact)
{
View3D *v3d = CTX_wm_view3d(C);
- const bool use_zbuf = (v3d->flag & V3D_ZBUF_SELECT) != 0;
+ const bool use_zbuf = V3D_IS_ZBUF(v3d);
Mesh *me = obact->data; /* already checked for NULL */
unsigned int index = 0;
@@ -2231,7 +2677,7 @@ static bool ed_wpaint_vertex_select_pick(
}
paintvert_flush_flags(obact);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
+ paintvert_tag_select_update(C, obact);
return true;
}
return false;
@@ -2319,8 +2765,8 @@ void VIEW3D_OT_select(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Activate/Select";
- ot->description = "Activate/select item(s)";
+ ot->name = "Select";
+ ot->description = "Select and activate item(s)";
ot->idname = "VIEW3D_OT_select";
/* api callbacks */
@@ -2334,9 +2780,12 @@ void VIEW3D_OT_select(wmOperatorType *ot)
/* properties */
WM_operator_properties_mouse_select(ot);
- RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting, in editmode used to extend object selection");
- RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
- RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)");
+ prop = RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting, in editmode used to extend object selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
@@ -2415,7 +2864,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva
if (ts->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) {
- edbm_backbuf_check_and_select_verts(vc->em, select);
+ edbm_backbuf_check_and_select_verts(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
else {
mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -2424,7 +2873,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva
if (ts->selectmode & SCE_SELECT_EDGE) {
if (bbsel) {
- edbm_backbuf_check_and_select_edges(vc->em, select);
+ edbm_backbuf_check_and_select_edges(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
else {
mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
@@ -2433,7 +2882,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva
if (ts->selectmode & SCE_SELECT_FACE) {
if (bbsel) {
- edbm_backbuf_check_and_select_faces(vc->em, select);
+ edbm_backbuf_check_and_select_faces(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
}
else {
mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -2454,14 +2903,14 @@ static void paint_facesel_circle_select(ViewContext *vc, const bool select, cons
bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
if (bbsel) {
- edbm_backbuf_check_and_select_tfaces(me, select);
+ edbm_backbuf_check_and_select_tfaces(me, select ? SEL_OP_ADD : SEL_OP_SUB);
EDBM_backbuf_free();
paintface_flush_flags(ob, SELECT);
+ paintface_tag_select_update(vc->C, ob);
}
}
-static void paint_vertsel_circle_select_doSelectVert(
- void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
{
CircleSelectUserData *data = userData;
@@ -2471,7 +2920,7 @@ static void paint_vertsel_circle_select_doSelectVert(
}
static void paint_vertsel_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
{
- const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
+ const bool use_zbuf = V3D_IS_ZBUF(vc->v3d);
Object *ob = vc->obact;
Mesh *me = ob->data;
bool bbsel;
@@ -2482,7 +2931,7 @@ static void paint_vertsel_circle_select(ViewContext *vc, const bool select, cons
bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
if (bbsel) {
- edbm_backbuf_check_and_select_verts_obmode(me, select);
+ edbm_backbuf_check_and_select_verts_obmode(me, select ? SEL_OP_ADD : SEL_OP_SET);
EDBM_backbuf_free();
}
}
@@ -2499,6 +2948,7 @@ static void paint_vertsel_circle_select(ViewContext *vc, const bool select, cons
BKE_mesh_mselect_validate(me);
}
paintvert_flush_flags(ob);
+ paintvert_tag_select_update(vc->C, ob);
}
@@ -2506,15 +2956,13 @@ static void nurbscurve_circle_doSelect(
void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
{
CircleSelectUserData *data = userData;
- Object *obedit = data->vc->obedit;
- Curve *cu = (Curve *)obedit->data;
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
if (bp) {
bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
}
else {
- if (cu->drawflag & CU_HIDE_HANDLES) {
+ if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
/* can only be (beztindex == 0) here since handles are hidden */
bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
}
@@ -2632,14 +3080,7 @@ static void pose_circle_select(ViewContext *vc, const bool select, const int mva
pose_foreachScreenBone(vc, do_circle_select_pose__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
if (data.is_changed) {
- bArmature *arm = vc->obact->data;
-
- WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obact);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&vc->obact->id, OB_RECALC_DATA);
- }
+ ED_pose_bone_select_tag_update(vc->obact);
}
}
@@ -2749,7 +3190,8 @@ static void mball_circle_select(ViewContext *vc, const bool select, const int mv
/** Callbacks for circle selection in Editmode */
-static void obedit_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
+static void obedit_circle_select(
+ ViewContext *vc, const bool select, const int mval[2], float rad)
{
switch (vc->obedit->type) {
case OB_MESH:
@@ -2775,23 +3217,25 @@ static void obedit_circle_select(ViewContext *vc, const bool select, const int m
static bool object_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad)
{
- Scene *scene = vc->scene;
+ ViewLayer *view_layer = vc->view_layer;
+ View3D *v3d = vc->v3d;
+
const float radius_squared = rad * rad;
const float mval_fl[2] = {mval[0], mval[1]};
bool changed = false;
- const int select_flag = select ? SELECT : 0;
+ const int select_flag = select ? BASE_SELECTED : 0;
Base *base;
- for (base = FIRSTBASE; base; base = base->next) {
- if (BASE_SELECTABLE(vc->v3d, base) && ((base->flag & SELECT) != select_flag)) {
+ for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ if (BASE_SELECTABLE(v3d, base) && ((base->flag & BASE_SELECTED) != select_flag)) {
float screen_co[2];
if (ED_view3d_project_float_global(
vc->ar, base->object->obmat[3], screen_co,
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
{
if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) {
- ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT);
+ ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
changed = true;
}
}
@@ -2805,43 +3249,54 @@ static bool object_circle_select(ViewContext *vc, const bool select, const int m
static int view3d_circle_select_exec(bContext *C, wmOperator *op)
{
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
- Object *obact = vc.obact;
- Object *obedit = vc.obedit;
const int radius = RNA_int_get(op->ptr, "radius");
const bool select = !RNA_boolean_get(op->ptr, "deselect");
const int mval[2] = {RNA_int_get(op->ptr, "x"),
RNA_int_get(op->ptr, "y")};
+
+ ED_view3d_viewcontext_init(C, &vc);
+
+ Object *obact = vc.obact;
+ Object *obedit = vc.obedit;
+
if (obedit || BKE_paint_select_elem_test(obact) ||
(obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) )
{
view3d_operator_needs_opengl(C);
- if (CTX_data_edit_object(C)) {
- obedit_circle_select(&vc, select, mval, (float)radius);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
- }
- else if (BKE_paint_select_face_test(obact)) {
- paint_facesel_circle_select(&vc, select, mval, (float)radius);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
- }
- else if (BKE_paint_select_vert_test(obact)) {
- paint_vertsel_circle_select(&vc, select, mval, (float)radius);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
- }
- else if (obact->mode & OB_MODE_POSE) {
- pose_circle_select(&vc, select, mval, (float)radius);
- }
- else {
- return PE_circle_select(C, select, mval, (float)radius);
+ FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->mode, ob_iter) {
+ ED_view3d_viewcontext_init_object(&vc, ob_iter);
+
+ obact = vc.obact;
+ obedit = vc.obedit;
+
+ if (CTX_data_edit_object(C)) {
+ obedit_circle_select(&vc, select, mval, (float)radius);
+ DEG_id_tag_update(obact->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
+ }
+ else if (BKE_paint_select_face_test(obact)) {
+ paint_facesel_circle_select(&vc, select, mval, (float)radius);
+ }
+ else if (BKE_paint_select_vert_test(obact)) {
+ paint_vertsel_circle_select(&vc, select, mval, (float)radius);
+ }
+ else if (obact->mode & OB_MODE_POSE) {
+ pose_circle_select(&vc, select, mval, (float)radius);
+ }
+ else {
+ return PE_circle_select(C, select, mval, (float)radius);
+ }
}
+ FOREACH_OBJECT_IN_MODE_END;
}
else if (obact && obact->mode & OB_MODE_SCULPT) {
return OPERATOR_CANCELLED;
}
else {
if (object_circle_select(&vc, select, mval, (float)radius)) {
+ DEG_id_tag_update(&vc.scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 80586217691..a220257c63f 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -30,6 +30,8 @@
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
@@ -40,13 +42,17 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_tracking.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -66,75 +72,96 @@ static bool snap_calc_active_center(bContext *C, const bool select_only, float r
/* *********************** operators ******************** */
+/** Snaps every individual object center to its nearest point on the grid. **/
static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- RegionView3D *rv3d = CTX_wm_region_data(C);
+ View3D *v3d = CTX_wm_view3d(C);
TransVertStore tvs = {NULL};
TransVert *tv;
float gridf, imat[3][3], bmat[3][3], vec[3];
int a;
- gridf = rv3d->gridview;
+ gridf = ED_view3d_grid_scale(scene, v3d, NULL);
if (obedit) {
- if (ED_transverts_check_obedit(obedit))
- ED_transverts_create_from_obedit(&tvs, obedit, 0);
- if (tvs.transverts_tot == 0)
- return OPERATOR_CANCELLED;
-
- copy_m3_m4(bmat, obedit->obmat);
- invert_m3_m3(imat, bmat);
-
- tv = tvs.transverts;
- for (a = 0; a < tvs.transverts_tot; a++, tv++) {
- copy_v3_v3(vec, tv->loc);
- mul_m3_v3(bmat, vec);
- add_v3_v3(vec, obedit->obmat[3]);
- vec[0] = gridf * floorf(0.5f + vec[0] / gridf);
- vec[1] = gridf * floorf(0.5f + vec[1] / gridf);
- vec[2] = gridf * floorf(0.5f + vec[2] / gridf);
- sub_v3_v3(vec, obedit->obmat[3]);
-
- mul_m3_v3(imat, vec);
- copy_v3_v3(tv->loc, vec);
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ obedit = objects[ob_index];
- ED_transverts_update_obedit(&tvs, obedit);
- ED_transverts_free(&tvs);
+ if (obedit->type == OB_MESH) {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+ }
+
+ if (ED_transverts_check_obedit(obedit)) {
+ ED_transverts_create_from_obedit(&tvs, obedit, 0);
+ }
+
+ if (tvs.transverts_tot != 0) {
+ copy_m3_m4(bmat, obedit->obmat);
+ invert_m3_m3(imat, bmat);
+
+ tv = tvs.transverts;
+ for (a = 0; a < tvs.transverts_tot; a++, tv++) {
+ copy_v3_v3(vec, tv->loc);
+ mul_m3_v3(bmat, vec);
+ add_v3_v3(vec, obedit->obmat[3]);
+ vec[0] = gridf * floorf(0.5f + vec[0] / gridf);
+ vec[1] = gridf * floorf(0.5f + vec[1] / gridf);
+ vec[2] = gridf * floorf(0.5f + vec[2] / gridf);
+ sub_v3_v3(vec, obedit->obmat[3]);
+
+ mul_m3_v3(imat, vec);
+ copy_v3_v3(tv->loc, vec);
+ }
+ ED_transverts_update_obedit(&tvs, obedit);
+ }
+ ED_transverts_free(&tvs);
+ }
+ MEM_freeN(objects);
}
else {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(view_layer_eval, v3d, ob_eval)
{
+ Object *ob = DEG_get_original_object(ob_eval);
if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan;
- bArmature *arm = ob->data;
+ bPoseChannel *pchan_eval;
+ bArmature *arm_eval = ob_eval->data;
- invert_m4_m4(ob->imat, ob->obmat);
+ invert_m4_m4(ob_eval->imat, ob_eval->obmat);
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_SELECTED) {
- if (pchan->bone->layer & arm->layer) {
- if ((pchan->bone->flag & BONE_CONNECTED) == 0) {
+ for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) {
+ if (pchan_eval->bone->flag & BONE_SELECTED) {
+ if (pchan_eval->bone->layer & arm_eval->layer) {
+ if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) {
float nLoc[3];
/* get nearest grid point to snap to */
- copy_v3_v3(nLoc, pchan->pose_mat[3]);
+ copy_v3_v3(nLoc, pchan_eval->pose_mat[3]);
/* We must operate in world space! */
- mul_m4_v3(ob->obmat, nLoc);
+ mul_m4_v3(ob_eval->obmat, nLoc);
vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf);
vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf);
vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf);
/* Back in object space... */
- mul_m4_v3(ob->imat, vec);
+ mul_m4_v3(ob_eval->imat, vec);
/* Get location of grid point in pose space. */
- BKE_armature_loc_pose_to_bone(pchan, vec, vec);
+ BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec);
- /* adjust location */
+ /* adjust location on the original pchan*/
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name);
if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
pchan->loc[0] = vec[0];
if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
@@ -153,34 +180,34 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
}
ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else {
- vec[0] = -ob->obmat[3][0] + gridf * floorf(0.5f + ob->obmat[3][0] / gridf);
- vec[1] = -ob->obmat[3][1] + gridf * floorf(0.5f + ob->obmat[3][1] / gridf);
- vec[2] = -ob->obmat[3][2] + gridf * floorf(0.5f + ob->obmat[3][2] / gridf);
+ vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf);
+ vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf);
+ vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf);
if (ob->parent) {
float originmat[3][3];
- BKE_object_where_is_calc_ex(scene, NULL, ob, originmat);
+ BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
invert_m3_m3(imat, originmat);
mul_m3_v3(imat, vec);
}
if ((ob->protectflag & OB_LOCK_LOCX) == 0)
- ob->loc[0] += vec[0];
+ ob->loc[0] = ob_eval->loc[0] + vec[0];
if ((ob->protectflag & OB_LOCK_LOCY) == 0)
- ob->loc[1] += vec[1];
+ ob->loc[1] = ob_eval->loc[1] + vec[1];
if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
- ob->loc[2] += vec[2];
+ ob->loc[2] = ob_eval->loc[2] + vec[2];
/* auto-keyframing */
ED_autokeyframe_object(C, scene, ob, ks);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
- CTX_DATA_END;
+ FOREACH_SELECTED_EDITABLE_OBJECT_END;
}
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -192,7 +219,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Snap Selection to Grid";
- ot->description = "Snap selected item(s) to nearest grid division";
+ ot->description = "Snap selected item(s) to their nearest grid division";
ot->idname = "VIEW3D_OT_snap_selected_to_grid";
/* api callbacks */
@@ -200,13 +227,20 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
ot->poll = ED_operator_region_view3d_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
/* *************************************************** */
+/** Snaps the selection as a whole (use_offset=true) or each selected object to the given location.
+ *
+ * \param snap_target_global: a location in global space to snap to (eg. 3D cursor or active object).
+ * \param use_offset: if the selected objects should maintain their relative offsets and be snapped by the selection
+ * pivot point (median, active), or if every object origin should be snapped to the given location.
+**/
static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
@@ -219,7 +253,7 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global
int a;
if (use_offset) {
- if ((v3d && v3d->around == V3D_AROUND_ACTIVE) &&
+ if ((v3d && scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) &&
snap_calc_active_center(C, true, center_global))
{
/* pass */
@@ -232,104 +266,122 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global
if (obedit) {
float snap_target_local[3];
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ obedit = objects[ob_index];
- if (ED_transverts_check_obedit(obedit))
- ED_transverts_create_from_obedit(&tvs, obedit, 0);
- if (tvs.transverts_tot == 0)
- return OPERATOR_CANCELLED;
+ if (obedit->type == OB_MESH) {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- copy_m3_m4(bmat, obedit->obmat);
- invert_m3_m3(imat, bmat);
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+ }
- /* get the cursor in object space */
- sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]);
- mul_m3_v3(imat, snap_target_local);
+ if (ED_transverts_check_obedit(obedit)) {
+ ED_transverts_create_from_obedit(&tvs, obedit, 0);
+ }
- if (use_offset) {
- float offset_local[3];
+ if (tvs.transverts_tot != 0) {
+ copy_m3_m4(bmat, obedit->obmat);
+ invert_m3_m3(imat, bmat);
- mul_v3_m3v3(offset_local, imat, offset_global);
+ /* get the cursor in object space */
+ sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]);
+ mul_m3_v3(imat, snap_target_local);
- tv = tvs.transverts;
- for (a = 0; a < tvs.transverts_tot; a++, tv++) {
- add_v3_v3(tv->loc, offset_local);
- }
- }
- else {
- tv = tvs.transverts;
- for (a = 0; a < tvs.transverts_tot; a++, tv++) {
- copy_v3_v3(tv->loc, snap_target_local);
+ if (use_offset) {
+ float offset_local[3];
+
+ mul_v3_m3v3(offset_local, imat, offset_global);
+
+ tv = tvs.transverts;
+ for (a = 0; a < tvs.transverts_tot; a++, tv++) {
+ add_v3_v3(tv->loc, offset_local);
+ }
+ }
+ else {
+ tv = tvs.transverts;
+ for (a = 0; a < tvs.transverts_tot; a++, tv++) {
+ copy_v3_v3(tv->loc, snap_target_local);
+ }
+ }
+ ED_transverts_update_obedit(&tvs, obedit);
}
+ ED_transverts_free(&tvs);
}
-
- ED_transverts_update_obedit(&tvs, obedit);
- ED_transverts_free(&tvs);
+ MEM_freeN(objects);
}
else if (obact && (obact->mode & OB_MODE_POSE)) {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
-
- bPoseChannel *pchan;
- bArmature *arm = obact->data;
- float snap_target_local[3];
-
- invert_m4_m4(obact->imat, obact->obmat);
- mul_v3_m4v3(snap_target_local, obact->imat, snap_target_global);
-
- for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->flag & BONE_SELECTED) &&
- (PBONE_VISIBLE(arm, pchan->bone)) &&
- /* if the bone has a parent and is connected to the parent,
- * don't do anything - will break chain unless we do auto-ik.
- */
- (pchan->bone->flag & BONE_CONNECTED) == 0)
- {
- pchan->bone->flag |= BONE_TRANSFORM;
- }
- else {
- pchan->bone->flag &= ~BONE_TRANSFORM;
- }
- }
-
- for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->flag & BONE_TRANSFORM) &&
- /* check that our parents not transformed (if we have one) */
- ((pchan->bone->parent &&
- BKE_armature_bone_flag_test_recursive(pchan->bone->parent, BONE_TRANSFORM)) == 0))
- {
- /* Get position in pchan (pose) space. */
- float cursor_pose[3];
-
- if (use_offset) {
- mul_v3_m4v3(cursor_pose, obact->obmat, pchan->pose_mat[3]);
- add_v3_v3(cursor_pose, offset_global);
-
- mul_m4_v3(obact->imat, cursor_pose);
- BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ bPoseChannel *pchan;
+ bArmature *arm = ob->data;
+ float snap_target_local[3];
+
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_v3_m4v3(snap_target_local, ob->imat, snap_target_global);
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_SELECTED) &&
+ (PBONE_VISIBLE(arm, pchan->bone)) &&
+ /* if the bone has a parent and is connected to the parent,
+ * don't do anything - will break chain unless we do auto-ik.
+ */
+ (pchan->bone->flag & BONE_CONNECTED) == 0)
+ {
+ pchan->bone->flag |= BONE_TRANSFORM;
}
else {
- BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose);
+ pchan->bone->flag &= ~BONE_TRANSFORM;
}
+ }
- /* copy new position */
- if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
- pchan->loc[0] = cursor_pose[0];
- if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
- pchan->loc[1] = cursor_pose[1];
- if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
- pchan->loc[2] = cursor_pose[2];
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_TRANSFORM) &&
+ /* check that our parents not transformed (if we have one) */
+ ((pchan->bone->parent &&
+ BKE_armature_bone_flag_test_recursive(pchan->bone->parent, BONE_TRANSFORM)) == 0))
+ {
+ /* Get position in pchan (pose) space. */
+ float cursor_pose[3];
+
+ if (use_offset) {
+ mul_v3_m4v3(cursor_pose, ob->obmat, pchan->pose_mat[3]);
+ add_v3_v3(cursor_pose, offset_global);
+
+ mul_m4_v3(ob->imat, cursor_pose);
+ BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
+ }
+ else {
+ BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose);
+ }
- /* auto-keyframing */
- ED_autokeyframe_pchan(C, scene, obact, pchan, ks);
+ /* copy new position */
+ if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
+ pchan->loc[0] = cursor_pose[0];
+ if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
+ pchan->loc[1] = cursor_pose[1];
+ if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
+ pchan->loc[2] = cursor_pose[2];
+
+ /* auto-keyframing */
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ }
}
- }
- for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan->bone->flag &= ~BONE_TRANSFORM;
- }
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone->flag &= ~BONE_TRANSFORM;
+ }
- obact->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
+ ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
- DAG_id_tag_update(&obact->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ CTX_DATA_END;
}
else {
struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
@@ -370,7 +422,7 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global
if (ob->parent) {
float originmat[3][3];
- BKE_object_where_is_calc_ex(scene, NULL, ob, originmat);
+ BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
invert_m3_m3(imat, originmat);
mul_m3_v3(imat, cursor_parent);
@@ -385,7 +437,7 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global
/* auto-keyframing */
ED_autokeyframe_object(C, scene, ob, ks);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
}
@@ -402,9 +454,8 @@ static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- const float *snap_target_global = ED_view3d_cursor3d_get(scene, v3d);
+ const float *snap_target_global = scene->cursor.location;
return snap_selected_to_location(C, snap_target_global, use_offset);
}
@@ -413,7 +464,7 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Snap Selection to Cursor";
- ot->description = "Snap selected item(s) to cursor";
+ ot->description = "Snap selected item(s) to the 3D cursor";
ot->idname = "VIEW3D_OT_snap_selected_to_cursor";
/* api callbacks */
@@ -421,12 +472,16 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
/* rna */
- RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", "");
+ RNA_def_boolean(ot->srna, "use_offset", 1, "Offset",
+ "If the selection should be snapped as a whole or by each object center");
}
+/* *************************************************** */
+
+/** Snaps each selected object to the location of the active selected object. **/
static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
{
float snap_target_global[3];
@@ -451,27 +506,28 @@ void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
/* *************************************************** */
+/** Snaps the 3D cursor location to its nearest point on the grid. **/
static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- RegionView3D *rv3d = CTX_wm_region_data(C);
View3D *v3d = CTX_wm_view3d(C);
float gridf, *curs;
- gridf = rv3d->gridview;
- curs = ED_view3d_cursor3d_get(scene, v3d);
+ gridf = ED_view3d_grid_scale(scene, v3d, NULL);
+ curs = scene->cursor.location;
curs[0] = gridf * floorf(0.5f + curs[0] / gridf);
curs[1] = gridf * floorf(0.5f + curs[1] / gridf);
curs[2] = gridf * floorf(0.5f + curs[2] / gridf);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); /* hrm */
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
@@ -480,7 +536,7 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Snap Cursor to Grid";
- ot->description = "Snap cursor to nearest grid division";
+ ot->description = "Snap 3D cursor to the nearest grid division";
ot->idname = "VIEW3D_OT_snap_cursor_to_grid";
/* api callbacks */
@@ -493,7 +549,8 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
/* **************************************************** */
-static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
+/** Returns the center position of a tracking marker visible on the viewport (useful to snap to). **/
+static void bundle_midpoint(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_vec[3])
{
MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
MovieTracking *tracking;
@@ -508,7 +565,7 @@ static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
copy_m4_m4(cammat, ob->obmat);
- BKE_tracking_get_camera_object_matrix(scene, ob, mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, scene, ob, mat);
INIT_MINMAX(min, max);
@@ -541,12 +598,15 @@ static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
}
if (ok) {
- mid_v3_v3v3(vec, min, max);
+ mid_v3_v3v3(r_vec, min, max);
}
}
+/** Snaps the 3D cursor location to the median point of the selection. **/
static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -560,46 +620,64 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
zero_v3(centroid);
if (obedit) {
+ int global_transverts_tot = 0;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ obedit = objects[ob_index];
+
+ /* We can do that quick check for meshes only... */
+ if (obedit->type == OB_MESH) {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+ }
- if (ED_transverts_check_obedit(obedit))
- ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES);
-
- if (tvs.transverts_tot == 0) {
- return false;
- }
-
- copy_m3_m4(bmat, obedit->obmat);
+ if (ED_transverts_check_obedit(obedit)) {
+ ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES);
+ }
- tv = tvs.transverts;
- for (a = 0; a < tvs.transverts_tot; a++, tv++) {
- copy_v3_v3(vec, tv->loc);
- mul_m3_v3(bmat, vec);
- add_v3_v3(vec, obedit->obmat[3]);
- add_v3_v3(centroid, vec);
- minmax_v3v3_v3(min, max, vec);
+ global_transverts_tot += tvs.transverts_tot;
+ if (tvs.transverts_tot != 0) {
+ Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ copy_m3_m4(bmat, obedit_eval->obmat);
+
+ tv = tvs.transverts;
+ for (a = 0; a < tvs.transverts_tot; a++, tv++) {
+ copy_v3_v3(vec, tv->loc);
+ mul_m3_v3(bmat, vec);
+ add_v3_v3(vec, obedit_eval->obmat[3]);
+ add_v3_v3(centroid, vec);
+ minmax_v3v3_v3(min, max, vec);
+ }
+ }
+ ED_transverts_free(&tvs);
}
+ MEM_freeN(objects);
- if (v3d->around == V3D_AROUND_CENTER_MEAN) {
- mul_v3_fl(centroid, 1.0f / (float)tvs.transverts_tot);
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEAN) {
+ mul_v3_fl(centroid, 1.0f / (float)global_transverts_tot);
copy_v3_v3(cursor, centroid);
}
else {
mid_v3_v3v3(cursor, min, max);
}
-
- ED_transverts_free(&tvs);
}
else {
Object *obact = CTX_data_active_object(C);
if (obact && (obact->mode & OB_MODE_POSE)) {
- bArmature *arm = obact->data;
+ Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
+ bArmature *arm = obact_eval->data;
bPoseChannel *pchan;
- for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (pchan = obact_eval->pose->chanbase.first; pchan; pchan = pchan->next) {
if (arm->layer & pchan->bone->layer) {
if (pchan->bone->flag & BONE_SELECTED) {
copy_v3_v3(vec, pchan->pose_head);
- mul_m4_v3(obact->obmat, vec);
+ mul_m4_v3(obact_eval->obmat, vec);
add_v3_v3(centroid, vec);
minmax_v3v3_v3(min, max, vec);
count++;
@@ -608,15 +686,15 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
}
}
else {
- CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
+ FOREACH_SELECTED_OBJECT_BEGIN(view_layer_eval, v3d, ob_eval)
{
- copy_v3_v3(vec, ob->obmat[3]);
+ copy_v3_v3(vec, ob_eval->obmat[3]);
/* special case for camera -- snap to bundles */
- if (ob->type == OB_CAMERA) {
+ if (ob_eval->type == OB_CAMERA) {
/* snap to bundles should happen only when bundles are visible */
if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) {
- bundle_midpoint(scene, ob, vec);
+ bundle_midpoint(depsgraph, scene, DEG_get_original_object(ob_eval), vec);
}
}
@@ -624,14 +702,14 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
minmax_v3v3_v3(min, max, vec);
count++;
}
- CTX_DATA_END;
+ FOREACH_SELECTED_OBJECT_END;
}
if (count == 0) {
return false;
}
- if (v3d->around == V3D_AROUND_CENTER_MEAN) {
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEAN) {
mul_v3_fl(centroid, 1.0f / (float)count);
copy_v3_v3(cursor, centroid);
}
@@ -645,13 +723,9 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
static int snap_curs_to_sel_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- float *curs;
-
- curs = ED_view3d_cursor3d_get(scene, v3d);
-
- if (snap_curs_to_sel_ex(C, curs)) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ if (snap_curs_to_sel_ex(C, scene->cursor.location)) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
return OPERATOR_FINISHED;
}
@@ -664,7 +738,7 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Snap Cursor to Selected";
- ot->description = "Snap cursor to center of selected item(s)";
+ ot->description = "Snap 3D cursor to the middle of the selected item(s)";
ot->idname = "VIEW3D_OT_snap_cursor_to_selected";
/* api callbacks */
@@ -672,16 +746,19 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
/* ********************************************** */
-/* this could be exported to be a generic function
- * see: calculateCenterActive */
-
+/** Calculates the center position of the active object in global space.
+ *
+ * Note: this could be exported to be a generic function.
+ * see: calculateCenterActive
+**/
static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3])
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
Object *obedit = CTX_data_edit_object(C);
if (obedit) {
@@ -692,21 +769,23 @@ static bool snap_calc_active_center(bContext *C, const bool select_only, float r
}
else {
Object *ob = CTX_data_active_object(C);
-
if (ob) {
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active(ob_eval);
if (pchan) {
if (!select_only || (pchan->bone->flag & BONE_SELECTED)) {
copy_v3_v3(r_center, pchan->pose_head);
- mul_m4_v3(ob->obmat, r_center);
+ mul_m4_v3(ob_eval->obmat, r_center);
return true;
}
}
}
else {
- if (!select_only || (ob->flag & SELECT)) {
- copy_v3_v3(r_center, ob->obmat[3]);
+
+ if (!select_only || (ob_eval->flag & SELECT)) {
+ copy_v3_v3(r_center, ob_eval->obmat[3]);
return true;
}
}
@@ -720,12 +799,11 @@ static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
- float *curs;
-
- curs = ED_view3d_cursor3d_get(scene, v3d);
- if (snap_calc_active_center(C, false, curs)) {
+ if (snap_calc_active_center(C, false, scene->cursor.location)) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+
return OPERATOR_FINISHED;
}
else {
@@ -737,7 +815,7 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Snap Cursor to Active";
- ot->description = "Snap cursor to active item";
+ ot->description = "Snap 3D cursor to the active item";
ot->idname = "VIEW3D_OT_snap_cursor_to_active";
/* api callbacks */
@@ -745,30 +823,29 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
}
/* **************************************************** */
-/*New Code - Snap Cursor to Center -*/
+
+/** Snaps the 3D cursor location to the origin. **/
static int snap_curs_to_center_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- float *curs;
- curs = ED_view3d_cursor3d_get(scene, v3d);
- zero_v3(curs);
+ zero_v3(scene->cursor.location);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
return OPERATOR_FINISHED;
}
void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Snap Cursor to Center";
- ot->description = "Snap cursor to the Center";
+ ot->name = "Snap Cursor to World Origin";
+ ot->description = "Snap 3D cursor to the world origin";
ot->idname = "VIEW3D_OT_snap_cursor_to_center";
/* api callbacks */
@@ -781,23 +858,22 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
/* **************************************************** */
-
-bool ED_view3d_minmax_verts(Object *obedit, float min[3], float max[3])
+/** Calculates the bounding box corners (min and max) for \a obedit. The returned values are in global space. **/
+bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
{
TransVertStore tvs = {NULL};
TransVert *tv;
float centroid[3], vec[3], bmat[3][3];
- int a;
- /* metaballs are an exception */
+ /* Metaballs are an exception. */
if (obedit->type == OB_MBALL) {
float ob_min[3], ob_max[3];
bool changed;
changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT);
if (changed) {
- minmax_v3v3_v3(min, max, ob_min);
- minmax_v3v3_v3(min, max, ob_max);
+ minmax_v3v3_v3(r_min, r_max, ob_min);
+ minmax_v3v3_v3(r_min, r_max, ob_max);
}
return changed;
}
@@ -811,12 +887,12 @@ bool ED_view3d_minmax_verts(Object *obedit, float min[3], float max[3])
copy_m3_m4(bmat, obedit->obmat);
tv = tvs.transverts;
- for (a = 0; a < tvs.transverts_tot; a++, tv++) {
+ for (int a = 0; a < tvs.transverts_tot; a++, tv++) {
copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc);
mul_m3_v3(bmat, vec);
add_v3_v3(vec, obedit->obmat[3]);
add_v3_v3(centroid, vec);
- minmax_v3v3_v3(min, max, vec);
+ minmax_v3v3_v3(r_min, r_max, vec);
}
ED_transverts_free(&tvs);
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index 76697a02270..707e0e7a394 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -28,231 +28,24 @@
* \ingroup spview3d
*/
-
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
-#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-
-#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_screen.h"
-
#include "WM_api.h"
#include "WM_types.h"
-#include "RNA_access.h"
-
#include "ED_screen.h"
-#include "ED_undo.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
#include "view3d_intern.h" /* own include */
-
-/* ******************* view3d space & buttons ************** */
-
-static void view3d_panel_operator_redo_buts(const bContext *C, Panel *pa, wmOperator *op)
-{
- uiTemplateOperatorPropertyButs(C, pa->layout, op, 'V', 0);
-}
-
-static void view3d_panel_operator_redo_header(const bContext *C, Panel *pa)
-{
- wmOperator *op = WM_operator_last_redo(C);
-
- if (op)
- BLI_strncpy(pa->drawname, RNA_struct_ui_name(op->type->srna), sizeof(pa->drawname));
- else
- BLI_strncpy(pa->drawname, IFACE_("Operator"), sizeof(pa->drawname));
-}
-
-static void view3d_panel_operator_redo_operator(const bContext *C, Panel *pa, wmOperator *op)
-{
- if (op->type->flag & OPTYPE_MACRO) {
- for (op = op->macro.first; op; op = op->next) {
- uiItemL(pa->layout, RNA_struct_ui_name(op->type->srna), ICON_NONE);
- view3d_panel_operator_redo_operator(C, pa, op);
- }
- }
- else {
- view3d_panel_operator_redo_buts(C, pa, op);
- }
-}
-
-/* TODO de-duplicate redo panel functions - campbell */
-static void view3d_panel_operator_redo(const bContext *C, Panel *pa)
-{
- wmOperator *op = WM_operator_last_redo(C);
- ARegion *ar;
- ARegion *ar1;
-
- if (op == NULL) {
- return;
- }
-
- /* keep in sync with logic in ED_undo_operator_repeat() */
- ar = CTX_wm_region(C);
- ar1 = BKE_area_find_region_active_win(CTX_wm_area(C));
- if (ar1)
- CTX_wm_region_set((bContext *)C, ar1);
-
- if (WM_operator_poll((bContext *)C, op->type)) {
- uiBlock *block = uiLayoutGetBlock(pa->layout);
-
- if (!WM_operator_check_ui_enabled(C, op->type->name))
- uiLayoutSetEnabled(pa->layout, false);
-
- /* note, blockfunc is a default but->func, use Handle func to allow button callbacks too */
- UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op);
-
- view3d_panel_operator_redo_operator(C, pa, op);
- }
-
- /* set region back */
- CTX_wm_region_set((bContext *)C, ar);
-}
-
-/* ******************* */
-
-typedef struct CustomTool {
- struct CustomTool *next, *prev;
- char opname[OP_MAX_TYPENAME];
- char context[OP_MAX_TYPENAME];
-} CustomTool;
-
-static void operator_call_cb(struct bContext *C, void *arg_listbase, void *arg2)
-{
- wmOperatorType *ot = arg2;
-
- if (ot) {
- CustomTool *ct = MEM_callocN(sizeof(CustomTool), "CustomTool");
-
- BLI_addtail(arg_listbase, ct);
- BLI_strncpy(ct->opname, ot->idname, OP_MAX_TYPENAME);
- BLI_strncpy(ct->context, CTX_data_mode_string(C), OP_MAX_TYPENAME);
- }
-
-}
-
-static void operator_search_cb(const struct bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
-{
- GHashIterator iter;
-
- for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
- wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
-
- if (BLI_strcasestr(ot->name, str)) {
- if (WM_operator_poll((bContext *)C, ot)) {
-
- if (false == UI_search_item_add(items, ot->name, ot, 0))
- break;
- }
- }
- }
-}
-
-
-/* ID Search browse menu, open */
-static uiBlock *tool_search_menu(bContext *C, ARegion *ar, void *arg_listbase)
-{
- static char search[OP_MAX_TYPENAME];
- wmEvent event;
- wmWindow *win = CTX_wm_window(C);
- uiBlock *block;
- uiBut *but;
-
- /* clear initial search string, then all items show */
- search[0] = 0;
-
- block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
- UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU);
- UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
-
- /* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
-
- but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, 150, 19, 0, 0, "");
- UI_but_func_search_set(but, NULL, operator_search_cb, arg_listbase, operator_call_cb, NULL);
-
- UI_block_bounds_set_normal(block, 6);
- UI_block_direction_set(block, UI_DIR_DOWN);
- UI_block_end(C, block);
-
- wm_event_init_from_window(win, &event);
- event.type = EVT_BUT_OPEN;
- event.val = KM_PRESS;
- event.customdata = but;
- event.customdatafree = false;
- wm_event_add(win, &event);
-
- return block;
-}
-
-
-static void view3d_panel_tool_shelf(const bContext *C, Panel *pa)
-{
- SpaceLink *sl = CTX_wm_space_data(C);
- SpaceType *st = NULL;
- uiLayout *col;
- const char *context = CTX_data_mode_string(C);
-
- if (sl)
- st = BKE_spacetype_from_id(sl->spacetype);
-
- if (st && st->toolshelf.first) {
- CustomTool *ct;
-
- for (ct = st->toolshelf.first; ct; ct = ct->next) {
- if (STREQLEN(context, ct->context, OP_MAX_TYPENAME)) {
- col = uiLayoutColumn(pa->layout, true);
- uiItemFullO(col, ct->opname, NULL, ICON_NONE, NULL, WM_OP_INVOKE_REGION_WIN, 0, NULL);
- }
- }
- }
- col = uiLayoutColumn(pa->layout, true);
- uiDefBlockBut(uiLayoutGetBlock(pa->layout), tool_search_menu, &st->toolshelf, "Add Tool", 0, 0, UI_UNIT_X, UI_UNIT_Y, "Add Tool in shelf, gets saved in files");
-}
-
-
-void view3d_toolshelf_register(ARegionType *art)
-{
- PanelType *pt;
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel tools");
- strcpy(pt->idname, "VIEW3D_PT_tool_shelf");
- strcpy(pt->label, N_("Tool Shelf"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = view3d_panel_tool_shelf;
- BLI_addtail(&art->paneltypes, pt);
-}
-
-void view3d_tool_props_register(ARegionType *art)
-{
- PanelType *pt;
-
- pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel last operator");
- strcpy(pt->idname, "VIEW3D_PT_last_operator");
- strcpy(pt->label, N_("Operator"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = view3d_panel_operator_redo_header;
- pt->draw = view3d_panel_operator_redo;
- BLI_addtail(&art->paneltypes, pt);
-}
-
/* ********** operator to open/close toolshelf region */
static int view3d_toolshelf_toggle_exec(bContext *C, wmOperator *UNUSED(op))
@@ -268,7 +61,7 @@ static int view3d_toolshelf_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void VIEW3D_OT_toolshelf(wmOperatorType *ot)
{
- ot->name = "Tool Shelf";
+ ot->name = "Toggle Toolbar";
ot->description = "Toggles tool shelf display";
ot->idname = "VIEW3D_OT_toolshelf";
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 68582644f34..d20dfa10923 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -36,6 +36,7 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
#include "MEM_guardedalloc.h"
@@ -46,14 +47,18 @@
#include "BKE_camera.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h" /* for ED_view3d_camera_lock_sync */
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_screen.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_matrix.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -61,6 +66,8 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "UI_resources.h"
+
#include "view3d_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -68,10 +75,33 @@
*
* \{ */
-float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d)
+void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float r_color[3])
{
- if (v3d && v3d->localvd) return v3d->cursor;
- else return scene->cursor;
+ switch (v3d->shading.background_type) {
+ case V3D_SHADING_BACKGROUND_WORLD:
+ copy_v3_v3(r_color, &scene->world->horr);
+ break;
+ case V3D_SHADING_BACKGROUND_VIEWPORT:
+ copy_v3_v3(r_color, v3d->shading.background_color);
+ break;
+ case V3D_SHADING_BACKGROUND_THEME:
+ default:
+ UI_GetThemeColor3fv(TH_HIGH_GRAD, r_color);
+ break;
+ }
+}
+
+void ED_view3d_cursor3d_calc_mat3(const Scene *scene, float mat[3][3])
+{
+ const View3DCursor *cursor = &scene->cursor;
+ quat_to_mat3(mat, cursor->rotation);
+}
+
+void ED_view3d_cursor3d_calc_mat4(const Scene *scene, float mat[4][4])
+{
+ const View3DCursor *cursor = &scene->cursor;
+ quat_to_mat4(mat, cursor->rotation);
+ copy_v3_v3(mat[3], cursor->location);
}
Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
@@ -97,6 +127,7 @@ void ED_view3d_dist_range_get(
* \note copies logic of #ED_view3d_viewplane_get(), keep in sync.
*/
bool ED_view3d_clip_range_get(
+ Depsgraph *depsgraph,
const View3D *v3d, const RegionView3D *rv3d,
float *r_clipsta, float *r_clipend,
const bool use_ortho_factor)
@@ -104,7 +135,7 @@ bool ED_view3d_clip_range_get(
CameraParams params;
BKE_camera_params_init(&params);
- BKE_camera_params_from_view3d(&params, v3d, rv3d);
+ BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
if (use_ortho_factor && params.is_ortho) {
const float fac = 2.0f / (params.clipend - params.clipsta);
@@ -119,13 +150,14 @@ bool ED_view3d_clip_range_get(
}
bool ED_view3d_viewplane_get(
+ Depsgraph *depsgraph,
const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
{
CameraParams params;
BKE_camera_params_init(&params);
- BKE_camera_params_from_view3d(&params, v3d, rv3d);
+ BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
if (r_viewplane) *r_viewplane = params.viewplane;
@@ -156,7 +188,7 @@ void view3d_operator_needs_opengl(const bContext *C)
view3d_region_operator_needs_opengl(win, ar);
}
-void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
+void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *ar)
{
/* for debugging purpose, context should always be OK */
if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) {
@@ -165,11 +197,9 @@ void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
else {
RegionView3D *rv3d = ar->regiondata;
- wmSubWindowSet(win, ar->swinid);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(rv3d->winmat);
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(rv3d->viewmat);
+ wmViewport(&ar->winrct); // TODO: bad
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
}
}
@@ -231,6 +261,7 @@ bool ED_view3d_context_activate(bContext *C)
/** \name View Clipping Utilities
*
* \{ */
+
void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip)
{
int val;
@@ -245,40 +276,35 @@ void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb,
}
}
-void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect)
+void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect)
{
- float modelview[4][4];
- double xs, ys, p[3];
- int val, flip_sign, a;
-
- /* near zero floating point values can give issues with gluUnProject
- * in side view on some implementations */
- if (fabs(mats->modelview[0]) < 1e-6) mats->modelview[0] = 0.0;
- if (fabs(mats->modelview[5]) < 1e-6) mats->modelview[5] = 0.0;
-
- /* Set up viewport so that gluUnProject will give correct values */
- mats->viewport[0] = 0;
- mats->viewport[1] = 0;
+ /* init in case unproject fails */
+ memset(bb->vec, 0, sizeof(bb->vec));
/* four clipping planes and bounding volume */
/* first do the bounding volume */
- for (val = 0; val < 4; val++) {
- xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax;
- ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax;
+ for (int val = 0; val < 4; val++) {
+ float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax;
+ float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax;
+
+ ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]);
+ ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]);
+ }
- gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
- copy_v3fl_v3db(bb->vec[val], p);
+ /* optionally transform to object space */
+ if (ob) {
+ float imat[4][4];
+ invert_m4_m4(imat, ob->obmat);
- gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
- copy_v3fl_v3db(bb->vec[4 + val], p);
+ for (int val = 0; val < 8; val++) {
+ mul_m4_v3(imat, bb->vec[val]);
+ }
}
/* verify if we have negative scale. doing the transform before cross
* product flips the sign of the vector compared to doing cross product
* before transform then, so we correct for that. */
- for (a = 0; a < 16; a++)
- ((float *)modelview)[a] = mats->modelview[a];
- flip_sign = is_negative_m4(modelview);
+ int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false;
ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign);
}
@@ -379,14 +405,15 @@ void ED_view3d_lock_clear(View3D *v3d)
* sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera,
* otherwise switching out of camera view may jump to a different part of the scene.
*/
-void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp)
+void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, const char persp)
{
BLI_assert(rv3d->persp == RV3D_CAMOB);
BLI_assert(persp != RV3D_CAMOB);
if (v3d->camera) {
- rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
- ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
+ Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ rv3d->dist = ED_view3d_offset_distance(ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
+ ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
}
if (!ED_view3d_camera_lock_check(v3d, rv3d)) {
@@ -399,7 +426,7 @@ void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const c
*
* shared with NDOF.
*/
-bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar)
+bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
@@ -413,7 +440,7 @@ bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar)
if (rv3d->persp == RV3D_CAMOB) {
/* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */
char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp;
- ED_view3d_persp_switch_from_camera(v3d, rv3d, persp);
+ ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, persp);
}
else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
rv3d->persp = RV3D_PERSP;
@@ -447,20 +474,21 @@ bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d)
* Apply the camera object transformation to the view-port.
* (needed so we can use regular view-port manipulation operators, that sync back to the camera).
*/
-void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
+void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, const bool calc_dist)
{
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+ Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
if (calc_dist) {
/* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */
- rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
+ rv3d->dist = ED_view3d_offset_distance(ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK);
}
- ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
+ ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
}
}
-void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d)
+void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
{
- ED_view3d_camera_lock_init_ex(v3d, rv3d, true);
+ ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, true);
}
/**
@@ -468,7 +496,7 @@ void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d)
*
* \return true if the camera is moved.
*/
-bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
+bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d)
{
if (ED_view3d_camera_lock_check(v3d, rv3d)) {
ObjectTfmProtectedChannels obtfm;
@@ -485,15 +513,17 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
while (root_parent->parent) {
root_parent = root_parent->parent;
}
+ Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ Object *root_parent_eval = DEG_get_evaluated_object(depsgraph, root_parent);
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
- normalize_m4_m4(tmat, v3d->camera->obmat);
+ normalize_m4_m4(tmat, ob_camera_eval->obmat);
invert_m4_m4(imat, tmat);
mul_m4_m4m4(diff_mat, view_mat, imat);
- mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat);
+ mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->obmat);
BKE_object_tfm_protected_backup(root_parent, &obtfm);
BKE_object_apply_mat4(root_parent, parent_mat, true, false);
@@ -501,7 +531,7 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
ob_update = v3d->camera;
while (ob_update) {
- DAG_id_tag_update(&ob_update->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob_update->id, OB_RECALC_OB);
WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update);
ob_update = ob_update->parent;
}
@@ -510,10 +540,10 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
/* always maintain the same scale */
const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
- ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+ ED_view3d_to_object(depsgraph, v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
- DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
+ DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera);
}
@@ -594,6 +624,7 @@ bool ED_view3d_camera_lock_autokey(
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Box View Support
*
@@ -878,22 +909,17 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
* \param fallback_depth_pt: Use this points depth when no depth can be found.
*/
bool ED_view3d_autodist(
- Main *bmain, Scene *scene, ARegion *ar, View3D *v3d,
+ Depsgraph *depsgraph, ARegion *ar, View3D *v3d,
const int mval[2], float mouse_worldloc[3],
const bool alphaoverride, const float fallback_depth_pt[3])
{
- bglMats mats; /* ZBuffer depth vars */
float depth_close;
- double cent[2], p[3];
int margin_arr[] = {0, 2, 4};
int i;
bool depth_ok = false;
/* Get Z Depths, needed for perspective, nice for ortho */
- ED_view3d_draw_depth(bmain, scene, ar, v3d, alphaoverride);
-
- /* call after in case settings have been modified since last drawing, see: T47089 */
- bgl_get_mats(&mats);
+ ED_view3d_draw_depth(depsgraph, ar, v3d, alphaoverride);
/* Attempt with low margin's first */
i = 0;
@@ -903,15 +929,10 @@ bool ED_view3d_autodist(
} while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr)));
if (depth_ok) {
- cent[0] = (double)mval[0] + 0.5;
- cent[1] = (double)mval[1] + 0.5;
+ float centx = (float)mval[0] + 0.5f;
+ float centy = (float)mval[1] + 0.5f;
- if (gluUnProject(cent[0], cent[1], depth_close,
- mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
- {
- mouse_worldloc[0] = (float)p[0];
- mouse_worldloc[1] = (float)p[1];
- mouse_worldloc[2] = (float)p[2];
+ if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) {
return true;
}
}
@@ -925,27 +946,28 @@ bool ED_view3d_autodist(
}
}
-void ED_view3d_autodist_init(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, int mode)
+void ED_view3d_autodist_init(Depsgraph *depsgraph,
+ ARegion *ar, View3D *v3d, int mode)
{
/* Get Z Depths, needed for perspective, nice for ortho */
switch (mode) {
case 0:
- ED_view3d_draw_depth(bmain, scene, ar, v3d, true);
+ ED_view3d_draw_depth(depsgraph, ar, v3d, true);
break;
case 1:
- ED_view3d_draw_depth_gpencil(scene, ar, v3d);
+ {
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ED_view3d_draw_depth_gpencil(depsgraph, scene, ar, v3d);
break;
+ }
}
}
/* no 4x4 sampling, run #ED_view3d_autodist_init first */
-bool ED_view3d_autodist_simple(
- ARegion *ar, const int mval[2], float mouse_worldloc[3],
- int margin, float *force_depth)
+bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3],
+ int margin, float *force_depth)
{
- bglMats mats; /* ZBuffer depth vars, could cache? */
float depth;
- double cent[2], p[3];
/* Get Z Depths, needed for perspective, nice for ortho */
if (force_depth)
@@ -956,21 +978,9 @@ bool ED_view3d_autodist_simple(
if (depth == FLT_MAX)
return false;
- cent[0] = (double)mval[0] + 0.5;
- cent[1] = (double)mval[1] + 0.5;
-
- bgl_get_mats(&mats);
-
- if (!gluUnProject(cent[0], cent[1], depth,
- mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
- {
- return false;
- }
-
- mouse_worldloc[0] = (float)p[0];
- mouse_worldloc[1] = (float)p[1];
- mouse_worldloc[2] = (float)p[2];
- return true;
+ float centx = (float)mval[0] + 0.5f;
+ float centy = (float)mval[1] + 0.5f;
+ return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc);
}
bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth)
@@ -1066,6 +1076,7 @@ float ED_view3d_radius_to_dist_ortho(const float lens, const float radius)
*/
float ED_view3d_radius_to_dist(
const View3D *v3d, const ARegion *ar,
+ const struct Depsgraph *depsgraph,
const char persp, const bool use_aspect,
const float radius)
{
@@ -1086,7 +1097,8 @@ float ED_view3d_radius_to_dist(
BKE_camera_params_init(&params);
params.clipsta = v3d->near;
params.clipend = v3d->far;
- BKE_camera_params_from_object(&params, v3d->camera);
+ Object *camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ BKE_camera_params_from_object(&params, camera_eval);
lens = params.lens;
sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
@@ -1276,7 +1288,7 @@ bool ED_view3d_lock(RegionView3D *rv3d)
* \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
* \param dist The view distance from ofs, normally from RegionView3D.dist.
*/
-void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist)
+void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], float *dist)
{
float nmat[3][3];
@@ -1321,13 +1333,14 @@ void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], c
/**
* Set the RegionView3D members from an objects transformation and optionally lens.
+ * \param depsgraph The depsgraph to get the evaluated object for the lens calculation.
* \param ob The object to set the view to.
* \param ofs The view offset to be set, normally from RegionView3D.ofs.
* \param quat The view rotation to be set, quaternion normally from RegionView3D.viewquat.
* \param dist The view distance from ofs to be set, normally from RegionView3D.dist.
* \param lens The view lens angle set for cameras and lamps, normally from View3D.lens.
*/
-void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
+void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float *dist, float *lens)
{
ED_view3d_from_m4(ob->obmat, ofs, quat, dist);
@@ -1342,16 +1355,19 @@ void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist,
/**
* Set the object transformation from RegionView3D members.
+ * \param depsgraph The depsgraph to get the evaluated object parent for the transformation calculation.
* \param ob The object which has the transformation assigned.
* \param ofs The view offset, normally from RegionView3D.ofs.
* \param quat The view rotation, quaternion normally from RegionView3D.viewquat.
* \param dist The view distance from ofs, normally from RegionView3D.dist.
*/
-void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist)
+void ED_view3d_to_object(const Depsgraph *depsgraph, Object *ob, const float ofs[3], const float quat[4], const float dist)
{
float mat[4][4];
ED_view3d_to_m4(mat, ofs, quat, dist);
- BKE_object_apply_mat4(ob, mat, true, true);
+
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ BKE_object_apply_mat4_ex(ob, mat, ob_eval->parent, ob_eval->parentinv, true);
}
/** \} */
@@ -1377,7 +1393,7 @@ float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2])
}
bool ED_view3d_depth_read_cached_normal(
- const ViewContext *vc, const bglMats *mats, const int mval[2],
+ const ViewContext *vc, const int mval[2],
float r_normal[3])
{
/* Note: we could support passing in a radius.
@@ -1396,7 +1412,7 @@ bool ED_view3d_depth_read_cached_normal(
const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs);
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
- if (ED_view3d_depth_unproject(ar, mats, mval_ofs, depth, coords[i])) {
+ if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) {
depths_valid[i] = true;
}
}
@@ -1438,21 +1454,13 @@ bool ED_view3d_depth_read_cached_normal(
}
bool ED_view3d_depth_unproject(
- const ARegion *ar, const bglMats *mats,
+ const ARegion *ar,
const int mval[2], const double depth,
float r_location_world[3])
{
- double p[3];
- if (gluUnProject(
- (double)ar->winrct.xmin + mval[0] + 0.5,
- (double)ar->winrct.ymin + mval[1] + 0.5,
- depth, mats->modelview, mats->projection, (const GLint *)mats->viewport,
- &p[0], &p[1], &p[2]))
- {
- copy_v3fl_v3db(r_location_world, p);
- return true;
- }
- return false;
+ float centx = (float)mval[0] + 0.5f;
+ float centy = (float)mval[1] + 0.5f;
+ return ED_view3d_unproject(ar, centx, centy, depth, r_location_world);
}
void ED_view3d_depth_tag_update(RegionView3D *rv3d)
@@ -1462,46 +1470,3 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d)
}
/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Background Image Utilities
- * \{ */
-
-BGpic *ED_view3d_background_image_new(View3D *v3d)
-{
- BGpic *bgpic = MEM_callocN(sizeof(BGpic), "Background Image");
-
- bgpic->rotation = 0.0f;
- bgpic->size = 5.0f;
- bgpic->blend = 0.5f;
- bgpic->iuser.fie_ima = 2;
- bgpic->iuser.ok = 1;
- bgpic->view = 0; /* 0 for all */
- bgpic->flag |= V3D_BGPIC_EXPANDED;
-
- BLI_addtail(&v3d->bgpicbase, bgpic);
-
- return bgpic;
-}
-
-void ED_view3d_background_image_remove(View3D *v3d, BGpic *bgpic)
-{
- BLI_remlink(&v3d->bgpicbase, bgpic);
-
- MEM_freeN(bgpic);
-}
-
-void ED_view3d_background_image_clear(View3D *v3d)
-{
- BGpic *bgpic = v3d->bgpicbase.first;
-
- while (bgpic) {
- BGpic *next_bgpic = bgpic->next;
-
- ED_view3d_background_image_remove(v3d, bgpic);
-
- bgpic = next_bgpic;
- }
-}
-
-/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 92f226f72de..98ae57e9c42 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -41,32 +41,30 @@
#include "BKE_action.h"
#include "BKE_camera.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BIF_gl.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "UI_resources.h"
+#include "GPU_glew.h"
#include "GPU_select.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_object.h"
#include "ED_screen.h"
-#ifdef WITH_GAMEENGINE
-# include "BLI_listbase.h"
-# include "BLI_callbacks.h"
-
-# include "GPU_draw.h"
-
-# include "BL_System.h"
-#endif
+#include "DRW_engine.h"
#include "view3d_intern.h" /* own include */
@@ -125,7 +123,7 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms
/* the arguments are the desired situation */
void ED_view3d_smooth_view_ex(
/* avoid passing in the context */
- wmWindowManager *wm, wmWindow *win, ScrArea *sa,
+ const Depsgraph *depsgraph, wmWindowManager *wm, wmWindow *win, ScrArea *sa,
View3D *v3d, ARegion *ar, const int smooth_viewtx,
const V3D_SmoothParams *sview)
{
@@ -156,7 +154,7 @@ void ED_view3d_smooth_view_ex(
* we allow camera option locking to initialize the view settings from the camera.
*/
if (sview->camera == NULL && sview->camera_old == NULL) {
- ED_view3d_camera_lock_init(v3d, rv3d);
+ ED_view3d_camera_lock_init(depsgraph, v3d, rv3d);
}
/* store the options we want to end with */
@@ -181,13 +179,14 @@ void ED_view3d_smooth_view_ex(
}
if (sview->camera) {
- sms.dst.dist = ED_view3d_offset_distance(sview->camera->obmat, sview->ofs, VIEW3D_DIST_FALLBACK);
- ED_view3d_from_object(sview->camera, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens);
+ Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera);
+ sms.dst.dist = ED_view3d_offset_distance(ob_camera_eval->obmat, sview->ofs, VIEW3D_DIST_FALLBACK);
+ ED_view3d_from_object(ob_camera_eval, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens);
sms.to_camera = true; /* restore view3d values in end */
}
/* skip smooth viewing for render engine draw */
- if (smooth_viewtx && v3d->drawtype != OB_RENDER) {
+ if (smooth_viewtx && v3d->shading.type != OB_RENDER) {
bool changed = false; /* zero means no difference */
if (sview->camera_old != sview->camera)
@@ -206,9 +205,10 @@ void ED_view3d_smooth_view_ex(
if (changed) {
/* original values */
if (sview->camera_old) {
- sms.src.dist = ED_view3d_offset_distance(sview->camera_old->obmat, rv3d->ofs, 0.0f);
+ Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old);
+ sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, rv3d->ofs, 0.0f);
/* this */
- ED_view3d_from_object(sview->camera_old, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
+ ED_view3d_from_object(ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
}
/* grid draw as floor */
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
@@ -230,9 +230,10 @@ void ED_view3d_smooth_view_ex(
/* ensure it shows correct */
if (sms.to_camera) {
/* use ortho if we move from an ortho view to an ortho camera */
+ Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera);
rv3d->persp = (((rv3d->is_persp == false) &&
- (sview->camera->type == OB_CAMERA) &&
- (((Camera *)sview->camera->data)->type == CAM_ORTHO)) ?
+ (ob_camera_eval->type == OB_CAMERA) &&
+ (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ?
RV3D_ORTHO : RV3D_PERSP);
}
@@ -265,7 +266,7 @@ void ED_view3d_smooth_view_ex(
rv3d->dist = sms.dst.dist;
v3d->lens = sms.dst.lens;
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
}
if (rv3d->viewlock & RV3D_BOXVIEW) {
@@ -281,11 +282,13 @@ void ED_view3d_smooth_view(
View3D *v3d, ARegion *ar, const int smooth_viewtx,
const struct V3D_SmoothParams *sview)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
ED_view3d_smooth_view_ex(
+ depsgraph,
wm, win, sa,
v3d, ar, smooth_viewtx,
sview);
@@ -294,6 +297,7 @@ void ED_view3d_smooth_view(
/* only meant for timer usage */
static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool sync_boxview)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
RegionView3D *rv3d = ar->regiondata;
struct SmoothView3DStore *sms = rv3d->sms;
float step, step_inv;
@@ -314,7 +318,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool
else {
view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d);
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
}
@@ -347,7 +351,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool
rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv;
v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv;
- ED_view3d_camera_lock_sync(v3d, rv3d);
+ ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
}
@@ -405,8 +409,9 @@ void ED_view3d_smooth_view_force_finish(
/* force update of view matrix so tools that run immediately after
* can use them without redrawing first */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL, NULL);
+ ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL);
}
}
@@ -433,6 +438,7 @@ void VIEW3D_OT_smoothview(wmOperatorType *ot)
static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op))
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
View3D *v3d;
ARegion *ar;
RegionView3D *rv3d;
@@ -446,11 +452,11 @@ static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op))
BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
- ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
+ ED_view3d_to_object(depsgraph, v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag);
- DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
+ DEG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
rv3d->persp = RV3D_CAMOB;
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, v3d->camera);
@@ -503,29 +509,30 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
* meant to take into account vertex/bone selection for eg. */
static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
Object *camera_ob = v3d ? v3d->camera : scene->camera;
+ Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
float r_co[3]; /* the new location to apply */
float r_scale; /* only for ortho cameras */
- if (camera_ob == NULL) {
+ if (camera_ob_eval == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active camera");
return OPERATOR_CANCELLED;
}
/* this function does all the important stuff */
- if (BKE_camera_view_frame_fit_to_scene(bmain, scene, v3d, camera_ob, r_co, &r_scale)) {
+ if (BKE_camera_view_frame_fit_to_scene(depsgraph, scene, camera_ob_eval, r_co, &r_scale)) {
ObjectTfmProtectedChannels obtfm;
float obmat_new[4][4];
- if ((camera_ob->type == OB_CAMERA) && (((Camera *)camera_ob->data)->type == CAM_ORTHO)) {
+ if ((camera_ob_eval->type == OB_CAMERA) && (((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) {
((Camera *)camera_ob->data)->ortho_scale = r_scale;
}
- copy_m4_m4(obmat_new, camera_ob->obmat);
+ copy_m4_m4(obmat_new, camera_ob_eval->obmat);
copy_v3_v3(obmat_new[3], r_co);
/* only touch location */
@@ -534,7 +541,7 @@ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op)
BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D);
/* notifiers */
- DAG_id_tag_update(&camera_ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&camera_ob->id, OB_RECALC_OB);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, camera_ob);
return OPERATOR_FINISHED;
}
@@ -689,14 +696,14 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
/**
* \param rect optional for picking (can be NULL).
*/
-void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect)
+void view3d_winmatrix_set(Depsgraph *depsgraph, ARegion *ar, const View3D *v3d, const rcti *rect)
{
RegionView3D *rv3d = ar->regiondata;
rctf viewplane;
float clipsta, clipend;
bool is_ortho;
- is_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
+ is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
rv3d->is_persp = !is_ortho;
#if 0
@@ -715,14 +722,14 @@ void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect)
}
if (is_ortho) {
- wmOrtho(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+ GPU_matrix_ortho_set(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
}
else {
- wmFrustum(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+ GPU_matrix_frustum_set(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
}
/* update matrix in 3d view region */
- glGetFloatv(GL_PROJECTION_MATRIX, (float *)rv3d->winmat);
+ GPU_matrix_projection_get(rv3d->winmat);
}
static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
@@ -741,6 +748,7 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
/**
* Sets #RegionView3D.viewmat
*
+ * \param depsgraph: Depsgraph.
* \param scene: Scene for camera and cursor location.
* \param v3d: View 3D space data.
* \param rv3d: 3D region which stores the final matrices.
@@ -750,13 +758,14 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
* \note don't set windows active in here, is used by renderwin too.
*/
void view3d_viewmatrix_set(
- Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2])
{
if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */
if (v3d->camera) {
- BKE_object_where_is_calc(scene, v3d->camera);
- obmat_to_viewmat(rv3d, v3d->camera);
+ Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ BKE_object_where_is_calc(depsgraph, scene, ob_camera_eval);
+ obmat_to_viewmat(rv3d, ob_camera_eval);
}
else {
quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
@@ -774,15 +783,15 @@ void view3d_viewmatrix_set(
quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist;
if (v3d->ob_centre) {
- Object *ob = v3d->ob_centre;
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, v3d->ob_centre);
float vec[3];
- copy_v3_v3(vec, ob->obmat[3]);
- if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone);
+ copy_v3_v3(vec, ob_eval->obmat[3]);
+ if (ob_eval->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob_eval->pose, v3d->ob_centre_bone);
if (pchan) {
copy_v3_v3(vec, pchan->pose_mat[3]);
- mul_m4_v3(ob->obmat, vec);
+ mul_m4_v3(ob_eval->obmat, vec);
}
}
translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
@@ -790,7 +799,7 @@ void view3d_viewmatrix_set(
}
else if (v3d->ob_centre_cursor) {
float vec[3];
- copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d));
+ copy_v3_v3(vec, scene->cursor.location);
translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
use_lock_ofs = true;
}
@@ -849,6 +858,71 @@ void view3d_opengl_select_cache_end(void)
GPU_select_cache_end();
}
+struct DrawSelectLoopUserData {
+ uint pass;
+ uint hits;
+ uint *buffer;
+ uint buffer_len;
+ const rcti *rect;
+ char gpu_select_mode;
+};
+
+static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
+{
+ bool continue_pass = false;
+ struct DrawSelectLoopUserData *data = user_data;
+ if (stage == DRW_SELECT_PASS_PRE) {
+ GPU_select_begin(data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits);
+ /* always run POST after PRE. */
+ continue_pass = true;
+ }
+ else if (stage == DRW_SELECT_PASS_POST) {
+ int hits = GPU_select_end();
+ if (data->pass == 0) {
+ /* quirk of GPU_select_end, only take hits value from first call. */
+ data->hits = hits;
+ }
+ if (data->gpu_select_mode == GPU_SELECT_NEAREST_FIRST_PASS) {
+ data->gpu_select_mode = GPU_SELECT_NEAREST_SECOND_PASS;
+ continue_pass = (hits > 0);
+ }
+ data->pass += 1;
+ }
+ else {
+ BLI_assert(0);
+ }
+ return continue_pass;
+
+}
+
+eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const Scene *scene, const Object *obact)
+{
+ if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ if (obact && (obact->mode & OB_MODE_WEIGHT_PAINT) &&
+ BKE_object_pose_armature_get((Object *)obact))
+ {
+ return VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK;
+ }
+ return VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK;
+ }
+ return VIEW3D_SELECT_FILTER_NOP;
+}
+
+/** Implement #VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK. */
+static bool drw_select_filter_object_mode_lock(Object *ob, void *user_data)
+{
+ const Object *obact = user_data;
+ return BKE_object_is_mode_compat(ob, obact->mode);
+}
+
+/** Implement #VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK for special case when
+ * we want to select pose bones (this doesn't switch modes). */
+static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void *user_data)
+{
+ const Object *ob_pose = user_data;
+ return (DEG_get_original_object(ob) == ob_pose);
+}
+
/**
* \warning be sure to account for a negative return value
* This is an error, "Too many objects in select buffer"
@@ -858,25 +932,27 @@ void view3d_opengl_select_cache_end(void)
*/
int view3d_opengl_select(
ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input,
- eV3DSelectMode select_mode)
+ eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter)
{
struct bThemeState theme_state;
+ Depsgraph *depsgraph = vc->depsgraph;
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
ARegion *ar = vc->ar;
rcti rect;
- int hits;
- const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
+ int hits = 0;
+ const bool use_obedit_skip = (OBEDIT_FROM_VIEW_LAYER(vc->view_layer) != NULL) && (vc->obedit == NULL);
const bool is_pick_select = (U.gpu_select_pick_deph != 0);
const bool do_passes = (
(is_pick_select == false) &&
(select_mode == VIEW3D_SELECT_PICK_NEAREST) &&
GPU_select_query_check_active());
const bool use_nearest = (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST);
+ bool draw_surface = true;
char gpu_select_mode;
- /* case not a border select */
+ /* case not a box select */
if (input->xmin == input->xmax) {
/* seems to be default value for bones only now */
BLI_rcti_init_pt_radius(&rect, (const int[2]){input->xmin, input->ymin}, 12);
@@ -905,6 +981,35 @@ int view3d_opengl_select(
}
}
+ struct {
+ DRW_ObjectFilterFn fn;
+ void *user_data;
+ } object_filter = {NULL, NULL};
+ switch (select_filter) {
+ case VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK:
+ {
+ Object *obact = OBACT(vc->view_layer);
+ if (obact && obact->mode != OB_MODE_OBJECT) {
+ object_filter.fn = drw_select_filter_object_mode_lock;
+ object_filter.user_data = obact;
+ }
+ break;
+ }
+ case VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK:
+ {
+ Object *obact = OBACT(vc->view_layer);
+ BLI_assert(obact && (obact->mode & OB_MODE_WEIGHT_PAINT));
+ Object *ob_pose = BKE_object_pose_armature_get(obact);
+
+ object_filter.fn = drw_select_filter_object_mode_lock_for_weight_paint;
+ object_filter.user_data = ob_pose;
+ break;
+ }
+ case VIEW3D_SELECT_FILTER_NOP:
+ break;
+
+ }
+
/* Tools may request depth outside of regular drawing code. */
UI_Theme_Store(&theme_state);
UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
@@ -918,47 +1023,81 @@ int view3d_opengl_select(
goto finally;
}
+ /* All of the queries need to be perform on the drawing context. */
+ DRW_opengl_context_enable();
+
G.f |= G_PICKSEL;
/* Important we use the 'viewmat' and don't re-calculate since
* the object & bone view locking takes 'rect' into account, see: T51629. */
- ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, &rect);
+ ED_view3d_draw_setup_view(vc->win, depsgraph, scene, ar, v3d, vc->rv3d->viewmat, NULL, &rect);
- if (v3d->drawtype > OB_WIRE) {
- v3d->zbuf = true;
- glEnable(GL_DEPTH_TEST);
+ if (v3d->shading.type > OB_WIRE) {
+ GPU_depth_test(true);
}
- if (vc->rv3d->rflag & RV3D_CLIPPING)
+ if (vc->rv3d->rflag & RV3D_CLIPPING) {
ED_view3d_clipping_set(vc->rv3d);
+ }
- GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
-
- ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest);
-
- hits = GPU_select_end();
-
- /* second pass, to get the closest object to camera */
- if (do_passes && (hits > 0)) {
- GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
-
- ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest);
+ /* If in xray mode, we select the wires in priority. */
+ if ((v3d->shading.flag & V3D_XRAY_FLAG(v3d)) && use_nearest) {
+ /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop
+ * because the OpenGL context created & destroyed inside this function. */
+ struct DrawSelectLoopUserData drw_select_loop_user_data = {
+ .pass = 0,
+ .hits = 0,
+ .buffer = buffer,
+ .buffer_len = bufsize,
+ .rect = &rect,
+ .gpu_select_mode = gpu_select_mode,
+ };
+ draw_surface = false;
+ DRW_draw_select_loop(
+ depsgraph, ar, v3d,
+ use_obedit_skip, draw_surface, use_nearest, &rect,
+ drw_select_loop_pass, &drw_select_loop_user_data,
+ object_filter.fn, object_filter.user_data);
+ hits = drw_select_loop_user_data.hits;
+ /* FIX: This cleanup the state before doing another selection pass.
+ * (see T56695) */
+ GPU_select_cache_end();
+ }
- GPU_select_end();
+ if (hits == 0) {
+ /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop
+ * because the OpenGL context created & destroyed inside this function. */
+ struct DrawSelectLoopUserData drw_select_loop_user_data = {
+ .pass = 0,
+ .hits = 0,
+ .buffer = buffer,
+ .buffer_len = bufsize,
+ .rect = &rect,
+ .gpu_select_mode = gpu_select_mode,
+ };
+ draw_surface = true;
+ DRW_draw_select_loop(
+ depsgraph, ar, v3d,
+ use_obedit_skip, draw_surface, use_nearest, &rect,
+ drw_select_loop_pass, &drw_select_loop_user_data,
+ object_filter.fn, object_filter.user_data);
+ hits = drw_select_loop_user_data.hits;
}
G.f &= ~G_PICKSEL;
- ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL);
+ ED_view3d_draw_setup_view(vc->win, depsgraph, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL);
- if (v3d->drawtype > OB_WIRE) {
- v3d->zbuf = 0;
- glDisable(GL_DEPTH_TEST);
+ if (v3d->shading.type > OB_WIRE) {
+ GPU_depth_test(false);
}
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_disable();
+ DRW_opengl_context_disable();
+
finally:
+
if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */
UI_Theme_Restore(&theme_state);
@@ -974,11 +1113,10 @@ finally:
static unsigned int free_localbit(Main *bmain)
{
- unsigned int lay;
ScrArea *sa;
bScreen *sc;
- lay = 0;
+ unsigned short local_view_bits = 0;
/* sometimes we loose a localview: when an area is closed */
/* check all areas: which localviews are in use? */
@@ -988,72 +1126,38 @@ static unsigned int free_localbit(Main *bmain)
for (; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *) sl;
- lay |= v3d->lay;
+ if (v3d->localvd) {
+ local_view_bits |= v3d->local_view_uuid;
+ }
}
}
}
}
- if ((lay & 0x01000000) == 0) return 0x01000000;
- if ((lay & 0x02000000) == 0) return 0x02000000;
- if ((lay & 0x04000000) == 0) return 0x04000000;
- if ((lay & 0x08000000) == 0) return 0x08000000;
- if ((lay & 0x10000000) == 0) return 0x10000000;
- if ((lay & 0x20000000) == 0) return 0x20000000;
- if ((lay & 0x40000000) == 0) return 0x40000000;
- if ((lay & 0x80000000) == 0) return 0x80000000;
-
- return 0;
-}
-
-int ED_view3d_scene_layer_set(int lay, const bool *values, int *active)
-{
- int i, tot = 0;
-
- /* ensure we always have some layer selected */
- for (i = 0; i < 20; i++)
- if (values[i])
- tot++;
-
- if (tot == 0)
- return lay;
-
- for (i = 0; i < 20; i++) {
-
- if (active) {
- /* if this value has just been switched on, make that layer active */
- if (values[i] && (lay & (1 << i)) == 0) {
- *active = (1 << i);
- }
- }
-
- if (values[i]) lay |= (1 << i);
- else lay &= ~(1 << i);
- }
-
- /* ensure always an active layer */
- if (active && (lay & *active) == 0) {
- for (i = 0; i < 20; i++) {
- if (lay & (1 << i)) {
- *active = 1 << i;
- break;
- }
+ for (int i = 0; i < 16; i++) {
+ if ((local_view_bits & (1 << i)) == 0) {
+ return (1 << i);
}
}
- return lay;
+ return 0;
}
static bool view3d_localview_init(
- wmWindowManager *wm, wmWindow *win,
- Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx,
+ const Depsgraph *depsgraph,
+ wmWindowManager *wm,
+ wmWindow *win,
+ Main *bmain,
+ ViewLayer *view_layer,
+ ScrArea *sa,
+ const int smooth_viewtx,
ReportList *reports)
{
View3D *v3d = sa->spacedata.first;
Base *base;
float min[3], max[3], box[3], mid[3];
float size = 0.0f;
- unsigned int locallay;
+ unsigned int local_view_bit;
bool ok = false;
if (v3d->localvd) {
@@ -1062,27 +1166,31 @@ static bool view3d_localview_init(
INIT_MINMAX(min, max);
- locallay = free_localbit(bmain);
+ local_view_bit = free_localbit(bmain);
- if (locallay == 0) {
- BKE_report(reports, RPT_ERROR, "No more than 8 local views");
+ if (local_view_bit == 0) {
+ /* TODO(dfelinto): We can kick one of the other 3D views out of local view
+ specially if it is not being used. */
+ BKE_report(reports, RPT_ERROR, "No more than 16 local views");
ok = false;
}
else {
- if (scene->obedit) {
- BKE_object_minmax(scene->obedit, min, max, false);
-
- ok = true;
-
- BASACT->lay |= locallay;
- scene->obedit->lay = BASACT->lay;
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ if (obedit) {
+ FOREACH_BASE_IN_EDIT_MODE_BEGIN(view_layer, v3d, base_iter) {
+ BKE_object_minmax(base_iter->object, min, max, false);
+ base_iter->local_view_bits |= local_view_bit;
+ ok = true;
+ } FOREACH_BASE_IN_EDIT_MODE_END;
}
else {
- for (base = FIRSTBASE; base; base = base->next) {
+ for (base = FIRSTBASE(view_layer); base; base = base->next) {
if (TESTBASE(v3d, base)) {
BKE_object_minmax(base->object, min, max, false);
- base->lay |= locallay;
- base->object->lay = base->lay;
+ base->local_view_bits |= local_view_bit;
+ /* Technically we should leave for Depsgraph to handle this.
+ But it is harmless to do it here, and it seems to be necessary. */
+ base->object->base_local_view_bits = base->local_view_bits;
ok = true;
}
}
@@ -1101,14 +1209,12 @@ static bool view3d_localview_init(
mid_v3_v3v3(mid, min, max);
- copy_v3_v3(v3d->cursor, mid);
-
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = ar->regiondata;
bool ok_dist = true;
- /* new view values */
+ /* New view values. */
Object *camera_old = NULL;
float dist_new, ofs_new[3];
@@ -1129,14 +1235,16 @@ static bool view3d_localview_init(
}
if (ok_dist) {
- dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
+ dist_new = ED_view3d_radius_to_dist(v3d, ar, depsgraph, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
+
if (rv3d->persp == RV3D_PERSP) {
- /* don't zoom closer than the near clipping plane */
+ /* Don't zoom closer than the near clipping plane. */
dist_new = max_ff(dist_new, v3d->near * 1.5f);
}
}
ED_view3d_smooth_view_ex(
+ depsgraph,
wm, win, sa, v3d, ar, smooth_viewtx,
&(const V3D_SmoothParams) {
.camera_old = camera_old,
@@ -1145,26 +1253,20 @@ static bool view3d_localview_init(
}
}
- v3d->lay = locallay;
- }
- else {
- /* clear flags */
- for (base = FIRSTBASE; base; base = base->next) {
- if (base->lay & locallay) {
- base->lay -= locallay;
- if (base->lay == 0) base->lay = v3d->layact;
- if (base->object != scene->obedit) base->flag |= SELECT;
- base->object->lay = base->lay;
- }
- }
+ v3d->local_view_uuid = local_view_bit;
}
- DAG_on_visible_update(bmain, false);
-
+ DEG_on_visible_update(bmain, false);
return ok;
}
-static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, ScrArea *sa, const int smooth_viewtx)
+static void restore_localviewdata(
+ const Depsgraph *depsgraph,
+ wmWindowManager *wm,
+ wmWindow *win,
+ Main *bmain,
+ ScrArea *sa,
+ const int smooth_viewtx)
{
const bool free = true;
ARegion *ar;
@@ -1176,9 +1278,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
camera_old = v3d->camera;
camera_new = v3d->localvd->camera;
- v3d->lay = v3d->localvd->lay;
- v3d->layact = v3d->localvd->layact;
- v3d->drawtype = v3d->localvd->drawtype;
+ v3d->local_view_uuid = 0;
v3d->camera = v3d->localvd->camera;
if (free) {
@@ -1201,6 +1301,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
rv3d->camzoom = rv3d->localvd->camzoom;
ED_view3d_smooth_view_ex(
+ depsgraph,
wm, win, sa,
v3d, ar, smooth_viewtx,
&(const V3D_SmoothParams) {
@@ -1220,35 +1321,35 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
}
static bool view3d_localview_exit(
- wmWindowManager *wm, wmWindow *win,
- Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx)
+ const Depsgraph *depsgraph,
+ wmWindowManager *wm,
+ wmWindow *win,
+ Main *bmain,
+ ViewLayer *view_layer,
+ ScrArea *sa,
+ const int smooth_viewtx)
{
View3D *v3d = sa->spacedata.first;
struct Base *base;
- unsigned int locallay;
+ unsigned int local_view_bit;
if (v3d->localvd) {
- locallay = v3d->lay & 0xFF000000;
-
- restore_localviewdata(wm, win, bmain, sa, smooth_viewtx);
+ local_view_bit = v3d->local_view_uuid;
- /* for when in other window the layers have changed */
- if (v3d->scenelock) v3d->lay = scene->lay;
+ restore_localviewdata(depsgraph, wm, win, bmain, sa, smooth_viewtx);
- for (base = FIRSTBASE; base; base = base->next) {
- if (base->lay & locallay) {
- base->lay -= locallay;
- if (base->lay == 0) base->lay = v3d->layact;
- if (base->object != scene->obedit) {
- base->flag |= SELECT;
- base->object->flag |= SELECT;
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ if (base->local_view_bits & local_view_bit) {
+ base->local_view_bits &= ~local_view_bit;
+ if (base->object != obedit) {
+ ED_object_base_select(base, BA_SELECT);
}
- base->object->lay = base->lay;
}
}
- DAG_on_visible_update(bmain, false);
+ DEG_on_visible_update(bmain, false);
return true;
}
@@ -1259,30 +1360,36 @@ static bool view3d_localview_exit(
static int localview_exec(bContext *C, wmOperator *op)
{
+ const Depsgraph *depsgraph = CTX_data_depsgraph(C);
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = CTX_wm_view3d(C);
bool changed;
if (v3d->localvd) {
- changed = view3d_localview_exit(wm, win, bmain, scene, sa, smooth_viewtx);
+ changed = view3d_localview_exit(depsgraph, wm, win, bmain, view_layer, sa, smooth_viewtx);
}
else {
- changed = view3d_localview_init(wm, win, bmain, scene, sa, smooth_viewtx, op->reports);
+ changed = view3d_localview_init(depsgraph, wm, win, bmain, view_layer, sa, smooth_viewtx, op->reports);
}
if (changed) {
- DAG_id_type_tag(bmain, ID_OB);
+ DEG_id_type_tag(bmain, ID_OB);
ED_area_tag_redraw(sa);
- /* unselected objects become selected when exiting */
+ /* Unselected objects become selected when exiting. */
if (v3d->localvd == NULL) {
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
+ else {
+ DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+ }
return OPERATOR_FINISHED;
}
@@ -1305,217 +1412,105 @@ void VIEW3D_OT_localview(wmOperatorType *ot)
ot->poll = ED_operator_view3d_active;
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Game Engine Operator
- *
- * Start the game engine (handles context switching).
- * \{ */
-
-#ifdef WITH_GAMEENGINE
-
-static ListBase queue_back;
-static void game_engine_save_state(bContext *C, wmWindow *win)
+static int localview_remove_from_exec(bContext *C, wmOperator *op)
{
+ View3D *v3d = CTX_wm_view3d(C);
Main *bmain = CTX_data_main(C);
- Object *obact = CTX_data_active_object(C);
-
- glPushAttrib(GL_ALL_ATTRIB_BITS);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bool changed = false;
- if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
- GPU_paint_set_mipmap(bmain, 1);
+ for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+ if (TESTBASE(v3d, base)) {
+ base->local_view_bits &= ~v3d->local_view_uuid;
+ ED_object_base_select(base, BA_DESELECT);
- queue_back = win->queue;
+ if (base == BASACT(view_layer)) {
+ view_layer->basact = NULL;
+ }
+ changed = true;
+ }
+ }
- BLI_listbase_clear(&win->queue);
+ if (changed) {
+ DEG_on_visible_update(bmain, false);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No object selected");
+ return OPERATOR_CANCELLED;
+ }
}
-static void game_engine_restore_state(bContext *C, wmWindow *win)
+static bool localview_remove_from_poll(bContext *C)
{
- Main *bmain = CTX_data_main(C);
- Object *obact = CTX_data_active_object(C);
-
- if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
- GPU_paint_set_mipmap(bmain, 0);
-
- /* check because closing win can set to NULL */
- if (win) {
- win->queue = queue_back;
+ if (CTX_data_edit_object(C) != NULL) {
+ return false;
}
- GPU_state_init();
- GPU_set_tpage(NULL, 0, 0);
-
- glPopAttrib();
+ View3D *v3d = CTX_wm_view3d(C);
+ return v3d && v3d->localvd;
}
-/* was space_set_commmandline_options in 2.4x */
-static void game_set_commmandline_options(GameData *gm)
+void VIEW3D_OT_localview_remove_from(wmOperatorType *ot)
{
- SYS_SystemHandle syshandle;
- int test;
-
- if ((syshandle = SYS_GetSystem())) {
- /* User defined settings */
- test = (U.gameflags & USER_DISABLE_MIPMAP);
- GPU_set_mipmap(G_MAIN, !test);
- SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
-
- /* File specific settings: */
- /* Only test the first one. These two are switched
- * simultaneously. */
- test = (gm->flag & GAME_SHOW_FRAMERATE);
- SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
- SYS_WriteCommandLineInt(syshandle, "show_profile", test);
-
- test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
- SYS_WriteCommandLineInt(syshandle, "show_properties", test);
-
- test = (gm->flag & GAME_SHOW_PHYSICS);
- SYS_WriteCommandLineInt(syshandle, "show_physics", test);
-
- test = (gm->flag & GAME_ENABLE_ALL_FRAMES);
- SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
-
- test = (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
- SYS_WriteCommandLineInt(syshandle, "animation_record", test);
-
- test = (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
- SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
-
- test = (gm->matmode == GAME_MAT_MULTITEX);
- SYS_WriteCommandLineInt(syshandle, "blender_material", test);
- test = (gm->matmode == GAME_MAT_GLSL);
- SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
- test = (gm->flag & GAME_DISPLAY_LISTS);
- SYS_WriteCommandLineInt(syshandle, "displaylists", test);
-
+ /* identifiers */
+ ot->name = "Remove from Local View";
+ ot->description = "Move selected objects out of local view";
+ ot->idname = "VIEW3D_OT_localview_remove_from";
- }
+ /* api callbacks */
+ ot->exec = localview_remove_from_exec;
+ ot->invoke = WM_operator_confirm;
+ ot->poll = localview_remove_from_poll;
+ ot->flag = OPTYPE_UNDO;
}
-#endif /* WITH_GAMEENGINE */
-
-static bool game_engine_poll(bContext *C)
-{
- bScreen *screen;
- /* we need a context and area to launch BGE
- * it's a temporary solution to avoid crash at load time
- * if we try to auto run the BGE. Ideally we want the
- * context to be set as soon as we load the file. */
-
- if (CTX_wm_window(C) == NULL) return 0;
- if ((screen = CTX_wm_screen(C)) == NULL) return 0;
-
- if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)
- return 0;
-
- if (!BKE_scene_uses_blender_game(screen->scene))
- return 0;
+/** \} */
- return 1;
-}
+/* -------------------------------------------------------------------- */
+/** \name View Layer Utilities
+ * \{ */
-static int game_engine_exec(bContext *C, wmOperator *op)
+int ED_view3d_view_layer_set(int lay, const bool *values, int *active)
{
-#ifdef WITH_GAMEENGINE
- Scene *startscene = CTX_data_scene(C);
- Main *bmain = CTX_data_main(C);
- ScrArea /* *sa, */ /* UNUSED */ *prevsa = CTX_wm_area(C);
- ARegion *ar, *prevar = CTX_wm_region(C);
- wmWindow *prevwin = CTX_wm_window(C);
- RegionView3D *rv3d;
- rcti cam_frame;
-
- UNUSED_VARS(op);
-
- /* bad context switch .. */
- if (!ED_view3d_context_activate(C))
- return OPERATOR_CANCELLED;
-
- /* redraw to hide any menus/popups, we don't go back to
- * the window manager until after this operator exits */
- WM_redraw_windows(C);
-
- BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_PRE);
-
- rv3d = CTX_wm_region_view3d(C);
- /* sa = CTX_wm_area(C); */ /* UNUSED */
- ar = CTX_wm_region(C);
-
- view3d_operator_needs_opengl(C);
-
- game_set_commmandline_options(&startscene->gm);
+ int i, tot = 0;
- if ((rv3d->persp == RV3D_CAMOB) &&
- (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) &&
- (startscene->gm.stereoflag != STEREO_DOME))
- {
- /* Letterbox */
- rctf cam_framef;
- ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false);
- cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
- cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
- cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
- cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
- BLI_rcti_isect(&ar->winrct, &cam_frame, &cam_frame);
- }
- else {
- cam_frame.xmin = ar->winrct.xmin;
- cam_frame.xmax = ar->winrct.xmax;
- cam_frame.ymin = ar->winrct.ymin;
- cam_frame.ymax = ar->winrct.ymax;
- }
+ /* ensure we always have some layer selected */
+ for (i = 0; i < 20; i++)
+ if (values[i])
+ tot++;
+ if (tot == 0)
+ return lay;
- game_engine_save_state(C, prevwin);
+ for (i = 0; i < 20; i++) {
- StartKetsjiShell(C, ar, &cam_frame, 1);
+ if (active) {
+ /* if this value has just been switched on, make that layer active */
+ if (values[i] && (lay & (1 << i)) == 0) {
+ *active = (1 << i);
+ }
+ }
- /* window wasnt closed while the BGE was running */
- if (BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
- prevwin = NULL;
- CTX_wm_window_set(C, NULL);
+ if (values[i]) lay |= (1 << i);
+ else lay &= ~(1 << i);
}
- ED_area_tag_redraw(CTX_wm_area(C));
-
- if (prevwin) {
- /* restore context, in case it changed in the meantime, for
- * example by working in another window or closing it */
- CTX_wm_region_set(C, prevar);
- CTX_wm_window_set(C, prevwin);
- CTX_wm_area_set(C, prevsa);
+ /* ensure always an active layer */
+ if (active && (lay & *active) == 0) {
+ for (i = 0; i < 20; i++) {
+ if (lay & (1 << i)) {
+ *active = 1 << i;
+ break;
+ }
+ }
}
- game_engine_restore_state(C, prevwin);
-
- //XXX restore_all_scene_cfra(scene_cfra_store);
- BKE_scene_set_background(CTX_data_main(C), startscene);
- //XXX BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
-
- BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_POST);
-
- return OPERATOR_FINISHED;
-#else
- UNUSED_VARS(C);
- BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build");
- return OPERATOR_CANCELLED;
-#endif
-}
-
-void VIEW3D_OT_game_start(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Start Game Engine";
- ot->description = "Start game engine";
- ot->idname = "VIEW3D_OT_game_start";
-
- /* api callbacks */
- ot->exec = game_engine_exec;
-
- ot->poll = game_engine_poll;
+ return lay;
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 33173ad3fd6..68a40f33368 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -37,6 +37,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BLT_translation.h"
@@ -56,6 +57,10 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_immediate.h"
+
+#include "DEG_depsgraph.h"
+
#include "view3d_intern.h" /* own include */
#ifdef WITH_INPUT_NDOF
@@ -172,59 +177,6 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "View3D Walk Modal", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_CANCEL);
-
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, WALK_MODAL_CONFIRM);
-
- WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_FAST_ENABLE);
- WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_FAST_DISABLE);
-
- WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_SLOW_ENABLE);
- WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_SLOW_DISABLE);
-
- /* WASD */
- WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_FORWARD);
- WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD);
- WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_LEFT);
- WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_RIGHT);
- WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_UP);
- WM_modalkeymap_add_item(keymap, QKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_DOWN);
-
- WM_modalkeymap_add_item(keymap, WKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_FORWARD_STOP);
- WM_modalkeymap_add_item(keymap, SKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD_STOP);
- WM_modalkeymap_add_item(keymap, AKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_LEFT_STOP);
- WM_modalkeymap_add_item(keymap, DKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_RIGHT_STOP);
- WM_modalkeymap_add_item(keymap, EKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_UP_STOP);
- WM_modalkeymap_add_item(keymap, QKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_DOWN_STOP);
-
- WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_FORWARD);
- WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_BACKWARD);
- WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_LEFT);
- WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_RIGHT);
-
- WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_FORWARD_STOP);
- WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD_STOP);
- WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_LEFT_STOP);
- WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_RIGHT_STOP);
-
- WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, 0, 0, WALK_MODAL_TOGGLE);
- WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, WALK_MODAL_TOGGLE);
-
- WM_modalkeymap_add_item(keymap, VKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_JUMP);
- WM_modalkeymap_add_item(keymap, VKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_JUMP_STOP);
-
- WM_modalkeymap_add_item(keymap, SPACEKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_TELEPORT);
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_TELEPORT);
-
- WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_ACCELERATE);
- WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, KM_ANY, 0, WALK_MODAL_DECELERATE);
- WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ANY, 0, WALK_MODAL_ACCELERATE);
- WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ANY, 0, WALK_MODAL_DECELERATE);
-
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_walk");
}
@@ -245,6 +197,7 @@ typedef struct WalkInfo {
RegionView3D *rv3d;
View3D *v3d;
ARegion *ar;
+ struct Depsgraph *depsgraph;
Scene *scene;
wmTimer *timer; /* needed for redraws */
@@ -328,7 +281,7 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a
rctf viewborder;
if (walk->scene->camera) {
- ED_view3d_calc_camera_border(walk->scene, ar, walk->v3d, walk->rv3d, &viewborder, false);
+ ED_view3d_calc_camera_border(walk->scene, walk->depsgraph, ar, walk->v3d, walk->rv3d, &viewborder, false);
xoff = viewborder.xmin + BLI_rctf_size_x(&viewborder) * 0.5f;
yoff = viewborder.ymin + BLI_rctf_size_y(&viewborder) * 0.5f;
}
@@ -337,24 +290,33 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a
yoff = walk->ar->winy / 2;
}
- UI_ThemeColor(TH_VIEW_OVERLAY);
- glBegin(GL_LINES);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+
+ immBegin(GPU_PRIM_LINES, 8);
+
/* North */
- glVertex2i(xoff, yoff + inner_length);
- glVertex2i(xoff, yoff + outter_length);
+ immVertex2i(pos, xoff, yoff + inner_length);
+ immVertex2i(pos, xoff, yoff + outter_length);
/* East */
- glVertex2i(xoff + inner_length, yoff);
- glVertex2i(xoff + outter_length, yoff);
+ immVertex2i(pos, xoff + inner_length, yoff);
+ immVertex2i(pos, xoff + outter_length, yoff);
/* South */
- glVertex2i(xoff, yoff - inner_length);
- glVertex2i(xoff, yoff - outter_length);
+ immVertex2i(pos, xoff, yoff - inner_length);
+ immVertex2i(pos, xoff, yoff - outter_length);
/* West */
- glVertex2i(xoff - inner_length, yoff);
- glVertex2i(xoff - outter_length, yoff);
- glEnd();
+ immVertex2i(pos, xoff - inner_length, yoff);
+ immVertex2i(pos, xoff - outter_length, yoff);
+
+ immEnd();
+ immUnbindProgram();
}
static void walk_update_header(bContext *C, wmOperator *op, WalkInfo *walk)
@@ -389,7 +351,7 @@ static void walk_update_header(bContext *C, wmOperator *op, WalkInfo *walk)
#undef WM_MODALKEY
- ED_area_headerprint(CTX_wm_area(C), header);
+ ED_workspace_status_text(C, header);
}
static void walk_navigation_mode_set(bContext *C, wmOperator *op, WalkInfo *walk, eWalkMethod mode)
@@ -493,11 +455,13 @@ static float userdef_speed = -1.f;
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
walk->rv3d = CTX_wm_region_view3d(C);
walk->v3d = CTX_wm_view3d(C);
walk->ar = CTX_wm_region(C);
+ walk->depsgraph = CTX_data_depsgraph(C);
walk->scene = CTX_data_scene(C);
#ifdef NDOF_WALK_DEBUG
@@ -587,11 +551,11 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
walk->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), walk->scene, 0,
+ bmain, walk->scene, CTX_data_depsgraph(C), 0,
walk->ar, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
- walk->scene, walk->v3d, walk->rv3d,
+ walk->depsgraph, walk->scene, walk->v3d, walk->rv3d,
(U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0);
/* center the mouse */
@@ -1419,7 +1383,7 @@ static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED))
- ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_workspace_status_text(C, NULL);
return exit_code;
}
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index b7de49d8158..ccc143af18f 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../ikplugin
../../makesdna
../../makesrna
+ ../../render/extern/include
../../windowmanager
../../depsgraph
../../../../intern/guardedalloc
@@ -44,8 +45,10 @@ set(SRC
transform_constraints.c
transform_conversions.c
transform_generics.c
+ transform_gizmo_2d.c
+ transform_gizmo_3d.c
+ transform_gizmo_extrude_3d.c
transform_input.c
- transform_manipulator.c
transform_ops.c
transform_orientations.c
transform_snap.c
@@ -58,10 +61,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
-endif()
-
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 3276c4af8fc..d05fc058184 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -41,8 +41,11 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_mask_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h" /* PET modes */
+#include "DNA_workspace_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_alloca.h"
#include "BLI_utildefines.h"
@@ -61,12 +64,21 @@
#include "BKE_constraint.h"
#include "BKE_particle.h"
#include "BKE_unit.h"
+#include "BKE_scene.h"
#include "BKE_mask.h"
+#include "BKE_mesh.h"
#include "BKE_report.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "ED_image.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
@@ -76,6 +88,7 @@
#include "ED_mesh.h"
#include "ED_clip.h"
#include "ED_node.h"
+#include "ED_gpencil.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -86,6 +99,7 @@
#include "UI_resources.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "BLF_api.h"
#include "BLT_translation.h"
@@ -103,9 +117,10 @@ static void drawEdgeSlide(TransInfo *t);
static void drawVertSlide(TransInfo *t);
static void postInputRotation(TransInfo *t, float values[3]);
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around);
+static void ElementRotation(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around);
static void initSnapSpatial(TransInfo *t, float r_snap[3]);
+static void storeCustomLNorValue(TransDataContainer *t, BMesh *bm);
/* Transform Callbacks */
static void initBend(TransInfo *t);
@@ -131,6 +146,9 @@ static void applyToSphere(TransInfo *t, const int mval[2]);
static void initRotation(TransInfo *t);
static void applyRotation(TransInfo *t, const int mval[2]);
+static void initNormalRotation(TransInfo *t);
+static void applyNormalRotation(TransInfo *t, const int mval[2]);
+
static void initShrinkFatten(TransInfo *t);
static void applyShrinkFatten(TransInfo *t, const int mval[2]);
@@ -204,7 +222,8 @@ static bool transdata_check_local_center(TransInfo *t, short around)
{
return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
(t->flag & (T_OBJECT | T_POSE)) ||
- (t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
+ /* implicit: (t->flag & T_EDIT) */
+ (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
(t->spacetype == SPACE_IPO) ||
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))
);
@@ -213,10 +232,10 @@ static bool transdata_check_local_center(TransInfo *t, short around)
bool transdata_check_local_islands(TransInfo *t, short around)
{
return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
- (t->obedit && ELEM(t->obedit->type, OB_MESH))));
+ (ELEM(t->obedit_type, OB_MESH))));
}
-/* ************************** SPACE DEPENDANT CODE **************************** */
+/* ************************** SPACE DEPENDENT CODE **************************** */
void setTransformViewMatrices(TransInfo *t)
{
@@ -238,6 +257,7 @@ void setTransformViewMatrices(TransInfo *t)
}
calculateCenter2D(t);
+ calculateCenterLocal(t, t->center_global);
}
void setTransformViewAspect(TransInfo *t, float r_aspect[3])
@@ -560,6 +580,10 @@ void removeAspectRatio(TransInfo *t, float vec[2])
static void viewRedrawForce(const bContext *C, TransInfo *t)
{
if (t->options & CTX_GPENCIL_STROKES) {
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+ }
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_VIEW3D) {
@@ -612,8 +636,12 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
else {
// XXX how to deal with lock?
SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
- if (sima->lock) WM_event_add_notifier(C, NC_GEOM | ND_DATA, t->obedit->data);
- else ED_area_tag_redraw(t->sa);
+ if (sima->lock) {
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data);
+ }
+ else {
+ ED_area_tag_redraw(t->sa);
+ }
}
}
else if (t->spacetype == SPACE_CLIP) {
@@ -637,7 +665,7 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
static void viewRedrawPost(bContext *C, TransInfo *t)
{
- ED_area_headerprint(t->sa, NULL);
+ ED_area_status_text(t->sa, NULL);
if (t->spacetype == SPACE_VIEW3D) {
/* if autokeying is enabled, send notifiers that keyframes were added */
@@ -798,6 +826,84 @@ enum {
TFM_MODAL_INSERTOFS_TOGGLE_DIR = 27,
};
+static bool transform_modal_item_poll(const wmOperator *op, int value)
+{
+ const TransInfo *t = op->customdata;
+ switch (value) {
+ case TFM_MODAL_PROPSIZE:
+ case TFM_MODAL_PROPSIZE_UP:
+ case TFM_MODAL_PROPSIZE_DOWN:
+ {
+ if ((t->flag & T_PROP_EDIT) == 0) {
+ return false;
+ }
+ break;
+ }
+ case TFM_MODAL_ADD_SNAP:
+ case TFM_MODAL_REMOVE_SNAP:
+ {
+ if (t->spacetype != SPACE_VIEW3D) {
+ return false;
+ }
+ else if (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) {
+ return false;
+ }
+ else if (!validSnap(t)) {
+ return false;
+ }
+ break;
+ }
+ case TFM_MODAL_AXIS_X:
+ case TFM_MODAL_AXIS_Y:
+ case TFM_MODAL_AXIS_Z:
+ case TFM_MODAL_PLANE_X:
+ case TFM_MODAL_PLANE_Y:
+ case TFM_MODAL_PLANE_Z:
+ {
+ if (t->flag & T_NO_CONSTRAINT) {
+ return false;
+ }
+ if (!ELEM(value, TFM_MODAL_AXIS_X, TFM_MODAL_AXIS_Y)) {
+ if (t->flag & T_2D_EDIT) {
+ return false;
+ }
+ }
+ break;
+ }
+ case TFM_MODAL_CONS_OFF:
+ {
+ if ((t->con.mode & CON_APPLY) == 0) {
+ return false;
+ }
+ break;
+ }
+ case TFM_MODAL_EDGESLIDE_UP:
+ case TFM_MODAL_EDGESLIDE_DOWN:
+ {
+ if (t->mode != TFM_EDGE_SLIDE) {
+ return false;
+ }
+ break;
+ }
+ case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
+ {
+ if (t->spacetype != SPACE_NODE) {
+ return false;
+ }
+ break;
+ }
+ case TFM_MODAL_AUTOIK_LEN_INC:
+ case TFM_MODAL_AUTOIK_LEN_DEC:
+ {
+ if ((t->flag & T_AUTOIK) == 0) {
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
/* called in transform_ops.c, on each regeneration of keymaps */
wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{
@@ -826,7 +932,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
{TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
{TFM_MODAL_INSERTOFS_TOGGLE_DIR, "INSERTOFS_TOGGLE_DIR", 0, "Toggle Direction for Node Auto-offset", ""},
- {TFM_MODAL_TRANSLATE, "TRANSLATE", 0, "Translate", ""},
+ {TFM_MODAL_TRANSLATE, "TRANSLATE", 0, "Move", ""},
{TFM_MODAL_ROTATE, "ROTATE", 0, "Rotate", ""},
{TFM_MODAL_RESIZE, "RESIZE", 0, "Resize", ""},
{0, NULL, 0, NULL, NULL}
@@ -834,63 +940,8 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Transform Modal Map");
- /* this function is called for each spacetype, only needs to add map once */
- if (keymap && keymap->modal_items) return NULL;
-
keymap = WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items);
-
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL);
-
- WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, TFM_MODAL_AXIS_X);
- WM_modalkeymap_add_item(keymap, YKEY, KM_PRESS, 0, 0, TFM_MODAL_AXIS_Y);
- WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, TFM_MODAL_AXIS_Z);
-
- WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PLANE_X);
- WM_modalkeymap_add_item(keymap, YKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PLANE_Y);
- WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PLANE_Z);
-
- WM_modalkeymap_add_item(keymap, CKEY, KM_PRESS, 0, 0, TFM_MODAL_CONS_OFF);
-
- WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE);
- WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE);
- WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, TFM_MODAL_RESIZE);
-
- WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_SNAP_TOGGLE);
-
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON);
- WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, TFM_MODAL_SNAP_INV_OFF);
-
- WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON);
- WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, TFM_MODAL_SNAP_INV_OFF);
-
- WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, TFM_MODAL_ADD_SNAP);
- WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_ALT, 0, TFM_MODAL_REMOVE_SNAP);
-
- WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
- WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
- WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
- WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
- WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
- WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
- WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_UP);
- WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_PROPSIZE_DOWN);
- WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
-
- WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
- WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN);
-
- WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC);
- WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC);
- WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC);
- WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC);
-
- /* node editor only */
- WM_modalkeymap_add_item(keymap, TKEY, KM_PRESS, 0, 0, TFM_MODAL_INSERTOFS_TOGGLE_DIR);
+ keymap->poll_modal_item = transform_modal_item_poll;
return keymap;
}
@@ -941,13 +992,28 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
}
}
else if (!edit_2d) {
- if (cmode == axis) {
- if (t->con.orientation != V3D_MANIP_GLOBAL) {
+ if (cmode != axis) {
+ /* First press, constraint to an axis. */
+ t->orientation.index = 0;
+ const short *orientation_ptr = t->orientation.types[t->orientation.index];
+ const short orientation = orientation_ptr ? *orientation_ptr : V3D_MANIP_GLOBAL;
+ if (is_plane == false) {
+ setUserConstraint(t, orientation, constraint_axis, msg2);
+ }
+ else {
+ setUserConstraint(t, orientation, constraint_plane, msg3);
+ }
+ }
+ else {
+ /* Successive presses on existing axis, cycle orientation modes. */
+ t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types);
+
+ if (t->orientation.index == 0) {
stopConstraint(t);
}
else {
- short orientation = (t->current_orientation != V3D_MANIP_GLOBAL ?
- t->current_orientation : V3D_MANIP_LOCAL);
+ const short *orientation_ptr = t->orientation.types[t->orientation.index];
+ const short orientation = orientation_ptr ? *orientation_ptr : V3D_MANIP_GLOBAL;
if (is_plane == false) {
setUserConstraint(t, orientation, constraint_axis, msg2);
}
@@ -956,14 +1022,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
}
}
}
- else {
- if (is_plane == false) {
- setUserConstraint(t, V3D_MANIP_GLOBAL, constraint_axis, msg2);
- }
- else {
- setUserConstraint(t, V3D_MANIP_GLOBAL, constraint_plane, msg3);
- }
- }
}
t->redraw |= TREDRAW_HARD;
}
@@ -1032,7 +1090,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
else {
- if (t->obedit && t->obedit->type == OB_MESH) {
+ if (t->obedit_type == OB_MESH) {
if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
restoreTransObjects(t);
resetTransModal(t);
@@ -1042,11 +1100,13 @@ int transformEvent(TransInfo *t, const wmEvent *event)
initEdgeSlide(t);
/* if that fails, do vertex slide */
if (t->state == TRANS_CANCEL) {
+ resetTransModal(t);
t->state = TRANS_STARTING;
initVertSlide(t);
}
/* vert slide can fail on unconnected vertices (rare but possible) */
if (t->state == TRANS_CANCEL) {
+ resetTransModal(t);
t->mode = TFM_TRANSLATION;
t->state = TRANS_STARTING;
restoreTransObjects(t);
@@ -1450,6 +1510,18 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
+ case NKEY:
+ if (ELEM(t->mode, TFM_ROTATION)) {
+ if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
+ restoreTransObjects(t);
+ resetTransModal(t);
+ resetTransRestrictions(t);
+ initNormalRotation(t);
+ t->redraw = TREDRAW_HARD;
+ handled = true;
+ }
+ }
+ break;
default:
break;
}
@@ -1519,6 +1591,12 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
+ if (t->redraw &&
+ !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))
+ {
+ WM_window_status_area_tag_redraw(CTX_wm_window(t->context));
+ }
+
if (handled || t->redraw) {
return 0;
}
@@ -1532,6 +1610,8 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data");
bool success;
+ t->context = C;
+
t->state = TRANS_RUNNING;
/* avoid calculating PET */
@@ -1548,7 +1628,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
t->around = centerMode; // override userdefined mode
- if (t->total == 0) {
+ if (t->data_len_all == 0) {
success = false;
}
else {
@@ -1583,8 +1663,16 @@ typedef enum {
LEFT,
RIGHT
} ArrowDirection;
+
+#define POS_INDEX 0
+/* NOTE: this --^ is a bit hackish, but simplifies GPUVertFormat usage among functions
+ * private to this file - merwin
+ */
+
static void drawArrow(ArrowDirection d, short offset, short length, short size)
{
+ immBegin(GPU_PRIM_LINES, 6);
+
switch (d) {
case LEFT:
offset = -offset;
@@ -1592,14 +1680,12 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size)
size = -size;
ATTR_FALLTHROUGH;
case RIGHT:
- glBegin(GL_LINES);
- glVertex2s(offset, 0);
- glVertex2s(offset + length, 0);
- glVertex2s(offset + length, 0);
- glVertex2s(offset + length - size, -size);
- glVertex2s(offset + length, 0);
- glVertex2s(offset + length - size, size);
- glEnd();
+ immVertex2f(POS_INDEX, offset, 0);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length - size, -size);
+ immVertex2f(POS_INDEX, offset + length, 0);
+ immVertex2f(POS_INDEX, offset + length - size, size);
break;
case DOWN:
@@ -1608,45 +1694,45 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size)
size = -size;
ATTR_FALLTHROUGH;
case UP:
- glBegin(GL_LINES);
- glVertex2s(0, offset);
- glVertex2s(0, offset + length);
- glVertex2s(0, offset + length);
- glVertex2s(-size, offset + length - size);
- glVertex2s(0, offset + length);
- glVertex2s(size, offset + length - size);
- glEnd();
+ immVertex2f(POS_INDEX, 0, offset);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, -size, offset + length - size);
+ immVertex2f(POS_INDEX, 0, offset + length);
+ immVertex2f(POS_INDEX, size, offset + length - size);
break;
}
+
+ immEnd();
}
static void drawArrowHead(ArrowDirection d, short size)
{
+ immBegin(GPU_PRIM_LINES, 4);
+
switch (d) {
case LEFT:
size = -size;
ATTR_FALLTHROUGH;
case RIGHT:
- glBegin(GL_LINES);
- glVertex2s(0, 0);
- glVertex2s(-size, -size);
- glVertex2s(0, 0);
- glVertex2s(-size, size);
- glEnd();
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, -size);
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, size);
break;
case DOWN:
size = -size;
ATTR_FALLTHROUGH;
case UP:
- glBegin(GL_LINES);
- glVertex2s(0, 0);
- glVertex2s(-size, -size);
- glVertex2s(0, 0);
- glVertex2s(size, -size);
- glEnd();
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, -size, -size);
+ immVertex2f(POS_INDEX, 0, 0);
+ immVertex2f(POS_INDEX, size, -size);
break;
}
+
+ immEnd();
}
static void drawArc(float size, float angle_start, float angle_end, int segments)
@@ -1655,14 +1741,14 @@ static void drawArc(float size, float angle_start, float angle_end, int segments
float angle;
int a;
- glBegin(GL_LINE_STRIP);
+ immBegin(GPU_PRIM_LINE_STRIP, segments + 1);
for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
- glVertex2f(cosf(angle) * size, sinf(angle) * size);
+ immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
}
- glVertex2f(cosf(angle_end) * size, sinf(angle_end) * size);
+ immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
- glEnd();
+ immEnd();
}
static bool helpline_poll(bContext *C)
@@ -1674,92 +1760,173 @@ static bool helpline_poll(bContext *C)
return 0;
}
-static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
+static void drawHelpline(bContext *C, int x, int y, void *customdata)
{
TransInfo *t = (TransInfo *)customdata;
- if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR)) {
+ if (t->helpline != HLP_NONE) {
float cent[2];
- int mval[2];
+ float mval[3] = {
+ x,
+ y,
+ 0.0f,
+ };
+ float tmval[2] = {
+ (float)t->mval[0],
+ (float)t->mval[1],
+ };
+
+ /* grease pencil only can edit one object at time because GP has
+ * multiframe edition that replaces multiobject edition.
+ * If multiobject edition is added, maybe this code will need
+ * an update
+ */
+ if ((t->flag & T_POINTS) && (t->options & CTX_GPENCIL_STROKES) &&
+ (t->around != V3D_AROUND_ACTIVE))
+ {
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ float vecrot[3];
+ copy_v3_v3(vecrot, t->center_global);
+ mul_m4_v3(ob->obmat, vecrot);
+ projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ }
+ }
+ else {
+ /* normally, never must be used */
+ projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ }
+ }
+ else {
+ projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ }
+
+ /* Offset the values for the area region. */
+ const float offset[2] = {
+ t->ar->winrct.xmin,
+ t->ar->winrct.ymin,
+ };
+
+ for (int i = 0; i < 2; i++) {
+ cent[i] += offset[i];
+ tmval[i] += offset[i];
+ }
+
+ GPU_matrix_push();
- mval[0] = x;
- mval[1] = y;
+ /* Dashed lines first. */
+ if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) {
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
+ UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */
+ BLI_assert(shdr_pos == POS_INDEX);
+
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(POS_INDEX, cent);
+ immVertex2f(POS_INDEX, tmval[0], tmval[1]);
+ immEnd();
+
+ immUnbindProgram();
+ }
- glPushMatrix();
+ /* And now, solid lines. */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ UNUSED_VARS_NDEBUG(pos); /* silence warning */
+ BLI_assert(pos == POS_INDEX);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
switch (t->helpline) {
case HLP_SPRING:
- UI_ThemeColor(TH_VIEW_OVERLAY);
+ immUniformThemeColor(TH_VIEW_OVERLAY);
- setlinestyle(3);
- glLineWidth(1);
- glBegin(GL_LINES);
- glVertex2iv(t->mval);
- glVertex2fv(cent);
- glEnd();
+ GPU_matrix_translate_3fv(mval);
+ GPU_matrix_rotate_axis(-RAD2DEGF(atan2f(cent[0] - tmval[0], cent[1] - tmval[1])), 'Z');
- glTranslate2iv(mval);
- glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1);
-
- setlinestyle(0);
- glLineWidth(3.0);
+ GPU_line_width(3.0f);
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
break;
case HLP_HARROW:
- UI_ThemeColor(TH_VIEW_OVERLAY);
-
- glTranslate2iv(mval);
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+ GPU_matrix_translate_3fv(mval);
- glLineWidth(3.0);
+ GPU_line_width(3.0f);
drawArrow(RIGHT, 5, 10, 5);
drawArrow(LEFT, 5, 10, 5);
break;
case HLP_VARROW:
- UI_ThemeColor(TH_VIEW_OVERLAY);
+ immUniformThemeColor(TH_VIEW_OVERLAY);
- glTranslate2iv(mval);
+ GPU_matrix_translate_3fv(mval);
- glLineWidth(3.0);
+ GPU_line_width(3.0f);
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
break;
+ case HLP_CARROW:
+ {
+ /* Draw arrow based on direction defined by custom-points. */
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+
+ GPU_matrix_translate_3fv(mval);
+
+ GPU_line_width(3.0f);
+
+ const int *data = t->mouse.data;
+ const float dx = data[2] - data[0], dy = data[3] - data[1];
+ const float angle = -atan2f(dx, dy);
+
+ GPU_matrix_push();
+
+ GPU_matrix_rotate_axis(RAD2DEGF(angle), 'Z');
+
+ drawArrow(UP, 5, 10, 5);
+ drawArrow(DOWN, 5, 10, 5);
+
+ GPU_matrix_pop();
+ break;
+ }
case HLP_ANGLE:
{
- float dx = t->mval[0] - cent[0], dy = t->mval[1] - cent[1];
+ float dx = tmval[0] - cent[0], dy = tmval[1] - cent[1];
float angle = atan2f(dy, dx);
float dist = hypotf(dx, dy);
float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f);
float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f);
- UI_ThemeColor(TH_VIEW_OVERLAY);
- setlinestyle(3);
- glLineWidth(1);
- glBegin(GL_LINES);
- glVertex2iv(t->mval);
- glVertex2fv(cent);
- glEnd();
+ immUniformThemeColor(TH_VIEW_OVERLAY);
- glTranslatef(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0);
+ GPU_matrix_translate_3f(cent[0] - tmval[0] + mval[0], cent[1] - tmval[1] + mval[1], 0);
- setlinestyle(0);
- glLineWidth(3.0);
+ GPU_line_width(3.0f);
drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
- glPushMatrix();
+ GPU_matrix_push();
- glTranslatef(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
- glRotatef(RAD2DEGF(angle - delta_angle), 0, 0, 1);
+ GPU_matrix_translate_3f(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle - delta_angle), 'Z');
drawArrowHead(DOWN, 5);
- glPopMatrix();
+ GPU_matrix_pop();
- glTranslatef(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
- glRotatef(RAD2DEGF(angle + delta_angle), 0, 0, 1);
+ GPU_matrix_translate_3f(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
+ GPU_matrix_rotate_axis(RAD2DEGF(angle + delta_angle), 'Z');
drawArrowHead(UP, 5);
break;
@@ -1769,18 +1936,18 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
unsigned char col[3], col2[3];
UI_GetThemeColor3ubv(TH_GRID, col);
- glTranslate2iv(mval);
+ GPU_matrix_translate_3fv(mval);
- glLineWidth(3.0);
+ GPU_line_width(3.0f);
UI_make_axis_color(col, col2, 'X');
- glColor3ubv((GLubyte *)col2);
+ immUniformColor3ubv(col2);
drawArrow(RIGHT, 5, 10, 5);
drawArrow(LEFT, 5, 10, 5);
UI_make_axis_color(col, col2, 'Y');
- glColor3ubv((GLubyte *)col2);
+ immUniformColor3ubv(col2);
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
@@ -1788,7 +1955,8 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
}
}
- glPopMatrix();
+ immUnbindProgram();
+ GPU_matrix_pop();
}
}
@@ -1796,7 +1964,7 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
{
TransInfo *t = arg;
- glLineWidth(1.0);
+ GPU_line_width(1.0f);
drawConstraint(t);
drawPropCircle(C, t);
@@ -1805,6 +1973,9 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi
/* edge slide, vert slide */
drawEdgeSlide(t);
drawVertSlide(t);
+
+ /* Rotation */
+ drawDial3d(t);
}
/* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
@@ -1817,7 +1988,8 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
ED_region_visible_rect(ar, &rect);
- BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
+ const int font_id = BLF_default();
+ BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
yco = (rect.ymax - U.widget_unit);
@@ -1825,7 +1997,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
/* warning text (to clarify meaning of overlays)
* - original color was red to match the icon, but that clashes badly with a less nasty border
*/
- UI_ThemeColorShade(TH_TEXT_HI, -50);
+ unsigned char color[3];
+ UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
+ BLF_color3ubv(font_id, color);
#ifdef WITH_INTERNATIONAL
BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#else
@@ -1833,22 +2007,23 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
#endif
/* autokey recording icon... */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(true);
xco -= U.widget_unit;
yco -= (int)printable_size[1] / 2;
UI_icon_draw(xco, yco, ICON_REC);
- glDisable(GL_BLEND);
+ GPU_blend(false);
}
static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, void *arg)
{
TransInfo *t = arg;
Scene *scene = t->scene;
- Object *ob = OBACT;
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
/* draw autokeyframing hint in the corner
* - only draw if enabled (advanced users may be distracted/annoyed),
@@ -1923,7 +2098,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->proportional_fcurve = proportional;
else if (t->spacetype == SPACE_ACTION)
ts->proportional_action = proportional;
- else if (t->obedit)
+ else if (t->obedit_type != -1)
ts->proportional = proportional;
else if (t->options & CTX_MASK)
ts->proportional_mask = (proportional != PROP_EDIT_OFF);
@@ -1953,11 +2128,13 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if (t->spacetype == SPACE_VIEW3D) {
if ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
- !RNA_property_is_set(op->ptr, prop))
+ !RNA_property_is_set(op->ptr, prop) &&
+ (t->orientation.user != V3D_MANIP_CUSTOM_MATRIX))
{
- View3D *v3d = t->view;
-
- v3d->twmode = t->current_orientation;
+ t->scene->orientation_type = t->orientation.user;
+ BLI_assert(((t->scene->orientation_index_custom == -1) && (t->orientation.custom == NULL)) ||
+ (BKE_scene_transform_orientation_get_index(
+ t->scene, t->orientation.custom) == t->scene->orientation_index_custom));
}
}
}
@@ -1972,19 +2149,33 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_float_set_array(op->ptr, prop, t->axis);
}
+ if ((prop = RNA_struct_find_property(op->ptr, "axis_ortho"))) {
+ RNA_property_float_set_array(op->ptr, prop, t->axis_ortho);
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
RNA_property_boolean_set(op->ptr, prop, (t->flag & T_MIRROR) != 0);
}
if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
- /* constraint orientation can be global, event if user selects something else
- * so use the orientation in the constraint if set
- * */
- if (t->con.mode & CON_APPLY) {
- RNA_enum_set(op->ptr, "constraint_orientation", t->con.orientation);
+ /* constraint orientation can be global, even if user selects something else
+ * so use the orientation in the constraint if set */
+ short orientation = (t->con.mode & CON_APPLY) ? t->con.orientation : t->orientation.user;
+
+ if (orientation == V3D_MANIP_CUSTOM) {
+ const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
+ t->scene, t->orientation.custom);
+
+ /* Maybe we need a t->con.custom_orientation? Seems like it would always match t->orientation.custom. */
+ orientation = V3D_MANIP_CUSTOM + orientation_index_custom;
+ BLI_assert(orientation >= V3D_MANIP_CUSTOM);
}
- else {
- RNA_enum_set(op->ptr, "constraint_orientation", t->current_orientation);
+
+ RNA_float_set_array(op->ptr, "constraint_matrix", &t->spacemtx[0][0]);
+
+ /* Use 'constraint_matrix' instead. */
+ if (orientation != V3D_MANIP_CUSTOM_MATRIX) {
+ RNA_enum_set(op->ptr, "constraint_orientation", orientation);
}
if (t->con.mode & CON_APPLY) {
@@ -2008,19 +2199,26 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
{
const char *prop_id = NULL;
+ bool prop_state = true;
if (t->mode == TFM_SHRINKFATTEN) {
prop_id = "use_even_offset";
+ prop_state = false;
}
if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
-
- RNA_property_boolean_set(op->ptr, prop, (t->flag & T_ALT_TRANSFORM) != 0);
+ RNA_property_boolean_set(op->ptr, prop, ((t->flag & T_ALT_TRANSFORM) != 0) == prop_state);
}
}
if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
RNA_property_boolean_set(op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
}
+
+ if (t->mode == TFM_SHEAR) {
+ prop = RNA_struct_find_property(op->ptr, "shear_axis");
+ t->custom.mode.data = POINTER_FROM_INT(RNA_property_enum_get(op->ptr, prop));
+ RNA_property_enum_set(op->ptr, prop, POINTER_AS_INT(t->custom.mode.data));
+ }
}
/**
@@ -2039,6 +2237,12 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->state = TRANS_STARTING;
+ if ((prop = RNA_struct_find_property(op->ptr, "cursor_transform")) && RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ options |= CTX_CURSOR;
+ }
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "texture_space")) && RNA_property_is_set(op->ptr, prop)) {
if (RNA_property_boolean_get(op->ptr, prop)) {
options |= CTX_TEXTURE;
@@ -2059,7 +2263,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1;
// XXX Remove this when wm_operator_call_internal doesn't use window->eventstate (which can have type = 0)
- // For manipulator only, so assume LEFTMOUSE
+ // For gizmo only, so assume LEFTMOUSE
if (t->launch_event == 0) {
t->launch_event = LEFTMOUSE;
}
@@ -2073,36 +2277,54 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ helpline_poll, drawHelpline, t);
}
else if (t->spacetype == SPACE_IMAGE) {
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
//t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ helpline_poll, drawHelpline, t);
}
else if (t->spacetype == SPACE_CLIP) {
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ helpline_poll, drawHelpline, t);
}
else if (t->spacetype == SPACE_NODE) {
/*t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);*/
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ helpline_poll, drawHelpline, t);
}
else if (t->spacetype == SPACE_IPO) {
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
//t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ helpline_poll, drawHelpline, t);
}
else if (t->spacetype == SPACE_ACTION) {
t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
//t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C),
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ helpline_poll, drawHelpline, t);
}
createTransData(C, t); // make TransData structs from selection
- if (t->total == 0) {
+ if (t->data_len_all == 0) {
postTrans(C, t);
return 0;
}
@@ -2111,10 +2333,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* keymap for shortcut header prints */
t->keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
- /* Stupid code to have Ctrl-Click on manipulator work ok
+ /* Stupid code to have Ctrl-Click on gizmo work ok
*
* do this only for translation/rotation/resize due to only this
- * moded are available from manipulator and doing such check could
+ * moded are available from gizmo and doing such check could
* lead to keymap conflicts for other modes (see #31584)
*/
if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
@@ -2147,6 +2369,68 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculatePropRatio(t);
calculateCenter(t);
+ /* Overwrite initial values if operator supplied a non-null vector.
+ *
+ * Run before init functions so 'values_modal_offset' can be applied on mouse input.
+ */
+ BLI_assert(is_zero_v4(t->values_modal_offset));
+ if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
+ float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
+
+ if (RNA_property_array_check(prop)) {
+ RNA_float_get_array(op->ptr, "value", values);
+ }
+ else {
+ values[0] = RNA_float_get(op->ptr, "value");
+ }
+
+ copy_v4_v4(t->values, values);
+
+ if (t->flag & T_MODAL) {
+ copy_v4_v4(t->values_modal_offset, values);
+ t->redraw = TREDRAW_HARD;
+ }
+ else {
+ copy_v4_v4(t->auto_values, values);
+ t->flag |= T_AUTOVALUES;
+ }
+ }
+
+ /* Transformation axis from operator */
+ if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, t->axis);
+ normalize_v3(t->axis);
+ copy_v3_v3(t->axis_orig, t->axis);
+ }
+
+ if ((prop = RNA_struct_find_property(op->ptr, "axis_ortho")) && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, t->axis_ortho);
+ normalize_v3(t->axis_ortho);
+ }
+
+ /* Constraint init from operator */
+ if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) {
+ bool constraint_axis[3];
+
+ RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
+
+ if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
+ t->con.mode |= CON_APPLY;
+
+ if (constraint_axis[0]) {
+ t->con.mode |= CON_AXIS0;
+ }
+ if (constraint_axis[1]) {
+ t->con.mode |= CON_AXIS1;
+ }
+ if (constraint_axis[2]) {
+ t->con.mode |= CON_AXIS2;
+ }
+
+ setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
+ }
+ }
+
if (event) {
/* Initialize accurate transform to settings requested by keymap. */
bool use_accurate = false;
@@ -2175,6 +2459,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initToSphere(t);
break;
case TFM_SHEAR:
+ prop = RNA_struct_find_property(op->ptr, "shear_axis");
+ t->custom.mode.data = POINTER_FROM_INT(RNA_property_enum_get(op->ptr, prop));
initShear(t);
break;
case TFM_BEND:
@@ -2206,7 +2492,9 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
break;
case TFM_BONESIZE:
{ /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
- bArmature *arm = t->poseobj->data;
+ /* Note: we have to pick one, use the active object. */
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
+ bArmature *arm = tc->poseobj->data;
if (arm->drawtype == ARM_ENVELOPE) {
initBoneEnvelope(t);
t->mode = TFM_BONE_ENVELOPE_DIST;
@@ -2286,6 +2574,9 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
case TFM_SEQ_SLIDE:
initSeqSlide(t);
break;
+ case TFM_NORMAL_ROTATION:
+ initNormalRotation(t);
+ break;
}
if (t->state == TRANS_CANCEL) {
@@ -2293,55 +2584,39 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
return 0;
}
- /* Transformation axis from operator */
- if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) {
- RNA_property_float_get_array(op->ptr, prop, t->axis);
- normalize_v3(t->axis);
- copy_v3_v3(t->axis_orig, t->axis);
- }
+ if ((prop = RNA_struct_find_property(op->ptr, "preserve_clnor"))) {
+ if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
- /* Constraint init from operator */
- if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) {
- bool constraint_axis[3];
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ if ((((Mesh *)(tc->obedit->data))->flag & ME_AUTOSMOOTH)) {
+ BMEditMesh *em = NULL;// BKE_editmesh_from_object(t->obedit);
+ bool do_skip = false;
- RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
-
- if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
- t->con.mode |= CON_APPLY;
+ /* Currently only used for two of three most frequent transform ops, can include more ops.
+ * Note that scaling cannot be included here, non-uniform scaling will affect normals. */
+ if (ELEM(t->mode, TFM_TRANSLATION, TFM_ROTATION)) {
+ if (em->bm->totvertsel == em->bm->totvert) {
+ /* No need to invalidate if whole mesh is selected. */
+ do_skip = true;
+ }
+ }
- if (constraint_axis[0]) {
- t->con.mode |= CON_AXIS0;
- }
- if (constraint_axis[1]) {
- t->con.mode |= CON_AXIS1;
- }
- if (constraint_axis[2]) {
- t->con.mode |= CON_AXIS2;
+ if (t->flag & T_MODAL) {
+ RNA_property_boolean_set(op->ptr, prop, false);
+ }
+ else if (!do_skip) {
+ const bool preserve_clnor = RNA_property_boolean_get(op->ptr, prop);
+ if (preserve_clnor) {
+ BKE_editmesh_lnorspace_update(em);
+ t->flag |= T_CLNOR_REBUILD;
+ }
+ BM_lnorspace_invalidate(em->bm, true);
+ }
+ }
}
-
- setUserConstraint(t, t->current_orientation, t->con.mode, "%s");
}
}
- /* overwrite initial values if operator supplied a non-null vector
- *
- * keep last so we can apply the constraints space.
- */
- if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
- float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
-
- if (RNA_property_array_check(prop)) {
- RNA_float_get_array(op->ptr, "value", values);
- }
- else {
- values[0] = RNA_float_get(op->ptr, "value");
- }
-
- copy_v4_v4(t->values, values);
- copy_v4_v4(t->auto_values, values);
- t->flag |= T_AUTOVALUES;
- }
-
t->context = NULL;
return 1;
@@ -2402,6 +2677,12 @@ int transformEnd(bContext *C, TransInfo *t)
restoreTransObjects(t); // calls recalcData()
}
else {
+ if (t->flag & T_CLNOR_REBUILD) {
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BM_lnorspace_rebuild(em->bm, true);
+ }
+ }
exit_code = OPERATOR_FINISHED;
}
@@ -2604,7 +2885,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
}
/* get constraint targets if needed */
- BKE_constraint_targets_for_solving_get(con, &cob, &targets, ctime);
+ BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
/* do constraint */
cti->evaluate_constraint(con, &cob, &targets);
@@ -2811,6 +3092,7 @@ static void constraintSizeLim(TransInfo *t, TransData *td)
* \{ */
struct BendCustomData {
+ /* All values are in global space. */
float warp_sta[3];
float warp_end[3];
@@ -2838,8 +3120,8 @@ static void initBend(TransInfo *t)
t->idx_max = 1;
t->num.idx_max = 1;
t->snap[0] = 0.0f;
- t->snap[1] = DEG2RAD(5.0);
- t->snap[2] = DEG2RAD(1.0);
+ t->snap[1] = SNAP_INCREMENTAL_ANGLE;
+ t->snap[2] = t->snap[1] * 0.2;
copy_v3_fl(t->num.val_inc, t->snap[1]);
t->num.unit_sys = t->scene->unit.system;
@@ -2851,23 +3133,19 @@ static void initBend(TransInfo *t)
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
- calculateCenterCursor(t, t->center);
+ calculateCenterCursor(t, t->center_global);
}
- calculateCenterGlobal(t, t->center, t->center_global);
+ calculateCenterLocal(t, t->center_global);
t->val = 0.0f;
data = MEM_callocN(sizeof(*data), __func__);
- curs = ED_view3d_cursor3d_get(t->scene, t->view);
+ curs = t->scene->cursor.location;
copy_v3_v3(data->warp_sta, curs);
ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end);
copy_v3_v3(data->warp_nor, t->viewinv[2]);
- if (t->flag & T_EDIT) {
- sub_v3_v3(data->warp_sta, t->obedit->obmat[3]);
- sub_v3_v3(data->warp_end, t->obedit->obmat[3]);
- }
normalize_v3(data->warp_nor);
/* tangent */
@@ -2894,10 +3172,9 @@ static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event)
static void Bend(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float vec[3];
- float pivot[3];
- float warp_end_radius[3];
+ float pivot_global[3];
+ float warp_end_radius_global[3];
int i;
char str[UI_MAX_DRAW_STR];
const struct BendCustomData *data = t->custom.mode.data;
@@ -2916,7 +3193,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
#else
/* hrmf, snapping radius is using 'angle' steps, need to convert to something else
* this isnt essential but nicer to give reasonable snapping values for radius */
- if (t->tsnap.mode == SCE_SNAP_MODE_INCREMENT) {
+ if (t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) {
const float radius_snap = 0.1f;
const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap;
values.scale *= snap_hack;
@@ -2952,69 +3229,92 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
values.scale *= data->warp_init_dist;
/* calc 'data->warp_end' from 'data->warp_end_init' */
- copy_v3_v3(warp_end_radius, data->warp_end);
- dist_ensure_v3_v3fl(warp_end_radius, data->warp_sta, values.scale);
+ copy_v3_v3(warp_end_radius_global, data->warp_end);
+ dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale);
/* done */
/* calculate pivot */
- copy_v3_v3(pivot, data->warp_sta);
+ copy_v3_v3(pivot_global, data->warp_sta);
if (values.angle > 0.0f) {
- madd_v3_v3fl(pivot, data->warp_tan, -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
+ madd_v3_v3fl(pivot_global, data->warp_tan, -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
}
else {
- madd_v3_v3fl(pivot, data->warp_tan, +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
+ madd_v3_v3fl(pivot_global, data->warp_tan, +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
}
- for (i = 0; i < t->total; i++, td++) {
- float mat[3][3];
- float delta[3];
- float fac, fac_scaled;
-
- if (td->flag & TD_NOACTION)
- break;
+ /* TODO(campbell): xform, compensate object center. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
- if (td->flag & TD_SKIP)
- continue;
+ float warp_sta_local[3];
+ float warp_end_local[3];
+ float warp_end_radius_local[3];
+ float pivot_local[3];
- if (UNLIKELY(values.angle == 0.0f)) {
- copy_v3_v3(td->loc, td->iloc);
- continue;
+ if (tc->use_local_mat) {
+ sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->mat[3]);
+ sub_v3_v3v3(warp_end_local, data->warp_end, tc->mat[3]);
+ sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]);
+ sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]);
+ }
+ else {
+ copy_v3_v3(warp_sta_local, data->warp_sta);
+ copy_v3_v3(warp_end_local, data->warp_end);
+ copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
+ copy_v3_v3(pivot_local, pivot_global);
}
- copy_v3_v3(vec, td->iloc);
- mul_m3_v3(td->mtx, vec);
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float mat[3][3];
+ float delta[3];
+ float fac, fac_scaled;
- fac = line_point_factor_v3(vec, data->warp_sta, warp_end_radius);
- if (is_clamp) {
- CLAMP(fac, 0.0f, 1.0f);
- }
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if (td->flag & TD_SKIP)
+ continue;
- fac_scaled = fac * td->factor;
- axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
- interp_v3_v3v3(delta, data->warp_sta, warp_end_radius, fac_scaled);
- sub_v3_v3(delta, data->warp_sta);
+ if (UNLIKELY(values.angle == 0.0f)) {
+ copy_v3_v3(td->loc, td->iloc);
+ continue;
+ }
- /* delta is subtracted, rotation adds back this offset */
- sub_v3_v3(vec, delta);
+ copy_v3_v3(vec, td->iloc);
+ mul_m3_v3(td->mtx, vec);
- sub_v3_v3(vec, pivot);
- mul_m3_v3(mat, vec);
- add_v3_v3(vec, pivot);
+ fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
+ if (is_clamp) {
+ CLAMP(fac, 0.0f, 1.0f);
+ }
- mul_m3_v3(td->smtx, vec);
+ fac_scaled = fac * td->factor;
+ axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
+ interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
+ sub_v3_v3(delta, warp_sta_local);
- /* rotation */
- if ((t->flag & T_POINTS) == 0) {
- ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
- }
+ /* delta is subtracted, rotation adds back this offset */
+ sub_v3_v3(vec, delta);
+
+ sub_v3_v3(vec, pivot_local);
+ mul_m3_v3(mat, vec);
+ add_v3_v3(vec, pivot_local);
- /* location */
- copy_v3_v3(td->loc, vec);
+ mul_m3_v3(td->smtx, vec);
+
+ /* rotation */
+ if ((t->flag & T_POINTS) == 0) {
+ ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS);
+ }
+
+ /* location */
+ copy_v3_v3(td->loc, vec);
+ }
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -3025,13 +3325,42 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
/** \name Transform Shear
* \{ */
+static void initShear_mouseInputMode(TransInfo *t)
+{
+ float dir[3];
+
+ if (t->custom.mode.data == NULL) {
+ copy_v3_v3(dir, t->axis_ortho);
+ }
+ else {
+ cross_v3_v3v3(dir, t->axis_ortho, t->axis);
+ }
+
+ mul_mat3_m4_v3(t->viewmat, dir);
+ if (normalize_v2(dir) == 0.0f) {
+ dir[0] = 1.0f;
+ }
+ setCustomPointsFromDirection(t, &t->mouse, dir);
+
+ initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
+}
+
static void initShear(TransInfo *t)
{
t->mode = TFM_SHEAR;
t->transform = applyShear;
t->handleEvent = handleEventShear;
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
+ if (is_zero_v3(t->axis)) {
+ negate_v3_v3(t->axis, t->viewinv[2]);
+ normalize_v3(t->axis);
+ }
+ if (is_zero_v3(t->axis_ortho)) {
+ copy_v3_v3(t->axis_ortho, t->viewinv[0]);
+ normalize_v3(t->axis_ortho);
+ }
+
+ initShear_mouseInputMode(t);
t->idx_max = 0;
t->num.idx_max = 0;
@@ -3053,25 +3382,24 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
/* Use custom.mode.data pointer to signal Shear direction */
if (t->custom.mode.data == NULL) {
- initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO);
t->custom.mode.data = (void *)1;
}
else {
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
t->custom.mode.data = NULL;
}
+ initShear_mouseInputMode(t);
status = TREDRAW_HARD;
}
else if (event->type == XKEY && event->val == KM_PRESS) {
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
t->custom.mode.data = NULL;
+ initShear_mouseInputMode(t);
status = TREDRAW_HARD;
}
else if (event->type == YKEY && event->val == KM_PRESS) {
- initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_RATIO);
t->custom.mode.data = (void *)1;
+ initShear_mouseInputMode(t);
status = TREDRAW_HARD;
}
@@ -3082,17 +3410,13 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float vec[3];
- float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
+ float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3];
float value;
int i;
char str[UI_MAX_DRAW_STR];
const bool is_local_center = transdata_check_local_center(t, t->around);
- copy_m3_m4(persmat, t->viewmat);
- invert_m3_m3(persinv, persmat);
-
value = t->values[0];
snapGridIncrement(t, &value);
@@ -3122,51 +3446,56 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
else
smat[0][1] = value;
- mul_m3_m3m3(tmat, smat, persmat);
- mul_m3_m3m3(totmat, persinv, tmat);
+ copy_v3_v3(axismat_inv[0], t->axis_ortho);
+ copy_v3_v3(axismat_inv[2], t->axis);
+ cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]);
+ invert_m3_m3(axismat, axismat_inv);
- for (i = 0; i < t->total; i++, td++) {
- const float *center, *co;
+ mul_m3_series(totmat, axismat_inv, smat, axismat);
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ const float *center, *co;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_NOACTION)
+ break;
- if (t->obedit) {
- float mat3[3][3];
- mul_m3_m3m3(mat3, totmat, td->mtx);
- mul_m3_m3m3(tmat, td->smtx, mat3);
- }
- else {
- copy_m3_m3(tmat, totmat);
- }
+ if (td->flag & TD_SKIP)
+ continue;
- if (is_local_center) {
- center = td->center;
- co = td->loc;
- }
- else {
- center = t->center;
- co = td->center;
- }
+ if (t->flag & T_EDIT) {
+ mul_m3_series(tmat, td->smtx, totmat, td->mtx);
+ }
+ else {
+ copy_m3_m3(tmat, totmat);
+ }
+
+ if (is_local_center) {
+ center = td->center;
+ co = td->loc;
+ }
+ else {
+ center = tc->center_local;
+ co = td->center;
+ }
- sub_v3_v3v3(vec, co, center);
+ sub_v3_v3v3(vec, co, center);
- mul_m3_v3(tmat, vec);
+ mul_m3_v3(tmat, vec);
- add_v3_v3(vec, center);
- sub_v3_v3(vec, co);
+ add_v3_v3(vec, center);
+ sub_v3_v3(vec, co);
- mul_v3_fl(vec, td->factor);
+ mul_v3_fl(vec, td->factor);
- add_v3_v3v3(td->loc, td->iloc, vec);
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -3189,7 +3518,7 @@ static void initResize(TransInfo *t)
t->num.val_flag[1] |= NUM_NULL_ONE;
t->num.val_flag[2] |= NUM_NULL_ONE;
t->num.flag |= NUM_AFFECT_ALL;
- if (!t->obedit) {
+ if ((t->flag & T_EDIT) == 0) {
t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
@@ -3273,7 +3602,7 @@ static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
if (dot_v3v3(rmat[2], smat[2]) < 0.0f) size[2] = -size[2];
}
-static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
+static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
{
float tmat[3][3], smat[3][3], center[3];
float vec[3];
@@ -3287,7 +3616,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
}
if (t->con.applySize) {
- t->con.applySize(t, td, tmat);
+ t->con.applySize(t, tc, td, tmat);
}
/* local constraint shouldn't alter center */
@@ -3299,14 +3628,15 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
copy_v3_v3(center, td->center);
}
else {
- copy_v3_v3(center, t->center);
+ copy_v3_v3(center, tc->center_local);
}
}
else {
- copy_v3_v3(center, t->center);
+ copy_v3_v3(center, tc->center_local);
}
- if (td->ext) {
+ /* Size checked needed since the 3D cursor only uses rotation fields. */
+ if (td->ext && td->ext->size) {
float fsize[3];
if (t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
@@ -3360,7 +3690,25 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
else
sub_v3_v3(vec, td->center);
- mul_v3_fl(vec, td->factor);
+ /* grease pencil falloff */
+ if (t->options & CTX_GPENCIL_STROKES) {
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
+
+ /* scale stroke thickness */
+ if (td->val) {
+ snapGridIncrement(t, t->values);
+ applyNumInput(&t->num, t->values);
+
+ float ratio = t->values[0];
+ *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff;
+ CLAMP_MIN(*td->val, 0.001f);
+ }
+
+ }
+ else {
+ mul_v3_fl(vec, td->factor);
+ }
if (t->flag & (T_OBJECT | T_POSE)) {
mul_m3_v3(td->smtx, vec);
@@ -3374,9 +3722,8 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
constraintTransLim(t, td);
}
-static void applyResize(TransInfo *t, const int mval[2])
+static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td;
float mat[3][3];
int i;
char str[UI_MAX_DRAW_STR];
@@ -3385,15 +3732,7 @@ static void applyResize(TransInfo *t, const int mval[2])
copy_v3_v3(t->values, t->auto_values);
}
else {
- float ratio;
-
- /* for manipulator, center handle, the scaling can't be done relative to center */
- if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
- ratio = 1.0f - ((t->mouse.imval[0] - mval[0]) + (t->mouse.imval[1] - mval[1])) / 100.0f;
- }
- else {
- ratio = t->values[0];
- }
+ float ratio = t->values[0];
copy_v3_fl(t->values, ratio);
@@ -3409,21 +3748,24 @@ static void applyResize(TransInfo *t, const int mval[2])
size_to_mat3(mat, t->values);
if (t->con.applySize) {
- t->con.applySize(t, NULL, mat);
+ t->con.applySize(t, NULL, NULL, mat);
}
- copy_m3_m3(t->mat, mat); // used in manipulator
+ copy_m3_m3(t->mat, mat); // used in gizmo
headerResize(t, t->values, str);
- for (i = 0, td = t->data; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- ElementResize(t, td, mat);
+ ElementResize(t, tc, td, mat);
+ }
}
/* evil hack - redo resize if cliping needed */
@@ -3431,23 +3773,27 @@ static void applyResize(TransInfo *t, const int mval[2])
size_to_mat3(mat, t->values);
if (t->con.applySize)
- t->con.applySize(t, NULL, mat);
+ t->con.applySize(t, NULL, NULL, mat);
- for (i = 0, td = t->data; i < t->total; i++, td++)
- ElementResize(t, td, mat);
- /* In proportional edit it can happen that */
- /* vertices in the radius of the brush end */
- /* outside the clipping area */
- /* XXX HACK - dg */
- if (t->flag & T_PROP_EDIT_ALL) {
- clipUVData(t);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++)
+ ElementResize(t, tc, td, mat);
+
+ /* In proportional edit it can happen that */
+ /* vertices in the radius of the brush end */
+ /* outside the clipping area */
+ /* XXX HACK - dg */
+ if (t->flag & T_PROP_EDIT_ALL) {
+ clipUVData(t);
+ }
}
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -3470,7 +3816,7 @@ static void initSkinResize(TransInfo *t)
t->num.val_flag[1] |= NUM_NULL_ONE;
t->num.val_flag[2] |= NUM_NULL_ONE;
t->num.flag |= NUM_AFFECT_ALL;
- if (!t->obedit) {
+ if ((t->flag & T_EDIT) == 0) {
t->flag |= T_NO_ZERO;
#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
@@ -3494,7 +3840,6 @@ static void initSkinResize(TransInfo *t)
static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td;
float size[3], mat[3][3];
int i;
char str[UI_MAX_DRAW_STR];
@@ -3519,36 +3864,39 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
headerResize(t, size, str);
- for (i = 0, td = t->data; i < t->total; i++, td++) {
- float tmat[3][3], smat[3][3];
- float fsize[3];
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float tmat[3][3], smat[3][3];
+ float fsize[3];
- if (td->flag & TD_NOACTION)
- break;
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (t->flag & T_EDIT) {
- mul_m3_m3m3(smat, mat, td->mtx);
- mul_m3_m3m3(tmat, td->smtx, smat);
- }
- else {
- copy_m3_m3(tmat, mat);
- }
+ if (t->flag & T_EDIT) {
+ mul_m3_m3m3(smat, mat, td->mtx);
+ mul_m3_m3m3(tmat, td->smtx, smat);
+ }
+ else {
+ copy_m3_m3(tmat, mat);
+ }
- if (t->con.applySize) {
- t->con.applySize(t, NULL, tmat);
- }
+ if (t->con.applySize) {
+ t->con.applySize(t, NULL, NULL, tmat);
+ }
- mat3_to_size(fsize, tmat);
- td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
- td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
+ mat3_to_size(fsize, tmat);
+ td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
+ td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
+ }
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -3561,7 +3909,6 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
static void initToSphere(TransInfo *t)
{
- TransData *td = t->data;
int i;
t->mode = TFM_TOSPHERE;
@@ -3583,11 +3930,14 @@ static void initToSphere(TransInfo *t)
t->flag |= T_NO_CONSTRAINT;
// Calculate average radius
- for (i = 0; i < t->total; i++, td++) {
- t->val += len_v3v3(t->center, td->iloc);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ t->val += len_v3v3(tc->center_local, td->iloc);
+ }
}
- t->val /= (float)t->total;
+ t->val /= (float)t->data_len_all;
}
static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
@@ -3596,7 +3946,6 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
float ratio, radius;
int i;
char str[UI_MAX_DRAW_STR];
- TransData *td = t->data;
ratio = t->values[0];
@@ -3621,30 +3970,31 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
}
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float tratio;
+ if (td->flag & TD_NOACTION)
+ break;
- for (i = 0; i < t->total; i++, td++) {
- float tratio;
- if (td->flag & TD_NOACTION)
- break;
-
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- sub_v3_v3v3(vec, td->iloc, t->center);
+ sub_v3_v3v3(vec, td->iloc, tc->center_local);
- radius = normalize_v3(vec);
+ radius = normalize_v3(vec);
- tratio = ratio * td->factor;
+ tratio = ratio * td->factor;
- mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio);
+ mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio);
- add_v3_v3v3(td->loc, t->center, vec);
+ add_v3_v3v3(td->loc, tc->center_local, vec);
+ }
}
-
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -3658,7 +4008,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
static void postInputRotation(TransInfo *t, float values[3])
{
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
- t->con.applyRot(t, NULL, t->axis, values);
+ t->con.applyRot(t, NULL, NULL, t->axis, values);
}
}
@@ -3697,13 +4047,35 @@ static void initRotation(TransInfo *t)
copy_v3_v3(t->axis_orig, t->axis);
}
+/* Used by Transform Rotation and Transform Normal Rotation */
+static void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
+{
+ size_t ofs = 0;
+
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
+ }
+ else {
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_("Rot: %.2f%s %s"),
+ RAD2DEGF(final), t->con.text, t->proptext);
+ }
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
+ }
+}
+
/**
* Applies values of rotation to `td->loc` and `td->ext->quat`
* based on a rotation matrix (mat) and a pivot (center).
*
* Protected axis and other transform settings are taken into account.
*/
-static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], const float *center)
+static void ElementRotation_ex(TransInfo *t, TransDataContainer *tc, 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];
@@ -3712,6 +4084,20 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
mul_m3_m3m3(totmat, mat, td->mtx);
mul_m3_m3m3(smat, td->smtx, totmat);
+ /* apply gpencil falloff */
+ if (t->options & CTX_GPENCIL_STROKES) {
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ float sx = smat[0][0];
+ float sy = smat[1][1];
+ float sz = smat[2][2];
+
+ mul_m3_fl(smat, gps->runtime.multi_frame_falloff);
+ /* fix scale */
+ smat[0][0] = sx;
+ smat[1][1] = sy;
+ smat[2][2] = sz;
+ }
+
sub_v3_v3v3(vec, td->iloc, center);
mul_m3_v3(smat, vec);
@@ -3747,18 +4133,14 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
* has been computed, it has to be converted back into the bone's space.
*/
else if (t->flag & T_POSE) {
- float pmtx[3][3], imtx[3][3];
-
// Extract and invert armature object matrix
- copy_m3_m4(pmtx, t->poseobj->obmat);
- invert_m3_m3(imtx, pmtx);
if ((td->flag & TD_NO_LOC) == 0) {
sub_v3_v3v3(vec, td->center, center);
- mul_m3_v3(pmtx, vec); // To Global space
+ mul_m3_v3(tc->mat3, vec); // To Global space
mul_m3_v3(mat, vec); // Applying rotation
- mul_m3_v3(imtx, vec); // To Local space
+ mul_m3_v3(tc->imat3, vec); // To Local space
add_v3_v3(vec, center);
/* vec now is the location where the object has to be */
@@ -3770,11 +4152,11 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
/* do nothing */
}
else if (td->flag & TD_PBONE_LOCAL_MTX_C) {
- mul_m3_v3(pmtx, vec); // To Global space
+ mul_m3_v3(tc->mat3, vec); // To Global space
mul_m3_v3(td->ext->l_smtx, vec); // To Pose space (Local Location)
}
else {
- mul_m3_v3(pmtx, vec); // To Global space
+ mul_m3_v3(tc->mat3, vec); // To Global space
mul_m3_v3(td->smtx, vec); // To Pose space
}
@@ -3916,7 +4298,7 @@ static void ElementRotation_ex(TransInfo *t, TransData *td, float mat[3][3], con
}
}
-static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around)
+static void ElementRotation(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around)
{
const float *center;
@@ -3925,44 +4307,45 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const
center = td->center;
}
else {
- center = t->center;
+ center = tc->center_local;
}
- ElementRotation_ex(t, td, mat, center);
+ ElementRotation_ex(t, tc, td, mat, center);
}
static void applyRotationValue(TransInfo *t, float angle, float axis[3])
{
- TransData *td = t->data;
float mat[3][3];
int i;
axis_angle_normalized_to_mat3(mat, axis, angle);
- for (i = 0; i < t->total; i++, td++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (t->con.applyRot) {
- t->con.applyRot(t, td, axis, NULL);
- axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
- }
- else if (t->flag & T_PROP_EDIT) {
- axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
- }
+ if (t->con.applyRot) {
+ t->con.applyRot(t, tc, td, axis, NULL);
+ axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
+ }
+ else if (t->flag & T_PROP_EDIT) {
+ axis_angle_normalized_to_mat3(mat, axis, angle * td->factor);
+ }
- ElementRotation(t, td, mat, t->around);
+ ElementRotation(t, tc, td, mat, t->around);
+ }
}
}
static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
- size_t ofs = 0;
float final;
@@ -3971,7 +4354,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
snapGridIncrement(t, &final);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
- t->con.applyRot(t, NULL, t->axis, NULL);
+ t->con.applyRot(t, NULL, NULL, t->axis, NULL);
}
else {
/* reset axis if constraint is not set */
@@ -3985,27 +4368,13 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
t->values[0] = final;
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
- }
- else {
- ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_("Rot: %.2f%s %s"),
- RAD2DEGF(final), t->con.text, t->proptext);
- }
-
- if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" Proportional size: %.2f"), t->prop_size);
- }
+ headerRotation(t, str, final);
applyRotationValue(t, final, t->axis);
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -4040,7 +4409,6 @@ static void initTrackball(TransInfo *t)
static void applyTrackballValue(TransInfo *t, const float axis1[3], const float axis2[3], float angles[2])
{
- TransData *td = t->data;
float mat[3][3];
float axis[3];
float angle;
@@ -4051,18 +4419,21 @@ static void applyTrackballValue(TransInfo *t, const float axis1[3], const float
angle = normalize_v3(axis);
axis_angle_normalized_to_mat3(mat, axis, angle);
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (t->flag & T_PROP_EDIT) {
- axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
- }
+ if (t->flag & T_PROP_EDIT) {
+ axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
+ }
- ElementRotation(t, td, mat, t->around);
+ ElementRotation(t, tc, td, mat, t->around);
+ }
}
}
@@ -4113,19 +4484,140 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
mul_m3_m3m3(mat, smat, totmat);
// TRANSFORM_FIX_ME
- //copy_m3_m3(t->mat, mat); // used in manipulator
+ //copy_m3_m3(t->mat, mat); // used in gizmo
#endif
applyTrackballValue(t, axis1, axis2, phi);
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
/* -------------------------------------------------------------------- */
+/* Transform (Normal Rotation) */
+
+/** \name Transform Normal Rotation
+* \{ */
+
+static void storeCustomLNorValue(TransDataContainer *tc, BMesh *bm)
+{
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm);
+ // BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ tc->custom.mode.data = lnors_ed_arr;
+ tc->custom.mode.free_cb = freeCustomNormalArray;
+}
+
+void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
+{
+ BMLoopNorEditDataArray *lnors_ed_arr = custom_data->data;
+
+ if (t->state == TRANS_CANCEL) {
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { /* Restore custom loop normal on cancel */
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->niloc, lnor_ed->clnors_data);
+ }
+ }
+
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+
+ tc->custom.mode.data = NULL;
+ tc->custom.mode.free_cb = NULL;
+}
+
+static void initNormalRotation(TransInfo *t)
+{
+ t->mode = TFM_NORMAL_ROTATION;
+ t->transform = applyNormalRotation;
+
+ setInputPostFct(&t->mouse, postInputRotation);
+ initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = DEG2RAD(5.0);
+ t->snap[2] = DEG2RAD(1.0);
+
+ copy_v3_fl(t->num.val_inc, t->snap[2]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+ t->num.unit_type[0] = B_UNIT_ROTATION;
+
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ BKE_editmesh_lnorspace_update(em);
+
+ storeCustomLNorValue(tc, bm);
+ }
+
+ negate_v3_v3(t->axis, t->viewinv[2]);
+ normalize_v3(t->axis);
+
+ copy_v3_v3(t->axis_orig, t->axis);
+}
+
+/* Works by getting custom normal from clnor_data, transform, then store */
+static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
+{
+ char str[UI_MAX_DRAW_STR];
+
+ if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
+ t->con.applyRot(t, NULL, NULL, t->axis, NULL);
+ }
+ else {
+ /* reset axis if constraint is not set */
+ copy_v3_v3(t->axis, t->axis_orig);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ BMLoopNorEditDataArray *lnors_ed_arr = tc->custom.mode.data;
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ float axis[3];
+ float mat[3][3];
+ float angle = t->values[0];
+ copy_v3_v3(axis, t->axis);
+
+ snapGridIncrement(t, &angle);
+
+ applySnapping(t, &angle);
+
+ applyNumInput(&t->num, &angle);
+
+ headerRotation(t, str, angle);
+
+ axis_angle_normalized_to_mat3(mat, axis, angle);
+
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ mul_v3_m3v3(lnor_ed->nloc, mat, lnor_ed->niloc);
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->sa, str);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
/* Transform (Translation) */
static void initSnapSpatial(TransInfo *t, float r_snap[3])
@@ -4134,8 +4626,9 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3])
RegionView3D *rv3d = t->ar->regiondata;
if (rv3d) {
+ View3D *v3d = t->sa->spacedata.first;
r_snap[0] = 0.0f;
- r_snap[1] = rv3d->gridview * 1.0f;
+ r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f;
r_snap[2] = r_snap[1] * 0.1f;
}
}
@@ -4225,12 +4718,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
dist = len_v3(vec);
if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
- const bool do_split = (t->scene->unit.flag & USER_UNIT_OPT_SPLIT) != 0;
int i;
for (i = 0; i < 3; i++) {
- bUnit_AsString(&tvec[NUM_STR_REP_LEN * i], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length,
- 4, t->scene->unit.system, B_UNIT_LENGTH, do_split, true);
+ bUnit_AsString2(
+ &tvec[NUM_STR_REP_LEN * i], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length,
+ 4, B_UNIT_LENGTH, &t->scene->unit, true);
}
}
else {
@@ -4241,9 +4734,9 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
}
if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
- const bool do_split = (t->scene->unit.flag & USER_UNIT_OPT_SPLIT) != 0;
- bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system,
- B_UNIT_LENGTH, do_split, false);
+ bUnit_AsString2(
+ distvec, sizeof(distvec), dist * t->scene->unit.scale_length,
+ 4, B_UNIT_LENGTH, &t->scene->unit, false);
}
else if (dist > 1e10f || dist < -1e10f) {
/* prevent string buffer overflow */
@@ -4317,81 +4810,97 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
static void applyTranslationValue(TransInfo *t, const float vec[3])
{
- TransData *td = t->data;
+ const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT);
float tvec[3];
/* The ideal would be "apply_snap_align_rotation" only when a snap point is found
* so, maybe inside this function is not the best place to apply this rotation.
* but you need "handle snapping rotation before doing the translation" (really?) */
- const bool apply_snap_align_rotation = usingSnappingNormal(t);// && (t->tsnap.status & POINT_INIT);
- float pivot[3];
- if (apply_snap_align_rotation) {
- copy_v3_v3(pivot, t->tsnap.snapTarget);
- /* The pivot has to be in local-space (see T49494) */
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->imat, pivot);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ float pivot[3];
+ if (apply_snap_align_rotation) {
+ copy_v3_v3(pivot, t->tsnap.snapTarget);
+ /* The pivot has to be in local-space (see T49494) */
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->imat, pivot);
+ }
}
- }
- for (int i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- float rotate_offset[3] = {0};
- bool use_rotate_offset = false;
+ float rotate_offset[3] = {0};
+ bool use_rotate_offset = false;
- /* handle snapping rotation before doing the translation */
- if (apply_snap_align_rotation) {
- float mat[3][3];
+ /* handle snapping rotation before doing the translation */
+ if (apply_snap_align_rotation) {
+ float mat[3][3];
- if (validSnappingNormal(t)) {
- const float *original_normal;
+ if (validSnappingNormal(t)) {
+ const float *original_normal;
- /* In pose mode, we want to align normals with Y axis of bones... */
- if (t->flag & T_POSE)
- original_normal = td->axismtx[1];
- else
- original_normal = td->axismtx[2];
+ /* In pose mode, we want to align normals with Y axis of bones... */
+ if (t->flag & T_POSE)
+ original_normal = td->axismtx[1];
+ else
+ original_normal = td->axismtx[2];
+
+ rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
+ }
+ else {
+ unit_m3(mat);
+ }
+
+ ElementRotation_ex(t, tc, td, mat, pivot);
- rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
+ 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, tc, td, vec, tvec, pvec);
}
else {
- unit_m3(mat);
+ copy_v3_v3(tvec, vec);
}
- ElementRotation_ex(t, td, mat, pivot);
-
- if (td->loc) {
- use_rotate_offset = true;
- sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
+ if (use_rotate_offset) {
+ add_v3_v3(tvec, rotate_offset);
}
- }
-
- if (t->con.applyVec) {
- float pvec[3];
- t->con.applyVec(t, td, vec, tvec, pvec);
- }
- else {
- copy_v3_v3(tvec, vec);
- }
- if (use_rotate_offset) {
- add_v3_v3(tvec, rotate_offset);
- }
+ mul_m3_v3(td->smtx, tvec);
- mul_m3_v3(td->smtx, tvec);
- mul_v3_fl(tvec, td->factor);
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* grease pencil multiframe falloff */
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ if (gps != NULL) {
+ mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff);
+ }
+ else {
+ mul_v3_fl(tvec, td->factor);
+ }
+ }
+ else {
+ /* proportional editing falloff */
+ mul_v3_fl(tvec, td->factor);
+ }
- protectedTransBits(td->protectflag, tvec);
+ protectedTransBits(td->protectflag, tvec);
- if (td->loc)
- add_v3_v3v3(td->loc, td->iloc, tvec);
+ if (td->loc)
+ add_v3_v3v3(td->loc, td->iloc, tvec);
- constraintTransLim(t, td);
+ constraintTransLim(t, td);
+ }
}
}
@@ -4417,7 +4926,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
- t->con.applyVec(t, NULL, t->values, value_final, pvec);
+ t->con.applyVec(t, NULL, NULL, t->values, value_final, pvec);
headerTranslation(t, pvec, str);
/* only so we have re-usable value with redo, see T46741. */
@@ -4447,7 +4956,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -4461,7 +4970,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
static void initShrinkFatten(TransInfo *t)
{
// If not in mesh edit mode, fallback to Resize
- if (t->obedit == NULL || t->obedit->type != OB_MESH) {
+ if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) {
initResize(t);
}
else {
@@ -4491,7 +5000,6 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
int i;
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
- TransData *td = t->data;
distance = -t->values[0];
@@ -4525,29 +5033,32 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
}
}
BLI_snprintf(str + ofs, sizeof(str) - ofs, IFACE_(" or Alt) Even Thickness %s"),
- WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
+ WM_bool_as_string((t->flag & T_ALT_TRANSFORM) == 0));
/* done with header string */
- for (i = 0; i < t->total; i++, td++) {
- float tdistance; /* temp dist */
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float tdistance; /* temp dist */
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- /* get the final offset */
- tdistance = distance * td->factor;
- if (td->ext && (t->flag & T_ALT_TRANSFORM)) {
- tdistance *= td->ext->isize[0]; /* shell factor */
- }
+ /* get the final offset */
+ tdistance = distance * td->factor;
+ if (td->ext && (t->flag & T_ALT_TRANSFORM) == 0) {
+ tdistance *= td->ext->isize[0]; /* shell factor */
+ }
- madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
+ madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
+ }
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -4582,7 +5093,6 @@ static void initTilt(TransInfo *t)
static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
int i;
char str[UI_MAX_DRAW_STR];
@@ -4610,21 +5120,24 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
}
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->val) {
- *td->val = td->ival + final * td->factor;
+ if (td->val) {
+ *td->val = td->ival + final * td->factor;
+ }
}
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -4662,7 +5175,6 @@ static void initCurveShrinkFatten(TransInfo *t)
static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float ratio;
int i;
char str[UI_MAX_DRAW_STR];
@@ -4686,24 +5198,27 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->val) {
- *td->val = td->ival * ratio;
- /* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- if (*td->val <= 0.0f) *td->val = 0.001f;
+ if (td->val) {
+ *td->val = td->ival * ratio;
+ /* apply PET */
+ *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ if (*td->val <= 0.0f) *td->val = 0.001f;
+ }
}
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -4741,7 +5256,6 @@ static void initMaskShrinkFatten(TransInfo *t)
static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td;
float ratio;
int i;
bool initial_feather = false;
@@ -4770,41 +5284,47 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (ratio > 1.0f) {
initial_feather = true;
- for (td = t->data, i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->ival >= 0.001f)
- initial_feather = false;
+ if (td->ival >= 0.001f)
+ initial_feather = false;
+ }
}
}
/* apply shrink/fatten */
- for (td = t->data, i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (td = tc->data, i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->val) {
- if (initial_feather)
- *td->val = td->ival + (ratio - 1.0f) * 0.01f;
- else
- *td->val = td->ival * ratio;
+ if (td->val) {
+ if (initial_feather)
+ *td->val = td->ival + (ratio - 1.0f) * 0.01f;
+ else
+ *td->val = td->ival * ratio;
- /* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- if (*td->val <= 0.0f) *td->val = 0.001f;
+ /* apply PET */
+ *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ if (*td->val <= 0.0f) *td->val = 0.001f;
+ }
}
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -4842,7 +5362,6 @@ static void initGPShrinkFatten(TransInfo *t)
static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float ratio;
int i;
char str[UI_MAX_DRAW_STR];
@@ -4866,24 +5385,25 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Shrink/Fatten: %3f"), ratio);
}
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->val) {
- *td->val = td->ival * ratio;
- /* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- if (*td->val <= 0.0f) *td->val = 0.001f;
+ if (td->val) {
+ *td->val = td->ival * ratio;
+ /* apply PET */
+ *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ if (*td->val <= 0.0f) *td->val = 0.001f;
+ }
}
}
- recalcData(t);
-
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -4919,7 +5439,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
float distance;
int i;
char str[UI_MAX_DRAW_STR];
- TransData *td = t->data;
distance = t->values[0];
@@ -4943,40 +5462,43 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
}
if (t->con.applyRot && t->con.mode & CON_APPLY) {
- t->con.applyRot(t, NULL, axis_global, NULL);
+ t->con.applyRot(t, NULL, NULL, axis_global, NULL);
}
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
-
- if (td->flag & TD_SKIP)
- continue;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- sub_v3_v3v3(vec, t->center, td->center);
- if (t->con.applyRot && t->con.mode & CON_APPLY) {
- float axis[3];
- copy_v3_v3(axis, axis_global);
- t->con.applyRot(t, td, axis, NULL);
+ if (td->flag & TD_SKIP)
+ continue;
- mul_m3_v3(td->smtx, axis);
- if (isLockConstraint(t)) {
- float dvec[3];
- project_v3_v3v3(dvec, vec, axis);
- sub_v3_v3(vec, dvec);
- }
- else {
- project_v3_v3v3(vec, vec, axis);
+ sub_v3_v3v3(vec, tc->center_local, td->center);
+ if (t->con.applyRot && t->con.mode & CON_APPLY) {
+ float axis[3];
+ copy_v3_v3(axis, axis_global);
+ t->con.applyRot(t, tc, td, axis, NULL);
+
+ mul_m3_v3(td->smtx, axis);
+ if (isLockConstraint(t)) {
+ float dvec[3];
+ project_v3_v3v3(dvec, vec, axis);
+ sub_v3_v3(vec, dvec);
+ }
+ else {
+ project_v3_v3v3(vec, vec, axis);
+ }
}
- }
- normalize_v3_length(vec, distance * td->factor);
+ normalize_v3_length(vec, distance * td->factor);
- add_v3_v3v3(td->loc, td->iloc, vec);
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -5009,7 +5531,6 @@ static void initBevelWeight(TransInfo *t)
static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float weight;
int i;
char str[UI_MAX_DRAW_STR];
@@ -5043,20 +5564,23 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
}
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->val) {
- *td->val = td->ival + weight * td->factor;
- if (*td->val < 0.0f) *td->val = 0.0f;
- if (*td->val > 1.0f) *td->val = 1.0f;
+ if (td->val) {
+ *td->val = td->ival + weight * td->factor;
+ if (*td->val < 0.0f) *td->val = 0.0f;
+ if (*td->val > 1.0f) *td->val = 1.0f;
+ }
}
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -5089,7 +5613,6 @@ static void initCrease(TransInfo *t)
static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float crease;
int i;
char str[UI_MAX_DRAW_STR];
@@ -5123,23 +5646,26 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Crease: %.3f %s"), crease, t->proptext);
}
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->val) {
- *td->val = td->ival + crease * td->factor;
- if (*td->val < 0.0f) *td->val = 0.0f;
- if (*td->val > 1.0f) *td->val = 1.0f;
+ if (td->val) {
+ *td->val = td->ival + crease * td->factor;
+ if (*td->val < 0.0f) *td->val = 0.0f;
+ if (*td->val > 1.0f) *td->val = 1.0f;
+ }
}
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -5200,7 +5726,7 @@ static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRA
}
}
-static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
+static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
{
float tmat[3][3], smat[3][3], oldy;
float sizemat[3][3];
@@ -5209,7 +5735,7 @@ static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
mul_m3_m3m3(tmat, td->smtx, smat);
if (t->con.applySize) {
- t->con.applySize(t, td, tmat);
+ t->con.applySize(t, tc, td, tmat);
}
/* we've tucked the scale in loc */
@@ -5220,23 +5746,13 @@ static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
td->loc[1] = oldy;
}
-static void applyBoneSize(TransInfo *t, const int mval[2])
+static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float size[3], mat[3][3];
- float ratio;
+ float ratio = t->values[0];
int i;
char str[UI_MAX_DRAW_STR];
- // TRANSFORM_FIX_ME MOVE TO MOUSE INPUT
- /* for manipulator, center handle, the scaling can't be done relative to center */
- if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
- ratio = 1.0f - ((t->mouse.imval[0] - mval[0]) + (t->mouse.imval[1] - mval[1])) / 100.0f;
- }
- else {
- ratio = t->values[0];
- }
-
copy_v3_fl(size, ratio);
snapGridIncrement(t, size);
@@ -5250,26 +5766,29 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
size_to_mat3(mat, size);
if (t->con.applySize) {
- t->con.applySize(t, NULL, mat);
+ t->con.applySize(t, NULL, NULL, mat);
}
- copy_m3_m3(t->mat, mat); // used in manipulator
+ copy_m3_m3(t->mat, mat); // used in gizmo
headerBoneSize(t, size, str);
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- ElementBoneSize(t, td, mat);
+ ElementBoneSize(t, tc, td, mat);
+ }
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -5302,7 +5821,6 @@ static void initBoneEnvelope(TransInfo *t)
static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float ratio;
int i;
char str[UI_MAX_DRAW_STR];
@@ -5326,25 +5844,28 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
BLI_snprintf(str, sizeof(str), IFACE_("Envelope: %3f"), ratio);
}
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->val) {
- /* if the old/original value was 0.0f, then just use ratio */
- if (td->ival)
- *td->val = td->ival * ratio;
- else
- *td->val = ratio;
+ if (td->val) {
+ /* if the old/original value was 0.0f, then just use ratio */
+ if (td->ival)
+ *td->val = td->ival * ratio;
+ else
+ *td->val = ratio;
+ }
}
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -5355,9 +5876,9 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
* \{ */
static void slide_origdata_init_flag(
- TransInfo *t, SlideOrigData *sod)
+ TransInfo *t, TransDataContainer *tc, SlideOrigData *sod)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
const bool has_layer_math = CustomData_has_math(&bm->ldata);
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -5378,10 +5899,10 @@ static void slide_origdata_init_flag(
}
static void slide_origdata_init_data(
- TransInfo *t, SlideOrigData *sod)
+ TransDataContainer *tc, SlideOrigData *sod)
{
if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
sod->origfaces = BLI_ghash_ptr_new(__func__);
@@ -5442,11 +5963,11 @@ static void slide_origdata_create_data_vert(
}
static void slide_origdata_create_data(
- TransInfo *t, SlideOrigData *sod,
+ TransInfo *t, TransDataContainer *tc, SlideOrigData *sod,
TransDataGenericSlideVert *sv_array, unsigned int v_stride, unsigned int v_num)
{
if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
unsigned int i;
TransDataGenericSlideVert *sv;
@@ -5478,15 +5999,15 @@ static void slide_origdata_create_data(
}
if (t->flag & T_MIRROR) {
- TransData *td = t->data;
+ TransData *td = tc->data;
TransDataGenericSlideVert *sv_mirror;
- sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * t->total, __func__);
- sod->totsv_mirror = t->total;
+ sod->sv_mirror = MEM_callocN(sizeof(*sv_mirror) * tc->data_len, __func__);
+ sod->totsv_mirror = tc->data_len;
sv_mirror = sod->sv_mirror;
- for (i = 0; i < t->total; i++, td++) {
+ for (i = 0; i < tc->data_len; i++, td++) {
BMVert *eve = td->extra;
if (eve) {
sv_mirror->v = eve;
@@ -5640,12 +6161,12 @@ static void slide_origdata_interp_data_vert(
}
static void slide_origdata_interp_data(
- TransInfo *t, SlideOrigData *sod,
+ Object *obedit, SlideOrigData *sod,
TransDataGenericSlideVert *sv, unsigned int v_stride, unsigned int v_num,
bool is_final)
{
if (sod->use_origfaces) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
unsigned int i;
const bool has_mdisps = (sod->cd_loop_mdisp_offset != -1);
@@ -5708,7 +6229,7 @@ static void slide_origdata_free_date(
static void calcEdgeSlideCustomPoints(struct TransInfo *t)
{
- EdgeSlideData *sld = t->custom.mode.data;
+ EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
@@ -5776,6 +6297,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp,
BMLoop *l_last = l_tmp->prev;
BMLoop *l_iter;
float dist = FLT_MAX;
+ bool found = false;
l_iter = l_first;
do {
@@ -5794,12 +6316,13 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp,
if (tdist < dist) {
copy_v3_v3(r_co, tvec);
dist = tdist;
+ found = true;
}
}
}
} while ((l_iter = l_iter->next) != l_last);
- return (dist != FLT_MAX);
+ return found;
}
/**
@@ -5905,11 +6428,11 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
* Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
*/
static void calcEdgeSlide_mval_range(
- TransInfo *t, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
+ TransInfo *t, TransDataContainer *tc, EdgeSlideData *sld, const int *sv_table, const int loop_nr,
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);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
ARegion *ar = t->ar;
View3D *v3d = NULL;
@@ -5936,7 +6459,7 @@ static void calcEdgeSlide_mval_range(
unit_m4(projectMat);
}
else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
}
if (use_occlude_geometry) {
@@ -5978,7 +6501,9 @@ static void calcEdgeSlide_mval_range(
continue;
/* This test is only relevant if object is not wire-drawn! See [#32068]. */
- if (use_occlude_geometry && !BMBVH_EdgeVisible(bmbvh, e_other, ar, v3d, t->obedit)) {
+ if (use_occlude_geometry &&
+ !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, tc->obedit))
+ {
continue;
}
@@ -6065,7 +6590,7 @@ static void calcEdgeSlide_mval_range(
}
static void calcEdgeSlide_even(
- TransInfo *t, EdgeSlideData *sld, const float mval[2])
+ TransInfo *t, TransDataContainer *tc, EdgeSlideData *sld, const float mval[2])
{
TransDataEdgeSlideVert *sv = sld->sv;
@@ -6090,7 +6615,7 @@ static void calcEdgeSlide_even(
unit_m4(projectMat);
}
else {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
}
for (i = 0; i < sld->totsv; i++, sv++) {
@@ -6110,9 +6635,9 @@ static void calcEdgeSlide_even(
}
}
-static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
BMIter iter;
BMEdge *e;
@@ -6127,13 +6652,9 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
- slide_origdata_init_flag(t, &sld->orig_data);
+ slide_origdata_init_flag(t, tc, &sld->orig_data);
- sld->use_even = use_even;
sld->curr_sv_index = 0;
- sld->flipped = flipped;
- if (!use_clamp)
- t->flag |= T_ALT_TRANSFORM;
/*ensure valid selection*/
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -6449,25 +6970,23 @@ 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_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && v3d->shading.type > OB_WIRE);
}
- calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
+ calcEdgeSlide_mval_range(t, tc, 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);
- slide_origdata_init_data(t, &sld->orig_data);
- slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+ slide_origdata_init_data(tc, &sld->orig_data);
+ slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
if (rv3d) {
- calcEdgeSlide_even(t, sld, mval);
+ calcEdgeSlide_even(t, tc, sld, mval);
}
sld->em = em;
- sld->perc = 0.0f;
-
- t->custom.mode.data = sld;
+ tc->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -6478,9 +6997,9 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool f
* A simple version of #createEdgeSlideVerts_double_side
* Which assumes the longest unselected.
*/
-static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
BMIter iter;
BMEdge *e;
@@ -6500,15 +7019,9 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
rv3d = t->ar ? t->ar->regiondata : NULL;
}
- slide_origdata_init_flag(t, &sld->orig_data);
+ slide_origdata_init_flag(t, tc, &sld->orig_data);
- sld->use_even = use_even;
sld->curr_sv_index = 0;
- /* happens to be best for single-sided */
- sld->flipped = !flipped;
- if (!use_clamp)
- t->flag |= T_ALT_TRANSFORM;
-
/* ensure valid selection */
{
int i = 0, j = 0;
@@ -6652,25 +7165,23 @@ 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_occlude_geometry = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
+ use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE && v3d->shading.type > OB_WIRE);
}
- calcEdgeSlide_mval_range(t, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
+ calcEdgeSlide_mval_range(t, tc, 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);
- slide_origdata_init_data(t, &sld->orig_data);
- slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+ slide_origdata_init_data(tc, &sld->orig_data);
+ slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
if (rv3d) {
- calcEdgeSlide_even(t, sld, mval);
+ calcEdgeSlide_even(t, tc, sld, mval);
}
sld->em = em;
- sld->perc = 0.0f;
-
- t->custom.mode.data = sld;
+ tc->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -6679,14 +7190,16 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool f
void projectEdgeSlideData(TransInfo *t, bool is_final)
{
- EdgeSlideData *sld = t->custom.mode.data;
- SlideOrigData *sod = &sld->orig_data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ SlideOrigData *sod = &sld->orig_data;
- if (sod->use_origfaces == false) {
- return;
- }
+ if (sod->use_origfaces == false) {
+ return;
+ }
- slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+ slide_origdata_interp_data(tc->obedit, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+ }
}
void freeEdgeSlideTempFaces(EdgeSlideData *sld)
@@ -6694,7 +7207,7 @@ void freeEdgeSlideTempFaces(EdgeSlideData *sld)
slide_origdata_free_date(&sld->orig_data);
}
-void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
+void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
{
EdgeSlideData *sld = custom_data->data;
@@ -6714,17 +7227,39 @@ void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
{
EdgeSlideData *sld;
- bool ok;
+ bool ok = false;
t->mode = TFM_EDGE_SLIDE;
t->transform = applyEdgeSlide;
t->handleEvent = handleEventEdgeSlide;
+ {
+ EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
+ slp->use_even = use_even;
+ slp->flipped = flipped;
+ /* happens to be best for single-sided */
+ if (use_double_side == false) {
+ slp->flipped = !flipped;
+ }
+ slp->perc = 0.0f;
+
+ if (!use_clamp) {
+ t->flag |= T_ALT_TRANSFORM;
+ }
+
+ t->custom.mode.data = slp;
+ t->custom.mode.use_free = true;
+ }
+
if (use_double_side) {
- ok = createEdgeSlideVerts_double_side(t, use_even, flipped, use_clamp);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createEdgeSlideVerts_double_side(t, tc);
+ }
}
else {
- ok = createEdgeSlideVerts_single_side(t, use_even, flipped, use_clamp);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createEdgeSlideVerts_single_side(t, tc);
+ }
}
if (!ok) {
@@ -6732,12 +7267,13 @@ static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even,
return;
}
- sld = t->custom.mode.data;
-
- if (!sld)
- return;
-
- t->custom.mode.free_cb = freeEdgeSlideVerts;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sld = tc->custom.mode.data;
+ if (!sld) {
+ continue;
+ }
+ tc->custom.mode.free_cb = freeEdgeSlideVerts;
+ }
/* set custom point first if you want value to be initialized by init */
calcEdgeSlideCustomPoints(t);
@@ -6764,20 +7300,20 @@ static void initEdgeSlide(TransInfo *t)
static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->custom.mode.data;
+ EdgeSlideParams *slp = t->custom.mode.data;
- if (sld) {
+ if (slp) {
switch (event->type) {
case EKEY:
if (event->val == KM_PRESS) {
- sld->use_even = !sld->use_even;
+ slp->use_even = !slp->use_even;
calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
case FKEY:
if (event->val == KM_PRESS) {
- sld->flipped = !sld->flipped;
+ slp->flipped = !slp->flipped;
calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
@@ -6791,6 +7327,7 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
}
break;
case EVT_MODAL_MAP:
+#if 0
switch (event->val) {
case TFM_MODAL_EDGESLIDE_DOWN:
sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
@@ -6799,6 +7336,7 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
return TREDRAW_HARD;
}
+#endif
break;
case MOUSEMOVE:
calcEdgeSlideCustomPoints(t);
@@ -6813,30 +7351,31 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
static void drawEdgeSlide(TransInfo *t)
{
- if ((t->mode == TFM_EDGE_SLIDE) && t->custom.mode.data) {
- EdgeSlideData *sld = t->custom.mode.data;
+ if ((t->mode == TFM_EDGE_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) {
+ const EdgeSlideParams *slp = t->custom.mode.data;
+ EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
/* Even mode */
- if ((sld->use_even == true) || (is_clamp == false)) {
- View3D *v3d = t->view;
+ if ((slp->use_even == true) || (is_clamp == false)) {
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
- if (v3d && v3d->zbuf)
- glDisable(GL_DEPTH_TEST);
+ GPU_depth_test(false);
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_matrix_push();
+ GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
- glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
- glPushMatrix();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- glMultMatrixf(t->obedit->obmat);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- if (sld->use_even == true) {
+ if (slp->use_even == true) {
float co_a[3], co_b[3], co_mark[3];
TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float fac = (sld->perc + 1.0f) / 2.0f;
+ const float fac = (slp->perc + 1.0f) / 2.0f;
const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
const float guide_size = ctrl_size - 0.5f;
const int alpha_shade = -30;
@@ -6844,40 +7383,36 @@ static void drawEdgeSlide(TransInfo *t)
add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]);
add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]);
- glLineWidth(line_size);
- UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- glBegin(GL_LINES);
+ GPU_line_width(line_size);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ immBeginAtMost(GPU_PRIM_LINES, 4);
if (curr_sv->v_side[0]) {
- glVertex3fv(curr_sv->v_side[0]->co);
- glVertex3fv(curr_sv->v_co_orig);
+ immVertex3fv(pos, curr_sv->v_side[0]->co);
+ immVertex3fv(pos, curr_sv->v_co_orig);
}
if (curr_sv->v_side[1]) {
- glVertex3fv(curr_sv->v_side[1]->co);
- glVertex3fv(curr_sv->v_co_orig);
+ immVertex3fv(pos, curr_sv->v_side[1]->co);
+ immVertex3fv(pos, curr_sv->v_co_orig);
}
- glEnd();
+ immEnd();
- UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
- glPointSize(ctrl_size);
- glBegin(GL_POINTS);
- if (sld->flipped) {
- if (curr_sv->v_side[1]) glVertex3fv(curr_sv->v_side[1]->co);
+ immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
+ GPU_point_size(ctrl_size);
+ immBegin(GPU_PRIM_POINTS, 1);
+ if (slp->flipped) {
+ if (curr_sv->v_side[1]) immVertex3fv(pos, curr_sv->v_side[1]->co);
}
else {
- if (curr_sv->v_side[0]) glVertex3fv(curr_sv->v_side[0]->co);
+ if (curr_sv->v_side[0]) immVertex3fv(pos, curr_sv->v_side[0]->co);
}
- glEnd();
+ immEnd();
- UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
- glPointSize(guide_size);
- glBegin(GL_POINTS);
-#if 0
- interp_v3_v3v3(co_mark, co_b, co_a, fac);
- glVertex3fv(co_mark);
-#endif
+ immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
+ GPU_point_size(guide_size);
+ immBegin(GPU_PRIM_POINTS, 1);
interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
- glVertex3fv(co_mark);
- glEnd();
+ immVertex3fv(pos, co_mark);
+ immEnd();
}
else {
if (is_clamp == false) {
@@ -6886,10 +7421,11 @@ static void drawEdgeSlide(TransInfo *t)
int i;
const int alpha_shade = -160;
- glLineWidth(line_size);
- UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- glBegin(GL_LINES);
+ GPU_line_width(line_size);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ immBegin(GPU_PRIM_LINES, sld->totsv * 2);
+ /* TODO(campbell): Loop over all verts */
sv = sld->sv;
for (i = 0; i < sld->totsv; i++, sv++) {
float a[3], b[3];
@@ -6906,61 +7442,66 @@ static void drawEdgeSlide(TransInfo *t)
add_v3_v3(a, sv->v_co_orig);
add_v3_v3(b, sv->v_co_orig);
- glVertex3fv(a);
- glVertex3fv(b);
+ immVertex3fv(pos, a);
+ immVertex3fv(pos, b);
}
- glEnd();
+ immEnd();
}
else {
BLI_assert(0);
}
}
- glPopMatrix();
- glPopAttrib();
+ immUnbindProgram();
+
+ GPU_matrix_pop();
- glDisable(GL_BLEND);
+ GPU_blend(false);
- if (v3d && v3d->zbuf)
- glEnable(GL_DEPTH_TEST);
+ GPU_depth_test(true);
}
}
}
static void doEdgeSlide(TransInfo *t, float perc)
{
- EdgeSlideData *sld = t->custom.mode.data;
- TransDataEdgeSlideVert *svlist = sld->sv, *sv;
- int i;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ EdgeSlideData *sld_active = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
- sld->perc = perc;
- sv = svlist;
+ slp->perc = perc;
- if (sld->use_even == false) {
+ if (slp->use_even == false) {
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
if (is_clamp) {
const int side_index = (perc < 0.0f);
const float perc_final = fabsf(perc);
- for (i = 0; i < sld->totsv; i++, sv++) {
- madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
+ }
+ sld->curr_side_unclamp = side_index;
}
-
- sld->curr_side_unclamp = side_index;
}
else {
- const int side_index = sld->curr_side_unclamp;
- const float perc_init = fabsf(perc) * ((sld->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
- for (i = 0; i < sld->totsv; i++, sv++) {
- float dir_flip[3];
- float perc_final = perc_init;
- if (!is_zero_v3(sv->dir_side[side_index])) {
- copy_v3_v3(dir_flip, sv->dir_side[side_index]);
- }
- else {
- copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
- perc_final *= -1;
+ const float perc_init = fabsf(perc) * ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
+ const int side_index = sld_active->curr_side_unclamp;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
+ float dir_flip[3];
+ float perc_final = perc_init;
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(dir_flip, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
+ perc_final *= -1;
+ }
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
}
- madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
}
}
}
@@ -6973,24 +7514,28 @@ static void doEdgeSlide(TransInfo *t, float perc)
* \note len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])
* is the same as the distance between the original vert locations, same goes for the lines below.
*/
- TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float curr_length_perc = curr_sv->edge_len * (((sld->flipped ? perc : -perc) + 1.0f) / 2.0f);
+ TransDataEdgeSlideVert *curr_sv = &sld_active->sv[sld_active->curr_sv_index];
+ const float curr_length_perc = curr_sv->edge_len * (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f);
float co_a[3];
float co_b[3];
- for (i = 0; i < sld->totsv; i++, sv++) {
- if (sv->edge_len > FLT_EPSILON) {
- const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
+ if (sv->edge_len > FLT_EPSILON) {
+ const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
- add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
- add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
+ add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
+ add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
- if (sld->flipped) {
- interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
- }
- else {
- interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac);
+ if (slp->flipped) {
+ interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
+ }
+ else {
+ interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac);
+ }
}
}
}
@@ -7002,9 +7547,9 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
- EdgeSlideData *sld = t->custom.mode.data;
- bool flipped = sld->flipped;
- bool use_even = sld->use_even;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ bool flipped = slp->flipped;
+ bool use_even = slp->use_even;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
@@ -7043,7 +7588,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -7056,7 +7601,8 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
static void calcVertSlideCustomPoints(struct TransInfo *t)
{
- VertSlideData *sld = t->custom.mode.data;
+ VertSlideParams *slp = t->custom.mode.data;
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
const float *co_orig_3d = sv->co_orig_3d;
@@ -7073,7 +7619,7 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]);
ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]);
- if (sld->flipped && sld->use_even) {
+ if (slp->flipped && slp->use_even) {
setCustomPoints(t, &t->mouse, mval_start, mval_end);
}
else {
@@ -7091,7 +7637,8 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
*/
static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
{
- VertSlideData *sld = t->custom.mode.data;
+ /* Active object may have no selected vertices. */
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
float mval_fl[2] = {UNPACK2(mval)};
TransDataVertSlideVert *sv;
@@ -7118,7 +7665,7 @@ static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
*/
static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
{
- VertSlideData *sld = t->custom.mode.data;
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
float imval_fl[2] = {UNPACK2(t->mouse.imval)};
float mval_fl[2] = {UNPACK2(mval)};
@@ -7146,7 +7693,7 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
float dir_dot;
sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]);
- mul_mat3_m4_v3(t->obedit->obmat, tdir);
+ mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir);
project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]);
normalize_v3(tdir);
@@ -7164,9 +7711,9 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
}
}
-static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm;
BMIter iter;
BMIter eiter;
@@ -7176,13 +7723,9 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
int j;
- slide_origdata_init_flag(t, &sld->orig_data);
+ slide_origdata_init_flag(t, tc, &sld->orig_data);
- sld->use_even = use_even;
sld->curr_sv_index = 0;
- sld->flipped = flipped;
- if (!use_clamp)
- t->flag |= T_ALT_TRANSFORM;
j = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -7245,14 +7788,12 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
sld->totsv = j;
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
- slide_origdata_init_data(t, &sld->orig_data);
- slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
+ slide_origdata_init_data(tc, &sld->orig_data);
+ slide_origdata_create_data(t, tc, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
sld->em = em;
- sld->perc = 0.0f;
-
- t->custom.mode.data = sld;
+ tc->custom.mode.data = sld;
/* most likely will be set below */
unit_m4(sld->proj_mat);
@@ -7264,9 +7805,12 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
rv3d = ar ? ar->regiondata : NULL;
if (rv3d) {
- ED_view3d_ob_project_mat_get(rv3d, t->obedit, sld->proj_mat);
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat);
}
+ }
+ /* XXX, calc vert slide across all objects */
+ if (tc == t->data_container) {
calcVertSlideMouseActiveVert(t, t->mval);
calcVertSlideMouseActiveEdges(t, t->mval);
}
@@ -7276,14 +7820,13 @@ static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool
void projectVertSlideData(TransInfo *t, bool is_final)
{
- VertSlideData *sld = t->custom.mode.data;
- SlideOrigData *sod = &sld->orig_data;
-
- if (sod->use_origfaces == false) {
- return;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ VertSlideData *sld = tc->custom.mode.data;
+ SlideOrigData *sod = &sld->orig_data;
+ if (sod->use_origfaces == true) {
+ slide_origdata_interp_data(tc->obedit, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
+ }
}
-
- slide_origdata_interp_data(t, sod, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv, is_final);
}
void freeVertSlideTempFaces(VertSlideData *sld)
@@ -7291,7 +7834,7 @@ void freeVertSlideTempFaces(VertSlideData *sld)
slide_origdata_free_date(&sld->orig_data);
}
-void freeVertSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
+void freeVertSlideVerts(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
{
VertSlideData *sld = custom_data->data;
@@ -7318,23 +7861,38 @@ void freeVertSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
{
- VertSlideData *sld;
t->mode = TFM_VERT_SLIDE;
t->transform = applyVertSlide;
t->handleEvent = handleEventVertSlide;
- if (!createVertSlideVerts(t, use_even, flipped, use_clamp)) {
- t->state = TRANS_CANCEL;
- return;
+ {
+ VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
+ slp->use_even = use_even;
+ slp->flipped = flipped;
+ slp->perc = 0.0f;
+
+ if (!use_clamp) {
+ t->flag |= T_ALT_TRANSFORM;
+ }
+
+ t->custom.mode.data = slp;
+ t->custom.mode.use_free = true;
}
- sld = t->custom.mode.data;
+ bool ok = false;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createVertSlideVerts(t, tc);
+ VertSlideData *sld = tc->custom.mode.data;
+ if (sld) {
+ tc->custom.mode.free_cb = freeVertSlideVerts;
+ }
+ }
- if (!sld)
+ if (ok == false) {
+ t->state = TRANS_CANCEL;
return;
-
- t->custom.mode.free_cb = freeVertSlideVerts;
+ }
/* set custom point first if you want value to be initialized by init */
calcVertSlideCustomPoints(t);
@@ -7361,14 +7919,14 @@ static void initVertSlide(TransInfo *t)
static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = t->custom.mode.data;
+ VertSlideParams *slp = t->custom.mode.data;
- if (sld) {
+ if (slp) {
switch (event->type) {
case EKEY:
if (event->val == KM_PRESS) {
- sld->use_even = !sld->use_even;
- if (sld->flipped) {
+ slp->use_even = !slp->use_even;
+ if (slp->flipped) {
calcVertSlideCustomPoints(t);
}
return TREDRAW_HARD;
@@ -7376,7 +7934,7 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
break;
case FKEY:
if (event->val == KM_PRESS) {
- sld->flipped = !sld->flipped;
+ slp->flipped = !slp->flipped;
calcVertSlideCustomPoints(t);
return TREDRAW_HARD;
}
@@ -7421,13 +7979,13 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
static void drawVertSlide(TransInfo *t)
{
- if ((t->mode == TFM_VERT_SLIDE) && t->custom.mode.data) {
- VertSlideData *sld = t->custom.mode.data;
+ if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) {
+ const VertSlideParams *slp = t->custom.mode.data;
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
/* Non-Prop mode */
{
- View3D *v3d = t->view;
TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
TransDataVertSlideVert *sv;
const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
@@ -7435,25 +7993,27 @@ static void drawVertSlide(TransInfo *t)
const int alpha_shade = -160;
int i;
- if (v3d && v3d->zbuf)
- glDisable(GL_DEPTH_TEST);
+ GPU_depth_test(false);
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GPU_matrix_push();
+ GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
- glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
- glPushMatrix();
+ GPU_line_width(line_size);
- glMultMatrixf(t->obedit->obmat);
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- glLineWidth(line_size);
- UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- glBegin(GL_LINES);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+
+ immBegin(GPU_PRIM_LINES, sld->totsv * 2);
if (is_clamp) {
sv = sld->sv;
for (i = 0; i < sld->totsv; i++, sv++) {
- glVertex3fv(sv->co_orig_3d);
- glVertex3fv(sv->co_link_orig_3d[sv->co_link_curr]);
+ immVertex3fv(shdr_pos, sv->co_orig_3d);
+ immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]);
}
}
else {
@@ -7466,21 +8026,21 @@ static void drawVertSlide(TransInfo *t)
add_v3_v3(a, sv->co_orig_3d);
add_v3_v3(b, sv->co_orig_3d);
- glVertex3fv(a);
- glVertex3fv(b);
+ immVertex3fv(shdr_pos, a);
+ immVertex3fv(shdr_pos, b);
}
}
- glEnd();
+ immEnd();
- glPointSize(ctrl_size);
+ GPU_point_size(ctrl_size);
- glBegin(GL_POINTS);
- glVertex3fv((sld->flipped && sld->use_even) ?
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(shdr_pos, (slp->flipped && slp->use_even) ?
curr_sv->co_link_orig_3d[curr_sv->co_link_curr] :
curr_sv->co_orig_3d);
- glEnd();
+ immEnd();
- glDisable(GL_BLEND);
+ immUnbindProgram();
/* direction from active vertex! */
if ((t->mval[0] != t->mouse.imval[0]) ||
@@ -7494,73 +8054,86 @@ static void drawVertSlide(TransInfo *t)
mval_ofs[0] = t->mval[0] - t->mouse.imval[0];
mval_ofs[1] = t->mval[1] - t->mouse.imval[1];
- mul_v3_m4v3(co_orig_3d, t->obedit->obmat, curr_sv->co_orig_3d);
+ mul_v3_m4v3(co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d);
zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL);
ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac);
- invert_m4_m4(t->obedit->imat, t->obedit->obmat);
- mul_mat3_m4_v3(t->obedit->imat, co_dest_3d);
+ invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
+ mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d);
add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
- glLineWidth(1);
- setlinestyle(1);
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- cpack(0xffffff);
- glBegin(GL_LINES);
- glVertex3fv(curr_sv->co_orig_3d);
- glVertex3fv(co_dest_3d);
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
- glEnd();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, curr_sv->co_orig_3d);
+ immVertex3fv(shdr_pos, co_dest_3d);
+ immEnd();
+
+ immUnbindProgram();
}
- glPopMatrix();
- glPopAttrib();
+ GPU_matrix_pop();
- if (v3d && v3d->zbuf)
- glEnable(GL_DEPTH_TEST);
+ GPU_depth_test(true);
}
}
}
static void doVertSlide(TransInfo *t, float perc)
{
- VertSlideData *sld = t->custom.mode.data;
- TransDataVertSlideVert *svlist = sld->sv, *sv;
- int i;
+ VertSlideParams *slp = t->custom.mode.data;
- sld->perc = perc;
- sv = svlist;
+ slp->perc = perc;
- if (sld->use_even == false) {
- for (i = 0; i < sld->totsv; i++, sv++) {
- interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ VertSlideData *sld = tc->custom.mode.data;
+ TransDataVertSlideVert *svlist = sld->sv, *sv;
+ int i;
+
+ sv = svlist;
+
+ if (slp->use_even == false) {
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
+ }
}
- }
- else {
- TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index];
- const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, sv_curr->co_link_orig_3d[sv_curr->co_link_curr]);
- const float tperc = perc * edge_len_curr;
+ else {
+ TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index];
+ const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, sv_curr->co_link_orig_3d[sv_curr->co_link_curr]);
+ const float tperc = perc * edge_len_curr;
- for (i = 0; i < sld->totsv; i++, sv++) {
- float edge_len;
- float dir[3];
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float edge_len;
+ float dir[3];
- sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
- edge_len = normalize_v3(dir);
+ sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
+ edge_len = normalize_v3(dir);
- if (edge_len > FLT_EPSILON) {
- if (sld->flipped) {
- madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
+ if (edge_len > FLT_EPSILON) {
+ if (slp->flipped) {
+ madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
+ }
+ else {
+ madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc);
+ }
}
else {
- madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc);
+ copy_v3_v3(sv->v->co, sv->co_orig_3d);
}
}
- else {
- copy_v3_v3(sv->v->co, sv->co_orig_3d);
- }
}
}
}
@@ -7570,9 +8143,9 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
float final;
- VertSlideData *sld = t->custom.mode.data;
- const bool flipped = sld->flipped;
- const bool use_even = sld->use_even;
+ VertSlideParams *slp = t->custom.mode.data;
+ const bool flipped = slp->flipped;
+ const bool use_even = slp->use_even;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
@@ -7611,7 +8184,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -7645,7 +8218,6 @@ static void initBoneRoll(TransInfo *t)
static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
int i;
char str[UI_MAX_DRAW_STR];
@@ -7671,19 +8243,22 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
}
/* set roll values */
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- *(td->val) = td->ival - final;
+ *(td->val) = td->ival - final;
+ }
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -7712,7 +8287,6 @@ static void initBakeTime(TransInfo *t)
static void applyBakeTime(TransInfo *t, const int mval[2])
{
- TransData *td = t->data;
float time;
int i;
char str[UI_MAX_DRAW_STR];
@@ -7756,23 +8330,26 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
BLI_snprintf(str, sizeof(str), IFACE_("Time: %.3f %s"), time, t->proptext);
}
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->val) {
- *td->val = td->ival + time * td->factor;
- if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size;
- if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
+ if (td->val) {
+ *td->val = td->ival + time * td->factor;
+ if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size;
+ if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
+ }
}
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -7789,14 +8366,13 @@ static void initMirror(TransInfo *t)
initMouseInputMode(t, &t->mouse, INPUT_NONE);
t->flag |= T_NULL_ONE;
- if (!t->obedit) {
+ if ((t->flag & T_EDIT) == 0) {
t->flag |= T_NO_ZERO;
}
}
static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td;
float size[3], mat[3][3];
int i;
char str[UI_MAX_DRAW_STR];
@@ -7814,46 +8390,52 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
size_to_mat3(mat, size);
if (t->con.applySize) {
- t->con.applySize(t, NULL, mat);
+ t->con.applySize(t, NULL, NULL, mat);
}
BLI_snprintf(str, sizeof(str), IFACE_("Mirror%s"), t->con.text);
- for (i = 0, td = t->data; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- ElementResize(t, td, mat);
+ ElementResize(t, tc, td, mat);
+ }
}
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
else {
size[0] = size[1] = size[2] = 1;
size_to_mat3(mat, size);
- for (i = 0, td = t->data; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- ElementResize(t, td, mat);
+ ElementResize(t, tc, td, mat);
+ }
}
recalcData(t);
if (t->flag & T_2D_EDIT)
- ED_area_headerprint(t->sa, IFACE_("Select a mirror axis (X, Y)"));
+ ED_area_status_text(t->sa, IFACE_("Select a mirror axis (X, Y)"));
else
- ED_area_headerprint(t->sa, IFACE_("Select a mirror axis (X, Y, Z)"));
+ ED_area_status_text(t->sa, IFACE_("Select a mirror axis (X, Y, Z)"));
}
}
/** \} */
@@ -7876,45 +8458,46 @@ static void initAlign(TransInfo *t)
static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
{
- TransData *td = t->data;
float center[3];
int i;
- /* saving original center */
- copy_v3_v3(center, t->center);
- for (i = 0; i < t->total; i++, td++) {
- float mat[3][3], invmat[3][3];
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ /* saving original center */
+ copy_v3_v3(center, tc->center_local);
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float mat[3][3], invmat[3][3];
- if (td->flag & TD_NOACTION)
- break;
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- /* around local centers */
- if (t->flag & (T_OBJECT | T_POSE)) {
- copy_v3_v3(t->center, td->center);
- }
- else {
- if (t->settings->selectmode & SCE_SELECT_FACE) {
- copy_v3_v3(t->center, td->center);
+ /* around local centers */
+ if (t->flag & (T_OBJECT | T_POSE)) {
+ copy_v3_v3(tc->center_local, td->center);
+ }
+ else {
+ if (t->settings->selectmode & SCE_SELECT_FACE) {
+ copy_v3_v3(tc->center_local, td->center);
+ }
}
- }
- invert_m3_m3(invmat, td->axismtx);
+ invert_m3_m3(invmat, td->axismtx);
- mul_m3_m3m3(mat, t->spacemtx, invmat);
+ mul_m3_m3m3(mat, t->spacemtx, invmat);
- ElementRotation(t, td, mat, t->around);
+ ElementRotation(t, tc, td, mat, t->around);
+ }
+ /* restoring original center */
+ copy_v3_v3(tc->center_local, center);
}
- /* restoring original center */
- copy_v3_v3(t->center, center);
-
recalcData(t);
- ED_area_headerprint(t->sa, IFACE_("Align"));
+ ED_area_status_text(t->sa, IFACE_("Align"));
}
/** \} */
@@ -7972,17 +8555,19 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRA
static void applySeqSlideValue(TransInfo *t, const float val[2])
{
- TransData *td = t->data;
int i;
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
+ madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
+ }
}
}
@@ -7995,7 +8580,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
if (t->con.mode & CON_APPLY) {
float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
- t->con.applyVec(t, NULL, t->values, tvec, pvec);
+ t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
copy_v3_v3(t->values, tvec);
}
else {
@@ -8011,7 +8596,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -8215,8 +8800,6 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
static void applyTimeTranslateValue(TransInfo *t)
{
- TransData *td = t->data;
- TransData2D *td2d = t->data2d;
Scene *scene = t->scene;
int i;
@@ -8225,46 +8808,50 @@ static void applyTimeTranslateValue(TransInfo *t)
float deltax, val /* , valprev */;
- /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
- for (i = 0; i < t->total; i++, td++, td2d++) {
- /* it is assumed that td->extra is a pointer to the AnimData,
- * whose active action is where this keyframe comes from
- * (this is only valid when not in NLA)
- */
- AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ TransData2D *td2d = tc->data_2d;
+ /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
+ for (i = 0; i < tc->data_len; i++, td++, td2d++) {
+ /* it is assumed that td->extra is a pointer to the AnimData,
+ * whose active action is where this keyframe comes from
+ * (this is only valid when not in NLA)
+ */
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
- /* valprev = *td->val; */ /* UNUSED */
+ /* valprev = *td->val; */ /* UNUSED */
- /* check if any need to apply nla-mapping */
- if (adt && (t->spacetype != SPACE_SEQ)) {
- deltax = t->values[0];
+ /* check if any need to apply nla-mapping */
+ if (adt && (t->spacetype != SPACE_SEQ)) {
+ deltax = t->values[0];
- if (autosnap == SACTSNAP_TSTEP) {
- deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf);
- }
- else if (autosnap == SACTSNAP_STEP) {
- deltax = floorf(deltax + 0.5f);
+ if (autosnap == SACTSNAP_TSTEP) {
+ deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf);
+ }
+ else if (autosnap == SACTSNAP_STEP) {
+ deltax = floorf(deltax + 0.5f);
+ }
+
+ val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
+ val += deltax * td->factor;
+ *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
}
+ else {
+ deltax = val = t->values[0];
- val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
- val += deltax * td->factor;
- *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
- }
- else {
- deltax = val = t->values[0];
+ if (autosnap == SACTSNAP_TSTEP) {
+ val = (float)(floor(((double)deltax / secf) + 0.5) * secf);
+ }
+ else if (autosnap == SACTSNAP_STEP) {
+ val = floorf(val + 0.5f);
+ }
- if (autosnap == SACTSNAP_TSTEP) {
- val = (float)(floor(((double)deltax / secf) + 0.5) * secf);
- }
- else if (autosnap == SACTSNAP_STEP) {
- val = floorf(val + 0.5f);
+ *(td->val) = td->ival + val;
}
- *(td->val) = td->ival + val;
+ /* apply nearest snapping */
+ doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
}
-
- /* apply nearest snapping */
- doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
}
}
@@ -8293,7 +8880,7 @@ static void applyTimeTranslate(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -8331,18 +8918,19 @@ static void initTimeSlide(TransInfo *t)
float min = 999999999.0f, max = -999999999.0f;
int i;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+ float val = *(td->val);
- TransData *td = t->data;
- for (i = 0; i < t->total; i++, td++) {
- AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
- float val = *(td->val);
-
- /* strip/action time to global (mapped) time */
- if (adt)
- val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP);
+ /* strip/action time to global (mapped) time */
+ if (adt)
+ val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP);
- if (min > val) min = val;
- if (max < val) max = val;
+ if (min > val) min = val;
+ if (max < val) max = val;
+ }
}
if (min == max) {
@@ -8395,7 +8983,6 @@ static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW
static void applyTimeSlideValue(TransInfo *t, float sval)
{
- TransData *td = t->data;
int i;
const float *range = t->custom.mode.data;
float minx = range[0];
@@ -8410,44 +8997,47 @@ static void applyTimeSlideValue(TransInfo *t, float sval)
}
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
- for (i = 0; i < t->total; i++, td++) {
- /* it is assumed that td->extra is a pointer to the AnimData,
- * whose active action is where this keyframe comes from
- * (this is only valid when not in NLA)
- */
- AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
- float cval = t->values[0];
-
- /* only apply to data if in range */
- if ((sval > minx) && (sval < maxx)) {
- float cvalc = CLAMPIS(cval, minx, maxx);
- float ival = td->ival;
- float timefac;
-
- /* NLA mapping magic here works as follows:
- * - "ival" goes from strip time to global time
- * - calculation is performed into td->val in global time
- * (since sval and min/max are all in global time)
- * - "td->val" then gets put back into strip time
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ /* it is assumed that td->extra is a pointer to the AnimData,
+ * whose active action is where this keyframe comes from
+ * (this is only valid when not in NLA)
*/
- if (adt) {
- /* strip to global */
- ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
- }
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+ float cval = t->values[0];
+
+ /* only apply to data if in range */
+ if ((sval > minx) && (sval < maxx)) {
+ float cvalc = CLAMPIS(cval, minx, maxx);
+ float ival = td->ival;
+ float timefac;
+
+ /* NLA mapping magic here works as follows:
+ * - "ival" goes from strip time to global time
+ * - calculation is performed into td->val in global time
+ * (since sval and min/max are all in global time)
+ * - "td->val" then gets put back into strip time
+ */
+ if (adt) {
+ /* strip to global */
+ ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
+ }
- /* left half? */
- if (ival < sval) {
- timefac = (sval - ival) / (sval - minx);
- *(td->val) = cvalc - timefac * (cvalc - minx);
- }
- else {
- timefac = (ival - sval) / (maxx - sval);
- *(td->val) = cvalc + timefac * (maxx - cvalc);
- }
+ /* left half? */
+ if (ival < sval) {
+ timefac = (sval - ival) / (sval - minx);
+ *(td->val) = cvalc - timefac * (cvalc - minx);
+ }
+ else {
+ timefac = (ival - sval) / (maxx - sval);
+ *(td->val) = cvalc + timefac * (maxx - cvalc);
+ }
- if (adt) {
- /* global to strip */
- *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP);
+ if (adt) {
+ /* global to strip */
+ *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP);
+ }
}
}
}
@@ -8480,7 +9070,7 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -8508,8 +9098,8 @@ static void initTimeScale(TransInfo *t)
/* recalculate center2d to use CFRA and mouse Y, since that's
* what is used in time scale */
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
- t->center[0] = t->scene->r.cfra;
- projectFloatView(t, t->center, center);
+ t->center_global[0] = t->scene->r.cfra;
+ projectFloatView(t, t->center_global, center);
center[1] = t->mouse.imval[1];
}
@@ -8550,39 +9140,40 @@ static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
static void applyTimeScaleValue(TransInfo *t)
{
Scene *scene = t->scene;
- TransData *td = t->data;
- TransData2D *td2d = t->data2d;
int i;
const short autosnap = getAnimEdit_SnapMode(t);
const double secf = FPS;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ TransData2D *td2d = tc->data_2d;
+ for (i = 0; i < tc->data_len; i++, td++, td2d++) {
+ /* it is assumed that td->extra is a pointer to the AnimData,
+ * whose active action is where this keyframe comes from
+ * (this is only valid when not in NLA)
+ */
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+ float startx = CFRA;
+ float fac = t->values[0];
- for (i = 0; i < t->total; i++, td++, td2d++) {
- /* it is assumed that td->extra is a pointer to the AnimData,
- * whose active action is where this keyframe comes from
- * (this is only valid when not in NLA)
- */
- AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
- float startx = CFRA;
- float fac = t->values[0];
-
- if (autosnap == SACTSNAP_TSTEP) {
- fac = (float)(floor((double)fac / secf + 0.5) * secf);
- }
- else if (autosnap == SACTSNAP_STEP) {
- fac = floorf(fac + 0.5f);
- }
+ if (autosnap == SACTSNAP_TSTEP) {
+ fac = (float)(floor((double)fac / secf + 0.5) * secf);
+ }
+ else if (autosnap == SACTSNAP_STEP) {
+ fac = floorf(fac + 0.5f);
+ }
- /* check if any need to apply nla-mapping */
- if (adt)
- startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP);
+ /* check if any need to apply nla-mapping */
+ if (adt)
+ startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP);
- /* now, calculate the new value */
- *(td->val) = ((td->ival - startx) * fac) + startx;
+ /* now, calculate the new value */
+ *(td->val) = ((td->ival - startx) * fac) + startx;
- /* apply nearest snapping */
- doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
+ /* apply nearest snapping */
+ doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
+ }
}
}
@@ -8600,7 +9191,7 @@ static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_headerprint(t->sa, str);
+ ED_area_status_text(t->sa, str);
}
/** \} */
@@ -8611,7 +9202,7 @@ bool checkUseAxisMatrix(TransInfo *t)
/* currently only checks for editmode */
if (t->flag & T_EDIT) {
if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)))
+ (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)))
{
/* not all editmode supports axis-matrix */
return true;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 5369fc05005..ca341fc8738 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -37,11 +37,17 @@
#include "ED_numinput.h"
#include "ED_view3d.h"
+#include "RE_engine.h"
+
#include "DNA_listBase.h"
+#include "DEG_depsgraph.h"
+
/* ************************** Types ***************************** */
+struct Depsgraph;
struct TransInfo;
+struct TransDataContainer;
struct TransData;
struct TransformOrientation;
struct TransSnap;
@@ -50,6 +56,7 @@ struct Object;
struct View3D;
struct ScrArea;
struct Scene;
+struct ViewLayer;
struct bConstraint;
struct wmKeyMap;
struct wmKeyConfig;
@@ -58,9 +65,13 @@ struct wmEvent;
struct wmTimer;
struct ARegion;
struct ReportList;
+struct RNG;
struct EditBone;
+struct RenderEngineType;
struct SnapObjectContext;
+#include "DNA_object_enums.h"
+
/* transinfo->redraw */
typedef enum {
TREDRAW_NOTHING = 0,
@@ -100,7 +111,7 @@ typedef struct TransSnap {
* \note Return value can be anything,
* where the smallest absolute value defines whats closest.
*/
- float (*distance)(struct TransInfo *, const float p1[3], const float p2[3]);
+ float (*distance)(struct TransInfo *t, const float p1[3], const float p2[3]);
/**
* Re-usable snap context data.
@@ -115,17 +126,19 @@ typedef struct TransCon {
float imtx[3][3]; /* Inverse Matrix of the Constraint space */
float pmtx[3][3]; /* Projection Constraint Matrix (same as imtx with some axis == 0) */
int imval[2]; /* initial mouse value for visual calculation */
- /* the one in TransInfo is not garanty to stay the same (Rotates change it) */
+ /* the one in TransInfo is not guarantee to stay the same (Rotates change it) */
int mode; /* Mode flags of the Constraint */
void (*drawExtra)(struct TransInfo *t);
+
+ /* Note: if 'tc' is NULL, 'td' must also be NULL. */
/* For constraints that needs to draw differently from the other
* uses this instead of the generic draw function */
- void (*applyVec)(struct TransInfo *t, struct TransData *td, const float in[3], float out[3], float pvec[3]);
+ void (*applyVec)(struct TransInfo *t, struct TransDataContainer *tc, struct TransData *td, const float in[3], float out[3], float pvec[3]);
/* Apply function pointer for linear vectorial transformation */
/* The last three parameters are pointers to the in/out/printable vectors */
- void (*applySize)(struct TransInfo *t, struct TransData *td, float smat[3][3]);
+ void (*applySize)(struct TransInfo *t, struct TransDataContainer *tc, struct TransData *td, float smat[3][3]);
/* Apply function pointer for size transformation */
- void (*applyRot)(struct TransInfo *t, struct TransData *td, float vec[3], float *angle);
+ void (*applyRot)(struct TransInfo *t, struct TransDataContainer *tc, struct TransData *td, float vec[3], float *angle);
/* Apply function pointer for rotation transformation */
} TransCon;
@@ -261,10 +274,6 @@ typedef struct EdgeSlideData {
SlideOrigData orig_data;
- float perc;
-
- bool use_even;
- bool flipped;
int curr_sv_index;
@@ -272,6 +281,12 @@ typedef struct EdgeSlideData {
int curr_side_unclamp;
} EdgeSlideData;
+typedef struct EdgeSlideParams {
+ float perc;
+
+ bool use_even;
+ bool flipped;
+} EdgeSlideParams;
typedef struct TransDataVertSlideVert {
/* TransDataGenericSlideVert */
@@ -293,17 +308,19 @@ typedef struct VertSlideData {
SlideOrigData orig_data;
- float perc;
-
- bool use_even;
- bool flipped;
-
int curr_sv_index;
/* result of ED_view3d_ob_project_mat_get */
float proj_mat[4][4];
} VertSlideData;
+typedef struct VertSlideParams {
+ float perc;
+
+ bool use_even;
+ bool flipped;
+} VertSlideParams;
+
typedef struct BoneInitData {
struct EditBone *bone;
float tail[3];
@@ -364,16 +381,80 @@ typedef struct MouseInput {
typedef struct TransCustomData {
void *data;
- void (*free_cb)(struct TransInfo *, struct TransCustomData *);
+ void (*free_cb)(struct TransInfo *, struct TransDataContainer *tc, struct TransCustomData *custom_data);
unsigned int use_free : 1;
} TransCustomData;
typedef struct TransCenterData {
- float local[3], global[3];
+ float global[3];
unsigned int is_set : 1;
} TransCenterData;
+/**
+ * Rule of thumb for choosing between mode/type:
+ * - If transform mode uses the data, assign to `mode`
+ * (typically in transform.c).
+ * - If conversion uses the data as an extension to the #TransData, assign to `type`
+ * (typically in transform_conversion.c).
+ */
+typedef struct TransCustomDataContainer {
+ /** Owned by the mode (grab, scale, bend... ).*/
+ union {
+ TransCustomData mode, first_elem;
+ };
+ TransCustomData type;
+} TransCustomDataContainer;
+#define TRANS_CUSTOM_DATA_ELEM_MAX (sizeof(TransCustomDataContainer) / sizeof(TransCustomData))
+
+typedef struct TransDataContainer {
+ /**
+ * Use for cases we care about the active, eg: active vert of active mesh.
+ * if set this will _always_ be the first item in the array.
+ */
+ bool is_active;
+
+ /** Transformed data (array). */
+ TransData *data;
+ /** Total number of transformed data. */
+ int data_len;
+
+ /** Transformed data extension (array). */
+ TransDataExtension *data_ext;
+ /** Transformed data for 2d (array). */
+ TransData2D *data_2d;
+
+ struct Object *obedit;
+
+ /**
+ * Use when #T_LOCAL_MATRIX is set.
+ * Typically: 'obedit->obmat' or 'poseobj->obmat', but may be used elsewhere too.
+ */
+ bool use_local_mat;
+ float mat[4][4];
+ float imat[4][4];
+ /** 3x3 copies of matrices above. */
+ float mat3[3][3];
+ float imat3[3][3];
+
+ /** Normalized 'mat3' */
+ float mat3_unit[3][3];
+
+ /** if 't->flag & T_POSE', this denotes pose object */
+ struct Object *poseobj;
+
+ /** Center of transformation (in local-space), Calculated from #TransInfo.center_global. */
+ float center_local[3];
+
+ TransCustomDataContainer custom;
+} TransDataContainer;
+
typedef struct TransInfo {
+ TransDataContainer *data_container;
+ int data_container_len;
+ /** Combine length of all #TransDataContainer.data_len
+ * Use to check if nothing is selected or if we have a single selection. */
+ int data_len_all;
+
int mode; /* current mode */
int flag; /* generic flags for special behaviors */
int modifiers; /* special modifiers, by function, not key */
@@ -384,10 +465,6 @@ typedef struct TransInfo {
/* transform function pointer */
eRedrawFlag (*handleEvent)(struct TransInfo *, const struct wmEvent *);
/* event handler function pointer RETURN 1 if redraw is needed */
- int total; /* total number of transformed data */
- TransData *data; /* transformed data (array) */
- TransDataExtension *ext; /* transformed data extension (array) */
- TransData2D *data2d; /* transformed data for 2d (array) */
TransCon con; /* transformed constraint */
TransSnap tsnap;
NumInput num; /* numerical input */
@@ -397,7 +474,6 @@ typedef struct TransInfo {
char proptext[20]; /* proportional falloff text */
float aspect[3]; /* spaces using non 1:1 aspect, (uv's, f-curve, movie-clip... etc)
* use for conversion and snapping. */
- float center[3]; /* center of transformation (in local-space) */
float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
/* Lazy initialize center data for when we need other center values.
@@ -415,7 +491,8 @@ typedef struct TransInfo {
short persp;
short around;
char spacetype; /* spacetype where transforming is */
- char helpline; /* helpline modes (not to be confused with hotline) */
+ char helpline; /* Choice of custom cursor with or without a help line from the gizmo to the mouse position. */
+ short obedit_type; /* Avoid looking inside TransDataContainer obedit. */
float vec[3]; /* translation, to show for widget */
float mat[3][3]; /* rot/rescale, to show for widget */
@@ -423,39 +500,30 @@ typedef struct TransInfo {
float spacemtx[3][3]; /* orientation matrix of the current space */
char spacename[64]; /* name of the current space, MAX_NAME */
- struct Object *poseobj; /* if t->flag & T_POSE, this denotes pose object */
-
- /**
- * Rule of thumb for choosing between mode/type:
- * - If transform mode uses the data, assign to `mode`
- * (typically in transform.c).
- * - If conversion uses the data as an extension to the #TransData, assign to `type`
- * (typically in transform_conversion.c).
- */
- struct {
- /* owned by the mode (grab, scale, bend... )*/
- union {
- TransCustomData mode, first_elem;
- };
- /* owned by the type (mesh, armature, nla...) */
- TransCustomData type;
- } custom;
-#define TRANS_CUSTOM_DATA_ELEM_MAX (sizeof(((TransInfo *)NULL)->custom) / sizeof(TransCustomData))
-
/*************** NEW STUFF *********************/
short launch_event; /* event type used to launch transform */
- short current_orientation;
- short twtype; /* backup from view3d, to restore on end */
+ struct {
+ short user;
+ /* Used when user is global. */
+ short user_alt;
+ short index;
+ short *types[2];
+ /* this gets used when current_orientation is V3D_MANIP_CUSTOM */
+ TransformOrientation *custom;
+ } orientation;
+ short gizmo_flag; /* backup from view3d, to restore on end */
short prop_mode;
short mirror;
float values[4];
+ float values_modal_offset[4]; /* Offset applied ontop of modal input. */
float auto_values[4];
float axis[3];
float axis_orig[3]; /* TransCon can change 'axis', store the original value here */
+ float axis_ortho[3];
bool remove_on_cancel; /* remove elements if operator is canceled */
@@ -463,19 +531,25 @@ typedef struct TransInfo {
struct bContext *context; /* Only valid (non null) during an operator called function. */
struct ScrArea *sa;
struct ARegion *ar;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
+ struct ViewLayer *view_layer;
struct ToolSettings *settings;
struct wmTimer *animtimer;
struct wmKeyMap *keymap; /* so we can do lookups for header text */
struct ReportList *reports; /* assign from the operator, or can be NULL */
int mval[2]; /* current mouse position */
float zfac; /* use for 3d view */
- struct Object *obedit;
- float obedit_mat[3][3]; /* normalized editmode matrix (T_EDIT only) */
void *draw_handle_apply;
void *draw_handle_view;
void *draw_handle_pixel;
void *draw_handle_cursor;
+
+ /** Currently only used for random curve of proportional editing. */
+ struct RNG *rng;
+
+ /** Typically for mode settings. */
+ TransCustomDataContainer custom;
} TransInfo;
@@ -489,15 +563,20 @@ typedef struct TransInfo {
/* transinfo->flag */
#define T_OBJECT (1 << 0)
+/** \note We could remove 'T_EDIT' and use 'obedit_type', for now ensure they're in sync. */
#define T_EDIT (1 << 1)
#define T_POSE (1 << 2)
#define T_TEXTURE (1 << 3)
/* transforming the camera while in camera view */
#define T_CAMERA (1 << 4)
+ /* transforming the 3D cursor. */
+#define T_CURSOR (1 << 5)
// trans on points, having no rotation/scale
#define T_POINTS (1 << 6)
- // for manipulator exceptions, like scaling using center point, drawing help lines
-#define T_USES_MANIPULATOR (1 << 7)
+/**
+ * Apply matrix #TransDataContainer.matrix, this avoids having to have duplicate check all over
+ * that happen to apply to spesiifc modes (edit & pose for eg). */
+#define T_LOCAL_MATRIX (1 << 7)
/* restrictions flags */
#define T_ALL_RESTRICTIONS ((1 << 8)|(1 << 9)|(1 << 10))
@@ -536,6 +615,10 @@ typedef struct TransInfo {
/** #TransInfo.center has been set, don't change it. */
#define T_OVERRIDE_CENTER (1 << 25)
+#define T_MODAL_CURSOR_SET (1 << 26)
+
+#define T_CLNOR_REBUILD (1 << 27)
+
/* TransInfo->modifiers */
#define MOD_CONSTRAINT_SELECT 0x01
#define MOD_PRECISION 0x02
@@ -557,7 +640,8 @@ typedef struct TransInfo {
#define HLP_ANGLE 2
#define HLP_HARROW 3
#define HLP_VARROW 4
-#define HLP_TRACKBALL 5
+#define HLP_CARROW 5
+#define HLP_TRACKBALL 6
/* transinfo->con->mode */
#define CON_APPLY 1
@@ -635,10 +719,15 @@ void flushTransSeq(TransInfo *t);
void flushTransTracking(TransInfo *t);
void flushTransMasking(TransInfo *t);
void flushTransPaintCurve(TransInfo *t);
-void restoreBones(TransInfo *t);
+void restoreBones(TransDataContainer *tc);
+
+/*********************** transform_gizmo.c ********** */
-/*********************** exported from transform_manipulator.c ********** */
-bool gimbal_axis(struct Object *ob, float gmat[3][3]); /* return 0 when no gimbal for selection */
+#define GIZMO_AXIS_LINE_WIDTH 2.0f
+
+/* return 0 when no gimbal for selection */
+bool gimbal_axis(struct Object *ob, float gmat[3][3]);
+void drawDial3d(const TransInfo *t);
/*********************** TransData Creation and General Handling *********** */
void createTransData(struct bContext *C, TransInfo *t);
@@ -649,13 +738,17 @@ int special_transform_moving(TransInfo *t);
void transform_autoik_update(TransInfo *t, short mode);
bool transdata_check_local_islands(TransInfo *t, short around);
-int count_set_pose_transflags(int *out_mode, short around, struct Object *ob);
+int count_set_pose_transflags(struct Object *ob, const int mode, const short around, bool has_translate_rotate[2]);
+
+/* Auto-keyframe applied after transform, returns true if motion paths need to be updated. */
+void autokeyframe_object(
+ struct bContext *C, struct Scene *scene, struct ViewLayer *view_layer, struct Object *ob, int tmode);
+void autokeyframe_pose(
+ struct bContext *C, struct Scene *scene, struct Object *ob, int tmode, short targetless_ik);
-/* auto-keying stuff used by special_aftertrans_update */
-void autokeyframe_ob_cb_func(
- struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode);
-void autokeyframe_pose_cb_func(
- struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode, short targetless_ik);
+/* Test if we need to update motion paths for a given object. */
+bool motionpath_need_update_object(struct Scene *scene, struct Object *ob);
+bool motionpath_need_update_pose(struct Scene *scene, struct Object *ob);
/*********************** Constraints *****************************/
@@ -739,11 +832,14 @@ eRedrawFlag handleMouseInput(struct TransInfo *t, struct MouseInput *mi, const s
void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]);
void setCustomPoints(TransInfo *t, MouseInput *mi, const int start[2], const int end[2]);
+void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2]);
void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float values[3]));
/*********************** Generics ********************************/
+void initTransDataContainers_FromObjectData(TransInfo *t, struct Object *obact, struct Object **objects, uint objects_len);
void initTransInfo(struct bContext *C, TransInfo *t, struct wmOperator *op, const struct wmEvent *event);
+void freeTransCustomDataForMode(TransInfo *t);
void postTrans(struct bContext *C, TransInfo *t);
void resetTransModal(TransInfo *t);
void resetTransRestrictions(TransInfo *t);
@@ -758,9 +854,7 @@ void restoreTransObjects(TransInfo *t);
void recalcData(TransInfo *t);
void calculateCenter2D(TransInfo *t);
-void calculateCenterGlobal(
- TransInfo *t, const float center_local[3],
- float r_center_global[3]);
+void calculateCenterLocal(TransInfo *t, const float center_global[3]);
const TransCenterData *transformCenter_from_type(TransInfo *t, int around);
void calculateCenter(TransInfo *t);
@@ -789,7 +883,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
struct TransformOrientation *addMatrixSpace(struct bContext *C, float mat[3][3],
const char *name, const bool overwrite);
-bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r_name[64], int index);
+bool applyTransformOrientation(const struct TransformOrientation *ts, float r_mat[3][3], char r_name[64]);
#define ORIENTATION_NONE 0
#define ORIENTATION_NORMAL 1
@@ -802,20 +896,37 @@ bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r
int getTransformOrientation_ex(const struct bContext *C, float normal[3], float plane[3], const short around);
int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
+void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
+
void freeEdgeSlideTempFaces(EdgeSlideData *sld);
-void freeEdgeSlideVerts(TransInfo *t, TransCustomData *custom_data);
+void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
void projectEdgeSlideData(TransInfo *t, bool is_final);
void freeVertSlideTempFaces(VertSlideData *sld);
-void freeVertSlideVerts(TransInfo *t, TransCustomData *custom_data);
+void freeVertSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
void projectVertSlideData(TransInfo *t, bool is_final);
/* TODO. transform_query.c */
bool checkUseAxisMatrix(TransInfo *t);
-#define TRANSFORM_DIST_MAX_PX 1000.0f
#define TRANSFORM_SNAP_MAX_PX 100.0f
#define TRANSFORM_DIST_INVALID -FLT_MAX
+/* Temp macros. */
+
+#define TRANS_DATA_CONTAINER_FIRST_OK(t) (&(t)->data_container[0])
+/* For cases we _know_ there is only one handle. */
+#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t) (BLI_assert((t)->data_container_len == 1), (&(t)->data_container[0]))
+
+#define FOREACH_TRANS_DATA_CONTAINER(t, th) \
+ for (TransDataContainer *tc = t->data_container, *tc_end = t->data_container + t->data_container_len; \
+ th != tc_end; \
+ th++)
+
+#define FOREACH_TRANS_DATA_CONTAINER_INDEX(t, th, i) \
+ for (TransDataContainer *tc = ((i = 0), t->data_container), *tc_end = t->data_container + t->data_container_len; \
+ th != tc_end; \
+ th++, i++)
+
#endif
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 719a6e11ce7..fe997b77a31 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -40,9 +40,12 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
@@ -333,15 +336,15 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
*
*/
-static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3], float out[3], float pvec[3])
+static void applyAxisConstraintVec(
+ TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3], float pvec[3])
{
copy_v3_v3(out, in);
if (!td && t->con.mode & CON_APPLY) {
mul_m3_v3(t->con.pmtx, out);
// With snap, a projection is alright, no need to correct for view alignment
- if (!(!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t))) {
-
+ if (!validSnap(t)) {
const int dims = getConstraintSpaceDimension(t);
if (dims == 2) {
if (!is_zero_v3(out)) {
@@ -380,7 +383,8 @@ static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3
* Further down, that vector is mapped to each data's space.
*/
-static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in[3], float out[3], float pvec[3])
+static void applyObjectConstraintVec(
+ TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3], float pvec[3])
{
copy_v3_v3(out, in);
if (t->con.mode & CON_APPLY) {
@@ -428,7 +432,7 @@ static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in
mul_m3_v3(td->axismtx, out);
if (t->flag & T_EDIT) {
- mul_m3_v3(t->obedit_mat, out);
+ mul_m3_v3(tc->mat3_unit, out);
}
}
}
@@ -438,7 +442,8 @@ static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in
* Generic callback for constant spatial constraints applied to resize motion
*/
-static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
+static void applyAxisConstraintSize(
+ TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, float smat[3][3])
{
if (!td && t->con.mode & CON_APPLY) {
float tmat[3][3];
@@ -462,7 +467,8 @@ static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3
* Callback for object based spatial constraints applied to resize motion
*/
-static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
+static void applyObjectConstraintSize(
+ TransInfo *t, TransDataContainer *tc, TransData *td, float smat[3][3])
{
if (td && t->con.mode & CON_APPLY) {
float tmat[3][3];
@@ -482,7 +488,7 @@ static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3]
mul_m3_m3m3(tmat, smat, imat);
if (t->flag & T_EDIT) {
- mul_m3_m3m3(smat, t->obedit_mat, smat);
+ mul_m3_m3m3(smat, tc->mat3_unit, smat);
}
mul_m3_m3m3(smat, td->axismtx, tmat);
}
@@ -502,7 +508,7 @@ static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3]
* (ie: not doing counterclockwise rotations when the mouse moves clockwise).
*/
-static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
+static void applyAxisConstraintRot(TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, float vec[3], float *angle)
{
if (!td && t->con.mode & CON_APPLY) {
int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2);
@@ -544,7 +550,8 @@ static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], fl
* (ie: not doing counterclockwise rotations when the mouse moves clockwise).
*/
-static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
+static void applyObjectConstraintRot(
+ TransInfo *t, TransDataContainer *tc, TransData *td, float vec[3], float *angle)
{
if (t->con.mode & CON_APPLY) {
int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2);
@@ -553,11 +560,13 @@ static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3],
/* on setup call, use first object */
if (td == NULL) {
- td = t->data;
+ BLI_assert(tc == NULL);
+ tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
+ td = tc->data;
}
if (t->flag & T_EDIT) {
- mul_m3_m3m3(tmp_axismtx, t->obedit_mat, td->axismtx);
+ mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx);
axismtx = tmp_axismtx;
}
else {
@@ -607,20 +616,21 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
/* applies individual td->axismtx constraints */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
{
- if (t->total == 1) {
+ TransDataContainer *tc = t->data_container;
+ if (t->data_len_all == 1) {
float axismtx[3][3];
if (t->flag & T_EDIT) {
- mul_m3_m3m3(axismtx, t->obedit_mat, t->data->axismtx);
+ mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx);
}
else {
- copy_m3_m3(axismtx, t->data->axismtx);
+ copy_m3_m3(axismtx, tc->data->axismtx);
}
setConstraint(t, axismtx, mode, text);
}
else {
BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
- copy_m3_m3(t->con.mtx, t->data->axismtx);
+ copy_m3_m3(t->con.mtx, tc->data->axismtx);
t->con.mode = mode;
getConstraintMatrix(t);
@@ -638,7 +648,9 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
{
/* edit-mode now allows local transforms too */
if (t->flag & T_EDIT) {
- setConstraint(t, t->obedit_mat, mode, text);
+ /* Use the active (first) edit object. */
+ TransDataContainer *tc = t->data_container;
+ setConstraint(t, tc->mat3_unit, mode, text);
}
else {
setAxisMatrixConstraint(t, mode, text);
@@ -653,7 +665,7 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
*/
void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[])
{
- char text[40];
+ char text[256];
switch (orientation) {
case V3D_MANIP_GLOBAL:
@@ -681,14 +693,27 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte
BLI_snprintf(text, sizeof(text), ftext, IFACE_("view"));
setConstraint(t, t->spacemtx, mode, text);
break;
+ case V3D_MANIP_CURSOR:
+ BLI_snprintf(text, sizeof(text), ftext, IFACE_("cursor"));
+ setConstraint(t, t->spacemtx, mode, text);
+ break;
case V3D_MANIP_GIMBAL:
BLI_snprintf(text, sizeof(text), ftext, IFACE_("gimbal"));
setConstraint(t, t->spacemtx, mode, text);
break;
- default: /* V3D_MANIP_CUSTOM */
- BLI_snprintf(text, sizeof(text), ftext, t->spacename);
+ case V3D_MANIP_CUSTOM_MATRIX:
+ BLI_snprintf(text, sizeof(text), ftext, IFACE_("custom matrix"));
+ setConstraint(t, t->spacemtx, mode, text);
+ break;
+ case V3D_MANIP_CUSTOM:
+ {
+ char orientation_str[128];
+ BLI_snprintf(orientation_str, sizeof(orientation_str), "%s \"%s\"",
+ IFACE_("custom orientation"), t->orientation.custom->name);
+ BLI_snprintf(text, sizeof(text), ftext, orientation_str);
setConstraint(t, t->spacemtx, mode, text);
break;
+ }
}
t->con.orientation = orientation;
@@ -706,8 +731,6 @@ void drawConstraint(TransInfo *t)
return;
if (!(tc->mode & CON_APPLY))
return;
- if (t->flag & T_USES_MANIPULATOR)
- return;
if (t->flag & T_NO_CONSTRAINT)
return;
@@ -717,7 +740,6 @@ void drawConstraint(TransInfo *t)
else {
if (tc->mode & CON_SELECT) {
float vec[3];
- char col2[3] = {255, 255, 255};
int depth_test_enabled;
convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1]));
@@ -727,21 +749,32 @@ void drawConstraint(TransInfo *t)
drawLine(t, t->center_global, tc->mtx[1], 'Y', 0);
drawLine(t, t->center_global, tc->mtx[2], 'Z', 0);
- glColor3ubv((GLubyte *)col2);
-
- depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
+ depth_test_enabled = GPU_depth_test_enabled();
if (depth_test_enabled)
- glDisable(GL_DEPTH_TEST);
+ GPU_depth_test(false);
+
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
- setlinestyle(1);
- glBegin(GL_LINES);
- glVertex3fv(t->center_global);
- glVertex3fv(vec);
- glEnd();
- setlinestyle(0);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ immUniform1f("dash_width", 2.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, t->center_global);
+ immVertex3fv(shdr_pos, vec);
+ immEnd();
+
+ immUnbindProgram();
if (depth_test_enabled)
- glEnable(GL_DEPTH_TEST);
+ GPU_depth_test(true);
}
if (tc->mode & CON_AXIS0) {
@@ -764,8 +797,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
float tmat[4][4], imat[4][4];
int depth_test_enabled;
- UI_ThemeColor(TH_GRID);
-
if (t->spacetype == SPACE_VIEW3D && rv3d != NULL) {
copy_m4_m4(tmat, rv3d->viewmat);
invert_m4_m4(imat, tmat);
@@ -775,13 +806,13 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
unit_m4(imat);
}
- glPushMatrix();
+ GPU_matrix_push();
if (t->spacetype == SPACE_VIEW3D) {
/* pass */
}
else if (t->spacetype == SPACE_IMAGE) {
- glScalef(1.0f / t->aspect[0], 1.0f / t->aspect[1], 1.0f);
+ GPU_matrix_scale_2f(1.0f / t->aspect[0], 1.0f / t->aspect[1]);
}
else if (ELEM(t->spacetype, SPACE_IPO, SPACE_ACTION)) {
/* only scale y */
@@ -791,21 +822,28 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
float ysize = BLI_rctf_size_y(datamask);
float xmask = BLI_rcti_size_x(mask);
float ymask = BLI_rcti_size_y(mask);
- glScalef(1.0f, (ysize / xsize) * (xmask / ymask), 1.0f);
+ GPU_matrix_scale_2f(1.0f, (ysize / xsize) * (xmask / ymask));
}
- depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
+ depth_test_enabled = GPU_depth_test_enabled();
if (depth_test_enabled)
- glDisable(GL_DEPTH_TEST);
+ GPU_depth_test(false);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColor(TH_GRID);
set_inverted_drawing(1);
- drawcircball(GL_LINE_LOOP, t->center_global, t->prop_size, imat);
+ imm_drawcircball(t->center_global, t->prop_size, imat, pos);
set_inverted_drawing(0);
+ immUnbindProgram();
+
if (depth_test_enabled)
- glEnable(GL_DEPTH_TEST);
+ GPU_depth_test(true);
- glPopMatrix();
+ GPU_matrix_pop();
}
}
@@ -818,57 +856,59 @@ static void drawObjectConstraint(TransInfo *t)
* Without drawing the first light, users have little clue what they are doing.
*/
short options = DRAWLIGHT;
- TransData *td = t->data;
int i;
float tmp_axismtx[3][3];
- for (i = 0; i < t->total; i++, td++) {
- float co[3];
- float (*axismtx)[3];
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float co[3];
+ float (*axismtx)[3];
- if (t->flag & T_PROP_EDIT) {
- /* we're sorted, so skip the rest */
- if (td->factor == 0.0f) {
- break;
+ if (t->flag & T_PROP_EDIT) {
+ /* we're sorted, so skip the rest */
+ if (td->factor == 0.0f) {
+ break;
+ }
}
- }
- if (t->options & CTX_GPENCIL_STROKES) {
- /* only draw a constraint line for one point, otherwise we can't see anything */
- if ((options & DRAWLIGHT) == 0) {
- break;
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* only draw a constraint line for one point, otherwise we can't see anything */
+ if ((options & DRAWLIGHT) == 0) {
+ break;
+ }
}
- }
- if (t->flag & T_OBJECT) {
- copy_v3_v3(co, td->ob->obmat[3]);
- axismtx = td->axismtx;
- }
- else if (t->flag & T_EDIT) {
- mul_v3_m4v3(co, t->obedit->obmat, td->center);
+ if (t->flag & T_OBJECT) {
+ copy_v3_v3(co, td->ob->obmat[3]);
+ axismtx = td->axismtx;
+ }
+ else if (t->flag & T_EDIT) {
+ mul_v3_m4v3(co, tc->mat, td->center);
- mul_m3_m3m3(tmp_axismtx, t->obedit_mat, td->axismtx);
- axismtx = tmp_axismtx;
- }
- else if (t->flag & T_POSE) {
- mul_v3_m4v3(co, t->poseobj->obmat, td->center);
- axismtx = td->axismtx;
- }
- else {
- copy_v3_v3(co, td->center);
- axismtx = td->axismtx;
- }
+ mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx);
+ axismtx = tmp_axismtx;
+ }
+ else if (t->flag & T_POSE) {
+ mul_v3_m4v3(co, tc->mat, td->center);
+ axismtx = td->axismtx;
+ }
+ else {
+ copy_v3_v3(co, td->center);
+ axismtx = td->axismtx;
+ }
- if (t->con.mode & CON_AXIS0) {
- drawLine(t, co, axismtx[0], 'X', options);
- }
- if (t->con.mode & CON_AXIS1) {
- drawLine(t, co, axismtx[1], 'Y', options);
- }
- if (t->con.mode & CON_AXIS2) {
- drawLine(t, co, axismtx[2], 'Z', options);
+ if (t->con.mode & CON_AXIS0) {
+ drawLine(t, co, axismtx[0], 'X', options);
+ }
+ if (t->con.mode & CON_AXIS1) {
+ drawLine(t, co, axismtx[1], 'Y', options);
+ }
+ if (t->con.mode & CON_AXIS2) {
+ drawLine(t, co, axismtx[2], 'Z', options);
+ }
+ options &= ~DRAWLIGHT;
}
- options &= ~DRAWLIGHT;
}
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index da4ee21ff6f..0fca84074f5 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -61,17 +61,16 @@
#include "BLI_bitmap.h"
#include "BLI_rect.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_layer.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -91,6 +90,7 @@
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
#include "BKE_mask.h"
+#include "BKE_colortools.h"
#include "BIK_api.h"
@@ -118,6 +118,8 @@
#include "RNA_access.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "transform.h"
#include "bmesh.h"
@@ -128,7 +130,7 @@
*/
static void transform_around_single_fallback(TransInfo *t)
{
- if ((t->total == 1) &&
+ if ((t->data_len_all == 1) &&
(ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEAN, V3D_AROUND_ACTIVE)) &&
(ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL)))
{
@@ -167,29 +169,38 @@ static int trans_data_compare_rdist(const void *a, const void *b)
else return 0;
}
-void sort_trans_data_dist(TransInfo *t)
+static void sort_trans_data_dist_container(const TransInfo *t, TransDataContainer *tc)
{
- TransData *start = t->data;
+ TransData *start = tc->data;
int i;
- for (i = 0; i < t->total && start->flag & TD_SELECTED; i++)
+ for (i = 0; i < tc->data_len && start->flag & TD_SELECTED; i++) {
start++;
+ }
- if (i < t->total) {
- if (t->flag & T_PROP_CONNECTED)
- qsort(start, t->total - i, sizeof(TransData), trans_data_compare_dist);
- else
- qsort(start, t->total - i, sizeof(TransData), trans_data_compare_rdist);
+ if (i < tc->data_len) {
+ if (t->flag & T_PROP_CONNECTED) {
+ qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_dist);
+ }
+ else {
+ qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_rdist);
+ }
+ }
+}
+void sort_trans_data_dist(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sort_trans_data_dist_container(t, tc);
}
}
-static void sort_trans_data(TransInfo *t)
+static void sort_trans_data_container(TransDataContainer *tc)
{
TransData *sel, *unsel;
TransData temp;
- unsel = t->data;
- sel = t->data;
- sel += t->total - 1;
+ unsel = tc->data;
+ sel = tc->data;
+ sel += tc->data_len - 1;
while (sel > unsel) {
while (unsel->flag & TD_SELECTED) {
unsel++;
@@ -210,12 +221,17 @@ static void sort_trans_data(TransInfo *t)
unsel++;
}
}
+static void sort_trans_data(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sort_trans_data_container(tc);
+ }
+}
/* distance calculated from not-selected vertex to nearest selected vertex
* warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
static void set_prop_dist(TransInfo *t, const bool with_dist)
{
- TransData *tob;
int a;
float _proj_vec[3];
@@ -232,49 +248,52 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
}
}
- for (a = 0, tob = t->data; a < t->total; a++, tob++) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *tob = tc->data;
+ for (a = 0; a < tc->data_len; a++, tob++) {
- tob->rdist = 0.0f; // init, it was mallocced
+ tob->rdist = 0.0f; // init, it was mallocced
- if ((tob->flag & TD_SELECTED) == 0) {
- TransData *td;
- int i;
- float dist_sq, vec[3];
+ if ((tob->flag & TD_SELECTED) == 0) {
+ TransData *td;
+ int i;
+ float dist_sq, vec[3];
- tob->rdist = -1.0f; // signal for next loop
+ tob->rdist = -1.0f; // signal for next loop
- for (i = 0, td = t->data; i < t->total; i++, td++) {
- if (td->flag & TD_SELECTED) {
- if (use_island) {
- sub_v3_v3v3(vec, tob->iloc, td->iloc);
- }
- else {
- sub_v3_v3v3(vec, tob->center, td->center);
- }
- mul_m3_v3(tob->mtx, vec);
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_SELECTED) {
+ if (use_island) {
+ sub_v3_v3v3(vec, tob->iloc, td->iloc);
+ }
+ else {
+ sub_v3_v3v3(vec, tob->center, td->center);
+ }
+ mul_m3_v3(tob->mtx, vec);
- if (proj_vec) {
- float vec_p[3];
- project_v3_v3v3(vec_p, vec, proj_vec);
- sub_v3_v3(vec, vec_p);
- }
+ if (proj_vec) {
+ float vec_p[3];
+ project_v3_v3v3(vec_p, vec, proj_vec);
+ sub_v3_v3(vec, vec_p);
+ }
- dist_sq = len_squared_v3(vec);
- if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) {
- tob->rdist = sqrtf(dist_sq);
- if (use_island) {
- copy_v3_v3(tob->center, td->center);
- copy_m3_m3(tob->axismtx, td->axismtx);
+ dist_sq = len_squared_v3(vec);
+ if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) {
+ tob->rdist = sqrtf(dist_sq);
+ if (use_island) {
+ copy_v3_v3(tob->center, td->center);
+ copy_m3_m3(tob->axismtx, td->axismtx);
+ }
}
}
+ else {
+ break; /* by definition transdata has selected items in beginning */
+ }
}
- else {
- break; /* by definition transdata has selected items in beginning */
+ if (with_dist) {
+ tob->dist = tob->rdist;
}
}
- if (with_dist) {
- tob->dist = tob->rdist;
- }
}
}
}
@@ -285,35 +304,37 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
static void createTransTexspace(TransInfo *t)
{
- Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
TransData *td;
Object *ob;
ID *id;
short *texflag;
- ob = OBACT;
+ ob = OBACT(view_layer);
if (ob == NULL) { // Shouldn't logically happen, but still...
- t->total = 0;
return;
}
id = ob->data;
if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
- t->total = 0;
return;
}
if (BKE_object_obdata_is_libdata(ob)) {
BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
- t->total = 0;
return;
}
- t->total = 1;
- td = t->data = MEM_callocN(sizeof(TransData), "TransTexspace");
- td->ext = t->ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+ }
td->flag = TD_SELECTED;
copy_v3_v3(td->center, ob->obmat[3]);
@@ -334,76 +355,151 @@ static void createTransTexspace(TransInfo *t)
copy_v3_v3(td->ext->isize, td->ext->size);
}
-/* ********************* edge (for crease) ***** */
+/* -------------------------------------------------------------------- */
+/** \name Cursor Transform Creation
+ *
+ * Instead of transforming the selection, move the 2D/3D cursor.
+ *
+ * \{ */
-static void createTransEdge(TransInfo *t)
+static void createTransCursor_image(TransInfo *t)
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
- TransData *td = NULL;
- BMEdge *eed;
- BMIter iter;
- float mtx[3][3], smtx[3][3];
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- int cd_edge_float_offset;
+ TransData *td;
+ SpaceImage *sima = t->sa->spacedata.first;
+ float *cursor_location = sima->cursor;
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
- if (is_prop_edit) count++;
- }
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
}
- if (countsel == 0)
- return;
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, cursor_location);
+ td->ob = NULL;
- if (is_prop_edit) {
- t->total = count;
- }
- else {
- t->total = countsel;
- }
+ unit_m3(td->mtx);
+ unit_m3(td->axismtx);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransCrease");
+ td->loc = cursor_location;
+ copy_v3_v3(td->iloc, cursor_location);
+}
- copy_m3_m4(mtx, t->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+static void createTransCursor_view3d(TransInfo *t)
+{
+ TransData *td;
- /* create data we need */
- if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_EDGE_BWEIGHT);
- cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
+ Scene *scene = t->scene;
+ if (ID_IS_LINKED(scene)) {
+ BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
+ return;
}
- else { //if (t->mode == TFM_CREASE) {
- BLI_assert(t->mode == TFM_CREASE);
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_EDGE_CREASE);
- cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
+
+ View3DCursor *cursor = &scene->cursor;
+ {
+ BLI_assert(t->data_container_len == 1);
+ TransDataContainer *tc = t->data_container;
+ tc->data_len = 1;
+ td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
}
- BLI_assert(cd_edge_float_offset != -1);
+ td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, cursor->location);
+ td->ob = NULL;
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
- float *fl_ptr;
- /* need to set center for center calculations */
- mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
+ unit_m3(td->mtx);
+ quat_to_mat3(td->axismtx, cursor->rotation);
+ normalize_m3(td->axismtx);
+ pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
- td->loc = NULL;
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT))
- td->flag = TD_SELECTED;
- else
- td->flag = 0;
+ td->loc = cursor->location;
+ copy_v3_v3(td->iloc, cursor->location);
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
+ td->ext->quat = cursor->rotation;
+ copy_qt_qt(td->ext->iquat, cursor->rotation);
+}
- td->ext = NULL;
+/** \} */
- fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
- td->val = fl_ptr;
- td->ival = *fl_ptr;
+/* ********************* edge (for crease) ***** */
- td++;
+static void createTransEdge(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ TransData *td = NULL;
+ BMEdge *eed;
+ BMIter iter;
+ float mtx[3][3], smtx[3][3];
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ int cd_edge_float_offset;
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
+ if (is_prop_edit) count++;
+ }
+ }
+
+ if (countsel == 0) {
+ tc->data_len = 0;
+ continue;
+ }
+
+ if (is_prop_edit) {
+ tc->data_len = count;
+ }
+ else {
+ tc->data_len = countsel;
+ }
+
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease");
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ /* create data we need */
+ if (t->mode == TFM_BWEIGHT) {
+ BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
+ cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
+ }
+ else { //if (t->mode == TFM_CREASE) {
+ BLI_assert(t->mode == TFM_CREASE);
+ BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
+ cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
+ }
+
+ BLI_assert(cd_edge_float_offset != -1);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
+ float *fl_ptr;
+ /* need to set center for center calculations */
+ mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
+
+ td->loc = NULL;
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT))
+ td->flag = TD_SELECTED;
+ else
+ td->flag = 0;
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+
+ td->ext = NULL;
+
+ fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
+ td->val = fl_ptr;
+ td->ival = *fl_ptr;
+
+ td++;
+ }
}
}
}
@@ -521,7 +617,7 @@ static short apply_targetless_ik(Object *ob)
return apply;
}
-static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td)
+static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
{
Bone *bone = pchan->bone;
float pmat[3][3], omat[3][3];
@@ -632,7 +728,7 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
normalize_m3(td->axismtx);
if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- bArmature *arm = t->poseobj->data;
+ bArmature *arm = tc->poseobj->data;
if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
td->loc = NULL;
@@ -695,12 +791,11 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
/* sets transform flags in the bones
* returns total number of bones with BONE_TRANSFORM */
-int count_set_pose_transflags(int *out_mode, short around, Object *ob)
+int count_set_pose_transflags(Object *ob, const int mode, const short around, bool has_translate_rotate[2])
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
Bone *bone;
- int mode = *out_mode;
int total = 0;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -728,42 +823,34 @@ 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 */
- bool has_translation = false, has_rotation = false;
-
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
if (bone->flag & BONE_TRANSFORM) {
total++;
- if (mode == TFM_TRANSLATION) {
+ if (has_translate_rotate != NULL) {
if (has_targetless_ik(pchan) == NULL) {
if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
- if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM)
- has_translation = true;
+ if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
+ has_translate_rotate[0] = true;
+ }
}
else {
- if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC)
- has_translation = true;
+ if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
+ has_translate_rotate[0] = true;
+ }
+ }
+ if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
+ has_translate_rotate[1] = true;
}
- if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT)
- has_rotation = true;
}
- else
- has_translation = true;
+ else {
+ has_translate_rotate[0] = true;
+ }
}
}
}
- /* if there are no translatable bones, do rotation */
- if (mode == TFM_TRANSLATION && !has_translation) {
- if (has_rotation) {
- *out_mode = TFM_ROTATION;
- }
- else {
- *out_mode = TFM_RESIZE;
- }
- }
-
return total;
}
@@ -828,25 +915,25 @@ void transform_autoik_update(TransInfo *t, short mode)
}
}
- /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
- if (ELEM(NULL, t->poseobj, t->poseobj->pose))
- return;
-
/* apply to all pose-channels */
bool changed = false;
- for (pchan = t->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
- changed |= pchan_autoik_adjust(pchan, *chainlen);
- }
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!DEG_depsgraph_use_legacy())
-#endif
- {
- if (changed) {
- /* TODO(sergey): Consider doing partial update only. */
- DAG_relations_tag_update(bmain);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
+ if (ELEM(NULL, tc->poseobj, tc->poseobj->pose)) {
+ continue;
+ }
+
+ for (pchan = tc->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
+ changed |= pchan_autoik_adjust(pchan, *chainlen);
}
}
+
+ if (changed) {
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+ }
}
/* frees temporal IKs */
@@ -855,9 +942,7 @@ static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
bKinematicConstraint *data;
bPoseChannel *pchan;
bConstraint *con, *next;
-#ifdef WITH_LEGACY_DEPSGRAPH
- bool need_dependency_update = false;
-#endif
+ bool relations_changed = false;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* clear all temporary lock flags */
@@ -871,10 +956,9 @@ static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
data = con->data;
if (data->flag & CONSTRAINT_IK_TEMP) {
+ relations_changed = true;
+
/* iTaSC needs clear for removed constraints */
-#ifdef WITH_LEGACY_DEPSGRAPH
- need_dependency_update = true;
-#endif
BIK_clear_data(ob->pose);
BLI_remlink(&pchan->constraints, con);
@@ -889,12 +973,9 @@ static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
}
}
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!DEG_depsgraph_use_legacy() && need_dependency_update)
-#endif
- {
+ if (relations_changed) {
/* TODO(sergey): Consider doing partial update only. */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
}
@@ -1048,89 +1129,115 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
/* iTaSC needs clear for new IK constraints */
if (tot_ik) {
BIK_clear_data(ob->pose);
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!DEG_depsgraph_use_legacy())
-#endif
- {
- /* TODO(sergey): Consider doing partial update only. */
- DAG_relations_tag_update(bmain);
- }
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
}
return (tot_ik) ? 1 : 0;
}
-/* only called with pose mode active object now */
-static void createTransPose(TransInfo *t, Object *ob)
+/**
+ * When objects array is NULL, use 't->data_container' as is.
+ */
+static void createTransPose(TransInfo *t)
{
Main *bmain = CTX_data_main(t->context);
- bArmature *arm;
- bPoseChannel *pchan;
- TransData *td;
- TransDataExtension *tdx;
- short ik_on = 0;
- int i;
- t->total = 0;
+ t->data_len_all = 0;
- /* check validity of state */
- arm = BKE_armature_from_object(ob);
- if ((arm == NULL) || (ob->pose == NULL)) return;
+ bool has_translate_rotate_buf[2] = {false, false};
+ bool *has_translate_rotate = (t->mode == TFM_TRANSLATION) ? has_translate_rotate_buf : NULL;
- if (arm->flag & ARM_RESTPOS) {
- if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
- BKE_report(t->reports, RPT_ERROR, "Cannot change Pose when 'Rest Position' is enabled");
- return;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->poseobj;
+
+ bArmature *arm;
+ short ik_on = 0;
+
+ /* check validity of state */
+ arm = BKE_armature_from_object(tc->poseobj);
+ if ((arm == NULL) || (ob->pose == NULL)) {
+ continue;
+ }
+
+ if (arm->flag & ARM_RESTPOS) {
+ if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
+ BKE_report(t->reports, RPT_ERROR, "Cannot change Pose when 'Rest Position' is enabled");
+ return;
+ }
+ }
+
+ /* do we need to add temporal IK chains? */
+ if ((arm->flag & ARM_AUTO_IK) && t->mode == TFM_TRANSLATION) {
+ ik_on = pose_grab_with_ik(bmain, ob);
+ if (ik_on) t->flag |= T_AUTOIK;
}
+
+ /* set flags and count total (warning, can change transform to rotate) */
+ tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
+ /* len may be zero, skip next iteration. */
}
- /* do we need to add temporal IK chains? */
- if ((arm->flag & ARM_AUTO_IK) && t->mode == TFM_TRANSLATION) {
- ik_on = pose_grab_with_ik(bmain, ob);
- if (ik_on) t->flag |= T_AUTOIK;
+ /* if there are no translatable bones, do rotation */
+ if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
+ if (has_translate_rotate[1]) {
+ t->mode = TFM_ROTATION;
+ }
+ else {
+ t->mode = TFM_RESIZE;
+ }
}
- /* set flags and count total (warning, can change transform to rotate) */
- t->total = count_set_pose_transflags(&t->mode, t->around, ob);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len == 0) {
+ continue;
+ }
+ Object *ob = tc->poseobj;
+ TransData *td;
+ TransDataExtension *tdx;
+ short ik_on = 0;
+ int i;
- if (t->total == 0) return;
+ tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
- t->flag |= T_POSE;
- t->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
+ /* init trans data */
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransPoseBone");
+ tdx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransPoseBoneExt");
+ for (i = 0; i < tc->data_len; i++, td++, tdx++) {
+ td->ext = tdx;
+ td->val = NULL;
+ }
- /* disable PET, its not usable in pose mode yet [#32444] */
- t->flag &= ~T_PROP_EDIT_ALL;
+ /* use pose channels to fill trans data */
+ td = tc->data;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ add_pose_transdata(t, pchan, ob, tc, td);
+ td++;
+ }
+ }
- /* init trans data */
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransPoseBone");
- tdx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "TransPoseBoneExt");
- for (i = 0; i < t->total; i++, td++, tdx++) {
- td->ext = tdx;
- td->val = NULL;
- }
+ if (td != (tc->data + tc->data_len)) {
+ BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
+ }
- /* use pose channels to fill trans data */
- td = t->data;
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- add_pose_transdata(t, pchan, ob, td);
- td++;
+ /* initialize initial auto=ik chainlen's? */
+ if (ik_on) {
+ transform_autoik_update(t, 0);
}
}
- if (td != (t->data + t->total)) {
- BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
- }
+ t->flag |= T_POSE;
+ /* disable PET, its not usable in pose mode yet [#32444] */
+ t->flag &= ~T_PROP_EDIT_ALL;
- /* initialize initial auto=ik chainlen's? */
- if (ik_on) transform_autoik_update(t, 0);
}
-void restoreBones(TransInfo *t)
+void restoreBones(TransDataContainer *tc)
{
- bArmature *arm = t->obedit->data;
- BoneInitData *bid = t->custom.type.data;
+ bArmature *arm = tc->obedit->data;
+ BoneInitData *bid = tc->custom.type.data;
EditBone *ebo;
while (bid->bone) {
@@ -1171,226 +1278,230 @@ void restoreBones(TransInfo *t)
/* ********************* armature ************** */
static void createTransArmatureVerts(TransInfo *t)
{
- EditBone *ebo, *eboflip;
- bArmature *arm = t->obedit->data;
- ListBase *edbo = arm->edbo;
- TransData *td, *td_old;
- float mtx[3][3], smtx[3][3], bonemat[3][3];
- bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
- int total_mirrored = 0, i;
- int oldtot;
- BoneInitData *bid;
-
- t->total = 0;
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- oldtot = t->total;
-
- if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- if (ebo->flag & BONE_SELECTED)
- t->total++;
- }
- else if (t->mode == TFM_BONE_ROLL) {
- if (ebo->flag & BONE_SELECTED)
- t->total++;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EditBone *ebo, *eboflip;
+ bArmature *arm = tc->obedit->data;
+ ListBase *edbo = arm->edbo;
+ TransData *td, *td_old;
+ float mtx[3][3], smtx[3][3], bonemat[3][3];
+ bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
+ int total_mirrored = 0, i;
+ int oldtot;
+ BoneInitData *bid = NULL;
+
+ tc->data_len = 0;
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ oldtot = tc->data_len;
+
+ if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
+ if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ if (ebo->flag & BONE_SELECTED)
+ tc->data_len++;
+ }
+ else if (t->mode == TFM_BONE_ROLL) {
+ if (ebo->flag & BONE_SELECTED)
+ tc->data_len++;
+ }
+ else {
+ if (ebo->flag & BONE_TIPSEL)
+ tc->data_len++;
+ if (ebo->flag & BONE_ROOTSEL)
+ tc->data_len++;
+ }
}
- else {
- if (ebo->flag & BONE_TIPSEL)
- t->total++;
- if (ebo->flag & BONE_ROOTSEL)
- t->total++;
+
+ if (mirror && (oldtot < tc->data_len)) {
+ eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
+ if (eboflip)
+ total_mirrored++;
}
}
- if (mirror && (oldtot < t->total)) {
- eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
- if (eboflip)
- total_mirrored++;
+ if (!tc->data_len) {
+ continue;
}
- }
- if (!t->total) return;
+ transform_around_single_fallback(t);
- transform_around_single_fallback(t);
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- copy_m3_m4(mtx, t->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone");
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransEditBone");
+ if (mirror) {
+ tc->custom.type.data = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
+ tc->custom.type.use_free = true;
+ }
- if (mirror) {
- t->custom.type.data = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
- t->custom.type.use_free = true;
- }
+ i = 0;
- i = 0;
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ td_old = td;
+ ebo->oldlength = ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- td_old = td;
- ebo->oldlength = ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
+ if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
+ if (t->mode == TFM_BONE_ENVELOPE) {
+ if (ebo->flag & BONE_ROOTSEL) {
+ td->val = &ebo->rad_head;
+ td->ival = *td->val;
- if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
- if (t->mode == TFM_BONE_ENVELOPE) {
- if (ebo->flag & BONE_ROOTSEL) {
- td->val = &ebo->rad_head;
- td->ival = *td->val;
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
+ td->loc = NULL;
+ td->ext = NULL;
+ td->ob = tc->obedit;
- td->loc = NULL;
- td->ext = NULL;
- td->ob = t->obedit;
+ td++;
+ }
+ if (ebo->flag & BONE_TIPSEL) {
+ td->val = &ebo->rad_tail;
+ td->ival = *td->val;
+ copy_v3_v3(td->center, ebo->tail);
+ td->flag = TD_SELECTED;
- td++;
- }
- if (ebo->flag & BONE_TIPSEL) {
- td->val = &ebo->rad_tail;
- td->ival = *td->val;
- copy_v3_v3(td->center, ebo->tail);
- td->flag = TD_SELECTED;
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
+ td->loc = NULL;
+ td->ext = NULL;
+ td->ob = tc->obedit;
- td->loc = NULL;
- td->ext = NULL;
- td->ob = t->obedit;
+ td++;
+ }
- td++;
}
+ else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
+ if (ebo->flag & BONE_SELECTED) {
+ if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
+ td->loc = NULL;
+ td->val = &ebo->dist;
+ td->ival = ebo->dist;
+ }
+ else {
+ // abusive storage of scale in the loc pointer :)
+ td->loc = &ebo->xwidth;
+ copy_v3_v3(td->iloc, td->loc);
+ td->val = NULL;
+ }
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
- }
- else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
- if (ebo->flag & BONE_SELECTED) {
- if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
- td->loc = NULL;
- td->val = &ebo->dist;
- td->ival = ebo->dist;
- }
- else {
- // abusive storage of scale in the loc pointer :)
- td->loc = &ebo->xwidth;
- copy_v3_v3(td->iloc, td->loc);
- td->val = NULL;
- }
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
-
- /* use local bone matrix */
- ED_armature_ebone_to_mat3(ebo, bonemat);
- mul_m3_m3m3(td->mtx, mtx, bonemat);
- invert_m3_m3(td->smtx, td->mtx);
+ /* use local bone matrix */
+ ED_armature_ebone_to_mat3(ebo, bonemat);
+ mul_m3_m3m3(td->mtx, mtx, bonemat);
+ invert_m3_m3(td->smtx, td->mtx);
- copy_m3_m3(td->axismtx, td->mtx);
- normalize_m3(td->axismtx);
+ copy_m3_m3(td->axismtx, td->mtx);
+ normalize_m3(td->axismtx);
- td->ext = NULL;
- td->ob = t->obedit;
+ td->ext = NULL;
+ td->ob = tc->obedit;
- td++;
+ td++;
+ }
}
- }
- else if (t->mode == TFM_BONE_ROLL) {
- if (ebo->flag & BONE_SELECTED) {
- td->loc = NULL;
- td->val = &(ebo->roll);
- td->ival = ebo->roll;
+ else if (t->mode == TFM_BONE_ROLL) {
+ if (ebo->flag & BONE_SELECTED) {
+ td->loc = NULL;
+ td->val = &(ebo->roll);
+ td->ival = ebo->roll;
- copy_v3_v3(td->center, ebo->head);
- td->flag = TD_SELECTED;
+ copy_v3_v3(td->center, ebo->head);
+ td->flag = TD_SELECTED;
- td->ext = NULL;
- td->ob = t->obedit;
+ td->ext = NULL;
+ td->ob = tc->obedit;
- td++;
- }
- }
- else {
- if (ebo->flag & BONE_TIPSEL) {
- copy_v3_v3(td->iloc, ebo->tail);
-
- /* Don't allow single selected tips to have a modified center,
- * causes problem with snapping (see T45974).
- * However, in rotation mode, we want to keep that 'rotate bone around root with
- * only its tip selected' behavior (see T46325). */
- if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL)))
- {
- copy_v3_v3(td->center, ebo->head);
- }
- else {
- copy_v3_v3(td->center, td->iloc);
+ td++;
}
+ }
+ else {
+ if (ebo->flag & BONE_TIPSEL) {
+ copy_v3_v3(td->iloc, ebo->tail);
+
+ /* Don't allow single selected tips to have a modified center,
+ * causes problem with snapping (see T45974).
+ * However, in rotation mode, we want to keep that 'rotate bone around root with
+ * only its tip selected' behavior (see T46325). */
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL)))
+ {
+ copy_v3_v3(td->center, ebo->head);
+ }
+ else {
+ copy_v3_v3(td->center, td->iloc);
+ }
- td->loc = ebo->tail;
- td->flag = TD_SELECTED;
- if (ebo->flag & BONE_EDITMODE_LOCKED)
- td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
+ td->loc = ebo->tail;
+ td->flag = TD_SELECTED;
+ if (ebo->flag & BONE_EDITMODE_LOCKED)
+ td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
- ED_armature_ebone_to_mat3(ebo, td->axismtx);
+ ED_armature_ebone_to_mat3(ebo, td->axismtx);
- if ((ebo->flag & BONE_ROOTSEL) == 0) {
- td->extra = ebo;
- td->ival = ebo->roll;
- }
+ if ((ebo->flag & BONE_ROOTSEL) == 0) {
+ td->extra = ebo;
+ td->ival = ebo->roll;
+ }
- td->ext = NULL;
- td->val = NULL;
- td->ob = t->obedit;
+ td->ext = NULL;
+ td->val = NULL;
+ td->ob = tc->obedit;
- td++;
- }
- if (ebo->flag & BONE_ROOTSEL) {
- copy_v3_v3(td->iloc, ebo->head);
- copy_v3_v3(td->center, td->iloc);
- td->loc = ebo->head;
- td->flag = TD_SELECTED;
- if (ebo->flag & BONE_EDITMODE_LOCKED)
- td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
+ td++;
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ copy_v3_v3(td->iloc, ebo->head);
+ copy_v3_v3(td->center, td->iloc);
+ td->loc = ebo->head;
+ td->flag = TD_SELECTED;
+ if (ebo->flag & BONE_EDITMODE_LOCKED)
+ td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
- ED_armature_ebone_to_mat3(ebo, td->axismtx);
+ ED_armature_ebone_to_mat3(ebo, td->axismtx);
- td->extra = ebo; /* to fix roll */
- td->ival = ebo->roll;
+ td->extra = ebo; /* to fix roll */
+ td->ival = ebo->roll;
- td->ext = NULL;
- td->val = NULL;
- td->ob = t->obedit;
+ td->ext = NULL;
+ td->val = NULL;
+ td->ob = tc->obedit;
- td++;
+ td++;
+ }
}
}
- }
- if (mirror && (td_old != td)) {
- eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
- if (eboflip) {
- bid[i].bone = eboflip;
- bid[i].dist = eboflip->dist;
- bid[i].rad_tail = eboflip->rad_tail;
- bid[i].roll = eboflip->roll;
- bid[i].xwidth = eboflip->xwidth;
- bid[i].zwidth = eboflip->zwidth;
- copy_v3_v3(bid[i].head, eboflip->head);
- copy_v3_v3(bid[i].tail, eboflip->tail);
- i++;
+ if (mirror && (td_old != td)) {
+ eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
+ if (eboflip) {
+ bid[i].bone = eboflip;
+ bid[i].dist = eboflip->dist;
+ bid[i].rad_tail = eboflip->rad_tail;
+ bid[i].roll = eboflip->roll;
+ bid[i].xwidth = eboflip->xwidth;
+ bid[i].zwidth = eboflip->zwidth;
+ copy_v3_v3(bid[i].head, eboflip->head);
+ copy_v3_v3(bid[i].tail, eboflip->tail);
+ i++;
+ }
}
}
- }
- if (mirror) {
- /* trick to terminate iteration */
- bid[total_mirrored].bone = NULL;
+ if (mirror) {
+ /* trick to terminate iteration */
+ bid[total_mirrored].bone = NULL;
+ }
}
}
@@ -1398,72 +1509,76 @@ static void createTransArmatureVerts(TransInfo *t)
static void createTransMBallVerts(TransInfo *t)
{
- MetaBall *mb = (MetaBall *)t->obedit->data;
- MetaElem *ml;
- TransData *td;
- TransDataExtension *tx;
- float mtx[3][3], smtx[3][3];
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- /* count totals */
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) countsel++;
- if (is_prop_edit) count++;
- }
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ MetaBall *mb = (MetaBall *)tc->obedit->data;
+ MetaElem *ml;
+ TransData *td;
+ TransDataExtension *tx;
+ float mtx[3][3], smtx[3][3];
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ /* count totals */
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) countsel++;
+ if (is_prop_edit) count++;
+ }
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) return;
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ continue;
+ }
- if (is_prop_edit) t->total = count;
- else t->total = countsel;
+ if (is_prop_edit) tc->data_len = count;
+ else tc->data_len = countsel;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(MBall EditMode)");
- tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "MetaElement_TransExtension");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(MBall EditMode)");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "MetaElement_TransExtension");
- copy_m3_m4(mtx, t->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (is_prop_edit || (ml->flag & SELECT)) {
- td->loc = &ml->x;
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->center, td->loc);
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (is_prop_edit || (ml->flag & SELECT)) {
+ td->loc = &ml->x;
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
- quat_to_mat3(td->axismtx, ml->quat);
+ quat_to_mat3(td->axismtx, ml->quat);
- if (ml->flag & SELECT) td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
- else td->flag = TD_USEQUAT;
+ if (ml->flag & SELECT) td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
+ else td->flag = TD_USEQUAT;
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
- td->ext = tx;
+ td->ext = tx;
- /* Radius of MetaElem (mass of MetaElem influence) */
- if (ml->flag & MB_SCALE_RAD) {
- td->val = &ml->rad;
- td->ival = ml->rad;
- }
- else {
- td->val = &ml->s;
- td->ival = ml->s;
- }
+ /* Radius of MetaElem (mass of MetaElem influence) */
+ if (ml->flag & MB_SCALE_RAD) {
+ td->val = &ml->rad;
+ td->ival = ml->rad;
+ }
+ else {
+ td->val = &ml->s;
+ td->ival = ml->s;
+ }
- /* expx/expy/expz determine "shape" of some MetaElem types */
- tx->size = &ml->expx;
- tx->isize[0] = ml->expx;
- tx->isize[1] = ml->expy;
- tx->isize[2] = ml->expz;
+ /* expx/expy/expz determine "shape" of some MetaElem types */
+ tx->size = &ml->expx;
+ tx->isize[0] = ml->expx;
+ tx->isize[1] = ml->expy;
+ tx->isize[2] = ml->expz;
- /* quat is used for rotation of MetaElem */
- tx->quat = ml->quat;
- copy_qt_qt(tx->iquat, ml->quat);
+ /* quat is used for rotation of MetaElem */
+ tx->quat = ml->quat;
+ copy_qt_qt(tx->iquat, ml->quat);
- tx->rot = NULL;
+ tx->rot = NULL;
- td++;
- tx++;
+ td++;
+ tx++;
+ }
}
}
}
@@ -1572,271 +1687,278 @@ static int bezt_select_to_transform_triple_flag(
static void createTransCurveVerts(TransInfo *t)
{
- Curve *cu = t->obedit->data;
- TransData *td = NULL;
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- float mtx[3][3], smtx[3][3];
- int a;
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
- ListBase *nurbs;
-
- /* to be sure */
- if (cu->editnurb == NULL) return;
#define SEL_F1 (1 << 0)
#define SEL_F2 (1 << 1)
#define SEL_F3 (1 << 2)
- /* count total of vertices, check identical as in 2nd loop for making transdata! */
- nurbs = BKE_curve_editNurbs_get(cu);
- for (nu = nurbs->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
- if (bezt->hide == 0) {
- const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
- if (bezt_tx & SEL_F1) { countsel++; }
- if (bezt_tx & SEL_F2) { countsel++; }
- if (bezt_tx & SEL_F3) { countsel++; }
- if (is_prop_edit) count += 3;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ Curve *cu = tc->obedit->data;
+ TransData *td = NULL;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ float mtx[3][3], smtx[3][3];
+ int a;
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ View3D *v3d = t->view;
+ short hide_handles = (v3d != NULL) ? ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) : false;
+ ListBase *nurbs;
+
+ /* to be sure */
+ if (cu->editnurb == NULL) return;
+
+ /* count total of vertices, check identical as in 2nd loop for making transdata! */
+ nurbs = BKE_curve_editNurbs_get(cu);
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
+ if (bezt->hide == 0) {
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+ if (bezt_tx & SEL_F1) { countsel++; }
+ if (bezt_tx & SEL_F2) { countsel++; }
+ if (bezt_tx & SEL_F3) { countsel++; }
+ if (is_prop_edit) count += 3;
+ }
}
}
- }
- else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
- if (bp->hide == 0) {
- if (is_prop_edit) count++;
- if (bp->f1 & SELECT) countsel++;
+ else {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
+ if (bp->hide == 0) {
+ if (is_prop_edit) count++;
+ if (bp->f1 & SELECT) countsel++;
+ }
}
}
}
- }
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) return;
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ tc->data_len = 0;
+ continue;
+ }
- if (is_prop_edit) t->total = count;
- else t->total = countsel;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)");
+ if (is_prop_edit) tc->data_len = count;
+ else tc->data_len = countsel;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Curve EditMode)");
- transform_around_single_fallback(t);
+ transform_around_single_fallback(t);
- copy_m3_m4(mtx, t->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- td = t->data;
- for (nu = nurbs->first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- TransData *head, *tail;
- head = tail = td;
- for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
- if (bezt->hide == 0) {
- TransDataCurveHandleFlags *hdata = NULL;
- float axismtx[3][3];
+ td = tc->data;
+ for (nu = nurbs->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ TransData *head, *tail;
+ head = tail = td;
+ for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
+ if (bezt->hide == 0) {
+ TransDataCurveHandleFlags *hdata = NULL;
+ float axismtx[3][3];
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- float normal[3], plane[3];
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ float normal[3], plane[3];
- BKE_nurb_bezt_calc_normal(nu, bezt, normal);
- BKE_nurb_bezt_calc_plane(nu, bezt, plane);
+ BKE_nurb_bezt_calc_normal(nu, bezt, normal);
+ BKE_nurb_bezt_calc_plane(nu, bezt, plane);
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
+ if (createSpaceNormalTangent(axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(axismtx, normal);
+ invert_m3(axismtx);
+ }
}
- }
- /* Elements that will be transform (not always a match to selection). */
- const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+ /* Elements that will be transform (not always a match to selection). */
+ const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
+
+ if (is_prop_edit || bezt_tx & SEL_F1) {
+ copy_v3_v3(td->iloc, bezt->vec[0]);
+ td->loc = bezt->vec[0];
+ copy_v3_v3(td->center, bezt->vec[(hide_handles ||
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
+ (bezt->f2 & SELECT)) ? 1 : 0]);
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
+ else td->flag = 0;
+ }
+ else {
+ if (bezt->f1 & SELECT) td->flag = TD_SELECTED;
+ else td->flag = 0;
+ }
+ td->ext = NULL;
+ td->val = NULL;
- if (is_prop_edit || bezt_tx & SEL_F1) {
- copy_v3_v3(td->iloc, bezt->vec[0]);
- td->loc = bezt->vec[0];
- copy_v3_v3(td->center, bezt->vec[(hide_handles ||
- (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
- (bezt->f2 & SELECT)) ? 1 : 0]);
- if (hide_handles) {
- if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
- else td->flag = 0;
- }
- else {
- if (bezt->f1 & SELECT) td->flag = TD_SELECTED;
- else td->flag = 0;
- }
- td->ext = NULL;
- td->val = NULL;
+ hdata = initTransDataCurveHandles(td, bezt);
- hdata = initTransDataCurveHandles(td, bezt);
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
+ td++;
+ count++;
+ tail++;
}
- td++;
- count++;
- tail++;
- }
+ /* This is the Curve Point, the other two are handles */
+ if (is_prop_edit || bezt_tx & SEL_F2) {
+ copy_v3_v3(td->iloc, bezt->vec[1]);
+ td->loc = bezt->vec[1];
+ copy_v3_v3(td->center, td->loc);
+ if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
+ else td->flag = 0;
+ td->ext = NULL;
- /* This is the Curve Point, the other two are handles */
- if (is_prop_edit || bezt_tx & SEL_F2) {
- copy_v3_v3(td->iloc, bezt->vec[1]);
- td->loc = bezt->vec[1];
- copy_v3_v3(td->center, td->loc);
- if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
- else td->flag = 0;
- td->ext = NULL;
+ if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */
+ td->val = &(bezt->radius);
+ td->ival = bezt->radius;
+ }
+ else if (t->mode == TFM_TILT) {
+ td->val = &(bezt->alfa);
+ td->ival = bezt->alfa;
+ }
+ else {
+ td->val = NULL;
+ }
- if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */
- td->val = &(bezt->radius);
- td->ival = bezt->radius;
- }
- else if (t->mode == TFM_TILT) {
- td->val = &(bezt->alfa);
- td->ival = bezt->alfa;
- }
- else {
- td->val = NULL;
- }
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
+ if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0)
+ /* If the middle is selected but the sides arnt, this is needed */
+ if (hdata == NULL) { /* if the handle was not saved by the previous handle */
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+
+ td++;
+ count++;
+ tail++;
}
+ if (is_prop_edit || bezt_tx & SEL_F3) {
+ copy_v3_v3(td->iloc, bezt->vec[2]);
+ td->loc = bezt->vec[2];
+ copy_v3_v3(td->center, bezt->vec[(hide_handles ||
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
+ (bezt->f2 & SELECT)) ? 1 : 2]);
+ if (hide_handles) {
+ if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
+ else td->flag = 0;
+ }
+ else {
+ if (bezt->f3 & SELECT) td->flag = TD_SELECTED;
+ else td->flag = 0;
+ }
+ td->ext = NULL;
+ td->val = NULL;
- if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0)
- /* If the middle is selected but the sides arnt, this is needed */
if (hdata == NULL) { /* if the handle was not saved by the previous handle */
hdata = initTransDataCurveHandles(td, bezt);
}
- td++;
- count++;
- tail++;
- }
- if (is_prop_edit || bezt_tx & SEL_F3) {
- copy_v3_v3(td->iloc, bezt->vec[2]);
- td->loc = bezt->vec[2];
- copy_v3_v3(td->center, bezt->vec[(hide_handles ||
- (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
- (bezt->f2 & SELECT)) ? 1 : 2]);
- if (hide_handles) {
- if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
- else td->flag = 0;
- }
- else {
- if (bezt->f3 & SELECT) td->flag = TD_SELECTED;
- else td->flag = 0;
- }
- td->ext = NULL;
- td->val = NULL;
-
- if (hdata == NULL) { /* if the handle was not saved by the previous handle */
- hdata = initTransDataCurveHandles(td, bezt);
- }
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- copy_m3_m3(td->axismtx, axismtx);
+ td++;
+ count++;
+ tail++;
}
- td++;
- count++;
- tail++;
+ (void)hdata; /* quiet warning */
+ }
+ else if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ head = tail;
}
-
- (void)hdata; /* quiet warning */
}
- else if (is_prop_edit && head != tail) {
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
- head = tail;
- }
- }
- if (is_prop_edit && head != tail)
- calc_distanceCurveVerts(head, tail - 1);
- /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
- * but for now just don't change handle types */
- if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
- /* sets the handles based on their selection, do this after the data is copied to the TransData */
- BKE_nurb_handles_test(nu, !hide_handles);
+ /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
+ * but for now just don't change handle types */
+ if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
+ /* sets the handles based on their selection, do this after the data is copied to the TransData */
+ BKE_nurb_handles_test(nu, !hide_handles);
+ }
}
- }
- else {
- TransData *head, *tail;
- head = tail = td;
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
- if (bp->hide == 0) {
- if (is_prop_edit || (bp->f1 & SELECT)) {
- float axismtx[3][3];
-
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- float normal[3], plane[3];
-
- BKE_nurb_bpoint_calc_normal(nu, bp, normal);
- BKE_nurb_bpoint_calc_plane(nu, bp, plane);
-
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
+ else {
+ TransData *head, *tail;
+ head = tail = td;
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
+ if (bp->hide == 0) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
+ float axismtx[3][3];
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ float normal[3], plane[3];
+
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+
+ if (createSpaceNormalTangent(axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(axismtx, normal);
+ invert_m3(axismtx);
+ }
}
}
- }
- copy_v3_v3(td->iloc, bp->vec);
- td->loc = bp->vec;
- copy_v3_v3(td->center, td->loc);
- if (bp->f1 & SELECT) td->flag = TD_SELECTED;
- else td->flag = 0;
- td->ext = NULL;
+ copy_v3_v3(td->iloc, bp->vec);
+ td->loc = bp->vec;
+ copy_v3_v3(td->center, td->loc);
+ if (bp->f1 & SELECT) td->flag = TD_SELECTED;
+ else td->flag = 0;
+ td->ext = NULL;
- if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) {
- td->val = &(bp->radius);
- td->ival = bp->radius;
- }
- else {
- td->val = &(bp->alfa);
- td->ival = bp->alfa;
- }
+ if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) {
+ td->val = &(bp->radius);
+ td->ival = bp->radius;
+ }
+ else {
+ td->val = &(bp->alfa);
+ td->ival = bp->alfa;
+ }
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- copy_m3_m3(td->axismtx, axismtx);
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ if (nu->pntsv == 1) {
+ copy_m3_m3(td->axismtx, axismtx);
+ }
}
- }
- td++;
- count++;
- tail++;
+ td++;
+ count++;
+ tail++;
+ }
+ }
+ else if (is_prop_edit && head != tail) {
+ calc_distanceCurveVerts(head, tail - 1);
+ head = tail;
}
}
- else if (is_prop_edit && head != tail) {
+ if (is_prop_edit && head != tail)
calc_distanceCurveVerts(head, tail - 1);
- head = tail;
- }
}
- if (is_prop_edit && head != tail)
- calc_distanceCurveVerts(head, tail - 1);
}
}
-
#undef SEL_F1
#undef SEL_F2
#undef SEL_F3
@@ -1846,228 +1968,235 @@ static void createTransCurveVerts(TransInfo *t)
static void createTransLatticeVerts(TransInfo *t)
{
- Lattice *latt = ((Lattice *)t->obedit->data)->editlatt->latt;
- TransData *td = NULL;
- BPoint *bp;
- float mtx[3][3], smtx[3][3];
- int a;
- int count = 0, countsel = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- bp = latt->def;
- a = latt->pntsu * latt->pntsv * latt->pntsw;
- while (a--) {
- if (bp->hide == 0) {
- if (bp->f1 & SELECT) countsel++;
- if (is_prop_edit) count++;
+ Lattice *latt = ((Lattice *)tc->obedit->data)->editlatt->latt;
+ TransData *td = NULL;
+ BPoint *bp;
+ float mtx[3][3], smtx[3][3];
+ int a;
+ int count = 0, countsel = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ bp = latt->def;
+ a = latt->pntsu * latt->pntsv * latt->pntsw;
+ while (a--) {
+ if (bp->hide == 0) {
+ if (bp->f1 & SELECT) countsel++;
+ if (is_prop_edit) count++;
+ }
+ bp++;
}
- bp++;
- }
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) return;
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) return;
- if (is_prop_edit) t->total = count;
- else t->total = countsel;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Lattice EditMode)");
+ if (is_prop_edit) tc->data_len = count;
+ else tc->data_len = countsel;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)");
- copy_m3_m4(mtx, t->obedit->obmat);
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- td = t->data;
- bp = latt->def;
- a = latt->pntsu * latt->pntsv * latt->pntsw;
- while (a--) {
- if (is_prop_edit || (bp->f1 & SELECT)) {
- if (bp->hide == 0) {
- copy_v3_v3(td->iloc, bp->vec);
- td->loc = bp->vec;
- copy_v3_v3(td->center, td->loc);
- if (bp->f1 & SELECT) {
- td->flag = TD_SELECTED;
- }
- else {
- td->flag = 0;
- }
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
+ td = tc->data;
+ bp = latt->def;
+ a = latt->pntsu * latt->pntsv * latt->pntsw;
+ while (a--) {
+ if (is_prop_edit || (bp->f1 & SELECT)) {
+ if (bp->hide == 0) {
+ copy_v3_v3(td->iloc, bp->vec);
+ td->loc = bp->vec;
+ copy_v3_v3(td->center, td->loc);
+ if (bp->f1 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
- td->ext = NULL;
- td->val = NULL;
+ td->ext = NULL;
+ td->val = NULL;
- td++;
- count++;
+ td++;
+ count++;
+ }
}
+ bp++;
}
- bp++;
}
}
/* ******************* particle edit **************** */
static void createTransParticleVerts(bContext *C, TransInfo *t)
{
- TransData *td = NULL;
- TransDataExtension *tx;
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- ParticleEditSettings *pset = PE_settings(t->scene);
- PTCacheEdit *edit = PE_get_current(bmain, t->scene, ob);
- ParticleSystem *psys = NULL;
- ParticleSystemModifierData *psmd = NULL;
- PTCacheEditPoint *point;
- PTCacheEditKey *key;
- float mat[4][4];
- int i, k, transformparticle;
- int count = 0, hasselected = 0;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return;
-
- psys = edit->psys;
-
- if (psys)
- psmd = psys_get_modifier(ob, psys);
-
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
- point->flag &= ~PEP_TRANSFORM;
- transformparticle = 0;
-
- if ((point->flag & PEP_HIDE) == 0) {
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- if ((key->flag & PEK_HIDE) == 0) {
- if (key->flag & PEK_SELECT) {
- hasselected = 1;
- transformparticle = 1;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ TransData *td = NULL;
+ TransDataExtension *tx;
+ Object *ob = CTX_data_active_object(C);
+ ParticleEditSettings *pset = PE_settings(t->scene);
+ PTCacheEdit *edit = PE_get_current(t->scene, ob);
+ ParticleSystem *psys = NULL;
+ ParticleSystemModifierData *psmd = NULL;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ float mat[4][4];
+ int i, k, transformparticle;
+ int count = 0, hasselected = 0;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return;
+
+ psys = edit->psys;
+
+ if (psys)
+ psmd = psys_get_modifier(ob, psys);
+
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
+ point->flag &= ~PEP_TRANSFORM;
+ transformparticle = 0;
+
+ if ((point->flag & PEP_HIDE) == 0) {
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ if ((key->flag & PEK_HIDE) == 0) {
+ if (key->flag & PEK_SELECT) {
+ hasselected = 1;
+ transformparticle = 1;
+ }
+ else if (is_prop_edit)
+ transformparticle = 1;
}
- else if (is_prop_edit)
- transformparticle = 1;
}
}
- }
- if (transformparticle) {
- count += point->totkey;
- point->flag |= PEP_TRANSFORM;
+ if (transformparticle) {
+ count += point->totkey;
+ point->flag |= PEP_TRANSFORM;
+ }
}
- }
- /* note: in prop mode we need at least 1 selected */
- if (hasselected == 0) return;
+ /* note: in prop mode we need at least 1 selected */
+ if (hasselected == 0) return;
- t->total = count;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Particle Mode)");
+ tc->data_len = count;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Particle Mode)");
- if (t->mode == TFM_BAKE_TIME)
- tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "Particle_TransExtension");
- else
- tx = t->ext = NULL;
+ if (t->mode == TFM_BAKE_TIME)
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "Particle_TransExtension");
+ else
+ tx = tc->data_ext = NULL;
- unit_m4(mat);
+ unit_m4(mat);
- invert_m4_m4(ob->imat, ob->obmat);
+ invert_m4_m4(ob->imat, ob->obmat);
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
- TransData *head, *tail;
- head = tail = td;
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
+ TransData *head, *tail;
+ head = tail = td;
- if (!(point->flag & PEP_TRANSFORM)) continue;
+ if (!(point->flag & PEP_TRANSFORM)) continue;
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + i, mat);
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR))
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles + i, mat);
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- if (key->flag & PEK_USE_WCO) {
- copy_v3_v3(key->world_co, key->co);
- mul_m4_v3(mat, key->world_co);
- td->loc = key->world_co;
- }
- else
- td->loc = key->co;
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ if (key->flag & PEK_USE_WCO) {
+ copy_v3_v3(key->world_co, key->co);
+ mul_m4_v3(mat, key->world_co);
+ td->loc = key->world_co;
+ }
+ else
+ td->loc = key->co;
- copy_v3_v3(td->iloc, td->loc);
- copy_v3_v3(td->center, td->loc);
+ copy_v3_v3(td->iloc, td->loc);
+ copy_v3_v3(td->center, td->loc);
- if (key->flag & PEK_SELECT)
- td->flag |= TD_SELECTED;
- else if (!is_prop_edit)
- td->flag |= TD_SKIP;
+ if (key->flag & PEK_SELECT)
+ td->flag |= TD_SELECTED;
+ else if (!is_prop_edit)
+ td->flag |= TD_SKIP;
- unit_m3(td->mtx);
- unit_m3(td->smtx);
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
- /* don't allow moving roots */
- if (k == 0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR)))
- td->protectflag |= OB_LOCK_LOC;
+ /* don't allow moving roots */
+ if (k == 0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR)))
+ td->protectflag |= OB_LOCK_LOC;
- td->ob = ob;
- td->ext = tx;
- if (t->mode == TFM_BAKE_TIME) {
- td->val = key->time;
- td->ival = *(key->time);
- /* abuse size and quat for min/max values */
- td->flag |= TD_NO_EXT;
- if (k == 0) tx->size = NULL;
- else tx->size = (key - 1)->time;
+ td->ob = ob;
+ td->ext = tx;
+ if (t->mode == TFM_BAKE_TIME) {
+ td->val = key->time;
+ td->ival = *(key->time);
+ /* abuse size and quat for min/max values */
+ td->flag |= TD_NO_EXT;
+ if (k == 0) tx->size = NULL;
+ else tx->size = (key - 1)->time;
- if (k == point->totkey - 1) tx->quat = NULL;
- else tx->quat = (key + 1)->time;
- }
+ if (k == point->totkey - 1) tx->quat = NULL;
+ else tx->quat = (key + 1)->time;
+ }
- td++;
- if (tx)
- tx++;
- tail++;
+ td++;
+ if (tx)
+ tx++;
+ tail++;
+ }
+ if (is_prop_edit && head != tail)
+ calc_distanceCurveVerts(head, tail - 1);
}
- if (is_prop_edit && head != tail)
- calc_distanceCurveVerts(head, tail - 1);
}
}
void flushTransParticles(TransInfo *t)
{
- Main *bmain = CTX_data_main(t->context);
- Scene *scene = t->scene;
- Object *ob = OBACT;
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd = NULL;
- PTCacheEditPoint *point;
- PTCacheEditKey *key;
- TransData *td;
- float mat[4][4], imat[4][4], co[3];
- int i, k;
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
-
- if (psys)
- psmd = psys_get_modifier(ob, psys);
-
- /* we do transform in world space, so flush world space position
- * back to particle local space (only for hair particles) */
- td = t->data;
- for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
- if (!(point->flag & PEP_TRANSFORM)) continue;
-
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + i, mat);
- invert_m4_m4(imat, mat);
-
- for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
- copy_v3_v3(co, key->world_co);
- mul_m4_v3(imat, co);
-
-
- /* optimization for proportional edit */
- if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
- copy_v3_v3(key->co, co);
- point->flag |= PEP_EDIT_RECALC;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ ParticleSystem *psys = edit->psys;
+ ParticleSystemModifierData *psmd = NULL;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ TransData *td;
+ float mat[4][4], imat[4][4], co[3];
+ int i, k;
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+
+ if (psys)
+ psmd = psys_get_modifier(ob, psys);
+
+ /* we do transform in world space, so flush world space position
+ * back to particle local space (only for hair particles) */
+ td = tc->data;
+ for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
+ if (!(point->flag & PEP_TRANSFORM)) continue;
+
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles + i, mat);
+ invert_m4_m4(imat, mat);
+
+ for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
+ copy_v3_v3(co, key->world_co);
+ mul_m4_v3(imat, co);
+
+
+ /* optimization for proportional edit */
+ if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
+ copy_v3_v3(key->co, co);
+ point->flag |= PEP_EDIT_RECALC;
+ }
}
}
+ else
+ point->flag |= PEP_EDIT_RECALC;
}
- else
- point->flag |= PEP_EDIT_RECALC;
- }
- PE_update_object(bmain, scene, OBACT, 1);
+ PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1);
+ }
}
/* ********************* mesh ****************** */
@@ -2477,243 +2606,248 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
static void createTransEditVerts(TransInfo *t)
{
- TransData *tob = NULL;
- TransDataExtension *tx = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
- Mesh *me = t->obedit->data;
- BMesh *bm = em->bm;
- BMVert *eve;
- BMIter iter;
- float (*mappedcos)[3] = NULL, (*quats)[4] = NULL;
- float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
- float *dists = NULL;
- int a;
- const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
- int mirror = 0;
- int cd_vert_bweight_offset = -1;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- struct TransIslandData *island_info = NULL;
- int island_info_tot;
- int *island_vert_map = NULL;
+ TransData *tob = NULL;
+ TransDataExtension *tx = NULL;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ Mesh *me = tc->obedit->data;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
+ float (*mappedcos)[3] = NULL, (*quats)[4] = NULL;
+ float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
+ float *dists = NULL;
+ int a;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+ int mirror = 0;
+ int cd_vert_bweight_offset = -1;
+ bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
- /* Even for translation this is needed because of island-orientation, see: T51651. */
- const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
- /* Original index of our connected vertex when connected distances are calculated.
- * Optional, allocate if needed. */
- int *dists_index = NULL;
+ struct TransIslandData *island_info = NULL;
+ int island_info_tot;
+ int *island_vert_map = NULL;
- if (t->flag & T_MIRROR) {
- EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
- mirror = 1;
- }
+ /* Even for translation this is needed because of island-orientation, see: T51651. */
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
+ /* Original index of our connected vertex when connected distances are calculated.
+ * Optional, allocate if needed. */
+ int *dists_index = NULL;
- /**
- * Quick check if we can transform.
- *
- * \note ignore modes here, even in edge/face modes, transform data is created by selected vertices.
- * \note in prop mode we need at least 1 selected.
- */
- if (bm->totvertsel == 0) {
- goto cleanup;
- }
+ if (t->flag & T_MIRROR) {
+ /* TODO(campbell): xform: We need support for many mirror objects at once! */
+ if (tc->is_active) {
+ EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
+ mirror = 1;
+ }
+ }
- if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_VERT_BWEIGHT);
- cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- }
+ /**
+ * Quick check if we can transform.
+ *
+ * \note ignore modes here, even in edge/face modes, transform data is created by selected vertices.
+ * \note in prop mode we need at least 1 selected.
+ */
+ if (bm->totvertsel == 0) {
+ goto cleanup;
+ }
- if (prop_mode) {
- unsigned int count = 0;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- count++;
- }
+ if (t->mode == TFM_BWEIGHT) {
+ BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
+ cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
- t->total = count;
+ if (prop_mode) {
+ unsigned int count = 0;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ count++;
+ }
+ }
- /* allocating scratch arrays */
- if (prop_mode & T_PROP_CONNECTED) {
- dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
- if (is_island_center) {
- dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
+ tc->data_len = count;
+
+ /* allocating scratch arrays */
+ if (prop_mode & T_PROP_CONNECTED) {
+ dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
+ if (is_island_center) {
+ dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
+ }
}
}
- }
- else {
- t->total = bm->totvertsel;
- }
-
- tob = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mesh EditMode)");
- if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
- /* warning, this is overkill, we only need 2 extra floats,
- * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
- * since we may not use the 'alt' transform mode to maintain shell thickness,
- * but with generic transform code its hard to lazy init vars */
- tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension),
- "TransObData ext");
- }
+ else {
+ tc->data_len = bm->totvertsel;
+ }
- copy_m3_m4(mtx, t->obedit->obmat);
- /* we use a pseudoinverse so that when one of the axes is scaled to 0,
- * matrix inversion still works and we can still moving along the other */
- pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+ tob = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
+ if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
+ /* warning, this is overkill, we only need 2 extra floats,
+ * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
+ * since we may not use the 'alt' transform mode to maintain shell thickness,
+ * but with generic transform code its hard to lazy init vars */
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObData ext");
+ }
- if (prop_mode & T_PROP_CONNECTED) {
- editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
- }
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ /* we use a pseudoinverse so that when one of the axes is scaled to 0,
+ * matrix inversion still works and we can still moving along the other */
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
- if (is_island_center) {
- /* In this specific case, near-by vertices will need to know the island of the nearest connected vertex. */
- const bool calc_single_islands = (
- (prop_mode & T_PROP_CONNECTED) &&
- (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
- (em->selectmode & SCE_SELECT_VERTEX));
+ if (prop_mode & T_PROP_CONNECTED) {
+ editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
+ }
- island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map, calc_single_islands);
- }
+ if (is_island_center) {
+ /* In this specific case, near-by vertices will need to know the island of the nearest connected vertex. */
+ const bool calc_single_islands = (
+ (prop_mode & T_PROP_CONNECTED) &&
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (em->selectmode & SCE_SELECT_VERTEX));
- /* detect CrazySpace [tm] */
- if (modifiers_getCageIndex(t->scene, t->obedit, NULL, 1) != -1) {
- int totleft = -1;
- if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) {
- /* check if we can use deform matrices for modifier from the
- * start up to stack, they are more accurate than quats */
- totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->scene, t->obedit, em, &defmats, &defcos);
+ island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map, calc_single_islands);
}
- /* if we still have more modifiers, also do crazyspace
- * correction with quats, relative to the coordinates after
- * the modifiers that support deform matrices (defcos) */
+ /* detect CrazySpace [tm] */
+ if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
+ int totleft = -1;
+ if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
+ /* check if we can use deform matrices for modifier from the
+ * start up to stack, they are more accurate than quats */
+ totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->depsgraph, t->scene, tc->obedit, em, &defmats, &defcos);
+ }
+
+ /* if we still have more modifiers, also do crazyspace
+ * correction with quats, relative to the coordinates after
+ * the modifiers that support deform matrices (defcos) */
#if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */
- if ((totleft > 0) || (totleft == -1))
+ if ((totleft > 0) || (totleft == -1))
#else
- if (totleft > 0)
+ if (totleft > 0)
#endif
- {
- mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit);
- quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
- BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
- if (mappedcos)
- MEM_freeN(mappedcos);
- }
+ {
+ mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, t->scene, tc->obedit);
+ quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
+ BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
+ if (mappedcos)
+ MEM_freeN(mappedcos);
+ }
- if (defcos) {
- MEM_freeN(defcos);
+ if (defcos) {
+ MEM_freeN(defcos);
+ }
}
- }
- /* find out which half we do */
- if (mirror) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) {
- if (eve->co[0] < 0.0f) {
- t->mirror = -1;
- mirror = -1;
+ /* find out which half we do */
+ if (mirror) {
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) {
+ if (eve->co[0] < 0.0f) {
+ t->mirror = -1;
+ mirror = -1;
+ }
+ break;
}
- break;
}
}
- }
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- struct TransIslandData *v_island = NULL;
- float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ struct TransIslandData *v_island = NULL;
+ float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
+
+ if (island_info) {
+ const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
+ v_island = (island_vert_map[connected_index] != -1) ?
+ &island_info[island_vert_map[connected_index]] : NULL;
+ }
- if (island_info) {
- const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
- v_island = (island_vert_map[connected_index] != -1) ?
- &island_info[island_vert_map[connected_index]] : NULL;
- }
+ VertsToTransData(t, tob, tx, em, eve, bweight, v_island);
+ if (tx)
+ tx++;
- VertsToTransData(t, tob, tx, em, eve, bweight, v_island);
- if (tx)
- tx++;
-
- /* selected */
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
- tob->flag |= TD_SELECTED;
+ /* selected */
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
+ tob->flag |= TD_SELECTED;
- if (prop_mode) {
- if (prop_mode & T_PROP_CONNECTED) {
- tob->dist = dists[a];
- }
- else {
- tob->flag |= TD_NOTCONNECTED;
- tob->dist = FLT_MAX;
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
+ tob->dist = dists[a];
+ }
+ else {
+ tob->flag |= TD_NOTCONNECTED;
+ tob->dist = FLT_MAX;
+ }
}
- }
- /* CrazySpace */
- if (defmats || (quats && BM_elem_flag_test(eve, BM_ELEM_TAG))) {
- float mat[3][3], qmat[3][3], imat[3][3];
+ /* CrazySpace */
+ if (defmats || (quats && BM_elem_flag_test(eve, BM_ELEM_TAG))) {
+ float mat[3][3], qmat[3][3], imat[3][3];
- /* use both or either quat and defmat correction */
- if (quats && BM_elem_flag_test(eve, BM_ELEM_TAG)) {
- quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
+ /* use both or either quat and defmat correction */
+ if (quats && BM_elem_flag_test(eve, BM_ELEM_TAG)) {
+ quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
- if (defmats)
- mul_m3_series(mat, defmats[a], qmat, mtx);
+ if (defmats)
+ mul_m3_series(mat, defmats[a], qmat, mtx);
+ else
+ mul_m3_m3m3(mat, mtx, qmat);
+ }
else
- mul_m3_m3m3(mat, mtx, qmat);
- }
- else
- mul_m3_m3m3(mat, mtx, defmats[a]);
+ mul_m3_m3m3(mat, mtx, defmats[a]);
- invert_m3_m3(imat, mat);
+ invert_m3_m3(imat, mat);
- copy_m3_m3(tob->smtx, imat);
- copy_m3_m3(tob->mtx, mat);
- }
- else {
- copy_m3_m3(tob->smtx, smtx);
- copy_m3_m3(tob->mtx, mtx);
- }
+ copy_m3_m3(tob->smtx, imat);
+ copy_m3_m3(tob->mtx, mat);
+ }
+ else {
+ copy_m3_m3(tob->smtx, smtx);
+ copy_m3_m3(tob->mtx, mtx);
+ }
- /* Mirror? */
- if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) {
- BMVert *vmir = EDBM_verts_mirror_get(em, eve); //t->obedit, em, eve, tob->iloc, a);
- if (vmir && vmir != eve) {
- tob->extra = vmir;
+ /* Mirror? */
+ if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) {
+ BMVert *vmir = EDBM_verts_mirror_get(em, eve); //t->obedit, em, eve, tob->iloc, a);
+ if (vmir && vmir != eve) {
+ tob->extra = vmir;
+ }
}
+ tob++;
}
- tob++;
}
}
- }
- if (island_info) {
- MEM_freeN(island_info);
- MEM_freeN(island_vert_map);
- }
+ if (island_info) {
+ MEM_freeN(island_info);
+ MEM_freeN(island_vert_map);
+ }
- if (mirror != 0) {
- tob = t->data;
- for (a = 0; a < t->total; a++, tob++) {
- if (ABS(tob->loc[0]) <= 0.00001f) {
- tob->flag |= TD_MIRROR_EDGE;
+ if (mirror != 0) {
+ tob = tc->data;
+ for (a = 0; a < tc->data_len; a++, tob++) {
+ if (ABS(tob->loc[0]) <= 0.00001f) {
+ tob->flag |= TD_MIRROR_EDGE;
+ }
}
}
- }
cleanup:
- /* crazy space free */
- if (quats)
- MEM_freeN(quats);
- if (defmats)
- MEM_freeN(defmats);
- if (dists)
- MEM_freeN(dists);
- if (dists_index)
- MEM_freeN(dists_index);
-
- if (t->flag & T_MIRROR) {
- EDBM_verts_mirror_cache_end(em);
+ /* crazy space free */
+ if (quats)
+ MEM_freeN(quats);
+ if (defmats)
+ MEM_freeN(defmats);
+ if (dists)
+ MEM_freeN(dists);
+ if (dists_index)
+ MEM_freeN(dists_index);
+
+ if (t->flag & T_MIRROR) {
+ EDBM_verts_mirror_cache_end(em);
+ }
}
}
@@ -2721,39 +2855,42 @@ cleanup:
void flushTransNodes(TransInfo *t)
{
const float dpi_fac = UI_DPI_FAC;
- int a;
- TransData *td;
- TransData2D *td2d;
- applyGridAbsolute(t);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ int a;
+ TransData *td;
+ TransData2D *td2d;
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
- bNode *node = td->extra;
- float locx, locy;
+ applyGridAbsolute(t);
- /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
+ bNode *node = td->extra;
+ float locx, locy;
+
+ /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
#ifdef USE_NODE_CENTER
- locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
- locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
+ locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
+ locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
#else
- locx = td2d->loc[0] / dpi_fac;
- locy = td2d->loc[1] / dpi_fac;
+ locx = td2d->loc[0] / dpi_fac;
+ locy = td2d->loc[1] / dpi_fac;
#endif
- /* account for parents (nested nodes) */
- if (node->parent) {
- nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
- }
- else {
- node->locx = locx;
- node->locy = locy;
+ /* account for parents (nested nodes) */
+ if (node->parent) {
+ nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
+ }
+ else {
+ node->locx = locx;
+ node->locy = locy;
+ }
}
- }
- /* handle intersection with noodles */
- if (t->total == 1) {
- ED_node_link_intersect_test(t->sa, 1);
+ /* handle intersection with noodles */
+ if (tc->data_len == 1) {
+ ED_node_link_intersect_test(t->sa, 1);
+ }
}
}
@@ -2783,13 +2920,14 @@ BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int s
void flushTransSeq(TransInfo *t)
{
ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep; /* Editing null check already done */
+
int a, new_frame;
TransData *td = NULL;
TransData2D *td2d = NULL;
TransDataSeq *tdsq = NULL;
Sequence *seq;
-
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* prevent updating the same seq twice
* if the transdata order is changed this will mess up
@@ -2798,7 +2936,7 @@ void flushTransSeq(TransInfo *t)
int old_start_prev = 0, sel_flag_prev = 0;
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
int old_start;
tdsq = (TransDataSeq *)td->extra;
seq = tdsq->seq;
@@ -2871,8 +3009,8 @@ void flushTransSeq(TransInfo *t)
}
/* update effects inside meta's */
- for (a = 0, seq_prev = NULL, td = t->data, td2d = t->data2d;
- a < t->total;
+ for (a = 0, seq_prev = NULL, td = tc->data, td2d = tc->data_2d;
+ a < tc->data_len;
a++, td++, td2d++, seq_prev = seq)
{
tdsq = (TransDataSeq *)td->extra;
@@ -2888,7 +3026,7 @@ void flushTransSeq(TransInfo *t)
/* need to do the overlap check in a new loop otherwise adjacent strips
* will not be updated and we'll get false positives */
seq_prev = NULL;
- for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
+ for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
tdsq = (TransDataSeq *)td->extra;
seq = tdsq->seq;
@@ -2949,159 +3087,163 @@ static void createTransUVs(bContext *C, TransInfo *t)
Image *ima = CTX_data_edit_image(C);
Scene *scene = t->scene;
ToolSettings *ts = CTX_data_tool_settings(C);
- TransData *td = NULL;
- TransData2D *td2d = NULL;
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
- BMFace *efa;
- BMIter iter, liter;
- UvElementMap *elementmap = NULL;
- BLI_bitmap *island_enabled = NULL;
- struct { float co[2]; int co_num; } *island_center = NULL;
- int count = 0, countsel = 0, count_rejected = 0;
+
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
- if (!ED_space_image_show_uvedit(sima, t->obedit))
- return;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- /* count */
- if (is_prop_connected || is_island_center) {
- /* create element map with island information */
- const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
- elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
- if (elementmap == NULL) {
- return;
- }
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMFace *efa;
+ BMIter iter, liter;
+ UvElementMap *elementmap = NULL;
+ BLI_bitmap *island_enabled = NULL;
+ struct { float co[2]; int co_num; } *island_center = NULL;
+ int count = 0, countsel = 0, count_rejected = 0;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (is_prop_connected) {
- island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
+ if (!ED_space_image_show_uvedit(sima, tc->obedit)) {
+ continue;
}
- if (is_island_center) {
- island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
- }
- }
+ /* count */
+ if (is_prop_connected || is_island_center) {
+ /* create element map with island information */
+ const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
+ elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
+ if (elementmap == NULL) {
+ return;
+ }
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- BMLoop *l;
+ if (is_prop_connected) {
+ island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
+ }
- if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- continue;
+ if (is_island_center) {
+ island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
+ }
}
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- countsel++;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
- if (is_prop_connected || island_center) {
- UvElement *element = BM_uv_element_get(elementmap, efa, l);
+ if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ continue;
+ }
- if (is_prop_connected) {
- BLI_BITMAP_ENABLE(island_enabled, element->island);
- }
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ countsel++;
- if (is_island_center) {
- if (element->flag == false) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(island_center[element->island].co, luv->uv);
- island_center[element->island].co_num++;
- element->flag = true;
+ if (is_prop_connected || island_center) {
+ UvElement *element = BM_uv_element_get(elementmap, efa, l);
+
+ if (is_prop_connected) {
+ BLI_BITMAP_ENABLE(island_enabled, element->island);
+ }
+
+ if (is_island_center) {
+ if (element->flag == false) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(island_center[element->island].co, luv->uv);
+ island_center[element->island].co_num++;
+ element->flag = true;
+ }
}
}
}
- }
- if (is_prop_edit) {
- count++;
+ if (is_prop_edit) {
+ count++;
+ }
}
}
- }
- /* note: in prop mode we need at least 1 selected */
- if (countsel == 0) {
- goto finally;
- }
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel == 0) {
+ goto finally;
+ }
- if (is_island_center) {
- int i;
+ if (is_island_center) {
+ int i;
- for (i = 0; i < elementmap->totalIslands; i++) {
- mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
- mul_v2_v2(island_center[i].co, t->aspect);
+ for (i = 0; i < elementmap->totalIslands; i++) {
+ mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
+ mul_v2_v2(island_center[i].co, t->aspect);
+ }
}
- }
- t->total = (is_prop_edit) ? count : countsel;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(UV Editing)");
- /* for each 2d uv coord a 3d vector is allocated, so that they can be
- * treated just as if they were 3d verts */
- t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransObData2D(UV Editing)");
+ tc->data_len = (is_prop_edit) ? count : countsel;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(UV Editing)");
+ /* for each 2d uv coord a 3d vector is allocated, so that they can be
+ * treated just as if they were 3d verts */
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(UV Editing)");
- if (sima->flag & SI_CLIP_UV)
- t->flag |= T_CLIP_UV;
+ if (sima->flag & SI_CLIP_UV)
+ t->flag |= T_CLIP_UV;
- td = t->data;
- td2d = t->data2d;
+ td = tc->data;
+ td2d = tc->data_2d;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BMLoop *l;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BMLoop *l;
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
- MLoopUV *luv;
- const float *center = NULL;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ MLoopUV *luv;
+ const float *center = NULL;
- if (!is_prop_edit && !selected)
- continue;
+ if (!is_prop_edit && !selected)
+ continue;
- if (is_prop_connected || is_island_center) {
- UvElement *element = BM_uv_element_get(elementmap, efa, l);
+ if (is_prop_connected || is_island_center) {
+ UvElement *element = BM_uv_element_get(elementmap, efa, l);
- if (is_prop_connected) {
- if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
- count_rejected++;
- continue;
+ if (is_prop_connected) {
+ if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
+ count_rejected++;
+ continue;
+ }
}
- }
- if (is_island_center) {
- center = island_center[element->island].co;
+ if (is_island_center) {
+ center = island_center[element->island].co;
+ }
}
- }
- BM_elem_flag_enable(l, BM_ELEM_TAG);
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
+ BM_elem_flag_enable(l, BM_ELEM_TAG);
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
+ }
}
- }
- if (is_prop_connected) {
- t->total -= count_rejected;
- }
-
- if (sima->flag & SI_LIVE_UNWRAP)
- ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
+ if (is_prop_connected) {
+ tc->data_len -= count_rejected;
+ }
+ if (sima->flag & SI_LIVE_UNWRAP) {
+ ED_uvedit_live_unwrap_begin(t->scene, tc->obedit);
+ }
finally:
- if (is_prop_connected || is_island_center) {
- BM_uv_element_map_free(elementmap);
+ if (is_prop_connected || is_island_center) {
+ BM_uv_element_map_free(elementmap);
- if (is_prop_connected) {
- MEM_freeN(island_enabled);
- }
+ if (is_prop_connected) {
+ MEM_freeN(island_enabled);
+ }
- if (island_center) {
- MEM_freeN(island_center);
+ if (island_center) {
+ MEM_freeN(island_center);
+ }
}
}
}
@@ -3109,37 +3251,38 @@ finally:
void flushTransUVs(TransInfo *t)
{
SpaceImage *sima = t->sa->spacedata.first;
- TransData2D *td;
- int a;
- float aspect_inv[2], size[2];
const bool use_pixel_snap = ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL));
- aspect_inv[0] = 1.0f / t->aspect[0];
- aspect_inv[1] = 1.0f / t->aspect[1];
-
- if (use_pixel_snap) {
- int size_i[2];
- ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
- size[0] = size_i[0];
- size[1] = size_i[1];
- }
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData2D *td;
+ int a;
+ float aspect_inv[2], size[2];
- /* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data2d; a < t->total; a++, td++) {
- td->loc2d[0] = td->loc[0] * aspect_inv[0];
- td->loc2d[1] = td->loc[1] * aspect_inv[1];
+ aspect_inv[0] = 1.0f / t->aspect[0];
+ aspect_inv[1] = 1.0f / t->aspect[1];
if (use_pixel_snap) {
- td->loc2d[0] = roundf(td->loc2d[0] * size[0]) / size[0];
- td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1];
+ int size_i[2];
+ ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
+ size[0] = size_i[0];
+ size[1] = size_i[1];
+ }
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a = 0, td = tc->data_2d; a < tc->data_len; a++, td++) {
+ td->loc2d[0] = td->loc[0] * aspect_inv[0];
+ td->loc2d[1] = td->loc[1] * aspect_inv[1];
+
+ if (use_pixel_snap) {
+ td->loc2d[0] = roundf(td->loc2d[0] * size[0]) / size[0];
+ td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1];
+ }
}
}
}
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
{
- TransData *td;
- int a;
bool clipx = true, clipy = true;
float min[2], max[2];
@@ -3147,39 +3290,45 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
max[0] = t->aspect[0];
max[1] = t->aspect[1];
- for (a = 0, td = t->data; a < t->total; a++, td++) {
- minmax_v2v2_v2(min, max, td->loc);
- }
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (resize) {
- if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < t->aspect[0] * 0.5f)
- vec[0] *= t->center[0] / (t->center[0] - min[0]);
- else if (max[0] > t->aspect[0] && t->center[0] < t->aspect[0])
- vec[0] *= (t->center[0] - t->aspect[0]) / (t->center[0] - max[0]);
- else
- clipx = 0;
+ TransData *td;
+ int a;
- if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < t->aspect[1] * 0.5f)
- vec[1] *= t->center[1] / (t->center[1] - min[1]);
- else if (max[1] > t->aspect[1] && t->center[1] < t->aspect[1])
- vec[1] *= (t->center[1] - t->aspect[1]) / (t->center[1] - max[1]);
- else
- clipy = 0;
- }
- else {
- if (min[0] < 0.0f)
- vec[0] -= min[0];
- else if (max[0] > t->aspect[0])
- vec[0] -= max[0] - t->aspect[0];
- else
- clipx = 0;
+ for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
+ minmax_v2v2_v2(min, max, td->loc);
+ }
- if (min[1] < 0.0f)
- vec[1] -= min[1];
- else if (max[1] > t->aspect[1])
- vec[1] -= max[1] - t->aspect[1];
- else
- clipy = 0;
+ if (resize) {
+ if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f)
+ vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
+ else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0])
+ vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
+ else
+ clipx = 0;
+
+ if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f)
+ vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
+ else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1])
+ vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
+ else
+ clipy = 0;
+ }
+ else {
+ if (min[0] < 0.0f)
+ vec[0] -= min[0];
+ else if (max[0] > t->aspect[0])
+ vec[0] -= max[0] - t->aspect[0];
+ else
+ clipx = 0;
+
+ if (min[1] < 0.0f)
+ vec[1] -= min[1];
+ else if (max[1] > t->aspect[1])
+ vec[1] -= max[1] - t->aspect[1];
+ else
+ clipy = 0;
+ }
}
return (clipx || clipy);
@@ -3187,18 +3336,18 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
void clipUVData(TransInfo *t)
{
- TransData *td = NULL;
- int a;
-
- for (a = 0, td = t->data; a < t->total; a++, td++) {
- if (td->flag & TD_NOACTION)
- break;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (int a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
- if ((td->flag & TD_SKIP) || (!td->loc))
- continue;
+ if ((td->flag & TD_SKIP) || (!td->loc))
+ continue;
- td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
- td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
+ td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
+ td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
+ }
}
}
@@ -3233,6 +3382,8 @@ static void createTransNlaData(bContext *C, TransInfo *t)
int count = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
@@ -3292,12 +3443,12 @@ static void createTransNlaData(bContext *C, TransInfo *t)
}
/* allocate memory for data */
- t->total = count;
+ tc->data_len = count;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(NLA Editor)");
- td = t->data;
- t->custom.type.data = tdn = MEM_callocN(t->total * sizeof(TransDataNla), "TransDataNla (NLA Editor)");
- t->custom.type.use_free = true;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(NLA Editor)");
+ td = tc->data;
+ tc->custom.type.data = tdn = MEM_callocN(tc->data_len * sizeof(TransDataNla), "TransDataNla (NLA Editor)");
+ tc->custom.type.use_free = true;
/* loop 2: build transdata array */
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -3488,6 +3639,8 @@ static void posttrans_gpd_clean(bGPdata *gpd)
}
#endif
}
+ /* set cache flag to dirty */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
}
static void posttrans_mask_clean(Mask *mask)
@@ -3827,11 +3980,11 @@ typedef struct tGPFtransdata {
/* This function helps flush transdata written to tempdata into the gp-frames */
void flushTransIntFrameActionData(TransInfo *t)
{
- tGPFtransdata *tfd = t->custom.type.data;
- int i;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ tGPFtransdata *tfd = tc->custom.type.data;
/* flush data! */
- for (i = 0; i < t->total; i++, tfd++) {
+ for (int i = 0; i < tc->data_len; i++, tfd++) {
*(tfd->sdata) = round_fl_to_int(tfd->val);
}
}
@@ -3988,17 +4141,19 @@ static void createTransActionData(bContext *C, TransInfo *t)
return;
}
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* allocate memory for data */
- t->total = count;
+ tc->data_len = count;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(Action Editor)");
- t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "transdata2d");
- td = t->data;
- td2d = t->data2d;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)");
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d");
+ td = tc->data;
+ td2d = tc->data_2d;
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- t->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
- t->custom.type.use_free = true;
+ tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
+ tc->custom.type.use_free = true;
}
/* loop 2: build transdata array */
@@ -4043,7 +4198,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* calculate distances for proportional editing */
if (is_prop_edit) {
- td = t->data;
+ td = tc->data;
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt;
@@ -4069,7 +4224,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
else {
bGPDframe *gpf_iter;
int min = INT_MAX;
- for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf->next) {
+ for (gpf_iter = gpl->frames.first; gpf_iter; gpf_iter = gpf_iter->next) {
if (gpf_iter->flag & GP_FRAME_SELECT) {
if (FrameOnMouseSide(t->frame_side, (float)gpf_iter->framenum, cfra)) {
int val = abs(gpf->framenum - gpf_iter->framenum);
@@ -4386,18 +4541,20 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
return;
}
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* allocate memory for data */
- t->total = count;
+ tc->data_len = count;
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransData (Graph Editor)");
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData (Graph Editor)");
/* for each 2d vert a 3d vector is allocated, so that they can be treated just as if they were 3d verts */
- t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D (Graph Editor)");
- t->custom.type.data = MEM_callocN(t->total * sizeof(TransDataGraph), "TransDataGraph");
- t->custom.type.use_free = true;
+ tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D (Graph Editor)");
+ tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataGraph), "TransDataGraph");
+ tc->custom.type.use_free = true;
- td = t->data;
- td2d = t->data2d;
- tdg = t->custom.type.data;
+ td = tc->data;
+ td2d = tc->data_2d;
+ tdg = tc->custom.type.data;
/* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
unit_m3(mtx);
@@ -4524,7 +4681,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if (is_prop_edit) {
/* loop 2: build transdata arrays */
- td = t->data;
+ td = tc->data;
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
@@ -4681,11 +4838,13 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
int i, j;
char *adjusted;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* dynamically allocate an array of chars to mark whether an TransData's
* pointers have been fixed already, so that we don't override ones that are
* already done
*/
- adjusted = MEM_callocN(t->total, "beztmap_adjusted_map");
+ adjusted = MEM_callocN(tc->data_len, "beztmap_adjusted_map");
/* for each beztmap item, find if it is used anywhere */
bezm = bezms;
@@ -4693,9 +4852,9 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
/* loop through transdata, testing if we have a hit
* for the handles (vec[0]/vec[2]), we must also check if they need to be swapped...
*/
- td2d = t->data2d;
- td = t->data;
- for (j = 0; j < t->total; j++, td2d++, td++) {
+ td2d = tc->data_2d;
+ td = tc->data;
+ for (j = 0; j < tc->data_len; j++, td2d++, td++) {
/* skip item if already marked */
if (adjusted[j] != 0) continue;
@@ -4798,9 +4957,11 @@ void flushTransGraphData(TransInfo *t)
double secf = FPS;
int a;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d, tdg = t->custom.type.data;
- a < t->total;
+ for (a = 0, td = tc->data, td2d = tc->data_2d, tdg = tc->custom.type.data;
+ a < tc->data_len;
a++, td++, td2d++, tdg++)
{
AnimData *adt = (AnimData *)td->extra; /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
@@ -5162,13 +5323,15 @@ static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
}
-static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
+static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
{
Editing *ed = BKE_sequencer_editing_get(t->scene, false);
if (ed != NULL) {
+
+
ListBase *seqbasep = ed->seqbasep;
- TransData *td = t->data;
+ TransData *td = tc->data;
int a;
/* prevent updating the same seq twice
@@ -5196,7 +5359,7 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
{
int overlap = 0;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
overlap = 1;
@@ -5209,8 +5372,8 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
for (seq = seqbasep->first; seq; seq = seq->next)
seq->tmp = NULL;
- td = t->data;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
/* check effects strips, we cant change their time */
@@ -5233,8 +5396,8 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
if (t->flag & T_ALT_TRANSFORM) {
int minframe = MAXFRAME;
- td = t->data;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0)) {
minframe = min_ii(minframe, seq->startdisp);
@@ -5270,8 +5433,8 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
if (has_effect_any) {
/* update effects strips based on strips just moved in time */
- td = t->data;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
@@ -5283,8 +5446,8 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
if (has_effect_root) {
/* now if any effects _still_ overlap, we need to move them up */
- td = t->data;
- for (a = 0, seq_prev = NULL; a < t->total; a++, td++, seq_prev = seq) {
+ td = tc->data;
+ for (a = 0, seq_prev = NULL; a < tc->data_len; a++, td++, seq_prev = seq) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0)) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) {
@@ -5313,7 +5476,7 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
}
else {
/* Canceled, need to update the strips display */
- for (a = 0; a < t->total; a++, td++) {
+ for (a = 0; a < tc->data_len; a++, td++) {
seq = ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth == 0)) {
if (seq->flag & SEQ_OVERLAP)
@@ -5332,10 +5495,6 @@ static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
MEM_freeN(custom_data->data);
custom_data->data = NULL;
}
- if (t->data) {
- MEM_freeN(t->data); // XXX postTrans usually does this
- t->data = NULL;
- }
}
static void createTransSeqData(bContext *C, TransInfo *t)
@@ -5353,12 +5512,14 @@ static void createTransSeqData(bContext *C, TransInfo *t)
int count = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
if (ed == NULL) {
- t->total = 0;
+ tc->data_len = 0;
return;
}
- t->custom.type.free_cb = freeSeqData;
+ tc->custom.type.free_cb = freeSeqData;
xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]);
@@ -5397,18 +5558,18 @@ static void createTransSeqData(bContext *C, TransInfo *t)
count = SeqTransCount(t, NULL, ed->seqbasep, 0);
/* allocate memory for data */
- t->total = count;
+ tc->data_len = count;
/* stop if trying to build list if nothing selected */
if (count == 0) {
return;
}
- t->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
- t->custom.type.use_free = true;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransSeq TransData");
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransSeq TransData2D");
- ts->tdseq = tdsq = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq");
+ tc->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
+ tc->custom.type.use_free = true;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransSeq TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransSeq TransData2D");
+ ts->tdseq = tdsq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
/* loop 2: build transdata array */
SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
@@ -5446,6 +5607,7 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list)
if (ELEM(con->type,
CONSTRAINT_TYPE_FOLLOWPATH,
CONSTRAINT_TYPE_CLAMPTO,
+ CONSTRAINT_TYPE_ARMATURE,
CONSTRAINT_TYPE_OBJECTSOLVER,
CONSTRAINT_TYPE_FOLLOWTRACK))
{
@@ -5537,11 +5699,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
if (skip_invert == false && constinv == false) {
ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
- BKE_object_where_is_calc(t->scene, ob);
+ BKE_object_where_is_calc(t->depsgraph, t->scene, ob);
ob->transflag &= ~OB_NO_CONSTRAINTS;
}
else
- BKE_object_where_is_calc(t->scene, ob);
+ BKE_object_where_is_calc(t->depsgraph, t->scene, ob);
td->ob = ob;
@@ -5608,85 +5770,97 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
}
}
+static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.tag &= ~LIB_TAG_DOIT;
+ }
+}
+
+static void set_trans_object_base_deps_flag_cb(ID *id, void *UNUSED(user_data))
+{
+ /* Here we only handle object IDs. */
+ if (GS(id->name) != ID_OB) {
+ return;
+ }
+ id->tag |= LIB_TAG_DOIT;
+}
+
+static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
+{
+ object->id.tag |= LIB_TAG_DOIT;
+ DEG_foreach_dependent_ID(depsgraph, &object->id,
+ set_trans_object_base_deps_flag_cb, NULL);
+}
+
+static void trans_object_base_deps_flag_finish(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->id.tag & LIB_TAG_DOIT) {
+ base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
+ }
+ }
+}
/* sets flags in Bases to define whether they take part in transform */
/* it deselects Bases, so we have to call the clear function always after */
static void set_trans_object_base_flags(TransInfo *t)
{
Main *bmain = CTX_data_main(t->context);
- Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
View3D *v3d = t->view;
-
- /*
- * if Base selected and has parent selected:
- * base->flag = BA_WAS_SEL
+ Scene *scene = t->scene;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ /* NOTE: if Base selected and has parent selected:
+ * base->flag_legacy = BA_WAS_SEL
*/
- Base *base;
-
- /* don't do it if we're not actually going to recalculate anything */
- if (t->mode == TFM_DUMMY)
+ /* Don't do it if we're not actually going to recalculate anything. */
+ if (t->mode == TFM_DUMMY) {
return;
-
- /* makes sure base flags and object flags are identical */
- BKE_scene_base_flag_to_objects(t->scene);
-
- /* Make sure depsgraph is here. */
- DAG_scene_relations_update(bmain, t->scene);
-
- /* handle pending update events, otherwise they got copied below */
- for (base = scene->base.first; base; base = base->next) {
- if (base->object->recalc & OB_RECALC_ALL) {
- /* TODO(sergey): Ideally, it's not needed. */
- BKE_object_handle_update(bmain, bmain->eval_ctx, t->scene, base->object);
- }
}
-
- for (base = scene->base.first; base; base = base->next) {
- base->flag &= ~BA_WAS_SEL;
-
- if (TESTBASELIB_BGMODE(v3d, scene, base)) {
+ /* Makes sure base flags and object flags are identical. */
+ BKE_scene_base_flag_to_objects(t->view_layer);
+ /* Make sure depsgraph is here. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Clear all flags we need. It will be used to detect dependencies. */
+ trans_object_base_deps_flag_prepare(view_layer);
+ /* Traverse all bases and set all possible flags. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag_legacy &= ~BA_WAS_SEL;
+ if (TESTBASELIB_BGMODE(v3d, base)) {
Object *ob = base->object;
Object *parsel = ob->parent;
-
- /* if parent selected, deselect */
- while (parsel) {
- if (parsel->flag & SELECT) {
- Base *parbase = BKE_scene_base_find(scene, parsel);
- if (parbase) { /* in rare cases this can fail */
- if (TESTBASELIB_BGMODE(v3d, scene, parbase)) {
+ /* If parent selected, deselect. */
+ while (parsel != NULL) {
+ if (parsel->base_flag & BASE_SELECTED) {
+ Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
+ if (parbase != NULL) { /* in rare cases this can fail */
+ if (TESTBASELIB_BGMODE(v3d, parbase)) {
break;
}
}
}
parsel = parsel->parent;
}
-
- if (parsel) {
- /* rotation around local centers are allowed to propagate */
+ if (parsel != NULL) {
+ /* Rotation around local centers are allowed to propagate. */
if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))
{
- base->flag |= BA_TRANSFORM_CHILD;
+ base->flag_legacy |= BA_TRANSFORM_CHILD;
}
else {
- base->flag &= ~SELECT;
- base->flag |= BA_WAS_SEL;
+ base->flag &= ~BASE_SELECTED;
+ base->flag_legacy |= BA_WAS_SEL;
}
}
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
- }
- }
-
- /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
- DAG_scene_flush_update(bmain, t->scene, -1, 0);
-
- /* and we store them temporal in base (only used for transform code) */
- /* this because after doing updates, the object->recalc is cleared */
- for (base = scene->base.first; base; base = base->next) {
- if (base->object->recalc & (OB_RECALC_OB | OB_RECALC_DATA)) {
- base->flag |= BA_SNAP_FIX_DEPS_FIASCO;
+ flush_trans_object_base_deps_flag(depsgraph, ob);
}
}
+ /* Store temporary bits in base indicating that base is being modified
+ * (directly or indirectly) by transforming objects.
+ */
+ trans_object_base_deps_flag_finish(view_layer);
}
static bool mark_children(Object *ob)
@@ -5707,79 +5881,70 @@ static bool mark_children(Object *ob)
static int count_proportional_objects(TransInfo *t)
{
int total = 0;
- Main *bmain = CTX_data_main(t->context);
- Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
View3D *v3d = t->view;
- Base *base;
-
- /* rotations around local centers are allowed to propagate, so we take all objects */
+ Scene *scene = t->scene;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ /* Clear all flags we need. It will be used to detect dependencies. */
+ trans_object_base_deps_flag_prepare(view_layer);
+ /* Rotations around local centers are allowed to propagate, so we take all objects. */
if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)))
{
- /* mark all parents */
- for (base = scene->base.first; base; base = base->next) {
- if (TESTBASELIB_BGMODE(v3d, scene, base)) {
+ /* Mark all parents. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (TESTBASELIB_BGMODE(v3d, base)) {
Object *parent = base->object->parent;
-
/* flag all parents */
- while (parent) {
+ while (parent != NULL) {
parent->flag |= BA_TRANSFORM_PARENT;
parent = parent->parent;
}
}
}
-
- /* mark all children */
- for (base = scene->base.first; base; base = base->next) {
+ /* Mark all children. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
/* all base not already selected or marked that is editable */
- if ((base->object->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- (BASE_EDITABLE_BGMODE(v3d, scene, base)))
+ if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 &&
+ (BASE_EDITABLE_BGMODE(v3d, base)))
{
mark_children(base->object);
}
}
}
-
- for (base = scene->base.first; base; base = base->next) {
+ /* Flush changed flags to all dependencies. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
Object *ob = base->object;
-
- /* if base is not selected, not a parent of selection or not a child of selection and it is editable */
- if ((ob->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- (BASE_EDITABLE_BGMODE(v3d, scene, base)))
+ /* If base is not selected, not a parent of selection or not a child of
+ * selection and it is editable.
+ */
+ if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 &&
+ (BASE_EDITABLE_BGMODE(v3d, base)))
{
-
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
-
+ flush_trans_object_base_deps_flag(depsgraph, ob);
total += 1;
}
}
-
-
- /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
- DAG_scene_relations_update(bmain, t->scene);
- DAG_scene_flush_update(bmain, t->scene, -1, 0);
-
- /* and we store them temporal in base (only used for transform code) */
- /* this because after doing updates, the object->recalc is cleared */
- for (base = scene->base.first; base; base = base->next) {
- if (base->object->recalc & (OB_RECALC_OB | OB_RECALC_DATA)) {
- base->flag |= BA_SNAP_FIX_DEPS_FIASCO;
- }
- }
-
+ /* Store temporary bits in base indicating that base is being modified
+ * (directly or indirectly) by transforming objects.
+ */
+ trans_object_base_deps_flag_finish(view_layer);
return total;
}
static void clear_trans_object_base_flags(TransInfo *t)
{
- Scene *sce = t->scene;
+ ViewLayer *view_layer = t->view_layer;
Base *base;
- for (base = sce->base.first; base; base = base->next) {
- if (base->flag & BA_WAS_SEL)
- base->flag |= SELECT;
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->flag_legacy & BA_WAS_SEL) {
+ base->flag |= BASE_SELECTED;
+ }
- base->flag &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
+ base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
}
}
@@ -5787,7 +5952,7 @@ static void clear_trans_object_base_flags(TransInfo *t)
* tmode: should be a transform mode
*/
// NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases
-void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode)
+void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
{
Main *bmain = CTX_data_main(C);
ID *id = &ob->id;
@@ -5795,6 +5960,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
// TODO: this should probably be done per channel instead...
if (autokeyframe_cfra_can_key(scene, id)) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
@@ -5821,7 +5987,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
if (adt && adt->action) {
for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
fcu->flag &= ~FCURVE_SELECTED;
- insert_keyframe(bmain, reports, id, adt->action,
+ insert_keyframe(bmain, depsgraph, reports, id, adt->action,
(fcu->grp ? fcu->grp->name : NULL),
fcu->rna_path, fcu->array_index, cfra,
ts->keyframe_type, flag);
@@ -5836,26 +6002,30 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
do_loc = true;
}
else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (v3d->around == V3D_AROUND_ACTIVE) {
- if (ob != OBACT)
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
+ if (ob != OBACT(view_layer))
do_loc = true;
}
- else if (v3d->around == V3D_AROUND_CURSOR)
+ else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
do_loc = true;
+ }
- if ((v3d->flag & V3D_ALIGN) == 0)
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
do_rot = true;
+ }
}
else if (tmode == TFM_RESIZE) {
- if (v3d->around == V3D_AROUND_ACTIVE) {
- if (ob != OBACT)
+ if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
+ if (ob != OBACT(view_layer))
do_loc = true;
}
- else if (v3d->around == V3D_AROUND_CURSOR)
+ else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
do_loc = true;
+ }
- if ((v3d->flag & V3D_ALIGN) == 0)
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
do_scale = true;
+ }
}
/* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
@@ -5878,33 +6048,33 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
}
- /* only calculate paths if there are paths to be recalculated,
- * assuming that since we've autokeyed the transforms this is
- * now safe to apply...
- *
- * NOTE: only do this when there's context info
- */
- if (C && (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- //ED_objects_clear_paths(C); // XXX for now, don't need to clear
- ED_objects_recalculate_paths(C, scene);
-
- /* XXX: there's potential here for problems with unkeyed rotations/scale,
- * but for now (until proper data-locality for baking operations),
- * this should be a better fix for T24451 and T37755
- */
- }
-
/* free temp info */
BLI_freelistN(&dsources);
}
}
+/* Return if we need to update motion paths, only if they already exist,
+ * and we will insert a keyframe at the end of transform. */
+bool motionpath_need_update_object(Scene *scene, Object *ob)
+{
+ /* XXX: there's potential here for problems with unkeyed rotations/scale,
+ * but for now (until proper data-locality for baking operations),
+ * this should be a better fix for T24451 and T37755
+ */
+
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+ }
+
+ return false;
+}
+
/* auto-keyframing feature - for poses/pose-channels
* tmode: should be a transform mode
* targetless_ik: has targetless ik been done on any channels?
*/
// NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases
-void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode, short targetless_ik)
+void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik)
{
Main *bmain = CTX_data_main(C);
ID *id = &ob->id;
@@ -5916,6 +6086,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
// TODO: this should probably be done per channel instead...
if (autokeyframe_cfra_can_key(scene, id)) {
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
@@ -5959,7 +6130,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
* NOTE: this will do constraints too, but those are ok to do here too?
*/
if (pchanName && STREQ(pchanName, pchan->name)) {
- insert_keyframe(bmain, reports, id, act,
+ insert_keyframe(bmain, depsgraph, reports, id, act,
((fcu->grp) ? (fcu->grp->name) : (NULL)),
fcu->rna_path, fcu->array_index, cfra,
ts->keyframe_type, flag);
@@ -5982,18 +6153,22 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
do_loc = true;
}
else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
+ if (ELEM(scene->toolsettings->transform_pivot_point, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE)) {
do_loc = true;
+ }
- if ((v3d->flag & V3D_ALIGN) == 0)
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
do_rot = true;
+ }
}
else if (tmode == TFM_RESIZE) {
- if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
+ if (ELEM(scene->toolsettings->transform_pivot_point, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE)) {
do_loc = true;
+ }
- if ((v3d->flag & V3D_ALIGN) == 0)
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
do_scale = true;
+ }
}
if (do_loc) {
@@ -6019,16 +6194,6 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
BLI_freelistN(&dsources);
}
}
-
- /* do the bone paths
- * - only do this when there is context info, since we need that to resolve
- * how to do the updates and so on...
- * - do not calculate unless there are paths already to update...
- */
- if (C && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
- ED_pose_recalculate_paths(bmain, scene, ob);
- }
}
else {
/* tag channels that should have unkeyed data */
@@ -6041,6 +6206,17 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
}
}
+/* Return if we need to update motion paths, only if they already exist,
+ * and we will insert a keyframe at the end of transform. */
+bool motionpath_need_update_pose(Scene *scene, Object *ob)
+{
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ return (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+ }
+
+ return false;
+}
+
static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
{
SpaceClip *sc = t->sa->spacedata.first;
@@ -6115,8 +6291,9 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
}
}
-static void special_aftertrans_update__node(bContext *UNUSED(C), TransInfo *t)
+static void special_aftertrans_update__node(bContext *C, TransInfo *t)
{
+ Main *bmain = CTX_data_main(C);
const bool canceled = (t->state == TRANS_CANCEL);
if (canceled && t->remove_on_cancel) {
@@ -6128,7 +6305,7 @@ static void special_aftertrans_update__node(bContext *UNUSED(C), TransInfo *t)
for (node = ntree->nodes.first; node; node = node_next) {
node_next = node->next;
if (node->flag & NODE_SELECT)
- nodeFreeNode(ntree, node);
+ nodeDeleteNode(bmain, ntree, node);
}
}
}
@@ -6138,39 +6315,42 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
/* so automerge supports mirror */
if ((t->scene->toolsettings->automerge) &&
- (t->obedit && t->obedit->type == OB_MESH))
+ ((t->flag & T_EDIT) && t->obedit_type == OB_MESH))
{
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
- BMesh *bm = em->bm;
- char hflag;
- bool has_face_sel = (bm->totfacesel != 0);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if (t->flag & T_MIRROR) {
- TransData *td;
- int i;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+ char hflag;
+ bool has_face_sel = (bm->totfacesel != 0);
- /* rather then adjusting the selection (which the user would notice)
- * tag all mirrored verts, then automerge those */
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+ if (t->flag & T_MIRROR) {
+ TransData *td;
+ int i;
+
+ /* rather then adjusting the selection (which the user would notice)
+ * tag all mirrored verts, then automerge those */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
- for (i = 0, td = t->data; i < t->total; i++, td++) {
- if (td->extra) {
- BM_elem_flag_enable((BMVert *)td->extra, BM_ELEM_TAG);
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ if (td->extra) {
+ BM_elem_flag_enable((BMVert *)td->extra, BM_ELEM_TAG);
+ }
}
- }
- hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
- }
- else {
- hflag = BM_ELEM_SELECT;
- }
+ hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
+ }
+ else {
+ hflag = BM_ELEM_SELECT;
+ }
- EDBM_automerge(t->scene, t->obedit, true, hflag);
+ EDBM_automerge(t->scene, tc->obedit, true, hflag);
- /* Special case, this is needed or faces won't re-select.
- * Flush selected edges to faces. */
- if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
- EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
+ /* Special case, this is needed or faces won't re-select.
+ * Flush selected edges to faces. */
+ if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_EDGE);
+ }
}
}
}
@@ -6191,50 +6371,53 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
const bool duplicate = (t->mode == TFM_TIME_DUPLICATE);
/* early out when nothing happened */
- if (t->total == 0 || t->mode == TFM_DUMMY)
+ if (t->data_len_all == 0 || t->mode == TFM_DUMMY) {
return;
+ }
if (t->spacetype == SPACE_VIEW3D) {
- if (t->obedit) {
+ if (t->flag & T_EDIT) {
/* Special Exception:
* We don't normally access 't->custom.mode' here, but its needed in this case. */
if (canceled == 0) {
/* we need to delete the temporary faces before automerging */
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->custom.mode.data;
-
/* handle multires re-projection, done
* on transform completion since it's
* really slow -joeedh */
projectEdgeSlideData(t, true);
- /* free temporary faces to avoid automerging and deleting
- * during cleanup - psy-fi */
- freeEdgeSlideTempFaces(sld);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+
+ /* free temporary faces to avoid automerging and deleting
+ * during cleanup - psy-fi */
+ freeEdgeSlideTempFaces(sld);
+ }
}
else if (t->mode == TFM_VERT_SLIDE) {
/* as above */
- VertSlideData *sld = t->custom.mode.data;
projectVertSlideData(t, true);
- freeVertSlideTempFaces(sld);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ VertSlideData *sld = tc->custom.mode.data;
+ freeVertSlideTempFaces(sld);
+ }
}
- if (t->obedit->type == OB_MESH) {
+ if (t->obedit_type == OB_MESH) {
special_aftertrans_update__mesh(C, t);
}
}
else {
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->custom.mode.data;
-
- sld->perc = 0.0;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ slp->perc = 0.0;
projectEdgeSlideData(t, false);
}
else if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = t->custom.mode.data;
-
- sld->perc = 0.0;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ slp->perc = 0.0;
projectVertSlideData(t, false);
}
}
@@ -6340,9 +6523,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
// fixme... some of this stuff is not good
if (ob) {
if (ob->pose || BKE_key_from_object(ob))
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
else
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
}
/* 3 cases here for curve cleanups:
@@ -6508,78 +6691,116 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
ED_nla_postop_refresh(&ac);
}
}
- else if (t->obedit) {
- if (t->obedit->type == OB_MESH) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
- /* table needs to be created for each edit command, since vertices can move etc */
- ED_mesh_mirror_spatial_table(t->obedit, em, NULL, NULL, 'e');
+ else if (t->flag & T_EDIT) {
+ if (t->obedit_type == OB_MESH) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ /* table needs to be created for each edit command, since vertices can move etc */
+ ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
+ /* TODO(campbell): xform: We need support for many mirror objects at once! */
+ break;
+ }
}
}
- else if ((t->flag & T_POSE) && (t->poseobj)) {
- bArmature *arm;
- bPoseChannel *pchan;
- short targetless_ik = 0;
+ else if (t->flag & T_POSE && (t->mode == TFM_BONESIZE)) {
+ /* Handle the exception where for TFM_BONESIZE in edit mode we pretend to be
+ * in pose mode (to use bone orientation matrix), in that case we don't do operations like autokeyframing. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ob = tc->poseobj;
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ }
+ else if (t->flag & T_POSE) {
+ GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
- ob = t->poseobj;
- arm = ob->data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- if ((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
- /* when running transform non-interactively (operator exec),
- * we need to update the pose otherwise no updates get called during
- * transform and the auto-ik is not applied. see [#26164] */
- struct Object *pose_ob = t->poseobj;
- BKE_pose_where_is(t->scene, pose_ob);
- }
+ bArmature *arm;
+ bPoseChannel *pchan;
+ short targetless_ik = 0;
- /* set BONE_TRANSFORM flags for autokey, manipulator draw might have changed them */
- if (!canceled && (t->mode != TFM_DUMMY))
- count_set_pose_transflags(&t->mode, t->around, ob);
+ ob = tc->poseobj;
+ arm = ob->data;
- /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
- if (!canceled && t->mode == TFM_TRANSLATION)
- targetless_ik = apply_targetless_ik(ob);
- else {
- /* not forget to clear the auto flag */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bKinematicConstraint *data = has_targetless_ik(pchan);
- if (data) data->flag &= ~CONSTRAINT_IK_AUTO;
+ if ((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
+ /* when running transform non-interactively (operator exec),
+ * we need to update the pose otherwise no updates get called during
+ * transform and the auto-ik is not applied. see [#26164] */
+ struct Object *pose_ob = tc->poseobj;
+ BKE_pose_where_is(t->depsgraph, t->scene, pose_ob);
}
- }
- if (t->mode == TFM_TRANSLATION)
- pose_grab_with_ik_clear(bmain, ob);
+ /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
+ if (!canceled && (t->mode != TFM_DUMMY)) {
+ count_set_pose_transflags(ob, t->mode, t->around, NULL);
+ }
- /* automatic inserting of keys and unkeyed tagging - only if transform wasn't canceled (or TFM_DUMMY) */
- if (!canceled && (t->mode != TFM_DUMMY)) {
- autokeyframe_pose_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
- else if (arm->flag & ARM_DELAYDEFORM) {
- /* old optimize trick... this enforces to bypass the depgraph */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- ob->recalc = 0; // is set on OK position already by recalcData()
+ /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
+ if (!canceled && t->mode == TFM_TRANSLATION)
+ targetless_ik = apply_targetless_ik(ob);
+ else {
+ /* not forget to clear the auto flag */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data) data->flag &= ~CONSTRAINT_IK_AUTO;
+ }
+ }
+
+ if (t->mode == TFM_TRANSLATION)
+ pose_grab_with_ik_clear(bmain, ob);
+
+ /* automatic inserting of keys and unkeyed tagging - only if transform wasn't canceled (or TFM_DUMMY) */
+ if (!canceled && (t->mode != TFM_DUMMY)) {
+ autokeyframe_pose(C, t->scene, ob, t->mode, targetless_ik);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else if (arm->flag & ARM_DELAYDEFORM) {
+ /* TODO(sergey): Armature is already updated by recalcData(), so we
+ * might save some time by skipping re-evaluating it. But this isn't
+ * possible yet within new dependency graph, and also other contexts
+ * might need to update their CoW copies.
+ */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ if (t->mode != TFM_DUMMY && motionpath_need_update_pose(t->scene, ob)) {
+ BLI_gset_insert(motionpath_updates, ob);
+ }
}
- else
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* Update motion paths once for all transformed bones in an object. */
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, motionpath_updates) {
+ bool current_frame_only = canceled;
+ ob = BLI_gsetIterator_getKey(&gs_iter);
+ ED_pose_recalculate_paths(C, t->scene, ob, current_frame_only);
+ }
+ BLI_gset_free(motionpath_updates, NULL);
}
else if (t->options & CTX_PAINT_CURVE) {
/* pass */
}
- else if ((t->scene->basact) &&
- (ob = t->scene->basact->object) &&
+ else if ((t->view_layer->basact) &&
+ (ob = t->view_layer->basact->object) &&
(ob->mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(bmain, t->scene, ob))
+ PE_get_current(t->scene, ob))
{
/* do nothing */
}
+ else if (t->flag & T_CURSOR) {
+ /* do nothing */
+ }
else { /* Objects */
- int i;
-
BLI_assert(t->flag & (T_OBJECT | T_TEXTURE));
- for (i = 0; i < t->total; i++) {
- TransData *td = t->data + i;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ bool motionpath_update = false;
+
+ for (int i = 0; i < tc->data_len; i++) {
+ TransData *td = tc->data + i;
ListBase pidlist;
PTCacheID *pid;
ob = td->ob;
@@ -6591,7 +6812,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
continue;
/* flag object caches as outdated */
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, t->scene, MAX_DUPLI_RECUR);
+ BKE_ptcache_ids_from_object(&pidlist, ob, t->scene, MAX_DUPLI_RECUR);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->type != PTCACHE_TYPE_PARTICLES) /* particles don't need reset on geometry change */
pid->cache->flag |= PTCACHE_OUTDATED;
@@ -6600,19 +6821,21 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* pointcache refresh */
if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED))
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
/* Needed for proper updating of "quick cached" dynamics. */
/* Creates troubles for moving animated objects without */
/* autokey though, probably needed is an anim sys override? */
/* Please remove if some other solution is found. -jahka */
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
/* Set autokey if necessary */
if (!canceled) {
- autokeyframe_ob_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode);
+ autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
}
+ motionpath_update |= motionpath_need_update_object(t->scene, ob);
+
/* restore rigid body transform */
if (ob->rigidbody_object && canceled) {
float ctime = BKE_scene_frame_get(t->scene);
@@ -6620,6 +6843,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
BKE_rigidbody_aftertrans_update(ob, td->ext->oloc, td->ext->orot, td->ext->oquat, td->ext->orotAxis, td->ext->orotAngle);
}
}
+
+ if (motionpath_update) {
+ /* Update motion paths once for all transformed objects. */
+ bool current_frame_only = canceled;
+ ED_objects_recalculate_paths(C, t->scene, current_frame_only);
+ }
}
clear_trans_object_base_flags(t);
@@ -6633,7 +6862,7 @@ int special_transform_moving(TransInfo *t)
else if (t->spacetype == SPACE_IPO) {
return G_TRANSFORM_FCURVES;
}
- else if (t->obedit || ((t->flag & T_POSE) && (t->poseobj))) {
+ else if ((t->flag & T_EDIT) || (t->flag & T_POSE)) {
return G_TRANSFORM_EDIT;
}
else if (t->flag & (T_OBJECT | T_TEXTURE)) {
@@ -6645,29 +6874,29 @@ int special_transform_moving(TransInfo *t)
static void createTransObject(bContext *C, TransInfo *t)
{
- Scene *scene = t->scene;
-
TransData *td = NULL;
TransDataExtension *tx;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
set_trans_object_base_flags(t);
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* count */
- t->total = CTX_DATA_COUNT(C, selected_objects);
+ tc->data_len = CTX_DATA_COUNT(C, selected_objects);
- if (!t->total) {
+ if (!tc->data_len) {
/* clear here, main transform function escapes too */
clear_trans_object_base_flags(t);
return;
}
if (is_prop_edit) {
- t->total += count_proportional_objects(t);
+ tc->data_len += count_proportional_objects(t);
}
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransOb");
- tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "TransObExtension");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransOb");
+ tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObExtension");
CTX_DATA_BEGIN(C, Base *, base, selected_bases)
{
@@ -6696,15 +6925,17 @@ static void createTransObject(bContext *C, TransInfo *t)
CTX_DATA_END;
if (is_prop_edit) {
+ ViewLayer *view_layer = t->view_layer;
View3D *v3d = t->view;
Base *base;
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
Object *ob = base->object;
/* if base is not selected, not a parent of selection or not a child of selection and it is editable */
- if ((ob->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
- BASE_EDITABLE_BGMODE(v3d, scene, base))
+ if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
+ (base->flag & BASE_SELECTED) == 0 &&
+ BASE_EDITABLE_BGMODE(v3d, base))
{
td->protectflag = ob->protectflag;
td->ext = tx;
@@ -6786,7 +7017,9 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
SpaceNode *snode = t->sa->spacedata.first;
bNode *node;
- t->total = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
if (!snode->edittree) {
return;
@@ -6799,15 +7032,15 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
for (node = snode->edittree->nodes.first; node; node = node->next) {
if (node->flag & NODE_SELECT && is_node_parent_select(node) == false) {
node->flag |= NODE_TRANSFORM;
- t->total++;
+ tc->data_len++;
}
else {
node->flag &= ~NODE_TRANSFORM;
}
}
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransNode TransData");
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransNode TransData2D");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransNode TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransNode TransData2D");
for (node = snode->edittree->nodes.first; node; node = node->next) {
if (node->flag & NODE_TRANSFORM) {
@@ -6992,7 +7225,7 @@ static void planeTrackToTransData(const int framenr, TransData *td, TransData2D
}
}
-static void transDataTrackingFree(TransInfo *UNUSED(t), TransCustomData *custom_data)
+static void transDataTrackingFree(TransInfo *UNUSED(t), TransDataContainer *UNUSED(tc), TransCustomData *custom_data)
{
if (custom_data->data) {
TransDataTracking *tdt = custom_data->data;
@@ -7017,22 +7250,24 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
TransDataTracking *tdt;
int framenr = ED_space_clip_get_clip_frame_number(sc);
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* count */
- t->total = 0;
+ tc->data_len = 0;
track = tracksbase->first;
while (track) {
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- t->total++; /* offset */
+ tc->data_len++; /* offset */
if (track->flag & SELECT)
- t->total++;
+ tc->data_len++;
if (track->pat_flag & SELECT)
- t->total += 4;
+ tc->data_len += 4;
if (track->search_flag & SELECT)
- t->total += 2;
+ tc->data_len += 2;
}
track = track->next;
@@ -7043,18 +7278,18 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
plane_track = plane_track->next)
{
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- t->total += 4;
+ tc->data_len += 4;
}
}
- if (t->total == 0)
+ if (tc->data_len == 0)
return;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
- tdt = t->custom.type.data = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransTracking TransData2D");
+ tdt = tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking), "TransTracking TransDataTracking");
- t->custom.type.free_cb = transDataTrackingFree;
+ tc->custom.type.free_cb = transDataTrackingFree;
/* create actual data */
track = tracksbase->first;
@@ -7156,8 +7391,10 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* count */
- t->total = 0;
+ tc->data_len = 0;
if ((sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) == 0) {
return;
@@ -7174,23 +7411,23 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
continue;
if (marker->flag & MARKER_GRAPH_SEL_X)
- t->total += 1;
+ tc->data_len += 1;
if (marker->flag & MARKER_GRAPH_SEL_Y)
- t->total += 1;
+ tc->data_len += 1;
}
}
track = track->next;
}
- if (t->total == 0)
+ if (tc->data_len == 0)
return;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
- t->custom.type.data = tdt = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
- t->custom.type.free_cb = transDataTrackingFree;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransTracking TransData2D");
+ tc->custom.type.data = tdt = MEM_callocN(tc->data_len * sizeof(TransDataTracking), "TransTracking TransDataTracking");
+ tc->custom.type.free_cb = transDataTrackingFree;
/* create actual data */
track = tracksbase->first;
@@ -7231,7 +7468,9 @@ static void createTransTrackingData(bContext *C, TransInfo *t)
MovieClip *clip = ED_space_clip_get_clip(sc);
int width, height;
- t->total = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
if (!clip)
return;
@@ -7252,12 +7491,14 @@ static void createTransTrackingData(bContext *C, TransInfo *t)
static void cancelTransTracking(TransInfo *t)
{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
SpaceClip *sc = t->sa->spacedata.first;
int i, framenr = ED_space_clip_get_clip_frame_number(sc);
- TransDataTracking *tdt_array = t->custom.type.data;
+ TransDataTracking *tdt_array = tc->custom.type.data;
+
i = 0;
- while (i < t->total) {
+ while (i < tc->data_len) {
TransDataTracking *tdt = &tdt_array[i];
if (tdt->mode == transDataTracking_ModeTracks) {
@@ -7314,8 +7555,10 @@ void flushTransTracking(TransInfo *t)
if (t->state == TRANS_CANCEL)
cancelTransTracking(t);
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d, tdt = t->custom.type.data; a < t->total; a++, td2d++, td++, tdt++) {
+ for (a = 0, td = tc->data, td2d = tc->data_2d, tdt = tc->custom.type.data; a < tc->data_len; a++, td2d++, td++, tdt++) {
if (tdt->mode == transDataTracking_ModeTracks) {
float loc2d[2];
@@ -7581,7 +7824,9 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
const bool is_prop_edit = (t->flag & T_PROP_EDIT);
float asp[2];
- t->total = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
if (!mask)
return;
@@ -7641,13 +7886,13 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
- t->total = (is_prop_edit) ? count : countsel;
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mask Editing)");
+ tc->data_len = (is_prop_edit) ? count : countsel;
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransObData2D(Mask Editing)");
- t->custom.type.data = tdm = MEM_callocN(t->total * sizeof(TransDataMasking), "TransDataMasking(Mask Editing)");
- t->custom.type.use_free = true;
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(Mask Editing)");
+ tc->custom.type.data = tdm = MEM_callocN(tc->data_len * sizeof(TransDataMasking), "TransDataMasking(Mask Editing)");
+ tc->custom.type.use_free = true;
/* create data */
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
@@ -7704,12 +7949,14 @@ void flushTransMasking(TransInfo *t)
int a;
float asp[2], inv[2];
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
inv[0] = 1.0f / asp[0];
inv[1] = 1.0f / asp[1];
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data2d, tdm = t->custom.type.data; a < t->total; a++, td++, tdm++) {
+ for (a = 0, td = tc->data_2d, tdm = tc->custom.type.data; a < tc->data_len; a++, td++, tdm++) {
td->loc2d[0] = td->loc[0] * inv[0];
td->loc2d[1] = td->loc[1] * inv[1];
mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d);
@@ -7828,7 +8075,9 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
int i;
int total = 0;
- t->total = 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ tc->data_len = 0;
if (!paint || !paint->brush || !paint->brush->paint_curve)
return;
@@ -7854,11 +8103,11 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
if (!total)
return;
- t->total = total;
- td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D");
- td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransData");
- t->custom.type.data = tdpc = MEM_callocN(t->total * sizeof(TransDataPaintCurve), "TransDataPaintCurve");
- t->custom.type.use_free = true;
+ tc->data_len = total;
+ td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransData2D");
+ td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData");
+ tc->custom.type.data = tdpc = MEM_callocN(tc->data_len * sizeof(TransDataPaintCurve), "TransDataPaintCurve");
+ tc->custom.type.use_free = true;
for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
if (PC_IS_ANY_SEL(pcp)) {
@@ -7889,10 +8138,13 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
void flushTransPaintCurve(TransInfo *t)
{
int i;
- TransData2D *td2d = t->data2d;
- TransDataPaintCurve *tdpc = t->custom.type.data;
- for (i = 0; i < t->total; i++, tdpc++, td2d++) {
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ TransData2D *td2d = tc->data_2d;
+ TransDataPaintCurve *tdpc = tc->custom.type.data;
+
+ for (i = 0; i < tc->data_len; i++, tdpc++, td2d++) {
PaintCurvePoint *pcp = tdpc->pcp;
copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc);
}
@@ -7901,7 +8153,14 @@ void flushTransPaintCurve(TransInfo *t)
static void createTransGPencil(bContext *C, TransInfo *t)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C); \
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+
+ Object *obact = CTX_data_active_object(C);
bGPDlayer *gpl;
TransData *td = NULL;
float mtx[3][3], smtx[3][3];
@@ -7912,6 +8171,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* == Grease Pencil Strokes to Transform Data ==
* Grease Pencil stroke points can be a mixture of 2D (screen-space),
@@ -7919,67 +8179,84 @@ static void createTransGPencil(bContext *C, TransInfo *t)
* For now, we just do these without creating TransData2D for the 2D
* strokes. This may cause issues in future though.
*/
- t->total = 0;
+ tc->data_len = 0;
if (gpd == NULL)
return;
+ /* initialize falloff curve */
+ if (is_multiedit) {
+ curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
/* First Pass: Count the number of datapoints required for the strokes,
* (and additional info about the configuration - e.g. 2D/3D?)
*/
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf = gpl->actframe;
+ bGPDframe *gpf;
bGPDstroke *gps;
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
- if (is_prop_edit) {
- /* Proportional Editing... */
- if (is_prop_edit_connected) {
- /* connected only - so only if selected */
- if (gps->flag & GP_STROKE_SELECT)
- t->total += gps->totpoints;
- }
- else {
- /* everything goes - connection status doesn't matter */
- t->total += gps->totpoints;
- }
- }
- else {
- /* only selected stroke points are considered */
- if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- // TODO: 2D vs 3D?
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT)
- t->total++;
+ if (is_prop_edit) {
+ /* Proportional Editing... */
+ if (is_prop_edit_connected) {
+ /* connected only - so only if selected */
+ if (gps->flag & GP_STROKE_SELECT)
+ tc->data_len += gps->totpoints;
+ }
+ else {
+ /* everything goes - connection status doesn't matter */
+ tc->data_len += gps->totpoints;
+ }
+ }
+ else {
+ /* only selected stroke points are considered */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ // TODO: 2D vs 3D?
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT)
+ tc->data_len++;
+ }
+ }
}
}
}
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
+ }
}
}
}
/* Stop trying if nothing selected */
- if (t->total == 0) {
+ if (tc->data_len == 0) {
return;
}
/* Allocate memory for data */
- t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(GPencil)");
- td = t->data;
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(GPencil)");
+ td = tc->data;
unit_m3(smtx);
unit_m3(mtx);
@@ -7994,176 +8271,236 @@ static void createTransGPencil(bContext *C, TransInfo *t)
float diff_mat[4][4];
float inverse_diff_mat[4][4];
- /* calculate difference matrix if parent object */
- if (gpl->parent != NULL) {
- ED_gpencil_parent_location(gpl, diff_mat);
- /* undo matrix */
- invert_m4_m4(inverse_diff_mat, diff_mat);
+ bGPDframe *init_gpf = gpl->actframe;
+ if (is_multiedit) {
+ init_gpf = gpl->frames.first;
+ }
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (use_multiframe_falloff) {
+ BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
}
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ /* undo matrix */
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+
/* Make a new frame to work on if the layer's frame and the current scene frame don't match up
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame...
*/
- if (gpf->framenum != cfra) {
+ // XXX: should this be allowed when framelock is enabled?
+ if ((gpf->framenum != cfra) && (!is_multiedit)) {
gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
/* in some weird situations (framelock enabled) return NULL */
if (gpf == NULL) {
continue;
}
+ if (!is_multiedit) {
+ init_gpf = gpf;
+ }
}
/* Loop over strokes, adding TransData for points as needed... */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- TransData *head = td;
- TransData *tail = td;
- bool stroke_ok;
-
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
- /* What we need to include depends on proportional editing settings... */
- if (is_prop_edit) {
- if (is_prop_edit_connected) {
- /* A) "Connected" - Only those in selected strokes */
- stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+
+ /* if multiframe and falloff, recalculate and save value */
+ float falloff = 1.0f; /* by default no falloff */
+ if ((is_multiedit) && (use_multiframe_falloff)) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ falloff = BKE_gpencil_multiframe_falloff_calc(gpf, gpl->actframe->framenum,
+ f_init, f_end, ts->gp_sculpt.cur_falloff);
}
- else {
- /* B) All points, always */
- stroke_ok = true;
- }
- }
- else {
- /* C) Only selected points in selected strokes */
- stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
- }
- /* Do stroke... */
- if (stroke_ok && gps->totpoints) {
- bGPDspoint *pt;
- int i;
-
-#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */
- const float ninv = 1.0f / gps->totpoints;
- float center[3] = {0.0f};
-
- /* compute midpoint of stroke */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- madd_v3_v3v3fl(center, center, &pt->x, ninv);
- }
-#endif
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ TransData *head = td;
+ TransData *tail = td;
+ bool stroke_ok;
- /* add all necessary points... */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- bool point_ok;
-
- /* include point? */
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+ /* What we need to include depends on proportional editing settings... */
if (is_prop_edit) {
- /* Always all points in strokes that get included */
- point_ok = true;
+ if (is_prop_edit_connected) {
+ /* A) "Connected" - Only those in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
+ }
+ else {
+ /* B) All points, always */
+ stroke_ok = true;
+ }
}
else {
- /* Only selected points in selected strokes */
- point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
+ /* C) Only selected points in selected strokes */
+ stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
}
- /* do point... */
- if (point_ok) {
- copy_v3_v3(td->iloc, &pt->x);
- copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local?
-
- td->loc = &pt->x;
-
- td->flag = 0;
+ /* Do stroke... */
+ if (stroke_ok && gps->totpoints) {
+ bGPDspoint *pt;
+ int i;
- if (pt->flag & GP_SPOINT_SELECT)
- td->flag |= TD_SELECTED;
-
- /* for other transform modes (e.g. shrink-fatten), need to additional data */
- if (t->mode == TFM_GPENCIL_SHRINKFATTEN) {
- td->val = &pt->pressure;
- td->ival = pt->pressure;
- }
+ /* save falloff factor */
+ gps->runtime.multi_frame_falloff = falloff;
- /* screenspace needs special matrices... */
- if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) {
- /* screenspace */
- td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ /* add all necessary points... */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bool point_ok;
- /* apply parent transformations */
- if (gpl->parent == NULL) {
- copy_m3_m4(td->smtx, t->persmat);
- copy_m3_m4(td->mtx, t->persinv);
- unit_m3(td->axismtx);
+ /* include point? */
+ if (is_prop_edit) {
+ /* Always all points in strokes that get included */
+ point_ok = true;
}
else {
- /* apply matrix transformation relative to parent */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
- }
- }
- else {
- /* configure 2D dataspace points so that they don't play up... */
- if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
- td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- // XXX: matrices may need to be different?
+ /* Only selected points in selected strokes */
+ point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
}
- /* apply parent transformations */
- if (gpl->parent == NULL) {
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- unit_m3(td->axismtx); // XXX?
- }
- else {
- /* apply matrix transformation relative to parent */
- copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
- copy_m3_m4(td->mtx, diff_mat); /* display position */
- copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ /* do point... */
+ if (point_ok) {
+ copy_v3_v3(td->iloc, &pt->x);
+ copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local?
+
+ td->loc = &pt->x;
+
+ td->flag = 0;
+
+ if (pt->flag & GP_SPOINT_SELECT)
+ td->flag |= TD_SELECTED;
+
+ /* for other transform modes (e.g. shrink-fatten), need to additional data
+ * but never for scale or mirror
+ */
+ if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) {
+ td->val = &pt->pressure;
+ td->ival = pt->pressure;
+ }
+
+ /* screenspace needs special matrices... */
+ if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) {
+ /* screenspace */
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+
+ /* apply matrix transformation relative to parent */
+ copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m4(td->mtx, diff_mat); /* display position */
+ copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ }
+ else {
+ /* configure 2D dataspace points so that they don't play up... */
+ if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ // XXX: matrices may need to be different?
+ }
+
+ /* apply parent transformations */
+ copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */
+ copy_m3_m4(td->mtx, diff_mat); /* display position */
+ copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */
+ }
+ /* Triangulation must be calculated again, so save the stroke for recalc function */
+ td->extra = gps;
+
+ /* save pointer to object */
+ td->ob = obact;
+
+ td++;
+ tail++;
}
}
- /* Triangulation must be calculated again, so save the stroke for recalc function */
- td->extra = gps;
- td++;
- tail++;
+ /* March over these points, and calculate the proportional editing distances */
+ if (is_prop_edit && (head != tail)) {
+ /* XXX: for now, we are similar enough that this works... */
+ calc_distanceCurveVerts(head, tail - 1);
+ }
}
}
-
- /* March over these points, and calculate the proportional editing distances */
- if (is_prop_edit && (head != tail)) {
- /* XXX: for now, we are similar enough that this works... */
- calc_distanceCurveVerts(head, tail - 1);
- }
+ }
+ /* if not multiedit out of loop */
+ if (!is_multiedit) {
+ break;
}
}
}
}
}
+static int countAndCleanTransDataContainer(TransInfo *t)
+{
+ BLI_assert(ELEM(t->data_len_all, 0, -1));
+ t->data_len_all = 0;
+ uint data_container_len_orig = t->data_container_len;
+ for (TransDataContainer *th_end = t->data_container - 1, *tc = t->data_container + (t->data_container_len - 1); tc != th_end; tc--) {
+ if (tc->data_len == 0) {
+ uint index = tc - t->data_container;
+ if (index + 1 != t->data_container_len) {
+ SWAP(TransDataContainer, t->data_container[index], t->data_container[t->data_container_len - 1]);
+ }
+ t->data_container_len -= 1;
+ }
+ else {
+ t->data_len_all += tc->data_len;
+ }
+ }
+ if (data_container_len_orig != t->data_container_len) {
+ t->data_container = MEM_reallocN(t->data_container, sizeof(*t->data_container) * t->data_container_len);
+ }
+ return t->data_len_all;
+}
+
void createTransData(bContext *C, TransInfo *t)
{
- Main *bmain = CTX_data_main(C);
Scene *scene = t->scene;
- Object *ob = OBACT;
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
+
+ t->data_len_all = -1;
/* if tests must match recalcData for correct updates */
- if (t->options & CTX_TEXTURE) {
+ if (t->options & CTX_CURSOR) {
+ t->flag |= T_CURSOR;
+ t->obedit_type = -1;
+
+ if (t->spacetype == SPACE_IMAGE) {
+ createTransCursor_image(t);
+ }
+ else {
+ createTransCursor_view3d(t);
+ }
+ countAndCleanTransDataContainer(t);
+ }
+ else if (t->options & CTX_TEXTURE) {
t->flag |= T_TEXTURE;
+ t->obedit_type = -1;
+
createTransTexspace(t);
+ countAndCleanTransDataContainer(t);
}
else if (t->options & CTX_EDGE) {
- t->ext = NULL;
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->data_ext = NULL;
+ }
t->flag |= T_EDIT;
+
createTransEdge(t);
- if (t->data && t->flag & T_PROP_EDIT) {
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8172,9 +8509,11 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->options & CTX_GPENCIL_STROKES) {
t->options |= CTX_GPENCIL_STROKES;
t->flag |= T_POINTS;
+
createTransGPencil(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8183,22 +8522,32 @@ void createTransData(bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_IMAGE) {
t->flag |= T_POINTS | T_2D_EDIT;
if (t->options & CTX_MASK) {
+
/* copied from below */
createTransMaskingData(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, true);
sort_trans_data_dist(t);
}
}
else if (t->options & CTX_PAINT_CURVE) {
- if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN))
+ if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
createTransPaintCurveVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ }
}
- else if (t->obedit) {
+ else if (t->obedit_type == OB_MESH) {
+
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
createTransUVs(C, t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ countAndCleanTransDataContainer(t);
+
+ t->flag |= T_EDIT;
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8207,9 +8556,12 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_ACTION) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
createTransActionData(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
//set_prop_dist(t, false); /* don't do that, distance has been set in createTransActionData already */
sort_trans_data_dist(t);
@@ -8217,18 +8569,27 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
createTransNlaData(C, t);
+ countAndCleanTransDataContainer(t);
}
else if (t->spacetype == SPACE_SEQ) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point transformations */
createTransSeqData(C, t);
+ countAndCleanTransDataContainer(t);
}
else if (t->spacetype == SPACE_IPO) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
createTransGraphEditData(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, false); /* don't do that, distance has been set in createTransGraphEditData already */
sort_trans_data_dist(t);
@@ -8236,8 +8597,12 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_NODE) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
createTransNodeData(C, t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ countAndCleanTransDataContainer(t);
+
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8245,34 +8610,44 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_CLIP) {
t->flag |= T_POINTS | T_2D_EDIT;
- if (t->options & CTX_MOVIECLIP)
+ t->obedit_type = -1;
+
+ if (t->options & CTX_MOVIECLIP) {
createTransTrackingData(C, t);
+ countAndCleanTransDataContainer(t);
+ }
else if (t->options & CTX_MASK) {
/* copied from above */
createTransMaskingData(C, t);
+ countAndCleanTransDataContainer(t);
- if (t->data && (t->flag & T_PROP_EDIT)) {
+ if (t->data_len_all && (t->flag & T_PROP_EDIT)) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, true);
sort_trans_data_dist(t);
}
}
}
- else if (t->obedit) {
- t->ext = NULL;
- if (t->obedit->type == OB_MESH) {
+ else if (t->obedit_type != -1) {
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->data_ext = NULL;
+ }
+ if (t->obedit_type == OB_MESH) {
createTransEditVerts(t);
}
- else if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
+ else if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
createTransCurveVerts(t);
}
- else if (t->obedit->type == OB_LATTICE) {
+ else if (t->obedit_type == OB_LATTICE) {
createTransLatticeVerts(t);
}
- else if (t->obedit->type == OB_MBALL) {
+ else if (t->obedit_type == OB_MBALL) {
createTransMBallVerts(t);
}
- else if (t->obedit->type == OB_ARMATURE) {
+ else if (t->obedit_type == OB_ARMATURE) {
t->flag &= ~T_PROP_EDIT;
createTransArmatureVerts(t);
}
@@ -8280,12 +8655,14 @@ void createTransData(bContext *C, TransInfo *t)
printf("edit type not implemented!\n");
}
+ countAndCleanTransDataContainer(t);
+
t->flag |= T_EDIT | T_POINTS;
- if (t->data && t->flag & T_PROP_EDIT) {
- if (ELEM(t->obedit->type, OB_CURVE, OB_MESH)) {
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
+ if (ELEM(t->obedit_type, OB_CURVE, OB_MESH)) {
sort_trans_data(t); // makes selected become first in array
- if ((t->obedit->type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
+ if ((t->obedit_type == OB_MESH) && (t->flag & T_PROP_CONNECTED)) {
/* already calculated by editmesh_set_connectivity_distance */
}
else {
@@ -8304,34 +8681,52 @@ void createTransData(bContext *C, TransInfo *t)
if (t->mode == TFM_BONESIZE) {
t->flag &= ~(T_EDIT | T_POINTS);
t->flag |= T_POSE;
- t->poseobj = ob; /* <- tsk tsk, this is going to give issues one day */
+ t->obedit_type = -1;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ tc->poseobj = tc->obedit;
+ tc->obedit = NULL;
+ }
}
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
// XXX this is currently limited to active armature only...
// XXX active-layer checking isn't done as that should probably be checked through context instead
- createTransPose(t, ob);
+
+ /* Multi object editing. */
+ initTransDataContainers_FromObjectData(t, ob, NULL, 0);
+ createTransPose(t);
+ countAndCleanTransDataContainer(t);
}
else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
/* important that ob_armature can be set even when its not selected [#23412]
* lines below just check is also visible */
Object *ob_armature = modifiers_isDeformedByArmature(ob);
if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
- Base *base_arm = BKE_scene_base_find(t->scene, ob_armature);
+ Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
if (base_arm) {
View3D *v3d = t->view;
if (BASE_VISIBLE(v3d, base_arm)) {
- createTransPose(t, ob_armature);
+ Object *objects[1];
+ objects[0] = ob_armature;
+ uint objects_len = 1;
+ initTransDataContainers_FromObjectData(t, ob_armature, objects, objects_len);
+ createTransPose(t);
+ countAndCleanTransDataContainer(t);
}
}
-
+ }
+ /* Mark as initialized if above checks fail. */
+ if (t->data_len_all == -1) {
+ t->data_len_all = 0;
}
}
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(bmain, scene, ob))) {
+ else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
createTransParticleVerts(C, t);
+ countAndCleanTransDataContainer(t);
t->flag |= T_POINTS;
- if (t->data && t->flag & T_PROP_EDIT) {
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
sort_trans_data(t); // makes selected become first in array
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8341,13 +8736,19 @@ void createTransData(bContext *C, TransInfo *t)
if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
t->flag |= T_POINTS | T_2D_EDIT;
createTransPaintCurveVerts(C, t);
+ countAndCleanTransDataContainer(t);
+ }
+ /* Mark as initialized if above checks fail. */
+ if (t->data_len_all == -1) {
+ t->data_len_all = 0;
}
}
else {
createTransObject(C, t);
+ countAndCleanTransDataContainer(t);
t->flag |= T_OBJECT;
- if (t->data && t->flag & T_PROP_EDIT) {
+ if (t->data_len_all && t->flag & T_PROP_EDIT) {
// selected objects are already first, no need to presort
set_prop_dist(t, 1);
sort_trans_data_dist(t);
@@ -8359,10 +8760,15 @@ void createTransData(bContext *C, TransInfo *t)
RegionView3D *rv3d = t->ar->regiondata;
if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
/* we could have a flag to easily check an object is being transformed */
- if (v3d->camera->recalc) {
+ if (v3d->camera->id.tag & LIB_TAG_DOIT) {
t->flag |= T_CAMERA;
}
}
}
}
+
+ /* Check that 'countAndCleanTransDataContainer' ran. */
+ BLI_assert(t->data_len_all != -1);
+
+ BLI_assert((!(t->flag & T_EDIT)) == (!(t->obedit_type != -1)));
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 5e24a3d9e47..f27df3bba25 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -58,31 +58,37 @@
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+#include "PIL_time.h"
+
#include "BLT_translation.h"
#include "RNA_access.h"
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "BIK_api.h"
-#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
+#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
-#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_nla.h"
-#include "BKE_context.h"
#include "BKE_paint.h"
+#include "BKE_scene.h"
#include "BKE_sequencer.h"
-#include "BKE_editmesh.h"
#include "BKE_tracking.h"
-#include "BKE_mask.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@@ -99,10 +105,13 @@
#include "ED_curve.h" /* for curve_editnurbs */
#include "ED_clip.h"
#include "ED_screen.h"
+#include "ED_gpencil.h"
#include "WM_types.h"
#include "WM_api.h"
+#include "RE_engine.h"
+
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -124,98 +133,101 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3])
/* ************************** GENERICS **************************** */
-static void clipMirrorModifier(TransInfo *t, Object *ob)
+static void clipMirrorModifier(TransInfo *t)
{
- ModifierData *md = ob->modifiers.first;
- float tolerance[3] = {0.0f, 0.0f, 0.0f};
- int axis = 0;
-
- for (; md; md = md->next) {
- if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData *) md;
-
- if (mmd->flag & MOD_MIR_CLIPPING) {
- axis = 0;
- if (mmd->flag & MOD_MIR_AXIS_X) {
- axis |= 1;
- tolerance[0] = mmd->tolerance;
- }
- if (mmd->flag & MOD_MIR_AXIS_Y) {
- axis |= 2;
- tolerance[1] = mmd->tolerance;
- }
- if (mmd->flag & MOD_MIR_AXIS_Z) {
- axis |= 4;
- tolerance[2] = mmd->tolerance;
- }
- if (axis) {
- float mtx[4][4], imtx[4][4];
- int i;
- TransData *td = t->data;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->obedit;
+ ModifierData *md = ob->modifiers.first;
+ float tolerance[3] = {0.0f, 0.0f, 0.0f};
+ int axis = 0;
+
+ for (; md; md = md->next) {
+ if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
+ MirrorModifierData *mmd = (MirrorModifierData *) md;
+
+ if (mmd->flag & MOD_MIR_CLIPPING) {
+ axis = 0;
+ if (mmd->flag & MOD_MIR_AXIS_X) {
+ axis |= 1;
+ tolerance[0] = mmd->tolerance;
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Y) {
+ axis |= 2;
+ tolerance[1] = mmd->tolerance;
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Z) {
+ axis |= 4;
+ tolerance[2] = mmd->tolerance;
+ }
+ if (axis) {
+ float mtx[4][4], imtx[4][4];
+ int i;
- if (mmd->mirror_ob) {
- float obinv[4][4];
+ if (mmd->mirror_ob) {
+ float obinv[4][4];
- invert_m4_m4(obinv, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, obinv, ob->obmat);
- invert_m4_m4(imtx, mtx);
- }
+ invert_m4_m4(obinv, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(mtx, obinv, ob->obmat);
+ invert_m4_m4(imtx, mtx);
+ }
- for (i = 0; i < t->total; i++, td++) {
- int clip;
- float loc[3], iloc[3];
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ int clip;
+ float loc[3], iloc[3];
- if (td->flag & TD_NOACTION)
- break;
- if (td->loc == NULL)
- break;
+ if (td->flag & TD_NOACTION)
+ break;
+ if (td->loc == NULL)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- copy_v3_v3(loc, td->loc);
- copy_v3_v3(iloc, td->iloc);
+ copy_v3_v3(loc, td->loc);
+ copy_v3_v3(iloc, td->iloc);
- if (mmd->mirror_ob) {
- mul_m4_v3(mtx, loc);
- mul_m4_v3(mtx, iloc);
- }
+ if (mmd->mirror_ob) {
+ mul_m4_v3(mtx, loc);
+ mul_m4_v3(mtx, iloc);
+ }
- clip = 0;
- if (axis & 1) {
- if (fabsf(iloc[0]) <= tolerance[0] ||
- loc[0] * iloc[0] < 0.0f)
- {
- loc[0] = 0.0f;
- clip = 1;
+ clip = 0;
+ if (axis & 1) {
+ if (fabsf(iloc[0]) <= tolerance[0] ||
+ loc[0] * iloc[0] < 0.0f)
+ {
+ loc[0] = 0.0f;
+ clip = 1;
+ }
}
- }
- if (axis & 2) {
- if (fabsf(iloc[1]) <= tolerance[1] ||
- loc[1] * iloc[1] < 0.0f)
- {
- loc[1] = 0.0f;
- clip = 1;
+ if (axis & 2) {
+ if (fabsf(iloc[1]) <= tolerance[1] ||
+ loc[1] * iloc[1] < 0.0f)
+ {
+ loc[1] = 0.0f;
+ clip = 1;
+ }
}
- }
- if (axis & 4) {
- if (fabsf(iloc[2]) <= tolerance[2] ||
- loc[2] * iloc[2] < 0.0f)
- {
- loc[2] = 0.0f;
- clip = 1;
+ if (axis & 4) {
+ if (fabsf(iloc[2]) <= tolerance[2] ||
+ loc[2] * iloc[2] < 0.0f)
+ {
+ loc[2] = 0.0f;
+ clip = 1;
+ }
}
- }
- if (clip) {
- if (mmd->mirror_ob) {
- mul_m4_v3(imtx, loc);
+ if (clip) {
+ if (mmd->mirror_ob) {
+ mul_m4_v3(imtx, loc);
+ }
+ copy_v3_v3(td->loc, loc);
}
- copy_v3_v3(td->loc, loc);
}
}
- }
+ }
}
}
}
@@ -224,27 +236,29 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
/* assumes obedit set to mesh object */
static void editbmesh_apply_to_mirror(TransInfo *t)
{
- TransData *td = t->data;
- BMVert *eve;
- int i;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ BMVert *eve;
+ int i;
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_NOACTION)
- break;
- if (td->loc == NULL)
- break;
- if (td->flag & TD_SKIP)
- continue;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+ if (td->loc == NULL)
+ break;
+ if (td->flag & TD_SKIP)
+ continue;
- eve = td->extra;
- if (eve) {
- eve->co[0] = -td->loc[0];
- eve->co[1] = td->loc[1];
- eve->co[2] = td->loc[2];
- }
+ eve = td->extra;
+ if (eve) {
+ eve->co[0] = -td->loc[0];
+ eve->co[1] = td->loc[1];
+ eve->co[2] = td->loc[2];
+ }
- if (td->flag & TD_MIRROR_EDGE) {
- td->loc[0] = 0;
+ if (td->flag & TD_MIRROR_EDGE) {
+ td->loc[0] = 0;
+ }
}
}
}
@@ -339,7 +353,7 @@ static bool fcu_test_selected(FCurve *fcu)
/* helper for recalcData() - for Action Editor transforms */
static void recalcData_actedit(TransInfo *t)
{
- Scene *scene = t->scene;
+ ViewLayer *view_layer = t->view_layer;
SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
bAnimContext ac = {NULL};
@@ -351,7 +365,8 @@ static void recalcData_actedit(TransInfo *t)
/* NOTE: sync this with the code in ANIM_animdata_get_context() */
ac.bmain = CTX_data_main(t->context);
ac.scene = t->scene;
- ac.obact = OBACT;
+ ac.view_layer = t->view_layer;
+ ac.obact = OBACT(view_layer);
ac.sa = t->sa;
ac.ar = t->ar;
ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
@@ -365,7 +380,8 @@ static void recalcData_actedit(TransInfo *t)
/* flush transform values back to actual coordinates */
flushTransIntFrameActionData(t);
}
- else {
+
+ if (ac.datatype != ANIMCONT_MASK) {
/* get animdata blocks visible in editor, assuming that these will be the ones where things changed */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -376,7 +392,7 @@ static void recalcData_actedit(TransInfo *t)
if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
for (ale = anim_data.first; ale; ale = ale->next) {
/* set refresh tags for objects using this animation */
- ANIM_list_elem_update(CTX_data_main(t->context), scene, ale);
+ ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
}
}
@@ -388,7 +404,7 @@ static void recalcData_actedit(TransInfo *t)
static void recalcData_graphedit(TransInfo *t)
{
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
- Scene *scene;
+ ViewLayer *view_layer = t->view_layer;
ListBase anim_data = {NULL, NULL};
bAnimContext ac = {NULL};
@@ -400,8 +416,9 @@ static void recalcData_graphedit(TransInfo *t)
/* initialize relevant anim-context 'context' data from TransInfo data */
/* NOTE: sync this with the code in ANIM_animdata_get_context() */
ac.bmain = CTX_data_main(t->context);
- scene = ac.scene = t->scene;
- ac.obact = OBACT;
+ ac.scene = t->scene;
+ ac.view_layer = t->view_layer;
+ ac.obact = OBACT(view_layer);
ac.sa = t->sa;
ac.ar = t->ar;
ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
@@ -448,17 +465,19 @@ static void recalcData_graphedit(TransInfo *t)
/* helper for recalcData() - for NLA Editor transforms */
static void recalcData_nla(TransInfo *t)
{
- TransDataNla *tdn = t->custom.type.data;
SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
Scene *scene = t->scene;
double secf = FPS;
int i;
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ TransDataNla *tdn = tc->custom.type.data;
+
/* for each strip we've got, perform some additional validation of the values that got set before
* using RNA to set the value (which does some special operations when setting these values to make
* sure that everything works ok)
*/
- for (i = 0; i < t->total; i++, tdn++) {
+ for (i = 0; i < tc->data_len; i++, tdn++) {
NlaStrip *strip = tdn->strip;
PointerRNA strip_ptr;
short pExceeded, nExceeded, iter;
@@ -472,7 +491,7 @@ static void recalcData_nla(TransInfo *t)
* BUT only if realtime updates are enabled
*/
if ((snla->flag & SNLA_NOREALTIMEUPDATES) == 0)
- ANIM_id_update(t->scene, tdn->id);
+ ANIM_id_update(CTX_data_main(t->context), tdn->id);
/* if canceling transform, just write the values without validating, then move on */
if (t->state == TRANS_CANCEL) {
@@ -663,7 +682,7 @@ static void recalcData_mask_common(TransInfo *t)
flushTransMasking(t);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
}
/* helper for recalcData() - for Image Editor transforms */
@@ -675,14 +694,18 @@ static void recalcData_image(TransInfo *t)
else if (t->options & CTX_PAINT_CURVE) {
flushTransPaintCurve(t);
}
- else if (t->obedit && t->obedit->type == OB_MESH) {
+ else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
SpaceImage *sima = t->sa->spacedata.first;
flushTransUVs(t);
if (sima->flag & SI_LIVE_UNWRAP)
ED_uvedit_live_unwrap_re_solve();
- DAG_id_tag_update(t->obedit->data, 0);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len) {
+ DEG_id_tag_update(tc->obedit->data, 0);
+ }
+ }
}
}
@@ -725,7 +748,7 @@ static void recalcData_spaceclip(TransInfo *t)
track = track->next;
}
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
}
else if (t->options & CTX_MASK) {
recalcData_mask_common(t);
@@ -735,55 +758,59 @@ static void recalcData_spaceclip(TransInfo *t)
/* helper for recalcData() - for object transforms, typically in the 3D view */
static void recalcData_objects(TransInfo *t)
{
- Main *bmain = CTX_data_main(t->context);
- Base *base = t->scene->basact;
+ Base *base = t->view_layer->basact;
- if (t->obedit) {
- if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
- Curve *cu = t->obedit->data;
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- Nurb *nu = nurbs->first;
+ if (t->obedit_type != -1) {
+ if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
if (t->state != TRANS_CANCEL) {
- clipMirrorModifier(t, t->obedit);
+ clipMirrorModifier(t);
applyProject(t);
}
- DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Curve *cu = tc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ Nurb *nu = nurbs->first;
- if (t->state == TRANS_CANCEL) {
- while (nu) {
- BKE_nurb_handles_calc(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
- nu = nu->next;
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+
+ if (t->state == TRANS_CANCEL) {
+ while (nu) {
+ BKE_nurb_handles_calc(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
+ nu = nu->next;
+ }
}
- }
- else {
- /* Normal updating */
- while (nu) {
- BKE_nurb_test_2d(nu);
- BKE_nurb_handles_calc(nu);
- nu = nu->next;
+ else {
+ /* Normal updating */
+ while (nu) {
+ BKE_nurb_test_2d(nu);
+ BKE_nurb_handles_calc(nu);
+ nu = nu->next;
+ }
}
}
}
- else if (t->obedit->type == OB_LATTICE) {
- Lattice *la = t->obedit->data;
+ else if (t->obedit_type == OB_LATTICE) {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
- DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
-
- if (la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Lattice *la = tc->obedit->data;
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ if (la->editlatt->latt->flag & LT_OUTSIDE) {
+ outside_lattice(la->editlatt->latt);
+ }
+ }
}
- else if (t->obedit->type == OB_MESH) {
- BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ else if (t->obedit_type == OB_MESH) {
/* mirror modifier clipping? */
if (t->state != TRANS_CANCEL) {
/* apply clipping after so we never project past the clip plane [#25423] */
applyProject(t);
- clipMirrorModifier(t, t->obedit);
+ clipMirrorModifier(t);
}
if ((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
editbmesh_apply_to_mirror(t);
@@ -795,178 +822,224 @@ static void recalcData_objects(TransInfo *t)
projectVertSlideData(t, false);
}
- DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
-
- EDBM_mesh_normals_update(em);
- BKE_editmesh_tessface_calc(em);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ EDBM_mesh_normals_update(em);
+ BKE_editmesh_tessface_calc(em);
+ }
}
- else if (t->obedit->type == OB_ARMATURE) { /* no recalc flag, does pose */
- bArmature *arm = t->obedit->data;
- ListBase *edbo = arm->edbo;
- EditBone *ebo, *ebo_parent;
- TransData *td = t->data;
- int i;
+ else if (t->obedit_type == OB_ARMATURE) { /* no recalc flag, does pose */
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
- /* Ensure all bones are correctly adjusted */
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ bArmature *arm = tc->obedit->data;
+ ListBase *edbo = arm->edbo;
+ EditBone *ebo, *ebo_parent;
+ TransData *td = tc->data;
+ int i;
- if (ebo_parent) {
- /* If this bone has a parent tip that has been moved */
- if (ebo_parent->flag & BONE_TIPSEL) {
- copy_v3_v3(ebo->head, ebo_parent->tail);
- if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo_parent->rad_tail;
- }
- /* If this bone has a parent tip that has NOT been moved */
- else {
- copy_v3_v3(ebo_parent->tail, ebo->head);
- if (t->mode == TFM_BONE_ENVELOPE) ebo_parent->rad_tail = ebo->rad_head;
- }
- }
+ /* Ensure all bones are correctly adjusted */
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
- /* on extrude bones, oldlength==0.0f, so we scale radius of points */
- ebo->length = len_v3v3(ebo->head, ebo->tail);
- if (ebo->oldlength == 0.0f) {
- ebo->rad_head = 0.25f * ebo->length;
- ebo->rad_tail = 0.10f * ebo->length;
- ebo->dist = 0.25f * ebo->length;
- if (ebo->parent) {
- if (ebo->rad_head > ebo->parent->rad_tail)
- ebo->rad_head = ebo->parent->rad_tail;
+ if (ebo_parent) {
+ /* If this bone has a parent tip that has been moved */
+ if (ebo_parent->flag & BONE_TIPSEL) {
+ copy_v3_v3(ebo->head, ebo_parent->tail);
+ if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo_parent->rad_tail;
+ }
+ /* If this bone has a parent tip that has NOT been moved */
+ else {
+ copy_v3_v3(ebo_parent->tail, ebo->head);
+ if (t->mode == TFM_BONE_ENVELOPE) ebo_parent->rad_tail = ebo->rad_head;
+ }
}
- }
- else if (t->mode != TFM_BONE_ENVELOPE) {
- /* if bones change length, lets do that for the deform distance as well */
- ebo->dist *= ebo->length / ebo->oldlength;
- ebo->rad_head *= ebo->length / ebo->oldlength;
- ebo->rad_tail *= ebo->length / ebo->oldlength;
- ebo->oldlength = ebo->length;
- if (ebo_parent) {
- ebo_parent->rad_tail = ebo->rad_head;
+ /* on extrude bones, oldlength==0.0f, so we scale radius of points */
+ ebo->length = len_v3v3(ebo->head, ebo->tail);
+ if (ebo->oldlength == 0.0f) {
+ ebo->rad_head = 0.25f * ebo->length;
+ ebo->rad_tail = 0.10f * ebo->length;
+ ebo->dist = 0.25f * ebo->length;
+ if (ebo->parent) {
+ if (ebo->rad_head > ebo->parent->rad_tail)
+ ebo->rad_head = ebo->parent->rad_tail;
+ }
+ }
+ else if (t->mode != TFM_BONE_ENVELOPE) {
+ /* if bones change length, lets do that for the deform distance as well */
+ ebo->dist *= ebo->length / ebo->oldlength;
+ ebo->rad_head *= ebo->length / ebo->oldlength;
+ ebo->rad_tail *= ebo->length / ebo->oldlength;
+ ebo->oldlength = ebo->length;
+
+ if (ebo_parent) {
+ ebo_parent->rad_tail = ebo->rad_head;
+ }
}
}
- }
- if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
- /* fix roll */
- for (i = 0; i < t->total; i++, td++) {
- if (td->extra) {
- float vec[3], up_axis[3];
- float qrot[4];
- float roll;
+ if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
+ /* fix roll */
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->extra) {
+ float vec[3], up_axis[3];
+ float qrot[4];
+ float roll;
- ebo = td->extra;
+ ebo = td->extra;
- if (t->state == TRANS_CANCEL) {
- /* restore roll */
- ebo->roll = td->ival;
- }
- else {
- copy_v3_v3(up_axis, td->axismtx[2]);
+ if (t->state == TRANS_CANCEL) {
+ /* restore roll */
+ ebo->roll = td->ival;
+ }
+ else {
+ copy_v3_v3(up_axis, td->axismtx[2]);
- sub_v3_v3v3(vec, ebo->tail, ebo->head);
- normalize_v3(vec);
- rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
- mul_qt_v3(qrot, up_axis);
+ sub_v3_v3v3(vec, ebo->tail, ebo->head);
+ normalize_v3(vec);
+ rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
+ mul_qt_v3(qrot, up_axis);
- /* roll has a tendency to flip in certain orientations - [#34283], [#33974] */
- roll = ED_armature_ebone_roll_to_vector(ebo, up_axis, false);
- ebo->roll = angle_compat_rad(roll, td->ival);
+ /* roll has a tendency to flip in certain orientations - [#34283], [#33974] */
+ roll = ED_armature_ebone_roll_to_vector(ebo, up_axis, false);
+ ebo->roll = angle_compat_rad(roll, td->ival);
+ }
}
}
}
- }
- if (arm->flag & ARM_MIRROR_EDIT) {
- if (t->state != TRANS_CANCEL)
- ED_armature_edit_transform_mirror_update(t->obedit);
- else
- restoreBones(t);
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ if (t->state != TRANS_CANCEL) {
+ ED_armature_edit_transform_mirror_update(tc->obedit);
+ }
+ else {
+ restoreBones(tc);
+ }
+ }
}
}
else {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
- DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->data_len) {
+ DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
+ }
+ }
}
+
}
- else if ((t->flag & T_POSE) && t->poseobj) {
- Object *ob = t->poseobj;
- bArmature *arm = ob->data;
+ else if (t->flag & T_POSE) {
+ GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
- /* if animtimer is running, and the object already has animation data,
- * check if the auto-record feature means that we should record 'samples'
- * (i.e. uneditable animation values)
- *
- * context is needed for keying set poll() functions.
- */
- // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
- if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
- int targetless_ik = (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ Object *ob = tc->poseobj;
+ bArmature *arm = ob->data;
+
+ /* if animtimer is running, and the object already has animation data,
+ * check if the auto-record feature means that we should record 'samples'
+ * (i.e. uneditable animation values)
+ *
+ * context is needed for keying set poll() functions.
+ */
+ // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
+ if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
+ int targetless_ik = (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
+
+ animrecord_check_state(t->scene, &ob->id, t->animtimer);
+ autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
+ }
- animrecord_check_state(t->scene, &ob->id, t->animtimer);
- autokeyframe_pose_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
+ if (motionpath_need_update_pose(t->scene, ob)) {
+ BLI_gset_insert(motionpath_updates, ob);
+ }
+
+ /* old optimize trick... this enforces to bypass the depgraph */
+ if (!(arm->flag & ARM_DELAYDEFORM)) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
+ /* transformation of pose may affect IK tree, make sure it is rebuilt */
+ BIK_clear_data(ob->pose);
+ }
+ else {
+ BKE_pose_where_is(t->depsgraph, t->scene, ob);
+ }
}
- /* old optimize trick... this enforces to bypass the depgraph */
- if (!(arm->flag & ARM_DELAYDEFORM)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
- /* transformation of pose may affect IK tree, make sure it is rebuilt */
- BIK_clear_data(ob->pose);
+ /* Update motion paths once for all transformed bones in an object. */
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, motionpath_updates) {
+ Object *ob = BLI_gsetIterator_getKey(&gs_iter);
+ ED_pose_recalculate_paths(t->context, t->scene, ob, true);
}
- else
- BKE_pose_where_is(t->scene, ob);
+ BLI_gset_free(motionpath_updates, NULL);
}
- else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(bmain, t->scene, base->object)) {
+ else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
+ PE_get_current(t->scene, base->object))
+ {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
flushTransParticles(t);
}
else {
- int i;
+ bool motionpath_update = false;
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
- for (i = 0; i < t->total; i++) {
- TransData *td = t->data + i;
- Object *ob = td->ob;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
- if (td->flag & TD_NOACTION)
- break;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ Object *ob = td->ob;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_NOACTION)
+ break;
- /* if animtimer is running, and the object already has animation data,
- * check if the auto-record feature means that we should record 'samples'
- * (i.e. uneditable animation values)
- */
- // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
- if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
- animrecord_check_state(t->scene, &ob->id, t->animtimer);
- autokeyframe_ob_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode);
- }
+ if (td->flag & TD_SKIP)
+ continue;
- /* sets recalc flags fully, instead of flushing existing ones
- * otherwise proxies don't function correctly
- */
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ /* if animtimer is running, and the object already has animation data,
+ * check if the auto-record feature means that we should record 'samples'
+ * (i.e. uneditable animation values)
+ */
+ // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
+ if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
+ animrecord_check_state(t->scene, &ob->id, t->animtimer);
+ autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
+ }
+
+ motionpath_update |= motionpath_need_update_object(t->scene, ob);
- if (t->flag & T_TEXTURE)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* sets recalc flags fully, instead of flushing existing ones
+ * otherwise proxies don't function correctly
+ */
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
+
+ if (t->flag & T_TEXTURE)
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ }
+
+ if (motionpath_update) {
+ /* Update motion paths once for all transformed objects. */
+ ED_objects_recalculate_paths(t->context, t->scene, true);
}
}
}
+static void recalcData_cursor(TransInfo *t)
+{
+ DEG_id_tag_update(&t->scene->id, DEG_TAG_COPY_ON_WRITE);
+}
+
/* helper for recalcData() - for sequencer transforms */
static void recalcData_sequencer(TransInfo *t)
{
@@ -974,7 +1047,9 @@ static void recalcData_sequencer(TransInfo *t)
int a;
Sequence *seq_prev = NULL;
- for (a = 0, td = t->data; a < t->total; a++, td++) {
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
TransDataSeq *tdsq = (TransDataSeq *) td->extra;
Sequence *seq = tdsq->seq;
@@ -999,8 +1074,10 @@ static void recalcData_sequencer(TransInfo *t)
/* force recalculation of triangles during transformation */
static void recalcData_gpencil_strokes(TransInfo *t)
{
- TransData *td = t->data;
- for (int i = 0; i < t->total; i++, td++) {
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
bGPDstroke *gps = td->extra;
if (gps != NULL) {
gps->flag |= GP_STROKE_RECALC_CACHES;
@@ -1012,7 +1089,10 @@ static void recalcData_gpencil_strokes(TransInfo *t)
void recalcData(TransInfo *t)
{
/* if tests must match createTransData for correct updates */
- if (t->options & CTX_TEXTURE) {
+ if (t->options & CTX_CURSOR) {
+ recalcData_cursor(t);
+ }
+ else if (t->options & CTX_TEXTURE) {
recalcData_objects(t);
}
else if (t->options & CTX_EDGE) {
@@ -1059,10 +1139,7 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = t->view;
- glPushMatrix();
-
- //if (t->obedit) glLoadMatrixf(t->obedit->obmat); // sets opengl viewing
-
+ GPU_matrix_push();
copy_v3_v3(v3, dir);
mul_v3_fl(v3, v3d->far);
@@ -1077,15 +1154,20 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
UI_GetThemeColor3ubv(TH_GRID, col);
}
UI_make_axis_color(col, col2, axis);
- glColor3ubv(col2);
- setlinestyle(0);
- glBegin(GL_LINES);
- glVertex3fv(v1);
- glVertex3fv(v2);
- glEnd();
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor3ubv(col2);
- glPopMatrix();
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
}
}
@@ -1094,12 +1176,7 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
*/
void resetTransModal(TransInfo *t)
{
- if (t->mode == TFM_EDGE_SLIDE) {
- freeEdgeSlideVerts(t, &t->custom.mode);
- }
- else if (t->mode == TFM_VERT_SLIDE) {
- freeVertSlideVerts(t, &t->custom.mode);
- }
+ freeTransCustomDataForMode(t);
}
void resetTransRestrictions(TransInfo *t)
@@ -1121,6 +1198,64 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
}
}
+void initTransDataContainers_FromObjectData(TransInfo *t, Object *obact, Object **objects, uint objects_len)
+{
+ const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
+ const short object_type = obact ? obact->type : -1;
+
+ if ((object_mode & OB_MODE_EDIT) ||
+ ((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE)))
+ {
+ if (t->data_container) {
+ MEM_freeN(t->data_container);
+ }
+
+ bool free_objects = false;
+ if (objects == NULL) {
+ objects = BKE_view_layer_array_from_objects_in_mode(
+ t->view_layer,
+ (t->spacetype == SPACE_VIEW3D) ? t->view : NULL,
+ &objects_len, {
+ .object_mode = object_mode,
+ .no_dup_data = true,
+ });
+ free_objects = true;
+ }
+
+ t->data_container = MEM_callocN(sizeof(*t->data_container) * objects_len, __func__);
+ t->data_container_len = objects_len;
+
+ for (int i = 0; i < objects_len; i++) {
+ TransDataContainer *tc = &t->data_container[i];
+ if (object_mode & OB_MODE_EDIT) {
+ tc->obedit = objects[i];
+ /* Check needed for UV's */
+ if ((t->flag & T_2D_EDIT) == 0) {
+ tc->use_local_mat = true;
+ }
+ }
+ else if (object_mode & OB_MODE_POSE) {
+ tc->poseobj = objects[i];
+ tc->use_local_mat = true;
+ }
+
+ if (tc->use_local_mat) {
+ BLI_assert((t->flag & T_2D_EDIT) == 0);
+ copy_m4_m4(tc->mat, objects[i]->obmat);
+ copy_m3_m4(tc->mat3, tc->mat);
+ invert_m4_m4(tc->imat, tc->mat);
+ invert_m3_m3(tc->imat3, tc->mat3);
+ normalize_m3_m3(tc->mat3_unit, tc->mat3);
+ }
+ /* Otherwise leave as zero. */
+ }
+
+ if (free_objects) {
+ MEM_freeN(objects);
+ }
+ }
+}
+
/**
* Setup internal data, mouse, vectors
*
@@ -1130,34 +1265,38 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
*/
void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const eObjectMode object_mode = OBACT(view_layer) ? OBACT(view_layer)->mode : OB_MODE_OBJECT;
+ const short object_type = OBACT(view_layer) ? OBACT(view_layer)->type : -1;
ToolSettings *ts = CTX_data_tool_settings(C);
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
- Object *obedit = CTX_data_edit_object(C);
- Object *ob = CTX_data_active_object(C);
+
bGPdata *gpd = CTX_data_gpencil_data(C);
PropertyRNA *prop;
+ t->depsgraph = depsgraph;
t->scene = sce;
+ t->view_layer = view_layer;
t->sa = sa;
t->ar = ar;
- t->obedit = obedit;
t->settings = ts;
t->reports = op ? op->reports : NULL;
- if (obedit) {
- copy_m3_m4(t->obedit_mat, obedit->obmat);
- normalize_m3(t->obedit_mat);
- }
-
- t->data = NULL;
- t->ext = NULL;
-
t->helpline = HLP_NONE;
t->flag = 0;
+ t->obedit_type = (object_mode == OB_MODE_EDIT) ? object_type : -1;
+
+ /* Many kinds of transform only use a single handle. */
+ if (t->data_container == NULL) {
+ t->data_container = MEM_callocN(sizeof(*t->data_container), __func__);
+ t->data_container_len = 1;
+ }
+
t->redraw = TREDRAW_HARD; /* redraw first time */
if (event) {
@@ -1178,12 +1317,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->transform = NULL;
t->handleEvent = NULL;
- t->total = 0;
+ t->data_len_all = 0;
t->val = 0.0f;
zero_v3(t->vec);
- zero_v3(t->center);
zero_v3(t->center_global);
unit_m3(t->mat);
@@ -1207,7 +1345,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* GPencil editing context */
- if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ if (GPENCIL_EDIT_MODE(gpd)) {
t->options |= CTX_GPENCIL_STROKES;
}
@@ -1232,9 +1370,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
prop_id = "use_even_offset";
}
- if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id)) &&
- RNA_property_is_set(op->ptr, prop))
- {
+ if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
SET_FLAG_FROM_TEST(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM);
}
}
@@ -1246,35 +1382,50 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->view = v3d;
t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
- /* turn manipulator off during transform */
- // FIXME: but don't do this when USING the manipulator...
+ /* turn gizmo off during transform */
if (t->flag & T_MODAL) {
- t->twtype = v3d->twtype;
- v3d->twtype = 0;
+ t->gizmo_flag = v3d->gizmo_flag;
+ v3d->gizmo_flag = V3D_GIZMO_HIDE;
}
- if (v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
- t->around = v3d->around;
+ if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) {
+ t->flag |= T_V3D_ALIGN;
+ }
+ t->around = t->scene->toolsettings->transform_pivot_point;
/* bend always uses the cursor */
if (t->mode == TFM_BEND) {
t->around = V3D_AROUND_CURSOR;
}
- t->current_orientation = v3d->twmode;
+ t->orientation.user = t->scene->orientation_type;
+ t->orientation.custom = BKE_scene_transform_orientation_find(
+ t->scene, t->scene->orientation_index_custom);
+
+ t->orientation.index = 0;
+ ARRAY_SET_ITEMS(
+ t->orientation.types,
+ NULL,
+ &t->orientation.user);
+
+ /* Make second orientation local if both are global. */
+ if (t->orientation.user == V3D_MANIP_GLOBAL) {
+ t->orientation.user_alt = V3D_MANIP_LOCAL;
+ t->orientation.types[1] = &t->orientation.user_alt;
+ }
/* exceptional case */
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
const bool use_island = transdata_check_local_islands(t, t->around);
- if (obedit && !use_island) {
+ if ((t->obedit_type != -1) && !use_island) {
t->options |= CTX_NO_PET;
}
}
}
- if (ob && ob->mode & OB_MODE_ALL_PAINT) {
+ if (object_mode & OB_MODE_ALL_PAINT) {
Paint *p = BKE_paint_get_active_from_context(C);
if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
t->options |= CTX_PAINT_CURVE;
@@ -1303,7 +1454,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->view = &ar->v2d;
t->around = sima->around;
- if (ED_space_image_show_uvedit(sima, t->obedit)) {
+ if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) {
/* UV transform */
}
else if (sima->mode == SI_MODE_MASK) {
@@ -1349,14 +1500,32 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CENTER_BOUNDS;
}
- if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_matrix")) &&
RNA_property_is_set(op->ptr, prop)))
{
- t->current_orientation = RNA_property_enum_get(op->ptr, prop);
+ RNA_property_float_get_array(op->ptr, prop, &t->spacemtx[0][0]);
+ t->orientation.user = V3D_MANIP_CUSTOM_MATRIX;
+ t->orientation.custom = 0;
+ }
+ else if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
+ RNA_property_is_set(op->ptr, prop)))
+ {
+ short orientation = RNA_property_enum_get(op->ptr, prop);
+ TransformOrientation *custom_orientation = NULL;
- if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) {
- t->current_orientation = V3D_MANIP_GLOBAL;
+ if (orientation >= V3D_MANIP_CUSTOM) {
+ if (orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) {
+ orientation = V3D_MANIP_GLOBAL;
+ }
+ else {
+ custom_orientation = BKE_scene_transform_orientation_find(
+ t->scene, orientation - V3D_MANIP_CUSTOM);
+ orientation = V3D_MANIP_CUSTOM;
+ }
}
+
+ t->orientation.user = orientation;
+ t->orientation.custom = custom_orientation;
}
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
@@ -1382,7 +1551,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
// Need stuff to take it from edit mesh or whatnot here
else if (t->spacetype == SPACE_VIEW3D) {
- if (t->obedit && t->obedit->type == OB_MESH && (((Mesh *)t->obedit->data)->editflag & ME_EDIT_MIRROR_X)) {
+ /* TODO(campbell): xform, get mirror from each object. */
+ if (t->obedit_type == OB_MESH && (((Mesh *)OBACT(t->view_layer)->data)->editflag & ME_EDIT_MIRROR_X)) {
t->flag |= T_MIRROR;
t->mirror = 1;
}
@@ -1403,7 +1573,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
else if (t->spacetype == SPACE_ACTION) {
t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
}
- else if (t->obedit) {
+ else if (t->obedit_type != -1) {
t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
}
else if (t->options & CTX_GPENCIL_STROKES) {
@@ -1418,7 +1588,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
}
- else if (t->obedit == NULL && ts->proportional_objects) {
+ else if ((t->obedit_type == -1) && ts->proportional_objects) {
t->flag |= T_PROP_EDIT;
}
}
@@ -1464,8 +1634,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
setTransformViewAspect(t, t->aspect);
if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) {
- RNA_property_float_get_array(op->ptr, prop, t->center);
- mul_v3_v3(t->center, t->aspect);
+ RNA_property_float_get_array(op->ptr, prop, t->center_global);
+ mul_v3_v3(t->center_global, t->aspect);
t->flag |= T_OVERRIDE_CENTER;
}
@@ -1473,11 +1643,47 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initNumInput(&t->num);
}
+
+static void freeTransCustomData(
+ TransInfo *t, TransDataContainer *tc,
+ TransCustomData *custom_data)
+{
+ if (custom_data->free_cb) {
+ /* Can take over freeing t->data and data_2d etc... */
+ custom_data->free_cb(t, tc, custom_data);
+ BLI_assert(custom_data->data == NULL);
+ }
+ else if ((custom_data->data != NULL) && custom_data->use_free) {
+ MEM_freeN(custom_data->data);
+ custom_data->data = NULL;
+ }
+ /* In case modes are switched in the same transform session. */
+ custom_data->free_cb = false;
+ custom_data->use_free = false;
+}
+
+static void freeTransCustomDataContainer(TransInfo *t, TransDataContainer *tc, TransCustomDataContainer *tcdc)
+{
+ TransCustomData *custom_data = &tcdc->first_elem;
+ for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
+ freeTransCustomData(t, tc, custom_data);
+ }
+}
+
+/**
+ * Needed for mode switching.
+ */
+void freeTransCustomDataForMode(TransInfo *t)
+{
+ freeTransCustomData(t, NULL, &t->custom.mode);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ freeTransCustomData(t, tc, &tc->custom.mode);
+ }
+}
+
/* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
void postTrans(bContext *C, TransInfo *t)
{
- TransData *td;
-
if (t->draw_handle_view)
ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view);
if (t->draw_handle_apply)
@@ -1487,46 +1693,41 @@ void postTrans(bContext *C, TransInfo *t)
if (t->draw_handle_cursor)
WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
+ if (t->flag & T_MODAL_CURSOR_SET) {
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ }
+
/* Free all custom-data */
- {
- TransCustomData *custom_data = &t->custom.first_elem;
- for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
- if (custom_data->free_cb) {
- /* Can take over freeing t->data and data2d etc... */
- custom_data->free_cb(t, custom_data);
- BLI_assert(custom_data->data == NULL);
- }
- else if ((custom_data->data != NULL) && custom_data->use_free) {
- MEM_freeN(custom_data->data);
- custom_data->data = NULL;
- }
- }
+ freeTransCustomDataContainer(t, NULL, &t->custom);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ freeTransCustomDataContainer(t, tc, &tc->custom);
}
/* postTrans can be called when nothing is selected, so data is NULL already */
- if (t->data) {
-
- /* free data malloced per trans-data */
- if ((t->obedit && ELEM(t->obedit->type, OB_CURVE, OB_SURF)) ||
- (t->spacetype == SPACE_IPO))
- {
- int a;
- for (a = 0, td = t->data; a < t->total; a++, td++) {
- if (td->flag & TD_BEZTRIPLE) {
- MEM_freeN(td->hdata);
+ if (t->data_len_all != 0) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ /* free data malloced per trans-data */
+ if (ELEM(t->obedit_type, OB_CURVE, OB_SURF) ||
+ (t->spacetype == SPACE_IPO))
+ {
+ TransData *td = tc->data;
+ for (int a = 0; a < tc->data_len; a++, td++) {
+ if (td->flag & TD_BEZTRIPLE) {
+ MEM_freeN(td->hdata);
+ }
}
}
+ MEM_freeN(tc->data);
+
+ MEM_SAFE_FREE(tc->data_ext);
+ MEM_SAFE_FREE(tc->data_2d);
}
- MEM_freeN(t->data);
}
- BLI_freelistN(&t->tsnap.points);
+ MEM_SAFE_FREE(t->data_container);
+ t->data_container = NULL;
- if (t->ext) MEM_freeN(t->ext);
- if (t->data2d) {
- MEM_freeN(t->data2d);
- t->data2d = NULL;
- }
+ BLI_freelistN(&t->tsnap.points);
if (t->spacetype == SPACE_IMAGE) {
if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) {
@@ -1540,9 +1741,9 @@ void postTrans(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = t->sa->spacedata.first;
- /* restore manipulator */
+ /* restore gizmo */
if (t->flag & T_MODAL) {
- v3d->twtype = t->twtype;
+ v3d->gizmo_flag = t->gizmo_flag;
}
}
@@ -1550,14 +1751,20 @@ void postTrans(bContext *C, TransInfo *t)
MEM_freeN(t->mouse.data);
}
+ if (t->rng != NULL) {
+ BLI_rng_free(t->rng);
+ }
+
freeSnapping(t);
}
void applyTransObjects(TransInfo *t)
{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
TransData *td;
- for (td = t->data; td < t->data + t->total; td++) {
+ for (td = tc->data; td < tc->data + tc->data_len; td++) {
copy_v3_v3(td->iloc, td->loc);
if (td->ext->rot) {
copy_v3_v3(td->ext->irot, td->ext->rot);
@@ -1606,25 +1813,29 @@ static void restoreElement(TransData *td)
void restoreTransObjects(TransInfo *t)
{
- TransData *td;
- TransData2D *td2d;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- for (td = t->data; td < t->data + t->total; td++) {
- restoreElement(td);
- }
+ TransData *td;
+ TransData2D *td2d;
- for (td2d = t->data2d; t->data2d && td2d < t->data2d + t->total; td2d++) {
- if (td2d->h1) {
- td2d->h1[0] = td2d->ih1[0];
- td2d->h1[1] = td2d->ih1[1];
+ for (td = tc->data; td < tc->data + tc->data_len; td++) {
+ restoreElement(td);
}
- if (td2d->h2) {
- td2d->h2[0] = td2d->ih2[0];
- td2d->h2[1] = td2d->ih2[1];
+
+ for (td2d = tc->data_2d; tc->data_2d && td2d < tc->data_2d + tc->data_len; td2d++) {
+ if (td2d->h1) {
+ td2d->h1[0] = td2d->ih1[0];
+ td2d->h1[1] = td2d->ih1[1];
+ }
+ if (td2d->h2) {
+ td2d->h2[0] = td2d->ih2[0];
+ td2d->h2[1] = td2d->ih2[1];
+ }
}
- }
- unit_m3(t->mat);
+ unit_m3(t->mat);
+
+ }
recalcData(t);
}
@@ -1632,59 +1843,53 @@ void restoreTransObjects(TransInfo *t)
void calculateCenter2D(TransInfo *t)
{
BLI_assert(!is_zero_v3(t->aspect));
-
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- float vec[3];
-
- copy_v3_v3(vec, t->center);
- mul_m4_v3(ob->obmat, vec);
- projectFloatView(t, vec, t->center2d);
- }
- else {
- projectFloatView(t, t->center, t->center2d);
- }
+ projectFloatView(t, t->center_global, t->center2d);
}
-void calculateCenterGlobal(
- TransInfo *t, const float center_local[3],
- float r_center_global[3])
+void calculateCenterLocal(
+ TransInfo *t, const float center_global[3])
{
/* setting constraint center */
/* note, init functions may over-ride t->center */
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_v3_m4v3(r_center_global, ob->obmat, center_local);
- }
- else {
- copy_v3_v3(r_center_global, center_local);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->use_local_mat) {
+ mul_v3_m4v3(tc->center_local, tc->imat, center_global);
+ }
+ else {
+ copy_v3_v3(tc->center_local, center_global);
+ }
}
}
void calculateCenterCursor(TransInfo *t, float r_center[3])
{
- const float *cursor;
-
- cursor = ED_view3d_cursor3d_get(t->scene, t->view);
+ const float *cursor = t->scene->cursor.location;
copy_v3_v3(r_center, cursor);
/* If edit or pose mode, move cursor in local space */
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- float mat[3][3], imat[3][3];
-
- sub_v3_v3v3(r_center, r_center, ob->obmat[3]);
- copy_m3_m4(mat, ob->obmat);
- invert_m3_m3(imat, mat);
- mul_m3_v3(imat, r_center);
- }
- else if (t->options & CTX_PAINT_CURVE) {
+ if (t->options & CTX_PAINT_CURVE) {
if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
r_center[0] = t->ar->winx / 2.0f;
r_center[1] = t->ar->winy / 2.0f;
}
r_center[2] = 0.0f;
}
+ else if (t->options & CTX_GPENCIL_STROKES) {
+ /* move cursor in local space */
+ TransData *td = NULL;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ float mat[3][3], imat[3][3];
+
+ td = tc->data;
+ Object *ob = td->ob;
+ if (ob) {
+ sub_v3_v3v3(r_center, r_center, ob->obmat[3]);
+ copy_m3_m4(mat, ob->obmat);
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, r_center);
+ }
+ }
+ }
}
void calculateCenterCursor2D(TransInfo *t, float r_center[2])
@@ -1752,13 +1957,21 @@ void calculateCenterMedian(TransInfo *t, float r_center[3])
{
float partial[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
- int i;
- for (i = 0; i < t->total; i++) {
- if (t->data[i].flag & TD_SELECTED) {
- if (!(t->data[i].flag & TD_NOCENTER)) {
- add_v3_v3(partial, t->data[i].center);
- total++;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ for (int i = 0; i < tc->data_len; i++) {
+ if (tc->data[i].flag & TD_SELECTED) {
+ if (!(tc->data[i].flag & TD_NOCENTER)) {
+ if (tc->use_local_mat) {
+ float v[3];
+ mul_v3_m4v3(v, tc->mat, tc->data[i].center);
+ add_v3_v3(partial, v);
+ }
+ else {
+ add_v3_v3(partial, tc->data[i].center);
+ }
+ total++;
+ }
}
}
}
@@ -1770,22 +1983,29 @@ void calculateCenterMedian(TransInfo *t, float r_center[3])
void calculateCenterBound(TransInfo *t, float r_center[3])
{
- float max[3];
- float min[3];
- int i;
- for (i = 0; i < t->total; i++) {
- if (i) {
- if (t->data[i].flag & TD_SELECTED) {
- if (!(t->data[i].flag & TD_NOCENTER))
- minmax_v3v3_v3(min, max, t->data[i].center);
+ float max[3], min[3];
+ bool changed = false;
+ INIT_MINMAX(min, max);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ for (int i = 0; i < tc->data_len; i++) {
+ if (tc->data[i].flag & TD_SELECTED) {
+ if (!(tc->data[i].flag & TD_NOCENTER)) {
+ if (tc->use_local_mat) {
+ float v[3];
+ mul_v3_m4v3(v, tc->mat, tc->data[i].center);
+ minmax_v3v3_v3(min, max, v);
+ }
+ else {
+ minmax_v3v3_v3(min, max, tc->data[i].center);
+ }
+ changed = true;
+ }
}
}
- else {
- copy_v3_v3(max, t->data[i].center);
- copy_v3_v3(min, t->data[i].center);
- }
}
- mid_v3_v3v3(r_center, min, max);
+ if (changed) {
+ mid_v3_v3v3(r_center, min, max);
+ }
}
/**
@@ -1793,26 +2013,30 @@ void calculateCenterBound(TransInfo *t, float r_center[3])
*/
bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
{
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
+
bool ok = false;
- if (t->obedit) {
- if (ED_object_editmode_calc_active_center(t->obedit, select_only, r_center)) {
+ if (tc->obedit) {
+ if (ED_object_editmode_calc_active_center(tc->obedit, select_only, r_center)) {
+ mul_m4_v3(tc->obedit->obmat, r_center);
ok = true;
}
}
else if (t->flag & T_POSE) {
- Scene *scene = t->scene;
- Object *ob = OBACT;
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
if (ob) {
bPoseChannel *pchan = BKE_pose_channel_active(ob);
if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
copy_v3_v3(r_center, pchan->pose_head);
+ mul_m4_v3(ob->obmat, r_center);
ok = true;
}
}
}
else if (t->options & CTX_PAINT_CURVE) {
- Paint *p = BKE_paint_get_active(t->scene);
+ Paint *p = BKE_paint_get_active(t->scene, t->view_layer);
Brush *br = p->brush;
PaintCurve *pc = br->paint_curve;
copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]);
@@ -1821,9 +2045,10 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
}
else {
/* object mode */
- Scene *scene = t->scene;
- Object *ob = OBACT;
- if (ob && (!select_only || (ob->flag & SELECT))) {
+ ViewLayer *view_layer = t->view_layer;
+ Object *ob = OBACT(view_layer);
+ Base *base = BASACT(view_layer);
+ if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) {
copy_v3_v3(r_center, ob->obmat[3]);
ok = true;
}
@@ -1870,14 +2095,13 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
void calculateCenter(TransInfo *t)
{
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
- calculateCenter_FromAround(t, t->around, t->center);
+ calculateCenter_FromAround(t, t->around, t->center_global);
}
- calculateCenterGlobal(t, t->center, t->center_global);
+ calculateCenterLocal(t, t->center_global);
/* avoid calculating again */
{
TransCenterData *cd = &t->center_cache[t->around];
- copy_v3_v3(cd->local, t->center);
copy_v3_v3(cd->global, t->center_global);
cd->is_set = true;
}
@@ -1895,16 +2119,15 @@ void calculateCenter(TransInfo *t)
normalize_v3(axis);
/* 6.0 = 6 grid units */
- axis[0] = t->center[0] - 6.0f * axis[0];
- axis[1] = t->center[1] - 6.0f * axis[1];
- axis[2] = t->center[2] - 6.0f * axis[2];
+ axis[0] = t->center_global[0] - 6.0f * axis[0];
+ axis[1] = t->center_global[1] - 6.0f * axis[1];
+ axis[2] = t->center_global[2] - 6.0f * axis[2];
projectFloatView(t, axis, t->center2d);
/* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
if (t->mode == TFM_TRANSLATION) {
- copy_v3_v3(t->center, axis);
- copy_v3_v3(t->center_global, t->center);
+ copy_v3_v3(t->center_global, axis);
}
}
}
@@ -1938,8 +2161,7 @@ const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
BLI_assert(around <= V3D_AROUND_ACTIVE);
TransCenterData *cd = &t->center_cache[around];
if (cd->is_set == false) {
- calculateCenter_FromAround(t, around, cd->local);
- calculateCenterGlobal(t, cd->local, cd->global);
+ calculateCenter_FromAround(t, around, cd->global);
cd->is_set = true;
}
return cd;
@@ -1947,7 +2169,6 @@ const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
void calculatePropRatio(TransInfo *t)
{
- TransData *td = t->data;
int i;
float dist;
const bool connected = (t->flag & T_PROP_CONNECTED) != 0;
@@ -1956,75 +2177,84 @@ void calculatePropRatio(TransInfo *t)
if (t->flag & T_PROP_EDIT) {
const char *pet_id = NULL;
- for (i = 0; i < t->total; i++, td++) {
- if (td->flag & TD_SELECTED) {
- td->factor = 1.0f;
- }
- else if (t->flag & T_MIRROR && td->loc[0] * t->mirror < -0.00001f) {
- td->flag |= TD_SKIP;
- td->factor = 0.0f;
- restoreElement(td);
- }
- else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
- (connected == 0 && td->rdist > t->prop_size))
- {
- /*
- * The elements are sorted according to their dist member in the array,
- * that means we can stop when it finds one element outside of the propsize.
- * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed.
- */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_SELECTED) {
+ td->factor = 1.0f;
+ }
+ else if (t->flag & T_MIRROR && td->loc[0] * t->mirror < -0.00001f) {
+ td->flag |= TD_SKIP;
+ td->factor = 0.0f;
+ restoreElement(td);
+ }
+ else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
+ (connected == 0 && td->rdist > t->prop_size))
+ {
+ /*
+ * The elements are sorted according to their dist member in the array,
+ * that means we can stop when it finds one element outside of the propsize.
+ * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed.
+ */
- td->factor = 0.0f;
- restoreElement(td);
- }
- else {
- /* Use rdist for falloff calculations, it is the real distance */
- td->flag &= ~TD_NOACTION;
-
- if (connected)
- dist = (t->prop_size - td->dist) / t->prop_size;
- else
- dist = (t->prop_size - td->rdist) / t->prop_size;
-
- /*
- * Clamp to positive numbers.
- * Certain corner cases with connectivity and individual centers
- * can give values of rdist larger than propsize.
- */
- if (dist < 0.0f)
- dist = 0.0f;
+ td->factor = 0.0f;
+ restoreElement(td);
+ }
+ else {
+ /* Use rdist for falloff calculations, it is the real distance */
+ td->flag &= ~TD_NOACTION;
+
+ if (connected)
+ dist = (t->prop_size - td->dist) / t->prop_size;
+ else
+ dist = (t->prop_size - td->rdist) / t->prop_size;
+
+ /*
+ * Clamp to positive numbers.
+ * Certain corner cases with connectivity and individual centers
+ * can give values of rdist larger than propsize.
+ */
+ if (dist < 0.0f)
+ dist = 0.0f;
- switch (t->prop_mode) {
- case PROP_SHARP:
- td->factor = dist * dist;
- break;
- case PROP_SMOOTH:
- td->factor = 3.0f * dist * dist - 2.0f * dist * dist * dist;
- break;
- case PROP_ROOT:
- td->factor = sqrtf(dist);
- break;
- case PROP_LIN:
- td->factor = dist;
- break;
- case PROP_CONST:
- td->factor = 1.0f;
- break;
- case PROP_SPHERE:
- td->factor = sqrtf(2 * dist - dist * dist);
- break;
- case PROP_RANDOM:
- td->factor = BLI_frand() * dist;
- break;
- case PROP_INVSQUARE:
- td->factor = dist * (2.0f - dist);
- break;
- default:
- td->factor = 1;
- break;
+ switch (t->prop_mode) {
+ case PROP_SHARP:
+ td->factor = dist * dist;
+ break;
+ case PROP_SMOOTH:
+ td->factor = 3.0f * dist * dist - 2.0f * dist * dist * dist;
+ break;
+ case PROP_ROOT:
+ td->factor = sqrtf(dist);
+ break;
+ case PROP_LIN:
+ td->factor = dist;
+ break;
+ case PROP_CONST:
+ td->factor = 1.0f;
+ break;
+ case PROP_SPHERE:
+ td->factor = sqrtf(2 * dist - dist * dist);
+ break;
+ case PROP_RANDOM:
+ if (t->rng == NULL) {
+ /* Lazy initialization. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ t->rng = BLI_rng_new(rng_seed);
+ }
+ td->factor = BLI_rng_get_float(t->rng) * dist;
+ break;
+ case PROP_INVSQUARE:
+ td->factor = dist * (2.0f - dist);
+ break;
+ default:
+ td->factor = 1;
+ break;
+ }
}
}
}
+
switch (t->prop_mode) {
case PROP_SHARP:
pet_id = N_("(Sharp)");
@@ -2059,8 +2289,11 @@ void calculatePropRatio(TransInfo *t)
}
}
else {
- for (i = 0; i < t->total; i++, td++) {
- td->factor = 1.0;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ td->factor = 1.0;
+ }
}
}
}
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
new file mode 100644
index 00000000000..7d0584e3571
--- /dev/null
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -0,0 +1,394 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/transform/transform_gizmo_2d.c
+ * \ingroup edtransform
+ *
+ * \name 2D Transform Gizmo
+ *
+ * Used for UV/Image Editor
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+
+#include "RNA_access.h"
+
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm.h" /* XXX */
+
+#include "ED_image.h"
+#include "ED_screen.h"
+#include "ED_uvedit.h"
+#include "ED_gizmo_library.h"
+
+#include "transform.h" /* own include */
+
+/* axes as index */
+enum {
+ MAN2D_AXIS_TRANS_X = 0,
+ MAN2D_AXIS_TRANS_Y,
+
+ MAN2D_AXIS_LAST,
+};
+
+typedef struct GizmoGroup2D {
+ wmGizmo *translate_x,
+ *translate_y;
+
+ wmGizmo *cage;
+
+ /* Current origin in view space, used to update widget origin for possible view changes */
+ float origin[2];
+ float min[2];
+ float max[2];
+
+} GizmoGroup2D;
+
+
+/* **************** Utilities **************** */
+
+/* loop over axes */
+#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \
+ { \
+ wmGizmo *axis; \
+ int axis_idx; \
+ for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \
+ axis = gizmo2d_get_axis_from_index(ggd, axis_idx);
+
+#define MAN2D_ITER_AXES_END \
+ } \
+ } ((void)0)
+
+static wmGizmo *gizmo2d_get_axis_from_index(const GizmoGroup2D *ggd, const short axis_idx)
+{
+ BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN2D_AXIS_TRANS_X, (float)MAN2D_AXIS_TRANS_Y));
+
+ switch (axis_idx) {
+ case MAN2D_AXIS_TRANS_X:
+ return ggd->translate_x;
+ case MAN2D_AXIS_TRANS_Y:
+ return ggd->translate_y;
+ }
+
+ return NULL;
+}
+
+static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
+{
+ const float alpha = 0.6f;
+ const float alpha_hi = 1.0f;
+ int col_id;
+
+ switch (axis_idx) {
+ case MAN2D_AXIS_TRANS_X:
+ col_id = TH_AXIS_X;
+ break;
+ case MAN2D_AXIS_TRANS_Y:
+ col_id = TH_AXIS_Y;
+ break;
+ }
+
+ UI_GetThemeColor4fv(col_id, r_col);
+
+ copy_v4_v4(r_col_hi, r_col);
+ r_col[3] *= alpha;
+ r_col_hi[3] *= alpha_hi;
+}
+
+static GizmoGroup2D *gizmogroup2d_init(wmGizmoGroup *gzgroup)
+{
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_2d", true);
+ const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_2d", true);
+
+ GizmoGroup2D *ggd = MEM_callocN(sizeof(GizmoGroup2D), __func__);
+
+ ggd->translate_x = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->translate_y = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL);
+
+ RNA_enum_set(ggd->cage->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE |
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE |
+ ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE);
+
+ return ggd;
+}
+
+/**
+ * Calculates origin in view space, use with #gizmo2d_origin_to_region.
+ */
+static void gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
+{
+ float min_buf[2], max_buf[2];
+ if (r_min == NULL) {
+ r_min = min_buf;
+ }
+ if (r_max == NULL) {
+ r_max = max_buf;
+ }
+
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = sa->spacedata.first;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Image *ima = ED_space_image(sima);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, NULL, &objects_len);
+ if (!ED_uvedit_minmax_multi(CTX_data_scene(C), ima, objects, objects_len, r_min, r_max)) {
+ zero_v2(r_min);
+ zero_v2(r_max);
+ }
+ MEM_freeN(objects);
+ }
+ else {
+ zero_v2(r_min);
+ zero_v2(r_max);
+ }
+ mid_v2_v2v2(r_center, r_min, r_max);
+}
+
+/**
+ * Convert origin (or any other point) from view to region space.
+ */
+BLI_INLINE void gizmo2d_origin_to_region(ARegion *ar, float *r_origin)
+{
+ UI_view2d_view_to_region_fl(&ar->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]);
+}
+
+/**
+ * Custom handler for gizmo widgets
+ */
+static int gizmo2d_modal(
+ bContext *C, wmGizmo *widget, const wmEvent *UNUSED(event),
+ eWM_GizmoFlagTweak UNUSED(tweak_flag))
+{
+ ARegion *ar = CTX_wm_region(C);
+ float origin[3];
+
+ gizmo2d_calc_bounds(C, origin, NULL, NULL);
+ gizmo2d_origin_to_region(ar, origin);
+ WM_gizmo_set_matrix_location(widget, origin);
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void ED_widgetgroup_gizmo2d_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
+ GizmoGroup2D *ggd = gizmogroup2d_init(gzgroup);
+ gzgroup->customdata = ggd;
+
+ MAN2D_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ const float offset[3] = {0.0f, 0.2f};
+
+ float color[4], color_hi[4];
+ gizmo2d_get_axis_color(axis_idx, color, color_hi);
+
+ /* custom handler! */
+ WM_gizmo_set_fn_custom_modal(axis, gizmo2d_modal);
+ /* set up widget data */
+ RNA_float_set(axis->ptr, "angle", -M_PI_2 * axis_idx);
+ RNA_float_set(axis->ptr, "length", 0.8f);
+ WM_gizmo_set_matrix_offset_location(axis, offset);
+ WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
+ WM_gizmo_set_scale(axis, U.gizmo_size);
+ WM_gizmo_set_color(axis, color);
+ WM_gizmo_set_color_highlight(axis, color_hi);
+
+ /* assign operator */
+ PointerRNA *ptr = WM_gizmo_operator_set(axis, 0, ot_translate, NULL);
+ bool constraint[3] = {0};
+ constraint[(axis_idx + 1) % 2] = 1;
+ if (RNA_struct_find_property(ptr, "constraint_axis"))
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint);
+ RNA_boolean_set(ptr, "release_confirm", 1);
+ }
+ MAN2D_ITER_AXES_END;
+
+ {
+ wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
+ wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
+ PointerRNA *ptr;
+
+ /* assign operator */
+ ptr = WM_gizmo_operator_set(ggd->cage, 0, ot_translate, NULL);
+ RNA_boolean_set(ptr, "release_confirm", 1);
+
+ bool constraint_x[3] = {1, 0, 0};
+ bool constraint_y[3] = {0, 1, 0};
+
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL);
+ PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
+ PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE, ot_rotate, NULL);
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ }
+}
+
+void ED_widgetgroup_gizmo2d_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroup2D *ggd = gzgroup->customdata;
+ float origin[3];
+ gizmo2d_calc_bounds(C, origin, ggd->min, ggd->max);
+ copy_v2_v2(ggd->origin, origin);
+ bool show_cage = !equals_v2v2(ggd->min, ggd->max);
+
+ if (show_cage) {
+ ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
+ ggd->translate_x->flag |= WM_GIZMO_HIDDEN;
+ ggd->translate_y->flag |= WM_GIZMO_HIDDEN;
+ }
+ else {
+ ggd->cage->flag |= WM_GIZMO_HIDDEN;
+ ggd->translate_x->flag &= ~WM_GIZMO_HIDDEN;
+ ggd->translate_y->flag &= ~WM_GIZMO_HIDDEN;
+ }
+
+ if (show_cage) {
+ wmGizmoOpElem *gzop;
+ float mid[2];
+ const float *min = ggd->min;
+ const float *max = ggd->max;
+ mid_v2_v2v2(mid, min, max);
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X);
+ PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f});
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f});
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f});
+
+ gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f});
+ }
+}
+
+void ED_widgetgroup_gizmo2d_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ GizmoGroup2D *ggd = gzgroup->customdata;
+ float origin[3] = {UNPACK2(ggd->origin), 0.0f};
+ float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
+
+ gizmo2d_origin_to_region(ar, origin);
+
+ MAN2D_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ WM_gizmo_set_matrix_location(axis, origin);
+ }
+ MAN2D_ITER_AXES_END;
+
+ UI_view2d_view_to_region_m4(&ar->v2d, ggd->cage->matrix_space);
+ WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
+ ggd->cage->matrix_offset[0][0] = (ggd->max[0] - ggd->min[0]);
+ ggd->cage->matrix_offset[1][1] = (ggd->max[1] - ggd->min[1]);
+}
+
+/* TODO (Julian)
+ * - Called on every redraw, better to do a more simple poll and check for selection in _refresh
+ * - UV editing only, could be expanded for other things.
+ */
+bool ED_widgetgroup_gizmo2d_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
+{
+ if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
+ return false;
+ }
+
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Object *obedit = CTX_data_edit_object(C);
+
+ if (ED_space_image_show_uvedit(sima, obedit)) {
+ Image *ima = ED_space_image(sima);
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* check if there's a selected poly */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
new file mode 100644
index 00000000000..1f001243a7c
--- /dev/null
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -0,0 +1,2206 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/transform/transform_gizmo_3d.c
+ * \ingroup edtransform
+ *
+ * \name 3D Transform Gizmo
+ *
+ * Used for 3D View
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_layer.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_editmesh.h"
+#include "BKE_lattice.h"
+#include "BKE_gpencil.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
+#include "BKE_object.h"
+
+#include "BIF_gl.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "wm.h"
+
+#include "ED_armature.h"
+#include "ED_curve.h"
+#include "ED_object.h"
+#include "ED_particle.h"
+#include "ED_view3d.h"
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+/* local module include */
+#include "transform.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_select.h"
+#include "GPU_state.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
+#include "DEG_depsgraph_query.h"
+
+/* return codes for select, and drawing flags */
+
+#define MAN_TRANS_X (1 << 0)
+#define MAN_TRANS_Y (1 << 1)
+#define MAN_TRANS_Z (1 << 2)
+#define MAN_TRANS_C (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z)
+
+#define MAN_ROT_X (1 << 3)
+#define MAN_ROT_Y (1 << 4)
+#define MAN_ROT_Z (1 << 5)
+#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z)
+
+#define MAN_SCALE_X (1 << 8)
+#define MAN_SCALE_Y (1 << 9)
+#define MAN_SCALE_Z (1 << 10)
+#define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z)
+
+/* threshold for testing view aligned gizmo axis */
+static struct {
+ float min, max;
+} g_tw_axis_range[2] = {
+ /* Regular range */
+ {0.02f, 0.1f},
+ /* Use a different range because we flip the dot product,
+ * also the view aligned planes are harder to see so hiding early is preferred. */
+ {0.175f, 0.25f},
+};
+
+/* axes as index */
+enum {
+ MAN_AXIS_TRANS_X = 0,
+ MAN_AXIS_TRANS_Y,
+ MAN_AXIS_TRANS_Z,
+ MAN_AXIS_TRANS_C,
+
+ MAN_AXIS_TRANS_XY,
+ MAN_AXIS_TRANS_YZ,
+ MAN_AXIS_TRANS_ZX,
+#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X
+#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1)
+
+ MAN_AXIS_ROT_X,
+ MAN_AXIS_ROT_Y,
+ MAN_AXIS_ROT_Z,
+ MAN_AXIS_ROT_C,
+ MAN_AXIS_ROT_T, /* trackball rotation */
+#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X
+#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1)
+
+ MAN_AXIS_SCALE_X,
+ MAN_AXIS_SCALE_Y,
+ MAN_AXIS_SCALE_Z,
+ MAN_AXIS_SCALE_C,
+ MAN_AXIS_SCALE_XY,
+ MAN_AXIS_SCALE_YZ,
+ MAN_AXIS_SCALE_ZX,
+#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X
+#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1)
+
+ MAN_AXIS_LAST = MAN_AXIS_SCALE_ZX + 1,
+};
+
+/* axis types */
+enum {
+ MAN_AXES_ALL = 0,
+ MAN_AXES_TRANSLATE,
+ MAN_AXES_ROTATE,
+ MAN_AXES_SCALE,
+};
+
+typedef struct GizmoGroup {
+ bool all_hidden;
+ int twtype;
+
+ /* Users may change the twtype, detect changes to re-setup gizmo options. */
+ int twtype_init;
+ int twtype_prev;
+ int use_twtype_refresh;
+
+ struct wmGizmo *gizmos[MAN_AXIS_LAST];
+} GizmoGroup;
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+/* loop over axes */
+#define MAN_ITER_AXES_BEGIN(axis, axis_idx) \
+ { \
+ wmGizmo *axis; \
+ int axis_idx; \
+ for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \
+ axis = gizmo_get_axis_from_index(ggd, axis_idx);
+
+#define MAN_ITER_AXES_END \
+ } \
+ } ((void)0)
+
+static wmGizmo *gizmo_get_axis_from_index(const GizmoGroup *ggd, const short axis_idx)
+{
+ BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST));
+ return ggd->gizmos[axis_idx];
+}
+
+static short gizmo_get_axis_type(const int axis_idx)
+{
+ if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
+ return MAN_AXES_TRANSLATE;
+ }
+ if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
+ return MAN_AXES_ROTATE;
+ }
+ if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) {
+ return MAN_AXES_SCALE;
+ }
+ BLI_assert(0);
+ return -1;
+}
+
+static uint gizmo_orientation_axis(const int axis_idx, bool *r_is_plane)
+{
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_YZ:
+ case MAN_AXIS_SCALE_YZ:
+ if (r_is_plane) {
+ *r_is_plane = true;
+ }
+ ATTR_FALLTHROUGH;
+ case MAN_AXIS_TRANS_X:
+ case MAN_AXIS_ROT_X:
+ case MAN_AXIS_SCALE_X:
+ return 0;
+
+ case MAN_AXIS_TRANS_ZX:
+ case MAN_AXIS_SCALE_ZX:
+ if (r_is_plane) {
+ *r_is_plane = true;
+ }
+ ATTR_FALLTHROUGH;
+ case MAN_AXIS_TRANS_Y:
+ case MAN_AXIS_ROT_Y:
+ case MAN_AXIS_SCALE_Y:
+ return 1;
+
+ case MAN_AXIS_TRANS_XY:
+ case MAN_AXIS_SCALE_XY:
+ if (r_is_plane) {
+ *r_is_plane = true;
+ }
+ ATTR_FALLTHROUGH;
+ case MAN_AXIS_TRANS_Z:
+ case MAN_AXIS_ROT_Z:
+ case MAN_AXIS_SCALE_Z:
+ return 2;
+ }
+ return 3;
+}
+
+static bool gizmo_is_axis_visible(
+ const RegionView3D *rv3d, const int twtype,
+ const float idot[3], const int axis_type, const int axis_idx)
+{
+ if ((axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) == 0) {
+ bool is_plane = false;
+ const uint aidx_norm = gizmo_orientation_axis(axis_idx, &is_plane);
+ /* don't draw axis perpendicular to the view */
+ if (aidx_norm < 3) {
+ float idot_axis = idot[aidx_norm];
+ if (is_plane) {
+ idot_axis = 1.0f - idot_axis;
+ }
+ if (idot_axis < g_tw_axis_range[is_plane].min) {
+ return false;
+ }
+ }
+ }
+
+ if ((axis_type == MAN_AXES_TRANSLATE && !(twtype & SCE_GIZMO_SHOW_TRANSLATE)) ||
+ (axis_type == MAN_AXES_ROTATE && !(twtype & SCE_GIZMO_SHOW_ROTATE)) ||
+ (axis_type == MAN_AXES_SCALE && !(twtype & SCE_GIZMO_SHOW_SCALE)))
+ {
+ return false;
+ }
+
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_X:
+ return (rv3d->twdrawflag & MAN_TRANS_X);
+ case MAN_AXIS_TRANS_Y:
+ return (rv3d->twdrawflag & MAN_TRANS_Y);
+ case MAN_AXIS_TRANS_Z:
+ return (rv3d->twdrawflag & MAN_TRANS_Z);
+ case MAN_AXIS_TRANS_C:
+ return (rv3d->twdrawflag & MAN_TRANS_C);
+ case MAN_AXIS_ROT_X:
+ return (rv3d->twdrawflag & MAN_ROT_X);
+ case MAN_AXIS_ROT_Y:
+ return (rv3d->twdrawflag & MAN_ROT_Y);
+ case MAN_AXIS_ROT_Z:
+ return (rv3d->twdrawflag & MAN_ROT_Z);
+ case MAN_AXIS_ROT_C:
+ case MAN_AXIS_ROT_T:
+ return (rv3d->twdrawflag & MAN_ROT_C);
+ case MAN_AXIS_SCALE_X:
+ return (rv3d->twdrawflag & MAN_SCALE_X);
+ case MAN_AXIS_SCALE_Y:
+ return (rv3d->twdrawflag & MAN_SCALE_Y);
+ case MAN_AXIS_SCALE_Z:
+ return (rv3d->twdrawflag & MAN_SCALE_Z);
+ case MAN_AXIS_SCALE_C:
+ return (rv3d->twdrawflag & MAN_SCALE_C && (twtype & SCE_GIZMO_SHOW_TRANSLATE) == 0);
+ case MAN_AXIS_TRANS_XY:
+ return (rv3d->twdrawflag & MAN_TRANS_X &&
+ rv3d->twdrawflag & MAN_TRANS_Y &&
+ (twtype & SCE_GIZMO_SHOW_ROTATE) == 0);
+ case MAN_AXIS_TRANS_YZ:
+ return (rv3d->twdrawflag & MAN_TRANS_Y &&
+ rv3d->twdrawflag & MAN_TRANS_Z &&
+ (twtype & SCE_GIZMO_SHOW_ROTATE) == 0);
+ case MAN_AXIS_TRANS_ZX:
+ return (rv3d->twdrawflag & MAN_TRANS_Z &&
+ rv3d->twdrawflag & MAN_TRANS_X &&
+ (twtype & SCE_GIZMO_SHOW_ROTATE) == 0);
+ case MAN_AXIS_SCALE_XY:
+ return (rv3d->twdrawflag & MAN_SCALE_X &&
+ rv3d->twdrawflag & MAN_SCALE_Y &&
+ (twtype & SCE_GIZMO_SHOW_TRANSLATE) == 0 &&
+ (twtype & SCE_GIZMO_SHOW_ROTATE) == 0);
+ case MAN_AXIS_SCALE_YZ:
+ return (rv3d->twdrawflag & MAN_SCALE_Y &&
+ rv3d->twdrawflag & MAN_SCALE_Z &&
+ (twtype & SCE_GIZMO_SHOW_TRANSLATE) == 0 &&
+ (twtype & SCE_GIZMO_SHOW_ROTATE) == 0);
+ case MAN_AXIS_SCALE_ZX:
+ return (rv3d->twdrawflag & MAN_SCALE_Z &&
+ rv3d->twdrawflag & MAN_SCALE_X &&
+ (twtype & SCE_GIZMO_SHOW_TRANSLATE) == 0 &&
+ (twtype & SCE_GIZMO_SHOW_ROTATE) == 0);
+ }
+ return false;
+}
+
+static void gizmo_get_axis_color(
+ const int axis_idx, const float idot[3],
+ float r_col[4], float r_col_hi[4])
+{
+ /* alpha values for normal/highlighted states */
+ const float alpha = 0.6f;
+ const float alpha_hi = 1.0f;
+ float alpha_fac;
+
+ if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
+ /* Never fade rotation rings. */
+ /* trackball rotation axis is a special case, we only draw a slight overlay */
+ alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f;
+ }
+ else {
+ bool is_plane = false;
+ const int axis_idx_norm = gizmo_orientation_axis(axis_idx, &is_plane);
+ /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */
+ if (axis_idx_norm < 3) {
+ const float idot_min = g_tw_axis_range[is_plane].min;
+ const float idot_max = g_tw_axis_range[is_plane].max;
+ float idot_axis = idot[axis_idx_norm];
+ if (is_plane) {
+ idot_axis = 1.0f - idot_axis;
+ }
+ alpha_fac = (
+ (idot_axis > idot_max) ?
+ 1.0f : (idot_axis < idot_min) ?
+ 0.0f : ((idot_axis - idot_min) / (idot_max - idot_min)));
+ }
+ else {
+ alpha_fac = 1.0f;
+ }
+ }
+
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_X:
+ case MAN_AXIS_ROT_X:
+ case MAN_AXIS_SCALE_X:
+ case MAN_AXIS_TRANS_YZ:
+ case MAN_AXIS_SCALE_YZ:
+ UI_GetThemeColor4fv(TH_AXIS_X, r_col);
+ break;
+ case MAN_AXIS_TRANS_Y:
+ case MAN_AXIS_ROT_Y:
+ case MAN_AXIS_SCALE_Y:
+ case MAN_AXIS_TRANS_ZX:
+ case MAN_AXIS_SCALE_ZX:
+ UI_GetThemeColor4fv(TH_AXIS_Y, r_col);
+ break;
+ case MAN_AXIS_TRANS_Z:
+ case MAN_AXIS_ROT_Z:
+ case MAN_AXIS_SCALE_Z:
+ case MAN_AXIS_TRANS_XY:
+ case MAN_AXIS_SCALE_XY:
+ UI_GetThemeColor4fv(TH_AXIS_Z, r_col);
+ break;
+ case MAN_AXIS_TRANS_C:
+ case MAN_AXIS_ROT_C:
+ case MAN_AXIS_SCALE_C:
+ case MAN_AXIS_ROT_T:
+ copy_v4_fl(r_col, 1.0f);
+ break;
+ }
+
+ copy_v4_v4(r_col_hi, r_col);
+
+ r_col[3] = alpha * alpha_fac;
+ r_col_hi[3] = alpha_hi * alpha_fac;
+}
+
+static void gizmo_get_axis_constraint(const int axis_idx, bool r_axis[3])
+{
+ ARRAY_SET_ITEMS(r_axis, 0, 0, 0);
+
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_X:
+ case MAN_AXIS_ROT_X:
+ case MAN_AXIS_SCALE_X:
+ r_axis[0] = 1;
+ break;
+ case MAN_AXIS_TRANS_Y:
+ case MAN_AXIS_ROT_Y:
+ case MAN_AXIS_SCALE_Y:
+ r_axis[1] = 1;
+ break;
+ case MAN_AXIS_TRANS_Z:
+ case MAN_AXIS_ROT_Z:
+ case MAN_AXIS_SCALE_Z:
+ r_axis[2] = 1;
+ break;
+ case MAN_AXIS_TRANS_XY:
+ case MAN_AXIS_SCALE_XY:
+ r_axis[0] = r_axis[1] = 1;
+ break;
+ case MAN_AXIS_TRANS_YZ:
+ case MAN_AXIS_SCALE_YZ:
+ r_axis[1] = r_axis[2] = 1;
+ break;
+ case MAN_AXIS_TRANS_ZX:
+ case MAN_AXIS_SCALE_ZX:
+ r_axis[2] = r_axis[0] = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* **************** Preparation Stuff **************** */
+
+/* transform widget center calc helper for below */
+static void calc_tw_center(struct TransformBounds *tbounds, const float co[3])
+{
+ minmax_v3v3_v3(tbounds->min, tbounds->max, co);
+ add_v3_v3(tbounds->center, co);
+
+ for (int i = 0; i < 3; i++) {
+ const float d = dot_v3v3(tbounds->axis[i], co);
+ tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]);
+ tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]);
+ }
+}
+
+static void calc_tw_center_with_matrix(
+ struct TransformBounds *tbounds, const float co[3],
+ const bool use_matrix, const float matrix[4][4])
+{
+ float co_world[3];
+ if (use_matrix) {
+ mul_v3_m4v3(co_world, matrix, co);
+ co = co_world;
+ }
+ calc_tw_center(tbounds, co);
+}
+
+static void protectflag_to_drawflags(short protectflag, short *drawflags)
+{
+ if (protectflag & OB_LOCK_LOCX)
+ *drawflags &= ~MAN_TRANS_X;
+ if (protectflag & OB_LOCK_LOCY)
+ *drawflags &= ~MAN_TRANS_Y;
+ if (protectflag & OB_LOCK_LOCZ)
+ *drawflags &= ~MAN_TRANS_Z;
+
+ if (protectflag & OB_LOCK_ROTX)
+ *drawflags &= ~MAN_ROT_X;
+ if (protectflag & OB_LOCK_ROTY)
+ *drawflags &= ~MAN_ROT_Y;
+ if (protectflag & OB_LOCK_ROTZ)
+ *drawflags &= ~MAN_ROT_Z;
+
+ if (protectflag & OB_LOCK_SCALEX)
+ *drawflags &= ~MAN_SCALE_X;
+ if (protectflag & OB_LOCK_SCALEY)
+ *drawflags &= ~MAN_SCALE_Y;
+ if (protectflag & OB_LOCK_SCALEZ)
+ *drawflags &= ~MAN_SCALE_Z;
+}
+
+/* for pose mode */
+static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
+{
+ protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
+}
+
+/* for editmode*/
+static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo)
+{
+ if (ebo->flag & BONE_EDITMODE_LOCKED) {
+ protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
+ }
+}
+
+/* could move into BLI_math however this is only useful for display/editing purposes */
+static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
+{
+ /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */
+
+ float cross_vec[3];
+ float quat[4];
+
+ /* this is an un-scientific method to get a vector to cross with
+ * XYZ intentionally YZX */
+ cross_vec[0] = axis[1];
+ cross_vec[1] = axis[2];
+ cross_vec[2] = axis[0];
+
+ /* X-axis */
+ cross_v3_v3v3(gmat[0], cross_vec, axis);
+ normalize_v3(gmat[0]);
+ axis_angle_to_quat(quat, axis, angle);
+ mul_qt_v3(quat, gmat[0]);
+
+ /* Y-axis */
+ axis_angle_to_quat(quat, axis, M_PI_2);
+ copy_v3_v3(gmat[1], gmat[0]);
+ mul_qt_v3(quat, gmat[1]);
+
+ /* Z-axis */
+ copy_v3_v3(gmat[2], axis);
+
+ normalize_m3(gmat);
+}
+
+
+static bool test_rotmode_euler(short rotmode)
+{
+ return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
+}
+
+bool gimbal_axis(Object *ob, float gmat[3][3])
+{
+ if (ob->mode & OB_MODE_POSE) {
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
+
+ if (pchan) {
+ float mat[3][3], tmat[3][3], obmat[3][3];
+ if (test_rotmode_euler(pchan->rotmode)) {
+ eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
+ }
+ else { /* quat */
+ return 0;
+ }
+
+
+ /* apply bone transformation */
+ mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
+
+ if (pchan->parent) {
+ float parent_mat[3][3];
+
+ copy_m3_m4(parent_mat, pchan->parent->pose_mat);
+ mul_m3_m3m3(mat, parent_mat, tmat);
+
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, mat);
+ }
+ else {
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, tmat);
+ }
+
+ normalize_m3(gmat);
+ return 1;
+ }
+ }
+ else {
+ if (test_rotmode_euler(ob->rotmode)) {
+ eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
+ }
+ else { /* quat */
+ return 0;
+ }
+
+ if (ob->parent) {
+ float parent_mat[3][3];
+ copy_m3_m4(parent_mat, ob->parent->obmat);
+ normalize_m3(parent_mat);
+ mul_m3_m3m3(gmat, parent_mat, gmat);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+void ED_transform_calc_orientation_from_type(
+ const bContext *C, float r_mat[3][3])
+{
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obedit = CTX_data_edit_object(C);
+ RegionView3D *rv3d = ar->regiondata;
+ Object *ob = OBACT(view_layer);
+ const short orientation_type = scene->orientation_type;
+ const int pivot_point = scene->toolsettings->transform_pivot_point;
+
+ ED_transform_calc_orientation_from_type_ex(
+ C, r_mat,
+ scene, rv3d, ob, obedit, orientation_type, pivot_point);
+}
+
+void ED_transform_calc_orientation_from_type_ex(
+ const bContext *C, float r_mat[3][3],
+ /* extra args (can be accessed from context) */
+ Scene *scene, RegionView3D *rv3d, Object *ob, Object *obedit,
+ const short orientation_type, const int pivot_point)
+{
+ bool ok = false;
+
+ switch (orientation_type) {
+ case V3D_MANIP_GLOBAL:
+ {
+ break; /* nothing to do */
+ }
+ case V3D_MANIP_GIMBAL:
+ {
+ if (gimbal_axis(ob, r_mat)) {
+ ok = true;
+ break;
+ }
+ /* if not gimbal, fall through to normal */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_MANIP_NORMAL:
+ {
+ if (obedit || ob->mode & OB_MODE_POSE) {
+ ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
+ ok = true;
+ break;
+ }
+ /* no break we define 'normal' as 'local' in Object mode */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_MANIP_LOCAL:
+ {
+ if (ob->mode & OB_MODE_POSE) {
+ /* each bone moves on its own local axis, but to avoid confusion,
+ * use the active pones axis for display [#33575], this works as expected on a single bone
+ * and users who select many bones will understand what's going on and what local means
+ * when they start transforming */
+ ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
+ ok = true;
+ break;
+ }
+ copy_m3_m4(r_mat, ob->obmat);
+ normalize_m3(r_mat);
+ ok = true;
+ break;
+ }
+ case V3D_MANIP_VIEW:
+ {
+ if (rv3d != NULL) {
+ copy_m3_m4(r_mat, rv3d->viewinv);
+ normalize_m3(r_mat);
+ ok = true;
+ }
+ break;
+ }
+ case V3D_MANIP_CURSOR:
+ {
+ ED_view3d_cursor3d_calc_mat3(scene, r_mat);
+ ok = true;
+ break;
+ }
+ case V3D_MANIP_CUSTOM:
+ {
+ TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
+ scene, scene->orientation_index_custom);
+ if (applyTransformOrientation(custom_orientation, r_mat, NULL)) {
+ ok = true;
+ }
+ break;
+ }
+ }
+
+ if (!ok) {
+ unit_m3(r_mat);
+ }
+}
+
+/* centroid, boundbox, of selection */
+/* returns total items selected */
+int ED_transform_calc_gizmo_stats(
+ const bContext *C,
+ const struct TransformCalcParams *params,
+ struct TransformBounds *tbounds)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = sa->spacedata.first;
+ Object *obedit = CTX_data_edit_object(C);
+ RegionView3D *rv3d = ar->regiondata;
+ Base *base;
+ Object *ob = OBACT(view_layer);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
+ int a, totsel = 0;
+ const int pivot_point = scene->toolsettings->transform_pivot_point;
+
+ /* transform widget matrix */
+ unit_m4(rv3d->twmat);
+
+ unit_m3(rv3d->tw_axis_matrix);
+ zero_v3(rv3d->tw_axis_min);
+ zero_v3(rv3d->tw_axis_max);
+
+ rv3d->twdrawflag = 0xFFFF;
+
+ /* global, local or normal orientation?
+ * if we could check 'totsel' now, this should be skipped with no selection. */
+ if (ob) {
+ const short orientation_type = params->orientation_type ? (params->orientation_type - 1) : scene->orientation_type;
+ float mat[3][3];
+ ED_transform_calc_orientation_from_type_ex(
+ C, mat,
+ scene, rv3d, ob, obedit, orientation_type, pivot_point);
+ copy_m4_m3(rv3d->twmat, mat);
+ }
+
+ /* transform widget centroid/center */
+ INIT_MINMAX(tbounds->min, tbounds->max);
+ zero_v3(tbounds->center);
+
+ copy_m3_m4(tbounds->axis, rv3d->twmat);
+ if (params->use_local_axis && (ob && ob->mode & OB_MODE_EDIT)) {
+ float diff_mat[3][3];
+ copy_m3_m4(diff_mat, ob->obmat);
+ normalize_m3(diff_mat);
+ invert_m3(diff_mat);
+ mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat);
+ normalize_m3(tbounds->axis);
+ }
+
+ for (int i = 0; i < 3; i++) {
+ tbounds->axis_min[i] = +FLT_MAX;
+ tbounds->axis_max[i] = -FLT_MAX;
+ }
+
+ if (is_gp_edit) {
+ float diff_mat[4][4];
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ const bool use_mat_local = gpl->parent != NULL;
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+
+ /* calculate difference matrix */
+ ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat);
+
+ for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ 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) {
+ calc_tw_center_with_matrix(tbounds, &pt->x, use_mat_local, diff_mat);
+ totsel++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /* selection center */
+ if (totsel) {
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */
+ }
+ }
+ else if (obedit) {
+
+#define FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) \
+ { \
+ invert_m4_m4(obedit->imat, obedit->obmat); \
+ uint objects_len = 0; \
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode(view_layer, CTX_wm_view3d(C), &objects_len); \
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) { \
+ Object *ob_iter = objects[ob_index]; \
+ const bool use_mat_local = (ob_iter != obedit);
+
+#define FOREACH_EDIT_OBJECT_END() \
+ } \
+ MEM_freeN(objects); \
+ } ((void)0)
+
+ ob = obedit;
+ if (obedit->type == OB_MESH) {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMEditSelection ese;
+ float vec[3] = {0, 0, 0};
+
+ /* USE LAST SELECT WITH ACTIVE */
+ if ((pivot_point == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
+ BM_editselection_center(&ese, vec);
+ calc_tw_center(tbounds, vec);
+ totsel = 1;
+ }
+ else {
+ FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) {
+ BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
+ BMesh *bm = em_iter->bm;
+
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ BMVert *eve;
+ BMIter iter;
+
+ float mat_local[4][4];
+ if (use_mat_local) {
+ mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
+ }
+
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ calc_tw_center_with_matrix(tbounds, eve->co, use_mat_local, mat_local);
+ totsel++;
+ }
+ }
+ }
+ } FOREACH_EDIT_OBJECT_END();
+ }
+ } /* end editmesh */
+ else if (obedit->type == OB_ARMATURE) {
+ bArmature *arm = obedit->data;
+ EditBone *ebo;
+
+ if ((pivot_point == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
+ /* doesn't check selection or visibility intentionally */
+ if (ebo->flag & BONE_TIPSEL) {
+ calc_tw_center(tbounds, ebo->tail);
+ totsel++;
+ }
+ if ((ebo->flag & BONE_ROOTSEL) ||
+ ((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */
+ {
+ calc_tw_center(tbounds, ebo->head);
+ totsel++;
+ }
+ protectflag_to_drawflags_ebone(rv3d, ebo);
+ }
+ else {
+ FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) {
+ arm = ob_iter->data;
+
+ float mat_local[4][4];
+ if (use_mat_local) {
+ mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
+ }
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ if (EBONE_VISIBLE(arm, ebo)) {
+ if (ebo->flag & BONE_TIPSEL) {
+ calc_tw_center_with_matrix(tbounds, ebo->tail, use_mat_local, mat_local);
+ totsel++;
+ }
+ if ((ebo->flag & BONE_ROOTSEL) &&
+ /* don't include same point multiple times */
+ ((ebo->flag & BONE_CONNECTED) &&
+ (ebo->parent != NULL) &&
+ (ebo->parent->flag & BONE_TIPSEL) &&
+ EBONE_VISIBLE(arm, ebo->parent)) == 0)
+ {
+ calc_tw_center_with_matrix(tbounds, ebo->head, use_mat_local, mat_local);
+ totsel++;
+ }
+ if (ebo->flag & BONE_SELECTED) {
+ protectflag_to_drawflags_ebone(rv3d, ebo);
+ }
+ }
+ }
+ } FOREACH_EDIT_OBJECT_END();
+ }
+ }
+ else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = obedit->data;
+ float center[3];
+
+ if ((pivot_point == V3D_AROUND_ACTIVE) && ED_curve_active_center(cu, center)) {
+ calc_tw_center(tbounds, center);
+ totsel++;
+ }
+ else {
+ FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) {
+ cu = ob_iter->data;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+
+ float mat_local[4][4];
+ if (use_mat_local) {
+ mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
+ }
+
+ nu = nurbs->first;
+ while (nu) {
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ /* exceptions
+ * if handles are hidden then only check the center points.
+ * If the center knot is selected then only use this as the center point.
+ */
+ if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ if (bezt->f2 & SELECT) {
+ calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local);
+ totsel++;
+ }
+ }
+ else if (bezt->f2 & SELECT) {
+ calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local);
+ totsel++;
+ }
+ else {
+ if (bezt->f1 & SELECT) {
+ const float *co = bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0];
+ calc_tw_center_with_matrix(tbounds, co, use_mat_local, mat_local);
+ totsel++;
+ }
+ if (bezt->f3 & SELECT) {
+ const float *co = bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2];
+ calc_tw_center_with_matrix(tbounds, co, use_mat_local, mat_local);
+ totsel++;
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp = nu->bp;
+ a = nu->pntsu * nu->pntsv;
+ while (a--) {
+ if (bp->f1 & SELECT) {
+ calc_tw_center_with_matrix(tbounds, bp->vec, use_mat_local, mat_local);
+ totsel++;
+ }
+ bp++;
+ }
+ }
+ nu = nu->next;
+ }
+ } FOREACH_EDIT_OBJECT_END();
+ }
+ }
+ else if (obedit->type == OB_MBALL) {
+ MetaBall *mb = (MetaBall *)obedit->data;
+ MetaElem *ml;
+
+ if ((pivot_point == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
+ calc_tw_center(tbounds, &ml->x);
+ totsel++;
+ }
+ else {
+ FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) {
+ mb = (MetaBall *)ob_iter->data;
+
+ float mat_local[4][4];
+ if (use_mat_local) {
+ mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
+ }
+
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ calc_tw_center_with_matrix(tbounds, &ml->x, use_mat_local, mat_local);
+ totsel++;
+ }
+ }
+ } FOREACH_EDIT_OBJECT_END();
+ }
+ }
+ else if (obedit->type == OB_LATTICE) {
+ Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
+ BPoint *bp;
+
+ if ((pivot_point == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
+ calc_tw_center(tbounds, bp->vec);
+ totsel++;
+ }
+ else {
+ FOREACH_EDIT_OBJECT_BEGIN(ob_iter, use_mat_local) {
+ lt = ((Lattice *)ob_iter->data)->editlatt->latt;
+ bp = lt->def;
+ a = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ float mat_local[4][4];
+ if (use_mat_local) {
+ mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
+ }
+
+ while (a--) {
+ if (bp->f1 & SELECT) {
+ calc_tw_center_with_matrix(tbounds, bp->vec, use_mat_local, mat_local);
+ totsel++;
+ }
+ bp++;
+ }
+ } FOREACH_EDIT_OBJECT_END();
+ }
+ }
+
+#undef FOREACH_EDIT_OBJECT_BEGIN
+#undef FOREACH_EDIT_OBJECT_END
+
+ /* selection center */
+ if (totsel) {
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
+ mul_m4_v3(obedit->obmat, tbounds->center);
+ mul_m4_v3(obedit->obmat, tbounds->min);
+ mul_m4_v3(obedit->obmat, tbounds->max);
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_POSE)) {
+ bPoseChannel *pchan;
+ int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the gizmo mode, could be mixed
+ bool ok = false;
+
+ if ((pivot_point == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
+ /* doesn't check selection or visibility intentionally */
+ Bone *bone = pchan->bone;
+ if (bone) {
+ calc_tw_center(tbounds, pchan->pose_head);
+ protectflag_to_drawflags_pchan(rv3d, pchan);
+ totsel = 1;
+ ok = true;
+ }
+ }
+ else {
+ totsel = count_set_pose_transflags(ob, mode, V3D_AROUND_CENTER_BOUNDS, NULL);
+
+ if (totsel) {
+ /* use channels to get stats */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ Bone *bone = pchan->bone;
+ if (bone && (bone->flag & BONE_TRANSFORM)) {
+ calc_tw_center(tbounds, pchan->pose_head);
+ protectflag_to_drawflags_pchan(rv3d, pchan);
+ }
+ }
+ ok = true;
+ }
+ }
+
+ if (ok) {
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
+ mul_m4_v3(ob->obmat, tbounds->center);
+ mul_m4_v3(ob->obmat, tbounds->min);
+ mul_m4_v3(ob->obmat, tbounds->max);
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
+ /* pass */
+ }
+ else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEditPoint *point;
+ PTCacheEditKey *ek;
+ int k;
+
+ if (edit) {
+ point = edit->points;
+ for (a = 0; a < edit->totpoint; a++, point++) {
+ if (point->flag & PEP_HIDE) continue;
+
+ for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
+ if (ek->flag & PEK_SELECT) {
+ calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
+ totsel++;
+ }
+ }
+ }
+
+ /* selection center */
+ if (totsel)
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
+ }
+ }
+ else {
+
+ /* we need the one selected object, if its not active */
+ base = BASACT(view_layer);
+ ob = OBACT(view_layer);
+ if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL;
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ if (!TESTBASELIB(v3d, base)) {
+ continue;
+ }
+ if (ob == NULL) {
+ ob = base->object;
+ }
+
+ /* Get the boundbox out of the evaluated object. */
+ const BoundBox *bb = NULL;
+ if (params->use_only_center == false) {
+ bb = BKE_object_boundbox_get(base->object);
+ }
+
+ if (params->use_only_center || (bb == NULL)) {
+ calc_tw_center(tbounds, base->object->obmat[3]);
+ }
+ else {
+ for (uint j = 0; j < 8; j++) {
+ float co[3];
+ mul_v3_m4v3(co, base->object->obmat, bb->vec[j]);
+ calc_tw_center(tbounds, co);
+ }
+ }
+ protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
+ totsel++;
+ }
+
+ /* selection center */
+ if (totsel) {
+ mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
+ }
+ }
+
+ if (totsel == 0) {
+ unit_m4(rv3d->twmat);
+ }
+ else {
+ copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min);
+ copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max);
+ copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis);
+ }
+
+ return totsel;
+}
+
+static void gizmo_get_idot(RegionView3D *rv3d, float r_idot[3])
+{
+ float view_vec[3], axis_vec[3];
+ ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
+ for (int i = 0; i < 3; i++) {
+ normalize_v3_v3(axis_vec, rv3d->twmat[i]);
+ r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
+ }
+}
+
+static void gizmo_prepare_mat(
+ const bContext *C, RegionView3D *rv3d, const struct TransformBounds *tbounds)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ switch (scene->toolsettings->transform_pivot_point) {
+ case V3D_AROUND_CENTER_BOUNDS:
+ case V3D_AROUND_ACTIVE:
+ {
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = OBACT(view_layer);
+
+ if (((scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) &&
+ (OBEDIT_FROM_OBACT(ob) == NULL)) &&
+ ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
+ (!(ob->mode & OB_MODE_POSE)))
+ {
+ copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
+ }
+ else {
+ mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max);
+ }
+ break;
+ }
+ case V3D_AROUND_LOCAL_ORIGINS:
+ case V3D_AROUND_CENTER_MEAN:
+ copy_v3_v3(rv3d->twmat[3], tbounds->center);
+ break;
+ case V3D_AROUND_CURSOR:
+ copy_v3_v3(rv3d->twmat[3], scene->cursor.location);
+ break;
+ }
+}
+
+/**
+ * Sets up \a r_start and \a r_len to define arrow line range.
+ * Needed to adjust line drawing for combined gizmo axis types.
+ */
+static void gizmo_line_range(const int twtype, const short axis_type, float *r_start, float *r_len)
+{
+ const float ofs = 0.2f;
+
+ *r_start = 0.2f;
+ *r_len = 1.0f;
+
+ switch (axis_type) {
+ case MAN_AXES_TRANSLATE:
+ if (twtype & SCE_GIZMO_SHOW_SCALE) {
+ *r_start = *r_len - ofs + 0.075f;
+ }
+ if (twtype & SCE_GIZMO_SHOW_ROTATE) {
+ *r_len += ofs;
+ }
+ break;
+ case MAN_AXES_SCALE:
+ if (twtype & (SCE_GIZMO_SHOW_TRANSLATE | SCE_GIZMO_SHOW_ROTATE)) {
+ *r_len -= ofs + 0.025f;
+ }
+ break;
+ }
+
+ *r_len -= *r_start;
+}
+
+static void gizmo_xform_message_subscribe(
+ wmGizmoGroup *gzgroup, struct wmMsgBus *mbus,
+ Scene *scene, bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar, const void *type_fn)
+{
+ /* Subscribe to view properties */
+ wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
+ .owner = ar,
+ .user_data = gzgroup->parent_gzmap,
+ .notify = WM_gizmo_do_msg_notify_tag_refresh,
+ };
+
+ PointerRNA scene_ptr;
+ RNA_id_pointer_create(&scene->id, &scene_ptr);
+
+ {
+ extern PropertyRNA rna_Scene_transform_orientation;
+ extern PropertyRNA rna_Scene_cursor_location;
+ const PropertyRNA *props[] = {
+ &rna_Scene_transform_orientation,
+ (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) ? &rna_Scene_cursor_location : NULL,
+ };
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ if (props[i]) {
+ WM_msg_subscribe_rna(mbus, &scene_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
+ }
+ }
+ }
+
+ PointerRNA toolsettings_ptr;
+ RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
+
+ if (type_fn == TRANSFORM_GGT_gizmo) {
+ extern PropertyRNA rna_ToolSettings_transform_pivot_point;
+ extern PropertyRNA rna_ToolSettings_use_gizmo_mode;
+ const PropertyRNA *props[] = {
+ &rna_ToolSettings_transform_pivot_point,
+ &rna_ToolSettings_use_gizmo_mode,
+ };
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &toolsettings_ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
+ }
+ }
+ else if (type_fn == VIEW3D_GGT_xform_cage) {
+ /* pass */
+ }
+ else if (type_fn == VIEW3D_GGT_xform_shear) {
+ /* pass */
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_gz_tag_refresh);
+}
+
+
+void drawDial3d(const TransInfo *t)
+{
+ if (t->mode == TFM_ROTATION && t->spacetype == SPACE_VIEW3D) {
+ wmGizmo *gz = wm_gizmomap_highlight_get(t->ar->gizmo_map);
+ if (gz == NULL) {
+ /* We only draw Dial3d if the operator has been called by a gizmo. */
+ return;
+ }
+
+ float mat_basis[4][4];
+ float mat_final[4][4];
+ float color[4];
+ float increment;
+ float line_with = GIZMO_AXIS_LINE_WIDTH + 1.0f;
+ float scale = UI_DPI_FAC * U.gizmo_size;
+
+ int axis_idx;
+
+ const TransCon *tc = &(t->con);
+ if (tc->mode & CON_APPLY) {
+ if (tc->mode & CON_AXIS0) {
+ axis_idx = MAN_AXIS_ROT_X;
+ negate_v3_v3(mat_basis[2], tc->mtx[0]);
+ }
+ else if (tc->mode & CON_AXIS1) {
+ axis_idx = MAN_AXIS_ROT_Y;
+ negate_v3_v3(mat_basis[2], tc->mtx[1]);
+ }
+ else {
+ BLI_assert((tc->mode & CON_AXIS2) != 0);
+ axis_idx = MAN_AXIS_ROT_Z;
+ negate_v3_v3(mat_basis[2], tc->mtx[2]);
+ }
+ }
+ else {
+ axis_idx = MAN_AXIS_ROT_C;
+ negate_v3_v3(mat_basis[2], t->axis);
+ scale *= 1.2f;
+ line_with -= 1.0f;
+ }
+
+ copy_v3_v3(mat_basis[3], t->center_global);
+ mat_basis[2][3] = -dot_v3v3(mat_basis[2], mat_basis[3]);
+
+ if (ED_view3d_win_to_3d_on_plane(
+ t->ar, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)},
+ false, mat_basis[1]))
+ {
+ sub_v3_v3(mat_basis[1], mat_basis[3]);
+ normalize_v3(mat_basis[1]);
+ cross_v3_v3v3(mat_basis[0], mat_basis[1], mat_basis[2]);
+ }
+ else {
+ /* The plane and the mouse direction are parallel.
+ * Calculate a matrix orthogonal to the axis. */
+ ortho_basis_v3v3_v3(mat_basis[0], mat_basis[1], mat_basis[2]);
+ }
+
+ mat_basis[0][3] = 0.0f;
+ mat_basis[1][3] = 0.0f;
+ mat_basis[2][3] = 0.0f;
+ mat_basis[3][3] = 1.0f;
+
+ copy_m4_m4(mat_final, mat_basis);
+ scale *= ED_view3d_pixel_size_no_ui_scale(t->ar->regiondata, mat_final[3]);
+ mul_mat3_m4_fl(mat_final, scale);
+
+ if ((t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) &&
+ activeSnap(t))
+ {
+ increment = (t->modifiers & MOD_PRECISION) ? t->snap[2] : t->snap[1];
+ }
+ else {
+ increment = t->snap[0];
+ }
+
+ BLI_assert(axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END);
+ gizmo_get_axis_color(axis_idx, NULL, color, color);
+
+ GPU_depth_test(false);
+ GPU_blend(true);
+ GPU_line_smooth(true);
+
+ ED_gizmotypes_dial_3d_draw_util(
+ mat_basis, mat_final, line_with, color,
+ &(struct Dial3dParams){
+ .draw_options = ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE,
+ .angle_delta = t->values[0],
+ .angle_increment = increment,
+ });
+
+ GPU_line_smooth(false);
+ GPU_depth_test(true);
+ GPU_blend(false);
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Gizmo
+ * \{ */
+
+static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
+{
+ GizmoGroup *ggd;
+
+ ggd = MEM_callocN(sizeof(GizmoGroup), "gizmo_data");
+
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
+ const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
+ const wmGizmoType *gzt_prim = WM_gizmotype_find("GIZMO_GT_primitive_3d", true);
+
+#define GIZMO_NEW_ARROW(v, draw_style) { \
+ ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); \
+ RNA_enum_set(ggd->gizmos[v]->ptr, "draw_style", draw_style); \
+} ((void)0)
+#define GIZMO_NEW_DIAL(v, draw_options) { \
+ ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); \
+ RNA_enum_set(ggd->gizmos[v]->ptr, "draw_options", draw_options); \
+} ((void)0)
+#define GIZMO_NEW_PRIM(v, draw_style) { \
+ ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_prim, gzgroup, NULL); \
+ RNA_enum_set(ggd->gizmos[v]->ptr, "draw_style", draw_style); \
+} ((void)0)
+
+ /* add/init widgets - order matters! */
+ GIZMO_NEW_DIAL(MAN_AXIS_ROT_T, ED_GIZMO_DIAL_DRAW_FLAG_FILL);
+
+ GIZMO_NEW_DIAL(MAN_AXIS_SCALE_C, ED_GIZMO_DIAL_DRAW_FLAG_NOP);
+
+ GIZMO_NEW_ARROW(MAN_AXIS_SCALE_X, ED_GIZMO_ARROW_STYLE_BOX);
+ GIZMO_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_GIZMO_ARROW_STYLE_BOX);
+ GIZMO_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_GIZMO_ARROW_STYLE_BOX);
+
+ GIZMO_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
+ GIZMO_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
+ GIZMO_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
+
+ GIZMO_NEW_DIAL(MAN_AXIS_ROT_X, ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
+ GIZMO_NEW_DIAL(MAN_AXIS_ROT_Y, ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
+ GIZMO_NEW_DIAL(MAN_AXIS_ROT_Z, ED_GIZMO_DIAL_DRAW_FLAG_CLIP);
+
+ /* init screen aligned widget last here, looks better, behaves better */
+ GIZMO_NEW_DIAL(MAN_AXIS_ROT_C, ED_GIZMO_DIAL_DRAW_FLAG_NOP);
+
+ GIZMO_NEW_DIAL(MAN_AXIS_TRANS_C, ED_GIZMO_DIAL_DRAW_FLAG_NOP);
+
+ GIZMO_NEW_ARROW(MAN_AXIS_TRANS_X, ED_GIZMO_ARROW_STYLE_NORMAL);
+ GIZMO_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_GIZMO_ARROW_STYLE_NORMAL);
+ GIZMO_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_GIZMO_ARROW_STYLE_NORMAL);
+
+ GIZMO_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
+ GIZMO_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
+ GIZMO_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_GIZMO_PRIMITIVE_STYLE_PLANE);
+
+ ggd->gizmos[MAN_AXIS_ROT_T]->flag |= WM_GIZMO_SELECT_BACKGROUND;
+
+ return ggd;
+}
+
+/**
+ * Custom handler for gizmo widgets
+ */
+static int gizmo_modal(
+ bContext *C, wmGizmo *widget, const wmEvent *event,
+ eWM_GizmoFlagTweak UNUSED(tweak_flag))
+{
+ /* Avoid unnecessary updates, partially address: T55458. */
+ if (ELEM(event->type, TIMER, INBETWEEN_MOUSEMOVE)) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ struct TransformBounds tbounds;
+
+
+ if (ED_transform_calc_gizmo_stats(
+ C, &(struct TransformCalcParams){
+ .use_only_center = true,
+ }, &tbounds))
+ {
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+ WM_gizmo_set_matrix_location(widget, rv3d->twmat[3]);
+ }
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
+{
+ struct {
+ wmOperatorType *translate, *rotate, *trackball, *resize;
+ } ot_store = {NULL};
+ GizmoGroup *ggd = gzgroup->customdata;
+
+ MAN_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ const short axis_type = gizmo_get_axis_type(axis_idx);
+ bool constraint_axis[3] = {1, 0, 0};
+ PointerRNA *ptr = NULL;
+
+ gizmo_get_axis_constraint(axis_idx, constraint_axis);
+
+ /* custom handler! */
+ WM_gizmo_set_fn_custom_modal(axis, gizmo_modal);
+
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_X:
+ case MAN_AXIS_TRANS_Y:
+ case MAN_AXIS_TRANS_Z:
+ case MAN_AXIS_SCALE_X:
+ case MAN_AXIS_SCALE_Y:
+ case MAN_AXIS_SCALE_Z:
+ if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
+ int draw_options = 0;
+ if ((ggd->twtype & (SCE_GIZMO_SHOW_ROTATE | SCE_GIZMO_SHOW_SCALE)) == 0) {
+ draw_options |= ED_GIZMO_ARROW_DRAW_FLAG_STEM;
+ }
+ RNA_enum_set(axis->ptr, "draw_options", draw_options);
+ }
+
+ WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
+ break;
+ case MAN_AXIS_ROT_X:
+ case MAN_AXIS_ROT_Y:
+ case MAN_AXIS_ROT_Z:
+ /* increased line width for better display */
+ WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH + 1.0f);
+ WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_VALUE, true);
+ break;
+ case MAN_AXIS_TRANS_XY:
+ case MAN_AXIS_TRANS_YZ:
+ case MAN_AXIS_TRANS_ZX:
+ case MAN_AXIS_SCALE_XY:
+ case MAN_AXIS_SCALE_YZ:
+ case MAN_AXIS_SCALE_ZX:
+ {
+ const float ofs_ax = 7.0f;
+ const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
+ WM_gizmo_set_scale(axis, 0.07f);
+ WM_gizmo_set_matrix_offset_location(axis, ofs);
+ WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
+ break;
+ }
+ case MAN_AXIS_TRANS_C:
+ case MAN_AXIS_ROT_C:
+ case MAN_AXIS_SCALE_C:
+ case MAN_AXIS_ROT_T:
+ WM_gizmo_set_line_width(axis, GIZMO_AXIS_LINE_WIDTH);
+ if (axis_idx == MAN_AXIS_ROT_T) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_HOVER, true);
+ }
+ else if (axis_idx == MAN_AXIS_ROT_C) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_VALUE, true);
+ WM_gizmo_set_scale(axis, 1.2f);
+ }
+ else {
+ WM_gizmo_set_scale(axis, 0.2f);
+ }
+ break;
+ }
+
+ switch (axis_type) {
+ case MAN_AXES_TRANSLATE:
+ if (ot_store.translate == NULL) {
+ ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
+ }
+ ptr = WM_gizmo_operator_set(axis, 0, ot_store.translate, NULL);
+ break;
+ case MAN_AXES_ROTATE:
+ {
+ wmOperatorType *ot_rotate;
+ if (axis_idx == MAN_AXIS_ROT_T) {
+ if (ot_store.trackball == NULL) {
+ ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true);
+ }
+ ot_rotate = ot_store.trackball;
+ }
+ else {
+ if (ot_store.rotate == NULL) {
+ ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
+ }
+ ot_rotate = ot_store.rotate;
+ }
+ ptr = WM_gizmo_operator_set(axis, 0, ot_rotate, NULL);
+ break;
+ }
+ case MAN_AXES_SCALE:
+ {
+ if (ot_store.resize == NULL) {
+ ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
+ }
+ ptr = WM_gizmo_operator_set(axis, 0, ot_store.resize, NULL);
+ break;
+ }
+ }
+
+ if (ptr) {
+ PropertyRNA *prop;
+ if (ELEM(true, UNPACK3(constraint_axis))) {
+ if ((prop = RNA_struct_find_property(ptr, "constraint_axis"))) {
+ RNA_property_boolean_set_array(ptr, prop, constraint_axis);
+ }
+ }
+
+ RNA_boolean_set(ptr, "release_confirm", 1);
+ }
+ }
+ MAN_ITER_AXES_END;
+}
+
+static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroup *ggd = gizmogroup_init(gzgroup);
+
+ gzgroup->customdata = ggd;
+
+ {
+ ggd->twtype = 0;
+ ScrArea *sa = CTX_wm_area(C);
+ const bToolRef *tref = sa->runtime.tool;
+
+ if (tref == NULL || STREQ(tref->idname, "Transform")) {
+ /* Setup all gizmos, they can be toggled via 'ToolSettings.gizmo_flag' */
+ ggd->twtype = SCE_GIZMO_SHOW_TRANSLATE | SCE_GIZMO_SHOW_ROTATE | SCE_GIZMO_SHOW_SCALE;
+ ggd->use_twtype_refresh = true;
+ }
+ else if (STREQ(tref->idname, "Move")) {
+ ggd->twtype |= SCE_GIZMO_SHOW_TRANSLATE;
+ }
+ else if (STREQ(tref->idname, "Rotate")) {
+ ggd->twtype |= SCE_GIZMO_SHOW_ROTATE;
+ }
+ else if (STREQ(tref->idname, "Scale")) {
+ ggd->twtype |= SCE_GIZMO_SHOW_SCALE;
+ }
+ BLI_assert(ggd->twtype != 0);
+ ggd->twtype_init = ggd->twtype;
+ }
+
+ /* *** set properties for axes *** */
+ gizmogroup_init_properties_from_twtype(gzgroup);
+}
+
+static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroup *ggd = gzgroup->customdata;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+ struct TransformBounds tbounds;
+
+ if (ggd->use_twtype_refresh) {
+ Scene *scene = CTX_data_scene(C);
+ ggd->twtype = scene->toolsettings->gizmo_flag & ggd->twtype_init;
+ if (ggd->twtype != ggd->twtype_prev) {
+ ggd->twtype_prev = ggd->twtype;
+ gizmogroup_init_properties_from_twtype(gzgroup);
+ }
+ }
+
+ /* skip, we don't draw anything anyway */
+ if ((ggd->all_hidden =
+ (ED_transform_calc_gizmo_stats(
+ C, &(struct TransformCalcParams){
+ .use_only_center = true,
+ }, &tbounds) == 0)))
+ {
+ return;
+ }
+
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+
+ /* *** set properties for axes *** */
+
+ MAN_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ const short axis_type = gizmo_get_axis_type(axis_idx);
+ const int aidx_norm = gizmo_orientation_axis(axis_idx, NULL);
+
+ WM_gizmo_set_matrix_location(axis, rv3d->twmat[3]);
+
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_X:
+ case MAN_AXIS_TRANS_Y:
+ case MAN_AXIS_TRANS_Z:
+ case MAN_AXIS_SCALE_X:
+ case MAN_AXIS_SCALE_Y:
+ case MAN_AXIS_SCALE_Z:
+ {
+ float start_co[3] = {0.0f, 0.0f, 0.0f};
+ float len;
+
+ gizmo_line_range(ggd->twtype, axis_type, &start_co[2], &len);
+
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
+ RNA_float_set(axis->ptr, "length", len);
+
+ if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
+ if (ggd->twtype & SCE_GIZMO_SHOW_ROTATE) {
+ /* Avoid rotate and translate arrows overlap. */
+ start_co[2] += 0.215f;
+ }
+ }
+ WM_gizmo_set_matrix_offset_location(axis, start_co);
+ WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
+ break;
+ }
+ case MAN_AXIS_ROT_X:
+ case MAN_AXIS_ROT_Y:
+ case MAN_AXIS_ROT_Z:
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
+ break;
+ case MAN_AXIS_TRANS_XY:
+ case MAN_AXIS_TRANS_YZ:
+ case MAN_AXIS_TRANS_ZX:
+ case MAN_AXIS_SCALE_XY:
+ case MAN_AXIS_SCALE_YZ:
+ case MAN_AXIS_SCALE_ZX:
+ {
+ const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
+ const float *z_axis = rv3d->twmat[aidx_norm];
+ WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
+ break;
+ }
+ }
+ }
+ MAN_ITER_AXES_END;
+}
+
+static void WIDGETGROUP_gizmo_message_subscribe(
+ const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus)
+{
+ Scene *scene = CTX_data_scene(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, TRANSFORM_GGT_gizmo);
+}
+
+static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoGroup *ggd = gzgroup->customdata;
+ // ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ // View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
+ float idot[3];
+
+ /* when looking through a selected camera, the gizmo can be at the
+ * exact same position as the view, skip so we don't break selection */
+ if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) {
+ MAN_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
+ MAN_ITER_AXES_END;
+ return;
+ }
+ gizmo_get_idot(rv3d, idot);
+
+ /* *** set properties for axes *** */
+
+ MAN_ITER_AXES_BEGIN(axis, axis_idx)
+ {
+ const short axis_type = gizmo_get_axis_type(axis_idx);
+ /* XXX maybe unset _HIDDEN flag on redraw? */
+
+ if (gizmo_is_axis_visible(rv3d, ggd->twtype, idot, axis_type, axis_idx)) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
+ }
+ else {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ continue;
+ }
+
+ float color[4], color_hi[4];
+ gizmo_get_axis_color(axis_idx, idot, color, color_hi);
+ WM_gizmo_set_color(axis, color);
+ WM_gizmo_set_color_highlight(axis, color_hi);
+
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_C:
+ case MAN_AXIS_ROT_C:
+ case MAN_AXIS_SCALE_C:
+ case MAN_AXIS_ROT_T:
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
+ break;
+ }
+ }
+ MAN_ITER_AXES_END;
+}
+
+static bool WIDGETGROUP_gizmo_poll(const struct bContext *C, struct wmGizmoGroupType *gzgt)
+{
+ if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
+ return false;
+ }
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
+ return false;
+ }
+ return true;
+}
+
+void TRANSFORM_GGT_gizmo(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Transform Gizmo";
+ gzgt->idname = "TRANSFORM_GGT_gizmo";
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = WIDGETGROUP_gizmo_poll;
+ gzgt->setup = WIDGETGROUP_gizmo_setup;
+ gzgt->refresh = WIDGETGROUP_gizmo_refresh;
+ gzgt->message_subscribe = WIDGETGROUP_gizmo_message_subscribe;
+ gzgt->draw_prepare = WIDGETGROUP_gizmo_draw_prepare;
+
+ static const EnumPropertyItem rna_enum_gizmo_items[] = {
+ {SCE_GIZMO_SHOW_TRANSLATE, "TRANSLATE", 0, "Move", ""},
+ {SCE_GIZMO_SHOW_ROTATE, "ROTATE", 0, "Rotate", ""},
+ {SCE_GIZMO_SHOW_SCALE, "SCALE", 0, "Scale", ""},
+ {0, "NONE", 0, "None", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ RNA_def_enum(gzgt->srna, "drag_action", rna_enum_gizmo_items, SCE_GIZMO_SHOW_TRANSLATE, "Drag Action", "");
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Scale Cage Gizmo
+ * \{ */
+
+struct XFormCageWidgetGroup {
+ wmGizmo *gizmo;
+ /* Only for view orientation. */
+ struct {
+ float viewinv_m3[3][3];
+ } prev;
+};
+
+static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmGizmoGroupType *gzgt)
+{
+ if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
+ return false;
+ }
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
+ return false;
+ }
+ return true;
+}
+
+static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct XFormCageWidgetGroup *xgzgroup = MEM_mallocN(sizeof(struct XFormCageWidgetGroup), __func__);
+ const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true);
+ xgzgroup->gizmo = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL);
+ wmGizmo *gz = xgzgroup->gizmo;
+
+ RNA_enum_set(gz->ptr, "transform",
+ ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE |
+ ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE);
+
+ gz->color[0] = 1;
+ gz->color_hi[0] = 1;
+
+ gzgroup->customdata = xgzgroup;
+
+ {
+ wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
+ PointerRNA *ptr;
+
+ /* assign operator */
+ PropertyRNA *prop_release_confirm = NULL;
+ PropertyRNA *prop_constraint_axis = NULL;
+
+ int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
+ for (int x = 0; x < 3; x++) {
+ for (int y = 0; y < 3; y++) {
+ for (int z = 0; z < 3; z++) {
+ bool constraint[3] = {x != 1, y != 1, z != 1};
+ ptr = WM_gizmo_operator_set(gz, i, ot_resize, NULL);
+ if (prop_release_confirm == NULL) {
+ prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
+ prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
+ }
+ RNA_property_boolean_set(ptr, prop_release_confirm, true);
+ RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
+ i++;
+ }
+ }
+ }
+ }
+}
+
+static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ struct XFormCageWidgetGroup *xgzgroup = gzgroup->customdata;
+ wmGizmo *gz = xgzgroup->gizmo;
+
+ struct TransformBounds tbounds;
+
+ if ((ED_transform_calc_gizmo_stats(
+ C, &(struct TransformCalcParams) {
+ .use_local_axis = true,
+ }, &tbounds) == 0) ||
+ equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max))
+ {
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
+ else {
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+ WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
+
+ float dims[3];
+ sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min);
+ RNA_float_set_array(gz->ptr, "dimensions", dims);
+ mul_v3_fl(dims, 0.5f);
+
+ copy_m4_m3(gz->matrix_offset, rv3d->tw_axis_matrix);
+ mid_v3_v3v3(gz->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min);
+ mul_m3_v3(rv3d->tw_axis_matrix, gz->matrix_offset[3]);
+
+ float matrix_offset_global[4][4];
+ mul_m4_m4m4(matrix_offset_global, gz->matrix_space, gz->matrix_offset);
+
+ PropertyRNA *prop_center_override = NULL;
+ float center[3];
+ float center_global[3];
+ int i = ED_GIZMO_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
+ for (int x = 0; x < 3; x++) {
+ center[0] = (float)(1 - x) * dims[0];
+ for (int y = 0; y < 3; y++) {
+ center[1] = (float)(1 - y) * dims[1];
+ for (int z = 0; z < 3; z++) {
+ center[2] = (float)(1 - z) * dims[2];
+ struct wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, i);
+ if (prop_center_override == NULL) {
+ prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
+ }
+ mul_v3_m4v3(center_global, matrix_offset_global, center);
+ RNA_property_float_set_array(&gzop->ptr, prop_center_override, center_global);
+ i++;
+ }
+ }
+ }
+ }
+
+ /* Needed to test view orientation changes. */
+ copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
+}
+
+static void WIDGETGROUP_xform_cage_message_subscribe(
+ const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus)
+{
+ Scene *scene = CTX_data_scene(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, VIEW3D_GGT_xform_cage);
+}
+
+static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct XFormCageWidgetGroup *xgzgroup = gzgroup->customdata;
+ wmGizmo *gz = xgzgroup->gizmo;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ if (ob && ob->mode & OB_MODE_EDIT) {
+ copy_m4_m4(gz->matrix_space, ob->obmat);
+ }
+ else {
+ unit_m4(gz->matrix_space);
+ }
+
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ {
+ Scene *scene = CTX_data_scene(C);
+ switch (scene->orientation_type) {
+ case V3D_MANIP_VIEW:
+ {
+ float viewinv_m3[3][3];
+ copy_m3_m4(viewinv_m3, rv3d->viewinv);
+ if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
+ /* Take care calling refresh from draw_prepare,
+ * this should be OK because it's only adjusting the cage orientation. */
+ WIDGETGROUP_xform_cage_refresh(C, gzgroup);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Transform Cage";
+ gzgt->idname = "VIEW3D_GGT_xform_cage";
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = WIDGETGROUP_xform_cage_poll;
+ gzgt->setup = WIDGETGROUP_xform_cage_setup;
+ gzgt->refresh = WIDGETGROUP_xform_cage_refresh;
+ gzgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe;
+ gzgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Shear Gizmo
+ * \{ */
+
+struct XFormShearWidgetGroup {
+ wmGizmo *gizmo[3][2];
+ /* Only for view orientation. */
+ struct {
+ float viewinv_m3[3][3];
+ } prev;
+};
+
+static bool WIDGETGROUP_xform_shear_poll(const bContext *C, wmGizmoGroupType *gzgt)
+{
+ if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
+ return false;
+ }
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
+ return false;
+ }
+ return true;
+}
+
+static void WIDGETGROUP_xform_shear_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ struct XFormShearWidgetGroup *xgzgroup = MEM_mallocN(sizeof(struct XFormShearWidgetGroup), __func__);
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
+ wmOperatorType *ot_shear = WM_operatortype_find("TRANSFORM_OT_shear", true);
+
+ float axis_color[3][3];
+ for (int i = 0; i < 3; i++) {
+ UI_GetThemeColor3fv(TH_AXIS_X + i, axis_color[i]);
+ }
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 2; j++) {
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
+ const int i_ortho_a = (i + j + 1) % 3;
+ const int i_ortho_b = (i + (1 - j) + 1) % 3;
+ interp_v3_v3v3(gz->color, axis_color[i_ortho_a], axis_color[i_ortho_b], 0.75f);
+ gz->color[3] = 0.5f;
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_shear, NULL);
+ RNA_enum_set(ptr, "shear_axis", 0);
+ RNA_boolean_set(ptr, "release_confirm", 1);
+ xgzgroup->gizmo[i][j] = gz;
+ }
+ }
+
+ gzgroup->customdata = xgzgroup;
+}
+
+static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ struct XFormShearWidgetGroup *xgzgroup = gzgroup->customdata;
+ struct TransformBounds tbounds;
+
+ if (ED_transform_calc_gizmo_stats(
+ C, &(struct TransformCalcParams) {
+ .use_local_axis = false,
+ }, &tbounds) == 0)
+ {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 2; j++) {
+ wmGizmo *gz = xgzgroup->gizmo[i][j];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
+ }
+ }
+ }
+ else {
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 2; j++) {
+ wmGizmo *gz = xgzgroup->gizmo[i][j];
+ WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
+ WM_gizmo_set_flag(gz, WM_GIZMO_MOVE_CURSOR, true);
+
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
+ const int i_ortho_a = (i + j + 1) % 3;
+ const int i_ortho_b = (i + (1 - j) + 1) % 3;
+ WM_gizmo_set_matrix_rotation_from_yz_axis(gz, rv3d->twmat[i_ortho_a], rv3d->twmat[i]);
+ WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
+
+ float axis[3];
+ if (j == 0) {
+ copy_v3_v3(axis, tbounds.axis[i_ortho_b]);
+ }
+ else {
+ negate_v3_v3(axis, tbounds.axis[i_ortho_b]);
+ }
+ RNA_float_set_array(&gzop->ptr, "axis", axis);
+ RNA_float_set_array(&gzop->ptr, "axis_ortho", tbounds.axis[i_ortho_a]);
+ mul_v3_fl(gz->matrix_basis[0], 0.5f);
+ mul_v3_fl(gz->matrix_basis[1], 6.0f);
+ }
+ }
+ }
+
+ /* Needed to test view orientation changes. */
+ copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
+}
+
+static void WIDGETGROUP_xform_shear_message_subscribe(
+ const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus)
+{
+ Scene *scene = CTX_data_scene(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, VIEW3D_GGT_xform_shear);
+}
+
+static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct XFormShearWidgetGroup *xgzgroup = gzgroup->customdata;
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ {
+ Scene *scene = CTX_data_scene(C);
+ switch (scene->orientation_type) {
+ case V3D_MANIP_VIEW:
+ {
+ float viewinv_m3[3][3];
+ copy_m3_m4(viewinv_m3, rv3d->viewinv);
+ if (!equals_m3m3(viewinv_m3, xgzgroup->prev.viewinv_m3)) {
+ /* Take care calling refresh from draw_prepare,
+ * this should be OK because it's only adjusting the cage orientation. */
+ WIDGETGROUP_xform_shear_refresh(C, gzgroup);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Basic ordering for drawing only. */
+ {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
+ /* Since we have two pairs of each axis,
+ * bias the values so gizmos that are orthogonal to the view get priority.
+ * This means we never default to shearing along the view axis in the case of an overlap. */
+ float axis_order[3], axis_bias[3];
+ copy_v3_v3(axis_order, gz->matrix_basis[2]);
+ copy_v3_v3(axis_bias, gz->matrix_basis[1]);
+ if (dot_v3v3(axis_bias, rv3d->viewinv[2]) < 0.0f) {
+ negate_v3(axis_bias);
+ }
+ madd_v3_v3fl(axis_order, axis_bias, 0.01f);
+ gz->temp.f = dot_v3v3(rv3d->viewinv[2], axis_order);
+ }
+ BLI_listbase_sort(&gzgroup->gizmos, WM_gizmo_cmp_temp_fl_reverse);
+ }
+}
+
+void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Transform Shear";
+ gzgt->idname = "VIEW3D_GGT_xform_shear";
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = WIDGETGROUP_xform_shear_poll;
+ gzgt->setup = WIDGETGROUP_xform_shear_setup;
+ gzgt->refresh = WIDGETGROUP_xform_shear_refresh;
+ gzgt->message_subscribe = WIDGETGROUP_xform_shear_message_subscribe;
+ gzgt->draw_prepare = WIDGETGROUP_xform_shear_draw_prepare;
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
new file mode 100644
index 00000000000..1dc50f476fa
--- /dev/null
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -0,0 +1,472 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/transform/transform_gizmo_extrude_3d.c
+ * \ingroup edmesh
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_array_utils.h"
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_view3d.h"
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
+
+#include "UI_resources.h"
+
+#include "MEM_guardedalloc.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Gizmo
+ * \{ */
+
+enum {
+ EXTRUDE_AXIS_NORMAL = 0,
+ EXTRUDE_AXIS_XYZ = 1,
+};
+
+static const float extrude_button_scale = 0.15f;
+static const float extrude_button_offset_scale = 1.5f;
+static const float extrude_arrow_scale = 1.0f;
+static const float extrude_arrow_xyz_axis_scale = 1.0f;
+static const float extrude_arrow_normal_axis_scale = 1.0f;
+static const float extrude_dial_scale = 0.2;
+
+static const uchar shape_plus[] = {
+ 0x5f, 0xfb, 0x40, 0xee, 0x25, 0xda, 0x11, 0xbf, 0x4, 0xa0, 0x0, 0x80, 0x4, 0x5f, 0x11,
+ 0x40, 0x25, 0x25, 0x40, 0x11, 0x5f, 0x4, 0x7f, 0x0, 0xa0, 0x4, 0xbf, 0x11, 0xda, 0x25,
+ 0xee, 0x40, 0xfb, 0x5f, 0xff, 0x7f, 0xfb, 0xa0, 0xee, 0xbf, 0xda, 0xda, 0xbf, 0xee,
+ 0xa0, 0xfb, 0x80, 0xff, 0x6e, 0xd7, 0x92, 0xd7, 0x92, 0x90, 0xd8, 0x90, 0xd8, 0x6d,
+ 0x92, 0x6d, 0x92, 0x27, 0x6e, 0x27, 0x6e, 0x6d, 0x28, 0x6d, 0x28, 0x90, 0x6e,
+ 0x90, 0x6e, 0xd7, 0x80, 0xff, 0x5f, 0xfb, 0x5f, 0xfb,
+};
+
+typedef struct GizmoExtrudeGroup {
+
+ /* XYZ & normal. */
+ wmGizmo *invoke_xyz_no[4];
+ /* Constrained & unconstrained (arrow & circle). */
+ wmGizmo *adjust[2];
+ int adjust_axis;
+
+ /* Copied from the transform operator,
+ * use to redo with the same settings. */
+ struct {
+ float constraint_matrix[3][3];
+ bool constraint_axis[3];
+ float value[4];
+ } redo_xform;
+
+ /* Depends on object type. */
+ int normal_axis;
+
+ struct {
+ float normal_mat3[3][3]; /* use Z axis for normal. */
+ int orientation_type;
+ } data;
+
+ wmOperatorType *ot_extrude;
+ PropertyRNA *gzgt_axis_type_prop;
+} GizmoExtrudeGroup;
+
+static void gizmo_mesh_extrude_orientation_matrix_set(
+ struct GizmoExtrudeGroup *ggd, const float mat[3][3])
+{
+ for (int i = 0; i < 3; i++) {
+ mul_v3_v3fl(
+ ggd->invoke_xyz_no[i]->matrix_offset[3],
+ mat[i],
+ (extrude_arrow_xyz_axis_scale * extrude_button_offset_scale) / extrude_button_scale);
+ }
+}
+
+static void gizmo_mesh_extrude_orientation_matrix_set_for_adjust(
+ struct GizmoExtrudeGroup *ggd, const float mat[3][3])
+{
+ /* Set orientation without location. */
+ for (int j = 0; j < 3; j++) {
+ copy_v3_v3(ggd->adjust[0]->matrix_basis[j], mat[j]);
+ }
+ /* nop when (i == 2). */
+ swap_v3_v3(ggd->adjust[0]->matrix_basis[ggd->adjust_axis], ggd->adjust[0]->matrix_basis[2]);
+}
+
+static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ struct GizmoExtrudeGroup *ggd = MEM_callocN(sizeof(GizmoExtrudeGroup), __func__);
+ gzgroup->customdata = ggd;
+
+ const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
+ const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_button_2d", true);
+ const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
+
+ ggd->adjust[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
+ ggd->adjust[1] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL);
+ for (int i = 0; i < 4; i++) {
+ ggd->invoke_xyz_no[i] = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
+ ggd->invoke_xyz_no[i]->flag |= WM_GIZMO_DRAW_OFFSET_SCALE;
+ }
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(ggd->invoke_xyz_no[3]->ptr, "shape");
+ for (int i = 0; i < 4; i++) {
+ RNA_property_string_set_bytes(
+ ggd->invoke_xyz_no[i]->ptr, prop,
+ (const char *)shape_plus, ARRAY_SIZE(shape_plus));
+ }
+ }
+
+ {
+ const Object *obedit = CTX_data_edit_object(C);
+ const char *op_idname = NULL;
+ if (obedit->type == OB_MESH) {
+ op_idname = "MESH_OT_extrude_context_move";
+ ggd->normal_axis = 2;
+ }
+ else if (obedit->type == OB_ARMATURE) {
+ op_idname = "ARMATURE_OT_extrude_move";
+ ggd->normal_axis = 1;
+ }
+ else if (obedit->type == OB_CURVE) {
+ op_idname = "CURVE_OT_extrude_move";
+ ggd->normal_axis = 2;
+ }
+ else {
+ BLI_assert(0);
+ }
+ ggd->ot_extrude = WM_operatortype_find(op_idname, true);
+ ggd->gzgt_axis_type_prop = RNA_struct_type_find_property(gzgroup->type->srna, "axis_type");
+ }
+
+ for (int i = 0; i < 3; i++) {
+ UI_GetThemeColor3fv(TH_AXIS_X + i, ggd->invoke_xyz_no[i]->color);
+ }
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->invoke_xyz_no[3]->color);
+ for (int i = 0; i < 2; i++) {
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, ggd->adjust[i]->color);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ WM_gizmo_set_scale(ggd->invoke_xyz_no[i], extrude_button_scale);
+ }
+ WM_gizmo_set_scale(ggd->adjust[0], extrude_arrow_scale);
+ WM_gizmo_set_scale(ggd->adjust[1], extrude_dial_scale);
+ ggd->adjust[1]->line_width = 2.0f;
+
+ /* XYZ & normal axis extrude. */
+ for (int i = 0; i < 4; i++) {
+ PointerRNA *ptr = WM_gizmo_operator_set(ggd->invoke_xyz_no[i], 0, ggd->ot_extrude, NULL);
+ {
+ bool constraint[3] = {0, 0, 0};
+ constraint[(i < 3) ? i : ggd->normal_axis] = true;
+ PointerRNA macroptr = RNA_pointer_get(ptr, "TRANSFORM_OT_translate");
+ RNA_boolean_set(&macroptr, "release_confirm", true);
+ RNA_boolean_set_array(&macroptr, "constraint_axis", constraint);
+ }
+ }
+
+ /* Adjust extrude. */
+ for (int i = 0; i < 2; i++) {
+ wmGizmo *gz = ggd->adjust[i];
+ PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ggd->ot_extrude, NULL);
+ PointerRNA macroptr = RNA_pointer_get(ptr, "TRANSFORM_OT_translate");
+ RNA_boolean_set(&macroptr, "release_confirm", true);
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
+ gzop->is_redo = true;
+ }
+}
+
+static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoExtrudeGroup *ggd = gzgroup->customdata;
+
+ for (int i = 0; i < 4; i++) {
+ WM_gizmo_set_flag(ggd->invoke_xyz_no[i], WM_GIZMO_HIDDEN, true);
+ }
+ for (int i = 0; i < 2; i++) {
+ WM_gizmo_set_flag(ggd->adjust[i], WM_GIZMO_HIDDEN, true);
+ }
+
+ if (G.moving) {
+ return;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+
+ int axis_type;
+ {
+ PointerRNA ptr;
+ bToolRef *tref = WM_toolsystem_ref_from_context((bContext *)C);
+ WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &ptr);
+ axis_type = RNA_property_enum_get(&ptr, ggd->gzgt_axis_type_prop);
+ }
+
+ ggd->data.orientation_type = scene->orientation_type;
+ const bool use_normal = (
+ (ggd->data.orientation_type != V3D_MANIP_NORMAL) ||
+ (axis_type == EXTRUDE_AXIS_NORMAL));
+ const int axis_len_used = use_normal ? 4 : 3;
+
+ struct TransformBounds tbounds;
+
+ if (use_normal) {
+ struct TransformBounds tbounds_normal;
+ if (!ED_transform_calc_gizmo_stats(
+ C, &(struct TransformCalcParams){
+ .orientation_type = V3D_MANIP_NORMAL + 1,
+ }, &tbounds_normal))
+ {
+ unit_m3(tbounds_normal.axis);
+ }
+ copy_m3_m3(ggd->data.normal_mat3, tbounds_normal.axis);
+ }
+
+ /* TODO(campbell): run second since this modifies the 3D view, it should not. */
+ if (!ED_transform_calc_gizmo_stats(
+ C, &(struct TransformCalcParams){
+ .orientation_type = ggd->data.orientation_type + 1,
+ }, &tbounds))
+ {
+ return;
+ }
+
+ /* Main axis is normal. */
+ if (!use_normal) {
+ copy_m3_m3(ggd->data.normal_mat3, tbounds.axis);
+ }
+
+ /* Offset the add icon. */
+ mul_v3_v3fl(
+ ggd->invoke_xyz_no[3]->matrix_offset[3],
+ ggd->data.normal_mat3[ggd->normal_axis],
+ (extrude_arrow_normal_axis_scale * extrude_button_offset_scale) / extrude_button_scale);
+
+ /* Adjust current operator. */
+ /* Don't use 'WM_operator_last_redo' because selection actions will be ignored. */
+ wmOperator *op = CTX_wm_manager(C)->operators.last;
+ bool has_redo = (op && op->type == ggd->ot_extrude);
+ wmOperator *op_xform = has_redo ? op->macro.last : NULL;
+
+ bool adjust_is_flip = false;
+ wmGizmo *gz_adjust = NULL;
+
+ if (has_redo) {
+ gz_adjust = ggd->adjust[1];
+ /* We can't access this from 'ot->last_properties'
+ * because some properties use skip-save. */
+ RNA_float_get_array(op_xform->ptr, "constraint_matrix", &ggd->redo_xform.constraint_matrix[0][0]);
+ RNA_boolean_get_array(op_xform->ptr, "constraint_axis", ggd->redo_xform.constraint_axis);
+ RNA_float_get_array(op_xform->ptr, "value", ggd->redo_xform.value);
+
+ /* Set properties for redo. */
+ for (int i = 0; i < 3; i++) {
+ if (ggd->redo_xform.constraint_axis[i]) {
+ adjust_is_flip = ggd->redo_xform.value[i] < 0.0f;
+ ggd->adjust_axis = i;
+ gz_adjust = ggd->adjust[0];
+ break;
+ }
+ }
+ }
+
+ /* Needed for normal orientation. */
+ gizmo_mesh_extrude_orientation_matrix_set(ggd, tbounds.axis);
+
+ /* Location. */
+ for (int i = 0; i < axis_len_used; i++) {
+ WM_gizmo_set_matrix_location(ggd->invoke_xyz_no[i], tbounds.center);
+ }
+ /* Un-hide. */
+ for (int i = 0; i < axis_len_used; i++) {
+ WM_gizmo_set_flag(ggd->invoke_xyz_no[i], WM_GIZMO_HIDDEN, false);
+ }
+
+ if (has_redo) {
+ if (gz_adjust == ggd->adjust[0]) {
+ gizmo_mesh_extrude_orientation_matrix_set_for_adjust(ggd, ggd->redo_xform.constraint_matrix);
+ if (adjust_is_flip) {
+ negate_v3(ggd->adjust[0]->matrix_basis[2]);
+ }
+ }
+ WM_gizmo_set_matrix_location(gz_adjust, tbounds.center);
+ WM_gizmo_set_flag(gz_adjust, WM_GIZMO_HIDDEN, false);
+ }
+
+ /* Redo with current settings. */
+ if (has_redo) {
+ for (int i = 0; i < 4; i++) {
+ RNA_enum_set(
+ ggd->invoke_xyz_no[i]->ptr,
+ "draw_options",
+ ((gz_adjust == ggd->adjust[0]) &&
+ dot_v3v3(ggd->adjust[0]->matrix_basis[2],
+ ggd->invoke_xyz_no[i]->matrix_offset[3]) > 0.98f) ? 0 : ED_GIZMO_BUTTON_SHOW_HELPLINE);
+ }
+ }
+ else {
+ for (int i = 0; i < 4; i++) {
+ RNA_enum_set(ggd->invoke_xyz_no[i]->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_HELPLINE);
+ }
+ }
+
+ /* TODO: skip calculating axis which wont be used (above). */
+ switch (axis_type) {
+ case EXTRUDE_AXIS_NORMAL:
+ for (int i = 0; i < 3; i++) {
+ WM_gizmo_set_flag(ggd->invoke_xyz_no[i], WM_GIZMO_HIDDEN, true);
+ }
+ break;
+ case EXTRUDE_AXIS_XYZ:
+ WM_gizmo_set_flag(ggd->invoke_xyz_no[3], WM_GIZMO_HIDDEN, true);
+ break;
+ }
+}
+
+static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ GizmoExtrudeGroup *ggd = gzgroup->customdata;
+ switch (ggd->data.orientation_type) {
+ case V3D_MANIP_VIEW:
+ {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ float mat[3][3];
+ copy_m3_m4(mat, rv3d->viewinv);
+ normalize_m3(mat);
+ gizmo_mesh_extrude_orientation_matrix_set(ggd, mat);
+ break;
+ }
+ }
+
+ /* Basic ordering for drawing only. */
+ {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
+ gz->temp.f = dot_v3v3(rv3d->viewinv[2], gz->matrix_offset[3]);
+ }
+ BLI_listbase_sort(&gzgroup->gizmos, WM_gizmo_cmp_temp_fl_reverse);
+
+ if ((ggd->adjust[1]->flag & WM_GIZMO_HIDDEN) == 0) {
+ copy_v3_v3(ggd->adjust[1]->matrix_basis[0], rv3d->viewinv[0]);
+ copy_v3_v3(ggd->adjust[1]->matrix_basis[1], rv3d->viewinv[1]);
+ copy_v3_v3(ggd->adjust[1]->matrix_basis[2], rv3d->viewinv[2]);
+ }
+ }
+}
+
+static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C), wmGizmoGroup *gzgroup, wmGizmo *gz)
+{
+ GizmoExtrudeGroup *ggd = gzgroup->customdata;
+ if (ELEM(gz, ggd->adjust[0], ggd->adjust[1])) {
+ /* Set properties for redo. */
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
+ PointerRNA macroptr = RNA_pointer_get(&gzop->ptr, "TRANSFORM_OT_translate");
+ if (gz == ggd->adjust[0]) {
+ RNA_float_set_array(&macroptr, "constraint_matrix", &ggd->redo_xform.constraint_matrix[0][0]);
+ RNA_boolean_set_array(&macroptr, "constraint_axis", ggd->redo_xform.constraint_axis);
+ }
+ RNA_float_set_array(&macroptr, "value", ggd->redo_xform.value);
+ }
+ else {
+ /* Workaround for extrude action modifying normals. */
+ const int i = BLI_array_findindex(ggd->invoke_xyz_no, ARRAY_SIZE(ggd->invoke_xyz_no), &gz);
+ BLI_assert(i != -1);
+ bool use_normal_matrix = false;
+ if (i == 3) {
+ use_normal_matrix = true;
+ }
+ else if (ggd->data.orientation_type == V3D_MANIP_NORMAL) {
+ use_normal_matrix = true;
+ }
+ if (use_normal_matrix) {
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0);
+ PointerRNA macroptr = RNA_pointer_get(&gzop->ptr, "TRANSFORM_OT_translate");
+ RNA_float_set_array(&macroptr, "constraint_matrix", &ggd->data.normal_mat3[0][0]);
+ }
+ }
+}
+
+static void gizmo_mesh_extrude_message_subscribe(
+ const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus)
+{
+ GizmoExtrudeGroup *ggd = gzgroup->customdata;
+ ARegion *ar = CTX_wm_region(C);
+
+ /* Subscribe to view properties */
+ wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
+ .owner = ar,
+ .user_data = gzgroup->parent_gzmap,
+ .notify = WM_gizmo_do_msg_notify_tag_refresh,
+ };
+
+ {
+ WM_msg_subscribe_rna_anon_prop(mbus, Scene, transform_orientation, &msg_sub_value_gz_tag_refresh);
+ }
+
+
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &(const wmMsgParams_RNA){
+ .ptr = (PointerRNA){.type = gzgroup->type->srna},
+ .prop = ggd->gzgt_axis_type_prop,
+ },
+ &msg_sub_value_gz_tag_refresh, __func__);
+}
+
+void VIEW3D_GGT_xform_extrude(struct wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "3D View Extrude";
+ gzgt->idname = "VIEW3D_GGT_xform_extrude";
+
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
+ gzgt->setup = gizmo_mesh_extrude_setup;
+ gzgt->refresh = gizmo_mesh_extrude_refresh;
+ gzgt->draw_prepare = gizmo_mesh_extrude_draw_prepare;
+ gzgt->invoke_prepare = gizmo_mesh_extrude_invoke_prepare;
+ gzgt->message_subscribe = gizmo_mesh_extrude_message_subscribe;
+
+ static const EnumPropertyItem axis_type_items[] = {
+ {EXTRUDE_AXIS_NORMAL, "NORMAL", 0, "Normal", "Only show normal axis"},
+ {EXTRUDE_AXIS_XYZ, "XYZ", 0, "XYZ", "Follow scene orientation"},
+ {0, NULL, 0, NULL, NULL}
+ };
+ RNA_def_enum(gzgt->srna, "axis_type", axis_type_items, 0, "Axis Type", "");
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index b60c8bf47f6..2721bccb7de 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -30,10 +30,13 @@
#include "DNA_screen_types.h"
+#include "BKE_context.h"
+
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "WM_types.h"
+#include "WM_api.h"
#include "transform.h"
@@ -134,6 +137,18 @@ void setCustomPoints(TransInfo *UNUSED(t), MouseInput *mi, const int mval_start[
data[3] = mval_end[1];
}
+void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2])
+{
+ BLI_ASSERT_UNIT_V2(dir);
+ const int win_axis = t->ar ? ((abs((int)(t->ar->winx * dir[0])) + abs((int)(t->ar->winy * dir[1]))) / 2) : 1;
+ const int mval_start[2] = {
+ mi->imval[0] + dir[0] * win_axis,
+ mi->imval[1] + dir[1] * win_axis,
+ };
+ const int mval_end[2] = {mi->imval[0], mi->imval[1]};
+ setCustomPoints(t, mi, mval_start, mval_end);
+}
+
static void InputCustomRatioFlip(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3])
{
double length;
@@ -329,11 +344,11 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
break;
case INPUT_CUSTOM_RATIO:
mi->apply = InputCustomRatio;
- t->helpline = HLP_NONE;
+ t->helpline = HLP_CARROW;
break;
case INPUT_CUSTOM_RATIO_FLIP:
mi->apply = InputCustomRatioFlip;
- t->helpline = HLP_NONE;
+ t->helpline = HLP_CARROW;
break;
case INPUT_NONE:
default:
@@ -341,14 +356,43 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
break;
}
+ /* setup for the mouse cursor: either set a custom one,
+ * or hide it if it will be drawn with the helpline */
+ wmWindow *win = CTX_wm_window(t->context);
+ switch (t->helpline) {
+ case HLP_NONE:
+ /* INPUT_VECTOR, INPUT_CUSTOM_RATIO, INPUT_CUSTOM_RATIO_FLIP */
+ if (t->flag & T_MODAL) {
+ t->flag |= T_MODAL_CURSOR_SET;
+ WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ }
+ break;
+ case HLP_SPRING:
+ case HLP_ANGLE:
+ case HLP_TRACKBALL:
+ case HLP_HARROW:
+ case HLP_VARROW:
+ case HLP_CARROW:
+ if (t->flag & T_MODAL) {
+ t->flag |= T_MODAL_CURSOR_SET;
+ WM_cursor_modal_set(win, CURSOR_NONE);
+ }
+ break;
+ default:
+ break;
+ }
+
/* if we've allocated new data, free the old data
* less hassle then checking before every alloc above */
if (mi_data_prev && (mi_data_prev != mi->data)) {
MEM_freeN(mi_data_prev);
}
- /* bootstrap mouse input with initial values */
- applyMouseInput(t, mi, mi->imval, t->values);
+ /* Don't write into the values when non-modal because they are already set from operator redo values. */
+ if (t->flag & T_MODAL) {
+ /* bootstrap mouse input with initial values */
+ applyMouseInput(t, mi, mi->imval, t->values);
+ }
}
void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float values[3]))
@@ -391,6 +435,17 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp
mi->apply(t, mi, mval_db, output);
}
+ if (!is_zero_v3(t->values_modal_offset)) {
+ float values_ofs[3];
+ if (t->con.mode & CON_APPLY) {
+ mul_v3_m3v3(values_ofs, t->spacemtx, t->values_modal_offset);
+ }
+ else {
+ copy_v3_v3(values_ofs, t->values_modal_offset);
+ }
+ add_v3_v3(t->values, values_ofs);
+ }
+
if (mi->post) {
mi->post(t, output);
}
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
deleted file mode 100644
index 79785f982c8..00000000000
--- a/source/blender/editors/transform/transform_manipulator.c
+++ /dev/null
@@ -1,1982 +0,0 @@
-/*
- * ***** 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) 2005 Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/transform/transform_manipulator.c
- * \ingroup edtransform
- */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
-#include "DNA_armature_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_view3d_types.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "RNA_access.h"
-
-#include "BKE_action.h"
-#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_particle.h"
-#include "BKE_pointcache.h"
-#include "BKE_editmesh.h"
-#include "BKE_lattice.h"
-#include "BKE_gpencil.h"
-
-#include "BIF_gl.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_armature.h"
-#include "ED_curve.h"
-#include "ED_particle.h"
-#include "ED_view3d.h"
-#include "ED_gpencil.h"
-
-#include "UI_resources.h"
-
-/* local module include */
-#include "transform.h"
-
-#include "GPU_select.h"
-
-/* return codes for select, and drawing flags */
-
-#define MAN_TRANS_X (1 << 0)
-#define MAN_TRANS_Y (1 << 1)
-#define MAN_TRANS_Z (1 << 2)
-#define MAN_TRANS_C (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z)
-
-#define MAN_ROT_X (1 << 3)
-#define MAN_ROT_Y (1 << 4)
-#define MAN_ROT_Z (1 << 5)
-#define MAN_ROT_V (1 << 6)
-#define MAN_ROT_T (1 << 7)
-#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z | MAN_ROT_V | MAN_ROT_T)
-
-#define MAN_SCALE_X (1 << 8)
-#define MAN_SCALE_Y (1 << 9)
-#define MAN_SCALE_Z (1 << 10)
-#define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z)
-
-/* color codes */
-
-#define MAN_RGB 0
-#define MAN_GHOST 1
-#define MAN_MOVECOL 2
-
-/* threshold for testing view aligned manipulator axis */
-#define TW_AXIS_DOT_MIN 0.02f
-#define TW_AXIS_DOT_MAX 0.1f
-
-struct TransformBounds {
- float center[3]; /* Center for transform widget. */
- float min[3], max[3]; /* Boundbox of selection for transform widget. */
-};
-
-/* transform widget center calc helper for below */
-static void calc_tw_center(struct TransformBounds *tbounds, const float co[3])
-{
- minmax_v3v3_v3(tbounds->min, tbounds->max, co);
- add_v3_v3(tbounds->center, co);
-}
-
-static void protectflag_to_drawflags(short protectflag, short *drawflags)
-{
- if (protectflag & OB_LOCK_LOCX)
- *drawflags &= ~MAN_TRANS_X;
- if (protectflag & OB_LOCK_LOCY)
- *drawflags &= ~MAN_TRANS_Y;
- if (protectflag & OB_LOCK_LOCZ)
- *drawflags &= ~MAN_TRANS_Z;
-
- if (protectflag & OB_LOCK_ROTX)
- *drawflags &= ~MAN_ROT_X;
- if (protectflag & OB_LOCK_ROTY)
- *drawflags &= ~MAN_ROT_Y;
- if (protectflag & OB_LOCK_ROTZ)
- *drawflags &= ~MAN_ROT_Z;
-
- if (protectflag & OB_LOCK_SCALEX)
- *drawflags &= ~MAN_SCALE_X;
- if (protectflag & OB_LOCK_SCALEY)
- *drawflags &= ~MAN_SCALE_Y;
- if (protectflag & OB_LOCK_SCALEZ)
- *drawflags &= ~MAN_SCALE_Z;
-}
-
-/* for pose mode */
-static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
-{
- protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
-}
-
-/* for editmode*/
-static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo)
-{
- if (ebo->flag & BONE_EDITMODE_LOCKED) {
- protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
- }
-}
-
-/* could move into BLI_math however this is only useful for display/editing purposes */
-static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
-{
- /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */
-
- float cross_vec[3];
- float quat[4];
-
- /* this is an un-scientific method to get a vector to cross with
- * XYZ intentionally YZX */
- cross_vec[0] = axis[1];
- cross_vec[1] = axis[2];
- cross_vec[2] = axis[0];
-
- /* X-axis */
- cross_v3_v3v3(gmat[0], cross_vec, axis);
- normalize_v3(gmat[0]);
- axis_angle_to_quat(quat, axis, angle);
- mul_qt_v3(quat, gmat[0]);
-
- /* Y-axis */
- axis_angle_to_quat(quat, axis, M_PI_2);
- copy_v3_v3(gmat[1], gmat[0]);
- mul_qt_v3(quat, gmat[1]);
-
- /* Z-axis */
- copy_v3_v3(gmat[2], axis);
-
- normalize_m3(gmat);
-}
-
-
-static bool test_rotmode_euler(short rotmode)
-{
- return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
-}
-
-bool gimbal_axis(Object *ob, float gmat[3][3])
-{
- if (ob->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
-
- if (pchan) {
- float mat[3][3], tmat[3][3], obmat[3][3];
- if (test_rotmode_euler(pchan->rotmode)) {
- eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
- }
- else { /* quat */
- return 0;
- }
-
-
- /* apply bone transformation */
- mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
-
- if (pchan->parent) {
- float parent_mat[3][3];
-
- copy_m3_m4(parent_mat, pchan->parent->pose_mat);
- mul_m3_m3m3(mat, parent_mat, tmat);
-
- /* needed if object transformation isn't identity */
- copy_m3_m4(obmat, ob->obmat);
- mul_m3_m3m3(gmat, obmat, mat);
- }
- else {
- /* needed if object transformation isn't identity */
- copy_m3_m4(obmat, ob->obmat);
- mul_m3_m3m3(gmat, obmat, tmat);
- }
-
- normalize_m3(gmat);
- return 1;
- }
- }
- else {
- if (test_rotmode_euler(ob->rotmode)) {
- eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
- }
- else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
- }
- else { /* quat */
- return 0;
- }
-
- if (ob->parent) {
- float parent_mat[3][3];
- copy_m3_m4(parent_mat, ob->parent->obmat);
- normalize_m3(parent_mat);
- mul_m3_m3m3(gmat, parent_mat, gmat);
- }
- return 1;
- }
-
- return 0;
-}
-
-
-/* centroid, boundbox, of selection */
-/* returns total items selected */
-static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbounds)
-{
- Main *bmain = CTX_data_main(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- View3D *v3d = sa->spacedata.first;
- RegionView3D *rv3d = ar->regiondata;
- Base *base;
- Object *ob = OBACT;
- bGPdata *gpd = CTX_data_gpencil_data(C);
- const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
- int a, totsel = 0;
-
- /* transform widget matrix */
- unit_m4(rv3d->twmat);
-
- rv3d->twdrawflag = 0xFFFF;
-
- /* transform widget centroid/center */
- INIT_MINMAX(tbounds->min, tbounds->max);
- zero_v3(tbounds->center);
-
- if (is_gp_edit) {
- 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(tbounds, &pt->x);
- totsel++;
- }
- else {
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- calc_tw_center(tbounds, fpt);
- totsel++;
- }
- }
- }
- }
- }
- }
- }
-
-
- /* selection center */
- if (totsel) {
- mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
- }
- }
- else if (obedit) {
- ob = obedit;
- if ((ob->lay & v3d->lay) == 0) return 0;
-
- if (obedit->type == OB_MESH) {
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMEditSelection ese;
- float vec[3] = {0, 0, 0};
-
- /* USE LAST SELECTE WITH ACTIVE */
- if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
- BM_editselection_center(&ese, vec);
- calc_tw_center(tbounds, vec);
- totsel = 1;
- }
- else {
- BMesh *bm = em->bm;
- BMVert *eve;
-
- BMIter iter;
-
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- totsel++;
- calc_tw_center(tbounds, eve->co);
- }
- }
- }
- }
- } /* end editmesh */
- else if (obedit->type == OB_ARMATURE) {
- bArmature *arm = obedit->data;
- EditBone *ebo;
-
- if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
- /* doesn't check selection or visibility intentionally */
- if (ebo->flag & BONE_TIPSEL) {
- calc_tw_center(tbounds, ebo->tail);
- totsel++;
- }
- if ((ebo->flag & BONE_ROOTSEL) ||
- ((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */
- {
- calc_tw_center(tbounds, ebo->head);
- totsel++;
- }
- protectflag_to_drawflags_ebone(rv3d, ebo);
- }
- else {
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- if (EBONE_VISIBLE(arm, ebo)) {
- if (ebo->flag & BONE_TIPSEL) {
- calc_tw_center(tbounds, ebo->tail);
- totsel++;
- }
- if ((ebo->flag & BONE_ROOTSEL) &&
- /* don't include same point multiple times */
- ((ebo->flag & BONE_CONNECTED) &&
- (ebo->parent != NULL) &&
- (ebo->parent->flag & BONE_TIPSEL) &&
- EBONE_VISIBLE(arm, ebo->parent)) == 0)
- {
- calc_tw_center(tbounds, ebo->head);
- totsel++;
- }
- if (ebo->flag & BONE_SELECTED) {
- protectflag_to_drawflags_ebone(rv3d, ebo);
- }
- }
- }
- }
- }
- else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
- Curve *cu = obedit->data;
- float center[3];
-
- if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) {
- calc_tw_center(tbounds, center);
- totsel++;
- }
- else {
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- ListBase *nurbs = BKE_curve_editNurbs_get(cu);
-
- nu = nurbs->first;
- while (nu) {
- if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
- while (a--) {
- /* exceptions
- * if handles are hidden then only check the center points.
- * If the center knot is selected then only use this as the center point.
- */
- if (cu->drawflag & CU_HIDE_HANDLES) {
- if (bezt->f2 & SELECT) {
- calc_tw_center(tbounds, bezt->vec[1]);
- totsel++;
- }
- }
- else if (bezt->f2 & SELECT) {
- calc_tw_center(tbounds, bezt->vec[1]);
- totsel++;
- }
- else {
- if (bezt->f1 & SELECT) {
- calc_tw_center(
- tbounds,
- bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
- totsel++;
- }
- if (bezt->f3 & SELECT) {
- calc_tw_center(
- tbounds,
- bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
- totsel++;
- }
- }
- bezt++;
- }
- }
- else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
- while (a--) {
- if (bp->f1 & SELECT) {
- calc_tw_center(tbounds, bp->vec);
- totsel++;
- }
- bp++;
- }
- }
- nu = nu->next;
- }
- }
- }
- else if (obedit->type == OB_MBALL) {
- MetaBall *mb = (MetaBall *)obedit->data;
- MetaElem *ml;
-
- if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
- calc_tw_center(tbounds, &ml->x);
- totsel++;
- }
- else {
- for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (ml->flag & SELECT) {
- calc_tw_center(tbounds, &ml->x);
- totsel++;
- }
- }
- }
- }
- else if (obedit->type == OB_LATTICE) {
- Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
- BPoint *bp;
-
- if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
- calc_tw_center(tbounds, bp->vec);
- totsel++;
- }
- else {
- bp = lt->def;
- a = lt->pntsu * lt->pntsv * lt->pntsw;
- while (a--) {
- if (bp->f1 & SELECT) {
- calc_tw_center(tbounds, bp->vec);
- totsel++;
- }
- bp++;
- }
- }
- }
-
- /* selection center */
- if (totsel) {
- mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
- mul_m4_v3(obedit->obmat, tbounds->center);
- mul_m4_v3(obedit->obmat, tbounds->min);
- mul_m4_v3(obedit->obmat, tbounds->max);
- }
- }
- else if (ob && (ob->mode & OB_MODE_POSE)) {
- bPoseChannel *pchan;
- int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
- bool ok = false;
-
- if ((ob->lay & v3d->lay) == 0) return 0;
-
- if ((v3d->around == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
- /* doesn't check selection or visibility intentionally */
- Bone *bone = pchan->bone;
- if (bone) {
- calc_tw_center(tbounds, pchan->pose_head);
- protectflag_to_drawflags_pchan(rv3d, pchan);
- totsel = 1;
- ok = true;
- }
- }
- else {
- totsel = count_set_pose_transflags(&mode, 0, ob);
-
- if (totsel) {
- /* use channels to get stats */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- Bone *bone = pchan->bone;
- if (bone && (bone->flag & BONE_TRANSFORM)) {
- calc_tw_center(tbounds, pchan->pose_head);
- protectflag_to_drawflags_pchan(rv3d, pchan);
- }
- }
- ok = true;
- }
- }
-
- if (ok) {
- mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
- mul_m4_v3(ob->obmat, tbounds->center);
- mul_m4_v3(ob->obmat, tbounds->min);
- mul_m4_v3(ob->obmat, tbounds->max);
- }
- }
- else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
- /* pass */
- }
- else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
- PTCacheEditPoint *point;
- PTCacheEditKey *ek;
- int k;
-
- if (edit) {
- point = edit->points;
- for (a = 0; a < edit->totpoint; a++, point++) {
- if (point->flag & PEP_HIDE) continue;
-
- for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
- if (ek->flag & PEK_SELECT) {
- calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
- totsel++;
- }
- }
- }
-
- /* selection center */
- if (totsel)
- mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
- }
- }
- else {
-
- /* we need the one selected object, if its not active */
- ob = OBACT;
- if (ob && !(ob->flag & SELECT)) ob = NULL;
-
- for (base = scene->base.first; base; base = base->next) {
- if (TESTBASELIB(v3d, base)) {
- if (ob == NULL)
- ob = base->object;
- calc_tw_center(tbounds, base->object->obmat[3]);
- protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
- totsel++;
- }
- }
-
- /* selection center */
- if (totsel) {
- mul_v3_fl(tbounds->center, 1.0f / (float)totsel);
- }
- }
-
- /* global, local or normal orientation? */
- if (ob && totsel && !is_gp_edit) {
-
- switch (v3d->twmode) {
-
- case V3D_MANIP_GLOBAL:
- {
- break; /* nothing to do */
- }
- case V3D_MANIP_GIMBAL:
- {
- float mat[3][3];
- if (gimbal_axis(ob, mat)) {
- copy_m4_m3(rv3d->twmat, mat);
- break;
- }
- /* if not gimbal, fall through to normal */
- ATTR_FALLTHROUGH;
- }
- case V3D_MANIP_NORMAL:
- {
- if (obedit || ob->mode & OB_MODE_POSE) {
- float mat[3][3];
- ED_getTransformOrientationMatrix(C, mat, v3d->around);
- copy_m4_m3(rv3d->twmat, mat);
- break;
- }
- /* no break we define 'normal' as 'local' in Object mode */
- ATTR_FALLTHROUGH;
- }
- case V3D_MANIP_LOCAL:
- {
- if (ob->mode & OB_MODE_POSE) {
- /* each bone moves on its own local axis, but to avoid confusion,
- * use the active pones axis for display [#33575], this works as expected on a single bone
- * and users who select many bones will understand whats going on and what local means
- * when they start transforming */
- float mat[3][3];
- ED_getTransformOrientationMatrix(C, mat, v3d->around);
- copy_m4_m3(rv3d->twmat, mat);
- break;
- }
- copy_m4_m4(rv3d->twmat, ob->obmat);
- normalize_m4(rv3d->twmat);
- break;
- }
- case V3D_MANIP_VIEW:
- {
- float mat[3][3];
- copy_m3_m4(mat, rv3d->viewinv);
- normalize_m3(mat);
- copy_m4_m3(rv3d->twmat, mat);
- break;
- }
- default: /* V3D_MANIP_CUSTOM */
- {
- float mat[3][3];
- if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) {
- copy_m4_m3(rv3d->twmat, mat);
- }
- break;
- }
- }
-
- }
-
- return totsel;
-}
-
-/* don't draw axis perpendicular to the view */
-static void test_manipulator_axis(const bContext *C)
-{
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- float view_vec[3], axis_vec[3];
- float idot;
- int i;
-
- const int twdrawflag_axis[3] = {
- (MAN_TRANS_X | MAN_SCALE_X),
- (MAN_TRANS_Y | MAN_SCALE_Y),
- (MAN_TRANS_Z | MAN_SCALE_Z)};
-
- ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
-
- for (i = 0; i < 3; i++) {
- normalize_v3_v3(axis_vec, rv3d->twmat[i]);
- rv3d->tw_idot[i] = idot = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
- if (idot < TW_AXIS_DOT_MIN) {
- rv3d->twdrawflag &= ~twdrawflag_axis[i];
- }
- }
-}
-
-
-/* ******************** DRAWING STUFFIES *********** */
-
-static float screen_aligned(RegionView3D *rv3d, float mat[4][4])
-{
- glTranslate3fv(mat[3]);
-
- /* sets view screen aligned */
- glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
-
- return len_v3(mat[0]); /* draw scale */
-}
-
-
-/**
- * \param radring: Radius of doughnut rings.
- * \param radhole: Radius hole.
- * \param start: Starting segment (based on \a nrings).
- * \param end: End segment.
- * \param nsides: Number of points in ring.
- * \param nrings: Number of rings.
- */
-static void partial_doughnut(float radring, float radhole, int start, int end, int nsides, int nrings)
-{
- float theta, phi, theta1;
- float cos_theta, sin_theta;
- float cos_theta1, sin_theta1;
- float ring_delta, side_delta;
- int i, j, do_caps = true;
-
- if (start == 0 && end == nrings) do_caps = false;
-
- ring_delta = 2.0f * (float)M_PI / (float)nrings;
- side_delta = 2.0f * (float)M_PI / (float)nsides;
-
- theta = (float)M_PI + 0.5f * ring_delta;
- cos_theta = cosf(theta);
- sin_theta = sinf(theta);
-
- for (i = nrings - 1; i >= 0; i--) {
- theta1 = theta + ring_delta;
- cos_theta1 = cosf(theta1);
- sin_theta1 = sinf(theta1);
-
- if (do_caps && i == start) { // cap
- glBegin(GL_POLYGON);
- phi = 0.0;
- for (j = nsides; j >= 0; j--) {
- float cos_phi, sin_phi, dist;
-
- phi += side_delta;
- cos_phi = cosf(phi);
- sin_phi = sinf(phi);
- dist = radhole + radring * cos_phi;
-
- glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
- }
- glEnd();
- }
- if (i >= start && i <= end) {
- glBegin(GL_QUAD_STRIP);
- phi = 0.0;
- for (j = nsides; j >= 0; j--) {
- float cos_phi, sin_phi, dist;
-
- phi += side_delta;
- cos_phi = cosf(phi);
- sin_phi = sinf(phi);
- dist = radhole + radring * cos_phi;
-
- glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
- glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi);
- }
- glEnd();
- }
-
- if (do_caps && i == end) { // cap
- glBegin(GL_POLYGON);
- phi = 0.0;
- for (j = nsides; j >= 0; j--) {
- float cos_phi, sin_phi, dist;
-
- phi -= side_delta;
- cos_phi = cosf(phi);
- sin_phi = sinf(phi);
- dist = radhole + radring * cos_phi;
-
- glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi);
- }
- glEnd();
- }
-
-
- theta = theta1;
- cos_theta = cos_theta1;
- sin_theta = sin_theta1;
- }
-}
-
-static char axisBlendAngle(float idot)
-{
- if (idot > TW_AXIS_DOT_MAX) {
- return 255;
- }
- else if (idot < TW_AXIS_DOT_MIN) {
- return 0;
- }
- else {
- return (char)(255.0f * (idot - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN));
- }
-}
-
-/* three colors can be set:
- * gray for ghosting
- * moving: in transform theme color
- * else the red/green/blue
- */
-static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned char alpha)
-{
- unsigned char col[4] = {0};
- col[3] = alpha;
-
- if (colcode == MAN_GHOST) {
- col[3] = 70;
- }
- else if (colcode == MAN_MOVECOL) {
- UI_GetThemeColor3ubv(TH_TRANSFORM, col);
- }
- else {
- switch (axis) {
- case 'C':
- UI_GetThemeColor3ubv(TH_TRANSFORM, col);
- if (v3d->twmode == V3D_MANIP_LOCAL) {
- col[0] = col[0] > 200 ? 255 : col[0] + 55;
- col[1] = col[1] > 200 ? 255 : col[1] + 55;
- col[2] = col[2] > 200 ? 255 : col[2] + 55;
- }
- else if (v3d->twmode == V3D_MANIP_NORMAL) {
- col[0] = col[0] < 55 ? 0 : col[0] - 55;
- col[1] = col[1] < 55 ? 0 : col[1] - 55;
- col[2] = col[2] < 55 ? 0 : col[2] - 55;
- }
- break;
- case 'X':
- UI_GetThemeColor3ubv(TH_AXIS_X, col);
- break;
- case 'Y':
- UI_GetThemeColor3ubv(TH_AXIS_Y, col);
- break;
- case 'Z':
- UI_GetThemeColor3ubv(TH_AXIS_Z, col);
- break;
- default:
- BLI_assert(0);
- break;
- }
- }
-
- glColor4ubv(col);
-}
-
-static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3])
-{
- float axis_values[3];
- float vec[3];
-
- ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec);
-
- axis_values[0] = -dot_v3v3(rv3d->twmat[0], vec);
- axis_values[1] = -dot_v3v3(rv3d->twmat[1], vec);
- axis_values[2] = -dot_v3v3(rv3d->twmat[2], vec);
-
- axis_sort_v3(axis_values, r_axis_order);
-}
-
-/* viewmatrix should have been set OK, also no shademode! */
-static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode,
- int flagx, int flagy, int flagz, int axis,
- const bool is_picksel)
-{
- switch (axis) {
- case 0:
- /* axes */
- if (flagx) {
- if (is_picksel) {
- if (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X);
- else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X);
- }
- else {
- manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
- }
- glBegin(GL_LINES);
- glVertex3f(0.2f, 0.0f, 0.0f);
- glVertex3f(1.0f, 0.0f, 0.0f);
- glEnd();
- }
- break;
- case 1:
- if (flagy) {
- if (is_picksel) {
- if (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y);
- else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y);
- }
- else {
- manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
- }
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.2f, 0.0f);
- glVertex3f(0.0f, 1.0f, 0.0f);
- glEnd();
- }
- break;
- case 2:
- if (flagz) {
- if (is_picksel) {
- if (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z);
- else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z);
- }
- else {
- manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
- }
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.2f);
- glVertex3f(0.0f, 0.0f, 1.0f);
- glEnd();
- }
- break;
- }
-}
-static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode,
- int flagx, int flagy, int flagz,
- const int axis_order[3], const bool is_picksel)
-{
- int i;
- for (i = 0; i < 3; i++) {
- draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i], is_picksel);
- }
-}
-
-static void preOrthoFront(const bool ortho, float twmat[4][4], int axis)
-{
- if (ortho == false) {
- float omat[4][4];
- copy_m4_m4(omat, twmat);
- orthogonalize_m4(omat, axis);
- glPushMatrix();
- glMultMatrixf(omat);
- glFrontFace(is_negative_m4(omat) ? GL_CW : GL_CCW);
- }
-}
-
-static void postOrtho(const bool ortho)
-{
- if (ortho == false) {
- glPopMatrix();
- }
-}
-
-BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags)
-{
- return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z));
-}
-
-static void draw_manipulator_rotate(
- View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo,
- const bool is_moving, const bool is_picksel)
-{
- double plane[4];
- float matt[4][4];
- float size, unitmat[4][4];
- float cywid = 0.33f * 0.01f * (float)U.tw_handlesize;
- float cusize = cywid * 0.65f;
- int arcs = (G.debug_value != 2);
- const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB;
- bool ortho;
-
- /* skip drawing if all axes are locked */
- if (manipulator_rotate_is_visible(drawflags) == false) return;
-
- /* Init stuff */
- glDisable(GL_DEPTH_TEST);
- unit_m4(unitmat);
-
- /* prepare for screen aligned draw */
- size = len_v3(rv3d->twmat[0]);
- glPushMatrix();
- glTranslate3fv(rv3d->twmat[3]);
-
- if (arcs) {
- /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
- copy_v3db_v3fl(plane, rv3d->viewinv[2]);
- plane[3] = -0.02f * size; // clip just a bit more
- glClipPlane(GL_CLIP_PLANE0, plane);
- }
- /* sets view screen aligned */
- glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
-
- /* Screen aligned help circle */
- if (arcs) {
- if (is_picksel == false) {
- UI_ThemeColorShade(TH_BACK, -30);
- drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat);
- }
- }
-
- /* Screen aligned trackball rot circle */
- if (drawflags & MAN_ROT_T) {
- if (is_picksel) GPU_select_load_id(MAN_ROT_T);
- else UI_ThemeColor(TH_TRANSFORM);
-
- drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
- }
-
- /* Screen aligned view rot circle */
- if (drawflags & MAN_ROT_V) {
- if (is_picksel) GPU_select_load_id(MAN_ROT_V);
- else UI_ThemeColor(TH_TRANSFORM);
- drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
-
- if (is_moving) {
- float vec[3];
- vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
- vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
- vec[2] = 0.0f;
- normalize_v3_length(vec, 1.2f * size);
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3fv(vec);
- glEnd();
- }
- }
- glPopMatrix();
-
-
- ortho = is_orthogonal_m4(rv3d->twmat);
-
- /* apply the transform delta */
- if (is_moving) {
- copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
- // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
- if (ortho) {
- glMultMatrixf(matt);
- glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW);
- }
- }
- else {
- if (ortho) {
- glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
- glMultMatrixf(rv3d->twmat);
- }
- }
-
- /* axes */
- if (arcs == 0) {
- if (!is_picksel) {
- if ((combo & V3D_MANIP_SCALE) == 0) {
- /* axis */
- if ((drawflags & MAN_ROT_X) || (is_moving && (drawflags & MAN_ROT_Z))) {
- preOrthoFront(ortho, rv3d->twmat, 2);
- manipulator_setcolor(v3d, 'X', colcode, 255);
- glBegin(GL_LINES);
- glVertex3f(0.2f, 0.0f, 0.0f);
- glVertex3f(1.0f, 0.0f, 0.0f);
- glEnd();
- postOrtho(ortho);
- }
- if ((drawflags & MAN_ROT_Y) || (is_moving && (drawflags & MAN_ROT_X))) {
- preOrthoFront(ortho, rv3d->twmat, 0);
- manipulator_setcolor(v3d, 'Y', colcode, 255);
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.2f, 0.0f);
- glVertex3f(0.0f, 1.0f, 0.0f);
- glEnd();
- postOrtho(ortho);
- }
- if ((drawflags & MAN_ROT_Z) || (is_moving && (drawflags & MAN_ROT_Y))) {
- preOrthoFront(ortho, rv3d->twmat, 1);
- manipulator_setcolor(v3d, 'Z', colcode, 255);
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.2f);
- glVertex3f(0.0f, 0.0f, 1.0f);
- glEnd();
- postOrtho(ortho);
- }
- }
- }
- }
-
- if (arcs == 0 && is_moving) {
-
- /* Z circle */
- if (drawflags & MAN_ROT_Z) {
- preOrthoFront(ortho, matt, 2);
- if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
- else manipulator_setcolor(v3d, 'Z', colcode, 255);
- drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
- postOrtho(ortho);
- }
- /* X circle */
- if (drawflags & MAN_ROT_X) {
- preOrthoFront(ortho, matt, 0);
- if (is_picksel) GPU_select_load_id(MAN_ROT_X);
- else manipulator_setcolor(v3d, 'X', colcode, 255);
- glRotatef(90.0, 0.0, 1.0, 0.0);
- drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- postOrtho(ortho);
- }
- /* Y circle */
- if (drawflags & MAN_ROT_Y) {
- preOrthoFront(ortho, matt, 1);
- if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
- else manipulator_setcolor(v3d, 'Y', colcode, 255);
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
- glRotatef(90.0, 1.0, 0.0, 0.0);
- postOrtho(ortho);
- }
- }
- // donut arcs
- if (arcs) {
- glEnable(GL_CLIP_PLANE0);
-
- /* Z circle */
- if (drawflags & MAN_ROT_Z) {
- preOrthoFront(ortho, rv3d->twmat, 2);
- if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
- else manipulator_setcolor(v3d, 'Z', colcode, 255);
- partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
- postOrtho(ortho);
- }
- /* X circle */
- if (drawflags & MAN_ROT_X) {
- preOrthoFront(ortho, rv3d->twmat, 0);
- if (is_picksel) GPU_select_load_id(MAN_ROT_X);
- else manipulator_setcolor(v3d, 'X', colcode, 255);
- glRotatef(90.0, 0.0, 1.0, 0.0);
- partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- postOrtho(ortho);
- }
- /* Y circle */
- if (drawflags & MAN_ROT_Y) {
- preOrthoFront(ortho, rv3d->twmat, 1);
- if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
- else manipulator_setcolor(v3d, 'Y', colcode, 255);
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
- glRotatef(90.0, 1.0, 0.0, 0.0);
- postOrtho(ortho);
- }
-
- glDisable(GL_CLIP_PLANE0);
- }
-
- if (arcs == 0) {
-
- /* Z handle on X axis */
- if (drawflags & MAN_ROT_Z) {
- preOrthoFront(ortho, rv3d->twmat, 2);
- glPushMatrix();
- if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
- else manipulator_setcolor(v3d, 'Z', colcode, 255);
-
- partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
-
- glPopMatrix();
- postOrtho(ortho);
- }
-
- /* Y handle on X axis */
- if (drawflags & MAN_ROT_Y) {
- preOrthoFront(ortho, rv3d->twmat, 1);
- glPushMatrix();
- if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
- else manipulator_setcolor(v3d, 'Y', colcode, 255);
-
- glRotatef(90.0, 1.0, 0.0, 0.0);
- glRotatef(90.0, 0.0, 0.0, 1.0);
- partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
-
- glPopMatrix();
- postOrtho(ortho);
- }
-
- /* X handle on Z axis */
- if (drawflags & MAN_ROT_X) {
- preOrthoFront(ortho, rv3d->twmat, 0);
- glPushMatrix();
- if (is_picksel) GPU_select_load_id(MAN_ROT_X);
- else manipulator_setcolor(v3d, 'X', colcode, 255);
-
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- glRotatef(90.0, 0.0, 0.0, 1.0);
- partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
-
- glPopMatrix();
- postOrtho(ortho);
- }
-
- }
-
- /* restore */
- glLoadMatrixf(rv3d->viewmat);
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
-
-}
-
-static void drawsolidcube(float size)
-{
- const float cube[8][3] = {
- {-1.0, -1.0, -1.0},
- {-1.0, -1.0, 1.0},
- {-1.0, 1.0, 1.0},
- {-1.0, 1.0, -1.0},
- { 1.0, -1.0, -1.0},
- { 1.0, -1.0, 1.0},
- { 1.0, 1.0, 1.0},
- { 1.0, 1.0, -1.0},
- };
- float n[3] = {0.0f};
-
- glPushMatrix();
- glScalef(size, size, size);
-
- glBegin(GL_QUADS);
- n[0] = -1.0;
- glNormal3fv(n);
- glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
- n[0] = 0;
- glEnd();
-
- glBegin(GL_QUADS);
- n[1] = -1.0;
- glNormal3fv(n);
- glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
- n[1] = 0;
- glEnd();
-
- glBegin(GL_QUADS);
- n[0] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
- n[0] = 0;
- glEnd();
-
- glBegin(GL_QUADS);
- n[1] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
- n[1] = 0;
- glEnd();
-
- glBegin(GL_QUADS);
- n[2] = 1.0;
- glNormal3fv(n);
- glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
- n[2] = 0;
- glEnd();
-
- glBegin(GL_QUADS);
- n[2] = -1.0;
- glNormal3fv(n);
- glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
- glEnd();
-
- glPopMatrix();
-}
-
-
-static void draw_manipulator_scale(
- View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo, const int colcode,
- const bool is_moving, const bool is_picksel)
-{
- float cywid = 0.25f * 0.01f * (float)U.tw_handlesize;
- float cusize = cywid * 0.75f, dz;
- int axis_order[3] = {2, 0, 1};
- int i;
-
- /* when called while moving in mixed mode, do not draw when... */
- if ((drawflags & MAN_SCALE_C) == 0) return;
-
- manipulator_axis_order(rv3d, axis_order);
-
- glDisable(GL_DEPTH_TEST);
-
- /* not in combo mode */
- if ((combo & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) == 0) {
- float size, unitmat[4][4];
- int shift = 0; // XXX
-
- /* center circle, do not add to selection when shift is pressed (planar constraint) */
- if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C);
- else manipulator_setcolor(v3d, 'C', colcode, 255);
-
- glPushMatrix();
- size = screen_aligned(rv3d, rv3d->twmat);
- unit_m4(unitmat);
- drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
- glPopMatrix();
-
- dz = 1.0;
- }
- else {
- dz = 1.0f - 4.0f * cusize;
- }
-
- if (is_moving) {
- float matt[4][4];
-
- copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
- // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
- glMultMatrixf(matt);
- glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW);
- }
- else {
- glMultMatrixf(rv3d->twmat);
- glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
- }
-
- /* axis */
-
- /* in combo mode, this is always drawn as first type */
- draw_manipulator_axes(v3d, rv3d, colcode,
- drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z,
- axis_order, is_picksel);
-
-
- for (i = 0; i < 3; i++) {
- switch (axis_order[i]) {
- case 0: /* X cube */
- if (drawflags & MAN_SCALE_X) {
- glTranslatef(dz, 0.0, 0.0);
- if (is_picksel) GPU_select_load_id(MAN_SCALE_X);
- else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
- drawsolidcube(cusize);
- glTranslatef(-dz, 0.0, 0.0);
- }
- break;
- case 1: /* Y cube */
- if (drawflags & MAN_SCALE_Y) {
- glTranslatef(0.0, dz, 0.0);
- if (is_picksel) GPU_select_load_id(MAN_SCALE_Y);
- else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
- drawsolidcube(cusize);
- glTranslatef(0.0, -dz, 0.0);
- }
- break;
- case 2: /* Z cube */
- if (drawflags & MAN_SCALE_Z) {
- glTranslatef(0.0, 0.0, dz);
- if (is_picksel) GPU_select_load_id(MAN_SCALE_Z);
- else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
- drawsolidcube(cusize);
- glTranslatef(0.0, 0.0, -dz);
- }
- break;
- }
- }
-
-#if 0 // XXX
- /* if shiftkey, center point as last, for selectbuffer order */
- if (is_picksel) {
- int shift = 0; // XXX
-
- if (shift) {
- glTranslatef(0.0, -dz, 0.0);
- GPU_select_load_id(MAN_SCALE_C);
- /* TODO: set glPointSize before drawing center point */
- glBegin(GL_POINTS);
- glVertex3f(0.0, 0.0, 0.0);
- glEnd();
- }
- }
-#endif
-
- /* restore */
- glLoadMatrixf(rv3d->viewmat);
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- glFrontFace(GL_CCW);
-}
-
-
-static void draw_cone(GLUquadricObj *qobj, float len, float width)
-{
- glTranslatef(0.0, 0.0, -0.5f * len);
- gluCylinder(qobj, width, 0.0, len, 8, 1);
- gluQuadricOrientation(qobj, GLU_INSIDE);
- gluDisk(qobj, 0.0, width, 8, 1);
- gluQuadricOrientation(qobj, GLU_OUTSIDE);
- glTranslatef(0.0, 0.0, 0.5f * len);
-}
-
-static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
-{
-
- width *= 0.8f; // just for beauty
-
- glTranslatef(0.0, 0.0, -0.5f * len);
- gluCylinder(qobj, width, width, len, 8, 1);
- gluQuadricOrientation(qobj, GLU_INSIDE);
- gluDisk(qobj, 0.0, width, 8, 1);
- gluQuadricOrientation(qobj, GLU_OUTSIDE);
- glTranslatef(0.0, 0.0, len);
- gluDisk(qobj, 0.0, width, 8, 1);
- glTranslatef(0.0, 0.0, -0.5f * len);
-}
-
-
-static void draw_manipulator_translate(
- View3D *v3d, RegionView3D *rv3d, int drawflags, int combo, int colcode,
- const bool UNUSED(is_moving), const bool is_picksel)
-{
- GLUquadricObj *qobj;
- float cylen = 0.01f * (float)U.tw_handlesize;
- float cywid = 0.25f * cylen, dz, size;
- float unitmat[4][4];
- int shift = 0; // XXX
- int axis_order[3] = {0, 1, 2};
- int i;
-
- /* when called while moving in mixed mode, do not draw when... */
- if ((drawflags & MAN_TRANS_C) == 0) return;
-
- manipulator_axis_order(rv3d, axis_order);
-
- // XXX if (moving) glTranslate3fv(t->vec);
- glDisable(GL_DEPTH_TEST);
-
- /* center circle, do not add to selection when shift is pressed (planar constraint) */
- if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C);
- else manipulator_setcolor(v3d, 'C', colcode, 255);
-
- glPushMatrix();
- size = screen_aligned(rv3d, rv3d->twmat);
- unit_m4(unitmat);
- drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
- glPopMatrix();
-
- /* and now apply matrix, we move to local matrix drawing */
- glMultMatrixf(rv3d->twmat);
-
- /* axis */
- GPU_select_load_id(-1);
-
- // translate drawn as last, only axis when no combo with scale, or for ghosting
- if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) {
- draw_manipulator_axes(v3d, rv3d, colcode,
- drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z,
- axis_order, is_picksel);
- }
-
-
- /* offset in combo mode, for rotate a bit more */
- if (combo & (V3D_MANIP_ROTATE)) dz = 1.0f + 2.0f * cylen;
- else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen;
- else dz = 1.0f;
-
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
-
- for (i = 0; i < 3; i++) {
- switch (axis_order[i]) {
- case 0: /* Z Cone */
- if (drawflags & MAN_TRANS_Z) {
- glTranslatef(0.0, 0.0, dz);
- if (is_picksel) GPU_select_load_id(MAN_TRANS_Z);
- else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
- draw_cone(qobj, cylen, cywid);
- glTranslatef(0.0, 0.0, -dz);
- }
- break;
- case 1: /* X Cone */
- if (drawflags & MAN_TRANS_X) {
- glTranslatef(dz, 0.0, 0.0);
- if (is_picksel) GPU_select_load_id(MAN_TRANS_X);
- else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
- glRotatef(90.0, 0.0, 1.0, 0.0);
- draw_cone(qobj, cylen, cywid);
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- glTranslatef(-dz, 0.0, 0.0);
- }
- break;
- case 2: /* Y Cone */
- if (drawflags & MAN_TRANS_Y) {
- glTranslatef(0.0, dz, 0.0);
- if (is_picksel) GPU_select_load_id(MAN_TRANS_Y);
- else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- draw_cone(qobj, cylen, cywid);
- glRotatef(90.0, 1.0, 0.0, 0.0);
- glTranslatef(0.0, -dz, 0.0);
- }
- break;
- }
- }
-
- gluDeleteQuadric(qobj);
- glLoadMatrixf(rv3d->viewmat);
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
-
-}
-
-static void draw_manipulator_rotate_cyl(
- View3D *v3d, RegionView3D *rv3d, int drawflags, const int combo, const int colcode,
- const bool is_moving, const bool is_picksel)
-{
- GLUquadricObj *qobj;
- float size;
- float cylen = 0.01f * (float)U.tw_handlesize;
- float cywid = 0.25f * cylen;
- int axis_order[3] = {2, 0, 1};
- int i;
-
- /* skip drawing if all axes are locked */
- if (manipulator_rotate_is_visible(drawflags) == false) return;
-
- manipulator_axis_order(rv3d, axis_order);
-
- /* prepare for screen aligned draw */
- glPushMatrix();
- size = screen_aligned(rv3d, rv3d->twmat);
-
- glDisable(GL_DEPTH_TEST);
-
- qobj = gluNewQuadric();
-
- /* Screen aligned view rot circle */
- if (drawflags & MAN_ROT_V) {
- float unitmat[4][4];
-
- unit_m4(unitmat);
-
- if (is_picksel) GPU_select_load_id(MAN_ROT_V);
- UI_ThemeColor(TH_TRANSFORM);
- drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
-
- if (is_moving) {
- float vec[3];
- vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
- vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
- vec[2] = 0.0f;
- normalize_v3_length(vec, 1.2f * size);
- glBegin(GL_LINES);
- glVertex3f(0.0, 0.0, 0.0);
- glVertex3fv(vec);
- glEnd();
- }
- }
- glPopMatrix();
-
- /* apply the transform delta */
- if (is_moving) {
- float matt[4][4];
- copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
- // XXX if (t->flag & T_USES_MANIPULATOR) {
- // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
- // XXX }
- glMultMatrixf(matt);
- }
- else {
- glMultMatrixf(rv3d->twmat);
- }
-
- glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
-
- /* axis */
- if (is_picksel == false) {
-
- // only draw axis when combo didn't draw scale axes
- if ((combo & V3D_MANIP_SCALE) == 0) {
- draw_manipulator_axes(v3d, rv3d, colcode,
- drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z,
- axis_order, is_picksel);
- }
-
- /* only has to be set when not in picking */
- gluQuadricDrawStyle(qobj, GLU_FILL);
- }
-
- for (i = 0; i < 3; i++) {
- switch (axis_order[i]) {
- case 0: /* X cylinder */
- if (drawflags & MAN_ROT_X) {
- glTranslatef(1.0, 0.0, 0.0);
- if (is_picksel) GPU_select_load_id(MAN_ROT_X);
- glRotatef(90.0, 0.0, 1.0, 0.0);
- manipulator_setcolor(v3d, 'X', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- glTranslatef(-1.0, 0.0, 0.0);
- }
- break;
- case 1: /* Y cylinder */
- if (drawflags & MAN_ROT_Y) {
- glTranslatef(0.0, 1.0, 0.0);
- if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- manipulator_setcolor(v3d, 'Y', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
- glRotatef(90.0, 1.0, 0.0, 0.0);
- glTranslatef(0.0, -1.0, 0.0);
- }
- break;
- case 2: /* Z cylinder */
- if (drawflags & MAN_ROT_Z) {
- glTranslatef(0.0, 0.0, 1.0);
- if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
- manipulator_setcolor(v3d, 'Z', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
- glTranslatef(0.0, 0.0, -1.0);
- }
- break;
- }
- }
-
- /* restore */
-
- gluDeleteQuadric(qobj);
- glLoadMatrixf(rv3d->viewmat);
-
- if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
-
-}
-
-
-/* ********************************************* */
-
-/* main call, does calc centers & orientation too */
-static int drawflags = 0xFFFF; // only for the calls below, belongs in scene...?
-
-void BIF_draw_manipulator(const bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = sa->spacedata.first;
- RegionView3D *rv3d = ar->regiondata;
- int totsel;
-
- const bool is_picksel = false;
-
- if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
-
- if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return;
-
- {
- struct TransformBounds tbounds;
- v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
-
- totsel = calc_manipulator_stats(C, &tbounds);
- if (totsel == 0) return;
-
- v3d->twflag |= V3D_DRAW_MANIPULATOR;
-
- /* now we can define center */
- switch (v3d->around) {
- case V3D_AROUND_CENTER_BOUNDS:
- case V3D_AROUND_ACTIVE:
- {
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = OBACT;
-
- if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) &&
- ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
- (ob && !(ob->mode & OB_MODE_POSE)))
- {
- copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
- }
- else {
- mid_v3_v3v3(rv3d->twmat[3], tbounds.min, tbounds.max);
- }
- break;
- }
- case V3D_AROUND_LOCAL_ORIGINS:
- case V3D_AROUND_CENTER_MEAN:
- copy_v3_v3(rv3d->twmat[3], tbounds.center);
- break;
- case V3D_AROUND_CURSOR:
- copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
- break;
- }
-
- mul_mat3_m4_fl(rv3d->twmat, ED_view3d_pixel_size(rv3d, rv3d->twmat[3]) * U.tw_size);
- }
-
- /* when looking through a selected camera, the manipulator can be at the
- * exact same position as the view, skip so we don't break selection */
- if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f)
- return;
-
- test_manipulator_axis(C);
- drawflags = rv3d->twdrawflag; /* set in calc_manipulator_stats */
-
- if (v3d->twflag & V3D_DRAW_MANIPULATOR) {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glLineWidth(1.0f);
-
- if (v3d->twtype & V3D_MANIP_ROTATE) {
- if (G.debug_value == 3) {
- if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT))
- draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_MOVECOL, true, is_picksel);
- else
- draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel);
- }
- else {
- draw_manipulator_rotate(v3d, rv3d, drawflags, v3d->twtype, false, is_picksel);
- }
- }
- if (v3d->twtype & V3D_MANIP_SCALE) {
- draw_manipulator_scale(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel);
- }
- if (v3d->twtype & V3D_MANIP_TRANSLATE) {
- draw_manipulator_translate(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel);
- }
-
- glDisable(GL_BLEND);
- }
-}
-
-static int manipulator_selectbuf(Scene *scene, ScrArea *sa, ARegion *ar, const int mval[2], float hotspot)
-{
- View3D *v3d = sa->spacedata.first;
- RegionView3D *rv3d = ar->regiondata;
- rcti rect;
- GLuint buffer[64]; // max 4 items per select, so large enuf
- short hits;
- const bool is_picksel = true;
- const bool do_passes = GPU_select_query_check_active();
-
- /* when looking through a selected camera, the manipulator can be at the
- * exact same position as the view, skip so we don't break selection */
- if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f)
- return 0;
-
- rect.xmin = mval[0] - hotspot;
- rect.xmax = mval[0] + hotspot;
- rect.ymin = mval[1] - hotspot;
- rect.ymax = mval[1] + hotspot;
-
- ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, &rect);
-
- if (do_passes)
- GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
- else
- GPU_select_begin(buffer, 64, &rect, GPU_SELECT_ALL, 0);
-
- /* do the drawing */
- if (v3d->twtype & V3D_MANIP_ROTATE) {
- if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
- else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel);
- }
- if (v3d->twtype & V3D_MANIP_SCALE)
- draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
- if (v3d->twtype & V3D_MANIP_TRANSLATE)
- draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
-
- hits = GPU_select_end();
-
- if (do_passes && (hits > 0)) {
- GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
-
- /* do the drawing */
- if (v3d->twtype & V3D_MANIP_ROTATE) {
- if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
- else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel);
- }
- if (v3d->twtype & V3D_MANIP_SCALE)
- draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
- if (v3d->twtype & V3D_MANIP_TRANSLATE)
- draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
-
- GPU_select_end();
- }
-
- ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, NULL);
-
- if (hits == 1) return buffer[3];
- else if (hits > 1) {
- GLuint val, dep, mindep = 0, mindeprot = 0, minval = 0, minvalrot = 0;
- int a;
-
- /* we compare the hits in buffer, but value centers highest */
- /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */
-
- for (a = 0; a < hits; a++) {
- dep = buffer[4 * a + 1];
- val = buffer[4 * a + 3];
-
- if (val == MAN_TRANS_C) {
- return MAN_TRANS_C;
- }
- else if (val == MAN_SCALE_C) {
- return MAN_SCALE_C;
- }
- else {
- if (val & MAN_ROT_C) {
- if (minvalrot == 0 || dep < mindeprot) {
- mindeprot = dep;
- minvalrot = val;
- }
- }
- else {
- if (minval == 0 || dep < mindep) {
- mindep = dep;
- minval = val;
- }
- }
- }
- }
-
- if (minval)
- return minval;
- else
- return minvalrot;
- }
- return 0;
-}
-
-static const char *manipulator_get_operator_name(int man_val)
-{
- if (man_val & MAN_TRANS_C) {
- return "TRANSFORM_OT_translate";
- }
- else if (man_val == MAN_ROT_T) {
- return "TRANSFORM_OT_trackball";
- }
- else if (man_val & MAN_ROT_C) {
- return "TRANSFORM_OT_rotate";
- }
- else if (man_val & MAN_SCALE_C) {
- return "TRANSFORM_OT_resize";
- }
-
- return NULL;
-}
-
-/* return 0; nothing happened */
-int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- ARegion *ar = CTX_wm_region(C);
- bool constraint_axis[3] = {false, false, false};
- int val;
- const bool use_planar = RNA_boolean_get(op->ptr, "use_planar_constraint");
-
- if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
- if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
-
- /* Force orientation */
- RNA_enum_set(op->ptr, "constraint_orientation", v3d->twmode);
-
- // find the hotspots first test narrow hotspot
- val = manipulator_selectbuf(scene, sa, ar, event->mval, 0.5f * (float)U.tw_hotspot);
- if (val) {
- wmOperatorType *ot;
- PointerRNA props_ptr;
- PropertyRNA *prop;
- const char *opname;
-
- // drawflags still global, for drawing call above
- drawflags = manipulator_selectbuf(scene, sa, ar, event->mval, 0.2f * (float)U.tw_hotspot);
- if (drawflags == 0) drawflags = val;
-
- /* Planar constraint doesn't make sense for rotation, give other keymaps a chance */
- if ((drawflags & MAN_ROT_C) && use_planar) {
- return 0;
- }
-
- opname = manipulator_get_operator_name(drawflags);
- ot = WM_operatortype_find(opname, true);
- WM_operator_properties_create_ptr(&props_ptr, ot);
-
- if (drawflags & MAN_TRANS_C) {
- switch (drawflags) {
- case MAN_TRANS_C:
- break;
- case MAN_TRANS_X:
- if (use_planar) {
- constraint_axis[1] = 1;
- constraint_axis[2] = 1;
- }
- else
- constraint_axis[0] = 1;
- break;
- case MAN_TRANS_Y:
- if (use_planar) {
- constraint_axis[0] = 1;
- constraint_axis[2] = 1;
- }
- else
- constraint_axis[1] = 1;
- break;
- case MAN_TRANS_Z:
- if (use_planar) {
- constraint_axis[0] = 1;
- constraint_axis[1] = 1;
- }
- else
- constraint_axis[2] = 1;
- break;
- }
- RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis);
- }
- else if (drawflags & MAN_SCALE_C) {
- switch (drawflags) {
- case MAN_SCALE_X:
- if (use_planar) {
- constraint_axis[1] = 1;
- constraint_axis[2] = 1;
- }
- else
- constraint_axis[0] = 1;
- break;
- case MAN_SCALE_Y:
- if (use_planar) {
- constraint_axis[0] = 1;
- constraint_axis[2] = 1;
- }
- else
- constraint_axis[1] = 1;
- break;
- case MAN_SCALE_Z:
- if (use_planar) {
- constraint_axis[0] = 1;
- constraint_axis[1] = 1;
- }
- else
- constraint_axis[2] = 1;
- break;
- }
- RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis);
- }
- else if (drawflags == MAN_ROT_T) {
- /* pass */
- }
- else if (drawflags & MAN_ROT_C) {
- switch (drawflags) {
- case MAN_ROT_X:
- constraint_axis[0] = 1;
- break;
- case MAN_ROT_Y:
- constraint_axis[1] = 1;
- break;
- case MAN_ROT_Z:
- constraint_axis[2] = 1;
- break;
- }
- RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis);
- }
-
- /* pass operator properties on to transform operators */
- prop = RNA_struct_find_property(op->ptr, "use_accurate");
- if (RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
- }
- prop = RNA_struct_find_property(op->ptr, "release_confirm");
- if (RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
- }
- prop = RNA_struct_find_property(op->ptr, "constraint_orientation");
- if (RNA_property_is_set(op->ptr, prop)) {
- RNA_property_enum_set(&props_ptr, prop, RNA_property_enum_get(op->ptr, prop));
- }
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
- WM_operator_properties_free(&props_ptr);
- }
- /* after transform, restore drawflags */
- drawflags = 0xFFFF;
-
- return val;
-}
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 7120158ab46..d11cfa8d3d3 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -45,7 +45,9 @@
#include "RNA_enum_types.h"
#include "WM_api.h"
+#include "WM_message.h"
#include "WM_types.h"
+#include "WM_toolsystem.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -81,6 +83,7 @@ static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
+static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal";
static void TRANSFORM_OT_translate(struct wmOperatorType *ot);
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot);
@@ -99,6 +102,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot);
static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot);
+static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot);
static TransformModeItem transform_modes[] =
{
@@ -119,6 +123,7 @@ static TransformModeItem transform_modes[] =
{OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
{OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight},
{OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide},
+ {OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal},
{NULL, 0}
};
@@ -160,11 +165,15 @@ const EnumPropertyItem rna_enum_transform_mode_types[] =
static int select_orientation_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
int orientation = RNA_enum_get(op->ptr, "orientation");
- BIF_selectTransformOrientationValue(C, orientation);
+ BIF_selectTransformOrientationValue(scene, orientation);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation);
return OPERATOR_FINISHED;
}
@@ -205,13 +214,10 @@ static void TRANSFORM_OT_select_orientation(struct wmOperatorType *ot)
static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op))
{
- View3D *v3d = CTX_wm_view3d(C);
- int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
-
- BIF_removeTransformOrientationIndex(C, selected_index);
+ Scene *scene = CTX_data_scene(C);
+ BIF_removeTransformOrientationIndex(C, scene->orientation_index_custom);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, CTX_data_scene(C));
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
return OPERATOR_FINISHED;
}
@@ -223,18 +229,12 @@ static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent
static bool delete_orientation_poll(bContext *C)
{
- int selected_index = -1;
- View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
if (ED_operator_areaactive(C) == 0)
return 0;
-
- if (v3d) {
- selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
- }
-
- return selected_index >= 0;
+ return (scene->orientation_type >= V3D_MANIP_CUSTOM) && (scene->orientation_index_custom != -1);
}
static void TRANSFORM_OT_delete_orientation(struct wmOperatorType *ot)
@@ -289,6 +289,9 @@ static void TRANSFORM_OT_create_orientation(struct wmOperatorType *ot)
RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the new custom orientation");
RNA_def_boolean(ot->srna, "use_view", false, "Use View",
"Use the current view instead of the active object to create the new orientation");
+
+ WM_operatortype_props_advanced_begin(ot);
+
RNA_def_boolean(ot->srna, "use", false, "Use after creation", "Select orientation after its creation");
RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite previous",
"Overwrite previously created orientation with same name");
@@ -319,7 +322,8 @@ static void transformops_loopsel_hack(bContext *C, wmOperator *op)
/* still switch if we were originally in face select mode */
if ((ts->selectmode != selectmode_orig) && (selectmode_orig != SCE_SELECT_FACE)) {
- BMEditMesh *em = BKE_editmesh_from_object(scene->obedit);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
em->selectmode = ts->selectmode = selectmode_orig;
EDBM_selectmode_set(em);
}
@@ -483,14 +487,26 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- if (RNA_struct_property_is_set(op->ptr, "value")) {
+ /* When modal, allow 'value' to set initial offset. */
+ if ((event == NULL) &&
+ RNA_struct_property_is_set(op->ptr, "value"))
+ {
return transform_exec(C, op);
}
else {
/* add temp handler */
WM_event_add_modal_handler(C, op);
- op->flag |= OP_IS_MODAL_GRAB_CURSOR; // XXX maybe we want this with the manipulator only?
+ op->flag |= OP_IS_MODAL_GRAB_CURSOR; // XXX maybe we want this with the gizmo only?
+
+ /* Use when modal input has some transformation to begin with. */
+ {
+ TransInfo *t = op->customdata;
+ if (UNLIKELY(!is_zero_v4(t->values_modal_offset))) {
+ transformApply(C, t);
+ }
+ }
+
return OPERATOR_RUNNING_MODAL;
}
}
@@ -537,11 +553,25 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_property_ui_text(prop, "Axis", "The axis around which the transformation occurs");
}
+ if (flags & P_AXIS_ORTHO) {
+ prop = RNA_def_property(ot->srna, "axis_ortho", PROP_FLOAT, PROP_DIRECTION);
+ RNA_def_property_array(prop, 3);
+ /* Make this not hidden when there's a nice axis selection widget */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_property_ui_text(prop, "Axis", "The orthogonal axis around which the transformation occurs");
+ }
+
if (flags & P_CONSTRAINT) {
RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
+
+ /* Set by 'constraint_orientation' or gizmo which acts on non-standard orientation. */
+ prop = RNA_def_float_matrix(ot->srna, "constraint_matrix", 3, 3, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
prop = RNA_def_property(ot->srna, "constraint_orientation", PROP_ENUM, PROP_NONE);
RNA_def_property_ui_text(prop, "Orientation", "Transformation orientation");
RNA_def_enum_funcs(prop, rna_TransformOrientation_itemf);
+
}
if (flags & P_MIRROR) {
@@ -556,7 +586,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
if (flags & P_PROPORTIONAL) {
RNA_def_enum(ot->srna, "proportional", rna_enum_proportional_editing_items, 0, "Proportional Editing", "");
prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0,
- "Proportional Editing Falloff", "Falloff type for proportional editing mode");
+ "Proportional Falloff", "Falloff type for proportional editing mode");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX,
"Proportional Size", "", 0.001f, 100.0f);
@@ -582,21 +612,28 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
}
if (flags & P_GPENCIL_EDIT) {
- RNA_def_boolean(ot->srna, "gpencil_strokes", 0, "Edit Grease Pencil", "Edit selected Grease Pencil strokes");
+ prop = RNA_def_boolean(ot->srna, "gpencil_strokes", 0, "Edit Grease Pencil", "Edit selected Grease Pencil strokes");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ }
+
+ if (flags & P_CURSOR_EDIT) {
+ prop = RNA_def_boolean(ot->srna, "cursor_transform", 0, "Transform Cursor", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
if ((flags & P_OPTIONS) && !(flags & P_NO_TEXSPACE)) {
- RNA_def_boolean(ot->srna, "texture_space", 0, "Edit Texture Space", "Edit Object data texture space");
+ prop = RNA_def_boolean(ot->srna, "texture_space", 0, "Edit Texture Space", "Edit Object data texture space");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "remove_on_cancel", 0, "Remove on Cancel", "Remove elements on cancel");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
if (flags & P_CORRECT_UV) {
- RNA_def_boolean(ot->srna, "correct_uv", 0, "Correct UVs", "Correct UV coordinates when transforming");
+ RNA_def_boolean(ot->srna, "correct_uv", true, "Correct UVs", "Correct UV coordinates when transforming");
}
if (flags & P_CENTER) {
- /* For manipulators that define their own center. */
+ /* For gizmos that define their own center. */
prop = RNA_def_property(ot->srna, "center_override", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(prop, 3);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
@@ -615,8 +652,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Translate";
- ot->description = "Translate (move) selected items";
+ ot->name = "Move";
+ ot->description = "Move selected items";
ot->idname = OP_TRANSLATION;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
@@ -630,7 +667,12 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
RNA_def_float_vector_xyz(ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Move", "", -FLT_MAX, FLT_MAX);
- Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS | P_GPENCIL_EDIT);
+ WM_operatortype_props_advanced_begin(ot);
+
+ Transform_Properties(
+ ot,
+ P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS |
+ P_GPENCIL_EDIT | P_CURSOR_EDIT);
}
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
@@ -651,6 +693,8 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Scale", "", -FLT_MAX, FLT_MAX);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(
ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT | P_CENTER);
}
@@ -683,6 +727,8 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Scale", "", -FLT_MAX, FLT_MAX);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_NO_TEXSPACE);
}
@@ -705,6 +751,8 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
/* Maybe we could use float_vector_xyz here too? */
RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
@@ -726,6 +774,8 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(
ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
@@ -751,6 +801,8 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
}
@@ -772,6 +824,8 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
@@ -792,9 +846,11 @@ static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
ot->poll_property = transform_poll_property;
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
+ RNA_def_enum(ot->srna, "shear_axis", rna_enum_axis_xy_items, 0, "Shear Axis", "");
+
+ WM_operatortype_props_advanced_begin(ot);
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
- // XXX Shear axis?
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_AXIS | P_AXIS_ORTHO);
}
static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot)
@@ -815,6 +871,8 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot)
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER);
}
@@ -838,6 +896,8 @@ static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
}
@@ -860,6 +920,8 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
@@ -906,6 +968,9 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
RNA_def_boolean(ot->srna, "use_even", false, "Even",
"Make the edge loop match the shape of the adjacent edge loop");
+
+ WM_operatortype_props_advanced_begin(ot);
+
RNA_def_boolean(ot->srna, "flipped", false, "Flipped",
"When Even mode is active, flips between the two adjacent edge loops");
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp",
@@ -933,6 +998,9 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_even", false, "Even",
"Make the edge loop match the shape of the adjacent edge loop");
+
+ WM_operatortype_props_advanced_begin(ot);
+
RNA_def_boolean(ot->srna, "flipped", false, "Flipped",
"When Even mode is active, flips between the two adjacent edge loops");
RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp",
@@ -959,30 +1027,11 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
- Transform_Properties(ot, P_SNAP);
-}
-
-static int edge_bevelweight_exec(bContext *C, wmOperator *op)
-{
- Mesh *me = (Mesh *)CTX_data_edit_object(C)->data;
-
- /* auto-enable bevel edge weight drawing, then chain to common transform code */
- me->drawflag |= ME_DRAWBWEIGHTS;
-
- return transform_exec(C, op);
-}
-
-static int edge_bevelweight_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Mesh *me = (Mesh *)CTX_data_edit_object(C)->data;
+ WM_operatortype_props_advanced_begin(ot);
- /* auto-enable bevel edge weight drawing, then chain to common transform code */
- me->drawflag |= ME_DRAWBWEIGHTS;
-
- return transform_invoke(C, op, event);
+ Transform_Properties(ot, P_SNAP);
}
-
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
{
/* identifiers */
@@ -992,14 +1041,16 @@ static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* api callbacks */
- ot->invoke = edge_bevelweight_invoke;
- ot->exec = edge_bevelweight_exec;
+ ot->invoke = transform_invoke;
+ ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
ot->poll = ED_operator_editmesh;
RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_SNAP);
}
@@ -1020,9 +1071,32 @@ static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot)
RNA_def_float_vector_xyz(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(ot, P_SNAP);
}
+static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Normal Rotate";
+ ot->description = "Rotate split normal of selected items";
+ ot->idname = OP_NORMAL_ROTATION;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* api callbacks */
+ ot->invoke = transform_invoke;
+ ot->exec = transform_exec;
+ ot->modal = transform_modal;
+ ot->cancel = transform_cancel;
+ ot->poll = ED_operator_editmesh_auto_smooth;
+
+ RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
+
+ Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_MIRROR);
+}
+
+
static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1046,10 +1120,64 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX);
+ WM_operatortype_props_advanced_begin(ot);
+
Transform_Properties(
ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
+static int transform_from_gizmo_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+ bToolRef *tref = WM_toolsystem_ref_from_context(C);
+ if (tref) {
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "TRANSFORM_GGT_gizmo") : NULL;
+ if (gzgroup != NULL) {
+ PointerRNA gzg_ptr;
+ WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &gzg_ptr);
+ const int drag_action = RNA_enum_get(&gzg_ptr, "drag_action");
+ const char *op_id = NULL;
+ switch (drag_action) {
+ case SCE_GIZMO_SHOW_TRANSLATE:
+ op_id = "TRANSFORM_OT_translate";
+ break;
+ case SCE_GIZMO_SHOW_ROTATE:
+ op_id = "TRANSFORM_OT_rotate";
+ break;
+ case SCE_GIZMO_SHOW_SCALE:
+ op_id = "TRANSFORM_OT_resize";
+ break;
+ default:
+ break;
+ }
+ if (op_id) {
+ wmOperatorType *ot = WM_operatortype_find(op_id, true);
+ PointerRNA op_ptr;
+ WM_operator_properties_create_ptr(&op_ptr, ot);
+ RNA_boolean_set(&op_ptr, "release_confirm", true);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_ptr);
+ WM_operator_properties_free(&op_ptr);
+ return OPERATOR_FINISHED;
+ }
+ }
+ }
+ return OPERATOR_PASS_THROUGH;
+}
+
+/* Use with 'TRANSFORM_GGT_gizmo'. */
+static void TRANSFORM_OT_from_gizmo(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Transform From Gizmo";
+ ot->description = "Transform selected items by mode type";
+ ot->idname = "TRANSFORM_OT_from_gizmo";
+ ot->flag = 0;
+
+ /* api callbacks */
+ ot->invoke = transform_from_gizmo_invoke;
+}
+
void transform_operatortypes(void)
{
TransformModeItem *tmode;
@@ -1063,169 +1191,18 @@ void transform_operatortypes(void)
WM_operatortype_append(TRANSFORM_OT_select_orientation);
WM_operatortype_append(TRANSFORM_OT_create_orientation);
WM_operatortype_append(TRANSFORM_OT_delete_orientation);
+
+ WM_operatortype_append(TRANSFORM_OT_from_gizmo);
}
-void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spaceid)
+void ED_keymap_transform(wmKeyConfig *keyconf)
{
- wmKeyMapItem *kmi;
- wmKeyMap *modalmap;
-
- /* transform.c, only adds modal map once, checks if it's there */
- modalmap = transform_modal_keymap(keyconf);
-
- /* assign map to operators only the first time */
- if (modalmap) {
- TransformModeItem *tmode;
-
- for (tmode = transform_modes; tmode->idname; tmode++) {
- WM_modalkeymap_assign(modalmap, tmode->idname);
- }
- WM_modalkeymap_assign(modalmap, "TRANSFORM_OT_transform");
- }
-
- switch (spaceid) {
- case SPACE_VIEW3D:
- WM_keymap_add_item(keymap, OP_TRANSLATION, GKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_TRANSLATION, EVT_TWEAK_S, KM_ANY, 0, 0);
-
- WM_keymap_add_item(keymap, OP_ROTATION, RKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_RESIZE, SKEY, KM_PRESS, 0, 0);
+ wmKeyMap *modalmap = transform_modal_keymap(keyconf);
- WM_keymap_add_item(keymap, OP_BEND, WKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, OP_TOSPHERE, SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, OP_SHEAR, SKEY, KM_PRESS, KM_ALT | KM_CTRL | KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "TRANSFORM_OT_select_orientation", SPACEKEY, KM_PRESS, KM_ALT, 0);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_create_orientation", SPACEKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "use", true);
-
- WM_keymap_add_item(keymap, OP_MIRROR, MKEY, KM_PRESS, KM_CTRL, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_snap");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_element");
-
-
- kmi = WM_keymap_add_item(keymap, OP_TRANSLATION, TKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "texture_space", true);
-
- kmi = WM_keymap_add_item(keymap, OP_RESIZE, TKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "texture_space", true);
-
- WM_keymap_add_item(keymap, OP_SKIN_RESIZE, AKEY, KM_PRESS, KM_CTRL, 0);
-
- break;
- case SPACE_ACTION:
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", GKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_TRANSLATE);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", EVT_TWEAK_S, KM_ANY, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_TRANSLATE);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", EKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_EXTEND);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_SCALE);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", TKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_SLIDE);
- break;
- case SPACE_IPO:
- WM_keymap_add_item(keymap, OP_TRANSLATION, GKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_TRANSLATION, EVT_TWEAK_S, KM_ANY, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", EKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_EXTEND);
-
- WM_keymap_add_item(keymap, OP_ROTATION, RKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_RESIZE, SKEY, KM_PRESS, 0, 0);
- break;
- case SPACE_NLA:
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", GKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TRANSLATION);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", EVT_TWEAK_S, KM_ANY, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TRANSLATION);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", EKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_EXTEND);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_SCALE);
- break;
- case SPACE_NODE:
- WM_keymap_add_item(keymap, "NODE_OT_translate_attach", GKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_translate_attach", EVT_TWEAK_A, KM_ANY, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_translate_attach", EVT_TWEAK_S, KM_ANY, 0, 0);
- /* NB: small trick: macro operator poll may fail due to library data edit,
- * in that case the secondary regular operators are called with same keymap.
- */
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_A, KM_ANY, 0, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0);
- RNA_boolean_set(kmi->ptr, "release_confirm", true);
-
- WM_keymap_add_item(keymap, OP_ROTATION, RKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_RESIZE, SKEY, KM_PRESS, 0, 0);
-
- /* detach and translate */
- WM_keymap_add_item(keymap, "NODE_OT_move_detach_links", DKEY, KM_PRESS, KM_ALT, 0);
- /* XXX release_confirm is set in the macro operator definition */
- WM_keymap_add_item(keymap, "NODE_OT_move_detach_links_release", EVT_TWEAK_A, KM_ANY, KM_ALT, 0);
- WM_keymap_add_item(keymap, "NODE_OT_move_detach_links", EVT_TWEAK_S, KM_ANY, KM_ALT, 0);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_snap");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_node_element");
- break;
- case SPACE_SEQ:
- WM_keymap_add_item(keymap, OP_SEQ_SLIDE, GKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_SEQ_SLIDE, EVT_TWEAK_S, KM_ANY, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", EKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", TFM_TIME_EXTEND);
- break;
- case SPACE_IMAGE:
- WM_keymap_add_item(keymap, OP_TRANSLATION, GKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_TRANSLATION, EVT_TWEAK_S, KM_ANY, 0, 0);
-
- WM_keymap_add_item(keymap, OP_ROTATION, RKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_RESIZE, SKEY, KM_PRESS, 0, 0);
-
- WM_keymap_add_item(keymap, OP_SHEAR, SKEY, KM_PRESS, KM_ALT | KM_CTRL | KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "TRANSFORM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0);
+ TransformModeItem *tmode;
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_snap");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_uv_element");
- break;
- case SPACE_CLIP:
- WM_keymap_add_item(keymap, OP_TRANSLATION, GKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, OP_TRANSLATION, EVT_TWEAK_S, KM_ANY, 0, 0);
- WM_keymap_add_item(keymap, OP_RESIZE, SKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, OP_ROTATION, RKEY, KM_PRESS, 0, 0);
- break;
- default:
- break;
+ for (tmode = transform_modes; tmode->idname; tmode++) {
+ WM_modalkeymap_assign(modalmap, tmode->idname);
}
+ WM_modalkeymap_assign(modalmap, "TRANSFORM_OT_transform");
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 8cd31c32911..5be23594afd 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -38,6 +38,7 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -52,6 +53,8 @@
#include "BKE_report.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "BLT_translation.h"
@@ -63,14 +66,15 @@
void BIF_clearTransformOrientation(bContext *C)
{
+ Scene *scene = CTX_data_scene(C);
+ ListBase *transform_orientations = &scene->transform_spaces;
View3D *v3d = CTX_wm_view3d(C);
- ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
- BLI_freelistN(transform_spaces);
+ BLI_freelistN(transform_orientations);
- // Need to loop over all view3d
- if (v3d && v3d->twmode >= V3D_MANIP_CUSTOM) {
- v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
+ if (v3d && scene->orientation_type == V3D_MANIP_CUSTOM) {
+ scene->orientation_type = V3D_MANIP_GLOBAL; /* fallback to global */
+ scene->orientation_index_custom = -1;
}
}
@@ -318,23 +322,24 @@ void BIF_createTransformOrientation(bContext *C, ReportList *reports,
TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3],
const char *name, const bool overwrite)
{
- ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
TransformOrientation *ts = NULL;
+ Scene *scene = CTX_data_scene(C);
+ ListBase *transform_orientations = &scene->transform_spaces;
char name_unique[sizeof(ts->name)];
if (overwrite) {
- ts = findOrientationName(transform_spaces, name);
+ ts = findOrientationName(transform_orientations, name);
}
else {
BLI_strncpy(name_unique, name, sizeof(name_unique));
- uniqueOrientationName(transform_spaces, name_unique);
+ uniqueOrientationName(transform_orientations, name_unique);
name = name_unique;
}
/* if not, create a new one */
if (ts == NULL) {
ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
- BLI_addtail(transform_spaces, ts);
+ BLI_addtail(transform_orientations, ts);
BLI_strncpy(ts->name, name, sizeof(ts->name));
}
@@ -346,70 +351,54 @@ TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3],
void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target)
{
- Scene *scene = CTX_data_scene(C);
- ListBase *transform_spaces = &scene->transform_spaces;
- const int i = BLI_findindex(transform_spaces, target);
-
- if (i != -1) {
- Main *bmain = CTX_data_main(C);
- BKE_screen_view3d_main_twmode_remove(&bmain->screen, scene, i);
- BLI_freelinkN(transform_spaces, target);
- }
+ BKE_scene_transform_orientation_remove(CTX_data_scene(C), target);
}
void BIF_removeTransformOrientationIndex(bContext *C, int index)
{
- ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
- TransformOrientation *ts = BLI_findlink(transform_spaces, index);
-
- if (ts) {
- BIF_removeTransformOrientation(C, ts);
- }
+ TransformOrientation *target = BKE_scene_transform_orientation_find(CTX_data_scene(C), index);
+ BIF_removeTransformOrientation(C, target);
}
void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target)
{
- ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
- const int i = BLI_findindex(transform_spaces, target);
+ Scene *scene = CTX_data_scene(C);
+ int index = BKE_scene_transform_orientation_get_index(scene, target);
- if (i != -1) {
- View3D *v3d = CTX_wm_view3d(C);
- v3d->twmode = V3D_MANIP_CUSTOM + i;
- }
+ BLI_assert(index != -1);
+
+ scene->orientation_type = V3D_MANIP_CUSTOM;
+ scene->orientation_index_custom = index;
}
-void BIF_selectTransformOrientationValue(bContext *C, int orientation)
+/**
+ * Activate a transform orientation in a 3D view based on an enum value.
+ *
+ * \param orientation: If this is #V3D_MANIP_CUSTOM or greater, the custom transform orientation
+ * with index \a orientation - #V3D_MANIP_CUSTOM gets activated.
+ */
+void BIF_selectTransformOrientationValue(Scene *scene, int orientation)
{
- View3D *v3d = CTX_wm_view3d(C);
- if (v3d) /* currently using generic poll */
- v3d->twmode = orientation;
+ const bool is_custom = orientation >= V3D_MANIP_CUSTOM;
+ scene->orientation_type = is_custom ? V3D_MANIP_CUSTOM : orientation;
+ scene->orientation_index_custom = is_custom ? (orientation - V3D_MANIP_CUSTOM) : -1;
}
int BIF_countTransformOrientation(const bContext *C)
{
- ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
- return BLI_listbase_count(transform_spaces);
+ Scene *scene = CTX_data_scene(C);
+ ListBase *transform_orientations = &scene->transform_spaces;
+ return BLI_listbase_count(transform_orientations);
}
-bool applyTransformOrientation(const bContext *C, float mat[3][3], char *r_name, int index)
+bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name)
{
- ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
- TransformOrientation *ts = BLI_findlink(transform_spaces, index);
-
- BLI_assert(index >= 0);
-
- if (ts) {
- if (r_name) {
- BLI_strncpy(r_name, ts->name, MAX_NAME);
- }
-
- copy_m3_m3(mat, ts->mat);
- return true;
- }
- else {
- /* invalid index, can happen sometimes */
- return false;
+ if (r_name) {
+ BLI_strncpy(r_name, ts->name, MAX_NAME);
}
+ copy_m3_m3(r_mat, ts->mat);
+
+ return true;
}
static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
@@ -443,7 +432,7 @@ void initTransformOrientation(bContext *C, TransInfo *t)
Object *ob = CTX_data_active_object(C);
Object *obedit = CTX_data_active_object(C);
- switch (t->current_orientation) {
+ switch (t->orientation.user) {
case V3D_MANIP_GLOBAL:
unit_m3(t->spacemtx);
BLI_strncpy(t->spacename, IFACE_("global"), sizeof(t->spacename));
@@ -492,8 +481,20 @@ void initTransformOrientation(bContext *C, TransInfo *t)
unit_m3(t->spacemtx);
}
break;
- default: /* V3D_MANIP_CUSTOM */
- if (applyTransformOrientation(C, t->spacemtx, t->spacename, t->current_orientation - V3D_MANIP_CUSTOM)) {
+ case V3D_MANIP_CURSOR:
+ {
+ BLI_strncpy(t->spacename, IFACE_("cursor"), sizeof(t->spacename));
+ ED_view3d_cursor3d_calc_mat3(t->scene, t->spacemtx);
+ break;
+ }
+ case V3D_MANIP_CUSTOM_MATRIX:
+ /* Already set. */
+ BLI_strncpy(t->spacename, IFACE_("custom"), sizeof(t->spacename));
+ break;
+ case V3D_MANIP_CUSTOM:
+ BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename));
+
+ if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) {
/* pass */
}
else {
@@ -586,10 +587,11 @@ static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const
int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3], const short around)
{
- Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
Object *obedit = CTX_data_edit_object(C);
Base *base;
- Object *ob = OBACT;
+ Object *ob = OBACT(view_layer);
int result = ORIENTATION_NONE;
const bool activeOnly = (around == V3D_AROUND_ACTIVE);
@@ -838,7 +840,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
}
}
else {
- const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0;
+ const bool use_handle = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
@@ -974,6 +976,14 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
ok = true;
}
else {
+ /* When we only have the root/tip are selected. */
+ bool fallback_ok = false;
+ float fallback_normal[3];
+ float fallback_plane[3];
+
+ zero_v3(fallback_normal);
+ zero_v3(fallback_plane);
+
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (arm->layer & ebone->layer) {
if (ebone->flag & BONE_SELECTED) {
@@ -982,8 +992,23 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
add_v3_v3(plane, tmat[1]);
ok = true;
}
+ else if ((ok == false) &&
+ ((ebone->flag & BONE_TIPSEL) ||
+ ((ebone->flag & BONE_ROOTSEL) &&
+ (ebone->parent && ebone->flag & BONE_CONNECTED) == false)))
+ {
+ ED_armature_ebone_to_mat3(ebone, tmat);
+ add_v3_v3(fallback_normal, tmat[2]);
+ add_v3_v3(fallback_plane, tmat[1]);
+ fallback_ok = true;
+ }
}
}
+ if ((ok == false) && fallback_ok) {
+ ok = true;
+ copy_v3_v3(normal, fallback_normal);
+ copy_v3_v3(plane, fallback_plane);
+ }
}
if (ok) {
@@ -1056,15 +1081,15 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
}
else {
/* we need the one selected object, if its not active */
- View3D *v3d = CTX_wm_view3d(C);
- ob = OBACT;
- if (ob && (ob->flag & SELECT)) {
+ base = BASACT(view_layer);
+ ob = OBACT(view_layer);
+ if (base && ((base->flag & BASE_SELECTED) != 0)) {
/* pass */
}
else {
/* first selected */
ob = NULL;
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
if (TESTBASELIB(v3d, base)) {
ob = base->object;
break;
@@ -1125,6 +1150,9 @@ void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[3
type = ORIENTATION_NONE;
}
break;
+ default:
+ BLI_assert(type == ORIENTATION_NONE);
+ break;
}
if (type == ORIENTATION_NONE) {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index b06f22f50cc..eb8bdb26450 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -49,10 +49,11 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "BKE_anim.h" /* for duplis */
#include "BKE_context.h"
@@ -70,6 +71,8 @@
#include "ED_view3d.h"
#include "ED_transform_snap_object_context.h"
+#include "DEG_depsgraph.h"
+
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -153,82 +156,58 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (validSnap(t)) {
TransSnapPoint *p;
- View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float imat[4][4];
float size;
- glDisable(GL_DEPTH_TEST);
+ GPU_depth_test(false);
size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
invert_m4_m4(imat, rv3d->viewmat);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
for (p = t->tsnap.points.first; p; p = p->next) {
if (p == t->tsnap.selectedPoint) {
- glColor4ubv(selectedCol);
+ immUniformColor4ubv(selectedCol);
}
else {
- glColor4ubv(col);
+ immUniformColor4ubv(col);
}
- drawcircball(GL_LINE_LOOP, p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat);
+ imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos);
}
if (t->tsnap.status & POINT_INIT) {
- glColor4ubv(activeCol);
+ immUniformColor4ubv(activeCol);
- drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat);
+ imm_drawcircball(t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos);
}
/* draw normal if needed */
if (usingSnappingNormal(t) && validSnappingNormal(t)) {
- glColor4ubv(activeCol);
-
- glBegin(GL_LINES);
- glVertex3f(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
- glVertex3f(t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
- t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
- t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
- glEnd();
+ immUniformColor4ubv(activeCol);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
+ immVertex3f(pos, t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
+ t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
+ t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
+ immEnd();
}
- if (v3d->zbuf)
- glEnable(GL_DEPTH_TEST);
+ immUnbindProgram();
+
+ GPU_depth_test(true);
}
}
else if (t->spacetype == SPACE_IMAGE) {
if (validSnap(t)) {
/* This will not draw, and Im nor sure why - campbell */
-#if 0
- float xuser_asp, yuser_asp;
- int wi, hi;
- float w, h;
-
- calc_image_view(G.sima, 'f'); // float
- myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
- glLoadIdentity();
-
- ED_space_image_get_aspect(t->sa->spacedata.first, &xuser_aspx, &yuser_asp);
- ED_space_image_width(t->sa->spacedata.first, &wi, &hi);
- w = (((float)wi) / IMG_SIZE_FALLBACK) * G.sima->zoom * xuser_asp;
- h = (((float)hi) / IMG_SIZE_FALLBACK) * G.sima->zoom * yuser_asp;
-
- cpack(0xFFFFFF);
- glTranslate2fv(t->tsnap.snapPoint);
-
- //glRectf(0, 0, 1, 1);
-
- setlinestyle(0);
- cpack(0x0);
- fdrawline(-0.020 / w, 0, -0.1 / w, 0);
- fdrawline(0.1 / w, 0, 0.020 / w, 0);
- fdrawline(0, -0.020 / h, 0, -0.1 / h);
- fdrawline(0, 0.1 / h, 0, 0.020 / h);
-
- glTranslatef(-t->tsnap.snapPoint[0], -t->tsnap.snapPoint[1], 0.0f);
- setlinestyle(0);
-#endif
+ /* TODO: see 2.7x for non-working code */
}
}
else if (t->spacetype == SPACE_NODE) {
@@ -239,26 +218,32 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
- glEnable(GL_BLEND);
+ GPU_blend(true);
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
for (p = t->tsnap.points.first; p; p = p->next) {
if (p == t->tsnap.selectedPoint) {
- glColor4ubv(selectedCol);
+ immUniformColor4ubv(selectedCol);
}
else {
- glColor4ubv(col);
+ immUniformColor4ubv(col);
}
- ED_node_draw_snap(&ar->v2d, p->co, size, 0);
+ ED_node_draw_snap(&ar->v2d, p->co, size, 0, pos);
}
if (t->tsnap.status & POINT_INIT) {
- glColor4ubv(activeCol);
+ immUniformColor4ubv(activeCol);
- ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder);
+ ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos);
}
- glDisable(GL_BLEND);
+ immUnbindProgram();
+
+ GPU_blend(false);
}
}
}
@@ -284,93 +269,88 @@ eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
void applyProject(TransInfo *t)
{
- Main *bmain = CTX_data_main(t->context);
-
/* XXX FLICKER IN OBJECT MODE */
if ((t->tsnap.project) && activeSnap(t) && (t->flag & T_NO_PROJECT) == 0) {
- TransData *td = t->data;
float tvec[3];
- float imat[4][4];
int i;
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- invert_m4_m4(imat, ob->obmat);
- }
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float iloc[3], loc[3], no[3];
+ float mval_fl[2];
- for (i = 0; i < t->total; i++, td++) {
- float iloc[3], loc[3], no[3];
- float mval_fl[2];
- float dist_px = TRANSFORM_DIST_MAX_PX;
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_NOACTION)
- break;
+ if (td->flag & TD_SKIP)
+ continue;
- if (td->flag & TD_SKIP)
- continue;
+ if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
+ continue;
- if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
- continue;
-
- copy_v3_v3(iloc, td->loc);
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, iloc);
- }
- else if (t->flag & T_OBJECT) {
- BKE_object_eval_transform_all(bmain->eval_ctx, t->scene, td->ob);
- copy_v3_v3(iloc, td->ob->obmat[3]);
- }
+ copy_v3_v3(iloc, td->loc);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, iloc);
+ }
+ else if (t->flag & T_OBJECT) {
+ BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+ copy_v3_v3(iloc, td->ob->obmat[3]);
+ }
- if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- if (snapObjectsTransform(
- t, mval_fl, &dist_px,
- loc, no))
- {
-// if (t->flag & (T_EDIT|T_POSE)) {
-// mul_m4_v3(imat, loc);
-// }
+ if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ if (ED_transform_snap_object_project_view3d(
+ t->tsnap.object_context,
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .use_occlusion_test = false,
+ },
+ mval_fl, 0, loc, no))
+ {
+#if 0
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->imat, loc);
+ }
+#endif
- sub_v3_v3v3(tvec, loc, iloc);
+ sub_v3_v3v3(tvec, loc, iloc);
- mul_m3_v3(td->smtx, tvec);
+ mul_m3_v3(td->smtx, tvec);
- add_v3_v3(td->loc, tvec);
+ add_v3_v3(td->loc, tvec);
- if (t->tsnap.align && (t->flag & T_OBJECT)) {
- /* handle alignment as well */
- const float *original_normal;
- float mat[3][3];
+ if (t->tsnap.align && (t->flag & T_OBJECT)) {
+ /* handle alignment as well */
+ const float *original_normal;
+ float mat[3][3];
- /* In pose mode, we want to align normals with Y axis of bones... */
- original_normal = td->axismtx[2];
+ /* In pose mode, we want to align normals with Y axis of bones... */
+ original_normal = td->axismtx[2];
- rotation_between_vecs_to_mat3(mat, original_normal, no);
+ rotation_between_vecs_to_mat3(mat, original_normal, no);
- transform_data_ext_rotate(td, mat, true);
+ transform_data_ext_rotate(td, mat, true);
- /* TODO support constraints for rotation too? see ElementRotation */
+ /* TODO support constraints for rotation too? see ElementRotation */
+ }
}
}
- }
- //XXX constraintTransLim(t, td);
+ //XXX constraintTransLim(t, td);
+ }
}
}
}
void applyGridAbsolute(TransInfo *t)
{
- Main *bmain = CTX_data_main(t->context);
-
float grid_size = 0.0f;
GearsType grid_action;
- TransData *td;
- float (*obmat)[4] = NULL;
- bool use_obmat = false;
int i;
- if (!(activeSnap(t) && (ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID))))
+ if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID))))
return;
grid_action = BIG_GEARS;
@@ -386,57 +366,58 @@ void applyGridAbsolute(TransInfo *t)
if (grid_size == 0.0f)
return;
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- obmat = ob->obmat;
- use_obmat = true;
- }
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ TransData *td;
- for (i = 0, td = t->data; i < t->total; i++, td++) {
- float iloc[3], loc[3], tvec[3];
+ for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+ float iloc[3], loc[3], tvec[3];
- if (td->flag & TD_NOACTION)
- break;
+ if (td->flag & TD_NOACTION)
+ break;
- if (td->flag & TD_SKIP)
- continue;
+ if (td->flag & TD_SKIP)
+ continue;
- if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
- continue;
+ if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
+ continue;
- copy_v3_v3(iloc, td->loc);
- if (use_obmat) {
- mul_m4_v3(obmat, iloc);
- }
- else if (t->flag & T_OBJECT) {
- BKE_object_eval_transform_all(bmain->eval_ctx, t->scene, td->ob);
- copy_v3_v3(iloc, td->ob->obmat[3]);
- }
+ copy_v3_v3(iloc, td->loc);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, iloc);
+ }
+ else if (t->flag & T_OBJECT) {
+ BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+ copy_v3_v3(iloc, td->ob->obmat[3]);
+ }
- mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
- loc[0] = roundf(loc[0]);
- loc[1] = roundf(loc[1]);
- loc[2] = roundf(loc[2]);
- mul_v3_fl(loc, grid_size);
+ mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
+ loc[0] = roundf(loc[0]);
+ loc[1] = roundf(loc[1]);
+ loc[2] = roundf(loc[2]);
+ mul_v3_fl(loc, grid_size);
- sub_v3_v3v3(tvec, loc, iloc);
- mul_m3_v3(td->smtx, tvec);
- add_v3_v3(td->loc, tvec);
+ sub_v3_v3v3(tvec, loc, iloc);
+ mul_m3_v3(td->smtx, tvec);
+ add_v3_v3(td->loc, tvec);
+ }
}
}
void applySnapping(TransInfo *t, float *vec)
{
- /* project is not applied this way */
- if (t->tsnap.project)
+ if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) {
+ /* Each Trans Data already makes the snap to face */
return;
+ }
if (t->tsnap.status & SNAP_FORCED) {
t->tsnap.targetSnap(t);
t->tsnap.applySnap(t, vec);
}
- else if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t)) {
+ else if (((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) != 0) &&
+ activeSnap(t))
+ {
double current = PIL_check_seconds_timer();
// Time base quirky code to go around findnearest slowness
@@ -520,9 +501,10 @@ static void initSnappingMode(TransInfo *t)
{
Main *bmain = CTX_data_main(t->context);
ToolSettings *ts = t->settings;
- Object *obedit = t->obedit;
- Scene *scene = t->scene;
- Base *base_act = scene->basact;
+ /* All obedit types will match. */
+ const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1;
+ ViewLayer *view_layer = t->view_layer;
+ Base *base_act = view_layer->basact;
if (t->spacetype == SPACE_NODE) {
/* force project off when not supported */
@@ -538,7 +520,7 @@ static void initSnappingMode(TransInfo *t)
}
else {
/* force project off when not supported */
- if (ts->snap_mode != SCE_SNAP_MODE_FACE)
+ if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0)
t->tsnap.project = 0;
t->tsnap.mode = ts->snap_mode;
@@ -551,10 +533,10 @@ static void initSnappingMode(TransInfo *t)
/* Edit mode */
if (t->tsnap.applySnap != NULL && // A snapping function actually exist
- (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
+ ((obedit_type != -1) && ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
{
/* Exclude editmesh if using proportional edit */
- if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
+ if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
}
else {
@@ -563,17 +545,19 @@ static void initSnappingMode(TransInfo *t)
}
/* Particles edit mode*/
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
- (obedit == NULL && base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT))
+ ((obedit_type == -1) && base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT))
{
t->tsnap.modeSelect = SNAP_ALL;
}
/* Object mode */
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
- (obedit == NULL) ) // Object Mode
+ (obedit_type == -1) ) // Object Mode
{
/* In "Edit Strokes" mode, Snap tool can perform snap to selected or active objects (see T49632)
* TODO: perform self snap in gpencil_strokes */
- t->tsnap.modeSelect = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_ALL : SNAP_NOT_SELECTED;
+ t->tsnap.modeSelect = (
+ ((t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR)) != 0) ?
+ SNAP_ALL : SNAP_NOT_SELECTED);
}
else {
/* Grid if snap is not possible */
@@ -603,8 +587,7 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- bmain, t->scene, 0,
- t->ar, t->view);
+ bmain, t->scene, t->depsgraph, 0, t->ar, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
@@ -883,7 +866,8 @@ static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const f
return len_squared_v3v3(p1, p2);
}
-static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
+static float RotationBetween(
+ TransInfo *t, const float p1[3], const float p2[3])
{
float angle, start[3], end[3];
@@ -894,7 +878,7 @@ static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
float axis[3], tmp[3];
- t->con.applyRot(t, NULL, axis, NULL);
+ t->con.applyRot(t, NULL, NULL, axis, NULL);
project_v3_v3v3(tmp, end, axis);
sub_v3_v3v3(end, end, tmp);
@@ -974,18 +958,22 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
mval[0] = t->mval[0];
mval[1] = t->mval[1];
- if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) {
- found = peelObjectsTransform(
- t, mval,
- (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
- loc, no, NULL);
- }
- else {
+ if (t->tsnap.mode &
+ (SCE_SNAP_MODE_VERTEX |
+ SCE_SNAP_MODE_EDGE |
+ SCE_SNAP_MODE_FACE))
+ {
zero_v3(no); /* objects won't set this */
found = snapObjectsTransform(
t, mval, &dist_px,
loc, no);
}
+ if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
+ found = peelObjectsTransform(
+ t, mval,
+ (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
+ loc, no, NULL);
+ }
if (found == true) {
copy_v3_v3(t->tsnap.snapPoint, loc);
@@ -997,36 +985,45 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
t->tsnap.status &= ~POINT_INIT;
}
}
- else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type == OB_MESH) {
- /* same as above but for UV's */
- Image *ima = ED_space_image(t->sa->spacedata.first);
- float co[2];
+ else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
+ if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
+ Image *ima = ED_space_image(t->sa->spacedata.first);
+ float co[2];
- UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
+ UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
- if (ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint)) {
- t->tsnap.snapPoint[0] *= t->aspect[0];
- t->tsnap.snapPoint[1] *= t->aspect[1];
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ t->view_layer, NULL, &objects_len);
- t->tsnap.status |= POINT_INIT;
- }
- else {
- t->tsnap.status &= ~POINT_INIT;
+ float dist_sq = FLT_MAX;
+ if (ED_uvedit_nearest_uv_multi(t->scene, ima, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
+ t->tsnap.snapPoint[0] *= t->aspect[0];
+ t->tsnap.snapPoint[1] *= t->aspect[1];
+
+ t->tsnap.status |= POINT_INIT;
+ }
+ else {
+ t->tsnap.status &= ~POINT_INIT;
+ }
+ MEM_freeN(objects);
}
}
else if (t->spacetype == SPACE_NODE) {
- float loc[2];
- float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
- char node_border;
+ if (t->tsnap.mode & (SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y)) {
+ float loc[2];
+ float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
+ char node_border;
- if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) {
- copy_v2_v2(t->tsnap.snapPoint, loc);
- t->tsnap.snapNodeBorder = node_border;
+ if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) {
+ copy_v2_v2(t->tsnap.snapPoint, loc);
+ t->tsnap.snapNodeBorder = node_border;
- t->tsnap.status |= POINT_INIT;
- }
- else {
- t->tsnap.status &= ~POINT_INIT;
+ t->tsnap.status |= POINT_INIT;
+ }
+ else {
+ t->tsnap.status &= ~POINT_INIT;
+ }
}
}
}
@@ -1079,11 +1076,6 @@ static void TargetSnapActive(TransInfo *t)
/* Only need to calculate once */
if ((t->tsnap.status & TARGET_INIT) == 0) {
if (calculateCenterActive(t, true, t->tsnap.snapTarget)) {
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
- }
-
TargetSnapOffset(t, NULL);
t->tsnap.status |= TARGET_INIT;
@@ -1101,24 +1093,32 @@ static void TargetSnapMedian(TransInfo *t)
{
// Only need to calculate once
if ((t->tsnap.status & TARGET_INIT) == 0) {
- TransData *td = NULL;
- int i;
+ int i_accum = 0;
t->tsnap.snapTarget[0] = 0;
t->tsnap.snapTarget[1] = 0;
t->tsnap.snapTarget[2] = 0;
- for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
- add_v3_v3(t->tsnap.snapTarget, td->center);
- }
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ int i;
+ float v[3];
+ zero_v3(v);
+
+ for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
+ add_v3_v3(v, td->center);
+ }
- mul_v3_fl(t->tsnap.snapTarget, 1.0 / i);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, v);
+ }
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
+ add_v3_v3(t->tsnap.snapTarget, v);
+ i_accum += i;
}
+ mul_v3_fl(t->tsnap.snapTarget, 1.0 / i_accum);
+
TargetSnapOffset(t, NULL);
t->tsnap.status |= TARGET_INIT;
@@ -1130,24 +1130,44 @@ static void TargetSnapClosest(TransInfo *t)
// Only valid if a snap point has been selected
if (t->tsnap.status & POINT_INIT) {
float dist_closest = 0.0f;
- TransData *closest = NULL, *td = NULL;
+ TransData *closest = NULL;
/* Object mode */
if (t->flag & T_OBJECT) {
int i;
- for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
- struct BoundBox *bb = BKE_object_boundbox_get(td->ob);
-
- /* use boundbox if possible */
- if (bb) {
- int j;
-
- for (j = 0; j < 8; j++) {
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ TransData *td = tc->data;
+ for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
+ struct BoundBox *bb = BKE_object_boundbox_get(td->ob);
+
+ /* use boundbox if possible */
+ if (bb) {
+ int j;
+
+ for (j = 0; j < 8; j++) {
+ float loc[3];
+ float dist;
+
+ copy_v3_v3(loc, bb->vec[j]);
+ mul_m4_v3(td->ext->obmat, loc);
+
+ dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
+
+ if ((dist != TRANSFORM_DIST_INVALID) &&
+ (closest == NULL || fabsf(dist) < fabsf(dist_closest)))
+ {
+ copy_v3_v3(t->tsnap.snapTarget, loc);
+ closest = td;
+ dist_closest = dist;
+ }
+ }
+ }
+ /* use element center otherwise */
+ else {
float loc[3];
float dist;
- copy_v3_v3(loc, bb->vec[j]);
- mul_m4_v3(td->ext->obmat, loc);
+ copy_v3_v3(loc, td->center);
dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
@@ -1156,17 +1176,25 @@ static void TargetSnapClosest(TransInfo *t)
{
copy_v3_v3(t->tsnap.snapTarget, loc);
closest = td;
- dist_closest = dist;
}
}
}
- /* use element center otherwise */
- else {
+ }
+ }
+ else {
+ FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+ TransData *td = tc->data;
+ int i;
+ for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
float loc[3];
float dist;
copy_v3_v3(loc, td->center);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, loc);
+ }
+
dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
if ((dist != TRANSFORM_DIST_INVALID) &&
@@ -1174,34 +1202,11 @@ static void TargetSnapClosest(TransInfo *t)
{
copy_v3_v3(t->tsnap.snapTarget, loc);
closest = td;
+ dist_closest = dist;
}
}
}
}
- else {
- int i;
- for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
- float loc[3];
- float dist;
-
- copy_v3_v3(loc, td->center);
-
- if (t->flag & (T_EDIT | T_POSE)) {
- Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_m4_v3(ob->obmat, loc);
- }
-
- dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
-
- if ((dist != TRANSFORM_DIST_INVALID) &&
- (closest == NULL || fabsf(dist) < fabsf(dist_closest)))
- {
- copy_v3_v3(t->tsnap.snapTarget, loc);
- closest = td;
- dist_closest = dist;
- }
- }
- }
TargetSnapOffset(t, closest);
@@ -1214,16 +1219,15 @@ bool snapObjectsTransform(
float *dist_px,
float r_loc[3], float r_no[3])
{
- return ED_transform_snap_object_project_view3d_ex(
+ return ED_transform_snap_object_project_view3d(
t->tsnap.object_context,
t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE,
},
- mval, dist_px, NULL,
- r_loc, r_no, NULL,
- NULL, NULL);
+ mval, dist_px, r_loc, r_no);
}
@@ -1329,15 +1333,14 @@ static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select)
static NodeBorder snapNodeBorder(int snap_node_mode)
{
- switch (snap_node_mode) {
- case SCE_SNAP_MODE_NODE_X:
- return NODE_LEFT | NODE_RIGHT;
- case SCE_SNAP_MODE_NODE_Y:
- return NODE_TOP | NODE_BOTTOM;
- case SCE_SNAP_MODE_NODE_XY:
- return NODE_LEFT | NODE_RIGHT | NODE_TOP | NODE_BOTTOM;
+ NodeBorder flag = 0;
+ if (snap_node_mode & SCE_SNAP_MODE_NODE_X) {
+ flag |= NODE_LEFT | NODE_RIGHT;
}
- return 0;
+ if (snap_node_mode & SCE_SNAP_MODE_NODE_Y) {
+ flag |= NODE_TOP | NODE_BOTTOM;
+ }
+ return flag;
}
static bool snapNode(
@@ -1445,9 +1448,13 @@ void snapGridIncrement(TransInfo *t, float *val)
{
GearsType action;
- /* only do something if using absolute or incremental grid snapping */
- if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID))
+ /* only do something if using absolute or incremental grid snapping
+ * and there is no valid snap point */
+ if (!(t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) ||
+ validSnap(t))
+ {
return;
+ }
action = activeSnap(t) ? BIG_GEARS : NO_GEARS;
@@ -1463,7 +1470,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2])
float xmouse, ymouse;
int frame;
int mframe;
- TransSeq *ts = t->custom.type.data;
+ TransSeq *ts = TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
/* reuse increment, strictly speaking could be another snap mode, but leave as is */
if (!(t->modifiers & MOD_SNAP_INVERT))
return;
@@ -1487,7 +1494,7 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl
const float *asp = use_aspect ? t->aspect : asp_local;
int i;
- BLI_assert(ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID));
+ BLI_assert(t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID));
BLI_assert(max_index <= 2);
/* Early bailing out if no need to snap */
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 1c6ad1fe752..176e1852b01 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -41,16 +41,25 @@
#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_bvhutils.h"
+#include "BKE_armature.h"
+#include "BKE_curve.h"
#include "BKE_object.h"
#include "BKE_anim.h" /* for duplis */
#include "BKE_editmesh.h"
#include "BKE_main.h"
#include "BKE_tracking.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
@@ -63,6 +72,8 @@
/** Internal Data Types
* \{ */
+#define MAX_CLIPPLANE_LEN 3
+
enum eViewProj {
VIEW_PROJ_NONE = -1,
VIEW_PROJ_ORTHO = 0,
@@ -70,15 +81,13 @@ enum eViewProj {
};
typedef struct SnapData {
- short snap_to;
+ short snap_to_flag;
float mval[2];
- float ray_origin[3];
- float ray_start[3];
- float ray_dir[3];
float pmat[4][4]; /* perspective matrix */
- float win_half[2];/* win x and y */
+ float win_size[2];/* win x and y */
enum eViewProj view_proj;
- float depth_range[2];
+ float clip_plane[MAX_CLIPPLANE_LEN][4];
+ short clip_plane_len;
} SnapData;
typedef struct SnapObjectData {
@@ -90,21 +99,27 @@ typedef struct SnapObjectData {
typedef struct SnapObjectData_Mesh {
SnapObjectData sd;
- BVHTreeFromMesh *bvh_trees[3];
- MPoly *mpoly;
- bool poly_allocated;
+ BVHTreeFromMesh treedata;
+ const struct MPoly *poly;
+ BVHTree *bvhtree[2]; /* from loose verts and from loose edges */
+ uint has_looptris : 1;
+ uint has_loose_edge : 1;
+ uint has_loose_vert : 1;
} SnapObjectData_Mesh;
typedef struct SnapObjectData_EditMesh {
SnapObjectData sd;
BVHTreeFromEditMesh *bvh_trees[3];
+ float min[3], max[3];
} SnapObjectData_EditMesh;
struct SnapObjectContext {
Main *bmain;
Scene *scene;
+ Depsgraph *depsgraph;
+
int flag;
/* Optional: when performing screen-space projection.
@@ -140,11 +155,59 @@ struct SnapObjectContext {
/** Common Utilities
* \{ */
+/**
+ * Calculate the minimum and maximum coordinates of the box that encompasses this mesh.
+ */
+static void bm_mesh_minmax(BMesh *bm, float r_min[3], float r_max[3])
+{
+ INIT_MINMAX(r_min, r_max);
+ BMIter iter;
+ BMVert * v;
+
+ BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
+ minmax_v3v3_v3(r_min, r_max, v->co);
+ }
+}
+
+static SnapObjectData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob)
+{
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ BLI_assert(((SnapObjectData *)*sod_p)->type == SNAP_MESH);
+ }
+ else {
+ SnapObjectData_Mesh *sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_MESH;
+ /* start assuming that it has each of these element types */
+ sod->has_looptris = true;
+ sod->has_loose_edge = true;
+ sod->has_loose_vert = true;
+ }
+
+ return *sod_p;
+}
+
+/* Use `em->ob` as the key in ghash since the editmesh is used
+ * to create bvhtree and is the same for each linked object. */
+static SnapObjectData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx, BMEditMesh *em)
+{
+ void **sod_p;
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, em->ob, &sod_p)) {
+ BLI_assert(((SnapObjectData *)*sod_p)->type == SNAP_EDIT_MESH);
+ }
+ else {
+ SnapObjectData_EditMesh *sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ sod->sd.type = SNAP_EDIT_MESH;
+ bm_mesh_minmax(em->bm, sod->min, sod->max);
+ }
+
+ return *sod_p;
+}
typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data);
/**
- * Walks through all objects in the scene to create the list of objets to snap.
+ * Walks through all objects in the scene to create the list of objects to snap.
*
* \param sctx: Snap context to store data.
* \param snap_select : from enum eSnapSelect.
@@ -152,110 +215,36 @@ typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Obj
*/
static void iter_snap_objects(
SnapObjectContext *sctx,
- const eSnapSelect snap_select,
- Object *obedit,
+ const struct SnapObjectParams *params,
IterSnapObjsCallback sob_callback,
void *data)
{
- Base *base_act = sctx->scene->basact;
- for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {
- if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
- (base->flag & BA_SNAP_FIX_DEPS_FIASCO) == 0 &&
- !((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL))) ||
+ ViewLayer *view_layer = DEG_get_input_view_layer(sctx->depsgraph);
+ const View3D *v3d = sctx->v3d_data.v3d;
+ const eSnapSelect snap_select = params->snap_select;
+ const bool use_object_edit_cage = params->use_object_edit_cage;
+
+ Base *base_act = view_layer->basact;
+ for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
+ if ((BASE_VISIBLE_BGMODE(v3d, base)) && (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) == 0 &&
+ !((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) ||
(snap_select == SNAP_NOT_ACTIVE && base == base_act)))
{
- bool use_obedit;
- Object *obj = base->object;
- if (obj->transflag & OB_DUPLI) {
+ Object *obj_eval = DEG_get_evaluated_object(sctx->depsgraph, base->object);
+ if (obj_eval->transflag & OB_DUPLI) {
DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(sctx->bmain, sctx->bmain->eval_ctx, sctx->scene, obj);
+ ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval);
for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- use_obedit = obedit && dupli_ob->ob->data == obedit->data;
- sob_callback(sctx, use_obedit, use_obedit ? obedit : dupli_ob->ob, dupli_ob->mat, data);
+ sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data);
}
free_object_duplilist(lb);
}
- use_obedit = obedit && obj->data == obedit->data;
- sob_callback(sctx, use_obedit, use_obedit ? obedit : obj, obj->obmat, data);
+ sob_callback(sctx, use_object_edit_cage, obj_eval, obj_eval->obmat, data);
}
}
}
-
-/**
- * Generates a struct with the immutable parameters that will be used on all objects.
- *
- * \param snap_to: Element to snap, Vertice, Edge or Face.
- * \param view_proj: ORTHO or PERSP.
- * Currently only works one at a time, but can eventually operate as flag.
- *
- * \param mval: Mouse coords.
- * (When NULL, ray-casting is handled without any projection matrix correction.)
- * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min.
- * \param ray_start: ray_origin moved for the start clipping plane (clip_min).
- * \param ray_direction: Unit length direction of the ray.
- * \param depth_range: distances of clipe plane min and clip plane max;
- */
-static void snap_data_set(
- SnapData *snapdata,
- const ARegion *ar, const unsigned short snap_to, const enum eViewProj view_proj,
- const float mval[2], const float ray_origin[3], const float ray_start[3],
- const float ray_direction[3], const float depth_range[2])
-{
- copy_m4_m4(snapdata->pmat, ((RegionView3D *)ar->regiondata)->persmat);
- snapdata->win_half[0] = ar->winx / 2;
- snapdata->win_half[1] = ar->winy / 2;
- copy_v2_v2(snapdata->mval, mval);
- snapdata->snap_to = snap_to;
- copy_v3_v3(snapdata->ray_origin, ray_origin);
- copy_v3_v3(snapdata->ray_start, ray_start);
- copy_v3_v3(snapdata->ray_dir, ray_direction);
- snapdata->view_proj = view_proj;
- copy_v2_v2(snapdata->depth_range, depth_range);
-}
-
-
-MINLINE float depth_get(const float co[3], const float ray_start[3], const float ray_dir[3])
-{
- float dvec[3];
- sub_v3_v3v3(dvec, co, ray_start);
- return dot_v3v3(dvec, ray_dir);
-}
-
-
-static bool walk_parent_bvhroot_cb(const BVHTreeAxisRange *bounds, void *userdata)
-{
- BVHTreeRay *ray = userdata;
- const float bbmin[3] = {bounds[0].min, bounds[1].min, bounds[2].min};
- const float bbmax[3] = {bounds[0].max, bounds[1].max, bounds[2].max};
- if (!isect_ray_aabb_v3_simple(ray->origin, ray->direction, bbmin, bbmax, &ray->radius, NULL)) {
- ray->radius = -1;
- }
- return false;
-}
-
-
-static bool isect_ray_bvhroot_v3(struct BVHTree *tree, const float ray_start[3], const float ray_dir[3], float *depth)
-{
- BVHTreeRay ray;
- copy_v3_v3(ray.origin, ray_start);
- copy_v3_v3(ray.direction, ray_dir);
-
- BLI_bvhtree_walk_dfs(tree, walk_parent_bvhroot_cb, NULL, NULL, &ray);
-
- if (ray.radius > 0) {
- *depth = ray.radius;
- return true;
- }
- else {
- return false;
- }
-}
-
-
-static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -338,14 +327,6 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
mul_m3_v3((float(*)[3])data->timat, normal);
normalize_v3(normal);
- /* currently unused, and causes issues when looptri's haven't been calculated.
- * since theres some overhead in ensuring this data is valid, it may need to be optional. */
-#if 0
- if (data->dm) {
- hit->index = dm_looptri_to_poly_index(data->dm, &data->dm_looptri[hit->index]);
- }
-#endif
-
struct SnapObjectHitDepth *hit_item = hit_depth_create(
depth, location, normal, hit->index,
data->ob, data->obmat, data->ob_uuid);
@@ -354,10 +335,10 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
}
-static bool raycastDerivedMesh(
+static bool raycastMesh(
SnapObjectContext *sctx,
const float ray_start[3], const float ray_dir[3],
- Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
+ Object *ob, Mesh *me, float obmat[4][4], const unsigned int ob_index,
/* read/write args */
float *ray_depth,
/* return args */
@@ -366,17 +347,15 @@ static bool raycastDerivedMesh(
{
bool retval = false;
- if (dm->getNumPolys(dm) == 0) {
+ if (me->totpoly == 0) {
return retval;
}
float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
float ray_start_local[3], ray_normal_local[3];
float local_scale, local_depth, len_diff = 0.0f;
invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
copy_v3_v3(ray_start_local, ray_start);
copy_v3_v3(ray_normal_local, ray_dir);
@@ -392,7 +371,7 @@ static bool raycastDerivedMesh(
}
/* Test BoundBox */
- BoundBox *bb = BKE_object_boundbox_get(ob);
+ BoundBox *bb = BKE_mesh_boundbox_get(ob);
if (bb) {
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!isect_ray_aabb_v3_simple(
@@ -401,85 +380,60 @@ static bool raycastDerivedMesh(
return retval;
}
}
-
- SnapObjectData_Mesh *sod = NULL;
- BVHTreeFromMesh *treedata;
-
- void **sod_p;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- sod = *sod_p;
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
+ * very far away ray_start values (as returned in case of ortho view3d), see T50486, T38358.
+ */
+ if (len_diff > 400.0f) {
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
+ local_depth -= len_diff;
}
else {
- sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_MESH;
+ len_diff = 0.0f;
}
- if (sod->bvh_trees[2] == NULL) {
- sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
- }
+ SnapObjectData_Mesh *sod = snap_object_data_mesh_get(sctx, ob);
- treedata = sod->bvh_trees[2];
+ BVHTreeFromMesh *treedata = &sod->treedata;
- if (treedata) {
- /* the tree is owned by the DM and may have been freed since we last used! */
- if (treedata->tree) {
- if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
- free_bvhtree_from_mesh(treedata);
+ /* The tree is owned by the Mesh and may have been freed since we last used. */
+ if (treedata->tree) {
+ BLI_assert(treedata->cached);
+ if (!bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) {
+ free_bvhtree_from_mesh(treedata);
+ }
+ else {
+ /* Update Pointers. */
+ if (treedata->vert && treedata->vert_allocated == false) {
+ treedata->vert = me->mvert;
}
- else {
- if (treedata->vert == NULL) {
- treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated);
- }
- if (treedata->loop == NULL) {
- treedata->loop = DM_get_loop_array(dm, &treedata->loop_allocated);
- }
- if (treedata->looptri == NULL) {
- if (sod->mpoly == NULL) {
- sod->mpoly = DM_get_poly_array(dm, &sod->poly_allocated);
- }
- treedata->looptri = dm->getLoopTriArray(dm);
- treedata->looptri_allocated = false;
- }
+ if (treedata->loop && treedata->loop_allocated == false) {
+ treedata->loop = me->mloop;
}
- }
-
- if (treedata->tree == NULL) {
- bvhtree_from_mesh_get(treedata, dm, BVHTREE_FROM_LOOPTRI, 4);
-
- if (treedata->tree == NULL) {
- return retval;
+ if (treedata->looptri && treedata->looptri_allocated == false) {
+ treedata->looptri = BKE_mesh_runtime_looptri_ensure(me);
}
+ /* required for snapping with occlusion. */
+ treedata->edge = me->medge;
+ sod->poly = me->mpoly;
}
}
- else {
- return retval;
- }
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (len_diff == 0.0f) { /* do_ray_start_correction */
- /* We *need* a reasonably valid len_diff in this case.
- * Get the distance to bvhtree root */
- if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) {
+ if (treedata->tree == NULL) {
+ BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4);
+
+ /* required for snapping with occlusion. */
+ treedata->edge = me->medge;
+ sod->poly = me->mpoly;
+
+ if (treedata->tree == NULL) {
return retval;
}
}
- /* You need to make sure that ray_start is really far away,
- * because even in the Orthografic view, in some cases,
- * the ray can start inside the object (see T50486) */
- if (len_diff > 400.0f) {
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
- * very far away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
- local_depth -= len_diff;
- }
- else {
- len_diff = 0.0f;
- }
+
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ transpose_m3_m4(timat, imat);
+
if (r_hit_list) {
struct RayCastAll_Data data;
@@ -525,7 +479,7 @@ static bool raycastDerivedMesh(
retval = true;
if (r_index) {
- *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]);
+ *r_index = treedata->looptri[hit.index].poly;
}
}
}
@@ -549,91 +503,100 @@ static bool raycastEditMesh(
return retval;
}
- SnapObjectData_EditMesh *sod = NULL;
- BVHTreeFromEditMesh *treedata = NULL;
+ BLI_assert(BKE_object_get_pre_modified_mesh(em->ob) == BKE_object_get_pre_modified_mesh(ob));
- void **sod_p;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- sod = *sod_p;
+ float imat[4][4];
+ float ray_start_local[3], ray_normal_local[3];
+ float local_scale, local_depth, len_diff = 0.0f;
+
+ invert_m4_m4(imat, obmat);
+
+ copy_v3_v3(ray_start_local, ray_start);
+ copy_v3_v3(ray_normal_local, ray_dir);
+
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+
+ /* local scale in normal direction */
+ local_scale = normalize_v3(ray_normal_local);
+ local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
+
+ SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, em);
+
+ /* Test BoundBox */
+
+ /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
+ if (!isect_ray_aabb_v3_simple(
+ ray_start_local, ray_normal_local, sod->min, sod->max, &len_diff, NULL))
+ {
+ return retval;
+ }
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
+ * very far away ray_start values (as returned in case of ortho view3d), see T50486, T38358.
+ */
+ if (len_diff > 400.0f) {
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
+ local_depth -= len_diff;
}
else {
- sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_EDIT_MESH;
+ len_diff = 0.0f;
}
if (sod->bvh_trees[2] == NULL) {
- sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(BVHTreeFromEditMesh));
}
- treedata = sod->bvh_trees[2];
- if (treedata) {
- if (treedata->tree == NULL) {
- BLI_bitmap *elem_mask = NULL;
- int looptri_num_active = -1;
-
- if (sctx->callbacks.edit_mesh.test_face_fn) {
- elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
- looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
- em->bm, elem_mask,
- sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
- }
- bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, NULL);
+ BVHTreeFromEditMesh *treedata = sod->bvh_trees[2];
- if (elem_mask) {
- MEM_freeN(elem_mask);
- }
- }
- if (treedata->tree == NULL) {
- return retval;
+ BVHCache *em_bvh_cache = ((Mesh *)em->ob->data)->runtime.bvh_cache;
+
+ if (sctx->callbacks.edit_mesh.test_face_fn == NULL) {
+ /* The tree is owned by the Mesh and may have been freed since we last used! */
+ if (!bvhcache_has_tree(em_bvh_cache, treedata->tree)) {
+ free_bvhtree_from_editmesh(treedata);
}
}
- else {
- return retval;
- }
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_normal_local[3], ray_start_local[3], len_diff = 0.0f;
+ if (treedata->tree == NULL) {
+ BVHCache **bvh_cache = NULL;
+ BLI_bitmap *elem_mask = NULL;
+ int looptri_num_active = -1;
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
-
- copy_v3_v3(ray_normal_local, ray_dir);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ if (sctx->callbacks.edit_mesh.test_face_fn) {
+ elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
+ looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
+ em->bm, elem_mask,
+ sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data);
+ }
+ else {
+ /* Only cache if bvhtree is created without a mask.
+ * This helps keep a standardized bvhtree in cache. */
+ bvh_cache = &em_bvh_cache;
+ }
- copy_v3_v3(ray_start_local, ray_start);
- mul_m4_v3(imat, ray_start_local);
+ /* Get original version of the edit_btmesh. */
+ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
- /* local scale in normal direction */
- float local_scale = normalize_v3(ray_normal_local);
- float local_depth = *ray_depth;
- if (local_depth != BVH_RAYCAST_DIST_MAX) {
- local_depth *= local_scale;
- }
+ bvhtree_from_editmesh_looptri_ex(
+ treedata, em_orig, elem_mask, looptri_num_active,
+ 0.0f, 4, 6, bvh_cache);
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start
- * may already been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp) { /* do_ray_start_correction */
- /* We *need* a reasonably valid len_diff in this case.
- * Get the distance to bvhtree root */
- if (!isect_ray_bvhroot_v3(treedata->tree, ray_start_local, ray_normal_local, &len_diff)) {
- return retval;
+ if (elem_mask) {
+ MEM_freeN(elem_mask);
}
- /* You need to make sure that ray_start is really far away,
- * because even in the Orthografic view, in some cases,
- * the ray can start inside the object (see T50486) */
- if (len_diff > 400.0f) {
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with
- * very far away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3fl(ray_start_local, ray_normal_local, len_diff);
- local_depth -= len_diff;
+ if (treedata->tree == NULL) {
+ return retval;
}
- else len_diff = 0.0f;
}
+
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ transpose_m3_m4(timat, imat);
+
if (r_hit_list) {
struct RayCastAll_Data data;
@@ -679,7 +642,10 @@ static bool raycastEditMesh(
retval = true;
if (r_index) {
- *r_index = hit.index;
+ /* Get original version of the edit_btmesh. */
+ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
+
+ *r_index = BM_elem_index_get(em_orig->looptris[hit.index][0]->f);
}
}
}
@@ -698,7 +664,7 @@ static bool raycastObj(
SnapObjectContext *sctx,
const float ray_start[3], const float ray_dir[3],
Object *ob, float obmat[4][4], const unsigned int ob_index,
- bool use_obedit,
+ bool use_obedit, bool use_occlusion_test,
/* read/write args */
float *ray_depth,
/* return args */
@@ -708,44 +674,53 @@ static bool raycastObj(
{
bool retval = false;
- if (ob->type == OB_MESH) {
- BMEditMesh *em;
-
- if (use_obedit) {
- em = BKE_editmesh_from_object(ob);
- retval = raycastEditMesh(
- sctx,
- ray_start, ray_dir,
- ob, em, obmat, ob_index,
- ray_depth, r_loc, r_no, r_index, r_hit_list);
+ if (use_occlusion_test) {
+ if (use_obedit && sctx->use_v3d &&
+ !V3D_IS_ZBUF(sctx->v3d_data.v3d))
+ {
+ /* Use of occlude geometry in editing mode disabled. */
+ return false;
}
- else {
- /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
- * still set the 'em' to NULL, since we only want the 'dm'. */
- DerivedMesh *dm;
- em = BKE_editmesh_from_object(ob);
- if (em) {
- editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm);
- }
- else {
- dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
+ }
+
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ Mesh *me = ob->data;
+ if (BKE_object_is_in_editmode(ob)) {
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ if (use_obedit) {
+ retval = raycastEditMesh(
+ sctx,
+ ray_start, ray_dir,
+ ob, em, obmat, ob_index,
+ ray_depth, r_loc, r_no, r_index, r_hit_list);
+ break;
+ }
+ else if (em->mesh_eval_final) {
+ me = em->mesh_eval_final;
+ }
}
- retval = raycastDerivedMesh(
+ retval = raycastMesh(
sctx,
ray_start, ray_dir,
- ob, dm, obmat, ob_index,
+ ob, me, obmat, ob_index,
ray_depth, r_loc, r_no, r_index, r_hit_list);
+ break;
}
}
if (retval) {
if (r_ob) {
*r_ob = ob;
+ }
+ if (r_obmat) {
copy_m4_m4(r_obmat, obmat);
}
+ return true;
}
- return retval;
+ return false;
}
@@ -762,16 +737,19 @@ struct RaycastObjUserData {
Object **r_ob;
float (*r_obmat)[4];
ListBase *r_hit_list;
+ bool use_occlusion_test;
bool ret;
};
-static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
+static void raycast_obj_cb(SnapObjectContext *sctx, bool use_obedit, Object *ob, float obmat[4][4], void *data)
{
struct RaycastObjUserData *dt = data;
+
dt->ret |= raycastObj(
sctx,
dt->ray_start, dt->ray_dir,
- ob, obmat, dt->ob_index++, is_obedit,
+ ob, obmat, dt->ob_index++,
+ use_obedit, dt->use_occlusion_test,
dt->ray_depth,
dt->r_loc, dt->r_no, dt->r_index,
dt->r_ob, dt->r_obmat,
@@ -808,8 +786,8 @@ static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob,
*/
static bool raycastObjects(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3], const float ray_dir[3],
- const eSnapSelect snap_select, const bool use_object_edit_cage,
/* read/write args */
float *ray_depth,
/* return args */
@@ -817,8 +795,6 @@ static bool raycastObjects(
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
-
struct RaycastObjUserData data = {
.ray_start = ray_start,
.ray_dir = ray_dir,
@@ -830,10 +806,11 @@ static bool raycastObjects(
.r_ob = r_ob,
.r_obmat = r_obmat,
.r_hit_list = r_hit_list,
+ .use_occlusion_test = params->use_occlusion_test,
.ret = false,
};
- iter_snap_objects(sctx, snap_select, obedit, raycast_obj_cb, &data);
+ iter_snap_objects(sctx, params, raycast_obj_cb, &data);
return data.ret;
}
@@ -845,65 +822,127 @@ static bool raycastObjects(
/** Snap Nearest utilities
* \{ */
-static void copy_dm_vert_no(const int index, float r_no[3], const BVHTreeFromMesh *data)
+ /* Test BoundBox */
+static bool snap_bound_box_check_dist(
+ float min[3], float max[3], float lpmat[4][4],
+ float win_size[2], float mval[2], float dist_px_sq)
+{
+ /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */
+
+ struct DistProjectedAABBPrecalc data_precalc;
+ dist_squared_to_projected_aabb_precalc(
+ &data_precalc, lpmat, win_size, mval);
+
+ bool dummy[3];
+ float bb_dist_px_sq = dist_squared_to_projected_aabb(
+ &data_precalc, min, max, dummy);
+
+ if (bb_dist_px_sq > dist_px_sq) {
+ return false;
+ }
+ return true;
+}
+
+static void cb_mvert_co_get(
+ const int index, const float **co, const BVHTreeFromMesh *data)
+{
+ *co = data->vert[index].co;
+}
+
+static void cb_bvert_co_get(
+ const int index, const float **co, const BMEditMesh *data)
+{
+ BMVert *eve = BM_vert_at_index(data->bm, index);
+ *co = eve->co;
+}
+
+static void cb_mvert_no_copy(
+ const int index, float r_no[3], const BVHTreeFromMesh *data)
{
const MVert *vert = data->vert + index;
normal_short_to_float_v3(r_no, vert->no);
}
-static void copy_bvert_no(const int index, float r_no[3], const BVHTreeFromEditMesh *data)
+static void cb_bvert_no_copy(
+ const int index, float r_no[3], const BMEditMesh *data)
{
- BMVert *eve = BM_vert_at_index(data->em->bm, index);
+ BMVert *eve = BM_vert_at_index(data->bm, index);
copy_v3_v3(r_no, eve->no);
}
-static void get_dm_edge_verts(const int index, const float *v_pair[2], const BVHTreeFromMesh *data)
+static void cb_medge_verts_get(
+ const int index, int v_index[2], const BVHTreeFromMesh *data)
{
- const MVert *vert = data->vert;
- const MEdge *edge = data->edge + index;
+ const MEdge *edge = &data->edge[index];
+
+ v_index[0] = edge->v1;
+ v_index[1] = edge->v2;
- v_pair[0] = vert[edge->v1].co;
- v_pair[1] = vert[edge->v2].co;
}
-static void get_bedge_verts(const int index, const float *v_pair[2], const BVHTreeFromEditMesh *data)
+static void cb_bedge_verts_get(
+ const int index, int v_index[2], const BMEditMesh *data)
{
- BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+ BMEdge *eed = BM_edge_at_index(data->bm, index);
+
+ v_index[0] = BM_elem_index_get(eed->v1);
+ v_index[1] = BM_elem_index_get(eed->v2);
+}
- v_pair[0] = eed->v1->co;
- v_pair[1] = eed->v2->co;
+static void cb_mlooptri_edges_get(
+ const int index, int v_index[3], const BVHTreeFromMesh *data)
+{
+ const MEdge *medge = data->edge;
+ const MLoop *mloop = data->loop;
+ const MLoopTri *lt = &data->looptri[index];
+ for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
+ const MEdge *ed = &medge[mloop[lt->tri[j]].e];
+ unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
+ if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) &&
+ ELEM(ed->v2, tri_edge[0], tri_edge[1]))
+ {
+ //printf("real edge found\n");
+ v_index[j] = mloop[lt->tri[j]].e;
+ }
+ else
+ v_index[j] = -1;
+ }
+}
+
+static void cb_mlooptri_verts_get(
+ const int index, int v_index[3], const BVHTreeFromMesh *data)
+{
+ const MLoop *loop = data->loop;
+ const MLoopTri *looptri = &data->looptri[index];
+
+ v_index[0] = loop[looptri->tri[0]].v;
+ v_index[1] = loop[looptri->tri[1]].v;
+ v_index[2] = loop[looptri->tri[2]].v;
}
static bool test_projected_vert_dist(
- const float depth_range[2], const float mval[2], const float co[3],
- float pmat[4][4], const float win_half[2], const bool is_persp,
+ const struct DistProjectedAABBPrecalc *precalc,
+ const float (*clip_plane)[4], const int clip_plane_len,
+ const bool is_persp, const float co[3],
float *dist_px_sq, float r_co[3])
{
- float depth;
- if (is_persp) {
- depth = mul_project_m4_v3_zfac(pmat, co);
- if (depth < depth_range[0] || depth > depth_range[1]) {
- return false;
- }
+ if (!isect_point_planes_v3_negated(clip_plane, clip_plane_len, co)) {
+ return false;
}
float co2d[2] = {
- (dot_m4_v3_row_x(pmat, co) + pmat[3][0]),
- (dot_m4_v3_row_y(pmat, co) + pmat[3][1]),
+ (dot_m4_v3_row_x(precalc->pmat, co) + precalc->pmat[3][0]),
+ (dot_m4_v3_row_y(precalc->pmat, co) + precalc->pmat[3][1]),
};
if (is_persp) {
- mul_v2_fl(co2d, 1 / depth);
+ float w = mul_project_m4_v3_zfac(precalc->pmat, co);
+ mul_v2_fl(co2d, 1.0f / w);
}
- co2d[0] += 1.0f;
- co2d[1] += 1.0f;
- co2d[0] *= win_half[0];
- co2d[1] *= win_half[1];
-
- const float dist_sq = len_squared_v2v2(mval, co2d);
+ const float dist_sq = len_squared_v2v2(precalc->mval, co2d);
if (dist_sq < *dist_px_sq) {
copy_v3_v3(r_co, co);
*dist_px_sq = dist_sq;
@@ -913,395 +952,490 @@ static bool test_projected_vert_dist(
}
static bool test_projected_edge_dist(
- const float depth_range[2], const float mval[2],
- float pmat[4][4], const float win_half[2], const bool is_persp,
- const float ray_start[3], const float ray_dir[3],
- const float va[3], const float vb[3],
+ const struct DistProjectedAABBPrecalc *precalc,
+ const float (*clip_plane)[4], const int clip_plane_len,
+ const bool is_persp, const float va[3], const float vb[3],
float *dist_px_sq, float r_co[3])
{
+ float near_co[3], lambda;
+ if (!isect_ray_seg_v3(
+ precalc->ray_origin,
+ precalc->ray_direction,
+ va, vb, &lambda))
+ {
+ copy_v3_v3(near_co, va);
+ }
+ else {
+ if (lambda <= 0.0f) {
+ copy_v3_v3(near_co, va);
+ }
+ else if (lambda >= 1.0f) {
+ copy_v3_v3(near_co, vb);
+ }
+ else {
+ interp_v3_v3v3(near_co, va, vb, lambda);
+ }
+ }
- float tmp_co[3], depth;
- dist_squared_ray_to_seg_v3(ray_start, ray_dir, va, vb, tmp_co, &depth);
- return test_projected_vert_dist(depth_range, mval, tmp_co, pmat, win_half, is_persp, dist_px_sq, r_co);
+ return test_projected_vert_dist(
+ precalc, clip_plane, clip_plane_len,
+ is_persp, near_co, dist_px_sq, r_co);
}
-typedef struct Nearest2dPrecalc {
- float ray_origin_local[3];
- float ray_direction_local[3];
- float ray_inv_dir[3];
- float ray_min_dist;
- float pmat[4][4]; /* perspective matrix multiplied by object matrix */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** Walk DFS
+ * \{ */
+
+typedef void (*Nearest2DGetVertCoCallback)(const int index, const float **co, void *data);
+typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, int v_index[2], void *data);
+typedef void (*Nearest2DGetTriVertsCallback)(const int index, int v_index[3], void *data);
+typedef void (*Nearest2DGetTriEdgesCallback)(const int index, int e_index[3], void *data); /* Equal the previous one */
+typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void *data);
+
+typedef struct Nearest2dUserData {
bool is_persp;
- float win_half[2];
- float mval[2];
- bool sign[3];
-} Nearest2dPrecalc;
+ void *userdata;
+ Nearest2DGetVertCoCallback get_vert_co;
+ Nearest2DGetEdgeVertsCallback get_edge_verts_index;
+ Nearest2DGetTriVertsCallback get_tri_verts_index;
+ Nearest2DGetTriEdgesCallback get_tri_edges_index;
+ Nearest2DCopyVertNoCallback copy_vert_no;
-/**
- * \param lpmat: Perspective matrix multiplied by object matrix
- */
-static void dist_squared_to_projected_aabb_precalc(
- struct Nearest2dPrecalc *neasrest_precalc,
- float lpmat[4][4], bool is_persp, const float win_half[2],
- const float ray_min_dist, const float mval[2],
- const float ray_origin_local[3], const float ray_direction_local[3])
+} Nearest2dUserData;
+
+
+static void cb_snap_vert(
+ void *userdata, int index,
+ const struct DistProjectedAABBPrecalc *precalc,
+ const float (*clip_plane)[4], const int clip_plane_len,
+ BVHTreeNearest *nearest)
{
- copy_m4_m4(neasrest_precalc->pmat, lpmat);
- neasrest_precalc->is_persp = is_persp;
- copy_v2_v2(neasrest_precalc->win_half, win_half);
- neasrest_precalc->ray_min_dist = ray_min_dist;
+ struct Nearest2dUserData *data = userdata;
- copy_v3_v3(neasrest_precalc->ray_origin_local, ray_origin_local);
- copy_v3_v3(neasrest_precalc->ray_direction_local, ray_direction_local);
- copy_v2_v2(neasrest_precalc->mval, mval);
+ const float *co;
+ data->get_vert_co(index, &co, data->userdata);
- for (int i = 0; i < 3; i++) {
- neasrest_precalc->ray_inv_dir[i] =
- (neasrest_precalc->ray_direction_local[i] != 0.0f) ?
- (1.0f / neasrest_precalc->ray_direction_local[i]) : FLT_MAX;
- neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f);
+ if (test_projected_vert_dist(
+ precalc,
+ clip_plane,
+ clip_plane_len,
+ data->is_persp, co,
+ &nearest->dist_sq,
+ nearest->co))
+ {
+ data->copy_vert_no(index, nearest->no, data->userdata);
+ nearest->index = index;
}
}
-/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */
-static float dist_squared_to_projected_aabb(
- struct Nearest2dPrecalc *data,
- const float bbmin[3], const float bbmax[3],
- bool r_axis_closest[3])
+static void cb_snap_edge(
+ void *userdata, int index,
+ const struct DistProjectedAABBPrecalc *precalc,
+ const float (*clip_plane)[4], const int clip_plane_len,
+ BVHTreeNearest *nearest)
{
- float local_bvmin[3], local_bvmax[3];
- if (data->sign[0]) {
- local_bvmin[0] = bbmax[0];
- local_bvmax[0] = bbmin[0];
- }
- else {
- local_bvmin[0] = bbmin[0];
- local_bvmax[0] = bbmax[0];
- }
- if (data->sign[1]) {
- local_bvmin[1] = bbmax[1];
- local_bvmax[1] = bbmin[1];
- }
- else {
- local_bvmin[1] = bbmin[1];
- local_bvmax[1] = bbmax[1];
- }
- if (data->sign[2]) {
- local_bvmin[2] = bbmax[2];
- local_bvmax[2] = bbmin[2];
- }
- else {
- local_bvmin[2] = bbmin[2];
- local_bvmax[2] = bbmax[2];
- }
+ struct Nearest2dUserData *data = userdata;
- const float tmin[3] = {
- (local_bvmin[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0],
- (local_bvmin[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1],
- (local_bvmin[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2],
- };
- const float tmax[3] = {
- (local_bvmax[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0],
- (local_bvmax[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1],
- (local_bvmax[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2],
- };
- /* `va` and `vb` are the coordinates of the AABB edge closest to the ray */
- float va[3], vb[3];
- /* `rtmin` and `rtmax` are the minimum and maximum distances of the ray hits on the AABB */
- float rtmin, rtmax;
- int main_axis;
-
- if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
- rtmax = tmax[0];
- va[0] = vb[0] = local_bvmax[0];
- main_axis = 3;
- r_axis_closest[0] = data->sign[0];
- }
- else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
- rtmax = tmax[1];
- va[1] = vb[1] = local_bvmax[1];
- main_axis = 2;
- r_axis_closest[1] = data->sign[1];
- }
- else {
- rtmax = tmax[2];
- va[2] = vb[2] = local_bvmax[2];
- main_axis = 1;
- r_axis_closest[2] = data->sign[2];
- }
+ int vindex[2];
+ data->get_edge_verts_index(index, vindex, data->userdata);
- if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
- rtmin = tmin[0];
- va[0] = vb[0] = local_bvmin[0];
- main_axis -= 3;
- r_axis_closest[0] = !data->sign[0];
- }
- else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
- rtmin = tmin[1];
- va[1] = vb[1] = local_bvmin[1];
- main_axis -= 1;
- r_axis_closest[1] = !data->sign[1];
- }
- else {
- rtmin = tmin[2];
- va[2] = vb[2] = local_bvmin[2];
- main_axis -= 2;
- r_axis_closest[2] = !data->sign[2];
- }
- if (main_axis < 0) {
- main_axis += 3;
- }
+ const float *v_pair[2];
+ data->get_vert_co(vindex[0], &v_pair[0], data->userdata);
+ data->get_vert_co(vindex[1], &v_pair[1], data->userdata);
-#define IGNORE_BEHIND_RAY
-#ifdef IGNORE_BEHIND_RAY
- float depth_max = depth_get(local_bvmax, data->ray_origin_local, data->ray_direction_local);
- if (depth_max < data->ray_min_dist) {
- return FLT_MAX;
+ if (test_projected_edge_dist(
+ precalc,
+ clip_plane,
+ clip_plane_len,
+ data->is_persp,
+ v_pair[0], v_pair[1],
+ &nearest->dist_sq,
+ nearest->co))
+ {
+ sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]);
+ nearest->index = index;
}
-#endif
-#undef IGNORE_BEHIND_RAY
+}
- /* if rtmin <= rtmax, ray intersect `AABB` */
- if (rtmin <= rtmax) {
- return 0;
+static void cb_snap_edge_verts(
+ void *userdata, int index,
+ const struct DistProjectedAABBPrecalc *precalc,
+ const float (*clip_plane)[4], const int clip_plane_len,
+ BVHTreeNearest *nearest)
+{
+ struct Nearest2dUserData *data = userdata;
+
+ int vindex[2];
+ data->get_edge_verts_index(index, vindex, data->userdata);
+
+ for (int i = 2; i--;) {
+ if (vindex[i] == nearest->index) {
+ continue;
+ }
+ cb_snap_vert(
+ userdata, vindex[i], precalc,
+ clip_plane, clip_plane_len, nearest);
}
+}
+
+static void cb_snap_tri_edges(
+ void *userdata, int index,
+ const struct DistProjectedAABBPrecalc *precalc,
+ const float (*clip_plane)[4], const int clip_plane_len,
+ BVHTreeNearest *nearest)
+{
+ struct Nearest2dUserData *data = userdata;
- if (data->sign[main_axis]) {
- va[main_axis] = local_bvmax[main_axis];
- vb[main_axis] = local_bvmin[main_axis];
+ int eindex[3];
+ data->get_tri_edges_index(index, eindex, data->userdata);
+ for (int i = 3; i--;) {
+ if (eindex[i] != -1) {
+ if (eindex[i] == nearest->index) {
+ continue;
+ }
+ cb_snap_edge(
+ userdata, eindex[i], precalc,
+ clip_plane, clip_plane_len, nearest);
+ }
}
- else {
- va[main_axis] = local_bvmin[main_axis];
- vb[main_axis] = local_bvmax[main_axis];
+}
+
+static void cb_snap_tri_verts(
+ void *userdata, int index,
+ const struct DistProjectedAABBPrecalc *precalc,
+ const float (*clip_plane)[4], const int clip_plane_len,
+ BVHTreeNearest *nearest)
+{
+ struct Nearest2dUserData *data = userdata;
+
+ int vindex[3];
+ data->get_tri_verts_index(index, vindex, data->userdata);
+ for (int i = 3; i--;) {
+ if (vindex[i] == nearest->index) {
+ continue;
+ }
+ cb_snap_vert(
+ userdata, vindex[i], precalc,
+ clip_plane, clip_plane_len, nearest);
}
- float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Object Snapping API
+ * \{ */
+
+static short snap_mesh_polygon(
+ SnapObjectContext *sctx, SnapData *snapdata,
+ Object *ob, float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index)
+{
+ short elem = 0;
- float (*pmat)[4] = data->pmat;
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- float va2d[2] = {
- (dot_m4_v3_row_x(pmat, va) + pmat[3][0]),
- (dot_m4_v3_row_y(pmat, va) + pmat[3][1]),
+ struct DistProjectedAABBPrecalc neasrest_precalc;
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+
+ float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
+ transpose_m4_m4(tobmat, obmat);
+ for (int i = snapdata->clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ }
+
+ Nearest2dUserData nearest2d = {
+ .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
};
- float vb2d[2] = {
- (va2d[0] + pmat[main_axis][0] * scale),
- (va2d[1] + pmat[main_axis][1] * scale),
+
+ BVHTreeNearest nearest = {
+ .index = -1,
+ .dist_sq = SQUARE(*dist_px),
};
- if (data->is_persp) {
- float depth_a = mul_project_m4_v3_zfac(pmat, va);
- float depth_b = depth_a + pmat[main_axis][3] * scale;
- va2d[0] /= depth_a;
- va2d[1] /= depth_a;
- vb2d[0] /= depth_b;
- vb2d[1] /= depth_b;
- }
-
- va2d[0] += 1.0f;
- va2d[1] += 1.0f;
- vb2d[0] += 1.0f;
- vb2d[1] += 1.0f;
-
- va2d[0] *= data->win_half[0];
- va2d[1] *= data->win_half[1];
- vb2d[0] *= data->win_half[0];
- vb2d[1] *= data->win_half[1];
-
- float dvec[2], edge[2], lambda, rdist;
- sub_v2_v2v2(dvec, data->mval, va2d);
- sub_v2_v2v2(edge, vb2d, va2d);
- lambda = dot_v2v2(dvec, edge);
- if (lambda != 0.0f) {
- lambda /= len_squared_v2(edge);
- if (lambda <= 0.0f) {
- rdist = len_squared_v2v2(data->mval, va2d);
- r_axis_closest[main_axis] = true;
- }
- else if (lambda >= 1.0f) {
- rdist = len_squared_v2v2(data->mval, vb2d);
- r_axis_closest[main_axis] = false;
+ SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
+ if (sod == NULL) {
+ /* The object is in edit mode, and the key used
+ * was the object referenced in BMEditMesh */
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ sod = BLI_ghash_lookup(sctx->cache.object_map, em->ob);
+ }
+
+ BLI_assert(sod != NULL);
+
+ if (sod->type == SNAP_MESH) {
+ BVHTreeFromMesh *treedata = &((SnapObjectData_Mesh *)sod)->treedata;
+
+ nearest2d.userdata = treedata;
+ nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
+ nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
+ nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
+
+ const MPoly *mp = &((SnapObjectData_Mesh *)sod)->poly[*r_index];
+ const MLoop *ml = &treedata->loop[mp->loopstart];
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ elem = SCE_SNAP_MODE_EDGE;
+ BLI_assert(treedata->edge != NULL);
+ for (int i = mp->totloop; i--; ml++) {
+ cb_snap_edge(
+ &nearest2d, ml->e, &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest);
+ }
}
else {
- va2d[0] += edge[0] * lambda;
- va2d[1] += edge[1] * lambda;
- rdist = len_squared_v2v2(data->mval, va2d);
- r_axis_closest[main_axis] = lambda < 0.5f;
+ elem = SCE_SNAP_MODE_VERTEX;
+ for (int i = mp->totloop; i--; ml++) {
+ cb_snap_vert(
+ &nearest2d, ml->v, &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest);
+ }
}
}
else {
- rdist = len_squared_v2v2(data->mval, va2d);
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+
+ nearest2d.userdata = em;
+ nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
+ nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
+ nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ BMFace *f = BM_face_at_index(em->bm, *r_index);
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ elem = SCE_SNAP_MODE_EDGE;
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE);
+ do {
+ cb_snap_edge(
+ &nearest2d, BM_elem_index_get(l_iter->e),
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ elem = SCE_SNAP_MODE_VERTEX;
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ do {
+ cb_snap_vert(
+ &nearest2d, BM_elem_index_get(l_iter->v),
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
}
- return rdist;
-}
-static float dist_squared_to_projected_aabb_simple(
- float lpmat[4][4], const float win_half[2],
- const float ray_min_dist, const float mval[2],
- const float ray_origin_local[3], const float ray_direction_local[3],
- const float bbmin[3], const float bbmax[3])
-{
- struct Nearest2dPrecalc data;
- dist_squared_to_projected_aabb_precalc(
- &data, lpmat, true, win_half, ray_min_dist,
- mval, ray_origin_local, ray_direction_local);
+ if (nearest.index != -1) {
+ *dist_px = sqrtf(nearest.dist_sq);
- bool dummy[3] = {true, true, true};
- return dist_squared_to_projected_aabb(&data, bbmin, bbmax, dummy);
-}
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
-/** \} */
+ if (r_no) {
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
-/* -------------------------------------------------------------------- */
-/** Walk DFS
- * \{ */
+ copy_v3_v3(r_no, nearest.no);
+ mul_transposed_mat3_m4_v3(imat, r_no);
+ normalize_v3(r_no);
+ }
-typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, const float *v_pair[2], void *data);
-typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void *data);
+ if (r_index) {
+ *r_index = nearest.index;
+ }
-typedef struct Nearest2dUserData {
- struct Nearest2dPrecalc data_precalc;
+ return elem;
+ }
- float dist_px_sq;
+ return 0;
+}
- bool r_axis_closest[3];
- float depth_range[2];
+static short snap_mesh_edge_verts_mixed(
+ SnapObjectContext *sctx, SnapData *snapdata,
+ Object *ob, float obmat[4][4], float original_dist_px,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3], float r_no[3], int *r_index)
+{
+ short elem = SCE_SNAP_MODE_EDGE;
- void *userdata;
- Nearest2DGetEdgeVertsCallback get_edge_verts;
- Nearest2DCopyVertNoCallback copy_vert_no;
+ if (ob->type != OB_MESH) {
+ return elem;
+ }
- int index;
- float co[3];
- float no[3];
-} Nearest2dUserData;
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
+ struct DistProjectedAABBPrecalc neasrest_precalc;
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
-static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
-{
- Nearest2dUserData *data = user_data;
- const float bbmin[3] = {bounds[0].min, bounds[1].min, bounds[2].min};
- const float bbmax[3] = {bounds[0].max, bounds[1].max, bounds[2].max};
- const float rdist = dist_squared_to_projected_aabb(
- &data->data_precalc, bbmin, bbmax, data->r_axis_closest);
- return rdist < data->dist_px_sq;
-}
+ Nearest2dUserData nearest2d = {
+ .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ };
-static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata)
-{
- struct Nearest2dUserData *data = userdata;
- struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
- const float co[3] = {
- (bounds[0].min + bounds[0].max) / 2,
- (bounds[1].min + bounds[1].max) / 2,
- (bounds[2].min + bounds[2].max) / 2,
+ BVHTreeNearest nearest = {
+ .index = -1,
+ .dist_sq = SQUARE(original_dist_px),
};
- if (test_projected_vert_dist(
- data->depth_range,
- neasrest_precalc->mval, co,
- neasrest_precalc->pmat,
- neasrest_precalc->win_half,
- neasrest_precalc->is_persp,
- &data->dist_px_sq,
- data->co))
- {
- data->copy_vert_no(index, data->no, data->userdata);
- data->index = index;
+ SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
+ BLI_assert(sod != NULL);
+
+ if (sod->type == SNAP_MESH) {
+ nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata;
+ nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
+ nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
+ nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
+ }
+ else {
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ nearest2d.userdata = BKE_editmesh_from_object(ob);
+ nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
+ nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
+ nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
}
- return true;
-}
-static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata)
-{
- struct Nearest2dUserData *data = userdata;
- struct Nearest2dPrecalc *neasrest_precalc = &data->data_precalc;
+ int vindex[2];
+ nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata);
const float *v_pair[2];
- data->get_edge_verts(index, v_pair, data->userdata);
-
- if (test_projected_edge_dist(
- data->depth_range,
- neasrest_precalc->mval,
- neasrest_precalc->pmat,
- neasrest_precalc->win_half,
- neasrest_precalc->is_persp,
- neasrest_precalc->ray_origin_local,
- neasrest_precalc->ray_direction_local,
- v_pair[0], v_pair[1],
- &data->dist_px_sq,
- data->co))
+ nearest2d.get_vert_co(vindex[0], &v_pair[0], nearest2d.userdata);
+ nearest2d.get_vert_co(vindex[1], &v_pair[1], nearest2d.userdata);
+
+ float lambda;
+ if (!isect_ray_seg_v3(
+ neasrest_precalc.ray_origin,
+ neasrest_precalc.ray_direction,
+ v_pair[0], v_pair[1], &lambda))
{
- sub_v3_v3v3(data->no, v_pair[0], v_pair[1]);
- data->index = index;
+ /* do nothing */;
}
- return true;
-}
+ else if (lambda < 0.25f || 0.75f < lambda) {
+ int v_id = lambda < 0.5f ? 0 : 1;
-static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata)
-{
- const bool *r_axis_closest = ((struct Nearest2dUserData *)userdata)->r_axis_closest;
- return r_axis_closest[axis];
-}
+ if (test_projected_vert_dist(
+ &neasrest_precalc, NULL, 0,
+ nearest2d.is_persp, v_pair[v_id],
+ &nearest.dist_sq, nearest.co))
+ {
+ nearest.index = vindex[v_id];
+ nearest2d.copy_vert_no(vindex[v_id], nearest.no, nearest2d.userdata);
+ elem = SCE_SNAP_MODE_VERTEX;
+ }
+ }
-/** \} */
+ if (nearest.index != -1) {
+ *dist_px = sqrtf(nearest.dist_sq);
-/* -------------------------------------------------------------------- */
-/** \name Internal Object Snapping API
- * \{ */
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
-static bool snapArmature(
+ if (r_no) {
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+
+ copy_v3_v3(r_no, nearest.no);
+ mul_transposed_mat3_m4_v3(imat, r_no);
+ normalize_v3(r_no);
+ }
+
+ if (r_index) {
+ *r_index = nearest.index;
+ }
+ }
+
+ return elem;
+}
+
+static short snapArmature(
SnapData *snapdata,
- Object *ob, bArmature *arm, float obmat[4][4],
+ Object *ob, float obmat[4][4], bool use_obedit,
/* read/write args */
- float *ray_depth, float *dist_px,
+ float *dist_px,
/* return args */
- float r_loc[3], float *UNUSED(r_no))
+ float r_loc[3], float *UNUSED(r_no), int *r_index)
{
- bool retval = false;
+ short retval = 0;
+
+ if (snapdata->snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
+ return retval;
+ }
- float ray_start_local[3], ray_normal_local[3]; /* Used only in the snap to edges */
- if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
- float imat[4][4];
- invert_m4_m4(imat, obmat);
+ float lpmat[4][4], dist_px_sq = SQUARE(*dist_px);
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- copy_v3_v3(ray_start_local, snapdata->ray_origin);
- copy_v3_v3(ray_normal_local, snapdata->ray_dir);
- mul_m4_v3(imat, ray_start_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ struct DistProjectedAABBPrecalc neasrest_precalc;
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+
+ use_obedit = use_obedit && BKE_object_is_in_editmode(ob);
+
+ if (use_obedit == false) {
+ /* Test BoundBox */
+ BoundBox *bb = BKE_armature_boundbox_get(ob);
+ if (bb && !snap_bound_box_check_dist(
+ bb->vec[0], bb->vec[6], lpmat,
+ snapdata->win_size, snapdata->mval, dist_px_sq))
+ {
+ return retval;
+ }
}
- else if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) { /* Currently only edge and vert */
- return retval;
+
+ float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
+ transpose_m4_m4(tobmat, obmat);
+ for (int i = snapdata->clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- float lpmat[4][4], dist_px_sq;
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- dist_px_sq = SQUARE(*dist_px);
+ bArmature *arm = ob->data;
if (arm->edbo) {
for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) {
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, eBone->head,
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, eBone->tail,
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- break;
- case SCE_SNAP_MODE_EDGE:
- retval |= test_projected_edge_dist(
- snapdata->depth_range, snapdata->mval, lpmat,
- snapdata->win_half, is_persp, ray_start_local, ray_normal_local,
- eBone->head, eBone->tail,
- &dist_px_sq, r_loc);
- break;
+ bool has_vert_snap = false;
+
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ has_vert_snap = test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, eBone->head, &dist_px_sq, r_loc);
+ has_vert_snap |= test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, eBone->tail, &dist_px_sq, r_loc);
+
+ if (has_vert_snap) {
+ retval = SCE_SNAP_MODE_VERTEX;
+ }
+ }
+ if (!has_vert_snap && snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (test_projected_edge_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, eBone->head, eBone->tail,
+ &dist_px_sq, r_loc))
+ {
+ retval = SCE_SNAP_MODE_EDGE;
+ }
}
}
}
@@ -1312,193 +1446,247 @@ static bool snapArmature(
Bone *bone = pchan->bone;
/* skip hidden bones */
if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
+ bool has_vert_snap = false;
const float *head_vec = pchan->pose_head;
const float *tail_vec = pchan->pose_tail;
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, head_vec,
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, tail_vec,
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- break;
- case SCE_SNAP_MODE_EDGE:
- retval |= test_projected_edge_dist(
- snapdata->depth_range, snapdata->mval, lpmat,
- snapdata->win_half, is_persp, ray_start_local, ray_normal_local,
- head_vec, tail_vec,
- &dist_px_sq, r_loc);
- break;
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ has_vert_snap = test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, head_vec, &dist_px_sq, r_loc);
+ has_vert_snap |= test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, tail_vec, &dist_px_sq, r_loc);
+
+ if (has_vert_snap) {
+ retval = SCE_SNAP_MODE_VERTEX;
+ }
+ }
+ if (!has_vert_snap && snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (test_projected_edge_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, head_vec, tail_vec,
+ &dist_px_sq, r_loc))
+ {
+ retval = SCE_SNAP_MODE_EDGE;
+ }
}
}
}
}
+
if (retval) {
*dist_px = sqrtf(dist_px_sq);
mul_m4_v3(obmat, r_loc);
- *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
- return true;
+ if (r_index) {
+ /* Does not support index. */
+ *r_index = -1;
+ }
+ return retval;
}
- return false;
+
+ return 0;
}
-static bool snapCurve(
+static short snapCurve(
SnapData *snapdata,
- Object *ob, Curve *cu, float obmat[4][4],
+ Object *ob, float obmat[4][4], bool use_obedit,
/* read/write args */
- float *ray_depth, float *dist_px,
+ float *dist_px,
/* return args */
- float r_loc[3], float *UNUSED(r_no))
+ float r_loc[3], float *UNUSED(r_no), int *r_index)
{
- bool retval = false;
+ bool has_snap = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
- if (snapdata->snap_to != SCE_SNAP_MODE_VERTEX) {
- return retval;
+ if (snapdata->snap_to_flag != SCE_SNAP_MODE_VERTEX) {
+ return 0;
}
- bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- float lpmat[4][4], dist_px_sq;
+ Curve *cu = ob->data;
+ float dist_px_sq = SQUARE(*dist_px);
+
+ float lpmat[4][4];
mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- dist_px_sq = SQUARE(*dist_px);
- for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
+ struct DistProjectedAABBPrecalc neasrest_precalc;
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
+
+ use_obedit = use_obedit && BKE_object_is_in_editmode(ob);
+
+ if (use_obedit == false) {
+ /* Test BoundBox */
+ BoundBox *bb = BKE_curve_texspace_get(cu, NULL, NULL, NULL);
+ if (bb && !snap_bound_box_check_dist(
+ bb->vec[0], bb->vec[6], lpmat,
+ snapdata->win_size, snapdata->mval, dist_px_sq))
+ {
+ return 0;
+ }
+ }
+
+ float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
+ transpose_m4_m4(tobmat, obmat);
+ for (int i = snapdata->clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ }
+
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+
+ for (Nurb *nu = (use_obedit ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (int u = 0; u < nu->pntsu; u++) {
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_VERTEX:
- {
- if (ob->mode == OB_MODE_EDIT) {
- if (nu->bezt) {
- /* don't snap to selected (moving) or hidden */
- if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
- break;
- }
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[1],
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
- if (!(nu->bezt[u].f1 & SELECT) &&
- !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
- {
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[0],
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- }
- if (!(nu->bezt[u].f3 & SELECT) &&
- !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
- {
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[2],
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- }
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (use_obedit) {
+ if (nu->bezt) {
+ /* don't snap to selected (moving) or hidden */
+ if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
+ break;
}
- else {
- /* don't snap to selected (moving) or hidden */
- if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
- break;
- }
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
+ has_snap |= test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, nu->bezt[u].vec[1], &dist_px_sq,
+ r_loc);
+ /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
+ if (!(nu->bezt[u].f1 & SELECT) &&
+ !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
+ {
+ has_snap |= test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, nu->bezt[u].vec[0], &dist_px_sq,
+ r_loc);
+ }
+ if (!(nu->bezt[u].f3 & SELECT) &&
+ !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
+ {
+ has_snap |= test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, nu->bezt[u].vec[2], &dist_px_sq,
r_loc);
}
}
else {
- /* curve is not visible outside editmode if nurb length less than two */
- if (nu->pntsu > 1) {
- if (nu->bezt) {
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, nu->bezt[u].vec[1],
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- }
- else {
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, nu->bp[u].vec,
- lpmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
- }
+ /* don't snap to selected (moving) or hidden */
+ if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
+ break;
+ }
+ has_snap |= test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, nu->bp[u].vec, &dist_px_sq,
+ r_loc);
+ }
+ }
+ else {
+ /* curve is not visible outside editmode if nurb length less than two */
+ if (nu->pntsu > 1) {
+ if (nu->bezt) {
+ has_snap |= test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, nu->bezt[u].vec[1], &dist_px_sq,
+ r_loc);
+ }
+ else {
+ has_snap |= test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, nu->bp[u].vec, &dist_px_sq,
+ r_loc);
}
}
- break;
}
- default:
- break;
}
}
}
- if (retval) {
+ if (has_snap) {
*dist_px = sqrtf(dist_px_sq);
mul_m4_v3(obmat, r_loc);
- *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
- return true;
+ if (r_index) {
+ /* Does not support index yet. */
+ *r_index = -1;
+ }
+ return SCE_SNAP_MODE_VERTEX;
}
- return false;
+
+ return 0;
}
/* may extend later (for now just snaps to empty center) */
-static bool snapEmpty(
+static short snapEmpty(
SnapData *snapdata,
Object *ob, float obmat[4][4],
/* read/write args */
- float *ray_depth, float *dist_px,
+ float *dist_px,
/* return args */
- float r_loc[3], float *UNUSED(r_no))
+ float r_loc[3], float *UNUSED(r_no), int *r_index)
{
- bool retval = false;
+ short retval = 0;
if (ob->transflag & OB_DUPLI) {
return retval;
}
/* for now only vertex supported */
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_VERTEX:
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ struct DistProjectedAABBPrecalc neasrest_precalc;
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
+
+ float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
+ transpose_m4_m4(tobmat, obmat);
+ for (int i = snapdata->clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ }
+
+ bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ float dist_px_sq = SQUARE(*dist_px);
+ float co[3];
+ copy_v3_v3(co, obmat[3]);
+ if (test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, co, &dist_px_sq, r_loc))
{
- bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- float dist_px_sq = SQUARE(*dist_px);
- float tmp_co[3];
- copy_v3_v3(tmp_co, obmat[3]);
- if (test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, tmp_co,
- snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc))
- {
- *dist_px = sqrtf(dist_px_sq);
- *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
- retval = true;
- }
- break;
+ *dist_px = sqrtf(dist_px_sq);
+ retval = SCE_SNAP_MODE_VERTEX;
}
- default:
- break;
}
- return retval;
+ if (retval) {
+ if (r_index) {
+ /* Does not support index. */
+ *r_index = -1;
+ }
+ return retval;
+ }
+
+ return 0;
}
-static bool snapCamera(
+static short snapCamera(
const SnapObjectContext *sctx, SnapData *snapdata,
Object *object, float obmat[4][4],
/* read/write args */
- float *ray_depth, float *dist_px,
+ float *dist_px,
/* return args */
- float r_loc[3], float *UNUSED(r_no))
+ float r_loc[3], float *UNUSED(r_no), int *r_index)
{
+ short retval = 0;
+
+ Depsgraph *depsgraph = sctx->depsgraph;
Scene *scene = sctx->scene;
bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
float dist_px_sq = SQUARE(*dist_px);
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
- bool retval = false;
MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
MovieTracking *tracking;
@@ -1509,394 +1697,464 @@ static bool snapCamera(
return retval;
}
+ float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
+ transpose_m4_m4(tobmat, obmat);
+ for (int i = snapdata->clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
+ }
+
tracking = &clip->tracking;
- BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, scene, object, orig_camera_mat);
invert_m4_m4(orig_camera_imat, orig_camera_mat);
invert_m4_m4(imat, obmat);
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_VERTEX:
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ struct DistProjectedAABBPrecalc neasrest_precalc;
+ dist_squared_to_projected_aabb_precalc(
+ &neasrest_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval);
+
+ MovieTrackingObject *tracking_object;
+ for (tracking_object = tracking->objects.first;
+ tracking_object;
+ tracking_object = tracking_object->next)
{
- MovieTrackingObject *tracking_object;
-
- for (tracking_object = tracking->objects.first;
- tracking_object;
- tracking_object = tracking_object->next)
- {
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
- MovieTrackingTrack *track;
- float reconstructed_camera_mat[4][4],
- reconstructed_camera_imat[4][4];
- float (*vertex_obmat)[4];
-
- if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
- CFRA, reconstructed_camera_mat);
-
- invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
- }
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ MovieTrackingTrack *track;
+ float reconstructed_camera_mat[4][4],
+ reconstructed_camera_imat[4][4];
+ float (*vertex_obmat)[4];
- for (track = tracksbase->first; track; track = track->next) {
- float bundle_pos[3];
+ if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
+ CFRA, reconstructed_camera_mat);
- if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
- continue;
- }
+ invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
+ }
- copy_v3_v3(bundle_pos, track->bundle_pos);
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- vertex_obmat = orig_camera_mat;
- }
- else {
- mul_m4_v3(reconstructed_camera_imat, bundle_pos);
- vertex_obmat = obmat;
- }
+ for (track = tracksbase->first; track; track = track->next) {
+ float bundle_pos[3];
- mul_m4_v3(vertex_obmat, bundle_pos);
- retval |= test_projected_vert_dist(
- snapdata->depth_range, snapdata->mval, bundle_pos,
- snapdata->pmat, snapdata->win_half, is_persp, &dist_px_sq,
- r_loc);
+ if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+ continue;
}
- }
- break;
+ copy_v3_v3(bundle_pos, track->bundle_pos);
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ vertex_obmat = orig_camera_mat;
+ }
+ else {
+ mul_m4_v3(reconstructed_camera_imat, bundle_pos);
+ vertex_obmat = obmat;
+ }
+
+ mul_m4_v3(vertex_obmat, bundle_pos);
+ if (test_projected_vert_dist(
+ &neasrest_precalc,
+ clip_planes_local, snapdata->clip_plane_len,
+ is_persp, bundle_pos, &dist_px_sq, r_loc))
+ {
+ retval = SCE_SNAP_MODE_VERTEX;
+ }
+ }
}
- default:
- break;
}
if (retval) {
*dist_px = sqrtf(dist_px_sq);
- *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
- return true;
+ if (r_index) {
+ /* Does not support index. */
+ *r_index = -1;
+ }
+ return retval;
}
- return false;
-}
-static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
-{
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
+ return 0;
}
-static bool snapDerivedMesh(
+static short snapMesh(
SnapObjectContext *sctx, SnapData *snapdata,
- Object *ob, DerivedMesh *dm, float obmat[4][4],
+ Object *ob, Mesh *me, float obmat[4][4],
/* read/write args */
- float *ray_depth, float *dist_px,
+ float *dist_px,
/* return args */
- float r_loc[3], float r_no[3])
+ float r_loc[3], float r_no[3], int *r_index)
{
- bool retval = false;
+ BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE);
- if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
- if (dm->getNumEdges(dm) == 0) {
- return retval;
+ if ((snapdata->snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_EDGE) {
+ if (me->totedge == 0) {
+ return 0;
}
}
else {
- if (dm->getNumVerts(dm) == 0) {
- return retval;
+ if (me->totvert == 0) {
+ return 0;
}
}
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_normal_local[3];
- float local_scale;
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
+ float dist_px_sq = SQUARE(*dist_px);
- copy_v3_v3(ray_normal_local, snapdata->ray_dir);
+ /* Test BoundBox */
+ BoundBox *bb = BKE_mesh_boundbox_get(ob);
+ if (bb && !snap_bound_box_check_dist(
+ bb->vec[0], bb->vec[6], lpmat, snapdata->win_size,
+ snapdata->mval, dist_px_sq))
+ {
+ return 0;
+ }
- mul_mat3_m4_v3(imat, ray_normal_local);
+ SnapObjectData_Mesh *sod = snap_object_data_mesh_get(sctx, ob);
- /* local scale in normal direction */
- local_scale = normalize_v3(ray_normal_local);
+ BVHTreeFromMesh *treedata, dummy_treedata;
+ BVHTree **bvhtree;
+ treedata = &sod->treedata;
+ bvhtree = sod->bvhtree;
- float lpmat[4][4];
- float ray_org_local[3];
- float ray_min_dist;
-
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- ray_min_dist = snapdata->depth_range[0] * local_scale;
+ /* The tree is owned by the Mesh and may have been freed since we last used! */
+ if ((sod->has_looptris && treedata->tree && !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) ||
+ (sod->has_loose_edge && bvhtree[0] && !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[0])) ||
+ (sod->has_loose_vert && bvhtree[1] && !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[1])))
+ {
+ BLI_assert(!treedata->tree || !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree));
+ BLI_assert(!bvhtree[0] || !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[0]));
+ BLI_assert(!bvhtree[1] || !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[1]));
- copy_v3_v3(ray_org_local, snapdata->ray_origin);
- mul_m4_v3(imat, ray_org_local);
+ free_bvhtree_from_mesh(treedata);
+ bvhtree[0] = NULL;
+ bvhtree[1] = NULL;
+ }
- /* Test BoundBox */
- BoundBox *bb = BKE_object_boundbox_get(ob);
- if (bb) {
- /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */
- float dist_px_sq = dist_squared_to_projected_aabb_simple(
- lpmat, snapdata->win_half, ray_min_dist, snapdata->mval,
- ray_org_local, ray_normal_local, bb->vec[0], bb->vec[6]);
- if (dist_px_sq > SQUARE(*dist_px)) {
- return retval;
+ if (sod->has_looptris && treedata->tree == NULL) {
+ BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4);
+ sod->has_looptris = (treedata->tree != NULL);
+ if (sod->has_looptris) {
+ /* Make sure that the array of edges is referenced in the callbacks. */
+ treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
}
}
+ if (sod->has_loose_edge && bvhtree[0] == NULL) {
+ bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2);
+ sod->has_loose_edge = bvhtree[0] != NULL;
- SnapObjectData_Mesh *sod = NULL;
- BVHTreeFromMesh *treedata = NULL;
+ if (sod->has_loose_edge) {
+ BLI_assert(treedata->vert_allocated == false);
+ treedata->vert = dummy_treedata.vert;
+ treedata->vert_allocated = dummy_treedata.vert_allocated;
- void **sod_p;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- sod = *sod_p;
+ BLI_assert(treedata->edge_allocated == false);
+ treedata->edge = dummy_treedata.edge;
+ treedata->edge_allocated = dummy_treedata.edge_allocated;
+ }
+ }
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (sod->has_loose_vert && bvhtree[1] == NULL) {
+ bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2);
+ sod->has_loose_vert = bvhtree[1] != NULL;
+
+ if (sod->has_loose_vert) {
+ BLI_assert(treedata->vert_allocated == false);
+ treedata->vert = dummy_treedata.vert;
+ treedata->vert_allocated = dummy_treedata.vert_allocated;
+ }
+ }
}
else {
- sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_MESH;
+ /* Not necessary, just to keep the data more consistent. */
+ sod->has_loose_vert = false;
}
- int tree_index = -1;
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_EDGE:
- tree_index = 1;
- break;
- case SCE_SNAP_MODE_VERTEX:
- tree_index = 0;
- break;
+ /* Update pointers. */
+ if (treedata->vert_allocated == false) {
+ treedata->vert = me->mvert; /* CustomData_get_layer(&me->vdata, CD_MVERT);? */
}
- if (tree_index != -1) {
- if (sod->bvh_trees[tree_index] == NULL) {
- sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ if (treedata->tree || bvhtree[0]) {
+ if (treedata->edge_allocated == false) {
+ /* If raycast has been executed before, `treedata->edge` can be NULL. */
+ treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
}
- treedata = sod->bvh_trees[tree_index];
-
- /* the tree is owned by the DM and may have been freed since we last used! */
- if (treedata && treedata->tree) {
- if (treedata->cached && !bvhcache_has_tree(dm->bvhCache, treedata->tree)) {
- free_bvhtree_from_mesh(treedata);
- }
- else {
- if (treedata->vert == NULL) {
- treedata->vert = DM_get_vert_array(dm, &treedata->vert_allocated);
- }
- if ((tree_index == 1) && (treedata->edge == NULL)) {
- treedata->edge = DM_get_edge_array(dm, &treedata->edge_allocated);
- }
- }
+ if (treedata->loop && treedata->loop_allocated == false) {
+ treedata->loop = me->mloop; /* CustomData_get_layer(&me->edata, CD_MLOOP);? */
+ }
+ if (treedata->looptri && treedata->looptri_allocated == false) {
+ treedata->looptri = BKE_mesh_runtime_looptri_ensure(me);
}
}
- if (treedata) {
- if (treedata->tree == NULL) {
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_EDGE:
- bvhtree_from_mesh_get(treedata, dm, BVHTREE_FROM_EDGES, 2);
- break;
- case SCE_SNAP_MODE_VERTEX:
- bvhtree_from_mesh_get(treedata, dm, BVHTREE_FROM_VERTS, 2);
- break;
- }
- }
- if (treedata->tree == NULL) {
- return retval;
- }
+ Nearest2dUserData nearest2d = {
+ .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ .userdata = treedata,
+ .get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get,
+ .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get,
+ .get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get,
+ .get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get,
+ .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy,
+ };
+
+ BVHTreeNearest nearest = {
+ .index = -1,
+ .dist_sq = dist_px_sq,
+ };
+ int last_index = nearest.index;
+ short elem = SCE_SNAP_MODE_VERTEX;
+
+ float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
+ transpose_m4_m4(tobmat, obmat);
+ for (int i = snapdata->clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
- else {
- return retval;
+
+ if (bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
+ /* snap to loose verts */
+ BLI_bvhtree_find_nearest_projected(
+ bvhtree[1], lpmat, snapdata->win_size, snapdata->mval,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest, cb_snap_vert, &nearest2d);
+
+ last_index = nearest.index;
}
- /* Warning: the depth_max is currently being used only in perspective view.
- * It is not correct to limit the maximum depth for elements obtained with nearest
- * since this limitation depends on the normal and the size of the occlusion face.
- * And more... ray_depth is being confused with Z-depth here... (varies only the precision) */
- const float ray_depth_max_global = *ray_depth + snapdata->depth_range[0];
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (bvhtree[0]) {
+ /* snap to loose edges */
+ BLI_bvhtree_find_nearest_projected(
+ bvhtree[0], lpmat, snapdata->win_size, snapdata->mval,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest, cb_snap_edge, &nearest2d);
+ }
- Nearest2dUserData neasrest2d = {
- .dist_px_sq = SQUARE(*dist_px),
- .r_axis_closest = {1.0f, 1.0f, 1.0f},
- .depth_range = {snapdata->depth_range[0], ray_depth_max_global},
- .userdata = treedata,
- .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_dm_edge_verts,
- .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_dm_vert_no,
- .index = -1};
+ if (treedata->tree) {
+ /* snap to looptris */
+ BLI_bvhtree_find_nearest_projected(
+ treedata->tree, lpmat, snapdata->win_size, snapdata->mval,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest, cb_snap_tri_edges, &nearest2d);
+ }
- dist_squared_to_projected_aabb_precalc(
- &neasrest2d.data_precalc, lpmat,
- snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half,
- ray_min_dist, snapdata->mval, ray_org_local, ray_normal_local);
+ if (last_index != nearest.index) {
+ elem = SCE_SNAP_MODE_EDGE;
+ }
+ }
+ else {
+ BLI_assert(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX);
+ if (bvhtree[0]) {
+ /* snap to loose edges */
+ BLI_bvhtree_find_nearest_projected(
+ bvhtree[0], lpmat, snapdata->win_size, snapdata->mval,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest, cb_snap_edge_verts, &nearest2d);
+ }
- BVHTree_WalkLeafCallback cb_walk_leaf =
- (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
- cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+ if (treedata->tree) {
+ /* snap to looptris */
+ BLI_bvhtree_find_nearest_projected(
+ treedata->tree, lpmat, snapdata->win_size, snapdata->mval,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest, cb_snap_tri_verts, &nearest2d);
+ }
+ }
- BLI_bvhtree_walk_dfs(
- treedata->tree,
- cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
+ if (nearest.index != -1) {
+ *dist_px = sqrtf(nearest.dist_sq);
- if (neasrest2d.index != -1) {
- copy_v3_v3(r_loc, neasrest2d.co);
+ copy_v3_v3(r_loc, nearest.co);
mul_m4_v3(obmat, r_loc);
+
if (r_no) {
- copy_v3_v3(r_no, neasrest2d.no);
- mul_m3_v3(timat, r_no);
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+
+ copy_v3_v3(r_no, nearest.no);
+ mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
- *dist_px = sqrtf(neasrest2d.dist_px_sq);
- *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
+ if (r_index) {
+ *r_index = nearest.index;
+ }
- retval = true;
+ return elem;
}
- return retval;
+ return 0;
}
-static bool snapEditMesh(
+static short snapEditMesh(
SnapObjectContext *sctx, SnapData *snapdata,
Object *ob, BMEditMesh *em, float obmat[4][4],
/* read/write args */
- float *ray_depth, float *dist_px,
+ float *dist_px,
/* return args */
- float r_loc[3], float r_no[3])
+ float r_loc[3], float r_no[3], int *r_index)
{
- bool retval = false;
+ BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE);
- if (snapdata->snap_to == SCE_SNAP_MODE_EDGE) {
+ if ((snapdata->snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_EDGE) {
if (em->bm->totedge == 0) {
- return retval;
+ return 0;
}
}
else {
if (em->bm->totvert == 0) {
- return retval;
+ return 0;
}
}
- float imat[4][4];
- float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_normal_local[3];
+ BVHTreeFromEditMesh *treedata_vert = NULL, *treedata_edge = NULL;
- invert_m4_m4(imat, obmat);
- transpose_m3_m4(timat, imat);
+ BLI_assert(BKE_object_get_pre_modified_mesh(ob) == BKE_object_get_pre_modified_mesh(ob));
+ UNUSED_VARS_NDEBUG(ob);
- copy_v3_v3(ray_normal_local, snapdata->ray_dir);
+ float lpmat[4][4];
+ mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- mul_mat3_m4_v3(imat, ray_normal_local);
+ float dist_px_sq = SQUARE(*dist_px);
- /* local scale in normal direction */
- float local_scale = normalize_v3(ray_normal_local);
+ SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, em);
- SnapObjectData_EditMesh *sod = NULL;
- BVHTreeFromEditMesh *treedata = NULL;
+ /* Test BoundBox */
- void **sod_p;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- sod = *sod_p;
- }
- else {
- sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_EDIT_MESH;
+ /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
+ if (!snap_bound_box_check_dist(
+ sod->min, sod->max, lpmat, snapdata->win_size, snapdata->mval, dist_px_sq))
+ {
+ return 0;
}
- int tree_index = -1;
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_EDGE:
- tree_index = 1;
- break;
- case SCE_SNAP_MODE_VERTEX:
- tree_index = 0;
- break;
- }
- if (tree_index != -1) {
- if (sod->bvh_trees[tree_index] == NULL) {
- sod->bvh_trees[tree_index] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*treedata));
+ BVHCache *em_bvh_cache = ((Mesh *)em->ob->data)->runtime.bvh_cache;
+
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ if (sod->bvh_trees[0] == NULL) {
+ sod->bvh_trees[0] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees));
}
- treedata = sod->bvh_trees[tree_index];
- }
+ treedata_vert = sod->bvh_trees[0];
- if (treedata) {
- if (treedata->tree == NULL) {
- BLI_bitmap *elem_mask = NULL;
- switch (snapdata->snap_to) {
- case SCE_SNAP_MODE_EDGE:
- {
- int edges_num_active = -1;
- if (sctx->callbacks.edit_mesh.test_edge_fn) {
- elem_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__);
- edges_num_active = BM_iter_mesh_bitmap_from_filter(
- BM_EDGES_OF_MESH, em->bm, elem_mask,
- (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
- sctx->callbacks.edit_mesh.user_data);
- }
- bvhtree_from_editmesh_edges_ex(treedata, em, elem_mask, edges_num_active, 0.0f, 2, 6);
- break;
- }
- case SCE_SNAP_MODE_VERTEX:
- {
- int verts_num_active = -1;
- if (sctx->callbacks.edit_mesh.test_vert_fn) {
- elem_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
- verts_num_active = BM_iter_mesh_bitmap_from_filter(
- BM_VERTS_OF_MESH, em->bm, elem_mask,
- (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
- sctx->callbacks.edit_mesh.user_data);
- }
- bvhtree_from_editmesh_verts_ex(treedata, em, elem_mask, verts_num_active, 0.0f, 2, 6);
- break;
- }
+ if (sctx->callbacks.edit_mesh.test_vert_fn == NULL) {
+ /* The tree is owned by the Mesh and may have been freed since we last used! */
+ if (!bvhcache_has_tree(em_bvh_cache, treedata_vert->tree)) {
+ free_bvhtree_from_editmesh(treedata_vert);
}
- if (elem_mask) {
- MEM_freeN(elem_mask);
+ }
+
+ if (treedata_vert->tree == NULL) {
+ BLI_bitmap *verts_mask = NULL;
+ int verts_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_vert_fn) {
+ verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
+ verts_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_VERTS_OF_MESH, em->bm, verts_mask,
+ (bool(*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn,
+ sctx->callbacks.edit_mesh.user_data);
+
+ bvhtree_from_editmesh_verts_ex(treedata_vert, em, verts_mask, verts_num_active, 0.0f, 2, 6);
+ MEM_freeN(verts_mask);
+ }
+ else {
+ bvhtree_from_editmesh_verts(treedata_vert, em, 0.0f, 2, 6, &em_bvh_cache);
}
}
- if (treedata->tree == NULL) {
- return retval;
+ }
+
+ if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ if (sod->bvh_trees[1] == NULL) {
+ sod->bvh_trees[1] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees));
+ }
+ treedata_edge = sod->bvh_trees[1];
+
+ if (sctx->callbacks.edit_mesh.test_edge_fn == NULL) {
+ /* The tree is owned by the Mesh and may have been freed since we last used! */
+ if (!bvhcache_has_tree(em_bvh_cache, treedata_edge->tree)) {
+ free_bvhtree_from_editmesh(treedata_edge);
+ }
+ }
+
+ if (treedata_edge->tree == NULL) {
+ BLI_bitmap *edges_mask = NULL;
+ int edges_num_active = -1;
+ if (sctx->callbacks.edit_mesh.test_edge_fn) {
+ edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__);
+ edges_num_active = BM_iter_mesh_bitmap_from_filter(
+ BM_EDGES_OF_MESH, em->bm, edges_mask,
+ (bool(*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn,
+ sctx->callbacks.edit_mesh.user_data);
+
+ bvhtree_from_editmesh_edges_ex(treedata_edge, em, edges_mask, edges_num_active, 0.0f, 2, 6);
+ MEM_freeN(edges_mask);
+ }
+ else {
+ bvhtree_from_editmesh_edges(treedata_edge, em, 0.0f, 2, 6, &em_bvh_cache);
+ }
}
}
- else {
- return retval;
+
+ Nearest2dUserData nearest2d = {
+ .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ .userdata = em,
+ .get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get,
+ .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get,
+ .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy,
+ };
+
+ BVHTreeNearest nearest = {
+ .index = -1,
+ .dist_sq = dist_px_sq,
+ };
+ int last_index = nearest.index;
+ short elem = SCE_SNAP_MODE_VERTEX;
+
+ float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
+ transpose_m4_m4(tobmat, obmat);
+
+ for (int i = snapdata->clip_plane_len; i--;) {
+ mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
- float ray_org_local[3];
- copy_v3_v3(ray_org_local, snapdata->ray_origin);
- mul_m4_v3(imat, ray_org_local);
+ if (treedata_vert && snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ BLI_bvhtree_find_nearest_projected(
+ treedata_vert->tree, lpmat, snapdata->win_size, snapdata->mval,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest, cb_snap_vert, &nearest2d);
- Nearest2dUserData neasrest2d = {
- .dist_px_sq = SQUARE(*dist_px),
- .r_axis_closest = {1.0f, 1.0f, 1.0f},
- .depth_range = {snapdata->depth_range[0], *ray_depth + snapdata->depth_range[0]},
- .userdata = treedata,
- .get_edge_verts = (Nearest2DGetEdgeVertsCallback)get_bedge_verts,
- .copy_vert_no = (Nearest2DCopyVertNoCallback)copy_bvert_no,
- .index = -1};
+ last_index = nearest.index;
+ }
- float lpmat[4][4];
- mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- dist_squared_to_projected_aabb_precalc(
- &neasrest2d.data_precalc, lpmat,
- snapdata->view_proj == VIEW_PROJ_PERSP, snapdata->win_half,
- (snapdata->depth_range[0] * local_scale), snapdata->mval,
- ray_org_local, ray_normal_local);
+ if (treedata_edge && snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
+ BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
+ BLI_bvhtree_find_nearest_projected(
+ treedata_edge->tree, lpmat, snapdata->win_size, snapdata->mval,
+ clip_planes_local, snapdata->clip_plane_len,
+ &nearest, cb_snap_edge, &nearest2d);
- BVHTree_WalkLeafCallback cb_walk_leaf =
- (snapdata->snap_to == SCE_SNAP_MODE_VERTEX) ?
- cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
+ if (last_index != nearest.index) {
+ elem = SCE_SNAP_MODE_EDGE;
+ }
+ }
- BLI_bvhtree_walk_dfs(
- treedata->tree,
- cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest2d);
+ if (nearest.index != -1) {
+ *dist_px = sqrtf(nearest.dist_sq);
- if (neasrest2d.index != -1) {
- copy_v3_v3(r_loc, neasrest2d.co);
+ copy_v3_v3(r_loc, nearest.co);
mul_m4_v3(obmat, r_loc);
if (r_no) {
- copy_v3_v3(r_no, neasrest2d.no);
- mul_m3_v3(timat, r_no);
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+
+ copy_v3_v3(r_no, nearest.no);
+ mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
- *dist_px = sqrtf(neasrest2d.dist_px_sq);
- *ray_depth = depth_get(r_loc, snapdata->ray_start, snapdata->ray_dir);
+ if (r_index) {
+ *r_index = nearest.index;
+ }
- retval = true;
+ return elem;
}
- return retval;
+ return 0;
}
/**
@@ -1904,112 +2162,119 @@ static bool snapEditMesh(
*
* \note Duplicate args here are documented at #snapObjectsRay
*/
-static bool snapObject(
+static short snapObject(
SnapObjectContext *sctx, SnapData *snapdata,
- Object *ob, float obmat[4][4],
- bool use_obedit,
+ Object *ob, float obmat[4][4], bool use_obedit,
/* read/write args */
- float *ray_depth, float *dist_px,
+ float *dist_px,
/* return args */
- float r_loc[3], float r_no[3],
+ float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
- bool retval = false;
-
- if (ob->type == OB_MESH) {
- BMEditMesh *em;
+ short retval = 0;
- if (use_obedit) {
- em = BKE_editmesh_from_object(ob);
- retval = snapEditMesh(
- sctx, snapdata, ob, em, obmat,
- ray_depth, dist_px,
- r_loc, r_no);
- }
- else {
- /* in this case we want the mesh from the editmesh, avoids stale data. see: T45978.
- * still set the 'em' to NULL, since we only want the 'dm'. */
- DerivedMesh *dm;
- em = BKE_editmesh_from_object(ob);
- if (em) {
- editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm);
- }
- else {
- dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH);
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ Mesh *me = ob->data;
+ if (BKE_object_is_in_editmode(ob)) {
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ if (use_obedit) {
+ retval = snapEditMesh(
+ sctx, snapdata, ob, em, obmat,
+ dist_px,
+ r_loc, r_no, r_index);
+ break;
+ }
+ else if (em->mesh_eval_final) {
+ me = em->mesh_eval_final;
+ }
}
- retval = snapDerivedMesh(
- sctx, snapdata, ob, dm, obmat,
- ray_depth, dist_px,
- r_loc, r_no);
-
- dm->release(dm);
+ retval = snapMesh(
+ sctx, snapdata, ob, me, obmat,
+ dist_px,
+ r_loc, r_no, r_index);
+ break;
}
- }
- else if (snapdata->snap_to != SCE_SNAP_MODE_FACE) {
- if (ob->type == OB_ARMATURE) {
+ case OB_ARMATURE:
retval = snapArmature(
snapdata,
- ob, ob->data, obmat,
- ray_depth, dist_px,
- r_loc, r_no);
- }
- else if (ob->type == OB_CURVE) {
+ ob, obmat, use_obedit,
+ dist_px,
+ r_loc, r_no, r_index);
+ break;
+
+ case OB_CURVE:
retval = snapCurve(
snapdata,
- ob, ob->data, obmat,
- ray_depth, dist_px,
- r_loc, r_no);
- }
- else if (ob->type == OB_EMPTY) {
+ ob, obmat, use_obedit,
+ dist_px,
+ r_loc, r_no, r_index);
+ break;
+
+ case OB_EMPTY:
retval = snapEmpty(
- snapdata,
- ob, obmat,
- ray_depth, dist_px,
- r_loc, r_no);
- }
- else if (ob->type == OB_CAMERA) {
+ snapdata, ob, obmat,
+ dist_px,
+ r_loc, r_no, r_index);
+ break;
+ case OB_GPENCIL:
+ retval = snapEmpty(
+ snapdata, ob, obmat,
+ dist_px,
+ r_loc, r_no, r_index);
+ break;
+ case OB_CAMERA:
retval = snapCamera(
sctx, snapdata, ob, obmat,
- ray_depth, dist_px,
- r_loc, r_no);
- }
+ dist_px,
+ r_loc, r_no, r_index);
+ break;
}
if (retval) {
if (r_ob) {
*r_ob = ob;
+ }
+ if (r_obmat) {
copy_m4_m4(r_obmat, obmat);
}
+ return retval;
}
- return retval;
+ return 0;
}
struct SnapObjUserData {
SnapData *snapdata;
/* read/write args */
- float *ray_depth;
float *dist_px;
/* return args */
float *r_loc;
float *r_no;
+ int *r_index;
Object **r_ob;
float (*r_obmat)[4];
- bool ret;
+ short ret;
};
static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
{
struct SnapObjUserData *dt = data;
- dt->ret |= snapObject(
+
+ short elem = snapObject(
sctx, dt->snapdata,
ob, obmat, is_obedit,
/* read/write args */
- dt->ray_depth, dt->dist_px,
+ dt->dist_px,
/* return args */
- dt->r_loc, dt->r_no,
+ dt->r_loc, dt->r_no, dt->r_index,
dt->r_ob, dt->r_obmat);
+
+ if (elem) {
+ dt->ret = elem;
+ }
}
@@ -2041,29 +2306,27 @@ static void sanp_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, flo
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*
*/
-static bool snapObjectsRay(
+static short snapObjectsRay(
SnapObjectContext *sctx, SnapData *snapdata,
- const eSnapSelect snap_select, const bool use_object_edit_cage,
+ const struct SnapObjectParams *params,
/* read/write args */
- float *ray_depth, float *dist_px,
+ float *dist_px,
/* return args */
- float r_loc[3], float r_no[3],
+ float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
- Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
-
struct SnapObjUserData data = {
.snapdata = snapdata,
- .ray_depth = ray_depth,
.dist_px = dist_px,
.r_loc = r_loc,
.r_no = r_no,
.r_ob = r_ob,
+ .r_index = r_index,
.r_obmat = r_obmat,
- .ret = false,
+ .ret = 0,
};
- iter_snap_objects(sctx, snap_select, obedit, sanp_obj_cb, &data);
+ iter_snap_objects(sctx, params, sanp_obj_cb, &data);
return data.ret;
}
@@ -2075,7 +2338,7 @@ static bool snapObjectsRay(
* \{ */
SnapObjectContext *ED_transform_snap_object_context_create(
- Main *bmain, Scene *scene, int flag)
+ Main *bmain, Scene *scene, Depsgraph *depsgraph, int flag)
{
SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
@@ -2083,6 +2346,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
sctx->bmain = bmain;
sctx->scene = scene;
+ sctx->depsgraph = depsgraph;
sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -2091,11 +2355,11 @@ SnapObjectContext *ED_transform_snap_object_context_create(
}
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
- Main *bmain, Scene *scene, int flag,
+ Main *bmain, Scene *scene, Depsgraph *depsgraph, int flag,
/* extra args for view3d */
const ARegion *ar, const View3D *v3d)
{
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, flag);
sctx->use_v3d = true;
sctx->v3d_data.ar = ar;
@@ -2110,13 +2374,8 @@ static void snap_object_data_free(void *sod_v)
case SNAP_MESH:
{
SnapObjectData_Mesh *sod = sod_v;
- for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
- if (sod->bvh_trees[i]) {
- free_bvhtree_from_mesh(sod->bvh_trees[i]);
- }
- }
- if (sod->poly_allocated) {
- MEM_freeN(sod->mpoly);
+ if (sod->treedata.tree) {
+ free_bvhtree_from_mesh(&sod->treedata);
}
break;
}
@@ -2164,9 +2423,8 @@ bool ED_transform_snap_object_project_ray_ex(
Object **r_ob, float r_obmat[4][4])
{
return raycastObjects(
- sctx,
+ sctx, params,
ray_start, ray_normal,
- params->snap_select, params->use_object_edit_cage,
ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
@@ -2193,9 +2451,8 @@ bool ED_transform_snap_object_project_ray_all(
#endif
bool retval = raycastObjects(
- sctx,
+ sctx, params,
ray_start, ray_normal,
- params->snap_select, params->use_object_edit_cage,
&ray_depth, NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -2256,61 +2513,159 @@ bool ED_transform_snap_object_project_ray(
r_co, r_no);
}
-static bool transform_snap_context_project_view3d_mixed_impl(
+static short transform_snap_context_project_view3d_mixed_impl(
SnapObjectContext *sctx,
const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
- bool use_depth,
- float r_co[3], float r_no[3])
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4])
{
- float ray_depth = BVH_RAYCAST_DIST_MAX;
- bool is_hit = false;
+ BLI_assert(
+ (snap_to_flag & (
+ SCE_SNAP_MODE_VERTEX |
+ SCE_SNAP_MODE_EDGE |
+ SCE_SNAP_MODE_FACE)) != 0);
- const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
+ short retval = 0;
+ bool has_hit = false;
+ int index = -1;
- BLI_assert(snap_to_flag != 0);
- BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
+ float loc[3], no[3], obmat[4][4];
+ Object *ob = NULL;
- if (use_depth) {
- const float dist_px_orig = dist_px ? *dist_px : 0;
- for (int i = 2; i >= 0; i--) {
- if (snap_to_flag & (1 << i)) {
- if (i == 0) {
- BLI_assert(dist_px != NULL);
- *dist_px = dist_px_orig;
- }
- if (ED_transform_snap_object_project_view3d(
- sctx,
- elem_type[i], params,
- mval, dist_px, &ray_depth,
- r_co, r_no))
- {
- /* 0.01 is a random but small value to prioritizing
- * the first elements of the loop */
- ray_depth += 0.01f;
- is_hit = true;
- }
- }
+ const ARegion *ar = sctx->v3d_data.ar;
+ const RegionView3D *rv3d = ar->regiondata;
+
+ bool use_occlusion_test =
+ params->use_occlusion_test &&
+ !(sctx->v3d_data.v3d->shading.flag & V3D_XRAY_FLAG(sctx->v3d_data.v3d));
+
+ if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
+ float ray_start[3], ray_normal[3];
+
+ if (!ED_view3d_win_to_ray_clipped_ex(
+ sctx->depsgraph,
+ sctx->v3d_data.ar, sctx->v3d_data.v3d,
+ mval, NULL, ray_normal, ray_start, true))
+ {
+ return false;
+ }
+
+ float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
+
+ has_hit = raycastObjects(
+ sctx, params,
+ ray_start, ray_normal,
+ &dummy_ray_depth, loc, no,
+ &index, &ob, obmat, NULL);
+
+ if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) {
+ retval = SCE_SNAP_MODE_FACE;
}
}
- else {
- for (int i = 0; i < 3; i++) {
- if (snap_to_flag & (1 << i)) {
- if (ED_transform_snap_object_project_view3d(
- sctx,
- elem_type[i], params,
- mval, dist_px, &ray_depth,
- r_co, r_no))
- {
- is_hit = true;
- break;
- }
+
+ if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE)) {
+ short elem;
+ float dist_px_tmp = *dist_px;
+
+ SnapData snapdata;
+ copy_m4_m4(snapdata.pmat, rv3d->persmat);
+ snapdata.win_size[0] = ar->winx;
+ snapdata.win_size[1] = ar->winy;
+ copy_v2_v2(snapdata.mval, mval);
+ snapdata.snap_to_flag = snap_to_flag;
+ snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
+
+ planes_from_projmat(
+ snapdata.pmat,
+ NULL, NULL, NULL, NULL,
+ snapdata.clip_plane[0], snapdata.clip_plane[1]);
+
+ snapdata.clip_plane_len = 2;
+
+ if (has_hit) {
+ /* Compute the new clip_pane but do not add it yet. */
+ float new_clipplane[4];
+ plane_from_point_normal_v3(new_clipplane, loc, no);
+ if (dot_v3v3(snapdata.clip_plane[0], new_clipplane) > 0.0f) {
+ /* The plane is facing the wrong direction. */
+ negate_v4(new_clipplane);
+ }
+
+ /* Small offset to simulate a kind of volume for edges and vertices. */
+ new_clipplane[3] += 0.01f;
+
+ /* Try to snap only to the polygon. */
+ elem = snap_mesh_polygon(
+ sctx, &snapdata, ob, obmat,
+ &dist_px_tmp, loc, no, &index);
+
+ if (elem) {
+ retval = elem;
+ }
+
+ /* Add the new clip plane to the beginning of the list. */
+ for (int i = snapdata.clip_plane_len; i != 0; i--) {
+ copy_v4_v4(snapdata.clip_plane[i], snapdata.clip_plane[i - 1]);
}
+ copy_v4_v4(snapdata.clip_plane[0], new_clipplane);
+ snapdata.clip_plane_len++;
}
+
+ elem = snapObjectsRay(
+ sctx, &snapdata, params,
+ &dist_px_tmp, loc, no, &index, &ob, obmat);
+
+ if (elem) {
+ retval = elem;
+ }
+
+ if ((retval == SCE_SNAP_MODE_EDGE) &&
+ (snapdata.snap_to_flag & SCE_SNAP_MODE_VERTEX))
+ {
+ retval = snap_mesh_edge_verts_mixed(
+ sctx, &snapdata,
+ ob, obmat, *dist_px,
+ &dist_px_tmp, loc, no, &index);
+ }
+
+ *dist_px = dist_px_tmp;
}
- return is_hit;
+ if (retval) {
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
+ return retval;
+ }
+
+ return 0;
+}
+
+bool ED_transform_snap_object_project_view3d_ex(
+ SnapObjectContext *sctx,
+ const unsigned short snap_to,
+ const struct SnapObjectParams *params,
+ const float mval[2], float *dist_px,
+ float r_loc[3], float r_no[3], int *r_index,
+ Object **r_ob, float r_obmat[4][4])
+{
+ return transform_snap_context_project_view3d_mixed_impl(
+ sctx,
+ snap_to, params,
+ mval, dist_px,
+ r_loc, r_no, r_index, r_ob, r_obmat) != 0;
}
/**
@@ -2321,86 +2676,15 @@ static bool transform_snap_context_project_view3d_mixed_impl(
* \param sctx: Snap context.
* \param mval_fl: Screenspace coordinate.
* \param dist_px: Maximum distance to snap (in pixels).
- * \param use_depth: Snap to the closest element, use when using more than one snap type.
* \param r_co: hit location.
* \param r_no: hit normal (optional).
* \return Snap success
*/
-bool ED_transform_snap_object_project_view3d_mixed(
- SnapObjectContext *sctx,
- const unsigned short snap_to_flag,
- const struct SnapObjectParams *params,
- const float mval_fl[2], float *dist_px,
- bool use_depth,
- float r_co[3], float r_no[3])
-{
- return transform_snap_context_project_view3d_mixed_impl(
- sctx,
- snap_to_flag, params,
- mval_fl, dist_px, use_depth,
- r_co, r_no);
-}
-
-bool ED_transform_snap_object_project_view3d_ex(
- SnapObjectContext *sctx,
- const unsigned short snap_to,
- const struct SnapObjectParams *params,
- const float mval[2], float *dist_px,
- float *ray_depth,
- float r_loc[3], float r_no[3], int *r_index,
- Object **r_ob, float r_obmat[4][4])
-{
- float ray_origin[3], ray_start[3], ray_normal[3], depth_range[2], ray_end[3];
-
- const ARegion *ar = sctx->v3d_data.ar;
- const RegionView3D *rv3d = ar->regiondata;
-
- ED_view3d_win_to_origin(ar, mval, ray_origin);
- ED_view3d_win_to_vector(ar, mval, ray_normal);
-
- ED_view3d_clip_range_get(
- sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata,
- &depth_range[0], &depth_range[1], false);
-
- madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]);
- madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]);
-
- if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) {
- return false;
- }
-
- float ray_depth_fallback;
- if (ray_depth == NULL) {
- ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
- ray_depth = &ray_depth_fallback;
- }
-
- if (snap_to == SCE_SNAP_MODE_FACE) {
- return raycastObjects(
- sctx,
- ray_start, ray_normal,
- params->snap_select, params->use_object_edit_cage,
- ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
- }
- else {
- SnapData snapdata;
- const enum eViewProj view_proj = ((RegionView3D *)ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
- snap_data_set(&snapdata, ar, snap_to, view_proj, mval,
- ray_origin, ray_start, ray_normal, depth_range);
-
- return snapObjectsRay(
- sctx, &snapdata,
- params->snap_select, params->use_object_edit_cage,
- ray_depth, dist_px, r_loc, r_no, r_ob, r_obmat);
- }
-}
-
bool ED_transform_snap_object_project_view3d(
SnapObjectContext *sctx,
const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
- float *ray_depth,
float r_loc[3], float r_no[3])
{
return ED_transform_snap_object_project_view3d_ex(
@@ -2408,7 +2692,6 @@ bool ED_transform_snap_object_project_view3d(
snap_to,
params,
mval, dist_px,
- ray_depth,
r_loc, r_no, NULL,
NULL, NULL);
}
@@ -2426,6 +2709,7 @@ bool ED_transform_snap_object_project_all_view3d_ex(
float ray_start[3], ray_normal[3];
if (!ED_view3d_win_to_ray_clipped_ex(
+ sctx->depsgraph,
sctx->v3d_data.ar, sctx->v3d_data.v3d,
mval, NULL, ray_normal, ray_start, true))
{
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index c69fabdbd70..8b4292dedbd 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -36,6 +36,7 @@
#include "CLG_log.h"
#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
#include "BLI_utildefines.h"
#include "BLI_callbacks.h"
@@ -48,18 +49,24 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_layer.h"
#include "BKE_undo_system.h"
+#include "BKE_workspace.h"
+#include "BKE_paint.h"
-#include "BLO_runtime.h"
+#include "BLO_writefile.h"
#include "ED_gpencil.h"
#include "ED_render.h"
+#include "ED_object.h"
#include "ED_screen.h"
#include "ED_undo.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -109,6 +116,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname, ReportList
CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
+ ScrArea *sa = CTX_wm_area(C);
/* undo during jobs are running can easily lead to freeing data using by jobs,
* or they can just lead to freezing job in some other cases */
@@ -127,6 +135,12 @@ static int ed_undo_step(bContext *C, int step, const char *undoname, ReportList
if (ED_gpencil_session_active()) {
return ED_undo_gpencil_step(C, step, undoname);
}
+ if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ Object *obact = CTX_data_active_object(C);
+ if (obact && (obact->type == OB_GPENCIL)) {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+ }
UndoStep *step_data_from_name = NULL;
int step_for_callback = step;
@@ -161,6 +175,23 @@ static int ed_undo_step(bContext *C, int step, const char *undoname, ReportList
else {
BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step);
}
+
+ /* Set special modes for grease pencil */
+ if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ Object *obact = CTX_data_active_object(C);
+ if (obact && (obact->type == OB_GPENCIL)) {
+ /* set cursor */
+ if (ELEM(obact->mode, OB_MODE_GPENCIL_PAINT, OB_MODE_GPENCIL_SCULPT, OB_MODE_GPENCIL_WEIGHT)) {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
+ else {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+ /* set workspace mode */
+ Base *basact = CTX_data_active_base(C);
+ ED_object_base_activate(C, basact);
+ }
+ }
}
/* App-Handlers (post). */
@@ -183,6 +214,11 @@ static int ed_undo_step(bContext *C, int step, const char *undoname, ReportList
WM_event_add_notifier(C, NC_WINDOW, NULL);
WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL);
+ WM_toolsystem_refresh_active(C);
+
+ Main *bmain = CTX_data_main(C);
+ WM_toolsystem_refresh_screen_all(bmain);
+
return OPERATOR_FINISHED;
}
@@ -363,7 +399,7 @@ void ED_OT_undo_redo(wmOperatorType *ot)
* \{ */
/* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
-int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
+int ED_undo_operator_repeat(bContext *C, wmOperator *op)
{
int ret = 0;
@@ -373,11 +409,12 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
struct Scene *scene = CTX_data_scene(C);
/* keep in sync with logic in view3d_panel_operator_redo() */
- ARegion *ar = CTX_wm_region(C);
- ARegion *ar1 = BKE_area_find_region_active_win(CTX_wm_area(C));
+ ARegion *ar_orig = CTX_wm_region(C);
+ ARegion *ar_win = BKE_area_find_region_active_win(CTX_wm_area(C));
- if (ar1)
- CTX_wm_region_set(C, ar1);
+ if (ar_win) {
+ CTX_wm_region_set(C, ar_win);
+ }
if ((WM_operator_repeat_check(C, op)) &&
(WM_operator_poll(C, op->type)) &&
@@ -390,8 +427,6 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
{
int retval;
- ED_viewport_render_kill_jobs(wm, CTX_data_main(C), true);
-
if (G.debug & G_DEBUG)
printf("redo_cb: operator redo %s\n", op->type->name);
@@ -409,6 +444,15 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
}
}
+ if (op->type->flag & OPTYPE_USE_EVAL_DATA) {
+ /* We need to force refresh of depsgraph after undo step,
+ * redoing the operator *may* rely on some valid evaluated data. */
+ Main *bmain = CTX_data_main(C);
+ scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BKE_scene_view_layer_graph_evaluated_ensure(bmain, scene, view_layer);
+ }
+
retval = WM_operator_repeat(C, op);
if ((retval & OPERATOR_FINISHED) == 0) {
if (G.debug & G_DEBUG)
@@ -426,7 +470,7 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
}
/* set region back */
- CTX_wm_region_set(C, ar);
+ CTX_wm_region_set(C, ar_orig);
}
else {
CLOG_WARN(&LOG, "called with NULL 'op'");
@@ -468,7 +512,7 @@ static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
item_tmp.identifier = us->name;
item_tmp.name = IFACE_(us->name);
if (us == wm->undo_stack->step_active) {
- item_tmp.icon = ICON_RESTRICT_VIEW_OFF;
+ item_tmp.icon = ICON_HIDE_OFF;
}
else {
item_tmp.icon = ICON_NONE;
@@ -551,3 +595,24 @@ void ED_OT_undo_history(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Undo Helper Functions
+ * \{ */
+
+void ED_undo_object_set_active_or_warn(ViewLayer *view_layer, Object *ob, const char *info, CLG_LogRef *log)
+{
+ Object *ob_prev = OBACT(view_layer);
+ if (ob_prev != ob) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base != NULL) {
+ view_layer->basact = base;
+ }
+ else {
+ /* Should never fail, may not crash but can give odd behavior. */
+ CLOG_WARN(log, "'%s' failed to restore active object: '%s'", info, ob->id.name + 2);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
index bb81da74f88..4b38ab282a0 100644
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -76,16 +76,15 @@ static bool memfile_undosys_step_encode(struct bContext *C, UndoStep *us_p)
MemFileUndoStep *us_prev = (MemFileUndoStep *)BKE_undosys_step_find_by_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE);
us->data = BKE_memfile_undo_encode(bmain, us_prev ? us_prev->data : NULL);
us->step.data_size = us->data->undo_size;
+
return true;
}
static void memfile_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
{
/* Loading the content will correctly switch into compatible non-object modes. */
- ED_object_mode_set(C, OB_MODE_OBJECT);
+ ED_object_mode_exit(C);
- /* This is needed so undoing/redoing doesn't crash with threaded previews going */
- ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true);
MemFileUndoStep *us = (MemFileUndoStep *)us_p;
BKE_memfile_undo_decode(us->data, C);
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index c0a6fe676f1..6bef0f77e1a 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../depsgraph
../../imbuf
../../gpu
../../makesdna
@@ -41,7 +42,9 @@ set(INC_SYS
set(SRC
ed_transverts.c
ed_util.c
+ gizmo_utils.c
numinput.c
+ select_utils.c
# general includes
../include/BIF_gl.h
@@ -53,6 +56,8 @@ set(SRC
../include/ED_curve.h
../include/ED_datafiles.h
../include/ED_fileselect.h
+ ../include/ED_gizmo_library.h
+ ../include/ED_gizmo_utils.h
../include/ED_gpencil.h
../include/ED_image.h
../include/ED_info.h
@@ -73,9 +78,11 @@ set(SRC
../include/ED_particle.h
../include/ED_physics.h
../include/ED_render.h
+ ../include/ED_scene.h
../include/ED_screen.h
../include/ED_screen_types.h
../include/ED_sculpt.h
+ ../include/ED_select_utils.h
../include/ED_sequencer.h
../include/ED_sound.h
../include/ED_space_api.h
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index 09f1c060641..011e9fc008c 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -39,11 +39,13 @@
#include "BLI_math.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_lattice.h"
#include "BKE_editmesh.h"
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
+#include "BKE_mesh_iterators.h"
+
+#include "DEG_depsgraph.h"
#include "ED_armature.h"
@@ -56,7 +58,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
const int mode = tvs->mode;
BLI_assert(ED_transverts_check_obedit(obedit) == true);
- DAG_id_tag_update(obedit->data, 0);
+ DEG_id_tag_update(obedit->data, 0);
if (obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -303,9 +305,9 @@ void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const
userdata[1] = tvs->transverts;
}
- if (tvs->transverts && em->derivedCage) {
+ if (tvs->transverts && em->mesh_eval_cage) {
BM_mesh_elem_table_ensure(bm, BM_VERT);
- em->derivedCage->foreachMappedVert(em->derivedCage, set_mapped_co, userdata, DM_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(em->mesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
}
}
else if (obedit->type == OB_ARMATURE) {
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 67b43814d40..f316b1a61cb 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -28,13 +28,13 @@
* \ingroup edutil
*/
-
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "MEM_guardedalloc.h"
+#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
@@ -53,12 +53,15 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_packedFile.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_undo_system.h"
+#include "BKE_workspace.h"
#include "ED_armature.h"
#include "ED_buttons.h"
@@ -71,6 +74,9 @@
#include "ED_space_api.h"
#include "ED_util.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -84,11 +90,8 @@
void ED_editors_init(bContext *C)
{
- wmWindowManager *wm = CTX_wm_manager(C);
Main *bmain = CTX_data_main(C);
- Scene *sce = CTX_data_scene(C);
- Object *ob, *obact = (sce && sce->basact) ? sce->basact->object : NULL;
- ID *data;
+ wmWindowManager *wm = CTX_wm_manager(C);
if (wm->undo_stack == NULL) {
wm->undo_stack = BKE_undosys_stack_create();
@@ -103,21 +106,35 @@ void ED_editors_init(bContext *C)
/* toggle on modes for objects that were saved with these enabled. for
* e.g. linked objects we have to ensure that they are actually the
* active object in this scene. */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- int mode = ob->mode;
-
- if (!ELEM(mode, OB_MODE_OBJECT, OB_MODE_POSE)) {
- ob->mode = OB_MODE_OBJECT;
- data = ob->data;
+ Object *obact = CTX_data_active_object(C);
+ if (obact != NULL) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ int mode = ob->mode;
- if (ob == obact && !ID_IS_LINKED(ob) && !(data && ID_IS_LINKED(data)))
- ED_object_mode_toggle(C, mode);
+ if (mode == OB_MODE_OBJECT) {
+ /* pass */
+ }
+ else if (!BKE_object_has_mode_data(ob, mode)) {
+ /* For multi-edit mode we may already have mode data.
+ * (grease pencil does not need it)
+ */
+ if (ob->type != OB_GPENCIL) {
+ ID *data = ob->data;
+ ob->mode = OB_MODE_OBJECT;
+ if ((ob == obact) && !ID_IS_LINKED(ob) && !(data && ID_IS_LINKED(data))) {
+ ED_object_mode_toggle(C, mode);
+ }
+ }
+ }
}
}
/* image editor paint mode */
- if (sce) {
- ED_space_image_paint_update(bmain, wm, sce);
+ {
+ Scene *sce = CTX_data_scene(C);
+ if (sce) {
+ ED_space_image_paint_update(bmain, wm, sce);
+ }
}
SWAP(int, reports->flag, reports_flag_prev);
@@ -127,7 +144,6 @@ void ED_editors_init(bContext *C)
void ED_editors_exit(bContext *C)
{
Main *bmain = CTX_data_main(C);
- Scene *sce;
if (!bmain)
return;
@@ -142,22 +158,19 @@ void ED_editors_exit(bContext *C)
}
}
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->obedit) {
- Object *ob = sce->obedit;
-
- if (ob) {
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- if (me->edit_btmesh) {
- EDBM_mesh_free(me->edit_btmesh);
- MEM_freeN(me->edit_btmesh);
- me->edit_btmesh = NULL;
- }
- }
- else if (ob->type == OB_ARMATURE) {
- ED_armature_edit_free(ob->data);
- }
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ if (me->edit_btmesh) {
+ EDBM_mesh_free(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ me->edit_btmesh = NULL;
+ }
+ }
+ else if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
+ if (arm->edbo) {
+ ED_armature_edit_free(ob->data);
}
}
}
@@ -329,16 +342,30 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info
{
wmWindow *win = CTX_wm_window(C);
const float *mval_src = (float *)arg_info;
- const int mval_dst[2] = {win->eventstate->x - ar->winrct.xmin,
- win->eventstate->y - ar->winrct.ymin};
-
- UI_ThemeColor(TH_VIEW_OVERLAY);
- setlinestyle(3);
- glBegin(GL_LINES);
- glVertex2iv(mval_dst);
- glVertex2fv(mval_src);
- glEnd();
- setlinestyle(0);
+ const float mval_dst[2] = {win->eventstate->x - ar->winrct.xmin,
+ win->eventstate->y - ar->winrct.ymin};
+
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformThemeColor(TH_VIEW_OVERLAY);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2fv(shdr_pos, mval_src);
+ immVertex2fv(shdr_pos, mval_dst);
+ immEnd();
+
+ immUnbindProgram();
}
/**
diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c
new file mode 100644
index 00000000000..6b150f93e38
--- /dev/null
+++ b/source/blender/editors/util/gizmo_utils.c
@@ -0,0 +1,76 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gizmo_utils.c
+ * \ingroup edutil
+ *
+ * \name Generic Gizmo Utilities.
+ */
+
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "DNA_workspace_types.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+#include "WM_toolsystem.h"
+
+#include "ED_gizmo_utils.h"
+
+bool ED_gizmo_poll_or_unlink_delayed_from_operator(
+ const bContext *C, wmGizmoGroupType *gzgt,
+ const char *idname)
+{
+#if 0
+ /* Causes selection to continue showing the last gizmo. */
+ wmOperator *op = WM_operator_last_redo(C);
+#else
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmOperator *op = wm->operators.last;
+#endif
+
+ if (op == NULL || !STREQ(op->type->idname, idname)) {
+ WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
+ return false;
+ }
+ return true;
+}
+
+bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C, wmGizmoGroupType *gzgt, const char *gzgt_idname)
+{
+ bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
+ if ((tref_rt == NULL) ||
+ !STREQ(gzgt_idname, tref_rt->gizmo_group))
+ {
+ WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
+ return false;
+ }
+ return true;
+}
+
+/** Can use this as poll function directly. */
+bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupType *gzgt)
+{
+ return ED_gizmo_poll_or_unlink_delayed_from_tool_ex(C, gzgt, gzgt->idname);
+}
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index f25bc6350c1..52cf1b2d708 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -48,12 +48,16 @@
#include "ED_numinput.h"
#include "UI_interface.h"
+/* Numeric input which isn't allowing full numeric editing. */
+#define USE_FAKE_EDIT
/* NumInput.flag */
enum {
/* (1 << 8) and below are reserved for public flags! */
NUM_EDIT_FULL = (1 << 9), /* Enable full editing, with units and math operators support. */
+#ifdef USE_FAKE_EDIT
NUM_FAKE_EDITED = (1 << 10), /* Fake edited state (temp, avoids issue with backspace). */
+#endif
};
/* NumInput.val_flag[] */
@@ -61,8 +65,10 @@ enum {
/* (1 << 8) and below are reserved for public flags! */
NUM_EDITED = (1 << 9), /* User has edited this value somehow. */
NUM_INVALID = (1 << 10), /* Current expression for this value is invalid. */
+#ifdef USE_FAKE_EDIT
NUM_NEGATE = (1 << 11), /* Current expression's result has to be negated. */
NUM_INVERSE = (1 << 12), /* Current expression's result has to be inverted. */
+#endif
};
/* ************************** Functions *************************** */
@@ -109,6 +115,7 @@ void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
char before_cursor[NUM_STR_REP_LEN];
char val[16];
+#ifdef USE_FAKE_EDIT
if (n->val_flag[i] & NUM_NEGATE) {
heading_exp = (n->val_flag[i] & NUM_INVERSE) ? "-1/(" : "-(";
trailing_exp = ")";
@@ -117,6 +124,7 @@ void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
heading_exp = "1/(";
trailing_exp = ")";
}
+#endif
if (n->val_flag[i] & NUM_INVALID) {
BLI_strncpy(val, "Invalid", sizeof(val));
@@ -156,9 +164,11 @@ bool hasNumInput(const NumInput *n)
{
short i;
+#ifdef USE_FAKE_EDIT
if (n->flag & NUM_FAKE_EDITED) {
return true;
}
+#endif
for (i = 0; i <= n->idx_max; i++) {
if (n->val_flag[i] & NUM_EDITED) {
@@ -179,10 +189,13 @@ bool applyNumInput(NumInput *n, float *vec)
if (hasNumInput(n)) {
for (j = 0; j <= n->idx_max; j++) {
+#ifdef USE_FAKE_EDIT
if (n->flag & NUM_FAKE_EDITED) {
val = n->val[j];
}
- else {
+ else
+#endif
+ {
/* if AFFECTALL and no number typed and cursor not on number, use first number */
i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j;
val = (!(n->val_flag[i] & NUM_EDITED) && n->val_flag[i] & NUM_NULL_ONE) ? 1.0f : n->val[i];
@@ -202,7 +215,9 @@ bool applyNumInput(NumInput *n, float *vec)
}
vec[j] = val;
}
+#ifdef USE_FAKE_EDIT
n->flag &= ~NUM_FAKE_EDITED;
+#endif
return true;
}
else {
@@ -239,6 +254,32 @@ static bool editstr_insert_at_cursor(NumInput *n, const char *buf, const int buf
return true;
}
+bool user_string_to_number(bContext *C, const char *str, const UnitSettings *unit, int type, double *r_value)
+{
+#ifdef WITH_PYTHON
+ double unit_scale = BKE_scene_unit_scale(unit, type, 1.0);
+ if (!bUnit_ContainsUnit(str, unit->system, type)) {
+ int success = BPY_execute_string_as_number(C, NULL, str, true, r_value);
+ *r_value *= bUnit_PreferredUnitScalar(unit, type);
+ *r_value /= unit_scale;
+ return success;
+ }
+ else {
+ char str_unit_convert[256];
+ BLI_strncpy(str_unit_convert, str, sizeof(str_unit_convert));
+ bUnit_ReplaceString(
+ str_unit_convert, sizeof(str_unit_convert), str,
+ unit_scale, unit->system, type);
+
+ return BPY_execute_string_as_number(C, NULL, str_unit_convert, true, r_value);
+ }
+#else
+ *r_value = atof(str);
+ return true;
+#endif
+}
+
+
static bool editstr_is_simple_numinput(const char ascii)
{
if (ascii >= '0' && ascii <= '9') {
@@ -261,6 +302,21 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
short dir = STRCUR_DIR_NEXT, mode = STRCUR_JUMP_NONE;
int cur;
+#ifdef USE_FAKE_EDIT
+ if (U.flag & USER_FLAG_NUMINPUT_ADVANCED)
+#endif
+ {
+ if ((event->ctrl == 0) && (event->alt == 0) && (event->ascii != '\0') &&
+ strchr("01234567890@%^&*-+/{}()[]<>.|", event->ascii))
+ {
+ if (!(n->flag & NUM_EDIT_FULL)) {
+ n->flag |= NUM_EDITED;
+ n->flag |= NUM_EDIT_FULL;
+ n->val_flag[idx] |= NUM_EDITED;
+ }
+ }
+ }
+
switch (event->type) {
case EVT_MODAL_MAP:
if (ELEM(event->val, NUM_MODAL_INCREMENT_UP, NUM_MODAL_INCREMENT_DOWN)) {
@@ -282,7 +338,11 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
n->val_flag[0] &= ~NUM_EDITED;
n->val_flag[1] &= ~NUM_EDITED;
n->val_flag[2] &= ~NUM_EDITED;
+#ifdef USE_FAKE_EDIT
n->flag |= NUM_FAKE_EDITED;
+#else
+ n->flag |= NUM_EDIT_FULL;
+#endif
updated = true;
break;
}
@@ -347,7 +407,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
}
return false;
case TABKEY:
+#ifdef USE_FAKE_EDIT
n->val_flag[idx] &= ~(NUM_NEGATE | NUM_INVERSE);
+#endif
idx = (idx + idx_max + (event->ctrl ? 0 : 2)) % (idx_max + 1);
n->idx = idx;
@@ -382,6 +444,8 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
}
break;
#endif
+
+#ifdef USE_FAKE_EDIT
case PADMINUS:
case MINUSKEY:
if (event->ctrl || !(n->flag & NUM_EDIT_FULL)) {
@@ -396,6 +460,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
updated = true;
}
break;
+#endif
case CKEY:
if (event->ctrl) {
/* Copy current str to the copypaste buffer. */
@@ -431,6 +496,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
ascii[0] = event->ascii;
}
+#ifdef USE_FAKE_EDIT
/* XXX Hack around keyboards without direct access to '=' nor '*'... */
if (ELEM(ascii[0], '=', '*')) {
if (!(n->flag & NUM_EDIT_FULL)) {
@@ -443,6 +509,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
return true;
}
}
+#endif
/* Up to this point, if we have a ctrl modifier, skip.
* This allows to still access most of modals' shortcuts even in numinput mode.
@@ -478,39 +545,21 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
/* At this point, our value has changed, try to interpret it with python (if str is not empty!). */
if (n->str[0]) {
const float val_prev = n->val[idx];
- double val;
-#ifdef WITH_PYTHON
Scene *sce = CTX_data_scene(C);
- char str_unit_convert[NUM_STR_REP_LEN * 6]; /* Should be more than enough! */
- const char *default_unit = NULL;
-
- /* Use scale_length if needed! */
- const float fac = (float)BKE_scene_unit_scale(&sce->unit, n->unit_type[idx], 1.0);
-
- /* Make radian default unit when needed. */
- if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) {
- default_unit = "r";
- }
-
- BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert));
- bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), default_unit, fac,
- n->unit_sys, n->unit_type[idx]);
+ double val;
+ int success = user_string_to_number(C, n->str, &sce->unit, n->unit_type[idx], &val);
- /* Note: with angles, we always get values as radians here... */
- if (BPY_execute_string_as_number(C, NULL, str_unit_convert, false, &val)) {
+ if (success) {
n->val[idx] = (float)val;
n->val_flag[idx] &= ~NUM_INVALID;
}
else {
n->val_flag[idx] |= NUM_INVALID;
}
-#else /* Very unlikely, but does not harm... */
- val = atof(n->str);
- n->val[idx] = (float)val;
- UNUSED_VARS(C);
-#endif /* WITH_PYTHON */
+
+#ifdef USE_FAKE_EDIT
if (n->val_flag[idx] & NUM_NEGATE) {
n->val[idx] = -n->val[idx];
}
@@ -526,6 +575,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
}
n->val[idx] = (float)val;
}
+#endif
if (UNLIKELY(!isfinite(n->val[idx]))) {
n->val[idx] = val_prev;
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
new file mode 100644
index 00000000000..92de124800b
--- /dev/null
+++ b/source/blender/editors/util/select_utils.c
@@ -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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file select_utils.c
+ * \ingroup edutil
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_kdtree.h"
+#include "BLI_math.h"
+
+#include "ED_select_utils.h"
+
+#include "float.h"
+
+/** 1: select, 0: deselect, -1: pass. */
+int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside)
+{
+ switch (sel_op) {
+ case SEL_OP_ADD:
+ return (!is_select && (is_inside)) ? 1 : -1;
+ case SEL_OP_SUB:
+ return (is_select && is_inside) ? 0 : -1;
+ case SEL_OP_SET:
+ return is_inside ? 1 : 0;
+ case SEL_OP_AND:
+ return (is_select && is_inside) ? -1 : (is_select ? 0 : -1);
+ case SEL_OP_XOR:
+ return (is_select && is_inside) ? 0 : ((!is_select && is_inside) ? 1 : -1);
+ }
+ BLI_assert(!"invalid sel_op");
+ return -1;
+}
+/**
+ * Use when we've de-selected all items first (for modes that need it).
+ *
+ * \note In some cases changing selection needs to perform other checks,
+ * so it's more straightforward to deselect all, then select.
+ */
+int ED_select_op_action_deselected(const eSelectOp sel_op, const bool is_select, const bool is_inside)
+{
+ switch (sel_op) {
+ case SEL_OP_ADD:
+ return (!is_select && is_inside) ? 1 : -1;
+ case SEL_OP_SUB:
+ return (is_select && is_inside) ? 0 : -1;
+ case SEL_OP_SET:
+ /* Only difference w/ function above. */
+ return is_inside ? 1 : -1;
+ case SEL_OP_AND:
+ return (is_select && is_inside) ? -1 : (is_select ? 0 : -1);
+ case SEL_OP_XOR:
+ return (is_select && is_inside) ? 0 : ((!is_select && is_inside) ? 1 : -1);
+ }
+ BLI_assert(!"invalid sel_op");
+ return -1;
+}
+
+int ED_select_similar_compare_float(const float delta, const float thresh, const int compare)
+{
+ switch (compare) {
+ case SIM_CMP_EQ:
+ return (fabsf(delta) < thresh + FLT_EPSILON);
+ case SIM_CMP_GT:
+ return ((delta + thresh) > -FLT_EPSILON);
+ case SIM_CMP_LT:
+ return ((delta - thresh) < FLT_EPSILON);
+ default:
+ BLI_assert(0);
+ return 0;
+ }
+}
+
+bool ED_select_similar_compare_float_tree(const KDTree *tree, const float length, const float thresh, const int compare)
+{
+ /* Length of the edge we want to compare against. */
+ float nearest_edge_length;
+
+ switch (compare) {
+ case SIM_CMP_EQ:
+ /* Compare to the edge closest to the current edge. */
+ nearest_edge_length = length;
+ break;
+ case SIM_CMP_GT:
+ /* Compare against the shortest edge. */
+ /* -FLT_MAX leads to some precision issues and the wrong edge being selected.
+ * For example, in a tree with 1, 2 and 3, which is stored squared as 1, 4, 9, it returns as the nearest
+ * length/node the "4" instead of "1". */
+ nearest_edge_length = -1.0f;
+ break;
+ case SIM_CMP_LT:
+ /* Compare against the longest edge. */
+ nearest_edge_length = FLT_MAX;
+ break;
+ default:
+ BLI_assert(0);
+ return false;
+ }
+
+ KDTreeNearest nearest;
+ float dummy[3] = {nearest_edge_length, 0.0f, 0.0f};
+ if (BLI_kdtree_find_nearest(tree, dummy, &nearest) != -1) {
+ float delta = length - nearest.co[0];
+ return ED_select_similar_compare_float(delta, thresh, compare);
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index 543ef0e0663..a933717fe98 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blenlib
../../blentranslation
../../bmesh
+ ../../depsgraph
../../gpu
../../makesdna
../../makesrna
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index f9c5dd89179..317a07bcf96 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -61,22 +61,19 @@
/* UV Utilities */
-static int uvedit_center(Scene *scene, BMEditMesh *em, Image *ima, float center[2])
+static int uvedit_center(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float center[2])
{
BMFace *f;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
int tot = 0;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
zero_v2(center);
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(f, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, f, tf))
+ if (!uvedit_face_visible_test(scene, obedit, ima, f))
continue;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
@@ -96,20 +93,17 @@ static int uvedit_center(Scene *scene, BMEditMesh *em, Image *ima, float center[
return tot;
}
-static void uvedit_translate(Scene *scene, BMEditMesh *em, Image *ima, float delta[2])
+static void uvedit_translate(Scene *scene, Object *obedit, BMEditMesh *em, Image *ima, float delta[2])
{
BMFace *f;
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
- MTexPoly *tf;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(f, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, f, tf))
+ if (!uvedit_face_visible_test(scene, obedit, ima, f))
continue;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
@@ -140,7 +134,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
em = BKE_editmesh_from_object(obedit);
- if (uvedit_center(scene, em, ima, center)) {
+ if (uvedit_center(scene, obedit, em, ima, center)) {
float range_xy[2][2] = {
{-10.0f, 10.0f},
{-10.0f, 10.0f},
@@ -196,7 +190,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
em = BKE_editmesh_from_object(obedit);
ED_space_image_get_size(sima, &imx, &imy);
- uvedit_center(scene, em, ima, center);
+ uvedit_center(scene, obedit, em, ima, center);
if (sima->flag & SI_COORDFLOATS) {
delta[0] = uvedit_old_center[0] - center[0];
@@ -207,7 +201,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
delta[1] = uvedit_old_center[1] / imy - center[1];
}
- uvedit_translate(scene, em, ima, delta);
+ uvedit_translate(scene, obedit, em, ima, delta);
WM_event_add_notifier(C, NC_IMAGE, sima->image);
}
@@ -216,6 +210,10 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
static bool image_panel_uv_poll(const bContext *C, PanelType *UNUSED(pt))
{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (sima->mode != SI_MODE_UV) {
+ return false;
+ }
Object *obedit = CTX_data_edit_object(C);
return ED_uvedit_test(obedit);
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index a9f650a6d7a..dcdcc50db6e 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -33,6 +33,8 @@
#include <stdlib.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -41,20 +43,32 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "../../draw/intern/draw_cache_impl.h"
+
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_buffer.h"
#include "BLI_bitmap.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_material.h"
+#include "BKE_layer.h"
#include "BKE_scene.h"
-#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+#include "GPU_draw.h"
+
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_uvedit.h"
@@ -65,56 +79,6 @@
#include "uvedit_intern.h"
-#include "GPU_basic_shader.h"
-
-/* use editmesh tessface */
-#define USE_EDBM_LOOPTRIS
-
-static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset);
-
-void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
-{
- float zoom[2], x_fac, y_fac;
-
- UI_view2d_scale_get_inverse(&ar->v2d, &zoom[0], &zoom[1]);
-
- mul_v2_fl(zoom, 256.0f * UI_DPI_FAC);
- x_fac = zoom[0];
- y_fac = zoom[1];
-
- cpack(0xFFFFFF);
- glTranslate2fv(cursor);
- fdrawline(-0.05f * x_fac, 0, 0, 0.05f * y_fac);
- fdrawline(0, 0.05f * y_fac, 0.05f * x_fac, 0.0f);
- fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac);
- fdrawline(0.0f, -0.05f * y_fac, -0.05f * x_fac, 0.0f);
-
- setlinestyle(4);
- cpack(0xFF);
- fdrawline(-0.05f * x_fac, 0.0f, 0.0f, 0.05f * y_fac);
- fdrawline(0.0f, 0.05f * y_fac, 0.05f * x_fac, 0.0f);
- fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac);
- fdrawline(0.0f, -0.05f * y_fac, -0.05f * x_fac, 0.0f);
-
-
- setlinestyle(0.0f);
- cpack(0x0);
- fdrawline(-0.020f * x_fac, 0.0f, -0.1f * x_fac, 0.0f);
- fdrawline(0.1f * x_fac, 0.0f, 0.020f * x_fac, 0.0f);
- fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac);
- fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac);
-
- setlinestyle(1);
- cpack(0xFFFFFF);
- fdrawline(-0.020f * x_fac, 0.0f, -0.1f * x_fac, 0.0f);
- fdrawline(0.1f * x_fac, 0.0f, 0.020f * x_fac, 0.0f);
- fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac);
- fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac);
-
- glTranslatef(-cursor[0], -cursor[1], 0.0);
- setlinestyle(0);
-}
-
static int draw_uvs_face_check(Scene *scene)
{
ToolSettings *ts = scene->toolsettings;
@@ -132,832 +96,360 @@ static int draw_uvs_face_check(Scene *scene)
return (ts->uv_selectmode == UV_SELECT_FACE);
}
-static void draw_uvs_shadow(Object *obedit)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMFace *efa;
- BMIter iter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- /* draws the mesh when painting */
- UI_ThemeColor(TH_UV_SHADOW);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
- }
-}
-
-static int draw_uvs_dm_shadow(DerivedMesh *dm)
+static uchar get_state(SpaceImage *sima, Scene *scene)
{
- /* draw shadow mesh - this is the mesh with the modifier applied */
+ ToolSettings *ts = scene->toolsettings;
+ int drawfaces = draw_uvs_face_check(scene);
+ const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
+ uchar state = UVEDIT_EDGES | UVEDIT_DATA;
- if (dm && dm->drawUVEdges && CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
- UI_ThemeColor(TH_UV_SHADOW);
- dm->drawUVEdges(dm);
- return 1;
+ if (drawfaces) {
+ state |= UVEDIT_FACEDOTS;
}
+ if (draw_stretch || !(sima->flag & SI_NO_DRAWFACES)) {
+ state |= UVEDIT_FACES;
- return 0;
-}
-
-static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTexPoly *activetf)
-{
- BMesh *bm = em->bm;
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MTexPoly *tf;
- MLoopUV *luv;
- Image *ima = sima->image;
- float aspx, aspy, col[4];
- int i;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
-
- BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_buffer_declare_static(vec2f, tf_uvorig_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
-
- ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
-
- switch (sima->dt_uvstretch) {
- case SI_UVDT_STRETCH_AREA:
- {
- float totarea = 0.0f, totuvarea = 0.0f, areadiff, uvarea, area;
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- const int efa_len = efa->len;
- float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len);
- float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len);
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(tf_uvorig[i], luv->uv);
- }
-
- uv_poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len);
-
- totarea += BM_face_calc_area(efa);
- totuvarea += area_poly_v2(tf_uv, efa->len);
-
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
- else {
- if (tf == activetf)
- activetf = NULL;
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- }
- }
-
- if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) {
- col[0] = 1.0;
- col[1] = col[2] = 0.0;
- glColor3fv(col);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- glBegin(GL_POLYGON);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
- }
- }
+ if (draw_stretch) {
+ if (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) {
+ state |= UVEDIT_STRETCH_AREA;
}
else {
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- const int efa_len = efa->len;
- float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len);
- float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len);
-
- area = BM_face_calc_area(efa) / totarea;
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(tf_uvorig[i], luv->uv);
- }
-
- uv_poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len);
-
- uvarea = area_poly_v2(tf_uv, efa->len) / totuvarea;
-
- if (area < FLT_EPSILON || uvarea < FLT_EPSILON)
- areadiff = 1.0f;
- else if (area > uvarea)
- areadiff = 1.0f - (uvarea / area);
- else
- areadiff = 1.0f - (area / uvarea);
-
- weight_to_rgb(col, areadiff);
- glColor3fv(col);
-
- /* TODO: USE_EDBM_LOOPTRIS */
- glBegin(GL_POLYGON);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
- }
- }
+ state |= UVEDIT_STRETCH_ANGLE;
}
- break;
- }
- case SI_UVDT_STRETCH_ANGLE:
- {
- float a;
-
- BLI_buffer_declare_static(float, uvang_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_buffer_declare_static(float, ang_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_buffer_declare_static(vec3f, av_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_buffer_declare_static(vec2f, auv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
-
- col[3] = 0.5f; /* hard coded alpha, not that nice */
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- const int efa_len = efa->len;
- float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len);
- float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len);
- float *uvang = BLI_buffer_reinit_data(&uvang_buf, float, efa_len);
- float *ang = BLI_buffer_reinit_data(&ang_buf, float, efa_len);
- float (*av)[3] = (float (*)[3])BLI_buffer_reinit_data(&av_buf, vec3f, efa_len);
- float (*auv)[2] = (float (*)[2])BLI_buffer_reinit_data(&auv_buf, vec2f, efa_len);
- int j;
-
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(tf_uvorig[i], luv->uv);
- }
-
- uv_poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa_len);
-
- j = efa_len - 1;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- sub_v2_v2v2(auv[i], tf_uv[j], tf_uv[i]); normalize_v2(auv[i]);
- sub_v3_v3v3(av[i], l->prev->v->co, l->v->co); normalize_v3(av[i]);
- j = i;
- }
-
- for (i = 0; i < efa_len; i++) {
-#if 0
- /* Simple but slow, better reuse normalized vectors
- * (Not ported to bmesh, copied for reference) */
- uvang1 = RAD2DEG(angle_v2v2v2(tf_uv[3], tf_uv[0], tf_uv[1]));
- ang1 = RAD2DEG(angle_v3v3v3(efa->v4->co, efa->v1->co, efa->v2->co));
-#endif
- uvang[i] = angle_normalized_v2v2(auv[i], auv[(i + 1) % efa_len]);
- ang[i] = angle_normalized_v3v3(av[i], av[(i + 1) % efa_len]);
- }
-
- /* TODO: USE_EDBM_LOOPTRIS */
- glBegin(GL_POLYGON);
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- a = fabsf(uvang[i] - ang[i]) / (float)M_PI;
- weight_to_rgb(col, 1.0f - pow2f(1.0f - a));
- glColor3fv(col);
- glVertex2fv(luv->uv);
- }
- glEnd();
- }
- else {
- if (tf == activetf)
- activetf = NULL;
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- }
- }
-
- BLI_buffer_free(&uvang_buf);
- BLI_buffer_free(&ang_buf);
- BLI_buffer_free(&av_buf);
- BLI_buffer_free(&auv_buf);
-
- break;
}
}
-
- BLI_buffer_free(&tf_uv_buf);
- BLI_buffer_free(&tf_uvorig_buf);
-}
-
-static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset)
-{
- BMIter liter;
- BMLoop *l;
- MLoopUV *luv;
-
- glBegin(GL_LINE_LOOP);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ state |= UVEDIT_SYNC_SEL;
}
- glEnd();
+ return state;
}
-static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly)
-{
- MLoopUV *mloopuv;
- int i;
+/* ------------------------- */
- glBegin(GL_LINE_LOOP);
- mloopuv = &me->mloopuv[mpoly->loopstart];
- for (i = mpoly->totloop; i != 0; i--, mloopuv++) {
- glVertex2fv(mloopuv->uv);
- }
- glEnd();
-}
-
-static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage, const int other_uv_filter)
+void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
{
- Mesh *me = ob->data;
- MPoly *mpoly = me->mpoly;
- MTexPoly *mtpoly = me->mtpoly;
- int a;
-
- if (me->mloopuv == NULL) {
- return;
- }
+ float zoom[2], x_fac, y_fac;
- for (a = me->totpoly; a != 0; a--, mpoly++, mtpoly++) {
- if (other_uv_filter == SI_FILTER_ALL) {
- /* Nothing to compare, all UV faces are visible. */
- }
- else if (other_uv_filter == SI_FILTER_SAME_IMAGE) {
- if (mtpoly->tpage != curimage) {
- continue;
- }
- }
+ UI_view2d_scale_get_inverse(&ar->v2d, &zoom[0], &zoom[1]);
- draw_uvs_lineloop_mpoly(me, mpoly);
- }
-}
-static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, const int other_uv_filter)
-{
- Mesh *me = ob->data;
- MPoly *mpoly = me->mpoly;
- int a;
- BLI_bitmap *mat_test_array;
- bool ok = false;
- int totcol = 0;
-
- if (me->mloopuv == NULL) {
- return;
- }
+ mul_v2_fl(zoom, 256.0f * UI_DPI_FAC);
+ x_fac = zoom[0];
+ y_fac = zoom[1];
- if (curimage && ob->totcol == 0) {
- return;
- }
+ GPU_line_width(1.0f);
- totcol = max_ii(ob->totcol, 1);
- mat_test_array = BLI_BITMAP_NEW_ALLOCA(totcol);
+ GPU_matrix_translate_2fv(cursor);
- for (a = 0; a < totcol; a++) {
- Image *image;
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- /* if no materials, assume a default material with no image */
- if (ob->totcol)
- ED_object_get_active_image(ob, a + 1, &image, NULL, NULL, NULL);
- else
- image = NULL;
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- if (image == curimage) {
- BLI_BITMAP_ENABLE(mat_test_array, a);
- ok = true;
- }
- }
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
- if (ok == false) {
- return;
- }
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 8.0f);
- for (a = me->totpoly; a != 0; a--, mpoly++) {
- if (other_uv_filter == SI_FILTER_ALL) {
- /* Nothing to compare, all UV faces are visible. */
- }
- else if (other_uv_filter == SI_FILTER_SAME_IMAGE) {
- const int mat_nr = mpoly->mat_nr;
- if ((mat_nr >= totcol) ||
- (BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0)
- {
- continue;
- }
- }
+ immBegin(GPU_PRIM_LINES, 8);
- draw_uvs_lineloop_mpoly(me, mpoly);
- }
-}
-static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes,
- const int other_uv_filter)
-{
- if (new_shading_nodes) {
- draw_uvs_other_mesh_new_shading(ob, curimage, other_uv_filter);
- }
- else {
- draw_uvs_other_mesh_texface(ob, curimage, other_uv_filter);
- }
-}
+ immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
-static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes,
- const int other_uv_filter)
-{
- Base *base;
+ immVertex2f(shdr_pos, 0.0f, 0.05f * y_fac);
+ immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
- UI_ThemeColor(TH_UV_OTHERS);
+ immVertex2f(shdr_pos, 0.05f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
- for (base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
+ immVertex2f(shdr_pos, 0.0f, -0.05f * y_fac);
+ immVertex2f(shdr_pos, -0.05f * x_fac, 0.0f);
- if (!(base->flag & SELECT)) continue;
- if (!(base->lay & scene->lay)) continue;
- if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
+ immEnd();
- if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) {
- draw_uvs_other_mesh(ob, curimage, new_shading_nodes, other_uv_filter);
- }
- }
-}
+ immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 2.0f);
-static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
-{
- const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
- Image *curimage = ED_space_image(sima);
- Mesh *me = ob->data;
- Material *ma;
+ immBegin(GPU_PRIM_LINES, 8);
- if (sima->flag & SI_DRAW_OTHER) {
- draw_uvs_other(scene, ob, curimage, new_shading_nodes, sima->other_uv_filter);
- }
+ immVertex2f(shdr_pos, -0.020f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, -0.1f * x_fac, 0.0f);
- UI_ThemeColor(TH_UV_SHADOW);
+ immVertex2f(shdr_pos, 0.1f * x_fac, 0.0f);
+ immVertex2f(shdr_pos, 0.020f * x_fac, 0.0f);
- ma = give_current_material(ob, ob->actcol);
+ immVertex2f(shdr_pos, 0.0f, -0.020f * y_fac);
+ immVertex2f(shdr_pos, 0.0f, -0.1f * y_fac);
- if (me->mloopuv) {
- MPoly *mpoly = me->mpoly;
- MLoopUV *mloopuv, *mloopuv_base;
- int a, b;
- if (!(ma && ma->texpaintslot && ma->texpaintslot[ma->paint_active_slot].uvname &&
- (mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, ma->texpaintslot[ma->paint_active_slot].uvname))))
- {
- mloopuv = me->mloopuv;
- }
+ immVertex2f(shdr_pos, 0.0f, 0.1f * y_fac);
+ immVertex2f(shdr_pos, 0.0f, 0.020f * y_fac);
- mloopuv_base = mloopuv;
+ immEnd();
- for (a = me->totpoly; a > 0; a--, mpoly++) {
- if ((scene->toolsettings->uv_flag & UV_SHOW_SAME_IMAGE) && mpoly->mat_nr != ob->actcol - 1)
- continue;
- glBegin(GL_LINE_LOOP);
+ immUnbindProgram();
- mloopuv = mloopuv_base + mpoly->loopstart;
- for (b = 0; b < mpoly->totloop; b++, mloopuv++) {
- glVertex2fv(mloopuv->uv);
- }
- glEnd();
- }
- }
+ GPU_matrix_translate_2f(-cursor[0], -cursor[1]);
}
-#ifdef USE_EDBM_LOOPTRIS
-static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const int cd_loop_uv_offset)
+static void draw_uvs_shadow(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph)
{
- unsigned int i = *r_loop_index;
- BMFace *f = em->looptris[i][0]->f;
- do {
- unsigned int j;
- for (j = 0; j < 3; j++) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(em->looptris[i][j], cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- i++;
- } while (i != em->tottri && (f == em->looptris[i][0]->f));
- *r_loop_index = i - 1;
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit);
+ GPUBatch *faces, *edges, *verts, *facedots;
+ uchar state = UVEDIT_EDGES | UVEDIT_DATA;
+ float col[4];
+ UI_GetThemeColor4fv(TH_UV_SHADOW, col);
+
+ DRW_mesh_cache_uvedit(
+ eval_ob, sima, scene, state,
+ &faces, &edges, &verts, &facedots);
+
+ if (edges) {
+ GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(edges, "color", col);
+ GPU_batch_draw(edges);
+ }
}
-#endif
-/* draws uv's in the image space */
-static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
+static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
{
- const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
- ToolSettings *ts;
- Mesh *me = obedit->data;
- BMEditMesh *em = me->edit_btmesh;
- BMesh *bm = em->bm;
- BMFace *efa, *efa_act;
-#ifndef USE_EDBM_LOOPTRIS
- BMFace *activef;
-#endif
- BMLoop *l;
- BMIter iter, liter;
- MTexPoly *tf, *activetf = NULL;
- MLoopUV *luv;
- DerivedMesh *finaldm, *cagedm;
- unsigned char col1[4], col2[4];
- float pointsize;
- int drawfaces, interpedges;
- Image *ima = sima->image;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
-
- efa_act = EDBM_uv_active_face_get(em, false, false, &activetf); /* will be set to NULL if hidden */
-#ifndef USE_EDBM_LOOPTRIS
- activef = BM_mesh_active_face_get(bm, false, false);
-#endif
- ts = scene->toolsettings;
-
- drawfaces = draw_uvs_face_check(scene);
- if (ts->uv_flag & UV_SYNC_SELECTION)
- interpedges = (ts->selectmode & SCE_SELECT_VERTEX);
- else
- interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX);
-
- /* draw other uvs */
- if (sima->flag & SI_DRAW_OTHER) {
- Image *curimage;
-
- if (new_shading_nodes) {
- if (efa_act) {
- ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL, NULL);
- }
- else {
- curimage = ima;
- }
- }
- else {
- curimage = (activetf) ? activetf->tpage : ima;
- }
-
- draw_uvs_other(scene, obedit, curimage, new_shading_nodes, sima->other_uv_filter);
- }
-
- /* 1. draw shadow mesh */
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *me = eval_ob->data;
+ ToolSettings *ts = scene->toolsettings;
+ GPUBatch *geom = DRW_mesh_batch_cache_get_texpaint_loop_wire(me);
+ float col[4];
+ UI_GetThemeColor4fv(TH_UV_SHADOW, col);
- if (sima->flag & SI_DRAWSHADOW) {
- DM_update_materials(em->derivedFinal, obedit);
- /* first try existing derivedmesh */
- if (!draw_uvs_dm_shadow(em->derivedFinal)) {
- /* create one if it does not exist */
- cagedm = editbmesh_get_derived_cage_and_final(
- scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH | CD_MASK_MTFACE,
- &finaldm);
-
- /* when sync selection is enabled, all faces are drawn (except for hidden)
- * so if cage is the same as the final, theres no point in drawing this */
- if (!((ts->uv_flag & UV_SYNC_SELECTION) && (cagedm == finaldm)))
- draw_uvs_dm_shadow(finaldm);
-
- /* release derivedmesh again */
- if (cagedm != finaldm) cagedm->release(cagedm);
- finaldm->release(finaldm);
- }
- }
+ if (!geom)
+ return;
- /* 2. draw colored faces */
+ GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(geom, "color", col);
- if (sima->flag & SI_DRAW_STRETCH) {
- draw_uvs_stretch(sima, scene, em, activetf);
- }
- else if (!(sima->flag & SI_NO_DRAWFACES)) {
- /* draw transparent faces */
- UI_GetThemeColor4ubv(TH_FACE, col1);
- UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
-
-#ifdef USE_EDBM_LOOPTRIS
- {
- unsigned int i;
- for (i = 0; i < em->tottri; i++) {
- efa = em->looptris[i][0]->f;
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset);
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
-
- if (tf == activetf) {
- /* only once */
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- UI_ThemeColor4(TH_EDITMESH_ACTIVE);
- }
- else {
- glColor4ubv((GLubyte *)(is_select ? col2 : col1));
- }
-
- glBegin(GL_TRIANGLES);
- draw_uvs_looptri(em, &i, cd_loop_uv_offset);
- glEnd();
-
- if (tf == activetf) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
+ const bool do_material_masking = (ts->uv_flag & UV_SHOW_SAME_IMAGE);
+ if (do_material_masking && me->mloopuv) {
+ /* Render loops that have the active material. Minize draw calls. */
+ MPoly *mpoly = me->mpoly;
+ uint draw_start = 0;
+ uint idx = 0;
+ bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
+
+ GPU_matrix_bind(geom->interface);
+
+ /* TODO(fclem): If drawcall count becomes a problem in the future
+ * we can use multi draw indirect drawcalls for this.
+ * (not implemented in GPU module at the time of writing). */
+ for (int a = 0; a < me->totpoly; a++, mpoly++) {
+ bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
+ if (ma_match != prev_ma_match) {
+ if (ma_match == false) {
+ GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
}
else {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ draw_start = idx;
}
}
+ idx += mpoly->totloop + 1;
+ prev_ma_match = ma_match;
}
-#else
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- if (tf == activetf) continue; /* important the temp boolean is set above */
-
- if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset))
- glColor4ubv((GLubyte *)col2);
- else
- glColor4ubv((GLubyte *)col1);
-
- glBegin(GL_POLYGON);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
- }
- else {
- if (tf == activetf)
- activetf = NULL;
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- }
+ if (prev_ma_match == true) {
+ GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
}
-#endif
- glDisable(GL_BLEND);
+
+ GPU_batch_program_use_end(geom);
}
else {
- /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
- else {
- if (tf == activetf)
- activetf = NULL;
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- }
- }
-
+ GPU_batch_draw(geom);
}
+}
- /* 3. draw active face stippled */
-#ifndef USE_EDBM_LOOPTRIS
- if (activef) {
- tf = BM_ELEM_CD_GET_VOID_P(activef, cd_poly_tex_offset);
- if (uvedit_face_visible_test(scene, ima, activef, tf)) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- UI_ThemeColor4(TH_EDITMESH_ACTIVE);
-
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
-
- glBegin(GL_POLYGON);
- BM_ITER_ELEM (l, &liter, activef, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glDisable(GL_BLEND);
- }
- }
-#endif
+/* draws uv's in the image space */
+static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph)
+{
+ GPUBatch *faces, *edges, *verts, *facedots;
+ Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit);
+ ToolSettings *ts = scene->toolsettings;
+ float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- /* 4. draw edges */
+ if (sima->flag & SI_DRAWSHADOW) {
+ /* XXX TODO: Need to check if shadow mesh is different than original mesh. */
+ bool is_cage_like_final_meshes = true;
- if (sima->flag & SI_SMOOTH_UV) {
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ /* When sync selection is enabled, all faces are drawn (except for hidden)
+ * so if cage is the same as the final, there is no point in drawing this. */
+ if (!((ts->uv_flag & UV_SYNC_SELECTION) && is_cage_like_final_meshes)) {
+ draw_uvs_shadow(sima, scene, obedit, depsgraph);
+ }
}
- glLineWidth(1);
-
- switch (sima->dt_uv) {
- case SI_UVDT_DASH:
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ uchar state = get_state(sima, scene);
- if (tf) {
- cpack(0x111111);
+ DRW_mesh_cache_uvedit(
+ eval_ob, sima, scene, state,
+ &faces, &edges, &verts, &facedots);
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
-
- setlinestyle(2);
- cpack(0x909090);
+ bool interpedges;
+ bool do_elem_order_fix = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
+ bool do_selected_edges = ((sima->flag & SI_NO_DRAWEDGES) == 0);
+ bool draw_stretch = (state & (UVEDIT_STRETCH_AREA | UVEDIT_STRETCH_ANGLE)) != 0;
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ interpedges = (ts->selectmode & SCE_SELECT_VERTEX) != 0;
+ }
+ else {
+ interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX);
+ }
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
+ GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- setlinestyle(0);
- }
- }
- break;
- case SI_UVDT_BLACK: /* black/white */
- case SI_UVDT_WHITE:
- if (sima->dt_uv == SI_UVDT_WHITE) glColor3f(1.0f, 1.0f, 1.0f);
- else glColor3f(0.0f, 0.0f, 0.0f);
+ if (faces) {
+ GPU_batch_program_set_builtin(faces, (draw_stretch)
+ ? GPU_SHADER_2D_UV_FACES_STRETCH
+ : GPU_SHADER_2D_UV_FACES);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
+ if (!draw_stretch) {
+ GPU_blend(true);
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
- }
- break;
- case SI_UVDT_OUTLINE:
- glLineWidth(3);
- cpack(0x0);
+ UI_GetThemeColor4fv(TH_FACE, col1);
+ UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
+ UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
+ col3[3] *= 0.2; /* Simulate dithering */
+ GPU_batch_uniform_4fv(faces, "faceColor", col1);
+ GPU_batch_uniform_4fv(faces, "selectColor", col2);
+ GPU_batch_uniform_4fv(faces, "activeColor", col3);
+ }
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
+ GPU_batch_draw(faces);
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
+ if (!draw_stretch) {
+ GPU_blend(false);
+ }
+ }
+ if (edges) {
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ }
+ switch (sima->dt_uv) {
+ case SI_UVDT_DASH:
+ {
+ float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}};
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+
+ GPU_line_width(1.0f);
+ GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors);
+ GPU_batch_uniform_2f(edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);
+ GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */
+ GPU_batch_uniform_1f(edges, "dash_width", 4.0f);
+ GPU_batch_draw(edges);
+ break;
}
-
- glLineWidth(1);
- UI_GetThemeColor4ubv(TH_WIRE_EDIT, col2);
- glColor4ubv((unsigned char *)col2);
-
- if (me->drawflag & ME_DRAWEDGES) {
- int sel, lastsel = -1;
- UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1);
-
- if (interpedges) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- glBegin(GL_LINE_LOOP);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
- glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2);
-
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
- }
+ case SI_UVDT_BLACK:
+ case SI_UVDT_WHITE:
+ {
+ GPU_line_width(1.0f);
+ GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
+ if (sima->dt_uv == SI_UVDT_WHITE) {
+ GPU_batch_uniform_4f(edges, "color", 1.0f, 1.0f, 1.0f, 1.0f);
}
else {
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- glBegin(GL_LINES);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset);
- if (sel != lastsel) {
- glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2);
- lastsel = sel;
- }
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
- }
+ GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
}
+ GPU_batch_draw(edges);
+ break;
}
- else {
- /* no nice edges */
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
+ case SI_UVDT_OUTLINE:
+ {
+ GPU_line_width(3.0f);
+ GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_draw(edges);
+
+ UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
+ UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
+
+ /* We could modify the vbo's data filling instead of modifying the provoking vert. */
+ glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
+
+ GPU_line_width(1.0f);
+ GPU_batch_program_set_builtin(edges, (interpedges)
+ ? GPU_SHADER_2D_UV_EDGES_SMOOTH
+ : GPU_SHADER_2D_UV_EDGES);
+ GPU_batch_uniform_4fv(edges, "edgeColor", col1);
+ GPU_batch_uniform_4fv(edges, "selectColor", do_selected_edges ? col2 : col1);
+ GPU_batch_draw(edges);
+
+ if (do_elem_order_fix && do_selected_edges) {
+ /* We have problem in this mode when face order make some edges
+ * appear unselected because an adjacent face is not selected and
+ * render after the selected face.
+ * So, to avoid sorting edges by state we just render selected edges
+ * on top. A bit overkill but it's simple. */
+ GPU_blend(true);
+ GPU_batch_uniform_4fv(edges, "edgeColor", transparent);
+ GPU_batch_uniform_4fv(edges, "selectColor", col2);
+ GPU_batch_draw(edges);
+ GPU_blend(false);
}
- }
-
- break;
- }
-
- if (sima->flag & SI_SMOOTH_UV) {
- glDisable(GL_LINE_SMOOTH);
- glDisable(GL_BLEND);
- }
-
- /* 5. draw face centers */
-
- if (drawfaces) {
- float cent[2];
-
- pointsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
- glPointSize(pointsize);
-
- glBegin(GL_POINTS);
-
- /* unselected faces */
- UI_ThemeColor(TH_WIRE);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- glVertex2fv(cent);
+ glProvokingVertex(GL_LAST_VERTEX_CONVENTION);
+ break;
}
}
-
- /* selected faces */
- UI_ThemeColor(TH_FACE_DOT);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- glVertex2fv(cent);
- }
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(false);
+ GPU_blend(false);
}
-
- glEnd();
}
-
- /* 6. draw uv vertices */
-
- if (drawfaces != 2) { /* 2 means Mesh Face Mode */
- /* unselected uvs */
- UI_ThemeColor(TH_VERTEX);
- pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
- glPointSize(pointsize);
-
- glBegin(GL_POINTS);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
- glVertex2fv(luv->uv);
+ if (verts || facedots) {
+ float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
+ if (verts) {
+ float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */
+ UI_GetThemeColor4fv(TH_VERTEX, col1);
+ GPU_blend(true);
+ GPU_enable_program_point_size();
+
+ GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS);
+ GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f);
+ GPU_batch_uniform_4fv(verts, "selectColor", (do_elem_order_fix) ? transparent : col2);
+ GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
+ GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2);
+ GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
+ GPU_batch_draw(verts);
+
+ if (do_elem_order_fix) {
+ /* We have problem in this mode when face order make some verts
+ * appear unselected because an adjacent face is not selected and
+ * render after the selected face.
+ * So, to avoid sorting verts by state we just render selected verts
+ * on top. A bit overkill but it's simple. */
+ GPU_batch_uniform_4fv(verts, "vertColor", transparent);
+ GPU_batch_uniform_4fv(verts, "selectColor", col2);
+ GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col);
+ GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2);
+ GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f);
+ GPU_batch_draw(verts);
}
- }
- glEnd();
-
- /* pinned uvs */
- /* give odd pointsizes odd pin pointsizes */
- glPointSize(pointsize * 2 + (((int)pointsize % 2) ? (-1) : 0));
- cpack(0xFF);
-
- glBegin(GL_POINTS);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_PINNED)
- glVertex2fv(luv->uv);
- }
+ GPU_blend(false);
+ GPU_disable_program_point_size();
}
- glEnd();
-
- /* selected uvs */
- UI_ThemeColor(TH_VERTEX_SELECT);
- glPointSize(pointsize);
-
- glBegin(GL_POINTS);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
- glVertex2fv(luv->uv);
- }
+ if (facedots) {
+ GPU_point_size(pointsize);
+
+ UI_GetThemeColor4fv(TH_WIRE, col1);
+ GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS);
+ GPU_batch_uniform_4fv(facedots, "vertColor", col1);
+ GPU_batch_uniform_4fv(facedots, "selectColor", col2);
+ GPU_batch_draw(facedots);
}
- glEnd();
}
}
-
-static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bool *show_shadow, bool *show_texpaint)
+static void draw_uv_shadows_get(
+ SpaceImage *sima, Object *ob, Object *obedit,
+ bool *show_shadow, bool *show_texpaint)
{
*show_shadow = *show_texpaint = false;
@@ -973,7 +465,9 @@ static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bo
*show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT);
}
-void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact)
+void ED_uvedit_draw_main(
+ SpaceImage *sima,
+ ARegion *ar, Scene *scene, ViewLayer *view_layer, Object *obedit, Object *obact, Depsgraph *depsgraph)
{
ToolSettings *toolsettings = scene->toolsettings;
bool show_uvedit, show_uvshadow, show_texpaint_uvshadow;
@@ -982,12 +476,21 @@ void ED_uvedit_draw_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *ob
draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow);
if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
- if (show_uvshadow)
- draw_uvs_shadow(obedit);
- else if (show_uvedit)
- draw_uvs(sima, scene, obedit);
- else
- draw_uvs_texpaint(sima, scene, obact);
+ if (show_uvshadow) {
+ draw_uvs_shadow(sima, scene, obedit, depsgraph);
+ }
+ else if (show_uvedit) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob_iter = objects[ob_index];
+ draw_uvs(sima, scene, ob_iter, depsgraph);
+ }
+ MEM_freeN(objects);
+ }
+ else {
+ draw_uvs_texpaint(scene, obact, depsgraph);
+ }
if (show_uvedit && !(toolsettings->use_uv_sculpt))
ED_image_draw_cursor(ar, sima->cursor);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index a9162d26d72..eed9d68f39c 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -32,7 +32,6 @@
#ifndef __UVEDIT_INTERN_H__
#define __UVEDIT_INTERN_H__
-struct MTexPoly;
struct Image;
struct Object;
struct Scene;
@@ -52,9 +51,10 @@ void uv_poly_center(struct BMFace *f, float r_cent[2], const int cd_loop_uv_off
/* find nearest */
typedef struct UvNearestHit {
+ /** Only for `*_multi(..)` versions of functions. */
+ struct Object *ob;
/** Always set if we have a hit. */
struct BMFace *efa;
- struct MTexPoly *tf;
struct BMLoop *l;
struct MLoopUV *luv, *luv_next;
/** Index of loop within face. */
@@ -66,15 +66,24 @@ typedef struct UvNearestHit {
#define UV_NEAREST_HIT_INIT { .dist_sq = FLT_MAX, }
bool uv_find_nearest_vert(
- struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+ struct Scene *scene, struct Image *ima, struct Object *obedit,
+ const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
+bool uv_find_nearest_vert_multi(
+ struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
const float co[2], const float penalty_dist, struct UvNearestHit *hit_final);
bool uv_find_nearest_edge(
- struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+ struct Scene *scene, struct Image *ima, struct Object *obedit,
+ const float co[2], struct UvNearestHit *hit_final);
+bool uv_find_nearest_edge_multi(
+ struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
const float co[2], struct UvNearestHit *hit_final);
bool uv_find_nearest_face(
- struct Scene *scene, struct Image *ima, struct BMEditMesh *em,
+ struct Scene *scene, struct Image *ima, struct Object *obedit,
+ const float co[2], struct UvNearestHit *hit_final);
+bool uv_find_nearest_face_multi(
+ struct Scene *scene, struct Image *ima, struct Object **objects, const uint objects_len,
const float co[2], struct UvNearestHit *hit_final);
/* utility tool functions */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index c0378f967ad..d02bd95c047 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -29,6 +29,7 @@
* \ingroup eduv
*/
+
#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -51,21 +52,25 @@
#include "BLI_lasso_2d.h"
#include "BLI_blenlib.h"
#include "BLI_array.h"
+#include "BLI_kdtree.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
+#include "BKE_editmesh.h"
#include "BKE_image.h"
-#include "BKE_library.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_editmesh.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -73,10 +78,12 @@
#include "ED_uvedit.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -87,9 +94,13 @@
#include "uvedit_intern.h"
-static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int action);
+static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit);
+static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len);
+static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
+static void uv_select_all_perform_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit);
/* -------------------------------------------------------------------- */
/** \name State Testing
@@ -189,144 +200,6 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
//#define USE_SWITCH_ASPECT
-void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, Image *ima, Image *previma)
-{
- BMEditMesh *em;
- BMIter iter;
- MTexPoly *tf;
- bool update = false;
- const bool selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
-
- /* skip assigning these procedural images... */
- if (ima && (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE))
- return;
-
- /* verify we have a mesh we can work with */
- if (!obedit || (obedit->type != OB_MESH))
- return;
-
- em = BKE_editmesh_from_object(obedit);
- if (!em || !em->bm->totface) {
- return;
- }
-
- if (BKE_scene_use_new_shading_nodes(scene)) {
- /* new shading system, do not assign anything */
- }
- else {
- BMFace *efa;
-
- int cd_loop_uv_offset;
- int cd_poly_tex_offset;
-
- /* old shading system, assign image to selected faces */
-#ifdef USE_SWITCH_ASPECT
- float prev_aspect[2], fprev_aspect;
- float aspect[2], faspect;
-
- ED_image_get_uv_aspect(previma, prev_aspect, prev_aspect + 1);
- ED_image_get_uv_aspect(ima, aspect, aspect + 1);
-
- fprev_aspect = prev_aspect[0] / prev_aspect[1];
- faspect = aspect[0] / aspect[1];
-#endif
-
- /* ensure we have a uv map */
- if (!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) {
- BM_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY);
- BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV);
- /* make UVs all nice 0-1 */
- ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer(&em->bm->pdata, CD_MTEXPOLY));
- update = true;
- }
-
- cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
-
- /* now assign to all visible faces */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (uvedit_face_visible_test(scene, previma, efa, tf) &&
- (selected == true || uvedit_face_select_test(scene, efa, cd_loop_uv_offset)))
- {
- if (ima) {
- tf->tpage = ima;
-
- if (ima->id.us == 0) id_us_plus(&ima->id);
- else id_lib_extern(&ima->id);
-
-#ifdef USE_SWITCH_ASPECT
- /* we also need to correct the aspect of uvs */
- if (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) {
- /* do nothing */
- }
- else {
- BMIter liter;
- BMLoop *l;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- luv->uv[0] *= fprev_aspect;
- luv->uv[0] /= faspect;
- }
- }
-#endif
- }
- else {
- tf->tpage = NULL;
- }
-
- update = true;
- }
- }
-
- /* and update depdency graph */
- if (update) {
- DAG_id_tag_update(obedit->data, 0);
- }
- }
-
-}
-
-/* dotile - 1, set the tile flag (from the space image)
- * 2, set the tile index for the faces. */
-static bool uvedit_set_tile(Object *obedit, Image *ima, int curtile)
-{
- BMEditMesh *em;
- BMFace *efa;
- BMIter iter;
- MTexPoly *tf;
- int cd_poly_tex_offset;
-
- /* verify if we have something to do */
- if (!ima || !ED_uvedit_test(obedit))
- return false;
-
- if ((ima->tpageflag & IMA_TILES) == 0)
- return false;
-
- /* skip assigning these procedural images... */
- if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE)
- return false;
-
- em = BKE_editmesh_from_object(obedit);
-
- cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT))
- tf->tile = curtile; /* set tile index */
- }
-
- DAG_id_tag_update(obedit->data, 0);
-
- return true;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -380,14 +253,18 @@ bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
}
-bool uvedit_face_visible_test(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf)
+bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *efa)
{
ToolSettings *ts = scene->toolsettings;
- if (ts->uv_flag & UV_SHOW_SAME_IMAGE)
- return (tf->tpage == ima) ? uvedit_face_visible_nolocal(scene, efa) : false;
- else
+ if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
+ Image *face_image;
+ ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
+ return (face_image == ima) ? uvedit_face_visible_nolocal(scene, efa) : false;
+ }
+ else {
return uvedit_face_visible_nolocal(scene, efa);
+ }
}
bool uvedit_face_select_test(
@@ -695,38 +572,45 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as
}
}
-bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
+bool ED_uvedit_minmax_multi(
+ Scene *scene, Image *ima, Object **objects_edit, uint objects_len,
+ float r_min[2], float r_max[2])
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MTexPoly *tf;
- MLoopUV *luv;
bool changed = false;
+ INIT_MINMAX2(r_min, r_max);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects_edit[ob_index];
- INIT_MINMAX2(r_min, r_max);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- continue;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- minmax_v2v2_v2(r_min, r_max, luv->uv);
- changed = true;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ minmax_v2v2_v2(r_min, r_max, luv->uv);
+ changed = true;
+ }
}
}
}
-
return changed;
}
+bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
+{
+ return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
+}
+
/* Be careful when using this, it bypasses all synchronization options */
void ED_uvedit_select_all(BMesh *bm)
{
@@ -745,30 +629,32 @@ void ED_uvedit_select_all(BMesh *bm)
}
}
-static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[2])
+static bool ED_uvedit_median_multi(Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MTexPoly *tf;
- MLoopUV *luv;
unsigned int sel = 0;
+ zero_v2(co);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects_edit[ob_index];
- zero_v2(co);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- continue;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- add_v2_v2(co, luv->uv);
- sel++;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ add_v2_v2(co, luv->uv);
+ sel++;
+ }
}
}
}
@@ -778,19 +664,24 @@ static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[
return (sel != 0);
}
-static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
+static bool UNUSED_FUNCTION(ED_uvedit_median)(Scene *scene, Image *ima, Object *obedit, float co[2])
+{
+ return ED_uvedit_median_multi(scene, ima, &obedit, 1, co);
+}
+
+bool ED_uvedit_center_multi(Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float cent[2], char mode)
{
bool changed = false;
if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
float min[2], max[2];
- if (ED_uvedit_minmax(scene, ima, obedit, min, max)) {
+ if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) {
mid_v2_v2v2(cent, min, max);
changed = true;
}
}
else {
- if (ED_uvedit_median(scene, ima, obedit, cent)) {
+ if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) {
changed = true;
}
}
@@ -798,6 +689,11 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2
return changed;
}
+bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
+{
+ return ED_uvedit_center_multi(scene, ima, &obedit, 1, cent, mode);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -805,10 +701,10 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2
* \{ */
bool uv_find_nearest_edge(
- Scene *scene, Image *ima, BMEditMesh *em, const float co[2],
+ Scene *scene, Image *ima, Object *obedit, const float co[2],
UvNearestHit *hit)
{
- MTexPoly *tf;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -817,13 +713,11 @@ bool uv_find_nearest_edge(
bool found = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -833,7 +727,6 @@ bool uv_find_nearest_edge(
const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
if (dist_test_sq < hit->dist_sq) {
- hit->tf = tf;
hit->efa = efa;
hit->l = l;
@@ -849,19 +742,34 @@ bool uv_find_nearest_edge(
return found;
}
+bool uv_find_nearest_edge_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len,
+ const float co[2], UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
bool uv_find_nearest_face(
- Scene *scene, Image *ima, BMEditMesh *em, const float co[2],
+ Scene *scene, Image *ima, Object *obedit, const float co[2],
UvNearestHit *hit_final)
{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool found = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
/* this will fill in hit.vert1 and hit.vert2 */
float dist_sq_init = hit_final->dist_sq;
UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+ if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
hit.dist_sq = dist_sq_init;
hit.l = NULL;
hit.luv = hit.luv_next = NULL;
@@ -870,8 +778,7 @@ bool uv_find_nearest_face(
BMFace *efa;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
@@ -893,6 +800,21 @@ bool uv_find_nearest_face(
return found;
}
+bool uv_find_nearest_face_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len,
+ const float co[2], UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
static bool uv_nearest_between(
const BMLoop *l, const float co[2],
const int cd_loop_uv_offset)
@@ -906,7 +828,7 @@ static bool uv_nearest_between(
}
bool uv_find_nearest_vert(
- Scene *scene, Image *ima, BMEditMesh *em,
+ Scene *scene, Image *ima, Object *obedit,
float const co[2], const float penalty_dist, UvNearestHit *hit_final)
{
bool found = false;
@@ -914,23 +836,22 @@ bool uv_find_nearest_vert(
/* this will fill in hit.vert1 and hit.vert2 */
float dist_sq_init = hit_final->dist_sq;
UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+ if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
hit.dist_sq = dist_sq_init;
hit.l = NULL;
hit.luv = hit.luv_next = NULL;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter;
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
@@ -975,41 +896,68 @@ bool uv_find_nearest_vert(
return found;
}
-bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2])
+bool uv_find_nearest_vert_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len,
+ float const co[2], const float penalty_dist, UvNearestHit *hit_final)
{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MTexPoly *tf;
- MLoopUV *luv;
- float mindist, dist;
bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
-
- mindist = 1e10f;
- copy_v2_v2(r_uv, co);
-
+bool ED_uvedit_nearest_uv(
+ Scene *scene, Object *obedit, Image *ima, const float co[2],
+ float *dist_sq, float r_uv[2])
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter;
+ BMFace *efa;
+ const float *uv_best = NULL;
+ float dist_best = *dist_sq;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
+ }
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
+ const float dist_test = len_squared_v2v2(co, uv);
+ if (dist_best > dist_test) {
+ dist_best = dist_test;
+ uv_best = uv;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- dist = len_manhattan_v2v2(co, luv->uv);
-
- if (dist <= mindist) {
- mindist = dist;
+ if (uv_best != NULL) {
+ copy_v2_v2(r_uv, uv_best);
+ *dist_sq = dist_best;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
- copy_v2_v2(r_uv, luv->uv);
- found = true;
- }
+bool ED_uvedit_nearest_uv_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, const float co[2],
+ float *dist_sq, float r_uv[2])
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
+ found = true;
}
}
-
return found;
}
@@ -1103,13 +1051,13 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1,
}
static int uv_select_edgeloop(
- Scene *scene, Image *ima, BMEditMesh *em, UvNearestHit *hit,
+ Scene *scene, Image *ima, Object *obedit, UvNearestHit *hit,
const float limit[2], const bool extend)
{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter, liter;
BMLoop *l;
- MTexPoly *tf;
UvVertMap *vmap;
UvMapVert *iterv_curr;
UvMapVert *iterv_next;
@@ -1117,7 +1065,6 @@ static int uv_select_edgeloop(
bool looking, select;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
/* setup */
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
@@ -1126,7 +1073,7 @@ static int uv_select_edgeloop(
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
if (!extend) {
- uv_select_all_perform(scene, ima, em, SEL_DESELECT);
+ uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
}
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
@@ -1150,9 +1097,7 @@ static int uv_select_edgeloop(
/* find correct valence edges which are not tagged yet, but connect to tagged one */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, obedit, ima, efa)) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
/* check face not hidden and not tagged */
if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l)))
@@ -1211,190 +1156,194 @@ static int uv_select_edgeloop(
/** \name Select Linked
* \{ */
-static void uv_select_linked(
- Scene *scene, Image *ima, BMEditMesh *em, const float limit[2], UvNearestHit *hit_final,
- bool extend, bool deselect, bool toggle, bool select_faces)
+static void uv_select_linked_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, const float limit[2],
+ UvNearestHit *hit_final, bool extend, bool deselect, bool toggle, bool select_faces)
{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvVertMap *vmap;
- UvMapVert *vlist, *iterv, *startv;
- int i, stacksize = 0, *stack;
- unsigned int a;
- char *flag;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ /* loop over objects, or just use hit_final->ob */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (hit_final && ob_index != 0) {
+ break;
+ }
+ Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
- BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvVertMap *vmap;
+ UvMapVert *vlist, *iterv, *startv;
+ int i, stacksize = 0, *stack;
+ unsigned int a;
+ char *flag;
- /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
- * this made *every* projection split the island into front/back islands.
- * Keep 'use_winding' to false, see: T50970.
- *
- * Better solve this by having a delimit option for select-linked operator,
- * keeping island-select working as is. */
- vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (vmap == NULL)
- return;
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
- stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
- flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
+ /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
+ * this made *every* projection split the island into front/back islands.
+ * Keep 'use_winding' to false, see: T50970.
+ *
+ * Better solve this by having a delimit option for select-linked operator,
+ * keeping island-select working as is. */
+ vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
- if (hit_final == NULL) {
- /* Use existing selection */
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ if (vmap == NULL)
+ return;
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
+ flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
- if (luv->flag & MLOOPUV_VERTSEL) {
+ if (hit_final == NULL) {
+ /* Use existing selection */
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
stack[stacksize] = a;
stacksize++;
flag[a] = 1;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- break;
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+
+ break;
+ }
}
}
}
}
}
- }
- else {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (efa == hit_final->efa) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- break;
+ else {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (efa == hit_final->efa) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ break;
+ }
}
}
- }
- while (stacksize > 0) {
+ while (stacksize > 0) {
- stacksize--;
- a = stack[stacksize];
+ stacksize--;
+ a = stack[stacksize];
- efa = BM_face_at_index(em->bm, a);
+ efa = BM_face_at_index(em->bm, a);
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- /* make_uv_vert_map_EM sets verts tmp.l to the indices */
- vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+ /* make_uv_vert_map_EM sets verts tmp.l to the indices */
+ vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
- startv = vlist;
+ startv = vlist;
- for (iterv = vlist; iterv; iterv = iterv->next) {
- if (iterv->separate)
- startv = iterv;
- if (iterv->poly_index == a)
- break;
- }
+ for (iterv = vlist; iterv; iterv = iterv->next) {
+ if (iterv->separate)
+ startv = iterv;
+ if (iterv->poly_index == a)
+ break;
+ }
+
+ for (iterv = startv; iterv; iterv = iterv->next) {
+ if ((startv != iterv) && (iterv->separate))
+ break;
+ else if (!flag[iterv->poly_index]) {
+ flag[iterv->poly_index] = 1;
+ stack[stacksize] = iterv->poly_index;
+ stacksize++;
+ }
- for (iterv = startv; iterv; iterv = iterv->next) {
- if ((startv != iterv) && (iterv->separate))
- break;
- else if (!flag[iterv->poly_index]) {
- flag[iterv->poly_index] = 1;
- stack[stacksize] = iterv->poly_index;
- stacksize++;
}
}
}
- }
- /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
- if ((toggle == true) && (extend == false) && (deselect == false)) {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- bool found_selected = false;
- if (!flag[a]) {
- continue;
- }
-
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- found_selected = true;
+ /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
+ if ((toggle == true) && (extend == false) && (deselect == false)) {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ bool found_selected = false;
+ if (!flag[a]) {
+ continue;
}
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
found_selected = true;
}
}
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (found_selected) {
- deselect = true;
- break;
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ found_selected = true;
+ }
+ }
+
+ if (found_selected) {
+ deselect = true;
+ break;
+ }
}
}
}
- }
#define SET_SELECTION(value) \
- if (select_faces) { \
- BM_face_select_set(em->bm, efa, value); \
- } \
- else { \
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
- luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
+ if (select_faces) { \
+ BM_face_select_set(em->bm, efa, value); \
} \
- } (void)0
+ else { \
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
+ luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
+ } \
+ } (void)0
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (!flag[a]) {
- if (!extend && !deselect && !toggle) {
- SET_SELECTION(false);
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (!flag[a]) {
+ if (!extend && !deselect && !toggle) {
+ SET_SELECTION(false);
+ }
+ continue;
}
- continue;
- }
- if (!deselect) {
- SET_SELECTION(true);
- }
- else {
- SET_SELECTION(false);
+ if (!deselect) {
+ SET_SELECTION(true);
+ }
+ else {
+ SET_SELECTION(false);
+ }
}
- }
#undef SET_SELECTION
- MEM_freeN(stack);
- MEM_freeN(flag);
- BM_uv_vert_map_free(vmap);
+ MEM_freeN(stack);
+ MEM_freeN(flag);
+ BM_uv_vert_map_free(vmap);
+ }
}
/* WATCH IT: this returns first selected UV,
* not ideal in many cases since there could be multiple */
-static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVert *eve)
+static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve)
{
BMIter liter;
BMLoop *l;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset);
-
- if (!uvedit_face_visible_test(scene, ima, l->f, tf))
+ if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
continue;
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
@@ -1415,103 +1364,110 @@ static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVer
static int uv_select_more_less(bContext *C, const bool select)
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
SpaceImage *sima = CTX_wm_space_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
ToolSettings *ts = scene->toolsettings;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (select) {
- EDBM_select_more(em, true);
- }
- else {
- EDBM_select_less(em, true);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- return OPERATOR_FINISHED;
- }
+ bool changed = false;
- if (ts->uv_selectmode == UV_SELECT_FACE) {
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* clear tags */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (select) {
+ EDBM_select_more(em, true);
+ }
+ else {
+ EDBM_select_less(em, true);
+ }
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ continue;
+ }
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (ts->uv_selectmode == UV_SELECT_FACE) {
+
+ /* clear tags */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
#define IS_SEL 1
#define IS_UNSEL 2
- int sel_state = 0;
+ int sel_state = 0;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- sel_state |= IS_SEL;
- }
- else {
- sel_state |= IS_UNSEL;
- }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ sel_state |= IS_SEL;
+ }
+ else {
+ sel_state |= IS_UNSEL;
+ }
- /* if we have a mixed selection, tag to grow it */
- if (sel_state == (IS_SEL | IS_UNSEL)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- break;
+ /* if we have a mixed selection, tag to grow it */
+ if (sel_state == (IS_SEL | IS_UNSEL)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ break;
+ }
}
- }
#undef IS_SEL
#undef IS_UNSEL
+ }
}
}
+ else {
- /* select tagged faces */
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- else {
-
- /* clear tags */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_disable(l, BM_ELEM_TAG);
+ /* clear tags */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l, BM_ELEM_TAG);
+ }
}
- }
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
- BM_elem_flag_enable(l->next, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
+ if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
+ BM_elem_flag_enable(l->next, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
+ changed = true;
+ }
}
}
}
}
- /* select tagged loops */
- uv_select_flush_from_tag_loop(sima, scene, obedit, select);
+ if (changed) {
+ /* Select tagged loops. */
+ uv_select_flush_from_tag_loop(sima, scene, obedit, select);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
}
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1558,232 +1514,261 @@ static void UV_OT_select_less(wmOperatorType *ot)
/** \name Weld Align Operator
* \{ */
-static void uv_weld_align(bContext *C, int tool)
+typedef enum eUVWeldAlign {
+ UV_STRAIGHTEN,
+ UV_STRAIGHTEN_X,
+ UV_STRAIGHTEN_Y,
+ UV_ALIGN_AUTO,
+ UV_ALIGN_X,
+ UV_ALIGN_Y,
+ UV_WELD,
+} eUVWeldAlign;
+
+static void uv_weld_align(bContext *C, eUVWeldAlign tool)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- SpaceImage *sima;
- Scene *scene;
- Image *ima;
- MTexPoly *tf;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
float cent[2], min[2], max[2];
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
-
- scene = CTX_data_scene(C);
- ima = CTX_data_edit_image(C);
- sima = CTX_wm_space_image(C);
-
INIT_MINMAX2(min, max);
- if (tool == 'a') {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ if (tool == UV_ALIGN_AUTO) {
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ if (synced_selection && (em->bm->totvertsel == 0)) {
continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- minmax_v2v2_v2(min, max, luv->uv);
- }
}
- }
- tool = (max[0] - min[0] >= max[1] - min[1]) ? 'y' : 'x';
- }
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- uvedit_center(scene, ima, obedit, cent, 0);
-
- if (tool == 'x' || tool == 'w') {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = cent[0];
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ minmax_v2v2_v2(min, max, luv->uv);
+ }
}
-
}
}
+ tool = (max[0] - min[0] >= max[1] - min[1]) ? 'y' : 'x';
}
- if (tool == 'y' || tool == 'w') {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- continue;
+ ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[1] = cent[1];
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool changed = false;
- }
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
}
- }
- if (tool == 's' || tool == 't' || tool == 'u') {
- BMEdge *eed;
- BMLoop *l;
- BMVert *eve;
- BMVert *eve_start;
- BMIter iter, liter, eiter;
-
- /* clear tag */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* tag verts with a selected UV */
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset);
+ if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
- if (!uvedit_face_visible_test(scene, ima, l->f, tf))
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- BM_elem_flag_enable(eve, BM_ELEM_TAG);
- break;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[0] = cent[0];
+ changed = true;
+ }
+
}
}
}
- /* flush vertex tags to edges */
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(
- eed, BM_ELEM_TAG,
- (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
- BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
- }
+ if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
- /* find a vertex with only one tagged edge */
- eve_start = NULL;
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- int tot_eed_tag = 0;
- BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
- tot_eed_tag++;
- }
- }
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
- if (tot_eed_tag == 1) {
- eve_start = eve;
- break;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->uv[1] = cent[1];
+ changed = true;
+ }
+
+ }
}
}
- if (eve_start) {
- BMVert **eve_line = NULL;
- BMVert *eve_next = NULL;
- BLI_array_declare(eve_line);
- int i;
+ if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) {
+ BMEdge *eed;
+ BMLoop *l;
+ BMVert *eve;
+ BMVert *eve_start;
+ BMIter iter, liter, eiter;
- eve = eve_start;
+ /* clear tag */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
- /* walk over edges, building an array of verts in a line */
- while (eve) {
- BLI_array_append(eve_line, eve);
- /* don't touch again */
- BM_elem_flag_disable(eve, BM_ELEM_TAG);
+ /* tag verts with a selected UV */
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
+ continue;
- eve_next = NULL;
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ BM_elem_flag_enable(eve, BM_ELEM_TAG);
+ break;
+ }
+ }
+ }
+
+ /* flush vertex tags to edges */
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(
+ eed, BM_ELEM_TAG,
+ (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
+ BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
+ }
- /* find next eve */
+ /* find a vertex with only one tagged edge */
+ eve_start = NULL;
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ int tot_eed_tag = 0;
BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
- BMVert *eve_other = BM_edge_other_vert(eed, eve);
- if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
- /* this is a tagged vert we didnt walk over yet, step onto it */
- eve_next = eve_other;
- break;
- }
+ tot_eed_tag++;
}
}
- eve = eve_next;
+ if (tot_eed_tag == 1) {
+ eve_start = eve;
+ break;
+ }
}
- /* now we have all verts, make into a line */
- if (BLI_array_len(eve_line) > 2) {
-
- /* we know the returns from these must be valid */
- const float *uv_start = uv_sel_co_from_eve(scene, ima, em, eve_line[0]);
- const float *uv_end = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
- /* For t & u modes */
- float a = 0.0f;
+ if (eve_start) {
+ BMVert **eve_line = NULL;
+ BMVert *eve_next = NULL;
+ BLI_array_declare(eve_line);
+ int i;
+
+ eve = eve_start;
+
+ /* walk over edges, building an array of verts in a line */
+ while (eve) {
+ BLI_array_append(eve_line, eve);
+ /* don't touch again */
+ BM_elem_flag_disable(eve, BM_ELEM_TAG);
+
+ eve_next = NULL;
+
+ /* find next eve */
+ BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
+ BMVert *eve_other = BM_edge_other_vert(eed, eve);
+ if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
+ /* this is a tagged vert we didn't walk over yet, step onto it */
+ eve_next = eve_other;
+ break;
+ }
+ }
+ }
- if (tool == 't') {
- if (uv_start[1] == uv_end[1])
- tool = 's';
- else
- a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
+ eve = eve_next;
}
- else if (tool == 'u') {
- if (uv_start[0] == uv_end[0])
- tool = 's';
- else
- a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
- }
-
- /* go over all verts except for endpoints */
- for (i = 0; i < BLI_array_len(eve_line); i++) {
- BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
- tf = BM_ELEM_CD_GET_VOID_P(l->f, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, l->f, tf))
- continue;
+ /* now we have all verts, make into a line */
+ if (BLI_array_len(eve_line) > 2) {
+
+ /* we know the returns from these must be valid */
+ const float *uv_start = uv_sel_co_from_eve(
+ scene, obedit, ima, em, eve_line[0]);
+ const float *uv_end = uv_sel_co_from_eve(
+ scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
+ /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
+ float a = 0.0f;
+ eUVWeldAlign tool_local = tool;
+
+ if (tool_local == UV_STRAIGHTEN_X) {
+ if (uv_start[1] == uv_end[1])
+ tool_local = UV_STRAIGHTEN;
+ else
+ a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
+ }
+ else if (tool_local == UV_STRAIGHTEN_Y) {
+ if (uv_start[0] == uv_end[0])
+ tool_local = UV_STRAIGHTEN;
+ else
+ a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
+ }
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
- * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
- * Maybe this should be a BLI func? Or is it already existing?
- * Could use interp_v2_v2v2, but not sure it's worth it here...*/
- if (tool == 't')
- luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
- else if (tool == 'u')
- luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
- else
- closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
+ /* go over all verts except for endpoints */
+ for (i = 0; i < BLI_array_len(eve_line); i++) {
+ BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
+ continue;
+
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
+ * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
+ * Maybe this should be a BLI func? Or is it already existing?
+ * Could use interp_v2_v2v2, but not sure it's worth it here...*/
+ if (tool_local == UV_STRAIGHTEN_X)
+ luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
+ else if (tool_local == UV_STRAIGHTEN_Y)
+ luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
+ else
+ closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
+ changed = true;
+ }
}
}
}
+ else {
+ /* error - not a line, needs 3+ points */
+ }
+
+ if (eve_line) {
+ MEM_freeN(eve_line);
+ }
}
else {
- /* error - not a line, needs 3+ points */
- }
-
- if (eve_line) {
- MEM_freeN(eve_line);
+ /* error - cant find an endpoint */
}
}
- else {
- /* error - cant find an endpoint */
+
+ if (changed) {
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
}
}
-
- uvedit_live_unwrap_update(sima, scene, obedit);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ MEM_freeN(objects);
}
static int uv_align_exec(bContext *C, wmOperator *op)
@@ -1796,12 +1781,16 @@ static int uv_align_exec(bContext *C, wmOperator *op)
static void UV_OT_align(wmOperatorType *ot)
{
static const EnumPropertyItem axis_items[] = {
- {'s', "ALIGN_S", 0, "Straighten", "Align UVs along the line defined by the endpoints"},
- {'t', "ALIGN_T", 0, "Straighten X", "Align UVs along the line defined by the endpoints along the X axis"},
- {'u', "ALIGN_U", 0, "Straighten Y", "Align UVs along the line defined by the endpoints along the Y axis"},
- {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
- {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
- {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
+ {UV_STRAIGHTEN, "ALIGN_S", 0, "Straighten",
+ "Align UVs along the line defined by the endpoints"},
+ {UV_STRAIGHTEN_X, "ALIGN_T", 0, "Straighten X",
+ "Align UVs along the line defined by the endpoints along the X axis"},
+ {UV_STRAIGHTEN_Y, "ALIGN_U", 0, "Straighten Y",
+ "Align UVs along the line defined by the endpoints along the Y axis"},
+ {UV_ALIGN_AUTO, "ALIGN_AUTO", 0, "Align Auto",
+ "Automatically choose the axis on which there is most alignment already"},
+ {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
+ {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
@@ -1815,7 +1804,7 @@ static void UV_OT_align(wmOperatorType *ot)
ot->poll = ED_operator_uvedit;
/* properties */
- RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
+ RNA_def_enum(ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on");
}
/** \} */
@@ -1824,153 +1813,275 @@ static void UV_OT_align(wmOperatorType *ot)
/** \name Remove Doubles Operator
* \{ */
-typedef struct UVvert {
- MLoopUV *uv_loop;
- bool weld;
-} UVvert;
-
-static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
+static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ ToolSettings *ts = scene->toolsettings;
+
const float threshold = RNA_float_get(op->ptr, "threshold");
- const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected");
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- SpaceImage *sima;
- Scene *scene;
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- Image *ima;
- MTexPoly *tf;
- int uv_a_index;
- int uv_b_index;
- float *uv_a;
- const float *uv_b;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
+ bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed");
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr.
+ * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */
+ uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len,
+ "uv_remove_doubles_selected.ob_mloopuv_max_idx");
- sima = CTX_wm_space_image(C);
- scene = CTX_data_scene(C);
- ima = CTX_data_edit_image(C);
+ /* Calculate max possible number of kdtree nodes. */
+ int uv_maxlen = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (use_unselected == false) {
- UVvert *vert_arr = NULL;
- BLI_array_declare(vert_arr);
- MLoopUV **loop_arr = NULL;
- BLI_array_declare(loop_arr);
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
- /* TODO, use kd-tree as with MESH_OT_remove_doubles, this isn't optimal */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ uv_maxlen += em->bm->totloop;
+ }
+
+ KDTree *tree = BLI_kdtree_new(uv_maxlen);
+
+ int *duplicates = NULL;
+ BLI_array_declare(duplicates);
+
+ MLoopUV **mloopuv_arr = NULL;
+ BLI_array_declare(mloopuv_arr);
+
+ int mloopuv_count = 0; /* Also used for *duplicates count. */
+
+ float uvw[3];
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- UVvert vert;
- vert.uv_loop = luv;
- vert.weld = false;
- BLI_array_append(vert_arr, vert);
+ copy_v3_fl3(uvw, luv->uv[0], luv->uv[1], 0.0f);
+ BLI_kdtree_insert(tree, mloopuv_count, uvw);
+ BLI_array_append(duplicates, -1);
+ BLI_array_append(mloopuv_arr, luv);
+ mloopuv_count++;
}
+ }
+ }
+
+ ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1;
+ }
+
+ BLI_kdtree_balance(tree);
+ int found_duplicates = BLI_kdtree_calc_duplicates_fast(tree, threshold, false, duplicates);
+ if (found_duplicates > 0) {
+ /* Calculate average uv for duplicates. */
+ int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count,
+ "uv_remove_doubles_selected.uv_duplicate_count");
+ for (int i = 0; i < mloopuv_count; i++) {
+ if (duplicates[i] == -1) { /* If doesn't reference another */
+ uv_duplicate_count[i]++; /* self */
+ continue;
}
+
+ if (duplicates[i] != i) {
+ /* If not self then accumulate uv for averaging.
+ * Self uv is already present in accumulator */
+ add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv);
+ }
+ uv_duplicate_count[duplicates[i]]++;
}
- for (uv_a_index = 0; uv_a_index < BLI_array_len(vert_arr); uv_a_index++) {
- if (vert_arr[uv_a_index].weld == false) {
- float uv_min[2];
- float uv_max[2];
+ for (int i = 0; i < mloopuv_count; i++) {
+ if (uv_duplicate_count[i] < 2) {
+ continue;
+ }
- BLI_array_clear(loop_arr);
- BLI_array_append(loop_arr, vert_arr[uv_a_index].uv_loop);
+ mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]);
+ }
+ MEM_freeN(uv_duplicate_count);
- uv_a = vert_arr[uv_a_index].uv_loop->uv;
+ /* Update duplicated uvs. */
+ uint ob_index = 0;
+ for (int i = 0; i < mloopuv_count; i++) {
+ /* Make sure we know which object owns the MLoopUV at this index.
+ * Remember that in some cases the object will have no loop uv,
+ * thus we need the while loop, and not simply an if check. */
+ while (ob_mloopuv_max_idx[ob_index] < i) {
+ ob_index++;
+ }
- copy_v2_v2(uv_max, uv_a);
- copy_v2_v2(uv_min, uv_a);
+ if (duplicates[i] == -1) {
+ continue;
+ }
- vert_arr[uv_a_index].weld = true;
- for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_len(vert_arr); uv_b_index++) {
- uv_b = vert_arr[uv_b_index].uv_loop->uv;
- if ((vert_arr[uv_b_index].weld == false) &&
- (len_manhattan_v2v2(uv_a, uv_b) < threshold))
- {
- minmax_v2v2_v2(uv_min, uv_max, uv_b);
- BLI_array_append(loop_arr, vert_arr[uv_b_index].uv_loop);
- vert_arr[uv_b_index].weld = true;
- }
- }
- if (BLI_array_len(loop_arr)) {
- float uv_mid[2];
- mid_v2_v2v2(uv_mid, uv_min, uv_max);
- for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr); uv_b_index++) {
- copy_v2_v2(loop_arr[uv_b_index]->uv, uv_mid);
- }
- }
+ copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv);
+ changed[ob_index] = true;
+ }
+
+ for (ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (changed[ob_index]) {
+ Object *obedit = objects[ob_index];
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
}
}
+ }
- BLI_array_free(vert_arr);
- BLI_array_free(loop_arr);
+ BLI_kdtree_free(tree);
+ BLI_array_free(mloopuv_arr);
+ BLI_array_free(duplicates);
+ MEM_freeN(changed);
+ MEM_freeN(objects);
+ MEM_freeN(ob_mloopuv_max_idx);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = CTX_data_edit_image(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+
+ /* Calculate max possible number of kdtree nodes. */
+ int uv_maxlen = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ uv_maxlen += em->bm->totloop;
}
- else {
- /* selected -> unselected
- *
- * No need to use 'UVvert' here */
- MLoopUV **loop_arr = NULL;
- BLI_array_declare(loop_arr);
- MLoopUV **loop_arr_unselected = NULL;
- BLI_array_declare(loop_arr_unselected);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ KDTree *tree = BLI_kdtree_new(uv_maxlen);
+
+ MLoopUV **mloopuv_arr = NULL;
+ BLI_array_declare(mloopuv_arr);
+
+ int mloopuv_count = 0;
+
+ float uvw[3];
+ /* Add visible non-selected uvs to tree */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- BLI_array_append(loop_arr, luv);
- }
- else {
- BLI_array_append(loop_arr_unselected, luv);
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v3_fl3(uvw, luv->uv[0], luv->uv[1], 0.0f);
+ BLI_kdtree_insert(tree, mloopuv_count, uvw);
+ BLI_array_append(mloopuv_arr, luv);
+ mloopuv_count++;
}
}
}
+ }
+
+ BLI_kdtree_balance(tree);
+
+ /* For each selected uv, find duplicate non selected uv. */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+ bool changed = false;
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
- for (uv_a_index = 0; uv_a_index < BLI_array_len(loop_arr); uv_a_index++) {
- float dist_best = FLT_MAX, dist;
- const float *uv_best = NULL;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- uv_a = loop_arr[uv_a_index]->uv;
- for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr_unselected); uv_b_index++) {
- uv_b = loop_arr_unselected[uv_b_index]->uv;
- dist = len_manhattan_v2v2(uv_a, uv_b);
- if ((dist < threshold) && (dist < dist_best)) {
- uv_best = uv_b;
- dist_best = dist;
- }
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
}
- if (uv_best) {
- copy_v2_v2(uv_a, uv_best);
+
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v3_fl3(uvw, luv->uv[0], luv->uv[1], 0.0f);
+
+ KDTreeNearest nearest;
+ const int i = BLI_kdtree_find_nearest(tree, uvw, &nearest);
+
+ if (i != -1 && nearest.dist < threshold) {
+ copy_v2_v2(luv->uv, mloopuv_arr[i]->uv);
+ changed = true;
+ }
+ }
}
}
- BLI_array_free(loop_arr);
- BLI_array_free(loop_arr_unselected);
+ if (changed) {
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
}
- uvedit_live_unwrap_update(sima, scene, obedit);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ BLI_kdtree_free(tree);
+ BLI_array_free(mloopuv_arr);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
+static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
+{
+ if (RNA_boolean_get(op->ptr, "use_unselected")) {
+ return uv_remove_doubles_to_unselected(C, op);
+ }
+ else {
+ return uv_remove_doubles_to_selected(C, op);
+ }
+}
+
static void UV_OT_remove_doubles(wmOperatorType *ot)
{
/* identifiers */
@@ -1996,7 +2107,7 @@ static void UV_OT_remove_doubles(wmOperatorType *ot)
static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op))
{
- uv_weld_align(C, 'w');
+ uv_weld_align(C, UV_WELD);
return OPERATOR_FINISHED;
}
@@ -2020,20 +2131,65 @@ static void UV_OT_weld(wmOperatorType *ot)
/** \name (De)Select All Operator
* \{ */
-static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int action)
+
+static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
+{
+ ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
+ }
+ else {
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_select_is_any_selected(scene, ima, obedit)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
{
ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
- if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (action == SEL_TOGGLE) {
+ action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
+ }
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
switch (action) {
case SEL_TOGGLE:
EDBM_select_toggle_all(em);
@@ -2051,30 +2207,8 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int
}
}
else {
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- continue;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- action = SEL_DESELECT;
- break;
- }
- }
- }
- }
-
-
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -2096,18 +2230,40 @@ static void uv_select_all_perform(Scene *scene, Image *ima, BMEditMesh *em, int
}
}
+static void uv_select_all_perform_multi(
+ Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
+{
+ if (action == SEL_TOGGLE) {
+ action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_all_perform(scene, ima, obedit, action);
+ }
+}
+
static int uv_select_all_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = scene->toolsettings;
Image *ima = CTX_data_edit_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
int action = RNA_enum_get(op->ptr, "action");
- uv_select_all_perform(scene, ima, em, action);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -2156,18 +2312,18 @@ static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], fl
return false;
}
-static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop)
+static int uv_mouse_select_multi(
+ bContext *C, Object **objects, uint objects_len,
+ const float co[2], bool extend, bool loop)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
UvNearestHit hit = UV_NEAREST_HIT_INIT;
int i, selectmode, sticky, sync, *hitv = NULL;
@@ -2175,9 +2331,6 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
float limit[2], **hituv = NULL;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
-
/* notice 'limit' is the same no matter the zoom level, since this is like
* remove doubles and could annoying if it joined points when zoomed out.
* 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
@@ -2214,7 +2367,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* find nearest element */
if (loop) {
/* find edge */
- if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2222,7 +2375,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_VERTEX) {
/* find vertex */
- if (!uv_find_nearest_vert(scene, ima, em, co, penalty_dist, &hit)) {
+ if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2238,7 +2391,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_EDGE) {
/* find edge */
- if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2256,10 +2409,13 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_FACE) {
/* find face */
- if (!uv_find_nearest_face(scene, ima, em, co, &hit)) {
+ if (!uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
+ BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
/* make active */
BM_mesh_active_face_set(em->bm, hit.efa);
@@ -2276,7 +2432,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
hitlen = hit.efa->len;
}
else if (selectmode == UV_SELECT_ISLAND) {
- if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2287,13 +2443,25 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
return OPERATOR_CANCELLED;
}
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
/* do selection */
if (loop) {
- flush = uv_select_edgeloop(scene, ima, em, &hit, limit, extend);
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
+ flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
}
else if (selectmode == UV_SELECT_ISLAND) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
/* Current behavior of 'extend' is actually toggling, so pass extend flag as 'toggle' here */
- uv_select_linked(scene, ima, em, limit, &hit, false, false, extend, false);
+ uv_select_linked_multi(scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
}
else if (extend) {
if (selectmode == UV_SELECT_VERTEX) {
@@ -2328,8 +2496,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -2344,7 +2511,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else {
/* deselect all */
- uv_select_all_perform(scene, ima, em, SEL_DESELECT);
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
if (selectmode == UV_SELECT_VERTEX) {
/* select vertex */
@@ -2364,8 +2531,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* select sticky uvs */
if (sticky != SI_STICKY_DISABLE) {
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -2408,11 +2574,22 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
#endif
}
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obiter = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obiter);
+ }
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
+static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+ int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, loop);
+ MEM_freeN(objects);
+ return ret;
+}
static int uv_select_exec(bContext *C, wmOperator *op)
{
@@ -2517,9 +2694,8 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
float limit[2];
int extend, deselect;
bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
@@ -2535,6 +2711,9 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
deselect = RNA_boolean_get(op->ptr, "deselect");
uvedit_pixel_to_float(sima, limit, 0.05f);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+
if (pick) {
float co[2];
@@ -2550,15 +2729,34 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
RNA_float_get_array(op->ptr, "location", co);
}
- if (!uv_find_nearest_edge(scene, ima, em, co, &hit)) {
+ if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
+ MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
}
- uv_select_linked(scene, ima, em, limit, pick ? &hit : NULL, extend, deselect, false, select_faces);
+ if (!extend) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ uv_select_linked_multi(
+ scene, ima, objects, objects_len, limit, pick ? &hit : NULL,
+ extend, deselect, false, select_faces);
+
+ /* weak!, but works */
+ Object **objects_free = objects;
+ if (pick) {
+ objects = &hit.ob;
+ objects_len = 1;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_SAFE_FREE(objects_free);
return OPERATOR_FINISHED;
}
@@ -2624,70 +2822,76 @@ static void UV_OT_select_linked_pick(wmOperatorType *ot)
static int uv_select_split_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
ToolSettings *ts = scene->toolsettings;
Image *ima = CTX_data_edit_image(C);
- Object *obedit = CTX_data_edit_object(C);
- BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
if (ts->uv_flag & UV_SYNC_SELECTION) {
BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
return OPERATOR_CANCELLED;
}
+ bool changed_multi = false;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- bool is_sel = false;
- bool is_unsel = false;
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- continue;
+ bool changed = false;
- /* are we all selected? */
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- if (luv->flag & MLOOPUV_VERTSEL) {
- is_sel = true;
- }
- else {
- is_unsel = true;
- }
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ bool is_sel = false;
+ bool is_unsel = false;
- /* we have mixed selection, bail out */
- if (is_sel && is_unsel) {
- break;
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
}
- }
- if (is_sel && is_unsel) {
+ /* are we all selected? */
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ is_sel = true;
+ }
+ else {
+ is_unsel = true;
+ }
+
+ /* we have mixed selection, bail out */
+ if (is_sel && is_unsel) {
+ break;
+ }
}
- changed = true;
+ if (is_sel && is_unsel) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ changed = true;
+ }
}
- }
- if (changed) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ }
}
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
@@ -2723,6 +2927,20 @@ static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short s
}
}
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+ else {
+ Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
+ /* Only for region redraw. */
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2796,7 +3014,6 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- /* MTexPoly *tf; */
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
@@ -2882,7 +3099,6 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- /* MTexPoly *tf; */
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
@@ -2952,139 +3168,149 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Border Select Operator
+/** \name Box Select Operator
* \{ */
-static int uv_border_select_exec(bContext *C, wmOperator *op)
+static int uv_box_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tf;
MLoopUV *luv;
rctf rectf;
- bool changed, pinned, select, extend;
+ bool pinned;
const bool use_face_center = (
(ts->uv_flag & UV_SYNC_SELECTION) ?
(ts->selectmode == SCE_SELECT_FACE) :
(ts->uv_selectmode == UV_SELECT_FACE));
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
-
/* get rectangle from operator */
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
- /* figure out what to select/deselect */
- select = !RNA_boolean_get(op->ptr, "deselect");
- extend = RNA_boolean_get(op->ptr, "extend");
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const bool select = (sel_op != SEL_OP_SUB);
+
pinned = RNA_boolean_get(op->ptr, "pinned");
- if (!extend)
- uv_select_all_perform(scene, ima, em, SEL_DESELECT);
+ bool changed_multi = false;
- /* do actual selection */
- if (use_face_center && !pinned) {
- /* handle face selection mode */
- float cent[2];
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- changed = false;
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
+ }
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* assume not touched */
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (BLI_rctf_isect_pt_v(&rectf, cent)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do actual selection */
+ if (use_face_center && !pinned) {
+ /* handle face selection mode */
+ float cent[2];
+
+ changed = false;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* assume not touched */
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (BLI_rctf_isect_pt_v(&rectf, cent)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
}
}
- }
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
}
- }
- else {
- /* other selection modes */
- changed = true;
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+ else {
+ /* other selection modes */
+ changed = true;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tf))
- continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
+ continue;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
+ if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
- /* UV_SYNC_SELECTION - can't do pinned selection */
- if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ /* UV_SYNC_SELECTION - can't do pinned selection */
+ if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
}
- }
- else if (pinned) {
- if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ else if (pinned) {
+ if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
}
}
}
- }
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
}
- }
- if (changed) {
- uv_select_sync_flush(ts, em, select);
+ if (changed) {
+ changed_multi = true;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
-
- return OPERATOR_FINISHED;
}
- return OPERATOR_CANCELLED;
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-static void UV_OT_select_border(wmOperatorType *ot)
+static void UV_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Border Select";
- ot->description = "Select UV vertices using border selection";
- ot->idname = "UV_OT_select_border";
+ ot->name = "Box Select";
+ ot->description = "Select UV vertices using box selection";
+ ot->idname = "UV_OT_select_box";
/* api callbacks */
- ot->invoke = WM_gesture_border_invoke;
- ot->exec = uv_border_select_exec;
- ot->modal = WM_gesture_border_modal;
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = uv_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
ot->poll = ED_operator_uvedit_space_image; /* requires space image */;
- ot->cancel = WM_gesture_border_cancel;
+ ot->cancel = WM_gesture_box_cancel;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
- WM_operator_properties_gesture_border_select(ot);
+ WM_operator_properties_gesture_box(ot);
+ WM_operator_properties_select_operation_simple(ot);
}
/** \} */
@@ -3104,11 +3330,11 @@ static int uv_inside_circle(const float uv[2], const float offset[2], const floa
static int uv_circle_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
ToolSettings *ts = scene->toolsettings;
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
ARegion *ar = CTX_wm_region(C);
BMFace *efa;
BMLoop *l;
@@ -3117,14 +3343,12 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
int x, y, radius, width, height;
float zoomx, zoomy, offset[2], ellipse[2];
const bool select = !RNA_boolean_get(op->ptr, "deselect");
- bool changed = false;
+
const bool use_face_center = (
(ts->uv_flag & UV_SYNC_SELECTION) ?
(ts->selectmode == SCE_SELECT_FACE) :
(ts->uv_selectmode == UV_SELECT_FACE));
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
/* get operator properties */
x = RNA_int_get(op->ptr, "x");
y = RNA_int_get(op->ptr, "y");
@@ -3140,61 +3364,77 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op)
UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
- /* do selection */
- if (use_face_center) {
- changed = false;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (uv_inside_circle(cent, offset, ellipse)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (use_face_center) {
+ changed = false;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (uv_inside_circle(cent, offset, ellipse)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
}
}
- }
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
}
- }
- else {
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+ else {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_inside_circle(luv->uv, offset, ellipse)) {
- changed = true;
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uv_inside_circle(luv->uv, offset, ellipse)) {
+ changed = true;
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
}
}
- }
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
}
- }
- if (changed) {
- uv_select_sync_flush(ts, em, select);
+ if (changed) {
+ changed_multi = true;
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
}
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-static void UV_OT_circle_select(wmOperatorType *ot)
+static void UV_OT_select_circle(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Circle Select";
ot->description = "Select UV vertices using circle selection";
- ot->idname = "UV_OT_circle_select";
+ ot->idname = "UV_OT_select_circle";
/* api callbacks */
ot->invoke = WM_gesture_circle_invoke;
@@ -3204,7 +3444,7 @@ static void UV_OT_circle_select(wmOperatorType *ot)
ot->cancel = WM_gesture_circle_cancel;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
/* properties */
WM_operator_properties_gesture_circle_select(ot);
@@ -3218,100 +3458,110 @@ static void UV_OT_circle_select(wmOperatorType *ot)
static bool do_lasso_select_mesh_uv(
bContext *C, const int mcords[][2], short moves,
- const bool select, const bool extend)
+ const eSelectOp sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const bool use_face_center = (
(ts->uv_flag & UV_SYNC_SELECTION) ?
(ts->selectmode == SCE_SELECT_FACE) :
(ts->uv_selectmode == UV_SELECT_FACE));
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ const bool select = (sel_op != SEL_OP_SUB);
BMIter iter, liter;
BMFace *efa;
BMLoop *l;
- MTexPoly *tf;
int screen_uv[2];
- bool changed = false;
+ bool changed_multi = false;
rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves);
- if (!extend && select) {
- uv_select_all_perform(scene, ima, em, SEL_DESELECT);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
}
- if (use_face_center) { /* Face Center Sel */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- if (UI_view2d_view_to_region_clip(&ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
- {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ bool changed = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (use_face_center) { /* Face Center Sel */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+
+ if (UI_view2d_view_to_region_clip(&ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
+ BLI_rcti_isect_pt_v(&rect, screen_uv) &&
+ BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
+ {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
}
}
- }
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
}
- }
- else { /* Vert Sel */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+ else { /* Vert Sel */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (uvedit_face_visible_test(scene, ima, efa, tf)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UI_view2d_view_to_region_clip(
- &ar->v2d,
- luv->uv[0], luv->uv[1],
- &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
- {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- changed = true;
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (UI_view2d_view_to_region_clip(
+ &ar->v2d,
+ luv->uv[0], luv->uv[1],
+ &screen_uv[0], &screen_uv[1]) &&
+ BLI_rcti_isect_pt_v(&rect, screen_uv) &&
+ BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
+ {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
}
}
}
}
- }
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
}
- }
- if (changed) {
- uv_select_sync_flush(scene->toolsettings, em, select);
+ if (changed) {
+ changed_multi = true;
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
}
+ MEM_freeN(objects);
- return changed;
+ return changed_multi;
}
static int uv_lasso_select_exec(bContext *C, wmOperator *op)
@@ -3320,13 +3570,8 @@ static int uv_lasso_select_exec(bContext *C, wmOperator *op)
const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
- bool select, extend;
- bool changed;
-
- select = !RNA_boolean_get(op->ptr, "deselect");
- extend = RNA_boolean_get(op->ptr, "extend");
- changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, select, extend);
-
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op);
MEM_freeN((void *)mcords);
return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
@@ -3351,7 +3596,8 @@ static void UV_OT_select_lasso(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- WM_operator_properties_gesture_lasso_select(ot);
+ WM_operator_properties_gesture_lasso(ot);
+ WM_operator_properties_select_operation_simple(ot);
}
/** \} */
@@ -3374,17 +3620,16 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima)
uv_snap_to_pixel(sima->cursor, width, height);
}
-static bool uv_snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
+static bool uv_snap_cursor_to_selection(
+ Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima)
{
- return uvedit_center(scene, ima, obedit, sima->cursor, sima->around);
+ return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around);
}
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Image *ima = CTX_data_edit_image(C);
+
bool changed = false;
switch (RNA_enum_get(op->ptr, "target")) {
@@ -3393,8 +3638,18 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
changed = true;
break;
case 1:
- changed = uv_snap_cursor_to_selection(scene, ima, obedit, sima);
+ {
+ Scene *scene = CTX_data_scene(C);
+ Image *ima = CTX_data_edit_image(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+ changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima);
+ MEM_freeN(objects);
break;
+ }
}
if (!changed)
@@ -3438,16 +3693,13 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tface;
MLoopUV *luv;
bool changed = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tface))
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3468,16 +3720,13 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *mtexpoly;
MLoopUV *luv;
bool changed = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- mtexpoly = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, mtexpoly))
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3499,17 +3748,14 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object
BMFace *f;
BMLoop *l, *lsub;
BMIter iter, liter, lsubiter;
- MTexPoly *tface;
MLoopUV *luv;
bool changed = false;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
/* index every vert that has a selected UV using it, but only once so as to
* get unique indices and to count how much to malloc */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- tface = BM_ELEM_CD_GET_VOID_P(f, cd_poly_tex_offset);
- if (uvedit_face_visible_test(scene, ima, f, tface)) {
+ if (uvedit_face_visible_test(scene, obedit, ima, f)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
@@ -3557,22 +3803,19 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tface;
MLoopUV *luv;
int width = 0, height = 0;
float w, h;
bool changed = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
ED_space_image_get_size(sima, &width, &height);
w = (float)width;
h = (float)height;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tface))
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
@@ -3590,42 +3833,62 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit
static int uv_snap_selection_exec(bContext *C, wmOperator *op)
{
- SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
- bool changed = false;
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+ const int target = RNA_enum_get(op->ptr, "target");
+ float offset[2] = {0};
- switch (RNA_enum_get(op->ptr, "target")) {
- case 0:
- changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
- break;
- case 1:
- changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor);
- break;
- case 2:
- {
- float center[2];
- if (uvedit_center(scene, ima, obedit, center, sima->around)) {
- float offset[2];
- sub_v2_v2v2(offset, sima->cursor, center);
- changed = uv_snap_uvs_offset(scene, ima, obedit, offset);
- }
- break;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+
+ if (target == 2) {
+ float center[2];
+ if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
}
- case 3:
- changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit);
- break;
+ sub_v2_v2v2(offset, sima->cursor, center);
}
- if (!changed)
- return OPERATOR_CANCELLED;
+ bool changed_multi = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- uvedit_live_unwrap_update(sima, scene, obedit);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
- return OPERATOR_FINISHED;
+ bool changed = false;
+ switch (target) {
+ case 0:
+ changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
+ break;
+ case 1:
+ changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor);
+ break;
+ case 2:
+ changed = uv_snap_uvs_offset(scene, ima, obedit, offset);
+ break;
+ case 3:
+ changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit);
+ break;
+ }
+
+ if (changed) {
+ changed_multi = true;
+ uvedit_live_unwrap_update(sima, scene, obedit);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void UV_OT_snap_selected(wmOperatorType *ot)
@@ -3660,39 +3923,55 @@ static void UV_OT_snap_selected(wmOperatorType *ot)
static int uv_pin_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tface;
MLoopUV *luv;
+ ToolSettings *ts = scene->toolsettings;
const bool clear = RNA_boolean_get(op->ptr, "clear");
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tface))
- continue;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
- if (!clear) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
- luv->flag |= MLOOPUV_PINNED;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
}
- else {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
- luv->flag &= ~MLOOPUV_PINNED;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ changed = true;
+ if (clear) {
+ luv->flag &= ~MLOOPUV_PINNED;
+ }
+ else {
+ luv->flag |= MLOOPUV_PINNED;
+ }
+ }
}
}
- }
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ if (changed) {
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3721,33 +4000,46 @@ static void UV_OT_pin(wmOperatorType *ot)
static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- MTexPoly *tface;
MLoopUV *luv;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- tface = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
- if (!uvedit_face_visible_test(scene, ima, efa, tface))
- continue;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ bool changed = false;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_PINNED)
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_PINNED) {
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
}
- }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -3805,16 +4097,16 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
- MTexPoly *tf;
const bool swap = RNA_boolean_get(op->ptr, "unselected");
Image *ima = sima ? sima->image : NULL;
const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
if (ts->uv_flag & UV_SYNC_SELECTION) {
EDBM_mesh_hide(em, swap);
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -3823,9 +4115,7 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
int hide = 0;
- tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
+ if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
@@ -3885,6 +4175,8 @@ static int uv_hide_exec(bContext *C, wmOperator *op)
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
BM_select_history_validate(em->bm);
+
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -3938,6 +4230,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *op)
/* call the mesh function if we are in mesh sync sel */
if (ts->uv_flag & UV_SYNC_SELECTION) {
EDBM_mesh_reveal(em, select);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -4027,6 +4320,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *op)
/* re-select tagged faces */
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ DEG_id_tag_update(obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -4106,9 +4400,6 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
ot->invoke = uv_set_2d_cursor_invoke;
ot->poll = uv_set_2d_cursor_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
/* properties */
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
"Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f);
@@ -4117,192 +4408,121 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Set Tile Operator
+/** \name Seam from UV Islands Operator
* \{ */
-static int set_tile_exec(bContext *C, wmOperator *op)
-{
- Image *ima = CTX_data_edit_image(C);
- int tile[2];
- Object *obedit = CTX_data_edit_object(C);
-
- RNA_int_get_array(op->ptr, "tile", tile);
-
- if (uvedit_set_tile(obedit, ima, tile[0] + ima->xrep * tile[1])) {
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
-
- return OPERATOR_FINISHED;
- }
-
- return OPERATOR_CANCELLED;
-}
-
-static int set_tile_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *ar = CTX_wm_region(C);
- float fx, fy;
- int tile[2];
-
- if (!ima || !(ima->tpageflag & IMA_TILES))
- return OPERATOR_CANCELLED;
-
- UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
-
- if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
- fx = fx * ima->xrep;
- fy = fy * ima->yrep;
-
- tile[0] = fx;
- tile[1] = fy;
-
- sima->curtile = tile[1] * ima->xrep + tile[0];
- RNA_int_set_array(op->ptr, "tile", tile);
- }
-
- return set_tile_exec(C, op);
-}
-
-static void UV_OT_tile_set(wmOperatorType *ot)
+static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
{
- /* identifiers */
- ot->name = "Set Tile";
- ot->description = "Set UV image tile coordinates";
- ot->idname = "UV_OT_tile_set";
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int ret = OPERATOR_CANCELLED;
+ const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+ const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
+ const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
- /* api callbacks */
- ot->exec = set_tile_exec;
- ot->invoke = set_tile_invoke;
- ot->poll = ED_operator_image_active;
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bm = em->bm;
- /* properties */
- RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate", 0, 10);
-}
+ UvVertMap *vmap;
+ BMEdge *editedge;
+ BMIter iter;
-/** \} */
+ if (!EDBM_uv_check(em)) {
+ continue;
+ }
+ ret = OPERATOR_FINISHED;
-/* -------------------------------------------------------------------- */
-/** \name Seam from UV Islands Operator
- * \{ */
+ /* This code sets editvert->tmp.l to the index. This will be useful later on. */
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(bm, limit, false, false);
-static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
-{
- UvVertMap *vmap;
- Object *ob = CTX_data_edit_object(C);
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *em;
- BMEdge *editedge;
- float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
- const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
- const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
+ BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
+ /* flags to determine if we uv is separated from first editface match */
+ char separated1 = 0, separated2;
+ /* set to denote edge must be flagged as seam */
+ char faces_separated = 0;
+ /* flag to keep track if uv1 is disconnected from first editface match */
+ char v1coincident = 1;
+ /* For use with v1coincident. v1coincident will change only if we've had commonFaces */
+ int commonFaces = 0;
- BMesh *bm;
- BMIter iter;
-
- em = me->edit_btmesh;
- bm = em->bm;
+ BMFace *efa1, *efa2;
- if (!EDBM_uv_check(em)) {
- return OPERATOR_CANCELLED;
- }
+ UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
+ /* mv2cache stores the first of the list of coincident uv's for later comparison
+ * mv2sep holds the last separator and is copied to mv2cache when a hit is first found */
+ UvMapVert *mv2cache = NULL, *mv2sep = NULL;
- /* This code sets editvert->tmp.l to the index. This will be useful later on. */
- BM_mesh_elem_table_ensure(bm, BM_FACE);
- vmap = BM_uv_vert_map_create(bm, limit, false, false);
-
- BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
- /* flags to determine if we uv is separated from first editface match */
- char separated1 = 0, separated2;
- /* set to denote edge must be flagged as seam */
- char faces_separated = 0;
- /* flag to keep track if uv1 is disconnected from first editface match */
- char v1coincident = 1;
- /* For use with v1coincident. v1coincident will change only if we've had commonFaces */
- int commonFaces = 0;
-
- BMFace *efa1, *efa2;
-
- UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
- /* mv2cache stores the first of the list of coincident uv's for later comparison
- * mv2sep holds the last separator and is copied to mv2cache when a hit is first found */
- UvMapVert *mv2cache = NULL, *mv2sep = NULL;
-
- mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)];
- if (mark_seams)
- BM_elem_flag_disable(editedge, BM_ELEM_SEAM);
-
- for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
- if (mv1->separate && commonFaces)
- v1coincident = 0;
-
- separated2 = 0;
- efa1 = BM_face_at_index(bm, mv1->poly_index);
- mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)];
-
- for (mv2 = mvinit2; mv2; mv2 = mv2->next) {
- if (mv2->separate)
- mv2sep = mv2;
-
- efa2 = BM_face_at_index(bm, mv2->poly_index);
- if (efa1 == efa2) {
- /* if v1 is not coincident no point in comparing */
- if (v1coincident) {
- /* have we found previously anything? */
- if (mv2cache) {
- /* flag seam unless proved to be coincident with previous hit */
- separated2 = 1;
- for (mviter = mv2cache; mviter; mviter = mviter->next) {
- if (mviter->separate && mviter != mv2cache)
- break;
- /* coincident with previous hit, do not flag seam */
- if (mviter == mv2)
- separated2 = 0;
+ mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)];
+ if (mark_seams)
+ BM_elem_flag_disable(editedge, BM_ELEM_SEAM);
+
+ for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
+ if (mv1->separate && commonFaces)
+ v1coincident = 0;
+
+ separated2 = 0;
+ efa1 = BM_face_at_index(bm, mv1->poly_index);
+ mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)];
+
+ for (mv2 = mvinit2; mv2; mv2 = mv2->next) {
+ if (mv2->separate)
+ mv2sep = mv2;
+
+ efa2 = BM_face_at_index(bm, mv2->poly_index);
+ if (efa1 == efa2) {
+ /* if v1 is not coincident no point in comparing */
+ if (v1coincident) {
+ /* have we found previously anything? */
+ if (mv2cache) {
+ /* flag seam unless proved to be coincident with previous hit */
+ separated2 = 1;
+ for (mviter = mv2cache; mviter; mviter = mviter->next) {
+ if (mviter->separate && mviter != mv2cache)
+ break;
+ /* coincident with previous hit, do not flag seam */
+ if (mviter == mv2)
+ separated2 = 0;
+ }
+ }
+ /* First hit case, store the hit in the cache */
+ else {
+ mv2cache = mv2sep;
+ commonFaces = 1;
}
}
- /* First hit case, store the hit in the cache */
- else {
- mv2cache = mv2sep;
- commonFaces = 1;
- }
- }
- else
- separated1 = 1;
+ else
+ separated1 = 1;
- if (separated1 || separated2) {
- faces_separated = 1;
- break;
+ if (separated1 || separated2) {
+ faces_separated = 1;
+ break;
+ }
}
}
}
- }
- if (faces_separated) {
- if (mark_seams)
- BM_elem_flag_enable(editedge, BM_ELEM_SEAM);
- if (mark_sharp)
- BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH);
+ if (faces_separated) {
+ if (mark_seams)
+ BM_elem_flag_enable(editedge, BM_ELEM_SEAM);
+ if (mark_sharp)
+ BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH);
+ }
}
- }
- if (mark_seams) {
- me->drawflag |= ME_DRAWSEAMS;
- }
- if (mark_sharp) {
- me->drawflag |= ME_DRAWSHARP;
- }
-
-
- BM_uv_vert_map_free(vmap);
+ BM_uv_vert_map_free(vmap);
- DAG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ DEG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ }
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ return ret;
}
@@ -4332,33 +4552,53 @@ static void UV_OT_seams_from_islands(wmOperatorType *ot)
static int uv_mark_seam_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *em = me->edit_btmesh;
- BMesh *bm = em->bm;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ToolSettings *ts = scene->toolsettings;
+
BMFace *efa;
BMLoop *loop;
BMIter iter, liter;
- bool flag_set = !RNA_boolean_get(op->ptr, "clear");
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ const bool flag_set = !RNA_boolean_get(op->ptr, "clear");
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
- BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bm = em->bm;
+
+ if (synced_selection && (bm->totedgesel == 0)) {
+ continue;
}
- }
- me->drawflag |= ME_DRAWSEAMS;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ bool changed = false;
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
+ BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
+ changed = true;
+ }
+ }
+ }
- if (scene->toolsettings->edge_mode_live_unwrap)
- ED_unwrap_lscm(scene, ob, false);
+ if (changed) {
+ if (scene->toolsettings->edge_mode_live_unwrap) {
+ ED_unwrap_lscm(scene, ob, false, false);
+ }
- DAG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ DEG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ }
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4417,9 +4657,9 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_select_linked_pick);
WM_operatortype_append(UV_OT_select_split);
WM_operatortype_append(UV_OT_select_pinned);
- WM_operatortype_append(UV_OT_select_border);
+ WM_operatortype_append(UV_OT_select_box);
WM_operatortype_append(UV_OT_select_lasso);
- WM_operatortype_append(UV_OT_circle_select);
+ WM_operatortype_append(UV_OT_select_circle);
WM_operatortype_append(UV_OT_select_more);
WM_operatortype_append(UV_OT_select_less);
@@ -4450,104 +4690,14 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_hide);
WM_operatortype_append(UV_OT_cursor_set);
- WM_operatortype_append(UV_OT_tile_set);
}
void ED_keymap_uvedit(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
- wmKeyMapItem *kmi;
keymap = WM_keymap_ensure(keyconf, "UV Editor", 0, 0);
keymap->poll = ED_operator_uvedit_can_uv_sculpt;
-
- /* Uv sculpt toggle */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_uv_sculpt");
-
- /* Mark edge seam */
- WM_keymap_add_item(keymap, "UV_OT_mark_seam", EKEY, KM_PRESS, KM_CTRL, 0);
-
- /* pick selection */
- RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0)->ptr, "extend", false);
- RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", true);
- RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_loop", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "extend", false);
- RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_loop", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "extend", true);
- WM_keymap_add_item(keymap, "UV_OT_select_split", YKEY, KM_PRESS, 0, 0);
-
- /* border/circle selection */
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "pinned", false);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "pinned", true);
-
- WM_keymap_add_item(keymap, "UV_OT_circle_select", CKEY, KM_PRESS, 0, 0);
-
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- /* selection manipulation */
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "extend", true);
- RNA_boolean_set(kmi->ptr, "deselect", false);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", true);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "extend", false);
- RNA_boolean_set(kmi->ptr, "deselect", true);
-
- /* select more/less */
- WM_keymap_add_item(keymap, "UV_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "UV_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_all", AKEY, KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
- kmi = WM_keymap_add_item(keymap, "UV_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
- RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
-
- WM_keymap_add_item(keymap, "UV_OT_select_pinned", PKEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, 0, 0);
-
- /* uv operations */
- WM_keymap_add_item(keymap, "UV_OT_stitch", VKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "UV_OT_pin", PKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "clear", false);
- kmi = WM_keymap_add_item(keymap, "UV_OT_pin", PKEY, KM_PRESS, KM_ALT, 0);
- RNA_boolean_set(kmi->ptr, "clear", true);
-
- /* unwrap */
- WM_keymap_add_item(keymap, "UV_OT_unwrap", EKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "UV_OT_minimize_stretch", VKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "UV_OT_pack_islands", PKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "UV_OT_average_islands_scale", AKEY, KM_PRESS, KM_CTRL, 0);
-
- /* hide */
- kmi = WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "unselected", false);
- kmi = WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "unselected", true);
-
- WM_keymap_add_item(keymap, "UV_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
-
- /* cursor */
- WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "UV_OT_tile_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
-
- /* menus */
- WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0);
-
- ED_keymap_proportional_cycle(keyconf, keymap);
- ED_keymap_proportional_editmode(keyconf, keymap, false);
-
- transform_keymap_for_space(keyconf, keymap, SPACE_IMAGE);
}
/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 352bfbf9a9e..412d68a5d4d 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -4189,7 +4189,7 @@ static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts,
float normal[3];
zero_v3(normal);
- const float *co_curr, *co_prev = co[nverts-1];
+ const float *co_curr, *co_prev = co[nverts - 1];
for (int j = 0; j < nverts; j++) {
co_curr = co[j];
add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 869009d1bdf..07184249d2c 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -52,9 +52,11 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh_mapping.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
#include "UI_interface.h"
@@ -63,6 +65,9 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "GPU_batch.h"
+#include "GPU_state.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
@@ -146,18 +151,11 @@ typedef struct UvEdge {
/* stitch state object */
typedef struct StitchState {
float aspect;
- /* use limit flag */
- bool use_limit;
- /* limit to operator, same as original operator */
- float limit_dist;
- /* snap uv islands together during stitching */
- bool snap_islands;
- /* stitch at midpoints or at islands */
- bool midpoints;
+ /* object for editmesh */
+ Object *obedit;
/* editmesh, cached for use in modal handler */
BMEditMesh *em;
- /* clear seams of stitched edges after stitch */
- bool clear_seams;
+
/* element map for getting info about uv connectivity */
UvElementMap *element_map;
/* edge container */
@@ -172,6 +170,8 @@ typedef struct StitchState {
UvEdge *edges;
/* hash for quick lookup of edges */
GHash *edge_hash;
+ /* which islands to stop at (to make active) when pressing 'I' */
+ bool *island_is_stitchable;
/* count of separate uvs and edges */
int total_separate_edges;
@@ -179,18 +179,39 @@ typedef struct StitchState {
/* hold selection related information */
void **selection_stack;
int selection_size;
- /* island that stays in place */
- int static_island;
+
/* store number of primitives per face so that we can allocate the active island buffer later */
unsigned int *tris_per_island;
+ /* preview data */
+ StitchPreviewer *stitch_preview;
+} StitchState;
+/* Stitch state container. */
+typedef struct StitchStateContainer {
+ /* clear seams of stitched edges after stitch */
+ bool clear_seams;
+ /* use limit flag */
+ bool use_limit;
+ /* limit to operator, same as original operator */
+ float limit_dist;
+ /* snap uv islands together during stitching */
+ bool snap_islands;
+ /* stitch at midpoints or at islands */
+ bool midpoints;
/* vert or edge mode used for stitching */
char mode;
/* handle for drawing */
void *draw_handle;
- /* preview data */
- StitchPreviewer *stitch_preview;
-} StitchState;
+ /* island that stays in place */
+ int static_island;
+
+ /* Objects and states are aligned. */
+ int objects_len;
+ Object **objects;
+ StitchState **states;
+
+ int active_object_index;
+} StitchStateContainer;
typedef struct PreviewPosition {
int data_position;
@@ -212,6 +233,18 @@ enum StitchModes {
STITCH_EDGE
};
+/* UvElement identification. */
+typedef struct UvElementID {
+ int faceIndex;
+ int elementIndex;
+} UvElementID;
+
+/* StitchState initializition. */
+typedef struct StitchStateInit {
+ int uv_selected_count;
+ UvElementID *to_select;
+} StitchStateInit;
+
/* constructor */
static StitchPreviewer *stitch_preview_init(void)
{
@@ -264,7 +297,7 @@ static void stitch_preview_delete(StitchPreviewer *stitch_preview)
}
/* This function updates the header of the UV editor when the stitch tool updates its settings */
-static void stitch_update_header(StitchState *state, bContext *C)
+static void stitch_update_header(StitchStateContainer *ssc, bContext *C)
{
const char *str = IFACE_(
"Mode(TAB) %s, "
@@ -279,14 +312,15 @@ static void stitch_update_header(StitchState *state, bContext *C)
ScrArea *sa = CTX_wm_area(C);
if (sa) {
- BLI_snprintf(msg, sizeof(msg), str,
- state->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"),
- WM_bool_as_string(state->snap_islands),
- WM_bool_as_string(state->midpoints),
- state->limit_dist,
- WM_bool_as_string(state->use_limit));
+ BLI_snprintf(
+ msg, sizeof(msg), str,
+ ssc->mode == STITCH_VERT ? IFACE_("Vertex") : IFACE_("Edge"),
+ WM_bool_as_string(ssc->snap_islands),
+ WM_bool_as_string(ssc->midpoints),
+ ssc->limit_dist,
+ WM_bool_as_string(ssc->use_limit));
- ED_area_headerprint(sa, msg);
+ ED_workspace_status_text(C, msg);
}
}
@@ -314,7 +348,9 @@ static void stitch_uv_rotate(float mat[2][2], float medianPoint[2], float uv[2],
}
/* check if two uvelements are stitchable. This should only operate on -different- separate UvElements */
-static bool stitch_check_uvs_stitchable(UvElement *element, UvElement *element_iter, StitchState *state)
+static bool stitch_check_uvs_stitchable(
+ UvElement *element, UvElement *element_iter,
+ StitchStateContainer *ssc, StitchState *state)
{
BMesh *bm = state->em->bm;
float limit;
@@ -323,9 +359,9 @@ static bool stitch_check_uvs_stitchable(UvElement *element, UvElement *element_i
return 0;
}
- limit = state->limit_dist;
+ limit = ssc->limit_dist;
- if (state->use_limit) {
+ if (ssc->use_limit) {
MLoopUV *luv, *luv_iter;
BMLoop *l;
@@ -349,7 +385,9 @@ static bool stitch_check_uvs_stitchable(UvElement *element, UvElement *element_i
}
}
-static bool stitch_check_edges_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchState *state)
+static bool stitch_check_edges_stitchable(
+ UvEdge *edge, UvEdge *edge_iter,
+ StitchStateContainer *ssc, StitchState *state)
{
BMesh *bm = state->em->bm;
float limit;
@@ -358,9 +396,9 @@ static bool stitch_check_edges_stitchable(UvEdge *edge, UvEdge *edge_iter, Stitc
return 0;
}
- limit = state->limit_dist;
+ limit = ssc->limit_dist;
- if (state->use_limit) {
+ if (ssc->use_limit) {
BMLoop *l;
MLoopUV *luv_orig1, *luv_iter1;
MLoopUV *luv_orig2, *luv_iter2;
@@ -391,27 +429,30 @@ static bool stitch_check_edges_stitchable(UvEdge *edge, UvEdge *edge_iter, Stitc
}
}
-static bool stitch_check_uvs_state_stitchable(UvElement *element, UvElement *element_iter, StitchState *state)
+static bool stitch_check_uvs_state_stitchable(
+ UvElement *element, UvElement *element_iter,
+ StitchStateContainer *ssc, StitchState *state)
{
- if ((state->snap_islands && element->island == element_iter->island) ||
- (!state->midpoints && element->island == element_iter->island))
+ if ((ssc->snap_islands && element->island == element_iter->island) ||
+ (!ssc->midpoints && element->island == element_iter->island))
{
return 0;
}
- return stitch_check_uvs_stitchable(element, element_iter, state);
+ return stitch_check_uvs_stitchable(element, element_iter, ssc, state);
}
-
-static bool stitch_check_edges_state_stitchable(UvEdge *edge, UvEdge *edge_iter, StitchState *state)
+static bool stitch_check_edges_state_stitchable(
+ UvEdge *edge, UvEdge *edge_iter,
+ StitchStateContainer *ssc, StitchState *state)
{
- if ((state->snap_islands && edge->element->island == edge_iter->element->island) ||
- (!state->midpoints && edge->element->island == edge_iter->element->island))
+ if ((ssc->snap_islands && edge->element->island == edge_iter->element->island) ||
+ (!ssc->midpoints && edge->element->island == edge_iter->element->island))
{
return 0;
}
- return stitch_check_edges_stitchable(edge, edge_iter, state);
+ return stitch_check_edges_stitchable(edge, edge_iter, ssc, state);
}
/* calculate snapping for islands */
@@ -500,8 +541,8 @@ static void stitch_calculate_island_snapping(
static void stitch_island_calculate_edge_rotation(
- UvEdge *edge, StitchState *state, UVVertAverage *uv_average, unsigned int *uvfinal_map,
- IslandStitchData *island_stitch_data)
+ UvEdge *edge, StitchStateContainer *ssc, StitchState *state, UVVertAverage *uv_average,
+ unsigned int *uvfinal_map, IslandStitchData *island_stitch_data)
{
BMesh *bm = state->em->bm;
UvElement *element1, *element2;
@@ -517,7 +558,7 @@ static void stitch_island_calculate_edge_rotation(
luv1 = CustomData_bmesh_get(&bm->ldata, element1->l->head.data, CD_MLOOPUV);
luv2 = CustomData_bmesh_get(&bm->ldata, element2->l->head.data, CD_MLOOPUV);
- if (state->mode == STITCH_VERT) {
+ if (ssc->mode == STITCH_VERT) {
index1 = uvfinal_map[element1 - state->element_map->buf];
index2 = uvfinal_map[element2 - state->element_map->buf];
}
@@ -556,7 +597,7 @@ static void stitch_island_calculate_edge_rotation(
static void stitch_island_calculate_vert_rotation(
- UvElement *element, StitchState *state,
+ UvElement *element, StitchStateContainer *ssc, StitchState *state,
IslandStitchData *island_stitch_data)
{
float edgecos = 1.0f, edgesin = 0.0f;
@@ -566,7 +607,7 @@ static void stitch_island_calculate_vert_rotation(
int rot_elem = 0, rot_elem_neg = 0;
BMLoop *l;
- if (element->island == state->static_island && !state->midpoints)
+ if (element->island == ssc->static_island && !ssc->midpoints)
return;
l = element->l;
@@ -576,12 +617,12 @@ static void stitch_island_calculate_vert_rotation(
element_iter = state->element_map->vert[index];
for (; element_iter; element_iter = element_iter->next) {
- if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, state)) {
+ if (element_iter->separate && stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
int index_tmp1, index_tmp2;
float normal[2];
/* only calculate rotation against static island uv verts */
- if (!state->midpoints && element_iter->island != state->static_island)
+ if (!ssc->midpoints && element_iter->island != ssc->static_island)
continue;
index_tmp1 = element_iter - state->element_map->buf;
@@ -603,7 +644,7 @@ static void stitch_island_calculate_vert_rotation(
}
}
- if (state->midpoints) {
+ if (ssc->midpoints) {
rotation /= 2.0f;
rotation_neg /= 2.0f;
}
@@ -617,6 +658,9 @@ static void stitch_island_calculate_vert_rotation(
static void state_delete(StitchState *state)
{
if (state) {
+ if (state->island_is_stitchable) {
+ MEM_freeN(state->island_is_stitchable);
+ }
if (state->element_map) {
BM_uv_element_map_free(state->element_map);
}
@@ -648,6 +692,18 @@ static void state_delete(StitchState *state)
}
}
+static void state_delete_all(StitchStateContainer *ssc)
+{
+ if (ssc) {
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ state_delete(ssc->states[ob_index]);
+ }
+ MEM_freeN(ssc->states);
+ MEM_freeN(ssc->objects);
+ MEM_freeN(ssc);
+ }
+}
+
static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *state)
{
UvEdge *edges = state->edges;
@@ -730,7 +786,7 @@ static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *
/* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */
static void determine_uv_stitchability(
- UvElement *element, StitchState *state,
+ UvElement *element, StitchStateContainer *ssc, StitchState *state,
IslandStitchData *island_stitch_data)
{
int vert_index;
@@ -744,7 +800,7 @@ static void determine_uv_stitchability(
for (; element_iter; element_iter = element_iter->next) {
if (element_iter->separate) {
- if (stitch_check_uvs_stitchable(element, element_iter, state)) {
+ if (stitch_check_uvs_stitchable(element, element_iter, ssc, state)) {
island_stitch_data[element_iter->island].stitchableCandidate = 1;
island_stitch_data[element->island].stitchableCandidate = 1;
element->flag |= STITCH_STITCHABLE_CANDIDATE;
@@ -754,13 +810,13 @@ static void determine_uv_stitchability(
}
static void determine_uv_edge_stitchability(
- UvEdge *edge, StitchState *state,
+ UvEdge *edge, StitchStateContainer *ssc, StitchState *state,
IslandStitchData *island_stitch_data)
{
UvEdge *edge_iter = edge->first;
for (; edge_iter; edge_iter = edge_iter->next) {
- if (stitch_check_edges_stitchable(edge, edge_iter, state)) {
+ if (stitch_check_edges_stitchable(edge, edge_iter, ssc, state)) {
island_stitch_data[edge_iter->element->island].stitchableCandidate = 1;
island_stitch_data[edge->element->island].stitchableCandidate = 1;
edge->flag |= STITCH_STITCHABLE_CANDIDATE;
@@ -785,16 +841,16 @@ static void stitch_set_face_preview_buffer_position(
/* setup face preview for all coincident uvs and their faces */
static void stitch_setup_face_preview_for_uv_group(
- UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
- PreviewPosition *preview_position)
+ UvElement *element, StitchStateContainer *ssc, StitchState *state,
+ IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
{
StitchPreviewer *preview = state->stitch_preview;
/* static island does not change so returning immediately */
- if (state->snap_islands && !state->midpoints && state->static_island == element->island)
+ if (ssc->snap_islands && !ssc->midpoints && ssc->static_island == element->island)
return;
- if (state->snap_islands) {
+ if (ssc->snap_islands) {
island_stitch_data[element->island].addedForPreview = 1;
}
@@ -807,11 +863,18 @@ static void stitch_setup_face_preview_for_uv_group(
/* checks if uvs are indeed stitchable and registers so that they can be shown in preview */
static void stitch_validate_uv_stitchability(
- UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
- PreviewPosition *preview_position)
+ UvElement *element, StitchStateContainer *ssc, StitchState *state,
+ IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
{
- UvElement *element_iter;
StitchPreviewer *preview = state->stitch_preview;
+
+ /* If not the active object, then it's unstitchable */
+ if (ssc->states[ssc->active_object_index] != state) {
+ preview->num_unstitchable++;
+ return;
+ }
+
+ UvElement *element_iter;
int vert_index;
BMLoop *l;
@@ -825,11 +888,11 @@ static void stitch_validate_uv_stitchability(
if (element_iter->separate) {
if (element_iter == element)
continue;
- if (stitch_check_uvs_state_stitchable(element, element_iter, state)) {
- if ((element_iter->island == state->static_island) || (element->island == state->static_island)) {
+ if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
+ if ((element_iter->island == ssc->static_island) || (element->island == ssc->static_island)) {
element->flag |= STITCH_STITCHABLE;
preview->num_stitchable++;
- stitch_setup_face_preview_for_uv_group(element, state, island_stitch_data, preview_position);
+ stitch_setup_face_preview_for_uv_group(element, ssc, state, island_stitch_data, preview_position);
return;
}
}
@@ -844,21 +907,36 @@ static void stitch_validate_uv_stitchability(
static void stitch_validate_edge_stitchability(
- UvEdge *edge, StitchState *state, IslandStitchData *island_stitch_data,
- PreviewPosition *preview_position)
+ UvEdge *edge, StitchStateContainer *ssc, StitchState *state,
+ IslandStitchData *island_stitch_data, PreviewPosition *preview_position)
{
- UvEdge *edge_iter = edge->first;
StitchPreviewer *preview = state->stitch_preview;
+ /* If not the active object, then it's unstitchable */
+ if (ssc->states[ssc->active_object_index] != state) {
+ preview->num_unstitchable++;
+ return;
+ }
+
+ UvEdge *edge_iter = edge->first;
+
for (; edge_iter; edge_iter = edge_iter->next) {
if (edge_iter == edge)
continue;
- if (stitch_check_edges_state_stitchable(edge, edge_iter, state)) {
- if ((edge_iter->element->island == state->static_island) || (edge->element->island == state->static_island)) {
+ if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) {
+ if ((edge_iter->element->island == ssc->static_island) || (edge->element->island == ssc->static_island)) {
edge->flag |= STITCH_STITCHABLE;
preview->num_stitchable++;
- stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv1], state, island_stitch_data, preview_position);
- stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv2], state, island_stitch_data, preview_position);
+ stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv1],
+ ssc,
+ state,
+ island_stitch_data,
+ preview_position);
+ stitch_setup_face_preview_for_uv_group(state->uvs[edge->uv2],
+ ssc,
+ state,
+ island_stitch_data,
+ preview_position);
return;
}
}
@@ -874,7 +952,7 @@ static void stitch_validate_edge_stitchability(
static void stitch_propagate_uv_final_position(
Scene *scene,
UvElement *element, int index, PreviewPosition *preview_position,
- UVVertAverage *final_position, StitchState *state,
+ UVVertAverage *final_position, StitchStateContainer *ssc, StitchState *state,
const bool final)
{
BMesh *bm = state->em->bm;
@@ -903,12 +981,12 @@ static void stitch_propagate_uv_final_position(
int face_preview_pos = preview_position[BM_elem_index_get(element_iter->l->f)].data_position;
if (face_preview_pos != STITCH_NO_PREVIEW) {
copy_v2_v2(preview->preview_polys + face_preview_pos + 2 * element_iter->loop_of_poly_index,
- final_position[index].uv);
+ final_position[index].uv);
}
}
/* end of calculations, keep only the selection flag */
- if ((!state->snap_islands) || ((!state->midpoints) && (element_iter->island == state->static_island))) {
+ if ((!ssc->snap_islands) || ((!ssc->midpoints) && (element_iter->island == ssc->static_island))) {
element_iter->flag &= STITCH_SELECTED;
}
@@ -918,18 +996,20 @@ static void stitch_propagate_uv_final_position(
}
/* main processing function. It calculates preview and final positions. */
-static int stitch_process_data(StitchState *state, Scene *scene, int final)
+static int stitch_process_data(
+ StitchStateContainer *ssc, StitchState *state, Scene *scene, int final)
{
int i;
StitchPreviewer *preview;
IslandStitchData *island_stitch_data = NULL;
- int previous_island = state->static_island;
+ int previous_island = ssc->static_island;
BMesh *bm = state->em->bm;
BMFace *efa;
BMIter iter;
UVVertAverage *final_position = NULL;
+ bool is_active_state = (state == ssc->states[ssc->active_object_index]);
- char stitch_midpoints = state->midpoints;
+ char stitch_midpoints = ssc->midpoints;
/* used to map uv indices to uvaverage indices for selection */
unsigned int *uvfinal_map = NULL;
/* per face preview position in preview buffer */
@@ -947,7 +1027,8 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
preview_position[i].data_position = STITCH_NO_PREVIEW;
}
- island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands, "stitch_island_data");
+ island_stitch_data = MEM_callocN(sizeof(*island_stitch_data) * state->element_map->totalIslands,
+ "stitch_island_data");
if (!island_stitch_data) {
return 0;
}
@@ -960,32 +1041,41 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
****************************************/
for (i = 0; i < state->selection_size; i++) {
- if (state->mode == STITCH_VERT) {
+ if (ssc->mode == STITCH_VERT) {
UvElement *element = (UvElement *)state->selection_stack[i];
- determine_uv_stitchability(element, state, island_stitch_data);
+ determine_uv_stitchability(element, ssc, state, island_stitch_data);
}
else {
UvEdge *edge = (UvEdge *)state->selection_stack[i];
- determine_uv_edge_stitchability(edge, state, island_stitch_data);
+ determine_uv_edge_stitchability(edge, ssc, state, island_stitch_data);
}
}
- /* set static island to one that is added for preview */
- state->static_island %= state->element_map->totalIslands;
- while (!(island_stitch_data[state->static_island].stitchableCandidate)) {
- state->static_island++;
- state->static_island %= state->element_map->totalIslands;
- /* this is entirely possible if for example limit stitching with no stitchable verts or no selection */
- if (state->static_island == previous_island)
- break;
+ /* remember stitchable candidates as places the 'I' button */
+ /* will stop at. */
+ for (int island_idx = 0; island_idx < state->element_map->totalIslands; island_idx++) {
+ state->island_is_stitchable[island_idx] = island_stitch_data[island_idx].stitchableCandidate ? true : false;
+ }
+
+ if (is_active_state) {
+ /* set static island to one that is added for preview */
+ ssc->static_island %= state->element_map->totalIslands;
+ while (!(island_stitch_data[ssc->static_island].stitchableCandidate)) {
+ ssc->static_island++;
+ ssc->static_island %= state->element_map->totalIslands;
+ /* this is entirely possible if for example limit stitching with no stitchable verts or no selection */
+ if (ssc->static_island == previous_island) {
+ break;
+ }
+ }
}
for (i = 0; i < state->selection_size; i++) {
- if (state->mode == STITCH_VERT) {
+ if (ssc->mode == STITCH_VERT) {
UvElement *element = (UvElement *)state->selection_stack[i];
if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
- stitch_validate_uv_stitchability(element, state, island_stitch_data, preview_position);
+ stitch_validate_uv_stitchability(element, ssc, state, island_stitch_data, preview_position);
}
else {
/* add to preview for unstitchable */
@@ -996,7 +1086,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
UvEdge *edge = (UvEdge *)state->selection_stack[i];
if (edge->flag & STITCH_STITCHABLE_CANDIDATE) {
edge->flag &= ~STITCH_STITCHABLE_CANDIDATE;
- stitch_validate_edge_stitchability(edge, state, island_stitch_data, preview_position);
+ stitch_validate_edge_stitchability(edge, ssc, state, island_stitch_data, preview_position);
}
else {
preview->num_unstitchable++;
@@ -1004,10 +1094,92 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
}
- /*****************************************
- * Setup preview for stitchable islands *
- *****************************************/
- if (state->snap_islands) {
+ /*********************************************************************
+ * Setup the stitchable & unstitchable preview buffers and fill *
+ * them with the appropriate data *
+ *********************************************************************/
+ if (!final) {
+ BMLoop *l;
+ MLoopUV *luv;
+ int stitchBufferIndex = 0, unstitchBufferIndex = 0;
+ int preview_size = (ssc->mode == STITCH_VERT) ? 2 : 4;
+ /* initialize the preview buffers */
+ preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size,
+ "stitch_preview_stitchable_data");
+ preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size,
+ "stitch_preview_unstitchable_data");
+
+ /* will cause cancel and freeing of all data structures so OK */
+ if (!preview->preview_stitchable || !preview->preview_unstitchable) {
+ return 0;
+ }
+
+ /* fill the appropriate preview buffers */
+ if (ssc->mode == STITCH_VERT) {
+ for (i = 0; i < state->total_separate_uvs; i++) {
+ UvElement *element = (UvElement *)state->uvs[i];
+ if (element->flag & STITCH_STITCHABLE) {
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
+
+ stitchBufferIndex++;
+ }
+ else if (element->flag & STITCH_SELECTED) {
+ l = element->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
+ unstitchBufferIndex++;
+ }
+ }
+ }
+ else {
+ for (i = 0; i < state->total_separate_edges; i++) {
+ UvEdge *edge = state->edges + i;
+ UvElement *element1 = state->uvs[edge->uv1];
+ UvElement *element2 = state->uvs[edge->uv2];
+
+ if (edge->flag & STITCH_STITCHABLE) {
+ l = element1->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv);
+
+ l = element2->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv);
+
+ stitchBufferIndex++;
+ BLI_assert(stitchBufferIndex <= preview->num_stitchable);
+ }
+ else if (edge->flag & STITCH_SELECTED) {
+ l = element1->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv);
+
+ l = element2->l;
+ luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
+ copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv);
+
+ unstitchBufferIndex++;
+ BLI_assert(unstitchBufferIndex <= preview->num_unstitchable);
+ }
+ }
+ }
+ }
+
+ if (ssc->states[ssc->active_object_index] != state) {
+ /* This is not the active object/state, exit here */
+ MEM_freeN(island_stitch_data);
+ MEM_freeN(preview_position);
+ return 1;
+ }
+
+ /****************************************
+ * Setup preview for stitchable islands *
+ ****************************************/
+ if (ssc->snap_islands) {
for (i = 0; i < state->element_map->totalIslands; i++) {
if (island_stitch_data[i].addedForPreview) {
int numOfIslandUVs = 0, j;
@@ -1022,26 +1194,26 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
/*********************************************************************
- * Setup the preview buffers and fill them with the appropriate data *
+ * Setup the remaining preview buffers and fill them with the *
+ * appropriate data *
*********************************************************************/
if (!final) {
BMIter liter;
BMLoop *l;
MLoopUV *luv;
unsigned int buffer_index = 0;
- int stitchBufferIndex = 0, unstitchBufferIndex = 0;
- int preview_size = (state->mode == STITCH_VERT) ? 2 : 4;
+
/* initialize the preview buffers */
- preview->preview_polys = (float *)MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, "tri_uv_stitch_prev");
- preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon), "tri_uv_stitch_prev");
- preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stitchable_data");
- preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size, "stitch_preview_unstitchable_data");
+ preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, "tri_uv_stitch_prev");
+ preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon),
+ "tri_uv_stitch_prev");
- preview->static_tris = (float *)MEM_mallocN(state->tris_per_island[state->static_island] * sizeof(float) * 6, "static_island_preview_tris");
+ preview->static_tris = MEM_mallocN(state->tris_per_island[ssc->static_island] * sizeof(float) * 6,
+ "static_island_preview_tris");
- preview->num_static_tris = state->tris_per_island[state->static_island];
+ preview->num_static_tris = state->tris_per_island[ssc->static_island];
/* will cause cancel and freeing of all data structures so OK */
- if (!preview->preview_polys || !preview->preview_stitchable || !preview->preview_unstitchable) {
+ if (!preview->preview_polys) {
return 0;
}
@@ -1062,7 +1234,8 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
}
- if (element->island == state->static_island) {
+ /* if this is the static_island on the active object */
+ if (element->island == ssc->static_island) {
BMLoop *fl = BM_FACE_FIRST_LOOP(efa);
MLoopUV *fuv = CustomData_bmesh_get(&bm->ldata, fl->head.data, CD_MLOOPUV);
@@ -1085,67 +1258,13 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
}
}
-
- /* fill the appropriate preview buffers */
- if (state->mode == STITCH_VERT) {
- for (i = 0; i < state->total_separate_uvs; i++) {
- UvElement *element = (UvElement *)state->uvs[i];
- if (element->flag & STITCH_STITCHABLE) {
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 2], luv->uv);
-
- stitchBufferIndex++;
- }
- else if (element->flag & STITCH_SELECTED) {
- l = element->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
-
- copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 2], luv->uv);
- unstitchBufferIndex++;
- }
- }
- }
- else {
- for (i = 0; i < state->total_separate_edges; i++) {
- UvEdge *edge = state->edges + i;
- UvElement *element1 = state->uvs[edge->uv1];
- UvElement *element2 = state->uvs[edge->uv2];
-
- if (edge->flag & STITCH_STITCHABLE) {
- l = element1->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4], luv->uv);
-
- l = element2->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex * 4 + 2], luv->uv);
-
- stitchBufferIndex++;
- BLI_assert(stitchBufferIndex <= preview->num_stitchable);
- }
- else if (edge->flag & STITCH_SELECTED) {
- l = element1->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4], luv->uv);
-
- l = element2->l;
- luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
- copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex * 4 + 2], luv->uv);
-
- unstitchBufferIndex++;
- BLI_assert(unstitchBufferIndex <= preview->num_unstitchable);
- }
- }
- }
}
/******************************************************
* Here we calculate the final coordinates of the uvs *
******************************************************/
- if (state->mode == STITCH_VERT) {
+ if (ssc->mode == STITCH_VERT) {
final_position = MEM_callocN(state->selection_size * sizeof(*final_position), "stitch_uv_average");
uvfinal_map = MEM_mallocN(state->element_map->totalUVs * sizeof(*uvfinal_map), "stitch_uv_final_map");
}
@@ -1155,7 +1274,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
/* first pass, calculate final position for stitchable uvs of the static island */
for (i = 0; i < state->selection_size; i++) {
- if (state->mode == STITCH_VERT) {
+ if (ssc->mode == STITCH_VERT) {
UvElement *element = state->selection_stack[i];
if (element->flag & STITCH_STITCHABLE) {
@@ -1171,21 +1290,21 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
copy_v2_v2(final_position[i].uv, luv->uv);
final_position[i].count = 1;
- if (state->snap_islands && element->island == state->static_island && !stitch_midpoints)
+ if (ssc->snap_islands && element->island == ssc->static_island && !stitch_midpoints)
continue;
element_iter = state->element_map->vert[BM_elem_index_get(l->v)];
for ( ; element_iter; element_iter = element_iter->next) {
if (element_iter->separate) {
- if (stitch_check_uvs_state_stitchable(element, element_iter, state)) {
+ if (stitch_check_uvs_state_stitchable(element, element_iter, ssc, state)) {
l = element_iter->l;
luv = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
if (stitch_midpoints) {
add_v2_v2(final_position[i].uv, luv->uv);
final_position[i].count++;
}
- else if (element_iter->island == state->static_island) {
+ else if (element_iter->island == ssc->static_island) {
/* if multiple uvs on the static island exist,
* last checked remains. to disambiguate we need to limit or use
* edge stitch */
@@ -1221,11 +1340,11 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
state->uvs[edge->uv1]->flag |= STITCH_STITCHABLE;
state->uvs[edge->uv2]->flag |= STITCH_STITCHABLE;
- if (state->snap_islands && edge->element->island == state->static_island && !stitch_midpoints)
+ if (ssc->snap_islands && edge->element->island == ssc->static_island && !stitch_midpoints)
continue;
for (edge_iter = edge->first; edge_iter; edge_iter = edge_iter->next) {
- if (stitch_check_edges_state_stitchable (edge, edge_iter, state)) {
+ if (stitch_check_edges_state_stitchable(edge, edge_iter, ssc, state)) {
l = state->uvs[edge_iter->uv1]->l;
luv1 = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_MLOOPUV);
l = state->uvs[edge_iter->uv2]->l;
@@ -1237,7 +1356,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
add_v2_v2(final_position[edge->uv2].uv, luv2->uv);
final_position[edge->uv2].count++;
}
- else if (edge_iter->element->island == state->static_island) {
+ else if (edge_iter->element->island == ssc->static_island) {
copy_v2_v2(final_position[edge->uv1].uv, luv1->uv);
copy_v2_v2(final_position[edge->uv2].uv, luv2->uv);
}
@@ -1248,7 +1367,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
/* take mean position here. For edge case, this can't be done inside the loop for shared uvverts */
- if (state->mode == STITCH_EDGE && stitch_midpoints) {
+ if (ssc->mode == STITCH_EDGE && stitch_midpoints) {
for (i = 0; i < state->total_separate_uvs; i++) {
final_position[i].uv[0] /= final_position[i].count;
final_position[i].uv[1] /= final_position[i].count;
@@ -1256,8 +1375,8 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
}
/* second pass, calculate island rotation and translation before modifying any uvs */
- if (state->snap_islands) {
- if (state->mode == STITCH_VERT) {
+ if (ssc->snap_islands) {
+ if (ssc->mode == STITCH_VERT) {
for (i = 0; i < state->selection_size; i++) {
UvElement *element = state->selection_stack[i];
@@ -1285,13 +1404,18 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
(state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
(state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
{
- stitch_island_calculate_edge_rotation(edge, state, final_position, uvfinal_map, island_stitch_data);
+ stitch_island_calculate_edge_rotation(edge,
+ ssc,
+ state,
+ final_position,
+ uvfinal_map,
+ island_stitch_data);
island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
}
}
/* clear seams of stitched edges */
- if (final && state->clear_seams) {
+ if (final && ssc->clear_seams) {
for (i = 0; i < state->total_separate_edges; i++) {
UvEdge *edge = state->edges + i;
if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
@@ -1306,7 +1430,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
UvElement *element = state->selection_stack[i];
if (!island_stitch_data[element->island].use_edge_rotation) {
if (element->flag & STITCH_STITCHABLE) {
- stitch_island_calculate_vert_rotation(element, state, island_stitch_data);
+ stitch_island_calculate_vert_rotation(element, ssc, state, island_stitch_data);
}
}
}
@@ -1336,13 +1460,13 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
UvEdge *edge = state->selection_stack[i];
if (edge->flag & STITCH_STITCHABLE) {
- stitch_island_calculate_edge_rotation(edge, state, final_position, NULL, island_stitch_data);
+ stitch_island_calculate_edge_rotation(edge, ssc, state, final_position, NULL, island_stitch_data);
island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
}
}
/* clear seams of stitched edges */
- if (final && state->clear_seams) {
+ if (final && ssc->clear_seams) {
for (i = 0; i < state->selection_size; i++) {
UvEdge *edge = state->selection_stack[i];
if (edge->flag & STITCH_STITCHABLE) {
@@ -1355,30 +1479,30 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
/* third pass, propagate changes to coincident uvs */
for (i = 0; i < state->selection_size; i++) {
- if (state->mode == STITCH_VERT) {
+ if (ssc->mode == STITCH_VERT) {
UvElement *element = state->selection_stack[i];
- stitch_propagate_uv_final_position(scene, element, i, preview_position, final_position, state, final);
+ stitch_propagate_uv_final_position(scene, element, i, preview_position, final_position, ssc, state, final);
}
else {
UvEdge *edge = state->selection_stack[i];
stitch_propagate_uv_final_position(
- scene, state->uvs[edge->uv1], edge->uv1, preview_position, final_position, state, final);
+ scene, state->uvs[edge->uv1], edge->uv1, preview_position, final_position, ssc, state, final);
stitch_propagate_uv_final_position(
- scene, state->uvs[edge->uv2], edge->uv2, preview_position, final_position, state, final);
+ scene, state->uvs[edge->uv2], edge->uv2, preview_position, final_position, ssc, state, final);
edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY);
}
}
/* final pass, calculate Island translation/rotation if needed */
- if (state->snap_islands) {
+ if (ssc->snap_islands) {
stitch_calculate_island_snapping(state, preview_position, preview, island_stitch_data, final);
}
MEM_freeN(final_position);
- if (state->mode == STITCH_VERT) {
+ if (ssc->mode == STITCH_VERT) {
MEM_freeN(uvfinal_map);
}
MEM_freeN(island_stitch_data);
@@ -1387,6 +1511,17 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
return 1;
}
+static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int final)
+{
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ if (!stitch_process_data(ssc, ssc->states[ob_index], scene, final)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
/* Stitch hash initialization functions */
static unsigned int uv_edge_hash(const void *key)
{
@@ -1471,13 +1606,13 @@ static void stitch_select_uv(UvElement *element, StitchState *state, int always_
}
}
-static void stitch_switch_selection_mode(StitchState *state)
+static void stitch_set_selection_mode(StitchState *state, const char from_stitch_mode)
{
void **old_selection_stack = state->selection_stack;
int old_selection_size = state->selection_size;
state->selection_size = 0;
- if (state->mode == STITCH_VERT) {
+ if (from_stitch_mode == STITCH_VERT) {
int i;
state->selection_stack = MEM_mallocN(state->total_separate_edges * sizeof(*state->selection_stack),
"stitch_new_edge_selection_stack");
@@ -1498,7 +1633,6 @@ static void stitch_switch_selection_mode(StitchState *state)
element->flag &= ~STITCH_SELECTED;
}
- state->mode = STITCH_EDGE;
}
else {
int i;
@@ -1515,12 +1649,26 @@ static void stitch_switch_selection_mode(StitchState *state)
edge->flag &= ~STITCH_SELECTED;
}
- state->mode = STITCH_VERT;
}
MEM_freeN(old_selection_stack);
}
-static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect)
+static void stitch_switch_selection_mode_all(StitchStateContainer *ssc)
+{
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ stitch_set_selection_mode(ssc->states[ob_index], ssc->mode);
+ }
+
+ if (ssc->mode == STITCH_VERT) {
+ ssc->mode = STITCH_EDGE;
+ }
+ else {
+ ssc->mode = STITCH_VERT;
+ }
+}
+
+static void stitch_calculate_edge_normal(
+ BMEditMesh *em, UvEdge *edge, float *normal, float aspect)
{
BMLoop *l1 = edge->element->l;
MLoopUV *luv1, *luv2;
@@ -1529,7 +1677,7 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no
luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV);
luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV);
- sub_v2_v2v2(tangent, luv2->uv, luv1->uv);
+ sub_v2_v2v2(tangent, luv2->uv, luv1->uv);
tangent[1] /= aspect;
@@ -1539,63 +1687,141 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no
normalize_v2(normal);
}
+/**
+ */
+static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float col[4])
+{
+ GPUBatch *batch = GPU_batch_create_ex(prim_type, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4fv(batch, "color", col);
+ GPU_batch_draw(batch);
+ GPU_batch_discard(batch);
+}
+
+/* TODO make things pretier : store batches inside StitchPreviewer instead of the bare verts pos */
static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
{
- int i, index = 0;
- StitchState *state = (StitchState *)arg;
- StitchPreviewer *stitch_preview = state->stitch_preview;
- glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
- glEnableClientState(GL_VERTEX_ARRAY);
+ StitchStateContainer *ssc = (StitchStateContainer *)arg;
- glEnable(GL_BLEND);
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ int j, index = 0;
+ unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
+ StitchState *state = ssc->states[ob_index];
+ StitchPreviewer *stitch_preview = state->stitch_preview;
+ GPUVertBuf *vbo, *vbo_line;
+ float col[4];
- UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_tris);
- glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_static_tris * 3);
+ static GPUVertFormat format = { 0 };
+ static unsigned int pos_id;
+ if (format.attr_len == 0) {
+ pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_polys);
- for (i = 0; i < stitch_preview->num_polys; i++) {
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- UI_ThemeColor4(TH_STITCH_PREVIEW_FACE);
- glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE);
- glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]);
-#if 0
- glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
- UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
- glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]);
-#endif
+ GPU_blend(true);
- index += stitch_preview->uvs_per_polygon[i];
- }
- glDisable(GL_BLEND);
+ /* Static Tris */
+ if (stitch_preview->static_tris) {
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_ACTIVE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_static_tris * 3);
+ for (int i = 0; i < stitch_preview->num_static_tris * 3; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->static_tris[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col);
+ }
- /* draw vert preview */
- if (state->mode == STITCH_VERT) {
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f);
+ /* Preview Polys */
+ if (stitch_preview->preview_polys) {
+ for (int i = 0; i < stitch_preview->num_polys; i++)
+ num_line += stitch_preview->uvs_per_polygon[i];
- UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
- glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
+ num_tri = num_line - 2 * stitch_preview->num_polys;
- UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
- glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable);
- }
- else {
- UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
- glDrawArrays(GL_LINES, 0, 2 * stitch_preview->num_stitchable);
+ /* we need to convert the polys into triangles / lines */
+ vbo = GPU_vertbuf_create_with_format(&format);
+ vbo_line = GPU_vertbuf_create_with_format(&format);
- UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
- glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
- glDrawArrays(GL_LINES, 0, 2 * stitch_preview->num_unstitchable);
- }
+ GPU_vertbuf_data_alloc(vbo, num_tri * 3);
+ GPU_vertbuf_data_alloc(vbo_line, num_line * 2);
+
+
+ for (int i = 0; i < stitch_preview->num_polys; i++) {
+ BLI_assert(stitch_preview->uvs_per_polygon[i] >= 3);
+
+ /* Start line */
+ GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
+ GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + 2]);
+
+ for (j = 1; j < stitch_preview->uvs_per_polygon[i] - 1; ++j) {
+ GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index]);
+ GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 0) * 2]);
+ GPU_vertbuf_attr_set(vbo, pos_id, tri_idx++, &stitch_preview->preview_polys[index + (j + 1) * 2]);
+
+ GPU_vertbuf_attr_set(vbo_line,
+ pos_id,
+ line_idx++,
+ &stitch_preview->preview_polys[index + (j + 0) * 2]);
+ GPU_vertbuf_attr_set(vbo_line,
+ pos_id,
+ line_idx++,
+ &stitch_preview->preview_polys[index + (j + 1) * 2]);
+ }
+
+ /* Closing line */
+ GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index]);
+ /* j = uvs_per_polygon[i] - 1*/
+ GPU_vertbuf_attr_set(vbo_line, pos_id, line_idx++, &stitch_preview->preview_polys[index + j * 2]);
+
+ index += stitch_preview->uvs_per_polygon[i] * 2;
+ }
+
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_FACE, col);
+ stitch_draw_vbo(vbo, GPU_PRIM_TRIS, col);
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_EDGE, col);
+ stitch_draw_vbo(vbo_line, GPU_PRIM_LINES, col);
+ }
+
+ GPU_blend(false);
+
+ /* draw stitch vert/lines preview */
+ if (ssc->mode == STITCH_VERT) {
+ GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f);
+
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable);
+ for (int i = 0; i < stitch_preview->num_stitchable; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col);
- glPopClientAttrib();
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable);
+ for (int i = 0; i < stitch_preview->num_unstitchable; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_POINTS, col);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_STITCHABLE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_stitchable * 2);
+ for (int i = 0; i < stitch_preview->num_stitchable * 2; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_stitchable[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_LINES, col);
+
+ UI_GetThemeColor4fv(TH_STITCH_PREVIEW_UNSTITCHABLE, col);
+ vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, stitch_preview->num_unstitchable * 2);
+ for (int i = 0; i < stitch_preview->num_unstitchable * 2; i++) {
+ GPU_vertbuf_attr_set(vbo, pos_id, i, &stitch_preview->preview_unstitchable[i * 2]);
+ }
+ stitch_draw_vbo(vbo, GPU_PRIM_LINES, col);
+ }
+ }
}
static UvEdge *uv_edge_get(BMLoop *l, StitchState *state)
@@ -1620,7 +1846,9 @@ static UvEdge *uv_edge_get(BMLoop *l, StitchState *state)
return BLI_ghash_lookup(state->edge_hash, &tmp_edge);
}
-static int stitch_init(bContext *C, wmOperator *op)
+static StitchState *stitch_init(
+ bContext *C, wmOperator *op,
+ StitchStateContainer *ssc, Object *obedit, StitchStateInit *state_init)
{
/* for fast edge lookup... */
GHash *edge_hash;
@@ -1638,46 +1866,16 @@ static int stitch_init(bContext *C, wmOperator *op)
StitchState *state;
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
- ARegion *ar = CTX_wm_region(C);
float aspx, aspy;
- Object *obedit = CTX_data_edit_object(C);
+
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (!ar)
- return 0;
-
- state = MEM_callocN(sizeof(StitchState), "stitch state");
-
- op->customdata = state;
+ state = MEM_callocN(sizeof(StitchState), "stitch state obj");
/* initialize state */
- state->use_limit = RNA_boolean_get(op->ptr, "use_limit");
- state->limit_dist = RNA_float_get(op->ptr, "limit");
+ state->obedit = obedit;
state->em = em;
- state->snap_islands = RNA_boolean_get(op->ptr, "snap_islands");
- state->static_island = RNA_int_get(op->ptr, "static_island");
- state->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
- state->clear_seams = RNA_boolean_get(op->ptr, "clear_seams");
- if (RNA_struct_property_is_set(op->ptr, "mode")) {
- state->mode = RNA_enum_get(op->ptr, "mode");
- }
- else {
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_VERTEX)
- state->mode = STITCH_VERT;
- else
- state->mode = STITCH_EDGE;
- }
- else {
- if (ts->uv_selectmode & UV_SELECT_VERTEX) {
- state->mode = STITCH_VERT;
- }
- else {
- state->mode = STITCH_EDGE;
- }
- }
- }
/* in uv synch selection, all uv's are visible */
if (ts->uv_flag & UV_SYNC_SELECTION) {
@@ -1688,16 +1886,12 @@ static int stitch_init(bContext *C, wmOperator *op)
}
if (!state->element_map) {
state_delete(state);
- return 0;
+ return NULL;
}
ED_uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy);
state->aspect = aspx / aspy;
- /* Entirely possible if redoing last operator that static island is bigger than total number of islands.
- * This ensures we get no hang in the island checking code in stitch_stitch_process_data. */
- state->static_island %= state->element_map->totalIslands;
-
/* Count 'unique' uvs */
for (i = 0; i < state->element_map->totalUVs; i++) {
if (state->element_map->buf[i].separate) {
@@ -1716,11 +1910,11 @@ static int stitch_init(bContext *C, wmOperator *op)
state->map = map = MEM_mallocN(sizeof(*map) * state->element_map->totalUVs, "uv_stitch_unique_map");
/* Allocate the edge stack */
edge_hash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
- all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "stitch_all_edges");
+ all_edges = MEM_mallocN(sizeof(*all_edges) * state->element_map->totalUVs, "ssc_edges");
if (!state->uvs || !map || !edge_hash || !all_edges) {
state_delete(state);
- return 0;
+ return NULL;
}
/* So that we can use this as index for the UvElements */
@@ -1789,7 +1983,7 @@ static int stitch_init(bContext *C, wmOperator *op)
/* I assume any system will be able to at least allocate an iterator :p */
if (!edges) {
state_delete(state);
- return 0;
+ return NULL;
}
state->total_separate_edges = total_edges;
@@ -1839,40 +2033,50 @@ static int stitch_init(bContext *C, wmOperator *op)
state->selection_size = 0;
/* Load old selection if redoing operator with different settings */
- if (RNA_struct_property_is_set(op->ptr, "selection")) {
+ if (state_init != NULL) {
int faceIndex, elementIndex;
UvElement *element;
enum StitchModes stored_mode = RNA_enum_get(op->ptr, "stored_mode");
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ int selected_count = state_init->uv_selected_count;
+
if (stored_mode == STITCH_VERT) {
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, "uv_stitch_selection_stack");
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs,
+ "uv_stitch_selection_stack");
- RNA_BEGIN (op->ptr, itemptr, "selection")
- {
- faceIndex = RNA_int_get(&itemptr, "face_index");
- elementIndex = RNA_int_get(&itemptr, "element_index");
+ while (selected_count--) {
+ faceIndex = state_init->to_select[selected_count].faceIndex;
+ elementIndex = state_init->to_select[selected_count].elementIndex;
efa = BM_face_at_index(em->bm, faceIndex);
- element = BM_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
+ element = BM_uv_element_get(state->element_map,
+ efa,
+ BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
stitch_select_uv(element, state, 1);
}
- RNA_END;
}
else {
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, "uv_stitch_selection_stack");
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges,
+ "uv_stitch_selection_stack");
- RNA_BEGIN (op->ptr, itemptr, "selection")
- {
+ while (selected_count--) {
UvEdge tmp_edge, *edge;
int uv1, uv2;
- faceIndex = RNA_int_get(&itemptr, "face_index");
- elementIndex = RNA_int_get(&itemptr, "element_index");
+ faceIndex = state_init->to_select[selected_count].faceIndex;
+ elementIndex = state_init->to_select[selected_count].elementIndex;
efa = BM_face_at_index(em->bm, faceIndex);
- element = BM_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
+ element = BM_uv_element_get(state->element_map,
+ efa,
+ BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, elementIndex));
uv1 = map[element - state->element_map->buf];
- element = BM_uv_element_get(state->element_map, efa, BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, (elementIndex + 1) % efa->len));
+ element = BM_uv_element_get(state->element_map,
+ efa,
+ BM_iter_at_index(NULL,
+ BM_LOOPS_OF_FACE,
+ efa,
+ (elementIndex + 1) % efa->len));
uv2 = map[element - state->element_map->buf];
if (uv1 < uv2) {
@@ -1888,21 +2092,17 @@ static int stitch_init(bContext *C, wmOperator *op)
stitch_select_edge(edge, state, true);
}
- RNA_END;
}
/* if user has switched the operator mode after operation, we need to convert
* the stored format */
- if (state->mode != stored_mode) {
- state->mode = stored_mode;
- stitch_switch_selection_mode(state);
+ if (ssc->mode != stored_mode) {
+ stitch_set_selection_mode(state, stored_mode);
}
- /* Clear the selection */
- RNA_collection_clear(op->ptr, "selection");
-
}
else {
- if (state->mode == STITCH_VERT) {
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs, "uv_stitch_selection_stack");
+ if (ssc->mode == STITCH_VERT) {
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_uvs,
+ "uv_stitch_selection_stack");
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -1916,7 +2116,8 @@ static int stitch_init(bContext *C, wmOperator *op)
}
}
else {
- state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, "uv_stitch_selection_stack");
+ state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges,
+ "uv_stitch_selection_stack");
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
@@ -1953,83 +2154,306 @@ static int stitch_init(bContext *C, wmOperator *op)
}
}
- if (!stitch_process_data(state, scene, false)) {
+ state->island_is_stitchable = MEM_callocN(sizeof(bool) * state->element_map->totalIslands, "stitch I stops");
+ if (!state->island_is_stitchable) {
+ state_delete(state);
+ return NULL;
+ }
+ if (!stitch_process_data(ssc, state, scene, false)) {
state_delete(state);
+ return NULL;
+ }
+
+ return state;
+}
+
+static bool goto_next_island(StitchStateContainer *ssc)
+{
+ StitchState *active_state = ssc->states[ssc->active_object_index];
+ StitchState *original_active_state = active_state;
+
+ int original_island = ssc->static_island;
+
+ do {
+ ssc->static_island++;
+ if (ssc->static_island >= active_state->element_map->totalIslands) {
+ /* go to next object */
+ ssc->active_object_index++;
+ ssc->active_object_index %= ssc->objects_len;
+
+ active_state = ssc->states[ssc->active_object_index];
+ ssc->static_island = 0;
+ }
+
+ if (active_state->island_is_stitchable[ssc->static_island]) {
+ /* We're at an island to make active */
+ return true;
+ }
+ } while (!(active_state == original_active_state &&
+ ssc->static_island == original_island));
+
+ return false;
+}
+
+static int stitch_init_all(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ if (!ar)
return 0;
+
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+
+ StitchStateContainer *ssc = MEM_callocN(sizeof(StitchStateContainer), "stitch collection");
+
+ op->customdata = ssc;
+
+ ssc->use_limit = RNA_boolean_get(op->ptr, "use_limit");
+ ssc->limit_dist = RNA_float_get(op->ptr, "limit");
+ ssc->snap_islands = RNA_boolean_get(op->ptr, "snap_islands");
+ ssc->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
+ ssc->clear_seams = RNA_boolean_get(op->ptr, "clear_seams");
+ ssc->active_object_index = RNA_int_get(op->ptr, "active_object_index");
+ ssc->static_island = 0;
+
+ if (RNA_struct_property_is_set(op->ptr, "mode")) {
+ ssc->mode = RNA_enum_get(op->ptr, "mode");
+ }
+ else {
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_VERTEX)
+ ssc->mode = STITCH_VERT;
+ else
+ ssc->mode = STITCH_EDGE;
+ }
+ else {
+ if (ts->uv_selectmode & UV_SELECT_VERTEX) {
+ ssc->mode = STITCH_VERT;
+ }
+ else {
+ ssc->mode = STITCH_EDGE;
+ }
+ }
}
- state->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, state, REGION_DRAW_POST_VIEW);
+ ssc->objects_len = 0;
+ ssc->states = NULL;
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, &objects_len);
+
+ if (objects_len == 0) {
+ MEM_freeN(objects);
+ state_delete_all(ssc);
+ return 0;
+ }
+
+ ssc->objects = MEM_callocN(sizeof(Object *) * objects_len, "Object *ssc->objects");
+ ssc->states = MEM_callocN(sizeof(StitchState *) * objects_len, "StitchState");
+ ssc->objects_len = 0;
+
+ int *objs_selection_count = NULL;
+ UvElementID *selected_uvs_arr = NULL;
+ StitchStateInit *state_init = NULL;
+
+ if (RNA_struct_property_is_set(op->ptr, "selection") &&
+ RNA_struct_property_is_set(op->ptr, "objects_selection_count"))
+ {
+ /* Retrieve list of selected UVs, one list contains all selected UVs
+ * for all objects. */
+
+ objs_selection_count = MEM_mallocN(sizeof(int *) * objects_len, "objects_selection_count");
+ RNA_int_get_array(op->ptr, "objects_selection_count", objs_selection_count);
+
+ int total_selected = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ total_selected += objs_selection_count[ob_index];
+ }
+
+ selected_uvs_arr = MEM_callocN(sizeof(UvElementID) * total_selected, "selected_uvs_arr");
+ int sel_idx = 0;
+ RNA_BEGIN (op->ptr, itemptr, "selection")
+ {
+ BLI_assert(sel_idx < total_selected);
+ selected_uvs_arr[sel_idx].faceIndex = RNA_int_get(&itemptr, "face_index");
+ selected_uvs_arr[sel_idx].elementIndex = RNA_int_get(&itemptr, "element_index");
+ sel_idx++;
+ }
+ RNA_END;
+
+ RNA_collection_clear(op->ptr, "selection");
+
+ state_init = MEM_callocN(sizeof(StitchStateInit), "UV_init_selected");
+ state_init->to_select = selected_uvs_arr;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ if (state_init != NULL) {
+ state_init->uv_selected_count = objs_selection_count[ob_index];
+ }
+
+ StitchState *stitch_state_ob = stitch_init(C, op, ssc, obedit, state_init);
+
+ if (state_init != NULL) {
+ /* Move pointer to beginning of next object's data. */
+ state_init->to_select += state_init->uv_selected_count;
+ }
+
+ if (stitch_state_ob) {
+ ssc->objects[ssc->objects_len] = obedit;
+ ssc->states[ssc->objects_len] = stitch_state_ob;
+ ssc->objects_len++;
+ }
+ }
+
+ MEM_freeN(objects);
+ MEM_SAFE_FREE(selected_uvs_arr);
+ MEM_SAFE_FREE(objs_selection_count);
+ MEM_SAFE_FREE(state_init);
+
+ if (ssc->objects_len == 0) {
+ state_delete_all(ssc);
+ return 0;
+ }
+
+ ssc->active_object_index %= ssc->objects_len;
+
+ ssc->static_island = RNA_int_get(op->ptr, "static_island");
+
+ StitchState *state = ssc->states[ssc->active_object_index];
+ ssc->static_island %= state->element_map->totalIslands;
+
+ /* If the initial active object doesn't have any stitchable islands */
+ /* then no active island will be seen in the UI. Make sure we're on */
+ /* a stitchable object and island. */
+ if (!state->island_is_stitchable[ssc->static_island]) {
+ goto_next_island(ssc);
+ state = ssc->states[ssc->active_object_index];
+ }
+
+ /* process active stitchobj again now that it can detect it's the active stitchobj */
+ stitch_process_data(ssc, state, scene, false);
+
+ stitch_update_header(ssc, C);
+
+ ssc->draw_handle = ED_region_draw_cb_activate(ar->type, stitch_draw, ssc, REGION_DRAW_POST_VIEW);
- stitch_update_header(state, C);
return 1;
}
static int stitch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- Object *obedit = CTX_data_edit_object(C);
- if (!stitch_init(C, op))
+ if (!stitch_init_all(C, op))
return OPERATOR_CANCELLED;
WM_event_add_modal_handler(C, op);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ StitchStateContainer *ssc = (StitchStateContainer *)op->customdata;
+
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ StitchState *state = ssc->states[ob_index];
+ Object *obedit = state->obedit;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+
return OPERATOR_RUNNING_MODAL;
}
static void stitch_exit(bContext *C, wmOperator *op, int finished)
{
- StitchState *state;
- Scene *scene;
- SpaceImage *sima;
+ Scene *scene = CTX_data_scene(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
ScrArea *sa = CTX_wm_area(C);
- Object *obedit;
-
- scene = CTX_data_scene(C);
- obedit = CTX_data_edit_object(C);
- sima = CTX_wm_space_image(C);
- state = (StitchState *)op->customdata;
+ StitchStateContainer *ssc = (StitchStateContainer *)op->customdata;
if (finished) {
- int i;
-
- RNA_float_set(op->ptr, "limit", state->limit_dist);
- RNA_boolean_set(op->ptr, "use_limit", state->use_limit);
- RNA_boolean_set(op->ptr, "snap_islands", state->snap_islands);
- RNA_int_set(op->ptr, "static_island", state->static_island);
- RNA_boolean_set(op->ptr, "midpoint_snap", state->midpoints);
- RNA_enum_set(op->ptr, "mode", state->mode);
- RNA_enum_set(op->ptr, "stored_mode", state->mode);
-
- /* Store selection for re-execution of stitch */
+ RNA_float_set(op->ptr, "limit", ssc->limit_dist);
+ RNA_boolean_set(op->ptr, "use_limit", ssc->use_limit);
+ RNA_boolean_set(op->ptr, "snap_islands", ssc->snap_islands);
+ RNA_boolean_set(op->ptr, "midpoint_snap", ssc->midpoints);
+ RNA_boolean_set(op->ptr, "clear_seams", ssc->clear_seams);
+ RNA_enum_set(op->ptr, "mode", ssc->mode);
+ RNA_enum_set(op->ptr, "stored_mode", ssc->mode);
+ RNA_int_set(op->ptr, "active_object_index", ssc->active_object_index);
+
+ RNA_int_set(op->ptr, "static_island", ssc->static_island);
+
+ int *objs_selection_count = NULL;
+ objs_selection_count = MEM_mallocN(sizeof(int *) * ssc->objects_len, "objects_selection_count");
+
+ /* Store selection for re-execution of stitch
+ * - Store all selected UVs in "selection"
+ * - Store how many each object has in "objects_selection_count". */
RNA_collection_clear(op->ptr, "selection");
- for (i = 0; i < state->selection_size; i++) {
- UvElement *element;
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ StitchState *state = ssc->states[ob_index];
+ Object *obedit = state->obedit;
+
PointerRNA itemptr;
- if (state->mode == STITCH_VERT) {
- element = state->selection_stack[i];
- }
- else {
- element = ((UvEdge *)state->selection_stack[i])->element;
+ for (int i = 0; i < state->selection_size; i++) {
+ UvElement *element;
+
+ if (ssc->mode == STITCH_VERT) {
+ element = state->selection_stack[i];
+ }
+ else {
+ element = ((UvEdge *)state->selection_stack[i])->element;
+ }
+ RNA_collection_add(op->ptr, "selection", &itemptr);
+
+ RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f));
+ RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index);
}
- RNA_collection_add(op->ptr, "selection", &itemptr);
+ uvedit_live_unwrap_update(sima, scene, obedit);
- RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->l->f));
- RNA_int_set(&itemptr, "element_index", element->loop_of_poly_index);
+ objs_selection_count[ob_index] = state->selection_size;
}
- uvedit_live_unwrap_update(sima, scene, obedit);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "objects_selection_count");
+ RNA_def_property_array(prop, ssc->objects_len);
+ RNA_int_set_array(op->ptr, "objects_selection_count", objs_selection_count);
+ MEM_freeN(objs_selection_count);
}
if (sa)
- ED_area_headerprint(sa, NULL);
+ ED_workspace_status_text(C, NULL);
+
+ ED_region_draw_cb_exit(CTX_wm_region(C)->type, ssc->draw_handle);
+
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- ED_region_draw_cb_exit(CTX_wm_region(C)->type, state->draw_handle);
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ StitchState *state = ssc->states[ob_index];
+ Object *obedit = state->obedit;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+
+ state_delete_all(ssc);
- state_delete(state);
op->customdata = NULL;
}
@@ -2044,9 +2468,9 @@ static int stitch_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- if (!stitch_init(C, op))
+ if (!stitch_init_all(C, op))
return OPERATOR_CANCELLED;
- if (stitch_process_data((StitchState *)op->customdata, scene, 1)) {
+ if (stitch_process_data_all((StitchStateContainer *)op->customdata, scene, 1)) {
stitch_exit(C, op, 1);
return OPERATOR_FINISHED;
}
@@ -2056,7 +2480,8 @@ static int stitch_exec(bContext *C, wmOperator *op)
}
}
-static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, StitchState *state)
+static StitchState *stitch_select(
+ bContext *C, Scene *scene, const wmEvent *event, StitchStateContainer *ssc)
{
/* add uv under mouse to processed uv's */
float co[2];
@@ -2066,36 +2491,54 @@ static void stitch_select(bContext *C, Scene *scene, const wmEvent *event, Stitc
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- if (state->mode == STITCH_VERT) {
- if (uv_find_nearest_vert(
- scene, ima, state->em, co, 0.0f, &hit))
- {
+ if (ssc->mode == STITCH_VERT) {
+ if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
/* Add vertex to selection, deselect all common uv's of vert other
* than selected and update the preview. This behavior was decided so that
* you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */
+ /* find StitchState from hit->ob */
+ StitchState *state = NULL;
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ if (hit.ob == ssc->objects[ob_index]) {
+ state = ssc->states[ob_index];
+ break;
+ }
+ }
+
/* This works due to setting of tmp in find nearest uv vert */
UvElement *element = BM_uv_element_get(state->element_map, hit.efa, hit.l);
stitch_select_uv(element, state, false);
+ return state;
}
}
- else {
- if (uv_find_nearest_edge(
- scene, ima, state->em, co, &hit))
- {
- UvEdge *edge = uv_edge_get(hit.l, state);
- stitch_select_edge(edge, state, false);
+ else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) {
+ /* find StitchState from hit->ob */
+ StitchState *state = NULL;
+ for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
+ if (hit.ob == ssc->objects[ob_index]) {
+ state = ssc->states[ob_index];
+ break;
+ }
}
+
+ UvEdge *edge = uv_edge_get(hit.l, state);
+ stitch_select_edge(edge, state, false);
+
+ return state;
}
+
+ return NULL;
}
static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- StitchState *state;
+ StitchStateContainer *ssc;
Scene *scene = CTX_data_scene(C);
- state = (StitchState *)op->customdata;
+ ssc = op->customdata;
+ StitchState *active_state = ssc->states[ssc->active_object_index];
switch (event->type) {
case MIDDLEMOUSE:
@@ -2107,22 +2550,10 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case LEFTMOUSE:
- if (event->shift && (U.flag & USER_LMOUSESELECT)) {
- if (event->val == KM_PRESS) {
- stitch_select(C, scene, event, state);
-
- if (!stitch_process_data(state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
- }
- break;
- }
- ATTR_FALLTHROUGH;
case PADENTER:
case RETKEY:
if (event->val == KM_PRESS) {
- if (stitch_process_data(state, scene, true)) {
+ if (stitch_process_data(ssc, active_state, scene, true)) {
stitch_exit(C, op, 1);
return OPERATOR_FINISHED;
}
@@ -2138,8 +2569,8 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
case PADPLUSKEY:
case WHEELUPMOUSE:
if (event->val == KM_PRESS && event->alt) {
- state->limit_dist += 0.01f;
- if (!stitch_process_data(state, scene, false)) {
+ ssc->limit_dist += 0.01f;
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
stitch_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -2152,9 +2583,9 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
case PADMINUS:
case WHEELDOWNMOUSE:
if (event->val == KM_PRESS && event->alt) {
- state->limit_dist -= 0.01f;
- state->limit_dist = MAX2(0.01f, state->limit_dist);
- if (!stitch_process_data(state, scene, false)) {
+ ssc->limit_dist -= 0.01f;
+ ssc->limit_dist = MAX2(0.01f, ssc->limit_dist);
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
stitch_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -2167,8 +2598,8 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Use Limit (Default off) */
case LKEY:
if (event->val == KM_PRESS) {
- state->use_limit = !state->use_limit;
- if (!stitch_process_data(state, scene, false)) {
+ ssc->use_limit = !ssc->use_limit;
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
stitch_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -2178,12 +2609,23 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
case IKEY:
if (event->val == KM_PRESS) {
- state->static_island++;
- state->static_island %= state->element_map->totalIslands;
+ /* Move to next island and maybe next object */
- if (!stitch_process_data(state, scene, false)) {
- stitch_cancel(C, op);
- return OPERATOR_CANCELLED;
+ if (goto_next_island(ssc)) {
+ StitchState *new_active_state = ssc->states[ssc->active_object_index];
+
+ /* active_state is the original active state */
+ if (active_state != new_active_state) {
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (!stitch_process_data(ssc, new_active_state, scene, false)) {
+ stitch_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
}
break;
}
@@ -2191,8 +2633,8 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MKEY:
if (event->val == KM_PRESS) {
- state->midpoints = !state->midpoints;
- if (!stitch_process_data(state, scene, false)) {
+ ssc->midpoints = !ssc->midpoints;
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
stitch_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -2205,10 +2647,10 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
stitch_cancel(C, op);
return OPERATOR_CANCELLED;
}
- if (event->val == KM_PRESS && !(U.flag & USER_LMOUSESELECT)) {
- stitch_select(C, scene, event, state);
+ if (event->val == KM_PRESS) {
+ StitchState *selected_state = stitch_select(C, scene, event, ssc);
- if (!stitch_process_data(state, scene, false)) {
+ if (selected_state && !stitch_process_data(ssc, selected_state, scene, false)) {
stitch_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -2219,8 +2661,8 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* snap islands on/off */
case SKEY:
if (event->val == KM_PRESS) {
- state->snap_islands = !state->snap_islands;
- if (!stitch_process_data(state, scene, false)) {
+ ssc->snap_islands = !ssc->snap_islands;
+ if (!stitch_process_data(ssc, active_state, scene, false)) {
stitch_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -2233,9 +2675,9 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* switch between edge/vertex mode */
case TABKEY:
if (event->val == KM_PRESS) {
- stitch_switch_selection_mode(state);
+ stitch_switch_selection_mode_all(ssc);
- if (!stitch_process_data(state, scene, false)) {
+ if (!stitch_process_data_all(ssc, scene, false)) {
stitch_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -2247,8 +2689,9 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* if updated settings, renew feedback message */
- stitch_update_header(state, C);
+ stitch_update_header(ssc, C);
ED_region_tag_redraw(CTX_wm_region(C));
+
return OPERATOR_RUNNING_MODAL;
}
@@ -2284,16 +2727,24 @@ void UV_OT_stitch(wmOperatorType *ot)
"Limit distance in normalized coordinates", 0.0, FLT_MAX);
RNA_def_int(ot->srna, "static_island", 0, 0, INT_MAX, "Static Island",
"Island that stays in place when stitching islands", 0, INT_MAX);
+ RNA_def_int(ot->srna, "active_object_index", 0, 0, INT_MAX, "Active Object",
+ "Index of the active object", 0, INT_MAX);
RNA_def_boolean(ot->srna, "midpoint_snap", 0, "Snap At Midpoint",
"UVs are stitched at midpoint instead of at static island");
RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams",
"Clear seams of stitched edges");
RNA_def_enum(ot->srna, "mode", stitch_modes, STITCH_VERT, "Operation Mode",
"Use vertex or edge stitching");
- prop = RNA_def_enum(ot->srna, "stored_mode", stitch_modes, STITCH_VERT, "Stored Operation Mode",
- "Use vertex or edge stitching");
+ prop = RNA_def_enum(ot->srna, "stored_mode", stitch_modes, STITCH_VERT, "Stored Operation Mode",
+ "Use vertex or edge stitching");
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_collection_runtime(ot->srna, "selection", &RNA_SelectedUvElement, "Selection", "");
/* Selection should not be editable or viewed in toolbar */
RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ /* test should not be editable or viewed in toolbar */
+ prop = RNA_def_int_array(ot->srna, "objects_selection_count", 1, NULL, 0, INT_MAX, "objects_selection_count",
+ "objects_selection_count", 0, INT_MAX);
+ RNA_def_property_array(prop, 6);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 088ed42b0c0..9a7fd97bdf3 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -55,12 +55,15 @@
#include "BKE_subsurf.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
#include "PIL_time.h"
@@ -100,9 +103,8 @@ static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subs
*r_use_subsurf = subsurf;
}
-static bool ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
+static bool ED_uvedit_ensure_uvs(bContext *C, Scene *UNUSED(scene), Object *obedit)
{
- Main *bmain = CTX_data_main(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter;
@@ -116,7 +118,7 @@ static bool ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
if (ED_uvedit_test(obedit))
return 1;
- if (em && em->bm->totface && !CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY))
+ if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV))
ED_mesh_uv_texture_add(obedit->data, NULL, true);
if (!ED_uvedit_test(obedit))
@@ -146,9 +148,6 @@ static bool ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
}
}
- if (ima)
- ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL);
-
/* select new UV's (ignore UV_SYNC_SELECTION in this case) */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMIter liter;
@@ -200,7 +199,22 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit)
return false;
}
-void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, float *aspy)
+static bool uvedit_have_selection_multi(
+ Scene *scene, Object **objects, const uint objects_len, bool implicit)
+{
+ bool have_select = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (uvedit_have_selection(scene, em, implicit)) {
+ have_select = true;
+ break;
+ }
+ }
+ return have_select;
+}
+
+void ED_uvedit_get_aspect(Scene *UNUSED(scene), Object *ob, BMesh *bm, float *aspx, float *aspy)
{
bool sloppy = true;
bool selected = false;
@@ -210,13 +224,7 @@ void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, floa
efa = BM_mesh_active_face_get(bm, sloppy, selected);
if (efa) {
- if (BKE_scene_use_new_shading_nodes(scene)) {
- ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
- }
- else {
- MTexPoly *tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY);
- ima = tf->tpage;
- }
+ ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
ED_image_get_uv_aspect(ima, NULL, aspx, aspy);
}
@@ -257,9 +265,11 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
param_face_add(handle, key, i, vkeys, co, uv, pin, select);
}
-static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
- const bool implicit, const bool fill, const bool sel,
- const bool correct_aspect)
+/* See: construct_param_handle_multi to handle multiple objects at once. */
+static ParamHandle *construct_param_handle(
+ Scene *scene, Object *ob, BMesh *bm,
+ const bool implicit, const bool fill, const bool sel,
+ const bool correct_aspect)
{
ParamHandle *handle;
BMFace *efa;
@@ -323,6 +333,89 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
return handle;
}
+/**
+ * Version of #construct_param_handle_single that handles multiple objects.
+ */
+static ParamHandle *construct_param_handle_multi(
+ Scene *scene, Object **objects, const uint objects_len,
+ const bool implicit, const bool fill, const bool sel,
+ const bool correct_aspect)
+{
+ ParamHandle *handle;
+ BMFace *efa;
+ BMLoop *l;
+ BMEdge *eed;
+ BMIter iter, liter;
+ int i;
+
+
+ handle = param_construct_begin();
+
+ if (correct_aspect) {
+ Object *ob = objects[0];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ float aspx, aspy;
+
+ ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
+ if (aspx != aspy) {
+ param_aspect_ratio(handle, aspx, aspy);
+ }
+ }
+
+ /* we need the vert indices */
+ EDBM_mesh_elem_index_ensure_multi(objects, objects_len, BM_VERT);
+
+ int offset = 0;
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+
+ if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
+ continue;
+ }
+
+ if (implicit) {
+ bool is_loopsel = false;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ is_loopsel = true;
+ break;
+ }
+ }
+ if (is_loopsel == false) {
+ continue;
+ }
+ }
+
+ construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
+ }
+
+ if (!implicit) {
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
+ ParamKey vkeys[2];
+ vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
+ vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
+ param_edge_set_seam(handle, vkeys);
+ }
+ }
+ }
+ offset += bm->totface;
+ }
+
+ param_construct_end(handle, fill, implicit);
+
+ return handle;
+}
+
static void texface_from_original_index(BMFace *efa, int index, float **uv, ParamBool *pin, ParamBool *select,
Scene *scene, const int cd_loop_uv_offset)
@@ -403,7 +496,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
smd.subdivType = smd_real->subdivType;
initialDerived = CDDM_from_editbmesh(em, false, false);
- derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd,
+ derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd, scene,
NULL, SUBSURF_IN_EDIT_MODE);
initialDerived->release(initialDerived);
@@ -505,8 +598,8 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
typedef struct MinStretch {
Scene *scene;
- Object *obedit;
- BMEditMesh *em;
+ Object **objects_edit;
+ uint objects_len;
ParamHandle *handle;
float blend;
double lasttime;
@@ -517,24 +610,28 @@ typedef struct MinStretch {
static bool minimize_stretch_init(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
MinStretch *ms;
const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
bool implicit = true;
- if (!uvedit_have_selection(scene, em, implicit)) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, implicit)) {
+ MEM_freeN(objects);
return false;
}
ms = MEM_callocN(sizeof(MinStretch), "MinStretch");
ms->scene = scene;
- ms->obedit = obedit;
- ms->em = em;
+ ms->objects_edit = objects;
+ ms->objects_len = objects_len;
ms->blend = RNA_float_get(op->ptr, "blend");
ms->iterations = RNA_int_get(op->ptr, "iterations");
ms->i = 0;
- ms->handle = construct_param_handle(scene, obedit, em->bm, implicit, fill_holes, 1, 1);
+ ms->handle = construct_param_handle_multi(scene, objects, objects_len, implicit, fill_holes, true, true);
ms->lasttime = PIL_check_seconds_timer();
param_stretch_begin(ms->handle);
@@ -550,6 +647,9 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
{
MinStretch *ms = op->customdata;
ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
param_stretch_blend(ms->handle, ms->blend);
param_stretch_iter(ms->handle);
@@ -563,15 +663,24 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
param_flush(ms->handle);
if (sa) {
- BLI_snprintf(str, sizeof(str),
- IFACE_("Minimize Stretch. Blend %.2f (Press + and -, or scroll wheel to set)"), ms->blend);
- ED_area_headerprint(sa, str);
+ BLI_snprintf(str, sizeof(str), IFACE_("Minimize Stretch. Blend %.2f"), ms->blend);
+ ED_area_status_text(sa, str);
+ ED_workspace_status_text(C, IFACE_("Press + and -, or scroll wheel to set blending"));
}
ms->lasttime = PIL_check_seconds_timer();
- DAG_id_tag_update(ms->obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ms->obedit->data);
+ for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
+ Object *obedit = ms->objects_edit[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totfacesel == 0)) {
+ continue;
+ }
+
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
}
}
@@ -579,9 +688,13 @@ static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
{
MinStretch *ms = op->customdata;
ScrArea *sa = CTX_wm_area(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+
+ ED_area_status_text(sa, NULL);
+ ED_workspace_status_text(C, NULL);
- if (sa)
- ED_area_headerprint(sa, NULL);
if (ms->timer)
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer);
@@ -593,9 +706,19 @@ static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
param_stretch_end(ms->handle);
param_delete(ms->handle);
- DAG_id_tag_update(ms->obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ms->obedit->data);
+ for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
+ Object *obedit = ms->objects_edit[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (synced_selection && (em->bm->totfacesel == 0)) {
+ continue;
+ }
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+
+ MEM_freeN(ms->objects_edit);
MEM_freeN(ms);
op->customdata = NULL;
}
@@ -714,6 +837,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* ******************** Pack Islands operator **************** */
+
void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect, bool do_rotate)
{
ParamHandle *handle;
@@ -723,14 +847,29 @@ void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected,
param_delete(handle);
}
+void ED_uvedit_pack_islands_multi(
+ Scene *scene, Object **objects, const uint objects_len,
+ bool selected, bool correct_aspect, bool do_rotate)
+{
+ ParamHandle *handle;
+ handle = construct_param_handle_multi(
+ scene, objects, objects_len, true, false, selected, correct_aspect);
+ param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
+ param_flush(handle);
+ param_delete(handle);
+}
+
static int pack_islands_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool do_rotate = RNA_boolean_get(op->ptr, "rotate");
- if (!uvedit_have_selection(scene, em, true)) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, true)) {
+ MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
@@ -739,10 +878,15 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
else
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
- ED_uvedit_pack_islands(scene, obedit, em->bm, true, true, do_rotate);
+ ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, do_rotate);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -770,23 +914,37 @@ void UV_OT_pack_islands(wmOperatorType *ot)
static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ToolSettings *ts = scene->toolsettings;
+ const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
+ const bool implicit = true;
ParamHandle *handle;
- bool implicit = true;
- if (!uvedit_have_selection(scene, em, implicit)) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, CTX_wm_view3d(C), &objects_len);
+
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, implicit)) {
+ MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
- handle = construct_param_handle(scene, obedit, em->bm, implicit, 0, 1, 1);
+ handle = construct_param_handle_multi(scene, objects, objects_len, implicit, false, true, true);
param_average(handle);
param_flush(handle);
param_delete(handle);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ if (synced_selection && (em->bm->totvertsel == 0)) {
+ continue;
+ }
+
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -806,10 +964,14 @@ void UV_OT_average_islands_scale(wmOperatorType *ot)
/**************** Live Unwrap *****************/
-static ParamHandle *liveHandle = NULL;
+static struct {
+ ParamHandle **handles;
+ uint len, len_alloc;
+} g_live_unwrap = {NULL};
void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
{
+ ParamHandle *handle = NULL;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool abf = (scene->toolsettings->unwrapper == 0);
const bool fillholes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0;
@@ -822,29 +984,49 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
}
if (use_subsurf)
- liveHandle = construct_param_handle_subsurfed(scene, obedit, em, fillholes, false, true);
+ handle = construct_param_handle_subsurfed(scene, obedit, em, fillholes, false, true);
else
- liveHandle = construct_param_handle(scene, obedit, em->bm, false, fillholes, false, true);
+ handle = construct_param_handle(scene, obedit, em->bm, false, fillholes, false, true);
+
+ param_lscm_begin(handle, PARAM_TRUE, abf);
- param_lscm_begin(liveHandle, PARAM_TRUE, abf);
+ /* Create or increase size of g_live_unwrap.handles array */
+ if (g_live_unwrap.handles == NULL) {
+ g_live_unwrap.len_alloc = 32;
+ g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc, "uvedit_live_unwrap_liveHandles");
+ g_live_unwrap.len = 0;
+ }
+ if (g_live_unwrap.len >= g_live_unwrap.len_alloc) {
+ g_live_unwrap.len_alloc *= 2;
+ g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles, sizeof(ParamHandle *) * g_live_unwrap.len_alloc);
+ }
+ g_live_unwrap.handles[g_live_unwrap.len] = handle;
+ g_live_unwrap.len++;
}
void ED_uvedit_live_unwrap_re_solve(void)
{
- if (liveHandle) {
- param_lscm_solve(liveHandle);
- param_flush(liveHandle);
+ if (g_live_unwrap.handles) {
+ for (int i = 0; i < g_live_unwrap.len; i++) {
+ param_lscm_solve(g_live_unwrap.handles[i]);
+ param_flush(g_live_unwrap.handles[i]);
+ }
}
}
void ED_uvedit_live_unwrap_end(short cancel)
{
- if (liveHandle) {
- param_lscm_end(liveHandle);
- if (cancel)
- param_flush_restore(liveHandle);
- param_delete(liveHandle);
- liveHandle = NULL;
+ if (g_live_unwrap.handles) {
+ for (int i = 0; i < g_live_unwrap.len; i++) {
+ param_lscm_end(g_live_unwrap.handles[i]);
+ if (cancel)
+ param_flush_restore(g_live_unwrap.handles[i]);
+ param_delete(g_live_unwrap.handles[i]);
+ }
+ MEM_freeN(g_live_unwrap.handles);
+ g_live_unwrap.handles = NULL;
+ g_live_unwrap.len = 0;
+ g_live_unwrap.len_alloc = 0;
}
}
@@ -855,7 +1037,7 @@ void ED_uvedit_live_unwrap(Scene *scene, Object *obedit)
if (scene->toolsettings->edge_mode_live_unwrap &&
CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV))
{
- ED_unwrap_lscm(scene, obedit, false); /* unwrap all not just sel */
+ ED_unwrap_lscm(scene, obedit, false, false); /* unwrap all not just sel */
}
}
@@ -903,7 +1085,7 @@ static void uv_map_transform_center(
float r_bounds[2][3])
{
/* only operates on the edit object - this is all that's needed now */
- const int around = (v3d) ? v3d->around : V3D_AROUND_CENTER_BOUNDS;
+ const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
float bounds[2][3];
INIT_MINMAX(bounds[0], bounds[1]);
@@ -925,7 +1107,7 @@ static void uv_map_transform_center(
case V3D_AROUND_CURSOR: /* cursor center */
{
invert_m4_m4(ob->imat, ob->obmat);
- mul_v3_m4v3(r_center, ob->imat, ED_view3d_cursor3d_get(scene, v3d));
+ mul_v3_m4v3(r_center, ob->imat, scene->cursor.location);
break;
}
case V3D_AROUND_ACTIVE:
@@ -953,12 +1135,12 @@ static void uv_map_transform_center(
}
}
-static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Object *ob,
- float upangledeg, float sideangledeg, float radius)
+static void uv_map_rotation_matrix_ex(
+ float result[4][4], RegionView3D *rv3d, Object *ob,
+ float upangledeg, float sideangledeg, float radius, float offset[4])
{
float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
float sideangle = 0.0f, upangle = 0.0f;
- int k;
/* get rotation of the current view matrix */
if (rv3d)
@@ -967,15 +1149,14 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec
unit_m4(viewmatrix);
/* but shifting */
- for (k = 0; k < 4; k++)
- viewmatrix[3][k] = 0.0f;
+ copy_v4_fl(viewmatrix[3], 0.0f);
/* get rotation of the current object matrix */
copy_m4_m4(rotobj, ob->obmat);
/* but shifting */
- for (k = 0; k < 4; k++)
- rotobj[3][k] = 0.0f;
+ add_v4_v4(rotobj[3], offset);
+ rotobj[3][3] = 0.0f;
zero_m4(rotup);
zero_m4(rotside);
@@ -1001,6 +1182,14 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec
mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
}
+static void uv_map_rotation_matrix(
+ float result[4][4], RegionView3D *rv3d, Object *ob,
+ float upangledeg, float sideangledeg, float radius)
+{
+ float offset[4] = {0};
+ uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset);
+}
+
static void uv_map_transform(bContext *C, wmOperator *op, float rotmat[4][4])
{
/* context checks are messy here, making it work in both 3d view and uv editor */
@@ -1108,7 +1297,7 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot)
"Scale UV coordinates to bounds after unwrapping");
}
-static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOperator *op)
+static void uv_map_clip_correct_multi(Scene *scene, Object **objects, uint objects_len, wmOperator *op)
{
BMFace *efa;
BMLoop *l;
@@ -1119,25 +1308,46 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
const bool clip_to_bounds = RNA_boolean_get(op->ptr, "clip_to_bounds");
const bool scale_to_bounds = RNA_boolean_get(op->ptr, "scale_to_bounds");
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ INIT_MINMAX2(min, max);
- /* correct for image aspect ratio */
- if (correct_aspect)
- correct_uv_aspect(scene, ob, em);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
- if (scale_to_bounds) {
- INIT_MINMAX2(min, max);
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ /* correct for image aspect ratio */
+ if (correct_aspect)
+ correct_uv_aspect(scene, ob, em);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- minmax_v2v2_v2(min, max, luv->uv);
+ if (scale_to_bounds) {
+ /* find uv limits */
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ minmax_v2v2_v2(min, max, luv->uv);
+ }
}
}
+ else if (clip_to_bounds) {
+ /* clipping and wrapping */
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ CLAMP(luv->uv[0], 0.0f, 1.0f);
+ CLAMP(luv->uv[1], 0.0f, 1.0f);
+ }
+ }
+ }
+ }
+ if (scale_to_bounds) {
/* rescale UV to be in 1/1 */
dx = (max[0] - min[0]);
dy = (max[1] - min[1]);
@@ -1147,37 +1357,36 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
if (dy > 0.0f)
dy = 1.0f / dy;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- luv->uv[0] = (luv->uv[0] - min[0]) * dx;
- luv->uv[1] = (luv->uv[1] - min[1]) * dy;
- }
- }
- }
- else if (clip_to_bounds) {
- /* clipping and wrapping */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- CLAMP(luv->uv[0], 0.0f, 1.0f);
- CLAMP(luv->uv[1], 0.0f, 1.0f);
+ BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->uv[0] = (luv->uv[0] - min[0]) * dx;
+ luv->uv[1] = (luv->uv[1] - min[1]) * dy;
+ }
}
}
}
}
+static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op)
+{
+ uv_map_clip_correct_multi(scene, &ob, 1, op);
+}
+
/* ******************** Unwrap operator **************** */
/* assumes UV Map is checked, doesn't run update funcs */
-void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
+void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel, const bool pack)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
ParamHandle *handle;
@@ -1198,42 +1407,85 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
param_lscm_end(handle);
param_average(handle);
- param_pack(handle, scene->toolsettings->uvcalc_margin, false);
+
+ if (pack) {
+ param_pack(handle, scene->toolsettings->uvcalc_margin, false);
+ }
param_flush(handle);
param_delete(handle);
}
+enum {
+ UNWRAP_ERROR_NONUNIFORM = (1 << 0),
+ UNWRAP_ERROR_NEGATIVE = (1 << 1),
+};
+
static int unwrap_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
int method = RNA_enum_get(op->ptr, "method");
const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
- bool use_subsurf_final;
- float obsize[3];
bool implicit = false;
+ int reported_errors = 0;
+ /* We will report an error unless at least one object has the subsurf modifier in the right place. */
+ bool subsurf_error = use_subsurf;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- if (!uvedit_have_selection(scene, em, implicit)) {
+ if (!uvedit_have_selection_multi(scene, objects, objects_len, implicit)) {
+ MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
/* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ float obsize[3];
+ bool use_subsurf_final;
+
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
+
+ if (subsurf_error) {
+ /* Double up the check here but better keep ED_unwrap_lscm interface simple and not
+ * pass operator for warning append. */
+ modifier_unwrap_state(obedit, scene, &use_subsurf_final);
+ if (use_subsurf_final) {
+ subsurf_error = false;
+ }
+ }
+
+ if (reported_errors & (UNWRAP_ERROR_NONUNIFORM | UNWRAP_ERROR_NEGATIVE)) {
+ continue;
+ }
+
+ mat4_to_size(obsize, obedit->obmat);
+ if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) {
+ if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) {
+ BKE_report(op->reports, RPT_INFO,
+ "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh");
+ reported_errors |= UNWRAP_ERROR_NONUNIFORM;
+ }
+ }
+ else if (is_negative_m4(obedit->obmat)) {
+ if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) {
+ BKE_report(op->reports, RPT_INFO,
+ "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
+ reported_errors |= UNWRAP_ERROR_NEGATIVE;
+ }
+ }
}
- mat4_to_size(obsize, obedit->obmat);
- if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f))
- BKE_report(op->reports, RPT_INFO,
- "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh");
- else if (is_negative_m4(obedit->obmat))
- BKE_report(op->reports, RPT_INFO,
- "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
+ if (subsurf_error) {
+ BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap");
+ }
/* remember last method for live unwrap */
if (RNA_struct_property_is_set(op->ptr, "method"))
@@ -1256,17 +1508,17 @@ static int unwrap_exec(bContext *C, wmOperator *op)
if (use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF;
else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF;
- /* double up the check here but better keep ED_unwrap_lscm interface simple and not
- * pass operator for warning append */
- modifier_unwrap_state(obedit, scene, &use_subsurf_final);
- if (use_subsurf != use_subsurf_final)
- BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap");
-
/* execute unwrap */
- ED_unwrap_lscm(scene, obedit, true);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ ED_unwrap_lscm(scene, obedit, true, false);
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+
+ ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, true);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1321,9 +1573,8 @@ static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
static int uv_from_view_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -1333,69 +1584,114 @@ static int uv_from_view_exec(bContext *C, wmOperator *op)
BMIter iter, liter;
MLoopUV *luv;
float rotmat[4][4];
+ float objects_pos_offset[4];
+ bool changed_multi = false;
- int cd_loop_uv_offset;
+ const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic");
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
- }
+ /* Note: objects that aren't touched are set to NULL (to skip clipping). */
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
- cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ if (use_orthographic) {
+ /* Calculate average object position. */
+ float objects_pos_avg[4] = {0};
- if (RNA_boolean_get(op->ptr, "orthographic")) {
- uv_map_rotation_matrix(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]);
+ }
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ mul_v4_fl(objects_pos_avg, 1.0f / objects_len);
+ negate_v4_v4(objects_pos_offset, objects_pos_avg);
+ }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat);
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool changed = false;
+
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
}
- }
- else if (camera) {
- const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds");
- struct ProjCameraInfo *uci = BLI_uvproject_camera_info(v3d->camera, obedit->obmat,
- camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f,
- camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f);
- if (uci) {
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (use_orthographic) {
+ uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset);
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- BLI_uvproject_from_camera(luv->uv, l->v->co, uci);
+ BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat);
}
+ changed = true;
}
+ }
+ else if (camera) {
+ const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds");
+ struct ProjCameraInfo *uci = BLI_uvproject_camera_info(
+ v3d->camera, obedit->obmat,
+ camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f,
+ camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f);
+
+ if (uci) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BLI_uvproject_from_camera(luv->uv, l->v->co, uci);
+ }
+ changed = true;
+ }
- MEM_freeN(uci);
+ MEM_freeN(uci);
+ }
}
- }
- else {
- copy_m4_m4(rotmat, obedit->obmat);
+ else {
+ copy_m4_m4(rotmat, obedit->obmat);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- BLI_uvproject_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BLI_uvproject_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
+ }
+ changed = true;
}
}
+
+ if (changed) {
+ changed_multi = true;
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ else {
+ ARRAY_DELETE_REORDER_LAST(objects, ob_index, 1, objects_len);
+ objects_len -= 1;
+ ob_index -= 1;
+ }
}
- uv_map_clip_correct(scene, obedit, em, op);
+ if (changed_multi) {
+ uv_map_clip_correct_multi(scene, objects, objects_len, op);
+ }
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ MEM_freeN(objects);
- return OPERATOR_FINISHED;
+ if (changed_multi) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static bool uv_from_view_poll(bContext *C)
@@ -1435,18 +1731,31 @@ void UV_OT_project_from_view(wmOperatorType *ot)
static int reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Mesh *me = (Mesh *)obedit->data;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
- }
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ Mesh *me = (Mesh *)obedit->data;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- ED_mesh_uv_loop_reset(C, me);
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
+
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ ED_mesh_uv_loop_reset(C, me);
+
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1481,7 +1790,7 @@ static void uv_sphere_project(float target[2], float source[3], float center[3],
target[0] -= 1.0f;
}
-static void uv_map_mirror(BMEditMesh *em, BMFace *efa, MTexPoly *UNUSED(tf))
+static void uv_map_mirror(BMEditMesh *em, BMFace *efa)
{
BMLoop *l;
BMIter liter;
@@ -1513,46 +1822,53 @@ static void uv_map_mirror(BMEditMesh *em, BMFace *efa, MTexPoly *UNUSED(tf))
static int sphere_project_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
View3D *v3d = CTX_wm_view3d(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MTexPoly *tf;
- MLoopUV *luv;
- float center[3], rotmat[4][4];
- int cd_loop_uv_offset;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
- uv_map_transform(C, op, rotmat);
- uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ float center[3], rotmat[4][4];
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ uv_map_transform(C, op, rotmat);
+ uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
- uv_sphere_project(luv->uv, l->v->co, center, rotmat);
- }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- uv_map_mirror(em, efa, tf);
- }
+ uv_sphere_project(luv->uv, l->v->co, center, rotmat);
+ }
- uv_map_clip_correct(scene, obedit, em, op);
+ uv_map_mirror(em, efa);
+ }
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ uv_map_clip_correct(scene, obedit, op);
+
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1594,46 +1910,53 @@ static void uv_cylinder_project(float target[2], float source[3], float center[3
static int cylinder_project_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
View3D *v3d = CTX_wm_view3d(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MTexPoly *tf;
- MLoopUV *luv;
- float center[3], rotmat[4][4];
- int cd_loop_uv_offset;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
- uv_map_transform(C, op, rotmat);
- uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ float center[3], rotmat[4][4];
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
- continue;
+ uv_map_transform(C, op, rotmat);
+ uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
+ continue;
- uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
- }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
- uv_map_mirror(em, efa, tf);
- }
+ uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
+ }
- uv_map_clip_correct(scene, obedit, em, op);
+ uv_map_mirror(em, efa);
+ }
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ uv_map_clip_correct(scene, obedit, op);
+
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -1663,7 +1986,6 @@ void ED_uvedit_unwrap_cube_project(BMesh *bm, float cube_size, bool use_select,
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- /* MTexPoly *tf; */ /* UNUSED */
MLoopUV *luv;
float loc[3];
int cox, coy;
@@ -1701,40 +2023,57 @@ static int cube_project_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
- float cube_size = RNA_property_float_get(op->ptr, prop_cube_size);
- float center[3];
- float bounds[2][3];
- float (*bounds_buf)[3] = NULL;
+ const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size);
- /* add uvs if they don't exist yet */
- if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
- return OPERATOR_CANCELLED;
- }
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!RNA_property_is_set(op->ptr, prop_cube_size)) {
- bounds_buf = bounds;
- }
+ if (em->bm->totfacesel == 0) {
+ continue;
+ }
- uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf);
+ /* add uvs if they don't exist yet */
+ if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
+ continue;
+ }
- /* calculate based on bounds */
- if (bounds_buf) {
- float dims[3];
- sub_v3_v3v3(dims, bounds[1], bounds[0]);
- cube_size = max_fff(UNPACK3(dims));
- cube_size = cube_size ? 2.0f / cube_size : 1.0f;
- RNA_property_float_set(op->ptr, prop_cube_size, cube_size);
- }
+ float bounds[2][3];
+ float (*bounds_buf)[3] = NULL;
- ED_uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
+ if (!RNA_property_is_set(op->ptr, prop_cube_size)) {
+ bounds_buf = bounds;
+ }
- uv_map_clip_correct(scene, obedit, em, op);
+ float center[3];
+ uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf);
+
+ /* calculate based on bounds */
+ float cube_size = cube_size_init;
+ if (bounds_buf) {
+ float dims[3];
+ sub_v3_v3v3(dims, bounds[1], bounds[0]);
+ cube_size = max_fff(UNPACK3(dims));
+ cube_size = cube_size ? 2.0f / cube_size : 1.0f;
+ if (ob_index == 0) {
+ /* This doesn't fit well with, multiple objects. */
+ RNA_property_float_set(op->ptr, prop_cube_size, cube_size);
+ }
+ }
+
+ ED_uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ uv_map_clip_correct(scene, obedit, op);
+
+ DEG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index f6b7efe978c..183eaf595ed 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -392,8 +392,8 @@ set(SRC
intern/scene_graph/NodeGroup.h
intern/scene_graph/NodeLight.cpp
intern/scene_graph/NodeLight.h
- intern/scene_graph/NodeSceneRenderLayer.cpp
- intern/scene_graph/NodeSceneRenderLayer.h
+ intern/scene_graph/NodeViewLayer.cpp
+ intern/scene_graph/NodeViewLayer.h
intern/scene_graph/NodeShape.cpp
intern/scene_graph/NodeShape.h
intern/scene_graph/NodeTransform.cpp
@@ -557,6 +557,7 @@ set(INC
../blenkernel
../blenlib
../blentranslation
+ ../depsgraph
../imbuf
../makesdna
../makesrna
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index a6382010ca7..58f1c343235 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
struct Render;
+struct RenderLayer;
struct Material;
struct FreestyleConfig;
struct FreestyleLineStyle;
@@ -50,13 +51,13 @@ extern struct FreestyleGlobals g_freestyle;
void FRS_initialize(void);
void FRS_set_context(struct bContext *C);
void FRS_read_file(struct bContext *C);
-int FRS_is_freestyle_enabled(struct SceneRenderLayer *srl);
+int FRS_is_freestyle_enabled(struct ViewLayer *view_layer);
void FRS_init_stroke_renderer(struct Render *re);
void FRS_begin_stroke_rendering(struct Render *re);
-struct Render *FRS_do_stroke_rendering(struct Render *re, struct SceneRenderLayer *srl, int render);
+struct Render *FRS_do_stroke_rendering(struct Render *re, struct ViewLayer *view_layer, int render);
void FRS_end_stroke_rendering(struct Render *re);
void FRS_free_view_map_cache(void);
-void FRS_composite_result(struct Render *re, struct SceneRenderLayer *srl, struct Render *freestyle_render);
+void FRS_composite_result(struct Render *re, struct ViewLayer *view_layer, struct Render *freestyle_render);
void FRS_exit(void);
/* FreestyleConfig.linesets */
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 03dc5f67d43..5ae04698a73 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -40,7 +40,7 @@ extern "C" {
#include "../scene_graph/NodeDrawingStyle.h"
#include "../scene_graph/NodeShape.h"
#include "../scene_graph/NodeTransform.h"
-#include "../scene_graph/NodeSceneRenderLayer.h"
+#include "../scene_graph/NodeViewLayer.h"
#include "../scene_graph/ScenePrettyPrinter.h"
#include "../scene_graph/VertexRep.h"
@@ -232,9 +232,9 @@ bool Controller::hitViewMapCache()
return false;
}
-int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
+int Controller::LoadMesh(Render *re, ViewLayer *view_layer)
{
- BlenderFileLoader loader(re, srl);
+ BlenderFileLoader loader(re, view_layer);
loader.setRenderMonitor(_pRenderMonitor);
@@ -301,7 +301,7 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
}
cam->setProjectionMatrix(proj);
_RootNode->AddChild(cam);
- _RootNode->AddChild(new NodeSceneRenderLayer(*re->scene, *srl));
+ _RootNode->AddChild(new NodeViewLayer(*re->scene, *view_layer));
sceneHashFunc.reset();
//blenderScene->accept(sceneHashFunc);
diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h
index 154edaf1e53..0304c18b8a6 100644
--- a/source/blender/freestyle/intern/application/Controller.h
+++ b/source/blender/freestyle/intern/application/Controller.h
@@ -68,7 +68,7 @@ public:
//soc
void init_options();
- int LoadMesh(Render *re, SceneRenderLayer *srl);
+ int LoadMesh(Render *re, ViewLayer *view_layer);
int Load3DSFile(const char *iFileName);
void CloseFile();
void ComputeViewMap();
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 7248bde0d10..a42e59ddb2a 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -32,16 +32,16 @@
namespace Freestyle {
-BlenderFileLoader::BlenderFileLoader(Render *re, SceneRenderLayer *srl)
+BlenderFileLoader::BlenderFileLoader(Render *re, ViewLayer *view_layer)
{
_re = re;
- _srl = srl;
+ _view_layer = view_layer;
_Scene = NULL;
_numFacesRead = 0;
#if 0
_minEdgeSize = DBL_MAX;
#endif
- _smooth = (srl->freestyleConfig.flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) != 0;
+ _smooth = (view_layer->freestyle_config.flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) != 0;
_pRenderMonitor = NULL;
}
@@ -52,8 +52,6 @@ BlenderFileLoader::~BlenderFileLoader()
NodeGroup *BlenderFileLoader::Load()
{
- ObjectInstanceRen *obi;
-
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "\n=== Importing triangular meshes into Blender ===" << endl;
}
@@ -81,6 +79,11 @@ NodeGroup *BlenderFileLoader::Load()
_z_offset = 0.f;
}
+ ViewLayer *view_layer = (ViewLayer*)BLI_findstring(&_re->scene->view_layers, _view_layer->name, offsetof(ViewLayer, name));
+ Depsgraph *depsgraph = DEG_graph_new(_re->scene, view_layer, DAG_EVAL_RENDER);
+
+ BKE_scene_graph_update_tagged(depsgraph, _re->main);
+
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Frustum: l " << _viewplane_left << " r " << _viewplane_right
@@ -90,34 +93,35 @@ NodeGroup *BlenderFileLoader::Load()
#endif
int id = 0;
- unsigned cnt = 1;
- unsigned cntStep = (unsigned)ceil(0.01f * _re->totinstance);
- for (obi = (ObjectInstanceRen *)_re->instancetable.first; obi; obi = obi->next) {
- if (_pRenderMonitor) {
- if (_pRenderMonitor->testBreak())
- break;
- if (cnt % cntStep == 0) {
- stringstream ss;
- ss << "Freestyle: Mesh loading " << (100 * cnt / _re->totinstance) << "%";
- _pRenderMonitor->setInfo(ss.str());
- _pRenderMonitor->progress((float)cnt / _re->totinstance);
- }
- cnt++;
+
+ DEG_OBJECT_ITER_BEGIN(
+ depsgraph, ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+ {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
+ break;
}
- if (!(obi->lay & _srl->lay))
- continue;
- char *name = obi->ob->id.name;
- //printf("%c%c:%s\n", name[0], name[1], name+2);
- //print_m4("obi->mat", obi->mat);
+ bool apply_modifiers = false;
+ bool calc_undeformed = false;
+ Mesh *mesh = BKE_mesh_new_from_object(depsgraph,
+ _re->main,
+ _re->scene,
+ ob,
+ apply_modifiers,
+ calc_undeformed);
- if (obi->obr->totvlak > 0) {
- insertShapeNode(obi, ++id);
- }
- else if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "Warning: " << (name + 2) << " is not a vlak-based object (ignored)" << endl;
+ if (mesh) {
+ insertShapeNode(ob, mesh, ++id);
+ BKE_libblock_free_ex(_re->main, &mesh->id, true, false);
}
}
+ DEG_OBJECT_ITER_END;
+
+ DEG_graph_free(depsgraph);
// Return the built scene.
return _Scene;
@@ -365,95 +369,86 @@ int BlenderFileLoader::testDegenerateTriangle(float v1[3], float v2[3], float v3
return 0;
}
-// Checks if edge rotation (if necessary) can prevent the given quad from
-// being decomposed into a degenerate triangle
-bool BlenderFileLoader::testEdgeRotation(float v1[3], float v2[3], float v3[3], float v4[3])
+static bool testEdgeMark(Mesh *me, FreestyleEdge *fed, const MLoopTri *lt, int i)
{
- if (testDegenerateTriangle(v1, v2, v3) == 2 || testDegenerateTriangle(v1, v3, v4) == 2) {
- if (testDegenerateTriangle(v1, v2, v4) == 2 || testDegenerateTriangle(v2, v3, v4) == 2) {
-#if 0
- if (G.debug & G_DEBUG_FREESTYLE) {
- printf("BlenderFileLoader::testEdgeRotation: edge rotation is unsuccessful.\n");
- }
-#endif
- return false;
- }
- return true;
+ MLoop *mloop = &me->mloop[lt->tri[i]];
+ MLoop *mloop_next = &me->mloop[lt->tri[(i+1)%3]];
+ MEdge *medge = &me->medge[mloop->e];
+
+ if (!ELEM(mloop_next->v, medge->v1, medge->v2)) {
+ /* Not an edge in the original mesh before triangulation. */
+ return false;
}
- return false;
+
+ return (fed[mloop->e].flag & FREESTYLE_EDGE_MARK) != 0;
}
-void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
+void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
{
- ObjectRen *obr = obi->obr;
- char *name = obi->ob->id.name + 2;
+ char *name = ob->id.name + 2;
+
+ // Compute loop triangles
+ int tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *mlooptri = (MLoopTri*)MEM_malloc_arrayN(tottri, sizeof(*mlooptri), __func__);
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly,
+ me->mvert,
+ me->totloop, me->totpoly,
+ mlooptri);
+
+ // Compute loop normals
+ BKE_mesh_calc_normals_split(me);
+ float (*lnors)[3] = NULL;
+
+ if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
+ lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
+ }
- // We parse vlak nodes and count the number of faces after the clipping by
- // the near and far view planes is applied (Note: mesh vertices are in the
- // camera coordinate system).
- VlakRen *vlr = NULL;
+ // Get other mesh data
+ MVert *mvert = me->mvert;
+ MLoop *mloop = me->mloop;
+ MPoly *mpoly = me->mpoly;
+ FreestyleEdge *fed = (FreestyleEdge*)CustomData_get_layer(&me->edata, CD_FREESTYLE_EDGE);
+ FreestyleFace *ffa = (FreestyleFace*)CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
+
+ // Compute matrix including camera transform
+ float obmat[4][4], nmat[4][4];
+ mul_m4_m4m4(obmat, _re->viewmat, ob->obmat);
+ invert_m4_m4(nmat, obmat);
+ transpose_m4(nmat);
+
+ // We count the number of triangles after the clipping by the near and far view
+ // planes is applied (Note: mesh vertices are in the camera coordinate system).
unsigned numFaces = 0;
- float v1[3], v2[3], v3[3], v4[3];
- float n1[3], n2[3], n3[3], n4[3], facenormal[3];
- int clip_1[3], clip_2[3];
- int wire_material = 0;
- for (int a = 0; a < obr->totvlak; a++) {
- if ((a & 255) == 0)
- vlr = obr->vlaknodes[a>>8].vlak;
- else
- vlr++;
- if (vlr->mat->mode & MA_ONLYCAST)
- continue;
- if (vlr->mat->material_type == MA_TYPE_WIRE) {
- wire_material = 1;
- continue;
- }
- copy_v3_v3(v1, vlr->v1->co);
- copy_v3_v3(v2, vlr->v2->co);
- copy_v3_v3(v3, vlr->v3->co);
- if (vlr->v4)
- copy_v3_v3(v4, vlr->v4->co);
- if (obi->flag & R_TRANSFORMED) {
- mul_m4_v3(obi->mat, v1);
- mul_m4_v3(obi->mat, v2);
- mul_m4_v3(obi->mat, v3);
- if (vlr->v4)
- mul_m4_v3(obi->mat, v4);
- }
+ float v1[3], v2[3], v3[3];
+ float n1[3], n2[3], n3[3], facenormal[3];
+ int clip[3];
+ for (int a = 0; a < tottri; a++) {
+ const MLoopTri *lt = &mlooptri[a];
+
+ copy_v3_v3(v1, mvert[mloop[lt->tri[0]].v].co);
+ copy_v3_v3(v2, mvert[mloop[lt->tri[1]].v].co);
+ copy_v3_v3(v3, mvert[mloop[lt->tri[2]].v].co);
+
+ mul_m4_v3(obmat, v1);
+ mul_m4_v3(obmat, v2);
+ mul_m4_v3(obmat, v3);
+
v1[2] += _z_offset;
v2[2] += _z_offset;
v3[2] += _z_offset;
- if (vlr->v4)
- v4[2] += _z_offset;
-#if 0
- print_v3("v1", v1);
- print_v3("v2", v2);
- print_v3("v3", v3);
- if (vlr->v4)
- print_v3("v4", v4);
-#endif
- if (!vlr->v4 || !testEdgeRotation(v1, v2, v3, v4)) {
- numFaces += countClippedFaces(v1, v2, v3, clip_1);
- if (vlr->v4)
- numFaces += countClippedFaces(v1, v3, v4, clip_2);
- }
- else {
- numFaces += countClippedFaces(v1, v2, v4, clip_1);
- numFaces += countClippedFaces(v2, v3, v4, clip_2);
- }
- }
- if (wire_material) {
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "Warning: Object " << name << " has wire materials (ignored)" << endl;
- }
+
+ numFaces += countClippedFaces(v1, v2, v3, clip);
}
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "numFaces " << numFaces << endl;
}
#endif
- if (numFaces == 0)
+ if (numFaces == 0) {
+ MEM_freeN(mlooptri);
return;
+ }
// We allocate memory for the meshes to be imported
NodeGroup *currentMesh = new NodeGroup;
@@ -496,107 +491,62 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
// We parse the vlak nodes again and import meshes while applying the clipping
// by the near and far view planes.
- int p;
- for (p = 0; p < obr->totvlak; ++p) { // we parse the faces of the mesh
- if ((p & 255) == 0)
- vlr = obr->vlaknodes[p>>8].vlak;
- else
- vlr++;
- if ((vlr->mat->mode & MA_ONLYCAST) || vlr->mat->material_type == MA_TYPE_WIRE)
- continue;
- copy_v3_v3(v1, vlr->v1->co);
- copy_v3_v3(v2, vlr->v2->co);
- copy_v3_v3(v3, vlr->v3->co);
- if (vlr->v4)
- copy_v3_v3(v4, vlr->v4->co);
- if (obi->flag & R_TRANSFORMED) {
- mul_m4_v3(obi->mat, v1);
- mul_m4_v3(obi->mat, v2);
- mul_m4_v3(obi->mat, v3);
- if (vlr->v4)
- mul_m4_v3(obi->mat, v4);
- }
+ for (int a = 0; a < tottri; a++) {
+ const MLoopTri *lt = &mlooptri[a];
+ const MPoly *mp = &mpoly[lt->poly];
+ Material *mat = give_current_material(ob, mp->mat_nr + 1);
+
+ copy_v3_v3(v1, mvert[mloop[lt->tri[0]].v].co);
+ copy_v3_v3(v2, mvert[mloop[lt->tri[1]].v].co);
+ copy_v3_v3(v3, mvert[mloop[lt->tri[2]].v].co);
+
+ mul_m4_v3(obmat, v1);
+ mul_m4_v3(obmat, v2);
+ mul_m4_v3(obmat, v3);
+
v1[2] += _z_offset;
v2[2] += _z_offset;
v3[2] += _z_offset;
- if (vlr->v4)
- v4[2] += _z_offset;
- if (_smooth && (vlr->flag & R_SMOOTH)) {
- copy_v3_v3(n1, vlr->v1->n);
- copy_v3_v3(n2, vlr->v2->n);
- copy_v3_v3(n3, vlr->v3->n);
- if (vlr->v4)
- copy_v3_v3(n4, vlr->v4->n);
- if (obi->flag & R_TRANSFORMED) {
- mul_m3_v3(obi->nmat, n1);
- mul_m3_v3(obi->nmat, n2);
- mul_m3_v3(obi->nmat, n3);
- normalize_v3(n1);
- normalize_v3(n2);
- normalize_v3(n3);
- if (vlr->v4) {
- mul_m3_v3(obi->nmat, n4);
- normalize_v3(n4);
- }
- }
+
+ if (_smooth && (mp->flag & ME_SMOOTH) && lnors) {
+ copy_v3_v3(n1, lnors[lt->tri[0]]);
+ copy_v3_v3(n2, lnors[lt->tri[1]]);
+ copy_v3_v3(n3, lnors[lt->tri[2]]);
+
+ mul_mat3_m4_v3(nmat, n1);
+ mul_mat3_m4_v3(nmat, n2);
+ mul_mat3_m4_v3(nmat, n3);
+
+ normalize_v3(n1);
+ normalize_v3(n2);
+ normalize_v3(n3);
}
else {
- RE_vlakren_get_normal(_re, obi, vlr, facenormal);
-#ifndef NDEBUG
- /* test if normals are inverted in rendering [T39669] */
- float tnor[3];
- if (vlr->v4)
- normal_quad_v3(tnor, v4, v3, v2, v1);
- else
- normal_tri_v3(tnor, v3, v2, v1);
- BLI_assert(dot_v3v3(tnor, facenormal) > 0.0f);
-#endif
+ normal_tri_v3(facenormal, v3, v2, v1);
+
copy_v3_v3(n1, facenormal);
copy_v3_v3(n2, facenormal);
copy_v3_v3(n3, facenormal);
- if (vlr->v4)
- copy_v3_v3(n4, facenormal);
}
- unsigned int numTris_1, numTris_2;
- bool edge_rotation;
- if (!vlr->v4 || !testEdgeRotation(v1, v2, v3, v4)) {
- numTris_1 = countClippedFaces(v1, v2, v3, clip_1);
- numTris_2 = (!vlr->v4) ? 0 : countClippedFaces(v1, v3, v4, clip_2);
- edge_rotation = false;
- }
- else {
- numTris_1 = countClippedFaces(v1, v2, v4, clip_1);
- numTris_2 = countClippedFaces(v2, v3, v4, clip_2);
- edge_rotation = true;
- if (G.debug & G_DEBUG_FREESTYLE) {
- printf("BlenderFileLoader::insertShapeNode: edge rotation is performed.\n");
- }
- }
- if (numTris_1 == 0 && numTris_2 == 0)
+ unsigned int numTris = countClippedFaces(v1, v2, v3, clip);
+ if (numTris == 0)
continue;
- bool fm, em1, em2, em3, em4;
- fm = (vlr->freestyle_face_mark) != 0;
- em1 = (vlr->freestyle_edge_mark & R_EDGE_V1V2) != 0;
- em2 = (vlr->freestyle_edge_mark & R_EDGE_V2V3) != 0;
- if (!vlr->v4) {
- em3 = (vlr->freestyle_edge_mark & R_EDGE_V3V1) != 0;
- em4 = false;
- }
- else {
- em3 = (vlr->freestyle_edge_mark & R_EDGE_V3V4) != 0;
- em4 = (vlr->freestyle_edge_mark & R_EDGE_V4V1) != 0;
+
+ bool fm = (ffa) ? (ffa[lt->poly].flag & FREESTYLE_FACE_MARK) != 0 : false;
+ bool em1 = false, em2 = false, em3 = false;
+
+ if (fed) {
+ em1 = testEdgeMark(me, fed, lt, 0);
+ em2 = testEdgeMark(me, fed, lt, 1);
+ em3 = testEdgeMark(me, fed, lt, 2);
}
- Material *mat = vlr->mat;
if (mat) {
tmpMat.setLine(mat->line_col[0], mat->line_col[1], mat->line_col[2], mat->line_col[3]);
- tmpMat.setDiffuse(mat->r, mat->g, mat->b, mat->alpha);
- tmpMat.setSpecular(mat->specr, mat->specg, mat->specb, mat->spectra);
- float s = 1.0 * (mat->har + 1) / 4 ; // in Blender: [1;511] => in OpenGL: [0;128]
- if (s > 128.f)
- s = 128.f;
- tmpMat.setShininess(s);
+ tmpMat.setDiffuse(mat->r, mat->g, mat->b, 1.0f);
+ tmpMat.setSpecular(mat->specr, mat->specg, mat->specb, 1.0f);
+ tmpMat.setShininess(128.f);
tmpMat.setPriority(mat->line_priority);
}
@@ -631,43 +581,19 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
float triCoords[5][3], triNormals[5][3];
bool edgeMarks[5]; // edgeMarks[i] is for the edge between i-th and (i+1)-th vertices
- if (numTris_1 > 0) {
- if (!edge_rotation) {
- clipTriangle(numTris_1, triCoords, v1, v2, v3, triNormals, n1, n2, n3,
- edgeMarks, em1, em2, (!vlr->v4) ? em3 : false, clip_1);
- }
- else {
- clipTriangle(numTris_1, triCoords, v1, v2, v4, triNormals, n1, n2, n4,
- edgeMarks, em1, false, em4, clip_1);
- }
- for (i = 0; i < numTris_1; i++) {
- addTriangle(&ls, triCoords[0], triCoords[i + 1], triCoords[i + 2],
- triNormals[0], triNormals[i + 1], triNormals[i + 2],
- fm, (i == 0) ? edgeMarks[0] : false, edgeMarks[i + 1],
- (i == numTris_1 - 1) ? edgeMarks[i + 2] : false);
- _numFacesRead++;
- }
- }
-
- if (numTris_2 > 0) {
- if (!edge_rotation) {
- clipTriangle(numTris_2, triCoords, v1, v3, v4, triNormals, n1, n3, n4,
- edgeMarks, false, em3, em4, clip_2);
- }
- else {
- clipTriangle(numTris_2, triCoords, v2, v3, v4, triNormals, n2, n3, n4,
- edgeMarks, em2, em3, false, clip_2);
- }
- for (i = 0; i < numTris_2; i++) {
- addTriangle(&ls, triCoords[0], triCoords[i + 1], triCoords[i + 2],
- triNormals[0], triNormals[i + 1], triNormals[i + 2],
- fm, (i == 0) ? edgeMarks[0] : false, edgeMarks[i + 1],
- (i == numTris_2 - 1) ? edgeMarks[i + 2] : false);
- _numFacesRead++;
- }
+ clipTriangle(numTris, triCoords, v1, v2, v3, triNormals, n1, n2, n3,
+ edgeMarks, em1, em2, em3, clip);
+ for (i = 0; i < numTris; i++) {
+ addTriangle(&ls, triCoords[0], triCoords[i + 1], triCoords[i + 2],
+ triNormals[0], triNormals[i + 1], triNormals[i + 2],
+ fm, (i == 0) ? edgeMarks[0] : false, edgeMarks[i + 1],
+ (i == numTris - 1) ? edgeMarks[i + 2] : false);
+ _numFacesRead++;
}
}
+ MEM_freeN(mlooptri);
+
// We might have several times the same vertex. We want a clean
// shape with no real-vertex. Here, we are making a cleaning pass.
float *cleanVertices = NULL;
@@ -806,8 +732,8 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
cleanNIndices, niSize, MIndices, viSize, 0, 0, 0);
// 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);
+ rep->setName(ob->id.name + 2);
+ rep->setLibraryPath(ob->id.lib ? 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/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
index 290701936e3..2fcf4373bba 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
@@ -40,19 +40,30 @@
#include "../system/RenderMonitor.h"
extern "C" {
+#include "MEM_guardedalloc.h"
+
#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "renderdatabase.h"
#include "render_types.h"
+#include "BKE_customdata.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
+#include "BLI_iterator.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
}
+#include "DEG_depsgraph_query.h"
+
#ifdef WITH_CXX_GUARDEDALLOC
#include "MEM_guardedalloc.h"
#endif
@@ -78,7 +89,7 @@ class BlenderFileLoader
{
public:
/*! Builds a MaxFileLoader */
- BlenderFileLoader(Render *re, SceneRenderLayer *srl);
+ BlenderFileLoader(Render *re, ViewLayer *view_layer);
virtual ~BlenderFileLoader();
/*! Loads the 3D scene and returns a pointer to the scene root node */
@@ -96,9 +107,8 @@ public:
inline void setRenderMonitor(RenderMonitor *iRenderMonitor) {_pRenderMonitor = iRenderMonitor;}
protected:
- void insertShapeNode(ObjectInstanceRen *obi, int id);
+ void insertShapeNode(Object *ob, Mesh *mesh, int id);
int testDegenerateTriangle(float v1[3], float v2[3], float v3[3]);
- bool testEdgeRotation(float v1[3], float v2[3], float v3[3], float v4[3]);
int countClippedFaces(float v1[3], float v2[3], float v3[3], int clip[3]);
void clipLine(float v1[3], float v2[3], float c[3], float z);
void clipTriangle(int numTris, float triCoords[][3], float v1[3], float v2[3], float v3[3],
@@ -114,7 +124,7 @@ protected:
unsigned n;
};
Render *_re;
- SceneRenderLayer *_srl;
+ ViewLayer *_view_layer;
NodeGroup *_Scene;
unsigned _numFacesRead;
#if 0
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 0b672ca6adb..14b638da545 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -34,6 +34,7 @@ extern "C" {
#include "RNA_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_listBase.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
@@ -43,9 +44,11 @@ extern "C" {
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
+#include "BKE_collection.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
+#include "BKE_idprop.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h" /* free_libblock */
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -59,6 +62,9 @@ extern "C" {
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "RE_pipeline.h"
#include "render_types.h"
@@ -85,7 +91,7 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
freestyle_scene = BKE_scene_add(freestyle_bmain, name);
freestyle_scene->r.cfra = old_scene->r.cfra;
freestyle_scene->r.mode = old_scene->r.mode &
- ~(R_EDGE_FRS | R_SHADOW | R_SSS | R_PANORAMA | R_ENVMAP | R_MBLUR | R_BORDER);
+ ~(R_EDGE_FRS | R_BORDER);
freestyle_scene->r.xsch = re->rectx; // old_scene->r.xsch
freestyle_scene->r.ysch = re->recty; // old_scene->r.ysch
freestyle_scene->r.xasp = 1.0f; // old_scene->r.xasp;
@@ -93,8 +99,6 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
freestyle_scene->r.tilex = old_scene->r.tilex;
freestyle_scene->r.tiley = old_scene->r.tiley;
freestyle_scene->r.size = 100; // old_scene->r.size
- //freestyle_scene->r.maximsize = old_scene->r.maximsize; /* DEPRECATED */
- freestyle_scene->r.ocres = old_scene->r.ocres;
freestyle_scene->r.color_mgt_flag = 0; // old_scene->r.color_mgt_flag;
freestyle_scene->r.scemode = (old_scene->r.scemode & ~(R_SINGLE_LAYER | R_NO_FRAME_UPDATE | R_MULTIVIEW)) &
(re->r.scemode | ~R_FULL_SAMPLE);
@@ -109,27 +113,39 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
freestyle_scene->r.safety.ymin = old_scene->r.safety.ymin;
freestyle_scene->r.safety.xmax = old_scene->r.safety.xmax;
freestyle_scene->r.safety.ymax = old_scene->r.safety.ymax;
- freestyle_scene->r.osa = old_scene->r.osa;
- freestyle_scene->r.filtertype = old_scene->r.filtertype;
- freestyle_scene->r.gauss = old_scene->r.gauss;
freestyle_scene->r.dither_intensity = old_scene->r.dither_intensity;
- BLI_strncpy(freestyle_scene->r.engine, old_scene->r.engine, sizeof(freestyle_scene->r.engine));
+ STRNCPY(freestyle_scene->r.engine, old_scene->r.engine);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Stroke rendering engine : " << freestyle_scene->r.engine << endl;
+ }
freestyle_scene->r.im_format.planes = R_IMF_PLANES_RGBA;
freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG;
+ // Copy ID properties, including Cycles render properties
+ if (old_scene->id.properties) {
+ freestyle_scene->id.properties = IDP_CopyProperty_ex(old_scene->id.properties, 0);
+ }
+
+ if (STREQ(freestyle_scene->r.engine, RE_engine_id_CYCLES)) {
+ /* Render with transparent background. */
+ PointerRNA freestyle_scene_ptr;
+ RNA_id_pointer_create(&freestyle_scene->id, &freestyle_scene_ptr);
+ PointerRNA freestyle_cycles_ptr = RNA_pointer_get(&freestyle_scene_ptr, "cycles");
+ RNA_boolean_set(&freestyle_cycles_ptr, "film_transparent", 1);
+ }
+
if (G.debug & G_DEBUG_FREESTYLE) {
printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r));
}
- // Render layer
- SceneRenderLayer *srl = (SceneRenderLayer *)freestyle_scene->r.layers.first;
- srl->layflag = SCE_LAY_SOLID | SCE_LAY_ZTRA;
-
BKE_scene_set_background(freestyle_bmain, freestyle_scene);
+ // Scene layer.
+ ViewLayer *view_layer = (ViewLayer *)freestyle_scene->view_layers.first;
+ view_layer->layflag = SCE_LAY_SOLID | SCE_LAY_ZTRA;
+
// Camera
- Object *object_camera = BKE_object_add(freestyle_bmain, freestyle_scene, OB_CAMERA, NULL);
- DAG_relations_tag_update(freestyle_bmain);
+ Object *object_camera = BKE_object_add(freestyle_bmain, freestyle_scene, view_layer, OB_CAMERA, NULL);
Camera *camera = (Camera *)object_camera->data;
camera->type = CAM_ORTHO;
@@ -149,14 +165,14 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
// Reset serial mesh ID (used for BlenderStrokeRenderer::NewMesh())
_mesh_id = 0xffffffff;
- // Check if the rendering engine uses new shading nodes
- _use_shading_nodes = BKE_scene_use_new_shading_nodes(freestyle_scene);
-
// Create a bNodeTree-to-Material hash table
- if (_use_shading_nodes)
- _nodetree_hash = BLI_ghash_ptr_new("BlenderStrokeRenderer::_nodetree_hash");
- else
- _nodetree_hash = NULL;
+ _nodetree_hash = BLI_ghash_ptr_new("BlenderStrokeRenderer::_nodetree_hash");
+
+ // Depsgraph
+ freestyle_depsgraph = DEG_graph_new(freestyle_scene, view_layer, DAG_EVAL_RENDER);
+ DEG_graph_id_tag_update(freestyle_bmain, freestyle_depsgraph, &freestyle_scene->id, 0);
+ DEG_graph_id_tag_update(freestyle_bmain, freestyle_depsgraph, &object_camera->id, 0);
+ DEG_graph_tag_relations_update(freestyle_depsgraph);
}
BlenderStrokeRenderer::~BlenderStrokeRenderer()
@@ -167,7 +183,8 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
// compositor has finished.
// release objects and data blocks
- for (Base *b = (Base *)freestyle_scene->base.first; b; b = b->next) {
+ ViewLayer *view_layer = (ViewLayer *)freestyle_scene->view_layers.first;
+ for (Base *b = (Base *)view_layer->object_bases.first; b; b = b->next) {
Object *ob = b->object;
void *data = ob->data;
char *name = ob->id.name;
@@ -190,7 +207,9 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
cerr << "Warning: unexpected object in the scene: " << name[0] << name[1] << ":" << (name + 2) << endl;
}
}
- BLI_freelistN(&freestyle_scene->base);
+
+ // Make sure we don't have any bases which might reference freed objects.
+ BKE_main_collection_sync(freestyle_bmain);
// release materials
Link *lnk = (Link *)freestyle_bmain->mat.first;
@@ -198,21 +217,13 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
while (lnk)
{
Material *ma = (Material*)lnk;
- // We want to retain the linestyle mtexs, so let's detach them first
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- ma->mtex[a] = NULL;
- }
- else {
- break; // Textures are ordered, no empty slots between two textures
- }
- }
lnk = lnk->next;
BKE_libblock_free(freestyle_bmain, ma);
}
- if (_use_shading_nodes)
- BLI_ghash_free(_nodetree_hash, NULL, NULL);
+ BLI_ghash_free(_nodetree_hash, NULL, NULL);
+
+ DEG_graph_free(freestyle_depsgraph);
FreeStrokeGroups();
}
@@ -454,89 +465,13 @@ void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
{
- if (_use_shading_nodes) {
- bNodeTree *nt = iStrokeRep->getNodeTree();
- Material *ma = (Material *)BLI_ghash_lookup(_nodetree_hash, nt);
- if (!ma) {
- ma = BlenderStrokeRenderer::GetStrokeShader(freestyle_bmain, nt, false);
- BLI_ghash_insert(_nodetree_hash, nt, ma);
- }
-
- if (STREQ(freestyle_scene->r.engine, RE_engine_id_CYCLES)) {
- PointerRNA scene_ptr, freestyle_scene_ptr;
- RNA_pointer_create(NULL, &RNA_Scene, old_scene, &scene_ptr);
- RNA_pointer_create(NULL, &RNA_Scene, freestyle_scene, &freestyle_scene_ptr);
-
- PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles");
- PointerRNA freestyle_cycles_ptr = RNA_pointer_get(&freestyle_scene_ptr, "cycles");
-
- int flag;
- RNA_STRUCT_BEGIN(&freestyle_cycles_ptr, prop)
- {
- flag = RNA_property_flag(prop);
- if (flag & PROP_HIDDEN)
- continue;
- RNA_property_copy(&freestyle_cycles_ptr, &cycles_ptr, prop, -1);
- }
- RNA_STRUCT_END;
-
- RNA_boolean_set(&freestyle_cycles_ptr, "film_transparent", 1);
- }
-
- iStrokeRep->setMaterial(ma);
- }
- else {
- bool has_mat = false;
- int a = 0;
-
- // Look for a good existing material
- for (Link *lnk = (Link *)freestyle_bmain->mat.first; lnk; lnk = lnk->next) {
- Material *ma = (Material*)lnk;
- bool texs_are_good = true;
- // as soon as textures differ it's not the right one
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] != iStrokeRep->getMTex(a)) {
- texs_are_good = false;
- break;
- }
- }
-
- if (texs_are_good) {
- iStrokeRep->setMaterial(ma);
- has_mat = true;
- break; // if textures are good, no need to search anymore
- }
- }
-
- // If still no material, create one
- if (!has_mat) {
- Material *ma = BKE_material_add(freestyle_bmain, "stroke_material");
- DAG_relations_tag_update(freestyle_bmain);
- ma->mode |= MA_VERTEXCOLP;
- ma->mode |= MA_TRANSP;
- ma->mode |= MA_SHLESS;
- ma->vcol_alpha = 1;
-
- id_us_min(&ma->id);
-
- // Textures
- while (iStrokeRep->getMTex(a)) {
- ma->mtex[a] = (MTex *)iStrokeRep->getMTex(a);
-
- // We'll generate both with tips and without tips
- // coordinates, on two different UV layers.
- if (ma->mtex[a]->texflag & MTEX_TIPS) {
- BLI_strncpy(ma->mtex[a]->uvname, uvNames[1], sizeof(ma->mtex[a]->uvname));
- }
- else {
- BLI_strncpy(ma->mtex[a]->uvname, uvNames[0], sizeof(ma->mtex[a]->uvname));
- }
- a++;
- }
-
- iStrokeRep->setMaterial(ma);
- }
+ bNodeTree *nt = iStrokeRep->getNodeTree();
+ Material *ma = (Material *)BLI_ghash_lookup(_nodetree_hash, nt);
+ if (!ma) {
+ ma = BlenderStrokeRenderer::GetStrokeShader(freestyle_bmain, nt, false);
+ BLI_ghash_insert(_nodetree_hash, nt, ma);
}
+ iStrokeRep->setMaterial(ma);
const vector<Strip*>& strips = iStrokeRep->getStrips();
const bool hasTex = iStrokeRep->hasTex();
@@ -675,8 +610,8 @@ int BlenderStrokeRenderer::get_stroke_count() const
void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
{
#if 0
- Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, OB_MESH);
- DAG_relations_tag_update(freestyle_bmain);
+ Object *object_mesh = BKE_object_add(freestyle_bmain, freestyle_scene, (ViewLayer *)freestyle_scene->view_layers.first, OB_MESH);
+ DEG_relations_tag_update(freestyle_bmain);
#else
Object *object_mesh = NewMesh();
#endif
@@ -701,17 +636,13 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
if (hasTex) {
// First UV layer
- CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, uvNames[0]);
CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, uvNames[0]);
- CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 0);
CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 0);
BKE_mesh_update_customdata_pointers(mesh, true);
loopsuv[0] = mesh->mloopuv;
// Second UV layer
- CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, uvNames[1]);
CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, uvNames[1]);
- CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 1);
CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 1);
BKE_mesh_update_customdata_pointers(mesh, true);
loopsuv[1] = mesh->mloopuv;
@@ -923,7 +854,6 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
Object *BlenderStrokeRenderer::NewMesh() const
{
Object *ob;
- Base *base;
char name[MAX_ID_NAME];
unsigned int mesh_id = get_stroke_mesh_id();
@@ -931,18 +861,15 @@ Object *BlenderStrokeRenderer::NewMesh() const
ob = BKE_object_add_only_object(freestyle_bmain, OB_MESH, name);
BLI_snprintf(name, MAX_ID_NAME, "0%08xME", mesh_id);
ob->data = BKE_mesh_add(freestyle_bmain, name);
- ob->lay = 1;
- base = BKE_scene_base_add(freestyle_scene, ob);
- DAG_relations_tag_update(freestyle_bmain);
-#if 0
- BKE_scene_base_deselect_all(scene);
- BKE_scene_base_select(scene, base);
-#else
- (void)base;
-#endif
+ Collection *collection_master = BKE_collection_master(freestyle_scene);
+ BKE_collection_object_add(freestyle_bmain, collection_master, ob);
+ DEG_graph_tag_relations_update(freestyle_depsgraph);
- DAG_id_tag_update_ex(freestyle_bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_graph_id_tag_update(freestyle_bmain,
+ freestyle_depsgraph,
+ &ob->id,
+ OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
return ob;
}
@@ -959,6 +886,8 @@ Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render)
#endif
Render *freestyle_render = RE_NewSceneRender(freestyle_scene);
+ ViewLayer *view_layer = (ViewLayer *)freestyle_scene->view_layers.first;
+ DEG_graph_relations_update(freestyle_depsgraph, freestyle_bmain, freestyle_scene, view_layer);
RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene,
render && get_stroke_count() > 0);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
index ec53efa14cd..c7204293839 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
@@ -29,6 +29,7 @@
#include "../system/FreestyleConfig.h"
extern "C" {
+struct Depsgraph;
struct GHash;
struct Main;
struct Material;
@@ -76,6 +77,7 @@ protected:
Main *freestyle_bmain;
Scene *old_scene;
Scene *freestyle_scene;
+ Depsgraph *freestyle_depsgraph;
bContext *_context;
float _width, _height;
float _z, _z_delta;
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 6e65b021805..0548d49dce0 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -41,29 +41,28 @@ extern "C" {
#include "MEM_guardedalloc.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_freestyle_types.h"
-#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_text_types.h"
+#include "BKE_context.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_linestyle.h"
-#include "BKE_main.h"
#include "BKE_text.h"
-#include "BKE_context.h"
#include "BLT_translation.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_math_color_blend.h"
#include "BLI_callbacks.h"
#include "BPY_extern.h"
#include "renderpipeline.h"
-#include "pixelblending.h"
#include "FRS_freestyle.h"
@@ -283,19 +282,19 @@ static bool test_edge_type_conditions(struct edge_type_condition *conditions,
return true;
}
-static void prepare(Render *re, SceneRenderLayer *srl)
+static void prepare(Render *re, ViewLayer *view_layer)
{
// load mesh
re->i.infostr = IFACE_("Freestyle: Mesh loading");
re->stats_draw(re->sdh, &re->i);
re->i.infostr = NULL;
- if (controller->LoadMesh(re, srl)) // returns if scene cannot be loaded or if empty
+ if (controller->LoadMesh(re, view_layer)) // returns if scene cannot be loaded or if empty
return;
if (re->test_break(re->tbh))
return;
// add style modules
- FreestyleConfig *config = &srl->freestyleConfig;
+ FreestyleConfig *config = &view_layer->freestyle_config;
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "\n=== Rendering options ===" << endl;
@@ -357,9 +356,9 @@ static void prepare(Render *re, SceneRenderLayer *srl)
if (lineset->flags & FREESTYLE_LINESET_ENABLED) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << " " << layer_count+1 << ": " << lineset->name << " - " <<
- (lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
+ (lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl;
}
- char *buffer = create_lineset_handler(srl->name, lineset->name);
+ char *buffer = create_lineset_handler(view_layer->name, lineset->name);
controller->InsertStyleModule(layer_count, lineset->name, buffer);
controller->toggleLayer(layer_count, true);
MEM_freeN(buffer);
@@ -445,7 +444,7 @@ static void prepare(Render *re, SceneRenderLayer *srl)
}
// set diffuse and z depth passes
- RenderLayer *rl = RE_GetRenderLayer(re->result, srl->name);
+ RenderLayer *rl = RE_GetRenderLayer(re->result, view_layer->name);
bool diffuse = false, z = false;
for (RenderPass *rpass = (RenderPass *)rl->passes.first; rpass; rpass = rpass->next) {
if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
@@ -473,7 +472,7 @@ static void prepare(Render *re, SceneRenderLayer *srl)
controller->ComputeViewMap();
}
-void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_render)
+void FRS_composite_result(Render *re, ViewLayer *view_layer, Render *freestyle_render)
{
RenderLayer *rl;
float *src, *dest, *pixSrc, *pixDest;
@@ -503,7 +502,7 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
}
#endif
- rl = RE_GetRenderLayer(re->result, srl->name);
+ rl = RE_GetRenderLayer(re->result, view_layer->name);
if (!rl) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "No destination render layer to composite to" << endl;
@@ -530,19 +529,19 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
pixSrc = src + 4 * (rectx * y + x);
if (pixSrc[3] > 0.0) {
pixDest = dest + 4 * (rectx * y + x);
- addAlphaOverFloat(pixDest, pixSrc);
+ blend_color_mix_float(pixDest, pixDest, pixSrc);
}
}
}
}
-static int displayed_layer_count(SceneRenderLayer *srl)
+static int displayed_layer_count(ViewLayer *view_layer)
{
int count = 0;
- switch (srl->freestyleConfig.mode) {
+ switch (view_layer->freestyle_config.mode) {
case FREESTYLE_CONTROL_SCRIPT_MODE:
- for (FreestyleModuleConfig *module = (FreestyleModuleConfig *)srl->freestyleConfig.modules.first;
+ for (FreestyleModuleConfig *module = (FreestyleModuleConfig *)view_layer->freestyle_config.modules.first;
module;
module = module->next)
{
@@ -551,7 +550,7 @@ static int displayed_layer_count(SceneRenderLayer *srl)
}
break;
case FREESTYLE_CONTROL_EDITOR_MODE:
- for (FreestyleLineSet *lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first;
+ for (FreestyleLineSet *lineset = (FreestyleLineSet *)view_layer->freestyle_config.linesets.first;
lineset;
lineset = lineset->next)
{
@@ -563,9 +562,11 @@ static int displayed_layer_count(SceneRenderLayer *srl)
return count;
}
-int FRS_is_freestyle_enabled(SceneRenderLayer *srl)
+int FRS_is_freestyle_enabled(ViewLayer *view_layer)
{
- return (!(srl->layflag & SCE_LAY_DISABLE) && srl->layflag & SCE_LAY_FRS && displayed_layer_count(srl) > 0);
+ return ((view_layer->flag & VIEW_LAYER_RENDER) &&
+ (view_layer->flag & VIEW_LAYER_FREESTYLE) &&
+ displayed_layer_count(view_layer) > 0);
}
void FRS_init_stroke_renderer(Render *re)
@@ -587,7 +588,7 @@ void FRS_begin_stroke_rendering(Render *re)
init_camera(re);
}
-Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
+Render *FRS_do_stroke_rendering(Render *re, ViewLayer *view_layer, int render)
{
Render *freestyle_render = NULL;
@@ -596,12 +597,12 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
RenderMonitor monitor(re);
controller->setRenderMonitor(&monitor);
- controller->setViewMapCache((srl->freestyleConfig.flags & FREESTYLE_VIEW_MAP_CACHE) ? true : false);
+ controller->setViewMapCache((view_layer->freestyle_config.flags & FREESTYLE_VIEW_MAP_CACHE) ? true : false);
if (G.debug & G_DEBUG_FREESTYLE) {
cout << endl;
cout << "----------------------------------------------------------" << endl;
- cout << "| " << (re->scene->id.name + 2) << "|" << srl->name << endl;
+ cout << "| " << (re->scene->id.name + 2) << "|" << view_layer->name << endl;
cout << "----------------------------------------------------------" << endl;
}
@@ -610,7 +611,7 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
// - add style modules
// - set parameters
// - compute view map
- prepare(re, srl);
+ prepare(re, view_layer);
if (re->test_break(re->tbh)) {
controller->CloseFile();
@@ -635,7 +636,7 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
// composite result
if (freestyle_render) {
- FRS_composite_result(re, srl, freestyle_render);
+ FRS_composite_result(re, view_layer, freestyle_render);
RE_FreeRenderResult(freestyle_render->result);
freestyle_render->result = NULL;
}
diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp
index 9c462bb6b2b..6f5491fc8ef 100644
--- a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp
+++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp
@@ -51,7 +51,6 @@ IndexedFaceSet::IndexedFaceSet() : Rep()
_MISize = 0;
_TIndices = NULL;
_TISize = 0;
- _displayList = 0;
}
IndexedFaceSet::IndexedFaceSet(float *iVertices, unsigned iVSize, float *iNormals, unsigned iNSize,
@@ -150,8 +149,6 @@ IndexedFaceSet::IndexedFaceSet(float *iVertices, unsigned iVSize, float *iNormal
_TISize = iTISize;
_TIndices = iTIndices;
}
-
- _displayList = 0;
}
IndexedFaceSet::IndexedFaceSet(const IndexedFaceSet& iBrother) : Rep(iBrother)
@@ -215,8 +212,6 @@ IndexedFaceSet::IndexedFaceSet(const IndexedFaceSet& iBrother) : Rep(iBrother)
_TIndices = new unsigned[_TISize];
memcpy(_TIndices, iBrother.tindices(), _TISize * sizeof(unsigned));
}
-
- _displayList = 0;
}
IndexedFaceSet::~IndexedFaceSet()
@@ -276,10 +271,6 @@ IndexedFaceSet::~IndexedFaceSet()
delete[] _TIndices;
_TIndices = NULL;
}
-
- // should find a way to deallocates the displayList
- // glDeleteLists(GLuint list, GLSizei range)
- _displayList = 0;
}
void IndexedFaceSet::accept(SceneVisitor& v)
diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
index 4103d3299d4..aa090155537 100644
--- a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
+++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
@@ -150,8 +150,6 @@ public:
std::swap(_MISize, ioOther._MISize);
std::swap(_TISize, ioOther._TISize);
- std::swap(_displayList, ioOther._displayList);
-
Rep::swap(ioOther);
}
@@ -173,12 +171,6 @@ public:
/*! Compute the Bounding Box */
virtual void ComputeBBox();
- /*! modifiers */
- inline void setDisplayList(unsigned int index)
- {
- _displayList = index;
- }
-
/*! Accessors */
virtual const float *vertices() const
{
@@ -280,11 +272,6 @@ public:
return _TISize;
}
- inline unsigned int displayList() const
- {
- return _displayList;
- }
-
protected:
float *_Vertices;
float *_Normals;
@@ -311,8 +298,6 @@ protected:
unsigned _MISize;
unsigned _TISize;
- unsigned int _displayList;
-
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:IndexedFaceSet")
#endif
diff --git a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.cpp b/source/blender/freestyle/intern/scene_graph/NodeViewLayer.cpp
index 24c56ff4e28..701c5caa91d 100644
--- a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.cpp
+++ b/source/blender/freestyle/intern/scene_graph/NodeViewLayer.cpp
@@ -18,18 +18,18 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.cpp
+/** \file blender/freestyle/intern/scene_graph/NodeViewLayer.cpp
* \ingroup freestyle
* \brief Class to represent a scene render layer in Blender.
*/
-#include "NodeSceneRenderLayer.h"
+#include "NodeViewLayer.h"
namespace Freestyle {
-void NodeSceneRenderLayer::accept(SceneVisitor& v)
+void NodeViewLayer::accept(SceneVisitor& v)
{
- v.visitNodeSceneRenderLayer(*this);
+ v.visitNodeViewLayer(*this);
}
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h b/source/blender/freestyle/intern/scene_graph/NodeViewLayer.h
index 8dc93d84201..cc64fda60b6 100644
--- a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
+++ b/source/blender/freestyle/intern/scene_graph/NodeViewLayer.h
@@ -18,38 +18,38 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __FREESTYLE_NODE_SCENE_RENDER_LAYER_H__
-#define __FREESTYLE_NODE_SCENE_RENDER_LAYER_H__
+#ifndef __FREESTYLE_NODE_VIEW_LAYER_H__
+#define __FREESTYLE_NODE_VIEW_LAYER_H__
-/** \file blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
+/** \file blender/freestyle/intern/scene_graph/NodeViewLayer.h
* \ingroup freestyle
- * \brief Class to represent a scene render layer in Blender.
+ * \brief Class to represent a view layer in Blender.
*/
#include "Node.h"
extern "C" {
-#include "DNA_scene_types.h" /* for Scene and SceneRenderLayer */
+#include "DNA_scene_types.h" /* for Scene and ViewLayer */
}
using namespace std;
namespace Freestyle {
-class NodeSceneRenderLayer : public Node
+class NodeViewLayer : public Node
{
public:
- inline NodeSceneRenderLayer(Scene& scene, SceneRenderLayer& srl) : Node(), _Scene(scene), _SceneRenderLayer(srl) {}
- virtual ~NodeSceneRenderLayer() {}
+ inline NodeViewLayer(Scene& scene, ViewLayer& view_layer) : Node(), _Scene(scene), _ViewLayer(view_layer) {}
+ virtual ~NodeViewLayer() {}
inline struct Scene& scene() const
{
return _Scene;
}
- inline struct SceneRenderLayer& sceneRenderLayer() const
+ inline struct ViewLayer& sceneLayer() const
{
- return _SceneRenderLayer;
+ return _ViewLayer;
}
/*! Accept the corresponding visitor */
@@ -58,9 +58,9 @@ public:
protected:
Scene& _Scene;
- SceneRenderLayer& _SceneRenderLayer;
+ ViewLayer& _ViewLayer;
};
} /* namespace Freestyle */
-#endif // __FREESTYLE_NODE_SCENE_RENDER_LAYER_H__
+#endif // __FREESTYLE_NODE_VIEW_LAYER_H__
diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
index 2af02ab5764..16c353678c1 100644
--- a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
+++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
@@ -35,14 +35,14 @@ string SceneHash::toString()
return ss.str();
}
-void SceneHash::visitNodeSceneRenderLayer(NodeSceneRenderLayer& node)
+void SceneHash::visitNodeViewLayer(NodeViewLayer& node)
{
struct RenderData *r = &node.scene().r;
adler32((unsigned char *)&r->xsch, sizeof(r->xsch)); // resolution_x
adler32((unsigned char *)&r->ysch, sizeof(r->ysch)); // resolution_y
adler32((unsigned char *)&r->size, sizeof(r->size)); // resolution_percentage
- struct FreestyleConfig *config = &node.sceneRenderLayer().freestyleConfig;
+ struct FreestyleConfig *config = &node.sceneLayer().freestyle_config;
adler32((unsigned char *)&config->flags, sizeof(config->flags));
adler32((unsigned char *)&config->crease_angle, sizeof(config->crease_angle));
adler32((unsigned char *)&config->sphere_radius, sizeof(config->sphere_radius));
diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.h b/source/blender/freestyle/intern/scene_graph/SceneHash.h
index 9da711673f0..662b4bba8f1 100644
--- a/source/blender/freestyle/intern/scene_graph/SceneHash.h
+++ b/source/blender/freestyle/intern/scene_graph/SceneHash.h
@@ -26,7 +26,7 @@
*/
#include "IndexedFaceSet.h"
-#include "NodeSceneRenderLayer.h"
+#include "NodeViewLayer.h"
#include "NodeCamera.h"
#include "SceneVisitor.h"
@@ -49,7 +49,7 @@ public:
virtual ~SceneHash() {}
VISIT_DECL(NodeCamera)
- VISIT_DECL(NodeSceneRenderLayer)
+ VISIT_DECL(NodeViewLayer)
VISIT_DECL(IndexedFaceSet)
string toString();
diff --git a/source/blender/freestyle/intern/scene_graph/SceneVisitor.h b/source/blender/freestyle/intern/scene_graph/SceneVisitor.h
index 712585c4064..d76e48980bf 100644
--- a/source/blender/freestyle/intern/scene_graph/SceneVisitor.h
+++ b/source/blender/freestyle/intern/scene_graph/SceneVisitor.h
@@ -56,7 +56,7 @@ class NodeLight;
class NodeCamera;
class NodeDrawingStyle;
class NodeTransform;
-class NodeSceneRenderLayer;
+class NodeViewLayer;
class Rep;
class LineRep;
@@ -88,7 +88,7 @@ public:
VISIT_COMPLETE_DEF(NodeCamera)
VISIT_COMPLETE_DEF(NodeDrawingStyle)
VISIT_COMPLETE_DEF(NodeTransform)
- VISIT_COMPLETE_DEF(NodeSceneRenderLayer)
+ VISIT_COMPLETE_DEF(NodeViewLayer)
VISIT_COMPLETE_DEF(Rep)
VISIT_COMPLETE_DEF(LineRep)
diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h
index ce63c528ac3..a813d516d44 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.h
+++ b/source/blender/freestyle/intern/stroke/Stroke.h
@@ -44,8 +44,7 @@
#endif
extern "C" {
-#include "DNA_material_types.h"
-
+struct MTex;
struct bNodeTree;
}
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
new file mode 100644
index 00000000000..b28a83372b8
--- /dev/null
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -0,0 +1,72 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2018, Blender Foundation
+# All rights reserved.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ ../blenkernel
+ ../blenlib
+ ../blenfont
+ ../depsgraph
+ ../makesdna
+ ../makesrna
+ ../bmesh
+ ../render/extern/include
+ ../../../intern/elbeem/extern
+ ../../../intern/guardedalloc
+ ../../../intern/eigen
+)
+
+set(INC_SYS
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ intern/MOD_gpencil_util.h
+
+ intern/MOD_gpencil_util.c
+ intern/MOD_gpencilarmature.c
+ intern/MOD_gpencilnoise.c
+ intern/MOD_gpencilsubdiv.c
+ intern/MOD_gpencilsimplify.c
+ intern/MOD_gpencilthick.c
+ intern/MOD_gpenciltint.c
+ intern/MOD_gpencilcolor.c
+ intern/MOD_gpencilarray.c
+ intern/MOD_gpencilbuild.c
+ intern/MOD_gpencilopacity.c
+ intern/MOD_gpencillattice.c
+ intern/MOD_gpencilmirror.c
+ intern/MOD_gpencilsmooth.c
+ intern/MOD_gpencilhook.c
+ intern/MOD_gpenciloffset.c
+ intern/MOD_gpenciltime.c
+
+ MOD_gpencil_modifiertypes.h
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_gpencil_modifiers "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
new file mode 100644
index 00000000000..07db9f15288
--- /dev/null
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -0,0 +1,53 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file MOD_gpencil_modifiertypes.h
+ * \ingroup modifiers
+ */
+
+#ifndef __MOD_GPENCIL_MODIFIERTYPES_H__
+#define __MOD_GPENCIL_MODIFIERTYPES_H__
+
+#include "BKE_gpencil_modifier.h"
+
+/* ****************** Type structures for all modifiers ****************** */
+
+extern GpencilModifierTypeInfo modifierType_Gpencil_None;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Noise;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Subdiv;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Simplify;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Thick;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Tint;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Color;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Array;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Build;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Opacity;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Lattice;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Mirror;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Smooth;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Hook;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Offset;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Armature;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Time;
+
+/* MOD_gpencil_util.c */
+void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
+
+#endif /* __MOD_GPENCIL_MODIFIERTYPES_H__ */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
new file mode 100644
index 00000000000..2551d9a216d
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -0,0 +1,216 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
+#include "BLI_rand.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_deform.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_lattice.h"
+#include "BKE_material.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_colortools.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_util.h"
+
+void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
+{
+#define INIT_GP_TYPE(typeName) (types[eGpencilModifierType_##typeName] = &modifierType_Gpencil_##typeName)
+ INIT_GP_TYPE(Noise);
+ INIT_GP_TYPE(Subdiv);
+ INIT_GP_TYPE(Simplify);
+ INIT_GP_TYPE(Thick);
+ INIT_GP_TYPE(Tint);
+ INIT_GP_TYPE(Color);
+ INIT_GP_TYPE(Array);
+ INIT_GP_TYPE(Build);
+ INIT_GP_TYPE(Opacity);
+ INIT_GP_TYPE(Lattice);
+ INIT_GP_TYPE(Mirror);
+ INIT_GP_TYPE(Smooth);
+ INIT_GP_TYPE(Hook);
+ INIT_GP_TYPE(Offset);
+ INIT_GP_TYPE(Armature);
+ INIT_GP_TYPE(Time);
+#undef INIT_GP_TYPE
+}
+
+/* verify if valid layer and pass index */
+bool is_stroke_affected_by_modifier(
+ Object *ob, char *mlayername, int mpassindex, int gpl_passindex, int minpoints,
+ bGPDlayer *gpl, bGPDstroke *gps, bool inv1, bool inv2, bool inv3)
+{
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* omit if filter by layer */
+ if (mlayername[0] != '\0') {
+ if (inv1 == false) {
+ if (!STREQ(mlayername, gpl->info)) {
+ return false;
+ }
+ }
+ else {
+ if (STREQ(mlayername, gpl->info)) {
+ return false;
+ }
+ }
+ }
+ /* verify layer pass */
+ if (gpl_passindex > 0) {
+ if (inv3 == false) {
+ if (gpl->pass_index != gpl_passindex) {
+ return false;
+ }
+ }
+ else {
+ if (gpl->pass_index == gpl_passindex) {
+ return false;
+ }
+ }
+ }
+ /* verify material pass */
+ if (mpassindex > 0) {
+ if (inv2 == false) {
+ if (gp_style->index != mpassindex) {
+ return false;
+ }
+ }
+ else {
+ if (gp_style->index == mpassindex) {
+ return false;
+ }
+ }
+ }
+ /* need to have a minimum number of points */
+ if ((minpoints > 0) && (gps->totpoints < minpoints)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* verify if valid vertex group *and return weight */
+float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
+{
+ float weight = 1.0f;
+
+ if ((dvert != NULL) && (def_nr != -1)) {
+ MDeformWeight *dw = defvert_find_index(dvert, def_nr);
+ weight = dw ? dw->weight : -1.0f;
+ if ((weight >= 0.0f) && (inverse == 1)) {
+ return -1.0f;
+ }
+
+ if ((weight < 0.0f) && (inverse == 0)) {
+ return -1.0f;
+ }
+
+ /* if inverse, weight is always 1 */
+ if ((weight < 0.0f) && (inverse == 1)) {
+ return 1.0f;
+ }
+
+ }
+
+ /* handle special empty groups */
+ if ((dvert == NULL) && (def_nr != -1)) {
+ if (inverse == 1) {
+ return 1.0f;
+ }
+ else {
+ return -1.0f;
+ }
+ }
+
+ return weight;
+}
+
+/* set material when apply modifiers (used in tint and color modifier) */
+void gpencil_apply_modifier_material(
+ Main *bmain, Object *ob, Material *mat,
+ GHash *gh_color, bGPDstroke *gps, bool crt_material)
+{
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+
+ /* look for color */
+ if (crt_material) {
+ Material *newmat = BLI_ghash_lookup(gh_color, mat->id.name);
+ if (newmat == NULL) {
+ BKE_object_material_slot_add(bmain, ob);
+ newmat = BKE_material_copy(bmain, mat);
+ newmat->preview = NULL;
+
+ assign_material(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+
+ copy_v4_v4(newmat->gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba);
+ copy_v4_v4(newmat->gp_style->fill_rgba, gps->runtime.tmp_fill_rgba);
+
+ BLI_ghash_insert(gh_color, mat->id.name, newmat);
+ DEG_id_tag_update(&newmat->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ /* reasign color index */
+ int idx = BKE_gpencil_get_material_index(ob, newmat);
+ gps->mat_nr = idx - 1;
+ }
+ else {
+ /* reuse existing color (but update only first time) */
+ if (BLI_ghash_lookup(gh_color, mat->id.name) == NULL) {
+ copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba);
+ copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba);
+ BLI_ghash_insert(gh_color, mat->id.name, mat);
+ }
+ /* update previews (icon and thumbnail) */
+ if (mat->preview != NULL) {
+ mat->preview->flag[ICON_SIZE_ICON] |= PRV_CHANGED;
+ mat->preview->flag[ICON_SIZE_PREVIEW] |= PRV_CHANGED;
+ }
+ DEG_id_tag_update(&mat->id, DEG_TAG_COPY_ON_WRITE);
+ }
+}
diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index cf9efcb0beb..480c431b8b4 100644
--- a/source/blender/render/intern/include/envmap.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -1,7 +1,4 @@
/*
- * envmap_ext.h
- *
- *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
@@ -18,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.
*
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * The Original Code is Copyright (C) Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
@@ -28,26 +25,32 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/render/intern/include/envmap.h
- * \ingroup render
+/** \file blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+ * \ingroup modifiers
*/
-#ifndef __ENVMAP_H__
-#define __ENVMAP_H__
+#ifndef __MOD_GPENCIL_UTIL_H__
+#define __MOD_GPENCIL_UTIL_H__
-/**
- * Make environment maps for all objects in the scene that have an
- * environment map as texture.
- * (initrender.c)
- */
+struct Main;
+struct Object;
+struct bGPDlayer;
+struct bGPDstroke;
+struct MDeformVert;
+struct Material;
+struct GHash;
+
+bool is_stroke_affected_by_modifier(
+ struct Object *ob, char *mlayername, int mpassindex,
+ int gpl_passindex, int minpoints,
+ bGPDlayer *gpl, bGPDstroke *gps,
+ bool inv1, bool inv2, bool inv3);
-struct Render;
-struct TexResult;
-struct ImagePool;
+float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr);
-void make_envmaps(struct Render *re);
-int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, const bool skip_image_load);
-void env_rotate_scene(struct Render *re, float mat[4][4], int do_rotate);
+void gpencil_apply_modifier_material(
+ struct Main *bmain, struct Object *ob, struct Material *mat,
+ struct GHash *gh_color, struct bGPDstroke *gps, bool crt_material);
-#endif /* __ENVMAP_H__ */
+#endif /* __MOD_GPENCIL_UTIL_H__ */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
new file mode 100644
index 00000000000..55728ca581f
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -0,0 +1,207 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_modifier_types.h"
+#include "BLI_math.h"
+
+#include "BLI_listbase.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_lattice.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ArmatureGpencilModifierData *gpmd = (ArmatureGpencilModifierData *)md;
+ gpmd->object = NULL;
+ gpmd->deformflag = ARM_DEF_VGROUP;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void gpencil_deform_verts(
+ ArmatureGpencilModifierData *mmd, Object *target,
+ bGPDstroke *gps)
+{
+ bGPDspoint *pt = gps->points;
+ float *all_vert_coords = MEM_callocN(sizeof(float) * 3 * gps->totpoints, __func__);
+ int i;
+
+ BKE_gpencil_dvert_ensure(gps);
+
+ /* prepare array of points */
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ float *pt_coords = &all_vert_coords[3 * i];
+ float co[3];
+ copy_v3_v3(co, &pt->x);
+ copy_v3_v3(pt_coords, co);
+ }
+
+ /* deform verts */
+ armature_deform_verts(
+ mmd->object, target, NULL,
+ (float(*)[3])all_vert_coords,
+ NULL, gps->totpoints,
+ mmd->deformflag,
+ (float(*)[3])mmd->prevCos,
+ mmd->vgname, gps);
+
+ /* Apply deformed coordinates */
+ pt = gps->points;
+ for (i = 0; i < gps->totpoints; i++, pt++) {
+ float *pt_coords = &all_vert_coords[3 * i];
+ copy_v3_v3(&pt->x, pt_coords);
+ }
+
+ MEM_SAFE_FREE(all_vert_coords);
+
+}
+
+/* deform stroke */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *UNUSED(gpl), bGPDstroke *gps)
+{
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
+ if (!mmd->object) {
+ return;
+ }
+
+ gpencil_deform_verts(mmd, ob, gps);
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL)
+ return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply armature effects on this frame
+ * NOTE: this assumes that we don't want armature animation on non-keyframed frames
+ */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* compute armature effects on this frame */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
+
+ return !mmd->object;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ ArmatureGpencilModifierData *lmd = (ArmatureGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Armature = {
+ /* name */ "Armature",
+ /* structName */ "ArmatureGpencilModifierData",
+ /* structSize */ sizeof(ArmatureGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
new file mode 100644
index 00000000000..553d9087c3f
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -0,0 +1,349 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_layer.h"
+#include "BKE_library_query.h"
+#include "BKE_collection.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ArrayGpencilModifierData *gpmd = (ArrayGpencilModifierData *)md;
+ gpmd->count = 2;
+ gpmd->offset[0] = 1.0f;
+ gpmd->offset[1] = 0.0f;
+ gpmd->offset[2] = 0.0f;
+ gpmd->shift[0] = 0.0f;
+ gpmd->shift[1] = 0.0f;
+ gpmd->shift[2] = 0.0f;
+ gpmd->scale[0] = 1.0f;
+ gpmd->scale[1] = 1.0f;
+ gpmd->scale[2] = 1.0f;
+ gpmd->rnd_rot = 0.5f;
+ gpmd->rnd_size = 0.5f;
+ gpmd->object = NULL;
+
+ /* fill random values */
+ BLI_array_frand(gpmd->rnd, 20, 1);
+ gpmd->rnd[0] = 1;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* -------------------------------- */
+/* helper function for per-instance positioning */
+static void BKE_gpencil_instance_modifier_instance_tfm(
+ Object *ob, ArrayGpencilModifierData *mmd, const int elem_idx,
+ float r_mat[4][4], float r_offset[4][4])
+{
+ float offset[3], rot[3], scale[3];
+ int ri = mmd->rnd[0];
+ float factor;
+
+ offset[0] = mmd->offset[0] * elem_idx;
+ offset[1] = mmd->offset[1] * elem_idx;
+ offset[2] = mmd->offset[2] * elem_idx;
+
+ /* rotation */
+ if (mmd->flag & GP_ARRAY_RANDOM_ROT) {
+ factor = mmd->rnd_rot * mmd->rnd[ri];
+ mul_v3_v3fl(rot, mmd->rot, factor);
+ add_v3_v3(rot, mmd->rot);
+ }
+ else {
+ copy_v3_v3(rot, mmd->rot);
+ }
+
+ /* scale */
+ if (mmd->flag & GP_ARRAY_RANDOM_SIZE) {
+ factor = mmd->rnd_size * mmd->rnd[ri];
+ mul_v3_v3fl(scale, mmd->scale, factor);
+ add_v3_v3(scale, mmd->scale);
+ }
+ else {
+ copy_v3_v3(scale, mmd->scale);
+ }
+
+ /* advance random index */
+ mmd->rnd[0]++;
+ if (mmd->rnd[0] > 19) {
+ mmd->rnd[0] = 1;
+ }
+
+ /* calculate matrix */
+ loc_eul_size_to_mat4(r_mat, offset, rot, scale);
+
+ copy_m4_m4(r_offset, r_mat);
+
+ /* offset object */
+ if (mmd->object) {
+ float mat_offset[4][4];
+ float obinv[4][4];
+
+ unit_m4(mat_offset);
+ add_v3_v3(mat_offset[3], mmd->offset);
+ invert_m4_m4(obinv, ob->obmat);
+
+ mul_m4_series(r_offset, mat_offset,
+ obinv, mmd->object->obmat);
+ copy_m4_m4(mat_offset, r_offset);
+
+ /* clear r_mat locations to avoid double transform */
+ zero_v3(r_mat[3]);
+ }
+}
+
+/* array modifier - generate geometry callback (for viewport/rendering) */
+static void generate_geometry(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
+ ListBase stroke_cache = {NULL, NULL};
+ bGPDstroke *gps;
+ int idx;
+
+ /* Check which strokes we can use once, and store those results in an array
+ * for quicker checking of what's valid (since string comparisons are expensive)
+ */
+ const int num_strokes = BLI_listbase_count(&gpf->strokes);
+ int num_valid = 0;
+
+ bool *valid_strokes = MEM_callocN(sizeof(bool) * num_strokes, __func__);
+
+ for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) {
+ /* Record whether this stroke can be used
+ * ATTENTION: The logic here is the inverse of what's used everywhere else!
+ */
+ if (is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 1, gpl, gps,
+ mmd->flag & GP_ARRAY_INVERT_LAYER, mmd->flag & GP_ARRAY_INVERT_PASS,
+ mmd->flag & GP_ARRAY_INVERT_LAYERPASS))
+ {
+ valid_strokes[idx] = true;
+ num_valid++;
+ }
+ }
+
+ /* Early exit if no strokes can be copied */
+ if (num_valid == 0) {
+ if (G.debug & G_DEBUG) {
+ printf("GP Array Mod - No strokes to be included\n");
+ }
+
+ MEM_SAFE_FREE(valid_strokes);
+ return;
+ }
+
+
+ /* Generate new instances of all existing strokes,
+ * keeping each instance together so they maintain
+ * the correct ordering relative to each other
+ */
+ float current_offset[4][4];
+ unit_m4(current_offset);
+
+ for (int x = 0; x < mmd->count; x++) {
+ /* original strokes are at index = 0 */
+ if (x == 0) {
+ continue;
+ }
+
+ /* Compute transforms for this instance */
+ float mat[4][4];
+ float mat_offset[4][4];
+ BKE_gpencil_instance_modifier_instance_tfm(ob, mmd, x, mat, mat_offset);
+
+ if (mmd->object) {
+ /* recalculate cumulative offset here */
+ mul_m4_m4m4(current_offset, current_offset, mat_offset);
+ }
+ else {
+ copy_m4_m4(current_offset, mat);
+ }
+ /* apply shift */
+ madd_v3_v3fl(current_offset[3], mmd->shift, x);
+
+ /* Duplicate original strokes to create this instance */
+ for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) {
+ /* check if stroke can be duplicated */
+ if (valid_strokes[idx]) {
+ /* Duplicate stroke */
+ bGPDstroke *gps_dst = MEM_dupallocN(gps);
+ gps_dst->points = MEM_dupallocN(gps->points);
+ if (gps->dvert) {
+ gps_dst->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gps_dst);
+ }
+ gps_dst->triangles = MEM_dupallocN(gps->triangles);
+
+ /* Move points */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps_dst->points[i];
+ if (mmd->object) {
+ /* apply local changes (rot/scale) */
+ mul_m4_v3(mat, &pt->x);
+ }
+ /* global changes */
+ mul_m4_v3(current_offset, &pt->x);
+ }
+
+ /* if replace material, use new one */
+ if ((mmd->mat_rpl > 0) && (mmd->mat_rpl <= ob->totcol)) {
+ gps_dst->mat_nr = mmd->mat_rpl - 1;
+ }
+
+ /* Add new stroke to cache, to be added to the frame once
+ * all duplicates have been made
+ */
+ BLI_addtail(&stroke_cache, gps_dst);
+ }
+ }
+ }
+
+ /* merge newly created stroke instances back into the main stroke list */
+ if (mmd->flag & GP_ARRAY_KEEP_ONTOP) {
+ BLI_movelisttolist_reverse(&gpf->strokes, &stroke_cache);
+ }
+ else {
+ BLI_movelisttolist(&gpf->strokes, &stroke_cache);
+ }
+
+ /* free temp data */
+ MEM_SAFE_FREE(valid_strokes);
+}
+
+static void bakeModifier(
+ Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ generate_geometry(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+}
+
+/* -------------------------------- */
+
+/* Generic "generateStrokes" callback */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ generate_geometry(md, depsgraph, ob, gpl, gpf);
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ ArrayGpencilModifierData *lmd = (ArrayGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Array Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Array Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Array Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+static int getDuplicationFactor(GpencilModifierData *md)
+{
+ ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
+ int t = mmd->count;
+ CLAMP_MIN(t, 1);
+ return t;
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Array = {
+ /* name */ "Array",
+ /* structName */ "ArrayGpencilModifierData",
+ /* structSize */ sizeof(ArrayGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ getDuplicationFactor,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
new file mode 100644
index 00000000000..ba814c8538a
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -0,0 +1,557 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ BuildGpencilModifierData *gpmd = (BuildGpencilModifierData *)md;
+
+ /* We deliberately set this range to the half the default
+ * frame-range to have an immediate effect ot suggest use-cases
+ */
+ gpmd->start_frame = 1;
+ gpmd->end_frame = 125;
+
+ /* Init default length of each build effect - Nothing special */
+ gpmd->start_delay = 0.0f;
+ gpmd->length = 100.0f;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static bool dependsOnTime(GpencilModifierData *UNUSED(md))
+{
+ return true;
+}
+
+/* ******************************************** */
+/* Build Modifier - Stroke generation logic
+ *
+ * There are two modes for how the strokes are sequenced (at a macro-level):
+ * - Sequential Mode - Strokes appear/disappear one after the other. Only a single one changes at a time.
+ * - Concurrent Mode - Multiple strokes appear/disappear at once.
+ *
+ * Assumptions:
+ * - Stroke points are generally equally spaced. This implies that we can just add/remove points,
+ * without worrying about distances between them / adding extra interpolated points between
+ * an visible point and one about to be added/removed (or any similar tapering effects).
+
+ * - All strokes present are fully visible (i.e. we don't have to ignore any)
+ */
+
+/* Remove a particular stroke */
+static void clear_stroke(bGPDframe *gpf, bGPDstroke *gps)
+{
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+}
+
+/* Clear all strokes in frame */
+static void gpf_clear_all_strokes(bGPDframe *gpf)
+{
+ bGPDstroke *gps, *gps_next;
+ for (gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ clear_stroke(gpf, gps);
+ }
+ BLI_listbase_clear(&gpf->strokes);
+}
+
+/* Reduce the number of points in the stroke
+ *
+ * Note: This won't be called if all points are present/removed
+ * TODO: Allow blending of growing/shrinking tip (e.g. for more gradual transitions)
+ */
+static void reduce_stroke_points(bGPDstroke *gps, const int num_points, const eBuildGpencil_Transition transition)
+{
+ bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * num_points, __func__);
+ MDeformVert *new_dvert = NULL;
+ if (gps->dvert != NULL) {
+ new_dvert = MEM_callocN(sizeof(MDeformVert) * num_points, __func__);
+ }
+
+ /* Which end should points be removed from */
+ // TODO: free stroke weights
+ switch (transition) {
+ case GP_BUILD_TRANSITION_GROW: /* Show in forward order = Remove ungrown-points from end of stroke */
+ case GP_BUILD_TRANSITION_SHRINK: /* Hide in reverse order = Remove dead-points from end of stroke */
+ {
+ /* copy over point data */
+ memcpy(new_points, gps->points, sizeof(bGPDspoint) * num_points);
+ if (gps->dvert != NULL) {
+ memcpy(new_dvert, gps->dvert, sizeof(MDeformVert) * num_points);
+
+ /* free unused point weights */
+ for (int i = num_points; i < gps->totpoints; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+ }
+ break;
+ }
+
+ /* Hide in forward order = Remove points from start of stroke */
+ case GP_BUILD_TRANSITION_FADE:
+ {
+ /* num_points is the number of points left after reducing.
+ * We need to know how many to remove
+ */
+ const int offset = gps->totpoints - num_points;
+
+ /* copy over point data */
+ memcpy(new_points, gps->points + offset, sizeof(bGPDspoint) * num_points);
+ if (gps->dvert != NULL) {
+ memcpy(new_dvert, gps->dvert + offset, sizeof(MDeformVert) * num_points);
+
+ /* free unused weights */
+ for (int i = 0; i < offset; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+ }
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown transition %d in %s()\n", (int)transition, __func__);
+ break;
+ }
+
+ /* replace stroke geometry */
+ MEM_SAFE_FREE(gps->points);
+ MEM_SAFE_FREE(gps->dvert);
+ gps->points = new_points;
+ gps->dvert = new_dvert;
+ gps->totpoints = num_points;
+
+ /* mark stroke as needing to have its geometry caches rebuilt */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ MEM_SAFE_FREE(gps->triangles);
+}
+
+/* --------------------------------------------- */
+
+/* Stroke Data Table Entry - This represents one stroke being generated */
+typedef struct tStrokeBuildDetails {
+ bGPDstroke *gps;
+
+ /* Indices - first/last indices for the stroke's points (overall) */
+ size_t start_idx, end_idx;
+
+ /* Number of points - Cache for more convenient access */
+ int totpoints;
+} tStrokeBuildDetails;
+
+
+/* Sequential - Show strokes one after the other */
+static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
+{
+ const size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
+ bGPDstroke *gps;
+ size_t i;
+
+ /* 1) Compute proportion of time each stroke should occupy */
+ /* NOTE: This assumes that the total number of points won't overflow! */
+ tStrokeBuildDetails *table = MEM_callocN(sizeof(tStrokeBuildDetails) * tot_strokes, __func__);
+ size_t totpoints = 0;
+
+ /* 1.1) First pass - Tally up points */
+ for (gps = gpf->strokes.first, i = 0; gps; gps = gps->next, i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ cell->gps = gps;
+ cell->totpoints = gps->totpoints;
+
+ totpoints += cell->totpoints;
+ }
+
+ /* 1.2) Second pass - Compute the overall indices for points */
+ for (i = 0; i < tot_strokes; i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ if (i == 0) {
+ cell->start_idx = 0;
+ }
+ else {
+ cell->start_idx = (cell - 1)->end_idx;
+ }
+ cell->end_idx = cell->start_idx + cell->totpoints - 1;
+ }
+
+
+ /* 2) Determine the global indices for points that should be visible */
+ size_t first_visible = 0;
+ size_t last_visible = 0;
+
+ switch (mmd->transition) {
+ /* Show in forward order
+ * - As fac increases, the number of visible points increases
+ */
+ case GP_BUILD_TRANSITION_GROW:
+ first_visible = 0; /* always visible */
+ last_visible = (size_t)roundf(totpoints * fac);
+ break;
+
+ /* Hide in reverse order
+ * - As fac increases, the number of points visible at the end decreases
+ */
+ case GP_BUILD_TRANSITION_SHRINK:
+ first_visible = 0; /* always visible (until last point removed) */
+ last_visible = (size_t)(totpoints * (1.0f - fac));
+ break;
+
+ /* Hide in forward order
+ * - As fac increases, the early points start getting hidden
+ */
+ case GP_BUILD_TRANSITION_FADE:
+ first_visible = (size_t)(totpoints * fac);
+ last_visible = totpoints; /* i.e. visible until the end, unless first overlaps this */
+ break;
+ }
+
+
+ /* 3) Go through all strokes, deciding which to keep, and/or how much of each to keep */
+ for (i = 0; i < tot_strokes; i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ /* Determine what portion of the stroke is visible */
+ if ((cell->end_idx < first_visible) || (cell->start_idx > last_visible)) {
+ /* Not visible at all - Either ended before */
+ clear_stroke(gpf, cell->gps);
+ }
+ else {
+ /* Some proportion of stroke is visible */
+ /* XXX: Will the transition settings still be valid now? */
+ if ((first_visible <= cell->start_idx) && (last_visible >= cell->end_idx)) {
+ /* Do nothing - whole stroke is visible */
+ }
+ else if (first_visible > cell->start_idx) {
+ /* Starts partway through this stroke */
+ int num_points = cell->end_idx - first_visible;
+ reduce_stroke_points(cell->gps, num_points, mmd->transition);
+ }
+ else {
+ /* Ends partway through this stroke */
+ int num_points = last_visible - cell->start_idx;
+ reduce_stroke_points(cell->gps, num_points, mmd->transition);
+ }
+ }
+ }
+
+ /* Free table */
+ MEM_freeN(table);
+}
+
+/* --------------------------------------------- */
+
+/* Concurrent - Show multiple strokes at once */
+// TODO: Allow random offsets to start times
+// TODO: Allow varying speeds? Scaling of progress?
+static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
+{
+ bGPDstroke *gps, *gps_next;
+ int max_points = 0;
+
+ const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
+
+ /* 1) Determine the longest stroke, to figure out when short strokes should start */
+ /* FIXME: A *really* long stroke here could dwarf everything else, causing bad timings */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->totpoints > max_points) {
+ max_points = gps->totpoints;
+ }
+ }
+ if (max_points == 0) {
+ printf("ERROR: Strokes are all empty (GP Build Modifier: %s)\n", __func__);
+ return;
+ }
+
+ /* 2) For each stroke, determine how it should be handled */
+ for (gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+
+ /* Relative Length of Stroke - Relative to the longest stroke,
+ * what proportion of the available time should this stroke use
+ */
+ const float relative_len = (float)gps->totpoints / (float)max_points;
+
+ /* Determine how many points should be left in the stroke */
+ int num_points = 0;
+
+ switch (mmd->time_alignment) {
+ case GP_BUILD_TIMEALIGN_START: /* all start on frame 1 */
+ {
+ /* Build effect occurs over when fac = 0, to fac = relative_len */
+ if (fac <= relative_len) {
+ /* Scale fac to fit relative_len */
+ /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */
+ const float scaled_fac = fac / relative_len;
+
+ if (reverse) {
+ num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
+ }
+ else {
+ num_points = (int)roundf(scaled_fac * gps->totpoints);
+ }
+ }
+ else {
+ /* Build effect has ended */
+ if (reverse) {
+ num_points = 0;
+ }
+ else {
+ num_points = gps->totpoints;
+ }
+ }
+
+ break;
+ }
+ case GP_BUILD_TIMEALIGN_END: /* all end on same frame */
+ {
+ /* Build effect occurs over 1.0 - relative_len, to 1.0 (i.e. over the end of the range) */
+ const float start_fac = 1.0f - relative_len;
+
+ if (fac >= start_fac) {
+ /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */
+ const float scaled_fac = (fac - start_fac) / relative_len;
+
+ if (reverse) {
+ num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
+ }
+ else {
+ num_points = (int)roundf(scaled_fac * gps->totpoints);
+ }
+ }
+ else {
+ /* Build effect hasn't started */
+ if (reverse) {
+ num_points = gps->totpoints;
+ }
+ else {
+ num_points = 0;
+ }
+ }
+
+ break;
+ }
+
+ /* TODO... */
+ }
+
+ /* Modify the stroke geometry */
+ if (num_points <= 0) {
+ /* Nothing Left - Delete the stroke */
+ clear_stroke(gpf, gps);
+ }
+ else if (num_points < gps->totpoints) {
+ /* Remove some points */
+ reduce_stroke_points(gps, num_points, mmd->transition);
+ }
+ }
+}
+
+/* --------------------------------------------- */
+
+/* Entry-point for Build Modifier */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *UNUSED(ob), bGPDlayer *gpl, bGPDframe *gpf)
+{
+ BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
+ const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
+
+ const float ctime = DEG_get_ctime(depsgraph);
+ //printf("GP Build Modifier - %f\n", ctime);
+
+ /* Early exit if it's an empty frame */
+ if (gpf->strokes.first == NULL) {
+ return;
+ }
+
+ /* Omit layer if filter by layer */
+ if (mmd->layername[0] != '\0') {
+ if ((mmd->flag & GP_BUILD_INVERT_LAYER) == 0) {
+ if (!STREQ(mmd->layername, gpl->info)) {
+ return;
+ }
+ }
+ else {
+ if (STREQ(mmd->layername, gpl->info)) {
+ return;
+ }
+ }
+ }
+ /* verify layer pass */
+ if (mmd->layer_pass > 0) {
+ if ((mmd->flag & GP_BUILD_INVERT_LAYERPASS) == 0) {
+ if (gpl->pass_index != mmd->layer_pass) {
+ return;
+ }
+ }
+ else {
+ if (gpl->pass_index == mmd->layer_pass) {
+ return;
+ }
+ }
+ }
+
+ /* Early exit if outside of the frame range for this modifier
+ * (e.g. to have one forward, and one backwards modifier)
+ */
+ if (mmd->flag & GP_BUILD_RESTRICT_TIME) {
+ if ((ctime < mmd->start_frame) || (ctime > mmd->end_frame)) {
+ return;
+ }
+ }
+
+ /* Compute start and end frames for the animation effect
+ * By default, the upper bound is given by the "maximum length" setting
+ */
+ float start_frame = gpf->framenum + mmd->start_delay;
+ float end_frame = gpf->framenum + mmd->length;
+
+ if (gpf->next) {
+ /* Use the next frame or upper bound as end frame, whichever is lower/closer */
+ end_frame = MIN2(end_frame, gpf->next->framenum);
+ }
+
+
+ /* Early exit if current frame is outside start/end bounds */
+ /* NOTE: If we're beyond the next/prev frames (if existent), then we wouldn't have this problem anyway... */
+ if (ctime < start_frame) {
+ /* Before Start - Animation hasn't started. Display initial state. */
+ if (reverse) {
+ /* 1) Reverse = Start with all, end with nothing.
+ * ==> Do nothing (everything already present)
+ */
+ }
+ else {
+ /* 2) Forward Order = Start with nothing, end with the full frame.
+ * ==> Free all strokes, and return an empty frame
+ */
+ gpf_clear_all_strokes(gpf);
+ }
+
+ /* Early exit */
+ return;
+ }
+ else if (ctime >= end_frame) {
+ /* Past End - Animation finished. Display final result. */
+ if (reverse) {
+ /* 1) Reverse = Start with all, end with nothing.
+ * ==> Free all strokes, and return an empty frame
+ */
+ gpf_clear_all_strokes(gpf);
+ }
+ else {
+ /* 2) Forward Order = Start with nothing, end with the full frame.
+ * ==> Do Nothing (everything already present)
+ */
+ }
+
+ /* Early exit */
+ return;
+ }
+
+
+ /* Determine how far along we are between the keyframes */
+ float fac = (ctime - start_frame) / (end_frame - start_frame);
+ //printf(" Progress on %d = %f (%f - %f)\n", gpf->framenum, fac, start_frame, end_frame);
+
+ /* Time management mode */
+ switch (mmd->mode) {
+ case GP_BUILD_MODE_SEQUENTIAL:
+ build_sequential(mmd, gpf, fac);
+ break;
+
+ case GP_BUILD_MODE_CONCURRENT:
+ build_concurrent(mmd, gpf, fac);
+ break;
+
+ default:
+ printf("Unsupported build mode (%d) for GP Build Modifier: '%s'\n", mmd->mode, mmd->modifier.name);
+ break;
+ }
+}
+
+
+/* ******************************************** */
+
+GpencilModifierTypeInfo modifierType_Gpencil_Build = {
+ /* name */ "Build",
+ /* structName */ "BuildGpencilModifierData",
+ /* structSize */ sizeof(BuildGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_NoApply,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ NULL,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ dependsOnTime,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
new file mode 100644
index 00000000000..94c5e9ddbdf
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -0,0 +1,168 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math_color.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ ARRAY_SET_ITEMS(gpmd->hsv, 1.0f, 1.0f, 1.0f);
+ gpmd->layername[0] = '\0';
+ gpmd->flag |= GP_COLOR_CREATE_COLORS;
+ gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* color correction strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+
+ ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
+ float hsv[3], factor[3];
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 1, gpl, gps,
+ mmd->flag & GP_COLOR_INVERT_LAYER, mmd->flag & GP_COLOR_INVERT_PASS,
+ mmd->flag & GP_COLOR_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ copy_v3_v3(factor, mmd->hsv);
+ add_v3_fl(factor, -1.0f);
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+ rgb_to_hsv_v(gps->runtime.tmp_stroke_rgba, hsv);
+ add_v3_v3(hsv, factor);
+ CLAMP3(hsv, 0.0f, 1.0f);
+ hsv_to_rgb_v(hsv, gps->runtime.tmp_stroke_rgba);
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ rgb_to_hsv_v(gps->runtime.tmp_fill_rgba, hsv);
+ add_v3_v3(hsv, factor);
+ CLAMP3(hsv, 0.0f, 1.0f);
+ hsv_to_rgb_v(hsv, gps->runtime.tmp_fill_rgba);
+ }
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ GHash *gh_color = BLI_ghash_str_new("GP_Color modifier");
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ if (mat == NULL)
+ continue;
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+ /* skip stroke if it doesn't have color info */
+ if (ELEM(NULL, gp_style))
+ continue;
+
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ deformStroke(md, depsgraph, ob, gpl, gps);
+
+ gpencil_apply_modifier_material(
+ bmain, ob, mat, gh_color, gps,
+ (bool)(mmd->flag & GP_COLOR_CREATE_COLORS));
+ }
+ }
+ }
+ /* free hash buffers */
+ if (gh_color) {
+ BLI_ghash_free(gh_color, NULL, NULL);
+ gh_color = NULL;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Color = {
+ /* name */ "Hue/Saturation",
+ /* structName */ "ColorGpencilModifierData",
+ /* structSize */ sizeof(ColorGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
new file mode 100644
index 00000000000..97f260f307f
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -0,0 +1,357 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_modifier_types.h"
+#include "BLI_math.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_context.h"
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+/* temp struct to hold data */
+struct GPHookData_cb {
+ struct CurveMapping *curfalloff;
+
+ char falloff_type;
+ float falloff;
+ float falloff_sq;
+ float fac_orig;
+
+ unsigned int use_falloff : 1;
+ unsigned int use_uniform : 1;
+
+ float cent[3];
+
+ float mat_uniform[3][3];
+ float mat[4][4];
+};
+
+static void initData(GpencilModifierData *md)
+{
+ HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->force = 0.5f;
+ gpmd->falloff_type = eGPHook_Falloff_Smooth;
+ gpmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curfalloff) {
+ curvemapping_initialize(gpmd->curfalloff);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ HookGpencilModifierData *gmd = (HookGpencilModifierData *)md;
+ HookGpencilModifierData *tgmd = (HookGpencilModifierData *)target;
+
+ if (tgmd->curfalloff != NULL) {
+ curvemapping_free(tgmd->curfalloff);
+ tgmd->curfalloff = NULL;
+ }
+
+ BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curfalloff = curvemapping_copy(gmd->curfalloff);
+}
+
+/* calculate factor of fallof */
+static float gp_hook_falloff(const struct GPHookData_cb *tData, const float len_sq)
+{
+ BLI_assert(tData->falloff_sq);
+ if (len_sq > tData->falloff_sq) {
+ return 0.0f;
+ }
+ else if (len_sq > 0.0f) {
+ float fac;
+
+ if (tData->falloff_type == eGPHook_Falloff_Const) {
+ fac = 1.0f;
+ goto finally;
+ }
+ else if (tData->falloff_type == eGPHook_Falloff_InvSquare) {
+ /* avoid sqrt below */
+ fac = 1.0f - (len_sq / tData->falloff_sq);
+ goto finally;
+ }
+
+ fac = 1.0f - (sqrtf(len_sq) / tData->falloff);
+
+ switch (tData->falloff_type) {
+ case eGPHook_Falloff_Curve:
+ fac = curvemapping_evaluateF(tData->curfalloff, 0, fac);
+ break;
+ case eGPHook_Falloff_Sharp:
+ fac = fac * fac;
+ break;
+ case eGPHook_Falloff_Smooth:
+ fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
+ break;
+ case eGPHook_Falloff_Root:
+ fac = sqrtf(fac);
+ break;
+ case eGPHook_Falloff_Linear:
+ /* pass */
+ break;
+ case eGPHook_Falloff_Sphere:
+ fac = sqrtf(2 * fac - fac * fac);
+ break;
+ default:
+ break;
+ }
+
+ finally:
+ return fac * tData->fac_orig;
+ }
+ else {
+ return tData->fac_orig;
+ }
+}
+
+/* apply point deformation */
+static void gp_hook_co_apply(struct GPHookData_cb *tData, float weight, bGPDspoint *pt)
+{
+ float fac;
+
+ if (tData->use_falloff) {
+ float len_sq;
+
+ if (tData->use_uniform) {
+ float co_uniform[3];
+ mul_v3_m3v3(co_uniform, tData->mat_uniform, &pt->x);
+ len_sq = len_squared_v3v3(tData->cent, co_uniform);
+ }
+ else {
+ len_sq = len_squared_v3v3(tData->cent, &pt->x);
+ }
+
+ fac = gp_hook_falloff(tData, len_sq);
+ }
+ else {
+ fac = tData->fac_orig;
+ }
+
+ if (fac) {
+ float co_tmp[3];
+ mul_v3_m4v3(co_tmp, tData->mat, &pt->x);
+ interp_v3_v3v3(&pt->x, &pt->x, co_tmp, fac * weight);
+ }
+}
+
+/* deform stroke */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+ if (!mmd->object) {
+ return;
+ }
+
+ const int def_nr = defgroup_name_index(ob, mmd->vgname);
+
+ bPoseChannel *pchan = BKE_pose_channel_find_name(mmd->object->pose, mmd->subtarget);
+ float dmat[4][4];
+ struct GPHookData_cb tData;
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 3, gpl, gps,
+ mmd->flag & GP_HOOK_INVERT_LAYER, mmd->flag & GP_HOOK_INVERT_PASS,
+ mmd->flag & GP_HOOK_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ /* init struct */
+ tData.curfalloff = mmd->curfalloff;
+ tData.falloff_type = mmd->falloff_type;
+ tData.falloff = (mmd->falloff_type == eHook_Falloff_None) ? 0.0f : mmd->falloff;
+ tData.falloff_sq = SQUARE(tData.falloff);
+ tData.fac_orig = mmd->force;
+ tData.use_falloff = (tData.falloff_sq != 0.0f);
+ tData.use_uniform = (mmd->flag & GP_HOOK_UNIFORM_SPACE) != 0;
+
+ if (tData.use_uniform) {
+ copy_m3_m4(tData.mat_uniform, mmd->parentinv);
+ mul_v3_m3v3(tData.cent, tData.mat_uniform, mmd->cent);
+ }
+ else {
+ unit_m3(tData.mat_uniform);
+ copy_v3_v3(tData.cent, mmd->cent);
+ }
+
+ /* get world-space matrix of target, corrected for the space the verts are in */
+ if (mmd->subtarget[0] && pchan) {
+ /* bone target if there's a matching pose-channel */
+ mul_m4_m4m4(dmat, mmd->object->obmat, pchan->pose_mat);
+ }
+ else {
+ /* just object target */
+ copy_m4_m4(dmat, mmd->object->obmat);
+ }
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_series(tData.mat, ob->imat, dmat, mmd->parentinv);
+
+ /* loop points and apply deform */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+
+ /* verify vertex group */
+ const float weight = get_modifier_point_weight(dvert, (mmd->flag & GP_HOOK_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+ gp_hook_co_apply(&tData, weight, pt);
+ }
+}
+
+/* FIXME: Ideally we be doing this on a copy of the main depsgraph
+ * (i.e. one where we don't have to worry about restoring state)
+ */
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL)
+ return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply hook effects on this frame
+ * NOTE: this assumes that we don't want hook animation on non-keyframed frames
+ */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* compute hook effects on this frame */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ if (mmd->curfalloff) {
+ curvemapping_free(mmd->curfalloff);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ return !mmd->object;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ HookGpencilModifierData *lmd = (HookGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Hook Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
+ /* name */ "Hook",
+ /* structName */ "HookGpencilModifierData",
+ /* structSize */ sizeof(HookGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
new file mode 100644
index 00000000000..1d8f2c20b59
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -0,0 +1,215 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_lattice.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->cache_data = NULL;
+ gpmd->strength = 1.0f;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ const int def_nr = defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 3, gpl, gps,
+ mmd->flag & GP_LATTICE_INVERT_LAYER, mmd->flag & GP_LATTICE_INVERT_PASS,
+ mmd->flag & GP_LATTICE_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ if (mmd->cache_data == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+
+ /* verify vertex group */
+ const float weight = get_modifier_point_weight(dvert, (mmd->flag & GP_LATTICE_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+ calc_latt_deform((struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight);
+ }
+}
+
+/* FIXME: Ideally we be doing this on a copy of the main depsgraph
+ * (i.e. one where we don't have to worry about restoring state)
+ */
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ struct LatticeDeformData *ldata = NULL;
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL)
+ return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply lattice effects on this frame
+ * NOTE: this assumes that we don't want lattice animation on non-keyframed frames
+ */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* recalculate lattice data */
+ BKE_gpencil_lattice_init(ob);
+
+ /* compute lattice effects on this frame */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+
+ /* free lingering data */
+ ldata = (struct LatticeDeformData *)mmd->cache_data;
+ if (ldata) {
+ end_latt_deform(ldata);
+ mmd->cache_data = NULL;
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ struct LatticeDeformData *ldata = (struct LatticeDeformData *)mmd->cache_data;
+ /* free deform data */
+ if (ldata) {
+ end_latt_deform(ldata);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+
+ return !mmd->object;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ LatticeGpencilModifierData *lmd = (LatticeGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
+ /* name */ "Lattice",
+ /* structName */ "LatticeGpencilModifierData",
+ /* structSize */ sizeof(LatticeGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_Single | eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
new file mode 100644
index 00000000000..7599e7e9bce
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -0,0 +1,230 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->flag |= GP_MIRROR_AXIS_X;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstroke *gps, int axis)
+{
+ int i;
+ bGPDspoint *pt;
+ float factor[3] = { 1.0f, 1.0f, 1.0f };
+ factor[axis] = -1.0f;
+
+ float clear[3] = { 0.0f, 0.0f, 0.0f };
+ clear[axis] = 1.0f;
+
+ float origin[3];
+ float mirror_origin[3];
+
+ copy_v3_v3(origin, ob->loc);
+ /* only works with current axis */
+ mul_v3_v3(origin, clear);
+ zero_v3(mirror_origin);
+
+ if (mmd->object) {
+ copy_v3_v3(mirror_origin, mmd->object->loc);
+ mul_v3_v3(mirror_origin, clear);
+ sub_v3_v3(origin, mirror_origin);
+ }
+ /* clear other axis */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(&pt->x, origin);
+ mul_v3_v3(&pt->x, factor);
+ add_v3_v3(&pt->x, mirror_origin);
+ }
+
+}
+
+/* Generic "generateStrokes" callback */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+ bGPDstroke *gps, *gps_new = NULL;
+ int tot_strokes;
+ int i;
+
+ /* check each axis for mirroring */
+ for (int xi = 0; xi < 3; ++xi) {
+ if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
+
+ /* count strokes to avoid infinite loop after adding new strokes to tail of listbase */
+ tot_strokes = BLI_listbase_count(&gpf->strokes);
+
+ for (i = 0, gps = gpf->strokes.first; i < tot_strokes; i++, gps = gps->next) {
+ if (is_stroke_affected_by_modifier(
+ ob, mmd->layername, mmd->pass_index, mmd->layer_pass,
+ 1, gpl, gps,
+ mmd->flag & GP_MIRROR_INVERT_LAYER,
+ mmd->flag & GP_MIRROR_INVERT_PASS,
+ mmd->flag & GP_MIRROR_INVERT_LAYERPASS))
+ {
+ gps_new = BKE_gpencil_stroke_duplicate(gps);
+ update_position(ob, mmd, gps_new, xi);
+ BLI_addtail(&gpf->strokes, gps_new);
+ }
+ }
+ }
+ }
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply mirror effects on this frame */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* compute mirror effects on this frame */
+ generateStrokes(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static bool isDisabled(GpencilModifierData *UNUSED(md), int UNUSED(userRenderParams))
+{
+ //MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+
+ return false;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ MirrorGpencilModifierData *lmd = (MirrorGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Mirror Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+static int getDuplicationFactor(GpencilModifierData *md)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+ int factor = 1;
+ /* create a duplication for each axis */
+ for (int xi = 0; xi < 3; ++xi) {
+ if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
+ factor++;
+ }
+ }
+ CLAMP_MIN(factor, 1);
+
+ return factor;
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
+ /* name */ "Mirror",
+ /* structName */ "MirrorGpencilModifierData",
+ /* structSize */ sizeof(MirrorGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ getDuplicationFactor,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
new file mode 100644
index 00000000000..097b5702721
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -0,0 +1,289 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_rand.h"
+
+#include "PIL_time.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->flag |= GP_NOISE_MOD_LOCATION;
+ gpmd->flag |= GP_NOISE_FULL_STROKE;
+ gpmd->flag |= GP_NOISE_USE_RANDOM;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->step = 1;
+ gpmd->scene_frame = -999999;
+ gpmd->gp_frame = -999999;
+
+ gpmd->vrand1 = 1.0;
+ gpmd->vrand2 = 1.0;
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+
+ if (mmd->rng != NULL) {
+ BLI_rng_free(mmd->rng);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static bool dependsOnTime(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+ return (mmd->flag & GP_NOISE_USE_RANDOM) != 0;
+}
+
+/* aply noise effect based on stroke direction */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+ bGPDspoint *pt0, *pt1;
+ MDeformVert *dvert = NULL;
+ float shift, vran, vdir;
+ float normal[3];
+ float vec1[3], vec2[3];
+ int sc_frame = 0;
+ int sc_diff = 0;
+ const int def_nr = defgroup_name_index(ob, mmd->vgname);
+
+ /* Random generator, only init once. */
+ if (mmd->rng == NULL) {
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= POINTER_AS_UINT(mmd);
+ mmd->rng = BLI_rng_new(rng_seed);
+ }
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 3, gpl, gps,
+ mmd->flag & GP_NOISE_INVERT_LAYER, mmd->flag & GP_NOISE_INVERT_PASS,
+ mmd->flag & GP_NOISE_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ sc_frame = (int)DEG_get_ctime(depsgraph);
+
+ zero_v3(vec2);
+
+ /* calculate stroke normal*/
+ BKE_gpencil_stroke_normal(gps, normal);
+
+ /* move points */
+ for (int i = 0; i < gps->totpoints; i++) {
+ if (((i == 0) || (i == gps->totpoints - 1)) && ((mmd->flag & GP_NOISE_MOVE_EXTREME) == 0)) {
+ continue;
+ }
+
+ /* last point is special */
+ if (i == gps->totpoints) {
+ if (gps->dvert) {
+ dvert = &gps->dvert[i - 2];
+ }
+ pt0 = &gps->points[i - 2];
+ pt1 = &gps->points[i - 1];
+ }
+ else {
+ if (gps->dvert) {
+ dvert = &gps->dvert[i - 1];
+ }
+ pt0 = &gps->points[i - 1];
+ pt1 = &gps->points[i];
+
+ }
+
+ /* verify vertex group */
+ const float weight = get_modifier_point_weight(dvert, (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+
+ /* initial vector (p0 -> p1) */
+ sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+ vran = len_v3(vec1);
+ /* vector orthogonal to normal */
+ cross_v3_v3v3(vec2, vec1, normal);
+ normalize_v3(vec2);
+ /* use random noise */
+ if (mmd->flag & GP_NOISE_USE_RANDOM) {
+ sc_diff = abs(mmd->scene_frame - sc_frame);
+ /* only recalc if the gp frame change or the number of scene frames is bigger than step */
+ if ((!gpl->actframe) || (mmd->gp_frame != gpl->actframe->framenum) ||
+ (sc_diff >= mmd->step))
+ {
+ vran = mmd->vrand1 = BLI_rng_get_float(mmd->rng);
+ vdir = mmd->vrand2 = BLI_rng_get_float(mmd->rng);
+ mmd->gp_frame = gpl->actframe->framenum;
+ mmd->scene_frame = sc_frame;
+ }
+ else {
+ vran = mmd->vrand1;
+ if (mmd->flag & GP_NOISE_FULL_STROKE) {
+ vdir = mmd->vrand2;
+ }
+ else {
+ int f = (mmd->vrand2 * 10.0f) + i;
+ vdir = f % 2;
+ }
+ }
+ }
+ else {
+ vran = 1.0f;
+ if (mmd->flag & GP_NOISE_FULL_STROKE) {
+ vdir = gps->totpoints % 2;
+ }
+ else {
+ vdir = i % 2;
+ }
+ mmd->gp_frame = -999999;
+ }
+
+ /* apply randomness to location of the point */
+ if (mmd->flag & GP_NOISE_MOD_LOCATION) {
+ /* factor is too sensitive, so need divide */
+ shift = ((vran * mmd->factor) / 1000.0f) * weight;
+ if (vdir > 0.5f) {
+ mul_v3_fl(vec2, shift);
+ }
+ else {
+ mul_v3_fl(vec2, shift * -1.0f);
+ }
+ add_v3_v3(&pt1->x, vec2);
+ }
+
+ /* apply randomness to thickness */
+ if (mmd->flag & GP_NOISE_MOD_THICKNESS) {
+ if (vdir > 0.5f) {
+ pt1->pressure -= pt1->pressure * vran * mmd->factor;
+ }
+ else {
+ pt1->pressure += pt1->pressure * vran * mmd->factor;
+ }
+ CLAMP_MIN(pt1->pressure, GPENCIL_STRENGTH_MIN);
+ }
+
+ /* apply randomness to color strength */
+ if (mmd->flag & GP_NOISE_MOD_STRENGTH) {
+ if (vdir > 0.5f) {
+ pt1->strength -= pt1->strength * vran * mmd->factor;
+ }
+ else {
+ pt1->strength += pt1->strength * vran * mmd->factor;
+ }
+ CLAMP_MIN(pt1->strength, GPENCIL_STRENGTH_MIN);
+ }
+ /* apply randomness to uv rotation */
+ if (mmd->flag & GP_NOISE_MOD_UV) {
+ if (vdir > 0.5f) {
+ pt1->uv_rot -= pt1->uv_rot * vran * mmd->factor;
+ }
+ else {
+ pt1->uv_rot += pt1->uv_rot * vran * mmd->factor;
+ }
+ CLAMP(pt1->uv_rot, -M_PI_2, M_PI_2);
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
+ /* name */ "Noise",
+ /* structName */ "NoiseGpencilModifierData",
+ /* structSize */ sizeof(NoiseGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ dependsOnTime,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
new file mode 100644
index 00000000000..2c2a5c2f994
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -0,0 +1,147 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ ARRAY_SET_ITEMS(gpmd->loc, 0.0f, 0.0f, 0.0f);
+ ARRAY_SET_ITEMS(gpmd->rot, 0.0f, 0.0f, 0.0f);
+ ARRAY_SET_ITEMS(gpmd->scale, 0.0f, 0.0f, 0.0f);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* change stroke offsetness */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ OffsetGpencilModifierData *mmd = (OffsetGpencilModifierData *)md;
+ const int def_nr = defgroup_name_index(ob, mmd->vgname);
+
+ float mat[4][4];
+ float loc[3], rot[3], scale[3];
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 1, gpl, gps,
+ mmd->flag & GP_OFFSET_INVERT_LAYER, mmd->flag & GP_OFFSET_INVERT_PASS,
+ mmd->flag & GP_OFFSET_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+
+ /* verify vertex group */
+ const float weight = get_modifier_point_weight(dvert, (mmd->flag & GP_OFFSET_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+ /* calculate matrix */
+ mul_v3_v3fl(loc, mmd->loc, weight);
+ mul_v3_v3fl(rot, mmd->rot, weight);
+ mul_v3_v3fl(scale, mmd->scale, weight);
+ add_v3_fl(scale, 1.0);
+ loc_eul_size_to_mat4(mat, loc, rot, scale);
+
+ mul_m4_v3(mat, &pt->x);
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Offset = {
+ /* name */ "Offset",
+ /* structName */ "OffsetGpencilModifierData",
+ /* structSize */ sizeof(OffsetGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
new file mode 100644
index 00000000000..7033b246e1c
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -0,0 +1,187 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_material.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->factor = 1.0f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->flag |= GP_OPACITY_CREATE_COLORS;
+ gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* opacity strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
+ const int def_nr = defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 1, gpl, gps,
+ mmd->flag & GP_OPACITY_INVERT_LAYER, mmd->flag & GP_OPACITY_INVERT_PASS,
+ mmd->flag & GP_OPACITY_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+ gps->runtime.tmp_stroke_rgba[3] *= mmd->factor;
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f) {
+ gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f);
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ gps->runtime.tmp_fill_rgba[3] *= mmd->factor;
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
+ gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP(gps->runtime.tmp_fill_rgba[3], 0.0f, 1.0f);
+ }
+
+ /* if opacity > 1.0, affect the strength of the stroke */
+ if (mmd->factor > 1.0f) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+
+ /* verify vertex group */
+ const float weight = get_modifier_point_weight(dvert, (mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ pt->strength += mmd->factor - 1.0f;
+ }
+ else {
+ pt->strength += (mmd->factor - 1.0f) * weight;
+ }
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ GHash *gh_color = BLI_ghash_str_new("GP_Opacity modifier");
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ if (mat == NULL)
+ continue;
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+ /* skip stroke if it doesn't have color info */
+ if (ELEM(NULL, gp_style))
+ continue;
+
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ deformStroke(md, depsgraph, ob, gpl, gps);
+
+ gpencil_apply_modifier_material(
+ bmain, ob, mat, gh_color, gps,
+ (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS));
+ }
+ }
+ }
+ /* free hash buffers */
+ if (gh_color) {
+ BLI_ghash_free(gh_color, NULL, NULL);
+ gh_color = NULL;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
+ /* name */ "Opacity",
+ /* structName */ "OpacityGpencilModifierData",
+ /* structSize */ sizeof(OpacityGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
new file mode 100644
index 00000000000..6ddf40df6c0
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -0,0 +1,127 @@
+/* ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_vec_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->step = 1;
+ gpmd->factor = 0.0f;
+ gpmd->layername[0] = '\0';
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SimplifyGpencilModifierData *mmd = (SimplifyGpencilModifierData *)md;
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 4, gpl, gps,
+ mmd->flag & GP_SIMPLIFY_INVERT_LAYER, mmd->flag & GP_SIMPLIFY_INVERT_PASS,
+ mmd->flag & GP_SIMPLIFY_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ if (mmd->mode == GP_SIMPLIFY_FIXED) {
+ for (int i = 0; i < mmd->step; i++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
+ }
+ else {
+ /* simplify stroke using Ramer-Douglas-Peucker algorithm */
+ BKE_gpencil_simplify_stroke(gps, mmd->factor);
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Simplify = {
+ /* name */ "Simplify",
+ /* structName */ "SimplifyGpencilModifierData",
+ /* structSize */ sizeof(SimplifyGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
new file mode 100644
index 00000000000..ece7ebc9816
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -0,0 +1,154 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->flag |= GP_SMOOTH_MOD_LOCATION;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->step = 1;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* aply smooth effect based on stroke direction */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md;
+ const int def_nr = defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 3, gpl, gps,
+ mmd->flag & GP_SMOOTH_INVERT_LAYER, mmd->flag & GP_SMOOTH_INVERT_PASS,
+ mmd->flag & GP_SMOOTH_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ /* smooth stroke */
+ if (mmd->factor > 0.0f) {
+ for (int r = 0; r < mmd->step; r++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+
+ /* verify vertex group */
+ const float weight = get_modifier_point_weight(
+ dvert, (mmd->flag & GP_SMOOTH_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+
+ const float val = mmd->factor * weight;
+ /* perform smoothing */
+ if (mmd->flag & GP_SMOOTH_MOD_LOCATION) {
+ BKE_gpencil_smooth_stroke(gps, i, val);
+ }
+ if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) {
+ BKE_gpencil_smooth_stroke_strength(gps, i, val);
+ }
+ if ((mmd->flag & GP_SMOOTH_MOD_THICKNESS) && (val > 0.0f)) {
+ /* thickness need to repeat process several times */
+ for (int r2 = 0; r2 < r * 10; r2++) {
+ BKE_gpencil_smooth_stroke_thickness(gps, i, val);
+ }
+ }
+ if (mmd->flag & GP_SMOOTH_MOD_UV) {
+ BKE_gpencil_smooth_stroke_uv(gps, i, val);
+ }
+ }
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
+ /* name */ "Smooth",
+ /* structName */ "SmoothGpencilModifierData",
+ /* structSize */ sizeof(SmoothGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
new file mode 100644
index 00000000000..71881de50fc
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
@@ -0,0 +1,131 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+ /** \file blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->level = 1;
+ gpmd->layername[0] = '\0';
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* subdivide stroke to get more control points */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 3, gpl, gps,
+ mmd->flag & GP_SUBDIV_INVERT_LAYER, mmd->flag & GP_SUBDIV_INVERT_PASS,
+ mmd->flag & GP_SUBDIV_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ BKE_gpencil_subdivide(gps, mmd->level, mmd->flag);
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+static int getDuplicationFactor(GpencilModifierData *md)
+{
+ SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+ int t = (mmd->level + 1) * (mmd->level + 1);
+ CLAMP_MIN(t, 2);
+ return t;
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
+ /* name */ "Subdivision",
+ /* structName */ "SubdivGpencilModifierData",
+ /* structSize */ sizeof(SubdivGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ getDuplicationFactor,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
new file mode 100644
index 00000000000..441cab909d3
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -0,0 +1,175 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->thickness = 2;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->curve_thickness = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_thickness) {
+ curvemapping_initialize(gpmd->curve_thickness);
+ }
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+
+ if (gpmd->curve_thickness) {
+ curvemapping_free(gpmd->curve_thickness);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ ThickGpencilModifierData *gmd = (ThickGpencilModifierData *)md;
+ ThickGpencilModifierData *tgmd = (ThickGpencilModifierData *)target;
+
+ if (tgmd->curve_thickness != NULL) {
+ curvemapping_free(tgmd->curve_thickness);
+ tgmd->curve_thickness = NULL;
+ }
+
+ BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curve_thickness = curvemapping_copy(gmd->curve_thickness);
+}
+
+/* change stroke thickness */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ ThickGpencilModifierData *mmd = (ThickGpencilModifierData *)md;
+ const int def_nr = defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 1, gpl, gps,
+ mmd->flag & GP_THICK_INVERT_LAYER, mmd->flag & GP_THICK_INVERT_PASS,
+ mmd->flag & GP_THICK_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ /* if normalize, set stroke thickness */
+ if (mmd->flag & GP_THICK_NORMALIZE) {
+ gps->thickness = mmd->thickness;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+ float curvef = 1.0f;
+ /* verify vertex group */
+ const float weight = get_modifier_point_weight(dvert, (mmd->flag & GP_THICK_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+
+ if (mmd->flag & GP_THICK_NORMALIZE) {
+ pt->pressure = 1.0f;
+ }
+ else {
+ if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) {
+ /* normalize value to evaluate curve */
+ float value = (float)i / (gps->totpoints - 1);
+ curvef = curvemapping_evaluateF(mmd->curve_thickness, 0, value);
+ }
+
+ pt->pressure += mmd->thickness * weight * curvef;
+ CLAMP_MIN(pt->pressure, 0.1f);
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Thick = {
+ /* name */ "Thickness",
+ /* structName */ "ThickGpencilModifierData",
+ /* structSize */ sizeof(ThickGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
new file mode 100644
index 00000000000..d90dea91af9
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
@@ -0,0 +1,191 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpenciltime.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)md;
+ gpmd->layername[0] = '\0';
+ gpmd->offset = 1;
+ gpmd->frame_scale = 1.0f;
+ gpmd->flag |= GP_TIME_KEEP_LOOP;
+ gpmd->sfra = 1;
+ gpmd->efra = 250;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static int remapTime(
+ struct GpencilModifierData *md, struct Depsgraph *UNUSED(depsgraph),
+ struct Scene *scene, struct Object *UNUSED(ob), struct bGPDlayer *gpl, int cfra)
+{
+ TimeGpencilModifierData *mmd = (TimeGpencilModifierData *)md;
+ const bool custom = mmd->flag & GP_TIME_CUSTOM_RANGE;
+ const bool invgpl = mmd->flag & GP_TIME_INVERT_LAYER;
+ const bool invpass = mmd->flag & GP_TIME_INVERT_LAYERPASS;
+ int sfra = custom ? mmd->sfra : scene->r.sfra;
+ int efra = custom ? mmd->efra : scene->r.efra;
+ CLAMP_MIN(sfra, 1);
+ CLAMP_MIN(efra, 1);
+ const int time_range = efra - sfra + 1;
+ int offset = mmd->offset;
+ int segments = 0;
+
+ /* omit if filter by layer */
+ if (mmd->layername[0] != '\0') {
+ if (invgpl == false) {
+ if (!STREQ(mmd->layername, gpl->info)) {
+ return cfra;
+ }
+ }
+ else {
+ if (STREQ(mmd->layername, gpl->info)) {
+ return cfra;
+ }
+ }
+ }
+ /* verify pass */
+ if (mmd->layer_pass > 0) {
+ if (invpass == false) {
+ if (gpl->pass_index != mmd->layer_pass) {
+ return cfra;
+ }
+ }
+ else {
+ if (gpl->pass_index == mmd->layer_pass) {
+ return cfra;
+ }
+ }
+ }
+
+ /* if fix mode, return predefined frame number */
+ if (mmd->mode == GP_TIME_MODE_FIX) {
+ return offset;
+ }
+
+ /* invert current frame number */
+ if (mmd->mode == GP_TIME_MODE_REVERSE) {
+ cfra = efra - cfra + sfra;
+ }
+
+ /* apply frame scale */
+ cfra *= mmd->frame_scale;
+
+ /* verify offset never is greater than frame range */
+ if (abs(offset) > time_range) {
+ offset = offset - ((offset / time_range) * time_range);
+ }
+
+ /* verify not outside range if loop is disabled */
+ if ((mmd->flag & GP_TIME_KEEP_LOOP) == 0) {
+ if (cfra + offset < sfra) {
+ return sfra;
+ }
+ if (cfra + offset > efra) {
+ return efra;
+ }
+ }
+
+ /* check frames before start */
+ if (cfra < sfra) {
+ segments = ((cfra + sfra) / time_range);
+ cfra = cfra + (segments * time_range);
+ }
+
+ /* check frames after end */
+ if (cfra > efra) {
+ segments = ((cfra - sfra) / time_range);
+ cfra = cfra - (segments * time_range);
+ }
+
+ if (mmd->flag & GP_TIME_KEEP_LOOP) {
+ const int nfra = cfra + offset;
+
+ /* if the sum of the cfra is out scene frame range, recalc */
+ if (cfra + offset < sfra) {
+ const int delta = abs(sfra - nfra);
+ return efra - delta + 1;
+ }
+ else if (cfra + offset > efra) {
+ return nfra - efra + sfra - 1;
+ }
+ }
+
+ return cfra + offset;
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Time = {
+ /* name */ "Time Offset",
+ /* structName */ "TimeGpencilModifierData",
+ /* structSize */ sizeof(TimeGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_NoApply,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ NULL,
+ /* remapTime */ remapTime,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
new file mode 100644
index 00000000000..385296c943e
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -0,0 +1,176 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ ARRAY_SET_ITEMS(gpmd->rgb, 1.0f, 1.0f, 1.0f);
+ gpmd->flag |= GP_TINT_CREATE_COLORS;
+ gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* tint strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, mmd->layer_pass, 1, gpl, gps,
+ mmd->flag & GP_TINT_INVERT_LAYER, mmd->flag & GP_TINT_INVERT_PASS,
+ mmd->flag & GP_TINT_INVERT_LAYERPASS))
+ {
+ return;
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+ interp_v3_v3v3(gps->runtime.tmp_stroke_rgba, gps->runtime.tmp_stroke_rgba, mmd->rgb, mmd->factor);
+ /* if factor is > 1, the alpha must be changed to get full tint */
+ if (mmd->factor > 1.0f) {
+ gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP4(gps->runtime.tmp_stroke_rgba, 0.0f, 1.0f);
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ interp_v3_v3v3(gps->runtime.tmp_fill_rgba, gps->runtime.tmp_fill_rgba, mmd->rgb, mmd->factor);
+ /* if factor is > 1, the alpha must be changed to get full tint */
+ if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
+ gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP4(gps->runtime.tmp_fill_rgba, 0.0f, 1.0f);
+ }
+
+ /* if factor > 1.0, affect the strength of the stroke */
+ if (mmd->factor > 1.0f) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->strength += mmd->factor - 1.0f;
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ GHash *gh_color = BLI_ghash_str_new("GP_Tint modifier");
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ if (mat == NULL)
+ continue;
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+ /* skip stroke if it doesn't have color info */
+ if (ELEM(NULL, gp_style))
+ continue;
+
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ deformStroke(md, depsgraph, ob, gpl, gps);
+
+ gpencil_apply_modifier_material(
+ bmain, ob, mat, gh_color, gps,
+ (bool)(mmd->flag & GP_TINT_CREATE_COLORS));
+ }
+ }
+ }
+ /* free hash buffers */
+ if (gh_color) {
+ BLI_ghash_free(gh_color, NULL, NULL);
+ gh_color = NULL;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
+ /* name */ "Tint",
+ /* structName */ "TintGpencilModifierData",
+ /* structSize */ sizeof(TintGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* getDuplicationFactor */ NULL,
+};
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 31cf2033714..2eb24f08227 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -23,6 +23,14 @@
#
# ***** END GPL LICENSE BLOCK *****
+# WITH_OPENGL limits the visibility of the opengl headers to just GPU and bg_gpu,
+# to more easily highlight codepadths in other libraries that need to be refactored,
+# bf_gpu is allowed to have opengl regardless of this option.
+
+if(NOT WITH_OPENGL)
+ add_definitions(-DWITH_OPENGL)
+endif()
+
set(INC
.
../blenkernel
@@ -31,6 +39,9 @@ set(INC
../imbuf
../makesdna
../makesrna
+ ../draw
+
+ ../editors/include
# For node muting stuff...
../nodes
@@ -46,67 +57,192 @@ set(INC_SYS
)
set(SRC
- intern/gpu_basic_shader.c
+ intern/gpu_attr_binding.c
+ intern/gpu_batch.c
+ intern/gpu_batch_presets.c
+ intern/gpu_batch_utils.c
intern/gpu_buffers.c
intern/gpu_codegen.c
- intern/gpu_compositing.c
+ intern/gpu_context.cpp
intern/gpu_debug.c
intern/gpu_draw.c
+ intern/gpu_element.c
intern/gpu_extensions.c
intern/gpu_framebuffer.c
+ intern/gpu_immediate.c
+ intern/gpu_immediate_util.c
intern/gpu_init_exit.c
intern/gpu_material.c
+ intern/gpu_matrix.c
+ intern/gpu_primitive.c
intern/gpu_select.c
intern/gpu_select_pick.c
intern/gpu_select_sample_query.c
intern/gpu_shader.c
+ intern/gpu_shader_interface.c
+ intern/gpu_state.c
intern/gpu_texture.c
+ intern/gpu_uniformbuffer.c
+ intern/gpu_vertex_buffer.c
+ intern/gpu_vertex_format.c
+ intern/gpu_viewport.c
- GPU_basic_shader.h
+ GPU_attr_binding.h
+ GPU_batch.h
+ GPU_batch_presets.h
+ GPU_batch_utils.h
GPU_buffers.h
- GPU_compositing.h
+ GPU_common.h
+ GPU_context.h
GPU_debug.h
GPU_draw.h
+ GPU_element.h
GPU_extensions.h
GPU_framebuffer.h
GPU_glew.h
+ GPU_immediate.h
+ GPU_immediate_util.h
GPU_init_exit.h
+ GPU_legacy_stubs.h
GPU_material.h
+ GPU_matrix.h
+ GPU_primitive.h
GPU_select.h
GPU_shader.h
+ GPU_shader_interface.h
+ GPU_state.h
GPU_texture.h
+ GPU_uniformbuffer.h
+ GPU_vertex_buffer.h
+ GPU_vertex_format.h
+ GPU_viewport.h
+
+ intern/gpu_attr_binding_private.h
+ intern/gpu_batch_private.h
intern/gpu_codegen.h
+ intern/gpu_context_private.h
+ intern/gpu_primitive_private.h
intern/gpu_private.h
intern/gpu_select_private.h
+ intern/gpu_shader_private.h
+ intern/gpu_vertex_format_private.h
)
+data_to_c_simple(shaders/gpu_shader_depth_only_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_checker_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_diag_stripes_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_simple_lighting_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_flat_id_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_area_borders_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_widget_base_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_widget_base_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_nodelink_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_nodelink_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_line_dashed_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_desaturate_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_linear_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_shuffle_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_mask_uniform_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_alpha_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_varying_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_depth_copy_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_interlace_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_multisample_resolve_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_normal_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_normal_smooth_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_passthrough_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl SRC)
+
+data_to_c_simple(shaders/gpu_shader_instance_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_screen_aligned_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_camera_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_distance_line_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_vert.glsl SRC)
+
+data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC)
+
+data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_point_uniform_color_aa_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_point_varying_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl SRC)
+
+data_to_c_simple(shaders/gpu_shader_2D_edituvs_points_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_edituvs_facedots_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_edituvs_faces_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_edituvs_stretch_vert.glsl SRC)
+
+data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_edges_front_back_ortho_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_edges_overlay_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_edges_overlay_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_edges_overlay_simple_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_edges_overlay_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_text_simple_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_text_simple_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_text_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_keyframe_diamond_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_keyframe_diamond_frag.glsl SRC)
+
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_smoke_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_basic_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_basic_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_basic_geom.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_ssao_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_dof_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_dof_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_dof_hq_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_dof_hq_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_dof_hq_geo.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_depth_resolve.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_fx_lib.glsl SRC)
-
-if(WITH_GAMEENGINE)
- add_definitions(-DWITH_GAMEENGINE)
-endif()
+
+data_to_c_simple(shaders/gpu_shader_gpencil_stroke_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_gpencil_stroke_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_gpencil_stroke_geom.glsl SRC)
+
+data_to_c_simple(shaders/gpu_shader_gpencil_fill_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC)
+
if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
@@ -118,8 +254,4 @@ if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
-if(WITH_OPENSUBDIV)
- add_definitions(-DWITH_OPENSUBDIV)
-endif()
-
blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/gpu/GPU_attr_binding.h b/source/blender/gpu/GPU_attr_binding.h
new file mode 100644
index 00000000000..186acacb71d
--- /dev/null
+++ b/source/blender/gpu/GPU_attr_binding.h
@@ -0,0 +1,42 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_attr_binding.h
+ * \ingroup gpu
+ *
+ * GPU vertex attribute binding
+ */
+
+#ifndef __GPU_ATTR_BINDING_H__
+#define __GPU_ATTR_BINDING_H__
+
+#include "GPU_common.h"
+
+typedef struct GPUAttrBinding {
+ uint64_t loc_bits; /* store 4 bits for each of the 16 attribs */
+ uint16_t enabled_bits; /* 1 bit for each attrib */
+} GPUAttrBinding;
+
+#endif /* __GPU_ATTR_BINDING_H__ */
diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h
deleted file mode 100644
index 230a5defe7b..00000000000
--- a/source/blender/gpu/GPU_basic_shader.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * ***** 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) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file GPU_basic_shader.h
- * \ingroup gpu
- */
-
-#ifndef __GPU_BASIC_SHADER_H__
-#define __GPU_BASIC_SHADER_H__
-
-#include "BLI_utildefines.h"
-#include "GPU_glew.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Fixed Function Shader */
-
-typedef enum GPUBasicShaderOption {
- GPU_SHADER_USE_COLOR = (1 << 0), /* use glColor, for lighting it replaces diffuse */
- GPU_SHADER_LIGHTING = (1 << 1), /* use lighting */
- GPU_SHADER_TWO_SIDED = (1 << 2), /* flip normals towards viewer */
- GPU_SHADER_TEXTURE_2D = (1 << 3), /* use 2D texture to replace diffuse color */
- GPU_SHADER_TEXTURE_RECT = (1 << 4), /* same as GPU_SHADER_TEXTURE_2D, for GL_TEXTURE_RECTANGLE */
-
- GPU_SHADER_SOLID_LIGHTING = (1 << 5), /* use faster lighting (set automatically) */
- GPU_SHADER_STIPPLE = (1 << 6), /* use stipple */
- GPU_SHADER_LINE = (1 << 7), /* draw lines */
- GPU_SHADER_FLAT_NORMAL = (1 << 8), /* use flat normals */
- GPU_SHADER_OPTIONS_NUM = 9,
- GPU_SHADER_OPTION_COMBINATIONS = (1 << GPU_SHADER_OPTIONS_NUM)
-} GPUBasicShaderOption;
-
-/* Keep these in sync with gpu_shader_basic_frag.glsl */
-typedef enum GPUBasicShaderStipple {
- GPU_SHADER_STIPPLE_HALFTONE = 0,
- GPU_SHADER_STIPPLE_QUARTTONE = 1,
- GPU_SHADER_STIPPLE_CHECKER_8PX = 2,
- GPU_SHADER_STIPPLE_HEXAGON = 3,
- GPU_SHADER_STIPPLE_DIAG_STRIPES = 4,
- GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP = 5,
- GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW = 6,
- GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP = 7,
- GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN = 8,
- GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP = 9,
- GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER = 10,
- GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP = 11
-} GPUBasicShaderStipple;
-
-void GPU_basic_shaders_init(void);
-void GPU_basic_shaders_exit(void);
-
-void GPU_basic_shader_bind(int options);
-void GPU_basic_shader_bind_enable(int options);
-void GPU_basic_shader_bind_disable(int options);
-
-int GPU_basic_shader_bound_options(void);
-
-/* Only use for small blocks of code that don't support glsl shader. */
-#define GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options) \
-if (GPU_basic_shader_use_glsl_get()) { \
- if ((bound_options = GPU_basic_shader_bound_options())) { \
- GPU_basic_shader_bind(0); \
- } \
-} \
-else { bound_options = 0; } ((void)0)
-#define GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options) \
-if (GPU_basic_shader_use_glsl_get()) { \
- if (bound_options) { \
- GPU_basic_shader_bind(bound_options); \
- } \
-} ((void)0)
-
-
-void GPU_basic_shader_colors(
- const float diffuse[3], const float specular[3],
- int shininess, float alpha);
-
-/* Fixed Function Lighting */
-
-typedef enum GPULightType {
- GPU_LIGHT_POINT,
- GPU_LIGHT_SPOT,
- GPU_LIGHT_SUN
-} GPULightType;
-
-typedef struct GPULightData {
- GPULightType type;
-
- float position[3];
- float direction[3];
-
- float diffuse[3];
- float specular[3];
-
- float constant_attenuation;
- float linear_attenuation;
- float quadratic_attenuation;
-
- float spot_cutoff;
- float spot_exponent;
-} GPULightData;
-
-void GPU_basic_shader_light_set(int light_num, GPULightData *light);
-void GPU_basic_shader_light_set_viewer(bool local);
-void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id);
-void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern);
-void GPU_basic_shader_line_width(float line_width);
-
-bool GPU_basic_shader_use_glsl_get(void);
-void GPU_basic_shader_use_glsl_set(bool enabled);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
new file mode 100644
index 00000000000..cf69af11aa6
--- /dev/null
+++ b/source/blender/gpu/GPU_batch.h
@@ -0,0 +1,209 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_batch.h
+ * \ingroup gpu
+ *
+ * GPU geometry batch
+ * Contains VAOs + VBOs + Shader representing a drawable entity.
+ */
+
+#ifndef __GPU_BATCH_H__
+#define __GPU_BATCH_H__
+
+#include "GPU_vertex_buffer.h"
+#include "GPU_element.h"
+#include "GPU_shader_interface.h"
+#include "GPU_shader.h"
+
+typedef enum {
+ GPU_BATCH_READY_TO_FORMAT,
+ GPU_BATCH_READY_TO_BUILD,
+ GPU_BATCH_BUILDING,
+ GPU_BATCH_READY_TO_DRAW
+} GPUBatchPhase;
+
+#define GPU_BATCH_VBO_MAX_LEN 3
+#define GPU_BATCH_VAO_STATIC_LEN 3
+#define GPU_BATCH_VAO_DYN_ALLOC_COUNT 16
+
+typedef struct GPUBatch {
+ /* geometry */
+ GPUVertBuf *verts[GPU_BATCH_VBO_MAX_LEN]; /* verts[0] is required, others can be NULL */
+ GPUVertBuf *inst; /* instance attribs */
+ GPUIndexBuf *elem; /* NULL if element list not needed */
+ uint32_t gl_prim_type;
+
+ /* cached values (avoid dereferencing later) */
+ uint32_t vao_id;
+ uint32_t program;
+ const struct GPUShaderInterface *interface;
+
+ /* book-keeping */
+ uint owns_flag;
+ struct GPUContext *context; /* used to free all vaos. this implies all vaos were created under the same context. */
+ GPUBatchPhase phase;
+ bool program_in_use;
+
+ /* Vao management: remembers all geometry state (vertex attrib bindings & element buffer)
+ * for each shader interface. Start with a static number of vaos and fallback to dynamic count
+ * if necessary. Once a batch goes dynamic it does not go back. */
+ bool is_dynamic_vao_count;
+ union {
+ /* Static handle count */
+ struct {
+ const struct GPUShaderInterface *interfaces[GPU_BATCH_VAO_STATIC_LEN];
+ uint32_t vao_ids[GPU_BATCH_VAO_STATIC_LEN];
+ } static_vaos;
+ /* Dynamic handle count */
+ struct {
+ uint count;
+ const struct GPUShaderInterface **interfaces;
+ uint32_t *vao_ids;
+ } dynamic_vaos;
+ };
+
+ /* XXX This is the only solution if we want to have some data structure using
+ * batches as key to identify nodes. We must destroy these nodes with this callback. */
+ void (*free_callback)(struct GPUBatch *, void *);
+ void *callback_data;
+} GPUBatch;
+
+enum {
+ GPU_BATCH_OWNS_VBO = (1 << 0),
+ /* each vbo index gets bit-shifted */
+ GPU_BATCH_OWNS_INSTANCES = (1 << 30),
+ GPU_BATCH_OWNS_INDEX = (1 << 31),
+};
+
+GPUBatch *GPU_batch_create_ex(GPUPrimType, GPUVertBuf *, GPUIndexBuf *, uint owns_flag);
+void GPU_batch_init_ex(GPUBatch *, GPUPrimType, GPUVertBuf *, GPUIndexBuf *, uint owns_flag);
+GPUBatch *GPU_batch_duplicate(GPUBatch *batch_src);
+
+#define GPU_batch_create(prim, verts, elem) \
+ GPU_batch_create_ex(prim, verts, elem, 0)
+#define GPU_batch_init(batch, prim, verts, elem) \
+ GPU_batch_init_ex(batch, prim, verts, elem, 0)
+
+void GPU_batch_discard(GPUBatch *); /* verts & elem are not discarded */
+
+void GPU_batch_vao_cache_clear(GPUBatch *);
+
+void GPU_batch_callback_free_set(GPUBatch *, void (*callback)(GPUBatch *, void *), void *);
+
+void GPU_batch_instbuf_set(GPUBatch *, GPUVertBuf *, bool own_vbo); /* Instancing */
+
+int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
+
+#define GPU_batch_vertbuf_add(batch, verts) \
+ GPU_batch_vertbuf_add_ex(batch, verts, false)
+
+void GPU_batch_program_set_no_use(GPUBatch *, uint32_t program, const GPUShaderInterface *);
+void GPU_batch_program_set(GPUBatch *, uint32_t program, const GPUShaderInterface *);
+void GPU_batch_program_set_builtin(GPUBatch *batch, GPUBuiltinShader shader_id);
+/* Entire batch draws with one shader program, but can be redrawn later with another program. */
+/* Vertex shader's inputs must be compatible with the batch's vertex format. */
+
+void GPU_batch_program_use_begin(GPUBatch *); /* call before Batch_Uniform (temp hack?) */
+void GPU_batch_program_use_end(GPUBatch *);
+
+void GPU_batch_uniform_1ui(GPUBatch *, const char *name, int value);
+void GPU_batch_uniform_1i(GPUBatch *, const char *name, int value);
+void GPU_batch_uniform_1b(GPUBatch *, const char *name, bool value);
+void GPU_batch_uniform_1f(GPUBatch *, const char *name, float value);
+void GPU_batch_uniform_2f(GPUBatch *, const char *name, float x, float y);
+void GPU_batch_uniform_3f(GPUBatch *, const char *name, float x, float y, float z);
+void GPU_batch_uniform_4f(GPUBatch *, const char *name, float x, float y, float z, float w);
+void GPU_batch_uniform_2fv(GPUBatch *, const char *name, const float data[2]);
+void GPU_batch_uniform_3fv(GPUBatch *, const char *name, const float data[3]);
+void GPU_batch_uniform_4fv(GPUBatch *, const char *name, const float data[4]);
+void GPU_batch_uniform_2fv_array(GPUBatch *, const char *name, int len, const float *data);
+void GPU_batch_uniform_4fv_array(GPUBatch *, const char *name, int len, const float *data);
+void GPU_batch_uniform_mat4(GPUBatch *, const char *name, const float data[4][4]);
+
+void GPU_batch_draw(GPUBatch *);
+
+/* This does not bind/unbind shader and does not call GPU_matrix_bind() */
+void GPU_batch_draw_range_ex(GPUBatch *, int v_first, int v_count, bool force_instance);
+
+/* Does not even need batch */
+void GPU_draw_primitive(GPUPrimType, int v_count);
+
+#if 0 /* future plans */
+
+/* Can multiple batches share a GPUVertBuf? Use ref count? */
+
+
+/* We often need a batch with its own data, to be created and discarded together. */
+/* WithOwn variants reduce number of system allocations. */
+
+typedef struct BatchWithOwnVertexBuffer {
+ GPUBatch batch;
+ GPUVertBuf verts; /* link batch.verts to this */
+} BatchWithOwnVertexBuffer;
+
+typedef struct BatchWithOwnElementList {
+ GPUBatch batch;
+ GPUIndexBuf elem; /* link batch.elem to this */
+} BatchWithOwnElementList;
+
+typedef struct BatchWithOwnVertexBufferAndElementList {
+ GPUBatch batch;
+ GPUIndexBuf elem; /* link batch.elem to this */
+ GPUVertBuf verts; /* link batch.verts to this */
+} BatchWithOwnVertexBufferAndElementList;
+
+GPUBatch *create_BatchWithOwnVertexBuffer(GPUPrimType, GPUVertFormat *, uint v_len, GPUIndexBuf *);
+GPUBatch *create_BatchWithOwnElementList(GPUPrimType, GPUVertBuf *, uint prim_len);
+GPUBatch *create_BatchWithOwnVertexBufferAndElementList(GPUPrimType, GPUVertFormat *, uint v_len, uint prim_len);
+/* verts: shared, own */
+/* elem: none, shared, own */
+GPUBatch *create_BatchInGeneral(GPUPrimType, VertexBufferStuff, ElementListStuff);
+
+#endif /* future plans */
+
+void gpu_batch_init(void);
+void gpu_batch_exit(void);
+
+/* Macros */
+
+#define GPU_BATCH_DISCARD_SAFE(batch) do { \
+ if (batch != NULL) { \
+ GPU_batch_discard(batch); \
+ batch = NULL; \
+ } \
+} while (0)
+
+#define GPU_BATCH_DISCARD_ARRAY_SAFE(_batch_array, _len) do { \
+ if (_batch_array != NULL) { \
+ BLI_assert(_len > 0); \
+ for (int _i = 0; _i < _len; _i++) { \
+ GPU_BATCH_DISCARD_SAFE(_batch_array[_i]); \
+ } \
+ MEM_freeN(_batch_array); \
+ } \
+} while (0)
+
+#endif /* __GPU_BATCH_H__ */
diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h
new file mode 100644
index 00000000000..d5cabf8bf90
--- /dev/null
+++ b/source/blender/gpu/GPU_batch_presets.h
@@ -0,0 +1,56 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_batch_presets.h
+ * \ingroup gpu
+ *
+ * Batched geometry rendering is powered by the GPU library.
+ * This file contains any additions or modifications specific to Blender.
+ */
+
+#ifndef __GPU_BATCH_PRESETS_H__
+#define __GPU_BATCH_PRESETS_H__
+
+struct rctf;
+struct GPUVertFormat;
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
+
+/* gpu_batch_presets.c */
+struct GPUVertFormat *GPU_batch_preset_format_3d(void);
+
+/* Replacement for gluSphere */
+struct GPUBatch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT;
+struct GPUBatch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT;
+
+void gpu_batch_presets_init(void);
+void gpu_batch_presets_register(struct GPUBatch *preset_batch);
+bool gpu_batch_presets_unregister(struct GPUBatch *preset_batch);
+void gpu_batch_presets_reset(void);
+void gpu_batch_presets_exit(void);
+
+#endif /* __GPU_BATCH_PRESETS_H__ */
diff --git a/source/blender/gpu/GPU_batch_utils.h b/source/blender/gpu/GPU_batch_utils.h
new file mode 100644
index 00000000000..05bbb6542ff
--- /dev/null
+++ b/source/blender/gpu/GPU_batch_utils.h
@@ -0,0 +1,44 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_batch_utils.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_BATCH_UTILS_H__
+#define __GPU_BATCH_UTILS_H__
+
+struct rctf;
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
+
+/* gpu_batch_utils.c */
+struct GPUBatch *GPU_batch_tris_from_poly_2d_encoded(
+ const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+struct GPUBatch *GPU_batch_wire_from_poly_2d_encoded(
+ const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect
+ ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
+/* Only use by draw manager. Use the presets function instead for interface. */
+struct GPUBatch *gpu_batch_sphere(int lat_res, int lon_res) ATTR_WARN_UNUSED_RESULT;
+
+#endif /* __GPU_BATCH_UTILS_H__ */
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 8fd34348f03..5b96312300b 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -32,193 +32,20 @@
#ifndef __GPU_BUFFERS_H__
#define __GPU_BUFFERS_H__
-#ifdef DEBUG
-/* #define DEBUG_VBO(X) printf(X)*/
-# define DEBUG_VBO(X)
-#else
-# define DEBUG_VBO(X)
-#endif
-
#include <stddef.h>
struct BMesh;
struct CCGElem;
struct CCGKey;
struct DMFlagMat;
-struct DerivedMesh;
struct GSet;
-struct GPUVertPointLink;
-struct GPUDrawObject;
-struct GridCommonGPUBuffer;
-struct PBVH;
+struct MLoop;
+struct MLoopTri;
+struct MPoly;
struct MVert;
+struct PBVH;
-typedef struct GPUBuffer {
- size_t size; /* in bytes */
- unsigned int id; /* used with vertex buffer objects */
-} GPUBuffer;
-
-typedef struct GPUBufferMaterial {
- /* range of points used for this material */
- unsigned int start;
- unsigned int totelements;
- unsigned int totloops;
- unsigned int *polys; /* array of polygons for this material */
- unsigned int totpolys; /* total polygons in polys */
- unsigned int totvisiblepolys; /* total visible polygons */
-
- /* original material index */
- short mat_nr;
-} GPUBufferMaterial;
-
-void GPU_buffer_material_finalize(struct GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat);
-
-/* meshes are split up by material since changing materials requires
- * GL state changes that can't occur in the middle of drawing an
- * array.
- *
- * some simplifying assumptions are made:
- * - all quads are treated as two triangles.
- * - no vertex sharing is used; each triangle gets its own copy of the
- * vertices it uses (this makes it easy to deal with a vertex used
- * by faces with different properties, such as smooth/solid shading,
- * different MCols, etc.)
- *
- * to avoid confusion between the original MVert vertices and the
- * arrays of OpenGL vertices, the latter are referred to here and in
- * the source as `points'. similarly, the OpenGL triangles generated
- * for MFaces are referred to as triangles rather than faces.
- */
-typedef struct GPUDrawObject {
- GPUBuffer *points;
- GPUBuffer *normals;
- GPUBuffer *uv;
- GPUBuffer *uv_tex;
- GPUBuffer *colors;
- GPUBuffer *edges;
- GPUBuffer *uvedges;
- GPUBuffer *triangles; /* triangle index buffer */
-
- /* for each original vertex, the list of related points */
- struct GPUVertPointLink *vert_points;
-
- /* see: USE_GPU_POINT_LINK define */
-#if 0
- /* storage for the vert_points lists */
- struct GPUVertPointLink *vert_points_mem;
- int vert_points_usage;
-#endif
-
- int colType;
-
- GPUBufferMaterial *materials;
- int totmaterial;
-
- unsigned int tot_triangle_point;
- unsigned int tot_loose_point;
- /* different than total loops since ngons get tesselated still */
- unsigned int tot_loop_verts;
-
- /* caches of the original DerivedMesh values */
- unsigned int totvert;
- unsigned int totedge;
-
- unsigned int loose_edge_offset;
- unsigned int tot_loose_edge_drawn;
- unsigned int tot_edge_drawn;
-
- /* for subsurf, offset where drawing of interior edges starts */
- unsigned int interior_offset;
- unsigned int totinterior;
-} GPUDrawObject;
-
-/* currently unused */
-// #define USE_GPU_POINT_LINK
-
-typedef struct GPUVertPointLink {
-#ifdef USE_GPU_POINT_LINK
- struct GPUVertPointLink *next;
-#endif
- /* -1 means uninitialized */
- int point_index;
-} GPUVertPointLink;
-
-
-
-/* used for GLSL materials */
-typedef struct GPUAttrib {
- int index;
- int info_index;
- int size;
- int type;
-} GPUAttrib;
-
-void GPU_global_buffer_pool_free(void);
-void GPU_global_buffer_pool_free_unused(void);
-
-GPUBuffer *GPU_buffer_alloc(size_t size);
-void GPU_buffer_free(GPUBuffer *buffer);
-
-void GPU_drawobject_free(struct DerivedMesh *dm);
-
-/* flag that controls data type to fill buffer with, a modifier will prepare. */
-typedef enum {
- GPU_BUFFER_VERTEX = 0,
- GPU_BUFFER_NORMAL,
- GPU_BUFFER_COLOR,
- GPU_BUFFER_UV,
- GPU_BUFFER_UV_TEXPAINT,
- GPU_BUFFER_EDGE,
- GPU_BUFFER_UVEDGE,
- GPU_BUFFER_TRIANGLES
-} GPUBufferType;
-
-typedef enum {
- GPU_BINDING_ARRAY = 0,
- GPU_BINDING_INDEX = 1,
-} GPUBindingType;
-
-typedef enum {
- GPU_ATTR_INFO_SRGB = (1 << 0),
-} GPUAttrInfo;
-
-/* called before drawing */
-void GPU_vertex_setup(struct DerivedMesh *dm);
-void GPU_normal_setup(struct DerivedMesh *dm);
-void GPU_uv_setup(struct DerivedMesh *dm);
-void GPU_texpaint_uv_setup(struct DerivedMesh *dm);
-/* colType is the cddata MCol type to use! */
-void GPU_color_setup(struct DerivedMesh *dm, int colType);
-void GPU_buffer_bind_as_color(GPUBuffer *buffer);
-void GPU_edge_setup(struct DerivedMesh *dm); /* does not mix with other data */
-void GPU_uvedge_setup(struct DerivedMesh *dm);
-
-void GPU_triangle_setup(struct DerivedMesh *dm);
-
-int GPU_attrib_element_size(GPUAttrib data[], int numdata);
-void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size);
-
-void GPU_buffer_bind(GPUBuffer *buffer, GPUBindingType binding);
-void GPU_buffer_unbind(GPUBuffer *buffer, GPUBindingType binding);
-
-/* can't lock more than one buffer at once */
-void *GPU_buffer_lock(GPUBuffer *buffer, GPUBindingType binding);
-void *GPU_buffer_lock_stream(GPUBuffer *buffer, GPUBindingType binding);
-void GPU_buffer_unlock(GPUBuffer *buffer, GPUBindingType binding);
-
-/* switch color rendering on=1/off=0 */
-void GPU_color_switch(int mode);
-
-/* used for drawing edges */
-void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count);
-
-/* called after drawing */
-void GPU_buffers_unbind(void);
-
-/* only unbind interleaved data */
-void GPU_interleaved_attrib_unbind(void);
-
-/* Buffers for non-DerivedMesh drawing */
+/* Buffers for drawing from PBVH grids. */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
/* build */
@@ -230,15 +57,13 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
const int face_indices_len);
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
- int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize, const struct CCGKey *key,
- struct GridCommonGPUBuffer **grid_common_gpu_buffer);
+ int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize, const struct CCGKey *key);
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading);
/* update */
enum {
- GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR = (1 << 0),
GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1),
};
@@ -263,19 +88,15 @@ void GPU_pbvh_grid_buffers_update(
const int update_flags);
/* draw */
-void GPU_pbvh_buffers_draw(
- GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
- bool wireframe, bool fast);
+struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast);
-/* debug PBVH draw*/
-void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf);
-void GPU_pbvh_BB_draw_init(void);
-void GPU_pbvh_BB_draw_end(void);
+bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers);
-bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color);
-bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask);
+/* debug PBVH draw */
+void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos);
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
-void GPU_pbvh_multires_buffers_free(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
+
+void GPU_pbvh_fix_linking(void);
#endif
diff --git a/source/blender/editors/space_logic/logic_intern.h b/source/blender/gpu/GPU_common.h
index ddbb145440d..3acc7fad5c2 100644
--- a/source/blender/editors/space_logic/logic_intern.h
+++ b/source/blender/gpu/GPU_common.h
@@ -15,40 +15,47 @@
* 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) 2009 Blender Foundation.
+ * The Original Code is Copyright (C) 2016 by Mike Erwin.
* All rights reserved.
*
- *
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/space_logic/logic_intern.h
- * \ingroup splogic
+/** \file blender/gpu/GPU_common.h
+ * \ingroup gpu
*/
+#ifndef __GPU_COMMON_H__
+#define __GPU_COMMON_H__
-#ifndef __LOGIC_INTERN_H__
-#define __LOGIC_INTERN_H__
+#define PROGRAM_NO_OPTI 0
-/* internal exports only */
-struct bContext;
-struct ARegion;
-struct ScrArea;
-struct wmOperatorType;
+#if defined(NDEBUG)
+# define TRUST_NO_ONE 0
+#else
+ /* strict error checking, enabled for debug builds during early development */
+# define TRUST_NO_ONE 1
+#endif
-/* space_logic.c */
-struct ARegion *logic_has_buttons_region(struct ScrArea *sa);
+#if defined(WITH_OPENGL)
+# include <GL/glew.h>
+#endif
-/* logic_ops.c */
+#include <stdbool.h>
+#include <stdint.h>
+#include "BLI_sys_types.h"
-/* logic_buttons.c */
-void LOGIC_OT_properties(struct wmOperatorType *ot);
-void LOGIC_OT_links_cut(struct wmOperatorType *ot);
+#if TRUST_NO_ONE
+# include <assert.h>
+#endif
-/* logic_window.c */
-void logic_buttons(struct bContext *C, struct ARegion *ar);
-void make_unique_prop_names(struct bContext *C, char *str);
+/* GPU_INLINE */
+#if defined(_MSC_VER)
+# define GPU_INLINE static __forceinline
+#else
+# define GPU_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__))
+#endif
-#endif /* __LOGIC_INTERN_H__ */
+#endif /* __GPU_COMMON_H__ */
diff --git a/source/blender/gpu/GPU_compositing.h b/source/blender/gpu/GPU_compositing.h
deleted file mode 100644
index d506d91a9aa..00000000000
--- a/source/blender/gpu/GPU_compositing.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * ***** 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) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Antony Riakiotakis.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file GPU_compositing.h
- * \ingroup gpu
- */
-
-#ifndef __GPU_COMPOSITING_H__
-#define __GPU_COMPOSITING_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* opaque handle for framebuffer compositing effects (defined in gpu_compositing.c )*/
-typedef struct GPUFX GPUFX;
-struct GPUDOFSettings;
-struct GPUSSAOSettings;
-struct GPUOffScreen;
-struct GPUFXSettings;
-struct rcti;
-struct Scene;
-struct GPUShader;
-enum eGPUFXFlags;
-
-/**** Public API *****/
-
-typedef enum GPUFXShaderEffect {
- /* Screen space ambient occlusion shader */
- GPU_SHADER_FX_SSAO = 1,
-
- /* depth of field passes. Yep, quite a complex effect */
- GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE = 2,
- GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO = 3,
- GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE = 4,
- GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR = 5,
- GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE = 6,
-
- /* high quality */
- GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE = 7,
- GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO = 8,
- GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE = 9,
-
- GPU_SHADER_FX_DEPTH_RESOLVE = 10,
-} GPUFXShaderEffect;
-
-/* keep in synch with enum above! */
-#define MAX_FX_SHADERS 11
-
-/* generate a new FX compositor */
-GPUFX *GPU_fx_compositor_create(void);
-
-/* destroy a text compositor */
-void GPU_fx_compositor_destroy(GPUFX *fx);
-
-/* initialize a framebuffer with size taken from the viewport */
-bool GPU_fx_compositor_initialize_passes(
- GPUFX *fx, const struct rcti *rect, const struct rcti *scissor_rect,
- const struct GPUFXSettings *fx_settings);
-
-/* do compositing on the fx passes that have been initialized */
-bool GPU_fx_do_composite_pass(
- GPUFX *fx, float projmat[4][4], bool is_persp,
- struct Scene *scene, struct GPUOffScreen *ofs);
-
-/* bind new depth buffer for XRay pass */
-void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray);
-
-/* resolve a final depth buffer by compositing the XRay and normal depth buffers */
-void GPU_fx_compositor_XRay_resolve(GPUFX *fx);
-
-void GPU_fx_compositor_init_dof_settings(struct GPUDOFSettings *dof);
-void GPU_fx_compositor_init_ssao_settings(struct GPUSSAOSettings *ssao);
-
-
-/* initialize and cache the shader unform interface for effects */
-void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect effect);
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __GPU_COMPOSITING_H__
diff --git a/source/blender/render/intern/include/occlusion.h b/source/blender/gpu/GPU_context.h
index 15a5a04e3f6..4d667a02fac 100644
--- a/source/blender/render/intern/include/occlusion.h
+++ b/source/blender/gpu/GPU_context.h
@@ -15,34 +15,41 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * The Original Code is Copyright (C) 2016 by Mike Erwin.
* All rights reserved.
*
- * The Original Code is: all of this file.
- *
- * Contributor(s): Brecht Van Lommel.
+ * Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/render/intern/include/occlusion.h
- * \ingroup render
+/** \file blender/gpu/GPU_context.h
+ * \ingroup gpu
+ *
+ * This interface allow GPU to manage VAOs for multiple context and threads.
*/
+#ifndef __GPU_CONTEXT_H__
+#define __GPU_CONTEXT_H__
-#ifndef __OCCLUSION_H__
-#define __OCCLUSION_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
-struct Render;
-struct ShadeInput;
-struct RenderPart;
-struct ShadeSample;
+#include "GPU_common.h"
+#include "GPU_batch.h"
+#include "GPU_shader_interface.h"
-void make_occ_tree(struct Render *re);
-void free_occ(struct Render *re);
-void sample_occ(struct Render *re, struct ShadeInput *shi);
+typedef struct GPUContext GPUContext;
-void cache_occ_samples(struct Render *re, struct RenderPart *pa, struct ShadeSample *ssamp);
-void free_occ_samples(struct Render *re, struct RenderPart *pa);
+GPUContext *GPU_context_create(void);
+void GPU_context_discard(GPUContext *);
+void GPU_context_active_set(GPUContext *);
+GPUContext *GPU_context_active_get(void);
+
+#ifdef __cplusplus
+}
#endif
+
+#endif /* __GPU_CONTEXT_H__ */
diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h
index 61b2bc591ce..c7a99d33654 100644
--- a/source/blender/gpu/GPU_debug.h
+++ b/source/blender/gpu/GPU_debug.h
@@ -41,24 +41,6 @@ extern "C" {
/* prints something if debug mode is active only */
void GPU_print_error_debug(const char *str);
-/* replacement for gluErrorString */
-const char *gpuErrorString(GLenum err);
-
-/* prints current OpenGL state */
-void GPU_state_print(void);
-
-void GPU_assert_no_gl_errors(const char *file, int line, const char *str);
-
-# define GPU_ASSERT_NO_GL_ERRORS(str) GPU_assert_no_gl_errors(__FILE__, __LINE__, (str))
-
-# define GPU_CHECK_ERRORS_AROUND(glProcCall) \
- ( \
- GPU_ASSERT_NO_GL_ERRORS("Pre: " #glProcCall), \
- (glProcCall), \
- GPU_ASSERT_NO_GL_ERRORS("Post: " #glProcCall) \
- )
-
-
/* inserts a debug marker message for the debug context messaging system */
void GPU_string_marker(const char *str);
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index de53b1e8739..008f4199b02 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -39,76 +39,32 @@ extern "C" {
struct ImBuf;
struct Image;
struct ImageUser;
-struct MTexPoly;
+struct Main;
struct Object;
struct Scene;
+struct ViewLayer;
struct View3D;
struct RegionView3D;
struct SmokeModifierData;
struct DupliObject;
-/* OpenGL drawing functions related to shading. These are also
- * shared with the game engine, where there were previously
- * duplicates of some of these functions. */
+#include "DNA_object_enums.h"
+
+/* OpenGL drawing functions related to shading. */
/* Initialize
* - sets the default Blender opengl state, if in doubt, check
* the contents of this function
- * - this is called when starting Blender, for opengl rendering,
- * and for switching back from the game engine for example. */
+ * - this is called when starting Blender, for opengl rendering. */
void GPU_state_init(void);
-/* Material drawing
- * - first the state is initialized by a particular object and
- * it's materials
- * - after this, materials can be quickly enabled by their number,
- * GPU_object_material_bind returns 0 if drawing should be skipped
- * - after drawing, the material must be disabled again */
-
-void GPU_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d,
- struct Scene *scene, struct Object *ob, bool glsl, bool *do_alpha_after);
-void GPU_end_object_materials(void);
-bool GPU_object_materials_check(void);
-
-int GPU_object_material_bind(int nr, void *attribs);
-void GPU_object_material_unbind(void);
-int GPU_object_material_visible(int nr, void *attribs);
-
-void GPU_begin_dupli_object(struct DupliObject *dob);
-void GPU_end_dupli_object(void);
-
-void GPU_material_diffuse_get(int nr, float diff[4]);
-bool GPU_material_use_matcaps_get(void);
-
-void GPU_set_material_alpha_blend(int alphablend);
-int GPU_get_material_alpha_blend(void);
-
-/* TexFace drawing
- * - this is mutually exclusive with material drawing, a mesh should
- * be drawn using one or the other
- * - passing NULL clears the state again */
-
-int GPU_set_tpage(struct MTexPoly *mtexpoly, int mipmap, int transp);
-void GPU_clear_tpage(bool force);
+/* Programmable point size
+ * - shaders set their own point size when enabled
+ * - use glPointSize when disabled */
-/* Lights
- * - returns how many lights were enabled
- * - this affects fixed functions materials and texface, not glsl */
-
-int GPU_default_lights(void);
-int GPU_scene_object_lights(
- struct Scene *scene, struct Object *ob,
- int lay, float viewmat[4][4], int ortho);
-
-/* Text render
- * - based on moving uv coordinates */
-
-void GPU_render_text(
- struct MTexPoly *mtexpoly, int mode,
- const char *textstr, int textlen, unsigned int *col,
- const float *v_quad[4], const float *uv_quad[4],
- int glattrib);
+void GPU_enable_program_point_size(void);
+void GPU_disable_program_point_size(void);
/* Mipmap settings
* - these will free textures on changes */
@@ -131,11 +87,6 @@ void GPU_set_gpu_mipmapping(struct Main *bmain, int gpu_mipmap);
* - these deal with images bound as opengl textures */
void GPU_paint_update_image(struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
-void GPU_update_images_framechange(struct Main *bmain);
-int GPU_update_image_time(struct Image *ima, double time);
-int GPU_verify_image(
- struct Image *ima, struct ImageUser *iuser,
- int textarget, int tftile, bool compare, bool mipmap, bool is_data);
void GPU_create_gl_tex(
unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima);
@@ -150,22 +101,31 @@ void GPU_free_images_old(struct Main *bmain);
/* smoke drawing functions */
void GPU_free_smoke(struct SmokeModifierData *smd);
+void GPU_free_smoke_velocity(struct SmokeModifierData *smd);
void GPU_create_smoke(struct SmokeModifierData *smd, int highres);
+void GPU_create_smoke_coba_field(struct SmokeModifierData *smd);
+void GPU_create_smoke_velocity(struct SmokeModifierData *smd);
/* Delayed free of OpenGL buffers by main thread */
void GPU_free_unused_buffers(struct Main *bmain);
-#ifdef WITH_OPENSUBDIV
-struct DerivedMesh;
-void GPU_draw_update_fvar_offset(struct DerivedMesh *dm);
-#endif
-
/* utilities */
void GPU_select_index_set(int index);
void GPU_select_index_get(int index, int *r_col);
int GPU_select_to_index(unsigned int col);
void GPU_select_to_index_array(unsigned int *col, const unsigned int size);
+typedef enum eGPUAttribMask {
+ GPU_DEPTH_BUFFER_BIT = (1 << 0),
+ GPU_ENABLE_BIT = (1 << 1),
+ GPU_SCISSOR_BIT = (1 << 2),
+ GPU_VIEWPORT_BIT = (1 << 3),
+ GPU_BLEND_BIT = (1 << 4),
+} eGPUAttribMask;
+
+void gpuPushAttrib(eGPUAttribMask mask);
+void gpuPopAttrib(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_element.h b/source/blender/gpu/GPU_element.h
new file mode 100644
index 00000000000..9d2458ef1aa
--- /dev/null
+++ b/source/blender/gpu/GPU_element.h
@@ -0,0 +1,103 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_element.h
+ * \ingroup gpu
+ *
+ * GPU element list (AKA index buffer)
+ */
+
+#ifndef __GPU_ELEMENT_H__
+#define __GPU_ELEMENT_H__
+
+#include "GPU_primitive.h"
+
+#define GPU_TRACK_INDEX_RANGE 1
+
+#define GPU_PRIM_RESTART 0xFFFFFFFF
+
+typedef enum {
+ GPU_INDEX_U8, /* GL has this, Vulkan does not */
+ GPU_INDEX_U16,
+ GPU_INDEX_U32
+} GPUIndexBufType;
+
+typedef struct GPUIndexBuf {
+ uint index_len;
+#if GPU_TRACK_INDEX_RANGE
+ GPUIndexBufType index_type;
+ uint32_t gl_index_type;
+ uint min_index;
+ uint max_index;
+ uint base_index;
+#endif
+ uint32_t vbo_id; /* 0 indicates not yet sent to VRAM */
+ bool use_prim_restart;
+} GPUIndexBuf;
+
+void GPU_indexbuf_use(GPUIndexBuf *);
+uint GPU_indexbuf_size_get(const GPUIndexBuf *);
+
+typedef struct GPUIndexBufBuilder {
+ uint max_allowed_index;
+ uint max_index_len;
+ uint index_len;
+ GPUPrimType prim_type;
+ uint *data;
+ bool use_prim_restart;
+} GPUIndexBufBuilder;
+
+
+/* supports all primitive types. */
+void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uint vertex_len, bool use_prim_restart);
+
+/* supports only GPU_PRIM_POINTS, GPU_PRIM_LINES and GPU_PRIM_TRIS. */
+void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len);
+
+void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *, uint v);
+void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *);
+
+void GPU_indexbuf_add_point_vert(GPUIndexBufBuilder *, uint v);
+void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *, uint v1, uint v2);
+void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3);
+void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3, uint v4);
+
+GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *);
+void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
+
+void GPU_indexbuf_discard(GPUIndexBuf *);
+
+int GPU_indexbuf_primitive_len(GPUPrimType prim_type);
+
+/* Macros */
+
+#define GPU_INDEXBUF_DISCARD_SAFE(elem) do { \
+ if (elem != NULL) { \
+ GPU_indexbuf_discard(elem); \
+ elem = NULL; \
+ } \
+} while (0)
+
+#endif /* __GPU_ELEMENT_H__ */
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 31ad8243c4b..07d8a5f8c8b 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -38,23 +38,22 @@ extern "C" {
/* GPU extensions support */
-void GPU_extensions_disable(void);
-
-bool GPU_legacy_support(void);
-bool GPU_full_non_power_of_two_support(void);
-bool GPU_display_list_support(void);
-bool GPU_bicubic_bump_support(void);
-bool GPU_geometry_shader_support(void);
-bool GPU_geometry_shader_support_via_extension(void);
-bool GPU_instanced_drawing_support(void);
-
int GPU_max_texture_size(void);
+int GPU_max_texture_layers(void);
int GPU_max_textures(void);
+int GPU_max_textures_vert(void);
+int GPU_max_textures_geom(void);
+int GPU_max_textures_frag(void);
float GPU_max_texture_anisotropy(void);
int GPU_max_color_texture_samples(void);
int GPU_max_cube_map_size(void);
+int GPU_max_ubo_binds(void);
+int GPU_max_ubo_size(void);
+float GPU_max_line_width(void);
int GPU_color_depth(void);
void GPU_get_dfdy_factors(float fac[2]);
+bool GPU_mip_render_workaround(void);
+bool GPU_depth_blitting_workaround(void);
bool GPU_mem_stats_supported(void);
void GPU_mem_stats_get(int *totalmem, int *freemem);
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index 2719b8fa6a8..ef49f9721dd 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -36,48 +36,166 @@
extern "C" {
#endif
+struct GPUTexture;
+
+typedef struct GPUAttachment {
+ struct GPUTexture *tex;
+ int mip, layer;
+} GPUAttachment;
+
+typedef enum GPUFrameBufferBits {
+ GPU_COLOR_BIT = (1 << 0),
+ GPU_DEPTH_BIT = (1 << 1),
+ GPU_STENCIL_BIT = (1 << 2),
+} GPUFrameBufferBits;
+
typedef struct GPUFrameBuffer GPUFrameBuffer;
typedef struct GPUOffScreen GPUOffScreen;
-struct GPUTexture;
/* GPU Framebuffer
* - this is a wrapper for an OpenGL framebuffer object (FBO). in practice
* multiple FBO's may be created, to get around limitations on the number
* of attached textures and the dimension requirements.
- * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must
- * be called before rendering to the window framebuffer again */
-
-void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex);
+ * - actual FBO creation & config is deferred until GPU_framebuffer_bind or
+ * GPU_framebuffer_check_valid to allow creation & config while another
+ * opengl context is bound (since FBOs are not shared between ogl contexts).
+ */
GPUFrameBuffer *GPU_framebuffer_create(void);
-int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, char err_out[256]);
-void GPU_framebuffer_texture_detach(struct GPUTexture *tex);
-void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot);
-void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex);
void GPU_framebuffer_free(GPUFrameBuffer *fb);
+void GPU_framebuffer_bind(GPUFrameBuffer *fb);
+void GPU_framebuffer_restore(void);
+
+bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
-void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot);
+GPUFrameBuffer *GPU_framebuffer_active_get(void);
-bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
+#define GPU_FRAMEBUFFER_FREE_SAFE(fb) do { \
+ if (fb != NULL) { \
+ GPU_framebuffer_free(fb); \
+ fb = NULL; \
+ } \
+} while (0)
-void GPU_framebuffer_restore(void);
-void GPU_framebuffer_blur(
- GPUFrameBuffer *fb, struct GPUTexture *tex,
- GPUFrameBuffer *blurfb, struct GPUTexture *blurtex);
+/* Framebuffer setup : You need to call GPU_framebuffer_bind for theses
+ * to be effective. */
+
+void GPU_framebuffer_texture_attach(
+ GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip);
+void GPU_framebuffer_texture_layer_attach(
+ GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip);
+void GPU_framebuffer_texture_cubeface_attach(
+ GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip);
+void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, struct GPUTexture *tex);
+void GPU_framebuffer_texture_detach_slot(
+ GPUFrameBuffer *fb, struct GPUTexture *tex, int type);
+
+/**
+ * How to use GPU_framebuffer_ensure_config().
+ *
+ * Example :
+ * GPU_framebuffer_ensure_config(&fb, {
+ * GPU_ATTACHMENT_TEXTURE(depth), // must be depth buffer
+ * GPU_ATTACHMENT_TEXTURE(tex1),
+ * GPU_ATTACHMENT_TEXTURE_CUBEFACE(tex2, 0),
+ * GPU_ATTACHMENT_TEXTURE_LAYER_MIP(tex2, 0, 0)
+ * })
+ *
+ * Note : Unspecified attachements (i.e: those beyond the last
+ * GPU_ATTACHMENT_* in GPU_framebuffer_ensure_config list)
+ * are left unchanged.
+ * Note : Make sure that the dimensions of your textures matches
+ * otherwise you will have an invalid framebuffer error.
+ **/
+#define GPU_framebuffer_ensure_config(_fb, ...) do { \
+ if (*(_fb) == NULL) { \
+ *(_fb) = GPU_framebuffer_create(); \
+ } \
+ GPUAttachment config[] = __VA_ARGS__; \
+ GPU_framebuffer_config_array(*(_fb), config, (sizeof(config) / sizeof(GPUAttachment))); \
+} while (0)
+
+void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_len);
+
+#define GPU_ATTACHMENT_NONE \
+ {.tex = NULL, .layer = -1, .mip = 0}
+#define GPU_ATTACHMENT_LEAVE \
+ {.tex = NULL, .layer = -1, .mip = -1}
+#define GPU_ATTACHMENT_TEXTURE(_tex) \
+ {.tex = _tex, .layer = -1, .mip = 0}
+#define GPU_ATTACHMENT_TEXTURE_MIP(_tex, _mip) \
+ {.tex = _tex, .layer = -1, .mip = _mip}
+#define GPU_ATTACHMENT_TEXTURE_LAYER(_tex, _layer) \
+ {.tex = _tex, .layer = _layer, .mip = 0}
+#define GPU_ATTACHMENT_TEXTURE_LAYER_MIP(_tex, _layer, _mip) \
+ {.tex = _tex, .layer = _layer, .mip = _mip}
+#define GPU_ATTACHMENT_TEXTURE_CUBEFACE(_tex, _face) \
+ {.tex = _tex, .layer = _face, .mip = 0}
+#define GPU_ATTACHMENT_TEXTURE_CUBEFACE_MIP(_tex, _face, _mip) \
+ {.tex = _tex, .layer = _face, .mip = _mip}
+
+/* Framebuffer operations */
+
+void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h);
+
+void GPU_framebuffer_clear(
+ GPUFrameBuffer *fb, GPUFrameBufferBits buffers,
+ const float clear_col[4], float clear_depth, unsigned int clear_stencil);
+
+#define GPU_framebuffer_clear_color(fb, col) \
+ GPU_framebuffer_clear(fb, GPU_COLOR_BIT, col, 0.0f, 0x00)
+
+#define GPU_framebuffer_clear_depth(fb, depth) \
+ GPU_framebuffer_clear(fb, GPU_DEPTH_BIT, NULL, depth, 0x00)
+
+#define GPU_framebuffer_clear_color_depth(fb, col, depth) \
+ GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT, col, depth, 0x00)
+
+#define GPU_framebuffer_clear_stencil(fb, stencil) \
+ GPU_framebuffer_clear(fb, GPU_STENCIL_BIT, NULL, 0.0f, stencil)
+
+#define GPU_framebuffer_clear_depth_stencil(fb, depth, stencil) \
+ GPU_framebuffer_clear(fb, GPU_DEPTH_BIT | GPU_STENCIL_BIT, NULL, depth, stencil)
+
+#define GPU_framebuffer_clear_color_depth_stencil(fb, col, depth, stencil) \
+ GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, col, depth, stencil)
+
+void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data);
+void GPU_framebuffer_read_color(
+ GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data);
+
+void GPU_framebuffer_blit(
+ GPUFrameBuffer *fb_read, int read_slot,
+ GPUFrameBuffer *fb_write, int write_slot,
+ GPUFrameBufferBits blit_buffers);
+
+void GPU_framebuffer_recursive_downsample(
+ GPUFrameBuffer *fb, int max_lvl,
+ void (*callback)(void *userData, int level), void *userData);
/* GPU OffScreen
* - wrapper around framebuffer and texture for simple offscreen drawing
- * - changes size if graphics card can't support it */
+ */
-GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]);
+GPUOffScreen *GPU_offscreen_create(
+ int width, int height, int samples,
+ bool depth, bool high_bitdepth, char err_out[256]);
void GPU_offscreen_free(GPUOffScreen *ofs);
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
+void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y);
int GPU_offscreen_width(const GPUOffScreen *ofs);
int GPU_offscreen_height(const GPUOffScreen *ofs);
-int GPU_offscreen_color_texture(const GPUOffScreen *ofs);
+struct GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs);
+
+void GPU_offscreen_viewport_data_get(
+ GPUOffScreen *ofs,
+ GPUFrameBuffer **r_fb, struct GPUTexture **r_color, struct GPUTexture **r_depth);
+
+void GPU_clear_color(float red, float green, float blue, float alpha);
+void GPU_clear(GPUFrameBufferBits flags);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/GPU_glew.h b/source/blender/gpu/GPU_glew.h
index 94217863fd6..663660ab234 100644
--- a/source/blender/gpu/GPU_glew.h
+++ b/source/blender/gpu/GPU_glew.h
@@ -32,6 +32,11 @@
#ifndef __GPU_GLEW_H__
#define __GPU_GLEW_H__
-#include "glew-mx.h"
+#if defined(WITH_OPENGL)
+# include "glew-mx.h"
+# ifndef WITH_LEGACY_OPENGL
+# include "GPU_legacy_stubs.h"
+# endif
+#endif
#endif /* __GPU_GLEW_H__ */
diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h
new file mode 100644
index 00000000000..a57ce674b77
--- /dev/null
+++ b/source/blender/gpu/GPU_immediate.h
@@ -0,0 +1,148 @@
+/*
+ * ***** 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): Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_immediate.h
+ * \ingroup gpu
+ *
+ * GPU immediate mode work-alike
+ */
+
+#ifndef __GPU_IMMEDIATE_H__
+#define __GPU_IMMEDIATE_H__
+
+#include "GPU_vertex_format.h"
+#include "GPU_primitive.h"
+#include "GPU_shader_interface.h"
+#include "GPU_batch.h"
+#include "GPU_immediate_util.h"
+#include "GPU_shader.h"
+
+GPUVertFormat *immVertexFormat(void); /* returns a cleared vertex format, ready for add_attrib. */
+
+void immBindProgram(uint32_t program, const GPUShaderInterface *); /* every immBegin must have a program bound first. */
+void immUnbindProgram(void); /* call after your last immEnd, or before binding another program. */
+
+void immBegin(GPUPrimType, uint vertex_len); /* must supply exactly vertex_len vertices. */
+void immBeginAtMost(GPUPrimType, uint max_vertex_len); /* can supply fewer vertices. */
+void immEnd(void); /* finishes and draws. */
+
+/* ImmBegin a batch, then use standard immFunctions as usual. */
+/* ImmEnd will finalize the batch instead of drawing. */
+/* Then you can draw it as many times as you like! Partially replaces the need for display lists. */
+GPUBatch *immBeginBatch(GPUPrimType, uint vertex_len);
+GPUBatch *immBeginBatchAtMost(GPUPrimType, uint vertex_len);
+
+/* Provide attribute values that can change per vertex. */
+/* First vertex after immBegin must have all its attributes specified. */
+/* Skipped attributes will continue using the previous value for that attr_id. */
+void immAttr1f(uint attr_id, float x);
+void immAttr2f(uint attr_id, float x, float y);
+void immAttr3f(uint attr_id, float x, float y, float z);
+void immAttr4f(uint attr_id, float x, float y, float z, float w);
+
+void immAttr2i(uint attr_id, int x, int y);
+
+void immAttr1u(uint attr_id, uint x);
+
+void immAttr2s(uint attr_id, short x, short y);
+
+void immAttr2fv(uint attr_id, const float data[2]);
+void immAttr3fv(uint attr_id, const float data[3]);
+void immAttr4fv(uint attr_id, const float data[4]);
+
+void immAttr3ub(uint attr_id, unsigned char r, unsigned char g, unsigned char b);
+void immAttr4ub(uint attr_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+
+void immAttr3ubv(uint attr_id, const unsigned char data[3]);
+void immAttr4ubv(uint attr_id, const unsigned char data[4]);
+
+/* Explicitly skip an attribute. */
+/* This advanced option kills automatic value copying for this attr_id. */
+void immAttrSkip(uint attr_id);
+
+/* Provide one last attribute value & end the current vertex. */
+/* This is most often used for 2D or 3D position (similar to glVertex). */
+void immVertex2f(uint attr_id, float x, float y);
+void immVertex3f(uint attr_id, float x, float y, float z);
+void immVertex4f(uint attr_id, float x, float y, float z, float w);
+
+void immVertex2i(uint attr_id, int x, int y);
+
+void immVertex2s(uint attr_id, short x, short y);
+
+void immVertex2fv(uint attr_id, const float data[2]);
+void immVertex3fv(uint attr_id, const float data[3]);
+
+void immVertex2iv(uint attr_id, const int data[2]);
+
+/* Provide uniform values that don't change for the entire draw call. */
+void immUniform1i(const char *name, int x);
+void immUniform4iv(const char *name, const int data[4]);
+void immUniform1f(const char *name, float x);
+void immUniform2f(const char *name, float x, float y);
+void immUniform2fv(const char *name, const float data[2]);
+void immUniform3f(const char *name, float x, float y, float z);
+void immUniform3fv(const char *name, const float data[3]);
+void immUniformArray3fv(const char *name, const float *data, int count);
+void immUniform4f(const char *name, float x, float y, float z, float w);
+void immUniform4fv(const char *name, const float data[4]);
+void immUniformArray4fv(const char *bare_name, const float *data, int count);
+void immUniformMatrix4fv(const char *name, const float data[4][4]);
+
+/* Convenience functions for setting "uniform vec4 color". */
+/* The rgb functions have implicit alpha = 1.0. */
+void immUniformColor4f(float r, float g, float b, float a);
+void immUniformColor4fv(const float rgba[4]);
+void immUniformColor3f(float r, float g, float b);
+void immUniformColor3fv(const float rgb[3]);
+void immUniformColor3fvAlpha(const float rgb[3], float a);
+
+void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b);
+void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+void immUniformColor3ubv(const unsigned char rgb[3]);
+void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char a);
+void immUniformColor4ubv(const unsigned char rgba[4]);
+
+/* Extend immBindProgram to use Blender’s library of built-in shader programs.
+ * Use immUnbindProgram() when done. */
+void immBindBuiltinProgram(GPUBuiltinShader shader_id);
+
+/* Extend immUniformColor to take Blender's themes */
+void immUniformThemeColor(int color_id);
+void immUniformThemeColor3(int color_id);
+void immUniformThemeColorShade(int color_id, int offset);
+void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset);
+void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset);
+void immUniformThemeColorBlend(int color_id1, int color_id2, float fac);
+void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset);
+
+/* These are called by the system -- not part of drawing API. */
+void immInit(void);
+void immActivate(void);
+void immDeactivate(void);
+void immDestroy(void);
+
+#endif /* __GPU_IMMEDIATE_H__ */
diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h
new file mode 100644
index 00000000000..e5b259b4783
--- /dev/null
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -0,0 +1,79 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_immediate_util.h
+ * \ingroup gpu
+ *
+ * Utility drawing functions (rough equivalent to OpenGL's GLU)
+ */
+
+#ifndef __GPU_IMMEDIATE_UTIL_H__
+#define __GPU_IMMEDIATE_UTIL_H__
+
+/* Draw 2D rectangles (replaces glRect functions) */
+/* caller is responsible for vertex format & shader */
+void immRectf(uint pos, float x1, float y1, float x2, float y2);
+void immRecti(uint pos, int x1, int y1, int x2, int y2);
+
+/* Same as immRectf/immRecti but does not call immBegin/immEnd. To use with GPU_PRIM_TRIS. */
+void immRectf_fast(uint pos, float x1, float y1, float x2, float y2);
+void immRectf_fast_with_color(uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4]);
+void immRecti_fast_with_color(uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4]);
+
+void imm_cpack(uint x);
+
+void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments);
+void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments);
+
+void imm_draw_circle_wire_aspect_2d(uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments);
+void imm_draw_circle_fill_aspect_2d(uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments);
+
+/* use this version when GPUVertFormat has a vec3 position */
+void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments);
+void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments);
+
+/* same as 'imm_draw_disk_partial_fill_2d', except it draws a wire arc. */
+void imm_draw_circle_partial_wire_2d(
+ uint pos, float x, float y,
+ float radius, int nsegments, float start, float sweep);
+
+void imm_draw_disk_partial_fill_2d(
+ uint pos, float x, float y,
+ float radius_inner, float radius_outer, int nsegments, float start, float sweep);
+
+void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2);
+void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2);
+
+void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2);
+
+void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]);
+void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]);
+
+void imm_draw_cylinder_fill_normal_3d(
+ uint pos, uint nor, float base, float top, float height,
+ int slices, int stacks);
+void imm_draw_cylinder_wire_3d(
+ uint pos, float base, float top, float height,
+ int slices, int stacks);
+void imm_draw_cylinder_fill_3d(
+ uint pos, float base, float top, float height,
+ int slices, int stacks);
+
+#endif /* __GPU_IMMEDIATE_UTIL_H__ */
diff --git a/source/blender/gpu/GPU_legacy_stubs.h b/source/blender/gpu/GPU_legacy_stubs.h
new file mode 100644
index 00000000000..27f805c4d31
--- /dev/null
+++ b/source/blender/gpu/GPU_legacy_stubs.h
@@ -0,0 +1,457 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation, Dalai Felinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_legacy_stubs.h
+ * \ingroup gpu
+ *
+ * This is to mark the transition to OpenGL core profile
+ * The idea is to allow Blender 2.8 to be built with OpenGL 3.3 even if it means breaking things
+ *
+ * This file should be removed in the future
+ */
+
+#ifndef __GPU_LEGACY_STUBS_H__
+#define __GPU_LEGACY_STUBS_H__
+
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+# pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+#include <stdlib.h> /* for abort(). */
+
+#include "BLI_utildefines.h"
+
+/**
+ * Empty function, use for breakpoint when a depreacated
+ * OpenGL function is called.
+ */
+static void gl_deprecated(void)
+{
+ BLI_assert(true);
+}
+
+#define _GL_BOOL BLI_INLINE GLboolean
+#define _GL_BOOL_RET { \
+ gl_deprecated(); \
+ return false; \
+}
+
+#define _GL_ENUM BLI_INLINE GLenum
+#define _GL_ENUM_RET { \
+ gl_deprecated(); \
+ return 0; \
+}
+
+#define _GL_INT BLI_INLINE GLint
+#define _GL_INT_RET { \
+ gl_deprecated(); \
+ return 0; \
+}
+
+
+#define _GL_UINT BLI_INLINE GLuint
+#define _GL_UINT_RET { \
+ gl_deprecated(); \
+ return 0; \
+}
+
+#define _GL_VOID BLI_INLINE void
+#define _GL_VOID_RET { \
+ gl_deprecated(); \
+}
+
+static bool disable_enable_check(GLenum cap)
+{
+ const bool is_deprecated = \
+ ELEM(
+ cap,
+ GL_ALPHA_TEST,
+ GL_LINE_STIPPLE,
+ GL_POINT_SPRITE,
+ GL_TEXTURE_1D,
+ GL_TEXTURE_2D,
+ GL_TEXTURE_GEN_S,
+ GL_TEXTURE_GEN_T,
+ -1
+ );
+
+ if (is_deprecated) {
+ gl_deprecated();
+ }
+
+ return is_deprecated;
+}
+
+_GL_VOID USE_CAREFULLY_glDisable (GLenum cap)
+{
+ if (!disable_enable_check(cap)) {
+ glDisable(cap);
+ }
+}
+#define glDisable USE_CAREFULLY_glDisable
+
+_GL_VOID USE_CAREFULLY_glEnable (GLenum cap)
+{
+ if (!disable_enable_check(cap)) {
+ glEnable(cap);
+ }
+}
+#define glEnable USE_CAREFULLY_glEnable
+
+/**
+ * Hand written cases
+ */
+
+_GL_VOID DO_NOT_USE_glClientActiveTexture (GLenum texture) _GL_VOID_RET
+
+
+/**
+ * List automatically generated from `gl-deprecated.h` and `glew.h`
+ */
+
+/**
+ * ENUM values
+ */
+#define DO_NOT_USE_GL_CURRENT_FOG_COORDINATE 0
+#define DO_NOT_USE_GL_FOG_COORDINATE 0
+#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY 0
+#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0
+#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_POINTER 0
+#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_STRIDE 0
+#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_TYPE 0
+#define DO_NOT_USE_GL_FOG_COORDINATE_SOURCE 0
+#define DO_NOT_USE_GL_POINT_SIZE_GRANULARITY 0
+#define DO_NOT_USE_GL_POINT_SIZE_RANGE 0
+#define DO_NOT_USE_GL_SOURCE0_ALPHA 0
+#define DO_NOT_USE_GL_SOURCE0_RGB 0
+#define DO_NOT_USE_GL_SOURCE1_ALPHA 0
+#define DO_NOT_USE_GL_SOURCE1_RGB 0
+#define DO_NOT_USE_GL_SOURCE2_ALPHA 0
+#define DO_NOT_USE_GL_SOURCE2_RGB 0
+
+/**
+ * Functions
+ */
+_GL_VOID DO_NOT_USE_glAccum (GLenum op, GLfloat value) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glAlphaFunc (GLenum func, GLclampf ref) _GL_VOID_RET
+_GL_BOOL DO_NOT_USE_glAreTexturesResident (GLsizei n, const GLuint *textures, GLboolean *residences) _GL_BOOL_RET
+_GL_VOID DO_NOT_USE_glArrayElement (GLint i) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glBegin (GLenum mode) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glCallList (GLuint list) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glCallLists (GLsizei n, GLenum type, const void *lists) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glClearAccum (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glClearIndex (GLfloat c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glClipPlane (GLenum plane, const GLdouble *equation) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3b (GLbyte red, GLbyte green, GLbyte blue) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3bv (const GLbyte *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3d (GLdouble red, GLdouble green, GLdouble blue) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3f (GLfloat red, GLfloat green, GLfloat blue) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3i (GLint red, GLint green, GLint blue) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3s (GLshort red, GLshort green, GLshort blue) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3ub (GLubyte red, GLubyte green, GLubyte blue) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3ubv (const GLubyte *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3ui (GLuint red, GLuint green, GLuint blue) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3uiv (const GLuint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3us (GLushort red, GLushort green, GLushort blue) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor3usv (const GLushort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4b (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4bv (const GLbyte *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4d (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4i (GLint red, GLint green, GLint blue, GLint alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4s (GLshort red, GLshort green, GLshort blue, GLshort alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4ubv (const GLubyte *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4ui (GLuint red, GLuint green, GLuint blue, GLuint alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4uiv (const GLuint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4us (GLushort red, GLushort green, GLushort blue, GLushort alpha) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColor4usv (const GLushort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColorMaterial (GLenum face, GLenum mode) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glCopyPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glDeleteLists (GLuint list, GLsizei range) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glDisableClientState (GLenum array) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glDrawPixels (GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEdgeFlag (GLboolean flag) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEdgeFlagPointer (GLsizei stride, const void *pointer) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEdgeFlagv (const GLboolean *flag) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEnableClientState (GLenum array) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEnd (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEndList (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalCoord1d (GLdouble u) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalCoord1dv (const GLdouble *u) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalCoord1f (GLfloat u) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalCoord1fv (const GLfloat *u) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalCoord2d (GLdouble u, GLdouble v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalCoord2dv (const GLdouble *u) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalCoord2f (GLfloat u, GLfloat v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalCoord2fv (const GLfloat *u) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalMesh1 (GLenum mode, GLint i1, GLint i2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalMesh2 (GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalPoint1 (GLint i) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glEvalPoint2 (GLint i, GLint j) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glFeedbackBuffer (GLsizei size, GLenum type, GLfloat *buffer) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glFogf (GLenum pname, GLfloat param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glFogfv (GLenum pname, const GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glFogi (GLenum pname, GLint param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glFogiv (GLenum pname, const GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) _GL_VOID_RET
+_GL_UINT DO_NOT_USE_glGenLists (GLsizei range) _GL_UINT_RET
+_GL_VOID DO_NOT_USE_glGetClipPlane (GLenum plane, GLdouble *equation) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetLightfv (GLenum light, GLenum pname, GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetLightiv (GLenum light, GLenum pname, GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetMapdv (GLenum target, GLenum query, GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetMapfv (GLenum target, GLenum query, GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetMapiv (GLenum target, GLenum query, GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetMaterialiv (GLenum face, GLenum pname, GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetPixelMapfv (GLenum map, GLfloat *values) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetPixelMapuiv (GLenum map, GLuint *values) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetPixelMapusv (GLenum map, GLushort *values) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetPolygonStipple (GLubyte *mask) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetTexEnvfv (GLenum target, GLenum pname, GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetTexEnviv (GLenum target, GLenum pname, GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetTexGendv (GLenum coord, GLenum pname, GLdouble *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetTexGenfv (GLenum coord, GLenum pname, GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glGetTexGeniv (GLenum coord, GLenum pname, GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexMask (GLuint mask) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexPointer (GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexd (GLdouble c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexdv (const GLdouble *c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexf (GLfloat c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexfv (const GLfloat *c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexi (GLint c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexiv (const GLint *c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexs (GLshort c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexsv (const GLshort *c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexub (GLubyte c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glIndexubv (const GLubyte *c) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glInitNames (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glInterleavedArrays (GLenum format, GLsizei stride, const void *pointer) _GL_VOID_RET
+_GL_BOOL DO_NOT_USE_glIsList (GLuint list) _GL_BOOL_RET
+_GL_VOID DO_NOT_USE_glLightModelf (GLenum pname, GLfloat param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLightModelfv (GLenum pname, const GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLightModeli (GLenum pname, GLint param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLightModeliv (GLenum pname, const GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLightf (GLenum light, GLenum pname, GLfloat param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLightfv (GLenum light, GLenum pname, const GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLighti (GLenum light, GLenum pname, GLint param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLightiv (GLenum light, GLenum pname, const GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLineStipple (GLint factor, GLushort pattern) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glListBase (GLuint base) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLoadIdentity (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLoadMatrixd (const GLdouble *m) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLoadMatrixf (const GLfloat *m) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glLoadName (GLuint name) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMap1d (GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMap1f (GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMap2d (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMap2f (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMapGrid1d (GLint un, GLdouble u1, GLdouble u2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMapGrid1f (GLint un, GLfloat u1, GLfloat u2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMapGrid2d (GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMapGrid2f (GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMaterialf (GLenum face, GLenum pname, GLfloat param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMaterialfv (GLenum face, GLenum pname, const GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMateriali (GLenum face, GLenum pname, GLint param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMaterialiv (GLenum face, GLenum pname, const GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMatrixMode (GLenum mode) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMultMatrixd (const GLdouble *m) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glMultMatrixf (const GLfloat *m) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNewList (GLuint list, GLenum mode) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3b (GLbyte nx, GLbyte ny, GLbyte nz) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3bv (const GLbyte *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3d (GLdouble nx, GLdouble ny, GLdouble nz) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3i (GLint nx, GLint ny, GLint nz) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3s (GLshort nx, GLshort ny, GLshort nz) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormal3sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glNormalPointer (GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPassThrough (GLfloat token) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPixelMapfv (GLenum map, GLsizei mapsize, const GLfloat *values) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPixelMapuiv (GLenum map, GLsizei mapsize, const GLuint *values) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPixelMapusv (GLenum map, GLsizei mapsize, const GLushort *values) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPixelTransferf (GLenum pname, GLfloat param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPixelTransferi (GLenum pname, GLint param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPixelZoom (GLfloat xfactor, GLfloat yfactor) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPolygonStipple (const GLubyte *mask) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPopAttrib (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPopClientAttrib (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPopMatrix (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPopName (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPrioritizeTextures (GLsizei n, const GLuint *textures, const GLclampf *priorities) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPushAttrib (GLbitfield mask) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPushClientAttrib (GLbitfield mask) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPushMatrix (void) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glPushName (GLuint name) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos2d (GLdouble x, GLdouble y) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos2dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos2f (GLfloat x, GLfloat y) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos2fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos2i (GLint x, GLint y) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos2iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos2s (GLshort x, GLshort y) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos2sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos3d (GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos3dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos3f (GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos3fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos3i (GLint x, GLint y, GLint z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos3iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos3s (GLshort x, GLshort y, GLshort z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos3sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos4dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos4fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos4i (GLint x, GLint y, GLint z, GLint w) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos4iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos4s (GLshort x, GLshort y, GLshort z, GLshort w) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRasterPos4sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRectd (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRectdv (const GLdouble *v1, const GLdouble *v2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRectfv (const GLfloat *v1, const GLfloat *v2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRecti (GLint x1, GLint y1, GLint x2, GLint y2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRectiv (const GLint *v1, const GLint *v2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRects (GLshort x1, GLshort y1, GLshort x2, GLshort y2) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRectsv (const GLshort *v1, const GLshort *v2) _GL_VOID_RET
+_GL_INT DO_NOT_USE_glRenderMode (GLenum mode) _GL_INT_RET
+_GL_VOID DO_NOT_USE_glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glScaled (GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glScalef (GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glSelectBuffer (GLsizei size, GLuint *buffer) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glShadeModel (GLenum mode) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord1d (GLdouble s) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord1dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord1f (GLfloat s) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord1fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord1i (GLint s) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord1iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord1s (GLshort s) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord1sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord2d (GLdouble s, GLdouble t) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord2dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord2f (GLfloat s, GLfloat t) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord2fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord2i (GLint s, GLint t) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord2iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord2s (GLshort s, GLshort t) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord2sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord3d (GLdouble s, GLdouble t, GLdouble r) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord3dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord3f (GLfloat s, GLfloat t, GLfloat r) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord3fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord3i (GLint s, GLint t, GLint r) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord3iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord3s (GLshort s, GLshort t, GLshort r) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord3sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord4d (GLdouble s, GLdouble t, GLdouble r, GLdouble q) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord4dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord4f (GLfloat s, GLfloat t, GLfloat r, GLfloat q) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord4fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord4i (GLint s, GLint t, GLint r, GLint q) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord4iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord4s (GLshort s, GLshort t, GLshort r, GLshort q) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoord4sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexEnvf (GLenum target, GLenum pname, GLfloat param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexEnvi (GLenum target, GLenum pname, GLint param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexEnviv (GLenum target, GLenum pname, const GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexGend (GLenum coord, GLenum pname, GLdouble param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexGendv (GLenum coord, GLenum pname, const GLdouble *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexGenf (GLenum coord, GLenum pname, GLfloat param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexGeni (GLenum coord, GLenum pname, GLint param) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTexGeniv (GLenum coord, GLenum pname, const GLint *params) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTranslated (GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glTranslatef (GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex2d (GLdouble x, GLdouble y) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex2dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex2f (GLfloat x, GLfloat y) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex2fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex2i (GLint x, GLint y) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex2iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex2s (GLshort x, GLshort y) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex2sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex3d (GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex3dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex3f (GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex3fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex3i (GLint x, GLint y, GLint z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex3iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex3s (GLshort x, GLshort y, GLshort z) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex3sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex4dv (const GLdouble *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex4fv (const GLfloat *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex4i (GLint x, GLint y, GLint z, GLint w) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex4iv (const GLint *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex4s (GLshort x, GLshort y, GLshort z, GLshort w) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertex4sv (const GLshort *v) _GL_VOID_RET
+_GL_VOID DO_NOT_USE_glVertexPointer (GLint size, GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET
+
+/**
+ * End of automatically generated list
+ */
+
+
+
+#undef _GL_BOOL
+#undef _GL_BOOL_RET
+#undef _GL_ENUM
+#undef _GL_ENUM_RET
+#undef _GL_INT
+#undef _GL_INT_RET
+#undef _GL_UINT
+#undef _GL_UINT_RET
+#undef _GL_VOID
+#undef _GL_VOID_RET
+
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+
+#endif /* __GPU_LEGACY_STUBS_H__ */
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index c94d6429f59..737093ddffc 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -43,31 +43,33 @@ extern "C" {
struct Image;
struct ImageUser;
+struct ListBase;
struct Main;
struct Material;
struct Object;
-struct Image;
struct Scene;
-struct SceneRenderLayer;
struct GPUVertexAttribs;
struct GPUNode;
struct GPUNodeLink;
struct GPUNodeStack;
struct GPUMaterial;
struct GPUTexture;
-struct GPULamp;
+struct GPUUniformBuffer;
struct PreviewImage;
struct World;
+struct bNode;
+struct bNodeTree;
typedef struct GPUNode GPUNode;
typedef struct GPUNodeLink GPUNodeLink;
typedef struct GPUMaterial GPUMaterial;
-typedef struct GPULamp GPULamp;
+
typedef struct GPUParticleInfo GPUParticleInfo;
/* Functions to create GPU Materials nodes */
typedef enum GPUType {
+ /* Keep in sync with GPU_DATATYPE_STR */
/* The value indicates the number of elements in each type */
GPU_NONE = 0,
GPU_FLOAT = 1,
@@ -77,9 +79,17 @@ typedef enum GPUType {
GPU_MAT3 = 9,
GPU_MAT4 = 16,
+ /* Values not in GPU_DATATYPE_STR */
+ GPU_TEX1D_ARRAY = 1001,
GPU_TEX2D = 1002,
- GPU_SHADOW2D = 1003,
- GPU_TEXCUBE = 1004,
+ GPU_TEX3D = 1003,
+ GPU_SHADOW2D = 1004,
+ GPU_TEXCUBE = 1005,
+
+ /* GLSL Struct types */
+ GPU_CLOSURE = 1006,
+
+ /* Opengl Attributes */
GPU_ATTRIB = 3001
} GPUType;
@@ -94,24 +104,25 @@ typedef enum GPUBuiltin {
GPU_AUTO_BUMPSCALE = (1 << 7),
GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
GPU_PARTICLE_SCALAR_PROPS = (1 << 9),
- GPU_PARTICLE_LOCATION = (1 << 10),
+ GPU_PARTICLE_LOCATION = (1 << 10),
GPU_PARTICLE_VELOCITY = (1 << 11),
GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
GPU_LOC_TO_VIEW_MATRIX = (1 << 13),
GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
- GPU_OBJECT_INFO = (1 << 15)
+ GPU_OBJECT_INFO = (1 << 15),
+ GPU_VOLUME_DENSITY = (1 << 16),
+ GPU_VOLUME_FLAME = (1 << 17),
+ GPU_VOLUME_TEMPERATURE = (1 << 18),
+ GPU_BARYCENTRIC_TEXCO = (1 << 19),
+ GPU_BARYCENTRIC_DIST = (1 << 20),
} GPUBuiltin;
-typedef enum GPUOpenGLBuiltin {
- GPU_MATCAP_NORMAL = 1,
- GPU_COLOR = 2,
-} GPUOpenGLBuiltin;
-
-typedef enum GPUMatType {
- GPU_MATERIAL_TYPE_MESH = 1,
- GPU_MATERIAL_TYPE_WORLD = 2,
-} GPUMatType;
-
+typedef enum GPUMatFlag {
+ GPU_MATFLAG_DIFFUSE = (1 << 0),
+ GPU_MATFLAG_GLOSSY = (1 << 1),
+ GPU_MATFLAG_REFRACT = (1 << 2),
+ GPU_MATFLAG_SSS = (1 << 3),
+} GPUMatFlag;
typedef enum GPUBlendMode {
GPU_BLEND_SOLID = 0,
@@ -124,237 +135,75 @@ typedef enum GPUBlendMode {
typedef struct GPUNodeStack {
GPUType type;
- const char *name;
float vec[4];
struct GPUNodeLink *link;
bool hasinput;
bool hasoutput;
short sockettype;
+ bool end;
} GPUNodeStack;
-
-#define GPU_DYNAMIC_GROUP_FROM_TYPE(f) ((f) & 0xFFFF0000)
-
-#define GPU_DYNAMIC_GROUP_MISC 0x00010000
-#define GPU_DYNAMIC_GROUP_LAMP 0x00020000
-#define GPU_DYNAMIC_GROUP_OBJECT 0x00030000
-#define GPU_DYNAMIC_GROUP_SAMPLER 0x00040000
-#define GPU_DYNAMIC_GROUP_MIST 0x00050000
-#define GPU_DYNAMIC_GROUP_WORLD 0x00060000
-#define GPU_DYNAMIC_GROUP_MAT 0x00070000
-
-typedef enum GPUDynamicType {
-
- GPU_DYNAMIC_NONE = 0,
-
- GPU_DYNAMIC_OBJECT_VIEWMAT = 1 | GPU_DYNAMIC_GROUP_OBJECT,
- GPU_DYNAMIC_OBJECT_MAT = 2 | GPU_DYNAMIC_GROUP_OBJECT,
- GPU_DYNAMIC_OBJECT_VIEWIMAT = 3 | GPU_DYNAMIC_GROUP_OBJECT,
- GPU_DYNAMIC_OBJECT_IMAT = 4 | GPU_DYNAMIC_GROUP_OBJECT,
- GPU_DYNAMIC_OBJECT_COLOR = 5 | GPU_DYNAMIC_GROUP_OBJECT,
- GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 6 | GPU_DYNAMIC_GROUP_OBJECT,
- GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT = 7 | GPU_DYNAMIC_GROUP_OBJECT,
- GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT = 8 | GPU_DYNAMIC_GROUP_OBJECT,
-
- GPU_DYNAMIC_LAMP_DYNVEC = 1 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_DYNCO = 2 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_DYNIMAT = 3 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_DYNPERSMAT = 4 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_DYNENERGY = 5 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_DYNCOL = 6 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_DISTANCE = 7 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_ATT1 = 8 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_SPOTSCALE = 12 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_COEFFCONST = 13 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_COEFFLIN = 14 | GPU_DYNAMIC_GROUP_LAMP,
- GPU_DYNAMIC_LAMP_COEFFQUAD = 15 | GPU_DYNAMIC_GROUP_LAMP,
-
- GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER,
- GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER,
- GPU_DYNAMIC_SAMPLER_2DSHADOW = 3 | GPU_DYNAMIC_GROUP_SAMPLER,
-
- GPU_DYNAMIC_MIST_ENABLE = 1 | GPU_DYNAMIC_GROUP_MIST,
- GPU_DYNAMIC_MIST_START = 2 | GPU_DYNAMIC_GROUP_MIST,
- GPU_DYNAMIC_MIST_DISTANCE = 3 | GPU_DYNAMIC_GROUP_MIST,
- GPU_DYNAMIC_MIST_INTENSITY = 4 | GPU_DYNAMIC_GROUP_MIST,
- GPU_DYNAMIC_MIST_TYPE = 5 | GPU_DYNAMIC_GROUP_MIST,
- GPU_DYNAMIC_MIST_COLOR = 6 | GPU_DYNAMIC_GROUP_MIST,
-
- GPU_DYNAMIC_HORIZON_COLOR = 1 | GPU_DYNAMIC_GROUP_WORLD,
- GPU_DYNAMIC_AMBIENT_COLOR = 2 | GPU_DYNAMIC_GROUP_WORLD,
- GPU_DYNAMIC_ZENITH_COLOR = 3 | GPU_DYNAMIC_GROUP_WORLD,
-
- GPU_DYNAMIC_MAT_DIFFRGB = 1 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_REF = 2 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_SPECRGB = 3 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_SPEC = 4 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_HARD = 5 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_EMIT = 6 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_AMB = 7 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_ALPHA = 8 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_MIR = 9 | GPU_DYNAMIC_GROUP_MAT
-} GPUDynamicType;
+typedef enum GPUMaterialStatus {
+ GPU_MAT_FAILED = 0,
+ GPU_MAT_QUEUED,
+ GPU_MAT_SUCCESS,
+} GPUMaterialStatus;
GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
+GPUNodeLink *GPU_constant(float *num);
GPUNodeLink *GPU_uniform(float *num);
-GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data);
GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data);
-GPUNodeLink *GPU_cube_map(struct Image *ima, struct ImageUser *iuser, bool is_data);
-GPUNodeLink *GPU_image_preview(struct PreviewImage *prv);
-GPUNodeLink *GPU_texture(int size, float *pixels);
-GPUNodeLink *GPU_dynamic_texture(struct GPUTexture *tex, GPUDynamicType dynamictype, void *data);
+GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer);
GPUNodeLink *GPU_builtin(GPUBuiltin builtin);
-GPUNodeLink *GPU_opengl_builtin(GPUOpenGLBuiltin builtin);
void GPU_node_link_set_type(GPUNodeLink *link, GPUType type);
bool GPU_link(GPUMaterial *mat, const char *name, ...);
-bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...);
+bool GPU_stack_link(GPUMaterial *mat, struct bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...);
+GPUNodeLink *GPU_uniformbuffer_link_out(
+ struct GPUMaterial *mat, struct bNode *node,
+ struct GPUNodeStack *stack, const int index);
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
-void GPU_material_enable_alpha(GPUMaterial *material);
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material);
-GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
-/* High level functions to create and use GPU materials */
-GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo);
+void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], short *falloff_type, float *sharpness);
+struct GPUUniformBuffer *GPU_material_sss_profile_get(
+ GPUMaterial *material, int sample_len, struct GPUTexture **tex_profile);
-GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
-GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
+/* High level functions to create and use GPU materials */
+GPUMaterial *GPU_material_from_nodetree_find(
+ struct ListBase *gpumaterials, const void *engine_type, int options);
+GPUMaterial *GPU_material_from_nodetree(
+ struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options,
+ const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, const char *name);
+void GPU_material_compile(GPUMaterial *mat);
void GPU_material_free(struct ListBase *gpumaterial);
void GPU_materials_free(struct Main *bmain);
-bool GPU_lamp_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
-void GPU_material_bind(
- GPUMaterial *material, int oblay, int viewlay, double time, int mipmap,
- float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
-void GPU_material_bind_uniforms(
- GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
- float autobumpscale, GPUParticleInfo *pi, float object_info[3]);
-void GPU_material_unbind(GPUMaterial *material);
-bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
-GPUMatType GPU_Material_get_type(GPUMaterial *material);
+struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
+struct ListBase *GPU_material_get_inputs(GPUMaterial *material);
+GPUMaterialStatus GPU_material_status(GPUMaterial *mat);
+
+struct GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material);
+void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
+struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void);
-void GPU_material_vertex_attributes(GPUMaterial *material,
- struct GPUVertexAttribs *attrib);
+void GPU_material_vertex_attributes(
+ GPUMaterial *material,
+ struct GPUVertexAttribs *attrib);
bool GPU_material_do_color_management(GPUMaterial *mat);
-bool GPU_material_use_new_shading_nodes(GPUMaterial *mat);
-bool GPU_material_use_world_space_shading(GPUMaterial *mat);
-
-/* Exported shading */
-
-typedef struct GPUShadeInput {
- GPUMaterial *gpumat;
- struct Material *mat;
-
- GPUNodeLink *rgb, *specrgb, *vn, *view, *vcol, *ref;
- GPUNodeLink *alpha, *refl, *spec, *emit, *har, *amb;
- GPUNodeLink *spectra, *mir, *refcol;
-} GPUShadeInput;
-
-typedef struct GPUShadeResult {
- GPUNodeLink *diff, *spec, *combined, *alpha;
-} GPUShadeResult;
-
-void GPU_shadeinput_set(GPUMaterial *mat, struct Material *ma, GPUShadeInput *shi);
-void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr);
-
-/* Export GLSL shader */
-
-typedef enum GPUDataType {
- GPU_DATA_NONE = 0,
- GPU_DATA_1I = 1, /* 1 integer */
- GPU_DATA_1F = 2,
- GPU_DATA_2F = 3,
- GPU_DATA_3F = 4,
- GPU_DATA_4F = 5,
- GPU_DATA_9F = 6,
- GPU_DATA_16F = 7,
- GPU_DATA_4UB = 8,
-} GPUDataType;
-
-/* this structure gives information of each uniform found in the shader */
-typedef struct GPUInputUniform {
- struct GPUInputUniform *next, *prev;
- char varname[32]; /* name of uniform in shader */
- GPUDynamicType type; /* type of uniform, data format and calculation derive from it */
- GPUDataType datatype; /* type of uniform data */
- struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */
- struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */
- struct Material *material;/* when type=GPU_DYNAMIC_MAT_... */
- int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */
- unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */
- int texsize; /* size in pixel of the texture in texpixels buffer:
- * for 2D textures, this is S and T size (square texture) */
-} GPUInputUniform;
-
-typedef struct GPUInputAttribute {
- struct GPUInputAttribute *next, *prev;
- char varname[32]; /* name of attribute in shader */
- int type; /* from CustomData.type, data type derives from it */
- GPUDataType datatype; /* type of attribute data */
- const char *name; /* layer name */
- int number; /* generic attribute number */
-} GPUInputAttribute;
-
-typedef struct GPUShaderExport {
- ListBase uniforms;
- ListBase attributes;
- char *vertex;
- char *fragment;
-} GPUShaderExport;
-
-GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma);
-void GPU_free_shader_export(GPUShaderExport *shader);
-
-/* Lamps */
-
-GPULamp *GPU_lamp_from_blender(struct Scene *scene, struct Object *ob, struct Object *par);
-void GPU_lamp_free(struct Object *ob);
-
-bool GPU_lamp_has_shadow_buffer(GPULamp *lamp);
-void GPU_lamp_update_buffer_mats(GPULamp *lamp);
-void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4]);
-void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp);
-int GPU_lamp_shadow_buffer_type(GPULamp *lamp);
-int GPU_lamp_shadow_bind_code(GPULamp *lamp);
-float *GPU_lamp_dynpersmat(GPULamp *lamp);
-
-void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]);
-void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy);
-void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2,
- float coeff_const, float coeff_lin, float coeff_quad);
-void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend);
-int GPU_lamp_shadow_layer(GPULamp *lamp);
-GPUNodeLink *GPU_lamp_get_data(
- GPUMaterial *mat, GPULamp *lamp,
- GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy);
-
-/* World */
-void GPU_mist_update_enable(short enable);
-void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]);
-void GPU_horizon_update_color(float color[3]);
-void GPU_ambient_update_color(float color[3]);
-void GPU_zenith_update_color(float color[3]);
-
-struct GPUParticleInfo
-{
- float scalprops[4];
- float location[4];
- float velocity[3];
- float angular_velocity[3];
-};
-
-#ifdef WITH_OPENSUBDIV
-struct DerivedMesh;
-void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
- struct DerivedMesh *dm);
-#endif
+bool GPU_material_use_domain_surface(GPUMaterial *mat);
+bool GPU_material_use_domain_volume(GPUMaterial *mat);
+
+void GPU_material_flag_set(GPUMaterial *mat, GPUMatFlag flag);
+bool GPU_material_flag_get(GPUMaterial *mat, GPUMatFlag flag);
+
+void GPU_pass_cache_init(void);
+void GPU_pass_cache_garbage_collect(void);
+void GPU_pass_cache_free(void);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
new file mode 100644
index 00000000000..23f19ed19cd
--- /dev/null
+++ b/source/blender/gpu/GPU_matrix.h
@@ -0,0 +1,190 @@
+/*
+ * ***** 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) 2012 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file source/blender/gpu/GPU_matrix.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_MATRIX_H__
+#define __GPU_MATRIX_H__
+
+#include "BLI_sys_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GPUShaderInterface;
+
+void GPU_matrix_reset(void); /* to Identity transform & empty stack */
+
+/* ModelView Matrix (2D or 3D) */
+
+void GPU_matrix_push(void); /* TODO: PushCopy vs PushIdentity? */
+void GPU_matrix_pop(void);
+
+void GPU_matrix_identity_set(void);
+
+void GPU_matrix_scale_1f(float factor);
+
+
+/* 3D ModelView Matrix */
+
+void GPU_matrix_set(const float m[4][4]);
+void GPU_matrix_mul(const float m[4][4]);
+
+void GPU_matrix_translate_3f(float x, float y, float z);
+void GPU_matrix_translate_3fv(const float vec[3]);
+void GPU_matrix_scale_3f(float x, float y, float z);
+void GPU_matrix_scale_3fv(const float vec[3]);
+void GPU_matrix_rotate_3f(float deg, float x, float y, float z); /* axis of rotation should be a unit vector */
+void GPU_matrix_rotate_3fv(float deg, const float axis[3]); /* axis of rotation should be a unit vector */
+void GPU_matrix_rotate_axis(float deg, char axis); /* TODO: enum for axis? */
+
+void GPU_matrix_look_at(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ);
+/* TODO: variant that takes eye[3], center[3], up[3] */
+
+
+/* 2D ModelView Matrix */
+
+void GPU_matrix_translate_2f(float x, float y);
+void GPU_matrix_translate_2fv(const float vec[2]);
+void GPU_matrix_scale_2f(float x, float y);
+void GPU_matrix_scale_2fv(const float vec[2]);
+void GPU_matrix_rotate_2d(float deg);
+
+/* Projection Matrix (2D or 3D) */
+
+void GPU_matrix_push_projection(void);
+void GPU_matrix_pop_projection(void);
+
+/* 3D Projection Matrix */
+
+void GPU_matrix_identity_projection_set(void);
+void GPU_matrix_projection_set(const float m[4][4]);
+
+void GPU_matrix_ortho_set(float left, float right, float bottom, float top, float near, float far);
+void GPU_matrix_frustum_set(float left, float right, float bottom, float top, float near, float far);
+void GPU_matrix_perspective_set(float fovy, float aspect, float near, float far);
+
+/* 3D Projection between Window and World Space */
+
+void GPU_matrix_project(const float world[3], const float model[4][4], const float proj[4][4], const int view[4], float win[3]);
+bool GPU_matrix_unproject(const float win[3], const float model[4][4], const float proj[4][4], const int view[4], float world[3]);
+
+/* 2D Projection Matrix */
+
+void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top);
+
+
+/* functions to get matrix values */
+const float (*GPU_matrix_model_view_get(float m[4][4]))[4];
+const float (*GPU_matrix_projection_get(float m[4][4]))[4];
+const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4];
+
+const float (*GPU_matrix_normal_get(float m[3][3]))[3];
+const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3];
+
+
+/* set uniform values for currently bound shader */
+void GPU_matrix_bind(const struct GPUShaderInterface *);
+bool GPU_matrix_dirty_get(void); /* since last bind */
+
+
+/* Python API needs to be able to inspect the stack so errors raise exceptions instead of crashing. */
+#ifdef USE_GPU_PY_MATRIX_API
+int GPU_matrix_stack_level_get_model_view(void);
+int GPU_matrix_stack_level_get_projection(void);
+/* static assert ensures this doesn't change! */
+#define GPU_PY_MATRIX_STACK_LEN 31
+#endif /* USE_GPU_PY_MATRIX_API */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef SUPPRESS_GENERIC_MATRIX_API
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+#define _GPU_MAT3_CONST_CAST(x) (_Generic((x), \
+ void *: (const float (*)[3])(x), \
+ float *: (const float (*)[3])(x), \
+ float [9]: (const float (*)[3])(x), \
+ float (*)[4]: (const float (*)[3])(x), \
+ float [4][4]: (const float (*)[3])(x), \
+ const void *: (const float (*)[3])(x), \
+ const float *: (const float (*)[3])(x), \
+ const float [9]: (const float (*)[3])(x), \
+ const float (*)[3]: (const float (*)[3])(x), \
+ const float [3][3]: (const float (*)[3])(x)) \
+)
+#define _GPU_MAT3_CAST(x) (_Generic((x), \
+ void *: (float (*)[3])(x), \
+ float *: (float (*)[3])(x), \
+ float [9]: (float (*)[3])(x), \
+ float (*)[3]: (float (*)[3])(x), \
+ float [3][3]: (float (*)[3])(x)) \
+)
+#define _GPU_MAT4_CONST_CAST(x) (_Generic((x), \
+ void *: (const float (*)[4])(x), \
+ float *: (const float (*)[4])(x), \
+ float [16]: (const float (*)[4])(x), \
+ float (*)[4]: (const float (*)[4])(x), \
+ float [4][4]: (const float (*)[4])(x), \
+ const void *: (const float (*)[4])(x), \
+ const float *: (const float (*)[4])(x), \
+ const float [16]: (const float (*)[4])(x), \
+ const float (*)[4]: (const float (*)[4])(x), \
+ const float [4][4]: (const float (*)[4])(x)) \
+)
+#define _GPU_MAT4_CAST(x) (_Generic((x), \
+ void *: (float (*)[4])(x), \
+ float *: (float (*)[4])(x), \
+ float [16]: (float (*)[4])(x), \
+ float (*)[4]: (float (*)[4])(x), \
+ float [4][4]: (float (*)[4])(x)) \
+)
+#else
+# define _GPU_MAT3_CONST_CAST(x) (const float (*)[3])(x)
+# define _GPU_MAT3_CAST(x) (float (*)[3])(x)
+# define _GPU_MAT4_CONST_CAST(x) (const float (*)[4])(x)
+# define _GPU_MAT4_CAST(x) (float (*)[4])(x)
+#endif /* C11 */
+
+/* make matrix inputs generic, to avoid warnings */
+# define GPU_matrix_mul(x) GPU_matrix_mul(_GPU_MAT4_CONST_CAST(x))
+# define GPU_matrix_set(x) GPU_matrix_set(_GPU_MAT4_CONST_CAST(x))
+# define GPU_matrix_projection_set(x) GPU_matrix_projection_set(_GPU_MAT4_CONST_CAST(x))
+# define GPU_matrix_model_view_get(x) GPU_matrix_model_view_get(_GPU_MAT4_CAST(x))
+# define GPU_matrix_projection_get(x) GPU_matrix_projection_get(_GPU_MAT4_CAST(x))
+# define GPU_matrix_model_view_projection_get(x) GPU_matrix_model_view_projection_get(_GPU_MAT4_CAST(x))
+# define GPU_matrix_normal_get(x) GPU_matrix_normal_get(_GPU_MAT3_CAST(x))
+# define GPU_matrix_normal_inverse_get(x) GPU_matrix_normal_inverse_get(_GPU_MAT3_CAST(x))
+#endif /* SUPPRESS_GENERIC_MATRIX_API */
+
+#endif /* __GPU_MATRIX_H__ */
diff --git a/source/blender/gpu/GPU_primitive.h b/source/blender/gpu/GPU_primitive.h
new file mode 100644
index 00000000000..bcedfa56ab1
--- /dev/null
+++ b/source/blender/gpu/GPU_primitive.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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_primitive.h
+ * \ingroup gpu
+ *
+ * GPU geometric primitives
+ */
+
+#ifndef __GPU_PRIMITIVE_H__
+#define __GPU_PRIMITIVE_H__
+
+#include "GPU_common.h"
+
+typedef enum {
+ GPU_PRIM_POINTS,
+ GPU_PRIM_LINES,
+ GPU_PRIM_TRIS,
+ GPU_PRIM_LINE_STRIP,
+ GPU_PRIM_LINE_LOOP, /* GL has this, Vulkan does not */
+ GPU_PRIM_TRI_STRIP,
+ GPU_PRIM_TRI_FAN,
+
+ GPU_PRIM_LINES_ADJ,
+ GPU_PRIM_TRIS_ADJ,
+ GPU_PRIM_LINE_STRIP_ADJ,
+
+ GPU_PRIM_NONE
+} GPUPrimType;
+
+/* what types of primitives does each shader expect? */
+typedef enum {
+ GPU_PRIM_CLASS_NONE = 0,
+ GPU_PRIM_CLASS_POINT = (1 << 0),
+ GPU_PRIM_CLASS_LINE = (1 << 1),
+ GPU_PRIM_CLASS_SURFACE = (1 << 2),
+ GPU_PRIM_CLASS_ANY = GPU_PRIM_CLASS_POINT | GPU_PRIM_CLASS_LINE | GPU_PRIM_CLASS_SURFACE
+} GPUPrimClass;
+
+GPUPrimClass GPU_primtype_class(GPUPrimType);
+bool GPU_primtype_belongs_to_class(GPUPrimType, GPUPrimClass);
+
+#endif /* __GPU_PRIMITIVE_H__ */
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index 53f480bccd7..f1342a1f6b8 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -57,4 +57,7 @@ void GPU_select_cache_begin(void);
void GPU_select_cache_load_id(void);
void GPU_select_cache_end(void);
+/* utilities */
+const uint *GPU_select_buffer_near(const uint *buffer, int hits);
+
#endif
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 5b94db6e120..308205339db 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -38,16 +38,18 @@ extern "C" {
typedef struct GPUShader GPUShader;
struct GPUTexture;
+struct GPUUniformBuffer;
/* GPU Shader
* - only for fragment shaders now
* - must call texture bind before setting a texture as uniform! */
-enum {
- GPU_SHADER_FLAGS_NONE = 0,
- GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0),
- GPU_SHADER_FLAGS_NEW_SHADING = (1 << 1),
-};
+typedef enum GPUShaderTFBType {
+ GPU_SHADER_TFB_NONE = 0, /* Transform feedback unsupported. */
+ GPU_SHADER_TFB_POINTS = 1,
+ GPU_SHADER_TFB_LINES = 2,
+ GPU_SHADER_TFB_TRIANGLES = 3,
+} GPUShaderTFBType;
GPUShader *GPU_shader_create(
const char *vertexcode,
@@ -55,29 +57,43 @@ GPUShader *GPU_shader_create(
const char *geocode,
const char *libcode,
const char *defines,
- int input, int output, int number);
+ const char *shader_name);
GPUShader *GPU_shader_create_ex(
const char *vertexcode,
const char *fragcode,
const char *geocode,
const char *libcode,
const char *defines,
- int input, int output, int number,
- const int flags);
+ const GPUShaderTFBType tf_type,
+ const char **tf_names,
+ const int tf_count,
+ const char *shader_name);
void GPU_shader_free(GPUShader *shader);
void GPU_shader_bind(GPUShader *shader);
void GPU_shader_unbind(void);
+/* Returns true if transform feedback was successfully enabled. */
+bool GPU_shader_transform_feedback_enable(GPUShader *shader, unsigned int vbo_id);
+void GPU_shader_transform_feedback_disable(GPUShader *shader);
+
+int GPU_shader_get_program(GPUShader *shader);
+
void *GPU_shader_get_interface(GPUShader *shader);
-void GPU_shader_set_interface(GPUShader *shader, void *interface);
+
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
-void GPU_shader_uniform_vector(GPUShader *shader, int location, int length,
- int arraysize, const float *value);
-void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length,
- int arraysize, const int *value);
+int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
+int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
+void GPU_shader_uniform_vector(
+ GPUShader *shader, int location, int length,
+ int arraysize, const float *value);
+void GPU_shader_uniform_vector_int(
+ GPUShader *shader, int location, int length,
+ int arraysize, const int *value);
+void GPU_shader_uniform_buffer(GPUShader *shader, int location, struct GPUUniformBuffer *ubo);
void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex);
+void GPU_shader_uniform_float(GPUShader *shader, int location, float value);
void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number);
@@ -85,15 +101,278 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name);
/* Builtin/Non-generated shaders */
typedef enum GPUBuiltinShader {
- GPU_SHADER_VSM_STORE = 0,
- GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
- GPU_SHADER_SMOKE = 2,
- GPU_SHADER_SMOKE_FIRE = 3,
- GPU_SHADER_SMOKE_COBA = 4,
+ /* specialized drawing */
+ GPU_SHADER_TEXT,
+ GPU_SHADER_TEXT_SIMPLE,
+ GPU_SHADER_EDGES_FRONT_BACK_PERSP,
+ GPU_SHADER_EDGES_FRONT_BACK_ORTHO,
+ GPU_SHADER_EDGES_OVERLAY_SIMPLE,
+ GPU_SHADER_EDGES_OVERLAY,
+ GPU_SHADER_KEYFRAME_DIAMOND,
+ GPU_SHADER_SIMPLE_LIGHTING,
+ GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR,
+ GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR,
+ GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA,
+
+ /* for simple 2D drawing */
+ /**
+ * Take a single color for all the vertices and a 2D position for each vertex.
+ *
+ * \param color: uniform vec4
+ * \param pos: in vec2
+ */
+ GPU_SHADER_2D_UNIFORM_COLOR,
+ /**
+ * Take a 2D position and color for each vertex without color interpolation.
+ *
+ * \param color: in vec4
+ * \param pos: in vec2
+ */
+ GPU_SHADER_2D_FLAT_COLOR,
+ /**
+ * Take a 2D position and color for each vertex with linear interpolation in window space.
+ *
+ * \param color: in vec4
+ * \param pos: in vec2
+ */
+ GPU_SHADER_2D_SMOOTH_COLOR,
+ GPU_SHADER_2D_SMOOTH_COLOR_DITHER,
+ GPU_SHADER_2D_IMAGE,
+ GPU_SHADER_2D_IMAGE_COLOR,
+ GPU_SHADER_2D_IMAGE_DESATURATE_COLOR,
+ GPU_SHADER_2D_IMAGE_ALPHA_COLOR,
+ GPU_SHADER_2D_IMAGE_ALPHA,
+ GPU_SHADER_2D_IMAGE_RECT_COLOR,
+ GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR,
+ GPU_SHADER_2D_IMAGE_MULTISAMPLE_2,
+ GPU_SHADER_2D_IMAGE_MULTISAMPLE_4,
+ GPU_SHADER_2D_IMAGE_MULTISAMPLE_8,
+ GPU_SHADER_2D_IMAGE_MULTISAMPLE_16,
+ GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST,
+ GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST,
+ GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST,
+ GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST,
+ GPU_SHADER_2D_CHECKER,
+ GPU_SHADER_2D_DIAG_STRIPES,
+ /* for simple 3D drawing */
+ /**
+ * Take a single color for all the vertices and a 3D position for each vertex.
+ *
+ * \param color: uniform vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_UNIFORM_COLOR,
+ GPU_SHADER_3D_UNIFORM_COLOR_U32,
+ GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE,
+ /**
+ * Take a 3D position and color for each vertex without color interpolation.
+ *
+ * \param color: in vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_FLAT_COLOR,
+ GPU_SHADER_3D_FLAT_COLOR_U32, /* use for select-id's */
+ /**
+ * Take a 3D position and color for each vertex with perspective correct interpolation.
+ *
+ * \param color: in vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_SMOOTH_COLOR,
+ /**
+ * Take a 3D position for each vertex and output only depth.
+ *
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_DEPTH_ONLY,
+ GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR,
+ /* basic image drawing */
+ GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB,
+ GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR,
+ GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR,
+ /**
+ * Draw texture with alpha. Take a 3D position and a 2D texture coordinate for each vertex.
+ *
+ * \param alpha: uniform float
+ * \param image: uniform sampler2D
+ * \param texCoord: in vec2
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_IMAGE_MODULATE_ALPHA,
+ /**
+ * Draw linearized depth texture relate to near and far distances.
+ * Take a 3D position and a 2D texture coordinate for each vertex.
+ *
+ * \param znear: uniform float
+ * \param zfar: uniform float
+ * \param image: uniform sampler2D
+ * \param texCoord: in vec2
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_IMAGE_DEPTH,
+ GPU_SHADER_3D_IMAGE_DEPTH_COPY,
+ /* stereo 3d */
+ GPU_SHADER_2D_IMAGE_INTERLACE,
+ /* points */
+ /**
+ * Draw round points with a hardcoded size.
+ * Take a single color for all the vertices and a 2D position for each vertex.
+ *
+ * \param color: uniform vec4
+ * \param pos: in vec2
+ */
+ GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR,
+ /**
+ * Draw round points with a constant size.
+ * Take a single color for all the vertices and a 2D position for each vertex.
+ *
+ * \param size: uniform float
+ * \param color: uniform vec4
+ * \param pos: in vec2
+ */
+ GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
+ /**
+ * Draw round points with a constant size and an outline.
+ * Take a single color for all the vertices and a 2D position for each vertex.
+ *
+ * \param size: uniform float
+ * \param outlineWidth: uniform float
+ * \param color: uniform vec4
+ * \param outlineColor: uniform vec4
+ * \param pos: in vec2
+ */
+ GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
+ /**
+ * Draw round points with a constant size and an outline. Take a 2D position and a color for each vertex.
+ *
+ * \param size: uniform float
+ * \param outlineWidth: uniform float
+ * \param outlineColor: uniform vec4
+ * \param color: in vec4
+ * \param pos: in vec2
+ */
+ GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA,
+ /**
+ * Draw round points with a constant size and an outline. Take a 2D position and a color for each vertex.
+ *
+ * \param size: in float
+ * \param color: in vec4
+ * \param pos: in vec2
+ */
+ GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR,
+ /**
+ * Draw round points with a hardcoded size.
+ * Take a single color for all the vertices and a 3D position for each vertex.
+ *
+ * \param color: uniform vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR,
+ /**
+ * Draw round points with a hardcoded size.
+ * Take a single color for all the vertices and a 3D position for each vertex.
+ *
+ * \param color: uniform vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR,
+ /**
+ * Draw round points with a constant size.
+ * Take a single color for all the vertices and a 3D position for each vertex.
+ *
+ * \param size: uniform float
+ * \param color: uniform vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
+ /**
+ * Draw round points with a constant size and an outline.
+ * Take a single color for all the vertices and a 3D position for each vertex.
+ *
+ * \param size: uniform float
+ * \param outlineWidth: uniform float
+ * \param color: uniform vec4
+ * \param outlineColor: uniform vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
+ /**
+ * Draw round points with a constant size and an outline.
+ * Take a single color for all the vertices and a 3D position for each vertex.
+ *
+ * \param color: uniform vec4
+ * \param size: in float
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR,
+ /**
+ * Draw round points with a constant size and an outline. Take a 3D position and a color for each vertex.
+ *
+ * \param size: in float
+ * \param color: in vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR,
+ /* lines */
+ GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR,
+ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR,
+ /* lamp drawing */
+ GPU_SHADER_3D_GROUNDPOINT,
+ GPU_SHADER_3D_GROUNDLINE,
+ GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR,
+ /* bone drawing */
+ GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR,
+ GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR,
+ /* camera drawing */
+ GPU_SHADER_CAMERA,
+ /* distance in front of objects */
+ GPU_SHADER_DISTANCE_LINES,
+ /* axis name */
+ GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS,
+ GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED,
+ /* instance */
+ GPU_SHADER_INSTANCE_UNIFORM_COLOR,
+ GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE, /* Uniformly scaled */
+ GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, /* Uniformly scaled */
+ GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE,
+ GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR,
+ /* grease pencil drawing */
+ GPU_SHADER_GPENCIL_STROKE,
+ GPU_SHADER_GPENCIL_FILL,
+ /* specialized for widget drawing */
+ GPU_SHADER_2D_AREA_EDGES,
+ GPU_SHADER_2D_WIDGET_BASE,
+ GPU_SHADER_2D_WIDGET_BASE_INST,
+ GPU_SHADER_2D_WIDGET_SHADOW,
+ GPU_SHADER_2D_NODELINK,
+ GPU_SHADER_2D_NODELINK_INST,
+ /* specialized for edituv drawing */
+ GPU_SHADER_2D_UV_VERTS,
+ GPU_SHADER_2D_UV_FACEDOTS,
+ GPU_SHADER_2D_UV_EDGES,
+ GPU_SHADER_2D_UV_EDGES_SMOOTH,
+ GPU_SHADER_2D_UV_FACES,
+ GPU_SHADER_2D_UV_FACES_STRETCH,
+
+ GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */
} GPUBuiltinShader;
+/** Keep these in sync with:
+ * - `gpu_shader_image_interlace_frag.glsl`
+ * - `gpu_shader_image_rect_interlace_frag.glsl`
+ */
+typedef enum GPUInterlaceShader {
+ GPU_SHADER_INTERLACE_ROW = 0,
+ GPU_SHADER_INTERLACE_COLUMN = 1,
+ GPU_SHADER_INTERLACE_CHECKER = 2,
+} GPUInterlaceShader;
+
GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
-GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
+
+void GPU_shader_get_builtin_shader_code(
+ GPUBuiltinShader shader,
+ const char **r_vert, const char **r_frag,
+ const char **r_geom, const char **r_defines);
void GPU_shader_free_builtin_shaders(void);
@@ -108,7 +387,7 @@ typedef struct GPUVertexAttribs {
int glinfoindoex;
int gltexco;
int attribid;
- char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
+ char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
} layer[GPU_MAX_ATTRIB];
int totlayer;
diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h
new file mode 100644
index 00000000000..af89e487cf8
--- /dev/null
+++ b/source/blender/gpu/GPU_shader_interface.h
@@ -0,0 +1,105 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_shader_interface.h
+ * \ingroup gpu
+ *
+ * GPU shader interface (C --> GLSL)
+ */
+
+#ifndef __GPU_SHADER_INTERFACE_H__
+#define __GPU_SHADER_INTERFACE_H__
+
+#include "GPU_common.h"
+
+typedef enum {
+ GPU_UNIFORM_NONE = 0, /* uninitialized/unknown */
+
+ GPU_UNIFORM_MODEL, /* mat4 ModelMatrix */
+ GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */
+ GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */
+ GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */
+ GPU_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */
+ GPU_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */
+
+ GPU_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */
+ GPU_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */
+ GPU_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */
+ GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */
+ GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */
+
+ GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */
+ GPU_UNIFORM_WORLDNORMAL, /* mat3 WorldNormalMatrix */
+ GPU_UNIFORM_CAMERATEXCO, /* vec4 CameraTexCoFactors */
+ GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */
+
+ GPU_UNIFORM_COLOR, /* vec4 color */
+ GPU_UNIFORM_EYE, /* vec3 eye */
+ GPU_UNIFORM_CALLID, /* int callId */
+ GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */
+
+ GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */
+
+ GPU_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */
+} GPUUniformBuiltin;
+
+typedef struct GPUShaderInput {
+ struct GPUShaderInput *next;
+ uint32_t name_offset;
+ uint name_hash;
+ GPUUniformBuiltin builtin_type; /* only for uniform inputs */
+ uint32_t gl_type; /* only for attrib inputs */
+ int32_t size; /* only for attrib inputs */
+ int32_t location;
+} GPUShaderInput;
+
+#define GPU_NUM_SHADERINTERFACE_BUCKETS 257
+#define GPU_SHADERINTERFACE_REF_ALLOC_COUNT 16
+
+typedef struct GPUShaderInterface {
+ int32_t program;
+ uint32_t name_buffer_offset;
+ GPUShaderInput *attrib_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS];
+ GPUShaderInput *uniform_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS];
+ GPUShaderInput *ubo_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS];
+ GPUShaderInput *builtin_uniforms[GPU_NUM_UNIFORMS];
+ char *name_buffer;
+ struct GPUBatch **batches; /* references to batches using this interface */
+ uint batches_len;
+} GPUShaderInterface;
+
+GPUShaderInterface *GPU_shaderinterface_create(int32_t program_id);
+void GPU_shaderinterface_discard(GPUShaderInterface *);
+
+const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *, const char *name);
+const GPUShaderInput *GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *, GPUUniformBuiltin);
+const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *, const char *name);
+const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *, const char *name);
+
+/* keep track of batches using this interface */
+void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *, struct GPUBatch *);
+void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *, struct GPUBatch *);
+
+#endif /* __GPU_SHADER_INTERFACE_H__ */
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
new file mode 100644
index 00000000000..057caffd17d
--- /dev/null
+++ b/source/blender/gpu/GPU_state.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.
+ *
+ * Contributor(s): Ray Molenkamp
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_state.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_STATE_H__
+#define __GPU_STATE_H__
+
+/* These map directly to the GL_ blend functions, to minimize API add as needed*/
+typedef enum GPUBlendFunction {
+ GPU_ONE,
+ GPU_SRC_ALPHA,
+ GPU_ONE_MINUS_SRC_ALPHA,
+ GPU_DST_COLOR,
+ GPU_ZERO,
+} GPUBlendFunction;
+
+/* These map directly to the GL_ filter functions, to minimize API add as needed*/
+typedef enum GPUFilterFunction {
+ GPU_NEAREST,
+ GPU_LINEAR
+} GPUFilterFunction;
+
+void GPU_blend(bool enable);
+void GPU_blend_set_func(GPUBlendFunction sfactor, GPUBlendFunction dfactor);
+void GPU_blend_set_func_separate(
+ GPUBlendFunction src_rgb, GPUBlendFunction dst_rgb,
+ GPUBlendFunction src_alpha, GPUBlendFunction dst_alpha);
+void GPU_depth_range(float near, float far);
+void GPU_depth_test(bool enable);
+bool GPU_depth_test_enabled(void);
+void GPU_line_smooth(bool enable);
+void GPU_line_stipple(bool enable);
+void GPU_line_width(float width);
+void GPU_point_size(float size);
+void GPU_polygon_smooth(bool enable);
+void GPU_scissor(int x, int y, int width, int height);
+void GPU_scissor_get_f(float coords[4]);
+void GPU_scissor_get_i(int coords[4]);
+void GPU_viewport_size_get_f(float coords[4]);
+void GPU_viewport_size_get_i(int coords[4]);
+
+void GPU_flush(void);
+void GPU_finish(void);
+
+#endif /* __GPU_STATE_H__ */
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 0aa6d86689e..7a10c2f4854 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -32,6 +32,8 @@
#ifndef __GPU_TEXTURE_H__
#define __GPU_TEXTURE_H__
+#include "GPU_state.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -39,6 +41,7 @@ extern "C" {
struct Image;
struct ImageUser;
struct PreviewImage;
+struct GPUVertBuf;
struct GPUFrameBuffer;
typedef struct GPUTexture GPUTexture;
@@ -55,25 +58,142 @@ typedef struct GPUTexture GPUTexture;
* - if created with from_blender, will not free the texture
*/
-typedef enum GPUHDRType {
- GPU_HDR_NONE = 0,
- GPU_HDR_HALF_FLOAT = 1,
- GPU_HDR_FULL_FLOAT = (1 << 1),
-} GPUHDRType;
-
-GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]);
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
-GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
-GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
-GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
+/* Wrapper to supported OpenGL/Vulkan texture internal storage
+ * If you need a type just uncomment it. Be aware that some formats
+ * are not supported by renderbuffers. All of the following formats
+ * are part of the OpenGL 3.3 core
+ * specification. */
+typedef enum GPUTextureFormat {
+ /* Formats texture & renderbuffer */
+ GPU_RGBA8UI,
+ GPU_RGBA8I,
+ GPU_RGBA8,
+ GPU_RGBA32UI,
+ GPU_RGBA32I,
+ GPU_RGBA32F,
+ GPU_RGBA16UI,
+ GPU_RGBA16I,
+ GPU_RGBA16F,
+ GPU_RGBA16,
+ GPU_RG8UI,
+ GPU_RG8I,
+ GPU_RG8,
+ GPU_RG32UI,
+ GPU_RG32I,
+ GPU_RG32F,
+ GPU_RG16UI,
+ GPU_RG16I,
+ GPU_RG16F,
+ GPU_RG16,
+ GPU_R8UI,
+ GPU_R8I,
+ GPU_R8,
+ GPU_R32UI,
+ GPU_R32I,
+ GPU_R32F,
+ GPU_R16UI,
+ GPU_R16I,
+ GPU_R16F,
+ GPU_R16, /* Max texture buffer format. */
+
+ /* Special formats texture & renderbuffer */
+#if 0
+ GPU_RGB10_A2,
+ GPU_RGB10_A2UI,
+#endif
+ GPU_R11F_G11F_B10F,
+ GPU_DEPTH32F_STENCIL8,
+ GPU_DEPTH24_STENCIL8,
+
+ /* Texture only format */
+ GPU_RGB16F,
+#if 0
+ GPU_RGBA16_SNORM,
+ GPU_RGBA8_SNORM,
+ GPU_RGB32F,
+ GPU_RGB32I,
+ GPU_RGB32UI,
+ GPU_RGB16_SNORM,
+ GPU_RGB16I,
+ GPU_RGB16UI,
+ GPU_RGB16,
+ GPU_RGB8_SNORM,
+ GPU_RGB8,
+ GPU_RGB8I,
+ GPU_RGB8UI,
+ GPU_RG16_SNORM,
+ GPU_RG8_SNORM,
+ GPU_R16_SNORM,
+ GPU_R8_SNORM,
+#endif
+
+ /* Special formats texture only */
+#if 0
+ GPU_SRGB8_A8,
+ GPU_SRGB8,
+ GPU_RGB9_E5,
+ GPU_COMPRESSED_RG_RGTC2,
+ GPU_COMPRESSED_SIGNED_RG_RGTC2,
+ GPU_COMPRESSED_RED_RGTC1,
+ GPU_COMPRESSED_SIGNED_RED_RGTC1,
+#endif
+
+ /* Depth Formats */
+ GPU_DEPTH_COMPONENT32F,
+ GPU_DEPTH_COMPONENT24,
+ GPU_DEPTH_COMPONENT16,
+} GPUTextureFormat;
+
+typedef enum GPUDataFormat {
+ GPU_DATA_FLOAT,
+ GPU_DATA_INT,
+ GPU_DATA_UNSIGNED_INT,
+ GPU_DATA_UNSIGNED_BYTE,
+ GPU_DATA_UNSIGNED_INT_24_8,
+ GPU_DATA_10_11_11_REV,
+} GPUDataFormat;
+
+unsigned int GPU_texture_memory_usage_get(void);
+
+/* TODO make it static function again. (create function with GPUDataFormat exposed) */
+GPUTexture *GPU_texture_create_nD(
+ int w, int h, int d, int n, const void *pixels,
+ GPUTextureFormat tex_format, GPUDataFormat gpu_data_format, int samples,
+ const bool can_rescale, char err_out[256]);
+
+GPUTexture *GPU_texture_create_1D(
+ int w, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_1D_array(
+ int w, int h, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D(
+ int w, int h, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_2D_multisample(
- int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]);
-GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]);
+ int w, int h, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_array(
+ int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_3D(
+ int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_cube(
+ int w, GPUTextureFormat data_type, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_from_vertbuf(
+ struct GPUVertBuf *vert);
+GPUTexture *GPU_texture_create_buffer(
+ GPUTextureFormat data_type, const uint buffer);
+
+GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode);
GPUTexture *GPU_texture_from_blender(
- struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap);
+ struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
+
+void GPU_texture_add_mipmap(GPUTexture *tex, GPUDataFormat gpu_data_format, int miplvl, const void *pixels);
+
+void GPU_texture_update(GPUTexture *tex, GPUDataFormat data_format, const void *pixels);
+void GPU_texture_update_sub(
+ GPUTexture *tex, GPUDataFormat gpu_data_format, const void *pixels,
+ int offset_x, int offset_y, int offset_z, int width, int height, int depth);
+
+void *GPU_texture_read(GPUTexture *tex, GPUDataFormat gpu_data_format, int miplvl);
+
void GPU_invalid_tex_init(void);
void GPU_invalid_tex_bind(int mode);
void GPU_invalid_tex_free(void);
@@ -81,23 +201,34 @@ void GPU_invalid_tex_free(void);
void GPU_texture_free(GPUTexture *tex);
void GPU_texture_ref(GPUTexture *tex);
-
void GPU_texture_bind(GPUTexture *tex, int number);
void GPU_texture_unbind(GPUTexture *tex);
int GPU_texture_bound_number(GPUTexture *tex);
-void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter);
+void GPU_texture_generate_mipmap(GPUTexture *tex);
+void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare);
+void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter);
+void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter);
+void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat);
+void GPU_texture_filters(GPUTexture *tex, GPUFilterFunction min_filter, GPUFilterFunction mag_filter);
-struct GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
-int GPU_texture_framebuffer_attachment(GPUTexture *tex);
-void GPU_texture_framebuffer_set(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment);
+void GPU_texture_attach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment);
+int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb);
int GPU_texture_target(const GPUTexture *tex);
int GPU_texture_width(const GPUTexture *tex);
int GPU_texture_height(const GPUTexture *tex);
-int GPU_texture_depth(const GPUTexture *tex);
+int GPU_texture_layers(const GPUTexture *tex);
+GPUTextureFormat GPU_texture_format(const GPUTexture *tex);
+int GPU_texture_samples(const GPUTexture *tex);
+bool GPU_texture_cube(const GPUTexture *tex);
+bool GPU_texture_depth(const GPUTexture *tex);
+bool GPU_texture_stencil(const GPUTexture *tex);
+bool GPU_texture_integer(const GPUTexture *tex);
int GPU_texture_opengl_bindcode(const GPUTexture *tex);
+void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h
new file mode 100644
index 00000000000..2f422fa1a92
--- /dev/null
+++ b/source/blender/gpu/GPU_uniformbuffer.h
@@ -0,0 +1,57 @@
+/*
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Clement Foucault.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_uniformbuffer.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_UNIFORMBUFFER_H__
+#define __GPU_UNIFORMBUFFER_H__
+
+struct ListBase;
+
+typedef struct GPUUniformBuffer GPUUniformBuffer;
+
+GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]);
+GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(struct ListBase *inputs, char err_out[256]);
+
+void GPU_uniformbuffer_free(GPUUniformBuffer *ubo);
+
+void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data);
+void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_);
+
+void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number);
+void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo);
+
+int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo);
+
+bool GPU_uniformbuffer_is_empty(GPUUniformBuffer *ubo);
+bool GPU_uniformbuffer_is_dirty(GPUUniformBuffer *ubo);
+
+#define GPU_UBO_BLOCK_NAME "nodeTree"
+
+#endif /* __GPU_UNIFORMBUFFER_H__ */
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
new file mode 100644
index 00000000000..db1309bcede
--- /dev/null
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -0,0 +1,144 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_vertex_buffer.h
+ * \ingroup gpu
+ *
+ * GPU vertex buffer
+ */
+
+#ifndef __GPU_VERTEX_BUFFER_H__
+#define __GPU_VERTEX_BUFFER_H__
+
+#include "GPU_vertex_format.h"
+
+#define VRAM_USAGE 1
+/* How to create a GPUVertBuf: */
+/* 1) verts = GPU_vertbuf_create() or GPU_vertbuf_init(verts) */
+/* 2) GPU_vertformat_attr_add(verts->format, ...) */
+/* 3) GPU_vertbuf_data_alloc(verts, vertex_len) <-- finalizes/packs vertex format */
+/* 4) GPU_vertbuf_attr_fill(verts, pos, application_pos_buffer) */
+
+/* Is GPUVertBuf always used as part of a GPUBatch? */
+
+typedef enum {
+ /* can be extended to support more types */
+ GPU_USAGE_STREAM,
+ GPU_USAGE_STATIC, /* do not keep data in memory */
+ GPU_USAGE_DYNAMIC
+} GPUUsageType;
+
+typedef struct GPUVertBuf {
+ GPUVertFormat format;
+ uint vertex_len; /* number of verts we want to draw */
+ uint vertex_alloc; /* number of verts data */
+ bool dirty;
+ unsigned char *data; /* NULL indicates data in VRAM (unmapped) */
+ uint32_t vbo_id; /* 0 indicates not yet allocated */
+ GPUUsageType usage; /* usage hint for GL optimisation */
+} GPUVertBuf;
+
+GPUVertBuf *GPU_vertbuf_create(GPUUsageType);
+GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *, GPUUsageType);
+
+#define GPU_vertbuf_create_with_format(format) \
+ GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_STATIC)
+
+void GPU_vertbuf_discard(GPUVertBuf *);
+
+void GPU_vertbuf_init(GPUVertBuf *, GPUUsageType);
+void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsageType);
+
+#define GPU_vertbuf_init_with_format(verts, format) \
+ GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_STATIC)
+
+uint GPU_vertbuf_size_get(const GPUVertBuf *);
+void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len);
+void GPU_vertbuf_data_resize(GPUVertBuf *, uint v_len);
+void GPU_vertbuf_vertex_count_set(GPUVertBuf *, uint v_len);
+
+/* The most important set_attrib variant is the untyped one. Get it right first. */
+/* It takes a void* so the app developer is responsible for matching their app data types */
+/* to the vertex attribute's type and component count. They're in control of both, so this */
+/* should not be a problem. */
+
+void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data);
+void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data); /* tightly packed, non interleaved input data */
+void GPU_vertbuf_attr_fill_stride(GPUVertBuf *, uint a_idx, uint stride, const void *data);
+
+/* For low level access only */
+typedef struct GPUVertBufRaw {
+ uint size;
+ uint stride;
+ unsigned char *data;
+ unsigned char *data_init;
+#if TRUST_NO_ONE
+ /* Only for overflow check */
+ unsigned char *_data_end;
+#endif
+} GPUVertBufRaw;
+
+GPU_INLINE void *GPU_vertbuf_raw_step(GPUVertBufRaw *a)
+{
+ unsigned char *data = a->data;
+ a->data += a->stride;
+#if TRUST_NO_ONE
+ assert(data < a->_data_end);
+#endif
+ return (void *)data;
+}
+
+GPU_INLINE uint GPU_vertbuf_raw_used(GPUVertBufRaw *a)
+{
+ return ((a->data - a->data_init) / a->stride);
+}
+
+void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *, uint a_idx, GPUVertBufRaw *access);
+
+/* TODO: decide whether to keep the functions below */
+/* doesn't immediate mode satisfy these needs? */
+
+/* void setAttrib1f(uint a_idx, uint v_idx, float x); */
+/* void setAttrib2f(uint a_idx, unsigned v_idx, float x, float y); */
+/* void setAttrib3f(unsigned a_idx, unsigned v_idx, float x, float y, float z); */
+/* void setAttrib4f(unsigned a_idx, unsigned v_idx, float x, float y, float z, float w); */
+
+/* void setAttrib3ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b); */
+/* void setAttrib4ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b, unsigned char a); */
+
+void GPU_vertbuf_use(GPUVertBuf *);
+
+/* Metrics */
+uint GPU_vertbuf_get_memory_usage(void);
+
+/* Macros */
+#define GPU_VERTBUF_DISCARD_SAFE(verts) do { \
+ if (verts != NULL) { \
+ GPU_vertbuf_discard(verts); \
+ verts = NULL; \
+ } \
+} while (0)
+
+#endif /* __GPU_VERTEX_BUFFER_H__ */
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
new file mode 100644
index 00000000000..113a3e894d0
--- /dev/null
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -0,0 +1,107 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/GPU_vertex_format.h
+ * \ingroup gpu
+ *
+ * GPU vertex format
+ */
+
+#ifndef __GPU_VERTEX_FORMAT_H__
+#define __GPU_VERTEX_FORMAT_H__
+
+#include "GPU_common.h"
+
+#define GPU_VERT_ATTR_MAX_LEN 16
+#define GPU_VERT_ATTR_MAX_NAMES 3
+#define GPU_VERT_ATTR_NAME_AVERAGE_LEN 11
+#define GPU_VERT_ATTR_NAMES_BUF_LEN ((GPU_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GPU_VERT_ATTR_MAX_LEN)
+
+typedef enum {
+ GPU_COMP_I8,
+ GPU_COMP_U8,
+ GPU_COMP_I16,
+ GPU_COMP_U16,
+ GPU_COMP_I32,
+ GPU_COMP_U32,
+
+ GPU_COMP_F32,
+
+ GPU_COMP_I10
+} GPUVertCompType;
+
+typedef enum {
+ GPU_FETCH_FLOAT,
+ GPU_FETCH_INT,
+ GPU_FETCH_INT_TO_FLOAT_UNIT, /* 127 (ubyte) -> 0.5 (and so on for other int types) */
+ GPU_FETCH_INT_TO_FLOAT /* 127 (any int type) -> 127.0 */
+} GPUVertFetchMode;
+
+typedef struct GPUVertAttr {
+ GPUVertFetchMode fetch_mode;
+ GPUVertCompType comp_type;
+ uint gl_comp_type;
+ uint comp_len; /* 1 to 4 or 8 or 12 or 16 */
+ uint sz; /* size in bytes, 1 to 64 */
+ uint offset; /* from beginning of vertex, in bytes */
+ uint name_len; /* up to GPU_VERT_ATTR_MAX_NAMES */
+ const char *name[GPU_VERT_ATTR_MAX_NAMES];
+} GPUVertAttr;
+
+typedef struct GPUVertFormat {
+ uint attr_len; /* 0 to 16 (GPU_VERT_ATTR_MAX_LEN) */
+ uint name_len; /* total count of active vertex attrib */
+ uint stride; /* stride in bytes, 1 to 256 */
+ uint name_offset;
+ bool packed;
+ char names[GPU_VERT_ATTR_NAMES_BUF_LEN];
+ GPUVertAttr attribs[GPU_VERT_ATTR_MAX_LEN]; /* TODO: variable-size attribs array */
+} GPUVertFormat;
+
+struct GPUShaderInterface;
+
+void GPU_vertformat_clear(GPUVertFormat *);
+void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src);
+void GPU_vertformat_from_interface(GPUVertFormat *format, const struct GPUShaderInterface *shaderface);
+
+uint GPU_vertformat_attr_add(
+ GPUVertFormat *, const char *name,
+ GPUVertCompType, uint comp_len, GPUVertFetchMode);
+void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
+int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
+
+/* format conversion */
+
+typedef struct GPUPackedNormal {
+ int x : 10;
+ int y : 10;
+ int z : 10;
+ int w : 2; /* 0 by default, can manually set to { -2, -1, 0, 1 } */
+} GPUPackedNormal;
+
+GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3]);
+GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3]);
+
+#endif /* __GPU_VERTEX_FORMAT_H__ */
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
new file mode 100644
index 00000000000..45712050b73
--- /dev/null
+++ b/source/blender/gpu/GPU_viewport.h
@@ -0,0 +1,130 @@
+/*
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_viewport.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_VIEWPORT_H__
+#define __GPU_VIEWPORT_H__
+
+#include <stdbool.h>
+
+#include "DNA_vec_types.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
+
+#define GPU_INFO_SIZE 512 /* IMA_MAX_RENDER_TEXT */
+
+typedef struct GPUViewport GPUViewport;
+
+/* Contains memory pools information */
+typedef struct ViewportMemoryPool {
+ struct BLI_mempool *calls;
+ struct BLI_mempool *states;
+ struct BLI_mempool *shgroups;
+ struct BLI_mempool *uniforms;
+ struct BLI_mempool *passes;
+} ViewportMemoryPool;
+
+/* All FramebufferLists are just the same pointers with different names */
+typedef struct FramebufferList {
+ struct GPUFrameBuffer *framebuffers[0];
+} FramebufferList;
+
+typedef struct TextureList {
+ struct GPUTexture *textures[0];
+} TextureList;
+
+typedef struct PassList {
+ struct DRWPass *passes[0];
+} PassList;
+
+typedef struct StorageList {
+ void *storage[0]; /* custom structs from the engine */
+} StorageList;
+
+typedef struct ViewportEngineData {
+ void *engine_type;
+
+ FramebufferList *fbl;
+ TextureList *txl;
+ PassList *psl;
+ StorageList *stl;
+ char info[GPU_INFO_SIZE];
+
+ /* we may want to put this elsewhere */
+ struct DRWTextStore *text_draw_cache;
+
+ /* Profiling data */
+ double init_time;
+ double render_time;
+ double background_time;
+} ViewportEngineData;
+
+typedef struct ViewportEngineData_Info {
+ int fbl_len;
+ int txl_len;
+ int psl_len;
+ int stl_len;
+} ViewportEngineData_Info;
+
+GPUViewport *GPU_viewport_create(void);
+void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect);
+void GPU_viewport_unbind(GPUViewport *viewport);
+void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect);
+void GPU_viewport_free(GPUViewport *viewport);
+
+GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs);
+void GPU_viewport_clear_from_offscreen(GPUViewport *viewport);
+
+ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport);
+struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport);
+
+void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type);
+void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type);
+void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport);
+void *GPU_viewport_texture_list_get(GPUViewport *viewport);
+void GPU_viewport_size_get(const GPUViewport *viewport, int size[2]);
+void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]);
+
+/* Profiling */
+double *GPU_viewport_cache_time_get(GPUViewport *viewport);
+
+void GPU_viewport_tag_update(GPUViewport *viewport);
+bool GPU_viewport_do_update(GPUViewport *viewport);
+
+GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport);
+
+/* Texture pool */
+GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int format);
+
+bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash);
+void GPU_viewport_cache_release(GPUViewport *viewport);
+
+#endif // __GPU_VIEWPORT_H__
diff --git a/source/blender/gpu/intern/gpu_attr_binding.c b/source/blender/gpu/intern/gpu_attr_binding.c
new file mode 100644
index 00000000000..398b97c7f9d
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_attr_binding.c
@@ -0,0 +1,85 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_attr_binding.c
+ * \ingroup gpu
+ *
+ * GPU vertex attribute binding
+ */
+
+#include "GPU_attr_binding.h"
+#include "gpu_attr_binding_private.h"
+#include <stddef.h>
+#include <stdlib.h>
+
+#if GPU_VERT_ATTR_MAX_LEN != 16
+# error "attrib binding code assumes GPU_VERT_ATTR_MAX_LEN = 16"
+#endif
+
+void AttribBinding_clear(GPUAttrBinding *binding)
+{
+ binding->loc_bits = 0;
+ binding->enabled_bits = 0;
+}
+
+uint read_attrib_location(const GPUAttrBinding *binding, uint a_idx)
+{
+#if TRUST_NO_ONE
+ assert(a_idx < GPU_VERT_ATTR_MAX_LEN);
+ assert(binding->enabled_bits & (1 << a_idx));
+#endif
+ return (binding->loc_bits >> (4 * a_idx)) & 0xF;
+}
+
+static void write_attrib_location(GPUAttrBinding *binding, uint a_idx, uint location)
+{
+#if TRUST_NO_ONE
+ assert(a_idx < GPU_VERT_ATTR_MAX_LEN);
+ assert(location < GPU_VERT_ATTR_MAX_LEN);
+#endif
+ const uint shift = 4 * a_idx;
+ const uint64_t mask = ((uint64_t)0xF) << shift;
+ /* overwrite this attrib's previous location */
+ binding->loc_bits = (binding->loc_bits & ~mask) | (location << shift);
+ /* mark this attrib as enabled */
+ binding->enabled_bits |= 1 << a_idx;
+}
+
+void get_attrib_locations(const GPUVertFormat *format, GPUAttrBinding *binding, const GPUShaderInterface *shaderface)
+{
+ AttribBinding_clear(binding);
+
+ for (uint a_idx = 0; a_idx < format->attr_len; ++a_idx) {
+ const GPUVertAttr *a = format->attribs + a_idx;
+ for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
+ const GPUShaderInput *input = GPU_shaderinterface_attr(shaderface, a->name[n_idx]);
+#if TRUST_NO_ONE
+ assert(input != NULL);
+ /* TODO: make this a recoverable runtime error? indicates mismatch between vertex format and program */
+#endif
+ write_attrib_location(binding, a_idx, input->location);
+ }
+ }
+}
diff --git a/source/blender/gpu/intern/gpu_attr_binding_private.h b/source/blender/gpu/intern/gpu_attr_binding_private.h
new file mode 100644
index 00000000000..c545983637c
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_attr_binding_private.h
@@ -0,0 +1,45 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_attr_binding_private.h
+ * \ingroup gpu
+ *
+ * GPU vertex attribute binding
+ */
+
+#ifndef __GPU_ATTR_BINDING_PRIVATE_H__
+#define __GPU_ATTR_BINDING_PRIVATE_H__
+
+#include "GPU_vertex_format.h"
+#include "GPU_shader_interface.h"
+
+void AttribBinding_clear(GPUAttrBinding *binding);
+
+void get_attrib_locations(
+ const GPUVertFormat *format, GPUAttrBinding *binding, const GPUShaderInterface *shaderface);
+uint read_attrib_location(
+ const GPUAttrBinding *binding, uint a_idx);
+
+#endif /* __GPU_ATTR_BINDING_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
deleted file mode 100644
index 5d23de78451..00000000000
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ /dev/null
@@ -1,718 +0,0 @@
-/*
- * ***** 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) 2013 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/gpu/intern/gpu_basic_shader.c
- * \ingroup gpu
- *
- * GLSL shaders to replace fixed function OpenGL materials and lighting. These
- * are deprecated in newer OpenGL versions and missing in OpenGL ES 2.0. Also,
- * two sided lighting is no longer natively supported on NVidia cards which
- * results in slow software fallback.
- *
- * Todo:
- * - Replace glLight and glMaterial functions entirely with GLSL uniforms, to
- * make OpenGL ES 2.0 work.
- * - Replace glTexCoord and glColor with generic attributes.
- * - Optimize for case where fewer than 3 or 8 lights are used.
- * - Optimize for case where specular is not used.
- * - Optimize for case where no texture matrix is used.
- */
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "GPU_basic_shader.h"
-#include "GPU_glew.h"
-#include "GPU_shader.h"
-
-/* State */
-
-static struct {
- GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS];
- bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS];
-
- int bound_options;
-
- int lights_enabled;
- int lights_directional;
- float line_width;
- GLint viewport[4];
-} GPU_MATERIAL_STATE;
-
-
-/* Stipple patterns */
-/* ******************************************** */
-const GLubyte stipple_halftone[128] = {
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
-
-const GLubyte stipple_quarttone[128] = {
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0};
-
-const GLubyte stipple_diag_stripes_pos[128] = {
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
- 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
- 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
- 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
- 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
- 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
- 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
- 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
- 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
- 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
- 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
- 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
- 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
- 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
- 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f};
-
-const GLubyte stipple_diag_stripes_neg[128] = {
- 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
- 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
- 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
- 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
- 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
- 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
- 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
- 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
- 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
- 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
- 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
- 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
- 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
- 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80};
-
-const GLubyte stipple_checker_8px[128] = {
- 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
- 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
- 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
- 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
- 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
- 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
- 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
- 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255};
-
-const GLubyte stipple_interlace_row[128] = {
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};
-
-const GLubyte stipple_interlace_row_swap[128] = {
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};
-
-const GLubyte stipple_interlace_column[128] = {
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
-
-const GLubyte stipple_interlace_column_swap[128] = {
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
-
-const GLubyte stipple_interlace_checker[128] = {
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa};
-
-const GLubyte stipple_interlace_checker_swap[128] = {
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
- 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55};
-
-const GLubyte stipple_hexagon[128] = {
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22};
-/* ********************************************* */
-
-/* GLSL State */
-
-static bool USE_GLSL = false;
-
-/**
- * \note this isn't part of the basic shader API,
- * only set from the command line once on startup.
- */
-void GPU_basic_shader_use_glsl_set(bool enabled)
-{
- USE_GLSL = enabled;
-}
-
-bool GPU_basic_shader_use_glsl_get(void)
-{
- return USE_GLSL;
-}
-
-/* Init / exit */
-
-void GPU_basic_shaders_init(void)
-{
- memset(&GPU_MATERIAL_STATE, 0, sizeof(GPU_MATERIAL_STATE));
-}
-
-void GPU_basic_shaders_exit(void)
-{
- int i;
-
- for (i = 0; i < GPU_SHADER_OPTION_COMBINATIONS; i++)
- if (GPU_MATERIAL_STATE.cached_shaders[i])
- GPU_shader_free(GPU_MATERIAL_STATE.cached_shaders[i]);
-}
-
-/* Shader lookup / create */
-
-static bool solid_compatible_lighting(void)
-{
- int enabled = GPU_MATERIAL_STATE.lights_enabled;
- int directional = GPU_MATERIAL_STATE.lights_directional;
-
- /* more than 3 lights? */
- if (enabled >= (1 << 3))
- return false;
-
- /* all directional? */
- return ((directional & enabled) == enabled);
-}
-
-#if 0
-static int detect_options()
-{
- GLint two_sided;
- int options = 0;
-
- if (glIsEnabled(GL_TEXTURE_2D))
- options |= GPU_SHADER_TEXTURE_2D;
- if (glIsEnabled(GL_TEXTURE_RECTANGLE))
- options |= GPU_SHADER_TEXTURE_RECT;
- GPU_SHADER_TEXTURE_RECT
- if (glIsEnabled(GL_COLOR_MATERIAL))
- options |= GPU_SHADER_USE_COLOR;
-
- if (glIsEnabled(GL_LIGHTING))
- options |= GPU_SHADER_LIGHTING;
-
- glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &two_sided);
- if (two_sided == GL_TRUE)
- options |= GPU_SHADER_TWO_SIDED;
-
- return options;
-}
-#endif
-
-static GPUShader *gpu_basic_shader(int options)
-{
- /* glsl code */
- extern char datatoc_gpu_shader_basic_vert_glsl[];
- extern char datatoc_gpu_shader_basic_frag_glsl[];
- extern char datatoc_gpu_shader_basic_geom_glsl[];
- char *geom_glsl = NULL;
- GPUShader *shader;
-
- /* detect if we can do faster lighting for solid draw mode */
- if (options & GPU_SHADER_LIGHTING)
- if (solid_compatible_lighting())
- options |= GPU_SHADER_SOLID_LIGHTING;
-
- /* cached shaders */
- shader = GPU_MATERIAL_STATE.cached_shaders[options];
-
- if (!shader && !GPU_MATERIAL_STATE.failed_shaders[options]) {
- /* create shader if it doesn't exist yet */
- char defines[64 * GPU_SHADER_OPTIONS_NUM] = "";
-
- if (options & GPU_SHADER_USE_COLOR)
- strcat(defines, "#define USE_COLOR\n");
- if (options & GPU_SHADER_TWO_SIDED)
- strcat(defines, "#define USE_TWO_SIDED\n");
- if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT))
- strcat(defines, "#define USE_TEXTURE\n");
- if (options & GPU_SHADER_TEXTURE_RECT)
- strcat(defines, "#define USE_TEXTURE_RECTANGLE\n");
- if (options & GPU_SHADER_STIPPLE)
- strcat(defines, "#define USE_STIPPLE\n");
- if (options & GPU_SHADER_LINE) {
- strcat(defines, "#define DRAW_LINE\n");
- geom_glsl = datatoc_gpu_shader_basic_geom_glsl;
- }
- if (options & GPU_SHADER_FLAT_NORMAL)
- strcat(defines, "#define USE_FLAT_NORMAL\n");
- if (options & GPU_SHADER_SOLID_LIGHTING)
- strcat(defines, "#define USE_SOLID_LIGHTING\n");
- else if (options & GPU_SHADER_LIGHTING)
- strcat(defines, "#define USE_SCENE_LIGHTING\n");
-
- shader = GPU_shader_create(
- datatoc_gpu_shader_basic_vert_glsl,
- datatoc_gpu_shader_basic_frag_glsl,
- geom_glsl,
- NULL,
- defines, 0, 0, 0);
-
- if (shader) {
- /* set texture map to first texture unit */
- if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT)) {
- GPU_shader_bind(shader);
- glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0);
- GPU_shader_unbind();
- }
-
- GPU_MATERIAL_STATE.cached_shaders[options] = shader;
- }
- else
- GPU_MATERIAL_STATE.failed_shaders[options] = true;
- }
-
- return shader;
-}
-
-static void gpu_basic_shader_uniform_autoset(GPUShader *shader, int options)
-{
- if (options & GPU_SHADER_LINE) {
- glGetIntegerv(GL_VIEWPORT, &GPU_MATERIAL_STATE.viewport[0]);
- glUniform4iv(GPU_shader_get_uniform(shader, "viewport"), 1, &GPU_MATERIAL_STATE.viewport[0]);
- glUniform1f(GPU_shader_get_uniform(shader, "line_width"), GPU_MATERIAL_STATE.line_width);
- }
-}
-
-/* Bind / unbind */
-
-void GPU_basic_shader_bind(int options)
-{
- if (USE_GLSL) {
- if (options) {
- const int bound_options = GPU_MATERIAL_STATE.bound_options;
-
- /* texture options need to be set for basic shader too */
- if (options & GPU_SHADER_TEXTURE_2D) {
- glEnable(GL_TEXTURE_2D);
- }
- else if (bound_options & GPU_SHADER_TEXTURE_2D) {
- glDisable(GL_TEXTURE_2D);
- }
-
- if (options & GPU_SHADER_TEXTURE_RECT) {
- glEnable(GL_TEXTURE_RECTANGLE);
- }
- else if (bound_options & GPU_SHADER_TEXTURE_RECT) {
- glDisable(GL_TEXTURE_RECTANGLE);
- }
-
- GPUShader *shader = gpu_basic_shader(options);
-
- if (shader) {
- GPU_shader_bind(shader);
- gpu_basic_shader_uniform_autoset(shader, options);
- }
- }
- else {
- GPU_shader_unbind();
- }
- }
- else {
- const int bound_options = GPU_MATERIAL_STATE.bound_options;
-
- if (options & GPU_SHADER_LIGHTING) {
- glEnable(GL_LIGHTING);
-
- if (options & GPU_SHADER_USE_COLOR)
- glEnable(GL_COLOR_MATERIAL);
- else
- glDisable(GL_COLOR_MATERIAL);
-
- if (options & GPU_SHADER_TWO_SIDED)
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
- else
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
- }
- else if (bound_options & GPU_SHADER_LIGHTING) {
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
- }
-
- if (options & GPU_SHADER_TEXTURE_2D) {
- GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE;
- glEnable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
- }
- else if (bound_options & GPU_SHADER_TEXTURE_2D) {
- if ((options & GPU_SHADER_TEXTURE_RECT) == 0) {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- }
- glDisable(GL_TEXTURE_2D);
- }
-
- if (options & GPU_SHADER_TEXTURE_RECT) {
- GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE;
- glEnable(GL_TEXTURE_RECTANGLE);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
- }
- else if (bound_options & GPU_SHADER_TEXTURE_RECT) {
- if ((options & GPU_SHADER_TEXTURE_2D) == 0) {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- }
- glDisable(GL_TEXTURE_RECTANGLE);
- }
-
- if ((options & GPU_SHADER_LINE) && (options & GPU_SHADER_STIPPLE)) {
- glEnable(GL_LINE_STIPPLE);
- }
- else if ((bound_options & GPU_SHADER_LINE) && (bound_options & GPU_SHADER_STIPPLE)) {
- glDisable(GL_LINE_STIPPLE);
- }
-
- if (((options & GPU_SHADER_LINE) == 0) && (options & GPU_SHADER_STIPPLE)) {
- glEnable(GL_POLYGON_STIPPLE);
- }
- else if (((bound_options & GPU_SHADER_LINE) == 0) && (bound_options & GPU_SHADER_STIPPLE)) {
- glDisable(GL_POLYGON_STIPPLE);
- }
-
- if (options & GPU_SHADER_FLAT_NORMAL) {
- glShadeModel(GL_FLAT);
- }
- else if (bound_options & GPU_SHADER_FLAT_NORMAL) {
- glShadeModel(GL_SMOOTH);
- }
- }
-
- GPU_MATERIAL_STATE.bound_options = options;
-}
-
-void GPU_basic_shader_bind_enable(int options)
-{
- GPU_basic_shader_bind(GPU_MATERIAL_STATE.bound_options | options);
-}
-
-void GPU_basic_shader_bind_disable(int options)
-{
- GPU_basic_shader_bind(GPU_MATERIAL_STATE.bound_options & ~options);
-}
-
-int GPU_basic_shader_bound_options(void)
-{
- /* ideally this should disappear, anything that uses this is making fragile
- * assumptions that the basic shader is bound and not another shader */
- return GPU_MATERIAL_STATE.bound_options;
-}
-
-/* Material Colors */
-
-void GPU_basic_shader_colors(
- const float diffuse[3], const float specular[3],
- int shininess, float alpha)
-{
- float gl_diffuse[4], gl_specular[4];
-
- if (diffuse)
- copy_v3_v3(gl_diffuse, diffuse);
- else
- zero_v3(gl_diffuse);
- gl_diffuse[3] = alpha;
-
- if (specular)
- copy_v3_v3(gl_specular, specular);
- else
- zero_v3(gl_specular);
- gl_specular[3] = 1.0f;
-
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, gl_specular);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128));
-}
-
-void GPU_basic_shader_light_set(int light_num, GPULightData *light)
-{
- int light_bit = (1 << light_num);
-
- /* note that light position is affected by the current modelview matrix! */
-
- GPU_MATERIAL_STATE.lights_enabled &= ~light_bit;
- GPU_MATERIAL_STATE.lights_directional &= ~light_bit;
-
- if (light) {
- float position[4], diffuse[4], specular[4];
-
- glEnable(GL_LIGHT0 + light_num);
-
- /* position */
- if (light->type == GPU_LIGHT_SUN) {
- copy_v3_v3(position, light->direction);
- position[3] = 0.0f;
- }
- else {
- copy_v3_v3(position, light->position);
- position[3] = 1.0f;
- }
- glLightfv(GL_LIGHT0 + light_num, GL_POSITION, position);
-
- /* energy */
- copy_v3_v3(diffuse, light->diffuse);
- copy_v3_v3(specular, light->specular);
- diffuse[3] = 1.0f;
- specular[3] = 1.0f;
- glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, diffuse);
- glLightfv(GL_LIGHT0 + light_num, GL_SPECULAR, specular);
-
- /* attenuation */
- if (light->type == GPU_LIGHT_SUN) {
- glLightf(GL_LIGHT0 + light_num, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf(GL_LIGHT0 + light_num, GL_LINEAR_ATTENUATION, 0.0f);
- glLightf(GL_LIGHT0 + light_num, GL_QUADRATIC_ATTENUATION, 0.0f);
- }
- else {
- glLightf(GL_LIGHT0 + light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation);
- glLightf(GL_LIGHT0 + light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation);
- glLightf(GL_LIGHT0 + light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation);
- }
-
- /* spot */
- glLightfv(GL_LIGHT0 + light_num, GL_SPOT_DIRECTION, light->direction);
- if (light->type == GPU_LIGHT_SPOT) {
- glLightf(GL_LIGHT0 + light_num, GL_SPOT_CUTOFF, light->spot_cutoff);
- glLightf(GL_LIGHT0 + light_num, GL_SPOT_EXPONENT, light->spot_exponent);
- }
- else {
- glLightf(GL_LIGHT0 + light_num, GL_SPOT_CUTOFF, 180.0f);
- glLightf(GL_LIGHT0 + light_num, GL_SPOT_EXPONENT, 0.0f);
- }
-
- GPU_MATERIAL_STATE.lights_enabled |= light_bit;
- if (position[3] == 0.0f)
- GPU_MATERIAL_STATE.lights_directional |= light_bit;
- }
- else {
- /* TODO(sergey): Needs revisit. */
- if (USE_GLSL || true) {
- /* glsl shader needs these zero to skip them */
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- glLightfv(GL_LIGHT0 + light_num, GL_POSITION, zero);
- glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, zero);
- glLightfv(GL_LIGHT0 + light_num, GL_SPECULAR, zero);
- }
-
- glDisable(GL_LIGHT0 + light_num);
- }
-}
-
-void GPU_basic_shader_light_set_viewer(bool local)
-{
- glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (local) ? GL_TRUE: GL_FALSE);
-}
-
-void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id)
-{
- if (USE_GLSL) {
- glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_id"), stipple_id);
- }
- else {
- switch (stipple_id) {
- case GPU_SHADER_STIPPLE_HALFTONE:
- glPolygonStipple(stipple_halftone);
- return;
- case GPU_SHADER_STIPPLE_QUARTTONE:
- glPolygonStipple(stipple_quarttone);
- return;
- case GPU_SHADER_STIPPLE_CHECKER_8PX:
- glPolygonStipple(stipple_checker_8px);
- return;
- case GPU_SHADER_STIPPLE_HEXAGON:
- glPolygonStipple(stipple_hexagon);
- return;
- case GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP:
- glPolygonStipple(stipple_diag_stripes_neg);
- return;
- case GPU_SHADER_STIPPLE_DIAG_STRIPES:
- glPolygonStipple(stipple_diag_stripes_pos);
- return;
- case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW:
- glPolygonStipple(stipple_interlace_row);
- return;
- case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP:
- glPolygonStipple(stipple_interlace_row_swap);
- return;
- case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN:
- glPolygonStipple(stipple_interlace_column);
- return;
- case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP:
- glPolygonStipple(stipple_interlace_column_swap);
- return;
- case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER:
- glPolygonStipple(stipple_interlace_checker);
- return;
- case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP:
- glPolygonStipple(stipple_interlace_checker_swap);
- return;
- default:
- glPolygonStipple(stipple_hexagon);
- return;
- }
- }
-}
-
-void GPU_basic_shader_line_width(float line_width)
-{
- if (USE_GLSL) {
- GPU_MATERIAL_STATE.line_width = line_width;
- if (GPU_MATERIAL_STATE.bound_options & GPU_SHADER_LINE) {
- glUniform1f(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "line_width"), line_width);
- }
- }
- else {
- glLineWidth(line_width);
- }
-}
-
-void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern)
-{
- if (USE_GLSL) {
- glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_factor"), stipple_factor);
- glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_pattern"), stipple_pattern);
- }
- else {
- glLineStipple(stipple_factor, stipple_pattern);
- }
-}
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
new file mode 100644
index 00000000000..2cbeeb26924
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -0,0 +1,691 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_batch.c
+ * \ingroup gpu
+ *
+ * GPU geometry batch
+ * Contains VAOs + VBOs + Shader representing a drawable entity.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_matrix.h"
+#include "GPU_shader.h"
+
+#include "gpu_batch_private.h"
+#include "gpu_context_private.h"
+#include "gpu_primitive_private.h"
+#include "gpu_shader_private.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static void batch_update_program_bindings(GPUBatch *batch, uint v_first);
+
+void GPU_batch_vao_cache_clear(GPUBatch *batch)
+{
+ if (batch->context == NULL) {
+ return;
+ }
+ if (batch->is_dynamic_vao_count) {
+ for (int i = 0; i < batch->dynamic_vaos.count; ++i) {
+ if (batch->dynamic_vaos.vao_ids[i]) {
+ GPU_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context);
+ }
+ if (batch->dynamic_vaos.interfaces[i]) {
+ GPU_shaderinterface_remove_batch_ref((GPUShaderInterface *)batch->dynamic_vaos.interfaces[i], batch);
+ }
+ }
+ MEM_freeN(batch->dynamic_vaos.interfaces);
+ MEM_freeN(batch->dynamic_vaos.vao_ids);
+ }
+ else {
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ if (batch->static_vaos.vao_ids[i]) {
+ GPU_vao_free(batch->static_vaos.vao_ids[i], batch->context);
+ }
+ if (batch->static_vaos.interfaces[i]) {
+ GPU_shaderinterface_remove_batch_ref((GPUShaderInterface *)batch->static_vaos.interfaces[i], batch);
+ }
+ }
+ }
+ batch->is_dynamic_vao_count = false;
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ batch->static_vaos.vao_ids[i] = 0;
+ batch->static_vaos.interfaces[i] = NULL;
+ }
+ gpu_context_remove_batch(batch->context, batch);
+ batch->context = NULL;
+}
+
+GPUBatch *GPU_batch_create_ex(
+ GPUPrimType prim_type, GPUVertBuf *verts, GPUIndexBuf *elem,
+ uint owns_flag)
+{
+ GPUBatch *batch = MEM_callocN(sizeof(GPUBatch), "GPUBatch");
+ GPU_batch_init_ex(batch, prim_type, verts, elem, owns_flag);
+ return batch;
+}
+
+void GPU_batch_init_ex(
+ GPUBatch *batch, GPUPrimType prim_type, GPUVertBuf *verts, GPUIndexBuf *elem,
+ uint owns_flag)
+{
+#if TRUST_NO_ONE
+ assert(verts != NULL);
+#endif
+
+ batch->verts[0] = verts;
+ for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ batch->verts[v] = NULL;
+ }
+ batch->inst = NULL;
+ batch->elem = elem;
+ batch->gl_prim_type = convert_prim_type_to_gl(prim_type);
+ batch->phase = GPU_BATCH_READY_TO_DRAW;
+ batch->is_dynamic_vao_count = false;
+ batch->owns_flag = owns_flag;
+ batch->free_callback = NULL;
+}
+
+/* This will share the VBOs with the new batch. */
+GPUBatch *GPU_batch_duplicate(GPUBatch *batch_src)
+{
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, batch_src->verts[0], batch_src->elem, 0);
+
+ batch->gl_prim_type = batch_src->gl_prim_type;
+ for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ batch->verts[v] = batch_src->verts[v];
+ }
+ return batch;
+}
+
+void GPU_batch_discard(GPUBatch *batch)
+{
+ if (batch->owns_flag & GPU_BATCH_OWNS_INDEX) {
+ GPU_indexbuf_discard(batch->elem);
+ }
+ if (batch->owns_flag & GPU_BATCH_OWNS_INSTANCES) {
+ GPU_vertbuf_discard(batch->inst);
+ }
+ if ((batch->owns_flag & ~GPU_BATCH_OWNS_INDEX) != 0) {
+ for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ if (batch->verts[v] == NULL) {
+ break;
+ }
+ if (batch->owns_flag & (1 << v)) {
+ GPU_vertbuf_discard(batch->verts[v]);
+ }
+ }
+ }
+ GPU_batch_vao_cache_clear(batch);
+
+ if (batch->free_callback) {
+ batch->free_callback(batch, batch->callback_data);
+ }
+ MEM_freeN(batch);
+}
+
+void GPU_batch_callback_free_set(GPUBatch *batch, void (*callback)(GPUBatch *, void *), void *user_data)
+{
+ batch->free_callback = callback;
+ batch->callback_data = user_data;
+}
+
+void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo)
+{
+#if TRUST_NO_ONE
+ assert(inst != NULL);
+#endif
+ /* redo the bindings */
+ GPU_batch_vao_cache_clear(batch);
+
+ if (batch->inst != NULL && (batch->owns_flag & GPU_BATCH_OWNS_INSTANCES)) {
+ GPU_vertbuf_discard(batch->inst);
+ }
+ batch->inst = inst;
+
+ if (own_vbo) {
+ batch->owns_flag |= GPU_BATCH_OWNS_INSTANCES;
+ }
+ else {
+ batch->owns_flag &= ~GPU_BATCH_OWNS_INSTANCES;
+ }
+}
+
+/* Returns the index of verts in the batch. */
+int GPU_batch_vertbuf_add_ex(
+ GPUBatch *batch, GPUVertBuf *verts,
+ bool own_vbo)
+{
+ /* redo the bindings */
+ GPU_batch_vao_cache_clear(batch);
+
+ for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; ++v) {
+ if (batch->verts[v] == NULL) {
+#if TRUST_NO_ONE
+ /* for now all VertexBuffers must have same vertex_len */
+ assert(verts->vertex_len == batch->verts[0]->vertex_len);
+#endif
+ batch->verts[v] = verts;
+ /* TODO: mark dirty so we can keep attrib bindings up-to-date */
+ if (own_vbo)
+ batch->owns_flag |= (1 << v);
+ return v;
+ }
+ }
+
+ /* we only make it this far if there is no room for another GPUVertBuf */
+#if TRUST_NO_ONE
+ assert(false);
+#endif
+ return -1;
+}
+
+static GLuint batch_vao_get(GPUBatch *batch)
+{
+ /* Search through cache */
+ if (batch->is_dynamic_vao_count) {
+ for (int i = 0; i < batch->dynamic_vaos.count; ++i)
+ if (batch->dynamic_vaos.interfaces[i] == batch->interface)
+ return batch->dynamic_vaos.vao_ids[i];
+ }
+ else {
+ for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i)
+ if (batch->static_vaos.interfaces[i] == batch->interface)
+ return batch->static_vaos.vao_ids[i];
+ }
+
+ /* Set context of this batch.
+ * It will be bound to it until GPU_batch_vao_cache_clear is called.
+ * Until then it can only be drawn with this context. */
+ if (batch->context == NULL) {
+ batch->context = GPU_context_active_get();
+ gpu_context_add_batch(batch->context, batch);
+ }
+#if TRUST_NO_ONE
+ else {
+ /* Make sure you are not trying to draw this batch in another context. */
+ assert(batch->context == GPU_context_active_get());
+ }
+#endif
+
+ /* Cache miss, time to add a new entry! */
+ GLuint new_vao = 0;
+ if (!batch->is_dynamic_vao_count) {
+ int i; /* find first unused slot */
+ for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i)
+ if (batch->static_vaos.vao_ids[i] == 0)
+ break;
+
+ if (i < GPU_BATCH_VAO_STATIC_LEN) {
+ batch->static_vaos.interfaces[i] = batch->interface;
+ batch->static_vaos.vao_ids[i] = new_vao = GPU_vao_alloc();
+ }
+ else {
+ /* Not enough place switch to dynamic. */
+ batch->is_dynamic_vao_count = true;
+ /* Erase previous entries, they will be added back if drawn again. */
+ for (int j = 0; j < GPU_BATCH_VAO_STATIC_LEN; ++j) {
+ GPU_shaderinterface_remove_batch_ref((GPUShaderInterface *)batch->static_vaos.interfaces[j], batch);
+ GPU_vao_free(batch->static_vaos.vao_ids[j], batch->context);
+ }
+ /* Init dynamic arrays and let the branch below set the values. */
+ batch->dynamic_vaos.count = GPU_BATCH_VAO_DYN_ALLOC_COUNT;
+ batch->dynamic_vaos.interfaces = MEM_callocN(batch->dynamic_vaos.count * sizeof(GPUShaderInterface *), "dyn vaos interfaces");
+ batch->dynamic_vaos.vao_ids = MEM_callocN(batch->dynamic_vaos.count * sizeof(GLuint), "dyn vaos ids");
+ }
+ }
+
+ if (batch->is_dynamic_vao_count) {
+ int i; /* find first unused slot */
+ for (i = 0; i < batch->dynamic_vaos.count; ++i)
+ if (batch->dynamic_vaos.vao_ids[i] == 0)
+ break;
+
+ if (i == batch->dynamic_vaos.count) {
+ /* Not enough place, realloc the array. */
+ i = batch->dynamic_vaos.count;
+ batch->dynamic_vaos.count += GPU_BATCH_VAO_DYN_ALLOC_COUNT;
+ batch->dynamic_vaos.interfaces = MEM_recallocN(batch->dynamic_vaos.interfaces, sizeof(GPUShaderInterface *) * batch->dynamic_vaos.count);
+ batch->dynamic_vaos.vao_ids = MEM_recallocN(batch->dynamic_vaos.vao_ids, sizeof(GLuint) * batch->dynamic_vaos.count);
+ }
+ batch->dynamic_vaos.interfaces[i] = batch->interface;
+ batch->dynamic_vaos.vao_ids[i] = new_vao = GPU_vao_alloc();
+ }
+
+ GPU_shaderinterface_add_batch_ref((GPUShaderInterface *)batch->interface, batch);
+
+#if TRUST_NO_ONE
+ assert(new_vao != 0);
+#endif
+
+ /* We just got a fresh VAO we need to initialize it. */
+ glBindVertexArray(new_vao);
+ batch_update_program_bindings(batch, 0);
+ glBindVertexArray(0);
+
+ return new_vao;
+}
+
+void GPU_batch_program_set_no_use(GPUBatch *batch, uint32_t program, const GPUShaderInterface *shaderface)
+{
+#if TRUST_NO_ONE
+ assert(glIsProgram(shaderface->program));
+ assert(batch->program_in_use == 0);
+#endif
+ batch->interface = shaderface;
+ batch->program = program;
+ batch->vao_id = batch_vao_get(batch);
+}
+
+void GPU_batch_program_set(GPUBatch *batch, uint32_t program, const GPUShaderInterface *shaderface)
+{
+ GPU_batch_program_set_no_use(batch, program, shaderface);
+ GPU_batch_program_use_begin(batch); /* hack! to make Batch_Uniform* simpler */
+}
+
+void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface)
+{
+ if (batch->is_dynamic_vao_count) {
+ for (int i = 0; i < batch->dynamic_vaos.count; ++i) {
+ if (batch->dynamic_vaos.interfaces[i] == interface) {
+ GPU_vao_free(batch->dynamic_vaos.vao_ids[i], batch->context);
+ batch->dynamic_vaos.vao_ids[i] = 0;
+ batch->dynamic_vaos.interfaces[i] = NULL;
+ break; /* cannot have duplicates */
+ }
+ }
+ }
+ else {
+ int i;
+ for (i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) {
+ if (batch->static_vaos.interfaces[i] == interface) {
+ GPU_vao_free(batch->static_vaos.vao_ids[i], batch->context);
+ batch->static_vaos.vao_ids[i] = 0;
+ batch->static_vaos.interfaces[i] = NULL;
+ break; /* cannot have duplicates */
+ }
+ }
+ }
+}
+
+static void create_bindings(
+ GPUVertBuf *verts, const GPUShaderInterface *interface,
+ uint v_first, const bool use_instancing)
+{
+ const GPUVertFormat *format = &verts->format;
+
+ const uint attr_len = format->attr_len;
+ const uint stride = format->stride;
+
+ GPU_vertbuf_use(verts);
+
+ for (uint a_idx = 0; a_idx < attr_len; ++a_idx) {
+ const GPUVertAttr *a = format->attribs + a_idx;
+ const GLvoid *pointer = (const GLubyte *)0 + a->offset + v_first * stride;
+
+ for (uint n_idx = 0; n_idx < a->name_len; ++n_idx) {
+ const GPUShaderInput *input = GPU_shaderinterface_attr(interface, a->name[n_idx]);
+
+ if (input == NULL) continue;
+
+ if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) {
+#if TRUST_NO_ONE
+ assert(a->fetch_mode == GPU_FETCH_FLOAT);
+ assert(a->gl_comp_type == GL_FLOAT);
+#endif
+ for (int i = 0; i < a->comp_len / 4; ++i) {
+ glEnableVertexAttribArray(input->location + i);
+ glVertexAttribDivisor(input->location + i, (use_instancing) ? 1 : 0);
+ glVertexAttribPointer(input->location + i, 4, a->gl_comp_type, GL_FALSE, stride,
+ (const GLubyte *)pointer + i * 16);
+ }
+ }
+ else {
+ glEnableVertexAttribArray(input->location);
+ glVertexAttribDivisor(input->location, (use_instancing) ? 1 : 0);
+
+ switch (a->fetch_mode) {
+ case GPU_FETCH_FLOAT:
+ case GPU_FETCH_INT_TO_FLOAT:
+ glVertexAttribPointer(input->location, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer);
+ break;
+ case GPU_FETCH_INT_TO_FLOAT_UNIT:
+ glVertexAttribPointer(input->location, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer);
+ break;
+ case GPU_FETCH_INT:
+ glVertexAttribIPointer(input->location, a->comp_len, a->gl_comp_type, stride, pointer);
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void batch_update_program_bindings(GPUBatch *batch, uint v_first)
+{
+ for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN && batch->verts[v] != NULL; ++v) {
+ create_bindings(batch->verts[v], batch->interface, (batch->inst) ? 0 : v_first, false);
+ }
+ if (batch->inst) {
+ create_bindings(batch->inst, batch->interface, v_first, true);
+ }
+ if (batch->elem) {
+ GPU_indexbuf_use(batch->elem);
+ }
+}
+
+void GPU_batch_program_use_begin(GPUBatch *batch)
+{
+ /* NOTE: use_program & done_using_program are fragile, depend on staying in sync with
+ * the GL context's active program. use_program doesn't mark other programs as "not used". */
+ /* TODO: make not fragile (somehow) */
+
+ if (!batch->program_in_use) {
+ glUseProgram(batch->program);
+ batch->program_in_use = true;
+ }
+}
+
+void GPU_batch_program_use_end(GPUBatch *batch)
+{
+ if (batch->program_in_use) {
+#if PROGRAM_NO_OPTI
+ glUseProgram(0);
+#endif
+ batch->program_in_use = false;
+ }
+}
+
+#if TRUST_NO_ONE
+# define GET_UNIFORM const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name); assert(uniform);
+#else
+# define GET_UNIFORM const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name);
+#endif
+
+void GPU_batch_uniform_1ui(GPUBatch *batch, const char *name, int value)
+{
+ GET_UNIFORM
+ glUniform1ui(uniform->location, value);
+}
+
+void GPU_batch_uniform_1i(GPUBatch *batch, const char *name, int value)
+{
+ GET_UNIFORM
+ glUniform1i(uniform->location, value);
+}
+
+void GPU_batch_uniform_1b(GPUBatch *batch, const char *name, bool value)
+{
+ GET_UNIFORM
+ glUniform1i(uniform->location, value ? GL_TRUE : GL_FALSE);
+}
+
+void GPU_batch_uniform_2f(GPUBatch *batch, const char *name, float x, float y)
+{
+ GET_UNIFORM
+ glUniform2f(uniform->location, x, y);
+}
+
+void GPU_batch_uniform_3f(GPUBatch *batch, const char *name, float x, float y, float z)
+{
+ GET_UNIFORM
+ glUniform3f(uniform->location, x, y, z);
+}
+
+void GPU_batch_uniform_4f(GPUBatch *batch, const char *name, float x, float y, float z, float w)
+{
+ GET_UNIFORM
+ glUniform4f(uniform->location, x, y, z, w);
+}
+
+void GPU_batch_uniform_1f(GPUBatch *batch, const char *name, float x)
+{
+ GET_UNIFORM
+ glUniform1f(uniform->location, x);
+}
+
+void GPU_batch_uniform_2fv(GPUBatch *batch, const char *name, const float data[2])
+{
+ GET_UNIFORM
+ glUniform2fv(uniform->location, 1, data);
+}
+
+void GPU_batch_uniform_3fv(GPUBatch *batch, const char *name, const float data[3])
+{
+ GET_UNIFORM
+ glUniform3fv(uniform->location, 1, data);
+}
+
+void GPU_batch_uniform_4fv(GPUBatch *batch, const char *name, const float data[4])
+{
+ GET_UNIFORM
+ glUniform4fv(uniform->location, 1, data);
+}
+
+void GPU_batch_uniform_2fv_array(GPUBatch *batch, const char *name, const int len, const float *data)
+{
+ GET_UNIFORM
+ glUniform2fv(uniform->location, len, data);
+}
+
+void GPU_batch_uniform_4fv_array(GPUBatch *batch, const char *name, const int len, const float *data)
+{
+ GET_UNIFORM
+ glUniform4fv(uniform->location, len, data);
+}
+
+void GPU_batch_uniform_mat4(GPUBatch *batch, const char *name, const float data[4][4])
+{
+ GET_UNIFORM
+ glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (const float *)data);
+}
+
+static void primitive_restart_enable(const GPUIndexBuf *el)
+{
+ // TODO(fclem) Replace by GL_PRIMITIVE_RESTART_FIXED_INDEX when we have ogl 4.3
+ glEnable(GL_PRIMITIVE_RESTART);
+ GLuint restart_index = (GLuint)0xFFFFFFFF;
+
+#if GPU_TRACK_INDEX_RANGE
+ if (el->index_type == GPU_INDEX_U8)
+ restart_index = (GLuint)0xFF;
+ else if (el->index_type == GPU_INDEX_U16)
+ restart_index = (GLuint)0xFFFF;
+#endif
+
+ glPrimitiveRestartIndex(restart_index);
+}
+
+static void primitive_restart_disable(void)
+{
+ glDisable(GL_PRIMITIVE_RESTART);
+}
+
+static void *elem_offset(const GPUIndexBuf *el, int v_first)
+{
+#if GPU_TRACK_INDEX_RANGE
+ if (el->index_type == GPU_INDEX_U8)
+ return (GLubyte *)0 + v_first;
+ else if (el->index_type == GPU_INDEX_U16)
+ return (GLushort *)0 + v_first;
+ else
+#endif
+ return (GLuint *)0 + v_first;
+}
+
+void GPU_batch_draw(GPUBatch *batch)
+{
+#if TRUST_NO_ONE
+ assert(batch->phase == GPU_BATCH_READY_TO_DRAW);
+ assert(batch->verts[0]->vbo_id != 0);
+#endif
+ GPU_batch_program_use_begin(batch);
+ GPU_matrix_bind(batch->interface); // external call.
+
+ GPU_batch_draw_range_ex(batch, 0, 0, false);
+
+ GPU_batch_program_use_end(batch);
+}
+
+void GPU_batch_draw_range_ex(GPUBatch *batch, int v_first, int v_count, bool force_instance)
+{
+#if TRUST_NO_ONE
+ assert(!(force_instance && (batch->inst == NULL)) || v_count > 0); // we cannot infer length if force_instance
+#endif
+
+ const bool do_instance = (force_instance || batch->inst);
+
+ // If using offset drawing, use the default VAO and redo bindings.
+ if (v_first != 0 && do_instance) {
+ glBindVertexArray(GPU_vao_default());
+ batch_update_program_bindings(batch, v_first);
+ }
+ else {
+ glBindVertexArray(batch->vao_id);
+ }
+
+ if (do_instance) {
+ /* Infer length if vertex count is not given */
+ if (v_count == 0) {
+ v_count = batch->inst->vertex_len;
+ }
+
+ if (batch->elem) {
+ const GPUIndexBuf *el = batch->elem;
+
+ if (el->use_prim_restart) {
+ primitive_restart_enable(el);
+ }
+#if GPU_TRACK_INDEX_RANGE
+ glDrawElementsInstancedBaseVertex(batch->gl_prim_type,
+ el->index_len,
+ el->gl_index_type,
+ 0,
+ v_count,
+ el->base_index);
+#else
+ glDrawElementsInstanced(batch->gl_prim_type, el->index_len, GL_UNSIGNED_INT, 0, v_count);
+#endif
+ if (el->use_prim_restart) {
+ primitive_restart_disable();
+ }
+ }
+ else {
+ glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_len, v_count);
+ }
+ }
+ else {
+ /* Infer length if vertex count is not given */
+ if (v_count == 0) {
+ v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len;
+ }
+
+ if (batch->elem) {
+ const GPUIndexBuf *el = batch->elem;
+
+ if (el->use_prim_restart) {
+ primitive_restart_enable(el);
+ }
+
+ void *v_first_ofs = elem_offset(el, v_first);
+
+#if GPU_TRACK_INDEX_RANGE
+ if (el->base_index) {
+ glDrawRangeElementsBaseVertex(
+ batch->gl_prim_type,
+ el->min_index,
+ el->max_index,
+ v_count,
+ el->gl_index_type,
+ v_first_ofs,
+ el->base_index);
+ }
+ else {
+ glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, v_first_ofs);
+ }
+#else
+ glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, v_first_ofs);
+#endif
+ if (el->use_prim_restart) {
+ primitive_restart_disable();
+ }
+ }
+ else {
+ glDrawArrays(batch->gl_prim_type, v_first, v_count);
+ }
+ }
+
+ /* Performance hog if you are drawing with the same vao multiple time.
+ * Only activate for debugging. */
+ // glBindVertexArray(0);
+}
+
+/* just draw some vertices and let shader place them where we want. */
+void GPU_draw_primitive(GPUPrimType prim_type, int v_count)
+{
+ /* we cannot draw without vao ... annoying ... */
+ glBindVertexArray(GPU_vao_default());
+
+ GLenum type = convert_prim_type_to_gl(prim_type);
+ glDrawArrays(type, 0, v_count);
+
+ /* Performance hog if you are drawing with the same vao multiple time.
+ * Only activate for debugging.*/
+ // glBindVertexArray(0);
+}
+
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+void GPU_batch_program_set_builtin(GPUBatch *batch, GPUBuiltinShader shader_id)
+{
+ GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
+ GPU_batch_program_set(batch, shader->program, shader->interface);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Init/Exit
+ * \{ */
+
+void gpu_batch_init(void)
+{
+ gpu_batch_presets_init();
+}
+
+void gpu_batch_exit(void)
+{
+ gpu_batch_presets_exit();
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
new file mode 100644
index 00000000000..629ab04bf24
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -0,0 +1,267 @@
+/*
+ * ***** 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): Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_batch_presets.c
+ * \ingroup gpu
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_threads.h"
+#include "BLI_listbase.h"
+#include "MEM_guardedalloc.h"
+
+#include "UI_interface.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_utils.h"
+#include "GPU_batch_presets.h" /* own include */
+#include "gpu_shader_private.h"
+
+/* Struct to store 3D Batches and their format */
+static struct {
+ struct {
+ GPUBatch *sphere_high;
+ GPUBatch *sphere_med;
+ GPUBatch *sphere_low;
+ GPUBatch *sphere_wire_low;
+ GPUBatch *sphere_wire_med;
+ } batch;
+
+ GPUVertFormat format;
+
+ struct {
+ uint pos, nor;
+ } attr_id;
+
+ ThreadMutex mutex;
+} g_presets_3d = {{0}};
+
+static ListBase presets_list = {NULL, NULL};
+
+
+/* -------------------------------------------------------------------- */
+/** \name 3D Primitives
+ * \{ */
+
+static GPUVertFormat *preset_3d_format(void)
+{
+ if (g_presets_3d.format.attr_len == 0) {
+ GPUVertFormat *format = &g_presets_3d.format;
+ g_presets_3d.attr_id.pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ g_presets_3d.attr_id.nor = GPU_vertformat_attr_add(format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ return &g_presets_3d.format;
+}
+
+static void batch_sphere_lat_lon_vert(
+ GPUVertBufRaw *pos_step, GPUVertBufRaw *nor_step,
+ float lat, float lon)
+{
+ float pos[3];
+ pos[0] = sinf(lat) * cosf(lon);
+ pos[1] = cosf(lat);
+ pos[2] = sinf(lat) * sinf(lon);
+ copy_v3_v3(GPU_vertbuf_raw_step(pos_step), pos);
+ copy_v3_v3(GPU_vertbuf_raw_step(nor_step), pos);
+}
+GPUBatch *GPU_batch_preset_sphere(int lod)
+{
+ BLI_assert(lod >= 0 && lod <= 2);
+ BLI_assert(BLI_thread_is_main());
+
+ if (lod == 0) {
+ return g_presets_3d.batch.sphere_low;
+ }
+ else if (lod == 1) {
+ return g_presets_3d.batch.sphere_med;
+ }
+ else {
+ return g_presets_3d.batch.sphere_high;
+ }
+}
+
+GPUBatch *GPU_batch_preset_sphere_wire(int lod)
+{
+ BLI_assert(lod >= 0 && lod <= 1);
+ BLI_assert(BLI_thread_is_main());
+
+ if (lod == 0) {
+ return g_presets_3d.batch.sphere_wire_low;
+ }
+ else {
+ return g_presets_3d.batch.sphere_wire_med;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Create Sphere (3D)
+ * \{ */
+
+/* Replacement for gluSphere */
+GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
+{
+ const float lon_inc = 2 * M_PI / lon_res;
+ const float lat_inc = M_PI / lat_res;
+ float lon, lat;
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(preset_3d_format());
+ const uint vbo_len = (lat_res - 1) * lon_res * 6;
+ GPU_vertbuf_data_alloc(vbo, vbo_len);
+
+ GPUVertBufRaw pos_step, nor_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step);
+
+ lon = 0.0f;
+ for (int i = 0; i < lon_res; i++, lon += lon_inc) {
+ lat = 0.0f;
+ for (int j = 0; j < lat_res; j++, lat += lat_inc) {
+ if (j != lat_res - 1) { /* Pole */
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon);
+ }
+
+ if (j != 0) { /* Pole */
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon + lon_inc);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon);
+ }
+ }
+ }
+
+ BLI_assert(vbo_len == GPU_vertbuf_raw_used(&pos_step));
+ BLI_assert(vbo_len == GPU_vertbuf_raw_used(&nor_step));
+
+ return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+static GPUBatch *batch_sphere_wire(int lat_res, int lon_res)
+{
+ const float lon_inc = 2 * M_PI / lon_res;
+ const float lat_inc = M_PI / lat_res;
+ float lon, lat;
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(preset_3d_format());
+ const uint vbo_len = (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2);
+ GPU_vertbuf_data_alloc(vbo, vbo_len);
+
+ GPUVertBufRaw pos_step, nor_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step);
+
+ lon = 0.0f;
+ for (int i = 0; i < lon_res; i++, lon += lon_inc) {
+ lat = 0.0f;
+ for (int j = 0; j < lat_res; j++, lat += lat_inc) {
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon);
+
+ if (j != lat_res - 1) { /* Pole */
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc);
+ batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon);
+ }
+ }
+ }
+
+ BLI_assert(vbo_len == GPU_vertbuf_raw_used(&pos_step));
+ BLI_assert(vbo_len == GPU_vertbuf_raw_used(&nor_step));
+
+ return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+/** \} */
+
+void gpu_batch_presets_init(void)
+{
+ BLI_mutex_init(&g_presets_3d.mutex);
+
+ /* Hard coded resolution */
+ g_presets_3d.batch.sphere_low = gpu_batch_sphere(8, 16);
+ gpu_batch_presets_register(g_presets_3d.batch.sphere_low);
+
+ g_presets_3d.batch.sphere_med = gpu_batch_sphere(16, 10);
+ gpu_batch_presets_register(g_presets_3d.batch.sphere_med);
+
+ g_presets_3d.batch.sphere_high = gpu_batch_sphere(32, 24);
+ gpu_batch_presets_register(g_presets_3d.batch.sphere_high);
+
+ g_presets_3d.batch.sphere_wire_low = batch_sphere_wire(6, 8);
+ gpu_batch_presets_register(g_presets_3d.batch.sphere_wire_low);
+
+ g_presets_3d.batch.sphere_wire_med = batch_sphere_wire(8, 16);
+ gpu_batch_presets_register(g_presets_3d.batch.sphere_wire_med);
+}
+
+void gpu_batch_presets_register(GPUBatch *preset_batch)
+{
+ BLI_mutex_lock(&g_presets_3d.mutex);
+ BLI_addtail(&presets_list, BLI_genericNodeN(preset_batch));
+ BLI_mutex_unlock(&g_presets_3d.mutex);
+}
+
+bool gpu_batch_presets_unregister(GPUBatch *preset_batch)
+{
+ BLI_mutex_lock(&g_presets_3d.mutex);
+ for (LinkData *link = presets_list.last; link; link = link->prev) {
+ if (preset_batch == link->data) {
+ BLI_remlink(&presets_list, link);
+ BLI_mutex_unlock(&g_presets_3d.mutex);
+ MEM_freeN(link);
+ return true;
+ }
+ }
+ BLI_mutex_unlock(&g_presets_3d.mutex);
+ return false;
+}
+
+void gpu_batch_presets_reset(void)
+{
+ BLI_mutex_lock(&g_presets_3d.mutex);
+ /* Reset vao caches for these every time we switch opengl context.
+ * This way they will draw correctly for each window. */
+ for (LinkData *link = presets_list.first; link; link = link->next) {
+ GPUBatch *preset = link->data;
+ GPU_batch_vao_cache_clear(preset);
+ }
+ BLI_mutex_unlock(&g_presets_3d.mutex);
+}
+
+void gpu_batch_presets_exit(void)
+{
+ LinkData *link;
+ while ((link = BLI_pophead(&presets_list))) {
+ GPUBatch *preset = link->data;
+ GPU_batch_discard(preset);
+ MEM_freeN(link);
+ }
+
+ BLI_mutex_end(&g_presets_3d.mutex);
+}
diff --git a/source/blender/blenloader/BLO_runtime.h b/source/blender/gpu/intern/gpu_batch_private.h
index 09f25bdca53..3a05e243065 100644
--- a/source/blender/blenloader/BLO_runtime.h
+++ b/source/blender/gpu/intern/gpu_batch_private.h
@@ -15,39 +15,36 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * The Original Code is Copyright (C) 2016 by Mike Erwin.
* All rights reserved.
*
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
+ * Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
- *
*/
-#ifndef __BLO_RUNTIME_H__
-#define __BLO_RUNTIME_H__
-
-/** \file BLO_runtime.h
- * \ingroup blenloader
+/** \file blender/gpu/intern/gpu_batch_private.h
+ * \ingroup gpu
+ *
+ * GPU geometry batch
+ * Contains VAOs + VBOs + Shader representing a drawable entity.
*/
+#ifndef __GPU_BATCH_PRIVATE_H__
+#define __GPU_BATCH_PRIVATE_H__
+
#ifdef __cplusplus
extern "C" {
#endif
-struct BlendFileData;
-struct Main;
-struct ReportList;
-
-int BLO_is_a_runtime(const char *file);
-struct BlendFileData *BLO_read_runtime(const char *file, struct ReportList *reports);
+#include "GPU_batch.h"
+#include "GPU_context.h"
+#include "GPU_shader_interface.h"
-bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports);
+void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface);
#ifdef __cplusplus
}
#endif
-#endif /* __BLO_RUNTIME_H__ */
+#endif /* __GPU_BATCH_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c
new file mode 100644
index 00000000000..13e615e120b
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_batch_utils.c
@@ -0,0 +1,244 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_batch_utils.c
+ * \ingroup gpu
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_rect.h"
+#include "BLI_math.h"
+#include "BLI_polyfill_2d.h"
+#include "BLI_sort_utils.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_utils.h" /* own include */
+#include "gpu_shader_private.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Polygon Creation (2D)
+ * \{ */
+
+/**
+ * Creates triangles from a byte-array of polygons.
+ *
+ * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function.
+ *
+ * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon).
+ * \param polys_flat_len: Length of the array (must be an even number).
+ * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1.
+ */
+GPUBatch *GPU_batch_tris_from_poly_2d_encoded(
+ const uchar *polys_flat, uint polys_flat_len, const rctf *rect)
+{
+ const uchar (*polys)[2] = (const void *)polys_flat;
+ const uint polys_len = polys_flat_len / 2;
+ BLI_assert(polys_flat_len == polys_len * 2);
+
+ /* Over alloc in both cases */
+ float (*verts)[2] = MEM_mallocN(sizeof(*verts) * polys_len, __func__);
+ float (*verts_step)[2] = verts;
+ uint (*tris)[3] = MEM_mallocN(sizeof(*tris) * polys_len, __func__);
+ uint (*tris_step)[3] = tris;
+
+ const float range_uchar[2] = {
+ (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f,
+ (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f,
+ };
+ const float min_uchar[2] = {
+ (rect ? rect->xmin : -1.0f),
+ (rect ? rect->ymin : -1.0f),
+ };
+
+ uint i_poly = 0;
+ uint i_vert = 0;
+ while (i_poly != polys_len) {
+ for (uint j = 0; j < 2; j++) {
+ verts[i_vert][j] = min_uchar[j] + ((float)polys[i_poly][j] * range_uchar[j]);
+ }
+ i_vert++;
+ i_poly++;
+ if (polys[i_poly - 1][0] == polys[i_poly][0] &&
+ polys[i_poly - 1][1] == polys[i_poly][1])
+ {
+ const uint verts_step_len = (&verts[i_vert]) - verts_step;
+ BLI_assert(verts_step_len >= 3);
+ const uint tris_len = (verts_step_len - 2);
+ BLI_polyfill_calc(verts_step, verts_step_len, -1, tris_step);
+ /* offset indices */
+ if (verts_step != verts) {
+ uint *t = tris_step[0];
+ const uint offset = (verts_step - verts);
+ uint tot = tris_len * 3;
+ while (tot--) {
+ *t += offset;
+ t++;
+ }
+ BLI_assert(t == tris_step[tris_len]);
+ }
+ verts_step += verts_step_len;
+ tris_step += tris_len;
+ i_poly++;
+ /* ignore the duplicate point */
+ }
+ }
+
+ /* We have vertices and tris, make a batch from this. */
+ static GPUVertFormat format = {0};
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ const uint verts_len = (verts_step - verts);
+ const uint tris_len = (tris_step - tris);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, verts_len);
+
+ GPUVertBufRaw pos_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+
+ for (uint i = 0; i < verts_len; i++) {
+ copy_v2_v2(GPU_vertbuf_raw_step(&pos_step), verts[i]);
+ }
+
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tris_len, verts_len);
+ for (uint i = 0; i < tris_len; i++) {
+ GPU_indexbuf_add_tri_verts(&elb, UNPACK3(tris[i]));
+ }
+ GPUIndexBuf *indexbuf = GPU_indexbuf_build(&elb);
+
+ MEM_freeN(tris);
+ MEM_freeN(verts);
+
+ return GPU_batch_create_ex(
+ GPU_PRIM_TRIS, vbo,
+ indexbuf,
+ GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+}
+
+GPUBatch *GPU_batch_wire_from_poly_2d_encoded(
+ const uchar *polys_flat, uint polys_flat_len, const rctf *rect)
+{
+ const uchar (*polys)[2] = (const void *)polys_flat;
+ const uint polys_len = polys_flat_len / 2;
+ BLI_assert(polys_flat_len == polys_len * 2);
+
+ /* Over alloc */
+ /* Lines are pairs of (x, y) byte locations packed into an int32_t. */
+ int32_t *lines = MEM_mallocN(sizeof(*lines) * polys_len, __func__);
+ int32_t *lines_step = lines;
+
+ const float range_uchar[2] = {
+ (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f,
+ (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f,
+ };
+ const float min_uchar[2] = {
+ (rect ? rect->xmin : -1.0f),
+ (rect ? rect->ymin : -1.0f),
+ };
+
+ uint i_poly_prev = 0;
+ uint i_poly = 0;
+ while (i_poly != polys_len) {
+ i_poly++;
+ if (polys[i_poly - 1][0] == polys[i_poly][0] &&
+ polys[i_poly - 1][1] == polys[i_poly][1])
+ {
+ const uchar (*polys_step)[2] = polys + i_poly_prev;
+ const uint polys_step_len = i_poly - i_poly_prev;
+ BLI_assert(polys_step_len >= 2);
+ for (uint i_prev = polys_step_len - 1, i = 0; i < polys_step_len; i_prev = i++) {
+ union {
+ uint8_t as_u8[4];
+ uint16_t as_u16[2];
+ uint32_t as_u32;
+ } data;
+ data.as_u16[0] = *((const uint16_t *)polys_step[i_prev]);
+ data.as_u16[1] = *((const uint16_t *)polys_step[i]);
+ if (data.as_u16[0] > data.as_u16[1]) {
+ SWAP(uint16_t, data.as_u16[0], data.as_u16[1]);
+ }
+ *lines_step = data.as_u32;
+ lines_step++;
+ }
+ i_poly++;
+ i_poly_prev = i_poly;
+ /* ignore the duplicate point */
+ }
+ }
+
+ uint lines_len = lines_step - lines;
+
+ /* Hide Lines (we could make optional) */
+ {
+ qsort(lines, lines_len, sizeof(int32_t), BLI_sortutil_cmp_int);
+ lines_step = lines;
+ for (uint i_prev = 0, i = 1; i < lines_len; i_prev = i++) {
+ if (lines[i] != lines[i_prev]) {
+ *lines_step++ = lines[i_prev];
+ }
+ else {
+ i++;
+ }
+ }
+ *lines_step++ = lines[lines_len - 1];
+ lines_len = lines_step - lines;
+ }
+
+ /* We have vertices and tris, make a batch from this. */
+ static GPUVertFormat format = {0};
+ static struct { uint pos; } attr_id;
+ if (format.attr_len == 0) {
+ attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ const uint vbo_len_capacity = lines_len * 2;
+ GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
+
+ GPUVertBufRaw pos_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step);
+
+ for (uint i = 0; i < lines_len; i++) {
+ union {
+ uint8_t as_u8_pair[2][2];
+ uint32_t as_u32;
+ } data;
+ data.as_u32 = lines[i];
+ for (uint k = 0; k < 2; k++) {
+ float *pos_v2 = GPU_vertbuf_raw_step(&pos_step);
+ for (uint j = 0; j < 2; j++) {
+ pos_v2[j] = min_uchar[j] + ((float)data.as_u8_pair[k][j] * range_uchar[j]);
+ }
+ }
+ }
+ BLI_assert(vbo_len_capacity == GPU_vertbuf_raw_used(&pos_step));
+ MEM_freeN(lines);
+ return GPU_batch_create_ex(
+ GPU_PRIM_LINES, vbo,
+ NULL,
+ GPU_BATCH_OWNS_VBO);
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index a35f678f8dc..38edcbe7f71 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -35,8 +35,6 @@
#include <stddef.h>
#include <string.h>
-#include "GPU_glew.h"
-
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
@@ -55,914 +53,20 @@
#include "GPU_buffers.h"
#include "GPU_draw.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_batch.h"
#include "bmesh.h"
-typedef enum {
- GPU_BUFFER_VERTEX_STATE = (1 << 0),
- GPU_BUFFER_NORMAL_STATE = (1 << 1),
- GPU_BUFFER_TEXCOORD_UNIT_0_STATE = (1 << 2),
- GPU_BUFFER_TEXCOORD_UNIT_2_STATE = (1 << 3),
- GPU_BUFFER_COLOR_STATE = (1 << 4),
- GPU_BUFFER_ELEMENT_STATE = (1 << 5),
-} GPUBufferState;
-
-typedef struct {
- GLenum gl_buffer_type;
- int num_components; /* number of data components for one vertex */
-} GPUBufferTypeSettings;
-
-
-static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type);
-
-static const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
- /* vertex */
- {GL_ARRAY_BUFFER, 3},
- /* normal */
- {GL_ARRAY_BUFFER, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */
- /* mcol */
- {GL_ARRAY_BUFFER, 4},
- /* uv */
- {GL_ARRAY_BUFFER, 2},
- /* uv for texpaint */
- {GL_ARRAY_BUFFER, 4},
- /* edge */
- {GL_ELEMENT_ARRAY_BUFFER, 2},
- /* uv edge */
- {GL_ELEMENT_ARRAY_BUFFER, 4},
- /* triangles, 1 point since we are allocating from tottriangle points, which account for all points */
- {GL_ELEMENT_ARRAY_BUFFER, 1},
-};
-
-#define MAX_GPU_ATTRIB_DATA 32
-
-#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n))
-
-static GPUBufferState GLStates = 0;
-static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
-
-static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER;
-
-/* multires global buffer, can be used for many grids having the same grid size */
-typedef struct GridCommonGPUBuffer {
- GPUBuffer *mres_buffer;
- int mres_prev_gridsize;
- GLenum mres_prev_index_type;
- unsigned mres_prev_totquad;
-} GridCommonGPUBuffer;
-
-void GPU_buffer_material_finalize(GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat)
-{
- int i, curmat, curelement;
-
- /* count the number of materials used by this DerivedMesh */
- for (i = 0; i < totmat; i++) {
- if (matinfo[i].totelements > 0)
- gdo->totmaterial++;
- }
-
- /* allocate an array of materials used by this DerivedMesh */
- gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
- "GPUDrawObject.materials");
-
- /* initialize the materials array */
- for (i = 0, curmat = 0, curelement = 0; i < totmat; i++) {
- if (matinfo[i].totelements > 0) {
- gdo->materials[curmat] = matinfo[i];
- gdo->materials[curmat].start = curelement;
- gdo->materials[curmat].mat_nr = i;
- gdo->materials[curmat].polys = MEM_mallocN(sizeof(int) * matinfo[i].totpolys, "GPUBufferMaterial.polys");
-
- curelement += matinfo[i].totelements;
- curmat++;
- }
- }
-
- MEM_freeN(matinfo);
-}
-
-
-/* stores recently-deleted buffers so that new buffers won't have to
- * be recreated as often
- *
- * only one instance of this pool is created, stored in
- * gpu_buffer_pool
- *
- * note that the number of buffers in the pool is usually limited to
- * MAX_FREE_GPU_BUFFERS, but this limit may be exceeded temporarily
- * when a GPUBuffer is released outside the main thread; due to OpenGL
- * restrictions it cannot be immediately released
- */
-typedef struct GPUBufferPool {
- /* number of allocated buffers stored */
- int totbuf;
- /* actual allocated length of the arrays */
- int maxsize;
- GPUBuffer **buffers;
-} GPUBufferPool;
-#define MAX_FREE_GPU_BUFFERS 8
-
-/* create a new GPUBufferPool */
-static GPUBufferPool *gpu_buffer_pool_new(void)
-{
- GPUBufferPool *pool;
-
- pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer_Pool");
-
- pool->maxsize = MAX_FREE_GPU_BUFFERS;
- pool->buffers = MEM_mallocN(sizeof(*pool->buffers) * pool->maxsize,
- "GPUBufferPool.buffers");
- return pool;
-}
-
-/* remove a GPUBuffer from the pool (does not free the GPUBuffer) */
-static void gpu_buffer_pool_remove_index(GPUBufferPool *pool, int index)
-{
- int i;
-
- if (!pool || index < 0 || index >= pool->totbuf)
- return;
-
- /* shift entries down, overwriting the buffer at `index' */
- for (i = index; i < pool->totbuf - 1; i++)
- pool->buffers[i] = pool->buffers[i + 1];
-
- /* clear the last entry */
- if (pool->totbuf > 0)
- pool->buffers[pool->totbuf - 1] = NULL;
-
- pool->totbuf--;
-}
-
-/* delete the last entry in the pool */
-static void gpu_buffer_pool_delete_last(GPUBufferPool *pool)
-{
- GPUBuffer *last;
-
- if (pool->totbuf <= 0)
- return;
-
- /* get the last entry */
- if (!(last = pool->buffers[pool->totbuf - 1]))
- return;
-
- /* delete the buffer's data */
- glDeleteBuffers(1, &last->id);
-
- /* delete the buffer and remove from pool */
- MEM_freeN(last);
- pool->totbuf--;
- pool->buffers[pool->totbuf] = NULL;
-}
-
-/* free a GPUBufferPool; also frees the data in the pool's
- * GPUBuffers */
-static void gpu_buffer_pool_free(GPUBufferPool *pool)
-{
- if (!pool)
- return;
-
- while (pool->totbuf)
- gpu_buffer_pool_delete_last(pool);
-
- MEM_freeN(pool->buffers);
- MEM_freeN(pool);
-}
-
-static void gpu_buffer_pool_free_unused(GPUBufferPool *pool)
-{
- if (!pool)
- return;
-
- BLI_mutex_lock(&buffer_mutex);
-
- while (pool->totbuf)
- gpu_buffer_pool_delete_last(pool);
-
- BLI_mutex_unlock(&buffer_mutex);
-}
-
-static GPUBufferPool *gpu_buffer_pool = NULL;
-static GPUBufferPool *gpu_get_global_buffer_pool(void)
-{
- /* initialize the pool */
- if (!gpu_buffer_pool)
- gpu_buffer_pool = gpu_buffer_pool_new();
-
- return gpu_buffer_pool;
-}
-
-void GPU_global_buffer_pool_free(void)
-{
- gpu_buffer_pool_free(gpu_buffer_pool);
- gpu_buffer_pool = NULL;
-}
-
-void GPU_global_buffer_pool_free_unused(void)
-{
- gpu_buffer_pool_free_unused(gpu_buffer_pool);
-}
-
-/* get a GPUBuffer of at least `size' bytes; uses one from the buffer
- * pool if possible, otherwise creates a new one
- *
- * Thread-unsafe version for internal usage only.
- */
-static GPUBuffer *gpu_buffer_alloc_intern(size_t size)
-{
- GPUBufferPool *pool;
- GPUBuffer *buf;
- int i, bestfit = -1;
- size_t bufsize;
-
- /* bad case, leads to leak of buf since buf->pointer will allocate
- * NULL, leading to return without cleanup. In any case better detect early
- * psy-fi */
- if (size == 0)
- return NULL;
-
- pool = gpu_get_global_buffer_pool();
-
- /* not sure if this buffer pool code has been profiled much,
- * seems to me that the graphics driver and system memory
- * management might do this stuff anyway. --nicholas
- */
-
- /* check the global buffer pool for a recently-deleted buffer
- * that is at least as big as the request, but not more than
- * twice as big */
- for (i = 0; i < pool->totbuf; i++) {
- bufsize = pool->buffers[i]->size;
-
- /* check for an exact size match */
- if (bufsize == size) {
- bestfit = i;
- break;
- }
- /* smaller buffers won't fit data and buffers at least
- * twice as big are a waste of memory */
- else if (bufsize > size && size > (bufsize / 2)) {
- /* is it closer to the required size than the
- * last appropriate buffer found. try to save
- * memory */
- if (bestfit == -1 || pool->buffers[bestfit]->size > bufsize) {
- bestfit = i;
- }
- }
- }
-
- /* if an acceptable buffer was found in the pool, remove it
- * from the pool and return it */
- if (bestfit != -1) {
- buf = pool->buffers[bestfit];
- gpu_buffer_pool_remove_index(pool, bestfit);
- return buf;
- }
-
- /* no acceptable buffer found in the pool, create a new one */
- buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer");
- buf->size = size;
-
- glGenBuffers(1, &buf->id);
- glBindBuffer(GL_ARRAY_BUFFER, buf->id);
- glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- return buf;
-}
-
-/* Same as above, but safe for threading. */
-GPUBuffer *GPU_buffer_alloc(size_t size)
-{
- GPUBuffer *buffer;
-
- if (size == 0) {
- /* Early out, no lock needed in this case. */
- return NULL;
- }
-
- BLI_mutex_lock(&buffer_mutex);
- buffer = gpu_buffer_alloc_intern(size);
- BLI_mutex_unlock(&buffer_mutex);
-
- return buffer;
-}
-
-/* release a GPUBuffer; does not free the actual buffer or its data,
- * but rather moves it to the pool of recently-freed buffers for
- * possible re-use
- *
- * Thread-unsafe version for internal usage only.
- */
-static void gpu_buffer_free_intern(GPUBuffer *buffer)
-{
- GPUBufferPool *pool;
- int i;
-
- if (!buffer)
- return;
-
- pool = gpu_get_global_buffer_pool();
-
- /* free the last used buffer in the queue if no more space, but only
- * if we are in the main thread. for e.g. rendering or baking it can
- * happen that we are in other thread and can't call OpenGL, in that
- * case cleanup will be done GPU_buffer_pool_free_unused */
- if (BLI_thread_is_main()) {
- /* in main thread, safe to decrease size of pool back
- * down to MAX_FREE_GPU_BUFFERS */
- while (pool->totbuf >= MAX_FREE_GPU_BUFFERS)
- gpu_buffer_pool_delete_last(pool);
- }
- else {
- /* outside of main thread, can't safely delete the
- * buffer, so increase pool size */
- if (pool->maxsize == pool->totbuf) {
- pool->maxsize += MAX_FREE_GPU_BUFFERS;
- pool->buffers = MEM_reallocN(pool->buffers,
- sizeof(GPUBuffer *) * pool->maxsize);
- }
- }
-
- /* shift pool entries up by one */
- for (i = pool->totbuf; i > 0; i--)
- pool->buffers[i] = pool->buffers[i - 1];
-
- /* insert the buffer into the beginning of the pool */
- pool->buffers[0] = buffer;
- pool->totbuf++;
-}
-
-/* Same as above, but safe for threading. */
-void GPU_buffer_free(GPUBuffer *buffer)
-{
- if (!buffer) {
- /* Early output, no need to lock in this case, */
- return;
- }
-
- BLI_mutex_lock(&buffer_mutex);
- gpu_buffer_free_intern(buffer);
- BLI_mutex_unlock(&buffer_mutex);
-}
-
-void GPU_drawobject_free(DerivedMesh *dm)
-{
- GPUDrawObject *gdo;
- int i;
-
- if (!dm || !(gdo = dm->drawObject))
- return;
-
- for (i = 0; i < gdo->totmaterial; i++) {
- if (gdo->materials[i].polys)
- MEM_freeN(gdo->materials[i].polys);
- }
-
- MEM_freeN(gdo->materials);
- if (gdo->vert_points)
- MEM_freeN(gdo->vert_points);
-#ifdef USE_GPU_POINT_LINK
- MEM_freeN(gdo->vert_points_mem);
-#endif
- GPU_buffer_free(gdo->points);
- GPU_buffer_free(gdo->normals);
- GPU_buffer_free(gdo->uv);
- GPU_buffer_free(gdo->uv_tex);
- GPU_buffer_free(gdo->colors);
- GPU_buffer_free(gdo->edges);
- GPU_buffer_free(gdo->uvedges);
- GPU_buffer_free(gdo->triangles);
-
- MEM_freeN(gdo);
- dm->drawObject = NULL;
-}
-
-static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, size_t size)
-{
- /* try freeing an entry from the pool
- * and reallocating the buffer */
- gpu_buffer_free_intern(buffer);
-
- buffer = NULL;
-
- while (pool->totbuf && !buffer) {
- gpu_buffer_pool_delete_last(pool);
- buffer = gpu_buffer_alloc_intern(size);
- }
-
- return buffer;
-}
-
-static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
- int type, void *user, GPUBuffer *buffer)
-{
- GPUBufferPool *pool;
- float *varray;
- int *mat_orig_to_new;
- int i;
- const GPUBufferTypeSettings *ts = &gpu_buffer_type_settings[type];
- GLenum target = ts->gl_buffer_type;
- size_t size = gpu_buffer_size_from_type(dm, type);
- GLboolean uploaded;
-
- pool = gpu_get_global_buffer_pool();
-
- BLI_mutex_lock(&buffer_mutex);
-
- /* alloc a GPUBuffer; fall back to legacy mode on failure */
- if (!buffer) {
- if (!(buffer = gpu_buffer_alloc_intern(size))) {
- BLI_mutex_unlock(&buffer_mutex);
- return NULL;
- }
- }
-
- mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
- "GPU_buffer_setup.mat_orig_to_new");
- for (i = 0; i < object->totmaterial; i++) {
- /* map from original material index to new
- * GPUBufferMaterial index */
- mat_orig_to_new[object->materials[i].mat_nr] = i;
- }
-
- /* bind the buffer and discard previous data,
- * avoids stalling gpu */
- glBindBuffer(target, buffer->id);
- glBufferData(target, buffer->size, NULL, GL_STATIC_DRAW);
-
- /* attempt to map the buffer */
- if (!(varray = glMapBuffer(target, GL_WRITE_ONLY))) {
- buffer = gpu_try_realloc(pool, buffer, size);
-
- /* allocation still failed; unfortunately we need to exit */
- if (!(buffer && (varray = glMapBuffer(target, GL_WRITE_ONLY)))) {
- if (buffer)
- gpu_buffer_free_intern(buffer);
- BLI_mutex_unlock(&buffer_mutex);
- return NULL;
- }
- }
-
- uploaded = GL_FALSE;
-
- /* attempt to upload the data to the VBO */
- while (uploaded == GL_FALSE) {
- dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user);
- /* glUnmapBuffer returns GL_FALSE if
- * the data store is corrupted; retry
- * in that case */
- uploaded = glUnmapBuffer(target);
- }
- glBindBuffer(target, 0);
-
- MEM_freeN(mat_orig_to_new);
-
- BLI_mutex_unlock(&buffer_mutex);
-
- return buffer;
-}
-
-/* get the GPUDrawObject buffer associated with a type */
-static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type)
-{
- switch (type) {
- case GPU_BUFFER_VERTEX:
- return &gdo->points;
- case GPU_BUFFER_NORMAL:
- return &gdo->normals;
- case GPU_BUFFER_COLOR:
- return &gdo->colors;
- case GPU_BUFFER_UV:
- return &gdo->uv;
- case GPU_BUFFER_UV_TEXPAINT:
- return &gdo->uv_tex;
- case GPU_BUFFER_EDGE:
- return &gdo->edges;
- case GPU_BUFFER_UVEDGE:
- return &gdo->uvedges;
- case GPU_BUFFER_TRIANGLES:
- return &gdo->triangles;
- default:
- return NULL;
- }
-}
-
-/* get the amount of space to allocate for a buffer of a particular type */
-static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
-{
- const int components = gpu_buffer_type_settings[type].num_components;
- switch (type) {
- case GPU_BUFFER_VERTEX:
- return sizeof(float) * components * (dm->drawObject->tot_loop_verts + dm->drawObject->tot_loose_point);
- case GPU_BUFFER_NORMAL:
- return sizeof(short) * components * dm->drawObject->tot_loop_verts;
- case GPU_BUFFER_COLOR:
- return sizeof(char) * components * dm->drawObject->tot_loop_verts;
- case GPU_BUFFER_UV:
- return sizeof(float) * components * dm->drawObject->tot_loop_verts;
- case GPU_BUFFER_UV_TEXPAINT:
- return sizeof(float) * components * dm->drawObject->tot_loop_verts;
- case GPU_BUFFER_EDGE:
- return sizeof(int) * components * dm->drawObject->totedge;
- case GPU_BUFFER_UVEDGE:
- return sizeof(int) * components * dm->drawObject->tot_loop_verts;
- case GPU_BUFFER_TRIANGLES:
- return sizeof(int) * components * dm->drawObject->tot_triangle_point;
- default:
- return -1;
- }
-}
-
-/* call gpu_buffer_setup with settings for a particular type of buffer */
-static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type, GPUBuffer *buf)
-{
- void *user_data = NULL;
-
- /* special handling for MCol and UV buffers */
- if (type == GPU_BUFFER_COLOR) {
- if (!(user_data = DM_get_loop_data_layer(dm, dm->drawObject->colType)))
- return NULL;
- }
- else if (ELEM(type, GPU_BUFFER_UV, GPU_BUFFER_UV_TEXPAINT)) {
- if (!DM_get_loop_data_layer(dm, CD_MLOOPUV))
- return NULL;
- }
-
- buf = gpu_buffer_setup(dm, dm->drawObject, type, user_data, buf);
-
- return buf;
-}
-
-/* get the buffer of `type', initializing the GPUDrawObject and
- * buffer if needed */
-static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type, bool update)
-{
- GPUBuffer **buf;
-
- if (!dm->drawObject)
- dm->drawObject = dm->gpuObjectNew(dm);
-
- buf = gpu_drawobject_buffer_from_type(dm->drawObject, type);
- if (!(*buf))
- *buf = gpu_buffer_setup_type(dm, type, NULL);
- else if (update)
- *buf = gpu_buffer_setup_type(dm, type, *buf);
-
- return *buf;
-}
-
-void GPU_vertex_setup(DerivedMesh *dm)
-{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX, false))
- return;
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->points->id);
- glVertexPointer(3, GL_FLOAT, 0, 0);
-
- GLStates |= GPU_BUFFER_VERTEX_STATE;
-}
-
-void GPU_normal_setup(DerivedMesh *dm)
-{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_NORMAL, false))
- return;
-
- glEnableClientState(GL_NORMAL_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->normals->id);
- glNormalPointer(GL_SHORT, 4 * sizeof(short), 0);
-
- GLStates |= GPU_BUFFER_NORMAL_STATE;
-}
-
-void GPU_uv_setup(DerivedMesh *dm)
-{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV, false))
- return;
-
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uv->id);
- glTexCoordPointer(2, GL_FLOAT, 0, 0);
-
- GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE;
-}
-
-void GPU_texpaint_uv_setup(DerivedMesh *dm)
-{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV_TEXPAINT, false))
- return;
-
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uv_tex->id);
- glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0);
- glClientActiveTexture(GL_TEXTURE2);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), BUFFER_OFFSET(2 * sizeof(float)));
- glClientActiveTexture(GL_TEXTURE0);
-
- GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE;
-}
-
-
-void GPU_color_setup(DerivedMesh *dm, int colType)
-{
- bool update = false;
-
- if (!dm->drawObject) {
- /* XXX Not really nice, but we need a valid gpu draw object to set the colType...
- * Else we would have to add a new param to gpu_buffer_setup_common. */
- dm->drawObject = dm->gpuObjectNew(dm);
- dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW;
- dm->drawObject->colType = colType;
- }
- /* In paint mode, dm may stay the same during stroke, however we still want to update colors!
- * Also check in case we changed color type (i.e. which MCol cdlayer we use). */
- else if ((dm->dirty & DM_DIRTY_MCOL_UPDATE_DRAW) || (colType != dm->drawObject->colType)) {
- update = true;
- dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW;
- dm->drawObject->colType = colType;
- }
-
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_COLOR, update))
- return;
-
- glEnableClientState(GL_COLOR_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->colors->id);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
-
- GLStates |= GPU_BUFFER_COLOR_STATE;
-}
-
-void GPU_buffer_bind_as_color(GPUBuffer *buffer)
-{
- glEnableClientState(GL_COLOR_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, buffer->id);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
-
- GLStates |= GPU_BUFFER_COLOR_STATE;
-}
-
-
-void GPU_edge_setup(DerivedMesh *dm)
-{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE, false))
- return;
-
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX, false))
- return;
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->points->id);
- glVertexPointer(3, GL_FLOAT, 0, 0);
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dm->drawObject->edges->id);
-
- GLStates |= (GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_ELEMENT_STATE);
-}
-
-void GPU_uvedge_setup(DerivedMesh *dm)
-{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UVEDGE, false))
- return;
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uvedges->id);
- glVertexPointer(2, GL_FLOAT, 0, 0);
-
- GLStates |= GPU_BUFFER_VERTEX_STATE;
-}
-
-void GPU_triangle_setup(struct DerivedMesh *dm)
-{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_TRIANGLES, false))
- return;
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dm->drawObject->triangles->id);
- GLStates |= GPU_BUFFER_ELEMENT_STATE;
-}
-
-static int gpu_typesize(int type)
-{
- switch (type) {
- case GL_FLOAT:
- return sizeof(float);
- case GL_INT:
- return sizeof(int);
- case GL_UNSIGNED_INT:
- return sizeof(unsigned int);
- case GL_BYTE:
- return sizeof(char);
- case GL_UNSIGNED_BYTE:
- return sizeof(unsigned char);
- default:
- return 0;
- }
-}
-
-int GPU_attrib_element_size(GPUAttrib data[], int numdata)
-{
- int i, elementsize = 0;
-
- for (i = 0; i < numdata; i++) {
- int typesize = gpu_typesize(data[i].type);
- if (typesize != 0)
- elementsize += typesize * data[i].size;
- }
- return elementsize;
-}
-
-void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size)
-{
- int i;
- int elementsize;
- size_t offset = 0;
-
- for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
- if (attribData[i].index != -1) {
- glDisableVertexAttribArray(attribData[i].index);
- }
- else
- break;
- }
- if (element_size == 0)
- elementsize = GPU_attrib_element_size(data, numdata);
- else
- elementsize = element_size;
-
- glBindBuffer(GL_ARRAY_BUFFER, buffer->id);
-
- for (i = 0; i < numdata; i++) {
- glEnableVertexAttribArray(data[i].index);
- int info = 0;
- if (data[i].type == GL_UNSIGNED_BYTE) {
- info |= GPU_ATTR_INFO_SRGB;
- }
- glUniform1i(data[i].info_index, info);
-
- glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
- GL_TRUE, elementsize, BUFFER_OFFSET(offset));
- offset += data[i].size * gpu_typesize(data[i].type);
-
- attribData[i].index = data[i].index;
- attribData[i].size = data[i].size;
- attribData[i].type = data[i].type;
- }
-
- attribData[numdata].index = -1;
-}
-
-void GPU_interleaved_attrib_unbind(void)
-{
- int i;
- for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
- if (attribData[i].index != -1) {
- glDisableVertexAttribArray(attribData[i].index);
- }
- else
- break;
- }
- attribData[0].index = -1;
-}
-
-void GPU_buffers_unbind(void)
-{
- int i;
-
- if (GLStates & GPU_BUFFER_VERTEX_STATE)
- glDisableClientState(GL_VERTEX_ARRAY);
- if (GLStates & GPU_BUFFER_NORMAL_STATE)
- glDisableClientState(GL_NORMAL_ARRAY);
- if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_0_STATE)
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_2_STATE) {
- glClientActiveTexture(GL_TEXTURE2);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glClientActiveTexture(GL_TEXTURE0);
- }
- if (GLStates & GPU_BUFFER_COLOR_STATE)
- glDisableClientState(GL_COLOR_ARRAY);
- if (GLStates & GPU_BUFFER_ELEMENT_STATE)
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-
- GLStates &= ~(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE |
- GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE |
- GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
-
- for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
- if (attribData[i].index != -1) {
- glDisableVertexAttribArray(attribData[i].index);
- }
- else
- break;
- }
- attribData[0].index = -1;
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-}
-
-void GPU_color_switch(int mode)
-{
- if (mode) {
- if (!(GLStates & GPU_BUFFER_COLOR_STATE))
- glEnableClientState(GL_COLOR_ARRAY);
- GLStates |= GPU_BUFFER_COLOR_STATE;
- }
- else {
- if (GLStates & GPU_BUFFER_COLOR_STATE)
- glDisableClientState(GL_COLOR_ARRAY);
- GLStates &= ~GPU_BUFFER_COLOR_STATE;
- }
-}
-
-static int gpu_binding_type_gl[] =
-{
- GL_ARRAY_BUFFER,
- GL_ELEMENT_ARRAY_BUFFER
-};
-
-void *GPU_buffer_lock(GPUBuffer *buffer, GPUBindingType binding)
-{
- float *varray;
- int bindtypegl;
-
- if (!buffer)
- return 0;
-
- bindtypegl = gpu_binding_type_gl[binding];
- glBindBuffer(bindtypegl, buffer->id);
- varray = glMapBuffer(bindtypegl, GL_WRITE_ONLY);
- return varray;
-}
-
-void *GPU_buffer_lock_stream(GPUBuffer *buffer, GPUBindingType binding)
-{
- float *varray;
- int bindtypegl;
-
- if (!buffer)
- return 0;
-
- bindtypegl = gpu_binding_type_gl[binding];
- glBindBuffer(bindtypegl, buffer->id);
- /* discard previous data, avoid stalling gpu */
- glBufferData(bindtypegl, buffer->size, 0, GL_STREAM_DRAW);
- varray = glMapBuffer(bindtypegl, GL_WRITE_ONLY);
- return varray;
-}
-
-void GPU_buffer_unlock(GPUBuffer *UNUSED(buffer), GPUBindingType binding)
-{
- int bindtypegl = gpu_binding_type_gl[binding];
- /* note: this operation can fail, could return
- * an error code from this function? */
- glUnmapBuffer(bindtypegl);
- glBindBuffer(bindtypegl, 0);
-}
-
-void GPU_buffer_bind(GPUBuffer *buffer, GPUBindingType binding)
-{
- int bindtypegl = gpu_binding_type_gl[binding];
- glBindBuffer(bindtypegl, buffer->id);
-}
-
-void GPU_buffer_unbind(GPUBuffer *UNUSED(buffer), GPUBindingType binding)
-{
- int bindtypegl = gpu_binding_type_gl[binding];
- glBindBuffer(bindtypegl, 0);
-}
-
-/* used for drawing edges */
-void GPU_buffer_draw_elements(GPUBuffer *UNUSED(elements), unsigned int mode, int start, int count)
-{
- glDrawElements(mode, count, GL_UNSIGNED_INT, BUFFER_OFFSET(start * sizeof(unsigned int)));
-}
-
-
/* XXX: the rest of the code in this file is used for optimized PBVH
* drawing and doesn't interact at all with the buffer code above */
-/* Convenience struct for building the VBO. */
-typedef struct {
- float co[3];
- short no[3];
-
- /* inserting this to align the 'color' field to a four-byte
- * boundary; drastically increases viewport performance on my
- * drivers (Gallium/Radeon) --nicholasbishop */
- char pad[2];
-
- unsigned char color[3];
-} VertexBufferFormat;
-
struct GPU_PBVH_Buffers {
- /* opengl buffer handles */
- GPUBuffer *vert_buf, *index_buf, *index_buf_fast;
- GLenum index_type;
+ GPUIndexBuf *index_buf, *index_buf_fast;
+ GPUVertBuf *vert_buf;
- int *baseelemarray;
- void **baseindex;
+ GPUBatch *triangles;
+ GPUBatch *triangles_fast;
/* mesh pointers in case buffer allocation fails */
const MPoly *mpoly;
@@ -972,7 +76,6 @@ struct GPU_PBVH_Buffers {
const int *face_indices;
int face_indices_len;
- const float *vmask;
/* grid pointers */
CCGKey gridkey;
@@ -986,50 +89,67 @@ struct GPU_PBVH_Buffers {
bool use_bmesh;
- unsigned int tot_tri, tot_quad;
+ uint tot_tri, tot_quad;
/* The PBVH ensures that either all faces in the node are
* smooth-shaded or all faces are flat-shaded */
bool smooth;
- bool show_diffuse_color;
bool show_mask;
-
- bool use_matcaps;
- float diffuse_color[4];
};
-static float gpu_color_from_mask(float mask)
-{
- return 1.0f - mask * 0.75f;
-}
+static struct {
+ uint pos, nor, msk;
+} g_vbo_id = {0};
-static void gpu_color_from_mask_copy(float mask, const float diffuse_color[4], unsigned char out[3])
+/* Allocates a non-initialized buffer to be sent to GPU.
+ * Return is false it indicates that the memory map failed. */
+static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
{
- float mask_color;
-
- mask_color = gpu_color_from_mask(mask) * 255.0f;
+ if (buffers->vert_buf == NULL) {
+ /* Initialize vertex buffer */
+ /* match 'VertexBufferFormat' */
- out[0] = diffuse_color[0] * mask_color;
- out[1] = diffuse_color[1] * mask_color;
- out[2] = diffuse_color[2] * mask_color;
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ g_vbo_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ g_vbo_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ g_vbo_id.msk = GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+#if 0
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
+ }
+ else if (vert_len != buffers->vert_buf->vertex_len) {
+ GPU_vertbuf_data_resize(buffers->vert_buf, vert_len);
+ }
+#else
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC);
+ }
+ GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
+#endif
+ return buffers->vert_buf->data != NULL;
}
-static void gpu_color_from_mask_quad_copy(const CCGKey *key,
- CCGElem *a, CCGElem *b,
- CCGElem *c, CCGElem *d,
- const float *diffuse_color,
- unsigned char out[3])
+static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
{
- float mask_color =
- gpu_color_from_mask((*CCG_elem_mask(key, a) +
- *CCG_elem_mask(key, b) +
- *CCG_elem_mask(key, c) +
- *CCG_elem_mask(key, d)) * 0.25f) * 255.0f;
-
- out[0] = diffuse_color[0] * mask_color;
- out[1] = diffuse_color[1] * mask_color;
- out[2] = diffuse_color[2] * mask_color;
+ /* force flushing to the GPU */
+ if (buffers->vert_buf->data) {
+ GPU_vertbuf_use(buffers->vert_buf);
+ }
+
+ if (buffers->triangles == NULL) {
+ buffers->triangles = GPU_batch_create(
+ prim, buffers->vert_buf,
+ /* can be NULL */
+ buffers->index_buf);
+ }
+
+ if ((buffers->triangles_fast == NULL) && buffers->index_buf_fast) {
+ buffers->triangles_fast = GPU_batch_create(
+ prim, buffers->vert_buf,
+ buffers->index_buf_fast);
+ }
}
void GPU_pbvh_mesh_buffers_update(
@@ -1038,76 +158,46 @@ void GPU_pbvh_mesh_buffers_update(
const int (*face_vert_indices)[3],
const int update_flags)
{
- const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0;
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
- VertexBufferFormat *vert_data;
- int i;
-
- buffers->vmask = vmask;
- buffers->show_diffuse_color = show_diffuse_color;
- buffers->show_mask = show_mask;
- buffers->use_matcaps = GPU_material_use_matcaps_get();
+ bool empty_mask = true;
{
int totelem = (buffers->smooth ? totvert : (buffers->tot_tri * 3));
- float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 0.8f};
-
- if (buffers->use_matcaps)
- diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0;
- else if (show_diffuse_color) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]];
- const MPoly *mp = &buffers->mpoly[lt->poly];
-
- GPU_material_diffuse_get(mp->mat_nr + 1, diffuse_color);
- }
-
- copy_v4_v4(buffers->diffuse_color, diffuse_color);
-
- uchar diffuse_color_ub[4];
- rgba_float_to_uchar(diffuse_color_ub, diffuse_color);
/* Build VBO */
- if (buffers->vert_buf)
- GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totelem);
- vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY);
-
- if (vert_data) {
+ if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
/* Vertex data is shared if smooth-shaded, but separate
* copies are made for flat shading because normals
* shouldn't be shared. */
if (buffers->smooth) {
- for (i = 0; i < totvert; ++i) {
+ for (uint i = 0; i < totvert; ++i) {
const MVert *v = &mvert[vert_indices[i]];
- VertexBufferFormat *out = vert_data + i;
-
- copy_v3_v3(out->co, v->co);
- memcpy(out->no, v->no, sizeof(short) * 3);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, i, v->co);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, i, v->no);
}
- for (i = 0; i < buffers->face_indices_len; i++) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- for (uint j = 0; j < 3; j++) {
- VertexBufferFormat *out = vert_data + face_vert_indices[i][j];
-
- if (vmask && show_mask) {
- uint v_index = buffers->mloop[lt->tri[j]].v;
- gpu_color_from_mask_copy(vmask[v_index], diffuse_color, out->color);
- }
- else {
- copy_v3_v3_uchar(out->color, diffuse_color_ub);
+ if (vmask && show_mask) {
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
+ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
+ for (uint j = 0; j < 3; j++) {
+ int vidx = face_vert_indices[i][j];
+ int v_index = buffers->mloop[lt->tri[j]].v;
+ float fmask = vmask[v_index];
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vidx, &fmask);
+ empty_mask = empty_mask && (fmask == 0.0f);
}
}
}
}
else {
/* calculate normal for each polygon only once */
- unsigned int mpoly_prev = UINT_MAX;
+ uint mpoly_prev = UINT_MAX;
short no[3];
+ int vbo_index = 0;
- for (i = 0; i < buffers->face_indices_len; ++i) {
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- const unsigned int vtri[3] = {
+ const uint vtri[3] = {
buffers->mloop[lt->tri[0]].v,
buffers->mloop[lt->tri[1]].v,
buffers->mloop[lt->tri[2]].v,
@@ -1125,36 +215,30 @@ void GPU_pbvh_mesh_buffers_update(
mpoly_prev = lt->poly;
}
- uchar color_ub[3];
+ float fmask = 0.0f;
if (vmask && show_mask) {
- float fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
- gpu_color_from_mask_copy(fmask, diffuse_color, color_ub);
- }
- else {
- copy_v3_v3_uchar(color_ub, diffuse_color_ub);
+ fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
}
for (uint j = 0; j < 3; j++) {
const MVert *v = &mvert[vtri[j]];
- VertexBufferFormat *out = vert_data;
- copy_v3_v3(out->co, v->co);
- copy_v3_v3_short(out->no, no);
- copy_v3_v3_uchar(out->color, color_ub);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, v->co);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &fmask);
- vert_data++;
+ vbo_index++;
}
+
+ empty_mask = empty_mask && (fmask == 0.0f);
}
}
- GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY);
- }
- else {
- GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = NULL;
+ gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
}
+ buffers->show_mask = !empty_mask;
buffers->mvert = mvert;
}
@@ -1166,16 +250,19 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
const int face_indices_len)
{
GPU_PBVH_Buffers *buffers;
- unsigned short *tri_data;
- int i, j, tottri;
+ int i, tottri;
buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers");
- buffers->index_type = GL_UNSIGNED_SHORT;
+
+ /* smooth or flat for all */
+#if 0
buffers->smooth = mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH;
+#else
+ /* for DrawManager we dont support mixed smooth/flat */
+ buffers->smooth = (mpoly[0].flag & ME_SMOOTH) != 0;
+#endif
- buffers->show_diffuse_color = false;
- buffers->show_mask = true;
- buffers->use_matcaps = false;
+ buffers->show_mask = false;
/* Count the number of visible triangles */
for (i = 0, tottri = 0; i < face_indices_len; ++i) {
@@ -1200,35 +287,28 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
* shading requires separate vertex normals so an index buffer is
* can't be used there. */
if (buffers->smooth) {
- buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3);
- buffers->is_index_buf_global = false;
- }
-
- if (buffers->index_buf) {
/* Fill the triangle buffer */
- tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX);
- if (tri_data) {
- for (i = 0; i < face_indices_len; ++i) {
- const MLoopTri *lt = &looptri[face_indices[i]];
-
- /* Skip hidden faces */
- if (paint_is_face_hidden(lt, mvert, mloop))
- continue;
-
- for (j = 0; j < 3; ++j) {
- *tri_data = face_vert_indices[i][j];
- tri_data++;
- }
- }
- GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX);
+ buffers->index_buf = NULL;
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, INT_MAX);
+
+ for (i = 0; i < face_indices_len; ++i) {
+ const MLoopTri *lt = &looptri[face_indices[i]];
+
+ /* Skip hidden faces */
+ if (paint_is_face_hidden(lt, mvert, mloop))
+ continue;
+
+ GPU_indexbuf_add_tri_verts(&elb, UNPACK3(face_vert_indices[i]));
}
- else {
- if (!buffers->is_index_buf_global) {
- GPU_buffer_free(buffers->index_buf);
- }
- buffers->index_buf = NULL;
- buffers->is_index_buf_global = false;
+ buffers->index_buf = GPU_indexbuf_build(&elb);
+ }
+ else {
+ if (!buffers->is_index_buf_global) {
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
}
+ buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
buffers->tot_tri = tottri;
@@ -1243,115 +323,208 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(
return buffers;
}
+static void gpu_pbvh_grid_fill_fast_buffer(GPU_PBVH_Buffers *buffers, int totgrid, int gridsize)
+{
+ GPUIndexBufBuilder elb;
+ if (buffers->smooth) {
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 6 * totgrid, INT_MAX);
+ for (int i = 0; i < totgrid; i++) {
+ GPU_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize + gridsize - 1);
+ GPU_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize);
+ GPU_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - gridsize);
+ GPU_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - 1);
+ GPU_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize + gridsize - 1);
+ GPU_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - gridsize);
+ }
+ }
+ else {
+ GPU_indexbuf_init_ex(&elb, GPU_PRIM_TRI_STRIP, 5 * totgrid, INT_MAX, true);
+ uint vbo_index_offset = 0;
+ for (int i = 0; i < totgrid; i++) {
+ uint grid_indices[4];
+ for (int j = 0; j < gridsize - 1; j++) {
+ for (int k = 0; k < gridsize - 1; k++) {
+ const bool is_row_start = (k == 0);
+ const bool is_row_end = (k == gridsize - 2);
+ const bool is_grid_start = (j == 0);
+ const bool is_grid_end = (j == gridsize - 2);
+ const bool is_first_grid = (i == 0);
+ const bool is_last_grid = (i == totgrid - 1);
+
+ if (is_row_start && !(is_grid_start && is_first_grid)) {
+ vbo_index_offset += 1;
+ }
+
+ if (is_grid_start && is_row_start) {
+ grid_indices[0] = vbo_index_offset + 0;
+ }
+ else if (is_grid_start && is_row_end) {
+ grid_indices[1] = vbo_index_offset + 2;
+ }
+ else if (is_grid_end && is_row_start) {
+ grid_indices[2] = vbo_index_offset + 1;
+ }
+ else if (is_grid_end && is_row_end) {
+ grid_indices[3] = vbo_index_offset + 3;
+ }
+ vbo_index_offset += 4;
+
+ if (is_row_end && !(is_grid_end && is_last_grid)) {
+ vbo_index_offset += 1;
+ }
+ }
+ }
+ GPU_indexbuf_add_generic_vert(&elb, grid_indices[1]);
+ GPU_indexbuf_add_generic_vert(&elb, grid_indices[0]);
+ GPU_indexbuf_add_generic_vert(&elb, grid_indices[3]);
+ GPU_indexbuf_add_generic_vert(&elb, grid_indices[2]);
+ GPU_indexbuf_add_primitive_restart(&elb);
+ }
+ }
+ buffers->index_buf_fast = GPU_indexbuf_build(&elb);
+}
+
void GPU_pbvh_grid_buffers_update(
GPU_PBVH_Buffers *buffers, CCGElem **grids,
const DMFlagMat *grid_flag_mats, int *grid_indices,
int totgrid, const CCGKey *key,
const int update_flags)
{
- const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0;
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
- VertexBufferFormat *vert_data;
+ bool empty_mask = true;
int i, j, k, x, y;
- buffers->show_diffuse_color = show_diffuse_color;
- buffers->show_mask = show_mask;
- buffers->use_matcaps = GPU_material_use_matcaps_get();
buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
/* Build VBO */
- if (buffers->vert_buf) {
- const int has_mask = key->has_mask;
- float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f};
+ const int has_mask = key->has_mask;
- if (buffers->use_matcaps)
- diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0;
- else if (show_diffuse_color) {
- const DMFlagMat *flags = &grid_flag_mats[grid_indices[0]];
+ uint vert_count = totgrid * key->grid_area;
- GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color);
- }
+ if (!buffers->smooth) {
+ vert_count = totgrid * (key->grid_size - 1) * (key->grid_size - 1) * 4;
+ /* Count strip restart verts (2 verts between each row and grid) */
+ vert_count += ((totgrid - 1) + totgrid * (key->grid_size - 2)) * 2;
+ }
- copy_v4_v4(buffers->diffuse_color, diffuse_color);
+ if (buffers->smooth && buffers->index_buf == NULL) {
+ /* Not sure if really needed. */
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
+ }
+ else if (!buffers->smooth && buffers->index_buf != NULL) {
+ /* Discard unnecessary index buffers. */
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
+ }
- vert_data = GPU_buffer_lock_stream(buffers->vert_buf, GPU_BINDING_ARRAY);
- if (vert_data) {
- for (i = 0; i < totgrid; ++i) {
- VertexBufferFormat *vd = vert_data;
- CCGElem *grid = grids[grid_indices[i]];
+ if (buffers->index_buf_fast == NULL) {
+ gpu_pbvh_grid_fill_fast_buffer(buffers, totgrid, key->grid_size);
+ }
+ uint vbo_index_offset = 0;
+ /* Build VBO */
+ if (gpu_pbvh_vert_buf_data_set(buffers, vert_count)) {
+ for (i = 0; i < totgrid; ++i) {
+ CCGElem *grid = grids[grid_indices[i]];
+ int vbo_index = vbo_index_offset;
+
+ if (buffers->smooth) {
for (y = 0; y < key->grid_size; y++) {
for (x = 0; x < key->grid_size; x++) {
CCGElem *elem = CCG_grid_elem(key, grid, x, y);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, CCG_elem_co(key, elem));
+
+ short no_short[3];
+ normal_float_to_short_v3(no_short, CCG_elem_no(key, elem));
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short);
- copy_v3_v3(vd->co, CCG_elem_co(key, elem));
- if (buffers->smooth) {
- normal_float_to_short_v3(vd->no, CCG_elem_no(key, elem));
-
- if (has_mask) {
- if (show_mask) {
- gpu_color_from_mask_copy(*CCG_elem_mask(key, elem),
- diffuse_color, vd->color);
- }
- else {
- unit_float_to_uchar_clamp_v3(vd->color, diffuse_color);
- }
- }
+ if (has_mask && show_mask) {
+ float fmask = *CCG_elem_mask(key, elem);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &fmask);
+ empty_mask = empty_mask && (fmask == 0.0f);
}
- vd++;
+ vbo_index += 1;
}
}
+ vbo_index_offset += key->grid_area;
+ }
+ else {
+ for (j = 0; j < key->grid_size - 1; j++) {
+ for (k = 0; k < key->grid_size - 1; k++) {
+ const bool is_row_start = (k == 0);
+ const bool is_row_end = (k == key->grid_size - 2);
+ const bool is_grid_start = (j == 0);
+ const bool is_grid_end = (j == key->grid_size - 2);
+ const bool is_first_grid = (i == 0);
+ const bool is_last_grid = (i == totgrid - 1);
+
+ CCGElem *elems[4] = {
+ CCG_grid_elem(key, grid, k, j + 1),
+ CCG_grid_elem(key, grid, k + 1, j + 1),
+ CCG_grid_elem(key, grid, k + 1, j),
+ CCG_grid_elem(key, grid, k, j)
+ };
+ float *co[4] = {
+ CCG_elem_co(key, elems[0]),
+ CCG_elem_co(key, elems[1]),
+ CCG_elem_co(key, elems[2]),
+ CCG_elem_co(key, elems[3])
+ };
+
+ float fno[3];
+ short no_short[3];
+ normal_quad_v3(fno, co[0], co[1], co[2], co[3]);
+ normal_float_to_short_v3(no_short, fno);
+
+ if (is_row_start && !(is_grid_start && is_first_grid)) {
+ /* Duplicate first vert
+ * (only pos is needed since the triangle will be degenerate) */
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, co[3]);
+ vbo_index += 1;
+ vbo_index_offset += 1;
+ }
+
+ /* Note indices orders (3, 0, 2, 1); we are drawing a triangle strip. */
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, co[3]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 1, co[0]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 1, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 2, co[2]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 2, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 3, co[1]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 3, no_short);
+
+ if (has_mask && show_mask) {
+ float fmask = (*CCG_elem_mask(key, elems[0]) +
+ *CCG_elem_mask(key, elems[1]) +
+ *CCG_elem_mask(key, elems[2]) +
+ *CCG_elem_mask(key, elems[3])) * 0.25f;
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &fmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 1, &fmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 2, &fmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 3, &fmask);
+ empty_mask = empty_mask && (fmask == 0.0f);
+ }
- if (!buffers->smooth) {
- /* for flat shading, recalc normals and set the last vertex of
- * each triangle in the index buffer to have the flat normal as
- * that is what opengl will use */
- for (j = 0; j < key->grid_size - 1; j++) {
- for (k = 0; k < key->grid_size - 1; k++) {
- CCGElem *elems[4] = {
- CCG_grid_elem(key, grid, k, j + 1),
- CCG_grid_elem(key, grid, k + 1, j + 1),
- CCG_grid_elem(key, grid, k + 1, j),
- CCG_grid_elem(key, grid, k, j)
- };
- float fno[3];
-
- normal_quad_v3(fno,
- CCG_elem_co(key, elems[0]),
- CCG_elem_co(key, elems[1]),
- CCG_elem_co(key, elems[2]),
- CCG_elem_co(key, elems[3]));
-
- vd = vert_data + (j + 1) * key->grid_size + k;
- normal_float_to_short_v3(vd->no, fno);
-
- if (has_mask) {
- if (show_mask) {
- gpu_color_from_mask_quad_copy(key,
- elems[0],
- elems[1],
- elems[2],
- elems[3],
- diffuse_color,
- vd->color);
- }
- else {
- unit_float_to_uchar_clamp_v3(vd->color, diffuse_color);
- }
- }
+ if (is_row_end && !(is_grid_end && is_last_grid)) {
+ /* Duplicate last vert
+ * (only pos is needed since the triangle will be degenerate) */
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 4, co[1]);
+ vbo_index += 1;
+ vbo_index_offset += 1;
}
+
+ vbo_index += 4;
}
}
-
- vert_data += key->grid_area;
+ vbo_index_offset += (key->grid_size - 1) * (key->grid_size - 1) * 4;
}
-
- GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY);
- }
- else {
- GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = NULL;
}
+
+ gpu_pbvh_batch_init(buffers, buffers->smooth ? GPU_PRIM_TRIS : GPU_PRIM_TRI_STRIP);
}
buffers->grids = grids;
@@ -1359,130 +532,73 @@ void GPU_pbvh_grid_buffers_update(
buffers->totgrid = totgrid;
buffers->grid_flag_mats = grid_flag_mats;
buffers->gridkey = *key;
+ buffers->show_mask = !empty_mask;
//printf("node updated %p\n", buffers);
}
/* Build the element array buffer of grid indices using either
- * unsigned shorts or unsigned ints. */
-#define FILL_QUAD_BUFFER(type_, tot_quad_, buffer_) \
- { \
- type_ *tri_data; \
- int offset = 0; \
- int i, j, k; \
- buffer_ = GPU_buffer_alloc(sizeof(type_) * (tot_quad_) * 6); \
+ * ushorts or uints. */
+#define FILL_QUAD_BUFFER(max_vert_, tot_quad_, buffer_) \
+ { \
+ int offset = 0; \
+ int i, j, k; \
+ \
+ GPUIndexBufBuilder elb; \
+ GPU_indexbuf_init( \
+ &elb, GPU_PRIM_TRIS, tot_quad_ * 2, max_vert_); \
+ \
+ /* Fill the buffer */ \
+ for (i = 0; i < totgrid; ++i) { \
+ BLI_bitmap *gh = NULL; \
+ if (grid_hidden) \
+ gh = grid_hidden[(grid_indices)[i]]; \
+ \
+ for (j = 0; j < gridsize - 1; ++j) { \
+ for (k = 0; k < gridsize - 1; ++k) { \
+ /* Skip hidden grid face */ \
+ if (gh && paint_is_grid_face_hidden( \
+ gh, gridsize, k, j)) \
+ { \
+ continue; \
+ } \
+ GPU_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k + 1); \
+ GPU_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k); \
+ GPU_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k); \
\
- /* Fill the buffer */ \
- tri_data = GPU_buffer_lock(buffer_, GPU_BINDING_INDEX); \
- if (tri_data) { \
- for (i = 0; i < totgrid; ++i) { \
- BLI_bitmap *gh = NULL; \
- if (grid_hidden) \
- gh = grid_hidden[(grid_indices)[i]]; \
+ GPU_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k + 1); \
+ GPU_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k + 1); \
+ GPU_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k); \
+ } \
+ } \
\
- for (j = 0; j < gridsize - 1; ++j) { \
- for (k = 0; k < gridsize - 1; ++k) { \
- /* Skip hidden grid face */ \
- if (gh && \
- paint_is_grid_face_hidden(gh, \
- gridsize, k, j)) \
- continue; \
- \
- *(tri_data++) = offset + j * gridsize + k + 1; \
- *(tri_data++) = offset + j * gridsize + k; \
- *(tri_data++) = offset + (j + 1) * gridsize + k; \
- \
- *(tri_data++) = offset + (j + 1) * gridsize + k + 1; \
- *(tri_data++) = offset + j * gridsize + k + 1; \
- *(tri_data++) = offset + (j + 1) * gridsize + k; \
- } \
- } \
- \
- offset += gridsize * gridsize; \
- } \
- GPU_buffer_unlock(buffer_, GPU_BINDING_INDEX); \
- } \
- else { \
- GPU_buffer_free(buffer_); \
- (buffer_) = NULL; \
- } \
- } (void)0
+ offset += gridsize * gridsize; \
+ } \
+ buffer_ = GPU_indexbuf_build(&elb); \
+ } (void)0
/* end FILL_QUAD_BUFFER */
-static GPUBuffer *gpu_get_grid_buffer(
- int gridsize, GLenum *index_type, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer)
+static GPUIndexBuf *gpu_get_grid_buffer(
+ int gridsize, uint *totquad,
+ /* remove this arg when GPU gets base-vertex support! */
+ int totgrid)
{
/* used in the FILL_QUAD_BUFFER macro */
BLI_bitmap * const *grid_hidden = NULL;
const int *grid_indices = NULL;
- int totgrid = 1;
-
- GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
-
- if (gridbuff == NULL) {
- *grid_common_gpu_buffer = gridbuff = MEM_mallocN(sizeof(GridCommonGPUBuffer), __func__);
- gridbuff->mres_buffer = NULL;
- gridbuff->mres_prev_gridsize = -1;
- gridbuff->mres_prev_index_type = 0;
- gridbuff->mres_prev_totquad = 0;
- }
-
- /* VBO is already built */
- if (gridbuff->mres_buffer && gridbuff->mres_prev_gridsize == gridsize) {
- *index_type = gridbuff->mres_prev_index_type;
- *totquad = gridbuff->mres_prev_totquad;
- return gridbuff->mres_buffer;
- }
- /* we can't reuse old, delete the existing buffer */
- else if (gridbuff->mres_buffer) {
- GPU_buffer_free(gridbuff->mres_buffer);
- }
/* Build new VBO */
- *totquad = (gridsize - 1) * (gridsize - 1);
+ *totquad = (gridsize - 1) * (gridsize - 1) * totgrid;
+ int max_vert = gridsize * gridsize * totgrid;
- if (gridsize * gridsize < USHRT_MAX) {
- *index_type = GL_UNSIGNED_SHORT;
- FILL_QUAD_BUFFER(unsigned short, *totquad, gridbuff->mres_buffer);
- }
- else {
- *index_type = GL_UNSIGNED_INT;
- FILL_QUAD_BUFFER(unsigned int, *totquad, gridbuff->mres_buffer);
- }
+ GPUIndexBuf *mres_buffer;
+ FILL_QUAD_BUFFER(max_vert, *totquad, mres_buffer);
- gridbuff->mres_prev_gridsize = gridsize;
- gridbuff->mres_prev_index_type = *index_type;
- gridbuff->mres_prev_totquad = *totquad;
- return gridbuff->mres_buffer;
+ return mres_buffer;
}
-#define FILL_FAST_BUFFER(type_) \
-{ \
- type_ *buffer; \
- buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid); \
- buffer = GPU_buffer_lock(buffers->index_buf_fast, GPU_BINDING_INDEX); \
- if (buffer) { \
- int i; \
- for (i = 0; i < totgrid; i++) { \
- int currentquad = i * 6; \
- buffer[currentquad] = i * gridsize * gridsize + gridsize - 1; \
- buffer[currentquad + 1] = i * gridsize * gridsize; \
- buffer[currentquad + 2] = (i + 1) * gridsize * gridsize - gridsize; \
- buffer[currentquad + 3] = (i + 1) * gridsize * gridsize - 1; \
- buffer[currentquad + 4] = i * gridsize * gridsize + gridsize - 1; \
- buffer[currentquad + 5] = (i + 1) * gridsize * gridsize - gridsize; \
- } \
- GPU_buffer_unlock(buffers->index_buf_fast, GPU_BINDING_INDEX); \
- } \
- else { \
- GPU_buffer_free(buffers->index_buf_fast); \
- buffers->index_buf_fast = NULL; \
- } \
-} (void)0
-
GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
- int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key,
- GridCommonGPUBuffer **grid_common_gpu_buffer)
+ int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *UNUSED(key))
{
GPU_PBVH_Buffers *buffers;
int totquad;
@@ -1492,9 +608,7 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
buffers->grid_hidden = grid_hidden;
buffers->totgrid = totgrid;
- buffers->show_diffuse_color = false;
- buffers->show_mask = true;
- buffers->use_matcaps = false;
+ buffers->show_mask = false;
/* Count the number of quads */
totquad = BKE_pbvh_count_grid_quads(grid_hidden, grid_indices, totgrid, gridsize);
@@ -1503,51 +617,23 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
if (totquad == 0)
return buffers;
- /* create and fill indices of the fast buffer too */
- if (totgrid * gridsize * gridsize < USHRT_MAX) {
- FILL_FAST_BUFFER(unsigned short);
- }
- else {
- FILL_FAST_BUFFER(unsigned int);
- }
-
+ /* TODO(fclem) this needs a bit of cleanup. It's only needed for smooth grids.
+ * Could be moved to the update function somehow. */
if (totquad == fully_visible_totquad) {
- buffers->index_buf = gpu_get_grid_buffer(
- gridsize, &buffers->index_type, &buffers->tot_quad, grid_common_gpu_buffer);
+ buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->tot_quad, totgrid);
buffers->has_hidden = false;
- buffers->is_index_buf_global = true;
+ buffers->is_index_buf_global = false;
}
else {
+ uint max_vert = totgrid * gridsize * gridsize;
buffers->tot_quad = totquad;
- if (totgrid * gridsize * gridsize < USHRT_MAX) {
- buffers->index_type = GL_UNSIGNED_SHORT;
- FILL_QUAD_BUFFER(unsigned short, totquad, buffers->index_buf);
- }
- else {
- buffers->index_type = GL_UNSIGNED_INT;
- FILL_QUAD_BUFFER(unsigned int, totquad, buffers->index_buf);
- }
+ FILL_QUAD_BUFFER(max_vert, totquad, buffers->index_buf);
- buffers->has_hidden = true;
+ buffers->has_hidden = false;
buffers->is_index_buf_global = false;
}
- /* Build coord/normal VBO */
- if (buffers->index_buf)
- buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area);
-
- if (GLEW_ARB_draw_elements_base_vertex /* 3.2 */) {
- int i;
- buffers->baseelemarray = MEM_mallocN(sizeof(int) * totgrid * 2, "GPU_PBVH_Buffers.baseelemarray");
- buffers->baseindex = MEM_mallocN(sizeof(void *) * totgrid, "GPU_PBVH_Buffers.baseindex");
- for (i = 0; i < totgrid; i++) {
- buffers->baseelemarray[i] = buffers->tot_quad * 6;
- buffers->baseelemarray[i + totgrid] = i * key->grid_area;
- buffers->baseindex[i] = NULL;
- }
- }
-
return buffers;
}
@@ -1559,32 +645,31 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(
* index '*v_index' in the 'vert_data' array and '*v_index' is
* incremented.
*/
-static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
- VertexBufferFormat *vert_data,
- int *v_index,
- const float fno[3],
- const float *fmask,
- const int cd_vert_mask_offset,
- const float diffuse_color[4],
- const bool show_mask)
+static void gpu_bmesh_vert_to_buffer_copy__gwn(
+ BMVert *v,
+ GPUVertBuf *vert_buf,
+ int *v_index,
+ const float fno[3],
+ const float *fmask,
+ const int cd_vert_mask_offset,
+ const bool show_mask,
+ bool *empty_mask)
{
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
- VertexBufferFormat *vd = &vert_data[*v_index];
/* Set coord, normal, and mask */
- copy_v3_v3(vd->co, v->co);
- normal_float_to_short_v3(vd->no, fno ? fno : v->no);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, *v_index, v->co);
+
+ short no_short[3];
+ normal_float_to_short_v3(no_short, fno ? fno : v->no);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, *v_index, no_short);
- float effective_mask;
if (show_mask) {
- effective_mask = fmask ? *fmask
- : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
+ float effective_mask = fmask ? *fmask
+ : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
+ GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, *v_index, &effective_mask);
+ *empty_mask = *empty_mask && (effective_mask == 0.0f);
}
- else {
- effective_mask = 0.0f;
- }
-
- gpu_color_from_mask_copy(effective_mask, diffuse_color, vd->color);
/* Assign index for use in the triangle index buffer */
/* note: caller must set: bm->elem_index_dirty |= BM_VERT; */
@@ -1641,56 +726,33 @@ void GPU_pbvh_bmesh_buffers_update(
GSet *bm_other_verts,
const int update_flags)
{
- const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0;
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
- VertexBufferFormat *vert_data;
- void *tri_data;
int tottri, totvert, maxvert = 0;
- float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f};
+ bool empty_mask = true;
/* TODO, make mask layer optional for bmesh buffer */
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
- buffers->show_diffuse_color = show_diffuse_color;
- buffers->show_mask = show_mask;
- buffers->use_matcaps = GPU_material_use_matcaps_get();
-
/* Count visible triangles */
tottri = gpu_bmesh_face_visible_count(bm_faces);
if (buffers->smooth) {
+ /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
/* Count visible vertices */
totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts);
}
- else
+ else {
totvert = tottri * 3;
+ }
if (!tottri) {
buffers->tot_tri = 0;
return;
}
- if (buffers->use_matcaps)
- diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0;
- else if (show_diffuse_color) {
- /* due to dynamic nature of dyntopo, only get first material */
- GSetIterator gs_iter;
- BMFace *f;
- BLI_gsetIterator_init(&gs_iter, bm_faces);
- f = BLI_gsetIterator_getKey(&gs_iter);
- GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color);
- }
-
- copy_v4_v4(buffers->diffuse_color, diffuse_color);
-
- /* Initialize vertex buffer */
- if (buffers->vert_buf)
- GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totvert);
-
/* Fill vertex buffer */
- vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY);
- if (vert_data) {
+ if (gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
int v_index = 0;
if (buffers->smooth) {
@@ -1701,17 +763,19 @@ void GPU_pbvh_bmesh_buffers_update(
bm->elem_index_dirty |= BM_VERT;
GSET_ITER (gs_iter, bm_unique_verts) {
- gpu_bmesh_vert_to_buffer_copy(BLI_gsetIterator_getKey(&gs_iter),
- vert_data, &v_index, NULL, NULL,
- cd_vert_mask_offset, diffuse_color,
- show_mask);
+ gpu_bmesh_vert_to_buffer_copy__gwn(
+ BLI_gsetIterator_getKey(&gs_iter),
+ buffers->vert_buf, &v_index, NULL, NULL,
+ cd_vert_mask_offset,
+ show_mask, &empty_mask);
}
GSET_ITER (gs_iter, bm_other_verts) {
- gpu_bmesh_vert_to_buffer_copy(BLI_gsetIterator_getKey(&gs_iter),
- vert_data, &v_index, NULL, NULL,
- cd_vert_mask_offset, diffuse_color,
- show_mask);
+ gpu_bmesh_vert_to_buffer_copy__gwn(
+ BLI_gsetIterator_getKey(&gs_iter),
+ buffers->vert_buf, &v_index, NULL, NULL,
+ cd_vert_mask_offset,
+ show_mask, &empty_mask);
}
maxvert = v_index;
@@ -1726,7 +790,7 @@ void GPU_pbvh_bmesh_buffers_update(
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
- float fmask = 0;
+ float fmask = 0.0f;
int i;
#if 0
@@ -1741,10 +805,11 @@ void GPU_pbvh_bmesh_buffers_update(
fmask /= 3.0f;
for (i = 0; i < 3; i++) {
- gpu_bmesh_vert_to_buffer_copy(v[i], vert_data,
- &v_index, f->no, &fmask,
- cd_vert_mask_offset, diffuse_color,
- show_mask);
+ gpu_bmesh_vert_to_buffer_copy__gwn(
+ v[i], buffers->vert_buf,
+ &v_index, f->no, &fmask,
+ cd_vert_mask_offset,
+ show_mask, &empty_mask);
}
}
}
@@ -1752,83 +817,61 @@ void GPU_pbvh_bmesh_buffers_update(
buffers->tot_tri = tottri;
}
- GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY);
-
/* gpu_bmesh_vert_to_buffer_copy sets dirty index values */
bm->elem_index_dirty |= BM_VERT;
}
else {
/* Memory map failed */
- GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = NULL;
return;
}
if (buffers->smooth) {
- const int use_short = (maxvert < USHRT_MAX);
+ /* Fill the triangle buffer */
+ buffers->index_buf = NULL;
+ GPUIndexBufBuilder elb;
+ GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, maxvert);
/* Initialize triangle index buffer */
- if (buffers->index_buf && !buffers->is_index_buf_global)
- GPU_buffer_free(buffers->index_buf);
buffers->is_index_buf_global = false;
- buffers->index_buf = GPU_buffer_alloc((use_short ?
- sizeof(unsigned short) :
- sizeof(unsigned int)) * 3 * tottri);
/* Fill triangle index buffer */
- tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX);
- if (tri_data) {
+
+ {
GSetIterator gs_iter;
GSET_ITER (gs_iter, bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
- BMLoop *l_iter;
- BMLoop *l_first;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BMVert *v = l_iter->v;
- if (use_short) {
- unsigned short *elem = tri_data;
- (*elem) = BM_elem_index_get(v);
- elem++;
- tri_data = elem;
- }
- else {
- unsigned int *elem = tri_data;
- (*elem) = BM_elem_index_get(v);
- elem++;
- tri_data = elem;
- }
- } while ((l_iter = l_iter->next) != l_first);
+ BMVert *v[3];
+
+ BM_face_as_array_vert_tri(f, v);
+ GPU_indexbuf_add_tri_verts(
+ &elb, BM_elem_index_get(v[0]), BM_elem_index_get(v[1]), BM_elem_index_get(v[2]));
}
}
- GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX);
-
buffers->tot_tri = tottri;
- buffers->index_type = (use_short ?
- GL_UNSIGNED_SHORT :
- GL_UNSIGNED_INT);
- }
- else {
- /* Memory map failed */
- if (!buffers->is_index_buf_global) {
- GPU_buffer_free(buffers->index_buf);
+
+ if (buffers->index_buf == NULL) {
+ buffers->index_buf = GPU_indexbuf_build(&elb);
+ }
+ else {
+ GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
}
- buffers->index_buf = NULL;
- buffers->is_index_buf_global = false;
}
}
else if (buffers->index_buf) {
if (!buffers->is_index_buf_global) {
- GPU_buffer_free(buffers->index_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
}
buffers->index_buf = NULL;
buffers->is_index_buf_global = false;
}
+
+ buffers->show_mask = !empty_mask;
+
+ gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
@@ -1838,290 +881,93 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers");
buffers->use_bmesh = true;
buffers->smooth = smooth_shading;
- buffers->show_diffuse_color = false;
buffers->show_mask = true;
- buffers->use_matcaps = false;
return buffers;
}
-void GPU_pbvh_buffers_draw(
- GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
- bool wireframe, bool fast)
+GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast)
{
- bool do_fast = fast && buffers->index_buf_fast;
- /* sets material from the first face, to solve properly face would need to
- * be sorted in buckets by materials */
- if (setMaterial) {
- if (buffers->face_indices_len) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]];
- const MPoly *mp = &buffers->mpoly[lt->poly];
- if (!setMaterial(mp->mat_nr + 1, NULL))
- return;
- }
- else if (buffers->totgrid) {
- const DMFlagMat *f = &buffers->grid_flag_mats[buffers->grid_indices[0]];
- if (!setMaterial(f->mat_nr + 1, NULL))
- return;
- }
- else {
- if (!setMaterial(1, NULL))
- return;
- }
- }
-
- if (buffers->vert_buf) {
- char *base = NULL;
- char *index_base = NULL;
- /* weak inspection of bound options, should not be necessary ideally */
- const int bound_options_old = GPU_basic_shader_bound_options();
- int bound_options_new = 0;
- glEnableClientState(GL_VERTEX_ARRAY);
- if (!wireframe) {
- glEnableClientState(GL_NORMAL_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
-
- bound_options_new |= GPU_SHADER_USE_COLOR;
- }
-
- GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY);
-
- if (do_fast) {
- GPU_buffer_bind(buffers->index_buf_fast, GPU_BINDING_INDEX);
- }
- else if (buffers->index_buf) {
- GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX);
- }
-
- if (wireframe) {
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- }
- else {
- if ((buffers->smooth == false) && (buffers->face_indices_len == 0)) {
- bound_options_new |= GPU_SHADER_FLAT_NORMAL;
- }
- }
-
- if (bound_options_new & ~bound_options_old) {
- GPU_basic_shader_bind(bound_options_old | bound_options_new);
- }
-
- if (buffers->tot_quad) {
- const char *offset = base;
- const bool drawall = !(buffers->has_hidden || do_fast);
-
- if (GLEW_ARB_draw_elements_base_vertex && drawall) {
-
- glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, co));
- if (!wireframe) {
- glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, no));
- glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, color));
- }
-
- glMultiDrawElementsBaseVertex(GL_TRIANGLES, buffers->baseelemarray, buffers->index_type,
- (const void * const *)buffers->baseindex,
- buffers->totgrid, &buffers->baseelemarray[buffers->totgrid]);
- }
- else {
- int i, last = drawall ? buffers->totgrid : 1;
-
- /* we could optimize this to one draw call, but it would need more memory */
- for (i = 0; i < last; i++) {
- glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, co));
- if (!wireframe) {
- glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, no));
- glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, color));
- }
-
- if (do_fast)
- glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, index_base);
- else
- glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, index_base);
-
- offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat);
- }
- }
- }
- else if (buffers->tot_tri) {
- int totelem = buffers->tot_tri * 3;
-
- glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat),
- (void *)(base + offsetof(VertexBufferFormat, co)));
-
- if (!wireframe) {
- glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
- (void *)(base + offsetof(VertexBufferFormat, no)));
- glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
- (void *)(base + offsetof(VertexBufferFormat, color)));
- }
-
- if (buffers->index_buf)
- glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, index_base);
- else
- glDrawArrays(GL_TRIANGLES, 0, totelem);
- }
-
- if (wireframe)
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ return (fast && buffers->triangles_fast) ?
+ buffers->triangles_fast : buffers->triangles;
+}
- GPU_buffer_unbind(buffers->vert_buf, GPU_BINDING_ARRAY);
- if (buffers->index_buf || do_fast)
- GPU_buffer_unbind(do_fast ? buffers->index_buf_fast : buffers->index_buf, GPU_BINDING_INDEX);
+bool GPU_pbvh_buffers_has_mask(GPU_PBVH_Buffers *buffers)
+{
+ return buffers->show_mask;
+}
- glDisableClientState(GL_VERTEX_ARRAY);
- if (!wireframe) {
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
+void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
+{
+ if (buffers) {
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ if (!buffers->is_index_buf_global) {
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
}
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
+ GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
- if (bound_options_new & ~bound_options_old) {
- GPU_basic_shader_bind(bound_options_old);
- }
+ MEM_freeN(buffers);
}
}
-bool GPU_pbvh_buffers_diffuse_changed(
- GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color)
+/* debug function, draws the pbvh BB */
+void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, uint pos)
{
- float diffuse_color[4];
- bool use_matcaps = GPU_material_use_matcaps_get();
-
- if (buffers->show_diffuse_color != show_diffuse_color)
- return true;
-
- if (buffers->use_matcaps != use_matcaps)
- return true;
-
- if ((buffers->show_diffuse_color == false) || use_matcaps)
- return false;
-
- if (buffers->looptri) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]];
- const MPoly *mp = &buffers->mpoly[lt->poly];
-
- GPU_material_diffuse_get(mp->mat_nr + 1, diffuse_color);
- }
- else if (buffers->use_bmesh) {
- /* due to dynamic nature of dyntopo, only get first material */
- if (BLI_gset_len(bm_faces) > 0) {
- GSetIterator gs_iter;
- BMFace *f;
+ if (leaf)
+ immUniformColor4f(0.0, 1.0, 0.0, 0.5);
+ else
+ immUniformColor4f(1.0, 0.0, 0.0, 0.5);
- BLI_gsetIterator_init(&gs_iter, bm_faces);
- f = BLI_gsetIterator_getKey(&gs_iter);
- GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color);
- }
- else {
- return false;
- }
- }
- else {
- const DMFlagMat *flags = &buffers->grid_flag_mats[buffers->grid_indices[0]];
+ /* TODO(merwin): revisit this after we have mutable VertexBuffers
+ * could keep a static batch & index buffer, change the VBO contents per draw
+ */
- GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color);
- }
+ immBegin(GPU_PRIM_LINES, 24);
- return !equals_v3v3(diffuse_color, buffers->diffuse_color);
-}
+ /* top */
+ immVertex3f(pos, min[0], min[1], max[2]);
+ immVertex3f(pos, min[0], max[1], max[2]);
-bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask)
-{
- return (buffers->show_mask != show_mask);
-}
+ immVertex3f(pos, min[0], max[1], max[2]);
+ immVertex3f(pos, max[0], max[1], max[2]);
-void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
-{
- if (buffers) {
- if (buffers->vert_buf)
- GPU_buffer_free(buffers->vert_buf);
- if (buffers->index_buf && !buffers->is_index_buf_global)
- GPU_buffer_free(buffers->index_buf);
- if (buffers->index_buf_fast)
- GPU_buffer_free(buffers->index_buf_fast);
- if (buffers->baseelemarray)
- MEM_freeN(buffers->baseelemarray);
- if (buffers->baseindex)
- MEM_freeN(buffers->baseindex);
+ immVertex3f(pos, max[0], max[1], max[2]);
+ immVertex3f(pos, max[0], min[1], max[2]);
- MEM_freeN(buffers);
- }
-}
+ immVertex3f(pos, max[0], min[1], max[2]);
+ immVertex3f(pos, min[0], min[1], max[2]);
-void GPU_pbvh_multires_buffers_free(GridCommonGPUBuffer **grid_common_gpu_buffer)
-{
- GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
+ /* bottom */
+ immVertex3f(pos, min[0], min[1], min[2]);
+ immVertex3f(pos, min[0], max[1], min[2]);
- if (gridbuff) {
- if (gridbuff->mres_buffer) {
- BLI_mutex_lock(&buffer_mutex);
- gpu_buffer_free_intern(gridbuff->mres_buffer);
- BLI_mutex_unlock(&buffer_mutex);
- }
- MEM_freeN(gridbuff);
- *grid_common_gpu_buffer = NULL;
- }
-}
+ immVertex3f(pos, min[0], max[1], min[2]);
+ immVertex3f(pos, max[0], max[1], min[2]);
-/* debug function, draws the pbvh BB */
-void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf)
-{
- const float quads[4][4][3] = {
- {
- {min[0], min[1], min[2]},
- {max[0], min[1], min[2]},
- {max[0], min[1], max[2]},
- {min[0], min[1], max[2]}
- },
+ immVertex3f(pos, max[0], max[1], min[2]);
+ immVertex3f(pos, max[0], min[1], min[2]);
- {
- {min[0], min[1], min[2]},
- {min[0], max[1], min[2]},
- {min[0], max[1], max[2]},
- {min[0], min[1], max[2]}
- },
+ immVertex3f(pos, max[0], min[1], min[2]);
+ immVertex3f(pos, min[0], min[1], min[2]);
- {
- {max[0], max[1], min[2]},
- {max[0], min[1], min[2]},
- {max[0], min[1], max[2]},
- {max[0], max[1], max[2]}
- },
+ /* sides */
+ immVertex3f(pos, min[0], min[1], min[2]);
+ immVertex3f(pos, min[0], min[1], max[2]);
- {
- {max[0], max[1], min[2]},
- {min[0], max[1], min[2]},
- {min[0], max[1], max[2]},
- {max[0], max[1], max[2]}
- },
- };
+ immVertex3f(pos, min[0], max[1], min[2]);
+ immVertex3f(pos, min[0], max[1], max[2]);
- if (leaf)
- glColor4f(0.0, 1.0, 0.0, 0.5);
- else
- glColor4f(1.0, 0.0, 0.0, 0.5);
+ immVertex3f(pos, max[0], max[1], min[2]);
+ immVertex3f(pos, max[0], max[1], max[2]);
- glVertexPointer(3, GL_FLOAT, 0, &quads[0][0][0]);
- glDrawArrays(GL_QUADS, 0, 16);
-}
+ immVertex3f(pos, max[0], min[1], min[2]);
+ immVertex3f(pos, max[0], min[1], max[2]);
-void GPU_pbvh_BB_draw_init(void)
-{
- glPushAttrib(GL_ENABLE_BIT);
- glDisable(GL_CULL_FACE);
- glEnableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- glEnable(GL_BLEND);
+ immEnd();
}
-void GPU_pbvh_BB_draw_end(void)
+void GPU_pbvh_fix_linking()
{
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glPopAttrib();
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index d1e74fc8b3f..952886bafed 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -36,17 +36,24 @@
#include "DNA_customdata_types.h"
#include "DNA_image_types.h"
#include "DNA_material_types.h"
+#include "DNA_node_types.h"
#include "BLI_blenlib.h"
+#include "BLI_hash_mm2a.h"
+#include "BLI_link_utils.h"
#include "BLI_utildefines.h"
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
+#include "BLI_threads.h"
+
+#include "PIL_time.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -56,21 +63,80 @@
#include <stdarg.h>
extern char datatoc_gpu_shader_material_glsl[];
-extern char datatoc_gpu_shader_vertex_glsl[];
-extern char datatoc_gpu_shader_vertex_world_glsl[];
extern char datatoc_gpu_shader_geometry_glsl[];
static char *glsl_material_library = NULL;
+/* -------------------- GPUPass Cache ------------------ */
+/**
+ * Internal shader cache: This prevent the shader recompilation / stall when
+ * using undo/redo AND also allows for GPUPass reuse if the Shader code is the
+ * same for 2 different Materials. Unused GPUPasses are free by Garbage collection.
+ **/
+
+/* Only use one linklist that contains the GPUPasses grouped by hash. */
+static GPUPass *pass_cache = NULL;
+static SpinLock pass_cache_spin;
+
+static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs, GPUVertexAttribs *attribs)
+{
+ BLI_HashMurmur2A hm2a;
+ BLI_hash_mm2a_init(&hm2a, 0);
+ BLI_hash_mm2a_add(&hm2a, (uchar *)frag_gen, strlen(frag_gen));
+ if (attribs) {
+ for (int att_idx = 0; att_idx < attribs->totlayer; att_idx++) {
+ char *name = attribs->layer[att_idx].name;
+ BLI_hash_mm2a_add(&hm2a, (uchar *)name, strlen(name));
+ }
+ }
+ if (defs)
+ BLI_hash_mm2a_add(&hm2a, (uchar *)defs, strlen(defs));
+
+ return BLI_hash_mm2a_end(&hm2a);
+}
+
+/* Search by hash only. Return first pass with the same hash.
+ * There is hash collision if (pass->next && pass->next->hash == hash) */
+static GPUPass *gpu_pass_cache_lookup(uint32_t hash)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ /* Could be optimized with a Lookup table. */
+ for (GPUPass *pass = pass_cache; pass; pass = pass->next) {
+ if (pass->hash == hash) {
+ BLI_spin_unlock(&pass_cache_spin);
+ return pass;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+ return NULL;
+}
+
+/* Check all possible passes with the same hash. */
+static GPUPass *gpu_pass_cache_resolve_collision(
+ GPUPass *pass, const char *vert, const char *geom, const char *frag, const char *defs, uint32_t hash)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ /* Collision, need to strcmp the whole shader. */
+ for (; pass && (pass->hash == hash); pass = pass->next) {
+ if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ }
+ else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ }
+ else if ((strcmp(pass->fragmentcode, frag) == 0) &&
+ (strcmp(pass->vertexcode, vert) == 0))
+ {
+ BLI_spin_unlock(&pass_cache_spin);
+ return pass;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+ return NULL;
+}
+
+/* -------------------- GPU Codegen ------------------ */
/* type definitions and constants */
-enum {
- MAX_FUNCTION_NAME = 64
-};
-enum {
- MAX_PARAMETER = 32
-};
+#define MAX_FUNCTION_NAME 64
+#define MAX_PARAMETER 32
typedef enum {
FUNCTION_QUAL_IN,
@@ -88,7 +154,7 @@ typedef struct GPUFunction {
/* Indices match the GPUType enum */
static const char *GPU_DATATYPE_STR[17] = {
"", "float", "vec2", "vec3", "vec4",
- NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4",
+ NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4"
};
/* GLSL code parsing for finding function definitions.
@@ -119,7 +185,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
/* skip a variable/function name */
while (*str) {
- if (ELEM(*str, ' ', '(', ')', ',', '\t', '\n', '\r'))
+ if (ELEM(*str, ' ', '(', ')', ',', ';', '\t', '\n', '\r'))
break;
else {
if (token && len < max - 1) {
@@ -137,7 +203,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
/* skip the next special characters:
* note the missing ')' */
while (*str) {
- if (ELEM(*str, ' ', '(', ',', '\t', '\n', '\r'))
+ if (ELEM(*str, ' ', '(', ',', ';', '\t', '\n', '\r'))
str++;
else
break;
@@ -172,7 +238,7 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
/* test for type */
type = GPU_NONE;
- for (i = 1; i <= 16; i++) {
+ for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) {
if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) {
type = i;
break;
@@ -185,9 +251,19 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
if (!type && gpu_str_prefix(code, "sampler2DShadow")) {
type = GPU_SHADOW2D;
}
+ if (!type && gpu_str_prefix(code, "sampler1DArray")) {
+ type = GPU_TEX1D_ARRAY;
+ }
if (!type && gpu_str_prefix(code, "sampler2D")) {
type = GPU_TEX2D;
}
+ if (!type && gpu_str_prefix(code, "sampler3D")) {
+ type = GPU_TEX3D;
+ }
+
+ if (!type && gpu_str_prefix(code, "Closure")) {
+ type = GPU_CLOSURE;
+ }
if (type) {
/* add parameter */
@@ -343,7 +419,7 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
else if (from == GPU_FLOAT)
BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name);
}
- else {
+ else if (to == GPU_VEC4) {
if (from == GPU_VEC3)
BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name);
else if (from == GPU_VEC2)
@@ -351,6 +427,19 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
else if (from == GPU_FLOAT)
BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name);
}
+ else if (to == GPU_CLOSURE) {
+ if (from == GPU_VEC4)
+ BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name);
+ else if (from == GPU_VEC3)
+ BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name);
+ else if (from == GPU_VEC2)
+ BLI_dynstr_appendf(ds, "closure_emission(%s.rrr)", name);
+ else if (from == GPU_FLOAT)
+ BLI_dynstr_appendf(ds, "closure_emission(vec3(%s, %s, %s))", name, name, name);
+ }
+ else {
+ BLI_dynstr_append(ds, name);
+ }
}
static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
@@ -372,10 +461,8 @@ static int codegen_input_has_texture(GPUInput *input)
{
if (input->link)
return 0;
- else if (input->ima || input->prv)
- return 1;
else
- return input->tex != NULL;
+ return (input->source == GPU_SOURCE_TEX);
}
const char *GPU_builtin_name(GPUBuiltin builtin)
@@ -412,6 +499,16 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
return "unfparticleangvel";
else if (builtin == GPU_OBJECT_INFO)
return "unfobjectinfo";
+ else if (builtin == GPU_VOLUME_DENSITY)
+ return "sampdensity";
+ else if (builtin == GPU_VOLUME_FLAME)
+ return "sampflame";
+ else if (builtin == GPU_VOLUME_TEMPERATURE)
+ return "unftemperature";
+ else if (builtin == GPU_BARYCENTRIC_TEXCO)
+ return "unfbarycentrictex";
+ else if (builtin == GPU_BARYCENTRIC_DIST)
+ return "unfbarycentricdist";
else
return "";
}
@@ -434,89 +531,67 @@ static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void
static void codegen_set_unique_ids(ListBase *nodes)
{
- GHash *bindhash, *definehash;
+ GHash *bindhash;
GPUNode *node;
GPUInput *input;
GPUOutput *output;
int id = 1, texid = 0;
bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
- definehash = BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
/* set id for unique names of uniform variables */
input->id = id++;
- input->bindtex = false;
- input->definetex = false;
- /* set texid used for settings texture slot with multitexture */
- if (codegen_input_has_texture(input) &&
- ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)))
- {
- /* assign only one texid per buffer to avoid sampling
- * the same texture twice */
- if (input->link) {
- /* input is texture from buffer */
- codegen_set_texid(bindhash, input, &texid, input->link);
- }
- else if (input->ima) {
+ /* set texid used for settings texture slot */
+ if (codegen_input_has_texture(input)) {
+ input->bindtex = false;
+ if (input->ima) {
/* input is texture from image */
codegen_set_texid(bindhash, input, &texid, input->ima);
}
- else if (input->prv) {
- /* input is texture from preview render */
- codegen_set_texid(bindhash, input, &texid, input->prv);
+ else if (input->coba) {
+ /* input is color band texture, check coba pointer */
+ codegen_set_texid(bindhash, input, &texid, input->coba);
}
- else if (input->tex) {
- /* input is user created texture, check tex pointer */
- codegen_set_texid(bindhash, input, &texid, input->tex);
- }
-
- /* make sure this pixel is defined exactly once */
- if (input->source == GPU_SOURCE_TEX_PIXEL) {
- if (input->ima) {
- if (!BLI_ghash_haskey(definehash, input->ima)) {
- input->definetex = true;
- BLI_ghash_insert(definehash, input->ima, POINTER_FROM_INT(input->texid));
- }
- }
- else {
- if (!BLI_ghash_haskey(definehash, input->link)) {
- input->definetex = true;
- BLI_ghash_insert(definehash, input->link, POINTER_FROM_INT(input->texid));
- }
- }
+ else {
+ /* Either input->ima or input->coba should be non-NULL. */
+ BLI_assert(0);
}
}
}
- for (output = node->outputs.first; output; output = output->next)
+ for (output = node->outputs.first; output; output = output->next) {
/* set id for unique names of tmp variables storing output */
output->id = id++;
+ }
}
BLI_ghash_free(bindhash, NULL, NULL);
- BLI_ghash_free(definehash, NULL, NULL);
}
-static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
+/**
+ * It will create an UBO for GPUMaterial if there is any GPU_DYNAMIC_UBO.
+ */
+static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds, ListBase *nodes)
{
GPUNode *node;
GPUInput *input;
const char *name;
int builtins = 0;
+ ListBase ubo_inputs = {NULL, NULL};
/* print uniforms */
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
- if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) {
+ if (input->source == GPU_SOURCE_TEX) {
/* create exactly one sampler for each texture */
if (codegen_input_has_texture(input) && input->bindtex) {
- BLI_dynstr_appendf(ds, "uniform %s samp%d;\n",
- (input->textype == GPU_TEX2D) ? "sampler2D" :
- (input->textype == GPU_TEXCUBE) ? "samplerCube" : "sampler2DShadow",
- input->texid);
+ BLI_dynstr_appendf(
+ ds, "uniform %s samp%d;\n",
+ (input->coba) ? "sampler1DArray" : "sampler2D",
+ input->texid);
}
}
else if (input->source == GPU_SOURCE_BUILTIN) {
@@ -525,50 +600,67 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
builtins |= input->builtin;
name = GPU_builtin_name(input->builtin);
- if (gpu_str_prefix(name, "unf")) {
- BLI_dynstr_appendf(ds, "uniform %s %s;\n",
- GPU_DATATYPE_STR[input->type], name);
+ if (gpu_str_prefix(name, "samp")) {
+ if ((input->builtin == GPU_VOLUME_DENSITY) ||
+ (input->builtin == GPU_VOLUME_FLAME))
+ {
+ BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name);
+ }
+ }
+ else if (gpu_str_prefix(name, "unf")) {
+ BLI_dynstr_appendf(
+ ds, "uniform %s %s;\n",
+ GPU_DATATYPE_STR[input->type], name);
}
else {
- BLI_dynstr_appendf(ds, "%s %s %s;\n",
- GLEW_VERSION_3_0 ? "in" : "varying",
- GPU_DATATYPE_STR[input->type], name);
+ BLI_dynstr_appendf(
+ ds, "in %s %s;\n",
+ GPU_DATATYPE_STR[input->type], name);
}
}
}
- else if (input->source == GPU_SOURCE_VEC_UNIFORM) {
- if (input->dynamicvec) {
- /* only create uniforms for dynamic vectors */
- BLI_dynstr_appendf(ds, "uniform %s unf%d;\n",
- GPU_DATATYPE_STR[input->type], input->id);
- }
- else {
- /* for others use const so the compiler can do folding */
- BLI_dynstr_appendf(ds, "const %s cons%d = ",
- GPU_DATATYPE_STR[input->type], input->id);
- codegen_print_datatype(ds, input->type, input->vec);
- BLI_dynstr_append(ds, ";\n");
+ else if (input->source == GPU_SOURCE_STRUCT) {
+ /* Add other struct here if needed. */
+ BLI_dynstr_appendf(ds, "Closure strct%d = CLOSURE_DEFAULT;\n", input->id);
+ }
+ else if (input->source == GPU_SOURCE_UNIFORM) {
+ if (!input->link) {
+ /* We handle the UBOuniforms separately. */
+ BLI_addtail(&ubo_inputs, BLI_genericNodeN(input));
}
}
+ else if (input->source == GPU_SOURCE_CONSTANT) {
+ BLI_dynstr_appendf(
+ ds, "const %s cons%d = ",
+ GPU_DATATYPE_STR[input->type], input->id);
+ codegen_print_datatype(ds, input->type, input->vec);
+ BLI_dynstr_append(ds, ";\n");
+ }
else if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
-#ifdef WITH_OPENSUBDIV
- bool skip_opensubdiv = input->attribtype == CD_TANGENT;
- if (skip_opensubdiv) {
- BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
- }
-#endif
- BLI_dynstr_appendf(ds, "%s %s var%d;\n",
- GLEW_VERSION_3_0 ? "in" : "varying",
- GPU_DATATYPE_STR[input->type], input->attribid);
-#ifdef WITH_OPENSUBDIV
- if (skip_opensubdiv) {
- BLI_dynstr_appendf(ds, "#endif\n");
- }
-#endif
+ BLI_dynstr_appendf(
+ ds, "in %s var%d;\n",
+ GPU_DATATYPE_STR[input->type], input->attribid);
}
}
}
+ /* Handle the UBO block separately. */
+ if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) {
+ GPU_material_uniform_buffer_create(material, &ubo_inputs);
+
+ /* Inputs are sorted */
+ BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME);
+
+ for (LinkData *link = ubo_inputs.first; link; link = link->next) {
+ input = link->data;
+ BLI_dynstr_appendf(
+ ds, "\t%s unf%d;\n",
+ GPU_DATATYPE_STR[input->type], input->id);
+ }
+ BLI_dynstr_append(ds, "};\n");
+ BLI_freelistN(&ubo_inputs);
+ }
+
BLI_dynstr_append(ds, "\n");
return builtins;
@@ -577,25 +669,20 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
{
GPUNode *node;
- GPUInput *input;
GPUOutput *output;
for (node = nodes->first; node; node = node->next) {
- /* load pixels from textures */
- for (input = node->inputs.first; input; input = input->next) {
- if (input->source == GPU_SOURCE_TEX_PIXEL) {
- if (codegen_input_has_texture(input) && input->definetex) {
- BLI_dynstr_appendf(ds, "\tvec4 tex%d = texture2D(", input->texid);
- BLI_dynstr_appendf(ds, "samp%d, gl_TexCoord[%d].st);\n",
- input->texid, input->texid);
- }
- }
- }
-
/* declare temporary variables for node output storage */
for (output = node->outputs.first; output; output = output->next) {
- BLI_dynstr_appendf(ds, "\t%s tmp%d;\n",
- GPU_DATATYPE_STR[output->type], output->id);
+ if (output->type == GPU_CLOSURE) {
+ BLI_dynstr_appendf(
+ ds, "\tClosure tmp%d;\n", output->id);
+ }
+ else {
+ BLI_dynstr_appendf(
+ ds, "\t%s tmp%d;\n",
+ GPU_DATATYPE_STR[output->type], output->id);
+ }
}
}
@@ -614,34 +701,51 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_TEX) {
BLI_dynstr_appendf(ds, "samp%d", input->texid);
- if (input->link)
- BLI_dynstr_appendf(ds, ", gl_TexCoord[%d].st", input->texid);
}
- else if (input->source == GPU_SOURCE_TEX_PIXEL) {
- codegen_convert_datatype(ds, input->link->output->type, input->type,
- "tmp", input->link->output->id);
+ else if (input->source == GPU_SOURCE_OUTPUT) {
+ codegen_convert_datatype(
+ ds, input->link->output->type, input->type,
+ "tmp", input->link->output->id);
}
else if (input->source == GPU_SOURCE_BUILTIN) {
- if (input->builtin == GPU_VIEW_NORMAL)
+ /* TODO(fclem) get rid of that. */
+ if (input->builtin == GPU_INVERSE_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "viewinv");
+ else if (input->builtin == GPU_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "viewmat");
+ else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS)
+ BLI_dynstr_append(ds, "camtexfac");
+ else if (input->builtin == GPU_LOC_TO_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "localtoviewmat");
+ else if (input->builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "invlocaltoviewmat");
+ else if (input->builtin == GPU_BARYCENTRIC_DIST)
+ BLI_dynstr_append(ds, "barycentricDist");
+ else if (input->builtin == GPU_BARYCENTRIC_TEXCO)
+ BLI_dynstr_append(ds, "barytexco");
+ else if (input->builtin == GPU_OBJECT_MATRIX)
+ BLI_dynstr_append(ds, "objmat");
+ else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX)
+ BLI_dynstr_append(ds, "objinv");
+ else if (input->builtin == GPU_VIEW_POSITION)
+ BLI_dynstr_append(ds, "viewposition");
+ else if (input->builtin == GPU_VIEW_NORMAL)
BLI_dynstr_append(ds, "facingnormal");
else
BLI_dynstr_append(ds, GPU_builtin_name(input->builtin));
}
- else if (input->source == GPU_SOURCE_VEC_UNIFORM) {
- if (input->dynamicvec)
- BLI_dynstr_appendf(ds, "unf%d", input->id);
- else
- BLI_dynstr_appendf(ds, "cons%d", input->id);
+ else if (input->source == GPU_SOURCE_STRUCT) {
+ BLI_dynstr_appendf(ds, "strct%d", input->id);
+ }
+ else if (input->source == GPU_SOURCE_UNIFORM) {
+ BLI_dynstr_appendf(ds, "unf%d", input->id);
+ }
+ else if (input->source == GPU_SOURCE_CONSTANT) {
+ BLI_dynstr_appendf(ds, "cons%d", input->id);
}
else if (input->source == GPU_SOURCE_ATTRIB) {
BLI_dynstr_appendf(ds, "var%d", input->attribid);
}
- else if (input->source == GPU_SOURCE_OPENGL_BUILTIN) {
- if (input->oglbuiltin == GPU_MATCAP_NORMAL)
- BLI_dynstr_append(ds, "gl_SecondaryColor");
- else if (input->oglbuiltin == GPU_COLOR)
- BLI_dynstr_append(ds, "gl_Color");
- }
BLI_dynstr_append(ds, ", ");
}
@@ -655,73 +759,77 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
BLI_dynstr_append(ds, ");\n");
}
- BLI_dynstr_append(ds, "\n\tgl_FragColor = ");
- codegen_convert_datatype(ds, finaloutput->type, GPU_VEC4, "tmp", finaloutput->id);
+ BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id);
BLI_dynstr_append(ds, ";\n");
}
-static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
+static char *code_generate_fragment(GPUMaterial *material, ListBase *nodes, GPUOutput *output, int *rbuiltins)
{
DynStr *ds = BLI_dynstr_new();
char *code;
int builtins;
-#ifdef WITH_OPENSUBDIV
- GPUNode *node;
- GPUInput *input;
-#endif
-
-
#if 0
BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);
#endif
codegen_set_unique_ids(nodes);
- builtins = codegen_print_uniforms_functions(ds, nodes);
+ *rbuiltins = builtins = codegen_process_uniforms_functions(material, ds, nodes);
-#if 0
- if (G.debug & G_DEBUG)
- BLI_dynstr_appendf(ds, "/* %s */\n", name);
-#endif
+ if (builtins & GPU_BARYCENTRIC_TEXCO)
+ BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n");
- BLI_dynstr_append(ds, "void main()\n{\n");
+ if (builtins & GPU_BARYCENTRIC_DIST)
+ BLI_dynstr_append(ds, "flat in vec3 barycentricDist;\n");
- if (builtins & GPU_VIEW_NORMAL)
- BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n");
+ BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n");
- /* Calculate tangent space. */
-#ifdef WITH_OPENSUBDIV
- {
- bool has_tangent = false;
- for (node = nodes->first; node; node = node->next) {
- for (input = node->inputs.first; input; input = input->next) {
- if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
- if (input->attribtype == CD_TANGENT) {
- BLI_dynstr_appendf(ds, "#ifdef USE_OPENSUBDIV\n");
- BLI_dynstr_appendf(ds, "\t%s var%d;\n",
- GPU_DATATYPE_STR[input->type],
- input->attribid);
- if (has_tangent == false) {
- BLI_dynstr_appendf(ds, "\tvec3 Q1 = dFdx(inpt.v.position.xyz);\n");
- BLI_dynstr_appendf(ds, "\tvec3 Q2 = dFdy(inpt.v.position.xyz);\n");
- BLI_dynstr_appendf(ds, "\tvec2 st1 = dFdx(inpt.v.uv);\n");
- BLI_dynstr_appendf(ds, "\tvec2 st2 = dFdy(inpt.v.uv);\n");
- BLI_dynstr_appendf(ds, "\tvec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n");
- }
- BLI_dynstr_appendf(ds, "\tvar%d = vec4(T, 1.0);\n", input->attribid);
- BLI_dynstr_appendf(ds, "#endif\n");
- }
- }
- }
- }
+ if (builtins & GPU_BARYCENTRIC_TEXCO) {
+ BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
+ BLI_dynstr_append(ds, "\tvec2 barytexco = vec2((fract(barycentricTexCo.y) != 0.0)\n"
+ "\t ? barycentricTexCo.x\n"
+ "\t : 1.0 - barycentricTexCo.x,\n"
+ "\t 0.0);\n");
+ BLI_dynstr_append(ds, "#else\n");
+ BLI_dynstr_append(ds, "\tvec2 barytexco = barycentricTexCo;\n");
+ BLI_dynstr_append(ds, "#endif\n");
}
-#endif
+ /* TODO(fclem) get rid of that. */
+ if (builtins & GPU_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "\t#define viewmat ViewMatrix\n");
+ if (builtins & GPU_CAMERA_TEXCO_FACTORS)
+ BLI_dynstr_append(ds, "\t#define camtexfac CameraTexCoFactors\n");
+ if (builtins & GPU_OBJECT_MATRIX)
+ BLI_dynstr_append(ds, "\t#define objmat ModelMatrix\n");
+ if (builtins & GPU_INVERSE_OBJECT_MATRIX)
+ BLI_dynstr_append(ds, "\t#define objinv ModelMatrixInverse\n");
+ if (builtins & GPU_INVERSE_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "\t#define viewinv ViewMatrixInverse\n");
+ if (builtins & GPU_LOC_TO_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "\t#define localtoviewmat ModelViewMatrix\n");
+ if (builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX)
+ BLI_dynstr_append(ds, "\t#define invlocaltoviewmat ModelViewMatrixInverse\n");
+ if (builtins & GPU_VIEW_NORMAL)
+ BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? viewNormal: -viewNormal;\n");
+ if (builtins & GPU_VIEW_POSITION)
+ BLI_dynstr_append(ds, "\t#define viewposition viewPosition\n");
codegen_declare_tmps(ds, nodes);
codegen_call_functions(ds, nodes, output);
BLI_dynstr_append(ds, "}\n");
+ /* XXX This cannot go into gpu_shader_material.glsl because main() would be parsed and generate error */
+ /* Old glsl mode compat. */
+ BLI_dynstr_append(ds, "#ifndef NODETREE_EXEC\n");
+ BLI_dynstr_append(ds, "out vec4 fragColor;\n");
+ BLI_dynstr_append(ds, "void main()\n");
+ BLI_dynstr_append(ds, "{\n");
+ BLI_dynstr_append(ds, "\tClosure cl = nodetree_exec();\n");
+ BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, cl.opacity);\n");
+ BLI_dynstr_append(ds, "}\n");
+ BLI_dynstr_append(ds, "#endif\n\n");
+
/* create shader */
code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
@@ -733,103 +841,233 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
return code;
}
-static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
+static const char *attrib_prefix_get(CustomDataType type)
+{
+ switch (type) {
+ case CD_ORCO: return "orco";
+ case CD_MTFACE: return "u";
+ case CD_TANGENT: return "t";
+ case CD_MCOL: return "c";
+ case CD_AUTO_FROM_NAME: return "a";
+ default: BLI_assert(false && "GPUVertAttr Prefix type not found : This should not happen!"); return "";
+ }
+}
+
+static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool use_geom)
{
DynStr *ds = BLI_dynstr_new();
GPUNode *node;
GPUInput *input;
char *code;
- char *vertcode = NULL;
+ int builtins = 0;
+
+ /* Hairs uv and col attribs are passed by bufferTextures. */
+ BLI_dynstr_append(
+ ds,
+ "#ifdef HAIR_SHADER\n"
+ "#define DEFINE_ATTRIB(type, attr) uniform samplerBuffer attr\n"
+ "#else\n"
+ "#define DEFINE_ATTRIB(type, attr) in type attr\n"
+ "#endif\n"
+ );
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
+ if (input->source == GPU_SOURCE_BUILTIN) {
+ builtins |= input->builtin;
+ }
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
-#ifdef WITH_OPENSUBDIV
- bool skip_opensubdiv = ELEM(input->attribtype, CD_MTFACE, CD_TANGENT);
- if (skip_opensubdiv) {
- BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
+ /* XXX FIXME : see notes in mesh_render_data_create() */
+ /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
+ if (input->attribtype == CD_ORCO) {
+ /* orco is computed from local positions, see below */
+ BLI_dynstr_appendf(ds, "uniform vec3 OrcoTexCoFactors[2];\n");
}
-#endif
- BLI_dynstr_appendf(ds, "%s %s att%d;\n",
- GLEW_VERSION_3_0 ? "in" : "attribute",
- GPU_DATATYPE_STR[input->type], input->attribid);
- BLI_dynstr_appendf(ds, "uniform int att%d_info;\n", input->attribid);
- BLI_dynstr_appendf(ds, "%s %s var%d;\n",
- GLEW_VERSION_3_0 ? "out" : "varying",
- GPU_DATATYPE_STR[input->type], input->attribid);
-#ifdef WITH_OPENSUBDIV
- if (skip_opensubdiv) {
- BLI_dynstr_appendf(ds, "#endif\n");
+ else if (input->attribname[0] == '\0') {
+ BLI_dynstr_appendf(ds, "DEFINE_ATTRIB(%s, %s);\n", GPU_DATATYPE_STR[input->type], attrib_prefix_get(input->attribtype));
+ BLI_dynstr_appendf(ds, "#define att%d %s\n", input->attribid, attrib_prefix_get(input->attribtype));
}
-#endif
+ else {
+ uint hash = BLI_ghashutil_strhash_p(input->attribname);
+ BLI_dynstr_appendf(
+ ds, "DEFINE_ATTRIB(%s, %s%u);\n",
+ GPU_DATATYPE_STR[input->type], attrib_prefix_get(input->attribtype), hash);
+ BLI_dynstr_appendf(
+ ds, "#define att%d %s%u\n",
+ input->attribid, attrib_prefix_get(input->attribtype), hash);
+ /* Auto attrib can be vertex color byte buffer.
+ * We need to know and convert them to linear space in VS. */
+ if (!use_geom && input->attribtype == CD_AUTO_FROM_NAME) {
+ BLI_dynstr_appendf(ds, "uniform bool ba%u;\n", hash);
+ BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%u\n", input->attribid, hash);
+ }
+ }
+ BLI_dynstr_appendf(
+ ds, "out %s var%d%s;\n",
+ GPU_DATATYPE_STR[input->type], input->attribid, use_geom ? "g" : "");
}
}
}
+ if (builtins & GPU_BARYCENTRIC_TEXCO) {
+ BLI_dynstr_appendf(
+ ds, "out vec2 barycentricTexCo%s;\n",
+ use_geom ? "g" : "");
+ }
+
+ if (builtins & GPU_BARYCENTRIC_DIST) {
+ BLI_dynstr_appendf(ds, "out vec3 barycentricPosg;\n");
+ }
+
+
BLI_dynstr_append(ds, "\n");
- switch (type) {
- case GPU_MATERIAL_TYPE_MESH:
- vertcode = datatoc_gpu_shader_vertex_glsl;
- break;
- case GPU_MATERIAL_TYPE_WORLD:
- vertcode = datatoc_gpu_shader_vertex_world_glsl;
- break;
- default:
- fprintf(stderr, "invalid material type, set one after GPU_material_construct_begin\n");
- break;
+ BLI_dynstr_append(
+ ds,
+ "#define ATTRIB\n"
+ "uniform mat3 NormalMatrix;\n"
+ "uniform mat4 ModelMatrixInverse;\n"
+ "uniform mat4 ModelMatrix;\n"
+ "vec3 srgb_to_linear_attrib(vec3 c) {\n"
+ "\tc = max(c, vec3(0.0));\n"
+ "\tvec3 c1 = c * (1.0 / 12.92);\n"
+ "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n"
+ "\treturn mix(c1, c2, step(vec3(0.04045), c));\n"
+ "}\n\n"
+ );
+
+ /* Prototype because defined later. */
+ BLI_dynstr_append(
+ ds,
+ "vec2 hair_get_customdata_vec2(const samplerBuffer);\n"
+ "vec3 hair_get_customdata_vec3(const samplerBuffer);\n"
+ "vec4 hair_get_customdata_vec4(const samplerBuffer);\n"
+ "vec3 hair_get_strand_pos(void);\n"
+ "int hair_get_base_id(void);\n"
+ "\n"
+ );
+
+ BLI_dynstr_append(ds, "void pass_attrib(in vec3 position) {\n");
+
+ BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
+
+ if (builtins & GPU_BARYCENTRIC_TEXCO) {
+ /* To match cycles without breaking into individual segment we encode if we need to invert
+ * the first component into the second component. We invert if the barycentricTexCo.y
+ * is NOT 0.0 or 1.0. */
+ BLI_dynstr_appendf(
+ ds, "\tint _base_id = hair_get_base_id();\n");
+ BLI_dynstr_appendf(
+ ds, "\tbarycentricTexCo%s.x = float((_base_id %% 2) == 1);\n",
+ use_geom ? "g" : "");
+ BLI_dynstr_appendf(
+ ds, "\tbarycentricTexCo%s.y = float(((_base_id %% 4) %% 3) > 0);\n",
+ use_geom ? "g" : "");
}
- BLI_dynstr_append(ds, vertcode);
+ if (builtins & GPU_BARYCENTRIC_DIST) {
+ BLI_dynstr_appendf(ds, "\tbarycentricPosg = position;\n");
+ }
- for (node = nodes->first; node; node = node->next)
- for (input = node->inputs.first; input; input = input->next)
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
- if (input->attribtype == CD_TANGENT) { /* silly exception */
-#ifdef WITH_OPENSUBDIV
- BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
-#endif
+ if (input->attribtype == CD_TANGENT) {
+ /* Not supported by hairs */
BLI_dynstr_appendf(
- ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n",
- input->attribid, input->attribid);
+ ds, "\tvar%d%s = vec4(0.0);\n",
+ input->attribid, use_geom ? "g" : "");
+ }
+ else if (input->attribtype == CD_ORCO) {
BLI_dynstr_appendf(
- ds, "\tvar%d.w = att%d.w;\n",
- input->attribid, input->attribid);
-#ifdef WITH_OPENSUBDIV
- BLI_dynstr_appendf(ds, "#endif\n");
-#endif
+ ds, "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n",
+ input->attribid, use_geom ? "g" : "");
}
else {
-#ifdef WITH_OPENSUBDIV
- bool is_mtface = input->attribtype == CD_MTFACE;
- if (is_mtface) {
- BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
- }
-#endif
- BLI_dynstr_appendf(ds, "\tset_var_from_attr(att%d, att%d_info, var%d);\n",
- input->attribid, input->attribid, input->attribid);
-#ifdef WITH_OPENSUBDIV
- if (is_mtface) {
- BLI_dynstr_appendf(ds, "#endif\n");
- }
-#endif
+ BLI_dynstr_appendf(
+ ds, "\tvar%d%s = hair_get_customdata_%s(att%d);\n",
+ input->attribid, use_geom ? "g" : "", GPU_DATATYPE_STR[input->type], input->attribid);
}
}
- /* unfortunately special handling is needed here because we abuse gl_Color/gl_SecondaryColor flat shading */
- else if (input->source == GPU_SOURCE_OPENGL_BUILTIN) {
- if (input->oglbuiltin == GPU_MATCAP_NORMAL) {
- /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
- * between shader stages and we want the full range of the normal */
- BLI_dynstr_appendf(ds, "\tvec3 matcapcol = vec3(0.5) * varnormal + vec3(0.5);\n");
- BLI_dynstr_appendf(ds, "\tgl_FrontSecondaryColor = vec4(matcapcol, 1.0);\n");
+ }
+ }
+
+ BLI_dynstr_append(ds, "#else /* MESH_SHADER */\n");
+
+ if (builtins & GPU_BARYCENTRIC_TEXCO) {
+ BLI_dynstr_appendf(
+ ds, "\tbarycentricTexCo%s.x = float((gl_VertexID %% 3) == 0);\n",
+ use_geom ? "g" : "");
+ BLI_dynstr_appendf(
+ ds, "\tbarycentricTexCo%s.y = float((gl_VertexID %% 3) == 1);\n",
+ use_geom ? "g" : "");
+ }
+
+ if (builtins & GPU_BARYCENTRIC_DIST) {
+ BLI_dynstr_appendf(ds, "\tbarycentricPosg = (ModelMatrix * vec4(position, 1.0)).xyz;\n");
+ }
+
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
+ if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
+ if (input->attribtype == CD_TANGENT) { /* silly exception */
+ BLI_dynstr_appendf(
+ ds, "\tvar%d%s.xyz = normalize(NormalMatrix * att%d.xyz);\n",
+ input->attribid, use_geom ? "g" : "", input->attribid);
+ BLI_dynstr_appendf(
+ ds, "\tvar%d%s.w = att%d.w;\n",
+ input->attribid, use_geom ? "g" : "", input->attribid);
}
- else if (input->oglbuiltin == GPU_COLOR) {
- BLI_dynstr_appendf(ds, "\tgl_FrontColor = gl_Color;\n");
+ else if (input->attribtype == CD_ORCO) {
+ BLI_dynstr_appendf(
+ ds, "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n",
+ input->attribid, use_geom ? "g" : "");
+ }
+ else if (input->attribtype == CD_MCOL) {
+ BLI_dynstr_appendf(
+ ds, "\tvar%d%s = srgb_to_linear_attrib(att%d);\n",
+ input->attribid, use_geom ? "g" : "", input->attribid);
+ }
+ else if (input->attribtype == CD_AUTO_FROM_NAME) {
+ BLI_dynstr_appendf(
+ ds, "\tvar%d%s = (att%d_is_srgb) ? srgb_to_linear_attrib(att%d) : att%d;\n",
+ input->attribid, use_geom ? "g" : "",
+ input->attribid, input->attribid, input->attribid);
+ }
+ else {
+ BLI_dynstr_appendf(
+ ds, "\tvar%d%s = att%d;\n",
+ input->attribid, use_geom ? "g" : "", input->attribid);
}
}
+ }
+ }
+ BLI_dynstr_append(ds, "#endif /* HAIR_SHADER */\n");
BLI_dynstr_append(ds, "}\n");
+ if (use_geom) {
+ /* XXX HACK: Eevee specific. */
+ char *vert_new, *vert_new2;
+ vert_new = BLI_str_replaceN(vert_code, "worldPosition", "worldPositiong");
+ vert_new2 = vert_new;
+ vert_new = BLI_str_replaceN(vert_new2, "viewPosition", "viewPositiong");
+ MEM_freeN(vert_new2);
+ vert_new2 = vert_new;
+ vert_new = BLI_str_replaceN(vert_new2, "worldNormal", "worldNormalg");
+ MEM_freeN(vert_new2);
+ vert_new2 = vert_new;
+ vert_new = BLI_str_replaceN(vert_new2, "viewNormal", "viewNormalg");
+ MEM_freeN(vert_new2);
+
+ BLI_dynstr_append(ds, vert_new);
+
+ MEM_freeN(vert_new);
+ }
+ else {
+ BLI_dynstr_append(ds, vert_code);
+ }
+
code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
@@ -841,65 +1079,141 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
return code;
}
-static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
+static char *code_generate_geometry(ListBase *nodes, const char *geom_code)
{
-#ifdef WITH_OPENSUBDIV
- if (use_opensubdiv) {
- DynStr *ds = BLI_dynstr_new();
- GPUNode *node;
- GPUInput *input;
- char *code;
-
- /* Generate varying declarations. */
- for (node = nodes->first; node; node = node->next) {
- for (input = node->inputs.first; input; input = input->next) {
- if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
- if (input->attribtype == CD_MTFACE) {
- /* NOTE: For now we are using varying on purpose,
- * otherwise we are not able to write to the varying.
- */
- BLI_dynstr_appendf(ds, "%s %s var%d%s;\n",
- "varying",
- GPU_DATATYPE_STR[input->type],
- input->attribid,
- "");
- BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n",
- input->attribid);
- }
- }
+ DynStr *ds = BLI_dynstr_new();
+ GPUNode *node;
+ GPUInput *input;
+ char *code;
+ int builtins = 0;
+
+ /* Create prototype because attributes cannot be declared before layout. */
+ BLI_dynstr_appendf(ds, "void pass_attrib(in int vert);\n");
+ BLI_dynstr_appendf(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2);\n");
+ BLI_dynstr_append(ds, "#define ATTRIB\n");
+
+ /* Generate varying declarations. */
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
+ if (input->source == GPU_SOURCE_BUILTIN) {
+ builtins |= input->builtin;
+ }
+ if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
+ BLI_dynstr_appendf(
+ ds, "in %s var%dg[];\n",
+ GPU_DATATYPE_STR[input->type],
+ input->attribid);
+ BLI_dynstr_appendf(
+ ds, "out %s var%d;\n",
+ GPU_DATATYPE_STR[input->type],
+ input->attribid);
}
}
+ }
- BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl);
+ if (builtins & GPU_BARYCENTRIC_TEXCO) {
+ BLI_dynstr_appendf(ds, "in vec2 barycentricTexCog[];\n");
+ BLI_dynstr_appendf(ds, "out vec2 barycentricTexCo;\n");
+ }
- /* Generate varying assignments. */
- for (node = nodes->first; node; node = node->next) {
- for (input = node->inputs.first; input; input = input->next) {
- if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
- if (input->attribtype == CD_MTFACE) {
- BLI_dynstr_appendf(
- ds,
- "\tINTERP_FACE_VARYING_ATT_2(var%d, "
- "int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n",
- input->attribid,
- input->attribid);
- }
- }
+ if (builtins & GPU_BARYCENTRIC_DIST) {
+ BLI_dynstr_appendf(ds, "in vec3 barycentricPosg[];\n");
+ BLI_dynstr_appendf(ds, "flat out vec3 barycentricDist;\n");
+ }
+
+ if (geom_code == NULL) {
+ if ((builtins & GPU_BARYCENTRIC_DIST) == 0) {
+ /* Early out */
+ BLI_dynstr_free(ds);
+ return NULL;
+ }
+ else {
+ /* Force geom shader usage */
+ /* TODO put in external file. */
+ BLI_dynstr_appendf(ds, "layout(triangles) in;\n");
+ BLI_dynstr_appendf(ds, "layout(triangle_strip, max_vertices=3) out;\n");
+
+ BLI_dynstr_appendf(ds, "in vec3 worldPositiong[];\n");
+ BLI_dynstr_appendf(ds, "in vec3 viewPositiong[];\n");
+ BLI_dynstr_appendf(ds, "in vec3 worldNormalg[];\n");
+ BLI_dynstr_appendf(ds, "in vec3 viewNormalg[];\n");
+
+ BLI_dynstr_appendf(ds, "out vec3 worldPosition;\n");
+ BLI_dynstr_appendf(ds, "out vec3 viewPosition;\n");
+ BLI_dynstr_appendf(ds, "out vec3 worldNormal;\n");
+ BLI_dynstr_appendf(ds, "out vec3 viewNormal;\n");
+
+ BLI_dynstr_appendf(ds, "void main(){\n");
+
+ if (builtins & GPU_BARYCENTRIC_DIST) {
+ BLI_dynstr_appendf(ds, "\tcalc_barycentric_distances(barycentricPosg[0], barycentricPosg[1], barycentricPosg[2]);\n");
}
+
+ BLI_dynstr_appendf(ds, "\tgl_Position = gl_in[0].gl_Position;\n");
+ BLI_dynstr_appendf(ds, "\tpass_attrib(0);\n");
+ BLI_dynstr_appendf(ds, "\tEmitVertex();\n");
+
+ BLI_dynstr_appendf(ds, "\tgl_Position = gl_in[1].gl_Position;\n");
+ BLI_dynstr_appendf(ds, "\tpass_attrib(1);\n");
+ BLI_dynstr_appendf(ds, "\tEmitVertex();\n");
+
+ BLI_dynstr_appendf(ds, "\tgl_Position = gl_in[2].gl_Position;\n");
+ BLI_dynstr_appendf(ds, "\tpass_attrib(2);\n");
+ BLI_dynstr_appendf(ds, "\tEmitVertex();\n");
+ BLI_dynstr_appendf(ds, "};\n");
}
+ }
+ else {
+ BLI_dynstr_append(ds, geom_code);
+ }
+ if (builtins & GPU_BARYCENTRIC_DIST) {
+ BLI_dynstr_appendf(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2) {\n");
+ BLI_dynstr_appendf(ds, "\tvec3 edge21 = pos2 - pos1;\n");
+ BLI_dynstr_appendf(ds, "\tvec3 edge10 = pos1 - pos0;\n");
+ BLI_dynstr_appendf(ds, "\tvec3 edge02 = pos0 - pos2;\n");
+ BLI_dynstr_appendf(ds, "\tvec3 d21 = normalize(edge21);\n");
+ BLI_dynstr_appendf(ds, "\tvec3 d10 = normalize(edge10);\n");
+ BLI_dynstr_appendf(ds, "\tvec3 d02 = normalize(edge02);\n");
+
+ BLI_dynstr_appendf(ds, "\tfloat d = dot(d21, edge02);\n");
+ BLI_dynstr_appendf(ds, "\tbarycentricDist.x = sqrt(dot(edge02, edge02) - d * d);\n");
+ BLI_dynstr_appendf(ds, "\td = dot(d02, edge10);\n");
+ BLI_dynstr_appendf(ds, "\tbarycentricDist.y = sqrt(dot(edge10, edge10) - d * d);\n");
+ BLI_dynstr_appendf(ds, "\td = dot(d10, edge21);\n");
+ BLI_dynstr_appendf(ds, "\tbarycentricDist.z = sqrt(dot(edge21, edge21) - d * d);\n");
BLI_dynstr_append(ds, "}\n");
- code = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
+ }
- //if (G.debug & G_DEBUG) printf("%s\n", code);
+ /* Generate varying assignments. */
+ BLI_dynstr_appendf(ds, "void pass_attrib(in int vert) {\n");
- return code;
+ /* XXX HACK: Eevee specific. */
+ if (geom_code == NULL) {
+ BLI_dynstr_appendf(ds, "\tworldPosition = worldPositiong[vert];\n");
+ BLI_dynstr_appendf(ds, "\tviewPosition = viewPositiong[vert];\n");
+ BLI_dynstr_appendf(ds, "\tworldNormal = worldNormalg[vert];\n");
+ BLI_dynstr_appendf(ds, "\tviewNormal = viewNormalg[vert];\n");
}
-#else
- UNUSED_VARS(nodes, use_opensubdiv);
-#endif
- return NULL;
+
+ if (builtins & GPU_BARYCENTRIC_TEXCO) {
+ BLI_dynstr_appendf(ds, "\tbarycentricTexCo = barycentricTexCog[vert];\n");
+ }
+
+ for (node = nodes->first; node; node = node->next) {
+ for (input = node->inputs.first; input; input = input->next) {
+ if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
+ /* TODO let shader choose what to do depending on what the attrib is. */
+ BLI_dynstr_appendf(ds, "\tvar%d = var%dg[vert];\n", input->attribid, input->attribid);
+ }
+ }
+ }
+ BLI_dynstr_append(ds, "}\n");
+
+ code = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return code;
}
void GPU_code_generate_glsl_lib(void)
@@ -923,20 +1237,17 @@ void GPU_code_generate_glsl_lib(void)
/* GPU pass binding/unbinding */
-GPUShader *GPU_pass_shader(GPUPass *pass)
+GPUShader *GPU_pass_shader_get(GPUPass *pass)
{
return pass->shader;
}
-static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
+void GPU_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs, ListBase *nodes)
{
- GPUShader *shader = pass->shader;
GPUNode *node;
GPUInput *next, *input;
- ListBase *inputs = &pass->inputs;
- int extract, z;
- memset(inputs, 0, sizeof(*inputs));
+ BLI_listbase_clear(inputs);
if (!shader)
return;
@@ -944,146 +1255,33 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
GPU_shader_bind(shader);
for (node = nodes->first; node; node = node->next) {
- z = 0;
+ int z = 0;
for (input = node->inputs.first; input; input = next, z++) {
next = input->next;
/* attributes don't need to be bound, they already have
- * an id that the drawing functions will use */
- if (input->source == GPU_SOURCE_ATTRIB) {
-#ifdef WITH_OPENSUBDIV
- /* We do need mtface attributes for later, so we can
- * update face-varuing variables offset in the texture
- * buffer for proper sampling from the shader.
- *
- * We don't do anything about attribute itself, we
- * only use it to learn which uniform name is to be
- * updated.
- *
- * TODO(sergey): We can add ad extra uniform input
- * for the offset, which will be purely internal and
- * which would avoid having such an exceptions.
- */
- if (input->attribtype != CD_MTFACE) {
- continue;
- }
-#else
- continue;
-#endif
- }
- if (input->source == GPU_SOURCE_BUILTIN ||
- input->source == GPU_SOURCE_OPENGL_BUILTIN)
- {
+ * an id that the drawing functions will use. Builtins have
+ * constant names. */
+ if (ELEM(input->source, GPU_SOURCE_ATTRIB, GPU_SOURCE_BUILTIN)) {
continue;
}
- if (input->ima || input->tex || input->prv)
+ if (input->source == GPU_SOURCE_TEX)
BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid);
- else
+ else {
BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id);
-
- /* pass non-dynamic uniforms to opengl */
- extract = 0;
-
- if (input->ima || input->tex || input->prv) {
- if (input->bindtex)
- extract = 1;
- }
- else if (input->dynamicvec)
- extract = 1;
-
- if (extract)
- input->shaderloc = GPU_shader_get_uniform(shader, input->shadername);
-
-#ifdef WITH_OPENSUBDIV
- if (input->source == GPU_SOURCE_ATTRIB &&
- input->attribtype == CD_MTFACE)
- {
- extract = 1;
- }
-#endif
-
- /* extract nodes */
- if (extract) {
- BLI_remlink(&node->inputs, input);
- BLI_addtail(inputs, input);
}
- }
- }
- GPU_shader_unbind();
-}
-
-void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
-{
- GPUInput *input;
- GPUShader *shader = pass->shader;
- ListBase *inputs = &pass->inputs;
-
- if (!shader)
- return;
-
- GPU_shader_bind(shader);
-
- /* create the textures */
- for (input = inputs->first; input; input = input->next) {
- if (input->ima)
- input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->textarget, input->image_isdata, time, mipmap);
- else if (input->prv)
- input->tex = GPU_texture_from_preview(input->prv, mipmap);
- }
-
- /* bind the textures, in second loop so texture binding during
- * create doesn't overwrite already bound textures */
- for (input = inputs->first; input; input = input->next) {
- if (input->tex && input->bindtex) {
- GPU_texture_bind(input->tex, input->texid);
- GPU_shader_uniform_texture(shader, input->shaderloc, input->tex);
- }
- }
-}
-
-void GPU_pass_update_uniforms(GPUPass *pass)
-{
- GPUInput *input;
- GPUShader *shader = pass->shader;
- ListBase *inputs = &pass->inputs;
-
- if (!shader)
- return;
-
- /* pass dynamic inputs to opengl, others were removed */
- for (input = inputs->first; input; input = input->next) {
- if (!(input->ima || input->tex || input->prv)) {
- if (input->dynamictype == GPU_DYNAMIC_MAT_HARD) {
- // The hardness is actually a short pointer, so we convert it here
- float val = (float)(*(short *)input->dynamicvec);
- GPU_shader_uniform_vector(shader, input->shaderloc, 1, 1, &val);
- }
- else {
- GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1,
- input->dynamicvec);
+ if (input->source == GPU_SOURCE_TEX) {
+ if (input->bindtex) {
+ input->shaderloc = GPU_shader_get_uniform(shader, input->shadername);
+ /* extract nodes */
+ BLI_remlink(&node->inputs, input);
+ BLI_addtail(inputs, input);
+ }
}
}
}
-}
-
-void GPU_pass_unbind(GPUPass *pass)
-{
- GPUInput *input;
- GPUShader *shader = pass->shader;
- ListBase *inputs = &pass->inputs;
-
- if (!shader)
- return;
-
- for (input = inputs->first; input; input = input->next) {
- if (input->tex && input->bindtex)
- GPU_texture_unbind(input->tex);
-
- if (input->ima || input->prv)
- input->tex = NULL;
- }
GPU_shader_unbind();
}
@@ -1093,7 +1291,6 @@ void GPU_pass_unbind(GPUPass *pass)
static GPUNodeLink *GPU_node_link_create(void)
{
GPUNodeLink *link = MEM_callocN(sizeof(GPUNodeLink), "GPUNodeLink");
- link->type = GPU_NONE;
link->users++;
return link;
@@ -1130,16 +1327,15 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
GPUNode *outnode;
const char *name;
- if (link->output) {
+ if (link->link_type == GPU_NODE_LINK_OUTPUT) {
outnode = link->output->node;
name = outnode->name;
input = outnode->inputs.first;
- if ((STREQ(name, "set_value") || STREQ(name, "set_rgb")) &&
+ if ((STREQ(name, "set_value") || STREQ(name, "set_rgb") || STREQ(name, "set_rgba")) &&
(input->type == type))
{
input = MEM_dupallocN(outnode->inputs.first);
- input->type = type;
if (input->link)
input->link->users++;
BLI_addtail(&node->inputs, input);
@@ -1149,120 +1345,132 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
input = MEM_callocN(sizeof(GPUInput), "GPUInput");
input->node = node;
+ input->type = type;
- if (link->builtin) {
- /* builtin uniform */
- input->type = type;
- input->source = GPU_SOURCE_BUILTIN;
- input->builtin = link->builtin;
-
- MEM_freeN(link);
+ switch (link->link_type) {
+ case GPU_NODE_LINK_BUILTIN:
+ input->source = GPU_SOURCE_BUILTIN;
+ input->builtin = link->builtin;
+ break;
+ case GPU_NODE_LINK_OUTPUT:
+ input->source = GPU_SOURCE_OUTPUT;
+ input->link = link;
+ link->users++;
+ break;
+ case GPU_NODE_LINK_COLORBAND:
+ input->source = GPU_SOURCE_TEX;
+ input->coba = link->coba;
+ break;
+ case GPU_NODE_LINK_IMAGE_BLENDER:
+ input->source = GPU_SOURCE_TEX;
+ input->ima = link->ima;
+ input->iuser = link->iuser;
+ input->image_isdata = link->image_isdata;
+ break;
+ case GPU_NODE_LINK_ATTRIB:
+ input->source = GPU_SOURCE_ATTRIB;
+ input->attribtype = link->attribtype;
+ BLI_strncpy(input->attribname, link->attribname, sizeof(input->attribname));
+ break;
+ case GPU_NODE_LINK_CONSTANT:
+ input->source = (type == GPU_CLOSURE) ? GPU_SOURCE_STRUCT : GPU_SOURCE_CONSTANT;
+ break;
+ case GPU_NODE_LINK_UNIFORM:
+ input->source = GPU_SOURCE_UNIFORM;
+ break;
+ default:
+ break;
}
- else if (link->oglbuiltin) {
- /* builtin uniform */
- input->type = type;
- input->source = GPU_SOURCE_OPENGL_BUILTIN;
- input->oglbuiltin = link->oglbuiltin;
- MEM_freeN(link);
+ if (ELEM(input->source, GPU_SOURCE_CONSTANT, GPU_SOURCE_UNIFORM)) {
+ memcpy(input->vec, link->data, type * sizeof(float));
}
- else if (link->output) {
- /* link to a node output */
- input->type = type;
- input->source = GPU_SOURCE_TEX_PIXEL;
- input->link = link;
- link->users++;
- }
- else if (link->dynamictex) {
- /* dynamic texture, GPUTexture is updated/deleted externally */
- input->type = type;
- input->source = GPU_SOURCE_TEX;
-
- input->tex = link->dynamictex;
- input->textarget = GL_TEXTURE_2D;
- input->textype = type;
- input->dynamictex = true;
- input->dynamicdata = link->ptr2;
+
+ if (link->link_type != GPU_NODE_LINK_OUTPUT) {
MEM_freeN(link);
}
- else if (link->texture) {
- /* small texture created on the fly, like for colorbands */
- input->type = GPU_VEC4;
- input->source = GPU_SOURCE_TEX;
- input->textype = type;
+ BLI_addtail(&node->inputs, input);
+}
-#if 0
- input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
-#endif
- input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL);
- input->textarget = GL_TEXTURE_2D;
- MEM_freeN(link->ptr1);
- MEM_freeN(link);
+static const char *gpu_uniform_set_function_from_type(eNodeSocketDatatype type)
+{
+ switch (type) {
+ case SOCK_FLOAT:
+ return "set_value";
+ case SOCK_VECTOR:
+ return "set_rgb";
+ case SOCK_RGBA:
+ return "set_rgba";
+ default:
+ BLI_assert(!"No gpu function for non-supported eNodeSocketDatatype");
+ return NULL;
}
- else if (link->image) {
- /* blender image */
- input->type = GPU_VEC4;
- input->source = GPU_SOURCE_TEX;
+}
- if (link->image == GPU_NODE_LINK_IMAGE_PREVIEW) {
- input->prv = link->ptr1;
- input->textarget = GL_TEXTURE_2D;
- input->textype = GPU_TEX2D;
- }
- else if (link->image == GPU_NODE_LINK_IMAGE_BLENDER) {
- input->ima = link->ptr1;
- input->iuser = link->ptr2;
- input->image_isdata = link->image_isdata;
- input->textarget = GL_TEXTURE_2D;
- input->textype = GPU_TEX2D;
- }
- else if (link->image == GPU_NODE_LINK_IMAGE_CUBE_MAP) {
- input->ima = link->ptr1;
- input->iuser = link->ptr2;
- input->image_isdata = link->image_isdata;
- input->textarget = GL_TEXTURE_CUBE_MAP;
- input->textype = GPU_TEXCUBE;
- }
- MEM_freeN(link);
- }
- else if (link->attribtype) {
- /* vertex attribute */
- input->type = type;
- input->source = GPU_SOURCE_ATTRIB;
+/**
+ * Link stack uniform buffer.
+ * This is called for the input/output sockets that are note connected.
+ */
+static GPUNodeLink *gpu_uniformbuffer_link(
+ GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index, const eNodeSocketInOut in_out)
+{
+ bNodeSocket *socket;
- input->attribtype = link->attribtype;
- BLI_strncpy(input->attribname, link->attribname, sizeof(input->attribname));
- MEM_freeN(link);
+ if (in_out == SOCK_IN) {
+ socket = BLI_findlink(&node->inputs, index);
}
else {
- /* uniform vector */
- input->type = type;
- input->source = GPU_SOURCE_VEC_UNIFORM;
-
- memcpy(input->vec, link->ptr1, type * sizeof(float));
- if (link->dynamic) {
- input->dynamicvec = link->ptr1;
- input->dynamictype = link->dynamictype;
- input->dynamicdata = link->ptr2;
- }
- MEM_freeN(link);
+ socket = BLI_findlink(&node->outputs, index);
}
- BLI_addtail(&node->inputs, input);
+ BLI_assert(socket != NULL);
+ BLI_assert(socket->in_out == in_out);
+
+ if ((socket->flag & SOCK_HIDE_VALUE) == 0) {
+ GPUNodeLink *link;
+ switch (socket->type) {
+ case SOCK_FLOAT:
+ {
+ bNodeSocketValueFloat *socket_data = socket->default_value;
+ link = GPU_uniform(&socket_data->value);
+ break;
+ }
+ case SOCK_VECTOR:
+ {
+ bNodeSocketValueVector *socket_data = socket->default_value;
+ link = GPU_uniform(socket_data->value);
+ break;
+ }
+ case SOCK_RGBA:
+ {
+ bNodeSocketValueRGBA *socket_data = socket->default_value;
+ link = GPU_uniform(socket_data->value);
+ break;
+ }
+ default:
+ return NULL;
+ break;
+ }
+
+ if (in_out == SOCK_IN) {
+ GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link);
+ }
+ return link;
+ }
+ return NULL;
}
-static void gpu_node_input_socket(GPUNode *node, GPUNodeStack *sock)
+static void gpu_node_input_socket(GPUMaterial *material, bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index)
{
- GPUNodeLink *link;
-
if (sock->link) {
gpu_node_input_link(node, sock->link, sock->type);
}
+ else if ((material != NULL) && (gpu_uniformbuffer_link(material, bnode, sock, index, SOCK_IN) != NULL)) {
+ gpu_node_input_link(node, sock->link, sock->type);
+ }
else {
- link = GPU_node_link_create();
- link->ptr1 = sock->vec;
- gpu_node_input_link(node, link, sock->type);
+ gpu_node_input_link(node, GPU_constant(sock->vec), sock->type);
}
}
@@ -1275,7 +1483,7 @@ static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **lin
if (link) {
*link = output->link = GPU_node_link_create();
- output->link->type = type;
+ output->link->link_type = GPU_NODE_LINK_OUTPUT;
output->link->output = output;
/* note: the caller owns the reference to the link, GPUOutput
@@ -1286,15 +1494,13 @@ static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **lin
BLI_addtail(&node->outputs, output);
}
-static void gpu_inputs_free(ListBase *inputs)
+void GPU_inputs_free(ListBase *inputs)
{
GPUInput *input;
for (input = inputs->first; input; input = input->next) {
if (input->link)
gpu_node_link_free(input->link);
- else if (input->tex && !input->dynamictex)
- GPU_texture_free(input->tex);
}
BLI_freelistN(inputs);
@@ -1304,7 +1510,7 @@ static void gpu_node_free(GPUNode *node)
{
GPUOutput *output;
- gpu_inputs_free(&node->inputs);
+ GPU_inputs_free(&node->inputs);
for (output = node->outputs.first; output; output = output->next)
if (output->link) {
@@ -1327,7 +1533,7 @@ static void gpu_nodes_free(ListBase *nodes)
/* vertex attributes */
-static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs)
+void GPU_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs)
{
GPUNode *node;
GPUInput *input;
@@ -1352,12 +1558,13 @@ static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *a
if (a < GPU_MAX_ATTRIB) {
if (a == attribs->totlayer) {
input->attribid = attribs->totlayer++;
- input->attribfirst = 1;
+ input->attribfirst = true;
attribs->layer[a].type = input->attribtype;
attribs->layer[a].attribid = input->attribid;
- BLI_strncpy(attribs->layer[a].name, input->attribname,
- sizeof(attribs->layer[a].name));
+ BLI_strncpy(
+ attribs->layer[a].name, input->attribname,
+ sizeof(attribs->layer[a].name));
}
else {
input->attribid = attribs->layer[a].attribid;
@@ -1368,127 +1575,63 @@ static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *a
}
}
-static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin)
-{
- GPUNode *node;
- GPUInput *input;
-
- *builtin = 0;
-
- for (node = nodes->first; node; node = node->next)
- for (input = node->inputs.first; input; input = input->next)
- if (input->source == GPU_SOURCE_BUILTIN)
- *builtin |= input->builtin;
-}
-
/* varargs linking */
GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name)
{
GPUNodeLink *link = GPU_node_link_create();
-
- link->attribtype = type;
+ link->link_type = GPU_NODE_LINK_ATTRIB;
link->attribname = name;
-
+ /* Fall back to the UV layer, which matches old behavior. */
+ if (type == CD_AUTO_FROM_NAME && name[0] == '\0') {
+ link->attribtype = CD_MTFACE;
+ }
+ else {
+ link->attribtype = type;
+ }
return link;
}
-GPUNodeLink *GPU_uniform(float *num)
+GPUNodeLink *GPU_constant(float *num)
{
GPUNodeLink *link = GPU_node_link_create();
-
- link->ptr1 = num;
- link->ptr2 = NULL;
-
+ link->link_type = GPU_NODE_LINK_CONSTANT;
+ link->data = num;
return link;
}
-GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data)
+GPUNodeLink *GPU_uniform(float *num)
{
GPUNodeLink *link = GPU_node_link_create();
-
- link->ptr1 = num;
- link->ptr2 = data;
- link->dynamic = true;
- link->dynamictype = dynamictype;
-
-
+ link->link_type = GPU_NODE_LINK_UNIFORM;
+ link->data = num;
return link;
}
GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data)
{
GPUNodeLink *link = GPU_node_link_create();
-
- link->image = GPU_NODE_LINK_IMAGE_BLENDER;
- link->ptr1 = ima;
- link->ptr2 = iuser;
+ link->link_type = GPU_NODE_LINK_IMAGE_BLENDER;
+ link->ima = ima;
+ link->iuser = iuser;
link->image_isdata = is_data;
-
- return link;
-}
-
-GPUNodeLink *GPU_cube_map(Image *ima, ImageUser *iuser, bool is_data)
-{
- GPUNodeLink *link = GPU_node_link_create();
-
- link->image = GPU_NODE_LINK_IMAGE_CUBE_MAP;
- link->ptr1 = ima;
- link->ptr2 = iuser;
- link->image_isdata = is_data;
-
- return link;
-}
-
-GPUNodeLink *GPU_image_preview(PreviewImage *prv)
-{
- GPUNodeLink *link = GPU_node_link_create();
-
- link->image = GPU_NODE_LINK_IMAGE_PREVIEW;
- link->ptr1 = prv;
-
- return link;
-}
-
-
-GPUNodeLink *GPU_texture(int size, float *pixels)
-{
- GPUNodeLink *link = GPU_node_link_create();
-
- link->texture = true;
- link->texturesize = size;
- link->ptr1 = pixels;
-
return link;
}
-GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, GPUDynamicType dynamictype, void *data)
+GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *row)
{
GPUNodeLink *link = GPU_node_link_create();
-
- link->dynamic = true;
- link->dynamictex = tex;
- link->dynamictype = dynamictype;
- link->ptr2 = data;
-
+ link->link_type = GPU_NODE_LINK_COLORBAND;
+ link->coba = gpu_material_ramp_texture_row_set(mat, size, pixels, row);
+ MEM_freeN(pixels);
return link;
}
GPUNodeLink *GPU_builtin(GPUBuiltin builtin)
{
GPUNodeLink *link = GPU_node_link_create();
-
+ link->link_type = GPU_NODE_LINK_BUILTIN;
link->builtin = builtin;
-
- return link;
-}
-
-GPUNodeLink *GPU_opengl_builtin(GPUOpenGLBuiltin builtin)
-{
- GPUNodeLink *link = GPU_node_link_create();
-
- link->oglbuiltin = builtin;
-
return link;
}
@@ -1526,7 +1669,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
return true;
}
-bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...)
+bool GPU_stack_link(GPUMaterial *material, bNode *bnode, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...)
{
GPUNode *node;
GPUFunction *function;
@@ -1545,16 +1688,20 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
totout = 0;
if (in) {
- for (i = 0; in[i].type != GPU_NONE; i++) {
- gpu_node_input_socket(node, &in[i]);
- totin++;
+ for (i = 0; !in[i].end; i++) {
+ if (in[i].type != GPU_NONE) {
+ gpu_node_input_socket(material, bnode, node, &in[i], i);
+ totin++;
+ }
}
}
if (out) {
- for (i = 0; out[i].type != GPU_NONE; i++) {
- gpu_node_output(node, out[i].type, &out[i].link);
- totout++;
+ for (i = 0; !out[i].end; i++) {
+ if (out[i].type != GPU_NONE) {
+ gpu_node_output(node, out[i].type, &out[i].link);
+ totout++;
+ }
}
}
@@ -1572,7 +1719,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
if (totin == 0) {
link = va_arg(params, GPUNodeLink *);
if (link->socket)
- gpu_node_input_socket(node, link->socket);
+ gpu_node_input_socket(NULL, NULL, node, link->socket, -1);
else
gpu_node_input_link(node, link, function->paramtype[i]);
}
@@ -1582,30 +1729,14 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
}
va_end(params);
- gpu_material_add_node(mat, node);
+ gpu_material_add_node(material, node);
return true;
}
-int GPU_link_changed(GPUNodeLink *link)
+GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index)
{
- GPUNode *node;
- GPUInput *input;
- const char *name;
-
- if (link->output) {
- node = link->output->node;
- name = node->name;
-
- if (STREQ(name, "set_value") || STREQ(name, "set_rgb")) {
- input = node->inputs.first;
- return (input->link != NULL);
- }
-
- return 1;
- }
- else
- return 0;
+ return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT);
}
/* Pass create/free */
@@ -1628,7 +1759,7 @@ static void gpu_nodes_tag(GPUNodeLink *link)
gpu_nodes_tag(input->link);
}
-static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
+void GPU_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
{
GPUNode *node, *next;
@@ -1647,91 +1778,228 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
}
}
+static bool gpu_pass_is_valid(GPUPass *pass)
+{
+ /* Shader is not null if compilation is successful. */
+ return (pass->compiled == false || pass->shader != NULL);
+}
+
GPUPass *GPU_generate_pass(
- ListBase *nodes, GPUNodeLink *outlink,
- GPUVertexAttribs *attribs, int *builtins,
- const GPUMatType type, const char *UNUSED(name),
- const bool use_opensubdiv,
- const bool use_new_shading)
+ GPUMaterial *material,
+ GPUNodeLink *frag_outlink,
+ struct GPUVertexAttribs *attribs,
+ ListBase *nodes,
+ int *builtins,
+ const char *vert_code,
+ const char *geom_code,
+ const char *frag_lib,
+ const char *defines)
{
- GPUShader *shader;
- GPUPass *pass;
char *vertexcode, *geometrycode, *fragmentcode;
+ GPUPass *pass = NULL, *pass_hash = NULL;
-#if 0
- if (!FUNCTION_LIB) {
- GPU_nodes_free(nodes);
- return NULL;
+ /* prune unused nodes */
+ GPU_nodes_prune(nodes, frag_outlink);
+
+ GPU_nodes_get_vertex_attributes(nodes, attribs);
+
+ /* generate code */
+ char *fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, builtins);
+
+ /* Cache lookup: Reuse shaders already compiled */
+ uint32_t hash = gpu_pass_hash(fragmentgen, defines, attribs);
+ pass_hash = gpu_pass_cache_lookup(hash);
+
+ if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) {
+ /* No collision, just return the pass. */
+ MEM_freeN(fragmentgen);
+ if (!gpu_pass_is_valid(pass_hash)) {
+ /* Shader has already been created but failed to compile. */
+ return NULL;
+ }
+ pass_hash->refcount += 1;
+ return pass_hash;
}
-#endif
- /* prune unused nodes */
- gpu_nodes_prune(nodes, outlink);
-
- gpu_nodes_get_vertex_attributes(nodes, attribs);
- gpu_nodes_get_builtin_flag(nodes, builtins);
-
- /* generate code and compile with opengl */
- fragmentcode = code_generate_fragment(nodes, outlink->output);
- vertexcode = code_generate_vertex(nodes, type);
- geometrycode = code_generate_geometry(nodes, use_opensubdiv);
-
- int flags = GPU_SHADER_FLAGS_NONE;
- if (use_opensubdiv) {
- flags |= GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV;
- }
- if (use_new_shading) {
- flags |= GPU_SHADER_FLAGS_NEW_SHADING;
- }
- shader = GPU_shader_create_ex(vertexcode,
- fragmentcode,
- geometrycode,
- glsl_material_library,
- NULL,
- 0,
- 0,
- 0,
- flags);
-
- /* failed? */
- if (!shader) {
- if (fragmentcode)
- MEM_freeN(fragmentcode);
- if (vertexcode)
- MEM_freeN(vertexcode);
- memset(attribs, 0, sizeof(*attribs));
- memset(builtins, 0, sizeof(*builtins));
- gpu_nodes_free(nodes);
- return NULL;
- }
-
- /* create pass */
- pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
-
- pass->output = outlink->output;
- pass->shader = shader;
- pass->fragmentcode = fragmentcode;
- pass->geometrycode = geometrycode;
- pass->vertexcode = vertexcode;
- pass->libcode = glsl_material_library;
-
- /* extract dynamic inputs and throw away nodes */
- gpu_nodes_extract_dynamic_inputs(pass, nodes);
- gpu_nodes_free(nodes);
+ /* Either the shader is not compiled or there is a hash collision...
+ * continue generating the shader strings. */
+ char *tmp = BLI_strdupcat(frag_lib, glsl_material_library);
+
+ geometrycode = code_generate_geometry(nodes, geom_code);
+ vertexcode = code_generate_vertex(nodes, vert_code, (geometrycode != NULL));
+ fragmentcode = BLI_strdupcat(tmp, fragmentgen);
+
+ MEM_freeN(fragmentgen);
+ MEM_freeN(tmp);
+
+ if (pass_hash) {
+ /* Cache lookup: Reuse shaders already compiled */
+ pass = gpu_pass_cache_resolve_collision(pass_hash, vertexcode, geometrycode, fragmentcode, defines, hash);
+ }
+
+ if (pass) {
+ /* Cache hit. Reuse the same GPUPass and GPUShader. */
+ if (!gpu_pass_is_valid(pass)) {
+ /* Shader has already been created but failed to compile. */
+ return NULL;
+ }
+
+ MEM_SAFE_FREE(vertexcode);
+ MEM_SAFE_FREE(fragmentcode);
+ MEM_SAFE_FREE(geometrycode);
+
+ pass->refcount += 1;
+ }
+ else {
+ /* We still create a pass even if shader compilation
+ * fails to avoid trying to compile again and again. */
+ pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
+ pass->shader = NULL;
+ pass->refcount = 1;
+ pass->hash = hash;
+ pass->vertexcode = vertexcode;
+ pass->fragmentcode = fragmentcode;
+ pass->geometrycode = geometrycode;
+ pass->defines = (defines) ? BLI_strdup(defines) : NULL;
+ pass->compiled = false;
+
+ BLI_spin_lock(&pass_cache_spin);
+ if (pass_hash != NULL) {
+ /* Add after the first pass having the same hash. */
+ pass->next = pass_hash->next;
+ pass_hash->next = pass;
+ }
+ else {
+ /* No other pass have same hash, just prepend to the list. */
+ BLI_LINKS_PREPEND(pass_cache, pass);
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+ }
return pass;
}
-void GPU_pass_free(GPUPass *pass)
+static int count_active_texture_sampler(GPUShader *shader, char *source)
+{
+ char *code = source;
+ int samplers_id[64]; /* Remember this is per stage. */
+ int sampler_len = 0;
+
+ while ((code = strstr(code, "uniform "))) {
+ /* Move past "uniform". */
+ code += 7;
+ /* Skip following spaces. */
+ while (*code == ' ') { code++; }
+ /* Skip "i" from potential isamplers. */
+ if (*code == 'i') { code++; }
+ /* Skip following spaces. */
+ if (gpu_str_prefix(code, "sampler")) {
+ /* Move past "uniform". */
+ code += 7;
+ /* Skip sampler type suffix. */
+ while (*code != ' ' && *code != '\0') { code++; }
+ /* Skip following spaces. */
+ while (*code == ' ') { code++; }
+
+ if (*code != '\0') {
+ char sampler_name[64];
+ code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name));
+ int id = GPU_shader_get_uniform(shader, sampler_name);
+
+ if (id == -1) {
+ continue;
+ }
+ /* Catch duplicates. */
+ bool is_duplicate = false;
+ for (int i = 0; i < sampler_len; ++i) {
+ if (samplers_id[i] == id) {
+ is_duplicate = true;
+ }
+ }
+
+ if (!is_duplicate) {
+ samplers_id[sampler_len] = id;
+ sampler_len++;
+ }
+ }
+ }
+ }
+
+ return sampler_len;
+}
+
+static bool gpu_pass_shader_validate(GPUPass *pass)
+{
+ if (pass->shader == NULL) {
+ return false;
+ }
+
+ /* NOTE: The only drawback of this method is that it will count a sampler
+ * used in the fragment shader and only declared (but not used) in the vertex
+ * shader as used by both. But this corner case is not happening for now. */
+ int vert_samplers_len = count_active_texture_sampler(pass->shader, pass->vertexcode);
+ int frag_samplers_len = count_active_texture_sampler(pass->shader, pass->fragmentcode);
+
+ int total_samplers_len = vert_samplers_len + frag_samplers_len;
+
+ /* Validate against opengl limit. */
+ if ((frag_samplers_len > GPU_max_textures_frag()) ||
+ (frag_samplers_len > GPU_max_textures_vert()))
+ {
+ return false;
+ }
+
+ if (pass->geometrycode) {
+ int geom_samplers_len = count_active_texture_sampler(pass->shader, pass->geometrycode);
+ total_samplers_len += geom_samplers_len;
+ if (geom_samplers_len > GPU_max_textures_geom()) {
+ return false;
+ }
+ }
+
+ return (total_samplers_len <= GPU_max_textures());
+}
+
+void GPU_pass_compile(GPUPass *pass, const char *shname)
+{
+ if (!pass->compiled) {
+ pass->shader = GPU_shader_create(
+ pass->vertexcode,
+ pass->fragmentcode,
+ pass->geometrycode,
+ NULL,
+ pass->defines,
+ shname);
+
+ /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit.
+ * We need to make sure to count active samplers to avoid undefined behaviour. */
+ if (!gpu_pass_shader_validate(pass)) {
+ if (pass->shader != NULL) {
+ fprintf(stderr, "GPUShader: error: too many samplers in shader.\n");
+ GPU_shader_free(pass->shader);
+ }
+ pass->shader = NULL;
+ }
+ pass->compiled = true;
+ }
+}
+
+void GPU_pass_release(GPUPass *pass)
{
- GPU_shader_free(pass->shader);
- gpu_inputs_free(&pass->inputs);
- if (pass->fragmentcode)
- MEM_freeN(pass->fragmentcode);
- if (pass->geometrycode)
- MEM_freeN(pass->geometrycode);
- if (pass->vertexcode)
- MEM_freeN(pass->vertexcode);
+ BLI_assert(pass->refcount > 0);
+ pass->refcount--;
+}
+
+static void gpu_pass_free(GPUPass *pass)
+{
+ BLI_assert(pass->refcount == 0);
+ if (pass->shader) {
+ GPU_shader_free(pass->shader);
+ }
+ MEM_SAFE_FREE(pass->fragmentcode);
+ MEM_SAFE_FREE(pass->geometrycode);
+ MEM_SAFE_FREE(pass->vertexcode);
+ MEM_SAFE_FREE(pass->defines);
MEM_freeN(pass);
}
@@ -1739,3 +2007,48 @@ void GPU_pass_free_nodes(ListBase *nodes)
{
gpu_nodes_free(nodes);
}
+
+void GPU_pass_cache_garbage_collect(void)
+{
+ static int lasttime = 0;
+ const int shadercollectrate = 60; /* hardcoded for now. */
+ int ctime = (int)PIL_check_seconds_timer();
+
+ if (ctime < shadercollectrate + lasttime)
+ return;
+
+ lasttime = ctime;
+
+ BLI_spin_lock(&pass_cache_spin);
+ GPUPass *next, **prev_pass = &pass_cache;
+ for (GPUPass *pass = pass_cache; pass; pass = next) {
+ next = pass->next;
+ if (pass->refcount == 0) {
+ /* Remove from list */
+ *prev_pass = next;
+ gpu_pass_free(pass);
+ }
+ else {
+ prev_pass = &pass->next;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+}
+
+void GPU_pass_cache_init(void)
+{
+ BLI_spin_init(&pass_cache_spin);
+}
+
+void GPU_pass_cache_free(void)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ while (pass_cache) {
+ GPUPass *next = pass_cache->next;
+ gpu_pass_free(pass_cache);
+ pass_cache = next;
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+
+ BLI_spin_end(&pass_cache_spin);
+}
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index ec2ff7615d5..82ee559b01f 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -52,20 +52,25 @@ struct PreviewImage;
*/
typedef enum GPUDataSource {
- GPU_SOURCE_VEC_UNIFORM,
+ GPU_SOURCE_OUTPUT,
+ GPU_SOURCE_CONSTANT,
+ GPU_SOURCE_UNIFORM,
+ GPU_SOURCE_ATTRIB,
GPU_SOURCE_BUILTIN,
- GPU_SOURCE_OPENGL_BUILTIN,
- GPU_SOURCE_TEX_PIXEL,
+ GPU_SOURCE_STRUCT,
GPU_SOURCE_TEX,
- GPU_SOURCE_ATTRIB
} GPUDataSource;
typedef enum {
- GPU_NODE_LINK_IMAGE_NONE = 0,
- GPU_NODE_LINK_IMAGE_BLENDER = 1,
- GPU_NODE_LINK_IMAGE_PREVIEW = 2,
- GPU_NODE_LINK_IMAGE_CUBE_MAP = 3
-} GPUNodeLinkImage;
+ GPU_NODE_LINK_NONE = 0,
+ GPU_NODE_LINK_ATTRIB,
+ GPU_NODE_LINK_BUILTIN,
+ GPU_NODE_LINK_COLORBAND,
+ GPU_NODE_LINK_CONSTANT,
+ GPU_NODE_LINK_IMAGE_BLENDER,
+ GPU_NODE_LINK_OUTPUT,
+ GPU_NODE_LINK_UNIFORM,
+} GPUNodeLinkType;
struct GPUNode {
struct GPUNode *next, *prev;
@@ -82,31 +87,30 @@ struct GPUNode {
struct GPUNodeLink {
GPUNodeStack *socket;
- CustomDataType attribtype;
- const char *attribname;
-
- GPUNodeLinkImage image;
- bool image_isdata;
-
- bool texture;
- int texturesize;
-
- void *ptr1, *ptr2;
-
- bool dynamic;
- GPUDynamicType dynamictype;
-
- GPUType type;
-
- /* Refcount */
- int users;
-
- struct GPUTexture *dynamictex;
-
- GPUBuiltin builtin;
- GPUOpenGLBuiltin oglbuiltin;
-
- struct GPUOutput *output;
+ GPUNodeLinkType link_type;
+ int users; /* Refcount */
+
+ union {
+ /* GPU_NODE_LINK_CONSTANT | GPU_NODE_LINK_UNIFORM */
+ float *data;
+ /* GPU_NODE_LINK_BUILTIN */
+ GPUBuiltin builtin;
+ /* GPU_NODE_LINK_COLORBAND */
+ struct GPUTexture **coba;
+ /* GPU_NODE_LINK_OUTPUT */
+ struct GPUOutput *output;
+ /* GPU_NODE_LINK_ATTRIB */
+ struct {
+ const char *attribname;
+ CustomDataType attribtype;
+ };
+ /* GPU_NODE_LINK_IMAGE_BLENDER */
+ struct {
+ struct Image *ima;
+ struct ImageUser *iuser;
+ bool image_isdata;
+ };
+ };
};
typedef struct GPUOutput {
@@ -122,69 +126,75 @@ typedef struct GPUInput {
struct GPUInput *next, *prev;
GPUNode *node;
-
GPUType type; /* datatype */
+ GPUNodeLink *link;
+ int id; /* unique id as created by code generator */
+
GPUDataSource source; /* data source */
- int id; /* unique id as created by code generator */
- int texid; /* number for multitexture, starting from zero */
- int attribid; /* id for vertex attributes */
- bool bindtex; /* input is responsible for binding the texture? */
- bool definetex; /* input is responsible for defining the pixel? */
- int textarget; /* GL texture target, e.g. GL_TEXTURE_2D */
- GPUType textype; /* datatype */
-
- struct Image *ima; /* image */
- struct ImageUser *iuser; /* image user */
- struct PreviewImage *prv; /* preview images & icons */
- bool image_isdata; /* image does not contain color data */
- float *dynamicvec; /* vector data in case it is dynamic */
- GPUDynamicType dynamictype; /* origin of the dynamic uniform */
- void *dynamicdata; /* data source of the dynamic uniform */
- struct GPUTexture *tex; /* input texture, only set at runtime */
int shaderloc; /* id from opengl */
char shadername[32]; /* name in shader */
- float vec[16]; /* vector data */
- GPUNodeLink *link;
- bool dynamictex; /* dynamic? */
- CustomDataType attribtype; /* attribute type */
- char attribname[MAX_CUSTOMDATA_LAYER_NAME]; /* attribute name */
- int attribfirst; /* this is the first one that is bound */
- GPUBuiltin builtin; /* builtin uniform */
- GPUOpenGLBuiltin oglbuiltin; /* opengl built in varying */
+ /* Content based on GPUDataSource */
+ union {
+ /* GPU_SOURCE_CONSTANT | GPU_SOURCE_UNIFORM */
+ float vec[16]; /* vector data */
+ /* GPU_SOURCE_BUILTIN */
+ GPUBuiltin builtin; /* builtin uniform */
+ /* GPU_SOURCE_TEX */
+ struct {
+ struct GPUTexture **coba; /* input texture, only set at runtime */
+ struct Image *ima; /* image */
+ struct ImageUser *iuser; /* image user */
+ bool image_isdata; /* image does not contain color data */
+ bool bindtex; /* input is responsible for binding the texture? */
+ int texid; /* number for multitexture, starting from zero */
+ GPUType textype; /* texture type (2D, 1D Array ...) */
+ };
+ /* GPU_SOURCE_ATTRIB */
+ struct {
+ char attribname[MAX_CUSTOMDATA_LAYER_NAME]; /* attribute name */
+ int attribid; /* id for vertex attributes */
+ bool attribfirst; /* this is the first one that is bound */
+ CustomDataType attribtype; /* attribute type */
+ };
+ };
} GPUInput;
struct GPUPass {
- struct GPUPass *next, *prev;
+ struct GPUPass *next;
- ListBase inputs;
- struct GPUOutput *output;
struct GPUShader *shader;
char *fragmentcode;
char *geometrycode;
char *vertexcode;
- const char *libcode;
+ char *defines;
+ uint refcount; /* Orphaned GPUPasses gets freed by the garbage collector. */
+ uint32_t hash; /* Identity hash generated from all GLSL code. */
+ bool compiled; /* Did we already tried to compile the attached GPUShader. */
};
-
typedef struct GPUPass GPUPass;
-GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink,
- struct GPUVertexAttribs *attribs, int *builtin,
- const GPUMatType type, const char *name,
- const bool use_opensubdiv,
- const bool use_new_shading);
+GPUPass *GPU_generate_pass(
+ GPUMaterial *material,
+ GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs,
+ ListBase *nodes, int *builtins,
+ const char *vert_code, const char *geom_code,
+ const char *frag_lib, const char *defines);
-struct GPUShader *GPU_pass_shader(GPUPass *pass);
+struct GPUShader *GPU_pass_shader_get(GPUPass *pass);
-void GPU_pass_bind(GPUPass *pass, double time, int mipmap);
-void GPU_pass_update_uniforms(GPUPass *pass);
-void GPU_pass_unbind(GPUPass *pass);
+void GPU_nodes_extract_dynamic_inputs(struct GPUShader *shader, ListBase *inputs, ListBase *nodes);
+void GPU_nodes_get_vertex_attributes(ListBase *nodes, struct GPUVertexAttribs *attribs);
+void GPU_nodes_prune(ListBase *nodes, struct GPUNodeLink *outlink);
-void GPU_pass_free(GPUPass *pass);
+void GPU_pass_compile(GPUPass *pass, const char *shname);
+void GPU_pass_release(GPUPass *pass);
void GPU_pass_free_nodes(ListBase *nodes);
+void GPU_inputs_free(ListBase *inputs);
+
void gpu_codegen_init(void);
void gpu_codegen_exit(void);
@@ -192,6 +202,6 @@ void gpu_codegen_exit(void);
const char *GPU_builtin_name(GPUBuiltin builtin);
void gpu_material_add_node(struct GPUMaterial *material, struct GPUNode *node);
-int GPU_link_changed(struct GPUNodeLink *link);
+struct GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, float *pixels, float *row);
#endif
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
deleted file mode 100644
index 15865a73056..00000000000
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ /dev/null
@@ -1,1460 +0,0 @@
-/*
- * ***** 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): Antony Riakiotakis.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/gpu/intern/gpu_compositing.c
- * \ingroup gpu
- *
- * System that manages framebuffer compositing.
- */
-
-#include "BLI_sys_types.h"
-#include "BLI_rect.h"
-#include "BLI_math.h"
-
-#include "BLI_rand.h"
-
-#include "DNA_vec_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_gpu_types.h"
-
-#include "GPU_compositing.h"
-#include "GPU_extensions.h"
-#include "GPU_framebuffer.h"
-#include "GPU_glew.h"
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-
-#include "MEM_guardedalloc.h"
-
-static const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}};
-static const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}};
-
-
-/* shader interfaces (legacy GL 2 style, without uniform buffer objects) */
-
-typedef struct {
- int ssao_uniform;
- int ssao_color_uniform;
- int color_uniform;
- int depth_uniform;
- int viewvecs_uniform;
- int ssao_sample_params_uniform;
- int ssao_concentric_tex;
- int ssao_jitter_uniform;
-} GPUSSAOShaderInterface;
-
-typedef struct {
- int invrendertargetdim_uniform;
- int color_uniform;
- int dof_uniform;
- int depth_uniform;
- int viewvecs_uniform;
-} GPUDOFHQPassOneInterface;
-
-typedef struct {
- int rendertargetdim_uniform;
- int color_uniform;
- int coc_uniform;
- int select_uniform;
- int dof_uniform;
-} GPUDOFHQPassTwoInterface;
-
-typedef struct {
- int dof_uniform;
- int invrendertargetdim_uniform;
- int color_uniform;
- int far_uniform;
- int near_uniform;
- int viewvecs_uniform;
- int depth_uniform;
-} GPUDOFHQPassThreeInterface;
-
-typedef struct {
- int dof_uniform;
- int invrendertargetdim_uniform;
- int color_uniform;
- int depth_uniform;
- int viewvecs_uniform;
-} GPUDOFPassOneInterface;
-
-typedef struct {
- int dof_uniform;
- int invrendertargetdim_uniform;
- int color_uniform;
- int depth_uniform;
- int viewvecs_uniform;
-} GPUDOFPassTwoInterface;
-
-typedef struct {
- int near_coc_downsampled;
- int near_coc_blurred;
-} GPUDOFPassThreeInterface;
-
-typedef struct {
- int near_coc_downsampled;
- int invrendertargetdim_uniform;
-} GPUDOFPassFourInterface;
-
-typedef struct {
- int medium_blurred_uniform;
- int high_blurred_uniform;
- int dof_uniform;
- int invrendertargetdim_uniform;
- int original_uniform;
- int depth_uniform;
- int viewvecs_uniform;
-} GPUDOFPassFiveInterface;
-
-typedef struct {
- int depth_uniform;
-} GPUDepthResolveInterface;
-
-
-struct GPUFX {
- /* we borrow the term gbuffer from deferred rendering however this is just a regular
- * depth/color framebuffer. Could be extended later though */
- GPUFrameBuffer *gbuffer;
-
- /* dimensions of the gbuffer */
- int gbuffer_dim[2];
-
- /* texture bound to the first color attachment of the gbuffer */
- GPUTexture *color_buffer;
-
- /* second texture used for ping-pong compositing */
- GPUTexture *color_buffer_sec;
- /* texture bound to the depth attachment of the gbuffer */
- GPUTexture *depth_buffer;
- GPUTexture *depth_buffer_xray;
-
- /* texture used for jittering for various effects */
- GPUTexture *jitter_buffer;
-
- /* all those buffers below have to coexist.
- * Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */
- int dof_downsampled_w;
- int dof_downsampled_h;
-
- /* texture used for near coc and color blurring calculation */
- GPUTexture *dof_near_coc_buffer;
- /* blurred near coc buffer. */
- GPUTexture *dof_near_coc_blurred_buffer;
- /* final near coc buffer. */
- GPUTexture *dof_near_coc_final_buffer;
-
- /* half size blur buffer */
- GPUTexture *dof_half_downsampled_near;
- GPUTexture *dof_half_downsampled_far;
- /* high quality dof texture downsamplers. 6 levels means 64 pixels wide - should be enough */
- GPUTexture *dof_nearfar_coc;
- GPUTexture *dof_near_blur;
- GPUTexture *dof_far_blur;
-
- /* for high quality we use again a spiral texture with radius adapted */
- bool dof_high_quality;
-
- /* texture used for ssao */
- int ssao_sample_count_cache;
- GPUTexture *ssao_spiral_samples_tex;
-
-
- GPUFXSettings settings;
-
- /* or-ed flags of enabled effects */
- int effects;
-
- /* number of passes, needed to detect if ping pong buffer allocation is needed */
- int num_passes;
-
- /* we have a stencil, restore the previous state */
- bool restore_stencil;
-
- unsigned int vbuffer;
-};
-
-#if 0
-/* concentric mapping, see "A Low Distortion Map Between Disk and Square" and
- * http://psgraphics.blogspot.nl/2011/01/improved-code-for-concentric-map.html */
-static GPUTexture * create_concentric_sample_texture(int side)
-{
- GPUTexture *tex;
- float midpoint = 0.5f * (side - 1);
- float *texels = (float *)MEM_mallocN(sizeof(float) * 2 * side * side, "concentric_tex");
- int i, j;
-
- for (i = 0; i < side; i++) {
- for (j = 0; j < side; j++) {
- int index = (i * side + j) * 2;
- float a = 1.0f - i / midpoint;
- float b = 1.0f - j / midpoint;
- float phi, r;
- if (a * a > b * b) {
- r = a;
- phi = (M_PI_4) * (b / a);
- }
- else {
- r = b;
- phi = M_PI_2 - (M_PI_4) * (a / b);
- }
- texels[index] = r * cos(phi);
- texels[index + 1] = r * sin(phi);
- }
- }
-
- tex = GPU_texture_create_1D_procedural(side * side, texels, NULL);
- MEM_freeN(texels);
- return tex;
-}
-#endif
-
-static GPUTexture *create_spiral_sample_texture(int numsaples)
-{
- GPUTexture *tex;
- float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * numsaples, "concentric_tex");
- const float numsaples_inv = 1.0f / numsaples;
- int i;
- /* arbitrary number to ensure we don't get conciding samples every circle */
- const float spirals = 7.357;
-
- for (i = 0; i < numsaples; i++) {
- float r = (i + 0.5f) * numsaples_inv;
- float phi = r * spirals * (float)(2.0 * M_PI);
- texels[i][0] = r * cosf(phi);
- texels[i][1] = r * sinf(phi);
- }
-
- tex = GPU_texture_create_1D_procedural(numsaples, (float *)texels, NULL);
- MEM_freeN(texels);
- return tex;
-}
-
-/* generate a new FX compositor */
-GPUFX *GPU_fx_compositor_create(void)
-{
- GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor");
-
- glGenBuffers(1, &fx->vbuffer);
- glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer);
- glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STATIC_DRAW);
- glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(float), fullscreencos);
- glBufferSubData(GL_ARRAY_BUFFER, 8 * sizeof(float), 8 * sizeof(float), fullscreenuvs);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- return fx;
-}
-
-static void cleanup_fx_dof_buffers(GPUFX *fx)
-{
- if (fx->dof_near_coc_blurred_buffer) {
- GPU_texture_free(fx->dof_near_coc_blurred_buffer);
- fx->dof_near_coc_blurred_buffer = NULL;
- }
- if (fx->dof_near_coc_buffer) {
- GPU_texture_free(fx->dof_near_coc_buffer);
- fx->dof_near_coc_buffer = NULL;
- }
- if (fx->dof_near_coc_final_buffer) {
- GPU_texture_free(fx->dof_near_coc_final_buffer);
- fx->dof_near_coc_final_buffer = NULL;
- }
-
- if (fx->dof_half_downsampled_near) {
- GPU_texture_free(fx->dof_half_downsampled_near);
- fx->dof_half_downsampled_near = NULL;
- }
- if (fx->dof_half_downsampled_far) {
- GPU_texture_free(fx->dof_half_downsampled_far);
- fx->dof_half_downsampled_far = NULL;
- }
- if (fx->dof_nearfar_coc) {
- GPU_texture_free(fx->dof_nearfar_coc);
- fx->dof_nearfar_coc = NULL;
- }
- if (fx->dof_near_blur) {
- GPU_texture_free(fx->dof_near_blur);
- fx->dof_near_blur = NULL;
- }
- if (fx->dof_far_blur) {
- GPU_texture_free(fx->dof_far_blur);
- fx->dof_far_blur = NULL;
- }
-}
-
-static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
-{
- if (fx->color_buffer) {
- GPU_framebuffer_texture_detach(fx->color_buffer);
- GPU_texture_free(fx->color_buffer);
- fx->color_buffer = NULL;
- }
-
- if (fx->color_buffer_sec) {
- GPU_framebuffer_texture_detach(fx->color_buffer_sec);
- GPU_texture_free(fx->color_buffer_sec);
- fx->color_buffer_sec = NULL;
- }
-
- if (fx->depth_buffer) {
- GPU_framebuffer_texture_detach(fx->depth_buffer);
- GPU_texture_free(fx->depth_buffer);
- fx->depth_buffer = NULL;
- }
-
- if (fx->depth_buffer_xray) {
- GPU_framebuffer_texture_detach(fx->depth_buffer_xray);
- GPU_texture_free(fx->depth_buffer_xray);
- fx->depth_buffer_xray = NULL;
- }
-
- cleanup_fx_dof_buffers(fx);
-
- if (fx->ssao_spiral_samples_tex) {
- GPU_texture_free(fx->ssao_spiral_samples_tex);
- fx->ssao_spiral_samples_tex = NULL;
- }
-
- if (fx->jitter_buffer && do_fbo) {
- GPU_texture_free(fx->jitter_buffer);
- fx->jitter_buffer = NULL;
- }
-
- if (fx->gbuffer && do_fbo) {
- GPU_framebuffer_free(fx->gbuffer);
- fx->gbuffer = NULL;
- }
-}
-
-/* destroy a text compositor */
-void GPU_fx_compositor_destroy(GPUFX *fx)
-{
- cleanup_fx_gl_data(fx, true);
- glDeleteBuffers(1, &fx->vbuffer);
- MEM_freeN(fx);
-}
-
-static GPUTexture * create_jitter_texture(void)
-{
- float jitter[64 * 64][2];
- int i;
-
- for (i = 0; i < 64 * 64; i++) {
- jitter[i][0] = 2.0f * BLI_frand() - 1.0f;
- jitter[i][1] = 2.0f * BLI_frand() - 1.0f;
- normalize_v2(jitter[i]);
- }
-
- return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL);
-}
-
-
-bool GPU_fx_compositor_initialize_passes(
- GPUFX *fx, const rcti *rect, const rcti *scissor_rect,
- const GPUFXSettings *fx_settings)
-{
- int w = BLI_rcti_size_x(rect), h = BLI_rcti_size_y(rect);
- char err_out[256];
- int num_passes = 0;
- char fx_flag;
-
- fx->effects = 0;
-
- if (!GLEW_EXT_framebuffer_object)
- return false;
-
- if (!fx_settings) {
- cleanup_fx_gl_data(fx, true);
- return false;
- }
-
- fx_flag = fx_settings->fx_flag;
-
- /* disable effects if no options passed for them */
- if (!fx_settings->dof) {
- fx_flag &= ~GPU_FX_FLAG_DOF;
- }
- if (!fx_settings->ssao || fx_settings->ssao->samples < 1) {
- fx_flag &= ~GPU_FX_FLAG_SSAO;
- }
-
- if (!fx_flag) {
- cleanup_fx_gl_data(fx, true);
- return false;
- }
-
- /* scissor is missing when drawing offscreen, in that case, dimensions match exactly. In opposite case
- * add one to match viewport dimensions */
- if (scissor_rect) {
- w++;
- h++;
- }
-
- fx->num_passes = 0;
- /* dof really needs a ping-pong buffer to work */
- if (fx_flag & GPU_FX_FLAG_DOF)
- num_passes++;
-
- if (fx_flag & GPU_FX_FLAG_SSAO)
- num_passes++;
-
- if (!fx->gbuffer) {
- fx->gbuffer = GPU_framebuffer_create();
-
- if (!fx->gbuffer) {
- return false;
- }
- }
-
- /* try creating the jitter texture */
- if (!fx->jitter_buffer)
- fx->jitter_buffer = create_jitter_texture();
-
- /* check if color buffers need recreation */
- if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) {
- cleanup_fx_gl_data(fx, false);
-
- if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
- printf(".256%s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
-
- if (!(fx->depth_buffer = GPU_texture_create_depth(w, h, err_out))) {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- }
-
- if (fx_flag & GPU_FX_FLAG_SSAO) {
- if (fx_settings->ssao->samples != fx->ssao_sample_count_cache || !fx->ssao_spiral_samples_tex) {
- if (fx_settings->ssao->samples < 1)
- fx_settings->ssao->samples = 1;
-
- fx->ssao_sample_count_cache = fx_settings->ssao->samples;
-
- if (fx->ssao_spiral_samples_tex) {
- GPU_texture_free(fx->ssao_spiral_samples_tex);
- }
-
- fx->ssao_spiral_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples);
- }
- }
- else {
- if (fx->ssao_spiral_samples_tex) {
- GPU_texture_free(fx->ssao_spiral_samples_tex);
- fx->ssao_spiral_samples_tex = NULL;
- }
- }
-
- /* create textures for dof effect */
- if (fx_flag & GPU_FX_FLAG_DOF) {
- bool dof_high_quality = (fx_settings->dof->high_quality != 0) &&
- GPU_geometry_shader_support() && GPU_instanced_drawing_support();
-
- /* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */
- if (dof_high_quality != fx->dof_high_quality)
- cleanup_fx_dof_buffers(fx);
-
- if (dof_high_quality) {
- fx->dof_downsampled_w = w / 2;
- fx->dof_downsampled_h = h / 2;
-
- if (!fx->dof_half_downsampled_near || !fx->dof_nearfar_coc || !fx->dof_near_blur ||
- !fx->dof_far_blur || !fx->dof_half_downsampled_far)
- {
-
- if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
-
-
- if (!(fx->dof_near_blur = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
-
- if (!(fx->dof_far_blur = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- }
- }
- else {
- fx->dof_downsampled_w = w / 4;
- fx->dof_downsampled_h = h / 4;
-
- if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) {
-
- if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D(
- fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- }
- }
-
- fx->dof_high_quality = dof_high_quality;
- }
- else {
- /* cleanup unnecessary buffers */
- cleanup_fx_dof_buffers(fx);
- }
-
- /* we need to pass data between shader stages, allocate an extra color buffer */
- if (num_passes > 1) {
- if (!fx->color_buffer_sec) {
- if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) {
- printf(".256%s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return false;
- }
- }
- }
- else {
- if (fx->color_buffer_sec) {
- GPU_framebuffer_texture_detach(fx->color_buffer_sec);
- GPU_texture_free(fx->color_buffer_sec);
- fx->color_buffer_sec = NULL;
- }
- }
-
- /* bind the buffers */
-
- /* first depth buffer, because system assumes read/write buffers */
- if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out))
- printf("%.256s\n", err_out);
-
- if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out))
- printf("%.256s\n", err_out);
-
- if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out))
- printf("%.256s\n", err_out);
-
- GPU_texture_bind_as_framebuffer(fx->color_buffer);
-
- /* enable scissor test. It's needed to ensure sculpting works correctly */
- if (scissor_rect) {
- int w_sc = BLI_rcti_size_x(scissor_rect) + 1;
- int h_sc = BLI_rcti_size_y(scissor_rect) + 1;
- glPushAttrib(GL_SCISSOR_BIT);
- glEnable(GL_SCISSOR_TEST);
- glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin,
- w_sc, h_sc);
- fx->restore_stencil = true;
- }
- else {
- fx->restore_stencil = false;
- }
-
- fx->effects = fx_flag;
-
- if (fx_settings)
- fx->settings = *fx_settings;
- fx->gbuffer_dim[0] = w;
- fx->gbuffer_dim[1] = h;
-
- fx->num_passes = num_passes;
-
- return true;
-}
-
-static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOffScreen *ofs, GPUTexture *target)
-{
- if ((*passes_left)-- == 1) {
- GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
- if (ofs) {
- GPU_offscreen_bind(ofs, false);
- }
- else
- GPU_framebuffer_restore();
- }
- else {
- /* bind the ping buffer to the color buffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, NULL);
- }
-}
-
-void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray)
-{
- char err_out[256];
-
- if (do_xray) {
- if (!fx->depth_buffer_xray &&
- !(fx->depth_buffer_xray = GPU_texture_create_depth(fx->gbuffer_dim[0], fx->gbuffer_dim[1], err_out)))
- {
- printf("%.256s\n", err_out);
- cleanup_fx_gl_data(fx, true);
- return;
- }
- }
- else {
- if (fx->depth_buffer_xray) {
- GPU_framebuffer_texture_detach(fx->depth_buffer_xray);
- GPU_texture_free(fx->depth_buffer_xray);
- fx->depth_buffer_xray = NULL;
- }
- return;
- }
-
- GPU_framebuffer_texture_detach(fx->depth_buffer);
-
- /* first depth buffer, because system assumes read/write buffers */
- if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out))
- printf("%.256s\n", err_out);
-}
-
-
-void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
-{
- GPUShader *depth_resolve_shader;
- GPU_framebuffer_texture_detach(fx->depth_buffer_xray);
-
- /* attach regular framebuffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, NULL);
-
- /* full screen quad where we will always write to depth buffer */
- glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT);
- glDepthFunc(GL_ALWAYS);
- /* disable scissor from sculpt if any */
- glDisable(GL_SCISSOR_TEST);
- /* disable writing to color buffer, it's depth only pass */
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-
- /* set up quad buffer */
- glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer);
- glVertexPointer(2, GL_FLOAT, 0, NULL);
- glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float)));
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
- depth_resolve_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_RESOLVE, false);
-
- if (depth_resolve_shader) {
- GPUDepthResolveInterface *interface = GPU_shader_get_interface(depth_resolve_shader);
-
- GPU_shader_bind(depth_resolve_shader);
-
- GPU_texture_bind(fx->depth_buffer_xray, 0);
- GPU_texture_filter_mode(fx->depth_buffer_xray, false, true);
- GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray);
-
- /* draw */
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- /* disable bindings */
- GPU_texture_filter_mode(fx->depth_buffer_xray, true, false);
- GPU_texture_unbind(fx->depth_buffer_xray);
-
- GPU_shader_unbind();
- }
-
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
- glPopAttrib();
-}
-
-
-bool GPU_fx_do_composite_pass(
- GPUFX *fx, float projmat[4][4], bool is_persp,
- struct Scene *scene, struct GPUOffScreen *ofs)
-{
- GPUTexture *src, *target;
- int numslots = 0;
- float invproj[4][4];
- int i;
- float dfdyfac[2];
- /* number of passes left. when there are no more passes, the result is passed to the frambuffer */
- int passes_left = fx->num_passes;
- /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */
- float viewvecs[3][4] = {
- {-1.0f, -1.0f, -1.0f, 1.0f},
- {1.0f, -1.0f, -1.0f, 1.0f},
- {-1.0f, 1.0f, -1.0f, 1.0f}
- };
-
- if (fx->effects == 0)
- return false;
-
- GPU_get_dfdy_factors(dfdyfac);
- /* first, unbind the render-to-texture framebuffer */
- GPU_framebuffer_texture_detach(fx->color_buffer);
- GPU_framebuffer_texture_detach(fx->depth_buffer);
-
- if (fx->restore_stencil)
- glPopAttrib();
-
- src = fx->color_buffer;
- target = fx->color_buffer_sec;
-
- /* set up quad buffer */
- glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer);
- glVertexPointer(2, GL_FLOAT, 0, NULL);
- glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float)));
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
- /* full screen FX pass */
-
- /* invert the view matrix */
- invert_m4_m4(invproj, projmat);
-
- /* convert the view vectors to view space */
- for (i = 0; i < 3; i++) {
- mul_m4_v4(invproj, viewvecs[i]);
- /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
- mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
- if (is_persp)
- mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
- viewvecs[i][3] = 1.0;
- }
-
- /* we need to store the differences */
- viewvecs[1][0] -= viewvecs[0][0];
- viewvecs[1][1] = viewvecs[2][1] - viewvecs[0][1];
-
- /* calculate a depth offset as well */
- if (!is_persp) {
- float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
- mul_m4_v4(invproj, vec_far);
- mul_v3_fl(vec_far, 1.0f / vec_far[3]);
- viewvecs[1][2] = vec_far[2] - viewvecs[0][2];
- }
-
- /* set invalid color in case shader fails */
- glColor3f(1.0, 0.0, 1.0);
- glDisable(GL_DEPTH_TEST);
-
- /* ssao pass */
- if (fx->effects & GPU_FX_FLAG_SSAO) {
- GPUShader *ssao_shader;
- ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp);
- if (ssao_shader) {
- const GPUSSAOSettings *fx_ssao = fx->settings.ssao;
- /* adjust attenuation to be scale invariant */
- float attenuation = fx_ssao->attenuation / (fx_ssao->distance_max * fx_ssao->distance_max);
- float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, attenuation, 0.0f};
- float sample_params[3];
-
- sample_params[0] = fx->ssao_sample_count_cache;
- /* multiplier so we tile the random texture on screen */
- sample_params[1] = fx->gbuffer_dim[0] / 64.0;
- sample_params[2] = fx->gbuffer_dim[1] / 64.0;
-
- ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1];
-
- GPUSSAOShaderInterface *interface = GPU_shader_get_interface(ssao_shader);
-
- GPU_shader_bind(ssao_shader);
-
- GPU_shader_uniform_vector(ssao_shader, interface->ssao_uniform, 4, 1, ssao_params);
- GPU_shader_uniform_vector(ssao_shader, interface->ssao_color_uniform, 4, 1, fx_ssao->color);
- GPU_shader_uniform_vector(ssao_shader, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
- GPU_shader_uniform_vector(ssao_shader, interface->ssao_sample_params_uniform, 3, 1, sample_params);
-
- GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(ssao_shader, interface->color_uniform, src);
-
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer);
-
- GPU_texture_bind(fx->jitter_buffer, numslots++);
- GPU_shader_uniform_texture(ssao_shader, interface->ssao_jitter_uniform, fx->jitter_buffer);
-
- GPU_texture_bind(fx->ssao_spiral_samples_tex, numslots++);
- GPU_shader_uniform_texture(ssao_shader, interface->ssao_concentric_tex, fx->ssao_spiral_samples_tex);
-
- /* draw */
- gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- /* disable bindings */
- GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
- GPU_texture_unbind(fx->jitter_buffer);
- GPU_texture_unbind(fx->ssao_spiral_samples_tex);
-
- /* may not be attached, in that case this just returns */
- if (target) {
- GPU_framebuffer_texture_detach(target);
- if (ofs) {
- GPU_offscreen_bind(ofs, false);
- }
- else {
- GPU_framebuffer_restore();
- }
- }
-
- /* swap here, after src/target have been unbound */
- SWAP(GPUTexture *, target, src);
- numslots = 0;
- }
- }
-
- /* second pass, dof */
- if (fx->effects & GPU_FX_FLAG_DOF) {
- const GPUDOFSettings *fx_dof = fx->settings.dof;
- float dof_params[4];
- float scale = scene->unit.system ? scene->unit.scale_length : 1.0f;
- /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
- * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though
- * because the shader reads coordinates in world space, which is in blender units.
- * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */
- float scale_camera = 0.001f / scale;
- /* we want radius here for the aperture number */
- float aperture = 0.5f * scale_camera * fx_dof->focal_length / fx_dof->fstop;
-
- dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length /
- (fx_dof->focus_distance - scale_camera * fx_dof->focal_length));
- dof_params[1] = fx_dof->focus_distance;
- dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
- dof_params[3] = fx_dof->num_blades;
-
- if (fx->dof_high_quality) {
- GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3;
-
- /* custom shaders close to the effect described in CryEngine 3 Graphics Gems */
- dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE, is_persp);
- dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO, is_persp);
- dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE, is_persp);
-
- /* error occured, restore framebuffers and return */
- if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3)) {
- GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
- GPU_framebuffer_restore();
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
- GPU_shader_unbind();
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- return false;
- }
-
- /* pass first, downsample the color buffer to near/far targets and calculate coc texture */
- {
- float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
-
- GPUDOFHQPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1);
-
- GPU_shader_bind(dof_shader_pass1);
-
- GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass1, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
-
- GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
-
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, false);
- GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer);
-
- GPU_texture_bind(src, numslots++);
- /* disable filtering for the texture so custom downsample can do the right thing */
- GPU_texture_filter_mode(src, false, false);
- GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src);
-
- /* target is the downsampled coc buffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL);
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL);
- /* binding takes care of setting the viewport to the downsampled size */
- GPU_framebuffer_slots_bind(fx->gbuffer, 0);
-
- GPU_framebuffer_check_valid(fx->gbuffer, NULL);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_filter_mode(src, false, true);
- GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
-
- GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near);
- GPU_framebuffer_texture_detach(fx->dof_half_downsampled_far);
- GPU_framebuffer_texture_detach(fx->dof_nearfar_coc);
- GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_half_downsampled_near);
-
- numslots = 0;
- }
-
- /* second pass, shoot quads for every pixel in the downsampled buffers, scaling according
- * to circle of confusion */
- {
- int rendertargetdim[2] = {fx->dof_downsampled_w, fx->dof_downsampled_h};
- float selection[2] = {0.0f, 1.0f};
-
- GPUDOFHQPassTwoInterface *interface = GPU_shader_get_interface(dof_shader_pass2);
-
- GPU_shader_bind(dof_shader_pass2);
-
- GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector_int(dof_shader_pass2, interface->rendertargetdim_uniform, 2, 1, rendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection);
-
- GPU_texture_bind(fx->dof_nearfar_coc, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, interface->coc_uniform, fx->dof_nearfar_coc);
-
- GPU_texture_bind(fx->dof_half_downsampled_far, numslots++);
- GPU_texture_bind(fx->dof_half_downsampled_near, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_far);
- GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false);
-
- /* target is the downsampled coc buffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL);
- GPU_texture_bind_as_framebuffer(fx->dof_far_blur);
-
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- glPointSize(1.0f);
- /* have to clear the buffer unfortunately */
- glClearColor(0.0, 0.0, 0.0, 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
- /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */
- glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h);
-
- GPU_texture_unbind(fx->dof_half_downsampled_far);
- GPU_framebuffer_texture_detach(fx->dof_far_blur);
-
- GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near);
- GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false);
-
- selection[0] = 1.0f;
- selection[1] = 0.0f;
-
- GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection);
-
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL);
- /* have to clear the buffer unfortunately */
- glClear(GL_COLOR_BUFFER_BIT);
- /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */
- glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h);
-
- /* disable bindings */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_BLEND);
-
- GPU_framebuffer_texture_detach(fx->dof_near_blur);
-
- GPU_texture_unbind(fx->dof_half_downsampled_near);
- GPU_texture_unbind(fx->dof_nearfar_coc);
-
- GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur);
- }
-
- /* third pass, accumulate the near/far blur fields */
- {
- float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
-
- GPUDOFHQPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3);
-
- GPU_shader_bind(dof_shader_pass3);
-
- GPU_shader_uniform_vector(dof_shader_pass3, interface->dof_uniform, 4, 1, dof_params);
-
- GPU_shader_uniform_vector(dof_shader_pass3, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass3, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
-
- GPU_texture_bind(fx->dof_near_blur, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, interface->near_uniform, fx->dof_near_blur);
- GPU_texture_filter_mode(fx->dof_near_blur, false, true);
-
- GPU_texture_bind(fx->dof_far_blur, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, interface->far_uniform, fx->dof_far_blur);
- GPU_texture_filter_mode(fx->dof_far_blur, false, true);
-
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, false);
- GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer);
-
- GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, interface->color_uniform, src);
-
- /* if this is the last pass, prepare for rendering on the frambuffer */
- gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_blur);
- GPU_texture_unbind(fx->dof_far_blur);
- GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
-
- /* may not be attached, in that case this just returns */
- if (target) {
- GPU_framebuffer_texture_detach(target);
- if (ofs) {
- GPU_offscreen_bind(ofs, false);
- }
- else {
- GPU_framebuffer_restore();
- }
- }
-
- numslots = 0;
- }
- }
- else {
- GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5;
-
- /* DOF effect has many passes but most of them are performed
- * on a texture whose dimensions are 4 times less than the original
- * (16 times lower than original screen resolution).
- * Technique used is not very exact but should be fast enough and is based
- * on "Practical Post-Process Depth of Field"
- * see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */
- dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp);
- dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp);
- dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp);
- dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp);
- dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp);
-
- /* error occured, restore framebuffers and return */
- if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) {
- GPU_framebuffer_texture_unbind(fx->gbuffer, NULL);
- GPU_framebuffer_restore();
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
- GPU_shader_unbind();
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- return false;
- }
-
- /* pass first, first level of blur in low res buffer */
- {
- float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
-
- GPUDOFPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1);
-
- GPU_shader_bind(dof_shader_pass1);
-
- GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass1, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
-
- GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass1, interface->color_uniform, src);
-
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer);
-
- /* target is the downsampled coc buffer */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
- /* binding takes care of setting the viewport to the downsampled size */
- GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
-
- GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
- numslots = 0;
- }
-
- /* second pass, gaussian blur the downsampled image */
- {
- float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer),
- 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)};
- float tmp = invrendertargetdim[0];
- invrendertargetdim[0] = 0.0f;
-
- GPUDOFPassTwoInterface *interface = GPU_shader_get_interface(dof_shader_pass2);
-
- dof_params[2] = GPU_texture_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor);
-
- /* Blurring vertically */
- GPU_shader_bind(dof_shader_pass2);
-
- GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass2, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass2, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
-
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass2, interface->depth_uniform, fx->depth_buffer);
-
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_buffer);
-
- /* use final buffer as a temp here */
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
-
- /* Drawing quad */
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- /* *unbind/detach */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
-
- /* Blurring horizontally */
- invrendertargetdim[0] = tmp;
- invrendertargetdim[1] = 0.0f;
- GPU_shader_uniform_vector(dof_shader_pass2, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
-
- GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_final_buffer);
-
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- /* *unbind/detach */
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
-
- GPU_texture_unbind(fx->dof_near_coc_final_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer);
-
- dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
-
- numslots = 0;
- }
-
- /* third pass, calculate near coc */
- {
- GPUDOFPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3);
-
- GPU_shader_bind(dof_shader_pass3);
-
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_downsampled, fx->dof_near_coc_buffer);
-
- GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_blurred, fx->dof_near_coc_blurred_buffer);
-
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
-
- /* unbinding here restores the size to the original */
- GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer);
-
- numslots = 0;
- }
-
- /* fourth pass blur final coc once to eliminate discontinuities */
- {
- float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer),
- 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)};
-
- GPUDOFPassFourInterface *interface = GPU_shader_get_interface(dof_shader_pass4);
-
- GPU_shader_bind(dof_shader_pass4);
-
- GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass4, interface->near_coc_downsampled, fx->dof_near_coc_final_buffer);
- GPU_shader_uniform_vector(dof_shader_pass4, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
-
- GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_final_buffer);
-
- /* unbinding here restores the size to the original */
- GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer);
- GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer);
-
- numslots = 0;
- }
-
- /* final pass, merge blurred layers according to final calculated coc */
- {
- float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
-
- GPUDOFPassFiveInterface *interface = GPU_shader_get_interface(dof_shader_pass5);
-
- GPU_shader_bind(dof_shader_pass5);
-
- GPU_shader_uniform_vector(dof_shader_pass5, interface->dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass5, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass5, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
-
- GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, interface->original_uniform, src);
-
- GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, interface->high_blurred_uniform, fx->dof_near_coc_blurred_buffer);
-
- GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, interface->medium_blurred_uniform, fx->dof_near_coc_buffer);
-
- GPU_texture_bind(fx->depth_buffer, numslots++);
- GPU_texture_filter_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass5, interface->depth_uniform, fx->depth_buffer);
-
- /* if this is the last pass, prepare for rendering on the frambuffer */
- gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- /* disable bindings */
- GPU_texture_unbind(fx->dof_near_coc_buffer);
- GPU_texture_unbind(fx->dof_near_coc_blurred_buffer);
- GPU_texture_unbind(src);
- GPU_texture_filter_mode(fx->depth_buffer, true, false);
- GPU_texture_unbind(fx->depth_buffer);
-
- /* may not be attached, in that case this just returns */
- if (target) {
- GPU_framebuffer_texture_detach(target);
- if (ofs) {
- GPU_offscreen_bind(ofs, false);
- }
- else {
- GPU_framebuffer_restore();
- }
- }
-
- SWAP(GPUTexture *, target, src);
- numslots = 0;
- }
- }
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- GPU_shader_unbind();
-
- return true;
-}
-
-void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof)
-{
- fx_dof->fstop = 128.0f;
- fx_dof->focal_length = 1.0f;
- fx_dof->focus_distance = 1.0f;
- fx_dof->sensor = 1.0f;
- fx_dof->num_blades = 6;
-}
-
-void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao)
-{
- fx_ssao->factor = 1.0f;
- fx_ssao->distance_max = 0.2f;
- fx_ssao->attenuation = 1.0f;
- fx_ssao->samples = 20;
-}
-
-void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect effect)
-{
- if (!shader)
- return;
-
- switch (effect) {
- case GPU_SHADER_FX_SSAO:
- {
- GPUSSAOShaderInterface *interface = MEM_mallocN(sizeof(GPUSSAOShaderInterface), "GPUSSAOShaderInterface");
-
- interface->ssao_uniform = GPU_shader_get_uniform(shader, "ssao_params");
- interface->ssao_color_uniform = GPU_shader_get_uniform(shader, "ssao_color");
- interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
- interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
- interface->ssao_sample_params_uniform = GPU_shader_get_uniform(shader, "ssao_sample_params");
- interface->ssao_concentric_tex = GPU_shader_get_uniform(shader, "ssao_concentric_tex");
- interface->ssao_jitter_uniform = GPU_shader_get_uniform(shader, "jitter_tex");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE:
- {
- GPUDOFHQPassOneInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassOneInterface), "GPUDOFHQPassOneInterface");
-
- interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
- interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
- interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
- interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO:
- {
- GPUDOFHQPassTwoInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassTwoInterface), "GPUDOFHQPassTwoInterface");
-
- interface->rendertargetdim_uniform = GPU_shader_get_uniform(shader, "rendertargetdim");
- interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->coc_uniform = GPU_shader_get_uniform(shader, "cocbuffer");
- interface->select_uniform = GPU_shader_get_uniform(shader, "layerselection");
- interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE:
- {
- GPUDOFHQPassThreeInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassThreeInterface), "GPUDOFHQPassThreeInterface");
-
- interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
- interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
- interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->far_uniform = GPU_shader_get_uniform(shader, "farbuffer");
- interface->near_uniform = GPU_shader_get_uniform(shader, "nearbuffer");
- interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
- interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE:
- {
- GPUDOFPassOneInterface *interface = MEM_mallocN(sizeof(GPUDOFPassOneInterface), "GPUDOFPassOneInterface");
-
- interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
- interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
- interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
- interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
- {
- GPUDOFPassTwoInterface *interface = MEM_mallocN(sizeof(GPUDOFPassTwoInterface), "GPUDOFPassTwoInterface");
-
- interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
- interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
- interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
- interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
- {
- GPUDOFPassThreeInterface *interface = MEM_mallocN(sizeof(GPUDOFPassThreeInterface), "GPUDOFPassThreeInterface");
-
- interface->near_coc_downsampled = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->near_coc_blurred = GPU_shader_get_uniform(shader, "blurredcolorbuffer");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
- {
- GPUDOFPassFourInterface *interface = MEM_mallocN(sizeof(GPUDOFPassFourInterface), "GPUDOFPassFourInterface");
-
- interface->near_coc_downsampled = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
- {
- GPUDOFPassFiveInterface *interface = MEM_mallocN(sizeof(GPUDOFPassFiveInterface), "GPUDOFPassFiveInterface");
-
- interface->medium_blurred_uniform = GPU_shader_get_uniform(shader, "mblurredcolorbuffer");
- interface->high_blurred_uniform = GPU_shader_get_uniform(shader, "blurredcolorbuffer");
- interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
- interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
- interface->original_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
- interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
- interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
-
- case GPU_SHADER_FX_DEPTH_RESOLVE:
- {
- GPUDepthResolveInterface *interface = MEM_mallocN(sizeof(GPUDepthResolveInterface), "GPUDepthResolveInterface");
-
- interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
-
- GPU_shader_set_interface(shader, interface);
- break;
- }
-
- default:
- break;
- }
-}
diff --git a/source/blender/gpu/intern/gpu_context.cpp b/source/blender/gpu/intern/gpu_context.cpp
new file mode 100644
index 00000000000..ce3eb64fa37
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_context.cpp
@@ -0,0 +1,329 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Clément Foucault
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_context.cpp
+ * \ingroup gpu
+ *
+ * Manage GL vertex array IDs in a thread-safe way
+ * Use these instead of glGenBuffers & its friends
+ * - alloc must be called from a thread that is bound
+ * to the context that will be used for drawing with
+ * this vao.
+ * - free can be called from any thread
+ */
+
+#include "BLI_assert.h"
+#include "BLI_utildefines.h"
+
+#include "GPU_context.h"
+#include "GPU_framebuffer.h"
+
+#include "gpu_batch_private.h"
+#include "gpu_context_private.h"
+
+#include <vector>
+#include <string.h>
+#include <pthread.h>
+#include <mutex>
+#include <unordered_set>
+
+#if TRUST_NO_ONE
+#if 0
+extern "C" {
+extern int BLI_thread_is_main(void); /* Blender-specific function */
+}
+
+static bool thread_is_main() {
+ /* "main" here means the GL context's thread */
+ return BLI_thread_is_main();
+}
+#endif
+#endif
+
+static std::vector<GLuint> orphaned_buffer_ids;
+static std::vector<GLuint> orphaned_texture_ids;
+
+static std::mutex orphans_mutex;
+
+struct GPUContext {
+ GLuint default_vao;
+ GPUFrameBuffer *current_fbo;
+ std::unordered_set<GPUBatch *> batches; /* Batches that have VAOs from this context */
+#ifdef DEBUG
+ std::unordered_set<GPUFrameBuffer *> framebuffers; /* Framebuffers that have FBO from this context */
+#endif
+ std::vector<GLuint> orphaned_vertarray_ids;
+ std::vector<GLuint> orphaned_framebuffer_ids;
+ std::mutex orphans_mutex; /* todo: try spinlock instead */
+#if TRUST_NO_ONE
+ pthread_t thread; /* Thread on which this context is active. */
+ bool thread_is_used;
+
+ GPUContext() {
+ thread_is_used = false;
+ current_fbo = 0;
+ }
+#endif
+};
+
+#if defined(_MSC_VER) && (_MSC_VER == 1800)
+#define thread_local __declspec(thread)
+thread_local GPUContext *active_ctx = NULL;
+#else
+static thread_local GPUContext *active_ctx = NULL;
+#endif
+
+static void orphans_add(GPUContext *ctx, std::vector<GLuint> *orphan_list, GLuint id)
+{
+ std::mutex *mutex = (ctx) ? &ctx->orphans_mutex : &orphans_mutex;
+
+ mutex->lock();
+ orphan_list->emplace_back(id);
+ mutex->unlock();
+}
+
+static void orphans_clear(GPUContext *ctx)
+{
+ BLI_assert(ctx); /* need at least an active context */
+ BLI_assert(pthread_equal(pthread_self(), ctx->thread)); /* context has been activated by another thread! */
+
+ ctx->orphans_mutex.lock();
+ if (!ctx->orphaned_vertarray_ids.empty()) {
+ uint orphan_len = (uint)ctx->orphaned_vertarray_ids.size();
+ glDeleteVertexArrays(orphan_len, ctx->orphaned_vertarray_ids.data());
+ ctx->orphaned_vertarray_ids.clear();
+ }
+ if (!ctx->orphaned_framebuffer_ids.empty()) {
+ uint orphan_len = (uint)ctx->orphaned_framebuffer_ids.size();
+ glDeleteFramebuffers(orphan_len, ctx->orphaned_framebuffer_ids.data());
+ ctx->orphaned_framebuffer_ids.clear();
+ }
+
+ ctx->orphans_mutex.unlock();
+
+ orphans_mutex.lock();
+ if (!orphaned_buffer_ids.empty()) {
+ uint orphan_len = (uint)orphaned_buffer_ids.size();
+ glDeleteBuffers(orphan_len, orphaned_buffer_ids.data());
+ orphaned_buffer_ids.clear();
+ }
+ if (!orphaned_texture_ids.empty()) {
+ uint orphan_len = (uint)orphaned_texture_ids.size();
+ glDeleteTextures(orphan_len, orphaned_texture_ids.data());
+ orphaned_texture_ids.clear();
+ }
+ orphans_mutex.unlock();
+}
+
+GPUContext *GPU_context_create(void)
+{
+ /* BLI_assert(thread_is_main()); */
+ GPUContext *ctx = new GPUContext;
+ glGenVertexArrays(1, &ctx->default_vao);
+ GPU_context_active_set(ctx);
+ return ctx;
+}
+
+/* to be called after GPU_context_active_set(ctx_to_destroy) */
+void GPU_context_discard(GPUContext *ctx)
+{
+ /* Make sure no other thread has locked it. */
+ BLI_assert(ctx == active_ctx);
+ BLI_assert(pthread_equal(pthread_self(), ctx->thread));
+ BLI_assert(ctx->orphaned_vertarray_ids.empty());
+#ifdef DEBUG
+ /* For now don't allow GPUFrameBuffers to be reuse in another ctx. */
+ BLI_assert(ctx->framebuffers.empty());
+#endif
+ /* delete remaining vaos */
+ while (!ctx->batches.empty()) {
+ /* this removes the array entry */
+ GPU_batch_vao_cache_clear(*ctx->batches.begin());
+ }
+ glDeleteVertexArrays(1, &ctx->default_vao);
+ delete ctx;
+ active_ctx = NULL;
+}
+
+/* ctx can be NULL */
+void GPU_context_active_set(GPUContext *ctx)
+{
+#if TRUST_NO_ONE
+ if (active_ctx) {
+ active_ctx->thread_is_used = false;
+ }
+ /* Make sure no other context is already bound to this thread. */
+ if (ctx) {
+ /* Make sure no other thread has locked it. */
+ assert(ctx->thread_is_used == false);
+ ctx->thread = pthread_self();
+ ctx->thread_is_used = true;
+ }
+#endif
+ if (ctx) {
+ orphans_clear(ctx);
+ }
+ active_ctx = ctx;
+}
+
+GPUContext *GPU_context_active_get(void)
+{
+ return active_ctx;
+}
+
+GLuint GPU_vao_default(void)
+{
+ BLI_assert(active_ctx); /* need at least an active context */
+ BLI_assert(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */
+ return active_ctx->default_vao;
+}
+
+GLuint GPU_vao_alloc(void)
+{
+ GLuint new_vao_id = 0;
+ orphans_clear(active_ctx);
+ glGenVertexArrays(1, &new_vao_id);
+ return new_vao_id;
+}
+
+GLuint GPU_fbo_alloc(void)
+{
+ GLuint new_fbo_id = 0;
+ orphans_clear(active_ctx);
+ glGenFramebuffers(1, &new_fbo_id);
+ return new_fbo_id;
+}
+
+GLuint GPU_buf_alloc(void)
+{
+ GLuint new_buffer_id = 0;
+ orphans_clear(active_ctx);
+ glGenBuffers(1, &new_buffer_id);
+ return new_buffer_id;
+}
+
+GLuint GPU_tex_alloc(void)
+{
+ GLuint new_texture_id = 0;
+ orphans_clear(active_ctx);
+ glGenTextures(1, &new_texture_id);
+ return new_texture_id;
+}
+
+void GPU_vao_free(GLuint vao_id, GPUContext *ctx)
+{
+ BLI_assert(ctx);
+ if (ctx == active_ctx) {
+ glDeleteVertexArrays(1, &vao_id);
+ }
+ else {
+ orphans_add(ctx, &ctx->orphaned_vertarray_ids, vao_id);
+ }
+}
+
+void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx)
+{
+ BLI_assert(ctx);
+ if (ctx == active_ctx) {
+ glDeleteFramebuffers(1, &fbo_id);
+ }
+ else {
+ orphans_add(ctx, &ctx->orphaned_framebuffer_ids, fbo_id);
+ }
+}
+
+void GPU_buf_free(GLuint buf_id)
+{
+ if (active_ctx) {
+ glDeleteBuffers(1, &buf_id);
+ }
+ else {
+ orphans_add(NULL, &orphaned_buffer_ids, buf_id);
+ }
+}
+
+void GPU_tex_free(GLuint tex_id)
+{
+ if (active_ctx) {
+ glDeleteTextures(1, &tex_id);
+ }
+ else {
+ orphans_add(NULL, &orphaned_texture_ids, tex_id);
+ }
+}
+
+/* GPUBatch & GPUFrameBuffer contains respectively VAO & FBO indices
+ * which are not shared across contexts. So we need to keep track of
+ * ownership. */
+
+void gpu_context_add_batch(GPUContext *ctx, GPUBatch *batch)
+{
+ BLI_assert(ctx);
+ ctx->orphans_mutex.lock();
+ ctx->batches.emplace(batch);
+ ctx->orphans_mutex.unlock();
+}
+
+void gpu_context_remove_batch(GPUContext *ctx, GPUBatch *batch)
+{
+ BLI_assert(ctx);
+ ctx->orphans_mutex.lock();
+ ctx->batches.erase(batch);
+ ctx->orphans_mutex.unlock();
+}
+
+void gpu_context_add_framebuffer(GPUContext *ctx, GPUFrameBuffer *fb)
+{
+#ifdef DEBUG
+ BLI_assert(ctx);
+ ctx->orphans_mutex.lock();
+ ctx->framebuffers.emplace(fb);
+ ctx->orphans_mutex.unlock();
+#else
+ UNUSED_VARS(ctx, fb);
+#endif
+}
+
+void gpu_context_remove_framebuffer(GPUContext *ctx, GPUFrameBuffer *fb)
+{
+#ifdef DEBUG
+ BLI_assert(ctx);
+ ctx->orphans_mutex.lock();
+ ctx->framebuffers.erase(fb);
+ ctx->orphans_mutex.unlock();
+#else
+ UNUSED_VARS(ctx, fb);
+#endif
+}
+
+void gpu_context_active_framebuffer_set(GPUContext *ctx, GPUFrameBuffer *fb)
+{
+ ctx->current_fbo = fb;
+}
+
+GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx)
+{
+ return ctx->current_fbo;
+}
diff --git a/source/blender/gpu/intern/gpu_context_private.h b/source/blender/gpu/intern/gpu_context_private.h
new file mode 100644
index 00000000000..7f13dd542da
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_context_private.h
@@ -0,0 +1,71 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_context_private.h
+ * \ingroup gpu
+ *
+ * This interface allow GPU to manage GL objects for multiple context and threads.
+ */
+
+#ifndef __GPU_CONTEXT_PRIVATE_H__
+#define __GPU_CONTEXT_PRIVATE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "GPU_context.h"
+
+struct GPUFrameBuffer;
+
+GLuint GPU_vao_default(void);
+
+/* These require a gl ctx bound. */
+GLuint GPU_buf_alloc(void);
+GLuint GPU_tex_alloc(void);
+GLuint GPU_vao_alloc(void);
+GLuint GPU_fbo_alloc(void);
+
+/* These can be called any threads even without gl ctx. */
+void GPU_buf_free(GLuint buf_id);
+void GPU_tex_free(GLuint tex_id);
+/* These two need the ctx the id was created with. */
+void GPU_vao_free(GLuint vao_id, GPUContext *ctx);
+void GPU_fbo_free(GLuint fbo_id, GPUContext *ctx);
+
+void gpu_context_add_batch(GPUContext *ctx, GPUBatch *batch);
+void gpu_context_remove_batch(GPUContext *ctx, GPUBatch *batch);
+
+void gpu_context_add_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb);
+void gpu_context_remove_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb);
+
+void gpu_context_active_framebuffer_set(GPUContext *ctx, struct GPUFrameBuffer *fb);
+struct GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GPU_CONTEXT_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c
index 859aab9565f..8aea87ef659 100644
--- a/source/blender/gpu/intern/gpu_debug.c
+++ b/source/blender/gpu/intern/gpu_debug.c
@@ -20,7 +20,7 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): Brecht Van Lommel, Jason Wilkins.
+ * Contributor(s): Brecht Van Lommel, Jason Wilkins, Mike Erwin.
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -44,122 +44,18 @@
#include <stdlib.h>
#include <string.h>
-#define CASE_CODE_RETURN_STR(code) case code: return #code;
+#ifndef __APPLE__ /* only non-Apple systems implement OpenGL debug callbacks */
-static const char *gpu_gl_error_symbol(GLenum err)
-{
- switch (err) {
- CASE_CODE_RETURN_STR(GL_NO_ERROR)
- CASE_CODE_RETURN_STR(GL_INVALID_ENUM)
- CASE_CODE_RETURN_STR(GL_INVALID_VALUE)
- CASE_CODE_RETURN_STR(GL_INVALID_OPERATION)
- CASE_CODE_RETURN_STR(GL_STACK_OVERFLOW)
- CASE_CODE_RETURN_STR(GL_STACK_UNDERFLOW)
- CASE_CODE_RETURN_STR(GL_OUT_OF_MEMORY)
-
-#if GL_ARB_imaging
- CASE_CODE_RETURN_STR(GL_TABLE_TOO_LARGE)
-#endif
-
-#if defined(WITH_GLU)
- CASE_CODE_RETURN_STR(GLU_INVALID_ENUM)
- CASE_CODE_RETURN_STR(GLU_INVALID_VALUE)
- CASE_CODE_RETURN_STR(GLU_OUT_OF_MEMORY)
-#endif
+/* control whether we use older AMD_debug_output extension
+ * some supported GPU + OS combos do not have the newer extensions */
+# define LEGACY_DEBUG 1
- default:
- return "<unknown error>";
- }
-}
-
-#undef CASE_CODE_RETURN_STR
-
-
-static bool gpu_report_gl_errors(const char *file, int line, const char *str)
-{
- GLenum gl_error = glGetError();
-
- if (gl_error == GL_NO_ERROR) {
- return true;
- }
- else {
- /* glGetError should have cleared the error flag, so if we get the
- * same flag twice that means glGetError itself probably triggered
- * the error. This happens on Windows if the GL context is invalid.
- */
- {
- GLenum new_error = glGetError();
- if (gl_error == new_error) {
- fprintf(stderr, "GL: Possible context invalidation issue\n");
- return false;
- }
- }
-
- fprintf(stderr,
- "%s:%d: ``%s'' -> GL Error (0x%04X - %s): %s\n",
- file, line, str, gl_error,
- gpu_gl_error_symbol(gl_error),
- gpuErrorString(gl_error));
-
- return false;
- }
-}
-
-
-const char *gpuErrorString(GLenum err)
-{
- switch (err) {
- case GL_NO_ERROR:
- return "No Error";
-
- case GL_INVALID_ENUM:
- return "Invalid Enumeration";
-
- case GL_INVALID_VALUE:
- return "Invalid Value";
-
- case GL_INVALID_OPERATION:
- return "Invalid Operation";
-
- case GL_STACK_OVERFLOW:
- return "Stack Overflow";
-
- case GL_STACK_UNDERFLOW:
- return "Stack Underflow";
-
- case GL_OUT_OF_MEMORY:
- return "Out of Memory";
-
-#if GL_ARB_imaging
- case GL_TABLE_TOO_LARGE:
- return "Table Too Large";
-#endif
-
-#if defined(WITH_GLU)
- case GLU_INVALID_ENUM:
- return "Invalid Enum (GLU)";
-
- case GLU_INVALID_VALUE:
- return "Invalid Value (GLU)";
-
- case GLU_OUT_OF_MEMORY:
- return "Out of Memory (GLU)";
-#endif
-
- default:
- return "<unknown error>";
- }
-}
-
-
-/* Debug callbacks need the same calling convention as OpenGL functions.
- */
-#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
- /* Win32 but not WinCE */
-# define APIENTRY __stdcall
-#else
-# define APIENTRY
-#endif
+/* Debug callbacks need the same calling convention as OpenGL functions. */
+# if defined(_WIN32)
+# define APIENTRY __stdcall
+# else
+# define APIENTRY
+# endif
static const char *source_name(GLenum source)
@@ -189,32 +85,11 @@ static const char *message_type_name(GLenum message)
}
}
-static const char *category_name_amd(GLenum category)
-{
- switch (category) {
- case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error";
- case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system";
- case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior";
- case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior";
- case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance";
- case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler";
- case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application";
- case GL_DEBUG_CATEGORY_OTHER_AMD: return "other";
- default: return "???";
- }
-}
-
-
static void APIENTRY gpu_debug_proc(
GLenum source, GLenum type, GLuint UNUSED(id),
GLenum severity, GLsizei UNUSED(length),
const GLchar *message, const GLvoid *UNUSED(userParm))
{
- if (type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) {
- /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */
- return;
- }
-
bool backtrace = false;
switch (severity) {
@@ -233,18 +108,28 @@ static void APIENTRY gpu_debug_proc(
}
}
+# if LEGACY_DEBUG
+
+static const char *category_name_amd(GLenum category)
+{
+ switch (category) {
+ case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error";
+ case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system";
+ case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior";
+ case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior";
+ case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance";
+ case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler";
+ case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application";
+ case GL_DEBUG_CATEGORY_OTHER_AMD: return "other";
+ default: return "???";
+ }
+}
-#ifndef GLEW_ES_ONLY
static void APIENTRY gpu_debug_proc_amd(
GLuint UNUSED(id), GLenum category,
GLenum severity, GLsizei UNUSED(length),
const GLchar *message, GLvoid *UNUSED(userParm))
{
- if (category == GL_DEBUG_CATEGORY_DEPRECATION_AMD) {
- /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */
- return;
- }
-
bool backtrace = false;
switch (severity) {
@@ -261,148 +146,88 @@ static void APIENTRY gpu_debug_proc_amd(
fflush(stderr);
}
}
-#endif
+# endif /* LEGACY_DEBUG */
-
-#undef APIENTRY
+# undef APIENTRY
+#endif /* not Apple */
void gpu_debug_init(void)
{
+#ifdef __APPLE__
+ fprintf(stderr, "OpenGL debug callback is not available on Apple.\n");
+#else /* not Apple */
const char success[] = "Successfully hooked OpenGL debug callback.";
-#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY)
- if (GLEW_VERSION_4_3) {
- fprintf(stderr, "Using OpenGL 4.3 debug facilities\n");
- glEnable(GL_DEBUG_OUTPUT);
- glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
- glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext());
- glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(success);
- return;
- }
-#endif
-
- if (GLEW_KHR_debug) {
-#ifndef GLEW_ES_ONLY
- fprintf(stderr, "Using KHR_debug extension\n");
+ if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
+ fprintf(stderr, "Using %s\n", GLEW_VERSION_4_3 ? "OpenGL 4.3 debug facilities" : "KHR_debug extension");
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
- glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext());
+ glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, NULL);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
GPU_string_marker(success);
-#endif
- return;
}
-
-#ifndef GLEW_ES_ONLY
- if (GLEW_ARB_debug_output) {
+ else if (GLEW_ARB_debug_output) {
fprintf(stderr, "Using ARB_debug_output extension\n");
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
- glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, mxGetCurrentContext());
+ glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, NULL);
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
GPU_string_marker(success);
-
- return;
}
-
- if (GLEW_AMD_debug_output) {
+# if LEGACY_DEBUG
+ else if (GLEW_AMD_debug_output) {
fprintf(stderr, "Using AMD_debug_output extension\n");
- glDebugMessageCallbackAMD(gpu_debug_proc_amd, mxGetCurrentContext());
+ glDebugMessageCallbackAMD(gpu_debug_proc_amd, NULL);
glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
GPU_string_marker(success);
-
- return;
}
-#endif
-
- fprintf(stderr, "Failed to hook OpenGL debug callback.\n");
-
- return;
+# endif
+ else {
+ fprintf(stderr, "Failed to hook OpenGL debug callback.\n");
+ }
+#endif /* not Apple */
}
void gpu_debug_exit(void)
{
-#ifndef WITH_GLEW_ES
-#ifndef GLEW_ES_ONLY
- if (GLEW_VERSION_4_3) {
- glDebugMessageCallback(NULL, NULL);
-
- return;
- }
-#endif
-#endif
-
- if (GLEW_KHR_debug) {
-#ifndef GLEW_ES_ONLY
+#ifndef __APPLE__
+ if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
glDebugMessageCallback(NULL, NULL);
-#endif
- return;
}
-
-#ifndef GLEW_ES_ONLY
- if (GLEW_ARB_debug_output) {
+ else if (GLEW_ARB_debug_output) {
glDebugMessageCallbackARB(NULL, NULL);
-
- return;
}
-
- if (GLEW_AMD_debug_output) {
+# if LEGACY_DEBUG
+ else if (GLEW_AMD_debug_output) {
glDebugMessageCallbackAMD(NULL, NULL);
-
- return;
}
+# endif
#endif
-
- return;
}
void GPU_string_marker(const char *buf)
{
-#ifndef WITH_GLEW_ES
-#ifndef GLEW_ES_ONLY
- if (GLEW_VERSION_4_3) {
- glDebugMessageInsert(
- GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
- GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf);
-
- return;
- }
-#endif
-#endif
-
- if (GLEW_KHR_debug) {
-#ifndef GLEW_ES_ONLY
+#ifdef __APPLE__
+ UNUSED_VARS(buf);
+#else /* not Apple */
+ if (GLEW_VERSION_4_3 || GLEW_KHR_debug) {
glDebugMessageInsert(
GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf);
-#endif
- return;
}
-
-#ifndef GLEW_ES_ONLY
- if (GLEW_ARB_debug_output) {
+ else if (GLEW_ARB_debug_output) {
glDebugMessageInsertARB(
GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0,
GL_DEBUG_SEVERITY_LOW_ARB, -1, buf);
-
- return;
}
-
- if (GLEW_AMD_debug_output) {
+# if LEGACY_DEBUG
+ else if (GLEW_AMD_debug_output) {
glDebugMessageInsertAMD(
GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0,
0, buf);
-
- return;
}
-
- if (GLEW_GREMEDY_string_marker) {
- glStringMarkerGREMEDY(0, buf);
-
- return;
- }
-#endif
+# endif
+#endif /* not Apple */
}
void GPU_print_error_debug(const char *str)
@@ -410,406 +235,3 @@ void GPU_print_error_debug(const char *str)
if (G.debug & G_DEBUG)
fprintf(stderr, "GPU: %s\n", str);
}
-
-
-void GPU_assert_no_gl_errors(const char *file, int line, const char *str)
-{
- if (G.debug) {
- GLboolean gl_ok = gpu_report_gl_errors(file, line, str);
-
- BLI_assert(gl_ok);
- (void) gl_ok;
- }
-}
-
-
-static void gpu_state_print_fl_ex(const char *name, GLenum type)
-{
-#define MAX_ARRAY_SIZE 64
-
- const unsigned char err_mark[4] = {0xff, 0xff, 0xff, 0xff};
-
- float value[MAX_ARRAY_SIZE];
- int a;
-
- memset(value, 0xff, sizeof(value));
- glGetFloatv(type, value);
-
- if (glGetError() == GL_NO_ERROR) {
- printf("%s: ", name);
- for (a = 0; a < MAX_ARRAY_SIZE; a++) {
- if (memcmp(&value[a], err_mark, sizeof(value[a])) == 0) {
- break;
- }
- printf("%.2f ", value[a]);
- }
- printf("\n");
- }
-
-#undef MAX_ARRAY_SIZE
-}
-
-#define gpu_state_print_fl(val) gpu_state_print_fl_ex(#val, val)
-
-void GPU_state_print(void)
-{
- GPU_ASSERT_NO_GL_ERRORS("GPU_state_print"); /* clear any errors */
-
- gpu_state_print_fl(GL_ACCUM_ALPHA_BITS);
- gpu_state_print_fl(GL_ACCUM_BLUE_BITS);
- gpu_state_print_fl(GL_ACCUM_CLEAR_VALUE);
- gpu_state_print_fl(GL_ACCUM_GREEN_BITS);
- gpu_state_print_fl(GL_ACCUM_RED_BITS);
- gpu_state_print_fl(GL_ACTIVE_TEXTURE);
- gpu_state_print_fl(GL_ALIASED_LINE_WIDTH_RANGE);
- gpu_state_print_fl(GL_ALIASED_POINT_SIZE_RANGE);
- gpu_state_print_fl(GL_ALPHA_BIAS);
- gpu_state_print_fl(GL_ALPHA_BITS);
- gpu_state_print_fl(GL_ALPHA_SCALE);
- gpu_state_print_fl(GL_ALPHA_TEST);
- gpu_state_print_fl(GL_ALPHA_TEST_FUNC);
- gpu_state_print_fl(GL_ALPHA_TEST_REF);
- gpu_state_print_fl(GL_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_ATTRIB_STACK_DEPTH);
- gpu_state_print_fl(GL_AUTO_NORMAL);
- gpu_state_print_fl(GL_AUX_BUFFERS);
- gpu_state_print_fl(GL_BLEND);
- gpu_state_print_fl(GL_BLEND_COLOR);
- gpu_state_print_fl(GL_BLEND_DST_ALPHA);
- gpu_state_print_fl(GL_BLEND_DST_RGB);
- gpu_state_print_fl(GL_BLEND_EQUATION_ALPHA);
- gpu_state_print_fl(GL_BLEND_EQUATION_RGB);
- gpu_state_print_fl(GL_BLEND_SRC_ALPHA);
- gpu_state_print_fl(GL_BLEND_SRC_RGB);
- gpu_state_print_fl(GL_BLUE_BIAS);
- gpu_state_print_fl(GL_BLUE_BITS);
- gpu_state_print_fl(GL_BLUE_SCALE);
- gpu_state_print_fl(GL_CLIENT_ACTIVE_TEXTURE);
- gpu_state_print_fl(GL_CLIENT_ATTRIB_STACK_DEPTH);
- gpu_state_print_fl(GL_CLIP_PLANE0);
- gpu_state_print_fl(GL_COLOR_ARRAY);
- gpu_state_print_fl(GL_COLOR_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_COLOR_ARRAY_SIZE);
- gpu_state_print_fl(GL_COLOR_ARRAY_STRIDE);
- gpu_state_print_fl(GL_COLOR_ARRAY_TYPE);
- gpu_state_print_fl(GL_COLOR_CLEAR_VALUE);
- gpu_state_print_fl(GL_COLOR_LOGIC_OP);
- gpu_state_print_fl(GL_COLOR_MATERIAL);
- gpu_state_print_fl(GL_COLOR_MATERIAL_FACE);
- gpu_state_print_fl(GL_COLOR_MATERIAL_PARAMETER);
- gpu_state_print_fl(GL_COLOR_MATRIX);
- gpu_state_print_fl(GL_COLOR_MATRIX_STACK_DEPTH);
- gpu_state_print_fl(GL_COLOR_SUM);
- gpu_state_print_fl(GL_COLOR_TABLE);
- gpu_state_print_fl(GL_COLOR_WRITEMASK);
- gpu_state_print_fl(GL_NUM_COMPRESSED_TEXTURE_FORMATS);
- gpu_state_print_fl(GL_COMPRESSED_TEXTURE_FORMATS);
- gpu_state_print_fl(GL_CONVOLUTION_1D);
- gpu_state_print_fl(GL_CONVOLUTION_2D);
- gpu_state_print_fl(GL_CULL_FACE);
- gpu_state_print_fl(GL_CULL_FACE_MODE);
- gpu_state_print_fl(GL_CURRENT_COLOR);
- gpu_state_print_fl(GL_CURRENT_FOG_COORD);
- gpu_state_print_fl(GL_CURRENT_INDEX);
- gpu_state_print_fl(GL_CURRENT_NORMAL);
- gpu_state_print_fl(GL_CURRENT_PROGRAM);
- gpu_state_print_fl(GL_CURRENT_RASTER_COLOR);
- gpu_state_print_fl(GL_CURRENT_RASTER_DISTANCE);
- gpu_state_print_fl(GL_CURRENT_RASTER_INDEX);
- gpu_state_print_fl(GL_CURRENT_RASTER_POSITION);
- gpu_state_print_fl(GL_CURRENT_RASTER_POSITION_VALID);
- gpu_state_print_fl(GL_CURRENT_RASTER_SECONDARY_COLOR);
- gpu_state_print_fl(GL_CURRENT_RASTER_TEXTURE_COORDS);
- gpu_state_print_fl(GL_CURRENT_SECONDARY_COLOR);
- gpu_state_print_fl(GL_CURRENT_TEXTURE_COORDS);
- gpu_state_print_fl(GL_DEPTH_BIAS);
- gpu_state_print_fl(GL_DEPTH_BITS);
- gpu_state_print_fl(GL_DEPTH_CLEAR_VALUE);
- gpu_state_print_fl(GL_DEPTH_FUNC);
- gpu_state_print_fl(GL_DEPTH_RANGE);
- gpu_state_print_fl(GL_DEPTH_SCALE);
- gpu_state_print_fl(GL_DEPTH_TEST);
- gpu_state_print_fl(GL_DEPTH_WRITEMASK);
- gpu_state_print_fl(GL_DITHER);
- gpu_state_print_fl(GL_DOUBLEBUFFER);
- gpu_state_print_fl(GL_DRAW_BUFFER);
- gpu_state_print_fl(GL_DRAW_BUFFER0);
- gpu_state_print_fl(GL_EDGE_FLAG);
- gpu_state_print_fl(GL_EDGE_FLAG_ARRAY);
- gpu_state_print_fl(GL_EDGE_FLAG_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_EDGE_FLAG_ARRAY_STRIDE);
- gpu_state_print_fl(GL_ELEMENT_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_FEEDBACK_BUFFER_SIZE);
- gpu_state_print_fl(GL_FEEDBACK_BUFFER_TYPE);
- gpu_state_print_fl(GL_FOG);
- gpu_state_print_fl(GL_FOG_COLOR);
- gpu_state_print_fl(GL_FOG_COORD_ARRAY);
- gpu_state_print_fl(GL_FOG_COORD_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_FOG_COORD_ARRAY_STRIDE);
- gpu_state_print_fl(GL_FOG_COORD_ARRAY_TYPE);
- gpu_state_print_fl(GL_FOG_COORD_SRC);
- gpu_state_print_fl(GL_FOG_DENSITY);
- gpu_state_print_fl(GL_FOG_END);
- gpu_state_print_fl(GL_FOG_HINT);
- gpu_state_print_fl(GL_FOG_INDEX);
- gpu_state_print_fl(GL_FOG_MODE);
- gpu_state_print_fl(GL_FOG_START);
- gpu_state_print_fl(GL_FRAGMENT_PROGRAM_ARB); /* TODO: remove ARB program support */
- gpu_state_print_fl(GL_FRAGMENT_SHADER_DERIVATIVE_HINT);
- gpu_state_print_fl(GL_FRONT_FACE);
- gpu_state_print_fl(GL_GENERATE_MIPMAP_HINT);
- gpu_state_print_fl(GL_GREEN_BIAS);
- gpu_state_print_fl(GL_GREEN_BITS);
- gpu_state_print_fl(GL_GREEN_SCALE);
- gpu_state_print_fl(GL_HISTOGRAM);
- gpu_state_print_fl(GL_INDEX_ARRAY);
- gpu_state_print_fl(GL_INDEX_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_INDEX_ARRAY_STRIDE);
- gpu_state_print_fl(GL_INDEX_ARRAY_TYPE);
- gpu_state_print_fl(GL_INDEX_BITS);
- gpu_state_print_fl(GL_INDEX_CLEAR_VALUE);
- gpu_state_print_fl(GL_INDEX_LOGIC_OP);
- gpu_state_print_fl(GL_INDEX_MODE);
- gpu_state_print_fl(GL_INDEX_OFFSET);
- gpu_state_print_fl(GL_INDEX_SHIFT);
- gpu_state_print_fl(GL_INDEX_WRITEMASK);
- gpu_state_print_fl(GL_LIGHT0);
- gpu_state_print_fl(GL_LIGHT1);
- gpu_state_print_fl(GL_LIGHT2);
- gpu_state_print_fl(GL_LIGHT3);
- gpu_state_print_fl(GL_LIGHT4);
- gpu_state_print_fl(GL_LIGHT5);
- gpu_state_print_fl(GL_LIGHT6);
- gpu_state_print_fl(GL_LIGHT7);
- gpu_state_print_fl(GL_LIGHTING);
- gpu_state_print_fl(GL_LIGHT_MODEL_AMBIENT);
- gpu_state_print_fl(GL_LIGHT_MODEL_COLOR_CONTROL);
- gpu_state_print_fl(GL_LIGHT_MODEL_LOCAL_VIEWER);
- gpu_state_print_fl(GL_LIGHT_MODEL_TWO_SIDE);
- gpu_state_print_fl(GL_LINE_SMOOTH);
- gpu_state_print_fl(GL_LINE_SMOOTH_HINT);
- gpu_state_print_fl(GL_LINE_STIPPLE);
- gpu_state_print_fl(GL_LINE_STIPPLE_PATTERN);
- gpu_state_print_fl(GL_LINE_STIPPLE_REPEAT);
- gpu_state_print_fl(GL_LINE_WIDTH);
- gpu_state_print_fl(GL_LINE_WIDTH_GRANULARITY);
- gpu_state_print_fl(GL_LINE_WIDTH_RANGE);
- gpu_state_print_fl(GL_LIST_BASE);
- gpu_state_print_fl(GL_LIST_INDEX);
- gpu_state_print_fl(GL_LIST_MODE);
- gpu_state_print_fl(GL_LOGIC_OP);
- gpu_state_print_fl(GL_LOGIC_OP_MODE);
- gpu_state_print_fl(GL_MAP1_COLOR_4);
- gpu_state_print_fl(GL_MAP1_GRID_DOMAIN);
- gpu_state_print_fl(GL_MAP1_GRID_SEGMENTS);
- gpu_state_print_fl(GL_MAP1_INDEX);
- gpu_state_print_fl(GL_MAP1_NORMAL);
- gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_1);
- gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_2);
- gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_3);
- gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_4);
- gpu_state_print_fl(GL_MAP1_VERTEX_3);
- gpu_state_print_fl(GL_MAP1_VERTEX_4);
- gpu_state_print_fl(GL_MAP2_COLOR_4);
- gpu_state_print_fl(GL_MAP2_GRID_DOMAIN);
- gpu_state_print_fl(GL_MAP2_GRID_SEGMENTS);
- gpu_state_print_fl(GL_MAP2_INDEX);
- gpu_state_print_fl(GL_MAP2_NORMAL);
- gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_1);
- gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_2);
- gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_3);
- gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_4);
- gpu_state_print_fl(GL_MAP2_VERTEX_3);
- gpu_state_print_fl(GL_MAP2_VERTEX_4);
- gpu_state_print_fl(GL_MAP_COLOR);
- gpu_state_print_fl(GL_MAP_STENCIL);
- gpu_state_print_fl(GL_MATRIX_MODE);
- gpu_state_print_fl(GL_MAX_3D_TEXTURE_SIZE);
- gpu_state_print_fl(GL_MAX_ATTRIB_STACK_DEPTH);
- gpu_state_print_fl(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH);
- gpu_state_print_fl(GL_MAX_CLIP_PLANES);
- gpu_state_print_fl(GL_MAX_COLOR_MATRIX_STACK_DEPTH);
- gpu_state_print_fl(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- gpu_state_print_fl(GL_MAX_CUBE_MAP_TEXTURE_SIZE);
- gpu_state_print_fl(GL_MAX_DRAW_BUFFERS);
- gpu_state_print_fl(GL_MAX_ELEMENTS_INDICES);
- gpu_state_print_fl(GL_MAX_ELEMENTS_VERTICES);
- gpu_state_print_fl(GL_MAX_EVAL_ORDER);
- gpu_state_print_fl(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS);
- gpu_state_print_fl(GL_MAX_LIGHTS);
- gpu_state_print_fl(GL_MAX_LIST_NESTING);
- gpu_state_print_fl(GL_MAX_MODELVIEW_STACK_DEPTH);
- gpu_state_print_fl(GL_MAX_NAME_STACK_DEPTH);
- gpu_state_print_fl(GL_MAX_PIXEL_MAP_TABLE);
- gpu_state_print_fl(GL_MAX_PROJECTION_STACK_DEPTH);
- gpu_state_print_fl(GL_MAX_TEXTURE_COORDS);
- gpu_state_print_fl(GL_MAX_TEXTURE_IMAGE_UNITS);
- gpu_state_print_fl(GL_MAX_TEXTURE_LOD_BIAS);
- gpu_state_print_fl(GL_MAX_TEXTURE_SIZE);
- gpu_state_print_fl(GL_MAX_TEXTURE_STACK_DEPTH);
- gpu_state_print_fl(GL_MAX_TEXTURE_UNITS);
- gpu_state_print_fl(GL_MAX_VARYING_FLOATS);
- gpu_state_print_fl(GL_MAX_VERTEX_ATTRIBS);
- gpu_state_print_fl(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
- gpu_state_print_fl(GL_MAX_VERTEX_UNIFORM_COMPONENTS);
- gpu_state_print_fl(GL_MAX_VIEWPORT_DIMS);
- gpu_state_print_fl(GL_MINMAX);
- gpu_state_print_fl(GL_MODELVIEW_MATRIX);
- gpu_state_print_fl(GL_MODELVIEW_STACK_DEPTH);
- gpu_state_print_fl(GL_MULTISAMPLE);
- gpu_state_print_fl(GL_NAME_STACK_DEPTH);
- gpu_state_print_fl(GL_NORMALIZE);
- gpu_state_print_fl(GL_NORMAL_ARRAY);
- gpu_state_print_fl(GL_NORMAL_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_NORMAL_ARRAY_STRIDE);
- gpu_state_print_fl(GL_NORMAL_ARRAY_TYPE);
- gpu_state_print_fl(GL_NUM_COMPRESSED_TEXTURE_FORMATS);
- gpu_state_print_fl(GL_PACK_ALIGNMENT);
- gpu_state_print_fl(GL_PACK_IMAGE_HEIGHT);
- gpu_state_print_fl(GL_PACK_LSB_FIRST);
- gpu_state_print_fl(GL_PACK_ROW_LENGTH);
- gpu_state_print_fl(GL_PACK_SKIP_IMAGES);
- gpu_state_print_fl(GL_PACK_SKIP_PIXELS);
- gpu_state_print_fl(GL_PACK_SKIP_ROWS);
- gpu_state_print_fl(GL_PACK_SWAP_BYTES);
- gpu_state_print_fl(GL_PERSPECTIVE_CORRECTION_HINT);
- gpu_state_print_fl(GL_PIXEL_MAP_A_TO_A_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_B_TO_B_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_G_TO_G_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_I_TO_A_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_I_TO_B_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_I_TO_G_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_I_TO_I_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_I_TO_R_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_R_TO_R_SIZE);
- gpu_state_print_fl(GL_PIXEL_MAP_S_TO_S_SIZE);
- gpu_state_print_fl(GL_PIXEL_PACK_BUFFER_BINDING);
- gpu_state_print_fl(GL_PIXEL_UNPACK_BUFFER_BINDING);
- gpu_state_print_fl(GL_POINT_DISTANCE_ATTENUATION);
- gpu_state_print_fl(GL_POINT_FADE_THRESHOLD_SIZE);
- gpu_state_print_fl(GL_POINT_SIZE);
- gpu_state_print_fl(GL_POINT_SIZE_GRANULARITY);
- gpu_state_print_fl(GL_POINT_SIZE_MAX);
- gpu_state_print_fl(GL_POINT_SIZE_MIN);
- gpu_state_print_fl(GL_POINT_SIZE_RANGE);
- gpu_state_print_fl(GL_POINT_SMOOTH);
- gpu_state_print_fl(GL_POINT_SMOOTH_HINT);
- gpu_state_print_fl(GL_POINT_SPRITE);
- gpu_state_print_fl(GL_POLYGON_MODE);
- gpu_state_print_fl(GL_POLYGON_OFFSET_FACTOR);
- gpu_state_print_fl(GL_POLYGON_OFFSET_FILL);
- gpu_state_print_fl(GL_POLYGON_OFFSET_LINE);
- gpu_state_print_fl(GL_POLYGON_OFFSET_POINT);
- gpu_state_print_fl(GL_POLYGON_OFFSET_UNITS);
- gpu_state_print_fl(GL_POLYGON_SMOOTH);
- gpu_state_print_fl(GL_POLYGON_SMOOTH_HINT);
- gpu_state_print_fl(GL_POLYGON_STIPPLE);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_ALPHA_BIAS);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_ALPHA_SCALE);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_BLUE_BIAS);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_BLUE_SCALE);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_COLOR_TABLE);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_GREEN_BIAS);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_GREEN_SCALE);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_RED_BIAS);
- gpu_state_print_fl(GL_POST_COLOR_MATRIX_RED_SCALE);
- gpu_state_print_fl(GL_POST_CONVOLUTION_ALPHA_BIAS);
- gpu_state_print_fl(GL_POST_CONVOLUTION_ALPHA_SCALE);
- gpu_state_print_fl(GL_POST_CONVOLUTION_BLUE_BIAS);
- gpu_state_print_fl(GL_POST_CONVOLUTION_BLUE_SCALE);
- gpu_state_print_fl(GL_POST_CONVOLUTION_COLOR_TABLE);
- gpu_state_print_fl(GL_POST_CONVOLUTION_GREEN_BIAS);
- gpu_state_print_fl(GL_POST_CONVOLUTION_GREEN_SCALE);
- gpu_state_print_fl(GL_POST_CONVOLUTION_RED_BIAS);
- gpu_state_print_fl(GL_POST_CONVOLUTION_RED_SCALE);
- gpu_state_print_fl(GL_PROJECTION_MATRIX);
- gpu_state_print_fl(GL_PROJECTION_STACK_DEPTH);
- gpu_state_print_fl(GL_READ_BUFFER);
- gpu_state_print_fl(GL_RED_BIAS);
- gpu_state_print_fl(GL_RED_BITS);
- gpu_state_print_fl(GL_RED_SCALE);
- gpu_state_print_fl(GL_RENDER_MODE);
- gpu_state_print_fl(GL_RESCALE_NORMAL);
- gpu_state_print_fl(GL_RGBA_MODE);
- gpu_state_print_fl(GL_SAMPLES);
- gpu_state_print_fl(GL_SAMPLE_BUFFERS);
- gpu_state_print_fl(GL_SAMPLE_COVERAGE_INVERT);
- gpu_state_print_fl(GL_SAMPLE_COVERAGE_VALUE);
- gpu_state_print_fl(GL_SCISSOR_BOX);
- gpu_state_print_fl(GL_SCISSOR_TEST);
- gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY);
- gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_SIZE);
- gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_STRIDE);
- gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_TYPE);
- gpu_state_print_fl(GL_SELECTION_BUFFER_SIZE);
- gpu_state_print_fl(GL_SEPARABLE_2D);
- gpu_state_print_fl(GL_SHADE_MODEL);
- gpu_state_print_fl(GL_SMOOTH_LINE_WIDTH_GRANULARITY);
- gpu_state_print_fl(GL_SMOOTH_LINE_WIDTH_RANGE);
- gpu_state_print_fl(GL_SMOOTH_POINT_SIZE_GRANULARITY);
- gpu_state_print_fl(GL_SMOOTH_POINT_SIZE_RANGE);
- gpu_state_print_fl(GL_STENCIL_BACK_FAIL);
- gpu_state_print_fl(GL_STENCIL_BACK_FUNC);
- gpu_state_print_fl(GL_STENCIL_BACK_PASS_DEPTH_FAIL);
- gpu_state_print_fl(GL_STENCIL_BACK_PASS_DEPTH_PASS);
- gpu_state_print_fl(GL_STENCIL_BACK_REF);
- gpu_state_print_fl(GL_STENCIL_BACK_VALUE_MASK);
- gpu_state_print_fl(GL_STENCIL_BACK_WRITEMASK);
- gpu_state_print_fl(GL_STENCIL_BITS);
- gpu_state_print_fl(GL_STENCIL_CLEAR_VALUE);
- gpu_state_print_fl(GL_STENCIL_FAIL);
- gpu_state_print_fl(GL_STENCIL_FUNC);
- gpu_state_print_fl(GL_STENCIL_PASS_DEPTH_FAIL);
- gpu_state_print_fl(GL_STENCIL_PASS_DEPTH_PASS);
- gpu_state_print_fl(GL_STENCIL_REF);
- gpu_state_print_fl(GL_STENCIL_TEST);
- gpu_state_print_fl(GL_STENCIL_VALUE_MASK);
- gpu_state_print_fl(GL_STENCIL_WRITEMASK);
- gpu_state_print_fl(GL_STEREO);
- gpu_state_print_fl(GL_SUBPIXEL_BITS);
- gpu_state_print_fl(GL_TEXTURE_1D);
- gpu_state_print_fl(GL_TEXTURE_2D);
- gpu_state_print_fl(GL_TEXTURE_3D);
- gpu_state_print_fl(GL_TEXTURE_BINDING_1D);
- gpu_state_print_fl(GL_TEXTURE_BINDING_2D);
- gpu_state_print_fl(GL_TEXTURE_BINDING_3D);
- gpu_state_print_fl(GL_TEXTURE_BINDING_CUBE_MAP);
- gpu_state_print_fl(GL_TEXTURE_COMPRESSION_HINT);
- gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY);
- gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_SIZE);
- gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_STRIDE);
- gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_TYPE);
- gpu_state_print_fl(GL_TEXTURE_CUBE_MAP);
- gpu_state_print_fl(GL_TEXTURE_GEN_Q);
- gpu_state_print_fl(GL_TEXTURE_GEN_R);
- gpu_state_print_fl(GL_TEXTURE_GEN_S);
- gpu_state_print_fl(GL_TEXTURE_GEN_T);
- gpu_state_print_fl(GL_TEXTURE_MATRIX);
- gpu_state_print_fl(GL_TEXTURE_STACK_DEPTH);
- gpu_state_print_fl(GL_TRANSPOSE_COLOR_MATRIX);
- gpu_state_print_fl(GL_TRANSPOSE_MODELVIEW_MATRIX);
- gpu_state_print_fl(GL_TRANSPOSE_PROJECTION_MATRIX);
- gpu_state_print_fl(GL_TRANSPOSE_TEXTURE_MATRIX);
- gpu_state_print_fl(GL_UNPACK_ALIGNMENT);
- gpu_state_print_fl(GL_UNPACK_IMAGE_HEIGHT);
- gpu_state_print_fl(GL_UNPACK_LSB_FIRST);
- gpu_state_print_fl(GL_UNPACK_ROW_LENGTH);
- gpu_state_print_fl(GL_UNPACK_SKIP_IMAGES);
- gpu_state_print_fl(GL_UNPACK_SKIP_PIXELS);
- gpu_state_print_fl(GL_UNPACK_SKIP_ROWS);
- gpu_state_print_fl(GL_UNPACK_SWAP_BYTES);
- gpu_state_print_fl(GL_VERTEX_ARRAY);
- gpu_state_print_fl(GL_VERTEX_ARRAY_BUFFER_BINDING);
- gpu_state_print_fl(GL_VERTEX_ARRAY_SIZE);
- gpu_state_print_fl(GL_VERTEX_ARRAY_STRIDE);
- gpu_state_print_fl(GL_VERTEX_ARRAY_TYPE);
- gpu_state_print_fl(GL_VERTEX_PROGRAM_POINT_SIZE);
- gpu_state_print_fl(GL_VERTEX_PROGRAM_TWO_SIDE);
- gpu_state_print_fl(GL_VIEWPORT);
- gpu_state_print_fl(GL_ZOOM_X);
- gpu_state_print_fl(GL_ZOOM_Y);
-}
-
-#undef gpu_state_print_fl
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 022de6c72fe..347b48bf321 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -31,15 +31,13 @@
* Utility functions for dealing with OpenGL texture & material context,
* mipmap generation and light objects.
*
- * These are some obscure rendering functions shared between the
- * game engine and the blender, in this module to avoid duplication
+ * These are some obscure rendering functions shared between the game engine (not anymore)
+ * and the blender, in this module to avoid duplication
* and abstract them away from the rest a bit.
*/
#include <string.h>
-#include "GPU_glew.h"
-
#include "BLI_blenlib.h"
#include "BLI_hash.h"
#include "BLI_linklist.h"
@@ -64,23 +62,19 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "BKE_bmfont.h"
+#include "BKE_colorband.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_scene.h"
-#include "BKE_DerivedMesh.h"
-#ifdef WITH_GAMEENGINE
-# include "BKE_object.h"
-#endif
-#include "GPU_basic_shader.h"
-#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_glew.h"
#include "GPU_material.h"
+#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -90,150 +84,20 @@
# include "smoke_API.h"
#endif
-#ifdef WITH_OPENSUBDIV
-# include "BKE_subsurf.h"
-# include "BKE_editmesh.h"
-
-# include "gpu_codegen.h"
-#endif
-
-extern Material defmaterial; /* from material.c */
-
-/* Text Rendering */
-
-static void gpu_mcol(unsigned int ucol)
-{
- /* mcol order is swapped */
- const char *cp = (char *)&ucol;
- glColor3ub(cp[3], cp[2], cp[1]);
-}
-
-void GPU_render_text(
- MTexPoly *mtexpoly, int mode,
- const char *textstr, int textlen, unsigned int *col,
- const float *v_quad[4], const float *uv_quad[4],
- int glattrib)
-{
- if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) {
- const float *v1 = v_quad[0];
- const float *v2 = v_quad[1];
- const float *v3 = v_quad[2];
- const float *v4 = v_quad[3];
- Image *ima = (Image *)mtexpoly->tpage;
- const size_t textlen_st = textlen;
- float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
-
- /* multiline */
- float line_start = 0.0f, line_height;
-
- if (v4)
- line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]);
- else
- line_height = max_fff(v1[1], v2[1], v3[1]) - min_fff(v1[1], v2[1], v3[1]);
- line_height *= 1.2f; /* could be an option? */
- /* end multiline */
-
-
- /* color has been set */
- if (mtexpoly->mode & TF_OBCOL)
- col = NULL;
- else if (!col)
- glColor3f(1.0f, 1.0f, 1.0f);
-
- glPushMatrix();
-
- /* get the tab width */
- ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima);
- matrixGlyph(first_ibuf, ' ', &centerx, &centery,
- &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
-
- float advance_tab = advance * 4; /* tab width could also be an option */
-
-
- for (size_t index = 0; index < textlen_st; ) {
- unsigned int character;
- float uv[4][2];
-
- /* lets calculate offset stuff */
- character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index);
-
- if (character == '\n') {
- glTranslatef(line_start, -line_height, 0.0f);
- line_start = 0.0f;
- continue;
- }
- else if (character == '\t') {
- glTranslatef(advance_tab, 0.0f, 0.0f);
- line_start -= advance_tab; /* so we can go back to the start of the line */
- continue;
-
- }
- else if (character > USHRT_MAX) {
- /* not much we can do here bmfonts take ushort */
- character = '?';
- }
-
- /* space starts at offset 1 */
- /* character = character - ' ' + 1; */
- matrixGlyph(first_ibuf, character, & centerx, &centery,
- &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
-
- uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx;
- uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy;
- uv[1][0] = (uv_quad[1][0] - centerx) * sizex + transx;
- uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy;
- uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx;
- uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy;
-
- glBegin(GL_POLYGON);
- if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]);
- else glTexCoord2fv(uv[0]);
- if (col) gpu_mcol(col[0]);
- glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
-
- if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]);
- else glTexCoord2fv(uv[1]);
- if (col) gpu_mcol(col[1]);
- glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
-
- if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[2]);
- else glTexCoord2fv(uv[2]);
- if (col) gpu_mcol(col[2]);
- glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
-
- if (v4) {
- uv[3][0] = (uv_quad[3][0] - centerx) * sizex + transx;
- uv[3][1] = (uv_quad[3][1] - centery) * sizey + transy;
-
- if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[3]);
- else glTexCoord2fv(uv[3]);
- if (col) gpu_mcol(col[3]);
- glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
- }
- glEnd();
-
- glTranslatef(advance, 0.0f, 0.0f);
- line_start -= advance; /* so we can go back to the start of the line */
- }
- glPopMatrix();
-
- BKE_image_release_ibuf(ima, first_ibuf, NULL);
- }
-}
-
-/* Checking powers of two for images since OpenGL ES requires it */
-
+//* Checking powers of two for images since OpenGL ES requires it */
+#ifdef WITH_DDS
static bool is_power_of_2_resolution(int w, int h)
{
return is_power_of_2_i(w) && is_power_of_2_i(h);
}
+#endif
static bool is_over_resolution_limit(GLenum textarget, int w, int h)
{
int size = (textarget == GL_TEXTURE_2D) ?
GPU_max_texture_size() : GPU_max_cube_map_size();
int reslimit = (U.glreslimit != 0) ?
- min_ii(U.glreslimit, size) : size;
+ min_ii(U.glreslimit, size) : size;
return (w > reslimit || h > reslimit);
}
@@ -253,12 +117,6 @@ static int smaller_power_of_2_limit(int num)
/* Current OpenGL state caching for GPU_set_tpage */
static struct GPUTextureState {
- int curtile, tile;
- int curtilemode, tilemode;
- int curtileXRep, tileXRep;
- int curtileYRep, tileYRep;
- Image *ima, *curima;
-
/* also controls min/mag filtering */
bool domipmap;
/* only use when 'domipmap' is set */
@@ -266,11 +124,9 @@ static struct GPUTextureState {
/* store this so that new images created while texture painting won't be set to mipmapped */
bool texpaint;
- int alphablend;
float anisotropic;
int gpu_mipmap;
- MTexPoly *lasttface;
-} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL};
+} GTS = {1, 0, 0, 1.0f, 0};
/* Mipmap settings */
@@ -279,36 +135,13 @@ void GPU_set_gpu_mipmapping(Main *bmain, int gpu_mipmap)
int old_value = GTS.gpu_mipmap;
/* only actually enable if it's supported */
- GTS.gpu_mipmap = gpu_mipmap && GLEW_EXT_framebuffer_object;
+ GTS.gpu_mipmap = gpu_mipmap;
if (old_value != GTS.gpu_mipmap) {
GPU_free_images(bmain);
}
}
-static void gpu_generate_mipmap(GLenum target)
-{
- const bool is_ati = GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY);
- int target_enabled = 0;
-
- /* work around bug in ATI driver, need to have GL_TEXTURE_2D enabled
- * http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation */
- if (is_ati) {
- target_enabled = glIsEnabled(target);
- if (!target_enabled)
- glEnable(target);
- }
-
- /* TODO: simplify when we transition to GL >= 3 */
- if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object)
- glGenerateMipmap(target);
- else if (GLEW_EXT_framebuffer_object)
- glGenerateMipmapEXT(target);
-
- if (is_ati && !target_enabled)
- glDisable(target);
-}
-
void GPU_set_mipmap(Main *bmain, bool mipmap)
{
if (GTS.domipmap != mipmap) {
@@ -381,136 +214,14 @@ float GPU_get_anisotropic(void)
/* Set OpenGL state for an MTFace */
-static void gpu_make_repbind(Image *ima)
-{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ibuf == NULL)
- return;
-
- if (ima->repbind) {
- glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
- MEM_freeN(ima->repbind);
- ima->repbind = NULL;
- ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
- }
-
- ima->totbind = ima->xrep * ima->yrep;
-
- if (ima->totbind > 1) {
- ima->repbind = MEM_callocN(sizeof(int) * ima->totbind, "repbind");
- }
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-}
-
-static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget)
+static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget)
{
- unsigned int *bind = 0;
-
if (textarget == GL_TEXTURE_2D)
- bind = &ima->bindcode[TEXTARGET_TEXTURE_2D];
+ return &ima->gputexture[TEXTARGET_TEXTURE_2D];
else if (textarget == GL_TEXTURE_CUBE_MAP)
- bind = &ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP];
-
- return bind;
-}
-
-void GPU_clear_tpage(bool force)
-{
- if (GTS.lasttface == NULL && !force)
- return;
-
- GTS.lasttface = NULL;
- GTS.curtile = 0;
- GTS.curima = NULL;
- if (GTS.curtilemode != 0) {
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- }
- GTS.curtilemode = 0;
- GTS.curtileXRep = 0;
- GTS.curtileYRep = 0;
- GTS.alphablend = -1;
-
- glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_TEXTURE_GEN_S);
- glDisable(GL_TEXTURE_GEN_T);
- glDisable(GL_ALPHA_TEST);
-}
-
-static void gpu_set_alpha_blend(GPUBlendMode alphablend)
-{
- if (alphablend == GPU_BLEND_SOLID) {
- glDisable(GL_BLEND);
- glDisable(GL_ALPHA_TEST);
- glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
- else if (alphablend == GPU_BLEND_ADD) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- glDisable(GL_ALPHA_TEST);
- glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
- }
- else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) {
- glEnable(GL_BLEND);
- glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
-
- /* for OpenGL render we use the alpha channel, this makes alpha blend correct */
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- /* if U.glalphaclip == 1.0, some cards go bonkers...
- * turn off alpha test in this case */
-
- /* added after 2.45 to clip alpha */
- if (U.glalphaclip == 1.0f) {
- glDisable(GL_ALPHA_TEST);
- }
- else {
- glEnable(GL_ALPHA_TEST);
- glAlphaFunc(GL_GREATER, U.glalphaclip);
- }
- }
- else if (alphablend == GPU_BLEND_CLIP) {
- glDisable(GL_BLEND);
- glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
- glEnable(GL_ALPHA_TEST);
- glAlphaFunc(GL_GREATER, 0.5f);
- }
- else if (alphablend == GPU_BLEND_ALPHA_TO_COVERAGE) {
- glEnable(GL_ALPHA_TEST);
- glAlphaFunc(GL_GREATER, U.glalphaclip);
- glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
- }
-}
-
-static void gpu_verify_alpha_blend(int alphablend)
-{
- /* verify alpha blending modes */
- if (GTS.alphablend == alphablend)
- return;
+ return &ima->gputexture[TEXTARGET_TEXTURE_CUBE_MAP];
- gpu_set_alpha_blend(alphablend);
- GTS.alphablend = alphablend;
-}
-
-static void gpu_verify_reflection(Image *ima)
-{
- if (ima && (ima->flag & IMA_REFLECT)) {
- /* enable reflection mapping */
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
-
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- }
- else {
- /* disable reflection mapping */
- glDisable(GL_TEXTURE_GEN_S);
- glDisable(GL_TEXTURE_GEN_T);
- }
+ return NULL;
}
typedef struct VerifyThreadData {
@@ -518,44 +229,48 @@ typedef struct VerifyThreadData {
float *srgb_frect;
} VerifyThreadData;
-static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect,
- ImBuf *ibuf,
- const int start_line,
- const int height)
+static void gpu_verify_high_bit_srgb_buffer_slice(
+ float *srgb_frect,
+ ImBuf *ibuf,
+ const int start_line,
+ const int height)
{
size_t offset = ibuf->channels * start_line * ibuf->x;
float *current_srgb_frect = srgb_frect + offset;
float *current_rect_float = ibuf->rect_float + offset;
- IMB_buffer_float_from_float(current_srgb_frect,
- current_rect_float,
- ibuf->channels,
- IB_PROFILE_SRGB,
- IB_PROFILE_LINEAR_RGB, true,
- ibuf->x, height,
- ibuf->x, ibuf->x);
+ IMB_buffer_float_from_float(
+ current_srgb_frect,
+ current_rect_float,
+ ibuf->channels,
+ IB_PROFILE_SRGB,
+ IB_PROFILE_LINEAR_RGB, true,
+ ibuf->x, height,
+ ibuf->x, ibuf->x);
IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height);
- /* Clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images. */
- IMB_buffer_float_clamp(current_srgb_frect, ibuf->x, height);
}
-static void verify_thread_do(void *data_v,
- int start_scanline,
- int num_scanlines)
+static void verify_thread_do(
+ void *data_v,
+ int start_scanline,
+ int num_scanlines)
{
VerifyThreadData *data = (VerifyThreadData *)data_v;
- gpu_verify_high_bit_srgb_buffer_slice(data->srgb_frect,
- data->ibuf,
- start_scanline,
- num_scanlines);
+ gpu_verify_high_bit_srgb_buffer_slice(
+ data->srgb_frect,
+ data->ibuf,
+ start_scanline,
+ num_scanlines);
}
-static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect,
- ImBuf *ibuf)
+static void gpu_verify_high_bit_srgb_buffer(
+ float *srgb_frect,
+ ImBuf *ibuf)
{
if (ibuf->y < 64) {
- gpu_verify_high_bit_srgb_buffer_slice(srgb_frect,
- ibuf,
- 0, ibuf->y);
+ gpu_verify_high_bit_srgb_buffer_slice(
+ srgb_frect,
+ ibuf,
+ 0, ibuf->y);
}
else {
VerifyThreadData data;
@@ -565,67 +280,46 @@ static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect,
}
}
-int GPU_verify_image(
- Image *ima, ImageUser *iuser,
- int textarget, int tftile, bool compare, bool mipmap, bool is_data)
+GPUTexture *GPU_texture_from_blender(
+ Image *ima,
+ ImageUser *iuser,
+ int textarget,
+ bool is_data,
+ double UNUSED(time))
{
- unsigned int *bind = NULL;
- int tpx = 0, tpy = 0;
- unsigned int *rect = NULL;
- float *frect = NULL;
- float *srgb_frect = NULL;
- /* flag to determine whether deep format is used */
- bool use_high_bit_depth = false, do_color_management = false;
-
- /* initialize tile mode and number of repeats */
- GTS.ima = ima;
- GTS.tilemode = (ima && (ima->tpageflag & (IMA_TILES | IMA_TWINANIM)));
- GTS.tileXRep = 0;
- GTS.tileYRep = 0;
-
- /* setting current tile according to frame */
- if (ima && (ima->tpageflag & IMA_TWINANIM))
- GTS.tile = ima->lastframe;
- else
- GTS.tile = tftile;
-
- GTS.tile = MAX2(0, GTS.tile);
-
- if (ima) {
- GTS.tileXRep = ima->xrep;
- GTS.tileYRep = ima->yrep;
+ if (ima == NULL) {
+ return NULL;
}
- /* if same image & tile, we're done */
- if (compare && ima == GTS.curima && GTS.curtile == GTS.tile &&
- GTS.tilemode == GTS.curtilemode && GTS.curtileXRep == GTS.tileXRep &&
- GTS.curtileYRep == GTS.tileYRep)
- {
- return (ima != NULL);
+ /* Test if we already have a texture. */
+ GPUTexture **tex = gpu_get_image_gputexture(ima, textarget);
+ if (*tex) {
+ return *tex;
}
- /* if tiling mode or repeat changed, change texture matrix to fit */
- if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep ||
- GTS.curtileYRep != GTS.tileYRep)
- {
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
-
- if (ima && (ima->tpageflag & IMA_TILES))
- glScalef(ima->xrep, ima->yrep, 1.0f);
-
- glMatrixMode(GL_MODELVIEW);
+ /* Check if we have a valid image. If not, we return a dummy
+ * texture with zero bindcode so we don't keep trying. */
+ uint bindcode = 0;
+ if (ima->ok == 0) {
+ *tex = GPU_texture_from_bindcode(textarget, bindcode);
+ return *tex;
}
- /* check if we have a valid image */
- if (ima == NULL || ima->ok == 0)
- return 0;
+ /* currently, tpage refresh is used by ima sequences */
+ if (ima->tpageflag & IMA_TPAGE_REFRESH) {
+ GPU_free_image(ima);
+ ima->tpageflag &= ~IMA_TPAGE_REFRESH;
+ }
/* check if we have a valid image buffer */
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if (ibuf == NULL) {
+ *tex = GPU_texture_from_bindcode(textarget, bindcode);
+ return *tex;
+ }
- if (ibuf == NULL)
- return 0;
+ /* flag to determine whether deep format is used */
+ bool use_high_bit_depth = false, do_color_management = false;
if (ibuf->rect_float) {
if (U.use_16bit_textures) {
@@ -647,121 +341,36 @@ int GPU_verify_image(
}
}
- /* currently, tpage refresh is used by ima sequences */
- if (ima->tpageflag & IMA_TPAGE_REFRESH) {
- GPU_free_image(ima);
- ima->tpageflag &= ~IMA_TPAGE_REFRESH;
- }
-
- if (GTS.tilemode) {
- /* tiled mode */
- if (ima->repbind == NULL) gpu_make_repbind(ima);
- if (GTS.tile >= ima->totbind) GTS.tile = 0;
-
- /* this happens when you change repeat buttons */
- if (ima->repbind && textarget == GL_TEXTURE_2D) bind = &ima->repbind[GTS.tile];
- else bind = gpu_get_image_bindcode(ima, textarget);
-
- if (*bind == 0) {
- short texwindx = ibuf->x / ima->xrep;
- short texwindy = ibuf->y / ima->yrep;
-
- if (GTS.tile >= ima->xrep * ima->yrep)
- GTS.tile = ima->xrep * ima->yrep - 1;
-
- short texwinsy = GTS.tile / ima->xrep;
- short texwinsx = GTS.tile - texwinsy * ima->xrep;
-
- texwinsx *= texwindx;
- texwinsy *= texwindy;
-
- tpx = texwindx;
- tpy = texwindy;
-
- if (use_high_bit_depth) {
- if (do_color_management) {
- srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor");
- gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
- frect = srgb_frect + (4 * (texwinsy * ibuf->x + texwinsx));
- }
- else {
- frect = ibuf->rect_float + (ibuf->channels * (texwinsy * ibuf->x + texwinsx));
- }
- }
- else {
- rect = ibuf->rect + texwinsy * ibuf->x + texwinsx;
- }
- }
- }
- else {
- /* regular image mode */
- bind = gpu_get_image_bindcode(ima, textarget);
-
- if (*bind == 0) {
- tpx = ibuf->x;
- tpy = ibuf->y;
- rect = ibuf->rect;
- if (use_high_bit_depth) {
- if (do_color_management) {
- frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor");
- gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
- }
- else
- frect = ibuf->rect_float;
- }
- }
- }
-
- if (*bind != 0) {
- /* enable opengl drawing with textures */
- glBindTexture(textarget, *bind);
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return *bind;
- }
-
- const int rectw = tpx;
- const int recth = tpy;
-
- unsigned *tilerect = NULL;
- float *ftilerect = NULL;
-
- /* for tiles, copy only part of image into buffer */
- if (GTS.tilemode) {
- if (use_high_bit_depth) {
- ftilerect = MEM_mallocN(rectw * recth * sizeof(*ftilerect), "tilerect");
-
- for (int y = 0; y < recth; y++) {
- const float *frectrow = &frect[y * ibuf->x];
- float *ftilerectrow = &ftilerect[y * rectw];
-
- memcpy(ftilerectrow, frectrow, tpx * sizeof(*frectrow));
- }
+ const int rectw = ibuf->x;
+ const int recth = ibuf->y;
+ uint *rect = ibuf->rect;
+ float *frect = NULL;
+ float *srgb_frect = NULL;
- frect = ftilerect;
+ if (use_high_bit_depth) {
+ if (do_color_management) {
+ frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor");
+ gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf);
}
else {
- tilerect = MEM_mallocN(rectw * recth * sizeof(*tilerect), "tilerect");
-
- for (int y = 0; y < recth; y++) {
- const unsigned *rectrow = &rect[y * ibuf->x];
- unsigned *tilerectrow = &tilerect[y * rectw];
-
- memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow));
- }
-
- rect = tilerect;
+ frect = ibuf->rect_float;
}
}
+ const bool mipmap = GPU_get_mipmap();
+
#ifdef WITH_DDS
- if (ibuf->ftype == IMB_FTYPE_DDS)
- GPU_create_gl_tex_compressed(bind, rect, rectw, recth, textarget, mipmap, ima, ibuf);
+ if (ibuf->ftype == IMB_FTYPE_DDS) {
+ GPU_create_gl_tex_compressed(&bindcode, rect, rectw, recth, textarget, mipmap, ima, ibuf);
+ }
else
#endif
- GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
+ {
+ GPU_create_gl_tex(&bindcode, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
+ }
/* mark as non-color data texture */
- if (*bind) {
+ if (bindcode) {
if (is_data)
ima->tpageflag |= IMA_GLBIND_IS_DATA;
else
@@ -769,21 +378,18 @@ int GPU_verify_image(
}
/* clean up */
- if (tilerect)
- MEM_freeN(tilerect);
- if (ftilerect)
- MEM_freeN(ftilerect);
if (srgb_frect)
MEM_freeN(srgb_frect);
BKE_image_release_ibuf(ima, ibuf, NULL);
- return *bind;
+ *tex = GPU_texture_from_bindcode(textarget, bindcode);
+ return *tex;
}
-static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int recth, bool use_high_bit_depth)
+static void **gpu_gen_cube_map(uint *rect, float *frect, int rectw, int recth, bool use_high_bit_depth)
{
- size_t block_size = use_high_bit_depth ? sizeof(float) * 4 : sizeof(unsigned char) * 4;
+ size_t block_size = use_high_bit_depth ? sizeof(float[4]) : sizeof(uchar[4]);
void **sides = NULL;
int h = recth / 2;
int w = rectw / 3;
@@ -821,7 +427,7 @@ static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int
}
}
else {
- unsigned int **isides = (unsigned int **)sides;
+ uint **isides = (uint **)sides;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
@@ -850,7 +456,7 @@ static void gpu_del_cube_map(void **cube_map)
/* Image *ima can be NULL */
void GPU_create_gl_tex(
- unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
+ uint *bind, uint *rect, float *frect, int rectw, int recth,
int textarget, bool mipmap, bool use_high_bit_depth, Image *ima)
{
ImBuf *ibuf = NULL;
@@ -858,49 +464,23 @@ void GPU_create_gl_tex(
int tpx = rectw;
int tpy = recth;
- /* scale if not a power of two. this is not strictly necessary for newer
- * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures
- * Then don't bother scaling for hardware that supports NPOT textures! */
- if (textarget == GL_TEXTURE_2D &&
- ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) ||
- is_over_resolution_limit(textarget, rectw, recth)))
- {
- rectw = smaller_power_of_2_limit(rectw);
- recth = smaller_power_of_2_limit(recth);
-
- if (use_high_bit_depth) {
- ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
- IMB_scaleImBuf(ibuf, rectw, recth);
-
- frect = ibuf->rect_float;
- }
- else {
- ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
- IMB_scaleImBuf(ibuf, rectw, recth);
-
- rect = ibuf->rect;
- }
- }
-
/* create image */
glGenTextures(1, (GLuint *)bind);
glBindTexture(textarget, *bind);
if (textarget == GL_TEXTURE_2D) {
if (use_high_bit_depth) {
- if (GLEW_ARB_texture_float)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
}
- else
+ else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ }
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
if (GPU_get_mipmap() && mipmap) {
if (GTS.gpu_mipmap) {
- gpu_generate_mipmap(GL_TEXTURE_2D);
+ glGenerateMipmap(GL_TEXTURE_2D);
}
else {
int i;
@@ -917,10 +497,7 @@ void GPU_create_gl_tex(
for (i = 1; i < ibuf->miptot; i++) {
ImBuf *mip = ibuf->mipmap[i - 1];
if (use_high_bit_depth) {
- if (GLEW_ARB_texture_float)
- glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F_ARB, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
- else
- glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
}
else {
glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
@@ -940,7 +517,7 @@ void GPU_create_gl_tex(
if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) {
void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth, use_high_bit_depth);
- GLenum informat = use_high_bit_depth ? (GLEW_ARB_texture_float ? GL_RGBA16F_ARB : GL_RGBA16) : GL_RGBA8;
+ GLenum informat = use_high_bit_depth ? GL_RGBA16F : GL_RGBA8;
GLenum type = use_high_bit_depth ? GL_FLOAT : GL_UNSIGNED_BYTE;
if (cube_map)
@@ -951,7 +528,7 @@ void GPU_create_gl_tex(
if (GPU_get_mipmap() && mipmap) {
if (GTS.gpu_mipmap) {
- gpu_generate_mipmap(GL_TEXTURE_CUBE_MAP);
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
}
else {
if (!ibuf) {
@@ -974,8 +551,9 @@ void GPU_create_gl_tex(
if (mip_cube_map) {
for (int j = 0; j < 6; j++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i,
- informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
+ glTexImage2D(
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i,
+ informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
}
}
gpu_del_cube_map(mip_cube_map);
@@ -1003,6 +581,8 @@ void GPU_create_gl_tex(
if (GLEW_EXT_texture_filter_anisotropic)
glTexParameterf(textarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
+ glBindTexture(textarget, 0);
+
if (ibuf)
IMB_freeImBuf(ibuf);
}
@@ -1055,8 +635,9 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
- glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height,
- 0, size, ibuf->dds_data.data + offset);
+ glCompressedTexImage2D(
+ GL_TEXTURE_2D, i, format, width, height,
+ 0, size, ibuf->dds_data.data + offset);
offset += size;
width >>= 1;
@@ -1074,7 +655,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
}
void GPU_create_gl_tex_compressed(
- unsigned int *bind, unsigned int *pix, int x, int y,
+ uint *bind, uint *pix, int x, int y,
int textarget, int mipmap, Image *ima, ImBuf *ibuf)
{
#ifndef WITH_DDS
@@ -1089,63 +670,9 @@ void GPU_create_gl_tex_compressed(
glDeleteTextures(1, (GLuint *)bind);
GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
}
-#endif
-}
-static void gpu_verify_repeat(Image *ima)
-{
- /* set either clamp or repeat in X/Y */
- if (ima->tpageflag & IMA_CLAMP_U)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- else
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-
- if (ima->tpageflag & IMA_CLAMP_V)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- else
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-}
-
-int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend)
-{
- /* check if we need to clear the state */
- if (mtexpoly == NULL) {
- GPU_clear_tpage(false);
- return 0;
- }
-
- Image *ima = mtexpoly->tpage;
- GTS.lasttface = mtexpoly;
-
- gpu_verify_alpha_blend(alphablend);
- gpu_verify_reflection(ima);
-
- if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, mtexpoly->tile, 1, mipmap, false)) {
- GTS.curtile = GTS.tile;
- GTS.curima = GTS.ima;
- GTS.curtilemode = GTS.tilemode;
- GTS.curtileXRep = GTS.tileXRep;
- GTS.curtileYRep = GTS.tileYRep;
- glEnable(GL_TEXTURE_2D);
- }
- else {
- glDisable(GL_TEXTURE_2D);
-
- GTS.curtile = 0;
- GTS.curima = NULL;
- GTS.curtilemode = 0;
- GTS.curtileXRep = 0;
- GTS.curtileYRep = 0;
-
- return 0;
- }
-
- gpu_verify_repeat(ima);
-
- /* Did this get lost in the image recode? */
- /* BKE_image_tag_time(ima);*/
-
- return 1;
+ glBindTexture(textarget, 0);
+#endif
}
/* these two functions are called on entering and exiting texture paint mode,
@@ -1161,17 +688,13 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
if (mipmap) {
for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
- if (BKE_image_has_bindcode(ima)) {
+ if (BKE_image_has_opengl_texture(ima)) {
if (ima->tpageflag & IMA_MIPMAP_COMPLETE) {
- if (ima->bindcode[TEXTARGET_TEXTURE_2D]) {
- glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
+ if (ima->gputexture[TEXTARGET_TEXTURE_2D]) {
+ GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- }
- if (ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]) {
- glBindTexture(GL_TEXTURE_CUBE_MAP, ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
}
}
else
@@ -1184,16 +707,12 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
}
else {
for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
- if (BKE_image_has_bindcode(ima)) {
- if (ima->bindcode[TEXTARGET_TEXTURE_2D]) {
- glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
+ if (BKE_image_has_opengl_texture(ima)) {
+ if (ima->gputexture[TEXTARGET_TEXTURE_2D]) {
+ GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- }
- if (ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]) {
- glBindTexture(GL_TEXTURE_CUBE_MAP, ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
}
}
else
@@ -1206,9 +725,7 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
/* check if image has been downscaled and do scaled partial update */
static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
{
- if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) ||
- is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y))
- {
+ if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) {
int x_limit = smaller_power_of_2_limit(ibuf->x);
int y_limit = smaller_power_of_2_limit(ibuf->y);
@@ -1228,21 +745,23 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
if (rectw + x > x_limit) rectw--;
if (recth + y > y_limit) recth--;
+ GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
+
/* float rectangles are already continuous in memory so we can use IMB_scaleImBuf */
if (frect) {
ImBuf *ibuf_scale = IMB_allocFromBuffer(NULL, frect, w, h);
IMB_scaleImBuf(ibuf_scale, rectw, recth);
- glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
- GL_FLOAT, ibuf_scale->rect_float);
+ glTexSubImage2D(
+ GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
+ GL_FLOAT, ibuf_scale->rect_float);
IMB_freeImBuf(ibuf_scale);
}
/* byte images are not continuous in memory so do manual interpolation */
else {
- unsigned char *scalerect = MEM_mallocN(rectw * recth * sizeof(*scalerect) * 4, "scalerect");
- unsigned int *p = (unsigned int *)scalerect;
+ uchar *scalerect = MEM_mallocN(rectw * recth * sizeof(*scalerect) * 4, "scalerect");
+ uint *p = (uint *)scalerect;
int i, j;
float inv_xratio = 1.0f / xratio;
float inv_yratio = 1.0f / yratio;
@@ -1250,23 +769,26 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
float u = (x + i) * inv_xratio;
for (j = 0; j < recth; j++) {
float v = (y + j) * inv_yratio;
- bilinear_interpolation_color_wrap(ibuf, (unsigned char *)(p + i + j * (rectw)), NULL, u, v);
+ bilinear_interpolation_color_wrap(ibuf, (uchar *)(p + i + j * (rectw)), NULL, u, v);
}
}
- glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
- GL_UNSIGNED_BYTE, scalerect);
+
+ glTexSubImage2D(
+ GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
+ GL_UNSIGNED_BYTE, scalerect);
MEM_freeN(scalerect);
}
if (GPU_get_mipmap()) {
- gpu_generate_mipmap(GL_TEXTURE_2D);
+ glGenerateMipmap(GL_TEXTURE_2D);
}
else {
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
+ GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
+
return true;
}
@@ -1277,9 +799,8 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
{
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ima->repbind ||
- (!GTS.gpu_mipmap && GPU_get_mipmap()) ||
- (ima->bindcode[TEXTARGET_TEXTURE_2D] == 0) ||
+ if ((!GTS.gpu_mipmap && GPU_get_mipmap()) ||
+ (ima->gputexture[TEXTARGET_TEXTURE_2D] == NULL) ||
(ibuf == NULL) ||
(w == 0) || (h == 0))
{
@@ -1303,7 +824,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
return;
}
- glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
+ GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer);
MEM_freeN(buffer);
@@ -1311,12 +832,14 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
/* we have already accounted for the case where GTS.gpu_mipmap is false
* so we will be using GPU mipmap generation here */
if (GPU_get_mipmap()) {
- gpu_generate_mipmap(GL_TEXTURE_2D);
+ glGenerateMipmap(GL_TEXTURE_2D);
}
else {
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
+ GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
+
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
@@ -1326,7 +849,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
return;
}
- glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
+ GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
@@ -1336,8 +859,9 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
- GL_UNSIGNED_BYTE, ibuf->rect);
+ glTexSubImage2D(
+ GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
+ GL_UNSIGNED_BYTE, ibuf->rect);
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
@@ -1345,70 +869,203 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
/* see comment above as to why we are using gpu mipmap generation here */
if (GPU_get_mipmap()) {
- gpu_generate_mipmap(GL_TEXTURE_2D);
+ glGenerateMipmap(GL_TEXTURE_2D);
}
else {
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
+
+ GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
}
BKE_image_release_ibuf(ima, ibuf, NULL);
}
-void GPU_update_images_framechange(Main *bmain)
-{
- for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
- if (ima->tpageflag & IMA_TWINANIM) {
- if (ima->twend >= ima->xrep * ima->yrep)
- ima->twend = ima->xrep * ima->yrep - 1;
+/* *************************** Transfer functions *************************** */
- /* check: is bindcode not in the array? free. (to do) */
+enum {
+ TFUNC_FLAME_SPECTRUM = 0,
+ TFUNC_COLOR_RAMP = 1,
+};
- ima->lastframe++;
- if (ima->lastframe > ima->twend)
- ima->lastframe = ima->twsta;
+#define TFUNC_WIDTH 256
+
+#ifdef WITH_SMOKE
+static void create_flame_spectrum_texture(float *data)
+{
+#define FIRE_THRESH 7
+#define MAX_FIRE_ALPHA 0.06f
+#define FULL_ON_FIRE 100
+
+ float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
+
+ blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000);
+
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 16; j++) {
+ for (int k = 0; k < TFUNC_WIDTH; k++) {
+ int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4;
+ if (k >= FIRE_THRESH) {
+ spec_pixels[index] = (data[k * 4]);
+ spec_pixels[index + 1] = (data[k * 4 + 1]);
+ spec_pixels[index + 2] = (data[k * 4 + 2]);
+ spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
+ (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
+ }
+ else {
+ zero_v4(&spec_pixels[index]);
+ }
+ }
}
}
+
+ memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH);
+
+ MEM_freeN(spec_pixels);
+
+#undef FIRE_THRESH
+#undef MAX_FIRE_ALPHA
+#undef FULL_ON_FIRE
+}
+
+static void create_color_ramp(const ColorBand *coba, float *data)
+{
+ for (int i = 0; i < TFUNC_WIDTH; i++) {
+ BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]);
+ }
}
-int GPU_update_image_time(Image *ima, double time)
+static GPUTexture *create_transfer_function(int type, const ColorBand *coba)
{
- if (!ima)
- return 0;
+ float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__);
+
+ switch (type) {
+ case TFUNC_FLAME_SPECTRUM:
+ create_flame_spectrum_texture(data);
+ break;
+ case TFUNC_COLOR_RAMP:
+ create_color_ramp(coba, data);
+ break;
+ }
- if (ima->lastupdate < 0)
- ima->lastupdate = 0;
+ GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, GPU_RGBA8, data, NULL);
- if (ima->lastupdate > (float)time)
- ima->lastupdate = (float)time;
+ MEM_freeN(data);
- int inc = 0;
+ return tex;
+}
- if (ima->tpageflag & IMA_TWINANIM) {
- if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1;
+static void swizzle_texture_channel_rrrr(GPUTexture *tex)
+{
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
+ GPU_texture_unbind(tex);
+}
+
+static GPUTexture *create_field_texture(SmokeDomainSettings *sds)
+{
+ float *field = NULL;
- /* check: is the bindcode not in the array? Then free. (still to do) */
+ switch (sds->coba_field) {
+ case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break;
+ case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break;
+ case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break;
+ case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break;
+ case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break;
+ case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break;
+ case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break;
+ case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break;
+ case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break;
+ case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break;
+ case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break;
+ case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break;
+ case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break;
+ case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break;
+ default: return NULL;
+ }
- float diff = (float)((float)time - ima->lastupdate);
- inc = (int)(diff * (float)ima->animspeed);
+ GPUTexture *tex = GPU_texture_create_nD(
+ sds->res[0], sds->res[1], sds->res[2], 3,
+ field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
- ima->lastupdate += ((float)inc / (float)ima->animspeed);
+ swizzle_texture_channel_rrrr(tex);
+ return tex;
+}
- int newframe = ima->lastframe + inc;
+static GPUTexture *create_density_texture(SmokeDomainSettings *sds, int highres)
+{
+ float *data = NULL, *source;
+ int cell_count = (highres) ? smoke_turbulence_get_cells(sds->wt) : sds->total_cells;
+ const bool has_color = (highres) ? smoke_turbulence_has_colors(sds->wt) : smoke_has_colors(sds->fluid);
+ int *dim = (highres) ? sds->res_wt : sds->res;
+ GPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8;
- if (newframe > (int)ima->twend) {
- if (ima->twend - ima->twsta != 0)
- newframe = (int)ima->twsta - 1 + (newframe - ima->twend) % (ima->twend - ima->twsta);
- else
- newframe = ima->twsta;
+ if (has_color) {
+ data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture");
+ }
+
+ if (highres) {
+ if (has_color) {
+ smoke_turbulence_get_rgba(sds->wt, data, 0);
+ }
+ else {
+ source = smoke_turbulence_get_density(sds->wt);
}
+ }
+ else {
+ if (has_color) {
+ smoke_get_rgba(sds->fluid, data, 0);
+ }
+ else {
+ source = smoke_get_density(sds->fluid);
+ }
+ }
- ima->lastframe = newframe;
+ GPUTexture *tex = GPU_texture_create_nD(
+ dim[0], dim[1], dim[2], 3,
+ (has_color) ? data : source,
+ format, GPU_DATA_FLOAT, 0, true, NULL);
+ if (data) {
+ MEM_freeN(data);
}
- return inc;
+ if (format == GPU_R8) {
+ /* Swizzle the RGBA components to read the Red channel so
+ * that the shader stay the same for colored and non color
+ * density textures. */
+ swizzle_texture_channel_rrrr(tex);
+ }
+ return tex;
}
+static GPUTexture *create_flame_texture(SmokeDomainSettings *sds, int highres)
+{
+ float *source = NULL;
+ const bool has_fuel = (highres) ? smoke_turbulence_has_fuel(sds->wt) : smoke_has_fuel(sds->fluid);
+ int *dim = (highres) ? sds->res_wt : sds->res;
+
+ if (!has_fuel)
+ return NULL;
+
+ if (highres) {
+ source = smoke_turbulence_get_flame(sds->wt);
+ }
+ else {
+ source = smoke_get_flame(sds->fluid);
+ }
+
+ GPUTexture *tex = GPU_texture_create_nD(
+ dim[0], dim[1], dim[2], 3,
+ source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
+
+ swizzle_texture_channel_rrrr(tex);
+
+ return tex;
+}
+#endif /* WITH_SMOKE */
void GPU_free_smoke(SmokeModifierData *smd)
{
@@ -1424,53 +1081,116 @@ void GPU_free_smoke(SmokeModifierData *smd)
if (smd->domain->tex_flame)
GPU_texture_free(smd->domain->tex_flame);
smd->domain->tex_flame = NULL;
+
+ if (smd->domain->tex_flame_coba)
+ GPU_texture_free(smd->domain->tex_flame_coba);
+ smd->domain->tex_flame_coba = NULL;
+
+ if (smd->domain->tex_coba)
+ GPU_texture_free(smd->domain->tex_coba);
+ smd->domain->tex_coba = NULL;
+
+ if (smd->domain->tex_field)
+ GPU_texture_free(smd->domain->tex_field);
+ smd->domain->tex_field = NULL;
}
}
-void GPU_create_smoke(SmokeModifierData *smd, int highres)
+void GPU_create_smoke_coba_field(SmokeModifierData *smd)
{
#ifdef WITH_SMOKE
if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
SmokeDomainSettings *sds = smd->domain;
- if (!sds->tex && !highres) {
- /* rgba texture for color + density */
- if (smoke_has_colors(sds->fluid)) {
- float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture");
- smoke_get_rgba(sds->fluid, data, 0);
- sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data);
- MEM_freeN(data);
- }
- /* density only */
- else {
- sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid));
- }
- sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL;
+
+ if (!sds->tex_field) {
+ sds->tex_field = create_field_texture(sds);
}
- else if (!sds->tex && highres) {
- /* rgba texture for color + density */
- if (smoke_turbulence_has_colors(sds->wt)) {
- float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture");
- smoke_turbulence_get_rgba(sds->wt, data, 0);
- sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data);
- MEM_freeN(data);
- }
- /* density only */
- else {
- sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt));
- }
- sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL;
+ if (!sds->tex_coba) {
+ sds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, sds->coba);
}
+ }
+#else // WITH_SMOKE
+ smd->domain->tex_field = NULL;
+#endif // WITH_SMOKE
+}
- sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow);
+void GPU_create_smoke(SmokeModifierData *smd, int highres)
+{
+#ifdef WITH_SMOKE
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ SmokeDomainSettings *sds = smd->domain;
+
+ if (!sds->tex) {
+ sds->tex = create_density_texture(sds, highres);
+ }
+ if (!sds->tex_flame) {
+ sds->tex_flame = create_flame_texture(sds, highres);
+ }
+ if (!sds->tex_flame_coba && sds->tex_flame) {
+ sds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL);
+ }
+ if (!sds->tex_shadow) {
+ sds->tex_shadow = GPU_texture_create_nD(
+ sds->res[0], sds->res[1], sds->res[2], 3,
+ sds->shadow,
+ GPU_R8, GPU_DATA_FLOAT, 0, true, NULL);
+ }
}
#else // WITH_SMOKE
(void)highres;
smd->domain->tex = NULL;
smd->domain->tex_flame = NULL;
+ smd->domain->tex_flame_coba = NULL;
smd->domain->tex_shadow = NULL;
#endif // WITH_SMOKE
}
+void GPU_create_smoke_velocity(SmokeModifierData *smd)
+{
+#ifdef WITH_SMOKE
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
+ SmokeDomainSettings *sds = smd->domain;
+
+ const float *vel_x = smoke_get_velocity_x(sds->fluid);
+ const float *vel_y = smoke_get_velocity_y(sds->fluid);
+ const float *vel_z = smoke_get_velocity_z(sds->fluid);
+
+ if (ELEM(NULL, vel_x, vel_y, vel_z)) {
+ return;
+ }
+
+ if (!sds->tex_velocity_x) {
+ sds->tex_velocity_x = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_x, NULL);
+ sds->tex_velocity_y = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_y, NULL);
+ sds->tex_velocity_z = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_z, NULL);
+ }
+ }
+#else // WITH_SMOKE
+ smd->domain->tex_velocity_x = NULL;
+ smd->domain->tex_velocity_y = NULL;
+ smd->domain->tex_velocity_z = NULL;
+#endif // WITH_SMOKE
+}
+
+/* TODO Unify with the other GPU_free_smoke. */
+void GPU_free_smoke_velocity(SmokeModifierData *smd)
+{
+ if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
+ if (smd->domain->tex_velocity_x)
+ GPU_texture_free(smd->domain->tex_velocity_x);
+
+ if (smd->domain->tex_velocity_y)
+ GPU_texture_free(smd->domain->tex_velocity_y);
+
+ if (smd->domain->tex_velocity_z)
+ GPU_texture_free(smd->domain->tex_velocity_z);
+
+ smd->domain->tex_velocity_x = NULL;
+ smd->domain->tex_velocity_y = NULL;
+ smd->domain->tex_velocity_z = NULL;
+ }
+}
+
static LinkNode *image_free_queue = NULL;
static void gpu_queue_image_for_free(Image *ima)
@@ -1499,9 +1219,6 @@ void GPU_free_unused_buffers(Main *bmain)
BLI_linklist_free(image_free_queue, NULL);
image_free_queue = NULL;
- /* vbo buffers */
- GPU_global_buffer_pool_free_unused();
-
BLI_thread_unlock(LOCK_OPENGL);
}
@@ -1513,11 +1230,6 @@ void GPU_free_image(Image *ima)
}
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- /* free regular image binding */
- if (ima->bindcode[i]) {
- glDeleteTextures(1, (GLuint *)&ima->bindcode[i]);
- ima->bindcode[i] = 0;
- }
/* free glsl image binding */
if (ima->gputexture[i]) {
GPU_texture_free(ima->gputexture[i]);
@@ -1525,14 +1237,6 @@ void GPU_free_image(Image *ima)
}
}
- /* free repeated image binding */
- if (ima->repbind) {
- glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
-
- MEM_freeN(ima->repbind);
- ima->repbind = NULL;
- }
-
ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE | IMA_GLBIND_IS_DATA);
}
@@ -1581,7 +1285,7 @@ void GPU_free_images_old(Main *bmain)
if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
/* If it's in GL memory, deallocate and set time tag to current time
* This gives textures a "second chance" to be used before dying. */
- if (BKE_image_has_bindcode(ima) || ima->repbind) {
+ if (BKE_image_has_opengl_texture(ima)) {
GPU_free_image(ima);
ima->lastused = ctime;
}
@@ -1594,679 +1298,7 @@ void GPU_free_images_old(Main *bmain)
}
}
-
-/* OpenGL Materials */
-
-#define FIXEDMAT 8
-
-/* OpenGL state caching for materials */
-
-typedef struct GPUMaterialFixed {
- float diff[3];
- float spec[3];
- int hard;
- float alpha;
-} GPUMaterialFixed;
-
-static struct GPUMaterialState {
- GPUMaterialFixed (*matbuf);
- GPUMaterialFixed matbuf_fixed[FIXEDMAT];
- int totmat;
-
- /* set when called inside GPU_begin_object_materials / GPU_end_object_materials
- * otherwise calling GPU_object_material_bind returns zero */
- bool is_enabled;
-
- Material **gmatbuf;
- Material *gmatbuf_fixed[FIXEDMAT];
- Material *gboundmat;
- Object *gob;
- DupliObject *dob;
- Scene *gscene;
- int glay;
- bool gscenelock;
- float (*gviewmat)[4];
- float (*gviewinv)[4];
- float (*gviewcamtexcofac);
-
- bool backface_culling;
- bool two_sided_lighting;
-
- GPUBlendMode *alphablend;
- GPUBlendMode alphablend_fixed[FIXEDMAT];
- bool use_alpha_pass, is_alpha_pass;
- bool use_matcaps;
-
- int lastmatnr, lastretval;
- GPUBlendMode lastalphablend;
- bool is_opensubdiv;
-} GMS = {NULL};
-
-/* fixed function material, alpha handed by caller */
-static void gpu_material_to_fixed(
- GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob,
- const int new_shading_nodes, const bool dimdown)
-{
- if (bmat->mode & MA_SHLESS) {
- copy_v3_v3(smat->diff, &bmat->r);
-
- if (gamma)
- linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
-
- zero_v3(smat->spec);
- smat->alpha = 1.0f;
- smat->hard = 0;
- }
- else if (new_shading_nodes) {
- copy_v3_v3(smat->diff, &bmat->r);
- copy_v3_v3(smat->spec, &bmat->specr);
- smat->alpha = 1.0f;
- smat->hard = CLAMPIS(bmat->har, 0, 128);
-
- if (dimdown) {
- mul_v3_fl(smat->diff, 0.8f);
- mul_v3_fl(smat->spec, 0.5f);
- }
-
- if (gamma) {
- linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
- linearrgb_to_srgb_v3_v3(smat->spec, smat->spec);
- }
- }
- else {
- mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit);
-
- if (bmat->shade_flag & MA_OBCOLOR)
- mul_v3_v3(smat->diff, ob->col);
-
- mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec);
- smat->hard = CLAMPIS(bmat->har, 1, 128);
- smat->alpha = 1.0f;
-
- if (gamma) {
- linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
- linearrgb_to_srgb_v3_v3(smat->spec, smat->spec);
- }
- }
-}
-
-static Material *gpu_active_node_material(Material *ma)
-{
- if (ma && ma->use_nodes && ma->nodetree) {
- bNode *node = nodeGetActiveID(ma->nodetree, ID_MA);
-
- if (node)
- return (Material *)node->id;
- else
- return NULL;
- }
-
- return ma;
-}
-
-void GPU_begin_dupli_object(DupliObject *dob)
-{
- GMS.dob = dob;
-}
-
-void GPU_end_dupli_object(void)
-{
- GMS.dob = NULL;
-}
-
-void GPU_begin_object_materials(
- View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob,
- bool glsl, bool *do_alpha_after)
-{
- Material *ma;
- GPUMaterial *gpumat;
- GPUBlendMode alphablend;
- DupliObject *dob;
- int a;
- const bool gamma = BKE_scene_check_color_management_enabled(scene);
- const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
- const bool use_matcap = (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) != 0; /* assumes v3d->defmaterial->preview is set */
- bool use_opensubdiv = false;
-
-#ifdef WITH_OPENSUBDIV
- {
- DerivedMesh *derivedFinal = NULL;
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
- if (em != NULL) {
- derivedFinal = em->derivedFinal;
- }
- else {
- derivedFinal = ob->derivedFinal;
- }
- }
- else {
- derivedFinal = ob->derivedFinal;
- }
-
- if (derivedFinal != NULL && derivedFinal->type == DM_TYPE_CCGDM) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) derivedFinal;
- use_opensubdiv = ccgdm->useGpuBackend;
- }
- }
-#endif
-
-#ifdef WITH_GAMEENGINE
- if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
- ob = BKE_object_lod_matob_get(ob, scene);
- }
-#endif
-
- /* initialize state */
- /* DupliObject must be restored */
- dob = GMS.dob;
- memset(&GMS, 0, sizeof(GMS));
- GMS.is_enabled = true;
- GMS.dob = dob;
- GMS.lastmatnr = -1;
- GMS.lastretval = -1;
- GMS.lastalphablend = GPU_BLEND_SOLID;
- GMS.use_matcaps = use_matcap;
-
- GMS.backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0;
-
- GMS.two_sided_lighting = false;
- if (ob && ob->type == OB_MESH)
- GMS.two_sided_lighting = (((Mesh *)ob->data)->flag & ME_TWOSIDED) != 0;
-
- GMS.gob = ob;
- GMS.gscene = scene;
- GMS.is_opensubdiv = use_opensubdiv;
- GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */
- GMS.glay = (v3d->localvd) ? v3d->localvd->lay : v3d->lay; /* keep lamps visible in local view */
- GMS.gscenelock = (v3d->scenelock != 0);
- GMS.gviewmat = rv3d->viewmat;
- GMS.gviewinv = rv3d->viewinv;
- GMS.gviewcamtexcofac = rv3d->viewcamtexcofac;
-
- /* alpha pass setup. there's various cases to handle here:
- * - object transparency on: only solid materials draw in the first pass,
- * and only transparent in the second 'alpha' pass.
- * - object transparency off: for glsl we draw both in a single pass, and
- * for solid we don't use transparency at all. */
- GMS.use_alpha_pass = (do_alpha_after != NULL);
- GMS.is_alpha_pass = (v3d->transp != false);
- if (GMS.use_alpha_pass)
- *do_alpha_after = false;
-
- if (GMS.totmat > FIXEDMAT) {
- GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf");
- GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf");
- GMS.alphablend = MEM_callocN(sizeof(*GMS.alphablend) * GMS.totmat, "GMS.matbuf");
- }
- else {
- GMS.matbuf = GMS.matbuf_fixed;
- GMS.gmatbuf = GMS.gmatbuf_fixed;
- GMS.alphablend = GMS.alphablend_fixed;
- }
-
- /* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */
- if (use_matcap) {
- GMS.gmatbuf[0] = v3d->defmaterial;
- GPU_material_matcap(scene, v3d->defmaterial, use_opensubdiv);
-
- /* do material 1 too, for displists! */
- memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
-
- GMS.alphablend[0] = GPU_BLEND_SOLID;
- }
- else {
-
- /* no materials assigned? */
- if (ob->totcol == 0) {
- gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true);
-
- /* do material 1 too, for displists! */
- memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
-
- if (glsl) {
- GMS.gmatbuf[0] = &defmaterial;
- GPU_material_from_blender(GMS.gscene, &defmaterial, GMS.is_opensubdiv);
- }
-
- GMS.alphablend[0] = GPU_BLEND_SOLID;
- }
-
- /* setup materials */
- for (a = 1; a <= ob->totcol; a++) {
- /* find a suitable material */
- ma = give_current_material(ob, a);
- if (!glsl && !new_shading_nodes) ma = gpu_active_node_material(ma);
- if (ma == NULL) ma = &defmaterial;
-
- /* create glsl material if requested */
- gpumat = glsl ? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv) : NULL;
-
- if (gpumat) {
- /* do glsl only if creating it succeed, else fallback */
- GMS.gmatbuf[a] = ma;
- alphablend = GPU_material_alpha_blend(gpumat, ob->col);
- }
- else {
- /* fixed function opengl materials */
- gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false);
-
- if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) {
- GMS.matbuf[a].alpha = ma->alpha;
- alphablend = (ma->alpha == 1.0f) ? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
- }
- else {
- GMS.matbuf[a].alpha = 1.0f;
- alphablend = GPU_BLEND_SOLID;
- }
- }
-
- /* setting 'do_alpha_after = true' indicates this object needs to be
- * drawn in a second alpha pass for improved blending */
- if (do_alpha_after && !GMS.is_alpha_pass)
- if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT))
- *do_alpha_after = true;
-
- GMS.alphablend[a] = alphablend;
- }
- }
-
- /* let's start with a clean state */
- GPU_object_material_unbind();
-}
-
-static int gpu_get_particle_info(GPUParticleInfo *pi)
-{
- DupliObject *dob = GMS.dob;
- if (dob->particle_system) {
- int ind;
- if (dob->persistent_id[0] < dob->particle_system->totpart)
- ind = dob->persistent_id[0];
- else {
- ind = dob->particle_system->child[dob->persistent_id[0] - dob->particle_system->totpart].parent;
- }
- if (ind >= 0) {
- ParticleData *p = &dob->particle_system->particles[ind];
-
- pi->scalprops[0] = ind;
- pi->scalprops[1] = GMS.gscene->r.cfra - p->time;
- pi->scalprops[2] = p->lifetime;
- pi->scalprops[3] = p->size;
-
- copy_v3_v3(pi->location, p->state.co);
- pi->location[3] = BLI_hash_int_01(ind);
-
- copy_v3_v3(pi->velocity, p->state.vel);
- copy_v3_v3(pi->angular_velocity, p->state.ave);
- return 1;
- }
- else return 0;
- }
- else
- return 0;
-}
-
-static void GPU_get_object_info(float oi[3], Material *mat)
-{
- Object *ob = GMS.gob;
- oi[0] = ob->index;
- oi[1] = mat->index;
- unsigned int random;
- if (GMS.dob) {
- random = GMS.dob->random_id;
- }
- else {
- random = BLI_hash_int_2d(BLI_hash_string(GMS.gob->id.name + 2), 0);
- }
- oi[2] = random * (1.0f / (float)0xFFFFFFFF);
-}
-
-int GPU_object_material_bind(int nr, void *attribs)
-{
- GPUVertexAttribs *gattribs = attribs;
-
- /* no GPU_begin_object_materials, use default material */
- if (!GMS.matbuf) {
- memset(&GMS, 0, sizeof(GMS));
-
- float diffuse[3], specular[3];
- mul_v3_v3fl(diffuse, &defmaterial.r, defmaterial.ref + defmaterial.emit);
- mul_v3_v3fl(specular, &defmaterial.specr, defmaterial.spec);
- GPU_basic_shader_colors(diffuse, specular, 35, 1.0f);
-
- if (GMS.two_sided_lighting)
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED);
- else
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING);
-
- return 0;
- }
-
- /* prevent index to use un-initialized array items */
- if (nr >= GMS.totmat)
- nr = 0;
-
- if (gattribs)
- memset(gattribs, 0, sizeof(*gattribs));
-
- /* keep current material */
- if (nr == GMS.lastmatnr)
- return GMS.lastretval;
-
- /* unbind glsl material */
- if (GMS.gboundmat) {
- if (GMS.is_alpha_pass) glDepthMask(0);
- GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv));
- GMS.gboundmat = NULL;
- }
-
- /* draw materials with alpha in alpha pass */
- GMS.lastmatnr = nr;
- GMS.lastretval = 1;
-
- if (GMS.use_alpha_pass) {
- GMS.lastretval = ELEM(GMS.alphablend[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP);
- if (GMS.is_alpha_pass)
- GMS.lastretval = !GMS.lastretval;
- }
- else
- GMS.lastretval = !GMS.is_alpha_pass;
-
- if (GMS.lastretval) {
- /* for alpha pass, use alpha blend */
- GPUBlendMode alphablend = GMS.alphablend[nr];
-
- if (gattribs && GMS.gmatbuf[nr]) {
- /* bind glsl material and get attributes */
- Material *mat = GMS.gmatbuf[nr];
- GPUParticleInfo partile_info;
- float object_info[3] = {0};
-
- float auto_bump_scale;
-
- GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv);
- GPU_material_vertex_attributes(gpumat, gattribs);
-
- if (GMS.dob) {
- gpu_get_particle_info(&partile_info);
- }
-
- if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) {
- GPU_get_object_info(object_info, mat);
- }
-
- GPU_material_bind(
- gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
- GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
-
- auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
- GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info);
- GMS.gboundmat = mat;
-
- /* for glsl use alpha blend mode, unless it's set to solid and
- * we are already drawing in an alpha pass */
- if (mat->game.alpha_blend != GPU_BLEND_SOLID)
- alphablend = mat->game.alpha_blend;
-
- if (GMS.is_alpha_pass) glDepthMask(1);
-
- if (GMS.backface_culling) {
- if (mat->game.flag)
- glEnable(GL_CULL_FACE);
- else
- glDisable(GL_CULL_FACE);
- }
-
- if (GMS.use_matcaps)
- glColor3f(1.0f, 1.0f, 1.0f);
- }
- else {
- /* or do fixed function opengl material */
- GPU_basic_shader_colors(
- GMS.matbuf[nr].diff,
- GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha);
-
- if (GMS.two_sided_lighting)
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED);
- else
- GPU_basic_shader_bind(GPU_SHADER_LIGHTING);
- }
-
- /* set (alpha) blending mode */
- GPU_set_material_alpha_blend(alphablend);
- }
-
- return GMS.lastretval;
-}
-
-int GPU_object_material_visible(int nr, void *attribs)
-{
- GPUVertexAttribs *gattribs = attribs;
- int visible;
-
- if (!GMS.matbuf)
- return 0;
-
- if (gattribs)
- memset(gattribs, 0, sizeof(*gattribs));
-
- if (nr >= GMS.totmat)
- nr = 0;
-
- if (GMS.use_alpha_pass) {
- visible = ELEM(GMS.alphablend[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP);
- if (GMS.is_alpha_pass)
- visible = !visible;
- }
- else
- visible = !GMS.is_alpha_pass;
-
- return visible;
-}
-
-void GPU_set_material_alpha_blend(int alphablend)
-{
- if (GMS.lastalphablend == alphablend)
- return;
-
- gpu_set_alpha_blend(alphablend);
- GMS.lastalphablend = alphablend;
-}
-
-int GPU_get_material_alpha_blend(void)
-{
- return GMS.lastalphablend;
-}
-
-void GPU_object_material_unbind(void)
-{
- GMS.lastmatnr = -1;
- GMS.lastretval = 1;
-
- if (GMS.gboundmat) {
- if (GMS.backface_culling)
- glDisable(GL_CULL_FACE);
-
- if (GMS.is_alpha_pass) glDepthMask(0);
- GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv));
- GMS.gboundmat = NULL;
- }
- else
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
- GPU_set_material_alpha_blend(GPU_BLEND_SOLID);
-}
-
-void GPU_material_diffuse_get(int nr, float diff[4])
-{
- /* prevent index to use un-initialized array items */
- if (nr >= GMS.totmat)
- nr = 0;
-
- /* no GPU_begin_object_materials, use default material */
- if (!GMS.matbuf) {
- mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit);
- }
- else {
- copy_v3_v3(diff, GMS.matbuf[nr].diff);
- diff[3] = GMS.matbuf[nr].alpha;
- }
-}
-
-bool GPU_material_use_matcaps_get(void)
-{
- return GMS.use_matcaps;
-}
-
-bool GPU_object_materials_check(void)
-{
- return GMS.is_enabled;
-}
-
-void GPU_end_object_materials(void)
-{
- GPU_object_material_unbind();
-
- GMS.is_enabled = false;
-
- if (GMS.matbuf && GMS.matbuf != GMS.matbuf_fixed) {
- MEM_freeN(GMS.matbuf);
- MEM_freeN(GMS.gmatbuf);
- MEM_freeN(GMS.alphablend);
- }
-
- GMS.matbuf = NULL;
- GMS.gmatbuf = NULL;
- GMS.alphablend = NULL;
- GMS.two_sided_lighting = false;
-
- /* resetting the texture matrix after the scaling needed for tiled textures */
- if (GTS.tilemode) {
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- }
-}
-
-/* Lights */
-
-int GPU_default_lights(void)
-{
- /* initialize */
- if (U.light[0].flag == 0 && U.light[1].flag == 0 && U.light[2].flag == 0) {
- U.light[0].flag = 1;
- U.light[0].vec[0] = -0.3; U.light[0].vec[1] = 0.3; U.light[0].vec[2] = 0.9;
- U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8;
- U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5;
- U.light[0].spec[3] = 1.0;
-
- U.light[1].flag = 0;
- U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1;
- U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8;
- U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5;
- U.light[1].spec[3] = 1.0;
-
- U.light[2].flag = 0;
- U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2;
- U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4;
- U.light[2].spec[0] = 0.5; U.light[2].spec[1] = 0.4; U.light[2].spec[2] = 0.3;
- U.light[2].spec[3] = 1.0;
- }
-
- GPU_basic_shader_light_set_viewer(false);
-
- int count = 0;
-
- for (int a = 0; a < 8; a++) {
- if (a < 3 && U.light[a].flag) {
- GPULightData light = {0};
-
- light.type = GPU_LIGHT_SUN;
-
- normalize_v3_v3(light.direction, U.light[a].vec);
- copy_v3_v3(light.diffuse, U.light[a].col);
- copy_v3_v3(light.specular, U.light[a].spec);
-
- GPU_basic_shader_light_set(a, &light);
-
- count++;
- }
- else
- GPU_basic_shader_light_set(a, NULL);
- }
-
- return count;
-}
-
-int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho)
-{
- /* disable all lights */
- for (int count = 0; count < 8; count++)
- GPU_basic_shader_light_set(count, NULL);
-
- /* view direction for specular is not computed correct by default in
- * opengl, so we set the settings ourselves */
- GPU_basic_shader_light_set_viewer(!ortho);
-
- int count = 0;
-
- for (Base *base = scene->base.first; base; base = base->next) {
- if (base->object->type != OB_LAMP)
- continue;
-
- if (!(base->lay & lay) || !(base->lay & ob->lay))
- continue;
-
- Lamp *la = base->object->data;
-
- /* setup lamp transform */
- glPushMatrix();
- glLoadMatrixf((float *)viewmat);
-
- /* setup light */
- GPULightData light = {0};
-
- mul_v3_v3fl(light.diffuse, &la->r, la->energy);
- mul_v3_v3fl(light.specular, &la->r, la->energy);
-
- if (la->type == LA_SUN) {
- /* directional sun light */
- light.type = GPU_LIGHT_SUN;
- normalize_v3_v3(light.direction, base->object->obmat[2]);
- }
- else {
- /* other lamps with position attenuation */
- copy_v3_v3(light.position, base->object->obmat[3]);
-
- light.constant_attenuation = 1.0f;
- light.linear_attenuation = la->att1 / la->dist;
- light.quadratic_attenuation = la->att2 / (la->dist * la->dist);
-
- if (la->type == LA_SPOT) {
- light.type = GPU_LIGHT_SPOT;
- negate_v3_v3(light.direction, base->object->obmat[2]);
- normalize_v3(light.direction);
- light.spot_cutoff = RAD2DEGF(la->spotsize * 0.5f);
- light.spot_exponent = 128.0f * la->spotblend;
- }
- else
- light.type = GPU_LIGHT_POINT;
- }
-
- GPU_basic_shader_light_set(count, &light);
-
- glPopMatrix();
-
- count++;
- if (count == 8)
- break;
- }
-
- return count;
-}
-
-static void gpu_multisample(bool enable)
+static void gpu_disable_multisample(void)
{
#ifdef __linux__
/* changing multisample from the default (enabled) causes problems on some
@@ -2282,115 +1314,51 @@ static void gpu_multisample(bool enable)
}
if (toggle_ok) {
- if (enable)
- glEnable(GL_MULTISAMPLE);
- else
- glDisable(GL_MULTISAMPLE);
+ glDisable(GL_MULTISAMPLE);
}
#else
- if (enable)
- glEnable(GL_MULTISAMPLE);
- else
- glDisable(GL_MULTISAMPLE);
+ glDisable(GL_MULTISAMPLE);
#endif
}
/* Default OpenGL State
*
- * This is called on startup, for opengl offscreen render and to restore state
- * for the game engine. Generally we should always return to this state when
+ * This is called on startup, for opengl offscreen render.
+ * Generally we should always return to this state when
* temporarily modifying the state for drawing, though that are (undocumented)
* exceptions that we should try to get rid of. */
void GPU_state_init(void)
{
- float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
- float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
-
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35);
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ GPU_disable_program_point_size();
- GPU_default_lights();
+ glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
glDepthFunc(GL_LEQUAL);
- /* scaling matrices */
- glEnable(GL_NORMALIZE);
- glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
- glDisable(GL_FOG);
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_LOGIC_OP);
+ glDisable(GL_COLOR_LOGIC_OP);
glDisable(GL_STENCIL_TEST);
- glDisable(GL_TEXTURE_1D);
- glDisable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
- /* default disabled, enable should be local per function */
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
- glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
- glPixelTransferi(GL_RED_SCALE, 1);
- glPixelTransferi(GL_RED_BIAS, 0);
- glPixelTransferi(GL_GREEN_SCALE, 1);
- glPixelTransferi(GL_GREEN_BIAS, 0);
- glPixelTransferi(GL_BLUE_SCALE, 1);
- glPixelTransferi(GL_BLUE_BIAS, 0);
- glPixelTransferi(GL_ALPHA_SCALE, 1);
- glPixelTransferi(GL_ALPHA_BIAS, 0);
-
- glPixelTransferi(GL_DEPTH_BIAS, 0);
- glPixelTransferi(GL_DEPTH_SCALE, 1);
- glDepthRange(0.0, 1.0);
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
+ glDepthRange(0.0, 1.0);
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
glDisable(GL_CULL_FACE);
- gpu_multisample(false);
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ gpu_disable_multisample();
}
-#ifdef WITH_OPENSUBDIV
-/* Update face-varying variables offset which might be
- * different from mesh to mesh sharing the same material.
- */
-void GPU_draw_update_fvar_offset(DerivedMesh *dm)
+void GPU_enable_program_point_size(void)
{
- /* Sanity check to be sure we only do this for OpenSubdiv draw. */
- BLI_assert(dm->type == DM_TYPE_CCGDM);
- BLI_assert(GMS.is_opensubdiv);
-
- for (int i = 0; i < GMS.totmat; ++i) {
- Material *material = GMS.gmatbuf[i];
- GPUMaterial *gpu_material;
-
- if (material == NULL) {
- continue;
- }
-
- gpu_material = GPU_material_from_blender(GMS.gscene,
- material,
- GMS.is_opensubdiv);
-
- GPU_material_update_fvar_offset(gpu_material, dm);
- }
+ glEnable(GL_PROGRAM_POINT_SIZE);
}
-#endif
+void GPU_disable_program_point_size(void)
+{
+ glDisable(GL_PROGRAM_POINT_SIZE);
+}
/** \name Framebuffer color depth, for selection codes
* \{ */
@@ -2399,9 +1367,9 @@ void GPU_draw_update_fvar_offset(DerivedMesh *dm)
/* apple seems to round colors to below and up on some configs */
-static unsigned int index_to_framebuffer(int index)
+static uint index_to_framebuffer(int index)
{
- unsigned int i = index;
+ uint i = index;
switch (GPU_color_depth()) {
case 12:
@@ -2429,9 +1397,9 @@ static unsigned int index_to_framebuffer(int index)
/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
-static unsigned int index_to_framebuffer(int index)
+static uint index_to_framebuffer(int index)
{
- unsigned int i = index;
+ uint i = index;
switch (GPU_color_depth()) {
case 8:
@@ -2487,7 +1455,7 @@ void GPU_select_index_get(int index, int *r_col)
#define INDEX_FROM_BUF_18(col) ((((col) & 0xFC0000) >> 6) + (((col) & 0xFC00) >> 4) + (((col) & 0xFC) >> 2))
#define INDEX_FROM_BUF_24(col) ((col) & 0xFFFFFF)
-int GPU_select_to_index(unsigned int col)
+int GPU_select_to_index(uint col)
{
if (col == 0) {
return 0;
@@ -2503,7 +1471,7 @@ int GPU_select_to_index(unsigned int col)
}
}
-void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
+void GPU_select_to_index_array(uint *col, const uint size)
{
#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
for (i = size; i--; col++) { \
@@ -2513,7 +1481,7 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
} ((void)0)
if (size > 0) {
- unsigned int i, c;
+ uint i, c;
switch (GPU_color_depth()) {
case 8:
@@ -2538,4 +1506,173 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
#undef INDEX_BUF_ARRAY
}
+#define STATE_STACK_DEPTH 16
+
+typedef struct {
+ eGPUAttribMask mask;
+
+ /* GL_ENABLE_BIT */
+ uint is_blend : 1;
+ uint is_cull_face : 1;
+ uint is_depth_test : 1;
+ uint is_dither : 1;
+ uint is_lighting : 1;
+ uint is_line_smooth : 1;
+ uint is_color_logic_op : 1;
+ uint is_multisample : 1;
+ uint is_polygon_offset_line : 1;
+ uint is_polygon_offset_fill : 1;
+ uint is_polygon_smooth : 1;
+ uint is_sample_alpha_to_coverage : 1;
+ uint is_scissor_test : 1;
+ uint is_stencil_test : 1;
+
+ bool is_clip_plane[6];
+
+ /* GL_DEPTH_BUFFER_BIT */
+ /* uint is_depth_test : 1; */
+ int depth_func;
+ double depth_clear_value;
+ bool depth_write_mask;
+
+ /* GL_SCISSOR_BIT */
+ int scissor_box[4];
+ /* uint is_scissor_test : 1; */
+
+ /* GL_VIEWPORT_BIT */
+ int viewport[4];
+ double near_far[2];
+} GPUAttribValues;
+
+typedef struct {
+ GPUAttribValues attrib_stack[STATE_STACK_DEPTH];
+ uint top;
+} GPUAttribStack;
+
+static GPUAttribStack state = {
+ .top = 0
+};
+
+#define AttribStack state
+#define Attrib state.attrib_stack[state.top]
+
+/**
+ * Replacement for glPush/PopAttributes
+ *
+ * We don't need to cover all the options of legacy OpenGL
+ * but simply the ones used by Blender.
+ */
+void gpuPushAttrib(eGPUAttribMask mask)
+{
+ Attrib.mask = mask;
+
+ if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
+ Attrib.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
+ glGetIntegerv(GL_DEPTH_FUNC, &Attrib.depth_func);
+ glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attrib.depth_clear_value);
+ glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attrib.depth_write_mask);
+ }
+
+ if ((mask & GPU_ENABLE_BIT) != 0) {
+ Attrib.is_blend = glIsEnabled(GL_BLEND);
+
+ for (int i = 0; i < 6; i++) {
+ Attrib.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
+ }
+
+ Attrib.is_cull_face = glIsEnabled(GL_CULL_FACE);
+ Attrib.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
+ Attrib.is_dither = glIsEnabled(GL_DITHER);
+ Attrib.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
+ Attrib.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
+ Attrib.is_multisample = glIsEnabled(GL_MULTISAMPLE);
+ Attrib.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
+ Attrib.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
+ Attrib.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
+ Attrib.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
+ Attrib.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+ Attrib.is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
+ }
+
+ if ((mask & GPU_SCISSOR_BIT) != 0) {
+ Attrib.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+ glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attrib.scissor_box);
+ }
+
+ if ((mask & GPU_VIEWPORT_BIT) != 0) {
+ glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attrib.near_far);
+ glGetIntegerv(GL_VIEWPORT, (GLint *)&Attrib.viewport);
+ }
+
+ if ((mask & GPU_BLEND_BIT) != 0) {
+ Attrib.is_blend = glIsEnabled(GL_BLEND);
+ }
+
+ BLI_assert(AttribStack.top < STATE_STACK_DEPTH);
+ AttribStack.top++;
+}
+
+static void restore_mask(GLenum cap, const bool value)
+{
+ if (value) {
+ glEnable(cap);
+ }
+ else {
+ glDisable(cap);
+ }
+}
+
+void gpuPopAttrib(void)
+{
+ BLI_assert(AttribStack.top > 0);
+ AttribStack.top--;
+
+ GLint mask = Attrib.mask;
+
+ if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
+ restore_mask(GL_DEPTH_TEST, Attrib.is_depth_test);
+ glDepthFunc(Attrib.depth_func);
+ glClearDepth(Attrib.depth_clear_value);
+ glDepthMask(Attrib.depth_write_mask);
+ }
+
+ if ((mask & GPU_ENABLE_BIT) != 0) {
+ restore_mask(GL_BLEND, Attrib.is_blend);
+
+ for (int i = 0; i < 6; i++) {
+ restore_mask(GL_CLIP_PLANE0 + i, Attrib.is_clip_plane[i]);
+ }
+
+ restore_mask(GL_CULL_FACE, Attrib.is_cull_face);
+ restore_mask(GL_DEPTH_TEST, Attrib.is_depth_test);
+ restore_mask(GL_DITHER, Attrib.is_dither);
+ restore_mask(GL_LINE_SMOOTH, Attrib.is_line_smooth);
+ restore_mask(GL_COLOR_LOGIC_OP, Attrib.is_color_logic_op);
+ restore_mask(GL_MULTISAMPLE, Attrib.is_multisample);
+ restore_mask(GL_POLYGON_OFFSET_LINE, Attrib.is_polygon_offset_line);
+ restore_mask(GL_POLYGON_OFFSET_FILL, Attrib.is_polygon_offset_fill);
+ restore_mask(GL_POLYGON_SMOOTH, Attrib.is_polygon_smooth);
+ restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attrib.is_sample_alpha_to_coverage);
+ restore_mask(GL_SCISSOR_TEST, Attrib.is_scissor_test);
+ restore_mask(GL_STENCIL_TEST, Attrib.is_stencil_test);
+ }
+
+ if ((mask & GPU_VIEWPORT_BIT) != 0) {
+ glViewport(Attrib.viewport[0], Attrib.viewport[1], Attrib.viewport[2], Attrib.viewport[3]);
+ glDepthRange(Attrib.near_far[0], Attrib.near_far[1]);
+ }
+
+ if ((mask & GPU_SCISSOR_BIT) != 0) {
+ restore_mask(GL_SCISSOR_TEST, Attrib.is_scissor_test);
+ glScissor(Attrib.scissor_box[0], Attrib.scissor_box[1], Attrib.scissor_box[2], Attrib.scissor_box[3]);
+ }
+
+ if ((mask & GPU_BLEND_BIT) != 0) {
+ restore_mask(GL_BLEND, Attrib.is_blend);
+ }
+}
+
+#undef Attrib
+#undef AttribStack
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c
new file mode 100644
index 00000000000..b8ce4faabea
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_element.c
@@ -0,0 +1,314 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_element.c
+ * \ingroup gpu
+ *
+ * GPU element list (AKA index buffer)
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_element.h"
+
+#include "gpu_context_private.h"
+
+#include <stdlib.h>
+
+#define KEEP_SINGLE_COPY 1
+
+static GLenum convert_index_type_to_gl(GPUIndexBufType type)
+{
+ static const GLenum table[] = {
+ [GPU_INDEX_U8] = GL_UNSIGNED_BYTE, /* GL has this, Vulkan does not */
+ [GPU_INDEX_U16] = GL_UNSIGNED_SHORT,
+ [GPU_INDEX_U32] = GL_UNSIGNED_INT
+ };
+ return table[type];
+}
+
+uint GPU_indexbuf_size_get(const GPUIndexBuf *elem)
+{
+#if GPU_TRACK_INDEX_RANGE
+ static const uint table[] = {
+ [GPU_INDEX_U8] = sizeof(GLubyte), /* GL has this, Vulkan does not */
+ [GPU_INDEX_U16] = sizeof(GLushort),
+ [GPU_INDEX_U32] = sizeof(GLuint)
+ };
+ return elem->index_len * table[elem->index_type];
+#else
+ return elem->index_len * sizeof(GLuint);
+#endif
+}
+
+int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
+{
+ switch (prim_type) {
+ case GPU_PRIM_POINTS:
+ return 1;
+ case GPU_PRIM_LINES:
+ return 2;
+ case GPU_PRIM_TRIS:
+ return 3;
+ case GPU_PRIM_LINES_ADJ:
+ return 4;
+ default:
+ break;
+ }
+#if TRUST_NO_ONE
+ assert(false);
+#endif
+ return -1;
+}
+
+void GPU_indexbuf_init_ex(
+ GPUIndexBufBuilder *builder, GPUPrimType prim_type,
+ uint index_len, uint vertex_len, bool use_prim_restart)
+{
+ builder->use_prim_restart = use_prim_restart;
+ builder->max_allowed_index = vertex_len - 1;
+ builder->max_index_len = index_len;
+ builder->index_len = 0; // start empty
+ builder->prim_type = prim_type;
+ builder->data = MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
+}
+
+void GPU_indexbuf_init(GPUIndexBufBuilder *builder, GPUPrimType prim_type, uint prim_len, uint vertex_len)
+{
+ int verts_per_prim = GPU_indexbuf_primitive_len(prim_type);
+#if TRUST_NO_ONE
+ assert(verts_per_prim != -1);
+#endif
+ GPU_indexbuf_init_ex(builder, prim_type, prim_len * (uint)verts_per_prim, vertex_len, false);
+}
+
+void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)
+{
+#if TRUST_NO_ONE
+ assert(builder->data != NULL);
+ assert(builder->index_len < builder->max_index_len);
+ assert(v <= builder->max_allowed_index);
+#endif
+ builder->data[builder->index_len++] = v;
+}
+
+void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *builder)
+{
+#if TRUST_NO_ONE
+ assert(builder->data != NULL);
+ assert(builder->index_len < builder->max_index_len);
+ assert(builder->use_prim_restart);
+#endif
+ builder->data[builder->index_len++] = GPU_PRIM_RESTART;
+}
+
+void GPU_indexbuf_add_point_vert(GPUIndexBufBuilder *builder, uint v)
+{
+#if TRUST_NO_ONE
+ assert(builder->prim_type == GPU_PRIM_POINTS);
+#endif
+ GPU_indexbuf_add_generic_vert(builder, v);
+}
+
+void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *builder, uint v1, uint v2)
+{
+#if TRUST_NO_ONE
+ assert(builder->prim_type == GPU_PRIM_LINES);
+ assert(v1 != v2);
+#endif
+ GPU_indexbuf_add_generic_vert(builder, v1);
+ GPU_indexbuf_add_generic_vert(builder, v2);
+}
+
+void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3)
+{
+#if TRUST_NO_ONE
+ assert(builder->prim_type == GPU_PRIM_TRIS);
+ assert(v1 != v2 && v2 != v3 && v3 != v1);
+#endif
+ GPU_indexbuf_add_generic_vert(builder, v1);
+ GPU_indexbuf_add_generic_vert(builder, v2);
+ GPU_indexbuf_add_generic_vert(builder, v3);
+}
+
+void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *builder, uint v1, uint v2, uint v3, uint v4)
+{
+#if TRUST_NO_ONE
+ assert(builder->prim_type == GPU_PRIM_LINES_ADJ);
+ assert(v2 != v3); /* only the line need diff indices */
+#endif
+ GPU_indexbuf_add_generic_vert(builder, v1);
+ GPU_indexbuf_add_generic_vert(builder, v2);
+ GPU_indexbuf_add_generic_vert(builder, v3);
+ GPU_indexbuf_add_generic_vert(builder, v4);
+}
+
+#if GPU_TRACK_INDEX_RANGE
+/* Everything remains 32 bit while building to keep things simple.
+ * Find min/max after, then convert to smallest index type possible. */
+
+static uint index_range(const uint values[], uint value_len, uint *min_out, uint *max_out)
+{
+ if (value_len == 0) {
+ *min_out = 0;
+ *max_out = 0;
+ return 0;
+ }
+ uint min_value = values[0];
+ uint max_value = values[0];
+ for (uint i = 1; i < value_len; ++i) {
+ const uint value = values[i];
+ if (value == GPU_PRIM_RESTART)
+ continue;
+ else if (value < min_value)
+ min_value = value;
+ else if (value > max_value)
+ max_value = value;
+ }
+ *min_out = min_value;
+ *max_out = max_value;
+ return max_value - min_value;
+}
+
+static void squeeze_indices_byte(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
+{
+ const uint *values = builder->data;
+ const uint index_len = elem->index_len;
+
+ /* data will never be *larger* than builder->data...
+ * converting in place to avoid extra allocation */
+ GLubyte *data = (GLubyte *)builder->data;
+
+ if (elem->max_index > 0xFF) {
+ const uint base = elem->min_index;
+ elem->base_index = base;
+ elem->min_index = 0;
+ elem->max_index -= base;
+ for (uint i = 0; i < index_len; ++i) {
+ data[i] = (values[i] == GPU_PRIM_RESTART) ? 0xFF : (GLubyte)(values[i] - base);
+ }
+ }
+ else {
+ elem->base_index = 0;
+ for (uint i = 0; i < index_len; ++i) {
+ data[i] = (GLubyte)(values[i]);
+ }
+ }
+}
+
+static void squeeze_indices_short(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
+{
+ const uint *values = builder->data;
+ const uint index_len = elem->index_len;
+
+ /* data will never be *larger* than builder->data...
+ * converting in place to avoid extra allocation */
+ GLushort *data = (GLushort *)builder->data;
+
+ if (elem->max_index > 0xFFFF) {
+ const uint base = elem->min_index;
+ elem->base_index = base;
+ elem->min_index = 0;
+ elem->max_index -= base;
+ for (uint i = 0; i < index_len; ++i) {
+ data[i] = (values[i] == GPU_PRIM_RESTART) ? 0xFFFF : (GLushort)(values[i] - base);
+ }
+ }
+ else {
+ elem->base_index = 0;
+ for (uint i = 0; i < index_len; ++i) {
+ data[i] = (GLushort)(values[i]);
+ }
+ }
+}
+
+#endif /* GPU_TRACK_INDEX_RANGE */
+
+GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *builder)
+{
+ GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
+ GPU_indexbuf_build_in_place(builder, elem);
+ return elem;
+}
+
+void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
+{
+#if TRUST_NO_ONE
+ assert(builder->data != NULL);
+#endif
+ elem->index_len = builder->index_len;
+ elem->use_prim_restart = builder->use_prim_restart;
+
+#if GPU_TRACK_INDEX_RANGE
+ uint range = index_range(builder->data, builder->index_len, &elem->min_index, &elem->max_index);
+
+ /* count the primitive restart index. */
+ if (elem->use_prim_restart) {
+ range += 1;
+ }
+
+ if (range <= 0xFF) {
+ elem->index_type = GPU_INDEX_U8;
+ squeeze_indices_byte(builder, elem);
+ }
+ else if (range <= 0xFFFF) {
+ elem->index_type = GPU_INDEX_U16;
+ squeeze_indices_short(builder, elem);
+ }
+ else {
+ elem->index_type = GPU_INDEX_U32;
+ elem->base_index = 0;
+ }
+ elem->gl_index_type = convert_index_type_to_gl(elem->index_type);
+#endif
+
+ if (elem->vbo_id == 0) {
+ elem->vbo_id = GPU_buf_alloc();
+ }
+ /* send data to GPU */
+ /* GL_ELEMENT_ARRAY_BUFFER changes the state of the last VAO bound,
+ * so we use the GL_ARRAY_BUFFER here to create a buffer without
+ * interfering in the VAO state. */
+ glBindBuffer(GL_ARRAY_BUFFER, elem->vbo_id);
+ glBufferData(GL_ARRAY_BUFFER, GPU_indexbuf_size_get(elem), builder->data, GL_STATIC_DRAW);
+
+ /* discard builder (one-time use) */
+ MEM_freeN(builder->data);
+ builder->data = NULL;
+ /* other fields are safe to leave */
+}
+
+void GPU_indexbuf_use(GPUIndexBuf *elem)
+{
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
+}
+
+void GPU_indexbuf_discard(GPUIndexBuf *elem)
+{
+ if (elem->vbo_id) {
+ GPU_buf_free(elem->vbo_id);
+ }
+ MEM_freeN(elem);
+}
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 16f8af2c1b7..e6e82b3cc86 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -37,9 +37,10 @@
#include "BLI_math_vector.h"
#include "BKE_global.h"
+#include "MEM_guardedalloc.h"
-#include "GPU_basic_shader.h"
#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
#include "GPU_glew.h"
#include "GPU_texture.h"
@@ -56,34 +57,76 @@
/* Extensions support */
/* -- extension: version of GL that absorbs it
+ * EXT_gpu_shader4: 3.0
* ARB_framebuffer object: 3.0
- * EXT_framebuffer_object: 3.0
- * EXT_framebuffer_blit: 3.0
- * EXT_framebuffer_multisample: 3.0
* EXT_framebuffer_multisample_blit_scaled: ???
* ARB_draw_instanced: 3.1
* ARB_texture_multisample: 3.2
- * EXT_geometry_shader4: 3.2
* ARB_texture_query_lod: 4.0
*/
static struct GPUGlobal {
GLint maxtexsize;
+ GLint maxtexlayers;
GLint maxcubemapsize;
GLint maxtextures;
- bool extdisabled;
+ GLint maxtexturesfrag;
+ GLint maxtexturesgeom;
+ GLint maxtexturesvert;
+ GLint maxubosize;
+ GLint maxubobinds;
int colordepth;
int samples_color_texture_max;
GPUDeviceType device;
GPUOSType os;
GPUDriverType driver;
+ float line_width_range[2];
/* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
* calculate dfdy in shader differently when drawing to an offscreen buffer. First
* number is factor on screen and second is off-screen */
float dfdyfactors[2];
float max_anisotropy;
+ /* Some Intel drivers have issues with using mips as framebuffer targets if
+ * GL_TEXTURE_MAX_LEVEL is higher than the target mip.
+ * We need a workaround in this cases. */
+ bool mip_render_workaround;
+ /* There is an issue with the glBlitFramebuffer on MacOS with radeon pro graphics.
+ * Blitting depth with GL_DEPTH24_STENCIL8 is buggy so the workaround is to use
+ * GPU_DEPTH32F_STENCIL8. Then Blitting depth will work but blitting stencil will
+ * still be broken. */
+ bool depth_blitting_workaround;
} GG = {1, 0};
+
+static void gpu_detect_mip_render_workaround(void)
+{
+ int cube_size = 2;
+ float *source_pix = MEM_callocN(sizeof(float) * 4 * 6 * cube_size * cube_size, __func__);
+ float clear_color[4] = {1.0f, 0.5f, 0.0f, 0.0f};
+
+ GPUTexture *tex = GPU_texture_create_cube(cube_size, GPU_RGBA16F, source_pix, NULL);
+ MEM_freeN(source_pix);
+
+ GPU_texture_bind(tex, 0);
+ GPU_texture_generate_mipmap(tex);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, 0);
+ GPU_texture_unbind(tex);
+
+ GPUFrameBuffer *fb = GPU_framebuffer_create();
+ GPU_framebuffer_texture_attach(fb, tex, 0, 1);
+ GPU_framebuffer_bind(fb);
+ GPU_framebuffer_clear_color(fb, clear_color);
+ GPU_framebuffer_restore();
+ GPU_framebuffer_free(fb);
+
+ float *data = GPU_texture_read(tex, GPU_DATA_FLOAT, 1);
+ GG.mip_render_workaround = !equals_v4v4(clear_color, data);
+
+ MEM_freeN(data);
+ GPU_texture_free(tex);
+}
+
/* GPU Types */
bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
@@ -93,14 +136,14 @@ bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
/* GPU Extensions */
-void GPU_extensions_disable(void)
+int GPU_max_texture_size(void)
{
- GG.extdisabled = true;
+ return GG.maxtexsize;
}
-int GPU_max_texture_size(void)
+int GPU_max_texture_layers(void)
{
- return GG.maxtexsize;
+ return GG.maxtexlayers;
}
int GPU_max_textures(void)
@@ -108,6 +151,21 @@ int GPU_max_textures(void)
return GG.maxtextures;
}
+int GPU_max_textures_frag(void)
+{
+ return GG.maxtexturesfrag;
+}
+
+int GPU_max_textures_geom(void)
+{
+ return GG.maxtexturesgeom;
+}
+
+int GPU_max_textures_vert(void)
+{
+ return GG.maxtexturesvert;
+}
+
float GPU_max_texture_anisotropy(void)
{
return GG.max_anisotropy;
@@ -123,19 +181,51 @@ int GPU_max_cube_map_size(void)
return GG.maxcubemapsize;
}
+int GPU_max_ubo_binds(void)
+{
+ return GG.maxubobinds;
+}
+
+int GPU_max_ubo_size(void)
+{
+ return GG.maxubosize;
+}
+
+float GPU_max_line_width(void)
+{
+ return GG.line_width_range[1];
+}
+
void GPU_get_dfdy_factors(float fac[2])
{
copy_v2_v2(fac, GG.dfdyfactors);
}
+bool GPU_mip_render_workaround(void)
+{
+ return GG.mip_render_workaround;
+}
+
+bool GPU_depth_blitting_workaround(void)
+{
+ return GG.depth_blitting_workaround;
+}
+
void gpu_extensions_init(void)
{
- /* BLI_assert(GLEW_VERSION_2_1); */
- /* ^-- maybe a bit extreme? */
+ /* during 2.8 development each platform has its own OpenGL minimum requirements
+ * final 2.8 release will be unified on OpenGL 3.3 core profile, no required extensions
+ * see developer.blender.org/T49012 for details
+ */
+ BLI_assert(GLEW_VERSION_3_3);
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures);
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtexturesfrag);
+ glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &GG.maxtexturesvert);
+ glGetIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &GG.maxtexturesgeom);
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &GG.maxtextures);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize);
+ glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GG.maxtexlayers);
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize);
if (GLEW_EXT_texture_filter_anisotropic)
@@ -143,23 +233,43 @@ void gpu_extensions_init(void)
else
GG.max_anisotropy = 1.0f;
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GG.maxubobinds);
+ glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize);
+
+ glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, GG.line_width_range);
+
+#ifndef NDEBUG
+ GLint ret;
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &ret);
+ /* We expect FRONT_LEFT to be the default buffer. */
+ BLI_assert(ret == GL_FRAMEBUFFER_DEFAULT);
+#endif
+
GLint r, g, b;
- glGetIntegerv(GL_RED_BITS, &r);
- glGetIntegerv(GL_GREEN_BITS, &g);
- glGetIntegerv(GL_BLUE_BITS, &b);
- GG.colordepth = r + g + b; /* assumes same depth for RGB */
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &r);
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, &g);
+ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, &b);
+ GG.colordepth = r + g + b; /* Assumes same depth for RGB. */
- if (GLEW_VERSION_3_2 || GLEW_ARB_texture_multisample) {
- glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max);
- }
+ glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max);
const char *vendor = (const char *)glGetString(GL_VENDOR);
const char *renderer = (const char *)glGetString(GL_RENDERER);
const char *version = (const char *)glGetString(GL_VERSION);
- if (strstr(vendor, "ATI")) {
+ if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
GG.device = GPU_DEVICE_ATI;
GG.driver = GPU_DRIVER_OFFICIAL;
+
+#if defined(__APPLE__)
+ if (strstr(renderer, "AMD Radeon Pro") ||
+ strstr(renderer, "AMD Radeon R9") ||
+ strstr(renderer, "AMD Radeon RX"))
+ {
+ GG.depth_blitting_workaround = true;
+ }
+#endif
}
else if (strstr(vendor, "NVIDIA")) {
GG.device = GPU_DEVICE_NVIDIA;
@@ -174,6 +284,7 @@ void gpu_extensions_init(void)
GG.driver = GPU_DRIVER_OFFICIAL;
}
else if ((strstr(renderer, "Mesa DRI R")) ||
+ (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) ||
(strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
(strstr(renderer, "Gallium ") && strstr(renderer, " on AMD ")))
{
@@ -197,14 +308,11 @@ void gpu_extensions_init(void)
GG.driver = GPU_DRIVER_SOFTWARE;
}
else {
+ printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
GG.device = GPU_DEVICE_ANY;
GG.driver = GPU_DRIVER_ANY;
}
- /* make sure double side isn't used by default and only getting enabled in places where it's
- * really needed to prevent different unexpected behaviors like with intel gme965 card (sergey) */
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
-
#ifdef _WIN32
GG.os = GPU_OS_WIN;
#elif defined(__APPLE__)
@@ -213,6 +321,7 @@ void gpu_extensions_init(void)
GG.os = GPU_OS_UNIX;
#endif
+ gpu_detect_mip_render_workaround();
/* df/dy calculation factors, those are dependent on driver */
if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
@@ -237,92 +346,13 @@ void gpu_extensions_init(void)
GPU_invalid_tex_init();
- GPU_basic_shaders_init();
}
void gpu_extensions_exit(void)
{
- GPU_basic_shaders_exit();
GPU_invalid_tex_free();
}
-bool GPU_legacy_support(void)
-{
- /* return whether or not current GL context is compatible with legacy OpenGL */
- static bool checked = false;
- static bool support = true;
-
- if (!checked) {
- if (GLEW_VERSION_3_2) {
- GLint profile;
- glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
-
- if (G.debug & G_DEBUG_GPU) {
- printf("GL_CONTEXT_PROFILE_MASK = %#x (%s profile)\n", (unsigned int)profile,
- (profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) ? "compatibility" :
- (profile & GL_CONTEXT_CORE_PROFILE_BIT) ? "core" : "unknown");
- }
-
- if (profile == 0) {
- /* workaround for nVidia's Linux driver */
- support = GLEW_ARB_compatibility;
- }
- else {
- support = profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
- }
- }
- else if (GLEW_VERSION_3_1) {
- support = GLEW_ARB_compatibility;
- }
-
- /* any OpenGL version <= 3.0 is legacy, so support remains true */
-
- checked = true;
- }
-
- return support;
-}
-
-bool GPU_full_non_power_of_two_support(void)
-{
- /* always supported on full GL but still relevant for OpenGL ES 2.0 where
- * NPOT textures can't use mipmaps or repeat wrap mode */
- return true;
-}
-
-bool GPU_display_list_support(void)
-{
- /* deprecated in GL 3
- * supported on older GL and compatibility profile
- * still queried by game engine
- */
- return true;
-}
-
-bool GPU_bicubic_bump_support(void)
-{
- return GLEW_VERSION_4_0 || (GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0);
-}
-
-bool GPU_geometry_shader_support(void)
-{
- /* in GL 3.2 geometry shaders are fully supported
- * core profile clashes with our other shaders so accept compatibility only
- * other GL versions can use EXT_geometry_shader4 if available
- */
- return (GLEW_VERSION_3_2 && GPU_legacy_support()) || GLEW_EXT_geometry_shader4;
-}
-
-bool GPU_geometry_shader_support_via_extension(void)
-{
- return GLEW_EXT_geometry_shader4 && !(GLEW_VERSION_3_2 && GPU_legacy_support());
-}
-
-bool GPU_instanced_drawing_support(void)
-{
- return GLEW_VERSION_3_1 || GLEW_ARB_draw_instanced;
-}
-
int GPU_color_depth(void)
{
return GG.colordepth;
@@ -330,12 +360,14 @@ int GPU_color_depth(void)
bool GPU_mem_stats_supported(void)
{
- return (GLEW_NVX_gpu_memory_info || (GLEW_ATI_meminfo)) && (G.debug & G_DEBUG_GPU_MEM);
+ return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo) && (G.debug & G_DEBUG_GPU_MEM);
}
void GPU_mem_stats_get(int *totalmem, int *freemem)
{
+ /* TODO(merwin): use Apple's platform API to get this info */
+
if (GLEW_NVX_gpu_memory_info) {
/* returned value in Kb */
glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem);
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index ff637b5b4de..f92899f91a0 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -28,308 +28,467 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
#include "BKE_global.h"
-#include "GPU_debug.h"
-#include "GPU_glew.h"
+#include "GPU_batch.h"
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
+#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
-static struct GPUFrameBufferGlobal {
- GLuint currentfb;
-} GG = {0};
+#include "gpu_private.h"
+#include "gpu_context_private.h"
-/* Number of maximum output slots.
- * We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */
-#define GPU_FB_MAX_SLOTS 4
+typedef enum {
+ GPU_FB_DEPTH_ATTACHMENT = 0,
+ GPU_FB_DEPTH_STENCIL_ATTACHMENT,
+ GPU_FB_COLOR_ATTACHMENT0,
+ GPU_FB_COLOR_ATTACHMENT1,
+ GPU_FB_COLOR_ATTACHMENT2,
+ GPU_FB_COLOR_ATTACHMENT3,
+ GPU_FB_COLOR_ATTACHMENT4,
+ /* Number of maximum output slots.
+ * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate). */
+ /* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to
+ * the maximum number of COLOR attachments specified by glDrawBuffers. */
+ GPU_FB_MAX_ATTACHEMENT
+} GPUAttachmentType;
+
+#define GPU_FB_MAX_COLOR_ATTACHMENT (GPU_FB_MAX_ATTACHEMENT - GPU_FB_COLOR_ATTACHMENT0)
+
+#define GPU_FB_DIRTY_DRAWBUFFER (1 << 15)
+
+#define GPU_FB_ATTACHEMENT_IS_DIRTY(flag, type) ((flag & (1 << type)) != 0)
+#define GPU_FB_ATTACHEMENT_SET_DIRTY(flag, type) (flag |= (1 << type))
struct GPUFrameBuffer {
+ GPUContext *ctx;
GLuint object;
- GPUTexture *colortex[GPU_FB_MAX_SLOTS];
- GPUTexture *depthtex;
+ GPUAttachment attachments[GPU_FB_MAX_ATTACHEMENT];
+ uint16_t dirty_flag;
+ int width, height;
+ bool multisample;
+ /* TODO Check that we always use the right context when binding
+ * (FBOs are not shared across ogl contexts). */
+ // void *ctx;
};
+static GLenum convert_attachment_type_to_gl(GPUAttachmentType type)
+{
+ static const GLenum table[] = {
+ [GPU_FB_DEPTH_ATTACHMENT] = GL_DEPTH_ATTACHMENT,
+ [GPU_FB_DEPTH_STENCIL_ATTACHMENT] = GL_DEPTH_STENCIL_ATTACHMENT,
+ [GPU_FB_COLOR_ATTACHMENT0] = GL_COLOR_ATTACHMENT0,
+ [GPU_FB_COLOR_ATTACHMENT1] = GL_COLOR_ATTACHMENT1,
+ [GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2,
+ [GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3,
+ [GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4
+ };
+ return table[type];
+}
+
+static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot)
+{
+ switch (GPU_texture_format(tex)) {
+ case GPU_DEPTH_COMPONENT32F:
+ case GPU_DEPTH_COMPONENT24:
+ case GPU_DEPTH_COMPONENT16:
+ return GPU_FB_DEPTH_ATTACHMENT;
+ case GPU_DEPTH24_STENCIL8:
+ case GPU_DEPTH32F_STENCIL8:
+ return GPU_FB_DEPTH_STENCIL_ATTACHMENT;
+ default:
+ return GPU_FB_COLOR_ATTACHMENT0 + slot;
+ }
+}
+
+static GLenum convert_buffer_bits_to_gl(GPUFrameBufferBits bits)
+{
+ GLbitfield mask = 0;
+ mask |= (bits & GPU_DEPTH_BIT) ? GL_DEPTH_BUFFER_BIT : 0;
+ mask |= (bits & GPU_STENCIL_BIT) ? GL_STENCIL_BUFFER_BIT : 0;
+ mask |= (bits & GPU_COLOR_BIT) ? GL_COLOR_BUFFER_BIT : 0;
+ return mask;
+}
+
+static GPUTexture *framebuffer_get_depth_tex(GPUFrameBuffer *fb)
+{
+ if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex)
+ return fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex;
+ else
+ return fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex;
+}
+
+static GPUTexture *framebuffer_get_color_tex(GPUFrameBuffer *fb, int slot)
+{
+ return fb->attachments[GPU_FB_COLOR_ATTACHMENT0 + slot].tex;
+}
+
static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
{
+ const char *format = "GPUFrameBuffer: framebuffer status %s\n";
const char *err = "unknown";
+#define format_status(X) \
+ case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \
+ break;
+
switch (status) {
- case GL_FRAMEBUFFER_COMPLETE_EXT:
- break;
- case GL_INVALID_OPERATION:
- err = "Invalid operation";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
- err = "Incomplete attachment";
- break;
- case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
- err = "Unsupported framebuffer format";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
- err = "Missing attachment";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
- err = "Attached images must have same dimensions";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
- err = "Attached images must have same format";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
- err = "Missing draw buffer";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
- err = "Missing read buffer";
- break;
+ /* success */
+ format_status(COMPLETE)
+ /* errors shared by OpenGL desktop & ES */
+ format_status(INCOMPLETE_ATTACHMENT)
+ format_status(INCOMPLETE_MISSING_ATTACHMENT)
+ format_status(UNSUPPORTED)
+#if 0 /* for OpenGL ES only */
+ format_status(INCOMPLETE_DIMENSIONS)
+#else /* for desktop GL only */
+ format_status(INCOMPLETE_DRAW_BUFFER)
+ format_status(INCOMPLETE_READ_BUFFER)
+ format_status(INCOMPLETE_MULTISAMPLE)
+ format_status(UNDEFINED)
+#endif
}
+#undef format_status
+
if (err_out) {
- BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
- (int)status, err);
+ BLI_snprintf(err_out, 256, format, err);
}
else {
- fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
- (int)status, err);
+ fprintf(stderr, format, err);
}
}
-/* GPUFrameBuffer */
+void gpu_framebuffer_module_init(void)
+{
+}
-GPUFrameBuffer *GPU_framebuffer_create(void)
+void gpu_framebuffer_module_exit(void)
{
- GPUFrameBuffer *fb;
+}
- if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object ||
- (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit)))
- {
- return NULL;
+GPUFrameBuffer *GPU_framebuffer_active_get(void)
+{
+ GPUContext *ctx = GPU_context_active_get();
+ if (ctx) {
+ return gpu_context_active_framebuffer_get(ctx);
}
+ else {
+ return 0;
+ }
+}
- fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
- glGenFramebuffersEXT(1, &fb->object);
-
- if (!fb->object) {
- fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
- (int)glGetError());
- GPU_framebuffer_free(fb);
- return NULL;
+static void gpu_framebuffer_current_set(GPUFrameBuffer *fb)
+{
+ GPUContext *ctx = GPU_context_active_get();
+ if (ctx) {
+ gpu_context_active_framebuffer_set(ctx, fb);
}
+}
- /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- glReadBuffer(GL_NONE);
- glDrawBuffer(GL_NONE);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+/* GPUFrameBuffer */
- return fb;
+GPUFrameBuffer *GPU_framebuffer_create(void)
+{
+ /* We generate the FB object later at first use in order to
+ * create the framebuffer in the right opengl context. */
+ return MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
}
-int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256])
+static void gpu_framebuffer_init(GPUFrameBuffer *fb)
{
- GLenum attachment;
- GLenum error;
+ fb->object = GPU_fbo_alloc();
+ fb->ctx = GPU_context_active_get();
+ gpu_context_add_framebuffer(fb->ctx, fb);
+}
- if (slot >= GPU_FB_MAX_SLOTS) {
- fprintf(stderr,
- "Attaching to index %d framebuffer slot unsupported. "
- "Use at most %d\n", slot, GPU_FB_MAX_SLOTS);
- return 0;
+void GPU_framebuffer_free(GPUFrameBuffer *fb)
+{
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
+ if (fb->attachments[type].tex != NULL) {
+ GPU_framebuffer_texture_detach(fb, fb->attachments[type].tex);
+ }
}
- if ((G.debug & G_DEBUG)) {
- if (GPU_texture_bound_number(tex) != -1) {
- fprintf(stderr,
- "Feedback loop warning!: "
- "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n");
- }
+ if (fb->object != 0) {
+ /* This restores the framebuffer if it was bound */
+ GPU_fbo_free(fb->object, fb->ctx);
+ gpu_context_remove_framebuffer(fb->ctx, fb);
}
- if (GPU_texture_depth(tex))
- attachment = GL_DEPTH_ATTACHMENT_EXT;
- else
- attachment = GL_COLOR_ATTACHMENT0_EXT + slot;
+ if (GPU_framebuffer_active_get() == fb) {
+ gpu_framebuffer_current_set(NULL);
+ }
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- GG.currentfb = fb->object;
+ MEM_freeN(fb);
+}
- /* Clean glError buffer. */
- while (glGetError() != GL_NO_ERROR) {}
+/* ---------- Attach ----------- */
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
- GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0);
+static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
+{
+ if (slot >= GPU_FB_MAX_COLOR_ATTACHMENT) {
+ fprintf(stderr,
+ "Attaching to index %d framebuffer slot unsupported. "
+ "Use at most %d\n", slot, GPU_FB_MAX_COLOR_ATTACHMENT);
+ return;
+ }
- error = glGetError();
+ GPUAttachmentType type = attachment_type_from_tex(tex, slot);
+ GPUAttachment *attachment = &fb->attachments[type];
- if (error == GL_INVALID_OPERATION) {
- GPU_framebuffer_restore();
- gpu_print_framebuffer_error(error, err_out);
- return 0;
+ if ((attachment->tex == tex) &&
+ (attachment->mip == mip) &&
+ (attachment->layer == layer))
+ {
+ return; /* Exact same texture already bound here. */
+ }
+ else if (attachment->tex != NULL) {
+ GPU_framebuffer_texture_detach(fb, attachment->tex);
}
- if (GPU_texture_depth(tex))
- fb->depthtex = tex;
- else
- fb->colortex[slot] = tex;
+ if (attachment->tex == NULL) {
+ GPU_texture_attach_framebuffer(tex, fb, type);
+ }
- GPU_texture_framebuffer_set(tex, fb, slot);
+ attachment->tex = tex;
+ attachment->mip = mip;
+ attachment->layer = layer;
+ GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type);
+}
- return 1;
+void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
+{
+ gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip);
}
-void GPU_framebuffer_texture_detach(GPUTexture *tex)
+void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
{
- GLenum attachment;
- GPUFrameBuffer *fb = GPU_texture_framebuffer(tex);
- int fb_attachment = GPU_texture_framebuffer_attachment(tex);
+ /* NOTE: We could support 1D ARRAY texture. */
+ BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_2D_ARRAY);
+ gpu_framebuffer_texture_attach_ex(fb, tex, slot, layer, mip);
+}
- if (!fb)
- return;
+void GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip)
+{
+ BLI_assert(GPU_texture_cube(tex));
+ gpu_framebuffer_texture_attach_ex(fb, tex, slot, face, mip);
+}
- if (GG.currentfb != fb->object) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- GG.currentfb = fb->object;
- }
+/* ---------- Detach ----------- */
- if (GPU_texture_depth(tex)) {
- fb->depthtex = NULL;
- attachment = GL_DEPTH_ATTACHMENT_EXT;
- }
- else {
- BLI_assert(fb->colortex[fb_attachment] == tex);
- fb->colortex[fb_attachment] = NULL;
- attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment;
- }
+void GPU_framebuffer_texture_detach_slot(GPUFrameBuffer *fb, GPUTexture *tex, int type)
+{
+ GPUAttachment *attachment = &fb->attachments[type];
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0);
+ if (attachment->tex != tex) {
+ fprintf(stderr,
+ "Warning, attempting to detach Texture %p from framebuffer %p "
+ "but texture is not attached.\n", tex, fb);
+ return;
+ }
- GPU_texture_framebuffer_set(tex, NULL, -1);
+ attachment->tex = NULL;
+ GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type);
}
-void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
+void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
{
- GPUFrameBuffer *fb = GPU_texture_framebuffer(tex);
- int fb_attachment = GPU_texture_framebuffer_attachment(tex);
+ GPUAttachmentType type = GPU_texture_detach_framebuffer(tex, fb);
+ GPU_framebuffer_texture_detach_slot(fb, tex, type);
+}
- if (!fb) {
- fprintf(stderr, "Error, texture not bound to framebuffer!\n");
- return;
+/* ---------- Config (Attach & Detach) ----------- */
+
+/**
+ * First GPUAttachment in *config is always the depth/depth_stencil buffer.
+ * Following GPUAttachments are color buffers.
+ * Setting GPUAttachment.mip to -1 will leave the texture in this slot.
+ * Setting GPUAttachment.tex to NULL will detach the texture in this slot.
+ **/
+void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_len)
+{
+ if (config[0].tex) {
+ BLI_assert(GPU_texture_depth(config[0].tex));
+ gpu_framebuffer_texture_attach_ex(fb, config[0].tex, 0, config[0].layer, config[0].mip);
+ }
+ else if (config[0].mip == -1) {
+ /* Leave texture attached */
+ }
+ else if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex != NULL) {
+ GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex);
+ }
+ else if (fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex != NULL) {
+ GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex);
}
- /* push attributes */
- glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
- glDisable(GL_SCISSOR_TEST);
+ int slot = 0;
+ for (int i = 1; i < config_len; ++i, ++slot) {
+ if (config[i].tex != NULL) {
+ BLI_assert(GPU_texture_depth(config[i].tex) == false);
+ gpu_framebuffer_texture_attach_ex(fb, config[i].tex, slot, config[i].layer, config[i].mip);
+ }
+ else if (config[i].mip != -1) {
+ GPUTexture *tex = framebuffer_get_color_tex(fb, slot);
+ if (tex != NULL) {
+ GPU_framebuffer_texture_detach(fb, tex);
+ }
+ }
+ }
+}
- /* bind framebuffer */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+/* ---------- Bind / Restore ----------- */
- if (GPU_texture_depth(tex)) {
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
+static void gpu_framebuffer_attachment_attach(GPUAttachment *attach, GPUAttachmentType attach_type)
+{
+ int tex_bind = GPU_texture_opengl_bindcode(attach->tex);
+ GLenum gl_attachment = convert_attachment_type_to_gl(attach_type);
+
+ if (attach->layer > -1) {
+ if (GPU_texture_cube(attach->tex)) {
+ glFramebufferTexture2D(
+ GL_FRAMEBUFFER, gl_attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach->layer,
+ tex_bind, attach->mip);
+ }
+ else {
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip, attach->layer);
+ }
}
else {
- /* last bound prevails here, better allow explicit control here too */
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment);
+ glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip);
}
+}
- if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) {
- glEnable(GL_MULTISAMPLE);
- }
-
- /* push matrices and set default viewport and matrix */
- glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
- GG.currentfb = fb->object;
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
+static void gpu_framebuffer_attachment_detach(GPUAttachment *UNUSED(attachment), GPUAttachmentType attach_type)
+{
+ GLenum gl_attachment = convert_attachment_type_to_gl(attach_type);
+ glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0);
}
-void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
+static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb)
{
- int numslots = 0, i;
- GLenum attachments[4];
+ GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT];
+ int numslots = 0;
- if (!fb->colortex[slot]) {
- fprintf(stderr, "Error, framebuffer slot empty!\n");
- return;
- }
+ BLI_assert(GPU_framebuffer_active_get() == fb);
+
+ /* Update attachments */
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
- for (i = 0; i < 4; i++) {
- if (fb->colortex[i]) {
- attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
+ if (type >= GPU_FB_COLOR_ATTACHMENT0) {
+ if (fb->attachments[type].tex) {
+ gl_attachments[numslots] = convert_attachment_type_to_gl(type);
+ }
+ else {
+ gl_attachments[numslots] = GL_NONE;
+ }
numslots++;
}
+
+ if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type) == false) {
+ continue;
+ }
+ else if (fb->attachments[type].tex != NULL) {
+ gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
+
+ fb->multisample = (GPU_texture_samples(fb->attachments[type].tex) > 0);
+ fb->width = GPU_texture_width(fb->attachments[type].tex);
+ fb->height = GPU_texture_height(fb->attachments[type].tex);
+ }
+ else {
+ gpu_framebuffer_attachment_detach(&fb->attachments[type], type);
+ }
}
+ fb->dirty_flag = 0;
- /* push attributes */
- glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
- glDisable(GL_SCISSOR_TEST);
+ /* Update draw buffers (color targets)
+ * This state is saved in the FBO */
+ if (numslots)
+ glDrawBuffers(numslots, gl_attachments);
+ else
+ glDrawBuffer(GL_NONE);
+}
- /* bind framebuffer */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- /* last bound prevails here, better allow explicit control here too */
- glDrawBuffers(numslots, attachments);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+#define FRAMEBUFFER_STACK_DEPTH 16
- /* push matrices and set default viewport and matrix */
- glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
- GG.currentfb = fb->object;
+static struct {
+ GPUFrameBuffer *framebuffers[FRAMEBUFFER_STACK_DEPTH];
+ uint top;
+} FrameBufferStack = { 0 };
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
+static void gpuPushFrameBuffer(GPUFrameBuffer *fbo)
+{
+ BLI_assert(FrameBufferStack.top < FRAMEBUFFER_STACK_DEPTH);
+ FrameBufferStack.framebuffers[FrameBufferStack.top] = fbo;
+ FrameBufferStack.top++;
+}
+
+static GPUFrameBuffer *gpuPopFrameBuffer(void)
+{
+ BLI_assert(FrameBufferStack.top > 0);
+ FrameBufferStack.top--;
+ return FrameBufferStack.framebuffers[FrameBufferStack.top];
}
+#undef FRAMEBUFFER_STACK_DEPTH
-void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
+
+void GPU_framebuffer_bind(GPUFrameBuffer *fb)
{
- /* restore matrix */
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
+ if (fb->object == 0)
+ gpu_framebuffer_init(fb);
+
+ if (GPU_framebuffer_active_get() != fb)
+ glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
+
+ gpu_framebuffer_current_set(fb);
+
+ if (fb->dirty_flag != 0)
+ gpu_framebuffer_update_attachments(fb);
+
+ /* TODO manually check for errors? */
+#if 0
+ char err_out[256];
+ if (!GPU_framebuffer_check_valid(fb, err_out)) {
+ printf("Invalid %s\n", err_out);
+ }
+#endif
- /* restore attributes */
- glPopAttrib();
+ if (fb->multisample)
+ glEnable(GL_MULTISAMPLE);
+
+ glViewport(0, 0, fb->width, fb->height);
}
-void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
+void GPU_framebuffer_restore(void)
{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- /* last bound prevails here, better allow explicit control here too */
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
-
- /* push matrices and set default viewport and matrix */
- glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
- GG.currentfb = fb->object;
- GG.currentfb = fb->object;
+ if (GPU_framebuffer_active_get() != NULL) {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ gpu_framebuffer_current_set(NULL);
+ }
}
bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
{
- return fb->object == GG.currentfb;
+ return (fb == GPU_framebuffer_active_get()) && (fb->object != 0);
}
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
{
- GLenum status;
-
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- GG.currentfb = fb->object;
+ if (!GPU_framebuffer_bound(fb))
+ GPU_framebuffer_bind(fb);
- /* Clean glError buffer. */
- while (glGetError() != GL_NO_ERROR) {}
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
-
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
GPU_framebuffer_restore();
gpu_print_framebuffer_error(status, err_out);
return false;
@@ -338,109 +497,221 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
return true;
}
-void GPU_framebuffer_free(GPUFrameBuffer *fb)
+/* ---------- Framebuffer Operations ----------- */
+
+#define CHECK_FRAMEBUFFER_IS_BOUND(_fb) \
+ BLI_assert(GPU_framebuffer_bound(_fb)); \
+ UNUSED_VARS_NDEBUG(_fb);
+
+/* Needs to be done after binding. */
+void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h)
{
- int i;
- if (fb->depthtex)
- GPU_framebuffer_texture_detach(fb->depthtex);
+ CHECK_FRAMEBUFFER_IS_BOUND(fb);
- for (i = 0; i < GPU_FB_MAX_SLOTS; i++) {
- if (fb->colortex[i]) {
- GPU_framebuffer_texture_detach(fb->colortex[i]);
- }
- }
+ glViewport(x, y, w, h);
+}
- if (fb->object) {
- glDeleteFramebuffersEXT(1, &fb->object);
+void GPU_framebuffer_clear(
+ GPUFrameBuffer *fb, GPUFrameBufferBits buffers,
+ const float clear_col[4], float clear_depth, uint clear_stencil)
+{
+ CHECK_FRAMEBUFFER_IS_BOUND(fb);
- if (GG.currentfb == fb->object) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- GG.currentfb = 0;
- }
+ if (buffers & GPU_COLOR_BIT) {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
+ }
+ if (buffers & GPU_DEPTH_BIT) {
+ glDepthMask(GL_TRUE);
+ glClearDepth(clear_depth);
+ }
+ if (buffers & GPU_STENCIL_BIT) {
+ glStencilMask(0xFF);
+ glClearStencil(clear_stencil);
}
- MEM_freeN(fb);
+ GLbitfield mask = convert_buffer_bits_to_gl(buffers);
+ glClear(mask);
}
-void GPU_framebuffer_restore(void)
+void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data)
{
- if (GG.currentfb != 0) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- GG.currentfb = 0;
- }
+ CHECK_FRAMEBUFFER_IS_BOUND(fb);
+
+ GLenum type = GL_DEPTH_COMPONENT;
+ glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */
+ glReadPixels(x, y, w, h, type, GL_FLOAT, data);
}
-void GPU_framebuffer_blur(
- GPUFrameBuffer *fb, GPUTexture *tex,
- GPUFrameBuffer *blurfb, GPUTexture *blurtex)
+void GPU_framebuffer_read_color(
+ GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data)
{
- const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f};
- const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)};
+ CHECK_FRAMEBUFFER_IS_BOUND(fb);
+
+ GLenum type;
+ switch (channels) {
+ case 1: type = GL_RED; break;
+ case 2: type = GL_RG; break;
+ case 3: type = GL_RGB; break;
+ case 4: type = GL_RGBA; break;
+ default:
+ BLI_assert(false && "wrong number of read channels");
+ return;
+ }
+ glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
+ glReadPixels(x, y, w, h, type, GL_FLOAT, data);
+}
- GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
- int scale_uniform, texture_source_uniform;
+/* read_slot and write_slot are only used for color buffers. */
+void GPU_framebuffer_blit(
+ GPUFrameBuffer *fb_read, int read_slot,
+ GPUFrameBuffer *fb_write, int write_slot,
+ GPUFrameBufferBits blit_buffers)
+{
+ BLI_assert(blit_buffers != 0);
- if (!blur_shader)
- return;
+ GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get();
- scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU");
- texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource");
+ /* Framebuffers must be up to date. This simplify this function. */
+ if (fb_read->dirty_flag != 0 || fb_read->object == 0) {
+ GPU_framebuffer_bind(fb_read);
+ }
+ if (fb_write->dirty_flag != 0 || fb_write->object == 0) {
+ GPU_framebuffer_bind(fb_write);
+ }
- /* Blurring horizontally */
+ const bool do_color = (blit_buffers & GPU_COLOR_BIT);
+ const bool do_depth = (blit_buffers & GPU_DEPTH_BIT);
+ const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT);
+
+ GPUTexture *read_tex = (
+ (do_depth || do_stencil) ?
+ framebuffer_get_depth_tex(fb_read) :
+ framebuffer_get_color_tex(fb_read, read_slot));
+ GPUTexture *write_tex = (
+ (do_depth || do_stencil) ?
+ framebuffer_get_depth_tex(fb_write) :
+ framebuffer_get_color_tex(fb_write, read_slot));
+
+ if (do_depth) {
+ BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex));
+ BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
+ }
+ if (do_stencil) {
+ BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex));
+ BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
+ }
+ if (GPU_texture_samples(write_tex) != 0 ||
+ GPU_texture_samples(read_tex) != 0)
+ {
+ /* Can only blit multisample textures to another texture of the same size. */
+ BLI_assert((fb_read->width == fb_write->width) &&
+ (fb_read->height == fb_write->height));
+ }
- /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid
- * pushing unnecessary matrices onto the OpenGL stack. */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object);
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object);
- /* avoid warnings from texture binding */
- GG.currentfb = blurfb->object;
+ if (do_color) {
+ glReadBuffer(GL_COLOR_ATTACHMENT0 + read_slot);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0 + write_slot);
+ /* XXX we messed with the glDrawBuffer, this will reset the
+ * glDrawBuffers the next time we bind fb_write. */
+ fb_write->dirty_flag = GPU_FB_DIRTY_DRAWBUFFER;
+ }
- GPU_shader_bind(blur_shader);
- GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh);
- GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
- glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex));
+ GLbitfield mask = convert_buffer_bits_to_gl(blit_buffers);
- /* Preparing to draw quad */
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+ glBlitFramebuffer(
+ 0, 0, fb_read->width, fb_read->height,
+ 0, 0, fb_write->width, fb_write->height,
+ mask, GL_NEAREST);
- glDisable(GL_DEPTH_TEST);
+ /* Restore previous framebuffer */
+ if (fb_write == prev_fb) {
+ GPU_framebuffer_bind(fb_write); /* To update drawbuffers */
+ }
+ else if (prev_fb) {
+ glBindFramebuffer(GL_FRAMEBUFFER, prev_fb->object);
+ gpu_framebuffer_current_set(prev_fb);
+ }
+ else {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ gpu_framebuffer_current_set(NULL);
+ }
+}
- GPU_texture_bind(tex, 0);
+/**
+ * Use this if you need to custom downsample your texture and use the previous mip level as input.
+ * This function only takes care of the correct texture handling. It execute the callback for each texture level.
+ **/
+void GPU_framebuffer_recursive_downsample(
+ GPUFrameBuffer *fb, int max_lvl,
+ void (*callback)(void *userData, int level), void *userData)
+{
+ /* Framebuffer must be up to date and bound. This simplify this function. */
+ if (GPU_framebuffer_active_get() != fb || fb->dirty_flag != 0 || fb->object == 0) {
+ GPU_framebuffer_bind(fb);
+ }
+ /* HACK: We make the framebuffer appear not bound in order to
+ * not trigger any error in GPU_texture_bind(). */
+ GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get();
+ gpu_framebuffer_current_set(NULL);
- /* Drawing quad */
- glBegin(GL_QUADS);
- glTexCoord2d(0, 0); glVertex2f(1, 1);
- glTexCoord2d(1, 0); glVertex2f(-1, 1);
- glTexCoord2d(1, 1); glVertex2f(-1, -1);
- glTexCoord2d(0, 1); glVertex2f(1, -1);
- glEnd();
+ int levels = floor(log2(max_ii(fb->width, fb->height)));
+ max_lvl = min_ii(max_lvl, levels);
- /* Blurring vertically */
+ int i;
+ int current_dim[2] = {fb->width, fb->height};
+ for (i = 1; i < max_lvl + 1; i++) {
+ /* calculate next viewport size */
+ current_dim[0] = max_ii(current_dim[0] / 2, 1);
+ current_dim[1] = max_ii(current_dim[1] / 2, 1);
+
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
+ if (fb->attachments[type].tex != NULL) {
+ /* Some Intel HDXXX have issue with rendering to a mipmap that is below
+ * the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
+ * we allow GL_TEXTURE_MAX_LEVEL to be one level lower. In practice it does work! */
+ int next_lvl = (GPU_mip_render_workaround()) ? i : i - 1;
+ /* bind next level for rendering but first restrict fetches only to previous level */
+ GPUTexture *tex = fb->attachments[type].tex;
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, next_lvl);
+ GPU_texture_unbind(tex);
+ /* copy attachment and replace miplevel. */
+ GPUAttachment attachment = fb->attachments[type];
+ attachment.mip = i;
+ gpu_framebuffer_attachment_attach(&attachment, type);
+ }
+ }
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ BLI_assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER));
- GG.currentfb = fb->object;
+ glViewport(0, 0, current_dim[0], current_dim[1]);
+ callback(userData, i);
- glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
- GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev);
- GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex);
- GPU_texture_bind(blurtex, 0);
+ if (current_dim[0] == 1 && current_dim[1] == 1)
+ break;
+ }
- glBegin(GL_QUADS);
- glTexCoord2d(0, 0); glVertex2f(1, 1);
- glTexCoord2d(1, 0); glVertex2f(-1, 1);
- glTexCoord2d(1, 1); glVertex2f(-1, -1);
- glTexCoord2d(0, 1); glVertex2f(1, -1);
- glEnd();
+ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
+ if (fb->attachments[type].tex != NULL) {
+ /* reset mipmap level range */
+ GPUTexture *tex = fb->attachments[type].tex;
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1);
+ GPU_texture_unbind(tex);
+ /* Reattach original level */
+ /* NOTE: This is not necessary but this makes the FBO config
+ * remain in sync with the GPUFrameBuffer config. */
+ gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
+ }
+ }
- GPU_shader_unbind();
+ gpu_framebuffer_current_set(prev_fb);
}
/* GPUOffScreen */
@@ -451,63 +722,43 @@ struct GPUOffScreen {
GPUTexture *depth;
};
-GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256])
+GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool depth, bool high_bitdepth, char err_out[256])
{
GPUOffScreen *ofs;
ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
- ofs->fb = GPU_framebuffer_create();
- if (!ofs->fb) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
+ ofs->color = GPU_texture_create_2D_multisample(
+ width, height,
+ (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, NULL, samples, err_out);
- if (samples) {
- if (!GLEW_EXT_framebuffer_multisample ||
- !GLEW_ARB_texture_multisample ||
- /* Only needed for GPU_offscreen_read_pixels.
- * We could add an arg if we intend to use multi-sample
- * offscreen buffers w/o reading their pixels */
- !GLEW_EXT_framebuffer_blit ||
- /* This is required when blitting from a multi-sampled buffers,
- * even though we're not scaling. */
- !GLEW_EXT_framebuffer_multisample_blit_scaled)
- {
- samples = 0;
- }
+ if (depth) {
+ ofs->depth = GPU_texture_create_2D_multisample(width, height, GPU_DEPTH24_STENCIL8, NULL, samples, err_out);
}
- ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out);
- if (!ofs->depth) {
+ if ((depth && !ofs->depth) || !ofs->color) {
GPU_offscreen_free(ofs);
return NULL;
}
- if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
+ gpuPushAttrib(GPU_VIEWPORT_BIT);
- ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out);
- if (!ofs->color) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
-
- if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
+ GPU_framebuffer_ensure_config(&ofs->fb, {
+ GPU_ATTACHMENT_TEXTURE(ofs->depth),
+ GPU_ATTACHMENT_TEXTURE(ofs->color)
+ });
/* check validity at the very end! */
if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) {
GPU_offscreen_free(ofs);
+ gpuPopAttrib();
return NULL;
}
GPU_framebuffer_restore();
+ gpuPopAttrib();
+
return ofs;
}
@@ -525,20 +776,48 @@ void GPU_offscreen_free(GPUOffScreen *ofs)
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
{
+ if (save) {
+ gpuPushAttrib(GPU_SCISSOR_BIT | GPU_VIEWPORT_BIT);
+ GPUFrameBuffer *fb = GPU_framebuffer_active_get();
+ gpuPushFrameBuffer(fb);
+ }
glDisable(GL_SCISSOR_TEST);
- if (save)
- GPU_texture_bind_as_framebuffer(ofs->color);
+ GPU_framebuffer_bind(ofs->fb);
+}
+
+void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore)
+{
+ GPUFrameBuffer *fb = NULL;
+
+ if (restore) {
+ gpuPopAttrib();
+ fb = gpuPopFrameBuffer();
+ }
+
+ if (fb) {
+ GPU_framebuffer_bind(fb);
+ }
else {
- GPU_framebuffer_bind_no_save(ofs->fb, 0);
+ GPU_framebuffer_restore();
}
}
-void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore)
+void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y)
{
- if (restore)
- GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
- GPU_framebuffer_restore();
- glEnable(GL_SCISSOR_TEST);
+ const int w = GPU_texture_width(ofs->color);
+ const int h = GPU_texture_height(ofs->color);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->fb->object);
+ GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
+
+ if (status == GL_FRAMEBUFFER_COMPLETE) {
+ glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ }
+ else {
+ gpu_print_framebuffer_error(status, NULL);
+ }
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
@@ -546,74 +825,48 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
const int w = GPU_texture_width(ofs->color);
const int h = GPU_texture_height(ofs->color);
+ BLI_assert(type == GL_UNSIGNED_BYTE || type == GL_FLOAT);
+
if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) {
/* For a multi-sample texture,
* we need to create an intermediate buffer to blit to,
* before its copied using 'glReadPixels' */
-
- /* not needed since 'ofs' needs to be bound to the framebuffer already */
-// #define USE_FBO_CTX_SWITCH
-
GLuint fbo_blit = 0;
GLuint tex_blit = 0;
- GLenum status;
/* create texture for new 'fbo_blit' */
glGenTextures(1, &tex_blit);
- if (!tex_blit) {
- goto finally;
- }
-
glBindTexture(GL_TEXTURE_2D, tex_blit);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, type, 0);
-
-#ifdef USE_FBO_CTX_SWITCH
- /* read from multi-sample buffer */
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object);
- glFramebufferTexture2DEXT(
- GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment,
- GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
- status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT);
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- goto finally;
- }
-#endif
+ glTexImage2D(
+ GL_TEXTURE_2D, 0, (type == GL_FLOAT) ? GL_RGBA16F : GL_RGBA8,
+ w, h, 0, GL_RGBA, type, 0);
/* write into new single-sample buffer */
- glGenFramebuffersEXT(1, &fbo_blit);
- glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
- glFramebufferTexture2DEXT(
- GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ glGenFramebuffers(1, &fbo_blit);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit);
+ glFramebufferTexture2D(
+ GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex_blit, 0);
- status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+
+ GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
goto finally;
}
/* perform the copy */
- glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
/* read the results */
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit);
glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
-#ifdef USE_FBO_CTX_SWITCH
/* restore the original frame-bufer */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ofs->color->fb->object);
-#undef USE_FBO_CTX_SWITCH
-#endif
-
+ glBindFramebuffer(GL_FRAMEBUFFER, ofs->fb->object);
finally:
/* cleanup */
- if (tex_blit) {
- glDeleteTextures(1, &tex_blit);
- }
- if (fbo_blit) {
- glDeleteFramebuffersEXT(1, &fbo_blit);
- }
-
- GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels");
+ glDeleteTextures(1, &tex_blit);
+ glDeleteFramebuffers(1, &fbo_blit);
}
else {
glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
@@ -630,7 +883,27 @@ int GPU_offscreen_height(const GPUOffScreen *ofs)
return GPU_texture_height(ofs->color);
}
-int GPU_offscreen_color_texture(const GPUOffScreen *ofs)
+GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs)
+{
+ return ofs->color;
+}
+
+/* only to be used by viewport code! */
+void GPU_offscreen_viewport_data_get(
+ GPUOffScreen *ofs,
+ GPUFrameBuffer **r_fb, GPUTexture **r_color, GPUTexture **r_depth)
+{
+ *r_fb = ofs->fb;
+ *r_color = ofs->color;
+ *r_depth = ofs->depth;
+}
+
+void GPU_clear_color(float red, float green, float blue, float alpha)
+{
+ glClearColor(red, green, blue, alpha);
+}
+
+void GPU_clear(GPUFrameBufferBits flags)
{
- return GPU_texture_opengl_bindcode(ofs->color);
+ glClear(convert_buffer_bits_to_gl(flags));
}
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c
new file mode 100644
index 00000000000..a71ba68821b
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_immediate.c
@@ -0,0 +1,924 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_immediate.c
+ * \ingroup gpu
+ *
+ * GPU immediate mode work-alike
+ */
+
+#include "UI_resources.h"
+
+#include "GPU_attr_binding.h"
+#include "GPU_immediate.h"
+
+#include "gpu_attr_binding_private.h"
+#include "gpu_context_private.h"
+#include "gpu_primitive_private.h"
+#include "gpu_shader_private.h"
+#include "gpu_vertex_format_private.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+/* necessary functions from matrix API */
+extern void GPU_matrix_bind(const GPUShaderInterface *);
+extern bool GPU_matrix_dirty_get(void);
+
+typedef struct {
+ /* TODO: organize this struct by frequency of change (run-time) */
+
+ GPUBatch *batch;
+ GPUContext *context;
+
+ /* current draw call */
+ GLubyte *buffer_data;
+ uint buffer_offset;
+ uint buffer_bytes_mapped;
+ uint vertex_len;
+ bool strict_vertex_len;
+ GPUPrimType prim_type;
+
+ GPUVertFormat vertex_format;
+
+ /* current vertex */
+ uint vertex_idx;
+ GLubyte *vertex_data;
+ uint16_t unassigned_attrib_bits; /* which attributes of current vertex have not been given values? */
+
+ GLuint vbo_id;
+ GLuint vao_id;
+
+ GLuint bound_program;
+ const GPUShaderInterface *shader_interface;
+ GPUAttrBinding attrib_binding;
+ uint16_t prev_enabled_attrib_bits; /* <-- only affects this VAO, so we're ok */
+} Immediate;
+
+/* size of internal buffer -- make this adjustable? */
+#define IMM_BUFFER_SIZE (4 * 1024 * 1024)
+
+static bool initialized = false;
+static Immediate imm;
+
+void immInit(void)
+{
+#if TRUST_NO_ONE
+ assert(!initialized);
+#endif
+ memset(&imm, 0, sizeof(Immediate));
+
+ imm.vbo_id = GPU_buf_alloc();
+ glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
+ glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+
+ imm.prim_type = GPU_PRIM_NONE;
+ imm.strict_vertex_len = true;
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ initialized = true;
+}
+
+void immActivate(void)
+{
+#if TRUST_NO_ONE
+ assert(initialized);
+ assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we're not between a Begin/End pair */
+ assert(imm.vao_id == 0);
+#endif
+ imm.vao_id = GPU_vao_alloc();
+ imm.context = GPU_context_active_get();
+}
+
+void immDeactivate(void)
+{
+#if TRUST_NO_ONE
+ assert(initialized);
+ assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we're not between a Begin/End pair */
+ assert(imm.vao_id != 0);
+#endif
+ GPU_vao_free(imm.vao_id, imm.context);
+ imm.vao_id = 0;
+ imm.prev_enabled_attrib_bits = 0;
+}
+
+void immDestroy(void)
+{
+ GPU_buf_free(imm.vbo_id);
+ initialized = false;
+}
+
+GPUVertFormat *immVertexFormat(void)
+{
+ GPU_vertformat_clear(&imm.vertex_format);
+ return &imm.vertex_format;
+}
+
+void immBindProgram(GLuint program, const GPUShaderInterface *shaderface)
+{
+#if TRUST_NO_ONE
+ assert(imm.bound_program == 0);
+ assert(glIsProgram(program));
+#endif
+
+ imm.bound_program = program;
+ imm.shader_interface = shaderface;
+
+ if (!imm.vertex_format.packed)
+ VertexFormat_pack(&imm.vertex_format);
+
+ glUseProgram(program);
+ get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, shaderface);
+ GPU_matrix_bind(shaderface);
+}
+
+void immBindBuiltinProgram(GPUBuiltinShader shader_id)
+{
+ GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
+ immBindProgram(shader->program, shader->interface);
+}
+
+void immUnbindProgram(void)
+{
+#if TRUST_NO_ONE
+ assert(imm.bound_program != 0);
+#endif
+#if PROGRAM_NO_OPTI
+ glUseProgram(0);
+#endif
+ imm.bound_program = 0;
+}
+
+#if TRUST_NO_ONE
+static bool vertex_count_makes_sense_for_primitive(uint vertex_len, GPUPrimType prim_type)
+{
+ /* does vertex_len make sense for this primitive type? */
+ if (vertex_len == 0) {
+ return false;
+ }
+
+ switch (prim_type) {
+ case GPU_PRIM_POINTS:
+ return true;
+ case GPU_PRIM_LINES:
+ return vertex_len % 2 == 0;
+ case GPU_PRIM_LINE_STRIP:
+ case GPU_PRIM_LINE_LOOP:
+ return vertex_len >= 2;
+ case GPU_PRIM_LINE_STRIP_ADJ:
+ return vertex_len >= 4;
+ case GPU_PRIM_TRIS:
+ return vertex_len % 3 == 0;
+ case GPU_PRIM_TRI_STRIP:
+ case GPU_PRIM_TRI_FAN:
+ return vertex_len >= 3;
+ default:
+ return false;
+ }
+}
+#endif
+
+void immBegin(GPUPrimType prim_type, uint vertex_len)
+{
+#if TRUST_NO_ONE
+ assert(initialized);
+ assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we haven't already begun */
+ assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type));
+#endif
+ imm.prim_type = prim_type;
+ imm.vertex_len = vertex_len;
+ imm.vertex_idx = 0;
+ imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
+
+ /* how many bytes do we need for this draw call? */
+ const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len);
+
+#if TRUST_NO_ONE
+ assert(bytes_needed <= IMM_BUFFER_SIZE);
+#endif
+
+ glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
+
+ /* does the current buffer have enough room? */
+ const uint available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset;
+ /* ensure vertex data is aligned */
+ const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); /* might waste a little space, but it's safe */
+ if ((bytes_needed + pre_padding) <= available_bytes) {
+ imm.buffer_offset += pre_padding;
+ }
+ else {
+ /* orphan this buffer & start with a fresh one */
+ /* this method works on all platforms, old & new */
+ glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
+
+ imm.buffer_offset = 0;
+ }
+
+/* printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); */
+
+ imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed,
+ GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT));
+
+#if TRUST_NO_ONE
+ assert(imm.buffer_data != NULL);
+#endif
+
+ imm.buffer_bytes_mapped = bytes_needed;
+ imm.vertex_data = imm.buffer_data;
+}
+
+void immBeginAtMost(GPUPrimType prim_type, uint vertex_len)
+{
+#if TRUST_NO_ONE
+ assert(vertex_len > 0);
+#endif
+
+ imm.strict_vertex_len = false;
+ immBegin(prim_type, vertex_len);
+}
+
+
+GPUBatch *immBeginBatch(GPUPrimType prim_type, uint vertex_len)
+{
+#if TRUST_NO_ONE
+ assert(initialized);
+ assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we haven't already begun */
+ assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type));
+#endif
+ imm.prim_type = prim_type;
+ imm.vertex_len = vertex_len;
+ imm.vertex_idx = 0;
+ imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
+
+ GPUVertBuf *verts = GPU_vertbuf_create_with_format(&imm.vertex_format);
+ GPU_vertbuf_data_alloc(verts, vertex_len);
+
+ imm.buffer_bytes_mapped = GPU_vertbuf_size_get(verts);
+ imm.vertex_data = verts->data;
+
+ imm.batch = GPU_batch_create_ex(prim_type, verts, NULL, GPU_BATCH_OWNS_VBO);
+ imm.batch->phase = GPU_BATCH_BUILDING;
+
+ return imm.batch;
+}
+
+GPUBatch *immBeginBatchAtMost(GPUPrimType prim_type, uint vertex_len)
+{
+ imm.strict_vertex_len = false;
+ return immBeginBatch(prim_type, vertex_len);
+}
+
+static void immDrawSetup(void)
+{
+ /* set up VAO -- can be done during Begin or End really */
+ glBindVertexArray(imm.vao_id);
+
+ /* enable/disable vertex attribs as needed */
+ if (imm.attrib_binding.enabled_bits != imm.prev_enabled_attrib_bits) {
+ for (uint loc = 0; loc < GPU_VERT_ATTR_MAX_LEN; ++loc) {
+ bool is_enabled = imm.attrib_binding.enabled_bits & (1 << loc);
+ bool was_enabled = imm.prev_enabled_attrib_bits & (1 << loc);
+
+ if (is_enabled && !was_enabled) {
+ glEnableVertexAttribArray(loc);
+ }
+ else if (was_enabled && !is_enabled) {
+ glDisableVertexAttribArray(loc);
+ }
+ }
+
+ imm.prev_enabled_attrib_bits = imm.attrib_binding.enabled_bits;
+ }
+
+ const uint stride = imm.vertex_format.stride;
+
+ for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
+ const GPUVertAttr *a = imm.vertex_format.attribs + a_idx;
+
+ const uint offset = imm.buffer_offset + a->offset;
+ const GLvoid *pointer = (const GLubyte *)0 + offset;
+
+ const uint loc = read_attrib_location(&imm.attrib_binding, a_idx);
+
+ switch (a->fetch_mode) {
+ case GPU_FETCH_FLOAT:
+ case GPU_FETCH_INT_TO_FLOAT:
+ glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer);
+ break;
+ case GPU_FETCH_INT_TO_FLOAT_UNIT:
+ glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer);
+ break;
+ case GPU_FETCH_INT:
+ glVertexAttribIPointer(loc, a->comp_len, a->gl_comp_type, stride, pointer);
+ }
+ }
+
+ if (GPU_matrix_dirty_get()) {
+ GPU_matrix_bind(imm.shader_interface);
+ }
+}
+
+void immEnd(void)
+{
+#if TRUST_NO_ONE
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+
+ uint buffer_bytes_used;
+ if (imm.strict_vertex_len) {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx == imm.vertex_len); /* with all vertices defined */
+#endif
+ buffer_bytes_used = imm.buffer_bytes_mapped;
+ }
+ else {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx <= imm.vertex_len);
+#endif
+ if (imm.vertex_idx == imm.vertex_len) {
+ buffer_bytes_used = imm.buffer_bytes_mapped;
+ }
+ else {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type));
+#endif
+ imm.vertex_len = imm.vertex_idx;
+ buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_len);
+ /* unused buffer bytes are available to the next immBegin */
+ }
+ /* tell OpenGL what range was modified so it doesn't copy the whole mapped range */
+ glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used);
+ }
+
+ if (imm.batch) {
+ if (buffer_bytes_used != imm.buffer_bytes_mapped) {
+ GPU_vertbuf_data_resize(imm.batch->verts[0], imm.vertex_len);
+ /* TODO: resize only if vertex count is much smaller */
+ }
+ GPU_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface);
+ imm.batch->phase = GPU_BATCH_READY_TO_DRAW;
+ imm.batch = NULL; /* don't free, batch belongs to caller */
+ }
+ else {
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ if (imm.vertex_len > 0) {
+ immDrawSetup();
+ glDrawArrays(convert_prim_type_to_gl(imm.prim_type), 0, imm.vertex_len);
+ }
+ /* These lines are causing crash on startup on some old GPU + drivers.
+ * They are not required so just comment them. (T55722) */
+ // glBindBuffer(GL_ARRAY_BUFFER, 0);
+ // glBindVertexArray(0);
+ /* prep for next immBegin */
+ imm.buffer_offset += buffer_bytes_used;
+ }
+
+ /* prep for next immBegin */
+ imm.prim_type = GPU_PRIM_NONE;
+ imm.strict_vertex_len = true;
+}
+
+static void setAttribValueBit(uint attrib_id)
+{
+ uint16_t mask = 1 << attrib_id;
+#if TRUST_NO_ONE
+ assert(imm.unassigned_attrib_bits & mask); /* not already set */
+#endif
+ imm.unassigned_attrib_bits &= ~mask;
+}
+
+
+/* --- generic attribute functions --- */
+
+void immAttr1f(uint attrib_id, float x)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_F32);
+ assert(attr->comp_len == 1);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ float *data = (float *)(imm.vertex_data + attr->offset);
+/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
+
+ data[0] = x;
+}
+
+void immAttr2f(uint attrib_id, float x, float y)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_F32);
+ assert(attr->comp_len == 2);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ float *data = (float *)(imm.vertex_data + attr->offset);
+/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
+
+ data[0] = x;
+ data[1] = y;
+}
+
+void immAttr3f(uint attrib_id, float x, float y, float z)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_F32);
+ assert(attr->comp_len == 3);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ float *data = (float *)(imm.vertex_data + attr->offset);
+/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
+
+ data[0] = x;
+ data[1] = y;
+ data[2] = z;
+}
+
+void immAttr4f(uint attrib_id, float x, float y, float z, float w)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_F32);
+ assert(attr->comp_len == 4);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ float *data = (float *)(imm.vertex_data + attr->offset);
+/* printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
+
+ data[0] = x;
+ data[1] = y;
+ data[2] = z;
+ data[3] = w;
+}
+
+void immAttr1u(uint attrib_id, uint x)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_U32);
+ assert(attr->comp_len == 1);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ uint *data = (uint *)(imm.vertex_data + attr->offset);
+
+ data[0] = x;
+}
+
+void immAttr2i(uint attrib_id, int x, int y)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_I32);
+ assert(attr->comp_len == 2);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ int *data = (int *)(imm.vertex_data + attr->offset);
+
+ data[0] = x;
+ data[1] = y;
+}
+
+void immAttr2s(uint attrib_id, short x, short y)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_I16);
+ assert(attr->comp_len == 2);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ short *data = (short *)(imm.vertex_data + attr->offset);
+
+ data[0] = x;
+ data[1] = y;
+}
+
+void immAttr2fv(uint attrib_id, const float data[2])
+{
+ immAttr2f(attrib_id, data[0], data[1]);
+}
+
+void immAttr3fv(uint attrib_id, const float data[3])
+{
+ immAttr3f(attrib_id, data[0], data[1], data[2]);
+}
+
+void immAttr4fv(uint attrib_id, const float data[4])
+{
+ immAttr4f(attrib_id, data[0], data[1], data[2], data[3]);
+}
+
+void immAttr3ub(uint attrib_id, uchar r, uchar g, uchar b)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_U8);
+ assert(attr->comp_len == 3);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ GLubyte *data = imm.vertex_data + attr->offset;
+/* printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */
+
+ data[0] = r;
+ data[1] = g;
+ data[2] = b;
+}
+
+void immAttr4ub(uint attrib_id, uchar r, uchar g, uchar b, uchar a)
+{
+ GPUVertAttr *attr = imm.vertex_format.attribs + attrib_id;
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(attr->comp_type == GPU_COMP_U8);
+ assert(attr->comp_len == 4);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+
+ GLubyte *data = imm.vertex_data + attr->offset;
+/* printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */
+
+ data[0] = r;
+ data[1] = g;
+ data[2] = b;
+ data[3] = a;
+}
+
+void immAttr3ubv(uint attrib_id, const uchar data[3])
+{
+ immAttr3ub(attrib_id, data[0], data[1], data[2]);
+}
+
+void immAttr4ubv(uint attrib_id, const uchar data[4])
+{
+ immAttr4ub(attrib_id, data[0], data[1], data[2], data[3]);
+}
+
+void immAttrSkip(uint attrib_id)
+{
+#if TRUST_NO_ONE
+ assert(attrib_id < imm.vertex_format.attr_len);
+ assert(imm.vertex_idx < imm.vertex_len);
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+#endif
+ setAttribValueBit(attrib_id);
+}
+
+static void immEndVertex(void) /* and move on to the next vertex */
+{
+#if TRUST_NO_ONE
+ assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+ assert(imm.vertex_idx < imm.vertex_len);
+#endif
+
+ /* have all attribs been assigned values?
+ * if not, copy value from previous vertex */
+ if (imm.unassigned_attrib_bits) {
+#if TRUST_NO_ONE
+ assert(imm.vertex_idx > 0); /* first vertex must have all attribs specified */
+#endif
+ for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
+ if ((imm.unassigned_attrib_bits >> a_idx) & 1) {
+ const GPUVertAttr *a = imm.vertex_format.attribs + a_idx;
+
+/* printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx); */
+
+ GLubyte *data = imm.vertex_data + a->offset;
+ memcpy(data, data - imm.vertex_format.stride, a->sz);
+ /* TODO: consolidate copy of adjacent attributes */
+ }
+ }
+ }
+
+ imm.vertex_idx++;
+ imm.vertex_data += imm.vertex_format.stride;
+ imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits;
+}
+
+void immVertex2f(uint attrib_id, float x, float y)
+{
+ immAttr2f(attrib_id, x, y);
+ immEndVertex();
+}
+
+void immVertex3f(uint attrib_id, float x, float y, float z)
+{
+ immAttr3f(attrib_id, x, y, z);
+ immEndVertex();
+}
+
+void immVertex4f(uint attrib_id, float x, float y, float z, float w)
+{
+ immAttr4f(attrib_id, x, y, z, w);
+ immEndVertex();
+}
+
+void immVertex2i(uint attrib_id, int x, int y)
+{
+ immAttr2i(attrib_id, x, y);
+ immEndVertex();
+}
+
+void immVertex2s(uint attrib_id, short x, short y)
+{
+ immAttr2s(attrib_id, x, y);
+ immEndVertex();
+}
+
+void immVertex2fv(uint attrib_id, const float data[2])
+{
+ immAttr2f(attrib_id, data[0], data[1]);
+ immEndVertex();
+}
+
+void immVertex3fv(uint attrib_id, const float data[3])
+{
+ immAttr3f(attrib_id, data[0], data[1], data[2]);
+ immEndVertex();
+}
+
+void immVertex2iv(uint attrib_id, const int data[2])
+{
+ immAttr2i(attrib_id, data[0], data[1]);
+ immEndVertex();
+}
+
+
+/* --- generic uniform functions --- */
+
+#if 0
+# if TRUST_NO_ONE
+# define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); assert(uniform);
+# else
+# define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform(imm.shader_interface, name);
+# endif
+#else
+ /* NOTE: It is possible to have uniform fully optimized out from the shader.
+ * In this case we can't assert failure or allow NULL-pointer dereference.
+ * TODO(sergey): How can we detect existing-but-optimized-out uniform but still
+ * catch typos in uniform names passed to immUniform*() functions? */
+# define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); if (uniform == NULL) return;
+#endif
+
+void immUniform1f(const char *name, float x)
+{
+ GET_UNIFORM
+ glUniform1f(uniform->location, x);
+}
+
+void immUniform2f(const char *name, float x, float y)
+{
+ GET_UNIFORM
+ glUniform2f(uniform->location, x, y);
+}
+
+void immUniform2fv(const char *name, const float data[2])
+{
+ GET_UNIFORM
+ glUniform2fv(uniform->location, 1, data);
+}
+
+void immUniform3f(const char *name, float x, float y, float z)
+{
+ GET_UNIFORM
+ glUniform3f(uniform->location, x, y, z);
+}
+
+void immUniform3fv(const char *name, const float data[3])
+{
+ GET_UNIFORM
+ glUniform3fv(uniform->location, 1, data);
+}
+
+/* can increase this limit or move to another file */
+#define MAX_UNIFORM_NAME_LEN 60
+
+void immUniformArray3fv(const char *bare_name, const float *data, int count)
+{
+ /* look up "name[0]" when given "name" */
+ const size_t len = strlen(bare_name);
+#if TRUST_NO_ONE
+ assert(len <= MAX_UNIFORM_NAME_LEN);
+#endif
+ char name[MAX_UNIFORM_NAME_LEN];
+ strcpy(name, bare_name);
+ name[len + 0] = '[';
+ name[len + 1] = '0';
+ name[len + 2] = ']';
+ name[len + 3] = '\0';
+
+ GET_UNIFORM
+ glUniform3fv(uniform->location, count, data);
+}
+
+void immUniform4f(const char *name, float x, float y, float z, float w)
+{
+ GET_UNIFORM
+ glUniform4f(uniform->location, x, y, z, w);
+}
+
+void immUniform4fv(const char *name, const float data[4])
+{
+ GET_UNIFORM
+ glUniform4fv(uniform->location, 1, data);
+}
+
+void immUniformArray4fv(const char *bare_name, const float *data, int count)
+{
+ /* look up "name[0]" when given "name" */
+ const size_t len = strlen(bare_name);
+#if TRUST_NO_ONE
+ assert(len <= MAX_UNIFORM_NAME_LEN);
+#endif
+ char name[MAX_UNIFORM_NAME_LEN];
+ strcpy(name, bare_name);
+ name[len + 0] = '[';
+ name[len + 1] = '0';
+ name[len + 2] = ']';
+ name[len + 3] = '\0';
+
+ GET_UNIFORM
+ glUniform4fv(uniform->location, count, data);
+}
+
+void immUniformMatrix4fv(const char *name, const float data[4][4])
+{
+ GET_UNIFORM
+ glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data);
+}
+
+void immUniform1i(const char *name, int x)
+{
+ GET_UNIFORM
+ glUniform1i(uniform->location, x);
+}
+
+void immUniform4iv(const char *name, const int data[4])
+{
+ GET_UNIFORM
+ glUniform4iv(uniform->location, 1, data);
+}
+
+/* --- convenience functions for setting "uniform vec4 color" --- */
+
+void immUniformColor4f(float r, float g, float b, float a)
+{
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(imm.shader_interface, GPU_UNIFORM_COLOR);
+#if TRUST_NO_ONE
+ assert(uniform != NULL);
+#endif
+ glUniform4f(uniform->location, r, g, b, a);
+}
+
+void immUniformColor4fv(const float rgba[4])
+{
+ immUniformColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);
+}
+
+void immUniformColor3f(float r, float g, float b)
+{
+ immUniformColor4f(r, g, b, 1.0f);
+}
+
+void immUniformColor3fv(const float rgb[3])
+{
+ immUniformColor4f(rgb[0], rgb[1], rgb[2], 1.0f);
+}
+
+void immUniformColor3fvAlpha(const float rgb[3], float a)
+{
+ immUniformColor4f(rgb[0], rgb[1], rgb[2], a);
+}
+
+/* TODO: v-- treat as sRGB? --v */
+
+void immUniformColor3ub(uchar r, uchar g, uchar b)
+{
+ const float scale = 1.0f / 255.0f;
+ immUniformColor4f(scale * r, scale * g, scale * b, 1.0f);
+}
+
+void immUniformColor4ub(uchar r, uchar g, uchar b, uchar a)
+{
+ const float scale = 1.0f / 255.0f;
+ immUniformColor4f(scale * r, scale * g, scale * b, scale * a);
+}
+
+void immUniformColor3ubv(const uchar rgb[3])
+{
+ immUniformColor3ub(rgb[0], rgb[1], rgb[2]);
+}
+
+void immUniformColor3ubvAlpha(const uchar rgb[3], uchar alpha)
+{
+ immUniformColor4ub(rgb[0], rgb[1], rgb[2], alpha);
+}
+
+void immUniformColor4ubv(const uchar rgba[4])
+{
+ immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]);
+}
+
+void immUniformThemeColor(int color_id)
+{
+ float color[4];
+ UI_GetThemeColor4fv(color_id, color);
+ immUniformColor4fv(color);
+}
+
+void immUniformThemeColor3(int color_id)
+{
+ float color[3];
+ UI_GetThemeColor3fv(color_id, color);
+ immUniformColor3fv(color);
+}
+
+void immUniformThemeColorShade(int color_id, int offset)
+{
+ float color[4];
+ UI_GetThemeColorShade4fv(color_id, offset, color);
+ immUniformColor4fv(color);
+}
+
+void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
+{
+ float color[4];
+ UI_GetThemeColorShadeAlpha4fv(color_id, color_offset, alpha_offset, color);
+ immUniformColor4fv(color);
+}
+
+void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset)
+{
+ float color[4];
+ UI_GetThemeColorBlendShade4fv(color_id1, color_id2, fac, offset, color);
+ immUniformColor4fv(color);
+}
+
+void immUniformThemeColorBlend(int color_id1, int color_id2, float fac)
+{
+ uint8_t color[3];
+ UI_GetThemeColorBlend3ubv(color_id1, color_id2, fac, color);
+ immUniformColor3ubv(color);
+}
+
+void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
+{
+ uchar col[4];
+ UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col);
+ immUniformColor4ub(col[0], col[1], col[2], col[3]);
+}
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
new file mode 100644
index 00000000000..5cba0c42ee3
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -0,0 +1,528 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_immediate_util.c
+ * \ingroup gpu
+ *
+ * GPU immediate mode drawing utilities
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+
+static const float cube_coords[8][3] = {
+ {-1, -1, -1},
+ {-1, -1, +1},
+ {-1, +1, -1},
+ {-1, +1, +1},
+ {+1, -1, -1},
+ {+1, -1, +1},
+ {+1, +1, -1},
+ {+1, +1, +1},
+};
+static const int cube_quad_index[6][4] = {
+ {0, 1, 3, 2},
+ {0, 2, 6, 4},
+ {0, 4, 5, 1},
+ {1, 5, 7, 3},
+ {2, 3, 7, 6},
+ {4, 6, 7, 5},
+};
+static const int cube_line_index[12][2] = {
+ {0, 1},
+ {0, 2},
+ {0, 4},
+ {1, 3},
+ {1, 5},
+ {2, 3},
+ {2, 6},
+ {3, 7},
+ {4, 5},
+ {4, 6},
+ {5, 7},
+ {6, 7},
+};
+
+void immRectf(uint pos, float x1, float y1, float x2, float y2)
+{
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y1);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x1, y2);
+ immEnd();
+}
+
+void immRecti(uint pos, int x1, int y1, int x2, int y2)
+{
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immVertex2i(pos, x1, y1);
+ immVertex2i(pos, x2, y1);
+ immVertex2i(pos, x2, y2);
+ immVertex2i(pos, x1, y2);
+ immEnd();
+}
+
+void immRectf_fast(uint pos, float x1, float y1, float x2, float y2)
+{
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y1);
+ immVertex2f(pos, x2, y2);
+
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x1, y2);
+}
+
+void immRectf_fast_with_color(uint pos, uint col, float x1, float y1, float x2, float y2, const float color[4])
+{
+ immAttr4fv(col, color);
+ immVertex2f(pos, x1, y1);
+ immAttr4fv(col, color);
+ immVertex2f(pos, x2, y1);
+ immAttr4fv(col, color);
+ immVertex2f(pos, x2, y2);
+
+ immAttr4fv(col, color);
+ immVertex2f(pos, x1, y1);
+ immAttr4fv(col, color);
+ immVertex2f(pos, x2, y2);
+ immAttr4fv(col, color);
+ immVertex2f(pos, x1, y2);
+}
+
+void immRecti_fast_with_color(uint pos, uint col, int x1, int y1, int x2, int y2, const float color[4])
+{
+ immAttr4fv(col, color);
+ immVertex2i(pos, x1, y1);
+ immAttr4fv(col, color);
+ immVertex2i(pos, x2, y1);
+ immAttr4fv(col, color);
+ immVertex2i(pos, x2, y2);
+
+ immAttr4fv(col, color);
+ immVertex2i(pos, x1, y1);
+ immAttr4fv(col, color);
+ immVertex2i(pos, x2, y2);
+ immAttr4fv(col, color);
+ immVertex2i(pos, x1, y2);
+}
+
+#if 0 /* more complete version in case we want that */
+void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = add_attrib(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+ immRecti(pos, x1, y1, x2, y2);
+ immUnbindProgram();
+}
+#endif
+
+/**
+ * Pack color into 3 bytes
+ *
+ * This define converts a numerical value to the equivalent 24-bit
+ * color, while not being endian-sensitive. On little-endians, this
+ * is the same as doing a 'naive' indexing, on big-endian, it is not!
+ *
+ * \note BGR format (i.e. 0xBBGGRR)...
+ *
+ * \param x color.
+ */
+void imm_cpack(uint x)
+{
+ immUniformColor3ub(((x) & 0xFF),
+ (((x) >> 8) & 0xFF),
+ (((x) >> 16) & 0xFF));
+}
+
+static void imm_draw_circle(
+ GPUPrimType prim_type, const uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+{
+ immBegin(prim_type, nsegments);
+ for (int i = 0; i < nsegments; ++i) {
+ const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
+ immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle)));
+ }
+ immEnd();
+}
+
+/**
+ * Draw a circle outline with the given \a radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \param shdr_pos The vertex attribute number for position.
+ * \param x Horizontal center.
+ * \param y Vertical center.
+ * \param radius The circle's radius.
+ * \param nsegments The number of segments to use in drawing (more = smoother).
+ */
+void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
+{
+ imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad, rad, nsegments);
+}
+
+/**
+ * Draw a filled circle with the given \a radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \param shdr_pos The vertex attribute number for position.
+ * \param x Horizontal center.
+ * \param y Vertical center.
+ * \param radius The circle's radius.
+ * \param nsegments The number of segments to use in drawing (more = smoother).
+ */
+void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float rad, int nsegments)
+{
+ imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad, rad, nsegments);
+}
+
+void imm_draw_circle_wire_aspect_2d(uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+{
+ imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad_x, rad_y, nsegments);
+}
+void imm_draw_circle_fill_aspect_2d(uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments)
+{
+ imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad_x, rad_y, nsegments);
+}
+
+static void imm_draw_circle_partial(
+ GPUPrimType prim_type, uint pos, float x, float y,
+ float rad, int nsegments, float start, float sweep)
+{
+ /* shift & reverse angle, increase 'nsegments' to match gluPartialDisk */
+ const float angle_start = -(DEG2RADF(start)) + (float)(M_PI / 2);
+ const float angle_end = -(DEG2RADF(sweep) - angle_start);
+ nsegments += 1;
+ immBegin(prim_type, nsegments);
+ for (int i = 0; i < nsegments; ++i) {
+ const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
+ const float angle_sin = sinf(angle);
+ const float angle_cos = cosf(angle);
+ immVertex2f(pos, x + rad * angle_cos, y + rad * angle_sin);
+ }
+ immEnd();
+}
+
+void imm_draw_circle_partial_wire_2d(
+ uint pos, float x, float y,
+ float rad, int nsegments, float start, float sweep)
+{
+ imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, rad, nsegments, start, sweep);
+}
+
+static void imm_draw_disk_partial(
+ GPUPrimType prim_type, uint pos, float x, float y,
+ float rad_inner, float rad_outer, int nsegments, float start, float sweep)
+{
+ /* to avoid artifacts */
+ const float max_angle = 3 * 360;
+ CLAMP(sweep, -max_angle, max_angle);
+
+ /* shift & reverse angle, increase 'nsegments' to match gluPartialDisk */
+ const float angle_start = -(DEG2RADF(start)) + (float)(M_PI / 2);
+ const float angle_end = -(DEG2RADF(sweep) - angle_start);
+ nsegments += 1;
+ immBegin(prim_type, nsegments * 2);
+ for (int i = 0; i < nsegments; ++i) {
+ const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1)));
+ const float angle_sin = sinf(angle);
+ const float angle_cos = cosf(angle);
+ immVertex2f(pos, x + rad_inner * angle_cos, y + rad_inner * angle_sin);
+ immVertex2f(pos, x + rad_outer * angle_cos, y + rad_outer * angle_sin);
+ }
+ immEnd();
+}
+
+/**
+ * Draw a filled arc with the given inner and outer radius.
+ * The circle is centered at \a x, \a y and drawn in the XY plane.
+ *
+ * \note Arguments are `gluPartialDisk` compatible.
+ *
+ * \param pos: The vertex attribute number for position.
+ * \param x: Horizontal center.
+ * \param y: Vertical center.
+ * \param radius_inner: The inner circle's radius.
+ * \param radius_outer: The outer circle's radius (can be zero).
+ * \param nsegments: The number of segments to use in drawing (more = smoother).
+ * \param start: Specifies the starting angle, in degrees, of the disk portion.
+ * \param sweep: Specifies the sweep angle, in degrees, of the disk portion.
+ */
+void imm_draw_disk_partial_fill_2d(
+ uint pos, float x, float y,
+ float rad_inner, float rad_outer, int nsegments, float start, float sweep)
+{
+ imm_draw_disk_partial(GPU_PRIM_TRI_STRIP, pos, x, y, rad_inner, rad_outer, nsegments, start, sweep);
+}
+
+static void imm_draw_circle_3D(
+ GPUPrimType prim_type, uint pos, float x, float y,
+ float rad, int nsegments)
+{
+ immBegin(prim_type, nsegments);
+ for (int i = 0; i < nsegments; ++i) {
+ float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
+ immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f);
+ }
+ immEnd();
+}
+
+void imm_draw_circle_wire_3d(uint pos, float x, float y, float rad, int nsegments)
+{
+ imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, rad, nsegments);
+}
+
+void imm_draw_circle_fill_3d(uint pos, float x, float y, float rad, int nsegments)
+{
+ imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, rad, nsegments);
+}
+
+/**
+ * Draw a lined box.
+ *
+ * \param pos The vertex attribute number for position.
+ * \param x1 left.
+ * \param y1 bottom.
+ * \param x2 right.
+ * \param y2 top.
+ */
+void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
+{
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, x1, y1);
+ immVertex2f(pos, x1, y2);
+ immVertex2f(pos, x2, y2);
+ immVertex2f(pos, x2, y1);
+ immEnd();
+}
+
+void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
+{
+ /* use this version when GPUVertFormat has a vec3 position */
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex3f(pos, x1, y1, 0.0f);
+ immVertex3f(pos, x1, y2, 0.0f);
+ immVertex3f(pos, x2, y2, 0.0f);
+ immVertex3f(pos, x2, y1, 0.0f);
+ immEnd();
+}
+
+/**
+ * Draw a standard checkerboard to indicate transparent backgrounds.
+ */
+void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
+{
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
+
+ immUniform4f("color1", 0.15f, 0.15f, 0.15f, 1.0f);
+ immUniform4f("color2", 0.2f, 0.2f, 0.2f, 1.0f);
+ immUniform1i("size", 8);
+
+ immRectf(pos, x1, y1, x2, y2);
+
+ immUnbindProgram();
+}
+
+void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3])
+{
+ float coords[ARRAY_SIZE(cube_coords)][3];
+
+ for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
+ madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect);
+ }
+
+ immBegin(GPU_PRIM_TRIS, ARRAY_SIZE(cube_quad_index) * 3 * 2);
+ for (int i = 0; i < ARRAY_SIZE(cube_quad_index); i++) {
+ immVertex3fv(pos, coords[cube_quad_index[i][0]]);
+ immVertex3fv(pos, coords[cube_quad_index[i][1]]);
+ immVertex3fv(pos, coords[cube_quad_index[i][2]]);
+
+ immVertex3fv(pos, coords[cube_quad_index[i][0]]);
+ immVertex3fv(pos, coords[cube_quad_index[i][2]]);
+ immVertex3fv(pos, coords[cube_quad_index[i][3]]);
+ }
+ immEnd();
+}
+
+void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3])
+{
+ float coords[ARRAY_SIZE(cube_coords)][3];
+
+ for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) {
+ madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect);
+ }
+
+ immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 2);
+ for (int i = 0; i < ARRAY_SIZE(cube_line_index); i++) {
+ immVertex3fv(pos, coords[cube_line_index[i][0]]);
+ immVertex3fv(pos, coords[cube_line_index[i][1]]);
+ }
+ immEnd();
+}
+
+/**
+ * Draw a cylinder. Replacement for gluCylinder.
+ * _warning_ : Slow, better use it only if you no other choices.
+ *
+ * \param pos The vertex attribute number for position.
+ * \param nor The vertex attribute number for normal.
+ * \param base Specifies the radius of the cylinder at z = 0.
+ * \param top Specifies the radius of the cylinder at z = height.
+ * \param height Specifies the height of the cylinder.
+ * \param slices Specifies the number of subdivisions around the z axis.
+ * \param stacks Specifies the number of subdivisions along the z axis.
+ */
+void imm_draw_cylinder_fill_normal_3d(
+ uint pos, uint nor, float base, float top, float height, int slices, int stacks)
+{
+ immBegin(GPU_PRIM_TRIS, 6 * slices * stacks);
+ for (int i = 0; i < slices; ++i) {
+ const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
+ const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
+ const float cos1 = cosf(angle1);
+ const float sin1 = sinf(angle1);
+ const float cos2 = cosf(angle2);
+ const float sin2 = sinf(angle2);
+
+ for (int j = 0; j < stacks; ++j) {
+ float fac1 = (float)j / (float)stacks;
+ float fac2 = (float)(j + 1) / (float)stacks;
+ float r1 = base * (1.f - fac1) + top * fac1;
+ float r2 = base * (1.f - fac2) + top * fac2;
+ float h1 = height * ((float)j / (float)stacks);
+ float h2 = height * ((float)(j + 1) / (float)stacks);
+
+ float v1[3] = {r1 * cos2, r1 * sin2, h1};
+ float v2[3] = {r2 * cos2, r2 * sin2, h2};
+ float v3[3] = {r2 * cos1, r2 * sin1, h2};
+ float v4[3] = {r1 * cos1, r1 * sin1, h1};
+ float n1[3], n2[3];
+
+ /* calc normals */
+ sub_v3_v3v3(n1, v2, v1);
+ normalize_v3(n1);
+ n1[0] = cos1; n1[1] = sin1; n1[2] = 1 - n1[2];
+
+ sub_v3_v3v3(n2, v3, v4);
+ normalize_v3(n2);
+ n2[0] = cos2; n2[1] = sin2; n2[2] = 1 - n2[2];
+
+ /* first tri */
+ immAttr3fv(nor, n2);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immAttr3fv(nor, n1);
+ immVertex3fv(pos, v3);
+
+ /* second tri */
+ immVertex3fv(pos, v3);
+ immVertex3fv(pos, v4);
+ immAttr3fv(nor, n2);
+ immVertex3fv(pos, v1);
+ }
+ }
+ immEnd();
+}
+
+void imm_draw_cylinder_wire_3d(uint pos, float base, float top, float height, int slices, int stacks)
+{
+ immBegin(GPU_PRIM_LINES, 6 * slices * stacks);
+ for (int i = 0; i < slices; ++i) {
+ const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
+ const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
+ const float cos1 = cosf(angle1);
+ const float sin1 = sinf(angle1);
+ const float cos2 = cosf(angle2);
+ const float sin2 = sinf(angle2);
+
+ for (int j = 0; j < stacks; ++j) {
+ float fac1 = (float)j / (float)stacks;
+ float fac2 = (float)(j + 1) / (float)stacks;
+ float r1 = base * (1.f - fac1) + top * fac1;
+ float r2 = base * (1.f - fac2) + top * fac2;
+ float h1 = height * ((float)j / (float)stacks);
+ float h2 = height * ((float)(j + 1) / (float)stacks);
+
+ float v1[3] = {r1 * cos2, r1 * sin2, h1};
+ float v2[3] = {r2 * cos2, r2 * sin2, h2};
+ float v3[3] = {r2 * cos1, r2 * sin1, h2};
+ float v4[3] = {r1 * cos1, r1 * sin1, h1};
+
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+
+ immVertex3fv(pos, v2);
+ immVertex3fv(pos, v3);
+
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v4);
+ }
+ }
+ immEnd();
+}
+
+void imm_draw_cylinder_fill_3d(uint pos, float base, float top, float height, int slices, int stacks)
+{
+ immBegin(GPU_PRIM_TRIS, 6 * slices * stacks);
+ for (int i = 0; i < slices; ++i) {
+ const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices);
+ const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices);
+ const float cos1 = cosf(angle1);
+ const float sin1 = sinf(angle1);
+ const float cos2 = cosf(angle2);
+ const float sin2 = sinf(angle2);
+
+ for (int j = 0; j < stacks; ++j) {
+ float fac1 = (float)j / (float)stacks;
+ float fac2 = (float)(j + 1) / (float)stacks;
+ float r1 = base * (1.f - fac1) + top * fac1;
+ float r2 = base * (1.f - fac2) + top * fac2;
+ float h1 = height * ((float)j / (float)stacks);
+ float h2 = height * ((float)(j + 1) / (float)stacks);
+
+ float v1[3] = {r1 * cos2, r1 * sin2, h1};
+ float v2[3] = {r2 * cos2, r2 * sin2, h2};
+ float v3[3] = {r2 * cos1, r2 * sin1, h2};
+ float v4[3] = {r1 * cos1, r1 * sin1, h1};
+
+ /* first tri */
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v2);
+ immVertex3fv(pos, v3);
+
+ /* second tri */
+ immVertex3fv(pos, v3);
+ immVertex3fv(pos, v4);
+ immVertex3fv(pos, v1);
+ }
+ }
+ immEnd();
+}
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index c72c83b6b07..55d0466c929 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -30,8 +30,11 @@
*/
#include "BLI_sys_types.h"
+#include "GPU_buffers.h"
#include "GPU_init_exit.h" /* interface */
-
+#include "GPU_immediate.h"
+#include "GPU_batch.h"
+#include "GPU_texture.h"
#include "BKE_global.h"
#include "intern/gpu_codegen.h"
@@ -55,18 +58,34 @@ void GPU_init(void)
gpu_extensions_init(); /* must come first */
gpu_codegen_init();
+ gpu_framebuffer_module_init();
if (G.debug & G_DEBUG_GPU)
gpu_debug_init();
+ gpu_batch_init();
+
+ if (!G.background) {
+ immInit();
+ }
+
+ GPU_pbvh_fix_linking();
}
void GPU_exit(void)
{
+ if (!G.background) {
+ immDestroy();
+ }
+
+ gpu_batch_exit();
+
if (G.debug & G_DEBUG_GPU)
gpu_debug_exit();
+
+ gpu_framebuffer_module_exit();
gpu_codegen_exit();
gpu_extensions_exit(); /* must come last */
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 9db9ed1f5e7..1002e6f483c 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -36,68 +36,44 @@
#include "MEM_guardedalloc.h"
-#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
-#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_world_types.h"
#include "BLI_math.h"
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
+#include "BLI_string.h"
-#include "BKE_anim.h"
-#include "BKE_colorband.h"
-#include "BKE_colortools.h"
-#include "BKE_global.h"
-#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_scene.h"
-#include "BKE_group.h"
-#include "IMB_imbuf_types.h"
-
-#include "GPU_extensions.h"
-#include "GPU_framebuffer.h"
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
-#include "gpu_codegen.h"
+#include "DRW_engine.h"
-#ifdef WITH_OPENSUBDIV
-# include "BKE_DerivedMesh.h"
-#endif
+#include "gpu_codegen.h"
/* Structs */
+#define MAX_COLOR_BAND 128
-typedef enum DynMatProperty {
- DYN_LAMP_CO = 1,
- DYN_LAMP_VEC = 2,
- DYN_LAMP_IMAT = 4,
- DYN_LAMP_PERSMAT = 8,
-} DynMatProperty;
-
-static struct GPUWorld {
- float mistenabled;
- float mistype;
- float miststart;
- float mistdistance;
- float mistintensity;
- float mistcol[4];
- float horicol[3];
- float ambcol[4];
- float zencol[3];
-} GPUWorld;
+typedef struct GPUColorBandBuilder {
+ float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4];
+ int current_layer;
+} GPUColorBandBuilder;
struct GPUMaterial {
- Scene *scene;
+ Scene *scene; /* DEPRECATED was only useful for lamps */
Material *ma;
- /* material for mesh surface, worlds or something else.
- * some code generation is done differently depending on the use case */
- int type;
+ GPUMaterialStatus status;
+
+ const void *engine_type; /* attached engine type */
+ int options; /* to identify shader variations (shadow, probe, world background...) */
/* for creating the material */
ListBase nodes;
@@ -105,6 +81,7 @@ struct GPUMaterial {
/* for binding the material */
GPUPass *pass;
+ ListBase inputs; /* GPUInput */
GPUVertexAttribs attribs;
int builtins;
int alpha, obcolalpha;
@@ -124,2101 +101,662 @@ struct GPUMaterial {
int objectinfoloc;
- ListBase lamps;
- bool bound;
-
- bool is_opensubdiv;
-};
-
-struct GPULamp {
- Scene *scene;
- Object *ob;
- Object *par;
- Lamp *la;
-
- int type, mode, lay, hide;
+ /* XXX: Should be in Material. But it depends on the output node
+ * used and since the output selection is difference for GPUMaterial...
+ */
+ int domain;
- float dynenergy, dyncol[3];
- float energy, col[3];
+ /* Only used by Eevee to know which bsdf are used. */
+ int flag;
- float co[3], vec[3];
- float dynco[3], dynvec[3];
- float obmat[4][4];
- float imat[4][4];
- float dynimat[4][4];
+ /* Used by 2.8 pipeline */
+ GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */
- float spotsi, spotbl, k;
- float spotvec[2];
- float dyndist, dynatt1, dynatt2;
- float dist, att1, att2;
- float coeff_const, coeff_lin, coeff_quad;
- float shadow_color[3];
+ /* Eevee SSS */
+ GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */
+ GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
+ float sss_enabled;
+ float sss_radii[3];
+ int sss_samples;
+ short int sss_falloff;
+ float sss_sharpness;
+ bool sss_dirty;
- float bias, d, clipend;
- int size;
+ GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
+ GPUColorBandBuilder *coba_builder;
- int falloff_type;
- struct CurveMapping *curfalloff;
-
- float winmat[4][4];
- float viewmat[4][4];
- float persmat[4][4];
- float dynpersmat[4][4];
-
- GPUFrameBuffer *fb;
- GPUFrameBuffer *blurfb;
- GPUTexture *tex;
- GPUTexture *depthtex;
- GPUTexture *blurtex;
-
- ListBase materials;
+#ifndef NDEBUG
+ char name[64];
+#endif
};
-/* Forward declaration so shade_light_textures() can use this, while still keeping the code somewhat organized */
-static void texture_rgb_blend(
- GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
- int blendtype, GPUNodeLink **in);
+enum {
+ GPU_DOMAIN_SURFACE = (1 << 0),
+ GPU_DOMAIN_VOLUME = (1 << 1),
+ GPU_DOMAIN_SSS = (1 << 2)
+};
/* Functions */
-static GPUMaterial *GPU_material_construct_begin(Material *ma)
+/* Returns the address of the future pointer to coba_tex */
+GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, float *pixels, float *row)
{
- GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
+ /* In order to put all the colorbands into one 1D array texture,
+ * we need them to be the same size. */
+ BLI_assert(size == CM_TABLE + 1);
+ UNUSED_VARS_NDEBUG(size);
- material->ma = ma;
+ if (mat->coba_builder == NULL) {
+ mat->coba_builder = MEM_mallocN(sizeof(GPUColorBandBuilder), "GPUColorBandBuilder");
+ mat->coba_builder->current_layer = 0;
+ }
- return material;
-}
+ int layer = mat->coba_builder->current_layer;
+ *row = (float)layer;
-static void gpu_material_set_attrib_id(GPUMaterial *material)
-{
- GPUVertexAttribs *attribs = &material->attribs;
- GPUPass *pass = material->pass;
- if (!pass) {
- attribs->totlayer = 0;
- return;
+ if (*row == MAX_COLOR_BAND) {
+ printf("Too many color band in shader! Remove some Curve, Black Body or Color Ramp Node.\n");
}
-
- GPUShader *shader = GPU_pass_shader(pass);
- if (!shader) {
- attribs->totlayer = 0;
- return;
+ else {
+ float *dst = (float *)mat->coba_builder->pixels[layer];
+ memcpy(dst, pixels, sizeof(float) * (CM_TABLE + 1) * 4);
+ mat->coba_builder->current_layer += 1;
}
- /* convert from attribute number to the actual id assigned by opengl,
- * in case the attrib does not get a valid index back, it was probably
- * removed by the glsl compiler by dead code elimination */
+ return &mat->coba_tex;
+}
- int b = 0;
- for (int a = 0; a < attribs->totlayer; a++) {
- char name[32];
- BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
- attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
+static void gpu_material_ramp_texture_build(GPUMaterial *mat)
+{
+ if (mat->coba_builder == NULL)
+ return;
- BLI_snprintf(name, sizeof(name), "att%d_info", attribs->layer[a].attribid);
- attribs->layer[a].glinfoindoex = GPU_shader_get_uniform(shader, name);
+ GPUColorBandBuilder *builder = mat->coba_builder;
- if (attribs->layer[a].glindex >= 0) {
- attribs->layer[b] = attribs->layer[a];
- b++;
- }
- }
+ mat->coba_tex = GPU_texture_create_1D_array(CM_TABLE + 1, builder->current_layer, GPU_RGBA16F,
+ (float *)builder->pixels, NULL);
- attribs->totlayer = b;
+ MEM_freeN(builder);
+ mat->coba_builder = NULL;
}
-static int gpu_material_construct_end(GPUMaterial *material, const char *passname)
+static void gpu_material_free_single(GPUMaterial *material)
{
- if (material->outlink) {
- GPUNodeLink *outlink = material->outlink;
- material->pass = GPU_generate_pass(&material->nodes, outlink,
- &material->attribs, &material->builtins, material->type,
- passname,
- material->is_opensubdiv,
- GPU_material_use_new_shading_nodes(material));
-
- if (!material->pass)
- return 0;
-
- gpu_material_set_attrib_id(material);
-
- GPUShader *shader = GPU_pass_shader(material->pass);
-
- if (material->builtins & GPU_VIEW_MATRIX)
- material->viewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_VIEW_MATRIX));
- if (material->builtins & GPU_INVERSE_VIEW_MATRIX)
- material->invviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_VIEW_MATRIX));
- if (material->builtins & GPU_OBJECT_MATRIX)
- material->obmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_MATRIX));
- if (material->builtins & GPU_INVERSE_OBJECT_MATRIX)
- material->invobmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_OBJECT_MATRIX));
- if (material->builtins & GPU_LOC_TO_VIEW_MATRIX)
- material->localtoviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_LOC_TO_VIEW_MATRIX));
- if (material->builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX)
- material->invlocaltoviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_LOC_TO_VIEW_MATRIX));
- if (material->builtins & GPU_OBCOLOR)
- material->obcolloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBCOLOR));
- if (material->builtins & GPU_AUTO_BUMPSCALE)
- material->obautobumpscaleloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_AUTO_BUMPSCALE));
- if (material->builtins & GPU_CAMERA_TEXCO_FACTORS)
- material->cameratexcofacloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_CAMERA_TEXCO_FACTORS));
- if (material->builtins & GPU_PARTICLE_SCALAR_PROPS)
- material->partscalarpropsloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_SCALAR_PROPS));
- if (material->builtins & GPU_PARTICLE_LOCATION)
- material->partcoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_LOCATION));
- if (material->builtins & GPU_PARTICLE_VELOCITY)
- material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY));
- if (material->builtins & GPU_PARTICLE_ANG_VELOCITY)
- material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY));
- if (material->builtins & GPU_OBJECT_INFO)
- material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO));
- return 1;
+ /* Cancel / wait any pending lazy compilation. */
+ DRW_deferred_shader_remove(material);
+
+ GPU_pass_free_nodes(&material->nodes);
+ GPU_inputs_free(&material->inputs);
+
+ if (material->pass != NULL) {
+ GPU_pass_release(material->pass);
}
- else {
- GPU_pass_free_nodes(&material->nodes);
+ if (material->ubo != NULL) {
+ GPU_uniformbuffer_free(material->ubo);
+ }
+ if (material->sss_tex_profile != NULL) {
+ GPU_texture_free(material->sss_tex_profile);
+ }
+ if (material->sss_profile != NULL) {
+ GPU_uniformbuffer_free(material->sss_profile);
+ }
+ if (material->coba_tex != NULL) {
+ GPU_texture_free(material->coba_tex);
}
-
- return 0;
}
void GPU_material_free(ListBase *gpumaterial)
{
for (LinkData *link = gpumaterial->first; link; link = link->next) {
GPUMaterial *material = link->data;
-
- if (material->pass)
- GPU_pass_free(material->pass);
-
- for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) {
- GPULamp *lamp = nlink->data;
-
- if (material->ma) {
- Material *ma = material->ma;
-
- LinkData *next = NULL;
- for (LinkData *mlink = lamp->materials.first; mlink; mlink = next) {
- next = mlink->next;
- if (mlink->data == ma)
- BLI_freelinkN(&lamp->materials, mlink);
- }
- }
- }
-
- BLI_freelistN(&material->lamps);
-
+ gpu_material_free_single(material);
MEM_freeN(material);
}
-
BLI_freelistN(gpumaterial);
}
-bool GPU_lamp_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma)
-{
- if (lamp->hide)
- return false;
- else if (srl && srl->light_override)
- return BKE_group_object_exists(srl->light_override, lamp->ob);
- else if (ma && ma->group)
- return BKE_group_object_exists(ma->group, lamp->ob);
- else
- return true;
-}
-
-void GPU_material_bind(
- GPUMaterial *material, int oblay, int viewlay, double time, int mipmap,
- float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock)
-{
- if (material->pass) {
- GPUShader *shader = GPU_pass_shader(material->pass);
- SceneRenderLayer *srl = scenelock ? BLI_findlink(&material->scene->r.layers, material->scene->r.actlay) : NULL;
-
- if (srl)
- viewlay &= srl->lay;
-
- /* handle layer lamps */
- if (material->type == GPU_MATERIAL_TYPE_MESH) {
- for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) {
- GPULamp *lamp = nlink->data;
-
- if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) &&
- GPU_lamp_visible(lamp, srl, material->ma))
- {
- lamp->dynenergy = lamp->energy;
- copy_v3_v3(lamp->dyncol, lamp->col);
- }
- else {
- lamp->dynenergy = 0.0f;
- lamp->dyncol[0] = lamp->dyncol[1] = lamp->dyncol[2] = 0.0f;
- }
-
- if (material->dynproperty & DYN_LAMP_VEC) {
- copy_v3_v3(lamp->dynvec, lamp->vec);
- normalize_v3(lamp->dynvec);
- negate_v3(lamp->dynvec);
- mul_mat3_m4_v3(viewmat, lamp->dynvec);
- }
-
- if (material->dynproperty & DYN_LAMP_CO) {
- copy_v3_v3(lamp->dynco, lamp->co);
- mul_m4_v3(viewmat, lamp->dynco);
- }
-
- if (material->dynproperty & DYN_LAMP_IMAT) {
- mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv);
- }
-
- if (material->dynproperty & DYN_LAMP_PERSMAT) {
- /* The lamp matrices are already updated if we're using shadow buffers */
- if (!GPU_lamp_has_shadow_buffer(lamp)) {
- GPU_lamp_update_buffer_mats(lamp);
- }
- mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv);
- }
- }
- }
-
- /* note material must be bound before setting uniforms */
- GPU_pass_bind(material->pass, time, mipmap);
-
- /* handle per material built-ins */
- if (material->builtins & GPU_VIEW_MATRIX) {
- GPU_shader_uniform_vector(shader, material->viewmatloc, 16, 1, (float *)viewmat);
- }
- if (material->builtins & GPU_INVERSE_VIEW_MATRIX) {
- GPU_shader_uniform_vector(shader, material->invviewmatloc, 16, 1, (float *)viewinv);
- }
- if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) {
- if (camerafactors) {
- GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)camerafactors);
- }
- else {
- /* use default, no scaling no offset */
- float borders[4] = {1.0f, 1.0f, 0.0f, 0.0f};
- GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)borders);
- }
- }
-
- GPU_pass_update_uniforms(material->pass);
-
- material->bound = 1;
- }
-}
-
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
{
return material->builtins;
}
-void GPU_material_bind_uniforms(
- GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
- float autobumpscale, GPUParticleInfo *pi, float object_info[3])
-{
- if (material->pass) {
- GPUShader *shader = GPU_pass_shader(material->pass);
- float invmat[4][4], col[4];
- float localtoviewmat[4][4];
- float invlocaltoviewmat[4][4];
-
- /* handle per object builtins */
- if (material->builtins & GPU_OBJECT_MATRIX) {
- GPU_shader_uniform_vector(shader, material->obmatloc, 16, 1, (float *)obmat);
- }
- if (material->builtins & GPU_INVERSE_OBJECT_MATRIX) {
- invert_m4_m4(invmat, obmat);
- GPU_shader_uniform_vector(shader, material->invobmatloc, 16, 1, (float *)invmat);
- }
- if (material->builtins & GPU_LOC_TO_VIEW_MATRIX) {
- if (viewmat) {
- mul_m4_m4m4(localtoviewmat, viewmat, obmat);
- GPU_shader_uniform_vector(shader, material->localtoviewmatloc, 16, 1, (float *)localtoviewmat);
- }
- }
- if (material->builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
- if (viewmat) {
- mul_m4_m4m4(localtoviewmat, viewmat, obmat);
- invert_m4_m4(invlocaltoviewmat, localtoviewmat);
- GPU_shader_uniform_vector(shader, material->invlocaltoviewmatloc, 16, 1, (float *)invlocaltoviewmat);
- }
- }
- if (material->builtins & GPU_OBCOLOR) {
- copy_v4_v4(col, obcol);
- CLAMP(col[3], 0.0f, 1.0f);
- GPU_shader_uniform_vector(shader, material->obcolloc, 4, 1, col);
- }
- if (material->builtins & GPU_AUTO_BUMPSCALE) {
- GPU_shader_uniform_vector(shader, material->obautobumpscaleloc, 1, 1, &autobumpscale);
- }
- if (material->builtins & GPU_PARTICLE_SCALAR_PROPS) {
- GPU_shader_uniform_vector(shader, material->partscalarpropsloc, 4, 1, pi->scalprops);
- }
- if (material->builtins & GPU_PARTICLE_LOCATION) {
- GPU_shader_uniform_vector(shader, material->partcoloc, 4, 1, pi->location);
- }
- if (material->builtins & GPU_PARTICLE_VELOCITY) {
- GPU_shader_uniform_vector(shader, material->partvel, 3, 1, pi->velocity);
- }
- if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) {
- GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity);
- }
- if (material->builtins & GPU_OBJECT_INFO) {
- GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info);
- }
-
- }
-}
-
-void GPU_material_unbind(GPUMaterial *material)
-{
- if (material->pass) {
- material->bound = 0;
- GPU_pass_unbind(material->pass);
- }
-}
-
-bool GPU_material_bound(GPUMaterial *material)
-{
- return material->bound;
-}
-
Scene *GPU_material_scene(GPUMaterial *material)
{
return material->scene;
}
-GPUMatType GPU_Material_get_type(GPUMaterial *material)
+GPUPass *GPU_material_get_pass(GPUMaterial *material)
{
- return material->type;
+ return material->pass;
}
-
-void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs)
+ListBase *GPU_material_get_inputs(GPUMaterial *material)
{
- *attribs = material->attribs;
+ return &material->inputs;
}
-void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
+GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material)
{
- if (!material->outlink)
- material->outlink = link;
+ return material->ubo;
}
-void GPU_material_enable_alpha(GPUMaterial *material)
+/**
+ * Create dynamic UBO from parameters
+ * \param ListBase of BLI_genericNodeN(GPUInput)
+ */
+void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
{
- material->alpha = 1;
+ material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL);
}
-GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4])
-{
- if (material->alpha || (material->obcolalpha && obcol[3] < 1.0f))
- return GPU_BLEND_ALPHA;
- else
- return GPU_BLEND_SOLID;
-}
+/* Eevee Subsurface scattering. */
+/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
-void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
-{
- BLI_addtail(&material->nodes, node);
-}
+#define SSS_SAMPLES 65
+#define SSS_EXPONENT 2.0f /* Importance sampling exponent */
-/* Code generation */
+typedef struct GPUSssKernelData {
+ float kernel[SSS_SAMPLES][4];
+ float param[3], max_radius;
+ int samples;
+} GPUSssKernelData;
-bool GPU_material_do_color_management(GPUMaterial *mat)
+static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent)
{
- if (!BKE_scene_check_color_management_enabled(mat->scene))
- return false;
-
- return true;
-}
-
-bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
-{
- return BKE_scene_use_new_shading_nodes(mat->scene);
-}
-
-bool GPU_material_use_world_space_shading(GPUMaterial *mat)
-{
- return BKE_scene_use_world_space_shading(mat->scene);
-}
-
-static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist)
-{
- GPUNodeLink *visifac;
-
- /* from get_lamp_visibility */
- if (lamp->type == LA_SUN || lamp->type == LA_HEMI) {
- mat->dynproperty |= DYN_LAMP_VEC;
- GPU_link(mat, "lamp_visibility_sun_hemi",
- GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), lv, dist, &visifac);
- return visifac;
- }
- else {
- mat->dynproperty |= DYN_LAMP_CO;
- GPU_link(mat, "lamp_visibility_other",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac);
-
- if (lamp->type == LA_AREA)
- return visifac;
-
- switch (lamp->falloff_type) {
- case LA_FALLOFF_CONSTANT:
- break;
- case LA_FALLOFF_INVLINEAR:
- GPU_link(mat, "lamp_falloff_invlinear",
- GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac);
- break;
- case LA_FALLOFF_INVSQUARE:
- GPU_link(mat, "lamp_falloff_invsquare",
- GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac);
- break;
- case LA_FALLOFF_SLIDERS:
- GPU_link(mat, "lamp_falloff_sliders",
- GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
- GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob),
- GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac);
- break;
- case LA_FALLOFF_INVCOEFFICIENTS:
- GPU_link(mat, "lamp_falloff_invcoefficients",
- GPU_dynamic_uniform(&lamp->coeff_const, GPU_DYNAMIC_LAMP_COEFFCONST, lamp->ob),
- GPU_dynamic_uniform(&lamp->coeff_lin, GPU_DYNAMIC_LAMP_COEFFLIN, lamp->ob),
- GPU_dynamic_uniform(&lamp->coeff_quad, GPU_DYNAMIC_LAMP_COEFFQUAD, lamp->ob), *dist, &visifac);
- break;
- case LA_FALLOFF_CURVE:
- {
- float *array;
- int size;
-
- curvemapping_initialize(lamp->curfalloff);
- curvemapping_table_RGBA(lamp->curfalloff, &array, &size);
- GPU_link(mat, "lamp_falloff_curve",
- GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
- GPU_texture(size, array), *dist, &visifac);
-
- break;
- }
- }
-
- if (lamp->mode & LA_SPHERE)
- GPU_link(mat, "lamp_visibility_sphere",
- GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
- *dist, visifac, &visifac);
-
- if (lamp->type == LA_SPOT) {
- GPUNodeLink *inpr;
-
- if (lamp->mode & LA_SQUARE) {
- mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT;
- GPU_link(mat, "lamp_visibility_spot_square",
- GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob),
- GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob),
- GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr);
- }
- else {
- mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT;
- GPU_link(mat, "lamp_visibility_spot_circle",
- GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob),
- GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob),
- GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr);
- }
-
- GPU_link(mat, "lamp_visibility_spot",
- GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob),
- GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTBLEND, lamp->ob),
- inpr, visifac, &visifac);
- }
-
- GPU_link(mat, "lamp_visibility_clamp", visifac, &visifac);
-
- return visifac;
+ float step = 2.0f / (float)(count - 1);
+ for (int i = 0; i < count; i++) {
+ float o = ((float)i) * step - 1.0f;
+ float sign = (o < 0.0f) ? -1.0f : 1.0f;
+ float ofs = sign * fabsf(powf(o, exponent));
+ kd->kernel[i][3] = ofs;
}
}
-#if 0
-static void area_lamp_vectors(LampRen *lar)
+#define GAUSS_TRUNCATE 12.46f
+static float gaussian_profile(float r, float radius)
{
- float xsize = 0.5f * lar->area_size, ysize = 0.5f * lar->area_sizey;
-
- /* make it smaller, so area light can be multisampled */
- float multifac = 1.0f / sqrtf((float)lar->ray_totsamp);
- xsize *= multifac;
- ysize *= multifac;
-
- /* corner vectors */
- lar->area[0][0] = lar->co[0] - xsize * lar->mat[0][0] - ysize * lar->mat[1][0];
- lar->area[0][1] = lar->co[1] - xsize * lar->mat[0][1] - ysize * lar->mat[1][1];
- lar->area[0][2] = lar->co[2] - xsize * lar->mat[0][2] - ysize * lar->mat[1][2];
-
- /* corner vectors */
- lar->area[1][0] = lar->co[0] - xsize * lar->mat[0][0] + ysize * lar->mat[1][0];
- lar->area[1][1] = lar->co[1] - xsize * lar->mat[0][1] + ysize * lar->mat[1][1];
- lar->area[1][2] = lar->co[2] - xsize * lar->mat[0][2] + ysize * lar->mat[1][2];
-
- /* corner vectors */
- lar->area[2][0] = lar->co[0] + xsize * lar->mat[0][0] + ysize * lar->mat[1][0];
- lar->area[2][1] = lar->co[1] + xsize * lar->mat[0][1] + ysize * lar->mat[1][1];
- lar->area[2][2] = lar->co[2] + xsize * lar->mat[0][2] + ysize * lar->mat[1][2];
-
- /* corner vectors */
- lar->area[3][0] = lar->co[0] + xsize * lar->mat[0][0] - ysize * lar->mat[1][0];
- lar->area[3][1] = lar->co[1] + xsize * lar->mat[0][1] - ysize * lar->mat[1][1];
- lar->area[3][2] = lar->co[2] + xsize * lar->mat[0][2] - ysize * lar->mat[1][2];
- /* only for correction button size, matrix size works on energy */
- lar->areasize = lar->dist * lar->dist / (4.0f * xsize * ysize);
-}
-#endif
+ const float v = radius * radius * (0.25f * 0.25f);
+ const float Rm = sqrtf(v * GAUSS_TRUNCATE);
-static void ramp_blend(
- GPUMaterial *mat, GPUNodeLink *fac, GPUNodeLink *col1, GPUNodeLink *col2, int type,
- GPUNodeLink **r_col)
-{
- static const char *names[] = {"mix_blend", "mix_add", "mix_mult", "mix_sub",
- "mix_screen", "mix_div", "mix_diff", "mix_dark", "mix_light",
- "mix_overlay", "mix_dodge", "mix_burn", "mix_hue", "mix_sat",
- "mix_val", "mix_color", "mix_soft", "mix_linear"};
-
- GPU_link(mat, names[type], fac, col1, col2, r_col);
+ if (r >= Rm) {
+ return 0.0f;
+ }
+ return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v);
}
-static void BKE_colorband_eval_blend(
- GPUMaterial *mat, ColorBand *coba, GPUNodeLink *fac, float rampfac, int type,
- GPUNodeLink *incol, GPUNodeLink **r_col)
+#define BURLEY_TRUNCATE 16.0f
+#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
+static float burley_profile(float r, float d)
{
- GPUNodeLink *tmp, *alpha, *col;
- float *array;
- int size;
-
- /* do colorband */
- BKE_colorband_evaluate_table_rgba(coba, &array, &size);
- GPU_link(mat, "valtorgb", fac, GPU_texture(size, array), &col, &tmp);
-
- /* use alpha in fac */
- GPU_link(mat, "mtex_alpha_from_col", col, &alpha);
- GPU_link(mat, "math_multiply", alpha, GPU_uniform(&rampfac), &fac);
-
- /* blending method */
- ramp_blend(mat, fac, incol, col, type, r_col);
+ float exp_r_3_d = expf(-r / (3.0f * d));
+ float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
+ return (exp_r_d + exp_r_3_d) / (4.0f * d);
}
-static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff)
+static float cubic_profile(float r, float radius, float sharpness)
{
- Material *ma = shi->mat;
- GPUMaterial *mat = shi->gpumat;
+ float Rm = radius * (1.0f + sharpness);
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS)) {
- if (ma->ramp_col) {
- if (ma->rampin_col == MA_RAMP_IN_RESULT) {
- GPUNodeLink *fac;
- GPU_link(mat, "ramp_rgbtobw", *diff, &fac);
-
- /* colorband + blend */
- BKE_colorband_eval_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, *diff, diff);
- }
- }
+ if (r >= Rm) {
+ return 0.0f;
}
-}
+ /* custom variation with extra sharpness, to match the previous code */
+ const float y = 1.0f / (1.0f + sharpness);
+ float Rmy, ry, ryinv;
-static void add_to_diffuse(
- GPUMaterial *mat, Material *ma, GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *rgb,
- GPUNodeLink **r_diff)
-{
- GPUNodeLink *fac, *tmp, *addcol;
+ Rmy = powf(Rm, y);
+ ry = powf(r, y);
+ ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f;
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) &&
- ma->ramp_col && (ma->mode & MA_RAMP_COL))
- {
- /* MA_RAMP_IN_RESULT is exceptional */
- if (ma->rampin_col == MA_RAMP_IN_RESULT) {
- addcol = shi->rgb;
- }
- else {
- /* input */
- switch (ma->rampin_col) {
- case MA_RAMP_IN_ENERGY:
- GPU_link(mat, "ramp_rgbtobw", rgb, &fac);
- break;
- case MA_RAMP_IN_SHADER:
- fac = is;
- break;
- case MA_RAMP_IN_NOR:
- GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
- break;
- default:
- GPU_link(mat, "set_value_zero", &fac);
- break;
- }
+ const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy;
+ const float f = Rmy - ry;
+ const float num = f * (f * f) * (y * ryinv);
- /* colorband + blend */
- BKE_colorband_eval_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, shi->rgb, &addcol);
- }
- }
- else
- addcol = shi->rgb;
-
- /* output to */
- GPU_link(mat, "shade_madd", *r_diff, rgb, addcol, r_diff);
+ return (10.0f * num) / (Rmy5 * M_PI);
}
-static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec)
+static float eval_profile(float r, short falloff_type, float sharpness, float param)
{
- Material *ma = shi->mat;
- GPUMaterial *mat = shi->gpumat;
+ r = fabsf(r);
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) &&
- ma->ramp_spec && ma->rampin_spec == MA_RAMP_IN_RESULT)
+ if (falloff_type == SHD_SUBSURFACE_BURLEY ||
+ falloff_type == SHD_SUBSURFACE_RANDOM_WALK)
{
- GPUNodeLink *fac;
- GPU_link(mat, "ramp_rgbtobw", *spec, &fac);
-
- /* colorband + blend */
- BKE_colorband_eval_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec);
+ return burley_profile(r, param) / BURLEY_TRUNCATE_CDF;
}
-}
-
-static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t, GPUNodeLink **spec)
-{
- Material *ma = shi->mat;
- GPUMaterial *mat = shi->gpumat;
- GPUNodeLink *fac, *tmp;
-
- *spec = shi->specrgb;
-
- /* MA_RAMP_IN_RESULT is exception */
- if (ma->ramp_spec && (ma->rampin_spec != MA_RAMP_IN_RESULT)) {
-
- /* input */
- switch (ma->rampin_spec) {
- case MA_RAMP_IN_ENERGY:
- fac = t;
- break;
- case MA_RAMP_IN_SHADER:
- fac = is;
- break;
- case MA_RAMP_IN_NOR:
- GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
- break;
- default:
- GPU_link(mat, "set_value_zero", &fac);
- break;
- }
-
- /* colorband + blend */
- BKE_colorband_eval_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec);
+ else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
+ return cubic_profile(r, param, sharpness);
+ }
+ else {
+ return gaussian_profile(r, param);
}
}
-static void add_user_list(ListBase *list, void *data)
-{
- LinkData *link = MEM_callocN(sizeof(LinkData), "GPULinkData");
- link->data = data;
- BLI_addtail(list, link);
-}
-
-static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **rgb)
+/* Resolution for each sample of the precomputed kernel profile */
+#define INTEGRAL_RESOLUTION 32
+static float eval_integral(float x0, float x1, short falloff_type, float sharpness, float param)
{
- for (int i = 0; i < MAX_MTEX; ++i) {
- MTex *mtex = lamp->la->mtex[i];
-
- if (mtex && mtex->tex && (mtex->tex->type & TEX_IMAGE) && mtex->tex->ima) {
- mat->dynproperty |= DYN_LAMP_PERSMAT;
+ const float range = x1 - x0;
+ const float step = range / INTEGRAL_RESOLUTION;
+ float integral = 0.0f;
- float one = 1.0f;
- GPUNodeLink *tex_rgb;
-
- GPU_link(mat, "shade_light_texture",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_image(mtex->tex->ima, &mtex->tex->iuser, false),
- GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- &tex_rgb);
- texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb);
- }
+ for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
+ float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
+ float y = eval_profile(x, falloff_type, sharpness, param);
+ integral += y * step;
}
+
+ return integral;
}
+#undef INTEGRAL_RESOLUTION
-static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *lamp)
+static void compute_sss_kernel(
+ GPUSssKernelData *kd, float radii[3], int sample_len, int falloff_type, float sharpness)
{
- Material *ma = shi->mat;
- GPUMaterial *mat = shi->gpumat;
- GPUNodeLink *lv, *dist, *is, *inp, *i;
- GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol;
- float one = 1.0f;
-
- if ((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW))
- return;
+ float rad[3];
+ /* Minimum radius */
+ rad[0] = MAX2(radii[0], 1e-15f);
+ rad[1] = MAX2(radii[1], 1e-15f);
+ rad[2] = MAX2(radii[2], 1e-15f);
- GPUNodeLink *vn = shi->vn;
- GPUNodeLink *view = shi->view;
+ /* Christensen-Burley fitting */
+ float l[3], d[3];
- GPUNodeLink *visifac = lamp_get_visibility(mat, lamp, &lv, &dist);
-
-#if 0
- if (ma->mode & MA_TANGENT_V)
- GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn);
-#endif
-
- GPU_link(mat, "shade_inp", vn, lv, &inp);
+ if (falloff_type == SHD_SUBSURFACE_BURLEY ||
+ falloff_type == SHD_SUBSURFACE_RANDOM_WALK)
+ {
+ mul_v3_v3fl(l, rad, 0.25f * M_1_PI);
+ const float A = 1.0f;
+ const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
+ /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */
+ mul_v3_v3fl(d, l, 0.6f / s);
+ mul_v3_v3fl(rad, d, BURLEY_TRUNCATE);
+ kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
- if (lamp->mode & LA_NO_DIFF) {
- GPU_link(mat, "shade_is_no_diffuse", &is);
+ copy_v3_v3(kd->param, d);
}
- else if (lamp->type == LA_HEMI) {
- GPU_link(mat, "shade_is_hemi", inp, &is);
+ else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
+ copy_v3_v3(kd->param, rad);
+ mul_v3_fl(rad, 1.0f + sharpness);
+ kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
}
else {
- if (lamp->type == LA_AREA) {
- float area[4][4] = {{0.0f}}, areasize = 0.0f;
-
- mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_CO;
- GPU_link(mat, "shade_inp_area",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob),
- GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn,
- GPU_uniform((float *)area),
- GPU_uniform(&areasize),
- GPU_uniform(&lamp->k), &inp);
- }
+ kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
- is = inp; /* Lambert */
-
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS)) {
- if (ma->diff_shader == MA_DIFF_ORENNAYAR)
- GPU_link(mat, "shade_diffuse_oren_nayer", inp, vn, lv, view,
- GPU_uniform(&ma->roughness), &is);
- else if (ma->diff_shader == MA_DIFF_TOON)
- GPU_link(mat, "shade_diffuse_toon", vn, lv, view,
- GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
- else if (ma->diff_shader == MA_DIFF_MINNAERT)
- GPU_link(mat, "shade_diffuse_minnaert", inp, vn, view,
- GPU_uniform(&ma->darkness), &is);
- else if (ma->diff_shader == MA_DIFF_FRESNEL)
- GPU_link(mat, "shade_diffuse_fresnel", vn, lv, view,
- GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
- }
+ copy_v3_v3(kd->param, rad);
}
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS))
- if (ma->shade_flag & MA_CUBIC)
- GPU_link(mat, "shade_cubic", is, &is);
-
- i = is;
- GPU_link(mat, "shade_visifac", i, visifac, shi->refl, &i);
+ /* Compute samples locations on the 1d kernel [-1..1] */
+ sss_calculate_offsets(kd, sample_len, SSS_EXPONENT);
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol);
- shade_light_textures(mat, lamp, &lcol);
- GPU_link(mat, "shade_mul_value_v3",
- GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), lcol, &lcol);
-
-#if 0
- if (ma->mode & MA_TANGENT_VN)
- GPU_link(mat, "shade_tangent_v_spec", GPU_attribute(CD_TANGENT, ""), &vn);
-#endif
+ /* Weights sum for normalization */
+ float sum[3] = {0.0f, 0.0f, 0.0f};
- /* this replaces if (i > 0.0) conditional until that is supported */
- /* done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i); */
+ /* Compute integral of each sample footprint */
+ for (int i = 0; i < sample_len; i++) {
+ float x0, x1;
- if ((ma->mode & MA_SHADOW) && GPU_lamp_has_shadow_buffer(lamp)) {
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS)) {
- mat->dynproperty |= DYN_LAMP_PERSMAT;
-
- if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
- GPU_link(mat, "test_shadowbuf_vsm",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
- GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), inp, &shadfac);
- }
- else {
- GPU_link(mat, "test_shadowbuf",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
- GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- GPU_uniform(&lamp->bias), inp, &shadfac);
- }
-
- if (lamp->mode & LA_ONLYSHADOW) {
- GPUNodeLink *shadrgb;
- GPU_link(mat, "shade_only_shadow", i, shadfac,
- GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob),
- GPU_uniform(lamp->shadow_color), &shadrgb);
-
- if (!(lamp->mode & LA_NO_DIFF)) {
- GPU_link(mat, "shade_only_shadow_diffuse", shadrgb, shi->rgb,
- shr->diff, &shr->diff);
- }
-
- if (!(lamp->mode & LA_NO_SPEC)) {
- GPU_link(mat, "shade_only_shadow_specular", shadrgb, shi->specrgb,
- shr->spec, &shr->spec);
- }
-
- add_user_list(&mat->lamps, lamp);
- add_user_list(&lamp->materials, shi->gpumat->ma);
- return;
- }
+ if (i == 0) {
+ x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f;
}
- }
- else if ((mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && (lamp->mode & LA_ONLYSHADOW)) {
- add_user_list(&mat->lamps, lamp);
- add_user_list(&lamp->materials, shi->gpumat->ma);
- return;
- }
- else
- GPU_link(mat, "set_value", GPU_uniform(&one), &shadfac);
-
- if (GPU_link_changed(shi->refl) || ma->ref != 0.0f) {
- if (!(lamp->mode & LA_NO_DIFF)) {
- GPUNodeLink *rgb;
- GPU_link(mat, "shade_mul_value", i, lcol, &rgb);
- GPU_link(mat, "mtex_value_invert", shadfac, &shadfac);
- GPU_link(mat, "mix_mult", shadfac, rgb, GPU_uniform(lamp->shadow_color), &rgb);
- GPU_link(mat, "mtex_value_invert", shadfac, &shadfac);
- add_to_diffuse(mat, ma, shi, is, rgb, &shr->diff);
+ else {
+ x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f;
}
- }
- if (mat->scene->gm.flag & GAME_GLSL_NO_SHADERS) {
- /* pass */
- }
- else if (!(lamp->mode & LA_NO_SPEC) && !(lamp->mode & LA_ONLYSHADOW) &&
- (GPU_link_changed(shi->spec) || ma->spec != 0.0f))
- {
- if (lamp->type == LA_HEMI) {
- GPU_link(mat, "shade_hemi_spec", vn, lv, view, GPU_uniform(&ma->spec), shi->har, visifac, &t);
- GPU_link(mat, "shade_add_spec", t, lcol, shi->specrgb, &outcol);
- GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
+ if (i == sample_len - 1) {
+ x1 = kd->kernel[sample_len - 1][3] + fabsf(kd->kernel[sample_len - 2][3] - kd->kernel[sample_len - 1][3]) / 2.0f;
}
else {
- if (ma->spec_shader == MA_SPEC_PHONG) {
- GPU_link(mat, "shade_phong_spec", vn, lv, view, shi->har, &specfac);
- }
- else if (ma->spec_shader == MA_SPEC_COOKTORR) {
- GPU_link(mat, "shade_cooktorr_spec", vn, lv, view, shi->har, &specfac);
- }
- else if (ma->spec_shader == MA_SPEC_BLINN) {
- GPU_link(mat, "shade_blinn_spec", vn, lv, view,
- GPU_uniform(&ma->refrac), shi->har, &specfac);
- }
- else if (ma->spec_shader == MA_SPEC_WARDISO) {
- GPU_link(mat, "shade_wardiso_spec", vn, lv, view,
- GPU_uniform(&ma->rms), &specfac);
- }
- else {
- GPU_link(mat, "shade_toon_spec", vn, lv, view,
- GPU_uniform(&ma->param[2]), GPU_uniform(&ma->param[3]), &specfac);
- }
+ x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f;
+ }
- if (lamp->type == LA_AREA)
- GPU_link(mat, "shade_spec_area_inp", specfac, inp, &specfac);
+ x0 *= kd->max_radius;
+ x1 *= kd->max_radius;
- GPU_link(mat, "shade_spec_t", shadfac, shi->spec, visifac, specfac, &t);
+ kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]);
+ kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]);
+ kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]);
- if (ma->mode & MA_RAMP_SPEC) {
- GPUNodeLink *spec;
- do_specular_ramp(shi, specfac, t, &spec);
- GPU_link(mat, "shade_add_spec", t, lcol, spec, &outcol);
- GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
- }
- else {
- GPU_link(mat, "shade_add_spec", t, lcol, shi->specrgb, &outcol);
- GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
+ sum[0] += kd->kernel[i][0];
+ sum[1] += kd->kernel[i][1];
+ sum[2] += kd->kernel[i][2];
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ if (sum[i] > 0.0f) {
+ /* Normalize */
+ for (int j = 0; j < sample_len; j++) {
+ kd->kernel[j][i] /= sum[i];
}
}
+ else {
+ /* Avoid 0 kernel sum. */
+ kd->kernel[sample_len / 2][i] = 1.0f;
+ }
}
- add_user_list(&mat->lamps, lamp);
- add_user_list(&lamp->materials, shi->gpumat->ma);
+ /* Put center sample at the start of the array (to sample first) */
+ float tmpv[4];
+ copy_v4_v4(tmpv, kd->kernel[sample_len / 2]);
+ for (int i = sample_len / 2; i > 0; i--) {
+ copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]);
+ }
+ copy_v4_v4(kd->kernel[0], tmpv);
+
+ kd->samples = sample_len;
}
-static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
+#define INTEGRAL_RESOLUTION 512
+static void compute_sss_translucence_kernel(
+ const GPUSssKernelData *kd, int resolution, short falloff_type, float sharpness, float **output)
{
- Base *base;
- Scene *sce_iter;
-
- for (SETLOOPER(shi->gpumat->scene, sce_iter, base)) {
- Object *ob = base->object;
-
- if (ob->type == OB_LAMP) {
- GPULamp *lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob, NULL);
- if (lamp)
- shade_one_light(shi, shr, lamp);
- }
+ float (*texels)[4];
+ texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel");
+ *output = (float *)texels;
- if (ob->transflag & OB_DUPLI) {
- ListBase *lb = object_duplilist(G.main, G.main->eval_ctx, shi->gpumat->scene, ob);
+ /* Last texel should be black, hence the - 1. */
+ for (int i = 0; i < resolution - 1; ++i) {
+ /* Distance from surface. */
+ float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution);
- for (DupliObject *dob = lb->first; dob; dob = dob->next) {
- Object *ob_iter = dob->ob;
+ /* For each distance d we compute the radiance incoming from an hypothetic parallel plane. */
+ /* Compute radius of the footprint on the hypothetic plane */
+ float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d);
+ float r_step = r_fp / INTEGRAL_RESOLUTION;
+ float area_accum = 0.0f;
+ for (float r = 0.0f; r < r_fp; r += r_step) {
+ /* Compute distance to the "shading" point through the medium. */
+ /* r_step * 0.5f to put sample between the area borders */
+ float dist = hypotf(r + r_step * 0.5f, d);
- if (ob_iter->type == OB_LAMP) {
- float omat[4][4];
- copy_m4_m4(omat, ob_iter->obmat);
- copy_m4_m4(ob_iter->obmat, dob->mat);
+ float profile[3];
+ profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]);
+ profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]);
+ profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]);
- GPULamp *lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob_iter, ob);
- if (lamp)
- shade_one_light(shi, shr, lamp);
+ /* Since the profile and configuration are radially symmetrical we
+ * can just evaluate it once and weight it accordingly */
+ float r_next = r + r_step;
+ float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r);
- copy_m4_m4(ob_iter->obmat, omat);
- }
- }
-
- free_object_duplilist(lb);
+ mul_v3_fl(profile, disk_area);
+ add_v3_v3(texels[i], profile);
+ area_accum += disk_area;
}
+ /* Normalize over the disk. */
+ mul_v3_fl(texels[i], 1.0f / (area_accum));
}
- /* prevent only shadow lamps from producing negative colors.*/
- GPU_link(shi->gpumat, "shade_clamp_positive", shr->spec, &shr->spec);
- GPU_link(shi->gpumat, "shade_clamp_positive", shr->diff, &shr->diff);
-}
-
-static void texture_rgb_blend(
- GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
- int blendtype, GPUNodeLink **in)
-{
- switch (blendtype) {
- case MTEX_BLEND:
- GPU_link(mat, "mtex_rgb_blend", out, tex, fact, facg, in);
- break;
- case MTEX_MUL:
- GPU_link(mat, "mtex_rgb_mul", out, tex, fact, facg, in);
- break;
- case MTEX_SCREEN:
- GPU_link(mat, "mtex_rgb_screen", out, tex, fact, facg, in);
- break;
- case MTEX_OVERLAY:
- GPU_link(mat, "mtex_rgb_overlay", out, tex, fact, facg, in);
- break;
- case MTEX_SUB:
- GPU_link(mat, "mtex_rgb_sub", out, tex, fact, facg, in);
- break;
- case MTEX_ADD:
- GPU_link(mat, "mtex_rgb_add", out, tex, fact, facg, in);
- break;
- case MTEX_DIV:
- GPU_link(mat, "mtex_rgb_div", out, tex, fact, facg, in);
- break;
- case MTEX_DIFF:
- GPU_link(mat, "mtex_rgb_diff", out, tex, fact, facg, in);
- break;
- case MTEX_DARK:
- GPU_link(mat, "mtex_rgb_dark", out, tex, fact, facg, in);
- break;
- case MTEX_LIGHT:
- GPU_link(mat, "mtex_rgb_light", out, tex, fact, facg, in);
- break;
- case MTEX_BLEND_HUE:
- GPU_link(mat, "mtex_rgb_hue", out, tex, fact, facg, in);
- break;
- case MTEX_BLEND_SAT:
- GPU_link(mat, "mtex_rgb_sat", out, tex, fact, facg, in);
- break;
- case MTEX_BLEND_VAL:
- GPU_link(mat, "mtex_rgb_val", out, tex, fact, facg, in);
- break;
- case MTEX_BLEND_COLOR:
- GPU_link(mat, "mtex_rgb_color", out, tex, fact, facg, in);
- break;
- case MTEX_SOFT_LIGHT:
- GPU_link(mat, "mtex_rgb_soft", out, tex, fact, facg, in);
- break;
- case MTEX_LIN_LIGHT:
- GPU_link(mat, "mtex_rgb_linear", out, tex, fact, facg, in);
- break;
- default:
- GPU_link(mat, "set_rgb_zero", &in);
- break;
+ /* Normalize */
+ for (int j = resolution - 2; j > 0; j--) {
+ texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f;
+ texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f;
+ texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f;
}
+
+ /* First texel should be white */
+ texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f;
+ texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f;
+ texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f;
+
+ /* dim the last few texels for smoother transition */
+ mul_v3_fl(texels[resolution - 2], 0.25f);
+ mul_v3_fl(texels[resolution - 3], 0.5f);
+ mul_v3_fl(texels[resolution - 4], 0.75f);
}
+#undef INTEGRAL_RESOLUTION
-static void texture_value_blend(
- GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
- int blendtype, GPUNodeLink **in)
+void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], short *falloff_type, float *sharpness)
{
- switch (blendtype) {
- case MTEX_BLEND:
- GPU_link(mat, "mtex_value_blend", out, tex, fact, facg, in);
- break;
- case MTEX_MUL:
- GPU_link(mat, "mtex_value_mul", out, tex, fact, facg, in);
- break;
- case MTEX_SCREEN:
- GPU_link(mat, "mtex_value_screen", out, tex, fact, facg, in);
- break;
- case MTEX_SUB:
- GPU_link(mat, "mtex_value_sub", out, tex, fact, facg, in);
- break;
- case MTEX_ADD:
- GPU_link(mat, "mtex_value_add", out, tex, fact, facg, in);
- break;
- case MTEX_DIV:
- GPU_link(mat, "mtex_value_div", out, tex, fact, facg, in);
- break;
- case MTEX_DIFF:
- GPU_link(mat, "mtex_value_diff", out, tex, fact, facg, in);
- break;
- case MTEX_DARK:
- GPU_link(mat, "mtex_value_dark", out, tex, fact, facg, in);
- break;
- case MTEX_LIGHT:
- GPU_link(mat, "mtex_value_light", out, tex, fact, facg, in);
- break;
- default:
- GPU_link(mat, "set_value_zero", &in);
- break;
+ copy_v3_v3(material->sss_radii, radii);
+ material->sss_falloff = (falloff_type) ? *falloff_type : 0.0;
+ material->sss_sharpness = (sharpness) ? *sharpness : 0.0;
+ material->sss_dirty = true;
+ material->sss_enabled = true;
+
+ /* Update / Create UBO */
+ if (material->sss_profile == NULL) {
+ material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL);
}
}
-static void do_material_tex(GPUShadeInput *shi)
+struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_len, GPUTexture **tex_profile)
{
- Material *ma = shi->mat;
- GPUMaterial *mat = shi->gpumat;
- MTex *mtex;
- Tex *tex;
- GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac;
- GPUNodeLink *texco_norm, *texco_orco, *texco_object;
- GPUNodeLink *texco_global, *texco_uv = NULL;
- GPUNodeLink *newnor, *orn;
- float one = 1.0f;
- int rgbnor, talpha;
- bool init_done = false;
- int iBumpSpacePrev = 0; /* Not necessary, quieting gcc warning. */
- GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude;
- int iFirstTimeNMap = 1;
- bool found_deriv_map = false;
-
- GPU_link(mat, "set_value", GPU_uniform(&one), &stencil);
-
- GPU_link(mat, "texco_norm", GPU_builtin(GPU_VIEW_NORMAL), &texco_norm);
- GPU_link(mat, "texco_orco", GPU_attribute(CD_ORCO, ""), &texco_orco);
- GPU_link(mat, "texco_object", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
- GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
- GPU_builtin(GPU_VIEW_POSITION), &texco_object);
-#if 0
- GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent);
-#endif
- GPU_link(mat, "texco_global", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
- GPU_builtin(GPU_VIEW_POSITION), &texco_global);
-
- orn = texco_norm;
-
- /* go over texture slots */
- for (int tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
- /* separate tex switching */
- if (ma->septex & (1 << tex_nr)) continue;
-
- if (ma->mtex[tex_nr]) {
- mtex = ma->mtex[tex_nr];
-
- tex = mtex->tex;
- if (tex == NULL) continue;
-
- /* which coords */
- if (mtex->texco == TEXCO_ORCO)
- texco = texco_orco;
- else if (mtex->texco == TEXCO_OBJECT)
- texco = texco_object;
- else if (mtex->texco == TEXCO_NORM)
- texco = orn;
- else if (mtex->texco == TEXCO_TANGENT)
- texco = texco_object;
- else if (mtex->texco == TEXCO_GLOB)
- texco = texco_global;
- else if (mtex->texco == TEXCO_REFL) {
- GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref);
- texco = shi->ref;
- }
- else if (mtex->texco == TEXCO_UV) {
- if (1) { //!(texco_uv && strcmp(mtex->uvname, lastuvname) == 0)) {
- GPU_link(mat, "texco_uv", GPU_attribute(CD_MTFACE, mtex->uvname), &texco_uv);
- /*lastuvname = mtex->uvname;*/ /*UNUSED*/
- }
- texco = texco_uv;
- }
- else
- continue;
-
- /* in case of uv, this would just undo a multiplication in texco_uv */
- if (mtex->texco != TEXCO_UV)
- GPU_link(mat, "mtex_2d_mapping", texco, &texco);
-
- if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f)
- GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(mtex->size), &texco);
-
- float ofs[3] = {
- mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0],
- mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1],
- 0.0f
- };
-
- if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f)
- GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco);
-
- talpha = 0;
-
- if (tex && tex->ima &&
- ((tex->type == TEX_IMAGE) ||
- ((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL))))
- {
- if (tex->type == TEX_IMAGE) {
- GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
- }
- else {
- GPU_link(mat, "mtex_cube_map_refl",
- GPU_cube_map(tex->ima, &tex->iuser, false), shi->view, shi->vn,
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
- GPU_builtin(GPU_VIEW_MATRIX), &tin, &trgb);
- }
- rgbnor = TEX_RGB;
-
- talpha = ((tex->imaflag & TEX_USEALPHA) && tex->ima && (tex->ima->flag & IMA_IGNORE_ALPHA) == 0);
- }
- else {
- continue;
- }
+ if (!material->sss_enabled)
+ return NULL;
- /* texture output */
- if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
- rgbnor -= TEX_RGB;
- }
+ if (material->sss_dirty || (material->sss_samples != sample_len)) {
+ GPUSssKernelData kd;
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgbnor & TEX_RGB)
- GPU_link(mat, "mtex_rgb_invert", trgb, &trgb);
- else
- GPU_link(mat, "mtex_value_invert", tin, &tin);
- }
+ float sharpness = material->sss_sharpness;
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgbnor & TEX_RGB)
- GPU_link(mat, "mtex_rgb_stencil", stencil, trgb, &stencil, &trgb);
- else
- GPU_link(mat, "mtex_value_stencil", stencil, tin, &stencil, &tin);
- }
+ /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */
+ sharpness *= 0.5f;
- /* mapping */
- if (mtex->mapto & (MAP_COL | MAP_COLSPEC | MAP_COLMIR)) {
- /* stencil maps on the texture control slider, not texture intensity value */
- if ((rgbnor & TEX_RGB) == 0) {
- GPU_link(mat, "set_rgb", GPU_uniform(&mtex->r), &tcol);
- }
- else {
- GPU_link(mat, "set_rgba", trgb, &tcol);
-
- if (mtex->mapto & MAP_ALPHA)
- GPU_link(mat, "set_value", stencil, &tin);
- else if (talpha)
- GPU_link(mat, "mtex_alpha_from_col", trgb, &tin);
- else
- GPU_link(mat, "set_value_one", &tin);
- }
-
- if ((tex->type == TEX_IMAGE) ||
- ((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL)))
- {
- if (GPU_material_do_color_management(mat)) {
- GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol);
- }
- }
-
- if (mtex->mapto & MAP_COL) {
- GPUNodeLink *colfac;
-
- if (mtex->colfac == 1.0f) colfac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->colfac), stencil, &colfac);
-
- texture_rgb_blend(mat, tcol, shi->rgb, tin, colfac, mtex->blendtype, &shi->rgb);
- }
-
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_COLSPEC)) {
- GPUNodeLink *colspecfac;
-
- if (mtex->colspecfac == 1.0f) colspecfac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->colspecfac), stencil, &colspecfac);
-
- texture_rgb_blend(mat, tcol, shi->specrgb, tin, colspecfac, mtex->blendtype, &shi->specrgb);
- }
-
- if (mtex->mapto & MAP_COLMIR) {
- GPUNodeLink *colmirfac;
-
- if (mtex->mirrfac == 1.0f) colmirfac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->mirrfac), stencil, &colmirfac);
-
- /* exception for envmap only */
- if (tex->type == TEX_ENVMAP && mtex->blendtype == MTEX_BLEND) {
- GPU_link(mat, "mtex_mirror", tcol, shi->refcol, tin, colmirfac, &shi->refcol);
- }
- else
- texture_rgb_blend(mat, tcol, shi->mir, tin, colmirfac, mtex->blendtype, &shi->mir);
- }
- }
+ compute_sss_kernel(&kd, material->sss_radii, sample_len, material->sss_falloff, sharpness);
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_NORM)) {
- if (tex->type == TEX_IMAGE) {
- found_deriv_map = tex->imaflag & TEX_DERIVATIVEMAP;
-
- if (tex->imaflag & TEX_NORMALMAP) {
- /* normalmap image */
- GPU_link(mat, "mtex_normal", texco, GPU_image(tex->ima, &tex->iuser, true), &tnor);
-
- if (mtex->norfac < 0.0f)
- GPU_link(mat, "mtex_negate_texnormal", tnor, &tnor);
-
- if (mtex->normapspace == MTEX_NSPACE_TANGENT) {
- if (iFirstTimeNMap != 0) {
- // use unnormalized normal (this is how we bake it - closer to gamedev)
- GPUNodeLink *vNegNorm;
- GPU_link(mat, "vec_math_negate",
- GPU_builtin(GPU_VIEW_NORMAL), &vNegNorm);
- GPU_link(mat, "mtex_nspace_tangent",
- GPU_attribute(CD_TANGENT, ""), vNegNorm, tnor, &newnor);
- iFirstTimeNMap = 0;
- }
- else { /* otherwise use accumulated perturbations */
- GPU_link(mat, "mtex_nspace_tangent",
- GPU_attribute(CD_TANGENT, ""), shi->vn, tnor, &newnor);
- }
- }
- else if (mtex->normapspace == MTEX_NSPACE_OBJECT) {
- /* transform normal by object then view matrix */
- GPU_link(mat, "mtex_nspace_object", tnor, &newnor);
- }
- else if (mtex->normapspace == MTEX_NSPACE_WORLD) {
- /* transform normal by view matrix */
- GPU_link(mat, "mtex_nspace_world", GPU_builtin(GPU_VIEW_MATRIX), tnor, &newnor);
- }
- else {
- /* no transform, normal in camera space */
- newnor = tnor;
- }
-
- float norfac = min_ff(fabsf(mtex->norfac), 1.0f);
-
- if (norfac == 1.0f && !GPU_link_changed(stencil)) {
- shi->vn = newnor;
- }
- else {
- tnorfac = GPU_uniform(&norfac);
-
- if (GPU_link_changed(stencil))
- GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac);
-
- GPU_link(mat, "mtex_blend_normal", tnorfac, shi->vn, newnor, &shi->vn);
- }
-
- }
- else if (found_deriv_map ||
- (mtex->texflag & (MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)))
- {
- /* ntap bumpmap image */
- int iBumpSpace;
- float ima_x, ima_y;
-
- float imag_tspace_dimension_x = 1024.0f; /* only used for texture space variant */
- float aspect = 1.0f;
-
- GPUNodeLink *vR1, *vR2;
- GPUNodeLink *dBs, *dBt, *fDet;
-
- float hScale = 0.1f; /* compatibility adjustment factor for all bumpspace types */
- if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
- hScale = 13.0f; /* factor for scaling texspace bumps */
- else if (found_deriv_map)
- hScale = 1.0f;
-
- /* resolve texture resolution */
- if ((mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
- ima_x = 512.0f; ima_y = 512.0f; /* prevent calling textureSize, glsl 1.3 only */
- if (ibuf) {
- ima_x = ibuf->x;
- ima_y = ibuf->y;
- aspect = (float)ima_y / ima_x;
- }
- BKE_image_release_ibuf(tex->ima, ibuf, NULL);
- }
-
- /* The negate on norfac is done because the
- * normal in the renderer points inward which corresponds
- * to inverting the bump map. Should this ever change
- * this negate must be removed. */
- float norfac = -hScale * mtex->norfac;
- if (found_deriv_map) {
- float fVirtDim = sqrtf(fabsf(ima_x * mtex->size[0] * ima_y * mtex->size[1]));
- norfac /= MAX2(fVirtDim, FLT_EPSILON);
- }
-
- tnorfac = GPU_uniform(&norfac);
-
- if (found_deriv_map)
- GPU_link(mat, "math_multiply", tnorfac, GPU_builtin(GPU_AUTO_BUMPSCALE), &tnorfac);
-
- if (GPU_link_changed(stencil))
- GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac);
-
- if (!init_done) {
- /* copy shi->vn to vNorg and vNacc, set magnitude to 1 */
- GPU_link(mat, "mtex_bump_normals_init", shi->vn, &vNorg, &vNacc, &fPrevMagnitude);
- iBumpSpacePrev = 0;
- init_done = true;
- }
-
- // find current bump space
- if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
- iBumpSpace = 1;
- else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
- iBumpSpace = 2;
- else
- iBumpSpace = 4; /* ViewSpace */
-
- /* re-initialize if bump space changed */
- if (iBumpSpacePrev != iBumpSpace) {
- GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION);
-
- if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
- GPU_link(mat, "mtex_bump_init_objspace",
- surf_pos, vNorg,
- GPU_builtin(GPU_VIEW_MATRIX),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
- GPU_builtin(GPU_OBJECT_MATRIX),
- GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
- fPrevMagnitude, vNacc,
- &fPrevMagnitude, &vNacc,
- &vR1, &vR2, &fDet);
-
- else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
- GPU_link(mat, "mtex_bump_init_texturespace",
- surf_pos, vNorg,
- fPrevMagnitude, vNacc,
- &fPrevMagnitude, &vNacc,
- &vR1, &vR2, &fDet);
-
- else
- GPU_link(mat, "mtex_bump_init_viewspace",
- surf_pos, vNorg,
- fPrevMagnitude, vNacc,
- &fPrevMagnitude, &vNacc,
- &vR1, &vR2, &fDet);
-
- iBumpSpacePrev = iBumpSpace;
- }
-
-
- if (found_deriv_map) {
- GPU_link(mat, "mtex_bump_deriv",
- texco, GPU_image(tex->ima, &tex->iuser, true),
- GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac,
- &dBs, &dBt);
- }
- else if (mtex->texflag & MTEX_3TAP_BUMP)
- GPU_link(mat, "mtex_bump_tap3",
- texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
- &dBs, &dBt);
- else if (mtex->texflag & MTEX_5TAP_BUMP)
- GPU_link(mat, "mtex_bump_tap5",
- texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
- &dBs, &dBt);
- else if (mtex->texflag & MTEX_BICUBIC_BUMP) {
- if (GPU_bicubic_bump_support()) {
- GPU_link(mat, "mtex_bump_bicubic",
- texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
- &dBs, &dBt);
- }
- else {
- GPU_link(mat, "mtex_bump_tap5",
- texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac,
- &dBs, &dBt);
- }
- }
-
-
- if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) {
- float imag_tspace_dimension_y = aspect * imag_tspace_dimension_x;
- GPU_link(mat, "mtex_bump_apply_texspace",
- fDet, dBs, dBt, vR1, vR2,
- GPU_image(tex->ima, &tex->iuser, true), texco,
- GPU_uniform(&imag_tspace_dimension_x),
- GPU_uniform(&imag_tspace_dimension_y), vNacc,
- &vNacc, &shi->vn);
- }
- else
- GPU_link(mat, "mtex_bump_apply",
- fDet, dBs, dBt, vR1, vR2, vNacc,
- &vNacc, &shi->vn);
-
- }
- }
-
- GPU_link(mat, "vec_math_negate", shi->vn, &orn);
- }
+ /* Update / Create UBO */
+ GPU_uniformbuffer_update(material->sss_profile, &kd);
- if ((mtex->mapto & MAP_VARS)) {
- if (rgbnor & TEX_RGB) {
- if (talpha)
- GPU_link(mat, "mtex_alpha_from_col", trgb, &tin);
- else
- GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
- }
-
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_REF) {
- GPUNodeLink *difffac;
-
- if (mtex->difffac == 1.0f) difffac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->difffac), stencil, &difffac);
-
- texture_value_blend(
- mat, GPU_uniform(&mtex->def_var), shi->refl, tin, difffac,
- mtex->blendtype, &shi->refl);
- GPU_link(mat, "mtex_value_clamp_positive", shi->refl, &shi->refl);
- }
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_SPEC) {
- GPUNodeLink *specfac;
-
- if (mtex->specfac == 1.0f) specfac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->specfac), stencil, &specfac);
-
- texture_value_blend(
- mat, GPU_uniform(&mtex->def_var), shi->spec, tin, specfac,
- mtex->blendtype, &shi->spec);
- GPU_link(mat, "mtex_value_clamp_positive", shi->spec, &shi->spec);
- }
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_EMIT) {
- GPUNodeLink *emitfac;
-
- if (mtex->emitfac == 1.0f) emitfac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->emitfac), stencil, &emitfac);
-
- texture_value_blend(
- mat, GPU_uniform(&mtex->def_var), shi->emit, tin, emitfac,
- mtex->blendtype, &shi->emit);
- GPU_link(mat, "mtex_value_clamp_positive", shi->emit, &shi->emit);
- }
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_HAR) {
- GPUNodeLink *hardfac;
-
- if (mtex->hardfac == 1.0f) hardfac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->hardfac), stencil, &hardfac);
-
- GPU_link(mat, "mtex_har_divide", shi->har, &shi->har);
- texture_value_blend(
- mat, GPU_uniform(&mtex->def_var), shi->har, tin, hardfac,
- mtex->blendtype, &shi->har);
- GPU_link(mat, "mtex_har_multiply_clamp", shi->har, &shi->har);
- }
- if (mtex->mapto & MAP_ALPHA) {
- GPUNodeLink *alphafac;
-
- if (mtex->alphafac == 1.0f) alphafac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->alphafac), stencil, &alphafac);
-
- texture_value_blend(
- mat, GPU_uniform(&mtex->def_var), shi->alpha, tin, alphafac,
- mtex->blendtype, &shi->alpha);
- GPU_link(mat, "mtex_value_clamp", shi->alpha, &shi->alpha);
- }
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_AMB) {
- GPUNodeLink *ambfac;
-
- if (mtex->ambfac == 1.0f) ambfac = stencil;
- else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->ambfac), stencil, &ambfac);
-
- texture_value_blend(
- mat, GPU_uniform(&mtex->def_var), shi->amb, tin, ambfac,
- mtex->blendtype, &shi->amb);
- GPU_link(mat, "mtex_value_clamp", shi->amb, &shi->amb);
- }
- }
+ /* Update / Create Tex */
+ float *translucence_profile;
+ compute_sss_translucence_kernel(&kd, 64, material->sss_falloff, sharpness, &translucence_profile);
+
+ if (material->sss_tex_profile != NULL) {
+ GPU_texture_free(material->sss_tex_profile);
}
+
+ material->sss_tex_profile = GPU_texture_create_1D(64, GPU_RGBA16F, translucence_profile, NULL);
+
+ MEM_freeN(translucence_profile);
+
+ material->sss_samples = sample_len;
+ material->sss_dirty = false;
}
-}
-void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
-{
- float one = 1.0f;
-
- memset(shi, 0, sizeof(*shi));
-
- shi->gpumat = mat;
- shi->mat = ma;
-
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, ma), &shi->rgb);
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, ma), &shi->specrgb);
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, ma), &shi->mir);
- GPU_link(mat, "set_rgba_zero", &shi->refcol);
- GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn);
-
- if (mat->alpha)
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, ma), &shi->alpha);
- else
- GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha);
-
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, ma), &shi->refl);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, ma), &shi->spec);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, ma), &shi->emit);
- GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, ma), &shi->har);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, ma), &shi->amb);
- GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra);
- GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view);
- GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol);
- if (GPU_material_do_color_management(mat))
- GPU_link(mat, "srgb_to_linearrgb", shi->vcol, &shi->vcol);
- GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref);
+ if (tex_profile != NULL) {
+ *tex_profile = material->sss_tex_profile;
+ }
+ return material->sss_profile;
}
-void GPU_mist_update_enable(short enable)
+struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void)
{
- GPUWorld.mistenabled = (float)enable;
+ return GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL);
}
-void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3])
-{
- GPUWorld.mistype = (float)type;
- GPUWorld.miststart = start;
- GPUWorld.mistdistance = dist;
- GPUWorld.mistintensity = inten;
- copy_v3_v3(GPUWorld.mistcol, color);
- GPUWorld.mistcol[3] = 1.0f;
-}
+#undef SSS_EXPONENT
+#undef SSS_SAMPLES
-void GPU_horizon_update_color(float color[3])
+void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs)
{
- copy_v3_v3(GPUWorld.horicol, color);
+ *attribs = material->attribs;
}
-void GPU_ambient_update_color(float color[3])
+void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
{
- copy_v3_v3(GPUWorld.ambcol, color);
- GPUWorld.ambcol[3] = 1.0f;
+ if (!material->outlink)
+ material->outlink = link;
}
-void GPU_zenith_update_color(float color[3])
+void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
{
- copy_v3_v3(GPUWorld.zencol, color);
+ BLI_addtail(&material->nodes, node);
}
-void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
+/* Return true if the material compilation has not yet begin or begin. */
+GPUMaterialStatus GPU_material_status(GPUMaterial *mat)
{
- GPUMaterial *mat = shi->gpumat;
- GPUNodeLink *emit, *ulinfac, *ulogfac, *mistfac;
- Material *ma = shi->mat;
- World *world = mat->scene->world;
- float linfac, logfac;
-
- memset(shr, 0, sizeof(*shr));
-
- if (ma->mode & MA_VERTEXCOLP)
- shi->rgb = shi->vcol;
-
- do_material_tex(shi);
-
- if ((mat->scene->gm.flag & GAME_GLSL_NO_LIGHTS) || (ma->mode & MA_SHLESS)) {
- GPU_link(mat, "set_rgb", shi->rgb, &shr->diff);
- GPU_link(mat, "set_rgb_zero", &shr->spec);
- GPU_link(mat, "set_value", shi->alpha, &shr->alpha);
- shr->combined = shr->diff;
- }
- else {
- if (GPU_link_changed(shi->emit) || ma->emit != 0.0f) {
- if ((ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == MA_VERTEXCOL) {
- GPU_link(mat, "shade_add", shi->emit, shi->vcol, &emit);
- GPU_link(mat, "shade_mul", emit, shi->rgb, &shr->diff);
- }
- else
- GPU_link(mat, "shade_mul_value", shi->emit, shi->rgb, &shr->diff);
- }
- else
- GPU_link(mat, "set_rgb_zero", &shr->diff);
-
- GPU_link(mat, "set_rgb_zero", &shr->spec);
-
- material_lights(shi, shr);
-
- shr->combined = shr->diff;
-
- GPU_link(mat, "set_value", shi->alpha, &shr->alpha);
-
- if (world) {
- /* exposure correction */
- if (world->exp != 0.0f || world->range != 1.0f) {
- linfac = 1.0f + powf((2.0f * world->exp + 0.5f), -10);
- logfac = logf((linfac - 1.0f) / linfac) / world->range;
-
- GPU_link(mat, "set_value", GPU_uniform(&linfac), &ulinfac);
- GPU_link(mat, "set_value", GPU_uniform(&logfac), &ulogfac);
-
- GPU_link(mat, "shade_exposure_correct", shr->combined,
- ulinfac, ulogfac, &shr->combined);
- GPU_link(mat, "shade_exposure_correct", shr->spec,
- ulinfac, ulogfac, &shr->spec);
- }
-
- /* environment lighting */
- if (!(mat->scene->gm.flag & GAME_GLSL_NO_ENV_LIGHTING) &&
- (world->mode & WO_ENV_LIGHT) &&
- (mat->scene->r.mode & R_SHADOW) &&
- !BKE_scene_use_new_shading_nodes(mat->scene))
- {
- if ((world->ao_env_energy != 0.0f) && (GPU_link_changed(shi->amb) || ma->amb != 0.0f) &&
- (GPU_link_changed(shi->refl) || ma->ref != 0.0f))
- {
- if (world->aocolor != WO_AOPLAIN) {
- if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) {
- GPUNodeLink *fcol, *f;
- GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
- GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
- GPU_link(mat, "shade_mul_value", f, shi->rgb, &fcol);
- GPU_link(mat, "env_apply", shr->combined,
- GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL),
- GPU_dynamic_uniform(GPUWorld.zencol, GPU_DYNAMIC_ZENITH_COLOR, NULL), fcol,
- GPU_builtin(GPU_VIEW_MATRIX), shi->vn, &shr->combined);
- }
- }
- else {
- GPUNodeLink *f;
- GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
- GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
- GPU_link(mat, "shade_maddf", shr->combined, f, shi->rgb, &shr->combined);
- }
- }
- }
-
- /* ambient color */
- if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) {
- GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb),
- GPU_dynamic_uniform(GPUWorld.ambcol, GPU_DYNAMIC_AMBIENT_COLOR, NULL),
- &shr->combined);
- }
- }
-
- if (ma->mode & MA_TRANSP && (ma->mode & (MA_ZTRANSP | MA_RAYTRANSP))) {
- if (GPU_link_changed(shi->spectra) || ma->spectra != 0.0f) {
- GPU_link(mat, "alpha_spec_correction", shr->spec, shi->spectra,
- shi->alpha, &shr->alpha);
- }
- }
-
- if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shi, &shr->combined);
- if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shi, &shr->spec);
-
- if (GPU_link_changed(shi->refcol))
- GPU_link(mat, "shade_add_mirror", shi->mir, shi->refcol, shr->combined, &shr->combined);
-
- if (GPU_link_changed(shi->spec) || ma->spec != 0.0f)
- GPU_link(mat, "shade_add", shr->combined, shr->spec, &shr->combined);
- }
-
- GPU_link(mat, "mtex_alpha_to_col", shr->combined, shr->alpha, &shr->combined);
-
- if (ma->shade_flag & MA_OBCOLOR)
- GPU_link(mat, "shade_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined);
-
- if (!(ma->mode & MA_NOMIST)) {
- GPU_link(mat, "shade_mist_factor", GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_uniform(&GPUWorld.mistenabled, GPU_DYNAMIC_MIST_ENABLE, NULL),
- GPU_dynamic_uniform(&GPUWorld.miststart, GPU_DYNAMIC_MIST_START, NULL),
- GPU_dynamic_uniform(&GPUWorld.mistdistance, GPU_DYNAMIC_MIST_DISTANCE, NULL),
- GPU_dynamic_uniform(&GPUWorld.mistype, GPU_DYNAMIC_MIST_TYPE, NULL),
- GPU_dynamic_uniform(&GPUWorld.mistintensity, GPU_DYNAMIC_MIST_INTENSITY, NULL), &mistfac);
-
- GPU_link(mat, "mix_blend", mistfac, shr->combined,
- GPU_dynamic_uniform(GPUWorld.mistcol, GPU_DYNAMIC_MIST_COLOR, NULL), &shr->combined);
- }
+ return mat->status;
+}
- if (!mat->alpha) {
- if (world && (GPU_link_changed(shr->alpha) || ma->alpha != 1.0f))
- GPU_link(mat, "shade_world_mix", GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL),
- shr->combined, &shr->combined);
+/* Code generation */
- GPU_link(mat, "shade_alpha_opaque", shr->combined, &shr->combined);
- }
+bool GPU_material_do_color_management(GPUMaterial *mat)
+{
+ if (!BKE_scene_check_color_management_enabled(mat->scene))
+ return false;
- if (ma->shade_flag & MA_OBCOLOR) {
- mat->obcolalpha = 1;
- GPU_link(mat, "shade_alpha_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined);
- }
+ return true;
}
-static GPUNodeLink *GPU_blender_material(GPUMaterial *mat, Material *ma)
+bool GPU_material_use_domain_surface(GPUMaterial *mat)
{
- GPUShadeInput shi;
- GPUShadeResult shr;
-
- GPU_shadeinput_set(mat, ma, &shi);
- GPU_shaderesult_set(&shi, &shr);
-
- return shr.combined;
+ return (mat->domain & GPU_DOMAIN_SURFACE);
}
-static GPUNodeLink *gpu_material_diffuse_bsdf(GPUMaterial *mat, Material *ma)
+bool GPU_material_use_domain_volume(GPUMaterial *mat)
{
- static float roughness = 0.0f;
- GPUNodeLink *outlink;
-
- GPU_link(mat, "node_bsdf_diffuse",
- GPU_uniform(&ma->r), GPU_uniform(&roughness), GPU_builtin(GPU_VIEW_NORMAL), &outlink);
-
- return outlink;
+ return (mat->domain & GPU_DOMAIN_VOLUME);
}
-static GPUNodeLink *gpu_material_preview_matcap(GPUMaterial *mat, Material *ma)
+void GPU_material_flag_set(GPUMaterial *mat, GPUMatFlag flag)
{
- GPUNodeLink *outlink;
-
- /* some explanations here:
- * matcap normal holds the normal remapped to the 0.0 - 1.0 range. To take advantage of flat shading, we abuse
- * the built in secondary color of opengl. Color is just the regular color, which should include mask value too.
- * This also needs flat shading so we use the primary opengl color built-in */
- GPU_link(mat, "material_preview_matcap", GPU_uniform(&ma->r), GPU_image_preview(ma->preview),
- GPU_opengl_builtin(GPU_MATCAP_NORMAL), GPU_opengl_builtin(GPU_COLOR), &outlink);
-
- return outlink;
+ mat->flag |= flag;
}
-/* new solid draw mode with glsl matcaps */
-GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv)
+bool GPU_material_flag_get(GPUMaterial *mat, GPUMatFlag flag)
{
- GPUMaterial *mat;
- GPUNodeLink *outlink;
- LinkData *link;
+ return (mat->flag & flag);
+}
- for (link = ma->gpumaterial.first; link; link = link->next) {
+GPUMaterial *GPU_material_from_nodetree_find(
+ ListBase *gpumaterials, const void *engine_type, int options)
+{
+ for (LinkData *link = gpumaterials->first; link; link = link->next) {
GPUMaterial *current_material = (GPUMaterial *)link->data;
- if (current_material->scene == scene &&
- current_material->is_opensubdiv == use_opensubdiv)
+ if (current_material->engine_type == engine_type &&
+ current_material->options == options)
{
return current_material;
}
}
- /* allocate material */
- mat = GPU_material_construct_begin(ma);
- mat->scene = scene;
- mat->type = GPU_MATERIAL_TYPE_MESH;
- mat->is_opensubdiv = use_opensubdiv;
-
- if (ma->preview && ma->preview->rect[0]) {
- outlink = gpu_material_preview_matcap(mat, ma);
- }
- else {
- outlink = gpu_material_diffuse_bsdf(mat, ma);
- }
+ return NULL;
+}
- GPU_material_output_link(mat, outlink);
+/**
+ * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
+ * This is enforced since constructing other arguments to this function may be expensive
+ * so only do this when they are needed.
+ */
+GPUMaterial *GPU_material_from_nodetree(
+ Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options,
+ const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, const char *name)
+{
+ LinkData *link;
+ bool has_volume_output, has_surface_output;
- gpu_material_construct_end(mat, "matcap_pass");
+ /* Caller must re-use materials. */
+ BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
- /* note that even if building the shader fails in some way, we still keep
- * it to avoid trying to compile again and again, and simple do not use
- * the actual shader on drawing */
+ /* allocate material */
+ GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
+ mat->scene = scene;
+ mat->engine_type = engine_type;
+ mat->options = options;
+#ifndef NDEBUG
+ BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
+#else
+ UNUSED_VARS(name);
+#endif
- link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
- link->data = mat;
- BLI_addtail(&ma->gpumaterial, link);
+ /* localize tree to create links for reroute and mute */
+ bNodeTree *localtree = ntreeLocalize(ntree);
+ ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output);
- return mat;
-}
+ gpu_material_ramp_texture_build(mat);
-static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor, GPUNodeLink **zen, GPUNodeLink **blend)
-{
- GPUMaterial *mat = shi->gpumat;
- GPUNodeLink *texco, *tin, *trgb, *stencil, *tcol, *zenfac;
- MTex *mtex;
- Tex *tex;
- float ofs[3], zero = 0.0f;
- int tex_nr, rgbnor;
-
- GPU_link(mat, "set_value_one", &stencil);
- /* go over texture slots */
- for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
- if (wo->mtex[tex_nr]) {
- mtex = wo->mtex[tex_nr];
- tex = mtex->tex;
- if (tex == NULL || !tex->ima || (tex->type != TEX_IMAGE && tex->type != TEX_ENVMAP))
- continue;
- /* which coords */
- if (mtex->texco == TEXCO_VIEW || mtex->texco == TEXCO_GLOB) {
- if (tex->type == TEX_IMAGE)
- texco = GPU_builtin(GPU_VIEW_POSITION);
- else if (tex->type == TEX_ENVMAP)
- GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco);
- }
- else if (mtex->texco == TEXCO_EQUIRECTMAP || mtex->texco == TEXCO_ANGMAP) {
- if ((tex->type == TEX_IMAGE && wo->skytype & WO_SKYREAL) || tex->type == TEX_ENVMAP)
- GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco);
- else
- texco = GPU_builtin(GPU_VIEW_POSITION);
- }
- else
- continue;
- GPU_link(mat, "texco_norm", texco, &texco);
- if (tex->type == TEX_IMAGE && !(wo->skytype & WO_SKYREAL)) {
- GPU_link(mat, "mtex_2d_mapping", texco, &texco);
- }
- if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) {
- float size[3] = { mtex->size[0], mtex->size[1], mtex->size[2] };
- if (tex->type == TEX_ENVMAP) {
- size[1] = mtex->size[2];
- size[2] = mtex->size[1];
- }
- GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(size), &texco);
- }
- ofs[0] = mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0];
- if (tex->type == TEX_ENVMAP) {
- ofs[1] = -mtex->ofs[2] + 0.5f - 0.5f * mtex->size[2];
- ofs[2] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
- }
- else {
- ofs[1] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
- ofs[2] = 0.0;
- }
- if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f)
- GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco);
- if (mtex->texco == TEXCO_EQUIRECTMAP) {
- GPU_link(mat, "node_tex_environment_equirectangular", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb);
- }
- else if (mtex->texco == TEXCO_ANGMAP) {
- GPU_link(mat, "node_tex_environment_mirror_ball", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb);
- }
- else {
- if (tex->type == TEX_ENVMAP)
- GPU_link(mat, "mtex_cube_map", texco, GPU_cube_map(tex->ima, &tex->iuser, false), &tin, &trgb);
- else if (tex->type == TEX_IMAGE)
- GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
- }
- rgbnor = TEX_RGB;
- if (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)
- if (GPU_material_do_color_management(mat))
- GPU_link(mat, "srgb_to_linearrgb", trgb, &trgb);
- /* texture output */
- if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
- rgbnor -= TEX_RGB;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgbnor & TEX_RGB)
- GPU_link(mat, "mtex_rgb_invert", trgb, &trgb);
- else
- GPU_link(mat, "mtex_value_invert", tin, &tin);
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgbnor & TEX_RGB)
- GPU_link(mat, "mtex_rgb_stencil", stencil, trgb, &stencil, &trgb);
- else
- GPU_link(mat, "mtex_value_stencil", stencil, tin, &stencil, &tin);
- }
- else {
- if (rgbnor & TEX_RGB)
- GPU_link(mat, "mtex_alpha_multiply_value", trgb, stencil, &trgb);
- else
- GPU_link(mat, "math_multiply", stencil, tin, &tin);
- }
- /* color mapping */
- if (mtex->mapto & (WOMAP_HORIZ + WOMAP_ZENUP + WOMAP_ZENDOWN)) {
- if ((rgbnor & TEX_RGB) == 0)
- GPU_link(mat, "set_rgb", GPU_uniform(&mtex->r), &trgb);
- else
- GPU_link(mat, "mtex_alpha_from_col", trgb, &tin);
- GPU_link(mat, "set_rgb", trgb, &tcol);
- if (mtex->mapto & WOMAP_HORIZ) {
- texture_rgb_blend(mat, tcol, *hor, tin, GPU_uniform(&mtex->colfac), mtex->blendtype, hor);
- }
- if (mtex->mapto & (WOMAP_ZENUP + WOMAP_ZENDOWN)) {
- GPU_link(mat, "set_value_zero", &zenfac);
- if (wo->skytype & WO_SKYREAL) {
- if (mtex->mapto & WOMAP_ZENUP) {
- if (mtex->mapto & WOMAP_ZENDOWN) {
- GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&mtex->zenupfac),
- GPU_uniform(&mtex->zendownfac), &zenfac);
- }
- else {
- GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&mtex->zenupfac),
- GPU_uniform(&zero), &zenfac);
- }
- }
- else if (mtex->mapto & WOMAP_ZENDOWN) {
- GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&zero),
- GPU_uniform(&mtex->zendownfac), &zenfac);
- }
- }
- else {
- if (mtex->mapto & WOMAP_ZENUP)
- GPU_link(mat, "set_value", GPU_uniform(&mtex->zenupfac), &zenfac);
- else if (mtex->mapto & WOMAP_ZENDOWN)
- GPU_link(mat, "set_value", GPU_uniform(&mtex->zendownfac), &zenfac);
- }
- texture_rgb_blend(mat, tcol, *zen, tin, zenfac, mtex->blendtype, zen);
- }
- }
- if (mtex->mapto & WOMAP_BLEND && wo->skytype & WO_SKYBLEND) {
- if (rgbnor & TEX_RGB)
- GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
- texture_value_blend(mat, GPU_uniform(&mtex->def_var), *blend, tin, GPU_uniform(&mtex->blendfac), mtex->blendtype, blend);
- }
- }
+ if (has_surface_output) {
+ mat->domain |= GPU_DOMAIN_SURFACE;
+ }
+ if (has_volume_output) {
+ mat->domain |= GPU_DOMAIN_VOLUME;
}
-}
-
-static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo)
-{
- GPUShadeInput shi;
- GPUShadeResult shr;
- GPUNodeLink *hor, *zen, *ray, *blend;
- shi.gpumat = mat;
+ if (mat->outlink) {
+ /* Prune the unused nodes and extract attribs before compiling so the
+ * generated VBOs are ready to accept the future shader. */
+ GPU_nodes_prune(&mat->nodes, mat->outlink);
+ GPU_nodes_get_vertex_attributes(&mat->nodes, &mat->attribs);
+ /* Create source code and search pass cache for an already compiled version. */
+ mat->pass = GPU_generate_pass(
+ mat,
+ mat->outlink,
+ &mat->attribs,
+ &mat->nodes,
+ &mat->builtins,
+ vert_code,
+ geom_code,
+ frag_lib,
+ defines);
- for (int i = 0; i < MAX_MTEX; i++) {
- if (wo->mtex[i] && wo->mtex[i]->tex) {
- wo->skytype |= WO_SKYTEX;
- break;
+ if (mat->pass == NULL) {
+ /* We had a cache hit and the shader has already failed to compile. */
+ mat->status = GPU_MAT_FAILED;
}
- }
- if ((wo->skytype & (WO_SKYBLEND + WO_SKYTEX)) == 0) {
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->horr, GPU_DYNAMIC_HORIZON_COLOR, NULL), &shr.combined);
- }
- else {
- GPU_link(mat, "set_rgb_zero", &shi.rgb);
- GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &ray);
- if (wo->skytype & WO_SKYPAPER)
- GPU_link(mat, "world_paper_view", GPU_builtin(GPU_VIEW_POSITION), &shi.view);
- else
- GPU_link(mat, "shade_view", ray, &shi.view);
- if (wo->skytype & WO_SKYBLEND) {
- if (wo->skytype & WO_SKYPAPER) {
- if (wo->skytype & WO_SKYREAL)
- GPU_link(mat, "world_blend_paper_real", GPU_builtin(GPU_VIEW_POSITION), &blend);
- else
- GPU_link(mat, "world_blend_paper", GPU_builtin(GPU_VIEW_POSITION), &blend);
+ else {
+ GPUShader *sh = GPU_pass_shader_get(mat->pass);
+ if (sh != NULL) {
+ /* We had a cache hit and the shader is already compiled. */
+ mat->status = GPU_MAT_SUCCESS;
+ GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
}
else {
- if (wo->skytype & WO_SKYREAL)
- GPU_link(mat, "world_blend_real", ray, &blend);
- else
- GPU_link(mat, "world_blend", ray, &blend);
+ mat->status = GPU_MAT_QUEUED;
}
}
- else {
- GPU_link(mat, "set_value_zero", &blend);
- }
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->horr, GPU_DYNAMIC_HORIZON_COLOR, NULL), &hor);
- GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->zenr, GPU_DYNAMIC_ZENITH_COLOR, NULL), &zen);
- do_world_tex(&shi, wo, &hor, &zen, &blend);
- if (wo->skytype & WO_SKYBLEND)
- GPU_link(mat, "node_mix_shader", blend, hor, zen, &shi.rgb);
- else
- GPU_link(mat, "set_rgb", hor, &shi.rgb);
- GPU_link(mat, "set_rgb", shi.rgb, &shr.combined);
- }
- GPU_material_output_link(mat, shr.combined);
-}
-
-GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
-{
- LinkData *link;
- GPUMaterial *mat;
-
- for (link = wo->gpumaterial.first; link; link = link->next)
- if (((GPUMaterial *)link->data)->scene == scene)
- return link->data;
-
- /* allocate material */
- mat = GPU_material_construct_begin(NULL);
- mat->scene = scene;
- mat->type = GPU_MATERIAL_TYPE_WORLD;
-
- /* create nodes */
- if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) {
- ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING);
}
else {
- gpu_material_old_world(mat, wo);
+ mat->status = GPU_MAT_FAILED;
}
- if (GPU_material_do_color_management(mat))
- if (mat->outlink)
- GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
-
- gpu_material_construct_end(mat, wo->id.name);
+ /* Only free after GPU_pass_shader_get where GPUUniformBuffer
+ * read data from the local tree. */
+ ntreeFreeTree(localtree);
+ MEM_freeN(localtree);
/* note that even if building the shader fails in some way, we still keep
- * it to avoid trying to compile again and again, and simple do not use
+ * it to avoid trying to compile again and again, and simply do not use
* the actual shader on drawing */
link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
link->data = mat;
- BLI_addtail(&wo->gpumaterial, link);
+ BLI_addtail(gpumaterials, link);
return mat;
}
-
-GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv)
+void GPU_material_compile(GPUMaterial *mat)
{
- GPUMaterial *mat;
- GPUNodeLink *outlink;
- LinkData *link;
+ /* Only run once! */
+ BLI_assert(mat->status == GPU_MAT_QUEUED);
+ BLI_assert(mat->pass);
- for (link = ma->gpumaterial.first; link; link = link->next) {
- GPUMaterial *current_material = (GPUMaterial *)link->data;
- if (current_material->scene == scene &&
- current_material->is_opensubdiv == use_opensubdiv)
- {
- return current_material;
- }
- }
+ /* NOTE: The shader may have already been compiled here since we are
+ * sharing GPUShader across GPUMaterials. In this case it's a no-op. */
+#ifndef NDEBUG
+ GPU_pass_compile(mat->pass, mat->name);
+#else
+ GPU_pass_compile(mat->pass, __func__);
+#endif
- /* allocate material */
- mat = GPU_material_construct_begin(ma);
- mat->scene = scene;
- mat->type = GPU_MATERIAL_TYPE_MESH;
- mat->is_opensubdiv = use_opensubdiv;
-
- /* render pipeline option */
- bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
- if (!new_shading_nodes && (ma->mode & MA_TRANSP))
- GPU_material_enable_alpha(mat);
- else if (new_shading_nodes && ma->alpha < 1.0f)
- GPU_material_enable_alpha(mat);
-
- if (!(scene->gm.flag & GAME_GLSL_NO_NODES) && ma->nodetree && ma->use_nodes) {
- /* create nodes */
- if (new_shading_nodes)
- ntreeGPUMaterialNodes(ma->nodetree, mat, NODE_NEW_SHADING);
- else
- ntreeGPUMaterialNodes(ma->nodetree, mat, NODE_OLD_SHADING);
+ GPUShader *sh = GPU_pass_shader_get(mat->pass);
+
+ if (sh != NULL) {
+ mat->status = GPU_MAT_SUCCESS;
+ GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
}
else {
- if (new_shading_nodes) {
- /* create simple diffuse material instead of nodes */
- outlink = gpu_material_diffuse_bsdf(mat, ma);
- }
- else {
- /* create blender material */
- outlink = GPU_blender_material(mat, ma);
- }
-
- GPU_material_output_link(mat, outlink);
+ mat->status = GPU_MAT_FAILED;
+ GPU_pass_free_nodes(&mat->nodes);
+ GPU_pass_release(mat->pass);
+ mat->pass = NULL;
}
-
- if (GPU_material_do_color_management(mat))
- if (mat->outlink)
- GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink);
-
- gpu_material_construct_end(mat, ma->id.name);
-
- /* note that even if building the shader fails in some way, we still keep
- * it to avoid trying to compile again and again, and simple do not use
- * the actual shader on drawing */
-
- link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
- link->data = mat;
- BLI_addtail(&ma->gpumaterial, link);
-
- return mat;
}
void GPU_materials_free(Main *bmain)
{
- Object *ob;
Material *ma;
World *wo;
extern Material defmaterial;
@@ -2230,684 +768,4 @@ void GPU_materials_free(Main *bmain)
GPU_material_free(&wo->gpumaterial);
GPU_material_free(&defmaterial.gpumaterial);
-
- for (ob = bmain->object.first; ob; ob = ob->id.next)
- GPU_lamp_free(ob);
-}
-
-/* Lamps and shadow buffers */
-
-static void gpu_lamp_calc_winmat(GPULamp *lamp)
-{
- float temp, angle, pixsize, wsize;
-
- if (lamp->type == LA_SUN) {
- wsize = lamp->la->shadow_frustum_size;
- orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
- }
- else if (lamp->type == LA_SPOT) {
- angle = saacos(lamp->spotsi);
- temp = 0.5f * lamp->size * cosf(angle) / sinf(angle);
- pixsize = lamp->d / temp;
- wsize = pixsize * 0.5f * lamp->size;
- /* compute shadows according to X and Y scaling factors */
- perspective_m4(
- lamp->winmat,
- -wsize * lamp->spotvec[0], wsize * lamp->spotvec[0],
- -wsize * lamp->spotvec[1], wsize * lamp->spotvec[1],
- lamp->d, lamp->clipend);
- }
-}
-
-void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4])
-{
- float mat[4][4];
- float obmat_scale[3];
-
- lamp->lay = lay;
- lamp->hide = hide;
-
- normalize_m4_m4_ex(mat, obmat, obmat_scale);
-
- copy_v3_v3(lamp->vec, mat[2]);
- copy_v3_v3(lamp->co, mat[3]);
- copy_m4_m4(lamp->obmat, mat);
- invert_m4_m4(lamp->imat, mat);
-
- if (lamp->type == LA_SPOT) {
- /* update spotlamp scale on X and Y axis */
- lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2];
- lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2];
- }
-
- if (GPU_lamp_has_shadow_buffer(lamp)) {
- /* makeshadowbuf */
- gpu_lamp_calc_winmat(lamp);
- }
-}
-
-void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy)
-{
- lamp->energy = energy;
- if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy;
-
- lamp->col[0] = r;
- lamp->col[1] = g;
- lamp->col[2] = b;
-}
-
-void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2,
- float coeff_const, float coeff_lin, float coeff_quad)
-{
- lamp->dist = distance;
- lamp->att1 = att1;
- lamp->att2 = att2;
- lamp->coeff_const = coeff_const;
- lamp->coeff_lin = coeff_lin;
- lamp->coeff_quad = coeff_quad;
-}
-
-void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend)
-{
- lamp->spotsi = cosf(spotsize * 0.5f);
- lamp->spotbl = (1.0f - lamp->spotsi) * spotblend;
-}
-
-static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp)
-{
- lamp->scene = scene;
- lamp->ob = ob;
- lamp->par = par;
- lamp->la = la;
-
- /* add_render_lamp */
- lamp->mode = la->mode;
- lamp->type = la->type;
-
- lamp->energy = la->energy;
- if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy;
-
- lamp->col[0] = la->r;
- lamp->col[1] = la->g;
- lamp->col[2] = la->b;
-
- GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), ob->obmat);
-
- lamp->spotsi = la->spotsize;
- if (lamp->mode & LA_HALO)
- if (lamp->spotsi > DEG2RADF(170.0f))
- lamp->spotsi = DEG2RADF(170.0f);
- lamp->spotsi = cosf(lamp->spotsi * 0.5f);
- lamp->spotbl = (1.0f - lamp->spotsi) * la->spotblend;
- lamp->k = la->k;
-
- lamp->dist = la->dist;
- lamp->falloff_type = la->falloff_type;
- lamp->att1 = la->att1;
- lamp->att2 = la->att2;
- lamp->coeff_const = la->coeff_const;
- lamp->coeff_lin = la->coeff_lin;
- lamp->coeff_quad = la->coeff_quad;
- lamp->curfalloff = la->curfalloff;
-
- /* initshadowbuf */
- lamp->bias = 0.02f * la->bias;
- lamp->size = la->bufsize;
- lamp->d = la->clipsta;
- lamp->clipend = la->clipend;
-
- /* arbitrary correction for the fact we do no soft transition */
- lamp->bias *= 0.25f;
-}
-
-static void gpu_lamp_shadow_free(GPULamp *lamp)
-{
- if (lamp->tex) {
- GPU_texture_free(lamp->tex);
- lamp->tex = NULL;
- }
- if (lamp->depthtex) {
- GPU_texture_free(lamp->depthtex);
- lamp->depthtex = NULL;
- }
- if (lamp->fb) {
- GPU_framebuffer_free(lamp->fb);
- lamp->fb = NULL;
- }
- if (lamp->blurtex) {
- GPU_texture_free(lamp->blurtex);
- lamp->blurtex = NULL;
- }
- if (lamp->blurfb) {
- GPU_framebuffer_free(lamp->blurfb);
- lamp->blurfb = NULL;
- }
-}
-
-GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
-{
- Lamp *la;
- GPULamp *lamp;
- LinkData *link;
-
- for (link = ob->gpulamp.first; link; link = link->next) {
- lamp = (GPULamp *)link->data;
-
- if (lamp->par == par && lamp->scene == scene)
- return link->data;
- }
-
- lamp = MEM_callocN(sizeof(GPULamp), "GPULamp");
-
- link = MEM_callocN(sizeof(LinkData), "GPULampLink");
- link->data = lamp;
- BLI_addtail(&ob->gpulamp, link);
-
- la = ob->data;
- gpu_lamp_from_blender(scene, ob, par, la, lamp);
-
- if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) ||
- (la->type == LA_SUN && (la->mode & LA_SHAD_RAY)))
- {
- /* opengl */
- lamp->fb = GPU_framebuffer_create();
- if (!lamp->fb) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
- /* Shadow depth map */
- lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, NULL);
- if (!lamp->depthtex) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- /* Shadow color map */
- lamp->tex = GPU_texture_create_vsm_shadow_map(lamp->size, NULL);
- if (!lamp->tex) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- /* FBO and texture for blurring */
- lamp->blurfb = GPU_framebuffer_create();
- if (!lamp->blurfb) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size * 0.5, NULL);
- if (!lamp->blurtex) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, NULL)) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- /* we need to properly bind to test for completeness */
- GPU_texture_bind_as_framebuffer(lamp->blurtex);
-
- if (!GPU_framebuffer_check_valid(lamp->blurfb, NULL)) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- GPU_framebuffer_texture_unbind(lamp->blurfb, lamp->blurtex);
- }
- else {
- lamp->tex = GPU_texture_create_depth(lamp->size, lamp->size, NULL);
- if (!lamp->tex) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
-
- if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) {
- gpu_lamp_shadow_free(lamp);
- return lamp;
- }
- }
-
- GPU_framebuffer_restore();
-
- lamp->shadow_color[0] = la->shdwr;
- lamp->shadow_color[1] = la->shdwg;
- lamp->shadow_color[2] = la->shdwb;
- }
- else {
- lamp->shadow_color[0] = 1.0;
- lamp->shadow_color[1] = 1.0;
- lamp->shadow_color[2] = 1.0;
- }
-
- return lamp;
-}
-
-void GPU_lamp_free(Object *ob)
-{
- GPULamp *lamp;
- LinkData *link;
- LinkData *nlink;
- Material *ma;
-
- for (link = ob->gpulamp.first; link; link = link->next) {
- lamp = link->data;
-
- while (lamp->materials.first) {
- nlink = lamp->materials.first;
- ma = nlink->data;
- BLI_freelinkN(&lamp->materials, nlink);
-
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
- }
-
- gpu_lamp_shadow_free(lamp);
-
- MEM_freeN(lamp);
- }
-
- BLI_freelistN(&ob->gpulamp);
-}
-
-bool GPU_lamp_has_shadow_buffer(GPULamp *lamp)
-{
- return (!(lamp->scene->gm.flag & GAME_GLSL_NO_SHADOWS) &&
- !(lamp->scene->gm.flag & GAME_GLSL_NO_LIGHTS) &&
- lamp->tex && lamp->fb);
-}
-
-void GPU_lamp_update_buffer_mats(GPULamp *lamp)
-{
- float rangemat[4][4], persmat[4][4];
-
- /* initshadowbuf */
- invert_m4_m4(lamp->viewmat, lamp->obmat);
- normalize_v3(lamp->viewmat[0]);
- normalize_v3(lamp->viewmat[1]);
- normalize_v3(lamp->viewmat[2]);
-
- /* makeshadowbuf */
- mul_m4_m4m4(persmat, lamp->winmat, lamp->viewmat);
-
- /* opengl depth buffer is range 0.0..1.0 instead of -1.0..1.0 in blender */
- unit_m4(rangemat);
- rangemat[0][0] = 0.5f;
- rangemat[1][1] = 0.5f;
- rangemat[2][2] = 0.5f;
- rangemat[3][0] = 0.5f;
- rangemat[3][1] = 0.5f;
- rangemat[3][2] = 0.5f;
-
- mul_m4_m4m4(lamp->persmat, rangemat, persmat);
-}
-
-void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4])
-{
- GPU_lamp_update_buffer_mats(lamp);
-
- /* opengl */
- glDisable(GL_SCISSOR_TEST);
- GPU_texture_bind_as_framebuffer(lamp->tex);
- if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE)
- GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE));
-
- /* set matrices */
- copy_m4_m4(viewmat, lamp->viewmat);
- copy_m4_m4(winmat, lamp->winmat);
- *winsize = lamp->size;
-}
-
-void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp)
-{
- if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
- GPU_shader_unbind();
- GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex);
- }
-
- GPU_framebuffer_texture_unbind(lamp->fb, lamp->tex);
- GPU_framebuffer_restore();
- glEnable(GL_SCISSOR_TEST);
-}
-
-int GPU_lamp_shadow_buffer_type(GPULamp *lamp)
-{
- return lamp->la->shadowmap_type;
}
-
-int GPU_lamp_shadow_bind_code(GPULamp *lamp)
-{
- return lamp->tex ? GPU_texture_opengl_bindcode(lamp->tex) : -1;
-}
-
-float *GPU_lamp_dynpersmat(GPULamp *lamp)
-{
- return &lamp->dynpersmat[0][0];
-}
-
-int GPU_lamp_shadow_layer(GPULamp *lamp)
-{
- if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW)))
- return lamp->lay;
- else
- return -1;
-}
-
-GPUNodeLink *GPU_lamp_get_data(
- GPUMaterial *mat, GPULamp *lamp,
- GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy)
-{
- GPUNodeLink *visifac;
-
- *r_col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob);
- *r_energy = GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob);
- visifac = lamp_get_visibility(mat, lamp, r_lv, r_dist);
-
- shade_light_textures(mat, lamp, r_col);
-
- if (GPU_lamp_has_shadow_buffer(lamp)) {
- GPUNodeLink *vn, *inp;
-
- GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &vn);
- GPU_link(mat, "shade_inp", vn, *r_lv, &inp);
- mat->dynproperty |= DYN_LAMP_PERSMAT;
-
- if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
- GPU_link(mat, "shadows_only_vsm",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
- GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias),
- GPU_uniform(lamp->shadow_color), inp, r_shadow);
- }
- else {
- GPU_link(mat, "shadows_only",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
- GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, r_shadow);
- }
- }
- else {
- GPU_link(mat, "set_rgb_one", r_shadow);
- }
-
- /* ensure shadow buffer and lamp textures will be updated */
- add_user_list(&mat->lamps, lamp);
- add_user_list(&lamp->materials, mat->ma);
-
- return visifac;
-}
-
-/* export the GLSL shader */
-
-GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
-{
- static struct {
- GPUBuiltin gputype;
- GPUDynamicType dynamictype;
- GPUDataType datatype;
- } builtins[] = {
- { GPU_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_VIEWMAT, GPU_DATA_16F },
- { GPU_INVERSE_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_VIEWIMAT, GPU_DATA_16F },
- { GPU_OBJECT_MATRIX, GPU_DYNAMIC_OBJECT_MAT, GPU_DATA_16F },
- { GPU_INVERSE_OBJECT_MATRIX, GPU_DYNAMIC_OBJECT_IMAT, GPU_DATA_16F },
- { GPU_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT, GPU_DATA_16F },
- { GPU_INVERSE_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT, GPU_DATA_16F },
- { GPU_OBCOLOR, GPU_DYNAMIC_OBJECT_COLOR, GPU_DATA_4F },
- { GPU_AUTO_BUMPSCALE, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE, GPU_DATA_1F },
- { 0 }
- };
-
- GPUShaderExport *shader = NULL;
- GPUInput *input;
- int liblen, fraglen;
-
- /* TODO(sergey): How to determine whether we need OSD or not here? */
- GPUMaterial *mat = GPU_material_from_blender(scene, ma, false);
- GPUPass *pass = (mat) ? mat->pass : NULL;
-
- if (pass && pass->fragmentcode && pass->vertexcode) {
- shader = MEM_callocN(sizeof(GPUShaderExport), "GPUShaderExport");
-
- for (input = pass->inputs.first; input; input = input->next) {
- GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
-
- if (input->ima) {
- /* image sampler uniform */
- uniform->type = GPU_DYNAMIC_SAMPLER_2DIMAGE;
- uniform->datatype = GPU_DATA_1I;
- uniform->image = input->ima;
- uniform->texnumber = input->texid;
- BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
- }
- else if (input->tex) {
- /* generated buffer */
- uniform->texnumber = input->texid;
- uniform->datatype = GPU_DATA_1I;
- BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
-
- switch (input->textype) {
- case GPU_SHADOW2D:
- uniform->type = GPU_DYNAMIC_SAMPLER_2DSHADOW;
- uniform->lamp = input->dynamicdata;
- break;
- case GPU_TEX2D:
- if (GPU_texture_opengl_bindcode(input->tex)) {
- uniform->type = GPU_DYNAMIC_SAMPLER_2DBUFFER;
- glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(input->tex));
- uniform->texsize = GPU_texture_width(input->tex) * GPU_texture_height(input->tex);
- uniform->texpixels = MEM_mallocN(uniform->texsize * 4, "RGBApixels");
- glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, uniform->texpixels);
- glBindTexture(GL_TEXTURE_2D, 0);
- }
- break;
-
- case GPU_NONE:
- case GPU_TEXCUBE:
- case GPU_FLOAT:
- case GPU_VEC2:
- case GPU_VEC3:
- case GPU_VEC4:
- case GPU_MAT3:
- case GPU_MAT4:
- case GPU_ATTRIB:
- break;
- }
- }
- else {
- uniform->type = input->dynamictype;
- BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
- switch (input->type) {
- case GPU_FLOAT:
- uniform->datatype = GPU_DATA_1F;
- break;
- case GPU_VEC2:
- uniform->datatype = GPU_DATA_2F;
- break;
- case GPU_VEC3:
- uniform->datatype = GPU_DATA_3F;
- break;
- case GPU_VEC4:
- uniform->datatype = GPU_DATA_4F;
- break;
- case GPU_MAT3:
- uniform->datatype = GPU_DATA_9F;
- break;
- case GPU_MAT4:
- uniform->datatype = GPU_DATA_16F;
- break;
-
- case GPU_NONE:
- case GPU_TEX2D:
- case GPU_TEXCUBE:
- case GPU_SHADOW2D:
- case GPU_ATTRIB:
- break;
- }
-
- if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP)
- uniform->lamp = input->dynamicdata;
-
- if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_MAT)
- uniform->material = input->dynamicdata;
- }
-
- if (uniform->type != GPU_DYNAMIC_NONE)
- BLI_addtail(&shader->uniforms, uniform);
- else
- MEM_freeN(uniform);
- }
-
- /* process builtin uniform */
- for (int i = 0; builtins[i].gputype; i++) {
- if (mat->builtins & builtins[i].gputype) {
- GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
- uniform->type = builtins[i].dynamictype;
- uniform->datatype = builtins[i].datatype;
- BLI_strncpy(uniform->varname, GPU_builtin_name(builtins[i].gputype), sizeof(uniform->varname));
- BLI_addtail(&shader->uniforms, uniform);
- }
- }
-
- /* now link fragment shader with library shader */
- /* TBD: remove the function that are not used in the main function */
- liblen = (pass->libcode) ? strlen(pass->libcode) : 0;
- fraglen = strlen(pass->fragmentcode);
- shader->fragment = (char *)MEM_mallocN(liblen + fraglen + 1, "GPUFragShader");
- if (pass->libcode)
- memcpy(shader->fragment, pass->libcode, liblen);
- memcpy(&shader->fragment[liblen], pass->fragmentcode, fraglen);
- shader->fragment[liblen + fraglen] = 0;
-
- // export the attribute
- for (int i = 0; i < mat->attribs.totlayer; i++) {
- GPUInputAttribute *attribute = MEM_callocN(sizeof(GPUInputAttribute), "GPUInputAttribute");
- attribute->type = mat->attribs.layer[i].type;
- attribute->number = mat->attribs.layer[i].glindex;
- BLI_snprintf(attribute->varname, sizeof(attribute->varname), "att%d", mat->attribs.layer[i].attribid);
-
- switch (attribute->type) {
- case CD_TANGENT:
- attribute->datatype = GPU_DATA_4F;
- break;
- case CD_MTFACE:
- attribute->datatype = GPU_DATA_2F;
- attribute->name = mat->attribs.layer[i].name;
- break;
- case CD_MCOL:
- attribute->datatype = GPU_DATA_4UB;
- attribute->name = mat->attribs.layer[i].name;
- break;
- case CD_ORCO:
- attribute->datatype = GPU_DATA_3F;
- break;
- }
-
- if (attribute->datatype != GPU_DATA_NONE)
- BLI_addtail(&shader->attributes, attribute);
- else
- MEM_freeN(attribute);
- }
-
- /* export the vertex shader */
- shader->vertex = BLI_strdup(pass->vertexcode);
- }
-
- return shader;
-}
-
-void GPU_free_shader_export(GPUShaderExport *shader)
-{
- if (shader == NULL)
- return;
-
- for (GPUInputUniform *uniform = shader->uniforms.first; uniform; uniform = uniform->next)
- if (uniform->texpixels)
- MEM_freeN(uniform->texpixels);
-
- BLI_freelistN(&shader->uniforms);
- BLI_freelistN(&shader->attributes);
-
- if (shader->vertex)
- MEM_freeN(shader->vertex);
- if (shader->fragment)
- MEM_freeN(shader->fragment);
-
- MEM_freeN(shader);
-}
-
-#ifdef WITH_OPENSUBDIV
-void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
- DerivedMesh *dm)
-{
- GPUPass *pass = gpu_material->pass;
- GPUShader *shader = (pass != NULL ? pass->shader : NULL);
- ListBase *inputs = (pass != NULL ? &pass->inputs : NULL);
- GPUInput *input;
-
- if (shader == NULL) {
- return;
- }
-
- GPU_shader_bind(shader);
-
- for (input = inputs->first;
- input != NULL;
- input = input->next)
- {
- if (input->source == GPU_SOURCE_ATTRIB &&
- input->attribtype == CD_MTFACE)
- {
- char name[64];
- /* TODO(sergey): This will work for until names are
- * consistent, we'll need to solve this somehow in the future.
- */
- int layer_index;
- int location;
-
- if (input->attribname[0] != '\0') {
- layer_index = CustomData_get_named_layer(&dm->loopData,
- CD_MLOOPUV,
- input->attribname);
- }
- else {
- layer_index = CustomData_get_active_layer(&dm->loopData,
- CD_MLOOPUV);
- }
-
- BLI_snprintf(name, sizeof(name),
- "fvar%d_offset",
- input->attribid);
- location = GPU_shader_get_uniform(shader, name);
- GPU_shader_uniform_int(shader, location, layer_index);
- }
- }
-
- GPU_shader_unbind();
-}
-#endif
diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c
new file mode 100644
index 00000000000..5ab8086397c
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_matrix.c
@@ -0,0 +1,649 @@
+/*
+ * ***** 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 ipmlied 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) 2012 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file source/blender/gpu/intern/gpu_matrix.c
+ * \ingroup gpu
+ */
+
+#include "GPU_shader_interface.h"
+
+#define SUPPRESS_GENERIC_MATRIX_API
+#define USE_GPU_PY_MATRIX_API /* only so values are declared */
+#include "GPU_matrix.h"
+#undef USE_GPU_PY_MATRIX_API
+
+#include "BLI_math_matrix.h"
+#include "BLI_math_rotation.h"
+#include "BLI_math_vector.h"
+
+
+#define DEBUG_MATRIX_BIND 0
+
+#define MATRIX_STACK_DEPTH 32
+
+typedef float Mat4[4][4];
+typedef float Mat3[3][3];
+
+typedef struct MatrixStack {
+ Mat4 stack[MATRIX_STACK_DEPTH];
+ uint top;
+} MatrixStack;
+
+typedef struct {
+ MatrixStack model_view_stack;
+ MatrixStack projection_stack;
+
+ bool dirty;
+
+ /* TODO: cache of derived matrices (Normal, MVP, inverse MVP, etc)
+ * generate as needed for shaders, invalidate when original matrices change
+ *
+ * TODO: separate Model from View transform? Batches/objects have model,
+ * camera/eye has view & projection
+ */
+} MatrixState;
+
+#define MATRIX_4X4_IDENTITY {{1.0f, 0.0f, 0.0f, 0.0f}, \
+ {0.0f, 1.0f, 0.0f, 0.0f}, \
+ {0.0f, 0.0f, 1.0f, 0.0f}, \
+ {0.0f, 0.0f, 0.0f, 1.0f}}
+
+static MatrixState state = {
+ .model_view_stack = {{MATRIX_4X4_IDENTITY}, 0},
+ .projection_stack = {{MATRIX_4X4_IDENTITY}, 0},
+ .dirty = true
+};
+
+#undef MATRIX_4X4_IDENTITY
+
+#define ModelViewStack state.model_view_stack
+#define ModelView ModelViewStack.stack[ModelViewStack.top]
+
+#define ProjectionStack state.projection_stack
+#define Projection ProjectionStack.stack[ProjectionStack.top]
+
+void GPU_matrix_reset(void)
+{
+ state.model_view_stack.top = 0;
+ state.projection_stack.top = 0;
+ unit_m4(ModelView);
+ unit_m4(Projection);
+ state.dirty = true;
+}
+
+#ifdef WITH_GPU_SAFETY
+
+/* Check if matrix is numerically good */
+static void checkmat(cosnt float *m)
+{
+ const int n = 16;
+ for (int i = 0; i < n; i++) {
+#if _MSC_VER
+ BLI_assert(_finite(m[i]));
+#else
+ BLI_assert(!isinf(m[i]));
+#endif
+ }
+}
+
+#define CHECKMAT(m) checkmat((const float *)m)
+
+#else
+
+#define CHECKMAT(m)
+
+#endif
+
+
+void GPU_matrix_push(void)
+{
+ BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH);
+ ModelViewStack.top++;
+ copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]);
+}
+
+void GPU_matrix_pop(void)
+{
+ BLI_assert(ModelViewStack.top > 0);
+ ModelViewStack.top--;
+ state.dirty = true;
+}
+
+void GPU_matrix_push_projection(void)
+{
+ BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH);
+ ProjectionStack.top++;
+ copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]);
+}
+
+void GPU_matrix_pop_projection(void)
+{
+ BLI_assert(ProjectionStack.top > 0);
+ ProjectionStack.top--;
+ state.dirty = true;
+}
+
+void GPU_matrix_set(const float m[4][4])
+{
+ copy_m4_m4(ModelView, m);
+ CHECKMAT(ModelView3D);
+ state.dirty = true;
+}
+
+void GPU_matrix_identity_projection_set(void)
+{
+ unit_m4(Projection);
+ CHECKMAT(Projection3D);
+ state.dirty = true;
+}
+
+void GPU_matrix_projection_set(const float m[4][4])
+{
+ copy_m4_m4(Projection, m);
+ CHECKMAT(Projection3D);
+ state.dirty = true;
+}
+
+void GPU_matrix_identity_set(void)
+{
+ unit_m4(ModelView);
+ state.dirty = true;
+}
+
+void GPU_matrix_translate_2f(float x, float y)
+{
+ Mat4 m;
+ unit_m4(m);
+ m[3][0] = x;
+ m[3][1] = y;
+ GPU_matrix_mul(m);
+}
+
+void GPU_matrix_translate_2fv(const float vec[2])
+{
+ GPU_matrix_translate_2f(vec[0], vec[1]);
+}
+
+void GPU_matrix_translate_3f(float x, float y, float z)
+{
+#if 1
+ translate_m4(ModelView, x, y, z);
+ CHECKMAT(ModelView);
+#else /* above works well in early testing, below is generic version */
+ Mat4 m;
+ unit_m4(m);
+ m[3][0] = x;
+ m[3][1] = y;
+ m[3][2] = z;
+ GPU_matrix_mul(m);
+#endif
+ state.dirty = true;
+}
+
+void GPU_matrix_translate_3fv(const float vec[3])
+{
+ GPU_matrix_translate_3f(vec[0], vec[1], vec[2]);
+}
+
+void GPU_matrix_scale_1f(float factor)
+{
+ Mat4 m;
+ scale_m4_fl(m, factor);
+ GPU_matrix_mul(m);
+}
+
+void GPU_matrix_scale_2f(float x, float y)
+{
+ Mat4 m = {{0.0f}};
+ m[0][0] = x;
+ m[1][1] = y;
+ m[2][2] = 1.0f;
+ m[3][3] = 1.0f;
+ GPU_matrix_mul(m);
+}
+
+void GPU_matrix_scale_2fv(const float vec[2])
+{
+ GPU_matrix_scale_2f(vec[0], vec[1]);
+}
+
+void GPU_matrix_scale_3f(float x, float y, float z)
+{
+ Mat4 m = {{0.0f}};
+ m[0][0] = x;
+ m[1][1] = y;
+ m[2][2] = z;
+ m[3][3] = 1.0f;
+ GPU_matrix_mul(m);
+}
+
+void GPU_matrix_scale_3fv(const float vec[3])
+{
+ GPU_matrix_scale_3f(vec[0], vec[1], vec[2]);
+}
+
+void GPU_matrix_mul(const float m[4][4])
+{
+ mul_m4_m4_post(ModelView, m);
+ CHECKMAT(ModelView);
+ state.dirty = true;
+}
+
+void GPU_matrix_rotate_2d(float deg)
+{
+ /* essentially RotateAxis('Z')
+ * TODO: simpler math for 2D case
+ */
+ rotate_m4(ModelView, 'Z', DEG2RADF(deg));
+}
+
+void GPU_matrix_rotate_3f(float deg, float x, float y, float z)
+{
+ const float axis[3] = {x, y, z};
+ GPU_matrix_rotate_3fv(deg, axis);
+}
+
+void GPU_matrix_rotate_3fv(float deg, const float axis[3])
+{
+ Mat4 m;
+ axis_angle_to_mat4(m, axis, DEG2RADF(deg));
+ GPU_matrix_mul(m);
+}
+
+void GPU_matrix_rotate_axis(float deg, char axis)
+{
+ /* rotate_m4 works in place */
+ rotate_m4(ModelView, axis, DEG2RADF(deg));
+ CHECKMAT(ModelView);
+ state.dirty = true;
+}
+
+static void mat4_ortho_set(float m[4][4], float left, float right, float bottom, float top, float near, float far)
+{
+ m[0][0] = 2.0f / (right - left);
+ m[1][0] = 0.0f;
+ m[2][0] = 0.0f;
+ m[3][0] = -(right + left) / (right - left);
+
+ m[0][1] = 0.0f;
+ m[1][1] = 2.0f / (top - bottom);
+ m[2][1] = 0.0f;
+ m[3][1] = -(top + bottom) / (top - bottom);
+
+ m[0][2] = 0.0f;
+ m[1][2] = 0.0f;
+ m[2][2] = -2.0f / (far - near);
+ m[3][2] = -(far + near) / (far - near);
+
+ m[0][3] = 0.0f;
+ m[1][3] = 0.0f;
+ m[2][3] = 0.0f;
+ m[3][3] = 1.0f;
+
+ state.dirty = true;
+}
+
+static void mat4_frustum_set(float m[4][4], float left, float right, float bottom, float top, float near, float far)
+{
+ m[0][0] = 2.0f * near / (right - left);
+ m[1][0] = 0.0f;
+ m[2][0] = (right + left) / (right - left);
+ m[3][0] = 0.0f;
+
+ m[0][1] = 0.0f;
+ m[1][1] = 2.0f * near / (top - bottom);
+ m[2][1] = (top + bottom) / (top - bottom);
+ m[3][1] = 0.0f;
+
+ m[0][2] = 0.0f;
+ m[1][2] = 0.0f;
+ m[2][2] = -(far + near) / (far - near);
+ m[3][2] = -2.0f * far * near / (far - near);
+
+ m[0][3] = 0.0f;
+ m[1][3] = 0.0f;
+ m[2][3] = -1.0f;
+ m[3][3] = 0.0f;
+
+ state.dirty = true;
+}
+
+static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3])
+{
+/* This function is loosely based on Mesa implementation.
+ *
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+ float side[3];
+
+ normalize_v3(lookdir);
+
+ cross_v3_v3v3(side, lookdir, camup);
+
+ normalize_v3(side);
+
+ cross_v3_v3v3(camup, side, lookdir);
+
+ m[0][0] = side[0];
+ m[1][0] = side[1];
+ m[2][0] = side[2];
+ m[3][0] = 0.0f;
+
+ m[0][1] = camup[0];
+ m[1][1] = camup[1];
+ m[2][1] = camup[2];
+ m[3][1] = 0.0f;
+
+ m[0][2] = -lookdir[0];
+ m[1][2] = -lookdir[1];
+ m[2][2] = -lookdir[2];
+ m[3][2] = 0.0f;
+
+ m[0][3] = 0.0f;
+ m[1][3] = 0.0f;
+ m[2][3] = 0.0f;
+ m[3][3] = 1.0f;
+
+ state.dirty = true;
+}
+
+void GPU_matrix_ortho_set(float left, float right, float bottom, float top, float near, float far)
+{
+ mat4_ortho_set(Projection, left, right, bottom, top, near, far);
+ CHECKMAT(Projection);
+ state.dirty = true;
+}
+
+void GPU_matrix_ortho_2d_set(float left, float right, float bottom, float top)
+{
+ Mat4 m;
+ mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f);
+ CHECKMAT(Projection2D);
+ state.dirty = true;
+}
+
+void GPU_matrix_frustum_set(float left, float right, float bottom, float top, float near, float far)
+{
+ mat4_frustum_set(Projection, left, right, bottom, top, near, far);
+ CHECKMAT(Projection);
+ state.dirty = true;
+}
+
+void GPU_matrix_perspective_set(float fovy, float aspect, float near, float far)
+{
+ float half_height = tanf(fovy * (float)(M_PI / 360.0)) * near;
+ float half_width = half_height * aspect;
+ GPU_matrix_frustum_set(-half_width, +half_width, -half_height, +half_height, near, far);
+}
+
+void GPU_matrix_look_at(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
+{
+ Mat4 cm;
+ float lookdir[3];
+ float camup[3] = {upX, upY, upZ};
+
+ lookdir[0] = centerX - eyeX;
+ lookdir[1] = centerY - eyeY;
+ lookdir[2] = centerZ - eyeZ;
+
+ mat4_look_from_origin(cm, lookdir, camup);
+
+ GPU_matrix_mul(cm);
+ GPU_matrix_translate_3f(-eyeX, -eyeY, -eyeZ);
+}
+
+void GPU_matrix_project(const float world[3], const float model[4][4], const float proj[4][4], const int view[4], float win[3])
+{
+ float v[4];
+
+ mul_v4_m4v3(v, model, world);
+ mul_m4_v4(proj, v);
+
+ if (v[3] != 0.0f) {
+ mul_v3_fl(v, 1.0f / v[3]);
+ }
+
+ win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f;
+ win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f;
+ win[2] = (v[2] + 1) * 0.5f;
+}
+
+bool GPU_matrix_unproject(const float win[3], const float model[4][4], const float proj[4][4], const int view[4], float world[3])
+{
+ float pm[4][4];
+ float in[4];
+ float out[4];
+
+ mul_m4_m4m4(pm, proj, model);
+
+ if (!invert_m4(pm)) {
+ zero_v3(world);
+ return false;
+ }
+
+ in[0] = win[0];
+ in[1] = win[1];
+ in[2] = win[2];
+ in[3] = 1;
+
+ /* Map x and y from window coordinates */
+ in[0] = (in[0] - view[0]) / view[2];
+ in[1] = (in[1] - view[1]) / view[3];
+
+ /* Map to range -1 to +1 */
+ in[0] = 2 * in[0] - 1;
+ in[1] = 2 * in[1] - 1;
+ in[2] = 2 * in[2] - 1;
+
+ mul_v4_m4v3(out, pm, in);
+
+ if (out[3] == 0.0f) {
+ copy_v3_v3(world, out);
+ return false;
+ }
+
+ mul_v3_v3fl(world, out, 1.0f / out[3]);
+ return true;
+}
+
+const float (*GPU_matrix_model_view_get(float m[4][4]))[4]
+{
+ if (m) {
+ copy_m4_m4(m, ModelView);
+ return m;
+ }
+ else {
+ return ModelView;
+ }
+}
+
+const float (*GPU_matrix_projection_get(float m[4][4]))[4]
+{
+ if (m) {
+ copy_m4_m4(m, Projection);
+ return m;
+ }
+ else {
+ return Projection;
+ }
+}
+
+const float (*GPU_matrix_model_view_projection_get(float m[4][4]))[4]
+{
+ if (m == NULL) {
+ static Mat4 temp;
+ m = temp;
+ }
+
+ mul_m4_m4m4(m, Projection, ModelView);
+ return m;
+}
+
+const float (*GPU_matrix_normal_get(float m[3][3]))[3]
+{
+ if (m == NULL) {
+ static Mat3 temp3;
+ m = temp3;
+ }
+
+ copy_m3_m4(m, (const float (*)[4])GPU_matrix_model_view_get(NULL));
+
+ invert_m3(m);
+ transpose_m3(m);
+
+ return m;
+}
+
+const float (*GPU_matrix_normal_inverse_get(float m[3][3]))[3]
+{
+ if (m == NULL) {
+ static Mat3 temp3;
+ m = temp3;
+ }
+
+ GPU_matrix_normal_get(m);
+ invert_m3(m);
+
+ return m;
+}
+
+void GPU_matrix_bind(const GPUShaderInterface *shaderface)
+{
+ /* set uniform values to matrix stack values
+ * call this before a draw call if desired matrices are dirty
+ * call glUseProgram before this, as glUniform expects program to be bound
+ */
+
+ const GPUShaderInput *MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW);
+ const GPUShaderInput *P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION);
+ const GPUShaderInput *MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP);
+
+ const GPUShaderInput *N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL);
+ const GPUShaderInput *MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV);
+ const GPUShaderInput *P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV);
+
+ if (MV) {
+#if DEBUG_MATRIX_BIND
+ puts("setting MV matrix");
+#endif
+
+ glUniformMatrix4fv(MV->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_get(NULL));
+ }
+
+ if (P) {
+#if DEBUG_MATRIX_BIND
+ puts("setting P matrix");
+#endif
+
+ glUniformMatrix4fv(P->location, 1, GL_FALSE, (const float *)GPU_matrix_projection_get(NULL));
+ }
+
+ if (MVP) {
+#if DEBUG_MATRIX_BIND
+ puts("setting MVP matrix");
+#endif
+
+ glUniformMatrix4fv(MVP->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_projection_get(NULL));
+ }
+
+ if (N) {
+#if DEBUG_MATRIX_BIND
+ puts("setting normal matrix");
+#endif
+
+ glUniformMatrix3fv(N->location, 1, GL_FALSE, (const float *)GPU_matrix_normal_get(NULL));
+ }
+
+ if (MV_inv) {
+ Mat4 m;
+ GPU_matrix_model_view_get(m);
+ invert_m4(m);
+ glUniformMatrix4fv(MV_inv->location, 1, GL_FALSE, (const float *)m);
+ }
+
+ if (P_inv) {
+ Mat4 m;
+ GPU_matrix_projection_get(m);
+ invert_m4(m);
+ glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m);
+ }
+
+ state.dirty = false;
+}
+
+bool GPU_matrix_dirty_get(void)
+{
+ return state.dirty;
+}
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Python API Helpers
+ * \{ */
+BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch");
+
+/* Return int since caller is may subtract. */
+
+int GPU_matrix_stack_level_get_model_view(void)
+{
+ return (int)state.model_view_stack.top;
+}
+
+int GPU_matrix_stack_level_get_projection(void)
+{
+ return (int)state.projection_stack.top;
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_primitive.c b/source/blender/gpu/intern/gpu_primitive.c
new file mode 100644
index 00000000000..189d17f2dd2
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_primitive.c
@@ -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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_primitive.c
+ * \ingroup gpu
+ *
+ * GPU geometric primitives
+ */
+
+#include "GPU_primitive.h"
+#include "gpu_primitive_private.h"
+
+GPUPrimClass GPU_primtype_class(GPUPrimType prim_type)
+{
+ static const GPUPrimClass classes[] = {
+ [GPU_PRIM_POINTS] = GPU_PRIM_CLASS_POINT,
+ [GPU_PRIM_LINES] = GPU_PRIM_CLASS_LINE,
+ [GPU_PRIM_LINE_STRIP] = GPU_PRIM_CLASS_LINE,
+ [GPU_PRIM_LINE_LOOP] = GPU_PRIM_CLASS_LINE,
+ [GPU_PRIM_TRIS] = GPU_PRIM_CLASS_SURFACE,
+ [GPU_PRIM_TRI_STRIP] = GPU_PRIM_CLASS_SURFACE,
+ [GPU_PRIM_TRI_FAN] = GPU_PRIM_CLASS_SURFACE,
+
+ [GPU_PRIM_LINES_ADJ] = GPU_PRIM_CLASS_LINE,
+ [GPU_PRIM_LINE_STRIP_ADJ] = GPU_PRIM_CLASS_LINE,
+ [GPU_PRIM_TRIS_ADJ] = GPU_PRIM_CLASS_SURFACE,
+
+ [GPU_PRIM_NONE] = GPU_PRIM_CLASS_NONE
+ };
+
+ return classes[prim_type];
+}
+
+bool GPU_primtype_belongs_to_class(GPUPrimType prim_type, GPUPrimClass prim_class)
+{
+ if (prim_class == GPU_PRIM_CLASS_NONE && prim_type == GPU_PRIM_NONE) {
+ return true;
+ }
+ return prim_class & GPU_primtype_class(prim_type);
+}
+
+GLenum convert_prim_type_to_gl(GPUPrimType prim_type)
+{
+#if TRUST_NO_ONE
+ assert(prim_type != GPU_PRIM_NONE);
+#endif
+ static const GLenum table[] = {
+ [GPU_PRIM_POINTS] = GL_POINTS,
+ [GPU_PRIM_LINES] = GL_LINES,
+ [GPU_PRIM_LINE_STRIP] = GL_LINE_STRIP,
+ [GPU_PRIM_LINE_LOOP] = GL_LINE_LOOP,
+ [GPU_PRIM_TRIS] = GL_TRIANGLES,
+ [GPU_PRIM_TRI_STRIP] = GL_TRIANGLE_STRIP,
+ [GPU_PRIM_TRI_FAN] = GL_TRIANGLE_FAN,
+
+ [GPU_PRIM_LINES_ADJ] = GL_LINES_ADJACENCY,
+ [GPU_PRIM_LINE_STRIP_ADJ] = GL_LINE_STRIP_ADJACENCY,
+ [GPU_PRIM_TRIS_ADJ] = GL_TRIANGLES_ADJACENCY,
+ };
+
+ return table[prim_type];
+}
diff --git a/source/blender/editors/space_time/time_intern.h b/source/blender/gpu/intern/gpu_primitive_private.h
index 67e33afabb6..d057f29fdc5 100644
--- a/source/blender/editors/space_time/time_intern.h
+++ b/source/blender/gpu/intern/gpu_primitive_private.h
@@ -15,28 +15,23 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * The Original Code is Copyright (C) 2016 by Mike Erwin.
* All rights reserved.
*
- *
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/space_time/time_intern.h
- * \ingroup sptime
+/** \file blender/gpu/intern/gpu_primitive_private.h
+ * \ingroup gpu
+ *
+ * GPU geometric primitives
*/
+#ifndef __GPU_PRIMITIVE_PRIVATE_H__
+#define __GPU_PRIMITIVE_PRIVATE_H__
-#ifndef __TIME_INTERN_H__
-#define __TIME_INTERN_H__
-
-/* internal exports only */
-
-
-/* time_ops.c */
-void time_operatortypes(void);
-void time_keymap(struct wmKeyConfig *keyconf);
+GLenum convert_prim_type_to_gl(GPUPrimType);
-#endif /* __TIME_INTERN_H__ */
+#endif /* __GPU_PRIMITIVE_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index 72627e3563e..df55f7922b3 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -25,6 +25,9 @@
#ifndef __GPU_PRIVATE_H__
#define __GPU_PRIVATE_H__
+struct GPUContext;
+struct GPUFrameBuffer;
+
/* call this before running any of the functions below */
void gpu_extensions_init(void);
void gpu_extensions_exit(void);
@@ -33,4 +36,8 @@ void gpu_extensions_exit(void);
void gpu_debug_init(void);
void gpu_debug_exit(void);
+/* gpu_framebuffer.c */
+void gpu_framebuffer_module_init(void);
+void gpu_framebuffer_module_exit(void);
+
#endif /* __GPU_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 291a552a041..1c0e7ed4c1c 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -187,12 +187,7 @@ uint GPU_select_end(void)
*/
bool GPU_select_query_check_active(void)
{
- return ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) ||
- ((U.gpu_select_method == USER_SELECT_AUTO) &&
- (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) ||
- /* unsupported by nouveau, gallium 0.4, see: T47940 */
- GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))));
-
+ return ELEM(U.gpu_select_method, USER_SELECT_USE_OCCLUSION_QUERY, USER_SELECT_AUTO);
}
/* ----------------------------------------------------------------------------
@@ -232,3 +227,29 @@ bool GPU_select_is_cached(void)
{
return g_select_state.use_cache && gpu_select_pick_is_cached();
}
+
+
+/* ----------------------------------------------------------------------------
+ * Utilities
+ */
+
+/**
+ * Helper function, nothing special but avoids doing inline since hit's aren't sorted by depth
+ * and purpose of 4x buffer indices isn't so clear.
+ *
+ * Note that comparing depth as uint is fine.
+ */
+const uint *GPU_select_buffer_near(const uint *buffer, int hits)
+{
+ const uint *buffer_near = NULL;
+ uint depth_min = (uint) - 1;
+ for (int i = 0; i < hits; i++) {
+ if (buffer[1] < depth_min) {
+ BLI_assert(buffer[3] != -1);
+ depth_min = buffer[1];
+ buffer_near = buffer;
+ }
+ buffer += 4;
+ }
+ return buffer_near;
+}
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index b31a527a2ad..9b64d48fe50 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -31,6 +31,8 @@
#include <stdlib.h>
#include <float.h>
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
#include "GPU_select.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
@@ -84,7 +86,7 @@ static void rect_subregion_stride_calc(const rcti *src, const rcti *dst, SubRect
const int y = dst->ymin - src->ymin;
BLI_assert(src->xmin <= dst->xmin && src->ymin <= dst->ymin &&
- src->ymax >= dst->ymax && src->ymax >= dst->ymax);
+ src->xmax >= dst->xmax && src->ymax >= dst->ymax);
BLI_assert(x >= 0 && y >= 0);
r_sub->start = (uint)((src_x * y) + x);
@@ -316,8 +318,8 @@ void gpu_select_pick_begin(
/* Restrict OpenGL operations for when we don't have cache */
if (ps->is_cached == false) {
+ gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT);
- glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
/* disable writing to the framebuffer */
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -334,12 +336,8 @@ void gpu_select_pick_begin(
glDepthFunc(GL_LEQUAL);
}
- /* set just in case */
- glPixelTransferf(GL_DEPTH_BIAS, 0.0);
- glPixelTransferf(GL_DEPTH_SCALE, 1.0);
-
float viewport[4];
- glGetFloatv(GL_SCISSOR_BOX, viewport);
+ glGetFloatv(GL_VIEWPORT, viewport);
ps->src.clip_rect = *input;
ps->src.rect_len = rect_len;
@@ -542,7 +540,7 @@ uint gpu_select_pick_end(void)
/* force finishing last pass */
gpu_select_pick_load_id(ps->gl.prev_id);
}
- glPopAttrib();
+ gpuPopAttrib();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h
index 8935bd7b253..d6c02d5b3ea 100644
--- a/source/blender/gpu/intern/gpu_select_private.h
+++ b/source/blender/gpu/intern/gpu_select_private.h
@@ -33,9 +33,9 @@
#define __GPU_SELECT_PRIVATE_H__
/* gpu_select_pick */
-void gpu_select_pick_begin(unsigned int (*buffer)[4], unsigned int bufsize, const rcti *input, char mode);
-bool gpu_select_pick_load_id(unsigned int id);
-unsigned int gpu_select_pick_end(void);
+void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode);
+bool gpu_select_pick_load_id(uint id);
+uint gpu_select_pick_end(void);
void gpu_select_pick_cache_begin(void);
void gpu_select_pick_cache_end(void);
@@ -43,11 +43,11 @@ bool gpu_select_pick_is_cached(void);
void gpu_select_pick_cache_load_id(void);
/* gpu_select_sample_query */
-void gpu_select_query_begin(unsigned int (*buffer)[4], unsigned int bufsize, const rcti *input, char mode, int oldhits);
-bool gpu_select_query_load_id(unsigned int id);
-unsigned int gpu_select_query_end(void);
+void gpu_select_query_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits);
+bool gpu_select_query_load_id(uint id);
+uint gpu_select_query_end(void);
-#define SELECT_ID_NONE ((unsigned int)0xffffffff)
+#define SELECT_ID_NONE ((uint)0xffffffff)
#endif /* __GPU_SELECT_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c
index b934dbf7aa8..4520025ea7f 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.c
+++ b/source/blender/gpu/intern/gpu_select_sample_query.c
@@ -32,6 +32,8 @@
#include <stdlib.h>
+#include "GPU_immediate.h"
+#include "GPU_draw.h"
#include "GPU_select.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
@@ -42,6 +44,8 @@
#include "BLI_utildefines.h"
+#include "PIL_time.h"
+
#include "gpu_select_private.h"
@@ -94,15 +98,15 @@ void gpu_select_query_begin(
g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids");
glGenQueries(g_query_state.num_of_queries, g_query_state.queries);
- glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
+ gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT | GPU_SCISSOR_BIT);
/* disable writing to the framebuffer */
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* In order to save some fill rate we minimize the viewport using rect.
- * We need to get the region of the scissor so that our geometry doesn't
+ * We need to get the region of the viewport so that our geometry doesn't
* get rejected before the depth test. Should probably cull rect against
- * scissor for viewport but this is a rare case I think */
- glGetFloatv(GL_SCISSOR_BOX, viewport);
+ * the viewport but this is a rare case I think */
+ glGetFloatv(GL_VIEWPORT, viewport);
glViewport(viewport[0], viewport[1], BLI_rcti_size_x(input), BLI_rcti_size_y(input));
/* occlusion queries operates on fragments that pass tests and since we are interested on all
@@ -171,7 +175,16 @@ uint gpu_select_query_end(void)
}
for (i = 0; i < g_query_state.active_query; i++) {
- uint result;
+ uint result = 0;
+ /* Wait until the result is available. */
+ while (result == 0) {
+ glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT_AVAILABLE, &result);
+ if (result == 0) {
+ /* (fclem) Not sure if this is better than calling
+ * glGetQueryObjectuiv() indefinitely. */
+ PIL_sleep_ms(1);
+ }
+ }
glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result);
if (result > 0) {
if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
@@ -206,7 +219,7 @@ uint gpu_select_query_end(void)
glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries);
MEM_freeN(g_query_state.queries);
MEM_freeN(g_query_state.id);
- glPopAttrib();
+ gpuPopAttrib();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
return hits;
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 5e35b9279d4..d428e2f9bd9 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -25,81 +25,175 @@
* ***** END GPL LICENSE BLOCK *****
*/
+/** \file blender/gpu/intern/gpu_shader.c
+ * \ingroup gpu
+ */
+
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
#include "BKE_appdir.h"
#include "BKE_global.h"
-#include "GPU_compositing.h"
-#include "GPU_debug.h"
+#include "DNA_space_types.h"
+
#include "GPU_extensions.h"
-#include "GPU_glew.h"
+#include "GPU_context.h"
+#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
-#include "GPU_material.h"
+#include "GPU_uniformbuffer.h"
-/* TODO(sergey): Find better default values for this constants. */
-#define MAX_DEFINE_LENGTH 1024
-#define MAX_EXT_DEFINE_LENGTH 1024
+#include "gpu_shader_private.h"
+
+/* Adjust these constants as needed. */
+#define MAX_DEFINE_LENGTH 256
+#define MAX_EXT_DEFINE_LENGTH 256
/* Non-generated shaders */
-extern char datatoc_gpu_shader_fire_frag_glsl[];
-extern char datatoc_gpu_shader_smoke_vert_glsl[];
-extern char datatoc_gpu_shader_smoke_frag_glsl[];
-extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
-extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
-extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
-extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[];
-extern char datatoc_gpu_shader_fx_vert_glsl[];
-extern char datatoc_gpu_shader_fx_ssao_frag_glsl[];
-extern char datatoc_gpu_shader_fx_dof_frag_glsl[];
-extern char datatoc_gpu_shader_fx_dof_vert_glsl[];
-extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[];
-extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[];
-extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[];
-extern char datatoc_gpu_shader_fx_depth_resolve_glsl[];
-extern char datatoc_gpu_shader_fx_lib_glsl[];
-
-static struct GPUShadersGlobal {
- struct {
- GPUShader *vsm_store;
- GPUShader *sep_gaussian_blur;
- GPUShader *smoke;
- GPUShader *smoke_fire;
- GPUShader *smoke_coba;
- /* cache for shader fx. Those can exist in combinations so store them here */
- GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
- } shaders;
-} GG = {{NULL}};
-
-/* GPUShader */
-
-struct GPUShader {
- GLuint program; /* handle for full program (links shader stages below) */
-
- GLuint vertex; /* handle for vertex shader */
- GLuint geometry; /* handle for geometry shader */
- GLuint fragment; /* handle for fragment shader */
-
- int totattrib; /* total number of attributes */
- int uniforms; /* required uniforms */
-
- void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */
-};
+extern char datatoc_gpu_shader_depth_only_frag_glsl[];
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_checker_frag_glsl[];
+extern char datatoc_gpu_shader_diag_stripes_frag_glsl[];
+extern char datatoc_gpu_shader_simple_lighting_frag_glsl[];
+extern char datatoc_gpu_shader_simple_lighting_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl[];
+extern char datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl[];
+extern char datatoc_gpu_shader_flat_id_frag_glsl[];
+extern char datatoc_gpu_shader_2D_area_borders_vert_glsl[];
+extern char datatoc_gpu_shader_2D_vert_glsl[];
+extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[];
+extern char datatoc_gpu_shader_2D_smooth_color_uniform_alpha_vert_glsl[];
+extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[];
+extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[];
+extern char datatoc_gpu_shader_2D_smooth_color_dithered_frag_glsl[];
+extern char datatoc_gpu_shader_2D_image_vert_glsl[];
+extern char datatoc_gpu_shader_2D_image_rect_vert_glsl[];
+extern char datatoc_gpu_shader_2D_image_multi_rect_vert_glsl[];
+extern char datatoc_gpu_shader_2D_widget_base_vert_glsl[];
+extern char datatoc_gpu_shader_2D_widget_base_frag_glsl[];
+extern char datatoc_gpu_shader_2D_widget_shadow_vert_glsl[];
+extern char datatoc_gpu_shader_2D_widget_shadow_frag_glsl[];
+extern char datatoc_gpu_shader_2D_nodelink_frag_glsl[];
+extern char datatoc_gpu_shader_2D_nodelink_vert_glsl[];
+
+extern char datatoc_gpu_shader_3D_image_vert_glsl[];
+extern char datatoc_gpu_shader_image_frag_glsl[];
+extern char datatoc_gpu_shader_image_linear_frag_glsl[];
+extern char datatoc_gpu_shader_image_color_frag_glsl[];
+extern char datatoc_gpu_shader_image_desaturate_frag_glsl[];
+extern char datatoc_gpu_shader_image_varying_color_frag_glsl[];
+extern char datatoc_gpu_shader_image_alpha_color_frag_glsl[];
+extern char datatoc_gpu_shader_image_shuffle_color_frag_glsl[];
+extern char datatoc_gpu_shader_image_interlace_frag_glsl[];
+extern char datatoc_gpu_shader_image_mask_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[];
+extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[];
+extern char datatoc_gpu_shader_image_depth_copy_frag_glsl[];
+extern char datatoc_gpu_shader_image_multisample_resolve_frag_glsl[];
+extern char datatoc_gpu_shader_3D_vert_glsl[];
+extern char datatoc_gpu_shader_3D_normal_vert_glsl[];
+extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[];
+extern char datatoc_gpu_shader_3D_normal_flat_color_vert_glsl[];
+extern char datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl[];
+extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+extern char datatoc_gpu_shader_3D_passthrough_vert_glsl[];
+extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[];
+
+extern char datatoc_gpu_shader_instance_vert_glsl[];
+extern char datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl[];
+extern char datatoc_gpu_shader_instance_variying_size_variying_id_vert_glsl[];
+extern char datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl[];
+extern char datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl[];
+extern char datatoc_gpu_shader_instance_screen_aligned_vert_glsl[];
+extern char datatoc_gpu_shader_instance_camera_vert_glsl[];
+extern char datatoc_gpu_shader_instance_distance_line_vert_glsl[];
+extern char datatoc_gpu_shader_instance_edges_variying_color_geom_glsl[];
+extern char datatoc_gpu_shader_instance_edges_variying_color_vert_glsl[];
+extern char datatoc_gpu_shader_instance_mball_handles_vert_glsl[];
+
+extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[];
+extern char datatoc_gpu_shader_3D_groundline_geom_glsl[];
+
+extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_point_uniform_color_aa_frag_glsl[];
+extern char datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[];
+extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
+extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[];
+extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[];
+extern char datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl[];
+extern char datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl[];
+extern char datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl[];
+extern char datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl[];
+extern char datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl[];
+extern char datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl[];
+extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl[];
+
+extern char datatoc_gpu_shader_2D_edituvs_points_vert_glsl[];
+extern char datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl[];
+extern char datatoc_gpu_shader_2D_edituvs_edges_vert_glsl[];
+extern char datatoc_gpu_shader_2D_edituvs_faces_vert_glsl[];
+extern char datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl[];
+
+extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[];
+extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[];
+extern char datatoc_gpu_shader_2D_line_dashed_geom_glsl[];
+extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_legacy_vert_glsl[];
+extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl[];
+
+extern char datatoc_gpu_shader_edges_front_back_persp_vert_glsl[];
+extern char datatoc_gpu_shader_edges_front_back_persp_geom_glsl[];
+extern char datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl[];
+extern char datatoc_gpu_shader_edges_front_back_ortho_vert_glsl[];
+extern char datatoc_gpu_shader_edges_overlay_vert_glsl[];
+extern char datatoc_gpu_shader_edges_overlay_geom_glsl[];
+extern char datatoc_gpu_shader_edges_overlay_simple_geom_glsl[];
+extern char datatoc_gpu_shader_edges_overlay_frag_glsl[];
+extern char datatoc_gpu_shader_text_vert_glsl[];
+extern char datatoc_gpu_shader_text_geom_glsl[];
+extern char datatoc_gpu_shader_text_frag_glsl[];
+extern char datatoc_gpu_shader_text_simple_vert_glsl[];
+extern char datatoc_gpu_shader_text_simple_geom_glsl[];
+extern char datatoc_gpu_shader_keyframe_diamond_vert_glsl[];
+extern char datatoc_gpu_shader_keyframe_diamond_frag_glsl[];
+
+extern char datatoc_gpu_shader_gpencil_stroke_vert_glsl[];
+extern char datatoc_gpu_shader_gpencil_stroke_frag_glsl[];
+extern char datatoc_gpu_shader_gpencil_stroke_geom_glsl[];
+
+extern char datatoc_gpu_shader_gpencil_fill_vert_glsl[];
+extern char datatoc_gpu_shader_gpencil_fill_frag_glsl[];
+
+/* cache of built-in shaders (each is created on first use) */
+static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL };
+
+#ifndef NDEBUG
+static uint g_shaderid = 0;
+#endif
+
+typedef struct {
+ const char *vert;
+ const char *frag;
+ const char *geom; /* geometry stage runs between vert & frag, but is less common, so it goes last */
+} GPUShaderStages;
static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
{
- int i;
int line = 1;
fprintf(stderr, "GPUShader: %s error:\n", task);
- for (i = 0; i < totcode; i++) {
+ for (int i = 0; i < totcode; i++) {
const char *c, *pos, *end = code[i] + strlen(code[i]);
if (G.debug & G_DEBUG) {
@@ -122,143 +216,70 @@ static void shader_print_errors(const char *task, const char *log, const char **
static const char *gpu_shader_version(void)
{
- if (GLEW_VERSION_3_2) {
- if (GLEW_ARB_compatibility) {
- return "#version 150 compatibility\n";
- /* highest version that is widely supported
- * gives us native geometry shaders!
- * use compatibility profile so we can continue using builtin shader input/output names
- */
- }
- else {
- return "#version 130\n";
- /* latest version that is compatible with existing shaders */
- }
- }
- else if (GLEW_VERSION_3_1) {
- if (GLEW_ARB_compatibility) {
- return "#version 140\n";
- /* also need the ARB_compatibility extension, handled below */
- }
- else {
- return "#version 130\n";
- /* latest version that is compatible with existing shaders */
- }
- }
- else if (GLEW_VERSION_3_0) {
- return "#version 130\n";
- /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available
- * older features are deprecated but still available without compatibility extension or profile
- */
- }
- else {
- return "#version 120\n";
- /* minimum supported */
- }
+ return "#version 330\n";
}
-
-static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_geometry_shader)
+static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH])
{
/* enable extensions for features that are not part of our base GLSL version
* don't use an extension for something already available!
*/
+ if (GLEW_ARB_texture_gather) {
+ /* There is a bug on older Nvidia GPU where GL_ARB_texture_gather
+ * is reported to be supported but yield a compile error (see T55802). */
+ if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) || GLEW_VERSION_4_0) {
+ strcat(defines, "#extension GL_ARB_texture_gather: enable\n");
+
+ /* Some drivers don't agree on GLEW_ARB_texture_gather and the actual support in the
+ * shader so double check the preprocessor define (see T56544). */
+ if (!GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY) && !GLEW_VERSION_4_0) {
+ strcat(defines, "#ifdef GL_ARB_texture_gather\n");
+ strcat(defines, "# define GPU_ARB_texture_gather\n");
+ strcat(defines, "#endif\n");
+ }
+ else {
+ strcat(defines, "#define GPU_ARB_texture_gather\n");
+ }
+ }
+ }
if (GLEW_ARB_texture_query_lod) {
- /* a #version 400 feature, but we use #version 150 maximum so use extension */
+ /* a #version 400 feature, but we use #version 330 maximum so use extension */
strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
}
-
- if (use_geometry_shader && GPU_geometry_shader_support_via_extension()) {
- strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n");
- }
-
- if (GLEW_VERSION_3_1 && !GLEW_VERSION_3_2 && GLEW_ARB_compatibility) {
- strcat(defines, "#extension GL_ARB_compatibility: enable\n");
- }
-
- if (!GLEW_VERSION_3_1) {
- if (GLEW_ARB_draw_instanced) {
- strcat(defines, "#extension GL_ARB_draw_instanced: enable\n");
- }
-
- if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) {
- strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n");
- /* TODO: maybe require this? shaders become so much nicer */
- }
- }
}
-static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH],
- bool use_opensubdiv,
- bool use_new_shading)
+static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
{
/* some useful defines to detect GPU type */
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY))
strcat(defines, "#define GPU_ATI\n");
- if (GLEW_VERSION_3_0) {
- /* TODO(merwin): revisit this version check; GLEW_VERSION_3_0 means GL 3.0 or newer */
- strcat(defines, "#define CLIP_WORKAROUND\n");
- }
- }
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY))
strcat(defines, "#define GPU_NVIDIA\n");
else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY))
strcat(defines, "#define GPU_INTEL\n");
- if (GPU_bicubic_bump_support())
- strcat(defines, "#define BUMP_BICUBIC\n");
-
- if (GLEW_VERSION_3_0) {
- strcat(defines, "#define BIT_OPERATIONS\n");
- }
-
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): Check whether we actually compiling shader for
- * the OpenSubdiv mesh.
- */
- if (use_opensubdiv) {
- strcat(defines, "#define USE_OPENSUBDIV\n");
-
- /* TODO(sergey): not strictly speaking a define, but this is
- * a global typedef which we don't have better place to define
- * in yet.
- */
- strcat(defines, "struct VertexData {\n"
- " vec4 position;\n"
- " vec3 normal;\n"
- " vec2 uv;"
- "};\n");
- }
-#else
- UNUSED_VARS(use_opensubdiv);
-#endif
-
- if (use_new_shading) {
- strcat(defines, "#define USE_NEW_SHADING\n");
- }
-
return;
}
-GPUShader *GPU_shader_create(const char *vertexcode,
- const char *fragcode,
- const char *geocode,
- const char *libcode,
- const char *defines,
- int input,
- int output,
- int number)
+GPUShader *GPU_shader_create(
+ const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines,
+ const char *shname)
{
- return GPU_shader_create_ex(vertexcode,
- fragcode,
- geocode,
- libcode,
- defines,
- input,
- output,
- number,
- GPU_SHADER_FLAGS_NONE);
+ return GPU_shader_create_ex(
+ vertexcode,
+ fragcode,
+ geocode,
+ libcode,
+ defines,
+ GPU_SHADER_TFB_NONE,
+ NULL,
+ 0,
+ shname);
}
#define DEBUG_SHADER_NONE ""
@@ -308,26 +329,17 @@ static void gpu_dump_shaders(const char **code, const int num_shaders, const cha
printf("Shader file written to disk: %s\n", shader_path);
}
-GPUShader *GPU_shader_create_ex(const char *vertexcode,
- const char *fragcode,
- const char *geocode,
- const char *libcode,
- const char *defines,
- int input,
- int output,
- int number,
- const int flags)
+GPUShader *GPU_shader_create_ex(
+ const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines,
+ const GPUShaderTFBType tf_type,
+ const char **tf_names,
+ const int tf_count,
+ const char *shname)
{
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): used to add #version 150 to the geometry shader.
- * Could safely be renamed to "use_geometry_code" since it's very
- * likely any of geometry code will want to use GLSL 1.5.
- */
- bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0;
-#else
- UNUSED_VARS(flags);
- bool use_opensubdiv = false;
-#endif
GLint status;
GLchar log[5000];
GLsizei length = 0;
@@ -335,12 +347,15 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
char standard_defines[MAX_DEFINE_LENGTH] = "";
char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
- if (geocode && !GPU_geometry_shader_support())
- return NULL;
-
shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE);
+#ifndef NDEBUG
+ BLI_snprintf(shader->name, sizeof(shader->name), "%s_%u", shname, g_shaderid++);
+#else
+ UNUSED_VARS(shname);
+#endif
+
if (vertexcode)
shader->vertex = glCreateShader(GL_VERTEX_SHADER);
if (fragcode)
@@ -360,10 +375,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
return NULL;
}
- gpu_shader_standard_defines(standard_defines,
- use_opensubdiv,
- (flags & GPU_SHADER_FLAGS_NEW_SHADING) != 0);
- gpu_shader_standard_extensions(standard_extensions, geocode != NULL);
+ gpu_shader_standard_defines(standard_defines);
+ gpu_shader_standard_extensions(standard_extensions);
if (vertexcode) {
const char *source[5];
@@ -402,18 +415,6 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
source[num_source++] = standard_extensions;
source[num_source++] = standard_defines;
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): Move to fragment shader source code generation. */
- if (use_opensubdiv) {
- source[num_source++] =
- "#ifdef USE_OPENSUBDIV\n"
- "in block {\n"
- " VertexData v;\n"
- "} inpt;\n"
- "#endif\n";
- }
-#endif
-
if (defines) source[num_source++] = defines;
if (libcode) source[num_source++] = libcode;
source[num_source++] = fragcode;
@@ -461,22 +462,14 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
GPU_shader_free(shader);
return NULL;
}
-
- if (!use_opensubdiv) {
- GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
- }
}
-#ifdef WITH_OPENSUBDIV
- if (use_opensubdiv) {
- glBindAttribLocation(shader->program, 0, "position");
- glBindAttribLocation(shader->program, 1, "normal");
- GPU_shader_geometry_stage_primitive_io(shader,
- GL_LINES_ADJACENCY_EXT,
- GL_TRIANGLE_STRIP,
- 4);
+ if (tf_names != NULL) {
+ glTransformFeedbackVaryings(shader->program, tf_count, tf_names, GL_INTERLEAVED_ATTRIBS);
+ /* Primitive type must be setup */
+ BLI_assert(tf_type != GPU_SHADER_TFB_NONE);
+ shader->feedback_transform_type = tf_type;
}
-#endif
glLinkProgram(shader->program);
glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
@@ -492,18 +485,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
return NULL;
}
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): Find a better place for this. */
- if (use_opensubdiv && GLEW_VERSION_4_1) {
- glProgramUniform1i(shader->program,
- glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"),
- 30); /* GL_TEXTURE30 */
-
- glProgramUniform1i(shader->program,
- glGetUniformLocation(shader->program, "FVarDataBuffer"),
- 31); /* GL_TEXTURE31 */
- }
-#endif
+ shader->interface = GPU_shaderinterface_create(shader->program);
return shader;
}
@@ -515,20 +497,46 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
void GPU_shader_bind(GPUShader *shader)
{
- GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind");
+ BLI_assert(shader && shader->program);
+
glUseProgram(shader->program);
- GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind");
+ GPU_matrix_bind(shader->interface);
}
void GPU_shader_unbind(void)
{
- GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind");
glUseProgram(0);
- GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind");
+}
+
+bool GPU_shader_transform_feedback_enable(GPUShader *shader, uint vbo_id)
+{
+ if (shader->feedback_transform_type == GPU_SHADER_TFB_NONE) {
+ return false;
+ }
+
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo_id);
+
+ switch (shader->feedback_transform_type) {
+ case GPU_SHADER_TFB_POINTS: glBeginTransformFeedback(GL_POINTS); return true;
+ case GPU_SHADER_TFB_LINES: glBeginTransformFeedback(GL_LINES); return true;
+ case GPU_SHADER_TFB_TRIANGLES: glBeginTransformFeedback(GL_TRIANGLES); return true;
+ default: return false;
+ }
+}
+
+void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader))
+{
+ glEndTransformFeedback();
}
void GPU_shader_free(GPUShader *shader)
{
+#if 0 /* Would be nice to have, but for now the Deferred compilation
+ * does not have a GPUContext. */
+ BLI_assert(GPU_context_active_get() != NULL);
+#endif
+ BLI_assert(shader);
+
if (shader->vertex)
glDeleteShader(shader->vertex);
if (shader->geometry)
@@ -538,25 +546,51 @@ void GPU_shader_free(GPUShader *shader)
if (shader->program)
glDeleteProgram(shader->program);
- if (shader->uniform_interface)
- MEM_freeN(shader->uniform_interface);
+ if (shader->interface)
+ GPU_shaderinterface_discard(shader->interface);
MEM_freeN(shader);
}
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
{
- return glGetUniformLocation(shader->program, name);
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name);
+ return uniform ? uniform->location : -1;
+}
+
+int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
+{
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(shader->interface, builtin);
+ return uniform ? uniform->location : -1;
+}
+
+int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+
+ const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
+ return ubo ? ubo->location : -1;
}
void *GPU_shader_get_interface(GPUShader *shader)
{
- return shader->uniform_interface;
+ return shader->interface;
+}
+
+/* Clement : Temp */
+int GPU_shader_get_program(GPUShader *shader)
+{
+ return (int)shader->program;
}
-void GPU_shader_set_interface(GPUShader *shader, void *interface)
+void GPU_shader_uniform_float(GPUShader *UNUSED(shader), int location, float value)
{
- shader->uniform_interface = interface;
+ if (location == -1)
+ return;
+
+ glUniform1f(location, value);
}
void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value)
@@ -564,16 +598,12 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng
if (location == -1 || value == NULL)
return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
-
if (length == 1) glUniform1fv(location, arraysize, value);
else if (length == 2) glUniform2fv(location, arraysize, value);
else if (length == 3) glUniform3fv(location, arraysize, value);
else if (length == 4) glUniform4fv(location, arraysize, value);
else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value);
else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value);
-
- GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
}
void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
@@ -581,14 +611,10 @@ void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int
if (location == -1)
return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
-
if (length == 1) glUniform1iv(location, arraysize, value);
else if (length == 2) glUniform2iv(location, arraysize, value);
else if (length == 3) glUniform3iv(location, arraysize, value);
else if (length == 4) glUniform4iv(location, arraysize, value);
-
- GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
}
void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
@@ -596,223 +622,447 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
if (location == -1)
return;
- GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value));
+ glUniform1i(location, value);
}
-void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number)
+void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer *ubo)
{
- if (GPU_geometry_shader_support_via_extension()) {
- /* geometry shaders must provide this info themselves for #version 150 and up */
- glProgramParameteriEXT(shader->program, GL_GEOMETRY_INPUT_TYPE_EXT, input);
- glProgramParameteriEXT(shader->program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
- glProgramParameteriEXT(shader->program, GL_GEOMETRY_VERTICES_OUT_EXT, number);
+ int bindpoint = GPU_uniformbuffer_bindpoint(ubo);
+
+ if (location == -1) {
+ return;
}
+
+ glUniformBlockBinding(shader->program, location, bindpoint);
}
void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
{
- GLenum arbnumber;
int number = GPU_texture_bound_number(tex);
- int bindcode = GPU_texture_opengl_bindcode(tex);
- int target = GPU_texture_target(tex);
- if (number >= GPU_max_textures()) {
- fprintf(stderr, "Not enough texture slots.\n");
+ if (number == -1) {
+ fprintf(stderr, "Texture is not bound.\n");
+ BLI_assert(0);
return;
}
- if (number == -1)
- return;
-
if (location == -1)
return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture");
-
- arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
-
- if (number != 0) glActiveTexture(arbnumber);
- if (bindcode != 0)
- glBindTexture(target, bindcode);
- else
- GPU_invalid_tex_bind(target);
glUniform1i(location, number);
- glEnable(target);
- if (number != 0) glActiveTexture(GL_TEXTURE0);
-
- GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture");
}
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
{
- int index;
-
- GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name));
-
- return index;
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *attrib = GPU_shaderinterface_attr(shader->interface, name);
+ return attrib ? attrib->location : -1;
}
-GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
-{
- GPUShader *retval = NULL;
+static const GPUShaderStages builtin_shader_stages[GPU_NUM_BUILTIN_SHADERS] = {
+ [GPU_SHADER_TEXT] =
+ { datatoc_gpu_shader_text_vert_glsl,
+ datatoc_gpu_shader_text_frag_glsl,
+ datatoc_gpu_shader_text_geom_glsl },
+ [GPU_SHADER_TEXT_SIMPLE] =
+ { datatoc_gpu_shader_text_simple_vert_glsl,
+ datatoc_gpu_shader_text_frag_glsl,
+ datatoc_gpu_shader_text_simple_geom_glsl },
+ [GPU_SHADER_KEYFRAME_DIAMOND] =
+ { datatoc_gpu_shader_keyframe_diamond_vert_glsl,
+ datatoc_gpu_shader_keyframe_diamond_frag_glsl },
+ [GPU_SHADER_EDGES_FRONT_BACK_PERSP] =
+ { datatoc_gpu_shader_edges_front_back_persp_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl, /* this version is */
+ datatoc_gpu_shader_edges_front_back_persp_geom_glsl }, /* magical but slooow */
+ [GPU_SHADER_EDGES_FRONT_BACK_ORTHO] =
+ { datatoc_gpu_shader_edges_front_back_ortho_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ [GPU_SHADER_EDGES_OVERLAY_SIMPLE] =
+ { datatoc_gpu_shader_3D_vert_glsl,
+ datatoc_gpu_shader_edges_overlay_frag_glsl,
+ datatoc_gpu_shader_edges_overlay_simple_geom_glsl },
+ [GPU_SHADER_EDGES_OVERLAY] =
+ { datatoc_gpu_shader_edges_overlay_vert_glsl,
+ datatoc_gpu_shader_edges_overlay_frag_glsl,
+ datatoc_gpu_shader_edges_overlay_geom_glsl },
+ [GPU_SHADER_SIMPLE_LIGHTING] =
+ { datatoc_gpu_shader_3D_normal_vert_glsl,
+ datatoc_gpu_shader_simple_lighting_frag_glsl },
+ /* Use 'USE_FLAT_NORMAL' to make flat shader from smooth */
+ [GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR] =
+ { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl,
+ datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl },
+ [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR] =
+ { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl,
+ datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl },
+ [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA] =
+ { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl,
+ datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl },
+
+ [GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_3D_image_vert_glsl,
+ datatoc_gpu_shader_image_mask_uniform_color_frag_glsl },
+ [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] =
+ { datatoc_gpu_shader_3D_image_vert_glsl,
+ datatoc_gpu_shader_image_modulate_alpha_frag_glsl },
+ [GPU_SHADER_3D_IMAGE_DEPTH] =
+ { datatoc_gpu_shader_3D_image_vert_glsl,
+ datatoc_gpu_shader_image_depth_linear_frag_glsl },
+ [GPU_SHADER_3D_IMAGE_DEPTH_COPY] =
+ { datatoc_gpu_shader_3D_image_vert_glsl,
+ datatoc_gpu_shader_image_depth_copy_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTISAMPLE_2] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_image_multisample_resolve_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_image_multisample_resolve_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_image_multisample_resolve_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_image_multisample_resolve_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_image_multisample_resolve_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_image_multisample_resolve_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_image_multisample_resolve_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_image_multisample_resolve_frag_glsl },
+
+ [GPU_SHADER_2D_IMAGE_INTERLACE] =
+ { datatoc_gpu_shader_2D_image_vert_glsl,
+ datatoc_gpu_shader_image_interlace_frag_glsl },
+ [GPU_SHADER_2D_CHECKER] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_checker_frag_glsl },
+
+ [GPU_SHADER_2D_DIAG_STRIPES] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_diag_stripes_frag_glsl },
+
+ [GPU_SHADER_2D_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl },
+ [GPU_SHADER_2D_FLAT_COLOR] =
+ { datatoc_gpu_shader_2D_flat_color_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ [GPU_SHADER_2D_SMOOTH_COLOR] =
+ { datatoc_gpu_shader_2D_smooth_color_vert_glsl,
+ datatoc_gpu_shader_2D_smooth_color_frag_glsl },
+ [GPU_SHADER_2D_SMOOTH_COLOR_DITHER] =
+ { datatoc_gpu_shader_2D_smooth_color_vert_glsl,
+ datatoc_gpu_shader_2D_smooth_color_dithered_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB] =
+ { datatoc_gpu_shader_2D_image_vert_glsl,
+ datatoc_gpu_shader_image_linear_frag_glsl },
+ [GPU_SHADER_2D_IMAGE] =
+ { datatoc_gpu_shader_2D_image_vert_glsl,
+ datatoc_gpu_shader_image_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_COLOR] =
+ { datatoc_gpu_shader_2D_image_vert_glsl,
+ datatoc_gpu_shader_image_color_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] =
+ { datatoc_gpu_shader_2D_image_vert_glsl,
+ datatoc_gpu_shader_image_desaturate_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_ALPHA_COLOR] =
+ { datatoc_gpu_shader_2D_image_vert_glsl,
+ datatoc_gpu_shader_image_alpha_color_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR] =
+ { datatoc_gpu_shader_2D_image_vert_glsl,
+ datatoc_gpu_shader_image_shuffle_color_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_RECT_COLOR] =
+ { datatoc_gpu_shader_2D_image_rect_vert_glsl,
+ datatoc_gpu_shader_image_color_frag_glsl },
+ [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] =
+ { datatoc_gpu_shader_2D_image_multi_rect_vert_glsl,
+ datatoc_gpu_shader_image_varying_color_frag_glsl },
+
+ [GPU_SHADER_3D_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_3D_vert_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl },
+ [GPU_SHADER_3D_UNIFORM_COLOR_U32] =
+ { datatoc_gpu_shader_3D_vert_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl },
+ [GPU_SHADER_3D_FLAT_COLOR] =
+ { datatoc_gpu_shader_3D_flat_color_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ [GPU_SHADER_3D_FLAT_COLOR_U32] =
+ { datatoc_gpu_shader_3D_flat_color_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ [GPU_SHADER_3D_SMOOTH_COLOR] =
+ { datatoc_gpu_shader_3D_smooth_color_vert_glsl,
+ datatoc_gpu_shader_3D_smooth_color_frag_glsl },
+ [GPU_SHADER_3D_DEPTH_ONLY] =
+ { datatoc_gpu_shader_3D_vert_glsl,
+ datatoc_gpu_shader_depth_only_frag_glsl },
+ [GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl },
+
+ [GPU_SHADER_3D_GROUNDPOINT] =
+ { datatoc_gpu_shader_3D_groundpoint_vert_glsl,
+ datatoc_gpu_shader_point_uniform_color_frag_glsl },
+ [GPU_SHADER_3D_GROUNDLINE] =
+ { datatoc_gpu_shader_3D_passthrough_vert_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl,
+ datatoc_gpu_shader_3D_groundline_geom_glsl },
+
+ [GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl,
+ datatoc_gpu_shader_2D_line_dashed_frag_glsl,
+ datatoc_gpu_shader_2D_line_dashed_geom_glsl },
+ [GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl,
+ datatoc_gpu_shader_2D_line_dashed_frag_glsl,
+ datatoc_gpu_shader_2D_line_dashed_geom_glsl },
+
+ [GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR] =
+ { datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl,
+ datatoc_gpu_shader_simple_lighting_frag_glsl},
+ [GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR] =
+ { datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl},
+ [GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR] =
+ { datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl},
+ [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS] =
+ { datatoc_gpu_shader_instance_screen_aligned_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl},
+ [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED] =
+ { datatoc_gpu_shader_instance_screen_aligned_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl},
+
+ [GPU_SHADER_CAMERA] =
+ { datatoc_gpu_shader_instance_camera_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl},
+ [GPU_SHADER_DISTANCE_LINES] =
+ { datatoc_gpu_shader_instance_distance_line_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl},
+
+ [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_2D_vert_glsl,
+ datatoc_gpu_shader_point_uniform_color_frag_glsl },
+ [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] =
+ { datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl,
+ datatoc_gpu_shader_point_varying_color_frag_glsl },
+ [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] =
+ { datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl,
+ datatoc_gpu_shader_point_uniform_color_aa_frag_glsl },
+ [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] =
+ { datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl,
+ datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl },
+ [GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA] =
+ { datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl,
+ datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl },
+ [GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_3D_vert_glsl,
+ datatoc_gpu_shader_point_uniform_color_frag_glsl },
+ [GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] =
+ { datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl,
+ datatoc_gpu_shader_point_varying_color_frag_glsl },
+ [GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_3D_point_varying_size_vert_glsl,
+ datatoc_gpu_shader_point_uniform_color_frag_glsl },
+ [GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] =
+ { datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl,
+ datatoc_gpu_shader_point_varying_color_frag_glsl },
+ [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] =
+ { datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl,
+ datatoc_gpu_shader_point_uniform_color_aa_frag_glsl },
+ [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] =
+ { datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl,
+ datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl },
+
+ [GPU_SHADER_INSTANCE_UNIFORM_COLOR] =
+ { datatoc_gpu_shader_instance_vert_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl },
+ [GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE] =
+ { datatoc_gpu_shader_instance_variying_size_variying_id_vert_glsl,
+ datatoc_gpu_shader_flat_id_frag_glsl },
+ [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] =
+ { datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE] =
+ { datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ [GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR] =
+ { datatoc_gpu_shader_instance_edges_variying_color_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ datatoc_gpu_shader_instance_edges_variying_color_geom_glsl},
+
+ [GPU_SHADER_2D_AREA_EDGES] =
+ { datatoc_gpu_shader_2D_area_borders_vert_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl},
+ [GPU_SHADER_2D_WIDGET_BASE] =
+ { datatoc_gpu_shader_2D_widget_base_vert_glsl,
+ datatoc_gpu_shader_2D_widget_base_frag_glsl},
+ [GPU_SHADER_2D_WIDGET_BASE_INST] =
+ { datatoc_gpu_shader_2D_widget_base_vert_glsl,
+ datatoc_gpu_shader_2D_widget_base_frag_glsl},
+ [GPU_SHADER_2D_WIDGET_SHADOW] =
+ { datatoc_gpu_shader_2D_widget_shadow_vert_glsl,
+ datatoc_gpu_shader_2D_widget_shadow_frag_glsl },
+ [GPU_SHADER_2D_NODELINK] =
+ { datatoc_gpu_shader_2D_nodelink_vert_glsl,
+ datatoc_gpu_shader_2D_nodelink_frag_glsl },
+ [GPU_SHADER_2D_NODELINK_INST] =
+ { datatoc_gpu_shader_2D_nodelink_vert_glsl,
+ datatoc_gpu_shader_2D_nodelink_frag_glsl },
+
+ [GPU_SHADER_2D_UV_VERTS] =
+ { datatoc_gpu_shader_2D_edituvs_points_vert_glsl,
+ datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl },
+ [GPU_SHADER_2D_UV_FACEDOTS] =
+ { datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl,
+ datatoc_gpu_shader_point_varying_color_frag_glsl },
+ [GPU_SHADER_2D_UV_EDGES] =
+ { datatoc_gpu_shader_2D_edituvs_edges_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ [GPU_SHADER_2D_UV_EDGES_SMOOTH] =
+ { datatoc_gpu_shader_2D_edituvs_edges_vert_glsl,
+ datatoc_gpu_shader_2D_smooth_color_frag_glsl },
+ [GPU_SHADER_2D_UV_FACES] =
+ { datatoc_gpu_shader_2D_edituvs_faces_vert_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl },
+ [GPU_SHADER_2D_UV_FACES_STRETCH] =
+ { datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl,
+ datatoc_gpu_shader_2D_smooth_color_frag_glsl },
+
+ [GPU_SHADER_GPENCIL_STROKE] =
+ { datatoc_gpu_shader_gpencil_stroke_vert_glsl,
+ datatoc_gpu_shader_gpencil_stroke_frag_glsl,
+ datatoc_gpu_shader_gpencil_stroke_geom_glsl },
+
+ [GPU_SHADER_GPENCIL_FILL] =
+ { datatoc_gpu_shader_gpencil_fill_vert_glsl,
+ datatoc_gpu_shader_gpencil_fill_frag_glsl },
+};
+/* just a few special cases */
+static const char *gpu_shader_get_builtin_shader_defines(
+ GPUBuiltinShader shader)
+{
switch (shader) {
- case GPU_SHADER_VSM_STORE:
- if (!GG.shaders.vsm_store)
- GG.shaders.vsm_store = GPU_shader_create(
- datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl,
- NULL, NULL, NULL, 0, 0, 0);
- retval = GG.shaders.vsm_store;
- break;
- case GPU_SHADER_SEP_GAUSSIAN_BLUR:
- if (!GG.shaders.sep_gaussian_blur)
- GG.shaders.sep_gaussian_blur = GPU_shader_create(
- datatoc_gpu_shader_sep_gaussian_blur_vert_glsl,
- datatoc_gpu_shader_sep_gaussian_blur_frag_glsl,
- NULL, NULL, NULL, 0, 0, 0);
- retval = GG.shaders.sep_gaussian_blur;
- break;
- case GPU_SHADER_SMOKE:
- if (!GG.shaders.smoke)
- GG.shaders.smoke = GPU_shader_create(
- datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
- NULL, NULL, NULL, 0, 0, 0);
- retval = GG.shaders.smoke;
- break;
- case GPU_SHADER_SMOKE_FIRE:
- if (!GG.shaders.smoke_fire)
- GG.shaders.smoke_fire = GPU_shader_create(
- datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl,
- NULL, NULL, NULL, 0, 0, 0);
- retval = GG.shaders.smoke_fire;
- break;
- case GPU_SHADER_SMOKE_COBA:
- if (!GG.shaders.smoke_coba)
- GG.shaders.smoke_coba = GPU_shader_create(
- datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
- NULL, NULL, "#define USE_COBA;\n", 0, 0, 0);
- retval = GG.shaders.smoke_coba;
- break;
- }
+ case GPU_SHADER_2D_IMAGE_MULTISAMPLE_2:
+ return "#define SAMPLES 2\n";
- if (retval == NULL)
- printf("Unable to create a GPUShader for builtin shader: %u\n", shader);
+ case GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST:
+ return "#define SAMPLES 2\n"
+ "#define USE_DEPTH\n";
- return retval;
-}
+ case GPU_SHADER_2D_IMAGE_MULTISAMPLE_4:
+ return "#define SAMPLES 4\n";
-#define MAX_DEFINES 100
+ case GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST:
+ return "#define SAMPLES 4\n"
+ "#define USE_DEPTH\n";
-GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp)
-{
- int offset;
- char defines[MAX_DEFINES] = "";
- /* avoid shaders out of range */
- if (effect >= MAX_FX_SHADERS)
- return NULL;
+ case GPU_SHADER_2D_IMAGE_MULTISAMPLE_8:
+ return "#define SAMPLES 8\n";
- offset = 2 * effect;
+ case GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST:
+ return "#define SAMPLES 8\n"
+ "#define USE_DEPTH\n";
- if (persp) {
- offset += 1;
- strcat(defines, "#define PERSP_MATRIX\n");
- }
+ case GPU_SHADER_2D_IMAGE_MULTISAMPLE_16:
+ return "#define SAMPLES 16\n";
- if (!GG.shaders.fx_shaders[offset]) {
- GPUShader *shader = NULL;
-
- switch (effect) {
- case GPU_SHADER_FX_SSAO:
- shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE:
- strcat(defines, "#define FIRST_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
- strcat(defines, "#define SECOND_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
- strcat(defines, "#define THIRD_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
- strcat(defines, "#define FOURTH_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
- strcat(defines, "#define FIFTH_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE:
- strcat(defines, "#define FIRST_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO:
- strcat(defines, "#define SECOND_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl,
- defines, GL_POINTS, GL_TRIANGLE_STRIP, 4);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE:
- strcat(defines, "#define THIRD_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_RESOLVE:
- shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0);
- break;
- }
+ case GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST:
+ return "#define SAMPLES 16\n"
+ "#define USE_DEPTH\n";
- GG.shaders.fx_shaders[offset] = shader;
- GPU_fx_shader_init_interface(shader, effect);
- }
+ case GPU_SHADER_2D_WIDGET_BASE_INST:
+ case GPU_SHADER_2D_NODELINK_INST:
+ return "#define USE_INSTANCE\n";
- return GG.shaders.fx_shaders[offset];
-}
+ case GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE:
+ case GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE:
+ return "#define UNIFORM_SCALE\n";
+ case GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS:
+ return "#define AXIS_NAME\n";
-void GPU_shader_free_builtin_shaders(void)
-{
- int i;
+ case GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR:
+ return "#define USE_INSTANCE_COLOR\n";
- if (GG.shaders.vsm_store) {
- GPU_shader_free(GG.shaders.vsm_store);
- GG.shaders.vsm_store = NULL;
- }
+ case GPU_SHADER_3D_FLAT_COLOR_U32:
+ case GPU_SHADER_3D_UNIFORM_COLOR_U32:
+ return "#define USE_COLOR_U32\n";
- if (GG.shaders.sep_gaussian_blur) {
- GPU_shader_free(GG.shaders.sep_gaussian_blur);
- GG.shaders.sep_gaussian_blur = NULL;
- }
+ case GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR:
+ return "#define USE_FLAT_NORMAL\n";
- if (GG.shaders.smoke) {
- GPU_shader_free(GG.shaders.smoke);
- GG.shaders.smoke = NULL;
- }
+ case GPU_SHADER_2D_UV_EDGES_SMOOTH:
+ return "#define SMOOTH_COLOR\n";
- if (GG.shaders.smoke_fire) {
- GPU_shader_free(GG.shaders.smoke_fire);
- GG.shaders.smoke_fire = NULL;
+ default:
+ return NULL;
}
+}
+
+GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
+{
+ BLI_assert(shader != GPU_NUM_BUILTIN_SHADERS); /* don't be a troll */
+
+ if (builtin_shaders[shader] == NULL) {
+ const char *defines = gpu_shader_get_builtin_shader_defines(shader);
- if (GG.shaders.smoke_coba) {
- GPU_shader_free(GG.shaders.smoke_coba);
- GG.shaders.smoke_coba = NULL;
+ const GPUShaderStages *stages = builtin_shader_stages + shader;
+
+ if (shader == GPU_SHADER_EDGES_FRONT_BACK_PERSP && !GLEW_VERSION_3_2) {
+ /* TODO: remove after switch to core profile (maybe) */
+ static const GPUShaderStages legacy_fancy_edges = {
+ datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl,
+ datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl,
+ };
+ stages = &legacy_fancy_edges;
+ }
+
+ if (shader == GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR && !GLEW_VERSION_3_2) {
+ /* Dashed need geometry shader, which are not supported by legacy OpenGL, fallback to solid lines. */
+ /* TODO: remove after switch to core profile (maybe) */
+ static const GPUShaderStages legacy_dashed_lines = {
+ datatoc_gpu_shader_3D_line_dashed_uniform_color_legacy_vert_glsl,
+ datatoc_gpu_shader_2D_line_dashed_frag_glsl,
+ };
+ stages = &legacy_dashed_lines;
+ }
+
+ /* common case */
+ builtin_shaders[shader] = GPU_shader_create(stages->vert, stages->frag, stages->geom, NULL, defines, __func__);
}
- for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) {
- if (GG.shaders.fx_shaders[i]) {
- GPU_shader_free(GG.shaders.fx_shaders[i]);
- GG.shaders.fx_shaders[i] = NULL;
+ return builtin_shaders[shader];
+}
+
+void GPU_shader_get_builtin_shader_code(
+ GPUBuiltinShader shader,
+ const char **r_vert, const char **r_frag,
+ const char **r_geom, const char **r_defines)
+{
+ const GPUShaderStages *stages = builtin_shader_stages + shader;
+ *r_vert = stages->vert;
+ *r_frag = stages->frag;
+ *r_geom = stages->geom;
+ *r_defines = gpu_shader_get_builtin_shader_defines(shader);
+}
+
+#define MAX_DEFINES 100
+
+void GPU_shader_free_builtin_shaders(void)
+{
+ for (int i = 0; i < GPU_NUM_BUILTIN_SHADERS; ++i) {
+ if (builtin_shaders[i]) {
+ GPU_shader_free(builtin_shaders[i]);
+ builtin_shaders[i] = NULL;
}
}
}
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
new file mode 100644
index 00000000000..d46fc979363
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -0,0 +1,369 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_shader_interface.c
+ * \ingroup gpu
+ *
+ * GPU shader interface (C --> GLSL)
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_shader_interface.h"
+
+#include "gpu_batch_private.h"
+#include "gpu_context_private.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#define DEBUG_SHADER_INTERFACE 0
+
+#if DEBUG_SHADER_INTERFACE
+# include <stdio.h>
+#endif
+
+static const char *BuiltinUniform_name(GPUUniformBuiltin u)
+{
+ static const char *names[] = {
+ [GPU_UNIFORM_NONE] = NULL,
+
+ [GPU_UNIFORM_MODEL] = "ModelMatrix",
+ [GPU_UNIFORM_VIEW] = "ViewMatrix",
+ [GPU_UNIFORM_MODELVIEW] = "ModelViewMatrix",
+ [GPU_UNIFORM_PROJECTION] = "ProjectionMatrix",
+ [GPU_UNIFORM_VIEWPROJECTION] = "ViewProjectionMatrix",
+ [GPU_UNIFORM_MVP] = "ModelViewProjectionMatrix",
+
+ [GPU_UNIFORM_MODEL_INV] = "ModelMatrixInverse",
+ [GPU_UNIFORM_VIEW_INV] = "ViewMatrixInverse",
+ [GPU_UNIFORM_MODELVIEW_INV] = "ModelViewMatrixInverse",
+ [GPU_UNIFORM_PROJECTION_INV] = "ProjectionMatrixInverse",
+ [GPU_UNIFORM_VIEWPROJECTION_INV] = "ViewProjectionMatrixInverse",
+
+ [GPU_UNIFORM_NORMAL] = "NormalMatrix",
+ [GPU_UNIFORM_WORLDNORMAL] = "WorldNormalMatrix",
+ [GPU_UNIFORM_CAMERATEXCO] = "CameraTexCoFactors",
+ [GPU_UNIFORM_ORCO] = "OrcoTexCoFactors",
+
+ [GPU_UNIFORM_COLOR] = "color",
+ [GPU_UNIFORM_EYE] = "eye",
+ [GPU_UNIFORM_CALLID] = "callId",
+ [GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo",
+
+ [GPU_UNIFORM_CUSTOM] = NULL,
+ [GPU_NUM_UNIFORMS] = NULL,
+ };
+
+ return names[u];
+}
+
+GPU_INLINE bool match(const char *a, const char *b)
+{
+ return strcmp(a, b) == 0;
+}
+
+GPU_INLINE uint hash_string(const char *str)
+{
+ uint i = 0, c;
+ while ((c = *str++)) {
+ i = i * 37 + c;
+ }
+ return i;
+}
+
+GPU_INLINE void set_input_name(
+ GPUShaderInterface *shaderface, GPUShaderInput *input,
+ const char *name, uint32_t name_len)
+{
+ input->name_offset = shaderface->name_buffer_offset;
+ input->name_hash = hash_string(name);
+ shaderface->name_buffer_offset += name_len + 1; /* include NULL terminator */
+}
+
+GPU_INLINE void shader_input_to_bucket(
+ GPUShaderInput *input,
+ GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS])
+{
+ const uint bucket_index = input->name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS;
+ input->next = buckets[bucket_index];
+ buckets[bucket_index] = input;
+}
+
+GPU_INLINE const GPUShaderInput *buckets_lookup(
+ GPUShaderInput *const buckets[GPU_NUM_SHADERINTERFACE_BUCKETS],
+ const char *name_buffer, const char *name)
+{
+ const uint name_hash = hash_string(name);
+ const uint bucket_index = name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS;
+ const GPUShaderInput *input = buckets[bucket_index];
+ if (input == NULL) {
+ /* Requested uniform is not found at all. */
+ return NULL;
+ }
+ /* Optimization bit: if there is no hash collision detected when constructing shader interface
+ * it means we can only request the single possible uniform. Surely, it's possible we request
+ * uniform which causes hash collision, but that will be detected in debug builds. */
+ if (input->next == NULL) {
+ if (name_hash == input->name_hash) {
+#if TRUST_NO_ONE
+ assert(match(name_buffer + input->name_offset, name));
+#endif
+ return input;
+ }
+ return NULL;
+ }
+ /* Work through possible collisions. */
+ const GPUShaderInput *next = input;
+ while (next != NULL) {
+ input = next;
+ next = input->next;
+ if (input->name_hash != name_hash) {
+ continue;
+ }
+ if (match(name_buffer + input->name_offset, name)) {
+ return input;
+ }
+ }
+ return NULL; /* not found */
+}
+
+GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS])
+{
+ for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index) {
+ GPUShaderInput *input = buckets[bucket_index];
+ while (input != NULL) {
+ GPUShaderInput *input_next = input->next;
+ MEM_freeN(input);
+ input = input_next;
+ }
+ }
+}
+
+static bool setup_builtin_uniform(GPUShaderInput *input, const char *name)
+{
+ /* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */
+
+ /* detect built-in uniforms (name must match) */
+ for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) {
+ const char *builtin_name = BuiltinUniform_name(u);
+ if (match(name, builtin_name)) {
+ input->builtin_type = u;
+ return true;
+ }
+ }
+ input->builtin_type = GPU_UNIFORM_CUSTOM;
+ return false;
+}
+
+static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const char *name)
+{
+ GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Unif");
+
+ input->location = glGetUniformLocation(shaderface->program, name);
+
+ uint name_len = strlen(name);
+ shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, shaderface->name_buffer_offset + name_len + 1); /* include NULL terminator */
+ char *name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset;
+ strcpy(name_buffer, name);
+
+ set_input_name(shaderface, input, name, name_len);
+ setup_builtin_uniform(input, name);
+
+ shader_input_to_bucket(input, shaderface->uniform_buckets);
+ if (input->builtin_type != GPU_UNIFORM_NONE &&
+ input->builtin_type != GPU_UNIFORM_CUSTOM)
+ {
+ shaderface->builtin_uniforms[input->builtin_type] = input;
+ }
+#if DEBUG_SHADER_INTERFACE
+ printf("GPUShaderInterface %p, program %d, uniform[] '%s' at location %d\n",
+ shaderface,
+ shaderface->program,
+ name,
+ input->location);
+#endif
+ return input;
+}
+
+GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
+{
+ GPUShaderInterface *shaderface = MEM_callocN(sizeof(GPUShaderInterface), "GPUShaderInterface");
+ shaderface->program = program;
+
+#if DEBUG_SHADER_INTERFACE
+ printf("%s {\n", __func__); /* enter function */
+ printf("GPUShaderInterface %p, program %d\n", shaderface, program);
+#endif
+
+ GLint max_attrib_name_len, attr_len;
+ glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len);
+ glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len);
+
+ GLint max_ubo_name_len, ubo_len;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len);
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len);
+
+ const uint32_t name_buffer_len = attr_len * max_attrib_name_len + ubo_len * max_ubo_name_len;
+ shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer");
+
+ /* Attributes */
+ for (uint32_t i = 0; i < attr_len; ++i) {
+ GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr");
+ GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
+ char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
+ GLsizei name_len = 0;
+
+ glGetActiveAttrib(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name);
+
+ /* remove "[0]" from array name */
+ if (name[name_len - 1] == ']') {
+ name[name_len - 3] = '\0';
+ name_len -= 3;
+ }
+
+ /* TODO: reject DOUBLE gl_types */
+
+ input->location = glGetAttribLocation(program, name);
+
+ set_input_name(shaderface, input, name, name_len);
+
+ shader_input_to_bucket(input, shaderface->attrib_buckets);
+
+#if DEBUG_SHADER_INTERFACE
+ printf("attrib[%u] '%s' at location %d\n", i, name, input->location);
+#endif
+ }
+ /* Uniform Blocks */
+ for (uint32_t i = 0; i < ubo_len; ++i) {
+ GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO");
+ GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
+ char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
+ GLsizei name_len = 0;
+
+ glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
+
+ input->location = i;
+
+ set_input_name(shaderface, input, name, name_len);
+
+ shader_input_to_bucket(input, shaderface->ubo_buckets);
+
+#if DEBUG_SHADER_INTERFACE
+ printf("ubo '%s' at location %d\n", name, input->location);
+#endif
+ }
+ /* Builtin Uniforms */
+ for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; ++u) {
+ const char *builtin_name = BuiltinUniform_name(u);
+ if (glGetUniformLocation(program, builtin_name) != -1) {
+ add_uniform((GPUShaderInterface *)shaderface, builtin_name);
+ }
+ }
+ /* Batches ref buffer */
+ shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT;
+ shaderface->batches = MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), "GPUShaderInterface batches");
+
+ return shaderface;
+}
+
+void GPU_shaderinterface_discard(GPUShaderInterface *shaderface)
+{
+ /* Free memory used by buckets and has entries. */
+ buckets_free(shaderface->uniform_buckets);
+ buckets_free(shaderface->attrib_buckets);
+ buckets_free(shaderface->ubo_buckets);
+ /* Free memory used by name_buffer. */
+ MEM_freeN(shaderface->name_buffer);
+ /* Remove this interface from all linked Batches vao cache. */
+ for (int i = 0; i < shaderface->batches_len; ++i) {
+ if (shaderface->batches[i] != NULL) {
+ gpu_batch_remove_interface_ref(shaderface->batches[i], shaderface);
+ }
+ }
+ MEM_freeN(shaderface->batches);
+ /* Free memory used by shader interface by its self. */
+ MEM_freeN(shaderface);
+}
+
+const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, const char *name)
+{
+ /* TODO: Warn if we find a matching builtin, since these can be looked up much quicker. */
+ const GPUShaderInput *input = buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name);
+ /* If input is not found add it so it's found next time. */
+ if (input == NULL) {
+ input = add_uniform((GPUShaderInterface *)shaderface, name);
+ }
+ return (input->location != -1) ? input : NULL;
+}
+
+const GPUShaderInput *GPU_shaderinterface_uniform_builtin(
+ const GPUShaderInterface *shaderface, GPUUniformBuiltin builtin)
+{
+#if TRUST_NO_ONE
+ assert(builtin != GPU_UNIFORM_NONE);
+ assert(builtin != GPU_UNIFORM_CUSTOM);
+ assert(builtin != GPU_NUM_UNIFORMS);
+#endif
+ return shaderface->builtin_uniforms[builtin];
+}
+
+const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, const char *name)
+{
+ return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name);
+}
+
+const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, const char *name)
+{
+ return buckets_lookup(shaderface->attrib_buckets, shaderface->name_buffer, name);
+}
+
+void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
+{
+ int i; /* find first unused slot */
+ for (i = 0; i < shaderface->batches_len; ++i) {
+ if (shaderface->batches[i] == NULL) {
+ break;
+ }
+ }
+ if (i == shaderface->batches_len) {
+ /* Not enough place, realloc the array. */
+ i = shaderface->batches_len;
+ shaderface->batches_len += GPU_SHADERINTERFACE_REF_ALLOC_COUNT;
+ shaderface->batches = MEM_recallocN(shaderface->batches, sizeof(GPUBatch *) * shaderface->batches_len);
+ }
+ shaderface->batches[i] = batch;
+}
+
+void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
+{
+ for (int i = 0; i < shaderface->batches_len; ++i) {
+ if (shaderface->batches[i] == batch) {
+ shaderface->batches[i] = NULL;
+ break; /* cannot have duplicates */
+ }
+ }
+}
diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h
new file mode 100644
index 00000000000..69c0c41cef4
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_private.h
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gpu_shader_private.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_SHADER_PRIVATE_H__
+#define __GPU_SHADER_PRIVATE_H__
+
+#include "GPU_glew.h"
+#include "GPU_shader_interface.h"
+
+struct GPUShader {
+ GLuint program; /* handle for full program (links shader stages below) */
+
+ GLuint vertex; /* handle for vertex shader */
+ GLuint geometry; /* handle for geometry shader */
+ GLuint fragment; /* handle for fragment shader */
+
+ GPUShaderInterface *interface; /* cached uniform & attrib interface for shader */
+
+ int feedback_transform_type;
+#ifndef NDEBUG
+ char name[64];
+#endif
+};
+
+#endif /* __GPU_SHADER_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c
new file mode 100644
index 00000000000..d06854f669f
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_state.c
@@ -0,0 +1,179 @@
+/*
+ * ***** 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): Ray Molenkamp
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_state.c
+ * \ingroup gpu
+ *
+ */
+
+#include "DNA_userdef_types.h"
+
+#include "GPU_glew.h"
+#include "GPU_state.h"
+#include "GPU_extensions.h"
+
+static GLenum gpu_get_gl_blendfunction(GPUBlendFunction blend)
+{
+ switch (blend) {
+ case GPU_ONE:
+ return GL_ONE;
+ case GPU_SRC_ALPHA:
+ return GL_SRC_ALPHA;
+ case GPU_ONE_MINUS_SRC_ALPHA:
+ return GL_ONE_MINUS_SRC_ALPHA;
+ case GPU_DST_COLOR:
+ return GL_DST_COLOR;
+ case GPU_ZERO:
+ return GL_ZERO;
+ default:
+ BLI_assert(!"Unhandled blend mode");
+ return GL_ZERO;
+ }
+}
+
+void GPU_blend(bool enable)
+{
+ if (enable) {
+ glEnable(GL_BLEND);
+ }
+ else {
+ glDisable(GL_BLEND);
+ }
+}
+
+void GPU_blend_set_func(GPUBlendFunction sfactor, GPUBlendFunction dfactor)
+{
+ glBlendFunc(gpu_get_gl_blendfunction(sfactor), gpu_get_gl_blendfunction(dfactor));
+}
+
+void GPU_blend_set_func_separate(
+ GPUBlendFunction src_rgb, GPUBlendFunction dst_rgb,
+ GPUBlendFunction src_alpha, GPUBlendFunction dst_alpha)
+{
+ glBlendFuncSeparate(
+ gpu_get_gl_blendfunction(src_rgb),
+ gpu_get_gl_blendfunction(dst_rgb),
+ gpu_get_gl_blendfunction(src_alpha),
+ gpu_get_gl_blendfunction(dst_alpha));
+}
+
+void GPU_depth_range(float near, float far)
+{
+ /* glDepthRangef is only for OpenGL 4.1 or higher */
+ glDepthRange(near, far);
+}
+
+void GPU_depth_test(bool enable)
+{
+ if (enable) {
+ glEnable(GL_DEPTH_TEST);
+ }
+ else {
+ glDisable(GL_DEPTH_TEST);
+ }
+}
+
+bool GPU_depth_test_enabled()
+{
+ return glIsEnabled(GL_DEPTH_TEST);
+}
+
+void GPU_line_smooth(bool enable)
+{
+ if (enable) {
+ glEnable(GL_LINE_SMOOTH);
+ }
+ else {
+ glDisable(GL_LINE_SMOOTH);
+ }
+}
+
+void GPU_line_stipple(bool enable)
+{
+ if (enable) {
+ glEnable(GL_LINE_STIPPLE);
+ }
+ else {
+ glDisable(GL_LINE_STIPPLE);
+ }
+}
+
+void GPU_line_width(float width)
+{
+ float max_size = GPU_max_line_width();
+ float final_size = width * U.pixelsize;
+ /* Fix opengl errors on certain platform / drivers. */
+ if (max_size < final_size) {
+ final_size = max_size;
+ }
+ glLineWidth(final_size);
+}
+
+void GPU_point_size(float size)
+{
+ glPointSize(size * U.pixelsize);
+}
+
+void GPU_polygon_smooth(bool enable)
+{
+ if (enable) {
+ glEnable(GL_POLYGON_SMOOTH);
+ }
+ else {
+ glDisable(GL_POLYGON_SMOOTH);
+ }
+}
+
+void GPU_scissor(int x, int y, int width, int height)
+{
+ glScissor(x, y, width, height);
+}
+
+void GPU_scissor_get_f(float coords[4])
+{
+ glGetFloatv(GL_SCISSOR_BOX, coords);
+}
+
+void GPU_scissor_get_i(int coords[4])
+{
+ glGetIntegerv(GL_SCISSOR_BOX, coords);
+}
+
+void GPU_viewport_size_get_f(float coords[4])
+{
+ glGetFloatv(GL_VIEWPORT, coords);
+}
+
+void GPU_viewport_size_get_i(int coords[4])
+{
+ glGetIntegerv(GL_VIEWPORT, coords);
+}
+
+void GPU_flush(void)
+{
+ glFlush();
+}
+
+void GPU_finish(void)
+{
+ glFinish();
+}
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index c201254ffae..d5b33b88350 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -32,380 +32,793 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
+#include "BLI_listbase.h"
+#include "BLI_threads.h"
#include "BKE_global.h"
+#include "GPU_batch.h"
+#include "GPU_context.h"
#include "GPU_debug.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
-#include "GPU_framebuffer.h"
#include "GPU_glew.h"
+#include "GPU_framebuffer.h"
#include "GPU_texture.h"
+#include "gpu_context_private.h"
+
static struct GPUTextureGlobal {
GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
GPUTexture *invalid_tex_2D;
GPUTexture *invalid_tex_3D;
} GG = {NULL, NULL, NULL};
-/* GPUTexture */
+/* Maximum number of FBOs a texture can be attached to. */
+#define GPU_TEX_MAX_FBO_ATTACHED 10
+typedef enum GPUTextureFormatFlag {
+ GPU_FORMAT_DEPTH = (1 << 0),
+ GPU_FORMAT_STENCIL = (1 << 1),
+ GPU_FORMAT_INTEGER = (1 << 2),
+ GPU_FORMAT_FLOAT = (1 << 3),
+
+ GPU_FORMAT_1D = (1 << 10),
+ GPU_FORMAT_2D = (1 << 11),
+ GPU_FORMAT_3D = (1 << 12),
+ GPU_FORMAT_CUBE = (1 << 13),
+ GPU_FORMAT_ARRAY = (1 << 14),
+} GPUTextureFormatFlag;
+
+/* GPUTexture */
struct GPUTexture {
- int w, h; /* width/height */
+ int w, h, d; /* width/height/depth */
int number; /* number for multitexture binding */
int refcount; /* reference count */
GLenum target; /* GL_TEXTURE_* */
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 */
- GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
- int fb_attachment; /* slot the texture is attached to */
- int depth; /* is a depth texture? if 3D how deep? */
-};
+ GPUTextureFormat format;
+ GPUTextureFormatFlag format_flag;
-static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels)
-{
- unsigned char *pixels, *p;
- const float *fp = fpixels;
- const int len = 4 * length;
+ uint bytesize; /* number of byte for one pixel */
+ int components; /* number of color/alpha channels */
+ int samples; /* number of samples for multisamples textures. 0 if not multisample target */
- p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels");
+ int fb_attachment[GPU_TEX_MAX_FBO_ATTACHED];
+ GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED];
+};
- for (int a = 0; a < len; a++, p++, fp++)
- *p = unit_float_to_uchar_clamp((*fp));
+/* ------ Memory Management ------- */
+/* Records every texture allocation / free
+ * to estimate the Texture Pool Memory consumption */
+static uint memory_usage;
- return pixels;
+static uint gpu_texture_memory_footprint_compute(GPUTexture *tex)
+{
+ int samp = max_ii(tex->samples, 1);
+ switch (tex->target) {
+ case GL_TEXTURE_1D:
+ return tex->bytesize * tex->w * samp;
+ case GL_TEXTURE_1D_ARRAY:
+ case GL_TEXTURE_2D:
+ return tex->bytesize * tex->w * tex->h * samp;
+ case GL_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_3D:
+ return tex->bytesize * tex->w * tex->h * tex->d * samp;
+ case GL_TEXTURE_CUBE_MAP:
+ return tex->bytesize * 6 * tex->w * tex->h * samp;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ return tex->bytesize * 6 * tex->w * tex->h * tex->d * samp;
+ default:
+ return 0;
+ }
}
-static void gpu_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
+static void gpu_texture_memory_footprint_add(GPUTexture *tex)
{
- void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
-
- if (target == GL_TEXTURE_1D)
- glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
- else
- glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
+ memory_usage += gpu_texture_memory_footprint_compute(tex);
+}
- MEM_freeN(pixels);
+static void gpu_texture_memory_footprint_remove(GPUTexture *tex)
+{
+ memory_usage -= gpu_texture_memory_footprint_compute(tex);
}
-static GPUTexture *GPU_texture_create_nD(
- int w, int h, int n, const float *fpixels, int depth,
- GPUHDRType hdr_type, int components, int samples,
- char err_out[256])
+uint GPU_texture_memory_usage_get(void)
{
- GLenum type, format, internalformat;
- void *pixels = NULL;
+ return memory_usage;
+}
- if (samples) {
- CLAMP_MAX(samples, GPU_max_color_texture_samples());
- }
+/* -------------------------------- */
- GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->w = w;
- tex->h = h;
- tex->number = -1;
- tex->refcount = 1;
- tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
- tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D;
- tex->depth = depth;
- tex->fb_attachment = -1;
-
- glGenTextures(1, &tex->bindcode);
+static int gpu_get_component_count(GPUTextureFormat format)
+{
+ switch (format) {
+ case GPU_RGBA8:
+ case GPU_RGBA8UI:
+ case GPU_RGBA16F:
+ case GPU_RGBA16:
+ case GPU_RGBA32F:
+ return 4;
+ case GPU_RGB16F:
+ case GPU_R11F_G11F_B10F:
+ return 3;
+ case GPU_RG8:
+ case GPU_RG16:
+ case GPU_RG16F:
+ case GPU_RG16I:
+ case GPU_RG16UI:
+ case GPU_RG32F:
+ return 2;
+ default:
+ return 1;
+ }
+}
- if (!tex->bindcode) {
- if (err_out) {
- BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d",
- (int)glGetError());
+/* Definitely not complete, edit according to the gl specification. */
+static void gpu_validate_data_format(GPUTextureFormat tex_format, GPUDataFormat data_format)
+{
+ (void)data_format;
+
+ if (ELEM(tex_format,
+ GPU_DEPTH_COMPONENT24,
+ GPU_DEPTH_COMPONENT16,
+ GPU_DEPTH_COMPONENT32F))
+ {
+ BLI_assert(data_format == GPU_DATA_FLOAT);
+ }
+ else if (ELEM(tex_format,
+ GPU_DEPTH24_STENCIL8,
+ GPU_DEPTH32F_STENCIL8))
+ {
+ BLI_assert(data_format == GPU_DATA_UNSIGNED_INT_24_8);
+ }
+ else {
+ /* Integer formats */
+ if (ELEM(tex_format, GPU_RG16I, GPU_R16I, GPU_RG16UI, GPU_R16UI, GPU_R32UI)) {
+ if (ELEM(tex_format, GPU_R16UI, GPU_RG16UI, GPU_R32UI)) {
+ BLI_assert(data_format == GPU_DATA_UNSIGNED_INT);
+ }
+ else {
+ BLI_assert(data_format == GPU_DATA_INT);
+ }
}
+ /* Byte formats */
+ else if (ELEM(tex_format, GPU_R8, GPU_RG8, GPU_RGBA8, GPU_RGBA8UI)) {
+ BLI_assert(ELEM(data_format, GPU_DATA_UNSIGNED_BYTE, GPU_DATA_FLOAT));
+ }
+ /* Special case */
+ else if (ELEM(tex_format, GPU_R11F_G11F_B10F)) {
+ BLI_assert(ELEM(data_format, GPU_DATA_10_11_11_REV, GPU_DATA_FLOAT));
+ }
+ /* Float formats */
else {
- fprintf(stderr, "GPUTexture: texture create failed: %d\n",
- (int)glGetError());
+ BLI_assert(ELEM(data_format, GPU_DATA_FLOAT));
}
- GPU_texture_free(tex);
- return NULL;
}
+}
- if (!GPU_full_non_power_of_two_support()) {
- tex->w = power_of_2_max_i(tex->w);
- tex->h = power_of_2_max_i(tex->h);
+static GPUDataFormat gpu_get_data_format_from_tex_format(GPUTextureFormat tex_format)
+{
+ if (ELEM(tex_format,
+ GPU_DEPTH_COMPONENT24,
+ GPU_DEPTH_COMPONENT16,
+ GPU_DEPTH_COMPONENT32F))
+ {
+ return GPU_DATA_FLOAT;
}
-
- tex->number = 0;
- glBindTexture(tex->target, tex->bindcode);
-
- if (depth) {
- type = GL_UNSIGNED_BYTE;
- format = GL_DEPTH_COMPONENT;
- internalformat = GL_DEPTH_COMPONENT;
+ else if (ELEM(tex_format,
+ GPU_DEPTH24_STENCIL8,
+ GPU_DEPTH32F_STENCIL8))
+ {
+ return GPU_DATA_UNSIGNED_INT_24_8;
}
else {
- type = GL_FLOAT;
-
- if (components == 4) {
- format = GL_RGBA;
- switch (hdr_type) {
- case GPU_HDR_NONE:
- internalformat = GL_RGBA8;
- break;
- /* the following formats rely on ARB_texture_float or OpenGL 3.0 */
- case GPU_HDR_HALF_FLOAT:
- internalformat = GL_RGBA16F_ARB;
- break;
- case GPU_HDR_FULL_FLOAT:
- internalformat = GL_RGBA32F_ARB;
- break;
- default:
- break;
+ /* Integer formats */
+ if (ELEM(tex_format, GPU_RG16I, GPU_R16I, GPU_RG16UI, GPU_R16UI, GPU_R32UI)) {
+ if (ELEM(tex_format, GPU_R16UI, GPU_RG16UI, GPU_R32UI)) {
+ return GPU_DATA_UNSIGNED_INT;
}
- }
- else if (components == 2) {
- /* these formats rely on ARB_texture_rg or OpenGL 3.0 */
- format = GL_RG;
- switch (hdr_type) {
- case GPU_HDR_NONE:
- internalformat = GL_RG8;
- break;
- case GPU_HDR_HALF_FLOAT:
- internalformat = GL_RG16F;
- break;
- case GPU_HDR_FULL_FLOAT:
- internalformat = GL_RG32F;
- break;
- default:
- break;
+ else {
+ return GPU_DATA_INT;
}
}
-
- if (fpixels && hdr_type == GPU_HDR_NONE) {
- type = GL_UNSIGNED_BYTE;
- pixels = GPU_texture_convert_pixels(w * h, fpixels);
+ /* Byte formats */
+ else if (ELEM(tex_format, GPU_R8)) {
+ return GPU_DATA_UNSIGNED_BYTE;
+ }
+ /* Special case */
+ else if (ELEM(tex_format, GPU_R11F_G11F_B10F)) {
+ return GPU_DATA_10_11_11_REV;
+ }
+ else {
+ return GPU_DATA_FLOAT;
}
}
+}
- if (tex->target == GL_TEXTURE_1D) {
- glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
-
- if (fpixels) {
- glTexSubImage1D(tex->target, 0, 0, w, format, type,
- pixels ? pixels : fpixels);
-
- if (tex->w > w) {
- gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1);
- }
- }
+/* Definitely not complete, edit according to the gl specification. */
+static GLenum gpu_get_gl_dataformat(GPUTextureFormat data_type, GPUTextureFormatFlag *format_flag)
+{
+ if (ELEM(data_type,
+ GPU_DEPTH_COMPONENT24,
+ GPU_DEPTH_COMPONENT16,
+ GPU_DEPTH_COMPONENT32F))
+ {
+ *format_flag |= GPU_FORMAT_DEPTH;
+ return GL_DEPTH_COMPONENT;
+ }
+ else if (ELEM(data_type,
+ GPU_DEPTH24_STENCIL8,
+ GPU_DEPTH32F_STENCIL8))
+ {
+ *format_flag |= GPU_FORMAT_DEPTH | GPU_FORMAT_STENCIL;
+ return GL_DEPTH_STENCIL;
}
else {
- if (samples) {
- glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true);
+ /* Integer formats */
+ if (ELEM(data_type, GPU_RG16I, GPU_R16I, GPU_RG16UI, GPU_R16UI, GPU_R32UI)) {
+ *format_flag |= GPU_FORMAT_INTEGER;
+
+ switch (gpu_get_component_count(data_type)) {
+ case 1: return GL_RED_INTEGER; break;
+ case 2: return GL_RG_INTEGER; break;
+ case 3: return GL_RGB_INTEGER; break;
+ case 4: return GL_RGBA_INTEGER; break;
+ }
}
- else {
- glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
- format, type, NULL);
+ else if (ELEM(data_type, GPU_R8)) {
+ *format_flag |= GPU_FORMAT_FLOAT;
+ return GL_RED;
}
+ else {
+ *format_flag |= GPU_FORMAT_FLOAT;
- if (fpixels) {
- glTexSubImage2D(tex->target, 0, 0, 0, w, h,
- format, type, pixels ? pixels : fpixels);
-
- if (tex->w > w) {
- gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h);
- }
- if (tex->h > h) {
- gpu_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h);
+ switch (gpu_get_component_count(data_type)) {
+ case 1: return GL_RED; break;
+ case 2: return GL_RG; break;
+ case 3: return GL_RGB; break;
+ case 4: return GL_RGBA; break;
}
}
}
- if (pixels)
- MEM_freeN(pixels);
+ BLI_assert(0);
+ *format_flag |= GPU_FORMAT_FLOAT;
+ return GL_RGBA;
+}
- if (depth) {
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
+static uint gpu_get_bytesize(GPUTextureFormat data_type)
+{
+ switch (data_type) {
+ case GPU_RGBA32F:
+ return 32;
+ case GPU_RG32F:
+ case GPU_RGBA16F:
+ case GPU_RGBA16:
+ return 16;
+ case GPU_RGB16F:
+ return 12;
+ case GPU_DEPTH32F_STENCIL8:
+ return 8;
+ case GPU_RG16F:
+ case GPU_RG16I:
+ case GPU_RG16UI:
+ case GPU_RG16:
+ case GPU_DEPTH24_STENCIL8:
+ case GPU_DEPTH_COMPONENT32F:
+ case GPU_RGBA8UI:
+ case GPU_RGBA8:
+ case GPU_R11F_G11F_B10F:
+ case GPU_R32F:
+ case GPU_R32UI:
+ case GPU_R32I:
+ return 4;
+ case GPU_DEPTH_COMPONENT24:
+ return 3;
+ case GPU_DEPTH_COMPONENT16:
+ case GPU_R16F:
+ case GPU_R16UI:
+ case GPU_R16I:
+ case GPU_RG8:
+ case GPU_R16:
+ return 2;
+ case GPU_R8:
+ return 1;
+ default:
+ BLI_assert(!"Texture format incorrect or unsupported\n");
+ return 0;
}
- else {
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+}
+
+static GLenum gpu_get_gl_internalformat(GPUTextureFormat format)
+{
+ /* You can add any of the available type to this list
+ * For available types see GPU_texture.h */
+ switch (format) {
+ /* Formats texture & renderbuffer */
+ case GPU_RGBA32F: return GL_RGBA32F;
+ case GPU_RGBA16F: return GL_RGBA16F;
+ case GPU_RGBA16: return GL_RGBA16;
+ case GPU_RG32F: return GL_RG32F;
+ case GPU_RGB16F: return GL_RGB16F;
+ case GPU_RG16F: return GL_RG16F;
+ case GPU_RG16I: return GL_RG16I;
+ case GPU_RG16: return GL_RG16;
+ case GPU_RGBA8: return GL_RGBA8;
+ case GPU_RGBA8UI: return GL_RGBA8UI;
+ case GPU_R32F: return GL_R32F;
+ case GPU_R32UI: return GL_R32UI;
+ case GPU_R32I: return GL_R32I;
+ case GPU_R16F: return GL_R16F;
+ case GPU_R16I: return GL_R16I;
+ case GPU_R16UI: return GL_R16UI;
+ case GPU_RG8: return GL_RG8;
+ case GPU_RG16UI: return GL_RG16UI;
+ case GPU_R16: return GL_R16;
+ case GPU_R8: return GL_R8;
+ /* Special formats texture & renderbuffer */
+ case GPU_R11F_G11F_B10F: return GL_R11F_G11F_B10F;
+ case GPU_DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8;
+ case GPU_DEPTH32F_STENCIL8: return GL_DEPTH32F_STENCIL8;
+ /* Texture only format */
+ /* ** Add Format here **/
+ /* Special formats texture only */
+ /* ** Add Format here **/
+ /* Depth Formats */
+ case GPU_DEPTH_COMPONENT32F: return GL_DEPTH_COMPONENT32F;
+ case GPU_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT24;
+ case GPU_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT16;
+ default:
+ BLI_assert(!"Texture format incorrect or unsupported\n");
+ return 0;
}
+}
- if (tex->target_base != GL_TEXTURE_1D) {
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+static GLenum gpu_get_gl_datatype(GPUDataFormat format)
+{
+ switch (format) {
+ case GPU_DATA_FLOAT:
+ return GL_FLOAT;
+ case GPU_DATA_INT:
+ return GL_INT;
+ case GPU_DATA_UNSIGNED_INT:
+ return GL_UNSIGNED_INT;
+ case GPU_DATA_UNSIGNED_BYTE:
+ return GL_UNSIGNED_BYTE;
+ case GPU_DATA_UNSIGNED_INT_24_8:
+ return GL_UNSIGNED_INT_24_8;
+ case GPU_DATA_10_11_11_REV:
+ return GL_UNSIGNED_INT_10F_11F_11F_REV;
+ default:
+ BLI_assert(!"Unhandled data format");
+ return GL_FLOAT;
}
- else
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+}
- return tex;
+static float *GPU_texture_3D_rescale(GPUTexture *tex, int w, int h, int d, int channels, const float *fpixels)
+{
+ const uint xf = w / tex->w, yf = h / tex->h, zf = d / tex->d;
+ float *nfpixels = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->d, "GPUTexture Rescaled 3Dtex");
+
+ if (nfpixels) {
+ GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
+
+ for (uint k = 0; k < tex->d; k++) {
+ for (uint j = 0; j < tex->h; j++) {
+ for (uint i = 0; i < tex->w; i++) {
+ /* obviously doing nearest filtering here,
+ * it's going to be slow in any case, let's not make it worse */
+ float xb = i * xf;
+ float yb = j * yf;
+ float zb = k * zf;
+ uint offset = k * (tex->w * tex->h) + i * tex->h + j;
+ uint offset_orig = (zb) * (w * h) + (xb) * h + (yb);
+
+ if (channels == 4) {
+ nfpixels[offset * 4] = fpixels[offset_orig * 4];
+ nfpixels[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
+ nfpixels[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
+ nfpixels[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
+ }
+ else
+ nfpixels[offset] = fpixels[offset_orig];
+ }
+ }
+ }
+ }
+
+ return nfpixels;
}
+/* This tries to allocate video memory for a given texture
+ * If alloc fails, lower the resolution until it fits. */
+static bool gpu_texture_try_alloc(
+ GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum data_format, GLenum data_type,
+ int channels, bool try_rescale, const float *fpixels, float **rescaled_fpixels)
+{
+ int r_width;
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels)
+ switch (proxy) {
+ case GL_PROXY_TEXTURE_1D:
+ glTexImage1D(proxy, 0, internalformat, tex->w, 0, data_format, data_type, NULL);
+ break;
+ case GL_PROXY_TEXTURE_1D_ARRAY:
+ case GL_PROXY_TEXTURE_2D:
+ glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, NULL);
+ break;
+ case GL_PROXY_TEXTURE_2D_ARRAY:
+ /* HACK: Some driver wrongly check GL_PROXY_TEXTURE_2D_ARRAY as a GL_PROXY_TEXTURE_3D
+ * checking all dimensions against GPU_max_texture_layers (see T55888). */
+ return (tex->w > 0) && (tex->w <= GPU_max_texture_size()) &&
+ (tex->h > 0) && (tex->h <= GPU_max_texture_size()) &&
+ (tex->d > 0) && (tex->d <= GPU_max_texture_layers());
+ case GL_PROXY_TEXTURE_3D:
+ glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, data_format, data_type, NULL);
+ break;
+ }
+
+ glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &r_width);
+
+ if (r_width == 0 && try_rescale) {
+ const int w = tex->w, h = tex->h, d = tex->d;
+
+ /* Find largest texture possible */
+ while (r_width == 0) {
+ tex->w /= 2;
+ tex->h /= 2;
+ tex->d /= 2;
+
+ /* really unlikely to happen but keep this just in case */
+ if (tex->w == 0) break;
+ if (tex->h == 0 && proxy != GL_PROXY_TEXTURE_1D) break;
+ if (tex->d == 0 && proxy == GL_PROXY_TEXTURE_3D) break;
+
+ if (proxy == GL_PROXY_TEXTURE_1D)
+ glTexImage1D(proxy, 0, internalformat, tex->w, 0, data_format, data_type, NULL);
+ else if (proxy == GL_PROXY_TEXTURE_2D)
+ glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, NULL);
+ else if (proxy == GL_PROXY_TEXTURE_3D)
+ glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, data_format, data_type, NULL);
+
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+ }
+
+ /* Rescale */
+ if (r_width > 0) {
+ switch (proxy) {
+ case GL_PROXY_TEXTURE_1D:
+ case GL_PROXY_TEXTURE_2D:
+ /* Do nothing for now */
+ return false;
+ case GL_PROXY_TEXTURE_3D:
+ BLI_assert(data_type == GL_FLOAT);
+ *rescaled_fpixels = GPU_texture_3D_rescale(tex, w, h, d, channels, fpixels);
+ return (bool)*rescaled_fpixels;
+ }
+ }
+ }
+
+ return (r_width > 0);
+}
+
+GPUTexture *GPU_texture_create_nD(
+ int w, int h, int d, int n, const void *pixels,
+ GPUTextureFormat tex_format, GPUDataFormat gpu_data_format, int samples,
+ const bool can_rescale, char err_out[256])
{
- GLenum type, format, internalformat;
- void *pixels = NULL;
+ if (samples) {
+ CLAMP_MAX(samples, GPU_max_color_texture_samples());
+ }
+
+ if ((tex_format == GPU_DEPTH24_STENCIL8) && GPU_depth_blitting_workaround()) {
+ /* MacOS + Radeon Pro fails to blit depth on GPU_DEPTH24_STENCIL8
+ * but works on GPU_DEPTH32F_STENCIL8. */
+ tex_format = GPU_DEPTH32F_STENCIL8;
+ }
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->w = w;
tex->h = h;
- tex->depth = depth;
+ tex->d = d;
+ tex->samples = samples;
tex->number = -1;
tex->refcount = 1;
- tex->target = GL_TEXTURE_3D;
- tex->target_base = GL_TEXTURE_3D;
+ tex->format = tex_format;
+ tex->components = gpu_get_component_count(tex_format);
+ tex->bytesize = gpu_get_bytesize(tex_format);
+ tex->format_flag = 0;
+
+ if (n == 2) {
+ if (d == 0)
+ tex->target_base = tex->target = GL_TEXTURE_2D;
+ else
+ tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY;
+ }
+ else if (n == 1) {
+ if (h == 0)
+ tex->target_base = tex->target = GL_TEXTURE_1D;
+ else
+ tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY;
+ }
+ else if (n == 3) {
+ tex->target_base = tex->target = GL_TEXTURE_3D;
+ }
+ else {
+ /* should never happen */
+ MEM_freeN(tex);
+ return NULL;
+ }
+
+ gpu_validate_data_format(tex_format, gpu_data_format);
+
+ if (samples && n == 2 && d == 0)
+ tex->target = GL_TEXTURE_2D_MULTISAMPLE;
- glGenTextures(1, &tex->bindcode);
+ GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+ GLenum data_format = gpu_get_gl_dataformat(tex_format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
+
+ gpu_texture_memory_footprint_add(tex);
+
+ /* Generate Texture object */
+ tex->bindcode = GPU_tex_alloc();
if (!tex->bindcode) {
- fprintf(stderr, "GPUTexture: texture create failed: %d\n",
- (int)glGetError());
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUTexture: texture create failed\n");
+ else
+ fprintf(stderr, "GPUTexture: texture create failed\n");
GPU_texture_free(tex);
return NULL;
}
- tex->number = 0;
glBindTexture(tex->target, tex->bindcode);
- GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture");
+ /* Check if texture fit in VRAM */
+ GLenum proxy = GL_PROXY_TEXTURE_2D;
+
+ if (n == 2) {
+ if (d > 0)
+ proxy = GL_PROXY_TEXTURE_2D_ARRAY;
+ }
+ else if (n == 1) {
+ if (h == 0)
+ proxy = GL_PROXY_TEXTURE_1D;
+ else
+ proxy = GL_PROXY_TEXTURE_1D_ARRAY;
+ }
+ else if (n == 3) {
+ proxy = GL_PROXY_TEXTURE_3D;
+ }
+
+ float *rescaled_pixels = NULL;
+ bool valid = gpu_texture_try_alloc(tex, proxy, internalformat, data_format, data_type, tex->components, can_rescale,
+ pixels, &rescaled_pixels);
+ if (!valid) {
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUTexture: texture alloc failed");
+ else
+ fprintf(stderr, "GPUTexture: texture alloc failed. Not enough Video Memory.");
+ GPU_texture_free(tex);
+ return NULL;
+ }
- type = GL_FLOAT;
- if (channels == 4) {
- format = GL_RGBA;
- internalformat = GL_RGBA8;
+ /* Upload Texture */
+ const float *pix = (rescaled_pixels) ? rescaled_pixels : pixels;
+
+ if (tex->target == GL_TEXTURE_2D ||
+ tex->target == GL_TEXTURE_2D_MULTISAMPLE ||
+ tex->target == GL_TEXTURE_1D_ARRAY)
+ {
+ if (samples) {
+ glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true);
+ if (pix)
+ glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, data_format, data_type, pix);
+ }
+ else {
+ glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pix);
+ }
+ }
+ else if (tex->target == GL_TEXTURE_1D) {
+ glTexImage1D(tex->target, 0, internalformat, tex->w, 0, data_format, data_type, pix);
}
else {
- format = GL_RED;
- internalformat = GL_INTENSITY8;
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, data_format, data_type, pix);
}
- /* 3D textures are quite heavy, test if it's possible to create them first */
- glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ if (rescaled_pixels)
+ MEM_freeN(rescaled_pixels);
- bool rescale = false;
- int r_width;
+ /* Texture Parameters */
+ if (GPU_texture_stencil(tex) || /* Does not support filtering */
+ GPU_texture_integer(tex) || /* Does not support filtering */
+ GPU_texture_depth(tex))
+ {
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ }
+ else {
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
- glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+ if (GPU_texture_depth(tex)) {
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ }
- while (r_width == 0) {
- rescale = true;
- tex->w /= 2;
- tex->h /= 2;
- tex->depth /= 2;
- glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
- glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ if (n > 1) {
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ if (n > 2) {
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
- /* really unlikely to happen but keep this just in case */
- tex->w = max_ii(tex->w, 1);
- tex->h = max_ii(tex->h, 1);
- tex->depth = max_ii(tex->depth, 1);
+ glBindTexture(tex->target, 0);
-#if 0
- if (fpixels)
- pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
-#endif
+ return tex;
+}
- GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D");
+static GPUTexture *GPU_texture_cube_create(
+ int w, int d,
+ const float *fpixels_px, const float *fpixels_py, const float *fpixels_pz,
+ const float *fpixels_nx, const float *fpixels_ny, const float *fpixels_nz,
+ GPUTextureFormat tex_format, GPUDataFormat gpu_data_format,
+ char err_out[256])
+{
+ GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ tex->w = w;
+ tex->h = w;
+ tex->d = d;
+ tex->samples = 0;
+ tex->number = -1;
+ tex->refcount = 1;
+ tex->format = tex_format;
+ tex->components = gpu_get_component_count(tex_format);
+ tex->bytesize = gpu_get_bytesize(tex_format);
+ tex->format_flag = GPU_FORMAT_CUBE;
- /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it
- * for gooseberry */
- if (rescale && fpixels) {
- /* FIXME: should these be floating point? */
- const unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth;
- float *tex3d = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->depth, "tex3d");
+ if (d == 0) {
+ tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP;
+ }
+ else {
+ BLI_assert(false && "Cubemap array Not implemented yet");
+ // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY;
+ }
- GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
+ GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+ GLenum data_format = gpu_get_gl_dataformat(tex_format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
- for (unsigned k = 0; k < tex->depth; k++) {
- for (unsigned j = 0; j < tex->h; j++) {
- for (unsigned i = 0; i < tex->w; i++) {
- /* obviously doing nearest filtering here,
- * it's going to be slow in any case, let's not make it worse */
- float xb = i * xf;
- float yb = j * yf;
- float zb = k * zf;
- unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
- unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
+ gpu_texture_memory_footprint_add(tex);
- if (channels == 4) {
- tex3d[offset * 4] = fpixels[offset_orig * 4];
- tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
- tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
- tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
- }
- else
- tex3d[offset] = fpixels[offset_orig];
- }
- }
- }
+ /* Generate Texture object */
+ tex->bindcode = GPU_tex_alloc();
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d);
+ if (!tex->bindcode) {
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUTexture: texture create failed\n");
+ else
+ fprintf(stderr, "GPUTexture: texture create failed\n");
+ GPU_texture_free(tex);
+ return NULL;
+ }
- MEM_freeN(tex3d);
+ glBindTexture(tex->target, tex->bindcode);
+
+ /* Upload Texture */
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_px);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_py);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_pz);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_nx);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_ny);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, fpixels_nz);
+
+ /* Texture Parameters */
+ if (GPU_texture_stencil(tex) || /* Does not support filtering */
+ GPU_texture_integer(tex) || /* Does not support filtering */
+ GPU_texture_depth(tex))
+ {
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
else {
- if (fpixels) {
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels);
- GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D");
- }
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
+ if (GPU_texture_depth(tex)) {
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ }
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
-
- if (pixels)
- MEM_freeN(pixels);
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
- GPU_texture_unbind(tex);
+ glBindTexture(tex->target, 0);
return tex;
}
-GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data, double time, int mipmap)
+/* Special buffer textures. tex_format must be compatible with the buffer content. */
+GPUTexture *GPU_texture_create_buffer(GPUTextureFormat tex_format, const GLuint buffer)
{
- int gputt;
- /* this binds a texture, so that's why to restore it to 0 */
- GLint bindcode = GPU_verify_image(ima, iuser, textarget, 0, 0, mipmap, is_data);
- GPU_update_image_time(ima, time);
+ GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ tex->number = -1;
+ tex->refcount = 1;
+ tex->format = tex_format;
+ tex->components = gpu_get_component_count(tex_format);
+ tex->format_flag = 0;
+ tex->target_base = tex->target = GL_TEXTURE_BUFFER;
+ tex->bytesize = gpu_get_bytesize(tex_format);
+
+ GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+
+ gpu_get_gl_dataformat(tex_format, &tex->format_flag);
+
+ if (!(ELEM(tex_format, GPU_R8, GPU_R16) ||
+ ELEM(tex_format, GPU_R16F, GPU_R32F) ||
+ ELEM(tex_format, GPU_R8I, GPU_R16I, GPU_R32I) ||
+ ELEM(tex_format, GPU_R8UI, GPU_R16UI, GPU_R32UI) ||
+ ELEM(tex_format, GPU_RG8, GPU_RG16) ||
+ ELEM(tex_format, GPU_RG16F, GPU_RG32F) ||
+ ELEM(tex_format, GPU_RG8I, GPU_RG16I, GPU_RG32I) ||
+ ELEM(tex_format, GPU_RG8UI, GPU_RG16UI, GPU_RG32UI) ||
+ //ELEM(tex_format, GPU_RGB32F, GPU_RGB32I, GPU_RGB32UI) || /* Not available until gl 4.0 */
+ ELEM(tex_format, GPU_RGBA8, GPU_RGBA16) ||
+ ELEM(tex_format, GPU_RGBA16F, GPU_RGBA32F) ||
+ ELEM(tex_format, GPU_RGBA8I, GPU_RGBA16I, GPU_RGBA32I) ||
+ ELEM(tex_format, GPU_RGBA8UI, GPU_RGBA16UI, GPU_RGBA32UI)))
+ {
+ fprintf(stderr, "GPUTexture: invalid format for texture buffer\n");
+ GPU_texture_free(tex);
+ return NULL;
+ }
- /* 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
- gputt = TEXTARGET_TEXTURE_CUBE_MAP;
+ /* Generate Texture object */
+ tex->bindcode = GPU_tex_alloc();
- if (ima->gputexture[gputt]) {
- ima->gputexture[gputt]->bindcode = bindcode;
- glBindTexture(textarget, 0);
- return ima->gputexture[gputt];
+ if (!tex->bindcode) {
+ fprintf(stderr, "GPUTexture: texture create failed\n");
+ GPU_texture_free(tex);
+ BLI_assert(0 && "glGenTextures failed: Are you sure a valid OGL context is active on this thread?\n");
+ return NULL;
}
+ glBindTexture(tex->target, tex->bindcode);
+ glTexBuffer(tex->target, internalformat, buffer);
+ glBindTexture(tex->target, 0);
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
+{
+ /* 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 */
+ /* (is any of this obsolete now that we don't glEnable/Disable textures?) */
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->bindcode = bindcode;
tex->number = -1;
tex->refcount = 1;
tex->target = textarget;
tex->target_base = textarget;
- tex->fromblender = 1;
-
- ima->gputexture[gputt] = tex;
+ tex->format = -1;
+ tex->components = -1;
+ tex->samples = 0;
if (!glIsTexture(tex->bindcode)) {
- GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
+ GPU_print_error_debug("Blender Texture Not Loaded");
}
else {
- GLint w, h, border;
+ GLint w, h;
GLenum gettarget;
@@ -417,14 +830,11 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
glBindTexture(textarget, tex->bindcode);
glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_HEIGHT, &h);
- glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_BORDER, &border);
-
- tex->w = w - border;
- tex->h = h - border;
+ tex->w = w;
+ tex->h = h;
+ glBindTexture(textarget, 0);
}
- glBindTexture(textarget, 0);
-
return tex;
}
@@ -452,11 +862,13 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
tex->refcount = 1;
tex->target = GL_TEXTURE_2D;
tex->target_base = GL_TEXTURE_2D;
+ tex->format = -1;
+ tex->components = -1;
prv->gputexture[0] = tex;
if (!glIsTexture(tex->bindcode)) {
- GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
+ GPU_print_error_debug("Blender Texture Not Loaded");
}
else {
GLint w, h;
@@ -475,114 +887,292 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
}
-GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256])
+GPUTexture *GPU_texture_create_1D(
+ int w, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, 0, 0, 1, pixels, tex_format, data_format, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256])
+GPUTexture *GPU_texture_create_1D_array(
+ int w, int h, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, 0, 1, pixels, tex_format, data_format, 0, false, err_out);
+}
- return tex;
+GPUTexture *GPU_texture_create_2D(
+ int w, int h, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
+{
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, tex_format, data_format, 0, false, err_out);
}
+
GPUTexture *GPU_texture_create_2D_multisample(
- int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256])
+ int w, int h, GPUTextureFormat tex_format, const float *pixels, int samples, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, 0, 2, pixels, tex_format, data_format, samples, false, err_out);
+}
- return tex;
+GPUTexture *GPU_texture_create_2D_array(
+ int w, int h, int d, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
+{
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, d, 2, pixels, tex_format, data_format, 0, false, err_out);
}
-GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
+GPUTexture *GPU_texture_create_3D(
+ int w, int h, int d, GPUTextureFormat tex_format, const float *pixels, char err_out[256])
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out);
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format);
+ return GPU_texture_create_nD(w, h, d, 3, pixels, tex_format, data_format, 0, true, err_out);
+}
- if (tex)
- GPU_texture_unbind(tex);
+GPUTexture *GPU_texture_create_cube(
+ int w, GPUTextureFormat tex_format, const float *fpixels, char err_out[256])
+{
+ const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz;
+ const int channels = gpu_get_component_count(tex_format);
+
+ if (fpixels) {
+ int face_ofs = w * w * channels;
+ fpixels_px = fpixels + 0 * face_ofs;
+ fpixels_nx = fpixels + 1 * face_ofs;
+ fpixels_py = fpixels + 2 * face_ofs;
+ fpixels_ny = fpixels + 3 * face_ofs;
+ fpixels_pz = fpixels + 4 * face_ofs;
+ fpixels_nz = fpixels + 5 * face_ofs;
+ }
+ else {
+ fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL;
+ }
- return tex;
+ return GPU_texture_cube_create(w, 0, fpixels_px, fpixels_py, fpixels_pz, fpixels_nx, fpixels_ny, fpixels_nz,
+ tex_format, GPU_DATA_FLOAT, err_out);
}
-GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256])
+
+GPUTexture *GPU_texture_create_from_vertbuf(GPUVertBuf *vert)
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out);
+ GPUVertFormat *format = &vert->format;
+ GPUVertAttr *attr = &format->attribs[0];
- if (tex)
- GPU_texture_unbind(tex);
+ /* Detect incompatible cases (not supported by texture buffers) */
+ BLI_assert(format->attr_len == 1 && vert->vbo_id != 0);
+ BLI_assert(attr->comp_len != 3); /* Not until OGL 4.0 */
+ BLI_assert(attr->comp_type != GPU_COMP_I10);
+ BLI_assert(attr->fetch_mode != GPU_FETCH_INT_TO_FLOAT);
- return tex;
+ uint byte_per_comp = attr->sz / attr->comp_len;
+ bool is_uint = ELEM(attr->comp_type, GPU_COMP_U8, GPU_COMP_U16, GPU_COMP_U32);
+
+ /* Cannot fetch signed int or 32bit ints as normalized float. */
+ if (attr->fetch_mode == GPU_FETCH_INT_TO_FLOAT_UNIT) {
+ BLI_assert(is_uint || byte_per_comp <= 2);
+ }
+
+ GPUTextureFormat data_type;
+ switch (attr->fetch_mode) {
+ case GPU_FETCH_FLOAT:
+ switch (attr->comp_len) {
+ case 1: data_type = GPU_R32F; break;
+ case 2: data_type = GPU_RG32F; break;
+ // case 3: data_type = GPU_RGB32F; break; /* Not supported */
+ default: data_type = GPU_RGBA32F; break;
+ }
+ break;
+ case GPU_FETCH_INT:
+ switch (attr->comp_len) {
+ case 1:
+ switch (byte_per_comp) {
+ case 1: data_type = (is_uint) ? GPU_R8UI : GPU_R8I; break;
+ case 2: data_type = (is_uint) ? GPU_R16UI : GPU_R16I; break;
+ default: data_type = (is_uint) ? GPU_R32UI : GPU_R32I; break;
+ }
+ break;
+ case 2:
+ switch (byte_per_comp) {
+ case 1: data_type = (is_uint) ? GPU_RG8UI : GPU_RG8I; break;
+ case 2: data_type = (is_uint) ? GPU_RG16UI : GPU_RG16I; break;
+ default: data_type = (is_uint) ? GPU_RG32UI : GPU_RG32I; break;
+ }
+ break;
+ default:
+ switch (byte_per_comp) {
+ case 1: data_type = (is_uint) ? GPU_RGBA8UI : GPU_RGBA8I; break;
+ case 2: data_type = (is_uint) ? GPU_RGBA16UI : GPU_RGBA16I; break;
+ default: data_type = (is_uint) ? GPU_RGBA32UI : GPU_RGBA32I; break;
+ }
+ break;
+ }
+ break;
+ case GPU_FETCH_INT_TO_FLOAT_UNIT:
+ switch (attr->comp_len) {
+ case 1: data_type = (byte_per_comp == 1) ? GPU_R8 : GPU_R16; break;
+ case 2: data_type = (byte_per_comp == 1) ? GPU_RG8 : GPU_RG16; break;
+ default: data_type = (byte_per_comp == 1) ? GPU_RGBA8 : GPU_RGBA16; break;
+ }
+ break;
+ default:
+ BLI_assert(0);
+ return NULL;
+ }
+
+ return GPU_texture_create_buffer(data_type, vert->vbo_id);
}
-/**
- * A shadow map for VSM needs two components (depth and depth^2)
- */
-GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
+void GPU_texture_add_mipmap(
+ GPUTexture *tex, GPUDataFormat gpu_data_format, int miplvl, const void *pixels)
{
- GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out);
+ BLI_assert((int)tex->format > -1);
+ BLI_assert(tex->components > -1);
- if (tex) {
- /* Now we tweak some of the settings */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gpu_validate_data_format(tex->format, gpu_data_format);
+
+ GLenum internalformat = gpu_get_gl_internalformat(tex->format);
+ GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
+
+ glBindTexture(tex->target, tex->bindcode);
- GPU_texture_unbind(tex);
+ int size[3];
+ GPU_texture_get_mipmap_size(tex, miplvl, size);
+
+ switch (tex->target) {
+ case GL_TEXTURE_1D:
+ glTexImage1D(tex->target, miplvl, internalformat, size[0], 0, data_format, data_type, pixels);
+ break;
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_1D_ARRAY:
+ glTexImage2D(tex->target, miplvl, internalformat, size[0], size[1], 0, data_format, data_type, pixels);
+ break;
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_2D_ARRAY:
+ glTexImage3D(tex->target, miplvl, internalformat, size[0], size[1], size[2], 0, data_format, data_type, pixels);
+ break;
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ /* Multisample textures cannot have mipmaps. */
+ default:
+ BLI_assert(!"tex->target mode not supported");
}
- return tex;
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, miplvl);
+
+ glBindTexture(tex->target, 0);
}
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
+void GPU_texture_update_sub(
+ GPUTexture *tex, GPUDataFormat gpu_data_format, const void *pixels,
+ int offset_x, int offset_y, int offset_z, int width, int height, int depth)
{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
+ BLI_assert((int)tex->format > -1);
+ BLI_assert(tex->components > -1);
- if (tex) {
- /* Now we tweak some of the settings */
- if (repeat) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
+ GLint alignment;
- GPU_texture_unbind(tex);
+ /* The default pack size for textures is 4, which won't work for byte based textures */
+ if (tex->bytesize == 1) {
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
- return tex;
+ glBindTexture(tex->target, tex->bindcode);
+ switch (tex->target) {
+ case GL_TEXTURE_1D:
+ glTexSubImage1D(tex->target, 0, offset_x, width, data_format, data_type, pixels);
+ break;
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_TEXTURE_1D_ARRAY:
+ glTexSubImage2D(
+ tex->target, 0, offset_x, offset_y,
+ width, height, data_format, data_type, pixels);
+ break;
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_2D_ARRAY:
+ glTexSubImage3D(
+ tex->target, 0, offset_x, offset_y, offset_z,
+ width, height, depth, data_format, data_type, pixels);
+ break;
+ default:
+ BLI_assert(!"tex->target mode not supported");
+ }
+
+ if (tex->bytesize == 1) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
+ }
+
+ glBindTexture(tex->target, 0);
}
-GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256])
+void *GPU_texture_read(GPUTexture *tex, GPUDataFormat gpu_data_format, int miplvl)
{
- GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
+ int size[3] = {0, 0, 0};
+ GPU_texture_get_mipmap_size(tex, miplvl, size);
- if (tex) {
- /* Now we tweak some of the settings */
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ gpu_validate_data_format(tex->format, gpu_data_format);
+
+ size_t buf_size = gpu_texture_memory_footprint_compute(tex);
+ size_t samples_count = max_ii(1, tex->samples);
+
+ samples_count *= size[0];
+ samples_count *= max_ii(1, size[1]);
+ samples_count *= max_ii(1, size[2]);
+ samples_count *= (GPU_texture_cube(tex)) ? 6 : 1;
- GPU_texture_unbind(tex);
+ switch (gpu_data_format) {
+ case GPU_DATA_FLOAT:
+ buf_size = sizeof(float) * samples_count * tex->components;
+ break;
+ case GPU_DATA_INT:
+ case GPU_DATA_UNSIGNED_INT:
+ buf_size = sizeof(int) * samples_count * tex->components;
+ break;
+ case GPU_DATA_UNSIGNED_INT_24_8:
+ case GPU_DATA_10_11_11_REV:
+ buf_size = sizeof(int) * samples_count;
+ break;
+ case GPU_DATA_UNSIGNED_BYTE:
+ break;
}
- return tex;
+ void *buf = MEM_mallocN(buf_size, "GPU_texture_read");
+
+ GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
+ GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
+
+ glBindTexture(tex->target, tex->bindcode);
+
+ if (GPU_texture_cube(tex)) {
+ int cube_face_size = buf_size / 6;
+ for (int i = 0; i < 6; ++i) {
+ glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, miplvl, data_format, data_type,
+ ((char *)buf) + cube_face_size * i);
+ }
+ }
+ else {
+ glGetTexImage(tex->target, miplvl, data_format, data_type, buf);
+ }
+
+ glBindTexture(tex->target, 0);
+
+ return buf;
+}
+
+void GPU_texture_update(GPUTexture *tex, GPUDataFormat data_format, const void *pixels)
+{
+ GPU_texture_update_sub(tex, data_format, pixels, 0, 0, 0, tex->w, tex->h, tex->d);
}
void GPU_invalid_tex_init(void)
{
+ memory_usage = 0;
const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
- GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
- GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
- GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
+ GG.invalid_tex_1D = GPU_texture_create_1D(1, GPU_RGBA8, color, NULL);
+ GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, GPU_RGBA8, color, NULL);
+ GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, GPU_RGBA8, color, NULL);
}
void GPU_invalid_tex_bind(int mode)
@@ -610,61 +1200,46 @@ void GPU_invalid_tex_free(void)
GPU_texture_free(GG.invalid_tex_3D);
}
-
void GPU_texture_bind(GPUTexture *tex, int number)
{
+ BLI_assert(number >= 0);
+
if (number >= GPU_max_textures()) {
fprintf(stderr, "Not enough texture slots.\n");
return;
}
if ((G.debug & G_DEBUG)) {
- if (tex->fb && GPU_framebuffer_bound(tex->fb)) {
- fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n");
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) {
+ fprintf(stderr,
+ "Feedback loop warning!: Attempting to bind "
+ "texture attached to current framebuffer!\n");
+ BLI_assert(0); /* Should never happen! */
+ break;
+ }
}
}
- if (number < 0)
- return;
-
- GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind");
+ glActiveTexture(GL_TEXTURE0 + number);
- GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
- if (number != 0) glActiveTexture(arbnumber);
- if (tex->bindcode != 0) {
- glBindTexture(tex->target_base, tex->bindcode);
- }
+ if (tex->bindcode != 0)
+ glBindTexture(tex->target, tex->bindcode);
else
GPU_invalid_tex_bind(tex->target_base);
- glEnable(tex->target_base);
- if (number != 0) glActiveTexture(GL_TEXTURE0);
tex->number = number;
-
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind");
}
void GPU_texture_unbind(GPUTexture *tex)
{
- if (tex->number >= GPU_max_textures()) {
- fprintf(stderr, "Not enough texture slots.\n");
- return;
- }
-
if (tex->number == -1)
return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
-
- GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
- if (tex->number != 0) glActiveTexture(arbnumber);
- glBindTexture(tex->target_base, 0);
- glDisable(tex->target_base);
- if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+ glBindTexture(tex->target, 0);
tex->number = -1;
-
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
}
int GPU_texture_bound_number(GPUTexture *tex)
@@ -672,39 +1247,120 @@ int GPU_texture_bound_number(GPUTexture *tex)
return tex->number;
}
-void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
+#define WARN_NOT_BOUND(_tex) do { \
+ if (_tex->number == -1) { \
+ fprintf(stderr, "Warning : Trying to set parameter on a texture not bound.\n"); \
+ BLI_assert(0); \
+ return; \
+ } \
+} while (0);
+
+void GPU_texture_generate_mipmap(GPUTexture *tex)
{
- if (tex->number >= GPU_max_textures()) {
- fprintf(stderr, "Not enough texture slots.\n");
- return;
+ WARN_NOT_BOUND(tex);
+
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+
+ if (GPU_texture_depth(tex)) {
+ /* Some drivers have bugs when using glGenerateMipmap with depth textures (see T56789).
+ * In this case we just create a complete texture with mipmaps manually without downsampling.
+ * You must initialize the texture levels using other methods like GPU_framebuffer_recursive_downsample(). */
+ int levels = 1 + floor(log2(max_ii(tex->w, tex->h)));
+ GPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format);
+ for (int i = 1; i < levels; ++i) {
+ GPU_texture_add_mipmap(tex, data_format, i, NULL);
+ }
+ glBindTexture(tex->target, tex->bindcode);
+ }
+ else {
+ glGenerateMipmap(tex->target_base);
}
+}
- if (tex->number == -1)
+void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare)
+{
+ WARN_NOT_BOUND(tex);
+
+ /* Could become an assertion ? (fclem) */
+ if (!GPU_texture_depth(tex))
return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
+ GLenum mode = (use_compare) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE;
- GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
- if (tex->number != 0) glActiveTexture(arbnumber);
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, mode);
+}
- if (tex->depth) {
- if (compare)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- else
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
- }
+void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter)
+{
+ WARN_NOT_BOUND(tex);
- if (use_filter) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
- else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ /* Stencil and integer format does not support filtering. */
+ BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
+
+ GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST;
+
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter);
+}
+
+void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter)
+{
+ WARN_NOT_BOUND(tex);
+
+ /* Stencil and integer format does not support filtering. */
+ BLI_assert((!use_filter && !use_mipmap) || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
+
+ GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST;
+ GLenum mipmap = (
+ (use_filter) ?
+ (use_mipmap) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR :
+ (use_mipmap) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
+
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter);
+}
+
+void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat)
+{
+ WARN_NOT_BOUND(tex);
+
+ GLenum repeat = (use_repeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE;
+
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat);
+ if (tex->target_base != GL_TEXTURE_1D)
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat);
+ if (tex->target_base == GL_TEXTURE_3D)
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat);
+}
+
+static GLenum gpu_get_gl_filterfunction(GPUFilterFunction filter)
+{
+ switch (filter) {
+ case GPU_NEAREST:
+ return GL_NEAREST;
+ case GPU_LINEAR:
+ return GL_LINEAR;
+ default:
+ BLI_assert(!"Unhandled filter mode");
+ return GL_NEAREST;
}
- if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
+}
+
+void GPU_texture_filters(GPUTexture *tex, GPUFilterFunction min_filter, GPUFilterFunction mag_filter)
+{
+ WARN_NOT_BOUND(tex);
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
+ /* Stencil and integer format does not support filtering. */
+ BLI_assert(!(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
+ BLI_assert(mag_filter == GPU_NEAREST || mag_filter == GPU_LINEAR);
+
+ glActiveTexture(GL_TEXTURE0 + tex->number);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, gpu_get_gl_filterfunction(min_filter));
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, gpu_get_gl_filterfunction(mag_filter));
}
void GPU_texture_free(GPUTexture *tex)
@@ -715,10 +1371,16 @@ void GPU_texture_free(GPUTexture *tex)
fprintf(stderr, "GPUTexture: negative refcount\n");
if (tex->refcount == 0) {
- if (tex->fb)
- GPU_framebuffer_texture_detach(tex);
- if (tex->bindcode && !tex->fromblender)
- glDeleteTextures(1, &tex->bindcode);
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ if (tex->fb[i] != NULL) {
+ GPU_framebuffer_texture_detach_slot(tex->fb[i], tex, tex->fb_attachment[i]);
+ }
+ }
+
+ if (tex->bindcode)
+ GPU_tex_free(tex->bindcode);
+
+ gpu_texture_memory_footprint_remove(tex);
MEM_freeN(tex);
}
@@ -744,9 +1406,39 @@ int GPU_texture_height(const GPUTexture *tex)
return tex->h;
}
-int GPU_texture_depth(const GPUTexture *tex)
+int GPU_texture_layers(const GPUTexture *tex)
+{
+ return tex->d;
+}
+
+GPUTextureFormat GPU_texture_format(const GPUTexture *tex)
+{
+ return tex->format;
+}
+
+int GPU_texture_samples(const GPUTexture *tex)
+{
+ return tex->samples;
+}
+
+bool GPU_texture_depth(const GPUTexture *tex)
+{
+ return (tex->format_flag & GPU_FORMAT_DEPTH) != 0;
+}
+
+bool GPU_texture_stencil(const GPUTexture *tex)
+{
+ return (tex->format_flag & GPU_FORMAT_STENCIL) != 0;
+}
+
+bool GPU_texture_integer(const GPUTexture *tex)
+{
+ return (tex->format_flag & GPU_FORMAT_INTEGER) != 0;
+}
+
+bool GPU_texture_cube(const GPUTexture *tex)
{
- return tex->depth;
+ return (tex->format_flag & GPU_FORMAT_CUBE) != 0;
}
int GPU_texture_opengl_bindcode(const GPUTexture *tex)
@@ -754,18 +1446,50 @@ int GPU_texture_opengl_bindcode(const GPUTexture *tex)
return tex->bindcode;
}
-GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
+void GPU_texture_attach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb, int attachment)
{
- return tex->fb;
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ if (tex->fb[i] == NULL) {
+ tex->fb[i] = fb;
+ tex->fb_attachment[i] = attachment;
+ return;
+ }
+ }
+
+ BLI_assert(!"Error: Texture: Not enough Framebuffer slots");
}
-int GPU_texture_framebuffer_attachment(GPUTexture *tex)
+/* Return previous attachment point */
+int GPU_texture_detach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb)
{
- return tex->fb_attachment;
+ for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) {
+ if (tex->fb[i] == fb) {
+ tex->fb[i] = NULL;
+ return tex->fb_attachment[i];
+ }
+ }
+
+ BLI_assert(!"Error: Texture: Framebuffer is not attached");
+ return 0;
}
-void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment)
+void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size)
{
- tex->fb = fb;
- tex->fb_attachment = attachment;
+ /* TODO assert if lvl is below the limit of 1px in each dimension. */
+ int div = 1 << lvl;
+ size[0] = max_ii(1, tex->w / div);
+
+ if (tex->target == GL_TEXTURE_1D_ARRAY) {
+ size[1] = tex->h;
+ }
+ else if (tex->h > 0) {
+ size[1] = max_ii(1, tex->h / div);
+ }
+
+ if (tex->target == GL_TEXTURE_2D_ARRAY) {
+ size[2] = tex->d;
+ }
+ else if (tex->d > 0) {
+ size[2] = max_ii(1, tex->d / div);
+ }
}
diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c
new file mode 100644
index 00000000000..9bc3727bb03
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_uniformbuffer.c
@@ -0,0 +1,345 @@
+/*
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Clement Foucault.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gpu_uniformbuffer.c
+ * \ingroup gpu
+ */
+
+#include <string.h>
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "gpu_codegen.h"
+#include "gpu_context_private.h"
+
+#include "GPU_extensions.h"
+#include "GPU_glew.h"
+#include "GPU_material.h"
+#include "GPU_uniformbuffer.h"
+
+typedef enum GPUUniformBufferFlag {
+ GPU_UBO_FLAG_INITIALIZED = (1 << 0),
+ GPU_UBO_FLAG_DIRTY = (1 << 1),
+} GPUUniformBufferFlag;
+
+typedef enum GPUUniformBufferType {
+ GPU_UBO_STATIC = 0,
+ GPU_UBO_DYNAMIC = 1,
+} GPUUniformBufferType;
+
+struct GPUUniformBuffer {
+ int size; /* in bytes */
+ GLuint bindcode; /* opengl identifier for UBO */
+ int bindpoint; /* current binding point */
+ GPUUniformBufferType type;
+};
+
+#define GPUUniformBufferStatic GPUUniformBuffer
+
+typedef struct GPUUniformBufferDynamic {
+ GPUUniformBuffer buffer;
+ void *data; /* Continuous memory block to copy to GPU. */
+ char flag;
+} GPUUniformBufferDynamic;
+
+/* Prototypes */
+static GPUType get_padded_gpu_type(struct LinkData *link);
+static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs);
+
+/* Only support up to this type, if you want to extend it, make sure the
+ * padding logic is correct for the new types. */
+#define MAX_UBO_GPU_TYPE GPU_VEC4
+
+static void gpu_uniformbuffer_initialize(GPUUniformBuffer *ubo, const void *data)
+{
+ glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
+ glBufferData(GL_UNIFORM_BUFFER, ubo->size, data, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+}
+
+GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256])
+{
+ GPUUniformBuffer *ubo = MEM_callocN(sizeof(GPUUniformBufferStatic), "GPUUniformBufferStatic");
+ ubo->size = size;
+ ubo->bindpoint = -1;
+
+ /* Generate Buffer object */
+ ubo->bindcode = GPU_buf_alloc();
+
+ if (!ubo->bindcode) {
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed");
+ GPU_uniformbuffer_free(ubo);
+ return NULL;
+ }
+
+ if (ubo->size > GPU_max_ubo_size()) {
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big");
+ GPU_uniformbuffer_free(ubo);
+ return NULL;
+ }
+
+ gpu_uniformbuffer_initialize(ubo, data);
+ return ubo;
+}
+
+/**
+ * Create dynamic UBO from parameters
+ * Return NULL if failed to create or if \param inputs is empty.
+ *
+ * \param inputs ListBase of BLI_genericNodeN(GPUInput)
+ */
+GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_out[256])
+{
+ /* There is no point on creating an UBO if there is no arguments. */
+ if (BLI_listbase_is_empty(inputs)) {
+ return NULL;
+ }
+
+ GPUUniformBufferDynamic *ubo = MEM_callocN(sizeof(GPUUniformBufferDynamic), "GPUUniformBufferDynamic");
+ ubo->buffer.type = GPU_UBO_DYNAMIC;
+ ubo->buffer.bindpoint = -1;
+ ubo->flag = GPU_UBO_FLAG_DIRTY;
+
+ /* Generate Buffer object. */
+ ubo->buffer.bindcode = GPU_buf_alloc();
+
+ if (!ubo->buffer.bindcode) {
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed");
+ GPU_uniformbuffer_free(&ubo->buffer);
+ return NULL;
+ }
+
+ if (ubo->buffer.size > GPU_max_ubo_size()) {
+ if (err_out)
+ BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big");
+ GPU_uniformbuffer_free(&ubo->buffer);
+ return NULL;
+ }
+
+ /* Make sure we comply to the ubo alignment requirements. */
+ gpu_uniformbuffer_inputs_sort(inputs);
+
+ for (LinkData *link = inputs->first; link; link = link->next) {
+ const GPUType gputype = get_padded_gpu_type(link);
+ ubo->buffer.size += gputype * sizeof(float);
+ }
+
+ /* Allocate the data. */
+ ubo->data = MEM_mallocN(ubo->buffer.size, __func__);
+
+ /* Now that we know the total ubo size we can start populating it. */
+ float *offset = ubo->data;
+ for (LinkData *link = inputs->first; link; link = link->next) {
+ GPUInput *input = link->data;
+ memcpy(offset, input->vec, input->type * sizeof(float));
+ offset += get_padded_gpu_type(link);
+ }
+
+ /* Note since we may create the UBOs in the CPU in a different thread than the main drawing one,
+ * we don't create the UBO in the GPU here. This will happen when we first bind the UBO.
+ */
+
+ return &ubo->buffer;
+}
+
+/**
+ * Free the data
+ */
+static void gpu_uniformbuffer_dynamic_free(GPUUniformBuffer *ubo_)
+{
+ BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
+ GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
+
+ ubo->buffer.size = 0;
+ if (ubo->data) {
+ MEM_freeN(ubo->data);
+ }
+}
+
+void GPU_uniformbuffer_free(GPUUniformBuffer *ubo)
+{
+ if (ubo->type == GPU_UBO_DYNAMIC) {
+ gpu_uniformbuffer_dynamic_free(ubo);
+ }
+
+ GPU_buf_free(ubo->bindcode);
+ MEM_freeN(ubo);
+}
+
+static void gpu_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
+{
+ glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+}
+
+void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
+{
+ BLI_assert(ubo->type == GPU_UBO_STATIC);
+ gpu_uniformbuffer_update(ubo, data);
+}
+
+/**
+ * We need to recalculate the internal data, and re-generate it
+ * from its populated items.
+ */
+void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_)
+{
+ BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
+ GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
+
+ if (ubo->flag & GPU_UBO_FLAG_INITIALIZED) {
+ gpu_uniformbuffer_update(ubo_, ubo->data);
+ }
+ else {
+ ubo->flag |= GPU_UBO_FLAG_INITIALIZED;
+ gpu_uniformbuffer_initialize(ubo_, ubo->data);
+ }
+
+ ubo->flag &= ~GPU_UBO_FLAG_DIRTY;
+}
+
+/**
+ * We need to pad some data types (vec3) on the C side
+ * To match the GPU expected memory block alignment.
+ */
+static GPUType get_padded_gpu_type(LinkData *link)
+{
+ GPUInput *input = link->data;
+ GPUType gputype = input->type;
+
+ /* Unless the vec3 is followed by a float we need to treat it as a vec4. */
+ if (gputype == GPU_VEC3 &&
+ (link->next != NULL) &&
+ (((GPUInput *)link->next->data)->type != GPU_FLOAT))
+ {
+ gputype = GPU_VEC4;
+ }
+
+ return gputype;
+}
+
+/**
+ * Returns 1 if the first item shold be after second item.
+ * We make sure the vec4 uniforms come first.
+ */
+static int inputs_cmp(const void *a, const void *b)
+{
+ const LinkData *link_a = a, *link_b = b;
+ const GPUInput *input_a = link_a->data, *input_b = link_b->data;
+ return input_a->type < input_b->type ? 1 : 0;
+}
+
+/**
+ * Make sure we respect the expected alignment of UBOs.
+ * vec4, pad vec3 as vec4, then vec2, then floats.
+ */
+static void gpu_uniformbuffer_inputs_sort(ListBase *inputs)
+{
+ /* Order them as vec4, vec3, vec2, float. */
+ BLI_listbase_sort(inputs, inputs_cmp);
+
+ /* Creates a lookup table for the different types; */
+ LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {NULL};
+ GPUType cur_type = MAX_UBO_GPU_TYPE + 1;
+
+ for (LinkData *link = inputs->first; link; link = link->next) {
+ GPUInput *input = link->data;
+ if (input->type == cur_type) {
+ continue;
+ }
+ else {
+ inputs_lookup[input->type] = link;
+ cur_type = input->type;
+ }
+ }
+
+ /* If there is no GPU_VEC3 there is no need for alignment. */
+ if (inputs_lookup[GPU_VEC3] == NULL) {
+ return;
+ }
+
+ LinkData *link = inputs_lookup[GPU_VEC3];
+ while (link != NULL && ((GPUInput *)link->data)->type == GPU_VEC3) {
+ LinkData *link_next = link->next;
+
+ /* If GPU_VEC3 is followed by nothing or a GPU_FLOAT, no need for alignment. */
+ if ((link_next == NULL) ||
+ ((GPUInput *)link_next->data)->type == GPU_FLOAT)
+ {
+ break;
+ }
+
+ /* If there is a float, move it next to current vec3. */
+ if (inputs_lookup[GPU_FLOAT] != NULL) {
+ LinkData *float_input = inputs_lookup[GPU_FLOAT];
+ inputs_lookup[GPU_FLOAT] = float_input->next;
+
+ BLI_remlink(inputs, float_input);
+ BLI_insertlinkafter(inputs, link, float_input);
+ }
+
+ link = link_next;
+ }
+}
+
+void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number)
+{
+ if (number >= GPU_max_ubo_binds()) {
+ fprintf(stderr, "Not enough UBO slots.\n");
+ return;
+ }
+
+ if (ubo->type == GPU_UBO_DYNAMIC) {
+ GPUUniformBufferDynamic *ubo_dynamic = (GPUUniformBufferDynamic *)ubo;
+ if (ubo_dynamic->flag & GPU_UBO_FLAG_DIRTY) {
+ GPU_uniformbuffer_dynamic_update(ubo);
+ }
+ }
+
+ if (ubo->bindcode != 0) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode);
+ }
+
+ ubo->bindpoint = number;
+}
+
+void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo)
+{
+ ubo->bindpoint = -1;
+}
+
+int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo)
+{
+ return ubo->bindpoint;
+}
+
+#undef MAX_UBO_GPU_TYPE
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c
new file mode 100644
index 00000000000..b6058a2cb79
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.c
@@ -0,0 +1,272 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Clément Foucault
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_vertex_buffer.c
+ * \ingroup gpu
+ *
+ * GPU vertex buffer
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_vertex_buffer.h"
+
+#include "gpu_context_private.h"
+#include "gpu_vertex_format_private.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#define KEEP_SINGLE_COPY 1
+
+static uint vbo_memory_usage;
+
+static GLenum convert_usage_type_to_gl(GPUUsageType type)
+{
+ static const GLenum table[] = {
+ [GPU_USAGE_STREAM] = GL_STREAM_DRAW,
+ [GPU_USAGE_STATIC] = GL_STATIC_DRAW,
+ [GPU_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW
+ };
+ return table[type];
+}
+
+GPUVertBuf *GPU_vertbuf_create(GPUUsageType usage)
+{
+ GPUVertBuf *verts = MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf");
+ GPU_vertbuf_init(verts, usage);
+ return verts;
+}
+
+GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *format, GPUUsageType usage)
+{
+ GPUVertBuf *verts = GPU_vertbuf_create(usage);
+ GPU_vertformat_copy(&verts->format, format);
+ if (!format->packed) {
+ VertexFormat_pack(&verts->format);
+ }
+ return verts;
+
+ /* this function might seem redundant, but there is potential for memory savings here... */
+ /* TODO: implement those memory savings */
+}
+
+void GPU_vertbuf_init(GPUVertBuf *verts, GPUUsageType usage)
+{
+ memset(verts, 0, sizeof(GPUVertBuf));
+ verts->usage = usage;
+ verts->dirty = true;
+}
+
+void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts, const GPUVertFormat *format, GPUUsageType usage)
+{
+ GPU_vertbuf_init(verts, usage);
+ GPU_vertformat_copy(&verts->format, format);
+ if (!format->packed) {
+ VertexFormat_pack(&verts->format);
+ }
+}
+
+void GPU_vertbuf_discard(GPUVertBuf *verts)
+{
+ if (verts->vbo_id) {
+ GPU_buf_free(verts->vbo_id);
+#if VRAM_USAGE
+ vbo_memory_usage -= GPU_vertbuf_size_get(verts);
+#endif
+ }
+ if (verts->data) {
+ MEM_freeN(verts->data);
+ }
+ MEM_freeN(verts);
+}
+
+uint GPU_vertbuf_size_get(const GPUVertBuf *verts)
+{
+ return vertex_buffer_size(&verts->format, verts->vertex_len);
+}
+
+/* create a new allocation, discarding any existing data */
+void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
+{
+ GPUVertFormat *format = &verts->format;
+ if (!format->packed) {
+ VertexFormat_pack(format);
+ }
+#if TRUST_NO_ONE
+ /* catch any unnecessary use */
+ assert(verts->vertex_alloc != v_len || verts->data == NULL);
+#endif
+ /* only create the buffer the 1st time */
+ if (verts->vbo_id == 0) {
+ verts->vbo_id = GPU_buf_alloc();
+ }
+ /* discard previous data if any */
+ if (verts->data) {
+ MEM_freeN(verts->data);
+ }
+#if VRAM_USAGE
+ uint new_size = vertex_buffer_size(&verts->format, v_len);
+ vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts);
+#endif
+ verts->dirty = true;
+ verts->vertex_len = verts->vertex_alloc = v_len;
+ verts->data = MEM_mallocN(sizeof(GLubyte) * GPU_vertbuf_size_get(verts), "GPUVertBuf data");
+}
+
+/* resize buffer keeping existing data */
+void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len)
+{
+#if TRUST_NO_ONE
+ assert(verts->data != NULL);
+ assert(verts->vertex_alloc != v_len);
+#endif
+
+#if VRAM_USAGE
+ uint new_size = vertex_buffer_size(&verts->format, v_len);
+ vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts);
+#endif
+ verts->dirty = true;
+ verts->vertex_len = verts->vertex_alloc = v_len;
+ verts->data = MEM_reallocN(verts->data, sizeof(GLubyte) * GPU_vertbuf_size_get(verts));
+}
+
+/* Set vertex count but does not change allocation.
+ * Only this many verts will be uploaded to the GPU and rendered.
+ * This is useful for streaming data. */
+void GPU_vertbuf_vertex_count_set(GPUVertBuf *verts, uint v_len)
+{
+#if TRUST_NO_ONE
+ assert(verts->data != NULL); /* only for dynamic data */
+ assert(v_len <= verts->vertex_alloc);
+#endif
+
+#if VRAM_USAGE
+ uint new_size = vertex_buffer_size(&verts->format, v_len);
+ vbo_memory_usage += new_size - GPU_vertbuf_size_get(verts);
+#endif
+ verts->vertex_len = v_len;
+}
+
+void GPU_vertbuf_attr_set(GPUVertBuf *verts, uint a_idx, uint v_idx, const void *data)
+{
+ const GPUVertFormat *format = &verts->format;
+ const GPUVertAttr *a = format->attribs + a_idx;
+
+#if TRUST_NO_ONE
+ assert(a_idx < format->attr_len);
+ assert(v_idx < verts->vertex_alloc);
+ assert(verts->data != NULL);
+#endif
+ verts->dirty = true;
+ memcpy((GLubyte *)verts->data + a->offset + v_idx * format->stride, data, a->sz);
+}
+
+void GPU_vertbuf_attr_fill(GPUVertBuf *verts, uint a_idx, const void *data)
+{
+ const GPUVertFormat *format = &verts->format;
+ const GPUVertAttr *a = format->attribs + a_idx;
+
+#if TRUST_NO_ONE
+ assert(a_idx < format->attr_len);
+#endif
+ const uint stride = a->sz; /* tightly packed input data */
+
+ GPU_vertbuf_attr_fill_stride(verts, a_idx, stride, data);
+}
+
+void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts, uint a_idx, uint stride, const void *data)
+{
+ const GPUVertFormat *format = &verts->format;
+ const GPUVertAttr *a = format->attribs + a_idx;
+
+#if TRUST_NO_ONE
+ assert(a_idx < format->attr_len);
+ assert(verts->data != NULL);
+#endif
+ verts->dirty = true;
+ const uint vertex_len = verts->vertex_len;
+
+ if (format->attr_len == 1 && stride == format->stride) {
+ /* we can copy it all at once */
+ memcpy(verts->data, data, vertex_len * a->sz);
+ }
+ else {
+ /* we must copy it per vertex */
+ for (uint v = 0; v < vertex_len; ++v) {
+ memcpy((GLubyte *)verts->data + a->offset + v * format->stride, (const GLubyte *)data + v * stride, a->sz);
+ }
+ }
+}
+
+void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts, uint a_idx, GPUVertBufRaw *access)
+{
+ const GPUVertFormat *format = &verts->format;
+ const GPUVertAttr *a = format->attribs + a_idx;
+
+#if TRUST_NO_ONE
+ assert(a_idx < format->attr_len);
+ assert(verts->data != NULL);
+#endif
+
+ verts->dirty = true;
+
+ access->size = a->sz;
+ access->stride = format->stride;
+ access->data = (GLubyte *)verts->data + a->offset;
+ access->data_init = access->data;
+#if TRUST_NO_ONE
+ access->_data_end = access->data_init + (size_t)(verts->vertex_alloc * format->stride);
+#endif
+}
+
+static void VertBuffer_upload_data(GPUVertBuf *verts)
+{
+ uint buffer_sz = GPU_vertbuf_size_get(verts);
+
+ /* orphan the vbo to avoid sync */
+ glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage));
+ /* upload data */
+ glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data);
+
+ if (verts->usage == GPU_USAGE_STATIC) {
+ MEM_freeN(verts->data);
+ verts->data = NULL;
+ }
+ verts->dirty = false;
+}
+
+void GPU_vertbuf_use(GPUVertBuf *verts)
+{
+ glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
+ if (verts->dirty) {
+ VertBuffer_upload_data(verts);
+ }
+}
+
+uint GPU_vertbuf_get_memory_usage(void)
+{
+ return vbo_memory_usage;
+}
diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c
new file mode 100644
index 00000000000..c3de3d52b47
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_vertex_format.c
@@ -0,0 +1,438 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Clément Foucault
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_vertex_format.c
+ * \ingroup gpu
+ *
+ * GPU vertex format
+ */
+
+#include "GPU_shader_interface.h"
+
+#include "GPU_vertex_format.h"
+#include "gpu_vertex_format_private.h"
+#include <stddef.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+#define PACK_DEBUG 0
+
+#if PACK_DEBUG
+# include <stdio.h>
+#endif
+
+void GPU_vertformat_clear(GPUVertFormat *format)
+{
+#if TRUST_NO_ONE
+ memset(format, 0, sizeof(GPUVertFormat));
+#else
+ format->attr_len = 0;
+ format->packed = false;
+ format->name_offset = 0;
+ format->name_len = 0;
+
+ for (uint i = 0; i < GPU_VERT_ATTR_MAX_LEN; i++) {
+ format->attribs[i].name_len = 0;
+ }
+#endif
+}
+
+void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src)
+{
+ /* copy regular struct fields */
+ memcpy(dest, src, sizeof(GPUVertFormat));
+
+ for (uint i = 0; i < dest->attr_len; i++) {
+ for (uint j = 0; j < dest->attribs[i].name_len; j++) {
+ dest->attribs[i].name[j] = (char *)dest + (src->attribs[i].name[j] - ((char *)src));
+ }
+ }
+}
+
+static GLenum convert_comp_type_to_gl(GPUVertCompType type)
+{
+ static const GLenum table[] = {
+ [GPU_COMP_I8] = GL_BYTE,
+ [GPU_COMP_U8] = GL_UNSIGNED_BYTE,
+ [GPU_COMP_I16] = GL_SHORT,
+ [GPU_COMP_U16] = GL_UNSIGNED_SHORT,
+ [GPU_COMP_I32] = GL_INT,
+ [GPU_COMP_U32] = GL_UNSIGNED_INT,
+
+ [GPU_COMP_F32] = GL_FLOAT,
+
+ [GPU_COMP_I10] = GL_INT_2_10_10_10_REV
+ };
+ return table[type];
+}
+
+static uint comp_sz(GPUVertCompType type)
+{
+#if TRUST_NO_ONE
+ assert(type <= GPU_COMP_F32); /* other types have irregular sizes (not bytes) */
+#endif
+ const GLubyte sizes[] = {1, 1, 2, 2, 4, 4, 4};
+ return sizes[type];
+}
+
+static uint attrib_sz(const GPUVertAttr *a)
+{
+ if (a->comp_type == GPU_COMP_I10) {
+ return 4; /* always packed as 10_10_10_2 */
+ }
+ return a->comp_len * comp_sz(a->comp_type);
+}
+
+static uint attrib_align(const GPUVertAttr *a)
+{
+ if (a->comp_type == GPU_COMP_I10) {
+ return 4; /* always packed as 10_10_10_2 */
+ }
+ uint c = comp_sz(a->comp_type);
+ if (a->comp_len == 3 && c <= 2) {
+ return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */
+ }
+ else {
+ return c; /* most fetches are ok if components are naturally aligned */
+ }
+}
+
+uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len)
+{
+#if TRUST_NO_ONE
+ assert(format->packed && format->stride > 0);
+#endif
+ return format->stride * vertex_len;
+}
+
+static const char *copy_attrib_name(GPUVertFormat *format, const char *name)
+{
+ /* strncpy does 110% of what we need; let's do exactly 100% */
+ char *name_copy = format->names + format->name_offset;
+ uint available = GPU_VERT_ATTR_NAMES_BUF_LEN - format->name_offset;
+ bool terminated = false;
+
+ for (uint i = 0; i < available; ++i) {
+ const char c = name[i];
+ name_copy[i] = c;
+ if (c == '\0') {
+ terminated = true;
+ format->name_offset += (i + 1);
+ break;
+ }
+ }
+#if TRUST_NO_ONE
+ assert(terminated);
+ assert(format->name_offset <= GPU_VERT_ATTR_NAMES_BUF_LEN);
+#else
+ (void)terminated;
+#endif
+ return name_copy;
+}
+
+uint GPU_vertformat_attr_add(
+ GPUVertFormat *format, const char *name,
+ GPUVertCompType comp_type, uint comp_len, GPUVertFetchMode fetch_mode)
+{
+#if TRUST_NO_ONE
+ assert(format->name_len < GPU_VERT_ATTR_MAX_LEN); /* there's room for more */
+ assert(format->attr_len < GPU_VERT_ATTR_MAX_LEN); /* there's room for more */
+ assert(!format->packed); /* packed means frozen/locked */
+ assert((comp_len >= 1 && comp_len <= 4) || comp_len == 8 || comp_len == 12 || comp_len == 16);
+
+ switch (comp_type) {
+ case GPU_COMP_F32:
+ /* float type can only kept as float */
+ assert(fetch_mode == GPU_FETCH_FLOAT);
+ break;
+ case GPU_COMP_I10:
+ /* 10_10_10 format intended for normals (xyz) or colors (rgb)
+ * extra component packed.w can be manually set to { -2, -1, 0, 1 } */
+ assert(comp_len == 3 || comp_len == 4);
+ assert(fetch_mode == GPU_FETCH_INT_TO_FLOAT_UNIT); /* not strictly required, may relax later */
+ break;
+ default:
+ /* integer types can be kept as int or converted/normalized to float */
+ assert(fetch_mode != GPU_FETCH_FLOAT);
+ /* only support float matrices (see Batch_update_program_bindings) */
+ assert(comp_len != 8 && comp_len != 12 && comp_len != 16);
+ }
+#endif
+ format->name_len++; /* multiname support */
+
+ const uint attrib_id = format->attr_len++;
+ GPUVertAttr *attrib = format->attribs + attrib_id;
+
+ attrib->name[attrib->name_len++] = copy_attrib_name(format, name);
+ attrib->comp_type = comp_type;
+ attrib->gl_comp_type = convert_comp_type_to_gl(comp_type);
+ attrib->comp_len = (comp_type == GPU_COMP_I10) ? 4 : comp_len; /* system needs 10_10_10_2 to be 4 or BGRA */
+ attrib->sz = attrib_sz(attrib);
+ attrib->offset = 0; /* offsets & stride are calculated later (during pack) */
+ attrib->fetch_mode = fetch_mode;
+
+ return attrib_id;
+}
+
+void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
+{
+ GPUVertAttr *attrib = format->attribs + (format->attr_len - 1);
+#if TRUST_NO_ONE
+ assert(format->name_len < GPU_VERT_ATTR_MAX_LEN); /* there's room for more */
+ assert(attrib->name_len < GPU_VERT_ATTR_MAX_NAMES);
+#endif
+ format->name_len++; /* multiname support */
+ attrib->name[attrib->name_len++] = copy_attrib_name(format, alias);
+}
+
+int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name)
+{
+ for (int i = 0; i < format->attr_len; i++) {
+ const GPUVertAttr *attrib = format->attribs + i;
+ for (int j = 0; j < attrib->name_len; j++) {
+ if (STREQ(name, attrib->name[j])) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+uint padding(uint offset, uint alignment)
+{
+ const uint mod = offset % alignment;
+ return (mod == 0) ? 0 : (alignment - mod);
+}
+
+#if PACK_DEBUG
+static void show_pack(uint a_idx, uint sz, uint pad)
+{
+ const char c = 'A' + a_idx;
+ for (uint i = 0; i < pad; ++i) {
+ putchar('-');
+ }
+ for (uint i = 0; i < sz; ++i) {
+ putchar(c);
+ }
+}
+#endif
+
+void VertexFormat_pack(GPUVertFormat *format)
+{
+ /* For now, attributes are packed in the order they were added,
+ * making sure each attrib is naturally aligned (add padding where necessary)
+ * Later we can implement more efficient packing w/ reordering
+ * (keep attrib ID order, adjust their offsets to reorder in buffer). */
+
+ /* TODO: realloc just enough to hold the final combo string. And just enough to
+ * hold used attribs, not all 16. */
+
+ GPUVertAttr *a0 = format->attribs + 0;
+ a0->offset = 0;
+ uint offset = a0->sz;
+
+#if PACK_DEBUG
+ show_pack(0, a0->sz, 0);
+#endif
+
+ for (uint a_idx = 1; a_idx < format->attr_len; ++a_idx) {
+ GPUVertAttr *a = format->attribs + a_idx;
+ uint mid_padding = padding(offset, attrib_align(a));
+ offset += mid_padding;
+ a->offset = offset;
+ offset += a->sz;
+
+#if PACK_DEBUG
+ show_pack(a_idx, a->sz, mid_padding);
+#endif
+ }
+
+ uint end_padding = padding(offset, attrib_align(a0));
+
+#if PACK_DEBUG
+ show_pack(0, 0, end_padding);
+ putchar('\n');
+#endif
+ format->stride = offset + end_padding;
+ format->packed = true;
+}
+
+static uint calc_input_component_size(const GPUShaderInput *input)
+{
+ int size = input->size;
+ switch (input->gl_type) {
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ return size * 2;
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ return size * 3;
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ return size * 4;
+ case GL_FLOAT_MAT3:
+ return size * 9;
+ case GL_FLOAT_MAT4:
+ return size * 16;
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT3x2:
+ return size * 6;
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT4x2:
+ return size * 8;
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x3:
+ return size * 12;
+ default:
+ return size;
+ }
+}
+
+static void get_fetch_mode_and_comp_type(
+ int gl_type,
+ GPUVertCompType *r_comp_type,
+ uint *r_gl_comp_type,
+ GPUVertFetchMode *r_fetch_mode)
+{
+ switch (gl_type) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ *r_comp_type = GPU_COMP_F32;
+ *r_gl_comp_type = GL_FLOAT;
+ *r_fetch_mode = GPU_FETCH_FLOAT;
+ break;
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ *r_comp_type = GPU_COMP_I32;
+ *r_gl_comp_type = GL_INT;
+ *r_fetch_mode = GPU_FETCH_INT;
+ break;
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ *r_comp_type = GPU_COMP_U32;
+ *r_gl_comp_type = GL_UNSIGNED_INT;
+ *r_fetch_mode = GPU_FETCH_INT;
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterface *shaderface)
+{
+ const char *name_buffer = shaderface->name_buffer;
+
+ for (int i = 0; i < GPU_NUM_SHADERINTERFACE_BUCKETS; i++) {
+ const GPUShaderInput *input = shaderface->attrib_buckets[i];
+ if (input == NULL) {
+ continue;
+ }
+
+ const GPUShaderInput *next = input;
+ while (next != NULL) {
+ input = next;
+ next = input->next;
+
+ format->name_len++; /* multiname support */
+ format->attr_len++;
+
+ GPUVertAttr *attrib = format->attribs + input->location;
+
+ attrib->name[attrib->name_len++] = copy_attrib_name(format, name_buffer + input->name_offset);
+ attrib->offset = 0; /* offsets & stride are calculated later (during pack) */
+ attrib->comp_len = calc_input_component_size(input);
+ attrib->sz = attrib->comp_len * 4;
+ get_fetch_mode_and_comp_type(input->gl_type, &attrib->comp_type, &attrib->gl_comp_type, &attrib->fetch_mode);
+ }
+ }
+}
+
+
+/* OpenGL ES packs in a different order as desktop GL but component conversion is the same.
+ * Of the code here, only struct GPUPackedNormal needs to change. */
+
+#define SIGNED_INT_10_MAX 511
+#define SIGNED_INT_10_MIN -512
+
+static int clampi(int x, int min_allowed, int max_allowed)
+{
+#if TRUST_NO_ONE
+ assert(min_allowed <= max_allowed);
+#endif
+ if (x < min_allowed) {
+ return min_allowed;
+ }
+ else if (x > max_allowed) {
+ return max_allowed;
+ }
+ else {
+ return x;
+ }
+}
+
+static int quantize(float x)
+{
+ int qx = x * 511.0f;
+ return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX);
+}
+
+static int convert_i16(short x)
+{
+ /* 16-bit signed --> 10-bit signed */
+ /* TODO: round? */
+ return x >> 6;
+}
+
+GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
+{
+ GPUPackedNormal n = { .x = quantize(data[0]), .y = quantize(data[1]), .z = quantize(data[2]) };
+ return n;
+}
+
+GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3])
+{
+ GPUPackedNormal n = { .x = convert_i16(data[0]), .y = convert_i16(data[1]), .z = convert_i16(data[2]) };
+ return n;
+}
diff --git a/source/blender/gpu/intern/gpu_vertex_format_private.h b/source/blender/gpu/intern/gpu_vertex_format_private.h
new file mode 100644
index 00000000000..e4fe61e8697
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_vertex_format_private.h
@@ -0,0 +1,39 @@
+/*
+ * ***** 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 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_vertex_format_private.h
+ * \ingroup gpu
+ *
+ * GPU vertex format
+ */
+
+#ifndef __GPU_VERTEX_FORMAT_PRIVATE_H__
+#define __GPU_VERTEX_FORMAT_PRIVATE_H__
+
+void VertexFormat_pack(GPUVertFormat *format);
+uint padding(uint offset, uint alignment);
+uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len);
+
+#endif /* __GPU_VERTEX_FORMAT_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
new file mode 100644
index 00000000000..1dd3faa3b03
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -0,0 +1,644 @@
+/*
+ * ***** 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):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_viewport.c
+ * \ingroup gpu
+ *
+ * System that manages viewport drawing.
+ */
+
+#include <string.h>
+
+#include "BLI_listbase.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_mempool.h"
+
+#include "BIF_gl.h"
+
+#include "DNA_vec_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_global.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_glew.h"
+#include "GPU_immediate.h"
+#include "GPU_texture.h"
+#include "GPU_viewport.h"
+#include "GPU_draw.h"
+
+#include "DRW_engine.h"
+
+#include "MEM_guardedalloc.h"
+
+static const int default_fbl_len = (sizeof(DefaultFramebufferList)) / sizeof(void *);
+static const int default_txl_len = (sizeof(DefaultTextureList)) / sizeof(void *);
+
+/* Maximum number of simultaneous engine enabled at the same time.
+ * Setting it lower than the real number will do lead to
+ * higher VRAM usage due to sub-efficient buffer reuse. */
+#define MAX_ENGINE_BUFFER_SHARING 5
+
+typedef struct ViewportTempTexture {
+ struct ViewportTempTexture *next, *prev;
+ void *user[MAX_ENGINE_BUFFER_SHARING];
+ GPUTexture *texture;
+} ViewportTempTexture;
+
+struct GPUViewport {
+ int size[2];
+ int samples;
+ int flag;
+
+ ListBase data; /* ViewportEngineData wrapped in LinkData */
+ uint data_hash; /* If hash mismatch we free all ViewportEngineData in this viewport */
+
+ DefaultFramebufferList *fbl;
+ DefaultTextureList *txl;
+
+ ViewportMemoryPool vmempool; /* Used for rendering data structure. */
+ struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */
+
+ ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */
+
+ /* Profiling data */
+ double cache_time;
+};
+
+enum {
+ DO_UPDATE = (1 << 0),
+};
+
+static void gpu_viewport_buffers_free(FramebufferList *fbl, int fbl_len, TextureList *txl, int txl_len);
+static void gpu_viewport_storage_free(StorageList *stl, int stl_len);
+static void gpu_viewport_passes_free(PassList *psl, int psl_len);
+static void gpu_viewport_texture_pool_free(GPUViewport *viewport);
+static void gpu_viewport_default_fb_create(GPUViewport *viewport);
+
+void GPU_viewport_tag_update(GPUViewport *viewport)
+{
+ viewport->flag |= DO_UPDATE;
+}
+
+bool GPU_viewport_do_update(GPUViewport *viewport)
+{
+ bool ret = (viewport->flag & DO_UPDATE);
+ viewport->flag &= ~DO_UPDATE;
+ return ret;
+}
+
+GPUViewport *GPU_viewport_create(void)
+{
+ GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport");
+ viewport->fbl = MEM_callocN(sizeof(DefaultFramebufferList), "FramebufferList");
+ viewport->txl = MEM_callocN(sizeof(DefaultTextureList), "TextureList");
+ viewport->idatalist = DRW_instance_data_list_create();
+
+ viewport->size[0] = viewport->size[1] = -1;
+
+ return viewport;
+}
+
+GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs)
+{
+ GPUViewport *viewport = GPU_viewport_create();
+ GPUTexture *color, *depth;
+ GPUFrameBuffer *fb;
+ viewport->size[0] = GPU_offscreen_width(ofs);
+ viewport->size[1] = GPU_offscreen_height(ofs);
+
+ GPU_offscreen_viewport_data_get(ofs, &fb, &color, &depth);
+
+ if (GPU_texture_samples(color)) {
+ viewport->txl->multisample_color = color;
+ viewport->txl->multisample_depth = depth;
+ viewport->fbl->multisample_fb = fb;
+ gpu_viewport_default_fb_create(viewport);
+ }
+ else {
+ viewport->fbl->default_fb = fb;
+ viewport->txl->color = color;
+ viewport->txl->depth = depth;
+ GPU_framebuffer_ensure_config(&viewport->fbl->color_only_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(viewport->txl->color)
+ });
+ GPU_framebuffer_ensure_config(&viewport->fbl->depth_only_fb, {
+ GPU_ATTACHMENT_TEXTURE(viewport->txl->depth),
+ GPU_ATTACHMENT_NONE
+ });
+ }
+
+ return viewport;
+}
+/**
+ * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`.
+ */
+void GPU_viewport_clear_from_offscreen(GPUViewport *viewport)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+ DefaultTextureList *dtxl = viewport->txl;
+
+ if (dfbl->multisample_fb) {
+ /* GPUViewport expect the final result to be in default_fb but
+ * GPUOffscreen wants it in its multisample_fb, so we sync it back. */
+ GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, GPU_COLOR_BIT | GPU_DEPTH_BIT);
+ dfbl->multisample_fb = NULL;
+ dtxl->multisample_color = NULL;
+ dtxl->multisample_depth = NULL;
+ }
+ else {
+ viewport->fbl->default_fb = NULL;
+ dtxl->color = NULL;
+ dtxl->depth = NULL;
+ }
+}
+
+void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type)
+{
+ LinkData *ld = MEM_callocN(sizeof(LinkData), "LinkData");
+ ViewportEngineData *data = MEM_callocN(sizeof(ViewportEngineData), "ViewportEngineData");
+ int fbl_len, txl_len, psl_len, stl_len;
+
+ DRW_engine_viewport_data_size_get(engine_type, &fbl_len, &txl_len, &psl_len, &stl_len);
+
+ data->engine_type = engine_type;
+
+ data->fbl = MEM_callocN((sizeof(void *) * fbl_len) + sizeof(FramebufferList), "FramebufferList");
+ data->txl = MEM_callocN((sizeof(void *) * txl_len) + sizeof(TextureList), "TextureList");
+ data->psl = MEM_callocN((sizeof(void *) * psl_len) + sizeof(PassList), "PassList");
+ data->stl = MEM_callocN((sizeof(void *) * stl_len) + sizeof(StorageList), "StorageList");
+
+ ld->data = data;
+ BLI_addtail(&viewport->data, ld);
+
+ return data;
+}
+
+static void gpu_viewport_engines_data_free(GPUViewport *viewport)
+{
+ int fbl_len, txl_len, psl_len, stl_len;
+
+ LinkData *next;
+ for (LinkData *link = viewport->data.first; link; link = next) {
+ next = link->next;
+ ViewportEngineData *data = link->data;
+ DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, &psl_len, &stl_len);
+
+ gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len);
+ gpu_viewport_passes_free(data->psl, psl_len);
+ gpu_viewport_storage_free(data->stl, stl_len);
+
+ MEM_freeN(data->fbl);
+ MEM_freeN(data->txl);
+ MEM_freeN(data->psl);
+ MEM_freeN(data->stl);
+
+ /* We could handle this in the DRW module */
+ if (data->text_draw_cache) {
+ extern void DRW_text_cache_destroy(struct DRWTextStore *dt);
+ DRW_text_cache_destroy(data->text_draw_cache);
+ data->text_draw_cache = NULL;
+ }
+
+ MEM_freeN(data);
+
+ BLI_remlink(&viewport->data, link);
+ MEM_freeN(link);
+ }
+
+ gpu_viewport_texture_pool_free(viewport);
+}
+
+void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type)
+{
+ for (LinkData *link = viewport->data.first; link; link = link->next) {
+ ViewportEngineData *vdata = link->data;
+ if (vdata->engine_type == engine_type) {
+ return vdata;
+ }
+ }
+ return NULL;
+}
+
+ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport)
+{
+ return &viewport->vmempool;
+}
+
+struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport)
+{
+ return viewport->idatalist;
+}
+
+void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport)
+{
+ return viewport->fbl;
+}
+
+void *GPU_viewport_texture_list_get(GPUViewport *viewport)
+{
+ return viewport->txl;
+}
+
+void GPU_viewport_size_get(const GPUViewport *viewport, int size[2])
+{
+ size[0] = viewport->size[0];
+ size[1] = viewport->size[1];
+}
+
+/**
+ * Special case, this is needed for when we have a viewport without a frame-buffer output
+ * (occlusion queries for eg) but still need to set the size since it may be used for other calculations.
+ */
+void GPU_viewport_size_set(GPUViewport *viewport, const int size[2])
+{
+ viewport->size[0] = size[0];
+ viewport->size[1] = size[1];
+}
+
+double *GPU_viewport_cache_time_get(GPUViewport *viewport)
+{
+ return &viewport->cache_time;
+}
+
+/**
+ * Try to find a texture corresponding to params into the texture pool.
+ * If no texture was found, create one and add it to the pool.
+ */
+GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int format)
+{
+ GPUTexture *tex;
+
+ for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
+ if ((GPU_texture_format(tmp_tex->texture) == format) &&
+ (GPU_texture_width(tmp_tex->texture) == width) &&
+ (GPU_texture_height(tmp_tex->texture) == height))
+ {
+ /* Search if the engine is not already using this texture */
+ for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
+ if (tmp_tex->user[i] == engine) {
+ break;
+ }
+
+ if (tmp_tex->user[i] == NULL) {
+ tmp_tex->user[i] = engine;
+ return tmp_tex->texture;
+ }
+ }
+ }
+ }
+
+ tex = GPU_texture_create_2D(width, height, format, NULL, NULL);
+ GPU_texture_bind(tex, 0);
+ /* Doing filtering for depth does not make sense when not doing shadow mapping,
+ * and enabling texture filtering on integer texture make them unreadable. */
+ bool do_filter = !GPU_texture_depth(tex) && !GPU_texture_integer(tex);
+ GPU_texture_filter_mode(tex, do_filter);
+ GPU_texture_unbind(tex);
+
+ ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture");
+ tmp_tex->texture = tex;
+ tmp_tex->user[0] = engine;
+ BLI_addtail(&viewport->tex_pool, tmp_tex);
+
+ return tex;
+}
+
+static void gpu_viewport_texture_pool_clear_users(GPUViewport *viewport)
+{
+ ViewportTempTexture *tmp_tex_next;
+
+ for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex_next) {
+ tmp_tex_next = tmp_tex->next;
+ bool no_user = true;
+ for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
+ if (tmp_tex->user[i] != NULL) {
+ tmp_tex->user[i] = NULL;
+ no_user = false;
+ }
+ }
+
+ if (no_user) {
+ GPU_texture_free(tmp_tex->texture);
+ BLI_freelinkN(&viewport->tex_pool, tmp_tex);
+ }
+ }
+}
+
+static void gpu_viewport_texture_pool_free(GPUViewport *viewport)
+{
+ for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
+ GPU_texture_free(tmp_tex->texture);
+ }
+
+ BLI_freelistN(&viewport->tex_pool);
+}
+
+bool GPU_viewport_engines_data_validate(GPUViewport *viewport, uint hash)
+{
+ bool dirty = false;
+
+ if (viewport->data_hash != hash) {
+ gpu_viewport_engines_data_free(viewport);
+ dirty = true;
+ }
+
+ viewport->data_hash = hash;
+
+ return dirty;
+}
+
+void GPU_viewport_cache_release(GPUViewport *viewport)
+{
+ for (LinkData *link = viewport->data.first; link; link = link->next) {
+ ViewportEngineData *data = link->data;
+ int psl_len;
+ DRW_engine_viewport_data_size_get(data->engine_type, NULL, NULL, &psl_len, NULL);
+ gpu_viewport_passes_free(data->psl, psl_len);
+ }
+}
+
+static void gpu_viewport_default_fb_create(GPUViewport *viewport)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+ DefaultTextureList *dtxl = viewport->txl;
+ int *size = viewport->size;
+ bool ok = true;
+
+ dtxl->color = GPU_texture_create_2D(size[0], size[1], GPU_RGBA8, NULL, NULL);
+ dtxl->depth = GPU_texture_create_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, NULL, NULL);
+
+ if (!(dtxl->depth && dtxl->color)) {
+ ok = false;
+ goto cleanup;
+ }
+
+ GPU_framebuffer_ensure_config(&dfbl->default_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color)
+ });
+
+ GPU_framebuffer_ensure_config(&dfbl->depth_only_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ GPU_ATTACHMENT_NONE
+ });
+
+ GPU_framebuffer_ensure_config(&dfbl->color_only_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(dtxl->color)
+ });
+
+ ok = ok && GPU_framebuffer_check_valid(dfbl->default_fb, NULL);
+ ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL);
+ ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL);
+
+cleanup:
+ if (!ok) {
+ GPU_viewport_free(viewport);
+ DRW_opengl_context_disable();
+ return;
+ }
+
+ GPU_framebuffer_restore();
+}
+
+static void gpu_viewport_default_multisample_fb_create(GPUViewport *viewport)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+ DefaultTextureList *dtxl = viewport->txl;
+ int *size = viewport->size;
+ int samples = viewport->samples;
+ bool ok = true;
+
+ dtxl->multisample_color = GPU_texture_create_2D_multisample(size[0], size[1], GPU_RGBA8, NULL, samples, NULL);
+ dtxl->multisample_depth = GPU_texture_create_2D_multisample(size[0], size[1], GPU_DEPTH24_STENCIL8, NULL, samples, NULL);
+
+ if (!(dtxl->multisample_depth && dtxl->multisample_color)) {
+ ok = false;
+ goto cleanup;
+ }
+
+ GPU_framebuffer_ensure_config(&dfbl->multisample_fb, {
+ GPU_ATTACHMENT_TEXTURE(dtxl->multisample_depth),
+ GPU_ATTACHMENT_TEXTURE(dtxl->multisample_color)
+ });
+
+ ok = ok && GPU_framebuffer_check_valid(dfbl->multisample_fb, NULL);
+
+cleanup:
+ if (!ok) {
+ GPU_viewport_free(viewport);
+ DRW_opengl_context_disable();
+ return;
+ }
+
+ GPU_framebuffer_restore();
+}
+
+void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+ int fbl_len, txl_len;
+
+ /* add one pixel because of scissor test */
+ int rect_w = BLI_rcti_size_x(rect) + 1;
+ int rect_h = BLI_rcti_size_y(rect) + 1;
+
+ DRW_opengl_context_enable();
+
+ if (dfbl->default_fb) {
+ if (rect_w != viewport->size[0] || rect_h != viewport->size[1] || U.ogl_multisamples != viewport->samples) {
+ gpu_viewport_buffers_free(
+ (FramebufferList *)viewport->fbl, default_fbl_len,
+ (TextureList *)viewport->txl, default_txl_len);
+
+ for (LinkData *link = viewport->data.first; link; link = link->next) {
+ ViewportEngineData *data = link->data;
+ DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, NULL, NULL);
+ gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len);
+ }
+
+ gpu_viewport_texture_pool_free(viewport);
+ }
+ }
+
+ viewport->size[0] = rect_w;
+ viewport->size[1] = rect_h;
+ viewport->samples = U.ogl_multisamples;
+
+ gpu_viewport_texture_pool_clear_users(viewport);
+
+ /* Multisample Buffer */
+ if (viewport->samples > 0) {
+ if (!dfbl->default_fb) {
+ gpu_viewport_default_multisample_fb_create(viewport);
+ }
+ }
+
+ if (!dfbl->default_fb) {
+ gpu_viewport_default_fb_create(viewport);
+ }
+}
+
+void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+
+ if (dfbl->default_fb == NULL)
+ return;
+
+ DefaultTextureList *dtxl = viewport->txl;
+
+ GPUTexture *color = dtxl->color;
+
+ const float w = (float)GPU_texture_width(color);
+ const float h = (float)GPU_texture_height(color);
+
+ BLI_assert(w == BLI_rcti_size_x(rect) + 1);
+ BLI_assert(h == BLI_rcti_size_y(rect) + 1);
+
+ /* wmOrtho for the screen has this same offset */
+ const float halfx = GLA_PIXEL_OFS / w;
+ const float halfy = GLA_PIXEL_OFS / h;
+
+ float x1 = rect->xmin;
+ float x2 = rect->xmin + w;
+ float y1 = rect->ymin;
+ float y2 = rect->ymin + h;
+
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
+ GPU_shader_bind(shader);
+
+ GPU_texture_bind(color, 0);
+ glUniform1i(GPU_shader_get_uniform(shader, "image"), 0);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), halfx, halfy, 1.0f + halfx, 1.0f + halfy);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), x1, y1, x2, y2);
+ glUniform4f(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), 1.0f, 1.0f, 1.0f, 1.0f);
+
+ GPU_draw_primitive(GPU_PRIM_TRI_STRIP, 4);
+
+ GPU_texture_unbind(color);
+}
+
+void GPU_viewport_unbind(GPUViewport *UNUSED(viewport))
+{
+ GPU_framebuffer_restore();
+ DRW_opengl_context_disable();
+}
+
+
+GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport)
+{
+ DefaultFramebufferList *dfbl = viewport->fbl;
+
+ if (dfbl->default_fb) {
+ DefaultTextureList *dtxl = viewport->txl;
+ return dtxl->color;
+ }
+
+ return NULL;
+}
+
+static void gpu_viewport_buffers_free(
+ FramebufferList *fbl, int fbl_len,
+ TextureList *txl, int txl_len)
+{
+ for (int i = 0; i < fbl_len; i++) {
+ GPUFrameBuffer *fb = fbl->framebuffers[i];
+ if (fb) {
+ GPU_framebuffer_free(fb);
+ fbl->framebuffers[i] = NULL;
+ }
+ }
+ for (int i = 0; i < txl_len; i++) {
+ GPUTexture *tex = txl->textures[i];
+ if (tex) {
+ GPU_texture_free(tex);
+ txl->textures[i] = NULL;
+ }
+ }
+}
+
+static void gpu_viewport_storage_free(StorageList *stl, int stl_len)
+{
+ for (int i = 0; i < stl_len; i++) {
+ void *storage = stl->storage[i];
+ if (storage) {
+ MEM_freeN(storage);
+ stl->storage[i] = NULL;
+ }
+ }
+}
+
+static void gpu_viewport_passes_free(PassList *psl, int psl_len)
+{
+ for (int i = 0; i < psl_len; i++) {
+ struct DRWPass *pass = psl->passes[i];
+ if (pass) {
+ DRW_pass_free(pass);
+ psl->passes[i] = NULL;
+ }
+ }
+}
+
+/* Must be executed inside Drawmanager Opengl Context. */
+void GPU_viewport_free(GPUViewport *viewport)
+{
+ gpu_viewport_engines_data_free(viewport);
+
+ gpu_viewport_buffers_free(
+ (FramebufferList *)viewport->fbl, default_fbl_len,
+ (TextureList *)viewport->txl, default_txl_len);
+
+ gpu_viewport_texture_pool_free(viewport);
+
+ MEM_freeN(viewport->fbl);
+ MEM_freeN(viewport->txl);
+
+ if (viewport->vmempool.calls != NULL) {
+ BLI_mempool_destroy(viewport->vmempool.calls);
+ }
+ if (viewport->vmempool.states != NULL) {
+ BLI_mempool_destroy(viewport->vmempool.states);
+ }
+ if (viewport->vmempool.shgroups != NULL) {
+ BLI_mempool_destroy(viewport->vmempool.shgroups);
+ }
+ if (viewport->vmempool.uniforms != NULL) {
+ BLI_mempool_destroy(viewport->vmempool.uniforms);
+ }
+ if (viewport->vmempool.passes != NULL) {
+ BLI_mempool_destroy(viewport->vmempool.passes);
+ }
+
+ DRW_instance_data_list_free(viewport->idatalist);
+ MEM_freeN(viewport->idatalist);
+
+ MEM_freeN(viewport);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl
new file mode 100644
index 00000000000..5326076e269
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl
@@ -0,0 +1,42 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+uniform vec4 rect;
+uniform int cornerLen;
+uniform float scale;
+
+in vec2 pos;
+
+const vec2 jitter_ofs[8] = vec2[8](
+ vec2( 0.468813, -0.481430), vec2(-0.155755, -0.352820),
+ vec2( 0.219306, -0.238501), vec2(-0.393286, -0.110949),
+ vec2(-0.024699, 0.013908), vec2( 0.343805, 0.147431),
+ vec2(-0.272855, 0.269918), vec2( 0.095909, 0.388710)
+);
+
+void main()
+{
+ int corner_id = (gl_VertexID / cornerLen) % 4;
+ int jitter_id = gl_VertexID / (cornerLen * 4) % 8;
+
+ vec2 final_pos = pos * scale;
+
+ if (corner_id == 0)
+ final_pos += rect.yw; /* top right */
+ else if (corner_id == 1)
+ final_pos += rect.xw; /* top left */
+ else if (corner_id == 2)
+ final_pos += rect.xz; /* bottom left */
+ else
+ final_pos += rect.yz; /* bottom right */
+
+ /* Only jitter verts inside the corner (not the one shared with the edges). */
+ if ((gl_VertexID % cornerLen) % (cornerLen - 2) != 0) {
+ /* Only jitter intern verts not boundaries. */
+ if ((gl_VertexID % 2) == 0) {
+ final_pos += jitter_ofs[jitter_id];
+ }
+ }
+
+ gl_Position = (ModelViewProjectionMatrix * vec4(final_pos, 0.0, 1.0));
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl
new file mode 100644
index 00000000000..76e9c066103
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl
@@ -0,0 +1,29 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec4 edgeColor;
+uniform vec4 selectColor;
+
+in vec2 pos;
+in int flag;
+
+#ifdef SMOOTH_COLOR
+noperspective out vec4 finalColor;
+#else
+flat out vec4 finalColor;
+#endif
+
+#define VERTEX_SELECT (1 << 0)
+#define EDGE_SELECT (1 << 4)
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+
+#ifdef SMOOTH_COLOR
+ bool is_select = (flag & VERTEX_SELECT) != 0;
+#else
+ bool is_select = (flag & EDGE_SELECT) != 0;
+#endif
+
+ finalColor = (is_select) ? selectColor : edgeColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl
new file mode 100644
index 00000000000..c5f84b976c5
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl
@@ -0,0 +1,17 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec4 vertColor;
+uniform vec4 selectColor;
+
+in vec2 pos;
+in int flag;
+
+out vec4 finalColor;
+
+#define FACE_SELECT (1 << 2)
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ finalColor = ((flag & FACE_SELECT) != 0) ? selectColor : vertColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl
new file mode 100644
index 00000000000..82c8d3f0c4a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl
@@ -0,0 +1,24 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec4 faceColor;
+uniform vec4 selectColor;
+uniform vec4 activeColor;
+
+in vec2 pos;
+in int flag;
+
+flat out vec4 finalColor;
+
+#define FACE_SELECT (1 << 2)
+#define FACE_ACTIVE (1 << 3)
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+
+ bool is_selected = (flag & FACE_SELECT) != 0;
+ bool is_active = (flag & FACE_ACTIVE) != 0;
+
+ finalColor = (is_selected) ? selectColor : faceColor;
+ finalColor = (is_active) ? activeColor : finalColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl
new file mode 100644
index 00000000000..46dd1e066c8
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl
@@ -0,0 +1,42 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec4 vertColor;
+uniform vec4 selectColor;
+uniform vec4 pinnedColor;
+uniform float pointSize;
+uniform float outlineWidth;
+
+in vec2 pos;
+in int flag;
+
+out vec4 fillColor;
+out vec4 outlineColor;
+out vec4 radii;
+
+#define VERTEX_SELECT (1 << 0)
+#define VERTEX_PINNED (1 << 1)
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ gl_PointSize = pointSize;
+
+ bool is_selected = (flag & VERTEX_SELECT) != 0;
+ bool is_pinned = (flag & VERTEX_PINNED) != 0;
+
+ vec4 deselect_col = (is_pinned) ? pinnedColor : vertColor;
+ fillColor = (is_selected) ? selectColor : deselect_col;
+ outlineColor = (is_pinned) ? pinnedColor : vec4(fillColor.rgb, 0.0);
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * pointSize;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+ radii[2] = radius - outlineWidth;
+ radii[3] = radius - outlineWidth - 1.0;
+
+ // convert to PointCoord units
+ radii /= pointSize;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
new file mode 100644
index 00000000000..4588e41573b
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
@@ -0,0 +1,49 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 pos;
+in float stretch;
+
+noperspective out vec4 finalColor;
+
+vec3 weight_to_rgb(float weight)
+{
+ vec3 r_rgb;
+ float blend = ((weight / 2.0) + 0.5);
+
+ if (weight <= 0.25) { /* blue->cyan */
+ r_rgb[0] = 0.0;
+ r_rgb[1] = blend * weight * 4.0;
+ r_rgb[2] = blend;
+ }
+ else if (weight <= 0.50) { /* cyan->green */
+ r_rgb[0] = 0.0;
+ r_rgb[1] = blend;
+ r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0));
+ }
+ else if (weight <= 0.75) { /* green->yellow */
+ r_rgb[0] = blend * ((weight - 0.50) * 4.0);
+ r_rgb[1] = blend;
+ r_rgb[2] = 0.0;
+ }
+ else if (weight <= 1.0) { /* yellow->red */
+ r_rgb[0] = blend;
+ r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0));
+ r_rgb[2] = 0.0;
+ }
+ else {
+ /* exceptional value, unclamped or nan,
+ * avoid uninitialized memory use */
+ r_rgb[0] = 1.0;
+ r_rgb[1] = 0.0;
+ r_rgb[2] = 1.0;
+ }
+
+ return r_rgb;
+}
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ finalColor = vec4(weight_to_rgb(stretch), 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl
new file mode 100644
index 00000000000..769e2b0e37c
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl
@@ -0,0 +1,13 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 pos;
+in vec4 color;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
new file mode 100644
index 00000000000..9fdf8ececc5
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
@@ -0,0 +1,48 @@
+/**
+ * Simple shader that just draw multiple icons at the specified locations
+ * does not need any vertex input (producing less call to immBegin/End)
+ **/
+
+/* Same as ICON_DRAW_CACHE_SIZE */
+#define MAX_CALLS 16
+
+uniform vec4 calls_data[MAX_CALLS * 3];
+
+out vec2 texCoord_interp;
+flat out vec4 finalColor;
+
+void main()
+{
+ /* Rendering 2 triangle per icon. */
+ int i = gl_VertexID / 6;
+ int v = gl_VertexID % 6;
+
+ vec4 pos = calls_data[i*3];
+ vec4 tex = calls_data[i*3+1];
+ finalColor = calls_data[i*3+2];
+
+ /* TODO Remove this */
+ if (v == 2) v = 4;
+ else if (v == 3) v = 0;
+ else if (v == 5) v = 2;
+
+ if (v == 0) {
+ pos.xy = pos.xw;
+ tex.xy = tex.xw;
+ }
+ else if (v == 1) {
+ pos.xy = pos.xz;
+ tex.xy = tex.xz;
+ }
+ else if (v == 2) {
+ pos.xy = pos.yw;
+ tex.xy = tex.yw;
+ }
+ else {
+ pos.xy = pos.yz;
+ tex.xy = tex.yz;
+ }
+
+ gl_Position = vec4(pos.xy, 0.0f, 1.0f);
+ texCoord_interp = tex.xy;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
new file mode 100644
index 00000000000..118f4e3b187
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
@@ -0,0 +1,35 @@
+/**
+ * Simple shader that just draw one icon at the specified location
+ * does not need any vertex input (producing less call to immBegin/End)
+ **/
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec4 rect_icon;
+uniform vec4 rect_geom;
+
+out vec2 texCoord_interp;
+
+void main()
+{
+ vec2 uv;
+ vec2 co;
+ if (gl_VertexID == 0) {
+ co = rect_geom.xw;
+ uv = rect_icon.xw;
+ }
+ else if (gl_VertexID == 1) {
+ co = rect_geom.xy;
+ uv = rect_icon.xy;
+ }
+ else if (gl_VertexID == 2) {
+ co = rect_geom.zw;
+ uv = rect_icon.zw;
+ }
+ else {
+ co = rect_geom.zy;
+ uv = rect_icon.zy;
+ }
+
+ gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f);
+ texCoord_interp = uv;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
new file mode 100644
index 00000000000..0881f2b150f
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
@@ -0,0 +1,14 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+/* Keep in sync with intern/opencolorio/gpu_shader_display_transform_vertex.glsl */
+in vec2 texCoord;
+in vec2 pos;
+out vec2 texCoord_interp;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f);
+ gl_Position.z = 1.0;
+ texCoord_interp = texCoord;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
new file mode 100644
index 00000000000..3c5b0d1ca0a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
@@ -0,0 +1,54 @@
+
+/*
+ * Fragment Shader for dashed lines, with uniform multi-color(s), or any single-color, and any thickness.
+ *
+ * Dashed is performed in screen space.
+ */
+
+uniform float dash_width;
+
+/* Simple mode, discarding non-dash parts (so no need for blending at all). */
+uniform float dash_factor; /* if > 1.0, solid line. */
+
+/* More advanced mode, allowing for complex, multi-colored patterns. Enabled when colors_len > 0. */
+/* Note: max number of steps/colors in pattern is 32! */
+uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
+uniform vec4 colors[32];
+
+noperspective in float distance_along_line;
+noperspective in vec4 color_geom;
+
+out vec4 fragColor;
+
+void main()
+{
+ /* Multi-color option. */
+ if (colors_len > 0) {
+ /* Solid line case, simple. */
+ if (colors_len == 1) {
+ fragColor = colors[0];
+ }
+ /* Actually dashed line... */
+ else {
+ float normalized_distance = fract(distance_along_line / dash_width);
+ fragColor = colors[int(normalized_distance * colors_len)];
+ }
+ }
+ /* Single color option. */
+ else {
+ /* Solid line case, simple. */
+ if (dash_factor >= 1.0f) {
+ fragColor = color_geom;
+ }
+ /* Actually dashed line... */
+ else {
+ float normalized_distance = fract(distance_along_line / dash_width);
+ if (normalized_distance <= dash_factor) {
+ fragColor = color_geom;
+ }
+ else {
+ discard;
+ }
+ }
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl
new file mode 100644
index 00000000000..8fa19f94b39
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl
@@ -0,0 +1,56 @@
+
+/*
+ * Geometry Shader for dashed lines, with uniform multi-color(s), or any single-color, and unary thickness.
+ *
+ * Dashed is performed in screen space.
+ */
+
+
+/* Make to be used with dynamic batching so no Model Matrix needed */
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewport_size;
+
+/* Uniforms from fragment shader, used here to optimize out useless computation in case of solid line. */
+uniform float dash_factor; /* if > 1.0, solid line. */
+uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
+
+layout(lines) in;
+
+in vec4 color_vert[];
+
+layout(line_strip, max_vertices = 2) out;
+noperspective out float distance_along_line;
+noperspective out vec4 color_geom;
+
+void main()
+{
+ vec4 v1 = gl_in[0].gl_Position;
+ vec4 v2 = gl_in[1].gl_Position;
+
+ gl_Position = v1;
+ color_geom = color_vert[0];
+ distance_along_line = 0.0f;
+ EmitVertex();
+
+ gl_Position = v2;
+ color_geom = color_vert[1];
+ if ((colors_len == 1) || (dash_factor >= 1.0f)) {
+ /* Solid line, optimize out distance computation! */
+ distance_along_line = 0.0f;
+ }
+ else {
+ vec2 p1 = (v1.xy / v1.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range.
+ p1 = p1 * viewport_size; // <- 'virtual' screen coordinates.
+
+ vec2 p2 = (v2.xy / v2.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range.
+ p2 = p2 * viewport_size; // <- 'virtual' screen coordinates.
+
+ distance_along_line = distance(p1, p2);
+ }
+ EmitVertex();
+
+ EndPrimitive();
+
+ /* Note: we could also use similar approach as diag_stripes_frag, but this would give us dashed 'anchored'
+ * to the screen, and not to one end of the line... */
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
new file mode 100644
index 00000000000..f5c611586aa
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
@@ -0,0 +1,21 @@
+
+/*
+ * Vertex Shader for dashed lines with 2D coordinates, with uniform multi-colors or uniform single-color,
+ * and unary thickness.
+ *
+ * Dashed is performed in screen space.
+ */
+
+uniform mat4 ModelViewProjectionMatrix;
+
+uniform vec4 color;
+
+in vec2 pos;
+
+out vec4 color_vert;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ color_vert = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl
new file mode 100644
index 00000000000..5a4da5cc9d4
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl
@@ -0,0 +1,59 @@
+
+// Draw dashed lines, perforated in screen space, with non-unary width.
+
+/* Make to be used with dynamic batching so no Model Matrix needed */
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewport_size;
+
+/* Width of the generated 'line'. */
+uniform float width; /* in pixels, screen space. */
+
+/* Uniforms from fragment shader, used here to optimize out useless computation in case of solid line. */
+uniform float dash_factor; /* if > 1.0, solid line. */
+uniform int colors_len; /* Enabled if > 0, 1 for solid line. */
+
+layout(lines) in;
+
+layout(triangle_strip, max_vertices = 4) out;
+noperspective out float distance_along_line;
+
+void main()
+{
+ vec4 v1 = gl_in[0].gl_Position;
+ vec4 v2 = gl_in[1].gl_Position;
+
+ /* Width, from 2D screen space in pixels, to ModelViewProjection space of each input vertices. */
+ float w1 = (width / viewport_size) * v1.w * 2.0;
+ float w2 = (width / viewport_size) * v2.w * 2.0;
+
+ /* Normalized vector parallel to screen and orthogonal to line. */
+ vec4 wdir = normalize(vec4(v1.y - v2.y, v2.x - v1.x, 0.0, 0.0))
+
+ distance_along_line = 0.0f;
+ gl_Position = v1 + (wdir * w1);
+ EmitVertex();
+
+ gl_Position = v1 - (wdir * w1);
+ EmitVertex();
+
+ if ((colors_len == 1) || (dash_factor >= 1.0f)) {
+ /* Solid line, optimize out distance computation! */
+ distance_along_line = 0.0f;
+ }
+ else {
+ vec2 p1 = (v1.xy / v1.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range.
+ p1 = p1 * viewport_size; // <- 'virtual' screen coordinates.
+
+ vec2 p2 = (v2.xy / v2.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range.
+ p2 = p2 * viewport_size; // <- 'virtual' screen coordinates.
+
+ distance_along_line = distance(p1, p2);
+ }
+ gl_Position = v2 + (wdir * w2);
+ EmitVertex();
+
+ gl_Position = v2 - (wdir * w2);
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl
new file mode 100644
index 00000000000..1497f9eeeb1
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl
@@ -0,0 +1,10 @@
+
+in float colorGradient;
+in vec4 finalColor;
+
+out vec4 fragColor;
+
+void main() {
+ fragColor = finalColor;
+ fragColor.a *= smoothstep(1.0, 0.1, abs(colorGradient));
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
new file mode 100644
index 00000000000..4a9f5f94321
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
@@ -0,0 +1,107 @@
+/**
+ * 2D Quadratic Bezier thick line drawing
+ **/
+
+#define MID_VERTEX 57
+
+/* u is position along the curve, defining the tangent space.
+ * v is "signed" distance (compressed to [0..1] range) from the pos in expand direction */
+in vec2 uv;
+in vec2 pos; /* verts position in the curve tangent space */
+in vec2 expand;
+
+#ifdef USE_INSTANCE
+/* Instance attrib */
+in vec2 P0;
+in vec2 P1;
+in vec2 P2;
+in vec2 P3;
+in ivec4 colid_doarrow;
+
+uniform vec4 colors[6];
+
+#define colStart colors[colid_doarrow[0]]
+#define colEnd colors[colid_doarrow[1]]
+#define colShadow colors[colid_doarrow[2]]
+#define doArrow (colid_doarrow[3] != 0)
+
+#else
+/* Single curve drawcall, use uniform. */
+uniform vec2 bezierPts[4];
+
+#define P0 bezierPts[0]
+#define P1 bezierPts[1]
+#define P2 bezierPts[2]
+#define P3 bezierPts[3]
+
+uniform vec4 colors[3];
+uniform bool doArrow;
+
+#define colShadow colors[0]
+#define colStart colors[1]
+#define colEnd colors[2]
+
+#endif
+
+uniform float expandSize;
+uniform float arrowSize;
+uniform mat4 ModelViewProjectionMatrix;
+
+out float colorGradient;
+out vec4 finalColor;
+
+void main(void)
+{
+ float t = uv.x;
+ float t2 = t * t;
+ float t2_3 = 3.0 * t2;
+ float one_minus_t = 1.0 - t;
+ float one_minus_t2 = one_minus_t * one_minus_t;
+ float one_minus_t2_3 = 3.0 * one_minus_t2;
+
+ vec2 point = (P0 * one_minus_t2 * one_minus_t +
+ P1 * one_minus_t2_3 * t +
+ P2 * t2_3 * one_minus_t +
+ P3 * t2 * t);
+
+ vec2 tangent = ((P1 - P0) * one_minus_t2_3 +
+ (P2 - P1) * 6.0 * (t - t2) +
+ (P3 - P2) * t2_3);
+
+ /* tangent space at t */
+ tangent = normalize(tangent);
+ vec2 normal = tangent.yx * vec2(-1.0, 1.0);
+
+ /* Position vertex on the curve tangent space */
+ point += (pos.x * tangent + pos.y * normal) * arrowSize;
+
+ gl_Position = ModelViewProjectionMatrix * vec4(point, 0.0, 1.0);
+
+ vec2 exp_axis = expand.x * tangent + expand.y * normal;
+
+ /* rotate & scale the expand axis */
+ exp_axis = ModelViewProjectionMatrix[0].xy * exp_axis.xx +
+ ModelViewProjectionMatrix[1].xy * exp_axis.yy;
+
+
+ float expand_dist = (uv.y * 2.0 - 1.0);
+ colorGradient = expand_dist;
+
+ if (gl_VertexID < MID_VERTEX) {
+ /* Shadow pass */
+ finalColor = colShadow;
+ }
+ else {
+ /* Second pass */
+ finalColor = mix(colStart, colEnd, uv.x);
+ expand_dist *= 0.5;
+ }
+
+ /* Expand into a line */
+ gl_Position.xy += exp_axis * expandSize * expand_dist;
+
+ /* if arrow */
+ if (expand.y != 1.0 && !doArrow) {
+ gl_Position.xy *= 0.0;
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
new file mode 100644
index 00000000000..1f833cfb7be
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
@@ -0,0 +1,21 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform float size;
+
+in vec2 pos;
+out vec2 radii;
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ gl_PointSize = size;
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * size;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+
+ // convert to PointCoord units
+ radii /= size;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
new file mode 100644
index 00000000000..99bdeb22904
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
@@ -0,0 +1,24 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform float size;
+uniform float outlineWidth;
+
+in vec2 pos;
+out vec4 radii;
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ gl_PointSize = size;
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * size;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+ radii[2] = radius - outlineWidth;
+ radii[3] = radius - outlineWidth - 1.0;
+
+ // convert to PointCoord units
+ radii /= size;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl
new file mode 100644
index 00000000000..5fad95236df
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl
@@ -0,0 +1,27 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform float size;
+uniform float outlineWidth;
+
+in vec2 pos;
+in vec4 color;
+out vec4 radii;
+out vec4 fillColor;
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ gl_PointSize = size;
+ fillColor = color;
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * size;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+ radii[2] = radius - outlineWidth;
+ radii[3] = radius - outlineWidth - 1.0;
+
+ // convert to PointCoord units
+ radii /= size;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
new file mode 100644
index 00000000000..d6aacf0cdc5
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
@@ -0,0 +1,14 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 pos;
+in float size;
+in vec4 color;
+out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ gl_PointSize = size;
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl
new file mode 100644
index 00000000000..145ed16248a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl
@@ -0,0 +1,20 @@
+
+noperspective in vec4 finalColor;
+out vec4 fragColor;
+
+/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */
+#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0))
+const vec4 dither_mat4x4[4] = vec4[4](
+ vec4( P(0.0), P(8.0), P(2.0), P(10.0)),
+ vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
+ vec4( P(3.0), P(11.0), P(1.0), P(9.0)),
+ vec4(P(15.0), P(7.0), P(13.0), P(5.0))
+);
+
+void main()
+{
+ ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4;
+ ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2;
+ float dither_noise = dither_mat4x4[tx1.x][tx1.y];
+ fragColor = finalColor + dither_noise;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
new file mode 100644
index 00000000000..4a4bfb6a616
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
@@ -0,0 +1,8 @@
+
+noperspective in vec4 finalColor;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = finalColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl
new file mode 100644
index 00000000000..fe91f4d0902
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl
@@ -0,0 +1,13 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 pos;
+in vec4 color;
+
+noperspective out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl
new file mode 100644
index 00000000000..89e3c52f9f8
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl
@@ -0,0 +1,9 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 pos;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
new file mode 100644
index 00000000000..a356014d025
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
@@ -0,0 +1,40 @@
+uniform vec3 checkerColorAndSize;
+
+noperspective in vec4 finalColor;
+noperspective in float butCo;
+flat in float discardFac;
+
+out vec4 fragColor;
+
+vec4 do_checkerboard()
+{
+ float size = checkerColorAndSize.z;
+ vec2 phase = mod(gl_FragCoord.xy, size * 2.0);
+
+ if ((phase.x > size && phase.y < size) ||
+ (phase.x < size && phase.y > size))
+ {
+ return vec4(checkerColorAndSize.xxx, 1.0);
+ }
+ else {
+ return vec4(checkerColorAndSize.yyy, 1.0);
+ }
+}
+
+void main()
+{
+ if (min(1.0, -butCo) > discardFac) {
+ discard;
+ }
+
+ fragColor = finalColor;
+
+ if (butCo > 0.5) {
+ vec4 checker = do_checkerboard();
+ fragColor = mix(checker, fragColor, fragColor.a);
+ }
+
+ if (butCo > 0.0) {
+ fragColor.a = 1.0;
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
new file mode 100644
index 00000000000..7db0029e64d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
@@ -0,0 +1,214 @@
+#define BIT_RANGE(x) uint((1 << x) - 1)
+
+/* 2 bits for corner */
+/* Attention! Not the same order as in UI_interface.h!
+ * Ordered by drawing order. */
+#define BOTTOM_LEFT 0u
+#define BOTTOM_RIGHT 1u
+#define TOP_RIGHT 2u
+#define TOP_LEFT 3u
+#define CNR_FLAG_RANGE BIT_RANGE(2)
+
+/* 4bits for corner id */
+#define CORNER_VEC_OFS 2u
+#define CORNER_VEC_RANGE BIT_RANGE(4)
+const vec2 cornervec[36] = vec2[36](
+ vec2(0.0, 1.0), vec2(0.02, 0.805), vec2(0.067, 0.617), vec2(0.169, 0.45), vec2(0.293, 0.293), vec2(0.45, 0.169), vec2(0.617, 0.076), vec2(0.805, 0.02), vec2(1.0, 0.0),
+ vec2(-1.0, 0.0), vec2(-0.805, 0.02), vec2(-0.617, 0.067), vec2(-0.45, 0.169), vec2(-0.293, 0.293), vec2(-0.169, 0.45), vec2(-0.076, 0.617), vec2(-0.02, 0.805), vec2(0.0, 1.0),
+ vec2(0.0, -1.0), vec2(-0.02, -0.805), vec2(-0.067, -0.617), vec2(-0.169, -0.45), vec2(-0.293, -0.293), vec2(-0.45, -0.169), vec2(-0.617, -0.076), vec2(-0.805, -0.02), vec2(-1.0, 0.0),
+ vec2(1.0, 0.0), vec2(0.805, -0.02), vec2(0.617, -0.067), vec2(0.45, -0.169), vec2(0.293, -0.293), vec2(0.169, -0.45), vec2(0.076, -0.617), vec2(0.02, -0.805), vec2(0.0, -1.0)
+);
+
+/* 4bits for jitter id */
+#define JIT_OFS 6u
+#define JIT_RANGE BIT_RANGE(4)
+const vec2 jit[9] = vec2[9](
+ vec2( 0.468813, -0.481430), vec2(-0.155755, -0.352820),
+ vec2( 0.219306, -0.238501), vec2(-0.393286, -0.110949),
+ vec2(-0.024699, 0.013908), vec2( 0.343805, 0.147431),
+ vec2(-0.272855, 0.269918), vec2( 0.095909, 0.388710),
+ vec2( 0.0, 0.0)
+);
+
+/* 2bits for other flags */
+#define INNER_FLAG uint(1 << 10) /* is inner vert */
+#define EMBOSS_FLAG uint(1 << 11) /* is emboss vert */
+
+/* 2bits for color */
+#define COLOR_OFS 12u
+#define COLOR_RANGE BIT_RANGE(2)
+#define COLOR_INNER 0u
+#define COLOR_EDGE 1u
+#define COLOR_EMBOSS 2u
+
+/* 2bits for trias type */
+#define TRIA_FLAG uint(1 << 14) /* is tria vert */
+#define TRIA_FIRST INNER_FLAG /* is first tria (reuse INNER_FLAG) */
+
+/* We can reuse the CORNER_* bits for tria */
+#define TRIA_VEC_RANGE BIT_RANGE(6)
+
+/* Some GPUs have performanse issues with this array being const (Doesn't fit in the registers?).
+ * To resolve this issue, store the array as a uniform buffer.
+ * (The array is still stored in the registry, but indexing is done in the uniform buffer.) */
+uniform vec2 triavec[43] = vec2[43](
+
+ /* ROUNDBOX_TRIA_ARROWS */
+ vec2(-0.170000, 0.400000), vec2(-0.050000, 0.520000), vec2( 0.250000, 0.000000), vec2( 0.470000, -0.000000), vec2(-0.170000, -0.400000), vec2(-0.050000, -0.520000),
+ vec2( 0.170000, 0.400000), vec2( 0.050000, 0.520000), vec2(-0.250000, 0.000000), vec2(-0.470000, -0.000000), vec2( 0.170000, -0.400000), vec2( 0.050000, -0.520000),
+
+ /* ROUNDBOX_TRIA_SCROLL - circle tria (triangle strip) */
+ vec2(0.000000, 1.000000),
+ vec2(0.382684, 0.923879), vec2(-0.382683, 0.923880),
+ vec2(0.707107, 0.707107), vec2(-0.707107, 0.707107),
+ vec2(0.923879, 0.382684), vec2(-0.923879, 0.382684),
+ vec2(1.000000, 0.000000), vec2(-1.000000, 0.000000),
+ vec2(0.923879, -0.382684), vec2(-0.923879, -0.382684),
+ vec2(0.707107, -0.707107), vec2(-0.707107, -0.707107),
+ vec2(0.382684, -0.923879), vec2(-0.382683, -0.923880),
+ vec2(0.000000, -1.000000),
+
+ /* ROUNDBOX_TRIA_MENU - menu arrows */
+ vec2(-0.51, 0.08), vec2(-0.41, 0.20), vec2(-0.05, -0.39),
+ vec2(-0.05, -0.18), vec2(0.41, 0.08), vec2(0.3, 0.20),
+
+
+ /* ROUNDBOX_TRIA_CHECK - check mark */
+ vec2(-0.67000, 0.020000), vec2(-0.500000, 0.190000), vec2(-0.130000, -0.520000),
+ vec2(-0.130000, -0.170000), vec2(0.720000, 0.430000), vec2(0.530000, 0.590000),
+
+ /* ROUNDBOX_TRIA_HOLD_ACTION_ARROW - hold action arrows */
+#define OX (-0.32)
+#define OY (0.1)
+#define SC (0.35 * 2)
+// vec2(-0.5 + SC, 1.0 + OY), vec2( 0.5, 1.0 + OY), vec2( 0.5, 0.0 + OY + SC),
+ vec2((0.5 - SC) + OX, 1.0 + OY), vec2(-0.5 + OX, 1.0 + OY), vec2(-0.5 + OX, SC + OY)
+#undef OX
+#undef OY
+#undef SC
+);
+
+uniform mat4 ModelViewProjectionMatrix;
+
+#define MAX_PARAM 11
+#ifdef USE_INSTANCE
+#define MAX_INSTANCE 6
+uniform vec4 parameters[MAX_PARAM * MAX_INSTANCE];
+#else
+uniform vec4 parameters[MAX_PARAM];
+#endif
+
+/* gl_InstanceID is 0 if not drawing instances. */
+#define recti parameters[gl_InstanceID * MAX_PARAM + 0]
+#define rect parameters[gl_InstanceID * MAX_PARAM + 1]
+#define radsi parameters[gl_InstanceID * MAX_PARAM + 2].x
+#define rads parameters[gl_InstanceID * MAX_PARAM + 2].y
+#define faci parameters[gl_InstanceID * MAX_PARAM + 2].zw
+#define roundCorners parameters[gl_InstanceID * MAX_PARAM + 3]
+#define colorInner1 parameters[gl_InstanceID * MAX_PARAM + 4]
+#define colorInner2 parameters[gl_InstanceID * MAX_PARAM + 5]
+#define colorEdge parameters[gl_InstanceID * MAX_PARAM + 6]
+#define colorEmboss parameters[gl_InstanceID * MAX_PARAM + 7]
+#define colorTria parameters[gl_InstanceID * MAX_PARAM + 8]
+#define tria1Center parameters[gl_InstanceID * MAX_PARAM + 9].xy
+#define tria2Center parameters[gl_InstanceID * MAX_PARAM + 9].zw
+#define tria1Size parameters[gl_InstanceID * MAX_PARAM + 10].x
+#define tria2Size parameters[gl_InstanceID * MAX_PARAM + 10].y
+#define shadeDir parameters[gl_InstanceID * MAX_PARAM + 10].z
+#define alphaDiscard parameters[gl_InstanceID * MAX_PARAM + 10].w
+
+/* We encode alpha check and discard factor together. */
+#define doAlphaCheck (alphaDiscard < 0.0)
+#define discardFactor abs(alphaDiscard)
+
+in uint vflag;
+
+noperspective out vec4 finalColor;
+noperspective out float butCo;
+flat out float discardFac;
+
+vec2 do_widget(void)
+{
+ uint cflag = vflag & CNR_FLAG_RANGE;
+ uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE;
+
+ vec2 v = cornervec[cflag * 9u + vofs];
+
+ bool is_inner = (vflag & INNER_FLAG) != 0u;
+
+ /* Scale by corner radius */
+ v *= roundCorners[cflag] * ((is_inner) ? radsi : rads);
+
+ /* Position to corner */
+ vec4 rct = (is_inner) ? recti : rect;
+ if (cflag == BOTTOM_LEFT)
+ v += rct.xz;
+ else if (cflag == BOTTOM_RIGHT)
+ v += rct.yz;
+ else if (cflag == TOP_RIGHT)
+ v += rct.yw;
+ else /* (cflag == TOP_LEFT) */
+ v += rct.xw;
+
+ vec2 uv = faci * (v - recti.xz);
+
+ /* compute uv and color gradient */
+ uint color_id = (vflag >> COLOR_OFS) & COLOR_RANGE;
+ if (color_id == COLOR_INNER) {
+ float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0);
+
+ if (doAlphaCheck) {
+ finalColor = colorInner1;
+ butCo = uv.x;
+ }
+ else {
+ finalColor = mix(colorInner2, colorInner1, fac);
+ butCo = -abs(uv.x);
+ }
+ }
+ else if (color_id == COLOR_EDGE) {
+ finalColor = colorEdge;
+ butCo = -abs(uv.x);
+ }
+ else /* (color_id == COLOR_EMBOSS) */ {
+ finalColor = colorEmboss;
+ butCo = -abs(uv.x);
+ }
+
+ bool is_emboss = (vflag & EMBOSS_FLAG) != 0u;
+ v.y -= (is_emboss) ? 1.0f : 0.0;
+
+ return v;
+}
+
+vec2 do_tria()
+{
+ uint vofs = vflag & TRIA_VEC_RANGE;
+
+ vec2 v = triavec[vofs];
+
+ finalColor = colorTria;
+ butCo = -1.0;
+
+ bool is_tria_first = (vflag & TRIA_FIRST) != 0u;
+
+ if (is_tria_first)
+ v = v * tria1Size + tria1Center;
+ else
+ v = v * tria2Size + tria2Center;
+
+ return v;
+}
+
+void main()
+{
+ discardFac = discardFactor;
+ bool is_tria = (vflag & TRIA_FLAG) != 0u;
+
+ vec2 v = (is_tria) ? do_tria() : do_widget();
+
+ /* Antialiasing offset */
+ v += jit[(vflag >> JIT_OFS) & JIT_RANGE];
+
+ gl_Position = ModelViewProjectionMatrix * vec4(v, 0.0, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl
new file mode 100644
index 00000000000..fc4d055a903
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl
@@ -0,0 +1,13 @@
+
+in float shadowFalloff;
+
+out vec4 fragColor;
+
+uniform float alpha;
+
+void main()
+{
+ fragColor = vec4(0.0);
+ /* Manual curve fit of the falloff curve of previous drawing method. */
+ fragColor.a = alpha * (shadowFalloff * shadowFalloff * 0.722 + shadowFalloff * 0.277);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl
new file mode 100644
index 00000000000..f6be496ac4f
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl
@@ -0,0 +1,64 @@
+#define BIT_RANGE(x) uint((1 << x) - 1)
+
+/* 2 bits for corner */
+/* Attention! Not the same order as in UI_interface.h!
+ * Ordered by drawing order. */
+#define BOTTOM_LEFT 0u
+#define BOTTOM_RIGHT 1u
+#define TOP_RIGHT 2u
+#define TOP_LEFT 3u
+#define CNR_FLAG_RANGE BIT_RANGE(2)
+
+/* 4bits for corner id */
+#define CORNER_VEC_OFS 2u
+#define CORNER_VEC_RANGE BIT_RANGE(4)
+const vec2 cornervec[36] = vec2[36](
+ vec2(0.0, 1.0), vec2(0.02, 0.805), vec2(0.067, 0.617), vec2(0.169, 0.45), vec2(0.293, 0.293), vec2(0.45, 0.169), vec2(0.617, 0.076), vec2(0.805, 0.02), vec2(1.0, 0.0),
+ vec2(-1.0, 0.0), vec2(-0.805, 0.02), vec2(-0.617, 0.067), vec2(-0.45, 0.169), vec2(-0.293, 0.293), vec2(-0.169, 0.45), vec2(-0.076, 0.617), vec2(-0.02, 0.805), vec2(0.0, 1.0),
+ vec2(0.0, -1.0), vec2(-0.02, -0.805), vec2(-0.067, -0.617), vec2(-0.169, -0.45), vec2(-0.293, -0.293), vec2(-0.45, -0.169), vec2(-0.617, -0.076), vec2(-0.805, -0.02), vec2(-1.0, 0.0),
+ vec2(1.0, 0.0), vec2(0.805, -0.02), vec2(0.617, -0.067), vec2(0.45, -0.169), vec2(0.293, -0.293), vec2(0.169, -0.45), vec2(0.076, -0.617), vec2(0.02, -0.805), vec2(0.0, -1.0)
+);
+
+#define INNER_FLAG uint(1 << 10) /* is inner vert */
+
+uniform mat4 ModelViewProjectionMatrix;
+
+uniform vec4 parameters[4];
+/* radi and rad per corner */
+#define recti parameters[0]
+#define rect parameters[1]
+#define radsi parameters[2].x
+#define rads parameters[2].y
+#define roundCorners parameters[3]
+
+in uint vflag;
+
+out float shadowFalloff;
+
+void main()
+{
+ uint cflag = vflag & CNR_FLAG_RANGE;
+ uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE;
+
+ vec2 v = cornervec[cflag * 9u + vofs];
+
+ bool is_inner = (vflag & INNER_FLAG) != 0u;
+
+ shadowFalloff = (is_inner) ? 1.0 : 0.0;
+
+ /* Scale by corner radius */
+ v *= roundCorners[cflag] * ((is_inner) ? radsi : rads);
+
+ /* Position to corner */
+ vec4 rct = (is_inner) ? recti : rect;
+ if (cflag == BOTTOM_LEFT)
+ v += rct.xz;
+ else if (cflag == BOTTOM_RIGHT)
+ v += rct.yz;
+ else if (cflag == TOP_RIGHT)
+ v += rct.yw;
+ else /* (cflag == TOP_LEFT) */
+ v += rct.xw;
+
+ gl_Position = ModelViewProjectionMatrix * vec4(v, 0.0, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
new file mode 100644
index 00000000000..84e44837264
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
@@ -0,0 +1,12 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelMatrix;
+uniform vec4 ClipPlane;
+
+in vec3 pos;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_ClipDistance[0] = dot(ModelMatrix * vec4(pos, 1.0), ClipPlane);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
new file mode 100644
index 00000000000..7db7e28d8e6
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
@@ -0,0 +1,26 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+#if defined(USE_COLOR_U32)
+in uint color;
+#else
+in vec4 color;
+#endif
+
+flat out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+#if defined(USE_COLOR_U32)
+ finalColor = vec4(
+ ((color ) & uint(0xFF)) * (1.0f / 255.0f),
+ ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f),
+ ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f),
+ ((color >> 24) ) * (1.0f / 255.0f));
+#else
+ finalColor = color;
+#endif
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl
new file mode 100644
index 00000000000..f16fa21b342
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl
@@ -0,0 +1,16 @@
+
+/* Make to be used with dynamic batching so no Model Matrix needed */
+uniform mat4 ViewProjectionMatrix;
+
+layout(points) in;
+layout(line_strip, max_vertices = 2) out;
+
+void main()
+{
+ vec3 vert = gl_in[0].gl_Position.xyz;
+ gl_Position = ViewProjectionMatrix * vec4(vert.xyz, 1.0);
+ EmitVertex();
+ gl_Position = ViewProjectionMatrix * vec4(vert.xy, 0.0, 1.0);
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl
new file mode 100644
index 00000000000..55f410eb25d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl
@@ -0,0 +1,11 @@
+
+/* Made to be used with dynamic batching so no Model Matrix needed */
+uniform mat4 ViewProjectionMatrix;
+
+in vec3 pos;
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * vec4(pos.xy, 0.0, 1.0);
+ gl_PointSize = 2.0;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl
new file mode 100644
index 00000000000..eb877ab20b6
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl
@@ -0,0 +1,12 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 texCoord;
+in vec3 pos;
+out vec2 texCoord_interp;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos.xyz, 1.0f);
+ texCoord_interp = texCoord;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl
new file mode 100644
index 00000000000..84fbf977846
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl
@@ -0,0 +1,26 @@
+
+/*
+ * Vertex Shader for dashed lines with 3D coordinates, with uniform multi-colors or uniform single-color,
+ * and unary thickness.
+ *
+ * Legacy version, without geometry shader support, always produce solid lines!
+ */
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewport_size;
+
+uniform vec4 color;
+
+in vec3 pos;
+noperspective out float distance_along_line;
+noperspective out vec4 color_geom;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ /* Hack - prevent stupid GLSL compiler to optimize out unused viewport_size uniform, which gives crash! */
+ distance_along_line = viewport_size.x * 0.000001f - viewport_size.x * 0.0000009f;
+
+ color_geom = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
new file mode 100644
index 00000000000..2fe08896585
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
@@ -0,0 +1,21 @@
+
+/*
+ * Vertex Shader for dashed lines with 3D coordinates, with uniform multi-colors or uniform single-color,
+ * and unary thickness.
+ *
+ * Dashed is performed in screen space.
+ */
+
+uniform mat4 ModelViewProjectionMatrix;
+
+uniform vec4 color;
+
+in vec3 pos;
+
+out vec4 color_vert;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ color_vert = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl
new file mode 100644
index 00000000000..e6b8fed7265
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl
@@ -0,0 +1,22 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+
+in vec3 pos;
+in vec3 nor;
+in vec4 color;
+
+#ifdef USE_FLAT_NORMAL
+flat out vec3 normal;
+flat out vec4 finalColor;
+#else
+out vec3 normal;
+out vec4 finalColor;
+#endif
+
+void main()
+{
+ normal = normalize(NormalMatrix * nor);
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl
new file mode 100644
index 00000000000..a3f447a85f9
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl
@@ -0,0 +1,13 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+
+in vec3 pos;
+in vec3 nor;
+out vec3 normal;
+
+void main()
+{
+ normal = normalize(NormalMatrix * nor);
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl
new file mode 100644
index 00000000000..60793bf56b6
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl
@@ -0,0 +1,8 @@
+
+/* Does Nothing */
+in vec3 pos;
+
+void main()
+{
+ gl_Position = vec4(pos, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
new file mode 100644
index 00000000000..2fe9c0623fa
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
@@ -0,0 +1,12 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 color;
+out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
new file mode 100644
index 00000000000..ebc945fcf35
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
@@ -0,0 +1,21 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform float size;
+
+in vec3 pos;
+out vec2 radii;
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = size;
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * size;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+
+ // convert to PointCoord units
+ radii /= size;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl
new file mode 100644
index 00000000000..0d6b90cfba4
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl
@@ -0,0 +1,24 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform float size;
+uniform float outlineWidth;
+
+in vec3 pos;
+out vec4 radii;
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = size;
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * size;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+ radii[2] = radius - outlineWidth;
+ radii[3] = radius - outlineWidth - 1.0;
+
+ // convert to PointCoord units
+ radii /= size;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
new file mode 100644
index 00000000000..e14b9535c89
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
@@ -0,0 +1,14 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in float size;
+in vec4 color;
+out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = size;
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl
new file mode 100644
index 00000000000..e4f173ab617
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl
@@ -0,0 +1,11 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in float size;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = size;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
new file mode 100644
index 00000000000..41fdefd22e8
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
@@ -0,0 +1,8 @@
+
+in vec4 finalColor;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = finalColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl
new file mode 100644
index 00000000000..a1feb2f75b7
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl
@@ -0,0 +1,13 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 color;
+
+out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl
new file mode 100644
index 00000000000..059473ebb74
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl
@@ -0,0 +1,9 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
deleted file mode 100644
index a030756e992..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
+++ /dev/null
@@ -1,288 +0,0 @@
-
-/* Options:
- *
- * USE_COLOR: use glColor for diffuse colors
- * USE_TEXTURE: use texture for diffuse colors
- * USE_TEXTURE_RECTANGLE: use GL_TEXTURE_RECTANGLE instead of GL_TEXTURE_2D
- * USE_SCENE_LIGHTING: use lights (up to 8)
- * USE_SOLID_LIGHTING: assume 3 directional lights for solid draw mode
- * USE_TWO_SIDED: flip normal towards viewer
- * NO_SPECULAR: use specular component
- */
-
-#define NUM_SOLID_LIGHTS 3
-#define NUM_SCENE_LIGHTS 8
-
-/* Keep these in sync with GPU_basic_shader.h */
-#define STIPPLE_HALFTONE 0
-#define STIPPLE_QUARTTONE 1
-#define STIPPLE_CHECKER_8PX 2
-#define STIPPLE_HEXAGON 3
-#define STIPPLE_DIAG_STRIPES 4
-#define STIPPLE_DIAG_STRIPES_SWAP 5
-#define STIPPLE_S3D_INTERLACE_ROW 6
-#define STIPPLE_S3D_INTERLACE_ROW_SWAP 7
-#define STIPPLE_S3D_INTERLACE_COLUMN 8
-#define STIPPLE_S3D_INTERLACE_COLUMN_SWAP 9
-#define STIPPLE_S3D_INTERLACE_CHECKERBOARD 10
-#define STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP 11
-
-#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
-#if defined(USE_FLAT_NORMAL)
-varying vec3 eyespace_vert_pos;
-#else
-varying vec3 varying_normal;
-#endif
-#ifndef USE_SOLID_LIGHTING
-varying vec3 varying_position;
-#endif
-#endif
-
-#ifdef USE_COLOR
-varying vec4 varying_vertex_color;
-#endif
-
-#ifdef USE_TEXTURE
-#ifdef USE_TEXTURE_RECTANGLE
-#define sampler2D_default sampler2DRect
-#define texture2D_default texture2DRect
-#else
-#define sampler2D_default sampler2D
-#define texture2D_default texture2D
-#endif
-
-varying vec2 varying_texture_coord;
-uniform sampler2D_default texture_map;
-#endif
-
-#ifdef USE_STIPPLE
-uniform int stipple_id;
-#if defined(DRAW_LINE)
-varying in float t;
-uniform int stipple_pattern;
-#endif
-#endif
-
-void main()
-{
-#if defined(USE_STIPPLE)
-#if defined(DRAW_LINE)
- /* GLSL 1.3 */
- if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
- discard;
-#else
- /* We have to use mod function and integer casting.
- * This can be optimized further with the bitwise operations
- * when GLSL 1.3 is supported. */
- if (stipple_id == STIPPLE_HALFTONE ||
- stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD ||
- stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
- {
- int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2));
- bool dis = result == 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_QUARTTONE) {
- int mody = int(mod(gl_FragCoord.y, 4));
- int modx = int(mod(gl_FragCoord.x, 4));
- if (mody == 0) {
- if (modx != 2)
- discard;
- }
- else if (mody == 2) {
- if (modx != 0)
- discard;
- }
- else
- discard;
- }
- else if (stipple_id == STIPPLE_CHECKER_8PX) {
- int result = int(mod(int(gl_FragCoord.x) / 8 + int(gl_FragCoord.y) / 8, 2));
- if (result != 0)
- discard;
- }
- else if (stipple_id == STIPPLE_DIAG_STRIPES) {
- int mody = int(mod(gl_FragCoord.y, 16));
- int modx = int(mod(gl_FragCoord.x, 16));
- if ((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)
- discard;
- }
- else if (stipple_id == STIPPLE_DIAG_STRIPES_SWAP) {
- int mody = int(mod(gl_FragCoord.y, 16));
- int modx = int(mod(gl_FragCoord.x, 16));
- if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx))
- discard;
- }
- else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) {
- int result = int(mod(gl_FragCoord.y, 2));
- bool dis = result == 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) {
- int result = int(mod(gl_FragCoord.x, 2));
- bool dis = result != 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_HEXAGON) {
- int mody = int(mod(gl_FragCoord.y, 2));
- int modx = int(mod(gl_FragCoord.x, 4));
- if (mody != 0) {
- if (modx != 1)
- discard;
- }
- else {
- if (modx != 3)
- discard;
- }
- }
-#endif /* !DRAW_LINE */
-#endif /* USE_STIPPLE */
-
-#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
- /* compute normal */
-#if defined(USE_FLAT_NORMAL)
- vec3 N = normalize(cross(dFdx(eyespace_vert_pos), dFdy(eyespace_vert_pos)));
-#else
- vec3 N = normalize(varying_normal);
-#endif
-
-#ifdef USE_TWO_SIDED
- if (!gl_FrontFacing)
- N = -N;
-#endif
-
- /* compute diffuse and specular lighting */
- vec3 L_diffuse = vec3(0.0);
-#ifndef NO_SPECULAR
- vec3 L_specular = vec3(0.0);
-#endif
-
-#ifdef USE_SOLID_LIGHTING
- /* assume 3 directional lights */
- for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
- vec3 light_direction = gl_LightSource[i].position.xyz;
-
- /* diffuse light */
- vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
- float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse * diffuse_bsdf;
-
-#ifndef NO_SPECULAR
- /* specular light */
- vec3 light_specular = gl_LightSource[i].specular.rgb;
- vec3 H = gl_LightSource[i].halfVector.xyz;
-
- float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
- L_specular += light_specular * specular_bsdf;
-#endif
- }
-#else
- /* all 8 lights, makes no assumptions, potentially slow */
-
-#ifndef NO_SPECULAR
- /* view vector computation, depends on orthographics or perspective */
- vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position) : vec3(0.0, 0.0, -1.0);
-#endif
-
- for (int i = 0; i < NUM_SCENE_LIGHTS; i++) {
- /* todo: this is a slow check for disabled lights */
- if (gl_LightSource[i].specular.a == 0.0)
- continue;
-
- float intensity = 1.0;
- vec3 light_direction;
-
- if (gl_LightSource[i].position.w == 0.0) {
- /* directional light */
- light_direction = gl_LightSource[i].position.xyz;
- }
- else {
- /* point light */
- vec3 d = gl_LightSource[i].position.xyz - varying_position;
- light_direction = normalize(d);
-
- /* spot light cone */
- if (gl_LightSource[i].spotCutoff < 90.0) {
- float cosine = max(dot(light_direction, -gl_LightSource[i].spotDirection), 0.0);
- intensity = pow(cosine, gl_LightSource[i].spotExponent);
- intensity *= step(gl_LightSource[i].spotCosCutoff, cosine);
- }
-
- /* falloff */
- float distance = length(d);
-
- intensity /= gl_LightSource[i].constantAttenuation +
- gl_LightSource[i].linearAttenuation * distance +
- gl_LightSource[i].quadraticAttenuation * distance * distance;
- }
-
- /* diffuse light */
- vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
- float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse * diffuse_bsdf * intensity;
-
-#ifndef NO_SPECULAR
- /* specular light */
- vec3 light_specular = gl_LightSource[i].specular.rgb;
- vec3 H = normalize(light_direction - V);
-
- float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
- L_specular += light_specular * specular_bsdf * intensity;
-#endif
- }
-#endif
-
- /* compute diffuse color, possibly from texture or vertex colors */
- float alpha;
-
-#if defined(USE_TEXTURE) && defined(USE_COLOR)
- vec4 texture_color = texture2D_default(texture_map, varying_texture_coord);
-
- L_diffuse *= texture_color.rgb * varying_vertex_color.rgb;
- alpha = texture_color.a * varying_vertex_color.a;
-#elif defined(USE_TEXTURE)
- vec4 texture_color = texture2D_default(texture_map, varying_texture_coord);
-
- L_diffuse *= texture_color.rgb;
- alpha = texture_color.a;
-#elif defined(USE_COLOR)
- L_diffuse *= varying_vertex_color.rgb;
- alpha = varying_vertex_color.a;
-#else
- L_diffuse *= gl_FrontMaterial.diffuse.rgb;
- alpha = gl_FrontMaterial.diffuse.a;
-#endif
-
- /* sum lighting */
- vec3 L = gl_FrontLightModelProduct.sceneColor.rgb + L_diffuse;
-
-#ifndef NO_SPECULAR
- L += L_specular * gl_FrontMaterial.specular.rgb;
-#endif
-
- /* write out fragment color */
- gl_FragColor = vec4(L, alpha);
-#else
-
- /* no lighting */
-#if defined(USE_TEXTURE) && defined(USE_COLOR)
- gl_FragColor = texture2D_default(texture_map, varying_texture_coord) * varying_vertex_color;
-#elif defined(USE_TEXTURE)
- gl_FragColor = texture2D_default(texture_map, varying_texture_coord);
-#elif defined(USE_COLOR)
- gl_FragColor = varying_vertex_color;
-#else
- gl_FragColor = gl_FrontMaterial.diffuse;
-#endif
-
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
deleted file mode 100644
index a88681a5fd3..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
- */
-
-#define PASSTHROUGH 0
-
-layout(lines) in;
-
-#if defined(DRAW_LINE)
-
-#if PASSTHROUGH
-layout(line_strip, max_vertices = 10) out;
-#else
-layout(triangle_strip, max_vertices = 6) out;
-#endif
-
-varying out float t;
-varying in vec4 varying_vertex_color_line[];
-varying out vec4 varying_vertex_color;
-
-uniform ivec4 viewport;
-uniform float line_width;
-uniform int stipple_factor;
-
-void main(void)
-{
- vec2 window_size = viewport.zw;
- vec4 start = gl_in[0].gl_Position;
- vec4 end = gl_in[1].gl_Position;
-#if PASSTHROUGH
- gl_Position = start; EmitVertex();
- gl_Position = end; EmitVertex();
- EndPrimitive();
- return;
-#endif
-
- /* t = 0 t = ~(len(end - start) + 2*line_width)
- * A-------------------------------------B
- * | | | |
- * | side | |
- * | | | |
- * |--axis--*start--------------*end-----|
- * | | | |
- * | | | |
- * | | | |
- * D-------------------------------------C
- */
-
- /* Clip the line before homogenization.
- * Compute line start and end distances to nearplane in clipspace
- * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
- */
- float t0 = start.z + start.w;
- float t1 = end.z + end.w;
- if (t0 < 0.0) {
- if (t1 < 0.0) {
- return;
- }
- start = mix(start, end, (0 - t0) / (t1 - t0));
- }
- if (t1 < 0.0) {
- end = mix(start, end, (0 - t0) / (t1 - t0));
- }
-
- /* Compute line axis and side vector in screen space */
- vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
- vec2 endInNDC = end.xy / end.w;
- vec2 lineInNDC = endInNDC - startInNDC;
- vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
-
- vec2 axisInScreen = normalize(lineInScreen);
- vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
- vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
- vec2 sideInNDC = sideInScreen / window_size;
- vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
- vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
-
- vec4 A = (start + (side - axis) * start.w);
- vec4 B = (end + (side + axis) * end.w);
- vec4 C = (end - (side - axis) * end.w);
- vec4 D = (start - (side + axis) * start.w);
-
- /* There is no relation between lines yet */
- /* TODO Pass here t0 to make continuous pattern. */
- t0 = 0;
- t1 = (length(lineInScreen) + 2 * line_width) / (2 * line_width * stipple_factor);
-
- gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
- gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
- gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
- gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
- EndPrimitive();
-}
-
-#else
-void main(void)
-{
-
-}
-#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
deleted file mode 100644
index c29a39b4e34..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
+++ /dev/null
@@ -1,71 +0,0 @@
-
-#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
-#if defined(USE_FLAT_NORMAL)
-varying vec3 eyespace_vert_pos;
-#else
-varying vec3 varying_normal;
-#endif
-
-#ifndef USE_SOLID_LIGHTING
-varying vec3 varying_position;
-#endif
-#endif
-
-#ifdef USE_COLOR
-#ifdef DRAW_LINE
-varying vec4 varying_vertex_color_line;
-#else
-varying vec4 varying_vertex_color;
-#endif
-#endif
-
-#ifdef USE_TEXTURE
-varying vec2 varying_texture_coord;
-#endif
-
-#ifdef CLIP_WORKAROUND
-varying float gl_ClipDistance[6];
-#endif
-
-void main()
-{
- vec4 co = gl_ModelViewMatrix * gl_Vertex;
-
-#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
-#if !defined(USE_FLAT_NORMAL)
- varying_normal = normalize(gl_NormalMatrix * gl_Normal);
-#endif
-#if defined(USE_FLAT_NORMAL)
- /* transform vertex into eyespace */
- eyespace_vert_pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
-#endif
-
-#ifndef USE_SOLID_LIGHTING
- varying_position = co.xyz;
-#endif
-#endif
-
- gl_Position = gl_ProjectionMatrix * co;
-
-#ifdef CLIP_WORKAROUND
- int i;
- for (i = 0; i < 6; i++)
- gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
-#elif !defined(GPU_ATI)
- // Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
- // graphic cards, while on ATI it can cause a software fallback.
- gl_ClipVertex = co;
-#endif
-
-#ifdef USE_COLOR
-#ifdef DRAW_LINE
- varying_vertex_color_line = gl_Color;
-#else
- varying_vertex_color = gl_Color;
-#endif
-#endif
-
-#ifdef USE_TEXTURE
- varying_texture_coord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).st;
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl
new file mode 100644
index 00000000000..545f6d19e21
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl
@@ -0,0 +1,20 @@
+
+uniform vec4 color1;
+uniform vec4 color2;
+uniform int size;
+
+out vec4 fragColor;
+
+void main()
+{
+ vec2 phase = mod(gl_FragCoord.xy, (size*2));
+
+ if ((phase.x > size && phase.y < size) ||
+ (phase.x < size && phase.y > size))
+ {
+ fragColor = color1;
+ }
+ else {
+ fragColor = color2;
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl
new file mode 100644
index 00000000000..60e71e19004
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl
@@ -0,0 +1,6 @@
+
+void main()
+{
+ // no color output, only depth (line below is implicit)
+ // gl_FragDepth = gl_FragCoord.z;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl
new file mode 100644
index 00000000000..beb71c58100
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl
@@ -0,0 +1,20 @@
+
+uniform vec4 color1;
+uniform vec4 color2;
+uniform int size1;
+uniform int size2;
+
+out vec4 fragColor;
+
+void main()
+{
+ float phase = mod((gl_FragCoord.x + gl_FragCoord.y), (size1 + size2));
+
+ if (phase < size1)
+ {
+ fragColor = color1;
+ }
+ else {
+ fragColor = color2;
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl
new file mode 100644
index 00000000000..4ed7ed56c11
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl
@@ -0,0 +1,54 @@
+
+// Draw "fancy" wireframe, displaying front-facing, back-facing and
+// silhouette lines differently.
+// Mike Erwin, April 2015
+
+uniform bool drawFront = true;
+uniform bool drawBack = true;
+uniform bool drawSilhouette = true;
+
+uniform vec4 frontColor;
+uniform vec4 backColor;
+uniform vec4 silhouetteColor;
+
+uniform vec3 eye; // direction we are looking
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+
+// normals of faces this edge joins (object coords)
+in vec3 N1;
+in vec3 N2;
+
+flat out vec4 finalColor;
+
+// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley
+
+// to discard an entire line, set both endpoints to nowhere
+// and it won't produce any fragments
+const vec4 nowhere = vec4(vec3(0.0), 1.0);
+
+void main()
+{
+ bool face_1_front = dot(N1, eye) > 0.0;
+ bool face_2_front = dot(N2, eye) > 0.0;
+
+ vec4 position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ if (face_1_front && face_2_front) {
+ // front-facing edge
+ gl_Position = drawFront ? position : nowhere;
+ finalColor = frontColor;
+ }
+ else if (face_1_front || face_2_front) {
+ // exactly one face is front-facing, silhouette edge
+ gl_Position = drawSilhouette ? position : nowhere;
+ finalColor = silhouetteColor;
+ }
+ else {
+ // back-facing edge
+ gl_Position = drawBack ? position : nowhere;
+ finalColor = backColor;
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl
new file mode 100644
index 00000000000..e7632fcad15
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl
@@ -0,0 +1,60 @@
+
+// Draw "fancy" wireframe, displaying front-facing, back-facing and
+// silhouette lines differently.
+// Mike Erwin, April 2015
+
+// After working with this shader a while, convinced we should make
+// separate shaders for perpective & ortho. (Oct 2016)
+
+// Due to perspective, the line segment's endpoints might disagree on
+// whether the adjacent faces are front facing. This geometry shader
+// decides which edge type to use if endpoints disagree.
+
+uniform mat4 ProjectionMatrix;
+
+uniform bool drawFront = true;
+uniform bool drawBack = true;
+uniform bool drawSilhouette = true;
+
+uniform vec4 frontColor;
+uniform vec4 backColor;
+uniform vec4 silhouetteColor;
+
+layout(lines) in;
+layout(line_strip, max_vertices = 2) out;
+
+in vec4 MV_pos[];
+in float edgeClass[];
+
+flat out vec4 finalColor;
+
+void emitLine(vec4 color)
+{
+ gl_Position = ProjectionMatrix * MV_pos[0];
+ EmitVertex();
+ gl_Position = ProjectionMatrix * MV_pos[1];
+ finalColor = color;
+ EmitVertex();
+ EndPrimitive();
+}
+
+void main()
+{
+ float finalEdgeClass = max(edgeClass[0], edgeClass[1]);
+
+ if (finalEdgeClass > 0.0f) {
+ // front-facing edge
+ if (drawFront)
+ emitLine(frontColor);
+ }
+ else if (finalEdgeClass < 0.0f) {
+ // back-facing edge
+ if (drawBack)
+ emitLine(backColor);
+ }
+ else {
+ // exactly one face is front-facing, silhouette edge
+ if (drawSilhouette)
+ emitLine(silhouetteColor);
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl
new file mode 100644
index 00000000000..30b3bdb890d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl
@@ -0,0 +1,68 @@
+
+// Draw "fancy" wireframe, displaying front-facing, back-facing and
+// silhouette lines differently.
+// Mike Erwin, April 2015
+
+// After working with this shader a while, convinced we should make
+// separate shaders for perpective & ortho. (Oct 2016)
+
+// This shader is an imperfect stepping stone until all platforms are
+// ready for geometry shaders.
+
+// Due to perspective, the line segment's endpoints might disagree on
+// whether the adjacent faces are front facing. Need to use a geometry
+// shader or pass in an extra position attribute (the other endpoint)
+// to do this properly.
+
+uniform bool drawFront = true;
+uniform bool drawBack = true;
+uniform bool drawSilhouette = true;
+
+uniform vec4 frontColor;
+uniform vec4 backColor;
+uniform vec4 silhouetteColor;
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+
+in vec3 pos;
+
+// normals of faces this edge joins (object coords)
+in vec3 N1;
+in vec3 N2;
+
+flat out vec4 finalColor;
+
+// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley
+
+// to discard an entire line, set its color to invisible
+// (must have GL_BLEND enabled, or discard in fragment shader)
+const vec4 invisible = vec4(0.0);
+
+bool front(vec3 N)
+{
+ vec4 xformed = ModelViewMatrix * vec4(pos, 1.0);
+ return dot(NormalMatrix * N, normalize(-xformed.xyz)) > 0.0;
+}
+
+void main()
+{
+ bool face_1_front = front(N1);
+ bool face_2_front = front(N2);
+
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ if (face_1_front && face_2_front) {
+ // front-facing edge
+ finalColor = drawFront ? frontColor : invisible;
+ }
+ else if (face_1_front || face_2_front) {
+ // exactly one face is front-facing, silhouette edge
+ finalColor = drawSilhouette ? silhouetteColor : invisible;
+ }
+ else {
+ // back-facing edge
+ finalColor = drawBack ? backColor : invisible;
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl
new file mode 100644
index 00000000000..e1fb78dd1a9
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl
@@ -0,0 +1,44 @@
+
+// Draw "fancy" wireframe, displaying front-facing, back-facing and
+// silhouette lines differently.
+// Mike Erwin, April 2015
+
+// After working with this shader a while, convinced we should make
+// separate shaders for perpective & ortho. (Oct 2016)
+
+// Due to perspective, the line segment's endpoints might disagree on
+// whether the adjacent faces are front facing. We use a geometry
+// shader to resolve this properly.
+
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+
+in vec3 pos;
+in vec3 N1, N2; // normals of faces this edge joins (object coords)
+
+out vec4 MV_pos;
+out float edgeClass;
+
+// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley
+
+bool front(vec3 N, vec3 eye)
+{
+ return dot(NormalMatrix * N, eye) > 0.0;
+}
+
+void main()
+{
+ MV_pos = ModelViewMatrix * vec4(pos, 1.0);
+
+ vec3 eye = normalize(-MV_pos.xyz);
+
+ bool face_1_front = front(N1, eye);
+ bool face_2_front = front(N2, eye);
+
+ if (face_1_front && face_2_front)
+ edgeClass = 1.0; // front-facing edge
+ else if (face_1_front || face_2_front)
+ edgeClass = 0.0; // exactly one face is front-facing, silhouette edge
+ else
+ edgeClass = -1.0; // back-facing edge
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl
new file mode 100644
index 00000000000..0538c037dcf
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl
@@ -0,0 +1,20 @@
+
+#define SMOOTH 1
+
+const float transitionWidth = 1.0;
+
+uniform vec4 fillColor = vec4(0);
+uniform vec4 outlineColor = vec4(0,0,0,1);
+
+noperspective in vec3 distanceToOutline;
+
+out vec4 FragColor;
+
+void main() {
+ float edgeness = min(min(distanceToOutline.x, distanceToOutline.y), distanceToOutline.z);
+#if SMOOTH
+ FragColor = mix(outlineColor, fillColor, smoothstep(0, transitionWidth, edgeness));
+#else
+ FragColor = (edgeness <= 0) ? outlineColor : fillColor;
+#endif
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl
new file mode 100644
index 00000000000..ad0dccb6c81
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl
@@ -0,0 +1,67 @@
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+uniform float outlineWidth = 1.0;
+uniform vec2 viewportSize;
+
+in vec4 pos_xformed[];
+in float widthModulator[];
+
+noperspective out vec3 distanceToOutline;
+
+// project to screen space
+vec2 proj(int axis) {
+ vec4 pos = pos_xformed[axis];
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+float dist(vec2 pos[3], int v) {
+ // current vertex position
+ vec2 vpos = pos[v];
+ // endpoints of opposite edge
+ vec2 e1 = pos[(v + 1) % 3];
+ vec2 e2 = pos[(v + 2) % 3];
+
+ float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify
+ return abs_det / distance(e2, e1);
+}
+
+vec3 distance[3];
+
+void clearEdge(int v) {
+ float distant = 10 * outlineWidth;
+ for (int i = 0; i < 3; ++i)
+ distance[i][v] += distant;
+}
+
+void modulateEdge(int v) {
+ float offset = min(widthModulator[v],1) * outlineWidth;
+ for (int i = 0; i < 3; ++i)
+ distance[i][v] -= offset;
+}
+
+void main() {
+ vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2));
+
+ for (int v = 0; v < 3; ++v)
+ distance[v] = vec3(0);
+
+ for (int v = 0; v < 3; ++v) {
+ if (widthModulator[v] > 0) {
+ distance[v][v] = dist(pos, v);
+ modulateEdge(v);
+ }
+ }
+
+ for (int v = 0; v < 3; ++v)
+ if (widthModulator[v] <= 0)
+ clearEdge(v);
+
+ for (int v = 0; v < 3; ++v) {
+ gl_Position = pos_xformed[v];
+ distanceToOutline = distance[v];
+ EmitVertex();
+ }
+
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl
new file mode 100644
index 00000000000..ec692e210c2
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl
@@ -0,0 +1,52 @@
+layout(triangles) in;
+layout(triangle_strip, max_vertices=3) out;
+
+uniform float outlineWidth = 1.0;
+uniform vec2 viewportSize;
+
+noperspective out vec3 distanceToOutline;
+
+// project to screen space
+vec2 proj(int axis) {
+ vec4 pos = gl_in[axis].gl_Position;
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+float dist(vec2 pos[3], int v) {
+ // current vertex position
+ vec2 vpos = pos[v];
+ // endpoints of opposite edge
+ vec2 e1 = pos[(v + 1) % 3];
+ vec2 e2 = pos[(v + 2) % 3];
+
+ float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify
+ return abs_det / distance(e2, e1);
+}
+
+vec3 distance[3];
+
+void modulateEdge(int v) {
+ float offset = 0.5 * outlineWidth;
+ for (int i = 0; i < 3; ++i)
+ distance[i][v] -= offset;
+}
+
+void main() {
+ vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2));
+
+ for (int v = 0; v < 3; ++v)
+ distance[v] = vec3(0);
+
+ for (int v = 0; v < 3; ++v) {
+ distance[v][v] = dist(pos, v);
+ modulateEdge(v);
+ }
+
+ for (int v = 0; v < 3; ++v) {
+ gl_Position = gl_in[v].gl_Position;
+ distanceToOutline = distance[v];
+ EmitVertex();
+ }
+
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl
new file mode 100644
index 00000000000..fb1d0aafe05
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl
@@ -0,0 +1,13 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in float edgeWidthModulator;
+
+out vec4 pos_xformed;
+out float widthModulator;
+
+void main() {
+ pos_xformed = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ widthModulator = edgeWidthModulator;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
deleted file mode 100644
index 3819203bcd9..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-
-varying vec3 coords;
-
-uniform sampler3D flame_texture;
-uniform sampler1D spectrum_texture;
-
-void main()
-{
- float flame = texture3D(flame_texture, coords).r;
- vec4 emission = texture1D(spectrum_texture, flame);
-
- vec4 color;
- color.rgb = emission.a * emission.rgb;
- color.a = emission.a;
-
- gl_FragColor = color;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
new file mode 100644
index 00000000000..cefae1021d2
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
@@ -0,0 +1,11 @@
+
+flat in vec4 finalColor;
+out vec4 fragColor;
+
+void main()
+{
+ if (finalColor.a > 0.0)
+ fragColor = finalColor;
+ else
+ discard;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
new file mode 100644
index 00000000000..d738ed5ddb2
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
@@ -0,0 +1,8 @@
+
+flat in vec4 finalColor;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = finalColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl
new file mode 100644
index 00000000000..aa6f30531ae
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl
@@ -0,0 +1,8 @@
+
+flat in uint finalId;
+out uint fragId;
+
+void main()
+{
+ fragId = finalId;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl b/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl
deleted file mode 100644
index e04cd7d3306..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl
+++ /dev/null
@@ -1,14 +0,0 @@
-uniform sampler2D depthbuffer;
-varying vec4 uvcoordsvar;
-
-void main(void)
-{
- float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
-
- /* XRay background, discard */
- if (depth >= 1.0) {
- discard;
- }
-
- gl_FragDepth = depth;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
deleted file mode 100644
index 338ef6d51a7..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
+++ /dev/null
@@ -1,208 +0,0 @@
-/* amount of offset to move one pixel left-right.
- * In second pass some dimensions are zero to control verical/horizontal convolution */
-uniform vec2 invrendertargetdim;
-// color buffer
-uniform sampler2D colorbuffer;
-//blurred color buffer for DOF effect
-uniform sampler2D blurredcolorbuffer;
-// slightly blurred buffer
-uniform sampler2D mblurredcolorbuffer;
-// depth buffer
-uniform sampler2D depthbuffer;
-
-// this includes focal distance in x and aperture size in y
-uniform vec4 dof_params;
-
-// viewvectors for reconstruction of world space
-uniform vec4 viewvecs[3];
-
-// coordinates on framebuffer in normalized (0.0-1.0) uv space
-varying vec4 uvcoordsvar;
-
-/* color texture coordinates, offset by a small amount */
-varying vec2 color_uv1;
-varying vec2 color_uv2;
-
-varying vec2 depth_uv1;
-varying vec2 depth_uv2;
-varying vec2 depth_uv3;
-varying vec2 depth_uv4;
-
-
-float calculate_far_coc(in float zdepth)
-{
- float coc = dof_params.x * max(1.0 - dof_params.y / zdepth, 0.0);
-
- /* multiply by 1.0 / sensor size to get the normalized size */
- return coc * dof_params.z;
-}
-
-/* near coc only! when distance is nearer than focus plane first term is bigger than one */
-vec4 calculate_near_coc(in vec4 zdepth)
-{
- vec4 coc = dof_params.x * max(vec4(dof_params.y) / zdepth - vec4(1.0), vec4(0.0));
-
- /* multiply by 1.0 / sensor size to get the normalized size */
- return coc * dof_params.z;
-}
-
-/* first pass blurs the color buffer heavily and gets the near coc only.
- * There are many texture accesses here but they are done on a
- * lower resolution image so overall bandwidth is not a concern */
-void first_pass()
-{
- vec4 depth;
- vec4 zdepth;
- vec4 coc;
- float final_coc;
-
- /* amount to add to uvs so that they move one row further */
- vec2 offset_row[3];
- offset_row[0] = vec2(0.0, invrendertargetdim.y);
- offset_row[1] = 2.0 * offset_row[0];
- offset_row[2] = 3.0 * offset_row[0];
-
- /* heavily blur the image */
- vec4 color = texture2D(colorbuffer, color_uv1);
- color += texture2D(colorbuffer, color_uv1 + offset_row[1]);
- color += texture2D(colorbuffer, color_uv2);
- color += texture2D(colorbuffer, color_uv2 + offset_row[1]);
- color /= 4.0;
-
- depth.r = texture2D(depthbuffer, depth_uv1).r;
- depth.g = texture2D(depthbuffer, depth_uv2).r;
- depth.b = texture2D(depthbuffer, depth_uv3).r;
- depth.a = texture2D(depthbuffer, depth_uv4).r;
-
- zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
- coc = calculate_near_coc(zdepth);
-
- depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[0]).r;
- depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[0]).r;
- depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[0]).r;
- depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[0]).r;
-
- zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
- coc = max(calculate_near_coc(zdepth), coc);
-
- depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[1]).r;
- depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[1]).r;
- depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[1]).r;
- depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[1]).r;
-
- zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
- coc = max(calculate_near_coc(zdepth), coc);
-
- depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[2]).r;
- depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[2]).r;
- depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[2]).r;
- depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[2]).r;
-
- zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
- coc = max(calculate_near_coc(zdepth), coc);
-
- final_coc = max(max(coc.x, coc.y), max(coc.z, coc.w));
- gl_FragColor = vec4(color.rgb, final_coc);
-}
-
-/* second pass, gaussian blur the downsampled image */
-void second_pass()
-{
- vec4 depth = vec4(texture2D(depthbuffer, uvcoordsvar.xy).r);
-
- /* clever sampling to sample 2 pixels at once. Of course it's not real gaussian sampling this way */
- vec4 color = texture2D(colorbuffer, uvcoordsvar.xy) * 0.3125;
- color += texture2D(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375;
- color += texture2D(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375;
- color += texture2D(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625;
- color += texture2D(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375;
- color += texture2D(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375;
- color += texture2D(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625;
-
- gl_FragColor = color;
-}
-
-
-/* third pass, calculate the final coc from blurred and unblurred images */
-void third_pass()
-{
- vec4 color = texture2D(colorbuffer, uvcoordsvar.xy);
- vec4 color_blurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
- float coc = 2.0 * max(color_blurred.a, color.a); -color.a;
- gl_FragColor = vec4(color.rgb, coc);
-}
-
-
-/* fourth pass, blur the final coc once to get rid of discontinuities */
-void fourth_pass()
-{
- vec4 color = texture2D(colorbuffer, uvcoordsvar.xz);
- color += texture2D(colorbuffer, uvcoordsvar.yz);
- color += texture2D(colorbuffer, uvcoordsvar.xw);
- color += texture2D(colorbuffer, uvcoordsvar.yw);
-
- gl_FragColor = color / 4.0;
-}
-
-vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
-{
- float weight = 1.0 / 17.0;
- vec4 result = weight * color;
- weight *= 4.0;
-
- result += weight * texture2D(colorbuffer, uv + color_uv1.xy);
- result += weight * texture2D(colorbuffer, uv - color_uv1.xy);
- result += weight * texture2D(colorbuffer, uv + color_uv1.yx);
- result += weight * texture2D(colorbuffer, uv - color_uv1.yx);
-
- return result;
-}
-
-
-/* fourth pass, just visualize the third pass contents */
-void fifth_pass()
-{
- vec4 factors;
- vec4 color_orig = texture2D(colorbuffer, uvcoordsvar.xy);
- vec4 highblurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
- vec4 mediumblurred = texture2D(mblurredcolorbuffer, uvcoordsvar.xy);
- vec4 smallblurred = small_sample_blur(colorbuffer, uvcoordsvar.xy, color_orig);
- float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
-
- float zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth)).r;
- float coc_far = clamp(calculate_far_coc(zdepth), 0.0, 1.0);
-
- /* calculate final coc here */
- float coc = max(max(coc_far, mediumblurred.a), 0.0);
-
- float width = 2.5;
- float radius = 0.2;
-
- factors.x = 1.0 - clamp(width * coc, 0.0, 1.0);
- factors.y = 1.0 - clamp(abs(width * (coc - 2.0 * radius)), 0.0, 1.0);
- factors.z = 1.0 - clamp(abs(width * (coc - 3.0 * radius)), 0.0, 1.0);
- factors.w = 1.0 - clamp(abs(width * (coc - 4.0 * radius)), 0.0, 1.0);
- /* blend! */
- vec4 color = factors.x * color_orig + factors.y * smallblurred + factors.z * mediumblurred + factors.w * highblurred;
-
- color /= dot(factors, vec4(1.0));
- /* using original color is not correct, but use that for now because alpha of
- * blurred buffers uses CoC instead */
- gl_FragColor = vec4(color.rgb, color_orig.a);
-}
-
-
-void main()
-{
-#ifdef FIRST_PASS
- first_pass();
-#elif defined(SECOND_PASS)
- second_pass();
-#elif defined(THIRD_PASS)
- third_pass();
-#elif defined(FOURTH_PASS)
- fourth_pass();
-#elif defined(FIFTH_PASS)
- fifth_pass();
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
deleted file mode 100644
index 182113367d3..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
+++ /dev/null
@@ -1,167 +0,0 @@
-/* amount of offset to move one pixel left-right.
- * In second pass some dimensions are zero to control verical/horizontal convolution */
-uniform vec2 invrendertargetdim;
-
-uniform ivec2 rendertargetdim;
-
-/* color buffer */
-uniform sampler2D colorbuffer;
-uniform sampler2D farbuffer;
-uniform sampler2D nearbuffer;
-
-/* depth buffer */
-uniform sampler2D depthbuffer;
-
-uniform sampler2D cocbuffer;
-
-/* this includes focal distance in x and aperture size in y */
-uniform vec4 dof_params;
-
-/* viewvectors for reconstruction of world space */
-uniform vec4 viewvecs[3];
-
-/* initial uv coordinate */
-varying vec2 uvcoord;
-
-/* coordinate used for calculating radius et al set in geometry shader */
-varying vec2 particlecoord;
-varying vec4 color;
-
-/* downsampling coordinates */
-varying vec2 downsample1;
-varying vec2 downsample2;
-varying vec2 downsample3;
-varying vec2 downsample4;
-
-#define M_PI 3.1415926535897932384626433832795
-
-/* calculate 4 samples at once */
-vec4 calculate_coc(in vec4 zdepth)
-{
- vec4 coc = dof_params.x * (vec4(dof_params.y) / zdepth - vec4(1.0));
-
- /* multiply by 1.0 / sensor size to get the normalized size */
- return coc * dof_params.z;
-}
-
-#define THRESHOLD 0.0
-
-/* downsample the color buffer to half resolution */
-void downsample_pass()
-{
- vec4 depth;
- vec4 zdepth;
- vec4 coc;
- float far_coc, near_coc;
-
- /* custom downsampling. We need to be careful to sample nearest here to avoid leaks */
- vec4 color1 = texture2D(colorbuffer, downsample1);
- vec4 color2 = texture2D(colorbuffer, downsample2);
- vec4 color3 = texture2D(colorbuffer, downsample3);
- vec4 color4 = texture2D(colorbuffer, downsample4);
-
- depth.r = texture2D(depthbuffer, downsample1).r;
- depth.g = texture2D(depthbuffer, downsample2).r;
- depth.b = texture2D(depthbuffer, downsample3).r;
- depth.a = texture2D(depthbuffer, downsample4).r;
-
- zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
- coc = calculate_coc(zdepth);
- vec4 coc_far = -coc;
-
- /* now we need to write the near-far fields premultiplied by the coc */
- vec4 near_weights = vec4((coc.x >= THRESHOLD) ? 1.0 : 0.0, (coc.y >= THRESHOLD) ? 1.0 : 0.0,
- (coc.z >= THRESHOLD) ? 1.0 : 0.0, (coc.w >= THRESHOLD) ? 1.0 : 0.0);
- vec4 far_weights = vec4((coc_far.x >= THRESHOLD) ? 1.0 : 0.0, (coc_far.y >= THRESHOLD) ? 1.0 : 0.0,
- (coc_far.z >= THRESHOLD) ? 1.0 : 0.0, (coc_far.w >= THRESHOLD) ? 1.0 : 0.0);
-
- near_coc = max(max(max(coc.x, coc.y), max(coc.z, coc.w)), 0.0);
- far_coc = max(max(max(coc_far.x, coc_far.y), max(coc_far.z, coc_far.w)), 0.0);
-
- float norm_near = dot(near_weights, vec4(1.0));
- float norm_far = dot(far_weights, vec4(1.0));
-
- /* now write output to weighted buffers. */
- gl_FragData[0] = color1 * near_weights.x + color2 * near_weights.y + color3 * near_weights.z +
- color4 * near_weights.w;
- gl_FragData[1] = color1 * far_weights.x + color2 * far_weights.y + color3 * far_weights.z +
- color4 * far_weights.w;
-
- if (norm_near > 0.0)
- gl_FragData[0] /= norm_near;
- if (norm_far > 0.0)
- gl_FragData[1] /= norm_far;
- gl_FragData[2] = vec4(near_coc, far_coc, 0.0, 1.0);
-}
-
-/* accumulate color in the near/far blur buffers */
-void accumulate_pass(void) {
- float theta = atan(particlecoord.y, particlecoord.x);
- float r;
-
- if (dof_params.w == 0.0)
- r = 1.0;
- else
- r = cos(M_PI / dof_params.w) /
- (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
-
- if (dot(particlecoord, particlecoord) > r * r)
- discard;
-
- gl_FragData[0] = color;
-}
-#define MERGE_THRESHOLD 4.0
-
-/* combine the passes, */
-void final_pass(void) {
- vec4 finalcolor;
- float totalweight;
- float depth = texture2D(depthbuffer, uvcoord).r;
-
- vec4 zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth));
- float coc_near = calculate_coc(zdepth).r;
- float coc_far = max(-coc_near, 0.0);
- coc_near = max(coc_near, 0.0);
-
- vec4 farcolor = texture2D(farbuffer, uvcoord);
- float farweight = farcolor.a;
- if (farweight > 0.0)
- farcolor /= farweight;
- vec4 nearcolor = texture2D(nearbuffer, uvcoord);
-
- vec4 srccolor = texture2D(colorbuffer, uvcoord);
-
- vec4 coc = texture2D(cocbuffer, uvcoord);
-
- float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far);
- finalcolor = mix(srccolor, farcolor, mixfac);
-
- farweight = mix(1.0, farweight, mixfac);
-
- float nearweight = nearcolor.a;
- if (nearweight > 0.0) {
- nearcolor /= nearweight;
- }
-
- if (coc_near > 1.0) {
- nearweight = 1.0;
- finalcolor = nearcolor;
- }
- else {
- totalweight = nearweight + farweight;
- finalcolor = mix(finalcolor, nearcolor, nearweight / totalweight);
- }
-
- gl_FragData[0] = finalcolor;
-}
-
-void main()
-{
-#ifdef FIRST_PASS
- downsample_pass();
-#elif defined(SECOND_PASS)
- accumulate_pass();
-#elif defined(THIRD_PASS)
- final_pass();
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
deleted file mode 100644
index 4c650e7695f..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
+++ /dev/null
@@ -1,66 +0,0 @@
-uniform ivec2 rendertargetdim;
-uniform sampler2D colorbuffer;
-
-uniform vec2 layerselection;
-
-uniform sampler2D cocbuffer;
-
-#if __VERSION__ >= 150
- layout(points) in;
- layout(triangle_strip, max_vertices = 4) out;
-
- #define POS gl_in[0].gl_Position
-#else
- /* use the EXT_geometry_shader4 way */
- #define POS gl_PositionIn[0]
-#endif
-
-/* initial uv coordinate */
-#if __VERSION__ < 130
- varying in vec2 uvcoord[];
- varying out vec2 particlecoord;
- varying out vec4 color;
- #define textureLod texture2DLod
-#else
- in vec2 uvcoord[];
- out vec2 particlecoord;
- out vec4 color;
-#endif
-
-#define M_PI 3.1415926535897932384626433832795
-
-void main()
-{
- vec4 coc = textureLod(cocbuffer, uvcoord[0], 0.0);
-
- float offset_val = dot(coc.rg, layerselection);
- if (offset_val < 1.0)
- return;
-
- vec4 colortex = textureLod(colorbuffer, uvcoord[0], 0.0);
-
- /* find the area the pixel will cover and divide the color by it */
- float alpha = 1.0 / (offset_val * offset_val * M_PI);
- colortex *= alpha;
- colortex.a = alpha;
-
- vec2 offset_far = vec2(offset_val * 0.5) / vec2(rendertargetdim.x, rendertargetdim.y);
-
- gl_Position = POS + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
- color = colortex;
- particlecoord = vec2(-1.0, -1.0);
- EmitVertex();
- gl_Position = POS + vec4(-offset_far.x, offset_far.y, 0.0, 0.0);
- particlecoord = vec2(-1.0, 1.0);
- color = colortex;
- EmitVertex();
- gl_Position = POS + vec4(offset_far.x, -offset_far.y, 0.0, 0.0);
- particlecoord = vec2(1.0, -1.0);
- color = colortex;
- EmitVertex();
- gl_Position = POS + vec4(offset_far.x, offset_far.y, 0.0, 0.0);
- particlecoord = vec2(1.0, 1.0);
- color = colortex;
- EmitVertex();
- EndPrimitive();
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
deleted file mode 100644
index eea4385578f..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
+++ /dev/null
@@ -1,58 +0,0 @@
-uniform vec2 invrendertargetdim;
-uniform ivec2 rendertargetdim;
-/* initial uv coordinate */
-varying vec2 uvcoord;
-
-/* coordinate used for calculating radius et al set in geometry shader */
-varying vec2 particlecoord;
-
-/* downsampling coordinates */
-varying vec2 downsample1;
-varying vec2 downsample2;
-varying vec2 downsample3;
-varying vec2 downsample4;
-
-void vert_dof_downsample()
-{
- /* gather pixels from neighbors. half dimensions means we offset half a pixel to
- * get this right though it's possible we may lose a pixel at some point */
- downsample1 = gl_MultiTexCoord0.xy + vec2(-0.5, -0.5) * invrendertargetdim;
- downsample2 = gl_MultiTexCoord0.xy + vec2(-0.5, 0.5) * invrendertargetdim;
- downsample3 = gl_MultiTexCoord0.xy + vec2(0.5, 0.5) * invrendertargetdim;
- downsample4 = gl_MultiTexCoord0.xy + vec2(0.5, -0.5) * invrendertargetdim;
-
- gl_Position = gl_Vertex;
-}
-
-/* geometry shading pass, calculate a texture coordinate based on the indexed id */
-void vert_dof_coc_scatter_pass()
-{
- vec2 pixel = vec2(rendertargetdim.x, rendertargetdim.y);
- /* some math to get the target pixel */
- int row = gl_InstanceID / rendertargetdim.x;
- int column = gl_InstanceID % rendertargetdim.x;
- uvcoord = (vec2(column, row) + vec2(0.5)) / pixel;
-
- vec2 pos = uvcoord * 2.0 - vec2(1.0);
- gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
-
-// uvcoord = vec2(0.5, 0.5);
-// gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
-}
-
-void vert_dof_final()
-{
- uvcoord = gl_MultiTexCoord0.xy;
- gl_Position = gl_Vertex;
-}
-
-void main()
-{
-#if defined(FIRST_PASS)
- vert_dof_downsample();
-#elif defined(SECOND_PASS)
- vert_dof_coc_scatter_pass();
-#else
- vert_dof_final();
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
deleted file mode 100644
index 221dd7e68df..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
+++ /dev/null
@@ -1,71 +0,0 @@
-uniform vec2 invrendertargetdim;
-
-//texture coordinates for framebuffer read
-varying vec4 uvcoordsvar;
-
-/* color texture coordinates, offset by a small amount */
-varying vec2 color_uv1;
-varying vec2 color_uv2;
-
-varying vec2 depth_uv1;
-varying vec2 depth_uv2;
-varying vec2 depth_uv3;
-varying vec2 depth_uv4;
-
-//very simple shader for gull screen FX, just pass values on
-
-void vert_generic()
-{
- uvcoordsvar = gl_MultiTexCoord0;
- gl_Position = gl_Vertex;
-}
-
-void vert_dof_first_pass()
-{
- /* we offset the texture coordinates by 1.5 pixel,
- * then we reuse that to sample the surrounding pixels */
- color_uv1 = gl_MultiTexCoord0.xy + vec2(-1.5, -1.5) * invrendertargetdim;
- color_uv2 = gl_MultiTexCoord0.xy + vec2(0.5, -1.5) * invrendertargetdim;
-
- depth_uv1 = gl_MultiTexCoord0.xy + vec2(-1.5, -1.5) * invrendertargetdim;
- depth_uv2 = gl_MultiTexCoord0.xy + vec2(-0.5, -1.5) * invrendertargetdim;
- depth_uv3 = gl_MultiTexCoord0.xy + vec2(0.5, -1.5) * invrendertargetdim;
- depth_uv4 = gl_MultiTexCoord0.xy + vec2(1.5, -1.5) * invrendertargetdim;
-
- gl_Position = gl_Vertex;
-}
-
-void vert_dof_fourth_pass()
-{
- vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5);
- uvcoordsvar = gl_MultiTexCoord0.xxyy +
- halfpixel *
- vec4(invrendertargetdim.x,
- invrendertargetdim.x,
- invrendertargetdim.y,
- invrendertargetdim.y);
-
- gl_Position = gl_Vertex;
-}
-
-void vert_dof_fifth_pass()
-{
- vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5);
- color_uv1 = vec2(0.5, 1.5) * invrendertargetdim;
-
- uvcoordsvar = gl_MultiTexCoord0;
- gl_Position = gl_Vertex;
-}
-
-void main()
-{
-#ifdef FIRST_PASS
- vert_dof_first_pass();
-#elif defined(FOURTH_PASS)
- vert_dof_fourth_pass();
-#elif defined(FIFTH_PASS)
- vert_dof_fifth_pass();
-#else
- vert_generic();
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
deleted file mode 100644
index 1dc49b52be1..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer
- * we change the factors from the article to fit the OpennGL model. */
-#ifdef PERSP_MATRIX
-
-/* perspective camera code */
-
-vec3 get_view_space_from_depth(in vec2 uvcoords, in vec3 viewvec_origin, in vec3 viewvec_diff, in float depth)
-{
- float d = 2.0 * depth - 1.0;
-
- float zview = -gl_ProjectionMatrix[3][2] / (d + gl_ProjectionMatrix[2][2]);
-
- return zview * (viewvec_origin + vec3(uvcoords, 0.0) * viewvec_diff);
-}
-
-vec4 get_view_space_z_from_depth(in vec4 near, in vec4 range, in vec4 depth)
-{
- vec4 d = 2.0 * depth - vec4(1.0);
-
- /* return positive value, so sign differs! */
- return vec4(gl_ProjectionMatrix[3][2]) / (d + vec4(gl_ProjectionMatrix[2][2]));
-}
-
-#else
-/* orthographic camera code */
-
-vec3 get_view_space_from_depth(in vec2 uvcoords, in vec3 viewvec_origin, in vec3 viewvec_diff, in float depth)
-{
- vec3 offset = vec3(uvcoords, depth);
-
- return vec3(viewvec_origin + offset * viewvec_diff);
-}
-
-vec4 get_view_space_z_from_depth(in vec4 near, in vec4 range, in vec4 depth)
-{
- return -(near + depth * range);
-}
-
-#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
deleted file mode 100644
index f19ff4ec65a..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ /dev/null
@@ -1,94 +0,0 @@
-// color buffer
-uniform sampler2D colorbuffer;
-
-// jitter texture for ssao
-uniform sampler2D jitter_tex;
-
-// concentric sample texture for ssao
-uniform sampler1D ssao_concentric_tex;
-
-// depth buffer
-uniform sampler2D depthbuffer;
-// coordinates on framebuffer in normalized (0.0-1.0) uv space
-varying vec4 uvcoordsvar;
-
-/* ssao_params.x : pixel scale for the ssao radious */
-/* ssao_params.y : factor for the ssao darkening */
-uniform vec4 ssao_params;
-uniform vec3 ssao_sample_params;
-uniform vec4 ssao_color;
-
-/* store the view space vectors for the corners of the view frustum here.
- * It helps to quickly reconstruct view space vectors by using uv coordinates,
- * see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
-uniform vec4 viewvecs[3];
-
-vec3 calculate_view_space_normal(in vec3 viewposition)
-{
- vec3 normal = cross(normalize(dFdx(viewposition)),
- ssao_params.w * normalize(dFdy(viewposition)));
- return normalize(normal);
-}
-
-float calculate_ssao_factor(float depth)
-{
- /* take the normalized ray direction here */
- vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz).rg;
- vec2 rotY = vec2(-rotX.y, rotX.x);
-
- /* occlusion is zero in full depth */
- if (depth == 1.0)
- return 0.0;
-
- vec3 position = get_view_space_from_depth(uvcoordsvar.xy, viewvecs[0].xyz, viewvecs[1].xyz, depth);
- vec3 normal = calculate_view_space_normal(position);
-
- /* find the offset in screen space by multiplying a point
- * in camera space at the depth of the point by the projection matrix. */
- vec2 offset;
- float homcoord = gl_ProjectionMatrix[2][3] * position.z + gl_ProjectionMatrix[3][3];
- offset.x = gl_ProjectionMatrix[0][0] * ssao_params.x / homcoord;
- offset.y = gl_ProjectionMatrix[1][1] * ssao_params.x / homcoord;
- /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
- offset *= 0.5;
-
- float factor = 0.0;
- int x;
- int num_samples = int(ssao_sample_params.x);
-
- for (x = 0; x < num_samples; x++) {
- vec2 dir_sample = texture1D(ssao_concentric_tex, (float(x) + 0.5) / ssao_sample_params.x).rg;
-
- /* rotate with random direction to get jittered result */
- vec2 dir_jittered = vec2(dot(dir_sample, rotX), dot(dir_sample, rotY));
-
- vec2 uvcoords = uvcoordsvar.xy + dir_jittered * offset;
-
- if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0)
- continue;
-
- float depth_new = texture2D(depthbuffer, uvcoords).r;
- if (depth_new != 1.0) {
- vec3 pos_new = get_view_space_from_depth(uvcoords, viewvecs[0].xyz, viewvecs[1].xyz, depth_new);
- vec3 dir = pos_new - position;
- float len = length(dir);
- float f = dot(dir, normal);
-
- /* use minor bias here to avoid self shadowing */
- if (f > 0.05 * len)
- factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z));
- }
- }
-
- factor /= ssao_sample_params.x;
-
- return clamp(factor * ssao_params.y, 0.0, 1.0);
-}
-
-void main()
-{
- float depth = texture2D(depthbuffer, uvcoordsvar.xy).r;
- vec4 scene_col = texture2D(colorbuffer, uvcoordsvar.xy);
- vec3 final_color = mix(scene_col.rgb, ssao_color.rgb, calculate_ssao_factor(depth));
- gl_FragColor = vec4(final_color.rgb, scene_col.a);
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl
deleted file mode 100644
index 5194e414520..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl
+++ /dev/null
@@ -1,9 +0,0 @@
-varying vec4 uvcoordsvar;
-
-//very simple shader for full screen FX, just pass values on
-
-void main()
-{
- uvcoordsvar = gl_MultiTexCoord0;
- gl_Position = gl_Vertex;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index fe630dbeddb..705b79cbf56 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -1,10 +1,11 @@
+
+uniform mat4 ProjectionMatrix;
+
uniform int PrimitiveIdBase;
uniform int osd_active_uv_offset;
-#if __VERSION__ >= 150
- layout(lines_adjacency) in;
- layout(triangle_strip, max_vertices = 4) out;
-#endif
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 4) out;
in block {
VertexData v;
@@ -31,17 +32,12 @@ uniform int osd_fvar_count;
tessCoord.t); \
}
-#ifdef USE_NEW_SHADING
# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \
{ \
vec2 tmp; \
INTERP_FACE_VARYING_2(tmp, fvarOffset, tessCoord); \
result = vec3(tmp, 0); \
}
-#else
-# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \
- INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord)
-#endif
uniform samplerBuffer FVarDataBuffer;
uniform isamplerBuffer FVarDataOffsetBuffer;
@@ -69,7 +65,7 @@ void emit_flat(int index, vec3 normal)
set_mtface_vertex_attrs(st);
- gl_Position = gl_ProjectionMatrix * inpt[index].v.position;
+ gl_Position = ProjectionMatrix * inpt[index].v.position;
EmitVertex();
}
@@ -90,7 +86,7 @@ void emit_smooth(int index)
set_mtface_vertex_attrs(st);
- gl_Position = gl_ProjectionMatrix * inpt[index].v.position;
+ gl_Position = ProjectionMatrix * inpt[index].v.position;
EmitVertex();
}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl
new file mode 100644
index 00000000000..328fbbe26a1
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl
@@ -0,0 +1,166 @@
+uniform vec4 color;
+uniform vec4 color2;
+uniform int fill_type;
+uniform float mix_factor;
+
+uniform float g_angle;
+uniform float g_radius;
+uniform float g_boxsize;
+uniform vec2 g_scale;
+uniform vec2 g_shift;
+
+uniform float t_angle;
+uniform vec2 t_scale;
+uniform vec2 t_offset;
+uniform int t_mix;
+uniform int t_flip;
+uniform float t_opacity;
+
+uniform sampler2D myTexture;
+
+/* keep this list synchronized with list in DNA_brush_types.h */
+#define SOLID 0
+#define GRADIENT 1
+#define RADIAL 2
+#define CHESS 3
+#define TEXTURE 4
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+#define texture2D texture
+
+void set_color(in vec4 color, in vec4 color2, in vec4 tcolor, in float mixv, in float factor,
+ in int tmix, in int flip, out vec4 ocolor)
+{
+ /* full color A */
+ if (mixv == 1.0) {
+ if (tmix == 1) {
+ if (flip == 0) {
+ ocolor = color;
+ }
+ else {
+ ocolor = tcolor;
+ }
+ }
+ else {
+ if (flip == 0) {
+ ocolor = color;
+ }
+ else {
+ ocolor = color2;
+ }
+ }
+ }
+ /* full color B */
+ else if (mixv == 0.0) {
+ if (tmix == 1) {
+ if (flip == 0) {
+ ocolor = tcolor;
+ }
+ else {
+ ocolor = color;
+ }
+ }
+ else {
+ if (flip == 0) {
+ ocolor = color2;
+ }
+ else {
+ ocolor = color;
+ }
+ }
+ }
+ /* mix of colors */
+ else {
+ if (tmix == 1) {
+ if (flip == 0) {
+ ocolor = mix(color, tcolor, factor);
+ }
+ else {
+ ocolor = mix(tcolor, color, factor);
+ }
+ }
+ else {
+ if (flip == 0) {
+ ocolor = mix(color, color2, factor);
+ }
+ else {
+ ocolor = mix(color2, color, factor);
+ }
+ }
+ }
+}
+
+void main()
+{
+ vec2 t_center = vec2(0.5, 0.5);
+ mat2 matrot_tex = mat2(cos(t_angle), -sin(t_angle), sin(t_angle), cos(t_angle));
+ vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + t_offset;
+ vec4 tmp_color = texture2D(myTexture, rot_tex * t_scale);
+ vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * t_opacity);
+ vec4 chesscolor;
+
+ /* solid fill */
+ if (fill_type == SOLID) {
+ if (t_mix == 1) {
+ fragColor = mix(color, text_color, mix_factor);
+ }
+ else {
+ fragColor = color;
+ }
+ }
+ else {
+ vec2 center = vec2(0.5, 0.5) + g_shift;
+ mat2 matrot = mat2(cos(g_angle), -sin(g_angle), sin(g_angle), cos(g_angle));
+ vec2 rot = (((matrot * (texCoord_interp - center)) + center) * g_scale) + g_shift;
+ /* gradient */
+ if (fill_type == GRADIENT) {
+ set_color(color, color2, text_color, mix_factor, rot.x - mix_factor + 0.5, t_mix, t_flip, fragColor);
+ }
+ /* radial gradient */
+ if (fill_type == RADIAL) {
+ float in_rad = g_radius * mix_factor;
+ float ex_rad = g_radius - in_rad;
+ float intensity = 0;
+ float distance = length((center - texCoord_interp) * g_scale);
+ if (distance > g_radius) {
+ discard;
+ }
+ if (distance > in_rad) {
+ intensity = clamp(((distance - in_rad) / ex_rad), 0.0, 1.0);
+ }
+ set_color(color, color2, text_color, mix_factor, intensity, t_mix, t_flip, fragColor);
+ }
+ /* chessboard */
+ if (fill_type == CHESS) {
+ vec2 pos = rot / g_boxsize;
+ if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) || (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) {
+ if (t_flip == 0) {
+ chesscolor = color;
+ }
+ else {
+ chesscolor = color2;
+ }
+ }
+ else {
+ if (t_flip == 0) {
+ chesscolor = color2;
+ }
+ else {
+ chesscolor = color;
+ }
+ }
+ /* mix with texture */
+ if (t_mix == 1) {
+ fragColor = mix(chesscolor, text_color, mix_factor);
+ }
+ else {
+ fragColor = chesscolor;
+ }
+ }
+ /* texture */
+ if (fill_type == TEXTURE) {
+ fragColor = text_color;
+ }
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl
new file mode 100644
index 00000000000..2bc381a3689
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl
@@ -0,0 +1,11 @@
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec2 texCoord;
+out vec2 texCoord_interp;
+
+void main(void)
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ texCoord_interp = texCoord;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
new file mode 100644
index 00000000000..7bb7693d202
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
@@ -0,0 +1,20 @@
+in vec4 mColor;
+in vec2 mTexCoord;
+
+out vec4 fragColor;
+
+void main()
+{
+ const vec2 center = vec2(0, 0.5);
+ vec4 tColor = vec4(mColor);
+ /* if alpha < 0, then encap */
+ if (mColor.a < 0) {
+ tColor.a = tColor.a * -1.0;
+ float dist = length(mTexCoord - center);
+ if (dist > 0.25) {
+ discard;
+ }
+ }
+ /* Solid */
+ fragColor = tColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
new file mode 100644
index 00000000000..3de1bd838b3
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
@@ -0,0 +1,196 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 Viewport;
+uniform int xraymode;
+
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 13) out;
+
+in vec4 finalColor[4];
+in float finalThickness[4];
+
+out vec4 mColor;
+out vec2 mTexCoord;
+
+#define GP_XRAY_FRONT 0
+#define GP_XRAY_3DSPACE 1
+#define GP_XRAY_BACK 2
+
+/* project 3d point to 2d on screen space */
+vec2 toScreenSpace(vec4 vertex)
+{
+ return vec2(vertex.xy / vertex.w) * Viewport;
+}
+
+/* get zdepth value */
+float getZdepth(vec4 point)
+{
+ if (xraymode == GP_XRAY_FRONT) {
+ return 0.0;
+ }
+ if (xraymode == GP_XRAY_3DSPACE) {
+ return (point.z / point.w);
+ }
+ if (xraymode == GP_XRAY_BACK) {
+ return 1.0;
+ }
+
+ /* in front by default */
+ return 0.0;
+}
+void main(void)
+{
+ float MiterLimit = 0.75;
+
+ /* receive 4 points */
+ vec4 P0 = gl_in[0].gl_Position;
+ vec4 P1 = gl_in[1].gl_Position;
+ vec4 P2 = gl_in[2].gl_Position;
+ vec4 P3 = gl_in[3].gl_Position;
+
+ /* get the four vertices passed to the shader */
+ vec2 sp0 = toScreenSpace(P0); // start of previous segment
+ vec2 sp1 = toScreenSpace(P1); // end of previous segment, start of current segment
+ vec2 sp2 = toScreenSpace(P2); // end of current segment, start of next segment
+ vec2 sp3 = toScreenSpace(P3); // end of next segment
+
+ /* culling outside viewport */
+ vec2 area = Viewport * 4.0;
+ if (sp1.x < -area.x || sp1.x > area.x) return;
+ if (sp1.y < -area.y || sp1.y > area.y) return;
+ if (sp2.x < -area.x || sp2.x > area.x) return;
+ if (sp2.y < -area.y || sp2.y > area.y) return;
+
+ /* determine the direction of each of the 3 segments (previous, current, next) */
+ vec2 v0 = normalize(sp1 - sp0);
+ vec2 v1 = normalize(sp2 - sp1);
+ vec2 v2 = normalize(sp3 - sp2);
+
+ /* determine the normal of each of the 3 segments (previous, current, next) */
+ vec2 n0 = vec2(-v0.y, v0.x);
+ vec2 n1 = vec2(-v1.y, v1.x);
+ vec2 n2 = vec2(-v2.y, v2.x);
+
+ /* determine miter lines by averaging the normals of the 2 segments */
+ vec2 miter_a = normalize(n0 + n1); // miter at start of current segment
+ vec2 miter_b = normalize(n1 + n2); // miter at end of current segment
+
+ /* determine the length of the miter by projecting it onto normal and then inverse it */
+ float an1 = dot(miter_a, n1);
+ float bn1 = dot(miter_b, n2);
+ if (an1 == 0) an1 = 1;
+ if (bn1 == 0) bn1 = 1;
+ float length_a = finalThickness[1] / an1;
+ float length_b = finalThickness[2] / bn1;
+ if (length_a <= 0.0) length_a = 0.01;
+ if (length_b <= 0.0) length_b = 0.01;
+
+ /* prevent excessively long miters at sharp corners */
+ if (dot(v0, v1) < -MiterLimit) {
+ miter_a = n1;
+ length_a = finalThickness[1];
+
+ /* close the gap */
+ if (dot(v0, n1) > 0) {
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0.5);
+ mColor = finalColor[1];
+ gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+ }
+ else {
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0.5);
+ mColor = finalColor[1];
+ gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+ }
+ }
+
+ if (dot(v1, v2) < -MiterLimit) {
+ miter_b = n1;
+ length_b = finalThickness[2];
+ }
+
+ /* generate the start endcap (alpha < 0 used as endcap flag)*/
+ if (P0 == P2) {
+ mTexCoord = vec2(1, 0.5);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0;
+ gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 1);
+ mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ;
+ gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+ }
+
+ /* generate the triangle strip */
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[1];
+ gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = finalColor[2];
+ gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 1);
+ mColor = finalColor[2];
+ gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ /* generate the end endcap (alpha < 0 used as endcap flag)*/
+ if (P1 == P3) {
+ mTexCoord = vec2(0, 1);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(0, 0);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+
+ mTexCoord = vec2(1, 0.5);
+ mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ;
+ vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0;
+ gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0);
+ EmitVertex();
+ }
+
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
new file mode 100644
index 00000000000..5cbe2f60ebd
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
@@ -0,0 +1,32 @@
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform float pixsize; /* rv3d->pixsize */
+uniform int keep_size;
+uniform float objscale;
+uniform int pixfactor;
+
+in vec3 pos;
+in vec4 color;
+in float thickness;
+
+out vec4 finalColor;
+out float finalThickness;
+
+#define TRUE 1
+
+float defaultpixsize = pixsize * (1000.0 / pixfactor);
+
+void main(void)
+{
+ gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 );
+ finalColor = color;
+
+ if (keep_size == TRUE) {
+ finalThickness = thickness;
+ }
+ else {
+ float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) : (thickness / defaultpixsize);
+ finalThickness = max(size * objscale, 1.0);
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl
new file mode 100644
index 00000000000..e2af83ec529
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl
@@ -0,0 +1,14 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform vec4 color;
+uniform sampler2D image;
+
+void main()
+{
+ fragColor = texture(image, texCoord_interp).r * color.rgba;
+ /* Premul by alpha (not texture alpha)
+ * Use blending function GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); */
+ fragColor.rgb *= color.a;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl
new file mode 100644
index 00000000000..ef8935cc7ba
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl
@@ -0,0 +1,11 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform vec4 color;
+uniform sampler2D image;
+
+void main()
+{
+ fragColor = texture(image, texCoord_interp) * color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl
new file mode 100644
index 00000000000..10f4dfd5a87
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl
@@ -0,0 +1,12 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+
+void main()
+{
+ float depth = texture(image, texCoord_interp).r;
+ fragColor = vec4(depth);
+ gl_FragDepth = depth;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl
new file mode 100644
index 00000000000..bcbe1f577fd
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl
@@ -0,0 +1,16 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform float znear;
+uniform float zfar;
+uniform sampler2D image;
+
+void main()
+{
+ float depth = texture(image, texCoord_interp).r;
+
+ /* normalize */
+ fragColor.rgb = vec3((2.0f * znear) / (zfar + znear - (depth * (zfar - znear))));
+ fragColor.a = 1.0f;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl
new file mode 100644
index 00000000000..1ac0d68b35f
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl
@@ -0,0 +1,14 @@
+
+uniform float factor;
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform vec4 color;
+uniform sampler2D image;
+
+void main()
+{
+ vec4 tex = texture(image, texCoord_interp);
+ tex.rgb = ((0.3333333 * factor) * vec3(tex.r + tex.g + tex.b)) + (tex.rgb * (1.0 - factor));
+ fragColor = tex * color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl
new file mode 100644
index 00000000000..6eeab8ca7e8
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl
@@ -0,0 +1,10 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+
+void main()
+{
+ fragColor = texture(image, texCoord_interp);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl
new file mode 100644
index 00000000000..d95645f58e5
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl
@@ -0,0 +1,34 @@
+
+/* Keep these in sync with GPU_shader.h */
+#define INTERLACE_ROW 0
+#define INTERLACE_COLUMN 1
+#define INTERLACE_CHECKERBOARD 2
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform int interlace_id;
+uniform sampler2D image_a;
+uniform sampler2D image_b;
+
+bool interlace()
+{
+ if (interlace_id == INTERLACE_CHECKERBOARD) {
+ return (int(gl_FragCoord.x + gl_FragCoord.y) & 1) != 0;
+ }
+ else if (interlace_id == INTERLACE_ROW) {
+ return (int(gl_FragCoord.y) & 1) != 0;
+ }
+ else if (interlace_id == INTERLACE_COLUMN) {
+ return (int(gl_FragCoord.x) & 1) != 0;
+ }
+}
+
+void main()
+{
+ if (interlace()) {
+ fragColor = texture(image_a, texCoord_interp);
+ } else {
+ fragColor = texture(image_b, texCoord_interp);
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_linear_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_linear_frag.glsl
new file mode 100644
index 00000000000..97eb3afc177
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_linear_frag.glsl
@@ -0,0 +1,30 @@
+
+/* Display a linear image texture into sRGB space */
+
+uniform sampler2D image;
+
+in vec2 texCoord_interp;
+
+out vec4 fragColor;
+
+float linearrgb_to_srgb(float c)
+{
+ if (c < 0.0031308)
+ return (c < 0.0) ? 0.0 : c * 12.92;
+ else
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
+}
+
+void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
+{
+ col_to.r = linearrgb_to_srgb(col_from.r);
+ col_to.g = linearrgb_to_srgb(col_from.g);
+ col_to.b = linearrgb_to_srgb(col_from.b);
+ col_to.a = col_from.a;
+}
+
+void main() {
+ fragColor = texture(image, texCoord_interp.st);
+
+ linearrgb_to_srgb(fragColor, fragColor);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl
new file mode 100644
index 00000000000..4a45d03175e
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl
@@ -0,0 +1,12 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+uniform vec4 color;
+
+void main()
+{
+ fragColor.a = texture(image, texCoord_interp).a * color.a;
+ fragColor.rgb = color.rgb;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl
new file mode 100644
index 00000000000..51092d56e5e
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl
@@ -0,0 +1,12 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform float alpha;
+uniform sampler2D image;
+
+void main()
+{
+ fragColor = texture(image, texCoord_interp);
+ fragColor.a *= alpha;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl
new file mode 100644
index 00000000000..1f59c9dfdbd
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl
@@ -0,0 +1,127 @@
+
+uniform sampler2DMS depthMulti;
+uniform sampler2DMS colorMulti;
+
+out vec4 fragColor;
+
+#if SAMPLES > 16
+#error "Too many samples"
+#endif
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+
+ bvec4 b1, b2, b3, b4;
+ vec4 w1, w2, w3, w4;
+ vec4 d1, d2, d3, d4;
+ vec4 c1, c2, c3, c4, c5, c6, c7, c8;
+ vec4 c9, c10, c11, c12, c13, c14, c15, c16;
+ d1 = d2 = d3 = d4 = vec4(0.5);
+ w1 = w2 = w3 = w4 = vec4(0.0);
+ c1 = c2 = c3 = c4 = c5 = c6 = c7 = c8 = vec4(0.0);
+ c9 = c10 = c11 = c12 = c13 = c14 = c15 = c16 = vec4(0.0);
+
+#ifdef USE_DEPTH
+ /* Depth */
+ d1.x = texelFetch(depthMulti, texel, 0).r;
+ d1.y = texelFetch(depthMulti, texel, 1).r;
+# if SAMPLES > 2
+ d1.z = texelFetch(depthMulti, texel, 2).r;
+ d1.w = texelFetch(depthMulti, texel, 3).r;
+# endif
+# if SAMPLES > 4
+ d2.x = texelFetch(depthMulti, texel, 4).r;
+ d2.y = texelFetch(depthMulti, texel, 5).r;
+ d2.z = texelFetch(depthMulti, texel, 6).r;
+ d2.w = texelFetch(depthMulti, texel, 7).r;
+# endif
+# if SAMPLES > 8
+ d3.x = texelFetch(depthMulti, texel, 8).r;
+ d3.y = texelFetch(depthMulti, texel, 9).r;
+ d3.z = texelFetch(depthMulti, texel, 10).r;
+ d3.w = texelFetch(depthMulti, texel, 11).r;
+ d4.x = texelFetch(depthMulti, texel, 12).r;
+ d4.y = texelFetch(depthMulti, texel, 13).r;
+ d4.z = texelFetch(depthMulti, texel, 14).r;
+ d4.w = texelFetch(depthMulti, texel, 15).r;
+# endif
+#endif
+
+ /* COLOR */
+ b1 = notEqual(d1, vec4(1.0));
+ if (any(b1)) {
+ c1 = texelFetch(colorMulti, texel, 0);
+ c2 = texelFetch(colorMulti, texel, 1);
+#if SAMPLES > 2
+ c3 = texelFetch(colorMulti, texel, 2);
+ c4 = texelFetch(colorMulti, texel, 3);
+#endif
+ w1 = vec4(b1);
+ }
+#if SAMPLES > 4
+ b2 = notEqual(d2, vec4(1.0));
+ if (any(b2)) {
+ c5 = texelFetch(colorMulti, texel, 4);
+ c6 = texelFetch(colorMulti, texel, 5);
+ c7 = texelFetch(colorMulti, texel, 6);
+ c8 = texelFetch(colorMulti, texel, 7);
+ w2 = vec4(b2);
+ }
+#endif
+#if SAMPLES > 8
+ b3 = notEqual(d3, vec4(1.0));
+ if (any(b3)) {
+ c9 = texelFetch(colorMulti, texel, 8);
+ c10 = texelFetch(colorMulti, texel, 9);
+ c11 = texelFetch(colorMulti, texel, 10);
+ c12 = texelFetch(colorMulti, texel, 11);
+ w3 = vec4(b3);
+ }
+ b4 = notEqual(d4, vec4(1.0));
+ if (any(b4)) {
+ c13 = texelFetch(colorMulti, texel, 12);
+ c14 = texelFetch(colorMulti, texel, 13);
+ c15 = texelFetch(colorMulti, texel, 14);
+ c16 = texelFetch(colorMulti, texel, 15);
+ w4 = vec4(b4);
+ }
+#endif
+
+#ifdef USE_DEPTH
+ d1 *= 1.0 - step(1.0, d1); /* make far plane depth = 0 */
+# if SAMPLES > 8
+ d4 *= 1.0 - step(1.0, d4);
+ d3 *= 1.0 - step(1.0, d3);
+ d1 = max(d1, max(d3, d4));
+# endif
+# if SAMPLES > 4
+ d2 *= 1.0 - step(1.0, d2);
+ d1 = max(d1, d2);
+ d1 = max(d1, d2);
+# endif
+# if SAMPLES > 2
+ d1.xy = max(d1.xy, d1.zw);
+# endif
+ gl_FragDepth = max(d1.x, d1.y);
+ /* Don't let the 0.0 farplane occlude other things */
+ if (gl_FragDepth == 0.0) {
+ gl_FragDepth = 1.0;
+ }
+#endif
+
+ c1 = c1 + c2;
+#if SAMPLES > 2
+ c1 += c3 + c4;
+#endif
+#if SAMPLES > 4
+ c1 += c5 + c6 + c7 + c8;
+#endif
+#if SAMPLES > 8
+ c1 += c9 + c10 + c11 + c12 + c13 + c14 + c15 + c16;
+#endif
+
+ const float inv_samples = 1.0 / float(SAMPLES);
+
+ fragColor = c1 * inv_samples;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl
new file mode 100644
index 00000000000..64662247d69
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl
@@ -0,0 +1,16 @@
+
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+uniform vec4 color;
+uniform vec4 shuffle;
+
+void main()
+{
+ vec4 sample = texture(image, texCoord_interp);
+ fragColor = vec4(sample.r * shuffle.r +
+ sample.g * shuffle.g +
+ sample.b * shuffle.b +
+ sample.a * shuffle.a) * color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl
new file mode 100644
index 00000000000..37686092700
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl
@@ -0,0 +1,11 @@
+
+in vec2 texCoord_interp;
+flat in vec4 finalColor;
+out vec4 fragColor;
+
+uniform sampler2D image;
+
+void main()
+{
+ fragColor = texture(image, texCoord_interp) * finalColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
new file mode 100644
index 00000000000..805ecd6085f
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl
@@ -0,0 +1,50 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instantiated Attribs ---- */
+in float pos;
+
+/* ---- Per instance Attribs ---- */
+in vec3 color;
+in vec4 corners[2]; /* trouble fetching vec2 */
+in float depth;
+in vec4 tria;
+in mat4 InstanceModelMatrix;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ vec3 pPos;
+
+ if (pos == 1.0) {
+ pPos = vec3(corners[0].xy, depth);
+ }
+ else if (pos == 2.0) {
+ pPos = vec3(corners[0].zw, depth);
+ }
+ else if (pos == 3.0) {
+ pPos = vec3(corners[1].xy, depth);
+ }
+ else if (pos == 4.0) {
+ pPos = vec3(corners[1].zw, depth);
+ }
+ else if (pos == 5.0) {
+ pPos = vec3(tria.xy, depth);
+ }
+ else if (pos == 6.0) {
+ vec2 ofs = tria.xy - corners[0].xy;
+ ofs.x = -ofs.x;
+ pPos = vec3(corners[1].zw + ofs, depth);
+ }
+ else if (pos == 7.0) {
+ pPos = vec3(tria.zw, depth);
+ }
+ else {
+ pPos = vec3(0.0);
+ }
+
+ gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pPos, 1.0);
+
+ finalColor = vec4(color, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
new file mode 100644
index 00000000000..255eeb9baf1
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl
@@ -0,0 +1,25 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attribs ---- */
+in vec3 color;
+in float start;
+in float end;
+in mat4 InstanceModelMatrix;
+
+uniform float size;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ float len = end - start;
+ vec3 sta = vec3(0.0, 0.0, -start);
+
+ gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos * -len + sta, 1.0);
+ gl_PointSize = size;
+ finalColor = vec4(color, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl
new file mode 100644
index 00000000000..e26f419b8cd
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl
@@ -0,0 +1,57 @@
+
+// Draw "fancy" wireframe, displaying front-facing, back-facing and
+// silhouette lines differently.
+// Mike Erwin, April 2015
+
+// After working with this shader a while, convinced we should make
+// separate shaders for perpective & ortho. (Oct 2016)
+
+// Due to perspective, the line segment's endpoints might disagree on
+// whether the adjacent faces are front facing. This geometry shader
+// decides which edge type to use if endpoints disagree.
+
+uniform mat4 ProjectionMatrix;
+
+uniform bool drawFront = true;
+uniform bool drawBack = true;
+uniform bool drawSilhouette = true;
+
+layout(lines) in;
+layout(line_strip, max_vertices = 2) out;
+
+in vec4 MV_pos[];
+in float edgeClass[];
+in vec3 fCol[];
+
+flat out vec4 finalColor;
+
+void emitLine(vec4 color)
+{
+ gl_Position = ProjectionMatrix * MV_pos[0];
+ EmitVertex();
+ gl_Position = ProjectionMatrix * MV_pos[1];
+ finalColor = color;
+ EmitVertex();
+ EndPrimitive();
+}
+
+void main()
+{
+ float finalEdgeClass = max(edgeClass[0], edgeClass[1]);
+
+ if (finalEdgeClass > 0.0f) {
+ // front-facing edge
+ if (drawFront)
+ emitLine(vec4(fCol[0], 0.75));
+ }
+ else if (finalEdgeClass < 0.0f) {
+ // back-facing edge
+ if (drawBack)
+ emitLine(vec4(fCol[0], 0.5));
+ }
+ else {
+ // exactly one face is front-facing, silhouette edge
+ if (drawSilhouette)
+ emitLine(vec4(fCol[0], 1.0));
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl
new file mode 100644
index 00000000000..fa30c9fb1ed
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl
@@ -0,0 +1,63 @@
+
+// Draw "fancy" wireframe, displaying front-facing, back-facing and
+// silhouette lines differently.
+// Mike Erwin, April 2015
+
+// After working with this shader a while, convinced we should make
+// separate shaders for perpective & ortho. (Oct 2016)
+
+// Due to perspective, the line segment's endpoints might disagree on
+// whether the adjacent faces are front facing. We use a geometry
+// shader to resolve this properly.
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+
+in vec3 pos;
+in vec3 N1, N2; // normals of faces this edge joins (object coords)
+
+/* instance attrib */
+in vec3 color;
+in mat4 InstanceModelMatrix;
+
+out vec4 MV_pos;
+out float edgeClass;
+out vec3 fCol;
+
+// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley
+
+bool front(mat3 NormalMatrix, vec3 N, vec3 eye)
+{
+ return dot(NormalMatrix * N, eye) > 0.0;
+}
+
+void main()
+{
+ vec3 eye;
+
+ mat4 ModelViewMatrix = ViewMatrix * InstanceModelMatrix;
+
+ MV_pos = ModelViewMatrix * vec4(pos, 1.0);
+
+ mat3 NormalMatrix = transpose(inverse(mat3(ModelViewMatrix)));
+
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ eye = normalize(-MV_pos.xyz);
+ }
+ else {
+ eye = vec3(0.0, 0.0, 1.0);
+ }
+
+ bool face_1_front = front(NormalMatrix, N1, eye);
+ bool face_2_front = front(NormalMatrix, N2, eye);
+
+ if (face_1_front && face_2_front)
+ edgeClass = 1.0; // front-facing edge
+ else if (face_1_front || face_2_front)
+ edgeClass = 0.0; // exactly one face is front-facing, silhouette edge
+ else
+ edgeClass = -1.0; // back-facing edge
+
+ fCol = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl
new file mode 100644
index 00000000000..d2b64608eaa
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl
@@ -0,0 +1,27 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos;
+in vec3 nor;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 color;
+
+out vec3 normal;
+flat out vec4 finalColor;
+
+void main()
+{
+ mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * InstanceModelMatrix;
+ /* This is slow and run per vertex, but it's still faster than
+ * doing it per instance on CPU and sending it on via instance attrib */
+ mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix)));
+
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ normal = NormalMatrix * nor;
+
+ finalColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl
new file mode 100644
index 00000000000..429b648ca53
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl
@@ -0,0 +1,32 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screen_vecs[2];
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos; /* using Z as axis id */
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec3 color;
+in float size;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ vec3 offset = vec3(0.0);
+
+#ifdef AXIS_NAME
+ if (pos.z == 0.0)
+ offset = vec3(1.125, 0.0, 0.0);
+ else if (pos.z == 1.0)
+ offset = vec3(0.0, 1.125, 0.0);
+ else
+ offset = vec3(0.0, 0.0, 1.125);
+ offset *= size;
+#endif
+
+ vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y;
+ gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(offset, 1.0) + vec4(screen_pos * size, 0.0));
+ finalColor = vec4(color, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl
new file mode 100644
index 00000000000..2a4675ce2c9
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl
@@ -0,0 +1,29 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screen_vecs[2];
+uniform float size;
+uniform float pixel_size;
+
+/* ---- Instantiated Attribs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attribs ---- */
+in vec3 world_pos;
+in vec3 color;
+
+flat out vec4 finalColor;
+
+float mul_project_m4_v3_zfac(in vec3 co)
+{
+ return (ViewProjectionMatrix[0][3] * co.x) +
+ (ViewProjectionMatrix[1][3] * co.y) +
+ (ViewProjectionMatrix[2][3] * co.z) + ViewProjectionMatrix[3][3];
+}
+
+void main()
+{
+ float pix_size = mul_project_m4_v3_zfac(world_pos) * pixel_size;
+ vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y;
+ gl_Position = ViewProjectionMatrix * vec4(world_pos + screen_pos * size * pix_size, 1.0);
+ finalColor = vec4(color, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
new file mode 100644
index 00000000000..1ec158ae15c
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
@@ -0,0 +1,23 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform float alpha;
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec3 color;
+#ifdef UNIFORM_SCALE
+in float size;
+#else
+in vec3 size;
+#endif
+
+flat out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos * size, 1.0);
+ finalColor = vec4(color, alpha);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
new file mode 100644
index 00000000000..f265bf9fc01
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl
@@ -0,0 +1,23 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform int baseId;
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+#ifdef UNIFORM_SCALE
+in float size;
+#else
+in vec3 size;
+#endif
+in int callId;
+
+flat out uint finalId;
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos * size, 1.0);
+ finalId = uint(baseId + callId);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
new file mode 100644
index 00000000000..a4facae435e
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl
@@ -0,0 +1,13 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instantiated Attribs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl
new file mode 100644
index 00000000000..1c12a4f942d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl
@@ -0,0 +1,87 @@
+flat in vec4 radii;
+flat in vec4 thresholds;
+
+flat in vec4 finalColor;
+flat in vec4 finalOutlineColor;
+
+flat in int finalFlags;
+
+out vec4 fragColor;
+
+const float diagonal_scale = sqrt(0.5);
+
+const float minmax_bias = 0.7;
+const float minmax_scale = sqrt(1.0 / (1.0 + 1.0/minmax_bias));
+
+bool test(int bit) {
+ return (finalFlags & bit) != 0;
+}
+
+void main() {
+ vec2 pos = gl_PointCoord - vec2(0.5);
+ vec2 absPos = abs(pos);
+ float radius = (absPos.x + absPos.y) * diagonal_scale;
+
+ float outline_dist = -1.0;
+
+ /* Diamond outline */
+ if (test(0x1)) {
+ outline_dist = max(outline_dist, radius - radii[0]);
+ }
+
+ /* Circle outline */
+ if (test(0x2)) {
+ radius = length(absPos);
+
+ outline_dist = max(outline_dist, radius - radii[1]);
+ }
+
+ /* Top & Bottom clamp */
+ if (test(0x4)) {
+ outline_dist = max(outline_dist, absPos.y - radii[2]);
+ }
+
+ /* Left & Right clamp */
+ if (test(0x8)) {
+ outline_dist = max(outline_dist, absPos.x - radii[2]);
+ }
+
+ float alpha = 1 - smoothstep(thresholds[0], thresholds[1], abs(outline_dist));
+
+ /* Inside the outline. */
+ if (outline_dist < 0) {
+ /* Middle dot */
+ if (test(0x10)) {
+ alpha = max(alpha, 1 - smoothstep(thresholds[2], thresholds[3], radius));
+ }
+
+ /* Up and down arrow-like shading. */
+ if (test(0x300)) {
+ float ypos = -1.0;
+
+ /* Up arrow (maximum) */
+ if (test(0x100)) {
+ ypos = max(ypos, pos.y);
+ }
+ /* Down arrow (minimum) */
+ if (test(0x200)) {
+ ypos = max(ypos, -pos.y);
+ }
+
+ /* Arrow shape threshold. */
+ float minmax_dist = (ypos - radii[3]) - absPos.x * minmax_bias;
+ float minmax_step = smoothstep(thresholds[0], thresholds[1], minmax_dist * minmax_scale);
+
+ /* Reduced alpha for uncertain extremes. */
+ float minmax_alpha = test(0x400) ? 0.55 : 0.85;
+
+ alpha = max(alpha, minmax_step * minmax_alpha);
+ }
+
+ fragColor = mix(finalColor, finalOutlineColor, alpha);
+ }
+ /* Outside the outline. */
+ else {
+ fragColor = vec4(finalOutlineColor.rgb, finalOutlineColor.a * alpha);
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl
new file mode 100644
index 00000000000..26eb864821a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl
@@ -0,0 +1,83 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 ViewportSize = vec2(-1, -1);
+
+const float line_falloff = 1.0;
+const float circle_scale = sqrt(2.0 / 3.1416);
+const float square_scale = sqrt(0.5);
+
+const float diagonal_scale = sqrt(0.5);
+
+in vec2 pos;
+in float size;
+in vec4 color;
+in vec4 outlineColor;
+in int flags;
+
+flat out vec4 finalColor;
+flat out vec4 finalOutlineColor;
+
+flat out int finalFlags;
+
+flat out vec4 radii;
+flat out vec4 thresholds;
+
+bool test(int bit) {
+ return (flags & bit) != 0;
+}
+
+vec2 line_thresholds(float width) {
+ return vec2(max(0, width - line_falloff), width);
+}
+
+void main() {
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
+
+ /* Align to pixel grid if the viewport size is known. */
+ if (ViewportSize.x > 0) {
+ vec2 scale = ViewportSize * 0.5;
+ vec2 px_pos = (gl_Position.xy + 1) * scale;
+ vec2 adj_pos = round(px_pos - 0.5) + 0.5;
+ gl_Position.xy = adj_pos / scale - 1;
+ }
+
+ /* Pass through parameters. */
+ finalColor = color;
+ finalOutlineColor = outlineColor;
+ finalFlags = flags;
+
+ if (!test(0xF)) {
+ finalFlags |= 1;
+ }
+
+ /* Size-dependent line thickness. */
+ float half_width = (0.06 + (size - 10) * 0.04);
+ float line_width = half_width + line_falloff;
+
+ /* Outline thresholds. */
+ thresholds.xy = line_thresholds(line_width);
+
+ /* Inner dot thresholds. */
+ thresholds.zw = line_thresholds(line_width * 1.6);
+
+ /* Extend the primitive size by half line width on either side; odd for symmetry. */
+ float ext_radius = round(0.5 * size) + thresholds.x;
+
+ gl_PointSize = ceil(ext_radius + thresholds.y) * 2 + 1;
+
+ /* Diamond radius. */
+ radii[0] = ext_radius * diagonal_scale;
+
+ /* Circle radius. */
+ radii[1] = ext_radius * circle_scale;
+
+ /* Square radius. */
+ radii[2] = round(ext_radius * square_scale);
+
+ /* Min/max cutout offset. */
+ radii[3] = -line_falloff;
+
+ /* Convert to PointCoord units. */
+ radii /= gl_PointSize;
+ thresholds /= gl_PointSize;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index ab044fff100..6c7c8f24f51 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1,12 +1,18 @@
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ModelViewMatrixInverse;
+uniform mat3 NormalMatrix;
+
+#ifndef ATTRIB
+uniform mat4 ModelMatrix;
+uniform mat4 ModelMatrixInverse;
+#endif
+
/* Converters */
float convert_rgba_to_float(vec4 color)
{
-#ifdef USE_NEW_SHADING
- return color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
-#else
- return (color.r + color.g + color.b) / 3.0;
-#endif
+ return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
}
float exp_blender(float f)
@@ -53,7 +59,7 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol)
h = 0.0;
}
else {
- c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta;
+ c = (vec3(cmax) - rgb.xyz) / cdelta;
if (rgb.x == cmax) h = c[2] - c[1];
else if (rgb.y == cmax) h = 2.0 + c[0] - c[2];
@@ -135,59 +141,25 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
col_to.a = col_from.a;
}
-void color_to_normal(vec3 color, out vec3 normal)
-{
- normal.x = 2.0 * ((color.r) - 0.5);
- normal.y = -2.0 * ((color.g) - 0.5);
- normal.z = 2.0 * ((color.b) - 0.5);
-}
-
void color_to_normal_new_shading(vec3 color, out vec3 normal)
{
- normal.x = 2.0 * ((color.r) - 0.5);
- normal.y = 2.0 * ((color.g) - 0.5);
- normal.z = 2.0 * ((color.b) - 0.5);
+ normal = vec3(2.0) * color - vec3(1.0);
}
void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
{
- normal.x = 2.0 * ((color.r) - 0.5);
- normal.y = -2.0 * ((color.g) - 0.5);
- normal.z = -2.0 * ((color.b) - 0.5);
+ normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0);
}
+#ifndef M_PI
#define M_PI 3.14159265358979323846
-#define M_1_PI 0.31830988618379069
+#endif
+#ifndef M_1_PI
+#define M_1_PI 0.318309886183790671538
+#endif
/*********** SHADER NODES ***************/
-void vcol_attribute(vec4 attvcol, out vec4 vcol)
-{
- vcol = vec4(attvcol.x, attvcol.y, attvcol.z, 1.0);
-}
-
-void uv_attribute(vec2 attuv, out vec3 uv)
-{
- uv = vec3(attuv * 2.0 - vec2(1.0, 1.0), 0.0);
-}
-
-void geom(
- vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 attvcol,
- out vec3 global, out vec3 local, out vec3 view, out vec3 orco, out vec3 uv,
- out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
-{
- local = co;
- view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0);
- global = (viewinvmat * vec4(local, 1.0)).xyz;
- orco = attorco;
- uv_attribute(attuv, uv);
- normal = -normalize(nor); /* blender render normal is negated */
- vcol_attribute(attvcol, vcol);
- srgb_to_linearrgb(vcol, vcol);
- vcol_alpha = attvcol.a;
- frontback = (gl_FrontFacing) ? 1.0 : 0.0;
-}
-
void particle_info(
vec4 sprops, vec4 loc, vec3 vel, vec3 avel,
out float index, out float random, out float age,
@@ -222,7 +194,13 @@ void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
void point_texco_remap_square(vec3 vin, out vec3 vout)
{
- vout = vec3(vin - vec3(0.5, 0.5, 0.5)) * 2.0;
+ vout = vin * 2.0 - 1.0;
+}
+
+void point_texco_clamp(vec3 vin, sampler2D ima, out vec3 vout)
+{
+ vec2 half_texel_size = 0.5 / vec2(textureSize(ima, 0).xy);
+ vout = clamp(vin, half_texel_size.xyy, 1.0 - half_texel_size.xyy);
}
void point_map_to_sphere(vec3 vin, out vec3 vout)
@@ -256,13 +234,11 @@ void point_map_to_tube(vec3 vin, out vec3 vout)
vout = vec3(u, v, 0.0);
}
-void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec)
+void mapping(vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
{
+ mat4 mat = mat4(m0, m1, m2, m3);
outvec = (mat * vec4(vec, 1.0)).xyz;
- if (domin == 1.0)
- outvec = max(outvec, minvec);
- if (domax == 1.0)
- outvec = min(outvec, maxvec);
+ outvec = clamp(outvec, minvec, maxvec);
}
void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
@@ -272,17 +248,6 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
outview = normalize(co);
}
-void lamp(
- vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac,
- out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
-{
- outcol = col * energy;
- outlv = lv;
- outdist = dist;
- outshadow = vec4(shadow, 1.0);
- outvisifac = visifac;
-}
-
void math_add(float val1, float val2, out float outval)
{
outval = val1 + val2;
@@ -449,13 +414,13 @@ void squeeze(float val, float width, float center, out float outval)
void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 + v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
+ outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
}
void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 - v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
+ outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
}
void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@ -471,7 +436,7 @@ void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
- outvec = vec3(0, 0, 0);
+ outvec = vec3(0);
outval = dot(v1, v2);
}
@@ -499,39 +464,32 @@ void invert_z(vec3 v, out vec3 outv)
outv = v;
}
-void normal(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
-{
- outnor = nor;
- outdot = -dot(dir, nor);
-}
-
-void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
+void normal_new_shading(vec3 nor, vec3 dir, out vec3 outnor, out float outdot)
{
- outnor = normalize(nor);
- outdot = dot(normalize(dir), nor);
+ outnor = dir;
+ outdot = dot(normalize(nor), dir);
}
-void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
+void curves_vec(float fac, vec3 vec, sampler1DArray curvemap, float layer, out vec3 outvec)
{
- outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
- outvec.y = texture2D(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
- outvec.z = texture2D(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
-
- if (fac != 1.0)
- outvec = (outvec * fac) + (vec * (1.0 - fac));
-
+ vec4 co = vec4(vec * 0.5 + 0.5, layer);
+ outvec.x = texture(curvemap, co.xw).x;
+ outvec.y = texture(curvemap, co.yw).y;
+ outvec.z = texture(curvemap, co.zw).z;
+ outvec = mix(vec, outvec, fac);
}
-void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol)
+void curves_rgb(float fac, vec4 col, sampler1DArray curvemap, float layer, out vec4 outcol)
{
- outcol.r = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.r, 0.0)).a, 0.0)).r;
- outcol.g = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.g, 0.0)).a, 0.0)).g;
- outcol.b = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
-
- if (fac != 1.0)
- outcol = (outcol * fac) + (col * (1.0 - fac));
-
+ vec4 co = vec4(col.rgb, layer);
+ co.x = texture(curvemap, co.xw).a;
+ co.y = texture(curvemap, co.yw).a;
+ co.z = texture(curvemap, co.zw).a;
+ outcol.r = texture(curvemap, co.xw).r;
+ outcol.g = texture(curvemap, co.yw).g;
+ outcol.b = texture(curvemap, co.zw).b;
outcol.a = col.a;
+ outcol = mix(col, outcol, fac);
}
void set_value(float val, out float outval)
@@ -844,24 +802,41 @@ void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
}
-void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
+void valtorgb_opti_constant(float fac, float edge, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
+{
+ outcol = (fac > edge) ? color2 : color1;
+ outalpha = outcol.a;
+}
+
+void valtorgb_opti_linear(float fac, vec2 mulbias, vec4 color1, vec4 color2, out vec4 outcol, out float outalpha)
+{
+ fac = clamp(fac * mulbias.x + mulbias.y, 0.0, 1.0);
+ outcol = mix(color1, color2, fac);
+ outalpha = outcol.a;
+}
+
+void valtorgb(float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
+{
+ outcol = texture(colormap, vec2(fac, layer));
+ outalpha = outcol.a;
+}
+
+void valtorgb_nearest(float fac, sampler1DArray colormap, float layer, out vec4 outcol, out float outalpha)
{
- outcol = texture2D(colormap, vec2(fac, 0.0));
+ fac = clamp(fac, 0.0, 1.0);
+ outcol = texelFetch(colormap, ivec2(fac * (textureSize(colormap, 0).x - 1), layer), 0);
outalpha = outcol.a;
}
void rgbtobw(vec4 color, out float outval)
{
-#ifdef USE_NEW_SHADING
- outval = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
-#else
- outval = color.r * 0.35 + color.g * 0.45 + color.b * 0.2; /* keep these factors in sync with texture.h:RGBTOBW */
-#endif
+ vec3 factors = vec3(0.2126, 0.7152, 0.0722);
+ outval = dot(color.rgb, factors);
}
void invert(float fac, vec4 col, out vec4 outcol)
{
- outcol.xyz = mix(col.xyz, vec3(1.0, 1.0, 1.0) - col.xyz, fac);
+ outcol.xyz = mix(col.xyz, vec3(1.0) - col.xyz, fac);
outcol.w = col.w;
}
@@ -939,56 +914,6 @@ void output_node(vec4 rgb, float alpha, out vec4 outrgb)
/*********** TEXTURES ***************/
-void texture_flip_blend(vec3 vec, out vec3 outvec)
-{
- outvec = vec.yxz;
-}
-
-void texture_blend_lin(vec3 vec, out float outval)
-{
- outval = (1.0 + vec.x) / 2.0;
-}
-
-void texture_blend_quad(vec3 vec, out float outval)
-{
- outval = max((1.0 + vec.x) / 2.0, 0.0);
- outval *= outval;
-}
-
-void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal)
-{
- float a = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) * 20.0;
- float wi = 0.5 + 0.5 * sin(a);
-
- value = wi;
- color = vec4(wi, wi, wi, 1.0);
- normal = vec3(0.0, 0.0, 0.0);
-}
-
-void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal)
-{
- color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5);
- value = color.a;
-
- normal.x = 2.0 * (color.r - 0.5);
- normal.y = 2.0 * (0.5 - color.g);
- normal.z = 2.0 * (color.b - 0.5);
-}
-
-/************* MTEX *****************/
-
-void texco_orco(vec3 attorco, out vec3 orco)
-{
- orco = attorco;
-}
-
-void texco_uv(vec2 attuv, out vec3 uv)
-{
- /* disabled for now, works together with leaving out mtex_2d_mapping */
- // uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0); */
- uv = vec3(attuv, 0.0);
-}
-
void texco_norm(vec3 normal, out vec3 outnormal)
{
/* corresponds to shi->orn, which is negated so cancels
@@ -996,436 +921,11 @@ void texco_norm(vec3 normal, out vec3 outnormal)
outnormal = normalize(normal);
}
-void texco_tangent(vec4 tangent, out vec3 outtangent)
-{
- outtangent = normalize(tangent.xyz);
-}
-
-void texco_global(mat4 viewinvmat, vec3 co, out vec3 global)
-{
- global = (viewinvmat * vec4(co, 1.0)).xyz;
-}
-
-void texco_object(mat4 viewinvmat, mat4 obinvmat, vec3 co, out vec3 object)
-{
- object = (obinvmat * (viewinvmat * vec4(co, 1.0))).xyz;
-}
-
-void texco_refl(vec3 vn, vec3 view, out vec3 ref)
-{
- ref = view - 2.0 * dot(vn, view) * vn;
-}
-
-void shade_norm(vec3 normal, out vec3 outnormal)
-{
- /* blender render normal is negated */
- outnormal = -normalize(normal);
-}
-
-void mtex_mirror(vec3 tcol, vec4 refcol, float tin, float colmirfac, out vec4 outrefcol)
-{
- outrefcol = mix(refcol, vec4(1.0, tcol), tin * colmirfac);
-}
-
-void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- float facm;
-
- fact *= facg;
- facm = 1.0 - fact;
-
- incol = fact * texcol + facm * outcol;
-}
-
-void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- float facm;
-
- fact *= facg;
- facm = 1.0 - fact;
-
- incol = (facm + fact * texcol) * outcol;
-}
-
-void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- float facm;
-
- fact *= facg;
- facm = 1.0 - fact;
-
- incol = vec3(1.0) - (vec3(facm) + fact * (vec3(1.0) - texcol)) * (vec3(1.0) - outcol);
-}
-
-void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- float facm;
-
- fact *= facg;
- facm = 1.0 - fact;
-
- if (outcol.r < 0.5)
- incol.r = outcol.r * (facm + 2.0 * fact * texcol.r);
- else
- incol.r = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.r)) * (1.0 - outcol.r);
-
- if (outcol.g < 0.5)
- incol.g = outcol.g * (facm + 2.0 * fact * texcol.g);
- else
- incol.g = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.g)) * (1.0 - outcol.g);
-
- if (outcol.b < 0.5)
- incol.b = outcol.b * (facm + 2.0 * fact * texcol.b);
- else
- incol.b = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.b)) * (1.0 - outcol.b);
-}
-
-void mtex_rgb_sub(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- incol = -fact * facg * texcol + outcol;
-}
-
-void mtex_rgb_add(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- incol = fact * facg * texcol + outcol;
-}
-
-void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- float facm;
-
- fact *= facg;
- facm = 1.0 - fact;
-
- if (texcol.r != 0.0) incol.r = facm * outcol.r + fact * outcol.r / texcol.r;
- if (texcol.g != 0.0) incol.g = facm * outcol.g + fact * outcol.g / texcol.g;
- if (texcol.b != 0.0) incol.b = facm * outcol.b + fact * outcol.b / texcol.b;
-}
-
-void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- float facm;
-
- fact *= facg;
- facm = 1.0 - fact;
-
- incol = facm * outcol + fact * abs(texcol - outcol);
-}
-
-void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- float facm, col;
-
- fact *= facg;
- facm = 1.0 - fact;
-
- incol.r = min(outcol.r, texcol.r) * fact + outcol.r * facm;
- incol.g = min(outcol.g, texcol.g) * fact + outcol.g * facm;
- incol.b = min(outcol.b, texcol.b) * fact + outcol.b * facm;
-}
-
-void mtex_rgb_light(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- float facm, col;
-
- fact *= facg;
-
- col = fact * texcol.r;
- if (col > outcol.r) incol.r = col; else incol.r = outcol.r;
- col = fact * texcol.g;
- if (col > outcol.g) incol.g = col; else incol.g = outcol.g;
- col = fact * texcol.b;
- if (col > outcol.b) incol.b = col; else incol.b = outcol.b;
-}
-
-void mtex_rgb_hue(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- vec4 col;
-
- mix_hue(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
- incol.rgb = col.rgb;
-}
-
-void mtex_rgb_sat(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- vec4 col;
-
- mix_sat(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
- incol.rgb = col.rgb;
-}
-
-void mtex_rgb_val(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- vec4 col;
-
- mix_val(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
- incol.rgb = col.rgb;
-}
-
-void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- vec4 col;
-
- mix_color(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
- incol.rgb = col.rgb;
-}
-
-void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- vec4 col;
-
- mix_soft(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
- incol.rgb = col.rgb;
-}
-
-void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
-{
- fact *= facg;
-
- if (texcol.r > 0.5)
- incol.r = outcol.r + fact * (2.0 * (texcol.r - 0.5));
- else
- incol.r = outcol.r + fact * (2.0 * (texcol.r) - 1.0);
-
- if (texcol.g > 0.5)
- incol.g = outcol.g + fact * (2.0 * (texcol.g - 0.5));
- else
- incol.g = outcol.g + fact * (2.0 * (texcol.g) - 1.0);
-
- if (texcol.b > 0.5)
- incol.b = outcol.b + fact * (2.0 * (texcol.b - 0.5));
- else
- incol.b = outcol.b + fact * (2.0 * (texcol.b) - 1.0);
-}
-
-void mtex_value_vars(inout float fact, float facg, out float facm)
-{
- fact *= abs(facg);
- facm = 1.0 - fact;
-
- if (facg < 0.0) {
- float tmp = fact;
- fact = facm;
- facm = tmp;
- }
-}
-
-void mtex_value_blend(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- incol = fact * texcol + facm * outcol;
-}
-
-void mtex_value_mul(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- facm = 1.0 - facg;
- incol = (facm + fact * texcol) * outcol;
-}
-
-void mtex_value_screen(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- facm = 1.0 - facg;
- incol = 1.0 - (facm + fact * (1.0 - texcol)) * (1.0 - outcol);
-}
-
-void mtex_value_sub(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- fact = -fact;
- incol = fact * texcol + outcol;
-}
-
-void mtex_value_add(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- fact = fact;
- incol = fact * texcol + outcol;
-}
-
-void mtex_value_div(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- if (texcol != 0.0)
- incol = facm * outcol + fact * outcol / texcol;
- else
- incol = 0.0;
-}
-
-void mtex_value_diff(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- incol = facm * outcol + fact * abs(texcol - outcol);
-}
-
-void mtex_value_dark(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- incol = facm * outcol + fact * min(outcol, texcol);
-}
-
-void mtex_value_light(float outcol, float texcol, float fact, float facg, out float incol)
-{
- float facm;
- mtex_value_vars(fact, facg, facm);
-
- float col = fact * texcol;
- if (col > outcol) incol = col; else incol = outcol;
-}
-
-void mtex_value_clamp_positive(float fac, out float outfac)
-{
- outfac = max(fac, 0.0);
-}
-
-void mtex_value_clamp(float fac, out float outfac)
-{
- outfac = clamp(fac, 0.0, 1.0);
-}
-
-void mtex_har_divide(float har, out float outhar)
-{
- outhar = har / 128.0;
-}
-
-void mtex_har_multiply_clamp(float har, out float outhar)
-{
- har *= 128.0;
-
- if (har < 1.0) outhar = 1.0;
- else if (har > 511.0) outhar = 511.0;
- else outhar = har;
-}
-
-void mtex_alpha_from_col(vec4 col, out float alpha)
-{
- alpha = col.a;
-}
-
-void mtex_alpha_to_col(vec4 col, float alpha, out vec4 outcol)
-{
- outcol = vec4(col.rgb, alpha);
-}
-
-void mtex_alpha_multiply_value(vec4 col, float value, out vec4 outcol)
-{
- outcol = vec4(col.rgb, col.a * value);
-}
-
-void mtex_rgbtoint(vec4 rgb, out float intensity)
-{
- intensity = dot(vec3(0.35, 0.45, 0.2), rgb.rgb);
-}
-
-void mtex_value_invert(float invalue, out float outvalue)
-{
- outvalue = 1.0 - invalue;
-}
-
-void mtex_rgb_invert(vec4 inrgb, out vec4 outrgb)
-{
- outrgb = vec4(vec3(1.0) - inrgb.rgb, inrgb.a);
-}
-
-void mtex_value_stencil(float stencil, float intensity, out float outstencil, out float outintensity)
-{
- float fact = intensity;
- outintensity = intensity * stencil;
- outstencil = stencil * fact;
-}
-
-void mtex_rgb_stencil(float stencil, vec4 rgb, out float outstencil, out vec4 outrgb)
-{
- float fact = rgb.a;
- outrgb = vec4(rgb.rgb, rgb.a * stencil);
- outstencil = stencil * fact;
-}
-
-void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco)
-{
- outtexco = texco + ofs;
-}
-
-void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco)
-{
- outtexco = size * texco;
-}
-
-void mtex_2d_mapping(vec3 vec, out vec3 outvec)
-{
- outvec = vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
-}
-
vec3 mtex_2d_mapping(vec3 vec)
{
return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
}
-void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
-{
- color = textureCube(ima, co);
- value = 1.0;
-}
-
-void mtex_cube_map_refl_from_refldir(
- samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color)
-{
- color = textureCube(ima, reflecteddirection);
- value = color.a;
-}
-
-void mtex_cube_map_refl(
- samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix,
- out float value, out vec4 color)
-{
- vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0));
- vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix));
- vec3 reflecteddirection = reflect(viewdirection, normaldirection);
- color = textureCube(ima, reflecteddirection);
- value = 1.0;
-}
-
-void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color)
-{
- color = texture2D(ima, texco.xy);
- value = 1.0;
-}
-
-void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal)
-{
- // The invert of the red channel is to make
- // the normal map compliant with the outside world.
- // It needs to be done because in Blender
- // the normal used points inward.
- // Should this ever change this negate must be removed.
- vec4 color = texture2D(ima, texco.xy);
- normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
-}
-
-void mtex_bump_normals_init(vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude)
-{
- vNorg = vN;
- vNacc = vN;
- fPrevMagnitude = 1.0;
-}
-
/** helper method to extract the upper left 3x3 matrix from a 4x4 matrix */
mat3 to_mat3(mat4 m4)
{
@@ -1436,976 +936,6 @@ mat3 to_mat3(mat4 m4)
return m3;
}
-void mtex_bump_init_objspace(
- vec3 surf_pos, vec3 surf_norm,
- mat4 mView, mat4 mViewInv, mat4 mObj, mat4 mObjInv,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet)
-{
- mat3 obj2view = to_mat3(gl_ModelViewMatrix);
- mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse);
-
- vec3 vSigmaS = view2obj * dFdx(surf_pos);
- vec3 vSigmaT = view2obj * dFdy(surf_pos);
- vec3 vN = normalize(surf_norm * obj2view);
-
- vR1 = cross(vSigmaT, vN);
- vR2 = cross(vN, vSigmaS);
- fDet = dot(vSigmaS, vR1);
-
- /* pretransform vNacc (in mtex_bump_apply) using the inverse transposed */
- vR1 = vR1 * view2obj;
- vR2 = vR2 * view2obj;
- vN = vN * view2obj;
-
- float fMagnitude = abs(fDet) * length(vN);
- vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
- fPrevMagnitude_out = fMagnitude;
-}
-
-void mtex_bump_init_texturespace(
- vec3 surf_pos, vec3 surf_norm,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet)
-{
- vec3 vSigmaS = dFdx(surf_pos);
- vec3 vSigmaT = dFdy(surf_pos);
- vec3 vN = surf_norm; /* normalized interpolated vertex normal */
-
- vR1 = normalize(cross(vSigmaT, vN));
- vR2 = normalize(cross(vN, vSigmaS));
- fDet = sign(dot(vSigmaS, vR1));
-
- float fMagnitude = abs(fDet);
- vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
- fPrevMagnitude_out = fMagnitude;
-}
-
-void mtex_bump_init_viewspace(
- vec3 surf_pos, vec3 surf_norm,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet)
-{
- vec3 vSigmaS = dFdx(surf_pos);
- vec3 vSigmaT = dFdy(surf_pos);
- vec3 vN = surf_norm; /* normalized interpolated vertex normal */
-
- vR1 = cross(vSigmaT, vN);
- vR2 = cross(vN, vSigmaS);
- fDet = dot(vSigmaS, vR1);
-
- float fMagnitude = abs(fDet);
- vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
- fPrevMagnitude_out = fMagnitude;
-}
-
-void mtex_bump_tap3(
- vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt)
-{
- vec2 STll = texco.xy;
- vec2 STlr = texco.xy + dFdx(texco.xy);
- vec2 STul = texco.xy + dFdy(texco.xy);
-
- float Hll, Hlr, Hul;
- rgbtobw(texture2D(ima, STll), Hll);
- rgbtobw(texture2D(ima, STlr), Hlr);
- rgbtobw(texture2D(ima, STul), Hul);
-
- dBs = hScale * (Hlr - Hll);
- dBt = hScale * (Hul - Hll);
-}
-
-#ifdef BUMP_BICUBIC
-
-void mtex_bump_bicubic(
- vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
-{
- float Hl;
- float Hr;
- float Hd;
- float Hu;
-
- vec2 TexDx = dFdx(texco.xy);
- vec2 TexDy = dFdy(texco.xy);
-
- vec2 STl = texco.xy - 0.5 * TexDx;
- vec2 STr = texco.xy + 0.5 * TexDx;
- vec2 STd = texco.xy - 0.5 * TexDy;
- vec2 STu = texco.xy + 0.5 * TexDy;
-
- rgbtobw(texture2D(ima, STl), Hl);
- rgbtobw(texture2D(ima, STr), Hr);
- rgbtobw(texture2D(ima, STd), Hd);
- rgbtobw(texture2D(ima, STu), Hu);
-
- vec2 dHdxy = vec2(Hr - Hl, Hu - Hd);
- float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
- if (fBlend != 0.0) {
- // the derivative of the bicubic sampling of level 0
- ivec2 vDim;
- vDim = textureSize(ima, 0);
-
- // taking the fract part of the texture coordinate is a hardcoded wrap mode.
- // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender.
- // this is done so that we can still get a valid texel with uvs outside the 0,1 range
- // by texelFetch below, as coordinates are clamped when using this function.
- vec2 fTexLoc = vDim * fract(texco.xy) - vec2(0.5, 0.5);
- ivec2 iTexLoc = ivec2(floor(fTexLoc));
- vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic
-
-/*******************************************************************************************
- * This block will replace the one below when one channel textures are properly supported. *
- *******************************************************************************************
- vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim);
- vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim);
- vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim);
- vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim);
-
- mat4 H = mat4(vSamplesUL.w, vSamplesUL.x, vSamplesLL.w, vSamplesLL.x,
- vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y,
- vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x,
- vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y);
- */
- ivec2 iTexLocMod = iTexLoc + ivec2(-1, -1);
-
- mat4 H;
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- ivec2 iTexTmp = iTexLocMod + ivec2(i, j);
-
- // wrap texture coordinates manually for texelFetch to work on uvs oitside the 0,1 range.
- // this is guaranteed to work since we take the fractional part of the uv above.
- iTexTmp.x = (iTexTmp.x < 0) ? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x) ? iTexTmp.x - vDim.x : iTexTmp.x);
- iTexTmp.y = (iTexTmp.y < 0) ? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y) ? iTexTmp.y - vDim.y : iTexTmp.y);
-
- rgbtobw(texelFetch(ima, iTexTmp, 0), H[i][j]);
- }
- }
-
- float x = t.x, y = t.y;
- float x2 = x * x, x3 = x2 * x, y2 = y * y, y3 = y2 * y;
-
- vec4 X = vec4(-0.5 * (x3 + x) + x2, 1.5 * x3 - 2.5 * x2 + 1, -1.5 * x3 + 2 * x2 + 0.5 * x, 0.5 * (x3 - x2));
- vec4 Y = vec4(-0.5 * (y3 + y) + y2, 1.5 * y3 - 2.5 * y2 + 1, -1.5 * y3 + 2 * y2 + 0.5 * y, 0.5 * (y3 - y2));
- vec4 dX = vec4(-1.5 * x2 + 2 * x - 0.5, 4.5 * x2 - 5 * x, -4.5 * x2 + 4 * x + 0.5, 1.5 * x2 - x);
- vec4 dY = vec4(-1.5 * y2 + 2 * y - 0.5, 4.5 * y2 - 5 * y, -4.5 * y2 + 4 * y + 0.5, 1.5 * y2 - y);
-
- // complete derivative in normalized coordinates (mul by vDim)
- vec2 dHdST = vDim * vec2(dot(Y, H * dX), dot(dY, H * X));
-
- // transform derivative to screen-space
- vec2 dHdxy_bicubic = vec2(dHdST.x * TexDx.x + dHdST.y * TexDx.y,
- dHdST.x * TexDy.x + dHdST.y * TexDy.y);
-
- // blend between the two
- dHdxy = dHdxy * (1 - fBlend) + dHdxy_bicubic * fBlend;
- }
-
- dBs = hScale * dHdxy.x;
- dBt = hScale * dHdxy.y;
-}
-
-#endif
-
-void mtex_bump_tap5(
- vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt)
-{
- vec2 TexDx = dFdx(texco.xy);
- vec2 TexDy = dFdy(texco.xy);
-
- vec2 STc = texco.xy;
- vec2 STl = texco.xy - 0.5 * TexDx;
- vec2 STr = texco.xy + 0.5 * TexDx;
- vec2 STd = texco.xy - 0.5 * TexDy;
- vec2 STu = texco.xy + 0.5 * TexDy;
-
- float Hc, Hl, Hr, Hd, Hu;
- rgbtobw(texture2D(ima, STc), Hc);
- rgbtobw(texture2D(ima, STl), Hl);
- rgbtobw(texture2D(ima, STr), Hr);
- rgbtobw(texture2D(ima, STd), Hd);
- rgbtobw(texture2D(ima, STu), Hu);
-
- dBs = hScale * (Hr - Hl);
- dBt = hScale * (Hu - Hd);
-}
-
-void mtex_bump_deriv(
- vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale,
- out float dBs, out float dBt)
-{
- float s = 1.0; // negate this if flipped texture coordinate
- vec2 TexDx = dFdx(texco.xy);
- vec2 TexDy = dFdy(texco.xy);
-
- // this variant using a derivative map is described here
- // http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
- vec2 dim = vec2(ima_x, ima_y);
- vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0);
-
- dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y;
- dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y;
-}
-
-void mtex_bump_apply(
- float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in,
- out vec3 vNacc_out, out vec3 perturbed_norm)
-{
- vec3 vSurfGrad = sign(fDet) * (dBs * vR1 + dBt * vR2);
-
- vNacc_out = vNacc_in - vSurfGrad;
- perturbed_norm = normalize(vNacc_out);
-}
-
-void mtex_bump_apply_texspace(
- float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2,
- sampler2D ima, vec3 texco, float ima_x, float ima_y, vec3 vNacc_in,
- out vec3 vNacc_out, out vec3 perturbed_norm)
-{
- vec2 TexDx = dFdx(texco.xy);
- vec2 TexDy = dFdy(texco.xy);
-
- vec3 vSurfGrad = sign(fDet) * (
- dBs / length(vec2(ima_x * TexDx.x, ima_y * TexDx.y)) * vR1 +
- dBt / length(vec2(ima_x * TexDy.x, ima_y * TexDy.y)) * vR2);
-
- vNacc_out = vNacc_in - vSurfGrad;
- perturbed_norm = normalize(vNacc_out);
-}
-
-void mtex_negate_texnormal(vec3 normal, out vec3 outnormal)
-{
- outnormal = vec3(-normal.x, -normal.y, normal.z);
-}
-
-void mtex_nspace_tangent(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
-{
- vec3 B = tangent.w * cross(normal, tangent.xyz);
-
- outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
- outnormal = normalize(outnormal);
-}
-
-void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal)
-{
- outnormal = normalize((viewmat * vec4(texnormal, 0.0)).xyz);
-}
-
-void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
-{
- outnormal = normalize(gl_NormalMatrix * texnormal);
-}
-
-void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal)
-{
- outnormal = (1.0 - norfac) * normal + norfac * newnormal;
- outnormal = normalize(outnormal);
-}
-
-/******* MATERIAL *********/
-
-void lamp_visibility_sun_hemi(vec3 lampvec, out vec3 lv, out float dist, out float visifac)
-{
- lv = lampvec;
- dist = 1.0;
- visifac = 1.0;
-}
-
-void lamp_visibility_other(vec3 co, vec3 lampco, out vec3 lv, out float dist, out float visifac)
-{
- lv = co - lampco;
- dist = length(lv);
- lv = normalize(lv);
- visifac = 1.0;
-}
-
-void lamp_falloff_invlinear(float lampdist, float dist, out float visifac)
-{
- visifac = lampdist / (lampdist + dist);
-}
-
-void lamp_falloff_invsquare(float lampdist, float dist, out float visifac)
-{
- visifac = lampdist / (lampdist + dist * dist);
-}
-
-void lamp_falloff_sliders(float lampdist, float ld1, float ld2, float dist, out float visifac)
-{
- float lampdistkw = lampdist * lampdist;
-
- visifac = lampdist / (lampdist + ld1 * dist);
- visifac *= lampdistkw / (lampdistkw + ld2 * dist * dist);
-}
-
-void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coeff_quad, float dist, out float visifac)
-{
- vec3 coeff = vec3(coeff_const, coeff_lin, coeff_quad);
- vec3 d_coeff = vec3(1.0, dist, dist * dist);
- float visifac_r = dot(coeff, d_coeff);
- if (visifac_r > 0.0)
- visifac = 1.0 / visifac_r;
- else
- visifac = 0.0;
-}
-
-void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac)
-{
- visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x;
-}
-
-void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac)
-{
- float t = lampdist - dist;
-
- outvisifac = visifac * max(t, 0.0) / lampdist;
-}
-
-void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
-{
- if (dot(lv, lampvec) > 0.0) {
- vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz;
- /* without clever non-uniform scale, we could do: */
- // float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z));
- float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z));
-
- inpr = 1.0 / sqrt(1.0 + x * x);
- }
- else
- inpr = 0.0;
-}
-
-void lamp_visibility_spot_circle(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
-{
- /* without clever non-uniform scale, we could do: */
- // inpr = dot(lv, lampvec);
- if (dot(lv, lampvec) > 0.0) {
- vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz;
- float x = abs(lvrot.x / lvrot.z);
- float y = abs(lvrot.y / lvrot.z);
-
- float ellipse = abs((x * x) / (scale.x * scale.x) + (y * y) / (scale.y * scale.y));
-
- inpr = 1.0 / sqrt(1.0 + ellipse);
- }
- else
- inpr = 0.0;
-}
-
-void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac, out float outvisifac)
-{
- float t = spotsi;
-
- if (inpr <= t) {
- outvisifac = 0.0;
- }
- else {
- t = inpr - t;
-
- /* soft area */
- if (spotbl != 0.0)
- inpr *= smoothstep(0.0, 1.0, t / spotbl);
-
- outvisifac = visifac * inpr;
- }
-}
-
-void lamp_visibility_clamp(float visifac, out float outvisifac)
-{
- outvisifac = (visifac < 0.001) ? 0.0 : visifac;
-}
-
-void world_paper_view(vec3 vec, out vec3 outvec)
-{
- vec3 nvec = normalize(vec);
- outvec = (gl_ProjectionMatrix[3][3] == 0.0) ? vec3(nvec.x, 0.0, nvec.y) : vec3(0.0, 0.0, -1.0);
-}
-
-void world_zen_mapping(vec3 view, float zenup, float zendown, out float zenfac)
-{
- if (view.z >= 0.0)
- zenfac = zenup;
- else
- zenfac = zendown;
-}
-
-void world_blend_paper_real(vec3 vec, out float blend)
-{
- blend = abs(vec.y);
-}
-
-void world_blend_paper(vec3 vec, out float blend)
-{
- blend = (vec.y + 1.0) * 0.5;
-}
-
-void world_blend_real(vec3 vec, out float blend)
-{
- blend = abs(normalize(vec).z);
-}
-
-void world_blend(vec3 vec, out float blend)
-{
- blend = (normalize(vec).z + 1) * 0.5;
-}
-
-void shade_view(vec3 co, out vec3 view)
-{
- /* handle perspective/orthographic */
- view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0);
-}
-
-void shade_tangent_v(vec3 lv, vec3 tang, out vec3 vn)
-{
- vec3 c = cross(lv, tang);
- vec3 vnor = cross(c, tang);
-
- vn = -normalize(vnor);
-}
-
-void shade_inp(vec3 vn, vec3 lv, out float inp)
-{
- inp = dot(vn, lv);
-}
-
-void shade_is_no_diffuse(out float is)
-{
- is = 0.0;
-}
-
-void shade_is_hemi(float inp, out float is)
-{
- is = 0.5 * inp + 0.5;
-}
-
-float area_lamp_energy(mat4 area, vec3 co, vec3 vn)
-{
- vec3 vec[4], c[4];
- float rad[4], fac;
-
- vec[0] = normalize(co - area[0].xyz);
- vec[1] = normalize(co - area[1].xyz);
- vec[2] = normalize(co - area[2].xyz);
- vec[3] = normalize(co - area[3].xyz);
-
- c[0] = normalize(cross(vec[0], vec[1]));
- c[1] = normalize(cross(vec[1], vec[2]));
- c[2] = normalize(cross(vec[2], vec[3]));
- c[3] = normalize(cross(vec[3], vec[0]));
-
- rad[0] = acos(dot(vec[0], vec[1]));
- rad[1] = acos(dot(vec[1], vec[2]));
- rad[2] = acos(dot(vec[2], vec[3]));
- rad[3] = acos(dot(vec[3], vec[0]));
-
- fac = rad[0] * dot(vn, c[0]);
- fac += rad[1] * dot(vn, c[1]);
- fac += rad[2] * dot(vn, c[2]);
- fac += rad[3] * dot(vn, c[3]);
-
- return max(fac, 0.0);
-}
-
-void shade_inp_area(
- vec3 position, vec3 lampco, vec3 lampvec, vec3 vn, mat4 area, float areasize, float k,
- out float inp)
-{
- vec3 co = position;
- vec3 vec = co - lampco;
-
- if (dot(vec, lampvec) < 0.0) {
- inp = 0.0;
- }
- else {
- float intens = area_lamp_energy(area, co, vn);
-
- inp = pow(intens * areasize, k);
- }
-}
-
-void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out float is)
-{
- vec3 h = normalize(v + l);
- float nh = max(dot(n, h), 0.0);
- float nv = max(dot(n, v), 0.0);
- float realnl = dot(n, l);
-
- if (realnl < 0.0) {
- is = 0.0;
- }
- else if (nl < 0.0) {
- is = 0.0;
- }
- else {
- float vh = max(dot(v, h), 0.0);
- float Lit_A = acos(realnl);
- float View_A = acos(nv);
-
- vec3 Lit_B = normalize(l - realnl * n);
- vec3 View_B = normalize(v - nv * n);
-
- float t = max(dot(Lit_B, View_B), 0.0);
-
- float a, b;
-
- if (Lit_A > View_A) {
- a = Lit_A;
- b = View_A;
- }
- else {
- a = View_A;
- b = Lit_A;
- }
-
- float A = 1.0 - (0.5 * ((rough * rough) / ((rough * rough) + 0.33)));
- float B = 0.45 * ((rough * rough) / ((rough * rough) + 0.09));
-
- b *= 0.95;
- is = nl * (A + (B * t * sin(a) * tan(b)));
- }
-}
-
-void shade_diffuse_toon(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float is)
-{
- float rslt = dot(n, l);
- float ang = acos(rslt);
-
- if (ang < size) is = 1.0;
- else if (ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0;
- else is = 1.0 - ((ang - size) / tsmooth);
-}
-
-void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float is)
-{
- if (nl <= 0.0) {
- is = 0.0;
- }
- else {
- float nv = max(dot(n, v), 0.0);
-
- if (darkness <= 1.0)
- is = nl * pow(max(nv * nl, 0.1), darkness - 1.0);
- else
- is = nl * pow(1.0001 - nv, darkness - 1.0);
- }
-}
-
-float fresnel_fac(vec3 view, vec3 vn, float grad, float fac)
-{
- float t1, t2;
- float ffac;
-
- if (fac == 0.0) {
- ffac = 1.0;
- }
- else {
- t1 = dot(view, vn);
- if (t1 > 0.0) t2 = 1.0 + t1;
- else t2 = 1.0 - t1;
-
- t2 = grad + (1.0 - grad) * pow(t2, fac);
-
- if (t2 < 0.0) ffac = 0.0;
- else if (t2 > 1.0) ffac = 1.0;
- else ffac = t2;
- }
-
- return ffac;
-}
-
-void shade_diffuse_fresnel(vec3 vn, vec3 lv, vec3 view, float fac_i, float fac, out float is)
-{
- is = fresnel_fac(lv, vn, fac_i, fac);
-}
-
-void shade_cubic(float is, out float outis)
-{
- if (is > 0.0 && is < 1.0)
- outis = smoothstep(0.0, 1.0, is);
- else
- outis = is;
-}
-
-void shade_visifac(float i, float visifac, float refl, out float outi)
-{
- /*if (i > 0.0)*/
- outi = max(i * visifac * refl, 0.0);
- /*else
- outi = i;*/
-}
-
-void shade_tangent_v_spec(vec3 tang, out vec3 vn)
-{
- vn = tang;
-}
-
-void shade_add_to_diffuse(float i, vec3 lampcol, vec3 col, out vec3 outcol)
-{
- if (i > 0.0)
- outcol = i * lampcol * col;
- else
- outcol = vec3(0.0, 0.0, 0.0);
-}
-
-void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float visifac, out float t)
-{
- lv += view;
- lv = normalize(lv);
-
- t = dot(vn, lv);
- t = 0.5 * t + 0.5;
-
- t = visifac * spec * pow(t, hard);
-}
-
-void shade_phong_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
-{
- vec3 h = normalize(l + v);
- float rslt = max(dot(h, n), 0.0);
-
- specfac = pow(rslt, hard);
-}
-
-void shade_cooktorr_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
-{
- vec3 h = normalize(v + l);
- float nh = dot(n, h);
-
- if (nh < 0.0) {
- specfac = 0.0;
- }
- else {
- float nv = max(dot(n, v), 0.0);
- float i = pow(nh, hard);
-
- i = i / (0.1 + nv);
- specfac = i;
- }
-}
-
-void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, out float specfac)
-{
- if (refrac < 1.0) {
- specfac = 0.0;
- }
- else if (spec_power == 0.0) {
- specfac = 0.0;
- }
- else {
- if (spec_power < 100.0)
- spec_power = sqrt(1.0 / spec_power);
- else
- spec_power = 10.0 / spec_power;
-
- vec3 h = normalize(v + l);
- float nh = dot(n, h);
- if (nh < 0.0) {
- specfac = 0.0;
- }
- else {
- float nv = max(dot(n, v), 0.01);
- float nl = dot(n, l);
- if (nl <= 0.01) {
- specfac = 0.0;
- }
- else {
- float vh = max(dot(v, h), 0.01);
-
- float a = 1.0;
- float b = (2.0 * nh * nv) / vh;
- float c = (2.0 * nh * nl) / vh;
-
- float g = 0.0;
-
- if (a < b && a < c) g = a;
- else if (b < a && b < c) g = b;
- else if (c < a && c < b) g = c;
-
- float p = sqrt(((refrac * refrac) + (vh * vh) - 1.0));
- float f = ((((p - vh) * (p - vh)) / ((p + vh) * (p + vh))) *
- (1.0 + ((((vh * (p + vh)) - 1.0) * ((vh * (p + vh)) - 1.0)) /
- (((vh * (p - vh)) + 1.0) * ((vh * (p - vh)) + 1.0)))));
- float ang = acos(nh);
-
- specfac = max(f * g * exp_blender((-(ang * ang) / (2.0 * spec_power * spec_power))), 0.0);
- }
- }
- }
-}
-
-void shade_wardiso_spec(vec3 n, vec3 l, vec3 v, float rms, out float specfac)
-{
- vec3 h = normalize(l + v);
- float nh = max(dot(n, h), 0.001);
- float nv = max(dot(n, v), 0.001);
- float nl = max(dot(n, l), 0.001);
- float angle = tan(acos(nh));
- float alpha = max(rms, 0.001);
-
- specfac = nl * (1.0 / (4.0 * M_PI * alpha * alpha)) * (exp_blender(-(angle * angle) / (alpha * alpha)) / (sqrt(nv * nl)));
-}
-
-void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float specfac)
-{
- vec3 h = normalize(l + v);
- float rslt = dot(h, n);
- float ang = acos(rslt);
-
- if (ang < size) rslt = 1.0;
- else if (ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0;
- else rslt = 1.0 - ((ang - size) / tsmooth);
-
- specfac = rslt;
-}
-
-void shade_spec_area_inp(float specfac, float inp, out float outspecfac)
-{
- outspecfac = specfac * inp;
-}
-
-void shade_spec_t(float shadfac, float spec, float visifac, float specfac, out float t)
-{
- t = shadfac * spec * visifac * specfac;
-}
-
-void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol)
-{
- outcol = t * lampcol * speccol;
-}
-
-void shade_add_mirror(vec3 mir, vec4 refcol, vec3 combined, out vec3 result)
-{
- result = mir * refcol.gba + (vec3(1.0) - mir * refcol.rrr) * combined;
-}
-
-void alpha_spec_correction(vec3 spec, float spectra, float alpha, out float outalpha)
-{
- if (spectra > 0.0) {
- float t = clamp(max(max(spec.r, spec.g), spec.b) * spectra, 0.0, 1.0);
- outalpha = (1.0 - t) * alpha + t;
- }
- else {
- outalpha = alpha;
- }
-}
-
-void shade_add(vec4 col1, vec4 col2, out vec4 outcol)
-{
- outcol = col1 + col2;
-}
-
-void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
-{
- outcol = col + col1 * col2;
-}
-
-void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
-{
- outcol = col1 + max(col2, vec4(0.0, 0.0, 0.0, 0.0));
-}
-
-void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
-{
- outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0));
-}
-
-void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol)
-{
- vec3 vv = normalize(vm[2].xyz);
- float skyfac = 0.5 * (1.0 + dot(vn, -vv));
- outcol = col + f * vec4(mix(hor, zen, skyfac), 0);
-}
-
-void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol)
-{
- outcol = col + f * col1;
-}
-
-void shade_mul(vec4 col1, vec4 col2, out vec4 outcol)
-{
- outcol = col1 * col2;
-}
-
-void shade_mul_value(float fac, vec4 col, out vec4 outcol)
-{
- outcol = col * fac;
-}
-
-void shade_mul_value_v3(float fac, vec3 col, out vec3 outcol)
-{
- outcol = col * fac;
-}
-
-void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
-{
- outcol = vec4(col.rgb * obcol.rgb, col.a);
-}
-
-void ramp_rgbtobw(vec3 color, out float outval)
-{
- outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12;
-}
-
-void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb)
-{
- outshadrgb = i * energy * (1.0 - shadfac) * (vec3(1.0) - shadcol);
-}
-
-void shade_only_shadow_diffuse(vec3 shadrgb, vec3 rgb, vec4 diff, out vec4 outdiff)
-{
- outdiff = diff - vec4(rgb * shadrgb, 0.0);
-}
-
-void shade_only_shadow_specular(vec3 shadrgb, vec3 specrgb, vec4 spec, out vec4 outspec)
-{
- outspec = spec - vec4(specrgb * shadrgb, 0.0);
-}
-
-void shade_clamp_positive(vec4 col, out vec4 outcol)
-{
- outcol = max(col, vec4(0.0));
-}
-
-void test_shadowbuf(
- vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp,
- out float result)
-{
- if (inp <= 0.0) {
- result = 0.0;
- }
- else {
- vec4 co = shadowpersmat * vec4(rco, 1.0);
-
- //float bias = (1.5 - inp*inp)*shadowbias;
- co.z -= shadowbias * co.w;
-
- if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0)
- result = shadow2DProj(shadowmap, co).x;
- else
- result = 1.0;
- }
-}
-
-void test_shadowbuf_vsm(
- vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp,
- out float result)
-{
- if (inp <= 0.0) {
- result = 0.0;
- }
- else {
- vec4 co = shadowpersmat * vec4(rco, 1.0);
- if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) {
- vec2 moments = texture2DProj(shadowmap, co).rg;
- float dist = co.z / co.w;
- float p = 0.0;
-
- if (dist <= moments.x)
- p = 1.0;
-
- float variance = moments.y - (moments.x * moments.x);
- variance = max(variance, shadowbias / 10.0);
-
- float d = moments.x - dist;
- float p_max = variance / (variance + d * d);
-
- // Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1]
- p_max = clamp((p_max - bleedbias) / (1.0 - bleedbias), 0.0, 1.0);
-
- result = max(p, p_max);
- }
- else {
- result = 1.0;
- }
- }
-}
-
-void shadows_only(
- vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat,
- float shadowbias, vec3 shadowcolor, float inp,
- out vec3 result)
-{
- result = vec3(1.0);
-
- if (inp > 0.0) {
- float shadfac;
-
- test_shadowbuf(rco, shadowmap, shadowpersmat, shadowbias, inp, shadfac);
- result -= (1.0 - shadfac) * (vec3(1.0) - shadowcolor);
- }
-}
-
-void shadows_only_vsm(
- vec3 rco, sampler2D shadowmap, mat4 shadowpersmat,
- float shadowbias, float bleedbias, vec3 shadowcolor, float inp,
- out vec3 result)
-{
- result = vec3(1.0);
-
- if (inp > 0.0) {
- float shadfac;
-
- test_shadowbuf_vsm(rco, shadowmap, shadowpersmat, shadowbias, bleedbias, inp, shadfac);
- result -= (1.0 - shadfac) * (vec3(1.0) - shadowcolor);
- }
-}
-
-void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec4 result)
-{
-
- vec4 co = shadowpersmat * vec4(rco, 1.0);
-
- result = texture2DProj(cookie, co);
-}
-
-void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol)
-{
- outcol = linfac * (1.0 - exp(col * logfac));
-}
-
-void shade_mist_factor(
- vec3 co, float enable, float miststa, float mistdist, float misttype, float misi,
- out float outfac)
-{
- if (enable == 1.0) {
- float fac, zcor;
-
- zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
-
- fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
- if (misttype == 0.0) fac *= fac;
- else if (misttype == 1.0) ;
- else fac = sqrt(fac);
-
- outfac = 1.0 - (1.0 - fac) * (1.0 - misi);
- }
- else {
- outfac = 0.0;
- }
-}
-
-void shade_world_mix(vec3 hor, vec4 col, out vec4 outcol)
-{
- float fac = clamp(col.a, 0.0, 1.0);
- outcol = vec4(mix(hor, col.rgb, fac), col.a);
-}
-
-void shade_alpha_opaque(vec4 col, out vec4 outcol)
-{
- outcol = vec4(col.rgb, 1.0);
-}
-
-void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
-{
- outcol = vec4(col.rgb, col.a * obcol.a);
-}
-
/*********** NEW SHADER UTILITIES **************/
float fresnel_dielectric_0(float eta)
@@ -2451,7 +981,15 @@ float hypot(float x, float y)
void generated_from_orco(vec3 orco, out vec3 generated)
{
- generated = orco * 0.5 + vec3(0.5);
+#ifdef VOLUMETRICS
+#ifdef MESH_SHADER
+ generated = volumeObjectLocalCoord;
+#else
+ generated = worldPosition;
+#endif
+#else
+ generated = orco;
+#endif
}
int floor_to_int(float x)
@@ -2464,7 +1002,6 @@ int quick_floor(float x)
return int(x) - ((x < 0) ? 1 : 0);
}
-#ifdef BIT_OPERATIONS
float integer_noise(int n)
{
int nn;
@@ -2528,7 +1065,6 @@ vec3 cellnoise_color(vec3 p)
return vec3(r, g, b);
}
-#endif // BIT_OPERATIONS
float floorfrac(float x, out int i)
{
@@ -2536,325 +1072,548 @@ float floorfrac(float x, out int i)
return x - i;
}
+/* bsdfs */
-/* Principled BSDF operations */
-
-float sqr(float a)
+vec3 tint_from_color(vec3 color)
{
- return a*a;
+ float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
+ return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
}
-float schlick_fresnel(float u)
+void convert_metallic_to_specular_tinted(
+ vec3 basecol, vec3 basecol_tint, float metallic, float specular_fac, float specular_tint,
+ out vec3 diffuse, out vec3 f0)
{
- float m = clamp(1.0 - u, 0.0, 1.0);
- float m2 = m * m;
- return m2 * m2 * m; // pow(m,5)
+ vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
+ f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
+ diffuse = basecol * (1.0 - metallic);
}
-float GTR1(float NdotH, float a)
+vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
{
- if (a >= 1.0) {
- return M_1_PI;
- }
+ float f = 1.0 - NV;
+ /* Empirical approximation (manual curve fitting). Can be refined. */
+ float sheen = f*f*f*0.077 + f*0.01 + 0.00026;
+ return sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
+}
- a = max(a, 0.001);
- float a2 = a*a;
- float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
- return (a2 - 1.0) / (M_PI * log(a2) * t);
+#ifndef VOLUMETRICS
+void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
+{
+ N = normalize(N);
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance);
+ result.radiance *= color.rgb;
}
-float GTR2(float NdotH, float a)
+void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
{
- float a2 = a*a;
- float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
- return a2 / (M_PI * t*t);
+ N = normalize(N);
+ vec3 out_spec, ssr_spec;
+ eevee_closure_glossy(N, vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec * color.rgb;
+ result.ssr_data = vec4(ssr_spec * color.rgb, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
}
-float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
+void node_bsdf_anisotropic(
+ vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
+ out Closure result)
{
- return 1.0 / (M_PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH));
+ node_bsdf_glossy(color, roughness, N, -1, result);
}
-float smithG_GGX(float NdotV, float alphaG)
+void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result)
{
- float a = alphaG*alphaG;
- float b = NdotV*NdotV;
- return 1.0 / (NdotV + sqrt(a + b - a * b));
+ N = normalize(N);
+ vec3 out_spec, out_refr, ssr_spec;
+ vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb : color.rgb; /* Simulate 2 transmission event */
+ eevee_closure_glass(N, vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
+ out_refr *= refr_color;
+ out_spec *= color.rgb;
+ float fresnel = F_eta(ior, dot(N, cameraVec));
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = mix(out_refr, out_spec, fresnel);
+ result.ssr_data = vec4(ssr_spec * color.rgb * fresnel, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
}
-vec3 rotate_vector(vec3 p, vec3 n, float theta) {
- return (
- p * cos(theta) + cross(n, p) *
- sin(theta) + n * dot(p, n) *
- (1.0 - cos(theta))
- );
+void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
+{
+ node_bsdf_diffuse(color, 0.0, N, result);
}
+void node_bsdf_principled(
+ vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+ float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+ float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+ float sss_id, vec3 sss_scale, out Closure result)
+{
+ N = normalize(N);
+ ior = max(ior, 1e-5);
+ metallic = saturate(metallic);
+ transmission = saturate(transmission);
+ float dielectric = 1.0 - metallic;
+ transmission *= dielectric;
+ sheen *= dielectric;
+ subsurface_color *= dielectric;
+
+ vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ /* Far from being accurate, but 2 glossy evaluation is too expensive.
+ * Most noticeable difference is at grazing angles since the bsdf lut
+ * f0 color interpolation is done on top of this interpolation. */
+ vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
+ float fresnel = F_eta(ior, NV);
+ vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
+ f0 = mix(f0, spec_col, transmission);
+
+ vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
+
+ float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
+ eevee_closure_principled(N, mixed_ss_base_color, f0, int(ssr_id), roughness,
+ CN, clearcoat * 0.25, clearcoat_roughness, 1.0, sss_scalef, ior,
+ out_diff, out_trans, out_spec, out_refr, ssr_spec);
+
+ vec3 refr_color = base_color.rgb;
+ refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission event */
+ out_refr *= refr_color * (1.0 - fresnel) * transmission;
+
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec + out_refr;
+ result.radiance += out_diff * out_sheen; /* Coarse approx. */
+#ifndef USE_SSS
+ result.radiance += (out_diff + out_trans) * mixed_ss_base_color * (1.0 - transmission);
+#endif
+ result.ssr_data = vec4(ssr_spec, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
+#ifdef USE_SSS
+ result.sss_data.a = sss_scalef;
+ result.sss_data.rgb = out_diff + out_trans;
+# ifdef USE_SSS_ALBEDO
+ result.sss_albedo.rgb = mixed_ss_base_color;
+# else
+ result.sss_data.rgb *= mixed_ss_base_color;
+# endif
+ result.sss_data.rgb *= (1.0 - transmission);
+#endif
+}
-/*********** NEW SHADER NODES ***************/
+void node_bsdf_principled_dielectric(
+ vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+ float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+ float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+ float sss_id, vec3 sss_scale, out Closure result)
+{
+ N = normalize(N);
+ metallic = saturate(metallic);
+ float dielectric = 1.0 - metallic;
+
+ vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ eevee_closure_default(N, diffuse, f0, int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
+
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec + out_diff * (diffuse + out_sheen);
+ result.ssr_data = vec4(ssr_spec, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
+}
+
+void node_bsdf_principled_metallic(
+ vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+ float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+ float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+ float sss_id, vec3 sss_scale, out Closure result)
+{
+ N = normalize(N);
+ vec3 out_spec, ssr_spec;
+
+ eevee_closure_glossy(N, base_color.rgb, int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
+
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ result.ssr_data = vec4(ssr_spec, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
+}
+
+void node_bsdf_principled_clearcoat(
+ vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+ float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+ float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+ float sss_id, vec3 sss_scale, out Closure result)
+{
+ vec3 out_spec, ssr_spec;
+ N = normalize(N);
+
+ eevee_closure_clearcoat(N, base_color.rgb, int(ssr_id), roughness, CN, clearcoat * 0.25, clearcoat_roughness,
+ 1.0, out_spec, ssr_spec);
+
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ result.ssr_data = vec4(ssr_spec, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
+}
+
+void node_bsdf_principled_subsurface(
+ vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+ float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+ float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+ float sss_id, vec3 sss_scale, out Closure result)
+{
+ metallic = saturate(metallic);
+ N = normalize(N);
+
+ vec3 diffuse, f0, out_diff, out_spec, out_trans, ssr_spec;
+ vec3 ctint = tint_from_color(base_color.rgb);
+ convert_metallic_to_specular_tinted(base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
+
+ subsurface_color = subsurface_color * (1.0 - metallic);
+ vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
+ float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
+
+ float NV = dot(N, cameraVec);
+ vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
+
+ eevee_closure_skin(N, mixed_ss_base_color, f0, int(ssr_id), roughness, 1.0, sss_scalef,
+ out_diff, out_trans, out_spec, ssr_spec);
+
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_spec;
+ result.ssr_data = vec4(ssr_spec, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
+#ifdef USE_SSS
+ result.sss_data.a = sss_scalef;
+ result.sss_data.rgb = out_diff + out_trans;
+# ifdef USE_SSS_ALBEDO
+ result.sss_albedo.rgb = mixed_ss_base_color;
+# else
+ result.sss_data.rgb *= mixed_ss_base_color;
+# endif
+#else
+ result.radiance += (out_diff + out_trans) * mixed_ss_base_color;
+#endif
+ result.radiance += out_diff * out_sheen;
+}
-#define NUM_LIGHTS 3
+void node_bsdf_principled_glass(
+ vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+ float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+ float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+ float sss_id, vec3 sss_scale, out Closure result)
+{
+ ior = max(ior, 1e-5);
+ N = normalize(N);
-/* bsdfs */
+ vec3 f0, out_spec, out_refr, ssr_spec;
+ f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
-void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
-{
- /* ambient light */
- vec3 L = vec3(0.2);
+ eevee_closure_glass(N, vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
- /* directional lights */
- for (int i = 0; i < NUM_LIGHTS; i++) {
- vec3 light_position = gl_LightSource[i].position.xyz;
- vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
+ vec3 refr_color = base_color.rgb;
+ refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission events */
+ out_refr *= refr_color;
- float bsdf = max(dot(N, light_position), 0.0);
- L += light_diffuse * bsdf;
- }
+ float fresnel = F_eta(ior, dot(N, cameraVec));
+ vec3 spec_col = F_color_blend(ior, fresnel, f0);
+ out_spec *= spec_col;
+ ssr_spec *= spec_col * fresnel;
- result = vec4(L * color.rgb, 1.0);
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.radiance = mix(out_refr, out_spec, fresnel);
+ result.ssr_data = vec4(ssr_spec, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
}
-void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
+void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
{
- /* ambient light */
- vec3 L = vec3(0.2);
-
- /* directional lights */
- for (int i = 0; i < NUM_LIGHTS; i++) {
- vec3 light_position = gl_LightSource[i].position.xyz;
- vec3 H = gl_LightSource[i].halfVector.xyz;
- vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
- vec3 light_specular = gl_LightSource[i].specular.rgb;
-
- /* we mix in some diffuse so low roughness still shows up */
- float r2 = roughness * roughness;
- float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / r2);
- bsdf += 0.5 * max(dot(N, light_position), 0.0);
- L += light_specular * bsdf;
- }
-
- result = vec4(L * color.rgb, 1.0);
+ node_bsdf_diffuse(color, 0.0, -N, result);
}
-void node_bsdf_anisotropic(
- vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
- out vec4 result)
+void node_bsdf_transparent(vec4 color, out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
+ /* this isn't right */
+ result = CLOSURE_DEFAULT;
+ result.radiance = vec3(0.0);
+ result.opacity = clamp(1.0 - dot(color.rgb, vec3(0.3333334)), 0.0, 1.0);
+ result.ssr_id = TRANSPARENT_CLOSURE_FLAG;
}
-void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
+void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 result)
-{
+void node_subsurface_scattering(
+ vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, float sss_id,
+ out Closure result)
+{
+#if defined(USE_SSS)
+ N = normalize(N);
+ vec3 out_diff, out_trans;
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.ssr_data = vec4(0.0);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = -1;
+ result.sss_data.a = scale;
+ eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
+ result.sss_data.rgb = out_diff + out_trans;
+# ifdef USE_SSS_ALBEDO
+ /* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */
+ result.sss_albedo.rgb = mix(color.rgb, vec3(1.0), texture_blur);
+ result.sss_data.rgb *= mix(vec3(1.0), color.rgb, texture_blur);
+# else
+ result.sss_data.rgb *= color.rgb;
+# endif
+#else
node_bsdf_diffuse(color, 0.0, N, result);
+#endif
}
-void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
- float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
- float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
+void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
{
- /* ambient light */
- // TODO: set ambient light to an appropriate value
- vec3 L = mix(0.1, 0.03, metallic) * mix(base_color.rgb, subsurface_color.rgb, subsurface * (1.0 - metallic));
-
- float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
-
- /* set the viewing vector */
- vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0);
-
- /* get the tangent */
- vec3 Tangent = T;
- if (T == vec3(0.0)) {
- // if no tangent is set, use a default tangent
- if(N.x != N.y || N.x != N.z) {
- Tangent = vec3(N.z-N.y, N.x-N.z, N.y-N.x); // (1,1,1) x N
- }
- else {
- Tangent = vec3(N.z-N.y, N.x+N.z, -N.y-N.x); // (-1,1,1) x N
- }
- }
-
- /* rotate tangent */
- if (anisotropic_rotation != 0.0) {
- Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI);
- }
-
- /* calculate the tangent and bitangent */
- vec3 Y = normalize(cross(N, Tangent));
- vec3 X = cross(Y, N);
-
- /* fresnel normalization parameters */
- float F0 = fresnel_dielectric_0(eta);
- float F0_norm = 1.0 / (1.0 - F0);
-
- /* directional lights */
- for (int i = 0; i < NUM_LIGHTS; i++) {
- vec3 light_position_world = gl_LightSource[i].position.xyz;
- vec3 light_position = normalize(light_position_world);
-
- vec3 H = normalize(light_position + V);
-
- vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
- vec3 light_specular = gl_LightSource[i].specular.rgb;
-
- float NdotL = dot(N, light_position);
- float NdotV = dot(N, V);
- float LdotH = dot(light_position, H);
-
- vec3 diffuse_and_specular_bsdf = vec3(0.0);
- if (NdotL >= 0.0 && NdotV >= 0.0) {
- float NdotH = dot(N, H);
+ N = normalize(N);
+ vec3 out_refr;
+ color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
+ eevee_closure_refraction(N, roughness, ior, out_refr);
+ vec3 vN = mat3(ViewMatrix) * N;
+ result = CLOSURE_DEFAULT;
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.radiance = out_refr * color.rgb;
+ result.ssr_id = REFRACT_CLOSURE_FLAG;
+}
- float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx.
+void node_ambient_occlusion(vec4 color, float distance, vec3 normal, out vec4 result_color, out float result_ao)
+{
+ vec3 bent_normal;
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal);
+ result_color = result_ao * color;
+}
- vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat
- vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic);
- vec3 Csheen = mix(vec3(1.0), Ctint, sheen_tint);
+#endif /* VOLUMETRICS */
- // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
- // and mix in diffuse retro-reflection based on roughness
+/* emission */
- float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV);
- float Fd90 = 0.5 + 2.0 * LdotH*LdotH * roughness;
- float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);
+void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
+{
+#ifndef VOLUMETRICS
+ color *= strength;
+ result = CLOSURE_DEFAULT;
+ result.radiance = color.rgb;
+ result.opacity = color.a;
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+#else
+ result = Closure(vec3(0.0), vec3(0.0), color.rgb * strength, 0.0);
+#endif
+}
- // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
- // 1.25 scale is used to (roughly) preserve albedo
- // Fss90 used to "flatten" retroreflection based on roughness
- float Fss90 = LdotH*LdotH * roughness;
- float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV);
- float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5);
+void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac)
+{
+ vec3 barys = barycentric.xyy;
+ barys.z = 1.0 - barycentric.x - barycentric.y;
- // specular
- float aspect = sqrt(1.0 - anisotropic * 0.9);
- float a = sqr(roughness);
- float ax = max(0.001, a / aspect);
- float ay = max(0.001, a * aspect);
- float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a);
- float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm;
- vec3 Fs = mix(Cspec0, vec3(1.0), FH);
- float roughg = sqr(roughness * 0.5 + 0.5);
- float Gs = smithG_GGX(NdotL, roughg) * smithG_GGX(NdotV, roughg);
+ size *= 0.5;
+ vec3 s = step(-size, -barys * barycentric_dist);
- // sheen
- vec3 Fsheen = schlick_fresnel(LdotH) * sheen * Csheen;
+ fac = max(s.x, max(s.y, s.z));
+}
- vec3 diffuse_bsdf = (mix(Fd * base_color.rgb, ss * subsurface_color.rgb, subsurface) + Fsheen) * light_diffuse;
- vec3 specular_bsdf = Gs * Fs * Ds * light_specular;
- diffuse_and_specular_bsdf = diffuse_bsdf * (1.0 - metallic) + specular_bsdf;
- }
- diffuse_and_specular_bsdf *= max(NdotL, 0.0);
+void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
+{
+ vec3 barys = barycentric.xyy;
+ barys.z = 1.0 - barycentric.x - barycentric.y;
- float CNdotL = dot(CN, light_position);
- float CNdotV = dot(CN, V);
+ size *= (1.0 / 3.0);
+ vec3 dx = dFdx(barys);
+ vec3 dy = dFdy(barys);
+ vec3 deltas = sqrt(dx * dx + dy * dy);
- vec3 clearcoat_bsdf = vec3(0.0);
- if (CNdotL >= 0.0 && CNdotV >= 0.0 && clearcoat > 0.0) {
- float CNdotH = dot(CN, H);
- //float FH = schlick_fresnel(LdotH);
+ vec3 s = step(-deltas * size, -barys);
- // clearcoat (ior = 1.5 -> F0 = 0.04)
- float Dr = GTR1(CNdotH, sqr(clearcoat_roughness));
- float Fr = fresnel_dielectric_cos(LdotH, 1.5); //mix(0.04, 1.0, FH);
- float Gr = smithG_GGX(CNdotL, 0.25) * smithG_GGX(CNdotV, 0.25);
+ fac = max(s.x, max(s.y, s.z));
+}
- clearcoat_bsdf = clearcoat * Gr * Fr * Dr * vec3(0.25) * light_specular;
- }
- clearcoat_bsdf *= max(CNdotL, 0.0);
+/* background */
- L += diffuse_and_specular_bsdf + clearcoat_bsdf;
- }
+void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec)
+{
+#ifdef MESH_SHADER
+ worldvec = worldPosition;
+#else
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
- result = vec4(L, 1.0);
+ vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
+# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ worldvec = (ViewMatrixInverse * co).xyz;
+# else
+ worldvec = (ModelViewMatrixInverse * co).xyz;
+# endif
+#endif
}
-void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
+void node_background(vec4 color, float strength, out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
+#ifndef VOLUMETRICS
+ color *= strength;
+ result = CLOSURE_DEFAULT;
+ result.radiance = color.rgb;
+ result.opacity = color.a;
+#else
+ result = CLOSURE_DEFAULT;
+#endif
}
-void node_bsdf_transparent(vec4 color, out vec4 result)
-{
- /* this isn't right */
- result.r = color.r;
- result.g = color.g;
- result.b = color.b;
- result.a = 0.0;
-}
+/* volumes */
-void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result)
+void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
+#ifdef VOLUMETRICS
+ result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
}
-void node_subsurface_scattering(
- vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N,
- out vec4 result)
+void node_volume_absorption(vec4 color, float density, out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
+#ifdef VOLUMETRICS
+ result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
}
-void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out vec4 result)
+void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, out vec4 color)
{
- result = color;
+ if (temperature >= 12000.0) {
+ color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0);
+ }
+ else if (temperature < 965.0) {
+ color = vec4(4.70366907, 0.0, 0.0, 1.0);
+ }
+ else {
+ float t = (temperature - 965.0) / (12000.0 - 965.0);
+ color = vec4(texture(spectrummap, vec2(t, layer)).rgb, 1.0);
+ }
}
-void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
+void node_volume_principled(
+ vec4 color,
+ float density,
+ float anisotropy,
+ vec4 absorption_color,
+ float emission_strength,
+ vec4 emission_color,
+ float blackbody_intensity,
+ vec4 blackbody_tint,
+ float temperature,
+ float density_attribute,
+ vec4 color_attribute,
+ float temperature_attribute,
+ sampler1DArray spectrummap,
+ float layer,
+ out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
-}
+#ifdef VOLUMETRICS
+ vec3 absorption_coeff = vec3(0.0);
+ vec3 scatter_coeff = vec3(0.0);
+ vec3 emission_coeff = vec3(0.0);
-void node_ambient_occlusion(vec4 color, float distance, vec3 normal, out vec4 result_color, out float result_ao)
-{
- result_color = color;
- result_ao = 1.0;
-}
+ /* Compute density. */
+ density = max(density, 0.0);
-/* emission */
+ if(density > 1e-5) {
+ density = max(density * density_attribute, 0.0);
+ }
-void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
-{
- result = color * strength;
-}
+ if(density > 1e-5) {
+ /* Compute scattering and absorption coefficients. */
+ vec3 scatter_color = color.rgb * color_attribute.rgb;
-/* background */
+ scatter_coeff = scatter_color * density;
+ absorption_color.rgb = sqrt(max(absorption_color.rgb, 0.0));
+ absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color.rgb, 0.0) * density;
+ }
-void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
-{
- vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
+ /* Compute emission. */
+ emission_strength = max(emission_strength, 0.0);
- vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
- worldvec = (gl_ModelViewMatrixInverse * co).xyz;
-}
+ if(emission_strength > 1e-5) {
+ emission_coeff += emission_strength * emission_color.rgb;
+ }
-void node_background(vec4 color, float strength, vec3 N, out vec4 result)
-{
- result = color * strength;
+ if(blackbody_intensity > 1e-3) {
+ /* Add temperature from attribute. */
+ float T = max(temperature * max(temperature_attribute, 0.0), 0.0);
+
+ /* Stefan-Boltzman law. */
+ float T4 = (T * T) * (T * T);
+ float sigma = 5.670373e-8 * 1e-6 / M_PI;
+ float intensity = sigma * mix(1.0, T4, blackbody_intensity);
+
+ if(intensity > 1e-5) {
+ vec4 bb;
+ node_blackbody(T, spectrummap, layer, bb);
+ emission_coeff += bb.rgb * blackbody_tint.rgb * intensity;
+ }
+ }
+
+ result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy);
+#else
+ result = CLOSURE_DEFAULT;
+#endif
}
/* closures */
-void node_mix_shader(float fac, vec4 shader1, vec4 shader2, out vec4 shader)
+void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
{
- shader = mix(shader1, shader2, fac);
+ shader = closure_mix(shader1, shader2, fac);
}
-void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
+void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
{
- shader = shader1 + shader2;
+ shader = closure_add(shader1, shader2);
}
/* fresnel */
void node_fresnel(float ior, vec3 N, vec3 I, out float result)
{
+ N = normalize(N);
/* handle perspective/orthographic */
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
float eta = max(ior, 0.00001);
result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
@@ -2864,9 +1623,11 @@ void node_fresnel(float ior, vec3 N, vec3 I, out float result)
void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float facing)
{
+ N = normalize(N);
+
/* fresnel */
float eta = max(1.0 - blend, 0.00001);
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
@@ -2896,11 +1657,67 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol)
/* geometry */
+void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ outvec = texture(tex, cos).aaa;
+ outcol = vec4(outvec, 1.0);
+ outf = dot(vec3(1.0 / 3.0), outvec);
+}
+
+void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+
+ vec4 value = texture(tex, cos).rgba;
+ /* Density is premultiplied for interpolation, divide it out here. */
+ if (value.a > 1e-8)
+ value.rgb /= value.a;
+
+ outvec = value.rgb;
+ outcol = vec4(outvec, 1.0);
+ outf = dot(vec3(1.0 / 3.0), outvec);
+}
+
+void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ outf = texture(tex, cos).r;
+ outvec = vec3(outf, outf, outf);
+ outcol = vec4(outf, outf, outf, 1.0);
+}
+
+void node_attribute_volume_temperature(sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 cos = volumeObjectLocalCoord;
+#else
+ vec3 cos = vec3(0.0);
+#endif
+ float flame = texture(tex, cos).r;
+
+ outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x): 0.0;
+ outvec = vec3(outf, outf, outf);
+ outcol = vec4(outf, outf, outf, 1.0);
+}
+
void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
{
outcol = vec4(attr, 1.0);
outvec = attr;
- outf = (attr.x + attr.y + attr.z) / 3.0;
+ outf = dot(vec3(1.0 / 3.0), attr);
}
void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -2908,24 +1725,87 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec)
outvec = attr_uv;
}
+void tangent_orco_x(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.xzy * vec3(0.0, -0.5, 0.5) + vec3(0.0, 0.25, -0.25);
+}
+
+void tangent_orco_y(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.zyx * vec3(-0.5, 0.0, 0.5) + vec3(0.25, 0.0, -0.25);
+}
+
+void tangent_orco_z(vec3 orco_in, out vec3 orco_out)
+{
+ orco_out = orco_in.yxz * vec3(-0.5, 0.5, 0.0) + vec3(0.25, -0.25, 0.0);
+}
+
+void node_tangentmap(vec4 attr_tangent, mat4 toworld, out vec3 tangent)
+{
+ tangent = (toworld * vec4(attr_tangent.xyz, 0.0)).xyz;
+}
+
+void node_tangent(vec3 N, vec3 orco, mat4 objmat, mat4 toworld, out vec3 T)
+{
+#ifndef VOLUMETRICS
+ N = normalize(worldNormal);
+#else
+ N = (toworld * vec4(N, 0.0)).xyz;
+#endif
+ T = (objmat * vec4(orco, 0.0)).xyz;
+ T = cross(N, normalize(cross(T, N)));
+}
+
void node_geometry(
- vec3 I, vec3 N, mat4 toworld,
+ vec3 I, vec3 N, vec3 orco, mat4 objmat, mat4 toworld, vec2 barycentric,
out vec3 position, out vec3 normal, out vec3 tangent,
out vec3 true_normal, out vec3 incoming, out vec3 parametric,
out float backfacing, out float pointiness)
{
- position = (toworld * vec4(I, 1.0)).xyz;
- normal = (toworld * vec4(N, 0.0)).xyz;
- tangent = vec3(0.0);
- true_normal = normal;
-
/* handle perspective/orthographic */
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
incoming = -(toworld * vec4(I_view, 0.0)).xyz;
- parametric = vec3(0.0);
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ position = -incoming;
+ true_normal = normal = incoming;
+ tangent = parametric = vec3(0.0);
+ vec3(0.0);
+ backfacing = 0.0;
+ pointiness = 0.0;
+#else
+
+ position = worldPosition;
+# ifndef VOLUMETRICS
+ normal = normalize(worldNormal);
+
+ vec3 B = dFdx(worldPosition);
+ vec3 T = dFdy(worldPosition);
+ true_normal = normalize(cross(B, T));
+# else
+ normal = (toworld * vec4(N, 0.0)).xyz;
+ true_normal = normal;
+# endif
+ tangent_orco_z(orco, orco);
+ node_tangent(N, orco, objmat, toworld, tangent);
+
+ parametric = vec3(barycentric, 0.0);
backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
pointiness = 0.5;
+#endif
+}
+
+void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated)
+{
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
+ vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
+ co.xyz = normalize(co.xyz);
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ generated = (ViewMatrixInverse * co).xyz;
+#else
+ generated_from_orco(attr_orco, generated);
+#endif
}
void node_tex_coord(
@@ -2934,16 +1814,15 @@ void node_tex_coord(
out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
out vec3 camera, out vec3 window, out vec3 reflection)
{
- generated = attr_orco * 0.5 + vec3(0.5);
+ generated = attr_orco;
normal = normalize((obinvmat * (viewinvmat * vec4(N, 0.0))).xyz);
uv = attr_uv;
object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz;
camera = vec3(I.xy, -I.z);
- vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0);
+ vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
- vec3 shade_I;
- shade_view(I, shade_I);
+ vec3 shade_I = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
vec3 view_reflection = reflect(shade_I, normalize(N));
reflection = (viewinvmat * vec4(view_reflection, 0.0)).xyz;
}
@@ -2954,13 +1833,18 @@ void node_tex_coord_background(
out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
out vec3 camera, out vec3 window, out vec3 reflection)
{
- vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
+ vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+ vec4 co_homogenous = (ProjectionMatrixInverse * v);
vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
co = normalize(co);
- vec3 coords = (gl_ModelViewMatrixInverse * co).xyz;
+
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ vec3 coords = (ViewMatrixInverse * co).xyz;
+#else
+ vec3 coords = (ModelViewMatrixInverse * co).xyz;
+#endif
generated = coords;
normal = -coords;
@@ -2968,13 +1852,17 @@ void node_tex_coord_background(
object = coords;
camera = vec3(co.xy, -co.z);
- window = (gl_ProjectionMatrix[3][3] == 0.0) ?
+ window = (ProjectionMatrix[3][3] == 0.0) ?
vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
reflection = -coords;
}
+#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
+#define node_tex_coord node_tex_coord_background
+#endif
+
/* textures */
float calc_gradient(vec3 p, int gradient_type)
@@ -3030,9 +1918,7 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c
vec3 p = co * scale;
/* Prevent precision issues on unit coordinates. */
- p.x = (p.x + 0.000001) * 0.999999;
- p.y = (p.y + 0.000001) * 0.999999;
- p.z = (p.z + 0.000001) * 0.999999;
+ p = (p + 0.000001) * 0.999999;
int xi = int(abs(floor(p.x)));
int yi = int(abs(floor(p.y)));
@@ -3044,7 +1930,6 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c
fac = check ? 1.0 : 0.0;
}
-#ifdef BIT_OPERATIONS
vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bias,
float brick_width, float row_height,
float offset_amount, int offset_frequency,
@@ -3080,7 +1965,6 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bi
return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
}
}
-#endif
void node_tex_brick(vec3 co,
vec4 color1, vec4 color2,
@@ -3091,7 +1975,6 @@ void node_tex_brick(vec3 co,
float squash_amount, float squash_frequency,
out vec4 color, out float fac)
{
-#ifdef BIT_OPERATIONS
vec2 f2 = calc_brick_texture(co * scale,
mortar_size, mortar_smooth, bias,
brick_width, row_height,
@@ -3105,10 +1988,6 @@ void node_tex_brick(vec3 co,
}
color = mix(color1, mortar, f);
fac = f;
-#else
- color = vec4(1.0);
- fac = 1.0;
-#endif
}
void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
@@ -3117,29 +1996,27 @@ void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
fac = 1.0;
}
-void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color)
+void node_tex_environment_equirectangular(vec3 co, float clamp_size, sampler2D ima, out vec3 uv)
{
vec3 nco = normalize(co);
- float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
- float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
+ uv.x = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
+ uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
- color = texture2D(ima, vec2(u, v));
+ /* Fix pole bleeding */
+ float half_height = clamp_size / float(textureSize(ima, 0).y);
+ uv.y = clamp(uv.y, half_height, 1.0 - half_height);
+ uv.z = 0.0;
}
-void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
+void node_tex_environment_mirror_ball(vec3 co, out vec3 uv)
{
vec3 nco = normalize(co);
-
nco.y -= 1.0;
float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0));
- if (div > 0.0)
- nco /= div;
-
- float u = 0.5 * (nco.x + 1.0);
- float v = 0.5 * (nco.z + 1.0);
+ nco /= max(1e-8, div);
- color = texture2D(ima, vec2(u, v));
+ uv = 0.5 * nco.xzz + 0.5;
}
void node_tex_environment_empty(vec3 co, out vec4 color)
@@ -3147,24 +2024,217 @@ void node_tex_environment_empty(vec3 co, out vec4 color)
color = vec4(1.0, 0.0, 1.0, 1.0);
}
-void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ color = texture(ima, co.xy);
+ alpha = color.a;
+}
+
+void node_tex_image_linear_no_mip(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ color = textureLod(ima, co.xy, 0.0);
+ alpha = color.a;
+}
+
+void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float alpha)
{
- color = texture2D(ima, co.xy);
+ ivec2 pix = ivec2(fract(co.xy) * textureSize(ima, 0).xy);
+ color = texelFetch(ima, pix, 0);
alpha = color.a;
}
+/* @arg f: signed distance to texel center. */
+void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3)
+{
+ vec2 f2 = f * f;
+ vec2 f3 = f2 * f;
+ /* Bspline coefs (optimized) */
+ w3 = f3 / 6.0;
+ w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0;
+ w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0;
+ w2 = 1.0 - w0 - w1 - w3;
+}
+
+void node_tex_image_cubic_ex(vec3 co, sampler2D ima, float do_extend, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+
+ co.xy *= tex_size;
+ /* texel center */
+ vec2 tc = floor(co.xy - 0.5) + 0.5;
+ vec2 w0, w1, w2, w3;
+ cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
+
+#if 1 /* Optimized version using 4 filtered tap. */
+ vec2 s0 = w0 + w1;
+ vec2 s1 = w2 + w3;
+
+ vec2 f0 = w1 / (w0 + w1);
+ vec2 f1 = w3 / (w2 + w3);
+
+ vec4 final_co;
+ final_co.xy = tc - 1.0 + f0;
+ final_co.zw = tc + 1.0 + f1;
+
+ if (do_extend == 1.0) {
+ final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5);
+ }
+ final_co /= tex_size.xyxy;
+
+ color = textureLod(ima, final_co.xy, 0.0) * s0.x * s0.y;
+ color += textureLod(ima, final_co.zy, 0.0) * s1.x * s0.y;
+ color += textureLod(ima, final_co.xw, 0.0) * s0.x * s1.y;
+ color += textureLod(ima, final_co.zw, 0.0) * s1.x * s1.y;
+
+#else /* Reference bruteforce 16 tap. */
+ color = texelFetch(ima, ivec2(tc + vec2(-1.0, -1.0)), 0) * w0.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 0.0, -1.0)), 0) * w1.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 1.0, -1.0)), 0) * w2.x * w0.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 2.0, -1.0)), 0) * w3.x * w0.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 0.0)), 0) * w0.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 0.0, 0.0)), 0) * w1.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 1.0, 0.0)), 0) * w2.x * w1.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 2.0, 0.0)), 0) * w3.x * w1.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 1.0)), 0) * w0.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 0.0, 1.0)), 0) * w1.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 1.0, 1.0)), 0) * w2.x * w2.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 2.0, 1.0)), 0) * w3.x * w2.y;
+
+ color += texelFetch(ima, ivec2(tc + vec2(-1.0, 2.0)), 0) * w0.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 0.0, 2.0)), 0) * w1.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 1.0, 2.0)), 0) * w2.x * w3.y;
+ color += texelFetch(ima, ivec2(tc + vec2( 2.0, 2.0)), 0) * w3.x * w3.y;
+#endif
+
+ alpha = color.a;
+}
+
+void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
+}
+
+void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ node_tex_image_cubic_ex(co, ima, 1.0, color, alpha);
+}
+
+void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha)
+{
+ /* use cubic for now */
+ node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
+}
+
+void tex_box_sample_linear(vec3 texco,
+ vec3 N,
+ sampler2D ima,
+ out vec4 color1,
+ out vec4 color2,
+ out vec4 color3)
+{
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color1 = texture(ima, uv);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color2 = texture(ima, uv);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ color3 = texture(ima, uv);
+}
+
+void tex_box_sample_nearest(vec3 texco,
+ vec3 N,
+ sampler2D ima,
+ out vec4 color1,
+ out vec4 color2,
+ out vec4 color3)
+{
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ ivec2 pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color1 = texelFetch(ima, pix, 0);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color2 = texelFetch(ima, pix, 0);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ pix = ivec2(uv.xy * textureSize(ima, 0).xy);
+ color3 = texelFetch(ima, pix, 0);
+}
+
+void tex_box_sample_cubic(vec3 texco,
+ vec3 N,
+ sampler2D ima,
+ out vec4 color1,
+ out vec4 color2,
+ out vec4 color3)
+{
+ float alpha;
+ /* X projection */
+ vec2 uv = texco.yz;
+ if (N.x < 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha);
+ /* Y projection */
+ uv = texco.xz;
+ if (N.y > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha);
+ /* Z projection */
+ uv = texco.yx;
+ if (N.z > 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+ node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha);
+}
+
+void tex_box_sample_smart(vec3 texco,
+ vec3 N,
+ sampler2D ima,
+ out vec4 color1,
+ out vec4 color2,
+ out vec4 color3)
+{
+ tex_box_sample_cubic(texco, N, ima, color1, color2, color3);
+}
+
void node_tex_image_box(vec3 texco,
vec3 N,
+ vec4 color1,
+ vec4 color2,
+ vec4 color3,
sampler2D ima,
float blend,
out vec4 color,
out float alpha)
{
- vec3 signed_N = N;
-
/* project from direction vector to barycentric coordinates in triangles */
- N = vec3(abs(N.x), abs(N.y), abs(N.z));
- N /= (N.x + N.y + N.z);
+ N = abs(N);
+ N /= dot(N, vec3(1.0));
/* basic idea is to think of this as a triangle, each corner representing
* one of the 3 faces of the cube. in the corners we have single textures,
@@ -3174,75 +2244,100 @@ void node_tex_image_box(vec3 texco,
* the Nxyz values are the barycentric coordinates in an equilateral
* triangle, which in case of blending, in the middle has a smaller
* equilateral triangle where 3 textures blend. this divides things into
- * 7 zones, with an if () test for each zone */
+ * 7 zones, with an if () test for each zone
+ * EDIT: Now there is only 4 if's. */
- vec3 weight = vec3(0.0, 0.0, 0.0);
- float limit = 0.5 * (1.0 + blend);
+ float limit = 0.5 + 0.5 * blend;
- /* first test for corners with single texture */
- if (N.x > limit * (N.x + N.y) && N.x > limit * (N.x + N.z)) {
- weight.x = 1.0;
- }
- else if (N.y > limit * (N.x + N.y) && N.y > limit * (N.y + N.z)) {
- weight.y = 1.0;
+ vec3 weight;
+ weight = N.xyz / (N.xyx + N.yzz);
+ weight = clamp((weight - 0.5 * (1.0 - blend)) / max(1e-8, blend), 0.0, 1.0);
+
+ /* test for mixes between two textures */
+ if (N.z < (1.0 - limit) * (N.y + N.x)) {
+ weight.z = 0.0;
+ weight.y = 1.0 - weight.x;
}
- else if (N.z > limit * (N.x + N.z) && N.z > limit * (N.y + N.z)) {
- weight.z = 1.0;
+ else if (N.x < (1.0 - limit) * (N.y + N.z)) {
+ weight.x = 0.0;
+ weight.z = 1.0 - weight.y;
}
- else if (blend > 0.0) {
- /* in case of blending, test for mixes between two textures */
- if (N.z < (1.0 - limit) * (N.y + N.x)) {
- weight.x = N.x / (N.x + N.y);
- weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
- weight.y = 1.0 - weight.x;
- }
- else if (N.x < (1.0 - limit) * (N.y + N.z)) {
- weight.y = N.y / (N.y + N.z);
- weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
- weight.z = 1.0 - weight.y;
- }
- else if (N.y < (1.0 - limit) * (N.x + N.z)) {
- weight.x = N.x / (N.x + N.z);
- weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
- weight.z = 1.0 - weight.x;
- }
- else {
- /* last case, we have a mix between three */
- weight.x = ((2.0 - limit) * N.x + (limit - 1.0)) / (2.0 * limit - 1.0);
- weight.y = ((2.0 - limit) * N.y + (limit - 1.0)) / (2.0 * limit - 1.0);
- weight.z = ((2.0 - limit) * N.z + (limit - 1.0)) / (2.0 * limit - 1.0);
- }
+ else if (N.y < (1.0 - limit) * (N.x + N.z)) {
+ weight.y = 0.0;
+ weight.x = 1.0 - weight.z;
}
else {
- /* Desperate mode, no valid choice anyway, fallback to one side.*/
- weight.x = 1.0;
- }
- color = vec4(0);
- if (weight.x > 0.0) {
- vec2 uv = texco.yz;
- if(signed_N.x < 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color += weight.x * texture2D(ima, uv);
- }
- if (weight.y > 0.0) {
- vec2 uv = texco.xz;
- if(signed_N.y > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color += weight.y * texture2D(ima, uv);
- }
- if (weight.z > 0.0) {
- vec2 uv = texco.yx;
- if(signed_N.z > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- color += weight.z * texture2D(ima, uv);
+ /* last case, we have a mix between three */
+ weight = ((2.0 - limit) * N + (limit - 1.0)) / max(1e-8, 2.0 * limit - 1.0);
}
+ color = weight.x * color1 + weight.y * color2 + weight.z * color3;
+ alpha = color.a;
+}
+
+void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+ vec2 minco = min(co.xy, 1.0 - co.xy);
+ minco = clamp(minco * tex_size + 0.5, 0.0, 1.0);
+ float fac = minco.x * minco.y;
+
+ color = mix(vec4(0.0), icolor, fac);
+ alpha = color.a;
+}
+
+void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec4 minco = vec4(co.xy, 1.0 - co.xy);
+ color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor;
+ alpha = color.a;
+}
+
+void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ vec2 tex_size = vec2(textureSize(ima, 0).xy);
+
+ co.xy *= tex_size;
+ /* texel center */
+ vec2 tc = floor(co.xy - 0.5) + 0.5;
+ vec2 w0, w1, w2, w3;
+ cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
+
+ /* TODO Optimize this part. I'm sure there is a smarter way to do that.
+ * Could do that when sampling? */
+#define CLIP_CUBIC_SAMPLE(samp, size) (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size))))
+ ivec2 itex_size = textureSize(ima, 0).xy;
+ float fac;
+ fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 0.0, -1.0), itex_size) * w1.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 1.0, -1.0), itex_size) * w2.x * w0.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 2.0, -1.0), itex_size) * w3.x * w0.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 0.0, 0.0), itex_size) * w1.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 1.0, 0.0), itex_size) * w2.x * w1.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 2.0, 0.0), itex_size) * w3.x * w1.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 0.0, 1.0), itex_size) * w1.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 1.0, 1.0), itex_size) * w2.x * w2.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 2.0, 1.0), itex_size) * w3.x * w2.y;
+
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 0.0, 2.0), itex_size) * w1.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 1.0, 2.0), itex_size) * w2.x * w3.y;
+ fac += CLIP_CUBIC_SAMPLE(tc + vec2( 2.0, 2.0), itex_size) * w3.x * w3.y;
+#undef CLIP_CUBIC_SAMPLE
+
+ color = mix(vec4(0.0), icolor, fac);
alpha = color.a;
}
+void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
+{
+ tex_clip_cubic(co, ima, icolor, color, alpha);
+}
+
void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
{
color = vec4(0.0);
@@ -3310,7 +2405,6 @@ void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec
fac = (color.x + color.y + color.z) / 3.0;
}
-#ifdef BIT_OPERATIONS
float noise_fade(float t)
{
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
@@ -3385,10 +2479,9 @@ float noise_turbulence(vec3 p, float octaves, int hard)
float fscale = 1.0;
float amp = 1.0;
float sum = 0.0;
- int i, n;
octaves = clamp(octaves, 0.0, 16.0);
- n = int(octaves);
- for (i = 0; i <= n; i++) {
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
if (hard != 0) {
t = abs(2.0 * t - 1.0);
@@ -3398,7 +2491,7 @@ float noise_turbulence(vec3 p, float octaves, int hard)
fscale *= 2.0;
}
float rmd = octaves - floor(octaves);
- if (rmd != 0.0) {
+ if (rmd != 0.0) {
float t = noise(fscale * p);
if (hard != 0) {
t = abs(2.0 * t - 1.0);
@@ -3413,11 +2506,9 @@ float noise_turbulence(vec3 p, float octaves, int hard)
return sum;
}
}
-#endif // BIT_OPERATIONS
void node_tex_noise(vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac)
{
-#ifdef BIT_OPERATIONS
vec3 p = co * scale;
int hard = 0;
if (distortion != 0.0) {
@@ -3433,15 +2524,8 @@ void node_tex_noise(vec3 co, float scale, float detail, float distortion, out ve
noise_turbulence(vec3(p.y, p.x, p.z), detail, hard),
noise_turbulence(vec3(p.y, p.z, p.x), detail, hard),
1);
-#else // BIT_OPERATIONS
- color = vec4(1.0);
- fac = 1.0;
-#endif // BIT_OPERATIONS
}
-
-#ifdef BIT_OPERATIONS
-
/* Musgrave fBm
*
* H: fractal increment parameter
@@ -3457,9 +2541,8 @@ float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
float value = 0.0;
float pwr = 1.0;
float pwHL = pow(lacunarity, -H);
- int i;
- for (i = 0; i < int(octaves); i++) {
+ for (int i = 0; i < int(octaves); i++) {
value += snoise(p) * pwr;
pwr *= pwHL;
p *= lacunarity;
@@ -3485,9 +2568,8 @@ float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octa
float value = 1.0;
float pwr = 1.0;
float pwHL = pow(lacunarity, -H);
- int i;
- for (i = 0; i < int(octaves); i++) {
+ for (int i = 0; i < int(octaves); i++) {
value *= (pwr * snoise(p) + 1.0);
pwr *= pwHL;
p *= lacunarity;
@@ -3513,13 +2595,12 @@ float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float oct
float value, increment, rmd;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
/* first unscaled octave of function; later octaves are scaled */
value = offset + snoise(p);
p *= lacunarity;
- for (i = 1; i < int(octaves); i++) {
+ for (int i = 1; i < int(octaves); i++) {
increment = (snoise(p) + offset) * pwr * value;
value += increment;
pwr *= pwHL;
@@ -3548,13 +2629,12 @@ float noise_musgrave_hybrid_multi_fractal(vec3 p, float H, float lacunarity, flo
float result, signal, weight, rmd;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
result = snoise(p) + offset;
weight = gain * result;
p *= lacunarity;
- for (i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
if (weight > 1.0)
weight = 1.0;
@@ -3585,14 +2665,13 @@ float noise_musgrave_ridged_multi_fractal(vec3 p, float H, float lacunarity, flo
float result, signal, weight;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
signal = offset - abs(snoise(p));
signal *= signal;
result = signal;
weight = 1.0;
- for (i = 1; i < int(octaves); i++) {
+ for (int i = 1; i < int(octaves); i++) {
p *= lacunarity;
weight = clamp(signal * gain, 0.0, 1.0);
signal = offset - abs(snoise(p));
@@ -3614,19 +2693,18 @@ float svm_musgrave(int type,
float gain,
vec3 p)
{
- if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/)
+ if (type == 0 /* NODE_MUSGRAVE_MULTIFRACTAL */)
return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- else if (type == 1 /*NODE_MUSGRAVE_FBM*/)
+ else if (type == 1 /* NODE_MUSGRAVE_FBM */)
return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/)
+ else if (type == 2 /* NODE_MUSGRAVE_HYBRID_MULTIFRACTAL */)
return intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/)
+ else if (type == 3 /* NODE_MUSGRAVE_RIDGED_MULTIFRACTAL */)
return intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/)
+ else if (type == 4 /* NODE_MUSGRAVE_HETERO_TERRAIN */)
return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
return 0.0;
}
-#endif // #ifdef BIT_OPERATIONS
void node_tex_musgrave(vec3 co,
float scale,
@@ -3639,7 +2717,6 @@ void node_tex_musgrave(vec3 co,
out vec4 color,
out float fac)
{
-#ifdef BIT_OPERATIONS
fac = svm_musgrave(int(type),
dimension,
lacunarity,
@@ -3648,9 +2725,6 @@ void node_tex_musgrave(vec3 co,
1.0,
gain,
co * scale);
-#else
- fac = 1.0;
-#endif
color = vec4(fac, fac, fac, 1.0);
}
@@ -3660,9 +2734,8 @@ void node_tex_sky(vec3 co, out vec4 color)
color = vec4(1.0);
}
-void node_tex_voronoi(vec3 co, float scale, float exponent, float coloring, out vec4 color, out float fac)
+void node_tex_voronoi(vec3 co, float scale, float exponent, float coloring, float metric, float feature, out vec4 color, out float fac)
{
-#ifdef BIT_OPERATIONS
vec3 p = co * scale;
int xx, yy, zz, xi, yi, zi;
float da[4];
@@ -3683,7 +2756,21 @@ void node_tex_voronoi(vec3 co, float scale, float exponent, float coloring, out
vec3 ip = vec3(xx, yy, zz);
vec3 vp = cellnoise_color(ip);
vec3 pd = p - (vp + ip);
- float d = dot(pd, pd);
+
+ float d = 0.0;
+ if (metric == 0) { /* SHD_VORONOI_DISTANCE 0 */
+ d = dot(pd, pd);
+ }
+ else if (metric == 1) { /* SHD_VORONOI_MANHATTAN 1 */
+ d = abs(pd[0]) + abs(pd[1]) + abs(pd[2]);
+ }
+ else if (metric == 2) { /* SHD_VORONOI_CHEBYCHEV 2 */
+ d = max(abs(pd[0]), max(abs(pd[1]), abs(pd[2])));
+ }
+ else if (metric == 3) { /* SHD_VORONOI_MINKOWSKI 3 */
+ d = pow(pow(abs(pd[0]), exponent) + pow(abs(pd[1]), exponent) + pow(abs(pd[2]), exponent), 1.0/exponent);
+ }
+
vp += vec3(xx, yy, zz);
if (d < da[0]) {
da[3] = da[2];
@@ -3720,20 +2807,48 @@ void node_tex_voronoi(vec3 co, float scale, float exponent, float coloring, out
}
if (coloring == 0.0) {
- fac = abs(da[0]);
+ /* Intensity output */
+ if (feature == 0) { /* F1 */
+ fac = abs(da[0]);
+ }
+ else if (feature == 1) { /* F2 */
+ fac = abs(da[1]);
+ }
+ else if (feature == 2) { /* F3 */
+ fac = abs(da[2]);
+ }
+ else if (feature == 3) { /* F4 */
+ fac = abs(da[3]);
+ }
+ else if (feature == 4) { /* F2F1 */
+ fac = abs(da[1] - da[0]);
+ }
color = vec4(fac, fac, fac, 1);
}
else {
- color = vec4(cellnoise_color(pa[0]), 1);
+ /* Color output */
+ vec3 col = vec3(fac, fac, fac);
+ if (feature == 0) { /* F1 */
+ col = pa[0];
+ }
+ else if (feature == 1) { /* F2 */
+ col = pa[1];
+ }
+ else if (feature == 2) { /* F3 */
+ col = pa[2];
+ }
+ else if (feature == 3) { /* F4 */
+ col = pa[3];
+ }
+ else if (feature == 4) { /* F2F1 */
+ col = abs(pa[1] - pa[0]);
+ }
+
+ color = vec4(cellnoise_color(col), 1);
fac = (color.x + color.y + color.z) * (1.0 / 3.0);
}
-#else // BIT_OPERATIONS
- color = vec4(1.0);
- fac = 1.0;
-#endif // BIT_OPERATIONS
}
-#ifdef BIT_OPERATIONS
float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
{
float n;
@@ -3755,22 +2870,16 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int
return (n < 0.0) ? n + 1.0 : n;
}
}
-#endif // BIT_OPERATIONS
void node_tex_wave(
vec3 co, float scale, float distortion, float detail, float detail_scale, float wave_type, float wave_profile,
out vec4 color, out float fac)
{
-#ifdef BIT_OPERATIONS
float f;
f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
color = vec4(f, f, f, 1.0);
fac = f;
-#else // BIT_OPERATIONS
- color = vec4(1.0);
- fac = 1;
-#endif // BIT_OPERATIONS
}
/* light path */
@@ -3790,19 +2899,22 @@ void node_light_path(
out float transparent_depth,
out float transmission_depth)
{
- is_camera_ray = 1.0;
- is_shadow_ray = 0.0;
- is_diffuse_ray = 0.0;
- is_glossy_ray = 0.0;
- is_singular_ray = 0.0;
- is_reflection_ray = 0.0;
- is_transmission_ray = 0.0;
+ /* Supported. */
+ is_camera_ray = (rayType == EEVEE_RAY_CAMERA) ? 1.0 : 0.0;
+ is_shadow_ray = (rayType == EEVEE_RAY_SHADOW) ? 1.0 : 0.0;
+ is_diffuse_ray = (rayType == EEVEE_RAY_DIFFUSE) ? 1.0 : 0.0;
+ is_glossy_ray = (rayType == EEVEE_RAY_GLOSSY) ? 1.0 : 0.0;
+ /* Kind of supported. */
+ is_singular_ray = is_glossy_ray;
+ is_reflection_ray = is_glossy_ray;
+ is_transmission_ray = is_glossy_ray;
+ ray_depth = rayDepth;
+ diffuse_depth = (is_diffuse_ray == 1.0) ? rayDepth : 0.0;
+ glossy_depth = (is_glossy_ray == 1.0) ? rayDepth : 0.0;
+ transmission_depth = (is_transmission_ray == 1.0) ? glossy_depth : 0.0;
+ /* Not supported. */
ray_length = 1.0;
- ray_depth = 1.0;
- diffuse_depth = 1.0;
- glossy_depth = 1.0;
- transparent_depth = 1.0;
- transmission_depth = 1.0;
+ transparent_depth = 0.0;
}
void node_light_falloff(float strength, float tsmooth, out float quadratic, out float linear, out float constant)
@@ -3830,9 +2942,9 @@ void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnorm
void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos, float invert, out vec3 result)
{
- if (invert != 0.0) {
- dist *= -1.0;
- }
+ N = mat3(ViewMatrix) * normalize(N);
+ dist *= invert;
+
vec3 dPdx = dFdx(surf_pos);
vec3 dPdy = dFdy(surf_pos);
@@ -3842,7 +2954,6 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos,
/* Compute surface gradient and determinant. */
float det = dot(dPdx, Rx);
- float absdet = abs(det);
float dHdx = dFdx(height);
float dHdy = dFdy(height);
@@ -3850,8 +2961,10 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos,
strength = max(strength, 0.0);
- result = normalize(absdet * N - dist * sign(det) * surfgrad);
- result = normalize(strength * result + (1.0 - strength) * N);
+ result = normalize(abs(det) * N - dist * sign(det) * surfgrad);
+ result = normalize(mix(N, result, strength));
+
+ result = mat3(ViewMatrixInverse) * result;
}
void node_bevel(float radius, vec3 N, out vec3 result)
@@ -3859,6 +2972,23 @@ void node_bevel(float radius, vec3 N, out vec3 result)
result = N;
}
+void node_hair_info(out float is_strand, out float intercept, out float thickness, out vec3 tangent, out float random)
+{
+#ifdef HAIR_SHADER
+ is_strand = 1.0;
+ intercept = hairTime;
+ thickness = hairThickness;
+ tangent = normalize(hairTangent);
+ random = wang_hash_noise(uint(hairStrandID)); /* TODO: could be precomputed per strand instead. */
+#else
+ is_strand = 0.0;
+ intercept = 0.0;
+ thickness = 0.0;
+ tangent = vec3(1.0);
+ random = 0.0;
+#endif
+}
+
void node_displacement_object(float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result)
{
N = (vec4(N, 0.0) * obmat).xyz;
@@ -3895,37 +3025,91 @@ void node_vector_displacement_world(vec4 vector, float midlevel, float scale, ou
/* output */
-void node_output_material(vec4 surface, vec4 volume, vec3 displacement, out vec4 result)
+void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
{
+#ifdef VOLUMETRICS
+ result = volume;
+#else
result = surface;
+#endif
}
-void node_output_world(vec4 surface, vec4 volume, out vec4 result)
+uniform float backgroundAlpha;
+
+void node_output_world(Closure surface, Closure volume, out Closure result)
{
- result = surface;
+#ifndef VOLUMETRICS
+ result.radiance = surface.radiance;
+ result.opacity = backgroundAlpha;
+#else
+ result = volume;
+#endif /* VOLUMETRICS */
}
-/* ********************** matcap style render ******************** */
-
-void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 result)
+#ifndef VOLUMETRICS
+/* TODO : clean this ifdef mess */
+/* EEVEE output */
+void world_normals_get(out vec3 N)
{
- vec3 normal;
- vec2 tex;
-
-#ifndef USE_OPENSUBDIV
- /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
- * between shader stages and we want the full range of the normal */
- normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0);
- if (normal.z < 0.0) {
- normal.z = 0.0;
+#ifdef HAIR_SHADER
+ vec3 B = normalize(cross(worldNormal, hairTangent));
+ float cos_theta;
+ if (hairThicknessRes == 1) {
+ vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0);
+ /* Random cosine normal distribution on the hair surface. */
+ cos_theta = rand.x * 2.0 - 1.0;
+ }
+ else {
+ /* Shade as a cylinder. */
+ cos_theta = hairThickTime / hairThickness;
}
- normal = normalize(normal);
+ float sin_theta = sqrt(max(0.0, 1.0f - cos_theta*cos_theta));
+ N = normalize(worldNormal * sin_theta + B * cos_theta);
#else
- normal = inpt.v.normal;
- mask = vec4(1.0, 1.0, 1.0, 1.0);
+ N = gl_FrontFacing ? worldNormal : -worldNormal;
#endif
+}
+
+void node_eevee_specular(
+ vec4 diffuse, vec4 specular, float roughness, vec4 emissive, float transp, vec3 normal,
+ float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal,
+ float occlusion, float ssr_id, out Closure result)
+{
+ vec3 out_diff, out_spec, ssr_spec;
+ eevee_closure_default(normal, diffuse.rgb, specular.rgb, int(ssr_id), roughness, occlusion,
+ out_diff, out_spec, ssr_spec);
- tex.x = 0.5 + 0.49 * normal.x;
- tex.y = 0.5 + 0.49 * normal.y;
- result = texture2D(ima, tex) * mask;
+ vec3 vN = normalize(mat3(ViewMatrix) * normal);
+ result = CLOSURE_DEFAULT;
+ result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
+ result.opacity = 1.0 - transp;
+ result.ssr_data = vec4(ssr_spec, roughness);
+ result.ssr_normal = normal_encode(vN, viewCameraVec);
+ result.ssr_id = int(ssr_id);
}
+
+void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
+{
+ vec4 spec_accum = vec4(0.0);
+ if (ssrToggle && cl.ssr_id == outputSsrId) {
+ vec3 V = cameraVec;
+ vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec);
+ vec3 N = transform_direction(ViewMatrixInverse, vN);
+ float roughness = cl.ssr_data.a;
+ float roughnessSquared = max(1e-3, roughness * roughness);
+ fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum);
+ }
+
+ outalpha = cl.opacity;
+ outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
+
+# ifdef USE_SSS
+# ifdef USE_SSS_ALBEDO
+ outcol.rgb += cl.sss_data.rgb * cl.sss_albedo;
+# else
+ outcol.rgb += cl.sss_data.rgb;
+# endif
+# endif
+}
+
+#endif /* VOLUMETRICS */
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl
new file mode 100644
index 00000000000..fef81cf58fe
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl
@@ -0,0 +1,24 @@
+
+uniform vec4 color;
+
+in vec2 radii;
+out vec4 fragColor;
+
+void main() {
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+// transparent outside of point
+// --- 0 ---
+// smooth transition
+// --- 1 ---
+// pure point color
+// ...
+// dist = 0 at center of point
+
+ fragColor.rgb = color.rgb;
+ fragColor.a = mix(color.a, 0.0, smoothstep(radii[1], radii[0], dist));
+
+ if (fragColor.a == 0.0) {
+ discard;
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl
new file mode 100644
index 00000000000..852c76fcb26
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl
@@ -0,0 +1,17 @@
+
+uniform vec4 color;
+
+out vec4 fragColor;
+
+void main()
+{
+ vec2 centered = gl_PointCoord - vec2(0.5);
+ float dist_squared = dot(centered, centered);
+ const float rad_squared = 0.25;
+
+ // round point with jaggy edges
+ if (dist_squared > rad_squared)
+ discard;
+
+ fragColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
new file mode 100644
index 00000000000..eae5ee633ae
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
@@ -0,0 +1,36 @@
+
+uniform vec4 color;
+uniform vec4 outlineColor;
+
+in vec4 radii;
+out vec4 fragColor;
+
+void main() {
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+// transparent outside of point
+// --- 0 ---
+// smooth transition
+// --- 1 ---
+// pure outline color
+// --- 2 ---
+// smooth transition
+// --- 3 ---
+// pure point color
+// ...
+// dist = 0 at center of point
+
+ float midStroke = 0.5 * (radii[1] + radii[2]);
+
+ if (dist > midStroke) {
+ fragColor.rgb = outlineColor.rgb;
+ fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist));
+ }
+ else {
+ fragColor = mix(color, outlineColor, smoothstep(radii[3], radii[2], dist));
+ }
+
+ if (fragColor.a == 0.0) {
+ discard;
+ }
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
new file mode 100644
index 00000000000..2d2724bb686
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
@@ -0,0 +1,16 @@
+
+in vec4 finalColor;
+out vec4 fragColor;
+
+void main()
+{
+ vec2 centered = gl_PointCoord - vec2(0.5);
+ float dist_squared = dot(centered, centered);
+ const float rad_squared = 0.25;
+
+ // round point with jaggy edges
+ if (dist_squared > rad_squared)
+ discard;
+
+ fragColor = finalColor;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl
new file mode 100644
index 00000000000..9b7d4bfc6d6
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl
@@ -0,0 +1,31 @@
+
+uniform vec4 outlineColor;
+
+in vec4 radii;
+in vec4 fillColor;
+out vec4 fragColor;
+
+void main() {
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+// transparent outside of point
+// --- 0 ---
+// smooth transition
+// --- 1 ---
+// pure outline color
+// --- 2 ---
+// smooth transition
+// --- 3 ---
+// pure fill color
+// ...
+// dist = 0 at center of point
+
+ float midStroke = 0.5 * (radii[1] + radii[2]);
+
+ if (dist > midStroke) {
+ fragColor.rgb = outlineColor.rgb;
+ fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist));
+ }
+ else
+ fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist));
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
new file mode 100644
index 00000000000..e1f8203cb26
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
@@ -0,0 +1,30 @@
+
+in vec4 radii;
+in vec4 fillColor;
+in vec4 outlineColor;
+out vec4 fragColor;
+
+void main() {
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+// transparent outside of point
+// --- 0 ---
+// smooth transition
+// --- 1 ---
+// pure outline color
+// --- 2 ---
+// smooth transition
+// --- 3 ---
+// pure fill color
+// ...
+// dist = 0 at center of point
+
+ float midStroke = 0.5 * (radii[1] + radii[2]);
+
+ if (dist > midStroke) {
+ fragColor.rgb = outlineColor.rgb;
+ fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist));
+ }
+ else
+ fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist));
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
deleted file mode 100644
index b485d2cce86..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-uniform vec2 ScaleU;
-uniform sampler2D textureSource;
-
-void main()
-{
- vec4 color = vec4(0.0);
- color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y)) * 0.015625;
- color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y)) * 0.09375;
- color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y)) * 0.234375;
- color += texture2D(textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125;
- color += texture2D(textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y)) * 0.234375;
- color += texture2D(textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y)) * 0.09375;
- color += texture2D(textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y)) * 0.015625;
-
- gl_FragColor = color;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
deleted file mode 100644
index 5d00108b052..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
+++ /dev/null
@@ -1,6 +0,0 @@
-
-void main()
-{
- gl_Position = ftransform();
- gl_TexCoord[0] = gl_MultiTexCoord0;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
new file mode 100644
index 00000000000..d65768eff4d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
@@ -0,0 +1,18 @@
+
+#ifndef USE_INSTANCE_COLOR
+uniform vec4 color;
+#endif
+uniform vec3 light;
+
+in vec3 normal;
+#ifdef USE_INSTANCE_COLOR
+flat in vec4 finalColor;
+# define color finalColor
+#endif
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = color;
+ fragColor.xyz *= clamp(dot(normalize(normal), light), 0.0, 1.0);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl
new file mode 100644
index 00000000000..6b13f408c84
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl
@@ -0,0 +1,14 @@
+
+uniform vec3 light;
+uniform float alpha;
+uniform float global;
+
+in vec3 normal;
+in vec4 finalColor;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = finalColor * (global + (1.0 - global) * max(0.0, dot(normalize(normal), light)));
+ fragColor.a = alpha;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl
new file mode 100644
index 00000000000..58c5f292647
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl
@@ -0,0 +1,16 @@
+
+uniform vec3 light;
+
+#ifdef USE_FLAT_NORMAL
+flat in vec3 normal;
+flat in vec4 finalColor;
+#else
+in vec3 normal;
+in vec4 finalColor;
+#endif
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = finalColor * max(0.0, dot(normalize(normal), light));
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
deleted file mode 100644
index 6ded453225e..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
+++ /dev/null
@@ -1,48 +0,0 @@
-
-varying vec3 coords;
-
-uniform vec3 active_color;
-uniform float step_size;
-uniform float density_scale;
-
-uniform sampler3D soot_texture;
-uniform sampler3D shadow_texture;
-
-#ifdef USE_COBA
-uniform sampler1D transfer_texture;
-uniform sampler3D color_band_texture;
-#endif
-
-void main()
-{
- /* compute color and density from volume texture */
- vec4 soot = texture3D(soot_texture, coords);
-
-#ifndef USE_COBA
- vec3 soot_color;
- if (soot.a != 0) {
- soot_color = active_color * soot.rgb / soot.a;
- }
- else {
- soot_color = vec3(0, 0, 0);
- }
- float soot_density = density_scale * soot.a;
-
- /* compute transmittance and alpha */
- float soot_transmittance = pow(2.71828182846, -soot_density * step_size);
- float soot_alpha = 1.0 - soot_transmittance;
-
- /* shade */
- float shadow = texture3D(shadow_texture, coords).r;
- soot_color *= soot_transmittance * shadow;
-
- /* premultiply alpha */
- vec4 color = vec4(soot_alpha * soot_color, soot_alpha);
-#else
- float color_band = texture3D(color_band_texture, coords).r;
- vec4 transfer_function = texture1D(transfer_texture, color_band);
- vec4 color = transfer_function * density_scale;
-#endif
-
- gl_FragColor = color;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl
deleted file mode 100644
index 297486ae26a..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl
+++ /dev/null
@@ -1,12 +0,0 @@
-
-varying vec3 coords;
-
-uniform vec3 min_location;
-uniform vec3 invsize;
-uniform vec3 ob_sizei;
-
-void main()
-{
- gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz * ob_sizei, 1.0);
- coords = (gl_Vertex.xyz - min_location) * invsize;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
new file mode 100644
index 00000000000..fbfa4cfcc9d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -0,0 +1,74 @@
+
+flat in vec4 color_flat;
+flat in vec4 texCoord_rect;
+noperspective in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D glyph;
+
+const vec2 offsets4[4] = vec2[4](
+ vec2(-0.5, 0.5), vec2( 0.5, 0.5),
+ vec2(-0.5, -0.5), vec2(-0.5, -0.5)
+);
+
+const vec2 offsets16[16] = vec2[16](
+ vec2(-1.5, 1.5), vec2(-0.5, 1.5), vec2( 0.5, 1.5), vec2( 1.5, 1.5),
+ vec2(-1.5, 0.5), vec2(-0.5, 0.5), vec2( 0.5, 0.5), vec2( 1.5, 0.5),
+ vec2(-1.5, -0.5), vec2(-0.5, -0.5), vec2( 0.5, -0.5), vec2( 1.5, -0.5),
+ vec2(-1.5, -1.5), vec2(-0.5, -1.5), vec2( 0.5, -1.5), vec2( 1.5, -1.5)
+);
+
+#define sample_glyph_offset(texco, texel, ofs) texture(glyph, texco + ofs * texel).r
+
+void main()
+{
+ // input color replaces texture color
+ fragColor.rgb = color_flat.rgb;
+
+ vec2 texel = 1.0 / vec2(textureSize(glyph, 0));
+ vec2 texco = mix(abs(texCoord_rect.xy), abs(texCoord_rect.zw), texCoord_interp);
+
+ // modulate input alpha & texture alpha
+ if (texCoord_rect.x > 0) {
+ fragColor.a = texture(glyph, texco).r;
+ }
+ else {
+ fragColor.a = 0.0;
+
+ if (texCoord_rect.w > 0) {
+ /* 3x3 blur */
+ /* Manual unroll for perf. (stupid glsl compiler) */
+ fragColor.a += sample_glyph_offset(texco, texel, offsets4[0]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets4[1]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets4[2]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets4[3]);
+ fragColor.a *= (1.0 / 4.0);
+ }
+ else {
+ /* 5x5 blur */
+ /* Manual unroll for perf. (stupid glsl compiler) */
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 0]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 1]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 2]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 3]);
+
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 4]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 5]) * 2.0;
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 6]) * 2.0;
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 7]);
+
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 8]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 9]) * 2.0;
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[10]) * 2.0;
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[11]);
+
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[12]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[13]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[14]);
+ fragColor.a += sample_glyph_offset(texco, texel, offsets16[15]);
+ fragColor.a *= (1.0 / 20.0);
+ }
+ }
+
+ fragColor.a *= color_flat.a;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_geom.glsl b/source/blender/gpu/shaders/gpu_shader_text_geom.glsl
new file mode 100644
index 00000000000..0acd2106f7a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_text_geom.glsl
@@ -0,0 +1,37 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+layout(points) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+in vec4 pos_rect[];
+in vec4 tex_rect[];
+in vec4 color[];
+
+flat out vec4 color_flat;
+flat out vec4 texCoord_rect;
+noperspective out vec2 texCoord_interp;
+
+void main()
+{
+ color_flat = color[0];
+ texCoord_rect = tex_rect[0];
+
+ gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].xy, 0.0, 1.0));
+ texCoord_interp = vec2(0.0, 0.0);
+ EmitVertex();
+
+ gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].zy, 0.0, 1.0));
+ texCoord_interp = vec2(1.0, 0.0);
+ EmitVertex();
+
+ gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].xw, 0.0, 1.0));
+ texCoord_interp = vec2(0.0, 1.0);
+ EmitVertex();
+
+ gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].zw, 0.0, 1.0));
+ texCoord_interp = vec2(1.0, 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl b/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl
new file mode 100644
index 00000000000..8903fd1df57
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl
@@ -0,0 +1,36 @@
+
+layout(points) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+in vec4 pos_rect[];
+in vec4 tex_rect[];
+in vec4 color[];
+
+flat out vec4 color_flat;
+flat out vec4 texCoord_rect;
+noperspective out vec2 texCoord_interp;
+
+void main()
+{
+ color_flat = color[0];
+ texCoord_rect = tex_rect[0];
+ gl_Position.zw = vec2(0.0, 1.0);
+
+ gl_Position.xy = pos_rect[0].xy;
+ texCoord_interp = vec2(0.0, 0.0);
+ EmitVertex();
+
+ gl_Position.xy = pos_rect[0].zy;
+ texCoord_interp = vec2(1.0, 0.0);
+ EmitVertex();
+
+ gl_Position.xy = pos_rect[0].xw;
+ texCoord_interp = vec2(0.0, 1.0);
+ EmitVertex();
+
+ gl_Position.xy = pos_rect[0].zw;
+ texCoord_interp = vec2(1.0, 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl
new file mode 100644
index 00000000000..4a2cde71e07
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl
@@ -0,0 +1,22 @@
+
+/* Simpler version of gpu_shader_text_vert that supports only 2D translation. */
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec4 pos; /* rect */
+in vec4 tex; /* rect */
+in vec4 col;
+
+out vec4 pos_rect;
+out vec4 tex_rect;
+out vec4 color;
+
+void main()
+{
+ /* Manual mat4*vec2 */
+ pos_rect = ModelViewProjectionMatrix[0].xyxy * pos.xxzz;
+ pos_rect += ModelViewProjectionMatrix[1].xyxy * pos.yyww;
+ pos_rect += ModelViewProjectionMatrix[3].xyxy;
+ tex_rect = tex;
+ color = col;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
new file mode 100644
index 00000000000..338156f5b68
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
@@ -0,0 +1,17 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec4 pos; /* rect */
+in vec4 tex; /* rect */
+in vec4 col;
+
+out vec4 pos_rect;
+out vec4 tex_rect;
+out vec4 color;
+
+void main()
+{
+ pos_rect = pos;
+ tex_rect = tex;
+ color = col;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
new file mode 100644
index 00000000000..118a661863d
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
@@ -0,0 +1,21 @@
+
+#if defined(USE_COLOR_U32)
+uniform uint color;
+#else
+uniform vec4 color;
+#endif
+
+out vec4 fragColor;
+
+void main()
+{
+#if defined(USE_COLOR_U32)
+ fragColor = vec4(
+ ((color ) & uint(0xFF)) * (1.0f / 255.0f),
+ ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f),
+ ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f),
+ ((color >> 24) ) * (1.0f / 255.0f));
+#else
+ fragColor = color;
+#endif
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
deleted file mode 100644
index 2c5bcd54b33..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ /dev/null
@@ -1,111 +0,0 @@
-#ifdef USE_OPENSUBDIV
-in vec3 normal;
-in vec4 position;
-
-out block {
- VertexData v;
-} outpt;
-#endif
-
-varying vec3 varposition;
-varying vec3 varnormal;
-
-#ifdef CLIP_WORKAROUND
-varying float gl_ClipDistance[6];
-#endif
-
-
-/* Color, keep in sync with: gpu_shader_vertex_world.glsl */
-
-float srgb_to_linearrgb(float c)
-{
- if (c < 0.04045)
- return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
- else
- return pow((c + 0.055) * (1.0 / 1.055), 2.4);
-}
-
-void srgb_to_linearrgb(vec3 col_from, out vec3 col_to)
-{
- col_to.r = srgb_to_linearrgb(col_from.r);
- col_to.g = srgb_to_linearrgb(col_from.g);
- col_to.b = srgb_to_linearrgb(col_from.b);
-}
-
-void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
-{
- col_to.r = srgb_to_linearrgb(col_from.r);
- col_to.g = srgb_to_linearrgb(col_from.g);
- col_to.b = srgb_to_linearrgb(col_from.b);
- col_to.a = col_from.a;
-}
-
-bool is_srgb(int info)
-{
-#ifdef USE_NEW_SHADING
- return (info == 1)? true: false;
-#else
- return false;
-#endif
-}
-
-void set_var_from_attr(float attr, int info, out float var)
-{
- var = attr;
-}
-
-void set_var_from_attr(vec2 attr, int info, out vec2 var)
-{
- var = attr;
-}
-
-void set_var_from_attr(vec3 attr, int info, out vec3 var)
-{
- if (is_srgb(info)) {
- srgb_to_linearrgb(attr, var);
- }
- else {
- var = attr;
- }
-}
-
-void set_var_from_attr(vec4 attr, int info, out vec4 var)
-{
- if (is_srgb(info)) {
- srgb_to_linearrgb(attr, var);
- }
- else {
- var = attr;
- }
-}
-
-/* end color code */
-
-
-void main()
-{
-#ifndef USE_OPENSUBDIV
- vec4 position = gl_Vertex;
- vec3 normal = gl_Normal;
-#endif
-
- vec4 co = gl_ModelViewMatrix * position;
-
- varposition = co.xyz;
- varnormal = normalize(gl_NormalMatrix * normal);
- gl_Position = gl_ProjectionMatrix * co;
-
-#ifdef CLIP_WORKAROUND
- int i;
- for (i = 0; i < 6; i++)
- gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
-#elif !defined(GPU_ATI)
- // Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
- // graphic cards, while on ATI it can cause a software fallback.
- gl_ClipVertex = co;
-#endif
-
-#ifdef USE_OPENSUBDIV
- outpt.v.position = co;
- outpt.v.normal = varnormal;
-#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
deleted file mode 100644
index a81d2bcef69..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl
+++ /dev/null
@@ -1,80 +0,0 @@
-
-varying vec3 varposition;
-varying vec3 varnormal;
-
-
-/* Color, keep in sync with: gpu_shader_vertex.glsl */
-
-float srgb_to_linearrgb(float c)
-{
- if (c < 0.04045)
- return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
- else
- return pow((c + 0.055) * (1.0 / 1.055), 2.4);
-}
-
-void srgb_to_linearrgb(vec3 col_from, out vec3 col_to)
-{
- col_to.r = srgb_to_linearrgb(col_from.r);
- col_to.g = srgb_to_linearrgb(col_from.g);
- col_to.b = srgb_to_linearrgb(col_from.b);
-}
-
-void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
-{
- col_to.r = srgb_to_linearrgb(col_from.r);
- col_to.g = srgb_to_linearrgb(col_from.g);
- col_to.b = srgb_to_linearrgb(col_from.b);
- col_to.a = col_from.a;
-}
-
-bool is_srgb(int info)
-{
-#ifdef USE_NEW_SHADING
- return (info == 1)? true: false;
-#else
- return false;
-#endif
-}
-
-void set_var_from_attr(float attr, int info, out float var)
-{
- var = attr;
-}
-
-void set_var_from_attr(vec2 attr, int info, out vec2 var)
-{
- var = attr;
-}
-
-void set_var_from_attr(vec3 attr, int info, out vec3 var)
-{
- if (is_srgb(info)) {
- srgb_to_linearrgb(attr, var);
- }
- else {
- var = attr;
- }
-}
-
-void set_var_from_attr(vec4 attr, int info, out vec4 var)
-{
- if (is_srgb(info)) {
- srgb_to_linearrgb(attr, var);
- }
- else {
- var = attr;
- }
-}
-
-/* end color code */
-
-
-void main()
-{
- /* position does not need to be transformed, we already have it */
- gl_Position = gl_Vertex;
-
- varposition = gl_Vertex.xyz;
-
- varnormal = normalize(-varposition);
diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
deleted file mode 100644
index 3761bf350eb..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * This fragment shader was initially found at http://fabiensanglard.net/shadowmappingVSM/index.php
- */
-
-varying vec4 v_position;
-
-void main()
-{
- float depth = v_position.z / v_position.w;
- depth = depth * 0.5 + 0.5;
-
- float moment1 = depth;
- float moment2 = depth * depth;
-
- // Adjusting moments using partial derivative
- float dx = dFdx(depth);
- float dy = dFdy(depth);
- moment2 += 0.25 * (dx * dx + dy * dy);
-
- gl_FragColor = vec4(moment1, moment2, 0.0, 0.0);
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl
deleted file mode 100644
index 224c3e78adc..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl
+++ /dev/null
@@ -1,7 +0,0 @@
-varying vec4 v_position;
-
-void main()
-{
- gl_Position = ftransform();
- v_position = gl_Position;
-}
diff --git a/source/blender/ikplugin/BIK_api.h b/source/blender/ikplugin/BIK_api.h
index 3f53e24f24a..07a223b738e 100644
--- a/source/blender/ikplugin/BIK_api.h
+++ b/source/blender/ikplugin/BIK_api.h
@@ -43,6 +43,7 @@ struct bPoseChannel;
struct bPose;
struct Scene;
struct bConstraint;
+struct Depsgraph;
enum BIK_ParamType {
BIK_PARAM_TYPE_FLOAT = 0,
@@ -61,8 +62,8 @@ struct BIK_ParamValue {
};
typedef struct BIK_ParamValue BIK_ParamValue;
-void BIK_initialize_tree(struct Scene *scene, struct Object *ob, float ctime);
-void BIK_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
+void BIK_initialize_tree(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime);
+void BIK_execute_tree(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
void BIK_release_tree(struct Scene *scene, struct Object *ob, float ctime);
void BIK_clear_data(struct bPose *pose);
void BIK_clear_cache(struct bPose *pose);
diff --git a/source/blender/ikplugin/intern/ikplugin_api.c b/source/blender/ikplugin/intern/ikplugin_api.c
index 00fb5768d79..80de0beb9f4 100644
--- a/source/blender/ikplugin/intern/ikplugin_api.c
+++ b/source/blender/ikplugin/intern/ikplugin_api.c
@@ -53,8 +53,8 @@ static IKPlugin ikplugin_tab[] = {
{
iksolver_initialize_tree,
iksolver_execute_tree,
- NULL,
- NULL,
+ iksolver_release_tree,
+ iksolver_clear_data,
NULL,
NULL,
NULL,
@@ -89,20 +89,20 @@ static IKPlugin *get_plugin(bPose *pose)
/*----------------------------------------*/
/* Plugin API */
-void BIK_initialize_tree(Scene *scene, Object *ob, float ctime)
+void BIK_initialize_tree(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime)
{
IKPlugin *plugin = get_plugin(ob->pose);
if (plugin && plugin->initialize_tree_func)
- plugin->initialize_tree_func(scene, ob, ctime);
+ plugin->initialize_tree_func(depsgraph, scene, ob, ctime);
}
-void BIK_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan, float ctime)
+void BIK_execute_tree(struct Depsgraph *depsgraph, struct Scene *scene, Object *ob, bPoseChannel *pchan, float ctime)
{
IKPlugin *plugin = get_plugin(ob->pose);
if (plugin && plugin->execute_tree_func)
- plugin->execute_tree_func(scene, ob, pchan, ctime);
+ plugin->execute_tree_func(depsgraph, scene, ob, pchan, ctime);
}
void BIK_release_tree(struct Scene *scene, Object *ob, float ctime)
diff --git a/source/blender/ikplugin/intern/ikplugin_api.h b/source/blender/ikplugin/intern/ikplugin_api.h
index 0b4df11de60..139a50f44f0 100644
--- a/source/blender/ikplugin/intern/ikplugin_api.h
+++ b/source/blender/ikplugin/intern/ikplugin_api.h
@@ -38,14 +38,15 @@
extern "C" {
#endif
+struct Depsgraph;
struct Object;
-struct bPoseChannel;
struct Scene;
+struct bPoseChannel;
struct IKPlugin {
- void (*initialize_tree_func)(struct Scene *scene, struct Object *ob, float ctime);
- void (*execute_tree_func)(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
+ void (*initialize_tree_func)(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime);
+ void (*execute_tree_func)(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime);
void (*release_tree_func)(struct Scene *scene, struct Object *ob, float ctime);
void (*remove_armature_func)(struct bPose *pose);
void (*clear_cache)(struct bPose *pose);
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index 616e9a723f6..0baaa406201 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -252,7 +252,7 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr =
/* called from within the core BKE_pose_where_is loop, all animsystems and constraints
* were executed & assigned. Now as last we do an IK pass */
-static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
+static void execute_posetree(struct Depsgraph *depsgraph, struct Scene *scene, Object *ob, PoseTree *tree)
{
float R_parmat[3][3], identity[3][3];
float iR_parmat[3][3];
@@ -394,7 +394,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
/* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
* strictly speaking, it is a posechannel)
*/
- BKE_constraint_target_matrix_get(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+ BKE_constraint_target_matrix_get(depsgraph, scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
/* and set and transform goal */
mul_m4_m4m4(goal, goalinv, rootmat);
@@ -405,7 +405,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
/* same for pole vector target */
if (data->poletar) {
- BKE_constraint_target_matrix_get(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+ BKE_constraint_target_matrix_get(depsgraph, scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
if (data->flag & CONSTRAINT_IK_SETANGLE) {
/* don't solve IK when we are setting the pole angle */
@@ -534,7 +534,7 @@ static void free_posetree(PoseTree *tree)
///----------------------------------------
/// Plugin API for legacy iksolver
-void iksolver_initialize_tree(struct Scene *UNUSED(scene), struct Object *ob, float UNUSED(ctime))
+void iksolver_initialize_tree(struct Depsgraph *UNUSED(depsgraph), struct Scene *UNUSED(scene), struct Object *ob, float UNUSED(ctime))
{
bPoseChannel *pchan;
@@ -545,7 +545,7 @@ void iksolver_initialize_tree(struct Scene *UNUSED(scene), struct Object *ob, fl
ob->pose->flag &= ~POSE_WAS_REBUILT;
}
-void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+void iksolver_execute_tree(struct Depsgraph *depsgraph, struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
while (pchan_root->iktree.first) {
PoseTree *tree = pchan_root->iktree.first;
@@ -558,13 +558,13 @@ void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan
/* 4. walk over the tree for regular solving */
for (a = 0; a < tree->totchannel; a++) {
if (!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag
- BKE_pose_where_is_bone(scene, ob, tree->pchan[a], ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, tree->pchan[a], ctime, 1);
/* tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is() */
tree->pchan[a]->flag |= POSE_CHAIN;
}
/* 5. execute the IK solver */
- execute_posetree(scene, ob, tree);
+ execute_posetree(depsgraph, scene, ob, tree);
/* 6. apply the differences to the channels,
* we need to calculate the original differences first */
@@ -582,3 +582,27 @@ void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan
free_posetree(tree);
}
}
+
+void iksolver_release_tree(struct Scene *UNUSED(scene), struct Object *ob, float UNUSED(ctime))
+{
+ iksolver_clear_data(ob->pose);
+}
+
+void iksolver_clear_data(bPose *pose)
+{
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->flag & POSE_IKTREE) == 0)
+ continue;
+
+ while (pchan->iktree.first) {
+ PoseTree *tree = pchan->iktree.first;
+
+ /* stop on the first tree that isn't a standard IK chain */
+ if (tree->type != CONSTRAINT_TYPE_KINEMATIC)
+ break;
+
+ BLI_remlink(&pchan->iktree, tree);
+ free_posetree(tree);
+ }
+ }
+}
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.h b/source/blender/ikplugin/intern/iksolver_plugin.h
index bb12c83d885..09eb7139192 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.h
+++ b/source/blender/ikplugin/intern/iksolver_plugin.h
@@ -40,8 +40,13 @@
extern "C" {
#endif
-void iksolver_initialize_tree(struct Scene *scene, struct Object *ob, float ctime);
-void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
+void iksolver_initialize_tree(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime);
+void iksolver_execute_tree(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ struct bPoseChannel *pchan_root, float ctime);
+void iksolver_release_tree(struct Scene *scene, struct Object *ob, float ctime);
+void iksolver_clear_data(struct bPose *pose);
#ifdef __cplusplus
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 17f9cd5bc7a..4a71b36bfef 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -90,6 +90,7 @@ typedef void (*ErrorCallback)(const iTaSC::ConstraintValues *values, unsigned in
// one structure for each target in the scene
struct IK_Target {
+ struct Depsgraph *bldepsgraph;
struct Scene *blscene;
iTaSC::MovingFrame* target;
iTaSC::ConstraintSet* constraint;
@@ -107,6 +108,7 @@ struct IK_Target {
float eeRest[4][4]; //end effector initial pose relative to armature
IK_Target() {
+ bldepsgraph = NULL;
blscene = NULL;
target = NULL;
constraint = NULL;
@@ -157,6 +159,7 @@ struct IK_Channel {
};
struct IK_Scene {
+ struct Depsgraph *bldepsgraph;
struct Scene *blscene;
IK_Scene* next;
int numchan; // number of channel in pchan
@@ -177,6 +180,7 @@ struct IK_Scene {
std::vector<IK_Target*> targets;
IK_Scene() {
+ bldepsgraph = NULL;
blscene = NULL;
next = NULL;
channels = NULL;
@@ -550,7 +554,7 @@ static bool target_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Fram
bConstraint *constraint = (bConstraint *)target->blenderConstraint;
float tarmat[4][4];
- BKE_constraint_target_matrix_get(target->blscene, constraint, 0, CONSTRAINT_OBTYPE_OBJECT, target->owner, tarmat, 1.0);
+ BKE_constraint_target_matrix_get(target->bldepsgraph, target->blscene, constraint, 0, CONSTRAINT_OBTYPE_OBJECT, target->owner, tarmat, 1.0);
// rootmat contains the target pose in world coordinate
// if enforce is != 1.0, blend the target position with the end effector position
@@ -619,7 +623,7 @@ static bool base_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Frame&
IK_Channel &rootchan = ikscene->channels[0];
// get polar target matrix in world space
- BKE_constraint_target_matrix_get(ikscene->blscene, ikscene->polarConstraint, 1, CONSTRAINT_OBTYPE_OBJECT, ikscene->blArmature, mat, 1.0);
+ BKE_constraint_target_matrix_get(ikscene->bldepsgraph, ikscene->blscene, ikscene->polarConstraint, 1, CONSTRAINT_OBTYPE_OBJECT, ikscene->blArmature, mat, 1.0);
// convert to armature space
mul_m4_m4m4(polemat, imat, mat);
// get the target in world space (was computed before as target object are defined before base object)
@@ -863,7 +867,7 @@ static bool joint_callback(const iTaSC::Timestamp& timestamp, iTaSC::ConstraintV
}
// build array of joint corresponding to IK chain
-static int convert_channels(IK_Scene *ikscene, PoseTree *tree, float ctime)
+static int convert_channels(struct Depsgraph *depsgraph, IK_Scene *ikscene, PoseTree *tree, float ctime)
{
IK_Channel *ikchan;
bPoseChannel *pchan;
@@ -880,7 +884,7 @@ static int convert_channels(IK_Scene *ikscene, PoseTree *tree, float ctime)
// this is because some of the pose data (e.g. pose head) don't have corresponding
// joint angles and can't be applied to the iTaSC armature dynamically
if (!(pchan->flag & POSE_DONE))
- BKE_pose_where_is_bone(ikscene->blscene, ikscene->blArmature, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, ikscene->blscene, ikscene->blArmature, pchan, ctime, 1);
// tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is()
pchan->flag |= (POSE_DONE | POSE_CHAIN);
@@ -1056,7 +1060,7 @@ static void BKE_pose_rest(IK_Scene *ikscene)
}
}
-static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, float ctime)
+static IK_Scene *convert_tree(struct Depsgraph *depsgraph, Scene *blscene, Object *ob, bPoseChannel *pchan, float ctime)
{
PoseTree *tree = (PoseTree *)pchan->iktree.first;
PoseTarget *target;
@@ -1068,12 +1072,11 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, f
IK_Scene *ikscene;
IK_Channel *ikchan;
KDL::Frame initPose;
- KDL::Rotation boneRot;
Bone *bone;
int a, numtarget;
unsigned int t;
float length;
- bool ret = true, ingame;
+ bool ret = true;
double *rot;
float start[3];
@@ -1082,6 +1085,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, f
ikscene = new IK_Scene;
ikscene->blscene = blscene;
+ ikscene->bldepsgraph = depsgraph;
arm = new iTaSC::Armature();
scene = new iTaSC::Scene();
ikscene->channels = new IK_Channel[tree->totchannel];
@@ -1089,26 +1093,13 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, f
ikscene->armature = arm;
ikscene->scene = scene;
ikparam = (bItasc *)ob->pose->ikparam;
- ingame = (ob->pose->flag & POSE_GAME_ENGINE);
+
if (!ikparam) {
// you must have our own copy
ikparam = &DefIKParam;
}
- else if (ingame) {
- // tweak the param when in game to have efficient stepping
- // using fixed substep is not effecient since frames in the GE are often
- // shorter than in animation => move to auto step automatically and set
- // the target substep duration via min/max
- if (!(ikparam->flag & ITASC_AUTO_STEP)) {
- float timestep = blscene->r.frs_sec_base / blscene->r.frs_sec;
- if (ikparam->numstep > 0)
- timestep /= ikparam->numstep;
- // with equal min and max, the algorythm will take this step and the indicative substep most of the time
- ikparam->minstep = ikparam->maxstep = timestep;
- ikparam->flag |= ITASC_AUTO_STEP;
- }
- }
- if ((ikparam->flag & ITASC_SIMULATION) && !ingame)
+
+ if (ikparam->flag & ITASC_SIMULATION)
// no cache in animation mode
ikscene->cache = new iTaSC::Cache();
@@ -1134,16 +1125,9 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, f
std::vector<double> weights;
double weight[3];
// build the array of joints corresponding to the IK chain
- convert_channels(ikscene, tree, ctime);
- if (ingame) {
- // in the GE, set the initial joint angle to match the current pose
- // this will update the jointArray in ikscene
- convert_pose(ikscene);
- }
- else {
- // in Blender, the rest pose is always 0 for joints
- BKE_pose_rest(ikscene);
- }
+ convert_channels(depsgraph, ikscene, tree, ctime);
+ // in Blender, the rest pose is always 0 for joints
+ BKE_pose_rest(ikscene);
rot = ikscene->jointArray(0);
for (a = 0, ikchan = ikscene->channels; a < tree->totchannel; ++a, ++ikchan) {
@@ -1439,6 +1423,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, f
for (t = 0; t < ikscene->targets.size(); t++) {
IK_Target *iktarget = ikscene->targets[t];
iktarget->blscene = blscene;
+ iktarget->bldepsgraph = depsgraph;
condata = (bKinematicConstraint *)iktarget->blenderConstraint->data;
pchan = tree->pchan[iktarget->channel];
unsigned int controltype, bonecnt;
@@ -1526,7 +1511,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, f
return ikscene;
}
-static void create_scene(Scene *scene, Object *ob, float ctime)
+static void create_scene(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime)
{
bPoseChannel *pchan;
@@ -1537,7 +1522,7 @@ static void create_scene(Scene *scene, Object *ob, float ctime)
if (tree) {
IK_Data *ikdata = get_ikdata(ob->pose);
// convert tree in iTaSC::Scene
- IK_Scene *ikscene = convert_tree(scene, ob, pchan, ctime);
+ IK_Scene *ikscene = convert_tree(depsgraph, scene, ob, pchan, ctime);
if (ikscene) {
ikscene->next = ikdata->first;
ikdata->first = ikscene;
@@ -1576,7 +1561,7 @@ static int init_scene(Object *ob)
return 0;
}
-static void execute_scene(Scene *blscene, IK_Scene *ikscene, bItasc *ikparam, float ctime, float frtime)
+static void execute_scene(struct Depsgraph *depsgraph, Scene *blscene, IK_Scene *ikscene, bItasc *ikparam, float ctime, float frtime)
{
int i;
IK_Channel *ikchan;
@@ -1592,7 +1577,7 @@ static void execute_scene(Scene *blscene, IK_Scene *ikscene, bItasc *ikparam, fl
// in animation mode, we must get the bone position from action and constraints
for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ++ikchan) {
if (!(ikchan->pchan->flag & POSE_DONE))
- BKE_pose_where_is_bone(blscene, ikscene->blArmature, ikchan->pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, blscene, ikscene->blArmature, ikchan->pchan, ctime, 1);
// tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is()
ikchan->pchan->flag |= (POSE_DONE | POSE_CHAIN);
ikchan->jointValid = 0;
@@ -1744,7 +1729,7 @@ static void execute_scene(Scene *blscene, IK_Scene *ikscene, bItasc *ikparam, fl
//---------------------------------------------------
// plugin interface
//
-void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime)
+void itasc_initialize_tree(struct Depsgraph *depsgraph, struct Scene *scene, Object *ob, float ctime)
{
bPoseChannel *pchan;
int count = 0;
@@ -1764,13 +1749,13 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime)
// if at least one tree, create the scenes from the PoseTree stored in the channels
// postpone until execute_tree: this way the pose constraint are included
if (count)
- create_scene(scene, ob, ctime);
+ create_scene(depsgraph, scene, ob, ctime);
itasc_update_param(ob->pose);
// make sure we don't rebuilt until the user changes something important
ob->pose->flag &= ~POSE_WAS_REBUILT;
}
-void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+void itasc_execute_tree(struct Depsgraph *depsgraph, struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
if (ob->pose->ikdata) {
IK_Data *ikdata = (IK_Data *)ob->pose->ikdata;
@@ -1781,13 +1766,7 @@ void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_ro
for (IK_Scene *ikscene = ikdata->first; ikscene; ikscene = ikscene->next) {
if (ikscene->channels[0].pchan == pchan_root) {
float timestep = scene->r.frs_sec_base / scene->r.frs_sec;
- if (ob->pose->flag & POSE_GAME_ENGINE) {
- timestep = ob->pose->ctime;
- // limit the timestep to avoid excessive number of iteration
- if (timestep > 0.2f)
- timestep = 0.2f;
- }
- execute_scene(scene, ikscene, ikparam, ctime, timestep);
+ execute_scene(depsgraph, scene, ikscene, ikparam, ctime, timestep);
break;
}
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.h b/source/blender/ikplugin/intern/itasc_plugin.h
index bbdb0687eba..2853ae095db 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.h
+++ b/source/blender/ikplugin/intern/itasc_plugin.h
@@ -40,8 +40,8 @@
extern "C" {
#endif
-void itasc_initialize_tree(struct Scene *scene, struct Object *ob, float ctime);
-void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
+void itasc_initialize_tree(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime);
+void itasc_execute_tree(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
void itasc_release_tree(struct Scene *scene, struct Object *ob, float ctime);
void itasc_clear_data(struct bPose *pose);
void itasc_clear_cache(struct bPose *pose);
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 75f8df99e63..04ce2d6eaa3 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -431,7 +431,6 @@ bool IMB_isfloat(struct ImBuf *ibuf);
* \attention Defined in divers.c
*/
void IMB_de_interlace(struct ImBuf *ibuf);
-void IMB_interlace(struct ImBuf *ibuf);
/* create char buffer, color corrected if necessary, for ImBufs that lack one */
void IMB_rect_from_float(struct ImBuf *ibuf);
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 30a9468808c..d407845e45d 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -222,12 +222,10 @@ typedef struct ImBuf {
struct DDSData dds_data;
} ImBuf;
-/* Moved from BKE_bmfont_types.h because it is a userflag bit mask. */
/**
* \brief userflags: Flags used internally by blender for imagebuffers
*/
-#define IB_BITMAPFONT (1 << 0) /* this image is a font */
#define IB_BITMAPDIRTY (1 << 1) /* image needs to be saved is not the same as filename */
#define IB_MIPMAP_INVALID (1 << 2) /* image mipmaps are invalid, need recreate */
#define IB_RECT_INVALID (1 << 3) /* float buffer changed, needs recreation of byte rect */
@@ -242,7 +240,6 @@ typedef struct ImBuf {
#define IB_rect (1 << 0)
#define IB_test (1 << 1)
-#define IB_fields (1 << 2)
#define IB_zbuf (1 << 3)
#define IB_mem (1 << 4)
#define IB_rectfloat (1 << 5)
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 589955d2ab3..f7005d7ee89 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -155,13 +155,6 @@ void imb_freetilesImBuf(ImBuf *ibuf)
ibuf->mall &= ~IB_tiles;
}
-static void imb_free_bitmap_font(ImBuf *ibuf)
-{
- if (ibuf->userdata && (ibuf->userflags & IB_BITMAPFONT)) {
- MEM_freeN(ibuf->userdata);
- }
-}
-
static void freeencodedbufferImBuf(ImBuf *ibuf)
{
if (ibuf == NULL) return;
@@ -215,7 +208,6 @@ void IMB_freeImBuf(ImBuf *ibuf)
imb_freerectImBuf(ibuf);
imb_freerectfloatImBuf(ibuf);
imb_freetilesImBuf(ibuf);
- imb_free_bitmap_font(ibuf);
IMB_freezbufImBuf(ibuf);
IMB_freezbuffloatImBuf(ibuf);
freeencodedbufferImBuf(ibuf);
@@ -521,7 +513,6 @@ ImBuf *IMB_dupImBuf(const ImBuf *ibuf1)
x = ibuf1->x;
y = ibuf1->y;
- if (ibuf1->flags & IB_fields) y *= 2;
ibuf2 = IMB_allocImBuf(x, y, ibuf1->planes, flags);
if (ibuf2 == NULL) return NULL;
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 2b6fa573e63..e6635080163 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -45,62 +45,6 @@
#include "MEM_guardedalloc.h"
-/**************************** Interlace/Deinterlace **************************/
-
-void IMB_de_interlace(ImBuf *ibuf)
-{
- ImBuf *tbuf1, *tbuf2;
-
- if (ibuf == NULL) return;
- if (ibuf->flags & IB_fields) return;
- ibuf->flags |= IB_fields;
-
- if (ibuf->rect) {
- /* make copies */
- tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
- tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
-
- ibuf->x *= 2;
- IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
- IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
-
- ibuf->x /= 2;
- IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
- IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
-
- IMB_freeImBuf(tbuf1);
- IMB_freeImBuf(tbuf2);
- }
- ibuf->y /= 2;
-}
-
-void IMB_interlace(ImBuf *ibuf)
-{
- ImBuf *tbuf1, *tbuf2;
-
- if (ibuf == NULL) return;
- ibuf->flags &= ~IB_fields;
-
- ibuf->y *= 2;
-
- if (ibuf->rect) {
- /* make copies */
- tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
- tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
-
- IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
- IMB_rectcpy(tbuf2, ibuf, 0, 0, 0, tbuf2->y, ibuf->x, ibuf->y);
-
- ibuf->x *= 2;
- IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
- IMB_rectcpy(ibuf, tbuf2, tbuf2->x, 0, 0, 0, tbuf2->x, tbuf2->y);
- ibuf->x /= 2;
-
- IMB_freeImBuf(tbuf1);
- IMB_freeImBuf(tbuf2);
- }
-}
-
/************************* Floyd-Steinberg dithering *************************/
typedef struct DitherContext {
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 167f2e4f8e0..56f90d39850 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -1041,7 +1041,7 @@ static IndexBuildContext *index_fallback_create_context(struct anim *anim, IMB_T
/* since timecode indices only work with ffmpeg right now,
* don't know a sensible fallback here...
*
- * so no proxies, no game to play...
+ * so no proxies...
*/
if (proxy_sizes_in_use == IMB_PROXY_NONE) {
return NULL;
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index 0b4490a3beb..0cb1ab4b2c5 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -230,7 +230,6 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S
BLI_strncpy(ibuf->cachename, filepath_tx, sizeof(ibuf->cachename));
for (a = 1; a < ibuf->miptot; a++)
BLI_strncpy(ibuf->mipmap[a - 1]->cachename, filepath_tx, sizeof(ibuf->cachename));
- if (flags & IB_fields) IMB_de_interlace(ibuf);
}
close(file);
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index a4418443790..7c58815c216 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -722,7 +722,6 @@ ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *i
ibuf_stereo->rect_colorspace = ibuf_left->rect_colorspace;
ibuf_stereo->float_colorspace = ibuf_left->float_colorspace;
- /* copy flags for IB_fields and other settings */
ibuf_stereo->flags = ibuf_left->flags;
imb_stereo3d_data_initialize(
@@ -1233,7 +1232,6 @@ void IMB_ImBufFromStereo3d(
ibuf_left = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
ibuf_right = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect));
- /* copy flags for IB_fields and other settings */
ibuf_left->flags = ibuf_stereo3d->flags;
ibuf_right->flags = ibuf_stereo3d->flags;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 9d2b635bd7b..fbc34264b30 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -44,10 +44,10 @@
#include "BLI_threads.h"
#include BLI_SYSTEM_PID_H
-#include "BLO_readfile.h"
-
#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */
+#include "BLO_readfile.h"
+
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_thumbs.h"
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index a2363f96bfa..5bdab03e57c 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -32,13 +32,13 @@
#include "BLI_endian_switch.h"
#include "BLI_fileops.h"
#include "BLI_linklist.h"
+#include "BLI_listbase.h" /* Needed due to import of BLO_readfile.h */
#include "BLO_blend_defs.h"
#include "BLO_readfile.h"
#include "BKE_idcode.h"
#include "BKE_icons.h"
-#include "BKE_library.h"
#include "BKE_main.h"
#include "DNA_ID.h" /* For preview images... */
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index e9bc0f41980..9e5e822c4d5 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -45,6 +45,27 @@ struct ID;
struct PackedFile;
struct GPUTexture;
+/* Runtime display data */
+struct DrawData;
+typedef void (*DrawDataInitCb)(struct DrawData *engine_data);
+typedef void (*DrawDataFreeCb)(struct DrawData *engine_data);
+
+#
+#
+typedef struct DrawData {
+ struct DrawData *next, *prev;
+ struct DrawEngineType *engine_type;
+ /* Only nested data, NOT the engine data itself. */
+ DrawDataFreeCb free;
+ /* Accumulated recalc flags, which corresponds to ID->recalc flags. */
+ int recalc;
+} DrawData;
+
+typedef struct DrawDataList {
+ struct DrawData *first, *last;
+} DrawDataList;
+
+
typedef struct IDPropertyData {
void *pointer;
ListBase group;
@@ -96,14 +117,104 @@ enum {
IDP_STRING_SUB_BYTE = 1, /* arbitrary byte array, _not_ null terminated */
};
+/* IDP_GROUP */
+enum {
+ IDP_GROUP_SUB_NONE = 0, /* default */
+ IDP_GROUP_SUB_MODE_OBJECT = 1, /* object mode settings */
+ IDP_GROUP_SUB_MODE_EDIT = 2, /* mesh edit mode settings */
+ IDP_GROUP_SUB_ENGINE_RENDER = 3, /* render engine settings */
+ IDP_GROUP_SUB_OVERRIDE = 4, /* data override */
+ IDP_GROUP_SUB_MODE_PAINT_WEIGHT = 5, /* weight paint mode settings */
+ IDP_GROUP_SUB_MODE_PAINT_VERTEX = 6, /* vertex paint mode settings */
+};
+
/*->flag*/
enum {
+ /* This IDProp may be statically overridden. Should only be used/be relevant for custom properties. */
+ IDP_FLAG_OVERRIDABLE_STATIC = 1 << 0,
+
IDP_FLAG_GHOST = 1 << 7, /* this means the property is set but RNA will return false when checking
* 'RNA_property_is_set', currently this is a runtime flag */
};
/* add any future new id property types here.*/
+
+/* Static ID override structs. */
+
+typedef struct IDOverrideStaticPropertyOperation {
+ struct IDOverrideStaticPropertyOperation *next, *prev;
+
+ /* Type of override. */
+ short operation;
+ short flag;
+ short pad_s1[2];
+
+ /* Sub-item references, if needed (for arrays or collections only).
+ * We need both reference and local values to allow e.g. insertion into collections (constraints, modifiers...).
+ * In collection case, if names are defined, they are used in priority.
+ * Names are pointers (instead of char[64]) to save some space, NULL when unset.
+ * Indices are -1 when unset. */
+ char *subitem_reference_name;
+ char *subitem_local_name;
+ int subitem_reference_index;
+ int subitem_local_index;
+} IDOverrideStaticPropertyOperation;
+
+/* IDOverridePropertyOperation->operation. */
+enum {
+ /* Basic operations. */
+ IDOVERRIDESTATIC_OP_NOOP = 0, /* Special value, forbids any overriding. */
+
+ IDOVERRIDESTATIC_OP_REPLACE = 1, /* Fully replace local value by reference one. */
+
+ /* Numeric-only operations. */
+ IDOVERRIDESTATIC_OP_ADD = 101, /* Add local value to reference one. */
+ /* Subtract local value from reference one (needed due to unsigned values etc.). */
+ IDOVERRIDESTATIC_OP_SUBTRACT = 102,
+ /* Multiply reference value by local one (more useful than diff for scales and the like). */
+ IDOVERRIDESTATIC_OP_MULTIPLY = 103,
+
+ /* Collection-only operations. */
+ IDOVERRIDESTATIC_OP_INSERT_AFTER = 201, /* Insert after given reference's subitem. */
+ IDOVERRIDESTATIC_OP_INSERT_BEFORE = 202, /* Insert before given reference's subitem. */
+ /* We can add more if needed (move, delete, ...). */
+};
+
+/* IDOverridePropertyOperation->flag. */
+enum {
+ IDOVERRIDESTATIC_FLAG_MANDATORY = 1 << 0, /* User cannot remove that override operation. */
+ IDOVERRIDESTATIC_FLAG_LOCKED = 1 << 1, /* User cannot change that override operation. */
+};
+
+/* A single overridden property, contain all operations on this one. */
+typedef struct IDOverrideStaticProperty {
+ struct IDOverrideStaticProperty *next, *prev;
+
+ /* Path from ID to overridden property. *Does not* include indices/names for final arrays/collections items. */
+ char *rna_path;
+
+ ListBase operations; /* List of overriding operations (IDOverridePropertyOperation) applied to this property. */
+} IDOverrideStaticProperty;
+
+/* Main container for all overriding data info of a data-block. */
+typedef struct IDOverrideStatic {
+ struct ID *reference; /* Reference linked ID which this one overrides. */
+ ListBase properties; /* List of IDOverrideProperty structs. */
+
+ short flag;
+ short pad[3];
+
+ /* Read/write data. */
+ /* Temp ID storing extra override data (used for differential operations only currently).
+ * Always NULL outside of read/write context. */
+ struct ID *storage;
+} IDOverrideStatic;
+
+enum eStaticOverride_Flag {
+ STATICOVERRIDE_AUTO = 1 << 0, /* Allow automatic generation of overriding rules. */
+};
+
/* watch it: Sequence has identical beginning. */
/**
* ID is the first thing included in all serializable types. It
@@ -134,6 +245,13 @@ typedef struct ID {
int pad;
IDProperty *properties;
+ IDOverrideStatic *override_static; /* Reference linked ID which this one overrides. */
+
+ /* Only set for datablocks which are coming from copy-on-write, points to
+ * the original version of it.
+ */
+ struct ID *orig_id;
+
void *py_instance;
} ID;
@@ -257,6 +375,8 @@ typedef enum ID_Type {
ID_PAL = MAKE_ID2('P', 'L'), /* Palette */
ID_PC = MAKE_ID2('P', 'C'), /* PaintCurve */
ID_CF = MAKE_ID2('C', 'F'), /* CacheFile */
+ ID_WS = MAKE_ID2('W', 'S'), /* WorkSpace */
+ ID_LP = MAKE_ID2('L', 'P'), /* LightProbe */
} ID_Type;
/* Only used as 'placeholder' in .blend files for directly linked datablocks. */
@@ -280,7 +400,7 @@ typedef enum ID_Type {
#define ID_REAL_USERS(id) (((ID *)id)->us - ID_FAKE_USERS(id))
#define ID_EXTRA_USERS(id) (((ID *)id)->tag & LIB_TAG_EXTRAUSER ? 1 : 0)
-#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM))
+#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM) && (GS((id)->name) != ID_WS))
#define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : BKE_main_blendfile_path((_bmain)))
#define ID_BLEND_PATH_FROM_GLOBAL(_id) ((_id)->lib ? (_id)->lib->filepath : BKE_main_blendfile_path_from_global())
@@ -289,6 +409,21 @@ typedef enum ID_Type {
#define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL)
+#define ID_IS_STATIC_OVERRIDE(_id) (((ID *)(_id))->override_static != NULL && \
+ ((ID *)(_id))->override_static->reference != NULL)
+
+#define ID_IS_STATIC_OVERRIDE_TEMPLATE(_id) (((ID *)(_id))->override_static != NULL && \
+ ((ID *)(_id))->override_static->reference == NULL)
+
+#define ID_IS_STATIC_OVERRIDE_AUTO(_id) (!ID_IS_LINKED((_id)) && \
+ ID_IS_STATIC_OVERRIDE((_id)) && \
+ (((ID *)(_id))->override_static->flag & STATICOVERRIDE_AUTO))
+
+/* No copy-on-write for these types.
+ * Keep in sync with check_datablocks_copy_on_writable and deg_copy_on_write_is_needed */
+#define ID_TYPE_IS_COW(_id_type) \
+ (!ELEM(_id_type, ID_BR, ID_LS, ID_PAL, ID_IM))
+
#ifdef GS
# undef GS
#endif
@@ -300,7 +435,7 @@ typedef enum ID_Type {
/* id->flag (persitent). */
enum {
- LIB_FAKEUSER = 1 << 9,
+ LIB_FAKEUSER = 1 << 9,
};
/**
@@ -335,6 +470,11 @@ enum {
/* RESET_NEVER tag datablock as a place-holder (because the real one could not be linked from its library e.g.). */
LIB_TAG_MISSING = 1 << 6,
+ /* RESET_NEVER tag datablock as being up-to-date regarding its reference. */
+ LIB_TAG_OVERRIDESTATIC_REFOK = 1 << 9,
+ /* RESET_NEVER tag datablock as needing an auto-override execution, if enabled. */
+ LIB_TAG_OVERRIDESTATIC_AUTOREFRESH = 1 << 17,
+
/* tag datablock has having an extra user. */
LIB_TAG_EXTRAUSER = 1 << 2,
/* tag datablock has having actually increased usercount for the extra virtual user. */
@@ -349,21 +489,34 @@ enum {
/* RESET_AFTER_USE tag existing data before linking so we know what is new. */
LIB_TAG_PRE_EXISTING = 1 << 11,
+ /* The datablock is a copy-on-write/localized version. */
+ LIB_TAG_COPIED_ON_WRITE = 1 << 12,
+ LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT = 1 << 13,
+ LIB_TAG_LOCALIZED = 1 << 14,
+
/* RESET_NEVER tag datablock for freeing etc. behavior (usually set when copying real one into temp/runtime one). */
- LIB_TAG_NO_MAIN = 1 << 12, /* Datablock is not listed in Main database. */
- LIB_TAG_NO_USER_REFCOUNT = 1 << 13, /* Datablock does not refcount usages of other IDs. */
+ LIB_TAG_NO_MAIN = 1 << 15, /* Datablock is not listed in Main database. */
+ LIB_TAG_NO_USER_REFCOUNT = 1 << 16, /* Datablock does not refcount usages of other IDs. */
/* Datablock was not allocated by standard system (BKE_libblock_alloc), do not free its memory
* (usual type-specific freeing is called though). */
- LIB_TAG_NOT_ALLOCATED = 1 << 14,
+ LIB_TAG_NOT_ALLOCATED = 1 << 17,
};
+/* WARNING - when adding flags check on PSYS_RECALC */
enum {
/* RESET_AFTER_USE, used by update code (depsgraph). */
ID_RECALC_NONE = 0,
+ /* Generic recalc flag, when nothing else matches. */
ID_RECALC = 1 << 0,
- ID_RECALC_DATA = 1 << 1,
- ID_RECALC_SKIP_ANIM_TAG = 1 << 2,
- ID_RECALC_ALL = (ID_RECALC | ID_RECALC_DATA),
+ /* Per-component update flags. */
+ ID_RECALC_ANIMATION = 1 << 1,
+ ID_RECALC_DRAW = 1 << 2,
+ ID_RECALC_DRAW_CACHE = 1 << 3,
+ ID_RECALC_GEOMETRY = 1 << 4,
+ ID_RECALC_TRANSFORM = 1 << 5,
+ ID_RECALC_COPY_ON_WRITE = 1 << 6,
+ /* Special flag to check if SOMETHING was changed. */
+ ID_RECALC_ALL = (~(int)0),
};
/* To filter ID types (filter_id) */
@@ -401,15 +554,18 @@ enum {
FILTER_ID_WO = (1 << 26),
FILTER_ID_PA = (1 << 27),
FILTER_ID_CF = (1 << 28),
+ FILTER_ID_WS = (1 << 29),
+ FILTER_ID_LP = (1u << 31),
};
-/* IMPORTANT: this enum matches the order currently use in set_lisbasepointers,
+/* IMPORTANT: this enum matches the order currently use in set_listbasepointers,
* keep them in sync! */
enum {
INDEX_ID_LI = 0,
INDEX_ID_IP,
INDEX_ID_AC,
INDEX_ID_KE,
+ INDEX_ID_PAL,
INDEX_ID_GD,
INDEX_ID_NT,
INDEX_ID_IM,
@@ -427,20 +583,22 @@ enum {
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_LP,
INDEX_ID_WO,
INDEX_ID_MC,
INDEX_ID_SCR,
INDEX_ID_OB,
INDEX_ID_LS,
INDEX_ID_SCE,
+ INDEX_ID_WS,
INDEX_ID_WM,
INDEX_ID_MSK,
INDEX_ID_NULL,
+ INDEX_ID_MAX,
};
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index bcb92cccecd..4d0f4ef1b0f 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -43,7 +43,7 @@
struct SpaceLink;
struct Object;
-struct Group;
+struct Collection;
struct GHash;
/* ************************************************ */
@@ -61,7 +61,8 @@ typedef struct bMotionPathVert {
/* bMotionPathVert->flag */
typedef enum eMotionPathVert_Flag {
/* vert is selected */
- MOTIONPATH_VERT_SEL = (1 << 0)
+ MOTIONPATH_VERT_SEL = (1 << 0),
+ MOTIONPATH_VERT_KEY = (1 << 1),
} eMotionPathVert_Flag;
/* ........ */
@@ -79,6 +80,12 @@ typedef struct bMotionPath {
float color[3]; /* optional custom color */
int line_thickness; /* line thickness */
int flag; /* baking settings - eMotionPath_Flag */
+
+ /* Used for drawing. */
+ struct GPUVertBuf *points_vbo;
+ struct GPUBatch *batch_line;
+ struct GPUBatch *batch_points;
+ void *pad;
} bMotionPath;
/* bMotionPath->flag */
@@ -180,6 +187,34 @@ typedef enum eMotionPaths_BakeFlag {
MOTIONPATH_BAKE_HAS_PATHS = (1 << 2)
} eMotionPath_BakeFlag;
+/* runtime */
+#
+#
+typedef struct bPoseChannelDrawData {
+ float solid_color[4];
+ float wire_color[4];
+
+ int bbone_matrix_len;
+ /* keep last */
+ float bbone_matrix[0][4][4];
+} bPoseChannelDrawData;
+
+struct Mat4;
+struct DualQuat;
+
+typedef struct bPoseChannelRuntime {
+ int bbone_segments;
+ char pad[4];
+
+ /* Rest and posed matrices for segments. */
+ struct Mat4 *bbone_rest_mats;
+ struct Mat4 *bbone_pose_mats;
+
+ /* Delta from rest to pose in matrix and DualQuat form. */
+ struct Mat4 *bbone_deform_mats;
+ struct DualQuat *bbone_dual_quats;
+} bPoseChannelRuntime;
+
/* ************************************************ */
/* Poses */
@@ -205,7 +240,7 @@ typedef struct bPoseChannel {
char constflag; /* for quick detecting which constraints affect this channel */
char selectflag; /* copy of bone flag, so you can work with library armatures, not for runtime use */
char drawflag;
- char bboneflag;
+ char bboneflag DNA_DEPRECATED;
char pad0[4];
struct Bone *bone; /* set on read file or rebuild pose */
@@ -238,6 +273,8 @@ typedef struct bPoseChannel {
float chan_mat[4][4]; /* matrix result of loc/quat/size, and where we put deform in, see next line */
float pose_mat[4][4]; /* constraints accumulate here. in the end, pose_mat = bone->arm_mat * chan_mat
* this matrix is object space */
+ float disp_mat[4][4]; /* for display, pose_mat with bone length applied */
+ float disp_tail_mat[4][4]; /* for display, pose_mat with bone length applied and translated to tail*/
float constinv[4][4]; /* inverse result of constraints.
* doesn't include effect of restposition, parent, and local transform*/
@@ -257,10 +294,18 @@ typedef struct bPoseChannel {
float ease1, ease2;
float scaleIn, scaleOut;
- struct bPoseChannel *bbone_prev; /* next/prev bones to use as handle references when calculating bbones (optional) */
+ struct bPoseChannel *bbone_prev; /* B-Bone custom handles; set on read file or rebuild pose based on pchan->bone data */
struct bPoseChannel *bbone_next;
void *temp; /* use for outliner */
+ /* Runtime data for color and bbone segment matrix. */
+ bPoseChannelDrawData *draw_data;
+
+ /* Points to an original pose channel. */
+ struct bPoseChannel *orig_pchan;
+
+ /* Runtime data. */
+ struct bPoseChannelRuntime runtime;
} bPoseChannel;
@@ -335,6 +380,7 @@ typedef enum ePchan_DrawFlag {
#define PCHAN_CUSTOM_DRAW_SIZE(pchan) \
(pchan)->custom_scale * (((pchan)->drawflag & PCHAN_DRAW_NO_CUSTOM_BONE_SIZE) ? 1.0f : (pchan)->bone->length)
+#ifdef DNA_DEPRECATED_ALLOW
/* PoseChannel->bboneflag */
typedef enum ePchan_BBoneFlag {
/* Use custom reference bones (for roll and handle alignment), instead of immediate neighbors */
@@ -344,6 +390,7 @@ typedef enum ePchan_BBoneFlag {
/* Evaluate end handle as being "relative" */
PCHAN_BBONE_CUSTOM_END_REL = (1 << 3),
} ePchan_BBoneFlag;
+#endif
/* PoseChannel->rotmode and Object->rotmode */
typedef enum eRotationModes {
@@ -418,8 +465,7 @@ typedef enum ePose_Flags {
POSE_RECALCPATHS = (1 << 4),
/* set by BKE_pose_rebuild to give a chance to the IK solver to rebuild IK tree */
POSE_WAS_REBUILT = (1 << 5),
- /* set by game_copy_pose to indicate that this pose is used in the game engine */
- POSE_GAME_ENGINE = (1 << 6),
+ POSE_FLAG_DEPRECATED = (1 << 6), /* deprecated. */
/* pose constraint flags needs to be updated */
POSE_CONSTRAINTS_NEED_UPDATE_FLAGS = (1 << 7),
} ePose_Flags;
@@ -573,8 +619,8 @@ typedef struct bDopeSheet {
ID *source; /* currently ID_SCE (for Dopesheet), and ID_SC (for Grease Pencil) */
ListBase chanbase; /* cache for channels (only initialized when pinned) */ // XXX not used!
- struct Group *filter_grp; /* object group for ADS_FILTER_ONLYOBGROUP filtering option */
- char searchstr[64]; /* string to search for in displayed names of F-Curves for ADS_FILTER_BY_FCU_NAME filtering option */
+ struct Collection *filter_grp; /* object group for option to only include objects that belong to this Collection */
+ char searchstr[64]; /* string to search for in displayed names of F-Curves, or NlaTracks/GP Layers/etc. */
int filterflag; /* flags to use for filtering data */
int flag; /* standard flags */
@@ -596,7 +642,6 @@ typedef enum eDopeSheet_FilterFlag {
/* general filtering */
ADS_FILTER_SUMMARY = (1 << 4), /* for 'DopeSheet' Editors - include 'summary' line */
- ADS_FILTER_ONLYOBGROUP = (1 << 5), /* only the objects in the specified object group get used */
/* datatype-based filtering */
ADS_FILTER_NOSHAPEKEYS = (1 << 6),
@@ -625,7 +670,6 @@ typedef enum eDopeSheet_FilterFlag {
/* general filtering 3 */
ADS_FILTER_INCL_HIDDEN = (1 << 26), /* include 'hidden' channels too (i.e. those from hidden Objects/Bones) */
- ADS_FILTER_BY_FCU_NAME = (1 << 27), /* for F-Curves, filter by the displayed name (i.e. to isolate all Location curves only) */
ADS_FILTER_ONLY_ERRORS = (1 << 28), /* show only F-Curves which are disabled/have errors - for debugging drivers */
/* GPencil Mode */
@@ -662,9 +706,16 @@ typedef struct SpaceAction {
bAction *action; /* the currently active action */
bDopeSheet ads; /* the currently active context (when not showing action) */
- char mode, autosnap; /* mode: editing context; autosnap: automatic keyframe snapping mode */
- short flag; /* flag: bitmapped settings; */
float timeslide; /* for Time-Slide transform mode drawing - current frame? */
+
+ short flag;
+ /* Editing context */
+ char mode;
+ /* Storage for sub-space types. */
+ char mode_prev;
+ char autosnap; /* automatic keyframe snapping mode */
+ char cache_display; /* (eTimeline_Cache_Flag) */
+ char _pad1[6];
} SpaceAction;
/* SpaceAction flag */
@@ -692,7 +743,11 @@ typedef enum eSAction_Flag {
/* don't perform realtime updates */
SACTION_NOREALTIMEUPDATES = (1 << 10),
/* move markers as well as keyframes */
- SACTION_MARKERS_MOVE = (1 << 11)
+ SACTION_MARKERS_MOVE = (1 << 11),
+ /* show interpolation type */
+ SACTION_SHOW_INTERPOLATION = (1 << 12),
+ /* show extremes */
+ SACTION_SHOW_EXTREMES = (1 << 13),
} eSAction_Flag;
/* SpaceAction Mode Settings */
@@ -709,6 +764,8 @@ typedef enum eAnimEdit_Context {
SACTCONT_MASK = 4,
/* cache file */
SACTCONT_CACHEFILE = 5,
+ /* timeline - replacement for the standalone "timeline editor" */
+ SACTCONT_TIMELINE = 6,
} eAnimEdit_Context;
/* SpaceAction AutoSnap Settings (also used by other Animation Editors) */
@@ -727,6 +784,17 @@ typedef enum eAnimEdit_AutoSnap {
SACTSNAP_TSTEP = 5
} eAnimEdit_AutoSnap;
+/* SAction->cache_display */
+typedef enum eTimeline_Cache_Flag {
+ TIME_CACHE_DISPLAY = (1 << 0),
+ TIME_CACHE_SOFTBODY = (1 << 1),
+ TIME_CACHE_PARTICLES = (1 << 2),
+ TIME_CACHE_CLOTH = (1 << 3),
+ TIME_CACHE_SMOKE = (1 << 4),
+ TIME_CACHE_DYNAMICPAINT = (1 << 5),
+ TIME_CACHE_RIGIDBODY = (1 << 6),
+} eTimeline_Cache_Flag;
+
/* ************************************************ */
/* Legacy Data */
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
deleted file mode 100644
index 6461ad5445f..00000000000
--- a/source/blender/makesdna/DNA_actuator_types.h
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file DNA_actuator_types.h
- * \ingroup DNA
- *
- * #bActuator type is specifically for use by Object logic-bricks in the game-engine.
- */
-
-#ifndef __DNA_ACTUATOR_TYPES_H__
-#define __DNA_ACTUATOR_TYPES_H__
-
-struct Object;
-struct Mesh;
-struct Scene;
-struct Group;
-struct Text;
-
-/* ****************** ACTUATORS ********************* */
-
-/* unused now, moved to editobjectactuator in 2.02. Still needed for dna */
-typedef struct bAddObjectActuator {
- int time, pad;
- struct Object *ob;
-} bAddObjectActuator;
-
-typedef struct bActionActuator {
- struct bAction *act; /* Pointer to action */
- short type, flag; /* Playback type */ // not in use
- float sta, end; /* Start & End frames */
- char name[64]; /* For property-driven playback, MAX_NAME */
- char frameProp[64]; /* Set this property to the actions current frame, MAX_NAME */
- short blendin; /* Number of frames of blending */
- short priority; /* Execution priority */
- short layer; /* Animation layer */
- short end_reset; /* Ending the actuator (negative pulse) wont reset the action to its starting frame */
- short strideaxis; /* Displacement axis */
- short blend_mode; /* Layer blending mode */
- float stridelength; /* Displacement incurred by cycle */ // not in use
- float layer_weight; /* How much of the previous layer to use for blending. (<0 = disable, 0 = add mode) */
-} bActionActuator;
-
-typedef struct Sound3D {
- float min_gain;
- float max_gain;
- float reference_distance;
- float max_distance;
- float rolloff_factor;
- float cone_inner_angle;
- float cone_outer_angle;
- float cone_outer_gain;
-} Sound3D;
-
-typedef struct bSoundActuator {
- short flag, sndnr;
- int pad1, pad2;
- short pad3[2];
- float volume, pitch;
- struct bSound *sound;
- struct Sound3D sound3D;
- short type, pad4;
- short pad5, pad6[1];
-} bSoundActuator;
-
-typedef struct bEditObjectActuator {
- int time;
- short type, flag;
- struct Object *ob;
- struct Mesh *me;
- char name[64]; /* MAX_NAME */
- float linVelocity[3]; /* initial lin. velocity on creation */
- float angVelocity[3]; /* initial ang. velocity on creation */
- float mass;
- short localflag; /* flag for the lin & ang. vel: apply locally */
- short dyn_operation;
- short upflag, trackflag; /* flag for up axis and track axis */
- int pad;
-} bEditObjectActuator;
-
-typedef struct bSceneActuator {
- short type, pad1;
- int pad;
- struct Scene *scene;
- struct Object *camera;
-} bSceneActuator;
-
-typedef struct bPropertyActuator {
- int pad, type;
- char name[64], value[64]; /* MAX_NAME */
- struct Object *ob;
-} bPropertyActuator;
-
-typedef struct bObjectActuator {
- short flag, type, otype;
- short damping;
- float forceloc[3], forcerot[3];
- float pad[3], pad1[3];
- float dloc[3], drot[3]; /* angle in radians */
- float linearvelocity[3], angularvelocity[3];
- struct Object *reference;
-} bObjectActuator;
-
-/* deprecated, handled by bActionActuator now */
-typedef struct bIpoActuator {
- short flag, type;
- float sta, end;
- char name[64]; /* MAX_NAME */
- char frameProp[64]; /* Set this property to the actions current frame, MAX_NAME */
-
- short pad1, pad2, pad3, pad4;
-
-} bIpoActuator;
-
-typedef struct bCameraActuator {
- struct Object *ob;
- float height, min, max;
- float damping;
- short pad1, axis;
- float pad2;
-} bCameraActuator;
-
-typedef struct bConstraintActuator {
- short type, mode;
- short flag, damp;
- short time, rotdamp;
- int pad;
- float minloc[3], maxloc[3];
- float minrot[3], maxrot[3];
- char matprop[64]; /* MAX_NAME */
-} bConstraintActuator;
-
-typedef struct bGroupActuator {
- short flag, type;
- int sta, end;
- char name[64]; /* property or groupkey, MAX_NAME */
-
- short pad[3], cur, butsta, butend;/* not referenced, can remove? */
- /* struct Group *group; not used, remove */
-
-} bGroupActuator;
-
-/* I added a few extra fields here, to facilitate conversions */
-typedef struct bRandomActuator {
- int seed;
- int distribution;
- int int_arg_1;
- int int_arg_2;
- float float_arg_1;
- float float_arg_2;
- char propname[64]; /* MAX_NAME */
-} bRandomActuator;
-
-typedef struct bMessageActuator {
- char toPropName[64]; /* Send to all objects with this propertyname. Empty to broadcast. MAX_NAME. */
- struct Object *toObject;/* (Possible future use) pointer to a single destination object. */
- char subject[64]; /* Message Subject to send. MAX_NAME. */
- short bodyType, pad1; /* bodyType is either 'User defined text' or PropName */
- int pad2;
- char body[64]; /* Either User Defined Text or our PropName to send value of, MAX_NAME */
-} bMessageActuator;
-
-typedef struct bGameActuator {
- short flag, type;
- int sta, end;
- char filename[64];
- char loadaniname[64];
-} bGameActuator;
-
-typedef struct bVisibilityActuator {
- /** bit 0: Is this object visible?
- ** bit 1: Apply recursively
- ** bit 2: Is this object an occluder? */
- int flag;
-} bVisibilityActuator;
-
-typedef struct bTwoDFilterActuator {
- char pad[4];
- /* Tells what type of 2D Filter */
- short type;
- /* (flag == 0) means 2D filter is activate and
- * (flag != 0) means 2D filter is inactive */
- short flag;
- int int_arg;
- /* a float argument */
- float float_arg;
- struct Text *text;
-} bTwoDFilterActuator;
-
-typedef struct bParentActuator {
- char pad[2];
- short flag;
- int type;
- struct Object *ob;
-} bParentActuator;
-
-typedef struct bStateActuator {
- int type; /* 0=Set, 1=Add, 2=Rem, 3=Chg */
- unsigned int mask; /* the bits to change */
-} bStateActuator;
-
-typedef struct bArmatureActuator {
- char posechannel[64]; /* MAX_NAME */
- char constraint[64]; /* MAX_NAME */
- int type; /* 0=run, 1=enable, 2=disable, 3=set target, 4=set weight */
- float weight;
- float influence;
- float pad;
- struct Object *target;
- struct Object *subtarget;
-} bArmatureActuator;
-
-typedef struct bSteeringActuator {
- char pad[5];
- char flag;
- short facingaxis;
- int type; /* 0=seek, 1=flee, 2=path following */
- float dist;
- float velocity;
- float acceleration;
- float turnspeed;
- int updateTime;
- struct Object *target;
- struct Object *navmesh;
-} bSteeringActuator;
-
-typedef struct bMouseActuator {
- short type; /* 0=Visibility, 1=Look */
- short flag;
-
- int object_axis[2];
- float threshold[2];
- float sensitivity[2];
- float limit_x[2];
- float limit_y[2];
-} bMouseActuator;
-
-
-typedef struct bActuator {
- struct bActuator *next, *prev, *mynew;
- short type;
- /**
- * Tells what type of actuator data \ref data holds.
- */
- short flag;
- short otype, go;
- char name[64]; /* MAX_NAME */
-
- /**
- * data must point to an object actuator type struct.
- */
- void *data;
-
- /**
- * For ipo's and props: to find out which object the actuator
- * belongs to */
- struct Object *ob;
-
-} bActuator;
-
-/* objectactuator->flag */
-#define ACT_FORCE_LOCAL 1
-#define ACT_TORQUE_LOCAL 2
-#define ACT_SERVO_LIMIT_X 2
-#define ACT_DLOC_LOCAL 4
-#define ACT_SERVO_LIMIT_Y 4
-#define ACT_DROT_LOCAL 8
-#define ACT_SERVO_LIMIT_Z 8
-#define ACT_LIN_VEL_LOCAL 16
-#define ACT_ANG_VEL_LOCAL 32
-//#define ACT_ADD_LIN_VEL_LOCAL 64
-#define ACT_ADD_LIN_VEL 64
-#define ACT_ADD_CHAR_LOC 128
-#define ACT_CHAR_JUMP 256
-
-/* objectactuator->type */
-#define ACT_OBJECT_NORMAL 0
-#define ACT_OBJECT_SERVO 1
-#define ACT_OBJECT_CHARACTER 2
-
-/* actuator->type */
-#define ACT_OBJECT 0
-#define ACT_IPO 1
-#define ACT_LAMP 2
-#define ACT_CAMERA 3
-#define ACT_MATERIAL 4
-#define ACT_SOUND 5
-#define ACT_PROPERTY 6
- /* these two obsolete since 2.02 */
-#define ACT_ADD_OBJECT 7
-#define ACT_END_OBJECT 8
-
-#define ACT_CONSTRAINT 9
-#define ACT_EDIT_OBJECT 10
-#define ACT_SCENE 11
-#define ACT_GROUP 12
-#define ACT_RANDOM 13
-#define ACT_MESSAGE 14
-#define ACT_ACTION 15 /* __ NLA */
-#define ACT_GAME 17
-#define ACT_VISIBILITY 18
-#define ACT_2DFILTER 19
-#define ACT_PARENT 20
-#define ACT_SHAPEACTION 21
-#define ACT_STATE 22
-#define ACT_ARMATURE 23
-#define ACT_STEERING 24
-#define ACT_MOUSE 25
-
-/* actuator flag */
-#define ACT_SHOW 1
-#define ACT_DEL 2
-#define ACT_NEW 4
-#define ACT_LINKED 8
-#define ACT_VISIBLE 16
-#define ACT_PIN 32
-#define ACT_DEACTIVATE 64
-
-/* link codes */
-#define LINK_SENSOR 0
-#define LINK_CONTROLLER 1
-#define LINK_ACTUATOR 2
-
-/* keyboardsensor->type */
-#define SENS_ALL_KEYS 1
-
-/* actionactuator->type */
-#define ACT_ACTION_PLAY 0
-#define ACT_ACTION_PINGPONG 1
-#define ACT_ACTION_FLIPPER 2
-#define ACT_ACTION_LOOP_STOP 3
-#define ACT_ACTION_LOOP_END 4
-#define ACT_ACTION_KEY2KEY 5
-#define ACT_ACTION_FROM_PROP 6
-#define ACT_ACTION_MOTION 7
-
-/* actionactuator->blend_mode */
-#define ACT_ACTION_BLEND 0
-#define ACT_ACTION_ADD 1
-
-/* ipoactuator->type */
-/* used for conversion from 2.01 */
-#define ACT_IPO_FROM_PROP 6
-
-/* groupactuator->type */
-#define ACT_GROUP_PLAY 0
-#define ACT_GROUP_PINGPONG 1
-#define ACT_GROUP_FLIPPER 2
-#define ACT_GROUP_LOOP_STOP 3
-#define ACT_GROUP_LOOP_END 4
-#define ACT_GROUP_FROM_PROP 5
-#define ACT_GROUP_SET 6
-
-/* ipoactuator->flag */
-#define ACT_IPOFORCE (1 << 0)
-#define ACT_IPOEND (1 << 1)
-#define ACT_IPOLOCAL (1 << 2)
-#define ACT_IPOCHILD (1 << 4)
-#define ACT_IPOADD (1 << 5)
-
-/* property actuator->type */
-#define ACT_PROP_ASSIGN 0
-#define ACT_PROP_ADD 1
-#define ACT_PROP_COPY 2
-#define ACT_PROP_TOGGLE 3
-#define ACT_PROP_LEVEL 4
-
-/* constraint flag */
-#define ACT_CONST_NONE 0
-#define ACT_CONST_LOCX 1
-#define ACT_CONST_LOCY 2
-#define ACT_CONST_LOCZ 4
-#define ACT_CONST_ROTX 8
-#define ACT_CONST_ROTY 16
-#define ACT_CONST_ROTZ 32
-#define ACT_CONST_NORMAL 64
-#define ACT_CONST_MATERIAL 128
-#define ACT_CONST_PERMANENT 256
-#define ACT_CONST_DISTANCE 512
-#define ACT_CONST_LOCAL 1024
-#define ACT_CONST_DOROTFH 2048
-
-/* constraint mode */
-#define ACT_CONST_DIRPX 1
-#define ACT_CONST_DIRPY 2
-#define ACT_CONST_DIRPZ 4
-#define ACT_CONST_DIRNX 8
-#define ACT_CONST_DIRNY 16
-#define ACT_CONST_DIRNZ 32
-
-/* constraint type */
-#define ACT_CONST_TYPE_LOC 0
-#define ACT_CONST_TYPE_DIST 1
-#define ACT_CONST_TYPE_ORI 2
-#define ACT_CONST_TYPE_FH 3
-
-/* editObjectActuator->type */
-#define ACT_EDOB_ADD_OBJECT 0
-#define ACT_EDOB_END_OBJECT 1
-#define ACT_EDOB_REPLACE_MESH 2
-#define ACT_EDOB_TRACK_TO 3
-#define ACT_EDOB_DYNAMICS 4
-
-/* editObjectActuator->localflag */
-#define ACT_EDOB_LOCAL_LINV 2
-#define ACT_EDOB_LOCAL_ANGV 4
-
-/* editObjectActuator->flag */
-#define ACT_TRACK_3D 1
-
-/* editObjectActuator->upflag */
-#define ACT_TRACK_UP_X 0
-#define ACT_TRACK_UP_Y 1
-#define ACT_TRACK_UP_Z 2
-
-/* editObjectActuator->trackflag */
-#define ACT_TRACK_TRAXIS_X 0
-#define ACT_TRACK_TRAXIS_Y 1
-#define ACT_TRACK_TRAXIS_Z 2
-#define ACT_TRACK_TRAXIS_NEGX 3
-#define ACT_TRACK_TRAXIS_NEGY 4
-#define ACT_TRACK_TRAXIS_NEGZ 5
-
-/* editObjectActuator->flag for replace mesh actuator */
-#define ACT_EDOB_REPLACE_MESH_NOGFX 2 /* use for replace mesh actuator */
-#define ACT_EDOB_REPLACE_MESH_PHYS 4
-
-/* editObjectActuator->dyn_operation */
-#define ACT_EDOB_RESTORE_DYN 0
-#define ACT_EDOB_SUSPEND_DYN 1
-#define ACT_EDOB_ENABLE_RB 2
-#define ACT_EDOB_DISABLE_RB 3
-#define ACT_EDOB_SET_MASS 4
-
-
-/* SceneActuator->type */
-#define ACT_SCENE_RESTART 0
-#define ACT_SCENE_SET 1
-#define ACT_SCENE_CAMERA 2
-#define ACT_SCENE_ADD_FRONT 3
-#define ACT_SCENE_ADD_BACK 4
-#define ACT_SCENE_REMOVE 5
-#define ACT_SCENE_SUSPEND 6
-#define ACT_SCENE_RESUME 7
-
-
-/* randomAct->distribution */
-#define ACT_RANDOM_BOOL_CONST 0
-#define ACT_RANDOM_BOOL_UNIFORM 1
-#define ACT_RANDOM_BOOL_BERNOUILLI 2
-#define ACT_RANDOM_INT_CONST 3
-#define ACT_RANDOM_INT_UNIFORM 4
-#define ACT_RANDOM_INT_POISSON 5
-#define ACT_RANDOM_FLOAT_CONST 6
-#define ACT_RANDOM_FLOAT_UNIFORM 7
-#define ACT_RANDOM_FLOAT_NORMAL 8
-#define ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL 9
-
-/* SoundActuator->flag */
-#define ACT_SND_3D_SOUND 1
-
-/* SoundActuator->type */
-#define ACT_SND_PLAY_STOP_SOUND 0
-#define ACT_SND_PLAY_END_SOUND 1
-#define ACT_SND_LOOP_STOP_SOUND 2
-#define ACT_SND_LOOP_END_SOUND 3
-#define ACT_SND_LOOP_BIDIRECTIONAL_SOUND 4
-#define ACT_SND_LOOP_BIDIRECTIONAL_STOP_SOUND 5
-
-/* messageactuator->type */
-#define ACT_MESG_MESG 0
-#define ACT_MESG_PROP 1
-
-/* gameactuator->type */
-#define ACT_GAME_LOAD 0
-#define ACT_GAME_START 1
-#define ACT_GAME_RESTART 2
-#define ACT_GAME_QUIT 3
-#define ACT_GAME_SAVECFG 4
-#define ACT_GAME_LOADCFG 5
-#define ACT_GAME_SCREENSHOT 6
-
-/* visibilityact->flag */
-/* Set means the object will become invisible */
-#define ACT_VISIBILITY_INVISIBLE (1 << 0)
-#define ACT_VISIBILITY_RECURSIVE (1 << 1)
-#define ACT_VISIBILITY_OCCLUSION (1 << 2)
-
-/* twodfilter->type */
-#define ACT_2DFILTER_ENABLED -2
-#define ACT_2DFILTER_DISABLED -1
-#define ACT_2DFILTER_NOFILTER 0
-#define ACT_2DFILTER_MOTIONBLUR 1
-#define ACT_2DFILTER_BLUR 2
-#define ACT_2DFILTER_SHARPEN 3
-#define ACT_2DFILTER_DILATION 4
-#define ACT_2DFILTER_EROSION 5
-#define ACT_2DFILTER_LAPLACIAN 6
-#define ACT_2DFILTER_SOBEL 7
-#define ACT_2DFILTER_PREWITT 8
-#define ACT_2DFILTER_GRAYSCALE 9
-#define ACT_2DFILTER_SEPIA 10
-#define ACT_2DFILTER_INVERT 11
-#define ACT_2DFILTER_CUSTOMFILTER 12
-#define ACT_2DFILTER_NUMBER_OF_FILTERS 13
-
-/* parentactuator->type */
-#define ACT_PARENT_SET 0
-#define ACT_PARENT_REMOVE 1
-
-/* parentactuator->flag */
-#define ACT_PARENT_COMPOUND 1
-#define ACT_PARENT_GHOST 2
-
-/* armatureactuator->type */
-#define ACT_ARM_RUN 0
-#define ACT_ARM_ENABLE 1
-#define ACT_ARM_DISABLE 2
-#define ACT_ARM_SETTARGET 3
-#define ACT_ARM_SETWEIGHT 4
-#define ACT_ARM_SETINFLUENCE 5
-/* update this define if more types are added */
-#define ACT_ARM_MAXTYPE 5
-
-/* stateactuator->type */
-#define ACT_STATE_SET 0
-#define ACT_STATE_ADD 1
-#define ACT_STATE_REMOVE 2
-#define ACT_STATE_CHANGE 3
-
-/* steeringactuator->type */
-#define ACT_STEERING_SEEK 0
-#define ACT_STEERING_FLEE 1
-#define ACT_STEERING_PATHFOLLOWING 2
-/* steeringactuator->flag */
-#define ACT_STEERING_SELFTERMINATED 1
-#define ACT_STEERING_ENABLEVISUALIZATION 2
-#define ACT_STEERING_AUTOMATICFACING 4
-#define ACT_STEERING_NORMALUP 8
-#define ACT_STEERING_LOCKZVEL 16
-
-/* mouseactuator->type */
-#define ACT_MOUSE_VISIBILITY 0
-#define ACT_MOUSE_LOOK 1
-
-/* mouseactuator->flag */
-#define ACT_MOUSE_VISIBLE (1 << 0)
-#define ACT_MOUSE_USE_AXIS_X (1 << 1)
-#define ACT_MOUSE_USE_AXIS_Y (1 << 2)
-#define ACT_MOUSE_RESET_X (1 << 3)
-#define ACT_MOUSE_RESET_Y (1 << 4)
-#define ACT_MOUSE_LOCAL_X (1 << 5)
-#define ACT_MOUSE_LOCAL_Y (1 << 6)
-
-/* mouseactuator->object_axis */
-#define ACT_MOUSE_OBJECT_AXIS_X 0
-#define ACT_MOUSE_OBJECT_AXIS_Y 1
-#define ACT_MOUSE_OBJECT_AXIS_Z 2
-
-#endif /* __DNA_ACTUATOR_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 5119c06f927..2d1cbdc490d 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -415,6 +415,8 @@ typedef struct ChannelDriver {
char expression[256]; /* expression to compile for evaluation */
void *expr_comp; /* PyObject - compiled expression, don't save this */
+ struct ExprPyLike_Parsed *expr_simple; /* compiled simple arithmetic expression */
+
float curval; /* result of previous evaluation */
float influence; /* influence of driver on result */ // XXX to be implemented... this is like the constraint influence setting
@@ -438,6 +440,7 @@ typedef enum eDriver_Types {
} eDriver_Types;
/* driver flags */
+/* note: (1<<5) is deprecated; was "DRIVER_FLAG_SHOWDEBUG" */
typedef enum eDriver_Flags {
/* driver has invalid settings (internal flag) */
DRIVER_FLAG_INVALID = (1<<0),
@@ -450,8 +453,6 @@ typedef enum eDriver_Flags {
DRIVER_FLAG_RECOMPILE = (1<<3),
/* 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),
/* include 'self' in the drivers namespace. */
DRIVER_FLAG_USE_SELF = (1<<6),
} eDriver_Flags;
@@ -488,11 +489,13 @@ typedef struct FCurve {
/* value cache + settings */
float curval; /* value stored from last time curve was evaluated (not threadsafe, debug display only!) */
+ /* Value which comes from original DNA ddatablock at a time f-curve was evaluated. */
+ float orig_dna_val;
short flag; /* user-editable settings for this curve */
short extend; /* value-extending mode for this curve (does not cover */
char auto_smoothing; /* auto-handle smoothing mode */
- char pad[7];
+ char pad[3];
/* RNA - data link */
int array_index; /* if applicable, the index of the RNA-array item to get */
@@ -563,42 +566,6 @@ typedef enum eFCurve_Smoothing {
/* ************************************************ */
-/* Animation Reuse - i.e. users of Actions */
-
-/* Retargetting ----------------------------------- */
-
-/* Retargetting Pair
- *
- * Defines what parts of the paths should be remapped from 'abc' to 'xyz'.
- * TODO:
- * - Regrex (possibly provided through PY, though having our own module might be faster)
- * would be important to have at some point. Current replacements are just simple
- * string matches...
- */
-typedef struct AnimMapPair {
- char from[128]; /* part of path to bed replaced */
- char to[128]; /* part of path to replace with */
-} AnimMapPair;
-
-/* Retargetting Information for Actions
- *
- * This should only be used if it is strictly necessary (i.e. user will need to explicitly
- * add this when they find that some channels do not match, or motion is not going to right
- * places). When executing an action, this will be checked to see if it provides any useful
- * remaps for the given paths.
- *
- * NOTE: we currently don't store this in the Action itself, as that causes too many problems.
- */
-// FIXME: will this be too clumsy or slow? If we're using RNA paths anyway, we'll have to accept
-// such consequences...
-typedef struct AnimMapper {
- struct AnimMapper *next, *prev;
-
- bAction *target; /* target action */
- ListBase mappings; /* remapping table (bAnimMapPair) */
-} AnimMapper;
-
-/* ************************************************ */
/* NLA - Non-Linear Animation */
/* NLA Strips ------------------------------------- */
@@ -613,7 +580,6 @@ typedef struct NlaStrip {
ListBase strips; /* 'Child' strips (used for 'meta' strips) */
bAction *act; /* Action that is referenced by this strip (strip is 'user' of the action) */
- AnimMapper *remap; /* Remapping info this strip (for tweaking correspondence of action with context) */
ListBase fcurves; /* F-Curves for controlling this strip's influence and timing */ // TODO: move out?
ListBase modifiers; /* F-Curve modifiers to be applied to the entire strip's referenced F-Curves */
@@ -852,6 +818,7 @@ typedef enum eInsertKeyFlags {
* Used by copy/paste code. */
INSERTKEY_OVERWRITE_FULL = (1<<7),
INSERTKEY_DRIVER = (1<<8), /* for driver FCurves, use driver's "input" value - for easier corrective driver setup */
+ INSERTKEY_CYCLE_AWARE = (1<<9), /* for cyclic FCurves, adjust key timing to preserve the cycle period and flow */
} eInsertKeyFlags;
/* ************************************************ */
@@ -898,10 +865,6 @@ typedef struct AnimData {
* took over to be edited in the Animation Editors)
*/
bAction *tmpact;
- /* remapping-info for active action - should only be used if needed
- * (for 'foreign' actions that aren't working correctly)
- */
- AnimMapper *remap;
/* nla-tracks */
ListBase nla_tracks;
@@ -916,6 +879,8 @@ typedef struct AnimData {
ListBase drivers; /* standard user-created Drivers/Expressions (used as part of a rig) */
ListBase overrides; /* temp storage (AnimOverride) of values for settings that are animated (but the value hasn't been keyframed) */
+ FCurve **driver_array; /* runtime data, for depsgraph evaluation */
+
/* settings for animation evaluation */
int flag; /* user-defined settings */
int recalc; /* depsgraph recalculation flags */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index a7c9c934304..3e68ddcb96b 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -78,8 +78,10 @@ typedef struct Bone {
int layer; /* layers that bone appears on */
short segments; /* for B-bones */
- short pad1;
-
+ char bbone_prev_type; /* Type of next/prev bone handles */
+ char bbone_next_type;
+ struct Bone *bbone_prev; /* Next/prev bones to use as handle references when calculating bbones (optional) */
+ struct Bone *bbone_next;
} Bone;
typedef struct bArmature {
@@ -99,8 +101,6 @@ typedef struct bArmature {
Bone *act_bone; /* active bone */
struct EditBone *act_edbone; /* active editbone (in editmode) */
- void *sketch; /* sketch struct for etch-a-ton */
-
int flag;
int drawtype;
int gevertdeformer; /* how vertex deformation is handled in the ge */
@@ -216,6 +216,14 @@ typedef enum eBone_Flag {
} eBone_Flag;
+/* bone->bbone_prev_type, bbone_next_type */
+typedef enum eBone_BBoneHandleType {
+ BBONE_HANDLE_AUTO = 0, /* Default mode based on parents & children. */
+ BBONE_HANDLE_ABSOLUTE, /* Custom handle in absolute position mode. */
+ BBONE_HANDLE_RELATIVE, /* Custom handle in relative position mode. */
+ BBONE_HANDLE_TANGENT, /* Custom handle in tangent mode (use direction, not location). */
+} eBone_BBoneHandleType;
+
#define MAXBONENAME 64
#endif
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index fc3b4afe18d..d51c94fb536 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -44,6 +44,7 @@
struct CurveMapping;
struct MTex;
struct Image;
+struct Material;
typedef struct BrushClone {
struct Image *image; /* image for clone tool */
@@ -51,6 +52,107 @@ typedef struct BrushClone {
float alpha, pad; /* transparency for drawing of clone image */
} BrushClone;
+
+typedef struct BrushGpencilSettings {
+ float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
+ float draw_sensitivity; /* amount of sensitivity to apply to newly created strokes */
+ float draw_strength; /* amount of alpha strength to apply to newly created strokes */
+ float draw_jitter; /* amount of jitter to apply to newly created strokes */
+ float draw_angle; /* angle when the brush has full thickness */
+ float draw_angle_factor; /* factor to apply when angle change (only 90 degrees) */
+ float draw_random_press; /* factor of randomness for pressure */
+ float draw_random_strength; /* factor of strength for strength */
+ float draw_random_sub; /* factor of randomness for subdivision */
+ short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
+ short draw_subdivide; /* number of times to subdivide new strokes */
+ short flag; /* internal grease pencil drawing flags */
+
+ short thick_smoothlvl; /* number of times to apply thickness smooth factor to new strokes */
+ float thick_smoothfac; /* amount of thickness smoothing to apply to newly created strokes */
+
+ float fill_threshold; /* factor for transparency */
+ short fill_leak; /* number of pixel to consider the leak is too small (x 2) */
+ char pad_1[6];
+
+ int fill_simplylvl; /* number of simplify steps */
+ int fill_draw_mode; /* type of control lines drawing mode */
+ int icon_id; /* icon identifier */
+
+ int input_samples; /* maximum distance before generate new point for very fast mouse movements */
+ float uv_random; /* random factor for UV rotation */
+ int brush_type DNA_DEPRECATED; /* moved to 'Brush.gpencil_tool' */
+ int eraser_mode; /* soft, hard or stroke */
+ float active_smooth; /* smooth while drawing factor */
+ float era_strength_f; /* factor to apply to strength for soft eraser */
+ float era_thickness_f; /* factor to apply to thickness for soft eraser */
+ char pad_2[4];
+
+ struct CurveMapping *curve_sensitivity;
+ struct CurveMapping *curve_strength;
+ struct CurveMapping *curve_jitter;
+
+ /* optional link of material to replace default in context */
+ struct Material *material; /* material */
+} BrushGpencilSettings;
+
+/* BrushGpencilSettings->gp_flag */
+typedef enum eGPDbrush_Flag {
+ /* brush use pressure */
+ GP_BRUSH_USE_PRESSURE = (1 << 0),
+ /* brush use pressure for alpha factor */
+ GP_BRUSH_USE_STENGTH_PRESSURE = (1 << 1),
+ /* brush use pressure for alpha factor */
+ GP_BRUSH_USE_JITTER_PRESSURE = (1 << 2),
+ /* enable screen cursor */
+ GP_BRUSH_ENABLE_CURSOR = (1 << 5),
+ /* fill hide transparent */
+ GP_BRUSH_FILL_HIDE = (1 << 6),
+ /* show fill help lines */
+ GP_BRUSH_FILL_SHOW_HELPLINES = (1 << 7),
+ /* lazy mouse */
+ GP_BRUSH_STABILIZE_MOUSE = (1 << 8),
+ /* lazy mouse override (internal only) */
+ GP_BRUSH_STABILIZE_MOUSE_TEMP = (1 << 9),
+ /* default eraser brush for quick switch */
+ GP_BRUSH_DEFAULT_ERASER = (1 << 10),
+ /* settings group */
+ GP_BRUSH_GROUP_SETTINGS = (1 << 11),
+ /* Random settings group */
+ GP_BRUSH_GROUP_RANDOM = (1 << 12),
+ /* Keep material assigned to brush */
+ GP_BRUSH_MATERIAL_PINNED = (1 << 13),
+ /* Do not show fill color while drawing (no lasso mode) */
+ GP_BRUSH_DISSABLE_LASSO = (1 << 14),
+} eGPDbrush_Flag;
+
+/* BrushGpencilSettings->gp_fill_draw_mode */
+typedef enum eGP_FillDrawModes {
+ GP_FILL_DMODE_BOTH = 0,
+ GP_FILL_DMODE_STROKE = 1,
+ GP_FILL_DMODE_CONTROL = 2,
+} eGP_FillDrawModes;
+
+/* BrushGpencilSettings->gp_eraser_mode */
+typedef enum eGP_BrushEraserMode {
+ GP_BRUSH_ERASER_SOFT = 0,
+ GP_BRUSH_ERASER_HARD = 1,
+ GP_BRUSH_ERASER_STROKE = 2,
+} eGP_BrushEraserMode;
+
+/* BrushGpencilSettings default brush icons */
+typedef enum eGP_BrushIcons {
+ GP_BRUSH_ICON_PENCIL = 1,
+ GP_BRUSH_ICON_PEN = 2,
+ GP_BRUSH_ICON_INK = 3,
+ GP_BRUSH_ICON_INKNOISE = 4,
+ GP_BRUSH_ICON_BLOCK = 5,
+ GP_BRUSH_ICON_MARKER = 6,
+ GP_BRUSH_ICON_FILL = 7,
+ GP_BRUSH_ICON_ERASE_SOFT = 8,
+ GP_BRUSH_ICON_ERASE_HARD = 9,
+ GP_BRUSH_ICON_ERASE_STROKE = 10
+} eGP_BrushIcons;
+
typedef struct Brush {
ID id;
@@ -103,9 +205,12 @@ typedef struct Brush {
float falloff_angle;
char sculpt_tool; /* active sculpt tool */
- char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */
+ char vertexpaint_tool; /* active vertex paint */
+ char weightpaint_tool; /* active weight paint */
char imagepaint_tool; /* active image paint tool */
char mask_tool; /* enum eBrushMaskTool, only used if sculpt_tool is SCULPT_TOOL_MASK */
+ char gpencil_tool; /* Active grease pencil tool. */
+ char _pad0[6];
float autosmooth_factor;
@@ -139,8 +244,10 @@ typedef struct Brush {
float mask_stencil_pos[2];
float mask_stencil_dimension[2];
-} Brush;
+ struct BrushGpencilSettings *gpencil_settings;
+
+} Brush;
typedef struct PaletteColor {
struct PaletteColor *next, *prev;
/* two values, one to store rgb, other to store values for sculpt/weight */
@@ -304,6 +411,28 @@ typedef enum eBrushImagePaintTool {
PAINT_TOOL_MASK = 5
} eBrushImagePaintTool;
+typedef enum eBrushVertexPaintTool {
+ VPAINT_TOOL_DRAW = 0,
+ VPAINT_TOOL_BLUR = 1,
+ VPAINT_TOOL_AVERAGE = 2,
+ VPAINT_TOOL_SMEAR = 3,
+} eBrushVertexPaintTool;
+
+typedef enum eBrushWeightPaintTool {
+ WPAINT_TOOL_DRAW = 0,
+ WPAINT_TOOL_BLUR = 1,
+ WPAINT_TOOL_AVERAGE = 2,
+ WPAINT_TOOL_SMEAR = 3,
+} eBrushWeightPaintTool;
+
+/* BrushGpencilSettings->brush type */
+typedef enum eBrushGPaintTool {
+ GPAINT_TOOL_DRAW = 0,
+ GPAINT_TOOL_FILL = 1,
+ GPAINT_TOOL_ERASE = 2,
+} eBrushGPaintTool;
+
+
/* direction that the brush displaces along */
enum {
SCULPT_DISP_DIR_AREA = 0,
@@ -313,30 +442,6 @@ enum {
SCULPT_DISP_DIR_Z = 4
};
-enum {
- PAINT_BLEND_MIX = 0,
- PAINT_BLEND_ADD = 1,
- PAINT_BLEND_SUB = 2,
- PAINT_BLEND_MUL = 3,
- PAINT_BLEND_BLUR = 4,
- PAINT_BLEND_LIGHTEN = 5,
- PAINT_BLEND_DARKEN = 6,
- PAINT_BLEND_AVERAGE = 7,
- PAINT_BLEND_SMEAR = 8,
- PAINT_BLEND_COLORDODGE = 9,
- PAINT_BLEND_DIFFERENCE = 10,
- PAINT_BLEND_SCREEN = 11,
- PAINT_BLEND_HARDLIGHT = 12,
- PAINT_BLEND_OVERLAY = 13,
- PAINT_BLEND_SOFTLIGHT = 14,
- PAINT_BLEND_EXCLUSION = 15,
- PAINT_BLEND_LUMINOCITY = 16,
- PAINT_BLEND_SATURATION = 17,
- PAINT_BLEND_HUE = 18,
- PAINT_BLEND_ALPHA_SUB = 19,
- PAINT_BLEND_ALPHA_ADD = 20,
-};
-
typedef enum {
BRUSH_MASK_DRAW = 0,
BRUSH_MASK_SMOOTH = 1
@@ -355,5 +460,6 @@ enum {
};
#define MAX_BRUSH_PIXEL_RADIUS 500
+#define GP_MAX_BRUSH_PIXEL_RADIUS 1000
#endif /* __DNA_BRUSH_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index 961f32246d3..7bf89887d8c 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -34,6 +34,8 @@
#include "DNA_defs.h"
#include "DNA_gpu_types.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_image_types.h"
#include "DNA_ID.h"
#ifdef __cplusplus
@@ -59,6 +61,20 @@ typedef struct CameraStereoSettings {
float pole_merge_angle_to;
} CameraStereoSettings;
+/* Background Picture */
+typedef struct CameraBGImage {
+ struct CameraBGImage *next, *prev;
+
+ struct Image *ima;
+ struct ImageUser iuser;
+ struct MovieClip *clip;
+ struct MovieClipUser cuser;
+ float offset[2], scale, rotation;
+ float alpha;
+ short flag;
+ short source;
+} CameraBGImage;
+
typedef struct Camera {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -82,9 +98,19 @@ typedef struct Camera {
struct Object *dof_ob;
struct GPUDOFSettings gpu_dof;
+ /* CameraBGImage reference images */
+ struct ListBase bg_images;
+
char sensor_fit;
char pad[7];
+ /* runtime only, used for drawing */
+ float drwcorners[4][2];
+ float drwtria[2][2];
+ float drwdepth, pad1;
+ float drwfocusmat[4][4];
+ float drwnormalmat[4][4];
+
/* Stereo settings */
struct CameraStereoSettings stereo;
} Camera;
@@ -124,6 +150,7 @@ enum {
#endif
CAM_SHOWSENSOR = (1 << 8),
CAM_SHOW_SAFE_CENTER = (1 << 9),
+ CAM_SHOW_BG_IMAGE = (1 << 10),
};
/* yafray: dof sampling switch */
@@ -136,8 +163,8 @@ enum {
CAMERA_SENSOR_FIT_VERT = 2,
};
-#define DEFAULT_SENSOR_WIDTH 32.0f
-#define DEFAULT_SENSOR_HEIGHT 18.0f
+#define DEFAULT_SENSOR_WIDTH 36.0f
+#define DEFAULT_SENSOR_HEIGHT 24.0f
/* stereo->convergence_mode */
enum {
@@ -159,6 +186,32 @@ enum {
CAM_S3D_POLE_MERGE = (1 << 1),
};
+/* CameraBGImage->flag */
+/* may want to use 1 for select ? */
+enum {
+ CAM_BGIMG_FLAG_EXPANDED = (1 << 1),
+ CAM_BGIMG_FLAG_CAMERACLIP = (1 << 2),
+ CAM_BGIMG_FLAG_DISABLED = (1 << 3),
+ CAM_BGIMG_FLAG_FOREGROUND = (1 << 4),
+
+ /* Camera framing options */
+ CAM_BGIMG_FLAG_CAMERA_ASPECT = (1 << 5), /* don't stretch to fit the camera view */
+ CAM_BGIMG_FLAG_CAMERA_CROP = (1 << 6), /* crop out the image */
+
+ /* Axis flip options */
+ CAM_BGIMG_FLAG_FLIP_X = (1 << 7),
+ CAM_BGIMG_FLAG_FLIP_Y = (1 << 8),
+};
+
+#define CAM_BGIMG_FLAG_EXPANDED (CAM_BGIMG_FLAG_EXPANDED | CAM_BGIMG_FLAG_CAMERACLIP)
+
+/* CameraBGImage->source */
+/* may want to use 1 for select ?*/
+enum {
+ CAM_BGIMG_SOURCE_IMAGE = 0,
+ CAM_BGIMG_SOURCE_MOVIE = 1,
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index 992cfedbc47..39a110d6ad4 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -49,17 +49,17 @@
typedef struct ClothSimSettings {
struct LinkNode *cache; /* UNUSED atm */
float mingoal; /* see SB */
- float Cdis; /* Mechanical damping of springs. */
+ float Cdis DNA_DEPRECATED; /* Mechanical damping of springs. */
float Cvi; /* Viscous/fluid damping. */
float gravity[3]; /* Gravity/external force vector. */
float dt; /* This is the duration of our time step, computed. */
float mass; /* The mass of the entire cloth. */
- float structural; /* Structural spring stiffness. */
+ float structural DNA_DEPRECATED; /* Structural spring stiffness. */
float shear; /* Shear spring stiffness. */
float bending; /* Flexion spring stiffness. */
float max_bend; /* max bending scaling value, min is "bending" */
- float max_struct; /* max structural scaling value, min is "structural" */
- float max_shear; /* max shear scaling value, UNUSED */
+ float max_struct DNA_DEPRECATED; /* max structural scaling value, min is "structural" */
+ float max_shear; /* max shear scaling value */
float max_sewing; /* max sewing force */
float avg_spring_len; /* used for normalized springs */
float timescale; /* parameter how fast cloth runs */
@@ -75,7 +75,7 @@ typedef struct ClothSimSettings {
float density_target; /* minimum density for hair */
float density_strength; /* influence of hair density */
float collider_friction; /* friction with colliders */
- float vel_damping; /* damp the velocity to speed up getting to the resting position */
+ float vel_damping DNA_DEPRECATED; /* damp the velocity to speed up getting to the resting position */
float shrink_min; /* min amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing) */
float shrink_max; /* max amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing) */
@@ -101,6 +101,16 @@ typedef struct ClothSimSettings {
char pad0[4];
struct EffectorWeights *effector_weights;
+
+ short bending_model;
+ short vgroup_shear; /* Vertex group for scaling structural stiffness. */
+ float tension;
+ float compression;
+ float max_tension;
+ float max_compression;
+ float tension_damp; /* Mechanical damping of tension springs. */
+ float compression_damp; /* Mechanical damping of compression springs. */
+ float shear_damp; /* Mechanical damping of shear springs. */
} ClothSimSettings;
@@ -111,14 +121,17 @@ typedef struct ClothCollSettings {
float friction; /* Friction/damping applied on contact with other object.*/
float damping; /* Collision restitution on contact with other object.*/
float selfepsilon; /* for selfcollision */
- float repel_force, distance_repel;
+ float repel_force DNA_DEPRECATED;
+ float distance_repel DNA_DEPRECATED;
int flags; /* collision flags defined in BKE_cloth.h */
- short self_loop_count; /* How many iterations for the selfcollision loop */
+ short self_loop_count DNA_DEPRECATED; /* How many iterations for the selfcollision loop */
short loop_count; /* How many iterations for the collision loop. */
int pad;
- struct Group *group; /* Only use colliders from this group of objects */
+ struct Collection *group; /* Only use colliders from this group of objects */
short vgroup_selfcol; /* vgroup to paint which vertices are used for self collisions */
short pad2[3];
+ float clamp; /* Impulse clamp for object collisions. */
+ float self_clamp; /* Impulse clamp for self collisions. */
} ClothCollSettings;
diff --git a/source/blender/makesdna/DNA_collection_types.h b/source/blender/makesdna/DNA_collection_types.h
new file mode 100644
index 00000000000..f08725e9fe0
--- /dev/null
+++ b/source/blender/makesdna/DNA_collection_types.h
@@ -0,0 +1,94 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): mar-2001 nzc
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_collection_types.h
+ * \ingroup DNA
+ *
+ * \brief Object groups, one object can be in many groups at once.
+ */
+
+#ifndef __DNA_COLLECTION_TYPES_H__
+#define __DNA_COLLECTION_TYPES_H__
+
+#include "DNA_defs.h"
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+struct Object;
+struct Collection;
+
+typedef struct CollectionObject {
+ struct CollectionObject *next, *prev;
+ struct Object *ob;
+} CollectionObject;
+
+
+typedef struct CollectionChild {
+ struct CollectionChild *next, *prev;
+ struct Collection *collection;
+} CollectionChild;
+
+
+typedef struct Collection {
+ ID id;
+
+ ListBase gobject; /* CollectionObject */
+ ListBase children; /* CollectionChild */
+
+ struct PreviewImage *preview;
+
+ unsigned int layer DNA_DEPRECATED;
+ float dupli_ofs[3];
+
+ short flag, pad[3];
+
+ /* Runtime. Cache of objects in this collection and all its
+ * children. This is created on demand when e.g. some physics
+ * simulation needs it, we don't want to have it for every
+ * collections due to memory usage reasons. */
+ ListBase object_cache;
+
+ /* Runtime. List of collections that are a parent of this
+ * datablock. */
+ ListBase parents;
+
+ /* Deprecated */
+ struct SceneCollection *collection DNA_DEPRECATED;
+ struct ViewLayer *view_layer DNA_DEPRECATED;
+} Collection;
+
+/* Collection->flag */
+enum {
+ COLLECTION_RESTRICT_VIEW = (1 << 0), /* Hidden in viewport. */
+ COLLECTION_RESTRICT_SELECT = (1 << 1), /* Not selectable in viewport. */
+ COLLECTION_DISABLED_DEPRECATED = (1 << 2), /* Not used anymore */
+ COLLECTION_RESTRICT_RENDER = (1 << 3), /* Hidden in renders. */
+ COLLECTION_HAS_OBJECT_CACHE = (1 << 4), /* Runtime: object_cache is populated. */
+ COLLECTION_IS_MASTER = (1 << 5), /* Is master collection embedded in the scene. */
+};
+
+#endif /* __DNA_COLLECTION_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index 8ed38b0b05d..01f0b06c178 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -82,6 +82,9 @@ typedef struct CurveMapping {
float bwmul[3]; /* black/white point multiply value, for speed */
float sample[3]; /* sample values, if flag set it draws line and intersection */
+
+ short tone;
+ short pad[3];
} CurveMapping;
/* cumapping->flag */
@@ -99,8 +102,15 @@ typedef enum eCurveMappingPreset {
CURVE_PRESET_MID9 = 4,
CURVE_PRESET_ROUND = 5,
CURVE_PRESET_ROOT = 6,
+ CURVE_PRESET_GAUSS = 7,
} eCurveMappingPreset;
+/* CurveMapping->tone */
+typedef enum eCurveMappingTone {
+ CURVE_TONE_STANDARD = 0,
+ CURVE_TONE_FILMLIKE = 2,
+} eCurveMappingTone;
+
/* histogram->mode */
enum {
HISTO_MODE_LUMA = 0,
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index e49cd65fa9b..a2c756dd197 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -58,14 +58,14 @@ typedef struct bConstraint {
short type; /* Constraint type */
short flag; /* Flag - General Settings */
- char ownspace; /* Space that owner should be evaluated in */
+ char ownspace; /* Space that owner should be evaluated in */
char tarspace; /* Space that target should be evaluated in (only used if 1 target) */
char name[64]; /* Constraint name, MAX_NAME */
short pad;
- float enforce; /* Amount of influence exherted by constraint (0.0-1.0) */
+ float enforce; /* Amount of influence exherted by constraint (0.0-1.0) */
float headtail; /* Point along subtarget bone where the actual target is. 0=head (default for all), 1=tail*/
struct Ipo *ipo DNA_DEPRECATED; /* local influence ipo or driver */ /* old animation system, deprecated for 2.5 */
@@ -94,6 +94,8 @@ typedef struct bConstraintTarget {
short flag; /* runtime settings (for editor, etc.) */
short type; /* type of target (eConstraintObType) */
short rotOrder; /* rotation order for target (as defined in BLI_math.h) */
+ float weight; /* weight for armature deform */
+ char pad[4];
} bConstraintTarget;
/* bConstraintTarget -> flag */
@@ -180,6 +182,13 @@ typedef struct bSplineIKConstraint {
float bulge_smooth;
} bSplineIKConstraint;
+/* Armature Constraint */
+typedef struct bArmatureConstraint {
+ int flag; /* general settings/state indicators accessed by bitmapping */
+ char pad[4];
+
+ ListBase targets; /* a list of targets that this constraint has (bConstraintTarget-s) */
+} bArmatureConstraint;
/* Single-target subobject constraints --------------------- */
@@ -345,19 +354,19 @@ typedef struct bTransformConstraint {
char map[3]; /* defines which target-axis deform is copied by each owner-axis */
char expo; /* extrapolate motion? if 0, confine to ranges */
- float from_min[3]; /* from_min/max defines range of target transform */
- float from_max[3]; /* to map on to to_min/max range. */
+ float from_min[3]; /* from_min/max defines range of target transform */
+ float from_max[3]; /* to map on to to_min/max range. */
float to_min[3]; /* range of motion on owner caused by target */
float to_max[3];
- float from_min_rot[3]; /* from_min/max defines range of target transform */
- float from_max_rot[3]; /* to map on to to_min/max range. */
+ float from_min_rot[3]; /* from_min/max defines range of target transform */
+ float from_max_rot[3]; /* to map on to to_min/max range. */
float to_min_rot[3]; /* range of motion on owner caused by target */
float to_max_rot[3];
- float from_min_scale[3]; /* from_min/max defines range of target transform */
- float from_max_scale[3]; /* to map on to to_min/max range. */
- float to_min_scale[3]; /* range of motion on owner caused by target */
+ float from_min_scale[3]; /* from_min/max defines range of target transform */
+ float from_max_scale[3]; /* to map on to to_min/max range. */
+ float to_min_scale[3]; /* range of motion on owner caused by target */
float to_max_scale[3];
} bTransformConstraint;
@@ -428,7 +437,10 @@ typedef struct bShrinkwrapConstraint {
char projAxis; /* axis to project/constrain */
char projAxisSpace; /* space to project axis in */
float projLimit; /* distance to search */
- char pad[4];
+ char shrinkMode; /* inside/outside/on surface (see MOD shrinkwrap) */
+ char flag; /* options */
+ char trackAxis; /* axis to align to normal */
+ char pad;
} bShrinkwrapConstraint;
/* Follow Track constraints */
@@ -488,7 +500,7 @@ typedef enum eBConstraint_Types {
CONSTRAINT_TYPE_DISTLIMIT = 14, /* limit distance */
CONSTRAINT_TYPE_STRETCHTO = 15, /* claiming this to be mine :) is in tuhopuu bjornmose */
CONSTRAINT_TYPE_MINMAX = 16, /* floor constraint */
- CONSTRAINT_TYPE_RIGIDBODYJOINT = 17, /* rigidbody constraint */
+ /* CONSTRAINT_TYPE_DEPRECATED = 17 */
CONSTRAINT_TYPE_CLAMPTO = 18, /* clampto constraint */
CONSTRAINT_TYPE_TRANSFORM = 19, /* transformation (loc/rot/size -> loc/rot/size) constraint */
CONSTRAINT_TYPE_SHRINKWRAP = 20, /* shrinkwrap (loc/rot) constraint */
@@ -501,6 +513,7 @@ typedef enum eBConstraint_Types {
CONSTRAINT_TYPE_CAMERASOLVER = 27, /* Camera Solver Constraint */
CONSTRAINT_TYPE_OBJECTSOLVER = 28, /* Object Solver Constraint */
CONSTRAINT_TYPE_TRANSFORM_CACHE = 29, /* Transform Cache Constraint */
+ CONSTRAINT_TYPE_ARMATURE = 30, /* Armature Deform Constraint */
/* NOTE: no constraints are allowed to be added after this */
NUM_CONSTRAINT_TYPES
@@ -524,8 +537,12 @@ typedef enum eBConstraint_Flags {
CONSTRAINT_PROXY_LOCAL = (1<<8),
/* indicates that constraint is temporarily disabled (only used in GE) */
CONSTRAINT_OFF = (1<<9),
- /* use bbone curve shape when calculating headtail values */
+ /* use bbone curve shape when calculating headtail values (also used by dependency graph!) */
CONSTRAINT_BBONE_SHAPE = (1<<10),
+ /* That constraint has been inserted in local override (i.e. it can be fully edited!). */
+ CONSTRAINT_STATICOVERRIDE_LOCAL = (1 << 11),
+ /* use full transformation (not just segment locations) - only set at runtime */
+ CONSTRAINT_BBONE_SHAPE_FULL = (1 << 12),
} eBConstraint_Flags;
/* bConstraint->ownspace/tarspace */
@@ -582,7 +599,8 @@ typedef enum eCopyScale_Flags {
SIZELIKE_X = (1<<0),
SIZELIKE_Y = (1<<1),
SIZELIKE_Z = (1<<2),
- SIZELIKE_OFFSET = (1<<3)
+ SIZELIKE_OFFSET = (1<<3),
+ SIZELIKE_MULTIPLY = (1<<4),
} eCopyScale_Flags;
/* bTransformConstraint.to/from */
@@ -629,6 +647,23 @@ typedef enum eTrackToAxis_Modes {
TRACK_nZ = 5
} eTrackToAxis_Modes;
+/* Shrinkwrap flags */
+typedef enum eShrinkwrap_Flags {
+ /* Also raycast in the opposite direction. */
+ CON_SHRINKWRAP_PROJECT_OPPOSITE = (1 << 0),
+ /* Invert the cull mode when projecting opposite. */
+ CON_SHRINKWRAP_PROJECT_INVERT_CULL = (1 << 1),
+ /* Align the specified axis to the target normal. */
+ CON_SHRINKWRAP_TRACK_NORMAL = (1 << 2),
+
+ /* Ignore front faces in project; same value as MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE */
+ CON_SHRINKWRAP_PROJECT_CULL_FRONTFACE = (1 << 3),
+ /* Ignore back faces in project; same value as MOD_SHRINKWRAP_CULL_TARGET_BACKFACE */
+ CON_SHRINKWRAP_PROJECT_CULL_BACKFACE = (1 << 4),
+} eShrinkwrap_Flags;
+
+#define CON_SHRINKWRAP_PROJECT_CULL_MASK (CON_SHRINKWRAP_PROJECT_CULL_FRONTFACE | CON_SHRINKWRAP_PROJECT_CULL_BACKFACE)
+
/* FollowPath flags */
typedef enum eFollowPath_Flags {
FOLLOWPATH_FOLLOW = (1<<0),
@@ -722,6 +757,13 @@ typedef enum eSplineIK_XZScaleModes {
CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC = 3
} eSplineIK_XZScaleModes;
+/* bArmatureConstraint -> flag */
+typedef enum eArmature_Flags {
+ CONSTRAINT_ARMATURE_QUATERNION = (1<<0), /* use dual quaternion blending */
+ CONSTRAINT_ARMATURE_ENVELOPE = (1<<1), /* use envelopes */
+ CONSTRAINT_ARMATURE_CUR_LOCATION = (1<<2), /* use current bone location */
+} eArmature_Flags;
+
/* MinMax (floor) flags */
typedef enum eFloor_Flags {
MINMAX_STICKY = (1<<0),
@@ -841,10 +883,6 @@ typedef enum eObjectSolver_Flags {
OBJECTSOLVER_ACTIVECLIP = (1<<0)
} eObjectSolver_Flags;
-/* Rigid-Body Constraint */
-#define CONSTRAINT_DRAW_PIVOT 0x40
-#define CONSTRAINT_DISABLE_LINKED_COLLISION 0x80
-
/* ObjectSolver Constraint -> flag */
typedef enum eStretchTo_Flags {
STRETCHTOCON_USE_BULGE_MIN = (1 << 0),
diff --git a/source/blender/makesdna/DNA_controller_types.h b/source/blender/makesdna/DNA_controller_types.h
deleted file mode 100644
index db0c8078211..00000000000
--- a/source/blender/makesdna/DNA_controller_types.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file DNA_controller_types.h
- * \ingroup DNA
- *
- * #bController type is specifically for use by Object logic-bricks in the game-engine.
- */
-
-#ifndef __DNA_CONTROLLER_TYPES_H__
-#define __DNA_CONTROLLER_TYPES_H__
-
-struct bActuator;
-struct Text;
-struct bSensor;
-
-/* ****************** CONTROLLERS ********************* */
-
-typedef struct bExpressionCont {
- char str[128];
-} bExpressionCont;
-
-typedef struct bPythonCont {
- struct Text *text;
- char module[64];
- int mode;
- int flag; /* only used for debug now */
-} bPythonCont;
-
-typedef struct bController {
- struct bController *next, *prev, *mynew;
- short type, flag, inputs, totlinks;
- short otype, totslinks, pad2, pad3;
-
- char name[64];
- void *data;
-
- struct bActuator **links;
-
- struct bSensor **slinks;
- short val, valo;
- unsigned int state_mask;
-
-} bController;
-
-/* controller->type */
-#define CONT_LOGIC_AND 0
-#define CONT_LOGIC_OR 1
-#define CONT_EXPRESSION 2
-#define CONT_PYTHON 3
-#define CONT_LOGIC_NAND 4
-#define CONT_LOGIC_NOR 5
-#define CONT_LOGIC_XOR 6
-#define CONT_LOGIC_XNOR 7
-
-/* controller->flag */
-#define CONT_SHOW 1
-#define CONT_DEL 2
-#define CONT_NEW 4
-#define CONT_MASK 8
-#define CONT_PRIO 16
-#define CONT_DEACTIVATE 32
-
-/* pyctrl->flag */
-#define CONT_PY_DEBUG 1
-
-/* pyctrl->mode */
-#define CONT_PY_SCRIPT 0
-#define CONT_PY_MODULE 1
-
-#endif /* __DNA_CONTROLLER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index e4db69fb1b6..0cf60a98376 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -225,11 +225,12 @@ typedef struct Curve {
/* edit, index in active nurb (BPoint or BezTriple) */
int actvert;
- char pad[4];
+ char overflow;
+ char spacemode, align_y;
+ char pad[3];
/* font part */
short lines;
- char spacemode, align_y;
float spacing, linedist, shear, fsize, wordspace, ulpos, ulheight;
float xof, yof;
float linewidth;
@@ -264,7 +265,10 @@ typedef struct Curve {
char bevfac1_mapping, bevfac2_mapping;
char pad2[2];
+ float fsize_realtime;
+ float pad3;
+ void *batch_cache;
} Curve;
#define CURVE_VFONT_ANY(cu) \
@@ -277,11 +281,13 @@ enum {
CU_AUTOSPACE = 1,
};
+#if 0 /* Moved to overlay options in 2.8 */
/* Curve.drawflag */
enum {
CU_HIDE_HANDLES = 1 << 0,
CU_HIDE_NORMALS = 1 << 1,
};
+#endif
/* Curve.flag */
enum {
@@ -333,7 +339,15 @@ enum {
CU_ALIGN_Y_TOP_BASELINE = 0,
CU_ALIGN_Y_TOP = 1,
CU_ALIGN_Y_CENTER = 2,
- CU_ALIGN_Y_BOTTOM = 3,
+ CU_ALIGN_Y_BOTTOM_BASELINE = 3,
+ CU_ALIGN_Y_BOTTOM = 4,
+};
+
+/* Curve.overflow. */
+enum {
+ CU_OVERFLOW_NONE = 0,
+ CU_OVERFLOW_SCALE = 1,
+ CU_OVERFLOW_TRUNCATE = 2,
};
/* Nurb.flag */
@@ -441,8 +455,8 @@ typedef enum eBezTriple_KeyframeType {
/* checks if the given BezTriple is selected */
#define BEZT_ISSEL_ANY(bezt) \
(((bezt)->f2 & SELECT) || ((bezt)->f1 & SELECT) || ((bezt)->f3 & SELECT))
-#define BEZT_ISSEL_ANY_HIDDENHANDLES(cu, bezt) \
- (((cu)->drawflag & CU_HIDE_HANDLES) ? (bezt)->f2 & SELECT : BEZT_ISSEL_ANY(bezt))
+#define BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) \
+ ((((v3d) != NULL) && ((v3d)->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) ? (bezt)->f2 & SELECT : BEZT_ISSEL_ANY(bezt))
#define BEZT_SEL_ALL(bezt) { (bezt)->f1 |= SELECT; (bezt)->f2 |= SELECT; (bezt)->f3 |= SELECT; } ((void)0)
#define BEZT_DESEL_ALL(bezt) { (bezt)->f1 &= ~SELECT; (bezt)->f2 &= ~SELECT; (bezt)->f3 &= ~SELECT; } ((void)0)
@@ -453,13 +467,14 @@ typedef enum eBezTriple_KeyframeType {
/* CharInfo.flag */
enum {
- /* note: CU_CHINFO_WRAP and CU_CHINFO_SMALLCAPS_TEST are set dynamically */
+ /* note: CU_CHINFO_WRAP, CU_CHINFO_SMALLCAPS_TEST and CU_CHINFO_TRUNCATE are set dynamically */
CU_CHINFO_BOLD = 1 << 0,
CU_CHINFO_ITALIC = 1 << 1,
CU_CHINFO_UNDERLINE = 1 << 2,
CU_CHINFO_WRAP = 1 << 3, /* wordwrap occurred here */
CU_CHINFO_SMALLCAPS = 1 << 4,
CU_CHINFO_SMALLCAPS_CHECK = 1 << 5, /* set at runtime, checks if case switching is needed */
+ CU_CHINFO_OVERFLOW = 1 << 6, /* Set at runtime, indicates char that doesn't fit in text boxes. */
};
/* mixed with KEY_LINEAR but define here since only curve supports */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 2d1ffaa53eb..0e0b1d669d9 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -92,13 +92,13 @@ typedef enum CustomDataType {
CD_MCOL = 6,
CD_ORIGINDEX = 7,
CD_NORMAL = 8,
-/* CD_POLYINDEX = 9, */
+ CD_FACEMAP = 9, /* exclusive face group, each face can only be part of one */
CD_PROP_FLT = 10,
CD_PROP_INT = 11,
CD_PROP_STR = 12,
CD_ORIGSPACE = 13, /* for modifier stack face location mapping */
CD_ORCO = 14,
- CD_MTEXPOLY = 15,
+/* CD_MTEXPOLY = 15, */ /* deprecated */
CD_MLOOPUV = 16,
CD_MLOOPCOL = 17,
CD_TANGENT = 18,
@@ -143,13 +143,13 @@ typedef enum CustomDataType {
#define CD_MASK_MCOL (1 << CD_MCOL)
#define CD_MASK_ORIGINDEX (1 << CD_ORIGINDEX)
#define CD_MASK_NORMAL (1 << CD_NORMAL)
-// #define CD_MASK_POLYINDEX (1 << CD_POLYINDEX)
+#define CD_MASK_FACEMAP (1 << CD_FACEMAP)
#define CD_MASK_PROP_FLT (1 << CD_PROP_FLT)
#define CD_MASK_PROP_INT (1 << CD_PROP_INT)
#define CD_MASK_PROP_STR (1 << CD_PROP_STR)
#define CD_MASK_ORIGSPACE (1 << CD_ORIGSPACE)
#define CD_MASK_ORCO (1 << CD_ORCO)
-#define CD_MASK_MTEXPOLY (1 << CD_MTEXPOLY)
+// #define CD_MASK_MTEXPOLY (1 << CD_MTEXPOLY) /* DEPRECATED */
#define CD_MASK_MLOOPUV (1 << CD_MLOOPUV)
#define CD_MASK_MLOOPCOL (1 << CD_MLOOPCOL)
#define CD_MASK_TANGENT (1 << CD_TANGENT)
diff --git a/source/blender/makesdna/DNA_defs.h b/source/blender/makesdna/DNA_defs.h
index fc9dd8f06a9..bfa8da02707 100644
--- a/source/blender/makesdna/DNA_defs.h
+++ b/source/blender/makesdna/DNA_defs.h
@@ -44,6 +44,12 @@
# endif
#endif
+#ifdef __GNUC__
+# define DNA_PRIVATE_ATTR __attribute__ ((deprecated))
+#else
+# define DNA_PRIVATE_ATTR
+#endif
+
/* poison pragma */
#ifdef DNA_DEPRECATED_ALLOW
diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h
index b0afe99a77d..589135e1d58 100644
--- a/source/blender/makesdna/DNA_dynamicpaint_types.h
+++ b/source/blender/makesdna/DNA_dynamicpaint_types.h
@@ -104,7 +104,7 @@ typedef struct DynamicPaintSurface {
struct DynamicPaintCanvasSettings *canvas; /* for fast RNA access */
struct PaintSurfaceData *data;
- struct Group *brush_group;
+ struct Collection *brush_group;
struct EffectorWeights *effector_weights;
/* cache */
@@ -163,7 +163,7 @@ enum {
/* Canvas settings */
typedef struct DynamicPaintCanvasSettings {
struct DynamicPaintModifierData *pmd; /* for fast RNA access */
- struct DerivedMesh *dm;
+ struct Mesh *mesh;
struct ListBase surfaces;
short active_sur, flags;
@@ -177,7 +177,7 @@ typedef struct DynamicPaintCanvasSettings {
/* flags */
enum {
MOD_DPAINT_PART_RAD = 1 << 0, /* use particle radius */
- MOD_DPAINT_USE_MATERIAL = 1 << 1, /* use object material */
+ //MOD_DPAINT_USE_MATERIAL = 1 << 1, /* DNA_DEPRECATED */
MOD_DPAINT_ABS_ALPHA = 1 << 2, /* don't increase alpha unless paint alpha is higher than existing */
MOD_DPAINT_ERASE = 1 << 3, /* removes paint */
@@ -229,9 +229,8 @@ enum {
/* Brush settings */
typedef struct DynamicPaintBrushSettings {
struct DynamicPaintModifierData *pmd; /* for fast RNA access */
- struct DerivedMesh *dm;
+ struct Mesh *mesh;
struct ParticleSystem *psys;
- struct Material *mat;
int flags;
int collision;
diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h
index 36c46b23c9e..373b1584c77 100644
--- a/source/blender/makesdna/DNA_effect_types.h
+++ b/source/blender/makesdna/DNA_effect_types.h
@@ -97,7 +97,7 @@ typedef struct Particle {
short mat_nr, rt;
} Particle;
-struct Group;
+struct Collection;
typedef struct PartEff {
struct PartEff *next, *prev;
@@ -122,7 +122,7 @@ typedef struct PartEff {
float imat[4][4]; /* inverse matrix of parent Object */
Particle *keys;
- struct Group *group;
+ struct Collection *group;
} PartEff;
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index 98d433d8454..24fb1c86627 100644
--- a/source/blender/makesdna/DNA_fileglobal_types.h
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -32,9 +32,6 @@
#ifndef __DNA_FILEGLOBAL_TYPES_H__
#define __DNA_FILEGLOBAL_TYPES_H__
-struct bScreen;
-struct Scene;
-
/**
* FileGlobal stores a part of the current user-interface settings at
* the moment of saving, and the file-specific settings.
@@ -46,6 +43,9 @@ typedef struct FileGlobal {
char pad[6];
struct bScreen *curscreen;
struct Scene *curscene;
+ struct ViewLayer *cur_view_layer;
+ void *pad1;
+
int fileflags;
int globalf;
uint64_t build_commit_timestamp; /* commit timestamp from buildinfo */
diff --git a/source/blender/makesdna/DNA_freestyle_types.h b/source/blender/makesdna/DNA_freestyle_types.h
index b3c881d09fc..36cf151b76e 100644
--- a/source/blender/makesdna/DNA_freestyle_types.h
+++ b/source/blender/makesdna/DNA_freestyle_types.h
@@ -40,7 +40,7 @@ extern "C" {
#endif
struct FreestyleLineStyle;
-struct Group;
+struct Collection;
struct Text;
/* FreestyleConfig::flags */
@@ -125,7 +125,7 @@ typedef struct FreestyleLineSet {
int qi_start, qi_end;
int edge_types, exclude_edge_types; /* feature edge types */
int pad2;
- struct Group *group; /* group of target objects */
+ struct Collection *group; /* group of target objects */
struct FreestyleLineStyle *linestyle;
} FreestyleLineSet;
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
new file mode 100644
index 00000000000..af680b8fb9d
--- /dev/null
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -0,0 +1,483 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_gpencil_modifier_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_GPENCIL_MODIFIER_TYPES_H__
+#define __DNA_GPENCIL_MODIFIER_TYPES_H__
+
+#include "DNA_defs.h"
+#include "DNA_listBase.h"
+
+/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
+ * (ONLY ADD NEW ITEMS AT THE END)
+ */
+
+struct RNG;
+
+typedef enum GpencilModifierType {
+ eGpencilModifierType_None = 0,
+ eGpencilModifierType_Noise = 1,
+ eGpencilModifierType_Subdiv = 2,
+ eGpencilModifierType_Thick = 3,
+ eGpencilModifierType_Tint = 4,
+ eGpencilModifierType_Array = 5,
+ eGpencilModifierType_Build = 6,
+ eGpencilModifierType_Opacity = 7,
+ eGpencilModifierType_Color = 8,
+ eGpencilModifierType_Lattice = 9,
+ eGpencilModifierType_Simplify = 10,
+ eGpencilModifierType_Smooth = 11,
+ eGpencilModifierType_Hook = 12,
+ eGpencilModifierType_Offset = 13,
+ eGpencilModifierType_Mirror = 14,
+ eGpencilModifierType_Armature = 15,
+ eGpencilModifierType_Time = 16,
+ NUM_GREASEPENCIL_MODIFIER_TYPES
+} GpencilModifierType;
+
+typedef enum GpencilModifierMode {
+ eGpencilModifierMode_Realtime = (1 << 0),
+ eGpencilModifierMode_Render = (1 << 1),
+ eGpencilModifierMode_Editmode = (1 << 2),
+ eGpencilModifierMode_Expanded = (1 << 3),
+} GpencilModifierMode;
+
+typedef enum {
+ /* This modifier has been inserted in local override, and hence can be fully edited. */
+ eGpencilModifierFlag_StaticOverride_Local = (1 << 0),
+} GpencilModifierFlag;
+
+typedef struct GpencilModifierData {
+ struct GpencilModifierData *next, *prev;
+
+ int type, mode;
+ int stackindex;
+ short flag;
+ short pad;
+ char name[64]; /* MAX_NAME */
+
+ char *error;
+} GpencilModifierData;
+
+typedef struct NoiseGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* several flags */
+ float factor; /* factor of noise */
+ int step; /* how many frames before recalculate randoms */
+ int gp_frame; /* last gp frame used */
+ int scene_frame; /* last scene frame used */
+ float vrand1, vrand2; /* random values */
+ struct RNG *rng;
+ int layer_pass; /* custom index for passes */
+ char pad_[4];
+} NoiseGpencilModifierData;
+
+typedef enum eNoiseGpencil_Flag {
+ GP_NOISE_USE_RANDOM = (1 << 0),
+ GP_NOISE_MOD_LOCATION = (1 << 1),
+ GP_NOISE_MOD_STRENGTH = (1 << 2),
+ GP_NOISE_MOD_THICKNESS = (1 << 3),
+ GP_NOISE_FULL_STROKE = (1 << 4),
+ GP_NOISE_MOVE_EXTREME = (1 << 5),
+ GP_NOISE_INVERT_LAYER = (1 << 6),
+ GP_NOISE_INVERT_PASS = (1 << 7),
+ GP_NOISE_INVERT_VGROUP = (1 << 8),
+ GP_NOISE_MOD_UV = (1 << 9),
+ GP_NOISE_INVERT_LAYERPASS = (1 << 10),
+} eNoiseGpencil_Flag;
+
+typedef struct SubdivGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ int level; /* factor of subdivision */
+ int layer_pass; /* custom index for passes */
+} SubdivGpencilModifierData;
+
+typedef enum eSubdivGpencil_Flag {
+ GP_SUBDIV_SIMPLE = (1 << 0),
+ GP_SUBDIV_INVERT_LAYER = (1 << 1),
+ GP_SUBDIV_INVERT_PASS = (1 << 2),
+ GP_SUBDIV_INVERT_LAYERPASS = (1 << 3),
+} eSubdivGpencil_Flag;
+
+typedef struct ThickGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ int thickness; /* Thickness change */
+ int layer_pass; /* custom index for passes */
+ struct CurveMapping *curve_thickness;
+} ThickGpencilModifierData;
+
+typedef enum eThickGpencil_Flag {
+ GP_THICK_INVERT_LAYER = (1 << 0),
+ GP_THICK_INVERT_PASS = (1 << 1),
+ GP_THICK_INVERT_VGROUP = (1 << 2),
+ GP_THICK_CUSTOM_CURVE = (1 << 3),
+ GP_THICK_NORMALIZE = (1 << 4),
+ GP_THICK_INVERT_LAYERPASS = (1 << 5),
+} eThickGpencil_Flag;
+
+typedef struct TimeGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int layer_pass; /* custom index for passes */
+ int flag; /* flags */
+ int offset;
+ float frame_scale; /* animation scale */
+ int mode;
+ int sfra, efra; /* start and end frame for custom range */
+ char pad_[4];
+} TimeGpencilModifierData;
+
+typedef enum eTimeGpencil_Flag {
+ GP_TIME_INVERT_LAYER = (1 << 0),
+ GP_TIME_KEEP_LOOP = (1 << 1),
+ GP_TIME_INVERT_LAYERPASS = (1 << 2),
+ GP_TIME_CUSTOM_RANGE = (1 << 3),
+} eTimeGpencil_Flag;
+
+typedef enum eTimeGpencil_Mode {
+ GP_TIME_MODE_NORMAL = 0,
+ GP_TIME_MODE_REVERSE = 1,
+ GP_TIME_MODE_FIX = 2
+} eTimeGpencil_Mode;
+
+
+typedef enum eModifyColorGpencil_Flag {
+ GP_MODIFY_COLOR_BOTH = 0,
+ GP_MODIFY_COLOR_STROKE = 1,
+ GP_MODIFY_COLOR_FILL = 2
+} eModifyColorGpencil_Flag;
+
+typedef struct TintGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float rgb[3]; /* Tint color */
+ float factor; /* Mix factor */
+ char modify_color; /* modify stroke, fill or both */
+ char pad[7];
+ int layer_pass; /* custom index for passes */
+ char pad_[4];
+} TintGpencilModifierData;
+
+typedef enum eTintGpencil_Flag {
+ GP_TINT_CREATE_COLORS = (1 << 0),
+ GP_TINT_INVERT_LAYER = (1 << 1),
+ GP_TINT_INVERT_PASS = (1 << 2),
+ GP_TINT_INVERT_LAYERPASS = (1 << 3),
+} eTintGpencil_Flag;
+
+typedef struct ColorGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float hsv[3]; /* hsv factors */
+ char modify_color; /* modify stroke, fill or both */
+ char pad[3];
+ int layer_pass; /* custom index for passes */
+ char pad_[4];
+} ColorGpencilModifierData;
+
+typedef enum eColorGpencil_Flag {
+ GP_COLOR_CREATE_COLORS = (1 << 0),
+ GP_COLOR_INVERT_LAYER = (1 << 1),
+ GP_COLOR_INVERT_PASS = (1 << 2),
+ GP_COLOR_INVERT_LAYERPASS = (1 << 3),
+} eColorGpencil_Flag;
+
+typedef struct OpacityGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float factor; /* Main Opacity factor */
+ char modify_color; /* modify stroke, fill or both */
+ char pad[3];
+ int layer_pass; /* custom index for passes */
+ char pad_[4];
+} OpacityGpencilModifierData;
+
+typedef enum eOpacityGpencil_Flag {
+ GP_OPACITY_INVERT_LAYER = (1 << 0),
+ GP_OPACITY_INVERT_PASS = (1 << 1),
+ GP_OPACITY_INVERT_VGROUP = (1 << 2),
+ GP_OPACITY_CREATE_COLORS = (1 << 3),
+ GP_OPACITY_INVERT_LAYERPASS = (1 << 4),
+} eOpacityGpencil_Flag;
+
+typedef struct ArrayGpencilModifierData {
+ GpencilModifierData modifier;
+ struct Object *object;
+ int count; /* number of elements in array */
+ int flag; /* several flags */
+ float offset[3]; /* Location increments */
+ float shift[3]; /* shift increment */
+ float rnd_size; /* random size factor */
+ float rnd_rot; /* random size factor */
+ float rot[3]; /* Rotation changes */
+ float scale[3]; /* Scale changes */
+ float rnd[20]; /* (first element is the index) random values */
+ char pad_[4];
+
+ int pass_index; /* custom index for passes */
+ char layername[64]; /* layer name */
+ int mat_rpl; /* material replace (0 keep default) */
+ int layer_pass; /* custom index for passes */
+} ArrayGpencilModifierData;
+
+typedef enum eArrayGpencil_Flag {
+ GP_ARRAY_RANDOM_SIZE = (1 << 0),
+ GP_ARRAY_RANDOM_ROT = (1 << 1),
+ GP_ARRAY_INVERT_LAYER = (1 << 2),
+ GP_ARRAY_INVERT_PASS = (1 << 3),
+ GP_ARRAY_KEEP_ONTOP = (1 << 4),
+ GP_ARRAY_INVERT_LAYERPASS = (1 << 5),
+} eArrayGpencil_Flag;
+
+typedef struct BuildGpencilModifierData {
+ GpencilModifierData modifier;
+
+ char layername[64]; /* if set, restrict modifier to operating on this layer */
+ int pass_index;
+
+ int layer_pass; /* custom index for passes */
+
+ float start_frame; /* If GP_BUILD_RESTRICT_TIME is set, the defines the frame range where GP frames are considered */
+ float end_frame;
+
+ float start_delay; /* For each pair of gp keys, number of frames before strokes start appearing */
+ float length; /* For each pair of gp keys, number of frames that build effect must be completed within */
+
+ short flag; /* (eGpencilBuild_Flag) Options for controlling modifier behaviour */
+
+ short mode; /* (eGpencilBuild_Mode) How are strokes ordered */
+ short transition; /* (eGpencilBuild_Transition) In what order do stroke points appear/disappear */
+
+ short time_alignment; /* (eGpencilBuild_TimeAlignment) For the "Concurrent" mode, when should "shorter" strips start/end */
+} BuildGpencilModifierData;
+
+typedef enum eBuildGpencil_Mode {
+ /* Strokes are shown one by one until all have appeared */
+ GP_BUILD_MODE_SEQUENTIAL = 0,
+ /* All strokes start at the same time */
+ GP_BUILD_MODE_CONCURRENT = 1,
+} eBuildGpencil_Mode;
+
+typedef enum eBuildGpencil_Transition {
+ /* Show in forward order */
+ GP_BUILD_TRANSITION_GROW = 0,
+ /* Hide in reverse order */
+ GP_BUILD_TRANSITION_SHRINK = 1,
+ /* Hide in forward order */
+ GP_BUILD_TRANSITION_FADE = 2,
+} eBuildGpencil_Transition;
+
+typedef enum eBuildGpencil_TimeAlignment {
+ /* All strokes start at same time */
+ GP_BUILD_TIMEALIGN_START = 0,
+ /* All strokes end at same time */
+ GP_BUILD_TIMEALIGN_END = 1,
+
+ /* TODO: Random Offsets, Stretch-to-Fill */
+} eBuildGpencil_TimeAlignment;
+
+typedef enum eBuildGpencil_Flag {
+ /* Restrict modifier to particular layer/passes? */
+ GP_BUILD_INVERT_LAYER = (1 << 0),
+ GP_BUILD_INVERT_PASS = (1 << 1),
+
+ /* Restrict modifier to only operating between the nominated frames */
+ GP_BUILD_RESTRICT_TIME = (1 << 2),
+ GP_BUILD_INVERT_LAYERPASS = (1 << 3),
+} eBuildGpencil_Flag;
+
+typedef struct LatticeGpencilModifierData {
+ GpencilModifierData modifier;
+ struct Object *object;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float strength;
+ int layer_pass; /* custom index for passes */
+ void *cache_data; /* runtime only (LatticeDeformData) */
+} LatticeGpencilModifierData;
+
+typedef enum eLatticeGpencil_Flag {
+ GP_LATTICE_INVERT_LAYER = (1 << 0),
+ GP_LATTICE_INVERT_PASS = (1 << 1),
+ GP_LATTICE_INVERT_VGROUP = (1 << 2),
+ GP_LATTICE_INVERT_LAYERPASS = (1 << 3),
+} eLatticeGpencil_Flag;
+
+typedef struct MirrorGpencilModifierData {
+ GpencilModifierData modifier;
+ struct Object *object;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ int layer_pass; /* custom index for passes */
+ char pad_[4];
+} MirrorGpencilModifierData;
+
+typedef enum eMirrorGpencil_Flag {
+ GP_MIRROR_INVERT_LAYER = (1 << 0),
+ GP_MIRROR_INVERT_PASS = (1 << 1),
+ GP_MIRROR_CLIPPING = (1 << 2),
+ GP_MIRROR_AXIS_X = (1 << 3),
+ GP_MIRROR_AXIS_Y = (1 << 4),
+ GP_MIRROR_AXIS_Z = (1 << 5),
+ GP_MIRROR_INVERT_LAYERPASS = (1 << 6),
+} eMirrorGpencil_Flag;
+
+typedef struct HookGpencilModifierData {
+ GpencilModifierData modifier;
+
+ struct Object *object;
+ char subtarget[64]; /* optional name of bone target, MAX_ID_NAME-2 */
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int layer_pass; /* custom index for passes */
+ char pad_[4];
+
+ int flag;
+ char falloff_type; /* use enums from WarpGpencilModifier (exact same functionality) */
+ char pad[3];
+ float parentinv[4][4]; /* matrix making current transform unmodified */
+ float cent[3]; /* visualization of hook */
+ float falloff; /* if not zero, falloff is distance where influence zero */
+ float force;
+ struct CurveMapping *curfalloff;
+} HookGpencilModifierData;
+
+typedef enum eHookGpencil_Flag {
+ GP_HOOK_INVERT_LAYER = (1 << 0),
+ GP_HOOK_INVERT_PASS = (1 << 1),
+ GP_HOOK_INVERT_VGROUP = (1 << 2),
+ GP_HOOK_UNIFORM_SPACE = (1 << 3),
+ GP_HOOK_INVERT_LAYERPASS = (1 << 4),
+} eHookGpencil_Flag;
+
+typedef enum eHookGpencil_Falloff {
+ eGPHook_Falloff_None = 0,
+ eGPHook_Falloff_Curve = 1,
+ eGPHook_Falloff_Sharp = 2,
+ eGPHook_Falloff_Smooth = 3,
+ eGPHook_Falloff_Root = 4,
+ eGPHook_Falloff_Linear = 5,
+ eGPHook_Falloff_Const = 6,
+ eGPHook_Falloff_Sphere = 7,
+ eGPHook_Falloff_InvSquare = 8,
+} eHookGpencil_Falloff;
+
+typedef struct SimplifyGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float factor; /* factor of simplify */
+ short mode; /* type of simplify */
+ short step; /* every n vertex to keep */
+ int layer_pass; /* custom index for passes */
+ char pad_[4];
+} SimplifyGpencilModifierData;
+
+typedef enum eSimplifyGpencil_Flag {
+ GP_SIMPLIFY_INVERT_LAYER = (1 << 0),
+ GP_SIMPLIFY_INVERT_PASS = (1 << 1),
+ GP_SIMPLIFY_INVERT_LAYERPASS = (1 << 2),
+} eSimplifyGpencil_Flag;
+
+typedef enum eSimplifyGpencil_Mode {
+ /* Keep only one vertex every n vertices */
+ GP_SIMPLIFY_FIXED = 0,
+ /* Use RDP algorithm */
+ GP_SIMPLIFY_ADAPTATIVE = 1,
+} eSimplifyGpencil_Mode;
+
+typedef struct OffsetGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* flags */
+ float loc[3];
+ float rot[3];
+ float scale[3];
+ int layer_pass; /* custom index for passes */
+} OffsetGpencilModifierData;
+
+typedef enum eOffsetGpencil_Flag {
+ GP_OFFSET_INVERT_LAYER = (1 << 0),
+ GP_OFFSET_INVERT_PASS = (1 << 1),
+ GP_OFFSET_INVERT_VGROUP = (1 << 2),
+ GP_OFFSET_INVERT_LAYERPASS = (1 << 3),
+} eOffsetGpencil_Flag;
+
+typedef struct SmoothGpencilModifierData {
+ GpencilModifierData modifier;
+ char layername[64]; /* layer name */
+ char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */
+ int pass_index; /* custom index for passes */
+ int flag; /* several flags */
+ float factor; /* factor of noise */
+ int step; /* how many times apply smooth */
+ int layer_pass; /* custom index for passes */
+ char pad_[4];
+} SmoothGpencilModifierData;
+
+typedef enum eSmoothGpencil_Flag {
+ GP_SMOOTH_MOD_LOCATION = (1 << 0),
+ GP_SMOOTH_MOD_STRENGTH = (1 << 1),
+ GP_SMOOTH_MOD_THICKNESS = (1 << 2),
+ GP_SMOOTH_INVERT_LAYER = (1 << 3),
+ GP_SMOOTH_INVERT_PASS = (1 << 4),
+ GP_SMOOTH_INVERT_VGROUP = (1 << 5),
+ GP_SMOOTH_MOD_UV = (1 << 6),
+ GP_SMOOTH_INVERT_LAYERPASS = (1 << 7),
+} eSmoothGpencil_Flag;
+
+typedef struct ArmatureGpencilModifierData {
+ GpencilModifierData modifier;
+ short deformflag, multi; /* deformflag replaces armature->deformflag */
+ int pad2;
+ struct Object *object;
+ float *prevCos; /* stored input of previous modifier, for vertexgroup blending */
+ char vgname[64]; /* MAX_VGROUP_NAME */
+
+} ArmatureGpencilModifierData;
+
+#endif /* __DNA_GPENCIL_MODIFIER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index d5ef18bd1b8..43ce3649db3 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -34,8 +34,19 @@
#include "DNA_ID.h"
#include "DNA_brush_types.h"
+struct ARegion;
struct AnimData;
struct CurveMapping;
+struct GHash;
+struct MDeformVert;
+
+#define GP_OBGPENCIL_DEFAULT_SIZE 0.2f
+#define GP_DEFAULT_PIX_FACTOR 1.0f
+#define GP_DEFAULT_GRID_LINES 4
+#define GP_MAX_INPUT_SAMPLES 10
+
+/* ***************************************** */
+/* GP Stroke Points */
/* Grease-Pencil Annotations - 'Stroke Point'
* -> Coordinates may either be 2d or 3d depending on settings at the time
@@ -47,7 +58,10 @@ typedef struct bGPDspoint {
float pressure; /* pressure of input device (from 0 to 1) at this point */
float strength; /* color strength (used for alpha factor) */
float time; /* seconds since start of stroke */
- int flag; /* additional options (NOTE: can shrink this field down later if needed) */
+ int flag; /* additional options */
+
+ float uv_fac; /* factor of uv along the stroke */
+ float uv_rot; /* uv rotation for dot mode */
} bGPDspoint;
/* bGPDspoint->flag */
@@ -57,56 +71,28 @@ typedef enum eGPDspoint_Flag {
/* stroke point is tagged (for some editing operation) */
GP_SPOINT_TAG = (1 << 1),
+ /* stroke point is temp tagged (for some editing operation) */
+ GP_SPOINT_TEMP_TAG = (1 << 2),
} eGPSPoint_Flag;
+/* ***************************************** */
+/* GP Fill - Triangle Tessellation Data */
+
/* Grease-Pencil Annotations - 'Triangle'
- * A triangle contains the index of three vertices for filling the stroke
- * This is only used if high quality fill is enabled.
- * (not saved to blend file).
+ * -> A triangle contains the index of three vertices for filling the stroke
+ * This is only used if high quality fill is enabled
*/
typedef struct bGPDtriangle {
- /* indices for tesselated triangle used for GP Fill */
+ /* indices for tessellated triangle used for GP Fill */
unsigned int verts[3];
+ /* texture coordinates for verts */
+ float uv[3][2];
} bGPDtriangle;
-/* GP brush (used for new strokes) */
-typedef struct bGPDbrush {
- struct bGPDbrush *next, *prev;
+/* ***************************************** */
- char info[64]; /* Brush name. Must be unique. */
- short thickness; /* thickness to apply to strokes */
- short flag;
- float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
- short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */
- short sublevel; /* number of times to subdivide new strokes */
-
- float draw_sensitivity; /* amount of sensivity to apply to newly created strokes */
- float draw_strength; /* amount of alpha strength to apply to newly created strokes */
- float draw_jitter; /* amount of jitter to apply to newly created strokes */
- float draw_angle; /* angle when the brush has full thickness */
- float draw_angle_factor; /* factor to apply when angle change (only 90 degrees) */
- float draw_random_press; /* factor of randomness for sensitivity and strength */
- float draw_random_sub; /* factor of randomness for subdivision */
- struct CurveMapping *cur_sensitivity;
- struct CurveMapping *cur_strength;
- struct CurveMapping *cur_jitter;
-} bGPDbrush;
-
-/* bGPDbrush->flag */
-typedef enum eGPDbrush_Flag {
- /* brush is active */
- GP_BRUSH_ACTIVE = (1 << 0),
- /* brush use pressure */
- GP_BRUSH_USE_PRESSURE = (1 << 1),
- /* brush use pressure for alpha factor */
- GP_BRUSH_USE_STENGTH_PRESSURE = (1 << 2),
- /* brush use pressure for alpha factor */
- GP_BRUSH_USE_JITTER_PRESSURE = (1 << 3),
- /* brush use random for pressure */
- GP_BRUSH_USE_RANDOM_PRESSURE = (1 << 4),
- /* brush use random for strength */
- GP_BRUSH_USE_RANDOM_STRENGTH = (1 << 5)
-} eGPDbrush_Flag;
+/* ***************************************** */
+/* GP Palettes (Deprecated - 2.78 - 2.79 only) */
/* color of palettes */
typedef struct bGPDpalettecolor {
@@ -128,10 +114,8 @@ typedef enum eGPDpalettecolor_Flag {
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)
+ /* "volumetric" strokes */
+ PC_COLOR_VOLUMETRIC = (1 << 4)
} eGPDpalettecolor_Flag;
/* palette of colors */
@@ -152,6 +136,21 @@ typedef enum eGPDpalette_Flag {
PL_PALETTE_ACTIVE = (1 << 0)
} eGPDpalette_Flag;
+/* ***************************************** */
+/* GP Strokes */
+
+/* Runtime temp data for bGPDstroke */
+typedef struct bGPDstroke_Runtime {
+ /* runtime final colors (result of original colors and modifiers) */
+ float tmp_stroke_rgba[4];
+ float tmp_fill_rgba[4];
+
+ /* temporary layer name only used during copy/paste to put the stroke in the original layer */
+ char tmp_layerinfo[128];
+
+ float multi_frame_falloff; /* runtime falloff factor (only for transform) */
+} bGPDstroke_Runtime;
+
/* Grease-Pencil Annotations - 'Stroke'
* -> A stroke represents a (simplified version) of the curve
* drawn by the user in one 'mousedown'->'mouseup' operation
@@ -168,14 +167,16 @@ typedef struct bGPDstroke {
short flag, pad[2]; /* various settings about this stroke */
double inittime; /* Init time of stroke */
- /* The pointer to color is only used during drawing, but not saved
- * colorname is the join with the palette, but when draw, the pointer is update if the value is NULL
- * to speed up the drawing
- */
- char colorname[128]; /* color name */
- bGPDpalettecolor *palcolor; /* current palette color */
- /* temporary layer name only used during copy/paste to put the stroke in the original layer */
- char tmp_layerinfo[128];
+
+ char colorname[128] DNA_DEPRECATED; /* color name */
+
+ int mat_nr; /* material index */
+ char pad_[4];
+
+ struct MDeformVert *dvert; /* vertex weight data */
+
+ bGPDstroke_Runtime runtime;
+ char pad_1[4];
} bGPDstroke;
/* bGPDstroke->flag */
@@ -190,14 +191,22 @@ typedef enum eGPDstroke_Flag {
GP_STROKE_SELECT = (1 << 3),
/* Recalculate triangulation for high quality fill (when true, force a new recalc) */
GP_STROKE_RECALC_CACHES = (1 << 4),
- /* Recalculate the color pointer using the name as index (true force a new recalc) */
- GP_STROKE_RECALC_COLOR = (1 << 5),
/* Flag used to indicate that stroke is closed and draw edge between last and first point */
GP_STROKE_CYCLIC = (1 << 7),
+ /* Flag used to indicate that stroke is used for fill close and must use fill color for stroke and no fill area */
+ GP_STROKE_NOFILL = (1 << 8),
/* only for use with stroke-buffer (while drawing eraser) */
GP_STROKE_ERASER = (1 << 15)
} eGPDstroke_Flag;
+/* ***************************************** */
+/* GP Frame */
+
+/* Runtime temp data for bGPDframe */
+typedef struct bGPDframe_Runtime {
+ float viewmatrix[4][4]; /* parent matrix for drawing */
+} bGPDframe_Runtime;
+
/* Grease-Pencil Annotations - 'Frame'
* -> Acts as storage for the 'image' formed by strokes
*/
@@ -210,6 +219,8 @@ typedef struct bGPDframe {
short flag; /* temp settings */
short key_type; /* keyframe type (eBezTriple_KeyframeType) */
+
+ bGPDframe_Runtime runtime;
} bGPDframe;
/* bGPDframe->flag */
@@ -220,6 +231,15 @@ typedef enum eGPDframe_Flag {
GP_FRAME_SELECT = (1 << 1)
} eGPDframe_Flag;
+/* ***************************************** */
+/* GP Layer */
+
+/* Runtime temp data for bGPDlayer */
+typedef struct bGPDlayer_Runtime {
+ int icon_id; /* id for dynamic icon used to show annotation color preview for layer */
+ char pad_[4];
+} bGPDlayer_Runtime;
+
/* Grease-Pencil Annotations - 'Layer' */
typedef struct bGPDlayer {
struct bGPDlayer *next, *prev;
@@ -228,27 +248,39 @@ typedef struct bGPDlayer {
bGPDframe *actframe; /* active frame (should be the frame that is currently being displayed) */
short flag; /* settings for layer */
- short thickness; /* current thickness to apply to strokes */
+ short onion_flag; /* Per-layer onion-skinning flags (eGPDlayer_OnionFlag) */
- short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */
- short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */
+ float color[4]; /* Color for strokes in layers. Used for annotations, and for ruler (which uses GPencil internally) */
+ float fill[4]; /* Fill color for strokes in layers. Not used anymore (was only for) */
- float gcolor_prev[3]; /* optional color for ghosts before the active frame */
- float gcolor_next[3]; /* optional color for ghosts after the active frame */
+ char info[128]; /* name/reference info for this layer (i.e. "director's comments, 12/3")
+ * needs to be kept unique, as it's used as the layer identifier */
- 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. */
+ short thickness; /* thickness to apply to strokes (Annotations) */
+ short pass_index; /* used to filter groups of layers in modifiers */
struct Object *parent; /* parent object */
float inverse[4][4]; /* inverse matrix (only used if parented) */
char parsubstr[64]; /* String describing subobject info, MAX_ID_NAME-2 */
- short partype, pad;
+ short partype;
+ short line_change; /* Thickness adjustment */
float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */
float opacity; /* Opacity of the layer */
+ char viewlayername[64]; /* Name of the layer used to filter render output */
+
+ int blend_mode; /* blend modes */
+ char pad_[4];
+
+ /* annotation onion skin */
+ short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */
+ short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */
+
+ float gcolor_prev[3]; /* color for ghosts before the active frame */
+ float gcolor_next[3]; /* color for ghosts after the active frame */
+ char pad_1[4];
+
+ bGPDlayer_Runtime runtime;
} bGPDlayer;
/* bGPDlayer->flag */
@@ -261,50 +293,114 @@ typedef enum eGPDlayer_Flag {
GP_LAYER_ACTIVE = (1 << 2),
/* draw points of stroke for debugging purposes */
GP_LAYER_DRAWDEBUG = (1 << 3),
- /* do onion skinning */
- GP_LAYER_ONIONSKIN = (1 << 4),
/* for editing in Action Editor */
GP_LAYER_SELECT = (1 << 5),
/* current frame for layer can't be changed */
GP_LAYER_FRAMELOCK = (1 << 6),
/* don't render xray (which is default) */
GP_LAYER_NO_XRAY = (1 << 7),
- /* use custom color for ghosts before current frame */
- GP_LAYER_GHOST_PREVCOL = (1 << 8),
- /* use custom color for ghosts after current frame */
- GP_LAYER_GHOST_NEXTCOL = (1 << 9),
- /* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
+ /* "volumetric" strokes */
GP_LAYER_VOLUMETRIC = (1 << 10),
- /* Use high quality fill (instead of buggy legacy OpenGL Fill) */
- GP_LAYER_HQ_FILL = (1 << 11),
/* Unlock color */
GP_LAYER_UNLOCK_COLOR = (1 << 12),
- /* always show onion skins (i.e. even during renders/animation playback) */
- GP_LAYER_GHOST_ALWAYS = (1 << 13),
+ /* Mask Layer */
+ GP_LAYER_USE_MASK = (1 << 13),
} eGPDlayer_Flag;
+/* bGPDlayer->onion_flag */
+typedef enum eGPDlayer_OnionFlag {
+ /* do onion skinning */
+ GP_LAYER_ONIONSKIN = (1 << 0),
+} eGPDlayer_OnionFlag;
+
+/* layer blend_mode */
+typedef enum eGPLayerBlendModes {
+ eGplBlendMode_Normal = 0,
+ eGplBlendMode_Overlay = 1,
+ eGplBlendMode_Add = 2,
+ eGplBlendMode_Subtract = 3,
+ eGplBlendMode_Multiply = 4,
+ eGplBlendMode_Divide = 5,
+} eGPLayerBlendModes;
+
+/* ***************************************** */
+/* GP Datablock */
+
+/* Runtime temp data for bGPdata */
+typedef struct bGPdata_Runtime {
+ struct ARegion *ar; /* last region where drawing was originated */
+ void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
+
+ /* GP Object drawing */
+ float scolor[4]; /* buffer stroke color */
+ float sfill[4]; /* buffer fill color */
+ short mode; /* settings for color */
+ short bstroke_style; /* buffer style for drawing strokes (used to select shader type) */
+ short bfill_style; /* buffer style for filling areas (used to select shader type) */
+
+ /* Stroke Buffer data (only used during paint-session)
+ * - buffer must be initialized before use, but freed after
+ * whole paint operation is over
+ */
+ short sbuffer_size; /* number of elements currently in cache */
+ short sbuffer_sflag; /* flags for stroke that cache represents */
+ char pad_[6];
+} bGPdata_Runtime;
+
+/* grid configuration */
+typedef struct bGPgrid {
+ float color[3];
+ float scale[2];
+ float offset[2];
+ char _pad1[4];
+
+ int lines;
+ char pad_[4];
+} bGPgrid;
+
/* Grease-Pencil Annotations - 'DataBlock' */
typedef struct bGPdata {
ID id; /* Grease Pencil data is a datablock */
struct AnimData *adt; /* animation data - for animating draw settings */
- /* saved Grease-Pencil data */
+ /* Grease-Pencil data */
ListBase layers; /* bGPDlayers */
int flag; /* settings for this datablock */
- /* not-saved stroke buffer data (only used during paint-session)
- * - buffer must be initialized before use, but freed after
- * whole paint operation is over
- */
- short sbuffer_size; /* number of elements currently in cache */
- short sbuffer_sflag; /* flags for stroke that cache represents */
- void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */
- float scolor[4]; /* buffer color using palettes */
- char pad[6]; /* padding for compiler alignment error */
- short sflag; /* settings for palette color */
+ short xray_mode; /* xray mode for strokes (eGP_DepthOrdering) */
+ char pad_1[2];
- /* saved palettes */
- ListBase palettes;
+ /* Palettes */
+ ListBase palettes DNA_DEPRECATED; /* list of bGPDpalette's - Deprecated (2.78 - 2.79 only) */
+
+ /* 3D Viewport/Appearance Settings */
+ float pixfactor; /* factor to define pixel size conversion */
+ float line_color[4]; /* color for edit line */
+
+ /* Onion skinning */
+ float onion_factor; /* onion alpha factor change */
+ int onion_mode; /* onion skinning range (eGP_OnionModes) */
+ int onion_flag; /* onion skinning flags (eGPD_OnionFlag) */
+ short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */
+ short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */
+
+ float gcolor_prev[3]; /* optional color for ghosts before the active frame */
+ float gcolor_next[3]; /* optional color for ghosts after the active frame */
+
+ float zdepth_offset; /* offset for drawing over surfaces to keep strokes on top */
+ struct Material **mat; /* materials array */
+ short totcol; /* total materials */
+
+ /* stats */
+ short totlayer;
+ short totframe;
+ char pad_2[6];
+ int totstroke;
+ int totpoint;
+ char pad_3[4];
+ bGPgrid grid;
+
+ bGPdata_Runtime runtime;
} bGPdata;
/* bGPdata->flag */
@@ -313,8 +409,12 @@ typedef struct bGPdata {
* changes made during the porting process.
*/
typedef enum eGPdata_Flag {
- /* don't allow painting to occur at all */
- /* GP_DATA_LMBPLOCK = (1 << 0), */
+ /* datablock is used for "annotations"
+ * NOTE: This flag used to be used in 2.4x, but should hardly ever have been set.
+ * We can use this freely now, as all GP datablocks from pre-2.8 will get
+ * set on file load (as many old use cases are for "annotations" only)
+ */
+ GP_DATA_ANNOTATIONS = (1 << 0),
/* show debugging info in viewport (i.e. status print) */
GP_DATA_DISPINFO = (1 << 1),
@@ -338,10 +438,94 @@ typedef enum eGPdata_Flag {
/* Stroke Editing Mode - Toggle to enable alternative keymap for easier editing of stroke points */
GP_DATA_STROKE_EDITMODE = (1 << 8),
- /* Convenience/cache flag to make it easier to quickly toggle onion skinning on/off */
+ /* Main flag to switch onion skinning on/off */
GP_DATA_SHOW_ONIONSKINS = (1 << 9),
/* Draw a green and red point to indicate start and end of the stroke */
- GP_DATA_SHOW_DIRECTION = (1 << 10)
+ GP_DATA_SHOW_DIRECTION = (1 << 10),
+
+ /* Batch drawing cache need to be recalculated */
+ GP_DATA_CACHE_IS_DIRTY = (1 << 11),
+
+ /* Stroke Paint Mode - Toggle paint mode */
+ GP_DATA_STROKE_PAINTMODE = (1 << 12),
+ /* Stroke Editing Mode - Toggle sculpt mode */
+ GP_DATA_STROKE_SCULPTMODE = (1 << 13),
+ /* Stroke Editing Mode - Toggle weight paint mode */
+ GP_DATA_STROKE_WEIGHTMODE = (1 << 14),
+
+ /* keep stroke thickness unchanged when zoom change */
+ GP_DATA_STROKE_KEEPTHICKNESS = (1 << 15),
+
+ /* Allow edit several frames at the same time */
+ GP_DATA_STROKE_MULTIEDIT = (1 << 16),
+
+ /* Force fill recalc if use deformation modifiers.
+ * this is required if the stroke is deformed and the triangulation data is
+ * not valid.
+ */
+ GP_DATA_STROKE_FORCE_RECALC = (1 << 17),
+ /* Special mode drawing polygons */
+ GP_DATA_STROKE_POLYGON = (1 << 18),
+ /* Use adaptative UV scales */
+ GP_DATA_UV_ADAPTATIVE = (1 << 19),
+ /* Autolock not active layers */
+ GP_DATA_AUTOLOCK_LAYERS = (1 << 20),
} eGPdata_Flag;
+/* gpd->onion_flag */
+typedef enum eGPD_OnionFlag {
+ /* use custom color for ghosts before current frame */
+ GP_ONION_GHOST_PREVCOL = (1 << 0),
+ /* use custom color for ghosts after current frame */
+ GP_ONION_GHOST_NEXTCOL = (1 << 1),
+ /* always show onion skins (i.e. even during renders/animation playback) */
+ GP_ONION_GHOST_ALWAYS = (1 << 2),
+ /* use fade color in onion skin */
+ GP_ONION_FADE = (1 << 3),
+ /* Loop showing first frame after last frame */
+ GP_ONION_LOOP = (1 << 4),
+} eGPD_OnionFlag;
+
+/* gpd->onion_mode */
+typedef enum eGP_OnionModes {
+ GP_ONION_MODE_ABSOLUTE = 0,
+ GP_ONION_MODE_RELATIVE = 1,
+ GP_ONION_MODE_SELECTED = 2,
+} eGP_OnionModes;
+
+/* xray modes (Depth Ordering) */
+typedef enum eGP_DepthOrdering {
+ GP_XRAY_FRONT = 0,
+ GP_XRAY_3DSPACE = 1,
+ GP_XRAY_BACK = 2
+} eGP_DepthOrdering;
+
+/* ***************************************** */
+/* Mode Checking Macros */
+
+/* Check if 'multiedit sessions' is enabled */
+#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd) \
+ ((gpd) && (gpd->flag & \
+ (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)) && \
+ (gpd->flag & GP_DATA_STROKE_MULTIEDIT))
+
+/* Macros to check grease pencil modes */
+#define GPENCIL_ANY_MODE(gpd) \
+ ((gpd) && (gpd->flag & \
+ (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | \
+ GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
+#define GPENCIL_EDIT_MODE(gpd) \
+ ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE))
+#define GPENCIL_ANY_EDIT_MODE(gpd) \
+ ((gpd) && (gpd->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
+#define GPENCIL_PAINT_MODE(gpd) \
+ ((gpd) && (gpd->flag & (GP_DATA_STROKE_PAINTMODE)))
+#define GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd) \
+ ((gpd) && (gpd->flag & (GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
+#define GPENCIL_NONE_EDIT_MODE(gpd) \
+ ((gpd) && ((gpd->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)) == 0))
+#define GPENCIL_LAZY_MODE(brush, shift) \
+ (((brush) && ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) && (shift == 0))) || \
+ (((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && (shift == 1)))
+
#endif /* __DNA_GPENCIL_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_gpu_types.h b/source/blender/makesdna/DNA_gpu_types.h
index 967cb7284dc..be34309572f 100644
--- a/source/blender/makesdna/DNA_gpu_types.h
+++ b/source/blender/makesdna/DNA_gpu_types.h
@@ -38,6 +38,8 @@ typedef struct GPUDOFSettings {
float fstop;
float focal_length;
float sensor;
+ float rotation;
+ float ratio;
int num_blades;
int high_quality;
} GPUDOFSettings;
diff --git a/source/blender/makesdna/DNA_group_types.h b/source/blender/makesdna/DNA_group_types.h
deleted file mode 100644
index ae565427365..00000000000
--- a/source/blender/makesdna/DNA_group_types.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): mar-2001 nzc
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file DNA_group_types.h
- * \ingroup DNA
- *
- * \brief Object groups, one object can be in many groups at once.
- */
-
-#ifndef __DNA_GROUP_TYPES_H__
-#define __DNA_GROUP_TYPES_H__
-
-#include "DNA_listBase.h"
-#include "DNA_ID.h"
-
-struct Object;
-
-typedef struct GroupObject {
- struct GroupObject *next, *prev;
- struct Object *ob;
- void *lampren; /* used while render */
- short recalc; /* copy of ob->recalc, used to set animated groups OK */
- char pad[6];
-} GroupObject;
-
-
-typedef struct Group {
- ID id;
-
- ListBase gobject; /* GroupObject */
-
- struct PreviewImage *preview;
-
- /* Bad design, since layers stored in the scenes 'Base'
- * the objects that show in the group can change depending
- * on the last used scene */
- unsigned int layer;
- float dupli_ofs[3];
-} Group;
-
-#endif /* __DNA_GROUP_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 760e9b5461e..a7ec121efda 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -51,7 +51,7 @@ typedef struct ImageUser {
int framenr; /* movies, sequences: current to display */
int frames; /* total amount of frames to use */
int offset, sfra; /* offset within movie, start frame in global time */
- char fie_ima, cycl; /* fields/image in movie, cyclic flag */
+ char _pad, cycl; /* cyclic flag */
char ok;
char multiview_eye; /* multiview current eye - for internal use of drawing routines */
@@ -80,7 +80,9 @@ typedef struct ImagePackedFile {
} ImagePackedFile;
typedef struct RenderSlot {
+ struct RenderSlot *next, *prev;
char name[64]; /* 64 = MAX_NAME */
+ struct RenderResult *render;
} RenderSlot;
/* iuser->flag */
@@ -108,7 +110,7 @@ typedef struct Image {
ListBase anims;
struct RenderResult *rr;
- struct RenderResult *renders[8]; /* IMA_MAX_RENDER_SLOT */
+ ListBase renderslots;
short render_slot, last_render_slot;
int flag;
@@ -116,23 +118,17 @@ typedef struct Image {
int lastframe;
/* texture page */
- short tpageflag, totbind;
- short xrep, yrep;
- short twsta, twend;
- unsigned int bindcode[2]; /* only for current image... 2 = TEXTARGET_COUNT */
- char pad1[4];
- unsigned int *repbind; /* for repeat of parts of images */
+ short tpageflag;
+ short pad2;
+ unsigned int pad3;
struct PackedFile *packedfile DNA_DEPRECATED; /* deprecated */
struct ListBase packedfiles;
struct PreviewImage *preview;
- /* game engine tile animation */
- float lastupdate;
int lastused;
- short animspeed;
-
short ok;
+ short pad4[3];
/* for generated images */
int gen_x, gen_y;
@@ -154,8 +150,6 @@ typedef struct Image {
char views_format;
ListBase views; /* ImageView */
struct Stereo3dFormat *stereo3d_format;
-
- RenderSlot render_slots[8]; /* 8 = IMA_MAX_RENDER_SLOT */
} Image;
@@ -163,12 +157,12 @@ typedef struct Image {
/* Image.flag */
enum {
- IMA_FIELDS = (1 << 0),
- IMA_STD_FIELD = (1 << 1),
+ // IMA_FIELDS = (1 << 0),
+ // IMA_STD_FIELD = (1 << 1),
#ifdef DNA_DEPRECATED
IMA_DO_PREMUL = (1 << 2), /* deprecated, should not be used */
#endif
- IMA_REFLECT = (1 << 4),
+ //IMA_REFLECT = (1 << 4), /* deprecated */
IMA_NOCOLLECT = (1 << 5),
//IMA_DONE_TAG = (1 << 6), // UNUSED
IMA_OLD_PREMUL = (1 << 7),
@@ -184,12 +178,12 @@ enum {
};
/* Image.tpageflag */
-#define IMA_TILES 1
-#define IMA_TWINANIM 2
-#define IMA_COLCYCLE 4 /* Depreciated */
+//#define IMA_TILES 1 /* Deprecated */
+//#define IMA_TWINANIM 2 /* Deprecated */
+#define IMA_COLCYCLE 4 /* Deprecated */
#define IMA_MIPMAP_COMPLETE 8 /* all mipmap levels in OpenGL texture set? */
-#define IMA_CLAMP_U 16
-#define IMA_CLAMP_V 32
+//#define IMA_CLAMP_U 16 /* Deprecated */
+//#define IMA_CLAMP_V 32 /* Deprecated */
#define IMA_TPAGE_REFRESH 64
#define IMA_GLBIND_IS_DATA 128 /* opengl image texture bound as non-color data */
@@ -197,7 +191,6 @@ enum {
/* render */
#define IMA_MAX_RENDER_TEXT 512
-#define IMA_MAX_RENDER_SLOT 8
/* gen_flag */
#define IMA_GEN_FLOAT 1
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
index 2b097092bc4..fa58f8f8abd 100644
--- a/source/blender/makesdna/DNA_key_types.h
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -135,4 +135,15 @@ enum {
KEYBLOCK_LOCKED = (1 << 2)
};
+#define KEYELEM_FLOAT_LEN_COORD 3
+
+/* Curve key data layout constants */
+#define KEYELEM_ELEM_SIZE_CURVE 3
+
+#define KEYELEM_ELEM_LEN_BPOINT 2
+#define KEYELEM_FLOAT_LEN_BPOINT (KEYELEM_ELEM_LEN_BPOINT * KEYELEM_ELEM_SIZE_CURVE)
+
+#define KEYELEM_ELEM_LEN_BEZTRIPLE 4
+#define KEYELEM_FLOAT_LEN_BEZTRIPLE (KEYELEM_ELEM_LEN_BEZTRIPLE * KEYELEM_ELEM_SIZE_CURVE)
+
#endif /* __DNA_KEY_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h
index ca1a07fbcae..d035e0c5440 100644
--- a/source/blender/makesdna/DNA_lamp_types.h
+++ b/source/blender/makesdna/DNA_lamp_types.h
@@ -52,13 +52,10 @@ typedef struct Lamp {
short type, flag;
int mode;
- short colormodel, totex;
float r, g, b, k;
float shdwr, shdwg, shdwb, shdwpad;
float energy, dist, spotsize, spotblend;
- float haint;
-
float att1, att2; /* Quad1 and Quad2 attenuation */
float coeff_const, coeff_lin, coeff_quad, coeff_pad;
@@ -67,45 +64,30 @@ typedef struct Lamp {
short pad2;
float clipsta, clipend;
- float bias, soft, compressthresh, bleedbias, pad5;
+ float bias, soft, bleedbias, bleedexp;
short bufsize, samp, buffers, filtertype;
char bufflag, buftype;
- short ray_samp, ray_sampy, ray_sampz;
- short ray_samp_type;
short area_shape;
float area_size, area_sizey, area_sizez;
- float adapt_thresh;
- short ray_samp_method;
- short shadowmap_type;
/* texact is for buttons */
short texact, shadhalostep;
- /* sun/sky */
- short sun_effect_type;
- short skyblendtype;
- float horizon_brightness;
- float spread;
- float sun_brightness;
- float sun_size;
- float backscattered_light;
- float sun_intensity;
- float atm_turbidity;
- float atm_inscattering_factor;
- float atm_extinction_factor;
- float atm_distance_factor;
- float skyblendfac;
- float sky_exposure;
- float shadow_frustum_size; /* BGE Only */
- short sky_colorspace;
- char pad4[2];
-
struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
- struct MTex *mtex[18]; /* MAX_MTEX */
short pr_texture, use_nodes;
char pad6[4];
+ /* Eevee */
+ float cascade_max_dist;
+ float cascade_exponent;
+ float cascade_fade;
+ int cascade_count;
+
+ float contact_dist, contact_bias, contact_spread, contact_thickness;
+
+ float spec_fac, att_dist;
+
/* preview */
struct PreviewImage *preview;
@@ -126,40 +108,33 @@ typedef struct Lamp {
#define LA_LOCAL 0
#define LA_SUN 1
#define LA_SPOT 2
-#define LA_HEMI 3
+/* #define LA_HEMI 3 */ /* not used anymore */
#define LA_AREA 4
/* mode */
-#define LA_SHAD_BUF (1 << 0)
-#define LA_HALO (1 << 1)
-#define LA_LAYER (1 << 2)
-#define LA_QUAD (1 << 3) /* no longer used */
-#define LA_NEG (1 << 4)
-#define LA_ONLYSHADOW (1 << 5)
-#define LA_SPHERE (1 << 6)
+#define LA_SHADOW (1 << 0)
+/* #define LA_HALO (1 << 1) */ /* not used anymore */
+/* #define LA_LAYER (1 << 2) */ /* not used anymore */
+/* #define LA_QUAD (1 << 3) */ /* not used anymore */
+/* #define LA_NEG (1 << 4) */ /* not used anymore */
+/* #define LA_ONLYSHADOW(1 << 5) */ /* not used anymore */
+/* #define LA_SPHERE (1 << 6) */ /* not used anymore */
#define LA_SQUARE (1 << 7)
-#define LA_TEXTURE (1 << 8)
-#define LA_OSATEX (1 << 9)
+/* #define LA_TEXTURE (1 << 8) */ /* not used anymore */
+/* #define LA_OSATEX (1 << 9) */ /* not used anymore */
/* #define LA_DEEP_SHADOW (1 << 10) */ /* not used anywhere */
-#define LA_NO_DIFF (1 << 11)
-#define LA_NO_SPEC (1 << 12)
-#define LA_SHAD_RAY (1 << 13)
+/* #define LA_NO_DIFF (1 << 11) */ /* not used anywhere */
+/* #define LA_NO_SPEC (1 << 12) */ /* not used anywhere */
+/* #define LA_SHAD_RAY (1 << 13) */ /* not used anywhere - cleaned */
/* yafray: lamp shadowbuffer flag, softlight */
/* Since it is used with LOCAL lamp, can't use LA_SHAD */
-/* #define LA_YF_SOFT (1 << 14) */ /* no longer used */
-#define LA_LAYER_SHADOW (1 << 15)
-#define LA_SHAD_TEX (1 << 16)
+/* #define LA_YF_SOFT (1 << 14) */ /* not used anymore */
+/* #define LA_LAYER_SHADOW (1 << 15) */ /* not used anymore */
+/* #define LA_SHAD_TEX (1 << 16) */ /* not used anymore */
#define LA_SHOW_CONE (1 << 17)
-#define LA_SHOW_SHADOW_BOX (1 << 18)
-
-/* layer_shadow */
-#define LA_LAYER_SHADOW_BOTH 0
-#define LA_LAYER_SHADOW_CAST 1
-#define LA_LAYER_SHADOW_RECEIVE 2
-
-/* sun effect type*/
-#define LA_SUN_EFFECT_SKY 1
-#define LA_SUN_EFFECT_AP 2
+/* #define LA_SHOW_SHADOW_BOX (1 << 18) */
+#define LA_SHAD_CONTACT (1 << 19)
+#define LA_CUSTOM_ATTENUATION (1 << 20)
/* falloff_type */
#define LA_FALLOFF_CONSTANT 0
@@ -169,46 +144,12 @@ typedef struct Lamp {
#define LA_FALLOFF_SLIDERS 4
#define LA_FALLOFF_INVCOEFFICIENTS 5
-
-/* buftype, no flag */
-#define LA_SHADBUF_REGULAR 0
-#define LA_SHADBUF_IRREGULAR 1
-#define LA_SHADBUF_HALFWAY 2
-#define LA_SHADBUF_DEEP 3
-
-/* bufflag, auto clipping */
-#define LA_SHADBUF_AUTO_START 1
-#define LA_SHADBUF_AUTO_END 2
-
-/* filtertype */
-#define LA_SHADBUF_BOX 0
-#define LA_SHADBUF_TENT 1
-#define LA_SHADBUF_GAUSS 2
-
/* area shape */
#define LA_AREA_SQUARE 0
#define LA_AREA_RECT 1
#define LA_AREA_CUBE 2
#define LA_AREA_BOX 3
-
-/* ray_samp_method */
-#define LA_SAMP_CONSTANT 0
-#define LA_SAMP_HALTON 1
-#define LA_SAMP_HAMMERSLEY 2
-
-
-/* ray_samp_type */
-// #define LA_SAMP_ROUND 1 // UNUSED
-#define LA_SAMP_UMBRA 2
-#define LA_SAMP_DITHER 4
-#define LA_SAMP_JITTER 8
-
-/* mapto */
-#define LAMAP_COL 1
-#define LAMAP_SHAD 2
-
-/* shadowmap_type */
-#define LA_SHADMAP_SIMPLE 0
-#define LA_SHADMAP_VARIANCE 1
+#define LA_AREA_DISK 4
+#define LA_AREA_ELLIPSE 5
#endif /* __DNA_LAMP_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_lattice_types.h b/source/blender/makesdna/DNA_lattice_types.h
index 8fb0d58f1db..71d6b3bbb0e 100644
--- a/source/blender/makesdna/DNA_lattice_types.h
+++ b/source/blender/makesdna/DNA_lattice_types.h
@@ -69,6 +69,7 @@ typedef struct Lattice {
char vgroup[64]; /* multiply the influence, MAX_VGROUP_NAME */
struct EditLatt *editlatt;
+ void *batch_cache;
} Lattice;
/* ***************** LATTICE ********************* */
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
new file mode 100644
index 00000000000..c3e819c5538
--- /dev/null
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -0,0 +1,163 @@
+/*
+ * ***** 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): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_layer_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_LAYER_TYPES_H__
+#define __DNA_LAYER_TYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DNA_freestyle_types.h"
+#include "DNA_listBase.h"
+
+typedef struct Base {
+ struct Base *next, *prev;
+ short flag;
+ unsigned short local_view_bits;
+ short sx, sy;
+ struct Object *object;
+ unsigned int lay DNA_DEPRECATED;
+ int flag_legacy;
+} Base;
+
+typedef struct ViewLayerEngineData {
+ struct ViewLayerEngineData *next, *prev;
+ struct DrawEngineType *engine_type;
+ void *storage;
+ void (*free)(void *storage);
+} ViewLayerEngineData;
+
+typedef struct LayerCollection {
+ struct LayerCollection *next, *prev;
+ struct Collection *collection;
+ struct SceneCollection *scene_collection DNA_DEPRECATED;
+ short flag;
+ short runtime_flag;
+ short pad[2];
+ ListBase layer_collections; /* synced with collection->children */
+} LayerCollection;
+
+typedef struct ViewLayer {
+ struct ViewLayer *next, *prev;
+ char name[64]; /* MAX_NAME */
+ short flag;
+ short runtime_flag;
+ short pad[2];
+ ListBase object_bases; /* ObjectBase */
+ struct SceneStats *stats; /* default allocated now */
+ struct Base *basact;
+ ListBase layer_collections; /* LayerCollection */
+ LayerCollection *active_collection;
+
+ /* Old SceneRenderLayer data. */
+ int layflag;
+ int passflag; /* pass_xor has to be after passflag */
+ int pass_xor;
+ float pass_alpha_threshold;
+
+ struct IDProperty *id_properties; /* Equivalent to datablocks ID properties. */
+
+ struct FreestyleConfig freestyle_config;
+
+ /* Runtime data */
+ ListBase drawdata; /* ViewLayerEngineData */
+ struct Base **object_bases_array;
+ struct GHash *object_bases_hash;
+} ViewLayer;
+
+/* Base->flag */
+enum {
+ /* User controlled flags. */
+ BASE_SELECTED = (1 << 0), /* Object is selected. */
+ BASE_HIDDEN = (1 << 8), /* Object is hidden for editing. */
+
+ /* Runtime evaluated flags. */
+ BASE_VISIBLE = (1 << 1), /* Object is enabled and visible. */
+ BASE_SELECTABLE = (1 << 2), /* Object can be selected. */
+ BASE_FROMDUPLI = (1 << 3), /* Object comes from duplicator. */
+ /* BASE_DEPRECATED = (1 << 4), */
+ BASE_FROM_SET = (1 << 5), /* Object comes from set. */
+ BASE_ENABLED_VIEWPORT = (1 << 6), /* Object is enabled in viewport. */
+ BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */
+ BASE_ENABLED = (1 << 9), /* Object is enabled. */
+ BASE_HOLDOUT = (1 << 10), /* Object masked out from render */
+ BASE_INDIRECT_ONLY = (1 << 11), /* Object only contributes indirectly to render */
+};
+
+/* LayerCollection->flag */
+enum {
+ /* LAYER_COLLECTION_DEPRECATED0 = (1 << 0), */
+ /* LAYER_COLLECTION_DEPRECATED1 = (1 << 1), */
+ /* LAYER_COLLECTION_DEPRECATED2 = (1 << 2), */
+ /* LAYER_COLLECTION_DEPRECATED3 = (1 << 3), */
+ LAYER_COLLECTION_EXCLUDE = (1 << 4),
+ LAYER_COLLECTION_HOLDOUT = (1 << 5),
+ LAYER_COLLECTION_INDIRECT_ONLY = (1 << 6),
+};
+
+/* Layer Collection->runtime_flag */
+enum {
+ LAYER_COLLECTION_HAS_OBJECTS = (1 << 0),
+ LAYER_COLLECTION_HAS_VISIBLE_OBJECTS = (1 << 1),
+ LAYER_COLLECTION_HAS_HIDDEN_OBJECTS = (1 << 2),
+ LAYER_COLLECTION_HAS_ENABLED_OBJECTS = (1 << 3),
+};
+
+/* ViewLayer->flag */
+enum {
+ VIEW_LAYER_RENDER = (1 << 0),
+ /* VIEW_LAYER_DEPRECATED = (1 << 1), */
+ VIEW_LAYER_FREESTYLE = (1 << 2),
+};
+
+/* ViewLayer->runtime_flag */
+enum {
+ VIEW_LAYER_HAS_HIDE = (1 << 0),
+};
+
+/****************************** Deprecated ******************************/
+
+/* Compatibility with collections saved in early 2.8 versions,
+ * used in file reading and versioning code. */
+#define USE_COLLECTION_COMPAT_28
+
+typedef struct SceneCollection {
+ struct SceneCollection *next, *prev;
+ char name[64]; /* MAX_NAME */
+ int active_object_index; /* for UI */
+ short flag;
+ char type;
+ char pad;
+ ListBase objects; /* (Object *)LinkData->data */
+ ListBase scene_collections; /* nested collections */
+} SceneCollection;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNA_LAYER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h
new file mode 100644
index 00000000000..490e2574a33
--- /dev/null
+++ b/source/blender/makesdna/DNA_lightprobe_types.h
@@ -0,0 +1,184 @@
+/*
+ * ***** 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): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file DNA_lightprobe_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_LIGHTPROBE_TYPES_H__
+#define __DNA_LIGHTPROBE_TYPES_H__
+
+#include "DNA_defs.h"
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Object;
+struct AnimData;
+
+typedef struct LightProbe {
+ ID id;
+ struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
+
+ char type; /* For realtime probe objects */
+ char flag; /* General purpose flags for probes */
+ char attenuation_type; /* Attenuation type */
+ char parallax_type; /* Parallax type */
+
+ float distinf; /* Influence Radius */
+ float distpar; /* Parallax Radius */
+ float falloff; /* Influence falloff */
+
+ float clipsta, clipend;
+
+ float vis_bias, vis_bleedbias; /* VSM visibility biases */
+ float vis_blur;
+
+ float intensity; /* Intensity multiplier */
+
+ int grid_resolution_x; /* Irradiance grid resolution */
+ int grid_resolution_y;
+ int grid_resolution_z;
+ int pad1;
+
+ struct Object *parallax_ob; /* Object to use as a parallax origin */
+ struct Image *image; /* Image to use on as lighting data */
+ struct Collection *visibility_grp; /* Object visibility group, inclusive or exclusive */
+
+ /* Runtime display data */
+ float distfalloff, distgridinf;
+ float pad[2];
+} LightProbe;
+
+/* Probe->type */
+enum {
+ LIGHTPROBE_TYPE_CUBE = 0,
+ LIGHTPROBE_TYPE_PLANAR = 1,
+ LIGHTPROBE_TYPE_GRID = 2,
+};
+
+/* Probe->flag */
+enum {
+ LIGHTPROBE_FLAG_CUSTOM_PARALLAX = (1 << 0),
+ LIGHTPROBE_FLAG_SHOW_INFLUENCE = (1 << 1),
+ LIGHTPROBE_FLAG_SHOW_PARALLAX = (1 << 2),
+ LIGHTPROBE_FLAG_SHOW_CLIP_DIST = (1 << 3),
+ LIGHTPROBE_FLAG_SHOW_DATA = (1 << 4),
+ LIGHTPROBE_FLAG_INVERT_GROUP = (1 << 5),
+};
+
+/* Probe->display */
+enum {
+ LIGHTPROBE_DISP_WIRE = 0,
+ LIGHTPROBE_DISP_SHADED = 1,
+ LIGHTPROBE_DISP_DIFFUSE = 2,
+ LIGHTPROBE_DISP_REFLECTIVE = 3,
+};
+
+/* Probe->parallax && Probe->attenuation_type*/
+enum {
+ LIGHTPROBE_SHAPE_ELIPSOID = 0,
+ LIGHTPROBE_SHAPE_BOX = 1,
+};
+
+/* ------- Eevee LightProbes ------- */
+/* Needs to be there because written to file
+ * with the lightcache. */
+
+typedef struct LightProbeCache {
+ float position[3], parallax_type;
+ float attenuation_fac;
+ float attenuation_type;
+ float pad3[2];
+ float attenuationmat[4][4];
+ float parallaxmat[4][4];
+} LightProbeCache;
+
+typedef struct LightGridCache {
+ float mat[4][4];
+ int resolution[3], offset; /* offset to the first irradiance sample in the pool. */
+ float corner[3], attenuation_scale;
+ float increment_x[3], attenuation_bias; /* world space vector between 2 opposite cells */
+ float increment_y[3], level_bias;
+ float increment_z[3], pad4;
+ float visibility_bias, visibility_bleed, visibility_range, pad5;
+} LightGridCache;
+
+/* ------ Eevee Lightcache ------- */
+
+typedef struct LightCacheTexture {
+ struct GPUTexture *tex;
+ /* Copy of GPU datas to create GPUTextures on file read. */
+ char *data;
+ int tex_size[3];
+ char data_type;
+ char components;
+ char pad[2];
+} LightCacheTexture;
+
+typedef struct LightCache {
+ int flag;
+ /* only a single cache for now */
+ int cube_len, grid_len; /* Number of probes to use for rendering. */
+ int mips_len; /* Number of mipmap level to use. */
+ int vis_res, ref_res; /* Size of a visibility/reflection sample. */
+ int pad[2];
+ /* In the future, we could create a bigger texture containing
+ * multiple caches (for animation) and interpolate between the
+ * caches overtime to another texture. */
+ LightCacheTexture grid_tx;
+ LightCacheTexture cube_tx; /* Contains data for mipmap level 0. */
+ LightCacheTexture *cube_mips; /* Does not contains valid GPUTexture, only data. */
+ /* All lightprobes data contained in the cache. */
+ LightProbeCache *cube_data;
+ LightGridCache *grid_data;
+} LightCache;
+
+/* LightCache->flag */
+enum {
+ LIGHTCACHE_BAKED = (1 << 0),
+ LIGHTCACHE_BAKING = (1 << 1),
+ LIGHTCACHE_CUBE_READY = (1 << 2),
+ LIGHTCACHE_GRID_READY = (1 << 3),
+ /* Update tagging */
+ LIGHTCACHE_UPDATE_CUBE = (1 << 4),
+ LIGHTCACHE_UPDATE_GRID = (1 << 5),
+ LIGHTCACHE_UPDATE_WORLD = (1 << 6),
+ LIGHTCACHE_UPDATE_AUTO = (1 << 7),
+};
+
+/* EEVEE_LightCacheTexture->data_type */
+enum {
+ LIGHTCACHETEX_BYTE = (1 << 0),
+ LIGHTCACHETEX_FLOAT = (1 << 1),
+ LIGHTCACHETEX_UINT = (1 << 2),
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNA_LIGHTPROBE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index dfe7b441c71..85dfe300429 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -40,198 +40,134 @@
#define MAX_MTEX 18
#endif
-struct MTex;
struct Image;
-struct ColorBand;
-struct Group;
struct bNodeTree;
struct AnimData;
struct Ipo;
/* WATCH IT: change type? also make changes in ipo.h */
-typedef struct VolumeSettings {
- float density;
- float emission;
- float scattering;
- float reflection;
-
- float emission_col[3];
- float transmission_col[3];
- float reflection_col[3];
-
- float density_scale;
- float depth_cutoff;
- float asymmetry;
-
- short stepsize_type;
- short shadeflag;
- short shade_type;
- short precache_resolution;
-
- float stepsize;
- float ms_diff;
- float ms_intensity;
- float ms_spread;
-} VolumeSettings;
-
-/* Game Engine Options (old Texface mode, transp and flag) */
-typedef struct GameSettings {
- int flag;
- int alpha_blend;
- int face_orientation;
- int pad1;
-} GameSettings;
-
typedef struct TexPaintSlot {
struct Image *ima; /* image to be painted on */
char *uvname; /* customdata index for uv layer, MAX_NAME*/
- int index; /* index for mtex slot in material for blender internal */
+ int valid; /* do we have a valid image and UV map */
int pad;
} TexPaintSlot;
+typedef struct MaterialGPencilStyle {
+ struct Image *sima; /* Texture image for strokes */
+ struct Image *ima; /* Texture image for filling */
+ float stroke_rgba[4]; /* color for paint and strokes (alpha included) */
+ float fill_rgba[4]; /* color that should be used for drawing "fills" for strokes (alpha included) */
+ float mix_rgba[4]; /* secondary color used for gradients and other stuff */
+ short flag; /* settings */
+ short index; /* custom index for passes */
+ short stroke_style; /* style for drawing strokes (used to select shader type) */
+ short fill_style; /* style for filling areas (used to select shader type) */
+ float mix_factor; /* factor used to define shader behavior (several uses) */
+ float gradient_angle; /* angle used for gradients orientation */
+ float gradient_radius; /* radius for radial gradients */
+ float pattern_gridsize; /* cheesboard size */
+ float gradient_scale[2]; /* uv coordinates scale */
+ float gradient_shift[2]; /* factor to shift filling in 2d space */
+ float texture_angle; /* angle used for texture orientation */
+ float texture_scale[2]; /* texture scale (separated of uv scale) */
+ float texture_offset[2]; /* factor to shift texture in 2d space */
+ float texture_opacity; /* texture opacity */
+ float texture_pixsize; /* pixel size for uv along the stroke */
+ int mode; /* drawing mode (line or dots) */
+
+ int gradient_type; /* type of gradient */
+ char pad[4];
+} MaterialGPencilStyle;
+
+/* MaterialGPencilStyle->flag */
+typedef enum eMaterialGPencilStyle_Flag {
+ /* Fill Texture is a pattern */
+ GP_STYLE_FILL_PATTERN = (1 << 0),
+ /* don't display color */
+ GP_STYLE_COLOR_HIDE = (1 << 1),
+ /* protected from further editing */
+ GP_STYLE_COLOR_LOCKED = (1 << 2),
+ /* do onion skinning */
+ GP_STYLE_COLOR_ONIONSKIN = (1 << 3),
+ /* clamp texture */
+ GP_STYLE_COLOR_TEX_CLAMP = (1 << 4),
+ /* mix texture */
+ GP_STYLE_COLOR_TEX_MIX = (1 << 5),
+ /* Flip fill colors */
+ GP_STYLE_COLOR_FLIP_FILL = (1 << 6),
+ /* Stroke Texture is a pattern */
+ GP_STYLE_STROKE_PATTERN = (1 << 7),
+ /* Stroke show main switch */
+ GP_STYLE_STROKE_SHOW = (1 << 8),
+ /* Fill show main switch */
+ GP_STYLE_FILL_SHOW = (1 << 9)
+} eMaterialGPencilStyle_Flag;
+
+typedef enum eMaterialGPencilStyle_Mode {
+ GP_STYLE_MODE_LINE = 0, /* line */
+ GP_STYLE_MODE_DOTS = 1, /* dots */
+ GP_STYLE_MODE_BOX = 2, /* rectangles */
+} eMaterialGPencilStyle_Mode;
+
typedef struct Material {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
- short material_type, flag;
- /* note, keep this below synced with render_types.h */
+ short flag, pad1[7];
+
+ /* Colors from Blender Internal that we are still using. */
float r, g, b;
float specr, specg, specb;
- float mirr, mirg, mirb;
- float ambr, ambb, ambg;
- float amb, emit, ang, spectra, ray_mirror;
- float alpha, ref, spec, zoffs, add;
- float translucency;
- /* end synced with render_types.h */
-
- struct VolumeSettings vol;
- struct GameSettings game;
-
- float fresnel_mir, fresnel_mir_i;
- float fresnel_tra, fresnel_tra_i;
- float filter; /* filter added, for raytrace transparency and transmissivity */
- float tx_limit, tx_falloff;
- short ray_depth, ray_depth_tra;
- short har;
- char seed1, seed2;
-
- float gloss_mir, gloss_tra;
- short samp_gloss_mir, samp_gloss_tra;
- float adapt_thresh_mir, adapt_thresh_tra;
- float aniso_gloss_mir;
- float dist_mir;
- short fadeto_mir;
- short shade_flag; /* like Cubic interpolation */
-
- int mode, mode_l; /* mode_l is the or-ed result of all layer modes */
- int mode2, mode2_l; /* additional mode flags */
- short flarec, starc, linec, ringc;
- float hasize, flaresize, subsize, flareboost;
- float strand_sta, strand_end, strand_ease, strand_surfnor;
- float strand_min, strand_widthfade;
- char strand_uvname[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
-
- float sbias; /* shadow bias to prevent terminator prob */
- float lbias; /* factor to multiply lampbias with (0.0 = no mult) */
- float shad_alpha; /* in use for irregular shadowbuffer */
- int septex;
-
- /* for buttons and render*/
- char rgbsel, texact, pr_type, use_nodes;
- short pr_lamp, pr_texture, ml_flag; /* ml_flag is for disable base material */
-
- /* mapping */
- char mapflag, pad;
-
- /* shaders */
- short diff_shader, spec_shader;
- float roughness, refrac;
- /* XXX param[4] needs review and improvement (shader system as whole anyway)
- * This is nasty reused variable for different goals and not easy to RNAify nicely. -jesterKing */
- float param[4]; /* size, smooth, size, smooth, for toonshader, 0 (fac) and 1 (fresnel) also for fresnel shader */
- float rms;
- float darkness;
-
- /* runtime - OR'd from 'mtex' */
- short texco, mapto;
-
- /* ramp colors */
- struct ColorBand *ramp_col;
- struct ColorBand *ramp_spec;
- char rampin_col, rampin_spec;
- char rampblend_col, rampblend_spec;
- short ramp_show, pad3;
- float rampfac_col, rampfac_spec;
-
- struct MTex *mtex[18]; /* MAX_MTEX */
- struct bNodeTree *nodetree;
- struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
- struct Group *group; /* light group */
- struct PreviewImage *preview;
+ float alpha DNA_DEPRECATED;
+ float ray_mirror DNA_DEPRECATED;
+ float spec;
+ float gloss_mir DNA_DEPRECATED; /* renamed and inversed to roughness */
+ float roughness;
+ float metallic;
+ float pad4[2];
- /* dynamic properties */
- float friction, fh, reflect;
- float fhdist, xyfrict;
- short dynamode, pad2;
+ /* Ror buttons and render. */
+ char pr_type, use_nodes;
+ short pr_lamp, pr_texture;
- /* subsurface scattering */
- float sss_radius[3], sss_col[3];
- float sss_error, sss_scale, sss_ior;
- float sss_colfac, sss_texfac;
- float sss_front, sss_back;
- short sss_flag, sss_preset;
+ /* Index for render passes. */
+ short index;
- int mapto_textured; /* render-time cache to optimize texture lookups */
- short shadowonly_flag; /* "shadowsonly" type */
- short index; /* custom index for render passes */
+ struct bNodeTree *nodetree;
+ struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
+ struct PreviewImage *preview;
- /* Freestyle line settings */
+ /* Freestyle line settings. */
float line_col[4];
short line_priority;
short vcol_alpha;
- /* texture painting */
+ /* Texture painting slots. */
short paint_active_slot;
short paint_clone_slot;
short tot_slots;
- short pad4[3];
+ short pad2[3];
- /* multiple tangent (Normal Map node) */
- char nmap_tangent_names[9][64]; /* [MAX_MTFACE+1][MAX_NAME]; +1 for empty name */
- int nmap_tangent_names_count, pad5;
-
- struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use
- * with refresh_texpaint_image_cache */
- ListBase gpumaterial; /* runtime */
-} Material;
+ /* Transparency. */
+ float alpha_threshold;
+ float refract_depth;
+ char blend_method;
+ char blend_shadow;
+ char blend_flag;
+ char pad3[5];
+ /* Cached slots for texture painting, must be refreshed in
+ * refresh_texpaint_image_cache before using. */
+ struct TexPaintSlot *texpaintslot;
-/* **************** GAME PROPERTIES ********************* */
-// Blend Transparency Options - alpha_blend /* match GPU_material::GPUBlendMode */
-#define GEMAT_SOLID 0 /* GPU_BLEND_SOLID */
-#define GEMAT_ADD 1 /* GPU_BLEND_ADD */
-#define GEMAT_ALPHA 2 /* GPU_BLEND_ALPHA */
-#define GEMAT_CLIP 4 /* GPU_BLEND_CLIP */
-#define GEMAT_ALPHA_SORT 8 /* GPU_BLEND_ALPHA_SORT */
-#define GEMAT_ALPHA_TO_COVERAGE 16 /* GPU_BLEND_ALPHA_TO_COVERAGE */
-
-// Game Options - flag
-#define GEMAT_BACKCULL 16 /* KX_BACKCULL */
-#define GEMAT_SHADED 32 /* KX_LIGHT */
-#define GEMAT_TEXT 64 /* RAS_RENDER_3DPOLYGON_TEXT */
-#define GEMAT_NOPHYSICS 128
-#define GEMAT_INVISIBLE 256
-
-// Face Orientation Options - face_orientation
-#define GEMAT_NORMAL 0
-#define GEMAT_HALO 512 /* BILLBOARD_SCREENALIGNED */
-#define GEMAT_BILLBOARD 1024 /* BILLBOARD_AXISALIGNED */
-#define GEMAT_SHADOW 2048 /* SHADOW */
-
-// Use Textures - not defined directly in the UI
-#define GEMAT_TEX 4096 /* KX_TEX */
+ /* Runtime cache for GLSL materials. */
+ ListBase gpumaterial;
+ /* grease pencil color */
+ struct MaterialGPencilStyle *gp_style;
+} Material;
/* **************** MATERIAL ********************* */
@@ -241,12 +177,6 @@ typedef struct Material {
* -1 because for active material we store the index + 1 */
#define MAXMAT (32767-1)
-/* material_type */
-#define MA_TYPE_SURFACE 0
-#define MA_TYPE_HALO 1
-#define MA_TYPE_VOLUME 2
-#define MA_TYPE_WIRE 3
-
/* flag */
/* for render */
#define MA_IS_USED 1
@@ -258,101 +188,7 @@ typedef struct Material {
*/
#define MA_DS_SHOW_TEXS 4
-/* mode (is int) */
-#define MA_TRACEBLE 1
-#define MA_SHADOW 2
-#define MA_SHLESS 4
-#define MA_WIRE 8 /* deprecated */
-#define MA_VERTEXCOL 16
-#define MA_HALO_SOFT 16
-#define MA_HALO 32 /* deprecated */
-#define MA_ZTRANSP 64
-#define MA_VERTEXCOLP 128
-#define MA_ZINV 256
-#define MA_HALO_RINGS 256
-#define MA_ENV 512
-#define MA_HALO_LINES 512
-#define MA_ONLYSHADOW 1024
-#define MA_HALO_XALPHA 1024
-#define MA_STAR 0x800
-#define MA_FACETEXTURE 0x800
-#define MA_HALOTEX 0x1000
-#define MA_HALOPUNO 0x2000
-#define MA_ONLYCAST 0x2000
-#define MA_NOMIST 0x4000
-#define MA_HALO_SHADE 0x4000
-#define MA_HALO_FLARE 0x8000
-#define MA_TRANSP 0x10000
-#define MA_RAYTRANSP 0x20000
-#define MA_RAYMIRROR 0x40000
-#define MA_SHADOW_TRA 0x80000
-#define MA_RAMP_COL 0x100000
-#define MA_RAMP_SPEC 0x200000
-#define MA_RAYBIAS 0x400000
-#define MA_FULL_OSA 0x800000
-#define MA_TANGENT_STR 0x1000000
-#define MA_SHADBUF 0x2000000
- /* note; we drop MA_TANGENT_STR later to become tangent_u */
-#define MA_TANGENT_V 0x4000000
-/* qdn: a bit clumsy this, tangents needed for normal maps separated from shading */
-#define MA_NORMAP_TANG 0x8000000
-#define MA_GROUP_NOLAY 0x10000000
-#define MA_FACETEXTURE_ALPHA 0x20000000
-#define MA_STR_B_UNITS 0x40000000
-#define MA_STR_SURFDIFF 0x80000000
-
-#define MA_MODE_MASK 0x6fffffff /* all valid mode bits */
-#define MA_MODE_PIPELINE (MA_TRANSP | MA_ZTRANSP | MA_RAYTRANSP \
- | MA_TRACEBLE | MA_FULL_OSA | MA_ENV | MA_ZINV \
- | MA_ONLYCAST | MA_SHADBUF)
-
-/* mode2 (is int) */
-#define MA_CASTSHADOW (1 << 0)
-#define MA_MODE2_PIPELINE (MA_CASTSHADOW)
-#define MA_TANGENT_CONCRETE (1 << 1)
-
-/* mapflag */
-#define MA_MAPFLAG_UVPROJECT (1 << 0)
-
-/* ray mirror fadeout */
-#define MA_RAYMIR_FADETOSKY 0
-#define MA_RAYMIR_FADETOMAT 1
-
-/* shadowonly_flag */
-#define MA_SO_OLD 0
-#define MA_SO_SHADOW 1
-#define MA_SO_SHADED 2
-
-/* shade_flag */
-#define MA_CUBIC 1
-#define MA_OBCOLOR 2
-#define MA_APPROX_OCCLUSION 4
-#define MA_GROUP_LOCAL 8
-
-/* diff_shader */
-#define MA_DIFF_LAMBERT 0
-#define MA_DIFF_ORENNAYAR 1
-#define MA_DIFF_TOON 2
-#define MA_DIFF_MINNAERT 3
-#define MA_DIFF_FRESNEL 4
-
-/* spec_shader */
-#define MA_SPEC_COOKTORR 0
-#define MA_SPEC_PHONG 1
-#define MA_SPEC_BLINN 2
-#define MA_SPEC_TOON 3
-#define MA_SPEC_WARDISO 4
-
-/* dynamode */
-// #define MA_DRAW_DYNABUTS 1 /* deprecated */
-#define MA_FH_NOR 2
-
/* ramps */
-#define MA_RAMP_IN_SHADER 0
-#define MA_RAMP_IN_ENERGY 1
-#define MA_RAMP_IN_NOR 2
-#define MA_RAMP_IN_RESULT 3
-
#define MA_RAMP_BLEND 0
#define MA_RAMP_ADD 1
#define MA_RAMP_MULT 2
@@ -394,38 +230,7 @@ typedef struct Material {
/* mapto */
#define MAP_COL 1
-#define MAP_NORM 2
-#define MAP_COLSPEC 4
-#define MAP_COLMIR 8
-#define MAP_VARS (0xFFF0)
-#define MAP_REF 16
-#define MAP_SPEC 32
-#define MAP_EMIT 64
#define MAP_ALPHA 128
-#define MAP_HAR 256
-#define MAP_RAYMIRR 512
-#define MAP_TRANSLU 1024
-#define MAP_AMB 2048
-#define MAP_DISPLACE 4096
-#define MAP_WARP 8192
-// #define MAP_LAYER 16384 /* unused */
-
-/* volume mapto - reuse definitions for now - a bit naughty! */
-#define MAP_DENSITY 128
-#define MAP_EMISSION 64
-#define MAP_EMISSION_COL 1
-#define MAP_SCATTERING 16
-#define MAP_TRANSMISSION_COL 8
-#define MAP_REFLECTION_COL 4
-#define MAP_REFLECTION 32
-
-
-/* mapto for halo */
-//#define MAP_HA_COL 1
-//#define MAP_HA_ALPHA 128
-//#define MAP_HA_HAR 256
-//#define MAP_HA_SIZE 2
-//#define MAP_HA_ADD 64
/* pmapto */
/* init */
@@ -458,23 +263,50 @@ typedef struct Material {
#define MA_HAIR 10
#define MA_ATMOS 11
-/* sss_flag */
-#define MA_DIFF_SSS 1
-
-/* vol_stepsize_type */
-#define MA_VOL_STEP_RANDOMIZED 0
-#define MA_VOL_STEP_CONSTANT 1
-#define MA_VOL_STEP_ADAPTIVE 2
-
-/* vol_shadeflag */
-#define MA_VOL_RECV_EXT_SHADOW 1
-#define MA_VOL_PRECACHESHADING 8
-
-/* vol_shading_type */
-#define MA_VOL_SHADE_SHADELESS 0
-#define MA_VOL_SHADE_SHADOWED 2
-#define MA_VOL_SHADE_SHADED 1
-#define MA_VOL_SHADE_MULTIPLE 3
-#define MA_VOL_SHADE_SHADEDPLUSMULTIPLE 4
+/* blend_method */
+enum {
+ MA_BM_SOLID,
+ MA_BM_ADD,
+ MA_BM_MULTIPLY,
+ MA_BM_CLIP,
+ MA_BM_HASHED,
+ MA_BM_BLEND,
+};
+
+/* blend_flag */
+enum {
+ MA_BL_HIDE_BACKSIDE = (1 << 0),
+ MA_BL_SS_REFRACTION = (1 << 1),
+ MA_BL_SS_SUBSURFACE = (1 << 2), /* DEPRECATED */
+ MA_BL_TRANSLUCENCY = (1 << 3),
+};
+
+/* blend_shadow */
+enum {
+ MA_BS_NONE = 0,
+ MA_BS_SOLID,
+ MA_BS_CLIP,
+ MA_BS_HASHED,
+};
+
+/* Grease Pencil Stroke styles */
+enum {
+ GP_STYLE_STROKE_STYLE_SOLID = 0,
+ GP_STYLE_STROKE_STYLE_TEXTURE
+};
+
+/* Grease Pencil Fill styles */
+enum {
+ GP_STYLE_FILL_STYLE_SOLID = 0,
+ GP_STYLE_FILL_STYLE_GRADIENT,
+ GP_STYLE_FILL_STYLE_CHESSBOARD,
+ GP_STYLE_FILL_STYLE_TEXTURE
+};
+
+/* Grease Pencil Gradient Types */
+enum {
+ GP_STYLE_GRADIENT_LINEAR = 0,
+ GP_STYLE_GRADIENT_RADIAL
+};
#endif
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index a667d0e578d..fda18e5cbd6 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -39,11 +39,13 @@
struct AnimData;
struct Ipo;
struct Key;
+struct LinkNode;
struct MCol;
struct MEdge;
struct MFace;
struct MLoop;
struct MLoopCol;
+struct MLoopTri;
struct MLoopUV;
struct MPoly;
struct MTexPoly;
@@ -51,6 +53,65 @@ struct MVert;
struct Material;
struct Mesh;
struct Multires;
+struct SubdivCCG;
+
+#
+#
+typedef struct EditMeshData {
+ /** when set, \a vertexNos, polyNos are lazy initialized */
+ const float (*vertexCos)[3];
+
+ /** lazy initialize (when \a vertexCos is set) */
+ float const (*vertexNos)[3];
+ float const (*polyNos)[3];
+ /** also lazy init but dont depend on \a vertexCos */
+ const float (*polyCos)[3];
+} EditMeshData;
+
+
+/**
+ * \warning Typical access is done via #BKE_mesh_runtime_looptri_ensure, #BKE_mesh_runtime_looptri_len.
+ */
+struct MLoopTri_Store {
+ /* WARNING! swapping between array (ready-to-be-used data) and array_wip (where data is actually computed)
+ * shall always be protected by same lock as one used for looptris computing. */
+ struct MLoopTri *array, *array_wip;
+ int len;
+ int len_alloc;
+};
+
+/* not saved in file! */
+typedef struct Mesh_Runtime {
+ struct EditMeshData *edit_data;
+ void *batch_cache;
+
+ struct SubdivCCG *subdiv_ccg;
+ void *pad1;
+ int subdiv_ccg_tot_level;
+ int pad2;
+
+ int64_t cd_dirty_vert;
+ int64_t cd_dirty_edge;
+ int64_t cd_dirty_loop;
+ int64_t cd_dirty_poly;
+
+ struct MLoopTri_Store looptris;
+
+ /** 'BVHCache', for 'BKE_bvhutil.c' */
+ struct LinkNode *bvh_cache;
+
+ /** Non-manifold boundary data for Shrinkwrap Target Project. */
+ struct ShrinkwrapBoundaryData *shrinkwrap_data;
+
+ /** Set by modifier stack if only deformed from original. */
+ char deformed_only;
+ /**
+ * Copied from edit-mesh (hint, draw with editmesh data).
+ * In the future we may leave the mesh-data empty
+ * since its not needed if we can use edit-mesh data. */
+ char is_original;
+ char padding[6];
+} Mesh_Runtime;
typedef struct Mesh {
ID id;
@@ -66,7 +127,6 @@ typedef struct Mesh {
/* BMESH ONLY */
/*new face structures*/
struct MPoly *mpoly;
- struct MTexPoly *mtpoly;
struct MLoop *mloop;
struct MLoopUV *mloopuv;
struct MLoopCol *mloopcol;
@@ -127,6 +187,8 @@ typedef struct Mesh {
short totcol;
struct Multires *mr DNA_DEPRECATED; /* deprecated multiresolution modeling data, only keep for loading old files */
+
+ Mesh_Runtime runtime;
} Mesh;
/* deprecated by MTFace, only here for file reading */
@@ -188,6 +250,7 @@ enum {
ME_CDFLAG_EDGE_CREASE = 1 << 2,
};
+#if 0 /* Was moved to overlay options for 2.8 */
/* me->drawflag, short */
enum {
ME_DRAWEDGES = 1 << 0,
@@ -196,7 +259,7 @@ enum {
ME_DRAW_VNORMALS = 1 << 3,
ME_DRAWEIGHT = 1 << 4,
- /* ME_HIDDENEDGES = 1 << 5, */ /* DEPRECATED */
+ ME_DRAW_FACE_DOT = 1 << 5,
ME_DRAWCREASES = 1 << 6,
ME_DRAWSEAMS = 1 << 7,
@@ -220,6 +283,7 @@ enum {
/* draw loop normals */
ME_DRAW_LNORMALS = 1 << 18,
};
+#endif
/* Subsurf Type */
enum {
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index d1c137492de..8525f9d0334 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -95,7 +95,7 @@ typedef struct MLoop {
* There is no attempt to maintain this data's validity over time, any changes to the underlying mesh
* invalidate the #MLoopTri array, which will need to be re-calculated.
*
- * Users normally access this via #DerivedMesh.getLoopTriArray.
+ * Users normally access this via #BKE_mesh_runtime_looptri_ensure.
* In rare cases its calculated directly, with #BKE_mesh_recalc_looptri.
*
* Typical usage includes:
@@ -164,18 +164,18 @@ typedef struct MLoop {
* MEdge *ed = &medge[mloop[lt->tri[j]].e];
* unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
*
- * if (((ed->v1 == tri_edge[0]) && (ed->v1 == tri_edge[1])) ||
- * ((ed->v1 == tri_edge[1]) && (ed->v1 == tri_edge[0])))
+ * if (((ed->v1 == tri_edge[0]) && (ed->v2 == tri_edge[1])) ||
+ * ((ed->v1 == tri_edge[1]) && (ed->v2 == tri_edge[0])))
* {
* printf("real edge found %u %u\n", tri_edge[0], tri_edge[1]);
* }
* }
* \endcode
*
+ * See #BKE_mesh_looptri_get_real_edges for a utility that does this.
+ *
* \note A #MLoopTri may be in the middle of an ngon and not reference **any** edges.
*/
-#
-#
typedef struct MLoopTri {
unsigned int tri[3];
unsigned int poly;
@@ -186,22 +186,9 @@ typedef struct MVertTri {
unsigned int tri[3];
} MVertTri;
-
-typedef struct MTexPoly {
- struct Image *tpage;
- char flag, transp;
- short mode, tile, pad;
-} MTexPoly;
-
-/* can copy from/to MTexPoly/MTFace */
-#define ME_MTEXFACE_CPY(dst, src) \
-{ \
- (dst)->tpage = (src)->tpage; \
- (dst)->flag = (src)->flag; \
- (dst)->transp = (src)->transp; \
- (dst)->mode = (src)->mode; \
- (dst)->tile = (src)->tile; \
-} (void)0
+//typedef struct MTexPoly {
+// void *pad;
+//} MTexPoly;
typedef struct MLoopUV {
float uv[2];
@@ -256,9 +243,6 @@ typedef struct MSelect {
/*tessellation uv face data*/
typedef struct MTFace {
float uv[4][2];
- struct Image *tpage;
- char flag, transp;
- short mode, tile, unwrap;
} MTFace;
/*Custom Data Properties*/
@@ -463,58 +447,4 @@ enum {
ME_FSEL = 2,
};
-/* mtface->flag */
-enum {
- // TF_SELECT = (1 << 0), /* use MFace hide flag (after 2.43), should be able to reuse after 2.44 */
- // TF_ACTIVE = (1 << 1), /* deprecated! */
- TF_SEL1 = (1 << 2),
- TF_SEL2 = (1 << 3),
- TF_SEL3 = (1 << 4),
- TF_SEL4 = (1 << 5),
-};
-
-/* mtface->mode */
-enum {
- TF_DYNAMIC = (1 << 0),
- TF_ALPHASORT = (1 << 1),
- TF_TEX = (1 << 2),
- TF_SHAREDVERT = (1 << 3),
- TF_LIGHT = (1 << 4),
-
- TF_CONVERTED = (1 << 5), /* tface converted to material */
-
- TF_SHAREDCOL = (1 << 6),
- // TF_TILES = (1 << 7), /* deprecated */
- TF_BILLBOARD = (1 << 8),
- TF_TWOSIDE = (1 << 9),
- TF_INVISIBLE = (1 << 10),
-
- TF_OBCOL = (1 << 11),
- TF_BILLBOARD2 = (1 << 12), /* with Z axis constraint */
- TF_SHADOW = (1 << 13),
- TF_BMFONT = (1 << 14),
-};
-
-/* mtface->transp, values 1-4 are used as flags in the GL, WARNING, TF_SUB cant work with this */
-enum {
- TF_SOLID = 0,
- TF_ADD = (1 << 0),
- TF_ALPHA = (1 << 1),
- TF_CLIP = (1 << 2), /* clipmap alpha/binary alpha all or nothing! */
-
- TF_SUB = 3, /* sub is not available in the user interface anymore */
-};
-
-/* mtface->unwrap */
-enum {
- TF_DEPRECATED1 = (1 << 0),
- TF_DEPRECATED2 = (1 << 1),
- TF_DEPRECATED3 = (1 << 2),
- TF_DEPRECATED4 = (1 << 3),
- TF_PIN1 = (1 << 4),
- TF_PIN2 = (1 << 5),
- TF_PIN3 = (1 << 6),
- TF_PIN4 = (1 << 7),
-};
-
#endif /* __DNA_MESHDATA_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h
index aa926623e34..3f0b1b302c7 100644
--- a/source/blender/makesdna/DNA_meta_types.h
+++ b/source/blender/makesdna/DNA_meta_types.h
@@ -47,7 +47,8 @@ typedef struct MetaElem {
struct BoundBox *bb; /* Bound Box of MetaElem */
- short type, flag, selcol1, selcol2;
+ short type, flag;
+ short pad[2];
float x, y, z; /* Position of center of MetaElem */
float quat[4]; /* Rotation of MetaElem (MUST be kept normalized) */
float expx; /* dimension parameters, used for some types like cubes */
@@ -59,7 +60,6 @@ typedef struct MetaElem {
float len; /* old, only used for backwards compat. use dimensions now */
float *mat, *imat; /* matrix and inverted matrix */
-
} MetaElem;
typedef struct MetaBall {
@@ -93,6 +93,8 @@ typedef struct MetaBall {
/* used in editmode */
/*ListBase edit_elems;*/
MetaElem *lastelem;
+
+ void *batch_cache;
} MetaBall;
/* **************** METABALL ********************* */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 2adf4a02d22..c5045caec9c 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -32,6 +32,9 @@
* (ONLY ADD NEW ITEMS AT THE END)
*/
+struct Mesh;
+struct Scene;
+
typedef enum ModifierType {
eModifierType_None = 0,
eModifierType_Subsurf = 1,
@@ -87,6 +90,7 @@ typedef enum ModifierType {
eModifierType_CorrectiveSmooth = 51,
eModifierType_MeshSequenceCache = 52,
eModifierType_SurfaceDeform = 53,
+ eModifierType_WeightedNormal = 54,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -105,21 +109,20 @@ typedef struct ModifierData {
struct ModifierData *next, *prev;
int type, mode;
- int stackindex, pad;
+ int stackindex;
+ short flag;
+ short pad;
char name[64]; /* MAX_NAME */
- /* XXX for timing info set by caller... solve later? (ton) */
- struct Scene *scene;
-
char *error;
} ModifierData;
typedef enum {
- eSubsurfModifierFlag_Incremental = (1 << 0),
- eSubsurfModifierFlag_DebugIncr = (1 << 1),
- eSubsurfModifierFlag_ControlEdges = (1 << 2),
- eSubsurfModifierFlag_SubsurfUv = (1 << 3),
-} SubsurfModifierFlag;
+ /* This modifier has been inserted in local override, and hence can be fully edited. */
+ eModifierFlag_StaticOverride_Local = (1 << 0),
+ /* This modifier does not own its caches, but instead shares them with another modifier. */
+ eModifierFlag_SharedCaches = (1 << 1),
+} ModifierFlag;
/* not a real modifier */
typedef struct MappingInfoModifierData {
@@ -132,11 +135,35 @@ typedef struct MappingInfoModifierData {
int texmapping;
} MappingInfoModifierData;
+typedef enum {
+ eSubsurfModifierFlag_Incremental = (1 << 0),
+ eSubsurfModifierFlag_DebugIncr = (1 << 1),
+ eSubsurfModifierFlag_ControlEdges = (1 << 2),
+ /* DEPRECATED, ONLY USED FOR DO-VERSIONS */
+ eSubsurfModifierFlag_SubsurfUv_DEPRECATED = (1 << 3),
+} SubsurfModifierFlag;
+
+typedef enum {
+ SUBSURF_TYPE_CATMULL_CLARK = 0,
+ SUBSURF_TYPE_SIMPLE = 1,
+} eSubsurfModifierType;
+
+typedef enum {
+ SUBSURF_UV_SMOOTH_NONE = 0,
+ SUBSURF_UV_SMOOTH_PRESERVE_CORNERS = 1,
+ SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS = 2,
+ SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE = 3,
+ SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES = 4,
+ SUBSURF_UV_SMOOTH_ALL = 5,
+} eSubsurfUVSmooth;
+
typedef struct SubsurfModifierData {
ModifierData modifier;
short subdivType, levels, renderLevels, flags;
- short use_opensubdiv, pad[3];
+ short uv_smooth;
+ short quality;
+ short pad[2];
void *emCache, *mCache;
} SubsurfModifierData;
@@ -286,14 +313,20 @@ typedef struct MirrorModifierData {
/* MirrorModifierData->flag */
enum {
- MOD_MIR_CLIPPING = (1 << 0),
- MOD_MIR_MIRROR_U = (1 << 1),
- MOD_MIR_MIRROR_V = (1 << 2),
- MOD_MIR_AXIS_X = (1 << 3),
- MOD_MIR_AXIS_Y = (1 << 4),
- MOD_MIR_AXIS_Z = (1 << 5),
- MOD_MIR_VGROUP = (1 << 6),
- MOD_MIR_NO_MERGE = (1 << 7),
+ MOD_MIR_CLIPPING = (1 << 0),
+ MOD_MIR_MIRROR_U = (1 << 1),
+ MOD_MIR_MIRROR_V = (1 << 2),
+ MOD_MIR_AXIS_X = (1 << 3),
+ MOD_MIR_AXIS_Y = (1 << 4),
+ MOD_MIR_AXIS_Z = (1 << 5),
+ MOD_MIR_VGROUP = (1 << 6),
+ MOD_MIR_NO_MERGE = (1 << 7),
+ MOD_MIR_BISECT_AXIS_X = (1 << 8),
+ MOD_MIR_BISECT_AXIS_Y = (1 << 9),
+ MOD_MIR_BISECT_AXIS_Z = (1 << 10),
+ MOD_MIR_BISECT_FLIP_AXIS_X = (1 << 11),
+ MOD_MIR_BISECT_FLIP_AXIS_Y = (1 << 12),
+ MOD_MIR_BISECT_FLIP_AXIS_Z = (1 << 13),
};
typedef struct EdgeSplitModifierData {
@@ -309,6 +342,10 @@ enum {
MOD_EDGESPLIT_FROMFLAG = (1 << 2),
};
+typedef struct BevelModNorEditData {
+ struct GHash *faceHash;
+} BevelModNorEditData;
+
typedef struct BevelModifierData {
ModifierData modifier;
@@ -319,13 +356,16 @@ typedef struct BevelModifierData {
short lim_flags; /* flags to tell the tool how to limit the bevel */
short e_flags; /* flags to direct how edge weights are applied to verts */
short mat; /* material index if >= 0, else material inherited from surrounding faces */
- short pad;
+ short edge_flags;
int pad2;
float profile; /* controls profile shape (0->1, .5 is round) */
/* if the MOD_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */
float bevel_angle;
/* if the MOD_BEVEL_VWEIGHT option is set, this will be the name of the vert group, MAX_VGROUP_NAME */
+ int hnmode;
+ float hn_strength;
char defgrp_name[64];
+ struct BevelModNorEditData clnordata;
} BevelModifierData;
/* BevelModifierData->flags and BevelModifierData->lim_flags */
@@ -346,6 +386,7 @@ enum {
/* MOD_BEVEL_DIST = (1 << 12), */ /* same as above */
MOD_BEVEL_OVERLAP_OK = (1 << 13),
MOD_BEVEL_EVEN_WIDTHS = (1 << 14),
+ MOD_BEVEL_SET_WN_STR = (1 << 15),
};
/* BevelModifierData->val_flags (not used as flags any more) */
@@ -356,6 +397,20 @@ enum {
MOD_BEVEL_AMT_PERCENT = 3,
};
+/* BevelModifierData->edge_flags */
+enum {
+ MOD_BEVEL_MARK_SEAM = (1 << 0),
+ MOD_BEVEL_MARK_SHARP = (1 << 1),
+};
+
+/* BevelModifierData->hnmode */
+enum {
+ MOD_BEVEL_HN_NONE,
+ MOD_BEVEL_HN_FACE,
+ MOD_BEVEL_HN_ADJ,
+ MOD_BEVEL_FIX_SHA,
+};
+
typedef struct SmokeModifierData {
ModifierData modifier;
@@ -420,8 +475,7 @@ typedef struct UVProjectModifierData {
/* the objects which do the projecting */
struct Object *projectors[10]; /* MOD_UVPROJECT_MAXPROJECTORS */
- struct Image *image; /* the image to project */
- int flags;
+ int pad2;
int num_projectors;
float aspectx, aspecty;
float scalex, scaley;
@@ -600,12 +654,15 @@ typedef struct SoftbodyModifierData {
typedef struct ClothModifierData {
ModifierData modifier;
- struct Scene *scene; /* the context, time etc is here */
struct Cloth *clothObject; /* The internal data structure for cloth. */
struct ClothSimSettings *sim_parms; /* definition is in DNA_cloth_types.h */
struct ClothCollSettings *coll_parms; /* definition is in DNA_cloth_types.h */
+
+ /* PointCache can be shared with other instances of ClothModifierData.
+ * Inspect (modifier.flag & eModifierFlag_SharedCaches) to find out. */
struct PointCache *point_cache; /* definition is in DNA_object_force_types.h */
struct ListBase ptcaches;
+
/* XXX nasty hack, remove once hair can be separated from cloth modifier data */
struct ClothHairData *hairdata;
/* grid geometry values of hair continuum */
@@ -644,7 +701,7 @@ typedef struct SurfaceModifierData {
struct MVert *x; /* old position */
struct MVert *v; /* velocity */
- struct DerivedMesh *dm;
+ struct Mesh *mesh;
struct BVHTreeFromMesh *bvhtree; /* bounding volume hierarchy of the mesh faces */
@@ -713,7 +770,7 @@ typedef struct MeshDeformModifierData {
float *bindcos; /* deprecated storage of cage coords */
/* runtime */
- void (*bindfunc)(struct Scene *scene, struct MeshDeformModifierData *mmd, struct DerivedMesh *cagedm,
+ void (*bindfunc)(struct Scene *scene, struct MeshDeformModifierData *mmd, struct Mesh *cagemesh,
float *vertexcos, int totvert, float cagemat[4][4]);
} MeshDeformModifierData;
@@ -731,8 +788,8 @@ typedef struct ParticleSystemModifierData {
ModifierData modifier;
struct ParticleSystem *psys;
- struct DerivedMesh *dm_final; /* Final DM - its topology may differ from orig mesh. */
- struct DerivedMesh *dm_deformed; /* Deformed-onle DM - its topology is same as orig mesh one. */
+ struct Mesh *mesh_final; /* Final Mesh - its topology may differ from orig mesh. */
+ struct Mesh *mesh_original; /* Original mesh that particles are attached to. */
int totdmvert, totdmedge, totdmface;
short flag, pad;
} ParticleSystemModifierData;
@@ -794,18 +851,21 @@ typedef struct MultiresModifierData {
char lvl, sculptlvl, renderlvl, totlvl;
char simple, flags, pad[2];
+ short quality;
+ short uv_smooth;
+ short pad2[2];
} MultiresModifierData;
typedef enum {
eMultiresModifierFlag_ControlEdges = (1 << 0),
- eMultiresModifierFlag_PlainUv = (1 << 1),
+ /* DEPRECATED, only used for versioning. */
+ eMultiresModifierFlag_PlainUv_DEPRECATED = (1 << 1),
} MultiresModifierFlag;
typedef struct FluidsimModifierData {
ModifierData modifier;
struct FluidsimSettings *fss; /* definition is in DNA_object_fluidsim_types.h */
- struct PointCache *point_cache; /* definition is in DNA_object_force_types.h */
} FluidsimModifierData;
typedef struct ShrinkwrapModifierData {
@@ -817,7 +877,7 @@ typedef struct ShrinkwrapModifierData {
float keepDist; /* distance offset to keep from mesh/projection point */
short shrinkType; /* shrink type projection */
char shrinkOpts; /* shrink options */
- char pad1;
+ char shrinkMode; /* shrink to surface mode */
float projLimit; /* limit the projection ray cast */
char projAxis; /* axis to project over */
@@ -834,6 +894,21 @@ enum {
MOD_SHRINKWRAP_NEAREST_SURFACE = 0,
MOD_SHRINKWRAP_PROJECT = 1,
MOD_SHRINKWRAP_NEAREST_VERTEX = 2,
+ MOD_SHRINKWRAP_TARGET_PROJECT = 3,
+};
+
+/* Shrinkwrap->shrinkMode */
+enum {
+ /* Move vertex to the surface of the target object (keepDist towards original position) */
+ MOD_SHRINKWRAP_ON_SURFACE = 0,
+ /* Move the vertex inside the target object; don't change if already inside */
+ MOD_SHRINKWRAP_INSIDE = 1,
+ /* Move the vertex outside the target object; don't change if already outside */
+ MOD_SHRINKWRAP_OUTSIDE = 2,
+ /* Move vertex to the surface of the target object, with keepDist towards the outside */
+ MOD_SHRINKWRAP_OUTSIDE_SURFACE = 3,
+ /* Move vertex to the surface of the target object, with keepDist along the normal */
+ MOD_SHRINKWRAP_ABOVE_SURFACE = 4,
};
/* Shrinkwrap->shrinkOpts */
@@ -848,11 +923,16 @@ enum {
/* ignore vertex moves if a vertex ends projected on a back face of the target */
MOD_SHRINKWRAP_CULL_TARGET_BACKFACE = (1 << 4),
+#ifdef DNA_DEPRECATED_ALLOW
MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE = (1 << 5), /* distance is measure to the front face of the target */
+#endif
MOD_SHRINKWRAP_INVERT_VGROUP = (1 << 6),
+ MOD_SHRINKWRAP_INVERT_CULL_TARGET = (1 << 7),
};
+#define MOD_SHRINKWRAP_CULL_TARGET_MASK (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)
+
/* Shrinkwrap->projAxis */
enum {
MOD_SHRINKWRAP_PROJECT_OVER_NORMAL = 0, /* projection over normal is used if no axis is selected */
@@ -988,7 +1068,7 @@ typedef struct OceanModifierData {
char geometry_mode;
char flag;
- char refresh;
+ char pad2;
short repeat_x;
short repeat_y;
@@ -1008,13 +1088,6 @@ enum {
MOD_OCEAN_GEOM_SIM_ONLY = 2,
};
-enum {
- MOD_OCEAN_REFRESH_RESET = (1 << 0),
- /* MOD_OCEAN_REFRESH_SIM = (1 << 1), */
- /* MOD_OCEAN_REFRESH_ADD = (1 << 2), */
- MOD_OCEAN_REFRESH_CLEAR_CACHE = (1 << 3),
- /* MOD_OCEAN_REFRESH_TOPOLOGY = (1 << 4), */
-};
enum {
MOD_OCEAN_GENERATE_FOAM = (1 << 0),
@@ -1608,6 +1681,7 @@ typedef struct SDefVert {
typedef struct SurfaceDeformModifierData {
ModifierData modifier;
+ struct Depsgraph *depsgraph;
struct Object *target; /* bind target object */
SDefVert *verts; /* vertex bind data */
float falloff;
@@ -1618,7 +1692,9 @@ typedef struct SurfaceDeformModifierData {
/* Surface Deform modifier flags */
enum {
+ /* This indicates "do bind on next modifier evaluation" as well as "is bound". */
MOD_SDEF_BIND = (1 << 0),
+
MOD_SDEF_USES_LOOPTRI = (1 << 1),
MOD_SDEF_HAS_CONCAVE = (1 << 2),
};
@@ -1630,6 +1706,32 @@ enum {
MOD_SDEF_MODE_CENTROID = 2,
};
+typedef struct WeightedNormalModifierData {
+ ModifierData modifier;
+
+ char defgrp_name[64]; /* MAX_VGROUP_NAME */
+ char mode, flag;
+ short weight;
+ float thresh;
+} WeightedNormalModifierData;
+
+/* Name/id of the generic PROP_INT cdlayer storing face weights. */
+#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID "__mod_weightednormals_faceweight"
+
+/* WeightedNormalModifierData.mode */
+enum {
+ MOD_WEIGHTEDNORMAL_MODE_FACE = 0,
+ MOD_WEIGHTEDNORMAL_MODE_ANGLE = 1,
+ MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE = 2,
+};
+
+/* WeightedNormalModifierData.flag */
+enum {
+ MOD_WEIGHTEDNORMAL_KEEP_SHARP = (1 << 0),
+ MOD_WEIGHTEDNORMAL_INVERT_VGROUP = (1 << 1),
+ MOD_WEIGHTEDNORMAL_FACE_INFLUENCE = (1 << 2),
+};
+
#define MOD_MESHSEQ_READ_ALL \
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 91dc58ed1d4..a776fbbc3a6 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -221,8 +221,11 @@ typedef struct bNode {
* and replacing all uses with per-instance data.
*/
short preview_xsize, preview_ysize; /* reserved size of the preview rect */
- int pad2;
+ short pad2[2];
struct uiBlock *block; /* runtime during drawing */
+
+ float ssr_id; /* XXX: eevee only, id of screen space reflection layer, needs to be a float to feed GPU_uniform. */
+ float sss_id; /* XXX: eevee only, id of screen subsurface scatter layer, needs to be a float to feed GPU_uniform. */
} bNode;
/* node->flag */
@@ -416,7 +419,8 @@ typedef struct bNodeTree {
#define NTREE_TWO_PASS 4 /* two pass */
#define NTREE_COM_GROUPNODE_BUFFER 8 /* use groupnode buffers */
#define NTREE_VIEWER_BORDER 16 /* use a border for viewer nodes */
-#define NTREE_IS_LOCALIZED 32 /* tree is localized copy, free when deleting node groups */
+/* NOTE: DEPRECATED, use (id->tag & LIB_TAG_LOCALIZED) instead. */
+/*#define NTREE_IS_LOCALIZED 32*/ /* tree is localized copy, free when deleting node groups */
/* XXX not nice, but needed as a temporary flags
* for group updates after library linking.
@@ -650,11 +654,6 @@ typedef struct NodeTwoFloats {
float x, y;
} NodeTwoFloats;
-typedef struct NodeGeometry {
- char uvname[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
- char colname[64];
-} NodeGeometry;
-
typedef struct NodeVertexCol {
char name[64];
} NodeVertexCol;
@@ -1125,39 +1124,6 @@ enum {
#define CMP_NODE_MASK_MBLUR_SAMPLES_MAX 64
-/* geometry output socket defines */
-#define GEOM_OUT_GLOB 0
-#define GEOM_OUT_LOCAL 1
-#define GEOM_OUT_VIEW 2
-#define GEOM_OUT_ORCO 3
-#define GEOM_OUT_UV 4
-#define GEOM_OUT_NORMAL 5
-#define GEOM_OUT_VCOL 6
-#define GEOM_OUT_VCOL_ALPHA 7
-#define GEOM_OUT_FRONTBACK 8
-
-/* material input socket defines */
-#define MAT_IN_COLOR 0
-#define MAT_IN_SPEC 1
-#define MAT_IN_REFL 2
-#define MAT_IN_NORMAL 3
-#define MAT_IN_MIR 4
-#define MAT_IN_AMB 5
-#define MAT_IN_EMIT 6
-#define MAT_IN_SPECTRA 7
-#define MAT_IN_RAY_MIRROR 8
-#define MAT_IN_ALPHA 9
-#define MAT_IN_TRANSLUCENCY 10
-#define NUM_MAT_IN 11 /* for array size */
-
-/* material output socket defines */
-#define MAT_OUT_COLOR 0
-#define MAT_OUT_ALPHA 1
-#define MAT_OUT_NORMAL 2
-#define MAT_OUT_DIFFUSE 3
-#define MAT_OUT_SPEC 4
-#define MAT_OUT_AO 5
-
/* image */
#define CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT 1
@@ -1200,4 +1166,12 @@ enum {
SHD_POINTDENSITY_COLOR_VERTNOR = 2,
};
+/* Output shader node */
+
+typedef enum NodeShaderOutputTarget {
+ SHD_OUTPUT_ALL = 0,
+ SHD_OUTPUT_EEVEE = 1,
+ SHD_OUTPUT_CYCLES = 2,
+} NodeShaderOutputTarget;
+
#endif
diff --git a/source/blender/makesdna/DNA_object_enums.h b/source/blender/makesdna/DNA_object_enums.h
index 58f9e29297f..8a7016ccd13 100644
--- a/source/blender/makesdna/DNA_object_enums.h
+++ b/source/blender/makesdna/DNA_object_enums.h
@@ -37,13 +37,22 @@ typedef enum eObjectMode {
OB_MODE_TEXTURE_PAINT = 1 << 4,
OB_MODE_PARTICLE_EDIT = 1 << 5,
OB_MODE_POSE = 1 << 6,
- OB_MODE_GPENCIL = 1 << 7, /* NOTE: Just a dummy to make the UI nicer */
+ OB_MODE_GPENCIL_EDIT = 1 << 7,
+ OB_MODE_GPENCIL_PAINT = 1 << 8,
+ OB_MODE_GPENCIL_SCULPT = 1 << 9,
+ OB_MODE_GPENCIL_WEIGHT = 1 << 10,
} eObjectMode;
/* Any mode where the brush system is used. */
#define OB_MODE_ALL_PAINT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)
+#define OB_MODE_ALL_PAINT_GPENCIL (OB_MODE_GPENCIL_PAINT | OB_MODE_GPENCIL_SCULPT | OB_MODE_GPENCIL_WEIGHT)
+
/* Any mode that uses Object.sculpt. */
#define OB_MODE_ALL_SCULPT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)
+/* Any mode that has data we need to free when switching modes, see: #ED_object_mode_generic_exit */
+#define OB_MODE_ALL_MODE_DATA \
+ (OB_MODE_EDIT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_SCULPT | OB_MODE_POSE)
+
#endif /* __DNA_OBJECT_ENUMS_H__ */
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index c90a626784a..6e42284f1a4 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -37,6 +37,7 @@ extern "C" {
#endif
#include "DNA_listBase.h"
+#include "DNA_defs.h"
/* pd->forcefield: Effector Fields types */
typedef enum ePFieldType {
@@ -112,11 +113,20 @@ typedef struct PartDeflect {
float f_noise; /* noise of force */
int seed; /* noise random seed */
+ /* Display Size */
+ float drawvec1[4]; /* Runtime only : start of the curve or draw scale */
+ float drawvec2[4]; /* Runtime only : end of the curve */
+ float drawvec_falloff_min[3], pad1; /* Runtime only */
+ float drawvec_falloff_max[3], pad2; /* Runtime only */
+
struct Object *f_source; /* force source object */
+
+ float pdef_cfrict; /* Friction of cloth collisions. */
+ float pad;
} PartDeflect;
typedef struct EffectorWeights {
- struct Group *group; /* only use effectors from this group of objects */
+ struct Collection *group; /* only use effectors from this group of objects */
float weight[14]; /* effector type specific weights */
float global_gravity;
@@ -212,58 +222,14 @@ typedef struct SBVertex {
float vec[4];
} SBVertex;
-typedef struct BulletSoftBody {
- int flag; /* various boolean options */
- float linStiff; /* linear stiffness 0..1 */
- float angStiff; /* angular stiffness 0..1 */
- float volume; /* volume preservation 0..1 */
-
- int viterations; /* Velocities solver iterations */
- int piterations; /* Positions solver iterations */
- int diterations; /* Drift solver iterations */
- int citerations; /* Cluster solver iterations */
-
- float kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */
- float kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */
- float kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */
- float kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
-
- float kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
- float kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
- float kVCF; /* Velocities correction factor (Baumgarte) */
- float kDP; /* Damping coefficient [0,1] */
-
- float kDG; /* Drag coefficient [0,+inf] */
- float kLF; /* Lift coefficient [0,+inf] */
- float kPR; /* Pressure coefficient [-inf,+inf] */
- float kVC; /* Volume conversation coefficient [0,+inf] */
-
- float kDF; /* Dynamic friction coefficient [0,1] */
- float kMT; /* Pose matching coefficient [0,1] */
- float kCHR; /* Rigid contacts hardness [0,1] */
- float kKHR; /* Kinetic contacts hardness [0,1] */
-
- float kSHR; /* Soft contacts hardness [0,1] */
- float kAHR; /* Anchors hardness [0,1] */
- int collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */
- int numclusteriterations; /* number of iterations to refine collision clusters*/
- float welding; /* welding limit to remove duplicate/nearby vertices, 0.0..0.01 */
- float margin; /* margin specific to softbody */
-} BulletSoftBody;
-
-/* BulletSoftBody.flag */
-#define OB_BSB_SHAPE_MATCHING 2
-// #define OB_BSB_UNUSED 4
-#define OB_BSB_BENDING_CONSTRAINTS 8
-#define OB_BSB_AERO_VPOINT 16 /* aero model, Vertex normals are oriented toward velocity*/
-// #define OB_BSB_AERO_VTWOSIDE 32 /* aero model, Vertex normals are flipped to match velocity */
-
-/* BulletSoftBody.collisionflags */
-#define OB_BSB_COL_SDF_RS 2 /* SDF based rigid vs soft */
-#define OB_BSB_COL_CL_RS 4 /* Cluster based rigid vs soft */
-#define OB_BSB_COL_CL_SS 8 /* Cluster based soft vs soft */
-#define OB_BSB_COL_VF_SS 16 /* Vertex/Face based soft vs soft */
-
+/* Container for data that is shared among CoW copies.
+ *
+ * This is placed in a separate struct so that values can be changed
+ * without having to update all CoW copies. */
+typedef struct SoftBody_Shared {
+ struct PointCache *pointcache;
+ struct ListBase ptcaches;
+} SoftBody_Shared;
typedef struct SoftBody {
/* dynamic data */
@@ -336,10 +302,11 @@ typedef struct SoftBody {
float shearstiff;
float inpush;
- struct PointCache *pointcache;
- struct ListBase ptcaches;
+ struct SoftBody_Shared *shared;
+ struct PointCache *pointcache DNA_DEPRECATED; /* Moved to SoftBody_Shared */
+ struct ListBase ptcaches DNA_DEPRECATED; /* Moved to SoftBody_Shared */
- struct Group *collision_group;
+ struct Collection *collision_group;
struct EffectorWeights *effector_weights;
/* reverse esimated obmatrix .. no need to store in blend file .. how ever who cares */
@@ -373,6 +340,8 @@ typedef struct SoftBody {
#define PFIELD_GUIDE_PATH_WEIGHT (1<<16) /* apply curve weights */
#define PFIELD_SMOKE_DENSITY (1<<17) /* multiply smoke force by density */
#define PFIELD_GRAVITATION (1<<18) /* used for (simple) force */
+#define PFIELD_CLOTH_USE_CULLING (1<<19) /* Enable cloth collision side detection based on normal. */
+#define PFIELD_CLOTH_USE_NORMAL (1<<20) /* Replace collision direction with collider normal. */
/* pd->falloff */
#define PFIELD_FALL_SPHERE 0
@@ -384,6 +353,7 @@ typedef struct SoftBody {
#define PFIELD_SHAPE_PLANE 1
#define PFIELD_SHAPE_SURFACE 2
#define PFIELD_SHAPE_POINTS 3
+#define PFIELD_SHAPE_LINE 4
/* pd->tex_mode */
#define PFIELD_TEX_RGB 0
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index a9b43a5a957..631bb26feec 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -58,7 +58,7 @@ struct DerivedMesh;
struct SculptSession;
struct bGPdata;
struct RigidBodyOb;
-
+struct GpencilBatchCache;
/* Vertex Groups - Name Info */
typedef struct bDeformGroup {
@@ -67,6 +67,15 @@ typedef struct bDeformGroup {
/* need this flag for locking weights */
char flag, pad[7];
} bDeformGroup;
+
+/* Face Maps*/
+typedef struct bFaceMap {
+ struct bFaceMap *next, *prev;
+ char name[64]; /* MAX_VGROUP_NAME */
+ char flag;
+ char pad[7];
+} bFaceMap;
+
#define MAX_VGROUP_NAME 64
/* bDeformGroup->flag */
@@ -114,9 +123,45 @@ typedef struct LodLevel {
int obhysteresis;
} LodLevel;
+typedef struct ObjectDisplay {
+ int flag;
+} ObjectDisplay;
+
+/* Forward declaration for cache bbone deformation information.
+ *
+ * TODO(sergey): Consider moving it to more appropriate place. */
+struct ObjectBBoneDeform;
+
+/* Not saved in file! */
+typedef struct Object_Runtime {
+ /* Original mesh pointer, before object->data was changed to point
+ * to mesh_eval.
+ * Is assigned by dependency graph's copy-on-write evaluation.
+ */
+ struct Mesh *mesh_orig;
+ /* Mesh structure created during object evaluation.
+ * It has all modifiers applied.
+ */
+ struct Mesh *mesh_eval;
+ /* Mesh structure created during object evaluation.
+ * It has deforemation only modifiers applied on it.
+ */
+ struct Mesh *mesh_deform_eval;
+
+
+ /* Runtime evaluated curve-specific data, not stored in the file. */
+ struct CurveCache *curve_cache;
+
+ /* Runtime grease pencil drawing data */
+ struct GpencilBatchCache *gpencil_cache;
+
+ struct ObjectBBoneDeform *cached_bbone_deformation;
+} Object_Runtime;
+
typedef struct Object {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
+ struct DrawDataList drawdata; /* runtime (must be immediately after id for utilities to use it). */
struct SculptSession *sculpt;
@@ -145,9 +190,12 @@ typedef struct Object {
ListBase effect DNA_DEPRECATED; // XXX deprecated... keep for readfile
ListBase defbase; /* list of bDeformGroup (vertex groups) names and flag only */
ListBase modifiers; /* list of ModifierData structures */
+ ListBase greasepencil_modifiers; /* list of GpencilModifierData structures */
+ ListBase fmaps; /* list of facemaps */
+ ListBase shader_fx; /* list of viewport effects. Actually only used by grease pencil */
int mode; /* Local object mode */
- int restore_mode; /* Keep track of what mode to return to after toggling a mode */
+ int restore_mode;
/* materials */
struct Material **mat; /* material slots */
@@ -178,7 +226,7 @@ typedef struct Object {
*/
float imat_ren[4][4];
- unsigned int lay; /* copy of Base's layer in the scene */
+ unsigned int lay DNA_DEPRECATED; /* copy of Base's layer in the scene */
short flag; /* copy of Base */
short colbits DNA_DEPRECATED; /* deprecated, use 'matbits' */
@@ -186,47 +234,18 @@ typedef struct Object {
short transflag, protectflag; /* transformation settings and transform locks */
short trackflag, upflag;
short nlaflag; /* used for DopeSheet filtering settings (expanded/collapsed) */
- short scaflag; /* ui state for game logic */
- char scavisflag; /* more display settings for game logic */
- char depsflag;
+ short pad[2];
/* did last modifier stack generation need mapping support? */
char lastNeedMapping; /* bool */
- char pad;
+ char duplicator_visibility_flag;
/* dupli-frame settings */
int dupon, dupoff, dupsta, dupend;
- /* during realtime */
-
- /* note that inertia is only called inertia for historical reasons
- * and is not changed to avoid DNA surgery. It actually reflects the
- * Size value in the GameButtons (= radius) */
-
- float mass, damping, inertia;
- /* The form factor k is introduced to give the user more control
- * and to fix incompatibility problems.
- * For rotational symmetric objects, the inertia value can be
- * expressed as: Theta = k * m * r^2
- * where m = Mass, r = Radius
- * For a Sphere, the form factor is by default = 0.4
- */
-
- float formfactor;
- float rdamping;
- float margin;
- float max_vel; /* clamp the maximum velocity 0.0 is disabled */
- float min_vel; /* clamp the minimum velocity 0.0 is disabled */
- float max_angvel; /* clamp the maximum angular velocity, 0.0 is disabled */
- float min_angvel; /* clamp the minimum angular velocity, 0.0 is disabled */
- float obstacleRad;
-
- /* "Character" physics properties */
- float step_height;
- float jump_speed;
- float fall_speed;
- unsigned char max_jumps;
- char pad2[3];
+ /* Depsgraph */
+ short base_flag; /* used by depsgraph, flushed from base */
+ unsigned short base_local_view_bits; /* used by viewport, synced from base */
/** Collision mask settings */
unsigned short col_group, col_mask;
@@ -242,66 +261,66 @@ typedef struct Object {
float empty_drawsize;
float dupfacesca; /* dupliface scale */
- ListBase prop; /* game logic property list (not to be confused with IDProperties) */
- ListBase sensors; /* game logic sensors */
- ListBase controllers; /* game logic controllers */
- ListBase actuators; /* game logic actuators */
-
float sf; /* sf is time-offset */
short index; /* custom index, for renderpasses */
unsigned short actdef; /* current deformation group, note: index starts at 1 */
+ unsigned short actfmap; /* current face map, note: index starts at 1 */
+ unsigned char pad5[6];
float col[4]; /* object color */
- int gameflag;
- int gameflag2;
-
char restrictflag; /* for restricting view, select, render etc. accessible in outliner */
- char recalc; /* dependency flag */
+ char pad3;
short softflag; /* softbody settings */
- float anisotropicFriction[3];
+ int pad2;
ListBase constraints; /* object constraints */
ListBase nlastrips DNA_DEPRECATED; // XXX deprecated... old animation system
ListBase hooks DNA_DEPRECATED; // XXX deprecated... old animation system
ListBase particlesystem; /* particle systems */
- struct BulletSoftBody *bsoft; /* settings for game engine bullet soft body */
struct PartDeflect *pd; /* particle deflector/attractor/collision data */
struct SoftBody *soft; /* if exists, saved in file */
- struct Group *dup_group; /* object duplicator for group */
+ struct Collection *dup_group; /* object duplicator for group */
+ void *pad10;
- char body_type; /* for now used to temporarily holds the type of collision object */
+ char pad4;
char shapeflag; /* flag for pinning */
short shapenr; /* current shape key for menu or pinned */
float smoothresh; /* smoothresh is phong interpolation ray_shadow correction in render */
struct FluidsimSettings *fluidsimSettings; /* if fluidsim enabled, store additional settings */
- /* Runtime valuated curve-specific data, not stored in the file */
- struct CurveCache *curve_cache;
-
struct DerivedMesh *derivedDeform, *derivedFinal;
+ void *pad7;
uint64_t lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */
uint64_t customdata_mask; /* (extra) custom data layer mask to use for creating derivedmesh, set by depsgraph */
- unsigned int state; /* bit masks of game controllers that are active */
- unsigned int init_state; /* bit masks of initial state as recorded by the users */
- ListBase gpulamp; /* runtime, for glsl lamp display only */
ListBase pc_ids;
- ListBase *duplilist; /* for temporary dupli list storage, only for use by RNA API */
struct RigidBodyOb *rigidbody_object; /* settings for Bullet rigid body */
struct RigidBodyCon *rigidbody_constraint; /* settings for Bullet constraint */
float ima_ofs[2]; /* offset for image empties */
- ImageUser *iuser; /* must be non-null when oject is an empty image */
- void *pad3;
+ ImageUser *iuser; /* must be non-null when object is an empty image */
+ char empty_image_visibility_flag;
+ char empty_image_depth;
+ char pad11[6];
ListBase lodlevels; /* contains data for levels of detail */
LodLevel *currentlod;
struct PreviewImage *preview;
+
+ int pad6;
+ int select_color;
+
+ /* Runtime evaluation data. */
+ Object_Runtime runtime;
+
+ /* Object Display */
+ struct ObjectDisplay display;
+ int pad9;
} Object;
/* Warning, this is not used anymore because hooks are now modifiers */
@@ -322,26 +341,6 @@ typedef struct ObHook {
float force;
} ObHook;
-/* runtime only, but include here for rna access */
-typedef struct DupliObject {
- struct DupliObject *next, *prev;
- struct Object *ob;
- float mat[4][4];
- float orco[3], uv[2];
-
- short type; /* from Object.transflag */
- char no_draw, animated;
-
- /* persistent identifier for a dupli object, for inter-frame matching of
- * objects with motion blur, or inter-update matching for syncing */
- int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */
-
- /* particle this dupli was generated from */
- struct ParticleSystem *particle_system;
- unsigned int random_id;
- unsigned int pad;
-} DupliObject;
-
/* **************** OBJECT ********************* */
/* used many places... should be specialized */
@@ -360,19 +359,29 @@ enum {
OB_CAMERA = 11,
OB_SPEAKER = 12,
+ OB_LIGHTPROBE = 13,
/* OB_WAVE = 21, */
OB_LATTICE = 22,
/* 23 and 24 are for life and sector (old file compat.) */
OB_ARMATURE = 25,
+/* Grease Pencil object used in 3D view but not used for annotation in 2D */
+ OB_GPENCIL = 26,
+
+ OB_TYPE_MAX,
+};
+
+/* ObjectDisplay.flag */
+enum {
+ OB_SHOW_SHADOW = (1 << 0),
};
/* check if the object type supports materials */
#define OB_TYPE_SUPPORT_MATERIAL(_type) \
- ((_type) >= OB_MESH && (_type) <= OB_MBALL)
+ (((_type) >= OB_MESH && (_type) <= OB_MBALL) || ((_type) == OB_GPENCIL))
#define OB_TYPE_SUPPORT_VGROUP(_type) \
- (ELEM(_type, OB_MESH, OB_LATTICE))
+ (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL))
#define OB_TYPE_SUPPORT_EDITMODE(_type) \
(ELEM(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE))
#define OB_TYPE_SUPPORT_PARVERT(_type) \
@@ -384,10 +393,10 @@ enum {
/* is this ID type used as object data */
#define OB_DATA_SUPPORT_ID(_id_type) \
- (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_CA, ID_LT, ID_AR))
+ (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_LP, ID_CA, ID_LT, ID_GD, ID_AR))
#define OB_DATA_SUPPORT_ID_CASE \
- ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_CA: case ID_LT: case ID_AR
+ ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_LP: case ID_CA: case ID_LT: case ID_GD: case ID_AR
/* partype: first 4 bits: type */
enum {
@@ -416,7 +425,7 @@ enum {
OB_DUPLIROT = 1 << 5,
OB_DUPLINOSPEED = 1 << 6,
OB_DUPLICALCDERIVED = 1 << 7, /* runtime, calculate derivedmesh for dupli before it's used */
- OB_DUPLIGROUP = 1 << 8,
+ OB_DUPLICOLLECTION = 1 << 8,
OB_DUPLIFACES = 1 << 9,
OB_DUPLIFACES_SCALE = 1 << 10,
OB_DUPLIPARTS = 1 << 11,
@@ -424,7 +433,7 @@ enum {
OB_NO_CONSTRAINTS = 1 << 13, /* runtime constraints disable */
OB_NO_PSYS_UPDATE = 1 << 14, /* hack to work around particle issue */
- OB_DUPLI = OB_DUPLIFRAMES | OB_DUPLIVERTS | OB_DUPLIGROUP | OB_DUPLIFACES | OB_DUPLIPARTS,
+ OB_DUPLI = OB_DUPLIFRAMES | OB_DUPLIVERTS | OB_DUPLICOLLECTION | OB_DUPLIFACES | OB_DUPLIPARTS,
};
/* (short) trackflag / upflag */
@@ -437,8 +446,6 @@ enum {
OB_NEGZ = 5,
};
-/* gameflag in game.h */
-
/* dt: no flags */
enum {
OB_BOUNDBOX = 1,
@@ -447,8 +454,6 @@ enum {
OB_MATERIAL = 4,
OB_TEXTURE = 5,
OB_RENDER = 6,
-
- OB_PAINT = 100, /* temporary used in draw code */
};
/* dtx: flags (short) */
@@ -479,6 +484,13 @@ enum {
OB_EMPTY_IMAGE = 8,
};
+/* gpencil add types */
+enum {
+ GP_EMPTY = 0,
+ GP_STROKE = 1,
+ GP_MONKEY = 2
+};
+
/* boundtype */
enum {
OB_BOUND_BOX = 0,
@@ -519,16 +531,10 @@ enum {
#define BA_TRANSFORM_CHILD (1 << 8) /* child of a transformed object */
#define BA_TRANSFORM_PARENT (1 << 13) /* parent of a transformed object */
-
-/* an initial attempt as making selection more specific! */
-#define BA_DESELECT 0
-#define BA_SELECT 1
-
-
#define OB_FROMDUPLI (1 << 9)
#define OB_DONE (1 << 10) /* unknown state, clear before use */
/* #define OB_RADIO (1 << 11) */ /* deprecated */
-#define OB_FROMGROUP (1 << 12)
+/* #define OB_FROMGROUP (1 << 12) */ /* deprecated */
/* WARNING - when adding flags check on PSYS_RECALC */
/* ob->recalc (flag bits!) */
@@ -547,90 +553,6 @@ enum {
/* collision masks */
#define OB_MAX_COL_MASKS 16
-/* ob->gameflag */
-enum {
- OB_DYNAMIC = 1 << 0,
- OB_CHILD = 1 << 1,
- OB_ACTOR = 1 << 2,
- OB_INERTIA_LOCK_X = 1 << 3,
- OB_INERTIA_LOCK_Y = 1 << 4,
- OB_INERTIA_LOCK_Z = 1 << 5,
- OB_DO_FH = 1 << 6,
- OB_ROT_FH = 1 << 7,
- OB_ANISOTROPIC_FRICTION = 1 << 8,
- OB_GHOST = 1 << 9,
- OB_RIGID_BODY = 1 << 10,
- OB_BOUNDS = 1 << 11,
-
- OB_COLLISION_RESPONSE = 1 << 12,
- OB_SECTOR = 1 << 13,
- OB_PROP = 1 << 14,
- OB_MAINACTOR = 1 << 15,
-
- OB_COLLISION = 1 << 16,
- OB_SOFT_BODY = 1 << 17,
- OB_OCCLUDER = 1 << 18,
- OB_SENSOR = 1 << 19,
- OB_NAVMESH = 1 << 20,
- OB_HASOBSTACLE = 1 << 21,
- OB_CHARACTER = 1 << 22,
-
- OB_RECORD_ANIMATION = 1 << 23,
-};
-
-/* ob->gameflag2 */
-enum {
- OB_NEVER_DO_ACTIVITY_CULLING = 1 << 0,
- OB_LOCK_RIGID_BODY_X_AXIS = 1 << 2,
- OB_LOCK_RIGID_BODY_Y_AXIS = 1 << 3,
- OB_LOCK_RIGID_BODY_Z_AXIS = 1 << 4,
- OB_LOCK_RIGID_BODY_X_ROT_AXIS = 1 << 5,
- OB_LOCK_RIGID_BODY_Y_ROT_AXIS = 1 << 6,
- OB_LOCK_RIGID_BODY_Z_ROT_AXIS = 1 << 7,
-
-/* OB_LIFE = OB_PROP | OB_DYNAMIC | OB_ACTOR | OB_MAINACTOR | OB_CHILD, */
-};
-
-/* ob->body_type */
-enum {
- OB_BODY_TYPE_NO_COLLISION = 0,
- OB_BODY_TYPE_STATIC = 1,
- OB_BODY_TYPE_DYNAMIC = 2,
- OB_BODY_TYPE_RIGID = 3,
- OB_BODY_TYPE_SOFT = 4,
- OB_BODY_TYPE_OCCLUDER = 5,
- OB_BODY_TYPE_SENSOR = 6,
- OB_BODY_TYPE_NAVMESH = 7,
- OB_BODY_TYPE_CHARACTER = 8,
-};
-
-/* ob->depsflag */
-enum {
- OB_DEPS_EXTRA_OB_RECALC = 1 << 0,
- OB_DEPS_EXTRA_DATA_RECALC = 1 << 1,
-};
-
-/* ob->scavisflag */
-enum {
- OB_VIS_SENS = 1 << 0,
- OB_VIS_CONT = 1 << 1,
- OB_VIS_ACT = 1 << 2,
-};
-
-/* ob->scaflag */
-enum {
- OB_SHOWSENS = 1 << 6,
- OB_SHOWACT = 1 << 7,
- OB_ADDSENS = 1 << 8,
- OB_ADDCONT = 1 << 9,
- OB_ADDACT = 1 << 10,
- OB_SHOWCONT = 1 << 11,
- OB_ALLSTATE = 1 << 12,
- OB_INITSTBIT = 1 << 13,
- OB_DEBUGSTATE = 1 << 14,
- OB_SHOWSTATE = 1 << 15,
-};
-
/* ob->restrictflag */
enum {
OB_RESTRICT_VIEW = 1 << 0,
@@ -678,6 +600,24 @@ enum {
OB_LOCK_ROT4D = 1 << 10,
};
+/* ob->duplicator_visibility_flag */
+enum {
+ OB_DUPLI_FLAG_VIEWPORT = 1 << 0,
+ OB_DUPLI_FLAG_RENDER = 1 << 1,
+};
+
+/* ob->empty_image_depth */
+#define OB_EMPTY_IMAGE_DEPTH_DEFAULT 0
+#define OB_EMPTY_IMAGE_DEPTH_FRONT 1
+#define OB_EMPTY_IMAGE_DEPTH_BACK 2
+
+/* ob->empty_image_visibility_flag */
+enum {
+ OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE = 1 << 0,
+ OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC = 1 << 1,
+ OB_EMPTY_IMAGE_VISIBLE_BACKSIDE = 1 << 2,
+};
+
#define MAX_DUPLI_RECUR 8
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h
index ed78e302022..75d0ce493f5 100644
--- a/source/blender/makesdna/DNA_outliner_types.h
+++ b/source/blender/makesdna/DNA_outliner_types.h
@@ -38,6 +38,9 @@ struct ID;
typedef struct TreeStoreElem {
short type, nr, flag, used;
+
+ /* XXX We actually also store non-ID data in this pointer for identifying
+ * the TreeStoreElem for a TreeElement when rebuilding the tree. Ugly! */
struct ID *id;
} TreeStoreElem;
@@ -50,11 +53,18 @@ typedef struct TreeStore {
} TreeStore;
/* TreeStoreElem->flag */
-#define TSE_CLOSED 1
-#define TSE_SELECTED 2
-#define TSE_TEXTBUT 4
-#define TSE_CHILDSEARCH 8
-#define TSE_SEARCHMATCH 16
+enum {
+ TSE_CLOSED = (1 << 0),
+ TSE_SELECTED = (1 << 1),
+ TSE_TEXTBUT = (1 << 2),
+ TSE_CHILDSEARCH = (1 << 3),
+ TSE_SEARCHMATCH = (1 << 4),
+ TSE_HIGHLIGHTED = (1 << 5),
+ TSE_DRAG_INTO = (1 << 6),
+ TSE_DRAG_BEFORE = (1 << 7),
+ TSE_DRAG_AFTER = (1 << 8),
+ TSE_DRAG_ANY = (TSE_DRAG_INTO | TSE_DRAG_BEFORE | TSE_DRAG_AFTER),
+};
/* TreeStoreElem->types */
#define TSE_NLA 1 /* NO ID */
@@ -78,7 +88,7 @@ typedef struct TreeStore {
#define TSE_PROXY 18
#define TSE_R_LAYER_BASE 19
#define TSE_R_LAYER 20
-#define TSE_R_PASS 21
+/* #define TSE_R_PASS 21 */ /* UNUSED */
#define TSE_LINKED_MAT 22
/* NOTE, is used for light group */
#define TSE_LINKED_LAMP 23
@@ -96,6 +106,10 @@ typedef struct TreeStore {
#define TSE_KEYMAP_ITEM 35 /* NO ID */
#define TSE_ID_BASE 36 /* NO ID */
#define TSE_GP_LAYER 37 /* NO ID */
+#define TSE_LAYER_COLLECTION 38
+#define TSE_SCENE_COLLECTION_BASE 39
+#define TSE_VIEW_COLLECTION_BASE 40
+#define TSE_SCENE_OBJECTS_BASE 41
/* Check whether given TreeStoreElem should have a real ID in its ->id member. */
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 26a99f49d86..5d830cf3d5f 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -160,14 +160,15 @@ typedef struct ParticleSettings {
struct SPHFluidSettings *fluid;
struct EffectorWeights *effector_weights;
- struct Group *collision_group;
+ struct Collection *collision_group;
int flag, rt;
short type, from, distr, texact;
/* physics modes */
short phystype, rotmode, avemode, reactevent;
- int draw, pad1;
- short draw_as, draw_size, childtype, pad2;
+ int draw;
+ float draw_size;
+ short draw_as, pad1, childtype, pad2;
short ren_as, subframes, draw_col;
/* number of path segments, power of 2 except */
short draw_step, ren_step;
@@ -187,11 +188,6 @@ typedef struct ParticleSettings {
/* draw color */
float color_vec_max;
- /* simplification */
- short simplify_flag, simplify_refsize;
- float simplify_rate, simplify_transition;
- float simplify_viewport;
-
/* time and emission */
float sta, end, lifetime, randlife;
float timetweak, courant_target;
@@ -248,9 +244,9 @@ typedef struct ParticleSettings {
struct MTex *mtex[18]; /* MAX_MTEX */
- struct Group *dup_group;
+ struct Collection *dup_group;
struct ListBase dupliweights;
- struct Group *eff_group DNA_DEPRECATED; // deprecated
+ struct Collection *eff_group DNA_DEPRECATED; // deprecated
struct Object *dup_ob;
struct Object *bb_ob;
struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
@@ -259,10 +255,18 @@ typedef struct ParticleSettings {
/* modified dm support */
short use_modifier_stack;
- short pad5[3];
+ short pad5;
+
+ /* hair shape */
+ short shape_flag;
+ short pad6;
+
+ float twist, pad8;
+
+ /* hair thickness shape */
+ float shape;
+ float rad_root, rad_tip, rad_scale;
- float twist;
- float pad6;
struct CurveMapping *twistcurve;
void *pad7;
} ParticleSettings;
@@ -286,7 +290,7 @@ typedef struct ParticleSystem {
ListBase pathcachebufs, childcachebufs; /* buffers for the above */
struct ClothModifierData *clmd; /* cloth simulation for hair */
- struct DerivedMesh *hair_in_dm, *hair_out_dm; /* input/output for cloth simulation */
+ struct Mesh *hair_in_mesh, *hair_out_mesh; /* input/output for cloth simulation */
struct Object *target_ob;
@@ -310,9 +314,6 @@ typedef struct ParticleSystem {
short vgroup[13], vg_neg, rt3; /* vertex groups, 0==disable, 1==starting index */
char pad[6];
- /* temporary storage during render */
- struct ParticleRenderData *renderdata;
-
/* point cache */
struct PointCache *pointcache;
struct ListBase ptcaches;
@@ -329,13 +330,26 @@ typedef struct ParticleSystem {
float dt_frac; /* current time step, as a fraction of a frame */
float lattice_strength; /* influence of the lattice modifier */
+
+ void *batch_cache;
+
+ /* Set by dependency graph's copy-on-write, allows to quickly go
+ * from evaluated particle system to original one.
+ *
+ * Original system will have this set to NULL.
+ *
+ * Use psys_orig_get() function to access,
+ */
+ struct ParticleSystem *orig_psys;
} ParticleSystem;
typedef enum eParticleDrawFlag {
PART_DRAW_VEL = (1 << 0),
PART_DRAW_GLOBAL_OB = (1 << 1),
PART_DRAW_SIZE = (1 << 2),
- PART_DRAW_EMITTER = (1 << 3), /* render emitter also */
+#ifdef DNA_DEPRECATED
+ PART_DRAW_EMITTER = (1 << 3), /* render emitter also */ /* DEPRECATED */
+#endif
PART_DRAW_HEALTH = (1 << 4),
PART_ABS_PATH_TIME = (1 << 5),
PART_DRAW_COUNT_GR = (1 << 6),
@@ -443,6 +457,11 @@ typedef enum eParticleChildFlag {
PART_CHILD_USE_TWIST_CURVE = (1<<3),
} eParticleChildFlag;
+/* part->shape_flag */
+typedef enum eParticleShapeFlag {
+ PART_SHAPE_CLOSE_TIP = (1<<0),
+} eParticleShapeFlag;
+
/* part->draw_col */
#define PART_DRAW_COL_NONE 0
#define PART_DRAW_COL_MAT 1
@@ -550,6 +569,7 @@ typedef enum eParticleChildFlag {
//#define PSYS_PROTECT_CACHE 4096 /* deprecated */
#define PSYS_DISABLED 8192
#define PSYS_OB_ANIM_RESTORE 16384 /* runtime flag */
+#define PSYS_SHARED_CACHES 32768
/* pars->flag */
#define PARS_UNEXIST 1
diff --git a/source/blender/makesdna/DNA_property_types.h b/source/blender/makesdna/DNA_property_types.h
deleted file mode 100644
index 82568e93f54..00000000000
--- a/source/blender/makesdna/DNA_property_types.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file DNA_property_types.h
- * \ingroup DNA
- * \since mar-2001
- * \author nzc
- * \attention Renderrecipe and scene decription. The fact that there is a
- * hierarchy here is a bit strange, and not desirable.
- *
- * #bProperty type is specifically for use by Objects game-logic.
- */
-
-#ifndef __DNA_PROPERTY_TYPES_H__
-#define __DNA_PROPERTY_TYPES_H__
-
-/* ********************* PROPERTY ************************ */
-
-typedef struct bProperty {
- struct bProperty *next, *prev;
- char name[64]; /* MAX_NAME */
- short type, flag;
- int data; /* data should be 4 bytes to store int,float stuff */
- void *poin; /* references data unless its a string which is malloc'd */
-
-} bProperty;
-
-/* property->type XXX Game Property, not RNA */
-#define GPROP_BOOL 0
-#define GPROP_INT 1
-#define GPROP_FLOAT 2
-#define GPROP_STRING 3
-// #define GPROP_VECTOR 4 // UNUSED
-#define GPROP_TIME 5
-
-/* property->flag */
-#define PROP_DEBUG 1
-
-#define MAX_PROPSTRING 128
-
-#endif /* __DNA_PROPERTY_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index dbfd3921b8b..1482667d8b8 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -35,13 +35,23 @@
#include "DNA_listBase.h"
-struct Group;
+struct Collection;
struct EffectorWeights;
/* ******************************** */
/* RigidBody World */
+/* Container for data shared by original and evaluated copies of RigidBodyWorld */
+typedef struct RigidBodyWorld_Shared {
+ /* cache */
+ struct PointCache *pointcache;
+ struct ListBase ptcaches;
+
+ /* References to Physics Sim objects. Exist at runtime only ---------------------- */
+ void *physics_world; /* Physics sim world (i.e. btDiscreteDynamicsWorld) */
+} RigidBodyWorld_Shared;
+
/* RigidBodyWorld (rbw)
*
* Represents a "simulation scene" existing within the parent scene.
@@ -50,17 +60,17 @@ typedef struct RigidBodyWorld {
/* Sim World Settings ------------------------------------------------------------- */
struct EffectorWeights *effector_weights; /* effectors info */
- struct Group *group; /* Group containing objects to use for Rigid Bodies */
+ struct Collection *group; /* Group containing objects to use for Rigid Bodies */
struct Object **objects; /* Array to access group objects by index, only used at runtime */
- struct Group *constraints; /* Group containing objects to use for Rigid Body Constraints*/
+ struct Collection *constraints; /* Group containing objects to use for Rigid Body Constraints*/
int pad;
float ltime; /* last frame world was evaluated for (internal) */
- /* cache */
- struct PointCache *pointcache;
- struct ListBase ptcaches;
+ struct RigidBodyWorld_Shared *shared; /* This pointer is shared between all evaluated copies */
+ struct PointCache *pointcache DNA_DEPRECATED; /* Moved to shared->pointcache */
+ struct ListBase ptcaches DNA_DEPRECATED; /* Moved to shared->ptcaches */
int numbodies; /* number of objects in rigid body group */
short steps_per_second; /* number of simulation steps thaken per second */
@@ -68,9 +78,6 @@ typedef struct RigidBodyWorld {
int flag; /* (eRigidBodyWorld_Flag) settings for this RigidBodyWorld */
float time_scale; /* used to speed up or slow down the simulation */
-
- /* References to Physics Sim objects. Exist at runtime only ---------------------- */
- void *physics_world; /* Physics sim world (i.e. btDiscreteDynamicsWorld) */
} RigidBodyWorld;
/* Flags for RigidBodyWorld */
@@ -86,6 +93,18 @@ typedef enum eRigidBodyWorld_Flag {
/* ******************************** */
/* RigidBody Object */
+/* Container for data that is shared among CoW copies.
+ *
+ * This is placed in a separate struct so that, for example, the physics_shape
+ * pointer can be replaced without having to update all CoW copies. */
+#
+#
+typedef struct RigidBodyOb_Shared {
+ /* References to Physics Sim objects. Exist at runtime only */
+ void *physics_object; /* Physics object representation (i.e. btRigidBody) */
+ void *physics_shape; /* Collision shape used by physics sim (i.e. btCollisionShape) */
+} RigidBodyOb_Shared;
+
/* RigidBodyObject (rbo)
*
* Represents an object participating in a RigidBody sim.
@@ -93,10 +112,6 @@ typedef enum eRigidBodyWorld_Flag {
* participating in a sim.
*/
typedef struct RigidBodyOb {
- /* References to Physics Sim objects. Exist at runtime only */
- void *physics_object; /* Physics object representation (i.e. btRigidBody) */
- void *physics_shape; /* Collision shape used by physics sim (i.e. btCollisionShape) */
-
/* General Settings for this RigidBodyOb */
short type; /* (eRigidBodyOb_Type) role of RigidBody in sim */
short shape; /* (eRigidBody_Shape) collision shape to use */
@@ -123,6 +138,8 @@ typedef struct RigidBodyOb {
float orn[4]; /* rigid body orientation */
float pos[3]; /* rigid body position */
float pad1;
+
+ struct RigidBodyOb_Shared *shared; /* This pointer is shared between all evaluated copies */
} RigidBodyOb;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index c7bba869ef4..6cc689378ea 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -47,7 +47,11 @@ extern "C" {
#include "DNA_ID.h"
#include "DNA_freestyle_types.h"
#include "DNA_gpu_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_material_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
struct CurveMapping;
struct Object;
@@ -55,29 +59,20 @@ struct Brush;
struct World;
struct Scene;
struct Image;
-struct Group;
+struct Collection;
struct Text;
struct bNodeTree;
struct AnimData;
struct Editing;
struct SceneStats;
struct bGPdata;
-struct bGPDbrush;
struct MovieClip;
struct ColorSpace;
+struct SceneCollection;
/* ************************************************************* */
/* Scene Data */
-/* Base - Wrapper for referencing Objects in a Scene */
-typedef struct Base {
- struct Base *next, *prev;
- unsigned int lay, selcol;
- int flag;
- short sx, sy;
- struct Object *object;
-} Base;
-
/* ************************************************************* */
/* Output Format Data */
@@ -197,27 +192,25 @@ typedef struct AudioData {
typedef struct SceneRenderLayer {
struct SceneRenderLayer *next, *prev;
- char name[64]; /* MAX_NAME */
+ char name[64] DNA_DEPRECATED; /* MAX_NAME */
- struct Material *mat_override;
- struct Group *light_override;
+ struct Material *mat_override DNA_DEPRECATED; /* Converted to ViewLayer override. */
- unsigned int lay; /* Scene.lay itself has priority over this */
- unsigned int lay_zmask; /* has to be after lay, this is for Z-masking */
- unsigned int lay_exclude; /* not used by internal, exclude */
- int layflag;
+ unsigned int lay DNA_DEPRECATED; /* Converted to LayerCollection cycles camera visibility override. */
+ unsigned int lay_zmask DNA_DEPRECATED; /* Converted to LayerCollection cycles holdout override. */
+ unsigned int lay_exclude DNA_DEPRECATED;
+ int layflag DNA_DEPRECATED; /* Converted to ViewLayer layflag and flag. */
/* pass_xor has to be after passflag */
- /* note, this is treestore element 'nr' in outliner, short still... */
- int passflag;
- int pass_xor;
+ int passflag DNA_DEPRECATED; /* pass_xor has to be after passflag */
+ int pass_xor DNA_DEPRECATED; /* Converted to ViewLayer passflag and flag. */
- int samples;
- float pass_alpha_threshold;
+ int samples DNA_DEPRECATED; /* Converted to ViewLayer override. */
+ float pass_alpha_threshold DNA_DEPRECATED; /* Converted to ViewLayer pass_alpha_threshold. */
- IDProperty *prop;
+ IDProperty *prop DNA_DEPRECATED; /* Converted to ViewLayer id_properties. */
- struct FreestyleConfig freestyleConfig;
+ struct FreestyleConfig freestyleConfig DNA_DEPRECATED; /* Converted to ViewLayer freestyleConfig. */
} SceneRenderLayer;
/* SceneRenderLayer.layflag */
@@ -447,7 +440,7 @@ typedef struct ImageFormatData {
#define R_IMF_IMTYPE_TIFF 22
#define R_IMF_IMTYPE_OPENEXR 23
#define R_IMF_IMTYPE_FFMPEG 24
-#define R_IMF_IMTYPE_FRAMESERVER 25
+/* #define R_IMF_IMTYPE_FRAMESERVER 25 */ /* frame server is nomore */
#define R_IMF_IMTYPE_CINEON 26
#define R_IMF_IMTYPE_DPX 27
#define R_IMF_IMTYPE_MULTILAYER 28
@@ -563,6 +556,12 @@ typedef enum eBakePassFilter {
#define R_BAKE_PASS_FILTER_ALL (~0)
+/* RenderEngineSettingsClay.options */
+typedef enum ClayFlagSettings {
+ CLAY_USE_AO = (1 << 0),
+ CLAY_USE_HSV = (1 << 1),
+} ClayFlagSettings;
+
/* *************************************************************** */
/* Render Data */
@@ -581,29 +580,14 @@ typedef struct RenderData {
float framelen, blurfac;
- /** For UR edge rendering: give the edges this color */
- float edgeR, edgeG, edgeB;
-
-
- /* standalone player */ // XXX deprecated since 2.5
- short fullscreen DNA_DEPRECATED, xplay DNA_DEPRECATED, yplay DNA_DEPRECATED;
- short freqplay DNA_DEPRECATED;
- /* standalone player */ // XXX deprecated since 2.5
- short depth DNA_DEPRECATED, attrib DNA_DEPRECATED;
-
-
int frame_step; /* frames to jump during render/playback */
short stereomode DNA_DEPRECATED; /* standalone player stereo settings */ // XXX deprecated since 2.5
short dimensionspreset; /* for the dimensions presets menu */
- short filtertype; /* filter is box, tent, gauss, mitch, etc */
-
short size; /* size in % */
- short maximsize DNA_DEPRECATED; /* max in Kb */
-
short pad6;
/* from buttons: */
@@ -617,15 +601,6 @@ typedef struct RenderData {
int ysch;
/**
- * The number of part to use in the x direction
- */
- short xparts DNA_DEPRECATED;
- /**
- * The number of part to use in the y direction
- */
- short yparts DNA_DEPRECATED;
-
- /**
* render tile dimensions
*/
int tilex, tiley;
@@ -650,22 +625,6 @@ typedef struct RenderData {
int mode;
/**
- * Flags for raytrace settings. Use bit-masking to access the settings.
- */
- int raytrace_options;
-
- /**
- * Raytrace acceleration structure
- */
- short raytrace_structure;
-
- short pad1;
-
- /* octree resolution */
- short ocres;
- short pad4;
-
- /**
* What to do with the sky/background. Picks sky/premul/key
* blending for the background
*/
@@ -676,7 +635,7 @@ typedef struct RenderData {
*/
short osa;
- short frs_sec, edgeint;
+ short frs_sec, pad[7];
/* safety, border and display rect */
@@ -684,11 +643,9 @@ typedef struct RenderData {
rcti disprect;
/* information on different layers to be rendered */
- ListBase layers;
- short actlay;
-
- /* number of mblur samples */
- short mblur_samples;
+ ListBase layers DNA_DEPRECATED; /* Converted to Scene->view_layers. */
+ short actlay DNA_DEPRECATED; /* Converted to Scene->active_layer. */
+ short pad1;
/**
* Adjustment factors for the aspect ratio in the x direction, was a short in 2.45
@@ -705,18 +662,13 @@ typedef struct RenderData {
/* color management settings - color profiles, gamma correction, etc */
int color_mgt_flag;
- /** post-production settings. deprecated, but here for upwards compat (initialized to 1) */
- float postgamma, posthue, postsat;
-
/* Dither noise intensity */
float dither_intensity;
/* Bake Render options */
- short bake_osa, bake_filter, bake_mode, bake_flag;
- short bake_normal_space, bake_quad_split;
- float bake_maxdist, bake_biasdist;
- short bake_samples, bake_pad;
- float bake_user_scale, bake_pad1;
+ short bake_mode, bake_flag;
+ short bake_filter, bake_samples;
+ float bake_biasdist, bake_user_scale;
/* path to render output */
char pic[1024]; /* 1024 = FILE_MAX */
@@ -739,28 +691,12 @@ typedef struct RenderData {
char pad5[5];
/* render simplify */
- int simplify_flag;
short simplify_subsurf;
short simplify_subsurf_render;
- short simplify_shadowsamples, pad9;
+ short simplify_gpencil;
+ short pad10;
float simplify_particles;
float simplify_particles_render;
- float simplify_aosss;
-
- /* cineon */
- short cineonwhite DNA_DEPRECATED, cineonblack DNA_DEPRECATED; /*deprecated*/
- float cineongamma DNA_DEPRECATED; /*deprecated*/
-
- /* jpeg2000 */
- short jp2_preset DNA_DEPRECATED, jp2_depth DNA_DEPRECATED; /*deprecated*/
- int rpad3;
-
- /* Dome variables */ // XXX deprecated since 2.5
- short domeres DNA_DEPRECATED, domemode DNA_DEPRECATED; // XXX deprecated since 2.5
- short domeangle DNA_DEPRECATED, dometilt DNA_DEPRECATED; // XXX deprecated since 2.5
- float domeresbuf DNA_DEPRECATED; // XXX deprecated since 2.5
- float pad2;
- struct Text *dometext DNA_DEPRECATED; // XXX deprecated since 2.5
/* Freestyle line thickness options */
int line_thickness_mode;
@@ -768,6 +704,7 @@ typedef struct RenderData {
/* render engine */
char engine[32];
+ int pad2;
/* Cycles baking */
struct BakeData bake;
@@ -784,12 +721,21 @@ typedef struct RenderData {
ListBase views; /* SceneRenderView */
short actview;
short views_format;
- short pad8[2];
+
+ /* Hair Display */
+ short hair_type, hair_subdiv;
/* Motion blur shutter */
struct CurveMapping mblur_shutter_curve;
} RenderData;
+/* RenderData.hair_type */
+typedef enum eHairType {
+ SCE_HAIR_SHAPE_STRAND = 0,
+ SCE_HAIR_SHAPE_STRIP = 1,
+} eHairType;
+
+
/* *************************************************************** */
/* Render Conversion/Simplfication Settings */
@@ -807,180 +753,6 @@ typedef struct RenderProfile {
} RenderProfile;
-/* *************************************************************** */
-/* Game Engine - Dome */
-
-typedef struct GameDome {
- short res, mode;
- short angle, tilt;
- float resbuf, pad2;
- struct Text *warptext;
-} GameDome;
-
-/* GameDome.mode */
-#define DOME_FISHEYE 1
-#define DOME_TRUNCATED_FRONT 2
-#define DOME_TRUNCATED_REAR 3
-#define DOME_ENVMAP 4
-#define DOME_PANORAM_SPH 5
-#define DOME_NUM_MODES 6
-
-/* *************************************************************** */
-/* Game Engine */
-
-typedef struct GameFraming {
- float col[3];
- char type, pad1, pad2, pad3;
-} GameFraming;
-
-/* GameFraming.type */
-#define SCE_GAMEFRAMING_BARS 0
-#define SCE_GAMEFRAMING_EXTEND 1
-#define SCE_GAMEFRAMING_SCALE 2
-
-typedef struct RecastData {
- float cellsize;
- float cellheight;
- float agentmaxslope;
- float agentmaxclimb;
- float agentheight;
- float agentradius;
- float edgemaxlen;
- float edgemaxerror;
- float regionminsize;
- float regionmergesize;
- int vertsperpoly;
- float detailsampledist;
- float detailsamplemaxerror;
- char partitioning;
- char pad1;
- short pad2;
-} RecastData;
-
-/* RecastData.partitioning */
-#define RC_PARTITION_WATERSHED 0
-#define RC_PARTITION_MONOTONE 1
-#define RC_PARTITION_LAYERS 2
-
-typedef struct GameData {
-
- /* standalone player */
- struct GameFraming framing;
- short playerflag, xplay, yplay, freqplay;
- short depth, attrib, rt1, rt2;
- short aasamples, pad4[3];
-
- /* stereo/dome mode */
- struct GameDome dome;
- short stereoflag, stereomode;
- float eyeseparation;
- RecastData recastData;
-
-
- /* physics (it was in world)*/
- float gravity; /*Gravitation constant for the game world*/
-
- /*
- * Radius of the activity bubble, in Manhattan length. Objects
- * outside the box are activity-culled. */
- float activityBoxRadius;
-
- /*
- * bit 3: (gameengine): Activity culling is enabled.
- * bit 5: (gameengine) : enable Bullet DBVT tree for view frustum culling
- */
- int flag;
- short mode, matmode;
- short occlusionRes; /* resolution of occlusion Z buffer in pixel */
- short physicsEngine;
- short exitkey;
- short vsync; /* Controls vsync: off, on, or adaptive (if supported) */
- short ticrate, maxlogicstep, physubstep, maxphystep;
- short obstacleSimulation;
- short raster_storage;
- float levelHeight;
- float deactivationtime, lineardeactthreshold, angulardeactthreshold;
-
- /* Scene LoD */
- short lodflag, pad2;
- int scehysteresis, pad5;
-
-} GameData;
-
-/* GameData.stereoflag */
-#define STEREO_NOSTEREO 1
-#define STEREO_ENABLED 2
-#define STEREO_DOME 3
-
-/* GameData.stereomode */
-//#define STEREO_NOSTEREO 1
-#define STEREO_QUADBUFFERED 2
-#define STEREO_ABOVEBELOW 3
-#define STEREO_INTERLACED 4
-#define STEREO_ANAGLYPH 5
-#define STEREO_SIDEBYSIDE 6
-#define STEREO_VINTERLACE 7
-//#define STEREO_DOME 8
-#define STEREO_3DTVTOPBOTTOM 9
-
-/* GameData.physicsEngine */
-#define WOPHY_NONE 0
-#define WOPHY_BULLET 5
-
-/* obstacleSimulation */
-#define OBSTSIMULATION_NONE 0
-#define OBSTSIMULATION_TOI_rays 1
-#define OBSTSIMULATION_TOI_cells 2
-
-/* GameData.raster_storage */
-#define RAS_STORE_AUTO 0
-/* #define RAS_STORE_IMMEDIATE 1 */ /* DEPRECATED */
-#define RAS_STORE_VA 2
-#define RAS_STORE_VBO 3
-
-/* GameData.vsync */
-#define VSYNC_ON 0
-#define VSYNC_OFF 1
-#define VSYNC_ADAPTIVE 2
-
-/* GameData.flag */
-#define GAME_RESTRICT_ANIM_UPDATES (1 << 0)
-#define GAME_ENABLE_ALL_FRAMES (1 << 1)
-#define GAME_SHOW_DEBUG_PROPS (1 << 2)
-#define GAME_SHOW_FRAMERATE (1 << 3)
-#define GAME_SHOW_PHYSICS (1 << 4)
-#define GAME_DISPLAY_LISTS (1 << 5)
-#define GAME_GLSL_NO_LIGHTS (1 << 6)
-#define GAME_GLSL_NO_SHADERS (1 << 7)
-#define GAME_GLSL_NO_SHADOWS (1 << 8)
-#define GAME_GLSL_NO_RAMPS (1 << 9)
-#define GAME_GLSL_NO_NODES (1 << 10)
-#define GAME_GLSL_NO_EXTRA_TEX (1 << 11)
-#define GAME_IGNORE_DEPRECATION_WARNINGS (1 << 12)
-#define GAME_ENABLE_ANIMATION_RECORD (1 << 13)
-#define GAME_SHOW_MOUSE (1 << 14)
-#define GAME_GLSL_NO_COLOR_MANAGEMENT (1 << 15)
-#define GAME_SHOW_OBSTACLE_SIMULATION (1 << 16)
-#define GAME_NO_MATERIAL_CACHING (1 << 17)
-#define GAME_GLSL_NO_ENV_LIGHTING (1 << 18)
-/* Note: GameData.flag is now an int (max 32 flags). A short could only take 16 flags */
-
-/* GameData.playerflag */
-#define GAME_PLAYER_FULLSCREEN (1 << 0)
-#define GAME_PLAYER_DESKTOP_RESOLUTION (1 << 1)
-
-/* GameData.matmode */
-enum {
-#ifdef DNA_DEPRECATED
- GAME_MAT_TEXFACE = 0, /* deprecated */
-#endif
- GAME_MAT_MULTITEX = 1,
- GAME_MAT_GLSL = 2,
-};
-
-/* GameData.lodflag */
-#define SCE_LOD_USE_HYST (1 << 0)
-
/* UV Paint */
/* ToolSettings.uv_sculpt_settings */
#define UV_SCULPT_LOCK_BORDERS 1
@@ -1025,9 +797,28 @@ typedef struct TimeMarker {
#define PAINT_MAX_INPUT_SAMPLES 64
+typedef struct Paint_Runtime {
+ /* Avoid having to compare with scene pointer everywhere. */
+ unsigned int tool_offset;
+ unsigned short ob_mode;
+ char _pad[2];
+} Paint_Runtime;
+
+/* We might want to store other things here. */
+typedef struct PaintToolSlot {
+ struct Brush *brush;
+} PaintToolSlot;
+
/* Paint Tool Base */
typedef struct Paint {
struct Brush *brush;
+
+ /* Each tool has it's own active brush,
+ * The currently active tool is defined by the current 'brush'. */
+ struct PaintToolSlot *tool_slots;
+ int tool_slots_len;
+ char _pad1[4];
+
struct Palette *palette;
struct CurveMapping *cavity_curve; /* cavity curve */
@@ -1047,6 +838,8 @@ typedef struct Paint {
float tile_offset[3];
int pad2;
+
+ struct Paint_Runtime runtime;
} Paint;
/* ------------------------------------------- */
@@ -1141,6 +934,11 @@ typedef struct UvSculpt {
Paint paint;
} UvSculpt;
+/* grease pencil drawing brushes */
+typedef struct GpPaint {
+ Paint paint;
+} GpPaint;
+
/* ------------------------------------------- */
/* Vertex Paint */
@@ -1161,78 +959,101 @@ enum {
/* ------------------------------------------- */
/* GPencil Stroke Sculpting */
-/* GP_BrushEdit_Settings.brushtype */
-typedef enum eGP_EditBrush_Types {
- GP_EDITBRUSH_TYPE_SMOOTH = 0,
- GP_EDITBRUSH_TYPE_THICKNESS = 1,
- GP_EDITBRUSH_TYPE_GRAB = 2,
- GP_EDITBRUSH_TYPE_PUSH = 3,
- GP_EDITBRUSH_TYPE_TWIST = 4,
- GP_EDITBRUSH_TYPE_PINCH = 5,
- GP_EDITBRUSH_TYPE_RANDOMIZE = 6,
- GP_EDITBRUSH_TYPE_SUBDIVIDE = 7,
- GP_EDITBRUSH_TYPE_SIMPLIFY = 8,
- GP_EDITBRUSH_TYPE_CLONE = 9,
- GP_EDITBRUSH_TYPE_STRENGTH = 10,
-
- /* !!! Update GP_EditBrush_Data brush[###]; below !!! */
- TOT_GP_EDITBRUSH_TYPES
-} eGP_EditBrush_Types;
-
-/* GP_BrushEdit_Settings.lock_axis */
+/* GP_Sculpt_Settings.brushtype */
+typedef enum eGP_Sculpt_Types {
+ GP_SCULPT_TYPE_SMOOTH = 0,
+ GP_SCULPT_TYPE_THICKNESS = 1,
+ GP_SCULPT_TYPE_STRENGTH = 2,
+ GP_SCULPT_TYPE_GRAB = 3,
+ GP_SCULPT_TYPE_PUSH = 4,
+ GP_SCULPT_TYPE_TWIST = 5,
+ GP_SCULPT_TYPE_PINCH = 6,
+ GP_SCULPT_TYPE_RANDOMIZE = 7,
+ GP_SCULPT_TYPE_CLONE = 8,
+ GP_SCULPT_TYPE_SUBDIVIDE = 9,
+ GP_SCULPT_TYPE_SIMPLIFY = 10,
+ /* add any sculpt brush above this value */
+ GP_SCULPT_TYPE_WEIGHT = 11,
+ /* add any weight paint brush below this value. Do no mix brushes */
+
+ /* !!! Update GP_Sculpt_Data brush[###]; below !!! */
+ GP_SCULPT_TYPE_MAX,
+} eGP_Sculpt_Types;
+
+/* GP_Sculpt_Settings.lock_axis */
typedef enum eGP_Lockaxis_Types {
- GP_LOCKAXIS_NONE = 0,
+ GP_LOCKAXIS_VIEW = 0,
GP_LOCKAXIS_X = 1,
GP_LOCKAXIS_Y = 2,
GP_LOCKAXIS_Z = 3
} eGP_Lockaxis_Types;
/* Settings for a GPencil Stroke Sculpting Brush */
-typedef struct GP_EditBrush_Data {
+typedef struct GP_Sculpt_Data {
short size; /* radius of brush */
- short flag; /* eGP_EditBrush_Flag */
+ short flag; /* eGP_Sculpt_Flag */
float strength; /* strength of effect */
-} GP_EditBrush_Data;
-
-/* GP_EditBrush_Data.flag */
-typedef enum eGP_EditBrush_Flag {
+ float curcolor_add[3]; /* cursor color for add */
+ float curcolor_sub[3]; /* cursor color for sub */
+ float target_weight; /* target weight */
+ char pad_[4];
+} GP_Sculpt_Data;
+
+/* GP_Sculpt_Data.flag */
+typedef enum eGP_Sculpt_Flag {
/* invert the effect of the brush */
- GP_EDITBRUSH_FLAG_INVERT = (1 << 0),
+ GP_SCULPT_FLAG_INVERT = (1 << 0),
/* adjust strength using pen pressure */
- GP_EDITBRUSH_FLAG_USE_PRESSURE = (1 << 1),
+ GP_SCULPT_FLAG_USE_PRESSURE = (1 << 1),
/* strength of brush falls off with distance from cursor */
- GP_EDITBRUSH_FLAG_USE_FALLOFF = (1 << 2),
+ GP_SCULPT_FLAG_USE_FALLOFF = (1 << 2),
/* smooth brush affects pressure values as well */
- GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE = (1 << 3)
-} eGP_EditBrush_Flag;
-
-
+ GP_SCULPT_FLAG_SMOOTH_PRESSURE = (1 << 3),
+ /* enable screen cursor */
+ GP_SCULPT_FLAG_ENABLE_CURSOR = (1 << 4),
+ /* temporary invert action */
+ GP_SCULPT_FLAG_TMP_INVERT = (1 << 5),
+ /* adjust radius using pen pressure */
+ GP_SCULPT_FLAG_PRESSURE_RADIUS = (1 << 6),
+} eGP_Sculpt_Flag;
/* GPencil Stroke Sculpting Settings */
-typedef struct GP_BrushEdit_Settings {
- GP_EditBrush_Data brush[11]; /* TOT_GP_EDITBRUSH_TYPES */
+typedef struct GP_Sculpt_Settings {
+ GP_Sculpt_Data brush[12]; /* GP_SCULPT_TYPE_MAX */
void *paintcursor; /* runtime */
- int brushtype; /* eGP_EditBrush_Types */
- int flag; /* eGP_BrushEdit_SettingsFlag */
+ int brushtype; /* eGP_Sculpt_Types (sculpt) */
+ int flag; /* eGP_Sculpt_SettingsFlag */
int lock_axis; /* eGP_Lockaxis_Types lock drawing to one axis */
- float alpha; /* alpha factor for selection color */
-} GP_BrushEdit_Settings;
+ char pad1[4];
+
+ /* weight paint is a submode of sculpt but use its own index. All weight paint
+ * brushes must be defined at the end of the brush array.
+ */
+ int weighttype; /* eGP_Sculpt_Types (weight paint) */
+ char pad[4];
+ struct CurveMapping *cur_falloff; /* multiframe edit falloff effect by frame */
+} GP_Sculpt_Settings;
-/* GP_BrushEdit_Settings.flag */
-typedef enum eGP_BrushEdit_SettingsFlag {
+/* GP_Sculpt_Settings.flag */
+typedef enum eGP_Sculpt_SettingsFlag {
/* only affect selected points */
- GP_BRUSHEDIT_FLAG_SELECT_MASK = (1 << 0),
+ GP_SCULPT_SETT_FLAG_SELECT_MASK = (1 << 0),
/* apply brush to position */
- GP_BRUSHEDIT_FLAG_APPLY_POSITION = (1 << 1),
+ GP_SCULPT_SETT_FLAG_APPLY_POSITION = (1 << 1),
/* apply brush to strength */
- GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
+ GP_SCULPT_SETT_FLAG_APPLY_STRENGTH = (1 << 2),
/* apply brush to thickness */
- GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3),
-} eGP_BrushEdit_SettingsFlag;
-
+ GP_SCULPT_SETT_FLAG_APPLY_THICKNESS = (1 << 3),
+ /* apply brush to thickness */
+ GP_SCULPT_SETT_FLAG_WEIGHT_MODE = (1 << 4),
+ /* enable falloff for multiframe editing */
+ GP_SCULPT_SETT_FLAG_FRAME_FALLOFF = (1 << 5),
+ /* apply brush to uv data */
+ GP_SCULPT_SETT_FLAG_APPLY_UV = (1 << 6),
+} eGP_Sculpt_SettingsFlag;
/* Settings for GP Interpolation Operators */
typedef struct GP_Interpolate_Settings {
@@ -1276,17 +1097,6 @@ typedef enum eGP_Interpolate_Type {
GP_IPO_SINE = 12,
} eGP_Interpolate_Type;
-
-/* *************************************************************** */
-/* Transform Orientations */
-
-typedef struct TransformOrientation {
- struct TransformOrientation *next, *prev;
- char name[64]; /* MAX_NAME */
- float mat[3][3];
- int pad;
-} TransformOrientation;
-
/* *************************************************************** */
/* Unified Paint Settings
*/
@@ -1460,14 +1270,15 @@ typedef struct ToolSettings {
VPaint *wpaint; /* weight paint */
Sculpt *sculpt;
UvSculpt *uvsculpt; /* uv smooth */
+ GpPaint *gp_paint; /* gpencil paint */
/* Vertex group weight - used only for editmode, not weight
* paint */
float vgroup_weight;
float doublimit; /* remove doubles limit */
- float normalsize; /* size of normals */
- short automerge;
+ char automerge;
+ char object_flag;
/* Selection Mode for Mesh */
short selectmode;
@@ -1485,23 +1296,25 @@ typedef struct ToolSettings {
/* Grease Pencil */
char gpencil_flags; /* flags/options for how the tool works */
- char gpencil_src; /* for main 3D view Grease Pencil, where data comes from */
char gpencil_v3d_align; /* stroke placement settings: 3D View */
char gpencil_v2d_align; /* : General 2D Editor */
char gpencil_seq_align; /* : Sequencer Preview */
char gpencil_ima_align; /* : Image Editor */
+ /* Annotations */
+ char annotate_v3d_align; /* stroke placement settings - 3D View */
+
+ short annotate_thickness; /* default stroke thickness for annotation strokes */
+ short gpencil_selectmode; /* stroke selection mode */
+
/* Grease Pencil Sculpt */
- struct GP_BrushEdit_Settings gp_sculpt;
+ struct GP_Sculpt_Settings gp_sculpt;
/* Grease Pencil Interpolation Tool(s) */
struct GP_Interpolate_Settings gp_interpolate;
- /* Grease Pencil Drawing Brushes (bGPDbrush) */
- ListBase gp_brushes;
-
- /* Image Paint (8 byttse aligned please!) */
+ /* Image Paint (8 bytes aligned please!) */
struct ImagePaintSettings imapaint;
/* Particle Editing */
@@ -1520,42 +1333,20 @@ typedef struct ToolSettings {
/* Multires */
char multires_subdiv_type;
- /* Skeleton generation */
- short skgen_resolution;
- float skgen_threshold_internal;
- float skgen_threshold_external;
- float skgen_length_ratio;
- float skgen_length_limit;
- float skgen_angle_limit;
- float skgen_correlation_limit;
- float skgen_symmetry_limit;
- float skgen_retarget_angle_weight;
- float skgen_retarget_length_weight;
- float skgen_retarget_distance_weight;
- short skgen_options;
- char skgen_postpro;
- char skgen_postpro_passes;
- char skgen_subdivisions[3];
- char skgen_multi_level;
-
- /* Skeleton Sketching */
- struct Object *skgen_template;
- char bone_sketching;
- char bone_sketching_convert;
- char skgen_subdivision_number;
- char skgen_retarget_options;
- char skgen_retarget_roll;
- char skgen_side_string[8];
- char skgen_num_string[8];
-
/* Alt+RMB option */
char edge_mode;
char edge_mode_live_unwrap;
+ /* SCE_MPR_LOC/SCAL */
+ char gizmo_flag;
+
/* Transform */
+ char transform_pivot_point;
+ char transform_flag;
char snap_mode, snap_node_mode;
char snap_uv_mode;
- short snap_flag, snap_target;
+ char snap_flag;
+ char snap_target;
short proportional, prop_mode;
char proportional_objects; /* proportional edit, object mode */
char proportional_mask; /* proportional edit, mask editing */
@@ -1570,10 +1361,11 @@ typedef struct ToolSettings {
char vgroupsubset; /* subset selection filter in wpaint */
/* UV painting */
- int use_uv_sculpt;
- int uv_sculpt_settings;
- int uv_sculpt_tool;
- int uv_relax_method;
+ char _pad2[2];
+ char use_uv_sculpt;
+ char uv_sculpt_settings;
+ char uv_sculpt_tool;
+ char uv_relax_method;
/* XXX: these sculpt_paint_* fields are deprecated, use the
* unified_paint_settings field instead! */
short sculpt_paint_settings DNA_DEPRECATED; short pad5;
@@ -1587,6 +1379,10 @@ typedef struct ToolSettings {
struct CurvePaintSettings curve_paint_settings;
struct MeshStatVis statvis;
+
+ /* Normal Editing */
+ float normal_vector[3];
+ int face_strength;
} ToolSettings;
/* *************************************************************** */
@@ -1610,6 +1406,12 @@ typedef struct UnitSettings {
char system; /* imperial, metric etc */
char system_rotation; /* not implemented as a proper unit system yet */
short flag;
+
+ char length_unit;
+ char mass_unit;
+ char time_unit;
+
+ char pad[5];
} UnitSettings;
/* ------------------------------------------- */
@@ -1635,6 +1437,82 @@ typedef struct DisplaySafeAreas {
float action_center[2];
} DisplaySafeAreas;
+/* ------------------------------------------- */
+/* Scene Display - used for store scene specific display settings for the 3d view */
+typedef struct SceneDisplay {
+ float light_direction[3]; /* light direction for shadows/highlight */
+ float shadow_shift;
+
+ /* Settings for Cavity Shader */
+ float matcap_ssao_distance;
+ float matcap_ssao_attenuation;
+ int matcap_ssao_samples;
+ int pad;
+
+ /* OpenGL render engine settings. */
+ View3DShading shading;
+} SceneDisplay;
+
+typedef struct SceneEEVEE {
+ int flag;
+ int gi_diffuse_bounces;
+ int gi_cubemap_resolution;
+ int gi_visibility_resolution;
+ float gi_irradiance_smoothing;
+ float gi_glossy_clamp;
+ float gi_filter_quality;
+ float pad;
+
+ float gi_cubemap_draw_size;
+ float gi_irradiance_draw_size;
+
+ int taa_samples;
+ int taa_render_samples;
+ int sss_samples;
+ float sss_jitter_threshold;
+
+ float ssr_quality;
+ float ssr_max_roughness;
+ float ssr_thickness;
+ float ssr_border_fade;
+ float ssr_firefly_fac;
+
+ float volumetric_start;
+ float volumetric_end;
+ int volumetric_tile_size;
+ int volumetric_samples;
+ float volumetric_sample_distribution;
+ float volumetric_light_clamp;
+ int volumetric_shadow_samples;
+
+ float gtao_distance;
+ float gtao_factor;
+ float gtao_quality;
+
+ float bokeh_max_size;
+ float bokeh_threshold;
+
+ float bloom_color[3];
+ float bloom_threshold;
+ float bloom_knee;
+ float bloom_intensity;
+ float bloom_radius;
+ float bloom_clamp;
+
+ int motion_blur_samples;
+ float motion_blur_shutter;
+
+ int shadow_method;
+ int shadow_cube_size;
+ int shadow_cascade_size;
+
+ struct LightCache *light_cache;
+ char light_cache_info[64];
+
+ float overscan;
+ float light_threshold;
+} SceneEEVEE;
+
/* *************************************************************** */
/* Scene ID-Block */
@@ -1647,16 +1525,15 @@ typedef struct Scene {
struct Scene *set;
- ListBase base;
- struct Base *basact; /* active base */
- struct Object *obedit; /* name replaces old G.obedit */
+ ListBase base DNA_DEPRECATED;
+ struct Base *basact DNA_DEPRECATED; /* active base */
+ void *_pad1;
- float cursor[3]; /* 3d cursor location */
- char _pad[4];
+ View3DCursor cursor; /* 3d cursor location */
- unsigned int lay; /* bitflags for layer visibility */
- int layact; /* active layer */
- unsigned int lay_updated; /* runtime flag, has layer ever been updated since load? */
+ unsigned int lay DNA_DEPRECATED; /* bitflags for layer visibility */
+ int layact DNA_DEPRECATED; /* active layer */
+ unsigned int pad1;
short flag; /* various settings */
@@ -1668,7 +1545,7 @@ typedef struct Scene {
struct Editing *ed; /* sequence editor data is allocated here */
struct ToolSettings *toolsettings; /* default allocated now */
- struct SceneStats *stats; /* default allocated now */
+ void *pad2;
struct DisplaySafeAreas safe_areas;
/* migrate or replace? depends on some internal things... */
@@ -1679,6 +1556,9 @@ typedef struct Scene {
ListBase markers;
ListBase transform_spaces;
+ int orientation_index_custom;
+ int orientation_type;
+
void *sound_scene;
void *playback_handle;
void *sound_scrub_handle;
@@ -1687,24 +1567,17 @@ typedef struct Scene {
void *fps_info; /* (runtime) info/cache used for presenting playback framerate info to the user */
/* none of the dependency graph vars is mean to be saved */
- struct Depsgraph *depsgraph;
- void *pad1;
- struct DagForest *theDag;
- short dagflags;
- short pad3;
+ struct GHash *depsgraph_hash;
+ int pad7;
/* User-Defined KeyingSets */
int active_keyingset; /* index of the active KeyingSet. first KeyingSet has index 1, 'none' active is 0, 'add new' is -1 */
ListBase keyingsets; /* KeyingSets for this scene */
- /* Game Settings */
- struct GameFraming framing DNA_DEPRECATED; // XXX deprecated since 2.5
- struct GameData gm;
-
/* Units */
struct UnitSettings unit;
- /* Grease Pencil */
+ /* Grease Pencil - Annotations */
struct bGPdata *gpd;
/* Movie Tracking */
@@ -1716,6 +1589,7 @@ typedef struct Scene {
uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */
uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */
+
/* Color Management */
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
@@ -1725,6 +1599,16 @@ typedef struct Scene {
struct RigidBodyWorld *rigidbody_world;
struct PreviewImage *preview;
+
+ ListBase view_layers;
+ /* Not an actual datablock, but memory owned by scene. */
+ Collection *master_collection;
+ struct SceneCollection *collection DNA_DEPRECATED;
+
+ IDProperty *layer_properties; /* settings to be override by workspaces */
+
+ struct SceneDisplay display;
+ struct SceneEEVEE eevee;
} Scene;
/* **************** RENDERDATA ********************* */
@@ -1738,25 +1622,25 @@ typedef struct Scene {
/* RenderData.mode */
#define R_OSA 0x0001
-#define R_SHADOW 0x0002
-#define R_GAMMA 0x0004
-#define R_ORTHO 0x0008
-#define R_ENVMAP 0x0010
-#define R_EDGE 0x0020
-#define R_FIELDS 0x0040
-#define R_FIELDSTILL 0x0080
-/*#define R_RADIO 0x0100 */ /* deprecated */
+/* #define R_SHADOW 0x0002 */
+/* #define R_GAMMA 0x0004 */
+/* #define R_ORTHO 0x0008 */
+/* #define R_ENVMAP 0x0010 */
+/* #define R_EDGE 0x0020 */
+/* #define R_FIELDS 0x0040 */
+/*#define R_FIELDSTILL 0x0080 */
+/*#define R_RADIO 0x0100 */ /* deprecated */
#define R_BORDER 0x0200
-#define R_PANORAMA 0x0400 /* deprecated as scene option, still used in renderer */
+#define R_PANORAMA 0x0400 /* deprecated */
#define R_CROP 0x0800
/* Disable camera switching: runtime (DURIAN_CAMERA_SWITCH) */
#define R_NO_CAMERA_SWITCH 0x1000
-#define R_ODDFIELD 0x2000
+/* #define R_ODDFIELD 0x2000 */
#define R_MBLUR 0x4000
/* unified was here */
-#define R_RAYTRACE 0x10000
+/* #define R_RAYTRACE 0x10000 */
/* R_GAUSS is obsolete, but used to retrieve setting from old files */
-#define R_GAUSS 0x20000
+/* #define R_GAUSS 0x20000 */
/* fbuf obsolete... */
/*#define R_FBUF 0x40000*/
/* threads obsolete... is there for old files, now use for autodetect threads */
@@ -1764,14 +1648,14 @@ typedef struct Scene {
/* Use the same flag for autothreads */
#define R_FIXED_THREADS 0x80000
-#define R_SPEED 0x100000
-#define R_SSS 0x200000
+/* #define R_SPEED 0x100000 */
+/* #define R_SSS 0x200000 */
#define R_NO_OVERWRITE 0x400000 /* skip existing files */
#define R_TOUCH 0x800000 /* touch files before rendering */
#define R_SIMPLIFY 0x1000000
#define R_EDGE_FRS 0x2000000 /* R_EDGE reserved for Freestyle */
#define R_PERSISTENT_DATA 0x4000000 /* keep data around for re-render */
-#define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */
+/* #define R_USE_WS_SHADING 0x8000000 */ /* use world space interpretation of lighting data */
/* RenderData.seq_flag */
enum {
@@ -1788,7 +1672,7 @@ enum {
#define R_OUTPUT_NONE 3
/*#define R_OUTPUT_FORKED 4*/
-/* RenderData.filtertype */
+/* RenderData.filtertype (used for nodes) */
#define R_FILTER_BOX 0
#define R_FILTER_TENT 1
#define R_FILTER_QUAD 2
@@ -1796,19 +1680,7 @@ enum {
#define R_FILTER_CATROM 4
#define R_FILTER_GAUSS 5
#define R_FILTER_MITCH 6
-#define R_FILTER_FAST_GAUSS 7 /* note, this is only used for nodes at the moment */
-
-/* RenderData.raytrace_structure */
-#define R_RAYSTRUCTURE_AUTO 0
-#define R_RAYSTRUCTURE_OCTREE 1
-#define R_RAYSTRUCTURE_BLIBVH 2 /* removed */
-#define R_RAYSTRUCTURE_VBVH 3
-#define R_RAYSTRUCTURE_SIMD_SVBVH 4 /* needs SIMD */
-#define R_RAYSTRUCTURE_SIMD_QBVH 5 /* needs SIMD */
-
-/* RenderData.raytrace_options */
-#define R_RAYTRACE_USE_LOCAL_COORDS 0x0001
-#define R_RAYTRACE_USE_INSTANCES 0x0002
+#define R_FILTER_FAST_GAUSS 7
/* RenderData.scemode (int now) */
#define R_DOSEQ 0x0001
@@ -1820,18 +1692,18 @@ enum {
#define R_MATNODE_PREVIEW 0x0020
#define R_DOCOMP 0x0040
#define R_COMP_CROP 0x0080
-#define R_FREE_IMAGE 0x0100
+/* #define R_FREE_IMAGE 0x0100 */
#define R_SINGLE_LAYER 0x0200
#define R_EXR_TILE_FILE 0x0400
/* #define R_COMP_FREE 0x0800 */
#define R_NO_IMAGE_LOAD 0x1000
-#define R_NO_TEX 0x2000
+/* #define R_NO_TEX 0x2000 */
#define R_NO_FRAME_UPDATE 0x4000
#define R_FULL_SAMPLE 0x8000
/* #define R_DEPRECATED 0x10000 */
/* #define R_RECURS_PROTECTION 0x20000 */
#define R_TEXNODE_PREVIEW 0x40000
-#define R_VIEWPORT_PREVIEW 0x80000
+/* #define R_VIEWPORT_PREVIEW 0x80000 */
#define R_EXR_CACHE_FILE 0x100000
#define R_MULTIVIEW 0x200000
@@ -1888,12 +1760,12 @@ enum {
/* bake_mode: same as RE_BAKE_xxx defines */
/* RenderData.bake_flag */
#define R_BAKE_CLEAR 1
-#define R_BAKE_OSA 2
+/* #define R_BAKE_OSA 2 */ /* deprecated */
#define R_BAKE_TO_ACTIVE 4
-#define R_BAKE_NORMALIZE 8
+/* #define R_BAKE_NORMALIZE 8 */ /* deprecated */
#define R_BAKE_MULTIRES 16
#define R_BAKE_LORES_MESH 32
-#define R_BAKE_VCOL 64
+/* #define R_BAKE_VCOL 64 */ /* deprecated */
#define R_BAKE_USERSCALE 128
#define R_BAKE_CAGE 256
#define R_BAKE_SPLIT_MAT 512
@@ -1905,9 +1777,6 @@ enum {
#define R_BAKE_SPACE_OBJECT 2
#define R_BAKE_SPACE_TANGENT 3
-/* RenderData.simplify_flag */
-#define R_SIMPLE_NO_TRIANGULATE 1
-
/* RenderData.line_thickness_mode */
#define R_LINE_THICKNESS_ABSOLUTE 1
#define R_LINE_THICKNESS_RELATIVE 2
@@ -1915,8 +1784,8 @@ enum {
/* sequencer seq_prev_type seq_rend_type */
/* RenderData.engine (scene.c) */
-extern const char *RE_engine_id_BLENDER_RENDER;
-extern const char *RE_engine_id_BLENDER_GAME;
+extern const char *RE_engine_id_BLENDER_EEVEE;
+extern const char *RE_engine_id_BLENDER_WORKBENCH;
extern const char *RE_engine_id_CYCLES;
/* **************** SCENE ********************* */
@@ -1935,39 +1804,56 @@ extern const char *RE_engine_id_CYCLES;
#define MINAFRAME -1048574
#define MINAFRAMEF -1048574.0f
-/* depricate this! */
+/* deprecate this! */
#define TESTBASE(v3d, base) ( \
- ((base)->flag & SELECT) && \
- ((base)->lay & v3d->lay) && \
- (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0))
+ (((v3d)->localvd == NULL) || ((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0) && \
+ (((base)->flag & BASE_SELECTED) != 0) && \
+ (((base)->flag & BASE_VISIBLE) != 0))
#define TESTBASELIB(v3d, base) ( \
- ((base)->flag & SELECT) && \
- ((base)->lay & v3d->lay) && \
+ (((v3d)->localvd == NULL) || ((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0) && \
+ (((base)->flag & BASE_SELECTED) != 0) && \
((base)->object->id.lib == NULL) && \
- (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0))
-#define TESTBASELIB_BGMODE(v3d, scene, base) ( \
- ((base)->flag & SELECT) && \
- ((base)->lay & (v3d ? v3d->lay : scene->lay)) && \
+ (((base)->flag & BASE_VISIBLE) != 0))
+#define TESTBASELIB_BGMODE(v3d, base) ( \
+ ((v3d == NULL) || ((v3d)->localvd == NULL) || ((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ ((v3d == NULL) || (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \
+ (((base)->flag & BASE_SELECTED) != 0) && \
((base)->object->id.lib == NULL) && \
- (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0))
-#define BASE_EDITABLE_BGMODE(v3d, scene, base) ( \
- ((base)->lay & (v3d ? v3d->lay : scene->lay)) && \
+ (((base)->flag & BASE_VISIBLE) != 0))
+#define BASE_EDITABLE_BGMODE(v3d, base) ( \
+ ((v3d == NULL) || ((v3d)->localvd == NULL) || ((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ ((v3d == NULL) || (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \
((base)->object->id.lib == NULL) && \
- (((base)->object->restrictflag & OB_RESTRICT_VIEW) == 0))
+ (((base)->flag & BASE_VISIBLE) != 0))
#define BASE_SELECTABLE(v3d, base) ( \
- (base->lay & v3d->lay) && \
- (base->object->restrictflag & (OB_RESTRICT_SELECT | OB_RESTRICT_VIEW)) == 0)
+ (((v3d)->localvd == NULL) || ((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0) && \
+ (((1 << (base)->object->type) & (v3d)->object_type_exclude_select) == 0) && \
+ (((base)->flag & BASE_SELECTABLE) != 0))
#define BASE_VISIBLE(v3d, base) ( \
- (base->lay & v3d->lay) && \
- (base->object->restrictflag & OB_RESTRICT_VIEW) == 0)
-#define BASE_VISIBLE_BGMODE(v3d, scene, base) ( \
- (base->lay & (v3d ? v3d->lay : scene->lay)) && \
- (base->object->restrictflag & OB_RESTRICT_VIEW) == 0)
-
-#define FIRSTBASE scene->base.first
-#define LASTBASE scene->base.last
-#define BASACT (scene->basact)
-#define OBACT (BASACT ? BASACT->object: NULL)
+ (((v3d)->localvd == NULL) || ((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0) && \
+ (((base)->flag & BASE_VISIBLE) != 0))
+#define BASE_VISIBLE_BGMODE(v3d, base) ( \
+ ((v3d == NULL) || ((v3d)->localvd == NULL) || ((v3d)->local_view_uuid & (base)->local_view_bits)) && \
+ ((v3d == NULL) || (((1 << (base)->object->type) & (v3d)->object_type_exclude_viewport) == 0)) && \
+ (((base)->flag & BASE_VISIBLE) != 0))
+
+#define FIRSTBASE(_view_layer) ((_view_layer)->object_bases.first)
+#define LASTBASE(_view_layer) ((_view_layer)->object_bases.last)
+#define BASACT(_view_layer) ((_view_layer)->basact)
+#define OBACT(_view_layer) (BASACT(_view_layer) ? BASACT(_view_layer)->object: NULL)
+
+#define OBEDIT_FROM_WORKSPACE(workspace, _view_layer) \
+ (((workspace)->object_mode & OD_MODE_EDIT) ? OBACT(_view_layer) : NULL)
+#define OBEDIT_FROM_OBACT(ob) \
+ ((ob) ? (((ob)->mode & OB_MODE_EDIT) ? ob : NULL) : NULL)
+#define OBPOSE_FROM_OBACT(ob) \
+ ((ob) ? (((ob)->mode & OB_MODE_POSE) ? ob : NULL) : NULL)
+#define OBEDIT_FROM_VIEW_LAYER(view_layer) \
+ OBEDIT_FROM_OBACT(OBACT(view_layer))
#define V3D_CAMERA_LOCAL(v3d) ((!(v3d)->scenelock && (v3d)->camera) ? (v3d)->camera : NULL)
#define V3D_CAMERA_SCENE(scene, v3d) ((!(v3d)->scenelock && (v3d)->camera) ? (v3d)->camera : (scene)->camera)
@@ -1985,6 +1871,16 @@ extern const char *RE_engine_id_CYCLES;
/* Base.flag is in DNA_object_types.h */
+/* ToolSettings.transform_flag */
+enum {
+ SCE_XFORM_AXIS_ALIGN = (1 << 0),
+};
+
+/* ToolSettings.object_flag */
+enum {
+ SCE_OBJECT_MODE_LOCK = (1 << 0),
+};
+
/* ToolSettings.snap_flag */
#define SCE_SNAP 1
#define SCE_SNAP_ROTATE 2
@@ -1998,16 +1894,18 @@ extern const char *RE_engine_id_CYCLES;
#define SCE_SNAP_TARGET_CENTER 1
#define SCE_SNAP_TARGET_MEDIAN 2
#define SCE_SNAP_TARGET_ACTIVE 3
+
/* ToolSettings.snap_mode */
-#define SCE_SNAP_MODE_INCREMENT 0
-#define SCE_SNAP_MODE_VERTEX 1
-#define SCE_SNAP_MODE_EDGE 2
-#define SCE_SNAP_MODE_FACE 3
-#define SCE_SNAP_MODE_VOLUME 4
-#define SCE_SNAP_MODE_NODE_X 5
-#define SCE_SNAP_MODE_NODE_Y 6
-#define SCE_SNAP_MODE_NODE_XY 7
-#define SCE_SNAP_MODE_GRID 8
+#define SCE_SNAP_MODE_VERTEX (1 << 0)
+#define SCE_SNAP_MODE_EDGE (1 << 1)
+#define SCE_SNAP_MODE_FACE (1 << 2)
+#define SCE_SNAP_MODE_VOLUME (1 << 3)
+#define SCE_SNAP_MODE_INCREMENT (1 << 4)
+
+/* ToolSettings.snap_node_mode */
+#define SCE_SNAP_MODE_GRID (1 << 5)
+#define SCE_SNAP_MODE_NODE_X (1 << 6)
+#define SCE_SNAP_MODE_NODE_Y (1 << 7)
/* ToolSettings.selectmode */
#define SCE_SELECT_VERTEX 1 /* for mesh */
@@ -2050,6 +1948,13 @@ enum {
OB_DRAW_GROUPUSER_ALL = 2
};
+/* toolsettings->face_strength */
+enum {
+ FACE_STRENGTH_WEAK = -16384,
+ FACE_STRENGTH_MEDIUM = 0,
+ FACE_STRENGTH_STRONG = 16384,
+};
+
/* object_vgroup.c */
/* ToolSettings.vgroupsubset */
typedef enum eVGroupSelect {
@@ -2151,6 +2056,7 @@ typedef enum eSculptFlags {
/* If set, dynamic-topology detail size will be constant in object space */
SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13),
SCULPT_DYNTOPO_DETAIL_BRUSH = (1 << 14),
+ SCULPT_DYNTOPO_DETAIL_MANUAL = (1 << 16),
/* Don't display mask in viewport, but still use it for strokes. */
SCULPT_HIDE_MASK = (1 << 15),
@@ -2206,21 +2112,42 @@ typedef enum eImagePaintMode {
#define EDGE_MODE_TAG_BEVEL 4
#define EDGE_MODE_TAG_FREESTYLE 5
+/* ToolSettings.gizmo_flag */
+enum {
+ SCE_GIZMO_SHOW_TRANSLATE = (1 << 0),
+ SCE_GIZMO_SHOW_ROTATE = (1 << 1),
+ SCE_GIZMO_SHOW_SCALE = (1 << 2),
+};
+
/* ToolSettings.gpencil_flags */
typedef enum eGPencil_Flags {
- /* "Continuous Drawing" - The drawing operator enters a mode where multiple strokes can be drawn */
- GP_TOOL_FLAG_PAINTSESSIONS_ON = (1 << 0),
/* When creating new frames, the last frame gets used as the basis for the new one */
GP_TOOL_FLAG_RETAIN_LAST = (1 << 1),
/* Add the strokes below all strokes in the layer */
- GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2)
+ GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2),
+ /* Show compact list of colors */
+ GP_TOOL_FLAG_THUMBNAIL_LIST = (1 << 3),
+ /* Generate wheight data for new strokes */
+ GP_TOOL_FLAG_CREATE_WEIGHTS = (1 << 4),
} eGPencil_Flags;
-/* ToolSettings.gpencil_src */
-typedef enum eGPencil_Source_3D {
- GP_TOOL_SOURCE_SCENE = 0,
- GP_TOOL_SOURCE_OBJECT = 1
-} eGPencil_Source_3d;
+/* scene->r.simplify_gpencil */
+typedef enum eGPencil_SimplifyFlags {
+ /* Simplify */
+ SIMPLIFY_GPENCIL_ENABLE = (1 << 0),
+ /* Simplify on play */
+ SIMPLIFY_GPENCIL_ON_PLAY = (1 << 1),
+ /* Simplify fill on viewport */
+ SIMPLIFY_GPENCIL_FILL = (1 << 2),
+ /* Simplify modifier on viewport */
+ SIMPLIFY_GPENCIL_MODIFIER = (1 << 3),
+ /* Remove fill external line */
+ SIMPLIFY_GPENCIL_REMOVE_FILL_LINE = (1 << 4),
+ /* Simplify Shader FX */
+ SIMPLIFY_GPENCIL_FX = (1 << 5),
+ /* Simplify layer blending */
+ SIMPLIFY_GPENCIL_BLEND = (1 << 6),
+} eGPencil_SimplifyFlags;
/* ToolSettings.gpencil_*_align - Stroke Placement mode flags */
typedef enum eGPencil_Placement_Flags {
@@ -2236,8 +2163,16 @@ typedef enum eGPencil_Placement_Flags {
/* "Use Endpoints" */
GP_PROJECT_DEPTH_STROKE_ENDPOINTS = (1 << 4),
+ GP_PROJECT_CURSOR = (1 << 5),
+ GP_PROJECT_DEPTH_STROKE_FIRST = (1 << 6),
} eGPencil_Placement_Flags;
+/* ToolSettings.gpencil_selectmode */
+typedef enum eGPencil_Selectmode_types {
+ GP_SELECTMODE_POINT = 0,
+ GP_SELECTMODE_STROKE = 1
+} eGPencil_Selectmode_types;
+
/* ToolSettings.particle flag */
#define PE_KEEP_LENGTHS 1
#define PE_LOCK_FIRST 2
@@ -2266,57 +2201,12 @@ typedef enum eGPencil_Placement_Flags {
#define PE_TYPE_SOFTBODY 1
#define PE_TYPE_CLOTH 2
-/* ToolSettings.skgen_options */
-#define SKGEN_FILTER_INTERNAL (1 << 0)
-#define SKGEN_FILTER_EXTERNAL (1 << 1)
-#define SKGEN_SYMMETRY (1 << 2)
-#define SKGEN_CUT_LENGTH (1 << 3)
-#define SKGEN_CUT_ANGLE (1 << 4)
-#define SKGEN_CUT_CORRELATION (1 << 5)
-#define SKGEN_HARMONIC (1 << 6)
-#define SKGEN_STICK_TO_EMBEDDING (1 << 7)
-#define SKGEN_ADAPTIVE_DISTANCE (1 << 8)
-#define SKGEN_FILTER_SMART (1 << 9)
-#define SKGEN_DISP_LENGTH (1 << 10)
-#define SKGEN_DISP_WEIGHT (1 << 11)
-#define SKGEN_DISP_ORIG (1 << 12)
-#define SKGEN_DISP_EMBED (1 << 13)
-#define SKGEN_DISP_INDEX (1 << 14)
-
-#define SKGEN_SUB_LENGTH 0
-#define SKGEN_SUB_ANGLE 1
-#define SKGEN_SUB_CORRELATION 2
-#define SKGEN_SUB_TOTAL 3
-
-/* ToolSettings.skgen_postpro */
-#define SKGEN_SMOOTH 0
-#define SKGEN_AVERAGE 1
-#define SKGEN_SHARPEN 2
-
-/* ToolSettings.bone_sketching */
-#define BONE_SKETCHING 1
-#define BONE_SKETCHING_QUICK 2
-#define BONE_SKETCHING_ADJUST 4
-
-/* ToolSettings.bone_sketching_convert */
-#define SK_CONVERT_CUT_FIXED 0
-#define SK_CONVERT_CUT_LENGTH 1
-#define SK_CONVERT_CUT_ADAPTATIVE 2
-#define SK_CONVERT_RETARGET 3
-
-/* ToolSettings.skgen_retarget_options */
-#define SK_RETARGET_AUTONAME 1
-
-/* ToolSettings.skgen_retarget_roll */
-#define SK_RETARGET_ROLL_NONE 0
-#define SK_RETARGET_ROLL_VIEW 1
-#define SK_RETARGET_ROLL_JOINT 2
-
/* PhysicsSettings.flag */
#define PHYS_GLOBAL_GRAVITY 1
/* UnitSettings */
+#define USER_UNIT_ADAPTIVE 0xFF
/* UnitSettings.system */
#define USER_UNIT_NONE 0
#define USER_UNIT_METRIC 1
@@ -2325,6 +2215,39 @@ typedef enum eGPencil_Placement_Flags {
#define USER_UNIT_OPT_SPLIT 1
#define USER_UNIT_ROT_RADIANS 2
+/* SceneEEVEE->flag */
+enum {
+ SCE_EEVEE_VOLUMETRIC_ENABLED = (1 << 0),
+ SCE_EEVEE_VOLUMETRIC_LIGHTS = (1 << 1),
+ SCE_EEVEE_VOLUMETRIC_SHADOWS = (1 << 2),
+// SCE_EEVEE_VOLUMETRIC_COLORED = (1 << 3), /* Unused */
+ SCE_EEVEE_GTAO_ENABLED = (1 << 4),
+ SCE_EEVEE_GTAO_BENT_NORMALS = (1 << 5),
+ SCE_EEVEE_GTAO_BOUNCE = (1 << 6),
+ SCE_EEVEE_DOF_ENABLED = (1 << 7),
+ SCE_EEVEE_BLOOM_ENABLED = (1 << 8),
+ SCE_EEVEE_MOTION_BLUR_ENABLED = (1 << 9),
+ SCE_EEVEE_SHADOW_HIGH_BITDEPTH = (1 << 10),
+ SCE_EEVEE_TAA_REPROJECTION = (1 << 11),
+ SCE_EEVEE_SSS_ENABLED = (1 << 12),
+ SCE_EEVEE_SSS_SEPARATE_ALBEDO = (1 << 13),
+ SCE_EEVEE_SSR_ENABLED = (1 << 14),
+ SCE_EEVEE_SSR_REFRACTION = (1 << 15),
+ SCE_EEVEE_SSR_HALF_RESOLUTION = (1 << 16),
+ SCE_EEVEE_SHOW_IRRADIANCE = (1 << 17),
+ SCE_EEVEE_SHOW_CUBEMAPS = (1 << 18),
+ SCE_EEVEE_GI_AUTOBAKE = (1 << 19),
+ SCE_EEVEE_SHADOW_SOFT = (1 << 20),
+ SCE_EEVEE_OVERSCAN = (1 << 21),
+};
+
+/* SceneEEVEE->shadow_method */
+enum {
+ SHADOW_ESM = 1,
+ SHADOW_VSM = 2,
+ SHADOW_METHOD_MAX = 3,
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index bdcbf9cb856..a62e7bc5036 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -30,6 +30,7 @@
#ifndef __DNA_SCREEN_TYPES_H__
#define __DNA_SCREEN_TYPES_H__
+#include "DNA_defs.h"
#include "DNA_listBase.h"
#include "DNA_view2d_types.h"
#include "DNA_vec_types.h"
@@ -43,20 +44,29 @@ struct ARegionType;
struct PanelType;
struct Scene;
struct uiLayout;
+struct wmDrawBuffer;
struct wmTimer;
struct wmTooltipState;
+
+/* TODO Doing this is quite ugly :)
+ * Once the top-bar is merged bScreen should be refactored to use ScrAreaMap. */
+#define AREAMAP_FROM_SCREEN(screen) ((ScrAreaMap *)&(screen)->vertbase)
+
typedef struct bScreen {
ID id;
+ /* TODO Should become ScrAreaMap now.
+ * ** NOTE: KEEP ORDER IN SYNC WITH ScrAreaMap! (see AREAMAP_FROM_SCREEN macro above) ** */
ListBase vertbase; /* screens have vertices/edges to define areas */
ListBase edgebase;
ListBase areabase;
+
ListBase regionbase; /* screen level regions (menus), runtime only */
- struct Scene *scene;
- struct Scene *newscene; /* temporary when switching */
+ struct Scene *scene DNA_DEPRECATED;
+ short flag; /* general flags */
short winid; /* winid from WM, starts with 1 */
short redraws_flag; /* user-setting for which editors get redrawn during anim playback (used to be time->redraws) */
@@ -67,18 +77,18 @@ typedef struct bScreen {
char do_draw_gesture; /* notifier for gesture draw. */
char do_draw_paintcursor; /* notifier for paint cursor draw. */
char do_draw_drag; /* notifier for dragging draw. */
- char swap; /* indicator to survive swap-exchange systems */
char skip_handling; /* set to delay screen handling after switching back from maximized area */
char scrubbing; /* set when scrubbing to avoid some costly updates */
- char pad[6];
+ char pad[1];
- short mainwin; /* screensize subwindow, for screenedges and global menus */
- short subwinactive; /* active subwindow */
+ struct ARegion *active_region; /* active region that has mouse focus */
struct wmTimer *animtimer; /* if set, screen has timer handler added in window */
void *context; /* context callback */
struct wmTooltipState *tool_tip; /* runtime */
+
+ PreviewImage *preview;
} bScreen;
typedef struct ScrVert {
@@ -96,6 +106,14 @@ typedef struct ScrEdge {
int pad;
} ScrEdge;
+typedef struct ScrAreaMap {
+ /* ** NOTE: KEEP ORDER IN SYNC WITH LISTBASES IN bScreen! ** */
+
+ ListBase vertbase; /* ScrVert - screens have vertices/edges to define areas */
+ ListBase edgebase; /* ScrEdge */
+ ListBase areabase; /* ScrArea */
+} ScrAreaMap;
+
typedef struct Panel { /* the part from uiBlock that needs saved in file */
struct Panel *next, *prev;
@@ -104,7 +122,9 @@ typedef struct Panel { /* the part from uiBlock that needs saved in file */
char panelname[64], tabname[64]; /* defined as UI_MAX_NAME_STR */
char drawname[64]; /* panelname is identifier for restoring location */
- int ofsx, ofsy, sizex, sizey;
+ int ofsx, ofsy; /* offset within the region */
+ int sizex, sizey; /* panel size including children */
+ int blocksizex, blocksizey; /* panel size excluding children */
short labelofs, pad;
short flag, runtime_flag;
short control;
@@ -112,6 +132,7 @@ typedef struct Panel { /* the part from uiBlock that needs saved in file */
int sortorder; /* panels are aligned according to increasing sortorder */
struct Panel *paneltab; /* this panel is tabbed in *paneltab */
void *activedata; /* runtime for panel manipulation */
+ ListBase children; /* sub panels */
} Panel;
@@ -194,6 +215,13 @@ typedef struct uiList { /* some list UI data need to be saved in file
uiListDyn *dyn_data;
} uiList;
+typedef struct TransformOrientation {
+ struct TransformOrientation *next, *prev;
+ char name[64]; /* MAX_NAME */
+ float mat[3][3];
+ int pad;
+} TransformOrientation;
+
typedef struct uiPreview { /* some preview UI data need to be saved in file */
struct uiPreview *next, *prev;
@@ -202,6 +230,41 @@ typedef struct uiPreview { /* some preview UI data need to be saved in
short pad1[3];
} uiPreview;
+/* These two lines with # tell makesdna this struct can be excluded.
+ * Should be: #ifndef WITH_GLOBAL_AREA_WRITING */
+#
+#
+typedef struct ScrGlobalAreaData {
+ /* Global areas have a non-dynamic size. That means, changing the window
+ * size doesn't affect their size at all. However, they can still be
+ * 'collapsed', by changing this value. Ignores DPI (ED_area_global_size_y
+ * and winx/winy don't) */
+ short cur_fixed_height;
+ /* For global areas, this is the min and max size they can use depending on
+ * if they are 'collapsed' or not. Value is set on area creation and not
+ * touched afterwards. */
+ short size_min, size_max;
+ short align; /* GlobalAreaAlign */
+
+ short flag; /* GlobalAreaFlag */
+ short pad;
+} ScrGlobalAreaData;
+
+enum GlobalAreaFlag {
+ GLOBAL_AREA_IS_HIDDEN = (1 << 0),
+};
+
+typedef enum GlobalAreaAlign {
+ GLOBAL_AREA_ALIGN_TOP,
+ GLOBAL_AREA_ALIGN_BOTTOM,
+} GlobalAreaAlign;
+
+typedef struct ScrArea_Runtime {
+ struct bToolRef *tool;
+ char is_tool_set;
+ char _pad0[7];
+} ScrArea_Runtime;
+
typedef struct ScrArea {
struct ScrArea *next, *prev;
@@ -210,11 +273,17 @@ typedef struct ScrArea {
rcti totrct; /* rect bound by v1 v2 v3 v4 */
- char spacetype, butspacetype; /* SPACE_..., butspacetype is button arg */
+ char spacetype; /* eSpace_Type (SPACE_FOO) */
+ /* Temporarily used while switching area type, otherwise this should be
+ * SPACE_EMPTY. Also, versioning uses it to nicely replace deprecated
+ * editors. It's been there for ages, name doesn't fit any more... */
+ char butspacetype; /* eSpace_Type (SPACE_FOO) */
+ short butspacetype_subtype;
+
short winx, winy; /* size */
- short headertype; /* OLD! 0=no header, 1= down, 2= up */
- short do_refresh; /* private, for spacetype refresh callback */
+ char headertype DNA_DEPRECATED;/* OLD! 0=no header, 1= down, 2= up */
+ char do_refresh; /* private, for spacetype refresh callback */
short flag;
short region_active_win; /* index of last used region of 'RGN_TYPE_WINDOW'
* runtime variable, updated by executing operators */
@@ -222,6 +291,9 @@ typedef struct ScrArea {
struct SpaceType *type; /* callbacks for this space type */
+ /* Non-NULL if this area is global. */
+ ScrGlobalAreaData *global;
+
/* 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.
@@ -234,8 +306,16 @@ typedef struct ScrArea {
ListBase handlers; /* wmEventHandler */
ListBase actionzones; /* AZone */
+
+ ScrArea_Runtime runtime;
} ScrArea;
+
+typedef struct ARegion_Runtime {
+ /* Panel category to use between 'layout' and 'draw'. */
+ const char *category;
+} ARegion_Runtime;
+
typedef struct ARegion {
struct ARegion *next, *prev;
@@ -244,7 +324,7 @@ typedef struct ARegion {
rcti drawrct; /* runtime for partial redraw, same or smaller than winrct */
short winx, winy; /* size */
- short swinid;
+ short visible; /* region is currently visible on screen */
short regiontype; /* window, header, etc. identifier for drawing */
short alignment; /* how it should split */
short flag; /* hide, ... */
@@ -254,10 +334,9 @@ typedef struct ARegion {
short do_draw; /* private, cached notifier events */
short do_draw_overlay; /* private, cached notifier events */
- short swap; /* private, indicator to survive swap-exchange */
short overlap; /* private, set for indicate drawing overlapped */
short flagfullscreen; /* temporary copy of flag settings for clean fullscreen */
- short pad;
+ short pad1, pad2;
struct ARegionType *type; /* callbacks for this region type */
@@ -269,24 +348,27 @@ typedef struct ARegion {
ListBase handlers; /* wmEventHandler */
ListBase panels_category; /* Panel categories runtime */
+ struct wmGizmoMap *gizmo_map; /* gizmo-map of this region */
struct wmTimer *regiontimer; /* blend in/out */
+ struct wmDrawBuffer *draw_buffer;
char *headerstr; /* use this string to draw info */
void *regiondata; /* XXX 2.50, need spacedata equivalent? */
-} ARegion;
-/* swap */
-#define WIN_BACK_OK 1
-#define WIN_FRONT_OK 2
-// #define WIN_EQUAL 3 // UNUSED
+ ARegion_Runtime runtime;
+} ARegion;
/* area->flag */
enum {
HEADER_NO_PULLDOWN = (1 << 0),
// AREA_FLAG_DEPRECATED_1 = (1 << 1),
// AREA_FLAG_DEPRECATED_2 = (1 << 2),
- AREA_TEMP_INFO = (1 << 3),
-// AREA_FLAG_DEPRECATED_4 = (1 << 4),
+#ifdef DNA_DEPRECATED_ALLOW
+ AREA_TEMP_INFO = (1 << 3), /* versioned to make slot reusable */
+#endif
+ /* update size of regions within the area */
+ AREA_FLAG_REGION_SIZE_UPDATE = (1 << 3),
+ AREA_FLAG_ACTIVE_TOOL_UPDATE = (1 << 4),
// AREA_FLAG_DEPRECATED_5 = (1 << 5),
/* used to check if we should switch back to prevspace (of a different type) */
AREA_FLAG_TEMP_TYPE = (1 << 6),
@@ -301,8 +383,11 @@ enum {
#define AREAMINX 32
#define HEADERY 26
-#define HEADERDOWN 1
-#define HEADERTOP 2
+/* screen->flag */
+enum {
+ SCREEN_COLLAPSE_TOPBAR = 1,
+ SCREEN_COLLAPSE_STATUSBAR = 2,
+};
/* screen->state */
enum {
@@ -320,6 +405,7 @@ enum {
/*PNL_TABBED = (1 << 3), */ /*UNUSED*/
PNL_OVERLAP = (1 << 4),
PNL_PIN = (1 << 5),
+ PNL_POPOVER = (1 << 6),
};
/* Panel->snap - for snapping to screen edges */
@@ -334,6 +420,7 @@ enum {
/* paneltype flag */
#define PNL_DEFAULT_CLOSED 1
#define PNL_NO_HEADER 2
+#define PNL_LAYOUT_VERT_BAR 4
/* Fallback panel category (only for old scripts which need updating) */
#define PNL_CATEGORY_FALLBACK "Misc"
@@ -369,6 +456,7 @@ enum {
/* uiList filter orderby type */
enum {
UILST_FLT_SORT_ALPHA = 1 << 0,
+ UILST_FLT_FORCED_REVERSE = 1 << 1, /* Special flag to indicate reverse was set by external parameter */
UILST_FLT_SORT_REVERSE = 1u << 31 /* Special value, bitflag used to reverse order! */
};
@@ -385,10 +473,16 @@ enum {
RGN_TYPE_TOOLS = 5,
RGN_TYPE_TOOL_PROPS = 6,
RGN_TYPE_PREVIEW = 7,
+ RGN_TYPE_HUD = 8,
+ /* Region to navigate the main region from (RGN_TYPE_WINDOW). */
+ RGN_TYPE_NAV_BAR = 9,
};
/* use for function args */
#define RGN_TYPE_ANY -1
+/* Region supports panel tabs (categories). */
+#define RGN_TYPE_HAS_CATEGORY_MASK (1 << RGN_TYPE_UI)
+
/* region alignment */
#define RGN_ALIGN_NONE 0
#define RGN_ALIGN_TOP 1
@@ -406,8 +500,14 @@ enum {
enum {
RGN_FLAG_HIDDEN = (1 << 0),
RGN_FLAG_TOO_SMALL = (1 << 1),
+ /* Force delayed reinit of region size data, so that region size is calculated
+ * just big enough to show all its content (if enough space is available).
+ * Note that only ED_region_header supports this right now. */
+ RGN_FLAG_DYNAMIC_SIZE = (1 << 2),
/* Region data is NULL'd on read, never written. */
RGN_FLAG_TEMP_REGIONDATA = (1 << 3),
+ /* The region must either use its prefsizex/y or be hidden. */
+ RGN_FLAG_PREFSIZE_OR_HIDDEN = (1 << 4),
};
/* region do_draw */
@@ -415,4 +515,5 @@ enum {
#define RGN_DRAW_PARTIAL 2
#define RGN_DRAWING 4
#define RGN_DRAW_REFRESH_UI 8 /* re-create uiBlock's where possible */
+#define RGN_DRAW_NO_REBUILD 16
#endif
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
deleted file mode 100644
index 1fee490319f..00000000000
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file DNA_sensor_types.h
- * \ingroup DNA
- * \since mar-2001
- * \author nzc
- *
- * #bSensor type is specifically for use by Object logic-bricks in the game-engine.
- */
-
-#ifndef __DNA_SENSOR_TYPES_H__
-#define __DNA_SENSOR_TYPES_H__
-
-struct Object;
-struct Material;
-
-/* ****************** SENSORS ********************* */
-
-typedef struct bNearSensor {
- char name[64]; /* MAX_NAME */
- float dist, resetdist;
- int lastval, pad;
-} bNearSensor;
-
-/**
- * Defines the settings of a mouse sensor.
- */
-typedef struct bMouseSensor {
- /**
- * The type of key this sensor listens to.
- */
- short type;
- short flag;
- short pad1;
- short mode; /* flag to choose material or property */
- char propname[64];
- char matname[64];
-} bMouseSensor;
-
-/* DEPRECATED */
-typedef struct bTouchSensor {
- char name[64]; /* MAX_NAME */
- struct Material *ma;
- float dist, pad;
-} bTouchSensor;
-
-typedef struct bKeyboardSensor {
- short key, qual;
- short type, qual2;
- /**
- * Name of the target property
- */
- char targetName[64]; /* MAX_NAME */
- /**
- * Name of the toggle property
- */
- char toggleName[64]; /* MAX_NAME */
-} bKeyboardSensor;
-
-typedef struct bPropertySensor {
- int type;
- int pad;
- char name[64]; /* MAX_NAME */
- char value[64];
- char maxvalue[64];
-} bPropertySensor;
-
-typedef struct bActuatorSensor {
- int type;
- int pad;
- char name[64]; /* MAX_NAME */
-} bActuatorSensor;
-
-typedef struct bDelaySensor {
- short delay;
- short duration;
- short flag;
- short pad;
-} bDelaySensor;
-
-typedef struct bCollisionSensor {
- char name[64]; /* property name. MAX_NAME */
- char materialName[64]; /* material */
- // struct Material *ma; // XXX remove materialName
- short damptimer, damp;
- short mode; /* flag to choose material or property */
- short pad2;
-} bCollisionSensor;
-
-typedef struct bRadarSensor {
- char name[64]; /* MAX_NAME */
- float angle;
- float range;
- short flag, axis;
-} bRadarSensor;
-
-typedef struct bRandomSensor {
- char name[64]; /* MAX_NAME */
- int seed;
- int delay;
-} bRandomSensor;
-
-typedef struct bRaySensor {
- char name[64]; /* MAX_NAME */
- float range;
- char propname[64];
- char matname[64];
- //struct Material *ma; // XXX remove materialName
- short mode;
- short pad1;
- int axisflag;
-} bRaySensor;
-
-typedef struct bArmatureSensor {
- char posechannel[64]; /* MAX_NAME */
- char constraint[64]; /* MAX_NAME */
- int type;
- float value;
-} bArmatureSensor;
-
-typedef struct bMessageSensor {
- /**
- * (Possible future use) pointer to a single sender object
- */
- struct Object *fromObject;
-
- /**
- * Can be used to filter on subjects like this
- */
- char subject[64];
-
- /**
- * (Possible future use) body to filter on
- */
- char body[64];
-} bMessageSensor;
-
-typedef struct bSensor {
- struct bSensor *next, *prev;
- /* pulse and freq are the bool toggle and frame count for pulse mode */
- short type, otype, flag, pulse;
- short freq, totlinks, pad1, pad2; /* freq makes reference to skipped ticks between 2 active pulses */
- char name[64]; /* MAX_NAME */
- void *data;
-
- struct bController **links;
-
- struct Object *ob;
-
- /* just add here, to avoid align errors... */
- short invert; /* Whether or not to invert the output. */
- short level; /* Whether the sensor is level base (edge by default) */
- short tap;
- short pad;
-} bSensor;
-
-typedef struct bJoystickSensor {
- char name[64]; /* MAX_NAME */
- char type;
- char joyindex;
- short flag;
- short axis;
- short axis_single;
- int axisf;
- int button;
- int hat;
- int hatf;
- int precision;
-} bJoystickSensor;
-
-/* bMouseSensor->type: uses blender event defines */
-
-/* bMouseSensor->flag: only pulse for now */
-#define SENS_MOUSE_FOCUS_PULSE 1
-
-/* propertysensor->type */
-#define SENS_PROP_EQUAL 0
-#define SENS_PROP_NEQUAL 1
-#define SENS_PROP_INTERVAL 2
-#define SENS_PROP_CHANGED 3
-#define SENS_PROP_EXPRESSION 4
-#define SENS_PROP_LESSTHAN 5
-#define SENS_PROP_GREATERTHAN 6
-
-/* raysensor->axisflag */
-/* flip x and y to make y default!!! */
-#define SENS_RAY_X_AXIS 1
-#define SENS_RAY_Y_AXIS 0
-#define SENS_RAY_Z_AXIS 2
-#define SENS_RAY_NEG_X_AXIS 3
-#define SENS_RAY_NEG_Y_AXIS 4
-#define SENS_RAY_NEG_Z_AXIS 5
-//#define SENS_RAY_NEGATIVE_AXIS 1
-
-/* bRadarSensor->axis */
-#define SENS_RADAR_X_AXIS 0
-#define SENS_RADAR_Y_AXIS 1
-#define SENS_RADAR_Z_AXIS 2
-#define SENS_RADAR_NEG_X_AXIS 3
-#define SENS_RADAR_NEG_Y_AXIS 4
-#define SENS_RADAR_NEG_Z_AXIS 5
-
-/* bMessageSensor->type */
-#define SENS_MESG_MESG 0
-#define SENS_MESG_PROP 1
-
-/* bArmatureSensor->type */
-#define SENS_ARM_STATE_CHANGED 0
-#define SENS_ARM_LIN_ERROR_BELOW 1
-#define SENS_ARM_LIN_ERROR_ABOVE 2
-#define SENS_ARM_ROT_ERROR_BELOW 3
-#define SENS_ARM_ROT_ERROR_ABOVE 4
-/* update this when adding new type */
-#define SENS_ARM_MAXTYPE 4
-
-/* sensor->type */
-#define SENS_ALWAYS 0
-#define SENS_TOUCH 1 /* DEPRECATED */
-#define SENS_NEAR 2
-#define SENS_KEYBOARD 3
-#define SENS_PROPERTY 4
-#define SENS_MOUSE 5
-#define SENS_COLLISION 6
-#define SENS_RADAR 7
-#define SENS_RANDOM 8
-#define SENS_RAY 9
-#define SENS_MESSAGE 10
-#define SENS_JOYSTICK 11
-#define SENS_ACTUATOR 12
-#define SENS_DELAY 13
-#define SENS_ARMATURE 14
-/* sensor->flag */
-#define SENS_SHOW 1
-#define SENS_DEL 2
-#define SENS_NEW 4
-#define SENS_NOT 8
-#define SENS_VISIBLE 16
-#define SENS_PIN 32
-#define SENS_DEACTIVATE 64
-
-/* sensor->pulse */
-#define SENS_PULSE_CONT 0
-#define SENS_PULSE_REPEAT 1
-//#define SENS_PULSE_ONCE 2
-#define SENS_NEG_PULSE_MODE 4
-
-/* sensor->suppress */
-#define SENS_SUPPRESS_POSITIVE (1 << 0)
-#define SENS_SUPPRESS_NEGATIVE (1 << 1)
-
-/* collision, ray sensor modes: */
-/* A little bit fake: when property is active, the first bit is
- * reset. Bite me :) So we don't actually use it, so we comment it out
- * ... The reason for this is that we need to be backward compatible,
- * and have a proper default value for this thing.
- * */
-#define SENS_COLLISION_PROPERTY 0
-#define SENS_COLLISION_MATERIAL 1
-#define SENS_COLLISION_PULSE 2
-
-/* ray specific mode */
-/* X-Ray means that the ray will traverse objects that don't have the property/material */
-#define SENS_RAY_PROPERTY 0
-#define SENS_RAY_MATERIAL 1
-#define SENS_RAY_XRAY 2
-
-/* Some stuff for the mouse sensor Type: */
-#define BL_SENS_MOUSE_LEFT_BUTTON 1
-#define BL_SENS_MOUSE_MIDDLE_BUTTON 2
-#define BL_SENS_MOUSE_RIGHT_BUTTON 4
-#define BL_SENS_MOUSE_WHEEL_UP 5
-#define BL_SENS_MOUSE_WHEEL_DOWN 6
-#define BL_SENS_MOUSE_MOVEMENT 8
-#define BL_SENS_MOUSE_MOUSEOVER 16
-#define BL_SENS_MOUSE_MOUSEOVER_ANY 32
-
-/* Joystick sensor - sorted by axis types */
-#define SENS_JOY_ANY_EVENT 1
-
-#define SENS_JOY_BUTTON 0 /* axis type */
-
-#define SENS_JOY_AXIS 1 /* axis type */
-#define SENS_JOY_X_AXIS 0
-#define SENS_JOY_Y_AXIS 1
-#define SENS_JOY_NEG_X_AXIS 2
-#define SENS_JOY_NEG_Y_AXIS 3
-#define SENS_JOY_PRECISION 4
-
-#define SENS_JOY_HAT 2 /* axis type */
-#define SENS_JOY_HAT_DIR 0
-#define SENS_JOY_HAT_UP 1
-#define SENS_JOY_HAT_RIGHT 2
-#define SENS_JOY_HAT_DOWN 4
-#define SENS_JOY_HAT_LEFT 8
-
-#define SENS_JOY_HAT_UP_RIGHT SENS_JOY_HAT_UP | SENS_JOY_HAT_RIGHT
-#define SENS_JOY_HAT_DOWN_RIGHT SENS_JOY_HAT_DOWN | SENS_JOY_HAT_RIGHT
-#define SENS_JOY_HAT_UP_LEFT SENS_JOY_HAT_UP | SENS_JOY_HAT_LEFT
-#define SENS_JOY_HAT_DOWN_LEFT SENS_JOY_HAT_DOWN | SENS_JOY_HAT_LEFT
-
-
-#define SENS_JOY_AXIS_SINGLE 3 /* axis type */
-
-
-#define SENS_DELAY_REPEAT 1
-// should match JOYINDEX_MAX in SCA_JoystickDefines.h */
-#define SENS_JOY_MAXINDEX 8
-
-#endif /* __DNA_SENSOR_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 6e2fd412445..2e6aa25ad9b 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -391,8 +391,8 @@ typedef struct SequencerScopes {
#define SEQ_EDIT_OVERLAY_SHOW 1
#define SEQ_EDIT_OVERLAY_ABS 2
-#define SEQ_STRIP_OFSBOTTOM 0.2f
-#define SEQ_STRIP_OFSTOP 0.8f
+#define SEQ_STRIP_OFSBOTTOM 0.05f
+#define SEQ_STRIP_OFSTOP 0.95f
/* Editor->proxy_storage */
/* store proxies in project directory */
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
new file mode 100644
index 00000000000..7c138f21887
--- /dev/null
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -0,0 +1,244 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_shader_fx_types.h
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SHADER_FX_TYPES_H__
+#define __DNA_SHADER_FX_TYPES_H__
+
+#include "DNA_defs.h"
+#include "DNA_listBase.h"
+
+struct DRWShadingGroup;
+
+/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE!
+ * (ONLY ADD NEW ITEMS AT THE END)
+ */
+
+typedef enum ShaderFxType {
+ eShaderFxType_None = 0,
+ eShaderFxType_Blur = 1,
+ eShaderFxType_Flip = 2,
+ eShaderFxType_Light = 3,
+ eShaderFxType_Pixel = 4,
+ eShaderFxType_Swirl = 5,
+ eShaderFxType_Wave = 6,
+ eShaderFxType_Rim = 7,
+ eShaderFxType_Colorize = 8,
+ eShaderFxType_Shadow = 9,
+ eShaderFxType_Glow = 10,
+ NUM_SHADER_FX_TYPES
+} ShaderFxType;
+
+typedef enum ShaderFxMode {
+ eShaderFxMode_Realtime = (1 << 0),
+ eShaderFxMode_Render = (1 << 1),
+ eShaderFxMode_Editmode = (1 << 2),
+ eShaderFxMode_Expanded = (1 << 3),
+} ShaderFxMode;
+
+typedef enum {
+ /* This fx has been inserted in local override, and hence can be fully edited. */
+ eShaderFxFlag_StaticOverride_Local = (1 << 0),
+} ShaderFxFlag;
+
+typedef struct ShaderFxData {
+ struct ShaderFxData *next, *prev;
+
+ int type, mode;
+ int stackindex;
+ short flag;
+ short pad;
+ char name[64]; /* MAX_NAME */
+
+ char *error;
+} ShaderFxData;
+
+/* Runtime temp data */
+typedef struct ShaderFxData_Runtime {
+ struct DRWShadingGroup *fx_sh;
+ struct DRWShadingGroup *fx_sh_b;
+ struct DRWShadingGroup *fx_sh_c;
+} ShaderFxData_Runtime;
+
+typedef struct BlurShaderFxData {
+ ShaderFxData shaderfx;
+ int radius[2];
+ int flag; /* flags */
+ int samples; /* number of samples */
+ float coc; /* circle of confusion */
+ int blur[2]; /* not visible in rna */
+ char pad[4];
+
+ ShaderFxData_Runtime runtime;
+} BlurShaderFxData;
+
+typedef enum eBlurShaderFx_Flag {
+ FX_BLUR_DOF_MODE = (1 << 0)
+} eBlurShaderFx_Flag;
+
+typedef struct ColorizeShaderFxData {
+ ShaderFxData shaderfx;
+ int mode;
+ float low_color[4];
+ float high_color[4];
+ float factor;
+ int flag; /* flags */
+ char pad[4];
+
+ ShaderFxData_Runtime runtime;
+} ColorizeShaderFxData;
+
+typedef enum ColorizeShaderFxModes {
+ eShaderFxColorizeMode_GrayScale = 0,
+ eShaderFxColorizeMode_Sepia = 1,
+ eShaderFxColorizeMode_BiTone = 2,
+ eShaderFxColorizeMode_Custom = 3,
+ eShaderFxColorizeMode_Transparent = 4,
+} ColorizeShaderFxModes;
+
+typedef struct FlipShaderFxData {
+ ShaderFxData shaderfx;
+ int flag; /* flags */
+ int flipmode; /* internal, not visible in rna */
+ ShaderFxData_Runtime runtime;
+} FlipShaderFxData;
+
+typedef enum eFlipShaderFx_Flag {
+ FX_FLIP_HORIZONTAL = (1 << 0),
+ FX_FLIP_VERTICAL = (1 << 1),
+} eFlipShaderFx_Flag;
+
+typedef struct GlowShaderFxData {
+ ShaderFxData shaderfx;
+ float glow_color[3];
+ float select_color[3];
+ float threshold;
+ int flag; /* flags */
+ int mode;
+ int blur[2];
+ int samples;
+ ShaderFxData_Runtime runtime;
+} GlowShaderFxData;
+
+typedef enum GlowShaderFxModes {
+ eShaderFxGlowMode_Luminance = 0,
+ eShaderFxGlowMode_Color = 1,
+} GlowShaderFxModes;
+
+typedef enum eGlowShaderFx_Flag {
+ FX_GLOW_USE_ALPHA = (1 << 0),
+} eGlowShaderFx_Flag;
+
+typedef struct LightShaderFxData {
+ ShaderFxData shaderfx;
+ struct Object *object;
+ int flag; /* flags */
+ float energy;
+ float ambient;
+ float loc[4]; /* internal, not visible in rna */
+ char pad[4];
+ ShaderFxData_Runtime runtime;
+} LightShaderFxData;
+
+typedef struct PixelShaderFxData {
+ ShaderFxData shaderfx;
+ int size[3]; /* last element used for shader only */
+ int flag; /* flags */
+ float rgba[4];
+ ShaderFxData_Runtime runtime;
+} PixelShaderFxData;
+
+typedef enum ePixelShaderFx_Flag {
+ FX_PIXEL_USE_LINES = (1 << 0),
+} ePixelShaderFx_Flag;
+
+typedef struct RimShaderFxData {
+ ShaderFxData shaderfx;
+ int offset[2];
+ int flag; /* flags */
+ float rim_rgb[3];
+ float mask_rgb[3];
+ int mode;
+ int blur[2];
+ int samples;
+ char pad[4];
+ ShaderFxData_Runtime runtime;
+} RimShaderFxData;
+
+typedef enum RimShaderFxModes {
+ eShaderFxRimMode_Normal = 0,
+ eShaderFxRimMode_Overlay = 1,
+ eShaderFxRimMode_Add = 2,
+ eShaderFxRimMode_Subtract = 3,
+ eShaderFxRimMode_Multiply = 4,
+ eShaderFxRimMode_Divide = 5,
+} RimShaderFxModes;
+
+typedef struct ShadowShaderFxData {
+ ShaderFxData shaderfx;
+ struct Object *object;
+ int offset[2];
+ int flag; /* flags */
+ float shadow_rgba[4];
+ float amplitude;
+ float period;
+ float phase;
+ int orientation;
+ float scale[2];
+ float rotation;
+ int blur[2];
+ int samples;
+ char pad[4];
+ ShaderFxData_Runtime runtime;
+} ShadowShaderFxData;
+
+typedef enum eShadowShaderFx_Flag {
+ FX_SHADOW_USE_OBJECT = (1 << 0),
+ FX_SHADOW_USE_WAVE = (1 << 1),
+} eShadowShaderFx_Flag;
+
+typedef struct SwirlShaderFxData {
+ ShaderFxData shaderfx;
+ struct Object *object;
+ int flag; /* flags */
+ int radius;
+ float angle;
+ int transparent; /* not visible in rna */
+ ShaderFxData_Runtime runtime;
+} SwirlShaderFxData;
+
+typedef enum eSwirlShaderFx_Flag {
+ FX_SWIRL_MAKE_TRANSPARENT = (1 << 0),
+} eSwirlShaderFx_Flag;
+
+typedef struct WaveShaderFxData {
+ ShaderFxData shaderfx;
+ float amplitude;
+ float period;
+ float phase;
+ int orientation;
+ int flag; /* flags */
+ char pad[4];
+ ShaderFxData_Runtime runtime;
+} WaveShaderFxData;
+#endif /* __DNA_SHADER_FX_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index ee7e080f39b..97913e29ad4 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -72,6 +72,12 @@ enum {
SLICE_AXIS_Z = 3,
};
+/* axis aligned method */
+enum {
+ VOLUME_INTERP_LINEAR = 0,
+ VOLUME_INTERP_CUBIC = 1,
+};
+
enum {
VECTOR_DRAW_NEEDLE = 0,
VECTOR_DRAW_STREAMLINE = 1,
@@ -129,14 +135,20 @@ typedef struct SmokeDomainSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
struct FLUID_3D *fluid;
void *fluid_mutex;
- struct Group *fluid_group;
- struct Group *eff_group; // UNUSED
- struct Group *coll_group; // collision objects group
+ struct Collection *fluid_group;
+ struct Collection *eff_group; // UNUSED
+ struct Collection *coll_group; // collision objects group
struct WTURBULENCE *wt; // WTURBULENCE object, if active
struct GPUTexture *tex;
struct GPUTexture *tex_wt;
struct GPUTexture *tex_shadow;
struct GPUTexture *tex_flame;
+ struct GPUTexture *tex_flame_coba;
+ struct GPUTexture *tex_coba;
+ struct GPUTexture *tex_field;
+ struct GPUTexture *tex_velocity_x;
+ struct GPUTexture *tex_velocity_y;
+ struct GPUTexture *tex_velocity_z;
float *shadow;
/* simulation data */
@@ -216,7 +228,7 @@ typedef struct SmokeDomainSettings {
char vector_draw_type;
char use_coba;
char coba_field; /* simulation field used for the color mapping */
- char pad2;
+ char interp_method;
float clipping;
float pad3;
@@ -247,7 +259,7 @@ typedef struct SmokeDomainSettings {
typedef struct SmokeFlowSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
- struct DerivedMesh *dm;
+ struct Mesh *mesh;
struct ParticleSystem *psys;
struct Tex *noise_texture;
@@ -287,7 +299,7 @@ typedef struct SmokeFlowSettings {
/* collision objects (filled with smoke) */
typedef struct SmokeCollSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
- struct DerivedMesh *dm;
+ struct Mesh *mesh;
float *verts_old;
int numverts;
short type; // static = 0, rigid = 1, dynamic = 2
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index e94364e8a65..43781c47828 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -67,6 +67,11 @@ struct MovieClipScopes;
struct Mask;
struct BLI_mempool;
+/* TODO 2.8: We don't write the global areas to files currently. Uncomment
+ * define to enable writing (should become the default in a bit). */
+//#define WITH_GLOBAL_AREA_WRITING
+
+
/* -------------------------------------------------------------------- */
/** \name SpaceLink (Base)
* \{ */
@@ -129,12 +134,14 @@ typedef struct SpaceButs {
View2D v2d DNA_DEPRECATED; /* deprecated, copied to region */
+ /* For different kinds of property editors (exposed in the space type selector). */
+ short space_subtype;
+
short mainb, mainbo, mainbuser; /* context tabs */
- short re_align, align; /* align for panels */
short preview; /* preview is signal to refresh */
- /* texture context selector (material, lamp, particles, world, other) */
- short texture_context, texture_context_prev;
- char flag, pad[7];
+ short pad[2];
+ char flag;
+ char collection_context;
void *path; /* runtime */
int pathflag, dataicon; /* runtime */
@@ -153,7 +160,7 @@ typedef struct SpaceButs {
#define CONTEXT_SHADING 3
#define CONTEXT_EDITING 4
// #define CONTEXT_SCRIPT 5
-#define CONTEXT_LOGIC 6
+// #define CONTEXT_LOGIC 6
/* SpaceButs.mainb old (deprecated) */
// #define BUTS_VIEW 0
@@ -164,7 +171,7 @@ typedef struct SpaceButs {
#define BUTS_WORLD 5
#define BUTS_RENDER 6
#define BUTS_EDIT 7
-#define BUTS_GAME 8
+// #define BUTS_GAME 8
#define BUTS_FPAINT 9
#define BUTS_RADIO 10
#define BUTS_SCRIPT 11
@@ -188,7 +195,10 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_MODIFIER = 10,
BCONTEXT_CONSTRAINT = 11,
BCONTEXT_BONE_CONSTRAINT = 12,
- BCONTEXT_RENDER_LAYER = 13,
+ BCONTEXT_VIEW_LAYER = 13,
+ BCONTEXT_TOOL = 14,
+ BCONTEXT_SHADERFX = 15,
+ BCONTEXT_OUTPUT = 16,
/* always as last... */
BCONTEXT_TOT
@@ -204,39 +214,6 @@ typedef enum eSpaceButtons_Flag {
SB_SHADING_CONTEXT = (1 << 4),
} eSpaceButtons_Flag;
-/* SpaceButs.texture_context */
-typedef enum eSpaceButtons_Texture_Context {
- SB_TEXC_MATERIAL = 0,
- SB_TEXC_WORLD = 1,
- SB_TEXC_LAMP = 2,
- SB_TEXC_PARTICLES = 3,
- SB_TEXC_OTHER = 4,
- SB_TEXC_LINESTYLE = 5,
-} eSpaceButtons_Texture_Context;
-
-/* SpaceButs.align */
-typedef enum eSpaceButtons_Align {
- BUT_FREE = 0,
- BUT_HORIZONTAL = 1,
- BUT_VERTICAL = 2,
- BUT_AUTO = 3,
-} eSpaceButtons_Align;
-
-/* SpaceButs.scaflag */
-#define BUTS_SENS_SEL 1
-#define BUTS_SENS_ACT 2
-#define BUTS_SENS_LINK 4
-#define BUTS_CONT_SEL 8
-#define BUTS_CONT_ACT 16
-#define BUTS_CONT_LINK 32
-#define BUTS_ACT_SEL 64
-#define BUTS_ACT_ACT 128
-#define BUTS_ACT_LINK 256
-#define BUTS_SENS_STATE 512
-#define BUTS_ACT_STATE 1024
-#define BUTS_CONT_INIT_STATE 2048
-
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -269,6 +246,10 @@ typedef struct SpaceOops {
struct TreeStoreElem search_tse;
short flag, outlinevis, storeflag, search_flags;
+ int filter;
+ char filter_state;
+ char pad;
+ short filter_id_type;
/* pointers to treestore elements, grouped by (id, type, nr) in hashtable for faster searching */
void *treehash;
@@ -284,31 +265,81 @@ typedef enum eSpaceOutliner_Flag {
SO_SKIP_SORT_ALPHA = (1 << 4),
} eSpaceOutliner_Flag;
+/* SpaceOops.filter */
+typedef enum eSpaceOutliner_Filter {
+ SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */
+ /* SO_FILTER_ENABLE = (1 << 1), */ /* Deprecated */
+ SO_FILTER_NO_OBJECT = (1 << 2),
+ SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */
+ SO_FILTER_NO_CHILDREN = (1 << 4),
+
+ /* SO_FILTER_OB_TYPE = (1 << 5), */ /* Deprecated */
+ SO_FILTER_NO_OB_MESH = (1 << 6),
+ SO_FILTER_NO_OB_ARMATURE = (1 << 7),
+ SO_FILTER_NO_OB_EMPTY = (1 << 8),
+ SO_FILTER_NO_OB_LAMP = (1 << 9),
+ SO_FILTER_NO_OB_CAMERA = (1 << 10),
+ SO_FILTER_NO_OB_OTHERS = (1 << 11),
+
+ /* SO_FILTER_OB_STATE = (1 << 12), */ /* Deprecated */
+ SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
+ SO_FILTER_OB_STATE_SELECTED = (1 << 14), /* Not set via DNA. */
+ SO_FILTER_OB_STATE_ACTIVE = (1 << 15), /* Not set via DNA. */
+ SO_FILTER_NO_COLLECTION = (1 << 16),
+
+ SO_FILTER_ID_TYPE = (1 << 17),
+} eSpaceOutliner_Filter;
+
+#define SO_FILTER_OB_TYPE (SO_FILTER_NO_OB_MESH | \
+ SO_FILTER_NO_OB_ARMATURE | \
+ SO_FILTER_NO_OB_EMPTY | \
+ SO_FILTER_NO_OB_LAMP | \
+ SO_FILTER_NO_OB_CAMERA | \
+ SO_FILTER_NO_OB_OTHERS)
+
+#define SO_FILTER_OB_STATE (SO_FILTER_OB_STATE_VISIBLE | \
+ SO_FILTER_OB_STATE_SELECTED | \
+ SO_FILTER_OB_STATE_ACTIVE)
+
+#define SO_FILTER_ANY (SO_FILTER_NO_OB_CONTENT | \
+ SO_FILTER_NO_CHILDREN | \
+ SO_FILTER_OB_TYPE | \
+ SO_FILTER_OB_STATE | \
+ SO_FILTER_NO_COLLECTION)
+
+/* SpaceOops.filter_state */
+typedef enum eSpaceOutliner_StateFilter {
+ SO_FILTER_OB_ALL = 0,
+ SO_FILTER_OB_VISIBLE = 1,
+ SO_FILTER_OB_SELECTED = 2,
+ SO_FILTER_OB_ACTIVE = 3,
+} eSpaceOutliner_StateFilter;
+
/* SpaceOops.outlinevis */
typedef enum eSpaceOutliner_Mode {
- SO_ALL_SCENES = 0,
- SO_CUR_SCENE = 1,
- SO_VISIBLE = 2,
- SO_SELECTED = 3,
- SO_ACTIVE = 4,
- SO_SAME_TYPE = 5,
- SO_GROUPS = 6,
- SO_LIBRARIES = 7,
- /* SO_VERSE_SESSION = 8, */ /* deprecated! */
- /* SO_VERSE_MS = 9, */ /* deprecated! */
- SO_SEQUENCE = 10,
- SO_DATABLOCKS = 11,
- SO_USERDEF = 12,
- /* SO_KEYMAP = 13, */ /* deprecated! */
- SO_ID_ORPHANS = 14,
+ SO_SCENES = 0,
+ /* SO_CUR_SCENE = 1, */ /* deprecated! */
+ /* SO_VISIBLE = 2, */ /* deprecated! */
+ /* SO_SELECTED = 3, */ /* deprecated! */
+ /* SO_ACTIVE = 4, */ /* deprecated! */
+ /* SO_SAME_TYPE = 5, */ /* deprecated! */
+ /* SO_GROUPS = 6, */ /* deprecated! */
+ SO_LIBRARIES = 7,
+ /* SO_VERSE_SESSION = 8, */ /* deprecated! */
+ /* SO_VERSE_MS = 9, */ /* deprecated! */
+ SO_SEQUENCE = 10,
+ SO_DATA_API = 11,
+ /* SO_USERDEF = 12, */ /* deprecated! */
+ /* SO_KEYMAP = 13, */ /* deprecated! */
+ SO_ID_ORPHANS = 14,
+ SO_VIEW_LAYER = 15,
} eSpaceOutliner_Mode;
/* SpaceOops.storeflag */
typedef enum eSpaceOutliner_StoreFlag {
/* cleanup tree */
SO_TREESTORE_CLEANUP = (1 << 0),
- /* if set, it allows redraws. gets set for some allqueue events */
- SO_TREESTORE_REDRAW = (1 << 1),
+ /* SO_TREESTORE_REDRAW = (1 << 1), */ /* Deprecated */
/* rebuild the tree, similar to cleanup,
* but defer a call to BKE_outliner_treehash_rebuild_from_treestore instead */
SO_TREESTORE_REBUILD = (1 << 2),
@@ -443,43 +474,6 @@ typedef enum eSpaceNla_Flag {
/** \name Timeline
* \{ */
-/* Pointcache drawing data */
-# /* Only store the data array in the cache to avoid constant reallocation. */
-# /* No need to store when saved. */
-typedef struct SpaceTimeCache {
- struct SpaceTimeCache *next, *prev;
- float *array;
-} SpaceTimeCache;
-
-/* Timeline View */
-typedef struct SpaceTime {
- SpaceLink *next, *prev;
- ListBase regionbase; /* storage of regions for inactive spaces */
- char spacetype;
- char link_flag;
- char _pad0[6];
- /* End 'SpaceLink' header. */
-
-
- View2D v2d DNA_DEPRECATED; /* deprecated, copied to region */
-
- ListBase caches;
-
- int cache_display;
- int flag;
-} SpaceTime;
-
-
-/* SpaceTime.flag */
-typedef enum eTimeline_Flag {
- /* show timing in frames instead of in seconds */
- TIME_DRAWFRAMES = (1 << 0),
- /* show time indicator box beside the frame number */
- TIME_CFRA_NUM = (1 << 1),
- /* only keyframes from active/selected channels get shown */
- TIME_ONLYACTSEL = (1 << 2),
-} eTimeline_Flag;
-
/* SpaceTime.redraws (now bScreen.redraws_flag) */
typedef enum eScreen_Redraws_Flag {
TIME_REGION = (1 << 0),
@@ -496,17 +490,6 @@ typedef enum eScreen_Redraws_Flag {
TIME_FOLLOW = (1 << 15),
} eScreen_Redraws_Flag;
-/* SpaceTime.cache */
-typedef enum eTimeline_Cache_Flag {
- TIME_CACHE_DISPLAY = (1 << 0),
- TIME_CACHE_SOFTBODY = (1 << 1),
- TIME_CACHE_PARTICLES = (1 << 2),
- TIME_CACHE_CLOTH = (1 << 3),
- TIME_CACHE_SMOKE = (1 << 4),
- TIME_CACHE_DYNAMICPAINT = (1 << 5),
- TIME_CACHE_RIGIDBODY = (1 << 6),
-} eTimeline_Cache_Flag;
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -693,17 +676,6 @@ typedef struct SpaceFile {
short systemnr, system_bookmarknr;
} SpaceFile;
-/* FSMenuEntry's without paths indicate separators */
-typedef struct FSMenuEntry {
- struct FSMenuEntry *next;
-
- char *path;
- char name[256]; /* FILE_MAXFILE */
- short save;
- short valid;
- short pad[2];
-} FSMenuEntry;
-
/* FileSelectParams.display */
enum eFileDisplayType {
FILE_DEFAULTDISPLAY = 0,
@@ -753,7 +725,7 @@ typedef enum eFileSel_Params_Flag {
FILE_LINK = (1 << 2),
FILE_HIDE_DOT = (1 << 3),
FILE_AUTOSELECT = (1 << 4),
- FILE_ACTIVELAY = (1 << 5),
+ FILE_ACTIVE_COLLECTION = (1 << 5),
/* FILE_ATCURSOR = (1 << 6), */ /* deprecated */
FILE_DIRSEL_ONLY = (1 << 7),
FILE_FILTER = (1 << 8),
@@ -946,8 +918,7 @@ typedef struct SpaceImage {
char dt_uvstretch;
char around;
- /* Filter settings when editor shows other object's UVs. */
- int other_uv_filter;
+ int pad2;
int flag;
@@ -973,7 +944,8 @@ typedef enum eSpaceImage_UVDT_Stretch {
typedef enum eSpaceImage_Mode {
SI_MODE_VIEW = 0,
SI_MODE_PAINT = 1,
- SI_MODE_MASK = 2 /* note: mesh edit mode overrides mask */
+ SI_MODE_MASK = 2,
+ SI_MODE_UV = 3,
} eSpaceImage_Mode;
/* SpaceImage.sticky
@@ -988,7 +960,7 @@ typedef enum eSpaceImage_Sticky {
/* SpaceImage.flag */
typedef enum eSpaceImage_Flag {
/* SI_BE_SQUARE = (1 << 0), */ /* deprecated */
- SI_EDITTILE = (1 << 1), /* XXX - not used but should be? */
+/* SI_EDITTILE = (1 << 1), */ /* deprecated */
SI_CLIP_UV = (1 << 2),
/* SI_DRAWTOOL = (1 << 3), */ /* deprecated */
SI_NO_DRAWFACES = (1 << 4),
@@ -1017,7 +989,7 @@ typedef enum eSpaceImage_Flag {
SI_SMOOTH_UV = (1 << 20),
SI_DRAW_STRETCH = (1 << 21),
SI_SHOW_GPENCIL = (1 << 22),
- SI_DRAW_OTHER = (1 << 23),
+/* SI_DEPRECATED6 = (1 << 23), */ /* deprecated */
SI_COLOR_CORRECTION = (1 << 24),
@@ -1027,6 +999,8 @@ typedef enum eSpaceImage_Flag {
SI_SHOW_R = (1 << 27),
SI_SHOW_G = (1 << 28),
SI_SHOW_B = (1 << 29),
+
+ SI_NO_DRAWEDGES = (1 << 30),
} eSpaceImage_Flag;
/* SpaceImage.other_uv_filter */
@@ -1217,14 +1191,14 @@ typedef enum eSpaceNode_Flag {
SNODE_AUTO_RENDER = (1 << 5),
// SNODE_SHOW_HIGHLIGHT = (1 << 6), DNA_DEPRECATED
// SNODE_USE_HIDDEN_PREVIEW = (1 << 10), DNA_DEPRECATED December2013
- SNODE_NEW_SHADERS = (1 << 11),
+// SNODE_NEW_SHADERS = (1 << 11), DNA_DEPRECATED
SNODE_PIN = (1 << 12),
SNODE_SKIP_INSOFFSET = (1 << 13), /* automatically offset following nodes in a chain on insertion */
} eSpaceNode_Flag;
/* SpaceNode.texfrom */
typedef enum eSpaceNode_TexFrom {
- SNODE_TEX_OBJECT = 0,
+ /* SNODE_TEX_OBJECT = 0, */
SNODE_TEX_WORLD = 1,
SNODE_TEX_BRUSH = 2,
SNODE_TEX_LINESTYLE = 3,
@@ -1246,27 +1220,6 @@ enum {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Game Logic Editor
- * \{ */
-
-/* Logic Editor */
-typedef struct SpaceLogic {
- SpaceLink *next, *prev;
- ListBase regionbase; /* storage of regions for inactive spaces */
- char spacetype;
- char link_flag;
- char _pad0[6];
- /* End 'SpaceLink' header. */
-
- short flag, scaflag;
- int pad;
-
- struct bGPdata *gpd; /* grease-pencil data */
-} SpaceLogic;
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Console
* \{ */
@@ -1396,7 +1349,7 @@ typedef enum eSpaceClip_Flag {
SC_SHOW_GRID = (1 << 9),
SC_SHOW_STABLE = (1 << 10),
SC_MANUAL_CALIBRATION = (1 << 11),
- SC_SHOW_GPENCIL = (1 << 12),
+ SC_SHOW_ANNOTATION = (1 << 12),
SC_SHOW_FILTERS = (1 << 13),
SC_SHOW_GRAPH_FRAMES = (1 << 14),
SC_SHOW_GRAPH_TRACKS_MOTION = (1 << 15),
@@ -1430,6 +1383,45 @@ typedef enum eSpaceClip_GPencil_Source {
SC_GPENCIL_SRC_TRACK = 1,
} eSpaceClip_GPencil_Source;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Top Bar
+ * \{ */
+
+/* These two lines with # tell makesdna this struct can be excluded.
+ * Should be: #ifndef WITH_GLOBAL_AREA_WRITING */
+#
+#
+typedef struct SpaceTopBar {
+ SpaceLink *next, *prev;
+ ListBase regionbase; /* storage of regions for inactive spaces */
+ char spacetype;
+ char link_flag;
+ char _pad0[6];
+ /* End 'SpaceLink' header. */
+} SpaceTopBar;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Status Bar
+ * \{ */
+
+/* These two lines with # tell makesdna this struct can be excluded.
+ * Should be: #ifndef WITH_GLOBAL_AREA_WRITING */
+#
+#
+typedef struct SpaceStatusBar {
+ SpaceLink *next, *prev;
+ ListBase regionbase; /* storage of regions for inactive spaces */
+ char spacetype;
+ char link_flag;
+ char _pad0[6];
+ /* End 'SpaceLink' header. */
+} SpaceStatusBar;
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1457,14 +1449,16 @@ typedef enum eSpace_Type {
SPACE_NLA = 13,
/* TODO: fully deprecate */
SPACE_SCRIPT = 14, /* Deprecated */
- SPACE_TIME = 15,
+ SPACE_TIME = 15, /* Deprecated */
SPACE_NODE = 16,
- SPACE_LOGIC = 17,
+ SPACE_LOGIC = 17, /* deprecated */
SPACE_CONSOLE = 18,
SPACE_USERPREF = 19,
SPACE_CLIP = 20,
+ SPACE_TOPBAR = 21,
+ SPACE_STATUSBAR = 22,
- SPACE_TYPE_LAST = SPACE_CLIP
+ SPACE_TYPE_LAST = SPACE_STATUSBAR
} eSpace_Type;
/* use for function args */
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 3972cbd2a0e..42198e22c6b 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -45,13 +45,11 @@ extern "C" {
struct AnimData;
struct Ipo;
struct ColorBand;
-struct EnvMap;
struct Object;
struct Tex;
struct Image;
struct PreviewImage;
struct ImBuf;
-struct Ocean;
struct CurveMapping;
typedef struct MTex {
@@ -121,21 +119,6 @@ typedef struct ColorBand {
CBData data[32];
} ColorBand;
-typedef struct EnvMap {
- struct Object *object;
- struct Image *ima; /* type ENV_LOAD */
- struct ImBuf *cube[6]; /* these images are dynamic, not part of the main struct */
- float imat[4][4];
- float obimat[3][3];
- short type, stype;
- float clipsta, clipend;
- float viewscale; /* viewscale is for planar envmaps to zoom in or out */
- unsigned int notlay;
- short cuberes, depth;
- int ok, lastframe;
- short recalc, lastsize;
-} EnvMap;
-
typedef struct PointDensity {
short flag;
@@ -172,38 +155,6 @@ typedef struct PointDensity {
struct CurveMapping *falloff_curve; /* falloff density curve */
} PointDensity;
-typedef struct VoxelData {
- int resol[3];
- int interp_type;
- short file_format;
- short flag;
- short extend;
- short smoked_type;
- short hair_type;
- short data_type;
- int _pad;
-
- struct Object *object; /* for rendering smoke sims */
- float int_multiplier;
- int still_frame;
- char source_path[1024]; /* 1024 = FILE_MAX */
-
- /* temporary data */
- float *dataset;
- int cachedframe;
- int ok;
-
-} VoxelData;
-
-typedef struct OceanTex {
- struct Object *object;
- char oceanmod[64];
-
- int output;
- int pad;
-
-} OceanTex;
-
typedef struct Tex {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -241,7 +192,7 @@ typedef struct Tex {
short extend;
/* variables disabled, moved to struct iuser */
- short fie_ima;
+ short _pad0;
int len;
int frames, offset, sfra;
@@ -254,11 +205,7 @@ typedef struct Tex {
struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
struct Image *ima;
struct ColorBand *coba;
- struct EnvMap *env;
struct PreviewImage *preview;
- struct PointDensity *pd;
- struct VoxelData *vd;
- struct OceanTex *ot;
char use_nodes;
char pad[7];
@@ -316,13 +263,13 @@ typedef struct ColorMapping {
#define TEX_NOISE 7
#define TEX_IMAGE 8
//#define TEX_PLUGIN 9 /* Deprecated */
-#define TEX_ENVMAP 10
+//#define TEX_ENVMAP 10 /* Deprecated */
#define TEX_MUSGRAVE 11
#define TEX_VORONOI 12
#define TEX_DISTNOISE 13
-#define TEX_POINTDENSITY 14
-#define TEX_VOXELDATA 15
-#define TEX_OCEAN 16
+//#define TEX_POINTDENSITY 14 /* Deprecated */
+//#define TEX_VOXELDATA 15 /* Deprecated */
+//#define TEX_OCEAN 16 /* Deprecated */
/* musgrave stype */
#define TEX_MFRACTAL 0
@@ -372,7 +319,7 @@ typedef struct ColorMapping {
/* imaflag unused, only for version check */
#ifdef DNA_DEPRECATED_ALLOW
-#define TEX_FIELDS_ 8
+// #define TEX_FIELDS_ 8
#define TEX_ANIMCYCLIC_ 64
#define TEX_ANIM5_ 128
#define TEX_ANTIALI_ 256
@@ -549,22 +496,6 @@ enum {
COLBAND_HUE_CCW = 3,
};
-/* **************** EnvMap ********************* */
-
-/* type */
-#define ENV_CUBE 0
-#define ENV_PLANE 1
-#define ENV_SPHERE 2
-
-/* stype */
-#define ENV_STATIC 0
-#define ENV_ANIM 1
-#define ENV_LOAD 2
-
-/* ok */
-#define ENV_NORMAL 1
-#define ENV_OSA 2
-
/* **************** PointDensity ********************* */
/* source */
@@ -592,9 +523,9 @@ enum {
/* noise_influence */
#define TEX_PD_NOISE_STATIC 0
-#define TEX_PD_NOISE_VEL 1
-#define TEX_PD_NOISE_AGE 2
-#define TEX_PD_NOISE_TIME 3
+/* #define TEX_PD_NOISE_VEL 1 */ /* Deprecated */
+/* #define TEX_PD_NOISE_AGE 2 */ /* Deprecated */
+/* #define TEX_PD_NOISE_TIME 3 */ /* Deprecated */
/* color_source */
enum {
@@ -613,55 +544,6 @@ enum {
#define POINT_DATA_LIFE 2
#define POINT_DATA_COLOR 4
-/******************** Voxel Data *****************************/
-/* flag */
-#define TEX_VD_STILL 1
-
-/* interpolation */
-#define TEX_VD_NEARESTNEIGHBOR 0
-#define TEX_VD_LINEAR 1
-#define TEX_VD_QUADRATIC 2
-#define TEX_VD_TRICUBIC_CATROM 3
-#define TEX_VD_TRICUBIC_BSPLINE 4
-#define TEX_VD_TRICUBIC_SLOW 5
-
-/* file format */
-#define TEX_VD_BLENDERVOXEL 0
-#define TEX_VD_RAW_8BIT 1
-#define TEX_VD_RAW_16BIT 2
-#define TEX_VD_IMAGE_SEQUENCE 3
-#define TEX_VD_SMOKE 4
-#define TEX_VD_HAIR 5
-/* for voxels which use VoxelData->source_path */
-#define TEX_VD_IS_SOURCE_PATH(_format) (ELEM(_format, TEX_VD_BLENDERVOXEL, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT))
-
-/* smoke data types */
-#define TEX_VD_SMOKEDENSITY 0
-#define TEX_VD_SMOKEHEAT 1
-#define TEX_VD_SMOKEVEL 2
-#define TEX_VD_SMOKEFLAME 3
-
-#define TEX_VD_HAIRDENSITY 0
-#define TEX_VD_HAIRVELOCITY 1
-#define TEX_VD_HAIRENERGY 2
-#define TEX_VD_HAIRRESTDENSITY 3
-
-/* data_type */
-#define TEX_VD_INTENSITY 0
-#define TEX_VD_RGBA_PREMUL 1
-
-/******************** Ocean *****************************/
-/* output */
-#define TEX_OCN_DISPLACEMENT 1
-#define TEX_OCN_FOAM 2
-#define TEX_OCN_JPLUS 3
-#define TEX_OCN_EMINUS 4
-#define TEX_OCN_EPLUS 5
-
-/* flag */
-#define TEX_OCN_GENERATE_NORMALS 1
-#define TEX_OCN_XZ 2
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index aea5f0fd87b..e0bed7216e2 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -48,6 +48,11 @@ struct ColorBand;
#define MAX_STYLE_NAME 64
+#define GPU_VIEWPORT_QUALITY_FXAA 0.10f
+#define GPU_VIEWPORT_QUALITY_TAA8 0.25f
+#define GPU_VIEWPORT_QUALITY_TAA16 0.6f
+#define GPU_VIEWPORT_QUALITY_TAA32 0.8f
+
/* default offered by Blender.
* uiFont.uifont_id */
typedef enum eUIFont_ID {
@@ -128,9 +133,10 @@ typedef struct uiWidgetColors {
char item[4];
char text[4];
char text_sel[4];
- short shaded;
+ char shaded;
+ char _pad0[7];
short shadetop, shadedown;
- char _pad0[2];
+ float roundness;
} uiWidgetColors;
typedef struct uiWidgetStateColors {
@@ -140,15 +146,16 @@ typedef struct uiWidgetStateColors {
char inner_key_sel[4];
char inner_driven[4];
char inner_driven_sel[4];
+ char inner_overridden[4];
+ char inner_overridden_sel[4];
float blend, pad;
} uiWidgetStateColors;
typedef struct uiPanelColors {
char header[4];
char back[4];
- short show_header;
- short show_back;
- int pad;
+ char sub_back[4];
+ char pad2[4];
} uiPanelColors;
typedef struct uiGradientColors {
@@ -160,9 +167,9 @@ typedef struct uiGradientColors {
typedef struct ThemeUI {
/* Interface Elements (buttons, menus, icons) */
- uiWidgetColors wcol_regular, wcol_tool, wcol_text;
+ uiWidgetColors wcol_regular, wcol_tool, wcol_toolbar_item, wcol_text;
uiWidgetColors wcol_radio, wcol_option, wcol_toggle;
- uiWidgetColors wcol_num, wcol_numslider;
+ uiWidgetColors wcol_num, wcol_numslider, wcol_tab;
uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item, wcol_tooltip;
uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item, wcol_pie_menu;
@@ -176,13 +183,30 @@ typedef struct ThemeUI {
float menu_shadow_fac;
short menu_shadow_width;
- short pad[3];
+ char editor_outline[4];
+ short pad[1];
char iconfile[256]; // FILE_MAXFILE length
float icon_alpha;
+ float icon_saturation;
+ char _pad[4];
/* Axis Colors */
char xaxis[4], yaxis[4], zaxis[4];
+
+ /* Gizmo Colors. */
+ char gizmo_hi[4];
+ char gizmo_primary[4];
+ char gizmo_secondary[4];
+ char gizmo_a[4];
+ char gizmo_b[4];
+
+ /* Icon Colors. */
+ char icon_collection[4]; /* Collection items */
+ char icon_object[4]; /* Object items */
+ char icon_object_data[4]; /* Object data items */
+ char icon_modifier[4]; /* Modifier and constraint items */
+ char icon_shading[4]; /* Shading related items */
} ThemeUI;
/* try to put them all in one, if needed a special struct can be created as well
@@ -219,6 +243,10 @@ typedef struct ThemeSpace {
char list_text[4];
char list_text_hi[4];
+ /* navigation bar regions */
+ char navigation_bar[4]; /* region background */
+ int pad2;
+
/* float panel */
/* char panel[4]; unused */
/* char panel_title[4]; unused */
@@ -262,10 +290,11 @@ typedef struct ThemeSpace {
char handle_free[4], handle_auto[4], handle_vect[4], handle_align[4], handle_auto_clamped[4];
char handle_sel_free[4], handle_sel_auto[4], handle_sel_vect[4], handle_sel_align[4], handle_sel_auto_clamped[4];
- char ds_channel[4], ds_subchannel[4]; /* dopesheet */
- char keytype_keyframe[4], keytype_extreme[4], keytype_breakdown[4], keytype_jitter[4]; /* keytypes */
- char keytype_keyframe_select[4], keytype_extreme_select[4], keytype_breakdown_select[4], keytype_jitter_select[4]; /* keytypes */
+ char ds_channel[4], ds_subchannel[4], ds_ipoline[4]; /* dopesheet */
+ char keytype_keyframe[4], keytype_extreme[4], keytype_breakdown[4], keytype_jitter[4], keytype_movehold[4]; /* keytypes */
+ char keytype_keyframe_select[4], keytype_extreme_select[4], keytype_breakdown_select[4], keytype_jitter_select[4], keytype_movehold_select[4]; /* keytypes */
char keyborder[4], keyborder_select[4];
+ char pad[4];
char console_output[4], console_input[4], console_info[4], console_error[4];
char console_cursor[4], console_select[4];
@@ -326,6 +355,8 @@ typedef struct ThemeSpace {
/* NLA */
char anim_active[4]; /* Active Action + Summary Channel */
char anim_non_active[4]; /* Active Action = NULL */
+ char anim_preview_range[4]; /* Preview range overlay */
+ char anim_pad[4];
char nla_tweaking[4]; /* NLA 'Tweaking' action/strip */
char nla_tweakdupli[4]; /* NLA - warning color for duplicate instances of tweaking strip */
@@ -387,10 +418,11 @@ typedef struct bTheme {
ThemeSpace toops;
ThemeSpace ttime;
ThemeSpace tnode;
- ThemeSpace tlogic;
ThemeSpace tuserpref;
ThemeSpace tconsole;
ThemeSpace tclip;
+ ThemeSpace ttopbar;
+ ThemeSpace tstatusbar;
/* 20 sets of bone colors for this theme */
ThemeWireColor tarm[20];
@@ -414,8 +446,54 @@ typedef struct bPathCompare {
char flag, pad[7];
} bPathCompare;
+typedef struct bUserMenu {
+ struct bUserMenu *next, *prev;
+ char space_type;
+ char _pad0[7];
+ char context[64];
+ /* bUserMenuItem */
+ ListBase items;
+} bUserMenu;
+
+/* May be part of bUserMenu or other list. */
+typedef struct bUserMenuItem {
+ struct bUserMenuItem *next, *prev;
+ char ui_name[64];
+ char type;
+ char _pad0[7];
+} bUserMenuItem;
+
+typedef struct bUserMenuItem_Op {
+ bUserMenuItem item;
+ char op_idname[64];
+ struct IDProperty *prop;
+ char opcontext;
+ char _pad0[7];
+} bUserMenuItem_Op;
+
+typedef struct bUserMenuItem_Menu {
+ bUserMenuItem item;
+ char mt_idname[64];
+} bUserMenuItem_Menu;
+
+typedef struct bUserMenuItem_Prop {
+ bUserMenuItem item;
+ char context_data_path[256];
+ char prop_id[64];
+ int prop_index;
+ char _pad0[4];
+} bUserMenuItem_Prop;
+
+enum {
+ USER_MENU_TYPE_SEP = 1,
+ USER_MENU_TYPE_OPERATOR = 2,
+ USER_MENU_TYPE_MENU = 3,
+ USER_MENU_TYPE_PROP = 4,
+};
+
typedef struct SolidLight {
- int flag, pad;
+ int flag;
+ float smooth;
float col[4], spec[4], vec[4];
} SolidLight;
@@ -456,7 +534,7 @@ typedef struct UserDef {
short versions;
short dbl_click_time;
- short gameflags;
+ short pad;
short wheellinescroll;
int uiflag; /* eUserpref_UI_Flag */
int uiflag2; /* eUserpref_UI_Flag2 */
@@ -464,7 +542,9 @@ typedef struct UserDef {
* which are outside the scope of typical preferences. */
short app_flag;
short language;
- short userpref, viewzoom;
+ short userpref;
+ char userpref_flag;
+ char viewzoom;
int mixbufsize;
int audiodevice;
@@ -472,12 +552,16 @@ typedef struct UserDef {
int audioformat;
int audiochannels;
+ float ui_scale; /* setting for UI scale */
+ int ui_line_width; /* setting for UI line width */
+ int dpi; /* runtime, full DPI divided by pixelsize */
+ float dpi_fac; /* runtime, multiplier to scale UI elements based on DPI */
+ float pixelsize; /* runtime, line width and point size based on DPI */
+ int virtual_pixel; /* deprecated, for forward compatibility */
+
int scrollback; /* console scrollback limit */
- int dpi; /* range 48-128? */
- float ui_scale; /* interface scale */
- int ui_line_width; /* interface line width */
char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
- char pad2;
+ char pad2[5];
short transopts; /* eUserpref_Translation_Flags */
short menuthreshold1, menuthreshold2;
@@ -487,28 +571,32 @@ typedef struct UserDef {
struct ListBase themes;
struct ListBase uifonts;
struct ListBase uistyles;
- struct ListBase keymaps DNA_DEPRECATED; /* deprecated in favor of user_keymaps */
struct ListBase user_keymaps;
+ struct ListBase user_keyconfig_prefs; /* wmKeyConfigPref. */
struct ListBase addons;
struct ListBase autoexec_paths;
+ struct ListBase user_menus; /* bUserMenu */
+
char keyconfigstr[64];
short undosteps;
short pad1;
int undomemory;
- int pad3;
+ float gpu_viewport_quality;
short gp_manhattendist, gp_euclideandist, gp_eraser;
short gp_settings; /* eGP_UserdefSettings */
short tb_leftmouse, tb_rightmouse;
struct SolidLight light[3];
- short tw_hotspot, tw_flag, tw_handlesize, tw_size;
+ float light_ambient[3], pad7;
+ short gizmo_flag, gizmo_size;
+ short edit_solid_light;
+ short pad6[2];
short textimeout, texcollectrate;
- short wmdrawmethod; /* eWM_DrawMethod */
short dragthreshold;
int memcachelimit;
int prefetchframes;
float pad_rot_angle; /* control the rotation step of the view when PAD2, PAD4, PAD6&PAD8 is use */
- short frameserverport;
+ short _pad0;
short obcenter_dia;
short rvisize; /* rotating view icon size */
short rvibright; /* rotating view icon brightness */
@@ -521,18 +609,21 @@ typedef struct UserDef {
char keyhandles_new; /* handle types for newly added keyframes */
char gpu_select_method;
char gpu_select_pick_deph;
- char pad4;
+ char pad0;
char view_frame_type; /* eZoomFrame_Mode */
int view_frame_keyframes; /* number of keyframes to zoom around current frame */
float view_frame_seconds; /* seconds to zoom around current frame */
- char _pad0[4];
+ char _pad1[4];
short widget_unit; /* private, defaults to 20 for 72 DPI setting */
short anisotropic_filter;
short use_16bit_textures, use_gpu_mipmap;
+ float pressure_threshold_max; /* raw tablet pressure that maps to 100% */
+ float pressure_softness; /* curve non-linearity parameter */
+
float ndof_sensitivity; /* overall sensitivity of 3D mouse */
float ndof_orbit_sensitivity;
float ndof_deadzone; /* deadzone of 3D mouse */
@@ -556,7 +647,7 @@ typedef struct UserDef {
float gpencil_new_layer_col[4]; /* default color for newly created Grease Pencil layers */
short tweak_threshold;
- char navigation_mode, pad;
+ char navigation_mode, pad10;
char author[80]; /* author name for file formats supporting it */
@@ -567,8 +658,6 @@ typedef struct UserDef {
int compute_device_id;
float fcu_inactive_alpha; /* opacity of inactive F-Curves in F-Curve Editor */
- float pixelsize; /* private, set by GHOST, to multiply DPI with */
- int virtual_pixel; /* virtual pixelsize mode */
short pie_interaction_type; /* if keeping a pie menu spawn button pressed after this time, it turns into
* a drag/release pie menu */
@@ -582,31 +671,53 @@ typedef struct UserDef {
struct WalkNavigation walk_navigation;
short opensubdiv_compute_type;
- char pad5[6];
+ short gpencil_multisamples; /* eMultiSample_Type, amount of samples for Grease Pencil */
+
+ char pad5[4];
} UserDef;
extern UserDef U; /* from blenkernel blender.c */
/* ***************** USERDEF ****************** */
+/* Toggles for unfinished 2.8 UserPref design. */
+//#define WITH_USERDEF_WORKSPACES
+//#define WITH_USERDEF_SYSTEM_SPLIT
+
/* UserDef.userpref (UI active_section) */
typedef enum eUserPref_Section {
- USER_SECTION_INTERFACE = 0,
- USER_SECTION_EDIT = 1,
- USER_SECTION_FILE = 2,
- USER_SECTION_SYSTEM = 3,
- USER_SECTION_THEME = 4,
- USER_SECTION_INPUT = 5,
- USER_SECTION_ADDONS = 6,
+ USER_SECTION_INTERFACE = 0,
+ USER_SECTION_EDIT = 1,
+ USER_SECTION_SYSTEM_FILES = 2,
+ USER_SECTION_SYSTEM_GENERAL = 3,
+ USER_SECTION_THEME = 4,
+ USER_SECTION_INPUT = 5,
+ USER_SECTION_ADDONS = 6,
+ USER_SECTION_LIGHT = 7,
+#ifdef WITH_USERDEF_WORKSPACES
+ USER_SECTION_WORKSPACE_CONFIG = 8,
+ USER_SECTION_WORKSPACE_ADDONS = 9,
+ USER_SECTION_WORKSPACE_KEYMAPS = 10,
+#endif
+#ifdef WITH_USERDEF_SYSTEM_SPLIT
+ USER_SECTION_SYSTEM_DISPLAY = 11,
+ USER_SECTION_SYSTEM_DEVICES = 12,
+#endif
} eUserPref_Section;
+/* UserDef.userpref_flag (State of the user preferences UI). */
+typedef enum eUserPref_SectionFlag {
+ /* Hide/expand keymap preferences. */
+ USER_SECTION_INPUT_HIDE_UI_KEYCONFIG = (1 << 0),
+} eUserPref_SectionFlag;
+
/* UserDef.flag */
typedef enum eUserPref_Flag {
USER_AUTOSAVE = (1 << 0),
- USER_FLAG_DEPRECATED_1 = (1 << 1), /* cleared */
+ USER_FLAG_NUMINPUT_ADVANCED = (1 << 1),
USER_FLAG_DEPRECATED_2 = (1 << 2), /* cleared */
USER_FLAG_DEPRECATED_3 = (1 << 3), /* cleared */
- USER_SCENEGLOBAL = (1 << 4),
+/* USER_SCENEGLOBAL = (1 << 4), deprecated */
USER_TRACKBALL = (1 << 5),
USER_FLAG_DEPRECATED_6 = (1 << 6), /* cleared */
USER_FLAG_DEPRECATED_7 = (1 << 7), /* cleared */
@@ -616,7 +727,7 @@ typedef enum eUserPref_Flag {
USER_TOOLTIPS = (1 << 11),
USER_TWOBUTTONMOUSE = (1 << 12),
USER_NONUMPAD = (1 << 13),
- USER_LMOUSESELECT = (1 << 14),
+ USER_FLAG_DEPRECATED_14 = (1 << 14), /* cleared */
USER_FILECOMPRESS = (1 << 15),
USER_SAVE_PREVIEWS = (1 << 16),
USER_CUSTOM_RANGE = (1 << 17),
@@ -676,12 +787,12 @@ typedef enum eUserpref_UI_Flag {
USER_MENUOPENAUTO = (1 << 9),
USER_DEPTH_CURSOR = (1 << 10),
USER_AUTOPERSP = (1 << 11),
- USER_LOCKAROUND = (1 << 12),
+ /* USER_LOCKAROUND = (1 << 12), */ /* DEPRECATED */
USER_GLOBALUNDO = (1 << 13),
USER_ORBIT_SELECTION = (1 << 14),
USER_DEPTH_NAVIGATE = (1 << 15),
USER_HIDE_DOT = (1 << 16),
- USER_SHOW_ROTVIEWICON = (1 << 17),
+ USER_SHOW_GIZMO_AXIS = (1 << 17),
USER_SHOW_VIEWPORTNAME = (1 << 18),
USER_CAM_LOCK_NO_PARENT = (1 << 19),
USER_ZOOM_TO_MOUSEPOS = (1 << 20),
@@ -708,7 +819,6 @@ typedef enum eUserpref_UI_Flag2 {
/* UserDef.app_flag */
typedef enum eUserpref_APP_Flag {
USER_APP_LOCK_UI_LAYOUT = (1 << 0),
- USER_APP_VIEW3D_HIDE_CURSOR = (1 << 1),
} eUserpref_APP_Flag;
/* Auto-Keying mode.
@@ -743,6 +853,7 @@ typedef enum eAutokey_Flag {
/* toolsettings->autokey_flag */
AUTOKEY_FLAG_ONLYKEYINGSET = (1 << 6),
AUTOKEY_FLAG_NOWARNING = (1 << 7),
+ AUTOKEY_FLAG_CYCLEAWARE = (1 << 8),
ANIMRECORD_FLAG_WITHNLA = (1 << 10),
} eAutokey_Flag;
@@ -775,15 +886,6 @@ typedef enum eDupli_ID_Flags {
USER_DUP_PSYS = (1 << 11)
} eDupli_ID_Flags;
-/* UserDef.gameflags */
-typedef enum eOpenGL_RenderingOptions {
- USER_GL_RENDER_DEPRECATED_0 = (1 << 0),
- USER_GL_RENDER_DEPRECATED_1 = (1 << 1),
- USER_DISABLE_MIPMAP = (1 << 2),
- USER_GL_RENDER_DEPRECATED_3 = (1 << 3),
- USER_GL_RENDER_DEPRECATED_4 = (1 << 4),
-} eOpenGL_RenderingOptions;
-
/* selection method for opengl gpu_select_method */
typedef enum eOpenGL_SelectOptions {
USER_SELECT_AUTO = 0,
@@ -791,15 +893,12 @@ typedef enum eOpenGL_SelectOptions {
USER_SELECT_USE_SELECT_RENDERMODE = 2
} eOpenGL_SelectOptions;
-/* wm draw method.
- * UserDef.wmdrawmethod */
-typedef enum eWM_DrawMethod {
- USER_DRAW_TRIPLE = 0,
- USER_DRAW_OVERLAP = 1,
- USER_DRAW_FULL = 2,
- USER_DRAW_AUTOMATIC = 3,
- USER_DRAW_OVERLAP_FLIP = 4,
-} eWM_DrawMethod;
+/* max anti alias draw method UserDef.gpu_viewport_antialias */
+typedef enum eOpenGL_AntiAliasMethod {
+ USER_AA_NONE = 0,
+ USER_AA_FXAA = 1,
+ USER_AA_TAA8 = 2,
+} eOpenGL_AntiAliasMethod;
/* text draw options
* UserDef.text_render */
@@ -816,10 +915,14 @@ typedef enum eText_Draw_Options {
/* Grease Pencil Settings.
* UserDef.gp_settings */
typedef enum eGP_UserdefSettings {
- GP_PAINT_DOSMOOTH = (1 << 0),
- GP_PAINT_DOSIMPLIFY = (1 << 1),
+ GP_PAINT_DOSMOOTH = (1 << 0),
+ GP_PAINT_DOSIMPLIFY = (1 << 1),
} eGP_UserdefSettings;
+enum {
+ USER_GIZMO_DRAW = (1 << 0),
+};
+
/* Color Picker Types.
* UserDef.color_picker_type */
typedef enum eColorPicker_Types {
@@ -899,7 +1002,7 @@ typedef enum eNdof_Flag {
#define NDOF_PIXELS_PER_SECOND 600.0f
-/* UserDef.ogl_multisamples */
+/* UserDef.ogl_multisamples and gpencil_multisamples */
typedef enum eMultiSample_Type {
USER_MULTISAMPLE_NONE = 0,
USER_MULTISAMPLE_2 = 2,
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index 4132e17a249..e2d8d836368 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -64,6 +64,10 @@ typedef struct View2D {
int tab_num; /* number of tabs stored */
int tab_cur; /* current tab */
+ /* Usually set externally (as in, not in view2d files). */
+ char alpha_vert, alpha_hor; /* alpha of vertical and horizontal scrollbars (range is [0, 255]) */
+ short pad[3];
+
/* animated smooth view */
struct SmoothView2DStore *sms;
struct wmTimer *smooth_timer;
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 1b3eef0f3ec..79d2c230fdc 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -44,11 +44,12 @@ struct bGPdata;
struct SmoothView3DStore;
struct wmTimer;
struct Material;
-struct GPUFX;
+struct GPUViewport;
#include "DNA_defs.h"
#include "DNA_listBase.h"
#include "DNA_image_types.h"
+#include "DNA_object_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_gpu_types.h"
@@ -61,23 +62,6 @@ struct GPUFX;
# undef far
#endif
-/* Background Picture in 3D-View */
-typedef struct BGpic {
- struct BGpic *next, *prev;
-
- struct Image *ima;
- struct ImageUser iuser;
- struct MovieClip *clip;
- struct MovieClipUser cuser;
- float xof, yof, size, blend, rotation;
- short view;
- short flag;
- short source;
- char pad[6];
-} BGpic;
-
-/* ********************************* */
-
typedef struct RegionView3D {
float winmat[4][4]; /* GL_PROJECTION matrix */
@@ -106,8 +90,13 @@ typedef struct RegionView3D {
struct wmTimer *smooth_timer;
- /* transform widget matrix */
+ /* transform gizmo matrix */
float twmat[4][4];
+ /* min/max dot product on twmat xyz axis. */
+ float tw_axis_min[3], tw_axis_max[3];
+ float tw_axis_matrix[3][3];
+
+ float gridview DNA_DEPRECATED;
float viewquat[4]; /* view rotation, must be kept normalized */
float dist; /* distance from 'ofs' along -viewinv[2] vector, where result is negative as is 'ofs' */
@@ -125,7 +114,7 @@ typedef struct RegionView3D {
char pad[3];
float ofs_lock[2]; /* normalized offset for locked view: (-1, -1) bottom left, (1, 1) upper right */
- short twdrawflag;
+ short twdrawflag; /* XXX can easily get rid of this (Julian) */
short rflag;
@@ -133,17 +122,90 @@ typedef struct RegionView3D {
float lviewquat[4];
short lpersp, lview; /* lpersp can never be set to 'RV3D_CAMOB' */
- float gridview;
- float tw_idot[3]; /* manipulator runtime: (1 - dot) product with view vector (used to check view alignment) */
-
-
/* active rotation from NDOF or elsewhere */
float rot_angle;
float rot_axis[3];
-
- struct GPUFX *compositor;
} RegionView3D;
+typedef struct View3DCursor {
+ float location[3];
+ float rotation[4];
+ char _pad[4];
+} View3DCursor;
+
+/* 3D Viewport Shading settings */
+typedef struct View3DShading {
+ char type; /* Shading type (VIEW3D_SHADE_SOLID, ..) */
+ char prev_type; /* Runtime, for toggle between rendered viewport. */
+ char prev_type_wire;
+
+ char color_type;
+ short flag;
+
+ char light;
+ char background_type;
+ char cavity_type;
+ char pad[7];
+
+ char studio_light[256]; /* FILE_MAXFILE */
+ char lookdev_light[256]; /* FILE_MAXFILE */
+ char matcap[256]; /* FILE_MAXFILE */
+
+ float shadow_intensity;
+ float single_color[3];
+
+ float studiolight_rot_z;
+ float studiolight_background;
+
+ float object_outline_color[3];
+ float xray_alpha;
+ float xray_alpha_wire;
+
+ float cavity_valley_factor;
+ float cavity_ridge_factor;
+
+ float background_color[3];
+
+ float curvature_ridge_factor;
+ float curvature_valley_factor;
+
+} View3DShading;
+
+/* 3D Viewport Overlay settings */
+typedef struct View3DOverlay {
+ int flag;
+
+ /* Edit mode settings */
+ int edit_flag;
+ float normals_length;
+ float backwire_opacity;
+
+ /* Paint mode settings */
+ int paint_flag;
+
+ /* Weight paint mode settings */
+ int wpaint_flag;
+ char _pad2[4];
+
+ /* Alpha for texture, weight, vertex paint overlay */
+ float texture_paint_mode_opacity;
+ float vertex_paint_mode_opacity;
+ float weight_paint_mode_opacity;
+
+ /* Armature edit/pose mode settings */
+ int arm_flag;
+ float xray_alpha_bone;
+
+ /* Other settings */
+ float wireframe_threshold;
+
+ /* grease pencil settings */
+ float gpencil_paper_opacity;
+ float gpencil_grid_opacity;
+ float gpencil_fade_layer;
+
+} View3DOverlay;
+
/* 3D ViewPort Struct */
typedef struct View3D {
struct SpaceLink *next, *prev;
@@ -160,8 +222,11 @@ typedef struct View3D {
char bundle_drawtype; /* display style for bundle */
char pad[3];
- unsigned int lay_prev; /* for active layer toggle */
- unsigned int lay_used; /* used while drawing */
+ unsigned int lay_prev DNA_DEPRECATED; /* for active layer toggle */
+ unsigned int lay_used DNA_DEPRECATED; /* used while drawing */
+
+ int object_type_exclude_viewport;
+ int object_type_exclude_select;
short persp DNA_DEPRECATED;
short view DNA_DEPRECATED;
@@ -169,29 +234,25 @@ typedef struct View3D {
struct Object *camera, *ob_centre;
rctf render_border;
- struct ListBase bgpicbase;
- struct BGpic *bgpic DNA_DEPRECATED; /* deprecated, use bgpicbase, only kept for do_versions(...) */
-
struct View3D *localvd; /* allocated backup of its self while in localview */
char ob_centre_bone[64]; /* optional string for armature bone to define center, MAXBONENAME */
- unsigned int lay;
- int layact;
+ unsigned short local_view_uuid;
+ short _pad6;
+ int layact DNA_DEPRECATED;
- /**
- * The drawing mode for the 3d display. Set to OB_BOUNDBOX, OB_WIRE, OB_SOLID,
- * OB_TEXTURE, OB_MATERIAL or OB_RENDER */
- char drawtype;
- char ob_centre_cursor; /* optional bool for 3d cursor to define center */
- short scenelock, around;
+ short ob_centre_cursor; /* optional bool for 3d cursor to define center */
+ short scenelock;
+ short gp_flag;
short flag;
int flag2;
float lens, grid;
float near, far;
float ofs[3] DNA_DEPRECATED; /* XXX deprecated */
- float cursor[3];
+
+ char _pad[4];
short matcap_icon; /* icon id */
@@ -199,36 +260,30 @@ typedef struct View3D {
short gridsubdiv; /* Number of subdivisions in the grid between each highlighted grid line */
char gridflag;
- /* transform widget info */
- char twtype, twmode, twflag;
+ /* transform gizmo info */
+ char _pad5[2], gizmo_flag;
- short _pad1;
-
- /* afterdraw, for xray & transparent */
- struct ListBase afterdraw_transp;
- struct ListBase afterdraw_xray;
- struct ListBase afterdraw_xraytransp;
+ short _pad2;
/* drawflags, denoting state */
- char zbuf, transp, xray;
+ char _pad3;
+ char transp, xray;
char multiview_eye; /* multiview current eye - for internal use */
- /* built-in shader effects (eGPUFXFlags) */
- char pad3[4];
+ /* actually only used to define the opacity of the grease pencil vertex in edit mode */
+ float vertex_opacity;
/* note, 'fx_settings.dof' is currently _not_ allocated,
* instead set (temporarily) from camera */
struct GPUFXSettings fx_settings;
void *properties_storage; /* Nkey panel stores stuff here (runtime only!) */
- /* Allocated per view, not library data (used by matcap). */
- struct Material *defmaterial;
/* XXX deprecated? */
struct bGPdata *gpd DNA_DEPRECATED; /* Grease-Pencil Data (annotation layers) */
- /* multiview - stereo 3d */
+ /* Stereoscopy settings */
short stereo3d_flag;
char stereo3d_camera;
char pad4;
@@ -236,12 +291,12 @@ typedef struct View3D {
float stereo3d_volume_alpha;
float stereo3d_convergence_alpha;
- /* Previous viewport draw type.
- * Runtime-only, set in the rendered viewport toggle operator.
- */
- short prev_drawtype;
- short pad1;
- float pad2;
+ /* Display settings */
+ short drawtype DNA_DEPRECATED;
+ short pad5[3];
+
+ View3DShading shading;
+ View3DOverlay overlay;
} View3D;
@@ -251,14 +306,14 @@ typedef struct View3D {
#define V3D_S3D_DISPVOLUME (1 << 2)
/* View3D->flag (short) */
-/*#define V3D_DISPIMAGE 1*/ /*UNUSED*/
-#define V3D_DISPBGPICS 2
+/*#define V3D_FLAG_DEPRECATED_1 (1 << 0) */ /*UNUSED */
+/*#define V3D_FLAG_DEPRECATED_2 (1 << 1) */ /* UNUSED */
#define V3D_HIDE_HELPLINES 4
#define V3D_INVALID_BACKBUF 8
-#define V3D_ALIGN 1024
+/* #define V3D_FLAG_DEPRECATED_10 (1 << 10) */ /* UNUSED */
#define V3D_SELECT_OUTLINE 2048
-#define V3D_ZBUF_SELECT 4096
+#define V3D_ZBUF_SELECT 4096 /* XXX: DNA deprecated */
#define V3D_GLOBAL_STATS 8192
#define V3D_DRAW_CENTERS 32768
@@ -271,7 +326,7 @@ typedef struct View3D {
#define RV3D_CLIPPING 4
#define RV3D_NAVIGATING 8
#define RV3D_GPULIGHT_UPDATE 16
-#define RV3D_IS_GAME_ENGINE 32 /* runtime flag, used to check if LoD's should be used */
+/*#define RV3D_IS_GAME_ENGINE 32 *//* UNUSED */
/**
* Disable zbuffer offset, skip calls to #ED_view3d_polygon_offset.
* Use when precise surface depth is needed and picking bias isn't, see T45434).
@@ -301,7 +356,7 @@ typedef struct View3D {
/* View3d->flag2 (int) */
#define V3D_RENDER_OVERRIDE (1 << 2)
#define V3D_SOLID_TEX (1 << 3)
-#define V3D_SHOW_GPENCIL (1 << 4)
+#define V3D_SHOW_ANNOTATION (1 << 4)
#define V3D_LOCK_CAMERA (1 << 5)
#define V3D_RENDER_SHADOW (1 << 6) /* This is a runtime only flag that's used to tell draw_mesh_object() that we're doing a shadow pass instead of a regular draw */
#define V3D_SHOW_RECONSTRUCTION (1 << 7)
@@ -311,10 +366,122 @@ typedef struct View3D {
#define V3D_RENDER_BORDER (1 << 11)
#define V3D_SOLID_MATCAP (1 << 12) /* user flag */
#define V3D_SHOW_SOLID_MATCAP (1 << 13) /* runtime flag */
-#define V3D_OCCLUDE_WIRE (1 << 14)
-#define V3D_SHADELESS_TEX (1 << 15)
-#define V3D_SHOW_WORLD (1 << 16)
+#define V3D_OCCLUDE_WIRE (1 << 14) /* XXX: DNA deprecated */
+#define V3D_SHOW_MODE_SHADE_OVERRIDE (1 << 15) /* XXX: DNA deprecated */
+
+/* View3d->gp_flag (short) */
+#define V3D_GP_SHOW_PAPER (1 << 0) /* Activate paper to cover all viewport */
+#define V3D_GP_SHOW_GRID (1 << 1) /* Activate paper grid */
+#define V3D_GP_SHOW_EDIT_LINES (1 << 2)
+#define V3D_GP_SHOW_MULTIEDIT_LINES (1 << 3)
+#define V3D_GP_SHOW_ONION_SKIN (1 << 4) /* main switch at view level */
+#define V3D_GP_FADE_NOACTIVE_LAYERS (1 << 5) /* fade layers not active */
+
+/* View3DShading->light */
+enum {
+ V3D_LIGHTING_FLAT = 0,
+ V3D_LIGHTING_STUDIO = 1,
+ V3D_LIGHTING_MATCAP = 2,
+};
+/* View3DShading->flag */
+enum {
+ V3D_SHADING_OBJECT_OUTLINE = (1 << 0),
+ V3D_SHADING_XRAY = (1 << 1),
+ V3D_SHADING_SHADOW = (1 << 2),
+ V3D_SHADING_SCENE_LIGHTS = (1 << 3),
+ V3D_SHADING_SPECULAR_HIGHLIGHT = (1 << 4),
+ V3D_SHADING_CAVITY = (1 << 5),
+ V3D_SHADING_MATCAP_FLIP_X = (1 << 6),
+ V3D_SHADING_SCENE_WORLD = (1 << 7),
+ V3D_SHADING_XRAY_BONE = (1 << 8),
+ V3D_SHADING_WORLD_ORIENTATION = (1 << 9),
+};
+
+/* View3DShading->color_type */
+enum {
+ V3D_SHADING_MATERIAL_COLOR = 0,
+ V3D_SHADING_RANDOM_COLOR = 1,
+ V3D_SHADING_SINGLE_COLOR = 2,
+ V3D_SHADING_TEXTURE_COLOR = 3,
+};
+
+/* View3DShading->background_type */
+enum {
+ V3D_SHADING_BACKGROUND_THEME = 0,
+ V3D_SHADING_BACKGROUND_WORLD = 1,
+ V3D_SHADING_BACKGROUND_VIEWPORT = 2,
+};
+
+/* View3DShading->cavity_type */
+enum {
+ V3D_SHADING_CAVITY_SSAO = 0,
+ V3D_SHADING_CAVITY_CURVATURE = 1,
+ V3D_SHADING_CAVITY_BOTH = 2,
+};
+
+/* View3DOverlay->flag */
+enum {
+ V3D_OVERLAY_FACE_ORIENTATION = (1 << 0),
+ V3D_OVERLAY_HIDE_CURSOR = (1 << 1),
+ V3D_OVERLAY_BONE_SELECT = (1 << 2),
+ V3D_OVERLAY_LOOK_DEV = (1 << 3),
+ V3D_OVERLAY_WIREFRAMES = (1 << 4),
+ V3D_OVERLAY_HIDE_TEXT = (1 << 5),
+ V3D_OVERLAY_HIDE_MOTION_PATHS = (1 << 6),
+ V3D_OVERLAY_ONION_SKINS = (1 << 7),
+ V3D_OVERLAY_HIDE_BONES = (1 << 8),
+ V3D_OVERLAY_HIDE_OBJECT_XTRAS = (1 << 9),
+ V3D_OVERLAY_HIDE_OBJECT_ORIGINS = (1 << 10),
+};
+
+/* View3DOverlay->edit_flag */
+enum {
+ V3D_OVERLAY_EDIT_VERT_NORMALS = (1 << 0),
+ V3D_OVERLAY_EDIT_LOOP_NORMALS = (1 << 1),
+ V3D_OVERLAY_EDIT_FACE_NORMALS = (1 << 2),
+
+ V3D_OVERLAY_EDIT_OCCLUDE_WIRE = (1 << 3),
+
+ V3D_OVERLAY_EDIT_WEIGHT = (1 << 4),
+
+ V3D_OVERLAY_EDIT_EDGES = (1 << 5),
+ V3D_OVERLAY_EDIT_FACES = (1 << 6),
+ V3D_OVERLAY_EDIT_FACE_DOT = (1 << 7),
+
+ V3D_OVERLAY_EDIT_SEAMS = (1 << 8),
+ V3D_OVERLAY_EDIT_SHARP = (1 << 9),
+ V3D_OVERLAY_EDIT_CREASES = (1 << 10),
+ V3D_OVERLAY_EDIT_BWEIGHTS = (1 << 11),
+
+ V3D_OVERLAY_EDIT_FREESTYLE_EDGE = (1 << 12),
+ V3D_OVERLAY_EDIT_FREESTYLE_FACE = (1 << 13),
+
+ V3D_OVERLAY_EDIT_STATVIS = (1 << 14),
+ V3D_OVERLAY_EDIT_EDGE_LEN = (1 << 15),
+ V3D_OVERLAY_EDIT_EDGE_ANG = (1 << 16),
+ V3D_OVERLAY_EDIT_FACE_ANG = (1 << 17),
+ V3D_OVERLAY_EDIT_FACE_AREA = (1 << 18),
+ V3D_OVERLAY_EDIT_INDICES = (1 << 19),
+
+ V3D_OVERLAY_EDIT_CU_HANDLES = (1 << 20),
+ V3D_OVERLAY_EDIT_CU_NORMALS = (1 << 21),
+};
+
+/* View3DOverlay->arm_flag */
+enum {
+ V3D_OVERLAY_ARM_TRANSP_BONES = (1 << 0),
+};
+
+/* View3DOverlay->paint_flag */
+enum {
+ V3D_OVERLAY_PAINT_WIRE = (1 << 0),
+};
+
+/* View3DOverlay->wpaint_flag */
+enum {
+ V3D_OVERLAY_WPAINT_CONTOURS = (1 << 0),
+};
/* View3D->around */
enum {
@@ -346,49 +513,25 @@ enum {
#define V3D_SHOW_Y 4
#define V3D_SHOW_Z 8
-/* View3d->twtype (bits, we can combine them) */
-#define V3D_MANIP_TRANSLATE 1
-#define V3D_MANIP_ROTATE 2
-#define V3D_MANIP_SCALE 4
-
-/* View3d->twmode */
+/* Scene.orientation_type */
#define V3D_MANIP_GLOBAL 0
#define V3D_MANIP_LOCAL 1
#define V3D_MANIP_NORMAL 2
#define V3D_MANIP_VIEW 3
#define V3D_MANIP_GIMBAL 4
-#define V3D_MANIP_CUSTOM 5 /* anything of value 5 or higher is custom */
-
-/* View3d->twflag */
- /* USE = user setting, DRAW = based on selection */
-#define V3D_USE_MANIPULATOR 1
-#define V3D_DRAW_MANIPULATOR 2
-/* #define V3D_CALC_MANIPULATOR 4 */ /*UNUSED*/
+#define V3D_MANIP_CURSOR 5
+#define V3D_MANIP_CUSTOM_MATRIX (V3D_MANIP_CUSTOM - 1) /* Runtime only, never saved to DNA. */
+#define V3D_MANIP_CUSTOM 1024
-/* BGPic->flag */
-/* may want to use 1 for select ? */
+/* View3d.mpr_flag (also) */
enum {
- V3D_BGPIC_EXPANDED = (1 << 1),
- V3D_BGPIC_CAMERACLIP = (1 << 2),
- V3D_BGPIC_DISABLED = (1 << 3),
- V3D_BGPIC_FOREGROUND = (1 << 4),
-
- /* Camera framing options */
- V3D_BGPIC_CAMERA_ASPECT = (1 << 5), /* don't stretch to fit the camera view */
- V3D_BGPIC_CAMERA_CROP = (1 << 6), /* crop out the image */
-
- /* Axis flip options */
- V3D_BGPIC_FLIP_X = (1 << 7),
- V3D_BGPIC_FLIP_Y = (1 << 8),
+ /** All gizmos. */
+ V3D_GIZMO_HIDE = (1 << 0),
+ V3D_GIZMO_HIDE_NAVIGATE = (1 << 1),
+ V3D_GIZMO_HIDE_CONTEXT = (1 << 2),
+ V3D_GIZMO_HIDE_TOOL = (1 << 3),
};
-#define V3D_BGPIC_EXPANDED (V3D_BGPIC_EXPANDED | V3D_BGPIC_CAMERACLIP)
-
-/* BGPic->source */
-/* may want to use 1 for select ?*/
-#define V3D_BGPIC_IMAGE 0
-#define V3D_BGPIC_MOVIE 1
-
#define RV3D_CAMZOOM_MIN -30
#define RV3D_CAMZOOM_MAX 600
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index c76a447097e..1fdd4d10586 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -32,6 +32,7 @@
#define __DNA_WINDOWMANAGER_TYPES_H__
#include "DNA_listBase.h"
+#include "DNA_screen_types.h"
#include "DNA_vec_types.h"
#include "DNA_userdef_types.h"
@@ -41,6 +42,7 @@
struct wmWindowManager;
struct wmWindow;
+struct wmMsgBus;
struct wmEvent;
struct wmGesture;
struct wmOperatorType;
@@ -116,8 +118,7 @@ typedef struct ReportList {
#
#
typedef struct ReportTimerInfo {
- float col[3];
- float grayscale;
+ float col[4];
float widthfac;
} ReportTimerInfo;
@@ -159,14 +160,19 @@ typedef struct wmWindowManager {
char is_interface_locked; /* indicates whether interface is locked for user interaction */
char par[7];
+
+ struct wmMsgBus *message_bus;
+
} wmWindowManager;
/* wmWindowManager.initialized */
enum {
- WM_INIT_WINDOW = (1<<0),
- WM_INIT_KEYMAP = (1<<1),
+ WM_WINDOW_IS_INITIALIZED = (1<<0),
+ WM_KEYCONFIG_IS_INITIALIZED = (1<<1),
};
+#define WM_KEYCONFIG_STR_DEFAULT "blender"
+
/* IME is win32 only! */
#ifndef WIN32
# ifdef __GNUC__
@@ -179,10 +185,21 @@ typedef struct wmWindow {
struct wmWindow *next, *prev;
void *ghostwin; /* don't want to include ghost.h stuff */
+ void *gpuctx; /* don't want to include gpu stuff */
+
+ struct wmWindow *parent; /* Parent window */
+
+ struct Scene *scene; /* Active scene displayed in this window. */
+ struct Scene *new_scene; /* temporary when switching */
+ char view_layer_name[64]; /* Active view layer displayed in this window. */
- struct bScreen *screen; /* active screen */
- struct bScreen *newscreen; /* temporary when switching */
- char screenname[64]; /* MAX_ID_NAME for matching window with active screen after file read */
+ struct WorkSpaceInstanceHook *workspace_hook;
+
+ /** Global areas aren't part of the screen, but part of the window directly.
+ * \note Code assumes global areas with fixed height, fixed width not supported yet */
+ ScrAreaMap global_areas;
+
+ struct bScreen *screen DNA_DEPRECATED;
short posx, posy, sizex, sizey; /* window coords */
short windowstate; /* borderless, full */
@@ -193,8 +210,7 @@ typedef struct wmWindow {
short modalcursor; /* the current modal cursor */
short grabcursor; /* cursor grab mode */
short addmousemove; /* internal: tag this for extra mousemove event, makes cursors/buttons active on UI switching */
- short multisamples; /* amount of samples for OpenGL FSA the ghost window was created with, if zero no FSA */
- short pad[3];
+ short pad[4];
int winid; /* winid also in screens, is for retrieving this window after read */
@@ -204,28 +220,25 @@ typedef struct wmWindow {
struct wmEvent *eventstate; /* storage for event system */
- struct wmSubWindow *curswin; /* internal for wm_subwindow.c only */
-
struct wmGesture *tweak; /* internal for wm_operators.c */
/* Input Method Editor data - complex character input (esp. for asian character input)
* Currently WIN32, runtime-only data */
struct wmIMEData *ime_data;
- int drawmethod, drawfail; /* internal for wm_draw.c only */
- ListBase drawdata; /* internal for wm_draw.c only */
-
ListBase queue; /* all events (ghost level events were handled) */
ListBase handlers; /* window+screen handlers, handled last */
ListBase modalhandlers; /* priority handlers, handled first */
- ListBase subwindows; /* opengl stuff for sub windows, see notes in wm_subwindow.c */
ListBase gesture; /* gesture stuff */
struct Stereo3dFormat *stereo3d_format; /* properties for stereoscopic displays */
/* custom drawing callbacks */
ListBase drawcalls;
+
+ /* Private runtime info to show text in the status bar. */
+ void *cursor_keymap_status;
} wmWindow;
#ifdef ime_data
@@ -311,6 +324,7 @@ typedef struct wmKeyMap {
char idname[64]; /* global editor keymaps, or for more per space/region */
short spaceid; /* same IDs as in DNA_space_types.h */
short regionid; /* see above */
+ char owner_id[64]; /* optional, see: #wmOwnerID */
short flag; /* general flags */
short kmi_id; /* last kmi id */
@@ -318,6 +332,8 @@ typedef struct wmKeyMap {
/* runtime */
/** Verify if enabled in the current context, use #WM_keymap_poll instead of direct calls. */
bool (*poll)(struct bContext *);
+ bool (*poll_modal_item)(const struct wmOperator *op, int value);
+
/** For modal, #EnumPropertyItem for now. */
const void *modal_items;
} wmKeyMap;
@@ -331,8 +347,22 @@ enum {
KEYMAP_DIFF = (1 << 4), /* diff keymap for user preferences */
KEYMAP_USER_MODIFIED = (1 << 5), /* keymap has user modifications */
KEYMAP_UPDATE = (1 << 6),
+ KEYMAP_TOOL = (1 << 7), /* keymap for active tool system */
};
+/**
+ * This is similar to addon-preferences,
+ * however unlike add-ons key-config's aren't saved to disk.
+ *
+ * #wmKeyConfigPref is written to DNA,
+ * #wmKeyConfigPrefType_Runtime has the RNA type.
+ */
+typedef struct wmKeyConfigPref {
+ struct wmKeyConfigPref *next, *prev;
+ char idname[64]; /* unique name */
+ IDProperty *prop;
+} wmKeyConfigPref;
+
typedef struct wmKeyConfig {
struct wmKeyConfig *next, *prev;
@@ -340,13 +370,15 @@ typedef struct wmKeyConfig {
char basename[64]; /* idname of configuration this is derives from, "" if none */
ListBase keymaps;
- int actkeymap, flag;
+ int actkeymap;
+ short flag;
+ char _pad0[2];
} wmKeyConfig;
/* wmKeyConfig.flag */
enum {
KEYCONF_USER = (1 << 1), /* And what about (1 << 0)? */
- KEYCONF_INIT_DEFAULT = (1 << 2),
+ KEYCONF_INIT_DEFAULT = (1 << 2), /* Has default keymap been initialized? */
};
/* this one is the operator itself, stored in files for macros etc */
@@ -370,7 +402,6 @@ typedef struct wmOperator {
struct wmOperator *opm; /* current running macro, not saved */
struct uiLayout *layout; /* runtime for drawing */
short flag, pad[3];
-
} wmOperator;
/* operator type return flags: exec(), invoke() modal(), return values */
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
new file mode 100644
index 00000000000..3ad5071fdf2
--- /dev/null
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -0,0 +1,214 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file DNA_workspace_types.h
+ * \ingroup DNA
+ *
+ * Use API in BKE_workspace.h!
+ * Struct members marked with DNA_PRIVATE_WORKSPACE will throw a
+ * warning saying it's deprecated when used outside of workspace.c.
+ */
+
+#ifndef __DNA_WORKSPACE_TYPES_H__
+#define __DNA_WORKSPACE_TYPES_H__
+
+#include "DNA_scene_types.h"
+
+/* Same logic as DNA_DEPRECATED_ALLOW, but throws 'deprecated'
+ * warnings if DNA_PRIVATE_WORKSPACE_ALLOW is not defined */
+#ifdef DNA_PRIVATE_WORKSPACE_ALLOW
+ /* allow use of private items */
+# define DNA_PRIVATE_WORKSPACE
+#else
+# ifndef DNA_PRIVATE_WORKSPACE
+# define DNA_PRIVATE_WORKSPACE DNA_PRIVATE_ATTR
+# endif
+#endif
+
+#ifdef DNA_PRIVATE_READ_WRITE_ALLOW
+# define DNA_PRIVATE_WORKSPACE_READ_WRITE
+#else
+# ifndef DNA_PRIVATE_WORKSPACE_READ_WRITE
+# define DNA_PRIVATE_WORKSPACE_READ_WRITE DNA_PRIVATE_WORKSPACE
+# endif
+#endif
+
+/* Currently testing, allow to disable. */
+#define USE_WORKSPACE_TOOL
+
+#
+#
+typedef struct bToolRef_Runtime {
+ int cursor;
+
+ /** One of these 3 must be defined. */
+ char keymap[64];
+ char gizmo_group[64];
+ char data_block[64];
+
+ /** Use to infer primary operator to use when setting accelerator keys. */
+ char op[64];
+
+ /** Index when a tool is a member of a group. */
+ int index;
+} bToolRef_Runtime;
+
+
+/* Stored per mode. */
+typedef struct bToolRef {
+ struct bToolRef *next, *prev;
+ char idname[64];
+
+ /** Use to avoid initializing the same tool multiple times. */
+ short tag;
+
+ /** #bToolKey (spacetype, mode), used in 'WM_api.h' */
+ short space_type;
+ /**
+ * Value depends ont the 'space_type', object mode for 3D view, image editor has own mode too.
+ * RNA needs to handle using item function.
+ */
+ int mode;
+
+ /**
+ * Use for tool options, each group's name must match a tool name:
+ *
+ * {"Tool Name": {"SOME_OT_operator": {...}, ..}, ..}
+ *
+ * This is done since different tools may call the same operators with their own options.
+ */
+ IDProperty *properties;
+
+ /** Variables needed to operate the tool. */
+ bToolRef_Runtime *runtime;
+} bToolRef;
+
+
+/**
+ * \brief Wrapper for bScreen.
+ *
+ * bScreens are IDs and thus stored in a main list-base. We also want to store a list-base of them within the
+ * workspace (so each workspace can have its own set of screen-layouts) which would mess with the next/prev pointers.
+ * So we use this struct to wrap a bScreen pointer with another pair of next/prev pointers.
+ */
+typedef struct WorkSpaceLayout {
+ struct WorkSpaceLayout *next, *prev;
+
+ struct bScreen *screen;
+ /* The name of this layout, we override the RNA name of the screen with this (but not ID name itself) */
+ char name[64] DNA_PRIVATE_WORKSPACE; /* MAX_NAME */
+} WorkSpaceLayout;
+
+/** Optional tags, which features to use, aligned with #bAddon names by convention. */
+typedef struct wmOwnerID {
+ struct wmOwnerID *next, *prev;
+ char name[64] DNA_PRIVATE_WORKSPACE; /* MAX_NAME */
+} wmOwnerID;
+
+typedef struct WorkSpace {
+ ID id;
+
+ ListBase layouts DNA_PRIVATE_WORKSPACE; /* WorkSpaceLayout */
+ /* Store for each hook (so for each window) which layout has
+ * been activated the last time this workspace was visible. */
+ ListBase hook_layout_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */
+
+ /* Feature tagging (use for addons) */
+ ListBase owner_ids DNA_PRIVATE_WORKSPACE_READ_WRITE; /* wmOwnerID */
+
+ /* should be: '#ifdef USE_WORKSPACE_TOOL'. */
+
+ /** List of #bToolRef */
+ ListBase tools;
+
+ /**
+ * BAD DESIGN WARNING:
+ * This is a workaround for the topbar not knowing which tools spac */
+ char tools_space_type;
+ /** Type is different for each space-type. */
+ char tools_mode;
+ char _pad[2];
+
+ int object_mode;
+
+ int flags DNA_PRIVATE_WORKSPACE; /* enum eWorkSpaceFlags */
+
+ /* Number for workspace tab reordering in the UI. */
+ int order;
+
+ /* Info text from modal operators (runtime). */
+ char *status_text;
+} WorkSpace;
+
+/* internal struct, but exported for read/write */
+#if defined(DNA_PRIVATE_READ_WRITE_ALLOW) || defined(DNA_PRIVATE_WORKSPACE_ALLOW)
+
+/**
+ * Generic (and simple/primitive) struct for storing a history of assignments/relations
+ * of workspace data to non-workspace data in a listbase inside the workspace.
+ *
+ * Using this we can restore the old state of a workspace if the user switches back to it.
+ *
+ * Usage
+ * =====
+ * When activating a workspace, it should activate the screen-layout that was active in that
+ * workspace before *in this window*.
+ * More concretely:
+ * * There are two windows, win1 and win2.
+ * * Both show workspace ws1, but both also had workspace ws2 activated at some point before.
+ * * Last time ws2 was active in win1, screen-layout sl1 was activated.
+ * * Last time ws2 was active in win2, screen-layout sl2 was activated.
+ * * When changing from ws1 to ws2 in win1, screen-layout sl1 should be activated again.
+ * * When changing from ws1 to ws2 in win2, screen-layout sl2 should be activated again.
+ * So that means we have to store the active screen-layout in a per workspace, per window
+ * relation. This struct is used to store an active screen-layout for each window within the
+ * workspace.
+ * To find the screen-layout to activate for this window-workspace combination, simply lookup
+ * the WorkSpaceDataRelation with the workspace-hook of the window set as parent.
+ */
+typedef struct WorkSpaceDataRelation {
+ struct WorkSpaceDataRelation *next, *prev;
+
+ /* the data used to identify the relation (e.g. to find screen-layout (= value) from/for a hook) */
+ void *parent;
+ /* The value for this parent-data/workspace relation */
+ void *value;
+} WorkSpaceDataRelation;
+
+#endif /* DNA_PRIVATE_WORKSPACE_READ_WRITE */
+
+/**
+ * Little wrapper to store data that is going to be per window, but coming from the workspace.
+ * It allows us to keep workspace and window data completely separate.
+ */
+typedef struct WorkSpaceInstanceHook {
+ WorkSpace *active DNA_PRIVATE_WORKSPACE;
+ struct WorkSpaceLayout *act_layout DNA_PRIVATE_WORKSPACE;
+
+ /* Needed because we can't change workspaces/layouts in running handler loop, it would break context. */
+ WorkSpace *temp_workspace_store;
+ struct WorkSpaceLayout *temp_layout_store;
+} WorkSpaceInstanceHook;
+
+typedef enum eWorkSpaceFlags {
+ WORKSPACE_USE_FILTER_BY_ORIGIN = (1 << 1),
+} eWorkSpaceFlags;
+
+#endif /* __DNA_WORKSPACE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
index 0ae9bcd0256..7769833a835 100644
--- a/source/blender/makesdna/DNA_world_types.h
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -47,18 +47,16 @@ struct MTex;
/**
* World defines general modeling data such as a background fill,
- * gravity, color model etc. It mixes game-data, rendering
- * data and modeling data. */
+ * gravity, color model etc. It mixes rendering data and modeling data. */
typedef struct World {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
+ DrawDataList drawdata; /* runtime (must be immediately after id for utilities to use it). */
- short colormodel, totex;
+ char _pad0[4];
short texact, mistype;
float horr, horg, horb;
- float zenr, zeng, zenb;
- float ambr, ambg, ambb;
/**
* Exposure= mult factor. unused now, but maybe back later. Kept in to be upward compat.
@@ -69,57 +67,21 @@ typedef struct World {
float linfac, logfac;
/**
- * Gravitation constant for the game world
- */
- float gravity; // XXX moved to scene->gamedata in 2.5
-
- /**
- * Radius of the activity bubble, in Manhattan length. Objects
- * outside the box are activity-culled. */
- float activityBoxRadius; // XXX moved to scene->gamedata in 2.5
-
- short skytype;
- /**
* Some world modes
* bit 0: Do mist
- * bit 1: Do stars
- * bit 2: (reserved) depth of field
- * bit 3: (gameengine): Activity culling is enabled.
- * bit 4: ambient occlusion
- * bit 5: (gameengine) : enable Bullet DBVT tree for view frustum culling
*/
short mode; // partially moved to scene->gamedata in 2.5
- short occlusionRes; /* resolution of occlusion Z buffer in pixel */ // XXX moved to scene->gamedata in 2.5
- short physicsEngine; /* here it's aligned */ // XXX moved to scene->gamedata in 2.5
- short ticrate, maxlogicstep, physubstep, maxphystep; // XXX moved to scene->gamedata in 2.5
+ short pad2[3];
float misi, miststa, mistdist, misthi;
- float starr DNA_DEPRECATED, starg DNA_DEPRECATED, starb DNA_DEPRECATED, stark DNA_DEPRECATED; /* Deprecated */
- float starsize DNA_DEPRECATED, starmindist DNA_DEPRECATED;
- float stardist DNA_DEPRECATED, starcolnoise DNA_DEPRECATED;
-
- /* unused now: DOF */
- short dofsta, dofend, dofmin, dofmax;
-
/* ambient occlusion */
- float aodist, aodistfac, aoenergy, aobias;
- short aomode, aosamp, aomix, aocolor;
- float ao_adapt_thresh, ao_adapt_speed_fac;
- float ao_approx_error, ao_approx_correction;
- float ao_indirect_energy, ao_env_energy, ao_pad2;
- short ao_indirect_bounces, ao_pad;
- short ao_samp_method, ao_gather_method, ao_approx_passes;
-
- /* assorted settings (in the middle of ambient occlusion settings for padding reasons) */
- short flag;
-
- /* ambient occlusion (contd...) */
- float *aosphere, *aotables;
+ float aodist, aoenergy;
+ /* assorted settings */
+ short flag, pad3[3];
struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
- struct MTex *mtex[18]; /* MAX_MTEX */
short pr_texture, use_nodes, pad[2];
/* previews */
@@ -128,71 +90,28 @@ typedef struct World {
/* nodes */
struct bNodeTree *nodetree;
+ float mistend, pad1; /* runtime : miststa + mistdist, used for drawing camera */
ListBase gpumaterial; /* runtime */
} World;
/* **************** WORLD ********************* */
-/* skytype */
-#define WO_SKYBLEND 1
-#define WO_SKYREAL 2
-#define WO_SKYPAPER 4
-/* while render: */
-#define WO_SKYTEX 8
-#define WO_ZENUP 16
-
/* mode */
#define WO_MIST 1
//#define WO_STARS 2 /* deprecated */
/*#define WO_DOF 4*/
-#define WO_ACTIVITY_CULLING 8
-#define WO_ENV_LIGHT 16
-#define WO_DBVT_CULLING 32
+//#define WO_ACTIVITY_CULLING 8 /* deprecated */
+//#define WO_ENV_LIGHT 16
+//#define WO_DBVT_CULLING 32 /* deprecated */
#define WO_AMB_OCC 64
-#define WO_INDIRECT_LIGHT 128
+//#define WO_INDIRECT_LIGHT 128
-/* aomix */
enum {
- WO_AOADD = 0,
-#ifdef DNA_DEPRECATED
- WO_AOSUB = 1, /* deprecated */
- WO_AOADDSUB = 2, /* deprecated */
-#endif
- WO_AOMUL = 3,
+ WO_MIST_QUADRATIC = 0,
+ WO_MIST_LINEAR = 1,
+ WO_MIST_INVERSE_QUADRATIC = 2,
};
-/* ao_samp_method - methods for sampling the AO hemi */
-#define WO_AOSAMP_CONSTANT 0
-#define WO_AOSAMP_HALTON 1
-#define WO_AOSAMP_HAMMERSLEY 2
-
-/* aomode (use distances & random sampling modes) */
-#define WO_AODIST 1
-#define WO_AORNDSMP 2
-#define WO_AOCACHE 4
-
-/* aocolor */
-#define WO_AOPLAIN 0
-#define WO_AOSKYCOL 1
-#define WO_AOSKYTEX 2
-
-/* ao_gather_method */
-#define WO_AOGATHER_RAYTRACE 0
-#define WO_AOGATHER_APPROX 1
-
-/* texco (also in DNA_material_types.h) */
-#define TEXCO_ANGMAP 64
-#define TEXCO_H_SPHEREMAP 256
-#define TEXCO_H_TUBEMAP 1024
-#define TEXCO_EQUIRECTMAP 2048
-
-/* mapto */
-#define WOMAP_BLEND 1
-#define WOMAP_HORIZ 2
-#define WOMAP_ZENUP 4
-#define WOMAP_ZENDOWN 8
-// #define WOMAP_MIST 16 /* Deprecated */
-
/* flag */
#define WO_DS_EXPAND (1<<0)
/* NOTE: this must have the same value as MA_DS_SHOW_TEXS,
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 077bae741b8..2881f3138b2 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -313,10 +313,52 @@ BLI_INLINE const char *pad_up_4(const char *ptr)
}
/**
+ * Temporary DNA doversion for files that were created with Blender 2.80
+ * between October 2016, and November 2017 (>=280.0 and < 280.2).
+ *
+ * /note This would be way more efficient if we can get the version from SDNA
+ * So we could return true if version == 280 && subversion < 2.
+ *
+ * Returns true if we need to do the DNA renaming.
+ */
+static bool need_doversion_280(SDNA *sdna, int *data, const bool data_alloc)
+{
+ if (data_alloc == false) {
+ return false;
+ }
+
+ bool active_layer = false, render_layers = false;
+
+ const char *cp = (char *)data;
+ for (int nr = 0; nr < sdna->nr_names; nr++) {
+ if (strcmp(cp, "active_layer") == 0) {
+ active_layer = true;
+ if (active_layer && render_layers) {
+ return true;
+ }
+ }
+ else if (strcmp(cp, "render_layers") == 0) {
+ render_layers = true;
+ if (active_layer && render_layers) {
+ return true;
+ }
+ }
+
+ while (*cp) cp++;
+ cp++;
+ }
+
+ /* If someone adds only one of them to the DNA, don't! */
+ BLI_assert(!(active_layer || render_layers));
+ return false;
+}
+
+/**
* In sdna->data the data, now we convert that to something understandable
*/
static bool init_structDNA(
SDNA *sdna, bool do_endian_swap,
+ bool data_alloc,
const char **r_error_message)
{
int *data, *verg, gravity_fix = -1;
@@ -362,6 +404,10 @@ static bool init_structDNA(
return false;
}
+ /* Temporary DNA doversion for files that were created with Blender 2.80
+ * between 280.0 and 280.2. */
+ const bool doversion_280 = need_doversion_280(sdna, data, data_alloc);
+
cp = (char *)data;
for (int nr = 0; nr < sdna->nr_names; nr++) {
sdna->names[nr] = cp;
@@ -375,6 +421,28 @@ static bool init_structDNA(
gravity_fix = nr;
}
}
+ else if (doversion_280) {
+ if (strcmp(cp, "*render_layer") == 0) {
+ /* WorkSpace. */
+ sdna->names[nr] = "*view_layer";
+ }
+ else if (strcmp(cp, "*scene_layer") == 0) {
+ /* ParticleEditSettings. */
+ sdna->names[nr] = "*view_layer";
+ }
+ else if (strcmp(cp, "render_layers") == 0) {
+ /* Scene. */
+ sdna->names[nr] = "view_layers";
+ }
+ else if (strcmp(cp, "active_layer") == 0) {
+ /* Scene. */
+ sdna->names[nr] = "active_view_layer";
+ }
+ else if (strcmp(cp, "*cur_render_layer") == 0) {
+ /* FileGlobal. */
+ sdna->names[nr] = "*cur_view_layer";
+ }
+ }
while (*cp) cp++;
cp++;
@@ -408,9 +476,24 @@ static bool init_structDNA(
/* this is a patch, to change struct names without a conflict with SDNA */
/* be careful to use it, in this case for a system-struct (opengl/X) */
- if (*cp == 'b') {
- /* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */
- if (strcmp("bScreen", cp) == 0) sdna->types[nr] = cp + 1;
+ /* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */
+ if (strcmp("bScreen", cp) == 0) {
+ sdna->types[nr] = cp + 1;
+ }
+ /* Groups renamed to collections in 2.8 */
+ else if (strcmp("Collection", cp) == 0) {
+ sdna->types[nr] = "Group";
+ }
+ else if (strcmp("CollectionObject", cp) == 0) {
+ sdna->types[nr] = "GroupObject";
+ }
+ else if (doversion_280) {
+ if (strcmp(cp, "SceneLayer") == 0) {
+ sdna->types[nr] = "ViewLayer";
+ }
+ else if (strcmp(cp, "SceneLayerEngineData") == 0) {
+ sdna->types[nr] = "ViewLayerEngineData";
+ }
}
while (*cp) cp++;
@@ -554,7 +637,7 @@ SDNA *DNA_sdna_from_data(
sdna->data_alloc = data_alloc;
- if (init_structDNA(sdna, do_endian_swap, &error_message)) {
+ if (init_structDNA(sdna, do_endian_swap, data_alloc, &error_message)) {
return sdna;
}
else {
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 5d5efda975f..1905b69ebc5 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -100,12 +100,8 @@ static const char *includefiles[] = {
"DNA_sequence_types.h",
"DNA_effect_types.h",
"DNA_outliner_types.h",
- "DNA_property_types.h",
- "DNA_sensor_types.h",
- "DNA_controller_types.h",
- "DNA_actuator_types.h",
"DNA_sound_types.h",
- "DNA_group_types.h",
+ "DNA_collection_types.h",
"DNA_armature_types.h",
"DNA_action_types.h",
"DNA_constraint_types.h",
@@ -117,6 +113,8 @@ static const char *includefiles[] = {
"DNA_particle_types.h",
"DNA_cloth_types.h",
"DNA_gpencil_types.h",
+ "DNA_gpencil_modifier_types.h",
+ "DNA_shader_fx_types.h",
"DNA_windowmanager_types.h",
"DNA_anim_types.h",
"DNA_boid_types.h",
@@ -130,6 +128,10 @@ static const char *includefiles[] = {
"DNA_freestyle_types.h",
"DNA_linestyle_types.h",
"DNA_cachefile_types.h",
+ "DNA_layer_types.h",
+ "DNA_workspace_types.h",
+ "DNA_lightprobe_types.h",
+
/* see comment above before editing! */
/* empty string to indicate end of includefiles */
@@ -504,6 +506,17 @@ static int preprocess_include(char *maindata, int len)
a -= 13;
cp += 13;
}
+ else if (strncmp("DNA_PRIVATE_WORKSPACE", cp, 21) == 0) {
+ /* Check for DNA_PRIVATE_WORKSPACE_READ_WRITE */
+ if (strncmp("_READ_WRITE", cp + 21, 11) == 0) {
+ a -= 31;
+ cp += 31;
+ }
+ else {
+ a -= 20;
+ cp += 20;
+ }
+ }
else {
md[0] = cp[0];
md++;
@@ -1313,12 +1326,8 @@ int main(int argc, char **argv)
#include "DNA_sequence_types.h"
#include "DNA_effect_types.h"
#include "DNA_outliner_types.h"
-#include "DNA_property_types.h"
-#include "DNA_sensor_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_sound_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_armature_types.h"
#include "DNA_action_types.h"
#include "DNA_constraint_types.h"
@@ -1330,6 +1339,8 @@ int main(int argc, char **argv)
#include "DNA_particle_types.h"
#include "DNA_cloth_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_anim_types.h"
#include "DNA_boid_types.h"
@@ -1343,4 +1354,8 @@ int main(int argc, char **argv)
#include "DNA_freestyle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_cachefile_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_lightprobe_types.h"
+
/* end of list */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index de46605bc40..86f0f2d85bf 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -39,14 +39,18 @@ extern "C" {
struct bContext;
struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct ListBase;
struct Main;
struct ReportList;
struct Scene;
/* Types */
-
extern BlenderRNA BLENDER_RNA;
+
+/* Keep sorted. */
extern StructRNA RNA_Action;
extern StructRNA RNA_ActionConstraint;
extern StructRNA RNA_ActionFCurves;
@@ -66,14 +70,15 @@ extern StructRNA RNA_AnimVizMotionPaths;
extern StructRNA RNA_AnimVizOnionSkinning;
extern StructRNA RNA_AnyType;
extern StructRNA RNA_Area;
-extern StructRNA RNA_AreaLamp;
+extern StructRNA RNA_AreaLight;
extern StructRNA RNA_Armature;
+extern StructRNA RNA_ArmatureGpencilModifier;
extern StructRNA RNA_ArmatureModifier;
extern StructRNA RNA_ArmatureSensor;
+extern StructRNA RNA_ArrayGpencilModifier;
extern StructRNA RNA_ArrayModifier;
extern StructRNA RNA_BackgroundImage;
extern StructRNA RNA_BevelModifier;
-extern StructRNA RNA_SplinePoint;
extern StructRNA RNA_BezierSplinePoint;
extern StructRNA RNA_BlendData;
extern StructRNA RNA_BlendTexture;
@@ -89,13 +94,12 @@ extern StructRNA RNA_BoidSettings;
extern StructRNA RNA_BoidState;
extern StructRNA RNA_Bone;
extern StructRNA RNA_BoneGroup;
-extern StructRNA RNA_BooleanModifier;
extern StructRNA RNA_BoolProperty;
+extern StructRNA RNA_BooleanModifier;
extern StructRNA RNA_Brush;
extern StructRNA RNA_BrushTextureSlot;
+extern StructRNA RNA_BuildGpencilModifier;
extern StructRNA RNA_BuildModifier;
-extern StructRNA RNA_MeshCacheModifier;
-extern StructRNA RNA_MeshSequenceCacheModifier;
extern StructRNA RNA_CacheFile;
extern StructRNA RNA_Camera;
extern StructRNA RNA_CastModifier;
@@ -106,18 +110,21 @@ extern StructRNA RNA_ClothCollisionSettings;
extern StructRNA RNA_ClothModifier;
extern StructRNA RNA_ClothSettings;
extern StructRNA RNA_CloudsTexture;
+extern StructRNA RNA_Collection;
+extern StructRNA RNA_CollectionEngineSettings;
extern StructRNA RNA_CollectionProperty;
extern StructRNA RNA_CollisionModifier;
extern StructRNA RNA_CollisionSensor;
extern StructRNA RNA_CollisionSettings;
+extern StructRNA RNA_ColorGpencilModifier;
+extern StructRNA RNA_ColorManagedDisplaySettings;
extern StructRNA RNA_ColorManagedInputColorspaceSettings;
extern StructRNA RNA_ColorManagedSequencerColorspaceSettings;
-extern StructRNA RNA_ColorManagedDisplaySettings;
extern StructRNA RNA_ColorManagedViewSettings;
+extern StructRNA RNA_ColorMixSequence;
extern StructRNA RNA_ColorRamp;
extern StructRNA RNA_ColorRampElement;
extern StructRNA RNA_ColorSequence;
-extern StructRNA RNA_ColorMixSequence;
extern StructRNA RNA_CompositorNode;
extern StructRNA RNA_CompositorNodeAlphaOver;
extern StructRNA RNA_CompositorNodeBilateralblur;
@@ -142,24 +149,24 @@ extern StructRNA RNA_CompositorNodeDiffMatte;
extern StructRNA RNA_CompositorNodeDilateErode;
extern StructRNA RNA_CompositorNodeDisplace;
extern StructRNA RNA_CompositorNodeDistanceMatte;
+extern StructRNA RNA_CompositorNodeDoubleEdgeMask;
extern StructRNA RNA_CompositorNodeFilter;
extern StructRNA RNA_CompositorNodeFlip;
extern StructRNA RNA_CompositorNodeGamma;
extern StructRNA RNA_CompositorNodeGlare;
extern StructRNA RNA_CompositorNodeHueSat;
extern StructRNA RNA_CompositorNodeIDMask;
-extern StructRNA RNA_CompositorNodeDoubleEdgeMask;
extern StructRNA RNA_CompositorNodeImage;
extern StructRNA RNA_CompositorNodeInpaint;
extern StructRNA RNA_CompositorNodeInvert;
extern StructRNA RNA_CompositorNodeLensdist;
extern StructRNA RNA_CompositorNodeLevels;
extern StructRNA RNA_CompositorNodeLumaMatte;
+extern StructRNA RNA_CompositorNodeMapRange;
extern StructRNA RNA_CompositorNodeMapUV;
extern StructRNA RNA_CompositorNodeMapValue;
-extern StructRNA RNA_CompositorNodeMapRange;
-extern StructRNA RNA_CompositorNodeMath;
extern StructRNA RNA_CompositorNodeMask;
+extern StructRNA RNA_CompositorNodeMath;
extern StructRNA RNA_CompositorNodeMixRGB;
extern StructRNA RNA_CompositorNodeNormal;
extern StructRNA RNA_CompositorNodeNormalize;
@@ -191,6 +198,7 @@ extern StructRNA RNA_CompositorNodeZcombine;
extern StructRNA RNA_ConsoleLine;
extern StructRNA RNA_Constraint;
extern StructRNA RNA_ConstraintTarget;
+extern StructRNA RNA_ConstraintTargetBone;
extern StructRNA RNA_Context;
extern StructRNA RNA_ControlFluidSettings;
extern StructRNA RNA_Controller;
@@ -198,6 +206,7 @@ extern StructRNA RNA_CopyLocationConstraint;
extern StructRNA RNA_CopyRotationConstraint;
extern StructRNA RNA_CopyScaleConstraint;
extern StructRNA RNA_CopyTransformsConstraint;
+extern StructRNA RNA_CorrectiveSmoothModifier;
extern StructRNA RNA_Curve;
extern StructRNA RNA_CurveMap;
extern StructRNA RNA_CurveMapPoint;
@@ -208,7 +217,9 @@ extern StructRNA RNA_DampedTrackConstraint;
extern StructRNA RNA_DataTransferModifier;
extern StructRNA RNA_DecimateModifier;
extern StructRNA RNA_DelaySensor;
-extern StructRNA RNA_CorrectiveSmoothModifier;
+extern StructRNA RNA_Depsgraph;
+extern StructRNA RNA_DepsgraphObjectInstance;
+extern StructRNA RNA_DepsgraphUpdate;
extern StructRNA RNA_DisplaceModifier;
extern StructRNA RNA_DisplaySafeAreas;
extern StructRNA RNA_DistortedNoiseTexture;
@@ -217,7 +228,7 @@ extern StructRNA RNA_DopeSheet;
extern StructRNA RNA_Driver;
extern StructRNA RNA_DriverTarget;
extern StructRNA RNA_DriverVariable;
-extern StructRNA RNA_DupliObject;
+extern StructRNA RNA_DupliGpencilModifier;
extern StructRNA RNA_DynamicPaintBrushSettings;
extern StructRNA RNA_DynamicPaintCanvasSettings;
extern StructRNA RNA_DynamicPaintModifier;
@@ -228,8 +239,6 @@ extern StructRNA RNA_EffectSequence;
extern StructRNA RNA_EffectorWeights;
extern StructRNA RNA_EnumProperty;
extern StructRNA RNA_EnumPropertyItem;
-extern StructRNA RNA_EnvironmentMap;
-extern StructRNA RNA_EnvironmentMapTexture;
extern StructRNA RNA_Event;
extern StructRNA RNA_ExplodeModifier;
extern StructRNA RNA_ExpressionController;
@@ -246,6 +255,7 @@ extern StructRNA RNA_FModifierLimits;
extern StructRNA RNA_FModifierNoise;
extern StructRNA RNA_FModifierPython;
extern StructRNA RNA_FModifierStepped;
+extern StructRNA RNA_FaceMap;
extern StructRNA RNA_FieldSettings;
extern StructRNA RNA_FileBrowserFSMenuEntry;
extern StructRNA RNA_FileSelectParams;
@@ -255,38 +265,33 @@ extern StructRNA RNA_FluidFluidSettings;
extern StructRNA RNA_FluidSettings;
extern StructRNA RNA_FluidSimulationModifier;
extern StructRNA RNA_FollowPathConstraint;
-extern StructRNA RNA_FreestyleLineStyle;
extern StructRNA RNA_FreestyleLineSet;
+extern StructRNA RNA_FreestyleLineStyle;
extern StructRNA RNA_FreestyleModuleSettings;
extern StructRNA RNA_FreestyleSettings;
extern StructRNA RNA_Function;
extern StructRNA RNA_GPencilFrame;
-extern StructRNA RNA_GPencilLayer;
-extern StructRNA RNA_GPencilPalette;
-extern StructRNA RNA_GPencilPaletteColor;
-extern StructRNA RNA_GPencilBrush;
extern StructRNA RNA_GPencilInterpolateSettings;
+extern StructRNA RNA_GPencilLayer;
+extern StructRNA RNA_GPencilSculptBrush;
+extern StructRNA RNA_GPencilSculptSettings;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
-extern StructRNA RNA_GPencilSculptSettings;
-extern StructRNA RNA_GPencilSculptBrush;
-extern StructRNA RNA_GameBooleanProperty;
-extern StructRNA RNA_GameFloatProperty;
-extern StructRNA RNA_GameIntProperty;
-extern StructRNA RNA_GameObjectSettings;
-extern StructRNA RNA_GameProperty;
-extern StructRNA RNA_GameSoftBodySettings;
-extern StructRNA RNA_GameStringProperty;
-extern StructRNA RNA_GameTimerProperty;
extern StructRNA RNA_GaussianBlurSequence;
+extern StructRNA RNA_Gizmo;
+extern StructRNA RNA_GizmoGroupProperties;
+extern StructRNA RNA_GizmoProperties;
extern StructRNA RNA_GlowSequence;
+extern StructRNA RNA_GpencilModifier;
extern StructRNA RNA_GreasePencil;
-extern StructRNA RNA_Group;
extern StructRNA RNA_Header;
-extern StructRNA RNA_HemiLamp;
+extern StructRNA RNA_HemiLight;
extern StructRNA RNA_Histogram;
+extern StructRNA RNA_HookGpencilModifier;
extern StructRNA RNA_HookModifier;
extern StructRNA RNA_ID;
+extern StructRNA RNA_IDOverrideStatic;
+extern StructRNA RNA_IDOverrideStaticProperty;
extern StructRNA RNA_IKParam;
extern StructRNA RNA_Image;
extern StructRNA RNA_ImageFormatSettings;
@@ -302,6 +307,7 @@ extern StructRNA RNA_Itasc;
extern StructRNA RNA_JoystickSensor;
extern StructRNA RNA_Key;
extern StructRNA RNA_KeyConfig;
+extern StructRNA RNA_KeyConfigPreferences;
extern StructRNA RNA_KeyMap;
extern StructRNA RNA_KeyMapItem;
extern StructRNA RNA_KeyMapItems;
@@ -312,15 +318,18 @@ extern StructRNA RNA_KeyingSetInfo;
extern StructRNA RNA_KeyingSetPath;
extern StructRNA RNA_KeyingSetsAll;
extern StructRNA RNA_KinematicConstraint;
-extern StructRNA RNA_Lamp;
-extern StructRNA RNA_LampSkySettings;
-extern StructRNA RNA_LampTextureSlot;
extern StructRNA RNA_LaplacianDeformModifier;
extern StructRNA RNA_LaplacianSmoothModifier;
extern StructRNA RNA_Lattice;
+extern StructRNA RNA_LatticeGpencilModifier;
extern StructRNA RNA_LatticeModifier;
extern StructRNA RNA_LatticePoint;
+extern StructRNA RNA_LayerCollection;
extern StructRNA RNA_Library;
+extern StructRNA RNA_Light;
+extern StructRNA RNA_LightProbe;
+extern StructRNA RNA_LightSkySettings;
+extern StructRNA RNA_LightTextureSlot;
extern StructRNA RNA_LimitDistanceConstraint;
extern StructRNA RNA_LimitLocationConstraint;
extern StructRNA RNA_LimitRotationConstraint;
@@ -374,36 +383,31 @@ extern StructRNA RNA_LockedTrackConstraint;
extern StructRNA RNA_Macro;
extern StructRNA RNA_MagicTexture;
extern StructRNA RNA_MarbleTexture;
+extern StructRNA RNA_Mask;
+extern StructRNA RNA_MaskLayer;
extern StructRNA RNA_MaskModifier;
extern StructRNA RNA_MaskSequence;
extern StructRNA RNA_Material;
-extern StructRNA RNA_MaterialHalo;
-extern StructRNA RNA_MaterialPhysics;
extern StructRNA RNA_MaterialRaytraceMirror;
-extern StructRNA RNA_MaterialRaytraceTransparency;
extern StructRNA RNA_MaterialSlot;
-extern StructRNA RNA_MaterialStrand;
-extern StructRNA RNA_MaterialSubsurfaceScattering;
-extern StructRNA RNA_MaterialTextureSlot;
-extern StructRNA RNA_MaterialVolume;
-extern StructRNA RNA_Mask;
-extern StructRNA RNA_MaskLayer;
extern StructRNA RNA_Menu;
extern StructRNA RNA_Mesh;
+extern StructRNA RNA_MeshCacheModifier;
extern StructRNA RNA_MeshColor;
extern StructRNA RNA_MeshColorLayer;
-extern StructRNA RNA_MeshLoopColorLayer;
extern StructRNA RNA_MeshDeformModifier;
extern StructRNA RNA_MeshEdge;
-extern StructRNA RNA_MeshPolygon;
-extern StructRNA RNA_MeshTessFace;
-extern StructRNA RNA_MeshLoop;
extern StructRNA RNA_MeshFloatProperty;
extern StructRNA RNA_MeshFloatPropertyLayer;
extern StructRNA RNA_MeshIntProperty;
extern StructRNA RNA_MeshIntPropertyLayer;
-extern StructRNA RNA_MeshSkinVertexLayer;
+extern StructRNA RNA_MeshLoop;
+extern StructRNA RNA_MeshLoopColorLayer;
+extern StructRNA RNA_MeshLoopTriangle;
+extern StructRNA RNA_MeshPolygon;
+extern StructRNA RNA_MeshSequenceCacheModifier;
extern StructRNA RNA_MeshSkinVertex;
+extern StructRNA RNA_MeshSkinVertexLayer;
extern StructRNA RNA_MeshSticky;
extern StructRNA RNA_MeshStringProperty;
extern StructRNA RNA_MeshStringPropertyLayer;
@@ -416,17 +420,18 @@ extern StructRNA RNA_MessageSensor;
extern StructRNA RNA_MetaBall;
extern StructRNA RNA_MetaElement;
extern StructRNA RNA_MetaSequence;
+extern StructRNA RNA_MirrorGpencilModifier;
extern StructRNA RNA_MirrorModifier;
extern StructRNA RNA_Modifier;
extern StructRNA RNA_MotionPath;
extern StructRNA RNA_MotionPathVert;
extern StructRNA RNA_MouseSensor;
-extern StructRNA RNA_MovieSequence;
extern StructRNA RNA_MovieClipSequence;
+extern StructRNA RNA_MovieSequence;
extern StructRNA RNA_MovieTracking;
extern StructRNA RNA_MovieTrackingObject;
-extern StructRNA RNA_MovieTrackingTrack;
extern StructRNA RNA_MovieTrackingStabilization;
+extern StructRNA RNA_MovieTrackingTrack;
extern StructRNA RNA_MulticamSequence;
extern StructRNA RNA_MultiresModifier;
extern StructRNA RNA_MusgraveTexture;
@@ -435,32 +440,38 @@ extern StructRNA RNA_NearSensor;
extern StructRNA RNA_NlaStrip;
extern StructRNA RNA_NlaTrack;
extern StructRNA RNA_Node;
-extern StructRNA RNA_NodeOutputFileSlotFile;
-extern StructRNA RNA_NodeOutputFileSlotLayer;
extern StructRNA RNA_NodeInstanceHash;
extern StructRNA RNA_NodeLink;
+extern StructRNA RNA_NodeOutputFileSlotFile;
+extern StructRNA RNA_NodeOutputFileSlotLayer;
extern StructRNA RNA_NodeSocket;
extern StructRNA RNA_NodeSocketInterface;
extern StructRNA RNA_NodeTree;
+extern StructRNA RNA_NoiseGpencilModifier;
extern StructRNA RNA_NoiseTexture;
extern StructRNA RNA_NorController;
+extern StructRNA RNA_NormalEditModifier;
extern StructRNA RNA_Object;
extern StructRNA RNA_ObjectBase;
+extern StructRNA RNA_ObjectDisplay;
extern StructRNA RNA_ObstacleFluidSettings;
extern StructRNA RNA_OceanModifier;
extern StructRNA RNA_OceanTexData;
extern StructRNA RNA_OceanTexture;
+extern StructRNA RNA_OffsetGpencilModifier;
+extern StructRNA RNA_OpacityGpencilModifier;
extern StructRNA RNA_Operator;
extern StructRNA RNA_OperatorFileListElement;
+extern StructRNA RNA_OperatorMacro;
extern StructRNA RNA_OperatorMousePath;
extern StructRNA RNA_OperatorProperties;
extern StructRNA RNA_OperatorStrokeElement;
-extern StructRNA RNA_OperatorMacro;
extern StructRNA RNA_OrController;
extern StructRNA RNA_OutflowFluidSettings;
extern StructRNA RNA_PackedFile;
extern StructRNA RNA_Paint;
extern StructRNA RNA_PaintCurve;
+extern StructRNA RNA_PaintToolSlot;
extern StructRNA RNA_Palette;
extern StructRNA RNA_PaletteColor;
extern StructRNA RNA_Panel;
@@ -479,9 +490,7 @@ extern StructRNA RNA_ParticleSystemModifier;
extern StructRNA RNA_ParticleTarget;
extern StructRNA RNA_PivotConstraint;
extern StructRNA RNA_PointCache;
-extern StructRNA RNA_PointDensity;
-extern StructRNA RNA_PointDensityTexture;
-extern StructRNA RNA_PointLamp;
+extern StructRNA RNA_PointLight;
extern StructRNA RNA_PointerProperty;
extern StructRNA RNA_Pose;
extern StructRNA RNA_PoseBone;
@@ -496,19 +505,22 @@ extern StructRNA RNA_RandomSensor;
extern StructRNA RNA_RaySensor;
extern StructRNA RNA_Region;
extern StructRNA RNA_RenderEngine;
+extern StructRNA RNA_RenderEngineSettings;
+extern StructRNA RNA_RenderEngineSettingsClay;
extern StructRNA RNA_RenderLayer;
extern StructRNA RNA_RenderPass;
extern StructRNA RNA_RenderResult;
extern StructRNA RNA_RenderSettings;
-extern StructRNA RNA_RigidBodyWorld;
-extern StructRNA RNA_RigidBodyObject;
extern StructRNA RNA_RigidBodyJointConstraint;
+extern StructRNA RNA_RigidBodyObject;
+extern StructRNA RNA_RigidBodyWorld;
extern StructRNA RNA_SPHFluidSettings;
extern StructRNA RNA_Scene;
-extern StructRNA RNA_SceneGameData;
+extern StructRNA RNA_SceneDisplay;
+extern StructRNA RNA_SceneEEVEE;
+extern StructRNA RNA_SceneObjects;
extern StructRNA RNA_SceneRenderLayer;
extern StructRNA RNA_SceneSequence;
-extern StructRNA RNA_SceneObjects;
extern StructRNA RNA_Scopes;
extern StructRNA RNA_Screen;
extern StructRNA RNA_ScrewModifier;
@@ -517,32 +529,44 @@ extern StructRNA RNA_SelectedUvElement;
extern StructRNA RNA_Sensor;
extern StructRNA RNA_Sequence;
extern StructRNA RNA_SequenceColorBalance;
+extern StructRNA RNA_SequenceColorBalanceData;
extern StructRNA RNA_SequenceCrop;
extern StructRNA RNA_SequenceEditor;
extern StructRNA RNA_SequenceElement;
+extern StructRNA RNA_SequenceModifier;
extern StructRNA RNA_SequenceProxy;
extern StructRNA RNA_SequenceTransform;
-extern StructRNA RNA_NormalEditModifier;
+extern StructRNA RNA_ShaderFx;
+extern StructRNA RNA_ShaderFxBlur;
+extern StructRNA RNA_ShaderFxColorize;
+extern StructRNA RNA_ShaderFxFlip;
+extern StructRNA RNA_ShaderFxGlow;
+extern StructRNA RNA_ShaderFxLight;
+extern StructRNA RNA_ShaderFxPixel;
+extern StructRNA RNA_ShaderFxRim;
+extern StructRNA RNA_ShaderFxShadow;
+extern StructRNA RNA_ShaderFxSwirl;
+extern StructRNA RNA_ShaderFxWave;
extern StructRNA RNA_ShaderNode;
extern StructRNA RNA_ShaderNodeCameraData;
extern StructRNA RNA_ShaderNodeCombineRGB;
extern StructRNA RNA_ShaderNodeExtendedMaterial;
+extern StructRNA RNA_ShaderNodeGamma;
extern StructRNA RNA_ShaderNodeGeometry;
extern StructRNA RNA_ShaderNodeHueSaturation;
extern StructRNA RNA_ShaderNodeIESLight;
extern StructRNA RNA_ShaderNodeInvert;
-extern StructRNA RNA_ShaderNodeLampData;
+extern StructRNA RNA_ShaderNodeLightData;
extern StructRNA RNA_ShaderNodeMapping;
extern StructRNA RNA_ShaderNodeMaterial;
extern StructRNA RNA_ShaderNodeMath;
extern StructRNA RNA_ShaderNodeMixRGB;
extern StructRNA RNA_ShaderNodeNormal;
-extern StructRNA RNA_ShaderNodeGamma;
extern StructRNA RNA_ShaderNodeOutput;
-extern StructRNA RNA_ShaderNodeScript;
extern StructRNA RNA_ShaderNodeRGB;
extern StructRNA RNA_ShaderNodeRGBCurve;
extern StructRNA RNA_ShaderNodeRGBToBW;
+extern StructRNA RNA_ShaderNodeScript;
extern StructRNA RNA_ShaderNodeSeparateRGB;
extern StructRNA RNA_ShaderNodeSqueeze;
extern StructRNA RNA_ShaderNodeTexture;
@@ -558,11 +582,13 @@ extern StructRNA RNA_ShapeKeyPoint;
extern StructRNA RNA_ShrinkwrapConstraint;
extern StructRNA RNA_ShrinkwrapModifier;
extern StructRNA RNA_SimpleDeformModifier;
+extern StructRNA RNA_SimplifyGpencilModifier;
extern StructRNA RNA_SkinModifier;
extern StructRNA RNA_SmokeCollSettings;
extern StructRNA RNA_SmokeDomainSettings;
extern StructRNA RNA_SmokeFlowSettings;
extern StructRNA RNA_SmokeModifier;
+extern StructRNA RNA_SmoothGpencilModifier;
extern StructRNA RNA_SmoothModifier;
extern StructRNA RNA_SoftBodyModifier;
extern StructRNA RNA_SoftBodySettings;
@@ -570,36 +596,37 @@ extern StructRNA RNA_SolidifyModifier;
extern StructRNA RNA_Sound;
extern StructRNA RNA_SoundSequence;
extern StructRNA RNA_Space;
+extern StructRNA RNA_SpaceClipEditor;
extern StructRNA RNA_SpaceConsole;
extern StructRNA RNA_SpaceDopeSheetEditor;
extern StructRNA RNA_SpaceFileBrowser;
extern StructRNA RNA_SpaceGraphEditor;
extern StructRNA RNA_SpaceImageEditor;
extern StructRNA RNA_SpaceInfo;
-extern StructRNA RNA_SpaceLogicEditor;
extern StructRNA RNA_SpaceNLA;
extern StructRNA RNA_SpaceNodeEditor;
extern StructRNA RNA_SpaceOutliner;
extern StructRNA RNA_SpaceProperties;
extern StructRNA RNA_SpaceSequenceEditor;
extern StructRNA RNA_SpaceTextEditor;
-extern StructRNA RNA_SpaceTimeline;
extern StructRNA RNA_SpaceUVEditor;
extern StructRNA RNA_SpaceUserPreferences;
extern StructRNA RNA_SpaceView3D;
-extern StructRNA RNA_SpaceClipEditor;
extern StructRNA RNA_Speaker;
extern StructRNA RNA_SpeedControlSequence;
extern StructRNA RNA_Spline;
extern StructRNA RNA_SplineIKConstraint;
-extern StructRNA RNA_SpotLamp;
+extern StructRNA RNA_SplinePoint;
+extern StructRNA RNA_SpotLight;
extern StructRNA RNA_Stereo3dDisplay;
extern StructRNA RNA_StretchToConstraint;
extern StructRNA RNA_StringProperty;
extern StructRNA RNA_Struct;
extern StructRNA RNA_StucciTexture;
+extern StructRNA RNA_StudioLight;
+extern StructRNA RNA_SubdivGpencilModifier;
extern StructRNA RNA_SubsurfModifier;
-extern StructRNA RNA_SunLamp;
+extern StructRNA RNA_SunLight;
extern StructRNA RNA_SurfaceCurve;
extern StructRNA RNA_SurfaceDeformModifier;
extern StructRNA RNA_SurfaceModifier;
@@ -609,6 +636,7 @@ extern StructRNA RNA_TextBox;
extern StructRNA RNA_TextCharacterFormat;
extern StructRNA RNA_TextCurve;
extern StructRNA RNA_TextLine;
+extern StructRNA RNA_TextSequence;
extern StructRNA RNA_Texture;
extern StructRNA RNA_TextureNode;
extern StructRNA RNA_TextureNodeBricks;
@@ -651,20 +679,21 @@ extern StructRNA RNA_ThemeNodeEditor;
extern StructRNA RNA_ThemeOutliner;
extern StructRNA RNA_ThemeProperties;
extern StructRNA RNA_ThemeSequenceEditor;
-extern StructRNA RNA_TextSequence;
extern StructRNA RNA_ThemeSpaceGeneric;
extern StructRNA RNA_ThemeSpaceGradient;
extern StructRNA RNA_ThemeSpaceListGeneric;
extern StructRNA RNA_ThemeStyle;
extern StructRNA RNA_ThemeTextEditor;
-extern StructRNA RNA_ThemeTimeline;
extern StructRNA RNA_ThemeUserInterface;
extern StructRNA RNA_ThemeUserPreferences;
extern StructRNA RNA_ThemeView3D;
extern StructRNA RNA_ThemeWidgetColors;
extern StructRNA RNA_ThemeWidgetStateColors;
+extern StructRNA RNA_ThickGpencilModifier;
+extern StructRNA RNA_TimeGpencilModifier;
extern StructRNA RNA_TimelineMarker;
extern StructRNA RNA_Timer;
+extern StructRNA RNA_TintGpencilModifier;
extern StructRNA RNA_ToolSettings;
extern StructRNA RNA_TrackToConstraint;
extern StructRNA RNA_TransformConstraint;
@@ -673,9 +702,9 @@ extern StructRNA RNA_UILayout;
extern StructRNA RNA_UIList;
extern StructRNA RNA_UIPieMenu;
extern StructRNA RNA_UIPopupMenu;
-extern StructRNA RNA_UVWarpModifier;
extern StructRNA RNA_UVProjectModifier;
extern StructRNA RNA_UVProjector;
+extern StructRNA RNA_UVWarpModifier;
extern StructRNA RNA_UnitSettings;
extern StructRNA RNA_UnknownType;
extern StructRNA RNA_UserPreferences;
@@ -690,19 +719,22 @@ extern StructRNA RNA_VectorFont;
extern StructRNA RNA_VertexGroup;
extern StructRNA RNA_VertexGroupElement;
extern StructRNA RNA_VertexPaint;
-extern StructRNA RNA_VoronoiTexture;
-extern StructRNA RNA_VoxelData;
-extern StructRNA RNA_VoxelDataTexture;
-extern StructRNA RNA_WarpModifier;
-extern StructRNA RNA_WaveModifier;
extern StructRNA RNA_VertexWeightEditModifier;
extern StructRNA RNA_VertexWeightMixModifier;
extern StructRNA RNA_VertexWeightProximityModifier;
+extern StructRNA RNA_View3DOverlay;
+extern StructRNA RNA_View3DShading;
+extern StructRNA RNA_ViewLayer;
+extern StructRNA RNA_VoronoiTexture;
+extern StructRNA RNA_WarpModifier;
+extern StructRNA RNA_WaveModifier;
+extern StructRNA RNA_WeightedNormalModifier;
extern StructRNA RNA_Window;
extern StructRNA RNA_WindowManager;
extern StructRNA RNA_WipeSequence;
extern StructRNA RNA_WireframeModifier;
extern StructRNA RNA_WoodTexture;
+extern StructRNA RNA_WorkSpace;
extern StructRNA RNA_World;
extern StructRNA RNA_WorldAmbientOcclusion;
extern StructRNA RNA_WorldLighting;
@@ -710,6 +742,8 @@ extern StructRNA RNA_WorldMistSettings;
extern StructRNA RNA_WorldTextureSlot;
extern StructRNA RNA_XnorController;
extern StructRNA RNA_XorController;
+extern StructRNA RNA_uiPopover;
+extern StructRNA RNA_wmOwnerIDs;
/* Pointer
*
@@ -807,6 +841,7 @@ PropertyType RNA_property_type(PropertyRNA *prop);
PropertySubType RNA_property_subtype(PropertyRNA *prop);
PropertyUnit RNA_property_unit(PropertyRNA *prop);
int RNA_property_flag(PropertyRNA *prop);
+int RNA_property_override_flag(PropertyRNA *prop);
int RNA_property_tags(PropertyRNA *prop);
bool RNA_property_builtin(PropertyRNA *prop);
void *RNA_property_py_data_get(PropertyRNA *prop);
@@ -844,6 +879,7 @@ bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r
bool RNA_enum_description(const EnumPropertyItem *item, const int value, const char **description);
int RNA_enum_from_value(const EnumPropertyItem *item, const int value);
int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifier);
+int RNA_enum_from_name(const EnumPropertyItem *item, const char *name);
unsigned int RNA_enum_items_count(const EnumPropertyItem *item);
void RNA_property_enum_items_ex(
@@ -881,6 +917,10 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index);
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop); /* without lib check, only checks the flag */
bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop);
+bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop);
+bool RNA_property_overridable_static_set(PointerRNA *ptr, PropertyRNA *prop, const bool is_overridable);
+bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop);
+bool RNA_property_comparable(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop); /* slow, use with care */
void RNA_property_update(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop);
@@ -972,7 +1012,7 @@ void RNA_property_collection_clear(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_collection_move(PointerRNA *ptr, PropertyRNA *prop, int key, int pos);
/* copy/reset */
-bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index);
+bool RNA_property_copy(struct Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index);
bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index);
/* Path
@@ -1002,6 +1042,16 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path,
bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path,
PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+/* path_resolve_property_and_item_pointer() variants ensure that pointer + property both exist,
+ * and resolve last Pointer value if possible (Pointer prop or item of a Collection prop). */
+bool RNA_path_resolve_property_and_item_pointer(
+ PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop,
+ PointerRNA *r_item_ptr);
+
+bool RNA_path_resolve_property_and_item_pointer_full(
+ PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index,
+ PointerRNA *r_item_ptr);
+
typedef struct PropertyElemRNA PropertyElemRNA;
struct PropertyElemRNA {
PropertyElemRNA *next, *prev;
@@ -1224,17 +1274,84 @@ StructRNA *ID_code_to_RNA_type(short idcode);
void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2);
-/* Equals test (skips pointers and collections)
- * is_strict false assumes uninitialized properties are equal */
-
-typedef enum eRNAEqualsMode {
- RNA_EQ_STRICT, /* set/unset ignored */
- RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */
- RNA_EQ_UNSET_MATCH_NONE /* unset property never matches set property */
-} eRNAEqualsMode;
+/* Equals test. */
+
+/* Note: In practice, EQ_STRICT and EQ_COMPARE have same behavior currently, and will yield same result. */
+typedef enum eRNACompareMode {
+ /* Only care about equality, not full comparison. */
+ RNA_EQ_STRICT, /* set/unset ignored */
+ RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */
+ RNA_EQ_UNSET_MATCH_NONE, /* unset property never matches set property */
+ /* Full comparison. */
+ RNA_EQ_COMPARE,
+} eRNACompareMode;
+
+bool RNA_property_equals(
+ struct Main *bmain,
+ struct PointerRNA *ptr_a, struct PointerRNA *ptr_b, struct PropertyRNA *prop, eRNACompareMode mode);
+bool RNA_struct_equals(
+ struct Main *bmain,
+ struct PointerRNA *ptr_a, struct PointerRNA *ptr_b, eRNACompareMode mode);
+
+/* Override. */
+
+/* flags for RNA_struct_override_matches. */
+typedef enum eRNAOverrideMatch {
+ /* Do not compare properties that are not overridable. */
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0,
+ /* Do not compare properties that are already overridden. */
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1,
+
+ /* Create new property override if needed and possible. */
+ RNA_OVERRIDE_COMPARE_CREATE = 1 << 16,
+ /* Restore property's value(s) to reference ones if needed and possible. */
+ RNA_OVERRIDE_COMPARE_RESTORE = 1 << 17,
+} eRNAOverrideMatch;
+
+typedef enum eRNAOverrideMatchResult {
+ /* Some new property overrides were created to take into account differences between local and reference. */
+ RNA_OVERRIDE_MATCH_RESULT_CREATED = 1 << 0,
+ /* Some properties were reset to reference values. */
+ RNA_OVERRIDE_MATCH_RESULT_RESTORED = 1 << 1,
+} eRNAOverrideMatchResult;
+
+typedef enum eRNAOverrideStatus {
+ RNA_OVERRIDE_STATUS_OVERRIDABLE = 1 << 0, /* The property is overridable. */
+ RNA_OVERRIDE_STATUS_OVERRIDDEN = 1 << 1, /* The property is overridden. */
+ RNA_OVERRIDE_STATUS_MANDATORY = 1 << 2, /* Overriding this property is mandatory when creating an override. */
+ RNA_OVERRIDE_STATUS_LOCKED = 1 << 3, /* The override status of this property is locked. */
+} eRNAOverrideStatus;
+
+bool RNA_struct_override_matches(
+ struct Main *bmain,
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, const char *root_path,
+ struct IDOverrideStatic *override, const eRNAOverrideMatch flags,
+ eRNAOverrideMatchResult *r_report_flags);
+
+bool RNA_struct_override_store(
+ struct Main *bmain,
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ struct IDOverrideStatic *override);
+
+void RNA_struct_override_apply(
+ struct Main *bmain,
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_override, struct PointerRNA *ptr_storage,
+ struct IDOverrideStatic *override);
+
+struct IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop);
+struct IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created);
+
+struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find(
+ PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict);
+struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
+ PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
+ const bool strict, bool *r_strict, bool *r_created);
+
+eRNAOverrideStatus RNA_property_static_override_status(PointerRNA *ptr, PropertyRNA *prop, const int index);
+
+void RNA_struct_state_owner_set(const char *name);
+const char *RNA_struct_state_owner_get(void);
-bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNAEqualsMode mode);
-bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNAEqualsMode mode);
#ifdef __cplusplus
}
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 97266028f06..e14dcbea09e 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -39,6 +39,14 @@
extern "C" {
#endif
+#ifdef UNIT_TEST
+#define RNA_MAX_ARRAY_LENGTH 64
+#else
+#define RNA_MAX_ARRAY_LENGTH 32
+#endif
+
+#define RNA_MAX_ARRAY_DIMENSION 3
+
/* Blender RNA */
BlenderRNA *RNA_create(void);
@@ -143,6 +151,8 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop, const char *structname,
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag);
+void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
+void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
void RNA_def_property_tags(PropertyRNA *prop, int tags);
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype);
void RNA_def_property_array(PropertyRNA *prop, int length);
@@ -165,12 +175,14 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value);
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description);
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision);
-void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, bool consecutive);
+void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, int consecutive);
void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *updatefunc);
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
+void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply);
+
void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func);
void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 64740098db4..bf6e1d28cb2 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -43,7 +43,9 @@ extern const EnumPropertyItem DummyRNA_DEFAULT_items[];
extern const EnumPropertyItem rna_enum_id_type_items[];
extern const EnumPropertyItem rna_enum_object_mode_items[];
+extern const EnumPropertyItem rna_enum_workspace_object_mode_items[];
extern const EnumPropertyItem rna_enum_object_empty_drawtype_items[];
+extern const EnumPropertyItem rna_enum_object_gpencil_type_items[];
extern const EnumPropertyItem rna_enum_metaelem_type_items[];
extern const EnumPropertyItem rna_enum_proportional_falloff_items[];
@@ -54,16 +56,23 @@ extern const EnumPropertyItem rna_enum_snap_element_items[];
extern const EnumPropertyItem rna_enum_snap_node_element_items[];
extern const EnumPropertyItem rna_enum_curve_fit_method_items[];
extern const EnumPropertyItem rna_enum_mesh_select_mode_items[];
+extern const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[];
extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
+extern const EnumPropertyItem rna_enum_space_graph_mode_items[];
extern const EnumPropertyItem rna_enum_space_type_items[];
+extern const EnumPropertyItem rna_enum_space_image_mode_items[];
+extern const EnumPropertyItem rna_enum_space_action_mode_items[];
extern const EnumPropertyItem rna_enum_region_type_items[];
extern const EnumPropertyItem rna_enum_object_modifier_type_items[];
extern const EnumPropertyItem rna_enum_constraint_type_items[];
extern const EnumPropertyItem rna_enum_boidrule_type_items[];
extern const EnumPropertyItem rna_enum_sequence_modifier_type_items[];
+extern const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[];
+extern const EnumPropertyItem rna_enum_object_shaderfx_type_items[];
extern const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[];
extern const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[];
+extern const EnumPropertyItem rna_enum_modifier_shrinkwrap_mode_items[];
extern const EnumPropertyItem rna_enum_image_type_items[];
extern const EnumPropertyItem rna_enum_image_color_mode_items[];
@@ -107,14 +116,18 @@ extern const EnumPropertyItem rna_enum_motionpath_bake_location_items[];
extern const EnumPropertyItem rna_enum_event_value_items[];
extern const EnumPropertyItem rna_enum_event_type_items[];
extern const EnumPropertyItem rna_enum_operator_return_items[];
+extern const EnumPropertyItem rna_enum_operator_property_tags[];
extern const EnumPropertyItem rna_enum_brush_sculpt_tool_items[];
extern const EnumPropertyItem rna_enum_brush_vertex_tool_items[];
+extern const EnumPropertyItem rna_enum_brush_weight_tool_items[];
+extern const EnumPropertyItem rna_enum_brush_gpencil_types_items[];
extern const EnumPropertyItem rna_enum_brush_image_tool_items[];
extern const EnumPropertyItem rna_enum_particle_edit_hair_brush_items[];
extern const EnumPropertyItem rna_enum_particle_edit_disconnected_hair_brush_items[];
extern const EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[];
+extern const EnumPropertyItem rna_enum_gpencil_weight_brush_items[];
extern const EnumPropertyItem rna_enum_uv_sculpt_tool_items[];
@@ -127,7 +140,7 @@ extern const EnumPropertyItem rna_enum_symmetrize_direction_items[];
extern const EnumPropertyItem rna_enum_texture_type_items[];
-extern const EnumPropertyItem rna_enum_lamp_type_items[];
+extern const EnumPropertyItem rna_enum_light_type_items[];
extern const EnumPropertyItem rna_enum_unpack_method_items[];
@@ -155,6 +168,8 @@ extern const EnumPropertyItem rna_enum_operator_context_items[];
extern const EnumPropertyItem rna_enum_wm_report_items[];
+extern const EnumPropertyItem rna_enum_transform_pivot_items_full[];
+extern const EnumPropertyItem rna_enum_transform_orientation_items[];
extern const EnumPropertyItem rna_enum_transform_mode_types[];
extern const EnumPropertyItem rna_enum_posebone_rotmode_items[];
@@ -163,16 +178,13 @@ extern const EnumPropertyItem rna_enum_property_type_items[];
extern const EnumPropertyItem rna_enum_property_subtype_items[];
extern const EnumPropertyItem rna_enum_property_unit_items[];
-extern const EnumPropertyItem rna_enum_gameproperty_type_items[];
-
-extern const EnumPropertyItem rna_enum_viewport_shade_items[];
+extern const EnumPropertyItem rna_enum_shading_type_items[];
extern const EnumPropertyItem rna_enum_navigation_mode_items[];
extern const EnumPropertyItem rna_enum_file_sort_items[];
extern const EnumPropertyItem rna_enum_node_socket_in_out_items[];
-extern const EnumPropertyItem rna_enum_node_icon_items[];
extern const EnumPropertyItem rna_enum_node_math_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
@@ -203,7 +215,7 @@ extern const EnumPropertyItem rna_enum_dt_layers_select_src_items[];
extern const EnumPropertyItem rna_enum_dt_layers_select_dst_items[];
extern const EnumPropertyItem rna_enum_abc_compression_items[];
-
+extern const EnumPropertyItem rna_enum_context_mode_items[];
/* API calls */
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
@@ -226,6 +238,7 @@ const EnumPropertyItem *rna_node_socket_type_itemf(
struct bContext;
struct PointerRNA;
struct PropertyRNA;
+
const EnumPropertyItem *rna_TransformOrientation_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
const EnumPropertyItem *rna_Sensor_type_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
const EnumPropertyItem *rna_Actuator_type_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
@@ -234,8 +247,8 @@ const EnumPropertyItem *rna_Actuator_type_itemf(struct bContext *C, struct Point
* in the linked list can add more for different types as needed */
const EnumPropertyItem *RNA_action_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
// EnumPropertyItem *RNA_action_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
-const EnumPropertyItem *RNA_group_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
-const EnumPropertyItem *RNA_group_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+const EnumPropertyItem *RNA_collection_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+const EnumPropertyItem *RNA_collection_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
const EnumPropertyItem *RNA_image_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
const EnumPropertyItem *RNA_image_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
const EnumPropertyItem *RNA_scene_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
@@ -246,4 +259,7 @@ const EnumPropertyItem *RNA_movieclip_local_itemf(struct bContext *C, struct Poi
const EnumPropertyItem *RNA_mask_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
const EnumPropertyItem *RNA_mask_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+/* Non confirming, utility function. */
+const EnumPropertyItem *RNA_enum_node_tree_types_itemf_impl(struct bContext *C, bool *r_free);
+
#endif /* __RNA_ENUM_TYPES_H__ */
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 0d972a118e8..72e1c05de3c 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -108,6 +108,8 @@ typedef enum PropertyUnit {
#define RNA_TRANSLATION_PREC_DEFAULT 5
+#define RNA_STACK_ARRAY 32
+
/* also update enums in bpy_props.c when adding items here
* watch it: these values are written to files as part of
* node socket button subtypes!
@@ -156,7 +158,7 @@ typedef enum PropertySubType {
/* Make sure enums are updated with these */
/* HIGHEST FLAG IN USE: 1 << 31
- * FREE FLAGS: 2, 3, 7, 9, 11, 13, 14, 15, 30 */
+ * FREE FLAGS: 2, 9, 11, 13, 14, 15, 30 */
typedef enum PropertyFlag {
/* editable means the property is editable in the user
* interface, properties are editable by default except
@@ -182,6 +184,7 @@ typedef enum PropertyFlag {
/* icon */
PROP_ICONS_CONSECUTIVE = (1 << 12),
+ PROP_ICONS_REVERSE = (1 << 8),
/* hidden in the user interface */
PROP_HIDDEN = (1 << 19),
@@ -208,6 +211,13 @@ typedef enum PropertyFlag {
* but setting NULL on a mesh object is not possible. So, if its not NULL, setting NULL cant be done! */
PROP_NEVER_UNLINK = (1 << 25),
+ /* Pointers to data that is not owned by the struct.
+ * Typical example: Bone.parent, Bone.child, etc., and nearly all ID pointers.
+ * This is crucial information for processes that walk the whole data of an ID e.g. (like static override).
+ * Note that all ID pointers are enforced to this by default, this probably will need to be rechecked
+ * (see ugly infamous NodeTrees of mat/tex/scene/etc.). */
+ PROP_PTR_NO_OWNERSHIP = (1 << 7),
+
/* flag contains multiple enums.
* note: not to be confused with prop->enumbitflags
* this exposes the flag as multiple options in python and the UI.
@@ -228,13 +238,33 @@ typedef enum PropertyFlag {
* most common case is functions that return arrays where the array */
PROP_THICK_WRAP = (1 << 23),
- PROP_EXPORT = (1 << 8), /* XXX Is this still used? makesrna.c seems to ignore it currently... */
PROP_IDPROPERTY = (1 << 10), /* This is an IDProperty, not a DNA one. */
PROP_DYNAMIC = (1 << 17), /* for dynamic arrays, and retvals of type string */
PROP_ENUM_NO_CONTEXT = (1 << 24), /* for enum that shouldn't be contextual */
- PROP_ENUM_NO_TRANSLATE = (1 << 29), /* for enums not to be translated (e.g. renderlayers' names in nodes) */
+ PROP_ENUM_NO_TRANSLATE = (1 << 29), /* for enums not to be translated (e.g. viewlayers' names in nodes) */
} PropertyFlag;
+/* Flags related to comparing and overriding RNA properties. Make sure enums are updated with these */
+/* FREE FLAGS: 2, 3, 4, 5, 6, 7, 8, 9, 12 and above. */
+typedef enum PropertyOverrideFlag {
+ /* Means the property can be overridden by a local 'proxy' of some linked datablock. */
+ PROPOVERRIDE_OVERRIDABLE_STATIC = (1 << 0),
+
+ /* Forbid usage of this property in comparison (& hence override) code.
+ * Useful e.g. for collections of data like mesh's geometry, particles, etc. */
+ PROPOVERRIDE_NO_COMPARISON = (1 << 1),
+
+ /*** Collections-related ***/
+
+ /* The property supports insertion (collections only). */
+ PROPOVERRIDE_STATIC_INSERTION = (1 << 10),
+
+ /* Only use indices to compare items in the property, never names (collections only). */
+ /* Useful when nameprop of the items is generated from other data
+ * (e.g. name of material slots is actually name of assigned material). */
+ PROPOVERRIDE_NO_PROP_NAME = (1 << 11),
+} PropertyOverrideFlag;
+
/* Function parameters flags.
* WARNING: 16bits only. */
typedef enum ParameterFlag {
@@ -282,6 +312,7 @@ typedef struct CollectionPropertyIterator {
union {
ArrayIterator array;
ListBaseIterator listbase;
+ void *custom;
} internal;
int idprop;
int level;
@@ -493,7 +524,6 @@ typedef struct ExtensionRNA {
StructRNA *srna;
StructCallbackFunc call;
StructFreeFunc free;
-
} ExtensionRNA;
#ifdef __cplusplus
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 5e7438ce4ee..28fe276cb98 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -32,7 +32,6 @@ endif()
set(DEFSRC
rna_ID.c
rna_action.c
- rna_actuator.c
rna_animation.c
rna_animviz.c
rna_armature.c
@@ -41,21 +40,23 @@ set(DEFSRC
rna_cachefile.c
rna_camera.c
rna_cloth.c
+ rna_collection.c
rna_color.c
rna_constraint.c
rna_context.c
- rna_controller.c
rna_curve.c
rna_depsgraph.c
rna_dynamicpaint.c
rna_fcurve.c
rna_fluidsim.c
rna_gpencil.c
- rna_group.c
+ rna_gpencil_modifier.c
rna_image.c
rna_key.c
rna_lamp.c
rna_lattice.c
+ rna_layer.c
+ rna_lightprobe.c
rna_linestyle.c
rna_main.c
rna_mask.c
@@ -72,15 +73,14 @@ set(DEFSRC
rna_palette.c
rna_particle.c
rna_pose.c
- rna_property.c
rna_render.c
rna_rigidbody.c
rna_rna.c
rna_scene.c
rna_screen.c
rna_sculpt_paint.c
- rna_sensor.c
rna_sequencer.c
+ rna_shader_fx.c
rna_smoke.c
rna_sound.c
rna_space.c
@@ -94,16 +94,16 @@ set(DEFSRC
rna_userdef.c
rna_vfont.c
rna_wm.c
+ rna_wm_gizmo.c
+ rna_workspace.c
rna_world.c
)
set(APISRC
rna_action_api.c
- rna_actuator_api.c
rna_animation_api.c
rna_armature_api.c
rna_camera_api.c
- rna_controller_api.c
rna_curve_api.c
rna_fcurve_api.c
rna_image_api.c
@@ -116,7 +116,6 @@ set(APISRC
rna_object_api.c
rna_pose_api.c
rna_scene_api.c
- rna_sensor_api.c
rna_sequencer_api.c
rna_sound_api.c
rna_space_api.c
@@ -124,6 +123,8 @@ set(APISRC
rna_ui_api.c
rna_vfont_api.c
rna_wm_api.c
+ rna_wm_gizmo_api.c
+ rna_workspace_api.c
)
string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}")
@@ -188,10 +189,6 @@ if(WITH_PYTHON)
)
endif()
-if(WITH_GAMEENGINE)
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
@@ -220,12 +217,8 @@ if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
-if(WITH_IMAGE_FRAMESERVER)
- add_definitions(-DWITH_FRAMESERVER)
-endif()
-
if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+ add_definitions(-DWITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
@@ -334,6 +327,7 @@ blender_include_dirs(
../../bmesh
../../blentranslation
../../depsgraph
+ ../../draw
../../gpu
../../imbuf
../../ikplugin
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index a47426861b1..f2352052800 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -906,7 +906,7 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr
}
else {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)dp->prop;
- StructRNA *type = rna_find_struct((const char *)pprop->type);
+ StructRNA *type = (pprop->type) ? rna_find_struct((const char *)pprop->type) : NULL;
if (type && (type->flag & STRUCT_ID)) {
fprintf(f, " if (value.data)\n");
fprintf(f, " id_lib_extern((ID *)value.data);\n\n");
@@ -2482,12 +2482,24 @@ static void rna_auto_types(void)
for (ds = DefRNA.structs.first; ds; ds = ds->cont.next) {
/* DNA name for Screen is patched in 2.5, we do the reverse here .. */
- if (ds->dnaname && STREQ(ds->dnaname, "Screen"))
- ds->dnaname = "bScreen";
+ if (ds->dnaname) {
+ if (STREQ(ds->dnaname, "Screen"))
+ ds->dnaname = "bScreen";
+ if (STREQ(ds->dnaname, "Group"))
+ ds->dnaname = "Collection";
+ if (STREQ(ds->dnaname, "GroupObject"))
+ ds->dnaname = "CollectionObject";
+ }
for (dp = ds->cont.properties.first; dp; dp = dp->next) {
- if (dp->dnastructname && STREQ(dp->dnastructname, "Screen"))
- dp->dnastructname = "bScreen";
+ if (dp->dnastructname) {
+ if (STREQ(dp->dnastructname, "Screen"))
+ dp->dnastructname = "bScreen";
+ if (STREQ(dp->dnastructname, "Group"))
+ dp->dnastructname = "Collection";
+ if (STREQ(dp->dnastructname, "GroupObject"))
+ dp->dnastructname = "CollectionObject";
+ }
if (dp->dnatype) {
if (dp->prop->type == PROP_POINTER) {
@@ -2654,7 +2666,7 @@ static void rna_generate_property_prototypes(BlenderRNA *UNUSED(brna), StructRNA
fprintf(f, "\n");
for (prop = srna->cont.properties.first; prop; prop = prop->next)
- fprintf(f, "%s%s rna_%s_%s;\n", (prop->flag & PROP_EXPORT) ? "" : "", rna_property_structname(prop->type),
+ fprintf(f, "%s rna_%s_%s;\n", rna_property_structname(prop->type),
srna->identifier, prop->identifier);
fprintf(f, "\n");
}
@@ -3023,12 +3035,33 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
}
break;
}
+ case PROP_POINTER:
+ {
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
+
+ /* XXX This systematically enforces that flag on ID pointers... we'll probably have to revisit. :/ */
+ StructRNA *type = rna_find_struct((const char *)pprop->type);
+ if (type && (type->flag & STRUCT_ID)) {
+ prop->flag |= PROP_PTR_NO_OWNERSHIP;
+ }
+ break;
+ }
+ case PROP_COLLECTION:
+ {
+ CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
+
+ /* XXX This systematically enforces that flag on ID pointers... we'll probably have to revisit. :/ */
+ StructRNA *type = rna_find_struct((const char *)cprop->item_type);
+ if (type && (type->flag & STRUCT_ID)) {
+ prop->flag |= PROP_PTR_NO_OWNERSHIP;
+ }
+ break;
+ }
default:
break;
}
- fprintf(f, "%s%s rna_%s%s_%s = {\n",
- (prop->flag & PROP_EXPORT) ? "" : "",
+ fprintf(f, "%s rna_%s%s_%s = {\n",
rna_property_structname(prop->type),
srna->identifier, strnest, prop->identifier);
@@ -3038,7 +3071,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
else fprintf(f, "NULL,\n");
fprintf(f, "\t%d, ", prop->magic);
rna_print_c_string(f, prop->identifier);
- fprintf(f, ", %d, %d, %d, %d, ", prop->flag, prop->flag_parameter, prop->flag_internal, prop->tags);
+ fprintf(f, ", %d, %d, %d, %d, %d, ", prop->flag, prop->flag_override, prop->flag_parameter, prop->flag_internal, prop->tags);
rna_print_c_string(f, prop->name); fprintf(f, ",\n\t");
rna_print_c_string(f, prop->description); fprintf(f, ",\n\t");
fprintf(f, "%d, ", prop->icon);
@@ -3053,12 +3086,15 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
prop->arraylength[1],
prop->arraylength[2],
prop->totarraylength);
- fprintf(f, "\t%s%s, %d, %s, %s,\n",
+ fprintf(f, "\t%s%s, %d, %s, %s, %s, %s, %s,\n",
(prop->flag & PROP_CONTEXT_UPDATE) ? "(UpdateFunc)" : "",
rna_function_string(prop->update),
prop->noteflag,
rna_function_string(prop->editable),
- rna_function_string(prop->itemeditable));
+ rna_function_string(prop->itemeditable),
+ rna_function_string(prop->override_diff),
+ rna_function_string(prop->override_store),
+ rna_function_string(prop->override_apply));
if (prop->flag_internal & PROP_INTERN_RAW_ACCESS) rna_set_raw_offset(f, srna, prop);
else fprintf(f, "\t0, -1");
@@ -3353,49 +3389,49 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_action.c", "rna_action_api.c", RNA_def_action},
{"rna_animation.c", "rna_animation_api.c", RNA_def_animation},
{"rna_animviz.c", NULL, RNA_def_animviz},
- {"rna_actuator.c", "rna_actuator_api.c", RNA_def_actuator},
{"rna_armature.c", "rna_armature_api.c", RNA_def_armature},
{"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_collection.c", NULL, RNA_def_collections},
{"rna_color.c", NULL, RNA_def_color},
{"rna_constraint.c", NULL, RNA_def_constraint},
{"rna_context.c", NULL, RNA_def_context},
- {"rna_controller.c", "rna_controller_api.c", RNA_def_controller},
{"rna_curve.c", "rna_curve_api.c", RNA_def_curve},
- {"rna_depsgraph.c", NULL, RNA_def_depsgraph},
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint},
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
{"rna_fluidsim.c", NULL, RNA_def_fluidsim},
{"rna_gpencil.c", NULL, RNA_def_gpencil},
- {"rna_group.c", NULL, RNA_def_group},
{"rna_image.c", "rna_image_api.c", RNA_def_image},
{"rna_key.c", NULL, RNA_def_key},
- {"rna_lamp.c", NULL, RNA_def_lamp},
+ {"rna_lamp.c", NULL, RNA_def_light},
{"rna_lattice.c", "rna_lattice_api.c", RNA_def_lattice},
+ {"rna_layer.c", NULL, RNA_def_view_layer},
{"rna_linestyle.c", NULL, RNA_def_linestyle},
{"rna_main.c", "rna_main_api.c", RNA_def_main},
{"rna_material.c", "rna_material_api.c", RNA_def_material},
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh},
{"rna_meta.c", "rna_meta_api.c", RNA_def_meta},
{"rna_modifier.c", NULL, RNA_def_modifier},
+ {"rna_gpencil_modifier.c", NULL, RNA_def_greasepencil_modifier},
+ {"rna_shader_fx.c", NULL, RNA_def_shader_fx },
{"rna_nla.c", NULL, RNA_def_nla},
{"rna_nodetree.c", NULL, RNA_def_nodetree},
{"rna_object.c", "rna_object_api.c", RNA_def_object},
{"rna_object_force.c", NULL, RNA_def_object_force},
+ {"rna_depsgraph.c", NULL, RNA_def_depsgraph},
{"rna_packedfile.c", NULL, RNA_def_packedfile},
{"rna_palette.c", NULL, RNA_def_palette},
{"rna_particle.c", NULL, RNA_def_particle},
{"rna_pose.c", "rna_pose_api.c", RNA_def_pose},
- {"rna_property.c", NULL, RNA_def_gameproperty},
+ {"rna_lightprobe.c", NULL, RNA_def_lightprobe},
{"rna_render.c", NULL, RNA_def_render},
{"rna_rigidbody.c", NULL, RNA_def_rigidbody},
{"rna_scene.c", "rna_scene_api.c", RNA_def_scene},
{"rna_screen.c", NULL, RNA_def_screen},
{"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint},
- {"rna_sensor.c", "rna_sensor_api.c", RNA_def_sensor},
{"rna_sequencer.c", "rna_sequencer_api.c", RNA_def_sequencer},
{"rna_smoke.c", NULL, RNA_def_smoke},
{"rna_space.c", "rna_space_api.c", RNA_def_space},
@@ -3408,6 +3444,8 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_userdef.c", NULL, RNA_def_userdef},
{"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont},
{"rna_wm.c", "rna_wm_api.c", RNA_def_wm},
+ {"rna_wm_gizmo.c", "rna_wm_gizmo_api.c", RNA_def_wm_gizmo},
+ {"rna_workspace.c", "rna_workspace_api.c", RNA_def_workspace},
{"rna_world.c", NULL, RNA_def_world},
{"rna_movieclip.c", NULL, RNA_def_movieclip},
{"rna_tracking.c", NULL, RNA_def_tracking},
@@ -3725,7 +3763,7 @@ static const char *cpp_classes = ""
" COLLECTION_PROPERTY_LENGTH_##has_length(sname, identifier) \\\n"
" COLLECTION_PROPERTY_LOOKUP_INT_##has_lookup_int(sname, identifier) \\\n"
" COLLECTION_PROPERTY_LOOKUP_STRING_##has_lookup_string(sname, identifier) \\\n"
-" Collection<sname, type, sname##_##identifier##_begin, \\\n"
+" CollectionRef<sname, type, sname##_##identifier##_begin, \\\n"
" sname##_##identifier##_next, sname##_##identifier##_end, \\\n"
" sname##_##identifier##_length_wrap, \\\n"
" sname##_##identifier##_lookup_int_wrap, sname##_##identifier##_lookup_string_wrap, collection_funcs> identifier;\n"
@@ -3738,6 +3776,9 @@ static const char *cpp_classes = ""
" operator void*() { return ptr.data; }\n"
" operator bool() { return ptr.data != NULL; }\n"
"\n"
+" bool operator==(const Pointer &other) { return ptr.data == other.ptr.data; }\n"
+" bool operator!=(const Pointer &other) { return ptr.data != other.ptr.data; }\n"
+"\n"
" PointerRNA ptr;\n"
"};\n"
"\n"
@@ -3819,9 +3860,9 @@ static const char *cpp_classes = ""
"template<typename Tp, typename T, TBeginFunc Tbegin, TNextFunc Tnext, TEndFunc Tend,\n"
" TLengthFunc Tlength, TLookupIntFunc Tlookup_int, TLookupStringFunc Tlookup_string,\n"
" typename Tcollection_funcs>\n"
-"class Collection : public Tcollection_funcs {\n"
+"class CollectionRef : public Tcollection_funcs {\n"
"public:\n"
-" Collection(const PointerRNA &p) : Tcollection_funcs(p), ptr(p) {}\n"
+" CollectionRef(const PointerRNA &p) : Tcollection_funcs(p), ptr(p) {}\n"
"\n"
" void begin(CollectionIterator<T, Tbegin, Tnext, Tend>& iter)\n"
" { iter.begin(ptr); }\n"
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index bebf232b3b9..b550b4043e3 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -36,6 +36,7 @@
#include "BLI_math_base.h"
#include "BKE_icons.h"
+#include "BKE_library.h"
#include "BKE_object.h"
#include "RNA_access.h"
@@ -58,10 +59,10 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
{ID_CU, "CURVE", ICON_CURVE_DATA, "Curve", ""},
{ID_VF, "FONT", ICON_FONT_DATA, "Font", ""},
{ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""},
- {ID_GR, "GROUP", ICON_GROUP, "Group", ""},
+ {ID_GR, "COLLECTION", ICON_GROUP, "Collection", ""},
{ID_IM, "IMAGE", ICON_IMAGE_DATA, "Image", ""},
{ID_KE, "KEY", ICON_SHAPEKEY_DATA, "Key", ""},
- {ID_LA, "LAMP", ICON_LAMP_DATA, "Lamp", ""},
+ {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""},
{ID_LI, "LIBRARY", ICON_LIBRARY_DATA_DIRECT, "Library", ""},
{ID_LS, "LINESTYLE", ICON_LINE_DATA, "Line Style", ""},
{ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
@@ -75,14 +76,15 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
{ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""},
{ID_PAL, "PALETTE", ICON_COLOR, "Palette", ""},
{ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""},
+ {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
{ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""},
- {ID_SCR, "SCREEN", ICON_SPLITSCREEN, "Screen", ""},
- {ID_SO, "SOUND", ICON_PLAY_AUDIO, "Sound", ""},
+ {ID_SO, "SOUND", ICON_SOUND, "Sound", ""},
{ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""},
{ID_TXT, "TEXT", ICON_TEXT, "Text", ""},
{ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""},
- {ID_WM, "WINDOWMANAGER", ICON_FULLSCREEN, "Window Manager", ""},
+ {ID_WM, "WINDOWMANAGER", ICON_WINDOW, "Window Manager", ""},
{ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
+ {ID_WS, "WORKSPACE", ICON_WORKSPACE, "Workspace", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -94,16 +96,44 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
#include "BKE_font.h"
#include "BKE_idprop.h"
-#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_library_override.h"
#include "BKE_library_remap.h"
#include "BKE_animsys.h"
#include "BKE_material.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h" /* XXX, remove me */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "WM_api.h"
+void rna_ID_override_static_property_operation_refname_get(PointerRNA *ptr, char *value)
+{
+ IDOverrideStaticPropertyOperation *opop = ptr->data;
+ strcpy(value, (opop->subitem_reference_name == NULL) ? "" : opop->subitem_reference_name);
+}
+
+int rna_ID_override_static_property_operation_refname_length(PointerRNA *ptr)
+{
+ IDOverrideStaticPropertyOperation *opop = ptr->data;
+ return (opop->subitem_reference_name == NULL) ? 0 : strlen(opop->subitem_reference_name);
+}
+
+void rna_ID_override_static_property_operation_locname_get(PointerRNA *ptr, char *value)
+{
+ IDOverrideStaticPropertyOperation *opop = ptr->data;
+ strcpy(value, (opop->subitem_local_name == NULL) ? "" : opop->subitem_local_name);
+}
+
+int rna_ID_override_static_property_operation_locname_length(PointerRNA *ptr)
+{
+ IDOverrideStaticPropertyOperation *opop = ptr->data;
+ return (opop->subitem_local_name == NULL) ? 0 : strlen(opop->subitem_local_name);
+}
+
+
/* name functions that ignore the first two ID characters */
void rna_ID_name_get(PointerRNA *ptr, char *value)
{
@@ -121,8 +151,15 @@ void rna_ID_name_set(PointerRNA *ptr, const char *value)
{
ID *id = (ID *)ptr->data;
BLI_strncpy_utf8(id->name + 2, value, sizeof(id->name) - 2);
- BLI_assert(BKE_id_is_in_gobal_main(id));
+ BLI_assert(BKE_id_is_in_global_main(id));
BLI_libblock_ensure_unique_name(G_MAIN, id->name);
+
+ if (GS(id->name) == ID_OB) {
+ Object *ob = (Object *)id;
+ if (ob->type == OB_MBALL) {
+ DEG_id_tag_update(&ob->id, DEG_TAG_GEOMETRY);
+ }
+ }
}
static int rna_ID_name_editable(PointerRNA *ptr, const char **UNUSED(r_info))
@@ -132,12 +169,43 @@ static int rna_ID_name_editable(PointerRNA *ptr, const char **UNUSED(r_info))
if (GS(id->name) == ID_VF) {
VFont *vfont = (VFont *)id;
if (BKE_vfont_is_builtin(vfont))
- return false;
+ return 0;
+ }
+ else if (!BKE_id_is_in_global_main(id)) {
+ return 0;
}
return PROP_EDITABLE;
}
+void rna_ID_name_full_get(PointerRNA *ptr, char *value)
+{
+ ID *id = (ID *)ptr->data;
+ BKE_id_full_name_get(value, id);
+}
+
+int rna_ID_name_full_length(PointerRNA *ptr)
+{
+ ID *id = (ID *)ptr->data;
+ char name[MAX_ID_FULL_NAME];
+ BKE_id_full_name_get(name, id);
+ return strlen(name);
+}
+
+static int rna_ID_is_evaluated_get(PointerRNA *ptr)
+{
+ ID *id = (ID *)ptr->data;
+
+ return (DEG_get_original_id(id) != id);
+}
+
+static PointerRNA rna_ID_original_get(PointerRNA *ptr)
+{
+ ID *id = (ID *)ptr->data;
+
+ return rna_pointer_inherit_refine(ptr, &RNA_ID, DEG_get_original_id(id));
+}
+
short RNA_type_to_ID_code(const StructRNA *type)
{
const StructRNA *base_type = RNA_struct_base_child_of(type, &RNA_ID);
@@ -151,10 +219,10 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (base_type == &RNA_Camera) return ID_CA;
if (base_type == &RNA_Curve) return ID_CU;
if (base_type == &RNA_GreasePencil) return ID_GD;
- if (base_type == &RNA_Group) return ID_GR;
+ if (base_type == &RNA_Collection) return ID_GR;
if (base_type == &RNA_Image) return ID_IM;
if (base_type == &RNA_Key) return ID_KE;
- if (base_type == &RNA_Lamp) return ID_LA;
+ if (base_type == &RNA_Light) return ID_LA;
if (base_type == &RNA_Library) return ID_LI;
if (base_type == &RNA_FreestyleLineStyle) return ID_LS;
if (base_type == &RNA_Lattice) return ID_LT;
@@ -168,6 +236,7 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (base_type == &RNA_ParticleSettings) return ID_PA;
if (base_type == &RNA_Palette) return ID_PAL;
if (base_type == &RNA_PaintCurve) return ID_PC;
+ if (base_type == &RNA_LightProbe) return ID_LP;
if (base_type == &RNA_Scene) return ID_SCE;
if (base_type == &RNA_Screen) return ID_SCR;
if (base_type == &RNA_Sound) return ID_SO;
@@ -175,6 +244,7 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (base_type == &RNA_Texture) return ID_TE;
if (base_type == &RNA_Text) return ID_TXT;
if (base_type == &RNA_VectorFont) return ID_VF;
+ if (base_type == &RNA_WorkSpace) return ID_WS;
if (base_type == &RNA_World) return ID_WO;
if (base_type == &RNA_WindowManager) return ID_WM;
@@ -193,10 +263,10 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_CF: return &RNA_CacheFile;
case ID_CU: return &RNA_Curve;
case ID_GD: return &RNA_GreasePencil;
- case ID_GR: return &RNA_Group;
+ case ID_GR: return &RNA_Collection;
case ID_IM: return &RNA_Image;
case ID_KE: return &RNA_Key;
- case ID_LA: return &RNA_Lamp;
+ case ID_LA: return &RNA_Light;
case ID_LI: return &RNA_Library;
case ID_LS: return &RNA_FreestyleLineStyle;
case ID_LT: return &RNA_Lattice;
@@ -210,6 +280,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_PA: return &RNA_ParticleSettings;
case ID_PAL: return &RNA_Palette;
case ID_PC: return &RNA_PaintCurve;
+ case ID_LP: return &RNA_LightProbe;
case ID_SCE: return &RNA_Scene;
case ID_SCR: return &RNA_Screen;
case ID_SO: return &RNA_Sound;
@@ -219,6 +290,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_VF: return &RNA_VectorFont;
case ID_WM: return &RNA_WindowManager;
case ID_WO: return &RNA_World;
+ case ID_WS: return &RNA_WorkSpace;
/* deprecated */
case ID_IP: break;
@@ -305,6 +377,15 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
return NULL;
}
+static ID *rna_ID_override_create(ID *id, Main *bmain)
+{
+ if (!BKE_override_static_is_enabled() || id->lib == NULL) {
+ return NULL;
+ }
+
+ return BKE_override_static_create_from_id(bmain, id);
+}
+
static void rna_ID_update_tag(ID *id, ReportList *reports, int flag)
{
/* XXX, new function for this! */
@@ -343,7 +424,7 @@ static void rna_ID_update_tag(ID *id, ReportList *reports, int flag)
}
}
- DAG_id_tag_update(id, flag);
+ DEG_id_tag_update(id, flag);
}
static void rna_ID_user_clear(ID *id)
@@ -379,14 +460,14 @@ static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, bool clear_pro
static AnimData *rna_ID_animation_data_create(ID *id, Main *bmain)
{
AnimData *adt = BKE_animdata_add_id(id);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
return adt;
}
static void rna_ID_animation_data_free(ID *id, Main *bmain)
{
BKE_animdata_free(id, true);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
#ifdef WITH_PYTHON
@@ -415,8 +496,8 @@ int rna_IDMaterials_assign_int(PointerRNA *ptr, int key, const PointerRNA *assig
short *totcol = give_totcolp_id(id);
Material *mat_id = assign_ptr->id.data;
if (totcol && (key >= 0 && key < *totcol)) {
- BLI_assert(BKE_id_is_in_gobal_main(id));
- BLI_assert(BKE_id_is_in_gobal_main(&mat_id->id));
+ BLI_assert(BKE_id_is_in_global_main(id));
+ BLI_assert(BKE_id_is_in_global_main(&mat_id->id));
assign_material_id(G_MAIN, id, mat_id, key + 1);
return 1;
}
@@ -455,7 +536,7 @@ static Material *rna_IDMaterials_pop_id(
return NULL;
}
- DAG_id_tag_update(id, OB_RECALC_DATA);
+ DEG_id_tag_update(id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, id);
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, id);
@@ -466,7 +547,7 @@ static void rna_IDMaterials_clear_id(ID *id, Main *bmain, bool remove_material_s
{
BKE_material_clear_id(bmain, id, remove_material_slot);
- DAG_id_tag_update(id, OB_RECALC_DATA);
+ DEG_id_tag_update(id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, id);
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, id);
}
@@ -474,7 +555,7 @@ static void rna_IDMaterials_clear_id(ID *id, Main *bmain, bool remove_material_s
static void rna_Library_filepath_set(PointerRNA *ptr, const char *value)
{
Library *lib = (Library *)ptr->data;
- BLI_assert(BKE_id_is_in_gobal_main(&lib->id));
+ BLI_assert(BKE_id_is_in_global_main(&lib->id));
BKE_library_filepath_set(G_MAIN, lib, value);
}
@@ -783,52 +864,52 @@ static void rna_def_ID_properties(BlenderRNA *brna)
/* IDP_STRING */
prop = RNA_def_property(srna, "string", PROP_STRING, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
/* IDP_INT */
prop = RNA_def_property(srna, "int", PROP_INT, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
prop = RNA_def_property(srna, "int_array", PROP_INT, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_array(prop, 1);
/* IDP_FLOAT */
prop = RNA_def_property(srna, "float", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
prop = RNA_def_property(srna, "float_array", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_array(prop, 1);
/* IDP_DOUBLE */
prop = RNA_def_property(srna, "double", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
prop = RNA_def_property(srna, "double_array", PROP_FLOAT, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_array(prop, 1);
/* IDP_GROUP */
prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "PropertyGroup");
prop = RNA_def_property(srna, "collection", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_struct_type(prop, "PropertyGroup");
prop = RNA_def_property(srna, "idp_array", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "PropertyGroup");
RNA_def_property_collection_funcs(prop, "rna_IDPArray_begin", "rna_iterator_array_next", "rna_iterator_array_end",
"rna_iterator_array_get", "rna_IDPArray_length", NULL, NULL, NULL);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
/* never tested, maybe its useful to have this? */
#if 0
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Name", "Unique name used in the code and scripting");
RNA_def_struct_name_property(srna, prop);
@@ -836,7 +917,7 @@ static void rna_def_ID_properties(BlenderRNA *brna)
/* IDP_ID */
prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY | PROP_NEVER_UNLINK);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY | PROP_NEVER_UNLINK);
RNA_def_property_struct_type(prop, "ID");
@@ -854,7 +935,7 @@ static void rna_def_ID_properties(BlenderRNA *brna)
* however this isn't prefect because it overrides how python would set the name
* when we only really want this so RNA_def_struct_name_property() is set to something useful */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
/*RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
RNA_def_property_ui_text(prop, "Name", "Unique name used in the code and scripting");
RNA_def_struct_name_property(srna, prop);
@@ -965,6 +1046,107 @@ static void rna_def_image_preview(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Reload the preview from its source path");
}
+static void rna_def_ID_override_static_property_operation(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem static_override_property_operation_items[] = {
+ {IDOVERRIDESTATIC_OP_NOOP, "NOOP", 0, "No-Op", "Does nothing, prevents adding actual overrides (NOT USED)"},
+ {IDOVERRIDESTATIC_OP_REPLACE, "REPLACE", 0, "Replace", "Replace value of reference by overriding one"},
+ {IDOVERRIDESTATIC_OP_ADD, "DIFF_ADD", 0, "Differential",
+ "Stores and apply difference between reference and local value (NOT USED)"},
+ {IDOVERRIDESTATIC_OP_SUBTRACT, "DIFF_SUB", 0, "Differential",
+ "Stores and apply difference between reference and local value (NOT USED)"},
+ {IDOVERRIDESTATIC_OP_MULTIPLY, "FACT_MULTIPLY", 0, "Factor",
+ "Stores and apply multiplication factor between reference and local value (NOT USED)"},
+ {IDOVERRIDESTATIC_OP_INSERT_AFTER, "INSERT_AFTER", 0, "Insert After",
+ "Insert a new item into collection after the one referenced in subitem_reference_name or _index"},
+ {IDOVERRIDESTATIC_OP_INSERT_BEFORE, "INSERT_BEFORE", 0, "Insert Before",
+ "Insert a new item into collection after the one referenced in subitem_reference_name or _index (NOT USED)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem static_override_property_flag_items[] = {
+ {IDOVERRIDESTATIC_FLAG_MANDATORY, "MANDATORY", 0, "Mandatory",
+ "For templates, prevents the user from removing pre-defined operation (NOT USED)"},
+ {IDOVERRIDESTATIC_FLAG_LOCKED, "LOCKED", 0, "Locked",
+ "Prevents the user from modifying that override operation (NOT USED)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "IDOverrideStaticPropertyOperation", NULL);
+ RNA_def_struct_ui_text(srna, "ID Static Override Property Operation",
+ "Description of an override operation over an overridden property");
+
+ prop = RNA_def_enum(srna, "operation", static_override_property_operation_items, IDOVERRIDESTATIC_OP_REPLACE,
+ "Operation", "What override operation is performed");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
+
+ prop = RNA_def_enum(srna, "flag", static_override_property_flag_items, 0,
+ "Flags", "Optional flags (NOT USED)");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
+
+ prop = RNA_def_string(srna, "subitem_reference_name", NULL, INT_MAX, "Subitem Reference Name",
+ "Used to handle insertions into collection");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
+ RNA_def_property_string_funcs(prop, "rna_ID_override_static_property_operation_refname_get",
+ "rna_ID_override_static_property_operation_refname_length", NULL);
+
+ prop = RNA_def_string(srna, "subitem_local_name", NULL, INT_MAX, "Subitem Local Name",
+ "Used to handle insertions into collection");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
+ RNA_def_property_string_funcs(prop, "rna_ID_override_static_property_operation_locname_get",
+ "rna_ID_override_static_property_operation_locname_length", NULL);
+
+ prop = RNA_def_int(srna, "subitem_reference_index", -1, -1, INT_MAX, "Subitem Reference Index",
+ "Used to handle insertions into collection", -1, INT_MAX);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
+
+ prop = RNA_def_int(srna, "subitem_local_index", -1, -1, INT_MAX, "Subitem Local Index",
+ "Used to handle insertions into collection", -1, INT_MAX);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
+}
+
+static void rna_def_ID_override_static_property(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "IDOverrideStaticProperty", NULL);
+ RNA_def_struct_ui_text(srna, "ID Static Override Property", "Description of an overridden property");
+
+ /* String pointer, we *should* add get/set/etc. But NULL rna_path would be a nasty bug anyway... */
+ prop = RNA_def_string(srna, "rna_path", NULL, INT_MAX, "RNA Path",
+ "RNA path leading to that property, from owning ID");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */
+
+ RNA_def_collection(srna, "operations", "IDOverrideStaticPropertyOperation", "Operations",
+ "List of overriding operations for a property");
+
+ rna_def_ID_override_static_property_operation(brna);
+}
+
+static void rna_def_ID_override_static(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "IDOverrideStatic", NULL);
+ RNA_def_struct_ui_text(srna, "ID Static Override", "Struct gathering all data needed by statically overridden IDs");
+
+ RNA_def_pointer(srna, "reference", "ID", "Reference ID", "Linked ID used as reference by this override");
+
+ prop = RNA_def_boolean(srna, "auto_generate", true, "Auto Generate Override",
+ "Automatically generate overriding operations by detecting changes in properties");
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", STATICOVERRIDE_AUTO);
+
+ RNA_def_collection(srna, "properties", "IDOverrideStaticProperty", "Properties",
+ "List of overridden properties");
+
+ rna_def_ID_override_static_property(brna);
+}
+
static void rna_def_ID(BlenderRNA *brna)
{
StructRNA *srna;
@@ -994,6 +1176,25 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_update(prop, NC_ID | NA_RENAME, NULL);
RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "name_full", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Full Name", "Unique data-block ID name, including library one is any");
+ RNA_def_property_string_funcs(prop, "rna_ID_name_full_get", "rna_ID_name_full_length", NULL);
+ RNA_def_property_string_maxlength(prop, MAX_ID_FULL_NAME);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "is_evaluated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Is Evaluated",
+ "Whether this ID is runtime-only, evaluated data-block, or actual data from .blend file");
+ RNA_def_property_boolean_funcs(prop, "rna_ID_is_evaluated_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "original", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ID");
+ RNA_def_property_ui_text(prop, "Original ID",
+ "Actual data-block from .blend file (Main database) that generated that evaluated one");
+ RNA_def_property_pointer_funcs(prop, "rna_ID_original_get", NULL, NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP);
+
prop = RNA_def_property(srna, "users", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "us");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1002,6 +1203,7 @@ static void rna_def_ID(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_fake_user", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_FAKEUSER);
RNA_def_property_ui_text(prop, "Fake User", "Save this data-block even if it has no users");
+ RNA_def_property_ui_icon(prop, ICON_FAKE_USER_OFF, true);
RNA_def_property_boolean_funcs(prop, NULL, "rna_ID_fake_user_set");
prop = RNA_def_property(srna, "tag", PROP_BOOLEAN, PROP_NONE);
@@ -1011,16 +1213,6 @@ static void rna_def_ID(BlenderRNA *brna)
"Tools can use this to tag data for their own purposes "
"(initial state is undefined)");
- prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "recalc", ID_RECALC);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Updated", "Data-block is tagged for recalculation");
-
- prop = RNA_def_property(srna, "is_updated_data", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "recalc", ID_RECALC_DATA);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Updated Data", "Data-block data is tagged for recalculation");
-
prop = RNA_def_property(srna, "is_library_indirect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_INDIRECT);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1031,6 +1223,9 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Library", "Library file the data-block is linked from");
+ prop = RNA_def_pointer(srna, "override_static", "IDOverrideStatic", "Static Override", "Static override data");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_pointer(srna, "preview", "ImagePreview", "Preview",
"Preview image and icon of this data-block (None if not supported for this type of data)");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1043,6 +1238,12 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "override_create", "rna_ID_override_create");
+ RNA_def_function_ui_description(func, "Create an overridden local copy of this linked data-block (not supported for all data-blocks)");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "id", "ID", "", "New overridden local copy of the ID");
+ RNA_def_function_return(func, parm);
+
func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear");
RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
"on reload the data will be removed");
@@ -1147,6 +1348,7 @@ void RNA_def_ID(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Any Type", "RNA type used for pointers to any possible data");
rna_def_ID(brna);
+ rna_def_ID_override_static(brna);
rna_def_image_preview(brna);
rna_def_ID_properties(brna);
rna_def_ID_materials(brna);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 51293340a6c..cb6f62d35eb 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -34,6 +34,8 @@
#include "DNA_ID.h"
#include "DNA_scene_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_windowmanager_types.h"
#include "BLI_blenlib.h"
@@ -42,6 +44,10 @@
#include "BLI_ghash.h"
#include "BLI_math.h"
+#ifdef DEBUG_OVERRIDE_TIMEIT
+# include "PIL_time_utildefines.h"
+#endif
+
#include "BLF_api.h"
#include "BLT_translation.h"
@@ -50,19 +56,21 @@
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
-#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "WM_api.h"
+#include "WM_message.h"
/* flush updates */
#include "DNA_object_types.h"
-#include "BKE_depsgraph.h"
#include "WM_types.h"
#include "rna_internal.h"
@@ -431,7 +439,7 @@ static PropertyRNA *arraytypemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_double_array
};
-IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
+static void *rna_idproperty_check_ex(PropertyRNA **prop, PointerRNA *ptr, const bool return_rnaprop)
{
/* This is quite a hack, but avoids some complexity in the API. we
* pass IDProperty structs as PropertyRNA pointers to the outside.
@@ -453,8 +461,9 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
return idprop;
}
- else
- return NULL;
+ else {
+ return return_rnaprop ? *prop : NULL;
+ }
}
{
@@ -469,6 +478,19 @@ IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
}
}
+/* This function only returns an IDProperty,
+ * or NULL (in case IDProp could not be found, or prop is a real RNA property). */
+IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
+{
+ return rna_idproperty_check_ex(prop, ptr, false);
+}
+
+/* This function always return the valid, real data pointer, be it a regular RNA property one, or an IDProperty one. */
+PropertyRNA *rna_ensure_property_realdata(PropertyRNA **prop, PointerRNA *ptr)
+{
+ return rna_idproperty_check_ex(prop, ptr, true);
+}
+
static PropertyRNA *rna_ensure_property(PropertyRNA *prop)
{
/* the quick version if we don't need the idproperty */
@@ -597,7 +619,7 @@ StructRNA *RNA_struct_base(StructRNA *type)
/**
* Use to find the subtype directly below a base-type.
*
- * So if type were `RNA_SpotLamp`, `RNA_struct_base_of(type, &RNA_ID)` would return `&RNA_Lamp`.
+ * So if type were `RNA_SpotLIght`, `RNA_struct_base_of(type, &RNA_ID)` would return `&RNA_Light`.
*/
const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type)
{
@@ -982,6 +1004,11 @@ int RNA_property_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag;
}
+int RNA_property_override_flag(PropertyRNA *prop)
+{
+ return rna_ensure_property(prop)->flag_override;
+}
+
/**
* Get the tags set for \a prop as int bitfield.
* \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
@@ -1637,6 +1664,21 @@ int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifie
return -1;
}
+/**
+ * Take care using this with translated enums,
+ * prefer #RNA_enum_from_identifier where possible.
+ */
+int RNA_enum_from_name(const EnumPropertyItem *item, const char *name)
+{
+ int i = 0;
+ for (; item->identifier; item++, i++) {
+ if (item->identifier[0] && STREQ(item->name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
{
int i = 0;
@@ -1819,7 +1861,8 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
return ((flag & PROP_EDITABLE) &&
(flag & PROP_REGISTER) == 0 &&
- (!id || !ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)));
+ (!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) &&
+ (!id->override_static || RNA_property_overridable_get(ptr, prop)))));
}
/**
@@ -1845,11 +1888,19 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
}
/* property from linked data-block */
- if (id && ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
- if (!(*r_info)[0]) {
- *r_info = N_("Can't edit this property from a linked data-block");
+ if (id) {
+ if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+ if (!(*r_info)[0]) {
+ *r_info = N_("Can't edit this property from a linked data-block.");
+ }
+ return false;
+ }
+ if (id->override_static != NULL && !RNA_property_overridable_get(ptr, prop)) {
+ if (!(*r_info)[0]) {
+ *r_info = N_("Can't edit this property from an override data-block.");
+ }
+ return false;
}
- return false;
}
return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0);
@@ -1923,6 +1974,70 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
return false;
}
+/** \note Does not take into account editable status, this has to be checked separately
+ * (using RNA_property_edtiable_flag() usually). */
+bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
+{
+ if (prop->magic == RNA_MAGIC) {
+ /* Special handling for insertions of constraints or modifiers... */
+ /* TODO Note We may want to add a more generic system to RNA (like a special property in struct of items)
+ * if we get more overrideable collections, for now we can live with those special-cases handling I think. */
+ if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
+ bConstraint *con = ptr->data;
+ if (con->flag & CONSTRAINT_STATICOVERRIDE_LOCAL) {
+ return true;
+ }
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
+ ModifierData *mod = ptr->data;
+ if (mod->flag & eModifierFlag_StaticOverride_Local) {
+ return true;
+ }
+ }
+ /* If this is a RNA-defined property (real or 'virtual' IDProp), we want to use RNA prop flag. */
+ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_STATIC);
+ }
+ else {
+ /* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
+ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_STATIC);
+ }
+}
+
+/* Should only be used for custom properties */
+bool RNA_property_overridable_static_set(PointerRNA *UNUSED(ptr), PropertyRNA *prop, const bool is_overridable)
+{
+ /* Only works for pure custom properties IDProps. */
+ if (prop->magic != RNA_MAGIC) {
+ IDProperty *idprop = (IDProperty *)prop;
+
+ idprop->flag = is_overridable ? (idprop->flag | IDP_FLAG_OVERRIDABLE_STATIC) :
+ (idprop->flag & ~IDP_FLAG_OVERRIDABLE_STATIC);
+ return true;
+ }
+
+ return false;
+}
+
+
+bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop)
+{
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ ID *id = ptr->id.data;
+
+ if (rna_path == NULL || id == NULL || id->override_static == NULL) {
+ return false;
+ }
+
+ return (BKE_override_static_property_find(id->override_static, rna_path) != NULL);
+}
+
+bool RNA_property_comparable(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+{
+ prop = rna_ensure_property(prop);
+
+ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON);
+}
+
/* this function is to check if its possible to create a valid path from the ID
* its slow so don't call in a loop */
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop)
@@ -1957,7 +2072,7 @@ static void rna_property_update(bContext *C, Main *bmain, Scene *scene, PointerR
* parts of the code that need it still, so we have this exception */
if (prop->flag & PROP_CONTEXT_UPDATE) {
if (C) {
- if (prop->flag & PROP_CONTEXT_PROPERTY_UPDATE) {
+ if ((prop->flag & PROP_CONTEXT_PROPERTY_UPDATE) == PROP_CONTEXT_PROPERTY_UPDATE) {
((ContextPropUpdateFunc)prop->update)(C, ptr, prop);
}
else {
@@ -1968,14 +2083,35 @@ static void rna_property_update(bContext *C, Main *bmain, Scene *scene, PointerR
else
prop->update(bmain, scene, ptr);
}
- if (prop->noteflag)
+
+#if 1
+ /* TODO(campbell): Should eventually be replaced entirely by message bus (below)
+ * for now keep since COW, bugs are hard to track when we have other missing updates. */
+ if (prop->noteflag) {
WM_main_add_notifier(prop->noteflag, ptr->id.data);
+ }
+#endif
+
+ /* if C is NULL, we're updating from animation.
+ * avoid slow-down from f-curves by not publishing (for now). */
+ if (C != NULL) {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ /* we could add NULL check, for now don't */
+ WM_msg_publish_rna(mbus, ptr, prop);
+ }
+ if (ptr->id.data != NULL) {
+ const short id_type = GS(((ID *)ptr->id.data)->name);
+ if (ID_TYPE_IS_COW(id_type)) {
+ DEG_id_tag_update(ptr->id.data, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+ /* End message bus. */
}
if (!is_rna || (prop->flag & PROP_IDPROPERTY)) {
/* WARNING! This is so property drivers update the display!
* not especially nice */
- DAG_id_tag_update(ptr->id.data, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_OB | OB_RECALC_DATA);
WM_main_add_notifier(NC_WINDOW, NULL);
/* Not nice as well, but the only way to make sure material preview
* is updated with custom nodes.
@@ -2173,6 +2309,20 @@ void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
}
}
+static void rna_property_boolean_get_default_array_values(BoolPropertyRNA *bprop, bool *values)
+{
+ unsigned int length = bprop->property.totarraylength;
+
+ if (bprop->defaultarray) {
+ memcpy(values, bprop->defaultarray, sizeof(bool) * length);
+ }
+ else {
+ for (unsigned int i = 0; i < length; i++) {
+ values[i] = bprop->defaultvalue;
+ }
+ }
+}
+
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
@@ -2198,10 +2348,8 @@ void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *va
bprop->getarray(ptr, values);
else if (bprop->getarray_ex)
bprop->getarray_ex(ptr, prop, values);
- else if (bprop->defaultarray)
- memcpy(values, bprop->defaultarray, sizeof(bool) * prop->totarraylength);
else
- memset(values, 0, sizeof(bool) * prop->totarraylength);
+ rna_property_boolean_get_default_array_values(bprop, values);
}
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
@@ -2325,10 +2473,8 @@ void RNA_property_boolean_get_default_array(PointerRNA *UNUSED(ptr), PropertyRNA
if (prop->arraydimension == 0)
values[0] = bprop->defaultvalue;
- else if (bprop->defaultarray)
- memcpy(values, bprop->defaultarray, sizeof(bool) * prop->totarraylength);
else
- memset(values, 0, sizeof(bool) * prop->totarraylength);
+ rna_property_boolean_get_default_array_values(bprop, values);
}
bool RNA_property_boolean_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
@@ -2408,6 +2554,20 @@ void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
}
}
+static void rna_property_int_get_default_array_values(IntPropertyRNA *iprop, int *values)
+{
+ unsigned int length = iprop->property.totarraylength;
+
+ if (iprop->defaultarray) {
+ memcpy(values, iprop->defaultarray, sizeof(int) * length);
+ }
+ else {
+ for (unsigned int i = 0; i < length; i++) {
+ values[i] = iprop->defaultvalue;
+ }
+ }
+}
+
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
@@ -2429,10 +2589,8 @@ void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
iprop->getarray(ptr, values);
else if (iprop->getarray_ex)
iprop->getarray_ex(ptr, prop, values);
- else if (iprop->defaultarray)
- memcpy(values, iprop->defaultarray, sizeof(int) * prop->totarraylength);
else
- memset(values, 0, sizeof(int) * prop->totarraylength);
+ rna_property_int_get_default_array_values(iprop, values);
}
void RNA_property_int_get_array_range(PointerRNA *ptr, PropertyRNA *prop, int values[2])
@@ -2580,10 +2738,8 @@ void RNA_property_int_get_default_array(PointerRNA *UNUSED(ptr), PropertyRNA *pr
if (prop->arraydimension == 0)
values[0] = iprop->defaultvalue;
- else if (iprop->defaultarray)
- memcpy(values, iprop->defaultarray, sizeof(int) * prop->totarraylength);
else
- memset(values, 0, sizeof(int) * prop->totarraylength);
+ rna_property_int_get_default_array_values(iprop, values);
}
int RNA_property_int_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
@@ -2673,6 +2829,20 @@ void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
}
}
+static void rna_property_float_get_default_array_values(FloatPropertyRNA *fprop, float *values)
+{
+ unsigned int length = fprop->property.totarraylength;
+
+ if (fprop->defaultarray) {
+ memcpy(values, fprop->defaultarray, sizeof(float) * length);
+ }
+ else {
+ for (unsigned int i = 0; i < length; i++) {
+ values[i] = fprop->defaultvalue;
+ }
+ }
+}
+
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
@@ -2700,10 +2870,8 @@ void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *val
fprop->getarray(ptr, values);
else if (fprop->getarray_ex)
fprop->getarray_ex(ptr, prop, values);
- else if (fprop->defaultarray)
- memcpy(values, fprop->defaultarray, sizeof(float) * prop->totarraylength);
else
- memset(values, 0, sizeof(float) * prop->totarraylength);
+ rna_property_float_get_default_array_values(fprop, values);
}
void RNA_property_float_get_array_range(PointerRNA *ptr, PropertyRNA *prop, float values[2])
@@ -2867,10 +3035,8 @@ void RNA_property_float_get_default_array(PointerRNA *UNUSED(ptr), PropertyRNA *
if (prop->arraydimension == 0)
values[0] = fprop->defaultvalue;
- else if (fprop->defaultarray)
- memcpy(values, fprop->defaultarray, sizeof(float) * prop->totarraylength);
else
- memset(values, 0, sizeof(float) * prop->totarraylength);
+ rna_property_float_get_default_array_values(fprop, values);
}
float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
@@ -4502,17 +4668,42 @@ static bool rna_path_parse_array_index(const char **path, PointerRNA *ptr, Prope
return true;
}
+/**
+ * Generic rna path parser.
+ *
+ * \note All parameters besides \a ptr and \a path are optional.
+ *
+ * \param ptr The root of given RNA path.
+ * \param path The RNA path.
+ * \param r_ptr The final RNA data holding the last property in \a path.
+ * \param r_prop The final property of \a r_ptr, from \a path.
+ * \param r_index The final index in the \a r_prop, if defined by \a path.
+ * \param r_item_ptr Only valid for Pointer and Collection, return the actual value of the pointer,
+ * or of the collection item. Mutually exclusive with \a eval_pointer option.
+ * \param r_elements A list of \a PropertyElemRNA items
+ * (pairs of \a PointerRNA, \a PropertyRNA that represent the whole given \a path).
+ * \param eval_pointer If \a true, and \a path leads to a Pointer property, or an item in a Collection property,
+ * \a r_ptr will be set to the value of that property, and \a r_prop will be NULL.
+ * Mutually exclusive with \a r_item_ptr.
+ * \return \a true on success, \a false if the path is somehow invalid.
+ */
static bool rna_path_parse(PointerRNA *ptr, const char *path,
PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index,
- ListBase *r_elements,
+ PointerRNA *r_item_ptr, ListBase *r_elements,
const bool eval_pointer)
{
+ BLI_assert(r_item_ptr == NULL || !eval_pointer);
PropertyRNA *prop;
- PointerRNA curptr;
+ PointerRNA curptr, nextptr;
PropertyElemRNA *prop_elem = NULL;
int index = -1;
char fixedbuf[256];
int type;
+ const bool do_item_ptr = r_item_ptr != NULL && !eval_pointer;
+
+ if (do_item_ptr) {
+ RNA_POINTER_INVALIDATE(&nextptr);
+ }
prop = NULL;
curptr = *ptr;
@@ -4521,20 +4712,26 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
return false;
while (*path) {
+ if (do_item_ptr) {
+ RNA_POINTER_INVALIDATE(&nextptr);
+ }
+
int use_id_prop = (*path == '[') ? 1 : 0;
char *token;
/* custom property lookup ?
* C.object["someprop"]
*/
- if (!curptr.data)
+ if (!curptr.data) {
return false;
+ }
/* look up property name in current struct */
token = rna_path_token(&path, fixedbuf, sizeof(fixedbuf), use_id_prop);
- if (!token)
+ if (!token) {
return false;
+ }
prop = NULL;
if (use_id_prop) { /* look up property name in current struct */
@@ -4546,11 +4743,13 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
prop = RNA_struct_find_property(&curptr, token);
}
- if (token != fixedbuf)
+ if (token != fixedbuf) {
MEM_freeN(token);
+ }
- if (!prop)
+ if (!prop) {
return false;
+ }
if (r_elements) {
prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__);
@@ -4570,9 +4769,11 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
/* resolve pointer if further path elements follow
* or explicitly requested
*/
- if (eval_pointer || *path) {
- PointerRNA nextptr = RNA_property_pointer_get(&curptr, prop);
+ if (do_item_ptr || eval_pointer || *path != '\0') {
+ nextptr = RNA_property_pointer_get(&curptr, prop);
+ }
+ if (eval_pointer || *path != '\0') {
curptr = nextptr;
prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
index = -1;
@@ -4582,17 +4783,18 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
case PROP_COLLECTION: {
/* Resolve pointer if further path elements follow.
* Note that if path is empty, rna_path_parse_collection_key will do nothing anyway,
- * so eval_pointer is of no use here (esp. as in this case, we want to keep found prop,
- * erasing it breaks operators - e.g. bpy.types.Operator.bl_rna.foobar errors...).
+ * so do_item_ptr is of no use in that case.
*/
if (*path) {
- PointerRNA nextptr;
- if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr))
+ if (!rna_path_parse_collection_key(&path, &curptr, prop, &nextptr)) {
return false;
+ }
- curptr = nextptr;
- prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
- index = -1;
+ if (eval_pointer || *path != '\0') {
+ curptr = nextptr;
+ prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
+ index = -1;
+ }
}
break;
}
@@ -4610,12 +4812,18 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
}
}
- if (r_ptr)
+ if (r_ptr) {
*r_ptr = curptr;
- if (r_prop)
+ }
+ if (r_prop) {
*r_prop = prop;
- if (r_index)
+ }
+ if (r_index) {
*r_index = index;
+ }
+ if (r_item_ptr && do_item_ptr) {
+ *r_item_ptr = nextptr;
+ }
if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || prop_elem->index != index)) {
prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__);
@@ -4636,7 +4844,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
*/
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, true))
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, true))
return false;
return r_ptr->data != NULL;
@@ -4650,7 +4858,7 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
*/
bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, true))
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, true))
return false;
return r_ptr->data != NULL;
@@ -4665,8 +4873,9 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr,
*/
bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, false))
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, NULL, false)) {
return false;
+ }
return r_ptr->data != NULL && *r_prop != NULL;
}
@@ -4681,13 +4890,51 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_
*/
bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, false))
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, NULL, false))
+ return false;
+
+ return r_ptr->data != NULL && *r_prop != NULL;
+}
+
+/**
+ * Resolve the given RNA Path to find both the pointer AND property indicated by fully resolving the path,
+ * and get the value of the Pointer property (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax, it combines both \a RNA_path_resolve and
+ * \a RNA_path_resolve_property in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_pointer The final Pointer or Collection item value. You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
+bool RNA_path_resolve_property_and_item_pointer(
+ PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, PointerRNA *r_item_ptr)
+{
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, r_item_ptr, NULL, false)) {
return false;
+ }
return r_ptr->data != NULL && *r_prop != NULL;
}
/**
+ * Resolve the given RNA Path to find both the pointer AND property (as well as the array index)
+ * indicated by fully resolving the path, and get the value of the Pointer property (or item of the collection).
+ *
+ * This is a convenience method to avoid logic errors and ugly syntax, it combines both \a RNA_path_resolve_full and
+ * \a RNA_path_resolve_property_full in a single call.
+ * \note Assumes all pointers provided are valid.
+ * \param r_item_pointer The final Pointer or Collection item value. You must check for its validity before use!
+ * \return True only if both a valid pointer and property are found after resolving the path
+ */
+bool RNA_path_resolve_property_and_item_pointer_full(
+ PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index, PointerRNA *r_item_ptr)
+{
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, r_item_ptr, NULL, false))
+ return false;
+
+ return r_ptr->data != NULL && *r_prop != NULL;
+}
+/**
* Resolve the given RNA Path into a linked list of PropertyElemRNA's.
*
* To be used when complex operations over path are needed, like e.g. get relative paths, to avoid too much
@@ -4698,7 +4945,7 @@ bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRN
*/
bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
{
- return rna_path_parse(ptr, path, NULL, NULL, NULL, r_elements, false);
+ return rna_path_parse(ptr, path, NULL, NULL, NULL, NULL, r_elements, false);
}
char *RNA_path_append(const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey)
@@ -6221,15 +6468,15 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSE
if (!(parm->flag_parameter & PARM_REQUIRED) && !(parm->flag & PROP_DYNAMIC)) {
switch (parm->type) {
case PROP_BOOLEAN:
- if (parm->arraydimension) memcpy(data, ((BoolPropertyRNA *)parm)->defaultarray, size);
+ if (parm->arraydimension) rna_property_boolean_get_default_array_values((BoolPropertyRNA *)parm, data);
else memcpy(data, &((BoolPropertyRNA *)parm)->defaultvalue, size);
break;
case PROP_INT:
- if (parm->arraydimension) memcpy(data, ((IntPropertyRNA *)parm)->defaultarray, size);
+ if (parm->arraydimension) rna_property_int_get_default_array_values((IntPropertyRNA *)parm, data);
else memcpy(data, &((IntPropertyRNA *)parm)->defaultvalue, size);
break;
case PROP_FLOAT:
- if (parm->arraydimension) memcpy(data, ((FloatPropertyRNA *)parm)->defaultarray, size);
+ if (parm->arraydimension) rna_property_float_get_default_array_values((FloatPropertyRNA *)parm, data);
else memcpy(data, &((FloatPropertyRNA *)parm)->defaultvalue, size);
break;
case PROP_ENUM:
@@ -7010,120 +7257,54 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
}
}
-bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
+static bool rna_property_override_operation_apply(
+ Main *bmain,
+ PointerRNA *ptr_local, PointerRNA *ptr_override, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_override, PropertyRNA *prop_storage,
+ PointerRNA *ptr_item_local, PointerRNA *ptr_item_override, PointerRNA *ptr_item_storage,
+ IDOverrideStaticPropertyOperation *opop);
+
+bool RNA_property_copy(Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
{
- int len, fromlen;
- PropertyRNA *fromprop = prop;
+ if (!RNA_property_editable(ptr, prop)) {
+ return false;
+ }
- if (prop->magic != RNA_MAGIC) {
- /* In case of IDProperty, we have to find the *real* idprop of ptr,
- * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
- prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name);
+ PropertyRNA *prop_dst = prop;
+ PropertyRNA *prop_src = prop;
- /* its possible the custom-prop doesn't exist on this data-block */
- if (prop == NULL) {
- return false;
- }
+ /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */
+ prop_dst = rna_ensure_property_realdata(&prop_dst, ptr);
+ prop_src = rna_ensure_property_realdata(&prop_src, fromptr);
- /* Even though currently we now prop will always be the 'fromprop', this might not be the case in the future. */
- if (prop == fromprop) {
- fromprop = (PropertyRNA *)rna_idproperty_find(fromptr, ((IDProperty *)prop)->name);
- }
+ /* IDprops: destination may not exist, if source does and is set, try to create it. */
+ /* Note: this is sort of quick hack/bandage to fix the issue, we need to rethink how IDProps are handled
+ * in 'diff' RNA code completely, imho... */
+ if (prop_src != NULL && prop_dst == NULL && RNA_property_is_set(fromptr, prop)) {
+ BLI_assert(prop_src->magic != RNA_MAGIC);
+ IDProperty *idp_dst = RNA_struct_idprops(ptr, true);
+ IDProperty *prop_idp_dst = IDP_CopyProperty((IDProperty *)prop_src);
+ IDP_AddToGroup(idp_dst, prop_idp_dst);
+ rna_idproperty_touch(prop_idp_dst);
+ /* Nothing else to do here... */
+ return true;
}
- /* get the length of the array to work with */
- len = RNA_property_array_length(ptr, prop);
- fromlen = RNA_property_array_length(fromptr, fromprop);
-
- if (len != fromlen)
+ if (ELEM(NULL, prop_dst, prop_src)) {
return false;
-
- /* get and set the default values as appropriate for the various types */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- if (len) {
- if (index == -1) {
- bool *tmparray = MEM_callocN(sizeof(bool) * len, "copy - boolean");
-
- RNA_property_boolean_get_array(fromptr, fromprop, tmparray);
- RNA_property_boolean_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- int value = RNA_property_boolean_get_index(fromptr, fromprop, index);
- RNA_property_boolean_set_index(ptr, prop, index, value);
- }
- }
- else {
- int value = RNA_property_boolean_get(fromptr, fromprop);
- RNA_property_boolean_set(ptr, prop, value);
- }
- return true;
- case PROP_INT:
- if (len) {
- if (index == -1) {
- int *tmparray = MEM_callocN(sizeof(int) * len, "copy - int");
-
- RNA_property_int_get_array(fromptr, fromprop, tmparray);
- RNA_property_int_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- int value = RNA_property_int_get_index(fromptr, fromprop, index);
- RNA_property_int_set_index(ptr, prop, index, value);
- }
- }
- else {
- int value = RNA_property_int_get(fromptr, fromprop);
- RNA_property_int_set(ptr, prop, value);
- }
- return true;
- case PROP_FLOAT:
- if (len) {
- if (index == -1) {
- float *tmparray = MEM_callocN(sizeof(float) * len, "copy - float");
-
- RNA_property_float_get_array(fromptr, fromprop, tmparray);
- RNA_property_float_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- float value = RNA_property_float_get_index(fromptr, fromprop, index);
- RNA_property_float_set_index(ptr, prop, index, value);
- }
- }
- else {
- float value = RNA_property_float_get(fromptr, fromprop);
- RNA_property_float_set(ptr, prop, value);
- }
- return true;
- case PROP_ENUM:
- {
- int value = RNA_property_enum_get(fromptr, fromprop);
- RNA_property_enum_set(ptr, prop, value);
- return true;
- }
- case PROP_POINTER:
- {
- PointerRNA value = RNA_property_pointer_get(fromptr, fromprop);
- RNA_property_pointer_set(ptr, prop, value);
- return true;
- }
- case PROP_STRING:
- {
- char *value = RNA_property_string_get_alloc(fromptr, fromprop, NULL, 0, NULL);
- RNA_property_string_set(ptr, prop, value);
- MEM_freeN(value);
- return true;
- }
- default:
- return false;
}
- return false;
+ IDOverrideStaticPropertyOperation opop = {
+ .operation = IDOVERRIDESTATIC_OP_REPLACE,
+ .subitem_reference_index = index,
+ .subitem_local_index = index
+ };
+ return rna_property_override_operation_apply(
+ bmain,
+ ptr, fromptr, NULL,
+ prop_dst, prop_src, NULL,
+ NULL, NULL, NULL,
+ &opop);
}
/* use RNA_warning macro which includes __func__ suffix */
@@ -7148,177 +7329,725 @@ void _RNA_warning(const char *format, ...)
#endif
}
-bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNAEqualsMode mode)
+static int rna_property_override_diff(
+ Main *bmain,
+ PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, PropertyRNA *prop_a, PropertyRNA *prop_b, const char *rna_path,
+ eRNACompareMode mode, IDOverrideStatic *override, const int flags, eRNAOverrideMatchResult *r_report_flags);
+
+bool RNA_property_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
+{
+ BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE));
+
+ return (rna_property_override_diff(bmain, ptr_a, ptr_b, prop, NULL, NULL, NULL, mode, NULL, 0, NULL) == 0);
+}
+
+bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode)
+{
+ CollectionPropertyIterator iter;
+ PropertyRNA *iterprop;
+ bool equals = true;
+
+ if (ptr_a == NULL && ptr_b == NULL)
+ return true;
+ else if (ptr_a == NULL || ptr_b == NULL)
+ return false;
+ else if (ptr_a->type != ptr_b->type)
+ return false;
+
+ iterprop = RNA_struct_iterator_property(ptr_a->type);
+
+ RNA_property_collection_begin(ptr_a, iterprop, &iter);
+ for (; iter.valid; RNA_property_collection_next(&iter)) {
+ PropertyRNA *prop = iter.ptr.data;
+
+ if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, mode)) {
+ equals = false;
+ break;
+ }
+ }
+ RNA_property_collection_end(&iter);
+
+ return equals;
+}
+
+/* Low-level functions, also used by non-override RNA API like copy or equality check. */
+
+/** Generic RNA property diff function.
+ *
+ * \note about \a prop and \a prop_a/prop_b parameters: the former is exptected to be an 'un-resolved' one,
+ * while the two laters are expected to be fully resolved ones (i.e. to be the IDProps when they should be, etc.).
+ * When \a prop is given, \a prop_a and \a prop_b should always be NULL, and vice-versa.
+ * This is necessary, because we cannot perform 'set/unset' checks on resolved properties
+ * (unset IDProps would merely be NULL then).
+ *
+ * \note When there is no equality, but we cannot determine an order (greater than/lesser than), we return 1.
+ */
+static int rna_property_override_diff(
+ Main *bmain,
+ PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, PropertyRNA *prop_a, PropertyRNA *prop_b,
+ const char *rna_path, eRNACompareMode mode,
+ IDOverrideStatic *override, const int flags, eRNAOverrideMatchResult *r_report_flags)
{
- int len, fromlen;
+ if (prop != NULL) {
+ BLI_assert(prop_a == NULL && prop_b == NULL);
+ prop_a = prop;
+ prop_b = prop;
+ }
+
+ if (ELEM(NULL, prop_a, prop_b)) {
+ return (prop_a == prop_b) ? 0 : 1;
+ }
+
+ if (!RNA_property_comparable(ptr_a, prop_a) || !RNA_property_comparable(ptr_b, prop_b)) {
+ return 0;
+ }
if (mode == RNA_EQ_UNSET_MATCH_ANY) {
/* uninitialized properties are assumed to match anything */
- if (!RNA_property_is_set(a, prop) || !RNA_property_is_set(b, prop))
- return true;
+ if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) {
+ return 0;
+ }
}
else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
/* unset properties never match set properties */
- if (RNA_property_is_set(a, prop) != RNA_property_is_set(b, prop))
- return false;
+ if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) {
+ return 1;
+ }
+ }
+
+ if (prop != NULL) {
+ /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */
+ prop_a = rna_ensure_property_realdata(&prop_a, ptr_a);
+ prop_b = rna_ensure_property_realdata(&prop_b, ptr_b);
+
+ if (ELEM(NULL, prop_a, prop_b)) {
+ return (prop_a == prop_b) ? 0 : 1;
+ }
+ }
+
+ /* Check if we are working with arrays. */
+ const bool is_array_a = RNA_property_array_check(prop_a);
+ const bool is_array_b = RNA_property_array_check(prop_b);
+
+ if (is_array_a != is_array_b) {
+ /* Should probably never happen actually... */
+ BLI_assert(0);
+ return is_array_a ? 1 : -1;
+ }
+
+ /* Get the length of the array to work with. */
+ const int len_a = RNA_property_array_length(ptr_a, prop_a);
+ const int len_b = RNA_property_array_length(ptr_b, prop_b);
+
+ if (len_a != len_b) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
+ return len_a > len_b ? 1 : -1;
+ }
+
+ if (is_array_a && len_a == 0) {
+ /* Empty arrays, will happen in some case with dynamic ones. */
+ return 0;
+ }
+
+ RNAPropOverrideDiff override_diff = NULL;
+ /* Special case for IDProps, we use default callback then. */
+ if (prop_a->magic != RNA_MAGIC) {
+ override_diff = rna_property_override_diff_default;
+ if (prop_b->magic == RNA_MAGIC && prop_b->override_diff != override_diff) {
+ override_diff = NULL;
+ }
+ }
+ else if (prop_b->magic != RNA_MAGIC) {
+ override_diff = rna_property_override_diff_default;
+ if (prop_a->override_diff != override_diff) {
+ override_diff = NULL;
+ }
+ }
+ else if (prop_a->override_diff == prop_b->override_diff) {
+ override_diff = prop_a->override_diff;
+ }
+
+ if (override_diff == NULL) {
+#ifndef NDEBUG
+ printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n",
+ rna_path ? rna_path : (prop_a->magic != RNA_MAGIC ? ((IDProperty *)prop_a)->name : prop_a->identifier),
+ prop_a->magic == RNA_MAGIC, prop_b->magic == RNA_MAGIC);
+#endif
+ BLI_assert(0);
+ return 1;
+ }
+
+ bool override_changed = false;
+ int diff_flags = flags;
+ if (!RNA_property_overridable_get(ptr_a, prop_a)) {
+ diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
+ }
+ const int diff = override_diff(
+ bmain,
+ ptr_a, ptr_b, prop_a, prop_b, len_a, len_b,
+ mode, override, rna_path, diff_flags, &override_changed);
+ if (override_changed && r_report_flags) {
+ *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
+ }
+
+ return diff;
+}
+
+/* Modify local data-block to make it ready for override application (only needed for diff operations, where we use
+ * the local data-block's data as second operand). */
+static bool rna_property_override_operation_store(
+ Main *bmain,
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage,
+ IDOverrideStaticProperty *op)
+{
+ int len_local, len_reference, len_storage = 0;
+ bool changed = false;
+
+ if (ptr_storage == NULL) {
+ return changed;
+ }
+
+ /* get the length of the array to work with */
+ len_local = RNA_property_array_length(ptr_local, prop_local);
+ len_reference = RNA_property_array_length(ptr_reference, prop_reference);
+ if (prop_storage) {
+ len_storage = RNA_property_array_length(ptr_storage, prop_storage);
+ }
+
+ if (len_local != len_reference || len_local != len_storage) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
+ return changed;
+ }
+
+ BLI_assert(prop_local->override_store == prop_reference->override_store &&
+ (!ptr_storage || prop_local->override_store == prop_storage->override_store) &&
+ prop_local->override_store != NULL);
+
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ /* Only needed for diff operations. */
+ if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) {
+ continue;
+ }
+
+ if (prop_local->override_store(
+ bmain,
+ ptr_local, ptr_reference, ptr_storage,
+ prop_local, prop_reference, prop_storage,
+ len_local, len_reference, len_storage,
+ opop))
+ {
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+static bool rna_property_override_operation_apply(
+ Main *bmain,
+ PointerRNA *ptr_local, PointerRNA *ptr_override, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_override, PropertyRNA *prop_storage,
+ PointerRNA *ptr_item_local, PointerRNA *ptr_item_override, PointerRNA *ptr_item_storage,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ int len_local, len_reference, len_storage = 0;
+
+ const short override_op = opop->operation;
+
+ if (override_op == IDOVERRIDESTATIC_OP_NOOP) {
+ return true;
+ }
+
+ if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !ptr_storage) {
+ /* We cannot apply 'diff' override operations without some reference storage.
+ * This should typically only happen at read time of .blend file... */
+ return false;
+ }
+
+ if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) {
+ /* We cannot apply 'diff' override operations without some reference storage.
+ * This should typically only happen at read time of .blend file... */
+ return false;
+ }
+
+ RNAPropOverrideApply override_apply = NULL;
+ /* Special case for IDProps, we use default callback then. */
+ if (prop_local->magic != RNA_MAGIC) {
+ override_apply = rna_property_override_apply_default;
+ if (prop_override->magic == RNA_MAGIC && prop_override->override_apply != override_apply) {
+ override_apply = NULL;
+ }
+ }
+ else if (prop_override->magic != RNA_MAGIC) {
+ override_apply = rna_property_override_apply_default;
+ if (prop_local->override_apply != override_apply) {
+ override_apply = NULL;
+ }
+ }
+ else if (prop_local->override_apply == prop_override->override_apply) {
+ override_apply = prop_local->override_apply;
+ }
+
+ if (ptr_storage && prop_storage->magic == RNA_MAGIC && prop_storage->override_apply != override_apply) {
+ override_apply = NULL;
+ }
+
+ if (override_apply == NULL) {
+#ifndef NDEBUG
+ printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n",
+ prop_local->magic != RNA_MAGIC ? ((IDProperty *)prop_local)->name : prop_local->identifier,
+ prop_local->magic == RNA_MAGIC, prop_override->magic == RNA_MAGIC);
+#endif
+ BLI_assert(0);
+ return false;
}
/* get the length of the array to work with */
- len = RNA_property_array_length(a, prop);
- fromlen = RNA_property_array_length(b, prop);
+ len_local = RNA_property_array_length(ptr_local, prop_local);
+ len_reference = RNA_property_array_length(ptr_override, prop_override);
+ if (ptr_storage) {
+ len_storage = RNA_property_array_length(ptr_storage, prop_storage);
+ }
- if (len != fromlen)
+ if (len_local != len_reference || (ptr_storage && len_local != len_storage)) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
return false;
+ }
/* get and set the default values as appropriate for the various types */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- {
- if (len) {
- bool fixed_a[16], fixed_b[16];
- bool *array_a, *array_b;
- bool equals;
+ return override_apply(
+ bmain,
+ ptr_local, ptr_override, ptr_storage,
+ prop_local, prop_override, prop_storage,
+ len_local, len_reference, len_storage,
+ ptr_item_local, ptr_item_override, ptr_item_storage,
+ opop);
+}
- array_a = (len > 16) ? MEM_mallocN(sizeof(bool) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(bool) * len, "RNA equals") : fixed_b;
+/**
+ * Check whether reference and local overridden data match (are the same),
+ * with respect to given restrictive sets of properties.
+ * If requested, will generate needed new property overrides, and/or restore values from reference.
+ *
+ * \param r_report_flags If given, will be set with flags matching actions taken by the function on \a ptr_local.
+ *
+ * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
+ */
+bool RNA_struct_override_matches(
+ Main *bmain,
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, const char *root_path,
+ IDOverrideStatic *override, const eRNAOverrideMatch flags,
+ eRNAOverrideMatchResult *r_report_flags)
+{
+ CollectionPropertyIterator iter;
+ PropertyRNA *iterprop;
+ bool matching = true;
+
+ BLI_assert(ptr_local->type == ptr_reference->type);
+ BLI_assert(ptr_local->id.data && ptr_reference->id.data);
+
+ const bool ignore_non_overridable = (flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE) != 0;
+ const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0;
+ const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
+ const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
+
+//#define DEBUG_OVERRIDE_TIMEIT
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ static float _sum_time_global = 0.0f;
+ static float _num_time_global = 0.0f;
+ double _timeit_time_global;
+ static float _sum_time_diffing = 0.0f;
+ static float _delta_time_diffing = 0.0f;
+ static int _num_delta_time_diffing = 0.0f;
+ static float _num_time_diffing = 0.0f;
+ double _timeit_time_diffing;
+
+ if (!root_path) {
+ _delta_time_diffing = 0.0f;
+ _num_delta_time_diffing = 0;
+ _timeit_time_global = PIL_check_seconds_timer();
+ }
+#endif
+
+ iterprop = RNA_struct_iterator_property(ptr_local->type);
+
+ for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) {
+ PropertyRNA *prop_local = iter.ptr.data;
+ PropertyRNA *prop_reference = iter.ptr.data;
- RNA_property_boolean_get_array(a, prop, array_a);
- RNA_property_boolean_get_array(b, prop, array_b);
+ /* Ensure we get real property data, be it an actual RNA property, or an IDProperty in disguise. */
+ prop_local = rna_ensure_property_realdata(&prop_local, ptr_local);
+ prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference);
- equals = memcmp(array_a, array_b, sizeof(bool) * len) == 0;
+ if (ELEM(NULL, prop_local, prop_reference)) {
+ continue;
+ }
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+ if (ignore_non_overridable && !RNA_property_overridable_get(ptr_local, prop_local)) {
+ continue;
+ }
- return equals;
+#if 0 /* This actually makes things slower, since it has to check for animation paths etc! */
+ if (RNA_property_animated(ptr_local, prop_local)) {
+ /* We cannot do anything here really, animation is some kind of dynamic overrides that has
+ * precedence over static one... */
+ continue;
+ }
+#endif
+
+#define RNA_PATH_BUFFSIZE 8192
+#define RNA_PATH_PRINTF(_str, ...) \
+ if (BLI_snprintf(rna_path, RNA_PATH_BUFFSIZE, \
+ (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE) \
+ { rna_path = BLI_sprintfN((_str), __VA_ARGS__); }(void)0
+#define RNA_PATH_FREE \
+ if (rna_path != rna_path_buffer) MEM_freeN(rna_path)
+
+ char rna_path_buffer[RNA_PATH_BUFFSIZE];
+ char *rna_path = rna_path_buffer;
+
+ /* XXX TODO this will have to be refined to handle collections insertions, and array items */
+ if (root_path) {
+ /* Inlined building, much much more efficient. */
+ if (prop_local->magic == RNA_MAGIC) {
+ RNA_PATH_PRINTF("%s.%s", root_path, RNA_property_identifier(prop_local));
}
else {
- int value = RNA_property_boolean_get(a, prop);
- return value == RNA_property_boolean_get(b, prop);
+ RNA_PATH_PRINTF("%s[\"%s\"]", root_path, RNA_property_identifier(prop_local));
}
}
+ else {
+ /* This is rather slow, but is not much called, so not really worth optimizing. */
+ rna_path = RNA_path_from_ID_to_property(ptr_local, prop_local);
+ }
+ if (rna_path == NULL) {
+ continue;
+ }
- case PROP_INT:
- {
- if (len) {
- int fixed_a[16], fixed_b[16];
- int *array_a, *array_b;
- bool equals;
+// printf("Override Checking %s\n", rna_path);
- array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b;
+ if (ignore_overridden && BKE_override_static_property_find(override, rna_path) != NULL) {
+ RNA_PATH_FREE;
+ continue;
+ }
- RNA_property_int_get_array(a, prop, array_a);
- RNA_property_int_get_array(b, prop, array_b);
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ if (!root_path) {
+ _timeit_time_diffing = PIL_check_seconds_timer();
+ }
+#endif
- equals = memcmp(array_a, array_b, sizeof(int) * len) == 0;
+ eRNAOverrideMatchResult report_flags = 0;
+ const int diff = rna_property_override_diff(
+ bmain,
+ ptr_local, ptr_reference, NULL, prop_local, prop_reference, rna_path,
+ RNA_EQ_STRICT, override, flags, &report_flags);
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ if (!root_path) {
+ const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time_diffing);
+ _delta_time_diffing += _delta_time;
+ _num_delta_time_diffing++;
+ }
+#endif
- return equals;
+ matching = matching && diff == 0;
+ if (r_report_flags) {
+ *r_report_flags |= report_flags;
+ }
+
+ if (diff != 0) {
+ /* XXX TODO: refine this for per-item overriding of arrays... */
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path);
+ IDOverrideStaticPropertyOperation *opop = op ? op->operations.first : NULL;
+
+ if (do_restore && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0) {
+ /* We are allowed to restore to reference's values. */
+ if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDESTATIC_OP_NOOP) {
+ /* We should restore that property to its reference value */
+ if (RNA_property_editable(ptr_local, prop_local)) {
+ IDOverrideStaticPropertyOperation opop_tmp = {
+ .operation = IDOVERRIDESTATIC_OP_REPLACE,
+ .subitem_reference_index = -1,
+ .subitem_local_index = -1
+ };
+ rna_property_override_operation_apply(
+ bmain,
+ ptr_local, ptr_reference, NULL,
+ prop_local, prop_reference, NULL,
+ NULL, NULL, NULL,
+ &opop_tmp);
+ if (r_report_flags) {
+ *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
+ }
+ }
+ else {
+ /* Too noisy for now, this triggers on runtime props like transform matrices etc. */
+ /* BLI_assert(!"We have differences between reference and overriding data on non-editable property."); */
+ matching = false;
+ }
+ }
}
- else {
- int value = RNA_property_int_get(a, prop);
- return value == RNA_property_int_get(b, prop);
+ else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(NULL, op, opop)) {
+ /* This property is not overridden, and differs from reference, so we have no match. */
+ matching = false;
+ if (!(do_create || do_restore)) {
+ /* Since we have no 'changing' action allowed, we can break here. */
+ MEM_SAFE_FREE(rna_path);
+ break;
+ }
}
}
- case PROP_FLOAT:
- {
- if (len) {
- float fixed_a[16], fixed_b[16];
- float *array_a, *array_b;
- bool equals;
+ RNA_PATH_FREE;
+
+#undef RNA_PATH_BUFFSIZE
+#undef RNA_PATH_PRINTF
+#undef RNA_PATH_FREE
+ }
+ RNA_property_collection_end(&iter);
- array_a = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_b;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ if (!root_path) {
+ const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time_global);
+ _sum_time_global += _delta_time;
+ _num_time_global++;
+ _sum_time_diffing += _delta_time_diffing;
+ _num_time_diffing++;
+ printf("ID: %s\n", ((ID *)ptr_local->id.data)->name);
+ printf("time end (%s): %.6f\n", __func__, _delta_time);
+ printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__,
+ (_sum_time_global / _num_time_global), _sum_time_global, (int)_num_time_global);
+ printf("diffing time end (%s): %.6f (in %d runs)\n", __func__, _delta_time_diffing, _num_delta_time_diffing);
+ printf("diffing time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__,
+ (_sum_time_diffing / _num_time_diffing), _sum_time_diffing, (int)_num_time_diffing);
+ }
+#endif
+
+ return matching;
+}
- RNA_property_float_get_array(a, prop, array_a);
- RNA_property_float_get_array(b, prop, array_b);
- equals = memcmp(array_a, array_b, sizeof(float) * len) == 0;
+/** Store needed second operands into \a storage data-block for differential override operations. */
+bool RNA_struct_override_store(
+ Main *bmain,
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, IDOverrideStatic *override)
+{
+ bool changed = false;
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(RNA_struct_override_store);
+#endif
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ /* Simplified for now! */
+ PointerRNA data_reference, data_local;
+ PropertyRNA *prop_reference, *prop_local;
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+ if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
+ RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference))
+ {
+ PointerRNA data_storage;
+ PropertyRNA *prop_storage = NULL;
- return equals;
+ /* It is totally OK if this does not success, only a subset of override operations actually need storage. */
+ if (ptr_storage && (ptr_storage->id.data != NULL)) {
+ RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
}
- else {
- float value = RNA_property_float_get(a, prop);
- return value == RNA_property_float_get(b, prop);
+
+ if (rna_property_override_operation_store(
+ bmain,
+ &data_local, &data_reference, &data_storage,
+ prop_reference, prop_local, prop_storage,
+ op))
+ {
+ changed = true;
}
}
+ }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(RNA_struct_override_store);
+#endif
- case PROP_ENUM:
- {
- int value = RNA_property_enum_get(a, prop);
- return value == RNA_property_enum_get(b, prop);
- }
+ return changed;
+}
- case PROP_STRING:
+static void rna_property_override_apply_ex(
+ Main *bmain,
+ PointerRNA *ptr_local, PointerRNA *ptr_override, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_override, PropertyRNA *prop_storage,
+ PointerRNA *ptr_item_local, PointerRNA *ptr_item_override, PointerRNA *ptr_item_storage,
+ IDOverrideStaticProperty *op, const bool do_insert)
+{
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ if (!do_insert != !ELEM(opop->operation, IDOVERRIDESTATIC_OP_INSERT_AFTER, IDOVERRIDESTATIC_OP_INSERT_BEFORE)) {
+ if (!do_insert) {
+ printf("Skipping insert override operations in first pass (%s)!\n", op->rna_path);
+ }
+ continue;
+ }
+ if (!rna_property_override_operation_apply(
+ bmain,
+ ptr_local, ptr_override, ptr_storage,
+ prop_local, prop_override, prop_storage,
+ ptr_item_local, ptr_item_override, ptr_item_storage,
+ opop))
{
- char fixed_a[128], fixed_b[128];
- int len_a, len_b;
- char *value_a = RNA_property_string_get_alloc(a, prop, fixed_a, sizeof(fixed_a), &len_a);
- char *value_b = RNA_property_string_get_alloc(b, prop, fixed_b, sizeof(fixed_b), &len_b);
- bool equals = STREQ(value_a, value_b);
+ /* TODO No assert here, would be much much better to just report as warning,
+ * failing override applications will probably be fairly common! */
+ BLI_assert(0);
+ }
+ }
+}
- if (value_a != fixed_a) MEM_freeN(value_a);
- if (value_b != fixed_b) MEM_freeN(value_b);
+/** Apply given \a override operations on \a ptr_local, using \a ptr_override
+ * (and \a ptr_storage form differential ops) as source. */
+void RNA_struct_override_apply(
+ Main *bmain,
+ PointerRNA *ptr_local, PointerRNA *ptr_override, PointerRNA *ptr_storage, IDOverrideStatic *override)
+{
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(RNA_struct_override_apply);
+#endif
+ /* Note: Applying insert operations in a separate pass is mandatory.
+ * We could optimize this later, but for now, as inneficient as it is, don't think this is a critical point.
+ */
+ bool do_insert = false;
+ for (int i = 0; i < 2; i++, do_insert = true) {
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ /* Simplified for now! */
+ PointerRNA data_override, data_local;
+ PointerRNA data_item_override, data_item_local;
+ PropertyRNA *prop_override, *prop_local;
+
+ if (RNA_path_resolve_property_and_item_pointer(
+ ptr_local, op->rna_path, &data_local, &prop_local, &data_item_local) &&
+ RNA_path_resolve_property_and_item_pointer(
+ ptr_override, op->rna_path, &data_override, &prop_override, &data_item_override))
+ {
+ PointerRNA data_storage, data_item_storage;
+ PropertyRNA *prop_storage = NULL;
- return equals;
- }
+ /* It is totally OK if this does not success, only a subset of override operations actually need storage. */
+ if (ptr_storage && (ptr_storage->id.data != NULL)) {
+ RNA_path_resolve_property_and_item_pointer(
+ ptr_storage, op->rna_path, &data_storage, &prop_storage, &data_item_storage);
+ }
- case PROP_POINTER:
- {
- if (!STREQ(RNA_property_identifier(prop), "rna_type")) {
- PointerRNA propptr_a = RNA_property_pointer_get(a, prop);
- PointerRNA propptr_b = RNA_property_pointer_get(b, prop);
- return RNA_struct_equals(&propptr_a, &propptr_b, mode);
+ rna_property_override_apply_ex(
+ bmain,
+ &data_local, &data_override, prop_storage ? &data_storage : NULL,
+ prop_local, prop_override, prop_storage,
+ &data_item_local, &data_item_override, prop_storage ? &data_item_storage : NULL,
+ op, do_insert);
}
- break;
+#ifndef NDEBUG
+ else {
+ printf("Failed to apply static override operation to '%s.%s' "
+ "(could not resolve some properties, local: %d, override: %d)\n",
+ ((ID *)ptr_override->id.data)->name, op->rna_path,
+ RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local),
+ RNA_path_resolve_property(ptr_override, op->rna_path, &data_override, &prop_override));
+ }
+#endif
}
+ }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(RNA_struct_override_apply);
+#endif
+}
- default:
- break;
+IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop)
+{
+ ID *id = ptr->id.data;
+
+ if (!id || !id->override_static) {
+ return NULL;
}
- return true;
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path) {
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(id->override_static, rna_path);
+ MEM_freeN(rna_path);
+ return op;
+ }
+ return NULL;
}
-bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode)
+IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created)
{
- CollectionPropertyIterator iter;
-// CollectionPropertyRNA *citerprop; /* UNUSED */
- PropertyRNA *iterprop;
- bool equals = true;
+ ID *id = ptr->id.data;
- if (a == NULL && b == NULL)
- return true;
- else if (a == NULL || b == NULL)
- return false;
- else if (a->type != b->type)
- return false;
+ if (!id || !id->override_static) {
+ return NULL;
+ }
- iterprop = RNA_struct_iterator_property(a->type);
-// citerprop = (CollectionPropertyRNA *)rna_ensure_property(iterprop); /* UNUSED */
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path) {
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(id->override_static, rna_path, r_created);
+ MEM_freeN(rna_path);
+ return op;
+ }
+ return NULL;
+}
- RNA_property_collection_begin(a, iterprop, &iter);
- for (; iter.valid; RNA_property_collection_next(&iter)) {
- PropertyRNA *prop = iter.ptr.data;
+IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find(
+ PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict)
+{
+ IDOverrideStaticProperty *op = RNA_property_override_property_find(ptr, prop);
- if (!RNA_property_equals(a, b, prop, mode)) {
- equals = false;
- break;
+ if (!op) {
+ return NULL;
+ }
+
+ return BKE_override_static_property_operation_find(op, NULL, NULL, index, index, strict, r_strict);
+}
+
+IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
+ PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
+ const bool strict, bool *r_strict, bool *r_created)
+{
+ IDOverrideStaticProperty *op = RNA_property_override_property_get(ptr, prop, NULL);
+
+ if (!op) {
+ return NULL;
+ }
+
+ return BKE_override_static_property_operation_get(op, operation, NULL, NULL, index, index, strict, r_strict, r_created);
+}
+
+eRNAOverrideStatus RNA_property_static_override_status(PointerRNA *ptr, PropertyRNA *prop, const int index)
+{
+ int override_status = 0;
+
+ if (!BKE_override_static_is_enabled()) {
+ return override_status;
+ }
+
+ if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_static) {
+ return override_status;
+ }
+
+ if (RNA_property_overridable_get(ptr, prop) && RNA_property_editable_flag(ptr, prop)) {
+ override_status |= RNA_OVERRIDE_STATUS_OVERRIDABLE;
+ }
+
+ IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL);
+ if (opop != NULL) {
+ override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN;
+ if (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) {
+ override_status |= RNA_OVERRIDE_STATUS_MANDATORY;
+ }
+ if (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) {
+ override_status |= RNA_OVERRIDE_STATUS_LOCKED;
}
}
- RNA_property_collection_end(&iter);
- return equals;
+ return override_status;
}
+
bool RNA_path_resolved_create(
PointerRNA *ptr, struct PropertyRNA *prop,
const int prop_index,
@@ -7337,3 +8066,22 @@ bool RNA_path_resolved_create(
return false;
}
}
+
+static char rna_struct_state_owner[64];
+void RNA_struct_state_owner_set(const char *name)
+{
+ if (name) {
+ BLI_strncpy(rna_struct_state_owner, name, sizeof(rna_struct_state_owner));
+ }
+ else {
+ rna_struct_state_owner[0] = '\0';
+ }
+}
+
+const char *RNA_struct_state_owner_get(void)
+{
+ if (rna_struct_state_owner[0]) {
+ return rna_struct_state_owner;
+ }
+ return NULL;
+}
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 675ed42a6d2..8728f0634da 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -102,7 +102,7 @@ static void rna_Action_groups_remove(bAction *act, ReportList *reports, PointerR
RNA_POINTER_INVALIDATE(agrp_ptr);
}
-static FCurve *rna_Action_fcurve_new(bAction *act, ReportList *reports, const char *data_path,
+static FCurve *rna_Action_fcurve_new(bAction *act, Main *bmain, ReportList *reports, const char *data_path,
int index, const char *group)
{
if (group && group[0] == '\0') group = NULL;
@@ -113,12 +113,12 @@ static FCurve *rna_Action_fcurve_new(bAction *act, ReportList *reports, const ch
}
/* annoying, check if this exists */
- if (verify_fcurve(act, group, NULL, data_path, index, 0)) {
+ if (verify_fcurve(bmain, act, group, NULL, data_path, index, 0)) {
BKE_reportf(reports, RPT_ERROR, "F-Curve '%s[%d]' already exists in action '%s'", data_path,
index, act->id.name + 2);
return NULL;
}
- return verify_fcurve(act, group, NULL, data_path, index, 1);
+ return verify_fcurve(bmain, act, group, NULL, data_path, index, 1);
}
static FCurve *rna_Action_fcurve_find(bAction *act, ReportList *reports, const char *data_path, int index)
@@ -322,49 +322,30 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_only_errors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLY_ERRORS);
RNA_def_property_ui_text(prop, "Show Errors", "Only include F-Curves and drivers that are disabled or have errors");
- RNA_def_property_ui_icon(prop, ICON_HELP, 0); /* XXX: this doesn't quite fit */
+ RNA_def_property_ui_icon(prop, ICON_ERROR, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
- /* Object Group Filtering Settings */
- prop = RNA_def_property(srna, "show_only_group_objects", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLYOBGROUP);
- RNA_def_property_ui_text(prop, "Only Objects in Group",
- "Only include channels from objects in the specified group");
- RNA_def_property_ui_icon(prop, ICON_GROUP, 0);
- RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
- prop = RNA_def_property(srna, "filter_group", PROP_POINTER, PROP_NONE);
+ /* Object Collection Filtering Settings */
+ prop = RNA_def_property(srna, "filter_collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "filter_grp");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Filtering Group", "Group that included object should be a member of");
+ RNA_def_property_ui_text(prop, "Filtering Collection", "Collection that included object should be a member of");
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
/* FCurve Display Name Search Settings */
- prop = RNA_def_property(srna, "show_only_matching_fcurves", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_BY_FCU_NAME);
- RNA_def_property_ui_text(prop, "Only Matching F-Curves",
- "Only include F-Curves with names containing search text");
- RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0);
- RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
prop = RNA_def_property(srna, "filter_fcurve_name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "searchstr");
RNA_def_property_ui_text(prop, "F-Curve Name Filter", "F-Curve live filtering string");
+ RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0);
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
/* NLA Name Search Settings (Shared with FCurve setting, but with different labels) */
- prop = RNA_def_property(srna, "use_filter_text", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_BY_FCU_NAME);
- RNA_def_property_ui_text(prop, "Only Matching Channels",
- "Only include channels with names containing search text");
- RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0);
- RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
-
prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "searchstr");
RNA_def_property_ui_text(prop, "Name Filter", "Live filtering string");
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
+ RNA_def_property_ui_icon(prop, ICON_VIEWZOOM, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
/* Multi-word fuzzy search option for name/text filters */
@@ -402,7 +383,7 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOOBJ);
RNA_def_property_ui_text(prop, "Display Transforms",
"Include visualization of object-level animation data (mostly transforms)");
- RNA_def_property_ui_icon(prop, ICON_MANIPUL, 0); /* XXX? */
+ RNA_def_property_ui_icon(prop, ICON_ORIENTATION_GLOBAL, 0); /* XXX? */
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_shapekeys", PROP_BOOLEAN, PROP_NONE);
@@ -421,19 +402,19 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_meshes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOMESH);
RNA_def_property_ui_text(prop, "Display Meshes", "Include visualization of mesh related animation data");
- RNA_def_property_ui_icon(prop, ICON_MESH_DATA, 0);
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_MESH, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_lattices", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOLAT);
RNA_def_property_ui_text(prop, "Display Lattices", "Include visualization of lattice related animation data");
- RNA_def_property_ui_icon(prop, ICON_LATTICE_DATA, 0);
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_LATTICE, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_cameras", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOCAM);
RNA_def_property_ui_text(prop, "Display Camera", "Include visualization of camera related animation data");
- RNA_def_property_ui_icon(prop, ICON_CAMERA_DATA, 0);
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_CAMERA, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_materials", PROP_BOOLEAN, PROP_NONE);
@@ -442,10 +423,10 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_MATERIAL_DATA, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
- prop = RNA_def_property(srna, "show_lamps", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOLAM);
- RNA_def_property_ui_text(prop, "Display Lamp", "Include visualization of lamp related animation data");
- RNA_def_property_ui_icon(prop, ICON_LAMP_DATA, 0);
+ RNA_def_property_ui_text(prop, "Display Light", "Include visualization of light related animation data");
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_LIGHT, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_linestyles", PROP_BOOLEAN, PROP_NONE);
@@ -487,13 +468,13 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_metaballs", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOMBA);
RNA_def_property_ui_text(prop, "Display Metaball", "Include visualization of metaball related animation data");
- RNA_def_property_ui_icon(prop, ICON_META_DATA, 0);
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_META, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_armatures", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOARM);
RNA_def_property_ui_text(prop, "Display Armature", "Include visualization of armature related animation data");
- RNA_def_property_ui_icon(prop, ICON_ARMATURE_DATA, 0);
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_ARMATURE, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_nodes", PROP_BOOLEAN, PROP_NONE);
@@ -505,13 +486,13 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_speakers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOSPK);
RNA_def_property_ui_text(prop, "Display Speaker", "Include visualization of speaker related animation data");
- RNA_def_property_ui_icon(prop, ICON_SPEAKER, 0);
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_SPEAKER, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_gpencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOGPENCIL);
RNA_def_property_ui_text(prop, "Display Grease Pencil", "Include visualization of Grease Pencil related animation data and frames");
- RNA_def_property_ui_icon(prop, ICON_GREASEPENCIL, 0);
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_OB_GREASEPENCIL, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
/* GPencil Mode Settings */
@@ -617,7 +598,7 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
/* Action.fcurves.new(...) */
func = RNA_def_function(srna, "new", "rna_Action_fcurve_new");
RNA_def_function_ui_description(func, "Add an F-Curve to the action");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path to use");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
deleted file mode 100644
index 6f0ff9aa556..00000000000
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ /dev/null
@@ -1,2220 +0,0 @@
-/*
- * ***** 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): Blender Foundation (2008).
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/makesrna/intern/rna_actuator.c
- * \ingroup RNA
- */
-
-
-#include <stdlib.h>
-
-#include "DNA_constraint_types.h"
-#include "DNA_object_types.h"
-#include "DNA_actuator_types.h"
-#include "DNA_scene_types.h" /* for MAXFRAME */
-
-#include "BLI_math.h"
-#include "BLI_string_utils.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "RNA_define.h"
-#include "RNA_access.h"
-#include "RNA_enum_types.h"
-
-#include "rna_internal.h"
-
-#include "WM_types.h"
-
-/* Always keep in alphabetical order */
-static const EnumPropertyItem actuator_type_items[] = {
- {ACT_ACTION, "ACTION", 0, "Action", ""},
- {ACT_ARMATURE, "ARMATURE", 0, "Armature", ""},
- {ACT_CAMERA, "CAMERA", 0, "Camera", ""},
- {ACT_CONSTRAINT, "CONSTRAINT", 0, "Constraint", ""},
- {ACT_EDIT_OBJECT, "EDIT_OBJECT", 0, "Edit Object", ""},
- {ACT_2DFILTER, "FILTER_2D", 0, "Filter 2D", ""},
- {ACT_GAME, "GAME", 0, "Game", ""},
- {ACT_MESSAGE, "MESSAGE", 0, "Message", ""},
- {ACT_OBJECT, "MOTION", 0, "Motion", ""},
- {ACT_MOUSE, "MOUSE", 0, "Mouse", ""},
- {ACT_PARENT, "PARENT", 0, "Parent", ""},
- {ACT_PROPERTY, "PROPERTY", 0, "Property", ""},
- {ACT_RANDOM, "RANDOM", 0, "Random", ""},
- {ACT_SCENE, "SCENE", 0, "Scene", ""},
- {ACT_SOUND, "SOUND", 0, "Sound", ""},
- {ACT_STATE, "STATE", 0, "State", ""},
- {ACT_STEERING, "STEERING", 0, "Steering", ""},
- {ACT_VISIBILITY, "VISIBILITY", 0, "Visibility", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_sca.h"
-
-static StructRNA *rna_Actuator_refine(struct PointerRNA *ptr)
-{
- bActuator *actuator = (bActuator *)ptr->data;
-
- switch (actuator->type) {
- case ACT_ACTION:
- return &RNA_ActionActuator;
- case ACT_OBJECT:
- return &RNA_ObjectActuator;
- case ACT_CAMERA:
- return &RNA_CameraActuator;
- case ACT_SOUND:
- return &RNA_SoundActuator;
- case ACT_PROPERTY:
- return &RNA_PropertyActuator;
- case ACT_CONSTRAINT:
- return &RNA_ConstraintActuator;
- case ACT_EDIT_OBJECT:
- return &RNA_EditObjectActuator;
- case ACT_SCENE:
- return &RNA_SceneActuator;
- case ACT_RANDOM:
- return &RNA_RandomActuator;
- case ACT_MESSAGE:
- return &RNA_MessageActuator;
- case ACT_GAME:
- return &RNA_GameActuator;
- case ACT_VISIBILITY:
- return &RNA_VisibilityActuator;
- case ACT_2DFILTER:
- return &RNA_Filter2DActuator;
- case ACT_PARENT:
- return &RNA_ParentActuator;
- case ACT_STATE:
- return &RNA_StateActuator;
- case ACT_ARMATURE:
- return &RNA_ArmatureActuator;
- case ACT_STEERING:
- return &RNA_SteeringActuator;
- case ACT_MOUSE:
- return &RNA_MouseActuator;
- default:
- return &RNA_Actuator;
- }
-}
-
-static void rna_Actuator_name_set(PointerRNA *ptr, const char *value)
-{
- Object *ob = ptr->id.data;
- bActuator *act = ptr->data;
- BLI_strncpy_utf8(act->name, value, sizeof(act->name));
- BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
-}
-
-static void rna_Actuator_type_set(struct PointerRNA *ptr, int value)
-{
- bActuator *act = (bActuator *)ptr->data;
-
- if (value != act->type) {
- act->type = value;
- init_actuator(act);
- }
-}
-
-static void rna_ConstraintActuator_type_set(struct PointerRNA *ptr, int value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
-
- if (value != ca->type) {
- ca->type = value;
- switch (ca->type) {
- case ACT_CONST_TYPE_ORI:
- /* negative axis not supported in the orientation mode */
- if (ELEM(ca->mode, ACT_CONST_DIRNX, ACT_CONST_DIRNY, ACT_CONST_DIRNZ))
- ca->mode = ACT_CONST_NONE;
- break;
-
- case ACT_CONST_TYPE_LOC:
- case ACT_CONST_TYPE_DIST:
- case ACT_CONST_TYPE_FH:
- default:
- break;
- }
- }
-}
-
-static float rna_ConstraintActuator_limitmin_get(struct PointerRNA *ptr)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->flag & ACT_CONST_LOCX) fp = ca->minloc;
- else if (ca->flag & ACT_CONST_LOCY) fp = ca->minloc + 1;
- else if (ca->flag & ACT_CONST_LOCZ) fp = ca->minloc + 2;
- else if (ca->flag & ACT_CONST_ROTX) fp = ca->minrot;
- else if (ca->flag & ACT_CONST_ROTY) fp = ca->minrot + 1;
- else fp = ca->minrot + 2;
-
- return *fp;
-}
-
-static void rna_ConstraintActuator_limitmin_set(struct PointerRNA *ptr, float value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->flag & ACT_CONST_LOCX) fp = ca->minloc;
- else if (ca->flag & ACT_CONST_LOCY) fp = ca->minloc + 1;
- else if (ca->flag & ACT_CONST_LOCZ) fp = ca->minloc + 2;
- else if (ca->flag & ACT_CONST_ROTX) fp = ca->minrot;
- else if (ca->flag & ACT_CONST_ROTY) fp = ca->minrot + 1;
- else fp = ca->minrot + 2;
-
- *fp = value;
-}
-
-static float rna_ConstraintActuator_limitmax_get(struct PointerRNA *ptr)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->flag & ACT_CONST_LOCX) fp = ca->maxloc;
- else if (ca->flag & ACT_CONST_LOCY) fp = ca->maxloc + 1;
- else if (ca->flag & ACT_CONST_LOCZ) fp = ca->maxloc + 2;
- else if (ca->flag & ACT_CONST_ROTX) fp = ca->maxrot;
- else if (ca->flag & ACT_CONST_ROTY) fp = ca->maxrot + 1;
- else fp = ca->maxrot + 2;
-
- return *fp;
-}
-
-static void rna_ConstraintActuator_limitmax_set(struct PointerRNA *ptr, float value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->flag & ACT_CONST_LOCX) fp = ca->maxloc;
- else if (ca->flag & ACT_CONST_LOCY) fp = ca->maxloc + 1;
- else if (ca->flag & ACT_CONST_LOCZ) fp = ca->maxloc + 2;
- else if (ca->flag & ACT_CONST_ROTX) fp = ca->maxrot;
- else if (ca->flag & ACT_CONST_ROTY) fp = ca->maxrot + 1;
- else fp = ca->maxrot + 2;
-
- *fp = value;
-}
-
-static float rna_ConstraintActuator_distance_get(struct PointerRNA *ptr)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->mode & (ACT_CONST_DIRPX | ACT_CONST_DIRNX)) fp = ca->minloc;
- else if (ca->mode & (ACT_CONST_DIRPY | ACT_CONST_DIRNY)) fp = ca->minloc + 1;
- else fp = ca->minloc + 2;
-
- return *fp;
-}
-
-static void rna_ConstraintActuator_distance_set(struct PointerRNA *ptr, float value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->mode & (ACT_CONST_DIRPX | ACT_CONST_DIRNX)) fp = ca->minloc;
- else if (ca->mode & (ACT_CONST_DIRPY | ACT_CONST_DIRNY)) fp = ca->minloc + 1;
- else fp = ca->minloc + 2;
-
- *fp = value;
-}
-
-static float rna_ConstraintActuator_range_get(struct PointerRNA *ptr)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->mode & (ACT_CONST_DIRPX | ACT_CONST_DIRNX)) fp = ca->maxloc;
- else if (ca->mode & (ACT_CONST_DIRPY | ACT_CONST_DIRNY)) fp = ca->maxloc + 1;
- else fp = ca->maxloc + 2;
-
- return *fp;
-}
-
-static void rna_ConstraintActuator_range_set(struct PointerRNA *ptr, float value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->mode & (ACT_CONST_DIRPX | ACT_CONST_DIRNX)) fp = ca->maxloc;
- else if (ca->mode & (ACT_CONST_DIRPY | ACT_CONST_DIRNY)) fp = ca->maxloc + 1;
- else fp = ca->maxloc + 2;
-
- *fp = value;
-}
-
-static float rna_ConstraintActuator_fhheight_get(struct PointerRNA *ptr)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->mode & (ACT_CONST_DIRPX | ACT_CONST_DIRNX)) fp = ca->minloc;
- else if (ca->mode & (ACT_CONST_DIRPY | ACT_CONST_DIRNY)) fp = ca->minloc + 1;
- else fp = ca->minloc + 2;
-
- return *fp;
-}
-
-static void rna_ConstraintActuator_fhheight_set(struct PointerRNA *ptr, float value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->mode & (ACT_CONST_DIRPX | ACT_CONST_DIRNX)) fp = ca->minloc;
- else if (ca->mode & (ACT_CONST_DIRPY | ACT_CONST_DIRNY)) fp = ca->minloc + 1;
- else fp = ca->minloc + 2;
-
- *fp = value;
-}
-
-static float rna_ConstraintActuator_spring_get(struct PointerRNA *ptr)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->mode & (ACT_CONST_DIRPX | ACT_CONST_DIRNX)) fp = ca->maxloc;
- else if (ca->mode & (ACT_CONST_DIRPY | ACT_CONST_DIRNY)) fp = ca->maxloc + 1;
- else fp = ca->maxloc + 2;
-
- return *fp;
-}
-
-static void rna_ConstraintActuator_spring_set(struct PointerRNA *ptr, float value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
- float *fp;
-
- if (ca->mode & (ACT_CONST_DIRPX | ACT_CONST_DIRNX)) fp = ca->maxloc;
- else if (ca->mode & (ACT_CONST_DIRPY | ACT_CONST_DIRNY)) fp = ca->maxloc + 1;
- else fp = ca->maxloc + 2;
-
- *fp = value;
-}
-/* ConstraintActuator uses the same property for Material and Property.
- * Therefore we need to clear the property when "use_material_detect" mode changes */
-static void rna_Actuator_constraint_detect_material_set(struct PointerRNA *ptr, bool value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bConstraintActuator *ca = act->data;
-
- short old_value = (ca->flag & ACT_CONST_MATERIAL) ? 1 : 0;
-
- if (old_value != value) {
- ca->flag ^= ACT_CONST_MATERIAL;
- ca->matprop[0] = '\0';
- }
-}
-
-static void rna_ActionActuator_add_set(struct PointerRNA *ptr, bool value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bActionActuator *aa = act->data;
-
- if (value) {
- aa->flag &= ~ACT_IPOFORCE;
- aa->flag |= ACT_IPOADD;
- }
- else {
- aa->flag &= ~ACT_IPOADD;
- }
-}
-
-static void rna_ActionActuator_force_set(struct PointerRNA *ptr, bool value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bActionActuator *aa = act->data;
-
- if (value) {
- aa->flag &= ~ACT_IPOADD;
- aa->flag |= ACT_IPOFORCE;
- }
- else {
- aa->flag &= ~ACT_IPOFORCE;
- }
-}
-
-static void rna_ObjectActuator_type_set(struct PointerRNA *ptr, int value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bObjectActuator *oa = act->data;
- if (value != oa->type) {
- oa->type = value;
- switch (oa->type) {
- case ACT_OBJECT_NORMAL:
- memset(oa, 0, sizeof(bObjectActuator));
- oa->flag = ACT_FORCE_LOCAL | ACT_TORQUE_LOCAL | ACT_DLOC_LOCAL | ACT_DROT_LOCAL;
- oa->type = ACT_OBJECT_NORMAL;
- break;
-
- case ACT_OBJECT_SERVO:
- memset(oa, 0, sizeof(bObjectActuator));
- oa->flag = ACT_LIN_VEL_LOCAL;
- oa->type = ACT_OBJECT_SERVO;
- oa->forcerot[0] = 30.0f;
- oa->forcerot[1] = 0.5f;
- oa->forcerot[2] = 0.0f;
- break;
-
- case ACT_OBJECT_CHARACTER:
- memset(oa, 0, sizeof(bObjectActuator));
- oa->flag = ACT_DLOC_LOCAL | ACT_DROT_LOCAL;
- oa->type = ACT_OBJECT_CHARACTER;
- break;
- }
- }
-}
-
-static void rna_ObjectActuator_integralcoefficient_set(struct PointerRNA *ptr, float value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bObjectActuator *oa = act->data;
-
- oa->forcerot[1] = value;
- oa->forcerot[0] = 60.0f * oa->forcerot[1];
-}
-
-static void rna_StateActuator_state_set(PointerRNA *ptr, const bool *values)
-{
- bActuator *act = (bActuator *)ptr->data;
- bStateActuator *sa = act->data;
-
- int i, tot = 0;
-
- /* ensure we always have some state selected */
- for (i = 0; i < OB_MAX_STATES; i++)
- if (values[i])
- tot++;
-
- if (tot == 0)
- return;
-
- for (i = 0; i < OB_MAX_STATES; i++) {
- if (values[i]) sa->mask |= (1 << i);
- else sa->mask &= ~(1 << i);
- }
-}
-
-/* Always keep in alphabetical order */
-const EnumPropertyItem *rna_Actuator_type_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem *item = NULL;
- Object *ob = NULL;
- int totitem = 0;
-
- if (ptr->type == &RNA_Actuator || RNA_struct_is_a(ptr->type, &RNA_Actuator)) {
- ob = (Object *)ptr->id.data;
- }
- else {
- /* can't use ob from ptr->id.data because that enum is also used by operators */
- ob = CTX_data_active_object(C);
- }
-
- if (ob != NULL) {
- if (ob->type == OB_ARMATURE) {
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_ARMATURE);
- }
- }
-
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_ACTION);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_CAMERA);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_CONSTRAINT);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_EDIT_OBJECT);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_2DFILTER);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_GAME);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_MESSAGE);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_MOUSE);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_OBJECT);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_PARENT);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_PROPERTY);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_RANDOM);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_SCENE);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_STEERING);
-
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_SOUND);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_STATE);
- RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_VISIBILITY);
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-static void rna_Actuator_Armature_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- bActuator *act = (bActuator *)ptr->data;
- bArmatureActuator *aa = act->data;
- Object *ob = (Object *)ptr->id.data;
-
- char *posechannel = aa->posechannel;
- char *constraint = aa->constraint;
-
- /* check that bone exist in the active object */
- if (ob->type == OB_ARMATURE && ob->pose) {
- bPoseChannel *pchan;
- bPose *pose = ob->pose;
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (STREQ(pchan->name, posechannel)) {
- /* found it, now look for constraint channel */
- bConstraint *con;
- for (con = pchan->constraints.first; con; con = con->next) {
- if (STREQ(con->name, constraint)) {
- /* found it, all ok */
- return;
- }
- }
- /* didn't find constraint, make empty */
- constraint[0] = 0;
- return;
- }
- }
- }
- /* didn't find any */
- posechannel[0] = 0;
- constraint[0] = 0;
-}
-
-static void rna_SteeringActuator_navmesh_set(PointerRNA *ptr, PointerRNA value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bSteeringActuator *sa = (bSteeringActuator *) act->data;
-
- Object *obj = value.data;
- if (obj && obj->body_type == OB_BODY_TYPE_NAVMESH)
- sa->navmesh = obj;
- else
- sa->navmesh = NULL;
-}
-
-/* note: the following set functions exists only to avoid id refcounting */
-static void rna_Actuator_editobject_mesh_set(PointerRNA *ptr, PointerRNA value)
-{
- bActuator *act = (bActuator *)ptr->data;
- bEditObjectActuator *eoa = (bEditObjectActuator *) act->data;
-
- eoa->me = value.data;
-}
-
-#else
-
-static void rna_def_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "Actuator", NULL);
- RNA_def_struct_ui_text(srna, "Actuator", "Actuator to apply actions in the game engine");
- RNA_def_struct_sdna(srna, "bActuator");
- RNA_def_struct_refine_func(srna, "rna_Actuator_refine");
-
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Name", "");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Actuator_name_set");
- RNA_def_struct_name_property(srna, prop);
-
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, actuator_type_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Actuator_type_set", "rna_Actuator_type_itemf");
- RNA_def_property_ui_text(prop, "Type", "");
-
- prop = RNA_def_property(srna, "pin", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_PIN);
- RNA_def_property_ui_text(prop, "Pinned", "Display when not linked to a visible states controller");
- RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SHOW);
- RNA_def_property_ui_text(prop, "Expanded", "Set actuator expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
-
- prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ACT_DEACTIVATE);
- RNA_def_property_ui_text(prop, "Active", "Set the active state of the actuator");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- RNA_api_actuator(srna);
-}
-
-static void rna_def_action_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_ACTION_PLAY, "PLAY", 0, "Play", ""},
- {ACT_ACTION_PINGPONG, "PINGPONG", 0, "Ping Pong", ""},
- {ACT_ACTION_FLIPPER, "FLIPPER", 0, "Flipper", ""},
- {ACT_ACTION_LOOP_STOP, "LOOPSTOP", 0, "Loop Stop", ""},
- {ACT_ACTION_LOOP_END, "LOOPEND", 0, "Loop End", ""},
- {ACT_ACTION_FROM_PROP, "PROPERTY", 0, "Property", ""},
-#ifdef __NLA_ACTION_BY_MOTION_ACTUATOR
- {ACT_ACTION_MOTION, "MOTION", 0, "Displacement", ""},
-#endif
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_blend_items[] = {
- {ACT_ACTION_BLEND, "BLEND", 0, "Blend", ""},
- {ACT_ACTION_ADD, "ADD", 0, "Add", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "ActionActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Action Actuator", "Actuator to control the object movement");
- RNA_def_struct_sdna_from(srna, "bActionActuator", "data");
-
- prop = RNA_def_property(srna, "play_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Action Type", "Action playback type");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "act");
- RNA_def_property_struct_type(prop, "Action");
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Action", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_continue_last_frame", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "end_reset", 1);
- RNA_def_property_ui_text(prop, "Continue",
- "Restore last frame when switching on/off, otherwise play from the start each time");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Property", "Use this property to define the Action position");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sta");
- RNA_def_property_ui_range(prop, 0.0, MAXFRAME, 100, 2);
- RNA_def_property_ui_text(prop, "Start Frame", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "end");
- RNA_def_property_ui_range(prop, 0.0, MAXFRAME, 100, 2);
- RNA_def_property_ui_text(prop, "End Frame", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "frame_blend_in", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "blendin");
- RNA_def_property_range(prop, 0, 32767);
- RNA_def_property_ui_text(prop, "Blendin", "Number of frames of motion blending");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "priority", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 100);
- RNA_def_property_ui_text(prop, "Priority",
- "Execution priority - lower numbers will override actions with higher numbers "
- "(with 2 or more actions at once, the overriding channels must be lower in the stack)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "layer", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 32766); /* This should match BL_ActionManager::MAX_ACTION_LAYERS - 1 */
- RNA_def_property_ui_text(prop, "Layer", "The animation layer to play the action on");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "layer_weight", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_text(prop, "Layer Weight",
- "How much of the previous layer to blend into this one");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "frame_property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "frameProp");
- RNA_def_property_ui_text(prop, "Frame Property", "Assign the action's current frame number to this property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* booleans */
- prop = RNA_def_property(srna, "use_additive", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOADD);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_ActionActuator_add_set");
- RNA_def_property_ui_text(prop, "Add",
- "Action is added to the current loc/rot/scale in global or local coordinate according to "
- "Local flag");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_force", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOFORCE);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_ActionActuator_force_set");
- RNA_def_property_ui_text(prop, "Force",
- "Apply Action as a global or local force depending on the local option "
- "(dynamic objects only)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_local", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOLOCAL);
- RNA_def_property_ui_text(prop, "L", "Let the Action act in local coordinates, used in Force and Add mode");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "apply_to_children", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOCHILD);
- RNA_def_property_ui_text(prop, "Child", "Update Action on all children Objects as well");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
- RNA_def_property_enum_items(prop, prop_blend_items);
- RNA_def_property_ui_text(prop, "Blend Mode", "How this layer is blended with previous layers");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
-#ifdef __NLA_ACTION_BY_MOTION_ACTUATOR
- prop = RNA_def_property(srna, "stride_length", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "stridelength");
- RNA_def_property_range(prop, 0.0, 2500.0);
- RNA_def_property_ui_text(prop, "Cycle", "Distance covered by a single cycle of the action");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-#endif
-}
-
-static void rna_def_object_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_OBJECT_NORMAL, "OBJECT_NORMAL", 0, "Simple Motion", ""},
- {ACT_OBJECT_SERVO, "OBJECT_SERVO", 0, "Servo Control", ""},
- {ACT_OBJECT_CHARACTER, "OBJECT_CHARACTER", 0, "Character Motion", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "ObjectActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Motion Actuator", "Actuator to control the object movement");
- RNA_def_struct_sdna_from(srna, "bObjectActuator", "data");
-
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_ObjectActuator_type_set", NULL);
- RNA_def_property_ui_text(prop, "Motion Type", "Specify the motion system");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "reference_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_sdna(prop, NULL, "reference");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Reference Object",
- "Reference object for velocity calculation, leave empty for world reference");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "damping", PROP_INT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0, 1000, 1, 1);
- RNA_def_property_ui_text(prop, "Damping Frames", "Number of frames to reach the target velocity");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "proportional_coefficient", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "forcerot[0]");
- RNA_def_property_ui_range(prop, 0.0, 200.0, 10, 2);
- RNA_def_property_ui_text(prop, "Proportional Coefficient", "Typical value is 60x integral coefficient");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "integral_coefficient", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "forcerot[1]");
- RNA_def_property_ui_range(prop, 0.0, 3.0, 10, 2);
- RNA_def_property_float_funcs(prop, NULL, "rna_ObjectActuator_integralcoefficient_set", NULL);
- RNA_def_property_ui_text(prop, "Integral Coefficient",
- "Low value (0.01) for slow response, high value (0.5) for fast response");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "derivate_coefficient", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "forcerot[2]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 10, 2);
- RNA_def_property_ui_text(prop, "Derivate Coefficient", "Not required, high values can cause instability");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Servo Limit */
- prop = RNA_def_property(srna, "force_max_x", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dloc[0]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 1, 2);
- RNA_def_property_ui_text(prop, "Max", "Upper limit for X force");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "force_min_x", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "drot[0]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 1, 2);
- RNA_def_property_ui_text(prop, "Min", "Lower limit for X force");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "force_max_y", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dloc[1]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 1, 2);
- RNA_def_property_ui_text(prop, "Max", "Upper limit for Y force");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "force_min_y", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "drot[1]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 1, 2);
- RNA_def_property_ui_text(prop, "Min", "Lower limit for Y force");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "force_max_z", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dloc[2]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 1, 2);
- RNA_def_property_ui_text(prop, "Max", "Upper limit for Z force");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "force_min_z", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "drot[2]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 1, 2);
- RNA_def_property_ui_text(prop, "Min", "Lower limit for Z force");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* floats 3 Arrays*/
- prop = RNA_def_property(srna, "offset_location", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "dloc");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Loc", "Location");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "offset_rotation", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float_sdna(prop, NULL, "drot");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Rot", "Rotation");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "force", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "forceloc");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Force", "Force");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "torque", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "forcerot");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Torque", "Torque");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "linear_velocity", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "linearvelocity");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Linear Velocity",
- "Linear velocity (in Servo mode it sets the target relative linear velocity, it will be "
- "achieved by automatic application of force - Null velocity is a valid target)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "angular_velocity", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "angularvelocity");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Angular Velocity", "Angular velocity");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* booleans */
- prop = RNA_def_property(srna, "use_local_location", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_DLOC_LOCAL);
- RNA_def_property_ui_text(prop, "L", "Location is defined in local coordinates");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_local_rotation", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_DROT_LOCAL);
- RNA_def_property_ui_text(prop, "L", "Rotation is defined in local coordinates");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_local_force", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_FORCE_LOCAL);
- RNA_def_property_ui_text(prop, "L", "Force is defined in local coordinates");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_local_torque", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_TORQUE_LOCAL);
- RNA_def_property_ui_text(prop, "L", "Torque is defined in local coordinates");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_local_linear_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_LIN_VEL_LOCAL);
- RNA_def_property_ui_text(prop, "L", "Velocity is defined in local coordinates");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_local_angular_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_ANG_VEL_LOCAL);
- RNA_def_property_ui_text(prop, "L", "Angular velocity is defined in local coordinates");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_add_linear_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_ADD_LIN_VEL);
- RNA_def_property_ui_text(prop, "Add", "Toggles between ADD and SET linV");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_add_character_location", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_ADD_CHAR_LOC);
- RNA_def_property_ui_text(prop, "Add", "Toggle between ADD and SET character location");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_servo_limit_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_X);
- RNA_def_property_ui_text(prop, "X", "Set limit to force along the X axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_servo_limit_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_Y);
- RNA_def_property_ui_text(prop, "Y", "Set limit to force along the Y axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_servo_limit_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_Z);
- RNA_def_property_ui_text(prop, "Z", "Set limit to force along the Z axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_character_jump", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CHAR_JUMP);
- RNA_def_property_ui_text(prop, "Jump", "Make the character jump using the settings in the physics properties");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_camera_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_axis_items[] = {
- {OB_POSX, "POS_X", 0, "+X", "Camera tries to get behind the X axis"},
- {OB_POSY, "POS_Y", 0, "+Y", "Camera tries to get behind the Y axis"},
- {OB_NEGX, "NEG_X", 0, "-X", "Camera tries to get behind the -X axis"},
- {OB_NEGY, "NEG_Y", 0, "-Y", "Camera tries to get behind the -Y axis"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "CameraActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Camera Actuator", "");
- RNA_def_struct_sdna_from(srna, "bCameraActuator", "data");
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_sdna(prop, NULL, "ob");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Camera Object", "Look at this Object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* floats */
- prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0.0, 20.0, 1, 2);
- RNA_def_property_ui_text(prop, "Height", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0.0, 20.0, 1, 2);
- RNA_def_property_ui_text(prop, "Min", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0.0, 20.0, 1, 2);
- RNA_def_property_ui_text(prop, "Max", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "damping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "damping");
- RNA_def_property_range(prop, 0, 10.0);
- RNA_def_property_ui_range(prop, 0, 5.0, 1, 2);
- RNA_def_property_ui_text(prop, "Damping", "Strength of the constraint that drives the camera behind the target");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* +x/+y/-x/-y */
- prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "axis");
- RNA_def_property_enum_items(prop, prop_axis_items);
- RNA_def_property_ui_text(prop, "Axis", "Axis the Camera will try to get behind");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_sound_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_SND_PLAY_STOP_SOUND, "PLAYSTOP", 0, "Play Stop", ""},
- {ACT_SND_PLAY_END_SOUND, "PLAYEND", 0, "Play End", ""},
- {ACT_SND_LOOP_STOP_SOUND, "LOOPSTOP", 0, "Loop Stop", ""},
- {ACT_SND_LOOP_END_SOUND, "LOOPEND", 0, "Loop End", ""},
- {ACT_SND_LOOP_BIDIRECTIONAL_SOUND, "LOOPBIDIRECTIONAL", 0, "Loop Bidirectional", ""},
- {ACT_SND_LOOP_BIDIRECTIONAL_STOP_SOUND, "LOOPBIDIRECTIONALSTOP", 0, "Loop Bidirectional Stop", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "SoundActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Sound Actuator", "Actuator to handle sound");
- RNA_def_struct_sdna_from(srna, "bSoundActuator", "data");
-
- prop = RNA_def_property(srna, "sound", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Sound");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_struct_ui_text(srna, "Sound", "Sound file");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Play Mode", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "volume", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2);
- RNA_def_property_range(prop, 0.0, 2.0);
- RNA_def_property_ui_text(prop, "Volume", "Initial volume of the sound");
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "pitch", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_range(prop, -12.0, 12.0, 1, 2);
- RNA_def_property_ui_text(prop, "Pitch", "Pitch of the sound");
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* floats - 3D Parameters */
- prop = RNA_def_property(srna, "gain_3d_min", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sound3D.min_gain");
- RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2);
- RNA_def_property_ui_text(prop, "Minimum Gain", "The minimum gain of the sound, no matter how far it is away");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "gain_3d_max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sound3D.max_gain");
- RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2);
- RNA_def_property_ui_text(prop, "Maximum Gain", "The maximum gain of the sound, no matter how near it is");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "distance_3d_reference", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sound3D.reference_distance");
- RNA_def_property_ui_range(prop, 0.0, FLT_MAX, 1, 2);
- RNA_def_property_ui_text(prop, "Reference Distance", "The distance where the sound has a gain of 1.0");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "distance_3d_max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sound3D.max_distance");
- RNA_def_property_ui_range(prop, 0.0, FLT_MAX, 1, 2);
- RNA_def_property_ui_text(prop, "Maximum Distance", "The maximum distance at which you can hear the sound");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "rolloff_factor_3d", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sound3D.rolloff_factor");
- RNA_def_property_ui_range(prop, 0.0, 5.0, 1, 2);
- RNA_def_property_ui_text(prop, "Rolloff", "The influence factor on volume depending on distance");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "cone_outer_gain_3d", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sound3D.cone_outer_gain");
- RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2);
- RNA_def_property_ui_text(prop, "Cone Outer Gain",
- "The gain outside the outer cone (the gain in the outer cone will be interpolated "
- "between this value and the normal gain in the inner cone)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "cone_outer_angle_3d", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "sound3D.cone_outer_angle");
- RNA_def_property_ui_range(prop, 0.0, DEG2RADF(360.0f), 1, 2);
- RNA_def_property_ui_text(prop, "Cone Outer Angle", "The angle of the outer cone");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "cone_inner_angle_3d", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "sound3D.cone_inner_angle");
- RNA_def_property_ui_range(prop, 0.0, DEG2RADF(360.0f), 1, 2);
- RNA_def_property_ui_text(prop, "Cone Inner Angle", "The angle of the inner cone");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* booleans */
- prop = RNA_def_property(srna, "use_sound_3d", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SND_3D_SOUND);
- RNA_def_property_ui_text(prop, "3D Sound", "Enable/Disable 3D Sound");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_property_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_PROP_ASSIGN, "ASSIGN", 0, "Assign", ""},
- {ACT_PROP_ADD, "ADD", 0, "Add", ""},
- {ACT_PROP_COPY, "COPY", 0, "Copy", ""},
- {ACT_PROP_TOGGLE, "TOGGLE", 0, "Toggle", "For bool/int/float/timer properties only"},
- {ACT_PROP_LEVEL, "LEVEL", 0, "Level", "For bool/int/float/timer properties only"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "PropertyActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Property Actuator", "Actuator to handle properties");
- RNA_def_struct_sdna_from(srna, "bPropertyActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Property", "The name of the property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "value", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Value", "The name of the property or the value to use (use \"\" around strings)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Copy Mode */
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_sdna(prop, NULL, "ob");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Object", "Copy from this Object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /*XXX add even magic'er property lookup (need to look for the property list of the target object) */
- prop = RNA_def_property(srna, "object_property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Property Name", "Copy this property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_constraint_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_CONST_TYPE_LOC, "LOC", 0, "Location Constraint", ""},
- {ACT_CONST_TYPE_DIST, "DIST", 0, "Distance Constraint", ""},
- {ACT_CONST_TYPE_ORI, "ORI", 0, "Orientation Constraint", ""},
- {ACT_CONST_TYPE_FH, "FH", 0, "Force Field Constraint", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_limit_items[] = {
- {ACT_CONST_NONE, "NONE", 0, "None", ""},
- {ACT_CONST_LOCX, "LOCX", 0, "Loc X", ""},
- {ACT_CONST_LOCY, "LOCY", 0, "Loc Y", ""},
- {ACT_CONST_LOCZ, "LOCZ", 0, "Loc Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_direction_items[] = {
- {ACT_CONST_NONE, "NONE", 0, "None", ""},
- {ACT_CONST_DIRPX, "DIRPX", 0, "X axis", ""},
- {ACT_CONST_DIRPY, "DIRPY", 0, "Y axis", ""},
- {ACT_CONST_DIRPZ, "DIRPZ", 0, "Z axis", ""},
- {ACT_CONST_DIRNX, "DIRNX", 0, "-X axis", ""},
- {ACT_CONST_DIRNY, "DIRNY", 0, "-Y axis", ""},
- {ACT_CONST_DIRNZ, "DIRNZ", 0, "-Z axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_direction_pos_items[] = {
- {ACT_CONST_NONE, "NONE", 0, "None", ""},
- {ACT_CONST_DIRPX, "DIRPX", 0, "X axis", ""},
- {ACT_CONST_DIRPY, "DIRPY", 0, "Y axis", ""},
- {ACT_CONST_DIRPZ, "DIRPZ", 0, "Z axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "ConstraintActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Constraint Actuator", "Actuator to handle Constraints");
- RNA_def_struct_sdna_from(srna, "bConstraintActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_ConstraintActuator_type_set", NULL);
- RNA_def_property_ui_text(prop, "Constraints Mode", "The type of the constraint");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "limit", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, prop_limit_items);
- RNA_def_property_ui_text(prop, "Limit", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, prop_direction_items);
- RNA_def_property_ui_text(prop, "Direction", "Direction of the ray");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "direction_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, prop_direction_items);
- RNA_def_property_ui_text(prop, "Direction", "Select the axis to be aligned along the reference direction");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_CONST_TYPE_LOC */
- prop = RNA_def_property(srna, "limit_min", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_funcs(prop, "rna_ConstraintActuator_limitmin_get",
- "rna_ConstraintActuator_limitmin_set", NULL);
- RNA_def_property_ui_range(prop, -2000.f, 2000.f, 1, 2);
- RNA_def_property_ui_text(prop, "Min", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "limit_max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_funcs(prop, "rna_ConstraintActuator_limitmax_get",
- "rna_ConstraintActuator_limitmax_set", NULL);
- RNA_def_property_ui_range(prop, -2000.f, 2000.f, 1, 2);
- RNA_def_property_ui_text(prop, "Max", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "damping", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "damp");
- RNA_def_property_ui_range(prop, 0, 100, 1, 1);
- RNA_def_property_ui_text(prop, "Damping", "Damping factor: time constant (in frame) of low pass filter");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_CONST_TYPE_DIST */
- prop = RNA_def_property(srna, "range", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_funcs(prop, "rna_ConstraintActuator_range_get", "rna_ConstraintActuator_range_set", NULL);
- RNA_def_property_ui_range(prop, 0.f, 2000.f, 1, 2);
- RNA_def_property_ui_text(prop, "Range", "Maximum length of ray");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_funcs(prop, "rna_ConstraintActuator_distance_get",
- "rna_ConstraintActuator_distance_set", NULL);
- RNA_def_property_ui_range(prop, -2000.f, 2000.f, 1, 2);
- RNA_def_property_ui_text(prop, "Distance", "Keep this distance to target");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /*XXX to use a pointer or add a material lookup */
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "matprop");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Material", "Ray detects only Objects with this material");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /*XXX add magic property lookup */
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "matprop");
- RNA_def_property_ui_text(prop, "Property", "Ray detects only Objects with this property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "time", PROP_INT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0, 1000, 1, 2);
- RNA_def_property_ui_text(prop, "Time", "Maximum activation time in frame, 0 for unlimited");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "damping_rotation", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "rotdamp");
- RNA_def_property_ui_range(prop, 0, 100, 1, 1);
- RNA_def_property_ui_text(prop, "RotDamp", "Use a different damping for orientation");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_CONST_TYPE_ORI */
- prop = RNA_def_property(srna, "direction_axis_pos", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, prop_direction_pos_items);
- RNA_def_property_ui_text(prop, "Direction", "Select the axis to be aligned along the reference direction");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "rotation_max", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "maxrot");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -2000.0, 2000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Reference Direction", "Reference Direction");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "angle_min", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "minloc[0]");
- RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
- RNA_def_property_ui_text(prop, "Min Angle",
- "Minimum angle to maintain with target direction "
- "(no correction is done if angle with target direction is between min and max)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "angle_max", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "maxloc[0]");
- RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
- RNA_def_property_ui_text(prop, "Max Angle",
- "Maximum angle allowed with target direction "
- "(no correction is done if angle with target direction is between min and max)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_CONST_TYPE_FH */
- prop = RNA_def_property(srna, "fh_height", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_funcs(prop, "rna_ConstraintActuator_fhheight_get",
- "rna_ConstraintActuator_fhheight_set", NULL);
- RNA_def_property_ui_range(prop, 0.01, 2000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Distance", "Height of the force field area");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "fh_force", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_funcs(prop, "rna_ConstraintActuator_spring_get", "rna_ConstraintActuator_spring_set", NULL);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 2);
- RNA_def_property_ui_text(prop, "Force", "Spring force within the force field area");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "fh_damping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "maxrot[0]");
- RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 2);
- RNA_def_property_ui_text(prop, "Damping", "Damping factor of the force field spring");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* booleans */
- prop = RNA_def_property(srna, "use_force_distance", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CONST_DISTANCE);
- RNA_def_property_ui_text(prop, "Force Distance", "Force distance of object to point of impact of ray");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_local", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CONST_LOCAL);
- RNA_def_property_ui_text(prop, "L", "Set ray along object's axis or global axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_normal", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CONST_NORMAL);
- RNA_def_property_ui_text(prop, "N",
- "Set object axis along (local axis) or parallel (global axis) to the normal at "
- "hit position");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_persistent", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CONST_PERMANENT);
- RNA_def_property_ui_text(prop, "PER", "Persistent actuator: stays active even if ray does not reach target");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /*XXX to use an enum instead of a flag if possible */
- prop = RNA_def_property(srna, "use_material_detect", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CONST_MATERIAL);
- RNA_def_property_ui_text(prop, "M/P", "Detect material instead of property");
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Actuator_constraint_detect_material_set");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_fh_paralel_axis", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CONST_DOROTFH);
- RNA_def_property_ui_text(prop, "Rot Fh", "Keep object axis parallel to normal");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_fh_normal", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CONST_NORMAL);
- RNA_def_property_ui_text(prop, "N", "Add a horizontal spring force on slopes");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_edit_object_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_dyn_items[] = {
- {ACT_EDOB_RESTORE_DYN, "RESTOREDYN", 0, "Restore Dynamics", ""},
- {ACT_EDOB_SUSPEND_DYN, "SUSPENDDYN", 0, "Suspend Dynamics", ""},
- {ACT_EDOB_ENABLE_RB, "ENABLERIGIDBODY", 0, "Enable Rigid Body", ""},
- {ACT_EDOB_DISABLE_RB, "DISABLERIGIDBODY", 0, "Disable Rigid Body", ""},
- {ACT_EDOB_SET_MASS, "SETMASS", 0, "Set Mass", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_EDOB_ADD_OBJECT, "ADDOBJECT", 0, "Add Object", ""},
- {ACT_EDOB_END_OBJECT, "ENDOBJECT", 0, "End Object", ""},
- {ACT_EDOB_REPLACE_MESH, "REPLACEMESH", 0, "Replace Mesh", ""},
- {ACT_EDOB_TRACK_TO, "TRACKTO", 0, "Track to", ""},
- {ACT_EDOB_DYNAMICS, "DYNAMICS", 0, "Dynamics", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_track_axis_items[] = {
- {ACT_TRACK_TRAXIS_X, "TRACKAXISX", 0, "X axis", ""},
- {ACT_TRACK_TRAXIS_Y, "TRACKAXISY", 0, "Y axis", ""},
- {ACT_TRACK_TRAXIS_Z, "TRACKAXISZ", 0, "Z axis", ""},
- {ACT_TRACK_TRAXIS_NEGX, "TRACKAXISNEGX", 0, "-X axis", ""},
- {ACT_TRACK_TRAXIS_NEGY, "TRACKAXISNEGY", 0, "-Y axis", ""},
- {ACT_TRACK_TRAXIS_NEGZ, "TRACKAXISNEGZ", 0, "-Z axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_up_axis_items[] = {
- {ACT_TRACK_UP_X, "UPAXISX", 0, "X axis", ""},
- {ACT_TRACK_UP_Y, "UPAXISY", 0, "Y axis", ""},
- {ACT_TRACK_UP_Z, "UPAXISZ", 0, "Z axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "EditObjectActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Edit Object Actuator", "Actuator used to edit objects");
- RNA_def_struct_sdna_from(srna, "bEditObjectActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Edit Object", "The mode of the actuator");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "dynamic_operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "dyn_operation");
- RNA_def_property_enum_items(prop, prop_dyn_items);
- RNA_def_property_ui_text(prop, "Dynamic Operation", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "up_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "upflag");
- RNA_def_property_enum_items(prop, prop_up_axis_items);
- RNA_def_property_ui_text(prop, "Up Axis", "The axis that points upward");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "trackflag");
- RNA_def_property_enum_items(prop, prop_track_axis_items);
- RNA_def_property_ui_text(prop, "Track Axis", "The axis that points to the target object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_sdna(prop, NULL, "ob");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Object", "Add this Object and all its children (can't be on a visible layer)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "track_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_sdna(prop, NULL, "ob");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Object", "Track to this Object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "mesh", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Mesh");
- RNA_def_property_pointer_sdna(prop, NULL, "me");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Mesh",
- "Replace the existing, when left blank 'Phys' will remake the existing physics mesh");
- /* note: custom set function is ONLY to avoid rna setting a user for this. */
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Actuator_editobject_mesh_set", NULL, NULL);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "time", PROP_INT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0, 2000, 1, 1);
- RNA_def_property_ui_text(prop, "Time", "Duration the new Object lives or the track takes");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0, 10000, 1, 2);
- RNA_def_property_ui_text(prop, "Mass", "The mass of the object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* floats 3 Arrays*/
- prop = RNA_def_property(srna, "linear_velocity", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "linVelocity");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -100.0, 100.0, 10, 2);
- RNA_def_property_ui_text(prop, "Linear Velocity", "Velocity upon creation");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "angular_velocity", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "angVelocity");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 2);
- RNA_def_property_ui_text(prop, "Angular Velocity", "Angular velocity upon creation");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* booleans */
- prop = RNA_def_property(srna, "use_local_linear_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "localflag", ACT_EDOB_LOCAL_LINV);
- RNA_def_property_ui_text(prop, "L", "Apply the transformation locally");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_local_angular_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "localflag", ACT_EDOB_LOCAL_ANGV);
- RNA_def_property_ui_text(prop, "L", "Apply the rotation locally");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_replace_display_mesh", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ACT_EDOB_REPLACE_MESH_NOGFX);
- RNA_def_property_ui_text(prop, "Gfx", "Replace the display mesh");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_replace_physics_mesh", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_EDOB_REPLACE_MESH_PHYS);
- RNA_def_property_ui_text(prop, "Phys",
- "Replace the physics mesh (triangle bounds only - compound shapes not supported)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_3d_tracking", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_TRACK_3D);
- RNA_def_property_ui_text(prop, "3D", "Enable 3D tracking");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_scene_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_SCENE_RESTART, "RESTART", 0, "Restart", ""},
- {ACT_SCENE_SET, "SET", 0, "Set Scene", ""},
- {ACT_SCENE_CAMERA, "CAMERA", 0, "Set Camera", ""},
- {ACT_SCENE_ADD_FRONT, "ADDFRONT", 0, "Add Overlay Scene", ""},
- {ACT_SCENE_ADD_BACK, "ADDBACK", 0, "Add Background Scene", ""},
- {ACT_SCENE_REMOVE, "REMOVE", 0, "Remove Scene", ""},
- {ACT_SCENE_SUSPEND, "SUSPEND", 0, "Suspend Scene", ""},
- {ACT_SCENE_RESUME, "RESUME", 0, "Resume Scene", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "SceneActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Scene Actuator", "");
- RNA_def_struct_sdna_from(srna, "bSceneActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "camera", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Camera_object_poll");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Camera Object", "Set this Camera (leave empty to refer to self object)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Scene");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Scene", "Scene to be added/removed/paused/resumed");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_random_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_distribution_items[] = {
- {ACT_RANDOM_BOOL_CONST, "BOOL_CONSTANT", 0, "Bool Constant", ""},
- {ACT_RANDOM_BOOL_UNIFORM, "BOOL_UNIFORM", 0, "Bool Uniform", ""},
- {ACT_RANDOM_BOOL_BERNOUILLI, "BOOL_BERNOUILLI", 0, "Bool Bernoulli", ""},
- {ACT_RANDOM_INT_CONST, "INT_CONSTANT", 0, "Int Constant", ""},
- {ACT_RANDOM_INT_UNIFORM, "INT_UNIFORM", 0, "Int Uniform", ""},
- {ACT_RANDOM_INT_POISSON, "INT_POISSON", 0, "Int Poisson", ""},
- {ACT_RANDOM_FLOAT_CONST, "FLOAT_CONSTANT", 0, "Float Constant", ""},
- {ACT_RANDOM_FLOAT_UNIFORM, "FLOAT_UNIFORM", 0, "Float Uniform", ""},
- {ACT_RANDOM_FLOAT_NORMAL, "FLOAT_NORMAL", 0, "Float Normal", ""},
- {ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL, "FLOAT_NEGATIVE_EXPONENTIAL", 0, "Float Neg. Exp.", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "RandomActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Random Actuator", "");
- RNA_def_struct_sdna_from(srna, "bRandomActuator", "data");
-
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0, 1000, 1, 1);
- RNA_def_property_range(prop, 0, MAXFRAME);
- RNA_def_property_ui_text(prop, "Seed",
- "Initial seed of the random generator, use Python for more freedom "
- "(choose 0 for not random)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "propname");
- RNA_def_property_ui_text(prop, "Property", "Assign the random value to this property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, prop_distribution_items);
- RNA_def_property_ui_text(prop, "Distribution", "Choose the type of distribution");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* arguments for the distribution */
- /* int_arg_1, int_arg_2, float_arg_1, float_arg_2 */
-
- /* ACT_RANDOM_BOOL_CONST */
- prop = RNA_def_property(srna, "use_always_true", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "int_arg_1", 1);
- RNA_def_property_ui_text(prop, "Always True", "Always false or always true");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_RANDOM_BOOL_UNIFORM */
- /* label => "Choose between true and false, 50% chance each" */
-
- /* ACT_RANDOM_BOOL_BERNOUILLI */
- prop = RNA_def_property(srna, "chance", PROP_FLOAT, PROP_PERCENTAGE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg_1");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_text(prop, "Chance", "Pick a number between 0 and 1, success if it's below this value");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_RANDOM_INT_CONST */
- prop = RNA_def_property(srna, "int_value", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "int_arg_1");
- RNA_def_property_ui_range(prop, -1000, 1000, 1, 1);
- RNA_def_property_ui_text(prop, "Value", "Always return this number");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_RANDOM_INT_UNIFORM */
- prop = RNA_def_property(srna, "int_min", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "int_arg_1");
- RNA_def_property_range(prop, -1000, 1000);
- RNA_def_property_ui_text(prop, "Min", "Choose a number from a range: lower boundary of the range");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "int_max", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "int_arg_2");
- RNA_def_property_range(prop, -1000, 1000);
- RNA_def_property_ui_text(prop, "Max", "Choose a number from a range: upper boundary of the range");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_RANDOM_INT_POISSON */
- prop = RNA_def_property(srna, "int_mean", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg_1");
- RNA_def_property_range(prop, 0.01, 100.0);
- RNA_def_property_ui_text(prop, "Mean", "Expected mean value of the distribution");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_RANDOM_FLOAT_CONST */
- prop = RNA_def_property(srna, "float_value", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg_1");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_text(prop, "Value", "Always return this number");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_RANDOM_FLOAT_UNIFORM */
- prop = RNA_def_property(srna, "float_min", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg_1");
- RNA_def_property_range(prop, -1000.0, 1000.0);
- RNA_def_property_ui_text(prop, "Min", "Choose a number from a range: lower boundary of the range");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "float_max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg_2");
- RNA_def_property_range(prop, -1000.0, 1000.0);
- RNA_def_property_ui_text(prop, "Max", "Choose a number from a range: upper boundary of the range");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_RANDOM_FLOAT_NORMAL */
- prop = RNA_def_property(srna, "float_mean", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg_1");
- RNA_def_property_range(prop, -1000.0, 1000.0);
- RNA_def_property_ui_text(prop, "Mean", "A normal distribution: mean of the distribution");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "standard_derivation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg_2");
- RNA_def_property_range(prop, -1000.0, 1000.0);
- RNA_def_property_ui_text(prop, "SD", "A normal distribution: standard deviation of the distribution");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL */
- prop = RNA_def_property(srna, "half_life_time", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg_1");
- RNA_def_property_range(prop, -1000.0, 1000.0);
- RNA_def_property_ui_text(prop, "Half-Life Time", "Negative exponential dropoff");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_message_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_body_type_items[] = {
- {ACT_MESG_MESG, "TEXT", 0, "Text", ""},
- {ACT_MESG_PROP, "PROPERTY", 0, "Property", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "MessageActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Message Actuator", "");
- RNA_def_struct_sdna_from(srna, "bMessageActuator", "data");
-
- prop = RNA_def_property(srna, "to_property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "toPropName");
- RNA_def_property_ui_text(prop, "To",
- "Optional, send message to objects with this name only, or empty to broadcast");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "subject", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Subject", "Optional, message subject (this is what can be filtered on)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "body_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "bodyType");
- RNA_def_property_enum_items(prop, prop_body_type_items);
- RNA_def_property_ui_text(prop, "Body", "Toggle message type: either Text or a PropertyName");
-
- /* ACT_MESG_MESG */
- prop = RNA_def_property(srna, "body_message", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "body");
- RNA_def_property_ui_text(prop, "Body", "Optional, message body Text");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_MESG_PROP */
- prop = RNA_def_property(srna, "body_property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "body");
- RNA_def_property_ui_text(prop, "Prop Name", "The message body will be set by the Property Value");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_game_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
-/* {ACT_GAME_LOAD, "LOAD", 0, "Load Game", ""}, */
-/* {ACT_GAME_START, "START", 0, "Start Loaded Game", ""}, */
-/* keeping the load/start hacky for compatibility with 2.49 */
-/* ideally we could use ACT_GAME_START again and do a do_version() */
-
- {ACT_GAME_LOAD, "START", 0, "Start Game From File", ""},
- {ACT_GAME_RESTART, "RESTART", 0, "Restart Game", ""},
- {ACT_GAME_QUIT, "QUIT", 0, "Quit Game", ""},
- {ACT_GAME_SAVECFG, "SAVECFG", 0, "Save bge.logic.globalDict", ""},
- {ACT_GAME_LOADCFG, "LOADCFG", 0, "Load bge.logic.globalDict", ""},
- {ACT_GAME_SCREENSHOT, "SCREENSHOT", 0, "Screenshot", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "GameActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Game Actuator", "");
- RNA_def_struct_sdna_from(srna, "bGameActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Game", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* ACT_GAME_LOAD */
- prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_ui_text(prop, "File",
- "The file to use, depending on the mode (e.g. the blend file to load or a destination "
- "for saving a screenshot) - use the \"//\" prefix for a relative path");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
- /*XXX to do: an operator that calls file_browse with relative_path on and blender filtering active */
-}
-
-static void rna_def_visibility_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "VisibilityActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Visibility Actuator", "Actuator to set visibility and occlusion of the object");
- RNA_def_struct_sdna_from(srna, "bVisibilityActuator", "data");
-
- prop = RNA_def_property(srna, "use_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ACT_VISIBILITY_INVISIBLE);
- RNA_def_property_ui_text(prop, "Visible",
- "Set the objects visible (initialized from the object render restriction toggle in "
- "physics button)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_occlusion", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_VISIBILITY_OCCLUSION);
- RNA_def_property_ui_text(prop, "Occlusion",
- "Set the object to occlude objects behind it (initialized from the object type in "
- "physics button)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "apply_to_children", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_VISIBILITY_RECURSIVE);
- RNA_def_property_ui_text(prop, "Children",
- "Set all the children of this object to the same visibility/occlusion recursively");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_twodfilter_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_2DFILTER_ENABLED, "ENABLE", 0, "Enable Filter", ""},
- {ACT_2DFILTER_DISABLED, "DISABLE", 0, "Disable Filter", ""},
- {ACT_2DFILTER_NOFILTER, "REMOVE", 0, "Remove Filter", ""},
- {ACT_2DFILTER_MOTIONBLUR, "MOTIONBLUR", 0, "Motion Blur", ""},
- {ACT_2DFILTER_BLUR, "BLUR", 0, "Blur", ""},
- {ACT_2DFILTER_SHARPEN, "SHARPEN", 0, "Sharpen", ""},
- {ACT_2DFILTER_DILATION, "DILATION", 0, "Dilation", ""},
- {ACT_2DFILTER_EROSION, "EROSION", 0, "Erosion", ""},
- {ACT_2DFILTER_LAPLACIAN, "LAPLACIAN", 0, "Laplacian", ""},
- {ACT_2DFILTER_SOBEL, "SOBEL", 0, "Sobel", ""},
- {ACT_2DFILTER_PREWITT, "PREWITT", 0, "Prewitt", ""},
- {ACT_2DFILTER_GRAYSCALE, "GRAYSCALE", 0, "Gray Scale", ""},
- {ACT_2DFILTER_SEPIA, "SEPIA", 0, "Sepia", ""},
- {ACT_2DFILTER_INVERT, "INVERT", 0, "Invert", ""},
- {ACT_2DFILTER_CUSTOMFILTER, "CUSTOMFILTER", 0, "Custom Filter", ""},
-/* {ACT_2DFILTER_NUMBER_OF_FILTERS, "", 0, "Do not use it. Sentinel", ""}, */
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "Filter2DActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Filter 2D Actuator", "Actuator to apply screen graphic effects");
- RNA_def_struct_sdna_from(srna, "bTwoDFilterActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Filter 2D Type", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "glsl_shader", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "text");
- RNA_def_property_struct_type(prop, "Text");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Script", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "filter_pass", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "int_arg");
- RNA_def_property_ui_text(prop, "Pass Number", "Set filter order");
- RNA_def_property_range(prop, 0, 99); /*MAX_RENDER_PASS-1 */
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "motion_blur_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "float_arg");
- RNA_def_property_ui_text(prop, "Value", "Motion blur factor");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* booleans */
- prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", 1);
- RNA_def_property_ui_text(prop, "Enable", "Enable/Disable Motion Blur");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_parent_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_PARENT_SET, "SETPARENT", 0, "Set Parent", ""},
- {ACT_PARENT_REMOVE, "REMOVEPARENT", 0, "Remove Parent", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "ParentActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Parent Actuator", "");
- RNA_def_struct_sdna_from(srna, "bParentActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Scene", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_sdna(prop, NULL, "ob");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Parent Object", "Set this object as parent");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* booleans */
- prop = RNA_def_property(srna, "use_compound", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ACT_PARENT_COMPOUND);
- RNA_def_property_ui_text(prop, "Compound",
- "Add this object shape to the parent shape "
- "(only if the parent shape is already compound)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_ghost", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ACT_PARENT_GHOST);
- RNA_def_property_ui_text(prop, "Ghost", "Make this object ghost while parented");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_state_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_STATE_SET, "SET", 0, "Set State", ""},
- {ACT_STATE_ADD, "ADD", 0, "Add State", ""},
- {ACT_STATE_REMOVE, "REMOVE", 0, "Remove State", ""},
- {ACT_STATE_CHANGE, "CHANGE", 0, "Change State", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "StateActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "State Actuator", "Actuator to handle states");
- RNA_def_struct_sdna_from(srna, "bStateActuator", "data");
-
- prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Operation", "Select the bit operation on object state mask");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "states", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "mask", 1);
- RNA_def_property_array(prop, OB_MAX_STATES);
- RNA_def_property_ui_text(prop, "State", "");
- RNA_def_property_boolean_funcs(prop, NULL, "rna_StateActuator_state_set");
-}
-
-static void rna_def_armature_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_ARM_RUN, "RUN", 0, "Run Armature", ""},
- {ACT_ARM_ENABLE, "ENABLE", 0, "Enable", ""},
- {ACT_ARM_DISABLE, "DISABLE", 0, "Disable", ""},
- {ACT_ARM_SETTARGET, "SETTARGET", 0, "Set Target", ""},
- {ACT_ARM_SETWEIGHT, "SETWEIGHT", 0, "Set Weight", ""},
- {ACT_ARM_SETINFLUENCE, "SETINFLUENCE", 0, "Set Influence", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "ArmatureActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Armature Actuator", "");
- RNA_def_struct_sdna_from(srna, "bArmatureActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Constraint Type", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "bone", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "posechannel");
- RNA_def_property_ui_text(prop, "Bone", "Bone on which the constraint is defined");
- RNA_def_property_update(prop, NC_LOGIC, "rna_Actuator_Armature_update");
-
- prop = RNA_def_property(srna, "constraint", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "constraint");
- RNA_def_property_ui_text(prop, "Constraint", "Name of the constraint to control");
- RNA_def_property_update(prop, NC_LOGIC, "rna_Actuator_Armature_update");
-
- prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Target", "Set this object as the target of the constraint");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "secondary_target", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "subtarget");
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Secondary Target",
- "Set this object as the secondary target of the constraint "
- "(only IK polar target at the moment)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "weight");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_text(prop, "Weight", "Weight of this constraint");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "influence");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_text(prop, "Influence", "Influence of this constraint");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_steering_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_STEERING_SEEK, "SEEK", 0, "Seek", ""},
- {ACT_STEERING_FLEE, "FLEE", 0, "Flee", ""},
- {ACT_STEERING_PATHFOLLOWING, "PATHFOLLOWING", 0, "Path following", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem facingaxis_items[] = {
- {1, "X", 0, "X", ""},
- {2, "Y", 0, "Y", ""},
- {3, "Z", 0, "Z", ""},
- {4, "NEG_X", 0, "-X", ""},
- {5, "NEG_Y", 0, "-Y", ""},
- {6, "NEG_Z", 0, "-Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "SteeringActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Steering Actuator", "");
- RNA_def_struct_sdna_from(srna, "bSteeringActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Behavior", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "velocity");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Velocity", "Velocity magnitude");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "acceleration", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "acceleration");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Acceleration", "Max acceleration");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "turn_speed", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "turnspeed");
- RNA_def_property_range(prop, 0.0, 720.0);
- RNA_def_property_ui_text(prop, "Turn Speed", "Max turn speed");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dist");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Dist", "Relax distance");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_sdna(prop, NULL, "target");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Target Object", "Target object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "self_terminated", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_STEERING_SELFTERMINATED);
- RNA_def_property_ui_text(prop, "Self Terminated", "Terminate when target is reached");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_visualization", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_STEERING_ENABLEVISUALIZATION);
- RNA_def_property_ui_text(prop, "Visualize", "Enable debug visualization for 'Path following'");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "update_period", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "updateTime");
- RNA_def_property_ui_range(prop, -1, 100000, 1, 1);
- RNA_def_property_ui_text(prop, "Update period", "Path update period");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "navmesh", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_sdna(prop, NULL, "navmesh");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Navigation Mesh Object", "Navigation mesh");
- RNA_def_property_pointer_funcs(prop, NULL, "rna_SteeringActuator_navmesh_set", NULL, NULL);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "facing", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_STEERING_AUTOMATICFACING);
- RNA_def_property_ui_text(prop, "Facing", "Enable automatic facing");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "facing_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "facingaxis");
- RNA_def_property_enum_items(prop, facingaxis_items);
- RNA_def_property_ui_text(prop, "Axis", "Axis for automatic facing");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "normal_up", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_STEERING_NORMALUP);
- RNA_def_property_ui_text(prop, "N", "Use normal of the navmesh to set \"UP\" vector");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "lock_z_velocity", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_STEERING_LOCKZVEL);
- RNA_def_property_ui_text(prop, "Lock Z velocity", "Disable simulation of linear motion along Z axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_mouse_actuator(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_type_items[] = {
- {ACT_MOUSE_VISIBILITY, "VISIBILITY", 0, "Visibility", ""},
- {ACT_MOUSE_LOOK, "LOOK", 0, "Look", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_object_axis_items[] = {
- {ACT_MOUSE_OBJECT_AXIS_X, "OBJECT_AXIS_X", 0, "X Axis", ""},
- {ACT_MOUSE_OBJECT_AXIS_Y, "OBJECT_AXIS_Y", 0, "Y Axis", ""},
- {ACT_MOUSE_OBJECT_AXIS_Z, "OBJECT_AXIS_Z", 0, "Z Axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "MouseActuator", "Actuator");
- RNA_def_struct_ui_text(srna, "Mouse Actuator", "");
- RNA_def_struct_sdna_from(srna, "bMouseActuator", "data");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Visibility */
- prop = RNA_def_property(srna, "visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_VISIBLE);
- RNA_def_property_ui_text(prop, "Visible", "Make mouse cursor visible");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Mouse Look */
- prop = RNA_def_property(srna, "use_axis_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_USE_AXIS_X);
- RNA_def_property_ui_text(prop, "Use X Axis", "Calculate mouse movement on the X axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_axis_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_USE_AXIS_Y);
- RNA_def_property_ui_text(prop, "Use Y Axis", "Calculate mouse movement on the Y axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "reset_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_RESET_X);
- RNA_def_property_ui_text(prop, "Reset",
- "Reset the cursor's X position to the center of the screen space after calculating");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "reset_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_RESET_Y);
- RNA_def_property_ui_text(prop, "Reset",
- "Reset the cursor's Y position to the center of the screen space after calculating");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "local_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_LOCAL_X);
- RNA_def_property_ui_text(prop, "Local", "Apply rotation locally");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "local_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_LOCAL_Y);
- RNA_def_property_ui_text(prop, "Local", "Apply rotation locally");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "threshold_x", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "threshold[0]");
- RNA_def_property_ui_range(prop, 0, 0.5, 1, 3);
- RNA_def_property_ui_text(prop, "Threshold", "Amount of X motion before mouse movement will register");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "threshold_y", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "threshold[1]");
- RNA_def_property_ui_range(prop, 0, 0.5, 1, 3);
- RNA_def_property_ui_text(prop, "Threshold", "Amount of Y motion before mouse movement will register");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "object_axis_x", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "object_axis[0]");
- RNA_def_property_enum_items(prop, prop_object_axis_items);
- RNA_def_property_ui_text(prop, "Object Axis", "Local object axis mouse movement in the X direction will apply to");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "object_axis_y", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "object_axis[1]");
- RNA_def_property_enum_items(prop, prop_object_axis_items);
- RNA_def_property_ui_text(prop, "Object Axis", "Local object axis mouse movement in the Y direction will apply to");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "sensitivity_x", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sensitivity[0]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 0.2, 3);
- RNA_def_property_ui_text(prop, "Sensitivity", "Sensitivity of the X axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "sensitivity_y", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sensitivity[1]");
- RNA_def_property_ui_range(prop, -100.0, 100.0, 0.2, 3);
- RNA_def_property_ui_text(prop, "Sensitivity", "Sensitivity of the Y axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "min_x", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "limit_x[0]");
- RNA_def_property_ui_range(prop, DEG2RADF(-3600.0f), 0.0, 9, 3);
- RNA_def_property_ui_text(prop, "Min", "Maximum negative rotation allowed by X mouse movement (0 for infinite)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "max_x", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "limit_x[1]");
- RNA_def_property_ui_range(prop, 0.0, DEG2RADF(3600.0f), 9, 3);
- RNA_def_property_ui_text(prop, "Max", "Maximum positive rotation allowed by X mouse movement (0 for infinite)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "min_y", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "limit_y[0]");
- RNA_def_property_ui_range(prop, DEG2RADF(-3600.0f), 0.0, 9, 3);
- RNA_def_property_ui_text(prop, "Min", "Maximum negative rotation allowed by Y mouse movement (0 for infinite)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "max_y", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "limit_y[1]");
- RNA_def_property_ui_range(prop, 0.0, DEG2RADF(3600.0f), 9, 3);
- RNA_def_property_ui_text(prop, "Max", "Maximum positive rotation allowed by Y mouse movement (0 for infinite)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-void RNA_def_actuator(BlenderRNA *brna)
-{
- rna_def_actuator(brna);
-
- rna_def_action_actuator(brna);
- rna_def_object_actuator(brna);
- rna_def_camera_actuator(brna);
- rna_def_sound_actuator(brna);
- rna_def_property_actuator(brna);
- rna_def_constraint_actuator(brna);
- rna_def_edit_object_actuator(brna);
- rna_def_scene_actuator(brna);
- rna_def_random_actuator(brna);
- rna_def_message_actuator(brna);
- rna_def_game_actuator(brna);
- rna_def_visibility_actuator(brna);
- rna_def_twodfilter_actuator(brna);
- rna_def_parent_actuator(brna);
- rna_def_state_actuator(brna);
- rna_def_armature_actuator(brna);
- rna_def_steering_actuator(brna);
- rna_def_mouse_actuator(brna);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_actuator_api.c b/source/blender/makesrna/intern/rna_actuator_api.c
deleted file mode 100644
index 0047d7257cb..00000000000
--- a/source/blender/makesrna/intern/rna_actuator_api.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * ***** 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) 2010 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s):
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/makesrna/intern/rna_actuator_api.c
- * \ingroup RNA
- */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "WM_types.h"
-#include "RNA_define.h"
-
-#include "rna_internal.h" /* own include */
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_sca.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
-
-static void rna_Actuator_link(bActuator *act, bController *cont)
-{
- link_logicbricks((void **)&act, (void ***)&(cont->links), &cont->totlinks, sizeof(bActuator *));
-}
-
-static void rna_Actuator_unlink(bActuator *act, bController *cont)
-{
- unlink_logicbricks((void **)&act, (void ***)&(cont->links), &cont->totlinks);
-}
-
-#else
-
-void RNA_api_actuator(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *parm;
-
- func = RNA_def_function(srna, "link", "rna_Actuator_link");
- RNA_def_function_ui_description(func, "Link the actuator to a controller");
- parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to link to");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_property_update(parm, NC_LOGIC, NULL);
-
- func = RNA_def_function(srna, "unlink", "rna_Actuator_unlink");
- RNA_def_function_ui_description(func, "Unlink the actuator from a controller");
- parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to unlink from");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_property_update(parm, NC_LOGIC, NULL);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 6f1445d31ef..6c0ce6b124e 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -73,22 +73,30 @@ const EnumPropertyItem rna_enum_keying_flag_items[] = {
#include "BLI_math_base.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "DNA_object_types.h"
+#include "ED_anim_api.h"
+
#include "WM_api.h"
-static void rna_AnimData_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_AnimData_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
ID *id = ptr->id.data;
- /* tag for refresh so that scheduled updates (e.g. action changed) will
- * get computed and reflected in the scene [#34869]
- */
- DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA);
+ ANIM_id_update(bmain, id);
+}
+
+static void rna_AnimData_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ DEG_relations_tag_update(bmain);
+
+ rna_AnimData_update(bmain, scene, ptr);
}
static int rna_AnimData_action_editable(PointerRNA *ptr, const char **UNUSED(r_info))
@@ -105,17 +113,9 @@ static int rna_AnimData_action_editable(PointerRNA *ptr, const char **UNUSED(r_i
static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value)
{
ID *ownerId = (ID *)ptr->id.data;
- AnimData *adt;
/* set action */
BKE_animdata_set_action(NULL, ownerId, value.data);
-
- /* force action to get evaluated [#34869] */
- adt = BKE_animdata_from_id(ownerId);
- if (adt) {
- adt->recalc |= ADT_RECALC_ANIM;
- DAG_id_tag_update(ownerId, OB_RECALC_TIME);
- }
}
static void rna_AnimData_tweakmode_set(PointerRNA *ptr, const bool value)
@@ -517,16 +517,19 @@ static void rna_KeyingSet_paths_clear(KeyingSet *keyingset, ReportList *reports)
}
/* needs wrapper function to push notifier */
-static NlaTrack *rna_NlaTrack_new(AnimData *adt, bContext *C, NlaTrack *track)
+static NlaTrack *rna_NlaTrack_new(ID *id, AnimData *adt, Main *bmain, bContext *C, NlaTrack *track)
{
NlaTrack *new_track = BKE_nlatrack_add(adt, track);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_ADDED, NULL);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update_ex(bmain, id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
+
return new_track;
}
-static void rna_NlaTrack_remove(AnimData *adt, bContext *C, ReportList *reports, PointerRNA *track_ptr)
+static void rna_NlaTrack_remove(ID *id, AnimData *adt, Main *bmain, bContext *C, ReportList *reports, PointerRNA *track_ptr)
{
NlaTrack *track = track_ptr->data;
@@ -535,10 +538,13 @@ static void rna_NlaTrack_remove(AnimData *adt, bContext *C, ReportList *reports,
return;
}
- BKE_nlatrack_free(&adt->nla_tracks, track);
+ BKE_nlatrack_free(&adt->nla_tracks, track, true);
RNA_POINTER_INVALIDATE(track_ptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_REMOVED, NULL);
+
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update_ex(bmain, id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
}
static PointerRNA rna_NlaTrack_active_get(PointerRNA *ptr)
@@ -584,6 +590,36 @@ static FCurve *rna_Driver_find(AnimData *adt, ReportList *reports, const char *d
return list_find_fcurve(&adt->drivers, data_path, index);
}
+bool rna_AnimaData_override_apply(
+ Main *UNUSED(bmain),
+ PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *UNUSED(prop_storage),
+ const int len_dst, const int len_src, const int len_storage,
+ PointerRNA *UNUSED(ptr_item_dst), PointerRNA *UNUSED(ptr_item_src), PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0);
+ BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_REPLACE && "Unsupported RNA override operation on animdata pointer");
+ UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop);
+
+ /* AnimData is a special case, since you cannot edit/replace it, it's either existent or not. */
+ AnimData *adt_dst = RNA_property_pointer_get(ptr_dst, prop_dst).data;
+ AnimData *adt_src = RNA_property_pointer_get(ptr_src, prop_src).data;
+
+ if (adt_dst == NULL && adt_src != NULL) {
+ /* Copy anim data from reference into final local ID. */
+ BKE_animdata_copy_id(NULL, ptr_dst->id.data, ptr_src->id.data, 0);
+ return true;
+ }
+ else if (adt_dst != NULL && adt_src == NULL) {
+ /* Override has cleared/removed anim data from its reference. */
+ BKE_animdata_free(ptr_dst->id.data, true);
+ return true;
+ }
+
+ return false;
+}
+
#else
/* helper function for Keying Set -> keying settings */
@@ -933,7 +969,7 @@ static void rna_api_animdata_nla_tracks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_ui_text(srna, "NLA Tracks", "Collection of NLA Tracks");
func = RNA_def_function(srna, "new", "rna_NlaTrack_new");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Add a new NLA Track");
RNA_def_pointer(func, "prev", "NlaTrack", "", "NLA Track to add the new one after");
/* return type */
@@ -941,7 +977,7 @@ static void rna_api_animdata_nla_tracks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_NlaTrack_remove");
- RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS | FUNC_USE_MAIN | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Remove a NLA Track");
parm = RNA_def_pointer(func, "track", "NlaTrack", "", "NLA Track to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
@@ -998,6 +1034,8 @@ void rna_def_animdata_common(StructRNA *srna)
prop = RNA_def_property(srna, "animation_data", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "adt");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_AnimaData_override_apply");
RNA_def_property_ui_text(prop, "Animation Data", "Animation data for this data-block");
}
@@ -1022,10 +1060,11 @@ static void rna_def_animdata(BlenderRNA *brna)
prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
/* this flag as well as the dynamic test must be defined for this to be editable... */
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll");
RNA_def_property_editable_func(prop, "rna_AnimData_action_editable");
RNA_def_property_ui_text(prop, "Action", "Active Action for this data-block");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA_ACTCHANGE, "rna_AnimData_update");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA_ACTCHANGE, "rna_AnimData_dependency_update");
/* Active Action Settings */
prop = RNA_def_property(srna, "action_extrapolation", PROP_ENUM, PROP_NONE);
@@ -1033,14 +1072,14 @@ static void rna_def_animdata(BlenderRNA *brna)
RNA_def_property_enum_items(prop, rna_enum_nla_mode_extend_items);
RNA_def_property_ui_text(prop, "Action Extrapolation",
"Action to take for gaps past the Active Action's range (when evaluating with NLA)");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, "rna_AnimData_update");
prop = RNA_def_property(srna, "action_blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "act_blendmode");
RNA_def_property_enum_items(prop, rna_enum_nla_mode_blend_items);
RNA_def_property_ui_text(prop, "Action Blending",
"Method used for combining Active Action's result with result of NLA stack");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, "rna_AnimData_update"); /* this will do? */
prop = RNA_def_property(srna, "action_influence", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "act_influence");
@@ -1048,12 +1087,13 @@ static void rna_def_animdata(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Action Influence",
"Amount the Active Action contributes to the result of the NLA stack");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, "rna_AnimData_update"); /* this will do? */
/* Drivers */
prop = RNA_def_property(srna, "drivers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "drivers", NULL);
RNA_def_property_struct_type(prop, "FCurve");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Drivers", "The Drivers/Expressions for this data-block");
rna_api_animdata_drivers(brna, prop);
@@ -1062,13 +1102,13 @@ static void rna_def_animdata(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_nla", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADT_NLA_EVAL_OFF);
RNA_def_property_ui_text(prop, "NLA Evaluation Enabled", "NLA stack is evaluated when evaluating this block");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, "rna_AnimData_update"); /* this will do? */
prop = RNA_def_property(srna, "use_tweak_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ADT_NLA_EDIT_ON);
RNA_def_property_boolean_funcs(prop, NULL, "rna_AnimData_tweakmode_set");
RNA_def_property_ui_text(prop, "Use NLA Tweak Mode", "Whether to enable or disable tweak mode in NLA");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, "rna_AnimData_update");
}
/* --- */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 6c728ac50e5..c3e68cf0869 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -43,8 +43,8 @@
#ifdef RNA_RUNTIME
+#include "BKE_action.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
@@ -52,15 +52,27 @@
#include "ED_armature.h"
#include "BKE_armature.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
static void rna_Armature_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
ID *id = ptr->id.data;
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
/*WM_main_add_notifier(NC_OBJECT|ND_POSE, NULL); */
}
+static void rna_Armature_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ID *id = ptr->id.data;
+
+ DEG_relations_tag_update(bmain);
+
+ DEG_id_tag_update(id, 0);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+}
static void rna_Armature_act_bone_set(PointerRNA *ptr, PointerRNA value)
{
@@ -140,6 +152,7 @@ static void rna_Armature_update_layers(Main *bmain, Scene *UNUSED(scene), Pointe
ob->pose->proxy_layer = arm->layer;
}
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
WM_main_add_notifier(NC_GEOM | ND_DATA, arm);
}
@@ -147,6 +160,7 @@ static void rna_Armature_redraw_data(Main *UNUSED(bmain), Scene *UNUSED(scene),
{
ID *id = ptr->id.data;
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
@@ -166,24 +180,30 @@ static void rna_Bone_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
{
ID *id = ptr->id.data;
- /* special updates for cases where rigs try to hook into armature drawing stuff
- * e.g. Mask Modifier - 'Armature' option
+ /* 1) special updates for cases where rigs try to hook into armature drawing stuff
+ * e.g. Mask Modifier - 'Armature' option
+ * 2) tag armature for copy-on-write, so that selection status (set by addons)
+ * will update properly, like standard tools do already
*/
if (id) {
if (GS(id->name) == ID_AR) {
bArmature *arm = (bArmature *)id;
if (arm->flag & ARM_HAS_VIZ_DEPS) {
- DAG_id_tag_update(id, OB_RECALC_DATA);
+ DEG_id_tag_update(id, OB_RECALC_DATA);
}
+
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
}
else if (GS(id->name) == ID_OB) {
Object *ob = (Object *)id;
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_HAS_VIZ_DEPS) {
- DAG_id_tag_update(id, OB_RECALC_DATA);
+ DEG_id_tag_update(id, OB_RECALC_DATA);
}
+
+ DEG_id_tag_update(&arm->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -238,6 +258,18 @@ static IDProperty *rna_EditBone_idprops(PointerRNA *ptr, bool create)
return ebone->prop;
}
+/* Update the layers_used variable after bones are moved between layer
+ * NOTE: Used to be done in drawing code in 2.7, but that won't work with
+ * Copy-on-Write, as drawing uses evaluated copies.
+ */
+static void rna_Armature_layer_used_refresh(bArmature *arm, ListBase *bones)
+{
+ for (Bone *bone = bones->first; bone; bone = bone->next) {
+ arm->layer_used |= bone->layer;
+ rna_Armature_layer_used_refresh(arm, &bone->childbase);
+ }
+}
+
static void rna_bone_layer_set(int *layer, const bool *values)
{
int i, tot = 0;
@@ -258,8 +290,13 @@ static void rna_bone_layer_set(int *layer, const bool *values)
static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values)
{
+ bArmature *arm = (bArmature *)ptr->id.data;
Bone *bone = (Bone *)ptr->data;
+
rna_bone_layer_set(&bone->layer, values);
+
+ arm->layer_used = 0;
+ rna_Armature_layer_used_refresh(arm, &arm->bonebase);
}
static void rna_Armature_layer_set(PointerRNA *ptr, const bool *values)
@@ -315,7 +352,7 @@ static void rna_EditBone_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(newname, value, sizeof(ebone->name));
BLI_strncpy(oldname, ebone->name, sizeof(ebone->name));
- BLI_assert(BKE_id_is_in_gobal_main(&arm->id));
+ BLI_assert(BKE_id_is_in_global_main(&arm->id));
ED_armature_bone_rename(G_MAIN, arm, oldname, newname);
}
@@ -329,7 +366,7 @@ static void rna_Bone_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(newname, value, sizeof(bone->name));
BLI_strncpy(oldname, bone->name, sizeof(bone->name));
- BLI_assert(BKE_id_is_in_gobal_main(&arm->id));
+ BLI_assert(BKE_id_is_in_global_main(&arm->id));
ED_armature_bone_rename(G_MAIN, arm, oldname, newname);
}
@@ -413,6 +450,82 @@ static void rna_EditBone_matrix_set(PointerRNA *ptr, const float *values)
ED_armature_ebone_from_mat4(ebone, (float(*)[4])values);
}
+static void rna_Bone_bbone_handle_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bArmature *arm = (bArmature *)ptr->id.data;
+ Bone *bone = (Bone *)ptr->data;
+
+ /* Update all users of this armature after changing B-Bone handles. */
+ for (Object *obt = bmain->object.first; obt; obt = obt->id.next) {
+ if (obt->data == arm && obt->pose) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(obt->pose, bone->name);
+
+ if (pchan && pchan->bone == bone) {
+ BKE_pchan_rebuild_bbone_handles(obt->pose, pchan);
+ DEG_id_tag_update(&obt->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ }
+ }
+
+ rna_Armature_dependency_update(bmain, scene, ptr);
+}
+
+static PointerRNA rna_EditBone_bbone_prev_get(PointerRNA *ptr)
+{
+ EditBone *data = (EditBone *)(ptr->data);
+ return rna_pointer_inherit_refine(ptr, &RNA_EditBone, data->bbone_prev);
+}
+
+static void rna_EditBone_bbone_prev_set(PointerRNA *ptr, PointerRNA value)
+{
+ EditBone *ebone = (EditBone *)(ptr->data);
+ EditBone *hbone = (EditBone *)value.data;
+
+ /* Within the same armature? */
+ if (hbone == NULL || value.id.data == ptr->id.data) {
+ ebone->bbone_prev = hbone;
+ }
+}
+
+static void rna_Bone_bbone_prev_set(PointerRNA *ptr, PointerRNA value)
+{
+ Bone *bone = (Bone *)ptr->data;
+ Bone *hbone = (Bone *)value.data;
+
+ /* Within the same armature? */
+ if (hbone == NULL || value.id.data == ptr->id.data) {
+ bone->bbone_prev = hbone;
+ }
+}
+
+static PointerRNA rna_EditBone_bbone_next_get(PointerRNA *ptr)
+{
+ EditBone *data = (EditBone *)(ptr->data);
+ return rna_pointer_inherit_refine(ptr, &RNA_EditBone, data->bbone_next);
+}
+
+static void rna_EditBone_bbone_next_set(PointerRNA *ptr, PointerRNA value)
+{
+ EditBone *ebone = (EditBone *)(ptr->data);
+ EditBone *hbone = (EditBone *)value.data;
+
+ /* Within the same armature? */
+ if (hbone == NULL || value.id.data == ptr->id.data) {
+ ebone->bbone_next = hbone;
+ }
+}
+
+static void rna_Bone_bbone_next_set(PointerRNA *ptr, PointerRNA value)
+{
+ Bone *bone = (Bone *)ptr->data;
+ Bone *hbone = (Bone *)value.data;
+
+ /* Within the same armature? */
+ if (hbone == NULL || value.id.data == ptr->id.data) {
+ bone->bbone_next = hbone;
+ }
+}
+
static void rna_Armature_editbone_transform_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bArmature *arm = (bArmature *)ptr->id.data;
@@ -581,6 +694,14 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
static void rna_def_bone_common(StructRNA *srna, int editbone)
{
+ static const EnumPropertyItem prop_bbone_handle_type[] = {
+ {BBONE_HANDLE_AUTO, "AUTO", 0, "Automatic", "Use connected parent and children to compute the handle"},
+ {BBONE_HANDLE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Use the position of the specified bone to compute the handle"},
+ {BBONE_HANDLE_RELATIVE, "RELATIVE", 0, "Relative", "Use the offset of the specified bone from rest pose to compute the handle"},
+ {BBONE_HANDLE_TANGENT, "TANGENT", 0, "Tangent", "Use the orientation of the specified bone to compute the handle, ignoring the location"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
PropertyRNA *prop;
/* strings */
@@ -641,7 +762,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_DRAWWIRE);
- RNA_def_property_ui_text(prop, "Draw Wire",
+ RNA_def_property_ui_text(prop, "Display Wire",
"Bone is always drawn as Wireframe regardless of viewport draw mode "
"(useful for non-obstructive custom bone shapes)");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
@@ -696,7 +817,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_int_sdna(prop, NULL, "segments");
RNA_def_property_range(prop, 1, 32);
RNA_def_property_ui_text(prop, "B-Bone Segments", "Number of subdivisions of bone (for B-Bones only)");
- RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+ RNA_def_property_update(prop, 0, "rna_Armature_dependency_update");
prop = RNA_def_property(srna, "bbone_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xwidth");
@@ -709,6 +830,50 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_range(prop, 0.0f, 1000.0f);
RNA_def_property_ui_text(prop, "B-Bone Display Z Width", "B-Bone Z size");
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
+
+ prop = RNA_def_property(srna, "bbone_handle_type_start", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "bbone_prev_type");
+ RNA_def_property_enum_items(prop, prop_bbone_handle_type);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "B-Bone Start Handle Type", "Selects how the start handle of the B-Bone is computed");
+ RNA_def_property_update(prop, 0, "rna_Armature_dependency_update");
+
+ prop = RNA_def_property(srna, "bbone_custom_handle_start", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "bbone_prev");
+ RNA_def_property_struct_type(prop, editbone ? "EditBone" : "Bone");
+ if (editbone) {
+ RNA_def_property_pointer_funcs(prop, "rna_EditBone_bbone_prev_get", "rna_EditBone_bbone_prev_set", NULL, NULL);
+ RNA_def_property_update(prop, 0, "rna_Armature_dependency_update");
+ }
+ else {
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Bone_bbone_prev_set", NULL, NULL);
+ RNA_def_property_update(prop, 0, "rna_Bone_bbone_handle_update");
+ }
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_ui_text(prop, "B-Bone Start Handle",
+ "Bone that serves as the start handle for the B-Bone curve");
+
+ prop = RNA_def_property(srna, "bbone_handle_type_end", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "bbone_next_type");
+ RNA_def_property_enum_items(prop, prop_bbone_handle_type);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "B-Bone End Handle Type", "Selects how the end handle of the B-Bone is computed");
+ RNA_def_property_update(prop, 0, "rna_Armature_dependency_update");
+
+ prop = RNA_def_property(srna, "bbone_custom_handle_end", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "bbone_next");
+ RNA_def_property_struct_type(prop, editbone ? "EditBone" : "Bone");
+ if (editbone) {
+ RNA_def_property_pointer_funcs(prop, "rna_EditBone_bbone_next_get", "rna_EditBone_bbone_next_set", NULL, NULL);
+ RNA_def_property_update(prop, 0, "rna_Armature_dependency_update");
+ }
+ else {
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Bone_bbone_next_set", NULL, NULL);
+ RNA_def_property_update(prop, 0, "rna_Bone_bbone_handle_update");
+ }
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_ui_text(prop, "B-Bone End Handle",
+ "Bone that serves as the end handle for the B-Bone curve");
}
/* err... bones should not be directly edited (only editbones should be...) */
@@ -728,6 +893,7 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Bone");
RNA_def_property_pointer_sdna(prop, NULL, "parent");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_ui_text(prop, "Parent", "Parent bone (in same Armature)");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
@@ -735,6 +901,7 @@ static void rna_def_bone(BlenderRNA *brna)
prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "childbase", NULL);
RNA_def_property_struct_type(prop, "Bone");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_ui_text(prop, "Children", "Bones which are children of this bone");
rna_def_bone_common(srna, 0);
@@ -989,11 +1156,6 @@ static void rna_def_armature(BlenderRNA *brna)
{ARM_WIRE, "WIRE", 0, "Wire", "Display bones as thin wires, showing subdivision and B-Splines"},
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem prop_vdeformer[] = {
- {ARM_VDEF_BLENDER, "BLENDER", 0, "Blender", "Use Blender's armature vertex deformation"},
- {ARM_VDEF_BGE_CPU, "BGE_CPU", 0, "BGE", "Use vertex deformation code optimized for the BGE"},
- {0, NULL, 0, NULL, NULL}
- };
static const EnumPropertyItem prop_ghost_type_items[] = {
{ARM_GHOST_CUR, "CURRENT_FRAME", 0, "Around Frame",
"Display Ghosts of poses within a fixed number of frames around the current frame"},
@@ -1044,17 +1206,10 @@ static void rna_def_armature(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
- prop = RNA_def_property(srna, "draw_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "drawtype");
RNA_def_property_enum_items(prop, prop_drawtype_items);
- RNA_def_property_ui_text(prop, "Draw Type", "");
- RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
- RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
-
- prop = RNA_def_property(srna, "deform_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "gevertdeformer");
- RNA_def_property_enum_items(prop, prop_vdeformer);
- RNA_def_property_ui_text(prop, "Vertex Deformer", "Vertex Deformer Method (Game Engine only)");
+ RNA_def_property_ui_text(prop, "Display Type Type", "");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
@@ -1089,13 +1244,13 @@ static void rna_def_armature(BlenderRNA *brna)
/* flag */
prop = RNA_def_property(srna, "show_axes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_DRAWAXES);
- RNA_def_property_ui_text(prop, "Draw Axes", "Draw bone axes");
+ RNA_def_property_ui_text(prop, "Display Axes", "Display bone axes");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
prop = RNA_def_property(srna, "show_names", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_DRAWNAMES);
- RNA_def_property_ui_text(prop, "Draw Names", "Draw bone names");
+ RNA_def_property_ui_text(prop, "Display Names", "Display bone names");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
@@ -1118,18 +1273,18 @@ static void rna_def_armature(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_bone_custom_shapes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ARM_NO_CUSTOM);
- RNA_def_property_ui_text(prop, "Draw Custom Bone Shapes", "Draw bones with their custom shapes");
+ RNA_def_property_ui_text(prop, "Display Custom Bone Shapes", "Display bones with their custom shapes");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
prop = RNA_def_property(srna, "show_group_colors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_COL_CUSTOM);
- RNA_def_property_ui_text(prop, "Draw Bone Group Colors", "Draw bone group colors");
+ RNA_def_property_ui_text(prop, "Display Bone Group Colors", "Display bone group colors");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
/* XXX deprecated ....... old animviz for armatures only */
prop = RNA_def_property(srna, "show_only_ghost_selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_GHOST_ONLYSEL);
- RNA_def_property_ui_text(prop, "Draw Ghosts on Selected Bones Only", "");
+ RNA_def_property_ui_text(prop, "Display Ghosts on Selected Bones Only", "");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
/* XXX deprecated ....... old animviz for armatures only */
diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c
index 222baf99afd..55caac973d8 100644
--- a/source/blender/makesrna/intern/rna_armature_api.c
+++ b/source/blender/makesrna/intern/rna_armature_api.c
@@ -42,6 +42,7 @@
#include <stddef.h>
+#include "BLI_math_vector.h"
#include "BKE_armature.h"
static void rna_EditBone_align_roll(EditBone *ebo, float no[3])
@@ -56,6 +57,24 @@ static float rna_Bone_do_envelope(Bone *bone, float *vec)
bone->rad_tail * scale, bone->dist * scale);
}
+static void rna_Bone_MatrixFromAxisRoll(float *axis, float roll, float *r_matrix)
+{
+ vec_roll_to_mat3(axis, roll, (float (*)[3])r_matrix);
+}
+
+static void rna_Bone_AxisRollFromMatrix(float *matrix, float *axis_override, float *r_axis, float *r_roll)
+{
+ float mat[3][3];
+
+ normalize_m3_m3(mat, (float (*)[3])matrix);
+
+ if (normalize_v3_v3(r_axis, axis_override) != 0.0f) {
+ mat3_vec_to_roll(mat, r_axis, r_roll);
+ }
+ else {
+ mat3_to_vec_roll(mat, r_axis, r_roll);
+ }
+}
#else
void RNA_api_armature_edit_bone(StructRNA *srna)
@@ -83,6 +102,40 @@ void RNA_api_bone(StructRNA *srna)
/* return value */
parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX);
RNA_def_function_return(func, parm);
+
+ /* Conversions between Matrix and Axis + Roll representations. */
+ func = RNA_def_function(srna, "MatrixFromAxisRoll", "rna_Bone_MatrixFromAxisRoll");
+ RNA_def_function_ui_description(func, "Convert the axis + roll representation to a matrix");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_property(func, "axis", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ RNA_def_property_ui_text(parm, "", "The main axis of the bone (tail - head)");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_property(func, "roll", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(parm, "", "The roll of the bone");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_property(func, "result_matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_3x3);
+ RNA_def_property_ui_text(parm, "", "The resulting orientation matrix");
+ RNA_def_function_output(func, parm);
+
+ func = RNA_def_function(srna, "AxisRollFromMatrix", "rna_Bone_AxisRollFromMatrix");
+ RNA_def_function_ui_description(func, "Convert a rotational matrix to the axis + roll representation");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_3x3);
+ RNA_def_property_ui_text(parm, "", "The orientation matrix of the bone");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_property(func, "axis", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_array(parm, 3);
+ RNA_def_property_ui_text(parm, "", "The optional override for the axis (finds closest approximation for the matrix)");
+ parm = RNA_def_property(func, "result_axis", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ RNA_def_property_ui_text(parm, "", "The main axis of the bone");
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_property(func, "result_roll", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(parm, "", "The roll of the bone");
+ RNA_def_function_output(func, parm);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c
index 8b0623a867c..413cb10422a 100644
--- a/source/blender/makesrna/intern/rna_boid.c
+++ b/source/blender/makesrna/intern/rna_boid.c
@@ -87,9 +87,11 @@ static const EnumPropertyItem boidruleset_type_items[] = {
#include "BLI_math_base.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_particle.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
static void rna_Boids_reset(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
if (ptr->type == &RNA_ParticleSystem) {
@@ -97,10 +99,10 @@ static void rna_Boids_reset(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRN
psys->recalc = PSYS_RECALC_RESET;
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
else
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
}
@@ -111,12 +113,12 @@ static void rna_Boids_reset_deps(Main *bmain, Scene *UNUSED(scene), PointerRNA *
psys->recalc = PSYS_RECALC_RESET;
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
else
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 4fba7a91a32..d9b9677bbc6 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -31,6 +31,8 @@
#include "DNA_texture_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
@@ -44,8 +46,8 @@
#include "WM_types.h"
static const EnumPropertyItem prop_direction_items[] = {
- {0, "ADD", 0, "Add", "Add effect of brush"},
- {BRUSH_DIR_IN, "SUBTRACT", 0, "Subtract", "Subtract effect of brush"},
+ {0, "ADD", ICON_ADD, "Add", "Add effect of brush"},
+ {BRUSH_DIR_IN, "SUBTRACT", ICON_REMOVE, "Subtract", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}
};
@@ -63,52 +65,44 @@ static const EnumPropertyItem sculpt_stroke_method_items[] = {
const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
- {SCULPT_TOOL_BLOB, "BLOB", ICON_BRUSH_BLOB, "Blob", ""},
+ {SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""},
{SCULPT_TOOL_CLAY, "CLAY", ICON_BRUSH_CLAY, "Clay", ""},
{SCULPT_TOOL_CLAY_STRIPS, "CLAY_STRIPS", ICON_BRUSH_CLAY_STRIPS, "Clay Strips", ""},
+ {SCULPT_TOOL_LAYER, "LAYER", ICON_BRUSH_LAYER, "Layer", ""},
+ {SCULPT_TOOL_INFLATE, "INFLATE", ICON_BRUSH_INFLATE, "Inflate", ""},
+ {SCULPT_TOOL_BLOB, "BLOB", ICON_BRUSH_BLOB, "Blob", ""},
{SCULPT_TOOL_CREASE, "CREASE", ICON_BRUSH_CREASE, "Crease", ""},
- {SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""},
- {SCULPT_TOOL_FILL, "FILL", ICON_BRUSH_FILL, "Fill", ""},
+ {0, "", 0, NULL, NULL},
+ {SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_SMOOTH, "Smooth", ""},
{SCULPT_TOOL_FLATTEN, "FLATTEN", ICON_BRUSH_FLATTEN, "Flatten", ""},
+ {SCULPT_TOOL_FILL, "FILL", ICON_BRUSH_FILL, "Fill", ""},
+ {SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""},
+ {SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""},
+ {0, "", 0, NULL, NULL},
{SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""},
- {SCULPT_TOOL_INFLATE, "INFLATE", ICON_BRUSH_INFLATE, "Inflate", ""},
- {SCULPT_TOOL_LAYER, "LAYER", ICON_BRUSH_LAYER, "Layer", ""},
- {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
+ {SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""},
+ {SCULPT_TOOL_THUMB, "THUMB", ICON_BRUSH_THUMB, "Thumb", ""},
{SCULPT_TOOL_NUDGE, "NUDGE", ICON_BRUSH_NUDGE, "Nudge", ""},
- {SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""},
{SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""},
- {SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""},
+ {0, "", 0, NULL, NULL},
+ {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_SUBTRACT /* icon TODO */, "Simplify", ""},
- {SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_SMOOTH, "Smooth", ""},
- {SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""},
- {SCULPT_TOOL_THUMB, "THUMB", ICON_BRUSH_THUMB, "Thumb", ""},
{0, NULL, 0, NULL, NULL}
};
-
const EnumPropertyItem rna_enum_brush_vertex_tool_items[] = {
- {PAINT_BLEND_MIX, "MIX", ICON_BRUSH_MIX, "Mix", "Use mix blending mode while painting"},
- {PAINT_BLEND_ADD, "ADD", ICON_BRUSH_ADD, "Add", "Use add blending mode while painting"},
- {PAINT_BLEND_SUB, "SUB", ICON_BRUSH_SUBTRACT, "Subtract", "Use subtract blending mode while painting"},
- {PAINT_BLEND_MUL, "MUL", ICON_BRUSH_MULTIPLY, "Multiply", "Use multiply blending mode while painting"},
- {PAINT_BLEND_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", "Blur the color with surrounding values"},
- {PAINT_BLEND_LIGHTEN, "LIGHTEN", ICON_BRUSH_LIGHTEN, "Lighten", "Use lighten blending mode while painting"},
- {PAINT_BLEND_DARKEN, "DARKEN", ICON_BRUSH_DARKEN, "Darken", "Use darken blending mode while painting"},
- {PAINT_BLEND_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", "Use average blending mode while painting"},
- {PAINT_BLEND_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", "Use smear blending mode while painting"},
- {PAINT_BLEND_COLORDODGE, "COLORDODGE", ICON_BRUSH_BLUR, "Color Dodge", "Use color dodge blending mode while painting" },
- {PAINT_BLEND_DIFFERENCE, "DIFFERENCE", ICON_BRUSH_BLUR, "Difference", "Use difference blending mode while painting"},
- {PAINT_BLEND_SCREEN, "SCREEN", ICON_BRUSH_BLUR, "Screen", "Use screen blending mode while painting"},
- {PAINT_BLEND_HARDLIGHT, "HARDLIGHT", ICON_BRUSH_BLUR, "Hardlight", "Use hardlight blending mode while painting"},
- {PAINT_BLEND_OVERLAY, "OVERLAY", ICON_BRUSH_BLUR, "Overlay", "Use overlay blending mode while painting"},
- {PAINT_BLEND_SOFTLIGHT, "SOFTLIGHT", ICON_BRUSH_BLUR, "Softlight", "Use softlight blending mode while painting"},
- {PAINT_BLEND_EXCLUSION, "EXCLUSION", ICON_BRUSH_BLUR, "Exclusion", "Use exclusion blending mode while painting"},
- {PAINT_BLEND_LUMINOCITY, "LUMINOCITY", ICON_BRUSH_BLUR, "Luminocity", "Use luminocity blending mode while painting"},
- {PAINT_BLEND_SATURATION, "SATURATION", ICON_BRUSH_BLUR, "Saturation", "Use saturation blending mode while painting"},
- {PAINT_BLEND_HUE, "HUE", ICON_BRUSH_BLUR, "Hue", "Use hue blending mode while painting"},
- {PAINT_BLEND_ALPHA_SUB, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"},
- {PAINT_BLEND_ALPHA_ADD, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"},
+ {VPAINT_TOOL_DRAW, "DRAW", ICON_BRUSH_MIX, "Draw", ""},
+ {VPAINT_TOOL_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""},
+ {VPAINT_TOOL_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", ""},
+ {VPAINT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+const EnumPropertyItem rna_enum_brush_weight_tool_items[] = {
+ {WPAINT_TOOL_DRAW, "DRAW", ICON_BRUSH_MIX, "Draw", ""},
+ {WPAINT_TOOL_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""},
+ {WPAINT_TOOL_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", ""},
+ {WPAINT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -122,6 +116,44 @@ const EnumPropertyItem rna_enum_brush_image_tool_items[] = {
{0, NULL, 0, NULL, NULL}
};
+const EnumPropertyItem rna_enum_brush_gpencil_types_items[] = {
+ {GPAINT_TOOL_DRAW, "DRAW", ICON_STROKE, "Draw", "The brush is of type used for drawing strokes"},
+ {GPAINT_TOOL_FILL, "FILL", ICON_COLOR, "Fill", "The brush is of type used for filling areas"},
+ {GPAINT_TOOL_ERASE, "ERASE", ICON_PANEL_CLOSE, "Erase", "The brush is used for erasing strokes"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+#ifndef RNA_RUNTIME
+static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = {
+ {GP_BRUSH_ERASER_SOFT, "SOFT", 0, "Soft", "Use soft eraser"},
+ {GP_BRUSH_ERASER_HARD, "HARD", 0, "Hard", "Use hard eraser"},
+ {GP_BRUSH_ERASER_STROKE, "STROKE", 0, "Stroke", "Use stroke eraser"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem rna_enum_gpencil_fill_draw_modes_items[] = {
+ {GP_FILL_DMODE_STROKE, "STROKE", 0, "Strokes", "Use visible strokes as fill boundary limits"},
+ {GP_FILL_DMODE_CONTROL, "CONTROL", 0, "Control", "Use internal control lines as fill boundary limits"},
+ {GP_FILL_DMODE_BOTH, "BOTH", 0, "Both", "Use visible strokes and control lines as fill boundary limits"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem rna_enum_gpencil_brush_icons_items[] = {
+ {GP_BRUSH_ICON_PENCIL, "PENCIL", ICON_GPBRUSH_PENCIL, "Pencil", ""},
+ {GP_BRUSH_ICON_PEN, "PEN", ICON_GPBRUSH_PEN, "Pen", ""},
+ {GP_BRUSH_ICON_INK, "INK", ICON_GPBRUSH_INK, "Ink", ""},
+ {GP_BRUSH_ICON_INKNOISE, "INKNOISE", ICON_GPBRUSH_INKNOISE, "Ink Noise", ""},
+ {GP_BRUSH_ICON_BLOCK, "BLOCK", ICON_GPBRUSH_BLOCK, "Block", ""},
+ {GP_BRUSH_ICON_MARKER, "MARKER", ICON_GPBRUSH_MARKER, "Marker", ""},
+ {GP_BRUSH_ICON_FILL, "FILL", ICON_GPBRUSH_FILL, "Fill", ""},
+ {GP_BRUSH_ICON_ERASE_SOFT, "SOFT", ICON_GPBRUSH_ERASE_SOFT, "Eraser Soft", ""},
+ {GP_BRUSH_ICON_ERASE_HARD, "HARD", ICON_GPBRUSH_ERASE_HARD, "Eraser Hard", ""},
+ {GP_BRUSH_ICON_ERASE_STROKE, "STROKE", ICON_GPBRUSH_ERASE_STROKE, "Eraser Stroke", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
+
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
@@ -131,6 +163,7 @@ const EnumPropertyItem rna_enum_brush_image_tool_items[] = {
#include "BKE_colorband.h"
#include "BKE_brush.h"
#include "BKE_icons.h"
+#include "BKE_gpencil.h"
#include "BKE_paint.h"
#include "WM_api.h"
@@ -349,7 +382,7 @@ static PointerRNA rna_Brush_capabilities_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_BrushCapabilities, ptr->id.data);
}
-static void rna_Brush_reset_icon(Brush *br, const char *UNUSED(type))
+static void rna_Brush_reset_icon(Brush *br)
{
ID *id = &br->id;
@@ -371,44 +404,61 @@ static void rna_Brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
/*WM_main_add_notifier(NC_SPACE|ND_SPACE_VIEW3D, NULL); */
}
-static void rna_Brush_main_tex_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Brush_material_update(bContext *C, PointerRNA *ptr)
{
- Brush *br = (Brush *)ptr->data;
- BKE_paint_invalidate_overlay_tex(scene, br->mtex.tex);
- rna_Brush_update(bmain, scene, ptr);
-}
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ Brush *br = (Brush *)ptr->id.data;
+ int index;
+
+ /* set material slot to same material */
+ if ((ob) && (ob->type == OB_GPENCIL) && (br->gpencil_settings != NULL)) {
+ BrushGpencilSettings *gpencil_settings = br->gpencil_settings;
+ if (gpencil_settings->material != NULL) {
+
+ index = BKE_gpencil_get_material_index(ob, gpencil_settings->material);
+ if ((index > 0) && (ob->actcol != index)) {
+ ob->actcol = index;
+ /* update other brushes to keep all synchro */
+ BKE_brush_update_material(bmain, gpencil_settings->material, br);
+ }
-static void rna_Brush_secondary_tex_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Brush *br = (Brush *)ptr->data;
- BKE_paint_invalidate_overlay_tex(scene, br->mask_mtex.tex);
- rna_Brush_update(bmain, scene, ptr);
+ }
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_PROPERTIES, NULL);
+ }
}
-static void rna_Brush_size_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Brush_main_tex_update(bContext *C, PointerRNA *ptr)
{
- BKE_paint_invalidate_overlay_all();
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Brush *br = (Brush *)ptr->data;
+ BKE_paint_invalidate_overlay_tex(scene, view_layer, br->mtex.tex);
rna_Brush_update(bmain, scene, ptr);
}
-static void rna_Brush_sculpt_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Brush_secondary_tex_update(bContext *C, PointerRNA *ptr)
{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Brush *br = (Brush *)ptr->data;
- rna_Brush_reset_icon(br, "sculpt");
+ BKE_paint_invalidate_overlay_tex(scene, view_layer, br->mask_mtex.tex);
rna_Brush_update(bmain, scene, ptr);
}
-static void rna_Brush_vertex_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Brush_size_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- Brush *br = (Brush *)ptr->data;
- rna_Brush_reset_icon(br, "vertex_paint");
+ BKE_paint_invalidate_overlay_all();
rna_Brush_update(bmain, scene, ptr);
}
-static void rna_Brush_imagepaint_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Brush_update_and_reset_icon(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- Brush *br = (Brush *)ptr->data;
- rna_Brush_reset_icon(br, "image_paint");
+ Brush *br = ptr->data;
+ rna_Brush_reset_icon(br);
rna_Brush_update(bmain, scene, ptr);
}
@@ -436,14 +486,17 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
}
-static void rna_TextureSlot_brush_angle_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_TextureSlot_brush_angle_update(bContext *C, PointerRNA *ptr)
{
+ Scene *scene = CTX_data_scene(C);
MTex *mtex = ptr->data;
/* skip invalidation of overlay for stencil mode */
- if (mtex->mapping != MTEX_MAP_MODE_STENCIL)
- BKE_paint_invalidate_overlay_tex(scene, mtex->tex);
+ if (mtex->mapping != MTEX_MAP_MODE_STENCIL) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BKE_paint_invalidate_overlay_tex(scene, view_layer, mtex->tex);
+ }
- rna_TextureSlot_update(bmain, scene, ptr);
+ rna_TextureSlot_update(C, ptr);
}
static void rna_Brush_set_size(PointerRNA *ptr, int value)
@@ -487,39 +540,39 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA
/* sculpt mode */
static const EnumPropertyItem prop_flatten_contrast_items[] = {
- {0, "FLATTEN", 0, "Flatten", "Add effect of brush"},
- {BRUSH_DIR_IN, "CONTRAST", 0, "Contrast", "Subtract effect of brush"},
+ {BRUSH_DIR_IN, "CONTRAST", ICON_ADD, "Contrast", "Subtract effect of brush"},
+ {0, "FLATTEN", ICON_REMOVE, "Flatten", "Add effect of brush"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem prop_fill_deepen_items[] = {
- {0, "FILL", 0, "Fill", "Add effect of brush"},
- {BRUSH_DIR_IN, "DEEPEN", 0, "Deepen", "Subtract effect of brush"},
+ {0, "FILL", ICON_ADD, "Fill", "Add effect of brush"},
+ {BRUSH_DIR_IN, "DEEPEN", ICON_REMOVE, "Deepen", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem prop_scrape_peaks_items[] = {
- {0, "SCRAPE", 0, "Scrape", "Add effect of brush"},
- {BRUSH_DIR_IN, "PEAKS", 0, "Peaks", "Subtract effect of brush"},
+ {0, "SCRAPE", ICON_ADD, "Scrape", "Add effect of brush"},
+ {BRUSH_DIR_IN, "PEAKS", ICON_REMOVE, "Peaks", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem prop_pinch_magnify_items[] = {
- {0, "PINCH", 0, "Pinch", "Add effect of brush"},
- {BRUSH_DIR_IN, "MAGNIFY", 0, "Magnify", "Subtract effect of brush"},
+ {BRUSH_DIR_IN, "MAGNIFY", ICON_ADD, "Magnify", "Subtract effect of brush"},
+ {0, "PINCH", ICON_REMOVE, "Pinch", "Add effect of brush"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem prop_inflate_deflate_items[] = {
- {0, "INFLATE", 0, "Inflate", "Add effect of brush"},
- {BRUSH_DIR_IN, "DEFLATE", 0, "Deflate", "Subtract effect of brush"},
+ {0, "INFLATE", ICON_ADD, "Inflate", "Add effect of brush"},
+ {BRUSH_DIR_IN, "DEFLATE", ICON_REMOVE, "Deflate", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}
};
/* texture paint mode */
static const EnumPropertyItem prop_soften_sharpen_items[] = {
- {0, "SOFTEN", 0, "Soften", "Blur effect of brush"},
- {BRUSH_DIR_IN, "SHARPEN", 0, "Sharpen", "Sharpen effect of brush"},
+ {BRUSH_DIR_IN, "SHARPEN", ICON_ADD, "Sharpen", "Sharpen effect of brush"},
+ {0, "SOFTEN", ICON_REMOVE, "Soften", "Blur effect of brush"},
{0, NULL, 0, NULL, NULL}
};
@@ -606,6 +659,63 @@ static const EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C, PointerRNA *U
return brush_stroke_method_items;
}
}
+
+/* Grease Pencil Drawing Brushes Settings */
+static char *rna_BrushGpencilSettings_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_paint.brush.gpencil_settings");
+}
+
+static void rna_BrushGpencilSettings_default_eraser_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ ToolSettings *ts = scene->toolsettings;
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *brush_cur = paint->brush;
+
+ /* disable default eraser in all brushes */
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if ((brush != brush_cur) &&
+ (brush->ob_mode == OB_MODE_GPENCIL_PAINT) &&
+ (brush->gpencil_tool == GPAINT_TOOL_ERASE))
+ {
+ brush->gpencil_settings->flag &= ~GP_BRUSH_DEFAULT_ERASER;
+ }
+ }
+}
+
+static void rna_BrushGpencilSettings_eraser_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ ToolSettings *ts = scene->toolsettings;
+ Paint *paint = &ts->gp_paint->paint;
+ Brush *brush = paint->brush;
+
+ /* set eraser icon */
+ if ((brush) && (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
+ switch (brush->gpencil_settings->eraser_mode) {
+ case GP_BRUSH_ERASER_SOFT:
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ break;
+ case GP_BRUSH_ERASER_HARD:
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ break;
+ case GP_BRUSH_ERASER_STROKE:
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
+ break;
+ default:
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ break;
+ }
+ }
+}
+
+static bool rna_BrushGpencilSettings_material_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+{
+ Material *ma = (Material *)value.data;
+
+ /* GP materials only */
+ return (ma->gp_style != NULL);
+}
+
#else
static void rna_def_brush_texture_slot(BlenderRNA *brna)
@@ -657,39 +767,46 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "rot");
RNA_def_property_range(prop, 0, M_PI * 2);
RNA_def_property_ui_text(prop, "Angle", "Brush texture rotation");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_angle_update");
prop = RNA_def_property(srna, "map_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "tex_paint_map_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_tex_paint_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "mask_map_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_mask_paint_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "use_rake", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "brush_angle_mode", MTEX_ANGLE_RAKE);
RNA_def_property_ui_text(prop, "Rake", "");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "use_random", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "brush_angle_mode", MTEX_ANGLE_RANDOM);
RNA_def_property_ui_text(prop, "Random", "");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "random_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0, M_PI * 2);
RNA_def_property_ui_text(prop, "Random Angle", "Brush texture random angle");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
TEXTURE_CAPABILITY(has_texture_angle_source, "Has Texture Angle Source");
@@ -793,6 +910,325 @@ static void rna_def_image_paint_capabilities(BlenderRNA *brna)
#undef IMAPAINT_TOOL_CAPABILITY
}
+static void rna_def_gpencil_options(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "BrushGpencilSettings", NULL);
+ RNA_def_struct_sdna(srna, "BrushGpencilSettings");
+ RNA_def_struct_path_func(srna, "rna_BrushGpencilSettings_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Brush Settings", "Settings for grease pencil brush");
+
+ /* Sensitivity factor for new strokes */
+ prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity");
+ RNA_def_property_range(prop, 0.1f, 3.0f);
+ RNA_def_property_ui_text(prop, "Sensitivity", "Pressure sensitivity factor for new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Strength factor for new strokes */
+ prop = RNA_def_property(srna, "pen_strength", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "draw_strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
+ RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Jitter factor for new strokes */
+ prop = RNA_def_property(srna, "pen_jitter", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_jitter");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Randomnes factor for pressure */
+ prop = RNA_def_property(srna, "random_pressure", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_random_press");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Pressure Randomness", "Randomness factor for pressure in new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Randomnes factor for strength */
+ prop = RNA_def_property(srna, "random_strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_random_strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Strength Randomness", "Randomness factor strength in new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Randomnes factor for subdivision */
+ prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_random_sub");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Random Subdivision", "Randomness factor for new strokes after subdivision");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Angle when brush is full size */
+ prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_angle");
+ RNA_def_property_range(prop, -M_PI_2, M_PI_2);
+ RNA_def_property_ui_text(prop, "Angle",
+ "Direction of the stroke at which brush gives maximal thickness "
+ "(0° for horizontal)");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Factor to change brush size depending of angle */
+ prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Angle Factor",
+ "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Smoothing factor for new strokes */
+ prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
+ RNA_def_property_range(prop, 0.0, 2.0f);
+ RNA_def_property_ui_text(prop, "Smooth",
+ "Amount of smoothing to apply after finish newly created strokes, to reduce jitter/noise");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Iterations of the Smoothing factor */
+ prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
+ RNA_def_property_range(prop, 1, 3);
+ RNA_def_property_ui_text(prop, "Iterations",
+ "Number of times to smooth newly created strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Thickness smoothing factor for new strokes */
+ prop = RNA_def_property(srna, "pen_thick_smooth_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "thick_smoothfac");
+ RNA_def_property_range(prop, 0.0, 2.0f);
+ RNA_def_property_ui_text(prop, "Smooth Thickness",
+ "Amount of thickness smoothing to apply after finish newly created strokes, to reduce jitter/noise");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Thickness iterations of the Smoothing factor */
+ prop = RNA_def_property(srna, "pen_thick_smooth_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "thick_smoothlvl");
+ RNA_def_property_range(prop, 1, 3);
+ RNA_def_property_ui_text(prop, "Iterations Thickness",
+ "Number of times to smooth thickness for newly created strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Subdivision level for new strokes */
+ prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "draw_subdivide");
+ RNA_def_property_range(prop, 0, 3);
+ RNA_def_property_ui_text(prop, "Subdivision Steps",
+ "Number of times to subdivide newly created strokes, for less jagged strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Curves for pressure */
+ prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_sensitivity");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_strength");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_jitter");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* fill threshold for transparence */
+ prop = RNA_def_property(srna, "fill_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "fill_threshold");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Threshold",
+ "Threshold to consider color transparent for filling");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* fill leak size */
+ prop = RNA_def_property(srna, "fill_leak", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "fill_leak");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Leak Size",
+ "Size in pixels to consider the leak closed");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* fill simplify steps */
+ prop = RNA_def_property(srna, "fill_simplify_level", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "fill_simplylvl");
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_text(prop, "Simplify",
+ "Number of simplify steps (large values reduce fill accuracy)");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "uv_random", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_random");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(prop, "UV Random", "Random factor for autogenerated UV rotation");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "input_samples");
+ RNA_def_property_range(prop, 0, GP_MAX_INPUT_SAMPLES);
+ RNA_def_property_ui_text(prop, "Input Samples", "Generate intermediate points for very fast mouse movements. Set to 0 to disable");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* active smooth factor while drawing */
+ prop = RNA_def_property(srna, "active_smooth_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "active_smooth");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Active Smooth",
+ "Amount of smoothing while drawing ");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "eraser_strength_factor", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_float_sdna(prop, NULL, "era_strength_f");
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1);
+ RNA_def_property_ui_text(prop, "Affect Stroke Strength",
+ "Amount of erasing for strength ");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "eraser_thickness_factor", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_float_sdna(prop, NULL, "era_thickness_f");
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 10, 1);
+ RNA_def_property_ui_text(prop, "Affect Stroke Thickness",
+ "Amount of erasing for thickness ");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* brush standard icon */
+ prop = RNA_def_property(srna, "gp_icon", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "icon_id");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_icons_items);
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_ui_text(prop, "Grease Pencil Icon", "");
+
+ /* Flags */
+ prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_settings_stabilizer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_STABILIZE_MOUSE);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Use Stabilizer",
+ "Draw lines with a delay to allow smooth strokes. Press Shift key to override while drawing");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "use_cursor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_ENABLE_CURSOR);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "eraser_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "eraser_mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_eraser_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Eraser Mode");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_eraser_mode_update");
+
+ prop = RNA_def_property(srna, "fill_draw_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "fill_draw_mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_fill_draw_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode to draw boundary limits");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ /* Material */
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Material");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_BrushGpencilSettings_material_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_CONTEXT_UPDATE);
+ RNA_def_property_ui_text(prop, "Material", "Material used for strokes drawn using this brush");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_Brush_material_update");
+
+ prop = RNA_def_property(srna, "show_fill_boundary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_SHOW_HELPLINES);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Show Lines", "Show help lines for filling to see boundaries");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "show_fill", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_BRUSH_FILL_HIDE);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Show Fill", "Show transparent lines to use as boundary for filling");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "use_default_eraser", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_DEFAULT_ERASER);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
+ RNA_def_property_ui_text(prop, "Default Eraser", "Use this brush when enable eraser with fast switch key");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_default_eraser_update");
+
+ prop = RNA_def_property(srna, "use_settings_postprocess", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_GROUP_SETTINGS);
+ RNA_def_property_ui_text(prop, "Use Post-Process Settings", "Additional post processing options for new strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "use_settings_random", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_GROUP_RANDOM);
+ RNA_def_property_ui_text(prop, "Random Settings", "Random brush settings");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "use_material_pin", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_MATERIAL_PINNED);
+ RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
+ RNA_def_property_ui_text(prop, "Pin Material", "Keep material assigned to brush");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "show_lasso", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_BRUSH_DISSABLE_LASSO);
+ RNA_def_property_ui_text(prop, "Show Lasso", "Do not draw fill color while drawing the stroke");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+}
+
static void rna_def_brush(BlenderRNA *brna)
{
StructRNA *srna;
@@ -800,29 +1236,35 @@ static void rna_def_brush(BlenderRNA *brna)
static const EnumPropertyItem prop_blend_items[] = {
{IMB_BLEND_MIX, "MIX", 0, "Mix", "Use mix blending mode while painting"},
- {IMB_BLEND_ADD, "ADD", 0, "Add", "Use add blending mode while painting"},
- {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use subtract blending mode while painting"},
- {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use multiply blending mode while painting"},
- {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use lighten blending mode while painting"},
+ {0, "", ICON_NONE, NULL, NULL},
{IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use darken blending mode while painting"},
- {IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"},
- {IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"},
- {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use overlay blending mode while painting"},
- {IMB_BLEND_HARDLIGHT, "HARDLIGHT", 0, "Hard light", "Use hard light blending mode while painting"},
+ {IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use multiply blending mode while painting"},
{IMB_BLEND_COLORBURN, "COLORBURN", 0, "Color burn", "Use color burn blending mode while painting"},
{IMB_BLEND_LINEARBURN, "LINEARBURN", 0, "Linear burn", "Use linear burn blending mode while painting"},
- {IMB_BLEND_COLORDODGE, "COLORDODGE", 0, "Color dodge", "Use color dodge blending mode while painting"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use lighten blending mode while painting"},
{IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use screen blending mode while painting"},
+ {IMB_BLEND_COLORDODGE, "COLORDODGE", 0, "Color dodge", "Use color dodge blending mode while painting"},
+ {IMB_BLEND_ADD, "ADD", 0, "Add", "Use add blending mode while painting"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use overlay blending mode while painting"},
{IMB_BLEND_SOFTLIGHT, "SOFTLIGHT", 0, "Soft light", "Use softlight blending mode while painting"},
- {IMB_BLEND_PINLIGHT, "PINLIGHT", 0, "Pin light", "Use pinlight blending mode while painting"},
+ {IMB_BLEND_HARDLIGHT, "HARDLIGHT", 0, "Hard light", "Use hard light blending mode while painting"},
{IMB_BLEND_VIVIDLIGHT, "VIVIDLIGHT", 0, "Vivid light", "Use vividlight blending mode while painting"},
{IMB_BLEND_LINEARLIGHT, "LINEARLIGHT", 0, "Linear light", "Use linearlight blending mode while painting"},
+ {IMB_BLEND_PINLIGHT, "PINLIGHT", 0, "Pin light", "Use pinlight blending mode while painting"},
+ {0, "", ICON_NONE, NULL, NULL},
{IMB_BLEND_DIFFERENCE, "DIFFERENCE", 0, "Difference", "Use difference blending mode while painting"},
{IMB_BLEND_EXCLUSION, "EXCLUSION", 0, "Exclusion", "Use exclusion blending mode while painting"},
+ {IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use subtract blending mode while painting"},
+ {0, "", ICON_NONE, NULL, NULL},
{IMB_BLEND_HUE, "HUE", 0, "Hue", "Use hue blending mode while painting"},
{IMB_BLEND_SATURATION, "SATURATION", 0, "Saturation", "Use saturation blending mode while painting"},
- {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Luminosity", "Use luminosity blending mode while painting"},
{IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use color blending mode while painting"},
+ {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Luminosity", "Use luminosity blending mode while painting"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"},
+ {IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"},
{0, NULL, 0, NULL, NULL}
};
@@ -877,22 +1319,42 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Blending mode", "Brush blending mode");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ /**
+ * Begin per-mode tool properties.
+ *
+ * keep in sync with #BKE_paint_get_tool_prop_id_from_paintmode
+ */
prop = RNA_def_property(srna, "sculpt_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_brush_sculpt_tool_items);
RNA_def_property_ui_text(prop, "Sculpt Tool", "");
- RNA_def_property_update(prop, 0, "rna_Brush_sculpt_tool_update");
+ RNA_def_property_update(prop, 0, "rna_Brush_update_and_reset_icon");
prop = RNA_def_property(srna, "vertex_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "vertexpaint_tool");
RNA_def_property_enum_items(prop, rna_enum_brush_vertex_tool_items);
- RNA_def_property_ui_text(prop, "Blending mode", "Brush blending mode");
- RNA_def_property_update(prop, 0, "rna_Brush_vertex_tool_update");
+ RNA_def_property_ui_text(prop, "Vertex Paint Tool", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update_and_reset_icon");
+
+ prop = RNA_def_property(srna, "weight_tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "weightpaint_tool");
+ RNA_def_property_enum_items(prop, rna_enum_brush_weight_tool_items);
+ RNA_def_property_ui_text(prop, "Weight Paint Tool", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update_and_reset_icon");
prop = RNA_def_property(srna, "image_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "imagepaint_tool");
RNA_def_property_enum_items(prop, rna_enum_brush_image_tool_items);
RNA_def_property_ui_text(prop, "Image Paint Tool", "");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_Brush_imagepaint_tool_update");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_Brush_update_and_reset_icon");
+
+ prop = RNA_def_property(srna, "gpencil_tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "gpencil_tool");
+ RNA_def_property_enum_items(prop, rna_enum_brush_gpencil_types_items);
+ RNA_def_property_ui_text(prop, "Type", "Category of the brush");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ /** End per mode tool properties. */
+
prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
@@ -1357,6 +1819,10 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_TEXTURE_PAINT);
RNA_def_property_ui_text(prop, "Use Texture", "Use this brush in texture paint mode");
+ prop = RNA_def_property(srna, "use_paint_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_GPENCIL_PAINT);
+ RNA_def_property_ui_text(prop, "Use Sculpt", "Use this brush in grease pencil drawing mode");
+
/* texture */
prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BrushTextureSlot");
@@ -1366,7 +1832,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "mtex.tex");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Texture", "");
RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_main_tex_update");
@@ -1378,7 +1844,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "mask_texture", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "mask_mtex.tex");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Mask Texture", "");
RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_secondary_tex_update");
@@ -1459,6 +1925,13 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ImapaintToolCapabilities");
RNA_def_property_pointer_funcs(prop, "rna_Imapaint_tool_capabilities_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Image Painting Capabilities", "Brush's capabilities in image paint mode");
+
+ prop = RNA_def_property(srna, "gpencil_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "BrushGpencilSettings");
+ RNA_def_property_pointer_sdna(prop, NULL, "gpencil_settings");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Gpencil Settings", "");
+
}
/**
@@ -1527,6 +2000,7 @@ void RNA_def_brush(BlenderRNA *brna)
rna_def_brush_capabilities(brna);
rna_def_sculpt_capabilities(brna);
rna_def_image_paint_capabilities(brna);
+ rna_def_gpencil_options(brna);
rna_def_brush_texture_slot(brna);
rna_def_operator_stroke_element(brna);
}
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
index 73928d377f1..dd76e2409db 100644
--- a/source/blender/makesrna/intern/rna_cachefile.c
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -23,6 +23,10 @@
* ***** END GPL LICENSE BLOCK *****
*/
+/** \file blender/makesrna/intern/rna_cachefile.c
+ * \ingroup RNA
+ */
+
#include "DNA_cachefile_types.h"
#include "DNA_scene_types.h"
@@ -37,7 +41,6 @@
#include "BLI_string.h"
#include "BKE_cachefile.h"
-#include "BKE_depsgraph.h"
#include "DEG_depsgraph.h"
@@ -52,7 +55,7 @@ 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);
+ DEG_id_tag_update(&cache_file->id, 0);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
UNUSED_VARS(bmain, scene);
@@ -63,7 +66,7 @@ static void rna_CacheFile_update_handle(Main *bmain, Scene *scene, PointerRNA *p
CacheFile *cache_file = ptr->data;
if ((cache_file->flag & CACHEFILE_DIRTY) != 0) {
- BKE_cachefile_clean(scene, cache_file);
+ BKE_cachefile_clean(bmain, cache_file);
BLI_freelistN(&cache_file->object_paths);
cache_file->flag &= ~CACHEFILE_DIRTY;
}
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 981ae75e7c5..1e68ab65965 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -30,20 +30,22 @@
#include "BLI_math.h"
+#include "RNA_access.h"
#include "RNA_define.h"
#include "rna_internal.h"
+#include "WM_api.h"
#include "WM_types.h"
#ifdef RNA_RUNTIME
#include "BKE_camera.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_sequencer.h"
-#include "WM_api.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
static float rna_Camera_angle_get(PointerRNA *ptr)
{
@@ -87,14 +89,43 @@ static void rna_Camera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointer
{
Camera *camera = (Camera *)ptr->id.data;
- DAG_id_tag_update(&camera->id, 0);
+ DEG_id_tag_update(&camera->id, 0);
}
static void rna_Camera_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Camera *camera = (Camera *)ptr->id.data;
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&camera->id, 0);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&camera->id, 0);
+}
+
+static CameraBGImage *rna_Camera_background_images_new(Camera *cam)
+{
+ CameraBGImage *bgpic = BKE_camera_background_image_new(cam);
+
+ WM_main_add_notifier(NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
+
+ return bgpic;
+}
+
+static void rna_Camera_background_images_remove(Camera *cam, ReportList *reports, PointerRNA *bgpic_ptr)
+{
+ CameraBGImage *bgpic = bgpic_ptr->data;
+ if (BLI_findindex(&cam->bg_images, bgpic) == -1) {
+ BKE_report(reports, RPT_ERROR, "Background image cannot be removed");
+ }
+
+ BKE_camera_background_image_remove(cam, bgpic);
+ RNA_POINTER_INVALIDATE(bgpic_ptr);
+
+ WM_main_add_notifier(NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
+}
+
+static void rna_Camera_background_images_clear(Camera *cam)
+{
+ BKE_camera_background_image_clear(cam);
+
+ WM_main_add_notifier(NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
}
static void rna_Camera_dof_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
@@ -107,6 +138,161 @@ static void rna_Camera_dof_update(Main *UNUSED(bmain), Scene *scene, PointerRNA
#else
+static void rna_def_camera_background_image(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem bgpic_source_items[] = {
+ {CAM_BGIMG_SOURCE_IMAGE, "IMAGE", 0, "Image", ""},
+ {CAM_BGIMG_SOURCE_MOVIE, "MOVIE_CLIP", 0, "Movie Clip", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem bgpic_camera_frame_items[] = {
+ {0, "STRETCH", 0, "Stretch", ""},
+ {CAM_BGIMG_FLAG_CAMERA_ASPECT, "FIT", 0, "Fit", ""},
+ {CAM_BGIMG_FLAG_CAMERA_ASPECT | CAM_BGIMG_FLAG_CAMERA_CROP, "CROP", 0, "Crop", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem bgpic_display_depth_items[] = {
+ {0, "BACK", 0, "Back", ""},
+ {CAM_BGIMG_FLAG_FOREGROUND, "FRONT", 0, "Front", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "CameraBackgroundImage", NULL);
+ RNA_def_struct_sdna(srna, "CameraBGImage");
+ RNA_def_struct_ui_text(srna, "Background Image", "Image and settings for display in the 3D View background");
+
+ prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "source");
+ RNA_def_property_enum_items(prop, bgpic_source_items);
+ RNA_def_property_ui_text(prop, "Background Source", "Data source used for background");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "ima");
+ RNA_def_property_ui_text(prop, "Image", "Image displayed and edited in this space");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "clip");
+ RNA_def_property_ui_text(prop, "MovieClip", "Movie clip displayed and edited in this space");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "iuser");
+ RNA_def_property_ui_text(prop, "Image User",
+ "Parameters defining which layer, pass and frame of the image is displayed");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "clip_user", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "MovieClipUser");
+ RNA_def_property_pointer_sdna(prop, NULL, "cuser");
+ RNA_def_property_ui_text(prop, "Clip User", "Parameters defining which frame of the movie clip is displayed");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "offset");
+ RNA_def_property_ui_text(prop, "Offset", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_ui_text(prop, "Scale", "Scale the background image");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "rotation");
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation for the background image (ortho view only)");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_flip_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_BGIMG_FLAG_FLIP_X);
+ RNA_def_property_ui_text(prop, "Flip Horizontally", "Flip the background image horizontally");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_flip_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_BGIMG_FLAG_FLIP_Y);
+ RNA_def_property_ui_text(prop, "Flip Vertically", "Flip the background image vertically");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "alpha");
+ RNA_def_property_ui_text(prop, "Alpha", "Image opacity to blend the image against the background color");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_BGIMG_FLAG_EXPANDED);
+ RNA_def_property_ui_text(prop, "Show Expanded", "Show the expanded in the user interface");
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
+
+ prop = RNA_def_property(srna, "use_camera_clip", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_BGIMG_FLAG_CAMERACLIP);
+ RNA_def_property_ui_text(prop, "Camera Clip", "Use movie clip from active scene camera");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_background_image", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CAM_BGIMG_FLAG_DISABLED);
+ RNA_def_property_ui_text(prop, "Show Background Image", "Show this image as background");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_on_foreground", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_BGIMG_FLAG_FOREGROUND);
+ RNA_def_property_ui_text(prop, "Show On Foreground", "Show this image in front of objects in viewport");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* expose 1 flag as a enum of 2 items */
+ prop = RNA_def_property(srna, "display_depth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, bgpic_display_depth_items);
+ RNA_def_property_ui_text(prop, "Depth", "Display under or over everything");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* expose 2 flags as a enum of 3 items */
+ prop = RNA_def_property(srna, "frame_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, bgpic_camera_frame_items);
+ RNA_def_property_ui_text(prop, "Frame Method", "How the image fits in the camera frame");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+}
+
+
+static void rna_def_camera_background_images(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "CameraBackgroundImages");
+ srna = RNA_def_struct(brna, "CameraBackgroundImages", NULL);
+ RNA_def_struct_sdna(srna, "Camera");
+ RNA_def_struct_ui_text(srna, "Background Images", "Collection of background images");
+
+ func = RNA_def_function(srna, "new", "rna_Camera_background_images_new");
+ RNA_def_function_ui_description(func, "Add new background image");
+ parm = RNA_def_pointer(func, "image", "CameraBackgroundImage", "", "Image displayed as viewport background");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Camera_background_images_remove");
+ RNA_def_function_ui_description(func, "Remove background image");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "image", "CameraBackgroundImage", "", "Image displayed as viewport background");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "clear", "rna_Camera_background_images_clear");
+ RNA_def_function_ui_description(func, "Remove all background images");
+}
+
static void rna_def_camera_stereo_data(BlenderRNA *brna)
{
StructRNA *srna;
@@ -192,7 +378,7 @@ void RNA_def_camera(BlenderRNA *brna)
{CAM_PANO, "PANO", 0, "Panoramic", ""},
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem prop_draw_type_extra_items[] = {
+ static const EnumPropertyItem prop_display_type_extra_items[] = {
{CAM_DTX_CENTER, "CENTER", 0, "Center", ""},
{CAM_DTX_CENTER_DIAG, "CENTER_DIAGONAL", 0, "Center Diagonal", ""},
{CAM_DTX_THIRDS, "THIRDS", 0, "Thirds", ""},
@@ -227,9 +413,9 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_guide", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dtx");
- RNA_def_property_enum_items(prop, prop_draw_type_extra_items);
+ RNA_def_property_enum_items(prop, prop_display_type_extra_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
- RNA_def_property_ui_text(prop, "Composition Guides", "Draw overlay");
+ RNA_def_property_ui_text(prop, "Composition Guides", "Display overlay");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "sensor_fit", PROP_ENUM, PROP_NONE);
@@ -242,6 +428,7 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "passepartalpha");
+ RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(prop, "Passepartout Alpha", "Opacity (alpha) of the darkened overlay in Camera view");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
@@ -268,6 +455,7 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
+ RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance");
@@ -275,6 +463,7 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipend");
+ RNA_def_property_float_default(prop, 1000.0f);
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance");
@@ -282,6 +471,7 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "lens", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "lens");
+ RNA_def_property_float_default(prop, 50.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 5000.0f, 1, 2);
RNA_def_property_ui_text(prop, "Focal Length", "Perspective Camera lens value in millimeters");
@@ -289,6 +479,7 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "sensor_width", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "sensor_x");
+ RNA_def_property_float_default(prop, 36.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 100.f, 1, 2);
RNA_def_property_ui_text(prop, "Sensor Width", "Horizontal size of the image sensor area in millimeters");
@@ -296,6 +487,7 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "sensor_height", PROP_FLOAT, PROP_DISTANCE_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "sensor_y");
+ RNA_def_property_float_default(prop, 34.0f);
RNA_def_property_range(prop, 1.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 100.f, 1, 2);
RNA_def_property_ui_text(prop, "Sensor Height", "Vertical size of the image sensor area in millimeters");
@@ -303,16 +495,18 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "ortho_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ortho_scale");
+ RNA_def_property_float_default(prop, 6.0f);
RNA_def_property_range(prop, FLT_MIN, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, 10000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Orthographic Scale", "Orthographic Camera scale (similar to zoom)");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update");
- prop = RNA_def_property(srna, "draw_size", PROP_FLOAT, PROP_DISTANCE);
+ prop = RNA_def_property(srna, "display_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "drawsize");
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.01f, 1000.0f);
RNA_def_property_ui_range(prop, 0.01, 100, 1, 2);
- RNA_def_property_ui_text(prop, "Draw Size", "Apparent size of the Camera object in the 3D View");
+ RNA_def_property_ui_text(prop, "Display Size", "Apparent size of the Camera object in the 3D View");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "shift_x", PROP_FLOAT, PROP_NONE);
@@ -346,16 +540,17 @@ void RNA_def_camera(BlenderRNA *brna)
/* flag */
prop = RNA_def_property(srna, "show_limits", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWLIMITS);
- RNA_def_property_ui_text(prop, "Show Limits", "Draw the clipping range and focus point on the camera");
+ RNA_def_property_ui_text(prop, "Show Limits", "Display the clipping range and focus point on the camera");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_mist", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWMIST);
- RNA_def_property_ui_text(prop, "Show Mist", "Draw a line from the Camera to indicate the mist area");
+ RNA_def_property_ui_text(prop, "Show Mist", "Display a line from the Camera to indicate the mist area");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_passepartout", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWPASSEPARTOUT);
+ RNA_def_property_boolean_default(prop, true);
RNA_def_property_ui_text(prop, "Show Passepartout",
"Show a darkened overlay outside the image area in Camera view");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
@@ -381,6 +576,12 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Sensor Size", "Show sensor size (film gate) in Camera view");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
+ prop = RNA_def_property(srna, "show_background_images", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOW_BG_IMAGE);
+ RNA_def_property_ui_text(prop, "Display Background Images",
+ "Display reference images behind objects in the 3D View");
+ RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
+
prop = RNA_def_property(srna, "lens_unit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_lens_unit_items);
@@ -399,8 +600,17 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "GPU Depth Of Field", "");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "background_images", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "bg_images", NULL);
+ RNA_def_property_struct_type(prop, "CameraBackgroundImage");
+ RNA_def_property_ui_text(prop, "Background Images", "List of background images");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
rna_def_animdata_common(srna);
+ rna_def_camera_background_image(brna);
+ rna_def_camera_background_images(brna, prop);
+
/* Nested Data */
RNA_define_animate_sdna(true);
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index ef2241e269b..4d648d8c00b 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -31,6 +31,8 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_math_base.h"
+
#include "RNA_define.h"
#include "rna_internal.h"
@@ -46,19 +48,20 @@
#ifdef RNA_RUNTIME
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
static void rna_cloth_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
static void rna_cloth_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
rna_cloth_update(bmain, scene, ptr);
}
@@ -70,7 +73,7 @@ static void rna_cloth_pinning_changed(Main *UNUSED(bmain), Scene *UNUSED(scene),
cloth_free_modifier(clmd);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
@@ -96,26 +99,70 @@ static void rna_ClothSettings_max_bend_set(struct PointerRNA *ptr, float value)
settings->max_bend = value;
}
-static void rna_ClothSettings_structural_set(struct PointerRNA *ptr, float value)
+static void rna_ClothSettings_tension_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->tension = value;
+
+ /* check for max clipping */
+ if (value > settings->max_tension)
+ settings->max_tension = value;
+}
+
+static void rna_ClothSettings_max_tension_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ /* check for clipping */
+ if (value < settings->tension)
+ value = settings->tension;
+
+ settings->max_tension = value;
+}
+
+static void rna_ClothSettings_compression_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->compression = value;
+
+ /* check for max clipping */
+ if (value > settings->max_compression)
+ settings->max_compression = value;
+}
+
+static void rna_ClothSettings_max_compression_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ /* check for clipping */
+ if (value < settings->compression)
+ value = settings->compression;
+
+ settings->max_compression = value;
+}
+
+static void rna_ClothSettings_shear_set(struct PointerRNA *ptr, float value)
{
ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
- settings->structural = value;
+ settings->shear = value;
/* check for max clipping */
- if (value > settings->max_struct)
- settings->max_struct = value;
+ if (value > settings->max_shear)
+ settings->max_shear = value;
}
-static void rna_ClothSettings_max_struct_set(struct PointerRNA *ptr, float value)
+static void rna_ClothSettings_max_shear_set(struct PointerRNA *ptr, float value)
{
ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
/* check for clipping */
- if (value < settings->structural)
- value = settings->structural;
+ if (value < settings->shear)
+ value = settings->shear;
- settings->max_struct = value;
+ settings->max_shear = value;
}
static void rna_ClothSettings_max_sewing_set(struct PointerRNA *ptr, float value)
@@ -129,6 +176,28 @@ static void rna_ClothSettings_max_sewing_set(struct PointerRNA *ptr, float value
settings->max_sewing = value;
}
+static void rna_ClothSettings_shrink_min_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ settings->shrink_min = value;
+
+ /* check for max clipping */
+ if (value > settings->shrink_max)
+ settings->shrink_max = value;
+}
+
+static void rna_ClothSettings_shrink_max_set(struct PointerRNA *ptr, float value)
+{
+ ClothSimSettings *settings = (ClothSimSettings *)ptr->data;
+
+ /* check for clipping */
+ if (value < settings->shrink_min)
+ value = settings->shrink_min;
+
+ settings->shrink_max = value;
+}
+
static void rna_ClothSettings_mass_vgroup_get(PointerRNA *ptr, char *value)
{
ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
@@ -183,6 +252,24 @@ static void rna_ClothSettings_struct_vgroup_set(PointerRNA *ptr, const char *val
rna_object_vgroup_name_index_set(ptr, value, &sim->vgroup_struct);
}
+static void rna_ClothSettings_shear_vgroup_get(PointerRNA *ptr, char *value)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ rna_object_vgroup_name_index_get(ptr, value, sim->vgroup_shear);
+}
+
+static int rna_ClothSettings_shear_vgroup_length(PointerRNA *ptr)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ return rna_object_vgroup_name_index_length(ptr, sim->vgroup_shear);
+}
+
+static void rna_ClothSettings_shear_vgroup_set(PointerRNA *ptr, const char *value)
+{
+ ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
+ rna_object_vgroup_name_index_set(ptr, value, &sim->vgroup_shear);
+}
+
static void rna_ClothSettings_bend_vgroup_get(PointerRNA *ptr, char *value)
{
ClothSimSettings *sim = (ClothSimSettings *)ptr->data;
@@ -349,6 +436,12 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static const EnumPropertyItem prop_bending_model_items[] = {
+ {CLOTH_BENDING_ANGULAR, "ANGULAR", 0, "Angular", "Cloth model with angular bending springs"},
+ {CLOTH_BENDING_LINEAR, "LINEAR", 0, "Linear", "Cloth model with linear bending springs (legacy)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "ClothSettings", NULL);
RNA_def_struct_ui_text(srna, "Cloth Settings", "Cloth simulation settings for an object");
RNA_def_struct_sdna(srna, "ClothSimSettings");
@@ -441,20 +534,6 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Air Damping", "Air has normally some thickness which slows falling things down");
RNA_def_property_update(prop, 0, "rna_cloth_update");
- prop = RNA_def_property(srna, "vel_damping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "vel_damping");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Velocity Damping",
- "Damp velocity to help cloth reach the resting position faster "
- "(1.0 = no damping, 0.0 = fully dampened)");
- RNA_def_property_update(prop, 0, "rna_cloth_update");
-
- prop = RNA_def_property(srna, "use_pin_cloth", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_GOAL);
- RNA_def_property_ui_text(prop, "Pin Cloth", "Enable pinning of cloth vertices to other objects/positions");
- RNA_def_property_update(prop, 0, "rna_cloth_pinning_changed");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
prop = RNA_def_property(srna, "pin_stiffness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "goalspring");
RNA_def_property_range(prop, 0.0f, 50.0);
@@ -485,12 +564,14 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "shrink_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "shrink_min");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Shrink Factor Min", "Min amount to shrink cloth by");
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_shrink_min_set", NULL);
+ RNA_def_property_ui_text(prop, "Shrink Factor", "Factor by which to shrink cloth");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "shrink_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "shrink_max");
RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_shrink_max_set", NULL);
RNA_def_property_ui_text(prop, "Shrink Factor Max", "Max amount to shrink cloth by");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -502,33 +583,64 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_cloth_update");
/* springs */
+ prop = RNA_def_property(srna, "tension_damping", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "tension_damp");
+ RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_ui_text(prop, "Tension Spring Damping", "Amount of damping in stretching behavior");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
- prop = RNA_def_property(srna, "use_stiffness_scale", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_SCALING);
- RNA_def_property_ui_text(prop, "Stiffness Scaling",
- "If enabled, stiffness can be scaled along a weight painted vertex group");
+ prop = RNA_def_property(srna, "compression_damping", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "compression_damp");
+ RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_ui_text(prop, "Compression Spring Damping", "Amount of damping in compression behavior");
RNA_def_property_update(prop, 0, "rna_cloth_update");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- prop = RNA_def_property(srna, "spring_damping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "Cdis");
+ prop = RNA_def_property(srna, "shear_damping", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "shear_damp");
RNA_def_property_range(prop, 0.0f, 50.0f);
- RNA_def_property_ui_text(prop, "Spring Damping",
- "Damping of cloth velocity (higher = more smooth, less jiggling)");
+ RNA_def_property_ui_text(prop, "Shear Spring Damping", "Amount of damping in shearing behavior");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "tension_stiffness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "tension");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_tension_set", NULL);
+ RNA_def_property_ui_text(prop, "Tension Stiffness", "How much the material resists stretching");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "tension_stiffness_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_tension");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_max_tension_set", NULL);
+ RNA_def_property_ui_text(prop, "Tension Stiffness Maximum", "Maximum tension stiffness value");
RNA_def_property_update(prop, 0, "rna_cloth_update");
- prop = RNA_def_property(srna, "structural_stiffness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "structural");
+ prop = RNA_def_property(srna, "compression_stiffness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "compression");
RNA_def_property_range(prop, 0.0f, 10000.0f);
- RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_structural_set", NULL);
- RNA_def_property_ui_text(prop, "Structural Stiffness", "Overall stiffness of structure");
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_compression_set", NULL);
+ RNA_def_property_ui_text(prop, "Compression Stiffness", "How much the material resists compression");
RNA_def_property_update(prop, 0, "rna_cloth_update");
- prop = RNA_def_property(srna, "structural_stiffness_max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "max_struct");
+ prop = RNA_def_property(srna, "compression_stiffness_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_compression");
RNA_def_property_range(prop, 0.0f, 10000.0f);
- RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_max_struct_set", NULL);
- RNA_def_property_ui_text(prop, "Structural Stiffness Maximum", "Maximum structural stiffness value");
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_max_compression_set", NULL);
+ RNA_def_property_ui_text(prop, "Compression Stiffness Maximum", "Maximum compression stiffness value");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "shear_stiffness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "shear");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_shear_set", NULL);
+ RNA_def_property_ui_text(prop, "Shear Stiffness", "How much the material resists shearing");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "shear_stiffness_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_shear");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_max_shear_set", NULL);
+ RNA_def_property_ui_text(prop, "Shear Stiffness Maximum", "Maximum shear scaling value");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "sewing_force_max", PROP_FLOAT, PROP_NONE);
@@ -546,12 +658,19 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"Vertex group for fine control over structural stiffness");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "vertex_group_shear_stiffness", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_ClothSettings_shear_vgroup_get",
+ "rna_ClothSettings_shear_vgroup_length",
+ "rna_ClothSettings_shear_vgroup_set");
+ RNA_def_property_ui_text(prop, "Shear Stiffness Vertex Group",
+ "Vertex group for fine control over shear stiffness");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
prop = RNA_def_property(srna, "bending_stiffness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bending");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_float_funcs(prop, NULL, "rna_ClothSettings_bending_set", NULL);
- RNA_def_property_ui_text(prop, "Bending Stiffness",
- "Wrinkle coefficient (higher = less smaller but more big wrinkles)");
+ RNA_def_property_ui_text(prop, "Bending Stiffness", "How much the material resists bending");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "bending_stiffness_max", PROP_FLOAT, PROP_NONE);
@@ -564,8 +683,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "bending_damping", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bending_damping");
RNA_def_property_range(prop, 0.0f, 1000.0f);
- RNA_def_property_ui_text(prop, "Bending Spring Damping",
- "Damping of bending motion");
+ RNA_def_property_ui_text(prop, "Bending Spring Damping", "Amount of damping in bending behavior");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "use_sewing_springs", PROP_BOOLEAN, PROP_NONE);
@@ -600,24 +718,17 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_cloth_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ prop = RNA_def_property(srna, "bending_model", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "bending_model");
+ RNA_def_property_enum_items(prop, prop_bending_model_items);
+ RNA_def_property_ui_text(prop, "Bending Model", "Physical model for simulating bending forces");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
/* unused */
/* unused still */
#if 0
- prop = RNA_def_property(srna, "shear_stiffness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "shear");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
- RNA_def_property_ui_text(prop, "Shear Stiffness", "Shear spring stiffness");
-#endif
- /* unused still */
-#if 0
- prop = RNA_def_property(srna, "shear_stiffness_max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "max_shear");
- RNA_def_property_range(prop, 0.0f, upperLimitf);
- RNA_def_property_ui_text(prop, "Shear Stiffness Maximum", "Maximum shear scaling value");
-#endif
- /* unused still */
-#if 0
prop = RNA_def_property(srna, "effector_force_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "eff_force_scale");
RNA_def_property_range(prop, 0.0f, 100.0f);
@@ -663,26 +774,11 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Enable Collision", "Enable collisions with other objects");
RNA_def_property_update(prop, 0, "rna_cloth_update");
- prop = RNA_def_property(srna, "repel_force", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "repel_force");
- RNA_def_property_range(prop, 0.0f, 20.0f);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Repulsion Force", "Repulsion force to apply on cloth when close to colliding");
- RNA_def_property_update(prop, 0, "rna_cloth_update");
-
- prop = RNA_def_property(srna, "distance_repel", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "distance_repel");
- RNA_def_property_range(prop, 0.001f, 10.0f);
- RNA_def_property_float_default(prop, 0.005f);
- RNA_def_property_ui_text(prop, "Repulsion Distance",
- "Maximum distance to apply repulsion force, must be greater than minimum distance");
- RNA_def_property_update(prop, 0, "rna_cloth_update");
-
prop = RNA_def_property(srna, "distance_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "epsilon");
RNA_def_property_range(prop, 0.001f, 1.0f);
RNA_def_property_ui_text(prop, "Minimum Distance",
- "Minimum distance between collision objects before collision response takes in");
+ "Minimum distance between collision objects before collision response takes effect");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "friction", PROP_FLOAT, PROP_NONE);
@@ -705,6 +801,12 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"How many collision iterations should be done. (higher is better quality but slower)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "impulse_clamp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "clamp");
+ RNA_def_property_range(prop, 0.0f, 100.0f);
+ RNA_def_property_ui_text(prop, "Impulse Clamping", "Clamp collision impulses to avoid instability (0.0 to disable clamping)");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
/* self collision */
prop = RNA_def_property(srna, "use_self_collision", PROP_BOOLEAN, PROP_NONE);
@@ -714,27 +816,19 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "self_distance_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "selfepsilon");
- RNA_def_property_range(prop, 0.5f, 1.0f);
- RNA_def_property_ui_text(prop, "Self Minimum Distance", "0.5 means no distance at all, 1.0 is maximum distance");
+ RNA_def_property_range(prop, 0.001f, 0.1f);
+ RNA_def_property_ui_text(prop, "Self Minimum Distance", "Minimum distance between cloth faces before collision response takes effect");
RNA_def_property_update(prop, 0, "rna_cloth_update");
prop = RNA_def_property(srna, "self_friction", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 80.0f);
- RNA_def_property_ui_text(prop, "Self Friction", "Friction/damping with self contact");
- RNA_def_property_update(prop, 0, "rna_cloth_update");
-
- 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, 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)");
+ RNA_def_property_ui_text(prop, "Self Friction", "Friction with self contact");
RNA_def_property_update(prop, 0, "rna_cloth_update");
- prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
+ RNA_def_property_ui_text(prop, "Collision Collection", "Limit colliders to this Collection");
RNA_def_property_update(prop, 0, "rna_cloth_dependency_update");
prop = RNA_def_property(srna, "vertex_group_self_collisions", PROP_STRING, PROP_NONE);
@@ -743,6 +837,12 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selfcollision Vertex Group",
"Vertex group to define vertices which are not used during self collisions");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "self_impulse_clamp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "self_clamp");
+ RNA_def_property_range(prop, 0.0f, 100.0f);
+ RNA_def_property_ui_text(prop, "Impulse Clamping", "Clamp collision impulses to avoid instability (0.0 to disable clamping)");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
}
void RNA_def_cloth(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c
new file mode 100644
index 00000000000..5230157cfad
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_collection.c
@@ -0,0 +1,381 @@
+/*
+ * ***** 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/makesrna/intern/rna_collection.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "DNA_collection_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "RNA_define.h"
+
+#include "rna_internal.h"
+
+#include "WM_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "BKE_collection.h"
+#include "BKE_global.h"
+#include "BKE_layer.h"
+
+#include "WM_api.h"
+
+#include "RNA_access.h"
+
+static void rna_Collection_all_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Collection *collection = (Collection *)ptr->data;
+ ListBase collection_objects = BKE_collection_object_cache_get(collection);
+ rna_iterator_listbase_begin(iter, &collection_objects, NULL);
+}
+
+static PointerRNA rna_Collection_all_objects_get(CollectionPropertyIterator *iter)
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+
+ /* we are actually iterating a ObjectBase list, so override get */
+ Base *base = (Base *)internal->link;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, base->object);
+}
+
+static void rna_Collection_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Collection *collection = (Collection *)ptr->data;
+ rna_iterator_listbase_begin(iter, &collection->gobject, NULL);
+}
+
+static PointerRNA rna_Collection_objects_get(CollectionPropertyIterator *iter)
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+
+ /* we are actually iterating a ObjectBase list, so override get */
+ CollectionObject *cob = (CollectionObject *)internal->link;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, cob->ob);
+}
+
+static void rna_Collection_objects_link(Collection *collection, Main *bmain, ReportList *reports, Object *object)
+{
+ if (!BKE_collection_object_add(bmain, collection, object)) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' already in collection '%s'", object->id.name + 2, collection->id.name + 2);
+ return;
+ }
+
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, &object->id);
+}
+
+static void rna_Collection_objects_unlink(Collection *collection, Main *bmain, ReportList *reports, Object *object)
+{
+ if (!BKE_collection_object_remove(bmain, collection, object, false)) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in collection '%s'", object->id.name + 2, collection->id.name + 2);
+ return;
+ }
+
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, &object->id);
+}
+
+static bool rna_Collection_objects_override_apply(
+ Main *bmain,
+ PointerRNA *ptr_dst, PointerRNA *UNUSED(ptr_src), PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *UNUSED(prop_dst), PropertyRNA *UNUSED(prop_src), PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst), const int UNUSED(len_src), const int UNUSED(len_storage),
+ PointerRNA *ptr_item_dst, PointerRNA *ptr_item_src, PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideStaticPropertyOperation *opop)
+{
+ (void)opop;
+ BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_REPLACE &&
+ "Unsupported RNA override operation on collections' objects");
+
+ Collection *coll_dst = ptr_dst->id.data;
+
+ if (ptr_item_dst->type == NULL || ptr_item_src->type == NULL) {
+ BLI_assert(0 && "invalid source or destination object.");
+ return false;
+ }
+
+ Object *ob_dst = ptr_item_dst->data;
+ Object *ob_src = ptr_item_src->data;
+
+ CollectionObject *cob_dst = BLI_findptr(&coll_dst->gobject, ob_dst, offsetof(CollectionObject, ob));
+
+ if (cob_dst == NULL) {
+ BLI_assert(0 && "Could not find destination object in destination collection!");
+ return false;
+ }
+
+ /* XXX TODO We most certainly rather want to have a 'swap object pointer in collection' util in BKE_collection...
+ * This is only temp auick dirty test! */
+ id_us_min(&cob_dst->ob->id);
+ cob_dst->ob = ob_src;
+ id_us_plus(&cob_dst->ob->id);
+
+ if (BKE_collection_is_in_scene(coll_dst)) {
+ BKE_main_collection_sync(bmain);
+ }
+
+ return true;
+}
+
+
+
+
+static void rna_Collection_children_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Collection *collection = (Collection *)ptr->data;
+ rna_iterator_listbase_begin(iter, &collection->children, NULL);
+}
+
+static PointerRNA rna_Collection_children_get(CollectionPropertyIterator *iter)
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+
+ /* we are actually iterating a CollectionChild list, so override get */
+ CollectionChild *child = (CollectionChild *)internal->link;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Collection, child->collection);
+}
+
+static void rna_Collection_children_link(Collection *collection, Main *bmain, ReportList *reports, Collection *child)
+{
+ if (!BKE_collection_child_add(bmain, collection, child)) {
+ BKE_reportf(reports, RPT_ERROR, "Collection '%s' already in collection '%s'", child->id.name + 2, collection->id.name + 2);
+ return;
+ }
+
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, &child->id);
+}
+
+static void rna_Collection_children_unlink(Collection *collection, Main *bmain, ReportList *reports, Collection *child)
+{
+ if (!BKE_collection_child_remove(bmain, collection, child)) {
+ BKE_reportf(reports, RPT_ERROR, "Collection '%s' not in collection '%s'", child->id.name + 2, collection->id.name + 2);
+ return;
+ }
+
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, &child->id);
+}
+
+static bool rna_Collection_children_override_apply(
+ Main *bmain,
+ PointerRNA *ptr_dst, PointerRNA *UNUSED(ptr_src), PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *UNUSED(prop_dst), PropertyRNA *UNUSED(prop_src), PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst), const int UNUSED(len_src), const int UNUSED(len_storage),
+ PointerRNA *ptr_item_dst, PointerRNA *ptr_item_src, PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideStaticPropertyOperation *opop)
+{
+ (void)opop;
+ BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_REPLACE &&
+ "Unsupported RNA override operation on collections' objects");
+
+ Collection *coll_dst = ptr_dst->id.data;
+
+ if (ptr_item_dst->type == NULL || ptr_item_src->type == NULL) {
+ BLI_assert(0 && "invalid source or destination sub-collection.");
+ return false;
+ }
+
+ Collection *subcoll_dst = ptr_item_dst->data;
+ Collection *subcoll_src = ptr_item_src->data;
+
+ CollectionChild *collchild_dst = BLI_findptr(&coll_dst->children, subcoll_dst, offsetof(CollectionChild, collection));
+
+ if (collchild_dst == NULL) {
+ BLI_assert(0 && "Could not find destination sub-collection in destination collection!");
+ return false;
+ }
+
+ /* XXX TODO We most certainly rather want to have a 'swap object pointer in collection' util in BKE_collection...
+ * This is only temp auick dirty test! */
+ id_us_min(&collchild_dst->collection->id);
+ collchild_dst->collection = subcoll_src;
+ id_us_plus(&collchild_dst->collection->id);
+
+ BKE_collection_object_cache_free(coll_dst);
+ BKE_main_collection_sync(bmain);
+
+ return true;
+}
+
+
+
+
+static void rna_Collection_flag_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Collection *collection = (Collection *)ptr->data;
+ BKE_collection_object_cache_free(collection);
+ BKE_main_collection_sync(bmain);
+
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
+}
+
+#else
+
+/* collection.objects */
+static void rna_def_collection_objects(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "CollectionObjects");
+ srna = RNA_def_struct(brna, "CollectionObjects", NULL);
+ RNA_def_struct_sdna(srna, "Collection");
+ RNA_def_struct_ui_text(srna, "Collection Objects", "Collection of collection objects");
+
+ /* add object */
+ func = RNA_def_function(srna, "link", "rna_Collection_objects_link");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Add this object to a collection");
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object to add");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* remove object */
+ func = RNA_def_function(srna, "unlink", "rna_Collection_objects_unlink");
+ RNA_def_function_ui_description(func, "Remove this object from a collection");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+}
+
+/* collection.children */
+static void rna_def_collection_children(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "CollectionChildren");
+ srna = RNA_def_struct(brna, "CollectionChildren", NULL);
+ RNA_def_struct_sdna(srna, "Collection");
+ RNA_def_struct_ui_text(srna, "Collection Children", "Collection of child collections");
+
+ /* add child */
+ func = RNA_def_function(srna, "link", "rna_Collection_children_link");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Add this collection as child of this collection");
+ parm = RNA_def_pointer(func, "child", "Collection", "", "Collection to add");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* remove child */
+ func = RNA_def_function(srna, "unlink", "rna_Collection_children_unlink");
+ RNA_def_function_ui_description(func, "Remove this child collection from a collection");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "child", "Collection", "", "Collection to remove");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+}
+
+
+void RNA_def_collections(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Collection", "ID");
+ /* XXX: CAN WE RENAME TO Collection? */
+ RNA_def_struct_sdna(srna, "Group"); /* it is actually Collection but for 2.8 the dna is patched! */
+ RNA_def_struct_ui_text(srna, "Collection", "Collection of Object data-blocks");
+ RNA_def_struct_ui_icon(srna, ICON_GROUP);
+ /* this is done on save/load in readfile.c, removed if no objects are in the collection and not in a scene */
+ RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
+
+ prop = RNA_def_property(srna, "instance_offset", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "dupli_ofs");
+ RNA_def_property_ui_text(prop, "Instance Offset", "Offset from the origin to use when instancing");
+ RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Collection_objects_override_apply");
+ RNA_def_property_ui_text(prop, "Objects", "Objects that are directly in this collection");
+ RNA_def_property_collection_funcs(prop, "rna_Collection_objects_begin",
+ "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end",
+ "rna_Collection_objects_get",
+ NULL, NULL, NULL, NULL);
+ rna_def_collection_objects(brna, prop);
+
+ prop = RNA_def_property(srna, "all_objects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "All Objects", "Objects that are in this collection and its child collections");
+ RNA_def_property_collection_funcs(prop, "rna_Collection_all_objects_begin",
+ "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end",
+ "rna_Collection_all_objects_get",
+ NULL, NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Collection_children_override_apply");
+ RNA_def_property_ui_text(prop, "Children", "Collections that are immediate children of this collection");
+ RNA_def_property_collection_funcs(prop, "rna_Collection_children_begin",
+ "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end",
+ "rna_Collection_children_get",
+ NULL, NULL, NULL, NULL);
+ rna_def_collection_children(brna, prop);
+
+ /* Flags */
+ prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_SELECT);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, -1);
+ RNA_def_property_ui_text(prop, "Disable Select", "Disable collection for viewport selection");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
+
+ prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_VIEW);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1);
+ RNA_def_property_ui_text(prop, "Disable Viewport", "Disable collection in viewport");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
+
+ prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_RENDER);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1);
+ RNA_def_property_ui_text(prop, "Disable Render", "Disable collection in renders");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 2dac5439c80..fded3d32cc1 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -54,13 +54,14 @@
#include "BKE_colorband.h"
#include "BKE_colortools.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_sequencer.h"
#include "BKE_linestyle.h"
+#include "DEG_depsgraph.h"
+
#include "ED_node.h"
#include "IMB_colormanagement.h"
@@ -113,6 +114,12 @@ static void rna_CurveMapping_white_level_set(PointerRNA *ptr, const float *value
curvemapping_set_black_white(cumap, NULL, NULL);
}
+static void rna_CurveMapping_tone_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
+}
+
static void rna_CurveMapping_clipminx_range(PointerRNA *ptr, float *min, float *max,
float *UNUSED(softmin), float *UNUSED(softmax))
{
@@ -159,17 +166,6 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
ID *id = ptr->id.data;
switch (GS(id->name)) {
- case ID_MA: /* material has 2 cases - diffuse and specular */
- {
- Material *ma = (Material *)id;
-
- if (ptr->data == ma->ramp_col)
- path = BLI_strdup("diffuse_ramp");
- else if (ptr->data == ma->ramp_spec)
- path = BLI_strdup("specular_ramp");
- break;
- }
-
case ID_NT:
{
bNodeTree *ntree = (bNodeTree *)id;
@@ -244,22 +240,6 @@ static char *rna_ColorRampElement_path(PointerRNA *ptr)
ID *id = ptr->id.data;
switch (GS(id->name)) {
- case ID_MA: /* 2 cases for material - diffuse and spec */
- {
- Material *ma = (Material *)id;
-
- /* try diffuse first */
- if (ma->ramp_col) {
- RNA_pointer_create(id, &RNA_ColorRamp, ma->ramp_col, &ramp_ptr);
- COLRAMP_GETPATH;
- }
- /* try specular if not diffuse */
- if (!path && ma->ramp_spec) {
- RNA_pointer_create(id, &RNA_ColorRamp, ma->ramp_spec, &ramp_ptr);
- COLRAMP_GETPATH;
- }
- break;
- }
case ID_NT:
{
bNodeTree *ntree = (bNodeTree *)id;
@@ -315,7 +295,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
{
Material *ma = ptr->id.data;
- DAG_id_tag_update(&ma->id, 0);
+ DEG_id_tag_update(&ma->id, 0);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ma);
break;
}
@@ -335,7 +315,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
{
Tex *tex = ptr->id.data;
- DAG_id_tag_update(&tex->id, 0);
+ DEG_id_tag_update(&tex->id, 0);
WM_main_add_notifier(NC_TEXTURE, tex);
break;
}
@@ -350,7 +330,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
{
ParticleSettings *part = ptr->id.data;
- DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
+ DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, part);
}
default:
@@ -446,7 +426,7 @@ static void rna_ColorManagedDisplaySettings_display_device_update(Main *UNUSED(b
IMB_colormanagement_validate_settings(&scene->display_settings, &scene->view_settings);
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
}
@@ -581,7 +561,7 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain, Scene
if (GS(id->name) == ID_IM) {
Image *ima = (Image *) id;
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
@@ -664,7 +644,7 @@ static void rna_ColorManagement_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
return;
if (GS(id->name) == ID_SCE) {
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
}
@@ -783,11 +763,24 @@ static void rna_def_curvemapping(BlenderRNA *brna)
PropertyRNA *prop;
FunctionRNA *func;
+ static const EnumPropertyItem tone_items[] = {
+ {CURVE_TONE_STANDARD, "STANDARD", 0, "Standard", ""},
+ {CURVE_TONE_FILMLIKE, "FILMLIKE", 0, "Film like", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "CurveMapping", NULL);
RNA_def_struct_ui_text(srna, "CurveMapping",
"Curve mapping to map color, vector and scalar values to other values using "
"a user defined curve");
+ prop = RNA_def_property(srna, "tone", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "tone");
+ RNA_def_property_enum_items(prop, tone_items);
+ RNA_def_property_ui_text(prop, "Tone", "Tone of the curve");
+ RNA_def_property_update(prop, 0, "rna_CurveMapping_tone_update");
+
+
prop = RNA_def_property(srna, "use_clip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CUMA_DO_CLIP);
RNA_def_property_ui_text(prop, "Clip", "Force the curve view to fit a defined boundary");
@@ -1012,7 +1005,7 @@ static void rna_def_histogram(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_line", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", HISTO_FLAG_LINE);
RNA_def_property_ui_text(prop, "Show Line", "Display lines rather than filled shapes");
- RNA_def_property_ui_icon(prop, ICON_IPO, 0);
+ RNA_def_property_ui_icon(prop, ICON_GRAPH, 0);
}
static void rna_def_scopes(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 4b563bf6659..4116dd5753f 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -27,6 +27,9 @@
#include <stdlib.h>
#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "MEM_guardedalloc.h"
#include "BLT_translation.h"
@@ -48,64 +51,66 @@
/* please keep the names in sync with constraint.c */
const EnumPropertyItem rna_enum_constraint_type_items[] = {
{0, "", 0, N_("Motion Tracking"), ""},
- {CONSTRAINT_TYPE_CAMERASOLVER, "CAMERA_SOLVER", ICON_CONSTRAINT_DATA, "Camera Solver", ""},
- {CONSTRAINT_TYPE_FOLLOWTRACK, "FOLLOW_TRACK", ICON_CONSTRAINT_DATA, "Follow Track", ""},
- {CONSTRAINT_TYPE_OBJECTSOLVER, "OBJECT_SOLVER", ICON_CONSTRAINT_DATA, "Object Solver", ""},
+ {CONSTRAINT_TYPE_CAMERASOLVER, "CAMERA_SOLVER", ICON_CONSTRAINT, "Camera Solver", ""},
+ {CONSTRAINT_TYPE_FOLLOWTRACK, "FOLLOW_TRACK", ICON_CONSTRAINT, "Follow Track", ""},
+ {CONSTRAINT_TYPE_OBJECTSOLVER, "OBJECT_SOLVER", ICON_CONSTRAINT, "Object Solver", ""},
{0, "", 0, N_("Transform"), ""},
- {CONSTRAINT_TYPE_LOCLIKE, "COPY_LOCATION", ICON_CONSTRAINT_DATA, "Copy Location",
+ {CONSTRAINT_TYPE_LOCLIKE, "COPY_LOCATION", ICON_CONSTRAINT, "Copy Location",
"Copy the location of a target (with an optional offset), so that they move together"},
- {CONSTRAINT_TYPE_ROTLIKE, "COPY_ROTATION", ICON_CONSTRAINT_DATA, "Copy Rotation",
+ {CONSTRAINT_TYPE_ROTLIKE, "COPY_ROTATION", ICON_CONSTRAINT, "Copy Rotation",
"Copy the rotation of a target (with an optional offset), so that they rotate together"},
- {CONSTRAINT_TYPE_SIZELIKE, "COPY_SCALE", ICON_CONSTRAINT_DATA, "Copy Scale",
+ {CONSTRAINT_TYPE_SIZELIKE, "COPY_SCALE", ICON_CONSTRAINT, "Copy Scale",
"Copy the scale factors of a target (with an optional offset), so that they are scaled by the same amount"},
- {CONSTRAINT_TYPE_TRANSLIKE, "COPY_TRANSFORMS", ICON_CONSTRAINT_DATA, "Copy Transforms",
+ {CONSTRAINT_TYPE_TRANSLIKE, "COPY_TRANSFORMS", ICON_CONSTRAINT, "Copy Transforms",
"Copy all the transformations of a target, so that they move together"},
- {CONSTRAINT_TYPE_DISTLIMIT, "LIMIT_DISTANCE", ICON_CONSTRAINT_DATA, "Limit Distance",
+ {CONSTRAINT_TYPE_DISTLIMIT, "LIMIT_DISTANCE", ICON_CONSTRAINT, "Limit Distance",
"Restrict movements to within a certain distance of a target (at the time of constraint evaluation only)"},
- {CONSTRAINT_TYPE_LOCLIMIT, "LIMIT_LOCATION", ICON_CONSTRAINT_DATA, "Limit Location",
+ {CONSTRAINT_TYPE_LOCLIMIT, "LIMIT_LOCATION", ICON_CONSTRAINT, "Limit Location",
"Restrict movement along each axis within given ranges"},
- {CONSTRAINT_TYPE_ROTLIMIT, "LIMIT_ROTATION", ICON_CONSTRAINT_DATA, "Limit Rotation",
+ {CONSTRAINT_TYPE_ROTLIMIT, "LIMIT_ROTATION", ICON_CONSTRAINT, "Limit Rotation",
"Restrict rotation along each axis within given ranges"},
- {CONSTRAINT_TYPE_SIZELIMIT, "LIMIT_SCALE", ICON_CONSTRAINT_DATA, "Limit Scale",
+ {CONSTRAINT_TYPE_SIZELIMIT, "LIMIT_SCALE", ICON_CONSTRAINT, "Limit Scale",
"Restrict scaling along each axis with given ranges"},
- {CONSTRAINT_TYPE_SAMEVOL, "MAINTAIN_VOLUME", ICON_CONSTRAINT_DATA, "Maintain Volume",
+ {CONSTRAINT_TYPE_SAMEVOL, "MAINTAIN_VOLUME", ICON_CONSTRAINT, "Maintain Volume",
"Compensate for scaling one axis by applying suitable scaling to the other two axes"},
- {CONSTRAINT_TYPE_TRANSFORM, "TRANSFORM", ICON_CONSTRAINT_DATA, "Transformation",
+ {CONSTRAINT_TYPE_TRANSFORM, "TRANSFORM", ICON_CONSTRAINT, "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",
+ {CONSTRAINT_TYPE_TRANSFORM_CACHE, "TRANSFORM_CACHE", ICON_CONSTRAINT, "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",
+ {CONSTRAINT_TYPE_CLAMPTO, "CLAMP_TO", ICON_CONSTRAINT, "Clamp To",
"Restrict movements to lie along a curve by remapping location along curve's longest axis"},
- {CONSTRAINT_TYPE_DAMPTRACK, "DAMPED_TRACK", ICON_CONSTRAINT_DATA, "Damped Track",
+ {CONSTRAINT_TYPE_DAMPTRACK, "DAMPED_TRACK", ICON_CONSTRAINT, "Damped Track",
"Point towards a target by performing the smallest rotation necessary"},
- {CONSTRAINT_TYPE_KINEMATIC, "IK", ICON_CONSTRAINT_DATA, "Inverse Kinematics",
+ {CONSTRAINT_TYPE_KINEMATIC, "IK", ICON_CONSTRAINT, "Inverse Kinematics",
"Control a chain of bones by specifying the endpoint target (Bones only)"},
- {CONSTRAINT_TYPE_LOCKTRACK, "LOCKED_TRACK", ICON_CONSTRAINT_DATA, "Locked Track",
+ {CONSTRAINT_TYPE_LOCKTRACK, "LOCKED_TRACK", ICON_CONSTRAINT, "Locked Track",
"Rotate around the specified ('locked') axis to point towards a target"},
- {CONSTRAINT_TYPE_SPLINEIK, "SPLINE_IK", ICON_CONSTRAINT_DATA, "Spline IK",
+ {CONSTRAINT_TYPE_SPLINEIK, "SPLINE_IK", ICON_CONSTRAINT, "Spline IK",
"Align chain of bones along a curve (Bones only)"},
- {CONSTRAINT_TYPE_STRETCHTO, "STRETCH_TO", ICON_CONSTRAINT_DATA, "Stretch To",
+ {CONSTRAINT_TYPE_STRETCHTO, "STRETCH_TO", ICON_CONSTRAINT, "Stretch To",
"Stretch along Y-Axis to point towards a target"},
- {CONSTRAINT_TYPE_TRACKTO, "TRACK_TO", ICON_CONSTRAINT_DATA, "Track To",
+ {CONSTRAINT_TYPE_TRACKTO, "TRACK_TO", ICON_CONSTRAINT, "Track To",
"Legacy tracking constraint prone to twisting artifacts"},
{0, "", 0, N_("Relationship"), ""},
- {CONSTRAINT_TYPE_ACTION, "ACTION", ICON_CONSTRAINT_DATA, "Action",
+ {CONSTRAINT_TYPE_ACTION, "ACTION", ICON_CONSTRAINT, "Action",
"Use transform property of target to look up pose for owner from an Action"},
- {CONSTRAINT_TYPE_CHILDOF, "CHILD_OF", ICON_CONSTRAINT_DATA, "Child Of",
+ {CONSTRAINT_TYPE_CHILDOF, "CHILD_OF", ICON_CONSTRAINT, "Child Of",
"Make target the 'detachable' parent of owner"},
- {CONSTRAINT_TYPE_MINMAX, "FLOOR", ICON_CONSTRAINT_DATA, "Floor",
+ {CONSTRAINT_TYPE_MINMAX, "FLOOR", ICON_CONSTRAINT, "Floor",
"Use position (and optionally rotation) of target to define a 'wall' or 'floor' that the owner can not cross"},
- {CONSTRAINT_TYPE_FOLLOWPATH, "FOLLOW_PATH", ICON_CONSTRAINT_DATA, "Follow Path",
+ {CONSTRAINT_TYPE_FOLLOWPATH, "FOLLOW_PATH", ICON_CONSTRAINT, "Follow Path",
"Use to animate an object/bone following a path"},
- {CONSTRAINT_TYPE_PIVOT, "PIVOT", ICON_CONSTRAINT_DATA, "Pivot",
+ {CONSTRAINT_TYPE_PIVOT, "PIVOT", ICON_CONSTRAINT, "Pivot",
"Change pivot point for transforms (buggy)"},
- {CONSTRAINT_TYPE_RIGIDBODYJOINT, "RIGID_BODY_JOINT", ICON_CONSTRAINT_DATA, "Rigid Body Joint",
- "Use to define a Rigid Body Constraint (for Game Engine use only)"},
+ /* {CONSTRAINT_TYPE_RIGIDBODYJOINT, "RIGID_BODY_JOINT", ICON_CONSTRAINT_DATA, "Rigid Body Joint",
+ "Use to define a Rigid Body Constraint (for Game Engine use only)"}, */
/* {CONSTRAINT_TYPE_PYTHON, "SCRIPT", ICON_CONSTRAINT_DATA, "Script",
"Custom constraint(s) written in Python (Not yet implemented)"}, */
- {CONSTRAINT_TYPE_SHRINKWRAP, "SHRINKWRAP", ICON_CONSTRAINT_DATA, "Shrinkwrap",
+ {CONSTRAINT_TYPE_SHRINKWRAP, "SHRINKWRAP", ICON_CONSTRAINT, "Shrinkwrap",
"Restrict movements to surface of target mesh"},
+ {CONSTRAINT_TYPE_ARMATURE, "ARMATURE", ICON_CONSTRAINT, "Armature",
+ "Apply weight-blended transformation from multiple bones like the Armature modifier"},
{0, NULL, 0, NULL, NULL}
};
@@ -138,6 +143,16 @@ static const EnumPropertyItem owner_space_pchan_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem track_axis_items[] = {
+ {TRACK_X, "TRACK_X", 0, "X", ""},
+ {TRACK_Y, "TRACK_Y", 0, "Y", ""},
+ {TRACK_Z, "TRACK_Z", 0, "Z", ""},
+ {TRACK_nX, "TRACK_NEGATIVE_X", 0, "-X", ""},
+ {TRACK_nY, "TRACK_NEGATIVE_Y", 0, "-Y", ""},
+ {TRACK_nZ, "TRACK_NEGATIVE_Z", 0, "-Z", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
static const EnumPropertyItem space_object_items[] = {
@@ -154,7 +169,6 @@ static const EnumPropertyItem space_object_items[] = {
#include "BKE_action.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
@@ -183,6 +197,8 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
return &RNA_MaintainVolumeConstraint;
case CONSTRAINT_TYPE_PYTHON:
return &RNA_PythonConstraint;
+ case CONSTRAINT_TYPE_ARMATURE:
+ return &RNA_ArmatureConstraint;
case CONSTRAINT_TYPE_ACTION:
return &RNA_ActionConstraint;
case CONSTRAINT_TYPE_LOCKTRACK:
@@ -191,8 +207,6 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
return &RNA_StretchToConstraint;
case CONSTRAINT_TYPE_MINMAX:
return &RNA_FloorConstraint;
- case CONSTRAINT_TYPE_RIGIDBODYJOINT:
- return &RNA_RigidBodyJointConstraint;
case CONSTRAINT_TYPE_CLAMPTO:
return &RNA_ClampToConstraint;
case CONSTRAINT_TYPE_TRANSFORM:
@@ -228,6 +242,17 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr)
}
}
+static void rna_ConstraintTargetBone_target_set(PointerRNA *ptr, PointerRNA value)
+{
+ bConstraintTarget *tgt = (bConstraintTarget *)ptr->data;
+ Object *ob = value.data;
+
+ if (!ob || ob->type == OB_ARMATURE) {
+ id_lib_extern((ID *)ob);
+ tgt->tar = ob;
+ }
+}
+
static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
{
bConstraint *con = ptr->data;
@@ -253,10 +278,8 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(NULL, "constraints", oldname, con->name);
}
-static char *rna_Constraint_path(PointerRNA *ptr)
+static char *rna_Constraint_do_compute_path(Object *ob, bConstraint *con)
{
- Object *ob = ptr->id.data;
- bConstraint *con = ptr->data;
bPoseChannel *pchan;
ListBase *lb = get_constraint_lb(ob, con, &pchan);
@@ -278,6 +301,55 @@ static char *rna_Constraint_path(PointerRNA *ptr)
}
}
+static char *rna_Constraint_path(PointerRNA *ptr)
+{
+ Object *ob = ptr->id.data;
+ bConstraint *con = ptr->data;
+
+ return rna_Constraint_do_compute_path(ob, con);
+}
+
+static bConstraint *rna_constraint_from_target(PointerRNA *ptr)
+{
+ Object *ob = ptr->id.data;
+ bConstraintTarget *tgt = ptr->data;
+
+ return BKE_constraint_find_from_target(ob, tgt, NULL);
+}
+
+static char *rna_ConstraintTarget_path(PointerRNA *ptr)
+{
+ Object *ob = ptr->id.data;
+ bConstraintTarget *tgt = ptr->data;
+ bConstraint *con = rna_constraint_from_target(ptr);
+ int index = -1;
+
+ if (con != NULL) {
+ if (con->type == CONSTRAINT_TYPE_ARMATURE) {
+ bArmatureConstraint *acon = con->data;
+ index = BLI_findindex(&acon->targets, tgt);
+ }
+ else if (con->type == CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *pcon = con->data;
+ index = BLI_findindex(&pcon->targets, tgt);
+ }
+ }
+
+ if (index >= 0) {
+ char *con_path = rna_Constraint_do_compute_path(ob, con);
+ char *result = BLI_sprintfN("%s.targets[%d]", con_path, index);
+
+ MEM_freeN(con_path);
+ return result;
+ }
+ else {
+ printf("%s: internal error, constraint '%s' of object '%s' does not contain the target\n",
+ __func__, con->name, ob->id.name);
+ }
+
+ return NULL;
+}
+
static void rna_Constraint_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
ED_object_constraint_tag_update(bmain, ptr->id.data, ptr->data);
@@ -288,6 +360,16 @@ static void rna_Constraint_dependency_update(Main *bmain, Scene *UNUSED(scene),
ED_object_constraint_dependency_tag_update(bmain, ptr->id.data, ptr->data);
}
+static void rna_ConstraintTarget_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ED_object_constraint_tag_update(bmain, ptr->id.data, rna_constraint_from_target(ptr));
+}
+
+static void rna_ConstraintTarget_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ED_object_constraint_dependency_tag_update(bmain, ptr->id.data, rna_constraint_from_target(ptr));
+}
+
static void rna_Constraint_influence_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Object *ob = ptr->id.data;
@@ -316,8 +398,9 @@ static void rna_Constraint_ik_type_set(struct PointerRNA *ptr, int value)
}
}
-static const EnumPropertyItem *rna_Constraint_owner_space_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+static const EnumPropertyItem *rna_Constraint_owner_space_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
Object *ob = (Object *)ptr->id.data;
bConstraint *con = (bConstraint *)ptr->data;
@@ -328,8 +411,9 @@ static const EnumPropertyItem *rna_Constraint_owner_space_itemf(bContext *UNUSED
return space_object_items;
}
-static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+static const EnumPropertyItem *rna_Constraint_target_space_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
bConstraint *con = (bConstraint *)ptr->data;
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
@@ -353,6 +437,43 @@ static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSE
return space_object_items;
}
+static bConstraintTarget *rna_ArmatureConstraint_target_new(ID *id, bConstraint *con, Main *bmain)
+{
+ bArmatureConstraint *acon = con->data;
+ bConstraintTarget *tgt = MEM_callocN(sizeof(bConstraintTarget), "Constraint Target");
+
+ tgt->weight = 1.0f;
+ BLI_addtail(&acon->targets, tgt);
+
+ ED_object_constraint_dependency_tag_update(bmain, (Object *)id, con);
+ return tgt;
+}
+
+static void rna_ArmatureConstraint_target_remove(
+ ID *id, bConstraint *con, Main *bmain, ReportList *reports, PointerRNA *target_ptr)
+{
+ bArmatureConstraint *acon = con->data;
+ bConstraintTarget *tgt = target_ptr->data;
+
+ if (BLI_findindex(&acon->targets, tgt) < 0) {
+ BKE_reportf(reports, RPT_ERROR, "Target is not in the constraint target list");
+ return;
+ }
+
+ BLI_freelinkN(&acon->targets, tgt);
+
+ ED_object_constraint_dependency_tag_update(bmain, (Object *)id, con);
+}
+
+static void rna_ArmatureConstraint_target_clear(ID *id, bConstraint *con, Main *bmain)
+{
+ bArmatureConstraint *acon = con->data;
+
+ BLI_freelistN(&acon->targets);
+
+ ED_object_constraint_dependency_tag_update(bmain, (Object *)id, con);
+}
+
static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float *max,
float *UNUSED(softmin), float *UNUSED(softmax))
{
@@ -399,6 +520,20 @@ static void rna_SplineIKConstraint_joint_bindings_set(PointerRNA *ptr, const flo
memcpy(ikData->points, values, ikData->numpoints * sizeof(float));
}
+static int rna_ShrinkwrapConstraint_face_cull_get(PointerRNA *ptr)
+{
+ bConstraint *con = (bConstraint *)ptr->data;
+ bShrinkwrapConstraint *swc = (bShrinkwrapConstraint *)con->data;
+ return swc->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK;
+}
+
+static void rna_ShrinkwrapConstraint_face_cull_set(struct PointerRNA *ptr, int value)
+{
+ bConstraint *con = (bConstraint *)ptr->data;
+ bShrinkwrapConstraint *swc = (bShrinkwrapConstraint *)con->data;
+ swc->flag = (swc->flag & ~CON_SHRINKWRAP_PROJECT_CULL_MASK) | value;
+}
+
static bool rna_Constraint_cameraObject_poll(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)value.data;
@@ -520,7 +655,7 @@ static void rna_def_constraint_headtail_common(StructRNA *srna)
prop = RNA_def_property(srna, "use_bbone_shape", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, "bConstraint", "flag", CONSTRAINT_BBONE_SHAPE);
RNA_def_property_ui_text(prop, "Follow B-Bone", "Follow shape of B-Bone segments when calculating Head/Tail position");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
}
static void rna_def_constraint_target_common(StructRNA *srna)
@@ -531,6 +666,7 @@ static void rna_def_constraint_target_common(StructRNA *srna)
RNA_def_property_pointer_sdna(prop, NULL, "tar");
RNA_def_property_ui_text(prop, "Target", "Target object");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE);
@@ -542,16 +678,58 @@ static void rna_def_constraint_target_common(StructRNA *srna)
static void rna_def_constrainttarget(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
srna = RNA_def_struct(brna, "ConstraintTarget", NULL);
RNA_def_struct_ui_text(srna, "Constraint Target", "Target object for multi-target constraints");
+ RNA_def_struct_path_func(srna, "rna_ConstraintTarget_path");
RNA_def_struct_sdna(srna, "bConstraintTarget");
- rna_def_constraint_target_common(srna);
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "tar");
+ RNA_def_property_ui_text(prop, "Target", "Target object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update");
+
+ prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "subtarget");
+ RNA_def_property_ui_text(prop, "Sub-Target", "Armature bone, mesh or lattice vertex group, ...");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update");
/* space, flag and type still to do */
}
+static void rna_def_constrainttarget_bone(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ConstraintTargetBone", NULL);
+ RNA_def_struct_ui_text(srna, "Constraint Target Bone", "Target bone for multi-target constraints");
+ RNA_def_struct_path_func(srna, "rna_ConstraintTarget_path");
+ RNA_def_struct_sdna(srna, "bConstraintTarget");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "tar");
+ RNA_def_property_ui_text(prop, "Target", "Target armature");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_ConstraintTargetBone_target_set", NULL, "rna_Armature_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update");
+
+ prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "subtarget");
+ RNA_def_property_ui_text(prop, "Sub-Target", "Target armature bone");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update");
+
+ prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "weight");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Blend Weight", "Blending weight of this bone");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_update");
+}
+
static void rna_def_constraint_childof(BlenderRNA *brna)
{
StructRNA *srna;
@@ -651,6 +829,70 @@ static void rna_def_constraint_python(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Script Error", "The linked Python script has thrown an error");
}
+
+static void rna_def_constraint_armature_deform_targets(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "ArmatureConstraintTargets");
+ srna = RNA_def_struct(brna, "ArmatureConstraintTargets", NULL);
+ RNA_def_struct_sdna(srna, "bConstraint");
+ RNA_def_struct_ui_text(srna, "Armature Deform Constraint Targets", "Collection of target bones and weights");
+
+ func = RNA_def_function(srna, "new", "rna_ArmatureConstraint_target_new");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Add a new target to the constraint");
+ parm = RNA_def_pointer(func, "target", "ConstraintTargetBone", "", "New target bone");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_ArmatureConstraint_target_remove");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Delete target from the constraint");
+ parm = RNA_def_pointer(func, "target", "ConstraintTargetBone", "", "Target to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "clear", "rna_ArmatureConstraint_target_clear");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func, "Delete all targets from object");
+}
+
+static void rna_def_constraint_armature_deform(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ArmatureConstraint", "Constraint");
+ RNA_def_struct_ui_text(srna, "Armature Constraint", "Applies transformations done by the Armature modifier");
+ RNA_def_struct_sdna_from(srna, "bArmatureConstraint", "data");
+
+ prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
+ RNA_def_property_struct_type(prop, "ConstraintTargetBone");
+ RNA_def_property_ui_text(prop, "Targets", "Target Bones");
+ rna_def_constraint_armature_deform_targets(brna, prop);
+
+ prop = RNA_def_property(srna, "use_deform_preserve_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_ARMATURE_QUATERNION);
+ RNA_def_property_ui_text(prop, "Preserve Volume", "Deform rotation interpolation with quaternions");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_ARMATURE_ENVELOPE);
+ RNA_def_property_ui_text(prop, "Use Envelopes",
+ "Multiply weights by envelope for all bones, instead of acting like Vertex Group based blending. "
+ "The specified weights are still used, and only the listed bones are considered");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_current_location", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_ARMATURE_CUR_LOCATION);
+ RNA_def_property_ui_text(prop, "Use Current Location",
+ "Use the current bone location for envelopes and choosing B-Bone segments instead of rest position");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+}
+
static void rna_def_constraint_kinematic(BlenderRNA *brna)
{
StructRNA *srna;
@@ -683,6 +925,7 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "poletar");
RNA_def_property_ui_text(prop, "Pole Target", "Object for pole rotation");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "pole_subtarget", PROP_STRING, PROP_NONE);
@@ -795,16 +1038,6 @@ static void rna_def_constraint_track_to(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem track_items[] = {
- {TRACK_X, "TRACK_X", 0, "X", ""},
- {TRACK_Y, "TRACK_Y", 0, "Y", ""},
- {TRACK_Z, "TRACK_Z", 0, "Z", ""},
- {TRACK_nX, "TRACK_NEGATIVE_X", 0, "-X", ""},
- {TRACK_nY, "TRACK_NEGATIVE_Y", 0, "-Y", ""},
- {TRACK_nZ, "TRACK_NEGATIVE_Z", 0, "-Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem up_items[] = {
{TRACK_X, "UP_X", 0, "X", ""},
{TRACK_Y, "UP_Y", 0, "Y", ""},
@@ -823,7 +1056,7 @@ static void rna_def_constraint_track_to(BlenderRNA *brna)
prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "reserved1");
- RNA_def_property_enum_items(prop, track_items);
+ RNA_def_property_enum_items(prop, track_axis_items);
RNA_def_property_ui_text(prop, "Track Axis", "Axis that points to the target object");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -964,7 +1197,12 @@ static void rna_def_constraint_size_like(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_offset", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIZELIKE_OFFSET);
- RNA_def_property_ui_text(prop, "Offset", "Add original scale into copied scale");
+ RNA_def_property_ui_text(prop, "Offset", "Combine original scale with copied scale");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_add", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIZELIKE_MULTIPLY);
+ RNA_def_property_ui_text(prop, "Additive", "Use addition instead of multiplication to combine scale (2.7 compatibility)");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
@@ -1091,6 +1329,7 @@ static void rna_def_constraint_action(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Action_id_poll");
RNA_def_property_ui_text(prop, "Action", "The constraining action");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "use_bone_object_action", PROP_BOOLEAN, PROP_NONE);
@@ -1132,16 +1371,6 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem locktrack_items[] = {
- {TRACK_X, "TRACK_X", 0, "X", ""},
- {TRACK_Y, "TRACK_Y", 0, "Y", ""},
- {TRACK_Z, "TRACK_Z", 0, "Z", ""},
- {TRACK_nX, "TRACK_NEGATIVE_X", 0, "-X", ""},
- {TRACK_nY, "TRACK_NEGATIVE_Y", 0, "-Y", ""},
- {TRACK_nZ, "TRACK_NEGATIVE_Z", 0, "-Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem lock_items[] = {
{TRACK_X, "LOCK_X", 0, "X", ""},
{TRACK_Y, "LOCK_Y", 0, "Y", ""},
@@ -1161,7 +1390,7 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna)
prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "trackflag");
- RNA_def_property_enum_items(prop, locktrack_items);
+ RNA_def_property_enum_items(prop, track_axis_items);
RNA_def_property_ui_text(prop, "Track Axis", "Axis that points to the target object");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -1203,6 +1432,7 @@ static void rna_def_constraint_follow_path(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll");
RNA_def_property_ui_text(prop, "Target", "Target Curve object");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TIME);
@@ -1324,178 +1554,6 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
-static void rna_def_constraint_rigid_body_joint(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem pivot_items[] = {
- {CONSTRAINT_RB_BALL, "BALL", 0, "Ball", "Allow rotations around all axes"},
- {CONSTRAINT_RB_HINGE, "HINGE", 0, "Hinge", "Work in one plane, allow rotations around one axis only"},
- {CONSTRAINT_RB_CONETWIST, "CONE_TWIST", 0, "Cone Twist",
- "Allow rotations around all axes with limits for the cone and twist axes"},
- {CONSTRAINT_RB_GENERIC6DOF, "GENERIC_6_DOF", 0, "Generic 6 DoF",
- "No constraints by default, limits can be set individually"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "RigidBodyJointConstraint", "Constraint");
- RNA_def_struct_ui_text(srna, "Rigid Body Joint Constraint", "For use with the Game Engine");
- RNA_def_struct_sdna_from(srna, "bRigidBodyJointConstraint", "data");
-
- prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "tar");
- RNA_def_property_ui_text(prop, "Target", "Target Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
-
- prop = RNA_def_property(srna, "child", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "Child Object", "Child object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
-
- prop = RNA_def_property(srna, "pivot_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, pivot_items);
- RNA_def_property_ui_text(prop, "Pivot Type", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "pivot_x", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "pivX");
- RNA_def_property_range(prop, -1000.0, 1000.f);
- RNA_def_property_ui_text(prop, "Pivot X", "Offset pivot on X");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "pivot_y", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "pivY");
- RNA_def_property_range(prop, -1000.0, 1000.f);
- RNA_def_property_ui_text(prop, "Pivot Y", "Offset pivot on Y");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "pivot_z", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "pivZ");
- RNA_def_property_range(prop, -1000.0, 1000.f);
- RNA_def_property_ui_text(prop, "Pivot Z", "Offset pivot on Z");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "axis_x", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "axX");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Axis X", "Rotate pivot on X axis");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "axis_y", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "axY");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Axis Y", "Rotate pivot on Y axis");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "axis_z", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "axZ");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Axis Z", "Rotate pivot on Z axis");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "use_linked_collision", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_DISABLE_LINKED_COLLISION);
- RNA_def_property_ui_text(prop, "Disable Linked Collision", "Disable collision between linked bodies");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "show_pivot", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_DRAW_PIVOT);
- RNA_def_property_ui_text(prop, "Draw Pivot", "Display the pivot point and rotation in 3D view");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
-
- /* Limits */
- /* Limit Min/Max */
- prop = RNA_def_property(srna, "limit_min_x", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "minLimit[0]");
- RNA_def_property_ui_text(prop, "Minimum Limit X", "");
-
- prop = RNA_def_property(srna, "limit_min_y", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "minLimit[1]");
- RNA_def_property_ui_text(prop, "Minimum Limit Y", "");
-
- prop = RNA_def_property(srna, "limit_min_z", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "minLimit[2]");
- RNA_def_property_ui_text(prop, "Minimum Limit Z", "");
-
- prop = RNA_def_property(srna, "limit_max_x", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "maxLimit[0]");
- RNA_def_property_ui_text(prop, "Maximum Limit X", "");
-
- prop = RNA_def_property(srna, "limit_max_y", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "maxLimit[1]");
- RNA_def_property_ui_text(prop, "Maximum Limit Y", "");
-
- prop = RNA_def_property(srna, "limit_max_z", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "maxLimit[2]");
- RNA_def_property_ui_text(prop, "Maximum Limit Z", "");
-
- /* Limit Min/Max for angle */
- prop = RNA_def_property(srna, "limit_angle_min_x", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "minLimit[3]");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Minimum Angular Limit X", "");
-
- prop = RNA_def_property(srna, "limit_angle_min_y", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "minLimit[4]");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Minimum Angular Limit Y", "");
-
- prop = RNA_def_property(srna, "limit_angle_min_z", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "minLimit[5]");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Minimum Angular Limit Z", "");
-
- prop = RNA_def_property(srna, "limit_angle_max_x", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "maxLimit[3]");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Maximum Angular Limit X", "");
-
- prop = RNA_def_property(srna, "limit_angle_max_y", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "maxLimit[4]");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Maximum Angular Limit Y", "");
-
- prop = RNA_def_property(srna, "limit_angle_max_z", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "maxLimit[5]");
- RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
- RNA_def_property_ui_text(prop, "Maximum Angular Limit Z", "");
-
- /* Limit Booleans */
- prop = RNA_def_property(srna, "use_limit_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", 1);
- RNA_def_property_ui_text(prop, "Limit X", "Use minimum/maximum X limit");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "use_limit_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", 2);
- RNA_def_property_ui_text(prop, "Limit Y", "Use minimum/maximum y limit");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "use_limit_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", 4);
- RNA_def_property_ui_text(prop, "Limit Z", "Use minimum/maximum z limit");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "use_angular_limit_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", 8);
- RNA_def_property_ui_text(prop, "Angular X Limit", "Use minimum/maximum X angular limit");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "use_angular_limit_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", 16);
- RNA_def_property_ui_text(prop, "Angular Y Limit", "Use minimum/maximum Y angular limit");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
- prop = RNA_def_property(srna, "use_angular_limit_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", 32);
- RNA_def_property_ui_text(prop, "Angular Z Limit", "Use minimum/maximum Z angular limit");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-}
-
static void rna_def_constraint_clamp_to(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1519,6 +1577,7 @@ static void rna_def_constraint_clamp_to(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll");
RNA_def_property_ui_text(prop, "Target", "Target Object (Curves only)");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "main_axis", PROP_ENUM, PROP_NONE);
@@ -2078,6 +2137,16 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
"Shrink the location to the nearest target surface along a given axis"},
{MOD_SHRINKWRAP_NEAREST_VERTEX, "NEAREST_VERTEX", 0, "Nearest Vertex",
"Shrink the location to the nearest target vertex"},
+ {MOD_SHRINKWRAP_TARGET_PROJECT, "TARGET_PROJECT", 0, "Target Normal Project",
+ "Shrink the location to the nearest target surface "
+ "along the interpolated vertex normals of the target"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem shrink_face_cull_items[] = {
+ {0, "OFF", 0, "Off", "No culling"},
+ {CON_SHRINKWRAP_PROJECT_CULL_FRONTFACE, "FRONT", 0, "Front", "No projection when in front of the face"},
+ {CON_SHRINKWRAP_PROJECT_CULL_BACKFACE, "BACK", 0, "Back", "No projection when behind the face"},
{0, NULL, 0, NULL, NULL}
};
@@ -2090,13 +2159,20 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll");
RNA_def_property_ui_text(prop, "Target", "Target Mesh object");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "shrinkwrap_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkType");
RNA_def_property_enum_items(prop, type_items);
RNA_def_property_ui_text(prop, "Shrinkwrap Type", "Select type of shrinkwrap algorithm for target position");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+ prop = RNA_def_property(srna, "wrap_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrinkMode");
+ RNA_def_property_enum_items(prop, rna_enum_modifier_shrinkwrap_mode_items);
+ RNA_def_property_ui_text(prop, "Snap Mode", "Select how to constrain the object to the target surface");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "dist");
@@ -2123,6 +2199,36 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 10, 3);
RNA_def_property_ui_text(prop, "Project Distance", "Limit the distance used for projection (zero disables)");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_project_opposite", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CON_SHRINKWRAP_PROJECT_OPPOSITE);
+ RNA_def_property_ui_text(prop, "Project Opposite", "Project in both specified and opposite directions");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, shrink_face_cull_items);
+ RNA_def_property_enum_funcs(prop, "rna_ShrinkwrapConstraint_face_cull_get",
+ "rna_ShrinkwrapConstraint_face_cull_set", NULL);
+ RNA_def_property_ui_text(prop, "Face Cull",
+ "Stop vertices from projecting to a face on the target when facing towards/away");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_invert_cull", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CON_SHRINKWRAP_PROJECT_INVERT_CULL);
+ RNA_def_property_ui_text(prop, "Invert Cull", "When projecting in the opposite direction invert the face cull mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_track_normal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CON_SHRINKWRAP_TRACK_NORMAL);
+ RNA_def_property_ui_text(prop, "Align Axis To Normal", "Align the specified axis to the surface normal");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+ prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "trackAxis");
+ RNA_def_property_enum_items(prop, track_axis_items);
+ RNA_def_property_ui_text(prop, "Track Axis", "Axis that is aligned to the normal");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_damped_track(BlenderRNA *brna)
@@ -2130,16 +2236,6 @@ static void rna_def_constraint_damped_track(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem damptrack_items[] = {
- {TRACK_X, "TRACK_X", 0, "X", ""},
- {TRACK_Y, "TRACK_Y", 0, "Y", ""},
- {TRACK_Z, "TRACK_Z", 0, "Z", ""},
- {TRACK_nX, "TRACK_NEGATIVE_X", 0, "-X", ""},
- {TRACK_nY, "TRACK_NEGATIVE_Y", 0, "-Y", ""},
- {TRACK_nZ, "TRACK_NEGATIVE_Z", 0, "-Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "DampedTrackConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Damped Track Constraint",
"Point toward target by taking the shortest rotation path");
@@ -2152,7 +2248,7 @@ rna_def_constraint_headtail_common(srna);
prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "trackflag");
- RNA_def_property_enum_items(prop, damptrack_items);
+ RNA_def_property_enum_items(prop, track_axis_items);
RNA_def_property_ui_text(prop, "Track Axis", "Axis that points to the target object");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
@@ -2183,6 +2279,7 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll");
RNA_def_property_ui_text(prop, "Target", "Curve that controls this relationship");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "chain_count", PROP_INT, PROP_NONE);
@@ -2301,6 +2398,7 @@ static void rna_def_constraint_pivot(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "tar");
RNA_def_property_ui_text(prop, "Target", "Target Object, defining the position of the pivot when defined");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE);
@@ -2351,6 +2449,7 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "clip");
RNA_def_property_ui_text(prop, "Movie Clip", "Movie Clip to get tracking data from");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
/* track */
@@ -2383,6 +2482,7 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Camera",
"Camera to which motion is parented (if empty active scene camera is used)");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
RNA_def_property_pointer_funcs(prop, NULL, "rna_Constraint_followTrack_camera_set", NULL,
"rna_Constraint_cameraObject_poll");
@@ -2393,6 +2493,7 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Depth Object",
"Object used to define depth in camera space by projecting onto surface of this object");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
RNA_def_property_pointer_funcs(prop, NULL, "rna_Constraint_followTrack_depthObject_set", NULL,
"rna_Constraint_followTrack_depthObject_poll");
@@ -2425,6 +2526,7 @@ static void rna_def_constraint_camera_solver(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "clip");
RNA_def_property_ui_text(prop, "Movie Clip", "Movie Clip to get tracking data from");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
/* use default clip */
@@ -2448,6 +2550,7 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "clip");
RNA_def_property_ui_text(prop, "Movie Clip", "Movie Clip to get tracking data from");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
/* use default clip */
@@ -2468,6 +2571,7 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Camera",
"Camera to which motion is parented (if empty active scene camera is used)");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
RNA_def_property_pointer_funcs(prop, NULL, "rna_Constraint_objectSolver_camera_set", NULL,
"rna_Constraint_cameraObject_poll");
@@ -2487,6 +2591,7 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
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_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, 0, "rna_Constraint_dependency_update");
prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
@@ -2536,12 +2641,14 @@ void RNA_def_constraint(BlenderRNA *brna)
/* flags */
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_OFF);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint");
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_EXPAND);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Expanded", "Constraint's panel is expanded in UI");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
/* XXX this is really an internal flag, but it may be useful for some tools to be able to access this... */
prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
@@ -2581,9 +2688,11 @@ void RNA_def_constraint(BlenderRNA *brna)
/* pointers */
rna_def_constrainttarget(brna);
+ rna_def_constrainttarget_bone(brna);
rna_def_constraint_childof(brna);
rna_def_constraint_python(brna);
+ rna_def_constraint_armature_deform(brna);
rna_def_constraint_stretch_to(brna);
rna_def_constraint_follow_path(brna);
rna_def_constraint_locked_track(brna);
@@ -2596,7 +2705,6 @@ void RNA_def_constraint(BlenderRNA *brna)
rna_def_constraint_minmax(brna);
rna_def_constraint_track_to(brna);
rna_def_constraint_kinematic(brna);
- rna_def_constraint_rigid_body_joint(brna);
rna_def_constraint_clamp_to(brna);
rna_def_constraint_distance_limit(brna);
rna_def_constraint_size_limit(brna);
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index 04b531740ed..618cefe13e5 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -34,11 +34,36 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "rna_internal.h" /* own include */
+const EnumPropertyItem rna_enum_context_mode_items[] = {
+ {CTX_MODE_EDIT_MESH, "EDIT_MESH", 0, "Mesh Edit", ""},
+ {CTX_MODE_EDIT_CURVE, "EDIT_CURVE", 0, "Curve Edit", ""},
+ {CTX_MODE_EDIT_SURFACE, "EDIT_SURFACE", 0, "Surface Edit", ""},
+ {CTX_MODE_EDIT_TEXT, "EDIT_TEXT", 0, "Edit Edit", ""},
+ {CTX_MODE_EDIT_ARMATURE, "EDIT_ARMATURE", 0, "Armature Edit", ""}, /* PARSKEL reuse will give issues */
+ {CTX_MODE_EDIT_METABALL, "EDIT_METABALL", 0, "Metaball Edit", ""},
+ {CTX_MODE_EDIT_LATTICE, "EDIT_LATTICE", 0, "Lattice Edit", ""},
+ {CTX_MODE_POSE, "POSE", 0, "Pose ", ""},
+ {CTX_MODE_SCULPT, "SCULPT", 0, "Sculpt", ""},
+ {CTX_MODE_PAINT_WEIGHT, "PAINT_WEIGHT", 0, "Weight Paint", ""},
+ {CTX_MODE_PAINT_VERTEX, "PAINT_VERTEX", 0, "Vertex Paint", ""},
+ {CTX_MODE_PAINT_TEXTURE, "PAINT_TEXTURE", 0, "Texture Paint", ""},
+ {CTX_MODE_PARTICLE, "PARTICLE", 0, "Particle", ""},
+ {CTX_MODE_OBJECT, "OBJECT", 0, "Object", ""},
+ {CTX_MODE_GPENCIL_PAINT, "GPENCIL_PAINT", 0, "Grease Pencil Paint", "" },
+ {CTX_MODE_GPENCIL_EDIT, "GPENCIL_EDIT", 0, "Grease Pencil Edit", "" },
+ {CTX_MODE_GPENCIL_SCULPT, "GPENCIL_SCULPT", 0, "Grease Pencil Sculpt", "" },
+ {CTX_MODE_GPENCIL_WEIGHT, "GPENCIL_WEIGHT", 0, "Grease Pencil Weight Paint", "" },
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
+#include "RE_engine.h"
+
static PointerRNA rna_Context_manager_get(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
@@ -51,6 +76,12 @@ static PointerRNA rna_Context_window_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_Window, CTX_wm_window(C));
}
+static PointerRNA rna_Context_workspace_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_WorkSpace, CTX_wm_workspace(C));
+}
+
static PointerRNA rna_Context_screen_get(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
@@ -95,18 +126,69 @@ static PointerRNA rna_Context_region_data_get(PointerRNA *ptr)
return PointerRNA_NULL;
}
+static PointerRNA rna_Context_gizmo_group_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ PointerRNA newptr;
+ RNA_pointer_create(NULL, &RNA_GizmoGroup, CTX_wm_gizmo_group(C), &newptr);
+ return newptr;
+}
+
static PointerRNA rna_Context_main_get(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
return rna_pointer_inherit_refine(ptr, &RNA_BlendData, CTX_data_main(C));
}
+static PointerRNA rna_Context_depsgraph_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_Depsgraph, CTX_data_depsgraph(C));
+}
+
static PointerRNA rna_Context_scene_get(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
return rna_pointer_inherit_refine(ptr, &RNA_Scene, CTX_data_scene(C));
}
+static PointerRNA rna_Context_view_layer_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ Scene *scene = CTX_data_scene(C);
+ PointerRNA scene_ptr;
+
+ RNA_id_pointer_create(&scene->id, &scene_ptr);
+ return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, CTX_data_view_layer(C));
+}
+
+static void rna_Context_engine_get(PointerRNA *ptr, char *value)
+ {
+ bContext *C = (bContext *)ptr->data;
+ RenderEngineType *engine_type = CTX_data_engine_type(C);
+ strcpy(value, engine_type->idname);
+}
+
+static int rna_Context_engine_length(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ RenderEngineType *engine_type = CTX_data_engine_type(C);
+ return strlen(engine_type->idname);
+}
+
+static PointerRNA rna_Context_collection_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_Collection, CTX_data_collection(C));
+}
+
+static PointerRNA rna_Context_layer_collection_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ ptr->id.data = CTX_data_scene(C);
+ return rna_pointer_inherit_refine(ptr, &RNA_LayerCollection, CTX_data_layer_collection(C));
+}
+
static PointerRNA rna_Context_tool_settings_get(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
@@ -134,24 +216,6 @@ void RNA_def_context(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem mode_items[] = {
- {CTX_MODE_EDIT_MESH, "EDIT_MESH", 0, "Mesh Edit", ""},
- {CTX_MODE_EDIT_CURVE, "EDIT_CURVE", 0, "Curve Edit", ""},
- {CTX_MODE_EDIT_SURFACE, "EDIT_SURFACE", 0, "Surface Edit", ""},
- {CTX_MODE_EDIT_TEXT, "EDIT_TEXT", 0, "Edit Edit", ""},
- {CTX_MODE_EDIT_ARMATURE, "EDIT_ARMATURE", 0, "Armature Edit", ""}, /* PARSKEL reuse will give issues */
- {CTX_MODE_EDIT_METABALL, "EDIT_METABALL", 0, "Metaball Edit", ""},
- {CTX_MODE_EDIT_LATTICE, "EDIT_LATTICE", 0, "Lattice Edit", ""},
- {CTX_MODE_POSE, "POSE", 0, "Pose ", ""},
- {CTX_MODE_SCULPT, "SCULPT", 0, "Sculpt", ""},
- {CTX_MODE_PAINT_WEIGHT, "PAINT_WEIGHT", 0, "Weight Paint", ""},
- {CTX_MODE_PAINT_VERTEX, "PAINT_VERTEX", 0, "Vertex Paint", ""},
- {CTX_MODE_PAINT_TEXTURE, "PAINT_TEXTURE", 0, "Texture Paint", ""},
- {CTX_MODE_PARTICLE, "PARTICLE", 0, "Particle", ""},
- {CTX_MODE_OBJECT, "OBJECT", 0, "Object", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "Context", NULL);
RNA_def_struct_ui_text(srna, "Context", "Current windowmanager and data context");
RNA_def_struct_sdna(srna, "bContext");
@@ -167,6 +231,11 @@ void RNA_def_context(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Window");
RNA_def_property_pointer_funcs(prop, "rna_Context_window_get", NULL, NULL, NULL);
+ prop = RNA_def_property(srna, "workspace", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "WorkSpace");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_workspace_get", NULL, NULL, NULL);
+
prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "Screen");
@@ -192,17 +261,46 @@ void RNA_def_context(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "RegionView3D");
RNA_def_property_pointer_funcs(prop, "rna_Context_region_data_get", NULL, NULL, NULL);
+ prop = RNA_def_property(srna, "gizmo_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "GizmoGroup");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_gizmo_group_get", NULL, NULL, NULL);
+
/* Data */
prop = RNA_def_property(srna, "blend_data", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "BlendData");
RNA_def_property_pointer_funcs(prop, "rna_Context_main_get", NULL, NULL, NULL);
+ prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "Depsgraph");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_depsgraph_get", NULL, NULL, NULL);
+
prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "Scene");
RNA_def_property_pointer_funcs(prop, "rna_Context_scene_get", NULL, NULL, NULL);
+ prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "ViewLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_view_layer_get", NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "engine", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(prop, "rna_Context_engine_get", "rna_Context_engine_length", NULL);
+
+ prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_collection_get", NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "layer_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "LayerCollection");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_layer_collection_get", NULL, NULL, NULL);
+
prop = RNA_def_property(srna, "tool_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "ToolSettings");
@@ -214,7 +312,7 @@ void RNA_def_context(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_Context_user_preferences_get", NULL, NULL, NULL);
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_context_mode_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_enum_funcs(prop, "rna_Context_mode_get", NULL, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c
deleted file mode 100644
index 606f482c92e..00000000000
--- a/source/blender/makesrna/intern/rna_controller.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * ***** 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): Blender Foundation (2008).
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/makesrna/intern/rna_controller.c
- * \ingroup RNA
- */
-
-#include <stdlib.h>
-
-#include "DNA_object_types.h"
-#include "DNA_controller_types.h"
-
-#include "BLI_string_utils.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "rna_internal.h"
-
-#include "WM_types.h"
-
-const EnumPropertyItem rna_enum_controller_type_items[] = {
- {CONT_LOGIC_AND, "LOGIC_AND", 0, "And", "Logic And"},
- {CONT_LOGIC_OR, "LOGIC_OR", 0, "Or", "Logic Or"},
- {CONT_LOGIC_NAND, "LOGIC_NAND", 0, "Nand", "Logic Nand"},
- {CONT_LOGIC_NOR, "LOGIC_NOR", 0, "Nor", "Logic Nor"},
- {CONT_LOGIC_XOR, "LOGIC_XOR", 0, "Xor", "Logic Xor"},
- {CONT_LOGIC_XNOR, "LOGIC_XNOR", 0, "Xnor", "Logic Xnor"},
- {CONT_EXPRESSION, "EXPRESSION", 0, "Expression", ""},
- {CONT_PYTHON, "PYTHON", 0, "Python", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_sca.h"
-#include "DNA_actuator_types.h"
-
-static StructRNA *rna_Controller_refine(struct PointerRNA *ptr)
-{
- bController *controller = (bController *)ptr->data;
-
- switch (controller->type) {
- case CONT_LOGIC_AND:
- return &RNA_AndController;
- case CONT_LOGIC_OR:
- return &RNA_OrController;
- case CONT_LOGIC_NAND:
- return &RNA_NandController;
- case CONT_LOGIC_NOR:
- return &RNA_NorController;
- case CONT_LOGIC_XOR:
- return &RNA_XorController;
- case CONT_LOGIC_XNOR:
- return &RNA_XnorController;
- case CONT_EXPRESSION:
- return &RNA_ExpressionController;
- case CONT_PYTHON:
- return &RNA_PythonController;
- default:
- return &RNA_Controller;
- }
-}
-
-static void rna_Constroller_name_set(PointerRNA *ptr, const char *value)
-{
- Object *ob = ptr->id.data;
- bController *cont = ptr->data;
- BLI_strncpy_utf8(cont->name, value, sizeof(cont->name));
- BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));
-}
-
-static void rna_Controller_type_set(struct PointerRNA *ptr, int value)
-{
- bController *cont = (bController *)ptr->data;
-
- if (value != cont->type) {
- cont->type = value;
- init_controller(cont);
- }
-}
-
-static void rna_Controller_mode_set(struct PointerRNA *ptr, int value)
-{
- bController *cont = (bController *)ptr->data;
- bPythonCont *pycon = (bPythonCont *)cont->data;
-
- /* if mode changed and previous mode were Script */
- if (value != pycon->mode && pycon->mode == CONT_PY_SCRIPT) {
- /* clear script to avoid it to get linked with the controller */
- pycon->text = NULL;
- }
- pycon->mode = value;
-}
-
-static int rna_Controller_state_number_get(struct PointerRNA *ptr)
-{
- bController *cont = (bController *)ptr->data;
- int bit;
-
- for (bit = 0; bit < 32; bit++) {
- if (cont->state_mask & (1u << bit))
- return bit + 1;
- }
- return 0;
-}
-
-static void rna_Controller_state_number_set(struct PointerRNA *ptr, const int value)
-{
- bController *cont = (bController *)ptr->data;
- if (value < 1 || value > OB_MAX_STATES)
- return;
-
- cont->state_mask = (1 << (value - 1));
-}
-
-static void rna_Controller_actuators_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- bController *cont = (bController *)ptr->data;
- rna_iterator_array_begin(iter, cont->links, sizeof(bActuator *), (int)cont->totlinks, 0, NULL);
-}
-
-static int rna_Controller_actuators_length(PointerRNA *ptr)
-{
- bController *cont = (bController *)ptr->data;
- return (int) cont->totlinks;
-}
-
-#if 0 /* editable is set to false, comment for now. */
-static void rna_Controller_state_get(PointerRNA *ptr, int *values)
-{
- bController *cont = (bController *)ptr->data;
- int i;
-
- memset(values, 0, sizeof(int) * OB_MAX_STATES);
- for (i = 0; i < OB_MAX_STATES; i++)
- values[i] = (cont->state_mask & (1 << i));
-}
-
-static void rna_Controller_state_set(PointerRNA *ptr, const bool *values)
-{
- bController *cont = (bController *)ptr->data;
- int i, tot = 0;
-
- /* ensure we always have some state selected */
- for (i = 0; i < OB_MAX_STATES; i++)
- if (values[i])
- tot++;
-
- if (tot == 0)
- return;
-
- /* only works for one state at once */
- if (tot > 1)
- return;
-
- for (i = 0; i < OB_MAX_STATES; i++) {
- if (values[i]) cont->state_mask |= (1 << i);
- else cont->state_mask &= ~(1 << i);
- }
-}
-#endif
-
-#else
-
-void RNA_def_controller(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem python_controller_modes[] = {
- {CONT_PY_SCRIPT, "SCRIPT", 0, "Script", ""},
- {CONT_PY_MODULE, "MODULE", 0, "Module", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* Controller */
- srna = RNA_def_struct(brna, "Controller", NULL);
- RNA_def_struct_sdna(srna, "bController");
- RNA_def_struct_refine_func(srna, "rna_Controller_refine");
- RNA_def_struct_ui_text(srna, "Controller",
- "Game engine logic brick to process events, connecting sensors to actuators");
-
- RNA_api_controller(srna);
-
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Name", "");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Constroller_name_set");
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Controller_type_set", NULL);
- RNA_def_property_enum_items(prop, rna_enum_controller_type_items);
- RNA_def_property_ui_text(prop, "Type", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CONT_SHOW);
- RNA_def_property_ui_text(prop, "Expanded", "Set controller expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", CONT_DEACTIVATE);
- RNA_def_property_ui_text(prop, "Active", "Set the active state of the controller");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_priority", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CONT_PRIO);
- RNA_def_property_ui_text(prop, "Priority",
- "Mark controller for execution before all non-marked controllers "
- "(good for startup scripts)");
- RNA_def_property_ui_icon(prop, ICON_BOOKMARKS, 1);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "actuators", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "links", NULL);
- RNA_def_property_struct_type(prop, "Actuator");
- RNA_def_property_ui_text(prop, "Actuators", "The list containing the actuators connected to the controller");
- RNA_def_property_collection_funcs(prop, "rna_Controller_actuators_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_dereference_get",
- "rna_Controller_actuators_length", NULL, NULL, NULL);
-
- /* State */
-
- /* array of OB_MAX_STATES */
- /*prop = RNA_def_property(srna, "states", PROP_BOOLEAN, PROP_LAYER_MEMBER); */
- /*RNA_def_property_array(prop, OB_MAX_STATES); */
- /*RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
- /*RNA_def_property_ui_text(prop, "", "Set Controller state index (1 to 30)"); */
- /*RNA_def_property_boolean_funcs(prop, "rna_Controller_state_get", "rna_Controller_state_set"); */
- /*RNA_def_property_update(prop, NC_LOGIC, NULL); */
-
- /* number of the state */
- prop = RNA_def_property(srna, "states", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "state_mask");
- RNA_def_property_range(prop, 1, OB_MAX_STATES);
- RNA_def_property_ui_text(prop, "", "Set Controller state index (1 to 30)");
- RNA_def_property_int_funcs(prop, "rna_Controller_state_number_get", "rna_Controller_state_number_set", NULL);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Expression Controller */
- srna = RNA_def_struct(brna, "ExpressionController", "Controller");
- RNA_def_struct_sdna_from(srna, "bExpressionCont", "data");
- RNA_def_struct_ui_text(srna, "Expression Controller",
- "Controller passing on events based on the evaluation of an expression");
-
- prop = RNA_def_property(srna, "expression", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "str");
- RNA_def_property_ui_text(prop, "Expression", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Python Controller */
- srna = RNA_def_struct(brna, "PythonController", "Controller");
- RNA_def_struct_sdna_from(srna, "bPythonCont", "data");
- RNA_def_struct_ui_text(srna, "Python Controller", "Controller executing a python script");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, python_controller_modes);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Controller_mode_set", NULL);
- RNA_def_property_ui_text(prop, "Execution Method", "Python script type (textblock or module - faster)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Text");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Text", "Text data-block with the python script");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "module", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Module",
- "Module name and function to run, e.g. \"someModule.main\" "
- "(internal texts and external python files can be used)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_debug", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CONT_PY_DEBUG);
- RNA_def_property_ui_text(prop, "D",
- "Continuously reload the module from disk for editing external modules "
- "without restarting");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Other Controllers */
- srna = RNA_def_struct(brna, "AndController", "Controller");
- RNA_def_struct_ui_text(srna, "And Controller", "Controller passing on events based on a logical AND operation");
-
- srna = RNA_def_struct(brna, "OrController", "Controller");
- RNA_def_struct_ui_text(srna, "Or Controller", "Controller passing on events based on a logical OR operation");
-
- srna = RNA_def_struct(brna, "NorController", "Controller");
- RNA_def_struct_ui_text(srna, "Nor Controller", "Controller passing on events based on a logical NOR operation");
-
- srna = RNA_def_struct(brna, "NandController", "Controller");
- RNA_def_struct_ui_text(srna, "Nand Controller", "Controller passing on events based on a logical NAND operation");
-
- srna = RNA_def_struct(brna, "XorController", "Controller");
- RNA_def_struct_ui_text(srna, "Xor Controller", "Controller passing on events based on a logical XOR operation");
-
- srna = RNA_def_struct(brna, "XnorController", "Controller");
- RNA_def_struct_ui_text(srna, "Xnor Controller", "Controller passing on events based on a logical XNOR operation");
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_controller_api.c b/source/blender/makesrna/intern/rna_controller_api.c
deleted file mode 100644
index c36d678e064..00000000000
--- a/source/blender/makesrna/intern/rna_controller_api.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * ***** 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) 2010 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s):
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/makesrna/intern/rna_controller_api.c
- * \ingroup RNA
- */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "WM_types.h"
-#include "RNA_define.h"
-
-#include "rna_internal.h" /* own include */
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_sca.h"
-#include "DNA_sensor_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
-
-static void rna_Controller_link(bController *cont, bSensor *sens, bActuator *act)
-{
- if (sens)
- link_logicbricks((void **)&cont, (void ***)&(sens->links), &sens->totlinks, sizeof(bController *));
- if (act)
- link_logicbricks((void **)&act, (void ***)&(cont->links), &cont->totlinks, sizeof(bActuator *));
-}
-
-static void rna_Controller_unlink(bController *cont, bSensor *sens, bActuator *act)
-{
- if (sens)
- unlink_logicbricks((void **)&cont, (void ***)&(sens->links), &sens->totlinks);
- if (act)
- unlink_logicbricks((void **)&act, (void ***)&(cont->links), &cont->totlinks);
-}
-
-#else
-
-void RNA_api_controller(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *parm;
-
- func = RNA_def_function(srna, "link", "rna_Controller_link");
- RNA_def_function_ui_description(func, "Link the controller with a sensor/actuator");
- parm = RNA_def_pointer(func, "sensor", "Sensor", "", "Sensor to link the controller to");
- RNA_def_property_update(parm, NC_LOGIC, NULL);
- parm = RNA_def_pointer(func, "actuator", "Actuator", "", "Actuator to link the controller to");
- RNA_def_property_update(parm, NC_LOGIC, NULL);
-
- func = RNA_def_function(srna, "unlink", "rna_Controller_unlink");
- RNA_def_function_ui_description(func, "Unlink the controller from a sensor/actuator");
- parm = RNA_def_pointer(func, "sensor", "Sensor", "", "Sensor to unlink the controller from");
- RNA_def_property_update(parm, NC_LOGIC, NULL);
- parm = RNA_def_pointer(func, "actuator", "Actuator", "", "Actuator to unlink the controller from");
- RNA_def_property_update(parm, NC_LOGIC, NULL);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 233303ef613..41849f3efe7 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -57,11 +57,11 @@ static const EnumPropertyItem beztriple_handle_type_items[] = {
#endif
const EnumPropertyItem rna_enum_keyframe_handle_type_items[] = {
- {HD_FREE, "FREE", 0, "Free", ""},
- {HD_VECT, "VECTOR", 0, "Vector", ""},
- {HD_ALIGN, "ALIGNED", 0, "Aligned", ""},
- {HD_AUTO, "AUTO", 0, "Automatic", ""},
- {HD_AUTO_ANIM, "AUTO_CLAMPED", 0, "Auto Clamped", "Auto handles clamped to not overshoot"},
+ {HD_FREE, "FREE", ICON_HANDLETYPE_FREE_VEC, "Free", "Completely independent manually set handle"},
+ {HD_ALIGN, "ALIGNED", ICON_HANDLETYPE_ALIGNED_VEC, "Aligned", "Manually set handle with rotation locked together with its pair"},
+ {HD_VECT, "VECTOR", ICON_HANDLETYPE_VECTOR_VEC, "Vector", "Automatic handles that create straight lines"},
+ {HD_AUTO, "AUTO", ICON_HANDLETYPE_AUTO_VEC, "Automatic", "Automatic handles that create smooth curves"},
+ {HD_AUTO_ANIM, "AUTO_CLAMPED", ICON_HANDLETYPE_AUTO_CLAMP_VEC, "Auto Clamped", "Automatic handles that create smooth curves which only change direction at keyframes"},
{0, NULL, 0, NULL, NULL}
};
@@ -124,9 +124,11 @@ static const EnumPropertyItem curve2d_fill_mode_items[] = {
#include "DNA_object_types.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "WM_api.h"
#include "MEM_guardedalloc.h"
@@ -338,7 +340,7 @@ static void rna_BPoint_array_begin(CollectionPropertyIterator *iter, PointerRNA
static void rna_Curve_update_data_id(Main *UNUSED(bmain), Scene *UNUSED(scene), ID *id)
{
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
@@ -349,7 +351,7 @@ static void rna_Curve_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_Curve_update_deps(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
rna_Curve_update_data(bmain, scene, ptr);
}
@@ -638,7 +640,7 @@ static void rna_Curve_spline_remove(Curve *cu, ReportList *reports, PointerRNA *
BKE_nurb_free(nu);
RNA_POINTER_INVALIDATE(nu_ptr);
- DAG_id_tag_update(&cu->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&cu->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
}
@@ -648,7 +650,7 @@ static void rna_Curve_spline_clear(Curve *cu)
BKE_nurbList_free(nurbs);
- DAG_id_tag_update(&cu->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&cu->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
}
@@ -954,19 +956,28 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
PropertyRNA *prop;
static const EnumPropertyItem prop_align_items[] = {
- {CU_ALIGN_X_LEFT, "LEFT", 0, "Left", "Align text to the left"},
- {CU_ALIGN_X_MIDDLE, "CENTER", 0, "Center", "Center text"},
- {CU_ALIGN_X_RIGHT, "RIGHT", 0, "Right", "Align text to the right"},
- {CU_ALIGN_X_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"},
- {CU_ALIGN_X_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"},
+ {CU_ALIGN_X_LEFT, "LEFT", ICON_ALIGN_LEFT, "Left", "Align text to the left"},
+ {CU_ALIGN_X_MIDDLE, "CENTER", ICON_ALIGN_CENTER, "Center", "Center text"},
+ {CU_ALIGN_X_RIGHT, "RIGHT", ICON_ALIGN_RIGHT, "Right", "Align text to the right"},
+ {CU_ALIGN_X_JUSTIFY, "JUSTIFY", ICON_ALIGN_JUSTIFY, "Justify", "Align to the left and the right"},
+ {CU_ALIGN_X_FLUSH, "FLUSH", ICON_ALIGN_FLUSH, "Flush", "Align to the left and the right, with equal character spacing"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem prop_align_y_items[] = {
- {CU_ALIGN_Y_TOP_BASELINE, "TOP_BASELINE", 0, "Top Base-Line", "Align to top but use the base-line of the text"},
- {CU_ALIGN_Y_TOP, "TOP", 0, "Top", "Align text to the top"},
- {CU_ALIGN_Y_CENTER, "CENTER", 0, "Center", "Align text to the middle"},
- {CU_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", "Align text to the bottom"},
+ {CU_ALIGN_Y_TOP_BASELINE, "TOP_BASELINE", ICON_ALIGN_TOP, "Top Base-Line", "Align to top but use the base-line of the text"},
+ {CU_ALIGN_Y_TOP, "TOP", ICON_ALIGN_TOP, "Top", "Align text to the top"},
+ {CU_ALIGN_Y_CENTER, "CENTER", ICON_ALIGN_MIDDLE, "Center", "Align text to the middle"},
+ {CU_ALIGN_Y_BOTTOM, "BOTTOM", ICON_ALIGN_BOTTOM, "Bottom", "Align text to the bottom"},
+ {CU_ALIGN_Y_BOTTOM_BASELINE, "BOTTOM_BASELINE", ICON_ALIGN_BOTTOM, "Bottom Base-Line",
+ "Align text to the bottom but use the base-line of the text"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem prop_overflow_items[] = {
+ {CU_OVERFLOW_NONE, "NONE", 0, "Overflow", "Let the text overflow outside the text boxes"},
+ {CU_OVERFLOW_SCALE, "SCALE", 0, "Scale to Fit", "Scale down the text to fit inside the text boxes"},
+ {CU_OVERFLOW_TRUNCATE, "TRUNCATE", 0, "Truncate", "Truncate the text that would go outside the text boxes"},
{0, NULL, 0, NULL, NULL}
};
@@ -983,6 +994,14 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
RNA_def_property_ui_text(prop, "Text Vertical Align", "Text vertical align from the object center");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
+ prop = RNA_def_property(srna, "overflow", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "overflow");
+ RNA_def_property_enum_items(prop, prop_overflow_items);
+ RNA_def_property_enum_default(prop, CU_OVERFLOW_NONE);
+ RNA_def_property_ui_text(prop, "Textbox Overflow",
+ "Handle the text behaviour when it doesn't fit in the text boxes");
+ RNA_def_property_update(prop, 0, "rna_Curve_update_data");
+
/* number values */
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fsize");
@@ -1175,16 +1194,19 @@ static void rna_def_charinfo(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_bold", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_CHINFO_BOLD);
RNA_def_property_ui_text(prop, "Bold", "");
+ RNA_def_property_ui_icon(prop, ICON_BOLD, 0);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "use_italic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_CHINFO_ITALIC);
RNA_def_property_ui_text(prop, "Italic", "");
+ RNA_def_property_ui_icon(prop, ICON_ITALIC, 0);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "use_underline", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_CHINFO_UNDERLINE);
RNA_def_property_ui_text(prop, "Underline", "");
+ RNA_def_property_ui_icon(prop, ICON_UNDERLINE, 0);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
/* probably there is no reason to expose this */
@@ -1198,6 +1220,7 @@ static void rna_def_charinfo(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_small_caps", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_CHINFO_SMALLCAPS);
RNA_def_property_ui_text(prop, "Small Caps", "");
+ RNA_def_property_ui_icon(prop, ICON_SMALL_CAPS, 0);
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
@@ -1240,7 +1263,7 @@ static void rna_def_curve_spline_points(BlenderRNA *brna, PropertyRNA *cprop)
/*PropertyRNA *prop; */
FunctionRNA *func;
- /*PropertyRNA *parm; */
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "SplinePoints");
srna = RNA_def_struct(brna, "SplinePoints", NULL);
@@ -1250,7 +1273,8 @@ static void rna_def_curve_spline_points(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "add", "rna_Curve_spline_points_add");
RNA_def_function_ui_description(func, "Add a number of points to this spline");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
#if 0
func = RNA_def_function(srna, "remove", "rna_Curve_spline_remove");
@@ -1268,7 +1292,7 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop)
/*PropertyRNA *prop; */
FunctionRNA *func;
- /*PropertyRNA *parm; */
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "SplineBezierPoints");
srna = RNA_def_struct(brna, "SplineBezierPoints", NULL);
@@ -1278,7 +1302,8 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "add", "rna_Curve_spline_bezpoints_add");
RNA_def_function_ui_description(func, "Add a number of points to this spline");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
#if 0
func = RNA_def_function(srna, "remove", "rna_Curve_spline_remove");
@@ -1379,16 +1404,6 @@ static void rna_def_curve(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Splines", "Collection of splines in this curve data object");
rna_def_curve_splines(brna, prop);
- prop = RNA_def_property(srna, "show_handles", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "drawflag", CU_HIDE_HANDLES);
- RNA_def_property_ui_text(prop, "Draw Handles", "Display Bezier handles in editmode");
- RNA_def_property_update(prop, NC_GEOM | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "show_normal_face", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "drawflag", CU_HIDE_NORMALS);
- RNA_def_property_ui_text(prop, "Draw Normals", "Display 3D curve normals in editmode");
- RNA_def_property_update(prop, NC_GEOM | ND_DATA, NULL);
-
rna_def_path(brna, srna);
/* Number values */
diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c
index d83a843c5c1..4e870d64f1c 100644
--- a/source/blender/makesrna/intern/rna_curve_api.c
+++ b/source/blender/makesrna/intern/rna_curve_api.c
@@ -47,8 +47,14 @@ static void rna_Curve_transform(Curve *cu, float *mat, bool shape_keys)
{
BKE_curve_transform(cu, (float (*)[4])mat, shape_keys, true);
- DAG_id_tag_update(&cu->id, 0);
+ DEG_id_tag_update(&cu->id, 0);
}
+
+static void rna_Curve_update_gpu_tag(Curve *cu)
+{
+ BKE_curve_batch_cache_dirty_tag(cu, BKE_CURVE_BATCH_DIRTY_ALL);
+}
+
static float rna_Nurb_calc_length(Nurb *nu, int resolution_u)
{
return BKE_nurb_calc_length(nu, resolution_u);
@@ -72,6 +78,8 @@ void RNA_api_curve(StructRNA *srna)
"has had invalid indices corrected (to default 0)");
parm = RNA_def_boolean(func, "result", 0, "Result", "");
RNA_def_function_return(func, parm);
+
+ RNA_def_function(srna, "update_gpu_tag", "rna_Curve_update_gpu_tag");
}
void RNA_api_curve_nurb(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index d004491a33b..2a9b1aac56e 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -1165,7 +1165,8 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
case PROP_STRING:
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
-
+ /* By default don't allow NULL string args, callers may clear. */
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
sprop->defaultvalue = "";
break;
}
@@ -1270,6 +1271,14 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
#endif
}
+ /* Override handling. */
+ if (DefRNA.preprocess) {
+ prop->override_diff = (RNAPropOverrideDiff)"rna_property_override_diff_default";
+ prop->override_store = (RNAPropOverrideStore)"rna_property_override_store_default";
+ prop->override_apply = (RNAPropOverrideApply)"rna_property_override_apply_default";
+ }
+ /* TODO: do we want that for runtime-defined stuff too? I’d say no, but... maybe yes :/ */
+
rna_addtail(&cont->properties, prop);
return prop;
@@ -1285,6 +1294,16 @@ void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
prop->flag &= ~flag;
}
+void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag)
+{
+ prop->flag_override |= flag;
+}
+
+void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag)
+{
+ prop->flag_override &= ~flag;
+}
+
/**
* Add the property-tags passed as \a tags to \a prop (if valid).
*
@@ -1408,11 +1427,13 @@ void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *d
prop->description = description;
}
-void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, bool consecutive)
+void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, int consecutive)
{
prop->icon = icon;
- if (consecutive)
+ if (consecutive != 0)
prop->flag |= PROP_ICONS_CONSECUTIVE;
+ if (consecutive < 0)
+ prop->flag |= PROP_ICONS_REVERSE;
}
/**
@@ -1860,7 +1881,7 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop, const char *stru
return dp;
}
else {
- fprintf(stderr, "%s: \"%s.%s\" (identifier \"%s\") not found.\n",
+ fprintf(stderr, "%s: \"%s.%s\" (identifier \"%s\") not found. Struct must be in DNA.\n",
__func__, structname, propname, prop->identifier);
DefRNA.error = 1;
return NULL;
@@ -2222,6 +2243,29 @@ void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editabl
if (editable) prop->itemeditable = (ItemEditableFunc)editable;
}
+/**
+ * Set custom callbacks for override operations handling.
+ *
+ * \note \a diff callback will also be used by RNA comparison/equality functions.
+ */
+void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply)
+{
+ if (!DefRNA.preprocess) {
+ fprintf(stderr, "%s: only during preprocessing.\n", __func__);
+ return;
+ }
+
+ if (diff) {
+ prop->override_diff = (RNAPropOverrideDiff)diff;
+ }
+ if (store) {
+ prop->override_store = (RNAPropOverrideStore)store;
+ }
+ if (apply) {
+ prop->override_apply = (RNAPropOverrideApply)apply;
+ }
+}
+
void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *func)
{
if (!DefRNA.preprocess) {
@@ -2241,7 +2285,7 @@ void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func)
void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func)
{
if (prop->type == PROP_POINTER) {
- ((PointerPropertyRNA *)prop)->poll = func;
+ ((PointerPropertyRNA *)prop)->poll = (void *)func;
}
else {
fprintf(stderr, "%s: %s is not a Pointer Property.\n", __func__, prop->identifier);
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index c6b18d8d387..4c455915361 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -34,16 +34,173 @@
#include "rna_internal.h"
-#include "DEG_depsgraph.h"
+#include "DNA_object_types.h"
-#include "BKE_depsgraph.h"
+#include "DEG_depsgraph.h"
#define STATS_MAX_SIZE 16384
#ifdef RNA_RUNTIME
+#include "BLI_iterator.h"
+#include "BLI_math.h"
+
+#include "BKE_anim.h"
+
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
+
+/* **************** Object Instance **************** */
+
+static PointerRNA rna_DepsgraphObjectInstance_object_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, iterator->current);
+}
+
+static int rna_DepsgraphObjectInstance_is_instance_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ return (deg_iter->dupli_object_current != NULL);
+}
+
+static PointerRNA rna_DepsgraphObjectInstance_instance_object_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ Object *instance_object = NULL;
+ if (deg_iter->dupli_object_current != NULL) {
+ instance_object = deg_iter->dupli_object_current->ob;
+ }
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, instance_object);
+}
+
+static PointerRNA rna_DepsgraphObjectInstance_parent_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ Object *dupli_parent = NULL;
+ if (deg_iter->dupli_object_current != NULL) {
+ dupli_parent = deg_iter->dupli_parent;
+ }
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, dupli_parent);
+}
+
+static PointerRNA rna_DepsgraphObjectInstance_particle_system_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ struct ParticleSystem *particle_system = NULL;
+ if (deg_iter->dupli_object_current != NULL) {
+ particle_system = deg_iter->dupli_object_current->particle_system;
+ }
+ return rna_pointer_inherit_refine(ptr, &RNA_ParticleSystem, particle_system);
+}
+
+static void rna_DepsgraphObjectInstance_persistent_id_get(PointerRNA *ptr, int *persistent_id)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ if (deg_iter->dupli_object_current != NULL) {
+ memcpy(persistent_id, deg_iter->dupli_object_current->persistent_id,
+ sizeof(deg_iter->dupli_object_current->persistent_id));
+ }
+ else {
+ memset(persistent_id, 0, sizeof(deg_iter->dupli_object_current->persistent_id));
+ }
+}
+
+static unsigned int rna_DepsgraphObjectInstance_random_id_get(PointerRNA *ptr)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ if (deg_iter->dupli_object_current != NULL) {
+ return deg_iter->dupli_object_current->random_id;
+ }
+ else {
+ return 0;
+ }
+}
+
+static void rna_DepsgraphObjectInstance_matrix_world_get(PointerRNA *ptr, float *mat)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ if (deg_iter->dupli_object_current != NULL) {
+ copy_m4_m4((float(*)[4])mat, deg_iter->dupli_object_current->mat);
+ }
+ else {
+ unit_m4((float(*)[4])mat);
+ }
+}
+
+static void rna_DepsgraphObjectInstance_orco_get(PointerRNA *ptr, float *orco)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ if (deg_iter->dupli_object_current != NULL) {
+ copy_v3_v3(orco, deg_iter->dupli_object_current->orco);
+ }
+ else {
+ zero_v3(orco);
+ }
+}
+
+static void rna_DepsgraphObjectInstance_uv_get(PointerRNA *ptr, float *uv)
+{
+ BLI_Iterator *iterator = ptr->data;
+ DEGObjectIterData *deg_iter = (DEGObjectIterData *)iterator->data;
+ if (deg_iter->dupli_object_current != NULL) {
+ copy_v2_v2(uv, deg_iter->dupli_object_current->uv);
+ }
+ else {
+ zero_v2(uv);
+ }
+}
+
+/* ******************** Sorted ***************** */
+
+static int rna_Depsgraph_mode_get(PointerRNA *ptr)
+{
+ Depsgraph *depsgraph = ptr->data;
+ return DEG_get_mode(depsgraph);
+}
+
+/* ******************** Updates ***************** */
+
+static PointerRNA rna_DepsgraphUpdate_id_get(PointerRNA *ptr)
+{
+ return rna_pointer_inherit_refine(ptr, &RNA_ID, ptr->data);
+}
+
+static bool rna_DepsgraphUpdate_is_dirty_transform_get(PointerRNA *ptr)
+{
+ ID *id = ptr->data;
+ return ((id->recalc & ID_RECALC_TRANSFORM) == 0);
+}
+
+static bool rna_DepsgraphUpdate_is_dirty_geometry_get(PointerRNA *ptr)
+{
+ ID *id = ptr->data;
+ if (id->recalc & ID_RECALC_GEOMETRY) {
+ return false;
+ }
+ if (GS(id->name) != ID_OB) {
+ return true;
+ }
+ Object *object = (Object *)id;
+ ID *data = object->data;
+ if (data == NULL) {
+ return true;
+ }
+ return ((data->recalc & ID_RECALC_ALL) == 0);
+}
+
+/* **************** Depsgraph **************** */
static void rna_Depsgraph_debug_relations_graphviz(Depsgraph *depsgraph,
const char *filename)
@@ -79,20 +236,316 @@ static void rna_Depsgraph_debug_stats(Depsgraph *depsgraph, char *result)
DEG_stats_simple(depsgraph, &outer, &ops, &rels);
BLI_snprintf(result, STATS_MAX_SIZE,
"Approx %lu Operations, %lu Relations, %lu Outer Nodes",
- ops, rels, outer);
+ ops, rels, outer);
+}
+
+/* Iteration over objects, simple version */
+
+static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
+ DEGObjectIterData *data = MEM_callocN(sizeof(DEGObjectIterData), __func__);
+
+ data->graph = (Depsgraph *)ptr->data;
+ data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
+
+ ((BLI_Iterator *)iter->internal.custom)->valid = true;
+ DEG_iterator_objects_begin(iter->internal.custom, data);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static void rna_Depsgraph_objects_next(CollectionPropertyIterator *iter)
+{
+ DEG_iterator_objects_next(iter->internal.custom);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static void rna_Depsgraph_objects_end(CollectionPropertyIterator *iter)
+{
+ DEG_iterator_objects_end(iter->internal.custom);
+ MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data);
+ MEM_freeN(iter->internal.custom);
+}
+
+static PointerRNA rna_Depsgraph_objects_get(CollectionPropertyIterator *iter)
+{
+ Object *ob = ((BLI_Iterator *)iter->internal.custom)->current;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ob);
+}
+
+/* Iteration over objects, extended version
+ *
+ * Contains extra information about duplicator and persistent ID.
+ */
+
+/* XXX Ugly python seems to query next item of an iterator before using current one (see T57558).
+ * This forces us to use that nasty ping-pong game between two sets of iterator data, so that previous one remains
+ * valid memory for python to access to. Yuck.
+ */
+typedef struct RNA_Depsgraph_Instances_Iterator
+{
+ BLI_Iterator iterators[2];
+ DEGObjectIterData deg_data[2];
+ int counter;
+} RNA_Depsgraph_Instances_Iterator;
+
+static void rna_Depsgraph_object_instances_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ RNA_Depsgraph_Instances_Iterator *di_it = iter->internal.custom = MEM_callocN(sizeof(*di_it), __func__);
+
+ DEGObjectIterData *data = &di_it->deg_data[0];
+ data->graph = (Depsgraph *)ptr->data;
+ data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI;
+
+ di_it->iterators[0].valid = true;
+ DEG_iterator_objects_begin(&di_it->iterators[0], data);
+ iter->valid = di_it->iterators[0].valid;
+}
+
+static void rna_Depsgraph_object_instances_next(CollectionPropertyIterator *iter)
+{
+ RNA_Depsgraph_Instances_Iterator *di_it = (RNA_Depsgraph_Instances_Iterator *)iter->internal.custom;
+
+ /* We need to copy current iterator status to next one beeing worked on. */
+ di_it->iterators[(di_it->counter + 1) % 2] = di_it->iterators[di_it->counter % 2];
+ di_it->deg_data[(di_it->counter + 1) % 2] = di_it->deg_data[di_it->counter % 2];
+ di_it->counter++;
+
+ di_it->iterators[di_it->counter % 2].data = &di_it->deg_data[di_it->counter % 2];
+ DEG_iterator_objects_next(&di_it->iterators[di_it->counter % 2]);
+ iter->valid = di_it->iterators[di_it->counter % 2].valid;
+}
+
+static void rna_Depsgraph_object_instances_end(CollectionPropertyIterator *iter)
+{
+ RNA_Depsgraph_Instances_Iterator *di_it = (RNA_Depsgraph_Instances_Iterator *)iter->internal.custom;
+ DEG_iterator_objects_end(&di_it->iterators[0]);
+ DEG_iterator_objects_end(&di_it->iterators[1]);
+ MEM_freeN(di_it);
+}
+
+static PointerRNA rna_Depsgraph_object_instances_get(CollectionPropertyIterator *iter)
+{
+ RNA_Depsgraph_Instances_Iterator *di_it = (RNA_Depsgraph_Instances_Iterator *)iter->internal.custom;
+ BLI_Iterator *iterator = &di_it->iterators[di_it->counter % 2];
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_DepsgraphObjectInstance, iterator);
+}
+
+/* Iteration over evaluated IDs */
+
+static void rna_Depsgraph_ids_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
+ DEGIDIterData *data = MEM_callocN(sizeof(DEGIDIterData), __func__);
+
+ data->graph = (Depsgraph *)ptr->data;
+
+ ((BLI_Iterator *)iter->internal.custom)->valid = true;
+ DEG_iterator_ids_begin(iter->internal.custom, data);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static void rna_Depsgraph_ids_next(CollectionPropertyIterator *iter)
+{
+ DEG_iterator_ids_next(iter->internal.custom);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static void rna_Depsgraph_ids_end(CollectionPropertyIterator *iter)
+{
+ DEG_iterator_ids_end(iter->internal.custom);
+ MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data);
+ MEM_freeN(iter->internal.custom);
+}
+
+static PointerRNA rna_Depsgraph_ids_get(CollectionPropertyIterator *iter)
+{
+ ID *id = ((BLI_Iterator *)iter->internal.custom)->current;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_ID, id);
+}
+
+static void rna_Depsgraph_updates_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
+ DEGIDIterData *data = MEM_callocN(sizeof(DEGIDIterData), __func__);
+
+ data->graph = (Depsgraph *)ptr->data;
+ data->only_updated = true;
+
+ ((BLI_Iterator *)iter->internal.custom)->valid = true;
+ DEG_iterator_ids_begin(iter->internal.custom, data);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
+}
+
+static PointerRNA rna_Depsgraph_updates_get(CollectionPropertyIterator *iter)
+{
+ ID *id = ((BLI_Iterator *)iter->internal.custom)->current;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_DepsgraphUpdate, id);
+}
+
+static ID *rna_Depsgraph_id_eval_get(Depsgraph *depsgraph, ID *id_orig)
+{
+ return DEG_get_evaluated_id(depsgraph, id_orig);
+}
+
+static bool rna_Depsgraph_id_type_updated(Depsgraph *depsgraph, int id_type)
+{
+ return DEG_id_type_updated(depsgraph, id_type);
+}
+
+static PointerRNA rna_Depsgraph_scene_get(PointerRNA *ptr)
+{
+ Depsgraph *depsgraph = (Depsgraph *)ptr->data;
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ return rna_pointer_inherit_refine(ptr, &RNA_Scene, scene);
+}
+
+static PointerRNA rna_Depsgraph_view_layer_get(PointerRNA *ptr)
+{
+ Depsgraph *depsgraph = (Depsgraph *)ptr->data;
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, view_layer);
+}
+
+static PointerRNA rna_Depsgraph_scene_eval_get(PointerRNA *ptr)
+{
+ Depsgraph *depsgraph = (Depsgraph *)ptr->data;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ return rna_pointer_inherit_refine(ptr, &RNA_Scene, scene_eval);
+}
+
+static PointerRNA rna_Depsgraph_view_layer_eval_get(PointerRNA *ptr)
+{
+ Depsgraph *depsgraph = (Depsgraph *)ptr->data;
+ ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
+ return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, view_layer_eval);
}
#else
+static void rna_def_depsgraph_instance(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "DepsgraphObjectInstance", NULL);
+ RNA_def_struct_ui_text(srna, "Dependency Graph Object Instance",
+ "Extended information about dependency graph object iterator "
+ "(WARNING: all data here is *evaluated* one, not original .blend IDs...)");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "Object", "Evaluated object the iterator points to");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_DepsgraphObjectInstance_object_get", NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "is_instance", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Instance", "Denotes whether the object is coming from dupli-list");
+ RNA_def_property_boolean_funcs(prop, "rna_DepsgraphObjectInstance_is_instance_get", NULL);
+
+ prop = RNA_def_property(srna, "instance_object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "Instance Object", "Evaluated object which is being instanced by this iterator");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_DepsgraphObjectInstance_instance_object_get", NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "Parent", "Evaluated parent object of the duplication list");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_DepsgraphObjectInstance_parent_get", NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ParticleSystem");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Particle System", "Evaluated particle system that this object was instanced from");
+ RNA_def_property_pointer_funcs(prop, "rna_DepsgraphObjectInstance_particle_system_get", NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "persistent_id", PROP_INT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Persistent ID",
+ "Persistent identifier for inter-frame matching of objects with motion blur");
+ RNA_def_property_array(prop, 2 * MAX_DUPLI_RECUR);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_int_funcs(prop, "rna_DepsgraphObjectInstance_persistent_id_get", NULL, NULL);
+
+ prop = RNA_def_property(srna, "random_id", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Dupli random id", "Random id for this dupli object");
+ RNA_def_property_int_funcs(prop, "rna_DepsgraphObjectInstance_random_id_get", NULL, NULL);
+
+ prop = RNA_def_property(srna, "matrix_world", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Generated Matrix", "Generated transform matrix in world space");
+ RNA_def_property_float_funcs(prop, "rna_DepsgraphObjectInstance_matrix_world_get", NULL, NULL);
+
+ prop = RNA_def_property(srna, "orco", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Generated Coordinates", "Generated coordinates in parent object space");
+ RNA_def_property_float_funcs(prop, "rna_DepsgraphObjectInstance_orco_get", NULL, NULL);
+
+ prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "UV Coordinates", "UV coordinates in parent object space");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_DepsgraphObjectInstance_uv_get", NULL, NULL);
+}
+
+static void rna_def_depsgraph_update(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "DepsgraphUpdate", NULL);
+ RNA_def_struct_ui_text(srna, "Dependency Graph Update",
+ "Information about ID that was updated");
+
+ prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ID");
+ RNA_def_property_ui_text(prop, "ID", "Updated datablock");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_DepsgraphUpdate_id_get", NULL, NULL, NULL);
+
+ prop = RNA_def_property(srna, "is_dirty_transform", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Transform", "Object transformation is not updated");
+ RNA_def_property_boolean_funcs(prop, "rna_DepsgraphUpdate_is_dirty_transform_get", NULL);
+
+ prop = RNA_def_property(srna, "is_dirty_geometry", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Geometry", "Object geometry is not updated");
+ RNA_def_property_boolean_funcs(prop, "rna_DepsgraphUpdate_is_dirty_geometry_get", NULL);
+}
+
static void rna_def_depsgraph(BlenderRNA *brna)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem enum_depsgraph_mode_items[] = {
+ {DAG_EVAL_VIEWPORT, "VIEWPORT", 0, "Viewport", "Viewport non-rendered mode"},
+ {DAG_EVAL_RENDER, "RENDER", 0, "Render", "Render"},
+ {0, NULL, 0, NULL, NULL}
+ };
srna = RNA_def_struct(brna, "Depsgraph", NULL);
RNA_def_struct_ui_text(srna, "Dependency Graph", "");
+ prop = RNA_def_enum(srna, "mode", enum_depsgraph_mode_items, 0, "Mode", "Evaluation mode");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_funcs(prop, "rna_Depsgraph_mode_get", NULL, NULL);
+
+ /* Debug helpers. */
+
func = RNA_def_function(srna, "debug_relations_graphviz", "rna_Depsgraph_debug_relations_graphviz");
parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name",
"File in which to store graphviz debug output");
@@ -114,10 +567,94 @@ static void rna_def_depsgraph(BlenderRNA *brna)
parm = RNA_def_string(func, "result", NULL, STATS_MAX_SIZE, "result", "");
RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
+
+ /* Queries for original datablockls (the ones depsgraph is built for). */
+
+ prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Scene");
+ RNA_def_property_pointer_funcs(prop, "rna_Depsgraph_scene_get", NULL, NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Scene", "Original scene dependency graph is built for");
+
+ prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ViewLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Depsgraph_view_layer_get", NULL, NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "View Layer", "Original view layer dependency graph is built for");
+
+ /* Queries for evaluated datablockls (the ones depsgraph is evaluating). */
+
+ func = RNA_def_function(srna, "id_eval_get", "rna_Depsgraph_id_eval_get");
+ parm = RNA_def_pointer(func, "id", "ID", "", "Original ID to get evaluated complementary part for");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "id_eval", "ID", "", "Evaluated ID for the given original one");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "id_type_updated", "rna_Depsgraph_id_type_updated");
+ parm = RNA_def_enum(func, "id_type", rna_enum_id_type_items, 0, "ID Type", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "updated", false, "Updated", "True if any datablock with this type was added, updated or removed");
+ RNA_def_function_return(func, parm);
+
+ prop = RNA_def_property(srna, "scene_eval", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Scene");
+ RNA_def_property_pointer_funcs(prop, "rna_Depsgraph_scene_eval_get", NULL, NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Scene", "Original scene dependency graph is built for");
+
+ prop = RNA_def_property(srna, "view_layer_eval", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ViewLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Depsgraph_view_layer_eval_get", NULL, NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "View Layer", "Original view layer dependency graph is built for");
+
+ /* Iterators. */
+
+ prop = RNA_def_property(srna, "ids", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ID");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Depsgraph_ids_begin",
+ "rna_Depsgraph_ids_next",
+ "rna_Depsgraph_ids_end",
+ "rna_Depsgraph_ids_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "IDs", "All evaluated datablocks");
+
+ prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Depsgraph_objects_begin",
+ "rna_Depsgraph_objects_next",
+ "rna_Depsgraph_objects_end",
+ "rna_Depsgraph_objects_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Objects", "Evaluated objects in the dependency graph");
+
+ prop = RNA_def_property(srna, "object_instances", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "DepsgraphObjectInstance");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Depsgraph_object_instances_begin",
+ "rna_Depsgraph_object_instances_next",
+ "rna_Depsgraph_object_instances_end",
+ "rna_Depsgraph_object_instances_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Object Instances", "All object instances to display or render");
+
+ prop = RNA_def_property(srna, "updates", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "DepsgraphUpdate");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Depsgraph_updates_begin",
+ "rna_Depsgraph_ids_next",
+ "rna_Depsgraph_ids_end",
+ "rna_Depsgraph_updates_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Updates", "Updates to datablocks");
}
void RNA_def_depsgraph(BlenderRNA *brna)
{
+ rna_def_depsgraph_instance(brna);
+ rna_def_depsgraph_update(brna);
rna_def_depsgraph(brna);
}
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 42f8e2ae787..11247fa6797 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -55,9 +55,10 @@ const EnumPropertyItem rna_enum_prop_dynamicpaint_type_items[] = {
#ifdef RNA_RUNTIME
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_particle.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
static char *rna_DynamicPaintCanvasSettings_path(PointerRNA *ptr)
{
@@ -98,7 +99,7 @@ static char *rna_DynamicPaintSurface_path(PointerRNA *ptr)
static void rna_DynamicPaint_redoModifier(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
static void rna_DynamicPaintSurfaces_updateFrames(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -160,7 +161,7 @@ static void rna_DynamicPaintSurfaces_changeFormat(Main *bmain, Scene *scene, Poi
static void rna_DynamicPaint_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_DynamicPaintSurface_reset(bmain, scene, ptr);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
static PointerRNA rna_PaintSurface_active_get(PointerRNA *ptr)
@@ -423,10 +424,11 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT, "rna_DynamicPaintSurface_uniqueName");
RNA_def_struct_name_property(srna, prop);
- prop = RNA_def_property(srna, "brush_group", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Group");
+ prop = RNA_def_property(srna, "brush_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_pointer_sdna(prop, NULL, "brush_group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Brush Group", "Only use brush objects from this group");
+ RNA_def_property_ui_text(prop, "Brush Collection", "Only use brush objects from this collection");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_DynamicPaint_reset_dependency");
@@ -774,8 +776,8 @@ static void rna_def_dynamic_paint_brush_settings(BlenderRNA *brna)
/* paint collision type */
static const EnumPropertyItem prop_dynamicpaint_collisiontype[] = {
{MOD_DPAINT_COL_PSYS, "PARTICLE_SYSTEM", ICON_PARTICLES, "Particle System", ""},
- {MOD_DPAINT_COL_POINT, "POINT", ICON_META_EMPTY, "Object Center", ""},
- {MOD_DPAINT_COL_DIST, "DISTANCE", ICON_META_EMPTY, "Proximity", ""},
+ {MOD_DPAINT_COL_POINT, "POINT", ICON_EMPTY_AXIS, "Object Center", ""},
+ {MOD_DPAINT_COL_DIST, "DISTANCE", ICON_DRIVER_DISTANCE, "Proximity", ""},
{MOD_DPAINT_COL_VOLDIST, "VOLUME_DISTANCE", ICON_META_CUBE, "Mesh Volume + Proximity", ""},
{MOD_DPAINT_COL_VOLUME, "VOLUME", ICON_MESH_CUBE, "Mesh Volume", ""},
{0, NULL, 0, NULL, NULL}
@@ -824,18 +826,6 @@ static void rna_def_dynamic_paint_brush_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Paint Alpha", "Paint alpha");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_DynamicPaint_redoModifier");
- prop = RNA_def_property(srna, "use_material", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_USE_MATERIAL);
- RNA_def_property_ui_text(prop, "Use object material", "Use object material to define color and influence");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_DynamicPaint_redoModifier");
-
- prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "mat");
- RNA_def_property_ui_text(prop, "Material",
- "Material to use (if not defined, material linked to the mesh is used)");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_DynamicPaint_redoModifier");
-
prop = RNA_def_property(srna, "use_absolute_alpha", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_ABS_ALPHA);
RNA_def_property_ui_text(prop, "Absolute Alpha",
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 92f6bb16340..ef573079116 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -72,11 +72,11 @@ const EnumPropertyItem rna_enum_fmodifier_type_items[] = {
};
const EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = {
- {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", VICO_KEYTYPE_KEYFRAME_VEC, "Keyframe", "Normal keyframe - e.g. for key poses"},
- {BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", VICO_KEYTYPE_BREAKDOWN_VEC, "Breakdown", "A breakdown pose - e.g. for transitions between key poses"},
- {BEZT_KEYTYPE_MOVEHOLD, "MOVING_HOLD", VICO_KEYTYPE_MOVING_HOLD_VEC, "Moving Hold", "A keyframe that is part of a moving hold"},
- {BEZT_KEYTYPE_EXTREME, "EXTREME", VICO_KEYTYPE_EXTREME_VEC, "Extreme", "An 'extreme' pose, or some other purpose as needed"},
- {BEZT_KEYTYPE_JITTER, "JITTER", VICO_KEYTYPE_JITTER_VEC, "Jitter", "A filler or baked keyframe for keying on ones, or some other purpose as needed"},
+ {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", ICON_KEYTYPE_KEYFRAME_VEC, "Keyframe", "Normal keyframe - e.g. for key poses"},
+ {BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", ICON_KEYTYPE_BREAKDOWN_VEC, "Breakdown", "A breakdown pose - e.g. for transitions between key poses"},
+ {BEZT_KEYTYPE_MOVEHOLD, "MOVING_HOLD", ICON_KEYTYPE_MOVING_HOLD_VEC, "Moving Hold", "A keyframe that is part of a moving hold"},
+ {BEZT_KEYTYPE_EXTREME, "EXTREME", ICON_KEYTYPE_EXTREME_VEC, "Extreme", "An 'extreme' pose, or some other purpose as needed"},
+ {BEZT_KEYTYPE_JITTER, "JITTER", ICON_KEYTYPE_JITTER_VEC, "Jitter", "A filler or baked keyframe for keying on ones, or some other purpose as needed"},
{0, NULL, 0, NULL, NULL}
};
@@ -129,9 +129,18 @@ static StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr)
/* ****************************** */
#include "BKE_fcurve.h"
-#include "BKE_depsgraph.h"
#include "BKE_animsys.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static bool rna_ChannelDriver_is_simple_expression_get(PointerRNA *ptr)
+{
+ ChannelDriver *driver = ptr->data;
+
+ return BKE_driver_has_simple_expression(driver);
+}
+
static void rna_ChannelDriver_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ID *id = ptr->id.data;
@@ -140,8 +149,8 @@ static void rna_ChannelDriver_update_data(Main *bmain, Scene *scene, PointerRNA
driver->flag &= ~DRIVER_FLAG_INVALID;
/* TODO: this really needs an update guard... */
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA);
WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
}
@@ -151,7 +160,7 @@ static void rna_ChannelDriver_update_expr(Main *bmain, Scene *scene, PointerRNA
ChannelDriver *driver = ptr->data;
/* tag driver as needing to be recompiled */
- driver->flag |= DRIVER_FLAG_RECOMPILE;
+ BKE_driver_invalidate_expression(driver, true, false);
/* update_data() clears invalid flag and schedules for updates */
rna_ChannelDriver_update_data(bmain, scene, ptr);
@@ -184,8 +193,7 @@ static void rna_DriverTarget_update_name(Main *bmain, Scene *scene, PointerRNA *
ChannelDriver *driver = ptr->data;
rna_DriverTarget_update_data(bmain, scene, ptr);
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
-
+ BKE_driver_invalidate_expression(driver, false, true);
}
/* ----------- */
@@ -481,6 +489,18 @@ static void rna_FCurve_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
rna_FCurve_update_data_ex((FCurve *)ptr->data);
}
+/* RNA update callback for F-Curves to indicate that there are copy-on-write tagging/flushing needed
+ * (e.g. for properties that affect how animation gets evaluated)
+ */
+static void rna_FCurve_update_eval(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ IdAdtTemplate *iat = (IdAdtTemplate *)ptr->id.data;
+ if (iat && iat->adt && iat->adt->action) {
+ /* action is separate datablock, needs separate tag */
+ DEG_id_tag_update(&iat->adt->action->id, DEG_TAG_COPY_ON_WRITE);
+ }
+}
+
static PointerRNA rna_FCurve_active_modifier_get(PointerRNA *ptr)
{
@@ -590,10 +610,22 @@ static void rna_FModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
ID *id = ptr->id.data;
FModifier *fcm = (FModifier *)ptr->data;
AnimData *adt = BKE_animdata_from_id(id);
- DAG_id_tag_update(id, (GS(id->name) == ID_OB) ? OB_RECALC_OB : OB_RECALC_DATA);
+
+ DEG_id_tag_update(id, (GS(id->name) == ID_OB) ? OB_RECALC_OB : OB_RECALC_DATA);
+
+ /* tag datablock for time update so that animation is recalculated,
+ * as FModifiers affect how animation plays...
+ */
+ DEG_id_tag_update(id, DEG_TAG_TIME);
if (adt != NULL) {
adt->recalc |= ADT_RECALC_ANIM;
+
+ if (adt->action != NULL) {
+ /* action is separate datablock, needs separate tag */
+ DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
+ }
}
+
if (fcm->curve && fcm->type == FMODIFIER_TYPE_CYCLES) {
calchandles_fcurve(fcm->curve);
}
@@ -1363,13 +1395,13 @@ static void rna_def_fmodifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_EXPANDED);
RNA_def_property_ui_text(prop, "Expanded", "F-Curve Modifier's panel is expanded in UI");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_MUTED);
RNA_def_property_ui_text(prop, "Muted", "F-Curve Modifier will not be evaluated");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
- RNA_def_property_ui_icon(prop, ICON_MUTE_IPO_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_CHECKBOX_DEHLT, 1);
prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1392,7 +1424,7 @@ static void rna_def_fmodifier(BlenderRNA *brna)
"F-Curve Modifier is only applied for the specified frame range to help "
"mask off effects in order to chain them");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); /* XXX: depends on UI implementation */
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); /* XXX: depends on UI implementation */
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sfra");
@@ -1425,7 +1457,7 @@ static void rna_def_fmodifier(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_USEINFLUENCE);
RNA_def_property_ui_text(prop, "Use Influence", "F-Curve Modifier's effects will be tempered by a default factor");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, "rna_FModifier_update");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); /* XXX: depends on UI implementation */
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); /* XXX: depends on UI implementation */
prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "influence");
@@ -1473,6 +1505,7 @@ static void rna_def_drivertarget(BlenderRNA *brna)
prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_func(prop, "rna_DriverTarget_id_editable");
/* note: custom set function is ONLY to avoid rna setting a user for this. */
RNA_def_property_pointer_funcs(prop, NULL, "rna_DriverTarget_id_set", "rna_DriverTarget_id_typef", NULL);
@@ -1523,10 +1556,10 @@ static void rna_def_drivervar(BlenderRNA *brna)
static const EnumPropertyItem prop_type_items[] = {
{DVAR_TYPE_SINGLE_PROP, "SINGLE_PROP", ICON_RNA, "Single Property", "Use the value from some RNA property (Default)"},
- {DVAR_TYPE_TRANSFORM_CHAN, "TRANSFORMS", ICON_MANIPUL, "Transform Channel",
+ {DVAR_TYPE_TRANSFORM_CHAN, "TRANSFORMS", ICON_DRIVER_TRANSFORM, "Transform Channel",
"Final transformation value of object or bone"},
- {DVAR_TYPE_ROT_DIFF, "ROTATION_DIFF", ICON_PARTICLE_TIP, "Rotational Difference", "Use the angle between two bones"}, /* XXX: Icon... */
- {DVAR_TYPE_LOC_DIFF, "LOC_DIFF", ICON_FULLSCREEN_ENTER, "Distance", "Distance between two bones or objects"}, /* XXX: Icon... */
+ {DVAR_TYPE_ROT_DIFF, "ROTATION_DIFF", ICON_DRIVER_ROTATIONAL_DIFFERENCE, "Rotational Difference", "Use the angle between two bones"},
+ {DVAR_TYPE_LOC_DIFF, "LOC_DIFF", ICON_DRIVER_DISTANCE, "Distance", "Distance between two bones or objects"},
{0, NULL, 0, NULL, NULL}
};
@@ -1557,6 +1590,7 @@ static void rna_def_drivervar(BlenderRNA *brna)
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "targets", "num_targets");
RNA_def_property_struct_type(prop, "DriverTarget");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Targets", "Sources of input data for evaluating this variable");
/* Name Validity Flags */
@@ -1633,15 +1667,11 @@ static void rna_def_channeldriver(BlenderRNA *brna)
prop = RNA_def_property(srna, "variables", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "variables", NULL);
RNA_def_property_struct_type(prop, "DriverVariable");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Variables", "Properties acting as inputs for this driver");
rna_def_channeldriver_variables(brna, prop);
/* Settings */
- prop = RNA_def_property(srna, "show_debug_info", PROP_BOOLEAN, PROP_NONE);
- 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",
@@ -1653,6 +1683,10 @@ static void rna_def_channeldriver(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", DRIVER_FLAG_INVALID);
RNA_def_property_ui_text(prop, "Invalid", "Driver could not be evaluated in past, so should be skipped");
+ prop = RNA_def_property(srna, "is_simple_expression", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_ChannelDriver_is_simple_expression_get", NULL);
+ RNA_def_property_ui_text(prop, "Simple Expression", "The scripted expression can be evaluated without using the full python interpreter");
/* Functions */
RNA_api_drivers(srna);
@@ -1862,7 +1896,8 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "add", "rna_FKeyframe_points_add");
RNA_def_function_ui_description(func, "Add a keyframe point to a F-Curve");
- RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_FKeyframe_points_remove");
RNA_def_function_ui_description(func, "Remove keyframe from an F-Curve");
@@ -1917,6 +1952,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
/* Pointers */
prop = RNA_def_property(srna, "driver", PROP_POINTER, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Driver", "Channel Driver (only set for Driver F-Curves)");
@@ -1968,7 +2004,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCURVE_MUTED);
RNA_def_property_ui_text(prop, "Muted", "F-Curve is not evaluated");
- RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, "rna_FCurve_update_eval");
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", FCURVE_VISIBLE);
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 54d89ec81ab..23d9155fccd 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -46,7 +46,6 @@
#include "DNA_scene_types.h"
#include "DNA_particle_types.h"
-#include "BKE_depsgraph.h"
#include "BKE_fluidsim.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -54,6 +53,8 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
+#include "DEG_depsgraph.h"
+
static StructRNA *rna_FluidSettings_refine(struct PointerRNA *ptr)
{
FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
@@ -82,7 +83,7 @@ static void rna_fluid_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
{
Object *ob = ptr->id.data;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 625ef7db2dc..0006a8859bf 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -26,8 +26,13 @@
#include <stdlib.h>
+#include "BLI_math.h"
+
+#include "DNA_meshdata_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
#include "MEM_guardedalloc.h"
@@ -38,12 +43,11 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "rna_internal.h"
#include "WM_types.h"
-#include "DNA_object_types.h"
-#include "ED_gpencil.h"
/* parent type */
static const EnumPropertyItem parent_type_items[] = {
@@ -53,31 +57,101 @@ static const EnumPropertyItem parent_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#ifndef RNA_RUNTIME
+static EnumPropertyItem rna_enum_gpencil_xraymodes_items[] = {
+ {GP_XRAY_FRONT, "FRONT", 0, "Front", "Draw all strokes in front"},
+ {GP_XRAY_3DSPACE, "3DSPACE", 0, "3D Space", "Draw strokes relative to other objects in 3D space"},
+ {GP_XRAY_BACK, "BACK", 0, "Back", "Draw all strokes last"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem rna_enum_gpencil_onion_modes_items[] = {
+ {GP_ONION_MODE_ABSOLUTE, "ABSOLUTE", 0, "Frames", "Frames in absolute range of the scene frame"},
+ {GP_ONION_MODE_RELATIVE, "RELATIVE", 0, "Keyframes", "Frames in relative range of the Grease Pencil keyframes"},
+ {GP_ONION_MODE_SELECTED, "SELECTED", 0, "Selected", "Only selected keyframes"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+const EnumPropertyItem rna_enum_gplayer_move_type_items[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem rna_enum_layer_blend_modes_items[] = {
+ {eGplBlendMode_Normal, "NORMAL", 0, "Normal", "" },
+ {eGplBlendMode_Overlay, "OVERLAY", 0, "Overlay", "" },
+ {eGplBlendMode_Add, "ADD", 0, "Add", "" },
+ {eGplBlendMode_Subtract, "SUBTRACT", 0, "Subtract", "" },
+ {eGplBlendMode_Multiply, "MULTIPLY", 0, "Multiply", "" },
+ {eGplBlendMode_Divide, "DIVIDE", 0, "Divide", "" },
+ {0, NULL, 0, NULL, NULL }
+};
+#endif
#ifdef RNA_RUNTIME
-#include "BLI_math.h"
+#include "BLI_ghash.h"
#include "WM_api.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_gpencil.h"
-#include "BKE_action.h"
+#include "BKE_icons.h"
+
+#include "DEG_depsgraph.h"
-static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
-static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_GPencil_autolock(Main *bmain, Scene *scene, PointerRNA *ptr)
{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+ bGPDlayer *gpl = NULL;
+
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
+
+ /* Lock all other layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* unlock active layer */
+ if (gpl == layer) {
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ }
+ else {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
+ }
+ }
+ else {
+ /* If disable is better unlock all layers by default or it looks there is
+ * a problem in the UI because the user expects all layers will be unlocked
+ */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ }
+ }
+
+ /* standard update */
+ rna_GPencil_update(bmain, scene, ptr);
+}
+
+static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+
/* Notify all places where GPencil data lives that the editing state is different */
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_MODE | NC_MOVIECLIP, NULL);
}
-static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void UNUSED_FUNCTION(rna_GPencil_onion_skinning_update)(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->id.data;
bGPDlayer *gpl;
@@ -87,7 +161,7 @@ static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, Pointer
* stays in sync with the status of the actual layers
*/
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->flag & GP_LAYER_ONIONSKIN) {
+ if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
enabled = true;
}
}
@@ -102,16 +176,22 @@ static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, Pointer
rna_GPencil_update(bmain, scene, ptr);
}
-static void rna_GPencil_stroke_colorname_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+
+/* Poll Callback to filter GP Datablocks to only show those for Annotations */
+bool rna_GPencil_datablocks_annotations_poll(PointerRNA *UNUSED(ptr), const PointerRNA value)
{
- bGPDstroke *gps = (bGPDstroke *)ptr->data;
- gps->flag |= GP_STROKE_RECALC_COLOR;
- gps->palcolor = NULL;
+ bGPdata *gpd = value.data;
+ return (gpd->flag & GP_DATA_ANNOTATIONS) != 0;
+}
- /* Now do standard updates... */
- rna_GPencil_update(bmain, scene, ptr);
+/* Poll Callback to filter GP Datablocks to only show those for GP Objects */
+bool rna_GPencil_datablocks_obdata_poll(PointerRNA *UNUSED(ptr), const PointerRNA value)
+{
+ bGPdata *gpd = value.data;
+ return (gpd->flag & GP_DATA_ANNOTATIONS) == 0;
}
+
static char *rna_GPencilLayer_path(PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
@@ -133,36 +213,6 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr, const char **
return PROP_EDITABLE;
}
-static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *max,
- int *softmin, int *softmax)
-{
- bGPDlayer *gpl = ptr->data;
-
- /* The restrictions on max width here are due to OpenGL on Windows not supporting
- * any widths greater than 10 (for driver-drawn) strokes/points.
- *
- * Although most of our 2D strokes also don't suffer from this restriction,
- * it's relatively hard to test for that. So, for now, only volumetric strokes
- * get to be larger...
- */
-
- /* From GP v2 this value is used to increase or decrease the thickness of the stroke */
- if (gpl->flag & GP_LAYER_VOLUMETRIC) {
- *min = -300;
- *max = 300;
-
- *softmin = -100;
- *softmax = 100;
- }
- else {
- *min = -10;
- *max = 10;
-
- *softmin = -10;
- *softmax = 10;
- }
-}
-
/* set parent */
static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char *substr)
{
@@ -202,21 +252,6 @@ static void rna_GPencilLayer_parent_set(PointerRNA *ptr, PointerRNA value)
set_parent(gpl, par, gpl->partype, gpl->parsubstr);
}
else {
- /* keep strokes in the same place, so apply current transformation */
- if (gpl->parent != NULL) {
- bGPDspoint *pt;
- int i;
- float diff_mat[4][4];
- /* calculate difference matrix */
- ED_gpencil_parent_location(gpl, diff_mat);
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- mul_m4_v3(diff_mat, &pt->x);
- }
- }
- }
- }
/* clear parent */
gpl->parent = NULL;
}
@@ -306,6 +341,15 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value)
{
bGPdata *gpd = ptr->id.data;
+ /* Don't allow setting active layer to NULL if layers exist
+ * as this breaks various tools. Tools should be used instead
+ * if it's necessary to remove layers
+ */
+ if (value.data == NULL) {
+ printf("%s: Setting active layer to None is not allowed\n", __func__);
+ return;
+ }
+
if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
bGPDlayer *gl;
@@ -336,6 +380,10 @@ static void rna_GPencil_active_layer_index_set(PointerRNA *ptr, int value)
bGPDlayer *gpl = BLI_findlink(&gpd->layers, value);
BKE_gpencil_layer_setactive(gpd, gpl);
+
+ /* Now do standard updates... */
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL);
}
static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
@@ -349,6 +397,36 @@ static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int
*softmax = *max;
}
+static const EnumPropertyItem *rna_GPencil_active_layer_itemf(
+ bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+ bGPDlayer *gpl;
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, gpd)) {
+ return DummyRNA_NULL_items;
+ }
+
+ /* Existing layers */
+ for (gpl = gpd->layers.first, i = 0; gpl; gpl = gpl->next, i++) {
+ item_tmp.identifier = gpl->info;
+ item_tmp.name = gpl->info;
+ item_tmp.value = i;
+
+ item_tmp.icon = BKE_icon_gplayer_color_ensure(gpl);
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
{
bGPdata *gpd = ptr->id.data;
@@ -366,31 +444,6 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info);
}
-static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const bool value)
-{
- bGPdata *gpd = ptr->id.data;
- bGPDlayer *gpl;
-
- /* set new value */
- if (value) {
- /* enable on active layer (it's the one that's most likely to be of interest right now) */
- gpl = BKE_gpencil_layer_getactive(gpd);
- if (gpl) {
- gpl->flag |= GP_LAYER_ONIONSKIN;
- }
-
- gpd->flag |= GP_DATA_SHOW_ONIONSKINS;
- }
- else {
- /* disable on all layers - allowa quickly turning them all off, without having to check */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- gpl->flag &= ~GP_LAYER_ONIONSKIN;
- }
-
- gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
- }
-}
-
static bGPDstroke *rna_GPencil_stroke_point_find_stroke(const bGPdata *gpd, const bGPDspoint *pt, bGPDlayer **r_gpl, bGPDframe **r_gpf)
{
bGPDlayer *gpl;
@@ -454,14 +507,21 @@ static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pr
stroke->points = MEM_recallocN_id(stroke->points,
sizeof(bGPDspoint) * (stroke->totpoints + count),
"gp_stroke_points");
+ stroke->dvert = MEM_recallocN_id(stroke->dvert,
+ sizeof(MDeformVert) * (stroke->totpoints + count),
+ "gp_stroke_weight");
/* init the pressure and strength values so that old scripts won't need to
* be modified to give these initial values...
*/
for (int i = 0; i < count; i++) {
bGPDspoint *pt = stroke->points + (stroke->totpoints + i);
+ MDeformVert *dvert = stroke->dvert + (stroke->totpoints + i);
pt->pressure = pressure;
pt->strength = strength;
+
+ dvert->totweight = 0;
+ dvert->dw = NULL;
}
stroke->totpoints += count;
@@ -471,6 +531,7 @@ static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pr
static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports, int index)
{
bGPDspoint *pt_tmp = stroke->points;
+ MDeformVert *pt_dvert = stroke->dvert;
/* python style negative indexing */
if (index < 0) {
@@ -485,27 +546,37 @@ static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports
stroke->totpoints--;
stroke->points = MEM_callocN(sizeof(bGPDspoint) * stroke->totpoints, "gp_stroke_points");
+ if (pt_dvert != NULL) {
+ stroke->dvert = MEM_callocN(sizeof(MDeformVert) * stroke->totpoints, "gp_stroke_weights");
+ }
- if (index > 0)
+ if (index > 0) {
memcpy(stroke->points, pt_tmp, sizeof(bGPDspoint) * index);
+ /* verify weight data is available */
+ if (pt_dvert != NULL) {
+ memcpy(stroke->dvert, pt_dvert, sizeof(MDeformVert) * index);
+ }
+ }
- if (index < stroke->totpoints)
+ if (index < stroke->totpoints) {
memcpy(&stroke->points[index], &pt_tmp[index + 1], sizeof(bGPDspoint) * (stroke->totpoints - index));
+ if (pt_dvert != NULL) {
+ memcpy(&stroke->dvert[index], &pt_dvert[index + 1], sizeof(MDeformVert) * (stroke->totpoints - index));
+ }
+ }
/* free temp buffer */
MEM_freeN(pt_tmp);
+ if (pt_dvert != NULL) {
+ MEM_freeN(pt_dvert);
+ }
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
-static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame, const char *colorname)
+static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame)
{
bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- if (colorname) {
- BLI_strncpy(stroke->colorname, colorname, sizeof(stroke->colorname));
- }
- stroke->palcolor = NULL;
- stroke->flag |= GP_STROKE_RECALC_COLOR;
BLI_addtail(&frame->strokes, stroke);
return stroke;
@@ -614,279 +685,62 @@ static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, PointerR
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-static void rna_GPencil_frame_clear(bGPDframe *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)
-{
- BKE_gpencil_free_frames(layer);
-
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-static void rna_GPencil_clear(bGPdata *gpd)
-{
- 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, bool setactive)
+static void rna_GPencil_layer_move(bGPdata *gpd, ReportList *reports, PointerRNA *layer_ptr, int type)
{
- 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");
+ bGPDlayer *gpl = layer_ptr->data;
+ if (BLI_findindex(&gpd->layers, gpl) == -1) {
+ BKE_report(reports, RPT_ERROR, "Layer not found in grease pencil data");
return;
}
- BKE_gpencil_palette_delete(gpd, palette);
- RNA_POINTER_INVALIDATE(palette_ptr);
+ BLI_assert(ELEM(type, -1, 0, 1)); /* we use value below */
- 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;
+ const int direction = type * -1;
- 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);
- }
+ if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
}
- 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)
+static void rna_GPencil_frame_clear(bGPDframe *frame)
{
- 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);
+ BKE_gpencil_free_strokes(frame);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-static PointerRNA rna_GPencilPalette_active_color_get(PointerRNA *ptr)
-{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
- bGPDpalettecolor *color;
-
- for (color = palette->colors.first; color; color = color->next) {
- if (color->flag & PC_COLOR_ACTIVE) {
- break;
- }
- }
-
- if (color) {
- return rna_pointer_inherit_refine(ptr, &RNA_GPencilPaletteColor, color);
- }
-
- return rna_pointer_inherit_refine(ptr, NULL, NULL);
-}
-
-static void rna_GPencilPalette_active_color_set(PointerRNA *ptr, PointerRNA value)
-{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
- bGPDpalettecolor *color = value.data;
-
- BKE_gpencil_palettecolor_setactive(palette, color);
-}
-
-static void rna_GPencilPalette_info_set(PointerRNA *ptr, const char *value)
-{
- bGPdata *gpd = ptr->id.data;
- bGPDpalette *palette = ptr->data;
-
- char oldname[64] = "";
- BLI_strncpy(oldname, palette->info, sizeof(oldname));
-
- /* copy the new name into the name slot */
- BLI_strncpy_utf8(palette->info, value, sizeof(palette->info));
-
- BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
- sizeof(palette->info));
- /* now fix animation paths */
- BKE_animdata_fix_paths_rename_all(&gpd->id, "palettes", oldname, palette->info);
-}
-
-static char *rna_GPencilPalette_path(PointerRNA *ptr)
-{
- bGPDpalette *palette = ptr->data;
- char name_esc[sizeof(palette->info) * 2];
-
- BLI_strescape(name_esc, palette->info, sizeof(name_esc));
-
- return BLI_sprintfN("palettes[\"%s\"]", name_esc);
-}
-
-static char *rna_GPencilPalette_color_path(PointerRNA *ptr)
+static void rna_GPencil_layer_clear(bGPDlayer *layer)
{
- 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));
+ BKE_gpencil_free_frames(layer);
- return BLI_sprintfN("palettes[\"%s\"].colors[\"%s\"]", name_palette, name_color);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-static void rna_GPencilPaletteColor_info_set(PointerRNA *ptr, const char *value)
+static void rna_GPencil_clear(bGPdata *gpd)
{
- bGPdata *gpd = ptr->id.data;
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = ptr->data;
-
- char oldname[64] = "";
- BLI_strncpy(oldname, palcolor->info, sizeof(oldname));
-
- /* copy the new name into the name slot */
- BLI_strncpy_utf8(palcolor->info, value, sizeof(palcolor->info));
- BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
- sizeof(palcolor->info));
-
- /* rename all strokes */
- BKE_gpencil_palettecolor_changename(gpd, oldname, palcolor->info);
+ BKE_gpencil_free_layers(&gpd->layers);
- /* now fix animation paths */
- BKE_animdata_fix_paths_rename_all(&gpd->id, "colors", oldname, palcolor->info);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
-static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value)
+static void rna_GpencilVertex_groups_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bGPDstroke *gps = ptr->data;
- /* copy the new name into the name slot */
- BLI_strncpy_utf8(gps->colorname, value, sizeof(gps->colorname));
-}
-
-
-static bool rna_GPencilPaletteColor_is_stroke_visible_get(PointerRNA *ptr)
-{
- bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
- return (pcolor->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
-}
-
-static bool rna_GPencilPaletteColor_is_fill_visible_get(PointerRNA *ptr)
-{
- bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data;
- return (pcolor->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH);
-}
-
-static int rna_GPencilPaletteColor_index_get(PointerRNA *ptr)
-{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
- bGPDpalettecolor *pcolor = BKE_gpencil_palettecolor_getactive(palette);
+ if (gps->dvert) {
+ MDeformVert *dvert = gps->dvert;
- 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);
+ rna_iterator_array_begin(iter, (void *)dvert->dw, sizeof(MDeformWeight), dvert->totweight, 0, NULL);
+ }
+ else
+ rna_iterator_array_begin(iter, NULL, 0, 0, 0, NULL);
}
-static void rna_GPencilPaletteColor_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
+static char *rna_GreasePencilGrid_path(PointerRNA *UNUSED(ptr))
{
- bGPDpalette *palette = (bGPDpalette *)ptr->data;
-
- *min = 0;
- *max = max_ii(0, BLI_listbase_count(&palette->colors) - 1);
-
- *softmin = *min;
- *softmax = *max;
+ return BLI_sprintfN("grid");
}
#else
@@ -918,17 +772,31 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Strength", "Color intensity (alpha factor)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "uv_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_fac");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "UV Factor", "Internal UV factor");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "uv_rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_rot");
+ RNA_def_property_range(prop, 0.0f, M_PI * 2);
+ RNA_def_property_ui_text(prop, "UV Rotation", "Internal UV factor for dot mode");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SPOINT_SELECT);
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_point_select_set");
RNA_def_property_ui_text(prop, "Select", "Point is selected for viewport editing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
}
static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "GPencilStrokePoints");
srna = RNA_def_struct(brna, "GPencilStrokePoints", NULL);
@@ -937,7 +805,8 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr
func = RNA_def_function(srna, "add", "rna_GPencil_stroke_point_add");
RNA_def_function_ui_description(func, "Add a new grease pencil stroke point");
- RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the stroke", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the stroke", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_float(func, "pressure", 1.0f, 0.0f, 1.0f, "Pressure", "Pressure for newly created points", 0.0f, 1.0f);
RNA_def_float(func, "strength", 1.0f, 0.0f, 1.0f, "Strength", "Color intensity (alpha factor) for newly created points", 0.0f, 1.0f);
@@ -955,7 +824,7 @@ static void rna_def_gpencil_triangle(BlenderRNA *brna)
srna = RNA_def_struct(brna, "GPencilTriangle", NULL);
RNA_def_struct_sdna(srna, "bGPDtriangle");
- RNA_def_struct_ui_text(srna, "Triangle", "Triangulation data for HQ fill");
+ RNA_def_struct_ui_text(srna, "Triangle", "Triangulation data for Grease Pencil fills");
/* point v1 */
prop = RNA_def_property(srna, "v1", PROP_INT, PROP_NONE);
@@ -974,6 +843,51 @@ static void rna_def_gpencil_triangle(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "verts[2]");
RNA_def_property_ui_text(prop, "v3", "Third triangle vertex index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* texture coord for point v1 */
+ prop = RNA_def_property(srna, "uv1", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "uv[0]");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "uv1", "First triangle vertex texture coordinates");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* texture coord for point v2 */
+ prop = RNA_def_property(srna, "uv2", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "uv[1]");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "uv2", "Second triangle vertex texture coordinates");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* texture coord for point v3 */
+ prop = RNA_def_property(srna, "uv3", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "uv[2]");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "uv3", "Third triangle vertex texture coordinates");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
+static void rna_def_gpencil_mvert_group(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GpencilVertexGroupElement", NULL);
+ RNA_def_struct_sdna(srna, "MDeformWeight");
+ RNA_def_struct_ui_text(srna, "Vertex Group Element", "Weight value of a vertex in a vertex group");
+ RNA_def_struct_ui_icon(srna, ICON_GROUP_VERTEX);
+
+ /* we can't point to actual group, it is in the object and so
+ * there is no unique group to point to, hence the index */
+ prop = RNA_def_property(srna, "group", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "def_nr");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Group Index", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Weight", "Vertex Weight");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
}
static void rna_def_gpencil_stroke(BlenderRNA *brna)
@@ -981,7 +895,7 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem stroke_draw_mode_items[] = {
+ static const EnumPropertyItem stroke_display_mode_items[] = {
{0, "SCREEN", 0, "Screen", "Stroke is in screen-space"},
{GP_STROKE_3DSPACE, "3DSPACE", 0, "3D Space", "Stroke is in 3D-space"},
{GP_STROKE_2DSPACE, "2DSPACE", 0, "2D Space", "Stroke is in 2D-space"},
@@ -1000,24 +914,30 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stroke Points", "Stroke data points");
rna_def_gpencil_stroke_points_api(brna, prop);
+ /* vertex groups */
+ prop = RNA_def_property(srna, "groups", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_GpencilVertex_groups_begin", "rna_iterator_array_next",
+ "rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "GpencilVertexGroupElement");
+ RNA_def_property_ui_text(prop, "Groups", "Weights for the vertex groups this vertex is member of");
+
/* Triangles */
prop = RNA_def_property(srna, "triangles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "triangles", "tot_triangles");
RNA_def_property_struct_type(prop, "GPencilTriangle");
RNA_def_property_ui_text(prop, "Triangles", "Triangulation data for HQ fill");
- /* Color */
- prop = RNA_def_property(srna, "color", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilPaletteColor");
- RNA_def_property_pointer_sdna(prop, NULL, "palcolor");
- RNA_def_property_ui_text(prop, "Palette Color", "Color from palette used in Stroke");
- RNA_def_property_update(prop, 0, "rna_GPencil_update");
+ /* Material Index */
+ prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "mat_nr");
+ RNA_def_property_ui_text(prop, "Material Index", "Index of material used in this stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Settings */
- prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, stroke_draw_mode_items);
- RNA_def_property_ui_text(prop, "Draw Mode", "");
+ RNA_def_property_enum_items(prop, stroke_display_mode_items);
+ RNA_def_property_ui_text(prop, "Draw Mode", "Coordinate space that stroke is in");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
@@ -1026,22 +946,23 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Select", "Stroke is selected for viewport editing");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
- /* Color Name */
- prop = RNA_def_property(srna, "colorname", PROP_STRING, PROP_NONE);
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilStrokeColor_info_set");
- RNA_def_property_ui_text(prop, "Color Name", "Palette color name");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_colorname_update");
-
/* Cyclic: Draw a line from end to start point */
prop = RNA_def_property(srna, "draw_cyclic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_CYCLIC);
RNA_def_property_ui_text(prop, "Cyclic", "Enable cyclic drawing, closing the stroke");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
+ /* No fill: The stroke never must fill area and must use fill color as stroke color (this is a special flag for fill brush) */
+ prop = RNA_def_property(srna, "is_nofill_stroke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_NOFILL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "No Fill", "Special stroke to use as boundary for filling areas");
+ RNA_def_property_update(prop, 0, "rna_GPencil_update");
+
/* Line Thickness */
prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "thickness");
- RNA_def_property_range(prop, 1, 300);
+ RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_range(prop, 1, 10, 1, 0);
RNA_def_property_ui_text(prop, "Thickness", "Thickness of stroke (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
@@ -1062,7 +983,6 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_GPencil_stroke_new");
RNA_def_function_ui_description(func, "Add a new grease pencil stroke");
- parm = RNA_def_string(func, "colorname", 0, MAX_NAME, "Color", "Name of the color");
parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "", "The newly created stroke");
RNA_def_function_return(func, parm);
@@ -1156,6 +1076,8 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
PropertyRNA *prop;
FunctionRNA *func;
+ static const float default_onion_color_b[] = { 0.302f, 0.851f, 0.302f };
+ static const float default_onion_color_a[] = { 0.250f, 0.1f, 1.0f };
srna = RNA_def_struct(brna, "GPencilLayer", NULL);
RNA_def_struct_sdna(srna, "bGPDlayer");
@@ -1183,20 +1105,30 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_editable_func(prop, "rna_GPencilLayer_active_frame_editable");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Draw Style */
- // TODO: replace these with a "draw type" combo (i.e. strokes only, filled strokes, strokes + fills, volumetric)?
- prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_VOLUMETRIC);
- RNA_def_property_ui_text(prop, "Volumetric Strokes",
- "Draw strokes as a series of circular blobs, resulting in a volumetric effect");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Layer Opacity */
prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "opacity");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Stroke Drawing Color (Annotations) */
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Color", "Color for all strokes in this layer");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Line Thickness (Annotations) */
+ prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "thickness");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(prop, "Thickness", "Thickness of annotation strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+
/* Tint Color */
prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "tintcolor");
@@ -1212,66 +1144,79 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tint Factor", "Factor of tinting color");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* Line Thickness change */
+ /* Line Thickness Change */
prop = RNA_def_property(srna, "line_change", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "thickness");
- //RNA_def_property_range(prop, 1, 10); /* 10 px limit comes from Windows OpenGL limits for natively-drawn strokes */
- RNA_def_property_int_funcs(prop, NULL, NULL, "rna_GPencilLayer_line_width_range");
- RNA_def_property_ui_text(prop, "Thickness", "Thickness change to apply to current strokes (in pixels)");
+ RNA_def_property_int_sdna(prop, NULL, "line_change");
+ RNA_def_property_range(prop, -300, 300);
+ RNA_def_property_ui_range(prop, -100, 100, 1.0, 1);
+ RNA_def_property_ui_text(prop, "Thickness Change", "Thickness change to apply to current strokes (in pixels)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Onion-Skinning */
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ONIONSKIN);
- RNA_def_property_ui_text(prop, "Onion Skinning", "Ghost frames on either side of frame");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_onion_skinning_update");
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_LAYER_ONIONSKIN);
+ RNA_def_property_ui_text(prop, "Onion Skinning", "Display onion skins before and after the current frame");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "use_annotation_onion_skinning", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_LAYER_ONIONSKIN);
+ RNA_def_property_ui_text(prop, "Onion Skinning",
+ "Display annotation onion skins before and after the current frame");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "annotation_onion_before_range", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gstep");
RNA_def_property_range(prop, -1, 120);
RNA_def_property_ui_text(prop, "Frames Before",
- "Maximum number of frames to show before current frame "
- "(0 = show only the previous sketch, -1 = don't show any frames before current)");
+ "Maximum number of frames to show before current frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "annotation_onion_after_range", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gstep_next");
RNA_def_property_range(prop, -1, 120);
RNA_def_property_ui_text(prop, "Frames After",
- "Maximum number of frames to show after current frame "
- "(0 = show only the next sketch, -1 = don't show any frames after current)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL);
- RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames");
+ "Maximum number of frames to show after current frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "annotation_onion_before_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "gcolor_prev");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, default_onion_color_b);
RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "annotation_onion_after_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "gcolor_next");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, default_onion_color_a);
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_ALWAYS);
- RNA_def_property_ui_text(prop, "Always Show Ghosts",
- "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)");
+ /* pass index for compositing and modifiers */
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Layer Index\" pass");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "viewlayer_render", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "viewlayername");
+ RNA_def_property_ui_text(prop, "ViewLayer",
+ "Only include Layer in this View Layer render output (leave blank to include always)");
+
+ /* blend mode */
+ prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
+ RNA_def_property_enum_items(prop, rna_enum_layer_blend_modes_items);
+ RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode");
+ 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);
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_ui_text(prop, "Hide", "Set layer Visibility");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
@@ -1287,16 +1232,20 @@ 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 selected colors from further editing and/or frame changes");
+ prop = RNA_def_property(srna, "lock_material", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_LAYER_UNLOCK_COLOR);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Lock Material", "Disable Material editing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ prop = RNA_def_property(srna, "clamp_layer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Clamp Layer",
+ "Clamp any pixel outside underlying layers drawing");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* expose as layers.active */
+ /* exposed as layers.active */
#if 0
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ACTIVE);
@@ -1310,16 +1259,15 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, "rna_GPencil_update");
- /* XXX keep this option? */
prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_DRAWDEBUG);
RNA_def_property_ui_text(prop, "Show Points", "Draw the points which make up the strokes (for debugging purposes)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* X-Ray */
- prop = RNA_def_property(srna, "show_x_ray", PROP_BOOLEAN, PROP_NONE);
+ /* In Front */
+ prop = RNA_def_property(srna, "show_in_front", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_LAYER_NO_XRAY);
- RNA_def_property_ui_text(prop, "X Ray", "Make the layer draw in front of objects");
+ RNA_def_property_ui_text(prop, "In Front", "Make the layer draw in front of objects");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Parent object */
@@ -1391,6 +1339,15 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+ func = RNA_def_function(srna, "move", "rna_GPencil_layer_move");
+ RNA_def_function_ui_description(func, "Move a grease pencil layer in the layer stack");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The layer to move");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+ parm = RNA_def_enum(func, "type", rna_enum_gplayer_move_type_items, 1, "", "Direction of movement");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilLayer");
RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_layer_get", "rna_GPencil_active_layer_set", NULL, NULL);
@@ -1399,215 +1356,69 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop,
- "rna_GPencil_active_layer_index_get",
- "rna_GPencil_active_layer_index_set",
- "rna_GPencil_active_layer_index_range");
+ RNA_def_property_int_funcs(
+ prop,
+ "rna_GPencil_active_layer_index_get",
+ "rna_GPencil_active_layer_index_set",
+ "rna_GPencil_active_layer_index_range");
RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
+
+ /* Active Layer - As an enum (for selecting active layer for annotations) */
+ prop = RNA_def_property(srna, "active_note", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_funcs(
+ prop,
+ "rna_GPencil_active_layer_index_get",
+ "rna_GPencil_active_layer_index_set",
+ "rna_GPencil_active_layer_itemf");
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items); /* purely dynamic, as it maps to user-data */
+ RNA_def_property_ui_text(prop, "Active Note", "Note/Layer to add annotation strokes to");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
}
-static void rna_def_gpencil_palettecolor(BlenderRNA *brna)
+static void rna_def_gpencil_grid(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");
+ static const float default_grid_color[] = { 0.5f, 0.5f, 0.5f };
- /* 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");
+ srna = RNA_def_struct(brna, "GreasePencilGrid", NULL);
+ RNA_def_struct_sdna(srna, "bGPgrid");
+ RNA_def_struct_nested(brna, srna, "GreasePencil");
- 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");
+ RNA_def_struct_path_func(srna, "rna_GreasePencilGrid_path");
+ RNA_def_struct_ui_text(srna, "Grid and Canvas Settings",
+ "Settings for grid and canvas in 3D viewport");
- /* Name */
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "info");
- RNA_def_property_ui_text(prop, "Name", "Color name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPaletteColor_info_set");
- RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_range(prop, 0.01f, FLT_MAX);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Grid Scale", "Grid scale");
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");
+ 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, "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, "Show in Ghosts", "Display strokes using this color when showing onion skins");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Draw Style */
- prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_VOLUMETRIC);
- RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in "
- "a volumetric effect");
+ RNA_def_property_float_array_default(prop, default_grid_color);
+ RNA_def_property_ui_text(prop, "Grid Color", "Color for grid lines");
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)");
+ prop = RNA_def_property(srna, "lines", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "lines");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_int_default(prop, GP_DEFAULT_GRID_LINES);
+ RNA_def_property_ui_text(prop, "Grid Subdivisions", "Number of subdivisions in each side of symmetry line");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- /* Read-only state props (for simpler UI code) */
- prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_stroke_visible_get", NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible");
-
- prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_fill_visible_get", NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
-}
-
-/* palette colors api */
-static void rna_def_gpencil_palettecolors_api(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "GPencilPaletteColors");
- srna = RNA_def_struct(brna, "GPencilPaletteColors", NULL);
- RNA_def_struct_sdna(srna, "bGPDpalette");
- RNA_def_struct_ui_text(srna, "Palette colors", "Collection of palette colors");
-
- func = RNA_def_function(srna, "new", "rna_GPencilPalette_color_new");
- RNA_def_function_ui_description(func, "Add a new color to the palette");
- parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The newly created color");
- RNA_def_function_return(func, parm);
-
- func = RNA_def_function(srna, "remove", "rna_GPencilPalette_color_remove");
- RNA_def_function_ui_description(func, "Remove a color from the palette");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The color to remove");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
- RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilPaletteColor");
- RNA_def_property_pointer_funcs(prop, "rna_GPencilPalette_active_color_get", "rna_GPencilPalette_active_color_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Active Palette Color", "Current active color");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop,
- "rna_GPencilPaletteColor_index_get",
- "rna_GPencilPaletteColor_index_set",
- "rna_GPencilPaletteColor_index_range");
- RNA_def_property_ui_text(prop, "Active color Index", "Index of active palette color");
-}
-
-static void rna_def_gpencil_palette(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "GPencilPalette", NULL);
- RNA_def_struct_sdna(srna, "bGPDpalette");
- RNA_def_struct_ui_text(srna, "Grease Pencil Palette", "Collection of related palettes");
- RNA_def_struct_path_func(srna, "rna_GPencilPalette_path");
- RNA_def_struct_ui_icon(srna, ICON_COLOR);
-
- /* Name */
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "info");
- RNA_def_property_ui_text(prop, "Name", "Palette name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPalette_info_set");
- RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "offset");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Offset", "Offset of the canvas");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- /* Colors */
- prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "colors", NULL);
- RNA_def_property_struct_type(prop, "GPencilPaletteColor");
- RNA_def_property_ui_text(prop, "Colors", "Colors of the palette");
- rna_def_gpencil_palettecolors_api(brna, prop);
-
-}
-
-static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "GreasePencilPalettes");
- srna = RNA_def_struct(brna, "GreasePencilPalettes", NULL);
- RNA_def_struct_sdna(srna, "bGPdata");
- RNA_def_struct_ui_text(srna, "Grease Pencil Palettes", "Collection of grease pencil palettes");
-
- func = RNA_def_function(srna, "new", "rna_GPencil_palette_new");
- RNA_def_function_ui_description(func, "Add a new grease pencil palette");
- parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_boolean(func, "set_active", true, "Set Active", "Activate the newly created palette");
- parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The newly created palette");
- RNA_def_function_return(func, parm);
-
- func = RNA_def_function(srna, "remove", "rna_GPencil_palette_remove");
- RNA_def_function_ui_description(func, "Remove a grease pencil palette");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The palette to remove");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
- RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilPalette");
- RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_palette_get", "rna_GPencil_active_palette_set",
- NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Active Palette", "Current active palette");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop,
- "rna_GPencilPalette_index_get",
- "rna_GPencilPalette_index_set",
- "rna_GPencilPalette_index_range");
- RNA_def_property_ui_text(prop, "Active Palette Index", "Index of active palette");
}
static void rna_def_gpencil_data(BlenderRNA *brna)
@@ -1616,6 +1427,10 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
PropertyRNA *prop;
FunctionRNA *func;
+ static float default_1[4] = { 0.6f, 0.6f, 0.6f, 0.5f };
+ static float onion_dft1[3] = { 0.145098f, 0.419608f, 0.137255f }; /* green */
+ static float onion_dft2[3] = { 0.125490f, 0.082353f, 0.529412f }; /* blue */
+
srna = RNA_def_struct(brna, "GreasePencil", "ID");
RNA_def_struct_sdna(srna, "bGPdata");
RNA_def_struct_ui_text(srna, "Grease Pencil", "Freehand annotation sketchbook");
@@ -1628,28 +1443,52 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layers", "");
rna_def_gpencil_layers_api(brna, prop);
- /* Palettes */
- prop = RNA_def_property(srna, "palettes", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "palettes", NULL);
- RNA_def_property_struct_type(prop, "GPencilPalette");
- RNA_def_property_ui_text(prop, "Palettes", "");
- rna_def_gpencil_palettes_api(brna, prop);
-
/* Animation Data */
rna_def_animdata_common(srna);
+ /* materials */
+ prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
+ RNA_def_property_struct_type(prop, "Material");
+ RNA_def_property_ui_text(prop, "Materials", "");
+ RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */
+ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int");
+
+ /* xray modes */
+ prop = RNA_def_property(srna, "xray_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "xray_mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_xraymodes_items);
+ RNA_def_property_ui_text(prop, "Xray", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Flags */
prop = RNA_def_property(srna, "use_stroke_edit_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_EDITMODE);
RNA_def_property_ui_text(prop, "Stroke Edit Mode", "Edit Grease Pencil strokes instead of viewport data");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update");
+ prop = RNA_def_property(srna, "is_stroke_paint_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_PAINTMODE);
+ RNA_def_property_ui_text(prop, "Stroke Paint Mode", "Draw Grease Pencil strokes on click/drag");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update");
+
+ prop = RNA_def_property(srna, "is_stroke_sculpt_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_SCULPTMODE);
+ RNA_def_property_ui_text(prop, "Stroke Sculpt Mode", "Sculpt Grease Pencil strokes instead of viewport data");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update");
+
+ prop = RNA_def_property(srna, "is_stroke_weight_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_WEIGHTMODE);
+ RNA_def_property_ui_text(prop, "Stroke Weight Paint Mode", "Grease Pencil weight paint");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update");
+
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_ONIONSKINS);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_use_onion_skinning_set");
- RNA_def_property_ui_text(prop, "Onion Skins",
- "Show ghosts of the frames before and after the current frame, toggle to enable on active layer or disable all");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ RNA_def_property_ui_text(prop, "Onion Skins", "Show ghosts of the keyframes before and after the current frame");
+ RNA_def_property_update(prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update");
prop = RNA_def_property(srna, "show_stroke_direction", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_DIRECTION);
@@ -1657,9 +1496,137 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
"and smaller red dot (end) points");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "show_constant_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_KEEPTHICKNESS);
+ RNA_def_property_ui_text(prop, "Keep Thickness", "Maintain the thickness of the stroke when the viewport zoom changes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "pixel_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pixfactor");
+ RNA_def_property_range(prop, 0.1f, 30.0f);
+ RNA_def_property_ui_range(prop, 0.1f, 30.0f, 1, 2);
+ RNA_def_property_ui_text(prop, "Scale", "Scale conversion factor for pixel size (use larger values for thicker lines)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_multiedit", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_MULTIEDIT);
+ RNA_def_property_ui_text(prop, "MultiFrame", "Edit strokes from multiple grease pencil keyframes at the same time (keyframes must be selected to be included)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_force_fill_recalc", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_FORCE_RECALC);
+ RNA_def_property_ui_text(prop, "Force Fill Update", "Force recalc of fill data after use deformation modifiers (reduce FPS)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_adaptative_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_UV_ADAPTATIVE);
+ RNA_def_property_ui_text(prop, "Adaptative UV", "Automatic UVs are calculated depending of the stroke size");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_autolock_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_AUTOLOCK_LAYERS);
+ RNA_def_property_ui_text(prop, "Autolock Layers",
+ "Lock automatically all layers except active one to avoid accidental changes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_autolock");
+
+ prop = RNA_def_property(srna, "edit_line_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "line_color");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, default_1);
+ RNA_def_property_ui_text(prop, "Edit Line Color", "Color for editing line");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* onion skinning */
+ prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "gstep");
+ RNA_def_property_range(prop, 0, 120);
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Frames Before",
+ "Maximum number of frames to show before current frame "
+ "(0 = don't show any frames before current)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "gstep_next");
+ RNA_def_property_range(prop, 0, 120);
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Frames After",
+ "Maximum number of frames to show after current frame "
+ "(0 = don't show any frames after current)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
+ RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "gcolor_prev");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, onion_dft1);
+ RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame");
+ RNA_def_property_update(prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "gcolor_next");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, onion_dft2);
+ RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
+ RNA_def_property_update(prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_GHOST_ALWAYS);
+ RNA_def_property_ui_text(prop, "Always Show Ghosts",
+ "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "onion_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "onion_mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_onion_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode to display frames");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_onion_fade", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_FADE);
+ RNA_def_property_ui_text(prop, "Fade",
+ "Display onion keyframes with a fade in color transparency");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_onion_loop", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_LOOP);
+ RNA_def_property_ui_text(prop, "Loop",
+ "Display first onion keyframes using next frame color to show indication of loop start frame");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "onion_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "onion_factor");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_range(prop, 0.0, 1.0f);
+ RNA_def_property_ui_text(prop, "Onion Opacity", "Change fade opacity of displayed onion frames");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "zdepth_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "zdepth_offset");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 5);
+ RNA_def_property_ui_text(prop, "Surface Offset",
+ "Offset amount when drawing in surface mode");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Nested Structs */
+ prop = RNA_def_property(srna, "grid", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "GreasePencilGrid");
+ RNA_def_property_ui_text(prop, "Grid Settings", "Settings for grid and canvas in the 3D viewport");
+
+ rna_def_gpencil_grid(brna);
+
/* API Functions */
func = RNA_def_function(srna, "clear", "rna_GPencil_clear");
- RNA_def_function_ui_description(func, "Remove all the grease pencil data");
+ RNA_def_function_ui_description(func, "Remove all the Grease Pencil data");
}
/* --- */
@@ -1670,12 +1637,12 @@ void RNA_def_gpencil(BlenderRNA *brna)
rna_def_gpencil_layer(brna);
rna_def_gpencil_frame(brna);
- rna_def_gpencil_triangle(brna);
+
rna_def_gpencil_stroke(brna);
rna_def_gpencil_stroke_point(brna);
+ rna_def_gpencil_triangle(brna);
- rna_def_gpencil_palette(brna);
- rna_def_gpencil_palettecolor(brna);
+ rna_def_gpencil_mvert_group(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
new file mode 100644
index 00000000000..beba47f33b4
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -0,0 +1,1652 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_gpencil_modifier.c
+ * \ingroup RNA
+ */
+
+
+#include <float.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_cachefile_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+#include "BKE_data_transfer.h"
+#include "BKE_dynamicpaint.h"
+#include "BKE_effect.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_remap.h"
+#include "BKE_multires.h"
+#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
+ {0, "", 0, N_("Generate"), "" },
+ {eGpencilModifierType_Array, "GP_ARRAY", ICON_MOD_ARRAY, "Array", "Create array of duplicate instances"},
+ {eGpencilModifierType_Build, "GP_BUILD", ICON_MOD_BUILD, "Build", "Create duplication of strokes"},
+ {eGpencilModifierType_Mirror, "GP_MIRROR", ICON_MOD_MIRROR, "Mirror", "Duplicate strokes like a mirror"},
+ {eGpencilModifierType_Simplify, "GP_SIMPLIFY", ICON_MOD_SIMPLIFY, "Simplify", "Simplify stroke reducing number of points"},
+ {eGpencilModifierType_Subdiv, "GP_SUBDIV", ICON_MOD_SUBSURF, "Subdivide", "Subdivide stroke adding more control points"},
+ {0, "", 0, N_("Deform"), "" },
+ {eGpencilModifierType_Armature, "GP_ARMATURE", ICON_MOD_ARMATURE, "Armature", "Deform stroke points using armature object"},
+ {eGpencilModifierType_Hook, "GP_HOOK", ICON_HOOK, "Hook", "Deform stroke points using objects"},
+ {eGpencilModifierType_Lattice, "GP_LATTICE", ICON_MOD_LATTICE, "Lattice", "Deform strokes using lattice"},
+ {eGpencilModifierType_Noise, "GP_NOISE", ICON_MOD_NOISE, "Noise", "Add noise to strokes"},
+ {eGpencilModifierType_Offset, "GP_OFFSET", ICON_MOD_OFFSET, "Offset", "Change stroke location, rotation or scale"},
+ {eGpencilModifierType_Smooth, "GP_SMOOTH", ICON_MOD_SMOOTH, "Smooth", "Smooth stroke"},
+ {eGpencilModifierType_Thick, "GP_THICK", ICON_MOD_THICKNESS, "Thickness", "Change stroke thickness"},
+ {eGpencilModifierType_Time, "GP_TIME", ICON_MOD_TIME, "Time Offset", "Offset keyframes"},
+ {0, "", 0, N_("Color"), "" },
+ {eGpencilModifierType_Color, "GP_COLOR", ICON_MOD_HUE_SATURATION, "Hue/Saturation", "Apply changes to stroke colors"},
+ {eGpencilModifierType_Opacity, "GP_OPACITY", ICON_MOD_OPACITY, "Opacity", "Opacity of the strokes"},
+ {eGpencilModifierType_Tint, "GP_TINT", ICON_MOD_TINT, "Tint", "Tint strokes with new color"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+#ifndef RNA_RUNTIME
+static const EnumPropertyItem modifier_modify_color_items[] = {
+ {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Both", "Modify fill and stroke colors"},
+ {GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"},
+ {GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem modifier_gphook_falloff_items[] = {
+ {eGPHook_Falloff_None, "NONE", 0, "No Falloff", ""},
+ {eGPHook_Falloff_Curve, "CURVE", 0, "Curve", ""},
+ {eGPHook_Falloff_Smooth, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
+ {eGPHook_Falloff_Sphere, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
+ {eGPHook_Falloff_Root, "ROOT", ICON_ROOTCURVE, "Root", ""},
+ {eGPHook_Falloff_InvSquare, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", ""},
+ {eGPHook_Falloff_Sharp, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
+ {eGPHook_Falloff_Linear, "LINEAR", ICON_LINCURVE, "Linear", ""},
+ {eGPHook_Falloff_Const, "CONSTANT", ICON_NOCURVE, "Constant", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem rna_enum_time_mode_items[] = {
+ {GP_TIME_MODE_NORMAL, "NORMAL", 0, "Normal", "Apply offset in normal animation direction"},
+ {GP_TIME_MODE_REVERSE, "REVERSE", 0, "Reverse", "Apply offset in reverse animation direction"},
+ {GP_TIME_MODE_FIX, "FIX", 0, "Fixed Frame", "Keep frame and do not change with time"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+#endif
+
+#ifdef RNA_RUNTIME
+
+#include "DNA_particle_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_smoke_types.h"
+
+#include "BKE_cachefile.h"
+#include "BKE_context.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+#include "BKE_gpencil.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
+{
+ GpencilModifierData *md = (GpencilModifierData *)ptr->data;
+
+ switch ((GpencilModifierType)md->type) {
+ case eGpencilModifierType_Noise:
+ return &RNA_NoiseGpencilModifier;
+ case eGpencilModifierType_Subdiv:
+ return &RNA_SubdivGpencilModifier;
+ case eGpencilModifierType_Simplify:
+ return &RNA_SimplifyGpencilModifier;
+ case eGpencilModifierType_Thick:
+ return &RNA_ThickGpencilModifier;
+ case eGpencilModifierType_Tint:
+ return &RNA_TintGpencilModifier;
+ case eGpencilModifierType_Time:
+ return &RNA_TimeGpencilModifier;
+ case eGpencilModifierType_Color:
+ return &RNA_ColorGpencilModifier;
+ case eGpencilModifierType_Array:
+ return &RNA_ArrayGpencilModifier;
+ case eGpencilModifierType_Build:
+ return &RNA_BuildGpencilModifier;
+ case eGpencilModifierType_Opacity:
+ return &RNA_OpacityGpencilModifier;
+ case eGpencilModifierType_Lattice:
+ return &RNA_LatticeGpencilModifier;
+ case eGpencilModifierType_Mirror:
+ return &RNA_MirrorGpencilModifier;
+ case eGpencilModifierType_Smooth:
+ return &RNA_SmoothGpencilModifier;
+ case eGpencilModifierType_Hook:
+ return &RNA_HookGpencilModifier;
+ case eGpencilModifierType_Offset:
+ return &RNA_OffsetGpencilModifier;
+ case eGpencilModifierType_Armature:
+ return &RNA_ArmatureGpencilModifier;
+ /* Default */
+ case eGpencilModifierType_None:
+ case NUM_GREASEPENCIL_MODIFIER_TYPES:
+ return &RNA_GpencilModifier;
+ }
+
+ return &RNA_GpencilModifier;
+}
+
+static void rna_GpencilModifier_name_set(PointerRNA *ptr, const char *value)
+{
+ GpencilModifierData *gmd = ptr->data;
+ char oldname[sizeof(gmd->name)];
+
+ /* make a copy of the old name first */
+ BLI_strncpy(oldname, gmd->name, sizeof(gmd->name));
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(gmd->name, value, sizeof(gmd->name));
+
+ /* make sure the name is truly unique */
+ if (ptr->id.data) {
+ Object *ob = ptr->id.data;
+ BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, gmd);
+ }
+
+ /* fix all the animation data which may link to this */
+ BKE_animdata_fix_paths_rename_all(NULL, "grease_pencil_modifiers", oldname, gmd->name);
+}
+
+static char *rna_GpencilModifier_path(PointerRNA *ptr)
+{
+ GpencilModifierData *gmd = ptr->data;
+ char name_esc[sizeof(gmd->name) * 2];
+
+ BLI_strescape(name_esc, gmd->name, sizeof(name_esc));
+ return BLI_sprintfN("grease_pencil_modifiers[\"%s\"]", name_esc);
+}
+
+static void rna_GpencilModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->id.data);
+}
+
+static void rna_GpencilModifier_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_GpencilModifier_update(bmain, scene, ptr);
+ DEG_relations_tag_update(bmain);
+}
+
+/* Vertex Groups */
+
+#define RNA_GP_MOD_VGROUP_NAME_SET(_type, _prop) \
+static void rna_##_type##GpencilModifier_##_prop##_set(PointerRNA *ptr, const char *value) \
+{ \
+ _type##GpencilModifierData *tmd = (_type##GpencilModifierData *)ptr->data; \
+ rna_object_vgroup_name_set(ptr, value, tmd->_prop, sizeof(tmd->_prop)); \
+}
+
+RNA_GP_MOD_VGROUP_NAME_SET(Noise, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Thick, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Opacity, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Lattice, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Smooth, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Hook, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Offset, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Armature, vgname);
+
+#undef RNA_GP_MOD_VGROUP_NAME_SET
+
+/* Objects */
+
+static void greasepencil_modifier_object_set(Object *self, Object **ob_p, int type, PointerRNA value)
+{
+ Object *ob = value.data;
+
+ if (!self || ob != self) {
+ if (!ob || type == OB_EMPTY || ob->type == type) {
+ id_lib_extern((ID *)ob);
+ *ob_p = ob;
+ }
+ }
+}
+
+#define RNA_GP_MOD_OBJECT_SET(_type, _prop, _obtype) \
+static void rna_##_type##GpencilModifier_##_prop##_set(PointerRNA *ptr, PointerRNA value) \
+{ \
+ _type##GpencilModifierData *tmd = (_type##GpencilModifierData *)ptr->data; \
+ greasepencil_modifier_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \
+}
+
+RNA_GP_MOD_OBJECT_SET(Armature, object, OB_ARMATURE);
+RNA_GP_MOD_OBJECT_SET(Lattice, object, OB_LATTICE);
+RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY);
+
+#undef RNA_GP_MOD_OBJECT_SET
+
+static void rna_HookGpencilModifier_object_set(PointerRNA *ptr, PointerRNA value)
+{
+ HookGpencilModifierData *hmd = ptr->data;
+ Object *ob = (Object *)value.data;
+
+ hmd->object = ob;
+ id_lib_extern((ID *)ob);
+ BKE_object_modifier_gpencil_hook_reset(ob, hmd);
+}
+
+static void rna_TimeModifier_start_frame_set(PointerRNA *ptr, int value)
+{
+ TimeGpencilModifierData *tmd = ptr->data;
+ CLAMP(value, MINFRAME, MAXFRAME);
+ tmd->sfra = value;
+
+ if (tmd->sfra >= tmd->efra) {
+ tmd->efra = MIN2(tmd->sfra, MAXFRAME);
+ }
+}
+
+static void rna_TimeModifier_end_frame_set(PointerRNA *ptr, int value)
+{
+ TimeGpencilModifierData *tmd = ptr->data;
+ CLAMP(value, MINFRAME, MAXFRAME);
+ tmd->efra = value;
+
+ if (tmd->sfra >= tmd->efra) {
+ tmd->sfra = MAX2(tmd->efra, MINFRAME);
+ }
+}
+
+#else
+
+static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "NoiseGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Noise Modifier", "Noise effect modifier");
+ RNA_def_struct_sdna(srna, "NoiseGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_NOISE);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NoiseGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_range(prop, 0, 30.0);
+ RNA_def_property_ui_text(prop, "Factor", "Amount of noise to apply");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_USE_RANDOM);
+ RNA_def_property_ui_text(prop, "Random", "Use random values");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edit_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_LOCATION);
+ RNA_def_property_ui_text(prop, "Affect Position", "The modifier affects the position of the point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edit_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_STRENGTH);
+ RNA_def_property_ui_text(prop, "Affect Strength", "The modifier affects the color strength of the point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edit_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_THICKNESS);
+ RNA_def_property_ui_text(prop, "Affect Thickness", "The modifier affects the thickness of the point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edit_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_UV);
+ RNA_def_property_ui_text(prop, "Affect UV", "The modifier affects the UV rotation factor of the point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "full_stroke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_FULL_STROKE);
+ RNA_def_property_ui_text(prop, "Full Stroke", "The noise moves the stroke as a whole, not point by point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "move_extreme", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOVE_EXTREME);
+ RNA_def_property_ui_text(prop, "Move Extremes", "The noise moves the stroke extreme points");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(prop, "Step", "Number of frames before recalculate random values again");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilsmooth(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SmoothGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Smooth Modifier", "Smooth effect modifier");
+ RNA_def_struct_sdna(srna, "SmoothGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SmoothGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_ui_text(prop, "Factor", "Amount of smooth to apply");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edit_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_LOCATION);
+ RNA_def_property_ui_text(prop, "Affect Position", "The modifier affects the position of the point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edit_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_STRENGTH);
+ RNA_def_property_ui_text(prop, "Affect Strength", "The modifier affects the color strength of the point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edit_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_THICKNESS);
+ RNA_def_property_ui_text(prop, "Affect Thickness", "The modifier affects the thickness of the point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_edit_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_UV);
+ RNA_def_property_ui_text(prop, "Affect UV", "The modifier affects the UV rotation factor of the point");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(prop, "Step", "Number of times to apply smooth (high numbers can reduce fps)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilsubdiv(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SubdivGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Subdivision Modifier", "Subdivide Stroke modifier");
+ RNA_def_struct_sdna(srna, "SubdivGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SUBSURF);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "level", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "level");
+ RNA_def_property_range(prop, 0, 5);
+ RNA_def_property_ui_text(prop, "Level", "Number of subdivisions");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "simple", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_SIMPLE);
+ RNA_def_property_ui_text(prop, "Simple", "The modifier only add control points");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_gpencil_simplify_mode_items[] = {
+ {GP_SIMPLIFY_FIXED, "FIXED", ICON_IPO_CONSTANT, "Fixed",
+ "Delete alternative vertices in the stroke, except extrems"},
+ {GP_SIMPLIFY_ADAPTATIVE, "ADAPTATIVE", ICON_IPO_EASE_IN_OUT, "Adaptative",
+ "Use a RDP algorithm to simplify" },
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "SimplifyGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Simplify Modifier", "Simplify Stroke modifier");
+ RNA_def_struct_sdna(srna, "SimplifyGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SIMPLIFY);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_range(prop, 0, 100.0);
+ RNA_def_property_ui_range(prop, 0, 100.0, 1.0f, 3);
+ RNA_def_property_ui_text(prop, "Factor", "Factor of Simplify");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SIMPLIFY_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SIMPLIFY_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SIMPLIFY_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Mode */
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_gpencil_simplify_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How simplify the stroke");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "step");
+ RNA_def_property_range(prop, 1, 50);
+ RNA_def_property_ui_text(prop, "Iterations", "Number of times to apply simplify");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilthick(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ThickGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Thick Modifier", "Subdivide and Smooth Stroke modifier");
+ RNA_def_struct_sdna(srna, "ThickGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_THICKNESS);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ThickGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "thickness");
+ RNA_def_property_range(prop, -100, 500);
+ RNA_def_property_ui_text(prop, "Thickness", "Factor of thickness change");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_CUSTOM_CURVE);
+ RNA_def_property_ui_text(prop, "Custom Curve", "Use a custom curve to define thickness changes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "normalize_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_NORMALIZE);
+ RNA_def_property_ui_text(prop, "Normalize", "Normalize the full stroke to modifier thickness");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_thickness");
+ RNA_def_property_ui_text(prop, "Curve", "Custom Thickness Curve");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpenciloffset(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "OffsetGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Offset Modifier", "Offset Stroke modifier");
+ RNA_def_struct_sdna(srna, "OffsetGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_OFFSET);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_OffsetGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OFFSET_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OFFSET_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OFFSET_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OFFSET_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "loc");
+ RNA_def_property_ui_text(prop, "Location", "Values for change location");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
+ RNA_def_property_float_sdna(prop, NULL, "rot");
+ RNA_def_property_ui_text(prop, "Rotation", "Values for changes in rotation");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_ui_text(prop, "Scale", "Values for changes in scale");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpenciltint(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "TintGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Tint Modifier", "Tint Stroke Color modifier");
+ RNA_def_struct_sdna(srna, "TintGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_COLOR);
+
+ prop = RNA_def_property(srna, "modify_color", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_modify_color_items); /* share the enum */
+ RNA_def_property_ui_text(prop, "Mode", "Set what colors of the stroke are affected");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "rgb");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Color used for tinting");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Factor", "Factor for mixing color");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "create_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_CREATE_COLORS);
+ RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpenciltime(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "TimeGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Time Offset Modifier", "Time offset modifier");
+ RNA_def_struct_sdna(srna, "TimeGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_TIME);
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, rna_enum_time_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TIME_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TIME_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "offset", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "offset");
+ RNA_def_property_range(prop, -INT_MAX, INT_MAX);
+ RNA_def_property_ui_text(prop, "Frame Offset",
+ "Number of frames to offset original keyframe number or frame to fix");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "frame_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "frame_scale");
+ RNA_def_property_range(prop, 0.001f, 100.0f);
+ RNA_def_property_ui_text(prop, "Frame Scale", "Evaluation time in seconds");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_sdna(prop, NULL, "sfra");
+ RNA_def_property_int_funcs(prop, NULL, "rna_TimeModifier_start_frame_set", NULL);
+ RNA_def_property_range(prop, MINFRAME, MAXFRAME);
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Start Frame", "First frame of the range");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_TIME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_sdna(prop, NULL, "efra");
+ RNA_def_property_int_funcs(prop, NULL, "rna_TimeModifier_end_frame_set", NULL);
+ RNA_def_property_range(prop, MINFRAME, MAXFRAME);
+ RNA_def_property_int_default(prop, 250);
+ RNA_def_property_ui_text(prop, "End Frame", "Final frame of the range");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_keep_loop", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TIME_KEEP_LOOP);
+ RNA_def_property_ui_text(prop, "Keep Loop",
+ "Retiming end frames and move to start of animation to keep loop");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_custom_frame_range", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TIME_CUSTOM_RANGE);
+ RNA_def_property_ui_text(prop, "Custom Range",
+ "Define a custom range of frames to use in modifier");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilcolor(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ColorGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Hue/Saturation Modifier", "Change Hue/Saturation modifier");
+ RNA_def_struct_sdna(srna, "ColorGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_TINT);
+
+ prop = RNA_def_property(srna, "modify_color", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_modify_color_items); /* share the enum */
+ RNA_def_property_ui_text(prop, "Mode", "Set what colors of the stroke are affected");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "hue", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3);
+ RNA_def_property_float_sdna(prop, NULL, "hsv[0]");
+ RNA_def_property_ui_text(prop, "Hue", "Color Hue");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3);
+ RNA_def_property_float_sdna(prop, NULL, "hsv[1]");
+ RNA_def_property_ui_text(prop, "Saturation", "Color Saturation");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3);
+ RNA_def_property_float_sdna(prop, NULL, "hsv[2]");
+ RNA_def_property_ui_text(prop, "Value", "Color Value");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "create_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_CREATE_COLORS);
+ RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "OpacityGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Opacity Modifier", "Opacity of Strokes modifier");
+ RNA_def_struct_sdna(srna, "OpacityGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_OPACITY);
+
+ prop = RNA_def_property(srna, "modify_color", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_modify_color_items); /* share the enum */
+ RNA_def_property_ui_text(prop, "Mode", "Set what colors of the stroke are affected");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_OpacityGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Factor", "Factor of Opacity");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "create_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_CREATE_COLORS);
+ RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilinstance(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ArrayGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Instance Modifier", "Create grid of duplicate instances");
+ RNA_def_struct_sdna(srna, "ArrayGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_ARRAY);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "count", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_ui_range(prop, 1, 50, 1, -1);
+ RNA_def_property_ui_text(prop, "Count", "Number of items");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Offset parameters */
+ prop = RNA_def_property(srna, "offset_object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "object");
+ RNA_def_property_ui_text(prop, "Object Offset",
+ "Use the location and rotation of another object to determine the distance and "
+ "rotational change between arrayed items");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "offset");
+ RNA_def_property_ui_text(prop, "Offset", "Value for the distance between items");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "shift", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_float_sdna(prop, NULL, "shift");
+ RNA_def_property_ui_text(prop, "Shift", "Shiftness value");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
+ RNA_def_property_float_sdna(prop, NULL, "rot");
+ RNA_def_property_ui_text(prop, "Rotation", "Value for changes in rotation");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_ui_text(prop, "Scale", "Value for changes in scale");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random_rot", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_RANDOM_ROT);
+ RNA_def_property_ui_text(prop, "Random Rotation", "Use random factors for rotation");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "rot_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rnd_rot");
+ RNA_def_property_ui_text(prop, "Rotation Factor", "Random factor for rotation");
+ RNA_def_property_range(prop, -10.0, 10.0);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "random_scale", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_RANDOM_SIZE);
+ RNA_def_property_ui_text(prop, "Random Scale", "Use random factors for scale");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "scale_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rnd_size");
+ RNA_def_property_ui_text(prop, "Scale Factor", "Random factor for scale");
+ RNA_def_property_range(prop, -10.0, 10.0);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "replace_material", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "mat_rpl");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Material", "Index of the material used for generated strokes (0 keep original material)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "keep_on_top", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_KEEP_ONTOP);
+ RNA_def_property_ui_text(prop, "Keep On Top",
+ "Keep the original stroke in front of new instances (only affect by layer)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilbuild(BlenderRNA *brna)
+{
+ static EnumPropertyItem prop_gpencil_build_mode_items[] = {
+ {GP_BUILD_MODE_SEQUENTIAL, "SEQUENTIAL", ICON_PARTICLE_POINT, "Sequential",
+ "Strokes appear/disappear one after the other, but only a single one changes at a time"},
+ {GP_BUILD_MODE_CONCURRENT, "CONCURRENT", ICON_PARTICLE_TIP, "Concurrent",
+ "Multiple strokes appear/disappear at once"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_gpencil_build_transition_items[] = {
+ {GP_BUILD_TRANSITION_GROW, "GROW", 0, "Grow",
+ "Show points in the order they occur in each stroke "
+ "(e.g. for animating lines being drawn)"},
+ {GP_BUILD_TRANSITION_SHRINK, "SHRINK", 0, "Shrink",
+ "Hide points from the end of each stroke to the start "
+ "(e.g. for animating lines being erased)"},
+ {GP_BUILD_TRANSITION_FADE, "FADE", 0, "Fade",
+ "Hide points in the order they occur in each stroke "
+ "(e.g. for animating ink fading or vanishing after getting drawn)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_gpencil_build_time_align_items[] = {
+ {GP_BUILD_TIMEALIGN_START, "START", 0, "Align Start",
+ "All strokes start at same time (i.e. short strokes finish earlier)"},
+ {GP_BUILD_TIMEALIGN_END, "END", 0, "Align End",
+ "All strokes end at same time (i.e. short strokes start later)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "BuildGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Build Modifier", "Animate strokes appearing and disappearing");
+ RNA_def_struct_sdna(srna, "BuildGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_BUILD);
+
+ /* Mode */
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_gpencil_build_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How many strokes are being animated at a time");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Direction */
+ prop = RNA_def_property(srna, "transition", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_gpencil_build_transition_items);
+ RNA_def_property_ui_text(prop, "Transition", "How are strokes animated (i.e. are they appearing or disappearing)");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+
+ /* Transition Onset Delay + Length */
+ prop = RNA_def_property(srna, "start_delay", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "start_delay");
+ RNA_def_property_ui_text(prop, "Start Delay", "Number of frames after each GP keyframe before the modifier has any effect");
+ RNA_def_property_range(prop, 0, MAXFRAMEF);
+ RNA_def_property_ui_range(prop, 0, 200, 1, -1);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "length");
+ RNA_def_property_ui_text(prop, "Length",
+ "Maximum number of frames that the build effect can run for "
+ "(unless another GP keyframe occurs before this time has elapsed)");
+ RNA_def_property_range(prop, 1, MAXFRAMEF);
+ RNA_def_property_ui_range(prop, 1, 1000, 1, -1);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+
+ /* Concurrent Mode Settings */
+ prop = RNA_def_property(srna, "concurrent_time_alignment", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "time_alignment");
+ RNA_def_property_enum_items(prop, prop_gpencil_build_time_align_items);
+ RNA_def_property_ui_text(prop, "Time Alignment", "When should strokes start to appear/disappear");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+
+
+ /* Time Limits */
+ prop = RNA_def_property(srna, "use_restrict_frame_range", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_RESTRICT_TIME);
+ RNA_def_property_ui_text(prop, "Restrict Frame Range", "Only modify strokes during the specified frame range");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "start_frame");
+ RNA_def_property_ui_text(prop, "Start Frame", "Start Frame (when Restrict Frame Range is enabled)");
+ RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "end_frame");
+ RNA_def_property_ui_text(prop, "End Frame", "End Frame (when Restrict Frame Range is enabled)");
+ RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+
+ /* Filters - Layer */
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencillattice(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LatticeGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Lattice Modifier", "Change stroke using lattice to deform modifier");
+ RNA_def_struct_sdna(srna, "LatticeGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_LATTICE);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_LatticeGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LATTICE_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LATTICE_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LATTICE_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LATTICE_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Lattice object to deform with");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_LatticeGpencilModifier_object_set", NULL, "rna_Lattice_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 10, 2);
+ RNA_def_property_ui_text(prop, "Strength", "Strength of modifier effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilmirror(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MirrorGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Mirror Modifier", "Change stroke using lattice to deform modifier");
+ RNA_def_struct_sdna(srna, "MirrorGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_MIRROR);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Object used as center");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_MirrorGpencilModifier_object_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "clip", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_CLIPPING);
+ RNA_def_property_ui_text(prop, "Clip", "Clip points");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "x_axis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_X);
+ RNA_def_property_ui_text(prop, "X", "Mirror this axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "y_axis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_Y);
+ RNA_def_property_ui_text(prop, "Y", "Mirror this axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "z_axis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_Z);
+ RNA_def_property_ui_text(prop, "Z", "Mirror this axis");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "HookGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Hook Modifier", "Hook modifier to modify the location of stroke points");
+ RNA_def_struct_sdna(srna, "HookGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_HOOK);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_HookGpencilModifier_object_set", NULL, NULL);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "subtarget");
+ RNA_def_property_ui_text(prop, "Sub-Target",
+ "Name of Parent Bone for hook (if applicable), also recalculates and clears offset");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_HookGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "force");
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_text(prop, "Strength", "Relative force of the hook");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_gphook_falloff_items); /* share the enum */
+ RNA_def_property_ui_text(prop, "Falloff Type", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "falloff_radius", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "falloff");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 100, 100, 2);
+ RNA_def_property_ui_text(prop, "Radius", "If not zero, the distance from the hook where influence ends");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Lamp Falloff Curve");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "cent");
+ RNA_def_property_ui_text(prop, "Hook Center", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_float_sdna(prop, NULL, "parentinv");
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target");
+ RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_falloff_uniform", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_UNIFORM_SPACE);
+ RNA_def_property_ui_text(prop, "Uniform Falloff", "Compensate for non-uniform object scale");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
+static void rna_def_modifier_gpencilarmature(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ArmatureGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Armature Modifier", "Change stroke using armature to deform modifier");
+ RNA_def_struct_sdna(srna, "ArmatureGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_ARMATURE);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Armature object to deform with");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_ArmatureGpencilModifier_object_set", NULL, "rna_Armature_object_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_ENVELOPE);
+ RNA_def_property_ui_text(prop, "Use Bone Envelopes", "Bind Bone envelopes to armature modifier");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "use_vertex_groups", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_VGROUP);
+ RNA_def_property_ui_text(prop, "Use Vertex Groups", "Bind vertex groups to armature modifier");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "use_deform_preserve_volume", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_QUATERNION);
+ RNA_def_property_ui_text(prop, "Preserve Volume", "Deform rotation interpolation with quaternions");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+#if 0 /* GPXX keep disabled now */
+ prop = RNA_def_property(srna, "use_multi_modifier", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "multi", 0);
+ RNA_def_property_ui_text(prop, "Multi Modifier",
+ "Use same input as previous modifier, and mix results using overall vgroup");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+#endif
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group",
+ "Name of Vertex Group which determines influence of modifier per point");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ArmatureGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+}
+
+void RNA_def_greasepencil_modifier(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* data */
+ srna = RNA_def_struct(brna, "GpencilModifier", NULL);
+ RNA_def_struct_ui_text(srna, "GpencilModifier", "Modifier affecting the grease pencil object");
+ RNA_def_struct_refine_func(srna, "rna_GpencilModifier_refine");
+ RNA_def_struct_path_func(srna, "rna_GpencilModifier_path");
+ RNA_def_struct_sdna(srna, "GpencilModifierData");
+
+ /* strings */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GpencilModifier_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Modifier name");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER | NA_RENAME, NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ /* enums */
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, rna_enum_object_greasepencil_modifier_type_items);
+ RNA_def_property_ui_text(prop, "Type", "");
+
+ /* flags */
+ prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Realtime);
+ RNA_def_property_ui_text(prop, "Realtime", "Display modifier in viewport");
+ RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_ON, 1);
+
+ prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Render);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Render", "Use modifier during render");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_ON, 1);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Editmode);
+ RNA_def_property_ui_text(prop, "Edit Mode", "Display modifier in Edit mode");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0);
+
+ prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Expanded);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface");
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
+
+ /* types */
+ rna_def_modifier_gpencilnoise(brna);
+ rna_def_modifier_gpencilsmooth(brna);
+ rna_def_modifier_gpencilsubdiv(brna);
+ rna_def_modifier_gpencilsimplify(brna);
+ rna_def_modifier_gpencilthick(brna);
+ rna_def_modifier_gpenciloffset(brna);
+ rna_def_modifier_gpenciltint(brna);
+ rna_def_modifier_gpenciltime(brna);
+ rna_def_modifier_gpencilcolor(brna);
+ rna_def_modifier_gpencilinstance(brna);
+ rna_def_modifier_gpencilbuild(brna);
+ rna_def_modifier_gpencilopacity(brna);
+ rna_def_modifier_gpencillattice(brna);
+ rna_def_modifier_gpencilmirror(brna);
+ rna_def_modifier_gpencilhook(brna);
+ rna_def_modifier_gpencilarmature(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c
deleted file mode 100644
index 87e35ca4102..00000000000
--- a/source/blender/makesrna/intern/rna_group.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * ***** 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/makesrna/intern/rna_group.c
- * \ingroup RNA
- */
-
-#include <stdlib.h>
-
-#include "DNA_group_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "RNA_define.h"
-
-#include "rna_internal.h"
-
-#include "WM_types.h"
-
-#ifdef RNA_RUNTIME
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-
-#include "BKE_group.h"
-
-#include "WM_api.h"
-
-static PointerRNA rna_Group_objects_get(CollectionPropertyIterator *iter)
-{
- ListBaseIterator *internal = &iter->internal.listbase;
-
- /* we are actually iterating a GroupObject list, so override get */
- return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((GroupObject *)internal->link)->ob);
-}
-
-static void rna_Group_objects_link(Group *group, bContext *C, ReportList *reports, Object *object)
-{
- if (!BKE_group_object_add(group, object, CTX_data_scene(C), NULL)) {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' already in group '%s'", object->id.name + 2, group->id.name + 2);
- return;
- }
-
- WM_main_add_notifier(NC_OBJECT | ND_DRAW, &object->id);
-}
-
-static void rna_Group_objects_unlink(Group *group, bContext *C, ReportList *reports, Object *object)
-{
- Main *bmain = CTX_data_main(C);
- if (!BKE_group_object_unlink(bmain, group, object, CTX_data_scene(C), NULL)) {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' not in group '%s'", object->id.name + 2, group->id.name + 2);
- return;
- }
-
- WM_main_add_notifier(NC_OBJECT | ND_DRAW, &object->id);
-}
-
-#else
-
-/* group.objects */
-static void rna_def_group_objects(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
-/* PropertyRNA *prop; */
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "GroupObjects");
- srna = RNA_def_struct(brna, "GroupObjects", NULL);
- RNA_def_struct_sdna(srna, "Group");
- RNA_def_struct_ui_text(srna, "Group Objects", "Collection of group objects");
-
- /* add object */
- func = RNA_def_function(srna, "link", "rna_Group_objects_link");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Add this object to a group");
- /* object to add */
- parm = RNA_def_pointer(func, "object", "Object", "", "Object to add");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
-
- /* remove object */
- func = RNA_def_function(srna, "unlink", "rna_Group_objects_unlink");
- RNA_def_function_ui_description(func, "Remove this object to a group");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
- /* object to remove */
- parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-}
-
-
-void RNA_def_group(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "Group", "ID");
- RNA_def_struct_ui_text(srna, "Group", "Group of Object data-blocks");
- RNA_def_struct_ui_icon(srna, ICON_GROUP);
- /* this is done on save/load in readfile.c, removed if no objects are in the group */
- RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
-
- prop = RNA_def_property(srna, "dupli_offset", PROP_FLOAT, PROP_TRANSLATION);
- RNA_def_property_float_sdna(prop, NULL, "dupli_ofs");
- RNA_def_property_ui_text(prop, "Dupli Offset", "Offset from the origin to use when instancing as DupliGroup");
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, RNA_TRANSLATION_PREC_DEFAULT);
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER);
- RNA_def_property_boolean_sdna(prop, NULL, "layer", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_ui_text(prop, "Dupli Layers", "Layers visible when this group is instanced as a dupli");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "gobject", NULL);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_ui_text(prop, "Objects", "A collection of this groups objects");
- RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_Group_objects_get", NULL, NULL, NULL, NULL);
-
- rna_def_group_objects(brna, prop);
-
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 018a4765cd0..9d3699e220e 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -33,9 +33,10 @@
#include "BLI_math_base.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -66,23 +67,11 @@ static const EnumPropertyItem image_source_items[] = {
#include "BKE_global.h"
#include "GPU_draw.h"
+#include "GPU_texture.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-static void rna_Image_animated_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Image *ima = (Image *)ptr->data;
- int nr;
-
- if (ima->flag & IMA_TWINANIM) {
- nr = ima->xrep * ima->yrep;
- if (ima->twsta >= nr) ima->twsta = 1;
- if (ima->twend >= nr) ima->twend = nr - 1;
- if (ima->twsta > ima->twend) ima->twsta = 1;
- }
-}
-
static bool rna_Image_is_stereo_3d_get(PointerRNA *ptr)
{
return BKE_image_is_stereo((Image *)ptr->data);
@@ -104,31 +93,10 @@ static void rna_Image_source_set(PointerRNA *ptr, int value)
if (value != ima->source) {
ima->source = value;
- BLI_assert(BKE_id_is_in_gobal_main(&ima->id));
+ BLI_assert(BKE_id_is_in_global_main(&ima->id));
BKE_image_signal(G_MAIN, ima, NULL, IMA_SIGNAL_SRC_CHANGE);
- DAG_id_tag_update(&ima->id, 0);
- }
-}
-
-static void rna_Image_fields_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Image *ima = ptr->id.data;
- ImBuf *ibuf;
- void *lock;
-
- ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
-
- if (ibuf) {
- short nr = 0;
-
- if (!(ima->flag & IMA_FIELDS) && (ibuf->flags & IB_fields)) nr = 1;
- if ((ima->flag & IMA_FIELDS) && !(ibuf->flags & IB_fields)) nr = 1;
-
- if (nr)
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_FREE);
+ DEG_id_tag_update(&ima->id, 0);
}
-
- BKE_image_release_ibuf(ima, ibuf, lock);
}
static void rna_Image_reload_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -136,7 +104,7 @@ static void rna_Image_reload_update(Main *bmain, Scene *UNUSED(scene), PointerRN
Image *ima = ptr->id.data;
BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
}
static void rna_Image_generated_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -149,7 +117,7 @@ static void rna_Image_colormanage_update(Main *bmain, Scene *UNUSED(scene), Poin
{
Image *ima = ptr->id.data;
BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
}
@@ -175,11 +143,11 @@ static void rna_ImageUser_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *
{
ImageUser *iuser = ptr->data;
- BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
+ BKE_image_user_frame_calc(iuser, scene->r.cfra);
if (ptr->id.data) {
/* Update material or texture for render preview. */
- DAG_id_tag_update(ptr->id.data, 0);
+ DEG_id_tag_update(ptr->id.data, 0);
}
}
@@ -311,6 +279,13 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
BKE_image_release_ibuf(im, ibuf, lock);
}
+static int rna_Image_bindcode_get(PointerRNA *ptr)
+{
+ Image *ima = (Image *)ptr->data;
+ GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D];
+ return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
+}
+
static int rna_Image_depth_get(PointerRNA *ptr)
{
Image *im = (Image *)ptr->data;
@@ -467,16 +442,19 @@ static PointerRNA rna_Image_packed_file_get(PointerRNA *ptr)
}
}
-static void rna_Image_render_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+static void rna_RenderSlot_clear(ID *id, RenderSlot *slot, ImageUser *iuser)
{
- Image *image = (Image *)ptr->id.data;
- rna_iterator_array_begin(iter, (void *)image->render_slots, sizeof(RenderSlot), IMA_MAX_RENDER_SLOT, 0, NULL);
+ Image *image = (Image *) id;
+ int index = BLI_findindex(&image->renderslots, slot);
+ BKE_image_clear_renderslot(image, iuser, index);
+
+ WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, image);
}
static PointerRNA rna_render_slots_active_get(PointerRNA *ptr)
{
Image *image = (Image *)ptr->id.data;
- RenderSlot *render_slot = &image->render_slots[image->render_slot];
+ RenderSlot *render_slot = BKE_image_get_renderslot(image, image->render_slot);
return rna_pointer_inherit_refine(ptr, &RNA_RenderSlot, render_slot);
}
@@ -485,9 +463,9 @@ static void rna_render_slots_active_set(PointerRNA *ptr, PointerRNA value)
{
Image *image = (Image *)ptr->id.data;
if (value.id.data == image) {
- RenderSlot *render_slot = (RenderSlot *)value.data;
- int index = render_slot - image->render_slots;
- image->render_slot = CLAMPIS(index, 0, IMA_MAX_RENDER_SLOT - 1);
+ RenderSlot *slot = (RenderSlot *)value.data;
+ int index = BLI_findindex(&image->renderslots, slot);
+ if (index != -1) image->render_slot = index;
}
}
@@ -500,8 +478,17 @@ static int rna_render_slots_active_index_get(PointerRNA *ptr)
static void rna_render_slots_active_index_set(PointerRNA *ptr, int value)
{
Image *image = (Image *)ptr->id.data;
+ int num_slots = BLI_listbase_count(&image->renderslots);
image->render_slot = value;
- CLAMP(image->render_slot, 0, IMA_MAX_RENDER_SLOT - 1);
+ CLAMP(image->render_slot, 0, num_slots - 1);
+}
+
+static void rna_render_slots_active_index_range(PointerRNA *ptr, int *min, int *max,
+ int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Image *image = (Image *)ptr->id.data;
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&image->renderslots) - 1);
}
#else
@@ -554,13 +541,6 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_ImageUser_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- prop = RNA_def_property(srna, "fields_per_frame", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "fie_ima");
- RNA_def_property_range(prop, 1, 200);
- RNA_def_property_ui_text(prop, "Fields per Frame", "Number of fields per rendered frame (2 fields is 1 image)");
- RNA_def_property_update(prop, 0, "rna_ImageUser_update");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
prop = RNA_def_property(srna, "multilayer_layer", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "layer");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
@@ -601,7 +581,9 @@ static void rna_def_image_packed_files(BlenderRNA *brna)
static void rna_def_render_slot(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop;
+ PropertyRNA *prop, *parm;
+ FunctionRNA *func;
+
srna = RNA_def_struct(brna, "RenderSlot", NULL);
RNA_def_struct_ui_text(srna, "Render Slot", "Parameters defining the render slot");
@@ -609,32 +591,45 @@ static void rna_def_render_slot(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "Name", "Render slot name");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+
+ func = RNA_def_function(srna, "clear", "rna_RenderSlot_clear");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_ui_description(func, "Clear the render slot");
+ parm = RNA_def_pointer(func, "iuser", "ImageUser", "ImageUser", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
-static void rna_def_render_slots(BlenderRNA *brna)
+static void rna_def_render_slots(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
- PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *prop, *parm;
+ RNA_def_property_srna(cprop, "RenderSlots");
srna = RNA_def_struct(brna, "RenderSlots", NULL);
- RNA_def_struct_sdna(srna, "RenderSlot");
- RNA_def_struct_ui_text(srna, "Render Slots", "Collection of the render slots");
+ RNA_def_struct_sdna(srna, "Image");
+ RNA_def_struct_ui_text(srna, "Render Layers", "Collection of render layers");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "render_slot");
+ RNA_def_property_int_funcs(prop, "rna_render_slots_active_index_get",
+ "rna_render_slots_active_index_set",
+ "rna_render_slots_active_index_range");
+ RNA_def_property_ui_text(prop, "Active", "Active render slot of the image");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "RenderSlot");
RNA_def_property_pointer_funcs(prop, "rna_render_slots_active_get", "rna_render_slots_active_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active", "Active render slot of the image");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_NONE);
- RNA_def_property_int_funcs(prop, "rna_render_slots_active_index_get",
- "rna_render_slots_active_index_set",
- NULL);
- RNA_def_property_range(prop, 0, IMA_MAX_RENDER_SLOT);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Active Index", "Index of an active render slot of the image");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+ func = RNA_def_function(srna, "new", "BKE_image_add_renderslot");
+ RNA_def_function_ui_description(func, "Add a render slot to the image");
+ parm = RNA_def_string(func, "name", NULL, 0, "Name", "New name for the render slot");
+ parm = RNA_def_pointer(func, "result", "RenderSlot", "", "Newly created render layer");
+ RNA_def_function_return(func, parm);
}
static void rna_def_image(BlenderRNA *brna)
@@ -649,16 +644,6 @@ static void rna_def_image(BlenderRNA *brna)
{IMA_TYPE_COMPOSITE, "COMPOSITING", 0, "Compositing", ""},
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem prop_mapping_items[] = {
- {0, "UV", 0, "UV Coordinates", "Use UV coordinates for mapping the image"},
- {IMA_REFLECT, "REFLECTION", 0, "Reflection", "Use reflection mapping for mapping the image"},
- {0, NULL, 0, NULL, NULL}
- };
- static const EnumPropertyItem prop_field_order_items[] = {
- {0, "EVEN", 0, "Upper First", "Upper field first"},
- {IMA_STD_FIELD, "ODD", 0, "Lower First", "Lower field first"},
- {0, NULL, 0, NULL, NULL}
- };
static const EnumPropertyItem alpha_mode_items[] = {
{IMA_ALPHA_STRAIGHT, "STRAIGHT", 0, "Straight", "Transparent RGB and alpha pixels are unmodified"},
{IMA_ALPHA_PREMUL, "PREMUL", 0, "Premultiplied", "Transparent RGB pixels are multiplied by the alpha channel"},
@@ -670,6 +655,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_IMAGE_DATA);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "File Name", "Image/Movie file name");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
@@ -708,51 +694,44 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Packed Files", "Collection of packed images");
- prop = RNA_def_property(srna, "field_order", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, prop_field_order_items);
- RNA_def_property_ui_text(prop, "Field Order", "Order of video fields (select which lines are displayed first)");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
- /* booleans */
- prop = RNA_def_property(srna, "use_fields", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS);
- RNA_def_property_ui_text(prop, "Fields", "Use fields of the image");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_fields_update");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
-
prop = RNA_def_property(srna, "use_view_as_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_VIEW_AS_RENDER);
RNA_def_property_ui_text(prop, "View as Render", "Apply render part of display transformation when displaying this image on the screen");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA);
RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information from the image or make image fully opaque");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DEINTERLACE);
RNA_def_property_ui_text(prop, "Deinterlace", "Deinterlace movie file on load");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_USE_VIEWS);
RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_is_stereo_3d_get", NULL);
RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_is_multiview_get", NULL);
RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dirty", "Image has changed and is not saved");
@@ -794,14 +773,8 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- /* realtime properties */
- prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, prop_mapping_items);
- RNA_def_property_ui_text(prop, "Mapping", "Mapping type to use for this image in the game engine");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
prop = RNA_def_property(srna, "display_aspect", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_float_sdna(prop, NULL, "aspx");
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.1f, FLT_MAX);
@@ -809,69 +782,17 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display Aspect", "Display Aspect for this image, does not affect rendering");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
- prop = RNA_def_property(srna, "use_animation", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_TWINANIM);
- RNA_def_property_ui_text(prop, "Animated", "Use as animated texture in the game engine");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update");
-
- prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "twsta");
- RNA_def_property_range(prop, 0, 255);
- RNA_def_property_ui_text(prop, "Animation Start", "Start frame of an animated texture");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update");
-
- prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "twend");
- RNA_def_property_range(prop, 0, 255);
- RNA_def_property_ui_text(prop, "Animation End", "End frame of an animated texture");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update");
-
- prop = RNA_def_property(srna, "fps", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "animspeed");
- RNA_def_property_range(prop, 1, 100);
- RNA_def_property_ui_text(prop, "Animation Speed", "Speed of the animation in frames per second");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
- prop = RNA_def_property(srna, "use_tiles", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_TILES);
- RNA_def_property_ui_text(prop, "Tiles",
- "Use of tilemode for faces (default shift-LMB to pick the tile for selected faces)");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
- prop = RNA_def_property(srna, "tiles_x", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "xrep");
- RNA_def_property_range(prop, 1, 16);
- RNA_def_property_ui_text(prop, "Tiles X", "Degree of repetition in the X direction");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
- prop = RNA_def_property(srna, "tiles_y", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "yrep");
- RNA_def_property_range(prop, 1, 16);
- RNA_def_property_ui_text(prop, "Tiles Y", "Degree of repetition in the Y direction");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
- prop = RNA_def_property(srna, "use_clamp_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_CLAMP_U);
- RNA_def_property_ui_text(prop, "Clamp X", "Disable texture repeating horizontally");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
- prop = RNA_def_property(srna, "use_clamp_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_CLAMP_V);
- RNA_def_property_ui_text(prop, "Clamp Y", "Disable texture repeating vertically");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
-
prop = RNA_def_property(srna, "bindcode", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "bindcode");
+ RNA_def_property_int_funcs(prop, "rna_Image_bindcode_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Bindcode", "OpenGL bindcode");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "render_slots", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "RenderSlot");
+ RNA_def_property_collection_sdna(prop, NULL, "renderslots", NULL);
RNA_def_property_ui_text(prop, "Render Slots", "Render slots of the image");
- RNA_def_property_collection_funcs(prop, "rna_Image_render_slots_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
- RNA_def_property_srna(prop, "RenderSlots");
+ rna_def_render_slots(brna, prop);
/*
* Image.has_data and Image.depth are temporary,
@@ -894,6 +815,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_float_vector(srna, "resolution", 2, NULL, 0, 0, "Resolution", "X/Y pixels per meter", 0, 0);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_float_funcs(prop, "rna_Image_resolution_get", "rna_Image_resolution_set", NULL);
prop = RNA_def_property(srna, "frame_duration", PROP_INT, PROP_UNSIGNED);
@@ -928,12 +850,14 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_enum_items(prop, alpha_mode_items);
RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
/* multiview */
prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_enum_sdna(prop, NULL, "views_format");
RNA_def_property_enum_items(prop, rna_enum_views_format_items);
RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
@@ -951,7 +875,6 @@ static void rna_def_image(BlenderRNA *brna)
void RNA_def_image(BlenderRNA *brna)
{
rna_def_render_slot(brna);
- rna_def_render_slots(brna);
rna_def_image(brna);
rna_def_imageuser(brna);
rna_def_image_packed_files(brna);
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index dc625ca8d9a..d6b7cabc335 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -56,9 +56,6 @@
#include "IMB_imbuf.h"
#include "IMB_colormanagement.h"
-#include "GPU_draw.h"
-#include "GPU_debug.h"
-
#include "DNA_image_types.h"
#include "DNA_scene_types.h"
@@ -225,18 +222,18 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int filter, int mag)
{
- ImBuf *ibuf;
- unsigned int *bind = &image->bindcode[TEXTARGET_TEXTURE_2D];
+ GPUTexture *tex = image->gputexture[TEXTARGET_TEXTURE_2D];
int error = GL_NO_ERROR;
- ImageUser iuser = {NULL};
- void *lock;
- if (*bind)
+ if (tex)
return error;
+
+ ImageUser iuser = {NULL};
iuser.framenr = frame;
iuser.ok = true;
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
/* clean glError buffer */
while (glGetError() != GL_NO_ERROR) {}
@@ -247,17 +244,22 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
return (int)GL_INVALID_OPERATION;
}
- GPU_create_gl_tex(bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D,
+ unsigned int bindcode = 0;
+ GPU_create_gl_tex(&bindcode, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D,
(filter != GL_NEAREST && filter != GL_LINEAR), false, image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag);
+ /* TODO(merwin): validate input (dimensions, filter, mag) before calling OpenGL
+ * instead of trusting input & testing for error after */
error = glGetError();
if (error) {
- glDeleteTextures(1, (GLuint *)bind);
- image->bindcode[TEXTARGET_TEXTURE_2D] = 0;
+ glDeleteTextures(1, (GLuint *)&bindcode);
+ }
+ else {
+ image->gputexture[TEXTARGET_TEXTURE_2D] = GPU_texture_from_bindcode(GL_TEXTURE_2D, bindcode);
}
BKE_image_release_ibuf(image, ibuf, lock);
@@ -267,12 +269,11 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame, int filter, int mag)
{
- unsigned int *bind = &image->bindcode[TEXTARGET_TEXTURE_2D];
int error = GL_NO_ERROR;
BKE_image_tag_time(image);
- if (*bind == 0)
+ if (image->gputexture[TEXTARGET_TEXTURE_2D] == NULL)
error = rna_Image_gl_load(image, reports, frame, filter, mag);
return error;
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index c3ccdc6f446..155c030587d 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -35,13 +35,19 @@
#define RNA_MAGIC ((int)~0)
+struct Depsgraph;
+struct FreestyleSettings;
struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct IDProperty;
struct Main;
struct Mesh;
struct Object;
struct ReportList;
struct SDNA;
+struct ViewLayer;
/* Data structures used during define */
@@ -136,6 +142,7 @@ 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_collections(struct BlenderRNA *brna);
void RNA_def_color(struct BlenderRNA *brna);
void RNA_def_constraint(struct BlenderRNA *brna);
void RNA_def_context(struct BlenderRNA *brna);
@@ -145,12 +152,12 @@ void RNA_def_depsgraph(struct BlenderRNA *brna);
void RNA_def_dynamic_paint(struct BlenderRNA *brna);
void RNA_def_fluidsim(struct BlenderRNA *brna);
void RNA_def_fcurve(struct BlenderRNA *brna);
-void RNA_def_gameproperty(struct BlenderRNA *brna);
void RNA_def_gpencil(struct BlenderRNA *brna);
-void RNA_def_group(struct BlenderRNA *brna);
+void RNA_def_greasepencil_modifier(struct BlenderRNA *brna);
+void RNA_def_shader_fx(struct BlenderRNA *brna);
void RNA_def_image(struct BlenderRNA *brna);
void RNA_def_key(struct BlenderRNA *brna);
-void RNA_def_lamp(struct BlenderRNA *brna);
+void RNA_def_light(struct BlenderRNA *brna);
void RNA_def_lattice(struct BlenderRNA *brna);
void RNA_def_linestyle(struct BlenderRNA *brna);
void RNA_def_main(struct BlenderRNA *brna);
@@ -166,10 +173,12 @@ void RNA_def_packedfile(struct BlenderRNA *brna);
void RNA_def_palette(struct BlenderRNA *brna);
void RNA_def_particle(struct BlenderRNA *brna);
void RNA_def_pose(struct BlenderRNA *brna);
+void RNA_def_lightprobe(struct BlenderRNA *brna);
void RNA_def_render(struct BlenderRNA *brna);
void RNA_def_rigidbody(struct BlenderRNA *brna);
void RNA_def_rna(struct BlenderRNA *brna);
void RNA_def_scene(struct BlenderRNA *brna);
+void RNA_def_view_layer(struct BlenderRNA *brna);
void RNA_def_screen(struct BlenderRNA *brna);
void RNA_def_sculpt_paint(struct BlenderRNA *brna);
void RNA_def_sensor(struct BlenderRNA *brna);
@@ -186,6 +195,8 @@ void RNA_def_ui(struct BlenderRNA *brna);
void RNA_def_userdef(struct BlenderRNA *brna);
void RNA_def_vfont(struct BlenderRNA *brna);
void RNA_def_wm(struct BlenderRNA *brna);
+void RNA_def_wm_gizmo(struct BlenderRNA *brna);
+void RNA_def_workspace(struct BlenderRNA *brna);
void RNA_def_world(struct BlenderRNA *brna);
void RNA_def_movieclip(struct BlenderRNA *brna);
void RNA_def_tracking(struct BlenderRNA *brna);
@@ -195,6 +206,14 @@ void RNA_def_mask(struct BlenderRNA *brna);
void rna_def_animdata_common(struct StructRNA *srna);
+bool rna_AnimaData_override_apply(
+ struct Main *bmain,
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct PointerRNA *ptr_item_local, struct PointerRNA *ptr_item_reference, struct PointerRNA *ptr_item_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
@@ -205,7 +224,7 @@ void rna_def_mtex_common(struct BlenderRNA *brna, struct StructRNA *srna, const
const char *activeset, const char *activeeditable, const char *structname,
const char *structname_slots, const char *update, const char *update_index);
void rna_def_texpaint_slots(struct BlenderRNA *brna, struct StructRNA *srna);
-void rna_def_render_layer_common(struct StructRNA *srna, int scene);
+void rna_def_view_layer_common(struct StructRNA *srna, int scene);
void rna_def_actionbone_group_common(struct StructRNA *srna, int update_flag, const char *update_cb);
void rna_ActionGroup_colorset_set(struct PointerRNA *ptr, int value);
@@ -234,16 +253,40 @@ void rna_object_vcollayer_name_set(struct PointerRNA *ptr, const char *value, ch
PointerRNA rna_object_shapekey_index_get(struct ID *id, int value);
int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current);
+/* ViewLayer related functions defined in rna_scene.c but required in rna_layer.c */
+void rna_def_freestyle_settings(struct BlenderRNA *brna);
+struct PointerRNA rna_FreestyleLineSet_linestyle_get(struct PointerRNA *ptr);
+void rna_FreestyleLineSet_linestyle_set(struct PointerRNA *ptr, struct PointerRNA value);
+struct FreestyleLineSet *rna_FreestyleSettings_lineset_add(
+ struct ID *id, struct FreestyleSettings *config, struct Main *bmain, const char *name);
+void rna_FreestyleSettings_lineset_remove(
+ struct ID *id, struct FreestyleSettings *config, struct ReportList *reports, struct PointerRNA *lineset_ptr);
+struct PointerRNA rna_FreestyleSettings_active_lineset_get(struct PointerRNA *ptr);
+void rna_FreestyleSettings_active_lineset_index_range(
+ struct PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax);
+int rna_FreestyleSettings_active_lineset_index_get(struct PointerRNA *ptr);
+void rna_FreestyleSettings_active_lineset_index_set(struct PointerRNA *ptr, int value);
+struct FreestyleModuleConfig *rna_FreestyleSettings_module_add(struct ID *id, struct FreestyleSettings *config);
+void rna_FreestyleSettings_module_remove(
+ struct ID *id, struct FreestyleSettings *config, struct ReportList *reports, struct PointerRNA *module_ptr);
+
+void rna_Scene_use_view_map_cache_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
+void rna_Scene_glsl_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
+void rna_Scene_freestyle_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
+void rna_ViewLayer_name_set(struct PointerRNA *ptr, const char *value);
+void rna_ViewLayer_pass_update(struct Main *bmain, struct Scene *activescene, struct PointerRNA *ptr);
+
/* named internal so as not to conflict with obj.update() rna func */
void rna_Object_internal_update_data(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
void rna_Mesh_update_draw(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
-void rna_TextureSlot_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
+void rna_TextureSlot_update(struct bContext *C, struct PointerRNA *ptr);
/* basic poll functions for object types */
bool rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Camera_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Curve_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
-bool rna_Lamp_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
+bool rna_GPencil_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
+bool rna_Light_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Lattice_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
@@ -251,6 +294,10 @@ bool rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Action_id_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Action_actedit_assign_poll(struct PointerRNA *ptr, struct PointerRNA value);
+/* Grease Pencil datablock polling functions - for filtering GP Object vs Annotation datablocks */
+bool rna_GPencil_datablocks_annotations_poll(struct PointerRNA *ptr, const struct PointerRNA value);
+bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct PointerRNA value);
+
char *rna_TextureSlot_path(struct PointerRNA *ptr);
char *rna_Node_ImageUser_path(struct PointerRNA *ptr);
@@ -269,6 +316,8 @@ void RNA_api_image(struct StructRNA *srna);
void RNA_api_lattice(struct StructRNA *srna);
void RNA_api_operator(struct StructRNA *srna);
void RNA_api_macro(struct StructRNA *srna);
+void RNA_api_gizmo(struct StructRNA *srna);
+void RNA_api_gizmogroup(struct StructRNA *srna);
void RNA_api_keyconfig(struct StructRNA *srna);
void RNA_api_keyconfigs(struct StructRNA *srna);
void RNA_api_keyingset(struct StructRNA *srna);
@@ -281,7 +330,7 @@ void RNA_api_material(StructRNA *srna);
void RNA_api_mesh(struct StructRNA *srna);
void RNA_api_meta(struct StructRNA *srna);
void RNA_api_object(struct StructRNA *srna);
-void RNA_api_object_base(struct StructRNA *srna);
+void RNA_api_object_base_legacy(struct StructRNA *srna);
void RNA_api_pose(struct StructRNA *srna);
void RNA_api_pose_channel(struct StructRNA *srna);
void RNA_api_scene(struct StructRNA *srna);
@@ -303,6 +352,8 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_api_sound(struct StructRNA *srna);
void RNA_api_vfont(struct StructRNA *srna);
+void RNA_api_workspace(struct StructRNA *srna);
+void RNA_api_workspace_tool(struct StructRNA *srna);
/* main collection functions */
void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop);
@@ -311,7 +362,7 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop);
-void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_lights(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_libraries(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_screens(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_window_managers(BlenderRNA *brna, PropertyRNA *cprop);
@@ -323,7 +374,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop);
-void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_collections(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop);
@@ -337,6 +388,8 @@ 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);
void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_workspaces(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop);
/* ID Properties */
@@ -358,6 +411,38 @@ extern StructRNA RNA_PropertyGroup;
#endif
struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr);
+struct PropertyRNA *rna_ensure_property_realdata(struct PropertyRNA **prop, struct PointerRNA *ptr);
+
+/* Override default callbacks. */
+/* Default override callbacks for all types. */
+/* TODO: Maybe at some point we'll want to write that in direct RNA-generated code instead
+ * (like we do for default get/set/etc.)?
+ * Not obvious though, those are fairly more complicated than basic SDNA access.
+ */
+int rna_property_override_diff_default(
+ struct Main *bmain,
+ struct PointerRNA *ptr_a, struct PointerRNA *ptr_b,
+ struct PropertyRNA *prop_a, struct PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ struct IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed);
+
+bool rna_property_override_store_default(
+ struct Main *bmain,
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
+bool rna_property_override_apply_default(
+ struct Main *bmain,
+ struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ struct PointerRNA *ptr_item_dst, struct PointerRNA *ptr_item_src, struct PointerRNA *ptr_item_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
/* Builtin Property Callbacks */
@@ -404,8 +489,8 @@ PointerRNA rna_pointer_inherit_refine(struct PointerRNA *ptr, struct StructRNA *
int rna_parameter_size(struct PropertyRNA *parm);
struct Mesh *rna_Main_meshes_new_from_object(
- struct Main *bmain, struct ReportList *reports, struct Scene *sce,
- struct Object *ob, bool apply_modifiers, int settings, bool calc_tessface, bool calc_undeformed);
+ struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph,
+ struct Object *ob, bool apply_modifiers, bool calc_undeformed);
/* XXX, these should not need to be defined here~! */
struct MTex *rna_mtex_texture_slots_add(struct ID *self, struct bContext *C, struct ReportList *reports);
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index f9929cec7b1..f03752968c9 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -40,20 +40,14 @@ struct PointerRNA;
struct FunctionRNA;
struct CollectionPropertyIterator;
struct bContext;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct IDProperty;
struct GHash;
struct Main;
struct Scene;
-#ifdef UNIT_TEST
-#define RNA_MAX_ARRAY_LENGTH 64
-#else
-#define RNA_MAX_ARRAY_LENGTH 32
-#endif
-
-#define RNA_MAX_ARRAY_DIMENSION 3
-
-
/* store local properties here */
#define RNA_IDP_UI "_RNA_UI"
@@ -126,6 +120,58 @@ typedef void (*PropStringSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *
typedef int (*PropEnumGetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*PropEnumSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value);
+/* Handling override operations, and also comparison. */
+
+/**
+ * If \a override is NULL, merely do comparison between prop_a from ptr_a and prop_b from ptr_b,
+ * following comparison mode given.
+ * If \a override and \a rna_path are not NULL, it will add a new override operation for overridable properties
+ * that differ and have not yet been overridden (and set accordingly \a r_override_changed if given).
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ * \note \a override, \a rna_path and \a r_override_changed may be NULL pointers.
+ */
+typedef int (*RNAPropOverrideDiff)(
+ struct Main *bmain,
+ struct PointerRNA *ptr_a, struct PointerRNA *ptr_b,
+ struct PropertyRNA *prop_a, struct PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ struct IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed);
+
+/**
+ * Only used for differential override (add, sub, etc.).
+ * Store into storage the value needed to transform reference's value into local's value.
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ * \note Might change given override operation (e.g. change 'add' one into 'sub'), in case computed storage value
+ * is out of range (or even change it to basic 'set' operation if nothing else works).
+ */
+typedef bool (*RNAPropOverrideStore)(
+ struct Main *bmain,
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
+/**
+ * Apply given override operation from src to dst (using value from storage as second operand
+ * for differential operations).
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ */
+typedef bool (*RNAPropOverrideApply)(
+ struct Main *bmain,
+ struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ struct PointerRNA *ptr_item_dst, struct PointerRNA *ptr_item_src, struct PointerRNA *ptr_item_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
/* Container - generic abstracted container of RNA properties */
typedef struct ContainerRNA {
void *next, *prev;
@@ -164,6 +210,8 @@ struct PropertyRNA {
const char *identifier;
/* various options */
int flag;
+ /* various override options */
+ int flag_override;
/* Function parameters flags. */
short flag_parameter;
/* Internal ("private") flags. */
@@ -203,6 +251,11 @@ struct PropertyRNA {
/* callback for testing if array-item editable (if applicable) */
ItemEditableFunc itemeditable;
+ /* Override handling callbacks (diff is also used for comparison). */
+ RNAPropOverrideDiff override_diff;
+ RNAPropOverrideStore override_store;
+ RNAPropOverrideApply override_apply;
+
/* raw access */
int rawoffset;
RawPropertyType rawtype;
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 6170c884b51..ed1e0d2690e 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -51,10 +51,11 @@
#include "DNA_object_types.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_key.h"
#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -486,7 +487,7 @@ static void rna_Key_update_data(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (BKE_key_from_object(ob) == key) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
}
@@ -712,7 +713,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
prop = RNA_def_property(srna, "relative_key", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ShapeKey");
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL | PROP_PTR_NO_OWNERSHIP);
RNA_def_property_pointer_funcs(prop, "rna_ShapeKey_relative_key_get",
"rna_ShapeKey_relative_key_set", NULL, NULL);
RNA_def_property_ui_text(prop, "Relative Key", "Shape used as a relative key");
@@ -721,7 +722,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYBLOCK_MUTE);
RNA_def_property_ui_text(prop, "Mute", "Mute this shape key");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_update(prop, 0, "rna_Key_update_data");
prop = RNA_def_property(srna, "slider_min", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index 1e1ae2e8183..d9bd9c42445 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -45,15 +45,16 @@
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+
#include "ED_node.h"
#include "WM_api.h"
#include "WM_types.h"
-static void rna_Lamp_buffer_size_set(PointerRNA *ptr, int value)
+static void rna_Light_buffer_size_set(PointerRNA *ptr, int value)
{
Lamp *la = (Lamp *)ptr->data;
@@ -62,295 +63,77 @@ static void rna_Lamp_buffer_size_set(PointerRNA *ptr, int value)
la->bufsize &= (~15); /* round to multiple of 16 */
}
-static PointerRNA rna_Lamp_sky_settings_get(PointerRNA *ptr)
-{
- return rna_pointer_inherit_refine(ptr, &RNA_LampSkySettings, ptr->id.data);
-}
-
-static void rna_Lamp_mtex_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- Lamp *la = (Lamp *)ptr->data;
- rna_iterator_array_begin(iter, (void *)la->mtex, sizeof(MTex *), MAX_MTEX, 0, NULL);
-}
-
-static PointerRNA rna_Lamp_active_texture_get(PointerRNA *ptr)
-{
- Lamp *la = (Lamp *)ptr->data;
- Tex *tex;
-
- tex = give_current_lamp_texture(la);
- return rna_pointer_inherit_refine(ptr, &RNA_Texture, tex);
-}
-
-static void rna_Lamp_active_texture_set(PointerRNA *ptr, PointerRNA value)
-{
- Lamp *la = (Lamp *)ptr->data;
-
- set_current_lamp_texture(la, value.data);
-}
-
-static bool rna_use_shadow_get(PointerRNA *ptr)
-{
- Lamp *la = (Lamp *)ptr->data;
-
- if (la->type == LA_SPOT) {
- return (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY)) != 0;
- }
- else {
- return (la->mode & LA_SHAD_RAY) != 0;
- }
-}
-
-static void rna_use_shadow_set(PointerRNA *ptr, bool value)
-{
- Lamp *la = (Lamp *)ptr->data;
- la->mode &= ~(LA_SHAD_BUF | LA_SHAD_RAY);
- if (value) {
- la->mode |= LA_SHAD_RAY;
- }
-}
-
-static StructRNA *rna_Lamp_refine(struct PointerRNA *ptr)
+static StructRNA *rna_Light_refine(struct PointerRNA *ptr)
{
Lamp *la = (Lamp *)ptr->data;
switch (la->type) {
case LA_LOCAL:
- return &RNA_PointLamp;
+ return &RNA_PointLight;
case LA_SUN:
- return &RNA_SunLamp;
+ return &RNA_SunLight;
case LA_SPOT:
- return &RNA_SpotLamp;
- case LA_HEMI:
- return &RNA_HemiLamp;
+ return &RNA_SpotLight;
case LA_AREA:
- return &RNA_AreaLamp;
+ return &RNA_AreaLight;
default:
- return &RNA_Lamp;
+ return &RNA_Light;
}
}
-static void rna_Lamp_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Light_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Lamp *la = ptr->id.data;
- DAG_id_tag_update(&la->id, 0);
+ DEG_id_tag_update(&la->id, 0);
WM_main_add_notifier(NC_LAMP | ND_LIGHTING, la);
}
-static void rna_Lamp_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Light_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Lamp *la = ptr->id.data;
- DAG_id_tag_update(&la->id, 0);
+ DEG_id_tag_update(&la->id, 0);
WM_main_add_notifier(NC_LAMP | ND_LIGHTING_DRAW, la);
}
-static void rna_Lamp_sky_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Lamp *la = ptr->id.data;
-
- DAG_id_tag_update(&la->id, 0);
- WM_main_add_notifier(NC_LAMP | ND_SKY, la);
-}
-
-static void rna_Lamp_use_nodes_update(bContext *C, PointerRNA *ptr)
+static void rna_Light_use_nodes_update(bContext *C, PointerRNA *ptr)
{
Lamp *la = (Lamp *)ptr->data;
if (la->use_nodes && la->nodetree == NULL)
ED_node_shader_default(C, &la->id);
- rna_Lamp_update(CTX_data_main(C), CTX_data_scene(C), ptr);
+ rna_Light_update(CTX_data_main(C), CTX_data_scene(C), ptr);
}
#else
-/* Don't define icons here, so they don't show up in the Lamp UI (properties Editor) - DingTo */
-const EnumPropertyItem rna_enum_lamp_type_items[] = {
+/* Don't define icons here, so they don't show up in the Light UI (properties Editor) - DingTo */
+const EnumPropertyItem rna_enum_light_type_items[] = {
{LA_LOCAL, "POINT", 0, "Point", "Omnidirectional point light source"},
{LA_SUN, "SUN", 0, "Sun", "Constant direction parallel ray light source"},
{LA_SPOT, "SPOT", 0, "Spot", "Directional cone light source"},
- {LA_HEMI, "HEMI", 0, "Hemi", "180 degree constant light source"},
{LA_AREA, "AREA", 0, "Area", "Directional area light source"},
{0, NULL, 0, NULL, NULL}
};
-static void rna_def_lamp_mtex(BlenderRNA *brna)
+static void rna_def_light(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+ static float default_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- static const EnumPropertyItem prop_texture_coordinates_items[] = {
- {TEXCO_GLOB, "GLOBAL", 0, "Global", "Use global coordinates for the texture coordinates"},
- {TEXCO_VIEW, "VIEW", 0, "View", "Use view coordinates for the texture coordinates"},
- {TEXCO_OBJECT, "OBJECT", 0, "Object", "Use linked object's coordinates for texture coordinates"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "LampTextureSlot", "TextureSlot");
- RNA_def_struct_sdna(srna, "MTex");
- RNA_def_struct_ui_text(srna, "Lamp Texture Slot", "Texture slot for textures in a Lamp data-block");
-
- prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "texco");
- RNA_def_property_enum_items(prop, prop_texture_coordinates_items);
- RNA_def_property_ui_text(prop, "Texture Coordinates", "");
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "object");
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Object", "Object to use for mapping with Object texture coordinates");
-
- prop = RNA_def_property(srna, "use_map_color", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", LAMAP_COL);
- RNA_def_property_ui_text(prop, "Color", "Let the texture affect the basic color of the lamp");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "use_map_shadow", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", LAMAP_SHAD);
- RNA_def_property_ui_text(prop, "Shadow", "Let the texture affect the shadow color of the lamp");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "color_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "colfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Color Factor", "Amount texture affects color values");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "shadow_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "shadowfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Shadow Factor", "Amount texture affects shadow");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-}
-
-static void rna_def_lamp_sky_settings(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_skycolorspace_items[] = {
- {0, "SMPTE", 0, "SMPTE", ""},
- {1, "REC709", 0, "REC709", ""},
- {2, "CIE", 0, "CIE", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "LampSkySettings", NULL);
+ srna = RNA_def_struct(brna, "Light", "ID");
RNA_def_struct_sdna(srna, "Lamp");
- RNA_def_struct_nested(brna, srna, "SunLamp");
- RNA_def_struct_ui_text(srna, "Lamp Sky Settings", "Sky related settings for a sun lamp");
-
- prop = RNA_def_property(srna, "sky_color_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "sky_colorspace");
- RNA_def_property_enum_items(prop, prop_skycolorspace_items);
- RNA_def_property_ui_text(prop, "Sky Color Space", "Color space to use for internal XYZ->RGB color conversion");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "sky_blend_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "skyblendtype");
- RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
- RNA_def_property_ui_text(prop, "Sky Blend Mode", "Blend mode for combining sun sky with world sky");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- /* Number values */
-
- prop = RNA_def_property(srna, "horizon_brightness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 20.0f);
- RNA_def_property_ui_text(prop, "Horizon Brightness", "Horizon brightness");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "spread", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 10.0f);
- RNA_def_property_ui_text(prop, "Horizon Spread", "Horizon Spread");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "sun_brightness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 10.0f);
- RNA_def_property_ui_text(prop, "Sun Brightness", "Sun brightness");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "sun_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 10.0f);
- RNA_def_property_ui_text(prop, "Sun Size", "Sun size");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "backscattered_light", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, -1.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Backscattered Light", "Backscattered light");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "sun_intensity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 10.0f);
- RNA_def_property_ui_text(prop, "Sun Intensity", "Sun intensity");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "atmosphere_turbidity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "atm_turbidity");
- RNA_def_property_range(prop, 1.0f, 30.0f);
- RNA_def_property_ui_range(prop, 2.0f, 10.0f, 1, 2);
- RNA_def_property_ui_text(prop, "Atmosphere Turbidity", "Sky turbidity");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "atmosphere_inscattering", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "atm_inscattering_factor");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Atmosphere Inscatter", "Scatter contribution factor");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "atmosphere_extinction", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "atm_extinction_factor");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Atmosphere Extinction", "Extinction scattering contribution factor");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "atmosphere_distance_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "atm_distance_factor");
- RNA_def_property_range(prop, 0.0f, 500.0f);
- RNA_def_property_ui_text(prop, "Atmosphere Distance Factor",
- "Multiplier to convert blender units to physical distance");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "sky_blend", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "skyblendfac");
- RNA_def_property_range(prop, 0.0f, 2.0f);
- RNA_def_property_ui_text(prop, "Sky Blend", "Blend factor with sky");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "sky_exposure", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 20.0f);
- RNA_def_property_ui_text(prop, "Sky Exposure", "Strength of sky shading exponential exposure correction");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- /* boolean */
-
- prop = RNA_def_property(srna, "use_sky", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "sun_effect_type", LA_SUN_EFFECT_SKY);
- RNA_def_property_ui_text(prop, "Sky", "Apply sun effect on sky");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-
- prop = RNA_def_property(srna, "use_atmosphere", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "sun_effect_type", LA_SUN_EFFECT_AP);
- RNA_def_property_ui_text(prop, "Atmosphere", "Apply sun effect on atmosphere");
- RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
-}
-
-static void rna_def_lamp(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "Lamp", "ID");
- RNA_def_struct_refine_func(srna, "rna_Lamp_refine");
- RNA_def_struct_ui_text(srna, "Lamp", "Lamp data-block for lighting a scene");
- RNA_def_struct_ui_icon(srna, ICON_LAMP_DATA);
+ RNA_def_struct_refine_func(srna, "rna_Light_refine");
+ RNA_def_struct_ui_text(srna, "Light", "Light data-block for lighting a scene");
+ RNA_def_struct_ui_icon(srna, ICON_LIGHT_DATA);
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_lamp_type_items);
- RNA_def_property_ui_text(prop, "Type", "Type of Lamp");
+ RNA_def_property_enum_items(prop, rna_enum_light_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of Light");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LAMP);
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "dist");
@@ -358,61 +141,59 @@ static void rna_def_lamp(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 1000, 1, 3);
RNA_def_property_ui_text(prop, "Distance",
"Falloff distance - the light is at half the original intensity at this point");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_range(prop, 0, 10, 1, 3);
- RNA_def_property_ui_text(prop, "Energy", "Amount of light that the lamp emits");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_ui_text(prop, "Energy", "Amount of light emitted");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "r");
RNA_def_property_array(prop, 3);
+ RNA_def_property_float_array_default(prop, default_color);
RNA_def_property_ui_text(prop, "Color", "Light color");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
-
- prop = RNA_def_property(srna, "use_own_layer", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_LAYER);
- RNA_def_property_ui_text(prop, "Layer", "Illuminate objects only on the same layers the lamp is on");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "use_negative", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_NEG);
- RNA_def_property_ui_text(prop, "Negative", "Cast negative light");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
- prop = RNA_def_property(srna, "use_specular", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "mode", LA_NO_SPEC);
- RNA_def_property_ui_text(prop, "Specular", "Create specular highlights");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "use_diffuse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "mode", LA_NO_DIFF);
- RNA_def_property_ui_text(prop, "Diffuse", "Do diffuse shading");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ prop = RNA_def_property(srna, "specular_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "spec_fac");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.0f, 9999.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01, 2);
+ RNA_def_property_ui_text(prop, "Specular Factor", "Specular reflection multiplier");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "use_custom_distance", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_CUSTOM_ATTENUATION);
+ RNA_def_property_ui_text(prop, "Custom Attenuation", "Use custom attenuation distance instead of global light threshold");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "cutoff_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "att_dist");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.01f, 100.0f, 1.0, 2);
+ RNA_def_property_ui_text(prop, "Cutoff Distance", "Distance at which the light influence will be set to 0");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
/* nodes */
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "nodetree");
- RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based lamps");
+ RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based lights");
prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_nodes", 1);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_ui_text(prop, "Use Nodes", "Use shader nodes to render the lamp");
- RNA_def_property_update(prop, 0, "rna_Lamp_use_nodes_update");
+ RNA_def_property_ui_text(prop, "Use Nodes", "Use shader nodes to render the light");
+ RNA_def_property_update(prop, 0, "rna_Light_use_nodes_update");
/* common */
rna_def_animdata_common(srna);
-
- /* textures */
- rna_def_mtex_common(brna, srna, "rna_Lamp_mtex_begin", "rna_Lamp_active_texture_get",
- "rna_Lamp_active_texture_set", NULL, "LampTextureSlot", "LampTextureSlots",
- "rna_Lamp_draw_update", "rna_Lamp_draw_update");
}
-static void rna_def_lamp_falloff(StructRNA *srna)
+static void rna_def_light_falloff(StructRNA *srna)
{
PropertyRNA *prop;
@@ -429,124 +210,54 @@ static void rna_def_lamp_falloff(StructRNA *srna)
prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_fallofftype_items);
RNA_def_property_ui_text(prop, "Falloff Type", "Intensity Decay with distance");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
- RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Lamp Falloff Curve");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "use_sphere", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SPHERE);
- RNA_def_property_ui_text(prop, "Sphere", "Set light intensity to zero beyond lamp distance");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom light falloff curve");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "linear_attenuation", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "att1");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Linear Attenuation", "Linear distance attenuation");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "quadratic_attenuation", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "att2");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Quadratic Attenuation", "Quadratic distance attenuation");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "constant_coefficient", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "coeff_const");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Constant Coefficient",
"Constant distance attenuation coefficient");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "linear_coefficient", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "coeff_lin");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Linear Coefficient",
"Linear distance attenuation coefficient");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "quadratic_coefficient", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "coeff_quad");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Quadratic Coefficient",
"Quadratic distance attenuation coefficient");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
}
-static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
+static void rna_def_light_shadow(StructRNA *srna, int sun)
{
PropertyRNA *prop;
- static const EnumPropertyItem prop_shadow_items[] = {
- {0, "NOSHADOW", 0, "No Shadow", ""},
- {LA_SHAD_RAY, "RAY_SHADOW", 0, "Ray Shadow", "Use ray tracing for shadow"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_spot_shadow_items[] = {
- {0, "NOSHADOW", 0, "No Shadow", ""},
- {LA_SHAD_BUF, "BUFFER_SHADOW", 0, "Buffer Shadow", "Let spotlight produce shadows using shadow buffer"},
- {LA_SHAD_RAY, "RAY_SHADOW", 0, "Ray Shadow", "Use ray tracing for shadow"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_ray_sampling_method_items[] = {
- {LA_SAMP_HALTON, "ADAPTIVE_QMC", 0, "Adaptive QMC", ""},
- {LA_SAMP_HAMMERSLEY, "CONSTANT_QMC", 0, "Constant QMC", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_spot_ray_sampling_method_items[] = {
- {LA_SAMP_HALTON, "ADAPTIVE_QMC", 0, "Adaptive QMC", ""},
- {LA_SAMP_HAMMERSLEY, "CONSTANT_QMC", 0, "Constant QMC", ""},
- {LA_SAMP_CONSTANT, "CONSTANT_JITTERED", 0, "Constant Jittered", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_shadbuftype_items[] = {
- {LA_SHADBUF_REGULAR, "REGULAR", 0, "Classical", "Classic shadow buffer"},
- {LA_SHADBUF_HALFWAY, "HALFWAY", 0, "Classic-Halfway",
- "Regular buffer, averaging the closest and 2nd closest Z value to reducing "
- "bias artifacts"},
- {LA_SHADBUF_IRREGULAR, "IRREGULAR", 0, "Irregular",
- "Irregular buffer produces sharp shadow always, but it doesn't show up for raytracing"},
- {LA_SHADBUF_DEEP, "DEEP", 0, "Deep",
- "Deep shadow buffer supports transparency and better filtering, at the cost of "
- "more memory usage and processing time"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_shadbuffiltertype_items[] = {
- {LA_SHADBUF_BOX, "BOX", 0, "Box", "Apply the Box filter to shadow buffer samples"},
- {LA_SHADBUF_TENT, "TENT", 0, "Tent", "Apply the Tent Filter to shadow buffer samples"},
- {LA_SHADBUF_GAUSS, "GAUSS", 0, "Gauss", "Apply the Gauss filter to shadow buffer samples"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_numbuffer_items[] = {
- {1, "BUFFERS_1", 0, "1", "Only one buffer rendered"},
- {4, "BUFFERS_4", 0, "4", "Render 4 buffers for better AA, this quadruples memory usage"},
- {9, "BUFFERS_9", 0, "9", "Render 9 buffers for better AA, this uses nine times more memory"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* GE only */
- static const EnumPropertyItem prop_ge_shadowbuffer_type_items[] = {
- {LA_SHADMAP_SIMPLE, "SIMPLE", 0, "Simple", "Simple shadow maps"},
- {LA_SHADMAP_VARIANCE, "VARIANCE", 0, "Variance", "Variance shadow maps"},
- {0, NULL, 0, NULL, NULL}
- };
-
prop = RNA_def_property(srna, "use_shadow", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_use_shadow_get", "rna_use_shadow_set");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
-
- prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, (spot) ? prop_spot_shadow_items : prop_shadow_items);
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHADOW);
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "shadow_buffer_size", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "bufsize");
@@ -554,158 +265,157 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
RNA_def_property_ui_text(prop, "Shadow Buffer Size",
"Resolution of the shadow buffer, higher values give crisper shadows "
"but use more memory");
- RNA_def_property_int_funcs(prop, NULL, "rna_Lamp_buffer_size_set", NULL);
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "shadow_filter_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "filtertype");
- RNA_def_property_enum_items(prop, prop_shadbuffiltertype_items);
- RNA_def_property_ui_text(prop, "Shadow Filter Type", "Type of shadow filter (Buffer Shadows)");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "shadow_sample_buffers", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "buffers");
- RNA_def_property_enum_items(prop, prop_numbuffer_items);
- RNA_def_property_ui_text(prop, "Shadow Sample Buffers",
- "Number of shadow buffers to render for better AA, this increases memory usage");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_int_funcs(prop, NULL, "rna_Light_buffer_size_set", NULL);
+ RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_buffer_clip_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipsta");
+ RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_text(prop, "Shadow Buffer Clip Start",
"Shadow map clip start, below which objects will not generate shadows");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "shadow_buffer_clip_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "clipend");
+ RNA_def_property_float_default(prop, 40.0f);
RNA_def_property_range(prop, 0.0f, 9999.0f);
RNA_def_property_ui_text(prop, "Shadow Buffer Clip End",
"Shadow map clip end, beyond which objects will not generate shadows");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "shadow_buffer_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bias");
- RNA_def_property_range(prop, 0.001f, 5.0f);
- RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Shadow buffer sampling bias");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.001f, 9999.0f);
+ RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
+ RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Bias for reducing self shadowing");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_buffer_bleed_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bleedbias");
RNA_def_property_range(prop, 0.f, 1.f);
RNA_def_property_ui_text(prop, "Shadow Buffer Bleed Bias", "Bias for reducing light-bleed on variance shadow maps");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "shadow_buffer_exp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "bleedexp");
+ RNA_def_property_float_default(prop, 2.5f);
+ RNA_def_property_range(prop, 1.0f, 9999.0f);
+ RNA_def_property_ui_text(prop, "Shadow Buffer Exponent", "Bias for reducing light-bleed on exponential shadow maps");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_buffer_soft", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "soft");
+ RNA_def_property_float_default(prop, 3.0f);
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_text(prop, "Shadow Buffer Soft", "Size of shadow buffer sampling area");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_buffer_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "samp");
RNA_def_property_range(prop, 1, 16);
RNA_def_property_ui_text(prop, "Samples", "Number of shadow buffer samples");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "shadow_buffer_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "buftype");
- RNA_def_property_enum_items(prop, prop_shadbuftype_items);
- RNA_def_property_ui_text(prop, "Shadow Buffer Type", "Type of shadow buffer");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "ge_shadow_buffer_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "shadowmap_type");
- RNA_def_property_enum_items(prop, prop_ge_shadowbuffer_type_items);
- RNA_def_property_ui_text(prop, "Shadow Map Type", "The shadow mapping algorithm used");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
-
- prop = RNA_def_property(srna, "use_auto_clip_start", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bufflag", LA_SHADBUF_AUTO_START);
- RNA_def_property_ui_text(prop, "Autoclip Start",
- "Automatic calculation of clipping-start, based on visible vertices");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
-
- prop = RNA_def_property(srna, "use_auto_clip_end", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bufflag", LA_SHADBUF_AUTO_END);
- RNA_def_property_ui_text(prop, "Autoclip End", "Automatic calculation of clipping-end, based on visible vertices");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
-
- prop = RNA_def_property(srna, "compression_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "compressthresh");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Compress", "Deep shadow map compression threshold");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "shdwr");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Shadow Color", "Color of shadows cast by the lamp");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "use_only_shadow", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_ONLYSHADOW);
- RNA_def_property_ui_text(prop, "Only Shadow", "Cast shadows only, without illuminating objects");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "shadow_ray_sample_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "ray_samp_method");
- RNA_def_property_enum_items(prop, (area) ? prop_spot_ray_sampling_method_items : prop_ray_sampling_method_items);
- RNA_def_property_ui_text(prop, "Shadow Ray Sampling Method",
- "Method for generating shadow samples: Adaptive QMC is fastest, "
- "Constant QMC is less noisy but slower");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, (area) ? "shadow_ray_samples_x" : "shadow_ray_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "ray_samp");
- RNA_def_property_range(prop, 1, 64);
- RNA_def_property_ui_text(prop, (area) ? "Shadow Ray Samples" : "Shadow Ray Samples X",
- "Number of samples taken extra (samples x samples)");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- if (area) {
- prop = RNA_def_property(srna, "shadow_ray_samples_y", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "ray_sampy");
- RNA_def_property_range(prop, 1, 64);
- RNA_def_property_ui_text(prop, "Shadow Ray Samples Y",
- "Number of samples taken extra (samples x samples)");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
- }
-
- prop = RNA_def_property(srna, "shadow_adaptive_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "adapt_thresh");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Shadow Adaptive Threshold", "Threshold for Adaptive Sampling (Raytraced shadows)");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_ui_text(prop, "Shadow Color", "Color of shadows cast by the light");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
prop = RNA_def_property(srna, "shadow_soft_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_size");
+ RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(prop, "Shadow Soft Size", "Light size for ray shadow sampling (Raytraced shadows)");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ /* Eevee */
+ prop = RNA_def_property(srna, "use_contact_shadow", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHAD_CONTACT);
+ RNA_def_property_ui_text(prop, "Contact Shadow", "Use screen space raytracing to have correct shadowing "
+ "near occluder, or for small features that does not appear "
+ "in shadow maps");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "contact_shadow_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "contact_dist");
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_range(prop, 0.0f, 9999.0f);
+ RNA_def_property_ui_text(prop, "Contact Shadow Distance", "World space distance in which to search for "
+ "screen space occluder");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "contact_shadow_bias", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "contact_bias");
+ RNA_def_property_float_default(prop, 0.03f);
+ RNA_def_property_range(prop, 0.001f, 9999.0f);
+ RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
+ RNA_def_property_ui_text(prop, "Contact Shadow Bias", "Bias to avoid self shadowing");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "contact_shadow_soft_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "contact_spread");
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_range(prop, 0.0f, 9999.0f);
+ RNA_def_property_ui_text(prop, "Contact Shadow Soft", "Control how soft the contact shadows will be");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
- prop = RNA_def_property(srna, "use_shadow_layer", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_LAYER_SHADOW);
- RNA_def_property_ui_text(prop, "Shadow Layer", "Objects on the same layers only cast shadows");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ prop = RNA_def_property(srna, "contact_shadow_thickness", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "contact_thickness");
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_range(prop, 0.0f, 9999.0f);
+ RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Contact Shadow Thickness", "Pixel thickness used to detect occlusion");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ if (sun) {
+ prop = RNA_def_property(srna, "shadow_cascade_max_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "cascade_max_dist");
+ RNA_def_property_float_default(prop, 200.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Cascade Max Distance", "End distance of the cascaded shadow map (only in perspective view)");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "shadow_cascade_count", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "cascade_count");
+ RNA_def_property_int_default(prop, 4);
+ RNA_def_property_range(prop, 1, 4);
+ RNA_def_property_ui_text(prop, "Cascade Count", "Number of texture used by the cascaded shadow map");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "shadow_cascade_exponent", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "cascade_exponent");
+ RNA_def_property_float_default(prop, 0.8f);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Exponential Distribution", "Higher value increase resolution towards the viewpoint");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+
+ prop = RNA_def_property(srna, "shadow_cascade_fade", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "cascade_fade");
+ RNA_def_property_float_default(prop, 0.1f);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Cascade Fade", "How smooth is the transition between each cascade");
+ RNA_def_property_update(prop, 0, "rna_Light_update");
+ }
}
-static void rna_def_point_lamp(BlenderRNA *brna)
+static void rna_def_point_light(BlenderRNA *brna)
{
StructRNA *srna;
- srna = RNA_def_struct(brna, "PointLamp", "Lamp");
+ srna = RNA_def_struct(brna, "PointLight", "Light");
RNA_def_struct_sdna(srna, "Lamp");
- RNA_def_struct_ui_text(srna, "Point Lamp", "Omnidirectional point lamp");
- RNA_def_struct_ui_icon(srna, ICON_LAMP_POINT);
+ RNA_def_struct_ui_text(srna, "Point Light", "Omnidirectional point Light");
+ RNA_def_struct_ui_icon(srna, ICON_LIGHT_POINT);
- rna_def_lamp_falloff(srna);
- rna_def_lamp_shadow(srna, 0, 0);
+ rna_def_light_falloff(srna);
+ rna_def_light_shadow(srna, 0);
}
-static void rna_def_area_lamp(BlenderRNA *brna)
+static void rna_def_area_light(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -713,167 +423,112 @@ static void rna_def_area_lamp(BlenderRNA *brna)
static const EnumPropertyItem prop_areashape_items[] = {
{LA_AREA_SQUARE, "SQUARE", 0, "Square", ""},
{LA_AREA_RECT, "RECTANGLE", 0, "Rectangle", ""},
+ {LA_AREA_DISK, "DISK", 0, "Disk", ""},
+ {LA_AREA_ELLIPSE, "ELLIPSE", 0, "Ellipse", ""},
{0, NULL, 0, NULL, NULL}
};
- srna = RNA_def_struct(brna, "AreaLamp", "Lamp");
+ srna = RNA_def_struct(brna, "AreaLight", "Light");
RNA_def_struct_sdna(srna, "Lamp");
- RNA_def_struct_ui_text(srna, "Area Lamp", "Directional area lamp");
- RNA_def_struct_ui_icon(srna, ICON_LAMP_AREA);
-
- rna_def_lamp_shadow(srna, 0, 1);
+ RNA_def_struct_ui_text(srna, "Area Light", "Directional area Light");
+ RNA_def_struct_ui_icon(srna, ICON_LIGHT_AREA);
- prop = RNA_def_property(srna, "use_umbra", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "ray_samp_type", LA_SAMP_UMBRA);
- RNA_def_property_ui_text(prop, "Umbra", "Emphasize parts that are fully shadowed (Constant Jittered sampling)");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "use_dither", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "ray_samp_type", LA_SAMP_DITHER);
- RNA_def_property_ui_text(prop, "Dither", "Use 2x2 dithering for sampling (Constant Jittered sampling)");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "use_jitter", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "ray_samp_type", LA_SAMP_JITTER);
- RNA_def_property_ui_text(prop, "Jitter", "Use noise for sampling (Constant Jittered sampling)");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ rna_def_light_shadow(srna, 0);
+ rna_def_light_falloff(srna);
prop = RNA_def_property(srna, "shape", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "area_shape");
RNA_def_property_enum_items(prop, prop_areashape_items);
- RNA_def_property_ui_text(prop, "Shape", "Shape of the area lamp");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_ui_text(prop, "Shape", "Shape of the area Light");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "area_size");
+ RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
- RNA_def_property_ui_text(prop, "Size", "Size of the area of the area Lamp, X direction size for Rectangle shapes");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_ui_text(prop, "Size", "Size of the area of the area light, X direction size for rectangle shapes");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "size_y", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_float_sdna(prop, NULL, "area_sizey");
+ RNA_def_property_float_default(prop, 0.25f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 0.1, 3);
RNA_def_property_ui_text(prop, "Size Y",
- "Size of the area of the area Lamp in the Y direction for Rectangle shapes");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
-
- prop = RNA_def_property(srna, "gamma", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "k");
- RNA_def_property_ui_range(prop, 0.001, 2.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Gamma", "Light gamma correction value");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ "Size of the area of the area light in the Y direction for rectangle shapes");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
}
-static void rna_def_spot_lamp(BlenderRNA *brna)
+static void rna_def_spot_light(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "SpotLamp", "Lamp");
+ srna = RNA_def_struct(brna, "SpotLight", "Light");
RNA_def_struct_sdna(srna, "Lamp");
- RNA_def_struct_ui_text(srna, "Spot Lamp", "Directional cone lamp");
- RNA_def_struct_ui_icon(srna, ICON_LAMP_SPOT);
+ RNA_def_struct_ui_text(srna, "Spot Light", "Directional cone Light");
+ RNA_def_struct_ui_icon(srna, ICON_LIGHT_SPOT);
- rna_def_lamp_falloff(srna);
- rna_def_lamp_shadow(srna, 1, 0);
+ rna_def_light_falloff(srna);
+ rna_def_light_shadow(srna, 0);
prop = RNA_def_property(srna, "use_square", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SQUARE);
RNA_def_property_ui_text(prop, "Square", "Cast a square spot light shape");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
-
- prop = RNA_def_property(srna, "use_halo", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_HALO);
- RNA_def_property_ui_text(prop, "Halo", "Render spotlight with a volumetric halo");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "halo_intensity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "haint");
- RNA_def_property_ui_range(prop, 0, 5.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Halo Intensity", "Brightness of the spotlight's halo cone");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
-
- prop = RNA_def_property(srna, "halo_step", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "shadhalostep");
- RNA_def_property_range(prop, 0, 12);
- RNA_def_property_ui_text(prop, "Halo Step", "Volumetric halo sampling frequency");
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "spot_blend", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spotblend");
+ RNA_def_property_float_default(prop, 0.15f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Spot Blend", "The softness of the spotlight edge");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "spot_size", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "spotsize");
+ RNA_def_property_float_default(prop, DEG2RADF(45.0f));
RNA_def_property_range(prop, DEG2RADF(1.0f), DEG2RADF(180.0f));
RNA_def_property_ui_text(prop, "Spot Size", "Angle of the spotlight beam");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
prop = RNA_def_property(srna, "show_cone", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHOW_CONE);
RNA_def_property_ui_text(prop, "Show Cone",
"Draw transparent cone in 3D view to visualize which objects are contained in it");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
}
-static void rna_def_sun_lamp(BlenderRNA *brna)
+static void rna_def_sun_light(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop;
- srna = RNA_def_struct(brna, "SunLamp", "Lamp");
+ srna = RNA_def_struct(brna, "SunLight", "Light");
RNA_def_struct_sdna(srna, "Lamp");
- RNA_def_struct_ui_text(srna, "Sun Lamp", "Constant direction parallel ray lamp");
- RNA_def_struct_ui_icon(srna, ICON_LAMP_SUN);
-
- rna_def_lamp_shadow(srna, 0, 0);
-
- /* sky */
- prop = RNA_def_property(srna, "sky", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "LampSkySettings");
- RNA_def_property_pointer_funcs(prop, "rna_Lamp_sky_settings_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Sky Settings", "Sky related settings for sun lamps");
-
- rna_def_lamp_sky_settings(brna);
-
- /* BGE Only */
- prop = RNA_def_property(srna, "shadow_frustum_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "shadow_frustum_size");
- RNA_def_property_ui_range(prop, 0.001, 100.0, 2, 1);
- RNA_def_property_ui_text(prop, "Frustum Size", "Size of the frustum used for creating the shadow map");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
-
- prop = RNA_def_property(srna, "show_shadow_box", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHOW_SHADOW_BOX);
- RNA_def_property_ui_text(prop, "Show Shadow Box",
- "Draw a box in 3D view to visualize which objects are contained in it");
- RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+ RNA_def_struct_ui_text(srna, "Sun Light", "Constant direction parallel ray Light");
+ RNA_def_struct_ui_icon(srna, ICON_LIGHT_SUN);
+
+ rna_def_light_shadow(srna, 1);
}
-static void rna_def_hemi_lamp(BlenderRNA *brna)
+static void rna_def_hemi_light(BlenderRNA *brna)
{
StructRNA *srna;
- srna = RNA_def_struct(brna, "HemiLamp", "Lamp");
+ srna = RNA_def_struct(brna, "HemiLight", "Light");
RNA_def_struct_sdna(srna, "Lamp");
- RNA_def_struct_ui_text(srna, "Hemi Lamp", "180 degree constant lamp");
- RNA_def_struct_ui_icon(srna, ICON_LAMP_HEMI);
+ RNA_def_struct_ui_text(srna, "Hemi Light", "180 degree constant Light");
+ RNA_def_struct_ui_icon(srna, ICON_LIGHT_HEMI);
}
-void RNA_def_lamp(BlenderRNA *brna)
+void RNA_def_light(BlenderRNA *brna)
{
- rna_def_lamp(brna);
- rna_def_point_lamp(brna);
- rna_def_area_lamp(brna);
- rna_def_spot_lamp(brna);
- rna_def_sun_lamp(brna);
- rna_def_hemi_lamp(brna);
- rna_def_lamp_mtex(brna);
+ rna_def_light(brna);
+ rna_def_point_light(brna);
+ rna_def_area_light(brna);
+ rna_def_spot_light(brna);
+ rna_def_sun_light(brna);
+ rna_def_hemi_light(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c
index 782ca0d76b3..cc6a46123db 100644
--- a/source/blender/makesrna/intern/rna_lattice.c
+++ b/source/blender/makesrna/intern/rna_lattice.c
@@ -43,11 +43,12 @@
#include "DNA_scene_types.h"
#include "BLI_string.h"
-#include "BKE_depsgraph.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_deform.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "ED_lattice.h"
@@ -97,7 +98,7 @@ static void rna_Lattice_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), P
{
ID *id = ptr->id.data;
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
@@ -119,7 +120,7 @@ static void rna_Lattice_update_data_editlatt(Main *UNUSED(bmain), Scene *UNUSED(
BLI_strncpy(lt_em->vgroup, lt->vgroup, sizeof(lt_em->vgroup));
}
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
diff --git a/source/blender/makesrna/intern/rna_lattice_api.c b/source/blender/makesrna/intern/rna_lattice_api.c
index ee1a94f2ecb..405b7922a0a 100644
--- a/source/blender/makesrna/intern/rna_lattice_api.c
+++ b/source/blender/makesrna/intern/rna_lattice_api.c
@@ -45,8 +45,14 @@ static void rna_Lattice_transform(Lattice *lt, float *mat, bool shape_keys)
{
BKE_lattice_transform(lt, (float (*)[4])mat, shape_keys);
- DAG_id_tag_update(&lt->id, 0);
+ DEG_id_tag_update(&lt->id, 0);
}
+
+static void rna_Lattice_update_gpu_tag(Lattice *lt)
+{
+ BKE_lattice_batch_cache_dirty_tag(lt, BKE_LATTICE_BATCH_DIRTY_ALL);
+}
+
#else
void RNA_api_lattice(StructRNA *srna)
@@ -59,6 +65,8 @@ void RNA_api_lattice(StructRNA *srna)
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
+
+ RNA_def_function(srna, "update_gpu_tag", "rna_Lattice_update_gpu_tag");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
new file mode 100644
index 00000000000..46d1f5bef7d
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -0,0 +1,455 @@
+/*
+ * ***** 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): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_layer.c
+ * \ingroup RNA
+ */
+
+#include "DNA_scene_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_math.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "ED_object.h"
+#include "ED_render.h"
+
+#include "RE_engine.h"
+
+#include "DRW_engine.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_define.h"
+
+#include "rna_internal.h"
+
+#ifdef RNA_RUNTIME
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
+
+#include "RNA_access.h"
+
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_node.h"
+#include "BKE_scene.h"
+#include "BKE_mesh.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+/***********************************/
+
+
+static PointerRNA rna_ViewLayer_active_layer_collection_get(PointerRNA *ptr)
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ LayerCollection *lc = view_layer->active_collection;
+ return rna_pointer_inherit_refine(ptr, &RNA_LayerCollection, lc);
+}
+
+static void rna_ViewLayer_active_layer_collection_set(PointerRNA *ptr, PointerRNA value)
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ LayerCollection *lc = (LayerCollection *)value.data;
+ const int index = BKE_layer_collection_findindex(view_layer, lc);
+ if (index != -1) {
+ BKE_layer_collection_activate(view_layer, lc);
+ }
+}
+
+static PointerRNA rna_LayerObjects_active_object_get(PointerRNA *ptr)
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, view_layer->basact ? view_layer->basact->object : NULL);
+}
+
+static void rna_LayerObjects_active_object_set(PointerRNA *ptr, PointerRNA value)
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ if (value.data)
+ view_layer->basact = BKE_view_layer_base_find(view_layer, (Object *)value.data);
+ else
+ view_layer->basact = NULL;
+}
+
+static char *rna_ViewLayer_path(PointerRNA *ptr)
+{
+ ViewLayer *srl = (ViewLayer *)ptr->data;
+ char name_esc[sizeof(srl->name) * 2];
+
+ BLI_strescape(name_esc, srl->name, sizeof(name_esc));
+ return BLI_sprintfN("view_layers[\"%s\"]", name_esc);
+}
+
+static IDProperty *rna_ViewLayer_idprops(PointerRNA *ptr, bool create)
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+
+ if (create && !view_layer->id_properties) {
+ IDPropertyTemplate val = {0};
+ view_layer->id_properties = IDP_New(IDP_GROUP, &val, "ViewLayer ID properties");
+ }
+
+ return view_layer->id_properties;
+}
+
+static void rna_ViewLayer_update_render_passes(ID *id)
+{
+ Scene *scene = (Scene *)id;
+ if (scene->nodetree)
+ ntreeCompositUpdateRLayers(scene->nodetree);
+}
+
+static PointerRNA rna_ViewLayer_objects_get(CollectionPropertyIterator *iter)
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+
+ /* we are actually iterating a ObjectBase list */
+ Base *base = (Base *)internal->link;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, base->object);
+}
+
+static int rna_ViewLayer_objects_selected_skip(CollectionPropertyIterator *iter, void *UNUSED(data))
+{
+ ListBaseIterator *internal = &iter->internal.listbase;
+ Base *base = (Base *)internal->link;
+
+ if ((base->flag & BASE_SELECTED) != 0) {
+ return 0;
+ }
+
+ return 1;
+};
+
+static PointerRNA rna_ViewLayer_depsgraph_get(PointerRNA *ptr)
+{
+ ID *id = ptr->id.data;
+ if (GS(id->name) == ID_SCE) {
+ Scene *scene = (Scene *)id;
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
+ return rna_pointer_inherit_refine(ptr, &RNA_Depsgraph, depsgraph);
+ }
+ return PointerRNA_NULL;
+}
+
+static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ rna_iterator_listbase_begin(iter, &view_layer->object_bases, rna_ViewLayer_objects_selected_skip);
+}
+
+static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main *bmain)
+{
+#ifdef WITH_PYTHON
+ /* Allow drivers to be evaluated */
+ BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+ Scene *scene = (Scene *)id_ptr;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+
+#ifdef WITH_PYTHON
+ BPy_END_ALLOW_THREADS;
+#endif
+}
+
+static void rna_ObjectBase_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Base *base = (Base *)ptr->data;
+ short mode = (base->flag & BASE_SELECTED) ? BA_SELECT : BA_DESELECT;
+ ED_object_base_select(base, mode);
+}
+
+static void rna_LayerCollection_name_get(struct PointerRNA *ptr, char *value)
+{
+ ID *id = (ID *)((LayerCollection *)ptr->data)->collection;
+ BLI_strncpy(value, id->name + 2, sizeof(id->name) - 2);
+}
+
+int rna_LayerCollection_name_length(PointerRNA *ptr)
+{
+ ID *id = (ID *)((LayerCollection *)ptr->data)->collection;
+ return strlen(id->name + 2);
+}
+
+static void rna_LayerCollection_use_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ LayerCollection *lc = (LayerCollection *)ptr->data;
+ ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc);
+
+ BKE_layer_collection_sync(scene, view_layer);
+
+ DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+}
+
+static bool rna_LayerCollection_has_objects(LayerCollection *lc)
+{
+ return (lc->runtime_flag & LAYER_COLLECTION_HAS_OBJECTS) != 0;
+}
+
+static bool rna_LayerCollection_has_visible_objects(LayerCollection *lc, ViewLayer *view_layer)
+{
+ if ((view_layer->runtime_flag & VIEW_LAYER_HAS_HIDE) &&
+ !(lc->runtime_flag & LAYER_COLLECTION_HAS_VISIBLE_OBJECTS))
+ {
+ return false;
+ }
+ return true;
+}
+
+static bool rna_LayerCollection_has_hidden_objects(LayerCollection *lc, ViewLayer *view_layer)
+{
+ if ((view_layer->runtime_flag & VIEW_LAYER_HAS_HIDE) &&
+ (lc->runtime_flag & LAYER_COLLECTION_HAS_HIDDEN_OBJECTS))
+ {
+ return true;
+ }
+ return false;
+}
+
+static bool rna_LayerCollection_has_selected_objects(LayerCollection *lc, ViewLayer *view_layer)
+{
+ return BKE_layer_collection_has_selected_objects(view_layer, lc);
+}
+
+#else
+
+static void rna_def_layer_collection(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LayerCollection", NULL);
+ RNA_def_struct_ui_text(srna, "Layer Collection", "Layer collection");
+ RNA_def_struct_ui_icon(srna, ICON_GROUP);
+
+ prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE | PROP_ANIMATABLE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_ui_text(prop, "Collection", "Collection this layer collection is wrapping");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "collection->id.name");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE | PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Name", "Name of this view layer (same as its collection one)");
+ RNA_def_property_string_funcs(prop, "rna_LayerCollection_name_get", "rna_LayerCollection_name_length", NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "layer_collections", NULL);
+ RNA_def_property_struct_type(prop, "LayerCollection");
+ RNA_def_property_ui_text(prop, "Children", "Child layer collections");
+
+ prop = RNA_def_property(srna, "exclude", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_EXCLUDE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Exclude", "Exclude collection from view layer");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update");
+
+ prop = RNA_def_property(srna, "holdout", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_HOLDOUT);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Holdout", "Mask out objects in collection from view layer");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update");
+
+ prop = RNA_def_property(srna, "indirect_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_INDIRECT_ONLY);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Indirect Only",
+ "Objects in collection only contribute indirectly (through shadows and reflections) "
+ "in the view layer");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update");
+
+ func = RNA_def_function(srna, "has_objects", "rna_LayerCollection_has_objects");
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_return(func, RNA_def_boolean(func, "result", 0, "", ""));
+
+ func = RNA_def_function(srna, "has_visible_objects", "rna_LayerCollection_has_visible_objects");
+ RNA_def_function_ui_description(func, "");
+ prop = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "ViewLayer the layer collection belongs to");
+ RNA_def_parameter_flags(prop, 0, PARM_REQUIRED);
+ RNA_def_function_return(func, RNA_def_boolean(func, "result", 0, "", ""));
+
+ func = RNA_def_function(srna, "has_hidden_objects", "rna_LayerCollection_has_hidden_objects");
+ RNA_def_function_ui_description(func, "");
+ prop = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "ViewLayer the layer collection belongs to");
+ RNA_def_parameter_flags(prop, 0, PARM_REQUIRED);
+ RNA_def_function_return(func, RNA_def_boolean(func, "result", 0, "", ""));
+
+ func = RNA_def_function(srna, "has_selected_objects", "rna_LayerCollection_has_selected_objects");
+ RNA_def_function_ui_description(func, "");
+ prop = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "ViewLayer the layer collection belongs to");
+ RNA_def_parameter_flags(prop, 0, PARM_REQUIRED);
+ RNA_def_function_return(func, RNA_def_boolean(func, "result", 0, "", ""));
+}
+
+static void rna_def_layer_objects(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ RNA_def_property_srna(cprop, "LayerObjects");
+ srna = RNA_def_struct(brna, "LayerObjects", NULL);
+ RNA_def_struct_sdna(srna, "ViewLayer");
+ RNA_def_struct_ui_text(srna, "Layer Objects", "Collections of objects");
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_pointer_funcs(prop, "rna_LayerObjects_active_object_get",
+ "rna_LayerObjects_active_object_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
+ RNA_def_property_ui_text(prop, "Active Object", "Active object for this layer");
+ /* Could call: ED_object_base_activate(C, rl->basact);
+ * but would be a bad level call and it seems the notifier is enough */
+ RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, NULL);
+
+ prop = RNA_def_property(srna, "selected", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "object_bases", NULL);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_collection_funcs(prop, "rna_LayerObjects_selected_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_ViewLayer_objects_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Selected Objects", "All the selected objects of this layer");
+}
+
+static void rna_def_object_base(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ObjectBase", NULL);
+ RNA_def_struct_sdna(srna, "Base");
+ RNA_def_struct_ui_text(srna, "Object Base", "An object instance in a render layer");
+ RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "object");
+ RNA_def_property_ui_text(prop, "Object", "Object this base links to");
+
+ prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BASE_SELECTED);
+ RNA_def_property_ui_text(prop, "Select", "Object base selection state");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ObjectBase_select_update");
+}
+
+void RNA_def_view_layer(BlenderRNA *brna)
+{
+ FunctionRNA *func;
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ViewLayer", NULL);
+ RNA_def_struct_ui_text(srna, "View Layer", "View layer");
+ RNA_def_struct_ui_icon(srna, ICON_RENDER_RESULT);
+ RNA_def_struct_path_func(srna, "rna_ViewLayer_path");
+ RNA_def_struct_idprops_func(srna, "rna_ViewLayer_idprops");
+
+ rna_def_view_layer_common(srna, 1);
+
+ func = RNA_def_function(srna, "update_render_passes", "rna_ViewLayer_update_render_passes");
+ RNA_def_function_ui_description(func, "Requery the enabled render passes from the render engine");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF);
+
+ prop = RNA_def_property(srna, "layer_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LayerCollection");
+ RNA_def_property_pointer_sdna(prop, NULL, "layer_collections.first");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Layer Collection",
+ "Root of collections hierarchy of this view layer,"
+ "its 'collection' pointer property is the same as the scene's master collection");
+
+ prop = RNA_def_property(srna, "active_layer_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "LayerCollection");
+ RNA_def_property_pointer_funcs(prop, "rna_ViewLayer_active_layer_collection_get",
+ "rna_ViewLayer_active_layer_collection_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Active Layer Collection",
+ "Active layer collection in this view layer's hierarchy");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL);
+
+ prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "object_bases", NULL);
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_ViewLayer_objects_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Objects", "All the objects in this layer");
+ rna_def_layer_objects(brna, prop);
+
+ /* layer options */
+ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", VIEW_LAYER_RENDER);
+ RNA_def_property_ui_text(prop, "Enabled", "Disable or enable the render layer");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL);
+
+ prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", VIEW_LAYER_FREESTYLE);
+ RNA_def_property_ui_text(prop, "Freestyle", "Render stylized strokes in this Layer");
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER, NULL);
+
+ /* Freestyle */
+ rna_def_freestyle_settings(brna);
+
+ prop = RNA_def_property(srna, "freestyle_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "freestyle_config");
+ RNA_def_property_struct_type(prop, "FreestyleSettings");
+ RNA_def_property_ui_text(prop, "Freestyle Settings", "");
+
+ /* debug update routine */
+ func = RNA_def_function(srna, "update", "rna_ViewLayer_update_tagged");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ RNA_def_function_ui_description(func,
+ "Update data tagged to be updated from previous access to data or operators");
+
+ /* Dependency Graph */
+ prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Depsgraph");
+ RNA_def_property_ui_text(prop, "Dependency Graph", "Dependencies in the scene data");
+ RNA_def_property_pointer_funcs(prop, "rna_ViewLayer_depsgraph_get", NULL, NULL, NULL);
+
+ /* Nested Data */
+ /* *** Non-Animated *** */
+ RNA_define_animate_sdna(false);
+ rna_def_layer_collection(brna);
+ rna_def_object_base(brna);
+ RNA_define_animate_sdna(true);
+ /* *** Animated *** */
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c
new file mode 100644
index 00000000000..85df1c5ba72
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_lightprobe.c
@@ -0,0 +1,231 @@
+/*
+ * ***** 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): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_lightprobe.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "DNA_lightprobe_types.h"
+
+#include "WM_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
+
+#include "WM_api.h"
+
+static void rna_LightProbe_recalc(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+}
+
+#else
+
+static EnumPropertyItem parallax_type_items[] = {
+ {LIGHTPROBE_SHAPE_ELIPSOID, "ELIPSOID", ICON_NONE, "Sphere", ""},
+ {LIGHTPROBE_SHAPE_BOX, "BOX", ICON_NONE, "Box", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem lightprobe_type_items[] = {
+ {LIGHTPROBE_TYPE_CUBE, "CUBEMAP", ICON_LIGHTPROBE_CUBEMAP, "Reflection Cubemap", "Capture reflections"},
+ {LIGHTPROBE_TYPE_PLANAR, "PLANAR", ICON_LIGHTPROBE_PLANAR, "Reflection Plane", ""},
+ {LIGHTPROBE_TYPE_GRID, "GRID", ICON_LIGHTPROBE_GRID, "Irradiance Volume", "Volume used for precomputing indirect lighting"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static void rna_def_lightprobe(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "LightProbe", "ID");
+ RNA_def_struct_ui_text(srna, "LightProbe", "Light Probe data-block for lighting capture objects");
+ RNA_def_struct_ui_icon(srna, ICON_LIGHTPROBE_CUBEMAP);
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, lightprobe_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of light probe");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "clipsta");
+ RNA_def_property_float_default(prop, 0.8f);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
+ RNA_def_property_ui_text(prop, "Clip Start",
+ "Probe clip start, below which objects will not appear in reflections");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "clipend");
+ RNA_def_property_float_default(prop, 40.0f);
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
+ RNA_def_property_ui_text(prop, "Clip End",
+ "Probe clip end, beyond which objects will not appear in reflections");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ prop = RNA_def_property(srna, "show_clip", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_CLIP_DIST);
+ RNA_def_property_ui_text(prop, "Clipping", "Show the clipping distances in the 3D view");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "influence_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "attenuation_type");
+ RNA_def_property_enum_items(prop, parallax_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of influence volume");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "show_influence", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_INFLUENCE);
+ RNA_def_property_ui_text(prop, "Influence", "Show the influence volume in the 3D view");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "influence_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "distinf");
+ RNA_def_property_float_default(prop, 2.5f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Influence Distance", "Influence distance of the probe");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Falloff", "Control how fast the probe influence decreases");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "use_custom_parallax", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_CUSTOM_PARALLAX);
+ RNA_def_property_ui_text(prop, "Use Custom Parallax", "Enable custom settings for the parallax correction volume");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "show_parallax", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_PARALLAX);
+ RNA_def_property_ui_text(prop, "Parallax", "Show the parallax correction volume in the 3D view");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "parallax_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, parallax_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of parallax volume");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "parallax_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "distpar");
+ RNA_def_property_float_default(prop, 2.5f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Parallax Radius", "Lowest corner of the parallax bounding box");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ /* irradiance grid */
+ prop = RNA_def_property(srna, "grid_resolution_x", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 256);
+ RNA_def_property_int_default(prop, 4);
+ RNA_def_property_ui_text(prop, "Resolution X", "Number of sample along the x axis of the volume");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ prop = RNA_def_property(srna, "grid_resolution_y", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 256);
+ RNA_def_property_int_default(prop, 4);
+ RNA_def_property_ui_text(prop, "Resolution Y", "Number of sample along the y axis of the volume");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ prop = RNA_def_property(srna, "grid_resolution_z", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 256);
+ RNA_def_property_int_default(prop, 4);
+ RNA_def_property_ui_text(prop, "Resolution Z", "Number of sample along the z axis of the volume");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ prop = RNA_def_property(srna, "visibility_buffer_bias", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vis_bias");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.001f, 9999.0f);
+ RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
+ RNA_def_property_ui_text(prop, "Visibility Bias", "Bias for reducing self shadowing");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "visibility_bleed_bias", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vis_bleedbias");
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Visibility Bleed Bias", "Bias for reducing light-bleed on variance shadow maps");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "visibility_blur", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vis_blur");
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Visibility Blur", "Filter size of the visibilty blur");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "intensity");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 3.0f, 1.0, 3);
+ RNA_def_property_ui_text(prop, "Intensity", "Modify the intensity of the lighting captured by this probe");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ prop = RNA_def_property(srna, "visibility_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_pointer_sdna(prop, NULL, "visibility_grp");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Visibility Collection", "Restrict objects visible for this probe");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ prop = RNA_def_property(srna, "invert_visibility_collection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_INVERT_GROUP);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Invert Collection", "Invert visibility collection");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
+ /* Data preview */
+ prop = RNA_def_property(srna, "show_data", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_DATA);
+ RNA_def_property_ui_text(prop, "Show Data", "Show captured lighting data into the 3D view for debugging purpose");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ /* common */
+ rna_def_animdata_common(srna);
+}
+
+
+void RNA_def_lightprobe(BlenderRNA *brna)
+{
+ rna_def_lightprobe(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index b50102079a9..5cee2fb90cb 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -101,7 +101,8 @@ const EnumPropertyItem rna_enum_linestyle_geometry_modifier_type_items[] = {
#include "BKE_linestyle.h"
#include "BKE_texture.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
#include "ED_node.h"
@@ -323,7 +324,7 @@ static void rna_LineStyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
{
FreestyleLineStyle *linestyle = ptr->id.data;
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
}
@@ -347,7 +348,7 @@ static LineStyleModifier *rna_LineStyle_color_modifier_add(FreestyleLineStyle *l
return NULL;
}
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
return modifier;
@@ -365,7 +366,7 @@ static void rna_LineStyle_color_modifier_remove(FreestyleLineStyle *linestyle, R
RNA_POINTER_INVALIDATE(modifier_ptr);
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
}
@@ -379,7 +380,7 @@ static LineStyleModifier *rna_LineStyle_alpha_modifier_add(FreestyleLineStyle *l
return NULL;
}
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
return modifier;
@@ -397,7 +398,7 @@ static void rna_LineStyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, R
RNA_POINTER_INVALIDATE(modifier_ptr);
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
}
@@ -411,7 +412,7 @@ static LineStyleModifier *rna_LineStyle_thickness_modifier_add(FreestyleLineStyl
return NULL;
}
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
return modifier;
@@ -429,7 +430,7 @@ static void rna_LineStyle_thickness_modifier_remove(FreestyleLineStyle *linestyl
RNA_POINTER_INVALIDATE(modifier_ptr);
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
}
@@ -443,7 +444,7 @@ static LineStyleModifier *rna_LineStyle_geometry_modifier_add(FreestyleLineStyle
return NULL;
}
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
return modifier;
@@ -461,7 +462,7 @@ static void rna_LineStyle_geometry_modifier_remove(FreestyleLineStyle *linestyle
RNA_POINTER_INVALIDATE(modifier_ptr);
- DAG_id_tag_update(&linestyle->id, 0);
+ DEG_id_tag_update(&linestyle->id, 0);
WM_main_add_notifier(NC_LINESTYLE, linestyle);
}
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 5d7088c952b..4f145d1f48d 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -31,6 +31,7 @@
#include "BLI_path_util.h"
#include "RNA_define.h"
+#include "RNA_access.h"
#include "rna_internal.h"
@@ -107,7 +108,7 @@ static void rna_Main_object_begin(CollectionPropertyIterator *iter, PointerRNA *
rna_iterator_listbase_begin(iter, &bmain->object, NULL);
}
-static void rna_Main_lamp_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+static void rna_Main_light_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Main *bmain = (Main *)ptr->data;
rna_iterator_listbase_begin(iter, &bmain->lamp, NULL);
@@ -209,10 +210,10 @@ static void rna_Main_sound_begin(CollectionPropertyIterator *iter, PointerRNA *p
rna_iterator_listbase_begin(iter, &bmain->sound, NULL);
}
-static void rna_Main_group_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+static void rna_Main_collection_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Main *bmain = (Main *)ptr->data;
- rna_iterator_listbase_begin(iter, &bmain->group, NULL);
+ rna_iterator_listbase_begin(iter, &bmain->collection, NULL);
}
static void rna_Main_armature_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -293,6 +294,251 @@ static void rna_Main_paintcurves_begin(CollectionPropertyIterator *iter, Pointer
rna_iterator_listbase_begin(iter, &bmain->paintcurves, NULL);
}
+static void rna_Main_workspaces_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->workspaces, NULL);
+}
+
+static void rna_Main_lightprobes_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main *)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->lightprobe, NULL);
+}
+
+static int rna_ID_lookup_string(ListBase *lb, const char *key, PointerRNA *r_ptr)
+{
+ ID *id;
+ for (id = lb->first; id != NULL; id = id->next) {
+ if (STREQ(id->name + 2, key)) {
+ break;
+ }
+ else if (strstr(key, id->name + 2) != NULL) {
+ char full_name_ui[MAX_ID_FULL_NAME_UI];
+ BKE_id_full_name_ui_prefix_get(full_name_ui, id);
+ /* Second check skips the three 'UI keycode letters' prefix. */
+ if (STREQ(full_name_ui, key) || STREQ(full_name_ui + 3, key)) {
+ break;
+ }
+ }
+ }
+ if (id != NULL) {
+ RNA_id_pointer_create(id, r_ptr);
+ return true;
+ }
+ return false;
+}
+
+int rna_Main_camera_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->camera, key, r_ptr);
+}
+
+int rna_Main_scene_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->scene, key, r_ptr);
+}
+
+int rna_Main_object_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->object, key, r_ptr);
+}
+
+int rna_Main_mat_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->mat, key, r_ptr);
+}
+
+int rna_Main_nodetree_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->nodetree, key, r_ptr);
+}
+
+int rna_Main_mesh_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->mesh, key, r_ptr);
+}
+
+int rna_Main_light_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->lamp, key, r_ptr);
+}
+
+int rna_Main_library_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->library, key, r_ptr);
+}
+
+int rna_Main_screen_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->screen, key, r_ptr);
+}
+
+int rna_Main_wm_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->wm, key, r_ptr);
+}
+
+int rna_Main_image_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->image, key, r_ptr);
+}
+
+int rna_Main_latt_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->latt, key, r_ptr);
+}
+
+int rna_Main_curve_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->curve, key, r_ptr);
+}
+
+int rna_Main_mball_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->mball, key, r_ptr);
+}
+
+int rna_Main_font_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->vfont, key, r_ptr);
+}
+
+int rna_Main_tex_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->tex, key, r_ptr);
+}
+
+int rna_Main_brush_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->brush, key, r_ptr);
+}
+
+int rna_Main_world_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->world, key, r_ptr);
+}
+
+int rna_Main_collection_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->collection, key, r_ptr);
+}
+
+int rna_Main_key_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->key, key, r_ptr);
+}
+
+int rna_Main_text_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->text, key, r_ptr);
+}
+
+int rna_Main_speaker_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->speaker, key, r_ptr);
+}
+
+int rna_Main_sound_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->sound, key, r_ptr);
+}
+
+int rna_Main_armature_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->armature, key, r_ptr);
+}
+
+int rna_Main_action_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->action, key, r_ptr);
+}
+
+int rna_Main_particle_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->particle, key, r_ptr);
+}
+
+int rna_Main_palette_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->palettes, key, r_ptr);
+}
+
+int rna_Main_gpencil_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->gpencil, key, r_ptr);
+}
+
+int rna_Main_movieclip_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->movieclip, key, r_ptr);
+}
+
+int rna_Main_mask_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->mask, key, r_ptr);
+}
+
+int rna_Main_linestyle_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->linestyle, key, r_ptr);
+}
+
+int rna_Main_cachefile_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->cachefiles, key, r_ptr);
+}
+
+int rna_Main_paintcurve_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->paintcurves, key, r_ptr);
+}
+
+int rna_Main_workspace_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->workspaces, key, r_ptr);
+}
+
+int rna_Main_lightprobe_lookup_string(PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr)
+{
+ Main *bmain = ptr->data;
+ return rna_ID_lookup_string(&bmain->lightprobe, key, r_ptr);
+}
+
static void rna_Main_version_get(PointerRNA *ptr, int *value)
{
Main *bmain = (Main *)ptr->data;
@@ -325,6 +571,7 @@ typedef struct MainCollectionDef {
const char *name;
const char *description;
CollectionDefFunc *func;
+ const char *lookup_string;
} MainCollectionDef;
void RNA_def_main(BlenderRNA *brna)
@@ -335,39 +582,41 @@ void RNA_def_main(BlenderRNA *brna)
/* plural must match idtypes in readblenentry.c */
MainCollectionDef lists[] = {
- {"cameras", "Camera", "rna_Main_camera_begin", "Cameras", "Camera data-blocks", RNA_def_main_cameras},
- {"scenes", "Scene", "rna_Main_scene_begin", "Scenes", "Scene data-blocks", RNA_def_main_scenes},
- {"objects", "Object", "rna_Main_object_begin", "Objects", "Object data-blocks", RNA_def_main_objects},
- {"materials", "Material", "rna_Main_mat_begin", "Materials", "Material data-blocks", RNA_def_main_materials},
- {"node_groups", "NodeTree", "rna_Main_nodetree_begin", "Node Groups", "Node group data-blocks", RNA_def_main_node_groups},
- {"meshes", "Mesh", "rna_Main_mesh_begin", "Meshes", "Mesh data-blocks", RNA_def_main_meshes},
- {"lamps", "Lamp", "rna_Main_lamp_begin", "Lamps", "Lamp data-blocks", RNA_def_main_lamps},
- {"libraries", "Library", "rna_Main_library_begin", "Libraries", "Library data-blocks", RNA_def_main_libraries},
- {"screens", "Screen", "rna_Main_screen_begin", "Screens", "Screen data-blocks", RNA_def_main_screens},
- {"window_managers", "WindowManager", "rna_Main_wm_begin", "Window Managers", "Window manager data-blocks", RNA_def_main_window_managers},
- {"images", "Image", "rna_Main_image_begin", "Images", "Image data-blocks", RNA_def_main_images},
- {"lattices", "Lattice", "rna_Main_latt_begin", "Lattices", "Lattice data-blocks", RNA_def_main_lattices},
- {"curves", "Curve", "rna_Main_curve_begin", "Curves", "Curve data-blocks", RNA_def_main_curves},
- {"metaballs", "MetaBall", "rna_Main_mball_begin", "Metaballs", "Metaball data-blocks", RNA_def_main_metaballs},
- {"fonts", "VectorFont", "rna_Main_font_begin", "Vector Fonts", "Vector font data-blocks", RNA_def_main_fonts},
- {"textures", "Texture", "rna_Main_tex_begin", "Textures", "Texture data-blocks", RNA_def_main_textures},
- {"brushes", "Brush", "rna_Main_brush_begin", "Brushes", "Brush data-blocks", RNA_def_main_brushes},
- {"worlds", "World", "rna_Main_world_begin", "Worlds", "World data-blocks", RNA_def_main_worlds},
- {"groups", "Group", "rna_Main_group_begin", "Groups", "Group data-blocks", RNA_def_main_groups},
- {"shape_keys", "Key", "rna_Main_key_begin", "Shape Keys", "Shape Key data-blocks", NULL},
- {"texts", "Text", "rna_Main_text_begin", "Texts", "Text data-blocks", RNA_def_main_texts},
- {"speakers", "Speaker", "rna_Main_speaker_begin", "Speakers", "Speaker data-blocks", RNA_def_main_speakers},
- {"sounds", "Sound", "rna_Main_sound_begin", "Sounds", "Sound data-blocks", RNA_def_main_sounds},
- {"armatures", "Armature", "rna_Main_armature_begin", "Armatures", "Armature data-blocks", RNA_def_main_armatures},
- {"actions", "Action", "rna_Main_action_begin", "Actions", "Action data-blocks", RNA_def_main_actions},
- {"particles", "ParticleSettings", "rna_Main_particle_begin", "Particles", "Particle data-blocks", RNA_def_main_particles},
- {"palettes", "Palette", "rna_Main_palettes_begin", "Palettes", "Palette data-blocks", RNA_def_main_palettes},
- {"grease_pencil", "GreasePencil", "rna_Main_gpencil_begin", "Grease Pencil", "Grease Pencil data-blocks", RNA_def_main_gpencil},
- {"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip data-blocks", RNA_def_main_movieclips},
- {"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks data-blocks", RNA_def_main_masks},
- {"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style data-blocks", RNA_def_main_linestyles},
- {"cache_files", "CacheFile", "rna_Main_cachefiles_begin", "Cache Files", "Cache Files data-blocks", RNA_def_main_cachefiles},
- {"paint_curves", "PaintCurve", "rna_Main_paintcurves_begin", "Paint Curves", "Paint Curves data-blocks", RNA_def_main_paintcurves},
+ {"cameras", "Camera", "rna_Main_camera_begin", "Cameras", "Camera data-blocks", RNA_def_main_cameras, "rna_Main_camera_lookup_string"},
+ {"scenes", "Scene", "rna_Main_scene_begin", "Scenes", "Scene data-blocks", RNA_def_main_scenes, "rna_Main_scene_lookup_string"},
+ {"objects", "Object", "rna_Main_object_begin", "Objects", "Object data-blocks", RNA_def_main_objects, "rna_Main_object_lookup_string"},
+ {"materials", "Material", "rna_Main_mat_begin", "Materials", "Material data-blocks", RNA_def_main_materials, "rna_Main_mat_lookup_string"},
+ {"node_groups", "NodeTree", "rna_Main_nodetree_begin", "Node Groups", "Node group data-blocks", RNA_def_main_node_groups, "rna_Main_nodetree_lookup_string"},
+ {"meshes", "Mesh", "rna_Main_mesh_begin", "Meshes", "Mesh data-blocks", RNA_def_main_meshes, "rna_Main_mesh_lookup_string"},
+ {"lights", "Light", "rna_Main_light_begin", "Lights", "Light data-blocks", RNA_def_main_lights, "rna_Main_light_lookup_string"},
+ {"libraries", "Library", "rna_Main_library_begin", "Libraries", "Library data-blocks", RNA_def_main_libraries, "rna_Main_library_lookup_string"},
+ {"screens", "Screen", "rna_Main_screen_begin", "Screens", "Screen data-blocks", RNA_def_main_screens, "rna_Main_screen_lookup_string"},
+ {"window_managers", "WindowManager", "rna_Main_wm_begin", "Window Managers", "Window manager data-blocks", RNA_def_main_window_managers, "rna_Main_wm_lookup_string"},
+ {"images", "Image", "rna_Main_image_begin", "Images", "Image data-blocks", RNA_def_main_images, "rna_Main_image_lookup_string"},
+ {"lattices", "Lattice", "rna_Main_latt_begin", "Lattices", "Lattice data-blocks", RNA_def_main_lattices, "rna_Main_latt_lookup_string"},
+ {"curves", "Curve", "rna_Main_curve_begin", "Curves", "Curve data-blocks", RNA_def_main_curves, "rna_Main_curve_lookup_string"},
+ {"metaballs", "MetaBall", "rna_Main_mball_begin", "Metaballs", "Metaball data-blocks", RNA_def_main_metaballs, "rna_Main_mball_lookup_string"},
+ {"fonts", "VectorFont", "rna_Main_font_begin", "Vector Fonts", "Vector font data-blocks", RNA_def_main_fonts, "rna_Main_font_lookup_string"},
+ {"textures", "Texture", "rna_Main_tex_begin", "Textures", "Texture data-blocks", RNA_def_main_textures, "rna_Main_tex_lookup_string"},
+ {"brushes", "Brush", "rna_Main_brush_begin", "Brushes", "Brush data-blocks", RNA_def_main_brushes, "rna_Main_brush_lookup_string"},
+ {"worlds", "World", "rna_Main_world_begin", "Worlds", "World data-blocks", RNA_def_main_worlds, "rna_Main_world_lookup_string"},
+ {"collections", "Collection", "rna_Main_collection_begin", "Collections", "Collection data-blocks", RNA_def_main_collections, "rna_Main_collection_lookup_string"},
+ {"shape_keys", "Key", "rna_Main_key_begin", "Shape Keys", "Shape Key data-blocks", NULL, "rna_Main_key_lookup_string"},
+ {"texts", "Text", "rna_Main_text_begin", "Texts", "Text data-blocks", RNA_def_main_texts, "rna_Main_text_lookup_string"},
+ {"speakers", "Speaker", "rna_Main_speaker_begin", "Speakers", "Speaker data-blocks", RNA_def_main_speakers, "rna_Main_speaker_lookup_string"},
+ {"sounds", "Sound", "rna_Main_sound_begin", "Sounds", "Sound data-blocks", RNA_def_main_sounds, "rna_Main_sound_lookup_string"},
+ {"armatures", "Armature", "rna_Main_armature_begin", "Armatures", "Armature data-blocks", RNA_def_main_armatures, "rna_Main_armature_lookup_string"},
+ {"actions", "Action", "rna_Main_action_begin", "Actions", "Action data-blocks", RNA_def_main_actions, "rna_Main_action_lookup_string"},
+ {"particles", "ParticleSettings", "rna_Main_particle_begin", "Particles", "Particle data-blocks", RNA_def_main_particles, "rna_Main_particle_lookup_string"},
+ {"palettes", "Palette", "rna_Main_palettes_begin", "Palettes", "Palette data-blocks", RNA_def_main_palettes, "rna_Main_palette_lookup_string"},
+ {"grease_pencil", "GreasePencil", "rna_Main_gpencil_begin", "Grease Pencil", "Grease Pencil data-blocks", RNA_def_main_gpencil, "rna_Main_gpencil_lookup_string"},
+ {"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip data-blocks", RNA_def_main_movieclips, "rna_Main_movieclip_lookup_string"},
+ {"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks data-blocks", RNA_def_main_masks, "rna_Main_mask_lookup_string"},
+ {"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style data-blocks", RNA_def_main_linestyles, "rna_Main_linestyle_lookup_string"},
+ {"cache_files", "CacheFile", "rna_Main_cachefiles_begin", "Cache Files", "Cache Files data-blocks", RNA_def_main_cachefiles, "rna_Main_cachefile_lookup_string"},
+ {"paint_curves", "PaintCurve", "rna_Main_paintcurves_begin", "Paint Curves", "Paint Curves data-blocks", RNA_def_main_paintcurves, "rna_Main_paintcurve_lookup_string"},
+ {"workspaces", "WorkSpace", "rna_Main_workspaces_begin", "Workspaces", "Workspace data-blocks", RNA_def_main_workspaces, "rna_Main_workspace_lookup_string"},
+ {"lightprobes", "LightProbe", "rna_Main_lightprobes_begin", "LightProbes", "LightProbe data-blocks", RNA_def_main_lightprobes, "rna_Main_lightprobe_lookup_string"},
{NULL, NULL, NULL, NULL, NULL, NULL}
};
@@ -409,7 +658,7 @@ void RNA_def_main(BlenderRNA *brna)
RNA_def_property_struct_type(prop, lists[i].type);
RNA_def_property_collection_funcs(prop, lists[i].iter_begin, "rna_iterator_listbase_next",
"rna_iterator_listbase_end", "rna_iterator_listbase_get",
- NULL, NULL, NULL, NULL);
+ NULL, NULL, lists[i].lookup_string, NULL);
RNA_def_property_ui_text(prop, lists[i].name, lists[i].description);
/* collection functions */
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index f2249eb397d..c6094dc2dc3 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -49,41 +49,42 @@
#ifdef RNA_RUNTIME
-#include "BKE_main.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_brush.h"
#include "BKE_camera.h"
+#include "BKE_collection.h"
#include "BKE_curve.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
-#include "BKE_mesh.h"
-#include "BKE_armature.h"
-#include "BKE_lamp.h"
-#include "BKE_library.h"
-#include "BKE_library_remap.h"
-#include "BKE_object.h"
-#include "BKE_material.h"
+#include "BKE_font.h"
+#include "BKE_gpencil.h"
#include "BKE_icons.h"
#include "BKE_idcode.h"
#include "BKE_image.h"
-#include "BKE_texture.h"
-#include "BKE_scene.h"
-#include "BKE_sound.h"
-#include "BKE_text.h"
-#include "BKE_action.h"
-#include "BKE_group.h"
-#include "BKE_brush.h"
+#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_library_remap.h"
+#include "BKE_lightprobe.h"
+#include "BKE_linestyle.h"
+#include "BKE_mask.h"
+#include "BKE_material.h"
#include "BKE_mball.h"
-#include "BKE_world.h"
-#include "BKE_particle.h"
-#include "BKE_paint.h"
-#include "BKE_font.h"
+#include "BKE_mesh.h"
+#include "BKE_movieclip.h"
#include "BKE_node.h"
-#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+#include "BKE_sound.h"
#include "BKE_speaker.h"
-#include "BKE_movieclip.h"
-#include "BKE_mask.h"
-#include "BKE_gpencil.h"
-#include "BKE_linestyle.h"
+#include "BKE_text.h"
+#include "BKE_texture.h"
+#include "BKE_workspace.h"
+#include "BKE_world.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
@@ -93,9 +94,10 @@
#include "DNA_mesh_types.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_text_types.h"
#include "DNA_texture_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_brush_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meta_types.h"
@@ -115,6 +117,8 @@
# include "BPY_extern.h"
#endif
+#include "WM_api.h"
+
static void rna_idname_validate(const char *name, char *r_name)
{
@@ -171,14 +175,15 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports
(scene_new = scene->id.next))
{
if (do_unlink) {
- bScreen *sc = CTX_wm_screen(C);
- if (sc->scene == scene) {
+ wmWindow *win = CTX_wm_window(C);
+
+ if (WM_window_get_active_scene(win) == scene) {
#ifdef WITH_PYTHON
BPy_BEGIN_ALLOW_THREADS;
#endif
- ED_screen_set_scene(C, sc, scene_new);
+ WM_window_set_active_scene(bmain, C, win, scene_new);
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -224,6 +229,9 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
case ID_LT:
type = OB_LATTICE;
break;
+ case ID_GD:
+ type = OB_GPENCIL;
+ break;
case ID_AR:
type = OB_ARMATURE;
break;
@@ -242,7 +250,6 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
}
ob = BKE_object_add_only_object(bmain, type, safe_name);
- id_us_min(&ob->id);
ob->data = data;
test_object_materials(bmain, ob, ob->data);
@@ -260,6 +267,13 @@ static Material *rna_Main_materials_new(Main *bmain, const char *name)
return (Material *)id;
}
+static void rna_Main_materials_gpencil_data(Main *UNUSED(bmain), PointerRNA *id_ptr)
+{
+ ID *id = id_ptr->data;
+ Material *ma = (Material *)id;
+ BKE_material_init_gpencil_settings(ma);
+}
+
static const EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
return rna_node_tree_type_itemf(NULL, NULL, r_free);
@@ -292,11 +306,12 @@ static Mesh *rna_Main_meshes_new(Main *bmain, const char *name)
}
/* copied from Mesh_getFromObject and adapted to RNA interface */
-/* settings: 1 - preview, 2 - render */
Mesh *rna_Main_meshes_new_from_object(
- Main *bmain, ReportList *reports, Scene *sce,
- Object *ob, bool apply_modifiers, int settings, bool calc_tessface, bool calc_undeformed)
+ Main *bmain, ReportList *reports, Depsgraph *depsgraph,
+ Object *ob, bool apply_modifiers, bool calc_undeformed)
{
+ Scene *sce = DEG_get_evaluated_scene(depsgraph);
+
switch (ob->type) {
case OB_FONT:
case OB_CURVE:
@@ -309,10 +324,10 @@ Mesh *rna_Main_meshes_new_from_object(
return NULL;
}
- return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
+ return BKE_mesh_new_from_object(depsgraph, bmain, sce, ob, apply_modifiers, calc_undeformed);
}
-static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type)
+static Lamp *rna_Main_lights_new(Main *bmain, const char *name, int type)
{
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
@@ -426,6 +441,14 @@ static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode)
return brush;
}
+static void rna_Main_brush_gpencil_data(Main *UNUSED(bmain), PointerRNA *id_ptr)
+{
+ ID *id = id_ptr->data;
+ Brush *brush = (Brush *)id;
+ BKE_brush_init_gpencil_settings(brush);
+}
+
+
static World *rna_Main_worlds_new(Main *bmain, const char *name)
{
char safe_name[MAX_ID_NAME - 2];
@@ -436,12 +459,12 @@ static World *rna_Main_worlds_new(Main *bmain, const char *name)
return world;
}
-static Group *rna_Main_groups_new(Main *bmain, const char *name)
+static Collection *rna_Main_collections_new(Main *bmain, const char *name)
{
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
- return BKE_group_add(bmain, safe_name);
+ return BKE_collection_add(bmain, NULL, safe_name);
}
static Speaker *rna_Main_speakers_new(Main *bmain, const char *name)
@@ -545,7 +568,7 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons
}
if (clip != NULL) {
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
else {
BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath,
@@ -574,14 +597,21 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name
return linestyle;
}
-/* tag and is_updated functions, all the same */
+static LightProbe *rna_Main_lightprobe_new(Main *bmain, const char *name)
+{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ LightProbe *probe = BKE_lightprobe_add(bmain, safe_name);
+ id_us_min(&probe->id);
+ return probe;
+}
+
+/* tag functions, all the same */
#define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \
static void rna_Main_##_func_name##_tag(Main *bmain, bool value) { \
BKE_main_id_tag_listbase(&bmain->_listbase_name, LIB_TAG_DOIT, value); \
} \
- static bool rna_Main_##_func_name##_is_updated_get(PointerRNA *ptr) { \
- return DAG_id_type_tagged(ptr->data, _id_type) != 0; \
- }
RNA_MAIN_ID_TAG_FUNCS_DEF(cameras, camera, ID_CA)
RNA_MAIN_ID_TAG_FUNCS_DEF(scenes, scene, ID_SCE)
@@ -589,7 +619,7 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(objects, object, ID_OB)
RNA_MAIN_ID_TAG_FUNCS_DEF(materials, mat, ID_MA)
RNA_MAIN_ID_TAG_FUNCS_DEF(node_groups, nodetree, ID_NT)
RNA_MAIN_ID_TAG_FUNCS_DEF(meshes, mesh, ID_ME)
-RNA_MAIN_ID_TAG_FUNCS_DEF(lamps, lamp, ID_LA)
+RNA_MAIN_ID_TAG_FUNCS_DEF(lights, lamp, ID_LA)
RNA_MAIN_ID_TAG_FUNCS_DEF(libraries, library, ID_LI)
RNA_MAIN_ID_TAG_FUNCS_DEF(screens, screen, ID_SCR)
RNA_MAIN_ID_TAG_FUNCS_DEF(window_managers, wm, ID_WM)
@@ -601,7 +631,7 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(fonts, vfont, ID_VF)
RNA_MAIN_ID_TAG_FUNCS_DEF(textures, tex, ID_TE)
RNA_MAIN_ID_TAG_FUNCS_DEF(brushes, brush, ID_BR)
RNA_MAIN_ID_TAG_FUNCS_DEF(worlds, world, ID_WO)
-RNA_MAIN_ID_TAG_FUNCS_DEF(groups, group, ID_GR)
+RNA_MAIN_ID_TAG_FUNCS_DEF(collections, collection, ID_GR)
//RNA_MAIN_ID_TAG_FUNCS_DEF(shape_keys, key, ID_KE)
RNA_MAIN_ID_TAG_FUNCS_DEF(texts, text, ID_TXT)
RNA_MAIN_ID_TAG_FUNCS_DEF(speakers, speaker, ID_SPK)
@@ -616,6 +646,8 @@ 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)
RNA_MAIN_ID_TAG_FUNCS_DEF(paintcurves, paintcurves, ID_PC)
+RNA_MAIN_ID_TAG_FUNCS_DEF(workspaces, workspaces, ID_WS)
+RNA_MAIN_ID_TAG_FUNCS_DEF(lightprobes, lightprobe, ID_LP)
#undef RNA_MAIN_ID_TAG_FUNCS_DEF
@@ -643,7 +675,6 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataCameras");
srna = RNA_def_struct(brna, "BlendDataCameras", NULL);
@@ -675,10 +706,6 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_cameras_is_updated_get", NULL);
}
void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
@@ -686,7 +713,6 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataScenes");
srna = RNA_def_struct(brna, "BlendDataScenes", NULL);
@@ -712,10 +738,6 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_scenes_is_updated_get", NULL);
}
void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
@@ -723,7 +745,6 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataObjects");
srna = RNA_def_struct(brna, "BlendDataObjects", NULL);
@@ -757,10 +778,6 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_objects_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_objects_is_updated_get", NULL);
}
void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
@@ -768,7 +785,6 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataMaterials");
srna = RNA_def_struct(brna, "BlendDataMaterials", NULL);
@@ -783,6 +799,11 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "create_gpencil_data", "rna_Main_materials_gpencil_data");
+ RNA_def_function_ui_description(func, "Add grease pencil material settings");
+ parm = RNA_def_pointer(func, "material", "Material", "", "Material");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+
func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a material from the current blendfile");
@@ -798,17 +819,12 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_materials_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_materials_is_updated_get", NULL);
}
void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
static const EnumPropertyItem dummy_items[] = {
{0, "DUMMY", 0, "", ""},
@@ -846,23 +862,12 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_node_groups_is_updated_get", NULL);
}
void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
-
- static const EnumPropertyItem mesh_type_items[] = {
- {eModifierMode_Realtime, "PREVIEW", 0, "Preview", "Apply modifier preview settings"},
- {eModifierMode_Render, "RENDER", 0, "Render", "Apply modifier render settings"},
- {0, NULL, 0, NULL, NULL}
- };
RNA_def_property_srna(cprop, "BlendDataMeshes");
srna = RNA_def_struct(brna, "BlendDataMeshes", NULL);
@@ -880,15 +885,12 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new_from_object", "rna_Main_meshes_new_from_object");
RNA_def_function_ui_description(func, "Add a new mesh created from object with modifiers applied");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
+ parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "Dependency Graph", "Evaluated dependency graph within which to evaluate modifiers");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object", "Object", "", "Object to create mesh from");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces");
RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates");
parm = RNA_def_pointer(func, "mesh", "Mesh", "",
"Mesh created from object, remove it if it is only used for export");
@@ -911,54 +913,46 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_meshes_is_updated_get", NULL);
}
-void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
+
+void RNA_def_main_lights(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
- RNA_def_property_srna(cprop, "BlendDataLamps");
- srna = RNA_def_struct(brna, "BlendDataLamps", NULL);
+ RNA_def_property_srna(cprop, "BlendDataLights");
+ srna = RNA_def_struct(brna, "BlendDataLights", NULL);
RNA_def_struct_sdna(srna, "Main");
- RNA_def_struct_ui_text(srna, "Main Lamps", "Collection of lamps");
+ RNA_def_struct_ui_text(srna, "Main Lights", "Collection of lights");
- func = RNA_def_function(srna, "new", "rna_Main_lamps_new");
- RNA_def_function_ui_description(func, "Add a new lamp to the main database");
- parm = RNA_def_string(func, "name", "Lamp", 0, "", "New name for the data-block");
+ func = RNA_def_function(srna, "new", "rna_Main_lights_new");
+ RNA_def_function_ui_description(func, "Add a new light to the main database");
+ parm = RNA_def_string(func, "name", "Light", 0, "", "New name for the data-block");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_enum(func, "type", rna_enum_lamp_type_items, 0, "Type", "The type of texture to add");
+ parm = RNA_def_enum(func, "type", rna_enum_light_type_items, 0, "Type", "The type of texture to add");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block");
+ parm = RNA_def_pointer(func, "light", "Light", "", "New light data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile");
- parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove");
+ RNA_def_function_ui_description(func, "Remove a light from the current blendfile");
+ parm = RNA_def_pointer(func, "light", "Light", "", "Light to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
RNA_def_boolean(func, "do_unlink", true, "",
- "Unlink all usages of this lamp before deleting it "
- "(WARNING: will also delete objects instancing that lamp data)");
+ "Unlink all usages of this Light before deleting it "
+ "(WARNING: will also delete objects instancing that light data)");
RNA_def_boolean(func, "do_id_user", true, "",
- "Decrement user counter of all datablocks used by this lamp data");
+ "Decrement user counter of all datablocks used by this light data");
RNA_def_boolean(func, "do_ui_user", true, "",
- "Make sure interface does not reference this lamp data");
+ "Make sure interface does not reference this light data");
- func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag");
+ func = RNA_def_function(srna, "tag", "rna_Main_lights_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_lamps_is_updated_get", NULL);
}
void RNA_def_main_libraries(BlenderRNA *brna, PropertyRNA *cprop)
@@ -966,7 +960,6 @@ void RNA_def_main_libraries(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataLibraries");
srna = RNA_def_struct(brna, "BlendDataLibraries", NULL);
@@ -976,10 +969,6 @@ void RNA_def_main_libraries(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_libraries_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_libraries_is_updated_get", NULL);
}
void RNA_def_main_screens(BlenderRNA *brna, PropertyRNA *cprop)
@@ -987,7 +976,6 @@ void RNA_def_main_screens(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataScreens");
srna = RNA_def_struct(brna, "BlendDataScreens", NULL);
@@ -997,10 +985,6 @@ void RNA_def_main_screens(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_screens_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_screens_is_updated_get", NULL);
}
void RNA_def_main_window_managers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1008,7 +992,6 @@ void RNA_def_main_window_managers(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataWindowManagers");
srna = RNA_def_struct(brna, "BlendDataWindowManagers", NULL);
@@ -1018,17 +1001,12 @@ void RNA_def_main_window_managers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_window_managers_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_window_managers_is_updated_get", NULL);
}
void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataImages");
srna = RNA_def_struct(brna, "BlendDataImages", NULL);
@@ -1075,10 +1053,6 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_images_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_images_is_updated_get", NULL);
}
void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1086,7 +1060,6 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataLattices");
srna = RNA_def_struct(brna, "BlendDataLattices", NULL);
@@ -1118,17 +1091,12 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_lattices_is_updated_get", NULL);
}
void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataCurves");
srna = RNA_def_struct(brna, "BlendDataCurves", NULL);
@@ -1162,17 +1130,12 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_curves_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_curves_is_updated_get", NULL);
}
void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataMetaBalls");
srna = RNA_def_struct(brna, "BlendDataMetaBalls", NULL);
@@ -1204,17 +1167,12 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_metaballs_is_updated_get", NULL);
}
void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataFonts");
srna = RNA_def_struct(brna, "BlendDataFonts", NULL);
@@ -1246,22 +1204,17 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_fonts_is_updated_get", NULL);
}
void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataTextures");
srna = RNA_def_struct(brna, "BlendDataTextures", NULL);
RNA_def_struct_sdna(srna, "Main");
- RNA_def_struct_ui_text(srna, "Main Textures", "Collection of groups");
+ RNA_def_struct_ui_text(srna, "Main Textures", "Collection of textures");
func = RNA_def_function(srna, "new", "rna_Main_textures_new");
RNA_def_function_ui_description(func, "Add a new texture to the main database");
@@ -1288,17 +1241,12 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_textures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_textures_is_updated_get", NULL);
}
void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataBrushes");
srna = RNA_def_struct(brna, "BlendDataBrushes", NULL);
@@ -1330,9 +1278,10 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- 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_brushes_is_updated_get", NULL);
+ func = RNA_def_function(srna, "create_gpencil_data", "rna_Main_brush_gpencil_data");
+ RNA_def_function_ui_description(func, "Add grease pencil brush settings");
+ parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1340,7 +1289,6 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataWorlds");
srna = RNA_def_struct(brna, "BlendDataWorlds", NULL);
@@ -1370,51 +1318,42 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_worlds_is_updated_get", NULL);
}
-void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
+void RNA_def_main_collections(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
- RNA_def_property_srna(cprop, "BlendDataGroups");
- srna = RNA_def_struct(brna, "BlendDataGroups", NULL);
+ RNA_def_property_srna(cprop, "BlendDataCollections");
+ srna = RNA_def_struct(brna, "BlendDataCollections", NULL);
RNA_def_struct_sdna(srna, "Main");
- RNA_def_struct_ui_text(srna, "Main Groups", "Collection of groups");
+ RNA_def_struct_ui_text(srna, "Main Collections", "Collection of collections");
- func = RNA_def_function(srna, "new", "rna_Main_groups_new");
- RNA_def_function_ui_description(func, "Add a new group to the main database");
- parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the data-block");
+ func = RNA_def_function(srna, "new", "rna_Main_collections_new");
+ RNA_def_function_ui_description(func, "Add a new collection to the main database");
+ parm = RNA_def_string(func, "name", "Collection", 0, "", "New name for the data-block");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block");
+ parm = RNA_def_pointer(func, "collection", "Collection", "", "New collection data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
- RNA_def_function_ui_description(func, "Remove a group from the current blendfile");
+ RNA_def_function_ui_description(func, "Remove a collection from the current blendfile");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove");
+ parm = RNA_def_pointer(func, "collection", "Collection", "", "Collection to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
- RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it");
+ RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this collection before deleting it");
RNA_def_boolean(func, "do_id_user", true, "",
- "Decrement user counter of all datablocks used by this group");
+ "Decrement user counter of all datablocks used by this collection");
RNA_def_boolean(func, "do_ui_user", true, "",
- "Make sure interface does not reference this group");
+ "Make sure interface does not reference this collection");
- func = RNA_def_function(srna, "tag", "rna_Main_groups_tag");
+ func = RNA_def_function(srna, "tag", "rna_Main_collections_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_groups_is_updated_get", NULL);
}
void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1422,7 +1361,6 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataSpeakers");
srna = RNA_def_struct(brna, "BlendDataSpeakers", NULL);
@@ -1454,10 +1392,6 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_speakers_is_updated_get", NULL);
}
void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1465,7 +1399,6 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataTexts");
srna = RNA_def_struct(brna, "BlendDataTexts", NULL);
@@ -1506,10 +1439,6 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_texts_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_texts_is_updated_get", NULL);
}
void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1517,7 +1446,6 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataSounds");
srna = RNA_def_struct(brna, "BlendDataSounds", NULL);
@@ -1549,10 +1477,6 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_sounds_is_updated_get", NULL);
}
void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1560,7 +1484,6 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataArmatures");
srna = RNA_def_struct(brna, "BlendDataArmatures", NULL);
@@ -1592,17 +1515,12 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_armatures_is_updated_get", NULL);
}
void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataActions");
srna = RNA_def_struct(brna, "BlendDataActions", NULL);
@@ -1632,17 +1550,12 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_actions_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_actions_is_updated_get", NULL);
}
void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataParticles");
srna = RNA_def_struct(brna, "BlendDataParticles", NULL);
@@ -1672,17 +1585,13 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_particles_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_particles_is_updated_get", NULL);
}
+
void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataPalettes");
srna = RNA_def_struct(brna, "BlendDataPalettes", NULL);
@@ -1712,17 +1621,12 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_palettes_is_updated_get", NULL);
}
void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataCacheFiles");
srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL);
@@ -1732,17 +1636,12 @@ void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_cachefiles_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_paintcurves(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataPaintCurves");
srna = RNA_def_struct(brna, "BlendDataPaintCurves", NULL);
@@ -1752,17 +1651,12 @@ void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "tag", "rna_Main_paintcurves_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- 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_paintcurves_is_updated_get", NULL);
}
void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataGreasePencils");
srna = RNA_def_struct(brna, "BlendDataGreasePencils", NULL);
@@ -1792,10 +1686,6 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
"Decrement user counter of all datablocks used by this grease pencil");
RNA_def_boolean(func, "do_ui_user", true, "",
"Make sure interface does not reference this grease pencil");
-
- 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_gpencil_is_updated_get", NULL);
}
void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1803,7 +1693,6 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataMovieClips");
srna = RNA_def_struct(brna, "BlendDataMovieClips", NULL);
@@ -1839,10 +1728,6 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
/* return type */
parm = RNA_def_pointer(func, "clip", "MovieClip", "", "New movie clip data-block");
RNA_def_function_return(func, parm);
-
- 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_movieclips_is_updated_get", NULL);
}
void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1850,7 +1735,6 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataMasks");
srna = RNA_def_struct(brna, "BlendDataMasks", NULL);
@@ -1882,10 +1766,6 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
"Decrement user counter of all datablocks used by this mask");
RNA_def_boolean(func, "do_ui_user", true, "",
"Make sure interface does not reference this mask");
-
- 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_masks_is_updated_get", NULL);
}
void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1893,7 +1773,6 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
- PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataLineStyles");
srna = RNA_def_struct(brna, "BlendDataLineStyles", NULL);
@@ -1923,10 +1802,60 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
"Decrement user counter of all datablocks used by this line style");
RNA_def_boolean(func, "do_ui_user", true, "",
"Make sure interface does not reference this line style");
+}
+
+void RNA_def_main_workspaces(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "BlendDataWorkSpaces");
+ srna = RNA_def_struct(brna, "BlendDataWorkSpaces", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Workspaces", "Collection of workspaces");
+
+ func = RNA_def_function(srna, "tag", "rna_Main_workspaces_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+}
+
+void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
- 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_linestyle_is_updated_get", NULL);
+ RNA_def_property_srna(cprop, "BlendDataProbes");
+ srna = RNA_def_struct(brna, "BlendDataProbes", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Light Probes", "Collection of light probes");
+
+ func = RNA_def_function(srna, "new", "rna_Main_lightprobe_new");
+ RNA_def_function_ui_description(func, "Add a new probe to the main database");
+ parm = RNA_def_string(func, "name", "Probe", 0, "", "New name for the data-block");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "lightprobe", "LightProbe", "", "New light probe data-block");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove a probe from the current blendfile");
+ parm = RNA_def_pointer(func, "lightprobe", "LightProbe", "", "Probe to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_boolean(func, "do_unlink", true, "",
+ "Unlink all usages of this probe before deleting it "
+ "(WARNING: will also delete objects instancing that light probe data)");
+ RNA_def_boolean(func, "do_id_user", true, "",
+ "Decrement user counter of all datablocks used by this light probe");
+ RNA_def_boolean(func, "do_ui_user", true, "",
+ "Make sure interface does not reference this light probe");
+
+ func = RNA_def_function(srna, "tag", "rna_Main_lightprobes_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index c266e0e7f31..2cd427fbbd8 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -56,9 +56,10 @@
#include "DNA_movieclip_types.h"
-#include "BKE_depsgraph.h"
#include "BKE_mask.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "WM_api.h"
@@ -68,7 +69,7 @@ static void rna_Mask_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
Mask *mask = ptr->id.data;
WM_main_add_notifier(NC_MASK | ND_DATA, mask);
- DAG_id_tag_update( &mask->id, 0);
+ DEG_id_tag_update( &mask->id, 0);
}
static void rna_Mask_update_parent(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -448,7 +449,7 @@ static void rna_MaskLayer_spline_remove(ID *id, MaskLayer *mask_layer, ReportLis
RNA_POINTER_INVALIDATE(spline_ptr);
- DAG_id_tag_update(&mask->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&mask->id, OB_RECALC_DATA);
}
static void rna_Mask_start_frame_set(PointerRNA *ptr, int value)
@@ -522,7 +523,7 @@ static void rna_MaskSpline_points_add(ID *id, MaskSpline *spline, int count)
}
WM_main_add_notifier(NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
}
static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList *reports, PointerRNA *point_ptr)
@@ -582,7 +583,7 @@ static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList *
BKE_mask_layer_shape_changed_remove(layer, BKE_mask_layer_shape_spline_to_index(layer, spline) + point_index, 1);
WM_main_add_notifier(NC_MASK | ND_DATA, mask);
- DAG_id_tag_update(&mask->id, 0);
+ DEG_id_tag_update(&mask->id, 0);
RNA_POINTER_INVALIDATE(point_ptr);
}
@@ -810,7 +811,8 @@ static void rna_def_maskSplinePoints(BlenderRNA *brna)
func = RNA_def_function(srna, "add", "rna_MaskSpline_points_add");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Add a number of point to this spline");
- RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the spline", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* Remove the point */
func = RNA_def_function(srna, "remove", "rna_MaskSpline_point_remove");
@@ -931,19 +933,19 @@ static void rna_def_mask_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", MASK_RESTRICT_VIEW);
RNA_def_property_ui_text(prop, "Restrict View", "Restrict visibility in the viewport");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1);
RNA_def_property_update(prop, NC_MASK | ND_DRAW, NULL);
prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", MASK_RESTRICT_SELECT);
RNA_def_property_ui_text(prop, "Restrict Select", "Restrict selection in the viewport");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, -1);
RNA_def_property_update(prop, NC_MASK | ND_DRAW, NULL);
prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", MASK_RESTRICT_RENDER);
RNA_def_property_ui_text(prop, "Restrict Render", "Restrict renderability");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1);
RNA_def_property_update(prop, NC_MASK | NA_EDITED, NULL);
/* select (for dopesheet)*/
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 5bd12d727ed..2ad379f60eb 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -38,41 +38,30 @@
#include "WM_api.h"
#include "WM_types.h"
-static const EnumPropertyItem prop_texture_coordinates_items[] = {
- {TEXCO_GLOB, "GLOBAL", 0, "Global", "Use global coordinates for the texture coordinates"},
- {TEXCO_OBJECT, "OBJECT", 0, "Object", "Use linked object's coordinates for texture coordinates"},
- {TEXCO_UV, "UV", 0, "UV", "Use UV coordinates for texture coordinates"},
- {TEXCO_ORCO, "ORCO", 0, "Generated", "Use the original undeformed coordinates of the object"},
- {TEXCO_STRAND, "STRAND", 0, "Strand / Particle",
- "Use normalized strand texture coordinate (1D) or particle age (X) and trail position (Y)"},
- {TEXCO_WINDOW, "WINDOW", 0, "Window", "Use screen coordinates as texture coordinates"},
- {TEXCO_NORM, "NORMAL", 0, "Normal", "Use normal vector as texture coordinates"},
- {TEXCO_REFL, "REFLECTION", 0, "Reflection", "Use reflection vector as texture coordinates"},
- {TEXCO_STRESS, "STRESS", 0, "Stress",
- "Use the difference of edge lengths compared to original coordinates of the mesh"},
- {TEXCO_TANGENT, "TANGENT", 0, "Tangent", "Use the optional tangent vector as texture coordinates"},
- {0, NULL, 0, NULL, NULL}
-};
-
const EnumPropertyItem rna_enum_ramp_blend_items[] = {
{MA_RAMP_BLEND, "MIX", 0, "Mix", ""},
- {MA_RAMP_ADD, "ADD", 0, "Add", ""},
- {MA_RAMP_MULT, "MULTIPLY", 0, "Multiply", ""},
- {MA_RAMP_SUB, "SUBTRACT", 0, "Subtract", ""},
- {MA_RAMP_SCREEN, "SCREEN", 0, "Screen", ""},
- {MA_RAMP_DIV, "DIVIDE", 0, "Divide", ""},
- {MA_RAMP_DIFF, "DIFFERENCE", 0, "Difference", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{MA_RAMP_DARK, "DARKEN", 0, "Darken", ""},
+ {MA_RAMP_MULT, "MULTIPLY", 0, "Multiply", ""},
+ {MA_RAMP_BURN, "BURN", 0, "Burn", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{MA_RAMP_LIGHT, "LIGHTEN", 0, "Lighten", ""},
- {MA_RAMP_OVERLAY, "OVERLAY", 0, "Overlay", ""},
+ {MA_RAMP_SCREEN, "SCREEN", 0, "Screen", ""},
{MA_RAMP_DODGE, "DODGE", 0, "Dodge", ""},
- {MA_RAMP_BURN, "BURN", 0, "Burn", ""},
+ {MA_RAMP_ADD, "ADD", 0, "Add", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {MA_RAMP_OVERLAY, "OVERLAY", 0, "Overlay", ""},
+ {MA_RAMP_SOFT, "SOFT_LIGHT", 0, "Soft Light", ""},
+ {MA_RAMP_LINEAR, "LINEAR_LIGHT", 0, "Linear Light", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {MA_RAMP_DIFF, "DIFFERENCE", 0, "Difference", ""},
+ {MA_RAMP_SUB, "SUBTRACT", 0, "Subtract", ""},
+ {MA_RAMP_DIV, "DIVIDE", 0, "Divide", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{MA_RAMP_HUE, "HUE", 0, "Hue", ""},
{MA_RAMP_SAT, "SATURATION", 0, "Saturation", ""},
- {MA_RAMP_VAL, "VALUE", 0, "Value", ""},
{MA_RAMP_COLOR, "COLOR", 0, "Color", ""},
- {MA_RAMP_SOFT, "SOFT_LIGHT", 0, "Soft Light", ""},
- {MA_RAMP_LINEAR, "LINEAR_LIGHT", 0, "Linear Light", ""},
+ {MA_RAMP_VAL, "VALUE", 0, "Value", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -87,22 +76,28 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = {
#include "BKE_colorband.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
+#include "BKE_gpencil.h"
#include "BKE_material.h"
#include "BKE_texture.h"
#include "BKE_node.h"
#include "BKE_paint.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "ED_node.h"
#include "ED_image.h"
-#include "BKE_scene.h"
+#include "ED_screen.h"
+#include "ED_gpencil.h"
static void rna_Material_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Material *ma = ptr->id.data;
- DAG_id_tag_update(&ma->id, 0);
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, ma);
}
@@ -116,58 +111,28 @@ static void rna_Material_update_previews(Main *UNUSED(bmain), Scene *UNUSED(scen
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_PREVIEW, ma);
}
-static void rna_Material_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_MaterialGpencil_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Material *ma = ptr->id.data;
- DAG_id_tag_update(&ma->id, 0);
- WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ma);
-}
-
-static PointerRNA rna_Material_mirror_get(PointerRNA *ptr)
-{
- return rna_pointer_inherit_refine(ptr, &RNA_MaterialRaytraceMirror, ptr->id.data);
-}
-
-static PointerRNA rna_Material_transp_get(PointerRNA *ptr)
-{
- return rna_pointer_inherit_refine(ptr, &RNA_MaterialRaytraceTransparency, ptr->id.data);
-}
-
-static PointerRNA rna_Material_halo_get(PointerRNA *ptr)
-{
- return rna_pointer_inherit_refine(ptr, &RNA_MaterialHalo, ptr->id.data);
+ rna_Material_update(bmain, scene, ptr);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma);
}
-static PointerRNA rna_Material_sss_get(PointerRNA *ptr)
+static void rna_MaterialGpencil_nopreview_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- return rna_pointer_inherit_refine(ptr, &RNA_MaterialSubsurfaceScattering, ptr->id.data);
-}
+ Material *ma = ptr->id.data;
-static PointerRNA rna_Material_strand_get(PointerRNA *ptr)
-{
- return rna_pointer_inherit_refine(ptr, &RNA_MaterialStrand, ptr->id.data);
+ rna_Material_update(bmain, scene, ptr);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma);
}
-static PointerRNA rna_Material_physics_get(PointerRNA *ptr)
-{
- return rna_pointer_inherit_refine(ptr, &RNA_MaterialPhysics, ptr->id.data);
-}
-
-static void rna_Material_type_set(PointerRNA *ptr, int value)
+static void rna_Material_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- Material *ma = (Material *)ptr->data;
-
- if (ma->material_type == MA_TYPE_HALO && value != MA_TYPE_HALO)
- ma->mode &= ~(MA_STAR | MA_HALO_XALPHA | MA_ZINV | MA_ENV);
-
- ma->material_type = value;
-}
+ Material *ma = ptr->id.data;
-static void rna_Material_mtex_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- Material *ma = (Material *)ptr->data;
- rna_iterator_array_begin(iter, (void *)ma->mtex, sizeof(MTex *), MAX_MTEX, 0, NULL);
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ma);
}
static void rna_Material_texpaint_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -199,181 +164,47 @@ static void rna_Material_active_paint_texture_index_update(Main *bmain, Scene *s
if (ma->texpaintslot) {
Image *image = ma->texpaintslot[ma->paint_active_slot].ima;
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
+ wmWindow *win = ED_screen_window_find(sc, bmain->wm.first);
+ if (win == NULL) {
+ continue;
+ }
+
+ Object *obedit = NULL;
+ {
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ }
+
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
-
- if (!sima->pin)
- ED_space_image_set(bmain, sima, scene, scene->obedit, image);
+ if (!sima->pin) {
+ ED_space_image_set(bmain, sima, scene, obedit, image);
+ }
}
}
}
}
}
- DAG_id_tag_update(&ma->id, 0);
+ DEG_id_tag_update(&ma->id, 0);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, ma);
}
-static PointerRNA rna_Material_active_texture_get(PointerRNA *ptr)
-{
- Material *ma = (Material *)ptr->data;
- Tex *tex;
-
- tex = give_current_material_texture(ma);
- return rna_pointer_inherit_refine(ptr, &RNA_Texture, tex);
-}
-
-static void rna_Material_active_texture_set(PointerRNA *ptr, PointerRNA value)
-{
- Material *ma = (Material *)ptr->data;
-
- set_current_material_texture(ma, value.data);
-}
-
-static int rna_Material_active_texture_editable(PointerRNA *ptr, const char **UNUSED(r_info))
-{
- Material *ma = (Material *)ptr->id.data;
-
- return has_current_material_texture(ma) ? PROP_EDITABLE : 0;
-}
-
-static PointerRNA rna_Material_active_node_material_get(PointerRNA *ptr)
-{
- Material *ma = give_node_material((Material *)ptr->data);
- return rna_pointer_inherit_refine(ptr, &RNA_Material, ma);
-}
-
-static void rna_Material_active_node_material_set(PointerRNA *ptr, PointerRNA value)
-{
- Material *ma = (Material *)ptr->data;
- Material *ma_act = value.data;
-
- nodeSetActiveID(ma->nodetree, ID_MA, &ma_act->id);
-}
-
-static void rna_MaterialStrand_start_size_range(PointerRNA *ptr, float *min, float *max,
- float *UNUSED(softmin), float *UNUSED(softmax))
-{
- Material *ma = (Material *)ptr->id.data;
-
- if (ma->mode & MA_STR_B_UNITS) {
- *min = 0.0001f;
- *max = 2.0f;
- }
- else {
- *min = 0.25f;
- *max = 20.0f;
- }
-}
-
-static void rna_MaterialStrand_end_size_range(PointerRNA *ptr, float *min, float *max,
- float *UNUSED(softmin), float *UNUSED(softmax))
-{
- Material *ma = (Material *)ptr->id.data;
-
- if (ma->mode & MA_STR_B_UNITS) {
- *min = 0.0001f;
- *max = 1.0f;
- }
- else {
- *min = 0.25f;
- *max = 10.0f;
- }
-}
-
-static bool rna_MaterialTextureSlot_use_get(PointerRNA *ptr)
-{
- Material *ma = (Material *)ptr->id.data;
- MTex *mtex = (MTex *)ptr->data;
- int a;
-
- for (a = 0; a < MAX_MTEX; a++)
- if (ma->mtex[a] == mtex)
- return (ma->septex & (1 << a)) == 0;
-
- return 0;
-}
-
-static void rna_MaterialTextureSlot_use_set(PointerRNA *ptr, bool value)
-{
- Material *ma = (Material *)ptr->id.data;
- MTex *mtex = (MTex *)ptr->data;
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] == mtex) {
- if (value)
- ma->septex &= ~(1 << a);
- else
- ma->septex |= (1 << a);
- }
- }
-}
-
-static void rna_Material_use_diffuse_ramp_set(PointerRNA *ptr, bool value)
-{
- Material *ma = (Material *)ptr->data;
-
- if (value) ma->mode |= MA_RAMP_COL;
- else ma->mode &= ~MA_RAMP_COL;
-
- if ((ma->mode & MA_RAMP_COL) && ma->ramp_col == NULL)
- ma->ramp_col = BKE_colorband_add(false);
-}
-
-static void rna_Material_use_specular_ramp_set(PointerRNA *ptr, bool value)
-{
- Material *ma = (Material *)ptr->data;
-
- if (value) ma->mode |= MA_RAMP_SPEC;
- else ma->mode &= ~MA_RAMP_SPEC;
-
- if ((ma->mode & MA_RAMP_SPEC) && ma->ramp_spec == NULL)
- ma->ramp_spec = BKE_colorband_add(false);
-}
-
static void rna_Material_use_nodes_update(bContext *C, PointerRNA *ptr)
{
Material *ma = (Material *)ptr->data;
+ Main *bmain = CTX_data_main(C);
if (ma->use_nodes && ma->nodetree == NULL)
ED_node_shader_default(C, &ma->id);
- rna_Material_draw_update(CTX_data_main(C), CTX_data_scene(C), ptr);
-}
-
-static const EnumPropertyItem *rna_Material_texture_coordinates_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
-{
- Material *ma = (Material *)ptr->id.data;
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_GLOB);
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_OBJECT);
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_ORCO);
-
- if (ma->material_type == MA_TYPE_VOLUME) {
- /* pass */
- }
- else if (ELEM(ma->material_type, MA_TYPE_SURFACE, MA_TYPE_HALO, MA_TYPE_WIRE)) {
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_UV);
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_STRAND);
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_WINDOW);
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_NORM);
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_REFL);
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_STRESS);
- RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_TANGENT);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
+ DEG_id_tag_update(&ma->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ rna_Material_draw_update(bmain, CTX_data_scene(C), ptr);
}
MTex *rna_mtex_texture_slots_add(ID *self_id, struct bContext *C, ReportList *reports)
@@ -428,7 +259,7 @@ void rna_mtex_texture_slots_clear(ID *self_id, struct bContext *C, ReportList *r
id_us_min((ID *)mtex_ar[index]->tex);
MEM_freeN(mtex_ar[index]);
mtex_ar[index] = NULL;
- DAG_id_tag_update(self_id, 0);
+ DEG_id_tag_update(self_id, 0);
}
/* for redraw only */
@@ -462,470 +293,65 @@ static void rna_TexPaintSlot_uv_layer_set(PointerRNA *ptr, const char *value)
}
}
-
-#else
-
-static void rna_def_material_mtex(BlenderRNA *brna)
+static bool rna_is_grease_pencil_get(PointerRNA *ptr)
{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_mapping_items[] = {
- {MTEX_FLAT, "FLAT", 0, "Flat", "Map X and Y coordinates directly"},
- {MTEX_CUBE, "CUBE", 0, "Cube", "Map using the normal vector"},
- {MTEX_TUBE, "TUBE", 0, "Tube", "Map with Z as central axis"},
- {MTEX_SPHERE, "SPHERE", 0, "Sphere", "Map with Z as central axis"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_x_mapping_items[] = {
- {0, "NONE", 0, "None", ""},
- {1, "X", 0, "X", ""},
- {2, "Y", 0, "Y", ""},
- {3, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_y_mapping_items[] = {
- {0, "NONE", 0, "None", ""},
- {1, "X", 0, "X", ""},
- {2, "Y", 0, "Y", ""},
- {3, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_z_mapping_items[] = {
- {0, "NONE", 0, "None", ""},
- {1, "X", 0, "X", ""},
- {2, "Y", 0, "Y", ""},
- {3, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_normal_map_space_items[] = {
- {MTEX_NSPACE_CAMERA, "CAMERA", 0, "Camera", ""},
- {MTEX_NSPACE_WORLD, "WORLD", 0, "World", ""},
- {MTEX_NSPACE_OBJECT, "OBJECT", 0, "Object", ""},
- {MTEX_NSPACE_TANGENT, "TANGENT", 0, "Tangent", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_bump_method_items[] = {
- {0, "BUMP_ORIGINAL", 0, "Original", ""},
- {MTEX_COMPAT_BUMP, "BUMP_COMPATIBLE", 0, "Compatible", ""},
- {MTEX_3TAP_BUMP, "BUMP_LOW_QUALITY", 0, "Low Quality", "Use 3 tap filtering"},
- {MTEX_5TAP_BUMP, "BUMP_MEDIUM_QUALITY", 0, "Medium Quality", "Use 5 tap filtering"},
- {MTEX_BICUBIC_BUMP, "BUMP_BEST_QUALITY", 0,
- "Best Quality", "Use bicubic filtering (requires OpenGL 3.0+, it will fall back on "
- "medium setting for other systems)"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_bump_space_items[] = {
- {0, "BUMP_VIEWSPACE", 0, "ViewSpace", ""},
- {MTEX_BUMP_OBJECTSPACE, "BUMP_OBJECTSPACE", 0, "ObjectSpace", ""},
- {MTEX_BUMP_TEXTURESPACE, "BUMP_TEXTURESPACE", 0, "TextureSpace", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "MaterialTextureSlot", "TextureSlot");
- RNA_def_struct_sdna(srna, "MTex");
- RNA_def_struct_ui_text(srna, "Material Texture Slot", "Texture slot for textures in a Material data-block");
-
- prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "texco");
- RNA_def_property_enum_items(prop, prop_texture_coordinates_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Material_texture_coordinates_itemf");
- RNA_def_property_ui_text(prop, "Texture Coordinates", "");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "object");
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Object", "Object to use for mapping with Object texture coordinates");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "uvname");
- RNA_def_property_ui_text(prop, "UV Map", "UV map to use for mapping with UV texture coordinates");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_from_dupli", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_DUPLI_MAPTO);
- RNA_def_property_ui_text(prop, "From Dupli",
- "Dupli's instanced from verts, faces or particles, inherit texture coordinate "
- "from their parent");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_to_bounds", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_MAPTO_BOUNDS);
- RNA_def_property_ui_text(prop, "Map to Bounds",
- "Map coordinates in object bounds");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_from_original", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_OB_DUPLI_ORIG);
- RNA_def_property_ui_text(prop, "From Original",
- "Dupli's derive their object coordinates from the original object's transformation");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_color_diffuse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_COL);
- RNA_def_property_ui_text(prop, "Diffuse Color", "The texture affects basic color of the material");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_normal", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_NORM);
- RNA_def_property_ui_text(prop, "Normal", "The texture affects the rendered normal");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_color_spec", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_COLSPEC);
- RNA_def_property_ui_text(prop, "Specular Color", "The texture affects the specularity color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_mirror", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_COLMIR);
- RNA_def_property_ui_text(prop, "Mirror", "The texture affects the mirror color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_diffuse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_REF);
- RNA_def_property_ui_text(prop, "Diffuse", "The texture affects the value of diffuse reflectivity");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_specular", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_SPEC);
- RNA_def_property_ui_text(prop, "Specular", "The texture affects the value of specular reflectivity");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_ambient", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_AMB);
- RNA_def_property_ui_text(prop, "Ambient", "The texture affects the value of ambient");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_hardness", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_HAR);
- RNA_def_property_ui_text(prop, "Hardness", "The texture affects the hardness value");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_raymir", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_RAYMIRR);
- RNA_def_property_ui_text(prop, "Ray-Mirror", "The texture affects the ray-mirror value");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_alpha", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_ALPHA);
- RNA_def_property_ui_text(prop, "Alpha", "The texture affects the alpha value");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_emit", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_EMIT);
- RNA_def_property_ui_text(prop, "Emit", "The texture affects the emit value");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_translucency", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_TRANSLU);
- RNA_def_property_ui_text(prop, "Translucency", "The texture affects the translucency value");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_displacement", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_DISPLACE);
- RNA_def_property_ui_text(prop, "Displacement", "Let the texture displace the surface");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_warp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_WARP);
- RNA_def_property_ui_text(prop, "Warp", "Let the texture warp texture coordinates of next channels");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "mapping_x", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "projx");
- RNA_def_property_enum_items(prop, prop_x_mapping_items);
- RNA_def_property_ui_text(prop, "X Mapping", "");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "mapping_y", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "projy");
- RNA_def_property_enum_items(prop, prop_y_mapping_items);
- RNA_def_property_ui_text(prop, "Y Mapping", "");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "mapping_z", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "projz");
- RNA_def_property_enum_items(prop, prop_z_mapping_items);
- RNA_def_property_ui_text(prop, "Z Mapping", "");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, prop_mapping_items);
- RNA_def_property_ui_text(prop, "Mapping", "");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "normal_map_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "normapspace");
- RNA_def_property_enum_items(prop, prop_normal_map_space_items);
- RNA_def_property_ui_text(prop, "Normal Map Space", "Set space of normal map image");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "normal_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "norfac");
- RNA_def_property_ui_range(prop, -5, 5, 10, 3);
- RNA_def_property_ui_text(prop, "Normal Factor", "Amount texture affects normal values");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "displacement_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dispfac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Displacement Factor", "Amount texture displaces the surface");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "warp_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "warpfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Warp Factor", "Amount texture affects texture coordinates of next channels");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_color_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "colspecfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Specular Color Factor", "Amount texture affects specular color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_color_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "colfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Diffuse Color Factor", "Amount texture affects diffuse color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "mirror_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "mirrfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Mirror Factor", "Amount texture affects mirror color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "alpha_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "alphafac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Alpha Factor", "Amount texture affects alpha");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "difffac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Diffuse Factor", "Amount texture affects diffuse reflectivity");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "specfac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Specular Factor", "Amount texture affects specular reflectivity");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "emit_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "emitfac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Emit Factor", "Amount texture affects emission");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "hardness_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "hardfac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Hardness Factor", "Amount texture affects hardness");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "raymir_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "raymirrfac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Ray Mirror Factor", "Amount texture affects ray mirror");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "translucency_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "translfac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Translucency Factor", "Amount texture affects translucency");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "ambient_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ambfac");
- RNA_def_property_ui_range(prop, -1, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Ambient Factor", "Amount texture affects ambient");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- /* volume material */
- prop = RNA_def_property(srna, "use_map_color_emission", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_EMISSION_COL);
- RNA_def_property_ui_text(prop, "Emission Color", "The texture affects the color of emission");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_color_reflection", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_REFLECTION_COL);
- RNA_def_property_ui_text(prop, "Reflection Color", "The texture affects the color of scattered light");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_color_transmission", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_TRANSMISSION_COL);
- RNA_def_property_ui_text(prop, "Transmission Color",
- "The texture affects the result color after other light has been scattered/absorbed");
- RNA_def_property_update(prop, NC_TEXTURE, NULL);
-
- prop = RNA_def_property(srna, "use_map_density", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_DENSITY);
- RNA_def_property_ui_text(prop, "Density", "The texture affects the volume's density");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_emission", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_EMISSION);
- RNA_def_property_ui_text(prop, "Emission", "The texture affects the volume's emission");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_scatter", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_SCATTERING);
- RNA_def_property_ui_text(prop, "Scattering", "The texture affects the volume's scattering");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_map_reflect", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_REFLECTION);
- RNA_def_property_ui_text(prop, "Reflection", "The texture affects the reflected light's brightness");
- RNA_def_property_update(prop, NC_TEXTURE, NULL);
-
- prop = RNA_def_property(srna, "emission_color_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "colemitfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Emission Color Factor", "Amount texture affects emission color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "reflection_color_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "colreflfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Reflection Color Factor", "Amount texture affects color of out-scattered light");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "transmission_color_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "coltransfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Transmission Color Factor",
- "Amount texture affects result color after light has been scattered/absorbed");
- RNA_def_property_update(prop, NC_TEXTURE, NULL);
-
- prop = RNA_def_property(srna, "density_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "densfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Density Factor", "Amount texture affects density");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "emission_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "emitfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Emission Factor", "Amount texture affects emission");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "scattering_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "scatterfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Scattering Factor", "Amount texture affects scattering");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "reflection_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "reflfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Reflection Factor", "Amount texture affects brightness of out-scattered light");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- /* end volume material */
-
- prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_MaterialTextureSlot_use_get", "rna_MaterialTextureSlot_use_set");
- RNA_def_property_ui_text(prop, "Enabled", "Enable this material texture slot");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "bump_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "texflag");
- RNA_def_property_enum_items(prop, prop_bump_method_items);
- RNA_def_property_ui_text(prop, "Bump Method", "Method to use for bump mapping");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ Material *ma = (Material *)ptr->data;
+ if (ma->gp_style != NULL)
+ return true;
- prop = RNA_def_property(srna, "bump_objectspace", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "texflag");
- RNA_def_property_enum_items(prop, prop_bump_space_items);
- RNA_def_property_ui_text(prop, "Bump Space", "Space to apply bump mapping in");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ return false;
}
-static void rna_def_material_gamesettings(BlenderRNA *brna)
+static void rna_gpcolordata_uv_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_alpha_blend_items[] = {
- {GEMAT_SOLID, "OPAQUE", 0, "Opaque", "Render color of textured face as color"},
- {GEMAT_ADD, "ADD", 0, "Add", "Render face transparent and add color of face"},
- {GEMAT_CLIP, "CLIP", 0, "Alpha Clip", "Use the image alpha values clipped with no blending (binary alpha)"},
- {GEMAT_ALPHA, "ALPHA", 0, "Alpha Blend",
- "Render polygon transparent, depending on alpha channel of the texture"},
- {GEMAT_ALPHA_SORT, "ALPHA_SORT", 0, "Alpha Sort",
- "Sort faces for correct alpha drawing (slow, use Alpha Clip instead when possible)"},
- {GEMAT_ALPHA_TO_COVERAGE, "ALPHA_ANTIALIASING", 0, "Alpha Anti-Aliasing",
- "Use textures alpha as anti-aliasing mask, requires multi-sample OpenGL display"},
- {0, NULL, 0, NULL, NULL}
- };
+ /* update all uv strokes of this color */
+ Material *ma = ptr->id.data;
+ ED_gpencil_update_color_uv(bmain, ma);
- static const EnumPropertyItem prop_face_orientation_items[] = {
- {GEMAT_NORMAL, "NORMAL", 0, "Normal", "No transformation"},
- {GEMAT_HALO, "HALO", 0, "Halo", "Screen aligned billboard"},
- {GEMAT_BILLBOARD, "BILLBOARD", 0, "Billboard", "Billboard with Z-axis constraint"},
- {GEMAT_SHADOW, "SHADOW", 0, "Shadow", "Faces are used for shadow"},
- {0, NULL, 0, NULL, NULL}
- };
+ rna_MaterialGpencil_update(bmain, scene, ptr);
+}
- srna = RNA_def_struct(brna, "MaterialGameSettings", NULL);
- RNA_def_struct_sdna(srna, "GameSettings");
- RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Game Settings", "Game Engine settings for a Material data-block");
+static char *rna_GpencilColorData_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_sprintfN("grease_pencil");
+}
- prop = RNA_def_property(srna, "use_backface_culling", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GEMAT_BACKCULL); /* use bitflags */
- RNA_def_property_ui_text(prop, "Backface Culling", "Hide Back of the face in Game Engine ");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
+static int rna_GpencilColorData_is_stroke_visible_get(PointerRNA *ptr)
+{
+ MaterialGPencilStyle *pcolor = ptr->data;
+ return (pcolor->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH);
+}
- prop = RNA_def_property(srna, "text", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GEMAT_TEXT); /* use bitflags */
- RNA_def_property_ui_text(prop, "Text", "Use material as text in Game Engine ");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
+static int rna_GpencilColorData_is_fill_visible_get(PointerRNA *ptr)
+{
+ MaterialGPencilStyle *pcolor = (MaterialGPencilStyle *)ptr->data;
+ return ((pcolor->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (pcolor->fill_style > 0));
+}
- prop = RNA_def_property(srna, "invisible", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GEMAT_INVISIBLE); /* use bitflags */
- RNA_def_property_ui_text(prop, "Invisible", "Make face invisible");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
+static void rna_GpencilColorData_stroke_image_set(PointerRNA *ptr, PointerRNA value)
+{
+ MaterialGPencilStyle *pcolor = ptr->data;
+ ID *id = value.data;
- prop = RNA_def_property(srna, "alpha_blend", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "alpha_blend");
- RNA_def_property_enum_items(prop, prop_alpha_blend_items);
- RNA_def_property_ui_text(prop, "Blend Mode", "Blend Mode for Transparent Faces");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
+ id_us_plus(id);
+ pcolor->sima = (struct Image *)id;
+}
- prop = RNA_def_property(srna, "face_orientation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, prop_face_orientation_items);
- RNA_def_property_ui_text(prop, "Face Orientations", "Especial face orientation options");
+static void rna_GpencilColorData_fill_image_set(PointerRNA *ptr, PointerRNA value)
+{
+ MaterialGPencilStyle *pcolor = (MaterialGPencilStyle *)ptr->data;
+ ID *id = value.data;
- prop = RNA_def_property(srna, "physics", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GEMAT_NOPHYSICS); /* use bitflags */
- RNA_def_property_ui_text(prop, "Physics", "Use physics properties of materials ");
+ id_us_plus(id);
+ pcolor->ima = (struct Image *)id;
}
-static void rna_def_material_colors(StructRNA *srna)
+#else
+
+static void rna_def_material_display(StructRNA *srna)
{
PropertyRNA *prop;
- static const EnumPropertyItem prop_ramp_input_items[] = {
- {MA_RAMP_IN_SHADER, "SHADER", 0, "Shader", ""},
- {MA_RAMP_IN_ENERGY, "ENERGY", 0, "Energy", ""},
- {MA_RAMP_IN_NOR, "NORMAL", 0, "Normal", ""},
- {MA_RAMP_IN_RESULT, "RESULT", 0, "Result", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
prop = RNA_def_property(srna, "diffuse_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "r");
RNA_def_property_array(prop, 3);
@@ -938,82 +364,24 @@ static void rna_def_material_colors(StructRNA *srna)
RNA_def_property_ui_text(prop, "Specular Color", "Specular color of the material");
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "mirror_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "mirr");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Mirror Color", "Mirror color of the material");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Alpha", "Alpha transparency of the material");
+ prop = RNA_def_property(srna, "roughness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "roughness");
+ RNA_def_property_float_default(prop, 0.25f);
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_text(prop, "Roughness", "Roughness of the material");
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "specular_alpha", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "spectra");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Specular Alpha", "Alpha transparency for specular areas");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- /* Color bands */
- prop = RNA_def_property(srna, "use_diffuse_ramp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_RAMP_COL);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Material_use_diffuse_ramp_set");
- RNA_def_property_ui_text(prop, "Use Diffuse Ramp", "Toggle diffuse ramp operations");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_ramp", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "ramp_col");
- RNA_def_property_struct_type(prop, "ColorRamp");
- RNA_def_property_ui_text(prop, "Diffuse Ramp", "Color ramp used to affect diffuse shading");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_specular_ramp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_RAMP_SPEC);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Material_use_specular_ramp_set");
- RNA_def_property_ui_text(prop, "Use Specular Ramp", "Toggle specular ramp operations");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_ramp", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "ramp_spec");
- RNA_def_property_struct_type(prop, "ColorRamp");
- RNA_def_property_ui_text(prop, "Specular Ramp", "Color ramp used to affect specular shading");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_ramp_blend", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "rampblend_col");
- RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
- RNA_def_property_ui_text(prop, "Diffuse Ramp Blend", "Blending method of the ramp and the diffuse color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_ramp_blend", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "rampblend_spec");
- RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
- RNA_def_property_ui_text(prop, "Specular Ramp Blend", "Blending method of the ramp and the specular color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_ramp_input", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "rampin_col");
- RNA_def_property_enum_items(prop, prop_ramp_input_items);
- RNA_def_property_ui_text(prop, "Diffuse Ramp Input", "How the ramp maps on the surface");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_ramp_input", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "rampin_spec");
- RNA_def_property_enum_items(prop, prop_ramp_input_items);
- RNA_def_property_ui_text(prop, "Specular Ramp Input", "How the ramp maps on the surface");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_ramp_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "rampfac_col");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Diffuse Ramp Factor", "Blending factor (also uses alpha in Colorband)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ prop = RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "spec");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_text(prop, "Specular", "How intense (bright) the specular reflection is");
+ RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "specular_ramp_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "rampfac_spec");
+ prop = RNA_def_property(srna, "metallic", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "metallic");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Specular Ramp Factor", "Blending factor (also uses alpha in Colorband)");
+ RNA_def_property_ui_text(prop, "Metallic", "Amount of mirror reflection for raytrace");
RNA_def_property_update(prop, 0, "rna_Material_update");
/* Freestyle line color */
@@ -1031,768 +399,259 @@ static void rna_def_material_colors(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Material_update");
}
-static void rna_def_material_diffuse(StructRNA *srna)
+static void rna_def_material_greasepencil(BlenderRNA *brna)
{
+ StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem prop_diff_shader_items[] = {
- {MA_DIFF_LAMBERT, "LAMBERT", 0, "Lambert", "Use a Lambertian shader"},
- {MA_DIFF_ORENNAYAR, "OREN_NAYAR", 0, "Oren-Nayar", "Use an Oren-Nayar shader"},
- {MA_DIFF_TOON, "TOON", 0, "Toon", "Use a toon shader"},
- {MA_DIFF_MINNAERT, "MINNAERT", 0, "Minnaert", "Use a Minnaert shader"},
- {MA_DIFF_FRESNEL, "FRESNEL", 0, "Fresnel", "Use a Fresnel shader"},
+ /* mode type styles */
+ static EnumPropertyItem gpcolordata_mode_types_items[] = {
+ {GP_STYLE_MODE_LINE, "LINE", 0, "Line", "Draw strokes using a continuous line"},
+ {GP_STYLE_MODE_DOTS, "DOTS", 0, "Dots", "Draw strokes using separated dots"},
+ {GP_STYLE_MODE_BOX, "BOX", 0, "Boxes", "Draw strokes using separated rectangle boxes"},
{0, NULL, 0, NULL, NULL}
};
- prop = RNA_def_property(srna, "diffuse_shader", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "diff_shader");
- RNA_def_property_enum_items(prop, prop_diff_shader_items);
- RNA_def_property_ui_text(prop, "Diffuse Shader Model", "");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_intensity", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "ref");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Diffuse Intensity", "Amount of diffuse reflection");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
-
- prop = RNA_def_property(srna, "roughness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 3.14f);
- RNA_def_property_ui_text(prop, "Roughness", "Oren-Nayar Roughness");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_toon_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "param[0]");
- RNA_def_property_range(prop, 0.0f, 3.14f);
- RNA_def_property_ui_text(prop, "Diffuse Toon Size", "Size of diffuse toon area");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_toon_smooth", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "param[1]");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Diffuse Toon Smooth", "Smoothness of diffuse toon area");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_fresnel", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "param[1]");
- RNA_def_property_range(prop, 0.0f, 5.0f);
- RNA_def_property_ui_text(prop, "Diffuse Fresnel", "Power of Fresnel");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "diffuse_fresnel_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "param[0]");
- RNA_def_property_range(prop, 0.0f, 5.0f);
- RNA_def_property_ui_text(prop, "Diffuse Fresnel Factor", "Blending factor of Fresnel");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "darkness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 2.0f);
- RNA_def_property_ui_text(prop, "Darkness", "Minnaert darkness");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-}
-
-static void rna_def_material_raymirror(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_fadeto_mir_items[] = {
- {MA_RAYMIR_FADETOSKY, "FADE_TO_SKY", 0, "Sky", ""},
- {MA_RAYMIR_FADETOMAT, "FADE_TO_MATERIAL", 0, "Material", ""},
+ /* stroke styles */
+ static EnumPropertyItem stroke_style_items[] = {
+ {GP_STYLE_STROKE_STYLE_SOLID, "SOLID", 0, "Solid", "Draw strokes with solid color"},
+ {GP_STYLE_STROKE_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Draw strokes using texture"},
{0, NULL, 0, NULL, NULL}
};
- srna = RNA_def_struct(brna, "MaterialRaytraceMirror", NULL);
- RNA_def_struct_sdna(srna, "Material");
- RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Raytrace Mirror", "Raytraced reflection settings for a Material data-block");
-
- prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_RAYMIRROR); /* use bitflags */
- RNA_def_property_ui_text(prop, "Enabled", "Enable raytraced reflections");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "reflect_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "ray_mirror");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Reflectivity", "Amount of mirror reflection for raytrace");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "fresnel", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "fresnel_mir");
- RNA_def_property_range(prop, 0.0f, 5.0f);
- RNA_def_property_ui_text(prop, "Fresnel", "Power of Fresnel for mirror reflection");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "fresnel_mir_i");
- RNA_def_property_range(prop, 0.0f, 5.0f);
- RNA_def_property_ui_text(prop, "Fresnel Factor", "Blending factor for Fresnel");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "gloss_mir");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Gloss Amount",
- "The shininess of the reflection (values < 1.0 give diffuse, blurry reflections)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "gloss_anisotropic", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "aniso_gloss_mir");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Gloss Anisotropy",
- "The shape of the reflection, from 0.0 (circular) to 1.0 "
- "(fully stretched along the tangent");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "gloss_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "samp_gloss_mir");
- RNA_def_property_range(prop, 0, 1024);
- RNA_def_property_ui_text(prop, "Gloss Samples", "Number of cone samples averaged for blurry reflections");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "adapt_thresh_mir");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Gloss Threshold",
- "Threshold for adaptive sampling (if a sample contributes less than "
- "this amount [as a percentage], sampling is stopped)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "ray_depth");
- RNA_def_property_ui_range(prop, 0, 100, 1, 3);
- RNA_def_property_ui_text(prop, "Depth", "Maximum allowed number of light inter-reflections");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "dist_mir");
- RNA_def_property_range(prop, 0.0f, 10000.0f);
- RNA_def_property_ui_text(prop, "Maximum Distance",
- "Maximum distance of reflected rays (reflections further than this "
- "range fade to sky color or material color)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "fade_to", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "fadeto_mir");
- RNA_def_property_enum_items(prop, prop_fadeto_mir_items);
- RNA_def_property_ui_text(prop, "Fade-out Color",
- "The color that rays with no intersection within the Max Distance take "
- "(material color can be best for indoor scenes, sky color for outdoor)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-}
-
-static void rna_def_material_raytra(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "MaterialRaytraceTransparency", NULL);
- RNA_def_struct_sdna(srna, "Material");
- RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Raytrace Transparency",
- "Raytraced refraction settings for a Material data-block");
-
- prop = RNA_def_property(srna, "ior", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ang");
- RNA_def_property_range(prop, 0.25f, 4.0f);
- RNA_def_property_ui_text(prop, "IOR", "Angular index of refraction for raytraced refraction");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "fresnel", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "fresnel_tra");
- RNA_def_property_range(prop, 0.0f, 5.0f);
- RNA_def_property_ui_text(prop, "Fresnel", "Power of Fresnel for transparency (Ray or ZTransp)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "fresnel_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "fresnel_tra_i");
- RNA_def_property_range(prop, 1.0f, 5.0f);
- RNA_def_property_ui_text(prop, "Fresnel Factor", "Blending factor for Fresnel");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "gloss_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "gloss_tra");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Gloss Amount",
- "The clarity of the refraction. Values < 1.0 give diffuse, blurry refractions");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "gloss_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "samp_gloss_tra");
- RNA_def_property_range(prop, 0, 1024);
- RNA_def_property_ui_text(prop, "Gloss Samples", "Number of cone samples averaged for blurry refractions");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "gloss_threshold", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "adapt_thresh_tra");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Gloss Threshold",
- "Threshold for adaptive sampling. If a sample contributes less than "
- "this amount (as a percentage), sampling is stopped");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "ray_depth_tra");
- RNA_def_property_ui_range(prop, 0, 100, 1, 3);
- RNA_def_property_ui_text(prop, "Depth", "Maximum allowed number of light inter-refractions");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "filter", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "filter");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Filter",
- "Amount to blend in the material's diffuse color in raytraced "
- "transparency (simulating absorption)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "depth_max", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "tx_limit");
- RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_text(prop, "Limit",
- "Maximum depth for light to travel through the transparent material "
- "before becoming fully filtered (0.0 is disabled)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "tx_falloff");
- RNA_def_property_range(prop, 0.1f, 10.0f);
- RNA_def_property_ui_text(prop, "Falloff", "Falloff power for transmissivity filter effect (1.0 is linear)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-}
-
-static void rna_def_material_volume(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_lighting_items[] = {
- {MA_VOL_SHADE_SHADELESS, "SHADELESS", 0, "Shadeless", "Do not calculate lighting and shadows"},
- {MA_VOL_SHADE_SHADOWED, "SHADOWED", 0, "Shadowed", ""},
- {MA_VOL_SHADE_SHADED, "SHADED", 0, "Shaded", ""},
- {MA_VOL_SHADE_MULTIPLE, "MULTIPLE_SCATTERING", 0, "Multiple Scattering", ""},
- {MA_VOL_SHADE_SHADEDPLUSMULTIPLE, "SHADED_PLUS_MULTIPLE_SCATTERING", 0, "Shaded + Multiple Scattering", ""},
+ /* fill styles */
+ static EnumPropertyItem fill_style_items[] = {
+ {GP_STYLE_FILL_STYLE_SOLID, "SOLID", 0, "Solid", "Fill area with solid color"},
+ {GP_STYLE_FILL_STYLE_GRADIENT, "GRADIENT", 0, "Gradient", "Fill area with gradient color"},
+ {GP_STYLE_FILL_STYLE_CHESSBOARD, "CHESSBOARD", 0, "Checker Board", "Fill area with chessboard pattern"},
+ {GP_STYLE_FILL_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Fill area with image texture"},
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem prop_stepsize_items[] = {
- {MA_VOL_STEP_RANDOMIZED, "RANDOMIZED", 0, "Randomized", ""},
- {MA_VOL_STEP_CONSTANT, "CONSTANT", 0, "Constant", ""},
- /*{MA_VOL_STEP_ADAPTIVE, "ADAPTIVE", 0, "Adaptive", ""}, */
+ static EnumPropertyItem fill_gradient_items[] = {
+ {GP_STYLE_GRADIENT_LINEAR, "LINEAR", 0, "Linear", "Fill area with gradient color"},
+ {GP_STYLE_GRADIENT_RADIAL, "RADIAL", 0, "Radial", "Fill area with radial gradient"},
{0, NULL, 0, NULL, NULL}
};
- srna = RNA_def_struct(brna, "MaterialVolume", NULL);
- RNA_def_struct_sdna(srna, "VolumeSettings");
- RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Volume", "Volume rendering settings for a Material data-block");
-
- prop = RNA_def_property(srna, "step_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "stepsize_type");
- RNA_def_property_enum_items(prop, prop_stepsize_items);
- RNA_def_property_ui_text(prop, "Step Calculation", "Method of calculating the steps through the volume");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "step_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "stepsize");
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001f, 1.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Step Size", "Distance between subsequent volume depth samples");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ srna = RNA_def_struct(brna, "MaterialGPencilStyle", NULL);
+ RNA_def_struct_sdna(srna, "MaterialGPencilStyle");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Color", "");
+ RNA_def_struct_path_func(srna, "rna_GpencilColorData_path");
- prop = RNA_def_property(srna, "light_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "shade_type");
- RNA_def_property_enum_items(prop, prop_lighting_items);
- RNA_def_property_ui_text(prop, "Lighting Mode",
- "Method of shading, attenuating, and scattering light through the volume");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_external_shadows", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "shadeflag", MA_VOL_RECV_EXT_SHADOW); /* use bitflags */
- RNA_def_property_ui_text(prop, "External Shadows", "Receive shadows from sources outside the volume (temporary)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_light_cache", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "shadeflag", MA_VOL_PRECACHESHADING); /* use bitflags */
- RNA_def_property_ui_text(prop, "Light Cache",
- "Pre-calculate the shading information into a voxel grid, "
- "speeds up shading at slightly less accuracy");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "cache_resolution", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "precache_resolution");
- RNA_def_property_range(prop, 1, 1024);
- RNA_def_property_ui_text(prop, "Resolution",
- "Resolution of the voxel grid, low resolutions are faster, "
- "high resolutions use more memory");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "ms_diffusion", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ms_diff");
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_text(prop, "Diffusion", "Diffusion factor, the strength of the blurring effect");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "ms_spread", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ms_spread");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Spread", "Proportional distance over which the light is diffused");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "ms_intensity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ms_intensity");
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_text(prop, "Intensity", "Multiplier for multiple scattered light energy");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "stroke_rgba");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
- prop = RNA_def_property(srna, "depth_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "depth_cutoff");
+ /* Fill Drawing Color */
+ prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "fill_rgba");
+ RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Depth Cutoff",
- "Stop ray marching early if transmission drops below this luminance - "
- "higher values give speedups in dense volumes at the expense of accuracy");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
- prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "density");
+ /* Secondary Drawing Color */
+ prop = RNA_def_property(srna, "mix_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "mix_rgba");
+ RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Density", "The base density of the volume");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ RNA_def_property_ui_text(prop, "Mix Color", "Color for mixing with primary filling color");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
- prop = RNA_def_property(srna, "density_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "density_scale");
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Density Scale", "Multiplier for the material's density");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "scattering", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "scattering");
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Scattering",
- "Amount of light that gets scattered out by the volume - "
- "the more out-scattering, the shallower the light will penetrate");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "transmission_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "transmission_col");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Transmission Color",
- "Result color of the volume, after other light has been scattered/absorbed");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
-
- prop = RNA_def_property(srna, "reflection_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "reflection_col");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Reflection Color",
- "Color of light scattered out of the volume (does not affect transmission)");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
-
- prop = RNA_def_property(srna, "reflection", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "reflection");
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Reflection",
- "Multiplier to make out-scattered light brighter or darker (non-physically correct)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "emission_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "emission_col");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Emission Color", "Color of emitted light");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
-
- prop = RNA_def_property(srna, "emission", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "emission");
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Emission", "Amount of light that gets emitted by the volume");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "asymmetry", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "asymmetry");
- RNA_def_property_range(prop, -1.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Asymmetry",
- "Back scattering (-1.0) to Forward scattering (1.0) and the range in between");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-}
-
-
-static void rna_def_material_halo(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "MaterialHalo", NULL);
- RNA_def_struct_sdna(srna, "Material");
- RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Halo", "Halo particle effect settings for a Material data-block");
-
- prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "hasize");
- RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_text(prop, "Size", "Dimension of the halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "hardness", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "har");
- RNA_def_property_range(prop, 0, 127);
- RNA_def_property_ui_text(prop, "Hardness", "Hardness of the halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "add", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "add");
+ /* Mix factor */
+ prop = RNA_def_property(srna, "mix_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "mix_factor");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Add", "Strength of the add effect");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "ring_count", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "ringc");
- RNA_def_property_range(prop, 0, 24);
- RNA_def_property_ui_text(prop, "Rings", "Number of rings rendered over the halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "line_count", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "linec");
- RNA_def_property_range(prop, 0, 250);
- RNA_def_property_ui_text(prop, "Line Number", "Number of star shaped lines rendered over the halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "star_tip_count", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "starc");
- RNA_def_property_range(prop, 3, 50);
- RNA_def_property_ui_text(prop, "Star Tips", "Number of points on the star shaped halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "seed1");
- RNA_def_property_range(prop, 0, 255);
- RNA_def_property_ui_text(prop, "Seed", "Randomize ring dimension and line location");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_flare_mode", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_HALO_FLARE); /* use bitflags */
- RNA_def_property_ui_text(prop, "Flare", "Render halo as a lens flare");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "flare_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "flaresize");
- RNA_def_property_range(prop, 0.1f, 25.0f);
- RNA_def_property_ui_text(prop, "Flare Size", "Factor by which the flare is larger than the halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "flare_subflare_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "subsize");
- RNA_def_property_range(prop, 0.1f, 25.0f);
- RNA_def_property_ui_text(prop, "Flare Subsize", "Dimension of the sub-flares, dots and circles");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "flare_boost", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "flareboost");
- RNA_def_property_range(prop, 0.1f, 10.0f);
- RNA_def_property_ui_text(prop, "Flare Boost", "Give the flare extra strength");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "flare_seed", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "seed2");
- RNA_def_property_range(prop, 0, 255);
- RNA_def_property_ui_text(prop, "Flare Seed", "Offset in the flare seed table");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "flare_subflare_count", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "flarec");
- RNA_def_property_range(prop, 1, 32);
- RNA_def_property_ui_text(prop, "Flares Sub", "Number of sub-flares");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_ring", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_HALO_RINGS);
- RNA_def_property_ui_text(prop, "Rings", "Render rings over halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_HALO_LINES);
- RNA_def_property_ui_text(prop, "Lines", "Render star shaped lines over halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_star", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_STAR);
- RNA_def_property_ui_text(prop, "Star", "Render halo as a star");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_HALOTEX);
- RNA_def_property_ui_text(prop, "Texture", "Give halo a texture");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_vertex_normal", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_HALOPUNO);
- RNA_def_property_ui_text(prop, "Vertex Normal", "Use the vertex normal to specify the dimension of the halo");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_extreme_alpha", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_HALO_XALPHA);
- RNA_def_property_ui_text(prop, "Extreme Alpha", "Use extreme alpha");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_shaded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_HALO_SHADE);
- RNA_def_property_ui_text(prop, "Shaded", "Let halo receive light and shadows from external objects");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_soft", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_HALO_SOFT);
- RNA_def_property_ui_text(prop, "Soft", "Soften the edges of halos at intersections with other geometry");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-}
-
-static void rna_def_material_sss(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "MaterialSubsurfaceScattering", NULL);
- RNA_def_struct_sdna(srna, "Material");
- RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Subsurface Scattering",
- "Diffuse subsurface scattering settings for a Material data-block");
-
- prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_COLOR | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "sss_radius");
- RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001, 10000, 1, 3);
- RNA_def_property_ui_text(prop, "Radius", "Mean red/green/blue scattering path length");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "sss_col");
- RNA_def_property_ui_text(prop, "Color", "Scattering color");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "error_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sss_error");
- RNA_def_property_ui_range(prop, 0.0001, 10, 1, 3);
- RNA_def_property_ui_text(prop, "Error Tolerance", "Error tolerance (low values are slower and higher quality)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sss_scale");
- RNA_def_property_ui_range(prop, 0.001, 1000, 1, 3);
- RNA_def_property_ui_text(prop, "Scale", "Object scale factor");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "ior", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sss_ior");
- RNA_def_property_ui_range(prop, 0.1, 2, 1, 3);
- RNA_def_property_ui_text(prop, "IOR", "Index of refraction (higher values are denser)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "color_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "sss_colfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Color Factor", "Blend factor for SSS colors");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "texture_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "sss_texfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Texture Factor", "Texture scattering blend factor");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "front", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sss_front");
- RNA_def_property_range(prop, 0, 2);
- RNA_def_property_ui_text(prop, "Front", "Front scattering weight");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "back", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sss_back");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(prop, "Back", "Back scattering weight");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "sss_flag", MA_DIFF_SSS);
- RNA_def_property_ui_text(prop, "Enabled", "Enable diffuse subsurface scattering effects in a material");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-}
-
-static void rna_def_material_specularity(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_specular_shader_items[] = {
- {MA_SPEC_COOKTORR, "COOKTORR", 0, "CookTorr", "Use a Cook-Torrance shader"},
- {MA_SPEC_PHONG, "PHONG", 0, "Phong", "Use a Phong shader"},
- {MA_SPEC_BLINN, "BLINN", 0, "Blinn", "Use a Blinn shader"},
- {MA_SPEC_TOON, "TOON", 0, "Toon", "Use a toon shader"},
- {MA_SPEC_WARDISO, "WARDISO", 0, "WardIso", "Use a Ward anisotropic shader"},
- {0, NULL, 0, NULL, NULL}
- };
-
- prop = RNA_def_property(srna, "specular_shader", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "spec_shader");
- RNA_def_property_enum_items(prop, prop_specular_shader_items);
- RNA_def_property_ui_text(prop, "Specular Shader Model", "");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_intensity", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "spec");
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_text(prop, "Specular Intensity", "How intense (bright) the specular reflection is");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
-
- /* NOTE: "har", "param", etc are used for multiple purposes depending on
- * settings. This should be fixed in DNA once, for RNA we just expose them
- * multiple times, which may give somewhat strange changes in the outliner,
- * but in the UI they are never visible at the same time. */
-
- prop = RNA_def_property(srna, "specular_hardness", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "har");
- RNA_def_property_range(prop, 1, 511);
- RNA_def_property_ui_text(prop, "Specular Hardness", "How hard (sharp) the specular reflection is");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
-
- prop = RNA_def_property(srna, "specular_ior", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "refrac");
- RNA_def_property_range(prop, 1, 10);
- RNA_def_property_ui_text(prop, "Specular IOR", "Specular index of refraction");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_toon_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "param[2]");
- RNA_def_property_range(prop, 0.0f, 1.53f);
- RNA_def_property_ui_text(prop, "Specular Toon Size", "Size of specular toon area");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_toon_smooth", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "param[3]");
+ RNA_def_property_ui_text(prop, "Mix", "Mix Adjustment Factor");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Scale factor for uv coordinates */
+ prop = RNA_def_property(srna, "pattern_scale", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "gradient_scale");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Scale", "Scale Factor for UV coordinates");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Shift factor to move pattern filling in 2d space */
+ prop = RNA_def_property(srna, "pattern_shift", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "gradient_shift");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Shift", "Shift filling pattern in 2d space");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Gradient angle */
+ prop = RNA_def_property(srna, "pattern_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "gradient_angle");
+ RNA_def_property_ui_text(prop, "Angle", "Pattern Orientation Angle");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Gradient radius */
+ prop = RNA_def_property(srna, "pattern_radius", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "gradient_radius");
+ RNA_def_property_range(prop, 0.0001f, 10.0f);
+ RNA_def_property_ui_text(prop, "Radius", "Pattern Radius");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Box size */
+ prop = RNA_def_property(srna, "pattern_gridsize", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pattern_gridsize");
+ RNA_def_property_range(prop, 0.0001f, 10.0f);
+ RNA_def_property_ui_text(prop, "Size", "Box Size");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Texture angle */
+ prop = RNA_def_property(srna, "texture_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "texture_angle");
+ RNA_def_property_ui_text(prop, "Angle", "Texture Orientation Angle");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Scale factor for texture */
+ prop = RNA_def_property(srna, "texture_scale", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "texture_scale");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Scale", "Scale Factor for Texture");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Shift factor to move texture in 2d space */
+ prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "texture_offset");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Offset", "Shift Texture in 2d Space");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* Texture opacity size */
+ prop = RNA_def_property(srna, "texture_opacity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "texture_opacity");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Specular Toon Smooth", "Smoothness of specular toon area");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "specular_slope", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "rms");
- RNA_def_property_range(prop, 0, 0.4);
- RNA_def_property_ui_text(prop, "Specular Slope", "The standard deviation of surface slope");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-}
-
-static void rna_def_material_strand(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "MaterialStrand", NULL);
- RNA_def_struct_sdna(srna, "Material");
- RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Strand", "Strand settings for a Material data-block");
+ RNA_def_property_ui_text(prop, "Opacity", "Texture Opacity");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* texture pixsize factor (used for UV along the stroke) */
+ prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "texture_pixsize");
+ RNA_def_property_range(prop, 1, 5000);
+ RNA_def_property_ui_text(prop, "UV Factor", "Texture Pixel Size factor along the stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_gpcolordata_uv_update");
+
+ /* Flags */
+ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_HIDE);
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
+ RNA_def_property_ui_text(prop, "Hide", "Set color Visibility");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+
+ prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_LOCKED);
+ RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
+ RNA_def_property_ui_text(prop, "Locked", "Protect color from further editing and/or frame changes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+
+ prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_ONIONSKIN);
+ RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
+ RNA_def_property_ui_text(prop, "Show in Ghosts", "Display strokes using this color when showing onion skins");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+
+ prop = RNA_def_property(srna, "texture_clamp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_TEX_CLAMP);
+ RNA_def_property_ui_text(prop, "Clamp", "Do not repeat texture and clamp to one instance only");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ prop = RNA_def_property(srna, "texture_mix", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_TEX_MIX);
+ RNA_def_property_ui_text(prop, "Mix Texture", "Mix texture image with filling colors");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ prop = RNA_def_property(srna, "flip", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_FLIP_FILL);
+ RNA_def_property_ui_text(prop, "Flip", "Flip filling colors");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ prop = RNA_def_property(srna, "use_stroke_pattern", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_STROKE_PATTERN);
+ RNA_def_property_ui_text(prop, "Pattern", "Use Stroke Texture as a pattern to apply color");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ prop = RNA_def_property(srna, "use_fill_pattern", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_FILL_PATTERN);
+ RNA_def_property_ui_text(prop, "Pattern", "Use Fill Texture as a pattern to apply color");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ prop = RNA_def_property(srna, "show_stroke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_STROKE_SHOW);
+ RNA_def_property_ui_text(prop, "Show Stroke", "Show stroke lines of this material");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ prop = RNA_def_property(srna, "show_fill", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_FILL_SHOW);
+ RNA_def_property_ui_text(prop, "Show Fill", "Show stroke fills of this material");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* pass index for future compositing and editing tools */
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "index");
+ RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Color Index\" pass");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
- prop = RNA_def_property(srna, "use_tangent_shading", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_TANGENT_STR);
- RNA_def_property_ui_text(prop, "Tangent Shading", "Use direction of strands as normal for tangent-shading");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ /* mode type */
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, gpcolordata_mode_types_items);
+ RNA_def_property_ui_text(prop, "Mode Type", "Select draw mode for stroke");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* stroke style */
+ prop = RNA_def_property(srna, "stroke_style", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "stroke_style");
+ RNA_def_property_enum_items(prop, stroke_style_items);
+ RNA_def_property_ui_text(prop, "Stroke Style", "Select style used to draw strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* stroke image texture */
+ prop = RNA_def_property(srna, "stroke_image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "sima");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_GpencilColorData_stroke_image_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* fill style */
+ prop = RNA_def_property(srna, "fill_style", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "fill_style");
+ RNA_def_property_enum_items(prop, fill_style_items);
+ RNA_def_property_ui_text(prop, "Fill Style", "Select style used to fill strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* gradient type */
+ prop = RNA_def_property(srna, "gradient_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "gradient_type");
+ RNA_def_property_enum_items(prop, fill_gradient_items);
+ RNA_def_property_ui_text(prop, "Gradient Type", "Select type of gradient used to fill strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
+
+ /* fill image texture */
+ prop = RNA_def_property(srna, "fill_image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "ima");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_GpencilColorData_fill_image_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
- /* this flag is only set when rendering, not to be edited manually */
- prop = RNA_def_property(srna, "use_surface_diffuse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_STR_SURFDIFF);
+ /* Read-only state props (for simpler UI code) */
+ prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_GpencilColorData_is_stroke_visible_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Surface Diffuse", "Make diffuse shading more similar to shading the surface");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "blend_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "strand_surfnor");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(prop, "Blend Distance", "Worldspace distance over which to blend in the surface normal");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_blender_units", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_STR_B_UNITS);
- RNA_def_property_ui_text(prop, "Blender Units", "Use Blender units for widths instead of pixels");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "root_size", PROP_FLOAT, PROP_UNSIGNED);
- RNA_def_property_float_sdna(prop, NULL, "strand_sta");
- RNA_def_property_float_funcs(prop, NULL, NULL, "rna_MaterialStrand_start_size_range");
- RNA_def_property_ui_range(prop, 0, 10.0f, 10, 5);
- RNA_def_property_ui_text(prop, "Root Size", "Start size of strands in pixels or Blender units");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "tip_size", PROP_FLOAT, PROP_UNSIGNED);
- RNA_def_property_float_sdna(prop, NULL, "strand_end");
- RNA_def_property_ui_range(prop, 0, 10.0f, 10, 5);
- RNA_def_property_float_funcs(prop, NULL, NULL, "rna_MaterialStrand_end_size_range");
- RNA_def_property_ui_text(prop, "Tip Size", "End size of strands in pixels or Blender units");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ 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, "size_min", PROP_FLOAT, PROP_UNSIGNED);
- RNA_def_property_float_sdna(prop, NULL, "strand_min");
- RNA_def_property_range(prop, 0.001, 10);
- RNA_def_property_ui_text(prop, "Minimum Size", "Minimum size of strands in pixels");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "shape", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "strand_ease");
- RNA_def_property_range(prop, -0.9, 0.9);
- RNA_def_property_ui_text(prop, "Shape", "Positive values make strands rounder, negative ones make strands spiky");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "width_fade", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "strand_widthfade");
- RNA_def_property_range(prop, 0, 2);
- RNA_def_property_ui_text(prop, "Width Fade", "Transparency along the width of the strand");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "strand_uvname");
- RNA_def_property_ui_text(prop, "UV Map", "Name of UV map to override");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-}
-
-static void rna_def_material_physics(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "MaterialPhysics", NULL);
- RNA_def_struct_sdna(srna, "Material");
- RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Physics", "Physics settings for a Material data-block");
-
- prop = RNA_def_property(srna, "friction", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "friction");
- RNA_def_property_range(prop, 0, 100);
- RNA_def_property_ui_text(prop, "Friction", "Coulomb friction coefficient, when inside the physics distance area");
-
- prop = RNA_def_property(srna, "elasticity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "reflect");
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_text(prop, "Elasticity", "Elasticity of collisions");
-
- /* FH/Force Field Settings */
- prop = RNA_def_property(srna, "use_fh_normal", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "dynamode", MA_FH_NOR);
- RNA_def_property_ui_text(prop, "Align to Normal",
- "Align dynamic game objects along the surface normal, "
- "when inside the physics distance area");
-
- prop = RNA_def_property(srna, "fh_force", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "fh");
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 2);
- RNA_def_property_ui_text(prop, "Force", "Upward spring force, when inside the physics distance area");
-
- prop = RNA_def_property(srna, "fh_distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "fhdist");
- RNA_def_property_range(prop, 0, 20);
- RNA_def_property_ui_text(prop, "Distance", "Distance of the physics area");
+ prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_GpencilColorData_is_fill_visible_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible");
- prop = RNA_def_property(srna, "fh_damping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "xyfrict");
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_text(prop, "Damping", "Damping of the spring force, when inside the physics distance area");
}
void RNA_def_material(BlenderRNA *brna)
@@ -1800,20 +659,6 @@ void RNA_def_material(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem prop_type_items[] = {
- {MA_TYPE_SURFACE, "SURFACE", 0, "Surface", "Render object as a surface"},
- {MA_TYPE_WIRE, "WIRE", 0, "Wire", "Render the edges of faces as wires (not supported in raytracing)"},
- {MA_TYPE_VOLUME, "VOLUME", 0, "Volume", "Render object as a volume"},
- {MA_TYPE_HALO, "HALO", 0, "Halo", "Render object as halo particles"},
- {0, NULL, 0, NULL, NULL}
- };
- static const EnumPropertyItem transparency_items[] = {
- {0, "MASK", 0, "Mask", "Mask the background"},
- {MA_ZTRANSP, "Z_TRANSPARENCY", 0, "Z Transparency", "Use alpha buffer for transparent faces"},
- {MA_RAYTRANSP, "RAYTRACE", 0, "Raytrace", "Use raytracing for transparent refraction rendering"},
- {0, NULL, 0, NULL, NULL}
- };
-
/* Render Preview Types */
static const EnumPropertyItem preview_type_items[] = {
{MA_FLAT, "FLAT", ICON_MATPLANE, "Flat", "Flat XY plane"},
@@ -1825,11 +670,21 @@ void RNA_def_material(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem prop_shadows_only_items[] = {
- {MA_SO_OLD, "SHADOW_ONLY_OLD", 0, "Shadow and Distance", "Old shadow only method"},
- {MA_SO_SHADOW, "SHADOW_ONLY", 0, "Shadow Only", "Improved shadow only method"},
- {MA_SO_SHADED, "SHADOW_ONLY_SHADED", 0, "Shadow and Shading",
- "Improved shadow only method which also renders lightless areas as shadows"},
+ static EnumPropertyItem prop_eevee_blend_items[] = {
+ {MA_BM_SOLID, "OPAQUE", 0, "Opaque", "Render surface without transparency"},
+ {MA_BM_ADD, "ADD", 0, "Additive", "Render surface and blend the result with additive blending"},
+ {MA_BM_MULTIPLY, "MULTIPLY", 0, "Multiply", "Render surface and blend the result with multiplicative blending"},
+ {MA_BM_CLIP, "CLIP", 0, "Alpha Clip", "Use the alpha threshold to clip the visibility (binary visibility)"},
+ {MA_BM_HASHED, "HASHED", 0, "Alpha Hashed", "Use noise to dither the binary visibility (works well with multi-samples)"},
+ {MA_BM_BLEND, "BLEND", 0, "Alpha Blend", "Render polygon transparent, depending on alpha channel of the texture"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_eevee_blend_shadow_items[] = {
+ {MA_BS_NONE, "NONE", 0, "None", "Material will cast no shadow"},
+ {MA_BS_SOLID, "OPAQUE", 0, "Opaque", "Material will cast shadows without transparency"},
+ {MA_BS_CLIP, "CLIP", 0, "Clip", "Use the alpha threshold to clip the visibility (binary visibility)"},
+ {MA_BS_HASHED, "HASHED", 0, "Hashed", "Use noise to dither the binary visibility and use filtering to reduce the noise"},
{0, NULL, 0, NULL, NULL}
};
@@ -1838,284 +693,58 @@ void RNA_def_material(BlenderRNA *brna)
"Material data-block to define the appearance of geometric objects for rendering");
RNA_def_struct_ui_icon(srna, ICON_MATERIAL_DATA);
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "material_type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Type", "Material type defining how the object is rendered");
- RNA_def_property_enum_funcs(prop, NULL, "rna_Material_type_set", NULL);
+ /* Blending (only Eevee for now) */
+ prop = RNA_def_property(srna, "blend_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_eevee_blend_items);
+ RNA_def_property_ui_text(prop, "Blend Mode", "Blend Mode for Transparent Faces");
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "use_transparency", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_TRANSP);
- RNA_def_property_ui_text(prop, "Transparency", "Render material as transparent");
+ prop = RNA_def_property(srna, "transparent_shadow_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "blend_shadow");
+ RNA_def_property_enum_items(prop, prop_eevee_blend_shadow_items);
+ RNA_def_property_ui_text(prop, "Transparent Shadow", "Shadow method for transparent material");
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "transparency_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, transparency_items);
- RNA_def_property_ui_text(prop, "Transparency Method", "Method to use for rendering transparency");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- /* For Preview Render */
- prop = RNA_def_property(srna, "preview_render_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "pr_type");
- RNA_def_property_enum_items(prop, preview_type_items);
- RNA_def_property_ui_text(prop, "Preview render type", "Type of preview render");
- RNA_def_property_update(prop, 0, "rna_Material_update_previews");
-
- prop = RNA_def_property(srna, "ambient", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "amb");
+ prop = RNA_def_property(srna, "alpha_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_text(prop, "Ambient", "Amount of global ambient color the material receives");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "emit", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_range(prop, 0, 2.0f, 1, 2);
- RNA_def_property_ui_text(prop, "Emit", "Amount of light to emit");
+ RNA_def_property_ui_text(prop, "Clip Threshold", "A pixel is rendered only if its alpha value is above this threshold");
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "translucency", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_text(prop, "Translucency", "Amount of diffuse shading on the back side");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ prop = RNA_def_property(srna, "show_transparent_backside", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "blend_flag", MA_BL_HIDE_BACKSIDE);
+ RNA_def_property_ui_text(prop, "Show Backside", "Limit transparency to a single layer "
+ "(avoids transparency sorting problems)");
+ RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "use_cubic", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "shade_flag", MA_CUBIC);
- RNA_def_property_ui_text(prop, "Cubic Interpolation",
- "Use cubic interpolation for diffuse values, for smoother transitions");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ prop = RNA_def_property(srna, "use_screen_refraction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "blend_flag", MA_BL_SS_REFRACTION);
+ RNA_def_property_ui_text(prop, "Screen Space Refraction", "Use raytraced screen space refractions");
+ RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "use_object_color", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "shade_flag", MA_OBCOLOR);
- RNA_def_property_ui_text(prop, "Object Color", "Modulate the result with a per-object color");
+ prop = RNA_def_property(srna, "use_sss_translucency", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "blend_flag", MA_BL_TRANSLUCENCY);
+ RNA_def_property_ui_text(prop, "Subsurface Translucency", "Add translucency effect to subsurface");
RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "shadow_ray_bias", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "sbias");
- RNA_def_property_range(prop, 0, 0.25);
- RNA_def_property_ui_text(prop, "Shadow Ray Bias",
- "Shadow raytracing bias to prevent terminator problems on shadow boundary");
-
- prop = RNA_def_property(srna, "shadow_buffer_bias", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "lbias");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Factor to multiply shadow buffer bias with (0 is ignore)");
-
- prop = RNA_def_property(srna, "shadow_cast_alpha", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "shad_alpha");
- RNA_def_property_range(prop, 0.001, 1);
- RNA_def_property_ui_text(prop, "Shadow Casting Alpha",
- "Shadow casting alpha, in use for Irregular and Deep shadow buffer");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ prop = RNA_def_property(srna, "refraction_depth", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "refract_depth");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Refraction Depth", "Approximate the thickness of the object to compute two refraction "
+ "event (0 is disabled)");
+ RNA_def_property_update(prop, 0, "rna_Material_draw_update");
- prop = RNA_def_property(srna, "light_group", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "group");
- RNA_def_property_struct_type(prop, "Group");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Light Group", "Limit lighting to lamps in this Group");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ /* For Preview Render */
+ prop = RNA_def_property(srna, "preview_render_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "pr_type");
+ RNA_def_property_enum_items(prop, preview_type_items);
+ RNA_def_property_ui_text(prop, "Preview render type", "Type of preview render");
+ RNA_def_property_update(prop, 0, "rna_Material_update_previews");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "index");
RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Material Index\" render pass");
RNA_def_property_update(prop, NC_OBJECT, "rna_Material_update");
- /* flags */
-
- prop = RNA_def_property(srna, "use_light_group_exclusive", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_GROUP_NOLAY);
- RNA_def_property_ui_text(prop, "Light Group Exclusive",
- "Material uses the light group exclusively - these lamps are excluded "
- "from other scene lighting");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_light_group_local", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "shade_flag", MA_GROUP_LOCAL);
- RNA_def_property_ui_text(prop, "Light Group Local", "When linked in, material uses local light group with the same name");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_raytrace", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_TRACEBLE);
- RNA_def_property_ui_text(prop, "Traceable",
- "Include this material and geometry that uses it in raytracing calculations");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_shadows", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_SHADOW);
- RNA_def_property_ui_text(prop, "Shadows", "Allow this material to receive shadows");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_shadeless", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_SHLESS);
- RNA_def_property_ui_text(prop, "Shadeless", "Make this material insensitive to light or shadow");
- RNA_def_property_update(prop, 0, "rna_Material_draw_update");
-
- prop = RNA_def_property(srna, "use_vertex_color_light", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_VERTEXCOL);
- RNA_def_property_ui_text(prop, "Vertex Color Light", "Add vertex colors as additional lighting");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_vertex_color_paint", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_VERTEXCOLP);
- RNA_def_property_ui_text(prop, "Vertex Color Paint",
- "Replace object base color with vertex colors (multiply with "
- "'texture face' face assigned textures)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "invert_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_ZINV);
- RNA_def_property_ui_text(prop, "Invert Z Depth",
- "Render material's faces with an inverted Z buffer (scanline only)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "offset_z", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "zoffs");
- RNA_def_property_ui_text(prop, "Z Offset", "Give faces an artificial offset in the Z buffer for Z transparency");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_sky", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_ENV);
- RNA_def_property_ui_text(prop, "Sky",
- "Render this material with zero alpha, with sky background in place (scanline only)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_only_shadow", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_ONLYSHADOW);
- RNA_def_property_ui_text(prop, "Only Shadow",
- "Render shadows as the material's alpha value, making the material "
- "transparent except for shadowed areas");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "shadow_only_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "shadowonly_flag");
- RNA_def_property_enum_items(prop, prop_shadows_only_items);
- RNA_def_property_ui_text(prop, "Shadow Type", "How to draw shadows");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_face_texture", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_FACETEXTURE);
- RNA_def_property_ui_text(prop, "Face Textures",
- "Replace the object's base color with color from UV map image textures");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_face_texture_alpha", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_FACETEXTURE_ALPHA);
- RNA_def_property_ui_text(prop, "Face Textures Alpha",
- "Replace the object's base alpha value with alpha from UV map image textures");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_cast_shadows", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode2", MA_CASTSHADOW);
- RNA_def_property_ui_text(prop, "Cast Shadows",
- "Allow this material to cast shadows");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_cast_shadows_only", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_ONLYCAST);
- RNA_def_property_ui_text(prop, "Cast Shadows Only",
- "Make objects with this material appear invisible (not rendered), only casting shadows");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_mist", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "mode", MA_NOMIST);
- RNA_def_property_ui_text(prop, "Use Mist", "Use mist with this material (in world settings)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_transparent_shadows", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_SHADOW_TRA);
- RNA_def_property_ui_text(prop, "Receive Transparent Shadows",
- "Allow this object to receive transparent shadows cast through other objects");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_ray_shadow_bias", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_RAYBIAS);
- RNA_def_property_ui_text(prop, "Ray Shadow Bias",
- "Prevent raytraced shadow errors on surfaces with smooth shaded normals "
- "(terminator problem)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_full_oversampling", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_FULL_OSA);
- RNA_def_property_ui_text(prop, "Full Oversampling",
- "Force this material to render full shading/textures for all anti-aliasing samples");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_cast_buffer_shadows", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_SHADBUF);
- RNA_def_property_ui_text(prop, "Cast Buffer Shadows",
- "Allow this material to cast shadows from shadow buffer lamps");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_cast_approximate", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "shade_flag", MA_APPROX_OCCLUSION);
- RNA_def_property_ui_text(prop, "Cast Approximate",
- "Allow this material to cast shadows when using approximate ambient occlusion");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_tangent_shading", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_TANGENT_V);
- RNA_def_property_ui_text(prop, "Tangent Shading",
- "Use the material's tangent vector instead of the normal for shading "
- "- for anisotropic shading effects");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- prop = RNA_def_property(srna, "use_uv_project", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapflag", MA_MAPFLAG_UVPROJECT);
- RNA_def_property_ui_text(prop, "UV Project",
- "Use to ensure UV interpolation is correct for camera projections (use with UV project modifier)");
- RNA_def_property_update(prop, 0, "rna_Material_update");
-
- /* nested structs */
- prop = RNA_def_property(srna, "raytrace_mirror", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "MaterialRaytraceMirror");
- RNA_def_property_pointer_funcs(prop, "rna_Material_mirror_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Raytrace Mirror", "Raytraced reflection settings for the material");
-
- prop = RNA_def_property(srna, "raytrace_transparency", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "MaterialRaytraceTransparency");
- RNA_def_property_pointer_funcs(prop, "rna_Material_transp_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Raytrace Transparency", "Raytraced transparency settings for the material");
-
- prop = RNA_def_property(srna, "volume", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "vol");
- RNA_def_property_struct_type(prop, "MaterialVolume");
- RNA_def_property_ui_text(prop, "Volume", "Volume settings for the material");
-
- prop = RNA_def_property(srna, "halo", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "MaterialHalo");
- RNA_def_property_pointer_funcs(prop, "rna_Material_halo_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Halo", "Halo settings for the material");
-
- prop = RNA_def_property(srna, "subsurface_scattering", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "MaterialSubsurfaceScattering");
- RNA_def_property_pointer_funcs(prop, "rna_Material_sss_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Subsurface Scattering", "Subsurface scattering settings for the material");
-
- prop = RNA_def_property(srna, "strand", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "MaterialStrand");
- RNA_def_property_pointer_funcs(prop, "rna_Material_strand_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Strand", "Strand settings for the material");
-
- prop = RNA_def_property(srna, "physics", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "MaterialPhysics");
- RNA_def_property_pointer_funcs(prop, "rna_Material_physics_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Physics", "Game physics settings");
-
- /* game settings */
- prop = RNA_def_property(srna, "game_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "game");
- RNA_def_property_struct_type(prop, "MaterialGameSettings");
- RNA_def_property_ui_text(prop, "Game Settings", "Game material settings");
-
/* nodetree */
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "nodetree");
@@ -2128,43 +757,24 @@ void RNA_def_material(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Nodes", "Use shader nodes to render the material");
RNA_def_property_update(prop, 0, "rna_Material_use_nodes_update");
- prop = RNA_def_property(srna, "active_node_material", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Material");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_pointer_funcs(prop, "rna_Material_active_node_material_get",
- "rna_Material_active_node_material_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Material", "Active node material");
- RNA_def_property_update(prop, NC_MATERIAL, NULL);
-
/* common */
rna_def_animdata_common(srna);
- rna_def_mtex_common(brna, srna, "rna_Material_mtex_begin", "rna_Material_active_texture_get",
- "rna_Material_active_texture_set", "rna_Material_active_texture_editable",
- "MaterialTextureSlot", "MaterialTextureSlots", "rna_Material_update", "rna_Material_update");
-
rna_def_texpaint_slots(brna, srna);
- /* only material has this one */
- prop = RNA_def_property(srna, "use_textures", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "septex", 1);
- RNA_def_property_array(prop, 18);
- RNA_def_property_ui_text(prop, "Use Textures", "Enable/Disable each texture");
- RNA_def_property_update(prop, 0, "rna_Material_update");
+ rna_def_material_display(srna);
+
+ /* grease pencil */
+ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_style");
+ RNA_def_property_ui_text(prop, "Grease Pencil Settings", "Grease pencil color settings for material");
+
+ prop = RNA_def_property(srna, "is_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_is_grease_pencil_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Grease Pencil", "True if this material has grease pencil data");
+
+ rna_def_material_greasepencil(brna);
- rna_def_material_colors(srna);
- rna_def_material_diffuse(srna);
- rna_def_material_specularity(srna);
-
- /* nested structs */
- rna_def_material_raymirror(brna);
- rna_def_material_raytra(brna);
- rna_def_material_volume(brna);
- rna_def_material_halo(brna);
- rna_def_material_sss(brna);
- rna_def_material_mtex(brna);
- rna_def_material_strand(brna);
- rna_def_material_physics(brna);
- rna_def_material_gamesettings(brna);
RNA_api_material(srna);
}
@@ -2249,9 +859,10 @@ static void rna_def_tex_slot(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "UV Map", "Name of UV map");
RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_Material_update");
- prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "valid", 1);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Index", "Index of MTex slot in the material");
+ RNA_def_property_ui_text(prop, "Valid", "Slot has a valid image and UV map");
}
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index c97cf2923f2..40690731b76 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -68,11 +68,13 @@ const EnumPropertyItem rna_enum_mesh_delimit_mode_items[] = {
#include "BLI_math.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+
#include "ED_mesh.h" /* XXX Bad level call */
#include "WM_api.h"
@@ -138,12 +140,6 @@ static CustomData *rna_mesh_ldata(PointerRNA *ptr)
return rna_mesh_ldata_helper(me);
}
-static CustomData *rna_mesh_fdata(PointerRNA *ptr)
-{
- Mesh *me = rna_mesh(ptr);
- return rna_mesh_fdata_helper(me);
-}
-
/* -------------------------------------------------------------------- */
/* Generic CustomData Layer Functions */
@@ -186,22 +182,14 @@ static void rna_MeshEdgeLayer_name_set(PointerRNA *ptr, const char *value)
rna_cd_layer_name_set(rna_mesh_edata(ptr), (CustomDataLayer *)ptr->data, value);
}
#endif
-#if 0
static void rna_MeshPolyLayer_name_set(PointerRNA *ptr, const char *value)
{
rna_cd_layer_name_set(rna_mesh_pdata(ptr), (CustomDataLayer *)ptr->data, value);
}
-#endif
static void rna_MeshLoopLayer_name_set(PointerRNA *ptr, const char *value)
{
rna_cd_layer_name_set(rna_mesh_ldata(ptr), (CustomDataLayer *)ptr->data, value);
}
-#if 0
-static void rna_MeshTessfaceLayer_name_set(PointerRNA *ptr, const char *value)
-{
- rna_cd_layer_name_set(rna_mesh_fdata(ptr), (CustomDataLayer *)ptr->data, value);
-}
-#endif
/* only for layers shared between types */
static void rna_MeshAnyLayer_name_set(PointerRNA *ptr, const char *value)
{
@@ -224,20 +212,25 @@ static void rna_Mesh_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
/* cheating way for importers to avoid slow updates */
if (id->us > 0) {
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
}
-static void rna_Mesh_update_data_edit_color(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Mesh_update_data_edit_weight(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- Mesh *me = rna_mesh(ptr);
+ BKE_mesh_batch_cache_dirty_tag(rna_mesh(ptr), BKE_MESH_BATCH_DIRTY_ALL);
+
rna_Mesh_update_data(bmain, scene, ptr);
- if (me->edit_btmesh) {
- BKE_editmesh_color_free(me->edit_btmesh);
- }
}
+
+static void rna_Mesh_update_data_edit_active_color(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ BKE_mesh_batch_cache_dirty_tag(rna_mesh(ptr), BKE_MESH_BATCH_DIRTY_ALL);
+
+ rna_Mesh_update_data(bmain, scene, ptr);
+}
static void rna_Mesh_update_select(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
ID *id = ptr->id.data;
@@ -263,6 +256,9 @@ static void rna_Mesh_update_vertmask(Main *bmain, Scene *scene, PointerRNA *ptr)
if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && (me->editflag & ME_EDIT_PAINT_FACE_SEL)) {
me->editflag &= ~ME_EDIT_PAINT_FACE_SEL;
}
+
+ BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
+
rna_Mesh_update_draw(bmain, scene, ptr);
}
@@ -272,6 +268,9 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr)
if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && (me->editflag & ME_EDIT_PAINT_FACE_SEL)) {
me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
}
+
+ BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
+
rna_Mesh_update_draw(bmain, scene, ptr);
}
@@ -425,232 +424,57 @@ static void rna_MeshPolygon_flip(ID *id, MPoly *mp)
BKE_mesh_polygon_flip(mp, me->mloop, &me->ldata);
BKE_mesh_tessface_clear(me);
+ BKE_mesh_runtime_clear_geometry(me);
}
-static void rna_MeshTessFace_normal_get(PointerRNA *ptr, float *values)
+static void rna_MeshLoopTriangle_verts_get(PointerRNA *ptr, int *values)
{
Mesh *me = rna_mesh(ptr);
- MFace *mface = (MFace *)ptr->data;
-
- if (mface->v4)
- normal_quad_v3(values, me->mvert[mface->v1].co, me->mvert[mface->v2].co,
- me->mvert[mface->v3].co, me->mvert[mface->v4].co);
- else
- normal_tri_v3(values, me->mvert[mface->v1].co, me->mvert[mface->v2].co, me->mvert[mface->v3].co);
+ MLoopTri *lt = (MLoopTri *)ptr->data;
+ values[0] = me->mloop[lt->tri[0]].v;
+ values[1] = me->mloop[lt->tri[1]].v;
+ values[2] = me->mloop[lt->tri[2]].v;
}
-static void rna_MeshTessFace_split_normals_get(PointerRNA *ptr, float *values)
-{
- Mesh *me = rna_mesh(ptr);
- MFace *mface = (MFace *)ptr->data;
- const short (*vec)[4][3] = CustomData_get(&me->fdata, (int)(mface - me->mface), CD_TESSLOOPNORMAL);
- int i = 4;
-
- if (!vec) {
- while (i--) zero_v3(&values[i * 3]);
- }
- else {
- while (i--) normal_short_to_float_v3(&values[i * 3], (const short *)(*vec)[i]);
- }
-}
-static float rna_MeshTessFace_area_get(PointerRNA *ptr)
+static void rna_MeshLoopTriangle_normal_get(PointerRNA *ptr, float *values)
{
Mesh *me = rna_mesh(ptr);
- MFace *mface = (MFace *)ptr->data;
+ MLoopTri *lt = (MLoopTri *)ptr->data;
+ unsigned int v1 = me->mloop[lt->tri[0]].v;
+ unsigned int v2 = me->mloop[lt->tri[1]].v;
+ unsigned int v3 = me->mloop[lt->tri[2]].v;
- if (mface->v4)
- return area_quad_v3(me->mvert[mface->v1].co, me->mvert[mface->v2].co, me->mvert[mface->v3].co,
- me->mvert[mface->v4].co);
- else
- return area_tri_v3(me->mvert[mface->v1].co, me->mvert[mface->v2].co, me->mvert[mface->v3].co);
-}
-
-static void rna_MeshTextureFace_uv1_get(PointerRNA *ptr, float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
-
- values[0] = mtface->uv[0][0];
- values[1] = mtface->uv[0][1];
+ normal_tri_v3(values, me->mvert[v1].co, me->mvert[v2].co, me->mvert[v3].co);
}
-static void rna_MeshTextureFace_uv1_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
-
- mtface->uv[0][0] = values[0];
- mtface->uv[0][1] = values[1];
-}
-
-static void rna_MeshTextureFace_uv2_get(PointerRNA *ptr, float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
-
- values[0] = mtface->uv[1][0];
- values[1] = mtface->uv[1][1];
-}
-
-static void rna_MeshTextureFace_uv2_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
-
- mtface->uv[1][0] = values[0];
- mtface->uv[1][1] = values[1];
-}
-
-static void rna_MeshTextureFace_uv3_get(PointerRNA *ptr, float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
-
- values[0] = mtface->uv[2][0];
- values[1] = mtface->uv[2][1];
-}
-
-static void rna_MeshTextureFace_uv3_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
-
- mtface->uv[2][0] = values[0];
- mtface->uv[2][1] = values[1];
-}
-
-static void rna_MeshTextureFace_uv4_get(PointerRNA *ptr, float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
-
- values[0] = mtface->uv[3][0];
- values[1] = mtface->uv[3][1];
-}
-
-static void rna_MeshTextureFace_uv4_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
-
- mtface->uv[3][0] = values[0];
- mtface->uv[3][1] = values[1];
-}
-
-static int rna_CustomDataData_numverts(PointerRNA *ptr, int type)
+static void rna_MeshLoopTriangle_split_normals_get(PointerRNA *ptr, float *values)
{
Mesh *me = rna_mesh(ptr);
- CustomData *fdata = rna_mesh_fdata(ptr);
- CustomDataLayer *cdl;
- int a, b;
+ const float (*lnors)[3] = CustomData_get_layer(&me->ldata, CD_NORMAL);
- for (cdl = fdata->layers, a = 0; a < fdata->totlayer; cdl++, a++) {
- if (cdl->type == type) {
- b = ((char *)ptr->data - ((char *)cdl->data)) / CustomData_sizeof(type);
- if (b >= 0 && b < me->totface) {
- return (me->mface[b].v4 ? 4 : 3);
- }
- }
+ if (!lnors) {
+ zero_v3(values + 0);
+ zero_v3(values + 3);
+ zero_v3(values + 6);
+ }
+ else {
+ MLoopTri *lt = (MLoopTri *)ptr->data;
+ copy_v3_v3(values + 0, lnors[lt->tri[0]]);
+ copy_v3_v3(values + 3, lnors[lt->tri[1]]);
+ copy_v3_v3(values + 6, lnors[lt->tri[2]]);
}
-
- return 0;
-}
-
-static int rna_MeshTextureFace_uv_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
-{
- length[0] = rna_CustomDataData_numverts(ptr, CD_MTFACE);
- length[1] = 2;
- return length[0] * length[1];
-}
-
-static void rna_MeshTextureFace_uv_get(PointerRNA *ptr, float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
- int totvert = rna_CustomDataData_numverts(ptr, CD_MTFACE);
-
- memcpy(values, mtface->uv, totvert * 2 * sizeof(float));
-}
-
-static void rna_MeshTextureFace_uv_set(PointerRNA *ptr, const float *values)
-{
- MTFace *mtface = (MTFace *)ptr->data;
- int totvert = rna_CustomDataData_numverts(ptr, CD_MTFACE);
-
- memcpy(mtface->uv, values, totvert * 2 * sizeof(float));
-}
-
-/* notice red and blue are swapped */
-static void rna_MeshColor_color1_get(PointerRNA *ptr, float *values)
-{
- MCol *mcol = (MCol *)ptr->data;
-
- values[3] = mcol[0].a / 255.0f;
- values[2] = mcol[0].r / 255.0f;
- values[1] = mcol[0].g / 255.0f;
- values[0] = mcol[0].b / 255.0f;
-}
-
-static void rna_MeshColor_color1_set(PointerRNA *ptr, const float *values)
-{
- MCol *mcol = (MCol *)ptr->data;
-
- mcol[0].a = round_fl_to_uchar_clamp(values[3] * 255.0f);
- mcol[0].r = round_fl_to_uchar_clamp(values[2] * 255.0f);
- mcol[0].g = round_fl_to_uchar_clamp(values[1] * 255.0f);
- mcol[0].b = round_fl_to_uchar_clamp(values[0] * 255.0f);
-}
-
-static void rna_MeshColor_color2_get(PointerRNA *ptr, float *values)
-{
- MCol *mcol = (MCol *)ptr->data;
-
- values[3] = mcol[1].a / 255.0f;
- values[2] = mcol[1].r / 255.0f;
- values[1] = mcol[1].g / 255.0f;
- values[0] = mcol[1].b / 255.0f;
-}
-
-static void rna_MeshColor_color2_set(PointerRNA *ptr, const float *values)
-{
- MCol *mcol = (MCol *)ptr->data;
-
- mcol[1].a = round_fl_to_uchar_clamp(values[3] * 255.0f);
- mcol[1].r = round_fl_to_uchar_clamp(values[2] * 255.0f);
- mcol[1].g = round_fl_to_uchar_clamp(values[1] * 255.0f);
- mcol[1].b = round_fl_to_uchar_clamp(values[0] * 255.0f);
-}
-
-static void rna_MeshColor_color3_get(PointerRNA *ptr, float *values)
-{
- MCol *mcol = (MCol *)ptr->data;
-
- values[3] = mcol[2].a / 255.0f;
- values[2] = mcol[2].r / 255.0f;
- values[1] = mcol[2].g / 255.0f;
- values[0] = mcol[2].b / 255.0f;
-}
-
-static void rna_MeshColor_color3_set(PointerRNA *ptr, const float *values)
-{
- MCol *mcol = (MCol *)ptr->data;
-
- mcol[2].a = round_fl_to_uchar_clamp(values[3] * 255.0f);
- mcol[2].r = round_fl_to_uchar_clamp(values[2] * 255.0f);
- mcol[2].g = round_fl_to_uchar_clamp(values[1] * 255.0f);
- mcol[2].b = round_fl_to_uchar_clamp(values[0] * 255.0f);
-}
-
-static void rna_MeshColor_color4_get(PointerRNA *ptr, float *values)
-{
- MCol *mcol = (MCol *)ptr->data;
-
- values[3] = mcol[3].a / 255.0f;
- values[2] = mcol[3].r / 255.0f;
- values[1] = mcol[3].g / 255.0f;
- values[0] = mcol[3].b / 255.0f;
}
-static void rna_MeshColor_color4_set(PointerRNA *ptr, const float *values)
+static float rna_MeshLoopTriangle_area_get(PointerRNA *ptr)
{
- MCol *mcol = (MCol *)ptr->data;
+ Mesh *me = rna_mesh(ptr);
+ MLoopTri *lt = (MLoopTri *)ptr->data;
+ unsigned int v1 = me->mloop[lt->tri[0]].v;
+ unsigned int v2 = me->mloop[lt->tri[1]].v;
+ unsigned int v3 = me->mloop[lt->tri[2]].v;
- mcol[3].a = round_fl_to_uchar_clamp(values[3] * 255.0f);
- mcol[3].r = round_fl_to_uchar_clamp(values[2] * 255.0f);
- mcol[3].g = round_fl_to_uchar_clamp(values[1] * 255.0f);
- mcol[3].b = round_fl_to_uchar_clamp(values[0] * 255.0f);
+ return area_tri_v3(me->mvert[v1].co, me->mvert[v2].co, me->mvert[v3].co);
}
static void rna_MeshLoopColor_color_get(PointerRNA *ptr, float *values)
@@ -758,13 +582,6 @@ static void rna_CustomDataLayer_active_set(PointerRNA *ptr, CustomData *data, in
if (render) CustomData_set_layer_render(data, type, n);
else CustomData_set_layer_active(data, type, n);
- /* sync loop layer */
- if (type == CD_MTEXPOLY) {
- CustomData *ldata = rna_mesh_ldata(ptr);
- if (render) CustomData_set_layer_render(ldata, CD_MLOOPUV, n);
- else CustomData_set_layer_active(ldata, CD_MLOOPUV, n);
- }
-
BKE_mesh_update_customdata_pointers(me, true);
}
@@ -869,147 +686,38 @@ static int rna_MeshUVLoopLayer_data_length(PointerRNA *ptr)
return (me->edit_btmesh) ? 0 : me->totloop;
}
-/* face uv_textures */
-
-DEFINE_CUSTOMDATA_LAYER_COLLECTION(tessface_uv_texture, fdata, CD_MTFACE)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_uv_texture, fdata, CD_MTFACE, active, MeshTextureFaceLayer)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_uv_texture, fdata, CD_MTFACE, clone, MeshTextureFaceLayer)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_uv_texture, fdata, CD_MTFACE, stencil, MeshTextureFaceLayer)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_uv_texture, fdata, CD_MTFACE, render, MeshTextureFaceLayer)
-
-static void rna_MeshTextureFaceLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- Mesh *me = rna_mesh(ptr);
- CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
- rna_iterator_array_begin(iter, layer->data, sizeof(MTFace), (me->edit_btmesh) ? 0 : me->totface, 0, NULL);
-}
-
-static int rna_MeshTextureFaceLayer_data_length(PointerRNA *ptr)
+static bool rna_MeshUVLoopLayer_active_render_get(PointerRNA *ptr)
{
- Mesh *me = rna_mesh(ptr);
- return (me->edit_btmesh) ? 0 : me->totface;
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPUV, 1);
}
-static bool rna_MeshTextureFaceLayer_active_render_get(PointerRNA *ptr)
+static bool rna_MeshUVLoopLayer_active_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_fdata(ptr), CD_MTFACE, 1);
+ return rna_CustomDataLayer_active_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPUV, 0);
}
-static bool rna_MeshTextureFaceLayer_active_get(PointerRNA *ptr)
+static bool rna_MeshUVLoopLayer_clone_get(PointerRNA *ptr)
{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_fdata(ptr), CD_MTFACE, 0);
+ return rna_CustomDataLayer_clone_get(ptr, rna_mesh_ldata(ptr), CD_MLOOPUV);
}
-static bool rna_MeshTextureFaceLayer_clone_get(PointerRNA *ptr)
+static void rna_MeshUVLoopLayer_active_render_set(PointerRNA *ptr, bool value)
{
- return rna_CustomDataLayer_clone_get(ptr, rna_mesh_fdata(ptr), CD_MTFACE);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPUV, 1);
}
-static void rna_MeshTextureFaceLayer_active_render_set(PointerRNA *ptr, bool value)
+static void rna_MeshUVLoopLayer_active_set(PointerRNA *ptr, bool value)
{
- rna_CustomDataLayer_active_set(ptr, rna_mesh_fdata(ptr), value, CD_MTFACE, 1);
+ rna_CustomDataLayer_active_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPUV, 0);
}
-static void rna_MeshTextureFaceLayer_active_set(PointerRNA *ptr, int value)
+static void rna_MeshUVLoopLayer_clone_set(PointerRNA *ptr, bool value)
{
- rna_CustomDataLayer_active_set(ptr, rna_mesh_fdata(ptr), value, CD_MTFACE, 0);
-}
-
-static void rna_MeshTextureFaceLayer_clone_set(PointerRNA *ptr, int value)
-{
- rna_CustomDataLayer_clone_set(ptr, rna_mesh_fdata(ptr), value, CD_MTFACE);
-}
-
-/* poly uv_textures */
-
-DEFINE_CUSTOMDATA_LAYER_COLLECTION(uv_texture, pdata, CD_MTEXPOLY)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_texture, pdata, CD_MTEXPOLY, active, MeshTexturePolyLayer)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_texture, pdata, CD_MTEXPOLY, clone, MeshTexturePolyLayer)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_texture, pdata, CD_MTEXPOLY, stencil, MeshTexturePolyLayer)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(uv_texture, pdata, CD_MTEXPOLY, render, MeshTexturePolyLayer)
-
-static void rna_MeshTexturePolyLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- Mesh *me = rna_mesh(ptr);
- CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
- rna_iterator_array_begin(iter, layer->data, sizeof(MTexPoly), (me->edit_btmesh) ? 0 : me->totpoly, 0, NULL);
-}
-
-static int rna_MeshTexturePolyLayer_data_length(PointerRNA *ptr)
-{
- Mesh *me = rna_mesh(ptr);
- return (me->edit_btmesh) ? 0 : me->totpoly;
-}
-
-static bool rna_MeshTexturePolyLayer_active_render_get(PointerRNA *ptr)
-{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY, 1);
-}
-
-static bool rna_MeshTexturePolyLayer_active_get(PointerRNA *ptr)
-{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY, 0);
-}
-
-static bool rna_MeshTexturePolyLayer_clone_get(PointerRNA *ptr)
-{
- return rna_CustomDataLayer_clone_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY);
-}
-
-static void rna_MeshTexturePolyLayer_active_render_set(PointerRNA *ptr, bool value)
-{
- rna_CustomDataLayer_active_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY, 1);
-}
-
-static void rna_MeshTexturePolyLayer_active_set(PointerRNA *ptr, int value)
-{
- rna_CustomDataLayer_active_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY, 0);
-}
-
-static void rna_MeshTexturePolyLayer_clone_set(PointerRNA *ptr, bool value)
-{
- rna_CustomDataLayer_clone_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY);
+ rna_CustomDataLayer_clone_set(ptr, rna_mesh_ldata(ptr), value, CD_MLOOPUV);
}
/* vertex_color_layers */
-DEFINE_CUSTOMDATA_LAYER_COLLECTION(tessface_vertex_color, fdata, CD_MCOL)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_vertex_color, fdata, CD_MCOL, active, MeshColorLayer)
-DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(tessface_vertex_color, fdata, CD_MCOL, render, MeshColorLayer)
-
-static void rna_MeshColorLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- Mesh *me = rna_mesh(ptr);
- CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
- rna_iterator_array_begin(iter, layer->data, sizeof(MCol) * 4, me->totface, 0, NULL);
-}
-
-static int rna_MeshColorLayer_data_length(PointerRNA *ptr)
-{
- Mesh *me = rna_mesh(ptr);
- return me->totface;
-}
-
-static bool rna_MeshColorLayer_active_render_get(PointerRNA *ptr)
-{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_fdata(ptr), CD_MCOL, 1);
-}
-
-static bool rna_MeshColorLayer_active_get(PointerRNA *ptr)
-{
- return rna_CustomDataLayer_active_get(ptr, rna_mesh_fdata(ptr), CD_MCOL, 0);
-}
-
-static void rna_MeshColorLayer_active_render_set(PointerRNA *ptr, bool value)
-{
- rna_CustomDataLayer_active_set(ptr, rna_mesh_fdata(ptr), value, CD_MCOL, 1);
-}
-
-static void rna_MeshColorLayer_active_set(PointerRNA *ptr, int value)
-{
- rna_CustomDataLayer_active_set(ptr, rna_mesh_fdata(ptr), value, CD_MCOL, 0);
-}
-
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_color, ldata, CD_MLOOPCOL)
DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(vertex_color, ldata, CD_MLOOPCOL, active, MeshLoopColorLayer)
DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(vertex_color, ldata, CD_MLOOPCOL, render, MeshLoopColorLayer)
@@ -1194,66 +902,75 @@ static int rna_MeshPaintMaskLayer_data_length(PointerRNA *ptr)
/* End paint mask */
-static void rna_TexturePoly_image_set(PointerRNA *ptr, PointerRNA value)
-{
- MTexPoly *tf = (MTexPoly *)ptr->data;
- ID *id = value.data;
+/* Face maps */
- if (id) {
- /* special exception here, individual faces don't count
- * as reference, but we do ensure the refcount is not zero */
- if (id->us == 0)
- id_us_plus(id);
- else
- id_lib_extern(id);
- }
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(face_map, pdata, CD_FACEMAP)
+DEFINE_CUSTOMDATA_LAYER_COLLECTION_ACTIVEITEM(face_map, pdata, CD_FACEMAP, active, MeshFaceMapLayer)
- tf->tpage = (struct Image *)id;
+static char *rna_MeshFaceMapLayer_path(PointerRNA *ptr)
+{
+ CustomDataLayer *cdl = ptr->data;
+ char name_esc[sizeof(cdl->name) * 2];
+ BLI_strescape(name_esc, cdl->name, sizeof(name_esc));
+ return BLI_sprintfN("face_maps[\"%s\"]", name_esc);
}
-/* while this is supposed to be readonly,
- * keep it to support importers that only make tessfaces */
-static void rna_TextureFace_image_set(PointerRNA *ptr, PointerRNA value)
+static void rna_MeshFaceMapLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- MTFace *tf = (MTFace *)ptr->data;
- ID *id = value.data;
-
- if (id) {
- /* special exception here, individual faces don't count
- * as reference, but we do ensure the refcount is not zero */
- if (id->us == 0)
- id_us_plus(id);
- else
- id_lib_extern(id);
- }
+ Mesh *me = rna_mesh(ptr);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+ rna_iterator_array_begin(iter, layer->data, sizeof(int), me->totpoly, 0, NULL);
+}
- tf->tpage = (struct Image *)id;
+static int rna_MeshFaceMapLayer_data_length(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ return me->totpoly;
}
-static int rna_MeshTessFace_verts_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+static PointerRNA rna_Mesh_face_map_new(struct Mesh *me, ReportList *reports, const char *name)
{
- MFace *face = (MFace *)ptr->data;
+ if (BKE_mesh_ensure_facemap_customdata(me) == false) {
+ BKE_report(reports, RPT_ERROR, "Currently only single face-map layers are supported");
+ return PointerRNA_NULL;
+ }
- if (face)
- length[0] = (face->v4) ? 4 : 3;
- else
- length[0] = 4; /* XXX rna_raw_access wants the length of a dummy face. this needs fixing. - Campbell */
+ CustomData *pdata = rna_mesh_pdata_helper(me);
- return length[0];
-}
+ int index = CustomData_get_layer_index(pdata, CD_FACEMAP);
+ BLI_assert(index != -1);
+ CustomDataLayer *cdl = &pdata->layers[index];
+ rna_cd_layer_name_set(pdata, cdl, name);
-static void rna_MeshTessFace_verts_get(PointerRNA *ptr, int *values)
-{
- MFace *face = (MFace *)ptr->data;
- memcpy(values, &face->v1, (face->v4 ? 4 : 3) * sizeof(int));
+ PointerRNA ptr;
+ RNA_pointer_create(&me->id, &RNA_MeshFaceMapLayer, cdl, &ptr);
+ return ptr;
}
-static void rna_MeshTessFace_verts_set(PointerRNA *ptr, const int *values)
+static void rna_Mesh_face_map_remove(struct Mesh *me, ReportList *reports, struct CustomDataLayer *layer)
{
- MFace *face = (MFace *)ptr->data;
- memcpy(&face->v1, values, (face->v4 ? 4 : 3) * sizeof(int));
+ /* just for sanity check */
+ {
+ CustomData *pdata = rna_mesh_pdata_helper(me);
+ int index = CustomData_get_layer_index(pdata, CD_FACEMAP);
+ if (index != -1) {
+ CustomDataLayer *layer_test = &pdata->layers[index];
+ if (layer != layer_test) {
+ /* don't show name, its likely freed memory */
+ BKE_report(reports, RPT_ERROR, "FaceMap not in mesh");
+ return;
+ }
+ }
+ }
+
+ if (BKE_mesh_clear_facemap_customdata(me) == false) {
+ BKE_reportf(reports, RPT_ERROR, "Error removing face-map");
+ }
}
+/* End face maps */
+
+
/* poly.vertices - this is faked loop access for convenience */
static int rna_MeshPoly_vertices_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
{
@@ -1308,11 +1025,25 @@ static int rna_MeshEdge_index_get(PointerRNA *ptr)
return (int)(edge - me->medge);
}
-static int rna_MeshTessFace_index_get(PointerRNA *ptr)
+static int rna_MeshLoopTriangle_index_get(PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
- MFace *face = (MFace *)ptr->data;
- return (int)(face - me->mface);
+ MLoopTri *ltri = (MLoopTri *)ptr->data;
+ return (int)(ltri - me->runtime.looptris.array);
+}
+
+static int rna_MeshLoopTriangle_material_index_get(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ MLoopTri *ltri = (MLoopTri *)ptr->data;
+ return me->mpoly[ltri->poly].mat_nr;
+}
+
+static bool rna_MeshLoopTriangle_use_smooth_get(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ MLoopTri *ltri = (MLoopTri *)ptr->data;
+ return me->mpoly[ltri->poly].flag & ME_SMOOTH;
}
static int rna_MeshPolygon_index_get(PointerRNA *ptr)
@@ -1351,9 +1082,9 @@ static char *rna_MeshPolygon_path(PointerRNA *ptr)
return BLI_sprintfN("polygons[%d]", (int)((MPoly *)ptr->data - rna_mesh(ptr)->mpoly));
}
-static char *rna_MeshTessFace_path(PointerRNA *ptr)
+static char *rna_MeshLoopTriangle_path(PointerRNA *ptr)
{
- return BLI_sprintfN("tessfaces[%d]", (int)((MFace *)ptr->data - rna_mesh(ptr)->mface));
+ return BLI_sprintfN("loop_triangles[%d]", (int)((MLoopTri *)ptr->data - rna_mesh(ptr)->runtime.looptris.array));
}
static char *rna_MeshEdge_path(PointerRNA *ptr)
@@ -1372,22 +1103,6 @@ static char *rna_MeshVertex_path(PointerRNA *ptr)
return BLI_sprintfN("vertices[%d]", (int)((MVert *)ptr->data - rna_mesh(ptr)->mvert));
}
-static char *rna_MeshTextureFaceLayer_path(PointerRNA *ptr)
-{
- CustomDataLayer *cdl = ptr->data;
- char name_esc[sizeof(cdl->name) * 2];
- BLI_strescape(name_esc, cdl->name, sizeof(name_esc));
- return BLI_sprintfN("tessface_uv_textures[\"%s\"]", name_esc);
-}
-
-static char *rna_MeshTexturePolyLayer_path(PointerRNA *ptr)
-{
- CustomDataLayer *cdl = ptr->data;
- char name_esc[sizeof(cdl->name) * 2];
- BLI_strescape(name_esc, cdl->name, sizeof(name_esc));
- return BLI_sprintfN("uv_textures[\"%s\"]", name_esc);
-}
-
static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type)
{
CustomDataLayer *cdl;
@@ -1451,51 +1166,11 @@ static char *rna_LoopCustomData_data_path(PointerRNA *ptr, const char *collectio
return NULL;
}
-static char *rna_FaceCustomData_data_path(PointerRNA *ptr, const char *collection, int type)
-{
- CustomDataLayer *cdl;
- Mesh *me = rna_mesh(ptr);
- CustomData *fdata = rna_mesh_fdata(ptr);
- int a, b, totloop = (me->edit_btmesh) ? 0 : me->totloop;
-
- for (cdl = fdata->layers, a = 0; a < fdata->totlayer; cdl++, a++) {
- if (cdl->type == type) {
- b = ((char *)ptr->data - ((char *)cdl->data)) / CustomData_sizeof(type);
- if (b >= 0 && b < totloop) {
- char name_esc[sizeof(cdl->name) * 2];
- BLI_strescape(name_esc, cdl->name, sizeof(name_esc));
- return BLI_sprintfN("%s[\"%s\"].data[%d]", collection, name_esc, b);
- }
- }
- }
-
- return NULL;
-}
-
-
static char *rna_MeshUVLoop_path(PointerRNA *ptr)
{
return rna_LoopCustomData_data_path(ptr, "uv_layers", CD_MLOOPUV);
}
-static char *rna_MeshTextureFace_path(PointerRNA *ptr)
-{
- return rna_FaceCustomData_data_path(ptr, "tessface_uv_textures", CD_MTFACE);
-}
-
-static char *rna_MeshTexturePoly_path(PointerRNA *ptr)
-{
- return rna_PolyCustomData_data_path(ptr, "uv_textures", CD_MTEXPOLY);
-}
-
-static char *rna_MeshColorLayer_path(PointerRNA *ptr)
-{
- CustomDataLayer *cdl = ptr->data;
- char name_esc[sizeof(cdl->name) * 2];
- BLI_strescape(name_esc, cdl->name, sizeof(name_esc));
- return BLI_sprintfN("tessface_vertex_colors[\"%s\"]", name_esc);
-}
-
static char *rna_MeshLoopColorLayer_path(PointerRNA *ptr)
{
CustomDataLayer *cdl = ptr->data;
@@ -1675,6 +1350,12 @@ void rna_MeshStringProperty_s_set(PointerRNA *ptr, const char *value)
MStringProperty *ms = (MStringProperty *)ptr->data;
BLI_strncpy(ms->s, value, sizeof(ms->s));
}
+
+static char *rna_MeshFaceMap_path(PointerRNA *ptr)
+{
+ return rna_PolyCustomData_data_path(ptr, "face_maps", CD_FACEMAP);
+}
+
/***************************************/
static int rna_Mesh_tot_vert_get(PointerRNA *ptr)
@@ -1716,34 +1397,6 @@ static void rna_Mesh_vertex_color_remove(struct Mesh *me, ReportList *reports, C
}
}
-static PointerRNA rna_Mesh_tessface_vertex_color_new(struct Mesh *me, ReportList *reports, const char *name)
-{
- PointerRNA ptr;
- CustomData *fdata;
- CustomDataLayer *cdl = NULL;
- int index;
-
- if (me->edit_btmesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add tessface colors in edit mode");
- return PointerRNA_NULL;
- }
-
- if (me->mpoly) {
- BKE_report(reports, RPT_ERROR, "Cannot add tessface colors when MPoly's exist");
- return PointerRNA_NULL;
- }
-
- index = ED_mesh_color_add(me, name, false);
-
- if (index != -1) {
- fdata = rna_mesh_fdata_helper(me);
- cdl = &fdata->layers[CustomData_get_layer_index_n(fdata, CD_MCOL, index)];
- }
-
- RNA_pointer_create(&me->id, &RNA_MeshColorLayer, cdl, &ptr);
- return ptr;
-}
-
#define DEFINE_CUSTOMDATA_PROPERTY_API(elemname, datatype, cd_prop_type, cdata, countvar, layertype) \
static PointerRNA rna_Mesh_##elemname##_##datatype##_property_new(struct Mesh *me, const char *name) \
{ \
@@ -1768,61 +1421,29 @@ DEFINE_CUSTOMDATA_PROPERTY_API(polygon, int, CD_PROP_INT, pdata, totpoly, MeshPo
DEFINE_CUSTOMDATA_PROPERTY_API(polygon, string, CD_PROP_STR, pdata, totpoly, MeshPolygonStringPropertyLayer)
#undef DEFINE_CUSTOMDATA_PROPERTY_API
-static PointerRNA rna_Mesh_uv_texture_new(struct Mesh *me, const char *name)
+static PointerRNA rna_Mesh_uv_layers_new(struct Mesh *me, const char *name)
{
PointerRNA ptr;
- CustomData *pdata;
+ CustomData *ldata;
CustomDataLayer *cdl = NULL;
int index = ED_mesh_uv_texture_add(me, name, false);
if (index != -1) {
- pdata = rna_mesh_pdata_helper(me);
- cdl = &pdata->layers[CustomData_get_layer_index_n(pdata, CD_MTEXPOLY, index)];
+ ldata = rna_mesh_ldata_helper(me);
+ cdl = &ldata->layers[CustomData_get_layer_index_n(ldata, CD_MLOOPUV, index)];
}
- RNA_pointer_create(&me->id, &RNA_MeshTexturePolyLayer, cdl, &ptr);
+ RNA_pointer_create(&me->id, &RNA_MeshUVLoopLayer, cdl, &ptr);
return ptr;
}
-static void rna_Mesh_uv_texture_layers_remove(struct Mesh *me, ReportList *reports, CustomDataLayer *layer)
+static void rna_Mesh_uv_layers_remove(struct Mesh *me, ReportList *reports, CustomDataLayer *layer)
{
if (ED_mesh_uv_texture_remove_named(me, layer->name) == false) {
BKE_reportf(reports, RPT_ERROR, "Texture layer '%s' not found", layer->name);
}
}
-/* while this is supposed to be readonly,
- * keep it to support importers that only make tessfaces */
-
-static PointerRNA rna_Mesh_tessface_uv_texture_new(struct Mesh *me, ReportList *reports, const char *name)
-{
- PointerRNA ptr;
- CustomData *fdata;
- CustomDataLayer *cdl = NULL;
- int index;
-
- if (me->edit_btmesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add tessface uv's in edit mode");
- return PointerRNA_NULL;
- }
-
- if (me->mpoly) {
- BKE_report(reports, RPT_ERROR, "Cannot add tessface uv's when MPoly's exist");
- return PointerRNA_NULL;
- }
-
- index = ED_mesh_uv_texture_add(me, name, false);
-
- if (index != -1) {
- fdata = rna_mesh_fdata_helper(me);
- cdl = &fdata->layers[CustomData_get_layer_index_n(fdata, CD_MTFACE, index)];
- }
-
- RNA_pointer_create(&me->id, &RNA_MeshTextureFaceLayer, cdl, &ptr);
- return ptr;
-}
-
-
static bool rna_Mesh_is_editmode_get(PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
@@ -1835,38 +1456,18 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
/* unused functions made by macros */
(void)rna_Mesh_skin_vertice_index_range;
(void)rna_Mesh_vertex_paint_mask_index_range;
- (void)rna_Mesh_tessface_uv_texture_active_set;
- (void)rna_Mesh_tessface_uv_texture_clone_get;
- (void)rna_Mesh_tessface_uv_texture_clone_index_get;
- (void)rna_Mesh_tessface_uv_texture_clone_index_set;
- (void)rna_Mesh_tessface_uv_texture_clone_set;
- (void)rna_Mesh_tessface_uv_texture_index_range;
- (void)rna_Mesh_tessface_uv_texture_render_get;
- (void)rna_Mesh_tessface_uv_texture_render_index_get;
- (void)rna_Mesh_tessface_uv_texture_render_index_set;
- (void)rna_Mesh_tessface_uv_texture_render_set;
- (void)rna_Mesh_tessface_uv_texture_stencil_get;
- (void)rna_Mesh_tessface_uv_texture_stencil_index_get;
- (void)rna_Mesh_tessface_uv_texture_stencil_index_set;
- (void)rna_Mesh_tessface_uv_texture_stencil_set;
- (void)rna_Mesh_tessface_vertex_color_active_set;
- (void)rna_Mesh_tessface_vertex_color_index_range;
- (void)rna_Mesh_tessface_vertex_color_render_get;
- (void)rna_Mesh_tessface_vertex_color_render_index_get;
- (void)rna_Mesh_tessface_vertex_color_render_index_set;
- (void)rna_Mesh_tessface_vertex_color_render_set;
(void)rna_Mesh_uv_layer_render_get;
(void)rna_Mesh_uv_layer_render_index_get;
(void)rna_Mesh_uv_layer_render_index_set;
(void)rna_Mesh_uv_layer_render_set;
- (void)rna_Mesh_uv_texture_render_get;
- (void)rna_Mesh_uv_texture_render_index_get;
- (void)rna_Mesh_uv_texture_render_index_set;
- (void)rna_Mesh_uv_texture_render_set;
(void)rna_Mesh_vertex_color_render_get;
(void)rna_Mesh_vertex_color_render_index_get;
(void)rna_Mesh_vertex_color_render_index_set;
(void)rna_Mesh_vertex_color_render_set;
+ (void)rna_Mesh_face_map_index_range;
+ (void)rna_Mesh_face_map_active_index_set;
+ (void)rna_Mesh_face_map_active_index_get;
+ (void)rna_Mesh_face_map_active_set;
/* end unused function block */
}
@@ -1894,7 +1495,7 @@ static void rna_def_mvert_group(BlenderRNA *brna)
prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Weight", "Vertex Weight");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_edit_weight");
}
static void rna_def_mvert(BlenderRNA *brna)
@@ -2016,83 +1617,70 @@ static void rna_def_medge(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Index", "Index of this edge");
}
-static void rna_def_mface(BlenderRNA *brna)
+static void rna_def_mlooptri(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- const int splitnor_dim[] = {4, 3};
+ const int splitnor_dim[] = {3, 3};
- srna = RNA_def_struct(brna, "MeshTessFace", NULL);
- RNA_def_struct_sdna(srna, "MFace");
- RNA_def_struct_ui_text(srna, "Mesh TessFace", "TessFace in a Mesh data-block");
- RNA_def_struct_path_func(srna, "rna_MeshTessFace_path");
+ srna = RNA_def_struct(brna, "MeshLoopTriangle", NULL);
+ RNA_def_struct_sdna(srna, "MLoopTri");
+ RNA_def_struct_ui_text(srna, "Mesh Loop Triangle", "Tessellated triangle in a Mesh data-block");
+ RNA_def_struct_path_func(srna, "rna_MeshLoopTriangle_path");
RNA_def_struct_ui_icon(srna, ICON_FACESEL);
- /* XXX allows creating invalid meshes */
prop = RNA_def_property(srna, "vertices", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_array(prop, 4);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_dynamic_array_funcs(prop, "rna_MeshTessFace_verts_get_length");
- RNA_def_property_int_funcs(prop, "rna_MeshTessFace_verts_get", "rna_MeshTessFace_verts_set", NULL);
- RNA_def_property_ui_text(prop, "Vertices", "Vertex indices");
-
- /* leaving this fixed size array for foreach_set used in import scripts */
- prop = RNA_def_property(srna, "vertices_raw", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "v1");
- RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Vertices", "Fixed size vertex indices array");
-
- prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "mat_nr");
- RNA_def_property_ui_text(prop, "Material Index", "");
-#if 0
- RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range"); /* reuse for tessface is ok */
-#endif
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FACE_SEL);
- RNA_def_property_ui_text(prop, "Select", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_int_funcs(prop, "rna_MeshLoopTriangle_verts_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Vertices", "Indices of triangle vertices");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_HIDE);
- RNA_def_property_ui_text(prop, "Hide", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
+ prop = RNA_def_property(srna, "loops", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "tri");
+ RNA_def_property_ui_text(prop, "Loops", "Indices of mesh loops that make up the triangle");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "use_smooth", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH);
- RNA_def_property_ui_text(prop, "Smooth", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ prop = RNA_def_property(srna, "polygon_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "poly");
+ RNA_def_property_ui_text(prop, "Polygon", "Index of mesh polygon that the triangle is a part of");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -1.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_float_funcs(prop, "rna_MeshTessFace_normal_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Face Normal", "Local space unit length normal vector for this face");
+ RNA_def_property_float_funcs(prop, "rna_MeshLoopTriangle_normal_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Triangle Normal", "Local space unit length normal vector for this triangle");
prop = RNA_def_property(srna, "split_normals", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_multi_array(prop, 2, splitnor_dim);
RNA_def_property_range(prop, -1.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_float_funcs(prop, "rna_MeshTessFace_split_normals_get", NULL, NULL);
+ RNA_def_property_float_funcs(prop, "rna_MeshLoopTriangle_split_normals_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Split Normals",
- "Local space unit length split normals vectors of the vertices of this face "
- "(must be computed beforehand using calc_normals_split or calc_tangents, "
- "and then calc_tessface)");
+ "Local space unit length split normals vectors of the vertices of this triangle "
+ "(must be computed beforehand using calc_normals_split or calc_tangents)");
prop = RNA_def_property(srna, "area", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_float_funcs(prop, "rna_MeshTessFace_area_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Face Area", "Read only area of this face");
+ RNA_def_property_float_funcs(prop, "rna_MeshLoopTriangle_area_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Triangle Area", "Area of this triangle");
prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_int_funcs(prop, "rna_MeshTessFace_index_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Index", "Index of this face");
-}
+ RNA_def_property_int_funcs(prop, "rna_MeshLoopTriangle_index_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Index", "Index of this loop triangle");
+ prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_int_funcs(prop, "rna_MeshLoopTriangle_material_index_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Material Index", "");
+
+ prop = RNA_def_property(srna, "use_smooth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_MeshLoopTriangle_use_smooth_get", NULL);
+ RNA_def_property_ui_text(prop, "Smooth", "");
+}
static void rna_def_mloop(BlenderRNA *brna)
{
@@ -2264,282 +1852,42 @@ static void rna_def_mloopuv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name", "Name of UV map");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
- srna = RNA_def_struct(brna, "MeshUVLoop", NULL);
- RNA_def_struct_sdna(srna, "MLoopUV");
- RNA_def_struct_path_func(srna, "rna_MeshUVLoop_path");
-
- prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "pin_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_PINNED);
- RNA_def_property_ui_text(prop, "UV Pinned", "");
-
- prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_VERTSEL);
- RNA_def_property_ui_text(prop, "UV Select", "");
-
- prop = RNA_def_property(srna, "select_edge", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_EDGESEL);
- RNA_def_property_ui_text(prop, "UV Edge Select", "");
-}
-
-static void rna_def_mtface(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
- const int uv_dim[] = {4, 2};
-
- srna = RNA_def_struct(brna, "MeshTextureFaceLayer", NULL);
- RNA_def_struct_ui_text(srna, "Mesh UV Map", "UV map with assigned image textures in a Mesh data-block");
- RNA_def_struct_sdna(srna, "CustomDataLayer");
- RNA_def_struct_path_func(srna, "rna_MeshTextureFaceLayer_path");
- RNA_def_struct_ui_icon(srna, ICON_GROUP_UVS);
-
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshUVLayer_name_set");
- RNA_def_property_ui_text(prop, "Name", "Name of UV map");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_MeshTextureFaceLayer_active_get", "rna_MeshTextureFaceLayer_active_set");
- RNA_def_property_ui_text(prop, "Active", "Set the map as active for display and editing");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
- RNA_def_property_boolean_funcs(prop, "rna_MeshTextureFaceLayer_active_render_get",
- "rna_MeshTextureFaceLayer_active_render_set");
- RNA_def_property_ui_text(prop, "Active Render", "Set the map as active for rendering");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "active_clone", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "active_clone", 0);
- RNA_def_property_boolean_funcs(prop, "rna_MeshTextureFaceLayer_clone_get", "rna_MeshTextureFaceLayer_clone_set");
- RNA_def_property_ui_text(prop, "Active Clone", "Set the map as active for cloning");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "MeshTextureFace");
- RNA_def_property_ui_text(prop, "Data", "");
- RNA_def_property_collection_funcs(prop, "rna_MeshTextureFaceLayer_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_MeshTextureFaceLayer_data_length", NULL, NULL, NULL);
-
- srna = RNA_def_struct(brna, "MeshTextureFace", NULL);
- RNA_def_struct_sdna(srna, "MTFace");
- RNA_def_struct_ui_text(srna, "Mesh UV Map Face", "UV map and image texture for a face");
- RNA_def_struct_path_func(srna, "rna_MeshTextureFace_path");
- RNA_def_struct_ui_icon(srna, ICON_FACESEL_HLT);
-
- prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "tpage");
- RNA_def_property_pointer_funcs(prop, NULL, "rna_TextureFace_image_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Image", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- /* these are for editing only, access at loops now */
-#if 0
- prop = RNA_def_property(srna, "select_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TF_SEL1);
- RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "UV Selected", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
-
- prop = RNA_def_property(srna, "pin_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "unwrap", TF_PIN1);
- RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "UV Pinned", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
-#endif
-
- prop = RNA_def_property(srna, "uv1", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv1_get", "rna_MeshTextureFace_uv1_set", NULL);
- RNA_def_property_ui_text(prop, "UV 1", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "uv2", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv2_get", "rna_MeshTextureFace_uv2_set", NULL);
- RNA_def_property_ui_text(prop, "UV 2", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "uv3", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv3_get", "rna_MeshTextureFace_uv3_set", NULL);
- RNA_def_property_ui_text(prop, "UV 3", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "uv4", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv4_get", "rna_MeshTextureFace_uv4_set", NULL);
- RNA_def_property_ui_text(prop, "UV 4", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
- RNA_def_property_multi_array(prop, 2, uv_dim);
- RNA_def_property_flag(prop, PROP_DYNAMIC);
- RNA_def_property_dynamic_array_funcs(prop, "rna_MeshTextureFace_uv_get_length");
- RNA_def_property_float_funcs(prop, "rna_MeshTextureFace_uv_get", "rna_MeshTextureFace_uv_set", NULL);
- RNA_def_property_ui_text(prop, "UV", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "uv_raw", PROP_FLOAT, PROP_NONE);
- RNA_def_property_multi_array(prop, 2, uv_dim);
- RNA_def_property_float_sdna(prop, NULL, "uv");
- RNA_def_property_ui_text(prop, "UV Raw", "Fixed size UV coordinates array");
-
-}
-
-static void rna_def_mtexpoly(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-#if 0 /* BMESH_TODO: needed later when do another todo */
- int uv_dim[] = {4, 2};
-#endif
-
- srna = RNA_def_struct(brna, "MeshTexturePolyLayer", NULL);
- RNA_def_struct_ui_text(srna, "Mesh UV Map", "UV map with assigned image textures in a Mesh data-block");
- RNA_def_struct_sdna(srna, "CustomDataLayer");
- RNA_def_struct_path_func(srna, "rna_MeshTexturePolyLayer_path");
- RNA_def_struct_ui_icon(srna, ICON_GROUP_UVS);
-
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshUVLayer_name_set");
- RNA_def_property_ui_text(prop, "Name", "Name of UV map");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_MeshTexturePolyLayer_active_get", "rna_MeshTexturePolyLayer_active_set");
+ RNA_def_property_boolean_funcs(prop, "rna_MeshUVLoopLayer_active_get", "rna_MeshUVLoopLayer_active_set");
RNA_def_property_ui_text(prop, "Active", "Set the map as active for display and editing");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
- RNA_def_property_boolean_funcs(prop, "rna_MeshTexturePolyLayer_active_render_get",
- "rna_MeshTexturePolyLayer_active_render_set");
+ RNA_def_property_boolean_funcs(prop, "rna_MeshUVLoopLayer_active_render_get",
+ "rna_MeshUVLoopLayer_active_render_set");
RNA_def_property_ui_text(prop, "Active Render", "Set the map as active for rendering");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "active_clone", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "active_clone", 0);
- RNA_def_property_boolean_funcs(prop, "rna_MeshTexturePolyLayer_clone_get", "rna_MeshTexturePolyLayer_clone_set");
+ RNA_def_property_boolean_funcs(prop, "rna_MeshUVLoopLayer_clone_get", "rna_MeshUVLoopLayer_clone_set");
RNA_def_property_ui_text(prop, "Active Clone", "Set the map as active for cloning");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
- prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "MeshTexturePoly");
- RNA_def_property_ui_text(prop, "Data", "");
- RNA_def_property_collection_funcs(prop, "rna_MeshTexturePolyLayer_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_MeshTexturePolyLayer_data_length", NULL, NULL, NULL);
-
- srna = RNA_def_struct(brna, "MeshTexturePoly", NULL);
- RNA_def_struct_sdna(srna, "MTexPoly");
- RNA_def_struct_ui_text(srna, "Mesh UV Map Face", "UV map and image texture for a face");
- RNA_def_struct_path_func(srna, "rna_MeshTexturePoly_path");
- RNA_def_struct_ui_icon(srna, ICON_FACESEL_HLT);
+ srna = RNA_def_struct(brna, "MeshUVLoop", NULL);
+ RNA_def_struct_sdna(srna, "MLoopUV");
+ RNA_def_struct_path_func(srna, "rna_MeshUVLoop_path");
- prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "tpage");
- RNA_def_property_pointer_funcs(prop, NULL, "rna_TexturePoly_image_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Image", "");
+ prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_XYZ);
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-#if 0 /* moved to MeshUVLoopLayer */
- prop = RNA_def_property(srna, "select_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TF_SEL1);
- RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "UV Selected", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
-
prop = RNA_def_property(srna, "pin_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "unwrap", TF_PIN1);
- RNA_def_property_array(prop, 4);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_PINNED);
RNA_def_property_ui_text(prop, "UV Pinned", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
-
- prop = RNA_def_property(srna, "uv_raw", PROP_FLOAT, PROP_NONE);
- RNA_def_property_multi_array(prop, 2, uv_dim);
- RNA_def_property_float_sdna(prop, NULL, "uv");
- RNA_def_property_ui_text(prop, "UV", "Fixed size UV coordinates array");
-#endif
-}
-
-static void rna_def_mcol(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "MeshColorLayer", NULL);
- RNA_def_struct_ui_text(srna, "Mesh Vertex Color Layer", "Layer of vertex colors in a Mesh data-block");
- RNA_def_struct_sdna(srna, "CustomDataLayer");
- RNA_def_struct_path_func(srna, "rna_MeshColorLayer_path");
- RNA_def_struct_ui_icon(srna, ICON_GROUP_VCOL);
-
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_string_funcs(prop, NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Name", "Name of Vertex color layer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
- prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_MeshColorLayer_active_get", "rna_MeshColorLayer_active_set");
- RNA_def_property_ui_text(prop, "Active", "Sets the layer as active for display and editing");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "active_render", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "active_rnd", 0);
- RNA_def_property_boolean_funcs(prop, "rna_MeshColorLayer_active_render_get",
- "rna_MeshColorLayer_active_render_set");
- RNA_def_property_ui_text(prop, "Active Render", "Sets the layer as active for rendering");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "MeshColor");
- RNA_def_property_ui_text(prop, "Data", "");
- RNA_def_property_collection_funcs(prop, "rna_MeshColorLayer_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_MeshColorLayer_data_length", NULL, NULL, NULL);
-
- srna = RNA_def_struct(brna, "MeshColor", NULL);
- RNA_def_struct_sdna(srna, "MCol");
- RNA_def_struct_ui_text(srna, "Mesh Vertex Color", "Vertex colors for a face in a Mesh");
- RNA_def_struct_path_func(srna, "rna_MeshColor_path");
-
- prop = RNA_def_property(srna, "color1", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 4);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_funcs(prop, "rna_MeshColor_color1_get", "rna_MeshColor_color1_set", NULL);
- RNA_def_property_ui_text(prop, "Color 1", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "color2", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 4);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_funcs(prop, "rna_MeshColor_color2_get", "rna_MeshColor_color2_set", NULL);
- RNA_def_property_ui_text(prop, "Color 2", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "color3", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 4);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_funcs(prop, "rna_MeshColor_color3_get", "rna_MeshColor_color3_set", NULL);
- RNA_def_property_ui_text(prop, "Color 3", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_VERTSEL);
+ RNA_def_property_ui_text(prop, "UV Select", "");
- prop = RNA_def_property(srna, "color4", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_array(prop, 4);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_funcs(prop, "rna_MeshColor_color4_get", "rna_MeshColor_color4_set", NULL);
- RNA_def_property_ui_text(prop, "Color 4", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ prop = RNA_def_property(srna, "select_edge", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MLOOPUV_EDGESEL);
+ RNA_def_property_ui_text(prop, "UV Edge Select", "");
}
static void rna_def_mloopcol(BlenderRNA *brna)
@@ -2754,7 +2102,7 @@ static void rna_def_mesh_vertices(BlenderRNA *brna, PropertyRNA *cprop)
/* PropertyRNA *prop; */
FunctionRNA *func;
-/* PropertyRNA *parm; */
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "MeshVertices");
srna = RNA_def_struct(brna, "MeshVertices", NULL);
@@ -2763,7 +2111,8 @@ static void rna_def_mesh_vertices(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "add", "ED_mesh_vertices_add");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of vertices to add", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
#if 0 /* BMESH_TODO Remove until BMesh merge */
func = RNA_def_function(srna, "remove", "ED_mesh_vertices_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
@@ -2778,7 +2127,7 @@ static void rna_def_mesh_edges(BlenderRNA *brna, PropertyRNA *cprop)
/* PropertyRNA *prop; */
FunctionRNA *func;
-/* PropertyRNA *parm; */
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "MeshEdges");
srna = RNA_def_struct(brna, "MeshEdges", NULL);
@@ -2787,7 +2136,8 @@ static void rna_def_mesh_edges(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "add", "ED_mesh_edges_add");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of edges to add", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of edges to add", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
#if 0 /* BMESH_TODO Remove until BMesh merge */
func = RNA_def_function(srna, "remove", "ED_mesh_edges_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
@@ -2795,32 +2145,15 @@ static void rna_def_mesh_edges(BlenderRNA *brna, PropertyRNA *cprop)
#endif
}
-/* mesh.faces */
-static void rna_def_mesh_tessfaces(BlenderRNA *brna, PropertyRNA *cprop)
+/* mesh.loop_triangles */
+static void rna_def_mesh_looptris(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
- PropertyRNA *prop;
- FunctionRNA *func;
-/* PropertyRNA *parm; */
-
- RNA_def_property_srna(cprop, "MeshTessFaces");
- srna = RNA_def_struct(brna, "MeshTessFaces", NULL);
+ RNA_def_property_srna(cprop, "MeshLoopTriangle");
+ srna = RNA_def_struct(brna, "MeshLoopTriangles", NULL);
RNA_def_struct_sdna(srna, "Mesh");
- RNA_def_struct_ui_text(srna, "Mesh Faces", "Collection of mesh faces");
-
- prop = RNA_def_property(srna, "active", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "act_face");
- RNA_def_property_ui_text(prop, "Active Face", "The active face for this mesh");
-
- func = RNA_def_function(srna, "add", "ED_mesh_tessfaces_add");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of faces to add", 0, INT_MAX);
-#if 0 /* BMESH_TODO Remove until BMesh merge */
- func = RNA_def_function(srna, "remove", "ED_mesh_faces_remove");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of faces to remove", 0, INT_MAX);
-#endif
+ RNA_def_struct_ui_text(srna, "Mesh Loop Triangles", "Tessellation of mesh polygons into triangles");
}
/* mesh.loops */
@@ -2831,7 +2164,7 @@ static void rna_def_mesh_loops(BlenderRNA *brna, PropertyRNA *cprop)
/*PropertyRNA *prop;*/
FunctionRNA *func;
- /*PropertyRNA *parm;*/
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "MeshLoops");
srna = RNA_def_struct(brna, "MeshLoops", NULL);
@@ -2840,7 +2173,8 @@ static void rna_def_mesh_loops(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "add", "ED_mesh_loops_add");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of loops to add", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of loops to add", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
/* mesh.polygons */
@@ -2851,7 +2185,7 @@ static void rna_def_mesh_polygons(BlenderRNA *brna, PropertyRNA *cprop)
PropertyRNA *prop;
FunctionRNA *func;
- /* PropertyRNA *parm; */
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "MeshPolygons");
srna = RNA_def_struct(brna, "MeshPolygons", NULL);
@@ -2864,47 +2198,11 @@ static void rna_def_mesh_polygons(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "add", "ED_mesh_polys_add");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of polygons to add", 0, INT_MAX);
+ parm = RNA_def_int(func, "count", 0, 0, INT_MAX, "Count", "Number of polygons to add", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
-/* mesh.vertex_colors */
-static void rna_def_tessface_vertex_colors(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "VertexColors");
- srna = RNA_def_struct(brna, "VertexColors", NULL);
- RNA_def_struct_sdna(srna, "Mesh");
- RNA_def_struct_ui_text(srna, "Vertex Colors", "Collection of vertex colors");
-
- /* eventually deprecate this */
- func = RNA_def_function(srna, "new", "rna_Mesh_tessface_vertex_color_new");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Add a vertex color layer to Mesh");
- RNA_def_string(func, "name", "Col", 0, "", "Vertex color name");
- parm = RNA_def_pointer(func, "layer", "MeshColorLayer", "", "The newly created layer");
- RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
- RNA_def_function_return(func, parm);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "MeshColorLayer");
- RNA_def_property_pointer_funcs(prop, "rna_Mesh_tessface_vertex_color_active_get",
- "rna_Mesh_tessface_vertex_color_active_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Active Vertex Color Layer", "Active vertex color layer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_tessface_vertex_color_active_index_get",
- "rna_Mesh_tessface_vertex_color_active_index_set", "rna_Mesh_vertex_color_index_range");
- RNA_def_property_ui_text(prop, "Active Vertex Color Index", "Active vertex color index");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-}
-
static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -2938,13 +2236,13 @@ static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop)
"rna_Mesh_vertex_color_active_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
RNA_def_property_ui_text(prop, "Active Vertex Color Layer", "Active vertex color layer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_edit_active_color");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_Mesh_vertex_color_active_index_get",
"rna_Mesh_vertex_color_active_index_set", "rna_Mesh_vertex_color_index_range");
RNA_def_property_ui_text(prop, "Active Vertex Color Index", "Active vertex color index");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_edit_active_color");
}
static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
@@ -2952,14 +2250,27 @@ static void rna_def_uv_layers(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
PropertyRNA *prop;
- /* FunctionRNA *func; */
- /* PropertyRNA *parm; */
+ FunctionRNA *func;
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "UVLoopLayers");
srna = RNA_def_struct(brna, "UVLoopLayers", NULL);
RNA_def_struct_sdna(srna, "Mesh");
RNA_def_struct_ui_text(srna, "UV Loop Layers", "Collection of uv loop layers");
+ func = RNA_def_function(srna, "new", "rna_Mesh_uv_layers_new");
+ RNA_def_function_ui_description(func, "Add a UV map layer to Mesh");
+ RNA_def_string(func, "name", "UVMap", 0, "", "UV map name");
+ parm = RNA_def_pointer(func, "layer", "MeshUVLoopLayer", "", "The newly created layer");
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Mesh_uv_layers_remove");
+ RNA_def_function_ui_description(func, "Remove a vertex color layer");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "layer", "MeshUVLoopLayer", "", "The layer to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "MeshUVLoopLayer");
RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_layer_active_get",
@@ -3101,86 +2412,6 @@ static void rna_def_polygon_string_layers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
}
-/* mesh.tessface_uv_layers */
-static void rna_def_tessface_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "TessfaceUVTextures");
- srna = RNA_def_struct(brna, "TessfaceUVTextures", NULL);
- RNA_def_struct_sdna(srna, "Mesh");
- RNA_def_struct_ui_text(srna, "UV Maps", "Collection of UV maps for tessellated faces");
-
- /* eventually deprecate this */
- func = RNA_def_function(srna, "new", "rna_Mesh_tessface_uv_texture_new");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Add a UV tessface-texture layer to Mesh (only for meshes with no polygons)");
- RNA_def_string(func, "name", "UVMap", 0, "", "UV map name");
- parm = RNA_def_pointer(func, "layer", "MeshTextureFaceLayer", "", "The newly created layer");
- RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
- RNA_def_function_return(func, parm);
-
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
- RNA_def_property_pointer_funcs(prop, "rna_Mesh_tessface_uv_texture_active_get",
- "rna_Mesh_tessface_uv_texture_active_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Active UV Map", "Active UV Map");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_tessface_uv_texture_active_index_get",
- "rna_Mesh_tessface_uv_texture_active_index_set", "rna_Mesh_uv_texture_index_range");
- RNA_def_property_ui_text(prop, "Active UV Map Index", "Active UV Map index");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-}
-
-
-static void rna_def_uv_textures(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "UVTextures");
- srna = RNA_def_struct(brna, "UVTextures", NULL);
- RNA_def_struct_sdna(srna, "Mesh");
- RNA_def_struct_ui_text(srna, "UV Maps", "Collection of UV maps");
-
- func = RNA_def_function(srna, "new", "rna_Mesh_uv_texture_new");
- RNA_def_function_ui_description(func, "Add a UV map layer to Mesh");
- RNA_def_string(func, "name", "UVMap", 0, "", "UV map name");
- parm = RNA_def_pointer(func, "layer", "MeshTexturePolyLayer", "", "The newly created layer");
- RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
- RNA_def_function_return(func, parm);
-
- func = RNA_def_function(srna, "remove", "rna_Mesh_uv_texture_layers_remove");
- RNA_def_function_ui_description(func, "Remove a vertex color layer");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "layer", "MeshTexturePolyLayer", "", "The layer to remove");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
- RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_texture_active_get",
- "rna_Mesh_uv_texture_active_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
- RNA_def_property_ui_text(prop, "Active UV Map", "Active UV Map");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_active_index_get",
- "rna_Mesh_uv_texture_active_index_set", "rna_Mesh_uv_texture_index_range");
- RNA_def_property_ui_text(prop, "Active UV Map Index", "Active UV Map index");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-}
-
static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
{
StructRNA *srna;
@@ -3261,6 +2492,79 @@ static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
}
+static void rna_def_face_map(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MeshFaceMapLayer", NULL);
+ RNA_def_struct_ui_text(srna, "Mesh Face Map Layer", "Per-face map index");
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_path_func(srna, "rna_MeshFaceMapLayer_path");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshPolyLayer_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Name of face-map layer");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshFaceMap");
+ RNA_def_property_ui_text(prop, "Data", "");
+ RNA_def_property_collection_funcs(prop, "rna_MeshFaceMapLayer_data_begin", "rna_iterator_array_next",
+ "rna_iterator_array_end", "rna_iterator_array_get",
+ "rna_MeshFaceMapLayer_data_length", NULL, NULL, NULL);
+
+ /* FaceMap struct */
+ srna = RNA_def_struct(brna, "MeshFaceMap", NULL);
+ RNA_def_struct_sdna(srna, "MIntProperty");
+ RNA_def_struct_ui_text(srna, "Int Property", "");
+ RNA_def_struct_path_func(srna, "rna_MeshFaceMap_path");
+
+ prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "i");
+ RNA_def_property_ui_text(prop, "Value", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+}
+
+static void rna_def_face_maps(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ RNA_def_property_srna(cprop, "MeshFaceMapLayers");
+ srna = RNA_def_struct(brna, "MeshFaceMapLayers", NULL);
+ RNA_def_struct_ui_text(srna, "Mesh Face Map Layer", "Per-face map index");
+ RNA_def_struct_sdna(srna, "Mesh");
+ RNA_def_struct_ui_text(srna, "Mesh FaceMaps", "Collection of mesh face-maps");
+
+ /* add this since we only ever have one layer anyway, don't bother with active_index */
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshFaceMapLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Mesh_face_map_active_get",
+ NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active FaceMap Layer", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func = RNA_def_function(srna, "new", "rna_Mesh_face_map_new");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Add a float property layer to Mesh");
+ RNA_def_string(func, "name", "Face Map", 0, "", "Face map name");
+ parm = RNA_def_pointer(func, "layer", "MeshFaceMapLayer", "", "The newly created layer");
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Mesh_face_map_remove");
+ RNA_def_function_ui_description(func, "Remove a face map layer");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "layer", "MeshFaceMapLayer", "", "The layer to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+}
+
static void rna_def_mesh(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3282,12 +2586,6 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Edges", "Edges of the mesh");
rna_def_mesh_edges(brna, prop);
- prop = RNA_def_property(srna, "tessfaces", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "mface", "totface");
- RNA_def_property_struct_type(prop, "MeshTessFace");
- RNA_def_property_ui_text(prop, "TessFaces", "Tessellated faces of the mesh (derived from polygons)");
- rna_def_mesh_tessfaces(brna, prop);
-
prop = RNA_def_property(srna, "loops", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mloop", "totloop");
RNA_def_property_struct_type(prop, "MeshLoop");
@@ -3300,6 +2598,12 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Polygons", "Polygons of the mesh");
rna_def_mesh_polygons(brna, prop);
+ prop = RNA_def_property(srna, "loop_triangles", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "runtime.looptris.array", "runtime.looptris.len");
+ RNA_def_property_struct_type(prop, "MeshLoopTriangle");
+ RNA_def_property_ui_text(prop, "Loop Triangles", "Tessellation of mesh polygons into triangles");
+ rna_def_mesh_looptris(brna, prop);
+
/* TODO, should this be allowed to be its self? */
prop = RNA_def_property(srna, "texture_mesh", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "texcomesh");
@@ -3340,62 +2644,6 @@ static void rna_def_mesh(BlenderRNA *brna)
"rna_Mesh_uv_layer_stencil_index_set", "rna_Mesh_uv_layer_index_range");
RNA_def_property_ui_text(prop, "Mask UV loop layer Index", "Mask UV loop layer index");
- /* Tessellated face UV maps - used by renderers */
- prop = RNA_def_property(srna, "tessface_uv_textures", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
- RNA_def_property_collection_funcs(prop, "rna_Mesh_tessface_uv_textures_begin", NULL, NULL, NULL,
- "rna_Mesh_tessface_uv_textures_length", NULL, NULL, NULL);
- RNA_def_property_struct_type(prop, "MeshTextureFaceLayer");
- RNA_def_property_ui_text(prop, "Tessellated Face UV Maps",
- "All UV maps for tessellated faces (read-only, for use by renderers)");
- rna_def_tessface_uv_textures(brna, prop);
-
- /* UV maps */
- prop = RNA_def_property(srna, "uv_textures", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer");
- RNA_def_property_collection_funcs(prop, "rna_Mesh_uv_textures_begin", NULL, NULL, NULL,
- "rna_Mesh_uv_textures_length", NULL, NULL, NULL);
- RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
- RNA_def_property_ui_text(prop, "UV Maps", "All UV maps");
- rna_def_uv_textures(brna, prop);
-
- prop = RNA_def_property(srna, "uv_texture_clone", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
- RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_texture_clone_get",
- "rna_Mesh_uv_texture_clone_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Clone UV Map", "UV map to be used as cloning source");
-
- prop = RNA_def_property(srna, "uv_texture_clone_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_clone_index_get",
- "rna_Mesh_uv_texture_clone_index_set", "rna_Mesh_uv_texture_index_range");
- RNA_def_property_ui_text(prop, "Clone UV Map Index", "Clone UV map index");
-
- prop = RNA_def_property(srna, "uv_texture_stencil", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "MeshTexturePolyLayer");
- RNA_def_property_pointer_funcs(prop, "rna_Mesh_uv_texture_stencil_get",
- "rna_Mesh_uv_texture_stencil_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Mask UV Map", "UV map to mask the painted area");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- prop = RNA_def_property(srna, "uv_texture_stencil_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_stencil_index_get",
- "rna_Mesh_uv_texture_stencil_index_set", "rna_Mesh_uv_texture_index_range");
- RNA_def_property_ui_text(prop, "Mask UV Map Index", "Mask UV map index");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
-
- /* Tessellated face colors - used by renderers */
-
- prop = RNA_def_property(srna, "tessface_vertex_colors", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer");
- RNA_def_property_collection_funcs(prop, "rna_Mesh_tessface_vertex_colors_begin", NULL, NULL, NULL,
- "rna_Mesh_tessface_vertex_colors_length", NULL, NULL, NULL);
- RNA_def_property_struct_type(prop, "MeshColorLayer");
- RNA_def_property_ui_text(prop, "Tessellated Face Colors",
- "All tessellated face colors (read-only, for use by renderers)");
- rna_def_tessface_vertex_colors(brna, prop);
-
/* Vertex colors */
prop = RNA_def_property(srna, "vertex_colors", PROP_COLLECTION, PROP_NONE);
@@ -3455,6 +2703,15 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "String Property Layers", "");
rna_def_polygon_string_layers(brna, prop);
+ /* face-maps */
+ prop = RNA_def_property(srna, "face_maps", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "pdata.layers", "pdata.totlayer");
+ RNA_def_property_collection_funcs(prop, "rna_Mesh_face_maps_begin", NULL, NULL, NULL,
+ "rna_Mesh_face_maps_length", NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "MeshFaceMapLayer");
+ RNA_def_property_ui_text(prop, "FaceMap", "");
+ rna_def_face_maps(brna, prop);
+
/* Skin vertices */
prop = RNA_def_property(srna, "skin_vertices", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
@@ -3538,109 +2795,11 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
#endif
- /* Mesh Draw Options for Edit Mode*/
-
- prop = RNA_def_property(srna, "show_edges", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEDGES);
- RNA_def_property_ui_text(prop, "Draw Edges",
- "Display selected edges using highlights in the 3D view and UV editor");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_faces", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWFACES);
- RNA_def_property_ui_text(prop, "Draw Faces", "Display all faces as shades in the 3D view and UV editor");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_normal_face", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWNORMALS);
- RNA_def_property_ui_text(prop, "Draw Normals", "Display face normals as lines");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_normal_loop", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_LNORMALS);
- RNA_def_property_ui_text(prop, "Draw Split Normals", "Display vertex-per-face normals as lines");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_normal_vertex", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_VNORMALS);
- RNA_def_property_ui_text(prop, "Draw Vertex Normals", "Display vertex normals as lines");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_weight", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEIGHT);
- RNA_def_property_ui_text(prop, "Show Weights", "Draw weights in editmode");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data_edit_color"); /* needs to rebuild 'dm' */
-
- prop = RNA_def_property(srna, "show_edge_crease", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWCREASES);
- RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for Subdivision Surface modifier");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_edge_bevel_weight", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWBWEIGHTS);
- RNA_def_property_ui_text(prop, "Draw Bevel Weights", "Display weights created for the Bevel modifier");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_edge_seams", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWSEAMS);
- RNA_def_property_ui_text(prop, "Draw Seams", "Display UV unwrapping seams");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_edge_sharp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWSHARP);
- RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the Edge Split modifier");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_FREESTYLE_EDGE);
- RNA_def_property_ui_text(prop, "Draw Freestyle Edge Marks", "Display Freestyle edge marks, used with the Freestyle renderer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_freestyle_face_marks", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_FREESTYLE_FACE);
- RNA_def_property_ui_text(prop, "Draw Freestyle Face Marks", "Display Freestyle face marks, used with the Freestyle renderer");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_statvis", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_STATVIS);
- RNA_def_property_ui_text(prop, "Stat Vis", "Display statistical information about the mesh");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data_edit_color");
-
- prop = RNA_def_property(srna, "show_extra_edge_length", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_EDGELEN);
- RNA_def_property_ui_text(prop, "Edge Length",
- "Display selected edge lengths, using global values when set in the transform panel");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_extra_edge_angle", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_EDGEANG);
- RNA_def_property_ui_text(prop, "Edge Angle",
- "Display selected edge angle, using global values when set in the transform panel");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_extra_face_angle", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_FACEANG);
- RNA_def_property_ui_text(prop, "Face Angles",
- "Display the angles in the selected edges, "
- "using global values when set in the transform panel");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_extra_face_area", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_FACEAREA);
- RNA_def_property_ui_text(prop, "Face Area",
- "Display the area of selected faces, "
- "using global values when set in the transform panel");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
- prop = RNA_def_property(srna, "show_extra_indices", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_INDICES);
- RNA_def_property_ui_text(prop, "Indices", "Display the index numbers of selected vertices, edges, and faces");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
-
/* editflag */
prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_X);
RNA_def_property_ui_text(prop, "X Mirror", "X Axis mirror editing");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
#if 0
prop = RNA_def_property(srna, "use_mirror_y", PROP_BOOLEAN, PROP_NONE);
@@ -3661,7 +2820,7 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_paint_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_PAINT_FACE_SEL);
RNA_def_property_ui_text(prop, "Paint Mask", "Face selection masking for painting");
- RNA_def_property_ui_icon(prop, ICON_FACESEL_HLT, 0);
+ RNA_def_property_ui_icon(prop, ICON_FACESEL, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Mesh_update_facemask");
prop = RNA_def_property(srna, "use_paint_mask_vertex", PROP_BOOLEAN, PROP_NONE);
@@ -3720,15 +2879,13 @@ void RNA_def_mesh(BlenderRNA *brna)
rna_def_mvert(brna);
rna_def_mvert_group(brna);
rna_def_medge(brna);
- rna_def_mface(brna);
+ rna_def_mlooptri(brna);
rna_def_mloop(brna);
rna_def_mpolygon(brna);
rna_def_mloopuv(brna);
- rna_def_mtface(brna);
- rna_def_mtexpoly(brna);
- rna_def_mcol(brna);
rna_def_mloopcol(brna);
rna_def_mproperties(brna);
+ rna_def_face_map(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index 579898cce44..a08555794d8 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -48,7 +48,9 @@
#include "DNA_mesh_types.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "ED_mesh.h"
static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, struct Mesh *mesh2)
@@ -92,7 +94,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *
BKE_mesh_calc_normals_split(mesh);
}
- BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
+ BKE_mesh_calc_loop_tangent_single(mesh, uvmap, r_looptangents, reports);
}
static void rna_Mesh_free_tangents(Mesh *mesh)
@@ -100,9 +102,9 @@ static void rna_Mesh_free_tangents(Mesh *mesh)
CustomData_free_layers(&mesh->ldata, CD_MLOOPTANGENT, mesh->totloop);
}
-static void rna_Mesh_calc_tessface(Mesh *mesh, bool free_mpoly)
+static void rna_Mesh_calc_looptri(Mesh *mesh)
{
- ED_mesh_calc_tessface(mesh, free_mpoly != 0);
+ BKE_mesh_runtime_looptri_ensure(mesh);
}
static void rna_Mesh_calc_smooth_groups(Mesh *mesh, bool use_bitflags, int *r_poly_group_len,
@@ -172,7 +174,7 @@ static void rna_Mesh_normals_split_custom_set(Mesh *mesh, ReportList *reports, i
rna_Mesh_normals_split_custom_do(mesh, loopnors, false);
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
static void rna_Mesh_normals_split_custom_set_from_vertices(
@@ -190,14 +192,14 @@ static void rna_Mesh_normals_split_custom_set_from_vertices(
rna_Mesh_normals_split_custom_do(mesh, vertnors, true);
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
static void rna_Mesh_transform(Mesh *mesh, float *mat, bool shape_keys)
{
BKE_mesh_transform(mesh, (float (*)[4])mat, shape_keys);
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
static void rna_Mesh_flip_normals(Mesh *mesh)
@@ -205,8 +207,9 @@ static void rna_Mesh_flip_normals(Mesh *mesh)
BKE_mesh_polygons_flip(mesh->mpoly, mesh->mloop, &mesh->ldata, mesh->totpoly);
BKE_mesh_tessface_clear(mesh);
BKE_mesh_calc_normals(mesh);
+ BKE_mesh_runtime_clear_geometry(mesh);
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
static void rna_Mesh_split_faces(Mesh *mesh, bool free_loop_normals)
@@ -214,6 +217,12 @@ static void rna_Mesh_split_faces(Mesh *mesh, bool free_loop_normals)
BKE_mesh_split_faces(mesh, free_loop_normals != 0);
}
+static void rna_Mesh_update_gpu_tag(Mesh *mesh)
+{
+ BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
+}
+
+
#else
void RNA_api_mesh(StructRNA *srna)
@@ -262,12 +271,8 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "free_tangents", "rna_Mesh_free_tangents");
RNA_def_function_ui_description(func, "Free tangents");
- func = RNA_def_function(srna, "calc_tessface", "rna_Mesh_calc_tessface");
- RNA_def_function_ui_description(func, "Calculate face tessellation (supports editmode too)");
- RNA_def_boolean(func, "free_mpoly", 0, "Free MPoly", "Free data used by polygons and loops. "
- "WARNING: This destructive operation removes regular faces, "
- "only used on temporary mesh data-blocks to reduce memory footprint of render "
- "engines and export scripts");
+ func = RNA_def_function(srna, "calc_loop_triangles", "rna_Mesh_calc_looptri");
+ RNA_def_function_ui_description(func, "Calculate loop triangle tessellation (supports editmode too)");
func = RNA_def_function(srna, "calc_smooth_groups", "rna_Mesh_calc_smooth_groups");
RNA_def_function_ui_description(func, "Calculate smooth groups from sharp edges");
@@ -301,9 +306,12 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "update", "ED_mesh_update");
RNA_def_boolean(func, "calc_edges", 0, "Calculate Edges", "Force recalculation of edges");
- RNA_def_boolean(func, "calc_tessface", 0, "Calculate Tessellation", "Force recalculation of tessellation faces");
+ RNA_def_boolean(func, "calc_edges_loose", 0, "Calculate Loose Edges", "Calculate the loose state of each edge");
+ RNA_def_boolean(func, "calc_loop_triangles", 0, "Calculate Triangules", "Force recalculation of triangle tessellation");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function(srna, "update_gpu_tag", "rna_Mesh_update_gpu_tag");
+
func = RNA_def_function(srna, "unit_test_compare", "rna_Mesh_unit_test_compare");
RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to compare to");
/* return value */
diff --git a/source/blender/makesrna/intern/rna_mesh_utils.h b/source/blender/makesrna/intern/rna_mesh_utils.h
index 2bcce9d2a00..b16a7254a86 100644
--- a/source/blender/makesrna/intern/rna_mesh_utils.h
+++ b/source/blender/makesrna/intern/rna_mesh_utils.h
@@ -101,12 +101,6 @@
for (layer = data->layers + layer_index, a = 0; layer_index + a < data->totlayer; layer++, a++) { \
if (value.data == layer) { \
CustomData_set_layer_##active_type(data, layer_type, a); \
- \
- /* keep loops in sync */ \
- if (layer_type == CD_MTEXPOLY) { \
- CustomData *ldata = rna_mesh_ldata_helper(me); \
- CustomData_set_layer_##active_type(ldata, CD_MLOOPUV, a); \
- } \
BKE_mesh_update_customdata_pointers(me, true); \
return; \
} \
@@ -131,11 +125,6 @@
CustomData *data = rna_mesh_##customdata_type(ptr); \
if (data) { \
CustomData_set_layer_##active_type(data, layer_type, value); \
- /* keep loops in sync */ \
- if (layer_type == CD_MTEXPOLY) { \
- CustomData *ldata = rna_mesh_ldata_helper(me); \
- CustomData_set_layer_##active_type(ldata, CD_MLOOPUV, value); \
- } \
BKE_mesh_update_customdata_pointers(me, true); \
} \
}
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index 7025e05d56c..af674cd2763 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -47,8 +47,10 @@
#include "DNA_object_types.h"
#include "BKE_mball.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
#include "WM_types.h"
#include "WM_api.h"
@@ -101,9 +103,9 @@ static void rna_MetaBall_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
if (mb->id.us > 0) {
for (ob = bmain->object.first; ob; ob = ob->id.next)
if (ob->data == mb)
- BKE_mball_properties_copy(bmain, bmain->eval_ctx, scene, ob);
+ BKE_mball_properties_copy(scene, ob);
- DAG_id_tag_update(&mb->id, 0);
+ DEG_id_tag_update(&mb->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, mb);
}
}
@@ -121,7 +123,7 @@ static MetaElem *rna_MetaBall_elements_new(MetaBall *mb, int type)
/* cheating way for importers to avoid slow updates */
if (mb->id.us > 0) {
- DAG_id_tag_update(&mb->id, 0);
+ DEG_id_tag_update(&mb->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, &mb->id);
}
@@ -142,7 +144,7 @@ static void rna_MetaBall_elements_remove(MetaBall *mb, ReportList *reports, Poin
/* cheating way for importers to avoid slow updates */
if (mb->id.us > 0) {
- DAG_id_tag_update(&mb->id, 0);
+ DEG_id_tag_update(&mb->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, &mb->id);
}
}
@@ -153,7 +155,7 @@ static void rna_MetaBall_elements_clear(MetaBall *mb)
/* cheating way for importers to avoid slow updates */
if (mb->id.us > 0) {
- DAG_id_tag_update(&mb->id, 0);
+ DEG_id_tag_update(&mb->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, &mb->id);
}
}
diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c
index 4c3fa787b94..e747a849c12 100644
--- a/source/blender/makesrna/intern/rna_meta_api.c
+++ b/source/blender/makesrna/intern/rna_meta_api.c
@@ -47,7 +47,12 @@ static void rna_Meta_transform(struct MetaBall *mb, float *mat)
{
BKE_mball_transform(mb, (float (*)[4])mat, true);
- DAG_id_tag_update(&mb->id, 0);
+ DEG_id_tag_update(&mb->id, 0);
+}
+
+static void rna_Mball_update_gpu_tag(MetaBall *mb)
+{
+ BKE_mball_batch_cache_dirty_tag(mb, BKE_MBALL_BATCH_DIRTY_ALL);
}
#else
@@ -60,6 +65,8 @@ void RNA_api_meta(StructRNA *srna)
RNA_def_function_ui_description(func, "Transform meta elements by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ RNA_def_function(srna, "update_gpu_tag", "rna_Mball_update_gpu_tag");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index f9b848744d6..aa35f6e3278 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -45,12 +45,12 @@
#include "BKE_animsys.h"
#include "BKE_data_transfer.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_dynamicpaint.h"
#include "BKE_effect.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
+#include "BKE_ocean.h"
#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */
#include "RNA_access.h"
@@ -68,6 +68,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{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_WeightedNormal, "WEIGHTED_NORMAL", ICON_MOD_NORMALEDIT, "Weighted Normal", ""},
{eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
{eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""},
{eModifierType_WeightVGEdit, "VERTEX_WEIGHT_EDIT", ICON_MOD_VERTEX_WEIGHT, "Vertex Weight Edit", ""},
@@ -94,17 +95,17 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{0, "", 0, N_("Deform"), ""},
{eModifierType_Armature, "ARMATURE", ICON_MOD_ARMATURE, "Armature", ""},
{eModifierType_Cast, "CAST", ICON_MOD_CAST, "Cast", ""},
- {eModifierType_CorrectiveSmooth, "CORRECTIVE_SMOOTH", ICON_MOD_SMOOTH, "Corrective Smooth", ""},
{eModifierType_Curve, "CURVE", ICON_MOD_CURVE, "Curve", ""},
{eModifierType_Displace, "DISPLACE", ICON_MOD_DISPLACE, "Displace", ""},
{eModifierType_Hook, "HOOK", ICON_HOOK, "Hook", ""},
- {eModifierType_LaplacianSmooth, "LAPLACIANSMOOTH", ICON_MOD_SMOOTH, "Laplacian Smooth", ""},
{eModifierType_LaplacianDeform, "LAPLACIANDEFORM", ICON_MOD_MESHDEFORM, "Laplacian Deform", ""},
{eModifierType_Lattice, "LATTICE", ICON_MOD_LATTICE, "Lattice", ""},
{eModifierType_MeshDeform, "MESH_DEFORM", ICON_MOD_MESHDEFORM, "Mesh Deform", ""},
{eModifierType_Shrinkwrap, "SHRINKWRAP", ICON_MOD_SHRINKWRAP, "Shrinkwrap", ""},
{eModifierType_SimpleDeform, "SIMPLE_DEFORM", ICON_MOD_SIMPLEDEFORM, "Simple Deform", ""},
{eModifierType_Smooth, "SMOOTH", ICON_MOD_SMOOTH, "Smooth", ""},
+ {eModifierType_CorrectiveSmooth, "CORRECTIVE_SMOOTH", ICON_MOD_SMOOTH, "Smooth Corrective", ""},
+ {eModifierType_LaplacianSmooth, "LAPLACIANSMOOTH", ICON_MOD_SMOOTH, "Smooth Laplacian", ""},
{eModifierType_SurfaceDeform, "SURFACE_DEFORM", ICON_MOD_MESHDEFORM, "Surface Deform", ""},
{eModifierType_Warp, "WARP", ICON_MOD_WARP, "Warp", ""},
{eModifierType_Wave, "WAVE", ICON_MOD_WAVE, "Wave", ""},
@@ -115,11 +116,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{eModifierType_Explode, "EXPLODE", ICON_MOD_EXPLODE, "Explode", ""},
{eModifierType_Fluidsim, "FLUID_SIMULATION", ICON_MOD_FLUIDSIM, "Fluid Simulation", ""},
{eModifierType_Ocean, "OCEAN", ICON_MOD_OCEAN, "Ocean", ""},
- {eModifierType_ParticleInstance, "PARTICLE_INSTANCE", ICON_MOD_PARTICLES, "Particle Instance", ""},
+ {eModifierType_ParticleInstance, "PARTICLE_INSTANCE", ICON_MOD_PARTICLE_INSTANCE, "Particle Instance", ""},
{eModifierType_ParticleSystem, "PARTICLE_SYSTEM", ICON_MOD_PARTICLES, "Particle System", ""},
{eModifierType_Smoke, "SMOKE", ICON_MOD_SMOKE, "Smoke", ""},
{eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""},
- {eModifierType_Surface, "SURFACE", ICON_MOD_PHYSICS, "Surface", ""},
+ {eModifierType_Surface, "SURFACE", ICON_MODIFIER, "Surface", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -139,6 +140,24 @@ const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[] = {
{0, NULL, 0, NULL, NULL}
};
+const EnumPropertyItem rna_enum_modifier_shrinkwrap_mode_items[] = {
+ {MOD_SHRINKWRAP_ON_SURFACE, "ON_SURFACE", 0, "On Surface",
+ "The point is constrained to the surface of the target object, "
+ "with distance offset towards the original point location"},
+ {MOD_SHRINKWRAP_INSIDE, "INSIDE", 0, "Inside",
+ "The point is constrained to be inside the target object"},
+ {MOD_SHRINKWRAP_OUTSIDE, "OUTSIDE", 0, "Outside",
+ "The point is constrained to be outside the target object"},
+ {MOD_SHRINKWRAP_OUTSIDE_SURFACE, "OUTSIDE_SURFACE", 0, "Outside Surface",
+ "The point is constrained to the surface of the target object, "
+ "with distance offset always to the outside, towards or away from the original location"},
+ {MOD_SHRINKWRAP_ABOVE_SURFACE, "ABOVE_SURFACE", 0, "Above Surface",
+ "The point is constrained to the surface of the target object, "
+ "with distance offset applied exactly along the target normal"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
#ifndef RNA_RUNTIME
/* use eWarp_Falloff_*** & eHook_Falloff_***, they're in sync */
static const EnumPropertyItem modifier_warp_falloff_items[] = {
@@ -286,12 +305,14 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
#include "BKE_cachefile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_library.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
#endif
@@ -411,6 +432,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_MeshSequenceCacheModifier;
case eModifierType_SurfaceDeform:
return &RNA_SurfaceDeformModifier;
+ case eModifierType_WeightedNormal:
+ return &RNA_WeightedNormalModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -453,14 +476,14 @@ static char *rna_Modifier_path(PointerRNA *ptr)
static void rna_Modifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->id.data);
}
static void rna_Modifier_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_Modifier_update(bmain, scene, ptr);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
/* Vertex Groups */
@@ -501,6 +524,7 @@ RNA_MOD_VGROUP_NAME_SET(WeightVGMix, defgrp_name_b);
RNA_MOD_VGROUP_NAME_SET(WeightVGMix, mask_defgrp_name);
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, mask_defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(WeightedNormal, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name);
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
@@ -689,15 +713,13 @@ static int rna_MultiresModifier_filepath_length(PointerRNA *ptr)
static int rna_ShrinkwrapModifier_face_cull_get(PointerRNA *ptr)
{
ShrinkwrapModifierData *swm = (ShrinkwrapModifierData *)ptr->data;
- return swm->shrinkOpts & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE);
+ return swm->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_MASK;
}
static void rna_ShrinkwrapModifier_face_cull_set(struct PointerRNA *ptr, int value)
{
ShrinkwrapModifierData *swm = (ShrinkwrapModifierData *)ptr->data;
-
- swm->shrinkOpts =
- (swm->shrinkOpts & ~(MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) | value;
+ swm->shrinkOpts = (swm->shrinkOpts & ~MOD_SHRINKWRAP_CULL_TARGET_MASK) | value;
}
static bool rna_MeshDeformModifier_is_bound_get(PointerRNA *ptr)
@@ -714,7 +736,7 @@ static PointerRNA rna_SoftBodyModifier_settings_get(PointerRNA *ptr)
static PointerRNA rna_SoftBodyModifier_point_cache_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
- return rna_pointer_inherit_refine(ptr, &RNA_PointCache, ob->soft->pointcache);
+ return rna_pointer_inherit_refine(ptr, &RNA_PointCache, ob->soft->shared->pointcache);
}
static PointerRNA rna_CollisionModifier_settings_get(PointerRNA *ptr)
@@ -737,8 +759,7 @@ static void rna_OceanModifier_init_update(Main *bmain, Scene *scene, PointerRNA
{
OceanModifierData *omd = (OceanModifierData *)ptr->data;
- omd->refresh |= MOD_OCEAN_REFRESH_RESET | MOD_OCEAN_REFRESH_CLEAR_CACHE;
-
+ BKE_ocean_free_modifier_cache(omd);
rna_Modifier_update(bmain, scene, ptr);
}
@@ -752,8 +773,7 @@ static void rna_OceanModifier_ocean_chop_set(PointerRNA *ptr, float value)
if ((old_value == 0.0f && value > 0.0f) ||
(old_value > 0.0f && value == 0.0f))
{
- omd->refresh |= MOD_OCEAN_REFRESH_RESET;
- omd->refresh |= MOD_OCEAN_REFRESH_CLEAR_CACHE;
+ BKE_ocean_free_modifier_cache(omd);
}
}
@@ -775,11 +795,11 @@ static void rna_CurveModifier_dependency_update(Main *bmain, Scene *scene, Point
{
CurveModifierData *cmd = (CurveModifierData *)ptr->data;
rna_Modifier_update(bmain, scene, ptr);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
if (cmd->object != NULL) {
Curve *curve = cmd->object->data;
if ((curve->flag & CU_PATH) == 0) {
- DAG_id_tag_update(&curve->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&curve->id, OB_RECALC_DATA);
}
}
}
@@ -788,11 +808,11 @@ static void rna_ArrayModifier_dependency_update(Main *bmain, Scene *scene, Point
{
ArrayModifierData *amd = (ArrayModifierData *)ptr->data;
rna_Modifier_update(bmain, scene, ptr);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
if (amd->curve_ob != NULL) {
Curve *curve = amd->curve_ob->data;
if ((curve->flag & CU_PATH) == 0) {
- DAG_id_tag_update(&curve->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&curve->id, OB_RECALC_DATA);
}
}
}
@@ -815,7 +835,7 @@ static void rna_DataTransferModifier_use_data_update(Main *bmain, Scene *scene,
dtmd->data_types &= ~DT_TYPE_POLY_ALL;
}
- rna_Modifier_update(bmain, scene, ptr);
+ rna_Modifier_dependency_update(bmain, scene, ptr);
}
static void rna_DataTransferModifier_data_types_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -836,7 +856,7 @@ static void rna_DataTransferModifier_data_types_update(Main *bmain, Scene *scene
dtmd->flags |= MOD_DATATRANSFER_USE_POLY;
}
- rna_Modifier_update(bmain, scene, ptr);
+ rna_Modifier_dependency_update(bmain, scene, ptr);
}
static void rna_DataTransferModifier_verts_data_types_set(struct PointerRNA *ptr, int value)
@@ -881,6 +901,9 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
return rna_enum_dt_layers_select_src_items;
}
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+
/* No active here! */
RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC);
@@ -914,22 +937,18 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
Object *ob_src = dtmd->ob_source;
if (ob_src) {
- DerivedMesh *dm_src;
- CustomData *pdata;
+ Mesh *me_eval;
int num_data, i;
- dm_src = object_get_derived_final(ob_src, false);
- if (dm_src != NULL) {
- pdata = dm_src->getPolyDataLayout(dm_src);
- num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ me_eval = mesh_get_eval_final(depsgraph, scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPUV);
+ num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPUV);
- RNA_enum_item_add_separator(&item, &totitem);
+ RNA_enum_item_add_separator(&item, &totitem);
- for (i = 0; i < num_data; i++) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i);
- RNA_enum_item_add(&item, &totitem, &tmp_item);
- }
+ for (i = 0; i < num_data; i++) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(&me_eval->ldata, CD_MLOOPUV, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
}
@@ -937,22 +956,18 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
Object *ob_src = dtmd->ob_source;
if (ob_src) {
- DerivedMesh *dm_src;
- CustomData *ldata;
+ Mesh *me_eval;
int num_data, i;
- dm_src = object_get_derived_final(ob_src, false);
- if (dm_src != NULL) {
- ldata = dm_src->getLoopDataLayout(dm_src);
- num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
+ me_eval = mesh_get_eval_final(depsgraph, scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL);
+ num_data = CustomData_number_of_layers(&me_eval->ldata, CD_MLOOPCOL);
- RNA_enum_item_add_separator(&item, &totitem);
+ RNA_enum_item_add_separator(&item, &totitem);
- for (i = 0; i < num_data; i++) {
- tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i);
- RNA_enum_item_add(&item, &totitem, &tmp_item);
- }
+ for (i = 0; i < num_data; i++) {
+ tmp_item.value = i;
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(&me_eval->ldata, CD_MLOOPCOL, i);
+ RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
}
@@ -1006,18 +1021,18 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(
if (ob_dst && ob_dst->data) {
Mesh *me_dst;
- CustomData *pdata;
+ CustomData *ldata;
int num_data, i;
me_dst = ob_dst->data;
- pdata = &me_dst->pdata;
- num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ ldata = &me_dst->ldata;
+ num_data = CustomData_number_of_layers(ldata, CD_MLOOPUV);
RNA_enum_item_add_separator(&item, &totitem);
for (i = 0; i < num_data; i++) {
tmp_item.value = i;
- tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i);
+ tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPUV, i);
RNA_enum_item_add(&item, &totitem, &tmp_item);
}
}
@@ -1176,15 +1191,51 @@ static void rna_ParticleInstanceModifier_particle_system_set(PointerRNA *ptr, co
#else
+/* NOTE: *MUST* return subdivision_type property. */
static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[])
{
static const EnumPropertyItem prop_subdivision_type_items[] = {
- {0, "CATMULL_CLARK", 0, "Catmull-Clark", ""},
- {1, "SIMPLE", 0, "Simple", ""},
+ {SUBSURF_TYPE_CATMULL_CLARK, "CATMULL_CLARK", 0, "Catmull-Clark", ""},
+ {SUBSURF_TYPE_SIMPLE, "SIMPLE", 0, "Simple", ""},
{0, NULL, 0, NULL, NULL}
};
- PropertyRNA *prop = RNA_def_property(srna, "subdivision_type", PROP_ENUM, PROP_NONE);
+ static const EnumPropertyItem prop_uv_smooth_items[] = {
+ {SUBSURF_UV_SMOOTH_NONE, "NONE", 0,
+ "Sharp", "UVs are not smoothed, boundaries are kept sharp"},
+ {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, "PRESERVE_CORNERS", 0,
+ "Smooth, keep corners", "UVs are smoothed, corners on discontinuous boundary are kept sharp"},
+#if 0
+ {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS, "PRESERVE_CORNERS_AND_JUNCTIONS", 0,
+ "Smooth, keep corners+junctions", "UVs are smoothed, corners on discontinuous boundary and "
+ "junctions of 3 or more regions are kept sharp"},
+ {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE, "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE", 0,
+ "Smooth, keep corners+junctions+concave", "UVs are smoothed, corners on discontinuous boundary, "
+ "junctions of 3 or more regions and darts and concave corners are kept sharp"},
+ {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, "PRESERVE_BOUNDARIES", 0,
+ "Smooth, keep corners", "UVs are smoothed, boundaries are kept sharp"},
+ {SUBSURF_UV_SMOOTH_ALL, "PRESERVE_BOUNDARIES", 0,
+ "Smooth all", "UVs and boundaries are smoothed"},
+#endif
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "uv_smooth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "uv_smooth");
+ RNA_def_property_enum_items(prop, prop_uv_smooth_items);
+ RNA_def_property_ui_text(prop, "UV Smooth", "Controls how smoothing is applied to UVs");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "quality", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "quality");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_range(prop, 1, 6, 1, -1);
+ RNA_def_property_ui_text(prop, "Quality", "Accuracy of vertex positions, lower value is faster but less precise");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "subdivision_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, type);
RNA_def_property_enum_items(prop, prop_subdivision_type_items);
RNA_def_property_ui_text(prop, "Subdivision Type", "Select type of subdivision algorithm");
@@ -1223,18 +1274,6 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_ControlEdges);
RNA_def_property_ui_text(prop, "Optimal Display", "Skip drawing/rendering of interior subdivided edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "use_subsurf_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_SubsurfUv);
- RNA_def_property_ui_text(prop, "Subdivide UVs", "Use subsurf to subdivide UVs");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
-#ifdef WITH_OPENSUBDIV
- prop = RNA_def_property(srna, "use_opensubdiv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_opensubdiv", 1);
- RNA_def_property_ui_text(prop, "Use OpenSubdiv", "Use OpenSubdiv for the subdivisions (viewport only)");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-#endif
}
static void rna_def_modifier_generic_map_info(StructRNA *srna)
@@ -1312,7 +1351,7 @@ static void rna_def_modifier_warp(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
- RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Lamp Falloff Curve");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom falloff curve");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_volume_preserve", PROP_BOOLEAN, PROP_NONE);
@@ -1380,11 +1419,6 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", eMultiresModifierFlag_ControlEdges);
RNA_def_property_ui_text(prop, "Optimal Display", "Skip drawing/rendering of interior subdivided edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "use_subsurf_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flags", eMultiresModifierFlag_PlainUv);
- RNA_def_property_ui_text(prop, "Subdivide UVs", "Use subsurf to subdivide UVs");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_lattice(BlenderRNA *brna)
@@ -1505,19 +1539,22 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "MirrorModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MIRROR);
- prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_axis", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_AXIS_X);
- RNA_def_property_ui_text(prop, "X", "Enable X axis mirror");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Mirror Axis", "Enable axis mirror");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "use_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_AXIS_Y);
- RNA_def_property_ui_text(prop, "Y", "Enable Y axis mirror");
+ prop = RNA_def_property(srna, "use_bisect_axis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_BISECT_AXIS_X);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Bisect Axis", "Cuts the mesh across the mirrorplane");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "use_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_AXIS_Z);
- RNA_def_property_ui_text(prop, "Z", "Enable Z axis mirror");
+ prop = RNA_def_property(srna, "use_bisect_flip_axis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_BISECT_FLIP_AXIS_X);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Bisect Flip Axis", "Flips the direction of the slice");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_clip", PROP_BOOLEAN, PROP_NONE);
@@ -1835,6 +1872,7 @@ static void rna_def_modifier_armature(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Object", "Armature object to deform with");
RNA_def_property_pointer_funcs(prop, NULL, "rna_ArmatureModifier_object_set", NULL, "rna_Armature_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE);
@@ -1902,7 +1940,7 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
- RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Lamp Falloff Curve");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom falloff curve");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
@@ -2264,11 +2302,6 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
"rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Projectors", "");
- prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "Image", "");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
prop = RNA_def_property(srna, "aspect_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "aspectx");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
@@ -2301,11 +2334,6 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Vertical Scale", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "use_image_override", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_UVPROJECT_OVERRIDEIMAGE);
- RNA_def_property_ui_text(prop, "Override Image", "Override faces' current images with the given image");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
srna = RNA_def_struct(brna, "UVProjector", NULL);
RNA_def_struct_ui_text(srna, "UVProjector", "UV projector used by the UV project modifier");
@@ -3014,6 +3042,14 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_harden_normals_items[] = {
+ { MOD_BEVEL_HN_NONE, "HN_NONE", 0, "Off", "Do not use Harden Normals" },
+ { MOD_BEVEL_HN_FACE, "HN_FACE", 0, "Face Area", "Use faces as weight" },
+ { MOD_BEVEL_HN_ADJ, "HN_ADJ", 0, "Vertex average", "Use adjacent vertices as weight" },
+ { MOD_BEVEL_FIX_SHA, "FIX_SHA", 0, "Fix shading", "Fix normal shading continuity" },
+ { 0, NULL, 0, NULL, NULL },
+ };
+
srna = RNA_def_struct(brna, "BevelModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Bevel Modifier", "Bevel modifier to make edges and vertices more rounded");
RNA_def_struct_sdna(srna, "BevelModifierData");
@@ -3090,6 +3126,33 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "flags", MOD_BEVEL_EVEN_WIDTHS);
RNA_def_property_ui_text(prop, "Loop Slide", "Prefer sliding along edges to having even widths");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "mark_seam", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_flags", MOD_BEVEL_MARK_SEAM);
+ RNA_def_property_ui_text(prop, "Mark Seams", "Mark Seams along beveled edges");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "mark_sharp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_flags", MOD_BEVEL_MARK_SHARP);
+ RNA_def_property_ui_text(prop, "Mark Sharp", "Mark beveled edges as sharp");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "hnmode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_harden_normals_items);
+ RNA_def_property_ui_text(prop, "Normal Mode", "Weighting mode for Harden Normals");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "hn_strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_range(prop, 0, 1, 1, 2);
+ RNA_def_property_ui_text(prop, "Normal Strength", "Strength of calculated normal");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "set_wn_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_BEVEL_SET_WN_STR);
+ RNA_def_property_ui_text(prop, "Face Strength", "Set face strength of beveled faces for use in WN Modifier");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
@@ -3104,6 +3167,9 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
"Shrink the mesh to the nearest target surface along a given axis"},
{MOD_SHRINKWRAP_NEAREST_VERTEX, "NEAREST_VERTEX", 0, "Nearest Vertex",
"Shrink the mesh to the nearest target vertex"},
+ {MOD_SHRINKWRAP_TARGET_PROJECT, "TARGET_PROJECT", 0, "Target Normal Project",
+ "Shrink the mesh to the nearest target surface "
+ "along the interpolated vertex normals of the target"},
{0, NULL, 0, NULL, NULL}
};
@@ -3124,7 +3190,13 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "shrinkType");
RNA_def_property_enum_items(prop, shrink_type_items);
RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "wrap_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shrinkMode");
+ RNA_def_property_enum_items(prop, rna_enum_modifier_shrinkwrap_mode_items);
+ RNA_def_property_ui_text(prop, "Snap Mode", "Select how vertices are constrained to the target surface");
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkOpts");
@@ -3202,9 +3274,9 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Positive", "Allow vertices to move in the positive direction of axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "use_keep_above_surface", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "shrinkOpts", MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE);
- RNA_def_property_ui_text(prop, "Keep Above Surface", "");
+ prop = RNA_def_property(srna, "use_invert_cull", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrinkOpts", MOD_SHRINKWRAP_INVERT_CULL_TARGET);
+ RNA_def_property_ui_text(prop, "Invert Cull", "When projecting in the negative direction invert the face cull mode");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
@@ -4897,6 +4969,68 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
+static void rna_def_modifier_weightednormal(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_weighting_mode_items[] = {
+ {MOD_WEIGHTEDNORMAL_MODE_FACE, "FACE_AREA", 0, "Face Area", "Generate face area weighted normals"},
+ {MOD_WEIGHTEDNORMAL_MODE_ANGLE, "CORNER_ANGLE", 0, "Corner Angle", "Generate corner angle weighted normals"},
+ {MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE, "FACE_AREA_WITH_ANGLE", 0, "Face Area And Angle",
+ "Generated normals weighted by both face area and angle"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "WeightedNormalModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "WeightedNormal Modifier", "");
+ RNA_def_struct_sdna(srna, "WeightedNormalModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT);
+
+ prop = RNA_def_property(srna, "weight", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_range(prop, 1, 100, 1, -1);
+ RNA_def_property_ui_text(prop, "Weight",
+ "Corrective factor applied to faces' weights, 50 is neutral, "
+ "lower values increase weight of weak faces, "
+ "higher values increase weight of strong faces");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_weighting_mode_items);
+ RNA_def_property_ui_text(prop, "Weighting Mode", "Weighted vertex normal mode to use");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "thresh", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 10);
+ RNA_def_property_ui_range(prop, 0, 10, 1, 2);
+ RNA_def_property_ui_text(prop, "Threshold", "Threshold value for different weights to be considered equal");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "keep_sharp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_KEEP_SHARP);
+ RNA_def_property_ui_text(prop, "Keep Sharp",
+ "Keep sharp edges as computed for default split normals, "
+ "instead of setting a single weighted normal for each vertex");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modifying the selected areas");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightedNormalModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "face_influence", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_FACE_INFLUENCE);
+ RNA_def_property_ui_text(prop, "Face Influence", "Use influence of face for weighting");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+}
+
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4928,13 +5062,15 @@ void RNA_def_modifier(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Realtime);
RNA_def_property_ui_text(prop, "Realtime", "Display modifier in viewport");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_ON, 1);
prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Render);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Render", "Use modifier during render");
- RNA_def_property_ui_icon(prop, ICON_SCENE, 0);
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_ON, 1);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE);
@@ -4951,8 +5087,9 @@ void RNA_def_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Expanded);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
prop = RNA_def_property(srna, "use_apply_on_spline", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_ApplyOnSpline);
@@ -5015,6 +5152,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_normaledit(brna);
rna_def_modifier_meshseqcache(brna);
rna_def_modifier_surfacedeform(brna);
+ rna_def_modifier_weightednormal(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index 36c6bebe561..db93518a6c7 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -49,7 +49,7 @@
#ifdef RNA_RUNTIME
-#include "BKE_depsgraph.h"
+#include "DEG_depsgraph.h"
#include "ED_clip.h"
@@ -61,7 +61,7 @@ static void rna_MovieClip_reload_update(Main *bmain, Scene *UNUSED(scene), Point
MovieClip *clip = (MovieClip *)ptr->id.data;
BKE_movieclip_reload(bmain, clip);
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
}
static void rna_MovieClip_size_get(PointerRNA *ptr, int *values)
@@ -236,11 +236,11 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem clip_render_size_items[] = {
- {MCLIP_PROXY_RENDER_SIZE_25, "PROXY_25", 0, "Proxy size 25%", ""},
- {MCLIP_PROXY_RENDER_SIZE_50, "PROXY_50", 0, "Proxy size 50%", ""},
- {MCLIP_PROXY_RENDER_SIZE_75, "PROXY_75", 0, "Proxy size 75%", ""},
- {MCLIP_PROXY_RENDER_SIZE_100, "PROXY_100", 0, "Proxy size 100%", ""},
- {MCLIP_PROXY_RENDER_SIZE_FULL, "FULL", 0, "No proxy, full render", ""},
+ {MCLIP_PROXY_RENDER_SIZE_25, "PROXY_25", 0, "25%", ""},
+ {MCLIP_PROXY_RENDER_SIZE_50, "PROXY_50", 0, "50%", ""},
+ {MCLIP_PROXY_RENDER_SIZE_75, "PROXY_75", 0, "75%", ""},
+ {MCLIP_PROXY_RENDER_SIZE_100, "PROXY_100", 0, "100%", ""},
+ {MCLIP_PROXY_RENDER_SIZE_FULL, "FULL", 0, "None, full render", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -257,7 +257,7 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
prop = RNA_def_property(srna, "proxy_render_size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "render_size");
RNA_def_property_enum_items(prop, clip_render_size_items);
- RNA_def_property_ui_text(prop, "Proxy render size",
+ RNA_def_property_ui_text(prop, "Proxy Render Size",
"Draw preview using full resolution or different proxy resolutions");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClipUser_proxy_render_settings_update");
@@ -344,6 +344,7 @@ static void rna_def_movieclip(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this movie clip");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index d27a9d3740d..121a21293f0 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -50,7 +50,6 @@
/* needed for some of the validation stuff... */
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
@@ -58,6 +57,9 @@
#include "ED_anim_api.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph.h"
+
/* temp constant defined for these funcs only... */
#define NLASTRIP_MIN_LEN_THRESH 0.1f
@@ -105,11 +107,18 @@ static char *rna_NlaStrip_path(PointerRNA *ptr)
return BLI_strdup("");
}
-static void rna_NlaStrip_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_NlaStrip_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
ID *id = ptr->id.data;
- ANIM_id_update(scene, id);
+ ANIM_id_update(bmain, id);
+}
+
+static void rna_NlaStrip_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ DEG_relations_tag_update(bmain);
+
+ rna_NlaStrip_update(bmain, scene, ptr);
}
static void rna_NlaStrip_transform_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -368,7 +377,7 @@ static FCurve *rna_NlaStrip_fcurve_find(NlaStrip *strip, ReportList *reports, co
}
-static NlaStrip *rna_NlaStrip_new(NlaTrack *track, bContext *C, ReportList *reports, const char *UNUSED(name),
+static NlaStrip *rna_NlaStrip_new(ID *id, NlaTrack *track, Main *bmain, bContext *C, ReportList *reports, const char *UNUSED(name),
int start, bAction *action)
{
NlaStrip *strip = BKE_nlastrip_new(action);
@@ -384,7 +393,7 @@ static NlaStrip *rna_NlaStrip_new(NlaTrack *track, bContext *C, ReportList *repo
if (BKE_nlastrips_add_strip(&track->strips, strip) == 0) {
BKE_report(reports, RPT_ERROR,
"Unable to add strip (the track does not have any space to accommodate this new strip)");
- BKE_nlastrip_free(NULL, strip);
+ BKE_nlastrip_free(NULL, strip, true);
return NULL;
}
@@ -414,10 +423,13 @@ static NlaStrip *rna_NlaStrip_new(NlaTrack *track, bContext *C, ReportList *repo
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_ADDED, NULL);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update_ex(bmain, id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
+
return strip;
}
-static void rna_NlaStrip_remove(NlaTrack *track, bContext *C, ReportList *reports, PointerRNA *strip_ptr)
+static void rna_NlaStrip_remove(ID *id, NlaTrack *track, Main *bmain, bContext *C, ReportList *reports, PointerRNA *strip_ptr)
{
NlaStrip *strip = strip_ptr->data;
if (BLI_findindex(&track->strips, strip) == -1) {
@@ -425,10 +437,13 @@ static void rna_NlaStrip_remove(NlaTrack *track, bContext *C, ReportList *report
return;
}
- BKE_nlastrip_free(&track->strips, strip);
+ BKE_nlastrip_free(&track->strips, strip, true);
RNA_POINTER_INVALIDATE(strip_ptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_REMOVED, NULL);
+
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update_ex(bmain, id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
}
/* Set the 'solo' setting for the given NLA-track, making sure that it is the only one
@@ -603,7 +618,7 @@ static void rna_def_nlastrip(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_editable_func(prop, "rna_NlaStrip_action_editable");
RNA_def_property_ui_text(prop, "Action", "Action referenced by this strip");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_dependency_update");
/* Action extents */
prop = RNA_def_property(srna, "action_frame_start", PROP_FLOAT, PROP_TIME);
@@ -736,7 +751,7 @@ static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_ui_text(srna, "Nla Strips", "Collection of Nla Strips");
func = RNA_def_function(srna, "new", "rna_NlaStrip_new");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new Action-Clip strip to the track");
parm = RNA_def_string(func, "name", "NlaStrip", 0, "", "Name for the NLA Strips");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
@@ -750,7 +765,7 @@ static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_NlaStrip_remove");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a NLA Strip");
parm = RNA_def_pointer(func, "strip", "NlaStrip", "", "NLA Strip to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index abb88a44b4c..ca532b16bc3 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -43,7 +43,6 @@
#include "DNA_texture_types.h"
#include "BKE_animsys.h"
-#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_image.h"
#include "BKE_texture.h"
@@ -66,6 +65,9 @@
#include "NOD_composite.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
const EnumPropertyItem rna_enum_node_socket_in_out_items[] = {
{ SOCK_IN, "IN", 0, "Input", "" },
{ SOCK_OUT, "OUT", 0, "Output", "" },
@@ -110,41 +112,35 @@ static const EnumPropertyItem node_chunksize_items[] = {
};
#endif
-#define DEF_ICON_BLANK_SKIP
-#define DEF_ICON(name) {ICON_##name, (#name), 0, (#name), ""},
-#define DEF_VICO(name)
-const EnumPropertyItem rna_enum_node_icon_items[] = {
-#include "UI_icons.h"
- {0, NULL, 0, NULL, NULL}};
-#undef DEF_ICON_BLANK_SKIP
-#undef DEF_ICON
-#undef DEF_VICO
-
const EnumPropertyItem rna_enum_node_math_items[] = {
{NODE_MATH_ADD, "ADD", 0, "Add", ""},
{NODE_MATH_SUB, "SUBTRACT", 0, "Subtract", ""},
{NODE_MATH_MUL, "MULTIPLY", 0, "Multiply", ""},
{NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", ""},
- {NODE_MATH_SIN, "SINE", 0, "Sine", ""},
- {NODE_MATH_COS, "COSINE", 0, "Cosine", ""},
- {NODE_MATH_TAN, "TANGENT", 0, "Tangent", ""},
- {NODE_MATH_ASIN, "ARCSINE", 0, "Arcsine", ""},
- {NODE_MATH_ACOS, "ARCCOSINE", 0, "Arccosine", ""},
- {NODE_MATH_ATAN, "ARCTANGENT", 0, "Arctangent", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{NODE_MATH_POW, "POWER", 0, "Power", ""},
{NODE_MATH_LOG, "LOGARITHM", 0, "Logarithm", ""},
+ {NODE_MATH_SQRT, "SQRT", 0, "Square Root", ""},
+ {NODE_MATH_ABS, "ABSOLUTE", 0, "Absolute", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{NODE_MATH_MIN, "MINIMUM", 0, "Minimum", ""},
{NODE_MATH_MAX, "MAXIMUM", 0, "Maximum", ""},
- {NODE_MATH_ROUND, "ROUND", 0, "Round", ""},
{NODE_MATH_LESS, "LESS_THAN", 0, "Less Than", ""},
{NODE_MATH_GREATER, "GREATER_THAN", 0, "Greater Than", ""},
- {NODE_MATH_MOD, "MODULO", 0, "Modulo", ""},
- {NODE_MATH_ABS, "ABSOLUTE", 0, "Absolute", ""},
- {NODE_MATH_ATAN2, "ARCTAN2", 0, "Arctan2", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_MATH_ROUND, "ROUND", 0, "Round", ""},
{NODE_MATH_FLOOR, "FLOOR", 0, "Floor", ""},
{NODE_MATH_CEIL, "CEIL", 0, "Ceil", ""},
{NODE_MATH_FRACT, "FRACT", 0, "Fract", ""},
- {NODE_MATH_SQRT, "SQRT", 0, "Square Root", ""},
+ {NODE_MATH_MOD, "MODULO", 0, "Modulo", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_MATH_SIN, "SINE", 0, "Sine", ""},
+ {NODE_MATH_COS, "COSINE", 0, "Cosine", ""},
+ {NODE_MATH_TAN, "TANGENT", 0, "Tangent", ""},
+ {NODE_MATH_ASIN, "ARCSINE", 0, "Arcsine", ""},
+ {NODE_MATH_ACOS, "ARCCOSINE", 0, "Arccosine", ""},
+ {NODE_MATH_ATAN, "ARCTANGENT", 0, "Arctangent", ""},
+ {NODE_MATH_ATAN2, "ARCTAN2", 0, "Arctan2", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -176,6 +172,14 @@ static const EnumPropertyItem node_sampler_type_items[] = {
{2, "BICUBIC", 0, "Bicubic", ""},
{0, NULL, 0, NULL, NULL}
};
+
+
+static const EnumPropertyItem prop_shader_output_target_items[] = {
+ {SHD_OUTPUT_ALL, "ALL", 0, "All", "Use shaders for all renderers and viewports, unless there exists a more specific output"},
+ {SHD_OUTPUT_EEVEE, "EEVEE", 0, "Eevee", "Use shaders for Eevee renderer"},
+ {SHD_OUTPUT_CYCLES, "CYCLES", 0, "Cycles", "Use shaders for Cycles renderer"},
+ {0, NULL, 0, NULL, NULL}
+};
#endif
#ifdef RNA_RUNTIME
@@ -185,13 +189,14 @@ static const EnumPropertyItem node_sampler_type_items[] = {
#include "BKE_context.h"
#include "BKE_idprop.h"
-#include "BKE_library.h"
#include "BKE_global.h"
#include "ED_node.h"
#include "ED_render.h"
+#include "GPU_material.h"
+
#include "NOD_common.h"
#include "NOD_socket.h"
@@ -540,7 +545,7 @@ static bool rna_NodeTree_poll(const bContext *C, bNodeTreeType *ntreetype)
ParameterList list;
FunctionRNA *func;
void *ret;
- int visible;
+ bool visible;
RNA_pointer_create(NULL, ntreetype->ext.srna, NULL, &ptr); /* dummy */
func = &rna_NodeTree_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
@@ -744,7 +749,7 @@ static void rna_NodeTree_node_remove(bNodeTree *ntree, Main *bmain, ReportList *
}
id_us_min(node->id);
- nodeFreeNode(ntree, node);
+ nodeDeleteNode(bmain, ntree, node);
RNA_POINTER_INVALIDATE(node_ptr);
ntreeUpdateTree(bmain, ntree); /* update group node socket links */
@@ -764,7 +769,7 @@ static void rna_NodeTree_node_clear(bNodeTree *ntree, Main *bmain, ReportList *r
if (node->id)
id_us_min(node->id);
- nodeFreeNode(ntree, node);
+ nodeDeleteNode(bmain, ntree, node);
node = next_node;
}
@@ -2324,14 +2329,6 @@ static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *
/* fall back to searching node in the tree */
nodeFindNode(ntree, sock, &node, NULL);
}
-
- if (node) {
- nodeSynchronizeID(node, true);
-
- /* extra update for sockets that get synced to material */
- if (node->id && ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT))
- WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, node->id);
- }
}
@@ -2487,17 +2484,6 @@ static void rna_Node_tex_image_update(Main *bmain, Scene *UNUSED(scene), Pointer
WM_main_add_notifier(NC_IMAGE, NULL);
}
-static void rna_Node_material_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
-{
- bNodeTree *ntree = (bNodeTree *)ptr->id.data;
- bNode *node = (bNode *)ptr->data;
-
- if (node->id)
- nodeSetActive(ntree, node);
-
- ED_node_tag_update_nodetree(bmain, ntree, node);
-}
-
static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
@@ -2759,7 +2745,7 @@ static const EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C), Po
return item;
}
-static const EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+static const EnumPropertyItem *rna_Node_view_layer_itemf(bContext *UNUSED(C), PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *r_free)
{
bNode *node = (bNode *)ptr->data;
@@ -2772,7 +2758,7 @@ static const EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), P
return DummyRNA_NULL_items;
}
- rl = sce->r.layers.first;
+ rl = sce->view_layers.first;
item = renderresult_layers_add_enum(rl);
*r_free = true;
@@ -2780,7 +2766,7 @@ static const EnumPropertyItem *rna_Node_scene_layer_itemf(bContext *UNUSED(C), P
return item;
}
-static void rna_Node_scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Node_view_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_Node_update(bmain, scene, ptr);
if (scene->nodetree != NULL) {
@@ -3177,12 +3163,12 @@ static int point_density_vertex_color_source_from_shader(NodeShaderTexPointDensi
}
void rna_ShaderNodePointDensity_density_cache(bNode *self,
- Scene *scene,
- int settings)
+ Depsgraph *depsgraph)
{
NodeShaderTexPointDensity *shader_point_density = self->storage;
PointDensity *pd = &shader_point_density->pd;
- if (scene == NULL) {
+
+ if (depsgraph == NULL) {
return;
}
@@ -3214,14 +3200,11 @@ void rna_ShaderNodePointDensity_density_cache(bNode *self,
shader_point_density->cached_resolution = shader_point_density->resolution;
/* Single-threaded sampling of the voxel domain. */
- RE_point_density_cache(scene,
- pd,
- settings == 1);
+ RE_point_density_cache(depsgraph, pd);
}
void rna_ShaderNodePointDensity_density_calc(bNode *self,
- Scene *scene,
- int settings,
+ Depsgraph *depsgraph,
int *length,
float **values)
{
@@ -3229,7 +3212,7 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
PointDensity *pd = &shader_point_density->pd;
const int resolution = shader_point_density->cached_resolution;
- if (scene == NULL) {
+ if (depsgraph == NULL) {
*length = 0;
return;
}
@@ -3242,10 +3225,7 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
}
/* Single-threaded sampling of the voxel domain. */
- RE_point_density_sample(scene, pd,
- resolution,
- settings == 1,
- *values);
+ RE_point_density_sample(depsgraph, pd, resolution, *values);
/* We're done, time to clean up. */
BKE_texture_pointdensity_free_data(pd);
@@ -3254,19 +3234,20 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
}
void rna_ShaderNodePointDensity_density_minmax(bNode *self,
- Scene *scene,
- int settings,
+ Depsgraph *depsgraph,
float r_min[3],
float r_max[3])
{
NodeShaderTexPointDensity *shader_point_density = self->storage;
PointDensity *pd = &shader_point_density->pd;
- if (scene == NULL) {
+
+ if (depsgraph == NULL) {
zero_v3(r_min);
zero_v3(r_max);
return;
}
- RE_point_density_minmax(scene, pd, settings == 1, r_min, r_max);
+
+ RE_point_density_minmax(depsgraph, pd, r_min, r_max);
}
#else
@@ -3281,7 +3262,7 @@ static const EnumPropertyItem prop_image_view_items[] = {
{0, NULL, 0, NULL, NULL}
};
-static const EnumPropertyItem prop_scene_layer_items[] = {
+static const EnumPropertyItem prop_view_layer_items[] = {
{ 0, "PLACEHOLDER", 0, "Placeholder", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3600,6 +3581,12 @@ static void def_sh_output(StructRNA *srna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_DO_OUTPUT);
RNA_def_property_ui_text(prop, "Active Output", "True if this node is used as the active output");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "target", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, prop_shader_output_target_items);
+ RNA_def_property_ui_text(prop, "Target", "Which renderer and viewport shading types to use the shaders for");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_sh_output_linestyle(StructRNA *srna)
@@ -3608,33 +3595,6 @@ static void def_sh_output_linestyle(StructRNA *srna)
def_mix_rgb(srna);
}
-static void def_sh_material(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "id");
- RNA_def_property_struct_type(prop, "Material");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Material", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_material_update");
-
- prop = RNA_def_property(srna, "use_diffuse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom1", SH_NODE_MAT_DIFF);
- RNA_def_property_ui_text(prop, "Diffuse", "Material Node outputs Diffuse");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "use_specular", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom1", SH_NODE_MAT_SPEC);
- RNA_def_property_ui_text(prop, "Specular", "Material Node outputs Specular");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "invert_normal", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom1", SH_NODE_MAT_NEG);
- RNA_def_property_ui_text(prop, "Invert Normal", "Material Node uses inverted normal");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
static void def_sh_mapping(StructRNA *srna)
{
static const EnumPropertyItem prop_vect_type_items[] = {
@@ -3697,36 +3657,6 @@ static void def_sh_mapping(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
}
-static void def_sh_geometry(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometry", "storage");
-
- prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "uvname");
- RNA_def_property_ui_text(prop, "UV Map", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "color_layer", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "colname");
- RNA_def_property_ui_text(prop, "Vertex Color Layer", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
-static void def_sh_lamp(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_property(srna, "lamp_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "id");
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Lamp_object_poll");
- RNA_def_property_ui_text(prop, "Lamp Object", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
static void def_sh_attribute(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4128,9 +4058,9 @@ static void def_sh_tex_coord(StructRNA *srna)
RNA_def_property_ui_text(prop, "Object", "Use coordinates from this object (for object texture coordinates output)");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
- prop = RNA_def_property(srna, "from_dupli", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "from_instancer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
- RNA_def_property_ui_text(prop, "From Dupli", "Use the parent of the dupli object if possible");
+ RNA_def_property_ui_text(prop, "From Instancer", "Use the parent of the dupli object if possible");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -4230,13 +4160,6 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
- /* TODO(sergey): Use some mnemonic names for the hardcoded values here. */
- static const EnumPropertyItem calc_mode_items[] = {
- {0, "VIEWPORT", 0, "Viewport", "Canculate density using viewport settings"},
- {1, "RENDER", 0, "Render", "Canculate duplis using render settings"},
- {0, NULL, 0, NULL, NULL}
- };
-
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Object");
@@ -4298,13 +4221,11 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
func = RNA_def_function(srna, "cache_point_density", "rna_ShaderNodePointDensity_density_cache");
RNA_def_function_ui_description(func, "Cache point density data for later calculation");
- RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
+ RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
func = RNA_def_function(srna, "calc_point_density", "rna_ShaderNodePointDensity_density_calc");
RNA_def_function_ui_description(func, "Calculate point density");
- RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
+ RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
/* TODO, See how array size of 0 works, this shouldnt be used. */
parm = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0);
RNA_def_parameter_flags(parm, PROP_DYNAMIC, 0);
@@ -4312,8 +4233,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
func = RNA_def_function(srna, "calc_point_density_minmax", "rna_ShaderNodePointDensity_density_minmax");
RNA_def_function_ui_description(func, "Calculate point density");
- RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
+ RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS);
RNA_def_property_array(parm, 3);
RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
@@ -4436,9 +4356,9 @@ static void def_sh_uvmap(StructRNA *srna)
{
PropertyRNA *prop;
- prop = RNA_def_property(srna, "from_dupli", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "from_instancer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
- RNA_def_property_ui_text(prop, "From Dupli", "Use the parent of the dupli object if possible");
+ RNA_def_property_ui_text(prop, "From Instancer", "Use the parent of the dupli object if possible");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
RNA_def_struct_sdna_from(srna, "NodeShaderUVMap", "storage");
@@ -5057,15 +4977,15 @@ static void def_cmp_render_layers(StructRNA *srna)
RNA_def_property_struct_type(prop, "Scene");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Scene", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_scene_layer_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_view_layer_update");
prop = RNA_def_property(srna, "layer", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, prop_scene_layer_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_scene_layer_itemf");
+ RNA_def_property_enum_items(prop, prop_view_layer_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Node_view_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_scene_layer_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_view_layer_update");
}
static void rna_def_cmp_output_file_slot_file(BlenderRNA *brna)
@@ -7177,7 +7097,7 @@ static void rna_def_node_socket(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Node Socket", "Input or output socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_refine_func(srna, "rna_NodeSocket_refine");
- RNA_def_struct_ui_icon(srna, ICON_PLUG);
+ RNA_def_struct_ui_icon(srna, ICON_PLUGIN);
RNA_def_struct_path_func(srna, "rna_NodeSocket_path");
RNA_def_struct_register_funcs(srna, "rna_NodeSocket_register", "rna_NodeSocket_unregister", NULL);
RNA_def_struct_idprops_func(srna, "rna_NodeSocket_idprops");
@@ -7938,12 +7858,6 @@ static void rna_def_node(BlenderRNA *brna)
{NODE_CUSTOM, "CUSTOM", 0, "Custom", "Custom Node"},
{0, NULL, 0, NULL, NULL}};
- static const EnumPropertyItem node_shading_compatibilities[] = {
- {NODE_OLD_SHADING, "OLD_SHADING", 0, "Old Shading", "Old shading system compatibility"},
- {NODE_NEW_SHADING, "NEW_SHADING", 0, "New Shading", "New shading system compatibility"},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "Node", NULL);
RNA_def_struct_ui_text(srna, "Node", "Node in a node tree");
RNA_def_struct_sdna(srna, "bNode");
@@ -8083,12 +7997,6 @@ static void rna_def_node(BlenderRNA *brna)
parm = RNA_def_boolean(func, "result", false, "Result", "");
RNA_def_function_return(func, parm);
- prop = RNA_def_property(srna, "shading_compatibility", PROP_ENUM, PROP_NONE);
- RNA_def_property_flag(prop, PROP_ENUM_FLAG);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_sdna(prop, NULL, "typeinfo->compatibility");
- RNA_def_property_enum_items(prop, node_shading_compatibilities);
-
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname");
@@ -8106,7 +8014,7 @@ static void rna_def_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "bl_icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "typeinfo->ui_icon");
- RNA_def_property_enum_items(prop, rna_enum_node_icon_items);
+ RNA_def_property_enum_items(prop, rna_enum_icon_items);
RNA_def_property_enum_default(prop, ICON_NODE);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_ui_text(prop, "Icon", "The node icon");
@@ -8437,6 +8345,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
RNA_def_property_update(prop, NC_NODE, NULL);
@@ -8493,7 +8402,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
prop = RNA_def_property(srna, "bl_icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "typeinfo->ui_icon");
- RNA_def_property_enum_items(prop, rna_enum_node_icon_items);
+ RNA_def_property_enum_items(prop, rna_enum_icon_items);
RNA_def_property_enum_default(prop, ICON_NODETREE);
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Icon", "The node tree icon");
@@ -8573,12 +8482,21 @@ static void rna_def_composite_nodetree(BlenderRNA *brna)
static void rna_def_shader_nodetree(BlenderRNA *brna)
{
StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
srna = RNA_def_struct(brna, "ShaderNodeTree", "NodeTree");
RNA_def_struct_ui_text(srna, "Shader Node Tree",
"Node tree consisting of linked nodes used for materials (and other shading data-blocks)");
RNA_def_struct_sdna(srna, "bNodeTree");
RNA_def_struct_ui_icon(srna, ICON_MATERIAL);
+
+ func = RNA_def_function(srna, "get_output_node", "ntreeShaderOutputNode");
+ RNA_def_function_ui_description(func, "Return active shader output node for the specified target");
+ parm = RNA_def_enum(func, "target", prop_shader_output_target_items, SHD_OUTPUT_ALL, "Target", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "node", "ShaderNode", "Node", "");
+ RNA_def_function_return(func, parm);
}
static void rna_def_texture_nodetree(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 4094552d9bc..e2cce51fdcd 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -28,26 +28,30 @@
#include <stdlib.h>
#include "DNA_action_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_collection_types.h"
#include "DNA_customdata_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
-#include "DNA_property_types.h"
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_shader_fx_types.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BKE_camera.h"
+#include "BKE_collection.h"
#include "BKE_paint.h"
#include "BKE_editlattice.h"
#include "BKE_editmesh.h"
-#include "BKE_group.h" /* needed for BKE_group_object_exists() */
+#include "BKE_layer.h"
#include "BKE_object_deform.h"
+#include "BKE_object_facemap.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -70,22 +74,55 @@ const EnumPropertyItem rna_enum_object_mode_items[] = {
{OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
{OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
{OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""},
- {OB_MODE_GPENCIL, "GPENCIL_EDIT", ICON_GREASEPENCIL, "Edit Strokes", "Edit Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_EDIT, "GPENCIL_EDIT", ICON_EDITMODE_HLT, "Edit Mode", "Edit Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_SCULPT, "GPENCIL_SCULPT", ICON_SCULPTMODE_HLT, "Sculpt Mode", "Sculpt Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_PAINT, "GPENCIL_PAINT", ICON_GREASEPENCIL, "Draw", "Paint Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_WEIGHT, "GPENCIL_WEIGHT", ICON_WPAINT_HLT, "Weight Paint", "Grease Pencil Weight Paint Strokes" },
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* Same as above, but with names that distinguish grease pencil. */
+const EnumPropertyItem rna_enum_workspace_object_mode_items[] = {
+ {OB_MODE_OBJECT, "OBJECT", ICON_OBJECT_DATAMODE, "Object Mode", ""},
+ {OB_MODE_EDIT, "EDIT", ICON_EDITMODE_HLT, "Edit Mode", ""},
+ {OB_MODE_POSE, "POSE", ICON_POSE_HLT, "Pose Mode", ""},
+ {OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt Mode", ""},
+ {OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""},
+ {OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
+ {OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
+ {OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""},
+ {OB_MODE_GPENCIL_EDIT, "GPENCIL_EDIT", ICON_EDITMODE_HLT, "Grease Pencil Edit Mode", "Edit Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_SCULPT, "GPENCIL_SCULPT", ICON_SCULPTMODE_HLT, "Grease Pencil Sculpt Mode", "Sculpt Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_PAINT, "GPENCIL_PAINT", ICON_GREASEPENCIL, "Grease Pencil Draw", "Paint Grease Pencil Strokes"},
+ {OB_MODE_GPENCIL_WEIGHT, "GPENCIL_WEIGHT", ICON_WPAINT_HLT, "Grease Pencil Weight Paint", "Grease Pencil Weight Paint Strokes" },
{0, NULL, 0, NULL, NULL}
};
const EnumPropertyItem rna_enum_object_empty_drawtype_items[] = {
- {OB_PLAINAXES, "PLAIN_AXES", 0, "Plain Axes", ""},
- {OB_ARROWS, "ARROWS", 0, "Arrows", ""},
- {OB_SINGLE_ARROW, "SINGLE_ARROW", 0, "Single Arrow", ""},
- {OB_CIRCLE, "CIRCLE", 0, "Circle", ""},
- {OB_CUBE, "CUBE", 0, "Cube", ""},
- {OB_EMPTY_SPHERE, "SPHERE", 0, "Sphere", ""},
- {OB_EMPTY_CONE, "CONE", 0, "Cone", ""},
- {OB_EMPTY_IMAGE, "IMAGE", 0, "Image", ""},
+ {OB_PLAINAXES, "PLAIN_AXES", ICON_EMPTY_AXIS, "Plain Axes", ""},
+ {OB_ARROWS, "ARROWS", ICON_EMPTY_ARROWS, "Arrows", ""},
+ {OB_SINGLE_ARROW, "SINGLE_ARROW", ICON_EMPTY_SINGLE_ARROW, "Single Arrow", ""},
+ {OB_CIRCLE, "CIRCLE", ICON_MESH_CIRCLE, "Circle", ""},
+ {OB_CUBE, "CUBE", ICON_CUBE, "Cube", ""},
+ {OB_EMPTY_SPHERE, "SPHERE", ICON_SPHERE, "Sphere", ""},
+ {OB_EMPTY_CONE, "CONE", ICON_CONE, "Cone", ""},
+ {OB_EMPTY_IMAGE, "IMAGE", ICON_FILE_IMAGE, "Image", ""},
{0, NULL, 0, NULL, NULL}
};
+const EnumPropertyItem rna_enum_object_empty_image_depth_items[] = {
+ {OB_EMPTY_IMAGE_DEPTH_DEFAULT, "DEFAULT", 0, "Default", ""},
+ {OB_EMPTY_IMAGE_DEPTH_FRONT, "FRONT", 0, "Front", ""},
+ {OB_EMPTY_IMAGE_DEPTH_BACK, "BACK", 0, "Back", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+const EnumPropertyItem rna_enum_object_gpencil_type_items[] = {
+ {GP_EMPTY, "EMPTY", ICON_EMPTY_AXIS, "Blank", "Create an empty grease pencil object"},
+ {GP_STROKE, "STROKE", ICON_STROKE, "Stroke", "Create a simple stroke with basic colors"},
+ {GP_MONKEY, "MONKEY", ICON_MONKEY, "Monkey", "Construct a Suzanne grease pencil object"},
+ {0, NULL, 0, NULL, NULL }
+};
static const EnumPropertyItem parent_type_items[] = {
{PAROBJECT, "OBJECT", 0, "Object", "The object is parented to an object"},
@@ -97,28 +134,27 @@ static const EnumPropertyItem parent_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-#ifndef RNA_RUNTIME
-static const EnumPropertyItem dupli_items[] = {
- {0, "NONE", 0, "None", ""},
- {OB_DUPLIFRAMES, "FRAMES", 0, "Frames", "Make copy of object for every frame"},
- {OB_DUPLIVERTS, "VERTS", 0, "Verts", "Duplicate child objects on all vertices"},
- {OB_DUPLIFACES, "FACES", 0, "Faces", "Duplicate child objects on all faces"},
- {OB_DUPLIGROUP, "GROUP", 0, "Group", "Enable group instancing"},
+#define INSTANCE_ITEMS_SHARED \
+ {0, "NONE", 0, "None", ""}, \
+ {OB_DUPLIFRAMES, "FRAMES", 0, "Frames", "Make instance of object for every frame"}, \
+ {OB_DUPLIVERTS, "VERTS", 0, "Verts", "Instantiate child objects on all vertices"}, \
+ {OB_DUPLIFACES, "FACES", 0, "Faces", "Instantiate child objects on all faces"}
+
+#define INSTANCE_ITEM_COLLECTION \
+ {OB_DUPLICOLLECTION, "COLLECTION", 0, "Collection", "Enable collection instancing"}
+static const EnumPropertyItem instance_items[] = {
+ INSTANCE_ITEMS_SHARED,
+ INSTANCE_ITEM_COLLECTION,
{0, NULL, 0, NULL, NULL}
};
-#endif
-
-static const EnumPropertyItem collision_bounds_items[] = {
- {OB_BOUND_BOX, "BOX", ICON_MESH_CUBE, "Box", ""},
- {OB_BOUND_SPHERE, "SPHERE", ICON_MESH_UVSPHERE, "Sphere", ""},
- {OB_BOUND_CYLINDER, "CYLINDER", ICON_MESH_CYLINDER, "Cylinder", ""},
- {OB_BOUND_CONE, "CONE", ICON_MESH_CONE, "Cone", ""},
- {OB_BOUND_CONVEX_HULL, "CONVEX_HULL", ICON_MESH_ICOSPHERE, "Convex Hull", ""},
- {OB_BOUND_TRIANGLE_MESH, "TRIANGLE_MESH", ICON_MESH_MONKEY, "Triangle Mesh", ""},
- {OB_BOUND_CAPSULE, "CAPSULE", ICON_MESH_CAPSULE, "Capsule", ""},
- /*{OB_DYN_MESH, "DYNAMIC_MESH", 0, "Dynamic Mesh", ""}, */
+#ifdef RNA_RUNTIME
+static EnumPropertyItem instance_items_nogroup[] = {
+ INSTANCE_ITEMS_SHARED,
{0, NULL, 0, NULL, NULL}
};
+#endif
+#undef INSTANCE_ITEMS_SHARED
+#undef INSTANCE_ITEM_COLLECTION
const EnumPropertyItem rna_enum_metaelem_type_items[] = {
{MB_BALL, "BALL", ICON_META_BALL, "Ball", ""},
@@ -144,10 +180,12 @@ const EnumPropertyItem rna_enum_object_type_items[] = {
{OB_ARMATURE, "ARMATURE", 0, "Armature", ""},
{OB_LATTICE, "LATTICE", 0, "Lattice", ""},
{OB_EMPTY, "EMPTY", 0, "Empty", ""},
+ {OB_GPENCIL, "GPENCIL", 0, "GPencil", ""},
{0, "", 0, NULL, NULL},
{OB_CAMERA, "CAMERA", 0, "Camera", ""},
- {OB_LAMP, "LAMP", 0, "Lamp", ""},
+ {OB_LAMP, "LIGHT", 0, "Light", ""},
{OB_SPEAKER, "SPEAKER", 0, "Speaker", ""},
+ {OB_LIGHTPROBE, "LIGHT_PROBE", 0, "Probe", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -174,25 +212,30 @@ const EnumPropertyItem rna_enum_object_axis_items[] = {
#include "DNA_key_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_ID.h"
#include "DNA_lattice_types.h"
#include "DNA_node_types.h"
#include "BKE_armature.h"
-#include "BKE_bullet.h"
+#include "BKE_brush.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_object.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_deform.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_object.h"
#include "ED_particle.h"
#include "ED_curve.h"
@@ -200,12 +243,12 @@ const EnumPropertyItem rna_enum_object_axis_items[] = {
static void rna_Object_internal_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_tag_update(ptr->id.data, OB_RECALC_OB);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_OB);
}
static void rna_Object_internal_update_draw(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_tag_update(ptr->id.data, OB_RECALC_OB);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_OB);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ptr->id.data);
}
@@ -216,11 +259,29 @@ static void rna_Object_matrix_world_update(Main *bmain, Scene *scene, PointerRNA
rna_Object_internal_update(bmain, scene, ptr);
}
-static void rna_Object_hide_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_Object_hide_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_type_tag(bmain, ID_OB);
+ Object *ob = ptr->id.data;
+ BKE_main_collection_sync(bmain);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id);
}
+static void rna_MaterialIndex_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ /* update the material of all brushes not pinned */
+ Object *ob = (Object *)ptr->id.data;
+ if (ob && ob->type == OB_GPENCIL) {
+ Material *ma = give_current_material(ob, ob->actcol);
+ if (ma != NULL) {
+ BKE_brush_update_material(bmain, ma, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ }
+ }
+}
+
+
static void rna_Object_matrix_local_get(PointerRNA *ptr, float values[16])
{
Object *ob = ptr->id.data;
@@ -261,22 +322,24 @@ static void rna_Object_matrix_basis_set(PointerRNA *ptr, const float values[16])
void rna_Object_internal_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ptr->id.data);
}
-static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Object_active_shape_update(bContext *C, PointerRNA *ptr)
{
Object *ob = ptr->id.data;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
- if (scene->obedit == ob) {
+ if (CTX_data_edit_object(C) == ob) {
/* exit/enter editmode to get new shape */
switch (ob->type) {
case OB_MESH:
EDBM_mesh_load(bmain, ob);
EDBM_mesh_make(ob, scene->toolsettings->selectmode, true);
- DAG_id_tag_update(ob->data, 0);
+ DEG_id_tag_update(ob->data, 0);
EDBM_mesh_normals_update(((Mesh *)ob->data)->edit_btmesh);
BKE_editmesh_tessface_calc(((Mesh *)ob->data)->edit_btmesh);
@@ -298,75 +361,11 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA
static void rna_Object_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_tag_update(ptr->id.data, OB_RECALC_OB);
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_OB);
+ DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_OBJECT | ND_PARENT, ptr->id.data);
}
-/* when changing the selection flag the scene needs updating */
-static void rna_Object_select_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
-{
- if (scene) {
- Object *ob = (Object *)ptr->id.data;
- short mode = (ob->flag & SELECT) ? BA_SELECT : BA_DESELECT;
- ED_base_object_select(BKE_scene_base_find(scene, ob), mode);
- }
-}
-
-static void rna_Base_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Base *base = (Base *)ptr->data;
- short mode = (base->flag & BA_SELECT) ? BA_SELECT : BA_DESELECT;
- ED_base_object_select(base, mode);
-}
-
-static void rna_Object_layer_update__internal(Main *bmain, Scene *scene, Base *base, Object *ob)
-{
- /* try to avoid scene sort */
- if (scene == NULL) {
- /* pass - unlikely but when running scripts on startup it happens */
- }
- else if ((ob->lay & scene->lay) && (base->lay & scene->lay)) {
- /* pass */
- }
- else if ((ob->lay & scene->lay) == 0 && (base->lay & scene->lay) == 0) {
- /* pass */
- }
- else {
- DAG_relations_tag_update(bmain);
- }
-
- DAG_id_type_tag(bmain, ID_OB);
-}
-
-static void rna_Object_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
- Base *base;
-
- base = scene ? BKE_scene_base_find(scene, ob) : NULL;
- if (!base)
- return;
-
- SWAP(unsigned int, base->lay, ob->lay);
-
- rna_Object_layer_update__internal(bmain, scene, base, ob);
- ob->lay = base->lay;
-
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, scene);
-}
-
-static void rna_Base_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Base *base = (Base *)ptr->data;
- Object *ob = (Object *)base->object;
-
- rna_Object_layer_update__internal(bmain, scene, base, ob);
- ob->lay = base->lay;
-
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, scene);
-}
-
static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->data;
@@ -381,8 +380,8 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
return;
}
- BLI_assert(BKE_id_is_in_gobal_main(&ob->id));
- BLI_assert(BKE_id_is_in_gobal_main(id));
+ BLI_assert(BKE_id_is_in_global_main(&ob->id));
+ BLI_assert(BKE_id_is_in_global_main(id));
if (ob->type == OB_EMPTY) {
if (ob->data) {
@@ -410,10 +409,12 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
ob->data = id;
test_object_materials(G_MAIN, ob, id);
- if (GS(id->name) == ID_CU)
+ if (GS(id->name) == ID_CU) {
BKE_curve_type_test(ob);
- else if (ob->type == OB_ARMATURE)
- BKE_pose_rebuild(ob, ob->data);
+ }
+ else if (ob->type == OB_ARMATURE) {
+ BKE_pose_rebuild(G_MAIN, ob, ob->data, true);
+ }
}
}
@@ -429,15 +430,30 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr)
case OB_SURF: return &RNA_Curve;
case OB_FONT: return &RNA_Curve;
case OB_MBALL: return &RNA_MetaBall;
- case OB_LAMP: return &RNA_Lamp;
+ case OB_LAMP: return &RNA_Light;
case OB_CAMERA: return &RNA_Camera;
case OB_LATTICE: return &RNA_Lattice;
case OB_ARMATURE: return &RNA_Armature;
case OB_SPEAKER: return &RNA_Speaker;
+ case OB_LIGHTPROBE: return &RNA_LightProbe;
+ case OB_GPENCIL: return &RNA_GreasePencil;
default: return &RNA_ID;
}
}
+static bool rna_Object_data_poll(PointerRNA *ptr, const PointerRNA value)
+{
+ Object *ob = (Object *)ptr->data;
+
+ if (ob->type == OB_GPENCIL) {
+ /* GP Object - Don't allow using "Annotation" GP datablocks here */
+ bGPdata *gpd = value.data;
+ return (gpd->flag & GP_DATA_ANNOTATIONS) == 0;
+ }
+
+ return true;
+}
+
static void rna_Object_parent_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->data;
@@ -489,62 +505,59 @@ static const EnumPropertyItem *rna_Object_parent_type_itemf(bContext *UNUSED(C),
return item;
}
-static void rna_Object_empty_draw_type_set(PointerRNA *ptr, int value)
+static void rna_Object_empty_display_type_set(PointerRNA *ptr, int value)
{
Object *ob = (Object *)ptr->data;
BKE_object_empty_draw_type_set(ob, value);
}
-static const EnumPropertyItem *rna_Object_collision_bounds_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
+static void rna_Object_parent_bone_set(PointerRNA *ptr, const char *value)
{
Object *ob = (Object *)ptr->data;
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- if (ob->body_type != OB_BODY_TYPE_CHARACTER) {
- RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_TRIANGLE_MESH);
- }
- RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_CONVEX_HULL);
-
- if (ob->body_type != OB_BODY_TYPE_SOFT) {
- RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_CONE);
- RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_CYLINDER);
- RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_SPHERE);
- RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_BOX);
- RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_CAPSULE);
- }
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
+ ED_object_parent(ob, ob->parent, ob->partype, value);
}
-static void rna_Object_parent_bone_set(PointerRNA *ptr, const char *value)
+static const EnumPropertyItem *rna_Object_instance_type_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
Object *ob = (Object *)ptr->data;
+ const EnumPropertyItem *item;
- ED_object_parent(ob, ob->parent, ob->partype, value);
+ if (ob->type == OB_EMPTY) {
+ item = instance_items;
+ }
+ else {
+ item = instance_items_nogroup;
+ }
+
+ return item;
}
-static void rna_Object_dup_group_set(PointerRNA *ptr, PointerRNA value)
+static void rna_Object_dup_collection_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->data;
- Group *grp = (Group *)value.data;
+ Collection *grp = (Collection *)value.data;
/* must not let this be set if the object belongs in this group already,
* thus causing a cycle/infinite-recursion leading to crashes on load [#25298]
*/
- if (BKE_group_object_exists(grp, ob) == 0) {
- id_us_min(&ob->dup_group->id);
- ob->dup_group = grp;
- id_us_plus(&ob->dup_group->id);
+ if (BKE_collection_has_object_recursive(grp, ob) == 0) {
+ if (ob->type == OB_EMPTY) {
+ id_us_min(&ob->dup_group->id);
+ ob->dup_group = grp;
+ id_us_plus(&ob->dup_group->id);
+ }
+ else {
+ BKE_report(NULL, RPT_ERROR,
+ "Only empty objects support group instances");
+ }
}
else {
BKE_report(NULL, RPT_ERROR,
- "Cannot set dupli-group as object belongs in group being instanced, thus causing a cycle");
+ "Cannot set instance-collection as object belongs in group being instanced, thus causing a cycle");
}
}
@@ -628,6 +641,87 @@ void rna_object_vgroup_name_set(PointerRNA *ptr, const char *value, char *result
result[0] = '\0';
}
+static void rna_FaceMap_name_set(PointerRNA *ptr, const char *value)
+{
+ Object *ob = (Object *)ptr->id.data;
+ bFaceMap *fmap = (bFaceMap *)ptr->data;
+ BLI_strncpy_utf8(fmap->name, value, sizeof(fmap->name));
+ BKE_object_facemap_unique_name(ob, fmap);
+}
+
+static int rna_FaceMap_index_get(PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+
+ return BLI_findindex(&ob->fmaps, ptr->data);
+}
+
+static PointerRNA rna_Object_active_face_map_get(PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ return rna_pointer_inherit_refine(ptr, &RNA_FaceMap, BLI_findlink(&ob->fmaps, ob->actfmap - 1));
+}
+
+static int rna_Object_active_face_map_index_get(PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ return ob->actfmap - 1;
+}
+
+static void rna_Object_active_face_map_index_set(PointerRNA *ptr, int value)
+{
+ Object *ob = (Object *)ptr->id.data;
+ ob->actfmap = value + 1;
+}
+
+static void rna_Object_active_face_map_index_range(PointerRNA *ptr, int *min, int *max,
+ int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Object *ob = (Object *)ptr->id.data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&ob->fmaps) - 1);
+}
+
+void rna_object_BKE_object_facemap_name_index_get(PointerRNA *ptr, char *value, int index)
+{
+ Object *ob = (Object *)ptr->id.data;
+ bFaceMap *fmap;
+
+ fmap = BLI_findlink(&ob->fmaps, index - 1);
+
+ if (fmap) BLI_strncpy(value, fmap->name, sizeof(fmap->name));
+ else value[0] = '\0';
+}
+
+int rna_object_BKE_object_facemap_name_index_length(PointerRNA *ptr, int index)
+{
+ Object *ob = (Object *)ptr->id.data;
+ bFaceMap *fmap;
+
+ fmap = BLI_findlink(&ob->fmaps, index - 1);
+ return (fmap) ? strlen(fmap->name) : 0;
+}
+
+void rna_object_BKE_object_facemap_name_index_set(PointerRNA *ptr, const char *value, short *index)
+{
+ Object *ob = (Object *)ptr->id.data;
+ *index = BKE_object_facemap_name_index(ob, value) + 1;
+}
+
+void rna_object_fmap_name_set(PointerRNA *ptr, const char *value, char *result, int maxlen)
+{
+ Object *ob = (Object *)ptr->id.data;
+ bFaceMap *fmap = BKE_object_facemap_find_name(ob, value);
+ if (fmap) {
+ BLI_strncpy(result, value, maxlen); /* no need for BLI_strncpy_utf8, since this matches an existing group */
+ return;
+ }
+
+ result[0] = '\0';
+}
+
+
void rna_object_uvlayer_name_set(PointerRNA *ptr, const char *value, char *result, int maxlen)
{
Object *ob = (Object *)ptr->id.data;
@@ -638,10 +732,10 @@ void rna_object_uvlayer_name_set(PointerRNA *ptr, const char *value, char *resul
if (ob->type == OB_MESH && ob->data) {
me = (Mesh *)ob->data;
- for (a = 0; a < me->pdata.totlayer; a++) {
- layer = &me->pdata.layers[a];
+ for (a = 0; a < me->ldata.totlayer; a++) {
+ layer = &me->ldata.layers[a];
- if (layer->type == CD_MTEXPOLY && STREQ(layer->name, value)) {
+ if (layer->type == CD_MLOOPUV && STREQ(layer->name, value)) {
BLI_strncpy(result, value, maxlen);
return;
}
@@ -715,9 +809,9 @@ static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)ptr->id.data;
- DAG_id_tag_update(value.data, 0);
- BLI_assert(BKE_id_is_in_gobal_main(&ob->id));
- BLI_assert(BKE_id_is_in_gobal_main(value.data));
+ DEG_id_tag_update(value.data, 0);
+ BLI_assert(BKE_id_is_in_global_main(&ob->id));
+ BLI_assert(BKE_id_is_in_global_main(value.data));
assign_material(G_MAIN, ob, value.data, ob->actcol, BKE_MAT_ASSIGN_EXISTING);
}
@@ -757,11 +851,16 @@ static void rna_Object_active_particle_system_index_set(PointerRNA *ptr, int val
psys_set_current_num(ob, value);
}
-static void rna_Object_particle_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Object_particle_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
+ /* TODO: Disabled for now, because bContext is not available. */
+#if 0
Object *ob = (Object *)ptr->id.data;
-
- PE_current_changed(bmain, scene, ob);
+ PE_current_changed(NULL, scene, ob);
+#else
+ (void) scene;
+ (void) ptr;
+#endif
}
/* rotation - axis-angle */
@@ -874,12 +973,27 @@ static int rna_Object_rotation_4d_editable(PointerRNA *ptr, int index)
return PROP_EDITABLE;
}
+static int rna_MaterialSlot_material_editable(PointerRNA *ptr, const char **UNUSED(r_info))
+{
+ Object *ob = (Object *)ptr->id.data;
+ const int index = (Material **)ptr->data - ob->mat;
+ bool is_editable;
+
+ if ((ob->matbits == NULL) || ob->matbits[index]) {
+ is_editable = !ID_IS_LINKED(ob);
+ }
+ else {
+ is_editable = ob->data ? !ID_IS_LINKED(ob->data) : false;
+ }
+
+ return is_editable ? PROP_EDITABLE : 0;
+}
static PointerRNA rna_MaterialSlot_material_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
Material *ma;
- int index = (Material **)ptr->data - ob->mat;
+ const int index = (Material **)ptr->data - ob->mat;
ma = give_current_material(ob, index + 1);
return rna_pointer_inherit_refine(ptr, &RNA_Material, ma);
@@ -890,11 +1004,26 @@ static void rna_MaterialSlot_material_set(PointerRNA *ptr, PointerRNA value)
Object *ob = (Object *)ptr->id.data;
int index = (Material **)ptr->data - ob->mat;
- BLI_assert(BKE_id_is_in_gobal_main(&ob->id));
- BLI_assert(BKE_id_is_in_gobal_main(value.data));
+ BLI_assert(BKE_id_is_in_global_main(&ob->id));
+ BLI_assert(BKE_id_is_in_global_main(value.data));
assign_material(G_MAIN, ob, value.data, index + 1, BKE_MAT_ASSIGN_EXISTING);
}
+static bool rna_MaterialSlot_material_poll(PointerRNA *ptr, PointerRNA value)
+{
+ Object *ob = (Object *)ptr->id.data;
+ Material *ma = (Material *)value.data;
+
+ if (ob->type == OB_GPENCIL) {
+ /* GP Materials only */
+ return (ma->gp_style != NULL);
+ }
+ else {
+ /* Everything except GP materials */
+ return (ma->gp_style == NULL);
+ }
+}
+
static int rna_MaterialSlot_link_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
@@ -952,7 +1081,7 @@ static void rna_MaterialSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr)
WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, ptr->id.data);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
static char *rna_MaterialSlot_path(PointerRNA *ptr)
@@ -960,7 +1089,6 @@ static char *rna_MaterialSlot_path(PointerRNA *ptr)
Object *ob = (Object *)ptr->id.data;
int index = (Material **)ptr->data - ob->mat;
- /* from armature... */
return BLI_sprintfN("material_slots[%d]", index);
}
@@ -969,121 +1097,10 @@ static char *rna_MaterialSlot_path(PointerRNA *ptr)
*
* logic from check_body_type()
* */
-static int rna_GameObjectSettings_physics_type_get(PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
-
- /* determine the body_type setting based on flags */
- if (!(ob->gameflag & OB_COLLISION)) {
- if (ob->gameflag & OB_OCCLUDER) {
- ob->body_type = OB_BODY_TYPE_OCCLUDER;
- }
- else if (ob->gameflag & OB_NAVMESH) {
- ob->body_type = OB_BODY_TYPE_NAVMESH;
- }
- else {
- ob->body_type = OB_BODY_TYPE_NO_COLLISION;
- }
- }
- else if (ob->gameflag & OB_CHARACTER) {
- ob->body_type = OB_BODY_TYPE_CHARACTER;
- }
- else if (ob->gameflag & OB_SENSOR) {
- ob->body_type = OB_BODY_TYPE_SENSOR;
- }
- else if (!(ob->gameflag & OB_DYNAMIC)) {
- ob->body_type = OB_BODY_TYPE_STATIC;
- }
- else if (!(ob->gameflag & (OB_RIGID_BODY | OB_SOFT_BODY))) {
- ob->body_type = OB_BODY_TYPE_DYNAMIC;
- }
- else if (ob->gameflag & OB_RIGID_BODY) {
- ob->body_type = OB_BODY_TYPE_RIGID;
- }
- else {
- ob->body_type = OB_BODY_TYPE_SOFT;
- /* create the structure here because we display soft body buttons in the main panel */
- if (!ob->bsoft)
- ob->bsoft = bsbNew();
- }
- return ob->body_type;
-}
-
-static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
+static char *rna_ObjectDisplay_path(PointerRNA *UNUSED(ptr))
{
- Object *ob = (Object *)ptr->id.data;
- const int gameflag_prev = ob->gameflag;
- ob->body_type = value;
-
- switch (ob->body_type) {
- case OB_BODY_TYPE_SENSOR:
- ob->gameflag |= OB_SENSOR | OB_COLLISION;
- ob->gameflag &= ~(OB_OCCLUDER | OB_CHARACTER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR |
- OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH);
- break;
- case OB_BODY_TYPE_OCCLUDER:
- ob->gameflag |= OB_OCCLUDER;
- ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_DYNAMIC | OB_NAVMESH);
- break;
- case OB_BODY_TYPE_NAVMESH:
- ob->gameflag |= OB_NAVMESH;
- ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_DYNAMIC | OB_OCCLUDER);
-
- if (ob->type == OB_MESH) {
- /* could be moved into mesh UI but for now ensure mesh data layer */
- BKE_mesh_ensure_navmesh(ob->data);
- }
-
- break;
- case OB_BODY_TYPE_NO_COLLISION:
- ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH);
- break;
- case OB_BODY_TYPE_CHARACTER:
- ob->gameflag |= OB_COLLISION | OB_CHARACTER;
- ob->gameflag &= ~(OB_SENSOR | OB_OCCLUDER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR |
- OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH);
- /* When we switch to character physics and the collision bounds is set to triangle mesh
- * we have to change collision bounds because triangle mesh is not supported by Characters */
- if ((ob->gameflag & OB_BOUNDS) && ob->collision_boundtype == OB_BOUND_TRIANGLE_MESH) {
- ob->boundtype = ob->collision_boundtype = OB_BOUND_BOX;
- }
- break;
- case OB_BODY_TYPE_STATIC:
- ob->gameflag |= OB_COLLISION;
- ob->gameflag &= ~(OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_OCCLUDER | OB_CHARACTER | OB_SENSOR | OB_NAVMESH);
- break;
- case OB_BODY_TYPE_DYNAMIC:
- ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_ACTOR;
- ob->gameflag &= ~(OB_RIGID_BODY | OB_SOFT_BODY | OB_OCCLUDER | OB_CHARACTER | OB_SENSOR | OB_NAVMESH);
- break;
- case OB_BODY_TYPE_RIGID:
- ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_RIGID_BODY | OB_ACTOR;
- ob->gameflag &= ~(OB_SOFT_BODY | OB_OCCLUDER | OB_CHARACTER | OB_SENSOR | OB_NAVMESH);
- break;
- default:
- case OB_BODY_TYPE_SOFT:
- ob->gameflag |= OB_COLLISION | OB_DYNAMIC | OB_SOFT_BODY | OB_ACTOR;
- ob->gameflag &= ~(OB_RIGID_BODY | OB_OCCLUDER | OB_CHARACTER | OB_SENSOR | OB_NAVMESH);
-
- /* assume triangle mesh, if no bounds chosen for soft body */
- if ((ob->gameflag & OB_BOUNDS) && (ob->boundtype < OB_BOUND_TRIANGLE_MESH)) {
- ob->boundtype = OB_BOUND_TRIANGLE_MESH;
- }
- /* create a BulletSoftBody structure if not already existing */
- if (!ob->bsoft)
- ob->bsoft = bsbNew();
- break;
- }
-
- if ((gameflag_prev & OB_NAVMESH) != (ob->gameflag & OB_NAVMESH)) {
- if (ob->type == OB_MESH) {
- /* this is needed to refresh the derived meshes draw func */
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
- }
- }
-
- WM_main_add_notifier(NC_OBJECT | ND_DRAW, ptr->id.data);
+ return BLI_strdup("display");
}
static PointerRNA rna_Object_active_particle_system_get(PointerRNA *ptr)
@@ -1093,160 +1110,6 @@ static PointerRNA rna_Object_active_particle_system_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ParticleSystem, psys);
}
-static PointerRNA rna_Object_game_settings_get(PointerRNA *ptr)
-{
- return rna_pointer_inherit_refine(ptr, &RNA_GameObjectSettings, ptr->id.data);
-}
-
-
-static unsigned int rna_Object_layer_validate__internal(const bool *values, unsigned int lay)
-{
- int i, tot = 0;
-
- /* ensure we always have some layer selected */
- for (i = 0; i < 20; i++)
- if (values[i])
- tot++;
-
- if (tot == 0)
- return 0;
-
- for (i = 0; i < 20; i++) {
- if (values[i]) lay |= (1 << i);
- else lay &= ~(1 << i);
- }
-
- return lay;
-}
-
-static void rna_Object_layer_set(PointerRNA *ptr, const bool *values)
-{
- Object *ob = (Object *)ptr->data;
- unsigned int lay;
-
- lay = rna_Object_layer_validate__internal(values, ob->lay);
- if (lay)
- ob->lay = lay;
-}
-
-static void rna_Base_layer_set(PointerRNA *ptr, const bool *values)
-{
- Base *base = (Base *)ptr->data;
-
- unsigned int lay;
- lay = rna_Object_layer_validate__internal(values, base->lay);
- if (lay)
- base->lay = lay;
-
- /* rna_Base_layer_update updates the objects layer */
-}
-
-static void rna_GameObjectSettings_state_get(PointerRNA *ptr, bool *values)
-{
- Object *ob = (Object *)ptr->data;
- int i;
- int all_states = (ob->scaflag & OB_ALLSTATE) ? 1 : 0;
-
- memset(values, 0, sizeof(int) * OB_MAX_STATES);
- for (i = 0; i < OB_MAX_STATES; i++) {
- values[i] = (ob->state & (1 << i)) ? 1 : 0 | all_states;
- }
-}
-
-static void rna_GameObjectSettings_state_set(PointerRNA *ptr, const bool *values)
-{
- Object *ob = (Object *)ptr->data;
- int i, tot = 0;
-
- /* ensure we always have some state selected */
- for (i = 0; i < OB_MAX_STATES; i++)
- if (values[i])
- tot++;
-
- if (tot == 0)
- return;
-
- for (i = 0; i < OB_MAX_STATES; i++) {
- if (values[i]) ob->state |= (1 << i);
- else ob->state &= ~(1 << i);
- }
-}
-
-static void rna_GameObjectSettings_used_state_get(PointerRNA *ptr, bool *values)
-{
- Object *ob = (Object *)ptr->data;
- bController *cont;
-
- memset(values, 0, sizeof(int) * OB_MAX_STATES);
- for (cont = ob->controllers.first; cont; cont = cont->next) {
- int i;
-
- for (i = 0; i < OB_MAX_STATES; i++) {
- if (cont->state_mask & (1 << i))
- values[i] = 1;
- }
- }
-}
-
-static void rna_GameObjectSettings_col_group_get(PointerRNA *ptr, bool *values)
-{
- Object *ob = (Object *)ptr->data;
- int i;
-
- for (i = 0; i < OB_MAX_COL_MASKS; i++) {
- values[i] = (ob->col_group & (1 << i)) != 0;
- }
-}
-
-static void rna_GameObjectSettings_col_group_set(PointerRNA *ptr, const bool *values)
-{
- Object *ob = (Object *)ptr->data;
- int i, tot = 0;
-
- /* ensure we always have some group selected */
- for (i = 0; i < OB_MAX_COL_MASKS; i++)
- if (values[i])
- tot++;
-
- if (tot == 0)
- return;
-
- for (i = 0; i < OB_MAX_COL_MASKS; i++) {
- if (values[i]) ob->col_group |= (1 << i);
- else ob->col_group &= ~(1 << i);
- }
-}
-
-static void rna_GameObjectSettings_col_mask_get(PointerRNA *ptr, bool *values)
-{
- Object *ob = (Object *)ptr->data;
- int i;
-
- for (i = 0; i < OB_MAX_COL_MASKS; i++) {
- values[i] = (ob->col_mask & (1 << i)) != 0;
- }
-}
-
-static void rna_GameObjectSettings_col_mask_set(PointerRNA *ptr, const bool *values)
-{
- Object *ob = (Object *)ptr->data;
- int i, tot = 0;
-
- /* ensure we always have some mask selected */
- for (i = 0; i < OB_MAX_COL_MASKS; i++)
- if (values[i])
- tot++;
-
- if (tot == 0)
- return;
-
- for (i = 0; i < OB_MAX_COL_MASKS; i++) {
- if (values[i]) ob->col_mask |= (1 << i);
- else ob->col_mask &= ~(1 << i);
- }
-}
-
-
static void rna_Object_active_shape_key_index_range(PointerRNA *ptr, int *min, int *max,
int *UNUSED(softmin), int *UNUSED(softmax))
{
@@ -1366,6 +1229,56 @@ static void rna_Object_constraints_clear(Object *object, Main *bmain)
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, object);
}
+bool rna_Object_constraints_override_apply(
+ Main *UNUSED(bmain),
+ PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *UNUSED(prop_dst), PropertyRNA *UNUSED(prop_src), PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst), const int UNUSED(len_src), const int UNUSED(len_storage),
+ PointerRNA *UNUSED(ptr_item_dst), PointerRNA *UNUSED(ptr_item_src), PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_INSERT_AFTER &&
+ "Unsupported RNA override operation on constraints collection");
+
+ Object *ob_dst = (Object *)ptr_dst->id.data;
+ Object *ob_src = (Object *)ptr_src->id.data;
+
+ /* Remember that insertion operations are defined and stored in correct order, which means that
+ * even if we insert several items in a row, we alays insert first one, then second one, etc.
+ * So we should always find 'anchor' constraint in both _src *and* _dst> */
+ bConstraint *con_anchor = NULL;
+ if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+ con_anchor = BLI_findstring(&ob_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
+ }
+ if (con_anchor == NULL && opop->subitem_local_index >= 0) {
+ con_anchor = BLI_findlink(&ob_dst->constraints, opop->subitem_local_index);
+ }
+ /* Otherwise we just insert in first position. */
+
+ bConstraint *con_src = NULL;
+ if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+ con_src = BLI_findstring(&ob_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
+ }
+ if (con_src == NULL && opop->subitem_local_index >= 0) {
+ con_src = BLI_findlink(&ob_src->constraints, opop->subitem_local_index);
+ }
+ con_src = con_src ? con_src->next : ob_src->constraints.first;
+
+ BLI_assert(con_src != NULL);
+
+ bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true);
+
+ /* This handles NULL anchor as expected by adding at head of list. */
+ BLI_insertlinkafter(&ob_dst->constraints, con_anchor, con_dst);
+
+ /* This should actually *not* be needed in typical cases. However, if overridden source was edited,
+ * we *may* have some new conflicting names. */
+ BKE_constraint_unique_name(con_dst, &ob_dst->constraints);
+
+// printf("%s: We inserted a constraint...\n", __func__);
+ return true;
+}
+
static ModifierData *rna_Object_modifier_new(Object *object, bContext *C, ReportList *reports,
const char *name, int type)
{
@@ -1392,6 +1305,112 @@ static void rna_Object_modifier_clear(Object *object, bContext *C)
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
}
+bool rna_Object_modifiers_override_apply(
+ Main *UNUSED(bmain),
+ PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *UNUSED(prop_dst), PropertyRNA *UNUSED(prop_src), PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst), const int UNUSED(len_src), const int UNUSED(len_storage),
+ PointerRNA *UNUSED(ptr_item_dst), PointerRNA *UNUSED(ptr_item_src), PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_INSERT_AFTER &&
+ "Unsupported RNA override operation on modifiers collection");
+
+ Object *ob_dst = (Object *)ptr_dst->id.data;
+ Object *ob_src = (Object *)ptr_src->id.data;
+
+ /* Remember that insertion operations are defined and stored in correct order, which means that
+ * even if we insert several items in a row, we alays insert first one, then second one, etc.
+ * So we should always find 'anchor' constraint in both _src *and* _dst> */
+ ModifierData *mod_anchor = NULL;
+ if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+ mod_anchor = BLI_findstring(&ob_dst->modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
+ }
+ if (mod_anchor == NULL && opop->subitem_local_index >= 0) {
+ mod_anchor = BLI_findlink(&ob_dst->modifiers, opop->subitem_local_index);
+ }
+ /* Otherwise we just insert in first position. */
+
+ ModifierData *mod_src = NULL;
+ if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+ mod_src = BLI_findstring(&ob_src->modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
+ }
+ if (mod_src == NULL && opop->subitem_local_index >= 0) {
+ mod_src = BLI_findlink(&ob_src->modifiers, opop->subitem_local_index);
+ }
+ mod_src = mod_src ? mod_src->next : ob_src->modifiers.first;
+
+ BLI_assert(mod_src != NULL);
+
+ ModifierData *mod_dst = modifier_new(mod_src->type);
+ modifier_copyData(mod_src, mod_dst);
+
+ /* This handles NULL anchor as expected by adding at head of list. */
+ BLI_insertlinkafter(&ob_dst->modifiers, mod_anchor, mod_dst);
+
+ /* This should actually *not* be needed in typical cases. However, if overridden source was edited,
+ * we *may* have some new conflicting names. */
+ modifier_unique_name(&ob_dst->modifiers, mod_dst);
+
+// printf("%s: We inserted a modifier...\n", __func__);
+ return true;
+}
+
+static GpencilModifierData *rna_Object_greasepencil_modifier_new(
+ Object *object, bContext *C, ReportList *reports,
+ const char *name, int type)
+{
+ return ED_object_gpencil_modifier_add(reports, CTX_data_main(C), CTX_data_scene(C), object, name, type);
+}
+
+static void rna_Object_greasepencil_modifier_remove(
+ Object *object, bContext *C, ReportList *reports, PointerRNA *gmd_ptr)
+{
+ GpencilModifierData *gmd = gmd_ptr->data;
+ if (ED_object_gpencil_modifier_remove(reports, CTX_data_main(C), object, gmd) == false) {
+ /* error is already set */
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(gmd_ptr);
+
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
+}
+
+static void rna_Object_greasepencil_modifier_clear(Object *object, bContext *C)
+{
+ ED_object_gpencil_modifier_clear(CTX_data_main(C), object);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
+}
+
+/* shader fx */
+static ShaderFxData *rna_Object_shaderfx_new(
+ Object *object, bContext *C, ReportList *reports,
+ const char *name, int type)
+{
+ return ED_object_shaderfx_add(reports, CTX_data_main(C), CTX_data_scene(C), object, name, type);
+}
+
+static void rna_Object_shaderfx_remove(
+ Object *object, bContext *C, ReportList *reports, PointerRNA *gmd_ptr)
+{
+ ShaderFxData *gmd = gmd_ptr->data;
+ if (ED_object_shaderfx_remove(reports, CTX_data_main(C), object, gmd) == false) {
+ /* error is already set */
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(gmd_ptr);
+
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
+}
+
+static void rna_Object_shaderfx_clear(Object *object, bContext *C)
+{
+ ED_object_shaderfx_clear(CTX_data_main(C), object);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
+}
+
static void rna_Object_boundbox_get(PointerRNA *ptr, float *values)
{
Object *ob = (Object *)ptr->id.data;
@@ -1476,6 +1495,69 @@ static float rna_VertexGroup_weight(ID *id, bDeformGroup *dg, ReportList *report
return weight;
}
+static bFaceMap *rna_Object_fmap_new(Object *ob, const char *name)
+{
+ bFaceMap *fmap = BKE_object_facemap_add_name(ob, name);
+
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+
+ return fmap;
+}
+
+static void rna_Object_fmap_remove(Object *ob, ReportList *reports, PointerRNA *fmap_ptr)
+{
+ bFaceMap *fmap = fmap_ptr->data;
+ if (BLI_findindex(&ob->fmaps, fmap) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "FaceMap '%s' not in object '%s'", fmap->name, ob->id.name + 2);
+ return;
+ }
+
+ BKE_object_facemap_remove(ob, fmap);
+ RNA_POINTER_INVALIDATE(fmap_ptr);
+
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+}
+
+
+static void rna_Object_fmap_clear(Object *ob)
+{
+ BKE_object_facemap_clear(ob);
+
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+}
+
+
+static void rna_FaceMap_face_add(ID *id, bFaceMap *fmap, ReportList *reports, int index_len,
+ int *index)
+{
+ Object *ob = (Object *)id;
+
+ if (BKE_object_is_in_editmode(ob)) {
+ BKE_report(reports, RPT_ERROR, "FaceMap.add(): cannot be called while object is in edit mode");
+ return;
+ }
+
+ while (index_len--)
+ ED_object_facemap_face_add(ob, fmap, *index++);
+
+ WM_main_add_notifier(NC_GEOM | ND_DATA, (ID *)ob->data);
+}
+
+static void rna_FaceMap_face_remove(ID *id, bFaceMap *fmap, ReportList *reports, int index_len, int *index)
+{
+ Object *ob = (Object *)id;
+
+ if (BKE_object_is_in_editmode(ob)) {
+ BKE_report(reports, RPT_ERROR, "FaceMap.add(): cannot be called while object is in edit mode");
+ return;
+ }
+
+ while (index_len--)
+ ED_object_facemap_face_remove(ob, fmap, *index++);
+
+ WM_main_add_notifier(NC_GEOM | ND_DATA, (ID *)ob->data);
+}
+
/* generic poll functions */
bool rna_Lattice_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
@@ -1502,33 +1584,22 @@ bool rna_Camera_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
return ((Object *)value.id.data)->type == OB_CAMERA;
}
-bool rna_Lamp_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+bool rna_Light_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
return ((Object *)value.id.data)->type == OB_LAMP;
}
-int rna_DupliObject_index_get(PointerRNA *ptr)
+bool rna_GPencil_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
- DupliObject *dob = (DupliObject *)ptr->data;
- return dob->persistent_id[0];
+ return ((Object *)value.id.data)->type == OB_GPENCIL;
}
-bool rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr)
+int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr)
{
SculptSession *ss = ((Object *)ptr->id.data)->sculpt;
return (ss && ss->bm);
}
-static void rna_Object_lod_distance_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Object *ob = (Object *)ptr->id.data;
-
-#ifdef WITH_GAMEENGINE
- BKE_object_lod_sort(ob);
-#else
- (void)ob;
-#endif
-}
#else
static void rna_def_vertex_group(BlenderRNA *brna)
@@ -1595,6 +1666,49 @@ static void rna_def_vertex_group(BlenderRNA *brna)
RNA_def_function_return(func, parm);
}
+static void rna_def_face_map(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+ FunctionRNA *func;
+
+ srna = RNA_def_struct(brna, "FaceMap", NULL);
+ RNA_def_struct_sdna(srna, "bFaceMap");
+ RNA_def_struct_ui_text(srna, "Face Map", "Group of faces, each face can only be part of one map");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_TRIANGULATE);
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "Face map name");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_FaceMap_name_set");
+ /* update data because modifiers may use [#24761] */
+ RNA_def_property_update(prop, NC_GEOM | ND_DATA | NA_RENAME, "rna_Object_internal_update_data");
+
+ prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT);
+ RNA_def_property_ui_text(prop, "Select", "Face-map selection state (for tools to use)");
+ /* important not to use a notifier here, creates a feedback loop! */
+
+ prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_int_funcs(prop, "rna_FaceMap_index_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Index", "Index number of the face map");
+
+ func = RNA_def_function(srna, "add", "rna_FaceMap_face_add");
+ RNA_def_function_ui_description(func, "Add vertices to the group");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
+ /* TODO, see how array size of 0 works, this shouldnt be used */
+ prop = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0);
+ RNA_def_parameter_flags(prop, PROP_DYNAMIC, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "remove", "rna_FaceMap_face_remove");
+ RNA_def_function_ui_description(func, "Remove a vertex from the group");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
+ /* TODO, see how array size of 0 works, this shouldnt be used */
+ prop = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0);
+ RNA_def_parameter_flags(prop, PROP_DYNAMIC, PARM_REQUIRED);
+}
+
static void rna_def_material_slot(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1614,19 +1728,24 @@ static void rna_def_material_slot(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Material Slot", "Material slot in an object");
RNA_def_struct_ui_icon(srna, ICON_MATERIAL_DATA);
- prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Material");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Material", "Material data-block used by this material slot");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
-
+ /* WARNING! Order is crucial for override to work properly here... :/
+ * 'link' must come before material pointer, since it defines where (in object or obdata) that one is set! */
prop = RNA_def_property(srna, "link", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, link_items);
RNA_def_property_enum_funcs(prop, "rna_MaterialSlot_link_get", "rna_MaterialSlot_link_set", NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Link", "Link material to object or the object's data");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Material");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_editable_func(prop, "rna_MaterialSlot_material_editable");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, "rna_MaterialSlot_material_poll");
+ RNA_def_property_ui_text(prop, "Material", "Material data-block used by this material slot");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
+
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_MaterialSlot_name_get", "rna_MaterialSlot_name_length", NULL);
RNA_def_property_ui_text(prop, "Name", "Material slot name");
@@ -1636,313 +1755,6 @@ static void rna_def_material_slot(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_MaterialSlot_path");
}
-static void rna_def_object_game_settings(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem body_type_items[] = {
- {OB_BODY_TYPE_NO_COLLISION, "NO_COLLISION", 0, "No Collision", "Disable collision for this object"},
- {OB_BODY_TYPE_STATIC, "STATIC", 0, "Static", "Stationary object"},
- {OB_BODY_TYPE_DYNAMIC, "DYNAMIC", 0, "Dynamic", "Linear physics"},
- {OB_BODY_TYPE_RIGID, "RIGID_BODY", 0, "Rigid Body", "Linear and angular physics"},
- {OB_BODY_TYPE_SOFT, "SOFT_BODY", 0, "Soft Body", "Soft body"},
- {OB_BODY_TYPE_OCCLUDER, "OCCLUDER", 0, "Occluder", "Occluder for optimizing scene rendering"},
- {OB_BODY_TYPE_SENSOR, "SENSOR", 0, "Sensor",
- "Collision Sensor, detects static and dynamic objects but not the other "
- "collision sensor objects"},
- {OB_BODY_TYPE_NAVMESH, "NAVMESH", 0, "Navigation Mesh", "Navigation mesh"},
- {OB_BODY_TYPE_CHARACTER, "CHARACTER", 0, "Character",
- "Simple kinematic physics appropriate for game characters"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "GameObjectSettings", NULL);
- RNA_def_struct_sdna(srna, "Object");
- RNA_def_struct_nested(brna, srna, "Object");
- RNA_def_struct_ui_text(srna, "Game Object Settings", "Game engine related settings for the object");
- RNA_def_struct_ui_icon(srna, ICON_GAME);
-
- /* logic */
-
- prop = RNA_def_property(srna, "sensors", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "Sensor");
- RNA_def_property_ui_text(prop, "Sensors", "Game engine sensor to detect events");
-
- prop = RNA_def_property(srna, "controllers", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "Controller");
- RNA_def_property_ui_text(prop, "Controllers",
- "Game engine controllers to process events, connecting sensors to actuators");
-
- prop = RNA_def_property(srna, "actuators", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "Actuator");
- RNA_def_property_ui_text(prop, "Actuators", "Game engine actuators to act on events");
-
- prop = RNA_def_property(srna, "properties", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "prop", NULL);
- RNA_def_property_struct_type(prop, "GameProperty"); /* rna_property.c */
- RNA_def_property_ui_text(prop, "Properties", "Game engine properties");
-
- prop = RNA_def_property(srna, "show_sensors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_SHOWSENS);
- RNA_def_property_ui_text(prop, "Show Sensors", "Shows sensors for this object in the user interface");
-
- prop = RNA_def_property(srna, "show_controllers", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_SHOWCONT);
- RNA_def_property_ui_text(prop, "Show Controllers", "Shows controllers for this object in the user interface");
-
- prop = RNA_def_property(srna, "show_actuators", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_SHOWACT);
- RNA_def_property_ui_text(prop, "Show Actuators", "Shows actuators for this object in the user interface");
-
- /* physics */
-
- prop = RNA_def_property(srna, "physics_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "body_type");
- RNA_def_property_enum_items(prop, body_type_items);
- RNA_def_property_enum_default(prop, OB_BODY_TYPE_STATIC);
- RNA_def_property_enum_funcs(prop, "rna_GameObjectSettings_physics_type_get",
- "rna_GameObjectSettings_physics_type_set", NULL);
- RNA_def_property_ui_text(prop, "Physics Type", "Select the type of physical representation");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_record_animation", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_RECORD_ANIMATION);
- RNA_def_property_ui_text(prop, "Record Animation", "Record animation objects without physics");
-
- prop = RNA_def_property(srna, "use_actor", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_ACTOR);
- RNA_def_property_ui_text(prop, "Actor", "Object is detected by the Near and Radar sensor");
-
- prop = RNA_def_property(srna, "use_ghost", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_GHOST);
- RNA_def_property_ui_text(prop, "Ghost", "Object does not react to collisions, like a ghost");
-
- prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.01, 10000.0);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Mass", "Mass of the object");
-
- prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "inertia");
- RNA_def_property_range(prop, 0.01f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.01f, 10.0f, 1, 3);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Radius", "Radius of bounding sphere and material physics");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "use_sleep", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_COLLISION_RESPONSE);
- RNA_def_property_ui_text(prop, "No Sleeping", "Disable auto (de)activation in physics simulation");
-
- prop = RNA_def_property(srna, "damping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "damping");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_default(prop, 0.04f);
- RNA_def_property_ui_text(prop, "Damping", "General movement damping");
-
- prop = RNA_def_property(srna, "rotation_damping", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "rdamping");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_default(prop, 0.1f);
- RNA_def_property_ui_text(prop, "Rotation Damping", "General rotation damping");
-
- prop = RNA_def_property(srna, "velocity_min", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "min_vel");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Velocity Min", "Clamp velocity to this minimum speed (except when totally still), "
- "in distance per second");
-
- prop = RNA_def_property(srna, "velocity_max", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "max_vel");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Velocity Max", "Clamp velocity to this maximum speed, "
- "in distance per second");
-
- prop = RNA_def_property(srna, "angular_velocity_min", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "min_angvel");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Angular Velocity Min",
- "Clamp angular velocity to this minimum speed (except when totally still), "
- "in angle per second");
-
- prop = RNA_def_property(srna, "angular_velocity_max", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "max_angvel");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Angular Velocity Max", "Clamp angular velocity to this maximum speed, "
- "in angle per second");
-
- /* Character physics */
- prop = RNA_def_property(srna, "step_height", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "step_height");
- RNA_def_property_range(prop, 0.01, 1.0);
- RNA_def_property_float_default(prop, 0.15f);
- RNA_def_property_ui_text(prop, "Step Height", "Maximum height of steps the character can run over");
-
- prop = RNA_def_property(srna, "jump_speed", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "jump_speed");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_float_default(prop, 10.0f);
- RNA_def_property_ui_text(prop, "Jump Force", "Upward velocity applied to the character when jumping");
-
- prop = RNA_def_property(srna, "fall_speed", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "fall_speed");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_float_default(prop, 55.0f);
- RNA_def_property_ui_text(prop, "Fall Speed Max", "Maximum speed at which the character will fall");
-
- prop = RNA_def_property(srna, "jump_max", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "max_jumps");
- RNA_def_property_range(prop, 1, CHAR_MAX);
- RNA_def_property_ui_range(prop, 1, 10, 1, 1);
- RNA_def_property_int_default(prop, 1);
- RNA_def_property_ui_text(prop, "Max Jumps",
- "The maximum number of jumps the character can make before it hits the ground");
-
- /* Collision Masks */
- prop = RNA_def_property(srna, "collision_group", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "col_group", 1);
- RNA_def_property_array(prop, OB_MAX_COL_MASKS);
- RNA_def_property_ui_text(prop, "Collision Group", "The collision group of the object");
- RNA_def_property_boolean_funcs(prop, "rna_GameObjectSettings_col_group_get", "rna_GameObjectSettings_col_group_set");
-
- prop = RNA_def_property(srna, "collision_mask", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "col_mask", 1);
- RNA_def_property_array(prop, OB_MAX_COL_MASKS);
- RNA_def_property_ui_text(prop, "Collision Mask", "The groups this object can collide with");
- RNA_def_property_boolean_funcs(prop, "rna_GameObjectSettings_col_mask_get", "rna_GameObjectSettings_col_mask_set");
-
- /* lock position */
- prop = RNA_def_property(srna, "lock_location_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag2", OB_LOCK_RIGID_BODY_X_AXIS);
- RNA_def_property_ui_text(prop, "Lock X Axis", "Disable simulation of linear motion along the X axis");
-
- prop = RNA_def_property(srna, "lock_location_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag2", OB_LOCK_RIGID_BODY_Y_AXIS);
- RNA_def_property_ui_text(prop, "Lock Y Axis", "Disable simulation of linear motion along the Y axis");
-
- prop = RNA_def_property(srna, "lock_location_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag2", OB_LOCK_RIGID_BODY_Z_AXIS);
- RNA_def_property_ui_text(prop, "Lock Z Axis", "Disable simulation of linear motion along the Z axis");
-
-
- /* lock rotation */
- prop = RNA_def_property(srna, "lock_rotation_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag2", OB_LOCK_RIGID_BODY_X_ROT_AXIS);
- RNA_def_property_ui_text(prop, "Lock X Rotation Axis", "Disable simulation of angular motion along the X axis");
-
- prop = RNA_def_property(srna, "lock_rotation_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag2", OB_LOCK_RIGID_BODY_Y_ROT_AXIS);
- RNA_def_property_ui_text(prop, "Lock Y Rotation Axis", "Disable simulation of angular motion along the Y axis");
-
- prop = RNA_def_property(srna, "lock_rotation_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag2", OB_LOCK_RIGID_BODY_Z_ROT_AXIS);
- RNA_def_property_ui_text(prop, "Lock Z Rotation Axis", "Disable simulation of angular motion along the Z axis");
-
- /* is this used anywhere ? */
- prop = RNA_def_property(srna, "use_activity_culling", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflag2", OB_NEVER_DO_ACTIVITY_CULLING);
- RNA_def_property_ui_text(prop, "Lock Z Rotation Axis", "Disable simulation of angular motion along the Z axis");
-
-
- prop = RNA_def_property(srna, "use_material_physics_fh", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_DO_FH);
- RNA_def_property_ui_text(prop, "Use Material Force Field", "React to force field physics settings in materials");
-
- prop = RNA_def_property(srna, "use_rotate_from_normal", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_ROT_FH);
- RNA_def_property_ui_text(prop, "Rotate From Normal",
- "Use face normal to rotate object, so that it points away from the surface");
-
- prop = RNA_def_property(srna, "form_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "formfactor");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_default(prop, 0.4f);
- RNA_def_property_ui_text(prop, "Form Factor", "Form factor scales the inertia tensor");
-
- prop = RNA_def_property(srna, "use_anisotropic_friction", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_ANISOTROPIC_FRICTION);
- RNA_def_property_ui_text(prop, "Anisotropic Friction", "Enable anisotropic friction");
-
- prop = RNA_def_property(srna, "friction_coefficients", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "anisotropicFriction");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_text(prop, "Friction Coefficients",
- "Relative friction coefficients in the in the X, Y and Z directions, "
- "when anisotropic friction is enabled");
-
- prop = RNA_def_property(srna, "use_collision_bounds", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_BOUNDS);
- RNA_def_property_ui_text(prop, "Use Collision Bounds", "Specify a collision bounds type other than the default");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "collision_bounds_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "collision_boundtype");
- RNA_def_property_enum_items(prop, collision_bounds_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Object_collision_bounds_itemf");
- RNA_def_property_ui_text(prop, "Collision Shape", "Select the collision shape that better fits the object");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
- prop = RNA_def_property(srna, "use_collision_compound", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_CHILD);
- RNA_def_property_ui_text(prop, "Collision Compound", "Add children to form a compound collision object");
-
- prop = RNA_def_property(srna, "collision_margin", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "margin");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_float_default(prop, 0.04f);
- RNA_def_property_ui_text(prop, "Collision Margin",
- "Extra margin around object for collision detection, small amount required "
- "for stability");
-
- prop = RNA_def_property(srna, "soft_body", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "bsoft");
- RNA_def_property_ui_text(prop, "Soft Body Settings", "Settings for Bullet soft body simulation");
-
- prop = RNA_def_property(srna, "use_obstacle_create", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_HASOBSTACLE);
- RNA_def_property_ui_text(prop, "Create obstacle", "Create representation for obstacle simulation");
-
- prop = RNA_def_property(srna, "obstacle_radius", PROP_FLOAT, PROP_NONE | PROP_UNIT_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "obstacleRad");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Obstacle Radius", "Radius of object representation in obstacle simulation");
-
- /* state */
-
- prop = RNA_def_property(srna, "states_visible", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "state", 1);
- RNA_def_property_array(prop, OB_MAX_STATES);
- RNA_def_property_ui_text(prop, "State", "State determining which controllers are displayed");
- RNA_def_property_boolean_funcs(prop, "rna_GameObjectSettings_state_get", "rna_GameObjectSettings_state_set");
-
- prop = RNA_def_property(srna, "used_states", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_array(prop, OB_MAX_STATES);
- RNA_def_property_ui_text(prop, "Used State", "States which are being used by controllers");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_boolean_funcs(prop, "rna_GameObjectSettings_used_state_get", NULL);
-
- prop = RNA_def_property(srna, "states_initial", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "init_state", 1);
- RNA_def_property_array(prop, OB_MAX_STATES);
- RNA_def_property_ui_text(prop, "Initial State", "Initial state when the game starts");
-
- prop = RNA_def_property(srna, "show_debug_state", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_DEBUGSTATE);
- RNA_def_property_ui_text(prop, "Debug State", "Print state debug info in the game engine");
- RNA_def_property_ui_icon(prop, ICON_INFO, 0);
-
- prop = RNA_def_property(srna, "use_all_states", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_ALLSTATE);
- RNA_def_property_ui_text(prop, "All", "Set all state bits");
-
- prop = RNA_def_property(srna, "show_state_panel", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_SHOWSTATE);
- RNA_def_property_ui_text(prop, "States", "Show state panel");
- RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
-}
-
static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -2044,6 +1856,88 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Remove all modifiers from the object");
}
+/* object.grease_pencil_modifiers */
+static void rna_def_object_grease_pencil_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "ObjectGpencilModifiers");
+ srna = RNA_def_struct(brna, "ObjectGpencilModifiers", NULL);
+ RNA_def_struct_sdna(srna, "Object");
+ RNA_def_struct_ui_text(srna, "Object Grease Pencil Modifiers", "Collection of object grease pencil modifiers");
+
+ /* add greasepencil modifier */
+ func = RNA_def_function(srna, "new", "rna_Object_greasepencil_modifier_new");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Add a new greasepencil_modifier");
+ parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the greasepencil_modifier");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* greasepencil_modifier to add */
+ parm = RNA_def_enum(func, "type", rna_enum_object_greasepencil_modifier_type_items, 1, "", "Modifier type to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "greasepencil_modifier", "GpencilModifier", "", "Newly created modifier");
+ RNA_def_function_return(func, parm);
+
+ /* remove greasepencil_modifier */
+ func = RNA_def_function(srna, "remove", "rna_Object_greasepencil_modifier_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove an existing greasepencil_modifier from the object");
+ /* greasepencil_modifier to remove */
+ parm = RNA_def_pointer(func, "greasepencil_modifier", "GpencilModifier", "", "Modifier to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ /* clear all greasepencil modifiers */
+ func = RNA_def_function(srna, "clear", "rna_Object_greasepencil_modifier_clear");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Remove all grease pencil modifiers from the object");
+}
+
+/* object.shaderfxs */
+static void rna_def_object_shaderfxs(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "ObjectShaderFx");
+ srna = RNA_def_struct(brna, "ObjectShaderFx", NULL);
+ RNA_def_struct_sdna(srna, "Object");
+ RNA_def_struct_ui_text(srna, "Object Shader Effects", "Collection of object effects");
+
+ /* add shader_fx */
+ func = RNA_def_function(srna, "new", "rna_Object_shaderfx_new");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Add a new shader fx");
+ parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the effect");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* shader to add */
+ parm = RNA_def_enum(func, "type", rna_enum_object_shaderfx_type_items, 1, "", "Effect type to add");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "shader_fx", "ShaderFx", "", "Newly created effect");
+ RNA_def_function_return(func, parm);
+
+ /* remove shader_fx */
+ func = RNA_def_function(srna, "remove", "rna_Object_shaderfx_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove an existing effect from the object");
+ /* shader to remove */
+ parm = RNA_def_pointer(func, "shader_fx", "ShaderFx", "", "Effect to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ /* clear all shader fx */
+ func = RNA_def_function(srna, "clear", "rna_Object_shaderfx_clear");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Remove all effects from the object");
+}
+
/* object.particle_systems */
static void rna_def_object_particle_systems(BlenderRNA *brna, PropertyRNA *cprop)
{
@@ -2124,54 +2018,71 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Delete all vertex groups from object");
}
-
-static void rna_def_object_lodlevel(BlenderRNA *brna)
+/* object.face_maps */
+static void rna_def_object_face_maps(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
+
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "LodLevel", NULL);
- RNA_def_struct_sdna(srna, "LodLevel");
-
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "distance");
- RNA_def_property_range(prop, 0.0, FLT_MAX);
- RNA_def_property_ui_text(prop, "Distance", "Distance to begin using this level of detail");
- RNA_def_property_update(prop, NC_OBJECT | ND_LOD, "rna_Object_lod_distance_update");
-
- prop = RNA_def_property(srna, "object_hysteresis_percentage", PROP_INT, PROP_PERCENTAGE);
- RNA_def_property_int_sdna(prop, NULL, "obhysteresis");
- RNA_def_property_range(prop, 0, 100);
- RNA_def_property_ui_range(prop, 0, 100, 10, 1);
- RNA_def_property_ui_text(prop, "Hysteresis %",
- "Minimum distance change required to transition to the previous level of detail");
- RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "source");
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Object", "Object to use for this level of detail");
- RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "FaceMaps");
+ srna = RNA_def_struct(brna, "FaceMaps", NULL);
+ RNA_def_struct_sdna(srna, "Object");
+ RNA_def_struct_ui_text(srna, "Face Maps", "Collection of face maps");
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "FaceMap");
+ RNA_def_property_pointer_funcs(prop, "rna_Object_active_face_map_get",
+ "rna_Object_active_face_map_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Face Map", "Face maps of the object");
+ RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_Object_internal_update_data");
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_sdna(prop, NULL, "actfmap");
+ RNA_def_property_int_funcs(prop, "rna_Object_active_face_map_index_get",
+ "rna_Object_active_face_map_index_set",
+ "rna_Object_active_face_map_index_range");
+ RNA_def_property_ui_text(prop, "Active Face Map Index", "Active index in face map array");
+ RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_Object_internal_update_data");
- prop = RNA_def_property(srna, "use_mesh", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_LOD_USE_MESH);
- RNA_def_property_ui_text(prop, "Use Mesh", "Use the mesh from this object at this level of detail");
- RNA_def_property_ui_icon(prop, ICON_MESH_DATA, 0);
- RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
+ /* face maps */ /* add_face_map */
+ func = RNA_def_function(srna, "new", "rna_Object_fmap_new");
+ RNA_def_function_ui_description(func, "Add face map to object");
+ RNA_def_string(func, "name", "Map", 0, "", "face map name"); /* optional */
+ parm = RNA_def_pointer(func, "fmap", "FaceMap", "", "New face map");
+ RNA_def_function_return(func, parm);
- prop = RNA_def_property(srna, "use_material", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_LOD_USE_MAT);
- RNA_def_property_ui_text(prop, "Use Material", "Use the material from this object at this level of detail");
- RNA_def_property_ui_icon(prop, ICON_MATERIAL, 0);
- RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
+ func = RNA_def_function(srna, "remove", "rna_Object_fmap_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Delete vertex group from object");
+ parm = RNA_def_pointer(func, "group", "FaceMap", "", "Face map to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
- prop = RNA_def_property(srna, "use_object_hysteresis", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_LOD_USE_HYST);
- RNA_def_property_ui_text(prop, "Hysteresis Override", "Override LoD Hysteresis scene setting for this LoD level");
- RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
+ func = RNA_def_function(srna, "clear", "rna_Object_fmap_clear");
+ RNA_def_function_ui_description(func, "Delete all vertex groups from object");
}
+static void rna_def_object_display(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ObjectDisplay", NULL);
+ RNA_def_struct_ui_text(srna, "Object Display", "Object display settings for 3d viewport");
+ RNA_def_struct_sdna(srna, "ObjectDisplay");
+ RNA_def_struct_path_func(srna, "rna_ObjectDisplay_path");
+
+ prop = RNA_def_property(srna, "show_shadows", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_SHOW_SHADOW);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Shadow", "Object cast shadows in the 3d viewport");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+}
static void rna_def_object(BlenderRNA *brna)
{
@@ -2186,20 +2097,20 @@ static void rna_def_object(BlenderRNA *brna)
};
static const EnumPropertyItem drawtype_items[] = {
- {OB_BOUNDBOX, "BOUNDS", 0, "Bounds", "Draw the bounds of the object"},
- {OB_WIRE, "WIRE", 0, "Wire", "Draw the object as a wireframe"},
- {OB_SOLID, "SOLID", 0, "Solid", "Draw the object as a solid (if solid drawing is enabled in the viewport)"},
+ {OB_BOUNDBOX, "BOUNDS", 0, "Bounds", "Display the bounds of the object"},
+ {OB_WIRE, "WIRE", 0, "Wire", "Display the object as a wireframe"},
+ {OB_SOLID, "SOLID", 0, "Solid", "Display the object as a solid (if solid drawing is enabled in the viewport)"},
{OB_TEXTURE, "TEXTURED", 0, "Textured",
- "Draw the object with textures (if textures are enabled in the viewport)"},
+ "Display the object with textures (if textures are enabled in the viewport)"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem boundtype_items[] = {
- {OB_BOUND_BOX, "BOX", 0, "Box", "Draw bounds as box"},
- {OB_BOUND_SPHERE, "SPHERE", 0, "Sphere", "Draw bounds as sphere"},
- {OB_BOUND_CYLINDER, "CYLINDER", 0, "Cylinder", "Draw bounds as cylinder"},
- {OB_BOUND_CONE, "CONE", 0, "Cone", "Draw bounds as cone"},
- {OB_BOUND_CAPSULE, "CAPSULE", 0, "Capsule", "Draw bounds as capsule"},
+ {OB_BOUND_BOX, "BOX", 0, "Box", "Display bounds as box"},
+ {OB_BOUND_SPHERE, "SPHERE", 0, "Sphere", "Display bounds as sphere"},
+ {OB_BOUND_CYLINDER, "CYLINDER", 0, "Cylinder", "Display bounds as cylinder"},
+ {OB_BOUND_CONE, "CONE", 0, "Cone", "Display bounds as cone"},
+ {OB_BOUND_CAPSULE, "CAPSULE", 0, "Capsule", "Display bounds as capsule"},
{0, NULL, 0, NULL, NULL}
};
@@ -2231,8 +2142,9 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "data", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", NULL);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", "rna_Object_data_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Data", "Object data");
RNA_def_property_update(prop, 0, "rna_Object_internal_update_data");
@@ -2248,26 +2160,6 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mode", "Object interaction mode");
- prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_ui_text(prop, "Layers", "Layers the object is on");
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Object_layer_set");
- RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_layer_update");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "layers_local_view", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay", 0x01000000);
- RNA_def_property_array(prop, 8);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Local View Layers", "3D local view layers the object is on");
-
- prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT);
- RNA_def_property_ui_text(prop, "Select", "Object selection state");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_select_update");
-
/* for data access */
prop = RNA_def_property(srna, "bound_box", PROP_FLOAT, PROP_NONE);
RNA_def_property_multi_array(prop, 2, boundbox_dimsize);
@@ -2281,6 +2173,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_parent_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Parent", "Parent Object");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
@@ -2310,7 +2203,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "trackflag");
RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
RNA_def_property_ui_text(prop, "Track Axis",
- "Axis that points in 'forward' direction (applies to DupliFrame when "
+ "Axis that points in 'forward' direction (applies to InstanceFrame when "
"parent 'Follow' is enabled)");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
@@ -2318,7 +2211,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "upflag");
RNA_def_property_enum_items(prop, up_items);
RNA_def_property_ui_text(prop, "Up Axis",
- "Axis that points in the upward direction (applies to DupliFrame when "
+ "Axis that points in the upward direction (applies to InstanceFrame when "
"parent 'Follow' is enabled)");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
@@ -2326,13 +2219,15 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "proxy", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Proxy", "Library object this proxy object controls");
- prop = RNA_def_property(srna, "proxy_group", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "Proxy Group", "Library group duplicator object this proxy object controls");
+ prop = RNA_def_property(srna, "proxy_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "proxy_group");
+ RNA_def_property_ui_text(prop, "Proxy Collection", "Library collection duplicator object this proxy object controls");
/* materials */
prop = RNA_def_property(srna, "material_slots", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
RNA_def_property_struct_type(prop, "MaterialSlot");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_NO_PROP_NAME);
/* don't dereference pointer! */
RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_iterator_array_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Material Slots", "Material slots in the object");
@@ -2340,8 +2235,10 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_material", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Material");
RNA_def_property_pointer_funcs(prop, "rna_Object_active_material_get",
- "rna_Object_active_material_set", NULL, NULL);
+ "rna_Object_active_material_set", NULL,
+ "rna_MaterialSlot_material_poll");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_func(prop, "rna_Object_active_material_editable");
RNA_def_property_ui_text(prop, "Active Material", "Active material being displayed");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
@@ -2349,15 +2246,17 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_material_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "actcol");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_int_funcs(prop, "rna_Object_active_material_index_get", "rna_Object_active_material_index_set",
"rna_Object_active_material_index_range");
RNA_def_property_ui_text(prop, "Active Material Index", "Index of active material slot");
- RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_MaterialIndex_update");
/* transform */
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_editable_array_func(prop, "rna_Object_location_editable");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Location", "Location of the object");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2365,6 +2264,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "quat");
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_float_array_default(prop, default_quat);
RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2378,12 +2278,14 @@ static void rna_def_object(BlenderRNA *brna)
"rna_Object_rotation_axis_angle_set", NULL);
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable");
RNA_def_property_float_array_default(prop, default_axisAngle);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "rot");
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_euler_editable");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2397,6 +2299,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_Object_scale_editable");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
RNA_def_property_float_array_default(prop, default_scale);
@@ -2523,22 +2426,33 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Modifier");
RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting the geometric data of the object");
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_modifiers_override_apply");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION);
rna_def_object_modifiers(brna, prop);
+ /* Grease Pencil modifiers. */
+ prop = RNA_def_property(srna, "grease_pencil_modifiers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "greasepencil_modifiers", NULL);
+ RNA_def_property_struct_type(prop, "GpencilModifier");
+ RNA_def_property_ui_text(prop, "Grease Pencil Modifiers", "Modifiers affecting the data of the grease pencil object");
+ rna_def_object_grease_pencil_modifiers(brna, prop);
+
+ /* Shader FX. */
+ prop = RNA_def_property(srna, "shader_effects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "shader_fx", NULL);
+ RNA_def_property_struct_type(prop, "ShaderFx");
+ RNA_def_property_ui_text(prop, "Shader Effects", "Effects affecting display of object");
+ rna_def_object_shaderfxs(brna, prop);
+
/* constraints */
prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Constraint");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION);
RNA_def_property_ui_text(prop, "Constraints", "Constraints affecting the transformation of the object");
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_constraints_override_apply");
/* RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "constraints__add", "constraints__remove"); */
rna_def_object_constraints(brna, prop);
- /* game engine */
- prop = RNA_def_property(srna, "game", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "GameObjectSettings");
- RNA_def_property_pointer_funcs(prop, "rna_Object_game_settings_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Game Settings", "Game engine related settings for the object");
-
/* vertex groups */
prop = RNA_def_property(srna, "vertex_groups", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "defbase", NULL);
@@ -2546,15 +2460,23 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Vertex Groups", "Vertex groups of the object");
rna_def_object_vertex_groups(brna, prop);
+
+ /* face maps */
+ prop = RNA_def_property(srna, "face_maps", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "fmaps", NULL);
+ RNA_def_property_struct_type(prop, "FaceMap");
+ RNA_def_property_ui_text(prop, "Face Maps", "Maps of faces of the object");
+ rna_def_object_face_maps(brna, prop);
+
/* empty */
- prop = RNA_def_property(srna, "empty_draw_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "empty_display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "empty_drawtype");
RNA_def_property_enum_items(prop, rna_enum_object_empty_drawtype_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Object_empty_draw_type_set", NULL);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_Object_empty_display_type_set", NULL);
RNA_def_property_ui_text(prop, "Empty Display Type", "Viewport display style for empties");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
- prop = RNA_def_property(srna, "empty_draw_size", PROP_FLOAT, PROP_DISTANCE);
+ prop = RNA_def_property(srna, "empty_display_size", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "empty_drawsize");
RNA_def_property_range(prop, 0.0001f, 1000.0f);
RNA_def_property_ui_range(prop, 0.01, 100, 1, 2);
@@ -2574,6 +2496,26 @@ static void rna_def_object(BlenderRNA *brna)
"Parameters defining which layer, pass and frame of the image is displayed");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "empty_image_depth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_object_empty_image_depth_items);
+ RNA_def_property_ui_text(prop, "Empty Image Depth", "Determine which other objects will occlude the image");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "show_empty_image_perspective", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "empty_image_visibility_flag", OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE);
+ RNA_def_property_ui_text(prop, "Display in Perspective Mode", "Display image in perspective mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "show_empty_image_orthographic", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "empty_image_visibility_flag", OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC);
+ RNA_def_property_ui_text(prop, "Display in Orthographic Mode", "Display image in orthographic mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "show_empty_image_backside", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "empty_image_visibility_flag", OB_EMPTY_IMAGE_VISIBLE_BACKSIDE);
+ RNA_def_property_ui_text(prop, "Display Back Side", "Display empty image even when viewed from the back");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
/* render */
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "index");
@@ -2622,24 +2564,35 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rigid Body Constraint", "Constraint constraining rigid bodies");
/* restrict */
- prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_VIEW);
- RNA_def_property_ui_text(prop, "Restrict View", "Restrict visibility in the viewport");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Disable View", "Disable object in the viewport");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update");
prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_SELECT);
- RNA_def_property_ui_text(prop, "Restrict Select", "Restrict selection in the viewport");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1);
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Disable Select", "Disable object selection in the viewport");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, -1);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update");
prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "restrictflag", OB_RESTRICT_RENDER);
- RNA_def_property_ui_text(prop, "Restrict Render", "Restrict renderability");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Disable Render", "Disable object in renders");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update");
+ prop = RNA_def_property(srna, "show_instancer_for_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_RENDER);
+ RNA_def_property_ui_text(prop, "Render Instancer", "Make instancer visible when rendering");
+
+ prop = RNA_def_property(srna, "show_instancer_for_viewport", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_VIEWPORT);
+ RNA_def_property_ui_text(prop, "Display Instancer", "Make instancer visible in the viewport");
+
/* anim */
rna_def_animdata_common(srna);
@@ -2661,148 +2614,139 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Slow Parent Offset", "Delay in the parent relationship");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
- /* depsgraph hack */
- prop = RNA_def_property(srna, "use_extra_recalc_object", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "depsflag", OB_DEPS_EXTRA_OB_RECALC);
- RNA_def_property_ui_text(prop, "Extra Object Update", "Refresh this object again on frame changes, dependency graph hack");
-
- prop = RNA_def_property(srna, "use_extra_recalc_data", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "depsflag", OB_DEPS_EXTRA_DATA_RECALC);
- RNA_def_property_ui_text(prop, "Extra Data Update", "Refresh this object's data again on frame changes, dependency graph hack");
-
- /* duplicates */
- prop = RNA_def_property(srna, "dupli_type", PROP_ENUM, PROP_NONE);
+ /* instancing */
+ prop = RNA_def_property(srna, "instance_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "transflag");
- RNA_def_property_enum_items(prop, dupli_items);
- RNA_def_property_ui_text(prop, "Dupli Type", "If not None, object duplication method to use");
+ RNA_def_property_enum_items(prop, instance_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Object_instance_type_itemf");
+ RNA_def_property_ui_text(prop, "Instance Type", "If not None, object instancing method to use");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
- prop = RNA_def_property(srna, "use_dupli_frames_speed", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_instance_frames_speed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "transflag", OB_DUPLINOSPEED);
- RNA_def_property_ui_text(prop, "Dupli Frames Speed",
- "Set dupliframes to use the current frame instead of parent curve's evaluation time");
+ RNA_def_property_ui_text(prop, "Instance Frames Speed",
+ "Set frames instancing to use the current frame instead of parent curve's evaluation time");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
- prop = RNA_def_property(srna, "use_dupli_vertices_rotation", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_instance_vertices_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transflag", OB_DUPLIROT);
- RNA_def_property_ui_text(prop, "Dupli Verts Rotation", "Rotate dupli according to vertex normal");
+ RNA_def_property_ui_text(prop, "Instance Verts Rotation", "Rotate instance according to vertex normal");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
- prop = RNA_def_property(srna, "use_dupli_faces_scale", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_instance_faces_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transflag", OB_DUPLIFACES_SCALE);
- RNA_def_property_ui_text(prop, "Dupli Faces Inherit Scale", "Scale dupli based on face size");
+ RNA_def_property_ui_text(prop, "Instance Faces Inherit Scale", "Scale instance based on face size");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
- prop = RNA_def_property(srna, "dupli_faces_scale", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "instance_faces_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "dupfacesca");
RNA_def_property_range(prop, 0.001f, 10000.0f);
- RNA_def_property_ui_text(prop, "Dupli Faces Scale", "Scale the DupliFace objects");
+ RNA_def_property_ui_text(prop, "Instance Faces Scale", "Scale the face instance objects");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
- prop = RNA_def_property(srna, "dupli_group", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "instance_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_pointer_sdna(prop, NULL, "dup_group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_dup_group_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Dupli Group", "Instance an existing group");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_dup_collection_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Instance Collection", "Instance an existing collection");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
- prop = RNA_def_property(srna, "dupli_frames_start", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
+ prop = RNA_def_property(srna, "instance_frames_start", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
RNA_def_property_int_sdna(prop, NULL, "dupsta");
RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
- RNA_def_property_ui_text(prop, "Dupli Frames Start", "Start frame for DupliFrames");
+ RNA_def_property_ui_text(prop, "Instance Frames Start", "Start frame for frame instances");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
- prop = RNA_def_property(srna, "dupli_frames_end", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
+ prop = RNA_def_property(srna, "instance_frames_end", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
RNA_def_property_int_sdna(prop, NULL, "dupend");
RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
- RNA_def_property_ui_text(prop, "Dupli Frames End", "End frame for DupliFrames");
+ RNA_def_property_ui_text(prop, "Instance Frames End", "End frame for frame instances");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
- prop = RNA_def_property(srna, "dupli_frames_on", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
+ prop = RNA_def_property(srna, "instance_frames_on", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
RNA_def_property_int_sdna(prop, NULL, "dupon");
RNA_def_property_range(prop, 1, MAXFRAME);
RNA_def_property_ui_range(prop, 1, 1500, 1, -1);
- RNA_def_property_ui_text(prop, "Dupli Frames On", "Number of frames to use between DupOff frames");
+ RNA_def_property_ui_text(prop, "Instance Frames On", "Number of frames to use between DupOff frames");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
- prop = RNA_def_property(srna, "dupli_frames_off", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
+ prop = RNA_def_property(srna, "instance_frames_off", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
RNA_def_property_int_sdna(prop, NULL, "dupoff");
RNA_def_property_range(prop, 0, MAXFRAME);
RNA_def_property_ui_range(prop, 0, 1500, 1, -1);
- RNA_def_property_ui_text(prop, "Dupli Frames Off", "Recurring frames to exclude from the Dupliframes");
+ RNA_def_property_ui_text(prop, "Instance Frames Off", "Recurring frames to exclude from the frame instances");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
- prop = RNA_def_property(srna, "dupli_list", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "duplilist", NULL);
- RNA_def_property_struct_type(prop, "DupliObject");
- RNA_def_property_ui_text(prop, "Dupli list", "Object duplis");
-
- prop = RNA_def_property(srna, "is_duplicator", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "is_instancer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transflag", OB_DUPLI);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* drawing */
- prop = RNA_def_property(srna, "draw_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dt");
RNA_def_property_enum_items(prop, drawtype_items);
- RNA_def_property_ui_text(prop, "Maximum Draw Type", "Maximum draw type to display object with in viewport");
+ RNA_def_property_ui_text(prop, "Display As", "How to display object in viewport");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
prop = RNA_def_property(srna, "show_bounds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWBOUNDOX);
- RNA_def_property_ui_text(prop, "Draw Bounds", "Display the object's bounds");
+ RNA_def_property_ui_text(prop, "Display Bounds", "Display the object's bounds");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
- prop = RNA_def_property(srna, "draw_bounds_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_bounds_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "boundtype");
RNA_def_property_enum_items(prop, boundtype_items);
- RNA_def_property_ui_text(prop, "Draw Bounds Type", "Object boundary display type");
+ RNA_def_property_ui_text(prop, "Display Bounds Type", "Object boundary display type");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_name", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWNAME);
- RNA_def_property_ui_text(prop, "Draw Name", "Display the object's name");
+ RNA_def_property_ui_text(prop, "Display Name", "Display the object's name");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_axis", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_AXIS);
- RNA_def_property_ui_text(prop, "Draw Axes", "Display the object's origin and axes");
+ RNA_def_property_ui_text(prop, "Display Axes", "Display the object's origin and axes");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_texture_space", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_TEXSPACE);
- RNA_def_property_ui_text(prop, "Draw Texture Space", "Display the object's texture space");
+ RNA_def_property_ui_text(prop, "Display Texture Space", "Display the object's texture space");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWWIRE);
- RNA_def_property_ui_text(prop, "Draw Wire", "Add the object's wireframe over solid drawing");
+ RNA_def_property_ui_text(prop, "Display Wire", "Add the object's wireframe over solid drawing");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_all_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAW_ALL_EDGES);
- RNA_def_property_ui_text(prop, "Draw All Edges", "Display all edges for mesh objects");
+ RNA_def_property_ui_text(prop, "Display All Edges", "Display all edges for mesh objects");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "show_transparent", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWTRANSP);
- RNA_def_property_ui_text(prop, "Draw Transparent",
- "Display material transparency in the object (unsupported for duplicator drawing)");
+ RNA_def_property_ui_text(prop, "Display Transparent",
+ "Display material transparency in the object");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
- prop = RNA_def_property(srna, "show_x_ray", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_in_front", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWXRAY);
- RNA_def_property_ui_text(prop, "X-Ray",
- "Make the object draw in front of others (unsupported for duplicator drawing)");
+ RNA_def_property_ui_text(prop, "In Front",
+ "Make the object draw in front of others");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
/* Grease Pencil */
+#if 1 /* FIXME: Remove this code when all Open-Movie assets have been fixed */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_obdata_poll"); /* XXX */
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
+ RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block (deprecated)");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+#endif
/* pose */
prop = RNA_def_property(srna, "pose_library", PROP_POINTER, PROP_NONE);
@@ -2814,6 +2758,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "pose");
RNA_def_property_struct_type(prop, "Pose");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Pose", "Current pose for armatures");
/* shape keys */
@@ -2836,6 +2781,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_shape_key_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "shapenr");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); /* XXX this is really unpredictable... */
RNA_def_property_int_funcs(prop, "rna_Object_active_shape_key_index_get", "rna_Object_active_shape_key_index_set",
"rna_Object_active_shape_key_index_range");
@@ -2848,108 +2794,24 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dynamic Topology Sculpting", NULL);
- /* Levels of Detail */
- prop = RNA_def_property(srna, "lod_levels", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "lodlevels", NULL);
- RNA_def_property_struct_type(prop, "LodLevel");
- RNA_def_property_ui_text(prop, "Level of Detail Levels", "A collection of detail levels to automatically switch between");
- RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL);
-
- RNA_api_object(srna);
-}
-
-static void rna_def_dupli_object(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "DupliObject", NULL);
- RNA_def_struct_sdna(srna, "DupliObject");
- RNA_def_struct_ui_text(srna, "Object Duplicate", "An object duplicate");
- /* RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA); */
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "ob");
- /* RNA_def_property_pointer_funcs(prop, "rna_DupliObject_object_get", NULL, NULL, NULL); */
- RNA_def_property_ui_text(prop, "Object", "Object being duplicated");
-
- prop = RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX);
- RNA_def_property_float_sdna(prop, NULL, "mat");
- RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Object Duplicate Matrix", "Object duplicate transformation matrix");
-
- prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "no_draw", 0);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Hide", "Don't show dupli object in viewport or render");
-
- prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
- RNA_def_property_int_funcs(prop, "rna_DupliObject_index_get", NULL, NULL);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Index", "Index in the lowest-level dupli list");
-
- prop = RNA_def_property(srna, "persistent_id", PROP_INT, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Persistent ID", "Persistent identifier for inter-frame matching of objects with motion blur");
-
- prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Particle System", "Particle system that this dupli object was instanced from");
-
- prop = RNA_def_property(srna, "orco", PROP_FLOAT, PROP_TRANSLATION);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Generated Coordinates", "Generated coordinates in parent object space");
-
- prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 2);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "UV Coordinates", "UV coordinates in parent object space");
-
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, dupli_items);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object");
-
- prop = RNA_def_property(srna, "random_id", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Dupli random id", "Random id for this dupli object");
-}
-
-static void rna_def_object_base(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ObjectBase", NULL);
- RNA_def_struct_sdna(srna, "Base");
- RNA_def_struct_ui_text(srna, "Object Base", "An object instance in a scene");
- RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA);
+ /* Base Settings */
+ prop = RNA_def_property(srna, "is_from_instancer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "base_flag", BASE_FROMDUPLI);
+ RNA_def_property_ui_text(prop, "Base from Instancer", "Object comes from a instancer");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "object");
- RNA_def_property_ui_text(prop, "Object", "Object this base links to");
-
- /* same as object layer */
- prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_ui_text(prop, "Layers", "Layers the object base is on");
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Base_layer_set");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Base_layer_update");
-
- prop = RNA_def_property(srna, "layers_local_view", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay", 0x01000000);
- RNA_def_property_array(prop, 8);
+ prop = RNA_def_property(srna, "is_from_set", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "base_flag", BASE_FROM_SET);
+ RNA_def_property_ui_text(prop, "Base from Set", "Object comes from a background set");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Local View Layers", "3D local view layers the object base is on");
- prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", BA_SELECT);
- RNA_def_property_ui_text(prop, "Select", "Object base selection state");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Base_select_update");
+ /* Object Display */
+ prop = RNA_def_property(srna, "display", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "display");
+ RNA_def_property_struct_type(prop, "ObjectDisplay");
+ RNA_def_property_ui_text(prop, "Object Display", "Object display settings for 3d viewport");
- RNA_api_object_base(srna);
+ RNA_api_object(srna);
}
void RNA_def_object(BlenderRNA *brna)
@@ -2957,13 +2819,11 @@ void RNA_def_object(BlenderRNA *brna)
rna_def_object(brna);
RNA_define_animate_sdna(false);
- rna_def_object_game_settings(brna);
- rna_def_object_base(brna);
rna_def_vertex_group(brna);
+ rna_def_face_map(brna);
rna_def_material_slot(brna);
- rna_def_dupli_object(brna);
+ rna_def_object_display(brna);
RNA_define_animate_sdna(true);
- rna_def_object_lodlevel(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 6218de2469d..ad375449439 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -40,10 +40,13 @@
#include "RNA_define.h"
#include "DNA_constraint_types.h"
+#include "DNA_layer_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
#include "rna_internal.h" /* own include */
@@ -65,7 +68,6 @@ static const EnumPropertyItem space_items[] = {
#include "BKE_anim.h"
#include "BKE_bvhutils.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -86,9 +88,90 @@ static const EnumPropertyItem space_items[] = {
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
+#include "DEG_depsgraph_query.h"
+
#include "MEM_guardedalloc.h"
-#include "DEG_depsgraph.h"
+static void rna_Object_select_set(
+ Object *ob, bContext *C, ReportList *reports,
+ bool select, ViewLayer *view_layer)
+{
+ if (view_layer == NULL) {
+ view_layer = CTX_data_view_layer(C);
+ }
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (!base) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name);
+ return;
+ }
+
+ if (select) {
+ BKE_view_layer_base_select(base);
+ }
+ else {
+ base->flag &= ~BASE_SELECTED;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
+ WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
+}
+
+static bool rna_Object_select_get(Object *ob, bContext *C, ReportList *reports)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (!base) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name);
+ return false;
+ }
+
+ return ((base->flag & BASE_SELECTED) != 0);
+}
+
+static bool rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (!base) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name);
+ return false;
+ }
+
+ if (v3d && v3d->localvd && ((base->local_view_bits & v3d->local_view_uuid) == 0)) {
+ return false;
+ }
+
+ return ((base->flag & BASE_VISIBLE) != 0);
+}
+
+static bool rna_Object_holdout_get(Object *ob, ReportList *reports, ViewLayer *view_layer)
+{
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (!base) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name);
+ return false;
+ }
+
+ return ((base->flag & BASE_HOLDOUT) != 0);
+}
+
+static bool rna_Object_indirect_only_get(Object *ob, ReportList *reports, ViewLayer *view_layer)
+{
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+
+ if (!base) {
+ BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name);
+ return false;
+ }
+
+ return ((base->flag & BASE_INDIRECT_ONLY) != 0);
+}
/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
static void rna_Object_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
@@ -116,13 +199,14 @@ static void rna_Object_mat_convert_space(Object *ob, ReportList *reports, bPoseC
}
static void rna_Object_calc_matrix_camera(
- Object *ob, float mat_ret[16], int width, int height, float scalex, float scaley)
+ Object *ob, Depsgraph *depsgraph, float mat_ret[16], int width, int height, float scalex, float scaley)
{
+ const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
CameraParams params;
/* setup parameters */
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, ob);
+ BKE_camera_params_from_object(&params, ob_eval);
/* compute matrix, viewplane, .. */
BKE_camera_params_compute_viewplane(&params, width, height, scalex, scaley);
@@ -132,97 +216,20 @@ static void rna_Object_calc_matrix_camera(
}
static void rna_Object_camera_fit_coords(
- Object *ob, Scene *scene, int num_cos, float *cos, float co_ret[3], float *scale_ret)
+ Object *ob, Depsgraph *depsgraph, int num_cos, float *cos, float co_ret[3], float *scale_ret)
{
- BKE_camera_view_frame_fit_to_coords(scene, (const float (*)[3])cos, num_cos / 3, ob, co_ret, scale_ret);
+ BKE_camera_view_frame_fit_to_coords(depsgraph, (const float (*)[3])cos, num_cos / 3, ob, co_ret, scale_ret);
}
/* copied from Mesh_getFromObject and adapted to RNA interface */
/* settings: 0 - preview, 1 - render */
static Mesh *rna_Object_to_mesh(
- Object *ob, Main *bmain, ReportList *reports, Scene *sce,
- bool apply_modifiers, int settings, bool calc_tessface, bool calc_undeformed)
-{
- return rna_Main_meshes_new_from_object(bmain, reports, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
-}
-
-/* mostly a copy from convertblender.c */
-static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int enable)
-{
- /* ugly function, but we need to set particle systems to their render
- * settings before calling object_duplilist, to get render level duplis */
- Group *group;
- GroupObject *go;
- ParticleSystem *psys;
- DerivedMesh *dm;
- float mat[4][4];
-
- unit_m4(mat);
-
- if (level >= MAX_DUPLI_RECUR)
- return;
-
- if (ob->transflag & OB_DUPLIPARTS) {
- for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- if (ELEM(psys->part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
- if (enable)
- psys_render_set(ob, psys, mat, mat, 1, 1, 0.f);
- else
- psys_render_restore(ob, psys);
- }
- }
-
- if (enable) {
- /* this is to make sure we get render level duplis in groups:
- * the derivedmesh must be created before init_render_mesh,
- * since object_duplilist does dupliparticles before that */
- dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL);
- dm->release(dm);
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
- }
- }
-
- if (ob->dup_group == NULL) return;
- group = ob->dup_group;
-
- for (go = group->gobject.first; go; go = go->next)
- dupli_render_particle_set(scene, go->ob, level + 1, enable);
-}
-/* When no longer needed, duplilist should be freed with Object.free_duplilist */
-static void rna_Object_create_duplilist(Object *ob, Main *bmain, ReportList *reports, Scene *sce, int settings)
+ Object *ob, bContext *C, ReportList *reports, Depsgraph *depsgraph,
+ bool apply_modifiers, bool calc_undeformed)
{
- bool for_render = (settings == DAG_EVAL_RENDER);
- EvaluationContext eval_ctx;
- DEG_evaluation_context_init(&eval_ctx, settings);
-
- if (!(ob->transflag & OB_DUPLI)) {
- BKE_report(reports, RPT_ERROR, "Object does not have duplis");
- return;
- }
-
- /* free duplilist if a user forgets to */
- if (ob->duplilist) {
- BKE_report(reports, RPT_WARNING, "Object.dupli_list has not been freed");
-
- free_object_duplilist(ob->duplilist);
- ob->duplilist = NULL;
- }
- if (for_render)
- dupli_render_particle_set(sce, ob, 0, 1);
- ob->duplilist = object_duplilist(bmain, &eval_ctx, sce, ob);
- if (for_render)
- dupli_render_particle_set(sce, ob, 0, 0);
- /* ob->duplilist should now be freed with Object.free_duplilist */
-}
+ Main *bmain = CTX_data_main(C);
-static void rna_Object_free_duplilist(Object *ob)
-{
- if (ob->duplilist) {
- free_object_duplilist(ob->duplilist);
- ob->duplilist = NULL;
- }
+ return rna_Main_meshes_new_from_object(bmain, reports, depsgraph, ob, apply_modifiers, calc_undeformed);
}
static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *reports,
@@ -262,17 +269,12 @@ static void rna_Object_shape_key_remove(
return;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
RNA_POINTER_INVALIDATE(kb_ptr);
}
-static bool rna_Object_is_visible(Object *ob, Scene *sce)
-{
- return !(ob->restrictflag & OB_RESTRICT_VIEW) && (ob->lay & sce->lay);
-}
-
#if 0
static void rna_Mesh_assign_verts_to_group(Object *ob, bDeformGroup *group, int *indices, int totindex,
float weight, int assignmode)
@@ -311,9 +313,9 @@ static void rna_Mesh_assign_verts_to_group(Object *ob, bDeformGroup *group, int
#endif
/* don't call inside a loop */
-static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
+static int mesh_looptri_to_poly_index(Mesh *me_eval, const MLoopTri *lt)
{
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ const int *index_mp_to_orig = CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
@@ -324,7 +326,7 @@ static void rna_Object_ray_cast(
{
bool success = false;
- if (ob->derivedFinal == NULL) {
+ if (ob->runtime.mesh_eval == NULL) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2);
return;
}
@@ -339,7 +341,7 @@ static void rna_Object_ray_cast(
BVHTreeFromMesh treeData = {NULL};
/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
- bvhtree_from_mesh_get(&treeData, ob->derivedFinal, BVHTREE_FROM_LOOPTRI, 4);
+ BKE_bvhtree_from_mesh_get(&treeData, ob->runtime.mesh_eval, BVHTREE_FROM_LOOPTRI, 4);
/* may fail if the mesh has no faces, in that case the ray-cast misses */
if (treeData.tree != NULL) {
@@ -356,7 +358,7 @@ static void rna_Object_ray_cast(
copy_v3_v3(r_location, hit.co);
copy_v3_v3(r_normal, hit.no);
- *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
+ *r_index = mesh_looptri_to_poly_index(ob->runtime.mesh_eval, &treeData.looptri[hit.index]);
}
}
@@ -378,14 +380,14 @@ static void rna_Object_closest_point_on_mesh(
{
BVHTreeFromMesh treeData = {NULL};
- if (ob->derivedFinal == NULL) {
+ if (ob->runtime.mesh_eval == NULL) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for finding nearest point",
ob->id.name + 2);
return;
}
/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
- bvhtree_from_mesh_get(&treeData, ob->derivedFinal, BVHTREE_FROM_LOOPTRI, 4);
+ BKE_bvhtree_from_mesh_get(&treeData, ob->runtime.mesh_eval, BVHTREE_FROM_LOOPTRI, 4);
if (treeData.tree == NULL) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' could not create internal data for finding nearest point",
@@ -403,7 +405,7 @@ static void rna_Object_closest_point_on_mesh(
copy_v3_v3(r_location, nearest.co);
copy_v3_v3(r_normal, nearest.no);
- *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[nearest.index]);
+ *r_index = mesh_looptri_to_poly_index(ob->runtime.mesh_eval, &treeData.looptri[nearest.index]);
goto finally;
}
@@ -419,13 +421,6 @@ finally:
free_bvhtree_from_mesh(&treeData);
}
-/* ObjectBase */
-
-static void rna_ObjectBase_layers_from_view(Base *base, View3D *v3d)
-{
- base->lay = base->object->lay = v3d->lay;
-}
-
static bool rna_Object_is_modified(Object *ob, Scene *scene, int settings)
{
return BKE_object_is_modified(scene, ob) & settings;
@@ -437,10 +432,12 @@ static bool rna_Object_is_deform_modified(Object *ob, Scene *scene, int settings
}
#ifndef NDEBUG
-void rna_Object_dm_info(struct Object *ob, int type, char *result)
+
+#include "BKE_mesh_runtime.h"
+
+void rna_Object_me_eval_info(struct Object *ob, int type, char *result)
{
- DerivedMesh *dm = NULL;
- bool dm_release = false;
+ Mesh *me_eval = NULL;
char *ret = NULL;
result[0] = '\0';
@@ -448,24 +445,19 @@ void rna_Object_dm_info(struct Object *ob, int type, char *result)
switch (type) {
case 0:
if (ob->type == OB_MESH) {
- dm = CDDM_from_mesh(ob->data);
- ret = DM_debug_info(dm);
- dm_release = true;
+ me_eval = ob->data;
}
break;
case 1:
- dm = ob->derivedDeform;
+ me_eval = ob->runtime.mesh_deform_eval;
break;
case 2:
- dm = ob->derivedFinal;
+ me_eval = ob->runtime.mesh_eval;
break;
}
- if (dm) {
- ret = DM_debug_info(dm);
- if (dm_release) {
- dm->release(dm);
- }
+ if (me_eval) {
+ ret = BKE_mesh_runtime_debug_info(me_eval);
if (ret) {
strcpy(result, ret);
MEM_freeN(ret);
@@ -476,6 +468,7 @@ void rna_Object_dm_info(struct Object *ob, int type, char *result)
static bool rna_Object_update_from_editmode(Object *ob, Main *bmain)
{
+ /* fail gracefully if we aren't in edit-mode. */
return ED_object_editmode_load(bmain, ob);
}
#else /* RNA_RUNTIME */
@@ -491,13 +484,6 @@ void RNA_api_object(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem dupli_eval_mode_items[] = {
- {DAG_EVAL_VIEWPORT, "VIEWPORT", 0, "Viewport", "Generate duplis using viewport settings"},
- {DAG_EVAL_PREVIEW, "PREVIEW", 0, "Preview", "Generate duplis using preview settings"},
- {DAG_EVAL_RENDER, "RENDER", 0, "Render", "Generate duplis using render settings"},
- {0, NULL, 0, NULL, NULL}
- };
-
#ifndef NDEBUG
static const EnumPropertyItem mesh_dm_info_items[] = {
{0, "SOURCE", 0, "Source", "Source mesh"},
@@ -507,6 +493,42 @@ void RNA_api_object(StructRNA *srna)
};
#endif
+ /* Special wrapper to access the base selection value */
+ func = RNA_def_function(srna, "select_set", "rna_Object_select_set");
+ RNA_def_function_ui_description(func, "Select the object (for the active view layer)");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ parm = RNA_def_boolean(func, "state", 0, "", "Selection state to define");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "Operate on this view layer instead of the context");
+
+ func = RNA_def_function(srna, "select_get", "rna_Object_select_get");
+ RNA_def_function_ui_description(func, "Get the object selection for the active view layer");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ parm = RNA_def_boolean(func, "result", 0, "", "Object selected");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "visible_get", "rna_Object_visible_get");
+ RNA_def_function_ui_description(func, "Get the object visibility for the active view layer and viewport");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ parm = RNA_def_boolean(func, "result", 0, "", "Object visible");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "holdout_get", "rna_Object_holdout_get");
+ RNA_def_function_ui_description(func, "Test if object is masked in the view layer");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "View layer to check against");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "result", 0, "", "Object holdout");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "indirect_only_get", "rna_Object_indirect_only_get");
+ RNA_def_function_ui_description(func, "Test if object is set to contribute only indirectly (through shadows and reflections) in the view layer");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "View layer to check against");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "result", 0, "", "Object indirect only");
+ RNA_def_function_return(func, parm);
+
/* Matrix space conversion */
func = RNA_def_function(srna, "convert_space", "rna_Object_mat_convert_space");
RNA_def_function_ui_description(func, "Convert (transform) the given matrix from one space to another");
@@ -529,7 +551,9 @@ void RNA_api_object(StructRNA *srna)
/* Camera-related operations */
func = RNA_def_function(srna, "calc_matrix_camera", "rna_Object_calc_matrix_camera");
RNA_def_function_ui_description(func, "Generate the camera projection matrix of this object "
- "(mostly useful for Camera and Lamp types)");
+ "(mostly useful for Camera and Light types)");
+ parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "Depsgraph to get evaluated data from");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "result", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(parm, "", "The camera projection matrix");
@@ -537,12 +561,12 @@ void RNA_api_object(StructRNA *srna)
parm = RNA_def_int(func, "x", 1, 0, INT_MAX, "", "Width of the render area", 0, 10000);
parm = RNA_def_int(func, "y", 1, 0, INT_MAX, "", "Height of the render area", 0, 10000);
parm = RNA_def_float(func, "scale_x", 1.0f, 1.0e-6f, FLT_MAX, "", "Width scaling factor", 1.0e-2f, 100.0f);
- parm = RNA_def_float(func, "scale_y", 1.0f, 1.0e-6f, FLT_MAX, "", "height scaling factor", 1.0e-2f, 100.0f);
+ parm = RNA_def_float(func, "scale_y", 1.0f, 1.0e-6f, FLT_MAX, "", "Height scaling factor", 1.0e-2f, 100.0f);
func = RNA_def_function(srna, "camera_fit_coords", "rna_Object_camera_fit_coords");
RNA_def_function_ui_description(func, "Compute the coordinate (and scale for ortho cameras) "
"given object should be to 'see' all given coordinates");
- parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to get render size information from, if available");
+ parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "Depsgraph to get evaluated data from");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_array(func, "coordinates", 1, NULL, -FLT_MAX, FLT_MAX, "", "Coordinates to fit in",
-FLT_MAX, FLT_MAX);
@@ -558,32 +582,16 @@ void RNA_api_object(StructRNA *srna)
/* mesh */
func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh");
RNA_def_function_ui_description(func, "Create a Mesh data-block with modifiers applied");
- RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
+ parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "Dependency Graph", "Evaluated dependency graph within which to evaluate modifiers");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces");
RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates");
parm = RNA_def_pointer(func, "mesh", "Mesh", "",
"Mesh created from object, remove it if it is only used for export");
RNA_def_function_return(func, parm);
- /* duplis */
- func = RNA_def_function(srna, "dupli_list_create", "rna_Object_create_duplilist");
- RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Create a list of dupli objects for this object, needs to "
- "be freed manually with free_dupli_list to restore the "
- "objects real matrix and layers");
- parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate duplis");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
- RNA_def_enum(func, "settings", dupli_eval_mode_items, 0, "", "Generate texture coordinates for rendering");
-
- func = RNA_def_function(srna, "dupli_list_clear", "rna_Object_free_duplilist");
- RNA_def_function_ui_description(func, "Free the list of dupli objects");
-
/* Armature */
func = RNA_def_function(srna, "find_armature", "modifiers_isDeformedByArmature");
RNA_def_function_ui_description(func, "Find armature influencing this object as a parent or via a modifier");
@@ -607,21 +615,25 @@ void RNA_api_object(StructRNA *srna)
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+
/* Ray Cast */
func = RNA_def_function(srna, "ray_cast", "rna_Object_ray_cast");
RNA_def_function_ui_description(func, "Cast a ray onto in object space");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* ray start and end */
- parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX,
+ "", "Origin of the ray, in object space", -1e4, 1e4);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX,
+ "", "Direction of the ray, in object space", -1e4, 1e4);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_float(func, "distance", BVH_RAYCAST_DIST_MAX, 0.0, BVH_RAYCAST_DIST_MAX,
"", "Maximum distance", 0.0, BVH_RAYCAST_DIST_MAX);
/* return location and normal */
- parm = RNA_def_boolean(func, "result", 0, "", "");
+ parm = RNA_def_boolean(func, "result", 0, "", "Wheter the ray successfully hit the geometry");
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The hit location of this ray cast", -1e4, 1e4);
@@ -634,19 +646,22 @@ void RNA_api_object(StructRNA *srna)
parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
RNA_def_function_output(func, parm);
+
+
/* Nearest Point */
func = RNA_def_function(srna, "closest_point_on_mesh", "rna_Object_closest_point_on_mesh");
RNA_def_function_ui_description(func, "Find the nearest point in object space");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* location of point for test and max distance */
- parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX,
+ "", "Point to find closest geometry from (in object space)", -1e4, 1e4);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* default is sqrt(FLT_MAX) */
RNA_def_float(func, "distance", 1.844674352395373e+19, 0.0, FLT_MAX, "", "Maximum distance", 0.0, FLT_MAX);
/* return location and normal */
- parm = RNA_def_boolean(func, "result", 0, "", "");
+ parm = RNA_def_boolean(func, "result", 0, "", "Wheter closest point on geometry was found");
RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The location on the object closest to the point", -1e4, 1e4);
@@ -660,42 +675,38 @@ void RNA_api_object(StructRNA *srna)
parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
RNA_def_function_output(func, parm);
+
+
/* View */
- func = RNA_def_function(srna, "is_visible", "rna_Object_is_visible");
- RNA_def_function_ui_description(func, "Determine if object is visible in a given scene");
- parm = RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
- parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
- RNA_def_function_return(func, parm);
/* utility function for checking if the object is modified */
func = RNA_def_function(srna, "is_modified", "rna_Object_is_modified");
RNA_def_function_ui_description(func, "Determine if this object is modified from the base mesh data");
- parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene in which to check the object");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
+ parm = RNA_def_boolean(func, "result", 0, "", "Whether the object is modified");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "is_deform_modified", "rna_Object_is_deform_modified");
RNA_def_function_ui_description(func, "Determine if this object is modified by a deformation from the base mesh data");
- parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene in which to check the object");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_boolean(func, "result", 0, "", "Object visibility");
+ parm = RNA_def_boolean(func, "result", 0, "", "Whether the object is deform-modified");
RNA_def_function_return(func, parm);
#ifndef NDEBUG
/* mesh */
- func = RNA_def_function(srna, "dm_info", "rna_Object_dm_info");
- RNA_def_function_ui_description(func, "Returns a string for derived mesh data");
+ func = RNA_def_function(srna, "dm_info", "rna_Object_me_eval_info");
+ RNA_def_function_ui_description(func, "Returns a string for derived mesh data (debug builds only)");
parm = RNA_def_enum(func, "type", mesh_dm_info_items, 0, "", "Modifier settings to apply");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* weak!, no way to return dynamic string type */
- parm = RNA_def_string(func, "result", NULL, 16384, "result", "");
+ parm = RNA_def_string(func, "result", NULL, 16384, "", "Requested informations");
RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */
RNA_def_function_output(func, parm);
#endif /* NDEBUG */
@@ -710,17 +721,4 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func, "Release memory used by caches associated with this object. Intended to be used by render engines only");
}
-
-void RNA_api_object_base(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *parm;
-
- func = RNA_def_function(srna, "layers_from_view", "rna_ObjectBase_layers_from_view");
- RNA_def_function_ui_description(func,
- "Sets the object layers from a 3D View (use when adding an object in local view)");
- parm = RNA_def_pointer(func, "view", "SpaceView3D", "", "");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
-}
-
#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index c5d66581ca3..a58719085b9 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -42,10 +42,11 @@
#include "WM_types.h"
static const EnumPropertyItem effector_shape_items[] = {
- {PFIELD_SHAPE_POINT, "POINT", 0, "Point", ""},
- {PFIELD_SHAPE_PLANE, "PLANE", 0, "Plane", ""},
- {PFIELD_SHAPE_SURFACE, "SURFACE", 0, "Surface", ""},
- {PFIELD_SHAPE_POINTS, "POINTS", 0, "Every Point", ""},
+ {PFIELD_SHAPE_POINT, "POINT", 0, "Point", "Field originates from the object center"},
+ {PFIELD_SHAPE_LINE, "LINE", 0, "Line", "Field originates from the local Z axis of the object"},
+ {PFIELD_SHAPE_PLANE, "PLANE", 0, "Plane", "Field originates from the local XY plane of the object"},
+ {PFIELD_SHAPE_SURFACE, "SURFACE", 0, "Surface", "Field originates from the surface of the object"},
+ {PFIELD_SHAPE_POINTS, "POINTS", 0, "Every Point", "Field originates from all of the vertices of the object"},
{0, NULL, 0, NULL, NULL}
};
@@ -56,15 +57,17 @@ static const EnumPropertyItem effector_shape_items[] = {
/* type specific return values only used from functions */
static const EnumPropertyItem curve_shape_items[] = {
- {PFIELD_SHAPE_POINT, "POINT", 0, "Point", ""},
- {PFIELD_SHAPE_PLANE, "PLANE", 0, "Plane", ""},
- {PFIELD_SHAPE_SURFACE, "SURFACE", 0, "Curve", ""},
+ {PFIELD_SHAPE_POINT, "POINT", 0, "Point", "Field originates from the object center"},
+ {PFIELD_SHAPE_LINE, "LINE", 0, "Line", "Field originates from the local Z axis of the object"},
+ {PFIELD_SHAPE_PLANE, "PLANE", 0, "Plane", "Field originates from the local XY plane of the object"},
+ {PFIELD_SHAPE_SURFACE, "SURFACE", 0, "Curve", "Field originates from the curve itself"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem empty_shape_items[] = {
- {PFIELD_SHAPE_POINT, "POINT", 0, "Point", ""},
- {PFIELD_SHAPE_PLANE, "PLANE", 0, "Plane", ""},
+ {PFIELD_SHAPE_POINT, "POINT", 0, "Point", "Field originates from the object center"},
+ {PFIELD_SHAPE_LINE, "LINE", 0, "Line", "Field originates from the local Z axis of the object"},
+ {PFIELD_SHAPE_PLANE, "PLANE", 0, "Plane", "Field originates from the local XY plane of the object"},
{0, NULL, 0, NULL, NULL}
};
@@ -94,78 +97,59 @@ static const EnumPropertyItem empty_vortex_shape_items[] = {
#include "DNA_modifier_types.h"
#include "DNA_texture_types.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_object.h"
-static void rna_Cache_change(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Cache_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
PointCache *cache = (PointCache *)ptr->data;
- PTCacheID *pid = NULL;
- ListBase pidlist;
if (!ob)
return;
cache->flag |= PTCACHE_OUTDATED;
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0);
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache)
- break;
- }
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- if (pid) {
+ if (pid.cache) {
/* Just make sure this wasn't changed. */
- if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
+ if (pid.type == PTCACHE_TYPE_SMOKE_DOMAIN)
cache->step = 1;
- BKE_ptcache_update_info(pid);
+ BKE_ptcache_update_info(&pid);
}
-
- BLI_freelistN(&pidlist);
}
-static void rna_Cache_toggle_disk_cache(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Cache_toggle_disk_cache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
PointCache *cache = (PointCache *)ptr->data;
- PTCacheID *pid = NULL;
- ListBase pidlist;
if (!ob)
return;
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0);
-
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache)
- break;
- }
+ PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
/* smoke can only use disk cache */
- if (pid && pid->type != PTCACHE_TYPE_SMOKE_DOMAIN)
- BKE_ptcache_toggle_disk_cache(pid);
+ if (pid.cache && pid.type != PTCACHE_TYPE_SMOKE_DOMAIN)
+ BKE_ptcache_toggle_disk_cache(&pid);
else
cache->flag ^= PTCACHE_DISK_CACHE;
-
- BLI_freelistN(&pidlist);
}
-static void rna_Cache_idname_change(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->id.data;
PointCache *cache = (PointCache *)ptr->data;
- PTCacheID *pid = NULL, *pid2 = NULL;
- ListBase pidlist;
bool use_new_name = true;
if (!ob)
@@ -173,23 +157,22 @@ static void rna_Cache_idname_change(Main *bmain, Scene *UNUSED(scene), PointerRN
/* TODO: check for proper characters */
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0);
-
if (cache->flag & PTCACHE_EXTERNAL) {
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache)
- break;
- }
-
- if (!pid)
- return;
+ PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
- BKE_ptcache_load_external(pid);
+ if (pid.cache) {
+ BKE_ptcache_load_external(&pid);
+ }
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, ob);
}
else {
+ PTCacheID *pid = NULL, *pid2 = NULL;
+ ListBase pidlist;
+
+ BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
+
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->cache == cache)
pid2 = pid;
@@ -215,9 +198,9 @@ static void rna_Cache_idname_change(Main *bmain, Scene *UNUSED(scene), PointerRN
BLI_strncpy(cache->prev_name, cache->name, sizeof(cache->prev_name));
}
- }
- BLI_freelistN(&pidlist);
+ BLI_freelistN(&pidlist);
+ }
}
static void rna_Cache_list_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -238,45 +221,27 @@ static void rna_Cache_active_point_cache_index_range(PointerRNA *ptr, int *min,
{
Object *ob = ptr->id.data;
PointCache *cache = ptr->data;
- PTCacheID *pid;
- ListBase pidlist;
-
- BLI_assert(BKE_id_is_in_gobal_main(&ob->id));
- BKE_ptcache_ids_from_object(G_MAIN, &pidlist, ob, NULL, 0);
+ PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
*min = 0;
*max = 0;
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache) {
- *max = max_ii(0, BLI_listbase_count(pid->ptcaches) - 1);
- break;
- }
+ if (pid.cache) {
+ *max = max_ii(0, BLI_listbase_count(pid.ptcaches) - 1);
}
-
- BLI_freelistN(&pidlist);
}
static int rna_Cache_active_point_cache_index_get(PointerRNA *ptr)
{
Object *ob = ptr->id.data;
PointCache *cache = ptr->data;
- PTCacheID *pid;
- ListBase pidlist;
+ PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
int num = 0;
- BLI_assert(BKE_id_is_in_gobal_main(&ob->id));
- BKE_ptcache_ids_from_object(G_MAIN, &pidlist, ob, NULL, 0);
-
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache) {
- num = BLI_findindex(pid->ptcaches, cache);
- break;
- }
+ if (pid.cache) {
+ num = BLI_findindex(pid.ptcaches, cache);
}
- BLI_freelistN(&pidlist);
-
return num;
}
@@ -284,20 +249,11 @@ static void rna_Cache_active_point_cache_index_set(struct PointerRNA *ptr, int v
{
Object *ob = ptr->id.data;
PointCache *cache = ptr->data;
- PTCacheID *pid;
- ListBase pidlist;
-
- BLI_assert(BKE_id_is_in_gobal_main(&ob->id));
- BKE_ptcache_ids_from_object(G_MAIN, &pidlist, ob, NULL, 0);
+ PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache) {
- *(pid->cache_ptr) = BLI_findlink(pid->ptcaches, value);
- break;
- }
+ if (pid.cache) {
+ *(pid.cache_ptr) = BLI_findlink(pid.ptcaches, value);
}
-
- BLI_freelistN(&pidlist);
}
static void rna_PointCache_frame_step_range(PointerRNA *ptr, int *min, int *max,
@@ -305,23 +261,14 @@ static void rna_PointCache_frame_step_range(PointerRNA *ptr, int *min, int *max,
{
Object *ob = ptr->id.data;
PointCache *cache = ptr->data;
- PTCacheID *pid;
- ListBase pidlist;
+ PTCacheID pid = BKE_ptcache_id_find(ob, NULL, cache);
*min = 1;
*max = 20;
- BLI_assert(BKE_id_is_in_gobal_main(&ob->id));
- BKE_ptcache_ids_from_object(G_MAIN, &pidlist, ob, NULL, 0);
-
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache == cache) {
- *max = pid->max_step;
- break;
- }
+ if (pid.cache) {
+ *max = pid.max_step;
}
-
- BLI_freelistN(&pidlist);
}
static char *rna_CollisionSettings_path(PointerRNA *UNUSED(ptr))
@@ -505,7 +452,7 @@ static void rna_FieldSettings_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
part->pd2->tex = NULL;
}
- DAG_id_tag_update(&part->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME | PSYS_RECALC_RESET);
+ DEG_id_tag_update(&part->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME | PSYS_RECALC_RESET);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
@@ -517,7 +464,7 @@ static void rna_FieldSettings_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
ob->pd->tex = NULL;
}
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
}
@@ -553,7 +500,7 @@ static void rna_FieldSettings_type_set(PointerRNA *ptr, int value)
static void rna_FieldSettings_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
if (particle_id_check(ptr)) {
- DAG_id_tag_update((ID *)ptr->id.data, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME | PSYS_RECALC_RESET);
+ DEG_id_tag_update((ID *)ptr->id.data, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME | PSYS_RECALC_RESET);
}
else {
Object *ob = (Object *)ptr->id.data;
@@ -569,12 +516,12 @@ static void rna_FieldSettings_dependency_update(Main *bmain, Scene *scene, Point
rna_FieldSettings_shape_update(bmain, scene, ptr);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
if (ob->type == OB_CURVE && ob->pd->forcefield == PFIELD_GUIDE)
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
else
- DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
@@ -611,23 +558,23 @@ static void rna_EffectorWeight_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
if (id && GS(id->name) == ID_SCE) {
Scene *scene = (Scene *)id;
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH);
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
+ {
+ BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
}
+ FOREACH_SCENE_OBJECT_END;
}
else {
- DAG_id_tag_update(id, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_id_tag_update(id, OB_RECALC_DATA | PSYS_RECALC_RESET);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
}
static void rna_EffectorWeight_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
- DAG_id_tag_update((ID *)ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ DEG_id_tag_update((ID *)ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
@@ -724,7 +671,7 @@ static void rna_CollisionSettings_update(Main *UNUSED(bmain), Scene *UNUSED(scen
{
Object *ob = (Object *)ptr->id.data;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
@@ -732,13 +679,13 @@ static void rna_softbody_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Point
{
Object *ob = (Object *)ptr->id.data;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
static void rna_softbody_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
rna_softbody_update(bmain, scene, ptr);
}
@@ -1011,6 +958,22 @@ static void rna_def_collision(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Absorption",
"How much of effector force gets lost during collision with this object (in percent)");
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
+
+ prop = RNA_def_property(srna, "cloth_friction", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pdef_cfrict");
+ RNA_def_property_range(prop, 0.0f, 80.0f);
+ RNA_def_property_ui_text(prop, "Friction", "Friction for cloth collisions");
+ RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
+
+ prop = RNA_def_property(srna, "use_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_CLOTH_USE_CULLING);
+ RNA_def_property_ui_text(prop, "Single Sided", "Cloth collision acts with respect to the collider normals (improves penetration recovery)");
+ RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
+
+ prop = RNA_def_property(srna, "use_normal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_CLOTH_USE_NORMAL);
+ RNA_def_property_ui_text(prop, "Override Normals", "Cloth collision impulses act in the direction of the collider normals (more reliable in some cases)");
+ RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
}
static void rna_def_effector_weight(BlenderRNA *brna)
@@ -1031,9 +994,11 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
/* General */
- prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_pointer_sdna(prop, NULL, "group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Effector Group", "Limit effectors to this Group");
+ RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_dependency_update");
prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_NONE);
@@ -1515,78 +1480,6 @@ static void rna_def_field(BlenderRNA *brna)
/* falloff_power, use_max_distance, maximum_distance */
}
-static void rna_def_game_softbody(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "GameSoftBodySettings", NULL);
- RNA_def_struct_sdna(srna, "BulletSoftBody");
- RNA_def_struct_ui_text(srna, "Game Soft Body Settings",
- "Soft body simulation settings for an object in the game engine");
-
- /* Floats */
-
- prop = RNA_def_property(srna, "linear_stiffness", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "linStiff");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Linear Stiffness", "Linear stiffness of the soft body links");
-
- prop = RNA_def_property(srna, "dynamic_friction", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "kDF");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Friction", "Dynamic Friction");
-
- prop = RNA_def_property(srna, "shape_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "kMT");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Threshold", "Shape matching threshold");
-
- prop = RNA_def_property(srna, "collision_margin", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "margin");
- RNA_def_property_range(prop, 0.01f, 1.0f);
- RNA_def_property_ui_text(prop, "Margin",
- "Collision margin for soft body. Small value makes the algorithm unstable");
-
- prop = RNA_def_property(srna, "weld_threshold", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "welding");
- RNA_def_property_range(prop, 0.0f, 0.01f);
- RNA_def_property_ui_text(prop, "Welding",
- "Welding threshold: distance between nearby vertices to be considered equal "
- "=> set to 0.0 to disable welding test and speed up scene loading "
- "(ok if the mesh has no duplicates)");
-
- /* Integers */
-
- prop = RNA_def_property(srna, "location_iterations", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "piterations");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(prop, "Position Iterations", "Position solver iterations");
-
- prop = RNA_def_property(srna, "cluster_iterations", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "numclusteriterations");
- RNA_def_property_range(prop, 1, 128);
- RNA_def_property_ui_text(prop, "Cluster Iterations", "Number of cluster iterations");
-
- /* Booleans */
-
- prop = RNA_def_property(srna, "use_shape_match", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_BSB_SHAPE_MATCHING);
- RNA_def_property_ui_text(prop, "Shape Match", "Enable soft body shape matching goal");
-
- prop = RNA_def_property(srna, "use_bending_constraints", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_BSB_BENDING_CONSTRAINTS);
- RNA_def_property_ui_text(prop, "Bending Const", "Enable bending constraints");
-
- prop = RNA_def_property(srna, "use_cluster_rigid_to_softbody", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "collisionflags", OB_BSB_COL_CL_RS);
- RNA_def_property_ui_text(prop, "Rigid to Soft Body", "Enable cluster collision between soft and rigid body");
-
- prop = RNA_def_property(srna, "use_cluster_soft_to_softbody", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "collisionflags", OB_BSB_COL_CL_SS);
- RNA_def_property_ui_text(prop, "Soft to Soft Body", "Enable cluster collision between soft and soft body");
-}
-
static void rna_def_softbody(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1710,7 +1603,7 @@ static void rna_def_softbody(BlenderRNA *brna)
prop = RNA_def_property(srna, "spring_length", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "springpreload");
RNA_def_property_range(prop, 0.0f, 200.0f);
- RNA_def_property_ui_text(prop, "SL", "Alter spring length to shrink/blow up (unit %) 0 to disable");
+ RNA_def_property_ui_text(prop, "view_layer", "Alter spring length to shrink/blow up (unit %) 0 to disable");
RNA_def_property_update(prop, 0, "rna_softbody_update");
prop = RNA_def_property(srna, "aero", PROP_INT, PROP_NONE);
@@ -1889,9 +1782,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);
+ prop = RNA_def_property(srna, "collision_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_pointer_sdna(prop, NULL, "collision_group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
+ RNA_def_property_ui_text(prop, "Collision Collection", "Limit colliders to this collection");
RNA_def_property_update(prop, 0, "rna_softbody_dependency_update");
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
@@ -1907,7 +1802,6 @@ void RNA_def_object_force(BlenderRNA *brna)
rna_def_collision(brna);
rna_def_effector_weight(brna);
rna_def_field(brna);
- rna_def_game_softbody(brna);
rna_def_softbody(brna);
}
diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c
index 4d6b94bf709..547cac9f38d 100644
--- a/source/blender/makesrna/intern/rna_palette.c
+++ b/source/blender/makesrna/intern/rna_palette.c
@@ -39,7 +39,6 @@
#include "BKE_paint.h"
#include "BKE_report.h"
-
static PaletteColor *rna_Palette_color_new(Palette *palette)
{
PaletteColor *color = BKE_palette_color_add(palette);
@@ -139,6 +138,7 @@ static void rna_def_palettecolor(BlenderRNA *brna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "rgb");
+ RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -153,6 +153,7 @@ static void rna_def_palettecolor(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "value");
RNA_def_property_ui_text(prop, "Weight", "");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
}
static void rna_def_palette(BlenderRNA *brna)
@@ -167,6 +168,7 @@ static void rna_def_palette(BlenderRNA *brna)
prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "PaletteColor");
rna_def_palettecolors(brna, prop);
+
}
void RNA_def_palette(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 05fd0ee740e..4e9b738bfbd 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -32,6 +32,7 @@
#include <limits.h>
#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_cloth_types.h"
@@ -45,6 +46,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "BKE_mesh.h"
+
#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -112,7 +115,7 @@ static const EnumPropertyItem part_ren_as_items[] = {
{PART_DRAW_LINE, "LINE", 0, "Line", ""},
{PART_DRAW_PATH, "PATH", 0, "Path", ""},
{PART_DRAW_OB, "OBJECT", 0, "Object", ""},
- {PART_DRAW_GR, "GROUP", 0, "Group", ""},
+ {PART_DRAW_GR, "COLLECTION", 0, "Collection", ""},
{PART_DRAW_BB, "BILLBOARD", 0, "Billboard", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -122,7 +125,7 @@ static const EnumPropertyItem part_hair_ren_as_items[] = {
{PART_DRAW_NOT, "NONE", 0, "None", ""},
{PART_DRAW_PATH, "PATH", 0, "Path", ""},
{PART_DRAW_OB, "OBJECT", 0, "Object", ""},
- {PART_DRAW_GR, "GROUP", 0, "Group", ""},
+ {PART_DRAW_GR, "COLLECTION", 0, "Collection", ""},
{0, NULL, 0, NULL, NULL}
};
#endif
@@ -136,9 +139,6 @@ static const EnumPropertyItem part_hair_ren_as_items[] = {
#include "BKE_cloth.h"
#include "BKE_colortools.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
@@ -146,6 +146,9 @@ static const EnumPropertyItem part_hair_ren_as_items[] = {
#include "BKE_pointcache.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
/* use for object space hair get/set */
static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr, ParticleSystemModifierData **psmd_pt,
ParticleData **pa_pt)
@@ -178,7 +181,7 @@ static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr, ParticleSy
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
psmd = (ParticleSystemModifierData *) md;
- if (psmd && psmd->dm_final && psmd->psys) {
+ if (psmd && psmd->mesh_final && psmd->psys) {
psys = psmd->psys;
for (i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
/* hairkeys are stored sequentially in memory, so we can
@@ -205,15 +208,15 @@ static void rna_ParticleHairKey_location_object_get(PointerRNA *ptr, float *valu
rna_ParticleHairKey_location_object_info(ptr, &psmd, &pa);
if (pa) {
- DerivedMesh *hairdm = (psmd->psys->flag & PSYS_HAIR_DYNAMICS) ? psmd->psys->hair_out_dm : NULL;
+ Mesh *hair_mesh = (psmd->psys->flag & PSYS_HAIR_DYNAMICS) ? psmd->psys->hair_out_mesh : NULL;
- if (hairdm) {
- MVert *mvert = CDDM_get_vert(hairdm, pa->hair_index + (hkey - pa->hair));
+ if (hair_mesh) {
+ MVert *mvert = &hair_mesh->mvert[pa->hair_index + (hkey - pa->hair)];
copy_v3_v3(values, mvert->co);
}
else {
float hairmat[4][4];
- psys_mat_hair_to_object(ob, psmd->dm_final, psmd->psys->part->from, pa, hairmat);
+ psys_mat_hair_to_object(ob, psmd->mesh_final, psmd->psys->part->from, pa, hairmat);
copy_v3_v3(values, hkey->co);
mul_m4_v3(hairmat, values);
}
@@ -233,17 +236,17 @@ static void rna_ParticleHairKey_location_object_set(PointerRNA *ptr, const float
rna_ParticleHairKey_location_object_info(ptr, &psmd, &pa);
if (pa) {
- DerivedMesh *hairdm = (psmd->psys->flag & PSYS_HAIR_DYNAMICS) ? psmd->psys->hair_out_dm : NULL;
+ Mesh *hair_mesh = (psmd->psys->flag & PSYS_HAIR_DYNAMICS) ? psmd->psys->hair_out_mesh : NULL;
- if (hairdm) {
- MVert *mvert = CDDM_get_vert(hairdm, pa->hair_index + (hkey - pa->hair));
+ if (hair_mesh) {
+ MVert *mvert = &hair_mesh->mvert[pa->hair_index + (hkey - pa->hair)];
copy_v3_v3(mvert->co, values);
}
else {
float hairmat[4][4];
float imat[4][4];
- psys_mat_hair_to_object(ob, psmd->dm_final, psmd->psys->part->from, pa, hairmat);
+ psys_mat_hair_to_object(ob, psmd->mesh_final, psmd->psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
copy_v3_v3(hkey->co, values);
mul_m4_v3(imat, hkey->co);
@@ -258,15 +261,15 @@ static void rna_ParticleHairKey_co_object(HairKey *hairkey, Object *object, Part
float n_co[3])
{
- DerivedMesh *hairdm = (modifier->psys->flag & PSYS_HAIR_DYNAMICS) ? modifier->psys->hair_out_dm : NULL;
+ Mesh *hair_mesh = (modifier->psys->flag & PSYS_HAIR_DYNAMICS) ? modifier->psys->hair_out_mesh : NULL;
if (particle) {
- if (hairdm) {
- MVert *mvert = CDDM_get_vert(hairdm, particle->hair_index + (hairkey - particle->hair));
+ if (hair_mesh) {
+ MVert *mvert = &hair_mesh->mvert[particle->hair_index + (hairkey - particle->hair)];
copy_v3_v3(n_co, mvert->co);
}
else {
float hairmat[4][4];
- psys_mat_hair_to_object(object, modifier->dm_final, modifier->psys->part->from, particle, hairmat);
+ psys_mat_hair_to_object(object, modifier->mesh_final, modifier->psys->part->from, particle, hairmat);
copy_v3_v3(n_co, hairkey->co);
mul_m4_v3(hairmat, n_co);
}
@@ -285,14 +288,14 @@ static void rna_Particle_uv_on_emitter(ParticleData *particle, ReportList *repor
int num = particle->num_dmcache;
int from = modifier->psys->part->from;
- if (!CustomData_has_layer(&modifier->dm_final->loopData, CD_MLOOPUV)) {
+ if (!CustomData_has_layer(&modifier->mesh_final->ldata, CD_MLOOPUV)) {
BKE_report(reports, RPT_ERROR, "Mesh has no UV data");
return;
}
- DM_ensure_tessface(modifier->dm_final); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+ BKE_mesh_tessface_ensure(modifier->mesh_final); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
if (num == DMCACHE_NOTFOUND)
- if (particle->num < modifier->dm_final->getNumTessFaces(modifier->dm_final))
+ if (particle->num < modifier->mesh_final->totface)
num = particle->num;
/* get uvco */
@@ -302,8 +305,8 @@ static void rna_Particle_uv_on_emitter(ParticleData *particle, ReportList *repor
MFace *mface;
MTFace *mtface;
- mface = modifier->dm_final->getTessFaceData(modifier->dm_final, num, CD_MFACE);
- mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm_final->faceData, CD_MTFACE, 0);
+ mface = modifier->mesh_final->mface;
+ mtface = modifier->mesh_final->mtface;
if (mface && mtface) {
mtface += num;
@@ -324,27 +327,18 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o
ParticleData *pars = NULL;
ParticleCacheKey *cache = NULL;
int totchild = 0;
- int path_nbr = 0;
int totpart;
int max_k = 0;
- int step_nbr = 0;
if (particlesystem == NULL)
return;
part = particlesystem->part;
pars = particlesystem->particles;
+ totpart = particlesystem->totcached;
+ totchild = particlesystem->totchildcache;
- if (particlesystem->renderdata) {
- step_nbr = part->ren_step;
- totchild = particlesystem->totchild;
- }
- else {
- step_nbr = part->draw_step;
- totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f);
- }
-
- if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem, particlesystem->renderdata != NULL))
+ if (part == NULL || pars == NULL)
return;
if (part->ren_as == PART_DRAW_OB || part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_NOT)
@@ -354,47 +348,28 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o
if (part->type == PART_HAIR && !particlesystem->childcache)
totchild = 0;
- totpart = particlesystem->totpart;
-
- if (particle_no >= totpart + totchild)
- return;
-
- if (part->ren_as == PART_DRAW_PATH && particlesystem->pathcache)
- path_nbr = 1 << step_nbr;
- if (part->kink == PART_KINK_SPIRAL)
- path_nbr += part->kink_extra_steps;
-
if (particle_no < totpart) {
+ cache = particlesystem->pathcache[particle_no];
+ max_k = (int)cache->segments;
+ }
+ else if (particle_no < totpart + totchild) {
+ cache = particlesystem->childcache[particle_no - totpart];
- if (path_nbr) {
- cache = particlesystem->pathcache[particle_no];
+ if (cache->segments < 0)
+ max_k = 0;
+ else
max_k = (int)cache->segments;
- }
-
}
else {
-
- if (path_nbr) {
- cache = particlesystem->childcache[particle_no - totpart];
-
- if (cache->segments < 0)
- max_k = 0;
- else
- max_k = (int)cache->segments;
- }
+ return;
}
- /*strands key loop data stored in cache + step->co*/
- if (path_nbr) {
- if (step >= 0 && step <= path_nbr) {
- if (step <= max_k) {
- copy_v3_v3(n_co, (cache + step)->co);
- mul_m4_v3(particlesystem->imat, n_co);
- mul_m4_v3(object->obmat, n_co);
- }
- }
+ /* Strands key loop data stored in cache + step->co. */
+ if (step >= 0 && step <= max_k) {
+ copy_v3_v3(n_co, (cache + step)->co);
+ mul_m4_v3(particlesystem->imat, n_co);
+ mul_m4_v3(object->obmat, n_co);
}
-
}
@@ -450,9 +425,9 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
int totvert;
int num = -1;
- DM_ensure_tessface(modifier->dm_final); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
- totface = modifier->dm_final->getNumTessFaces(modifier->dm_final);
- totvert = modifier->dm_final->getNumVerts(modifier->dm_final);
+ BKE_mesh_tessface_ensure(modifier->mesh_final); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+ totface = modifier->mesh_final->totface;
+ totvert = modifier->mesh_final->totvert;
/* 1. check that everything is ok & updated */
if (!particlesystem || !totface) {
@@ -460,20 +435,13 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
}
part = particlesystem->part;
-
- if (particlesystem->renderdata) {
- totchild = particlesystem->totchild;
- }
- else {
- totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f);
- }
+ totpart = particlesystem->totcached;
+ totchild = particlesystem->totchildcache;
/* can happen for disconnected/global hair */
if (part->type == PART_HAIR && !particlesystem->childcache)
totchild = 0;
- totpart = particlesystem->totpart;
-
if (particle_no >= totpart + totchild)
return num;
@@ -489,7 +457,7 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
}
else if (part->from == PART_FROM_VERT) {
if (num != DMCACHE_NOTFOUND && num < totvert) {
- MFace *mface = modifier->dm_final->getTessFaceDataArray(modifier->dm_final, CD_MFACE);
+ MFace *mface = modifier->mesh_final->mface;
*r_fuv = &particle->fuv;
@@ -531,7 +499,7 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
}
else if (part->from == PART_FROM_VERT) {
if (num != DMCACHE_NOTFOUND && num < totvert) {
- MFace *mface = modifier->dm_final->getTessFaceDataArray(modifier->dm_final, CD_MFACE);
+ MFace *mface = modifier->mesh_final->mface;
*r_fuv = &parent->fuv;
@@ -555,7 +523,7 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep
ParticleSystemModifierData *modifier, ParticleData *particle,
int particle_no, int uv_no, float r_uv[2])
{
- if (!CustomData_has_layer(&modifier->dm_final->loopData, CD_MLOOPUV)) {
+ if (!CustomData_has_layer(&modifier->mesh_final->ldata, CD_MLOOPUV)) {
BKE_report(reports, RPT_ERROR, "Mesh has no UV data");
zero_v2(r_uv);
return;
@@ -572,8 +540,8 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep
zero_v2(r_uv);
}
else {
- MFace *mface = modifier->dm_final->getTessFaceData(modifier->dm_final, num, CD_MFACE);
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm_final->faceData, CD_MTFACE, uv_no);
+ MFace *mface = &modifier->mesh_final->mface[num];
+ MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->mesh_final->fdata, CD_MTFACE, uv_no);
psys_interpolate_uvs(&mtface[num], mface->v4, *fuv, r_uv);
}
@@ -584,7 +552,7 @@ static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, R
ParticleSystemModifierData *modifier, ParticleData *particle,
int particle_no, int vcol_no, float r_mcol[3])
{
- if (!CustomData_has_layer(&modifier->dm_final->loopData, CD_MLOOPCOL)) {
+ if (!CustomData_has_layer(&modifier->mesh_final->ldata, CD_MLOOPCOL)) {
BKE_report(reports, RPT_ERROR, "Mesh has no VCol data");
zero_v3(r_mcol);
return;
@@ -601,8 +569,8 @@ static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, R
zero_v3(r_mcol);
}
else {
- MFace *mface = modifier->dm_final->getTessFaceData(modifier->dm_final, num, CD_MFACE);
- MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm_final->faceData, CD_MCOL, vcol_no);
+ MFace *mface = &modifier->mesh_final->mface[num];
+ MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->mesh_final->fdata, CD_MCOL, vcol_no);
MCol mcol;
psys_interpolate_mcol(&mc[num * 4], mface->v4, *fuv, &mcol);
@@ -613,42 +581,18 @@ static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, R
}
}
-static void rna_ParticleSystem_set_resolution(
- ParticleSystem *particlesystem, Main *bmain, Scene *scene, Object *object, int resolution)
-{
- if (resolution == eModifierMode_Render) {
- ParticleSystemModifierData *psmd = psys_get_modifier(object, particlesystem);
- float mat[4][4];
-
- unit_m4(mat);
-
- psys_render_set(object, particlesystem, mat, mat, 1, 1, 0.f);
- psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(bmain, scene, object, particlesystem, true);
- }
- else {
- ParticleSystemModifierData *psmd = psys_get_modifier(object, particlesystem);
-
- if (particlesystem->renderdata) {
- psys_render_restore(object, particlesystem);
- }
-
- psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(bmain, scene, object, particlesystem, false);
- }
-}
-
static void particle_recalc(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr, short flag)
{
if (ptr->type == &RNA_ParticleSystem) {
+ Object *ob = ptr->id.data;
ParticleSystem *psys = (ParticleSystem *)ptr->data;
psys->recalc = flag;
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA | flag);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA | flag);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
}
@@ -659,10 +603,18 @@ static void rna_Particle_redo(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_Particle_redo_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
rna_Particle_redo(bmain, scene, ptr);
}
+static void rna_Particle_redo_count(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ ParticleSettings *part = (ParticleSettings *)ptr->data;
+ DEG_relations_tag_update(bmain);
+ psys_check_group_weights(part);
+ particle_recalc(bmain, scene, ptr, PSYS_RECALC_REDO);
+}
+
static void rna_Particle_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET);
@@ -670,14 +622,27 @@ static void rna_Particle_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_Particle_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
rna_Particle_reset(bmain, scene, ptr);
}
-static void rna_Particle_change_type(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Particle_change_type(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET | PSYS_RECALC_TYPE);
- DAG_relations_tag_update(bmain);
+ ParticleSettings *part = ptr->id.data;
+
+ /* Iterating over all object is slow, but no better solution exists at the moment. */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (psys->part == part) {
+ psys_changed_type(ob, psys);
+ psys->recalc |= PSYS_RECALC_RESET;
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ }
+ }
+
+ WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
+ DEG_relations_tag_update(bmain);
}
static void rna_Particle_change_physics_type(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -716,7 +681,7 @@ static void rna_Particle_cloth_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
{
Object *ob = (Object *)ptr->id.data;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
@@ -761,8 +726,8 @@ static void rna_Particle_target_reset(Main *bmain, Scene *UNUSED(scene), Pointer
psys->recalc = PSYS_RECALC_RESET;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
}
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
@@ -777,7 +742,7 @@ static void rna_Particle_target_redo(Main *UNUSED(bmain), Scene *UNUSED(scene),
psys->recalc = PSYS_RECALC_REDO;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
}
}
@@ -790,7 +755,7 @@ static void rna_Particle_hair_dynamics_update(Main *bmain, Scene *scene, Pointer
if (psys && !psys->clmd) {
psys->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
psys->clmd->sim_parms->goalspring = 0.0f;
- psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_GOAL | CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
+ psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS;
psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
rna_Particle_redo(bmain, scene, ptr);
}
@@ -798,9 +763,10 @@ static void rna_Particle_hair_dynamics_update(Main *bmain, Scene *scene, Pointer
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
}
+
static PointerRNA rna_particle_settings_get(PointerRNA *ptr)
{
ParticleSystem *psys = (ParticleSystem *)ptr->data;
@@ -811,6 +777,7 @@ static PointerRNA rna_particle_settings_get(PointerRNA *ptr)
static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value)
{
+ Object *ob = ptr->id.data;
ParticleSystem *psys = (ParticleSystem *)ptr->data;
int old_type = 0;
@@ -825,8 +792,9 @@ static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value)
if (psys->part) {
id_us_plus(&psys->part->id);
psys_check_boid_data(psys);
- if (old_type != psys->part->type)
- psys->recalc |= PSYS_RECALC_TYPE;
+ if (old_type != psys->part->type) {
+ psys_changed_type(ob, psys);
+ }
}
}
static void rna_Particle_abspathtime_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -1164,6 +1132,9 @@ static void rna_ParticleDupliWeight_active_index_set(struct PointerRNA *ptr, int
static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *str)
{
+ ParticleSettings *part = (ParticleSettings *)ptr->id.data;
+ psys_find_group_weights(part);
+
ParticleDupliWeight *dw = ptr->data;
if (dw->ob)
@@ -1591,7 +1562,7 @@ static void rna_def_particle_dupliweight(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "ParticleDupliWeight", NULL);
- RNA_def_struct_ui_text(srna, "Particle Dupliobject Weight", "Weight of a particle dupliobject in a group");
+ RNA_def_struct_ui_text(srna, "Particle Dupliobject Weight", "Weight of a particle dupliobject in a collection");
RNA_def_struct_sdna(srna, "ParticleDupliWeight");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
@@ -2333,11 +2304,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Size", "Show particle size");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "use_render_emitter", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_EMITTER);
- RNA_def_property_ui_text(prop, "Emitter", "Render emitter Object also");
- RNA_def_property_update(prop, 0, "rna_Particle_redo");
-
prop = RNA_def_property(srna, "show_health", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HEALTH);
RNA_def_property_ui_text(prop, "Health", "Draw boid health");
@@ -2358,29 +2324,29 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Number", "Show particle number");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "use_group_pick_random", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_collection_pick_random", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_RAND_GR);
- RNA_def_property_ui_text(prop, "Pick Random", "Pick objects from group randomly");
+ RNA_def_property_ui_text(prop, "Pick Random", "Pick objects from collection randomly");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "use_group_count", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_collection_count", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_COUNT_GR);
- RNA_def_property_ui_text(prop, "Use Count", "Use object multiple times in the same group");
- RNA_def_property_update(prop, 0, "rna_Particle_redo");
+ RNA_def_property_ui_text(prop, "Use Count", "Use object multiple times in the same collection");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_count");
- prop = RNA_def_property(srna, "use_global_dupli", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_global_instance", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_GLOBAL_OB);
RNA_def_property_ui_text(prop, "Global", "Use object's global coordinates for duplication");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "use_rotation_dupli", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_rotation_instance", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_ROTATE_OB);
RNA_def_property_ui_text(prop, "Rotation",
"Use object's rotation for duplication (global x-axis is aligned "
"particle rotation axis)");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "use_scale_dupli", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_scale_instance", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "draw", PART_DRAW_NO_SCALE_OB);
RNA_def_property_ui_text(prop, "Scale", "Use object's scale for duplication");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
@@ -2395,9 +2361,9 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Speed", "Multiply line length by particle speed");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "use_whole_group", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_whole_collection", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_WHOLE_GR);
- RNA_def_property_ui_text(prop, "Whole Group", "Use whole group at once");
+ RNA_def_property_ui_text(prop, "Whole Collection", "Use whole collection at once");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "use_strand_primitive", PROP_BOOLEAN, PROP_NONE);
@@ -2405,7 +2371,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Strand Render", "Use the strand primitive for rendering");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "draw_method", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "draw_as");
RNA_def_property_enum_items(prop, part_draw_as_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Particle_draw_as_itemf");
@@ -2419,16 +2385,17 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Particle Rendering", "How particles are rendered");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "draw_color", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_color", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "draw_col");
RNA_def_property_enum_items(prop, draw_col_items);
RNA_def_property_ui_text(prop, "Draw Color", "Draw additional particle data as a color");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- prop = RNA_def_property(srna, "draw_size", PROP_INT, PROP_PIXEL);
+ prop = RNA_def_property(srna, "display_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_size");
RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_range(prop, 0, 100, 1, -1);
- RNA_def_property_ui_text(prop, "Draw Size", "Size of particles on viewport in pixels (0=default)");
+ RNA_def_property_ui_text(prop, "Draw Size", "Size of particles on viewport in BU");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "child_type", PROP_ENUM, PROP_NONE);
@@ -2437,7 +2404,8 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Children From", "Create child particles");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
- prop = RNA_def_property(srna, "draw_step", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "display_step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "draw_step");
RNA_def_property_range(prop, 0, 10);
RNA_def_property_ui_range(prop, 0, 7, 1, -1);
RNA_def_property_ui_text(prop, "Steps", "How many steps paths are drawn with (power of 2)");
@@ -2477,7 +2445,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 50);
RNA_def_property_ui_text(prop, "Pixel", "How many pixels path has to cover to make another render segment");
- prop = RNA_def_property(srna, "draw_percentage", PROP_INT, PROP_PERCENTAGE);
+ prop = RNA_def_property(srna, "display_percentage", PROP_INT, PROP_PERCENTAGE);
RNA_def_property_int_sdna(prop, NULL, "disp");
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Display", "Percentage of particles to display in 3D view");
@@ -2586,33 +2554,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Billboard Velocity Tail", "Scale billboards by velocity");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
- /* simplification */
- prop = RNA_def_property(srna, "use_simplify", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_flag", PART_SIMPLIFY_ENABLE);
- RNA_def_property_ui_text(prop, "Child Simplification",
- "Remove child strands as the object becomes smaller on the screen");
-
- prop = RNA_def_property(srna, "use_simplify_viewport", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_flag", PART_SIMPLIFY_VIEWPORT);
- RNA_def_property_ui_text(prop, "Viewport", "");
-
- prop = RNA_def_property(srna, "simplify_refsize", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "simplify_refsize");
- RNA_def_property_range(prop, 1, SHRT_MAX);
- RNA_def_property_ui_text(prop, "Reference Size", "Reference size in pixels, after which simplification begins");
-
- prop = RNA_def_property(srna, "simplify_rate", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Rate", "Speed of simplification");
-
- prop = RNA_def_property(srna, "simplify_transition", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Transition", "Transition period for fading out strands");
-
- prop = RNA_def_property(srna, "simplify_viewport", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 0.999f);
- RNA_def_property_ui_text(prop, "Rate", "Speed of Simplification");
-
/* general values */
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sta"); /*optional if prop names are the same */
@@ -2839,9 +2780,11 @@ 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);
+ prop = RNA_def_property(srna, "collision_collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_pointer_sdna(prop, NULL, "collision_group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Collision Group", "Limit colliders to this Group");
+ RNA_def_property_ui_text(prop, "Collision Collection", "Limit colliders to this collection");
RNA_def_property_update(prop, 0, "rna_Particle_reset_dependency");
/* global physical properties */
@@ -3150,35 +3093,35 @@ static void rna_def_particle_settings(BlenderRNA *brna)
"(must use same subsurf level for viewport and render for correct results)");
RNA_def_property_update(prop, 0, "rna_Particle_change_type");
- /* draw objects & groups */
- prop = RNA_def_property(srna, "dupli_group", PROP_POINTER, PROP_NONE);
+ /* draw objects & collections */
+ prop = RNA_def_property(srna, "instance_collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "dup_group");
- RNA_def_property_struct_type(prop, "Group");
+ RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Dupli Group", "Show Objects in this Group in place of particles");
- RNA_def_property_update(prop, 0, "rna_Particle_redo");
+ RNA_def_property_ui_text(prop, "Dupli Collection", "Show Objects in this collection in place of particles");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_count");
- prop = RNA_def_property(srna, "dupli_weights", PROP_COLLECTION, PROP_NONE);
+ prop = RNA_def_property(srna, "instance_weights", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "dupliweights", NULL);
RNA_def_property_struct_type(prop, "ParticleDupliWeight");
- RNA_def_property_ui_text(prop, "Dupli Group Weights", "Weights for all of the objects in the dupli group");
+ RNA_def_property_ui_text(prop, "Dupli Collection Weights", "Weights for all of the objects in the dupli collection");
- prop = RNA_def_property(srna, "active_dupliweight", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "active_instanceweight", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ParticleDupliWeight");
RNA_def_property_pointer_funcs(prop, "rna_ParticleDupliWeight_active_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Active Dupli Object", "");
- prop = RNA_def_property(srna, "active_dupliweight_index", PROP_INT, PROP_UNSIGNED);
+ prop = RNA_def_property(srna, "active_instanceweight_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_ParticleDupliWeight_active_index_get",
"rna_ParticleDupliWeight_active_index_set",
"rna_ParticleDupliWeight_active_index_range");
RNA_def_property_ui_text(prop, "Active Dupli Object Index", "");
- prop = RNA_def_property(srna, "dupli_object", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "instance_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "dup_ob");
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Dupli Object", "Show this Object in place of particles");
+ RNA_def_property_ui_text(prop, "Instance Object", "Show this Object in place of particles");
RNA_def_property_update(prop, 0, "rna_Particle_redo_dependency");
prop = RNA_def_property(srna, "billboard_object", PROP_POINTER, PROP_NONE);
@@ -3239,6 +3182,38 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Twist Curve", "Curve defining twist");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+ /* hair shape */
+ prop = RNA_def_property(srna, "use_close_tip", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shape_flag", PART_SHAPE_CLOSE_TIP);
+ RNA_def_property_ui_text(prop, "Close Tip", "Set tip radius to zero");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo"); /* TODO: Only need to tell the render engine to update. */
+
+ prop = RNA_def_property(srna, "shape", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, -1.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Shape", "Strand shape parameter");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo"); /* TODO: Only need to tell the render engine to update. */
+
+ prop = RNA_def_property(srna, "root_radius", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rad_root");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 2);
+ RNA_def_property_ui_text(prop, "Root", "Strand width at the root");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo"); /* TODO: Only need to tell the render engine to update. */
+
+ prop = RNA_def_property(srna, "tip_radius", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rad_tip");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 2);
+ RNA_def_property_ui_text(prop, "Tip", "Strand width at the tip");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo"); /* TODO: Only need to tell the render engine to update. */
+
+ prop = RNA_def_property(srna, "radius_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "rad_scale");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 2);
+ RNA_def_property_ui_text(prop, "Scaling", "Multiplier of radius properties");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo"); /* TODO: Only need to tell the render engine to update. */
}
static void rna_def_particle_target(BlenderRNA *brna)
@@ -3309,12 +3284,6 @@ static void rna_def_particle_system(BlenderRNA *brna)
FunctionRNA *func;
PropertyRNA *parm;
- static const EnumPropertyItem resolution_items[] = {
- {eModifierMode_Realtime, "PREVIEW", 0, "Preview", "Apply modifier preview settings"},
- {eModifierMode_Render, "RENDER", 0, "Render", "Apply modifier render settings"},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "ParticleSystem", NULL);
RNA_def_struct_ui_text(srna, "Particle System", "Particle system in an object");
RNA_def_struct_ui_icon(srna, ICON_PARTICLE_DATA);
@@ -3338,11 +3307,13 @@ static void rna_def_particle_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "particles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "particles", "totpart");
RNA_def_property_struct_type(prop, "Particle");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "Particles", "Particles generated by the particle system");
prop = RNA_def_property(srna, "child_particles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "child", "totchild");
RNA_def_property_struct_type(prop, "ChildParticle");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "Child Particles", "Child particles generated by the particle system");
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
@@ -3625,14 +3596,6 @@ static void rna_def_particle_system(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_ParticleSystem_path");
- /* set viewport or render resolution */
- func = RNA_def_function(srna, "set_resolution", "rna_ParticleSystem_set_resolution");
- RNA_def_function_ui_description(func, "Set the resolution to use for the number of particles");
- RNA_def_function_flag(func, FUNC_USE_MAIN);
- RNA_def_pointer(func, "scene", "Scene", "", "Scene");
- RNA_def_pointer(func, "object", "Object", "", "Object");
- RNA_def_enum(func, "resolution", resolution_items, 0, "", "Resolution settings to apply");
-
/* extract cached hair location data */
func = RNA_def_function(srna, "co_hair", "rna_ParticleSystem_co_hair");
RNA_def_function_ui_description(func, "Obtain cache hair data");
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index e06aab8c4cc..4b6a19ab063 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -68,26 +68,26 @@ const EnumPropertyItem rna_enum_posebone_rotmode_items[] = {
/* Bone and Group Color Sets */
const EnumPropertyItem rna_enum_color_sets_items[] = {
{0, "DEFAULT", 0, "Default Colors", ""},
- {1, "THEME01", VICO_COLORSET_01_VEC, "01 - Theme Color Set", ""},
- {2, "THEME02", VICO_COLORSET_02_VEC, "02 - Theme Color Set", ""},
- {3, "THEME03", VICO_COLORSET_03_VEC, "03 - Theme Color Set", ""},
- {4, "THEME04", VICO_COLORSET_04_VEC, "04 - Theme Color Set", ""},
- {5, "THEME05", VICO_COLORSET_05_VEC, "05 - Theme Color Set", ""},
- {6, "THEME06", VICO_COLORSET_06_VEC, "06 - Theme Color Set", ""},
- {7, "THEME07", VICO_COLORSET_07_VEC, "07 - Theme Color Set", ""},
- {8, "THEME08", VICO_COLORSET_08_VEC, "08 - Theme Color Set", ""},
- {9, "THEME09", VICO_COLORSET_09_VEC, "09 - Theme Color Set", ""},
- {10, "THEME10", VICO_COLORSET_10_VEC, "10 - Theme Color Set", ""},
- {11, "THEME11", VICO_COLORSET_11_VEC, "11 - Theme Color Set", ""},
- {12, "THEME12", VICO_COLORSET_12_VEC, "12 - Theme Color Set", ""},
- {13, "THEME13", VICO_COLORSET_13_VEC, "13 - Theme Color Set", ""},
- {14, "THEME14", VICO_COLORSET_14_VEC, "14 - Theme Color Set", ""},
- {15, "THEME15", VICO_COLORSET_15_VEC, "15 - Theme Color Set", ""},
- {16, "THEME16", VICO_COLORSET_16_VEC, "16 - Theme Color Set", ""},
- {17, "THEME17", VICO_COLORSET_17_VEC, "17 - Theme Color Set", ""},
- {18, "THEME18", VICO_COLORSET_18_VEC, "18 - Theme Color Set", ""},
- {19, "THEME19", VICO_COLORSET_19_VEC, "19 - Theme Color Set", ""},
- {20, "THEME20", VICO_COLORSET_20_VEC, "20 - Theme Color Set", ""},
+ {1, "THEME01", ICON_COLORSET_01_VEC, "01 - Theme Color Set", ""},
+ {2, "THEME02", ICON_COLORSET_02_VEC, "02 - Theme Color Set", ""},
+ {3, "THEME03", ICON_COLORSET_03_VEC, "03 - Theme Color Set", ""},
+ {4, "THEME04", ICON_COLORSET_04_VEC, "04 - Theme Color Set", ""},
+ {5, "THEME05", ICON_COLORSET_05_VEC, "05 - Theme Color Set", ""},
+ {6, "THEME06", ICON_COLORSET_06_VEC, "06 - Theme Color Set", ""},
+ {7, "THEME07", ICON_COLORSET_07_VEC, "07 - Theme Color Set", ""},
+ {8, "THEME08", ICON_COLORSET_08_VEC, "08 - Theme Color Set", ""},
+ {9, "THEME09", ICON_COLORSET_09_VEC, "09 - Theme Color Set", ""},
+ {10, "THEME10", ICON_COLORSET_10_VEC, "10 - Theme Color Set", ""},
+ {11, "THEME11", ICON_COLORSET_11_VEC, "11 - Theme Color Set", ""},
+ {12, "THEME12", ICON_COLORSET_12_VEC, "12 - Theme Color Set", ""},
+ {13, "THEME13", ICON_COLORSET_13_VEC, "13 - Theme Color Set", ""},
+ {14, "THEME14", ICON_COLORSET_14_VEC, "14 - Theme Color Set", ""},
+ {15, "THEME15", ICON_COLORSET_15_VEC, "15 - Theme Color Set", ""},
+ {16, "THEME16", ICON_COLORSET_16_VEC, "16 - Theme Color Set", ""},
+ {17, "THEME17", ICON_COLORSET_17_VEC, "17 - Theme Color Set", ""},
+ {18, "THEME18", ICON_COLORSET_18_VEC, "18 - Theme Color Set", ""},
+ {19, "THEME19", ICON_COLORSET_19_VEC, "19 - Theme Color Set", ""},
+ {20, "THEME20", ICON_COLORSET_20_VEC, "20 - Theme Color Set", ""},
{-1, "CUSTOM", 0, "Custom Color Set", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -106,10 +106,12 @@ const EnumPropertyItem rna_enum_color_sets_items[] = {
#include "BKE_context.h"
#include "BKE_constraint.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_object.h"
#include "ED_armature.h"
@@ -121,7 +123,16 @@ static void rna_Pose_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRN
{
/* XXX when to use this? ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); */
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_POSE, ptr->id.data);
+}
+
+static void rna_Pose_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_relations_tag_update(bmain);
+
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_POSE, ptr->id.data);
}
static void rna_Pose_IK_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -129,7 +140,9 @@ static void rna_Pose_IK_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
/* XXX when to use this? ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK); */
Object *ob = ptr->id.data;
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_POSE, ptr->id.data);
+
BIK_clear_data(ob->pose);
}
@@ -234,13 +247,13 @@ static void rna_Pose_ik_solver_update(Main *bmain, Scene *UNUSED(scene), Pointer
bPose *pose = ptr->data;
BKE_pose_tag_recalc(bmain, pose); /* checks & sorts pose channels */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
BKE_pose_update_constraint_flags(pose);
object_test_constraints(bmain, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
}
/* rotation - axis-angle */
@@ -287,8 +300,8 @@ static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(newname, value, sizeof(pchan->name));
BLI_strncpy(oldname, pchan->name, sizeof(pchan->name));
- BLI_assert(BKE_id_is_in_gobal_main(&ob->id));
- BLI_assert(BKE_id_is_in_gobal_main(ob->data));
+ BLI_assert(BKE_id_is_in_global_main(&ob->id));
+ BLI_assert(BKE_id_is_in_global_main(ob->data));
ED_armature_bone_rename(G_MAIN, ob->data, oldname, newname);
}
@@ -352,7 +365,7 @@ static void rna_Itasc_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerR
itasc->maxvel = 100.f;
BIK_update_param(ob->pose);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
static void rna_Itasc_update_rebuild(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -564,6 +577,56 @@ static void rna_PoseChannel_constraints_remove(
}
}
+bool rna_PoseChannel_constraints_override_apply(
+ Main *UNUSED(bmain),
+ PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *UNUSED(prop_dst), PropertyRNA *UNUSED(prop_src), PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst), const int UNUSED(len_src), const int UNUSED(len_storage),
+ PointerRNA *UNUSED(ptr_item_dst), PointerRNA *UNUSED(ptr_item_src), PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_INSERT_AFTER &&
+ "Unsupported RNA override operation on constraints collection");
+
+ bPoseChannel *pchan_dst = (bPoseChannel *)ptr_dst->data;
+ bPoseChannel *pchan_src = (bPoseChannel *)ptr_src->data;
+
+ /* Remember that insertion operations are defined and stored in correct order, which means that
+ * even if we insert several items in a row, we alays insert first one, then second one, etc.
+ * So we should always find 'anchor' constraint in both _src *and* _dst> */
+ bConstraint *con_anchor = NULL;
+ if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+ con_anchor = BLI_findstring(&pchan_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
+ }
+ if (con_anchor == NULL && opop->subitem_local_index >= 0) {
+ con_anchor = BLI_findlink(&pchan_dst->constraints, opop->subitem_local_index);
+ }
+ /* Otherwise we just insert in first position. */
+
+ bConstraint *con_src = NULL;
+ if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+ con_src = BLI_findstring(&pchan_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
+ }
+ if (con_src == NULL && opop->subitem_local_index >= 0) {
+ con_src = BLI_findlink(&pchan_src->constraints, opop->subitem_local_index);
+ }
+ con_src = con_src ? con_src->next : pchan_src->constraints.first;
+
+ BLI_assert(con_src != NULL);
+
+ bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true);
+
+ /* This handles NULL anchor as expected by adding at head of list. */
+ BLI_insertlinkafter(&pchan_dst->constraints, con_anchor, con_dst);
+
+ /* This should actually *not* be needed in typical cases. However, if overridden source was edited,
+ * we *may* have some new conflicting names. */
+ BKE_constraint_unique_name(con_dst, &pchan_dst->constraints);
+
+// printf("%s: We inserted a constraint...\n", __func__);
+ return true;
+}
+
static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info)
{
Object *ob = (Object *)ptr->id.data;
@@ -675,11 +738,30 @@ static void rna_PoseChannel_matrix_set(PointerRNA *ptr, const float *values)
Object *ob = (Object *)ptr->id.data;
float tmat[4][4];
- BKE_armature_mat_pose_to_bone_ex(ob, pchan, (float (*)[4])values, tmat);
+ BKE_armature_mat_pose_to_bone_ex(NULL, ob, pchan, (float (*)[4])values, tmat);
BKE_pchan_apply_mat4(pchan, tmat, false); /* no compat for predictable result */
}
+static bPoseChannel *rna_PoseChannel_ensure_own_pchan(Object *ob, Object *ref_ob, bPoseChannel *ref_pchan)
+{
+ if (ref_ob != ob) {
+ /* We are trying to set a pchan from another object! Forbidden, try to find by name, or abort. */
+ if (ref_pchan != NULL) {
+ ref_pchan = BKE_pose_channel_find_name(ob->pose, ref_pchan->name);
+ }
+ }
+ return ref_pchan;
+}
+
+static void rna_PoseChannel_custom_shape_transform_set(PointerRNA *ptr, PointerRNA value)
+{
+ bPoseChannel *pchan = (bPoseChannel *)ptr->data;
+ Object *ob = (Object *)ptr->id.data;
+
+ pchan->custom_tx = rna_PoseChannel_ensure_own_pchan(ob, value.id.data, value.data);
+}
+
#else
/* common properties for Action/Bone Groups - related to color */
@@ -807,7 +889,9 @@ static void rna_def_pose_channel(BlenderRNA *brna)
/* Bone Constraints */
prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Constraint");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION);
RNA_def_property_ui_text(prop, "Constraints", "Constraints that act on this PoseChannel");
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_PoseChannel_constraints_override_apply");
rna_def_pose_channel_constraints(brna, prop);
@@ -825,22 +909,26 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "bone", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "Bone");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Bone", "Bone associated with this PoseBone");
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Parent", "Parent of this pose bone");
prop = RNA_def_property(srna, "child", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Child", "Child of this pose bone");
/* Transformation settings */
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_location_editable");
RNA_def_property_ui_text(prop, "Location", "");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
@@ -849,6 +937,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_scale_editable");
RNA_def_property_float_array_default(prop, default_scale);
RNA_def_property_ui_text(prop, "Scale", "");
@@ -856,6 +945,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "quat");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_4d_editable");
RNA_def_property_float_array_default(prop, default_quat);
RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions");
@@ -865,6 +955,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
* having a single one is better for Keyframing and other property-management situations...
*/
prop = RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_array(prop, 4);
RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_axis_angle_get",
"rna_PoseChannel_rotation_axis_angle_set", NULL);
@@ -875,6 +966,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "eul");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_euler_editable");
RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
@@ -892,45 +984,23 @@ static void rna_def_pose_channel(BlenderRNA *brna)
rna_def_bone_curved_common(srna, true);
/* Custom BBone next/prev sources */
- prop = RNA_def_property(srna, "use_bbone_custom_handles", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_HANDLES);
- RNA_def_property_ui_text(prop, "Use Custom Handle References",
- "Use custom reference bones as handles for B-Bones instead of next/previous bones, "
- "leave these blank to use only B-Bone offset properties to control the shape");
- RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
- RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
-
prop = RNA_def_property(srna, "bbone_custom_handle_start", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "bbone_prev");
RNA_def_property_struct_type(prop, "PoseBone");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "B-Bone Start Handle",
"Bone that serves as the start handle for the B-Bone curve");
- RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
- RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
-
- prop = RNA_def_property(srna, "use_bbone_relative_start_handle", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_START_REL);
- RNA_def_property_ui_text(prop, "Relative B-Bone Start Handle",
- "Treat custom start handle position as a relative value");
- RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
- RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_dependency_update");
prop = RNA_def_property(srna, "bbone_custom_handle_end", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "bbone_next");
RNA_def_property_struct_type(prop, "PoseBone");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "B-Bone End Handle",
"Bone that serves as the end handle for the B-Bone curve");
- RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
- RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
-
- prop = RNA_def_property(srna, "use_bbone_relative_end_handle", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bboneflag", PCHAN_BBONE_CUSTOM_END_REL);
- RNA_def_property_ui_text(prop, "Relative B-Bone End Handle",
- "Treat custom end handle position as a relative value");
- RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
- RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_dependency_update");
/* transform matrices - should be read-only since these are set directly by AnimSys evaluation */
prop = RNA_def_property(srna, "matrix_channel", PROP_FLOAT, PROP_MATRIX);
@@ -1136,10 +1206,12 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "custom_shape_transform", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "custom_tx");
RNA_def_property_struct_type(prop, "PoseBone");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Custom Shape Transform",
"Bone that defines the display transform of this custom shape");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_PoseChannel_custom_shape_transform_set", NULL, NULL);
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
/* bone groups */
@@ -1401,6 +1473,7 @@ static void rna_def_pose(BlenderRNA *brna)
prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "chanbase", NULL);
RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Pose Bones", "Individual pose bones for the armature");
/* can be removed, only for fast lookup */
RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, "rna_PoseBones_lookup_string", NULL);
diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c
index 04ecdd497f6..f4463e0f7d8 100644
--- a/source/blender/makesrna/intern/rna_pose_api.c
+++ b/source/blender/makesrna/intern/rna_pose_api.c
@@ -59,6 +59,45 @@ static float rna_PoseBone_do_envelope(bPoseChannel *chan, float *vec)
return distfactor_to_bone(vec, chan->pose_head, chan->pose_tail, bone->rad_head * scale,
bone->rad_tail * scale, bone->dist * scale);
}
+
+static void rna_PoseBone_bbone_segment_matrix(bPoseChannel *pchan, ReportList *reports, float mat_ret[16], int index, bool rest)
+{
+ if (!pchan->bone || pchan->bone->segments <= 1) {
+ BKE_reportf(reports, RPT_ERROR, "Bone '%s' is not a B-Bone!", pchan->name);
+ return;
+ }
+ if (pchan->runtime.bbone_segments != pchan->bone->segments) {
+ BKE_reportf(reports, RPT_ERROR, "Bone '%s' has out of date B-Bone segment data!", pchan->name);
+ return;
+ }
+ if (index < 0 || index >= pchan->runtime.bbone_segments) {
+ BKE_reportf(reports, RPT_ERROR, "Invalid index %d for B-Bone segments of '%s'!", index, pchan->name);
+ return;
+ }
+
+ if (rest) {
+ copy_m4_m4((float (*)[4])mat_ret, pchan->runtime.bbone_rest_mats[index].mat);
+ }
+ else {
+ copy_m4_m4((float (*)[4])mat_ret, pchan->runtime.bbone_pose_mats[index].mat);
+ }
+}
+
+static void rna_PoseBone_compute_bbone_handles(
+ bPoseChannel *pchan, ReportList *reports,
+ float ret_h1[3], float *ret_roll1, float ret_h2[3], float *ret_roll2,
+ bool rest, bool ease, bool offsets)
+{
+ if (!pchan->bone || pchan->bone->segments <= 1) {
+ BKE_reportf(reports, RPT_ERROR, "Bone '%s' is not a B-Bone!", pchan->name);
+ return;
+ }
+
+ BBoneSplineParameters params;
+
+ BKE_pchan_get_bbone_spline_parameters(pchan, rest, &params);
+ BKE_compute_b_bone_handles(&params, ret_h1, ret_roll1, ret_h2, ret_roll2, ease || offsets, offsets);
+}
#else
void RNA_api_pose(StructRNA *UNUSED(srna))
@@ -80,6 +119,38 @@ void RNA_api_pose_channel(StructRNA *srna)
/* return value */
parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX);
RNA_def_function_return(func, parm);
+
+ /* B-Bone segment matrices */
+ func = RNA_def_function(srna, "bbone_segment_matrix", "rna_PoseBone_bbone_segment_matrix");
+ RNA_def_function_ui_description(func, "Retrieve the matrix of the B-Bone segment if available");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_property(func, "matrix_return", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(parm, "", "The resulting matrix in bone local space");
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the segment", 0, 10000);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "rest", false, "", "Return the rest pose matrix");
+
+ /* B-Bone custom handle positions */
+ func = RNA_def_function(srna, "compute_bbone_handles", "rna_PoseBone_compute_bbone_handles");
+ RNA_def_function_ui_description(func, "Retrieve the vectors and rolls coming from B-Bone custom handles");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_property(func, "handle1", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ RNA_def_property_ui_text(parm, "", "The direction vector of the start handle in bone local space");
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_float(func, "roll1", 0, -FLT_MAX, FLT_MAX, "", "Roll of the start handle", -FLT_MAX, FLT_MAX);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_property(func, "handle2", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ RNA_def_property_ui_text(parm, "", "The direction vector of the end handle in bone local space");
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_float(func, "roll2", 0, -FLT_MAX, FLT_MAX, "", "Roll of the end handle", -FLT_MAX, FLT_MAX);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_boolean(func, "rest", false, "", "Return the rest pose state");
+ parm = RNA_def_boolean(func, "ease", false, "", "Apply scale from ease values");
+ parm = RNA_def_boolean(func, "offsets", false, "", "Apply roll and curve offsets from bone properties");
}
diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c
deleted file mode 100644
index 9a79aa4023c..00000000000
--- a/source/blender/makesrna/intern/rna_property.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * ***** 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): Blender Foundation (2008).
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/makesrna/intern/rna_property.c
- * \ingroup RNA
- */
-
-
-#include <stdlib.h>
-
-#include "DNA_property_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_path_util.h"
-#include "BLI_string_utils.h"
-
-#include "BLT_translation.h"
-
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "rna_internal.h"
-
-
-#include "WM_types.h"
-
-const EnumPropertyItem rna_enum_gameproperty_type_items[] = {
- {GPROP_BOOL, "BOOL", 0, "Boolean", "Boolean Property"},
- {GPROP_INT, "INT", 0, "Integer", "Integer Property"},
- {GPROP_FLOAT, "FLOAT", 0, "Float", "Floating-Point Property"},
- {GPROP_STRING, "STRING", 0, "String", "String Property"},
- {GPROP_TIME, "TIMER", 0, "Timer", "Timer Property"},
- {0, NULL, 0, NULL, NULL}
-};
-
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_property.h"
-
-static StructRNA *rna_GameProperty_refine(struct PointerRNA *ptr)
-{
- bProperty *property = (bProperty *)ptr->data;
-
- switch (property->type) {
- case GPROP_BOOL:
- return &RNA_GameBooleanProperty;
- case GPROP_INT:
- return &RNA_GameIntProperty;
- case GPROP_FLOAT:
- return &RNA_GameFloatProperty;
- case GPROP_STRING:
- return &RNA_GameStringProperty;
- case GPROP_TIME:
- return &RNA_GameTimerProperty;
- default:
- return &RNA_GameProperty;
- }
-}
-
-/* for both float and timer */
-static float rna_GameFloatProperty_value_get(PointerRNA *ptr)
-{
- bProperty *prop = (bProperty *)(ptr->data);
- return *(float *)(&prop->data);
-}
-
-static void rna_GameFloatProperty_value_set(PointerRNA *ptr, float value)
-{
- bProperty *prop = (bProperty *)(ptr->data);
- CLAMP(value, -10000.0f, 10000.0f);
- *(float *)(&prop->data) = value;
-}
-
-static void rna_GameProperty_type_set(PointerRNA *ptr, int value)
-{
- bProperty *prop = (bProperty *)(ptr->data);
-
- if (prop->type != value) {
- prop->type = value;
- BKE_bproperty_init(prop);
- }
-}
-
-static void rna_GameProperty_name_set(PointerRNA *ptr, const char *value)
-{
- Object *ob = ptr->id.data;
- bProperty *prop = ptr->data;
- BLI_strncpy_utf8(prop->name, value, sizeof(prop->name));
-
- BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name));
-}
-
-
-#else
-
-void RNA_def_gameproperty(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- /* Base Struct for GameProperty */
- srna = RNA_def_struct(brna, "GameProperty", NULL);
- RNA_def_struct_ui_text(srna, "Game Property", "Game engine user defined object property");
- RNA_def_struct_sdna(srna, "bProperty");
- RNA_def_struct_refine_func(srna, "rna_GameProperty_refine");
-
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Name", "Available as GameObject attributes in the game engine's python API");
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GameProperty_name_set");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_gameproperty_type_items);
- RNA_def_property_ui_text(prop, "Type", "");
- RNA_def_property_enum_funcs(prop, NULL, "rna_GameProperty_type_set", NULL);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_debug", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", PROP_DEBUG);
- RNA_def_property_ui_text(prop, "Debug", "Print debug information for this property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* GameBooleanProperty */
- srna = RNA_def_struct(brna, "GameBooleanProperty", "GameProperty");
- RNA_def_struct_ui_text(srna, "Game Boolean Property", "Game engine user defined Boolean property");
- RNA_def_struct_sdna(srna, "bProperty");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "value", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "data", 1);
- RNA_def_property_ui_text(prop, "Value", "Property value");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* GameIntProperty */
- srna = RNA_def_struct(brna, "GameIntProperty", "GameProperty");
- RNA_def_struct_ui_text(srna, "Game Integer Property", "Game engine user defined integer number property");
- RNA_def_struct_sdna(srna, "bProperty");
-
- prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "data");
- RNA_def_property_ui_text(prop, "Value", "Property value");
- RNA_def_property_range(prop, -10000, 10000);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* GameFloatProperty */
- srna = RNA_def_struct(brna, "GameFloatProperty", "GameProperty");
- RNA_def_struct_ui_text(srna, "Game Float Property", "Game engine user defined floating point number property");
- RNA_def_struct_sdna(srna, "bProperty");
-
- prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
- /* RNA_def_property_float_sdna(prop, NULL, "data"); */
- RNA_def_property_ui_text(prop, "Value", "Property value");
- RNA_def_property_range(prop, -10000, 10000);
- RNA_def_property_float_funcs(prop, "rna_GameFloatProperty_value_get", "rna_GameFloatProperty_value_set", NULL);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* GameTimerProperty */
- srna = RNA_def_struct(brna, "GameTimerProperty", "GameProperty");
- RNA_def_struct_ui_text(srna, "Game Timer Property", "Game engine user defined timer property");
- RNA_def_struct_sdna(srna, "bProperty");
-
- prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
- /* RNA_def_property_float_sdna(prop, NULL, "data"); */
- RNA_def_property_ui_text(prop, "Value", "Property value");
- RNA_def_property_range(prop, -10000, 10000);
- RNA_def_property_float_funcs(prop, "rna_GameFloatProperty_value_get", "rna_GameFloatProperty_value_set", NULL);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* GameStringProperty */
- srna = RNA_def_struct(brna, "GameStringProperty", "GameProperty");
- RNA_def_struct_ui_text(srna, "Game String Property", "Game engine user defined text string property");
- RNA_def_struct_sdna(srna, "bProperty");
-
- prop = RNA_def_property(srna, "value", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "poin");
- RNA_def_property_string_maxlength(prop, MAX_PROPSTRING);
- RNA_def_property_ui_text(prop, "Value", "Property value");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index b516accbf1e..46b77b80d49 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -33,6 +33,8 @@
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
+#include "DEG_depsgraph.h"
+
#include "BKE_scene.h"
#include "BKE_image.h"
@@ -54,7 +56,7 @@ const EnumPropertyItem rna_enum_render_pass_type_items[] = {
{SCE_PASS_DIFFUSE, "DIFFUSE", 0, "Diffuse", ""},
{SCE_PASS_SPEC, "SPECULAR", 0, "Specular", ""},
{SCE_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
- {SCE_PASS_AO, "AO", 0, "AO", ""},
+ {SCE_PASS_AO, "AO", 0, "Ambient Occlusion", ""},
{SCE_PASS_REFLECT, "REFLECTION", 0, "Reflection", ""},
{SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
{SCE_PASS_VECTOR, "VECTOR", 0, "Vector", ""},
@@ -85,7 +87,7 @@ const EnumPropertyItem rna_enum_render_pass_type_items[] = {
const EnumPropertyItem rna_enum_bake_pass_type_items[] = {
{SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
- {SCE_PASS_AO, "AO", 0, "AO", ""},
+ {SCE_PASS_AO, "AO", 0, "Ambient Occlusion", ""},
{SCE_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
{SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
{SCE_PASS_UV, "UV", 0, "UV", ""},
@@ -111,6 +113,8 @@ const EnumPropertyItem rna_enum_bake_pass_type_items[] = {
#include "IMB_colormanagement.h"
#include "GPU_extensions.h"
+#include "DEG_depsgraph_query.h"
+
/* RenderEngine Callbacks */
static void engine_tag_redraw(RenderEngine *engine)
@@ -146,7 +150,7 @@ static void engine_unbind_display_space_shader(RenderEngine *UNUSED(engine))
IMB_colormanagement_finish_glsl_draw();
}
-static void engine_update(RenderEngine *engine, Main *bmain, Scene *scene)
+static void engine_update(RenderEngine *engine, Main *bmain, Depsgraph *depsgraph)
{
extern FunctionRNA rna_RenderEngine_update_func;
PointerRNA ptr;
@@ -158,13 +162,13 @@ static void engine_update(RenderEngine *engine, Main *bmain, Scene *scene)
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "data", &bmain);
- RNA_parameter_set_lookup(&list, "scene", &scene);
+ RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph);
engine->type->ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
-static void engine_render(RenderEngine *engine, struct Scene *scene)
+static void engine_render(RenderEngine *engine, Depsgraph *depsgraph)
{
extern FunctionRNA rna_RenderEngine_render_func;
PointerRNA ptr;
@@ -175,13 +179,13 @@ static void engine_render(RenderEngine *engine, struct Scene *scene)
func = &rna_RenderEngine_render_func;
RNA_parameter_list_create(&list, &ptr, func);
- RNA_parameter_set_lookup(&list, "scene", &scene);
+ RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph);
engine->type->ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
-static void engine_bake(RenderEngine *engine, struct Scene *scene,
+static void engine_bake(RenderEngine *engine, struct Depsgraph *depsgraph,
struct Object *object, const int pass_type, const int pass_filter,
const int object_id, const struct BakePixel *pixel_array,
const int num_pixels, const int depth, void *result)
@@ -195,7 +199,7 @@ static void engine_bake(RenderEngine *engine, struct Scene *scene,
func = &rna_RenderEngine_bake_func;
RNA_parameter_list_create(&list, &ptr, func);
- RNA_parameter_set_lookup(&list, "scene", &scene);
+ RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph);
RNA_parameter_set_lookup(&list, "object", &object);
RNA_parameter_set_lookup(&list, "pass_type", &pass_type);
RNA_parameter_set_lookup(&list, "pass_filter", &pass_filter);
@@ -261,7 +265,7 @@ static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *nt
RNA_parameter_list_free(&list);
}
-static void engine_update_render_passes(RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl)
+static void engine_update_render_passes(RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer)
{
extern FunctionRNA rna_RenderEngine_update_render_passes_func;
PointerRNA ptr;
@@ -273,7 +277,7 @@ static void engine_update_render_passes(RenderEngine *engine, struct Scene *scen
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "scene", &scene);
- RNA_parameter_set_lookup(&list, "renderlayer", &srl);
+ RNA_parameter_set_lookup(&list, "renderlayer", &view_layer);
engine->type->ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
@@ -303,7 +307,7 @@ static StructRNA *rna_RenderEngine_register(
RenderEngineType *et, dummyet = {NULL};
RenderEngine dummyengine = {NULL};
PointerRNA dummyptr;
- int have_function[7];
+ int have_function[8];
/* setup dummy engine & engine type to store static properties in */
dummyengine.type = &dummyet;
@@ -347,7 +351,7 @@ static StructRNA *rna_RenderEngine_register(
et->update_script_node = (have_function[5]) ? engine_update_script_node : NULL;
et->update_render_passes = (have_function[6]) ? engine_update_render_passes : NULL;
- BLI_addtail(&R_engines, et);
+ RE_engines_register(et);
return et->ext.srna;
}
@@ -381,10 +385,11 @@ static PointerRNA rna_RenderEngine_render_get(PointerRNA *ptr)
static PointerRNA rna_RenderEngine_camera_override_get(PointerRNA *ptr)
{
RenderEngine *engine = (RenderEngine *)ptr->data;
-
+ /* TODO(sergey): Shouldn't engine point to an evaluated datablocks already? */
if (engine->re) {
Object *cam = RE_GetCamera(engine->re);
- return rna_pointer_inherit_refine(ptr, &RNA_Object, cam);
+ Object *cam_eval = DEG_get_evaluated_object(engine->depsgraph, cam);
+ return rna_pointer_inherit_refine(ptr, &RNA_Object, cam_eval);
}
else {
return rna_pointer_inherit_refine(ptr, &RNA_Object, engine->camera_override);
@@ -482,17 +487,18 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Export scene data for render");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "data", "BlendData", "", "");
- RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
func = RNA_def_function(srna, "render", NULL);
RNA_def_function_ui_description(func, "Render scene into an image");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
- RNA_def_pointer(func, "scene", "Scene", "", "");
+ parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "bake", NULL);
RNA_def_function_ui_description(func, "Bake passes");
RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
- parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ parm = RNA_def_pointer(func, "depsgraph", "Depsgraph", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "object", "Object", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
@@ -530,6 +536,12 @@ static void rna_def_render_engine(BlenderRNA *brna)
parm = RNA_def_pointer(func, "node", "Node", "", "");
RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
+ func = RNA_def_function(srna, "update_render_passes", NULL);
+ RNA_def_function_ui_description(func, "Update the render passes that will be generated");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
+ parm = RNA_def_pointer(func, "renderlayer", "ViewLayer", "", "");
+
/* tag for redraw */
func = RNA_def_function(srna, "tag_redraw", "engine_tag_redraw");
RNA_def_function_ui_description(func, "Request redraw for viewport rendering");
@@ -538,12 +550,6 @@ static void rna_def_render_engine(BlenderRNA *brna)
func = RNA_def_function(srna, "tag_update", "engine_tag_update");
RNA_def_function_ui_description(func, "Request update call for viewport rendering");
- func = RNA_def_function(srna, "update_render_passes", NULL);
- RNA_def_function_ui_description(func, "Update the render passes that will be generated");
- RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
- parm = RNA_def_pointer(func, "scene", "Scene", "", "");
- parm = RNA_def_pointer(func, "renderlayer", "SceneRenderLayer", "", "");
-
func = RNA_def_function(srna, "begin_result", "RE_engine_begin_result");
RNA_def_function_ui_description(func, "Create render result to write linear floating point render layers and passes");
parm = RNA_def_int(func, "x", 0, 0, INT_MAX, "X", "", 0, INT_MAX);
@@ -679,6 +685,9 @@ static void rna_def_render_engine(BlenderRNA *brna)
parm = RNA_def_int(func, "pixel_size", 0, 1, 8, "Pixel Size", "", 1, 8);
RNA_def_function_return(func, parm);
+ RNA_def_function(srna, "free_blender_memory", "RE_engine_free_blender_memory");
+ RNA_def_function_ui_description(func, "Free Blender side memory of render engine");
+
RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "is_animation", PROP_BOOLEAN, PROP_NONE);
@@ -719,17 +728,17 @@ static void rna_def_render_engine(BlenderRNA *brna)
func = RNA_def_function(srna, "register_pass", "RE_engine_register_pass");
RNA_def_function_ui_description(func, "Register a render pass that will be part of the render with the current settings");
- prop = RNA_def_pointer(func, "scene", "Scene", "", "");
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- prop = RNA_def_pointer(func, "srl", "SceneRenderLayer", "", "");
+ parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- prop = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
+ parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- prop = RNA_def_int(func, "channels", 1, 1, 8, "Channels", "", 1, 4);
+ parm = RNA_def_int(func, "channels", 1, 1, 8, "Channels", "", 1, 4);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- prop = RNA_def_string(func, "chanid", NULL, 8, "Channel IDs", "");
+ parm = RNA_def_string(func, "chanid", NULL, 8, "Channel IDs", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- prop = RNA_def_enum(func, "type", render_pass_type_items, SOCK_FLOAT, "Type", "");
+ parm = RNA_def_enum(func, "type", render_pass_type_items, SOCK_FLOAT, "Type", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* registration */
@@ -902,7 +911,7 @@ static void rna_def_render_layer(BlenderRNA *brna)
RNA_define_verify_sdna(0);
- rna_def_render_layer_common(srna, 0);
+ rna_def_view_layer_common(srna, 0);
prop = RNA_def_property(srna, "passes", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "RenderPass");
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index 5b86ec6b10d..e0d0ae57b30 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -33,7 +33,7 @@
#include "rna_internal.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
@@ -97,7 +97,6 @@ static const EnumPropertyItem rigidbody_mesh_source_items[] = {
# include "RBI_api.h"
#endif
-#include "BKE_depsgraph.h"
#include "BKE_rigidbody.h"
#include "WM_api.h"
@@ -131,8 +130,8 @@ static void rna_RigidBodyWorld_num_solver_iterations_set(PointerRNA *ptr, int va
rbw->num_solver_iterations = value;
#ifdef WITH_BULLET
- if (rbw->physics_world) {
- RB_dworld_set_solver_iterations(rbw->physics_world, value);
+ if (rbw->shared->physics_world) {
+ RB_dworld_set_solver_iterations(rbw->shared->physics_world, value);
}
#endif
}
@@ -144,8 +143,8 @@ static void rna_RigidBodyWorld_split_impulse_set(PointerRNA *ptr, bool value)
RB_FLAG_SET(rbw->flag, value, RBW_FLAG_USE_SPLIT_IMPULSE);
#ifdef WITH_BULLET
- if (rbw->physics_world) {
- RB_dworld_set_split_impulse(rbw->physics_world, value);
+ if (rbw->shared->physics_world) {
+ RB_dworld_set_split_impulse(rbw->shared->physics_world, value);
}
#endif
}
@@ -174,7 +173,7 @@ static void rna_RigidBodyOb_shape_reset(Main *UNUSED(bmain), Scene *scene, Point
RigidBodyOb *rbo = (RigidBodyOb *)ptr->data;
BKE_rigidbody_cache_reset(rbw);
- if (rbo->physics_shape)
+ if (rbo->shared->physics_shape)
rbo->flag |= RBO_FLAG_NEEDS_RESHAPE;
}
@@ -208,9 +207,9 @@ static void rna_RigidBodyOb_disabled_set(PointerRNA *ptr, bool value)
#ifdef WITH_BULLET
/* update kinematic state if necessary - only needed for active bodies */
- if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
- RB_body_set_kinematic_state(rbo->physics_object, !value);
+ if ((rbo->shared->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
+ RB_body_set_kinematic_state(rbo->shared->physics_object, !value);
rbo->flag |= RBO_FLAG_NEEDS_VALIDATE;
}
#endif
@@ -224,8 +223,8 @@ static void rna_RigidBodyOb_mass_set(PointerRNA *ptr, float value)
#ifdef WITH_BULLET
/* only active bodies need mass update */
- if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
+ if ((rbo->shared->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
}
#endif
}
@@ -237,8 +236,8 @@ static void rna_RigidBodyOb_friction_set(PointerRNA *ptr, float value)
rbo->friction = value;
#ifdef WITH_BULLET
- if (rbo->physics_object) {
- RB_body_set_friction(rbo->physics_object, value);
+ if (rbo->shared->physics_object) {
+ RB_body_set_friction(rbo->shared->physics_object, value);
}
#endif
}
@@ -249,8 +248,8 @@ static void rna_RigidBodyOb_restitution_set(PointerRNA *ptr, float value)
rbo->restitution = value;
#ifdef WITH_BULLET
- if (rbo->physics_object) {
- RB_body_set_restitution(rbo->physics_object, value);
+ if (rbo->shared->physics_object) {
+ RB_body_set_restitution(rbo->shared->physics_object, value);
}
#endif
}
@@ -262,13 +261,13 @@ static void rna_RigidBodyOb_collision_margin_set(PointerRNA *ptr, float value)
rbo->margin = value;
#ifdef WITH_BULLET
- if (rbo->physics_shape) {
- RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo));
+ if (rbo->shared->physics_shape) {
+ RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo));
}
#endif
}
-static void rna_RigidBodyOb_collision_groups_set(PointerRNA *ptr, const bool *values)
+static void rna_RigidBodyOb_collision_collections_set(PointerRNA *ptr, const bool *values)
{
RigidBodyOb *rbo = (RigidBodyOb *)ptr->data;
int i;
@@ -290,9 +289,9 @@ static void rna_RigidBodyOb_kinematic_state_set(PointerRNA *ptr, bool value)
#ifdef WITH_BULLET
/* update kinematic state if necessary */
- if (rbo->physics_object) {
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
- RB_body_set_kinematic_state(rbo->physics_object, value);
+ if (rbo->shared->physics_object) {
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
+ RB_body_set_kinematic_state(rbo->shared->physics_object, value);
rbo->flag |= RBO_FLAG_NEEDS_VALIDATE;
}
#endif
@@ -306,8 +305,8 @@ static void rna_RigidBodyOb_activation_state_set(PointerRNA *ptr, bool value)
#ifdef WITH_BULLET
/* update activation state if necessary - only active bodies can be deactivated */
- if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
- RB_body_set_activation_state(rbo->physics_object, value);
+ if ((rbo->shared->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
+ RB_body_set_activation_state(rbo->shared->physics_object, value);
}
#endif
}
@@ -320,8 +319,8 @@ static void rna_RigidBodyOb_linear_sleepThresh_set(PointerRNA *ptr, float value)
#ifdef WITH_BULLET
/* only active bodies need sleep threshold update */
- if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
- RB_body_set_linear_sleep_thresh(rbo->physics_object, value);
+ if ((rbo->shared->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
+ RB_body_set_linear_sleep_thresh(rbo->shared->physics_object, value);
}
#endif
}
@@ -334,8 +333,8 @@ static void rna_RigidBodyOb_angular_sleepThresh_set(PointerRNA *ptr, float value
#ifdef WITH_BULLET
/* only active bodies need sleep threshold update */
- if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
- RB_body_set_angular_sleep_thresh(rbo->physics_object, value);
+ if ((rbo->shared->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
+ RB_body_set_angular_sleep_thresh(rbo->shared->physics_object, value);
}
#endif
}
@@ -348,8 +347,8 @@ static void rna_RigidBodyOb_linear_damping_set(PointerRNA *ptr, float value)
#ifdef WITH_BULLET
/* only active bodies need damping update */
- if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
- RB_body_set_linear_damping(rbo->physics_object, value);
+ if ((rbo->shared->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
+ RB_body_set_linear_damping(rbo->shared->physics_object, value);
}
#endif
}
@@ -362,8 +361,8 @@ static void rna_RigidBodyOb_angular_damping_set(PointerRNA *ptr, float value)
#ifdef WITH_BULLET
/* only active bodies need damping update */
- if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
- RB_body_set_angular_damping(rbo->physics_object, value);
+ if ((rbo->shared->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
+ RB_body_set_angular_damping(rbo->shared->physics_object, value);
}
#endif
}
@@ -729,8 +728,8 @@ static void rna_RigidBodyWorld_convex_sweep_test(
#ifdef WITH_BULLET
RigidBodyOb *rob = object->rigidbody_object;
- if (rbw->physics_world != NULL && rob->physics_object != NULL) {
- RB_world_convex_sweep_test(rbw->physics_world, rob->physics_object, ray_start, ray_end,
+ if (rbw->shared->physics_world != NULL && rob->shared->physics_object != NULL) {
+ RB_world_convex_sweep_test(rbw->shared->physics_world, rob->shared->physics_object, ray_start, ray_end,
r_location, r_hitpoint, r_normal, r_hit);
if (*r_hit == -2) {
BKE_report(reports, RPT_ERROR,
@@ -746,6 +745,13 @@ static void rna_RigidBodyWorld_convex_sweep_test(
#endif
}
+static PointerRNA rna_RigidBodyWorld_PointCache_get(PointerRNA *ptr)
+{
+ RigidBodyWorld *rbw = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_PointCache, rbw->shared->pointcache);
+}
+
+
#else
static void rna_def_rigidbody_world(BlenderRNA *brna)
@@ -762,16 +768,17 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_RigidBodyWorld_path");
/* groups */
- prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Group");
+ prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_pointer_sdna(prop, NULL, "group");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_ui_text(prop, "Group", "Group containing objects participating in this simulation");
+ RNA_def_property_ui_text(prop, "Collection", "Collection containing objects participating in this simulation");
RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset");
prop = RNA_def_property(srna, "constraints", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Group");
+ RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_ui_text(prop, "Constraints", "Group containing rigid body constraint objects");
+ RNA_def_property_ui_text(prop, "Constraints", "Collection containing rigid body constraint objects");
RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset");
/* booleans */
@@ -824,7 +831,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
/* cache */
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "pointcache");
+ RNA_def_property_pointer_funcs(prop, "rna_RigidBodyWorld_PointCache_get", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "PointCache");
RNA_def_property_ui_text(prop, "Point Cache", "");
@@ -1018,11 +1025,11 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
"(best results when non-zero)");
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_shape_reset");
- prop = RNA_def_property(srna, "collision_groups", PROP_BOOLEAN, PROP_LAYER_MEMBER);
+ prop = RNA_def_property(srna, "collision_collections", PROP_BOOLEAN, PROP_LAYER_MEMBER);
RNA_def_property_boolean_sdna(prop, NULL, "col_groups", 1);
RNA_def_property_array(prop, 20);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_collision_groups_set");
- RNA_def_property_ui_text(prop, "Collision Groups", "Collision Groups Rigid Body belongs to");
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_collision_collections_set");
+ RNA_def_property_ui_text(prop, "Collision Collections", "Collision collections rigid body belongs to");
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
}
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index b8a9e9f92cd..d5755387ba0 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -131,6 +131,9 @@ const EnumPropertyItem rna_enum_property_unit_items[] = {
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
+#include "BLI_string.h"
+
+#include "BKE_library_override.h"
/* Struct */
@@ -589,6 +592,13 @@ static bool rna_Property_animatable_get(PointerRNA *ptr)
return (prop->flag & PROP_ANIMATABLE) != 0;
}
+static bool rna_Property_overridable_get(PointerRNA *ptr)
+{
+ PropertyRNA *prop = (PropertyRNA *)ptr->data;
+
+ return (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_STATIC) != 0;
+}
+
static bool rna_Property_use_output_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
@@ -741,46 +751,27 @@ static bool rna_NumberProperty_is_array_get(PointerRNA *ptr)
static void rna_IntProperty_default_array_get(PointerRNA *ptr, int *values)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- IntPropertyRNA *nprop = (IntPropertyRNA *)prop;
rna_idproperty_check(&prop, ptr);
-
- if (nprop->defaultarray) {
- memcpy(values, nprop->defaultarray, prop->totarraylength * sizeof(int));
- }
- else {
- int i;
- for (i = 0; i < prop->totarraylength; i++)
- values[i] = nprop->defaultvalue;
+ if (prop->totarraylength > 0) {
+ RNA_property_int_get_default_array(ptr, prop, values);
}
}
+
static void rna_BoolProperty_default_array_get(PointerRNA *ptr, bool *values)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- BoolPropertyRNA *nprop = (BoolPropertyRNA *)prop;
rna_idproperty_check(&prop, ptr);
-
- if (nprop->defaultarray) {
- memcpy(values, nprop->defaultarray, prop->totarraylength * sizeof(bool));
- }
- else {
- int i;
- for (i = 0; i < prop->totarraylength; i++)
- values[i] = nprop->defaultvalue;
+ if (prop->totarraylength > 0) {
+ RNA_property_boolean_get_default_array(ptr, prop, values);
}
}
+
static void rna_FloatProperty_default_array_get(PointerRNA *ptr, float *values)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- FloatPropertyRNA *nprop = (FloatPropertyRNA *)prop;
rna_idproperty_check(&prop, ptr);
-
- if (nprop->defaultarray) {
- memcpy(values, nprop->defaultarray, prop->totarraylength * sizeof(float));
- }
- else {
- int i;
- for (i = 0; i < prop->totarraylength; i++)
- values[i] = nprop->defaultvalue;
+ if (prop->totarraylength > 0) {
+ RNA_property_float_get_default_array(ptr, prop, values);
}
}
@@ -1107,6 +1098,1131 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key
return false;
}
+/* Default override (and compare) callbacks. */
+
+/* Ensures it makes sense to go inside the pointers to compare their content
+ * (if they are IDs, or have different names or RNA type, then this would be meaningless). */
+static bool rna_property_override_diff_propptr_validate_diffing(
+ PointerRNA *propptr_a, PointerRNA *propptr_b, const bool no_prop_name,
+ bool *r_is_id, bool *r_is_null, bool *r_is_type_diff,
+ char **r_propname_a, char *propname_a_buff, size_t propname_a_buff_size,
+ char **r_propname_b, char *propname_b_buff, size_t propname_b_buff_size)
+{
+ BLI_assert(propptr_a != NULL);
+
+ bool is_valid_for_diffing = true;
+ const bool do_force_name = !no_prop_name && r_propname_a != NULL;
+
+ if (do_force_name) {
+ BLI_assert(r_propname_a != NULL);
+ BLI_assert(r_propname_b != NULL);
+ }
+
+ *r_is_id = *r_is_null = *r_is_type_diff = false;
+
+ /* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */
+ if (propptr_a->type == NULL) {
+ if (propptr_b == NULL || propptr_b->type == NULL) {
+ *r_is_null = true;
+ }
+ else {
+ *r_is_id = RNA_struct_is_ID(propptr_b->type);
+ *r_is_null = true;
+ *r_is_type_diff = true;
+ }
+ is_valid_for_diffing = false;
+ }
+ else {
+ *r_is_id = RNA_struct_is_ID(propptr_a->type);
+ *r_is_null = *r_is_type_diff = (ELEM(NULL, propptr_b, propptr_b->type));
+ is_valid_for_diffing = !(*r_is_id || *r_is_null);
+ }
+
+ if (propptr_b == NULL || propptr_a->type != propptr_b->type) {
+ *r_is_type_diff = true;
+ is_valid_for_diffing = false;
+// printf("%s: different pointer RNA types\n", rna_path ? rna_path : "<UNKNOWN>");
+ }
+
+ /* We do a generic quick first comparison checking for "name" and/or "type" properties.
+ * We assume that is any of those are false, then we are not handling the same data.
+ * This helps a lot in static override case, especially to detect inserted items in collections. */
+ if (!no_prop_name && (is_valid_for_diffing || do_force_name)) {
+ PropertyRNA *nameprop_a = RNA_struct_name_property(propptr_a->type);
+ PropertyRNA *nameprop_b = (propptr_b != NULL) ? RNA_struct_name_property(propptr_b->type) : NULL;
+
+ int propname_a_len = 0, propname_b_len = 0;
+ char *propname_a = NULL;
+ char *propname_b = NULL;
+ char buff_a[4096];
+ char buff_b[4096];
+ if (nameprop_a != NULL) {
+ if (r_propname_a == NULL && propname_a_buff == NULL) {
+ propname_a_buff = buff_a;
+ propname_a_buff_size = sizeof(buff_a);
+ }
+
+ propname_a = RNA_property_string_get_alloc(
+ propptr_a, nameprop_a, propname_a_buff, propname_a_buff_size, &propname_a_len);
+// printf("propname_a = %s\n", propname_a ? propname_a : "<NONE>");
+
+ if (r_propname_a != NULL) {
+ *r_propname_a = propname_a;
+ }
+ }
+// else printf("item of type %s a has no name property!\n", propptr_a->type->name);
+ if (nameprop_b != NULL) {
+ if (r_propname_b == NULL && propname_b_buff == NULL) {
+ propname_b_buff = buff_b;
+ propname_b_buff_size = sizeof(buff_b);
+ }
+
+ propname_b = RNA_property_string_get_alloc(
+ propptr_b, nameprop_b, propname_b_buff, propname_b_buff_size, &propname_b_len);
+
+ if (r_propname_b != NULL) {
+ *r_propname_b = propname_b;
+ }
+ }
+ if (propname_a != NULL && propname_b != NULL) {
+ if (propname_a_len != propname_b_len ||
+ propname_a[0] != propname_b[0] ||
+ !STREQ(propname_a, propname_b))
+ {
+ is_valid_for_diffing = false;
+// printf("%s: different names\n", rna_path ? rna_path : "<UNKNOWN>");
+ }
+ }
+ }
+
+ if (*r_is_id) {
+ BLI_assert(propptr_a->data == propptr_a->id.data && propptr_b->data == propptr_b->id.data);
+ }
+
+ return is_valid_for_diffing;
+}
+
+/* Used for both Pointer and Collection properties. */
+static int rna_property_override_diff_propptr(
+ Main *bmain,
+ PointerRNA *propptr_a, PointerRNA *propptr_b,
+ eRNACompareMode mode, const bool no_ownership, const bool no_prop_name,
+ IDOverrideStatic *override, const char *rna_path, const int flags, bool *r_override_changed)
+{
+ const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
+
+ bool is_id = false;
+ bool is_null = false;
+ bool is_type_diff = false;
+ /* If false, it means that the whole data itself is different, so no point in going inside of it at all! */
+ bool is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(
+ propptr_a, propptr_b, no_prop_name, &is_id, &is_null, &is_type_diff,
+ NULL, NULL, 0, NULL, NULL, 0);
+
+ if (is_id) {
+ BLI_assert(no_ownership); /* For now, once we deal with nodetrees we'll want to get rid of that one. */
+ }
+
+ if (override) {
+ if (no_ownership /* || is_id */ || is_null || is_type_diff || !is_valid_for_diffing) {
+ /* In case this pointer prop does not own its data (or one is NULL), do not compare structs!
+ * This is a quite safe path to infinite loop, among other nasty issues.
+ * Instead, just compare pointers themselves. */
+ const int comp = (propptr_a->data != propptr_b->data);
+
+ if (do_create && comp != 0) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ else {
+ eRNAOverrideMatchResult report_flags = 0;
+ const bool match = RNA_struct_override_matches(
+ bmain, propptr_a, propptr_b, rna_path, override, flags, &report_flags);
+ if (r_override_changed && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) != 0) {
+ *r_override_changed = true;
+ }
+ return !match;
+ }
+ }
+ else {
+ /* We could also use is_diff_pointer, but then we potentially lose the gt/lt info -
+ * and don't think performances are critical here for now anyway... */
+ return !RNA_struct_equals(bmain, propptr_a, propptr_b, mode);
+ }
+}
+
+
+
+#define RNA_PROPERTY_GET_SINGLE(_typename, _ptr, _prop, _index) \
+ (is_array ? RNA_property_##_typename##_get_index((_ptr), (_prop), (_index)) : \
+ RNA_property_##_typename##_get((_ptr), (_prop)))
+#define RNA_PROPERTY_SET_SINGLE(_typename, _ptr, _prop, _index, _value) \
+ (is_array ? RNA_property_##_typename##_set_index((_ptr), (_prop), (_index), (_value)) : \
+ RNA_property_##_typename##_set((_ptr), (_prop), (_value)))
+
+int rna_property_override_diff_default(
+ Main *bmain,
+ PointerRNA *ptr_a, PointerRNA *ptr_b,
+ PropertyRNA *prop_a, PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed)
+{
+ BLI_assert(len_a == len_b);
+
+ /* Note: at this point, we are sure that when len_a is zero, we are not handling an (empty) array. */
+
+ const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
+
+ switch (RNA_property_type(prop_a)) {
+ case PROP_BOOLEAN:
+ {
+ if (len_a) {
+ bool array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ bool *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(bool) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(bool) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_boolean_get_array(ptr_a, prop_a, array_a);
+ RNA_property_boolean_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(bool) * len_a);
+
+ if (do_create && comp != 0) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overridden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const bool value_a = RNA_property_boolean_get(ptr_a, prop_a);
+ const bool value_b = RNA_property_boolean_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (do_create && comp != 0) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ }
+
+ case PROP_INT:
+ {
+ if (len_a) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_int_get_array(ptr_a, prop_a, array_a);
+ RNA_property_int_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
+
+ if (do_create && comp != 0) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overridden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const int value_a = RNA_property_int_get(ptr_a, prop_a);
+ const int value_b = RNA_property_int_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (do_create && comp != 0) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ }
+
+ case PROP_FLOAT:
+ {
+ if (len_a) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_float_get_array(ptr_a, prop_a, array_a);
+ RNA_property_float_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(float) * len_a);
+
+ if (do_create && comp != 0) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE,
+ NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overridden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const float value_a = RNA_property_float_get(ptr_a, prop_a);
+ const float value_b = RNA_property_float_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (do_create && comp != 0) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE,
+ NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp ;
+ }
+ }
+
+ case PROP_ENUM:
+ {
+ const int value_a = RNA_property_enum_get(ptr_a, prop_a);
+ const int value_b = RNA_property_enum_get(ptr_b, prop_b);
+ const int comp = value_a != value_b;
+
+ if (do_create && comp != 0) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+
+ case PROP_STRING:
+ {
+ char fixed_a[4096], fixed_b[4096];
+ int len_str_a, len_str_b;
+ char *value_a = RNA_property_string_get_alloc(ptr_a, prop_a, fixed_a, sizeof(fixed_a), &len_str_a);
+ char *value_b = RNA_property_string_get_alloc(ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b);
+ /* TODO we could do a check on length too, but then we would not have a 'real' string comparison...
+ * Maybe behind a eRNAOverrideMatch flag? */
+// const int comp = len_str_a < len_str_b ? -1 : len_str_a > len_str_b ? 1 : strcmp(value_a, value_b);
+ const int comp = strcmp(value_a, value_b);
+
+ if (do_create && comp != 0) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ if (value_a != fixed_a) MEM_freeN(value_a);
+ if (value_b != fixed_b) MEM_freeN(value_b);
+
+ return comp;
+ }
+
+ case PROP_POINTER:
+ {
+ if (STREQ(RNA_property_identifier(prop_a), "rna_type")) {
+ /* Dummy 'pass' answer, this is a meta-data and must be ignored... */
+ return 0;
+ }
+ else {
+ PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a);
+ PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b);
+ const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
+ const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0;
+ return rna_property_override_diff_propptr(
+ bmain,
+ &propptr_a, &propptr_b, mode, no_ownership, no_prop_name,
+ override, rna_path, flags, r_override_changed);
+ }
+ break;
+ }
+
+ case PROP_COLLECTION:
+ {
+ /* Note: we assume we only insert in ptr_a (i.e. we can only get new items in ptr_a),
+ * and that we never remove anything. */
+ const bool use_insertion = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_STATIC_INSERTION) && do_create;
+ const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0;
+ bool equals = true;
+ bool abort = false;
+ bool is_first_insert = true;
+ int idx_a = 0;
+ int idx_b = 0;
+
+#define RNA_PATH_BUFFSIZE 8192
+
+ char extended_rna_path_buffer[RNA_PATH_BUFFSIZE];
+ char *extended_rna_path = extended_rna_path_buffer;
+
+#define RNA_PATH_PRINTF(_str, ...) \
+ if (BLI_snprintf(extended_rna_path_buffer, RNA_PATH_BUFFSIZE, \
+ (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE - 1) \
+ { extended_rna_path = BLI_sprintfN((_str), __VA_ARGS__); }(void)0
+#define RNA_PATH_FREE() \
+ if (extended_rna_path != extended_rna_path_buffer) MEM_freeN(extended_rna_path)
+
+ CollectionPropertyIterator iter_a, iter_b;
+ RNA_property_collection_begin(ptr_a, prop_a, &iter_a);
+ RNA_property_collection_begin(ptr_b, prop_b, &iter_b);
+
+ char buff_a[4096];
+ char buff_prev_a[4096] = {0};
+ char buff_b[4096];
+ char *propname_a = NULL;
+ char *prev_propname_a = buff_prev_a;
+ char *propname_b = NULL;
+
+ for (; iter_a.valid && !abort; ) {
+ bool is_valid_for_diffing;
+ bool is_valid_for_insertion;
+ do {
+ bool is_id = false, is_null = false, is_type_diff = false;
+
+ is_valid_for_insertion = use_insertion;
+
+ /* If false, it means that the whole data itself is different, so no point in going inside of it at all! */
+ if (iter_b.valid) {
+ is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(
+ &iter_a.ptr, &iter_b.ptr, no_prop_name,
+ &is_id, &is_null, &is_type_diff,
+ &propname_a, buff_a, sizeof(buff_a),
+ &propname_b, buff_b, sizeof(buff_b));
+ }
+ else {
+ is_valid_for_diffing = false;
+ if (is_valid_for_insertion) {
+ /* We still need propname from 'a' item... */
+ rna_property_override_diff_propptr_validate_diffing(
+ &iter_a.ptr, NULL, no_prop_name,
+ &is_id, &is_null, &is_type_diff,
+ &propname_a, buff_a, sizeof(buff_a),
+ &propname_b, buff_b, sizeof(buff_b));
+ }
+ }
+
+ /* We do not support insertion of IDs for now, neither handle NULL pointers. */
+ if (is_id || is_valid_for_diffing) {
+ is_valid_for_insertion = false;
+ }
+
+#if 0
+ if (rna_path) {
+ printf("Checking %s, %s [%d] vs %s [%d]; is_id: %d, diffing: %d; "
+ "insert: %d (could be used: %d, do_create: %d)\n",
+ rna_path, propname_a ? propname_a : "", idx_a, propname_b ? propname_b : "", idx_b,
+ is_id, is_valid_for_diffing, is_valid_for_insertion,
+ (RNA_property_override_flag(prop_a) & PROPOVERRIDE_STATIC_INSERTION) != 0, do_create);
+ }
+#endif
+
+ if (!(is_id || is_valid_for_diffing || is_valid_for_insertion)) {
+ /* Differences we cannot handle, we can break here
+ * (we do not support replacing ID pointers in collections e.g.). */
+ equals = false;
+ abort = true;
+ break;
+ }
+
+ /* There may be a propname defined in some cases, while no actual name set
+ * (e.g. happens with point cache), in that case too we want to fall back to index.
+ * Note that we do not need the RNA path for insertion operations. */
+ if (is_id || is_valid_for_diffing) {
+ if ((propname_a != NULL && propname_a[0] != '\0') &&
+ (propname_b != NULL && propname_b[0] != '\0'))
+ {
+ if (rna_path) {
+ /* In case of name, either it is valid for diffing, and _a and _b are identical,
+ * or it is valid for insertion, and we need to use _a. */
+ char esc_item_name[RNA_PATH_BUFFSIZE];
+ BLI_strescape(esc_item_name, propname_a, RNA_PATH_BUFFSIZE);
+ RNA_PATH_PRINTF("%s[\"%s\"]", rna_path, esc_item_name);
+ }
+ }
+ else { /* Based on index... */
+ if (rna_path) {
+ /* In case of indices, we need _a one for insertion, but _b ones for in-depth diffing.
+ * Insertion always happen once all 'replace' operations have been done,
+ * otherwise local and reference paths for those would have to be different! */
+ RNA_PATH_PRINTF("%s[%d]", rna_path, is_valid_for_insertion ? idx_a : idx_b);
+ }
+ }
+ }
+
+ /* Collections do not support replacement of their data (since they do not support removing),
+ * only in *some* cases, insertion.
+ * We also assume then that _a data is the one where things are inserted. */
+ if (is_valid_for_insertion && use_insertion) {
+ bool created;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (is_first_insert) {
+ /* We need to clean up all possible existing insertion operations, otherwise we'd end up
+ * with a mess of ops everytime something changes. */
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first;
+ opop != NULL;)
+ {
+ IDOverrideStaticPropertyOperation *opop_next = opop->next;
+ if (ELEM(opop->operation,
+ IDOVERRIDESTATIC_OP_INSERT_AFTER, IDOVERRIDESTATIC_OP_INSERT_BEFORE))
+ {
+ BKE_override_static_property_operation_delete(op, opop);
+ }
+ opop = opop_next;
+ }
+ is_first_insert = false;
+ }
+
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_INSERT_AFTER,
+ NULL, prev_propname_a, -1, idx_a - 1, true, NULL, NULL);
+// printf("%s: Adding insertion op override after '%s'/%d\n", rna_path, prev_propname_a, idx_a - 1);
+ }
+ else if (is_id || is_valid_for_diffing) {
+ if (equals || do_create) {
+ const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
+ const int eq = rna_property_override_diff_propptr(
+ bmain,
+ &iter_a.ptr, &iter_b.ptr, mode, no_ownership, no_prop_name,
+ override, extended_rna_path, flags, r_override_changed);
+ equals = equals && eq;
+ }
+ }
+
+ if (prev_propname_a != buff_prev_a) {
+ MEM_freeN(prev_propname_a);
+ prev_propname_a = buff_prev_a;
+ }
+ prev_propname_a[0] = '\0';
+ if (propname_a != NULL &&
+ BLI_strncpy_rlen(prev_propname_a, propname_a, sizeof(buff_prev_a)) >= sizeof(buff_prev_a) - 1)
+ {
+ prev_propname_a = BLI_strdup(propname_a);
+ }
+ if (propname_a != buff_a) {
+ MEM_SAFE_FREE(propname_a);
+ propname_a = buff_a;
+ }
+ propname_a[0] = '\0';
+ if (propname_b != buff_b) {
+ MEM_SAFE_FREE(propname_b);
+ propname_b = buff_b;
+ }
+ propname_b[0] = '\0';
+ RNA_PATH_FREE();
+
+ if (!do_create && !equals) {
+ abort = true; /* Early out in case we do not want to loop over whole collection. */
+ break;
+ }
+
+ if (!(use_insertion && !(is_id || is_valid_for_diffing))) {
+ break;
+ }
+
+ if (iter_a.valid) {
+ RNA_property_collection_next(&iter_a);
+ idx_a++;
+ }
+ } while (iter_a.valid);
+
+ if (iter_a.valid) {
+ RNA_property_collection_next(&iter_a);
+ idx_a++;
+ }
+ if (iter_b.valid) {
+ RNA_property_collection_next(&iter_b);
+ idx_b++;
+ }
+
+#undef RNA_PATH_BUFFSIZE
+#undef RNA_PATH_PRINTF
+#undef RNA_PATH_FREE
+ }
+
+ equals = equals && !(iter_a.valid || iter_b.valid) && !abort; /* Not same number of items in both collections... */
+ RNA_property_collection_end(&iter_a);
+ RNA_property_collection_end(&iter_b);
+
+ return (equals == false);
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+bool rna_property_override_store_default(
+ Main *UNUSED(bmain),
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(len_local == len_reference && (!ptr_storage || len_local == len_storage));
+ UNUSED_VARS_NDEBUG(len_reference, len_storage);
+
+ bool changed = false;
+ const bool is_array = len_local > 0;
+ const int index = is_array ? opop->subitem_reference_index : 0;
+
+ if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) {
+ return changed;
+ }
+
+ /* XXX TODO About range limits.
+ * Ideally, it would be great to get rid of RNA range in that specific case.
+ * However, this won't be that easy and will add yet another layer of complexity in generated code,
+ * not to mention that we could most likely *not* bypass custom setters anyway.
+ * So for now, if needed second operand value is not in valid range, we simply fall back
+ * to a mere REPLACE operation.
+ * Time will say whether this is acceptable limitation or not. */
+ switch (RNA_property_type(prop_local)) {
+ case PROP_BOOLEAN:
+ /* TODO support boolean ops? Really doubt this would ever be useful though... */
+ BLI_assert(0 && "Boolean properties support no override diff operation");
+ break;
+ case PROP_INT:
+ {
+ int prop_min, prop_max;
+ RNA_property_int_range(ptr_local, prop_local, &prop_min, &prop_max);
+
+ if (is_array && index == -1) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a;
+ RNA_property_int_get_array(ptr_reference, prop_reference, array_a);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_int_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = fac * (array_b[i] - array_a[i]);
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = other_op;
+ for (int j = len_local; j--;) {
+ array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
+ if (array_b[j] < prop_min || array_b[j] > prop_max) {
+ /* We failed to find a suitable diff op,
+ * fall back to plain REPLACE one. */
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_int_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ break;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const int value = RNA_PROPERTY_GET_SINGLE(int, ptr_reference, prop_reference, index);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ int b = fac * (RNA_PROPERTY_GET_SINGLE(int, ptr_local, prop_local, index) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_PROPERTY_SET_SINGLE(int, ptr_storage, prop_storage, index, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ break;
+ }
+ }
+ break;
+ }
+ case PROP_FLOAT:
+ {
+ float prop_min, prop_max;
+ RNA_property_float_range(ptr_local, prop_local, &prop_min, &prop_max);
+
+ if (is_array && index == -1) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a;
+
+ RNA_property_float_get_array(ptr_reference, prop_reference, array_a);
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0 : -1.0;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = fac * (array_b[i] - array_a[i]);
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = other_op;
+ for (int j = len_local; j--;) {
+ array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
+ if (array_b[j] < prop_min || array_b[j] > prop_max) {
+ /* We failed to find a suitable diff op,
+ * fall back to plain REPLACE one. */
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_float_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ {
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = array_a[i] == 0.0f ? array_b[i] : array_b[i] / array_a[i];
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_float_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ break;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const float value = RNA_PROPERTY_GET_SINGLE(float, ptr_reference, prop_reference, index);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0f : -1.0f;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ float b = fac * (RNA_PROPERTY_GET_SINGLE(float, ptr_local, prop_local, index) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_PROPERTY_SET_SINGLE(float, ptr_storage, prop_storage, index, b);
+ break;
+ }
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ {
+ const float b = RNA_property_float_get_index(ptr_local, prop_local, index) / (value == 0.0f ? 1.0f : value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ changed = true;
+ RNA_property_float_set_index(ptr_storage, prop_storage, index, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ break;
+ }
+ }
+ return true;
+ }
+ case PROP_ENUM:
+ /* TODO support add/sub, for bitflags? */
+ BLI_assert(0 && "Enum properties support no override diff operation");
+ break;
+ case PROP_POINTER:
+ BLI_assert(0 && "Pointer properties support no override diff operation");
+ break;
+ case PROP_STRING:
+ BLI_assert(0 && "String properties support no override diff operation");
+ break;
+ case PROP_COLLECTION:
+ /* XXX TODO support this of course... */
+ BLI_assert(0 && "Collection properties support no override diff operation");
+ break;
+ default:
+ break;
+ }
+
+ return changed;
+}
+
+bool rna_property_override_apply_default(
+ Main *UNUSED(bmain),
+ PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ PointerRNA *UNUSED(ptr_item_dst), PointerRNA *UNUSED(ptr_item_src), PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage));
+ UNUSED_VARS_NDEBUG(len_src, len_storage);
+
+ const bool is_array = len_dst > 0;
+ const int index = is_array ? opop->subitem_reference_index : 0;
+ const short override_op = opop->operation;
+
+ switch (RNA_property_type(prop_dst)) {
+ case PROP_BOOLEAN:
+ if (is_array && index == -1) {
+ bool array_stack_a[RNA_STACK_ARRAY];
+ bool *array_a;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ RNA_property_boolean_get_array(ptr_src, prop_src, array_a);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_boolean_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const bool value = RNA_PROPERTY_GET_SINGLE(boolean, ptr_src, prop_src, index);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_PROPERTY_SET_SINGLE(boolean, ptr_dst, prop_dst, index, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ return false;
+ }
+ }
+ return true;
+ case PROP_INT:
+ if (is_array && index == -1) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_int_get_array(ptr_src, prop_src, array_a);
+ RNA_property_int_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_int_get_array(ptr_dst, prop_dst, array_a);
+ array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b;
+ RNA_property_int_get_array(ptr_storage, prop_storage, array_b);
+ if (override_op == IDOVERRIDESTATIC_OP_ADD) {
+ for (int i = len_dst; i--;) array_a[i] += array_b[i];
+ }
+ else {
+ for (int i = len_dst; i--;) array_a[i] -= array_b[i];
+ }
+ RNA_property_int_set_array(ptr_dst, prop_dst, array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on integer");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const int storage_value = ptr_storage ? RNA_PROPERTY_GET_SINGLE(int, ptr_storage, prop_storage, index) : 0;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_PROPERTY_SET_SINGLE(int, ptr_dst, prop_dst, index,
+ RNA_PROPERTY_GET_SINGLE(int, ptr_src, prop_src, index));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_PROPERTY_SET_SINGLE(int, ptr_dst, prop_dst, index,
+ RNA_PROPERTY_GET_SINGLE(int, ptr_dst, prop_dst, index) - storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_PROPERTY_SET_SINGLE(int, ptr_dst, prop_dst, index,
+ RNA_PROPERTY_GET_SINGLE(int, ptr_dst, prop_dst, index) - storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on integer");
+ return false;
+ }
+ }
+ return true;
+ case PROP_FLOAT:
+ if (is_array && index == -1) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_float_get_array(ptr_src, prop_src, array_a);
+ RNA_property_float_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ RNA_property_float_get_array(ptr_dst, prop_dst, array_a);
+ array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_storage, prop_storage, array_b);
+ if (override_op == IDOVERRIDESTATIC_OP_ADD) {
+ for (int i = len_dst; i--;) array_a[i] += array_b[i];
+ }
+ else if (override_op == IDOVERRIDESTATIC_OP_SUBTRACT) {
+ for (int i = len_dst; i--;) array_a[i] -= array_b[i];
+ }
+ else {
+ for (int i = len_dst; i--;) array_a[i] *= array_b[i];
+ }
+ RNA_property_float_set_array(ptr_dst, prop_dst, array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on float");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const float storage_value = ptr_storage ? RNA_PROPERTY_GET_SINGLE(float, ptr_storage, prop_storage, index) : 0.0f;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_PROPERTY_SET_SINGLE(float, ptr_dst, prop_dst, index,
+ RNA_PROPERTY_GET_SINGLE(float, ptr_src, prop_src, index));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_PROPERTY_SET_SINGLE(float, ptr_dst, prop_dst, index,
+ RNA_PROPERTY_GET_SINGLE(float, ptr_dst, prop_dst, index) + storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_PROPERTY_SET_SINGLE(float, ptr_dst, prop_dst, index,
+ RNA_PROPERTY_GET_SINGLE(float, ptr_dst, prop_dst, index) - storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ RNA_PROPERTY_SET_SINGLE(float, ptr_dst, prop_dst, index,
+ RNA_PROPERTY_GET_SINGLE(float, ptr_dst, prop_dst, index) * storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on float");
+ return false;
+ }
+ }
+ return true;
+ case PROP_ENUM:
+ {
+ const int value = RNA_property_enum_get(ptr_src, prop_src);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_enum_set(ptr_dst, prop_dst, value);
+ break;
+ /* TODO support add/sub, for bitflags? */
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on enum");
+ return false;
+ }
+ return true;
+ }
+ case PROP_POINTER:
+ {
+ PointerRNA value = RNA_property_pointer_get(ptr_src, prop_src);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_pointer_set(ptr_dst, prop_dst, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on pointer");
+ return false;
+ }
+ return true;
+ }
+ case PROP_STRING:
+ {
+ char buff[256];
+ char *value = RNA_property_string_get_alloc(ptr_src, prop_src, buff, sizeof(buff), NULL);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_string_set(ptr_dst, prop_dst, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on string");
+ return false;
+ }
+
+ if (value != buff) MEM_freeN(value);
+ return true;
+ }
+ case PROP_COLLECTION:
+ {
+ BLI_assert(!"You need to define a specific override apply callback for enums.");
+ return false;
+ }
+ default:
+ BLI_assert(0);
+ return false;
+ }
+
+ return false;
+}
+
+#undef RNA_PROPERTY_GET_SINGLE
+#undef RNA_PROPERTY_SET_SINGLE
+
#else
@@ -1284,6 +2400,11 @@ static void rna_def_property(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Property_animatable_get", NULL);
RNA_def_property_ui_text(prop, "Animatable", "Property is animatable through RNA");
+ prop = RNA_def_property(srna, "is_overridable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Property_overridable_get", NULL);
+ RNA_def_property_ui_text(prop, "Overridable", "Property is overridable through RNA");
+
prop = RNA_def_property(srna, "is_required", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Property_is_required_get", NULL);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index fb7fee06b83..d6d597aac73 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -27,15 +27,18 @@
#include <stdlib.h>
#include "DNA_brush_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_modifier_types.h"
#include "DNA_particle_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
+#include "DNA_layer_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h" /* TransformOrientation */
#include "IMB_imbuf_types.h"
@@ -47,8 +50,13 @@
#include "BKE_editmesh.h"
#include "BKE_paint.h"
+#include "ED_object.h"
+#include "ED_gpencil.h"
+
#include "GPU_extensions.h"
+#include "DRW_engine.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -66,12 +74,15 @@
#endif
#include "ED_render.h"
+#include "ED_transform.h"
#include "WM_api.h"
#include "WM_types.h"
#include "BLI_threads.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_OPENEXR
const EnumPropertyItem rna_enum_exr_codec_items[] = {
{R_IMF_EXR_CODEC_NONE, "NONE", 0, "None", ""},
@@ -155,6 +166,14 @@ const EnumPropertyItem rna_enum_mesh_select_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[] = {
+ {UV_SELECT_VERTEX, "VERTEX", ICON_UV_VERTEXSEL, "Vertex", "Vertex selection mode"},
+ {UV_SELECT_EDGE, "EDGE", ICON_UV_EDGESEL, "Edge", "Edge selection mode"},
+ {UV_SELECT_FACE, "FACE", ICON_UV_FACESEL, "Face", "Face selection mode"},
+ {UV_SELECT_ISLAND, "ISLAND", ICON_UV_ISLANDSEL, "Island", "Island selection mode"},
+ {0, NULL, 0, NULL, NULL}
+};
+
const EnumPropertyItem rna_enum_snap_element_items[] = {
{SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"},
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
@@ -165,10 +184,10 @@ const EnumPropertyItem rna_enum_snap_element_items[] = {
};
const EnumPropertyItem rna_enum_snap_node_element_items[] = {
- {SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"},
- {SCE_SNAP_MODE_NODE_X, "NODE_X", ICON_SNAP_EDGE, "Node X", "Snap to left/right node border"},
- {SCE_SNAP_MODE_NODE_Y, "NODE_Y", ICON_SNAP_EDGE, "Node Y", "Snap to top/bottom node border"},
- {SCE_SNAP_MODE_NODE_XY, "NODE_XY", ICON_SNAP_EDGE, "Node X / Y", "Snap to any node border"},
+ {SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"},
+ {SCE_SNAP_MODE_NODE_X, "NODE_X", ICON_NODE_SIDE, "Node X", "Snap to left/right node border"},
+ {SCE_SNAP_MODE_NODE_Y, "NODE_Y", ICON_NODE_TOP, "Node Y", "Snap to top/bottom node border"},
+ {SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y, "NODE_XY", ICON_NODE_CORNER, "Node X / Y", "Snap to any node border"},
{0, NULL, 0, NULL, NULL}
};
@@ -281,9 +300,6 @@ const EnumPropertyItem rna_enum_image_type_items[] = {
{0, "", 0, N_("Movie"), NULL},
{R_IMF_IMTYPE_AVIJPEG, "AVI_JPEG", ICON_FILE_MOVIE, "AVI JPEG", "Output video in AVI JPEG format"},
{R_IMF_IMTYPE_AVIRAW, "AVI_RAW", ICON_FILE_MOVIE, "AVI Raw", "Output video in AVI Raw format"},
-#ifdef WITH_FRAMESERVER
- {R_IMF_IMTYPE_FRAMESERVER, "FRAMESERVER", ICON_FILE_SCRIPT, "Frame Server", "Output image to a frameserver"},
-#endif
#ifdef WITH_FFMPEG
{R_IMF_IMTYPE_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "FFmpeg video", "The most versatile way to output video files"},
#endif
@@ -394,7 +410,7 @@ const EnumPropertyItem rna_enum_stereo3d_interlace_type_items[] = {
const EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
{R_BAKE_PASS_FILTER_NONE, "NONE", 0, "None", ""},
- {R_BAKE_PASS_FILTER_AO, "AO", 0, "AO", ""},
+ {R_BAKE_PASS_FILTER_AO, "AO", 0, "Ambient Occlusion", ""},
{R_BAKE_PASS_FILTER_EMIT, "EMIT", 0, "Emit", ""},
{R_BAKE_PASS_FILTER_DIRECT, "DIRECT", 0, "Direct", ""},
{R_BAKE_PASS_FILTER_INDIRECT, "INDIRECT", 0, "Indirect", ""},
@@ -406,6 +422,13 @@ const EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem rna_enum_gizmo_items[] = {
+ {SCE_GIZMO_SHOW_TRANSLATE, "TRANSLATE", 0, "Move", ""},
+ {SCE_GIZMO_SHOW_ROTATE, "ROTATE", 0, "Rotate", ""},
+ {SCE_GIZMO_SHOW_SCALE, "SCALE", 0, "Scale", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifndef RNA_RUNTIME
static const EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
/* interpolation */
@@ -430,8 +453,35 @@ static const EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+
#endif
+const EnumPropertyItem rna_enum_transform_pivot_items_full[] = {
+ {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_PIVOT_BOUNDBOX, "Bounding Box Center",
+ "Pivot around bounding box center of selected object(s)"},
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "3D Cursor", "Pivot around the 3D cursor"},
+ {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_PIVOT_INDIVIDUAL,
+ "Individual Origins", "Pivot around each object's own origin"},
+ {V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", ICON_PIVOT_MEDIAN, "Median Point",
+ "Pivot around the median point of selected objects"},
+ {V3D_AROUND_ACTIVE, "ACTIVE_ELEMENT", ICON_PIVOT_ACTIVE, "Active Element", "Pivot around active object"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* Icons could be made a consistent set of images. */
+const EnumPropertyItem rna_enum_transform_orientation_items[] = {
+ {V3D_MANIP_GLOBAL, "GLOBAL", ICON_ORIENTATION_GLOBAL, "Global", "Align the transformation axes to world space"},
+ {V3D_MANIP_LOCAL, "LOCAL", ICON_ORIENTATION_LOCAL, "Local", "Align the transformation axes to the selected objects' local space"},
+ {V3D_MANIP_NORMAL, "NORMAL", ICON_ORIENTATION_NORMAL, "Normal",
+ "Align the transformation axes to average normal of selected elements "
+ "(bone Y axis for pose mode)"},
+ {V3D_MANIP_GIMBAL, "GIMBAL", ICON_ORIENTATION_GIMBAL, "Gimbal", "Align each axis to the Euler rotation axis as used for input"},
+ {V3D_MANIP_VIEW, "VIEW", ICON_ORIENTATION_VIEW, "View", "Align the transformation axes to the window"},
+ {V3D_MANIP_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "Cursor", "Align the transformation axes to the 3D cursor"},
+ // {V3D_MANIP_CUSTOM, "CUSTOM", 0, "Custom", "Use a custom transform orientation"},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
@@ -440,22 +490,24 @@ static const EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
#include "DNA_text_types.h"
+#include "DNA_workspace_types.h"
#include "RNA_access.h"
#include "MEM_guardedalloc.h"
#include "BKE_brush.h"
+#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
-#include "BKE_depsgraph.h"
#include "BKE_mesh.h"
#include "BKE_sound.h"
#include "BKE_screen.h"
@@ -463,6 +515,7 @@ static const EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
#include "BKE_animsys.h"
#include "BKE_freestyle.h"
#include "BKE_gpencil.h"
+#include "BKE_unit.h"
#include "ED_info.h"
#include "ED_node.h"
@@ -470,11 +523,44 @@ static const EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = {
#include "ED_mesh.h"
#include "ED_keyframing.h"
#include "ED_image.h"
+#include "ED_scene.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#ifdef WITH_FREESTYLE
#include "FRS_freestyle.h"
#endif
+static void rna_ToolSettings_snap_mode_set(struct PointerRNA *ptr, int value)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+ if (value != 0) {
+ ts->snap_mode = value;
+ }
+}
+
+/* Grease Pencil update cache */
+static void rna_GPencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ /* mark all grease pencil datablocks of the scene */
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
+ {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob)
+ {
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
+
/* Grease Pencil Interpolation settings */
static char *rna_GPencilInterpolateSettings_path(PointerRNA *UNUSED(ptr))
{
@@ -496,219 +582,53 @@ static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
{
settings->custom_ipo = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-}
-
-/* Grease pencil Drawing Brushes */
-static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, bool setactive)
-{
- bGPDbrush *brush = BKE_gpencil_brush_addnew(ts, name, setactive != 0);
-
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return brush;
-}
-
-static void rna_GPencil_brush_remove(ToolSettings *ts, ReportList *reports, PointerRNA *brush_ptr)
-{
- bGPDbrush *brush = brush_ptr->data;
- if (BLI_findindex(&ts->gp_brushes, brush) == -1) {
- BKE_report(reports, RPT_ERROR, "Brush not found in grease pencil data");
- return;
- }
-
- BKE_gpencil_brush_delete(ts, brush);
- RNA_POINTER_INVALIDATE(brush_ptr);
-
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-}
-
-static PointerRNA rna_GPencilBrushes_active_get(PointerRNA *ptr)
-{
- ToolSettings *ts = (ToolSettings *) ptr->data;
-
- bGPDbrush *brush;
-
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- if (brush->flag & GP_BRUSH_ACTIVE) {
- break;
- }
- }
-
- if (brush) {
- return rna_pointer_inherit_refine(ptr, &RNA_GPencilBrush, brush);
- }
- return rna_pointer_inherit_refine(ptr, NULL, NULL);
}
-
-static void rna_GPencilBrushes_active_set(PointerRNA *ptr, PointerRNA value)
+static void rna_ToolSettings_gizmo_flag_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
- 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;
- }
+ ToolSettings *ts = scene->toolsettings;
+ if ((ts->gizmo_flag & (SCE_GIZMO_SHOW_TRANSLATE | SCE_GIZMO_SHOW_ROTATE | SCE_GIZMO_SHOW_SCALE)) == 0) {
+ ts->gizmo_flag |= SCE_GIZMO_SHOW_TRANSLATE;
}
- 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, bmain->wm.first, scene);
}
-static int rna_Scene_object_bases_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr)
-{
- Scene *scene = (Scene *)ptr->data;
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- if (STREQLEN(base->object->id.name + 2, key, sizeof(base->object->id.name) - 2)) {
- *r_ptr = rna_pointer_inherit_refine(ptr, &RNA_ObjectBase, base);
- return true;
- }
- }
-
- return false;
-}
-
-static PointerRNA rna_Scene_objects_get(CollectionPropertyIterator *iter)
-{
- ListBaseIterator *internal = &iter->internal.listbase;
- /* we are actually iterating a Base list, so override get */
- return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((Base *)internal->link)->object);
-}
+/* Read-only Iterator of all the scene objects. */
-static Base *rna_Scene_object_link(Scene *scene, Main *UNUSED(bmain), bContext *C, ReportList *reports, Object *ob)
+static void rna_Scene_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
- Scene *scene_act = CTX_data_scene(C);
- Base *base;
-
- if (BKE_scene_base_find(scene, ob)) {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' is already in scene '%s'", ob->id.name + 2, scene->id.name + 2);
- return NULL;
- }
-
- base = BKE_scene_base_add(scene, ob);
- id_us_plus(&ob->id);
-
- /* this is similar to what object_add_type and BKE_object_add do */
- base->lay = scene->lay;
-
- /* when linking to an inactive scene don't touch the layer */
- if (scene == scene_act)
- ob->lay = base->lay;
-
- /* TODO(sergey): Only update relations for the current scene. */
- DAG_relations_tag_update(CTX_data_main(C));
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
- /* slows down importers too much, run scene.update() */
- /* DAG_srelations_tag_update(bmain); */
-
- WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
+ Scene *scene = (Scene *)ptr->data;
+ iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
- return base;
+ ((BLI_Iterator *)iter->internal.custom)->valid = true;
+ BKE_scene_objects_iterator_begin(iter->internal.custom, (void *)scene);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
}
-static void rna_Scene_object_unlink(Scene *scene, Main *bmain, ReportList *reports, Object *ob)
+static void rna_Scene_objects_next(CollectionPropertyIterator *iter)
{
- Base *base = BKE_scene_base_find(scene, ob);
- if (!base) {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' is not in this scene '%s'", ob->id.name + 2, scene->id.name + 2);
- return;
- }
- if (base == scene->basact && ob->mode != OB_MODE_OBJECT) {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' must be in object mode to unlink", ob->id.name + 2);
- return;
- }
- if (scene->basact == base) {
- scene->basact = NULL;
- }
-
- BKE_scene_base_unlink(scene, base);
- MEM_freeN(base);
-
- id_us_min(&ob->id);
-
- /* needed otherwise the depgraph will contain freed objects which can crash, see [#20958] */
- DAG_relations_tag_update(bmain);
-
- WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene);
+ BKE_scene_objects_iterator_next(iter->internal.custom);
+ iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
}
-static void rna_Scene_skgen_etch_template_set(PointerRNA *ptr, PointerRNA value)
+static void rna_Scene_objects_end(CollectionPropertyIterator *iter)
{
- ToolSettings *ts = (ToolSettings *)ptr->data;
- if (value.data && ((Object *)value.data)->type == OB_ARMATURE)
- ts->skgen_template = value.data;
- else
- ts->skgen_template = NULL;
+ BKE_scene_objects_iterator_end(iter->internal.custom);
+ MEM_freeN(iter->internal.custom);
}
-static PointerRNA rna_Scene_active_object_get(PointerRNA *ptr)
+static PointerRNA rna_Scene_objects_get(CollectionPropertyIterator *iter)
{
- Scene *scene = (Scene *)ptr->data;
- return rna_pointer_inherit_refine(ptr, &RNA_Object, scene->basact ? scene->basact->object : NULL);
+ Object *ob = ((BLI_Iterator *)iter->internal.custom)->current;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ob);
}
-static void rna_Scene_active_object_set(PointerRNA *ptr, PointerRNA value)
-{
- Scene *scene = (Scene *)ptr->data;
- if (value.data)
- scene->basact = BKE_scene_base_find(scene, (Object *)value.data);
- else
- scene->basact = NULL;
-}
+/* End of read-only Iterator of all the scene objects. */
static void rna_Scene_set_set(PointerRNA *ptr, PointerRNA value)
{
@@ -728,35 +648,26 @@ static void rna_Scene_set_set(PointerRNA *ptr, PointerRNA value)
scene->set = set;
}
-static void rna_Scene_layer_set(PointerRNA *ptr, const bool *values)
-{
- Scene *scene = (Scene *)ptr->data;
-
- scene->lay = ED_view3d_scene_layer_set(scene->lay, values, &scene->layact);
-}
-
-static int rna_Scene_active_layer_get(PointerRNA *ptr)
+void rna_Scene_set_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- Scene *scene = (Scene *)ptr->data;
+ Scene *scene = (Scene *)ptr->id.data;
- return (int)(log(scene->layact) / M_LN2);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update_ex(bmain, &scene->id, 0);
+ if (scene->set != NULL) {
+ /* Objects which are pulled into main scene's depsgraph needs to have
+ * their base flags updated.
+ */
+ DEG_id_tag_update_ex(bmain, &scene->set->id, 0);
+ }
}
static void rna_Scene_view3d_update(Main *bmain, Scene *UNUSED(scene_unused), PointerRNA *ptr)
{
+ wmWindowManager *wm = bmain->wm.first;
Scene *scene = (Scene *)ptr->data;
- BKE_screen_view3d_main_sync(&bmain->screen, scene);
-}
-
-static void rna_Scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- rna_Scene_view3d_update(bmain, scene, ptr);
- /* XXX We would need do_time=true here, else we can have update issues like [#36289]...
- * However, this has too much drawbacks (like slower layer switch, undesired updates...).
- * That's TODO for future DAG updates.
- */
- DAG_on_visible_update(bmain, false);
+ WM_windows_scene_data_sync(&wm->windows, scene);
}
static void rna_Scene_fps_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
@@ -899,6 +810,7 @@ static void rna_Scene_frame_update(Main *bmain, Scene *UNUSED(current_scene), Po
{
Scene *scene = (Scene *)ptr->id.data;
BKE_sound_seek_scene(bmain, scene);
+ WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
}
static PointerRNA rna_Scene_active_keying_set_get(PointerRNA *ptr)
@@ -965,6 +877,11 @@ static void rna_Scene_all_keyingsets_next(CollectionPropertyIterator *iter)
iter->valid = (internal->link != NULL);
}
+static char *rna_SceneEEVEE_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("eevee");
+}
+
static int rna_RenderSettings_stereoViews_skip(CollectionPropertyIterator *iter, void *UNUSED(data))
{
ListBaseIterator *internal = &iter->internal.listbase;
@@ -1065,17 +982,6 @@ static bool rna_RenderSettings_is_movie_format_get(PointerRNA *ptr)
return BKE_imtype_is_movie(rd->im_format.imtype);
}
-static bool rna_RenderSettings_save_buffers_get(PointerRNA *ptr)
-{
- RenderData *rd = (RenderData *)ptr->data;
- Scene *scene = (Scene *)ptr->id.data;
-
- if (!BKE_scene_use_new_shading_nodes(scene))
- return (rd->scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) != 0;
- else
- return (rd->scemode & R_EXR_TILE_FILE) != 0;
-}
-
static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
@@ -1334,73 +1240,6 @@ static void rna_FFmpegSettings_codec_settings_update(Main *UNUSED(bmain), Scene
}
#endif
-static int rna_RenderSettings_active_layer_index_get(PointerRNA *ptr)
-{
- RenderData *rd = (RenderData *)ptr->data;
- return rd->actlay;
-}
-
-static void rna_RenderSettings_active_layer_index_set(PointerRNA *ptr, int value)
-{
- RenderData *rd = (RenderData *)ptr->data;
- int num_layers = BLI_listbase_count(&rd->layers);
- rd->actlay = min_ff(value, num_layers - 1);
-}
-
-static void rna_RenderSettings_active_layer_index_range(
- PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
-{
- RenderData *rd = (RenderData *)ptr->data;
-
- *min = 0;
- *max = max_ii(0, BLI_listbase_count(&rd->layers) - 1);
-}
-
-static PointerRNA rna_RenderSettings_active_layer_get(PointerRNA *ptr)
-{
- RenderData *rd = (RenderData *)ptr->data;
- SceneRenderLayer *srl = BLI_findlink(&rd->layers, rd->actlay);
-
- return rna_pointer_inherit_refine(ptr, &RNA_SceneRenderLayer, srl);
-}
-
-static void rna_RenderSettings_active_layer_set(PointerRNA *ptr, PointerRNA value)
-{
- RenderData *rd = (RenderData *)ptr->data;
- SceneRenderLayer *srl = (SceneRenderLayer *)value.data;
- const int index = BLI_findindex(&rd->layers, srl);
- if (index != -1) rd->actlay = index;
-}
-
-static SceneRenderLayer *rna_RenderLayer_new(ID *id, RenderData *UNUSED(rd), const char *name)
-{
- Scene *scene = (Scene *)id;
- SceneRenderLayer *srl = BKE_scene_add_render_layer(scene, name);
-
- DAG_id_tag_update(&scene->id, 0);
- WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- return srl;
-}
-
-static void rna_RenderLayer_remove(
- ID *id, RenderData *UNUSED(rd), Main *bmain, ReportList *reports, PointerRNA *srl_ptr)
-{
- SceneRenderLayer *srl = srl_ptr->data;
- Scene *scene = (Scene *)id;
-
- if (!BKE_scene_remove_render_layer(bmain, scene, srl)) {
- BKE_reportf(reports, RPT_ERROR, "Render layer '%s' could not be removed from scene '%s'",
- srl->name, scene->id.name + 2);
- return;
- }
-
- RNA_POINTER_INVALIDATE(srl_ptr);
-
- DAG_id_tag_update(&scene->id, 0);
- WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
-}
-
static int rna_RenderSettings_active_view_index_get(PointerRNA *ptr)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -1465,13 +1304,29 @@ static void rna_RenderView_remove(
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
+static void rna_RenderSettings_views_format_set(PointerRNA *ptr, int value)
+{
+ RenderData *rd = (RenderData *)ptr->data;
+
+ if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW &&
+ value == SCE_VIEWS_FORMAT_STEREO_3D)
+ {
+ /* make sure the actview is visible */
+ if (rd->actview > 1) rd->actview = 1;
+ }
+
+ rd->views_format = value;
+}
+
static void rna_RenderSettings_engine_set(PointerRNA *ptr, int value)
{
RenderData *rd = (RenderData *)ptr->data;
RenderEngineType *type = BLI_findlink(&R_engines, value);
- if (type)
+ if (type) {
BLI_strncpy_utf8(rd->engine, type->idname, sizeof(rd->engine));
+ DEG_id_tag_update(ptr->id.data, DEG_TAG_COPY_ON_WRITE);
+ }
}
static const EnumPropertyItem *rna_RenderSettings_engine_itemf(
@@ -1513,139 +1368,63 @@ static void rna_RenderSettings_engine_update(Main *bmain, Scene *UNUSED(unused),
ED_render_engine_changed(bmain);
}
-static void rna_Scene_glsl_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static bool rna_RenderSettings_multiple_engines_get(PointerRNA *UNUSED(ptr))
{
- Scene *scene = (Scene *)ptr->id.data;
-
- DAG_id_tag_update(&scene->id, 0);
+ return (BLI_listbase_count(&R_engines) > 1);
}
-static void rna_Scene_freestyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static bool rna_RenderSettings_use_spherical_stereo_get(PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
-
- DAG_id_tag_update(&scene->id, 0);
-}
-
-static void rna_Scene_use_view_map_cache_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
-{
-#ifdef WITH_FREESTYLE
- FRS_free_view_map_cache();
-#endif
-}
-
-static IDProperty *rna_SceneRenderLayer_idprops(PointerRNA *ptr, bool create)
-{
- SceneRenderLayer *srl = (SceneRenderLayer *)ptr->data;
-
- if (create && !srl->prop) {
- IDPropertyTemplate val = {0};
- srl->prop = IDP_New(IDP_GROUP, &val, "SceneRenderLayer ID properties");
- }
-
- return srl->prop;
+ return BKE_scene_use_spherical_stereo(scene);
}
-static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value)
+void rna_Scene_glsl_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
- SceneRenderLayer *rl = (SceneRenderLayer *)ptr->data;
- char oldname[sizeof(rl->name)];
- BLI_strncpy(oldname, rl->name, sizeof(rl->name));
-
- BLI_strncpy_utf8(rl->name, value, sizeof(rl->name));
- BLI_uniquename(&scene->r.layers, rl, DATA_("RenderLayer"), '.', offsetof(SceneRenderLayer, name), sizeof(rl->name));
-
- if (scene->nodetree) {
- bNode *node;
- int index = BLI_findindex(&scene->r.layers, rl);
-
- for (node = scene->nodetree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) {
- if (node->custom1 == index)
- BLI_strncpy(node->name, rl->name, NODE_MAXSTR);
- }
- }
- }
-
- /* fix all the animation data which may link to this */
- BKE_animdata_fix_paths_rename_all(NULL, "render.layers", oldname, rl->name);
+ DEG_id_tag_update(&scene->id, 0);
}
-static char *rna_SceneRenderLayer_path(PointerRNA *ptr)
+static void rna_Scene_world_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- SceneRenderLayer *srl = (SceneRenderLayer *)ptr->data;
- char name_esc[sizeof(srl->name) * 2];
+ Scene *sc = (Scene *)ptr->id.data;
- BLI_strescape(name_esc, srl->name, sizeof(name_esc));
- return BLI_sprintfN("render.layers[\"%s\"]", name_esc);
+ rna_Scene_glsl_update(bmain, scene, ptr);
+ WM_main_add_notifier(NC_WORLD | ND_WORLD, &sc->id);
}
-static void rna_SceneRenderView_name_set(PointerRNA *ptr, const char *value)
+void rna_Scene_freestyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
- SceneRenderView *rv = (SceneRenderView *)ptr->data;
- BLI_strncpy_utf8(rv->name, value, sizeof(rv->name));
- BLI_uniquename(&scene->r.views, rv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(rv->name));
-}
-static char *rna_SceneRenderView_path(PointerRNA *ptr)
-{
- SceneRenderView *srv = (SceneRenderView *)ptr->data;
- return BLI_sprintfN("render.views[\"%s\"]", srv->name);
+ DEG_id_tag_update(&scene->id, 0);
}
-static void rna_RenderSettings_views_format_set(PointerRNA *ptr, int value)
+void rna_Scene_use_view_map_cache_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
- RenderData *rd = (RenderData *)ptr->data;
-
- if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW &&
- value == SCE_VIEWS_FORMAT_STEREO_3D)
- {
- /* make sure the actview is visible */
- if (rd->actview > 1) rd->actview = 1;
- }
-
- rd->views_format = value;
-}
-
-static bool rna_RenderSettings_multiple_engines_get(PointerRNA *UNUSED(ptr))
-{
- return (BLI_listbase_count(&R_engines) > 1);
+#ifdef WITH_FREESTYLE
+ FRS_free_view_map_cache();
+#endif
}
-static bool rna_RenderSettings_use_shading_nodes_get(PointerRNA *ptr)
+void rna_ViewLayer_name_set(PointerRNA *ptr, const char *value)
{
Scene *scene = (Scene *)ptr->id.data;
- return BKE_scene_use_new_shading_nodes(scene);
+ ViewLayer *view_layer = (ViewLayer *)ptr->data;
+ BLI_assert(BKE_id_is_in_global_main(&scene->id));
+ BKE_view_layer_rename(G_MAIN, scene, view_layer, value);
}
-static bool rna_RenderSettings_use_spherical_stereo_get(PointerRNA *ptr)
+static void rna_SceneRenderView_name_set(PointerRNA *ptr, const char *value)
{
Scene *scene = (Scene *)ptr->id.data;
- return BKE_scene_use_spherical_stereo(scene);
-}
-
-static bool rna_RenderSettings_use_game_engine_get(PointerRNA *ptr)
-{
- RenderData *rd = (RenderData *)ptr->data;
- RenderEngineType *type;
-
- for (type = R_engines.first; type; type = type->next)
- if (STREQ(type->idname, rd->engine))
- return (type->flag & RE_GAME) != 0;
-
- return 0;
-}
-
-static void rna_SceneRenderLayer_layer_set(PointerRNA *ptr, const bool *values)
-{
- SceneRenderLayer *rl = (SceneRenderLayer *)ptr->data;
- rl->lay = ED_view3d_scene_layer_set(rl->lay, values, NULL);
+ SceneRenderView *rv = (SceneRenderView *)ptr->data;
+ BLI_strncpy_utf8(rv->name, value, sizeof(rv->name));
+ BLI_uniquename(&scene->r.views, rv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(rv->name));
}
-static void rna_SceneRenderLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr)
+void rna_ViewLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
@@ -1655,61 +1434,72 @@ static void rna_SceneRenderLayer_pass_update(Main *bmain, Scene *activescene, Po
rna_Scene_glsl_update(bmain, activescene, ptr);
}
-static void rna_SceneRenderLayer_update_render_passes(ID *id)
+static char *rna_SceneRenderView_path(PointerRNA *ptr)
{
- Scene *scene = (Scene *)id;
- if (scene->nodetree)
- ntreeCompositUpdateRLayers(scene->nodetree);
+ SceneRenderView *srv = (SceneRenderView *)ptr->data;
+ return BLI_sprintfN("render.views[\"%s\"]", srv->name);
}
static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->data;
-
- if (scene->use_nodes && scene->nodetree == NULL)
+ if (scene->use_nodes && scene->nodetree == NULL) {
ED_node_composit_default(C, scene);
+ }
+ DEG_relations_tag_update(CTX_data_main(C));
}
static void rna_Physics_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
- Base *base;
+ FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
+ {
+ BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
+ }
+ FOREACH_SCENE_OBJECT_END;
- for (base = scene->base.first; base; base = base->next)
- BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH);
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
}
static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const bool *value)
{
- Scene *scene = (Scene *)ptr->id.data;
ToolSettings *ts = (ToolSettings *)ptr->data;
int flag = (value[0] ? SCE_SELECT_VERTEX : 0) | (value[1] ? SCE_SELECT_EDGE : 0) | (value[2] ? SCE_SELECT_FACE : 0);
if (flag) {
ts->selectmode = flag;
- if (scene->basact) {
- Mesh *me = BKE_mesh_from_object(scene->basact->object);
- if (me && me->edit_btmesh && me->edit_btmesh->selectmode != flag) {
- me->edit_btmesh->selectmode = flag;
- EDBM_selectmode_set(me->edit_btmesh);
+ /* Update select mode in all the workspaces in mesh edit mode. */
+ wmWindowManager *wm = G_MAIN->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+
+ if (view_layer && view_layer->basact) {
+ Mesh *me = BKE_mesh_from_object(view_layer->basact->object);
+ if (me && me->edit_btmesh && me->edit_btmesh->selectmode != flag) {
+ me->edit_btmesh->selectmode = flag;
+ EDBM_selectmode_set(me->edit_btmesh);
+ }
}
}
}
}
-static void rna_Scene_editmesh_select_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_Scene_editmesh_select_mode_update(bContext *C, PointerRNA *UNUSED(ptr))
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Mesh *me = NULL;
- if (scene->basact) {
- me = BKE_mesh_from_object(scene->basact->object);
+ if (view_layer->basact) {
+ me = BKE_mesh_from_object(view_layer->basact->object);
if (me && me->edit_btmesh == NULL)
me = NULL;
}
- WM_main_add_notifier(NC_GEOM | ND_SELECT, me);
- WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+ if (me) {
+ DEG_id_tag_update(&me->id, DEG_TAG_SELECT_UPDATE);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
}
static void object_simplify_update(Object *ob)
@@ -1725,7 +1515,7 @@ static void object_simplify_update(Object *ob)
for (md = ob->modifiers.first; md; md = md->next) {
if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires, eModifierType_ParticleSystem)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
@@ -1733,40 +1523,40 @@ static void object_simplify_update(Object *ob)
psys->recalc |= PSYS_RECALC_CHILD;
if (ob->dup_group) {
- GroupObject *gob;
+ CollectionObject *cob;
- for (gob = ob->dup_group->gobject.first; gob; gob = gob->next)
- object_simplify_update(gob->ob);
+ for (cob = ob->dup_group->gobject.first; cob; cob = cob->next)
+ object_simplify_update(cob->ob);
}
}
-static void rna_Scene_use_simplify_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *sce = ptr->id.data;
Scene *sce_iter;
Base *base;
BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
- for (SETLOOPER(sce, sce_iter, base))
+ FOREACH_SCENE_OBJECT_BEGIN(sce, ob)
+ {
+ object_simplify_update(ob);
+ }
+ FOREACH_SCENE_OBJECT_END;
+
+ for (SETLOOPER_SET_ONLY(sce, sce_iter, base)) {
object_simplify_update(base->object);
+ }
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&sce->id, 0);
}
-static void rna_Scene_simplify_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Scene_simplify_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Scene *sce = ptr->id.data;
if (sce->r.mode & R_SIMPLIFY)
- rna_Scene_use_simplify_update(bmain, sce, ptr);
-}
-
-static void rna_SceneRenderData_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Scene *sce = ptr->id.data;
-
- DAG_id_tag_update(&sce->id, 0);
+ rna_Scene_use_simplify_update(bmain, scene, ptr);
}
static void rna_Scene_use_persistent_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -1820,26 +1610,7 @@ static void rna_Scene_sync_mode_set(PointerRNA *ptr, int value)
}
}
-static bool rna_GameSettings_auto_start_get(PointerRNA *UNUSED(ptr))
-{
- return (G.fileflags & G_FILE_AUTOPLAY) != 0;
-}
-
-static void rna_GameSettings_auto_start_set(PointerRNA *UNUSED(ptr), bool value)
-{
- if (value)
- G.fileflags |= G_FILE_AUTOPLAY;
- else
- G.fileflags &= ~G_FILE_AUTOPLAY;
-}
-
-static void rna_GameSettings_exit_key_set(PointerRNA *ptr, int value)
-{
- GameData *gm = (GameData *)ptr->data;
- if (ISKEYBOARD(value))
- gm->exitkey = value;
-}
static TimeMarker *rna_TimeLine_add(Scene *scene, const char name[], int frame)
{
@@ -1896,9 +1667,11 @@ static KeyingSet *rna_Scene_keying_set_new(Scene *sce, ReportList *reports, cons
}
}
-static void rna_UnifiedPaintSettings_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_UnifiedPaintSettings_update(bContext *C, PointerRNA *UNUSED(ptr))
{
- Brush *br = BKE_paint_brush(BKE_paint_get_active(scene));
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Brush *br = BKE_paint_brush(BKE_paint_get_active(scene, view_layer));
WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
}
@@ -1921,11 +1694,11 @@ static void rna_UnifiedPaintSettings_unprojected_radius_set(PointerRNA *ptr, flo
ups->unprojected_radius = value;
}
-static void rna_UnifiedPaintSettings_radius_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_UnifiedPaintSettings_radius_update(bContext *C, PointerRNA *ptr)
{
/* changing the unified size should invalidate the overlay but also update the brush */
BKE_paint_invalidate_overlay_all();
- rna_UnifiedPaintSettings_update(bmain, scene, ptr);
+ rna_UnifiedPaintSettings_update(C, ptr);
}
static char *rna_UnifiedPaintSettings_path(PointerRNA *UNUSED(ptr))
@@ -1939,18 +1712,19 @@ static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr))
}
/* generic function to recalc geometry */
-static void rna_EditMesh_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_EditMesh_update(bContext *C, PointerRNA *UNUSED(ptr))
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Mesh *me = NULL;
- if (scene->basact) {
- me = BKE_mesh_from_object(scene->basact->object);
+ if (view_layer->basact) {
+ me = BKE_mesh_from_object(view_layer->basact->object);
if (me && me->edit_btmesh == NULL)
me = NULL;
}
if (me) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_GEOM | ND_DATA, me);
}
}
@@ -1965,11 +1739,13 @@ static char *rna_MeshStatVis_path(PointerRNA *UNUSED(ptr))
* is not for general use and only for the few cases where changing scene
* settings and NOT for general purpose updates, possibly this should be
* given its own notifier. */
-static void rna_Scene_update_active_object_data(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_Scene_update_active_object_data(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = OBACT;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+
if (ob) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id);
}
}
@@ -1979,8 +1755,9 @@ static void rna_SceneCamera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
Scene *scene = (Scene *)ptr->id.data;
Object *camera = scene->camera;
- if (camera)
- DAG_id_tag_update(&camera->id, 0);
+ if (camera && (camera->type == OB_CAMERA)) {
+ DEG_id_tag_update(&camera->id, OB_RECALC_DATA);
+ }
}
static void rna_SceneSequencer_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -1994,14 +1771,14 @@ static char *rna_ToolSettings_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("tool_settings");
}
-static PointerRNA rna_FreestyleLineSet_linestyle_get(PointerRNA *ptr)
+PointerRNA rna_FreestyleLineSet_linestyle_get(PointerRNA *ptr)
{
FreestyleLineSet *lineset = (FreestyleLineSet *)ptr->data;
return rna_pointer_inherit_refine(ptr, &RNA_FreestyleLineStyle, lineset->linestyle);
}
-static void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value)
+void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value)
{
FreestyleLineSet *lineset = (FreestyleLineSet *)ptr->data;
@@ -2011,19 +1788,19 @@ static void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value
id_us_plus(&lineset->linestyle->id);
}
-static FreestyleLineSet *rna_FreestyleSettings_lineset_add(
+FreestyleLineSet *rna_FreestyleSettings_lineset_add(
ID *id, FreestyleSettings *config, Main *bmain, const char *name)
{
Scene *scene = (Scene *)id;
FreestyleLineSet *lineset = BKE_freestyle_lineset_add(bmain, (FreestyleConfig *)config, name);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
return lineset;
}
-static void rna_FreestyleSettings_lineset_remove(
+void rna_FreestyleSettings_lineset_remove(
ID *id, FreestyleSettings *config, ReportList *reports, PointerRNA *lineset_ptr)
{
FreestyleLineSet *lineset = lineset_ptr->data;
@@ -2036,18 +1813,18 @@ static void rna_FreestyleSettings_lineset_remove(
RNA_POINTER_INVALIDATE(lineset_ptr);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
-static PointerRNA rna_FreestyleSettings_active_lineset_get(PointerRNA *ptr)
+PointerRNA rna_FreestyleSettings_active_lineset_get(PointerRNA *ptr)
{
FreestyleConfig *config = (FreestyleConfig *)ptr->data;
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
return rna_pointer_inherit_refine(ptr, &RNA_FreestyleLineSet, lineset);
}
-static void rna_FreestyleSettings_active_lineset_index_range(
+void rna_FreestyleSettings_active_lineset_index_range(
PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
FreestyleConfig *config = (FreestyleConfig *)ptr->data;
@@ -2056,30 +1833,30 @@ static void rna_FreestyleSettings_active_lineset_index_range(
*max = max_ii(0, BLI_listbase_count(&config->linesets) - 1);
}
-static int rna_FreestyleSettings_active_lineset_index_get(PointerRNA *ptr)
+int rna_FreestyleSettings_active_lineset_index_get(PointerRNA *ptr)
{
FreestyleConfig *config = (FreestyleConfig *)ptr->data;
return BKE_freestyle_lineset_get_active_index(config);
}
-static void rna_FreestyleSettings_active_lineset_index_set(PointerRNA *ptr, int value)
+void rna_FreestyleSettings_active_lineset_index_set(PointerRNA *ptr, int value)
{
FreestyleConfig *config = (FreestyleConfig *)ptr->data;
BKE_freestyle_lineset_set_active_index(config, value);
}
-static FreestyleModuleConfig *rna_FreestyleSettings_module_add(ID *id, FreestyleSettings *config)
+FreestyleModuleConfig *rna_FreestyleSettings_module_add(ID *id, FreestyleSettings *config)
{
Scene *scene = (Scene *)id;
FreestyleModuleConfig *module = BKE_freestyle_module_add((FreestyleConfig *)config);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
return module;
}
-static void rna_FreestyleSettings_module_remove(
+void rna_FreestyleSettings_module_remove(
ID *id, FreestyleSettings *config, ReportList *reports, PointerRNA *module_ptr)
{
Scene *scene = (Scene *)id;
@@ -2095,7 +1872,7 @@ static void rna_FreestyleSettings_module_remove(
RNA_POINTER_INVALIDATE(module_ptr);
- DAG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(&scene->id, 0);
WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
@@ -2114,23 +1891,21 @@ char *rna_GPUDOF_path(PointerRNA *ptr)
return BLI_strdup("");
}
-static void rna_GPUFXSettings_fx_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- GPUFXSettings *fx_settings = ptr->data;
-
- BKE_screen_gpu_fx_validate(fx_settings);
-}
-
static void rna_GPUDOFSettings_blades_set(PointerRNA *ptr, const int value)
{
GPUDOFSettings *dofsettings = (GPUDOFSettings *)ptr->data;
- if (value < 3 && dofsettings->num_blades > 2)
- dofsettings->num_blades = 0;
- else if (value > 0 && dofsettings->num_blades == 0)
- dofsettings->num_blades = 3;
- else
+ if (value == 1 || value == 2) {
+ if (dofsettings->num_blades == 0) {
+ dofsettings->num_blades = 3;
+ }
+ else {
+ dofsettings->num_blades = 0;
+ }
+ }
+ else {
dofsettings->num_blades = value;
+ }
}
static void rna_GPUDOFSettings_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
@@ -2162,9 +1937,155 @@ static void rna_Stereo3dFormat_update(Main *bmain, Scene *UNUSED(scene), Pointer
}
}
-static bool rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr))
+static ViewLayer *rna_ViewLayer_new(
+ ID *id, Scene *UNUSED(sce), Main *bmain, const char *name)
{
- return GPU_instanced_drawing_support() && GPU_geometry_shader_support();
+ Scene *scene = (Scene *)id;
+ ViewLayer *view_layer = BKE_view_layer_add(scene, name);
+
+ DEG_id_tag_update(&scene->id, 0);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+
+ return view_layer;
+}
+
+static void rna_ViewLayer_remove(
+ ID *id, Scene *UNUSED(sce), Main *bmain, ReportList *reports, PointerRNA *sl_ptr)
+{
+ Scene *scene = (Scene *)id;
+ ViewLayer *view_layer = sl_ptr->data;
+
+ if (ED_scene_view_layer_delete(bmain, scene, view_layer, reports)) {
+ RNA_POINTER_INVALIDATE(sl_ptr);
+ }
+}
+
+static int rna_Scene_transform_orientation_get(PointerRNA *ptr)
+{
+ Scene *scene = ptr->data;
+ /* convert to enum value */
+ return (scene->orientation_type == V3D_MANIP_CUSTOM) ?
+ (scene->orientation_type + scene->orientation_index_custom) : scene->orientation_type;
+}
+
+void rna_Scene_transform_orientation_set(PointerRNA *ptr, int value)
+{
+ Scene *scene = ptr->data;
+ BIF_selectTransformOrientationValue(scene, value);
+}
+
+static PointerRNA rna_Scene_current_orientation_get(PointerRNA *ptr)
+{
+ Scene *scene = ptr->data;
+ TransformOrientation *orientation;
+
+ if (scene->orientation_type < V3D_MANIP_CUSTOM) {
+ orientation = NULL;
+ }
+ else {
+ orientation = BKE_scene_transform_orientation_find(scene, scene->orientation_index_custom);
+ }
+
+ return rna_pointer_inherit_refine(ptr, &RNA_TransformOrientation, orientation);
+}
+
+const EnumPropertyItem *rna_TransformOrientation_itemf(
+ bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem tmp = {0, "", 0, "", ""};
+ EnumPropertyItem *item = NULL;
+ int i = V3D_MANIP_CUSTOM, totitem = 0;
+
+ RNA_enum_items_add(&item, &totitem, rna_enum_transform_orientation_items);
+
+ Scene *scene;
+ if (ptr->type == &RNA_Scene) {
+ scene = ptr->data;
+ }
+ else {
+ scene = CTX_data_scene(C);
+ }
+ const ListBase *transform_orientations = scene ? &scene->transform_spaces : NULL;
+
+ if (transform_orientations && (BLI_listbase_is_empty(transform_orientations) == false)) {
+ RNA_enum_item_add_separator(&item, &totitem);
+
+ for (TransformOrientation *ts = transform_orientations->first; ts; ts = ts->next) {
+ tmp.identifier = ts->name;
+ tmp.name = ts->name;
+ tmp.value = i++;
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static const EnumPropertyItem *get_unit_enum_items(int system, int type, bool *r_free)
+{
+ const void *usys;
+ int len;
+ bUnit_GetSystem(system, type, &usys, &len);
+
+ EnumPropertyItem *items = NULL;
+ int totitem = 0;
+
+ EnumPropertyItem adaptive = { 0 };
+ adaptive.identifier = "ADAPTIVE";
+ adaptive.name = "Adaptive";
+ adaptive.value = USER_UNIT_ADAPTIVE;
+ RNA_enum_item_add(&items, &totitem, &adaptive);
+
+ for (int i = 0; i < len; i++) {
+ if (!bUnit_IsSuppressed(usys, i)) {
+ EnumPropertyItem tmp = { 0 };
+ tmp.identifier = bUnit_GetIdentifier(usys, i);
+ tmp.name = bUnit_GetNameDisplay(usys, i);
+ tmp.value = i;
+ RNA_enum_item_add(&items, &totitem, &tmp);
+ }
+ }
+
+ *r_free = true;
+ return items;
+}
+
+const EnumPropertyItem *rna_get_length_unit_items(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ UnitSettings *units = ptr->data;
+ return get_unit_enum_items(units->system, B_UNIT_LENGTH, r_free);
+}
+
+const EnumPropertyItem *rna_get_mass_unit_items(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ UnitSettings *units = ptr->data;
+ return get_unit_enum_items(units->system, B_UNIT_MASS, r_free);
+}
+
+const EnumPropertyItem *rna_get_time_unit_items(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ UnitSettings *units = ptr->data;
+ return get_unit_enum_items(units->system, B_UNIT_TIME, r_free);
+}
+
+static void rna_unit_system_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ UnitSettings *unit = &scene->unit;
+ if (unit->system == USER_UNIT_NONE) {
+ unit->length_unit = USER_UNIT_ADAPTIVE;
+ unit->mass_unit = USER_UNIT_ADAPTIVE;
+ }
+ else {
+ unit->length_unit = bUnit_GetBaseUnitOfType(unit->system, B_UNIT_LENGTH);
+ unit->mass_unit = bUnit_GetBaseUnitOfType(unit->system, B_UNIT_MASS);
+ }
}
#else
@@ -2236,205 +2157,6 @@ static void rna_def_gpencil_interpolate(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
}
-/* Grease Pencil Drawing Brushes */
-static void rna_def_gpencil_brush(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "GPencilBrush", NULL);
- RNA_def_struct_sdna(srna, "bGPDbrush");
- RNA_def_struct_ui_text(srna, "Grease Pencil Brush",
- "Collection of brushes being used to control the line style of new strokes");
- RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
-
- /* Name */
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "info");
- RNA_def_property_ui_text(prop, "Name", "Brush name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilBrush_name_set");
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Line Thickness */
- prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "thickness");
- RNA_def_property_range(prop, 1, 300);
- RNA_def_property_ui_range(prop, 1, 10, 1, 0);
- RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Sensitivity factor for new strokes */
- prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity");
- RNA_def_property_range(prop, 0.1f, 3.0f);
- RNA_def_property_ui_text(prop, "Sensitivity", "Pressure sensitivity factor for new strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Strength factor for new strokes */
- prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_strength");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Jitter factor for new strokes */
- prop = RNA_def_property(srna, "jitter", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_jitter");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Randomnes factor for sensitivity and strength */
- prop = RNA_def_property(srna, "random_press", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_random_press");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for pressure and strength in new strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Randomnes factor for subdivision */
- prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_random_sub");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Random Subdivision", "Randomness factor for new strokes after subdivision");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Angle when brush is full size */
- prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "draw_angle");
- RNA_def_property_range(prop, -M_PI_2, M_PI_2);
- RNA_def_property_ui_text(prop, "Angle",
- "Direction of the stroke at which brush gives maximal thickness "
- "(0° for horizontal)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Factor to change brush size depending of angle */
- prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Angle Factor",
- "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Smoothing factor for new strokes */
- prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
- RNA_def_property_range(prop, 0.0, 2.0f);
- RNA_def_property_ui_text(prop, "Smooth",
- "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Iterations of the Smoothing factor */
- prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
- RNA_def_property_range(prop, 1, 3);
- RNA_def_property_ui_text(prop, "Iterations",
- "Number of times to smooth newly created strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Subdivision level for new strokes */
- prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "sublevel");
- RNA_def_property_range(prop, 0, 3);
- RNA_def_property_ui_text(prop, "Subdivision Steps",
- "Number of times to subdivide newly created strokes, for less jagged strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Curves for pressure */
- prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "cur_sensitivity");
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "cur_strength");
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "cur_jitter");
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Flags */
- prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_random_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0);
- RNA_def_property_ui_text(prop, "Random Pressure", "Use random value for pressure");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_random_strength", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_STRENGTH);
- RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0);
- RNA_def_property_ui_text(prop, "Random Strength", "Use random value for strength");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
-}
-
-/* Grease Pencil Drawing Brushes API */
-static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "GreasePencilBrushes");
- srna = RNA_def_struct(brna, "GreasePencilBrushes", NULL);
- RNA_def_struct_sdna(srna, "ToolSettings");
- RNA_def_struct_ui_text(srna, "Grease Pencil Brushes", "Collection of grease pencil brushes");
-
- func = RNA_def_function(srna, "new", "rna_GPencil_brush_new");
- RNA_def_function_ui_description(func, "Add a new grease pencil brush");
- parm = RNA_def_string(func, "name", "GPencilBrush", MAX_NAME, "Name", "Name of the brush");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created brush to the active brush");
- parm = RNA_def_pointer(func, "palette", "GPencilBrush", "", "The newly created brush");
- RNA_def_function_return(func, parm);
-
- func = RNA_def_function(srna, "remove", "rna_GPencil_brush_remove");
- RNA_def_function_ui_description(func, "Remove a grease pencil brush");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "brush", "GPencilBrush", "", "The brush to remove");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
- RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilBrush");
- RNA_def_property_pointer_funcs(prop, "rna_GPencilBrushes_active_get", "rna_GPencilBrushes_active_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Active Brush", "Current active brush");
-
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_funcs(prop,
- "rna_GPencilBrushes_index_get",
- "rna_GPencilBrushes_index_set",
- "rna_GPencilBrushes_index_range");
- RNA_def_property_ui_text(prop, "Active Brush Index", "Index of active brush");
-}
-
static void rna_def_transform_orientation(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2458,14 +2180,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem uv_select_mode_items[] = {
- {UV_SELECT_VERTEX, "VERTEX", ICON_UV_VERTEXSEL, "Vertex", "Vertex selection mode"},
- {UV_SELECT_EDGE, "EDGE", ICON_UV_EDGESEL, "Edge", "Edge selection mode"},
- {UV_SELECT_FACE, "FACE", ICON_UV_FACESEL, "Face", "Face selection mode"},
- {UV_SELECT_ISLAND, "ISLAND", ICON_UV_ISLANDSEL, "Island", "Island selection mode"},
- {0, NULL, 0, NULL, NULL}
- };
-
/* the construction of this enum is quite special - everything is stored as bitflags,
* with 1st position only for for on/off (and exposed as boolean), while others are mutually
* exclusive options but which will only have any effect when autokey is enabled
@@ -2476,22 +2190,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem retarget_roll_items[] = {
- {SK_RETARGET_ROLL_NONE, "NONE", 0, "None", "Don't adjust roll"},
- {SK_RETARGET_ROLL_VIEW, "VIEW", 0, "View", "Roll bones to face the view"},
- {SK_RETARGET_ROLL_JOINT, "JOINT", 0, "Joint", "Roll bone to original joint plane offset"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem sketch_convert_items[] = {
- {SK_CONVERT_CUT_FIXED, "FIXED", 0, "Fixed", "Subdivide stroke in fixed number of bones"},
- {SK_CONVERT_CUT_LENGTH, "LENGTH", 0, "Length", "Subdivide stroke in bones of specific length"},
- {SK_CONVERT_CUT_ADAPTATIVE, "ADAPTIVE", 0, "Adaptive",
- "Subdivide stroke adaptively, with more subdivision in curvier parts"},
- {SK_CONVERT_RETARGET, "RETARGET", 0, "Retarget", "Retarget template bone chain to stroke"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem edge_tag_items[] = {
{EDGE_MODE_SELECT, "SELECT", 0, "Select", ""},
{EDGE_MODE_TAG_SEAM, "SEAM", 0, "Tag Seam", ""},
@@ -2502,6 +2200,13 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem mod_weighted_strength[] = {
+ {FACE_STRENGTH_WEAK, "Weak", 0, "Weak", ""},
+ {FACE_STRENGTH_MEDIUM, "Medium", 0, "Medium", ""},
+ {FACE_STRENGTH_STRONG, "Strong", 0, "Strong", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem draw_groupuser_items[] = {
{OB_DRAW_GROUPUSER_NONE, "NONE", 0, "None", ""},
{OB_DRAW_GROUPUSER_ACTIVE, "ACTIVE", 0, "Active", "Show vertices with no weights in the active group"},
@@ -2516,21 +2221,31 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem gpencil_source_3d_items[] = {
- {GP_TOOL_SOURCE_SCENE, "SCENE", 0, "Scene",
- "Grease Pencil data attached to the current scene is used, "
- "unless the active object already has Grease Pencil data (i.e. for old files)"},
- {GP_TOOL_SOURCE_OBJECT, "OBJECT", 0, "Object",
- "Grease Pencil data-blocks attached to the active object are used "
- "(required when using pre 2.73 add-ons, e.g. BSurfaces)"},
+ static const EnumPropertyItem gpencil_stroke_placement_items[] = {
+ {GP_PROJECT_VIEWSPACE, "ORIGIN", ICON_OBJECT_ORIGIN, "Origin", "Draw stroke at Object origin"},
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "3D Cursor", "Draw stroke at 3D cursor location" },
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", ICON_SNAP_FACE, "Surface", "Stick stroke to surfaces"},
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", ICON_STROKE, "Stroke", "Stick stroke to other strokes"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem gpencil_stroke_snap_items[] = {
+ {0, "NONE", 0, "All points", "No snap"},
+ {GP_PROJECT_DEPTH_STROKE_ENDPOINTS, "ENDS", 0, "End points", "Snap to first and last points and interpolate" },
+ {GP_PROJECT_DEPTH_STROKE_FIRST, "FIRST", 0, "First point", "Snap to first point" },
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem gpencil_stroke_placement_items[] = {
- {GP_PROJECT_VIEWSPACE, "CURSOR", 0, "Cursor", "Draw stroke at the 3D cursor"},
- {0, "VIEW", 0, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */
- {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", 0, "Surface", "Stick stroke to surfaces"},
- {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", 0, "Stroke", "Stick stroke to other strokes"},
+ static const EnumPropertyItem gpencil_selectmode_items[] = {
+ {GP_SELECTMODE_POINT, "POINT", ICON_GP_SELECT_POINTS, "Point", "Select only points"},
+ {GP_SELECTMODE_STROKE, "STROKE", ICON_GP_SELECT_STROKES, "Stroke", "Select all stroke points" },
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem annotation_stroke_placement_items[] = {
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "3D Cursor", "Draw stroke at 3D cursor location" },
+ {0, "VIEW", ICON_RESTRICT_VIEW_ON, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", ICON_FACESEL, "Surface", "Stick stroke to surfaces"},
{0, NULL, 0, NULL, NULL}
};
@@ -2544,6 +2259,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sculpt", "");
prop = RNA_def_property(srna, "use_auto_normalize", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_boolean_sdna(prop, NULL, "auto_normalize", 1);
RNA_def_property_ui_text(prop, "WPaint Auto-Normalize",
"Ensure all bone-deforming vertex groups add up "
@@ -2551,6 +2267,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "use_multipaint", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_boolean_sdna(prop, NULL, "multipaint", 1);
RNA_def_property_ui_text(prop, "WPaint Multi-Paint",
"Paint across the weights of all selected bones, "
@@ -2558,19 +2275,22 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "vertex_group_user", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_enum_sdna(prop, NULL, "weightuser");
RNA_def_property_enum_items(prop, draw_groupuser_items);
RNA_def_property_ui_text(prop, "Mask Non-Group Vertices", "Display unweighted vertices");
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "vertex_group_subset", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_enum_sdna(prop, NULL, "vgroupsubset");
RNA_def_property_enum_items(prop, vertex_group_select_items);
RNA_def_property_ui_text(prop, "Subset", "Filter Vertex groups for Display");
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "vertex_paint", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "vpaint"); RNA_def_property_ui_text(prop, "Vertex Paint", "");
+ RNA_def_property_pointer_sdna(prop, NULL, "vpaint");
+ RNA_def_property_ui_text(prop, "Vertex Paint", "");
prop = RNA_def_property(srna, "weight_paint", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "wpaint");
@@ -2584,6 +2304,10 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "uvsculpt");
RNA_def_property_ui_text(prop, "UV Sculpt", "");
+ prop = RNA_def_property(srna, "gpencil_paint", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_paint");
+ RNA_def_property_ui_text(prop, "Grease Pencil Paint", "");
+
prop = RNA_def_property(srna, "particle_edit", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "particle");
RNA_def_property_ui_text(prop, "Particle Edit", "");
@@ -2612,6 +2336,11 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, uv_sculpt_relaxation_items);
RNA_def_property_ui_text(prop, "Relaxation Method", "Algorithm used for UV relaxation");
+ prop = RNA_def_property(srna, "lock_object_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "object_flag", SCE_OBJECT_MODE_LOCK);
+ RNA_def_property_ui_text(prop, "Lock Object Modes", "Restrict select to the current mode");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
/* Transform */
prop = RNA_def_property(srna, "proportional_edit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "proportional");
@@ -2659,19 +2388,25 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Proportional Size", "Display size for proportional editing circle");
RNA_def_property_range(prop, 0.00001, 5000.0);
- prop = RNA_def_property(srna, "normal_size", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "normalsize");
- RNA_def_property_ui_text(prop, "Normal Size", "Display size for normals in the 3D view");
- RNA_def_property_range(prop, 0.00001, 1000.0);
- RNA_def_property_ui_range(prop, 0.01, 10.0, 10.0, 2);
- RNA_def_property_update(prop, NC_GEOM | ND_DATA, NULL);
-
prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "doublimit");
RNA_def_property_ui_text(prop, "Double Threshold", "Limit for removing duplicates and 'Auto Merge'");
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 0.1, 0.01, 6);
+ /* Pivot Point */
+ prop = RNA_def_property(srna, "transform_pivot_point", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "transform_pivot_point");
+ RNA_def_property_enum_items(prop, rna_enum_transform_pivot_items_full);
+ RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_transform_pivot_point_align", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_AXIS_ALIGN);
+ RNA_def_property_ui_text(prop, "Align", "Manipulate center points (object, pose and weight paint mode only)");
+ RNA_def_property_ui_icon(prop, ICON_CENTER_ONLY, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "automerge", 0);
RNA_def_property_ui_text(prop, "AutoMerge Editing", "Automatically merge vertices moved to the same location");
@@ -2685,33 +2420,33 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_snap_align_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_ROTATE);
- RNA_def_property_ui_text(prop, "Snap Align Rotation", "Align rotation with the snapping target");
- RNA_def_property_ui_icon(prop, ICON_SNAP_NORMAL, 0);
+ RNA_def_property_ui_text(prop, "Align Rotation to Target", "Align rotation with the snapping target");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_grid_absolute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_ABS_GRID);
RNA_def_property_ui_text(prop, "Absolute Grid Snap",
"Absolute grid alignment while translating (based on the pivot center)");
- RNA_def_property_ui_icon(prop, ICON_SNAP_GRID, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
- prop = RNA_def_property(srna, "snap_element", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "snap_mode");
+ prop = RNA_def_property(srna, "snap_elements", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_mode");
RNA_def_property_enum_items(prop, rna_enum_snap_element_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_ToolSettings_snap_mode_set", NULL);
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Snap Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
/* node editor uses own set of snap modes */
prop = RNA_def_property(srna, "snap_node_element", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "snap_node_mode");
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_node_mode");
RNA_def_property_enum_items(prop, rna_enum_snap_node_element_items);
RNA_def_property_ui_text(prop, "Snap Node Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
/* image editor uses own set of snap modes */
prop = RNA_def_property(srna, "snap_uv_element", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "snap_uv_mode");
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_uv_mode");
RNA_def_property_enum_items(prop, snap_uv_element_items);
RNA_def_property_ui_text(prop, "Snap UV Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -2725,30 +2460,28 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_snap_peel_object", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_PEEL_OBJECT);
RNA_def_property_ui_text(prop, "Snap Peel Object", "Consider objects as whole when finding volume center");
- RNA_def_property_ui_icon(prop, ICON_SNAP_PEEL_OBJECT, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_project", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_PROJECT);
RNA_def_property_ui_text(prop, "Project Individual Elements",
"Project individual elements on the surface of other objects");
- RNA_def_property_ui_icon(prop, ICON_RETOPO, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_self", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "snap_flag", SCE_SNAP_NO_SELF);
- RNA_def_property_ui_text(prop, "Project to Self", "Snap onto itself (editmode)");
- RNA_def_property_ui_icon(prop, ICON_ORTHO, 0);
+ RNA_def_property_ui_text(prop, "Project onto Self", "Snap onto itself (Edit Mode Only)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
- /* Grease Pencil */
- prop = RNA_def_property(srna, "use_gpencil_continuous_drawing", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_PAINTSESSIONS_ON);
- RNA_def_property_ui_text(prop, "Use Continuous Drawing",
- "Allow drawing multiple strokes at a time with Grease Pencil");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* xxx: need toolbar to be redrawn... */
+ prop = RNA_def_property(srna, "use_gizmo_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "gizmo_flag");
+ RNA_def_property_enum_items(prop, rna_enum_gizmo_items);
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Gizmo Mode", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ToolSettings_gizmo_flag_update");
- prop = RNA_def_property(srna, "use_gpencil_additive_drawing", PROP_BOOLEAN, PROP_NONE);
+ /* Grease Pencil */
+ prop = RNA_def_property(srna, "use_gpencil_draw_additive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_RETAIN_LAST);
RNA_def_property_ui_text(prop, "Use Additive Drawing",
"When creating new frames, the strokes from the previous/active frame "
@@ -2761,12 +2494,18 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"When draw new strokes, the new stroke is drawn below of all strokes in the layer");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "grease_pencil_source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_src");
- RNA_def_property_enum_items(prop, gpencil_source_3d_items);
- RNA_def_property_ui_text(prop, "Grease Pencil Source",
- "Data-block where active Grease Pencil data is found from");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ prop = RNA_def_property(srna, "use_gpencil_thumbnail_list", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_THUMBNAIL_LIST);
+ RNA_def_property_ui_text(prop, "Compact List",
+ "Show compact list of color instead of thumbnails");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_gpencil_weight_data_add", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_CREATE_WEIGHTS);
+ RNA_def_property_ui_text(prop, "Add weight data for new strokes",
+ "When creating new strokes, the weight data is added according to the current vertex group and weight, "
+ "if no vertex group selected, weight is not added");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
@@ -2780,13 +2519,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grease Pencil Interpolate",
"Settings for Grease Pencil Interpolation tools");
- /* Grease Pencil - Drawing brushes */
- prop = RNA_def_property(srna, "gpencil_brushes", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "gp_brushes", NULL);
- RNA_def_property_struct_type(prop, "GPencilBrush");
- RNA_def_property_ui_text(prop, "Grease Pencil Brushes", "Grease Pencil drawing brushes");
- rna_def_gpencil_brushes(brna, prop);
-
/* Grease Pencil - 3D View Stroke Placement */
prop = RNA_def_property(srna, "gpencil_stroke_placement_view3d", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v3d_align");
@@ -2794,32 +2526,59 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stroke Placement (3D View)", "");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ prop = RNA_def_property(srna, "gpencil_stroke_snap_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v3d_align");
+ RNA_def_property_enum_items(prop, gpencil_stroke_snap_items);
+ RNA_def_property_ui_text(prop, "Stroke Snap", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
prop = RNA_def_property(srna, "use_gpencil_stroke_endpoints", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gpencil_v3d_align", GP_PROJECT_DEPTH_STROKE_ENDPOINTS);
RNA_def_property_ui_text(prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Grease Pencil - 2D Views Stroke Placement */
- prop = RNA_def_property(srna, "gpencil_stroke_placement_view2d", PROP_ENUM, PROP_NONE);
+ /* Grease Pencil - Select mode */
+ prop = RNA_def_property(srna, "gpencil_selectmode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "gpencil_selectmode");
+ RNA_def_property_enum_items(prop, gpencil_selectmode_items);
+ RNA_def_property_ui_text(prop, "Select Mode", "");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ /* Annotations - 2D Views Stroke Placement */
+ prop = RNA_def_property(srna, "annotation_stroke_placement_view2d", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v2d_align");
- RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_enum_items(prop, annotation_stroke_placement_items);
RNA_def_property_ui_text(prop, "Stroke Placement (2D View)", "");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Grease Pencil - Sequencer Preview Stroke Placement */
- prop = RNA_def_property(srna, "gpencil_stroke_placement_sequencer_preview", PROP_ENUM, PROP_NONE);
+ /* Annotations - Sequencer Preview Stroke Placement */
+ prop = RNA_def_property(srna, "annotation_stroke_placement_sequencer_preview", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_seq_align");
- RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_enum_items(prop, annotation_stroke_placement_items);
RNA_def_property_ui_text(prop, "Stroke Placement (Sequencer Preview)", "");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Grease Pencil - Image Editor Stroke Placement */
- prop = RNA_def_property(srna, "gpencil_stroke_placement_image_editor", PROP_ENUM, PROP_NONE);
+ /* Annotations - Image Editor Stroke Placement */
+ prop = RNA_def_property(srna, "annotation_stroke_placement_image_editor", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_ima_align");
- RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_enum_items(prop, annotation_stroke_placement_items);
RNA_def_property_ui_text(prop, "Stroke Placement (Image Editor)", "");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ /* Annotations - 3D View Stroke Placement */
+ /* XXX: Do we need to decouple the stroke_endpoints setting too? */
+ prop = RNA_def_property(srna, "annotation_stroke_placement_view3d", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "annotate_v3d_align");
+ RNA_def_property_enum_items(prop, annotation_stroke_placement_items);
+ RNA_def_property_ui_text(prop, "Annotation Stroke Placement (3D View)", "How annotation strokes are orientated in 3D space");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Annotations - Stroke Thickness */
+ prop = RNA_def_property(srna, "annotation_thickness", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "annotate_thickness");
+ RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_ui_text(prop, "Annotation Stroke Thickness", "Thickness of annotation strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Auto Keying */
prop = RNA_def_property(srna, "use_keyframe_insert_auto", PROP_BOOLEAN, PROP_NONE);
@@ -2844,6 +2603,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Automatic keyframe insertion using active Keying Set only");
RNA_def_property_ui_icon(prop, ICON_KEYINGSET, 0);
+ prop = RNA_def_property(srna, "use_keyframe_cycle_aware", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_CYCLEAWARE);
+ RNA_def_property_ui_text(prop, "Cycle-Aware Keying",
+ "For channels with cyclic extrapolation, keyframe insertion is automatically "
+ "remapped inside the cycle time range, and keeps ends in sync");
+
/* Keyframing */
prop = RNA_def_property(srna, "keyframe_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "keyframe_type");
@@ -2853,19 +2618,19 @@ static void rna_def_tool_settings(BlenderRNA *brna)
/* UV */
prop = RNA_def_property(srna, "uv_select_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "uv_selectmode");
- RNA_def_property_enum_items(prop, uv_select_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_mesh_select_mode_uv_items);
RNA_def_property_ui_text(prop, "UV Selection Mode", "UV selection and display mode");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "use_uv_select_sync", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uv_flag", UV_SYNC_SELECTION);
RNA_def_property_ui_text(prop, "UV Sync Selection", "Keep UV and edit mode mesh selection in sync");
- RNA_def_property_ui_icon(prop, ICON_EDIT, 0);
+ RNA_def_property_ui_icon(prop, ICON_UV_SYNC_SELECT, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_uv_local_view", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uv_flag", UV_SHOW_SAME_IMAGE);
- RNA_def_property_ui_text(prop, "UV Local View", "Draw only faces with the currently displayed image assigned");
+ RNA_def_property_ui_text(prop, "UV Local View", "Display only faces with the currently displayed image assigned");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
/* Mesh */
@@ -2874,6 +2639,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_boolean_funcs(prop, NULL, "rna_Scene_editmesh_select_mode_set");
RNA_def_property_ui_text(prop, "Mesh Selection Mode", "Which mesh elements selection works on");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_Scene_editmesh_select_mode_update");
prop = RNA_def_property(srna, "vertex_group_weight", PROP_FLOAT, PROP_FACTOR);
@@ -2890,71 +2656,13 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "edge_mode_live_unwrap", 1);
RNA_def_property_ui_text(prop, "Live Unwrap", "Changing edges seam re-calculates UV unwrap");
- /* etch-a-ton */
- prop = RNA_def_property(srna, "use_bone_sketching", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bone_sketching", BONE_SKETCHING);
- RNA_def_property_ui_text(prop, "Use Bone Sketching", "Use sketching to create and edit bones");
- // RNA_def_property_ui_icon(prop, ICON_EDIT, 0);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "use_etch_quick", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bone_sketching", BONE_SKETCHING_QUICK);
- RNA_def_property_ui_text(prop, "Quick Sketching", "Automatically convert and delete on stroke end");
-
- prop = RNA_def_property(srna, "use_etch_overdraw", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bone_sketching", BONE_SKETCHING_ADJUST);
- RNA_def_property_ui_text(prop, "Overdraw Sketching", "Adjust strokes by drawing near them");
-
- prop = RNA_def_property(srna, "use_etch_autoname", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "skgen_retarget_options", SK_RETARGET_AUTONAME);
- RNA_def_property_ui_text(prop, "Autoname Bones",
- "Automatically generate values to replace &N and &S suffix placeholders in template names");
-
- prop = RNA_def_property(srna, "etch_number", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "skgen_num_string");
- RNA_def_property_ui_text(prop, "Number", "Text to replace &N with (e.g. 'Finger.&N' -> 'Finger.1' or 'Finger.One')");
-
- prop = RNA_def_property(srna, "etch_side", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "skgen_num_string");
- RNA_def_property_ui_text(prop, "Side", "Text to replace &S with (e.g. 'Arm.&S' -> 'Arm.R' or 'Arm.Right')");
-
- prop = RNA_def_property(srna, "etch_template", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "skgen_template");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Scene_skgen_etch_template_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Template", "Template armature that will be retargeted to the stroke");
-
- prop = RNA_def_property(srna, "etch_subdivision_number", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "skgen_subdivision_number");
- RNA_def_property_range(prop, 1, 255);
- RNA_def_property_ui_text(prop, "Subdivisions", "Number of bones in the subdivided stroke");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "normal_vector", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply");
+ RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, 3);
- prop = RNA_def_property(srna, "etch_adaptive_limit", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "skgen_correlation_limit");
- RNA_def_property_range(prop, 0.00001, 1.0);
- RNA_def_property_ui_range(prop, 0.01, 1.0, 0.01, 2);
- RNA_def_property_ui_text(prop, "Limit", "Correlation threshold for number of bones in the subdivided stroke");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "etch_length_limit", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "skgen_length_limit");
- RNA_def_property_range(prop, 0.00001, 100000.0);
- RNA_def_property_ui_range(prop, 0.001, 100.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Length", "Maximum length of the subdivided bones");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "etch_roll_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "skgen_retarget_roll");
- RNA_def_property_enum_items(prop, retarget_roll_items);
- RNA_def_property_ui_text(prop, "Retarget roll mode", "Method used to adjust the roll of bones when retargeting");
-
- prop = RNA_def_property(srna, "etch_convert_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "bone_sketching_convert");
- RNA_def_property_enum_items(prop, sketch_convert_items);
- RNA_def_property_ui_text(prop, "Stroke conversion method", "Method used to convert stroke to bones");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "face_strength", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mod_weighted_strength);
+ RNA_def_property_ui_text(prop, "Face Strength", "Set strength of face to specified value");
/* Unified Paint Settings */
prop = RNA_def_property(srna, "unified_paint_settings", PROP_POINTER, PROP_NONE);
@@ -3009,6 +2717,7 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
* from the active brush */
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_funcs(prop, NULL, "rna_UnifiedPaintSettings_size_set", NULL);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS * 10);
RNA_def_property_ui_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS, 1, -1);
RNA_def_property_ui_text(prop, "Radius", "Radius of the brush");
@@ -3016,6 +2725,7 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "unprojected_radius", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_funcs(prop, NULL, "rna_UnifiedPaintSettings_unprojected_radius_set", NULL);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 0.001, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001, 1, 0, -1);
RNA_def_property_ui_text(prop, "Unprojected Radius", "Radius of brush in Blender units");
@@ -3023,6 +2733,7 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "alpha");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
@@ -3031,6 +2742,7 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "weight");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
@@ -3038,12 +2750,14 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "rgb");
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update");
prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "secondary_rgb");
RNA_def_property_ui_text(prop, "Secondary Color", "");
@@ -3154,9 +2868,9 @@ static void rna_def_curve_paint_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Depth", "Method of projecting depth");
static const EnumPropertyItem surface_plane_items[] = {
- {CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW, "NORMAL_VIEW", 0, "Normal/View", "Draw perpendicular to the surface"},
- {CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE, "NORMAL_SURFACE", 0, "Normal/Surface", "Draw aligned to the surface"},
- {CURVE_PAINT_SURFACE_PLANE_VIEW, "VIEW", 0, "View", "Draw aligned to the viewport"},
+ {CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW, "NORMAL_VIEW", 0, "Normal/View", "Display perpendicular to the surface"},
+ {CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE, "NORMAL_SURFACE", 0, "Normal/Surface", "Display aligned to the surface"},
+ {CURVE_PAINT_SURFACE_PLANE_VIEW, "VIEW", 0, "View", "Display aligned to the viewport"},
{0, NULL, 0, NULL, NULL}};
prop = RNA_def_property(srna, "surface_plane", PROP_ENUM, PROP_NONE);
@@ -3185,6 +2899,7 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, stat_type);
RNA_def_property_ui_text(prop, "Type", "Type of data to visualize/check");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
@@ -3195,6 +2910,7 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 0.001, 3);
RNA_def_property_ui_text(prop, "Overhang Min", "Minimum angle to display");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
prop = RNA_def_property(srna, "overhang_max", PROP_FLOAT, PROP_ANGLE);
@@ -3203,12 +2919,14 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Overhang Max", "Maximum angle to display");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
prop = RNA_def_property(srna, "overhang_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "overhang_axis");
RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
RNA_def_property_ui_text(prop, "Axis", "");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
@@ -3219,6 +2937,7 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1000.0);
RNA_def_property_ui_range(prop, 0.0f, 100.0, 0.001, 3);
RNA_def_property_ui_text(prop, "Thickness Min", "Minimum for measuring thickness");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
prop = RNA_def_property(srna, "thickness_max", PROP_FLOAT, PROP_DISTANCE);
@@ -3227,12 +2946,14 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1000.0);
RNA_def_property_ui_range(prop, 0.0f, 100.0, 0.001, 3);
RNA_def_property_ui_text(prop, "Thickness Max", "Maximum for measuring thickness");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
prop = RNA_def_property(srna, "thickness_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "thickness_samples");
RNA_def_property_range(prop, 1, 32);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to test per face");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
/* distort */
@@ -3242,6 +2963,7 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Min", "Minimum angle to display");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
prop = RNA_def_property(srna, "distort_max", PROP_FLOAT, PROP_ANGLE);
@@ -3250,6 +2972,7 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Max", "Maximum angle to display");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
/* sharp */
@@ -3259,6 +2982,7 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Min", "Minimum angle to display");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
prop = RNA_def_property(srna, "sharp_max", PROP_FLOAT, PROP_ANGLE);
@@ -3267,10 +2991,11 @@ static void rna_def_statvis(BlenderRNA *brna)
RNA_def_property_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, -DEG2RADF(180.0f), DEG2RADF(180.0f), 10, 3);
RNA_def_property_ui_text(prop, "Distort Max", "Maximum angle to display");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
}
-static void rna_def_unit_settings(BlenderRNA *brna)
+static void rna_def_unit_settings(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -3295,7 +3020,7 @@ static void rna_def_unit_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "system", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, unit_systems);
RNA_def_property_ui_text(prop, "Unit System", "The unit system to use for button display");
- RNA_def_property_update(prop, NC_WINDOW, NULL);
+ RNA_def_property_update(prop, NC_WINDOW, "rna_unit_system_update");
prop = RNA_def_property(srna, "system_rotation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rotation_units);
@@ -3303,7 +3028,9 @@ static void rna_def_unit_settings(BlenderRNA *brna)
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(srna, "scale_length", PROP_FLOAT, PROP_UNSIGNED);
- RNA_def_property_ui_text(prop, "Unit Scale", "Scale to use when converting between blender units and dimensions");
+ RNA_def_property_ui_text(prop, "Unit Scale", "Scale to use when converting between blender units and dimensions."
+ " When working at microscopic or astronomical scale, a small or large unit scale"
+ " respectively can be used to avoid numerical precision problems");
RNA_def_property_range(prop, 0.00001, 100000.0);
RNA_def_property_ui_range(prop, 0.001, 100.0, 0.1, 6);
RNA_def_property_update(prop, NC_WINDOW, NULL);
@@ -3312,69 +3039,39 @@ static void rna_def_unit_settings(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_UNIT_OPT_SPLIT);
RNA_def_property_ui_text(prop, "Separate Units", "Display units in pairs (e.g. 1m 0cm)");
RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop = RNA_def_property(srna, "length_unit", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_get_length_unit_items");
+ RNA_def_property_ui_text(prop, "Length Unit", "Unit that will be used to display length values");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop = RNA_def_property(srna, "mass_unit", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_get_mass_unit_items");
+ RNA_def_property_ui_text(prop, "Mass Unit", "Unit that will be used to display mass values");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop = RNA_def_property(srna, "time_unit", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_get_time_unit_items");
+ RNA_def_property_ui_text(prop, "Time Unit", "Unit that will be used to display time values");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
}
-void rna_def_render_layer_common(StructRNA *srna, int scene)
+void rna_def_view_layer_common(StructRNA *srna, int scene)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- if (scene) RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneRenderLayer_name_set");
+ if (scene) RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ViewLayer_name_set");
else RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Name", "Render layer name");
+ RNA_def_property_ui_text(prop, "Name", "View layer name");
RNA_def_struct_name_property(srna, prop);
if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "material_override", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "mat_override");
- RNA_def_property_struct_type(prop, "Material");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Material Override",
- "Material to override all other materials in this render layer");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "light_override", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "light_override");
- RNA_def_property_struct_type(prop, "Group");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Light Override", "Group to override all other lights in this render layer");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- /* layers */
- prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_ui_text(prop, "Visible Layers", "Scene layers included in this render layer");
- if (scene) RNA_def_property_boolean_funcs(prop, NULL, "rna_SceneRenderLayer_layer_set");
- else RNA_def_property_boolean_funcs(prop, NULL, "rna_RenderLayer_layer_set");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- /* this seems to be too much trouble with depsgraph updates/etc. currently (20140423) */
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "layers_zmask", PROP_BOOLEAN, PROP_LAYER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay_zmask", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_ui_text(prop, "Zmask Layers", "Zmask scene layers for solid faces");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "layers_exclude", PROP_BOOLEAN, PROP_LAYER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay_exclude", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_ui_text(prop, "Exclude Layers", "Exclude scene layers from having any influence");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
if (scene) {
- prop = RNA_def_property(srna, "samples", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_ui_text(prop, "Samples", "Override number of render samples for this render layer, "
- "0 will use the scene setting");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "pass_alpha_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop, "Alpha Threshold",
"Z, Index, normal, UV and vector passes are only affected by surfaces with "
@@ -3383,12 +3080,6 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
}
/* layer options */
- prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "layflag", SCE_LAY_DISABLE);
- RNA_def_property_ui_text(prop, "Enabled", "Disable or enable the render layer");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
prop = RNA_def_property(srna, "use_zmask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_ZMASK);
RNA_def_property_ui_text(prop, "Zmask", "Only render what's in front of the solid z values");
@@ -3434,7 +3125,7 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
prop = RNA_def_property(srna, "use_ao", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_AO);
- RNA_def_property_ui_text(prop, "AO", "Render AO in this Layer");
+ RNA_def_property_ui_text(prop, "Ambient Occlusion", "Render Ambient Occlusion in this Layer");
if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -3450,247 +3141,161 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_FRS);
- RNA_def_property_ui_text(prop, "Freestyle", "Render stylized strokes in this Layer");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
/* passes */
prop = RNA_def_property(srna, "use_pass_combined", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_COMBINED);
RNA_def_property_ui_text(prop, "Combined", "Deliver full combined RGBA buffer");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_z", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_Z);
RNA_def_property_ui_text(prop, "Z", "Deliver Z values pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_vector", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_VECTOR);
RNA_def_property_ui_text(prop, "Vector", "Deliver speed vector pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_normal", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_NORMAL);
RNA_def_property_ui_text(prop, "Normal", "Deliver normal pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_uv", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_UV);
RNA_def_property_ui_text(prop, "UV", "Deliver texture UV pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_mist", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_MIST);
RNA_def_property_ui_text(prop, "Mist", "Deliver mist factor pass (0.0-1.0)");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_object_index", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_INDEXOB);
RNA_def_property_ui_text(prop, "Object Index", "Deliver object index pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_material_index", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_INDEXMA);
RNA_def_property_ui_text(prop, "Material Index", "Deliver material index pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "use_pass_color", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_RGBA);
- RNA_def_property_ui_text(prop, "Color", "Deliver shade-less color pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "use_pass_diffuse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_DIFFUSE);
- RNA_def_property_ui_text(prop, "Diffuse", "Deliver diffuse pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_specular", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_SPEC);
RNA_def_property_ui_text(prop, "Specular", "Deliver specular pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_shadow", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_SHADOW);
RNA_def_property_ui_text(prop, "Shadow", "Deliver shadow pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_ambient_occlusion", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_AO);
- RNA_def_property_ui_text(prop, "AO", "Deliver AO pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "use_pass_reflection", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_REFLECT);
- RNA_def_property_ui_text(prop, "Reflection", "Deliver raytraced reflection pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "use_pass_refraction", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_REFRACT);
- RNA_def_property_ui_text(prop, "Refraction", "Deliver raytraced refraction pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ RNA_def_property_ui_text(prop, "Ambient Occlusion", "Deliver Ambient Occlusion pass");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_emit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_EMIT);
RNA_def_property_ui_text(prop, "Emit", "Deliver emission pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_environment", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_ENVIRONMENT);
RNA_def_property_ui_text(prop, "Environment", "Deliver environment lighting pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_indirect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_INDIRECT);
RNA_def_property_ui_text(prop, "Indirect", "Deliver indirect lighting pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "exclude_specular", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_SPEC);
- RNA_def_property_ui_text(prop, "Specular Exclude", "Exclude specular pass from combined");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "exclude_shadow", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_SHADOW);
- RNA_def_property_ui_text(prop, "Shadow Exclude", "Exclude shadow pass from combined");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "exclude_ambient_occlusion", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_AO);
- RNA_def_property_ui_text(prop, "AO Exclude", "Exclude AO pass from combined");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "exclude_reflection", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_REFLECT);
- RNA_def_property_ui_text(prop, "Reflection Exclude", "Exclude raytraced reflection pass from combined");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "exclude_refraction", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_REFRACT);
- RNA_def_property_ui_text(prop, "Refraction Exclude", "Exclude raytraced refraction pass from combined");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "exclude_emit", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_EMIT);
- RNA_def_property_ui_text(prop, "Emit Exclude", "Exclude emission pass from combined");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "exclude_environment", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_ENVIRONMENT);
- RNA_def_property_ui_text(prop, "Environment Exclude", "Exclude environment pass from combined");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
- else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "exclude_indirect", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_INDIRECT);
- RNA_def_property_ui_text(prop, "Indirect Exclude", "Exclude indirect pass from combined");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_diffuse_direct", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_DIFFUSE_DIRECT);
RNA_def_property_ui_text(prop, "Diffuse Direct", "Deliver diffuse direct pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_diffuse_indirect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_DIFFUSE_INDIRECT);
RNA_def_property_ui_text(prop, "Diffuse Indirect", "Deliver diffuse indirect pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_diffuse_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_DIFFUSE_COLOR);
RNA_def_property_ui_text(prop, "Diffuse Color", "Deliver diffuse color pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_glossy_direct", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_GLOSSY_DIRECT);
RNA_def_property_ui_text(prop, "Glossy Direct", "Deliver glossy direct pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_glossy_indirect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_GLOSSY_INDIRECT);
RNA_def_property_ui_text(prop, "Glossy Indirect", "Deliver glossy indirect pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_glossy_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_GLOSSY_COLOR);
RNA_def_property_ui_text(prop, "Glossy Color", "Deliver glossy color pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_transmission_direct", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_TRANSM_DIRECT);
RNA_def_property_ui_text(prop, "Transmission Direct", "Deliver transmission direct pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_transmission_indirect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_TRANSM_INDIRECT);
RNA_def_property_ui_text(prop, "Transmission Indirect", "Deliver transmission indirect pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_transmission_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_TRANSM_COLOR);
RNA_def_property_ui_text(prop, "Transmission Color", "Deliver transmission color pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_subsurface_direct", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_SUBSURFACE_DIRECT);
RNA_def_property_ui_text(prop, "Subsurface Direct", "Deliver subsurface direct pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_subsurface_indirect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_SUBSURFACE_INDIRECT);
RNA_def_property_ui_text(prop, "Subsurface Indirect", "Deliver subsurface indirect pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_pass_subsurface_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_SUBSURFACE_COLOR);
RNA_def_property_ui_text(prop, "Subsurface Color", "Deliver subsurface color pass");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
@@ -3760,7 +3365,7 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
-static void rna_def_freestyle_settings(BlenderRNA *brna)
+void rna_def_freestyle_settings(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -3779,7 +3384,7 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem group_negation_items[] = {
+ static const EnumPropertyItem collection_negation_items[] = {
{0, "INCLUSIVE", 0, "Inclusive", "Select feature edges belonging to some object in the group"},
{FREESTYLE_LINESET_GR_NOT, "EXCLUSIVE", 0, "Exclusive",
"Select feature edges not belonging to any object in the group"},
@@ -3853,9 +3458,9 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selection by Edge Types", "Select feature edges based on edge types");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
- prop = RNA_def_property(srna, "select_by_group", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "select_by_collection", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_GROUP);
- RNA_def_property_ui_text(prop, "Selection by Group", "Select feature edges based on a group of objects");
+ RNA_def_property_ui_text(prop, "Selection by Collection", "Select feature edges based on a collection of objects");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_by_image_border", PROP_BOOLEAN, PROP_NONE);
@@ -3883,18 +3488,18 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
"Specify a logical combination of selection conditions on feature edge types");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
- prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "group");
- RNA_def_property_struct_type(prop, "Group");
+ RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Group", "A group of objects based on which feature edges are selected");
+ RNA_def_property_ui_text(prop, "Collection", "A collection of objects based on which feature edges are selected");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
- prop = RNA_def_property(srna, "group_negation", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "collection_negation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
- RNA_def_property_enum_items(prop, group_negation_items);
- RNA_def_property_ui_text(prop, "Group Negation",
- "Specify either inclusion or exclusion of feature edges belonging to a group of objects");
+ RNA_def_property_enum_items(prop, collection_negation_items);
+ RNA_def_property_ui_text(prop, "Collection Negation",
+ "Specify either inclusion or exclusion of feature edges belonging to a collection of objects");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "face_mark_negation", PROP_ENUM, PROP_NONE);
@@ -4053,8 +3658,8 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
srna = RNA_def_struct(brna, "FreestyleSettings", NULL);
RNA_def_struct_sdna(srna, "FreestyleConfig");
- RNA_def_struct_nested(brna, srna, "SceneRenderLayer");
- RNA_def_struct_ui_text(srna, "Freestyle Settings", "Freestyle settings for a SceneRenderLayer data-block");
+ RNA_def_struct_nested(brna, srna, "ViewLayer");
+ RNA_def_struct_ui_text(srna, "Freestyle Settings", "Freestyle settings for a ViewLayer data-block");
prop = RNA_def_property(srna, "modules", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "modules", NULL);
@@ -4130,124 +3735,6 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
rna_def_freestyle_linesets(brna, prop);
}
-static void rna_def_scene_game_recast_data(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem rna_enum_partitioning_items[] = {
- {RC_PARTITION_WATERSHED, "WATERSHED", 0, "Watershed", "Classic Recast partitioning method generating the nicest tessellation"},
- {RC_PARTITION_MONOTONE, "MONOTONE", 0, "Monotone", "Fastest navmesh generation method, may create long thin polygons"},
- {RC_PARTITION_LAYERS, "LAYERS", 0, "Layers", "Reasonably fast method that produces better triangles than monotone partitioning"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "SceneGameRecastData", NULL);
- RNA_def_struct_sdna(srna, "RecastData");
- RNA_def_struct_nested(brna, srna, "Scene");
- RNA_def_struct_ui_text(srna, "Recast Data", "Recast data for a Game data-block");
-
- prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "cellsize");
- RNA_def_property_ui_range(prop, 0.1, 1, 1, 2);
- RNA_def_property_float_default(prop, 0.3f);
- RNA_def_property_ui_text(prop, "Cell Size", "Rasterized cell size");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "cell_height", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "cellheight");
- RNA_def_property_ui_range(prop, 0.1, 1, 1, 2);
- RNA_def_property_float_default(prop, 0.2f);
- RNA_def_property_ui_text(prop, "Cell Height", "Rasterized cell height");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "agent_height", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "agentheight");
- RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
- RNA_def_property_float_default(prop, 2.0f);
- RNA_def_property_ui_text(prop, "Agent Height", "Minimum height where the agent can still walk");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "agent_radius", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "agentradius");
- RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
- RNA_def_property_float_default(prop, 0.6f);
- RNA_def_property_ui_text(prop, "Agent Radius", "Radius of the agent");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "climb_max", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "agentmaxclimb");
- RNA_def_property_ui_range(prop, 0.1, 5, 1, 2);
- RNA_def_property_float_default(prop, 0.9f);
- RNA_def_property_ui_text(prop, "Max Climb", "Maximum height between grid cells the agent can climb");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "slope_max", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "agentmaxslope");
- RNA_def_property_range(prop, 0, M_PI_2);
- RNA_def_property_float_default(prop, M_PI_4);
- RNA_def_property_ui_text(prop, "Max Slope", "Maximum walkable slope angle");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
-
- prop = RNA_def_property(srna, "region_min_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "regionminsize");
- RNA_def_property_ui_range(prop, 0, 150, 1, 2);
- RNA_def_property_float_default(prop, 8.0f);
- RNA_def_property_ui_text(prop, "Min Region Size", "Minimum regions size (smaller regions will be deleted)");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "region_merge_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "regionmergesize");
- RNA_def_property_ui_range(prop, 0, 150, 1, 2);
- RNA_def_property_float_default(prop, 20.0f);
- RNA_def_property_ui_text(prop, "Merged Region Size", "Minimum regions size (smaller regions will be merged)");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "partitioning", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "partitioning");
- RNA_def_property_enum_items(prop, rna_enum_partitioning_items);
- RNA_def_property_enum_default(prop, RC_PARTITION_WATERSHED);
- RNA_def_property_ui_text(prop, "Partitioning", "Choose partitioning method");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "edge_max_len", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "edgemaxlen");
- RNA_def_property_ui_range(prop, 0, 50, 1, 2);
- RNA_def_property_float_default(prop, 12.0f);
- RNA_def_property_ui_text(prop, "Max Edge Length", "Maximum contour edge length");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "edge_max_error", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "edgemaxerror");
- RNA_def_property_ui_range(prop, 0.1, 3.0, 1, 2);
- RNA_def_property_float_default(prop, 1.3f);
- RNA_def_property_ui_text(prop, "Max Edge Error", "Maximum distance error from contour to cells");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "verts_per_poly", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "vertsperpoly");
- RNA_def_property_ui_range(prop, 3, 12, 1, -1);
- RNA_def_property_int_default(prop, 6);
- RNA_def_property_ui_text(prop, "Verts Per Poly", "Max number of vertices per polygon");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "sample_dist", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "detailsampledist");
- RNA_def_property_ui_range(prop, 0.0, 16.0, 1, 2);
- RNA_def_property_float_default(prop, 6.0f);
- RNA_def_property_ui_text(prop, "Sample Distance", "Detail mesh sample spacing");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "sample_max_error", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "detailsamplemaxerror");
- RNA_def_property_ui_range(prop, 0.0, 16.0, 1, 2);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Max Sample Error", "Detail mesh simplification max sample error");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-}
-
-
static void rna_def_bake_data(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4362,7 +3849,7 @@ static void rna_def_bake_data(BlenderRNA *brna)
/* custom passes flags */
prop = RNA_def_property(srna, "use_pass_ambient_occlusion", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_AO);
- RNA_def_property_ui_text(prop, "AO", "Add ambient occlusion contribution");
+ RNA_def_property_ui_text(prop, "Ambient Occlusion", "Add ambient occlusion contribution");
prop = RNA_def_property(srna, "use_pass_emit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_EMIT);
@@ -4411,498 +3898,6 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
-static void rna_def_scene_game_data(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem aasamples_items[] = {
- {0, "SAMPLES_0", 0, "Off", ""},
- {2, "SAMPLES_2", 0, "2x", ""},
- {4, "SAMPLES_4", 0, "4x", ""},
- {8, "SAMPLES_8", 0, "8x", ""},
- {16, "SAMPLES_16", 0, "16x", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem framing_types_items[] = {
- {SCE_GAMEFRAMING_BARS, "LETTERBOX", 0, "Letterbox",
- "Show the entire viewport in the display window, using bar horizontally or vertically"},
- {SCE_GAMEFRAMING_EXTEND, "EXTEND", 0, "Extend",
- "Show the entire viewport in the display window, viewing more horizontally "
- "or vertically"},
- {SCE_GAMEFRAMING_SCALE, "SCALE", 0, "Scale", "Stretch or squeeze the viewport to fill the display window"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem dome_modes_items[] = {
- {DOME_FISHEYE, "FISHEYE", 0, "Fisheye", ""},
- {DOME_TRUNCATED_FRONT, "TRUNCATED_FRONT", 0, "Front-Truncated", ""},
- {DOME_TRUNCATED_REAR, "TRUNCATED_REAR", 0, "Rear-Truncated", ""},
- {DOME_ENVMAP, "ENVMAP", 0, "Cube Map", ""},
- {DOME_PANORAM_SPH, "PANORAM_SPH", 0, "Spherical Panoramic", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem stereo_modes_items[] = {
- {STEREO_QUADBUFFERED, "QUADBUFFERED", 0, "Quad-Buffer", ""},
- {STEREO_ABOVEBELOW, "ABOVEBELOW", 0, "Above-Below", ""},
- {STEREO_INTERLACED, "INTERLACED", 0, "Interlaced", ""},
- {STEREO_ANAGLYPH, "ANAGLYPH", 0, "Anaglyph", ""},
- {STEREO_SIDEBYSIDE, "SIDEBYSIDE", 0, "Side-by-side", ""},
- {STEREO_VINTERLACE, "VINTERLACE", 0, "Vinterlace", ""},
- {STEREO_3DTVTOPBOTTOM, "3DTVTOPBOTTOM", 0, "3DTV Top-Bottom", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem stereo_items[] = {
- {STEREO_NOSTEREO, "NONE", 0, "None", "Disable Stereo and Dome environments"},
- {STEREO_ENABLED, "STEREO", 0, "Stereo", "Enable Stereo environment"},
- {STEREO_DOME, "DOME", 0, "Dome", "Enable Dome environment"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem physics_engine_items[] = {
- {WOPHY_NONE, "NONE", 0, "None", "Don't use a physics engine"},
- {WOPHY_BULLET, "BULLET", 0, "Bullet", "Use the Bullet physics engine"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem material_items[] = {
- {GAME_MAT_MULTITEX, "MULTITEXTURE", 0, "Multitexture", "Multitexture materials"},
- {GAME_MAT_GLSL, "GLSL", 0, "GLSL", "OpenGL shading language shaders"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem obstacle_simulation_items[] = {
- {OBSTSIMULATION_NONE, "NONE", 0, "None", ""},
- {OBSTSIMULATION_TOI_rays, "RVO_RAYS", 0, "RVO (rays)", ""},
- {OBSTSIMULATION_TOI_cells, "RVO_CELLS", 0, "RVO (cells)", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem vsync_items[] = {
- {VSYNC_OFF, "OFF", 0, "Off", "Disable vsync"},
- {VSYNC_ON, "ON", 0, "On", "Enable vsync"},
- {VSYNC_ADAPTIVE, "ADAPTIVE", 0, "Adaptive", "Enable adaptive vsync (if supported)"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem storage_items[] = {
- {RAS_STORE_AUTO, "AUTO", 0, "Auto Select", "Choose the best supported mode"},
- {RAS_STORE_VA, "VERTEX_ARRAY", 0, "Vertex Arrays", "Usually the best choice (good performance with display lists)"},
- {RAS_STORE_VBO, "VERTEX_BUFFER_OBJECT", 0, "Vertex Buffer Objects",
- "Typically slower than vertex arrays with display lists, requires at least OpenGL 1.4"},
- {0, NULL, 0, NULL, NULL}};
-
- srna = RNA_def_struct(brna, "SceneGameData", NULL);
- RNA_def_struct_sdna(srna, "GameData");
- RNA_def_struct_nested(brna, srna, "Scene");
- RNA_def_struct_ui_text(srna, "Game Data", "Game data for a Scene data-block");
-
- prop = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "xplay");
- RNA_def_property_range(prop, 4, 10000);
- RNA_def_property_int_default(prop, 640);
- RNA_def_property_ui_text(prop, "Resolution X", "Number of horizontal pixels in the screen");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "yplay");
- RNA_def_property_range(prop, 4, 10000);
- RNA_def_property_int_default(prop, 480);
- RNA_def_property_ui_text(prop, "Resolution Y", "Number of vertical pixels in the screen");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "vsync", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "vsync");
- RNA_def_property_enum_items(prop, vsync_items);
- RNA_def_property_ui_text(prop, "Vsync", "Change vsync settings");
-
- prop = RNA_def_property(srna, "samples", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "aasamples");
- RNA_def_property_enum_items(prop, aasamples_items);
- RNA_def_property_ui_text(prop, "AA Samples", "The number of AA Samples to use for MSAA");
-
- prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "depth");
- RNA_def_property_range(prop, 8, 32);
- RNA_def_property_int_default(prop, 32);
- RNA_def_property_ui_text(prop, "Bits", "Display bit depth of full screen display");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "exit_key", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "exitkey");
- RNA_def_property_enum_items(prop, rna_enum_event_type_items);
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
- RNA_def_property_enum_default(prop, ESCKEY);
- RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_exit_key_set", NULL);
- RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "raster_storage", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "raster_storage");
- RNA_def_property_enum_items(prop, storage_items);
- RNA_def_property_ui_text(prop, "Storage", "Set the storage mode used by the rasterizer");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- /* Do we need it here ? (since we already have it in World */
- prop = RNA_def_property(srna, "frequency", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "freqplay");
- RNA_def_property_range(prop, 4, 2000);
- RNA_def_property_int_default(prop, 60);
- RNA_def_property_ui_text(prop, "Freq", "Display clock frequency of fullscreen display");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "show_fullscreen", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "playerflag", GAME_PLAYER_FULLSCREEN);
- RNA_def_property_ui_text(prop, "Fullscreen", "Start player in a new fullscreen display");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "use_desktop", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "playerflag", GAME_PLAYER_DESKTOP_RESOLUTION);
- RNA_def_property_ui_text(prop, "Desktop", "Use the current desktop resolution in fullscreen mode");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- /* Framing */
- prop = RNA_def_property(srna, "frame_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "framing.type");
- RNA_def_property_enum_items(prop, framing_types_items);
- RNA_def_property_ui_text(prop, "Framing Types", "Select the type of Framing you want");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "frame_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "framing.col");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Framing Color", "Set color of the bars");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- /* Stereo */
- prop = RNA_def_property(srna, "stereo", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "stereoflag");
- RNA_def_property_enum_items(prop, stereo_items);
- RNA_def_property_ui_text(prop, "Stereo Options", "");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "stereo_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "stereomode");
- RNA_def_property_enum_items(prop, stereo_modes_items);
- RNA_def_property_enum_default(prop, STEREO_ANAGLYPH);
- RNA_def_property_ui_text(prop, "Stereo Mode", "Stereographic techniques");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "stereo_eye_separation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "eyeseparation");
- RNA_def_property_range(prop, 0.01, 5.0);
- RNA_def_property_float_default(prop, 0.1f);
- RNA_def_property_ui_text(prop, "Eye Separation",
- "Set the distance between the eyes - the camera focal distance/30 should be fine");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- /* Dome */
- prop = RNA_def_property(srna, "dome_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "dome.mode");
- RNA_def_property_enum_items(prop, dome_modes_items);
- RNA_def_property_ui_text(prop, "Dome Mode", "Dome physical configurations");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "dome_tessellation", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "dome.res");
- RNA_def_property_ui_range(prop, 1, 8, 1, 1);
- RNA_def_property_int_default(prop, 4);
- RNA_def_property_ui_text(prop, "Tessellation", "Tessellation level - check the generated mesh in wireframe mode");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "dome_buffer_resolution", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dome.resbuf");
- RNA_def_property_ui_range(prop, 0.1, 1.0, 0.1, 2);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Buffer Resolution", "Buffer Resolution - decrease it to increase speed");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "dome_angle", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "dome.angle");
- RNA_def_property_ui_range(prop, 90, 250, 1, 1);
- RNA_def_property_int_default(prop, 180);
- RNA_def_property_ui_text(prop, "Angle", "Field of View of the Dome - it only works in mode Fisheye and Truncated");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "dome_tilt", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "dome.tilt");
- RNA_def_property_ui_range(prop, -180, 180, 1, 1);
- RNA_def_property_ui_text(prop, "Tilt", "Camera rotation in horizontal axis");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "dome_text", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "dome.warptext");
- RNA_def_property_struct_type(prop, "Text");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Warp Data", "Custom Warp Mesh data file");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- /* physics */
- prop = RNA_def_property(srna, "physics_engine", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "physicsEngine");
- RNA_def_property_enum_items(prop, physics_engine_items);
- RNA_def_property_enum_default(prop, WOPHY_BULLET);
- RNA_def_property_ui_text(prop, "Physics Engine", "Physics engine used for physics simulation in the game engine");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "physics_gravity", PROP_FLOAT, PROP_ACCELERATION);
- RNA_def_property_float_sdna(prop, NULL, "gravity");
- RNA_def_property_ui_range(prop, 0.0, 25.0, 1, 2);
- RNA_def_property_range(prop, 0.0, 10000.0);
- RNA_def_property_float_default(prop, 9.8f);
- RNA_def_property_ui_text(prop, "Physics Gravity",
- "Gravitational constant used for physics simulation in the game engine");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "occlusion_culling_resolution", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "occlusionRes");
- RNA_def_property_range(prop, 128.0, 1024.0);
- RNA_def_property_int_default(prop, 128);
- RNA_def_property_ui_text(prop, "Occlusion Resolution",
- "Size of the occlusion buffer, use higher value for better precision (slower)");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "fps", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "ticrate");
- RNA_def_property_ui_range(prop, 1, 60, 1, 1);
- RNA_def_property_range(prop, 1, 10000);
- RNA_def_property_int_default(prop, 60);
- RNA_def_property_ui_text(prop, "Frames Per Second",
- "Nominal number of game frames per second "
- "(physics fixed timestep = 1/fps, independently of actual frame rate)");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "logic_step_max", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "maxlogicstep");
- RNA_def_property_range(prop, 1, 10000);
- RNA_def_property_ui_range(prop, 1, 50, 1, 1);
- RNA_def_property_int_default(prop, 5);
- RNA_def_property_ui_text(prop, "Max Logic Steps",
- "Maximum number of logic frame per game frame if graphics slows down the game, "
- "higher value allows better synchronization with physics");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "physics_step_max", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "maxphystep");
- RNA_def_property_range(prop, 1, 10000);
- RNA_def_property_ui_range(prop, 1, 50, 1, 1);
- RNA_def_property_int_default(prop, 5);
- RNA_def_property_ui_text(prop, "Max Physics Steps",
- "Maximum number of physics step per game frame if graphics slows down the game, "
- "higher value allows physics to keep up with realtime");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "physics_step_sub", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "physubstep");
- RNA_def_property_range(prop, 1, 50);
- RNA_def_property_ui_range(prop, 1, 5, 1, 1);
- RNA_def_property_int_default(prop, 1);
- RNA_def_property_ui_text(prop, "Physics Sub Steps",
- "Number of simulation substep per physic timestep, "
- "higher value give better physics precision");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "deactivation_linear_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "lineardeactthreshold");
- RNA_def_property_ui_range(prop, 0.001, 10000.0, 2, 3);
- RNA_def_property_range(prop, 0.001, 10000.0);
- RNA_def_property_float_default(prop, 0.8f);
- RNA_def_property_ui_text(prop, "Deactivation Linear Threshold",
- "Linear velocity that an object must be below before the deactivation timer can start");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "deactivation_angular_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "angulardeactthreshold");
- RNA_def_property_ui_range(prop, 0.001, 10000.0, 2, 3);
- RNA_def_property_range(prop, 0.001, 10000.0);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Deactivation Angular Threshold",
- "Angular velocity that an object must be below before the deactivation timer can start");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "deactivation_time", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "deactivationtime");
- RNA_def_property_ui_range(prop, 0.0, 60.0, 1, 1);
- RNA_def_property_range(prop, 0.0, 60.0);
- RNA_def_property_ui_text(prop, "Deactivation Time",
- "Amount of time (in seconds) after which objects with a velocity less than the given "
- "threshold will deactivate (0.0 means no deactivation)");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- /* mode */
- /* not used *//* deprecated !!!!!!!!!!!!! */
- prop = RNA_def_property(srna, "use_occlusion_culling", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_DBVT_CULLING);
- RNA_def_property_ui_text(prop, "DBVT Culling",
- "Use optimized Bullet DBVT tree for view frustum and occlusion culling (more efficient, "
- "but it can waste unnecessary CPU if the scene doesn't have occluder objects)");
-
- /* not used *//* deprecated !!!!!!!!!!!!! */
- prop = RNA_def_property(srna, "use_activity_culling", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_ACTIVITY_CULLING);
- RNA_def_property_ui_text(prop, "Activity Culling", "Activity culling is enabled");
-
- /* not used *//* deprecated !!!!!!!!!!!!! */
- prop = RNA_def_property(srna, "activity_culling_box_radius", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "activityBoxRadius");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Box Radius",
- "Radius of the activity bubble, in Manhattan length "
- "(objects outside the box are activity-culled)");
-
- /* booleans */
- prop = RNA_def_property(srna, "show_debug_properties", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_DEBUG_PROPS);
- RNA_def_property_ui_text(prop, "Show Debug Properties",
- "Show properties marked for debugging while the game runs");
-
- prop = RNA_def_property(srna, "show_framerate_profile", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_FRAMERATE);
- RNA_def_property_ui_text(prop, "Show Framerate and Profile",
- "Show framerate and profiling information while the game runs");
-
- prop = RNA_def_property(srna, "show_physics_visualization", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_PHYSICS);
- RNA_def_property_ui_text(prop, "Show Physics Visualization",
- "Show a visualization of physics bounds and interactions");
-
- prop = RNA_def_property(srna, "show_mouse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_MOUSE);
- RNA_def_property_ui_text(prop, "Show Mouse", "Start player with a visible mouse cursor");
-
- prop = RNA_def_property(srna, "use_frame_rate", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_ENABLE_ALL_FRAMES);
- RNA_def_property_ui_text(prop, "Use Frame Rate",
- "Respect the frame rate from the Physics panel in the world properties "
- "rather than rendering as many frames as possible");
-
- prop = RNA_def_property(srna, "use_display_lists", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_DISPLAY_LISTS);
- RNA_def_property_ui_text(prop, "Display Lists",
- "Use display lists to speed up rendering by keeping geometry on the GPU");
-
- prop = RNA_def_property(srna, "use_deprecation_warnings", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_IGNORE_DEPRECATION_WARNINGS);
- RNA_def_property_ui_text(prop, "Deprecation Warnings",
- "Print warnings when using deprecated features in the python API");
-
- prop = RNA_def_property(srna, "use_animation_record", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_ENABLE_ANIMATION_RECORD);
- RNA_def_property_ui_text(prop, "Record Animation", "Record animation to F-Curves");
-
- prop = RNA_def_property(srna, "use_auto_start", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_GameSettings_auto_start_get", "rna_GameSettings_auto_start_set");
- RNA_def_property_ui_text(prop, "Auto Start", "Automatically start game at load time");
-
- prop = RNA_def_property(srna, "use_restrict_animation_updates", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_RESTRICT_ANIM_UPDATES);
- RNA_def_property_ui_text(prop, "Restrict Animation Updates",
- "Restrict the number of animation updates to the animation FPS (this is "
- "better for performance, but can cause issues with smooth playback)");
-
- /* materials */
- prop = RNA_def_property(srna, "material_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "matmode");
- RNA_def_property_enum_items(prop, material_items);
- RNA_def_property_ui_text(prop, "Material Mode", "Material mode to use for rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, NULL);
-
- prop = RNA_def_property(srna, "use_glsl_lights", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_LIGHTS);
- RNA_def_property_ui_text(prop, "GLSL Lights", "Use lights for GLSL rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_glsl_shaders", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_SHADERS);
- RNA_def_property_ui_text(prop, "GLSL Shaders", "Use shaders for GLSL rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_glsl_shadows", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_SHADOWS);
- RNA_def_property_ui_text(prop, "GLSL Shadows", "Use shadows for GLSL rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_glsl_ramps", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_RAMPS);
- RNA_def_property_ui_text(prop, "GLSL Ramps", "Use ramps for GLSL rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_glsl_nodes", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_NODES);
- RNA_def_property_ui_text(prop, "GLSL Nodes", "Use nodes for GLSL rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_glsl_color_management", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_COLOR_MANAGEMENT);
- RNA_def_property_ui_text(prop, "GLSL Color Management", "Use color management for GLSL rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_glsl_extra_textures", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_EXTRA_TEX);
- RNA_def_property_ui_text(prop, "GLSL Extra Textures",
- "Use extra textures like normal or specular maps for GLSL rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_glsl_environment_lighting", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_ENV_LIGHTING);
- RNA_def_property_ui_text(prop, "GLSL Environment Lighting", "Use environment lighting for GLSL rendering");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_material_caching", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_NO_MATERIAL_CACHING);
- RNA_def_property_ui_text(prop, "Use Material Caching",
- "Cache materials in the converter (this is faster, but can cause problems with older "
- "Singletexture and Multitexture games)");
-
- /* obstacle simulation */
- prop = RNA_def_property(srna, "obstacle_simulation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "obstacleSimulation");
- RNA_def_property_enum_items(prop, obstacle_simulation_items);
- RNA_def_property_ui_text(prop, "Obstacle simulation", "Simulation used for obstacle avoidance in the game engine");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "level_height", PROP_FLOAT, PROP_ACCELERATION);
- RNA_def_property_float_sdna(prop, NULL, "levelHeight");
- RNA_def_property_range(prop, 0.0f, 200.0f);
- RNA_def_property_float_default(prop, 2.0f);
- RNA_def_property_ui_text(prop, "Level height",
- "Max difference in heights of obstacles to enable their interaction");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "show_obstacle_simulation", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_OBSTACLE_SIMULATION);
- RNA_def_property_ui_text(prop, "Visualization", "Enable debug visualization for obstacle simulation");
-
- /* Recast Settings */
- prop = RNA_def_property(srna, "recast_data", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "recastData");
- RNA_def_property_struct_type(prop, "SceneGameRecastData");
- RNA_def_property_ui_text(prop, "Recast Data", "");
-
- /* Nestled Data */
- rna_def_scene_game_recast_data(brna);
-
- /* LoD */
- prop = RNA_def_property(srna, "use_scene_hysteresis", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "lodflag", SCE_LOD_USE_HYST);
- RNA_def_property_ui_text(prop, "Hysteresis", "Use LoD Hysteresis setting for the scene");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-
- prop = RNA_def_property(srna, "scene_hysteresis_percentage", PROP_INT, PROP_PERCENTAGE);
- RNA_def_property_int_sdna(prop, NULL, "scehysteresis");
- RNA_def_property_range(prop, 0, 100);
- RNA_def_property_ui_range(prop, 0, 100, 10, 1);
- RNA_def_property_int_default(prop, 10);
- RNA_def_property_ui_text(prop, "Hysteresis %",
- "Minimum distance change required to transition to the previous level of detail");
- RNA_def_property_update(prop, NC_SCENE, NULL);
-}
-
static void rna_def_gpu_dof_fx(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4910,7 +3905,6 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna)
srna = RNA_def_struct(brna, "GPUDOFSettings", NULL);
RNA_def_struct_ui_text(srna, "GPU DOF", "Settings for GPU based depth of field");
- RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS);
RNA_def_struct_path_func(srna, "rna_GPUDOF_path");
prop = RNA_def_property(srna, "focus_distance", PROP_FLOAT, PROP_DISTANCE);
@@ -4933,6 +3927,7 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna)
prop = RNA_def_property(srna, "fstop", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "F-stop", "F-stop for dof effect");
+ RNA_def_property_float_default(prop, 128.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update");
@@ -4944,15 +3939,16 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna)
RNA_def_property_int_funcs(prop, NULL, "rna_GPUDOFSettings_blades_set", NULL);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update");
- prop = RNA_def_property(srna, "use_high_quality", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "high_quality", 1);
- RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update");
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation of blades in aperture");
+ RNA_def_property_range(prop, -M_PI, M_PI);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "is_hq_supported", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_gpu_is_hq_supported_get", NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field");
+ prop = RNA_def_property(srna, "ratio", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Ratio", "Distortion to simulate anamorphic lens bokeh");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.0000001f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
@@ -4963,7 +3959,6 @@ static void rna_def_gpu_ssao_fx(BlenderRNA *brna)
srna = RNA_def_struct(brna, "GPUSSAOSettings", NULL);
RNA_def_struct_ui_text(srna, "GPU SSAO", "Settings for GPU based screen space ambient occlusion");
- RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS);
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Strength", "Strength of the SSAO effect");
@@ -5004,7 +3999,6 @@ static void rna_def_gpu_fx(BlenderRNA *brna)
srna = RNA_def_struct(brna, "GPUFXSettings", NULL);
RNA_def_struct_ui_text(srna, "GPU FX Settings", "Settings for GPU based compositing");
- RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS);
prop = RNA_def_property(srna, "dof", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -5015,7 +4009,7 @@ static void rna_def_gpu_fx(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "fx_flag", GPU_FX_FLAG_DOF);
RNA_def_property_ui_text(prop, "Depth Of Field",
"Use depth of field on viewport using the values from active camera");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUFXSettings_fx_update");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "ssao", PROP_POINTER, PROP_NONE);
@@ -5026,80 +4020,32 @@ static void rna_def_gpu_fx(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_ssao", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "fx_flag", GPU_FX_FLAG_SSAO);
RNA_def_property_ui_text(prop, "SSAO", "Use screen space ambient occlusion of field on viewport");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUFXSettings_fx_update");
-}
-
-
-static void rna_def_scene_render_layer(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
- FunctionRNA *func;
-
- srna = RNA_def_struct(brna, "SceneRenderLayer", NULL);
- RNA_def_struct_ui_text(srna, "Scene Render Layer", "Render layer");
- RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS);
- RNA_def_struct_path_func(srna, "rna_SceneRenderLayer_path");
- RNA_def_struct_idprops_func(srna, "rna_SceneRenderLayer_idprops");
-
- rna_def_render_layer_common(srna, 1);
-
- func = RNA_def_function(srna, "update_render_passes", "rna_SceneRenderLayer_update_render_passes");
- RNA_def_function_ui_description(func, "Requery the enabled render passes from the render engine");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF);
-
- /* Freestyle */
- rna_def_freestyle_settings(brna);
-
- prop = RNA_def_property(srna, "freestyle_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "freestyleConfig");
- RNA_def_property_struct_type(prop, "FreestyleSettings");
- RNA_def_property_ui_text(prop, "Freestyle Settings", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
-/* Render Layers */
-static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop)
+static void rna_def_view_layers(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
- PropertyRNA *prop;
-
FunctionRNA *func;
PropertyRNA *parm;
- RNA_def_property_srna(cprop, "RenderLayers");
- srna = RNA_def_struct(brna, "RenderLayers", NULL);
- RNA_def_struct_sdna(srna, "RenderData");
+ RNA_def_property_srna(cprop, "ViewLayers");
+ srna = RNA_def_struct(brna, "ViewLayers", NULL);
+ RNA_def_struct_sdna(srna, "Scene");
RNA_def_struct_ui_text(srna, "Render Layers", "Collection of render layers");
- prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "actlay");
- RNA_def_property_int_funcs(prop, "rna_RenderSettings_active_layer_index_get",
- "rna_RenderSettings_active_layer_index_set",
- "rna_RenderSettings_active_layer_index_range");
- RNA_def_property_ui_text(prop, "Active Layer Index", "Active index in render layer array");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "SceneRenderLayer");
- RNA_def_property_pointer_funcs(prop, "rna_RenderSettings_active_layer_get",
- "rna_RenderSettings_active_layer_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
- RNA_def_property_ui_text(prop, "Active Render Layer", "Active Render Layer");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- func = RNA_def_function(srna, "new", "rna_RenderLayer_new");
- RNA_def_function_ui_description(func, "Add a render layer to scene");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID);
- parm = RNA_def_string(func, "name", "RenderLayer", 0, "", "New name for the render layer (not unique)");
+ func = RNA_def_function(srna, "new", "rna_ViewLayer_new");
+ RNA_def_function_ui_description(func, "Add a view layer to scene");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+ parm = RNA_def_string(func, "name", "ViewLayer", 0, "", "New name for the view layer (not unique)");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_pointer(func, "result", "SceneRenderLayer", "", "Newly created render layer");
+ parm = RNA_def_pointer(func, "result", "ViewLayer", "", "Newly created view layer");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "rna_RenderLayer_remove");
- RNA_def_function_ui_description(func, "Remove a render layer");
- RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
- parm = RNA_def_pointer(func, "layer", "SceneRenderLayer", "", "Render layer to remove");
+ func = RNA_def_function(srna, "remove", "rna_ViewLayer_remove");
+ RNA_def_function_ui_description(func, "Remove a view layer");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "layer", "ViewLayer", "", "View layer to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
@@ -5134,6 +4080,7 @@ static void rna_def_scene_render_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "viewflag", SCE_VIEW_DISABLE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Enabled", "Disable or enable the render view");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
@@ -5665,17 +4612,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem pixel_filter_items[] = {
- {R_FILTER_BOX, "BOX", 0, "Box", "Use a box filter for anti-aliasing"},
- {R_FILTER_TENT, "TENT", 0, "Tent", "Use a tent filter for anti-aliasing"},
- {R_FILTER_QUAD, "QUADRATIC", 0, "Quadratic", "Use a quadratic filter for anti-aliasing"},
- {R_FILTER_CUBIC, "CUBIC", 0, "Cubic", "Use a cubic filter for anti-aliasing"},
- {R_FILTER_CATROM, "CATMULLROM", 0, "Catmull-Rom", "Use a Catmull-Rom filter for anti-aliasing"},
- {R_FILTER_GAUSS, "GAUSSIAN", 0, "Gaussian", "Use a Gaussian filter for anti-aliasing"},
- {R_FILTER_MITCH, "MITCHELL", 0, "Mitchell-Netravali", "Use a Mitchell-Netravali filter for anti-aliasing"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem alpha_mode_items[] = {
{R_ADDSKY, "SKY", 0, "Sky", "Transparent pixels are filled with sky color"},
{R_ALPHAPREMUL, "TRANSPARENT", 0, "Transparent", "World background is transparent with premultiplied alpha"},
@@ -5683,49 +4619,23 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
};
static const EnumPropertyItem display_mode_items[] = {
- {R_OUTPUT_SCREEN, "SCREEN", 0, "Full Screen", "Images are rendered in full Screen"},
- {R_OUTPUT_AREA, "AREA", 0, "Image Editor", "Images are rendered in Image Editor"},
- {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in new Window"},
- {R_OUTPUT_NONE, "NONE", 0, "Keep UI", "Images are rendered without forcing UI changes"},
+ {R_OUTPUT_SCREEN, "SCREEN", 0, "Full Screen", "Images are rendered in a maximized Image Editor"},
+ {R_OUTPUT_AREA, "AREA", 0, "Image Editor", "Images are rendered in an Image Editor"},
+ {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in a new window"},
+ {R_OUTPUT_NONE, "NONE", 0, "Keep User Interface", "Images are rendered without changing the user interface"},
{0, NULL, 0, NULL, NULL}
};
/* Bake */
static const EnumPropertyItem bake_mode_items[] = {
- {RE_BAKE_ALL, "FULL", 0, "Full Render", "Bake everything"},
- {RE_BAKE_AO, "AO", 0, "Ambient Occlusion", "Bake ambient occlusion"},
- {RE_BAKE_SHADOW, "SHADOW", 0, "Shadow", "Bake shadows"},
+ //{RE_BAKE_AO, "AO", 0, "Ambient Occlusion", "Bake ambient occlusion"},
{RE_BAKE_NORMALS, "NORMALS", 0, "Normals", "Bake normals"},
- {RE_BAKE_TEXTURE, "TEXTURE", 0, "Textures", "Bake textures"},
{RE_BAKE_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", "Bake displacement"},
- {RE_BAKE_DERIVATIVE, "DERIVATIVE", 0, "Derivative", "Bake derivative map"},
- {RE_BAKE_VERTEX_COLORS, "VERTEX_COLORS", 0, "Vertex Colors", "Bake vertex colors"},
- {RE_BAKE_EMIT, "EMIT", 0, "Emission", "Bake Emit values (glow)"},
- {RE_BAKE_ALPHA, "ALPHA", 0, "Alpha", "Bake Alpha values (transparency)"},
- {RE_BAKE_MIRROR_INTENSITY, "MIRROR_INTENSITY", 0, "Mirror Intensity", "Bake Mirror values"},
- {RE_BAKE_MIRROR_COLOR, "MIRROR_COLOR", 0, "Mirror Colors", "Bake Mirror colors"},
- {RE_BAKE_SPEC_INTENSITY, "SPEC_INTENSITY", 0, "Specular Intensity", "Bake Specular values"},
- {RE_BAKE_SPEC_COLOR, "SPEC_COLOR", 0, "Specular Colors", "Bake Specular colors"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem bake_normal_space_items[] = {
- {R_BAKE_SPACE_CAMERA, "CAMERA", 0, "Camera", "Bake the normals in camera space"},
- {R_BAKE_SPACE_WORLD, "WORLD", 0, "World", "Bake the normals in world space"},
- {R_BAKE_SPACE_OBJECT, "OBJECT", 0, "Object", "Bake the normals in object space"},
- {R_BAKE_SPACE_TANGENT, "TANGENT", 0, "Tangent", "Bake the normals in tangent space"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem bake_qyad_split_items[] = {
- {0, "AUTO", 0, "Automatic", "Split quads to give the least distortion while baking"},
- {1, "FIXED", 0, "Fixed", "Split quads predictably (0,1,2) (0,2,3)"},
- {2, "FIXED_ALT", 0, "Fixed Alternate", "Split quads predictably (1,2,3) (1,3,0)"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem pixel_size_items[] = {
- {0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the UI scale"},
+ {0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the user interface scale"},
{1, "1", 0, "1x", "Render at full resolution"},
{2, "2", 0, "2x", "Render at 50% resolution"},
{4, "4", 0, "4x", "Render at 25% resolution"},
@@ -5733,23 +4643,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem octree_resolution_items[] = {
- {64, "64", 0, "64", ""},
- {128, "128", 0, "128", ""},
- {256, "256", 0, "256", ""},
- {512, "512", 0, "512", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem raytrace_structure_items[] = {
- {R_RAYSTRUCTURE_AUTO, "AUTO", 0, "Auto", "Automatically select acceleration structure"},
- {R_RAYSTRUCTURE_OCTREE, "OCTREE", 0, "Octree", "Use old Octree structure"},
- {R_RAYSTRUCTURE_VBVH, "VBVH", 0, "vBVH", "Use vBVH"},
- {R_RAYSTRUCTURE_SIMD_SVBVH, "SIMD_SVBVH", 0, "SIMD SVBVH", "Use SIMD SVBVH"},
- {R_RAYSTRUCTURE_SIMD_QBVH, "SIMD_QBVH", 0, "SIMD QBVH", "Use SIMD QBVH"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem fixed_oversample_items[] = {
{5, "5", 0, "5", ""},
{8, "8", 0, "8", ""},
@@ -5758,12 +4651,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem field_order_items[] = {
- {0, "EVEN_FIRST", 0, "Upper First", "Upper field first"},
- {R_ODDFIELD, "ODD_FIRST", 0, "Lower First", "Lower field first"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem threads_mode_items[] = {
{0, "AUTO", 0, "Auto-detect", "Automatically determine the number of threads, based on CPUs"},
{R_FIXED_THREADS, "FIXED", 0, "Fixed", "Manually determine the number of threads"},
@@ -5771,7 +4658,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
};
static const EnumPropertyItem engine_items[] = {
- {0, "BLENDER_RENDER", 0, "Blender Render", "Use the Blender internal rendering engine for rendering"},
+ {0, "BLENDER_EEVEE", 0, "Eevee", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -5790,7 +4677,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
-
+ static const EnumPropertyItem hair_shape_type_items[] = {
+ {SCE_HAIR_SHAPE_STRAND, "STRAND", 0, "Strand", ""},
+ {SCE_HAIR_SHAPE_STRIP, "STRIP", 0, "Strip", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
rna_def_scene_ffmpeg_settings(brna);
@@ -5857,7 +4748,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "preview_pixel_size");
RNA_def_property_enum_items(prop, pixel_size_items);
RNA_def_property_ui_text(prop, "Pixel Size", "Pixel size for viewport rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_SceneRenderData_update");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "pixel_aspect_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xasp");
@@ -5922,15 +4813,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"Amount of dithering noise added to the rendered image to break up banding");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "pixel_filter_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "filtertype");
- RNA_def_property_enum_items(prop, pixel_filter_items);
- RNA_def_property_ui_text(prop, "Pixel Filter", "Reconstruction filter used for combining anti-aliasing samples");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "filter_size", PROP_FLOAT, PROP_PIXEL);
RNA_def_property_float_sdna(prop, NULL, "gauss");
- RNA_def_property_range(prop, 0.5f, 1.5f);
+ RNA_def_property_range(prop, 0.0f, 500.0f);
+ RNA_def_property_ui_range(prop, 0.01f, 10.0f, 1, 2);
RNA_def_property_ui_text(prop, "Filter Size", "Width over which the reconstruction filter combines samples");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5940,32 +4826,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
- prop = RNA_def_property(srna, "octree_resolution", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "ocres");
- RNA_def_property_enum_items(prop, octree_resolution_items);
- RNA_def_property_ui_text(prop, "Octree Resolution",
- "Resolution of raytrace accelerator, use higher resolutions for larger scenes");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "raytrace_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "raytrace_structure");
- RNA_def_property_enum_items(prop, raytrace_structure_items);
- RNA_def_property_ui_text(prop, "Raytrace Acceleration Structure", "Type of raytrace accelerator structure");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "use_instances", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "raytrace_options", R_RAYTRACE_USE_INSTANCES);
- RNA_def_property_ui_text(prop, "Use Instances",
- "Instance support leads to effective memory reduction when using duplicates");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "use_local_coords", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "raytrace_options", R_RAYTRACE_USE_LOCAL_COORDS);
- RNA_def_property_ui_text(prop, "Use Local Coords",
- "Vertex coordinates are stored locally on each primitive "
- "(increases memory usage, but may have impact on speed)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_OSA);
RNA_def_property_ui_text(prop, "Anti-Aliasing",
@@ -5978,72 +4838,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Anti-Aliasing Samples", "Amount of anti-aliasing samples per pixel");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_fields", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", R_FIELDS);
- RNA_def_property_ui_text(prop, "Fields", "Render image to two fields per frame, for interlaced TV output");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "field_order", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, field_order_items);
- RNA_def_property_ui_text(prop, "Field Order",
- "Order of video fields (select which lines get rendered first, "
- "to create smooth motion for TV output)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "use_fields_still", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", R_FIELDSTILL);
- RNA_def_property_ui_text(prop, "Fields Still", "Disable the time difference between fields");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- /* rendering features */
- prop = RNA_def_property(srna, "use_shadows", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SHADOW);
- RNA_def_property_ui_text(prop, "Shadows", "Calculate shadows while rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_envmaps", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", R_ENVMAP);
- RNA_def_property_ui_text(prop, "Environment Maps", "Calculate environment maps while rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_sss", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SSS);
- RNA_def_property_ui_text(prop, "Subsurface Scattering", "Calculate sub-surface scattering in materials rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_world_space_shading", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", R_USE_WS_SHADING);
- RNA_def_property_ui_text(prop, "World Space Shading", "Use world space interpretation of lighting data for node materials");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_raytrace", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", R_RAYTRACE);
- RNA_def_property_ui_text(prop, "Raytracing",
- "Pre-calculate the raytrace accelerator and render raytracing effects");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_textures", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "scemode", R_NO_TEX);
- RNA_def_property_ui_text(prop, "Textures", "Use textures to affect material properties");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "use_edge_enhance", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", R_EDGE);
- RNA_def_property_ui_text(prop, "Edge", "Create a toon outline around the edges of geometry");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "edge_threshold", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "edgeint");
- RNA_def_property_range(prop, 0, 255);
- RNA_def_property_ui_text(prop, "Edge Threshold", "Threshold for drawing outlines on geometry edges");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
- prop = RNA_def_property(srna, "edge_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "edgeR");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Edge Color", "Edge color");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -6075,18 +4869,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
- prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "mblur_samples");
- RNA_def_property_range(prop, 1, 32);
- RNA_def_property_ui_text(prop, "Motion Samples", "Number of scene samples to take with motion blur");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
-
prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_sdna(prop, NULL, "blurfac");
RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 2);
- RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close "
- "(NOTE: Blender Internal does not support animated shutter)");
+ RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "motion_blur_shutter_curve", PROP_POINTER, PROP_NONE);
@@ -6094,17 +4880,24 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_ui_text(prop, "Shutter Curve", "Curve defining the shutter's openness over time");
+ /* Hairs */
+ prop = RNA_def_property(srna, "hair_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, hair_shape_type_items);
+ RNA_def_property_ui_text(prop, "Hair Shape Type", "Hair shape type");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+
+ prop = RNA_def_property(srna, "hair_subdiv", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 3);
+ RNA_def_property_ui_text(prop, "Additional Subdiv", "Additional subdivision along the hair");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+
/* border */
prop = RNA_def_property(srna, "use_border", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_BORDER);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Border",
- "Render a user-defined border region, within the frame size "
- "(note that this disables save_buffers and full_sample)");
+ RNA_def_property_ui_text(prop, "Border", "Render a user-defined border region, within the frame size ");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
-
prop = RNA_def_property(srna, "border_min_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "border.xmin");
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -6194,16 +4987,9 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Movie Format", "When true the format is a movie");
- prop = RNA_def_property(srna, "use_free_image_textures", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_FREE_IMAGE);
- RNA_def_property_ui_text(prop, "Free Image Textures",
- "Free all image textures from memory after render, to save memory before compositing");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_save_buffers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXR_TILE_FILE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_save_buffers_get", NULL);
RNA_def_property_ui_text(prop, "Save Buffers",
"Save tiles for all RenderLayers and SceneNodes to files in the temp directory "
"(saves memory, required for Full Sample)");
@@ -6254,46 +5040,17 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Bake Mode", "Choose shading information to bake into the image");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "bake_normal_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "bake_normal_space");
- RNA_def_property_enum_items(prop, bake_normal_space_items);
- RNA_def_property_ui_text(prop, "Normal Space", "Choose normal space for baking");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "bake_quad_split", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, bake_qyad_split_items);
- RNA_def_property_ui_text(prop, "Quad Split", "Choose the method used to split a quad into 2 triangles for baking");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
- prop = RNA_def_property(srna, "bake_aa_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "bake_osa");
- RNA_def_property_enum_items(prop, fixed_oversample_items);
- RNA_def_property_ui_text(prop, "Anti-Aliasing Level", "");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_bake_selected_to_active", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_TO_ACTIVE);
RNA_def_property_ui_text(prop, "Selected to Active",
"Bake shading on the surface of selected objects to the active object");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_bake_normalize", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_NORMALIZE);
- RNA_def_property_ui_text(prop, "Normalized",
- "With displacement normalize to the distance, with ambient occlusion "
- "normalize without using material settings");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_bake_clear", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_CLEAR);
RNA_def_property_ui_text(prop, "Clear", "Clear Images before baking");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_bake_antialiasing", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_OSA);
- RNA_def_property_ui_text(prop, "Anti-Aliasing", "Enables Anti-aliasing");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "bake_margin", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "bake_filter");
RNA_def_property_range(prop, 0, 64);
@@ -6301,13 +5058,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"Extends the baked result as a post process filter");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "bake_distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "bake_maxdist");
- RNA_def_property_range(prop, 0.0, 1000.0);
- RNA_def_property_ui_text(prop, "Distance",
- "Maximum distance from active object to other object (in blender units)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "bake_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bake_biasdist");
RNA_def_property_range(prop, 0.0, 1000.0);
@@ -6332,12 +5082,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Samples", "Number of samples used for ambient occlusion baking from multires");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_bake_to_vertex_color", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_VCOL);
- RNA_def_property_ui_text(prop, "Bake to Vertex Color",
- "Bake to vertex colors instead of to a UV-mapped image");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_bake_user_scale", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_USERSCALE);
RNA_def_property_ui_text(prop, "User scale", "Use a user scale for the derivative map");
@@ -6425,7 +5169,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_stamp_labels", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "stamp", R_STAMP_HIDE_LABELS);
- RNA_def_property_ui_text(prop, "Stamp Labels", "Draw stamp labels (\"Camera\" in front of camera name, etc.)");
+ RNA_def_property_ui_text(prop, "Stamp Labels", "Display stamp labels (\"Camera\" in front of camera name, etc.)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_stamp_strip_meta", PROP_BOOLEAN, PROP_NONE);
@@ -6468,21 +5212,21 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "sequencer_gl_preview", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "seq_prev_type");
- RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
+ RNA_def_property_enum_items(prop, rna_enum_shading_type_items);
RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update");
#if 0 /* UNUSED, see R_SEQ_GL_REND comment */
prop = RNA_def_property(srna, "sequencer_gl_render", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "seq_rend_type");
- RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
+ RNA_def_property_enum_items(prop, rna_enum_shading_type_items);
/* XXX Label and tooltips are obviously wrong! */
RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view");
#endif
prop = RNA_def_property(srna, "use_sequencer_gl_textured_solid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "seq_flag", R_SEQ_SOLID_TEX);
- RNA_def_property_ui_text(prop, "Textured Solid", "Draw face-assigned textures in solid draw method");
+ RNA_def_property_ui_text(prop, "Textured Solid", "Display face-assigned textures in solid draw method");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update");
prop = RNA_def_property(srna, "use_sequencer_gl_dof", PROP_BOOLEAN, PROP_NONE);
@@ -6490,18 +5234,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Depth of Field", "Use depth of field using the values from scene strip active camera");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update");
- /* layers */
- prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "layers", NULL);
- RNA_def_property_struct_type(prop, "SceneRenderLayer");
- RNA_def_property_ui_text(prop, "Render Layers", "");
- rna_def_render_layers(brna, prop);
-
-
prop = RNA_def_property(srna, "use_single_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_SINGLE_LAYER);
- RNA_def_property_ui_text(prop, "Single Layer", "Only render the active layer");
- RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
+ RNA_def_property_ui_text(prop, "Render Single Layer", "Only render the active layer. Only affects rendering from the interface, ignored for rendering from command line");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
/* views (stereoscopy et al) */
@@ -6544,21 +5280,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Multiple Engines", "More than one rendering engine is available");
- prop = RNA_def_property(srna, "use_shading_nodes", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_shading_nodes_get", NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Use Shading Nodes", "Active render engine uses new shading nodes system");
-
prop = RNA_def_property(srna, "use_spherical_stereo", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_spherical_stereo_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Use Spherical Stereo", "Active render engine supports spherical stereo rendering");
- prop = RNA_def_property(srna, "use_game_engine", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_game_engine_get", NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Use Game Engine", "Current rendering engine is a game engine");
-
/* simplify */
prop = RNA_def_property(srna, "use_simplify", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SIMPLIFY);
@@ -6587,20 +5313,41 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Simplify Child Particles", "Global child particles percentage during rendering");
RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
- prop = RNA_def_property(srna, "simplify_shadow_samples", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "simplify_shadowsamples");
- RNA_def_property_ui_range(prop, 1, 16, 1, -1);
- RNA_def_property_ui_text(prop, "Simplify Shadow Samples", "Global maximum shadow samples");
- RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
-
- prop = RNA_def_property(srna, "simplify_ao_sss", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "simplify_aosss");
- RNA_def_property_ui_text(prop, "Simplify AO and SSS", "Global approximate AO and SSS quality factor");
- RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
-
- prop = RNA_def_property(srna, "use_simplify_triangulate", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "simplify_flag", R_SIMPLE_NO_TRIANGULATE);
- RNA_def_property_ui_text(prop, "Skip Quad to Triangles", "Disable non-planar quads being triangulated");
+ /* Grease Pencil - Simplify Options */
+ prop = RNA_def_property(srna, "simplify_gpencil", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ENABLE);
+ RNA_def_property_ui_text(prop, "Simplify", "Simplify Grease Pencil drawing");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "simplify_gpencil_onplay", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ON_PLAY);
+ RNA_def_property_ui_text(prop, "Simplify Playback", "Simplify Grease Pencil only during animation playback");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "simplify_gpencil_view_fill", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FILL);
+ RNA_def_property_ui_text(prop, "Disable Fill", "Disable fill strokes in the viewport");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "simplify_gpencil_remove_lines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_REMOVE_FILL_LINE);
+ RNA_def_property_ui_text(prop, "Disable Lines", "Disable external lines of fill strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "simplify_gpencil_view_modifier", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_MODIFIER);
+ RNA_def_property_ui_text(prop, "Disable Modifiers", "Do not apply modifiers in the viewport");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "simplify_gpencil_shader_fx", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FX);
+ RNA_def_property_ui_text(prop, "Simplify Shaders", "Do not apply shader fx");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "simplify_gpencil_blend", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_BLEND);
+ RNA_def_property_ui_text(prop, "Layers Blending", "Do not display blend layers");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* persistent data */
prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE);
@@ -6644,61 +5391,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
static void rna_def_scene_objects(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
- PropertyRNA *prop;
-
- FunctionRNA *func;
- PropertyRNA *parm;
RNA_def_property_srna(cprop, "SceneObjects");
srna = RNA_def_struct(brna, "SceneObjects", NULL);
RNA_def_struct_sdna(srna, "Scene");
- RNA_def_struct_ui_text(srna, "Scene Objects", "Collection of scene objects");
-
- func = RNA_def_function(srna, "link", "rna_Scene_object_link");
- RNA_def_function_ui_description(func, "Link object to scene, run scene.update() after");
- RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "object", "Object", "", "Object to add to scene");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
- parm = RNA_def_pointer(func, "base", "ObjectBase", "", "The newly created base");
- RNA_def_function_return(func, parm);
-
- func = RNA_def_function(srna, "unlink", "rna_Scene_object_unlink");
- RNA_def_function_ui_description(func, "Unlink object from scene");
- RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove from scene");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_pointer_funcs(prop, "rna_Scene_active_object_get", "rna_Scene_active_object_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
- RNA_def_property_ui_text(prop, "Active Object", "Active object for this scene");
- /* Could call: ED_base_object_activate(C, scene->basact);
- * but would be a bad level call and it seems the notifier is enough */
- RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, NULL);
-}
-
-
-/* scene.bases.* */
-static void rna_def_scene_bases(BlenderRNA *brna, PropertyRNA *cprop)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
-/* FunctionRNA *func; */
-/* PropertyRNA *parm; */
-
- RNA_def_property_srna(cprop, "SceneBases");
- srna = RNA_def_struct(brna, "SceneBases", NULL);
- RNA_def_struct_sdna(srna, "Scene");
- RNA_def_struct_ui_text(srna, "Scene Bases", "Collection of scene bases");
-
- prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "ObjectBase");
- RNA_def_property_pointer_sdna(prop, NULL, "basact");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Active Base", "Active object base in the scene");
- RNA_def_property_update(prop, NC_SCENE | ND_OB_ACTIVE, NULL);
+ RNA_def_struct_ui_text(srna, "Scene Objects", "All the of scene objects");
}
/* scene.timeline_markers */
@@ -6874,6 +5571,518 @@ static void rna_def_display_safe_areas(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
}
+static void rna_def_scene_display(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static float default_light_direction[3] = {-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3};
+
+ srna = RNA_def_struct(brna, "SceneDisplay", NULL);
+ RNA_def_struct_ui_text(srna, "Scene Display", "Scene display settings for 3d viewport");
+ RNA_def_struct_sdna(srna, "SceneDisplay");
+
+ prop = RNA_def_property(srna, "light_direction", PROP_FLOAT, PROP_DIRECTION);
+ RNA_def_property_float_sdna(prop, NULL, "light_direction");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_float_array_default(prop, default_light_direction);
+ RNA_def_property_ui_text(prop, "Light Direction", "Direction of the light for shadows and highlights");
+ RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_set_update");
+
+ prop = RNA_def_property(srna, "shadow_shift", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "shadow_shift");
+ RNA_def_property_float_default(prop, 0.1);
+ RNA_def_property_ui_text(prop, "Shadow Shift", "Shadow termination angle");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 2);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_set_update");
+
+ prop = RNA_def_property(srna, "matcap_ssao_distance", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the Cavity/Edge effect");
+ RNA_def_property_range(prop, 0.0f, 100000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
+
+ prop = RNA_def_property(srna, "matcap_ssao_attenuation", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Attenuation", "Attenuation constant");
+ RNA_def_property_range(prop, 1.0f, 100000.0f);
+ RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3);
+
+ prop = RNA_def_property(srna, "matcap_ssao_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 16);
+ RNA_def_property_ui_text(prop, "Samples", "Number of samples");
+ RNA_def_property_range(prop, 1, 500);
+
+ /* OpenGL render engine settings. */
+ prop = RNA_def_property(srna, "shading", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Shading Settings", "Shading settings for OpenGL render engine");
+}
+
+static void rna_def_scene_eevee(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem eevee_shadow_method_items[] = {
+ {SHADOW_ESM, "ESM", 0, "ESM", "Exponential Shadow Mapping"},
+ {SHADOW_VSM, "VSM", 0, "VSM", "Variance Shadow Mapping"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem eevee_shadow_size_items[] = {
+ {64, "64", 0, "64px", ""},
+ {128, "128", 0, "128px", ""},
+ {256, "256", 0, "256px", ""},
+ {512, "512", 0, "512px", ""},
+ {1024, "1024", 0, "1024px", ""},
+ {2048, "2048", 0, "2048px", ""},
+ {4096, "4096", 0, "4096px", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem eevee_gi_visibility_size_items[] = {
+ {8, "8", 0, "8px", ""},
+ {16, "16", 0, "16px", ""},
+ {32, "32", 0, "32px", ""},
+ {64, "64", 0, "64px", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static const EnumPropertyItem eevee_volumetric_tile_size_items[] = {
+ {2, "2", 0, "2px", ""},
+ {4, "4", 0, "4px", ""},
+ {8, "8", 0, "8px", ""},
+ {16, "16", 0, "16px", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static float default_bloom_color[3] = {1.0f, 1.0f, 1.0f};
+
+ srna = RNA_def_struct(brna, "SceneEEVEE", NULL);
+ RNA_def_struct_path_func(srna, "rna_SceneEEVEE_path");
+ RNA_def_struct_ui_text(srna, "Scene Display", "Scene display settings for 3d viewport");
+
+ /* Indirect Lighting */
+ prop = RNA_def_property(srna, "gi_diffuse_bounces", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 3);
+ RNA_def_property_ui_text(prop, "Diffuse Bounces", "Number of time the light is reinjected inside light grids, "
+ "0 disable indirect diffuse light");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_cubemap_resolution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, eevee_shadow_size_items);
+ RNA_def_property_enum_default(prop, 512);
+ RNA_def_property_ui_text(prop, "Cubemap Size", "Size of every cubemaps");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_visibility_resolution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, eevee_gi_visibility_size_items);
+ RNA_def_property_enum_default(prop, 32);
+ RNA_def_property_ui_text(prop, "Irradiance Visibility Size",
+ "Size of the shadow map applied to each irradiance sample");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_irradiance_smoothing", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 5, 2);
+ RNA_def_property_float_default(prop, 0.1f);
+ RNA_def_property_ui_text(prop, "Irradiance Smoothing", "Smoother irradiance interpolation but introduce light bleeding");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_glossy_clamp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "Clamp Glossy", "Clamp pixel intensity to reduce noise inside glossy reflections "
+ "from reflection cubemaps (0 to disabled)");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_filter_quality", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Filter Quality", "Take more samples during cubemap filtering to remove artifacts");
+ RNA_def_property_range(prop, 1.0f, 8.0f);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_show_irradiance", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHOW_IRRADIANCE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_icon(prop, ICON_HIDE_ON, 1);
+ RNA_def_property_ui_text(prop, "Show Irradiance Cache", "Display irradiance samples in the viewport");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_show_cubemaps", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHOW_CUBEMAPS);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_icon(prop, ICON_HIDE_ON, 1);
+ RNA_def_property_ui_text(prop, "Show Cubemap Cache", "Display captured cubemaps in the viewport");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gi_irradiance_display_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "gi_irradiance_draw_size");
+ RNA_def_property_range(prop, 0.05f, 10.0f);
+ RNA_def_property_float_default(prop, 0.1f);
+ RNA_def_property_ui_text(prop, "Irradiance Display Size", "Size of the irradiance sample spheres to debug captured light");
+
+ prop = RNA_def_property(srna, "gi_cubemap_display_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "gi_cubemap_draw_size");
+ RNA_def_property_range(prop, 0.05f, 10.0f);
+ RNA_def_property_float_default(prop, 0.3f);
+ RNA_def_property_ui_text(prop, "Cubemap Display Size", "Size of the cubemap spheres to debug captured light");
+
+ prop = RNA_def_property(srna, "gi_auto_bake", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GI_AUTOBAKE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Auto Bake", "Auto bake indirect lighting when editing probes");
+
+ prop = RNA_def_property(srna, "gi_cache_info", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "light_cache_info");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Light Cache Info", "Info on current cache status");
+
+ /* Temporal Anti-Aliasing (super sampling) */
+ prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 16);
+ RNA_def_property_ui_text(prop, "Viewport Samples", "Number of samples, unlimited if 0");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "taa_render_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 64);
+ RNA_def_property_ui_text(prop, "Render Samples", "Number of samples per pixels for rendering");
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_taa_reprojection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_TAA_REPROJECTION);
+ RNA_def_property_boolean_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Viewport Denoising", "Denoise image using temporal reprojection "
+ "(can leave some ghosting)");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Screen Space Subsurface Scattering */
+ prop = RNA_def_property(srna, "use_sss", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_ENABLED);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Subsurface Scattering", "Enable screen space subsurface scattering");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "sss_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 7);
+ RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute the scattering effect");
+ RNA_def_property_range(prop, 1, 32);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "sss_jitter_threshold", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.3f);
+ RNA_def_property_ui_text(prop, "Jitter Threshold", "Rotate samples that are below this threshold");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_sss_separate_albedo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_SEPARATE_ALBEDO);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Separate Albedo", "Avoid albedo being blurred by the subsurface scattering "
+ "but uses more video memory");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Screen Space Reflection */
+ prop = RNA_def_property(srna, "use_ssr", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_ENABLED);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Screen Space Reflections", "Enable screen space reflection");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_ssr_refraction", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_REFRACTION);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Screen Space Refractions", "Enable screen space Refractions");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_ssr_halfres", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_HALF_RESOLUTION);
+ RNA_def_property_boolean_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Half Res Trace", "Raytrace at a lower resolution");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "ssr_quality", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.25f);
+ RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the screen space raytracing");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "ssr_max_roughness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Max Roughness", "Do not raytrace reflections for roughness above this value");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_ui_text(prop, "Thickness", "Pixel thickness used to detect intersection");
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 5, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "ssr_border_fade", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.075f);
+ RNA_def_property_ui_text(prop, "Edge Fading", "Screen percentage used to fade the SSR");
+ RNA_def_property_range(prop, 0.0f, 0.5f);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "ssr_firefly_fac", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 10.0f);
+ RNA_def_property_ui_text(prop, "Clamp", "Clamp pixel intensity to remove noise (0 to disabled)");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Volumetrics */
+ prop = RNA_def_property(srna, "use_volumetric", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_ENABLED);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Volumetrics", "Enable scattering and absorbance of volumetric material");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_default(prop, 0.1f);
+ RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect");
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "volumetric_end", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_default(prop, 100.0f);
+ RNA_def_property_ui_text(prop, "End", "End distance of the volumetric effect");
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "volumetric_tile_size", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_default(prop, 8);
+ RNA_def_property_enum_items(prop, eevee_volumetric_tile_size_items);
+ RNA_def_property_ui_text(prop, "Tile Size", "Control the quality of the volumetric effects "
+ "(lower size increase vram usage and quality)");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "volumetric_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 64);
+ RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute volumetric effects");
+ RNA_def_property_range(prop, 1, 256);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "volumetric_sample_distribution", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.8f);
+ RNA_def_property_ui_text(prop, "Exponential Sampling", "Distribute more samples closer to the camera");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_volumetric_lights", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_LIGHTS);
+ RNA_def_property_boolean_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Volumetric Lighting", "Enable scene light interactions with volumetrics");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "volumetric_light_clamp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Clamp", "Maximum light contribution, reducing noise");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_volumetric_shadows", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_SHADOWS);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Volumetric Shadows", "Generate shadows from volumetric material (Very expensive)");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "volumetric_shadow_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_default(prop, 16);
+ RNA_def_property_range(prop, 1, 128);
+ RNA_def_property_ui_text(prop, "Volumetric Shadow Samples", "Number of samples to compute volumetric shadowing");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Ambient Occlusion */
+ prop = RNA_def_property(srna, "use_gtao", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_ENABLED);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Ambient Occlusion", "Enable ambient occlusion to simulate medium scale indirect shadowing");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_gtao_bent_normals", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BENT_NORMALS);
+ RNA_def_property_boolean_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Bent Normals", "Compute main non occluded direction to sample the environment");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_gtao_bounce", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BOUNCE);
+ RNA_def_property_boolean_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Bounces Approximation", "An approximation to simulate light bounces "
+ "giving less occlusion on brighter objects");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gtao_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Factor", "Factor for ambient occlusion blending");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 2);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gtao_quality", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.25f);
+ RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the horizon search");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "gtao_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_default(prop, 0.2f);
+ RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the ambient occlusion effect");
+ RNA_def_property_range(prop, 0.0f, 100000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Depth of Field */
+ prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_DOF_ENABLED);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Depth of Field", "Enable depth of field using the values from the active camera");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "bokeh_max_size", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 100.0f);
+ RNA_def_property_ui_text(prop, "Max Size", "Max size of the bokeh shape for the depth of field (lower is faster)");
+ RNA_def_property_range(prop, 0.0f, 2000.0f);
+ RNA_def_property_ui_range(prop, 2.0f, 200.0f, 1, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "bokeh_threshold", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Sprite Threshold", "Brightness threshold for using sprite base depth of field");
+ RNA_def_property_range(prop, 0.0f, 100000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Bloom */
+ prop = RNA_def_property(srna, "use_bloom", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_BLOOM_ENABLED);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Bloom", "High brightness pixels generate a glowing effect");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "bloom_threshold", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.8f);
+ RNA_def_property_ui_text(prop, "Threshold", "Filters out pixels under this level of brightness");
+ RNA_def_property_range(prop, 0.0f, 100000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "bloom_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_array_default(prop, default_bloom_color);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Color applied to the bloom effect");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "bloom_knee", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Knee", "Makes transition between under/over-threshold gradual");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "bloom_radius", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 6.5f);
+ RNA_def_property_ui_text(prop, "Radius", "Bloom spread distance");
+ RNA_def_property_range(prop, 0.0f, 100.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "bloom_clamp", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Clamp", "Maximum intensity a bloom pixel can have");
+ RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "bloom_intensity", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_default(prop, 0.8f);
+ RNA_def_property_ui_text(prop, "Intensity", "Blend factor");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Motion blur */
+ prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_MOTION_BLUR_ENABLED);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Motion Blur", "Enable motion blur effect (only in camera view)");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_default(prop, 8);
+ RNA_def_property_ui_text(prop, "Samples", "Number of samples to take with motion blur");
+ RNA_def_property_range(prop, 1, 64);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close");
+ RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 2);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Shadows */
+ prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_default(prop, SHADOW_ESM);
+ RNA_def_property_enum_items(prop, eevee_shadow_method_items);
+ RNA_def_property_ui_text(prop, "Method", "Technique use to compute the shadows");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "shadow_cube_size", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_default(prop, 512);
+ RNA_def_property_enum_items(prop, eevee_shadow_size_items);
+ RNA_def_property_ui_text(prop, "Cube Shadows Resolution", "Size of point and area light shadow maps");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "shadow_cascade_size", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_default(prop, 1024);
+ RNA_def_property_enum_items(prop, eevee_shadow_size_items);
+ RNA_def_property_ui_text(prop, "Directional Shadows Resolution", "Size of sun light shadow maps");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_shadow_high_bitdepth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "High Bitdepth", "Use 32bit shadows");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "use_soft_shadows", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_SOFT);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Soft Shadows", "Randomize shadowmaps origin to create soft shadows");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "light_threshold", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_default(prop, 0.01f);
+ RNA_def_property_ui_text(prop, "Light Threshold", "Minimum light intensity for a light to contribute to the lighting");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ /* Overscan */
+ prop = RNA_def_property(srna, "use_overscan", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_OVERSCAN);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_ui_text(prop, "Overscan", "Internally render past the image border to avoid "
+ "screen-space effects disapearing");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+
+ prop = RNA_def_property(srna, "overscan_size", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_float_sdna(prop, NULL, "overscan");
+ RNA_def_property_float_default(prop, 3.0f);
+ RNA_def_property_ui_text(prop, "Overscan Size", "Percentage of render size to add as overscan to the "
+ "internal render buffers");
+ RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 2);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+}
void RNA_def_scene(BlenderRNA *brna)
{
@@ -6921,51 +6130,35 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_pointer_funcs(prop, NULL, "rna_Scene_set_set", NULL, NULL);
RNA_def_property_ui_text(prop, "Background Scene", "Background set scene");
- RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
+ RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_set_update");
prop = RNA_def_property(srna, "world", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "World", "World used for rendering the scene");
- RNA_def_property_update(prop, NC_SCENE | ND_WORLD, "rna_Scene_glsl_update");
+ RNA_def_property_update(prop, NC_SCENE | ND_WORLD, "rna_Scene_world_update");
prop = RNA_def_property(srna, "cursor_location", PROP_FLOAT, PROP_XYZ_LENGTH);
- RNA_def_property_float_sdna(prop, NULL, "cursor");
+ RNA_def_property_float_sdna(prop, NULL, "cursor.location");
RNA_def_property_ui_text(prop, "Cursor Location", "3D cursor location");
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, 4);
RNA_def_property_update(prop, NC_WINDOW, NULL);
- /* Bases/Objects */
- prop = RNA_def_property(srna, "object_bases", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "base", NULL);
- RNA_def_property_struct_type(prop, "ObjectBase");
- RNA_def_property_ui_text(prop, "Bases", "");
- RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL,
- "rna_Scene_object_bases_lookup_string", NULL);
- rna_def_scene_bases(brna, prop);
+ prop = RNA_def_property(srna, "cursor_rotation", PROP_FLOAT, PROP_QUATERNION);
+ RNA_def_property_float_sdna(prop, NULL, "cursor.rotation");
+ RNA_def_property_ui_text(prop, "Cursor Rotation", "3D cursor rotation in quaternions (keep normalized)");
+ RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "base", NULL);
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_ui_text(prop, "Objects", "");
- RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_Scene_objects_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_collection_funcs(prop,
+ "rna_Scene_objects_begin",
+ "rna_Scene_objects_next",
+ "rna_Scene_objects_end",
+ "rna_Scene_objects_get",
+ NULL, NULL, NULL, NULL);
rna_def_scene_objects(brna, prop);
- /* Layers */
- prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- /* this seems to be too much trouble with depsgraph updates/etc. currently (20110420) */
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_boolean_sdna(prop, NULL, "lay", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Scene_layer_set");
- RNA_def_property_ui_text(prop, "Layers", "Visible layers - Shift-Click/Drag to select multiple layers");
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_Scene_layer_update");
-
- /* active layer */
- prop = RNA_def_property(srna, "active_layer", PROP_INT, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_int_funcs(prop, "rna_Scene_active_layer_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Active Layer", "Active scene layer index");
-
/* Frame Range Stuff */
prop = RNA_def_property(srna, "frame_current", PROP_INT, PROP_TIME);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -6997,6 +6190,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "r.sfra");
RNA_def_property_int_funcs(prop, NULL, "rna_Scene_start_frame_set", NULL);
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
+ RNA_def_property_int_default(prop, 1);
RNA_def_property_ui_text(prop, "Start Frame", "First frame of the playback/rendering range");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME_RANGE, NULL);
@@ -7005,6 +6199,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "r.efra");
RNA_def_property_int_funcs(prop, NULL, "rna_Scene_end_frame_set", NULL);
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
+ RNA_def_property_int_default(prop, 250);
RNA_def_property_ui_text(prop, "End Frame", "Final frame of the playback/rendering range");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME_RANGE, NULL);
@@ -7030,7 +6225,6 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Lock Frame Selection",
"Don't allow frame to be selected with mouse outside of frame range");
RNA_def_property_update(prop, NC_SCENE | ND_FRAME, NULL);
- RNA_def_property_ui_icon(prop, ICON_LOCKED, 0);
/* Preview Range (frame-range for UI playback) */
prop = RNA_def_property(srna, "use_preview_range", PROP_BOOLEAN, PROP_NONE);
@@ -7091,14 +6285,17 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
/* Frame dropping flag for playback and sync enum */
+#if 0 /* XXX: Is this actually needed? */
prop = RNA_def_property(srna, "use_frame_drop", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_FRAME_DROP);
RNA_def_property_ui_text(prop, "Frame Dropping", "Play back dropping frames if frame display is too slow");
RNA_def_property_update(prop, NC_SCENE, NULL);
+#endif
prop = RNA_def_property(srna, "sync_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_funcs(prop, "rna_Scene_sync_mode_get", "rna_Scene_sync_mode_set", NULL);
RNA_def_property_enum_items(prop, sync_mode_items);
+ RNA_def_property_enum_default(prop, AUDIO_SYNC);
RNA_def_property_ui_text(prop, "Sync Mode", "How to sync playback");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -7193,17 +6390,33 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Timeline Markers", "Markers used in all timelines for the current scene");
rna_def_timeline_markers(brna, prop);
+ /* Orientations */
+ prop = RNA_def_property(srna, "transform_orientation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "orientation_type");
+ RNA_def_property_enum_items(prop, rna_enum_transform_orientation_items);
+ RNA_def_property_enum_funcs(prop, "rna_Scene_transform_orientation_get", "rna_Scene_transform_orientation_set",
+ "rna_TransformOrientation_itemf");
+ RNA_def_property_ui_text(prop, "Transform Orientation", "Transformation orientation");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "current_orientation", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "TransformOrientation");
+ RNA_def_property_pointer_funcs(prop, "rna_Scene_current_orientation_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Current Transform Orientation", "Current transformation orientation");
+
/* Audio Settings */
prop = RNA_def_property(srna, "use_audio", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Scene_use_audio_get", "rna_Scene_use_audio_set");
RNA_def_property_ui_text(prop, "Audio Muted", "Play back of audio from Sequence Editor will be muted");
RNA_def_property_update(prop, NC_SCENE, NULL);
+#if 0 /* XXX: Is this actually needed? */
prop = RNA_def_property(srna, "use_audio_sync", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SYNC);
RNA_def_property_ui_text(prop, "Audio Sync",
"Play back and sync with audio clock, dropping frames if frame display is too slow");
RNA_def_property_update(prop, NC_SCENE, NULL);
+#endif
prop = RNA_def_property(srna, "use_audio_scrub", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "audio.flag", AUDIO_SCRUB);
@@ -7239,15 +6452,10 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE, NULL);
RNA_def_property_float_funcs(prop, NULL, "rna_Scene_volume_set", NULL);
- /* Game Settings */
- prop = RNA_def_property(srna, "game_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "gm");
- RNA_def_property_struct_type(prop, "SceneGameData");
- RNA_def_property_ui_text(prop, "Game Data", "");
-
/* Statistics */
func = RNA_def_function(srna, "statistics", "ED_info_stats_string");
+ parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "Active layer");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "statistics", NULL, 0, "Statistics", "");
RNA_def_function_return(func, parm);
@@ -7255,16 +6463,11 @@ void RNA_def_scene(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
+ RNA_def_property_ui_text(prop, "Annotations", "Grease Pencil data-block used for annotations in the 3D view");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- /* Transform Orientations */
- prop = RNA_def_property(srna, "orientations", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "transform_spaces", NULL);
- RNA_def_property_struct_type(prop, "TransformOrientation");
- RNA_def_property_ui_text(prop, "Transform Orientations", "");
-
/* active MovieClip */
prop = RNA_def_property(srna, "active_clip", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "clip");
@@ -7289,30 +6492,48 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ColorManagedSequencerColorspaceSettings");
RNA_def_property_ui_text(prop, "Sequencer Color Space Settings", "Settings of color space sequencer is working in");
- /* Dependency Graph */
- prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Depsgraph");
- RNA_def_property_ui_text(prop, "Dependency Graph", "Dependencies in the scene data");
+ /* Layer and Collections */
+ prop = RNA_def_property(srna, "view_layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "view_layers", NULL);
+ RNA_def_property_struct_type(prop, "ViewLayer");
+ RNA_def_property_ui_text(prop, "View Layers", "");
+ rna_def_view_layers(brna, prop);
+
+ prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "master_collection");
+ RNA_def_property_struct_type(prop, "Collection");
+ RNA_def_property_ui_text(prop, "Collection", "Scene master collection that objects and other collections in the scene");
+
+ /* Scene Display */
+ prop = RNA_def_property(srna, "display", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "display");
+ RNA_def_property_struct_type(prop, "SceneDisplay");
+ RNA_def_property_ui_text(prop, "Scene Display", "Scene display settings for 3d viewport");
+
+ /* EEVEE */
+ prop = RNA_def_property(srna, "eevee", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneEEVEE");
+ RNA_def_property_ui_text(prop, "EEVEE", "EEVEE settings for the scene");
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
rna_def_tool_settings(brna);
- rna_def_gpencil_brush(brna);
rna_def_gpencil_interpolate(brna);
rna_def_unified_paint_settings(brna);
rna_def_curve_paint_settings(brna);
rna_def_statvis(brna);
rna_def_unit_settings(brna);
rna_def_scene_image_format_data(brna);
- rna_def_scene_game_data(brna);
rna_def_transform_orientation(brna);
rna_def_selected_uv_element(brna);
rna_def_display_safe_areas(brna);
+ rna_def_scene_display(brna);
+ rna_def_scene_eevee(brna);
RNA_define_animate_sdna(true);
/* *** Animated *** */
rna_def_scene_render_data(brna);
- rna_def_scene_render_layer(brna);
rna_def_gpu_fx(brna);
rna_def_scene_render_view(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index eff9576248c..f25e093c8a9 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -60,13 +60,14 @@ const EnumPropertyItem rna_enum_abc_compression_items[] = {
#ifdef RNA_RUNTIME
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_scene.h"
#include "BKE_writeavi.h"
+#include "DEG_depsgraph_query.h"
+
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
@@ -86,8 +87,13 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
BPy_BEGIN_ALLOW_THREADS;
#endif
- /* It's possible that here we're including layers which were never visible before. */
- BKE_scene_update_for_newframe_ex(bmain->eval_ctx, bmain, scene, (1 << 20) - 1, true);
+ for (ViewLayer *view_layer = scene->view_layers.first;
+ view_layer != NULL;
+ view_layer = view_layer->next)
+ {
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+ }
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -99,7 +105,7 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
* redrawing while the data is being modified for render */
if (!G.is_rendering) {
/* cant use NC_SCENE|ND_FRAME because this causes wm_event_do_notifiers to call
- * BKE_scene_update_for_newframe which will loose any un-keyed changes [#24690] */
+ * BKE_scene_graph_update_for_newframe which will loose any un-keyed changes [#24690] */
/* WM_main_add_notifier(NC_SCENE|ND_FRAME, scene); */
/* instead just redraw the views */
@@ -127,7 +133,13 @@ static void rna_Scene_update_tagged(Scene *scene, Main *bmain)
BPy_BEGIN_ALLOW_THREADS;
#endif
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, scene);
+ for (ViewLayer *view_layer = scene->view_layers.first;
+ view_layer != NULL;
+ view_layer = view_layer->next)
+ {
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+ }
#ifdef WITH_PYTHON
BPy_END_ALLOW_THREADS;
@@ -154,14 +166,15 @@ static void rna_SceneRender_get_frame_path(
}
static void rna_Scene_ray_cast(
- Scene *scene, Main *bmain,
+ Scene *scene, Main *bmain, ViewLayer *view_layer,
float origin[3], float direction[3], float ray_dist,
bool *r_success, float r_location[3], float r_normal[3], int *r_index,
Object **r_ob, float r_obmat[16])
{
normalize_v3(direction);
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, 0);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, 0);
bool ret = ED_transform_snap_object_project_ray_ex(
sctx,
@@ -174,6 +187,10 @@ static void rna_Scene_ray_cast(
ED_transform_snap_object_context_destroy(sctx);
+ if (r_ob != NULL && *r_ob != NULL) {
+ *r_ob = DEG_get_original_object(*r_ob);
+ }
+
if (ret) {
*r_success = true;
}
@@ -299,6 +316,8 @@ void RNA_api_scene(StructRNA *srna)
func = RNA_def_function(srna, "ray_cast", "rna_Scene_ray_cast");
RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Cast a ray onto in object space");
+ parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "Scene Layer");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
/* ray start and end */
parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
@@ -333,7 +352,6 @@ void RNA_api_scene(StructRNA *srna)
func = RNA_def_function(srna, "sequence_editor_clear", "rna_Scene_sequencer_editing_free");
RNA_def_function_ui_description(func, "Clear sequence editor in this scene");
-
#ifdef WITH_ALEMBIC
/* XXX Deprecated, will be removed in 2.8 in favour of calling the export operator. */
func = RNA_def_function(srna, "alembic_export", "rna_Scene_alembic_export");
@@ -362,7 +380,7 @@ void RNA_api_scene(StructRNA *srna)
RNA_def_boolean(func, "export_hair", 1, "Export Hair", "Exports hair particle systems as animated curves");
RNA_def_boolean(func, "export_particles", 1, "Export Particles", "Exports non-hair particle systems");
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_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_boolean(func, "triangulate", 0, "Triangulate", "Export Polygons (Quads & NGons) as Triangles");
RNA_def_enum(func, "quad_method", rna_enum_modifier_triangulate_quad_method_items, 0, "Quad Method", "Method for splitting the quads into triangles");
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 0a997ca2163..0a7c71a683e 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -35,6 +35,7 @@
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
+#include "DNA_workspace_types.h"
const EnumPropertyItem rna_enum_region_type_items[] = {
{RGN_TYPE_WINDOW, "WINDOW", 0, "Window", ""},
@@ -45,6 +46,7 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
{RGN_TYPE_TOOLS, "TOOLS", 0, "Tools", ""},
{RGN_TYPE_TOOL_PROPS, "TOOL_PROPS", 0, "Tool Properties", ""},
{RGN_TYPE_PREVIEW, "PREVIEW", 0, "Preview", ""},
+ {RGN_TYPE_NAV_BAR, "NAVIGATION_BAR", 0, "Navigation Bar", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -56,7 +58,10 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
#ifdef RNA_RUNTIME
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
+#include "BKE_workspace.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
#include "UI_view2d.h"
@@ -64,55 +69,72 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
# include "BPY_extern.h"
#endif
-static void rna_Screen_scene_set(PointerRNA *ptr, PointerRNA value)
+static void rna_Screen_bar_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- bScreen *sc = (bScreen *)ptr->data;
-
- if (value.data == NULL)
- return;
-
- sc->newscene = value.data;
+ bScreen *screen = (bScreen *)ptr->data;
+ screen->do_draw = true;
+ screen->do_refresh = true;
}
-static void rna_Screen_scene_update(bContext *C, PointerRNA *ptr)
+static void rna_Screen_redraw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- bScreen *sc = (bScreen *)ptr->data;
-
- /* exception: must use context so notifier gets to the right window */
- if (sc->newscene) {
-#ifdef WITH_PYTHON
- BPy_BEGIN_ALLOW_THREADS;
-#endif
+ bScreen *screen = (bScreen *)ptr->data;
- ED_screen_set_scene(C, sc, sc->newscene);
+ /* the settings for this are currently only available from a menu in the TimeLine,
+ * hence refresh=SPACE_ACTION, as timeline is now in there
+ */
+ ED_screen_animation_timer_update(screen, screen->redraws_flag, SPACE_ACTION);
+}
-#ifdef WITH_PYTHON
- BPy_END_ALLOW_THREADS;
-#endif
+static bool rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr))
+{
+ /* can be NULL on file load, T42619 */
+ wmWindowManager *wm = G_MAIN->wm.first;
+ return wm ? (ED_screen_animation_playing(wm) != NULL) : 0;
+}
- WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, sc->newscene);
+static int rna_region_alignment_get(PointerRNA *ptr)
+{
+ ARegion *region = ptr->data;
+ return (region->alignment & ~RGN_SPLIT_PREV);
+}
- if (G.debug & G_DEBUG)
- printf("scene set %p\n", sc->newscene);
+static void rna_Screen_layout_name_get(PointerRNA *ptr, char *value)
+{
+ const bScreen *screen = ptr->data;
+ const WorkSpaceLayout *layout = BKE_workspace_layout_find_global(G_MAIN, screen, NULL);
- sc->newscene = NULL;
+ if (layout) {
+ const char *name = BKE_workspace_layout_name_get(layout);
+ strcpy(value, name);
+ }
+ else {
+ value[0] = '\0';
}
}
-static void rna_Screen_redraw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static int rna_Screen_layout_name_length(PointerRNA *ptr)
{
- bScreen *screen = (bScreen *)ptr->data;
+ const bScreen *screen = ptr->data;
+ const WorkSpaceLayout *layout = BKE_workspace_layout_find_global(G_MAIN, screen, NULL);
- /* the settings for this are currently only available from a menu in the TimeLine, hence refresh=SPACE_TIME */
- ED_screen_animation_timer_update(screen, screen->redraws_flag, SPACE_TIME);
-}
+ if (layout) {
+ const char *name = BKE_workspace_layout_name_get(layout);
+ return strlen(name);
+ }
+ return 0;
+}
-static bool rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr))
+static void rna_Screen_layout_name_set(PointerRNA *ptr, const char *value)
{
- /* can be NULL on file load, T42619 */
- wmWindowManager *wm = G_MAIN->wm.first;
- return wm ? (ED_screen_animation_playing(wm) != NULL) : 0;
+ bScreen *screen = ptr->data;
+ WorkSpace *workspace;
+ WorkSpaceLayout *layout = BKE_workspace_layout_find_global(G_MAIN, screen, &workspace);
+
+ if (layout) {
+ BKE_workspace_layout_name_set(workspace, layout, value);
+ }
}
static bool rna_Screen_fullscreen_get(PointerRNA *ptr)
@@ -124,21 +146,41 @@ static bool rna_Screen_fullscreen_get(PointerRNA *ptr)
/* UI compatible list: should not be needed, but for now we need to keep EMPTY
* at least in the static version of this enum for python scripts. */
static const EnumPropertyItem *rna_Area_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
/* +1 to skip SPACE_EMPTY */
- return rna_enum_space_type_items + 1;
+ for (const EnumPropertyItem *item_from = rna_enum_space_type_items + 1; item_from->identifier; item_from++) {
+ if (ELEM(item_from->value, SPACE_TOPBAR, SPACE_STATUSBAR)) {
+ continue;
+ }
+ RNA_enum_item_add(&item, &totitem, item_from);
+ }
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
}
static int rna_Area_type_get(PointerRNA *ptr)
{
ScrArea *sa = (ScrArea *)ptr->data;
- /* read from this instead of 'spacetype' for correct reporting: T41435 */
- return sa->butspacetype;
+ /* Usually 'spacetype' is used. It lags behind a bit while switching area
+ * type though, then we use 'butspacetype' instead (T41435). */
+ return (sa->butspacetype == SPACE_EMPTY) ? sa->spacetype : sa->butspacetype;
}
static void rna_Area_type_set(PointerRNA *ptr, int value)
{
+ if (ELEM(value, SPACE_TOPBAR, SPACE_STATUSBAR)) {
+ /* Special case: An area can not be set to show the top-bar editor (or
+ * other global areas). However it should still be possible to identify
+ * its type from Python. */
+ return;
+ }
+
ScrArea *sa = (ScrArea *)ptr->data;
sa->butspacetype = value;
}
@@ -152,7 +194,7 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
/* XXX this call still use context, so we trick it to work in the right context */
for (win = wm->windows.first; win; win = win->next) {
- if (sc == win->screen) {
+ if (sc == WM_window_get_active_screen(win)) {
wmWindow *prevwin = CTX_wm_window(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *prevar = CTX_wm_region(C);
@@ -164,9 +206,12 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
ED_area_newspace(C, sa, sa->butspacetype, true);
ED_area_tag_redraw(sa);
+ /* Unset so that rna_Area_type_get uses spacetype instead. */
+ sa->butspacetype = SPACE_EMPTY;
+
/* It is possible that new layers becomes visible. */
if (sa->spacetype == SPACE_VIEW3D) {
- DAG_on_visible_update(CTX_data_main(C), false);
+ DEG_on_visible_update(CTX_data_main(C), false);
}
CTX_wm_window_set(C, prevwin);
@@ -177,6 +222,75 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
}
}
+
+static const EnumPropertyItem *rna_Area_ui_type_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ /* +1 to skip SPACE_EMPTY */
+ for (const EnumPropertyItem *item_from = rna_enum_space_type_items + 1; item_from->identifier; item_from++) {
+ if (ELEM(item_from->value, SPACE_TOPBAR, SPACE_STATUSBAR)) {
+ continue;
+ }
+
+ SpaceType *st = item_from->identifier[0] ? BKE_spacetype_from_id(item_from->value) : NULL;
+ int totitem_prev = totitem;
+ if (st && st->space_subtype_item_extend != NULL) {
+ st->space_subtype_item_extend(C, &item, &totitem);
+ while (totitem_prev < totitem) {
+ item[totitem_prev++].value |= item_from->value << 16;
+ }
+ }
+ else {
+ RNA_enum_item_add(&item, &totitem, item_from);
+ item[totitem_prev++].value = item_from->value << 16;
+ }
+ }
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static int rna_Area_ui_type_get(PointerRNA *ptr)
+{
+ int value = rna_Area_type_get(ptr) << 16;
+ ScrArea *sa = ptr->data;
+ if (sa->type->space_subtype_item_extend != NULL) {
+ value |= sa->type->space_subtype_get(sa);
+ }
+ return value;
+}
+
+static void rna_Area_ui_type_set(PointerRNA *ptr, int value)
+{
+ ScrArea *sa = ptr->data;
+ const int space_type = value >> 16;
+ SpaceType *st = BKE_spacetype_from_id(space_type);
+
+ rna_Area_type_set(ptr, space_type);
+
+ if (st && st->space_subtype_item_extend != NULL) {
+ sa->butspacetype_subtype = value & 0xffff;
+ }
+}
+
+static void rna_Area_ui_type_update(bContext *C, PointerRNA *ptr)
+{
+ ScrArea *sa = ptr->data;
+ SpaceType *st = BKE_spacetype_from_id(sa->butspacetype);
+
+ rna_Area_type_update(C, ptr);
+
+ if ((sa->type == st) && (st->space_subtype_item_extend != NULL)) {
+ st->space_subtype_set(sa, sa->butspacetype_subtype);
+ }
+ sa->butspacetype_subtype = 0;
+}
+
static void rna_View2D_region_to_view(struct View2D *v2d, int x, int y, float result[2])
{
UI_view2d_region_to_view(v2d, x, y, &result[0], &result[1]);
@@ -212,12 +326,15 @@ static void rna_def_area_spaces(BlenderRNA *brna, PropertyRNA *cprop)
static void rna_def_area_api(StructRNA *srna)
{
FunctionRNA *func;
+ PropertyRNA *parm;
RNA_def_function(srna, "tag_redraw", "ED_area_tag_redraw");
- func = RNA_def_function(srna, "header_text_set", "ED_area_headerprint");
- RNA_def_function_ui_description(func, "Set the header text");
- RNA_def_string(func, "text", NULL, 0, "Text", "New string for the header, no argument clears the text");
+ func = RNA_def_function(srna, "header_text_set", "ED_area_status_text");
+ RNA_def_function_ui_description(func, "Set the header status text");
+ parm = RNA_def_string(func, "text", NULL, 0, "Text", "New string for the header, None clears the text");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_clear_flag(parm, PROP_NEVER_NULL);
}
static void rna_def_area(BlenderRNA *brna)
@@ -257,6 +374,15 @@ static void rna_def_area(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, 0, "rna_Area_type_update");
+ prop = RNA_def_property(srna, "ui_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items); /* infact dummy */
+ RNA_def_property_enum_default(prop, 0);
+ RNA_def_property_enum_funcs(prop, "rna_Area_ui_type_get", "rna_Area_ui_type_set", "rna_Area_ui_type_itemf");
+ RNA_def_property_ui_text(prop, "Editor Type", "Current editor type for this area");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Area_ui_type_update");
+
prop = RNA_def_property(srna, "x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "totrct.xmin");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -329,15 +455,23 @@ static void rna_def_region(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static const EnumPropertyItem alignment_types[] = {
+ {RGN_ALIGN_NONE, "NONE", 0, "None", "Don't use any fixed alignment, fill available space"},
+ {RGN_ALIGN_TOP, "TOP", 0, "Top", ""},
+ {RGN_ALIGN_BOTTOM, "BOTTOM", 0, "Bottom", ""},
+ {RGN_ALIGN_LEFT, "LEFT", 0, "Left", ""},
+ {RGN_ALIGN_RIGHT, "RIGHT", 0, "Right", ""},
+ {RGN_ALIGN_HSPLIT, "HORIZONTAL_SPLIT", 0, "Horizontal Split", ""},
+ {RGN_ALIGN_VSPLIT, "VERTICAL_SPLIT", 0, "Vertical Split", ""},
+ {RGN_ALIGN_FLOAT, "FLOAT", 0, "Float", "Region floats on screen, doesn't use any fixed alignment"},
+ {RGN_ALIGN_QSPLIT, "QUAD_SPLIT", 0, "Quad Split", "Region is split horizontally and vertically"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "Region", NULL);
RNA_def_struct_ui_text(srna, "Region", "Region in a subdivided screen area");
RNA_def_struct_sdna(srna, "ARegion");
- prop = RNA_def_property(srna, "id", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "swinid");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Region ID", "Unique ID for this region");
-
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "regiontype");
RNA_def_property_enum_items(prop, rna_enum_region_type_items);
@@ -370,6 +504,12 @@ static void rna_def_region(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "View2D", "2D view of the region");
+ prop = RNA_def_property(srna, "alignment", PROP_ENUM, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_items(prop, alignment_types);
+ RNA_def_property_enum_funcs(prop, "rna_region_alignment_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Alignment", "Alignment of the region within the area");
+
RNA_def_function(srna, "tag_redraw", "ED_region_tag_redraw");
}
@@ -381,15 +521,13 @@ static void rna_def_screen(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Screen", "ID");
RNA_def_struct_sdna(srna, "Screen"); /* it is actually bScreen but for 2.5 the dna is patched! */
RNA_def_struct_ui_text(srna, "Screen", "Screen data-block, defining the layout of areas in a window");
- RNA_def_struct_ui_icon(srna, ICON_SPLITSCREEN);
+ RNA_def_struct_ui_icon(srna, ICON_WORKSPACE);
- /* pointers */
- prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Screen_scene_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Scene", "Active scene to be edited in the screen");
- RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, 0, "rna_Screen_scene_update");
+ prop = RNA_def_property(srna, "layout_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_Screen_layout_name_get", "rna_Screen_layout_name_length",
+ "rna_Screen_layout_name_set");
+ RNA_def_property_ui_text(prop, "Layout Name", "The name of the layout that refers to the screen");
+ RNA_def_struct_name_property(srna, prop);
/* collections */
prop = RNA_def_property(srna, "areas", PROP_COLLECTION, PROP_NONE);
@@ -408,6 +546,16 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Screen_fullscreen_get", NULL);
RNA_def_property_ui_text(prop, "Maximize", "An area is maximized, filling this screen");
+ prop = RNA_def_property(srna, "show_topbar", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCREEN_COLLAPSE_TOPBAR);
+ RNA_def_property_ui_text(prop, "Show Top Bar", "Show top bar with tool settings");
+ RNA_def_property_update(prop, 0, "rna_Screen_bar_update");
+
+ prop = RNA_def_property(srna, "show_statusbar", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCREEN_COLLAPSE_STATUSBAR);
+ RNA_def_property_ui_text(prop, "Show Status Bar", "Show status bar");
+ RNA_def_property_update(prop, 0, "rna_Screen_bar_update");
+
/* Define Anim Playback Areas */
prop = RNA_def_property(srna, "use_play_top_left_3d_editor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_REGION);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 92f05bf366f..d106e2db6eb 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -35,6 +35,7 @@
#include "rna_internal.h"
#include "DNA_ID.h"
+#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "DNA_screen_types.h"
@@ -43,6 +44,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_paint.h"
+#include "BKE_brush.h"
#include "ED_image.h"
@@ -64,27 +66,30 @@ const EnumPropertyItem rna_enum_particle_edit_hair_brush_items[] = {
};
const EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
- {GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth stroke points"},
- {GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", 0, "Thickness", "Adjust thickness of strokes"},
- { GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", 0, "Strength", "Adjust color strength of strokes" },
- { GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle" },
- {GP_EDITBRUSH_TYPE_PUSH, "PUSH", 0, "Push", "Move points out of the way, as if combing them"},
- {GP_EDITBRUSH_TYPE_TWIST, "TWIST", 0, "Twist", "Rotate points around the midpoint of the brush"},
- {GP_EDITBRUSH_TYPE_PINCH, "PINCH", 0, "Pinch", "Pull points towards the midpoint of the brush"},
- {GP_EDITBRUSH_TYPE_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Introduce jitter/randomness into strokes"},
- //{GP_EDITBRUSH_TYPE_SUBDIVIDE, "SUBDIVIDE", 0, "Subdivide", "Increase point density for higher resolution strokes when zoomed in"},
- //{GP_EDITBRUSH_TYPE_SIMPLIFY, "SIMPLIFY", 0, "Simplify", "Reduce density of stroke points"},
- {GP_EDITBRUSH_TYPE_CLONE, "CLONE", 0, "Clone", "Paste copies of the strokes stored on the clipboard"},
+ {GP_SCULPT_TYPE_SMOOTH, "SMOOTH", ICON_GPBRUSH_SMOOTH, "Smooth", "Smooth stroke points"},
+ {GP_SCULPT_TYPE_THICKNESS, "THICKNESS", ICON_GPBRUSH_THICKNESS, "Thickness", "Adjust thickness of strokes"},
+ {GP_SCULPT_TYPE_STRENGTH, "STRENGTH", ICON_GPBRUSH_STRENGTH, "Strength", "Adjust color strength of strokes" },
+ {GP_SCULPT_TYPE_GRAB, "GRAB", ICON_GPBRUSH_GRAB, "Grab", "Translate the set of points initially within the brush circle" },
+ {GP_SCULPT_TYPE_PUSH, "PUSH", ICON_GPBRUSH_PUSH, "Push", "Move points out of the way, as if combing them"},
+ {GP_SCULPT_TYPE_TWIST, "TWIST", ICON_GPBRUSH_TWIST, "Twist", "Rotate points around the midpoint of the brush"},
+ {GP_SCULPT_TYPE_PINCH, "PINCH", ICON_GPBRUSH_PINCH, "Pinch", "Pull points towards the midpoint of the brush"},
+ {GP_SCULPT_TYPE_RANDOMIZE, "RANDOMIZE", ICON_GPBRUSH_RANDOMIZE, "Randomize", "Introduce jitter/randomness into strokes"},
+ {GP_SCULPT_TYPE_CLONE, "CLONE", ICON_GPBRUSH_CLONE, "Clone", "Paste copies of the strokes stored on the clipboard"},
{ 0, NULL, 0, NULL, NULL }
};
+const EnumPropertyItem rna_enum_gpencil_weight_brush_items[] = {
+ {GP_SCULPT_TYPE_WEIGHT, "WEIGHT", ICON_GPBRUSH_WEIGHT, "Weight", "Weight Paint for Vertex Groups"},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifndef RNA_RUNTIME
-static const EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = {
- { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", 0, "None", "" },
- { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Project strokes to plane locked to X" },
- { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Project strokes to plane locked to Y" },
- { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Project strokes to plane locked to Z" },
- { 0, NULL, 0, NULL, NULL }
+static const EnumPropertyItem rna_enum_gpencil_lock_axis_items[] = {
+ {GP_LOCKAXIS_VIEW, "VIEW", ICON_RESTRICT_VIEW_ON, "View", "Align strokes to current view plane"},
+ {GP_LOCKAXIS_Y, "AXIS_Y", ICON_AXIS_FRONT, "Front (X-Z)", "Project strokes to plane locked to Y"},
+ {GP_LOCKAXIS_X, "AXIS_X", ICON_AXIS_SIDE, "Side (Y-Z)", "Project strokes to plane locked to X"},
+ {GP_LOCKAXIS_Z, "AXIS_Z", ICON_AXIS_TOP, "Top (X-Y)", "Project strokes to plane locked to Z"},
+ {0, NULL, 0, NULL, NULL}
};
#endif
@@ -103,20 +108,36 @@ const EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
#include "BKE_particle.h"
-#include "BKE_pointcache.h"
#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_object.h"
+#include "BKE_gpencil.h"
-#include "GPU_buffers.h"
+
+#include "DEG_depsgraph.h"
#include "ED_particle.h"
-static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_GPencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
+ /* mark all grease pencil datablocks of the scene */
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
+ {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob)
+ {
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
@@ -154,32 +175,43 @@ static PointerRNA rna_ParticleBrush_curve_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_CurveMapping, NULL);
}
-static void rna_ParticleEdit_redo(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
if (!edit)
return;
+ if (ob) DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
psys_free_path_cache(edit->psys, edit);
+ DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_COPY_ON_WRITE);
}
-static void rna_ParticleEdit_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_ParticleEdit_update(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+
+ if (ob) DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- if (ob) DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* Sync tool setting changes from original to evaluated scenes. */
+ DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_COPY_ON_WRITE);
}
+
static void rna_ParticleEdit_tool_set(PointerRNA *ptr, int value)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
/* redraw hair completely if weight brush is/was used */
- if ((pset->brushtype == PE_BRUSH_WEIGHT || value == PE_BRUSH_WEIGHT) && pset->scene) {
- Object *ob = (pset->scene->basact) ? pset->scene->basact->object : NULL;
+ if ((pset->brushtype == PE_BRUSH_WEIGHT || value == PE_BRUSH_WEIGHT) && pset->object) {
+ Object *ob = pset->object;
if (ob) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
}
}
@@ -190,11 +222,11 @@ static const EnumPropertyItem *rna_ParticleEdit_tool_itemf(
bContext *C, PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
#if 0
- Main *bmain = CTX_data_main(C);
- PTCacheEdit *edit = PE_get_current(bmain, scene, ob);
+ Scene *scene = CTX_data_scene(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
ParticleSystem *psys = edit ? edit->psys : NULL;
#else
/* use this rather than PE_get_current() - because the editing cache is
@@ -219,20 +251,14 @@ static bool rna_ParticleEdit_editable_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
- if (pset->object != NULL && pset->scene != NULL) {
- BLI_assert(BKE_id_is_in_gobal_main(&pset->object->id));
- BLI_assert(BKE_id_is_in_gobal_main(&pset->scene->id));
- }
- return (pset->object && pset->scene && PE_get_current(G_MAIN, pset->scene, pset->object));
+ return (pset->object && pset->scene && PE_get_current(pset->scene, pset->object));
}
static bool rna_ParticleEdit_hair_get(PointerRNA *ptr)
{
ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
if (pset->scene) {
- BLI_assert(BKE_id_is_in_gobal_main(&pset->scene->id));
- BLI_assert(BKE_id_is_in_gobal_main(&pset->object->id));
- PTCacheEdit *edit = PE_get_current(G_MAIN, pset->scene, pset->object);
+ PTCacheEdit *edit = PE_get_current(pset->scene, pset->object);
return (edit && edit->psys);
}
@@ -247,32 +273,89 @@ static char *rna_ParticleEdit_path(PointerRNA *UNUSED(ptr))
static bool rna_Brush_mode_poll(PointerRNA *ptr, PointerRNA value)
{
+ const Paint *paint = ptr->data;
+ Brush *brush = value.id.data;
+ const uint tool_offset = paint->runtime.tool_offset;
+ const eObjectMode ob_mode = paint->runtime.ob_mode;
+ UNUSED_VARS_NDEBUG(tool_offset);
+ BLI_assert(tool_offset && ob_mode);
+
+ if (brush->ob_mode & ob_mode) {
+ if (paint->brush) {
+ if (BKE_brush_tool_get(paint->brush, paint) == BKE_brush_tool_get(brush, paint)) {
+ return true;
+ }
+ }
+ else {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool paint_contains_brush_slot(const Paint *paint, const PaintToolSlot *tslot, int *r_index)
+{
+ if ((tslot >= paint->tool_slots) &&
+ (tslot < (paint->tool_slots + paint->tool_slots_len)))
+ {
+ *r_index = (int)(tslot - paint->tool_slots);
+ return true;
+ }
+ return false;
+}
+
+static bool rna_Brush_mode_with_tool_poll(PointerRNA *ptr, PointerRNA value)
+{
Scene *scene = (Scene *)ptr->id.data;
+ const PaintToolSlot *tslot = ptr->data;
ToolSettings *ts = scene->toolsettings;
Brush *brush = value.id.data;
int mode = 0;
+ int slot_index = 0;
- /* check the origin of the Paint struct to see which paint
- * mode to select from */
-
- if (ptr->data == &ts->imapaint)
+ if (paint_contains_brush_slot(&ts->imapaint.paint, tslot, &slot_index)) {
+ if (slot_index != brush->imagepaint_tool) {
+ return false;
+ }
mode = OB_MODE_TEXTURE_PAINT;
- else if (ptr->data == ts->sculpt)
+ }
+ else if (paint_contains_brush_slot(&ts->sculpt->paint, tslot, &slot_index)) {
+ if (slot_index != brush->sculpt_tool) {
+ return false;
+ }
mode = OB_MODE_SCULPT;
- else if (ptr->data == ts->vpaint)
+ }
+ else if (paint_contains_brush_slot(&ts->vpaint->paint, tslot, &slot_index)) {
+ if (slot_index != brush->vertexpaint_tool) {
+ return false;
+ }
mode = OB_MODE_VERTEX_PAINT;
- else if (ptr->data == ts->wpaint)
+ }
+ else if (paint_contains_brush_slot(&ts->wpaint->paint, tslot, &slot_index)) {
+ if (slot_index != brush->weightpaint_tool) {
+ return false;
+ }
mode = OB_MODE_WEIGHT_PAINT;
+ }
+ else if (paint_contains_brush_slot(&ts->gp_paint->paint, tslot, &slot_index)) {
+ if (slot_index != brush->gpencil_tool) {
+ return false;
+ }
+ mode = OB_MODE_GPENCIL_PAINT;
+ }
return brush->ob_mode & mode;
}
-static void rna_Sculpt_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_Sculpt_update(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
if (ob) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
if (ob->sculpt) {
@@ -282,11 +365,13 @@ static void rna_Sculpt_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNU
}
}
-static void rna_Sculpt_ShowDiffuseColor_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_Sculpt_ShowDiffuseColor_update(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = (scene->basact) ? scene->basact->object : NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
if (ob && ob->sculpt) {
+ Scene *scene = CTX_data_scene(C);
Sculpt *sd = scene->toolsettings->sculpt;
ob->sculpt->show_diffuse_color = ((sd->flags & SCULPT_SHOW_DIFFUSE) != 0);
@@ -297,12 +382,14 @@ static void rna_Sculpt_ShowDiffuseColor_update(Main *UNUSED(bmain), Scene *scene
}
}
-static void rna_Sculpt_ShowMask_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_Sculpt_ShowMask_update(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *object = (scene->basact) ? scene->basact->object : NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *object = OBACT(view_layer);
if (object == NULL || object->sculpt == NULL) {
return;
}
+ Scene *scene = CTX_data_scene(C);
Sculpt *sd = scene->toolsettings->sculpt;
object->sculpt->show_mask = ((sd->flags & SCULPT_HIDE_MASK) == 0);
if (object->sculpt->pbvh != NULL) {
@@ -338,6 +425,11 @@ static char *rna_UvSculpt_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("tool_settings.uv_sculpt");
}
+static char *rna_GpPaint_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_paint");
+}
+
static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.particle_edit.brush");
@@ -348,6 +440,8 @@ static void rna_Paint_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
Paint *paint = ptr->data;
Brush *br = paint->brush;
BKE_paint_invalidate_overlay_all();
+ /* Needed because we're not calling 'BKE_paint_brush_set' which handles this. */
+ BKE_paint_toolslots_brush_update(paint);
WM_main_add_notifier(NC_BRUSH | NA_SELECTED, br);
}
@@ -357,55 +451,60 @@ static void rna_ImaPaint_viewport_update(Main *UNUSED(bmain), Scene *UNUSED(scen
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
-static void rna_ImaPaint_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_ImaPaint_mode_update(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = OBACT;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
if (ob && ob->type == OB_MESH) {
/* of course we need to invalidate here */
BKE_texpaint_slots_refresh_object(scene, ob);
/* we assume that changing the current mode will invalidate the uv layers so we need to refresh display */
- GPU_drawobject_free(ob->derivedFinal);
BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
}
-static void rna_ImaPaint_stencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_ImaPaint_stencil_update(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = OBACT;
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
if (ob && ob->type == OB_MESH) {
- GPU_drawobject_free(ob->derivedFinal);
BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
}
-static void rna_ImaPaint_canvas_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_ImaPaint_canvas_update(bContext *C, PointerRNA *UNUSED(ptr))
{
- Object *ob = OBACT;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
bScreen *sc;
Image *ima = scene->toolsettings->imapaint.canvas;
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
+ SpaceLink *slink;
+ for (slink = sa->spacedata.first; slink; slink = slink->next) {
+ if (slink->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)slink;
if (!sima->pin)
- ED_space_image_set(bmain, sima, scene, scene->obedit, ima);
+ ED_space_image_set(bmain, sima, scene, obedit, ima);
}
}
}
}
if (ob && ob->type == OB_MESH) {
- GPU_drawobject_free(ob->derivedFinal);
BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
@@ -419,12 +518,17 @@ static bool rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
static PointerRNA rna_GPencilSculptSettings_brush_get(PointerRNA *ptr)
{
- GP_BrushEdit_Settings *gset = (GP_BrushEdit_Settings *)ptr->data;
- GP_EditBrush_Data *brush = NULL;
-
- if ((gset->brushtype >= 0) && (gset->brushtype < TOT_GP_EDITBRUSH_TYPES))
- brush = &gset->brush[gset->brushtype];
+ GP_Sculpt_Settings *gset = (GP_Sculpt_Settings *)ptr->data;
+ GP_Sculpt_Data *brush = NULL;
+ if ((gset) && (gset->flag & GP_SCULPT_SETT_FLAG_WEIGHT_MODE)) {
+ if ((gset->weighttype >= GP_SCULPT_TYPE_WEIGHT) && (gset->weighttype < GP_SCULPT_TYPE_MAX))
+ brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ if ((gset->brushtype >= 0) && (gset->brushtype < GP_SCULPT_TYPE_WEIGHT))
+ brush = &gset->brush[gset->brushtype];
+ }
return rna_pointer_inherit_refine(ptr, &RNA_GPencilSculptBrush, brush);
}
@@ -450,6 +554,19 @@ static void rna_def_paint_curve(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_CURVE_BEZCURVE);
}
+static void rna_def_paint_tool_slot(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "PaintToolSlot", NULL);
+ RNA_def_struct_ui_text(srna, "Paint Tool Slot", "");
+
+ prop = RNA_def_property(srna, "brush", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Brush_mode_with_tool_poll");
+ RNA_def_property_ui_text(prop, "Brush", "");
+}
static void rna_def_paint(BlenderRNA *brna)
{
@@ -466,6 +583,14 @@ static void rna_def_paint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Brush", "Active Brush");
RNA_def_property_update(prop, 0, "rna_Paint_brush_update");
+ /* paint_tool_slots */
+ prop = RNA_def_property(srna, "tool_slots", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "tool_slots", "tool_slots_len");
+ RNA_def_property_struct_type(prop, "PaintToolSlot");
+ /* don't dereference pointer! */
+ RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Paint Tool Slots", "");
+
prop = RNA_def_property(srna, "palette", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, NULL);
@@ -564,8 +689,10 @@ static void rna_def_sculpt(BlenderRNA *brna)
"Relative Detail", "Mesh detail is relative to the brush size and detail size"},
{SCULPT_DYNTOPO_DETAIL_CONSTANT, "CONSTANT", 0,
"Constant Detail", "Mesh detail is constant in object space according to detail size"},
- {SCULPT_DYNTOPO_DETAIL_BRUSH, "BRUSH", 0,
+ {SCULPT_DYNTOPO_DETAIL_BRUSH, "BRUSH", 0,
"Brush Detail", "Mesh detail is relative to brush radius"},
+ {SCULPT_DYNTOPO_DETAIL_MANUAL, "MANUAL", 0,
+ "Manual Detail", "Mesh detail does not change on each stroke, only when using Flood Fill"},
{0, NULL, 0, NULL, NULL}
};
@@ -610,17 +737,20 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Deform Only",
"Use only deformation modifiers (temporary disable all "
"constructive modifiers except multi-resolution)");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update");
prop = RNA_def_property(srna, "show_diffuse_color", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SHOW_DIFFUSE);
RNA_def_property_ui_text(prop, "Show Diffuse Color",
"Show diffuse color of object and overlay sculpt mask on top of it");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowDiffuseColor_update");
prop = RNA_def_property(srna, "show_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flags", SCULPT_HIDE_MASK);
RNA_def_property_ui_text(prop, "Show Mask", "Show mask as overlay on object");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowMask_update");
prop = RNA_def_property(srna, "detail_size", PROP_FLOAT, PROP_PIXEL);
@@ -646,6 +776,7 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Smooth Shading",
"Show faces in dynamic-topology mode with smooth "
"shading rather than flat shaded");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update");
prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE);
@@ -689,6 +820,14 @@ static void rna_def_uv_sculpt(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "UV Sculpting", "");
}
+static void rna_def_gp_paint(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "GpPaint", "Paint");
+ RNA_def_struct_path_func(srna, "rna_GpPaint_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Paint", "");
+}
/* use for weight paint too */
static void rna_def_vertex_paint(BlenderRNA *brna)
@@ -727,7 +866,7 @@ static void rna_def_image_paint(BlenderRNA *brna)
{IMAGEPAINT_MODE_MATERIAL, "MATERIAL", 0,
"Material", "Detect image slots from the material"},
{IMAGEPAINT_MODE_IMAGE, "IMAGE", 0,
- "Image", "Set image for texture painting directly"},
+ "Single Image", "Set image for texture painting directly"},
{0, NULL, 0, NULL, NULL}
};
@@ -771,12 +910,12 @@ static void rna_def_image_paint(BlenderRNA *brna)
prop = RNA_def_property(srna, "stencil_image", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "stencil");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Stencil Image", "Image used as stencil");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update");
prop = RNA_def_property(srna, "canvas", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Canvas", "Image used as canvas");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_canvas_update");
@@ -818,6 +957,7 @@ static void rna_def_image_paint(BlenderRNA *brna)
RNA_def_property_range(prop, 512, 16384);
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_enum_items(prop, paint_type_items);
RNA_def_property_ui_text(prop, "Mode", "Mode of operation for projection painting");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_mode_update");
@@ -897,6 +1037,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_enum_bitflag_sdna(prop, NULL, "selectmode");
RNA_def_property_enum_items(prop, select_mode_items);
RNA_def_property_ui_text(prop, "Selection Mode", "Particle select and display mode");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_update");
prop = RNA_def_property(srna, "use_preserve_length", PROP_BOOLEAN, PROP_NONE);
@@ -919,6 +1060,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_fade_time", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_FADE_TIME);
RNA_def_property_ui_text(prop, "Fade Time", "Fade paths and keys further away from current frame");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_update");
prop = RNA_def_property(srna, "use_auto_velocity", PROP_BOOLEAN, PROP_NONE);
@@ -926,6 +1068,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Auto Velocity", "Calculate point velocities automatically");
prop = RNA_def_property(srna, "show_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_DRAW_PART);
RNA_def_property_ui_text(prop, "Draw Particles", "Draw actual particles");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_redo");
@@ -945,17 +1088,21 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_ParticleEdit_brush_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Brush", "");
- prop = RNA_def_property(srna, "draw_step", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "display_step", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "draw_step");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_range(prop, 1, 10);
- RNA_def_property_ui_text(prop, "Steps", "How many steps to draw the path with");
+ RNA_def_property_ui_text(prop, "Steps", "How many steps to display the path with");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_redo");
prop = RNA_def_property(srna, "fade_frames", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Frames", "How many frames to fade");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_update");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_enum_sdna(prop, NULL, "edittype");
RNA_def_property_enum_items(prop, edit_type_items);
RNA_def_property_ui_text(prop, "Type", "");
@@ -976,7 +1123,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Object", "The edited object");
prop = RNA_def_property(srna, "shape_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Shape Object", "Outer shape to use for tools");
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_redo");
@@ -1033,8 +1180,8 @@ static void rna_def_particle_edit(BlenderRNA *brna)
static void rna_def_gpencil_sculpt(BlenderRNA *brna)
{
static const EnumPropertyItem prop_direction_items[] = {
- {0, "ADD", 0, "Add", "Add effect of brush"},
- {GP_EDITBRUSH_FLAG_INVERT, "SUBTRACT", 0, "Subtract", "Subtract effect of brush"},
+ {0, "ADD", ICON_ADD, "Add", "Add effect of brush"},
+ {GP_SCULPT_FLAG_INVERT, "SUBTRACT", ICON_REMOVE, "Subtract", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
StructRNA *srna;
@@ -1042,94 +1189,169 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
/* == Settings == */
srna = RNA_def_struct(brna, "GPencilSculptSettings", NULL);
- RNA_def_struct_sdna(srna, "GP_BrushEdit_Settings");
+ RNA_def_struct_sdna(srna, "GP_Sculpt_Settings");
RNA_def_struct_path_func(srna, "rna_GPencilSculptSettings_path");
RNA_def_struct_ui_text(srna, "GPencil Sculpt Settings", "Properties for Grease Pencil stroke sculpting tool");
- prop = RNA_def_property(srna, "tool", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "sculpt_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brushtype");
RNA_def_property_enum_items(prop, rna_enum_gpencil_sculpt_brush_items);
RNA_def_property_ui_text(prop, "Tool", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "weight_tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "weighttype");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_weight_brush_items);
+ RNA_def_property_ui_text(prop, "Tool", "Tool for weight painting");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
prop = RNA_def_property(srna, "brush", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilSculptBrush");
RNA_def_property_pointer_funcs(prop, "rna_GPencilSculptSettings_brush_get", NULL, NULL, NULL);
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_ui_text(prop, "Brush", "");
prop = RNA_def_property(srna, "use_select_mask", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_SELECT_MASK);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_SELECT_MASK);
RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke points");
- RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0); // FIXME: this needs a custom icon
+ RNA_def_property_ui_icon(prop, ICON_GP_ONLY_SELECTED, 0);
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_POSITION);
+ prop = RNA_def_property(srna, "use_edit_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_POSITION);
RNA_def_property_ui_text(prop, "Affect Position", "The brush affects the position of the point");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "affect_strength", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_STRENGTH);
+ prop = RNA_def_property(srna, "use_edit_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_STRENGTH);
RNA_def_property_ui_text(prop, "Affect Strength", "The brush affects the color strength of the point");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "affect_thickness", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_THICKNESS);
+ prop = RNA_def_property(srna, "use_edit_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_THICKNESS);
RNA_def_property_ui_text(prop, "Affect Thickness", "The brush affects the thickness of the point");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "use_edit_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_UV);
+ RNA_def_property_ui_text(prop, "Affect UV", "The brush affects the UV rotation of the point");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "alpha");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Alpha", "Alpha value for selected vertices");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "use_multiframe_falloff", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_FRAME_FALLOFF);
+ RNA_def_property_ui_text(prop, "Use Falloff", "Use falloff effect when edit in multiframe mode to compute brush effect by frame");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* custom falloff curve */
+ prop = RNA_def_property(srna, "multiframe_falloff_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "cur_falloff");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve",
+ "Custom curve to control falloff of brush effect by Grease Pencil frames");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
/* lock axis */
- prop = RNA_def_property(srna, "lockaxis", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "lock_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "lock_axis");
- RNA_def_property_enum_items(prop, rna_enum_gpencil_lockaxis_items);
- RNA_def_property_ui_text(prop, "Lock", "");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_lock_axis_items);
+ RNA_def_property_ui_text(prop, "Lock Axis", "");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* brush */
srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL);
- RNA_def_struct_sdna(srna, "GP_EditBrush_Data");
+ RNA_def_struct_sdna(srna, "GP_Sculpt_Data");
RNA_def_struct_path_func(srna, "rna_GPencilSculptBrush_path");
RNA_def_struct_ui_text(srna, "GPencil Sculpt Brush", "Stroke editing brush");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
- RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS);
- RNA_def_property_ui_range(prop, 1, 100, 10, 3); // XXX: too big
+ RNA_def_property_range(prop, 1, GP_MAX_BRUSH_PIXEL_RADIUS);
+ RNA_def_property_ui_range(prop, 1, 500, 10, 3);
RNA_def_property_ui_text(prop, "Radius", "Radius of the brush in pixels");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.001, 1.0);
RNA_def_property_ui_text(prop, "Strength", "Brush strength");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "target_weight", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(prop, "Weight", "Target weight");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_USE_PRESSURE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_USE_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
RNA_def_property_ui_text(prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_pressure_radius", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_PRESSURE_RADIUS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Radius Pressure", "Enable tablet pressure sensitivity for radius");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_falloff", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_USE_FALLOFF);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_USE_FALLOFF);
RNA_def_property_ui_text(prop, "Use Falloff", "Strength of brush decays with distance from cursor");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "affect_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE);
+ prop = RNA_def_property(srna, "use_edit_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_SMOOTH_PRESSURE);
RNA_def_property_ui_text(prop, "Affect Pressure", "Affect pressure values as well when smoothing strokes");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_direction_items);
RNA_def_property_ui_text(prop, "Direction", "");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* Cursor Color */
+ static float default_1[3] = { 1.0f, 0.6f, 0.6f };
+ static float default_2[3] = { 0.6f, 0.6f, 1.0f };
+
+ prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "curcolor_add");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, default_1);
+ RNA_def_property_ui_text(prop, "Cursor Add", "Color for the cursor for addition");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "cursor_color_sub", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "curcolor_sub");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, default_2);
+ RNA_def_property_ui_text(prop, "Cursor Sub", "Color for the cursor for substration");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ prop = RNA_def_property(srna, "use_cursor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_ENABLE_CURSOR);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
}
void RNA_def_sculpt_paint(BlenderRNA *brna)
@@ -1137,9 +1359,11 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
rna_def_paint_curve(brna);
+ rna_def_paint_tool_slot(brna);
rna_def_paint(brna);
rna_def_sculpt(brna);
rna_def_uv_sculpt(brna);
+ rna_def_gp_paint(brna);
rna_def_vertex_paint(brna);
rna_def_image_paint(brna);
rna_def_particle_edit(brna);
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
deleted file mode 100644
index e04e78f3ac7..00000000000
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ /dev/null
@@ -1,939 +0,0 @@
-/*
- * ***** 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): Blender Foundation (2008).
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/makesrna/intern/rna_sensor.c
- * \ingroup RNA
- */
-
-#include <stdlib.h>
-
-#include "DNA_constraint_types.h"
-#include "DNA_object_types.h"
-#include "DNA_sensor_types.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_math.h"
-#include "BLI_string_utils.h"
-
-#include "BLT_translation.h"
-
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-#include "RNA_access.h"
-
-#include "rna_internal.h"
-
-#include "WM_types.h"
-
-/* Always keep in alphabetical order */
-static const EnumPropertyItem sensor_type_items[] = {
- {SENS_ACTUATOR, "ACTUATOR", 0, "Actuator", ""},
- {SENS_ALWAYS, "ALWAYS", 0, "Always", ""},
- {SENS_ARMATURE, "ARMATURE", 0, "Armature", ""},
- {SENS_COLLISION, "COLLISION", 0, "Collision", ""},
- {SENS_DELAY, "DELAY", 0, "Delay", ""},
- {SENS_JOYSTICK, "JOYSTICK", 0, "Joystick", ""},
- {SENS_KEYBOARD, "KEYBOARD", 0, "Keyboard", ""},
- {SENS_MESSAGE, "MESSAGE", 0, "Message", ""},
- {SENS_MOUSE, "MOUSE", 0, "Mouse", ""},
- {SENS_NEAR, "NEAR", 0, "Near", ""},
- {SENS_PROPERTY, "PROPERTY", 0, "Property", ""},
- {SENS_RADAR, "RADAR", 0, "Radar", ""},
- {SENS_RANDOM, "RANDOM", 0, "Random", ""},
- {SENS_RAY, "RAY", 0, "Ray", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_sca.h"
-#include "DNA_controller_types.h"
-
-static StructRNA *rna_Sensor_refine(struct PointerRNA *ptr)
-{
- bSensor *sensor = (bSensor *)ptr->data;
-
- switch (sensor->type) {
- case SENS_ALWAYS:
- return &RNA_AlwaysSensor;
- case SENS_NEAR:
- return &RNA_NearSensor;
- case SENS_KEYBOARD:
- return &RNA_KeyboardSensor;
- case SENS_PROPERTY:
- return &RNA_PropertySensor;
- case SENS_ARMATURE:
- return &RNA_ArmatureSensor;
- case SENS_MOUSE:
- return &RNA_MouseSensor;
- case SENS_COLLISION:
- return &RNA_CollisionSensor;
- case SENS_RADAR:
- return &RNA_RadarSensor;
- case SENS_RANDOM:
- return &RNA_RandomSensor;
- case SENS_RAY:
- return &RNA_RaySensor;
- case SENS_MESSAGE:
- return &RNA_MessageSensor;
- case SENS_JOYSTICK:
- return &RNA_JoystickSensor;
- case SENS_ACTUATOR:
- return &RNA_ActuatorSensor;
- case SENS_DELAY:
- return &RNA_DelaySensor;
- default:
- return &RNA_Sensor;
- }
-}
-
-static void rna_Sensor_name_set(PointerRNA *ptr, const char *value)
-{
- Object *ob = ptr->id.data;
- bSensor *sens = ptr->data;
- BLI_strncpy_utf8(sens->name, value, sizeof(sens->name));
- BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
-}
-
-static void rna_Sensor_type_set(struct PointerRNA *ptr, int value)
-{
- bSensor *sens = (bSensor *)ptr->data;
- if (value != sens->type) {
- sens->type = value;
- init_sensor(sens);
- }
-}
-
-/* Always keep in alphabetical order */
-
-static void rna_Sensor_controllers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- bSensor *sens = (bSensor *)ptr->data;
- rna_iterator_array_begin(iter, sens->links, sizeof(bController *), (int)sens->totlinks, 0, NULL);
-}
-
-static int rna_Sensor_controllers_length(PointerRNA *ptr)
-{
- bSensor *sens = (bSensor *)ptr->data;
- return (int) sens->totlinks;
-}
-
-const EnumPropertyItem *rna_Sensor_type_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem *item = NULL;
- Object *ob = NULL;
- int totitem = 0;
-
- if (ptr->type == &RNA_Sensor || RNA_struct_is_a(ptr->type, &RNA_Sensor)) {
- ob = (Object *)ptr->id.data;
- }
- else {
- /* can't use ob from ptr->id.data because that enum is also used by operators */
- ob = CTX_data_active_object(C);
- }
-
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_ACTUATOR);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_ALWAYS);
-
- if (ob != NULL) {
- if (ob->type == OB_ARMATURE) {
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_ARMATURE);
- }
- }
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_COLLISION);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_DELAY);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_JOYSTICK);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_KEYBOARD);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_MESSAGE);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_MOUSE);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_NEAR);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_PROPERTY);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_RADAR);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_RANDOM);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_RAY);
- RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_TOUCH);
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-static void rna_Sensor_keyboard_key_set(struct PointerRNA *ptr, int value)
-{
- bSensor *sens = (bSensor *)ptr->data;
- bKeyboardSensor *ks = (bKeyboardSensor *)sens->data;
-
- if (ISKEYBOARD(value))
- ks->key = value;
- else
- ks->key = 0;
-}
-
-static void rna_Sensor_keyboard_modifier_set(struct PointerRNA *ptr, int value)
-{
- bSensor *sens = (bSensor *)ptr->data;
- bKeyboardSensor *ks = (bKeyboardSensor *)sens->data;
-
- if (ISKEYBOARD(value))
- ks->qual = value;
- else
- ks->qual = 0;
-}
-
-static void rna_Sensor_keyboard_modifier2_set(struct PointerRNA *ptr, int value)
-{
- bSensor *sens = (bSensor *)ptr->data;
- bKeyboardSensor *ks = (bKeyboardSensor *)sens->data;
-
- if (ISKEYBOARD(value))
- ks->qual2 = value;
- else
- ks->qual2 = 0;
-}
-
-static void rna_Sensor_tap_set(struct PointerRNA *ptr, bool value)
-{
- bSensor *sens = (bSensor *)ptr->data;
-
- sens->tap = value;
- if (sens->tap == 1)
- sens->level = 0;
-}
-
-static void rna_Sensor_level_set(struct PointerRNA *ptr, bool value)
-{
- bSensor *sens = (bSensor *)ptr->data;
-
- sens->level = value;
- if (sens->level == 1)
- sens->tap = 0;
-}
-
-static void rna_Sensor_Armature_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- bSensor *sens = (bSensor *)ptr->data;
- bArmatureSensor *as = sens->data;
- Object *ob = (Object *)ptr->id.data;
-
- char *posechannel = as->posechannel;
- char *constraint = as->constraint;
-
- /* check that bone exist in the active object */
- if (ob->type == OB_ARMATURE && ob->pose) {
- bPoseChannel *pchan;
- bPose *pose = ob->pose;
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (STREQ(pchan->name, posechannel)) {
- /* found it, now look for constraint channel */
- bConstraint *con;
- for (con = pchan->constraints.first; con; con = con->next) {
- if (STREQ(con->name, constraint)) {
- /* found it, all ok */
- return;
- }
- }
- /* didn't find constraint, make empty */
- constraint[0] = 0;
- return;
- }
- }
- }
- /* didn't find any */
- posechannel[0] = 0;
- constraint[0] = 0;
-}
-#else
-
-static void rna_def_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "Sensor", NULL);
- RNA_def_struct_ui_text(srna, "Sensor", "Game engine logic brick to detect events");
- RNA_def_struct_sdna(srna, "bSensor");
- RNA_def_struct_refine_func(srna, "rna_Sensor_refine");
-
- prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Name", "Sensor name");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Sensor_name_set");
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_enum_items(prop, sensor_type_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_type_set", "rna_Sensor_type_itemf");
- RNA_def_property_ui_text(prop, "Type", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "pin", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_PIN);
- RNA_def_property_ui_text(prop, "Pinned", "Display when not linked to a visible states controller");
- RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SENS_DEACTIVATE);
- RNA_def_property_ui_text(prop, "Active", "Set active state of the sensor");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_SHOW);
- RNA_def_property_ui_text(prop, "Expanded", "Set sensor expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_ui_text(prop, "Invert Output", "Invert the level(output) of this sensor");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_level", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "level", 1);
- RNA_def_property_ui_text(prop, "Level",
- "Level detector, trigger controllers of new states "
- "(only applicable upon logic state transition)");
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Sensor_level_set");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_pulse_true_level", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pulse", SENS_PULSE_REPEAT);
- RNA_def_property_ui_text(prop, "Pulse True Level", "Activate TRUE level triggering (pulse mode)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_pulse_false_level", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "pulse", SENS_NEG_PULSE_MODE);
- RNA_def_property_ui_text(prop, "Pulse False Level", "Activate FALSE level triggering (pulse mode)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "tick_skip", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "freq");
- RNA_def_property_ui_text(prop, "Skip",
- "Number of logic ticks skipped between 2 active pulses "
- "(0 = pulse every logic tick, 1 = skip 1 logic tick between pulses, etc.)");
- RNA_def_property_range(prop, 0, 10000);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_tap", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "tap", 1);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Sensor_tap_set");
- RNA_def_property_ui_text(prop, "Tap",
- "Trigger controllers only for an instant, even while the sensor remains true");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "controllers", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "links", NULL);
- RNA_def_property_struct_type(prop, "Controller");
- RNA_def_property_ui_text(prop, "Controllers", "The list containing the controllers connected to the sensor");
- RNA_def_property_collection_funcs(prop, "rna_Sensor_controllers_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_dereference_get",
- "rna_Sensor_controllers_length", NULL, NULL, NULL);
-
-
- RNA_api_sensor(srna);
-}
-
-static void rna_def_always_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- srna = RNA_def_struct(brna, "AlwaysSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Always Sensor", "Sensor to generate continuous pulses");
-}
-
-static void rna_def_near_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "NearSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Near Sensor", "Sensor to detect nearby objects");
- RNA_def_struct_sdna_from(srna, "bNearSensor", "data");
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dist");
- RNA_def_property_ui_text(prop, "Distance", "Trigger distance");
- RNA_def_property_range(prop, 0.0f, 10000.0f);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "reset_distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "resetdist");
- RNA_def_property_ui_text(prop, "Reset Distance", "The distance where the sensor forgets the actor");
- RNA_def_property_range(prop, 0.0f, 10000.0f);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_mouse_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem mouse_event_items[] = {
- {BL_SENS_MOUSE_LEFT_BUTTON, "LEFTCLICK", 0, "Left Button", ""},
- {BL_SENS_MOUSE_MIDDLE_BUTTON, "MIDDLECLICK", 0, "Middle Button", ""},
- {BL_SENS_MOUSE_RIGHT_BUTTON, "RIGHTCLICK", 0, "Right Button", ""},
- {BL_SENS_MOUSE_WHEEL_UP, "WHEELUP", 0, "Wheel Up", ""},
- {BL_SENS_MOUSE_WHEEL_DOWN, "WHEELDOWN", 0, "Wheel Down", ""},
- {BL_SENS_MOUSE_MOVEMENT, "MOVEMENT", 0, "Movement", ""},
- {BL_SENS_MOUSE_MOUSEOVER, "MOUSEOVER", 0, "Mouse Over", ""},
- {BL_SENS_MOUSE_MOUSEOVER_ANY, "MOUSEOVERANY", 0, "Mouse Over Any", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_mouse_type_items[] = {
- {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a property for ray intersections"},
- {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a material for ray intersections"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "MouseSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Mouse Sensor", "Sensor to detect mouse events");
- RNA_def_struct_sdna_from(srna, "bMouseSensor", "data");
-
- prop = RNA_def_property(srna, "mouse_event", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, mouse_event_items);
- RNA_def_property_ui_text(prop, "Mouse Event", "Type of event this mouse sensor should trigger on");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_pulse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_MOUSE_FOCUS_PULSE);
- RNA_def_property_ui_text(prop, "Pulse", "Moving the mouse over a different object generates a pulse");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_material", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, prop_mouse_type_items);
- RNA_def_property_ui_text(prop, "M/P", "Toggle collision on material or property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "propname");
- RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "matname");
- RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_x_ray", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_RAY_XRAY);
- RNA_def_property_ui_text(prop, "X-Ray", "Toggle X-Ray option (see through objects that don't have the property)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_keyboard_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "KeyboardSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Keyboard Sensor", "Sensor to detect keyboard events");
- RNA_def_struct_sdna_from(srna, "bKeyboardSensor", "data");
-
- prop = RNA_def_property(srna, "key", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "key");
- RNA_def_property_enum_items(prop, rna_enum_event_type_items);
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_key_set", NULL);
- RNA_def_property_ui_text(prop, "Key", "");
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WINDOWMANAGER);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "modifier_key_1", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "qual");
- RNA_def_property_enum_items(prop, rna_enum_event_type_items);
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_modifier_set", NULL);
- RNA_def_property_ui_text(prop, "Modifier Key", "Modifier key code");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "modifier_key_2", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "qual2");
- RNA_def_property_enum_items(prop, rna_enum_event_type_items);
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_modifier2_set", NULL);
- RNA_def_property_ui_text(prop, "Second Modifier Key", "Modifier key code");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "target", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "targetName");
- RNA_def_property_ui_text(prop, "Target", "Property that receives the keystrokes in case a string is logged");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "log", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "toggleName");
- RNA_def_property_ui_text(prop, "Log Toggle", "Property that indicates whether to log keystrokes as a string");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_all_keys", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "type", 1);
- RNA_def_property_ui_text(prop, "All Keys", "Trigger this sensor on any keystroke");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_property_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
- static const EnumPropertyItem prop_type_items[] = {
- {SENS_PROP_EQUAL, "PROPEQUAL", 0, "Equal", ""},
- {SENS_PROP_NEQUAL, "PROPNEQUAL", 0, "Not Equal", ""},
- {SENS_PROP_INTERVAL, "PROPINTERVAL", 0, "Interval", ""},
- {SENS_PROP_CHANGED, "PROPCHANGED", 0, "Changed", ""},
- /* {SENS_PROP_EXPRESSION, "PROPEXPRESSION", 0, "Expression", ""}, NOT_USED_IN_UI */
- {SENS_PROP_LESSTHAN, "PROPLESSTHAN", 0, "Less Than", ""},
- {SENS_PROP_GREATERTHAN, "PROPGREATERTHAN", 0, "Greater Than", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "PropertySensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Property Sensor", "Sensor to detect values and changes in values of properties");
- RNA_def_struct_sdna_from(srna, "bPropertySensor", "data");
-
- prop = RNA_def_property(srna, "evaluation_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Evaluation Type", "Type of property evaluation");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Property", "");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "value", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Value", "Check for this value in types in Equal, Not Equal, Less Than and Greater Than types");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "value_min", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Minimum Value", "Minimum value in Interval type");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "value_max", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "maxvalue");
- RNA_def_property_ui_text(prop, "Maximum Value", "Maximum value in Interval type");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_armature_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
- static const EnumPropertyItem prop_type_items[] = {
- {SENS_ARM_STATE_CHANGED, "STATECHG", 0, "State Changed", ""},
- {SENS_ARM_LIN_ERROR_BELOW, "LINERRORBELOW", 0, "Lin error below", ""},
- {SENS_ARM_LIN_ERROR_ABOVE, "LINERRORABOVE", 0, "Lin error above", ""},
- {SENS_ARM_ROT_ERROR_BELOW, "ROTERRORBELOW", 0, "Rot error below", ""},
- {SENS_ARM_ROT_ERROR_ABOVE, "ROTERRORABOVE", 0, "Rot error above", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "ArmatureSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Armature Sensor", "Sensor to detect values and changes in values of IK solver");
- RNA_def_struct_sdna_from(srna, "bArmatureSensor", "data");
-
- prop = RNA_def_property(srna, "test_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Test", "Type of value and test");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "bone", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "posechannel");
- RNA_def_property_ui_text(prop, "Bone Name", "Identify the bone to check value from");
- RNA_def_property_update(prop, NC_LOGIC, "rna_Sensor_Armature_update");
-
- prop = RNA_def_property(srna, "constraint", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "constraint");
- RNA_def_property_ui_text(prop, "Constraint Name", "Identify the bone constraint to check value from");
- RNA_def_property_update(prop, NC_LOGIC, "rna_Sensor_Armature_update");
-
- prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Compare Value", "Value to be used in comparison");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_actuator_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ActuatorSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Actuator Sensor", "Sensor to detect state modifications of actuators");
- RNA_def_struct_sdna_from(srna, "bActuatorSensor", "data");
-
- /* XXX if eventually have Logics using RNA 100%, we could use the actuator data-block isntead of its name */
- prop = RNA_def_property(srna, "actuator", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Actuator", "Actuator name, actuator active state modifications will be detected");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_delay_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "DelaySensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Delay Sensor", "Sensor to send delayed events");
- RNA_def_struct_sdna_from(srna, "bDelaySensor", "data");
-
- prop = RNA_def_property(srna, "delay", PROP_INT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Delay",
- "Delay in number of logic tics before the positive trigger (default 60 per second)");
- RNA_def_property_range(prop, 0, 5000);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "duration", PROP_INT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Duration",
- "If >0, delay in number of logic tics before the negative trigger following "
- "the positive trigger");
- RNA_def_property_range(prop, 0, 5000);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_repeat", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_DELAY_REPEAT);
- RNA_def_property_ui_text(prop, "Repeat",
- "Toggle repeat option (if selected, the sensor restarts after Delay+Duration "
- "logic tics)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_collision_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "CollisionSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Collision Sensor",
- "Sensor to detect objects colliding with the current object, with more settings than "
- "the Touch sensor");
- RNA_def_struct_sdna_from(srna, "bCollisionSensor", "data");
-
- prop = RNA_def_property(srna, "use_pulse", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", SENS_COLLISION_PULSE);
- RNA_def_property_ui_text(prop, "Pulse", "Change to the set of colliding objects generates pulse");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_material", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", SENS_COLLISION_MATERIAL);
- RNA_def_property_ui_text(prop, "M/P", "Toggle collision on material or property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /*XXX to make a setFunction to create a lookup with all materials in Blend File (not only this object mat.) */
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialName");
- RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
-#if 0
- /* XXX either use a data-block look up to store the string name (material)
- * or to do a doversion and use a material pointer. */
- prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Material");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_pointer_sdna(prop, NULL, "ma");
- RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
-#endif
-}
-
-static void rna_def_radar_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
- static const EnumPropertyItem axis_items[] = {
- {SENS_RADAR_X_AXIS, "XAXIS", 0, "+X axis", ""},
- {SENS_RADAR_Y_AXIS, "YAXIS", 0, "+Y axis", ""},
- {SENS_RADAR_Z_AXIS, "ZAXIS", 0, "+Z axis", ""},
- {SENS_RADAR_NEG_X_AXIS, "NEGXAXIS", 0, "-X axis", ""},
- {SENS_RADAR_NEG_Y_AXIS, "NEGYAXIS", 0, "-Y axis", ""},
- {SENS_RADAR_NEG_Z_AXIS, "NEGZAXIS", 0, "-Z axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "RadarSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Radar Sensor",
- "Sensor to detect objects in a cone shaped radar emanating from the current object");
- RNA_def_struct_sdna_from(srna, "bRadarSensor", "data");
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, axis_items);
- RNA_def_property_ui_text(prop, "Axis", "Along which axis the radar cone is cast");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_range(prop, 0.0, DEG2RADF(179.9f));
- RNA_def_property_ui_text(prop, "Angle", "Opening angle of the radar cone");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "range");
- RNA_def_property_range(prop, 0.0, 10000.0);
- RNA_def_property_ui_text(prop, "Distance", "Depth of the radar cone");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_random_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "RandomSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Random Sensor", "Sensor to send random events");
- RNA_def_struct_sdna_from(srna, "bRandomSensor", "data");
-
- prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 1000);
- RNA_def_property_ui_text(prop, "Seed", "Initial seed of the generator (choose 0 for not random)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_ray_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
- static const EnumPropertyItem axis_items[] = {
- {SENS_RAY_X_AXIS, "XAXIS", 0, "+X axis", ""},
- {SENS_RAY_Y_AXIS, "YAXIS", 0, "+Y axis", ""},
- {SENS_RAY_Z_AXIS, "ZAXIS", 0, "+Z axis", ""},
- {SENS_RAY_NEG_X_AXIS, "NEGXAXIS", 0, "-X axis", ""},
- {SENS_RAY_NEG_Y_AXIS, "NEGYAXIS", 0, "-Y axis", ""},
- {SENS_RAY_NEG_Z_AXIS, "NEGZAXIS", 0, "-Z axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_ray_type_items[] = {
- {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a property for ray intersections"},
- {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a material for ray intersections"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "RaySensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Ray Sensor",
- "Sensor to detect intersections with a ray emanating from the current object");
- RNA_def_struct_sdna_from(srna, "bRaySensor", "data");
-
- prop = RNA_def_property(srna, "ray_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, prop_ray_type_items);
- RNA_def_property_ui_text(prop, "Ray Type", "Toggle collision on material or property");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "propname");
- RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "matname");
- RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
-#if 0
- /* XXX either use a data-block look up to store the string name (material)
- * or to do a doversion and use a material pointer. */
- prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "Material");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_pointer_sdna(prop, NULL, "ma");
- RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
-#endif
-
- prop = RNA_def_property(srna, "use_x_ray", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", SENS_RAY_XRAY);
- RNA_def_property_ui_text(prop, "X-Ray Mode",
- "Toggle X-Ray option (see through objects that don't have the property)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "range", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.01, 10000.0);
- RNA_def_property_ui_text(prop, "Range", "Sense objects no farther than this distance");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "axisflag");
- RNA_def_property_enum_items(prop, axis_items);
- RNA_def_property_ui_text(prop, "Axis", "Along which axis the ray is cast");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_message_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "MessageSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Message Sensor", "Sensor to detect incoming messages");
- RNA_def_struct_sdna_from(srna, "bMessageSensor", "data");
-
- prop = RNA_def_property(srna, "subject", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Subject",
- "Optional subject filter: only accept messages with this subject, "
- "or empty to accept all");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-static void rna_def_joystick_sensor(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem event_type_joystick_items[] = {
- {SENS_JOY_BUTTON, "BUTTON", 0, "Button", ""},
- {SENS_JOY_AXIS, "AXIS", 0, "Axis", ""},
- {SENS_JOY_HAT, "HAT", 0, "Hat", ""},
- {SENS_JOY_AXIS_SINGLE, "AXIS_SINGLE", 0, "Single Axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem axis_direction_items[] = {
- {SENS_JOY_X_AXIS, "RIGHTAXIS", 0, "Right Axis", ""},
- {SENS_JOY_Y_AXIS, "UPAXIS", 0, "Up Axis", ""},
- {SENS_JOY_NEG_X_AXIS, "LEFTAXIS", 0, "Left Axis", ""},
- {SENS_JOY_NEG_Y_AXIS, "DOWNAXIS", 0, "Down Axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem hat_direction_items[] = {
- {SENS_JOY_HAT_UP, "UP", 0, "Up", ""},
- {SENS_JOY_HAT_DOWN, "DOWN", 0, "Down", ""},
- {SENS_JOY_HAT_LEFT, "LEFT", 0, "Left", ""},
- {SENS_JOY_HAT_RIGHT, "RIGHT", 0, "Right", ""},
-
- {SENS_JOY_HAT_UP_RIGHT, "UPRIGHT", 0, "Up/Right", ""},
- {SENS_JOY_HAT_DOWN_LEFT, "DOWNLEFT", 0, "Down/Left", ""},
- {SENS_JOY_HAT_UP_LEFT, "UPLEFT", 0, "Up/Left", ""},
- {SENS_JOY_HAT_DOWN_RIGHT, "DOWNRIGHT", 0, "Down/Right", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "JoystickSensor", "Sensor");
- RNA_def_struct_ui_text(srna, "Joystick Sensor", "Sensor to detect joystick events");
- RNA_def_struct_sdna_from(srna, "bJoystickSensor", "data");
-
- prop = RNA_def_property(srna, "joystick_index", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "joyindex");
- RNA_def_property_ui_text(prop, "Index", "Which joystick to use");
- RNA_def_property_range(prop, 0, SENS_JOY_MAXINDEX - 1);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "event_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, event_type_joystick_items);
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
- RNA_def_property_ui_text(prop, "Event Type", "The type of event this joystick sensor is triggered on");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "use_all_events", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_JOY_ANY_EVENT);
- RNA_def_property_ui_text(prop, "All Events",
- "Triggered by all events on this joystick's current type (axis/button/hat)");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Button */
- prop = RNA_def_property(srna, "button_number", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "button");
- RNA_def_property_ui_text(prop, "Button Number", "Which button to use");
- RNA_def_property_range(prop, 0, 18);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Axis */
- prop = RNA_def_property(srna, "axis_number", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "axis");
- RNA_def_property_ui_text(prop, "Axis Number", "Which axis pair to use, 1 is usually the main direction input");
- RNA_def_property_range(prop, 1, 8);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "axis_threshold", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "precision");
- RNA_def_property_ui_text(prop, "Axis Threshold", "Precision of the axis");
- RNA_def_property_range(prop, 0, 32768);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "axis_direction", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "axisf");
- RNA_def_property_enum_items(prop, axis_direction_items);
- RNA_def_property_ui_text(prop, "Axis Direction", "The direction of the axis");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Single Axis */
- prop = RNA_def_property(srna, "single_axis_number", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "axis_single");
- RNA_def_property_ui_text(prop, "Axis Number", "Single axis (vertical/horizontal/other) to detect");
- RNA_def_property_range(prop, 1, 16);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* Hat */
- prop = RNA_def_property(srna, "hat_number", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "hat");
- RNA_def_property_ui_text(prop, "Hat Number", "Which hat to use");
- RNA_def_property_range(prop, 1, 2);
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "hat_direction", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "hatf");
- RNA_def_property_enum_items(prop, hat_direction_items);
- RNA_def_property_ui_text(prop, "Hat Direction", "Hat direction");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-}
-
-void RNA_def_sensor(BlenderRNA *brna)
-{
- rna_def_sensor(brna);
-
- rna_def_always_sensor(brna);
- rna_def_near_sensor(brna);
- rna_def_mouse_sensor(brna);
- rna_def_keyboard_sensor(brna);
- rna_def_property_sensor(brna);
- rna_def_armature_sensor(brna);
- rna_def_actuator_sensor(brna);
- rna_def_delay_sensor(brna);
- rna_def_collision_sensor(brna);
- rna_def_radar_sensor(brna);
- rna_def_random_sensor(brna);
- rna_def_ray_sensor(brna);
- rna_def_message_sensor(brna);
- rna_def_joystick_sensor(brna);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_sensor_api.c b/source/blender/makesrna/intern/rna_sensor_api.c
deleted file mode 100644
index 9db5c3f9f92..00000000000
--- a/source/blender/makesrna/intern/rna_sensor_api.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * ***** 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) 2010 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s):
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/makesrna/intern/rna_sensor_api.c
- * \ingroup RNA
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "BLI_utildefines.h"
-
-#include "RNA_define.h"
-
-#include "rna_internal.h" /* own include */
-
-#include "WM_types.h"
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_sca.h"
-#include "DNA_sensor_types.h"
-#include "DNA_controller_types.h"
-
-static void rna_Sensor_link(bSensor *sens, bController *cont)
-{
- link_logicbricks((void **)&cont, (void ***)&(sens->links), &sens->totlinks, sizeof(bController *));
-}
-
-static void rna_Sensor_unlink(bSensor *sens, bController *cont)
-{
- unlink_logicbricks((void **)&cont, (void ***)&(sens->links), &sens->totlinks);
-}
-
-#else
-
-void RNA_api_sensor(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *parm;
-
- func = RNA_def_function(srna, "link", "rna_Sensor_link");
- RNA_def_function_ui_description(func, "Link the sensor to a controller");
- parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to link to");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_property_update(parm, NC_LOGIC, NULL);
-
- func = RNA_def_function(srna, "unlink", "rna_Sensor_unlink");
- RNA_def_function_ui_description(func, "Unlink the sensor from a controller");
- parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to unlink from");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_property_update(parm, NC_LOGIC, NULL);
-}
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 5057d62774d..433ca729c65 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -1363,31 +1363,37 @@ static void rna_def_strip_color_balance(BlenderRNA *brna)
static const EnumPropertyItem blend_mode_items[] = {
{SEQ_BLEND_REPLACE, "REPLACE", 0, "Replace", ""},
{SEQ_TYPE_CROSS, "CROSS", 0, "Cross", ""},
- {SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
- {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
- {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", ""},
- {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", ""},
- {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""},
{SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
- {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Over Drop", ""},
+ {SEQ_TYPE_BURN, "BURN", 0, "Burn", ""},
+ {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
- {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""},
{SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
- {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""},
- {SEQ_TYPE_BURN, "BURN", 0, "Burn", ""},
- {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
+ {SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
{SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""},
- {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
- {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
{SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""},
- {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
+ {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
+ {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
+ {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
+ {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{SEQ_TYPE_HUE, "HUE", 0, "Hue", ""},
{SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""},
+ {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
{SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""},
- {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
- {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", ""},
+ {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", ""},
+ {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""},
+ {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Over Drop", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1504,12 +1510,13 @@ static void rna_def_sequence(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_MUTE);
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, true);
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_ui_text(prop, "Mute", "Disable strip so that it cannot be viewed in the output");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_mute_update");
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_LOCK);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true);
RNA_def_property_ui_text(prop, "Lock", "Lock strip so that it cannot be transformed");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
@@ -1589,6 +1596,7 @@ static void rna_def_sequence(BlenderRNA *brna)
prop = RNA_def_property(srna, "channel", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "machine");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 1, MAXSEQ);
RNA_def_property_ui_text(prop, "Channel", "Y position of the sequence strip");
RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_channel_set", NULL); /* overlap test */
@@ -2580,7 +2588,7 @@ static void rna_def_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQUENCE_MODIFIER_MUTE);
RNA_def_property_ui_text(prop, "Mute", "Mute this modifier");
- RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 509b6da2048..4c56f4c7ccd 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -48,9 +48,8 @@
#include "BLI_path_util.h" /* BLI_split_dirfile */
#include "BKE_image.h"
-#include "BKE_library.h" /* id_us_plus */
-#include "BKE_movieclip.h"
#include "BKE_mask.h"
+#include "BKE_movieclip.h"
#include "BKE_report.h"
#include "BKE_sequencer.h"
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
new file mode 100644
index 00000000000..ef045be82ca
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -0,0 +1,707 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_shader_fx.c
+ * \ingroup RNA
+ */
+
+
+#include <float.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "DNA_shader_fx_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+const EnumPropertyItem rna_enum_object_shaderfx_type_items[] = {
+ {eShaderFxType_Blur, "FX_BLUR", ICON_SHADERFX, "Blur", "Apply Gaussian Blur to object" },
+ {eShaderFxType_Colorize, "FX_COLORIZE", ICON_SHADERFX, "Colorize", "Apply different tint effects" },
+ {eShaderFxType_Flip, "FX_FLIP", ICON_SHADERFX, "Flip", "Flip image" },
+ {eShaderFxType_Glow, "FX_GLOW", ICON_SHADERFX, "Glow", "Create a glow effect" },
+ {eShaderFxType_Light, "FX_LIGHT", ICON_SHADERFX, "Light", "Simulate ilumination" },
+ {eShaderFxType_Pixel, "FX_PIXEL", ICON_SHADERFX, "Pixelate", "Pixelate image"},
+ {eShaderFxType_Rim, "FX_RIM", ICON_SHADERFX, "Rim", "Add a rim to the image" },
+ {eShaderFxType_Shadow, "FX_SHADOW", ICON_SHADERFX, "Shadow", "Create a shadow effect"},
+ {eShaderFxType_Swirl, "FX_SWIRL", ICON_SHADERFX, "Swirl", "Create a rotation distortion"},
+ {eShaderFxType_Wave, "FX_WAVE", ICON_SHADERFX, "Wave Distortion", "Apply sinusoidal deformation"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem rna_enum_shaderfx_rim_modes_items[] = {
+ {eShaderFxRimMode_Normal, "NORMAL", 0, "Normal", "" },
+ {eShaderFxRimMode_Overlay, "OVERLAY", 0, "Overlay", "" },
+ {eShaderFxRimMode_Add, "ADD", 0, "Add", "" },
+ {eShaderFxRimMode_Subtract, "SUBTRACT", 0, "Subtract", "" },
+ {eShaderFxRimMode_Multiply, "MULTIPLY", 0, "Multiply", "" },
+ {eShaderFxRimMode_Divide, "DIVIDE", 0, "Divide", "" },
+ {0, NULL, 0, NULL, NULL }
+};
+
+static const EnumPropertyItem rna_enum_shaderfx_glow_modes_items[] = {
+ {eShaderFxGlowMode_Luminance, "LUMINANCE", 0, "Luminance", "" },
+ {eShaderFxGlowMode_Color, "COLOR", 0, "Color", "" },
+ {0, NULL, 0, NULL, NULL }
+};
+
+static const EnumPropertyItem rna_enum_shaderfx_colorize_modes_items[] = {
+ {eShaderFxColorizeMode_GrayScale, "GRAYSCALE", 0, "Gray Scale", "" },
+ {eShaderFxColorizeMode_Sepia, "SEPIA", 0, "Sepia", "" },
+ {eShaderFxColorizeMode_BiTone, "BITONE", 0, "Bi-Tone", "" },
+ {eShaderFxColorizeMode_Transparent, "TRANSPARENT", 0, "Transparent", "" },
+ {eShaderFxColorizeMode_Custom, "CUSTOM", 0, "Custom", "" },
+ {0, NULL, 0, NULL, NULL }
+};
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_shader_fx.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static StructRNA *rna_ShaderFx_refine(struct PointerRNA *ptr)
+{
+ ShaderFxData *md = (ShaderFxData *)ptr->data;
+
+ switch ((ShaderFxType)md->type) {
+ case eShaderFxType_Blur:
+ return &RNA_ShaderFxBlur;
+ case eShaderFxType_Colorize:
+ return &RNA_ShaderFxColorize;
+ case eShaderFxType_Wave:
+ return &RNA_ShaderFxWave;
+ case eShaderFxType_Pixel:
+ return &RNA_ShaderFxPixel;
+ case eShaderFxType_Rim:
+ return &RNA_ShaderFxRim;
+ case eShaderFxType_Shadow:
+ return &RNA_ShaderFxShadow;
+ case eShaderFxType_Swirl:
+ return &RNA_ShaderFxSwirl;
+ case eShaderFxType_Flip:
+ return &RNA_ShaderFxFlip;
+ case eShaderFxType_Glow:
+ return &RNA_ShaderFxGlow;
+ case eShaderFxType_Light:
+ return &RNA_ShaderFxLight;
+ /* Default */
+ case eShaderFxType_None:
+ case NUM_SHADER_FX_TYPES:
+ return &RNA_ShaderFx;
+ }
+
+ return &RNA_ShaderFx;
+}
+
+static void rna_ShaderFx_name_set(PointerRNA *ptr, const char *value)
+{
+ ShaderFxData *gmd = ptr->data;
+ char oldname[sizeof(gmd->name)];
+
+ /* make a copy of the old name first */
+ BLI_strncpy(oldname, gmd->name, sizeof(gmd->name));
+
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(gmd->name, value, sizeof(gmd->name));
+
+ /* make sure the name is truly unique */
+ if (ptr->id.data) {
+ Object *ob = ptr->id.data;
+ BKE_shaderfx_unique_name(&ob->shader_fx, gmd);
+ }
+
+ /* fix all the animation data which may link to this */
+ BKE_animdata_fix_paths_rename_all(NULL, "shader_effects", oldname, gmd->name);
+}
+
+static char *rna_ShaderFx_path(PointerRNA *ptr)
+{
+ ShaderFxData *gmd = ptr->data;
+ char name_esc[sizeof(gmd->name) * 2];
+
+ BLI_strescape(name_esc, gmd->name, sizeof(name_esc));
+ return BLI_sprintfN("shader_effects[\"%s\"]", name_esc);
+}
+
+static void rna_ShaderFx_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->id.data);
+}
+
+static void rna_ShaderFx_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ rna_ShaderFx_update(bmain, scene, ptr);
+ DEG_relations_tag_update(bmain);
+}
+
+/* Objects */
+
+static void shaderfx_object_set(Object *self, Object **ob_p, int type, PointerRNA value)
+{
+ Object *ob = value.data;
+
+ if (!self || ob != self) {
+ if (!ob || type == OB_EMPTY || ob->type == type) {
+ id_lib_extern((ID *)ob);
+ *ob_p = ob;
+ }
+ }
+}
+
+#define RNA_FX_OBJECT_SET(_type, _prop, _obtype) \
+static void rna_##_type##ShaderFx_##_prop##_set(PointerRNA *ptr, PointerRNA value) \
+{ \
+ _type##ShaderFxData *tmd = (_type##ShaderFxData *)ptr->data; \
+ shaderfx_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \
+}
+
+RNA_FX_OBJECT_SET(Light, object, OB_EMPTY);
+RNA_FX_OBJECT_SET(Shadow, object, OB_EMPTY);
+RNA_FX_OBJECT_SET(Swirl, object, OB_EMPTY);
+
+#undef RNA_FX_OBJECT_SET
+
+#else
+
+static void rna_def_shader_fx_blur(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxBlur", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Gaussian Blur Effect", "Gaussian Blur effect");
+ RNA_def_struct_sdna(srna, "BlurShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "factor", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "radius");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Factor", "Factor of Blur");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "samples");
+ RNA_def_property_range(prop, 0, 32);
+ RNA_def_property_ui_range(prop, 0, 32, 2, -1);
+ RNA_def_property_int_default(prop, 4);
+ RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "coc", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "coc");
+ RNA_def_property_range(prop, 0.001f, 1.0f);
+ RNA_def_property_float_default(prop, 0.025f);
+ RNA_def_property_ui_text(prop, "Precision", "Define circle of confusion for depth of field");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "use_dof_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_BLUR_DOF_MODE);
+ RNA_def_property_ui_text(prop, "Lock Focal Plane", "Blur using focal plane distance as factor to simulate depth of field effect (only in camera view)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_colorize(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxColorize", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Colorize Effect", "Colorize effect");
+ RNA_def_struct_sdna(srna, "ColorizeShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_range(prop, 0, 1.0);
+ RNA_def_property_ui_text(prop, "Factor", "Mix factor");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "low_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "low_color");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Low color", "First color used for effect");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "high_color");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Height color", "Second color used for effect");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, rna_enum_shaderfx_colorize_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Effect mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_wave(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_shaderfx_wave_type_items[] = {
+ { 0, "HORIZONTAL", 0, "Horizontal", "" },
+ { 1, "VERTICAL", 0, "Vertical", "" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ srna = RNA_def_struct(brna, "ShaderFxWave", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Wave Deformation Effect", "Wave Deformation effect");
+ RNA_def_struct_sdna(srna, "WaveShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "orientation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "orientation");
+ RNA_def_property_enum_items(prop, prop_shaderfx_wave_type_items);
+ RNA_def_property_ui_text(prop, "Orientation", "Direction of the wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "period");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Period", "Period of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "phase");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Phase", "Phase Shift of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_pixel(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxPixel", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Pixelate Effect", "Pixelate effect");
+ RNA_def_struct_sdna(srna, "PixelShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "size");
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Size", "Pixel size");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "rgba");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Color", "Color used for lines");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "use_lines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_PIXEL_USE_LINES);
+ RNA_def_property_ui_text(prop, "Lines", "Display lines between pixels");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_rim(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxRim", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Rim Effect", "Rim effect");
+ RNA_def_struct_sdna(srna, "RimShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "offset", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "offset");
+ RNA_def_property_range(prop, -INT_MAX, INT_MAX);
+ RNA_def_property_ui_text(prop, "Offset", "Offset of the rim");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "rim_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "rim_rgb");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Rim Color", "Color used for Rim");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "mask_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "mask_rgb");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Mask Color", "Color that must be keept");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, rna_enum_shaderfx_rim_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Blend mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "blur", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "blur");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Blur", "Number of pixels for bluring rim (set to 0 to disable)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "samples");
+ RNA_def_property_range(prop, 0, 32);
+ RNA_def_property_ui_range(prop, 0, 32, 2, -1);
+ RNA_def_property_int_default(prop, 4);
+ RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_shadow(BlenderRNA *brna)
+{
+ static EnumPropertyItem prop_shaderfx_shadow_type_items[] = {
+ { 0, "HORIZONTAL", 0, "Horizontal", "" },
+ { 1, "VERTICAL", 0, "Vertical", "" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxShadow", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Shadow Effect", "Shadow effect");
+ RNA_def_struct_sdna(srna, "ShadowShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Object to determine center of rotation");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_ShadowShaderFx_object_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_ShaderFx_dependency_update");
+
+ prop = RNA_def_property(srna, "offset", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "offset");
+ RNA_def_property_range(prop, -INT_MAX, INT_MAX);
+ RNA_def_property_ui_text(prop, "Offset", "Offset of the shadow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Scale", "Offset of the shadow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "shadow_rgba");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Shadow Color", "Color used for Shadow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "orientation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "orientation");
+ RNA_def_property_enum_items(prop, prop_shaderfx_shadow_type_items);
+ RNA_def_property_ui_text(prop, "Orientation", "Direction of the wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "period");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Period", "Period of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "phase");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Phase", "Phase Shift of Wave");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "rotation");
+ RNA_def_property_range(prop, DEG2RAD(-360), DEG2RAD(360));
+ RNA_def_property_ui_range(prop, DEG2RAD(-360), DEG2RAD(360), 5, 2);
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation around center or object");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "blur", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "blur");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Blur", "Number of pixels for bluring shadow (set to 0 to disable)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "samples");
+ RNA_def_property_range(prop, 0, 32);
+ RNA_def_property_ui_range(prop, 0, 32, 2, -1);
+ RNA_def_property_int_default(prop, 4);
+ RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "use_object", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_SHADOW_USE_OBJECT);
+ RNA_def_property_ui_text(prop, "Use Object", "Use object as center of rotation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "use_wave", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_SHADOW_USE_WAVE);
+ RNA_def_property_ui_text(prop, "Wave", "Use wave effect");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_glow(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxGlow", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Glow Effect", "Glow effect");
+ RNA_def_struct_sdna(srna, "GlowShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "glow_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "glow_color");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Glow Color", "Color used for generated glow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "select_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "select_color");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Select Color", "Color selected to apply glow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, rna_enum_shaderfx_glow_modes_items);
+ RNA_def_property_ui_text(prop, "Mode", "Glow mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "threshold");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 3);
+ RNA_def_property_ui_text(prop, "Threshold", "Limit to select color for glow effect");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ /* use blur fields to make compatible with blur filter, but only makes public first array element */
+ prop = RNA_def_property(srna, "radius", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "blur[0]");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Radius", "Number of pixels for bluring glow (set to 0 to disable)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "samples");
+ RNA_def_property_range(prop, 1, 32);
+ RNA_def_property_ui_range(prop, 1, 32, 2, -1);
+ RNA_def_property_int_default(prop, 4);
+ RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "use_alpha_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_GLOW_USE_ALPHA);
+ RNA_def_property_ui_text(prop, "Use Alpha", "Glow only areas with alpha");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_swirl(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxSwirl", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Swirl Effect", "Swirl effect");
+ RNA_def_struct_sdna(srna, "SwirlShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "radius", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "radius");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Radius", "Radius to apply");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "angle");
+ RNA_def_property_range(prop, DEG2RAD(-5 * 360), DEG2RAD(5 * 360));
+ RNA_def_property_ui_range(prop, DEG2RAD(-5 * 360), DEG2RAD(5 * 360), 5, 2);
+ RNA_def_property_ui_text(prop, "Angle", "Angle of rotation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "transparent", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_SWIRL_MAKE_TRANSPARENT);
+ RNA_def_property_ui_text(prop, "Transparent", "Make image transparent outside of radius");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Object to determine center location");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_SwirlShaderFx_object_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_ShaderFx_dependency_update");
+}
+
+static void rna_def_shader_fx_flip(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxFlip", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Flip Effect", "Flip effect");
+ RNA_def_struct_sdna(srna, "FlipShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "flip_horizontal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_FLIP_HORIZONTAL);
+ RNA_def_property_ui_text(prop, "Horizontal", "Flip image horizontally");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "flip_vertical", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_FLIP_VERTICAL);
+ RNA_def_property_ui_text(prop, "Vertical", "Flip image vertically");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+}
+
+static void rna_def_shader_fx_light(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ShaderFxLight", "ShaderFx");
+ RNA_def_struct_ui_text(srna, "Light Effect", "Light effect");
+ RNA_def_struct_sdna(srna, "LightShaderFxData");
+ RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
+
+ prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "energy");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 1, FLT_MAX, 1, 2);
+ RNA_def_property_ui_text(prop, "Energy", "Strength of light source");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "ambient", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "ambient");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, 2);
+ RNA_def_property_ui_text(prop, "Ambient", "Strength of ambient light source");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Object to determine light source location");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_LightShaderFx_object_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_ShaderFx_dependency_update");
+}
+
+void RNA_def_shader_fx(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* data */
+ srna = RNA_def_struct(brna, "ShaderFx", NULL);
+ RNA_def_struct_ui_text(srna, "ShaderFx", "Effect affecting the grease pencil object");
+ RNA_def_struct_refine_func(srna, "rna_ShaderFx_refine");
+ RNA_def_struct_path_func(srna, "rna_ShaderFx_path");
+ RNA_def_struct_sdna(srna, "ShaderFxData");
+
+ /* strings */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ShaderFx_name_set");
+ RNA_def_property_ui_text(prop, "Name", "Effect name");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER | NA_RENAME, NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ /* enums */
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, rna_enum_object_shaderfx_type_items);
+ RNA_def_property_ui_text(prop, "Type", "");
+
+ /* flags */
+ prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Realtime);
+ RNA_def_property_ui_text(prop, "Realtime", "Display effect in viewport");
+ RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_ON, 1);
+
+ prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Render);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Render", "Use effect during render");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_ON, 1);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
+ prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Editmode);
+ RNA_def_property_ui_text(prop, "Edit Mode", "Display effect in Edit mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+ RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0);
+
+ prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Expanded);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Expanded", "Set effect expanded in the user interface");
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
+
+ /* types */
+ rna_def_shader_fx_blur(brna);
+ rna_def_shader_fx_colorize(brna);
+ rna_def_shader_fx_wave(brna);
+ rna_def_shader_fx_pixel(brna);
+ rna_def_shader_fx_rim(brna);
+ rna_def_shader_fx_shadow(brna);
+ rna_def_shader_fx_glow(brna);
+ rna_def_shader_fx_swirl(brna);
+ rna_def_shader_fx_flip(brna);
+ rna_def_shader_fx_light(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 65e56ddb487..8e375c3645e 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -54,21 +54,23 @@
#include "BKE_colorband.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_particle.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "smoke_API.h"
static void rna_Smoke_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
static void rna_Smoke_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_Smoke_update(bmain, scene, ptr);
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
static void rna_Smoke_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -76,7 +78,7 @@ static void rna_Smoke_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
if (settings->smd && settings->smd->domain)
settings->point_cache[0]->flag |= PTCACHE_OUTDATED;
- DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+ DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
}
static void rna_Smoke_cachetype_set(struct PointerRNA *ptr, int value)
@@ -512,6 +514,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static const EnumPropertyItem interp_method_item[] = {
+ {VOLUME_INTERP_LINEAR, "LINEAR", 0, "Linear", "Good smoothness and speed"},
+ {VOLUME_INTERP_CUBIC, "CUBIC", 0, "Cubic", "Smoothed high quality interpolation, but slower"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
static const EnumPropertyItem axis_slice_position_items[] = {
{SLICE_AXIS_AUTO, "AUTO", 0, "Auto", "Adjust slice direction according to the view direction"},
{SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"},
@@ -521,8 +529,8 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
};
static const EnumPropertyItem vector_draw_items[] = {
- {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Draw vectors as needles"},
- {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Draw vectors as streamlines"},
+ {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Display vectors as needles"},
+ {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Display vectors as streamlines"},
{0, NULL, 0, NULL, NULL}
};
@@ -581,25 +589,25 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
"How much heat affects smoke motion (higher value results in faster rising smoke)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
- prop = RNA_def_property(srna, "collision_group", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "collision_collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "coll_group");
- RNA_def_property_struct_type(prop, "Group");
+ RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Collision Group", "Limit collisions to this group");
+ RNA_def_property_ui_text(prop, "Collision Collection", "Limit collisions to this collection");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
- prop = RNA_def_property(srna, "fluid_group", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "fluid_collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "fluid_group");
- RNA_def_property_struct_type(prop, "Group");
+ RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Fluid Group", "Limit fluid objects to this group");
+ RNA_def_property_ui_text(prop, "Fluid Collection", "Limit fluid objects to this collection");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
- prop = RNA_def_property(srna, "effector_group", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "effector_collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "eff_group");
- RNA_def_property_struct_type(prop, "Group");
+ RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Effector Group", "Limit effectors to this group");
+ RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
@@ -854,15 +862,21 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
- prop = RNA_def_property(srna, "draw_velocity", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "interp_method");
+ RNA_def_property_enum_items(prop, interp_method_item);
+ RNA_def_property_ui_text(prop, "Interpolation", "Interpolation method to use for smoke/fire volumes in solid mode");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "display_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0);
- RNA_def_property_ui_text(prop, "Draw Velocity", "Toggle visualization of the velocity field as needles");
+ RNA_def_property_ui_text(prop, "Display Velocity", "Toggle visualization of the velocity field as needles");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
- prop = RNA_def_property(srna, "vector_draw_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "vector_display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type");
RNA_def_property_enum_items(prop, vector_draw_items);
- RNA_def_property_ui_text(prop, "Draw Type", "");
+ RNA_def_property_ui_text(prop, "Display Type", "");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c
index 3339c5ec405..fb0ba0cdd11 100644
--- a/source/blender/makesrna/intern/rna_sound.c
+++ b/source/blender/makesrna/intern/rna_sound.c
@@ -32,7 +32,6 @@
#include "rna_internal.h"
#include "DNA_sound_types.h"
-#include "DNA_property_types.h"
#ifdef RNA_RUNTIME
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 987f94c5238..e8cda30a511 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -35,8 +35,12 @@
#include "BKE_key.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_studiolight.h"
+
+#include "BLI_math.h"
#include "DNA_action_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -45,6 +49,7 @@
#include "DNA_sequence_types.h"
#include "DNA_mask_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -66,38 +71,110 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
/* General */
{0, "", ICON_NONE, "General", ""},
- {SPACE_VIEW3D, "VIEW_3D", ICON_VIEW3D, "3D View", "3D viewport"},
- {SPACE_IMAGE, "IMAGE_EDITOR", ICON_IMAGE_COL, "UV/Image Editor", "View and edit images and UV Maps"},
+ {SPACE_VIEW3D, "VIEW_3D", ICON_VIEW3D, "3D Viewport", "Manipulate objects in a 3D environment"},
+ {SPACE_IMAGE, "IMAGE_EDITOR", ICON_IMAGE, "UV/Image Editor", "View and edit images and UV Maps"},
{SPACE_NODE, "NODE_EDITOR", ICON_NODETREE, "Node Editor", "Editor for node-based shading and compositing tools"},
{SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequencer", "Video editing tools"},
{SPACE_CLIP, "CLIP_EDITOR", ICON_CLIP, "Movie Clip Editor", "Motion tracking tools"},
/* Animation */
{0, "", ICON_NONE, "Animation", ""},
- {SPACE_TIME, "TIMELINE", ICON_TIME, "Timeline", "Timeline and playback controls"},
- {SPACE_IPO, "GRAPH_EDITOR", ICON_IPO, "Graph Editor", "Edit drivers and keyframe interpolation"},
+ //{SPACE_ACTION, "TIMELINE", ICON_TIME, "Timeline", "Timeline and playback controls (NOTE: Switch to 'Timeline' mode)"}, /* XXX */
{SPACE_ACTION, "DOPESHEET_EDITOR", ICON_ACTION, "Dope Sheet", "Adjust timing of keyframes"},
- {SPACE_NLA, "NLA_EDITOR", ICON_NLA, "NLA Editor", "Combine and layer Actions"},
+ {SPACE_IPO, "GRAPH_EDITOR", ICON_GRAPH, "Graph Editor", "Edit drivers and keyframe interpolation"},
+ {SPACE_NLA, "NLA_EDITOR", ICON_NLA, "Nonlinear Animation", "Combine and layer Actions"},
/* Scripting */
{0, "", ICON_NONE, "Scripting", ""},
{SPACE_TEXT, "TEXT_EDITOR", ICON_TEXT, "Text Editor", "Edit scripts and in-file documentation"},
- {SPACE_LOGIC, "LOGIC_EDITOR", ICON_LOGIC, "Logic Editor", "Game logic editing"},
{SPACE_CONSOLE, "CONSOLE", ICON_CONSOLE, "Python Console", "Interactive programmatic console for "
"advanced editing and script development"},
{SPACE_INFO, "INFO", ICON_INFO, "Info", "Main menu bar and list of error messages "
"(drag down to expand and display)"},
+ /* Special case: Top-bar and Status-bar aren't supposed to be a regular editor for the user. */
+ {SPACE_TOPBAR, "TOPBAR", ICON_NONE, "Top Bar", "Global bar at the top of the screen for "
+ "global per-window settings"},
+ {SPACE_STATUSBAR, "STATUSBAR", ICON_NONE, "Status Bar", "Global bar at the bottom of the "
+ "screen for general status information"},
/* Data */
{0, "", ICON_NONE, "Data", ""},
- {SPACE_OUTLINER, "OUTLINER", ICON_OOPS, "Outliner", "Overview of scene graph and all available data-blocks"},
- {SPACE_BUTS, "PROPERTIES", ICON_BUTS, "Properties", "Edit properties of active object and related data-blocks"},
- {SPACE_FILE, "FILE_BROWSER", ICON_FILESEL, "File Browser", "Browse for files and assets"},
+ {SPACE_OUTLINER, "OUTLINER", ICON_OUTLINER, "Outliner", "Overview of scene graph and all available data-blocks"},
+ {SPACE_BUTS, "PROPERTIES", ICON_PROPERTIES, "Properties", "Edit properties of active object and related data-blocks"},
+ {SPACE_FILE, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", "Browse for files and assets"},
{SPACE_USERPREF, "USER_PREFERENCES", ICON_PREFERENCES, "User Preferences",
"Edit persistent configuration settings"},
{0, NULL, 0, NULL, NULL}
};
+const EnumPropertyItem rna_enum_space_graph_mode_items[] = {
+ {SIPO_MODE_ANIMATION, "FCURVES", ICON_GRAPH, "Graph Editor",
+ "Edit animation/keyframes displayed as 2D curves"},
+ {SIPO_MODE_DRIVERS, "DRIVERS", ICON_DRIVER, "Drivers", "Edit drivers"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+#define SACT_ITEM_DOPESHEET \
+ {SACTCONT_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dope Sheet", "Edit all keyframes in scene"}
+#define SACT_ITEM_TIMELINE \
+ {SACTCONT_TIMELINE, "TIMELINE", ICON_TIME, "Timeline", "Timeline and playback controls"}
+#define SACT_ITEM_ACTION \
+ {SACTCONT_ACTION, "ACTION", ICON_OBJECT_DATA, "Action Editor", "Edit keyframes in active object's Object-level action"}
+#define SACT_ITEM_SHAPEKEY \
+ {SACTCONT_SHAPEKEY, "SHAPEKEY", ICON_SHAPEKEY_DATA, "Shape Key Editor", "Edit keyframes in active object's Shape Keys action"}
+#define SACT_ITEM_GPENCIL \
+ {SACTCONT_GPENCIL, "GPENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Edit timings for all Grease Pencil sketches in file"}
+#define SACT_ITEM_MASK \
+ {SACTCONT_MASK, "MASK", ICON_MOD_MASK, "Mask", "Edit timings for Mask Editor splines"}
+#define SACT_ITEM_CACHEFILE \
+ {SACTCONT_CACHEFILE, "CACHEFILE", ICON_FILE, "Cache File", "Edit timings for Cache File data-blocks"}
+
+#ifndef RNA_RUNTIME
+/* XXX: action-editor is currently for object-level only actions, so show that using object-icon hint */
+static EnumPropertyItem rna_enum_space_action_mode_all_items[] = {
+ SACT_ITEM_DOPESHEET,
+ SACT_ITEM_TIMELINE,
+ SACT_ITEM_ACTION,
+ SACT_ITEM_SHAPEKEY,
+ SACT_ITEM_GPENCIL,
+ SACT_ITEM_MASK,
+ SACT_ITEM_CACHEFILE,
+ {0, NULL, 0, NULL, NULL}
+};
+static EnumPropertyItem rna_enum_space_action_ui_mode_items[] = {
+ SACT_ITEM_DOPESHEET,
+ /* SACT_ITEM_TIMELINE, */
+ SACT_ITEM_ACTION,
+ SACT_ITEM_SHAPEKEY,
+ SACT_ITEM_GPENCIL,
+ SACT_ITEM_MASK,
+ SACT_ITEM_CACHEFILE,
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+/* expose as ui_mode */
+const EnumPropertyItem rna_enum_space_action_mode_items[] = {
+ SACT_ITEM_DOPESHEET,
+ SACT_ITEM_TIMELINE,
+ {0, NULL, 0, NULL, NULL}
+};
+
+#undef SACT_ITEM_DOPESHEET
+#undef SACT_ITEM_TIMELINE
+#undef SACT_ITEM_ACTION
+#undef SACT_ITEM_SHAPEKEY
+#undef SACT_ITEM_GPENCIL
+#undef SACT_ITEM_MASK
+#undef SACT_ITEM_CACHEFILE
+
+const EnumPropertyItem rna_enum_space_image_mode_items[] = {
+ {SI_MODE_VIEW, "VIEW", ICON_FILE_IMAGE, "View", "View the image"},
+ {SI_MODE_UV, "UV", ICON_GROUP_UVS, "UV Edit", "UV edit in mesh editmode"},
+ {SI_MODE_PAINT, "PAINT", ICON_TPAINT_HLT, "Paint", "2D image painting mode"},
+ {SI_MODE_MASK, "MASK", ICON_MOD_MASK, "Mask", "Mask editing"},
+ {0, NULL, 0, NULL, NULL}
+};
+
#define V3D_S3D_CAMERA_LEFT {STEREO_LEFT_ID, "LEFT", ICON_RESTRICT_RENDER_OFF, "Left", ""},
#define V3D_S3D_CAMERA_RIGHT {STEREO_RIGHT_ID, "RIGHT", ICON_RESTRICT_RENDER_OFF, "Right", ""},
#define V3D_S3D_CAMERA_S3D {STEREO_3D_ID, "S3D", ICON_CAMERA_STEREO, "3D", ""},
@@ -133,43 +210,19 @@ static const EnumPropertyItem stereo3d_eye_items[] = {
};
#endif
-static const EnumPropertyItem pivot_items_full[] = {
- {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
- "Pivot around bounding box center of selected object(s)"},
- {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"},
- {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
- "Individual Origins", "Pivot around each object's own origin"},
- {V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
- "Pivot around the median point of selected objects"},
- {V3D_AROUND_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"},
- {0, NULL, 0, NULL, NULL}
-};
-
-static const EnumPropertyItem draw_channels_items[] = {
+static const EnumPropertyItem display_channels_items[] = {
{SI_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha",
- "Draw image with RGB colors and alpha transparency"},
- {0, "COLOR", ICON_IMAGE_RGB, "Color", "Draw image with RGB colors"},
- {SI_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Draw alpha transparency channel"},
+ "Display image with RGB colors and alpha transparency"},
+ {0, "COLOR", ICON_IMAGE_RGB, "Color", "Display image with RGB colors"},
+ {SI_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Display alpha transparency channel"},
{SI_SHOW_ZBUF, "Z_BUFFER", ICON_IMAGE_ZDEPTH, "Z-Buffer",
- "Draw Z-buffer associated with image (mapped from camera clip start to end)"},
+ "Display Z-buffer associated with image (mapped from camera clip start to end)"},
{SI_SHOW_R, "RED", ICON_COLOR_RED, "Red", ""},
{SI_SHOW_G, "GREEN", ICON_COLOR_GREEN, "Green", ""},
{SI_SHOW_B, "BLUE", ICON_COLOR_BLUE, "Blue", ""},
{0, NULL, 0, NULL, NULL}
};
-static const EnumPropertyItem transform_orientation_items[] = {
- {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", "Align the transformation axes to world space"},
- {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", "Align the transformation axes to the selected objects' local space"},
- {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal",
- "Align the transformation axes to average normal of selected elements "
- "(bone Y axis for pose mode)"},
- {V3D_MANIP_GIMBAL, "GIMBAL", 0, "Gimbal", "Align each axis to the Euler rotation axis as used for input"},
- {V3D_MANIP_VIEW, "VIEW", 0, "View", "Align the transformation axes to the window"},
- // {V3D_MANIP_CUSTOM, "CUSTOM", 0, "Custom", "Use a custom transform orientation"},
- {0, NULL, 0, NULL, NULL}
-};
-
#ifndef RNA_RUNTIME
static const EnumPropertyItem autosnap_items[] = {
{SACTSNAP_OFF, "NONE", 0, "No Auto-Snap", ""},
@@ -185,16 +238,34 @@ static const EnumPropertyItem autosnap_items[] = {
};
#endif
-const EnumPropertyItem rna_enum_viewport_shade_items[] = {
- {OB_BOUNDBOX, "BOUNDBOX", ICON_BBOX, "Bounding Box", "Display the object's local bounding boxes only"},
- {OB_WIRE, "WIREFRAME", ICON_WIRE, "Wireframe", "Display the object as wire edges"},
- {OB_SOLID, "SOLID", ICON_SOLID, "Solid", "Display the object solid, lit with default OpenGL lights"},
- {OB_TEXTURE, "TEXTURED", ICON_POTATO, "Texture", "Display the object solid, with a texture"},
- {OB_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Display objects solid, with GLSL material"},
- {OB_RENDER, "RENDERED", ICON_SMOOTH, "Rendered", "Display render preview"},
+const EnumPropertyItem rna_enum_shading_type_items[] = {
+ {OB_WIRE, "WIREFRAME", ICON_SHADING_WIRE, "Wireframe", "Display the object as wire edges"},
+ {OB_SOLID, "SOLID", ICON_SHADING_SOLID, "Solid", "Display in solid mode"},
+ {OB_MATERIAL, "MATERIAL", ICON_SHADING_TEXTURE, "LookDev", "Display in LookDev mode"},
+ {OB_RENDER, "RENDERED", ICON_SHADING_RENDERED, "Rendered", "Display render preview"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem rna_enum_viewport_lighting_items[] = {
+ {V3D_LIGHTING_FLAT, "FLAT", 0, "Flat", "Display using flat lighting"},
+ {V3D_LIGHTING_STUDIO, "STUDIO", 0, "Studio", "Display using studio lighting"},
+ {V3D_LIGHTING_MATCAP, "MATCAP", 0, "MatCap", "Display using matcap material and lighting"},
{0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem rna_enum_shading_color_type_items[] = {
+ {V3D_SHADING_SINGLE_COLOR, "SINGLE", 0, "Single", "Show scene in a single color"},
+ {V3D_SHADING_MATERIAL_COLOR, "MATERIAL", 0, "Material", "Show material color"},
+ {V3D_SHADING_RANDOM_COLOR, "RANDOM", 0, "Random", "Show random object color"},
+ {V3D_SHADING_TEXTURE_COLOR, "TEXTURE", 0, "Texture", "Show texture"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
+static const EnumPropertyItem rna_enum_studio_light_items[] = {
+ {0, "DEFAULT", 0, "Default", ""},
+ {0, NULL, 0, NULL, NULL}
+};
const EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
{SC_MODE_TRACKING, "TRACKING", ICON_ANIM_DATA, "Tracking", "Show tracking and solving tools"},
@@ -204,35 +275,26 @@ const EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
/* Actually populated dynamically trough a function, but helps for context-less access (e.g. doc, i18n...). */
static const EnumPropertyItem buttons_context_items[] = {
+ {BCONTEXT_TOOL, "TOOL", ICON_TOOL_SETTINGS, "Tool", "Active Tool and Workspace settings"},
{BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene"},
{BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render"},
- {BCONTEXT_RENDER_LAYER, "RENDER_LAYER", ICON_RENDERLAYERS, "Render Layers", "Render layers"},
+ {BCONTEXT_OUTPUT, "OUTPUT", ICON_OUTPUT, "Output", "Output"},
+ {BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View Layer"},
{BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World"},
{BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object"},
- {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraints", "Object constraints"},
- {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Object modifiers"},
- {BCONTEXT_DATA, "DATA", ICON_NONE, "Data", "Object data"},
+ {BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraints", "Object Constraints"},
+ {BCONTEXT_MODIFIER, "MODIFIER", ICON_MODIFIER, "Modifiers", "Modifiers"},
+ {BCONTEXT_DATA, "DATA", ICON_NONE, "Data", "Object Data"},
{BCONTEXT_BONE, "BONE", ICON_BONE_DATA, "Bone", "Bone"},
- {BCONTEXT_BONE_CONSTRAINT, "BONE_CONSTRAINT", ICON_CONSTRAINT_BONE, "Bone Constraints", "Bone constraints"},
+ {BCONTEXT_BONE_CONSTRAINT, "BONE_CONSTRAINT", ICON_CONSTRAINT_BONE, "Bone Constraints", "Bone Constraints"},
{BCONTEXT_MATERIAL, "MATERIAL", ICON_MATERIAL, "Material", "Material"},
{BCONTEXT_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture"},
- {BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particle"},
+ {BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particles"},
{BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics"},
+ {BCONTEXT_SHADERFX, "SHADERFX", ICON_SHADERFX, "Effects", "Object visual effects" },
{0, NULL, 0, NULL, NULL}
};
-/* Actually populated dynamically trough a function, but helps for context-less access (e.g. doc, i18n...). */
-static const EnumPropertyItem buttons_texture_context_items[] = {
- {SB_TEXC_MATERIAL, "MATERIAL", ICON_MATERIAL, "", "Show material textures"},
- {SB_TEXC_WORLD, "WORLD", ICON_WORLD, "", "Show world textures"},
- {SB_TEXC_LAMP, "LAMP", ICON_LAMP, "", "Show lamp textures"},
- {SB_TEXC_PARTICLES, "PARTICLES", ICON_PARTICLES, "", "Show particles textures"},
- {SB_TEXC_LINESTYLE, "LINESTYLE", ICON_LINE_DATA, "", "Show linestyle textures"},
- {SB_TEXC_OTHER, "OTHER", ICON_TEXTURE, "", "Show other data textures"},
- {0, NULL, 0, NULL, NULL}
-};
-
-
static const EnumPropertyItem fileselectparams_recursion_level_items[] = {
{0, "NONE", 0, "None", "Only list current directory's content, with no recursion"},
{1, "BLEND", 0, "Blend File", "List .blend files' content"},
@@ -257,7 +319,6 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
-#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
@@ -265,18 +326,24 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_icons.h"
+#include "BKE_workspace.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "ED_anim_api.h"
#include "ED_buttons.h"
#include "ED_fileselect.h"
#include "ED_image.h"
#include "ED_node.h"
+#include "ED_transform.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_sequencer.h"
@@ -316,12 +383,8 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
return &RNA_SpaceDopeSheetEditor;
case SPACE_NLA:
return &RNA_SpaceNLA;
- case SPACE_TIME:
- return &RNA_SpaceTimeline;
case SPACE_NODE:
return &RNA_SpaceNodeEditor;
- case SPACE_LOGIC:
- return &RNA_SpaceLogicEditor;
case SPACE_CONSOLE:
return &RNA_SpaceConsole;
case SPACE_USERPREF:
@@ -416,55 +479,15 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain), Scene *UNUSED(scen
}
}
-static PointerRNA rna_CurrentOrientation_get(PointerRNA *ptr)
+static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
- View3D *v3d = (View3D *)ptr->data;
-
- if (v3d->twmode < V3D_MANIP_CUSTOM)
- return rna_pointer_inherit_refine(ptr, &RNA_TransformOrientation, NULL);
- else
- return rna_pointer_inherit_refine(ptr, &RNA_TransformOrientation,
- BLI_findlink(&scene->transform_spaces, v3d->twmode - V3D_MANIP_CUSTOM));
-}
-
-const EnumPropertyItem *rna_TransformOrientation_itemf(
- bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
-{
- Scene *scene = NULL;
- ListBase *transform_spaces;
- TransformOrientation *ts = NULL;
- EnumPropertyItem tmp = {0, "", 0, "", ""};
- EnumPropertyItem *item = NULL;
- int i = V3D_MANIP_CUSTOM, totitem = 0;
-
- RNA_enum_items_add(&item, &totitem, transform_orientation_items);
-
- if (ptr->type == &RNA_SpaceView3D)
- scene = ((bScreen *)ptr->id.data)->scene;
- else
- scene = CTX_data_scene(C); /* can't use scene from ptr->id.data because that enum is also used by operators */
-
- if (scene) {
- transform_spaces = &scene->transform_spaces;
- ts = transform_spaces->first;
- }
-
- if (ts) {
- RNA_enum_item_add_separator(&item, &totitem);
-
- for (; ts; ts = ts->next) {
- tmp.identifier = ts->name;
- tmp.name = ts->name;
- tmp.value = i++;
- RNA_enum_item_add(&item, &totitem, &tmp);
+ /* need set all caches as dirty to recalculate onion skinning */
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_GPENCIL) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
/* Space 3D View */
@@ -472,8 +495,10 @@ static void rna_SpaceView3D_camera_update(Main *bmain, Scene *scene, PointerRNA
{
View3D *v3d = (View3D *)(ptr->data);
if (v3d->scenelock) {
+ wmWindowManager *wm = bmain->wm.first;
+
scene->camera = v3d->camera;
- BKE_screen_view3d_main_sync(&bmain->screen, scene);
+ WM_windows_scene_data_sync(&wm->windows, scene);
}
}
@@ -485,8 +510,13 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, bool val
v3d->scenelock = value;
if (value) {
+ Scene *scene = ED_screen_scene_find(sc, G_MAIN->wm.first);
+
+ /* TODO: restore local view. */
+#if 0
int bit;
- v3d->lay = sc->scene->lay;
+ v3d->lay = scene->lay;
+
/* seek for layact */
bit = 0;
while (bit < 32) {
@@ -496,120 +526,20 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, bool val
}
bit++;
}
- v3d->camera = sc->scene->camera;
+#endif
+ v3d->camera = scene->camera;
}
}
-static void rna_View3D_CursorLocation_get(PointerRNA *ptr, float *values)
+static float rna_View3DOverlay_GridScaleUnit_get(PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->id.data;
- Scene *scene = (Scene *)sc->scene;
- const float *loc = ED_view3d_cursor3d_get(scene, v3d);
-
- copy_v3_v3(values, loc);
-}
-
-static void rna_View3D_CursorLocation_set(PointerRNA *ptr, const float *values)
-{
- View3D *v3d = (View3D *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->id.data;
- Scene *scene = (Scene *)sc->scene;
- float *cursor = ED_view3d_cursor3d_get(scene, v3d);
-
- copy_v3_v3(cursor, values);
-}
-
-static float rna_View3D_GridScaleUnit_get(PointerRNA *ptr)
-{
- View3D *v3d = (View3D *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->id.data;
- Scene *scene = (Scene *)sc->scene;
+ bScreen *screen = ptr->id.data;
+ Scene *scene = ED_screen_scene_find(screen, G_MAIN->wm.first);
return ED_view3d_grid_scale(scene, v3d, NULL);
}
-static void rna_SpaceView3D_layer_set(PointerRNA *ptr, const bool *values)
-{
- View3D *v3d = (View3D *)(ptr->data);
-
- v3d->lay = ED_view3d_scene_layer_set(v3d->lay, values, &v3d->layact);
-}
-
-static int rna_SpaceView3D_active_layer_get(PointerRNA *ptr)
-{
- View3D *v3d = (View3D *)(ptr->data);
-
- return (int)(log(v3d->layact) / M_LN2);
-}
-
-static void rna_SpaceView3D_layer_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
-{
- DAG_on_visible_update(bmain, false);
-}
-
-static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
-{
- View3D *v3d = (View3D *)(ptr->data);
- ScrArea *sa = rna_area_from_space(ptr);
-
- ED_view3d_shade_update(bmain, v3d, sa);
-}
-
-static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- View3D *v3d = (View3D *)(ptr->data);
-
- if (v3d->defmaterial) {
- Material *ma = v3d->defmaterial;
-
- if (ma->preview)
- BKE_previewimg_free(&ma->preview);
-
- if (ma->gpumaterial.first)
- GPU_material_free(&ma->gpumaterial);
-
- WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ma);
- }
-}
-
-static void rna_SpaceView3D_matcap_enable(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- View3D *v3d = (View3D *)(ptr->data);
-
- if (v3d->matcap_icon < ICON_MATCAP_01 ||
- v3d->matcap_icon > ICON_MATCAP_24)
- {
- v3d->matcap_icon = ICON_MATCAP_01;
- }
-}
-
-static void rna_SpaceView3D_pivot_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
-{
- if (U.uiflag & USER_LOCKAROUND) {
- View3D *v3d_act = (View3D *)(ptr->data);
-
- /* TODO, space looper */
- bScreen *screen;
- for (screen = bmain->screen.first; screen; screen = screen->id.next) {
- ScrArea *sa;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- if (v3d != v3d_act) {
- v3d->around = v3d_act->around;
- v3d->flag = (v3d->flag & ~V3D_ALIGN) | (v3d_act->flag & V3D_ALIGN);
- ED_area_tag_redraw_regiontype(sa, RGN_TYPE_HEADER);
- }
- }
- }
- }
- }
- }
-}
-
static PointerRNA rna_SpaceView3D_region_3d_get(PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
@@ -706,45 +636,109 @@ static void rna_RegionView3D_view_matrix_set(PointerRNA *ptr, const float *value
ED_view3d_from_m4(mat, rv3d->ofs, rv3d->viewquat, &rv3d->dist);
}
-static int rna_SpaceView3D_viewport_shade_get(PointerRNA *ptr)
+static void rna_3DViewShading_type_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
- RenderEngineType *type = RE_engines_find(scene->r.engine);
- View3D *v3d = (View3D *)ptr->data;
- int drawtype = v3d->drawtype;
+ ID *id = ptr->id.data;
+ if (GS(id->name) == ID_SCE) {
+ return;
+ }
+
+ for (Material *ma = bmain->mat.first; ma; ma = ma->id.next) {
+ /* XXX Dependency graph does not support CD mask tracking,
+ * so we trigger materials shading for until it's properly supported.
+ * This is to ensure material batches are all recreated when switching
+ * shading type. In the future DEG should replace this and just tag
+ * the meshes itself.
+ * This hack just tag BKE_MESH_BATCH_DIRTY_SHADING for every mesh that
+ * have a material. (see T55059) */
+ DEG_id_tag_update(&ma->id, DEG_TAG_SHADING_UPDATE);
+ }
+
+ bScreen *screen = ptr->id.data;
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ if (&v3d->shading == ptr->data) {
+ ED_view3d_shade_update(bmain, v3d, sa);
+ return;
+ }
+ }
+ }
+ }
+}
+
+static Scene *rna_3DViewShading_scene(PointerRNA *ptr)
+{
+ /* Get scene, depends if using 3D view or OpenGL render settings. */
+ ID *id = ptr->id.data;
+ if (GS(id->name) == ID_SCE) {
+ return (Scene *)id;
+ }
+ else {
+ bScreen *screen = ptr->id.data;
+ return WM_windows_scene_get_from_screen(G_MAIN->wm.first, screen);
+ }
+}
- if (drawtype == OB_RENDER && !(type && type->view_draw))
- return OB_SOLID;
+static int rna_3DViewShading_type_get(PointerRNA *ptr)
+{
+ /* Available shading types depend on render engine. */
+ Scene *scene = rna_3DViewShading_scene(ptr);
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ View3DShading *shading = (View3DShading *)ptr->data;
- return drawtype;
+ if (BKE_scene_uses_blender_eevee(scene)) {
+ return shading->type;
+ }
+ else if (BKE_scene_uses_blender_workbench(scene)) {
+ return (shading->type == OB_MATERIAL) ? OB_RENDER : shading->type;
+ }
+ else {
+ if (shading->type == OB_RENDER && !(type && type->view_draw)) {
+ return OB_MATERIAL;
+ }
+ else {
+ return shading->type;
+ }
+ }
}
-static void rna_SpaceView3D_viewport_shade_set(PointerRNA *ptr, int value)
+static void rna_3DViewShading_type_set(PointerRNA *ptr, int value)
{
- View3D *v3d = (View3D *)ptr->data;
- if (value != v3d->drawtype && value == OB_RENDER) {
- v3d->prev_drawtype = v3d->drawtype;
+ View3DShading *shading = (View3DShading *)ptr->data;
+ if (value != shading->type && value == OB_RENDER) {
+ shading->prev_type = shading->type;
}
- v3d->drawtype = value;
+ shading->type = value;
}
-static const EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *rna_3DViewShading_type_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ Scene *scene = rna_3DViewShading_scene(ptr);
RenderEngineType *type = RE_engines_find(scene->r.engine);
EnumPropertyItem *item = NULL;
int totitem = 0;
- RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_BOUNDBOX);
- RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_WIRE);
- RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_SOLID);
- RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_TEXTURE);
- RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_MATERIAL);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_WIRE);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_SOLID);
- if (type && type->view_draw)
- RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_RENDER);
+ if (BKE_scene_uses_blender_eevee(scene)) {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_MATERIAL);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_RENDER);
+ }
+ else if (BKE_scene_uses_blender_workbench(scene)) {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_RENDER);
+ }
+ else {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_MATERIAL);
+ if (type && type->view_draw) {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_type_items, OB_RENDER);
+ }
+ }
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -752,10 +746,168 @@ static const EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UN
return item;
}
-static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+/* Shading.selected_studio_light */
+static PointerRNA rna_View3DShading_selected_studio_light_get(PointerRNA *ptr)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+ StudioLight *sl;
+ if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) {
+ sl = BKE_studiolight_find(shading->matcap, STUDIOLIGHT_FLAG_ALL);
+ }
+ else if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_STUDIO) {
+ sl = BKE_studiolight_find(shading->studio_light, STUDIOLIGHT_FLAG_ALL);
+ }
+ else {
+ sl = BKE_studiolight_find(shading->lookdev_light, STUDIOLIGHT_FLAG_ALL);
+ }
+ return rna_pointer_inherit_refine(ptr, &RNA_StudioLight, sl);
+}
+
+/* shading.light */
+static int rna_View3DShading_light_get(PointerRNA *ptr)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+ return shading->light;
+}
+
+static void rna_View3DShading_light_set(PointerRNA *ptr, int value)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+ if (value == V3D_LIGHTING_MATCAP && shading->color_type == V3D_SHADING_TEXTURE_COLOR) {
+ shading->color_type = V3D_SHADING_MATERIAL_COLOR;
+ }
+ shading->light = value;
+}
+
+static const EnumPropertyItem *rna_View3DShading_color_type_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+
+ int totitem = 0;
+ EnumPropertyItem *item = NULL;
+
+ if (shading->type == OB_SOLID) {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_SINGLE_COLOR);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_MATERIAL_COLOR);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_RANDOM_COLOR);
+ if (shading->light != V3D_LIGHTING_MATCAP) {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_shading_color_type_items, V3D_SHADING_TEXTURE_COLOR);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+ return item;
+}
+
+/* Studio light */
+static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+ char *dna_storage = shading->studio_light;
+
+ int flag = STUDIOLIGHT_TYPE_STUDIO;
+ if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) {
+ flag = STUDIOLIGHT_TYPE_MATCAP;
+ dna_storage = shading->matcap;
+ }
+ else if (shading->type == OB_MATERIAL) {
+ flag = STUDIOLIGHT_TYPE_WORLD;
+ dna_storage = shading->lookdev_light;
+ }
+ StudioLight *sl = BKE_studiolight_find(dna_storage, flag);
+ if (sl) {
+ BLI_strncpy(dna_storage, sl->name, FILE_MAXFILE);
+ return sl->index;
+ }
+ else {
+ return 0;
+ }
+}
+
+static void rna_View3DShading_studio_light_set(PointerRNA *ptr, int value)
+{
+ View3DShading *shading = (View3DShading *)ptr->data;
+ char *dna_storage = shading->studio_light;
+
+ int flag = STUDIOLIGHT_TYPE_STUDIO;
+ if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) {
+ flag = STUDIOLIGHT_TYPE_MATCAP;
+ dna_storage = shading->matcap;
+ }
+ else if (shading->type == OB_MATERIAL) {
+ flag = STUDIOLIGHT_TYPE_WORLD;
+ dna_storage = shading->lookdev_light;
+ }
+ StudioLight *sl = BKE_studiolight_findindex(value, flag);
+ if (sl) {
+ BLI_strncpy(dna_storage, sl->name, FILE_MAXFILE);
+ }
+}
+
+static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
- Scene *scene = ((bScreen *)ptr->id.data)->scene;
+ View3DShading *shading = (View3DShading *)ptr->data;
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ if (shading->type == OB_SOLID && shading->light == V3D_LIGHTING_MATCAP) {
+ const int flags = (STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_TYPE_MATCAP);
+
+ LISTBASE_FOREACH(StudioLight *, sl, BKE_studiolight_listbase()) {
+ int icon_id = (shading->flag & V3D_SHADING_MATCAP_FLIP_X) ? sl->icon_id_matcap_flipped: sl->icon_id_matcap;
+ if ((sl->flag & flags) == flags) {
+ EnumPropertyItem tmp = {sl->index, sl->name, icon_id, sl->name, ""};
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+ }
+ }
+ else {
+ LISTBASE_FOREACH(StudioLight *, sl, BKE_studiolight_listbase()) {
+ int icon_id = sl->icon_id_irradiance;
+ bool show_studiolight = false;
+
+ if (sl->flag & STUDIOLIGHT_INTERNAL) {
+ /* always show internal lights for solid */
+ if (shading->type == OB_SOLID) {
+ show_studiolight = true;
+ }
+ }
+ else {
+ switch (shading->type) {
+ case OB_SOLID:
+ case OB_TEXTURE:
+ show_studiolight = ((sl->flag & STUDIOLIGHT_TYPE_STUDIO) != 0);
+ break;
+
+ case OB_MATERIAL:
+ show_studiolight = ((sl->flag & STUDIOLIGHT_TYPE_WORLD) != 0);
+ icon_id = sl->icon_id_radiance;
+ break;
+ }
+ }
+
+ if (show_studiolight) {
+ EnumPropertyItem tmp = {sl->index, sl->name, icon_id, sl->name, ""};
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+ return item;
+}
+
+static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+{
+ Scene *scene = CTX_data_scene(C);
if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
return multiview_camera_items;
@@ -763,6 +915,30 @@ static const EnumPropertyItem *rna_SpaceView3D_stereo3d_camera_itemf(bContext *U
return stereo3d_camera_items;
}
+static int rna_SpaceView3D_icon_from_show_object_viewport_get(PointerRNA *ptr)
+{
+ const View3D *v3d = (View3D *)ptr->data;
+ /* Ignore selection values when view is off, intent is to show if visible objects aren't selectable. */
+ const int view_value = (v3d->object_type_exclude_viewport != 0);
+ const int select_value = (v3d->object_type_exclude_select & ~v3d->object_type_exclude_viewport) != 0;
+ return ICON_VIS_SEL_11 + (view_value << 1) + select_value;
+}
+
+static char *rna_View3DShading_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_sprintfN("shading");
+}
+
+static PointerRNA rna_SpaceView3D_overlay_get(PointerRNA *ptr)
+{
+ return rna_pointer_inherit_refine(ptr, &RNA_View3DOverlay, ptr->data);
+}
+
+static char *rna_View3DOverlay_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_sprintfN("overlay");
+}
+
/* Space Image Editor */
static PointerRNA rna_SpaceImageEditor_uvedit_get(PointerRNA *ptr)
@@ -823,23 +999,32 @@ static bool rna_SpaceImageEditor_show_uvedit_get(PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
bScreen *sc = (bScreen *)ptr->id.data;
- return ED_space_image_show_uvedit(sima, sc->scene->obedit);
+ wmWindow *win = ED_screen_window_find(sc, G_MAIN->wm.first);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ return ED_space_image_show_uvedit(sima, obedit);
}
static bool rna_SpaceImageEditor_show_maskedit_get(PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
bScreen *sc = (bScreen *)ptr->id.data;
- return ED_space_image_check_show_maskedit(sc->scene, sima);
+ wmWindow *win = ED_screen_window_find(sc, G_MAIN->wm.first);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ return ED_space_image_check_show_maskedit(sima, view_layer);
}
static void rna_SpaceImageEditor_image_set(PointerRNA *ptr, PointerRNA value)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
bScreen *sc = (bScreen *)ptr->id.data;
+ wmWindow *win;
+ Scene *scene = ED_screen_scene_find_with_window(sc, G_MAIN->wm.first, &win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
- BLI_assert(BKE_id_is_in_gobal_main(value.data));
- ED_space_image_set(G_MAIN, sima, sc->scene, sc->scene->obedit, (Image *)value.data);
+ BLI_assert(BKE_id_is_in_global_main(value.data));
+ ED_space_image_set(G_MAIN, sima, scene, obedit, (Image *)value.data);
}
static void rna_SpaceImageEditor_mask_set(PointerRNA *ptr, PointerRNA value)
@@ -849,8 +1034,9 @@ static void rna_SpaceImageEditor_mask_set(PointerRNA *ptr, PointerRNA value)
ED_space_image_set_mask(NULL, sima, (Mask *)value.data);
}
-static const EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *rna_SpaceImageEditor_display_channels_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
EnumPropertyItem *item = NULL;
@@ -866,24 +1052,24 @@ static const EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext
ED_space_image_release_buffer(sima, ibuf, lock);
if (alpha && zbuf)
- return draw_channels_items;
+ return display_channels_items;
if (alpha) {
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_USE_ALPHA);
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, 0);
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_SHOW_ALPHA);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, SI_USE_ALPHA);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, 0);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, SI_SHOW_ALPHA);
}
else if (zbuf) {
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, 0);
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_SHOW_ZBUF);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, 0);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, SI_SHOW_ZBUF);
}
else {
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, 0);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, 0);
}
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_SHOW_R);
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_SHOW_G);
- RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_SHOW_B);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, SI_SHOW_R);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, SI_SHOW_G);
+ RNA_enum_items_add_value(&item, &totitem, display_channels_items, SI_SHOW_B);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -971,14 +1157,15 @@ static void rna_SpaceImageEditor_scopes_update(struct bContext *C, struct Pointe
ED_space_image_release_buffer(sima, ibuf, lock);
}
-static const EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+static const EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
static const EnumPropertyItem pivot_items[] = {
- {V3D_AROUND_CENTER_BOUNDS, "CENTER", ICON_ROTATE, "Bounding Box Center", ""},
- {V3D_AROUND_CENTER_MEAN, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""},
- {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
- {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
+ {V3D_AROUND_CENTER_BOUNDS, "CENTER", ICON_PIVOT_BOUNDBOX, "Bounding Box Center", ""},
+ {V3D_AROUND_CENTER_MEAN, "MEDIAN", ICON_PIVOT_MEDIAN, "Median Point", ""},
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "2D Cursor", ""},
+ {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_PIVOT_INDIVIDUAL,
"Individual Origins", "Pivot around each selected island's own median point"},
{0, NULL, 0, NULL, NULL}
};
@@ -986,7 +1173,7 @@ static const EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED
SpaceImage *sima = (SpaceImage *)ptr->data;
if (sima->mode == SI_MODE_PAINT)
- return pivot_items_full;
+ return rna_enum_transform_pivot_items_full;
else
return pivot_items;
}
@@ -1074,19 +1261,32 @@ static void rna_SpaceProperties_context_set(PointerRNA *ptr, int value)
sbuts->mainbuser = value;
}
-static const EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSED(C), PointerRNA *ptr,
- PropertyRNA *UNUSED(prop), bool *r_free)
+static const EnumPropertyItem *rna_SpaceProperties_context_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
EnumPropertyItem *item = NULL;
int totitem = 0;
+ if (sbuts->pathflag & (1 << BCONTEXT_TOOL)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_TOOL);
+ }
+
+ if (totitem) {
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
+
if (sbuts->pathflag & (1 << BCONTEXT_RENDER)) {
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_RENDER);
}
- if (sbuts->pathflag & (1 << BCONTEXT_RENDER_LAYER)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_RENDER_LAYER);
+ if (sbuts->pathflag & (1 << BCONTEXT_OUTPUT)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_OUTPUT);
+ }
+
+ if (sbuts->pathflag & (1 << BCONTEXT_VIEW_LAYER)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_VIEW_LAYER);
}
if (sbuts->pathflag & (1 << BCONTEXT_SCENE)) {
@@ -1097,6 +1297,10 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSE
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_WORLD);
}
+ if (totitem) {
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
+
if (sbuts->pathflag & (1 << BCONTEXT_OBJECT)) {
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_OBJECT);
}
@@ -1109,6 +1313,10 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSE
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_MODIFIER);
}
+ if (sbuts->pathflag & (1 << BCONTEXT_SHADERFX)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_SHADERFX);
+ }
+
if (sbuts->pathflag & (1 << BCONTEXT_DATA)) {
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_DATA);
(item + totitem - 1)->icon = sbuts->dataicon;
@@ -1147,63 +1355,12 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSE
static void rna_SpaceProperties_context_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
- /* XXX BCONTEXT_DATA is ugly, but required for lamps... See T51318. */
+ /* XXX BCONTEXT_DATA is ugly, but required for lights... See T51318. */
if (ELEM(sbuts->mainb, BCONTEXT_WORLD, BCONTEXT_MATERIAL, BCONTEXT_TEXTURE, BCONTEXT_DATA)) {
sbuts->preview = 1;
}
}
-static void rna_SpaceProperties_align_set(PointerRNA *ptr, int value)
-{
- SpaceButs *sbuts = (SpaceButs *)(ptr->data);
-
- sbuts->align = value;
- sbuts->re_align = 1;
-}
-
-static const EnumPropertyItem *rna_SpaceProperties_texture_context_itemf(bContext *C, PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem *item = NULL;
- int totitem = 0;
-
- if (ED_texture_context_check_world(C)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_texture_context_items, SB_TEXC_WORLD);
- }
-
- if (ED_texture_context_check_lamp(C)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_texture_context_items, SB_TEXC_LAMP);
- }
- else if (ED_texture_context_check_material(C)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_texture_context_items, SB_TEXC_MATERIAL);
- }
-
- if (ED_texture_context_check_particles(C)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_texture_context_items, SB_TEXC_PARTICLES);
- }
-
- if (ED_texture_context_check_linestyle(C)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_texture_context_items, SB_TEXC_LINESTYLE);
- }
-
- if (ED_texture_context_check_others(C)) {
- RNA_enum_items_add_value(&item, &totitem, buttons_texture_context_items, SB_TEXC_OTHER);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-static void rna_SpaceProperties_texture_context_set(PointerRNA *ptr, int value)
-{
- SpaceButs *sbuts = (SpaceButs *)(ptr->data);
-
- /* User action, no need to keep "better" value in prev here! */
- sbuts->texture_context = sbuts->texture_context_prev = value;
-}
-
/* Space Console */
static void rna_ConsoleLine_body_get(PointerRNA *ptr, char *value)
{
@@ -1278,10 +1435,12 @@ static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr, PointerRNA valu
}
}
-static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr)
{
SpaceAction *saction = (SpaceAction *)(ptr->data);
- Object *obact = (scene->basact) ? scene->basact->object : NULL;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Main *bmain = CTX_data_main(C);
+ Object *obact = OBACT(view_layer);
/* we must set this action to be the one used by active object (if not pinned) */
if (obact /* && saction->pin == 0*/) {
@@ -1347,16 +1506,18 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, Po
}
/* force depsgraph flush too */
- DAG_id_tag_update(&obact->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&obact->id, OB_RECALC_OB | OB_RECALC_DATA);
/* Update relations as well, so new time source dependency is added. */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
}
-static void rna_SpaceDopeSheetEditor_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_SpaceDopeSheetEditor_mode_update(bContext *C, PointerRNA *ptr)
{
SpaceAction *saction = (SpaceAction *)(ptr->data);
- Object *obact = (scene->basact) ? scene->basact->object : NULL;
+ ScrArea *sa = CTX_wm_area(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(view_layer);
/* special exceptions for ShapeKey Editor mode */
if (saction->mode == SACTCONT_SHAPEKEY) {
@@ -1384,15 +1545,46 @@ static void rna_SpaceDopeSheetEditor_mode_update(Main *UNUSED(bmain), Scene *sce
saction->action = NULL;
}
+ /* Collapse (and show) summary channel and hide channel list for timeline */
+ if (saction->mode == SACTCONT_TIMELINE) {
+ saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED;
+ saction->ads.filterflag |= ADS_FILTER_SUMMARY;
+ }
+
+ if (sa && sa->spacedata.first == saction) {
+ ARegion *channels_region = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
+ if (channels_region) {
+ if (saction->mode == SACTCONT_TIMELINE) {
+ channels_region->flag |= RGN_FLAG_HIDDEN;
+ }
+ else {
+ channels_region->flag &= ~RGN_FLAG_HIDDEN;
+ }
+ ED_region_visibility_change_update(C, channels_region);
+ }
+ }
+
/* recalculate extents of channel list */
saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
+
+ /* store current mode as "old mode", so that returning from other editors doesn't always reset to "Action Editor" */
+ if (saction->mode != SACTCONT_TIMELINE) {
+ saction->mode_prev = saction->mode;
+ }
}
/* Space Graph Editor */
-static void rna_SpaceGraphEditor_display_mode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_SpaceGraphEditor_display_mode_update(bContext *C, PointerRNA *ptr)
{
ScrArea *sa = rna_area_from_space(ptr);
+ SpaceIpo *sipo = (SpaceIpo *)ptr->data;
+
+ /* for "Drivers" mode, enable all the necessary bits and pieces */
+ if (sipo->mode == SIPO_MODE_DRIVERS) {
+ ED_drivers_editor_init(C, sa);
+ ED_area_tag_redraw(sa);
+ }
/* after changing view mode, must force recalculation of F-Curve colors
* which can only be achieved using refresh as opposed to redraw
@@ -1418,59 +1610,6 @@ static void rna_Sequencer_view_type_update(Main *UNUSED(bmain), Scene *UNUSED(sc
ED_area_tag_refresh(sa);
}
-static float rna_BackgroundImage_opacity_get(PointerRNA *ptr)
-{
- BGpic *bgpic = (BGpic *)ptr->data;
- return 1.0f - bgpic->blend;
-}
-
-static void rna_BackgroundImage_opacity_set(PointerRNA *ptr, float value)
-{
- BGpic *bgpic = (BGpic *)ptr->data;
- bgpic->blend = 1.0f - value;
-}
-
-/* radius internally (expose as a distance value) */
-static float rna_BackgroundImage_size_get(PointerRNA *ptr)
-{
- BGpic *bgpic = ptr->data;
- return bgpic->size * 2.0f;
-}
-
-static void rna_BackgroundImage_size_set(PointerRNA *ptr, float value)
-{
- BGpic *bgpic = ptr->data;
- bgpic->size = value * 0.5f;
-}
-
-static BGpic *rna_BackgroundImage_new(View3D *v3d)
-{
- BGpic *bgpic = ED_view3d_background_image_new(v3d);
-
- WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, v3d);
-
- return bgpic;
-}
-
-static void rna_BackgroundImage_remove(View3D *v3d, ReportList *reports, PointerRNA *bgpic_ptr)
-{
- BGpic *bgpic = bgpic_ptr->data;
- if (BLI_findindex(&v3d->bgpicbase, bgpic) == -1) {
- BKE_report(reports, RPT_ERROR, "Background image cannot be removed");
- }
-
- ED_view3d_background_image_remove(v3d, bgpic);
- RNA_POINTER_INVALIDATE(bgpic_ptr);
-
- WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, v3d);
-}
-
-static void rna_BackgroundImage_clear(View3D *v3d)
-{
- ED_view3d_background_image_clear(v3d);
- WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, v3d);
-}
-
/* Space Node Editor */
static void rna_SpaceNodeEditor_node_tree_set(PointerRNA *ptr, const PointerRNA value)
@@ -1511,12 +1650,19 @@ static bool rna_SpaceNodeEditor_tree_type_poll(void *Cv, bNodeTreeType *type)
else
return true;
}
-static const EnumPropertyItem *rna_SpaceNodeEditor_tree_type_itemf(bContext *C, PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop), bool *r_free)
+
+const EnumPropertyItem *RNA_enum_node_tree_types_itemf_impl(bContext *C, bool *r_free)
{
return rna_node_tree_type_itemf(C, rna_SpaceNodeEditor_tree_type_poll, r_free);
}
+static const EnumPropertyItem *rna_SpaceNodeEditor_tree_type_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ return RNA_enum_node_tree_types_itemf_impl(C, r_free);
+}
+
static void rna_SpaceNodeEditor_path_get(PointerRNA *ptr, char *value)
{
SpaceNode *snode = ptr->data;
@@ -1696,6 +1842,18 @@ static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr, const
return fsm->save ? PROP_EDITABLE : 0;
}
+static bool rna_FileBrowser_FSMenuEntry_use_save_get(PointerRNA *ptr)
+{
+ FSMenuEntry *fsm = ptr->data;
+ return fsm->save;
+}
+
+static bool rna_FileBrowser_FSMenuEntry_is_valid_get(PointerRNA *ptr)
+{
+ FSMenuEntry *fsm = ptr->data;
+ return fsm->valid;
+}
+
static void rna_FileBrowser_FSMenu_next(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
@@ -1913,10 +2071,10 @@ static void rna_FileBrowser_FSMenuRecent_active_range(PointerRNA *ptr, int *min,
#else
static const EnumPropertyItem dt_uv_items[] = {
- {SI_UVDT_OUTLINE, "OUTLINE", 0, "Outline", "Draw white edges with black outline"},
- {SI_UVDT_DASH, "DASH", 0, "Dash", "Draw dashed black-white edges"},
- {SI_UVDT_BLACK, "BLACK", 0, "Black", "Draw black edges"},
- {SI_UVDT_WHITE, "WHITE", 0, "White", "Draw white edges"},
+ {SI_UVDT_OUTLINE, "OUTLINE", 0, "Outline", "Display white edges with black outline"},
+ {SI_UVDT_DASH, "DASH", 0, "Dash", "Display dashed black-white edges"},
+ {SI_UVDT_BLACK, "BLACK", 0, "Black", "Display black edges"},
+ {SI_UVDT_WHITE, "WHITE", 0, "White", "Display white edges"},
{0, NULL, 0, NULL, NULL}
};
@@ -1933,6 +2091,7 @@ static void rna_def_space(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spacetype");
RNA_def_property_enum_items(prop, rna_enum_space_type_items);
+ /* When making this editable, take care for the special case of global areas (see rna_Area_type_set). */
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Type", "Space data type");
@@ -1962,15 +2121,15 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m
RNA_def_property_update(prop, noteflag, NULL);
/* mask drawing */
- prop = RNA_def_property(srna, "mask_draw_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "mask_display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mask_info.draw_type");
RNA_def_property_enum_items(prop, dt_uv_items);
- RNA_def_property_ui_text(prop, "Edge Draw Type", "Draw type for mask splines");
+ RNA_def_property_ui_text(prop, "Edge Display Type", "Display type for mask splines");
RNA_def_property_update(prop, noteflag, NULL);
prop = RNA_def_property(srna, "show_mask_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_SMOOTH);
- RNA_def_property_ui_text(prop, "Draw Smooth Splines", "");
+ RNA_def_property_ui_text(prop, "Display Smooth Splines", "");
RNA_def_property_update(prop, noteflag, NULL);
prop = RNA_def_property(srna, "show_mask_overlay", PROP_BOOLEAN, PROP_NONE);
@@ -2005,13 +2164,6 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem other_uv_filter_items[] = {
- {SI_FILTER_ALL, "ALL", 0, "All", "No filter, show all islands from other objects"},
- {SI_FILTER_SAME_IMAGE, "SAME_IMAGE", ICON_IMAGE_DATA, "Same Image",
- "Only show others' UV islands whose active image matches image of the active face"},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "SpaceUVEditor", NULL);
RNA_def_struct_sdna(srna, "SpaceImage");
RNA_def_struct_nested(brna, srna, "SpaceImageEditor");
@@ -2026,59 +2178,59 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
/* drawing */
- prop = RNA_def_property(srna, "edge_draw_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "edge_display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dt_uv");
RNA_def_property_enum_items(prop, dt_uv_items);
- RNA_def_property_ui_text(prop, "Edge Draw Type", "Draw type for drawing UV edges");
+ RNA_def_property_ui_text(prop, "Edge Display Type", "Display type for drawing UV edges");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_smooth_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_SMOOTH_UV);
- RNA_def_property_ui_text(prop, "Draw Smooth Edges", "Draw UV edges anti-aliased");
+ RNA_def_property_ui_text(prop, "Display Smooth Edges", "Display UV edges anti-aliased");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_stretch", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_STRETCH);
- RNA_def_property_ui_text(prop, "Draw Stretch",
- "Draw faces colored according to the difference in shape between UVs and "
+ RNA_def_property_ui_text(prop, "Display Stretch",
+ "Display faces colored according to the difference in shape between UVs and "
"their 3D coordinates (blue for low distortion, red for high distortion)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
- prop = RNA_def_property(srna, "draw_stretch_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_stretch_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dt_uvstretch");
RNA_def_property_enum_items(prop, dt_uvstretch_items);
- RNA_def_property_ui_text(prop, "Draw Stretch Type", "Type of stretch to draw");
+ RNA_def_property_ui_text(prop, "Display Stretch Type", "Type of stretch to draw");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_modified_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAWSHADOW);
- RNA_def_property_ui_text(prop, "Draw Modified Edges", "Draw edges after modifiers are applied");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
-
- prop = RNA_def_property(srna, "show_other_objects", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_OTHER);
- RNA_def_property_ui_text(prop, "Draw Other Objects", "Draw other selected objects that share the same image");
+ RNA_def_property_ui_text(prop, "Display Modified Edges", "Display edges after modifiers are applied");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_metadata", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_METADATA);
- RNA_def_property_ui_text(prop, "Show Metadata", "Draw metadata properties of the image");
+ RNA_def_property_ui_text(prop, "Show Metadata", "Display metadata properties of the image");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_texpaint", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAW_TEXPAINT);
- RNA_def_property_ui_text(prop, "Draw Texture Paint UVs", "Draw overlay of texture paint uv layer");
+ RNA_def_property_ui_text(prop, "Display Texture Paint UVs", "Display overlay of texture paint uv layer");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
- prop = RNA_def_property(srna, "show_normalized_coords", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_COORDFLOATS);
- RNA_def_property_ui_text(prop, "Normalized Coordinates",
- "Display UV coordinates from 0.0 to 1.0 rather than in pixels");
+ prop = RNA_def_property(srna, "show_pixel_coords", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_COORDFLOATS);
+ RNA_def_property_ui_text(prop, "Pixel Coordinates",
+ "Display UV coordinates in pixels rather than from 0.0 to 1.0");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_faces", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAWFACES);
- RNA_def_property_ui_text(prop, "Draw Faces", "Draw faces over the image");
+ RNA_def_property_ui_text(prop, "Display Faces", "Display faces over the image");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
+ prop = RNA_def_property(srna, "show_edges", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAWEDGES);
+ RNA_def_property_ui_text(prop, "Display Edges", "Display edges in vertex select mode");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
/* todo: move edge and face drawing options here from G.f */
@@ -2099,13 +2251,6 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Live Unwrap",
"Continuously unwrap the selected UV island while transforming pinned vertices");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
-
- /* Other UV filtering */
- prop = RNA_def_property(srna, "other_uv_filter", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, other_uv_filter_items);
- RNA_def_property_ui_text(prop, "Other UV filter",
- "Filter applied on the other object's UV to limit displayed");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
}
static void rna_def_space_outliner(BlenderRNA *brna)
@@ -2114,23 +2259,24 @@ static void rna_def_space_outliner(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem display_mode_items[] = {
- {SO_ALL_SCENES, "ALL_SCENES", 0, "All Scenes", "Display data-blocks in all scenes"},
- {SO_CUR_SCENE, "CURRENT_SCENE", 0, "Current Scene", "Display data-blocks in current scene"},
- {SO_VISIBLE, "VISIBLE_LAYERS", 0, "Visible Layers", "Display data-blocks in visible layers"},
- {SO_SELECTED, "SELECTED", 0, "Selected", "Display data-blocks of selected, visible objects"},
- {SO_ACTIVE, "ACTIVE", 0, "Active", "Display data-blocks of active object"},
- {SO_SAME_TYPE, "SAME_TYPES", 0, "Same Types",
- "Display data-blocks of all objects of same type as selected object"},
- {SO_GROUPS, "GROUPS", 0, "Groups", "Display groups and their data-blocks"},
- {SO_SEQUENCE, "SEQUENCE", 0, "Sequence", "Display sequence data-blocks"},
- {SO_LIBRARIES, "LIBRARIES", 0, "Blender File", "Display data of current file and linked libraries"},
- {SO_DATABLOCKS, "DATABLOCKS", 0, "Data-Blocks", "Display all raw data-blocks"},
- {SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display user preference data"},
- {SO_ID_ORPHANS, "ORPHAN_DATA", 0, "Orphan Data",
+ {SO_SCENES, "SCENES", ICON_SCENE_DATA, "Scenes", "Display scenes and their view layers, collections and objects"},
+ {SO_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "Display collections and objects in the view layer"},
+ {SO_SEQUENCE, "SEQUENCE", ICON_SEQUENCE, "Sequence", "Display sequence data-blocks"},
+ {SO_LIBRARIES, "LIBRARIES", ICON_FILE_BLEND, "Blender File", "Display data of current file and linked libraries"},
+ {SO_DATA_API, "DATA_API", ICON_RNA, "Data API", "Display low level Blender data and its properties"},
+ {SO_ID_ORPHANS, "ORPHAN_DATA", ICON_ORPHAN_DATA, "Orphan Data",
"Display data-blocks which are unused and/or will be lost when the file is reloaded"},
{0, NULL, 0, NULL, NULL}
};
+ static const EnumPropertyItem filter_state_items[] = {
+ {SO_FILTER_OB_ALL, "ALL", 0, "All", "Show all objects in the view layer"},
+ {SO_FILTER_OB_VISIBLE, "VISIBLE", 0, "Visible", "Show visible objects"},
+ {SO_FILTER_OB_SELECTED, "SELECTED", 0, "Selected", "Show selected objects"},
+ {SO_FILTER_OB_ACTIVE, "ACTIVE", 0, "Active", "Show only the active object"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SpaceOutliner", "Space");
RNA_def_struct_sdna(srna, "SpaceOops");
RNA_def_struct_ui_text(srna, "Space Outliner", "Outliner space data");
@@ -2150,227 +2296,733 @@ static void rna_def_space_outliner(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_filter_case_sensitive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_CASE_SENSITIVE);
RNA_def_property_ui_text(prop, "Case Sensitive Matches Only", "Only use case sensitive matches of search string");
+ RNA_def_property_ui_icon(prop, ICON_SYNTAX_OFF, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "use_filter_complete", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_COMPLETE);
RNA_def_property_ui_text(prop, "Complete Matches Only", "Only use complete matches of search string");
+ RNA_def_property_ui_icon(prop, ICON_OUTLINER_DATA_FONT, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "use_sort_alpha", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_SKIP_SORT_ALPHA);
RNA_def_property_ui_text(prop, "Sort Alphabetically", "");
+ RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "show_restrict_columns", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_HIDE_RESTRICTCOLS);
RNA_def_property_ui_text(prop, "Show Restriction Columns", "Show column");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ /* Filters. */
+ prop = RNA_def_property(srna, "use_filter_object", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OBJECT);
+ RNA_def_property_ui_text(prop, "Filter Objects", "Show objects");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_content", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_CONTENT);
+ RNA_def_property_ui_text(prop, "Show Object Contents", "Show what is inside the objects elements");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_children", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_CHILDREN);
+ RNA_def_property_ui_text(prop, "Show Object Children", "Show children");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_collection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_COLLECTION);
+ RNA_def_property_ui_text(prop, "Show Collections", "Show collections");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ /* Filters object state. */
+ prop = RNA_def_property(srna, "filter_state", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "filter_state");
+ RNA_def_property_enum_items(prop, filter_state_items);
+ RNA_def_property_ui_text(prop, "Object State Filter", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ /* Filters object type. */
+ prop = RNA_def_property(srna, "use_filter_object_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_MESH);
+ RNA_def_property_ui_text(prop, "Show Meshes", "Show mesh objects");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_armature", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_ARMATURE);
+ RNA_def_property_ui_text(prop, "Show Armatures", "Show armature objects");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_empty", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_EMPTY);
+ RNA_def_property_ui_text(prop, "Show Empties", "Show empty objects");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_light", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_LAMP);
+ RNA_def_property_ui_text(prop, "Show Lights", "Show light objects");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_camera", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_CAMERA);
+ RNA_def_property_ui_text(prop, "Show Cameras", "Show camera objects");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_object_others", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_OTHERS);
+ RNA_def_property_ui_text(prop, "Show Other Objects", "Show curves, lattices, light probes, fonts, ...");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ /* Libraries filter. */
+ prop = RNA_def_property(srna, "use_filter_id_type", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_ID_TYPE);
+ RNA_def_property_ui_text(prop, "Filter By Type", "Show only data-blocks of one type");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "filter_id_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "filter_id_type");
+ RNA_def_property_enum_items(prop, rna_enum_id_type_items);
+ RNA_def_property_ui_text(prop, "Filter ID Type", "Data-block type to show");
}
-static void rna_def_background_image(BlenderRNA *brna)
+static void rna_def_space_view3d_shading(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- /* note: combinations work but don't flip so arnt that useful */
- static const EnumPropertyItem bgpic_axis_items[] = {
- {0, "", 0, N_("X Axis"), ""},
- {(1 << RV3D_VIEW_LEFT), "LEFT", 0, "Left", "Show background image while looking to the left"},
- {(1 << RV3D_VIEW_RIGHT), "RIGHT", 0, "Right", "Show background image while looking to the right"},
- /*{(1<<RV3D_VIEW_LEFT)|(1<<RV3D_VIEW_RIGHT), "LEFT_RIGHT", 0, "Left/Right", ""},*/
- {0, "", 0, N_("Y Axis"), ""},
- {(1 << RV3D_VIEW_BACK), "BACK", 0, "Back", "Show background image in back view"},
- {(1 << RV3D_VIEW_FRONT), "FRONT", 0, "Front", "Show background image in front view"},
- /*{(1<<RV3D_VIEW_BACK)|(1<<RV3D_VIEW_FRONT), "BACK_FRONT", 0, "Back/Front", ""},*/
- {0, "", 0, N_("Z Axis"), ""},
- {(1 << RV3D_VIEW_BOTTOM), "BOTTOM", 0, "Bottom", "Show background image in bottom view"},
- {(1 << RV3D_VIEW_TOP), "TOP", 0, "Top", "Show background image in top view"},
- /*{(1<<RV3D_VIEW_BOTTOM)|(1<<RV3D_VIEW_TOP), "BOTTOM_TOP", 0, "Top/Bottom", ""},*/
- {0, "", 0, N_("Other"), ""},
- {0, "ALL", 0, "All Views", "Show background image in all views"},
- {(1 << RV3D_VIEW_CAMERA), "CAMERA", 0, "Camera", "Show background image in camera view"},
+ static const EnumPropertyItem background_type_items[] = {
+ {V3D_SHADING_BACKGROUND_THEME, "THEME", 0, "Theme", "Use the theme for background color"},
+ {V3D_SHADING_BACKGROUND_WORLD, "WORLD", 0, "World", "Use the world for background color"},
+ {V3D_SHADING_BACKGROUND_VIEWPORT, "VIEWPORT", 0, "Viewport", "Use a custom color limited to this viewport only"},
{0, NULL, 0, NULL, NULL}
};
+ static const float default_background_color[] = {0.05f, 0.05f, 0.05f};
- static const EnumPropertyItem bgpic_source_items[] = {
- {V3D_BGPIC_IMAGE, "IMAGE", 0, "Image", ""},
- {V3D_BGPIC_MOVIE, "MOVIE_CLIP", 0, "Movie Clip", ""},
+ static const EnumPropertyItem cavity_type_items[] = {
+ {V3D_SHADING_CAVITY_SSAO, "WORLD", 0, "World", "Cavity shading computed in world space, useful for larger-scale occlusion"},
+ {V3D_SHADING_CAVITY_CURVATURE, "SCREEN", 0, "Screen", "Curvature-based shading, useful for making fine details more visible"},
+ {V3D_SHADING_CAVITY_BOTH, "BOTH", 0, "Both", "Use both effects simultaneously"},
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem bgpic_camera_frame_items[] = {
- {0, "STRETCH", 0, "Stretch", ""},
- {V3D_BGPIC_CAMERA_ASPECT, "FIT", 0, "Fit", ""},
- {V3D_BGPIC_CAMERA_ASPECT | V3D_BGPIC_CAMERA_CROP, "CROP", 0, "Crop", ""},
- {0, NULL, 0, NULL, NULL}
- };
- static const EnumPropertyItem bgpic_draw_depth_items[] = {
- {0, "BACK", 0, "Back", ""},
- {V3D_BGPIC_FOREGROUND, "FRONT", 0, "Front", ""},
- {0, NULL, 0, NULL, NULL}
- };
+ /* Note these settings are used for both 3D viewport and the OpenGL render
+ * engine in the scene, so can't assume to always be part of a screen. */
+ srna = RNA_def_struct(brna, "View3DShading", NULL);
+ RNA_def_struct_path_func(srna, "rna_View3DShading_path");
+ RNA_def_struct_ui_text(srna, "3D View Shading Settings", "Settings for shading in the 3D viewport");
- srna = RNA_def_struct(brna, "BackgroundImage", NULL);
- RNA_def_struct_sdna(srna, "BGpic");
- RNA_def_struct_ui_text(srna, "Background Image", "Image and settings for display in the 3D View background");
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_shading_type_items);
+ RNA_def_property_enum_funcs(prop, "rna_3DViewShading_type_get", "rna_3DViewShading_type_set",
+ "rna_3DViewShading_type_itemf");
+ RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_3DViewShading_type_update");
- prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "source");
- RNA_def_property_enum_items(prop, bgpic_source_items);
- RNA_def_property_ui_text(prop, "Background Source", "Data source used for background");
+ prop = RNA_def_property(srna, "light", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "light");
+ RNA_def_property_enum_items(prop, rna_enum_viewport_lighting_items);
+ RNA_def_property_enum_funcs(prop, "rna_View3DShading_light_get", "rna_View3DShading_light_set", NULL);
+ RNA_def_property_ui_text(prop, "Lighting", "Lighting Method for Solid/Texture Viewport Shading");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "ima");
- RNA_def_property_ui_text(prop, "Image", "Image displayed and edited in this space");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "show_object_outline", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_OBJECT_OUTLINE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Outline", "Show Object Outline");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "clip");
- RNA_def_property_ui_text(prop, "MovieClip", "Movie clip displayed and edited in this space");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "studio_light", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_studio_light_items);
+ RNA_def_property_enum_default(prop, 0);
+ RNA_def_property_enum_funcs(prop, "rna_View3DShading_studio_light_get", "rna_View3DShading_studio_light_set", "rna_View3DShading_studio_light_itemf");
+ RNA_def_property_ui_text(prop, "Studiolight", "Studio lighting setup");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "iuser");
- RNA_def_property_ui_text(prop, "Image User",
- "Parameters defining which layer, pass and frame of the image is displayed");
+ prop = RNA_def_property(srna, "use_world_space_lighting", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_WORLD_ORIENTATION);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "World Space Lighting", "Make the lighting fixed and not follow the camera");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "clip_user", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_struct_type(prop, "MovieClipUser");
- RNA_def_property_pointer_sdna(prop, NULL, "cuser");
- RNA_def_property_ui_text(prop, "Clip User", "Parameters defining which frame of the movie clip is displayed");
+ prop = RNA_def_property(srna, "show_cavity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_CAVITY);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Cavity", "Show Cavity");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "xof");
- RNA_def_property_ui_text(prop, "X Offset", "Offset image horizontally from the world origin");
+ prop = RNA_def_property(srna, "cavity_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, cavity_type_items);
+ RNA_def_property_ui_text(prop, "Cavity Type", "Way to draw the cavity shading");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "yof");
- RNA_def_property_ui_text(prop, "Y Offset", "Offset image vertically from the world origin");
+ prop = RNA_def_property(srna, "curvature_ridge_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "curvature_ridge_factor");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Curvature Ridge", "Factor for the curvature ridges");
+ RNA_def_property_range(prop, 0.0f, 2.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_float_funcs(prop, "rna_BackgroundImage_size_get", "rna_BackgroundImage_size_set", NULL);
- RNA_def_property_ui_text(prop, "Size", "Size of the background image (ortho view only)");
- RNA_def_property_range(prop, 0.0, FLT_MAX);
+ prop = RNA_def_property(srna, "curvature_valley_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "curvature_valley_factor");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Curvature Valley", "Factor for the curvature valleys");
+ RNA_def_property_range(prop, 0.0f, 2.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float_sdna(prop, NULL, "rotation");
- RNA_def_property_ui_text(prop, "Rotation", "Rotation for the background image (ortho view only)");
+ prop = RNA_def_property(srna, "cavity_ridge_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "cavity_ridge_factor");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Cavity Ridge", "Factor for the cavity ridges");
+ RNA_def_property_range(prop, 0.0f, 250.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "use_flip_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_FLIP_X);
- RNA_def_property_ui_text(prop, "Flip Horizontally", "Flip the background image horizontally");
+ prop = RNA_def_property(srna, "cavity_valley_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "cavity_valley_factor");
+ RNA_def_property_float_default(prop, 1.0);
+ RNA_def_property_ui_text(prop, "Cavity Valley", "Factor for the cavity valleys");
+ RNA_def_property_range(prop, 0.0f, 250.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "use_flip_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_FLIP_Y);
- RNA_def_property_ui_text(prop, "Flip Vertically", "Flip the background image vertically");
+ prop = RNA_def_property(srna, "selected_studio_light", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "StudioLight");
+ RNA_define_verify_sdna(0);
+ RNA_def_property_ui_text(prop, "Studio Light", "Selected StudioLight");
+ RNA_def_property_pointer_funcs(prop, "rna_View3DShading_selected_studio_light_get", NULL, NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_define_verify_sdna(1);
+
+ prop = RNA_def_property(srna, "studiolight_rotate_z", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "studiolight_rot_z");
+ RNA_def_property_float_default(prop, 0.0);
+ RNA_def_property_ui_text(prop, "Studiolight Rotation", "Rotation of the studiolight around the Z-Axis");
+ RNA_def_property_range(prop, -M_PI, M_PI);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "blend");
- RNA_def_property_float_funcs(prop, "rna_BackgroundImage_opacity_get", "rna_BackgroundImage_opacity_set", NULL);
- RNA_def_property_ui_text(prop, "Opacity", "Image opacity to blend the image against the background color");
- RNA_def_property_range(prop, 0.0, 1.0);
+ prop = RNA_def_property(srna, "color_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "color_type");
+ RNA_def_property_enum_items(prop, rna_enum_shading_color_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_View3DShading_color_type_itemf");
+ RNA_def_property_ui_text(prop, "Color", "Color Type");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "view_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "view");
- RNA_def_property_enum_items(prop, bgpic_axis_items);
- RNA_def_property_ui_text(prop, "Image Axis", "The axis to display the image on");
+ prop = RNA_def_property(srna, "single_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "single_color");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Color for single color mode");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_EXPANDED);
- RNA_def_property_ui_text(prop, "Show Expanded", "Show the expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ prop = RNA_def_property(srna, "background_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, background_type_items);
+ RNA_def_property_ui_text(prop, "Background", "Way to draw the background");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "use_camera_clip", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_CAMERACLIP);
- RNA_def_property_ui_text(prop, "Camera Clip", "Use movie clip from active scene camera");
+ prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_float_array_default(prop, default_background_color);
+ RNA_def_property_ui_text(prop, "Background Color", "Color for custom background color");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "show_background_image", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", V3D_BGPIC_DISABLED);
- RNA_def_property_ui_text(prop, "Show Background Image", "Show this image as background");
+ prop = RNA_def_property(srna, "show_shadows", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SHADOW);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Shadow", "Show Shadow");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "show_on_foreground", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_FOREGROUND);
- RNA_def_property_ui_text(prop, "Show On Foreground", "Show this image in front of objects in viewport");
+ prop = RNA_def_property(srna, "show_xray", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_XRAY);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Show X-Ray", "Show whole scene transparent");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- /* expose 1 flag as a enum of 2 items */
- prop = RNA_def_property(srna, "draw_depth", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, bgpic_draw_depth_items);
- RNA_def_property_ui_text(prop, "Depth", "Draw under or over everything");
+ prop = RNA_def_property(srna, "show_xray_wireframe", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_XRAY_BONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Show X-Ray", "Show whole scene transparent");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- /* expose 2 flags as a enum of 3 items */
- prop = RNA_def_property(srna, "frame_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, bgpic_camera_frame_items);
- RNA_def_property_ui_text(prop, "Frame Method", "How the image fits in the camera frame");
+ prop = RNA_def_property(srna, "xray_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "xray_alpha");
+ RNA_def_property_float_default(prop, 0.5);
+ RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "xray_alpha_wireframe", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "xray_alpha_wire");
+ RNA_def_property_float_default(prop, 0.5);
+ RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_scene_lights", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_LIGHTS);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Scene Lights", "Render lights and light probes of the scene");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_scene_world", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SCENE_WORLD);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Scene World", "Use scene world for lighting");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_specular_highlight", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SPECULAR_HIGHLIGHT);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Specular Highlights", "Render specular highlights");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "object_outline_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "object_outline_color");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Outline Color", "Color for object outline");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "shadow_intensity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "shadow_intensity");
+ RNA_def_property_float_default(prop, 0.5);
+ RNA_def_property_ui_text(prop, "Shadow Intensity", "Darkness of shadows");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "studiolight_background_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "studiolight_background");
+ RNA_def_property_float_default(prop, 0.0);
+ RNA_def_property_ui_text(prop, "Background", "Show the studiolight in the background");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 1.0f, 1, 3);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
}
-static void rna_def_backgroundImages(BlenderRNA *brna, PropertyRNA *cprop)
+static void rna_def_space_view3d_overlay(BlenderRNA *brna)
{
StructRNA *srna;
- FunctionRNA *func;
- PropertyRNA *parm;
+ PropertyRNA *prop;
- RNA_def_property_srna(cprop, "BackgroundImages");
- srna = RNA_def_struct(brna, "BackgroundImages", NULL);
+ srna = RNA_def_struct(brna, "View3DOverlay", NULL);
RNA_def_struct_sdna(srna, "View3D");
- RNA_def_struct_ui_text(srna, "Background Images", "Collection of background images");
+ RNA_def_struct_nested(brna, srna, "SpaceView3D");
+ RNA_def_struct_path_func(srna, "rna_View3DOverlay_path");
+ RNA_def_struct_ui_text(srna, "3D View Overlay Settings", "Settings for display of overlays in the 3D viewport");
- func = RNA_def_function(srna, "new", "rna_BackgroundImage_new");
- RNA_def_function_ui_description(func, "Add new background image");
- parm = RNA_def_pointer(func, "image", "BackgroundImage", "", "Image displayed as viewport background");
- RNA_def_function_return(func, parm);
+ prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag2", V3D_RENDER_OVERRIDE);
+ RNA_def_property_ui_text(prop, "Show Overlays", "Display overlays like gizmos and outlines");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
- func = RNA_def_function(srna, "remove", "rna_BackgroundImage_remove");
- RNA_def_function_ui_description(func, "Remove background image");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "image", "BackgroundImage", "", "Image displayed as viewport background");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
- RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+ prop = RNA_def_property(srna, "show_floor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_FLOOR);
+ RNA_def_property_ui_text(prop, "Display Grid Floor", "Show the ground plane grid in perspective view");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- func = RNA_def_function(srna, "clear", "rna_BackgroundImage_clear");
- RNA_def_function_ui_description(func, "Remove all background images");
-}
+ prop = RNA_def_property(srna, "show_axis_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_X);
+ RNA_def_property_ui_text(prop, "Display X Axis", "Show the X axis line in perspective view");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_axis_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_Y);
+ RNA_def_property_ui_text(prop, "Display Y Axis", "Show the Y axis line in perspective view");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_axis_z", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_Z);
+ RNA_def_property_ui_text(prop, "Display Z Axis", "Show the Z axis line in perspective view");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "grid_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "grid");
+ RNA_def_property_ui_text(prop, "Grid Scale", "Distance between 3D View grid lines");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 0.1f, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "grid_lines", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "gridlines");
+ RNA_def_property_ui_text(prop, "Grid Lines", "Number of grid lines to display in perspective view");
+ RNA_def_property_range(prop, 0, 1024);
+ RNA_def_property_int_default(prop, 16);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "grid_subdivisions", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "gridsubdiv");
+ RNA_def_property_ui_text(prop, "Grid Subdivisions", "Number of subdivisions between grid lines");
+ RNA_def_property_range(prop, 1, 1024);
+ RNA_def_property_int_default(prop, 10);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "grid_scale_unit", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_View3DOverlay_GridScaleUnit_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Grid Scale Unit", "Grid cell size scaled by scene unit system settings");
+
+ prop = RNA_def_property(srna, "show_outline_selected", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SELECT_OUTLINE);
+ RNA_def_property_ui_text(prop, "Outline Selected",
+ "Show an outline highlight around selected objects in non-wireframe views");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_object_origins", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_OBJECT_ORIGINS);
+ RNA_def_property_ui_text(prop, "Object Origins", "Show object center dots");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_object_origins_all", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_DRAW_CENTERS);
+ RNA_def_property_ui_text(prop, "All Object Origins",
+ "Show the object origin center dot for all (selected and unselected) objects");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_relationship_lines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", V3D_HIDE_HELPLINES);
+ RNA_def_property_ui_text(prop, "Relationship Lines",
+ "Show dashed lines indicating parent or constraint relationships");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* TODO: this should become a per object setting? */
+ prop = RNA_def_property(srna, "show_backface_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_BACKFACE_CULLING);
+ RNA_def_property_ui_text(prop, "Backface Culling", "Use back face culling to hide the back side of faces");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_cursor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_CURSOR);
+ RNA_def_property_ui_text(prop, "Show 3D Cursor", "Display 3D Cursor Overlay");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_text", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_TEXT);
+ RNA_def_property_ui_text(prop, "Show Text", "Display overlay text");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_extras", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_OBJECT_XTRAS);
+ RNA_def_property_ui_text(prop, "Extras", "Object details, including empty wire, cameras and other visual guides");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_bones", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_BONES);
+ RNA_def_property_ui_text(prop, "Show Bones", "Display bones");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_face_orientation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_FACE_ORIENTATION);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Face Orientation", "Show the Face Orientation Overlay");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_xray_bone", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_BONE_SELECT);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Show Bone X-Ray", "Show the bone selection overlay");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "xray_alpha_bone", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.xray_alpha_bone");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Opacity", "Opacity to use for bone selection");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "show_motion_paths", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_MOTION_PATHS);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Motion Paths", "Show the Motion Paths Overlay");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_onion_skins", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_ONION_SKINS);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Onion Skins", "Show the Onion Skinning Overlay");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_look_dev", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_LOOK_DEV);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Look Dev Preview", "Show look development balls and palette");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_wireframes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_WIREFRAMES);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Wireframe", "Show face edges wires");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_paint_wire", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.paint_flag", V3D_OVERLAY_PAINT_WIRE);
+ RNA_def_property_ui_text(prop, "Show Wire", "Use wireframe display in painting modes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_wpaint_contours", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.wpaint_flag", V3D_OVERLAY_WPAINT_CONTOURS);
+ RNA_def_property_ui_text(prop, "Show Weight Contours", "Show contour lines formed by points with the same interpolated weight");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_weight", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_WEIGHT);
+ RNA_def_property_ui_text(prop, "Show Weights", "Display weights in editmode");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_occlude_wire", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_OCCLUDE_WIRE);
+ RNA_def_property_ui_text(prop, "Hidden Wire", "Use hidden wireframe display");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_face_normals", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACE_NORMALS);
+ RNA_def_property_ui_text(prop, "Display Normals", "Display face normals as lines");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_vertex_normals", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_VERT_NORMALS);
+ RNA_def_property_ui_text(prop, "Display Vertex Normals", "Display vertex normals as lines");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_split_normals", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_LOOP_NORMALS);
+ RNA_def_property_ui_text(prop, "Display Split Normals", "Display vertex-per-face normals as lines");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_edges", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_EDGES);
+ RNA_def_property_ui_text(prop, "Draw Edges",
+ "Display selected edges using highlights in the 3D view and UV editor");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_faces", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACES);
+ RNA_def_property_ui_text(prop, "Draw Faces", "Display all faces as shades in the 3D view and UV editor");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_face_center", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACE_DOT);
+ RNA_def_property_ui_text(prop, "Draw Face Center", "Display face center");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_edge_crease", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_CREASES);
+ RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for Subdivision Surface modifier");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_edge_bevel_weight", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_BWEIGHTS);
+ RNA_def_property_ui_text(prop, "Draw Bevel Weights", "Display weights created for the Bevel modifier");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_edge_seams", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_SEAMS);
+ RNA_def_property_ui_text(prop, "Draw Seams", "Display UV unwrapping seams");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_edge_sharp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_SHARP);
+ RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the Edge Split modifier");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FREESTYLE_EDGE);
+ RNA_def_property_ui_text(prop, "Draw Freestyle Edge Marks", "Display Freestyle edge marks, used with the Freestyle renderer");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_freestyle_face_marks", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FREESTYLE_FACE);
+ RNA_def_property_ui_text(prop, "Draw Freestyle Face Marks", "Display Freestyle face marks, used with the Freestyle renderer");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_statvis", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_STATVIS);
+ RNA_def_property_ui_text(prop, "Stat Vis", "Display statistical information about the mesh");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_extra_edge_length", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_EDGE_LEN);
+ RNA_def_property_ui_text(prop, "Edge Length",
+ "Display selected edge lengths, using global values when set in the transform panel");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_extra_edge_angle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_EDGE_ANG);
+ RNA_def_property_ui_text(prop, "Edge Angle",
+ "Display selected edge angle, using global values when set in the transform panel");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_extra_face_angle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACE_ANG);
+ RNA_def_property_ui_text(prop, "Face Angles",
+ "Display the angles in the selected edges, "
+ "using global values when set in the transform panel");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_extra_face_area", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACE_AREA);
+ RNA_def_property_ui_text(prop, "Face Area",
+ "Display the area of selected faces, "
+ "using global values when set in the transform panel");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_extra_indices", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_INDICES);
+ RNA_def_property_ui_text(prop, "Indices", "Display the index numbers of selected vertices, edges, and faces");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_curve_handles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_CU_HANDLES);
+ RNA_def_property_ui_text(prop, "Draw Handles", "Display Bezier handles in editmode");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_curve_normals", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_CU_NORMALS);
+ RNA_def_property_ui_text(prop, "Draw Normals", "Display 3D curve normals in editmode");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "normals_length", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.normals_length");
+ RNA_def_property_ui_text(prop, "Normal Size", "Display size for normals in the 3D view");
+ RNA_def_property_range(prop, 0.00001, 1000.0);
+ RNA_def_property_ui_range(prop, 0.01, 10.0, 10.0, 2);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "backwire_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.backwire_opacity");
+ RNA_def_property_ui_text(prop, "Backwire Opacity", "Opacity when rendering transparent wires");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_transparent_bones", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.arm_flag", V3D_OVERLAY_ARM_TRANSP_BONES);
+ RNA_def_property_ui_text(prop, "Transparent Bones", "Display bones as transparent");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "texture_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.texture_paint_mode_opacity");
+ RNA_def_property_float_default(prop, 0.8f);
+ RNA_def_property_ui_text(prop, "Texture Opacity", "Opacity of the texture paint mode overlay");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "vertex_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.vertex_paint_mode_opacity");
+ RNA_def_property_float_default(prop, 0.8f);
+ RNA_def_property_ui_text(prop, "Vertex Paint Opacity", "Opacity of the vertex paint mode overlay");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "weight_paint_mode_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.weight_paint_mode_opacity");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Weight Paint Opacity", "Opacity of the weight paint mode overlay");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* grease pencil paper settings */
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_ANNOTATION);
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "use_gpencil_paper", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_PAPER);
+ RNA_def_property_ui_text(prop, "Use Paper",
+ "Cover all viewport with a full color layer to improve visibility while drawing over complex scenes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_gpencil_grid", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_GRID);
+ RNA_def_property_ui_text(prop, "Use Grid",
+ "Display a grid over grease pencil paper");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_gpencil_fade_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_FADE_NOACTIVE_LAYERS);
+ RNA_def_property_ui_text(prop, "Fade Layers",
+ "Toggle fading of Grease Pencil layers except the active one");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "gpencil_grid_opacity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_opacity");
+ RNA_def_property_range(prop, 0.1f, 1.0f);
+ RNA_def_property_float_default(prop, 0.9f);
+ RNA_def_property_ui_text(prop, "Opacity", "Canvas grid opacity");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* Paper opacity factor */
+ prop = RNA_def_property(srna, "gpencil_paper_opacity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_paper_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Opacity", "Paper opacity");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ /* Paper opacity factor */
+ prop = RNA_def_property(srna, "gpencil_fade_layer", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_fade_layer");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Opacity",
+ "Fade layer opacity for Grease Pencil layers except the active one");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ /* show edit lines */
+ prop = RNA_def_property(srna, "use_gpencil_edit_lines", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_EDIT_LINES);
+ RNA_def_property_ui_text(prop, "Show Edit Lines", "Show edit lines when editing strokes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_gpencil_multiedit_line_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_MULTIEDIT_LINES);
+ RNA_def_property_ui_text(prop, "Lines Only", "Only show edit lines for additional frames");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ /* main grease pencil onion switch */
+ prop = RNA_def_property(srna, "use_gpencil_onion_skin", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_ONION_SKIN);
+ RNA_def_property_ui_text(prop, "Onion Skins", "Show ghosts of the keyframes before and after the current frame");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ /* vertex opacity */
+ prop = RNA_def_property(srna, "vertex_opacity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vertex_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Vertex Opacity", "Opacity for edit vertices");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
+
+}
static void rna_def_space_view3d(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem manipulators_items[] = {
- {V3D_MANIP_TRANSLATE, "TRANSLATE", ICON_MAN_TRANS, "Translate",
- "Use the manipulator for movement transformations"},
- {V3D_MANIP_ROTATE, "ROTATE", ICON_MAN_ROT, "Rotate",
- "Use the manipulator for rotation transformations"},
- {V3D_MANIP_SCALE, "SCALE", ICON_MAN_SCALE, "Scale",
- "Use the manipulator for scale transformations"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem rv3d_persp_items[] = {
{RV3D_PERSP, "PERSP", 0, "Perspective", ""},
{RV3D_ORTHO, "ORTHO", 0, "Orthographic", ""},
@@ -2389,34 +3041,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem view3d_matcap_items[] = {
- {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""},
- {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""},
- {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""},
- {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""},
- {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""},
- {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""},
- {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""},
- {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""},
- {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""},
- {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""},
- {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""},
- {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""},
- {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""},
- {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""},
- {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""},
- {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""},
- {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""},
- {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""},
- {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""},
- {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""},
- {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""},
- {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""},
- {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""},
- {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "SpaceView3D", "Space");
RNA_def_struct_sdna(srna, "View3D");
RNA_def_struct_ui_text(srna, "3D View Space", "3D View space data");
@@ -2476,27 +3100,11 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Lock to Cursor", "3D View center is locked to the cursor's position");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "viewport_shade", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "drawtype");
- RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
- RNA_def_property_enum_funcs(prop, "rna_SpaceView3D_viewport_shade_get", "rna_SpaceView3D_viewport_shade_set",
- "rna_SpaceView3D_viewport_shade_itemf");
- RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_viewport_shade_update");
-
prop = RNA_def_property(srna, "local_view", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "localvd");
RNA_def_property_ui_text(prop, "Local View",
"Display an isolated sub-set of objects, apart from the scene visibility");
- prop = RNA_def_property(srna, "cursor_location", PROP_FLOAT, PROP_XYZ_LENGTH);
- RNA_def_property_array(prop, 3);
- RNA_def_property_float_funcs(prop, "rna_View3D_CursorLocation_get", "rna_View3D_CursorLocation_set", NULL);
- RNA_def_property_ui_text(prop, "3D Cursor Location",
- "3D cursor location for this view (dependent on local view setting)");
- RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, RNA_TRANSLATION_PREC_DEFAULT);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
prop = RNA_def_property(srna, "lens", PROP_FLOAT, PROP_UNIT_CAMERA);
RNA_def_property_float_sdna(prop, NULL, "lens");
RNA_def_property_ui_text(prop, "Lens", "Viewport lens angle");
@@ -2519,168 +3127,36 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "grid_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "grid");
- RNA_def_property_ui_text(prop, "Grid Scale", "Distance between 3D View grid lines");
- RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 0.1f, 3);
- RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "grid_lines", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "gridlines");
- RNA_def_property_ui_text(prop, "Grid Lines", "Number of grid lines to display in perspective view");
- RNA_def_property_range(prop, 0, 1024);
- RNA_def_property_int_default(prop, 16);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "grid_subdivisions", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "gridsubdiv");
- RNA_def_property_ui_text(prop, "Grid Subdivisions", "Number of subdivisions between grid lines");
- RNA_def_property_range(prop, 1, 1024);
- RNA_def_property_int_default(prop, 10);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "grid_scale_unit", PROP_FLOAT, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_float_funcs(prop, "rna_View3D_GridScaleUnit_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Grid Scale Unit", "Grid cell size scaled by scene unit system settings");
-
- prop = RNA_def_property(srna, "show_floor", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_FLOOR);
- RNA_def_property_ui_text(prop, "Display Grid Floor", "Show the ground plane grid in perspective view");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_axis_x", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_X);
- RNA_def_property_ui_text(prop, "Display X Axis", "Show the X axis line in perspective view");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_axis_y", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_Y);
- RNA_def_property_ui_text(prop, "Display Y Axis", "Show the Y axis line in perspective view");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_axis_z", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_Z);
- RNA_def_property_ui_text(prop, "Display Z Axis", "Show the Z axis line in perspective view");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_outline_selected", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SELECT_OUTLINE);
- RNA_def_property_ui_text(prop, "Outline Selected",
- "Show an outline highlight around selected objects in non-wireframe views");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_all_objects_origin", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_DRAW_CENTERS);
- RNA_def_property_ui_text(prop, "All Object Origins",
- "Show the object origin center dot for all (selected and unselected) objects");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_relationship_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", V3D_HIDE_HELPLINES);
- RNA_def_property_ui_text(prop, "Relationship Lines",
- "Show dashed lines indicating parent or constraint relationships");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
prop = RNA_def_property(srna, "show_textured_solid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SOLID_TEX);
RNA_def_property_ui_text(prop, "Textured Solid", "Display face-assigned textures in solid view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "show_backface_culling", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_BACKFACE_CULLING);
- RNA_def_property_ui_text(prop, "Backface Culling", "Use back face culling to hide the back side of faces");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_textured_shadeless", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHADELESS_TEX);
- RNA_def_property_ui_text(prop, "Shadeless", "Show shadeless texture without lighting in textured draw mode");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_occlude_wire", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_OCCLUDE_WIRE);
- RNA_def_property_ui_text(prop, "Hidden Wire", "Use hidden wireframe display");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
prop = RNA_def_property(srna, "lock_camera", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_LOCK_CAMERA);
RNA_def_property_ui_text(prop, "Lock Camera to View", "Enable view navigation within the camera view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "show_only_render", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_RENDER_OVERRIDE);
- RNA_def_property_ui_text(prop, "Only Render", "Display only objects which will be rendered");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "show_world", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_WORLD);
- RNA_def_property_ui_text(prop, "World Background", "Display world colors in the background");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "use_occlude_geometry", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ZBUF_SELECT);
- RNA_def_property_ui_text(prop, "Occlude Geometry", "Limit selection to visible (clipped with depth buffer)");
- RNA_def_property_ui_icon(prop, ICON_ORTHO, 0);
+ prop = RNA_def_property(srna, "show_gizmo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", V3D_GIZMO_HIDE);
+ RNA_def_property_ui_text(prop, "Show Gizmo", "Show gizmos of all types");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "background_images", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "bgpicbase", NULL);
- RNA_def_property_struct_type(prop, "BackgroundImage");
- RNA_def_property_ui_text(prop, "Background Images", "List of background images");
+ prop = RNA_def_property(srna, "show_gizmo_navigate", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", V3D_GIZMO_HIDE_NAVIGATE);
+ RNA_def_property_ui_text(prop, "Navigate Gizmo", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- rna_def_backgroundImages(brna, prop);
- prop = RNA_def_property(srna, "show_background_images", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_DISPBGPICS);
- RNA_def_property_ui_text(prop, "Display Background Images",
- "Display reference images behind objects in the 3D View");
+ prop = RNA_def_property(srna, "show_gizmo_context", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", V3D_GIZMO_HIDE_CONTEXT);
+ RNA_def_property_ui_text(prop, "Context Gizmo", "Context sensitive gizmos for the active item");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "around");
- RNA_def_property_enum_items(prop, pivot_items_full);
- RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_pivot_update");
-
- prop = RNA_def_property(srna, "use_pivot_point_align", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ALIGN);
- RNA_def_property_ui_text(prop, "Align", "Manipulate center points (object, pose and weight paint mode only)");
- RNA_def_property_ui_icon(prop, ICON_ALIGN, 0);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_pivot_update");
-
- prop = RNA_def_property(srna, "show_manipulator", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "twflag", V3D_USE_MANIPULATOR);
- RNA_def_property_ui_text(prop, "Manipulator", "Use a 3D manipulator widget for controlling transforms");
- RNA_def_property_ui_icon(prop, ICON_MANIPUL, 0);
+ prop = RNA_def_property(srna, "show_gizmo_tool", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "gizmo_flag", V3D_GIZMO_HIDE_TOOL);
+ RNA_def_property_ui_text(prop, "Tool Gizmo", "Active tool gizmo");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "transform_manipulators", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "twtype");
- RNA_def_property_enum_items(prop, manipulators_items);
- RNA_def_property_flag(prop, PROP_ENUM_FLAG);
- RNA_def_property_ui_text(prop, "Transform Manipulators", "Transformation manipulators");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "transform_orientation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "twmode");
- RNA_def_property_enum_items(prop, transform_orientation_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_TransformOrientation_itemf");
- RNA_def_property_ui_text(prop, "Transform Orientation", "Transformation orientation");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- prop = RNA_def_property(srna, "current_orientation", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "TransformOrientation");
- RNA_def_property_pointer_funcs(prop, "rna_CurrentOrientation_get", NULL, NULL, NULL);
- RNA_def_property_ui_text(prop, "Current Transform Orientation", "Current transformation orientation");
-
prop = RNA_def_property(srna, "lock_camera_and_layers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scenelock", 1);
RNA_def_property_boolean_funcs(prop, NULL, "rna_SpaceView3D_lock_camera_and_layers_set");
@@ -2689,30 +3165,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_LOCKVIEW_OFF, 1);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_SpaceView3D_layer_set");
- RNA_def_property_ui_text(prop, "Visible Layers", "Layers visible in this 3D View");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_layer_update");
-
- prop = RNA_def_property(srna, "active_layer", PROP_INT, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
- RNA_def_property_int_funcs(prop, "rna_SpaceView3D_active_layer_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Active Layer", "Active 3D view layer index");
-
- prop = RNA_def_property(srna, "layers_local_view", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay", 0x01000000);
- RNA_def_property_array(prop, 8);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Local View Layers", "Local view layers visible in this 3D View");
-
- prop = RNA_def_property(srna, "layers_used", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "lay_used", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Used Layers", "Layers that contain something");
-
prop = RNA_def_property(srna, "region_3d", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "RegionView3D");
RNA_def_property_pointer_funcs(prop, "rna_SpaceView3D_region_3d_get", NULL, NULL, NULL);
@@ -2731,14 +3183,14 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Reconstruction", "Display reconstruction data from active movie clip");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "tracks_draw_size", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "tracks_display_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 5, 1, 3);
RNA_def_property_float_sdna(prop, NULL, "bundle_size");
RNA_def_property_ui_text(prop, "Tracks Size", "Display size of tracks from reconstructed data");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "tracks_draw_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "tracks_display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "bundle_drawtype");
RNA_def_property_enum_items(prop, bundle_drawtype_items);
RNA_def_property_ui_text(prop, "Tracks Display Type", "Viewport display style for tracks");
@@ -2754,17 +3206,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show 3D Marker Names", "Show names for reconstructed tracks objects");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "use_matcap", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SOLID_MATCAP);
- RNA_def_property_ui_text(prop, "Matcap", "Active Objects draw images mapped on normals, enhancing Solid Draw Mode");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_matcap_enable");
-
- prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "matcap_icon");
- RNA_def_property_enum_items(prop, view3d_matcap_items);
- RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture, active objects only");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_matcap_update");
-
prop = RNA_def_property(srna, "fx_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -2809,6 +3250,77 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Volume Alpha", "Opacity (alpha) of the cameras' frustum volume");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ {
+ struct {
+ const char *name;
+ int type_mask;
+ const char *identifier[2];
+ } info[] = {
+ {"Mesh", (1 << OB_MESH),
+ {"show_object_viewport_mesh", "show_object_select_mesh"}},
+ {"Curve", (1 << OB_CURVE),
+ {"show_object_viewport_curve", "show_object_select_curve"}},
+ {"Surface", (1 << OB_SURF),
+ {"show_object_viewport_surf", "show_object_select_surf"}},
+ {"Meta", (1 << OB_MBALL),
+ {"show_object_viewport_meta", "show_object_select_meta"}},
+ {"Font", (1 << OB_FONT),
+ {"show_object_viewport_font", "show_object_select_font"}},
+ {"Armature", (1 << OB_ARMATURE),
+ {"show_object_viewport_armature", "show_object_select_armature"}},
+ {"Lattice", (1 << OB_LATTICE),
+ {"show_object_viewport_lattice", "show_object_select_lattice"}},
+ {"Empty", (1 << OB_EMPTY),
+ {"show_object_viewport_empty", "show_object_select_empty"}},
+ {"Grease Pencil", (1 << OB_GPENCIL),
+ {"show_object_viewport_grease_pencil", "show_object_select_grease_pencil"}},
+ {"Camera", (1 << OB_CAMERA),
+ {"show_object_viewport_camera", "show_object_select_camera"}},
+ {"Light", (1 << OB_LAMP),
+ {"show_object_viewport_light", "show_object_select_light"}},
+ {"Speaker", (1 << OB_SPEAKER),
+ {"show_object_viewport_speaker", "show_object_select_speaker"}},
+ {"Light Probe", (1 << OB_LIGHTPROBE),
+ {"show_object_viewport_light_probe", "show_object_select_light_probe"}},
+ };
+
+ const char *view_mask_member[2] = {
+ "object_type_exclude_viewport",
+ "object_type_exclude_select",
+ };
+ for (int mask_index = 0; mask_index < 2; mask_index++) {
+ for (int type_index = 0; type_index < ARRAY_SIZE(info); type_index++) {
+ prop = RNA_def_property(srna, info[type_index].identifier[mask_index], PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(
+ prop, NULL, view_mask_member[mask_index], info[type_index].type_mask);
+ RNA_def_property_ui_text(prop, info[type_index].name, "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ }
+ }
+
+ /* Heper for drawing the icon. */
+ prop = RNA_def_property(srna, "icon_from_show_object_viewport", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_SpaceView3D_icon_from_show_object_viewport_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Visibility Iconm", "");
+ }
+
+ /* Nested Structs */
+ prop = RNA_def_property(srna, "shading", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "View3DShading");
+ RNA_def_property_ui_text(prop, "Shading Settings", "Settings for shading in the 3D viewport");
+
+ prop = RNA_def_property(srna, "overlay", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "View3DOverlay");
+ RNA_def_property_pointer_funcs(prop, "rna_SpaceView3D_overlay_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Overlay Settings", "Settings for display of overlays in the 3D viewport");
+
+ rna_def_space_view3d_shading(brna);
+ rna_def_space_view3d_overlay(brna);
+
/* *** Animated *** */
RNA_define_animate_sdna(true);
/* region */
@@ -2922,12 +3434,6 @@ static void rna_def_space_buttons(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem align_items[] = {
- {BUT_HORIZONTAL, "HORIZONTAL", 0, "Horizontal", ""},
- {BUT_VERTICAL, "VERTICAL", 0, "Vertical", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "SpaceProperties", "Space");
RNA_def_struct_sdna(srna, "SpaceButs");
RNA_def_struct_ui_text(srna, "Properties Space", "Properties space data");
@@ -2936,28 +3442,9 @@ static void rna_def_space_buttons(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "mainb");
RNA_def_property_enum_items(prop, buttons_context_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_SpaceProperties_context_set", "rna_SpaceProperties_context_itemf");
- RNA_def_property_ui_text(prop, "Context", "Type of active data to display and edit");
+ RNA_def_property_ui_text(prop, "Context", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_context_update");
- prop = RNA_def_property(srna, "align", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "align");
- RNA_def_property_enum_items(prop, align_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_SpaceProperties_align_set", NULL);
- RNA_def_property_ui_text(prop, "Align", "Arrangement of the panels");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
-
- prop = RNA_def_property(srna, "texture_context", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, buttons_texture_context_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_SpaceProperties_texture_context_set",
- "rna_SpaceProperties_texture_context_itemf");
- RNA_def_property_ui_text(prop, "Texture Context", "Type of texture data to display and edit");
- RNA_def_property_update(prop, NC_TEXTURE, NULL);
-
- prop = RNA_def_property(srna, "use_limited_texture_context", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SB_TEX_USER_LIMITED);
- RNA_def_property_ui_text(prop, "Limited Texture Context",
- "Use the limited version of texture user (for 'old shading' mode)");
-
/* pinned data */
prop = RNA_def_property(srna, "pin_id", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "pinid");
@@ -2975,13 +3462,6 @@ static void rna_def_space_buttons(BlenderRNA *brna)
static void rna_def_space_image(BlenderRNA *brna)
{
- static const EnumPropertyItem image_space_mode_items[] = {
- {SI_MODE_VIEW, "VIEW", ICON_FILE_IMAGE, "View", "View the image and UV edit in mesh editmode"},
- {SI_MODE_PAINT, "PAINT", ICON_TPAINT_HLT, "Paint", "2D image painting mode"},
- {SI_MODE_MASK, "MASK", ICON_MOD_MASK, "Mask", "Mask editing"},
- {0, NULL, 0, NULL, NULL}
- };
-
StructRNA *srna;
PropertyRNA *prop;
@@ -3030,20 +3510,20 @@ static void rna_def_space_image(BlenderRNA *brna)
/* image draw */
prop = RNA_def_property(srna, "show_repeat", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_TILE);
- RNA_def_property_ui_text(prop, "Draw Repeated", "Draw the image repeated outside of the main view");
+ RNA_def_property_ui_text(prop, "Display Repeated", "Display the image repeated outside of the main view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
- prop = RNA_def_property(srna, "draw_channels", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_channels", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, draw_channels_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceImageEditor_draw_channels_itemf");
- RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the image to draw");
+ RNA_def_property_enum_items(prop, display_channels_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceImageEditor_display_channels_itemf");
+ RNA_def_property_ui_text(prop, "Display Channels", "Channels of the image to draw");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_stereo_3d", PROP_BOOLEAN, PROP_NONE);
@@ -3062,7 +3542,7 @@ static void rna_def_space_image(BlenderRNA *brna)
/* mode */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, image_space_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_image_mode_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_SpaceImageEditor_mode_update");
@@ -3076,7 +3556,7 @@ static void rna_def_space_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "around");
- RNA_def_property_enum_items(prop, pivot_items_full);
+ RNA_def_property_enum_items(prop, rna_enum_transform_pivot_items_full);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceImageEditor_pivot_itemf");
RNA_def_property_ui_text(prop, "Pivot", "Rotation/Scaling Pivot");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
@@ -3085,6 +3565,7 @@ static void rna_def_space_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
@@ -3130,8 +3611,8 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
static const EnumPropertyItem view_type_items[] = {
{SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
- {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Image Preview", ""},
- {SEQ_VIEW_SEQUENCE_PREVIEW, "SEQUENCER_PREVIEW", ICON_SEQ_SPLITVIEW, "Sequencer and Image Preview", ""},
+ {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Preview", ""},
+ {SEQ_VIEW_SEQUENCE_PREVIEW, "SEQUENCER_PREVIEW", ICON_SEQ_SPLITVIEW, "Sequencer/Preview", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3163,12 +3644,12 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
static const EnumPropertyItem preview_channels_items[] = {
{SEQ_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha",
- "Draw image with RGB colors and alpha transparency"},
- {0, "COLOR", ICON_IMAGE_RGB, "Color", "Draw image with RGB colors"},
+ "Display image with RGB colors and alpha transparency"},
+ {0, "COLOR", ICON_IMAGE_RGB, "Color", "Display image with RGB colors"},
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem waveform_type_draw_items[] = {
+ static const EnumPropertyItem waveform_type_display_items[] = {
{SEQ_NO_WAVEFORMS, "NO_WAVEFORMS", 0, "Waveforms Off",
"No waveforms drawn for any sound strips"},
{SEQ_ALL_WAVEFORMS, "ALL_WAVEFORMS", 0, "Waveforms On",
@@ -3205,7 +3686,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_frames", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_DRAWFRAMES);
- RNA_def_property_ui_text(prop, "Draw Frames", "Draw frames rather than seconds");
+ RNA_def_property_ui_text(prop, "Display Frames", "Display frames rather than seconds");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
prop = RNA_def_property(srna, "use_marker_sync", PROP_BOOLEAN, PROP_NONE);
@@ -3238,10 +3719,10 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
prop = RNA_def_property(srna, "display_channel", PROP_INT, PROP_NONE);
@@ -3254,16 +3735,16 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
prop = RNA_def_property(srna, "preview_channels", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, preview_channels_items);
- RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the preview to draw");
+ RNA_def_property_ui_text(prop, "Display Channels", "Channels of the preview to draw");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
- prop = RNA_def_property(srna, "waveform_draw_type", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "waveform_display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, waveform_type_draw_items);
- RNA_def_property_ui_text(prop, "Waveform Drawing", "How Waveforms are drawn");
+ RNA_def_property_enum_items(prop, waveform_type_display_items);
+ RNA_def_property_ui_text(prop, "Waveform Displaying", "How Waveforms are drawn");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
- prop = RNA_def_property(srna, "draw_overexposed", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "show_overexposed", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "zebra");
RNA_def_property_ui_text(prop, "Show Overexposed", "Show overexposed areas with zebra stripes");
RNA_def_property_range(prop, 0, 110);
@@ -3272,16 +3753,17 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
prop = RNA_def_property(srna, "proxy_render_size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "render_size");
RNA_def_property_enum_items(prop, proxy_render_size_items);
- RNA_def_property_ui_text(prop, "Proxy render size",
- "Draw preview using full resolution or different proxy resolutions");
+ RNA_def_property_ui_text(prop, "Proxy Render Size",
+ "Display preview using full resolution or different proxy resolutions");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
/* grease pencil */
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space");
+ RNA_def_property_ui_text(prop, "Grease Pencil", "Grease Pencil data for this Preview region");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
prop = RNA_def_property(srna, "overlay_type", PROP_ENUM, PROP_NONE);
@@ -3322,19 +3804,19 @@ static void rna_def_space_text(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "wordwrap", 0);
RNA_def_property_boolean_funcs(prop, NULL, "rna_SpaceTextEditor_word_wrap_set");
RNA_def_property_ui_text(prop, "Word Wrap", "Wrap words if there is not enough horizontal space");
- RNA_def_property_ui_icon(prop, ICON_WORDWRAP_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_WORDWRAP_ON, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "show_line_numbers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "showlinenrs", 0);
RNA_def_property_ui_text(prop, "Line Numbers", "Show line numbers next to the text");
- RNA_def_property_ui_icon(prop, ICON_LINENUMBERS_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_LINENUMBERS_ON, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "show_syntax_highlight", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "showsyntax", 0);
RNA_def_property_ui_text(prop, "Syntax Highlight", "Syntax highlight for scripting");
- RNA_def_property_ui_icon(prop, ICON_SYNTAX_OFF, 1);
+ RNA_def_property_ui_icon(prop, ICON_SYNTAX_ON, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "show_line_highlight", PROP_BOOLEAN, PROP_NONE);
@@ -3421,18 +3903,6 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- /* XXX: action-editor is currently for object-level only actions, so show that using object-icon hint */
- static const EnumPropertyItem mode_items[] = {
- {SACTCONT_DOPESHEET, "DOPESHEET", ICON_OOPS, "Dope Sheet", "Edit all keyframes in scene"},
- {SACTCONT_ACTION, "ACTION", ICON_OBJECT_DATA, "Action Editor", "Edit keyframes in active object's Object-level action"},
- {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}
- };
-
-
srna = RNA_def_struct(brna, "SpaceDopeSheetEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceAction");
RNA_def_struct_ui_text(srna, "Space Dope Sheet Editor", "Dope Sheet space data");
@@ -3443,13 +3913,22 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceDopeSheetEditor_action_set", NULL,
"rna_Action_actedit_assign_poll");
RNA_def_property_ui_text(prop, "Action", "Action displayed and edited in this space");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, "rna_SpaceDopeSheetEditor_action_update");
- /* mode */
+ /* mode (hidden in the UI, see 'ui_mode') */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_action_mode_all_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, "rna_SpaceDopeSheetEditor_mode_update");
+
+ prop = RNA_def_property(srna, "ui_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, rna_enum_space_action_ui_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, "rna_SpaceDopeSheetEditor_mode_update");
/* display */
@@ -3479,10 +3958,22 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_group_colors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NODRAWGCOLORS);
RNA_def_property_ui_text(prop, "Show Group Colors",
- "Draw groups and channels with colors matching their corresponding groups "
+ "Display groups and channels with colors matching their corresponding groups "
"(pose bones only currently)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
+ prop = RNA_def_property(srna, "show_interpolation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SHOW_INTERPOLATION);
+ RNA_def_property_ui_text(prop, "Show Handles And Interpolation",
+ "Display keyframe handle types and non-bezier interpolation modes");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
+
+ prop = RNA_def_property(srna, "show_extremes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SHOW_EXTREMES);
+ RNA_def_property_ui_text(prop, "Show Curve Extremes",
+ "Mark keyframes where the key value flow changes direction, based on comparison with adjacent keys");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
+
/* editing */
prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NOTRANSKEYCULL);
@@ -3511,6 +4002,42 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
RNA_def_property_enum_items(prop, autosnap_items);
RNA_def_property_ui_text(prop, "Auto Snap", "Automatic time snapping settings for transformations");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
+
+ /* displaying cache status */
+ prop = RNA_def_property(srna, "show_cache", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_DISPLAY);
+ RNA_def_property_ui_text(prop, "Show Cache", "Show the status of cached frames in the timeline");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
+
+ prop = RNA_def_property(srna, "cache_softbody", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_SOFTBODY);
+ RNA_def_property_ui_text(prop, "Softbody", "Show the active object's softbody point cache");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
+
+ prop = RNA_def_property(srna, "cache_particles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_PARTICLES);
+ RNA_def_property_ui_text(prop, "Particles", "Show the active object's particle point cache");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
+
+ prop = RNA_def_property(srna, "cache_cloth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_CLOTH);
+ RNA_def_property_ui_text(prop, "Cloth", "Show the active object's cloth point cache");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
+
+ prop = RNA_def_property(srna, "cache_smoke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_SMOKE);
+ RNA_def_property_ui_text(prop, "Smoke", "Show the active object's smoke cache");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
+
+ prop = RNA_def_property(srna, "cache_dynamicpaint", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_DYNAMICPAINT);
+ RNA_def_property_ui_text(prop, "Dynamic Paint", "Show the active object's Dynamic Paint cache");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
+
+ prop = RNA_def_property(srna, "cache_rigidbody", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_RIGIDBODY);
+ RNA_def_property_ui_text(prop, "Rigid Body", "Show the active object's Rigid Body cache");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
}
static void rna_def_space_graph(BlenderRNA *brna)
@@ -3518,18 +4045,11 @@ static void rna_def_space_graph(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem mode_items[] = {
- {SIPO_MODE_ANIMATION, "FCURVES", ICON_IPO, "F-Curve",
- "Edit animation/keyframes displayed as 2D curves"},
- {SIPO_MODE_DRIVERS, "DRIVERS", ICON_DRIVER, "Drivers", "Edit drivers"},
- {0, NULL, 0, NULL, NULL}
- };
-
/* this is basically the same as the one for the 3D-View, but with some entries omitted */
static const EnumPropertyItem gpivot_items[] = {
- {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", ""},
- {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
- {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Centers", ""},
+ {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_PIVOT_BOUNDBOX, "Bounding Box Center", ""},
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "2D Cursor", ""},
+ {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_PIVOT_INDIVIDUAL, "Individual Centers", ""},
/*{V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", 0, "Median Point", ""}, */
/*{V3D_AROUND_ACTIVE, "ACTIVE_ELEMENT", 0, "Active Element", ""}, */
{0, NULL, 0, NULL, NULL}
@@ -3543,8 +4063,9 @@ static void rna_def_space_graph(BlenderRNA *brna)
/* mode */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_graph_mode_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, "rna_SpaceGraphEditor_display_mode_update");
/* display */
@@ -3583,15 +4104,15 @@ static void rna_def_space_graph(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_beauty_drawing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_BEAUTYDRAW_OFF);
- RNA_def_property_ui_text(prop, "Use High Quality Drawing",
- "Draw F-Curves using Anti-Aliasing and other fancy effects "
+ RNA_def_property_ui_text(prop, "Use High Quality Display",
+ "Display F-Curves using Anti-Aliasing and other fancy effects "
"(disable for better performance)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
prop = RNA_def_property(srna, "show_group_colors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NODRAWGCOLORS);
RNA_def_property_ui_text(prop, "Show Group Colors",
- "Draw groups and channels with colors matching their corresponding groups");
+ "Display groups and channels with colors matching their corresponding groups");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
/* editing */
@@ -3714,63 +4235,6 @@ static void rna_def_space_nla(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
}
-static void rna_def_space_time(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "SpaceTimeline", "Space");
- RNA_def_struct_sdna(srna, "SpaceTime");
- RNA_def_struct_ui_text(srna, "Space Timeline Editor", "Timeline editor space data");
-
- /* view settings */
- prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TIME_CFRA_NUM);
- RNA_def_property_ui_text(prop, "Show Frame Number Indicator",
- "Show frame number beside the current frame indicator line");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
- prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", TIME_DRAWFRAMES);
- RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
- /* displaying cache status */
- prop = RNA_def_property(srna, "show_cache", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_DISPLAY);
- RNA_def_property_ui_text(prop, "Show Cache", "Show the status of cached frames in the timeline");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
- prop = RNA_def_property(srna, "cache_softbody", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_SOFTBODY);
- RNA_def_property_ui_text(prop, "Softbody", "Show the active object's softbody point cache");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
- prop = RNA_def_property(srna, "cache_particles", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_PARTICLES);
- RNA_def_property_ui_text(prop, "Particles", "Show the active object's particle point cache");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
- prop = RNA_def_property(srna, "cache_cloth", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_CLOTH);
- RNA_def_property_ui_text(prop, "Cloth", "Show the active object's cloth point cache");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
- prop = RNA_def_property(srna, "cache_smoke", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_SMOKE);
- RNA_def_property_ui_text(prop, "Smoke", "Show the active object's smoke cache");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
- prop = RNA_def_property(srna, "cache_dynamicpaint", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_DYNAMICPAINT);
- RNA_def_property_ui_text(prop, "Dynamic Paint", "Show the active object's Dynamic Paint cache");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-
- prop = RNA_def_property(srna, "cache_rigidbody", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_RIGIDBODY);
- RNA_def_property_ui_text(prop, "Rigid Body", "Show the active object's Rigid Body cache");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
-}
static void rna_def_console_line(BlenderRNA *brna)
{
@@ -3876,9 +4340,9 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{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"},
+ {FILTER_ID_GR, "GROUP", ICON_GROUP, "Collections", "Show/hide Collection data-blocks"},
{FILTER_ID_IM, "IMAGE", ICON_IMAGE_DATA, "Images", "Show/hide Image data-blocks"},
- {FILTER_ID_LA, "LAMP", ICON_LAMP_DATA, "Lamps", "Show/hide Lamp data-blocks"},
+ {FILTER_ID_LA, "LIGHT", ICON_LIGHT_DATA, "Lights", "Show/hide Light data-blocks"},
{FILTER_ID_LS, "LINESTYLE", ICON_LINE_DATA,
"Freestyle Linestyles", "Show/hide Freestyle's Line Style data-blocks"},
{FILTER_ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattices", "Show/hide Lattice data-blocks"},
@@ -3893,6 +4357,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
"Particles Settings", "Show/hide Particle Settings data-blocks"},
{FILTER_ID_PAL, "PALETTE", ICON_COLOR, "Palettes", "Show/hide Palette data-blocks"},
{FILTER_ID_PC, "PAINT_CURVE", ICON_CURVE_BEZCURVE, "Paint Curves", "Show/hide Paint Curve data-blocks"},
+ {FILTER_ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probes", "Show/hide Light Probe data-blocks"},
{FILTER_ID_SCE, "SCENE", ICON_SCENE_DATA, "Scenes", "Show/hide Scene data-blocks"},
{FILTER_ID_SPK, "SPEAKER", ICON_SPEAKER, "Speakers", "Show/hide Speaker data-blocks"},
{FILTER_ID_SO, "SOUND", ICON_SOUND, "Sounds", "Show/hide Sound data-blocks"},
@@ -3900,6 +4365,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{FILTER_ID_TXT, "TEXT", ICON_TEXT, "Texts", "Show/hide Text data-blocks"},
{FILTER_ID_VF, "FONT", ICON_FONT_DATA, "Fonts", "Show/hide Font data-blocks"},
{FILTER_ID_WO, "WORLD", ICON_WORLD_DATA, "Worlds", "Show/hide World data-blocks"},
+ {FILTER_ID_WS, "WORK_SPACE", ICON_NONE, "Workspaces", "Show/hide workspace data-blocks"},
{0, NULL, 0, NULL, NULL}
};
@@ -3909,7 +4375,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
{FILTER_ID_AC,
"ANIMATION", ICON_ANIM_DATA, "Animations", "Show/hide animation data"},
{FILTER_ID_OB | FILTER_ID_GR,
- "OBJECT", ICON_GROUP, "Objects & Groups", "Show/hide objects and groups"},
+ "OBJECT", ICON_GROUP, "Objects & Collections", "Show/hide objects and groups"},
{FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME,
"GEOMETRY", ICON_MESH_DATA, "Geometry", "Show/hide meshes, curves, lattice, armatures and metaballs data"},
{FILTER_ID_LS | FILTER_ID_MA | FILTER_ID_NT | FILTER_ID_TE,
@@ -3917,8 +4383,8 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
"Show/hide materials, nodetrees, textures and Freestyle's linestyles"},
{FILTER_ID_IM | FILTER_ID_MC | FILTER_ID_MSK | FILTER_ID_SO,
"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_CA | FILTER_ID_LA | FILTER_ID_SPK | FILTER_ID_WO | FILTER_ID_WS,
+ "ENVIRONMENT", ICON_WORLD_DATA, "Environment", "Show/hide worlds, lights, 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_CF,
"MISC", ICON_GREASEPENCIL, "Miscellaneous", "Show/hide other data types"},
{0, NULL, 0, NULL, NULL}
@@ -4081,14 +4547,12 @@ static void rna_def_filemenu_entry(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "File Select Parameters", "File Select Parameters");
prop = RNA_def_property(srna, "path", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_string_sdna(prop, NULL, "path");
RNA_def_property_string_funcs(prop, "rna_FileBrowser_FSMenuEntry_path_get",
"rna_FileBrowser_FSMenuEntry_path_length",
"rna_FileBrowser_FSMenuEntry_path_set");
RNA_def_property_ui_text(prop, "Path", "");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_string_funcs(prop, "rna_FileBrowser_FSMenuEntry_name_get",
"rna_FileBrowser_FSMenuEntry_name_length",
"rna_FileBrowser_FSMenuEntry_name_set");
@@ -4097,12 +4561,12 @@ static void rna_def_filemenu_entry(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "use_save", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "save", 1);
+ RNA_def_property_boolean_funcs(prop, "rna_FileBrowser_FSMenuEntry_use_save_get", NULL);
RNA_def_property_ui_text(prop, "Save", "Whether this path is saved in bookmarks, or generated from OS");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "valid", 1);
+ RNA_def_property_boolean_funcs(prop, "rna_FileBrowser_FSMenuEntry_is_valid_get", NULL);
RNA_def_property_ui_text(prop, "Valid", "Whether this path is currently reachable");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
@@ -4315,7 +4779,6 @@ static void rna_def_space_node(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem texture_id_type_items[] = {
- {SNODE_TEX_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Edit texture nodes from Object"},
{SNODE_TEX_WORLD, "WORLD", ICON_WORLD_DATA, "World", "Edit texture nodes from World"},
{SNODE_TEX_BRUSH, "BRUSH", ICON_BRUSH_DATA, "Brush", "Edit texture nodes from Brush"},
#ifdef WITH_FREESTYLE
@@ -4335,9 +4798,9 @@ static void rna_def_space_node(BlenderRNA *brna)
static const EnumPropertyItem backdrop_channels_items[] = {
{SNODE_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha",
- "Draw image with RGB colors and alpha transparency"},
- {0, "COLOR", ICON_IMAGE_RGB, "Color", "Draw image with RGB colors"},
- {SNODE_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Draw alpha transparency channel"},
+ "Display image with RGB colors and alpha transparency"},
+ {0, "COLOR", ICON_IMAGE_RGB, "Color", "Display image with RGB colors"},
+ {SNODE_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Display alpha transparency channel"},
{SNODE_SHOW_R, "RED", ICON_COLOR_RED, "Red", ""},
{SNODE_SHOW_G, "GREEN", ICON_COLOR_GREEN, "Green", ""},
{SNODE_SHOW_B, "BLUE", ICON_COLOR_BLUE, "Blue", ""},
@@ -4416,10 +4879,10 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Backdrop", "Use active Viewer Node output as backdrop for compositing nodes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, "rna_SpaceNodeEditor_show_backdrop_update");
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SNODE_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
prop = RNA_def_property(srna, "use_auto_render", PROP_BOOLEAN, PROP_NONE);
@@ -4435,20 +4898,16 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Backdrop Zoom", "Backdrop zoom factor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
- prop = RNA_def_property(srna, "backdrop_x", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "backdrop_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xof");
- RNA_def_property_ui_text(prop, "Backdrop X", "Backdrop X offset");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
-
- prop = RNA_def_property(srna, "backdrop_y", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "yof");
- RNA_def_property_ui_text(prop, "Backdrop Y", "Backdrop Y offset");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Backdrop Offset", "Backdrop offset");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
prop = RNA_def_property(srna, "backdrop_channels", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, backdrop_channels_items);
- RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the image to draw");
+ RNA_def_property_ui_text(prop, "Display Channels", "Channels of the image to draw");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
/* the mx/my "cursor" in the node editor is used only by operators to store the mouse position */
@@ -4475,75 +4934,6 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_api_space_node(srna);
}
-static void rna_def_space_logic(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "SpaceLogicEditor", "Space");
- RNA_def_struct_sdna(srna, "SpaceLogic");
- RNA_def_struct_ui_text(srna, "Space Logic Editor", "Logic editor space data");
-
- /* sensors */
- prop = RNA_def_property(srna, "show_sensors_selected_objects", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_SEL);
- RNA_def_property_ui_text(prop, "Show Selected Object", "Show sensors of all selected objects");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_sensors_active_object", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_ACT);
- RNA_def_property_ui_text(prop, "Show Active Object", "Show sensors of active object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_sensors_linked_controller", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_LINK);
- RNA_def_property_ui_text(prop, "Show Linked to Controller", "Show linked objects to the controller");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_sensors_active_states", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_STATE);
- RNA_def_property_ui_text(prop, "Show Active States", "Show only sensors connected to active states");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* controllers */
- prop = RNA_def_property(srna, "show_controllers_selected_objects", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_CONT_SEL);
- RNA_def_property_ui_text(prop, "Show Selected Object", "Show controllers of all selected objects");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_controllers_active_object", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_CONT_ACT);
- RNA_def_property_ui_text(prop, "Show Active Object", "Show controllers of active object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_controllers_linked_controller", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_CONT_LINK);
- RNA_def_property_ui_text(prop, "Show Linked to Controller", "Show linked objects to sensor/actuator");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- /* actuators */
- prop = RNA_def_property(srna, "show_actuators_selected_objects", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_ACT_SEL);
- RNA_def_property_ui_text(prop, "Show Selected Object", "Show actuators of all selected objects");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_actuators_active_object", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_ACT_ACT);
- RNA_def_property_ui_text(prop, "Show Active Object", "Show actuators of active object");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_actuators_linked_controller", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_ACT_LINK);
- RNA_def_property_ui_text(prop, "Show Linked to Actuator", "Show linked objects to the actuator");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
- prop = RNA_def_property(srna, "show_actuators_active_states", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_ACT_STATE);
- RNA_def_property_ui_text(prop, "Show Active States", "Show only actuators connected to active states");
- RNA_def_property_update(prop, NC_LOGIC, NULL);
-
-}
-
static void rna_def_space_clip(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4551,24 +4941,24 @@ static void rna_def_space_clip(BlenderRNA *brna)
static const EnumPropertyItem view_items[] = {
{SC_VIEW_CLIP, "CLIP", ICON_SEQUENCE, "Clip", "Show editing clip preview"},
- {SC_VIEW_GRAPH, "GRAPH", ICON_IPO, "Graph", "Show graph view for active element"},
+ {SC_VIEW_GRAPH, "GRAPH", ICON_GRAPH, "Graph", "Show graph view for active element"},
{SC_VIEW_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dopesheet", "Dopesheet view for tracking data"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem gpencil_source_items[] = {
- {SC_GPENCIL_SRC_CLIP, "CLIP", 0, "Clip", "Show grease pencil data-block which belongs to movie clip"},
- {SC_GPENCIL_SRC_TRACK, "TRACK", 0, "Track", "Show grease pencil data-block which belongs to active track"},
+ {SC_GPENCIL_SRC_CLIP, "CLIP", 0, "Clip", "Show annotation data-block which belongs to movie clip"},
+ {SC_GPENCIL_SRC_TRACK, "TRACK", 0, "Track", "Show annotation data-block which belongs to active track"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem pivot_items[] = {
- {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
+ {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_PIVOT_BOUNDBOX, "Bounding Box Center",
"Pivot around bounding box center of selected object(s)"},
- {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", "Pivot around the 2D cursor"},
- {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "2D Cursor", "Pivot around the 2D cursor"},
+ {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_CENTER_ONLY,
"Individual Origins", "Pivot around each object's own origin"},
- {V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
+ {V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", ICON_PIVOT_MEDIAN, "Median Point",
"Pivot around the median point of selected objects"},
{0, NULL, 0, NULL, NULL}
};
@@ -4708,11 +5098,11 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Manual Calibration", "Use manual calibration helpers");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
- /* show grease pencil */
- prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_GPENCIL);
- RNA_def_property_ui_text(prop, "Show Grease Pencil",
- "Show grease pencil for this view");
+ /* show annotation */
+ prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_ANNOTATION);
+ RNA_def_property_ui_text(prop, "Show Annotation",
+ "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
/* show filters */
@@ -4816,20 +5206,17 @@ void RNA_def_space(BlenderRNA *brna)
rna_def_filemenu_entry(brna);
rna_def_space_filebrowser(brna);
rna_def_space_outliner(brna);
- rna_def_background_image(brna);
rna_def_space_view3d(brna);
rna_def_space_buttons(brna);
rna_def_space_dopesheet(brna);
rna_def_space_graph(brna);
rna_def_space_nla(brna);
- rna_def_space_time(brna);
rna_def_space_console(brna);
rna_def_console_line(brna);
rna_def_space_info(brna);
rna_def_space_userpref(brna);
rna_def_node_tree_path(brna);
rna_def_space_node(brna);
- rna_def_space_logic(brna);
rna_def_space_clip(brna);
}
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 8f771eda99d..f1206b7130f 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -31,9 +31,12 @@
#ifdef RNA_RUNTIME
+#include "BKE_global.h"
+
+#include "ED_screen.h"
#include "ED_text.h"
-static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d)
+static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d, bContext *C)
{
bScreen *sc = (bScreen *)id;
@@ -43,11 +46,20 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d)
area_region_from_regiondata(sc, rv3d, &sa, &ar);
if (sa && ar && sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d;
-
- v3d = (View3D *)sa->spacedata.first;
-
- ED_view3d_update_viewmat(sc->scene, v3d, ar, NULL, NULL, NULL);
+ View3D *v3d = sa->spacedata.first;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win;
+
+ for (win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == sc) {
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+
+ ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL);
+ break;
+ }
+ }
}
}
@@ -71,7 +83,7 @@ void RNA_api_region_view3d(StructRNA *srna)
FunctionRNA *func;
func = RNA_def_function(srna, "update", "rna_RegionView3D_update");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Recalculate the view matrices");
}
diff --git a/source/blender/makesrna/intern/rna_speaker.c b/source/blender/makesrna/intern/rna_speaker.c
index 3a4bc3860d4..41f22929143 100644
--- a/source/blender/makesrna/intern/rna_speaker.c
+++ b/source/blender/makesrna/intern/rna_speaker.c
@@ -41,7 +41,6 @@
#include "MEM_guardedalloc.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "WM_api.h"
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index b2271c3903d..e9ef4bf7a8c 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -67,19 +67,14 @@ const EnumPropertyItem rna_enum_texture_type_items[] = {
{TEX_CLOUDS, "CLOUDS", ICON_TEXTURE, "Clouds", "Procedural - create a cloud-like fractal noise texture"},
{TEX_DISTNOISE, "DISTORTED_NOISE", ICON_TEXTURE,
"Distorted Noise", "Procedural - noise texture distorted by two noise algorithms"},
- {TEX_ENVMAP, "ENVIRONMENT_MAP", ICON_IMAGE_DATA,
- "Environment Map", "Create a render of the environment mapped to a texture"},
{TEX_IMAGE, "IMAGE", ICON_IMAGE_DATA, "Image or Movie", "Allow for images or movies to be used as textures"},
{TEX_MAGIC, "MAGIC", ICON_TEXTURE, "Magic", "Procedural - color texture based on trigonometric functions"},
{TEX_MARBLE, "MARBLE", ICON_TEXTURE, "Marble", "Procedural - marble-like noise texture with wave generated bands"},
{TEX_MUSGRAVE, "MUSGRAVE", ICON_TEXTURE, "Musgrave", "Procedural - highly flexible fractal noise texture"},
{TEX_NOISE, "NOISE", ICON_TEXTURE, "Noise",
"Procedural - random noise, gives a different result every time, for every frame, for every pixel"},
- {TEX_OCEAN, "OCEAN", ICON_TEXTURE, "Ocean", "Use a texture generated by an Ocean modifier"},
- {TEX_POINTDENSITY, "POINT_DENSITY", ICON_TEXTURE, "Point Density", ""},
{TEX_STUCCI, "STUCCI", ICON_TEXTURE, "Stucci", "Procedural - create a fractal noise texture"},
{TEX_VORONOI, "VORONOI", ICON_TEXTURE, "Voronoi", "Procedural - create cell-like patterns based on Worley noise"},
- {TEX_VOXELDATA, "VOXEL_DATA", ICON_TEXTURE, "Voxel Data", "Create a 3D texture based on volumetric data"},
{TEX_WOOD, "WOOD", ICON_TEXTURE, "Wood", "Procedural - wave generated bands or rings, with optional noise"},
{0, NULL, 0, NULL, NULL}
};
@@ -87,21 +82,26 @@ const EnumPropertyItem rna_enum_texture_type_items[] = {
#ifndef RNA_RUNTIME
static const EnumPropertyItem blend_type_items[] = {
{MTEX_BLEND, "MIX", 0, "Mix", ""},
- {MTEX_ADD, "ADD", 0, "Add", ""},
- {MTEX_SUB, "SUBTRACT", 0, "Subtract", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {MTEX_DARK, "DARKEN", 0, "Darken", ""},
{MTEX_MUL, "MULTIPLY", 0, "Multiply", ""},
+ {0, "", ICON_NONE, NULL, NULL},
+ {MTEX_LIGHT, "LIGHTEN", 0, "Lighten", ""},
{MTEX_SCREEN, "SCREEN", 0, "Screen", ""},
+ {MTEX_ADD, "ADD", 0, "Add", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{MTEX_OVERLAY, "OVERLAY", 0, "Overlay", ""},
+ {MTEX_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
+ {MTEX_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{MTEX_DIFF, "DIFFERENCE", 0, "Difference", ""},
+ {MTEX_SUB, "SUBTRACT", 0, "Subtract", ""},
{MTEX_DIV, "DIVIDE", 0, "Divide", ""},
- {MTEX_DARK, "DARKEN", 0, "Darken", ""},
- {MTEX_LIGHT, "LIGHTEN", 0, "Lighten", ""},
+ {0, "", ICON_NONE, NULL, NULL},
{MTEX_BLEND_HUE, "HUE", 0, "Hue", ""},
{MTEX_BLEND_SAT, "SATURATION", 0, "Saturation", ""},
- {MTEX_BLEND_VAL, "VALUE", 0, "Value", ""},
{MTEX_BLEND_COLOR, "COLOR", 0, "Color", ""},
- {MTEX_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
- {MTEX_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
+ {MTEX_BLEND_VAL, "VALUE", 0, "Value", ""},
{0, NULL, 0, NULL, NULL}
};
#endif
@@ -114,11 +114,12 @@ static const EnumPropertyItem blend_type_items[] = {
#include "BKE_colorband.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_texture.h"
#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+
#include "ED_node.h"
#include "ED_render.h"
@@ -133,8 +134,6 @@ static StructRNA *rna_Texture_refine(struct PointerRNA *ptr)
return &RNA_CloudsTexture;
case TEX_DISTNOISE:
return &RNA_DistortedNoiseTexture;
- case TEX_ENVMAP:
- return &RNA_EnvironmentMapTexture;
case TEX_IMAGE:
return &RNA_ImageTexture;
case TEX_MAGIC:
@@ -145,18 +144,12 @@ static StructRNA *rna_Texture_refine(struct PointerRNA *ptr)
return &RNA_MusgraveTexture;
case TEX_NOISE:
return &RNA_NoiseTexture;
- case TEX_POINTDENSITY:
- return &RNA_PointDensityTexture;
case TEX_STUCCI:
return &RNA_StucciTexture;
case TEX_VORONOI:
return &RNA_VoronoiTexture;
- case TEX_VOXELDATA:
- return &RNA_VoxelDataTexture;
case TEX_WOOD:
return &RNA_WoodTexture;
- case TEX_OCEAN:
- return &RNA_OceanTexture;
default:
return &RNA_Texture;
}
@@ -169,7 +162,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
if (GS(id->name) == ID_TE) {
Tex *tex = ptr->id.data;
- DAG_id_tag_update(&tex->id, 0);
+ DEG_id_tag_update(&tex->id, 0);
WM_main_add_notifier(NC_TEXTURE, tex);
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, NULL);
}
@@ -191,31 +184,12 @@ static void rna_Color_mapping_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
/* nothing to do */
}
-static void rna_Texture_voxeldata_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Tex *tex = ptr->id.data;
-
- tex->vd->ok = 0;
- rna_Texture_update(bmain, scene, ptr);
-}
-
-static void rna_Texture_voxeldata_image_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Tex *tex = ptr->id.data;
-
- if (tex->ima) { /* may be getting cleared too */
- tex->ima->source = IMA_SRC_SEQUENCE;
- }
- rna_Texture_voxeldata_update(bmain, scene, ptr);
-}
-
-
/* Used for Texture Properties, used (also) for/in Nodes */
static void rna_Texture_nodes_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Tex *tex = ptr->id.data;
- DAG_id_tag_update(&tex->id, 0);
+ DEG_id_tag_update(&tex->id, 0);
WM_main_add_notifier(NC_TEXTURE | ND_NODES, tex);
}
@@ -226,11 +200,11 @@ static void rna_Texture_type_set(PointerRNA *ptr, int value)
BKE_texture_type_set(tex, value);
}
-void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+void rna_TextureSlot_update(bContext *C, PointerRNA *ptr)
{
ID *id = ptr->id.data;
- DAG_id_tag_update(id, 0);
+ DEG_id_tag_update(id, 0);
switch (GS(id->name)) {
case ID_MA:
@@ -246,8 +220,10 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
break;
case ID_BR:
{
+ Scene *scene = CTX_data_scene(C);
MTex *mtex = ptr->data;
- BKE_paint_invalidate_overlay_tex(scene, mtex->tex);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BKE_paint_invalidate_overlay_tex(scene, view_layer, mtex->tex);
WM_main_add_notifier(NC_BRUSH, id);
break;
}
@@ -264,7 +240,7 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
if (mtex->mapto & PAMAP_CHILD)
recalc |= PSYS_RECALC_CHILD;
- DAG_id_tag_update(id, recalc);
+ DEG_id_tag_update(id, recalc);
WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
break;
}
@@ -430,54 +406,6 @@ static void rna_ImageTexture_mipmap_set(PointerRNA *ptr, bool value)
else tex->imaflag &= ~TEX_MIPMAP;
}
-static void rna_Envmap_update_generic(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Tex *tex = ptr->id.data;
- if (tex->env) {
- ED_preview_kill_jobs(bmain->wm.first, bmain);
- BKE_texture_envmap_free_data(tex->env);
- }
- rna_Texture_update(bmain, scene, ptr);
-}
-
-static PointerRNA rna_PointDensity_psys_get(PointerRNA *ptr)
-{
- PointDensity *pd = ptr->data;
- Object *ob = pd->object;
- ParticleSystem *psys = NULL;
- PointerRNA value;
-
- if (ob && pd->psys)
- psys = BLI_findlink(&ob->particlesystem, pd->psys - 1);
-
- RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &value);
- return value;
-}
-
-static void rna_PointDensity_psys_set(PointerRNA *ptr, PointerRNA value)
-{
- PointDensity *pd = ptr->data;
- Object *ob = pd->object;
-
- if (ob && value.id.data == ob)
- pd->psys = BLI_findindex(&ob->particlesystem, value.data) + 1;
-}
-
-static char *rna_PointDensity_path(PointerRNA *UNUSED(ptr))
-{
- return BLI_sprintfN("point_density");
-}
-
-static char *rna_VoxelData_path(PointerRNA *UNUSED(ptr))
-{
- return BLI_sprintfN("voxel_data");
-}
-
-static char *rna_OceanTex_path(PointerRNA *UNUSED(ptr))
-{
- return BLI_sprintfN("ocean");
-}
-
#else
static void rna_def_texmapping(BlenderRNA *brna)
@@ -649,7 +577,7 @@ static void rna_def_mtex(BlenderRNA *brna)
prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tex");
RNA_def_property_struct_type(prop, "Texture");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Texture", "Texture data-block used by this texture slot");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_TextureSlot_update");
@@ -657,6 +585,7 @@ static void rna_def_mtex(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, "rna_TextureSlot_name_get", "rna_TextureSlot_name_length", NULL);
RNA_def_property_ui_text(prop, "Name", "Texture slot name");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
@@ -664,12 +593,13 @@ static void rna_def_mtex(BlenderRNA *brna)
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "ofs");
RNA_def_property_ui_range(prop, -10, 10, 10, RNA_TRANSLATION_PREC_DEFAULT);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Offset", "Fine tune of the texture mapping X, Y and Z locations");
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_flag(prop, PROP_PROPORTIONAL);
+ RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_CONTEXT_UPDATE);
RNA_def_property_ui_range(prop, -100, 100, 10, 2);
RNA_def_property_ui_text(prop, "Size", "Set scaling for the texture's X, Y and Z sizes");
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
@@ -677,6 +607,7 @@ static void rna_def_mtex(BlenderRNA *brna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "r");
RNA_def_property_array(prop, 3);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Color",
"Default color for textures that don't return RGB or when RGB to intensity is enabled");
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
@@ -684,26 +615,31 @@ static void rna_def_mtex(BlenderRNA *brna)
prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "blendtype");
RNA_def_property_enum_items(prop, blend_type_items);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Blend Type", "Mode used to apply the texture");
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "use_stencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_STENCIL);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Stencil", "Use this texture as a blending value on the next texture");
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_NEGATIVE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Negate", "Invert the values of the texture to reverse its effect");
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "use_rgb_to_intensity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_RGBTOINT);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "RGB to Intensity", "Convert texture RGB values to intensity (gray) values");
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "default_value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "def_var");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
RNA_def_property_ui_text(prop, "Default Value",
"Value to use for Ref, Spec, Amb, Emit, Alpha, RayMir, TransLu and Hard");
@@ -712,6 +648,7 @@ static void rna_def_mtex(BlenderRNA *brna)
prop = RNA_def_property(srna, "output_node", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "which_output");
RNA_def_property_enum_items(prop, output_node_items);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_enum_funcs(prop, "rna_TextureSlot_output_node_get", NULL, "rna_TextureSlot_output_node_itemf");
RNA_def_property_ui_text(prop, "Output Node", "Which output node to use, for node-based textures");
RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
@@ -738,7 +675,7 @@ static void rna_def_filter_common(StructRNA *srna)
RNA_def_property_ui_text(prop, "Filter", "Texture filter to use for sampling image");
RNA_def_property_update(prop, 0, "rna_Texture_update");
- prop = RNA_def_property(srna, "filter_probes", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "filter_lightprobes", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "afmax");
RNA_def_property_range(prop, 1, 256);
RNA_def_property_ui_text(prop, "Filter Probes",
@@ -767,94 +704,6 @@ static void rna_def_filter_common(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Texture_update");
}
-static void rna_def_environment_map(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem prop_source_items[] = {
- {ENV_STATIC, "STATIC", 0, "Static", "Calculate environment map only once"},
- {ENV_ANIM, "ANIMATED", 0, "Animated", "Calculate environment map at each rendering"},
- {ENV_LOAD, "IMAGE_FILE", 0, "Image File", "Load a saved environment map image from disk"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_mapping_items[] = {
- {ENV_CUBE, "CUBE", 0, "Cube", "Use environment map with six cube sides"},
- {ENV_PLANE, "PLANE", 0, "Plane", "Only one side is rendered, with Z axis pointing in direction of image"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "EnvironmentMap", NULL);
- RNA_def_struct_sdna(srna, "EnvMap");
- RNA_def_struct_ui_text(srna, "EnvironmentMap",
- "Environment map created by the renderer and cached for subsequent renders");
-
- prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "stype");
- RNA_def_property_enum_items(prop, prop_source_items);
- RNA_def_property_ui_text(prop, "Source", "");
- RNA_def_property_update(prop, 0, "rna_Envmap_update_generic");
-
- prop = RNA_def_property(srna, "viewpoint_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "object");
- RNA_def_property_ui_text(prop, "Viewpoint Object", "Object to use as the environment map's viewpoint location");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_mapping_items);
- RNA_def_property_ui_text(prop, "Mapping", "");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "clipsta");
- RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.01, 50, 100, 2);
- RNA_def_property_ui_text(prop, "Clip Start", "Objects nearer than this are not visible to map");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "clipend");
- RNA_def_property_range(prop, 0.01, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.10, 20000, 100, 2);
- RNA_def_property_ui_text(prop, "Clip End", "Objects further than this are not visible to map");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "zoom", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "viewscale");
- RNA_def_property_range(prop, 0.1, 5.0);
- RNA_def_property_ui_range(prop, 0.5, 1.5, 1, 2);
- RNA_def_property_ui_text(prop, "Zoom", "");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "layers_ignore", PROP_BOOLEAN, PROP_LAYER_MEMBER);
- RNA_def_property_boolean_sdna(prop, NULL, "notlay", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_ui_text(prop, "Ignore Layers",
- "Hide objects on these layers when generating the Environment Map");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "resolution", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "cuberes");
- RNA_def_property_range(prop, 50, 4096);
- RNA_def_property_ui_text(prop, "Resolution", "Pixel resolution of the rendered environment map");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_range(prop, 0, 5);
- RNA_def_property_ui_text(prop, "Depth", "Number of times a map will be rendered recursively (mirror effects)");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, 0);
- RNA_def_property_boolean_sdna(prop, NULL, "ok", 2);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Validity", "True if this map is ready for use, False if it needs rendering");
-
- RNA_api_environment_map(srna);
-}
-
static const EnumPropertyItem prop_noise_basis_items[] = {
{TEX_BLENDER, "BLENDER_ORIGINAL", 0, "Blender Original",
"Noise algorithm - Blender original: Smooth interpolated noise"},
@@ -1360,43 +1209,6 @@ static void rna_def_texture_image(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "imaflag", TEX_NORMALMAP);
RNA_def_property_ui_text(prop, "Normal Map", "Use image RGB values for normal mapping");
RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- /* Derivative Map */
- prop = RNA_def_property(srna, "use_derivative_map", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "imaflag", TEX_DERIVATIVEMAP);
- RNA_def_property_ui_text(prop, "Derivative Map", "Use red and green as derivative values");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-}
-
-static void rna_def_texture_environment_map(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "EnvironmentMapTexture", "Texture");
- RNA_def_struct_ui_text(srna, "Environment Map", "Environment map texture");
- RNA_def_struct_sdna(srna, "Tex");
-
- prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "ima");
- RNA_def_property_struct_type(prop, "Image");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Image", "Source image file to read the environment map from");
- RNA_def_property_update(prop, 0, "rna_Envmap_update_generic");
-
- prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "iuser");
- RNA_def_property_ui_text(prop, "Image User",
- "Parameters defining which layer, pass and frame of the image is displayed");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- rna_def_filter_common(srna);
-
- prop = RNA_def_property(srna, "environment_map", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "env");
- RNA_def_property_struct_type(prop, "EnvironmentMap");
- RNA_def_property_ui_text(prop, "Environment Map", "Get the environment map associated with this texture");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
}
static void rna_def_texture_musgrave(BlenderRNA *brna)
@@ -1621,407 +1433,6 @@ static void rna_def_texture_distorted_noise(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Texture_update");
}
-static void rna_def_texture_pointdensity(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem point_source_items[] = {
- {TEX_PD_PSYS, "PARTICLE_SYSTEM", 0, "Particle System", "Generate point density from a particle system"},
- {TEX_PD_OBJECT, "OBJECT", 0, "Object Vertices", "Generate point density from an object's vertices"},
- /*{TEX_PD_FILE, "FILE", 0, "File", ""}, */
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem particle_cache_items[] = {
- {TEX_PD_OBJECTLOC, "OBJECT_LOCATION", 0, "Emit Object Location", ""},
- {TEX_PD_OBJECTSPACE, "OBJECT_SPACE", 0, "Emit Object Space", ""},
- {TEX_PD_WORLDSPACE, "WORLD_SPACE", 0, "Global Space", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem vertex_cache_items[] = {
- {TEX_PD_OBJECTLOC, "OBJECT_LOCATION", 0, "Object Location", ""},
- {TEX_PD_OBJECTSPACE, "OBJECT_SPACE", 0, "Object Space", ""},
- {TEX_PD_WORLDSPACE, "WORLD_SPACE", 0, "Global Space", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem falloff_items[] = {
- {TEX_PD_FALLOFF_STD, "STANDARD", 0, "Standard", ""},
- {TEX_PD_FALLOFF_SMOOTH, "SMOOTH", 0, "Smooth", ""},
- {TEX_PD_FALLOFF_SOFT, "SOFT", 0, "Soft", ""},
- {TEX_PD_FALLOFF_CONSTANT, "CONSTANT", 0, "Constant", "Density is constant within lookup radius"},
- {TEX_PD_FALLOFF_ROOT, "ROOT", 0, "Root", ""},
- {TEX_PD_FALLOFF_PARTICLE_AGE, "PARTICLE_AGE", 0, "Particle Age", ""},
- {TEX_PD_FALLOFF_PARTICLE_VEL, "PARTICLE_VELOCITY", 0, "Particle Velocity", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem particle_color_source_items[] = {
- {TEX_PD_COLOR_CONSTANT, "CONSTANT", 0, "Constant", ""},
- {TEX_PD_COLOR_PARTAGE, "PARTICLE_AGE", 0, "Particle Age", "Lifetime mapped as 0.0 - 1.0 intensity"},
- {TEX_PD_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed",
- "Particle speed (absolute magnitude of velocity) mapped as 0.0-1.0 intensity"},
- {TEX_PD_COLOR_PARTVEL, "PARTICLE_VELOCITY", 0, "Particle Velocity", "XYZ velocity mapped to RGB colors"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem vertex_color_source_items[] = {
- {TEX_PD_COLOR_CONSTANT, "CONSTANT", 0, "Constant", ""},
- {TEX_PD_COLOR_VERTCOL, "VERTEX_COLOR", 0, "Vertex Color", "Vertex color layer"},
- {TEX_PD_COLOR_VERTWEIGHT, "VERTEX_WEIGHT", 0, "Vertex Weight", "Vertex group weight"},
- {TEX_PD_COLOR_VERTNOR, "VERTEX_NORMAL", 0, "Vertex Normal", "XYZ normal vector mapped to RGB colors"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem turbulence_influence_items[] = {
- {TEX_PD_NOISE_STATIC, "STATIC", 0, "Static",
- "Noise patterns will remain unchanged, faster and suitable for stills"},
- {TEX_PD_NOISE_VEL, "PARTICLE_VELOCITY", 0, "Particle Velocity",
- "Turbulent noise driven by particle velocity"},
- {TEX_PD_NOISE_AGE, "PARTICLE_AGE", 0, "Particle Age",
- "Turbulent noise driven by the particle's age between birth and death"},
- {TEX_PD_NOISE_TIME, "GLOBAL_TIME", 0, "Global Time", "Turbulent noise driven by the global current frame"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "PointDensity", NULL);
- RNA_def_struct_sdna(srna, "PointDensity");
- RNA_def_struct_ui_text(srna, "PointDensity", "Point density settings");
- RNA_def_struct_path_func(srna, "rna_PointDensity_path");
-
- prop = RNA_def_property(srna, "point_source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "source");
- RNA_def_property_enum_items(prop, point_source_items);
- RNA_def_property_ui_text(prop, "Point Source", "Point data to use as renderable point density");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "object");
- RNA_def_property_ui_text(prop, "Object", "Object to take point data from");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "Particle System", "Particle System to render as points");
- RNA_def_property_struct_type(prop, "ParticleSystem");
- RNA_def_property_pointer_funcs(prop, "rna_PointDensity_psys_get", "rna_PointDensity_psys_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "particle_cache_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "psys_cache_space");
- RNA_def_property_enum_items(prop, particle_cache_items);
- RNA_def_property_ui_text(prop, "Particle Cache", "Coordinate system to cache particles in");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "vertex_cache_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "ob_cache_space");
- RNA_def_property_enum_items(prop, vertex_cache_items);
- RNA_def_property_ui_text(prop, "Vertices Cache", "Coordinate system to cache vertices in");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "radius");
- RNA_def_property_range(prop, 0.001, FLT_MAX);
- RNA_def_property_ui_text(prop, "Radius", "Radius from the shaded sample to look for points within");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "falloff", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "falloff_type");
- RNA_def_property_enum_items(prop, falloff_items);
- RNA_def_property_ui_text(prop, "Falloff", "Method of attenuating density by distance from the point");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "falloff_soft", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "falloff_softness");
- RNA_def_property_range(prop, 0.01, FLT_MAX);
- RNA_def_property_ui_text(prop, "Softness", "Softness of the 'soft' falloff option");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "particle_color_source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "color_source");
- RNA_def_property_enum_items(prop, particle_color_source_items);
- RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "vertex_color_source", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "ob_color_source");
- RNA_def_property_enum_items(prop, vertex_color_source_items);
- RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "vertex_attribute_name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Vertex Attribute Name", "Vertex attribute to use for color");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "speed_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "speed_scale");
- RNA_def_property_range(prop, 0.001, 100.0);
- RNA_def_property_ui_text(prop, "Scale", "Multiplier to bring particle speed within an acceptable range");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "falloff_speed_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "falloff_speed_scale");
- RNA_def_property_range(prop, 0.001, 100.0);
- RNA_def_property_ui_text(prop, "Velocity Scale", "Multiplier to bring particle speed within an acceptable range");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
-
- prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "coba");
- RNA_def_property_struct_type(prop, "ColorRamp");
- RNA_def_property_ui_text(prop, "Color Ramp", "");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "falloff_curve");
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Falloff Curve", "");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "use_falloff_curve", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEX_PD_FALLOFF_CURVE);
- RNA_def_property_ui_text(prop, "Falloff Curve", "Use a custom falloff curve");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- /* Turbulence */
- prop = RNA_def_property(srna, "use_turbulence", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEX_PD_TURBULENCE);
- RNA_def_property_ui_text(prop, "Turbulence", "Add directed noise to the density at render-time");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "turbulence_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "noise_size");
- RNA_def_property_range(prop, 0.01, FLT_MAX);
- RNA_def_property_ui_text(prop, "Size", "Scale of the added turbulent noise");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "turbulence_strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "noise_fac");
- RNA_def_property_range(prop, 0.01, FLT_MAX);
- RNA_def_property_ui_text(prop, "Turbulence Strength", "Strength of the added turbulent noise");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "turbulence_depth", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "noise_depth");
- RNA_def_property_range(prop, 0, 30);
- RNA_def_property_ui_text(prop, "Depth", "Level of detail in the added turbulent noise");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "turbulence_influence", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "noise_influence");
- RNA_def_property_enum_items(prop, turbulence_influence_items);
- RNA_def_property_ui_text(prop, "Turbulence Influence", "Method for driving added turbulent noise");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "noise_basis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "noise_basis");
- RNA_def_property_enum_items(prop, prop_noise_basis_items);
- RNA_def_property_ui_text(prop, "Noise Basis", "Noise formula used for turbulence");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
-
- srna = RNA_def_struct(brna, "PointDensityTexture", "Texture");
- RNA_def_struct_sdna(srna, "Tex");
- RNA_def_struct_ui_text(srna, "Point Density", "Settings for the Point Density texture");
-
- prop = RNA_def_property(srna, "point_density", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "pd");
- RNA_def_property_struct_type(prop, "PointDensity");
- RNA_def_property_ui_text(prop, "Point Density", "The point density settings associated with this texture");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-}
-
-static void rna_def_texture_voxeldata(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem interpolation_type_items[] = {
- {TEX_VD_NEARESTNEIGHBOR, "NEREASTNEIGHBOR", 0, "Nearest Neighbor",
- "No interpolation, fast but blocky and low quality"},
- {TEX_VD_LINEAR, "TRILINEAR", 0, "Linear", "Good smoothness and speed"},
- {TEX_VD_QUADRATIC, "QUADRATIC", 0, "Quadratic", "Mid-range quality and speed"},
- {TEX_VD_TRICUBIC_CATROM, "TRICUBIC_CATROM", 0, "Cubic Catmull-Rom", "High quality interpolation, but slower"},
- {TEX_VD_TRICUBIC_BSPLINE, "TRICUBIC_BSPLINE", 0, "Cubic B-Spline",
- "Smoothed high quality interpolation, but slower"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem file_format_items[] = {
- {TEX_VD_BLENDERVOXEL, "BLENDER_VOXEL", 0, "Blender Voxel", "Default binary voxel file format"},
- {TEX_VD_RAW_8BIT, "RAW_8BIT", 0, "8 bit RAW", "8 bit grayscale binary data"},
- /*{TEX_VD_RAW_16BIT, "RAW_16BIT", 0, "16 bit RAW", ""}, */
- {TEX_VD_IMAGE_SEQUENCE, "IMAGE_SEQUENCE", 0, "Image Sequence",
- "Generate voxels from a sequence of image slices"},
- {TEX_VD_SMOKE, "SMOKE", 0, "Smoke", "Render voxels from a Blender smoke simulation"},
- {TEX_VD_HAIR, "HAIR", 0, "Hair", "Render voxels from a Blender hair simulation"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem voxeldata_extension[] = {
- {TEX_EXTEND, "EXTEND", 0, "Extend", "Extend by repeating edge pixels of the image"},
- {TEX_CLIP, "CLIP", 0, "Clip", "Clip to image size and set exterior pixels as transparent"},
- {TEX_REPEAT, "REPEAT", 0, "Repeat", "Cause the image to repeat horizontally and vertically"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem smoked_type_items[] = {
- {TEX_VD_SMOKEDENSITY, "SMOKEDENSITY", 0, "Smoke", "Use smoke density and color as texture data"},
- {TEX_VD_SMOKEFLAME, "SMOKEFLAME", 0, "Flame", "Use flame temperature as texture data"},
- {TEX_VD_SMOKEHEAT, "SMOKEHEAT", 0, "Heat", "Use smoke heat as texture data. Values from -2.0 to 2.0 are used"},
- {TEX_VD_SMOKEVEL, "SMOKEVEL", 0, "Velocity", "Use smoke velocity as texture data"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem hair_type_items[] = {
- {TEX_VD_HAIRDENSITY, "HAIRDENSITY", 0, "Density", "Use hair density as texture data"},
- {TEX_VD_HAIRRESTDENSITY, "HAIRRESTDENSITY", 0, "Rest Density", "Use hair rest density as texture data"},
- {TEX_VD_HAIRVELOCITY, "HAIRVELOCITY", 0, "Velocity", "Use hair velocity as texture data"},
- {TEX_VD_HAIRENERGY, "HAIRENERGY", 0, "Energy", "Use potential hair energy as texture data"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "VoxelData", NULL);
- RNA_def_struct_sdna(srna, "VoxelData");
- RNA_def_struct_ui_text(srna, "VoxelData", "Voxel data settings");
- RNA_def_struct_path_func(srna, "rna_VoxelData_path");
-
- prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "interp_type");
- RNA_def_property_enum_items(prop, interpolation_type_items);
- RNA_def_property_ui_text(prop, "Interpolation", "Method to interpolate/smooth values between voxel cells");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "smoke_data_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "smoked_type");
- RNA_def_property_enum_items(prop, smoked_type_items);
- RNA_def_property_ui_text(prop, "Source", "Simulation value to be used as a texture");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-
- prop = RNA_def_property(srna, "hair_data_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "hair_type");
- RNA_def_property_enum_items(prop, hair_type_items);
- RNA_def_property_ui_text(prop, "Source", "Simulation value to be used as a texture");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-
- prop = RNA_def_property(srna, "extension", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "extend");
- RNA_def_property_enum_items(prop, voxeldata_extension);
- RNA_def_property_ui_text(prop, "Extension", "How the texture is extrapolated past its original bounds");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "int_multiplier");
- RNA_def_property_range(prop, 0.01, FLT_MAX);
- RNA_def_property_ui_text(prop, "Intensity", "Multiplier for intensity values");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "file_format", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "file_format");
- RNA_def_property_enum_items(prop, file_format_items);
- RNA_def_property_ui_text(prop, "File Format", "Format of the source data set to render");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-
- prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_string_sdna(prop, NULL, "source_path");
- RNA_def_property_ui_text(prop, "Source Path", "The external source data file to use");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-
- prop = RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "resol");
- RNA_def_property_range(prop, 1, 100000);
- RNA_def_property_ui_text(prop, "Resolution", "Resolution of the voxel grid");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-
- prop = RNA_def_property(srna, "use_still_frame", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEX_VD_STILL);
- RNA_def_property_ui_text(prop, "Still Frame Only", "Always render a still frame from the voxel data sequence");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-
- prop = RNA_def_property(srna, "still_frame", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "still_frame");
- RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
- RNA_def_property_ui_text(prop, "Still Frame Number", "The frame number to always use");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-
- prop = RNA_def_property(srna, "domain_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "object");
- RNA_def_property_ui_text(prop, "Domain Object", "Object used as the smoke simulation domain");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-
-
- srna = RNA_def_struct(brna, "VoxelDataTexture", "Texture");
- RNA_def_struct_sdna(srna, "Tex");
- RNA_def_struct_ui_text(srna, "Voxel Data", "Settings for the Voxel Data texture");
-
- prop = RNA_def_property(srna, "voxel_data", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "vd");
- RNA_def_property_struct_type(prop, "VoxelData");
- RNA_def_property_ui_text(prop, "Voxel Data", "The voxel data associated with this texture");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "ima");
- RNA_def_property_struct_type(prop, "Image");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Image", "");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_image_update");
-
- prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "iuser");
- RNA_def_property_ui_text(prop, "Image User",
- "Parameters defining which layer, pass and frame of the image is displayed");
- RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
-}
-
-static void rna_def_texture_ocean(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem ocean_output_items[] = {
- {TEX_OCN_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", "Output XYZ displacement in RGB channels"},
- /*{TEX_OCN_NORMALS, "NORMALS", 0, "Normals", "Outputs wave normals"}, *//* these are in nor channel now */
- {TEX_OCN_FOAM, "FOAM", 0, "Foam", "Output Foam (wave overlap) amount in single channel"},
- {TEX_OCN_JPLUS, "JPLUS", 0, "Eigenvalues", "Positive Eigenvalues"},
- {TEX_OCN_EMINUS, "EMINUS", 0, "Eigenvectors (-)", "Negative Eigenvectors"},
- {TEX_OCN_EPLUS, "EPLUS", 0, "Eigenvectors (+)", "Positive Eigenvectors"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "OceanTexData", NULL);
- RNA_def_struct_sdna(srna, "OceanTex");
- RNA_def_struct_ui_text(srna, "Ocean", "Ocean Texture settings");
- RNA_def_struct_path_func(srna, "rna_OceanTex_path");
-
- prop = RNA_def_property(srna, "output", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "output");
- RNA_def_property_enum_items(prop, ocean_output_items);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Output", "The data that is output by the texture");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- prop = RNA_def_property(srna, "ocean_object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "object");
- RNA_def_property_ui_text(prop, "Modifier Object", "Object containing the ocean modifier");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-
- srna = RNA_def_struct(brna, "OceanTexture", "Texture");
- RNA_def_struct_sdna(srna, "Tex");
- RNA_def_struct_ui_text(srna, "Ocean", "Settings for the Ocean texture");
-
- prop = RNA_def_property(srna, "ocean", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "ot");
- RNA_def_property_struct_type(prop, "OceanTexData");
- RNA_def_property_ui_text(prop, "Ocean", "The ocean data associated with this texture");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
-}
-
static void rna_def_texture(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2029,7 +1440,7 @@ static void rna_def_texture(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Texture", "ID");
RNA_def_struct_sdna(srna, "Tex");
- RNA_def_struct_ui_text(srna, "Texture", "Texture data-block used by materials, lamps, worlds and brushes");
+ RNA_def_struct_ui_text(srna, "Texture", "Texture data-block used by materials, lights, worlds and brushes");
RNA_def_struct_ui_icon(srna, ICON_TEXTURE_DATA);
RNA_def_struct_refine_func(srna, "rna_Texture_refine");
@@ -2122,13 +1533,9 @@ static void rna_def_texture(BlenderRNA *brna)
rna_def_texture_stucci(brna);
rna_def_texture_noise(brna);
rna_def_texture_image(brna);
- rna_def_texture_environment_map(brna);
rna_def_texture_musgrave(brna);
rna_def_texture_voronoi(brna);
rna_def_texture_distorted_noise(brna);
- rna_def_texture_pointdensity(brna);
- rna_def_texture_voxeldata(brna);
- rna_def_texture_ocean(brna);
/* XXX add more types here .. */
RNA_api_texture(srna);
@@ -2138,7 +1545,6 @@ void RNA_def_texture(BlenderRNA *brna)
{
rna_def_texture(brna);
rna_def_mtex(brna);
- rna_def_environment_map(brna);
rna_def_texmapping(brna);
rna_def_colormapping(brna);
}
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index 615d435f72e..1d513a494d7 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -45,30 +45,6 @@
#include "RE_pipeline.h"
#include "RE_shader_ext.h"
-static void save_envmap(struct EnvMap *env, bContext *C, ReportList *reports, const char *filepath,
- struct Scene *scene, float layout[12])
-{
- if (scene == NULL) {
- scene = CTX_data_scene(C);
- }
-
- RE_WriteEnvmapResult(reports, scene, env, filepath, scene->r.im_format.imtype, layout);
-}
-
-static void clear_envmap(struct EnvMap *env, bContext *C)
-{
- Main *bmain = CTX_data_main(C);
- Tex *tex;
-
- BKE_texture_envmap_free_data(env);
-
- for (tex = bmain->tex.first; tex; tex = tex->id.next)
- if (tex->env == env) {
- WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex);
- break;
- }
-}
-
static void texture_evaluate(struct Tex *tex, float value[3], float r_color[4])
{
TexResult texres = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
@@ -102,31 +78,4 @@ void RNA_api_texture(StructRNA *srna)
}
-void RNA_api_environment_map(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *parm;
-
- static const float default_layout[] = {0, 0, 1, 0, 2, 0, 0, 1, 1, 1, 2, 1};
-
- func = RNA_def_function(srna, "clear", "clear_envmap");
- RNA_def_function_ui_description(func, "Discard the environment map and free it from memory");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
-
-
- func = RNA_def_function(srna, "save", "save_envmap");
- RNA_def_function_ui_description(func, "Save the environment map to disc using the scene render settings");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
-
- parm = RNA_def_string_file_name(func, "filepath", NULL, FILE_MAX, "File path", "Location of the output file");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
-
- RNA_def_pointer(func, "scene", "Scene", "", "Overrides the scene from which image parameters are taken");
-
- RNA_def_float_array(func, "layout", 12, default_layout, 0.0f, 1000.0f, "File layout",
- "Flat array describing the X,Y position of each cube face in the "
- "output image, where 1 is the size of a face - order is [+Z -Z +Y -X -Y +X] "
- "(use -1 to skip a face)", 0.0f, 1000.0f);
-}
-
#endif
diff --git a/source/blender/makesrna/intern/rna_timeline.c b/source/blender/makesrna/intern/rna_timeline.c
index a732b550261..45f90d13477 100644
--- a/source/blender/makesrna/intern/rna_timeline.c
+++ b/source/blender/makesrna/intern/rna_timeline.c
@@ -74,7 +74,7 @@ static void rna_def_timeline_marker(BlenderRNA *brna)
prop = RNA_def_property(srna, "camera", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_ui_text(prop, "Camera", "Camera this timeline sets to active");
+ RNA_def_property_ui_text(prop, "Camera", "Camera that becomes active on this frame");
#endif
}
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index deb40070fe9..ed41d209f6a 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -51,9 +51,10 @@
#include "DNA_anim_types.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_node.h"
+#include "DEG_depsgraph.h"
+
#include "IMB_imbuf.h"
#include "WM_api.h"
@@ -426,7 +427,7 @@ static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerR
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
WM_main_add_notifier(NC_SCENE, NULL);
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
}
static void rna_tracking_resetIntrinsics(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -515,7 +516,7 @@ static void rna_trackingObject_flushUpdate(Main *UNUSED(bmain), Scene *UNUSED(sc
MovieClip *clip = (MovieClip *)ptr->id.data;
WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, NULL);
- DAG_id_tag_update(&clip->id, 0);
+ DEG_id_tag_update(&clip->id, 0);
}
static void rna_trackingMarker_frame_set(PointerRNA *ptr, int value)
@@ -914,14 +915,14 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_SETTINGS_SHOW_DEFAULT_EXPANDED);
RNA_def_property_ui_text(prop, "Show Expanded", "Show default options expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
/* ** extra tracker settings ** */
prop = RNA_def_property(srna, "show_extra_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_SETTINGS_SHOW_EXTRA_EXPANDED);
RNA_def_property_ui_text(prop, "Show Expanded", "Show extra options expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
/* solver settings */
prop = RNA_def_property(srna, "use_tripod_solver", PROP_BOOLEAN, PROP_NONE);
@@ -1479,6 +1480,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this track");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
@@ -1792,7 +1794,7 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRACKING_SHOW_STAB_TRACKS);
RNA_def_property_ui_text(prop, "Show Tracks", "Show UI list of tracks participating in stabilization");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
}
static void rna_def_reconstructedCamera(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index c6dc0c1b124..ea39ce72598 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
@@ -41,6 +42,7 @@
#include "UI_interface.h"
#include "WM_types.h"
+#include "WM_toolsystem.h"
/* see WM_types.h */
const EnumPropertyItem rna_enum_operator_context_items[] = {
@@ -113,7 +115,7 @@ static bool panel_poll(const bContext *C, PanelType *pt)
ParameterList list;
FunctionRNA *func;
void *ret;
- int visible;
+ bool visible;
RNA_pointer_create(NULL, pt->ext.srna, NULL, &ptr); /* dummy */
func = &rna_Panel_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
@@ -166,6 +168,24 @@ static void panel_draw_header(const bContext *C, Panel *pnl)
RNA_parameter_list_free(&list);
}
+static void panel_draw_header_preset(const bContext *C, Panel *pnl)
+{
+ extern FunctionRNA rna_Panel_draw_header_preset_func;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(&CTX_wm_screen(C)->id, pnl->type->ext.srna, pnl, &ptr);
+ func = &rna_Panel_draw_header_preset_func;
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ pnl->type->ext.call((bContext *)C, &ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type)
{
ARegionType *art;
@@ -179,6 +199,19 @@ static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type)
RNA_struct_free_extension(type, &pt->ext);
RNA_struct_free(&BLENDER_RNA, type);
+ if (pt->parent) {
+ LinkData *link = BLI_findptr(&pt->parent->children, pt, offsetof(LinkData, data));
+ BLI_freelinkN(&pt->parent->children, link);
+ }
+
+ WM_paneltype_remove(pt);
+
+ for (LinkData *link = pt->children.first; link; link = link->next) {
+ PanelType *child_pt = link->data;
+ child_pt->parent = NULL;
+ }
+
+ BLI_freelistN(&pt->children);
BLI_freelinkN(&art->paneltypes, pt);
/* update while blender is running */
@@ -190,10 +223,10 @@ static StructRNA *rna_Panel_register(
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
ARegionType *art;
- PanelType *pt, dummypt = {NULL};
+ PanelType *pt, *parent = NULL, dummypt = {NULL};
Panel dummypanel = {NULL};
PointerRNA dummyptr;
- int have_function[3];
+ int have_function[4];
/* setup dummy panel & panel type to store static properties in */
dummypanel.type = &dummypt;
@@ -212,9 +245,23 @@ static StructRNA *rna_Panel_register(
return NULL;
}
- if ((dummypt.category[0] == '\0') && (dummypt.region_type == RGN_TYPE_TOOLS)) {
- /* Use a fallback, otherwise an empty value will draw the panel in every category. */
- strcpy(dummypt.category, PNL_CATEGORY_FALLBACK);
+ if ((1 << dummypt.region_type) & RGN_TYPE_HAS_CATEGORY_MASK) {
+ if (dummypt.category[0] == '\0') {
+ /* Use a fallback, otherwise an empty value will draw the panel in every category. */
+ strcpy(dummypt.category, PNL_CATEGORY_FALLBACK);
+#ifndef NDEBUG
+ printf("Registering panel class: '%s' misses category, please update the script\n", dummypt.idname);
+#endif
+ }
+ }
+ else {
+ if (dummypt.category[0] != '\0') {
+ if ((1 << dummypt.space_type) & WM_TOOLSYSTEM_SPACE_MASK) {
+ BKE_reportf(reports, RPT_ERROR, "Registering panel class: '%s' has category '%s' ",
+ dummypt.idname, dummypt.category);
+ return NULL;
+ }
+ }
}
if (!(art = region_type_find(reports, dummypt.space_type, dummypt.region_type)))
@@ -229,6 +276,10 @@ static StructRNA *rna_Panel_register(
BLI_freelinkN(&art->paneltypes, pt);
break;
}
+
+ if (dummypt.parent_id[0] && STREQ(pt->idname, dummypt.parent_id)) {
+ parent = pt;
+ }
}
if (!RNA_struct_available_or_report(reports, dummypt.idname)) {
return NULL;
@@ -236,6 +287,11 @@ static StructRNA *rna_Panel_register(
if (!RNA_struct_bl_idname_ok_or_report(reports, dummypt.idname, "_PT_")) {
return NULL;
}
+ if (dummypt.parent_id[0] && !parent) {
+ BKE_reportf(reports, RPT_ERROR, "Registering panel class: parent '%s' for '%s' not found",
+ dummypt.parent_id, dummypt.idname);
+ return NULL;
+ }
/* create a new panel type */
pt = MEM_callocN(sizeof(PanelType), "python buttons panel");
@@ -252,6 +308,7 @@ static StructRNA *rna_Panel_register(
pt->poll = (have_function[0]) ? panel_poll : NULL;
pt->draw = (have_function[1]) ? panel_draw : NULL;
pt->draw_header = (have_function[2]) ? panel_draw_header : NULL;
+ pt->draw_header_preset = (have_function[3]) ? panel_draw_header_preset : NULL;
/* XXX use "no header" flag for some ordering of panels until we have real panel ordering */
if (pt->flag & PNL_NO_HEADER) {
@@ -267,6 +324,20 @@ static StructRNA *rna_Panel_register(
else
BLI_addtail(&art->paneltypes, pt);
+ if (parent) {
+ pt->parent = parent;
+ BLI_addtail(&parent->children, BLI_genericNodeN(pt));
+ }
+
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(pt->owner_id, owner_id, sizeof(pt->owner_id));
+ }
+ }
+
+ WM_paneltype_add(pt);
+
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -323,7 +394,7 @@ static void uilist_draw_item(uiList *ui_list, bContext *C, uiLayout *layout, Poi
RNA_parameter_list_free(&list);
}
-static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout)
+static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout, bool reverse)
{
extern FunctionRNA rna_UIList_draw_filter_func;
@@ -337,6 +408,7 @@ static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout)
RNA_parameter_list_create(&list, &ul_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "layout", &layout);
+ RNA_parameter_set_lookup(&list, "reverse", &reverse);
ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list);
RNA_parameter_list_free(&list);
@@ -561,7 +633,7 @@ static void rna_Header_unregister(Main *UNUSED(bmain), StructRNA *type)
if (!ht)
return;
- if (!(art = region_type_find(NULL, ht->space_type, RGN_TYPE_HEADER)))
+ if (!(art = region_type_find(NULL, ht->space_type, ht->region_type)))
return;
RNA_struct_free_extension(type, &ht->ext);
@@ -585,6 +657,7 @@ static StructRNA *rna_Header_register(
/* setup dummy header & header type to store static properties in */
dummyheader.type = &dummyht;
+ dummyht.region_type = RGN_TYPE_HEADER; /* RGN_TYPE_HEADER by default, may be overridden */
RNA_pointer_create(NULL, &RNA_Header, &dummyheader, &dummyhtr);
/* validate the python class */
@@ -597,7 +670,7 @@ static StructRNA *rna_Header_register(
return NULL;
}
- if (!(art = region_type_find(reports, dummyht.space_type, RGN_TYPE_HEADER)))
+ if (!(art = region_type_find(reports, dummyht.space_type, dummyht.region_type)))
return NULL;
/* check if we have registered this header type before, and remove it */
@@ -774,6 +847,13 @@ static StructRNA *rna_Menu_register(
mt->poll = (have_function[0]) ? menu_poll : NULL;
mt->draw = (have_function[1]) ? menu_draw : NULL;
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(mt->owner_id, owner_id, sizeof(mt->owner_id));
+ }
+ }
+
WM_menutype_add(mt);
/* update while blender is running */
@@ -890,6 +970,56 @@ static void rna_UILayout_scale_y_set(PointerRNA *ptr, float value)
uiLayoutSetScaleY(ptr->data, value);
}
+static float rna_UILayout_units_x_get(PointerRNA *ptr)
+{
+ return uiLayoutGetUnitsX(ptr->data);
+}
+
+static void rna_UILayout_units_x_set(PointerRNA *ptr, float value)
+{
+ uiLayoutSetUnitsX(ptr->data, value);
+}
+
+static float rna_UILayout_units_y_get(PointerRNA *ptr)
+{
+ return uiLayoutGetUnitsY(ptr->data);
+}
+
+static void rna_UILayout_units_y_set(PointerRNA *ptr, float value)
+{
+ uiLayoutSetUnitsY(ptr->data, value);
+}
+
+static int rna_UILayout_emboss_get(PointerRNA *ptr)
+{
+ return uiLayoutGetEmboss(ptr->data);
+}
+
+static void rna_UILayout_emboss_set(PointerRNA *ptr, int value)
+{
+ uiLayoutSetEmboss(ptr->data, value);
+}
+
+static bool rna_UILayout_property_split_get(PointerRNA *ptr)
+{
+ return uiLayoutGetPropSep(ptr->data);
+}
+
+static void rna_UILayout_property_split_set(PointerRNA *ptr, bool value)
+{
+ uiLayoutSetPropSep(ptr->data, value);
+}
+
+static bool rna_UILayout_property_decorate_get(PointerRNA *ptr)
+{
+ return uiLayoutGetPropDecorate(ptr->data);
+}
+
+static void rna_UILayout_property_decorate_set(PointerRNA *ptr, bool value)
+{
+ uiLayoutSetPropDecorate(ptr->data, value);
+}
+
#else /* RNA_RUNTIME */
static void rna_def_ui_layout(BlenderRNA *brna)
@@ -905,6 +1035,14 @@ static void rna_def_ui_layout(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static const EnumPropertyItem emboss_items[] = {
+ {UI_EMBOSS, "NORMAL", 0, "Normal", "Draw standard button emboss style"},
+ {UI_EMBOSS_NONE, "NONE", 0, "None", "Draw only text and icons"},
+ {UI_EMBOSS_PULLDOWN, "PULLDOWN_MENU", 0, "Pulldown Menu", "Draw pulldown menu style"},
+ {UI_EMBOSS_RADIAL, "RADIAL_MENU", 0, "Radial Menu", "Draw radial menu style"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* layout */
srna = RNA_def_struct(brna, "UILayout", NULL);
@@ -941,7 +1079,25 @@ static void rna_def_ui_layout(BlenderRNA *brna)
prop = RNA_def_property(srna, "scale_y", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_funcs(prop, "rna_UILayout_scale_y_get", "rna_UILayout_scale_y_set", NULL);
RNA_def_property_ui_text(prop, "Scale Y", "Scale factor along the Y for items in this (sub)layout");
+
+ prop = RNA_def_property(srna, "ui_units_x", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_funcs(prop, "rna_UILayout_units_x_get", "rna_UILayout_units_x_set", NULL);
+ RNA_def_property_ui_text(prop, "Units X", "Fixed Size along the X for items in this (sub)layout");
+
+ prop = RNA_def_property(srna, "ui_units_y", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_funcs(prop, "rna_UILayout_units_y_get", "rna_UILayout_units_y_set", NULL);
+ RNA_def_property_ui_text(prop, "Units Y", "Fixed Size along the Y for items in this (sub)layout");
RNA_api_ui_layout(srna);
+
+ prop = RNA_def_property(srna, "emboss", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, emboss_items);
+ RNA_def_property_enum_funcs(prop, "rna_UILayout_emboss_get", "rna_UILayout_emboss_set", NULL);
+
+ prop = RNA_def_property(srna, "use_property_split", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_UILayout_property_split_get", "rna_UILayout_property_split_set");
+
+ prop = RNA_def_property(srna, "use_property_decorate", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_UILayout_property_decorate_get", "rna_UILayout_property_decorate_set");
}
static void rna_def_panel(BlenderRNA *brna)
@@ -989,6 +1145,12 @@ static void rna_def_panel(BlenderRNA *brna)
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ func = RNA_def_function(srna, "draw_header_preset", NULL);
+ RNA_def_function_ui_description(func, "Draw UI elements for presets in the panel's header");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "UILayout");
RNA_def_property_ui_text(prop, "Layout", "Defines the structure of the panel in the UI");
@@ -1024,6 +1186,10 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "type->category");
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->owner_id");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->space_type");
RNA_def_property_enum_items(prop, rna_enum_space_type_items);
@@ -1049,11 +1215,26 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Options", "Options for this panel type");
+ prop = RNA_def_property(srna, "bl_parent_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->parent_id");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(prop, "Parent ID Name", "If this is set, the panel becomes a subpanel");
+
+ prop = RNA_def_property(srna, "bl_ui_units_x", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "type->ui_units_x");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(prop, "Units X", "When set, defines popup panel width");
+
prop = RNA_def_property(srna, "use_pin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PNL_PIN);
RNA_def_property_ui_text(prop, "Pin", "");
/* XXX, should only tag region for redraw */
RNA_def_property_update(prop, NC_WINDOW, NULL);
+
+ prop = RNA_def_property(srna, "is_popover", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", PNL_POPOVER);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Popover", "");
}
static void rna_def_uilist(BlenderRNA *brna)
@@ -1144,6 +1325,7 @@ static void rna_def_uilist(BlenderRNA *brna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_boolean(func, "reverse", false, "", "Display items in reverse order");
/* filter */
func = RNA_def_function(srna, "filter_items", NULL);
@@ -1223,6 +1405,14 @@ static void rna_def_header(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Space type", "The space where the header is going to be used in");
+ prop = RNA_def_property(srna, "bl_region_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type->region_type");
+ RNA_def_property_enum_default(prop, RGN_TYPE_HEADER);
+ RNA_def_property_enum_items(prop, rna_enum_region_type_items);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(prop, "Region Type", "The region where the header is going to be used in "
+ "(defaults to header region)");
+
RNA_define_verify_sdna(1);
}
@@ -1291,6 +1481,10 @@ static void rna_def_menu(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+ prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->owner_id");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
RNA_define_verify_sdna(1);
}
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index d647876796a..4d361920dcb 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -47,16 +47,14 @@
#include "rna_internal.h"
-#define DEF_ICON_BLANK_SKIP
#define DEF_ICON(name) {ICON_##name, (#name), 0, (#name), ""},
-#define DEF_VICO(name) {VICO_##name, (#name), 0, (#name), ""},
+#define DEF_ICON_VECTOR(name) {ICON_##name, (#name), 0, (#name), ""},
+#define DEF_ICON_COLOR(name) {ICON_##name, (#name), 0, (#name), ""},
+#define DEF_ICON_BLANK(name)
const EnumPropertyItem rna_enum_icon_items[] = {
#include "UI_icons.h"
{0, NULL, 0, NULL, NULL}
};
-#undef DEF_ICON_BLANK_SKIP
-#undef DEF_ICON
-#undef DEF_VICO
#ifdef RNA_RUNTIME
@@ -142,6 +140,25 @@ static void rna_uiItemMenuEnumR(
uiItemMenuEnumR_prop(layout, ptr, prop, name, icon);
}
+static void rna_uiItemTabsEnumR(
+ uiLayout *layout, bContext *C,
+ struct PointerRNA *ptr, const char *propname,
+ bool icon_only)
+{
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+
+ if (!prop) {
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+ if (RNA_property_type(prop) != PROP_ENUM) {
+ RNA_warning("property is not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ uiItemTabsEnumR_prop(layout, C, ptr, prop, icon_only);
+}
+
static void rna_uiItemEnumR_string(
uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value,
const char *name, const char *text_ctxt, bool translate, int icon)
@@ -277,6 +294,28 @@ static void rna_uiItemM(
uiItemM(layout, menuname, name, icon);
}
+static void rna_uiItemPopoverPanel(
+ uiLayout *layout, bContext *C,
+ const char *panel_type, const char *name, const char *text_ctxt,
+ bool translate, int icon, int icon_value)
+{
+ /* Get translated name (label). */
+ name = rna_translate_ui_text(name, text_ctxt, NULL, NULL, translate);
+
+ if (icon_value && !icon) {
+ icon = icon_value;
+ }
+
+ uiItemPopoverPanel(layout, C, panel_type, name, icon);
+}
+
+static void rna_uiItemPopoverPanelFromGroup(
+ uiLayout *layout, bContext *C,
+ int space_id, int region_id, const char *context, const char *category)
+{
+ uiItemPopoverPanelFromGroup(layout, C, space_id, region_id, context, category);
+}
+
static void rna_uiTemplateAnyID(
uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
const char *name, const char *text_ctxt, bool translate)
@@ -497,6 +536,19 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_return(func, parm);
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
+ func = RNA_def_function(srna, "grid_flow", "uiLayoutGridFlow");
+ RNA_def_boolean(func, "row_major", false, "", "Fill row by row, instead of column by column");
+ RNA_def_int(func, "columns", 0, INT_MIN, INT_MAX, "",
+ "Number of columns, positive are absolute fixed numbers, 0 is automatic, negative are "
+ "automatic multiple numbers along major axis (e.g. -2 will only produce 2, 4, 6 etc. "
+ "columns for row major layout, and 2, 4, 6 etc. rows for column major layout)",
+ INT_MIN, INT_MAX);
+ RNA_def_boolean(func, "even_columns", false, "", "All columns will have the same width");
+ RNA_def_boolean(func, "even_rows", false, "", "All rows will have the same height");
+ RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
+ parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
+ RNA_def_function_return(func, parm);
+
/* box layout */
func = RNA_def_function(srna, "box", "uiLayoutBox");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
@@ -508,7 +560,10 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "split", "uiLayoutSplit");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
- RNA_def_float(func, "percentage", 0.0f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at", 0.0f, 1.0f);
+ RNA_def_float(
+ func, "factor", 0.0f, 0.0f, 1.0f, "Percentage",
+ "Percentage of width to split at (leave unset for automatic calculation)",
+ 0.0f, 1.0f);
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
/* radial/pie layout */
@@ -581,6 +636,11 @@ void RNA_api_ui_layout(StructRNA *srna)
api_ui_item_rna_common(func);
api_ui_item_common(func);
+ func = RNA_def_function(srna, "prop_tabs_enum", "rna_uiItemTabsEnumR");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+ RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in tabs, no text");
+
func = RNA_def_function(srna, "prop_enum", "rna_uiItemEnumR_string");
api_ui_item_rna_common(func);
parm = RNA_def_string(func, "value", NULL, 0, "", "Enum property value");
@@ -681,8 +741,34 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
- func = RNA_def_function(srna, "separator", "uiItemS");
+ func = RNA_def_function(srna, "popover", "rna_uiItemPopoverPanel");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ parm = RNA_def_string(func, "panel", NULL, 0, "", "Identifier of the panel");
+ api_ui_item_common(func);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
+
+ func = RNA_def_function(srna, "popover_group", "rna_uiItemPopoverPanelFromGroup");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ parm = RNA_def_enum(func, "space_type", rna_enum_space_type_items, 0, "Space Type", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "context", NULL, 0, "", "panel type context");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_string(func, "category", NULL, 0, "", "panel type category");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "separator", "uiItemS_ex");
RNA_def_function_ui_description(func, "Item. Inserts empty space into the layout between items");
+ RNA_def_float(
+ func, "factor", 1.0f, 0.0f, FLT_MAX, "Percentage",
+ "Percentage of width to space (leave unset for default space)",
+ 0.0f, FLT_MAX);
+
+ func = RNA_def_function(srna, "separator_spacer", "uiItemSpacer");
+ RNA_def_function_ui_description(func, "Item. Inserts horizontal spacing empty space into the layout between items");
/* context */
func = RNA_def_function(srna, "context_pointer_set", "uiLayoutSetContextPointer");
@@ -704,6 +790,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block");
RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
"", "Optionally limit the items which can be selected");
+ RNA_def_boolean(func, "live_icon", false, "", "Show preview instead of fixed icon");
func = RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -715,6 +802,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
"", "Optionally limit the items which can be selected");
+ RNA_def_boolean(func, "hide_buttons", false, "", "Show only list, no buttons");
func = RNA_def_function(srna, "template_any_ID", "rna_uiTemplateAnyID");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
@@ -726,6 +814,38 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common_text(func);
+ func = RNA_def_function(srna, "template_ID_tabs", "uiTemplateIDTabs");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+ RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new ID block");
+ RNA_def_string(func, "menu", NULL, 0, "", "Context menu identifier");
+ RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
+ "", "Optionally limit the items which can be selected");
+
+ func = RNA_def_function(srna, "template_search", "uiTemplateSearch");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+ parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_string(func, "search_property", NULL, 0, "", "Identifier of search collection property");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new item for the collection");
+ RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink or delete the active "
+ "item from the collection");
+
+ func = RNA_def_function(srna, "template_search_preview", "uiTemplateSearchPreview");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+ parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_string(func, "search_property", NULL, 0, "", "Identifier of search collection property");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new item for the collection");
+ RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink or delete the active "
+ "item from the collection");
+ RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
+ RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
+
func = RNA_def_function(srna, "template_path_builder", "rna_uiTemplatePathBuilder");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
@@ -743,6 +863,31 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "template_greasepencil_modifier", "uiTemplateGpencilModifier");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Generates the UI layout for grease pencil modifiers");
+ parm = RNA_def_pointer(func, "data", "GpencilModifier", "", "Modifier data");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "template_shaderfx", "uiTemplateShaderFx");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Generates the UI layout for shader effect");
+ parm = RNA_def_pointer(func, "data", "ShaderFx", "", "Shader data");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "template_greasepencil_color", "uiTemplateGpencilColorPreview");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+ RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
+ RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
+ RNA_def_float(func, "scale", 1.0f, 0.1f, 1.5f, "Scale of the image thumbnails", "", 0.5f, 1.0f);
+ RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
+ "", "Optionally limit the items which can be selected");
+
func = RNA_def_function(srna, "template_constraint", "uiTemplateConstraint");
RNA_def_function_ui_description(func, "Generates the UI layout for constraints");
parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data");
@@ -751,7 +896,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "template_preview", "uiTemplatePreview");
- RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps or worlds");
+ RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lights or worlds");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "id", "ID", "", "ID data-block");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
@@ -763,18 +908,25 @@ void RNA_api_ui_layout(StructRNA *srna)
"(i.e. all previews of materials without explicit ID will have the same size...)");
func = RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping");
- RNA_def_function_ui_description(func, "Item. A curve mapping widget used for e.g falloff curves for lamps");
+ RNA_def_function_ui_description(func, "Item. A curve mapping widget used for e.g falloff curves for lights");
api_ui_item_rna_common(func);
RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display");
RNA_def_boolean(func, "levels", false, "", "Show black/white levels");
RNA_def_boolean(func, "brush", false, "", "Show brush options");
RNA_def_boolean(func, "use_negative_slope", false, "", "Use a negative slope by default");
+ RNA_def_boolean(func, "show_tone", false, "", "Show tone options");
func = RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp");
RNA_def_function_ui_description(func, "Item. A color ramp widget");
api_ui_item_rna_common(func);
RNA_def_boolean(func, "expand", false, "", "Expand button to show more detail");
+ func = RNA_def_function(srna, "template_icon", "uiTemplateIcon");
+ RNA_def_function_ui_description(func, "Display a large icon");
+ parm = RNA_def_int(func, "icon_value", 0, 0, INT_MAX, "Icon to display", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_float(func, "scale", 1.0f, 1.0f, 100.0f, "Scale", "Scale the icon size (by the button size)", 1.0f, 100.0f);
+
func = RNA_def_function(srna, "template_icon_view", "uiTemplateIconView");
RNA_def_function_ui_description(func, "Enum. Large widget showing Icon previews");
api_ui_item_rna_common(func);
@@ -880,10 +1032,11 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_string(func, "list_id", NULL, 0, "",
"Identifier of this list widget (mandatory when using default \"" UI_UL_DEFAULT_CLASS_NAME
"\" class). "
- "If this is set, the uilist gets a custom ID, otherwise it takes the "
+ "If this not an empty string, the uilist gets a custom ID, otherwise it takes the "
"name of the class used to define the uilist (for example, if the "
"class name is \"OBJECT_UL_vgroups\", and list_id is not set by the "
"script, then bl_idname = \"OBJECT_UL_vgroups\")");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "dataptr", "AnyType", "", "Data from which to take the Collection property");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "propname", NULL, 0, "", "Identifier of the Collection property in data");
@@ -900,6 +1053,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Default maximum number of rows to display", 0, INT_MAX);
RNA_def_enum(func, "type", rna_enum_uilist_layout_type_items, UILST_LAYOUT_DEFAULT, "Type", "Type of layout to use");
RNA_def_int(func, "columns", 9, 0, INT_MAX, "", "Number of items to display per row, for GRID layout", 0, INT_MAX);
+ RNA_def_boolean(func, "reverse", false, "", "Display items in reverse order");
func = RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -910,6 +1064,9 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Inserts common 3DView header UI (selectors for context mode, shading, etc.)");
+ func = RNA_def_function(srna, "template_header_3D_mode", "uiTemplateHeader3D_mode");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "");
func = RNA_def_function(srna, "template_edit_mode_selection", "uiTemplateEditModeSelection");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -918,6 +1075,9 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ func = RNA_def_function(srna, "template_input_status", "uiTemplateInputStatus");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+
func = RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink");
parm = RNA_def_pointer(func, "ntree", "NodeTree", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
@@ -971,6 +1131,12 @@ void RNA_api_ui_layout(StructRNA *srna)
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);
+
+ func = RNA_def_function(srna, "template_recent_files", "uiTemplateRecentFiles");
+ RNA_def_function_ui_description(func, "Show list of recently saved .blend files");
+ RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX);
+ parm = RNA_def_int(func, "found", 0, 0, INT_MAX, "", "Number of items drawn", 0, INT_MAX);
+ RNA_def_function_return(func, parm);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index c3e30de10af..af6150704e0 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -36,11 +36,12 @@
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
#include "BKE_appdir.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_sound.h"
#include "BKE_addon.h"
+#include "BKE_studiolight.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -52,7 +53,6 @@
#include "WM_types.h"
#include "BLT_lang.h"
-#include "GPU_buffers.h"
#ifdef WITH_OPENSUBDIV
static const EnumPropertyItem opensubdiv_compute_type_items[] = {
@@ -68,16 +68,7 @@ static const EnumPropertyItem opensubdiv_compute_type_items[] = {
#endif
static const EnumPropertyItem audio_device_items[] = {
- {0, "NONE", 0, "None", "Null device - there will be no audio output"},
-#ifdef WITH_SDL
- {1, "SDL", 0, "SDL", "SDL device - simple direct media layer, recommended for sequencer usage"},
-#endif
-#ifdef WITH_OPENAL
- {2, "OPENAL", 0, "OpenAL", "OpenAL device - supports 3D audio, recommended for game engine usage"},
-#endif
-#ifdef WITH_JACK
- {3, "JACK", 0, "JACK", "JACK Audio Connection Kit, recommended for pro audio users"},
-#endif
+ {0, "Null", 0, "None", "Null device - there will be no audio output"},
{0, NULL, 0, NULL, NULL}
};
@@ -87,26 +78,38 @@ const EnumPropertyItem rna_enum_navigation_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+
#if defined(WITH_INTERNATIONAL) || !defined(RNA_RUNTIME)
static const EnumPropertyItem rna_enum_language_default_items[] = {
- {0, "DEFAULT", 0, "Default (Default)", ""},
+ {0, "DEFAULT", 0, "Automatic (Automatic)",
+ "Automatically choose system's defined language if available, or fall-back to English"},
{0, NULL, 0, NULL, NULL}
};
#endif
+static const EnumPropertyItem rna_enum_studio_light_type_items[] = {
+ {STUDIOLIGHT_TYPE_STUDIO, "STUDIO", 0, "Studio", ""},
+ {STUDIOLIGHT_TYPE_WORLD, "WORLD", 0, "World", ""},
+ {STUDIOLIGHT_TYPE_MATCAP, "MATCAP", 0, "MatCap", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
#ifdef RNA_RUNTIME
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "BKE_blender.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
-#include "BKE_main.h"
#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_pbvh.h"
#include "BKE_paint.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_draw.h"
#include "GPU_select.h"
@@ -140,17 +143,11 @@ static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
}
/* also used by buffer swap switching */
-static void rna_userdef_dpi_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
/* font's are stored at each DPI level, without this we can easy load 100's of fonts */
BLF_cache_clear();
- /* force setting drawable again */
- wmWindowManager *wm = bmain->wm.first;
- if (wm) {
- wm->windrawable = NULL;
- }
-
WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
}
@@ -168,34 +165,6 @@ static void rna_userdef_language_update(Main *UNUSED(bmain), Scene *UNUSED(scene
UI_reinit_font();
}
-static void rna_userdef_show_manipulator_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- UserDef *userdef = (UserDef *)ptr->data;
-
- /* lame, loop over all views and set */
- bScreen *sc;
- ScrArea *sa;
- SpaceLink *sl;
-
- /* from scene copy to the other views */
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- if (userdef->tw_flag & V3D_USE_MANIPULATOR)
- v3d->twflag |= V3D_USE_MANIPULATOR;
- else
- v3d->twflag &= ~V3D_USE_MANIPULATOR;
- }
- }
- }
- }
-
- rna_userdef_update(bmain, scene, ptr);
-}
-
-
static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
UserDef *userdef = (UserDef *)ptr->data;
@@ -210,12 +179,6 @@ static void rna_userdef_load_ui_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
else G.fileflags &= ~G_FILE_NO_UI;
}
-static void rna_userdef_mipmap_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- GPU_set_mipmap(bmain, !(U.gameflags & USER_DISABLE_MIPMAP));
- rna_userdef_update(bmain, scene, ptr);
-}
-
static void rna_userdef_anisotropic_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
GPU_set_anisotropic(bmain, U.anisotropic_filter);
@@ -248,18 +211,6 @@ static void rna_userdef_undo_steps_set(PointerRNA *ptr, int value)
userdef->undosteps = (value == 1) ? 2 : value;
}
-static void rna_userdef_select_mouse_set(PointerRNA *ptr, int value)
-{
- UserDef *userdef = (UserDef *)ptr->data;
-
- if (value) {
- userdef->flag |= USER_LMOUSESELECT;
- userdef->flag &= ~USER_TWOBUTTONMOUSE;
- }
- else
- userdef->flag &= ~USER_LMOUSESELECT;
-}
-
static int rna_userdef_autokeymode_get(PointerRNA *ptr)
{
UserDef *userdef = (UserDef *)ptr->data;
@@ -366,12 +317,9 @@ static void rna_UserDef_weight_color_update(Main *bmain, Scene *scene, PointerRN
{
Object *ob;
- bTheme *btheme = UI_GetTheme();
- vDM_ColorBand_store((U.flag & USER_CUSTOM_RANGE) ? (&U.coba_weight) : NULL, btheme->tv3d.vertex_unreferenced);
-
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->mode & OB_MODE_WEIGHT_PAINT)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
rna_userdef_update(bmain, scene, ptr);
@@ -505,11 +453,7 @@ static void rna_userdef_opensubdiv_update(Main *bmain, Scene *UNUSED(scene), Poi
object;
object = object->id.next)
{
- if (object->derivedFinal != NULL &&
- object->derivedFinal->type == DM_TYPE_CCGDM)
- {
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
- }
+ DEG_id_tag_update(&object->id, OB_RECALC_OB);
}
}
@@ -522,7 +466,6 @@ static const EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C
int totitem = 0;
EnumPropertyItem *item = NULL;
-#ifdef WITH_SYSTEM_AUDASPACE
int i;
char **names = BKE_sound_get_device_names();
@@ -531,30 +474,12 @@ static const EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C
EnumPropertyItem new_item = {i, names[i], 0, names[i], names[i]};
RNA_enum_item_add(&item, &totitem, &new_item);
}
-#else
- /* NONE */
- RNA_enum_item_add(&item, &totitem, &audio_device_items[index++]);
-#ifdef WITH_SDL
-# ifdef WITH_SDL_DYNLOAD
- if (sdlewInit() == SDLEW_SUCCESS)
-# endif
- {
- RNA_enum_item_add(&item, &totitem, &audio_device_items[index]);
- }
- index++;
-#endif
-
-#ifdef WITH_OPENAL
- RNA_enum_item_add(&item, &totitem, &audio_device_items[index++]);
-#endif
-
-#ifdef WITH_JACK
- if (BKE_sound_is_jack_supported()) {
- RNA_enum_item_add(&item, &totitem, &audio_device_items[index]);
+#ifndef NDEBUG
+ if (i == 0) {
+ EnumPropertyItem new_item = {i, "SOUND_NONE", 0, "No Sound", ""};
+ RNA_enum_item_add(&item, &totitem, &new_item);
}
- index++;
-#endif
#endif
/* may be unused */
@@ -624,34 +549,34 @@ static StructRNA *rna_AddonPref_register(
Main *bmain, ReportList *reports, void *data, const char *identifier,
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
- bAddonPrefType *apt, dummyapt = {{'\0'}};
- bAddon dummyaddon = {NULL};
- PointerRNA dummyhtr;
+ bAddonPrefType *apt, dummy_apt = {{'\0'}};
+ bAddon dummy_addon = {NULL};
+ PointerRNA dummy_ptr;
// int have_function[1];
- /* setup dummy header & header type to store static properties in */
- RNA_pointer_create(NULL, &RNA_AddonPreferences, &dummyaddon, &dummyhtr);
+ /* setup dummy addon-pref & addon-pref type to store static properties in */
+ RNA_pointer_create(NULL, &RNA_AddonPreferences, &dummy_addon, &dummy_ptr);
/* validate the python class */
- if (validate(&dummyhtr, data, NULL /* have_function */ ) != 0)
+ if (validate(&dummy_ptr, data, NULL /* have_function */ ) != 0)
return NULL;
- BLI_strncpy(dummyapt.idname, dummyaddon.module, sizeof(dummyapt.idname));
- if (strlen(identifier) >= sizeof(dummyapt.idname)) {
+ BLI_strncpy(dummy_apt.idname, dummy_addon.module, sizeof(dummy_apt.idname));
+ if (strlen(identifier) >= sizeof(dummy_apt.idname)) {
BKE_reportf(reports, RPT_ERROR, "Registering add-on preferences class: '%s' is too long, maximum length is %d",
- identifier, (int)sizeof(dummyapt.idname));
+ identifier, (int)sizeof(dummy_apt.idname));
return NULL;
}
- /* check if we have registered this header type before, and remove it */
- apt = BKE_addon_pref_type_find(dummyaddon.module, true);
+ /* check if we have registered this addon-pref type before, and remove it */
+ apt = BKE_addon_pref_type_find(dummy_addon.module, true);
if (apt && apt->ext.srna) {
rna_AddonPref_unregister(bmain, apt->ext.srna);
}
- /* create a new header type */
+ /* create a new addon-pref type */
apt = MEM_mallocN(sizeof(bAddonPrefType), "addonpreftype");
- memcpy(apt, &dummyapt, sizeof(dummyapt));
+ memcpy(apt, &dummy_apt, sizeof(dummy_apt));
BKE_addon_pref_type_add(apt);
apt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_AddonPreferences);
@@ -674,6 +599,146 @@ static StructRNA *rna_AddonPref_refine(PointerRNA *ptr)
return (ptr->type) ? ptr->type : &RNA_AddonPreferences;
}
+static float rna_ThemeUI_roundness_get(PointerRNA *ptr)
+{
+ /* Remap from relative radius to 0..1 range. */
+ uiWidgetColors *tui = (uiWidgetColors *)ptr->data;
+ return tui->roundness * 2.0f;
+}
+
+static void rna_ThemeUI_roundness_set(PointerRNA *ptr, float value)
+{
+ uiWidgetColors *tui = (uiWidgetColors *)ptr->data;
+ tui->roundness = value * 0.5f;
+}
+
+/* Studio Light */
+static void rna_UserDef_studiolight_begin(CollectionPropertyIterator *iter, PointerRNA *UNUSED(ptr))
+{
+ rna_iterator_listbase_begin(iter, BKE_studiolight_listbase(), NULL);
+}
+
+static void rna_StudioLights_refresh(UserDef *UNUSED(userdef))
+{
+ BKE_studiolight_refresh();
+}
+
+static void rna_StudioLights_remove(UserDef *UNUSED(userdef), StudioLight *studio_light)
+{
+ BKE_studiolight_remove(studio_light);
+}
+
+static StudioLight *rna_StudioLights_load(UserDef *UNUSED(userdef), const char *path, int type)
+{
+ return BKE_studiolight_load(path, type);
+}
+
+/* TODO: Make it accept arguments. */
+static StudioLight *rna_StudioLights_new(UserDef *userdef, const char *name)
+{
+ return BKE_studiolight_create(name, userdef->light, userdef->light_ambient);
+}
+
+/* StudioLight.name */
+static void rna_UserDef_studiolight_name_get(PointerRNA *ptr, char *value)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ BLI_strncpy(value, sl->name, FILE_MAXFILE);
+}
+
+static int rna_UserDef_studiolight_name_length(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return strlen(sl->name);
+}
+
+/* StudioLight.path */
+static void rna_UserDef_studiolight_path_get(PointerRNA *ptr, char *value)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ BLI_strncpy(value, sl->path, FILE_MAX);
+}
+
+static int rna_UserDef_studiolight_path_length(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return strlen(sl->path);
+}
+
+/* StudioLight.path_irr_cache */
+static void rna_UserDef_studiolight_path_irr_cache_get(PointerRNA *ptr, char *value)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ if (sl->path_irr_cache) {
+ BLI_strncpy(value, sl->path_irr_cache, FILE_MAX);
+ }
+ else {
+ value[0] = '\0';
+ }
+}
+
+static int rna_UserDef_studiolight_path_irr_cache_length(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ if (sl->path_irr_cache) {
+ return strlen(sl->path_irr_cache);
+ }
+ return 0;
+}
+
+/* StudioLight.path_sh_cache */
+static void rna_UserDef_studiolight_path_sh_cache_get(PointerRNA *ptr, char *value)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ if (sl->path_sh_cache) {
+ BLI_strncpy(value, sl->path_sh_cache, FILE_MAX);
+ }
+ else {
+ value[0] = '\0';
+ }
+}
+
+static int rna_UserDef_studiolight_path_sh_cache_length(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ if (sl->path_sh_cache) {
+ return strlen(sl->path_sh_cache);
+ }
+ return 0;
+}
+
+/* StudioLight.index */
+static int rna_UserDef_studiolight_index_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return sl->index;
+}
+
+/* StudioLight.is_user_defined */
+static bool rna_UserDef_studiolight_is_user_defined_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return (sl->flag & STUDIOLIGHT_USER_DEFINED) != 0;
+}
+
+/* StudioLight.type */
+
+static int rna_UserDef_studiolight_type_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return sl->flag & STUDIOLIGHT_FLAG_ORIENTATIONS;
+}
+
+static void rna_UserDef_studiolight_spherical_harmonics_coefficients_get(PointerRNA *ptr, float *values)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ float *value = values;
+ for (int i = 0; i < STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN; i++) {
+ copy_v3_v3(value, sl->spherical_harmonics_coefs[i]);
+ value += 3;
+ }
+}
+
#else
/* TODO(sergey): This technically belongs to blenlib, but we don't link
@@ -844,6 +909,11 @@ static void rna_def_userdef_theme_ui_wcol(BlenderRNA *brna)
RNA_def_property_range(prop, -100, 100);
RNA_def_property_ui_text(prop, "Shade Down", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "roundness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_funcs(prop, "rna_ThemeUI_roundness_get", "rna_ThemeUI_roundness_set", NULL);
+ RNA_def_property_ui_text(prop, "Roundness", "Amount of edge rounding");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_ui_wcol_state(BlenderRNA *brna)
@@ -886,6 +956,16 @@ static void rna_def_userdef_theme_ui_wcol_state(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Driven Selected", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "inner_overridden", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Overridden", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "inner_overridden_sel", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Overridden Selected", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "blend", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop, "Blend", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -909,12 +989,8 @@ static void rna_def_userdef_theme_ui_panel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Background", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "show_header", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_ui_text(prop, "Show Header", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "show_back", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_ui_text(prop, "Show Background", "");
+ prop = RNA_def_property(srna, "sub_back", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_ui_text(prop, "Sub Background", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
@@ -969,6 +1045,11 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tool Widget Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "wcol_toolbar_item", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Toolbar Item Widget Colors", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "wcol_radio", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Radio Widget Colors", "");
@@ -1054,6 +1135,11 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "State Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "wcol_tab", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Tab Colors", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "menu_shadow_fac", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop, "Menu Shadow Strength", "Blending factor for menu shadows");
RNA_def_property_range(prop, 0.01f, 1.0f);
@@ -1073,12 +1159,22 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Icon Alpha", "Transparency of icons in the interface, to reduce contrast");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "icon_saturation", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_ui_text(prop, "Icon Saturation", "Saturation of icons in the interface");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "widget_emboss", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "widget_emboss");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Widget Emboss", "Color of the 1px shadow line underlying widgets");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "editor_outline", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "editor_outline");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Editor Outline", "Color of the outline of the editors and their round corners");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
/* axis */
prop = RNA_def_property(srna, "axis_x", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "xaxis");
@@ -1097,6 +1193,68 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Z Axis", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ /* Generic gizmo colors. */
+ prop = RNA_def_property(srna, "gizmo_hi", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "gizmo_hi");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Gizmo Highlight", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "gizmo_primary", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "gizmo_primary");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Gizmo Primary", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "gizmo_secondary", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "gizmo_secondary");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Gizmo Secondary", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "gizmo_a", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "gizmo_a");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Gizmo A", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "gizmo_b", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "gizmo_b");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Gizmo B", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ /* Icon colors. */
+ prop = RNA_def_property(srna, "icon_collection", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "icon_collection");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Collection", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "icon_object", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "icon_object");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Object", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "icon_object_data", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "icon_object_data");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Object Data", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "icon_modifier", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "icon_modifier");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Modifier", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "icon_shading", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "icon_shading");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Shading", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_space_common(StructRNA *srna)
@@ -1120,7 +1278,7 @@ static void rna_def_userdef_theme_space_common(StructRNA *srna)
/* header */
prop = RNA_def_property(srna, "header", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Header", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -1162,6 +1320,11 @@ static void rna_def_userdef_theme_space_common(StructRNA *srna)
RNA_def_property_ui_text(prop, "Region Text Highlight", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "navigation_bar", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Navigation Bar Background", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
/* tabs */
prop = RNA_def_property(srna, "tab_active", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
@@ -1300,7 +1463,7 @@ static void rna_def_userdef_theme_spaces_vertex(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "vertex_size", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_range(prop, 1, 32);
RNA_def_property_ui_text(prop, "Vertex Size", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -1522,7 +1685,7 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Handle Vertex Size", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
@@ -1565,7 +1728,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
/* General Viewport options */
prop = RNA_def_property(srna, "grid", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Grid", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -1581,7 +1744,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "wire_edit", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Wire Edit", "");
+ RNA_def_property_ui_text(prop, "Wire Edit", "Color for wireframe when in edit mode, but edge selection is active");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -1609,18 +1772,6 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active Object", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "object_grouped", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "group");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Object Grouped", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "object_grouped_active", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "group_active");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Object Grouped Active", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
prop = RNA_def_property(srna, "text_keyframe", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "time_keyframe");
RNA_def_property_array(prop, 3);
@@ -1639,9 +1790,10 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Empty", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "lamp", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "light", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "lamp");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Lamp", "");
+ RNA_def_property_ui_text(prop, "Light", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "speaker", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -1823,6 +1975,12 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active Channel Group", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "preview_range", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "anim_preview_range");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Preview Range", "Color of preview range overlay");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
rna_def_userdef_theme_spaces_vertex(srna);
rna_def_userdef_theme_spaces_curves(srna, false, true, true, true);
}
@@ -2268,23 +2426,6 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
-static void rna_def_userdef_theme_space_logic(BlenderRNA *brna)
-{
- StructRNA *srna;
-// PropertyRNA *prop;
-
- /* space_logic */
-
- srna = RNA_def_struct(brna, "ThemeLogicEditor", NULL);
- RNA_def_struct_sdna(srna, "ThemeSpace");
- RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(srna, "Theme Logic Editor", "Theme settings for the Logic Editor");
-
- rna_def_userdef_theme_spaces_main(srna);
-
-}
-
-
static void rna_def_userdef_theme_space_buts(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2301,44 +2442,6 @@ static void rna_def_userdef_theme_space_buts(BlenderRNA *brna)
}
-static void rna_def_userdef_theme_space_time(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- /* space_time */
-
- srna = RNA_def_struct(brna, "ThemeTimeline", NULL);
- RNA_def_struct_sdna(srna, "ThemeSpace");
- RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(srna, "Theme Timeline", "Theme settings for the Timeline");
-
- rna_def_userdef_theme_spaces_main(srna);
-
- prop = RNA_def_property(srna, "grid", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Grid", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "cframe");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Current Frame", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "time_keyframe", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "time_keyframe");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Keyframe", "Base color for keyframe indicator lines");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "time_grease_pencil", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "time_gp_keyframe");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Grease Pencil", "Color of Grease Pencil keyframes");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-}
-
static void rna_def_userdef_theme_space_image(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2606,51 +2709,51 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
prop = RNA_def_property(srna, "dopesheet_channel", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "ds_channel");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Dope Sheet Channel", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "dopesheet_subchannel", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "ds_subchannel");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Dope Sheet Sub-Channel", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "channels", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "shade2");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Channels", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "channels_selected", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "hilite");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Channels Selected", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "channel_group", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "group");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Channel Group", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "active_channels_group", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "group_active");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Active Channel Group", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "long_key", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "strip");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Long Key", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "long_key_selected", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "strip_select");
- RNA_def_property_array(prop, 3);
+ RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Long Key Selected", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
@@ -2704,6 +2807,18 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Jitter Keyframe Selected", "Color of selected jitter keyframe");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "keyframe_movehold", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "keytype_movehold");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Moving Hold Keyframe", "Color of moving hold keyframe");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "keyframe_movehold_selected", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "keytype_movehold_select");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Moving Hold Keyframe Selected", "Color of selected moving hold keyframe");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "keyframe_border", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "keyborder");
RNA_def_property_array(prop, 4);
@@ -2723,12 +2838,23 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
RNA_def_property_range(prop, 0.8f, 5.0f); /* Note: These limits prevent buttons overlapping (min), and excessive size... (max) */
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, "rna_userdef_update");
-
prop = RNA_def_property(srna, "summary", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "anim_active");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Summary", "Color of summary channel");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "preview_range", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "anim_preview_range");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Preview Range", "Color of preview range overlay");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "interpolation_line", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "ds_ipoline");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Interpolation Line", "Color of lines showing non-bezier interpolation modes");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)
@@ -2740,7 +2866,7 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)
srna = RNA_def_struct(brna, "ThemeNLAEditor", NULL);
RNA_def_struct_sdna(srna, "ThemeSpace");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(srna, "Theme NLA Editor", "Theme settings for the NLA Editor");
+ RNA_def_struct_ui_text(srna, "Theme Nonlinear Animation", "Theme settings for the NLA Editor");
rna_def_userdef_theme_spaces_main(srna);
rna_def_userdef_theme_spaces_list_main(srna);
@@ -2768,6 +2894,12 @@ static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "No Active Action", "Animation data-block doesn't have active action");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "preview_range", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "anim_preview_range");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Preview Range", "Color of preview range overlay");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "strips", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "strip");
RNA_def_property_array(prop, 3);
@@ -2970,32 +3102,60 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
rna_def_userdef_theme_spaces_curves(srna, false, false, false, true);
}
+static void rna_def_userdef_theme_space_topbar(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ /* space_topbar */
+
+ srna = RNA_def_struct(brna, "ThemeTopBar", NULL);
+ RNA_def_struct_sdna(srna, "ThemeSpace");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Theme Top Bar", "Theme settings for the Top Bar");
+
+ rna_def_userdef_theme_spaces_main(srna);
+}
+
+static void rna_def_userdef_theme_space_statusbar(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ /* space_statusbar */
+
+ srna = RNA_def_struct(brna, "ThemeStatusBar", NULL);
+ RNA_def_struct_sdna(srna, "ThemeSpace");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Theme Status Bar", "Theme settings for the Status Bar");
+
+ rna_def_userdef_theme_spaces_main(srna);
+}
+
static void rna_def_userdef_themes(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem active_theme_area[] = {
- {0, "USER_INTERFACE", ICON_UI, "User Interface", ""},
+ {0, "USER_INTERFACE", ICON_WORKSPACE, "User Interface", ""},
{19, "STYLE", ICON_FONTPREVIEW, "Text Style", ""},
{18, "BONE_COLOR_SETS", ICON_COLOR, "Bone Color Sets", ""},
{1, "VIEW_3D", ICON_VIEW3D, "3D View", ""},
- {2, "TIMELINE", ICON_TIME, "Timeline", ""},
- {3, "GRAPH_EDITOR", ICON_IPO, "Graph Editor", ""},
+ {3, "GRAPH_EDITOR", ICON_GRAPH, "Graph Editor", ""},
{4, "DOPESHEET_EDITOR", ICON_ACTION, "Dope Sheet", ""},
- {5, "NLA_EDITOR", ICON_NLA, "NLA Editor", ""},
- {6, "IMAGE_EDITOR", ICON_IMAGE_COL, "UV/Image Editor", ""},
+ {5, "NLA_EDITOR", ICON_NLA, "Nonlinear Animation", ""},
+ {6, "IMAGE_EDITOR", ICON_IMAGE, "UV/Image Editor", ""},
{7, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequence Editor", ""},
{8, "TEXT_EDITOR", ICON_TEXT, "Text Editor", ""},
{9, "NODE_EDITOR", ICON_NODETREE, "Node Editor", ""},
- {10, "LOGIC_EDITOR", ICON_LOGIC, "Logic Editor", ""},
- {11, "PROPERTIES", ICON_BUTS, "Properties", ""},
- {12, "OUTLINER", ICON_OOPS, "Outliner", ""},
+ {11, "PROPERTIES", ICON_PROPERTIES, "Properties", ""},
+ {12, "OUTLINER", ICON_OUTLINER, "Outliner", ""},
{14, "USER_PREFERENCES", ICON_PREFERENCES, "User Preferences", ""},
{15, "INFO", ICON_INFO, "Info", ""},
- {16, "FILE_BROWSER", ICON_FILESEL, "File Browser", ""},
+ {16, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", ""},
{17, "CONSOLE", ICON_CONSOLE, "Python Console", ""},
{20, "CLIP_EDITOR", ICON_CLIP, "Movie Clip Editor", ""},
+ {21, "TOPBAR", ICON_NONE, "Top Bar", ""},
+ {22, "STATUSBAR", ICON_NONE, "Status Bar", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3044,7 +3204,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "tnla");
RNA_def_property_struct_type(prop, "ThemeNLAEditor");
- RNA_def_property_ui_text(prop, "NLA Editor", "");
+ RNA_def_property_ui_text(prop, "Nonlinear Animation", "");
prop = RNA_def_property(srna, "dopesheet_editor", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -3076,24 +3236,12 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ThemeTextEditor");
RNA_def_property_ui_text(prop, "Text Editor", "");
- prop = RNA_def_property(srna, "timeline", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "ttime");
- RNA_def_property_struct_type(prop, "ThemeTimeline");
- RNA_def_property_ui_text(prop, "Timeline", "");
-
prop = RNA_def_property(srna, "node_editor", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "tnode");
RNA_def_property_struct_type(prop, "ThemeNodeEditor");
RNA_def_property_ui_text(prop, "Node Editor", "");
- prop = RNA_def_property(srna, "logic_editor", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_NEVER_NULL);
- RNA_def_property_pointer_sdna(prop, NULL, "tlogic");
- RNA_def_property_struct_type(prop, "ThemeLogicEditor");
- RNA_def_property_ui_text(prop, "Logic Editor", "");
-
prop = RNA_def_property(srna, "outliner", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "toops");
@@ -3129,6 +3277,18 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "tclip");
RNA_def_property_struct_type(prop, "ThemeClipEditor");
RNA_def_property_ui_text(prop, "Clip Editor", "");
+
+ prop = RNA_def_property(srna, "topbar", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "ttopbar");
+ RNA_def_property_struct_type(prop, "ThemeTopBar");
+ RNA_def_property_ui_text(prop, "Top Bar", "");
+
+ prop = RNA_def_property(srna, "statusbar", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "tstatusbar");
+ RNA_def_property_struct_type(prop, "ThemeStatusBar");
+ RNA_def_property_ui_text(prop, "Status Bar", "");
}
static void rna_def_userdef_addon(BlenderRNA *brna)
@@ -3151,6 +3311,97 @@ static void rna_def_userdef_addon(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_Addon_preferences_get", NULL, NULL, NULL);
}
+static void rna_def_userdef_studiolights(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "StudioLights", NULL);
+ RNA_def_struct_sdna(srna, "UserDef");
+ RNA_def_struct_ui_text(srna, "Studio Lights", "Collection of studio lights");
+
+ func = RNA_def_function(srna, "load", "rna_StudioLights_load");
+ RNA_def_function_ui_description(func, "Load studiolight from file");
+ parm = RNA_def_string(func, "path", NULL, 0, "File Path", "File path where the studio light file can be found");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "type", rna_enum_studio_light_type_items, STUDIOLIGHT_TYPE_WORLD, "Type", "The type for the new studio light");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "Newly created StudioLight");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "new", "rna_StudioLights_new");
+ RNA_def_function_ui_description(func, "Create studiolight from default lighting");
+ parm = RNA_def_string(func, "path", NULL, 0, "Path", "Path to the file that will contain the lighing info (without extension)");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "Newly created StudioLight");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_StudioLights_remove");
+ RNA_def_function_ui_description(func, "Remove a studio light");
+ parm = RNA_def_pointer(func, "studio_light", "StudioLight", "", "The studio light to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "refresh", "rna_StudioLights_refresh");
+ RNA_def_function_ui_description(func, "Refresh Studio Lights from disk");
+}
+
+static void rna_def_userdef_studiolight(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ RNA_define_verify_sdna(false);
+ srna = RNA_def_struct(brna, "StudioLight", NULL);
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Studio Light", "Studio light");
+
+ prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_UserDef_studiolight_index_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Index", "");
+
+ prop = RNA_def_property(srna, "is_user_defined", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_UserDef_studiolight_is_user_defined_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "User Defined", "");
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_studio_light_type_items);
+ RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_type_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Type", "");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_UserDef_studiolight_name_get", "rna_UserDef_studiolight_name_length", NULL);
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "path", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_funcs(prop, "rna_UserDef_studiolight_path_get", "rna_UserDef_studiolight_path_length", NULL);
+ RNA_def_property_ui_text(prop, "Path", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "path_irr_cache", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_funcs(prop, "rna_UserDef_studiolight_path_irr_cache_get", "rna_UserDef_studiolight_path_irr_cache_length", NULL);
+ RNA_def_property_ui_text(prop, "Irradiance Cache Path", "Path where the irradiance cache is stored");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "path_sh_cache", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_funcs(prop, "rna_UserDef_studiolight_path_sh_cache_get", "rna_UserDef_studiolight_path_sh_cache_length", NULL);
+ RNA_def_property_ui_text(prop, "SH Cache Path", "Path where the spherical harmonics cache is stored");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ const int spherical_harmonics_dim[] = {STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN, 3};
+ prop = RNA_def_property(srna, "spherical_harmonics_coefficients", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_multi_array(prop, 2, spherical_harmonics_dim);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_UserDef_studiolight_spherical_harmonics_coefficients_get", NULL, NULL);
+
+ RNA_define_verify_sdna(true);
+}
+
static void rna_def_userdef_pathcompare(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3212,14 +3463,14 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna)
rna_def_userdef_theme_space_seq(brna);
rna_def_userdef_theme_space_buts(brna);
rna_def_userdef_theme_space_text(brna);
- rna_def_userdef_theme_space_time(brna);
rna_def_userdef_theme_space_node(brna);
rna_def_userdef_theme_space_outliner(brna);
rna_def_userdef_theme_space_info(brna);
rna_def_userdef_theme_space_userpref(brna);
rna_def_userdef_theme_space_console(brna);
- rna_def_userdef_theme_space_logic(brna);
rna_def_userdef_theme_space_clip(brna);
+ rna_def_userdef_theme_space_topbar(brna);
+ rna_def_userdef_theme_space_statusbar(brna);
rna_def_userdef_theme_colorset(brna);
rna_def_userdef_themes(brna);
}
@@ -3240,6 +3491,13 @@ static void rna_def_userdef_solidlight(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Enabled", "Enable this OpenGL light in solid draw mode");
RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
+ prop = RNA_def_property(srna, "smooth", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "smooth");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Smooth", "Smooth the lighting from this light");
+ RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
+
prop = RNA_def_property(srna, "direction", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_float_sdna(prop, NULL, "vec");
RNA_def_property_array(prop, 3);
@@ -3247,17 +3505,17 @@ static void rna_def_userdef_solidlight(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Direction", "Direction that the OpenGL light is shining");
RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
- prop = RNA_def_property(srna, "diffuse_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "col");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Diffuse Color", "Diffuse color of the OpenGL light");
- RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
-
prop = RNA_def_property(srna, "specular_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "spec");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Specular Color", "Color of the light's specular highlight");
RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
+
+ prop = RNA_def_property(srna, "diffuse_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "col");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Diffuse Color", "Color of the light's diffuse highlight");
+ RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
}
static void rna_def_userdef_walk_navigation(BlenderRNA *brna)
@@ -3366,7 +3624,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tooltips", "Display tooltips (when off hold Alt to force display)");
prop = RNA_def_property(srna, "show_tooltips_python", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_TOOLTIPS_PYTHON);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TOOLTIPS_PYTHON);
RNA_def_property_ui_text(prop, "Python Tooltips", "Show Python references in tooltips");
prop = RNA_def_property(srna, "show_developer_ui", PROP_BOOLEAN, PROP_NONE);
@@ -3380,11 +3638,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display Object Info", "Display objects name and frame number in 3D view");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "use_global_scene", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_SCENEGLOBAL);
- RNA_def_property_ui_text(prop, "Global Scene", "Force the current Scene to be displayed in all Screens");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
prop = RNA_def_property(srna, "show_large_cursors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "curssize", 0);
RNA_def_property_ui_text(prop, "Large Cursors", "Use large mouse cursors when available");
@@ -3412,11 +3665,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Layout Widgets", "Show screen layout editing UI");
RNA_def_property_update(prop, 0, "rna_userdef_update_ui");
- prop = RNA_def_property(srna, "show_view3d_cursor", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "app_flag", USER_APP_VIEW3D_HIDE_CURSOR);
- RNA_def_property_ui_text(prop, "Show 3D View Cursor", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
/* menus */
prop = RNA_def_property(srna, "use_mouse_over_open", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_MENUOPENAUTO);
@@ -3488,10 +3736,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
"Otherwise menus, etc will always be top to bottom, left to right, "
"no matter opening direction");
- prop = RNA_def_property(srna, "use_global_pivot", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCKAROUND);
- RNA_def_property_ui_text(prop, "Global Pivot", "Lock the same rotation/scaling pivot in all 3D Views");
-
prop = RNA_def_property(srna, "use_mouse_depth_navigate", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DEPTH_NAVIGATE);
RNA_def_property_ui_text(prop, "Auto Depth",
@@ -3499,8 +3743,8 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mouse_depth_cursor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DEPTH_CURSOR);
- RNA_def_property_ui_text(prop, "Cursor Depth",
- "Use the depth under the mouse when placing the cursor");
+ RNA_def_property_ui_text(prop, "Cursor Surface Project",
+ "Use the surface depth for cursor placement");
prop = RNA_def_property(srna, "use_cursor_lock_adjust", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCK_CURSOR_ADJUST);
@@ -3532,10 +3776,17 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rotate Around Selection", "Use selection as the pivot point");
/* mini axis */
- prop = RNA_def_property(srna, "show_mini_axis", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_ROTVIEWICON);
- RNA_def_property_ui_text(prop, "Show Mini Axes",
- "Show a small rotating 3D axes in the bottom left corner of the 3D View");
+ static const EnumPropertyItem mini_axis_type_items[] = {
+ {0, "MINIMAL", 0, "Simple Axis", ""},
+ {USER_SHOW_GIZMO_AXIS, "GIZMO", 0, "Interactive Navigation", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "mini_axis_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mini_axis_type_items);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "uiflag");
+ RNA_def_property_ui_text(prop, "Mini Axes Type",
+ "Show a small rotating 3D axes in the top right corner of the 3D View");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "mini_axis_size", PROP_INT, PROP_NONE);
@@ -3561,35 +3812,22 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rotation Angle", "Rotation step for numerical pad keys (2 4 6 8)");
/* 3D transform widget */
- prop = RNA_def_property(srna, "show_manipulator", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "tw_flag", V3D_USE_MANIPULATOR);
- RNA_def_property_ui_text(prop, "Manipulator", "Use 3D transform manipulator");
- RNA_def_property_update(prop, 0, "rna_userdef_show_manipulator_update");
+ prop = RNA_def_property(srna, "show_gizmo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gizmo_flag", USER_GIZMO_DRAW);
+ RNA_def_property_ui_text(prop, "Gizmos", "Use transform gizmos by default");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "manipulator_size", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "tw_size");
+ prop = RNA_def_property(srna, "gizmo_size", PROP_INT, PROP_PIXEL);
+ RNA_def_property_int_sdna(prop, NULL, "gizmo_size");
RNA_def_property_range(prop, 10, 200);
RNA_def_property_int_default(prop, 75);
- RNA_def_property_ui_text(prop, "Manipulator Size", "Diameter of the manipulator");
+ RNA_def_property_ui_text(prop, "Gizmo Size", "Diameter of the gizmo");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "manipulator_handle_size", PROP_INT, PROP_PERCENTAGE);
- RNA_def_property_int_sdna(prop, NULL, "tw_handlesize");
- RNA_def_property_range(prop, 2, 40);
- RNA_def_property_int_default(prop, 25);
- RNA_def_property_ui_text(prop, "Manipulator Handle Size", "Size of manipulator handles as percentage of the radius");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "manipulator_hotspot", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "tw_hotspot");
- RNA_def_property_range(prop, 4, 40);
- RNA_def_property_int_default(prop, 14);
- RNA_def_property_ui_text(prop, "Manipulator Hotspot", "Distance around the handles to accept mouse clicks");
-
prop = RNA_def_property(srna, "object_origin_size", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "obcenter_dia");
RNA_def_property_range(prop, 4, 10);
- RNA_def_property_ui_text(prop, "Object Origin Size", "Diameter in Pixels for Object/Lamp origin display");
+ RNA_def_property_ui_text(prop, "Object Origin Size", "Diameter in Pixels for Object/Light origin display");
RNA_def_property_update(prop, 0, "rna_userdef_update");
/* View2D Grid Displays */
@@ -3680,6 +3918,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Release confirms",
"Moving things with a mouse drag confirms when releasing the button");
+ prop = RNA_def_property(srna, "use_numeric_input_advanced", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_FLAG_NUMINPUT_ADVANCED);
+ RNA_def_property_ui_text(
+ prop, "Default to Advanced Numeric Input",
+ "When entering numbers while transforming, "
+ "default to advanced mode for full math expression evaluation");
+
+
/* Undo */
prop = RNA_def_property(srna, "undo_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "undosteps");
@@ -3786,11 +4032,10 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_range(prop, 1, 500);
RNA_def_property_ui_text(prop, "Grease Pencil Eraser Radius", "Radius of eraser 'brush'");
-
prop = RNA_def_property(srna, "grease_pencil_default_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "gpencil_new_layer_col");
RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Grease Pencil Default Color", "Color of new Grease Pencil layers");
+ RNA_def_property_ui_text(prop, "Annotation Default Color", "Color of new annotation layers");
/* sculpt and paint */
@@ -3824,9 +4069,9 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_ARM);
RNA_def_property_ui_text(prop, "Duplicate Armature", "Causes armature data to be duplicated with the object");
- prop = RNA_def_property(srna, "use_duplicate_lamp", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_duplicate_light", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_LAMP);
- RNA_def_property_ui_text(prop, "Duplicate Lamp", "Causes lamp data to be duplicated with the object");
+ RNA_def_property_ui_text(prop, "Duplicate Light", "Causes light data to be duplicated with the object");
prop = RNA_def_property(srna, "use_duplicate_material", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_MAT);
@@ -3927,20 +4172,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem draw_method_items[] = {
- {USER_DRAW_AUTOMATIC, "AUTOMATIC", 0, "Automatic", "Automatically set based on graphics card and driver"},
- {USER_DRAW_TRIPLE, "TRIPLE_BUFFER", 0, "Triple Buffer",
- "Use a third buffer for minimal redraws at the cost of more memory"},
- {USER_DRAW_OVERLAP, "OVERLAP", 0, "Overlap",
- "Redraw all overlapping regions, minimal memory usage but more redraws"},
- {USER_DRAW_OVERLAP_FLIP, "OVERLAP_FLIP", 0, "Overlap Flip",
- "Redraw all overlapping regions, minimal memory usage but more redraws "
- "(for graphics drivers that do flipping)"},
- {USER_DRAW_FULL, "FULL", 0, "Full",
- "Do a full redraw each time, slow, only use for reference or when everything else fails"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem color_picker_types[] = {
{USER_CP_CIRCLE_HSV, "CIRCLE_HSV", 0, "Circle (HSV)", "A circular Hue/Saturation color wheel, with Value slider"},
{USER_CP_CIRCLE_HSL, "CIRCLE_HSL", 0, "Circle (HSL)", "A circular Hue/Saturation color wheel, with Lightness slider"},
@@ -3987,27 +4218,29 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
RNA_def_struct_ui_text(srna, "System & OpenGL", "Graphics driver and operating system settings");
- /* Language */
+ /* UI settings. */
- prop = RNA_def_property(srna, "use_international_fonts", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_DOTRANSLATE);
- RNA_def_property_ui_text(prop, "International Fonts", "Use international fonts");
- RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
+ prop = RNA_def_property(srna, "ui_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_sdna(prop, NULL, "dpi_fac");
+ RNA_def_property_ui_text(prop, "UI Scale",
+ "Size multiplier to use when drawing custom user interface elements, so that "
+ "they are scaled correctly on screens with different DPI. This value is based "
+ "on operating system DPI settings and Blender display scale");
+
+ prop = RNA_def_property(srna, "ui_line_width", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_sdna(prop, NULL, "pixelsize");
+ RNA_def_property_ui_text(prop, "UI Line Width",
+ "Suggested line thickness and point size in pixels, for add-ons drawing custom "
+ "user interface elements, based on operating system settings and Blender UI scale");
prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "DPI",
- "DPI for add-ons to use when drawing custom user interface elements, controlled by "
- "operating system settings and Blender UI scale, with a reference value of 72 DPI "
- "(note that since this value includes a user defined scale, it is not always the "
- "actual monitor DPI)");
prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_sdna(prop, NULL, "pixelsize");
- RNA_def_property_ui_text(prop, "Pixel Size",
- "Suggested line thickness and point size in pixels, for add-ons drawing custom user "
- "interface elements, controlled by operating system settings and Blender UI scale");
prop = RNA_def_property(srna, "font_path_ui", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "font_path_ui");
@@ -4030,7 +4263,12 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Author",
"Name that will be used in exported files when format supports such feature");
- /* Language Selection */
+ /* Language. */
+
+ prop = RNA_def_property(srna, "use_international_fonts", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_DOTRANSLATE);
+ RNA_def_property_ui_text(prop, "Translate UI", "Enable UI translation and use international fonts");
+ RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
prop = RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_language_default_items);
@@ -4042,17 +4280,21 @@ static void rna_def_userdef_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_translate_tooltips", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_TOOLTIPS);
- RNA_def_property_ui_text(prop, "Translate Tooltips", "Translate tooltips");
+ RNA_def_property_ui_text(prop, "Translate Tooltips",
+ "Translate the descriptions when hovering UI elements (recommended)");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "use_translate_interface", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_IFACE);
- RNA_def_property_ui_text(prop, "Translate Interface", "Translate interface");
+ RNA_def_property_ui_text(prop, "Translate Interface",
+ "Translate all labels in menus, buttons and panels "
+ "(note that this might make it hard to follow tutorials or the manual)");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "use_translate_new_dataname", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_TR_NEWDATANAME);
- RNA_def_property_ui_text(prop, "Translate New Names", "Translate new data names (when adding/creating some)");
+ RNA_def_property_ui_text(prop, "Translate New Names",
+ "Translate the names of new data-blocks (objects, materials...)");
RNA_def_property_update(prop, 0, "rna_userdef_update");
/* System & OpenGL */
@@ -4062,6 +4304,18 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "UserSolidLight");
RNA_def_property_ui_text(prop, "Solid Lights", "Lights user to display objects in solid draw mode");
+ prop = RNA_def_property(srna, "light_ambient", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "light_ambient");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Ambient Color", "Color of the ambient light that uniformly lit the scene");
+ RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
+
+ prop = RNA_def_property(srna, "edit_solid_light", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edit_solid_light", 1);
+ RNA_def_property_ui_text(prop, "Edit Solid Light",
+ "View the result of the solid lights in the viewport");
+ RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update");
+
prop = RNA_def_property(srna, "use_weight_color_range", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_CUSTOM_RANGE);
RNA_def_property_ui_text(prop, "Use Weight Color Range",
@@ -4111,24 +4365,12 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Memory Cache Limit", "Memory cache limit (in megabytes)");
RNA_def_property_update(prop, 0, "rna_Userdef_memcache_update");
- prop = RNA_def_property(srna, "frame_server_port", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "frameserverport");
- RNA_def_property_range(prop, 0, 32727);
- RNA_def_property_ui_text(prop, "Frame Server Port", "Frameserver Port for Frameserver Rendering");
-
prop = RNA_def_property(srna, "gl_clip_alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "glalphaclip");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Clip Alpha", "Clip alpha below this threshold in the 3D textured view");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "use_mipmaps", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_MIPMAP);
- RNA_def_property_ui_text(prop, "Mipmaps",
- "Scale textures for the 3D View (looks nicer but uses more memory and slows image "
- "reloading)");
- RNA_def_property_update(prop, 0, "rna_userdef_mipmap_update");
-
prop = RNA_def_property(srna, "use_16bit_textures", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_16bit_textures", 1);
RNA_def_property_ui_text(prop, "16 Bit Float Textures", "Use 16 bit per component texture for float images");
@@ -4173,12 +4415,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture Collection Rate",
"Number of seconds between each run of the GL texture garbage collector");
- prop = RNA_def_property(srna, "window_draw_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "wmdrawmethod");
- RNA_def_property_enum_items(prop, draw_method_items);
- RNA_def_property_ui_text(prop, "Window Draw Method", "Drawing method used by the window manager");
- RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
prop = RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mixbufsize");
RNA_def_property_enum_items(prop, audio_mixing_samples_items);
@@ -4237,6 +4473,15 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_enum_items(prop, multi_sample_levels);
RNA_def_property_ui_text(prop, "MultiSample",
"Enable OpenGL multi-sampling, only for systems that support it, requires restart");
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
+
+ /* grease pencil anti-aliasing */
+ prop = RNA_def_property(srna, "gpencil_multi_sample", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_multisamples");
+ RNA_def_property_enum_items(prop, multi_sample_levels);
+ RNA_def_property_ui_text(prop, "Gpencil MultiSample",
+ "Enable Grease Pencil OpenGL multi-sampling, only for systems that support it");
+ RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
prop = RNA_def_property(srna, "use_region_overlap", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP);
@@ -4244,6 +4489,14 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"Draw tool/property regions over the main region, when using Triple Buffer");
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
+ prop = RNA_def_property(srna, "gpu_viewport_quality", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "gpu_viewport_quality");
+ RNA_def_property_float_default(prop, 0.6f);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Viewport Quality", "Quality setting for Solid mode rendering in the 3d viewport");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+
#ifdef WITH_OPENSUBDIV
prop = RNA_def_property(srna, "opensubdiv_compute_type", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
@@ -4268,12 +4521,6 @@ static void rna_def_userdef_input(BlenderRNA *brna)
PropertyRNA *prop;
StructRNA *srna;
- static const EnumPropertyItem select_mouse_items[] = {
- {USER_LMOUSESELECT, "LEFT", 0, "Left", "Use left Mouse Button for selection"},
- {0, "RIGHT", 0, "Right", "Use Right Mouse Button for selection"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem view_rotation_items[] = {
{0, "TURNTABLE", 0, "Turntable", "Use turntable style rotation in the viewport"},
{USER_TRACKBALL, "TRACKBALL", 0, "Trackball", "Use trackball style rotation in the viewport"},
@@ -4314,11 +4561,9 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
RNA_def_struct_ui_text(srna, "Input", "Settings for input devices");
- prop = RNA_def_property(srna, "select_mouse", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, select_mouse_items);
- RNA_def_property_enum_funcs(prop, NULL, "rna_userdef_select_mouse_set", NULL);
- RNA_def_property_ui_text(prop, "Select Mouse", "Mouse button used for selection");
+ prop = RNA_def_property(srna, "show_ui_keyconfig", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "userpref_flag", USER_SECTION_INPUT_HIDE_UI_KEYCONFIG);
+ RNA_def_property_ui_text(prop, "Show UI Key-Config", "");
prop = RNA_def_property(srna, "view_zoom_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "viewzoom");
@@ -4370,6 +4615,20 @@ static void rna_def_userdef_input(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tweak Threshold",
"Number of pixels you have to drag before tweak event is triggered");
+ /* tablet pressure curve */
+ prop = RNA_def_property(srna, "pressure_threshold_max", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.01f, 3);
+ RNA_def_property_ui_text(prop, "Max Threshold",
+ "Raw input pressure value that is interpreted as 100% by Blender");
+
+ prop = RNA_def_property(srna, "pressure_softness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1f, 2);
+ RNA_def_property_ui_text(prop, "Softness",
+ "Adjusts softness of the low pressure response onset using a gamma curve");
+
#ifdef WITH_INPUT_NDOF
/* 3D mouse settings */
/* global options */
@@ -4699,13 +4958,26 @@ void RNA_def_userdef(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem user_pref_sections[] = {
+ {0, "", ICON_USER, "User Preferences", ""},
{USER_SECTION_INTERFACE, "INTERFACE", 0, "Interface", ""},
{USER_SECTION_EDIT, "EDITING", 0, "Editing", ""},
{USER_SECTION_INPUT, "INPUT", 0, "Input", ""},
{USER_SECTION_ADDONS, "ADDONS", 0, "Add-ons", ""},
{USER_SECTION_THEME, "THEMES", 0, "Themes", ""},
- {USER_SECTION_FILE, "FILES", 0, "File", ""},
- {USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""},
+ {USER_SECTION_LIGHT, "LIGHTS", 0, "Lights", ""},
+#ifdef WITH_USERDEF_WORKSPACES
+ {0, "", ICON_WORKSPACE, "Workspaces", ""},
+ {USER_SECTION_WORKSPACE_CONFIG, "WORKSPACE_CONFIG", 0, "Configuration File", ""},
+ {USER_SECTION_WORKSPACE_ADDONS, "WORKSPACE_ADDONS", 0, "Add-on Overrides", ""},
+ {USER_SECTION_WORKSPACE_KEYMAPS, "WORKSPACE_KEYMAPS", 0, "Keymap Overrides", ""},
+#endif
+ {0, "", ICON_SYSTEM, "System", ""},
+ {USER_SECTION_SYSTEM_GENERAL, "SYSTEM_GENERAL", 0, "General", ""},
+ {USER_SECTION_SYSTEM_FILES, "SYSTEM_FILES", 0, "Files", ""},
+#ifdef WITH_USERDEF_SYSTEM_SPLIT
+ {USER_SECTION_SYSTEM_DISPLAY, "SYSTEM_DISPLAY", 0, "Display", ""},
+ {USER_SECTION_SYSTEM_DEVICES, "SYSTEM_DEVICES", 0, "Devices", ""},
+#endif
{0, NULL, 0, NULL, NULL}
};
@@ -4789,6 +5061,16 @@ void RNA_def_userdef(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_flag(prop, PROP_THICK_WRAP);
+ /* StudioLight Collection */
+ prop = RNA_def_property(srna, "studio_lights", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "StudioLight");
+ RNA_def_property_srna(prop, "StudioLights");
+ RNA_def_property_collection_funcs(
+ prop, "rna_UserDef_studiolight_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Studio Lights", "");
+
rna_def_userdef_view(brna);
rna_def_userdef_edit(brna);
rna_def_userdef_input(brna);
@@ -4796,6 +5078,8 @@ void RNA_def_userdef(BlenderRNA *brna)
rna_def_userdef_system(brna);
rna_def_userdef_addon(brna);
rna_def_userdef_addon_pref(brna);
+ rna_def_userdef_studiolights(brna);
+ rna_def_userdef_studiolight(brna);
rna_def_userdef_pathcompare(brna);
}
diff --git a/source/blender/makesrna/intern/rna_vfont.c b/source/blender/makesrna/intern/rna_vfont.c
index 5c42a86c52e..487b5220c86 100644
--- a/source/blender/makesrna/intern/rna_vfont.c
+++ b/source/blender/makesrna/intern/rna_vfont.c
@@ -38,9 +38,10 @@
#ifdef RNA_RUNTIME
#include "BKE_font.h"
-#include "BKE_depsgraph.h"
#include "DNA_object_types.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
/* matching fnction in rna_ID.c */
@@ -60,7 +61,7 @@ static void rna_VectorFont_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scen
/* update */
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
- DAG_id_tag_update(&vf->id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(&vf->id, OB_RECALC_OB | OB_RECALC_DATA);
}
#else
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 9b2cc850169..77a10e6dbbc 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -36,6 +36,9 @@
#include "BLT_translation.h"
+#include "BKE_workspace.h"
+#include "BKE_keyconfig.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -72,8 +75,6 @@ static const EnumPropertyItem event_tweak_type_items[] = {
{EVT_TWEAK_L, "EVT_TWEAK_L", 0, "Left", ""},
{EVT_TWEAK_M, "EVT_TWEAK_M", 0, "Middle", ""},
{EVT_TWEAK_R, "EVT_TWEAK_R", 0, "Right", ""},
- {EVT_TWEAK_A, "EVT_TWEAK_A", 0, "Action", ""},
- {EVT_TWEAK_S, "EVT_TWEAK_S", 0, "Select", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -85,8 +86,6 @@ static const EnumPropertyItem event_mouse_type_items[] = {
{BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5", ""},
{BUTTON6MOUSE, "BUTTON6MOUSE", 0, "Button6", ""},
{BUTTON7MOUSE, "BUTTON7MOUSE", 0, "Button7", ""},
- {ACTIONMOUSE, "ACTIONMOUSE", 0, "Action", ""},
- {SELECTMOUSE, "SELECTMOUSE", 0, "Select", ""},
{0, "", 0, NULL, NULL},
{TABLET_STYLUS, "PEN", 0, "Pen", ""},
{TABLET_ERASER, "ERASER", 0, "Eraser", ""},
@@ -182,8 +181,6 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5 Mouse", "MB5"},
{BUTTON6MOUSE, "BUTTON6MOUSE", 0, "Button6 Mouse", "MB6"},
{BUTTON7MOUSE, "BUTTON7MOUSE", 0, "Button7 Mouse", "MB7"},
- {ACTIONMOUSE, "ACTIONMOUSE", 0, "Action Mouse", "MBA"},
- {SELECTMOUSE, "SELECTMOUSE", 0, "Select Mouse", "MBS"},
{0, "", 0, NULL, NULL},
{TABLET_STYLUS, "PEN", 0, "Pen", ""},
{TABLET_ERASER, "ERASER", 0, "Eraser", ""},
@@ -202,8 +199,6 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{EVT_TWEAK_L, "EVT_TWEAK_L", 0, "Tweak Left", "TwkL"},
{EVT_TWEAK_M, "EVT_TWEAK_M", 0, "Tweak Middle", "TwkM"},
{EVT_TWEAK_R, "EVT_TWEAK_R", 0, "Tweak Right", "TwkR"},
- {EVT_TWEAK_A, "EVT_TWEAK_A", 0, "Tweak Action", "TwkA"},
- {EVT_TWEAK_S, "EVT_TWEAK_S", 0, "Tweak Select", "TwkS"},
{0, "", 0, NULL, NULL},
{AKEY, "A", 0, "A", ""},
{BKEY, "B", 0, "B", ""},
@@ -434,6 +429,8 @@ static const EnumPropertyItem operator_flag_items[] = {
"is enabled"},
{OPTYPE_PRESET, "PRESET", 0, "Preset", "Display a preset button with the operators settings"},
{OPTYPE_INTERNAL, "INTERNAL", 0, "Internal", "Removes the operator from search results"},
+ {OPTYPE_USE_EVAL_DATA, "USE_EVAL_DATA", 0, "Use Evaluated Data",
+ "Uses evaluated data (i.e. needs a valid depsgraph for current context)"},
{0, NULL, 0, NULL, NULL}
};
#endif
@@ -448,6 +445,11 @@ const EnumPropertyItem rna_enum_operator_return_items[] = {
{0, NULL, 0, NULL, NULL}
};
+const EnumPropertyItem rna_enum_operator_property_tags[] = {
+ {OP_PROP_TAG_ADVANCED, "ADVANCED", 0, "Advanced", "The property is advanced so UI is suggested to hide it"},
+ {0, NULL, 0, NULL, NULL}
+};
+
/* flag/enum */
const EnumPropertyItem rna_enum_wm_report_items[] = {
{RPT_DEBUG, "DEBUG", 0, "Debug", ""},
@@ -468,12 +470,23 @@ const EnumPropertyItem rna_enum_wm_report_items[] = {
#include "WM_api.h"
+#include "DNA_object_types.h"
+#include "DNA_workspace_types.h"
+
+#include "ED_screen.h"
+
#include "UI_interface.h"
+#include "BKE_global.h"
#include "BKE_idprop.h"
#include "MEM_guardedalloc.h"
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+
static wmOperator *rna_OperatorProperties_find_operator(PointerRNA *ptr)
{
wmWindowManager *wm = ptr->id.data;
@@ -617,6 +630,17 @@ static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr)
return rptr;
}
+static PointerRNA rna_PopoverMenu_layout_get(PointerRNA *ptr)
+{
+ struct uiPopover *pup = ptr->data;
+ uiLayout *layout = UI_popover_layout(pup);
+
+ PointerRNA rptr;
+ RNA_pointer_create(ptr->id.data, &RNA_UILayout, layout, &rptr);
+
+ return rptr;
+}
+
static PointerRNA rna_PieMenu_layout_get(PointerRNA *ptr)
{
struct uiPieMenu *pie = ptr->data;
@@ -628,42 +652,142 @@ static PointerRNA rna_PieMenu_layout_get(PointerRNA *ptr)
return rptr;
}
-static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
+static void rna_Window_scene_set(PointerRNA *ptr, PointerRNA value)
+{
+ wmWindow *win = ptr->data;
+
+ if (value.data == NULL) {
+ return;
+ }
+
+ win->new_scene = value.data;
+}
+
+static void rna_Window_scene_update(bContext *C, PointerRNA *ptr)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = ptr->data;
+
+ /* exception: must use context so notifier gets to the right window */
+ if (win->new_scene) {
+#ifdef WITH_PYTHON
+ BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+ WM_window_set_active_scene(bmain, C, win, win->new_scene);
+
+#ifdef WITH_PYTHON
+ BPy_END_ALLOW_THREADS;
+#endif
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, win->new_scene);
+
+ if (G.debug & G_DEBUG)
+ printf("scene set %p\n", win->new_scene);
+
+ win->new_scene = NULL;
+ }
+}
+
+static PointerRNA rna_Window_workspace_get(PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_WorkSpace, BKE_workspace_active_get(win->workspace_hook));
+}
+
+static void rna_Window_workspace_set(PointerRNA *ptr, PointerRNA value)
{
wmWindow *win = (wmWindow *)ptr->data;
/* disallow ID-browsing away from temp screens */
- if (win->screen->temp) {
+ if (WM_window_is_temp_screen(win)) {
return;
}
+ if (value.data == NULL) {
+ return;
+ }
+
+ /* exception: can't set workspaces inside of area/region handlers */
+ win->workspace_hook->temp_workspace_store = value.data;
+}
+
+static void rna_Window_workspace_update(bContext *C, PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ WorkSpace *new_workspace = win->workspace_hook->temp_workspace_store;
+
+ /* exception: can't set screens inside of area/region handlers,
+ * and must use context so notifier gets to the right window */
+ if (new_workspace) {
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, new_workspace);
+ win->workspace_hook->temp_workspace_store = NULL;
+ }
+}
+
+PointerRNA rna_Window_screen_get(PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_Screen, BKE_workspace_active_screen_get(win->workspace_hook));
+}
- if (value.data == NULL)
+static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
+{
+ wmWindow *win = ptr->data;
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout_new;
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ /* disallow ID-browsing away from temp screens */
+ if (screen->temp) {
return;
+ }
+ if (value.data == NULL) {
+ return;
+ }
/* exception: can't set screens inside of area/region handlers */
- win->newscreen = value.data;
+ layout_new = BKE_workspace_layout_find(workspace, value.data);
+ win->workspace_hook->temp_layout_store = layout_new;
}
static bool rna_Window_screen_assign_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
- bScreen *screen = (bScreen *)value.id.data;
-
+ bScreen *screen = value.id.data;
return !screen->temp;
}
-
-static void rna_Window_screen_update(bContext *C, PointerRNA *ptr)
+static void rna_workspace_screen_update(bContext *C, PointerRNA *ptr)
{
- wmWindow *win = (wmWindow *)ptr->data;
+ wmWindow *win = ptr->data;
+ WorkSpaceLayout *layout_new = win->workspace_hook->temp_layout_store;
/* exception: can't set screens inside of area/region handlers,
* and must use context so notifier gets to the right window */
- if (win->newscreen) {
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENBROWSE, win->newscreen);
- win->newscreen = NULL;
+ if (layout_new) {
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new);
+ win->workspace_hook->temp_layout_store = NULL;
}
}
+static PointerRNA rna_Window_view_layer_get(PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ PointerRNA scene_ptr;
+
+ RNA_id_pointer_create(&scene->id, &scene_ptr);
+ return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, view_layer);
+}
+
+static void rna_Window_view_layer_set(PointerRNA *ptr, PointerRNA value)
+{
+ wmWindow *win = ptr->data;
+ ViewLayer *view_layer = value.data;
+
+ WM_window_set_active_view_layer(win, view_layer);
+}
+
static PointerRNA rna_KeyMapItem_properties_get(PointerRNA *ptr)
{
wmKeyMapItem *kmi = ptr->data;
@@ -863,6 +987,107 @@ static void rna_WindowManager_active_keyconfig_set(PointerRNA *ptr, PointerRNA v
WM_keyconfig_set_active(wm, kc->idname);
}
+/* -------------------------------------------------------------------- */
+/** \name Key Config Preferences
+ * \{ */
+
+static PointerRNA rna_wmKeyConfig_preferences_get(PointerRNA *ptr)
+{
+ wmKeyConfig *kc = ptr->data;
+ wmKeyConfigPrefType_Runtime *kpt_rt = BKE_keyconfig_pref_type_find(kc->idname, true);
+ if (kpt_rt) {
+ wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(&U, kc->idname);
+ return rna_pointer_inherit_refine(ptr, kpt_rt->ext.srna, kpt->prop);
+ }
+ else {
+ return PointerRNA_NULL;
+ }
+}
+
+static IDProperty *rna_wmKeyConfigPref_idprops(PointerRNA *ptr, bool create)
+{
+ if (create && !ptr->data) {
+ IDPropertyTemplate val = {0};
+ ptr->data = IDP_New(IDP_GROUP, &val, "RNA_KeyConfigPreferences group");
+ }
+ return ptr->data;
+}
+
+static void rna_wmKeyConfigPref_unregister(Main *UNUSED(bmain), StructRNA *type)
+{
+ wmKeyConfigPrefType_Runtime *kpt_rt = RNA_struct_blender_type_get(type);
+
+ if (!kpt_rt)
+ return;
+
+ RNA_struct_free_extension(type, &kpt_rt->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
+
+ /* Possible we're not in the preferences if they have been reset. */
+ BKE_keyconfig_pref_type_remove(kpt_rt);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_WINDOW, NULL);
+}
+
+static StructRNA *rna_wmKeyConfigPref_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+ wmKeyConfigPrefType_Runtime *kpt_rt, dummy_kpt_rt = {{'\0'}};
+ wmKeyConfigPref dummy_kpt = {NULL};
+ PointerRNA dummy_ptr;
+ // int have_function[1];
+
+ /* setup dummy keyconf-prefs & keyconf-prefs type to store static properties in */
+ RNA_pointer_create(NULL, &RNA_KeyConfigPreferences, &dummy_kpt, &dummy_ptr);
+
+ /* validate the python class */
+ if (validate(&dummy_ptr, data, NULL /* have_function */ ) != 0)
+ return NULL;
+
+ STRNCPY(dummy_kpt_rt.idname, dummy_kpt.idname);
+ if (strlen(identifier) >= sizeof(dummy_kpt_rt.idname)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering key-config preferences class: '%s' is too long, maximum length is %d",
+ identifier, (int)sizeof(dummy_kpt_rt.idname));
+ return NULL;
+ }
+
+ /* check if we have registered this keyconf-prefs type before, and remove it */
+ kpt_rt = BKE_keyconfig_pref_type_find(dummy_kpt.idname, true);
+ if (kpt_rt && kpt_rt->ext.srna) {
+ rna_wmKeyConfigPref_unregister(bmain, kpt_rt->ext.srna);
+ }
+
+ /* create a new keyconf-prefs type */
+ kpt_rt = MEM_mallocN(sizeof(wmKeyConfigPrefType_Runtime), "keyconfigpreftype");
+ memcpy(kpt_rt, &dummy_kpt_rt, sizeof(dummy_kpt_rt));
+
+ BKE_keyconfig_pref_type_add(kpt_rt);
+
+ kpt_rt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_KeyConfigPreferences);
+ kpt_rt->ext.data = data;
+ kpt_rt->ext.call = call;
+ kpt_rt->ext.free = free;
+ RNA_struct_blender_type_set(kpt_rt->ext.srna, kpt_rt);
+
+// kpt_rt->draw = (have_function[0]) ? header_draw : NULL;
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_WINDOW, NULL);
+
+ return kpt_rt->ext.srna;
+}
+
+/* placeholder, doesn't do anything useful yet */
+static StructRNA *rna_wmKeyConfigPref_refine(PointerRNA *ptr)
+{
+ return (ptr->type) ? ptr->type : &RNA_KeyConfigPreferences;
+}
+
+/** \} */
+
+
static void rna_wmKeyMapItem_idname_get(PointerRNA *ptr, char *value)
{
wmKeyMapItem *kmi = ptr->data;
@@ -1199,6 +1424,7 @@ static StructRNA *rna_Operator_register(
/* create a new operator type */
dummyot.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
RNA_def_struct_flag(dummyot.ext.srna, STRUCT_NO_IDPROPERTIES); /* operator properties are registered separately */
+ RNA_def_struct_property_tags(dummyot.ext.srna, rna_enum_operator_property_tags);
RNA_def_struct_translation_context(dummyot.ext.srna, dummyot.translation_context);
dummyot.ext.data = data;
dummyot.ext.call = call;
@@ -1558,6 +1784,7 @@ static void rna_def_operator(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Operator Properties", "Input properties of an Operator");
RNA_def_struct_refine_func(srna, "rna_OperatorProperties_refine");
RNA_def_struct_idprops_func(srna, "rna_OperatorProperties_idprops");
+ RNA_def_struct_property_tags(srna, rna_enum_operator_property_tags);
RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
}
@@ -1863,6 +2090,11 @@ static void rna_def_popupmenu(BlenderRNA *brna)
rna_def_popup_menu_wrapper(brna, "UIPopupMenu", "uiPopupMenu", "rna_PopupMenu_layout_get");
}
+static void rna_def_popovermenu(BlenderRNA *brna)
+{
+ rna_def_popup_menu_wrapper(brna, "UIPopover", "uiPopover", "rna_PopoverMenu_layout_get");
+}
+
static void rna_def_piemenu(BlenderRNA *brna)
{
rna_def_popup_menu_wrapper(brna, "UIPieMenu", "uiPieMenu", "rna_PieMenu_layout_get");
@@ -1908,16 +2140,40 @@ static void rna_def_window(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Window", "Open window");
RNA_def_struct_sdna(srna, "wmWindow");
+ prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Parent Window", "Active workspace and scene follow this window");
+
rna_def_window_stereo3d(brna);
- prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
+ prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_Window_scene_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Scene", "Active scene to be edited in the window");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, 0, "rna_Window_scene_update");
+
+ prop = RNA_def_property(srna, "workspace", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "WorkSpace");
+ RNA_def_property_ui_text(prop, "Workspace", "Active workspace showing in the window");
+ RNA_def_property_pointer_funcs(prop, "rna_Window_workspace_get", "rna_Window_workspace_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, 0, "rna_Window_workspace_update");
+
+ prop = RNA_def_property(srna, "screen", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Screen");
- RNA_def_property_ui_text(prop, "Screen", "Active screen showing in the window");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_pointer_funcs(prop, NULL, "rna_Window_screen_set", NULL, "rna_Window_screen_assign_poll");
- RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, 0, "rna_Window_screen_update");
+ RNA_def_property_ui_text(prop, "Screen", "Active workspace screen showing in the window");
+ RNA_def_property_pointer_funcs(prop, "rna_Window_screen_get", "rna_Window_screen_set", NULL,
+ "rna_Window_screen_assign_poll");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL | PROP_EDITABLE | PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, 0, "rna_workspace_screen_update");
+
+ prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ViewLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Window_view_layer_get", "rna_Window_view_layer_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active View Layer", "The active workspace view layer showing in the window");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL);
prop = RNA_def_property(srna, "x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "posx");
@@ -2044,6 +2300,28 @@ static void rna_def_wm_keymaps(BlenderRNA *brna, PropertyRNA *cprop)
RNA_api_keymaps(srna);
}
+static void rna_def_keyconfig_prefs(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "KeyConfigPreferences", NULL);
+ RNA_def_struct_ui_text(srna, "Key-Config Preferences", "");
+ RNA_def_struct_sdna(srna, "wmKeyConfigPref"); /* WARNING: only a bAddon during registration */
+
+ RNA_def_struct_refine_func(srna, "rna_wmKeyConfigPref_refine");
+ RNA_def_struct_register_funcs(srna, "rna_wmKeyConfigPref_register", "rna_wmKeyConfigPref_unregister", NULL);
+ RNA_def_struct_idprops_func(srna, "rna_wmKeyConfigPref_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */
+
+ /* registration */
+ RNA_define_verify_sdna(0);
+ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "idname");
+ RNA_def_property_flag(prop, PROP_REGISTER);
+ RNA_define_verify_sdna(1);
+}
+
static void rna_def_keyconfig(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2079,6 +2357,11 @@ static void rna_def_keyconfig(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "User Defined", "Indicates that a keyconfig was defined by the user");
+ /* Collection active property */
+ prop = RNA_def_property(srna, "preferences", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "KeyConfigPreferences");
+ RNA_def_property_pointer_funcs(prop, "rna_wmKeyConfig_preferences_get", NULL, NULL, NULL);
+
RNA_api_keyconfig(srna);
/* KeyMap */
@@ -2092,6 +2375,10 @@ static void rna_def_keyconfig(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name", "Name of the key map");
RNA_def_struct_name_property(srna, prop);
+ prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "owner_id");
+ RNA_def_property_ui_text(prop, "Owner", "Internal owner");
+
prop = RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spaceid");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -2123,12 +2410,12 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_expanded_items", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYMAP_EXPANDED);
RNA_def_property_ui_text(prop, "Items Expanded", "Expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
prop = RNA_def_property(srna, "show_expanded_children", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYMAP_CHILDREN_EXPANDED);
RNA_def_property_ui_text(prop, "Children Expanded", "Children expanded in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
RNA_api_keymap(srna);
@@ -2235,7 +2522,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", KMI_EXPANDED);
RNA_def_property_ui_text(prop, "Expanded", "Show key map event and property details in the user interface");
- RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
prop = RNA_def_property(srna, "propvalue", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "propvalue");
@@ -2275,9 +2562,11 @@ void RNA_def_wm(BlenderRNA *brna)
rna_def_event(brna);
rna_def_timer(brna);
rna_def_popupmenu(brna);
+ rna_def_popovermenu(brna);
rna_def_piemenu(brna);
rna_def_window(brna);
rna_def_windowmanager(brna);
+ rna_def_keyconfig_prefs(brna);
rna_def_keyconfig(brna);
}
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 3015d56e1ee..95c7d1cadf4 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -41,6 +41,8 @@
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
+#include "UI_interface.h"
+
#include "wm_cursors.h"
#include "rna_internal.h" /* own include */
@@ -71,6 +73,13 @@ const EnumPropertyItem rna_enum_window_cursor_items[] = {
#include "UI_interface.h"
#include "BKE_context.h"
+#include "WM_types.h"
+
+static void rna_KeyMapItem_to_string(wmKeyMapItem *kmi, bool compact, char *result)
+{
+ WM_keymap_item_to_string(kmi, compact, result, UI_MAX_SHORTCUT_STR);
+}
+
static wmKeyMap *rna_keymap_active(wmKeyMap *km, bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -115,6 +124,37 @@ static void rna_event_timer_remove(struct wmWindowManager *wm, wmTimer *timer)
WM_event_remove_timer(wm, timer->win, timer);
}
+
+static wmGizmoGroupType *wm_gizmogrouptype_find_for_add_remove(ReportList *reports, const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, true);
+ if (gzgt == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Gizmo group type '%s' not found!", idname);
+ return NULL;
+ }
+ if (gzgt->flag & WM_GIZMOGROUPTYPE_PERSISTENT) {
+ BKE_reportf(reports, RPT_ERROR, "Gizmo group '%s' has 'PERSISTENT' option set!", idname);
+ return NULL;
+ }
+ return gzgt;
+}
+
+static void rna_gizmo_group_type_add(ReportList *reports, const char *idname)
+{
+ wmGizmoGroupType *gzgt = wm_gizmogrouptype_find_for_add_remove(reports, idname);
+ if (gzgt != NULL) {
+ WM_gizmo_group_type_add_ptr(gzgt);
+ }
+}
+
+static void rna_gizmo_group_type_remove(Main *bmain, ReportList *reports, const char *idname)
+{
+ wmGizmoGroupType *gzgt = wm_gizmogrouptype_find_for_add_remove(reports, idname);
+ if (gzgt != NULL) {
+ WM_gizmo_group_type_remove_ptr(bmain, gzgt);
+ }
+}
+
/* placeholder data for final implementation of a true progressbar */
static struct wmStaticProgress {
float min;
@@ -207,6 +247,25 @@ static wmKeyMapItem *rna_KeyMap_item_new(
return kmi;
}
+static wmKeyMapItem *rna_KeyMap_item_new_from_item(
+ wmKeyMap *km, ReportList *reports, wmKeyMapItem *kmi_src, bool head)
+{
+/* wmWindowManager *wm = CTX_wm_manager(C); */
+
+ if ((km->flag & KEYMAP_MODAL) == (kmi_src->idname[0] != '\0')) {
+ BKE_report(reports, RPT_ERROR, "Can not mix mondal/non-modal items");
+ return NULL;
+ }
+
+ /* create keymap item */
+ wmKeyMapItem *kmi = WM_keymap_add_item_copy(km, kmi_src);
+ if (head) {
+ BLI_remlink(&km->items, kmi);
+ BLI_addhead(&km->items, kmi);
+ }
+ return kmi;
+}
+
static wmKeyMapItem *rna_KeyMap_item_new_modal(
wmKeyMap *km, ReportList *reports, const char *propvalue_str,
int type, int value, bool any, bool shift, bool ctrl, bool alt,
@@ -250,14 +309,22 @@ static void rna_KeyMap_item_remove(wmKeyMap *km, ReportList *reports, PointerRNA
RNA_POINTER_INVALIDATE(kmi_ptr);
}
-static wmKeyMap *rna_keymap_new(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid, bool modal)
+static wmKeyMap *rna_keymap_new(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid, bool modal, bool tool)
{
+ wmKeyMap *keymap;
+
if (modal == 0) {
- return WM_keymap_ensure(keyconf, idname, spaceid, regionid);
+ keymap = WM_keymap_ensure(keyconf, idname, spaceid, regionid);
}
else {
- return WM_modalkeymap_add(keyconf, idname, NULL); /* items will be lazy init */
+ keymap = WM_modalkeymap_add(keyconf, idname, NULL); /* items will be lazy init */
+ }
+
+ if (keymap && tool) {
+ keymap->flag |= KEYMAP_TOOL;
}
+
+ return keymap;
}
static wmKeyMap *rna_keymap_find(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
@@ -342,6 +409,24 @@ static void rna_PopMenuEnd(bContext *C, PointerRNA *handle)
UI_popup_menu_end(C, handle->data);
}
+/* popover wrapper */
+static PointerRNA rna_PopoverBegin(bContext *C, int ui_units_x)
+{
+ PointerRNA r_ptr;
+ void *data;
+
+ data = (void *)UI_popover_begin(C, U.widget_unit * ui_units_x);
+
+ RNA_pointer_create(NULL, &RNA_UIPopover, data, &r_ptr);
+
+ return r_ptr;
+}
+
+static void rna_PopoverEnd(bContext *C, PointerRNA *handle, wmKeyMap *keymap)
+{
+ UI_popover_end(C, handle->data, keymap);
+}
+
/* pie menu wrapper */
static PointerRNA rna_PieMenuBegin(bContext *C, const char *title, int icon, PointerRNA *event)
{
@@ -360,6 +445,18 @@ static void rna_PieMenuEnd(bContext *C, PointerRNA *handle)
UI_pie_menu_end(C, handle->data);
}
+static PointerRNA rna_WindoManager_operator_properties_last(const char *idname)
+{
+ wmOperatorType *ot = WM_operatortype_find(idname, true);
+
+ if (ot != NULL) {
+ PointerRNA ptr;
+ WM_operator_last_properties_ensure(ot, &ptr);
+ return ptr;
+ }
+ return PointerRNA_NULL;
+}
+
#else
#define WM_GEN_INVOKE_EVENT (1 << 0)
@@ -453,6 +550,18 @@ void RNA_api_wm(StructRNA *srna)
parm = RNA_def_pointer(func, "timer", "Timer", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ func = RNA_def_function(srna, "gizmo_group_type_add", "rna_gizmo_group_type_add");
+ RNA_def_function_ui_description(func, "Activate an existing widget group (when the persistent option isn't set)");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "identifier", NULL, 0, "", "Gizmo group type name");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "gizmo_group_type_remove", "rna_gizmo_group_type_remove");
+ RNA_def_function_ui_description(func, "De-activate a widget group (when the persistent option isn't set)");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "identifier", NULL, 0, "", "Gizmo group type name");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
/* Progress bar interface */
func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
RNA_def_function_ui_description(func, "Start progress report");
@@ -521,7 +630,24 @@ void RNA_api_wm(StructRNA *srna)
func = RNA_def_function(srna, "popmenu_end__internal", "rna_PopMenuEnd");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR | PARM_REQUIRED);
+
+ /* wrap UI_popover_begin */
+ func = RNA_def_function(srna, "popover_begin__internal", "rna_PopoverBegin");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+ RNA_def_property(func, "ui_units_x", PROP_INT, PROP_UNSIGNED);
+ /* return */
+ parm = RNA_def_pointer(func, "menu", "UIPopover", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
+ /* wrap UI_popover_end */
+ func = RNA_def_function(srna, "popover_end__internal", "rna_PopoverEnd");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+ parm = RNA_def_pointer(func, "menu", "UIPopover", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR | PARM_REQUIRED);
+ RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Active key map");
+
/* wrap uiPieMenuBegin */
func = RNA_def_function(srna, "piemenu_begin__internal", "rna_PieMenuBegin");
@@ -541,7 +667,18 @@ void RNA_api_wm(StructRNA *srna)
func = RNA_def_function(srna, "piemenu_end__internal", "rna_PieMenuEnd");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "menu", "UIPieMenu", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR | PARM_REQUIRED);
+
+ /* access last operator options (optionally create). */
+ func = RNA_def_function(srna, "operator_properties_last", "rna_WindoManager_operator_properties_last");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_string(func, "operator", NULL, 0, "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return */
+ parm = RNA_def_pointer(func, "result", "OperatorProperties", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
}
void RNA_api_operator(StructRNA *srna)
@@ -700,6 +837,12 @@ void RNA_api_keymapitem(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "Comparison result", "");
RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "to_string", "rna_KeyMapItem_to_string");
+ RNA_def_boolean(func, "compact", false, "Compact", "");
+ parm = RNA_def_string(func, "result", NULL, UI_MAX_SHORTCUT_STR, "result", "");
+ RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_function_output(func, parm);
}
void RNA_api_keymapitems(StructRNA *srna)
@@ -744,6 +887,14 @@ void RNA_api_keymapitems(StructRNA *srna)
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Added key map item");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "new_from_item", "rna_KeyMap_item_new_from_item");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Item to use as a reference");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_boolean(func, "head", 0, "At Head", "");
+ parm = RNA_def_pointer(func, "result", "KeyMapItem", "Item", "Added key map item");
+ RNA_def_function_return(func, parm);
+
func = RNA_def_function(srna, "remove", "rna_KeyMap_item_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
@@ -768,7 +919,8 @@ void RNA_api_keymaps(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
- RNA_def_boolean(func, "modal", 0, "Modal", "");
+ RNA_def_boolean(func, "modal", 0, "Modal", "Keymap for modal operators");
+ RNA_def_boolean(func, "tool", 0, "Tool", "Keymap for active tools");
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Added key map");
RNA_def_function_return(func, parm);
@@ -822,10 +974,10 @@ void RNA_api_keyconfigs(StructRNA *srna)
parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "");
RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_boolean(func, "is_hotkey", 0, "Hotkey", "Event is not a modifier");
- parm = RNA_def_pointer(func, "item", "KeyMapItem", "", "");
- RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
parm = RNA_def_pointer(func, "keymap", "KeyMap", "", "");
RNA_def_parameter_flags(parm, 0, PARM_RNAPTR | PARM_OUTPUT);
+ parm = RNA_def_pointer(func, "item", "KeyMapItem", "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_RNAPTR);
RNA_def_function_return(func, parm);
RNA_def_function(srna, "update", "rna_KeyConfig_update"); /* WM_keyconfig_update */
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c
new file mode 100644
index 00000000000..41e3929e8ae
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_wm_gizmo.c
@@ -0,0 +1,1408 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_wm_gizmo.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "WM_types.h"
+
+#ifdef RNA_RUNTIME
+/* enum definitions */
+#endif /* RNA_RUNTIME */
+
+#ifdef RNA_RUNTIME
+
+#include <assert.h>
+
+#include "WM_api.h"
+
+#include "DNA_workspace_types.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_workspace.h"
+
+#include "MEM_guardedalloc.h"
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+/* -------------------------------------------------------------------- */
+
+/** \name Gizmo API
+ * \{ */
+
+#ifdef WITH_PYTHON
+static void rna_gizmo_draw_cb(
+ const struct bContext *C, struct wmGizmo *gz)
+{
+ extern FunctionRNA rna_Gizmo_draw_func;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ PointerRNA gz_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ /* RNA_struct_find_function(&gz_ptr, "draw"); */
+ func = &rna_Gizmo_draw_func;
+ RNA_parameter_list_create(&list, &gz_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_gizmo_draw_select_cb(
+ const struct bContext *C, struct wmGizmo *gz, int select_id)
+{
+ extern FunctionRNA rna_Gizmo_draw_select_func;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ PointerRNA gz_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ /* RNA_struct_find_function(&gz_ptr, "draw_select"); */
+ func = &rna_Gizmo_draw_select_func;
+ RNA_parameter_list_create(&list, &gz_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "select_id", &select_id);
+ gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static int rna_gizmo_test_select_cb(
+ struct bContext *C, struct wmGizmo *gz, const int location[2])
+{
+ extern FunctionRNA rna_Gizmo_test_select_func;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ PointerRNA gz_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ /* RNA_struct_find_function(&gz_ptr, "test_select"); */
+ func = &rna_Gizmo_test_select_func;
+ RNA_parameter_list_create(&list, &gz_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "location", location);
+ gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+
+ void *ret;
+ RNA_parameter_get_lookup(&list, "intersect_id", &ret);
+ int intersect_id = *(int *)ret;
+
+ RNA_parameter_list_free(&list);
+ return intersect_id;
+}
+
+static int rna_gizmo_modal_cb(
+ struct bContext *C, struct wmGizmo *gz, const struct wmEvent *event,
+ eWM_GizmoFlagTweak tweak_flag)
+{
+ extern FunctionRNA rna_Gizmo_modal_func;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ PointerRNA gz_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ const int tweak_flag_int = tweak_flag;
+ RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ /* RNA_struct_find_function(&gz_ptr, "modal"); */
+ func = &rna_Gizmo_modal_func;
+ RNA_parameter_list_create(&list, &gz_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "event", &event);
+ RNA_parameter_set_lookup(&list, "tweak", &tweak_flag_int);
+ gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+
+ void *ret;
+ RNA_parameter_get_lookup(&list, "result", &ret);
+ int ret_enum = *(int *)ret;
+
+ RNA_parameter_list_free(&list);
+ return ret_enum;
+}
+
+static void rna_gizmo_setup_cb(
+ struct wmGizmo *gz)
+{
+ extern FunctionRNA rna_Gizmo_setup_func;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ PointerRNA gz_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ /* RNA_struct_find_function(&gz_ptr, "setup"); */
+ func = &rna_Gizmo_setup_func;
+ RNA_parameter_list_create(&list, &gz_ptr, func);
+ gzgroup->type->ext.call((bContext *)NULL, &gz_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+
+static int rna_gizmo_invoke_cb(
+ struct bContext *C, struct wmGizmo *gz, const struct wmEvent *event)
+{
+ extern FunctionRNA rna_Gizmo_invoke_func;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ PointerRNA gz_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ /* RNA_struct_find_function(&gz_ptr, "invoke"); */
+ func = &rna_Gizmo_invoke_func;
+ RNA_parameter_list_create(&list, &gz_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "event", &event);
+ gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+
+ void *ret;
+ RNA_parameter_get_lookup(&list, "result", &ret);
+ int ret_enum = *(int *)ret;
+
+ RNA_parameter_list_free(&list);
+ return ret_enum;
+}
+
+static void rna_gizmo_exit_cb(
+ struct bContext *C, struct wmGizmo *gz, bool cancel)
+{
+ extern FunctionRNA rna_Gizmo_exit_func;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ PointerRNA gz_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ /* RNA_struct_find_function(&gz_ptr, "exit"); */
+ func = &rna_Gizmo_exit_func;
+ RNA_parameter_list_create(&list, &gz_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ {
+ int cancel_i = cancel;
+ RNA_parameter_set_lookup(&list, "cancel", &cancel_i);
+ }
+ gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_gizmo_select_refresh_cb(
+ struct wmGizmo *gz)
+{
+ extern FunctionRNA rna_Gizmo_select_refresh_func;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ PointerRNA gz_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ /* RNA_struct_find_function(&gz_ptr, "select_refresh"); */
+ func = &rna_Gizmo_select_refresh_func;
+ RNA_parameter_list_create(&list, &gz_ptr, func);
+ gzgroup->type->ext.call((bContext *)NULL, &gz_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+#endif /* WITH_PYTHON */
+
+/* just to work around 'const char *' warning and to ensure this is a python op */
+static void rna_Gizmo_bl_idname_set(PointerRNA *ptr, const char *value)
+{
+ wmGizmo *data = ptr->data;
+ char *str = (char *)data->type->idname;
+ if (!str[0]) {
+ BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */
+ }
+ else {
+ assert(!"setting the bl_idname on a non-builtin operator");
+ }
+}
+
+static wmGizmo *rna_GizmoProperties_find_operator(PointerRNA *ptr)
+{
+#if 0
+ wmWindowManager *wm = ptr->id.data;
+#endif
+
+ /* We could try workaruond this lookup, but not trivial. */
+ for (bScreen *screen = G_MAIN->screen.first; screen; screen = screen->id.next) {
+ IDProperty *properties = ptr->data;
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->gizmo_map) {
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ for (wmGizmoGroup *gzgroup = WM_gizmomap_group_list(gzmap)->first;
+ gzgroup;
+ gzgroup = gzgroup->next)
+ {
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ if (gz->properties == properties) {
+ return gz;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static StructRNA *rna_GizmoProperties_refine(PointerRNA *ptr)
+{
+ wmGizmo *gz = rna_GizmoProperties_find_operator(ptr);
+
+ if (gz)
+ return gz->type->srna;
+ else
+ return ptr->type;
+}
+
+static IDProperty *rna_GizmoProperties_idprops(PointerRNA *ptr, bool create)
+{
+ if (create && !ptr->data) {
+ IDPropertyTemplate val = {0};
+ ptr->data = IDP_New(IDP_GROUP, &val, "RNA_GizmoProperties group");
+ }
+
+ return ptr->data;
+}
+
+static PointerRNA rna_Gizmo_properties_get(PointerRNA *ptr)
+{
+ wmGizmo *gz = ptr->data;
+ return rna_pointer_inherit_refine(ptr, gz->type->srna, gz->properties);
+}
+
+/* wmGizmo.float */
+#define RNA_GIZMO_GENERIC_FLOAT_RW_DEF(func_id, member_id) \
+static float rna_Gizmo_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ return gz->member_id; \
+} \
+static void rna_Gizmo_##func_id##_set(PointerRNA *ptr, float value) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ gz->member_id = value; \
+}
+#define RNA_GIZMO_GENERIC_FLOAT_ARRAY_INDEX_RW_DEF(func_id, member_id, index) \
+static float rna_Gizmo_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ return gz->member_id[index]; \
+} \
+static void rna_Gizmo_##func_id##_set(PointerRNA *ptr, float value) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ gz->member_id[index] = value; \
+}
+/* wmGizmo.float[len] */
+#define RNA_GIZMO_GENERIC_FLOAT_ARRAY_RW_DEF(func_id, member_id, len) \
+static void rna_Gizmo_##func_id##_get(PointerRNA *ptr, float value[len]) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ memcpy(value, gz->member_id, sizeof(float[len])); \
+} \
+static void rna_Gizmo_##func_id##_set(PointerRNA *ptr, const float value[len]) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ memcpy(gz->member_id, value, sizeof(float[len])); \
+}
+
+/* wmGizmo.flag */
+#define RNA_GIZMO_GENERIC_FLAG_RW_DEF(func_id, member_id, flag_value) \
+static bool rna_Gizmo_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ return (gz->member_id & flag_value) != 0; \
+} \
+static void rna_Gizmo_##func_id##_set(PointerRNA *ptr, bool value) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ SET_FLAG_FROM_TEST(gz->member_id, value, flag_value); \
+}
+
+/* wmGizmo.flag (negative) */
+#define RNA_GIZMO_GENERIC_FLAG_NEG_RW_DEF(func_id, member_id, flag_value) \
+static bool rna_Gizmo_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ return (gz->member_id & flag_value) == 0; \
+} \
+static void rna_Gizmo_##func_id##_set(PointerRNA *ptr, bool value) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ SET_FLAG_FROM_TEST(gz->member_id, !value, flag_value); \
+}
+
+#define RNA_GIZMO_FLAG_RO_DEF(func_id, member_id, flag_value) \
+static int rna_Gizmo_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmGizmo *gz = ptr->data; \
+ return (gz->member_id & flag_value) != 0; \
+}
+
+RNA_GIZMO_GENERIC_FLOAT_ARRAY_RW_DEF(color, color, 3);
+RNA_GIZMO_GENERIC_FLOAT_ARRAY_RW_DEF(color_hi, color_hi, 3);
+
+RNA_GIZMO_GENERIC_FLOAT_ARRAY_INDEX_RW_DEF(alpha, color, 3);
+RNA_GIZMO_GENERIC_FLOAT_ARRAY_INDEX_RW_DEF(alpha_hi, color_hi, 3);
+
+RNA_GIZMO_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_space, matrix_space, 16);
+RNA_GIZMO_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_basis, matrix_basis, 16);
+RNA_GIZMO_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_offset, matrix_offset, 16);
+
+static void rna_Gizmo_matrix_world_get(PointerRNA *ptr, float value[16])
+{
+ wmGizmo *gz = ptr->data;
+ WM_gizmo_calc_matrix_final(gz, (float (*)[4])value);
+}
+
+RNA_GIZMO_GENERIC_FLOAT_RW_DEF(scale_basis, scale_basis);
+RNA_GIZMO_GENERIC_FLOAT_RW_DEF(line_width, line_width);
+
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_hover, flag, WM_GIZMO_DRAW_HOVER);
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_modal, flag, WM_GIZMO_DRAW_MODAL);
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_value, flag, WM_GIZMO_DRAW_VALUE);
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_offset_scale, flag, WM_GIZMO_DRAW_OFFSET_SCALE);
+RNA_GIZMO_GENERIC_FLAG_NEG_RW_DEF(flag_use_draw_scale, flag, WM_GIZMO_DRAW_OFFSET_SCALE);
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_GIZMO_HIDDEN);
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide_select, flag, WM_GIZMO_HIDDEN_SELECT);
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_grab_cursor, flag, WM_GIZMO_MOVE_CURSOR);
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_select_background, flag, WM_GIZMO_SELECT_BACKGROUND);
+
+/* wmGizmo.state */
+RNA_GIZMO_FLAG_RO_DEF(state_is_highlight, state, WM_GIZMO_STATE_HIGHLIGHT);
+RNA_GIZMO_FLAG_RO_DEF(state_is_modal, state, WM_GIZMO_STATE_MODAL);
+RNA_GIZMO_FLAG_RO_DEF(state_select, state, WM_GIZMO_STATE_SELECT);
+
+static void rna_Gizmo_state_select_set(struct PointerRNA *ptr, bool value)
+{
+ wmGizmo *gz = ptr->data;
+ wmGizmoGroup *gzgroup = gz->parent_gzgroup;
+ WM_gizmo_select_set(gzgroup->parent_gzmap, gz, value);
+}
+
+static PointerRNA rna_Gizmo_group_get(PointerRNA *ptr)
+{
+ wmGizmo *gz = ptr->data;
+ return rna_pointer_inherit_refine(ptr, &RNA_GizmoGroup, gz->parent_gzgroup);
+}
+
+#ifdef WITH_PYTHON
+
+static void rna_Gizmo_unregister(struct Main *bmain, StructRNA *type);
+void BPY_RNA_gizmo_wrapper(wmGizmoType *gzgt, void *userdata);
+
+static StructRNA *rna_Gizmo_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+ struct {
+ char idname[MAX_NAME];
+ } temp_buffers;
+
+ wmGizmoType dummygt = {NULL};
+ wmGizmo dummymnp = {NULL};
+ PointerRNA mnp_ptr;
+
+ /* Two sets of functions. */
+ int have_function[8];
+
+ /* setup dummy gizmo & gizmo type to store static properties in */
+ dummymnp.type = &dummygt;
+ dummygt.idname = temp_buffers.idname;
+ RNA_pointer_create(NULL, &RNA_Gizmo, &dummymnp, &mnp_ptr);
+
+ /* Clear so we can detect if it's left unset. */
+ temp_buffers.idname[0] = '\0';
+
+ /* validate the python class */
+ if (validate(&mnp_ptr, data, have_function) != 0)
+ return NULL;
+
+ if (strlen(identifier) >= sizeof(temp_buffers.idname)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering gizmo class: '%s' is too long, maximum length is %d",
+ identifier, (int)sizeof(temp_buffers.idname));
+ return NULL;
+ }
+
+ /* check if we have registered this gizmo type before, and remove it */
+ {
+ const wmGizmoType *gzt = WM_gizmotype_find(dummygt.idname, true);
+ if (gzt && gzt->ext.srna) {
+ rna_Gizmo_unregister(bmain, gzt->ext.srna);
+ }
+ }
+ if (!RNA_struct_available_or_report(reports, dummygt.idname)) {
+ return NULL;
+ }
+
+ { /* allocate the idname */
+ /* For multiple strings see GizmoGroup. */
+ dummygt.idname = BLI_strdup(temp_buffers.idname);
+ }
+
+ /* create a new gizmo type */
+ dummygt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummygt.idname, &RNA_Gizmo);
+ /* gizmo properties are registered separately */
+ RNA_def_struct_flag(dummygt.ext.srna, STRUCT_NO_IDPROPERTIES);
+ dummygt.ext.data = data;
+ dummygt.ext.call = call;
+ dummygt.ext.free = free;
+
+ {
+ int i = 0;
+ dummygt.draw = (have_function[i++]) ? rna_gizmo_draw_cb : NULL;
+ dummygt.draw_select = (have_function[i++]) ? rna_gizmo_draw_select_cb : NULL;
+ dummygt.test_select = (have_function[i++]) ? rna_gizmo_test_select_cb : NULL;
+ dummygt.modal = (have_function[i++]) ? rna_gizmo_modal_cb : NULL;
+// dummygt.property_update = (have_function[i++]) ? rna_gizmo_property_update : NULL;
+// dummygt.position_get = (have_function[i++]) ? rna_gizmo_position_get : NULL;
+ dummygt.setup = (have_function[i++]) ? rna_gizmo_setup_cb : NULL;
+ dummygt.invoke = (have_function[i++]) ? rna_gizmo_invoke_cb : NULL;
+ dummygt.exit = (have_function[i++]) ? rna_gizmo_exit_cb : NULL;
+ dummygt.select_refresh = (have_function[i++]) ? rna_gizmo_select_refresh_cb : NULL;
+
+ BLI_assert(i == ARRAY_SIZE(have_function));
+ }
+
+ WM_gizmotype_append_ptr(BPY_RNA_gizmo_wrapper, (void *)&dummygt);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ return dummygt.ext.srna;
+}
+
+static void rna_Gizmo_unregister(struct Main *bmain, StructRNA *type)
+{
+ wmGizmoType *gzt = RNA_struct_blender_type_get(type);
+
+ if (!gzt) {
+ return;
+ }
+
+ RNA_struct_free_extension(type, &gzt->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ WM_gizmotype_remove_ptr(NULL, bmain, gzt);
+}
+
+static void **rna_Gizmo_instance(PointerRNA *ptr)
+{
+ wmGizmo *gz = ptr->data;
+ return &gz->py_instance;
+}
+
+#endif /* WITH_PYTHON */
+
+
+static StructRNA *rna_Gizmo_refine(PointerRNA *mnp_ptr)
+{
+ wmGizmo *gz = mnp_ptr->data;
+ return (gz->type && gz->type->ext.srna) ? gz->type->ext.srna : &RNA_Gizmo;
+}
+
+/** \} */
+
+/** \name Gizmo Group API
+ * \{ */
+
+static wmGizmoGroupType *rna_GizmoGroupProperties_find_gizmo_group_type(PointerRNA *ptr)
+{
+ IDProperty *properties = (IDProperty *)ptr->data;
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(properties->name, false);
+ return gzgt;
+}
+
+static StructRNA *rna_GizmoGroupProperties_refine(PointerRNA *ptr)
+{
+ wmGizmoGroupType *gzgt = rna_GizmoGroupProperties_find_gizmo_group_type(ptr);
+
+ if (gzgt)
+ return gzgt->srna;
+ else
+ return ptr->type;
+}
+
+static IDProperty *rna_GizmoGroupProperties_idprops(PointerRNA *ptr, bool create)
+{
+ if (create && !ptr->data) {
+ IDPropertyTemplate val = {0};
+ ptr->data = IDP_New(IDP_GROUP, &val, "RNA_GizmoGroupProperties group");
+ }
+
+ return ptr->data;
+}
+
+
+static wmGizmo *rna_GizmoGroup_gizmo_new(
+ wmGizmoGroup *gzgroup, ReportList *reports, const char *idname)
+{
+ const wmGizmoType *gzt = WM_gizmotype_find(idname, true);
+ if (gzt == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "GizmoType '%s' not known", idname);
+ return NULL;
+ }
+ wmGizmo *gz = WM_gizmo_new_ptr(gzt, gzgroup, NULL);
+ return gz;
+}
+
+static void rna_GizmoGroup_gizmo_remove(
+ wmGizmoGroup *gzgroup, bContext *C, wmGizmo *gz)
+{
+ WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, gz, C);
+}
+
+static void rna_GizmoGroup_gizmo_clear(
+ wmGizmoGroup *gzgroup, bContext *C)
+{
+ while (gzgroup->gizmos.first) {
+ WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, gzgroup->gizmos.first, C);
+ }
+}
+
+static void rna_GizmoGroup_name_get(PointerRNA *ptr, char *value)
+{
+ wmGizmoGroup *gzgroup = ptr->data;
+ strcpy(value, gzgroup->type->name);
+}
+
+static int rna_GizmoGroup_name_length(PointerRNA *ptr)
+{
+ wmGizmoGroup *gzgroup = ptr->data;
+ return strlen(gzgroup->type->name);
+}
+
+/* just to work around 'const char *' warning and to ensure this is a python op */
+static void rna_GizmoGroup_bl_idname_set(PointerRNA *ptr, const char *value)
+{
+ wmGizmoGroup *data = ptr->data;
+ char *str = (char *)data->type->idname;
+ if (!str[0])
+ BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */
+ else
+ assert(!"setting the bl_idname on a non-builtin operator");
+}
+
+static void rna_GizmoGroup_bl_label_set(PointerRNA *ptr, const char *value)
+{
+ wmGizmoGroup *data = ptr->data;
+ char *str = (char *)data->type->name;
+ if (!str[0])
+ BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */
+ else
+ assert(!"setting the bl_label on a non-builtin operator");
+}
+
+static bool rna_GizmoGroup_has_reports_get(PointerRNA *ptr)
+{
+ wmGizmoGroup *gzgroup = ptr->data;
+ return (gzgroup->reports && gzgroup->reports->list.first);
+}
+
+#ifdef WITH_PYTHON
+
+static bool rna_gizmogroup_poll_cb(const bContext *C, wmGizmoGroupType *gzgt)
+{
+
+ extern FunctionRNA rna_GizmoGroup_poll_func;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ void *ret;
+ bool visible;
+
+ RNA_pointer_create(NULL, gzgt->ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_GizmoGroup_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ gzgt->ext.call((bContext *)C, &ptr, func, &list);
+
+ RNA_parameter_get_lookup(&list, "visible", &ret);
+ visible = *(bool *)ret;
+
+ RNA_parameter_list_free(&list);
+
+ return visible;
+}
+
+static void rna_gizmogroup_setup_cb(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ extern FunctionRNA rna_GizmoGroup_setup_func;
+
+ PointerRNA gzgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, gzgroup->type->ext.srna, gzgroup, &gzgroup_ptr);
+ func = &rna_GizmoGroup_setup_func; /* RNA_struct_find_function(&wgroupr, "setup"); */
+
+ RNA_parameter_list_create(&list, &gzgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ gzgroup->type->ext.call((bContext *)C, &gzgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+static wmKeyMap *rna_gizmogroup_setup_keymap_cb(const wmGizmoGroupType *gzgt, wmKeyConfig *config)
+{
+ extern FunctionRNA rna_GizmoGroup_setup_keymap_func;
+ void *ret;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, gzgt->ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_GizmoGroup_setup_keymap_func; /* RNA_struct_find_function(&wgroupr, "setup_keymap"); */
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "keyconfig", &config);
+ gzgt->ext.call(NULL, &ptr, func, &list);
+
+ RNA_parameter_get_lookup(&list, "keymap", &ret);
+ wmKeyMap *keymap = *(wmKeyMap **)ret;
+
+ RNA_parameter_list_free(&list);
+
+ return keymap;
+}
+
+static void rna_gizmogroup_refresh_cb(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ extern FunctionRNA rna_GizmoGroup_refresh_func;
+
+ PointerRNA gzgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, gzgroup->type->ext.srna, gzgroup, &gzgroup_ptr);
+ func = &rna_GizmoGroup_refresh_func; /* RNA_struct_find_function(&wgroupr, "refresh"); */
+
+ RNA_parameter_list_create(&list, &gzgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ gzgroup->type->ext.call((bContext *)C, &gzgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_gizmogroup_draw_prepare_cb(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ extern FunctionRNA rna_GizmoGroup_draw_prepare_func;
+
+ PointerRNA gzgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, gzgroup->type->ext.srna, gzgroup, &gzgroup_ptr);
+ func = &rna_GizmoGroup_draw_prepare_func; /* RNA_struct_find_function(&wgroupr, "draw_prepare"); */
+
+ RNA_parameter_list_create(&list, &gzgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ gzgroup->type->ext.call((bContext *)C, &gzgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_gizmogroup_invoke_prepare_cb(const bContext *C, wmGizmoGroup *gzgroup, wmGizmo *gz)
+{
+ extern FunctionRNA rna_GizmoGroup_invoke_prepare_func;
+
+ PointerRNA gzgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, gzgroup->type->ext.srna, gzgroup, &gzgroup_ptr);
+ func = &rna_GizmoGroup_invoke_prepare_func; /* RNA_struct_find_function(&wgroupr, "invoke_prepare"); */
+
+ RNA_parameter_list_create(&list, &gzgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "gizmo", &gz);
+ gzgroup->type->ext.call((bContext *)C, &gzgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+void BPY_RNA_gizmogroup_wrapper(wmGizmoGroupType *gzgt, void *userdata);
+static void rna_GizmoGroup_unregister(struct Main *bmain, StructRNA *type);
+
+static StructRNA *rna_GizmoGroup_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+ struct {
+ char name[MAX_NAME];
+ char idname[MAX_NAME];
+ } temp_buffers;
+
+ wmGizmoGroupType dummywgt = {NULL};
+ wmGizmoGroup dummywg = {NULL};
+ PointerRNA wgptr;
+
+ /* Two sets of functions. */
+ int have_function[6];
+
+ /* setup dummy gizmogroup & gizmogroup type to store static properties in */
+ dummywg.type = &dummywgt;
+ dummywgt.name = temp_buffers.name;
+ dummywgt.idname = temp_buffers.idname;
+
+ RNA_pointer_create(NULL, &RNA_GizmoGroup, &dummywg, &wgptr);
+
+ /* Clear so we can detect if it's left unset. */
+ temp_buffers.idname[0] = temp_buffers.name[0] = '\0';
+
+ /* validate the python class */
+ if (validate(&wgptr, data, have_function) != 0)
+ return NULL;
+
+ if (strlen(identifier) >= sizeof(temp_buffers.idname)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering gizmogroup class: '%s' is too long, maximum length is %d",
+ identifier, (int)sizeof(temp_buffers.idname));
+ return NULL;
+ }
+
+ /* check if the area supports widgets */
+ const struct wmGizmoMapType_Params wmap_params = {
+ .spaceid = dummywgt.gzmap_params.spaceid,
+ .regionid = dummywgt.gzmap_params.regionid,
+ };
+
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&wmap_params);
+ if (gzmap_type == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Area type does not support gizmos");
+ return NULL;
+ }
+
+ /* check if we have registered this gizmogroup type before, and remove it */
+ {
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(dummywgt.idname, true);
+ if (gzgt && gzgt->ext.srna) {
+ rna_GizmoGroup_unregister(bmain, gzgt->ext.srna);
+ }
+ }
+ if (!RNA_struct_available_or_report(reports, dummywgt.idname)) {
+ return NULL;
+ }
+
+ { /* allocate the idname */
+ const char *strings[] = {
+ temp_buffers.idname,
+ temp_buffers.name,
+ };
+ char *strings_table[ARRAY_SIZE(strings)];
+ BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings));
+
+ dummywgt.idname = strings_table[0]; /* allocated string stored here */
+ dummywgt.name = strings_table[1];
+ BLI_assert(ARRAY_SIZE(strings) == 2);
+ }
+
+ /* create a new gizmogroup type */
+ dummywgt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywgt.idname, &RNA_GizmoGroup);
+ RNA_def_struct_flag(dummywgt.ext.srna, STRUCT_NO_IDPROPERTIES); /* gizmogroup properties are registered separately */
+ dummywgt.ext.data = data;
+ dummywgt.ext.call = call;
+ dummywgt.ext.free = free;
+
+ /* We used to register widget group types like this, now we do it similar to
+ * operator types. Thus we should be able to do the same as operator types now. */
+ dummywgt.poll = (have_function[0]) ? rna_gizmogroup_poll_cb : NULL;
+ dummywgt.setup_keymap = (have_function[1]) ? rna_gizmogroup_setup_keymap_cb : NULL;
+ dummywgt.setup = (have_function[2]) ? rna_gizmogroup_setup_cb : NULL;
+ dummywgt.refresh = (have_function[3]) ? rna_gizmogroup_refresh_cb : NULL;
+ dummywgt.draw_prepare = (have_function[4]) ? rna_gizmogroup_draw_prepare_cb : NULL;
+ dummywgt.invoke_prepare = (have_function[5]) ? rna_gizmogroup_invoke_prepare_cb : NULL;
+
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_append_ptr(
+ BPY_RNA_gizmogroup_wrapper, (void *)&dummywgt);
+
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(gzgt->owner_id, owner_id, sizeof(gzgt->owner_id));
+ }
+ }
+
+ if (gzgt->flag & WM_GIZMOGROUPTYPE_PERSISTENT) {
+ WM_gizmo_group_type_add_ptr_ex(gzgt, gzmap_type);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+ }
+
+ return dummywgt.ext.srna;
+}
+
+static void rna_GizmoGroup_unregister(struct Main *bmain, StructRNA *type)
+{
+ wmGizmoGroupType *gzgt = RNA_struct_blender_type_get(type);
+
+ if (!gzgt)
+ return;
+
+ RNA_struct_free_extension(type, &gzgt->ext);
+ RNA_struct_free(&BLENDER_RNA, type);
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ WM_gizmo_group_type_remove_ptr(bmain, gzgt);
+}
+
+static void **rna_GizmoGroup_instance(PointerRNA *ptr)
+{
+ wmGizmoGroup *gzgroup = ptr->data;
+ return &gzgroup->py_instance;
+}
+
+#endif /* WITH_PYTHON */
+
+static StructRNA *rna_GizmoGroup_refine(PointerRNA *gzgroup_ptr)
+{
+ wmGizmoGroup *gzgroup = gzgroup_ptr->data;
+ return (gzgroup->type && gzgroup->type->ext.srna) ? gzgroup->type->ext.srna : &RNA_GizmoGroup;
+}
+
+static void rna_GizmoGroup_gizmos_begin(CollectionPropertyIterator *iter, PointerRNA *gzgroup_ptr)
+{
+ wmGizmoGroup *gzgroup = gzgroup_ptr->data;
+ rna_iterator_listbase_begin(iter, &gzgroup->gizmos, NULL);
+}
+
+/** \} */
+
+
+#else /* RNA_RUNTIME */
+
+
+/* GizmoGroup.gizmos */
+static void rna_def_gizmos(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "Gizmos");
+ srna = RNA_def_struct(brna, "Gizmos", NULL);
+ RNA_def_struct_sdna(srna, "wmGizmoGroup");
+ RNA_def_struct_ui_text(srna, "Gizmos", "Collection of gizmos");
+
+ func = RNA_def_function(srna, "new", "rna_GizmoGroup_gizmo_new");
+ RNA_def_function_ui_description(func, "Add gizmo");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "type", "Type", 0, "", "Gizmo identifier"); /* optional */
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "gizmo", "Gizmo", "", "New gizmo");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_GizmoGroup_gizmo_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Delete gizmo");
+ parm = RNA_def_pointer(func, "gizmo", "Gizmo", "", "New gizmo");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "clear", "rna_GizmoGroup_gizmo_clear");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Delete all gizmos");
+}
+
+
+static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "Gizmo");
+ srna = RNA_def_struct(brna, "Gizmo", NULL);
+ RNA_def_struct_sdna(srna, "wmGizmo");
+ RNA_def_struct_ui_text(srna, "Gizmo", "Collection of gizmos");
+ RNA_def_struct_refine_func(srna, "rna_Gizmo_refine");
+
+#ifdef WITH_PYTHON
+ RNA_def_struct_register_funcs(
+ srna,
+ "rna_Gizmo_register",
+ "rna_Gizmo_unregister",
+ "rna_Gizmo_instance");
+#endif
+ RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+
+ prop = RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "GizmoProperties");
+ RNA_def_property_ui_text(prop, "Properties", "");
+ RNA_def_property_pointer_funcs(prop, "rna_Gizmo_properties_get", NULL, NULL, NULL);
+
+ /* -------------------------------------------------------------------- */
+ /* Registerable Variables */
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->idname");
+ RNA_def_property_string_maxlength(prop, MAX_NAME);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Gizmo_bl_idname_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ RNA_def_property_flag(prop, PROP_REGISTER);
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+
+ /* wmGizmo.draw */
+ func = RNA_def_function(srna, "draw", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* wmGizmo.draw_select */
+ func = RNA_def_function(srna, "draw_select", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_int(func, "select_id", 0, 0, INT_MAX, "", "", 0, INT_MAX);
+
+ /* wmGizmo.test_select */
+ func = RNA_def_function(srna, "test_select", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_int_array(func, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Region coordinates", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_int(func, "intersect_id", 0, 0, INT_MAX, "", "", 0, INT_MAX);
+ RNA_def_function_return(func, parm);
+
+ /* wmGizmo.handler */
+ static EnumPropertyItem tweak_actions[] = {
+ {WM_GIZMO_TWEAK_PRECISE, "PRECISE", 0, "Precise", ""},
+ {WM_GIZMO_TWEAK_SNAP, "SNAP", 0, "Snap", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ func = RNA_def_function(srna, "modal", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "event", "Event", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ /* TODO, shuold be a enum-flag */
+ parm = RNA_def_enum_flag(func, "tweak", tweak_actions, 0, "Tweak", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
+ RNA_def_function_return(func, parm);
+ /* wmGizmo.property_update */
+ /* TODO */
+
+ /* wmGizmo.setup */
+ func = RNA_def_function(srna, "setup", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+
+ /* wmGizmo.invoke */
+ func = RNA_def_function(srna, "invoke", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "event", "Event", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
+ RNA_def_function_return(func, parm);
+
+ /* wmGizmo.exit */
+ func = RNA_def_function(srna, "exit", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "cancel", 0, "Cancel, otherwise confirm", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ /* wmGizmo.cursor_get */
+ /* TODO */
+
+ /* wmGizmo.select_refresh */
+ func = RNA_def_function(srna, "select_refresh", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+
+
+ /* -------------------------------------------------------------------- */
+ /* Instance Variables */
+
+ prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "GizmoGroup");
+ RNA_def_property_pointer_funcs(prop, "rna_Gizmo_group_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "", "Gizmo group this gizmo is a member of");
+
+ /* Color & Alpha */
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_color_get", "rna_Gizmo_color_set", NULL);
+
+ prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Alpha", "");
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_alpha_get", "rna_Gizmo_alpha_set", NULL);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ /* Color & Alpha (highlight) */
+ prop = RNA_def_property(srna, "color_highlight", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_color_hi_get", "rna_Gizmo_color_hi_set", NULL);
+
+ prop = RNA_def_property(srna, "alpha_highlight", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Alpha", "");
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_alpha_hi_get", "rna_Gizmo_alpha_hi_set", NULL);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "matrix_space", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Space Matrix", "");
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_matrix_space_get", "rna_Gizmo_matrix_space_set", NULL);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "matrix_basis", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Basis Matrix", "");
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_matrix_basis_get", "rna_Gizmo_matrix_basis_set", NULL);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "matrix_offset", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Offset Matrix", "");
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_matrix_offset_get", "rna_Gizmo_matrix_offset_set", NULL);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "matrix_world", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Final World Matrix", "");
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_matrix_world_get", NULL, NULL);
+
+ prop = RNA_def_property(srna, "scale_basis", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Scale Basis", "");
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_scale_basis_get", "rna_Gizmo_scale_basis_set", NULL);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "line_width", PROP_FLOAT, PROP_PIXEL);
+ RNA_def_property_ui_text(prop, "Line Width", "");
+ RNA_def_property_float_funcs(prop, "rna_Gizmo_line_width_get", "rna_Gizmo_line_width_set", NULL);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ /* wmGizmo.flag */
+ /* WM_GIZMO_HIDDEN */
+ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_hide_get", "rna_Gizmo_flag_hide_set");
+ RNA_def_property_ui_text(prop, "Hide", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_GIZMO_HIDDEN_SELECT */
+ prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_hide_select_get", "rna_Gizmo_flag_hide_select_set");
+ RNA_def_property_ui_text(prop, "Hide Select", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_GIZMO_MOVE_CURSOR */
+ prop = RNA_def_property(srna, "use_grab_cursor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_use_grab_cursor_get", "rna_Gizmo_flag_use_grab_cursor_set");
+ RNA_def_property_ui_text(prop, "Grab Cursor", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ /* WM_GIZMO_DRAW_HOVER */
+ prop = RNA_def_property(srna, "use_draw_hover", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_use_draw_hover_get", "rna_Gizmo_flag_use_draw_hover_set");
+ RNA_def_property_ui_text(prop, "Draw Hover", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_GIZMO_DRAW_MODAL */
+ prop = RNA_def_property(srna, "use_draw_modal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_use_draw_modal_get", "rna_Gizmo_flag_use_draw_modal_set");
+ RNA_def_property_ui_text(prop, "Draw Active", "Draw while dragging");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_GIZMO_DRAW_VALUE */
+ prop = RNA_def_property(srna, "use_draw_value", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_use_draw_value_get", "rna_Gizmo_flag_use_draw_value_set");
+ RNA_def_property_ui_text(prop, "Draw Value", "Show an indicator for the current value while dragging");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_GIZMO_DRAW_OFFSET_SCALE */
+ prop = RNA_def_property(srna, "use_draw_offset_scale", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_use_draw_offset_scale_get", "rna_Gizmo_flag_use_draw_offset_scale_set");
+ RNA_def_property_ui_text(prop, "Scale Offset", "Scale the offset matrix (use to apply screen-space offset)");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_GIZMO_DRAW_NO_SCALE (negated) */
+ prop = RNA_def_property(srna, "use_draw_scale", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_use_draw_scale_get", "rna_Gizmo_flag_use_draw_scale_set");
+ RNA_def_property_ui_text(prop, "Scale", "Use scale when calculating the matrix");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_GIZMO_SELECT_BACKGROUND */
+ prop = RNA_def_property(srna, "use_select_background", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_use_select_background_get", "rna_Gizmo_flag_use_select_background_set");
+ RNA_def_property_ui_text(prop, "Select Background", "Don't write into the depth buffer");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ /* wmGizmo.state (readonly) */
+ /* WM_GIZMO_STATE_HIGHLIGHT */
+ prop = RNA_def_property(srna, "is_highlight", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Gizmo_state_is_highlight_get", NULL);
+ RNA_def_property_ui_text(prop, "Highlight", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ /* WM_GIZMO_STATE_MODAL */
+ prop = RNA_def_property(srna, "is_modal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Gizmo_state_is_modal_get", NULL);
+ RNA_def_property_ui_text(prop, "Highlight", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ /* WM_GIZMO_STATE_SELECT */
+ /* (note that setting is involved, needs to handle array) */
+ prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Gizmo_state_select_get", "rna_Gizmo_state_select_set");
+ RNA_def_property_ui_text(prop, "Select", "");
+
+ RNA_api_gizmo(srna);
+
+ srna = RNA_def_struct(brna, "GizmoProperties", NULL);
+ RNA_def_struct_ui_text(srna, "Gizmo Properties", "Input properties of an Gizmo");
+ RNA_def_struct_refine_func(srna, "rna_GizmoProperties_refine");
+ RNA_def_struct_idprops_func(srna, "rna_GizmoProperties_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
+}
+
+static void rna_def_gizmogroup(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "GizmoGroup", NULL);
+ RNA_def_struct_ui_text(srna, "GizmoGroup", "Storage of an operator being executed, or registered after execution");
+ RNA_def_struct_sdna(srna, "wmGizmoGroup");
+ RNA_def_struct_refine_func(srna, "rna_GizmoGroup_refine");
+#ifdef WITH_PYTHON
+ RNA_def_struct_register_funcs(
+ srna,
+ "rna_GizmoGroup_register",
+ "rna_GizmoGroup_unregister",
+ "rna_GizmoGroup_instance");
+#endif
+ RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+
+ /* -------------------------------------------------------------------- */
+ /* Registration */
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->idname");
+ RNA_def_property_string_maxlength(prop, MAX_NAME);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GizmoGroup_bl_idname_set");
+ RNA_def_property_flag(prop, PROP_REGISTER);
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->name");
+ RNA_def_property_string_maxlength(prop, MAX_NAME); /* else it uses the pointer size! */
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GizmoGroup_bl_label_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ RNA_def_property_flag(prop, PROP_REGISTER);
+
+ prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type->gzmap_params.spaceid");
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
+ RNA_def_property_flag(prop, PROP_REGISTER);
+ RNA_def_property_ui_text(prop, "Space type", "The space where the panel is going to be used in");
+
+ prop = RNA_def_property(srna, "bl_region_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type->gzmap_params.regionid");
+ RNA_def_property_enum_items(prop, rna_enum_region_type_items);
+ RNA_def_property_flag(prop, PROP_REGISTER);
+ RNA_def_property_ui_text(prop, "Region Type", "The region where the panel is going to be used in");
+
+ prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->owner_id");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
+ /* bl_options */
+ static EnumPropertyItem gizmogroup_flag_items[] = {
+ {WM_GIZMOGROUPTYPE_3D, "3D", 0, "3D",
+ "Use in 3D viewport"},
+ {WM_GIZMOGROUPTYPE_SCALE, "SCALE", 0, "Scale",
+ "Scale to respect zoom (otherwise zoom independent draw size)"},
+ {WM_GIZMOGROUPTYPE_DEPTH_3D, "DEPTH_3D", 0, "Depth 3D",
+ "Supports culled depth by other objects in the view"},
+ {WM_GIZMOGROUPTYPE_SELECT, "SELECT", 0, "Select",
+ "Supports selection"},
+ {WM_GIZMOGROUPTYPE_PERSISTENT, "PERSISTENT", 0, "Persistent",
+ ""},
+ {WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL, "SHOW_MODAL_ALL", 0, "Show Modal All",
+ "Show all while interacting"},
+ {WM_GIZMOGROUPTYPE_TOOL_INIT, "TOOL_INIT", 0, "Tool Init",
+ "Postpone running until tool operator run (when used with a tool)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+ prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type->flag");
+ RNA_def_property_enum_items(prop, gizmogroup_flag_items);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Options", "Options for this operator type");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+
+
+ /* Functions */
+
+ /* poll */
+ func = RNA_def_function(srna, "poll", NULL);
+ RNA_def_function_ui_description(func, "Test if the gizmo group can be called or not");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
+ RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", ""));
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* setup_keymap */
+ func = RNA_def_function(srna, "setup_keymap", NULL);
+ RNA_def_function_ui_description(
+ func,
+ "Initialize keymaps for this gizmo group, use fallback keymap when not present");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "keyconfig", "KeyConfig", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ /* return */
+ parm = RNA_def_pointer(func, "keymap", "KeyMap", "", "");
+ RNA_def_property_flag(parm, PROP_NEVER_NULL);
+ RNA_def_function_return(func, parm);
+
+ /* setup */
+ func = RNA_def_function(srna, "setup", NULL);
+ RNA_def_function_ui_description(func, "Create gizmos function for the gizmo group");
+ RNA_def_function_flag(func, FUNC_REGISTER);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* refresh */
+ func = RNA_def_function(srna, "refresh", NULL);
+ RNA_def_function_ui_description(func, "Refresh data (called on common state changes such as selection)");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "draw_prepare", NULL);
+ RNA_def_function_ui_description(func, "Run before each redraw");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "invoke_prepare", NULL);
+ RNA_def_function_ui_description(func, "Run before invoke");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "gizmo", "Gizmo", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* -------------------------------------------------------------------- */
+ /* Instance Variables */
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(prop, "rna_GizmoGroup_name_get", "rna_GizmoGroup_name_length", NULL);
+ RNA_def_property_ui_text(prop, "Name", "");
+
+ prop = RNA_def_property(srna, "has_reports", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* this is 'virtual' property */
+ RNA_def_property_boolean_funcs(prop, "rna_GizmoGroup_has_reports_get", NULL);
+ RNA_def_property_ui_text(prop, "Has Reports",
+ "GizmoGroup has a set of reports (warnings and errors) from last execution");
+
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ prop = RNA_def_property(srna, "gizmos", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "gizmos", NULL);
+ RNA_def_property_struct_type(prop, "Gizmo");
+ RNA_def_property_collection_funcs(
+ prop, "rna_GizmoGroup_gizmos_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+
+ RNA_def_property_ui_text(prop, "Gizmos", "List of gizmos in the Gizmo Map");
+ rna_def_gizmo(brna, prop);
+ rna_def_gizmos(brna, prop);
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+
+ RNA_api_gizmogroup(srna);
+
+ srna = RNA_def_struct(brna, "GizmoGroupProperties", NULL);
+ RNA_def_struct_ui_text(srna, "Gizmo Group Properties", "Input properties of a Gizmo Group");
+ RNA_def_struct_refine_func(srna, "rna_GizmoGroupProperties_refine");
+ RNA_def_struct_idprops_func(srna, "rna_GizmoGroupProperties_idprops");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
+}
+
+void RNA_def_wm_gizmo(BlenderRNA *brna)
+{
+ rna_def_gizmogroup(brna);
+}
+
+#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo_api.c b/source/blender/makesrna/intern/rna_wm_gizmo_api.c
new file mode 100644
index 00000000000..37c4e22b68e
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_wm_gizmo_api.c
@@ -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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_wm_gizmo_api.c
+ * \ingroup RNA
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "BKE_report.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DNA_windowmanager_types.h"
+
+#include "WM_api.h"
+
+#include "rna_internal.h" /* own include */
+
+#ifdef RNA_RUNTIME
+
+#include "UI_interface.h"
+#include "BKE_context.h"
+
+#include "ED_gizmo_library.h"
+
+static void rna_gizmo_draw_preset_box(
+ wmGizmo *gz, float matrix[16], int select_id)
+{
+ ED_gizmo_draw_preset_box(gz, (float (*)[4])matrix, select_id);
+}
+
+static void rna_gizmo_draw_preset_arrow(
+ wmGizmo *gz, float matrix[16], int axis, int select_id)
+{
+ ED_gizmo_draw_preset_arrow(gz, (float (*)[4])matrix, axis, select_id);
+}
+
+static void rna_gizmo_draw_preset_circle(
+ wmGizmo *gz, float matrix[16], int axis, int select_id)
+{
+ ED_gizmo_draw_preset_circle(gz, (float (*)[4])matrix, axis, select_id);
+}
+
+static void rna_gizmo_draw_preset_facemap(
+ wmGizmo *gz, struct bContext *C, struct Object *ob, int facemap, int select_id)
+{
+ ED_gizmo_draw_preset_facemap(C, gz, ob, facemap, select_id);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Gizmo Property Define
+ * \{ */
+
+static void rna_gizmo_target_set_prop(
+ wmGizmo *gz, ReportList *reports, const char *target_propname,
+ PointerRNA *ptr, const char *propname, int index)
+{
+ const wmGizmoPropertyType *gz_prop_type =
+ WM_gizmotype_target_property_find(gz->type, target_propname);
+ if (gz_prop_type == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Gizmo target property '%s.%s' not found",
+ gz->type->idname, target_propname);
+ return;
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ if (prop == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Property '%s.%s' not found",
+ RNA_struct_identifier(ptr->type), target_propname);
+ return;
+ }
+
+ if (gz_prop_type->data_type != RNA_property_type(prop)) {
+ const int gizmo_type_index = RNA_enum_from_value(rna_enum_property_type_items, gz_prop_type->data_type);
+ const int prop_type_index = RNA_enum_from_value(rna_enum_property_type_items, RNA_property_type(prop));
+ BLI_assert((gizmo_type_index != -1) && (prop_type_index == -1));
+
+ BKE_reportf(reports, RPT_ERROR, "Gizmo target '%s.%s' expects '%s', '%s.%s' is '%s'",
+ gz->type->idname, target_propname,
+ rna_enum_property_type_items[gizmo_type_index].identifier,
+ RNA_struct_identifier(ptr->type), propname,
+ rna_enum_property_type_items[prop_type_index].identifier);
+ return;
+ }
+
+ if (RNA_property_array_check(prop)) {
+ if (index == -1) {
+ const int prop_array_length = RNA_property_array_length(ptr, prop);
+ if (gz_prop_type->array_length != prop_array_length) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Gizmo target property '%s.%s' expects an array of length %d, found %d",
+ gz->type->idname, target_propname,
+ gz_prop_type->array_length,
+ prop_array_length);
+ return;
+ }
+ }
+ }
+ else {
+ if (gz_prop_type->array_length != 1) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Gizmo target property '%s.%s' expects an array of length %d",
+ gz->type->idname, target_propname,
+ gz_prop_type->array_length);
+ return;
+ }
+ }
+
+ if (index >= gz_prop_type->array_length) {
+ BKE_reportf(reports, RPT_ERROR, "Gizmo target property '%s.%s', index %d must be below %d",
+ gz->type->idname, target_propname, index, gz_prop_type->array_length);
+ return;
+ }
+
+ WM_gizmo_target_property_def_rna_ptr(gz, gz_prop_type, ptr, prop, index);
+}
+
+static PointerRNA rna_gizmo_target_set_operator(
+ wmGizmo *gz, ReportList *reports, const char *opname, int part_index)
+{
+ wmOperatorType *ot;
+
+ ot = WM_operatortype_find(opname, 0); /* print error next */
+ if (!ot || !ot->srna) {
+ BKE_reportf(reports, RPT_ERROR, "%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
+ return PointerRNA_NULL;
+ }
+
+ /* For the return value to be usable, we need 'PointerRNA.data' to be set. */
+ IDProperty *properties;
+ {
+ IDPropertyTemplate val = {0};
+ properties = IDP_New(IDP_GROUP, &val, "wmGizmoProperties");
+ }
+
+ return *WM_gizmo_operator_set(gz, part_index, ot, properties);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Gizmo Property Access
+ * \{ */
+
+static bool rna_gizmo_target_is_valid(
+ wmGizmo *gz, ReportList *reports, const char *target_propname)
+{
+ wmGizmoProperty *gz_prop =
+ WM_gizmo_target_property_find(gz, target_propname);
+ if (gz_prop == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Gizmo target property '%s.%s' not found",
+ gz->type->idname, target_propname);
+ return false;
+ }
+ return WM_gizmo_target_property_is_valid(gz_prop);
+}
+
+/** \} */
+
+#else
+
+void RNA_api_gizmo(StructRNA *srna)
+{
+ /* Utility draw functions, since we don't expose new OpenGL drawing wrappers via Python yet.
+ * exactly how these should be exposed isn't totally clear.
+ * However it's probably good to have some high level API's for this anyway.
+ * Just note that this could be re-worked once tests are done.
+ */
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ /* -------------------------------------------------------------------- */
+ /* Primitive Shapes */
+
+ /* draw_preset_box */
+ func = RNA_def_function(srna, "draw_preset_box", "rna_gizmo_draw_preset_box");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(parm, "", "The matrix to transform");
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+ /* draw_preset_box */
+ func = RNA_def_function(srna, "draw_preset_arrow", "rna_gizmo_draw_preset_arrow");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(parm, "", "The matrix to transform");
+ RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation");
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+ func = RNA_def_function(srna, "draw_preset_circle", "rna_gizmo_draw_preset_circle");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(parm, "", "The matrix to transform");
+ RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation");
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+ /* -------------------------------------------------------------------- */
+ /* Other Shapes */
+
+ /* draw_preset_facemap */
+ func = RNA_def_function(srna, "draw_preset_facemap", "rna_gizmo_draw_preset_facemap");
+ RNA_def_function_ui_description(func, "Draw the face-map of a mesh object");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_int(func, "face_map", 0, 0, INT_MAX, "Face map index", "", 0, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+
+ /* -------------------------------------------------------------------- */
+ /* Property API */
+
+ /* Define Properties */
+ /* note, 'target_set_handler' is defined in 'bpy_rna_gizmo.c' */
+ func = RNA_def_function(srna, "target_set_prop", "rna_gizmo_target_set_prop");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "");
+ parm = RNA_def_string(func, "target", NULL, 0, "", "Target property");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* similar to UILayout.prop */
+ parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_int(func, "index", -1, -1, INT_MAX, "", "", -1, INT_MAX); /* RNA_NO_INDEX == -1 */
+
+ func = RNA_def_function(srna, "target_set_operator", "rna_gizmo_target_set_operator");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(
+ func, "Operator to run when activating the gizmo "
+ "(overrides property targets)");
+ parm = RNA_def_string(func, "operator", NULL, 0, "", "Target operator");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_int(func, "index", 0, 0, 255, "Part index", "", 0, 255);
+
+ /* similar to UILayout.operator */
+ parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
+ /* Access Properties */
+ /* note, 'target_get', 'target_set' is defined in 'bpy_rna_gizmo.c' */
+ func = RNA_def_function(srna, "target_is_valid", "rna_gizmo_target_is_valid");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "property", NULL, 0, "", "Property identifier");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_function_ui_description(func, "");
+ parm = RNA_def_boolean(func, "result", 0, "", "");
+ RNA_def_function_return(func, parm);
+
+}
+
+
+void RNA_api_gizmogroup(StructRNA *UNUSED(srna))
+{
+ /* nothing yet */
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
new file mode 100644
index 00000000000..a79dc05e09b
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -0,0 +1,384 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_workspace.c
+ * \ingroup RNA
+ */
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+#include "RNA_types.h"
+
+#include "BKE_workspace.h"
+
+#include "ED_render.h"
+
+#include "RE_engine.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "rna_internal.h"
+
+/* Allow accessing private members of DNA_workspace_types.h */
+#define DNA_PRIVATE_WORKSPACE_ALLOW
+#include "DNA_workspace_types.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BLI_listbase.h"
+
+#include "BKE_global.h"
+
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "RNA_access.h"
+
+#include "WM_toolsystem.h"
+
+static void rna_window_update_all(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ WM_main_add_notifier(NC_WINDOW, NULL);
+}
+
+void rna_workspace_screens_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ WorkSpace *workspace = ptr->id.data;
+ rna_iterator_listbase_begin(iter, BKE_workspace_layouts_get(workspace), NULL);
+}
+
+static PointerRNA rna_workspace_screens_item_get(CollectionPropertyIterator *iter)
+{
+ WorkSpaceLayout *layout = rna_iterator_listbase_get(iter);
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Screen, screen);
+}
+
+/* workspace.owner_ids */
+
+static wmOwnerID *rna_WorkSpace_owner_ids_new(
+ WorkSpace *workspace, const char *name)
+{
+ wmOwnerID *owner_id = MEM_callocN(sizeof(*owner_id), __func__);
+ BLI_addtail(&workspace->owner_ids, owner_id);
+ BLI_strncpy(owner_id->name, name, sizeof(owner_id->name));
+ WM_main_add_notifier(NC_WINDOW, NULL);
+ return owner_id;
+}
+
+static void rna_WorkSpace_owner_ids_remove(
+ WorkSpace *workspace, ReportList *reports, PointerRNA *wstag_ptr)
+{
+ wmOwnerID *owner_id = wstag_ptr->data;
+ if (BLI_remlink_safe(&workspace->owner_ids, owner_id) == false) {
+ BKE_reportf(reports, RPT_ERROR,
+ "wmOwnerID '%s' not in workspace '%s'",
+ owner_id->name, workspace->id.name + 2);
+ return;
+ }
+
+ MEM_freeN(owner_id);
+ RNA_POINTER_INVALIDATE(wstag_ptr);
+
+ WM_main_add_notifier(NC_WINDOW, NULL);
+}
+
+static void rna_WorkSpace_owner_ids_clear(
+ WorkSpace *workspace)
+{
+ BLI_freelistN(&workspace->owner_ids);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, workspace);
+}
+
+static bToolRef *rna_WorkSpace_tools_from_tkey(WorkSpace *workspace, const bToolKey *tkey, bool create)
+{
+ if (create) {
+ bToolRef *tref;
+ WM_toolsystem_ref_ensure(workspace, tkey, &tref);
+ return tref;
+ }
+ return WM_toolsystem_ref_find(workspace, tkey);
+}
+
+static bToolRef *rna_WorkSpace_tools_from_space_view3d_mode(
+ WorkSpace *workspace, int mode, bool create)
+{
+ return rna_WorkSpace_tools_from_tkey(workspace, &(bToolKey){ .space_type = SPACE_VIEW3D, .mode = mode}, create);
+}
+
+static bToolRef *rna_WorkSpace_tools_from_space_image_mode(
+ WorkSpace *workspace, int mode, bool create)
+{
+ return rna_WorkSpace_tools_from_tkey(workspace, &(bToolKey){ .space_type = SPACE_IMAGE, .mode = mode}, create);
+}
+
+static bToolRef *rna_WorkSpace_tools_from_space_node(
+ WorkSpace *workspace, bool create)
+{
+ return rna_WorkSpace_tools_from_tkey(workspace, &(bToolKey){ .space_type = SPACE_NODE, .mode = 0}, create);
+}
+
+const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+{
+ WorkSpace *workspace = ptr->id.data;
+
+ switch (workspace->tools_space_type) {
+ case SPACE_VIEW3D:
+ return rna_enum_context_mode_items;
+ case SPACE_IMAGE:
+ return rna_enum_space_image_mode_items;
+ }
+ return DummyRNA_DEFAULT_items;
+}
+
+static int rna_WorkspaceTool_index_get(PointerRNA *ptr)
+{
+ bToolRef *tref = ptr->data;
+ return (tref->runtime) ? tref->runtime->index : 0;
+}
+
+static int rna_WorkspaceTool_has_datablock_get(PointerRNA *ptr)
+{
+ bToolRef *tref = ptr->data;
+ return (tref->runtime) ? (tref->runtime->data_block[0] != '\0') : false;
+}
+
+static void rna_WorkspaceTool_widget_get(PointerRNA *ptr, char *value)
+{
+ bToolRef *tref = ptr->data;
+ strcpy(value, tref->runtime ? tref->runtime->gizmo_group : "");
+}
+
+static int rna_WorkspaceTool_widget_length(PointerRNA *ptr)
+{
+ bToolRef *tref = ptr->data;
+ return tref->runtime ? strlen(tref->runtime->gizmo_group) : 0;
+}
+
+#else /* RNA_RUNTIME */
+
+static void rna_def_workspace_owner(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "wmOwnerID", NULL);
+ RNA_def_struct_sdna(srna, "wmOwnerID");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Work Space UI Tag", "");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_struct_name_property(srna, prop);
+}
+
+static void rna_def_workspace_owner_ids(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "wmOwnerIDs");
+ srna = RNA_def_struct(brna, "wmOwnerIDs", NULL);
+ RNA_def_struct_sdna(srna, "WorkSpace");
+ RNA_def_struct_ui_text(srna, "WorkSpace UI Tags", "");
+
+ /* add owner_id */
+ func = RNA_def_function(srna, "new", "rna_WorkSpace_owner_ids_new");
+ RNA_def_function_ui_description(func, "Add ui tag");
+ parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the tag");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "owner_id", "wmOwnerID", "", "");
+ RNA_def_function_return(func, parm);
+
+ /* remove owner_id */
+ func = RNA_def_function(srna, "remove", "rna_WorkSpace_owner_ids_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove ui tag");
+ /* owner_id to remove */
+ parm = RNA_def_pointer(func, "owner_id", "wmOwnerID", "", "Tag to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ /* clear all modifiers */
+ func = RNA_def_function(srna, "clear", "rna_WorkSpace_owner_ids_clear");
+ RNA_def_function_ui_description(func, "Remove all tags");
+}
+
+static void rna_def_workspace_tool(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "WorkspaceTool", NULL);
+ RNA_def_struct_sdna(srna, "bToolRef");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Work Space Tool", "");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "idname");
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Index", "");
+ RNA_def_property_int_funcs(prop, "rna_WorkspaceTool_index_get", NULL, NULL);
+
+ prop = RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "space_type");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
+ RNA_def_property_ui_text(prop, "Space Type", "");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_WorkSpace_tools_mode_itemf");
+ RNA_def_property_ui_text(prop, "Tool Mode", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ RNA_define_verify_sdna(0);
+ prop = RNA_def_property(srna, "has_datablock", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Has Datablock", "");
+ RNA_def_property_boolean_funcs(prop, "rna_WorkspaceTool_has_datablock_get", NULL);
+ RNA_define_verify_sdna(1);
+
+ prop = RNA_def_property(srna, "widget", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Widget", "");
+ RNA_def_property_string_funcs(prop, "rna_WorkspaceTool_widget_get", "rna_WorkspaceTool_widget_length", NULL);
+ RNA_define_verify_sdna(1);
+
+ RNA_api_workspace_tool(srna);
+}
+
+static void rna_def_workspace_tools(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "wmTools");
+ srna = RNA_def_struct(brna, "wmTools", NULL);
+ RNA_def_struct_sdna(srna, "WorkSpace");
+ RNA_def_struct_ui_text(srna, "WorkSpace UI Tags", "");
+
+ /* add owner_id */
+ func = RNA_def_function(srna, "from_space_view3d_mode", "rna_WorkSpace_tools_from_space_view3d_mode");
+ RNA_def_function_ui_description(func, "");
+ parm = RNA_def_enum(func, "mode", rna_enum_context_mode_items, 0, "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "create", false, "Create", "");
+ /* return type */
+ parm = RNA_def_pointer(func, "result", "WorkspaceTool", "", "");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "from_space_image_mode", "rna_WorkSpace_tools_from_space_image_mode");
+ RNA_def_function_ui_description(func, "");
+ parm = RNA_def_enum(func, "mode", rna_enum_space_image_mode_items, 0, "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_boolean(func, "create", false, "Create", "");
+ /* return type */
+ parm = RNA_def_pointer(func, "result", "WorkspaceTool", "", "");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "from_space_node", "rna_WorkSpace_tools_from_space_node");
+ RNA_def_function_ui_description(func, "");
+ RNA_def_boolean(func, "create", false, "Create", "");
+ /* return type */
+ parm = RNA_def_pointer(func, "result", "WorkspaceTool", "", "");
+ RNA_def_function_return(func, parm);
+}
+
+static void rna_def_workspace(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "WorkSpace", "ID");
+ RNA_def_struct_sdna(srna, "WorkSpace");
+ RNA_def_struct_ui_text(srna, "Workspace", "Workspace data-block, defining the working environment for the user");
+ /* TODO: real icon, just to show something */
+ RNA_def_struct_ui_icon(srna, ICON_WORKSPACE);
+
+ prop = RNA_def_property(srna, "screens", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "layouts", NULL);
+ RNA_def_property_struct_type(prop, "Screen");
+ RNA_def_property_collection_funcs(prop, "rna_workspace_screens_begin", NULL, NULL,
+ "rna_workspace_screens_item_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Screens", "Screen layouts of a workspace");
+
+ prop = RNA_def_property(srna, "owner_ids", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "wmOwnerID");
+ RNA_def_property_ui_text(prop, "UI Tags", "");
+ rna_def_workspace_owner_ids(brna, prop);
+
+ prop = RNA_def_property(srna, "tools", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "tools", NULL);
+ RNA_def_property_struct_type(prop, "WorkspaceTool");
+ RNA_def_property_ui_text(prop, "Tools", "");
+ rna_def_workspace_tools(brna, prop);
+
+ prop = RNA_def_property(srna, "tools_space_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "tools_space_type");
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
+ RNA_def_property_ui_text(prop, "Active Tool Space", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "tools_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "tools_mode");
+ RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_WorkSpace_tools_mode_itemf");
+ RNA_def_property_ui_text(prop, "Active Tool Mode", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_workspace_object_mode_items);
+ RNA_def_property_ui_text(prop, "Object Mode", "Switch to this object mode when activating the workspace");
+
+ /* Flags */
+ prop = RNA_def_property(srna, "use_filter_by_owner", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", WORKSPACE_USE_FILTER_BY_ORIGIN);
+ RNA_def_property_ui_text(prop, "Use UI Tags",
+ "Filter the UI by tags");
+ RNA_def_property_update(prop, 0, "rna_window_update_all");
+
+ RNA_api_workspace(srna);
+}
+
+void RNA_def_workspace(BlenderRNA *brna)
+{
+ rna_def_workspace_owner(brna);
+ rna_def_workspace_tool(brna);
+
+ rna_def_workspace(brna);
+}
+
+#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c
new file mode 100644
index 00000000000..fd268c898ff
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_workspace_api.c
@@ -0,0 +1,176 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_workspace_api.c
+ * \ingroup RNA
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "BLI_utildefines.h"
+
+#include "RNA_define.h"
+
+#include "DNA_object_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_enum_types.h" /* own include */
+
+#include "rna_internal.h" /* own include */
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_paint.h"
+
+#include "ED_screen.h"
+
+static void rna_WorkspaceTool_setup(
+ ID *id,
+ bToolRef *tref,
+ bContext *C,
+ const char *name,
+ /* Args for: 'bToolRef_Runtime'. */
+ int cursor,
+ const char *keymap,
+ const char *gizmo_group,
+ const char *data_block,
+ const char *operator,
+ int index)
+{
+ bToolRef_Runtime tref_rt = {0};
+
+ tref_rt.cursor = cursor;
+ STRNCPY(tref_rt.keymap, keymap);
+ STRNCPY(tref_rt.gizmo_group, gizmo_group);
+ STRNCPY(tref_rt.data_block, data_block);
+ STRNCPY(tref_rt.op, operator);
+ tref_rt.index = index;
+
+ WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, name);
+}
+
+static void rna_WorkspaceTool_refresh_from_context(
+ ID *id,
+ bToolRef *tref,
+ Main *bmain)
+{
+ WM_toolsystem_ref_sync_from_context(bmain, (WorkSpace *)id, tref);
+}
+
+static PointerRNA rna_WorkspaceTool_operator_properties(
+ bToolRef *tref,
+ ReportList *reports,
+ const char *idname)
+{
+ wmOperatorType *ot = WM_operatortype_find(idname, true);
+
+ if (ot != NULL) {
+ PointerRNA ptr;
+ WM_toolsystem_ref_properties_ensure_from_operator(tref, ot, &ptr);
+ return ptr;
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Operator '%s' not found!", idname);
+ }
+ return PointerRNA_NULL;
+}
+
+static PointerRNA rna_WorkspaceTool_gizmo_group_properties(
+ bToolRef *tref,
+ ReportList *reports,
+ const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ if (gzgt != NULL) {
+ PointerRNA ptr;
+ WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgt, &ptr);
+ return ptr;
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Gizmo group '%s' not found!", idname);
+ }
+ return PointerRNA_NULL;
+}
+
+#else
+
+void RNA_api_workspace(StructRNA *srna)
+{
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func = RNA_def_function(srna, "status_text_set", "ED_workspace_status_text");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Set the status bar text, typically key shortcuts for modal operators");
+ parm = RNA_def_string(func, "text", NULL, 0, "Text", "New string for the status bar, None clears the text");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_clear_flag(parm, PROP_NEVER_NULL);
+}
+
+void RNA_api_workspace_tool(StructRNA *srna)
+{
+ PropertyRNA *parm;
+ FunctionRNA *func;
+
+ func = RNA_def_function(srna, "setup", "rna_WorkspaceTool_setup");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Set the tool settings");
+
+ parm = RNA_def_string(func, "name", NULL, KMAP_MAX_NAME, "Name", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ /* 'bToolRef_Runtime' */
+ parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(parm, rna_enum_window_cursor_items);
+ RNA_def_string(func, "keymap", NULL, KMAP_MAX_NAME, "Key Map", "");
+ RNA_def_string(func, "gizmo_group", NULL, MAX_NAME, "Gizmo Group", "");
+ RNA_def_string(func, "data_block", NULL, MAX_NAME, "Data Block", "");
+ RNA_def_string(func, "operator", NULL, MAX_NAME, "Operator", "");
+ RNA_def_int(func, "index", 0, INT_MIN, INT_MAX, "Index", "", INT_MIN, INT_MAX);
+
+ /* Access tool operator options (optionally create). */
+ func = RNA_def_function(srna, "operator_properties", "rna_WorkspaceTool_operator_properties");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "operator", NULL, 0, "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return */
+ parm = RNA_def_pointer(func, "result", "OperatorProperties", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
+ /* Access gizmo-group options (optionally create). */
+ func = RNA_def_function(srna, "gizmo_group_properties", "rna_WorkspaceTool_gizmo_group_properties");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "group", NULL, 0, "", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return */
+ parm = RNA_def_pointer(func, "result", "GizmoGroupProperties", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "refresh_from_context", "rna_WorkspaceTool_refresh_from_context");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index 08287308e08..fe561cdef1c 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -43,10 +43,12 @@
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "ED_node.h"
#include "WM_api.h"
@@ -62,33 +64,11 @@ static PointerRNA rna_World_mist_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_WorldMistSettings, ptr->id.data);
}
-static void rna_World_mtex_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- World *wo = (World *)ptr->data;
- rna_iterator_array_begin(iter, (void *)wo->mtex, sizeof(MTex *), MAX_MTEX, 0, NULL);
-}
-
-static PointerRNA rna_World_active_texture_get(PointerRNA *ptr)
-{
- World *wo = (World *)ptr->data;
- Tex *tex;
-
- tex = give_current_world_texture(wo);
- return rna_pointer_inherit_refine(ptr, &RNA_Texture, tex);
-}
-
-static void rna_World_active_texture_set(PointerRNA *ptr, PointerRNA value)
-{
- World *wo = (World *)ptr->data;
-
- set_current_world_texture(wo, value.data);
-}
-
static void rna_World_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
World *wo = ptr->id.data;
- DAG_id_tag_update(&wo->id, 0);
+ DEG_id_tag_update(&wo->id, 0);
WM_main_add_notifier(NC_WORLD | ND_WORLD, wo);
}
@@ -97,7 +77,7 @@ static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
{
World *wo = ptr->id.data;
- DAG_id_tag_update(&wo->id, 0);
+ DEG_id_tag_update(&wo->id, 0);
WM_main_add_notifier(NC_WORLD | ND_WORLD_DRAW, wo);
}
#endif
@@ -106,7 +86,7 @@ static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
{
World *wo = ptr->id.data;
- DAG_id_tag_update(&wo->id, 0);
+ DEG_id_tag_update(&wo->id, 0);
WM_main_add_notifier(NC_WORLD | ND_WORLD_DRAW, wo);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
@@ -114,126 +94,24 @@ static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
static void rna_World_use_nodes_update(bContext *C, PointerRNA *ptr)
{
World *wrld = (World *)ptr->data;
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
if (wrld->use_nodes && wrld->nodetree == NULL)
ED_node_shader_default(C, &wrld->id);
- rna_World_update(CTX_data_main(C), CTX_data_scene(C), ptr);
+ DEG_relations_tag_update(bmain);
+ rna_World_update(bmain, scene, ptr);
+ rna_World_draw_update(bmain, scene, ptr);
}
#else
-static void rna_def_world_mtex(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- static const EnumPropertyItem texco_items[] = {
- {TEXCO_VIEW, "VIEW", 0, "View", "Use view vector for the texture coordinates"},
- {TEXCO_GLOB, "GLOBAL", 0, "Global", "Use global coordinates for the texture coordinates (interior mist)"},
- {TEXCO_ANGMAP, "ANGMAP", 0, "AngMap", "Use 360 degree angular coordinates, e.g. for spherical light probes"},
- {TEXCO_H_SPHEREMAP, "SPHERE", 0, "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"},
- {TEXCO_EQUIRECTMAP, "EQUIRECT", 0, "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"},
- {TEXCO_H_TUBEMAP, "TUBE", 0, "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"},
- {TEXCO_OBJECT, "OBJECT", 0, "Object", "Use linked object's coordinates for texture coordinates"},
- {0, NULL, 0, NULL, NULL}
- };
-
- srna = RNA_def_struct(brna, "WorldTextureSlot", "TextureSlot");
- RNA_def_struct_sdna(srna, "MTex");
- RNA_def_struct_ui_text(srna, "World Texture Slot", "Texture slot for textures in a World data-block");
-
- /* map to */
- prop = RNA_def_property(srna, "use_map_blend", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", WOMAP_BLEND);
- RNA_def_property_ui_text(prop, "Blend", "Affect the color progression of the background");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "use_map_horizon", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", WOMAP_HORIZ);
- RNA_def_property_ui_text(prop, "Horizon", "Affect the color of the horizon");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "use_map_zenith_up", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", WOMAP_ZENUP);
- RNA_def_property_ui_text(prop, "Zenith Up", "Affect the color of the zenith above");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "use_map_zenith_down", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", WOMAP_ZENDOWN);
- RNA_def_property_ui_text(prop, "Zenith Down", "Affect the color of the zenith below");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "texco");
- RNA_def_property_enum_items(prop, texco_items);
- RNA_def_property_ui_text(prop, "Texture Coordinates",
- "Texture coordinates used to map the texture onto the background");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "object");
- RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Object", "Object to use for mapping with Object texture coordinates");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "blend_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "blendfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Blend Factor", "Amount texture affects color progression of the background");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "horizon_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "colfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Horizon Factor", "Amount texture affects color of the horizon");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "zenith_up_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "zenupfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Zenith Up Factor", "Amount texture affects color of the zenith above");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "zenith_down_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "zendownfac");
- RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Zenith Down Factor", "Amount texture affects color of the zenith below");
- RNA_def_property_update(prop, 0, "rna_World_update");
-}
-
static void rna_def_lighting(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
- static const EnumPropertyItem blend_mode_items[] = {
- {WO_AOMUL, "MULTIPLY", 0, "Multiply", "Multiply direct lighting with ambient occlusion, darkening the result"},
- {WO_AOADD, "ADD", 0, "Add", "Add light and shadow"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_color_items[] = {
- {WO_AOPLAIN, "PLAIN", 0, "White", "Plain diffuse energy (white.)"},
- {WO_AOSKYCOL, "SKY_COLOR", 0, "Sky Color", "Use horizon and zenith color for diffuse energy"},
- {WO_AOSKYTEX, "SKY_TEXTURE", 0, "Sky Texture", "Does full Sky texture render for diffuse energy"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_sample_method_items[] = {
- {WO_AOSAMP_CONSTANT, "CONSTANT_JITTERED", 0, "Constant Jittered", "Fastest and gives the most noise"},
- {WO_AOSAMP_HALTON, "ADAPTIVE_QMC", 0, "Adaptive QMC", "Fast in high-contrast areas"},
- {WO_AOSAMP_HAMMERSLEY, "CONSTANT_QMC", 0, "Constant QMC", "Best quality"},
- {0, NULL, 0, NULL, NULL}
- };
-
- static const EnumPropertyItem prop_gather_method_items[] = {
- {WO_AOGATHER_RAYTRACE, "RAYTRACE", 0, "Raytrace", "Accurate, but slow when noise-free results are required"},
- {WO_AOGATHER_APPROX, "APPROXIMATE", 0, "Approximate", "Inaccurate, but faster and without noise"},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "WorldLighting", NULL);
RNA_def_struct_sdna(srna, "World");
RNA_def_struct_nested(brna, srna, "World");
@@ -253,135 +131,12 @@ static void rna_def_lighting(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Factor", "Factor for ambient occlusion blending");
RNA_def_property_update(prop, 0, "rna_World_update");
- prop = RNA_def_property(srna, "ao_blend_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "aomix");
- RNA_def_property_enum_items(prop, blend_mode_items);
- RNA_def_property_ui_text(prop, "Blend Mode", "Defines how AO mixes with material shading");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- /* environment lighting */
- prop = RNA_def_property(srna, "use_environment_light", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_ENV_LIGHT);
- RNA_def_property_ui_text(prop, "Use Environment Lighting", "Add light coming from the environment");
- RNA_def_property_update(prop, 0, "rna_World_draw_update");
-
- prop = RNA_def_property(srna, "environment_energy", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ao_env_energy");
- RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, 3);
- RNA_def_property_ui_text(prop, "Environment Color", "Defines the strength of environment light");
- RNA_def_property_update(prop, 0, "rna_World_draw_update");
-
- prop = RNA_def_property(srna, "environment_color", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "aocolor");
- RNA_def_property_enum_items(prop, prop_color_items);
- RNA_def_property_ui_text(prop, "Environment Color", "Defines where the color of the environment light comes from");
- RNA_def_property_update(prop, 0, "rna_World_draw_update");
-
- /* indirect lighting */
- prop = RNA_def_property(srna, "use_indirect_light", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_INDIRECT_LIGHT);
- RNA_def_property_ui_text(prop, "Use Indirect Lighting", "Add indirect light bouncing of surrounding objects");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "indirect_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "ao_indirect_energy");
- RNA_def_property_range(prop, 0, INT_MAX);
- RNA_def_property_ui_range(prop, 0, 1, 0.1, 2);
- RNA_def_property_ui_text(prop, "Indirect Factor", "Factor for how much surrounding objects contribute to light");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "indirect_bounces", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "ao_indirect_bounces");
- RNA_def_property_range(prop, 1, SHRT_MAX);
- RNA_def_property_ui_text(prop, "Bounces", "Number of indirect diffuse light bounces");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- /* gathering parameters */
- prop = RNA_def_property(srna, "gather_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "ao_gather_method");
- RNA_def_property_enum_items(prop, prop_gather_method_items);
- RNA_def_property_ui_text(prop, "Gather Method", "");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "passes", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "ao_approx_passes");
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(prop, "Passes", "Number of preprocessing passes to reduce over-occlusion");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "aodist");
RNA_def_property_ui_text(prop, "Distance",
"Length of rays, defines how far away other faces give occlusion effect");
RNA_def_property_update(prop, 0, "rna_World_update");
- prop = RNA_def_property(srna, "falloff_strength", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "aodistfac");
- RNA_def_property_ui_text(prop, "Strength",
- "Attenuation falloff strength, the higher, the less influence distant objects have");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "bias", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "aobias");
- RNA_def_property_range(prop, 0, 0.5);
- RNA_def_property_ui_text(prop, "Bias",
- "Bias (in radians) to prevent smoothed faces from showing banding "
- "(for Raytrace Constant Jittered)");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ao_adapt_thresh");
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_text(prop, "Threshold",
- "Samples below this threshold will be considered fully shadowed/unshadowed and skipped "
- "(for Raytrace Adaptive QMC)");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "adapt_to_speed", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ao_adapt_speed_fac");
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_text(prop, "Adapt To Speed",
- "Use the speed vector pass to reduce AO samples in fast moving pixels - "
- "higher values result in more aggressive sample reduction "
- "(requires Vec pass enabled, for Raytrace Adaptive QMC)");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "error_threshold", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ao_approx_error");
- RNA_def_property_range(prop, 0.0001, 10);
- RNA_def_property_ui_text(prop, "Error Tolerance", "Low values are slower and higher quality");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "correction", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ao_approx_correction");
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_range(prop, 0, 1, 0.1, 2);
- RNA_def_property_ui_text(prop, "Correction", "Ad-hoc correction for over-occlusion due to the approximation");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "use_falloff", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "aomode", WO_AODIST);
- RNA_def_property_ui_text(prop, "Falloff", "Distance will be used to attenuate shadows");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "use_cache", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "aomode", WO_AOCACHE);
- RNA_def_property_ui_text(prop, "Pixel Cache",
- "Cache AO results in pixels and interpolate over neighboring pixels for speedup");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "aosamp");
- RNA_def_property_range(prop, 1, 128);
- RNA_def_property_ui_text(prop, "Samples",
- "Amount of ray samples. Higher values give smoother results and longer rendering times");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "sample_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "ao_samp_method");
- RNA_def_property_enum_items(prop, prop_sample_method_items);
- RNA_def_property_ui_text(prop, "Sample Method", "Method for generating shadow samples (for Raytrace)");
- RNA_def_property_update(prop, 0, "rna_World_update");
}
static void rna_def_world_mist(BlenderRNA *brna)
@@ -390,9 +145,9 @@ static void rna_def_world_mist(BlenderRNA *brna)
PropertyRNA *prop;
static const EnumPropertyItem falloff_items[] = {
- {0, "QUADRATIC", 0, "Quadratic", "Use quadratic progression"},
- {1, "LINEAR", 0, "Linear", "Use linear progression"},
- {2, "INVERSE_QUADRATIC", 0, "Inverse Quadratic", "Use inverse quadratic progression"},
+ {WO_MIST_QUADRATIC, "QUADRATIC", 0, "Quadratic", "Use quadratic progression"},
+ {WO_MIST_LINEAR, "LINEAR", 0, "Linear", "Use linear progression"},
+ {WO_MIST_INVERSE_QUADRATIC, "INVERSE_QUADRATIC", 0, "Inverse Quadratic", "Use inverse quadratic progression"},
{0, NULL, 0, NULL, NULL}
};
@@ -444,66 +199,25 @@ void RNA_def_world(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static float default_world_color[] = {0.05f, 0.05f, 0.05f};
+
srna = RNA_def_struct(brna, "World", "ID");
RNA_def_struct_ui_text(srna, "World",
"World data-block describing the environment and ambient lighting of a scene");
RNA_def_struct_ui_icon(srna, ICON_WORLD_DATA);
rna_def_animdata_common(srna);
- rna_def_mtex_common(brna, srna, "rna_World_mtex_begin", "rna_World_active_texture_get",
- "rna_World_active_texture_set", NULL, "WorldTextureSlot", "WorldTextureSlots",
- "rna_World_update", "rna_World_update");
/* colors */
- prop = RNA_def_property(srna, "horizon_color", PROP_FLOAT, PROP_COLOR);
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "horr");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Horizon Color", "Color at the horizon");
+ RNA_def_property_float_array_default(prop, default_world_color);
+ RNA_def_property_ui_text(prop, "Color", "Color of the background");
/* RNA_def_property_update(prop, 0, "rna_World_update"); */
/* render-only uses this */
RNA_def_property_update(prop, 0, "rna_World_draw_update");
- prop = RNA_def_property(srna, "zenith_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "zenr");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Zenith Color", "Color at the zenith");
- RNA_def_property_update(prop, 0, "rna_World_draw_update");
-
- prop = RNA_def_property(srna, "ambient_color", PROP_FLOAT, PROP_COLOR);
- RNA_def_property_float_sdna(prop, NULL, "ambr");
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Ambient Color", "Ambient color of the world");
- RNA_def_property_update(prop, 0, "rna_World_draw_update");
-
- /* exp, range */
- prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "exp");
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_text(prop, "Exposure", "Amount of exponential color correction for light");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- prop = RNA_def_property(srna, "color_range", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "range");
- RNA_def_property_range(prop, 0.2, 5.0);
- RNA_def_property_ui_text(prop, "Range", "The color range that will be mapped to 0-1");
- RNA_def_property_update(prop, 0, "rna_World_update");
-
- /* sky type */
- prop = RNA_def_property(srna, "use_sky_blend", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "skytype", WO_SKYBLEND);
- RNA_def_property_ui_text(prop, "Blend Sky", "Render background with natural progression from horizon to zenith");
- RNA_def_property_update(prop, NC_WORLD | ND_WORLD_DRAW, "rna_World_update");
-
- prop = RNA_def_property(srna, "use_sky_paper", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "skytype", WO_SKYPAPER);
- RNA_def_property_ui_text(prop, "Paper Sky", "Flatten blend or texture coordinates");
- RNA_def_property_update(prop, NC_WORLD | ND_WORLD_DRAW, "rna_World_update");
-
- prop = RNA_def_property(srna, "use_sky_real", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "skytype", WO_SKYREAL);
- RNA_def_property_ui_text(prop, "Real Sky", "Render background with a real horizon, relative to the camera angle");
- RNA_def_property_update(prop, NC_WORLD | ND_WORLD_DRAW, "rna_World_update");
-
/* nested structs */
prop = RNA_def_property(srna, "light_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -531,7 +245,6 @@ void RNA_def_world(BlenderRNA *brna)
rna_def_lighting(brna);
rna_def_world_mist(brna);
- rna_def_world_mtex(brna);
}
#endif
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 80a67083582..e914100249b 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -100,6 +100,7 @@ set(SRC
intern/MOD_uvproject.c
intern/MOD_warp.c
intern/MOD_wave.c
+ intern/MOD_weighted_normal.c
intern/MOD_weightvg_util.c
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
@@ -113,10 +114,6 @@ set(SRC
intern/MOD_weightvg_util.h
)
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
-endif()
-
if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
list(APPEND INC
@@ -147,8 +144,7 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_OPENSUBDIV)
- add_definitions(-DWITH_OPENSUBDIV)
-endif()
+# So we can have special tricks in modifier system.
+add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_modifiers "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index bf121af2bd1..3511b0edbec 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -86,6 +86,7 @@ extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
extern ModifierTypeInfo modifierType_MeshSequenceCache;
extern ModifierTypeInfo modifierType_SurfaceDeform;
+extern ModifierTypeInfo modifierType_WeightedNormal;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 5b5e139d33a..f37b5d4ec4d 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -42,15 +42,17 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
-
-#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
-#include "MEM_guardedalloc.h"
+#include "bmesh.h"
+#include "bmesh_tools.h"
-#include "depsgraph_private.h"
+#include "MEM_guardedalloc.h"
#include "MOD_util.h"
@@ -62,14 +64,14 @@ static void initData(ModifierData *md)
amd->deformflag = ARM_DEF_VGROUP;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
#if 0
const ArmatureModifierData *amd = (const ArmatureModifierData *) md;
#endif
ArmatureModifierData *tamd = (ArmatureModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
tamd->prevCos = NULL;
}
@@ -83,7 +85,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(
return dataMask;
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
@@ -99,18 +101,6 @@ static void foreachObjectLink(
walk(userData, ob, &amd->object, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- ArmatureModifierData *amd = (ArmatureModifierData *) md;
-
- if (amd->object) {
- DagNode *curNode = dag_get_node(ctx->forest, amd->object);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Armature Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -122,18 +112,17 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
- modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
+ MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */
- armature_deform_verts(amd->object, ob, derivedData, vertexCos, NULL,
- numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name);
+ armature_deform_verts(amd->object, ctx->object, mesh, vertexCos, NULL,
+ numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name, NULL);
/* free cache */
if (amd->prevCos) {
@@ -143,18 +132,16 @@ static void deformVerts(
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *em,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
- DerivedMesh *dm = derivedData;
-
- if (!derivedData) dm = CDDM_from_editbmesh(em, false, false);
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
- modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
+ MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */
- armature_deform_verts(amd->object, ob, dm, vertexCos, NULL,
- numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name);
+ armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, NULL,
+ numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name, NULL);
/* free cache */
if (amd->prevCos) {
@@ -162,38 +149,40 @@ static void deformVertsEM(
amd->prevCos = NULL;
}
- if (!derivedData) dm->release(dm);
+ if (mesh_src != mesh) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformMatricesEM(
- ModifierData *md, Object *ob, struct BMEditMesh *em,
- DerivedMesh *derivedData, float (*vertexCos)[3],
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em,
+ Mesh *mesh, float (*vertexCos)[3],
float (*defMats)[3][3], int numVerts)
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
- DerivedMesh *dm = derivedData;
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
- if (!derivedData) dm = CDDM_from_editbmesh(em, false, false);
+ armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, defMats, numVerts,
+ amd->deformflag, NULL, amd->defgrp_name, NULL);
- armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts,
- amd->deformflag, NULL, amd->defgrp_name);
-
- if (!derivedData) dm->release(dm);
+ if (mesh_src != mesh) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformMatrices(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
- DerivedMesh *dm = derivedData;
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
- if (!derivedData) dm = CDDM_from_mesh((Mesh *)ob->data);
+ armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, defMats, numVerts,
+ amd->deformflag, NULL, amd->defgrp_name, NULL);
- armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts,
- amd->deformflag, NULL, amd->defgrp_name);
-
- if (!derivedData) dm->release(dm);
+ if (mesh_src != mesh) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
ModifierTypeInfo modifierType_Armature = {
@@ -206,17 +195,23 @@ ModifierTypeInfo modifierType_Armature = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ deformMatricesEM,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index d7f6c263906..9decf8e3bb5 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -41,13 +41,14 @@
#include "BLI_utildefines.h"
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_displist.h"
#include "BKE_curve.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
@@ -55,13 +56,7 @@
#include "MOD_util.h"
-#include "depsgraph_private.h"
-
-/* Due to cyclic dependencies it's possible that curve used for
- * deformation here is not evaluated at the time of evaluating
- * this modifier.
- */
-#define CYCLIC_DEPENDENCY_WORKAROUND
+#include "DEG_depsgraph.h"
static void initData(ModifierData *md)
{
@@ -94,37 +89,6 @@ static void foreachObjectLink(
walk(userData, ob, &amd->offset_ob, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- ArrayModifierData *amd = (ArrayModifierData *) md;
-
- if (amd->start_cap) {
- DagNode *curNode = dag_get_node(ctx->forest, amd->start_cap);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
- }
- if (amd->end_cap) {
- DagNode *curNode = dag_get_node(ctx->forest, amd->end_cap);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
- }
- if (amd->curve_ob) {
- DagNode *curNode = dag_get_node(ctx->forest, amd->curve_ob);
- curNode->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
- }
- if (amd->offset_ob) {
- DagNode *curNode = dag_get_node(ctx->forest, amd->offset_ob);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ArrayModifierData *amd = (ArrayModifierData *)md;
@@ -137,13 +101,13 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DEG_add_object_relation(ctx->node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Array Modifier End Cap");
}
if (amd->curve_ob) {
- struct Depsgraph *depsgraph = DEG_get_graph_from_handle(ctx->node);
DEG_add_object_relation(ctx->node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve");
- DEG_add_special_eval_flag(depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
+ DEG_add_special_eval_flag(ctx->node, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
}
if (amd->offset_ob != NULL) {
DEG_add_object_relation(ctx->node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset");
}
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Array Modifier");
}
BLI_INLINE float sum_v3(const float v[3])
@@ -303,8 +267,8 @@ static void dm_mvert_map_doubles(
}
-static void dm_merge_transform(
- DerivedMesh *result, DerivedMesh *cap_dm, float cap_offset[4][4],
+static void mesh_merge_transform(
+ Mesh *result, Mesh *cap_mesh, float cap_offset[4][4],
unsigned int cap_verts_index, unsigned int cap_edges_index, int cap_loops_index, int cap_polys_index,
int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys, int *remap, int remap_len)
{
@@ -316,18 +280,12 @@ static void dm_merge_transform(
MPoly *mp;
MDeformVert *dvert;
- /* needed for subsurf so arrays are allocated */
- cap_dm->getVertArray(cap_dm);
- cap_dm->getEdgeArray(cap_dm);
- cap_dm->getLoopArray(cap_dm);
- cap_dm->getPolyArray(cap_dm);
-
- DM_copy_vert_data(cap_dm, result, 0, cap_verts_index, cap_nverts);
- DM_copy_edge_data(cap_dm, result, 0, cap_edges_index, cap_nedges);
- DM_copy_loop_data(cap_dm, result, 0, cap_loops_index, cap_nloops);
- DM_copy_poly_data(cap_dm, result, 0, cap_polys_index, cap_npolys);
+ CustomData_copy_data(&cap_mesh->vdata, &result->vdata, 0, cap_verts_index, cap_nverts);
+ CustomData_copy_data(&cap_mesh->edata, &result->edata, 0, cap_edges_index, cap_nedges);
+ CustomData_copy_data(&cap_mesh->ldata, &result->ldata, 0, cap_loops_index, cap_nloops);
+ CustomData_copy_data(&cap_mesh->pdata, &result->pdata, 0, cap_polys_index, cap_npolys);
- mv = CDDM_get_verts(result) + cap_verts_index;
+ mv = result->mvert + cap_verts_index;
for (i = 0; i < cap_nverts; i++, mv++) {
mul_m4_v3(cap_offset, mv->co);
@@ -336,57 +294,55 @@ static void dm_merge_transform(
}
/* remap the vertex groups if necessary */
- dvert = DM_get_vert_data(result, cap_verts_index, CD_MDEFORMVERT);
+ dvert = result->dvert + cap_verts_index;
if (dvert != NULL) {
BKE_object_defgroup_index_map_apply(dvert, cap_nverts, remap, remap_len);
}
/* adjust cap edge vertex indices */
- me = CDDM_get_edges(result) + cap_edges_index;
+ me = result->medge + cap_edges_index;
for (i = 0; i < cap_nedges; i++, me++) {
me->v1 += cap_verts_index;
me->v2 += cap_verts_index;
}
/* adjust cap poly loopstart indices */
- mp = CDDM_get_polys(result) + cap_polys_index;
+ mp = result->mpoly + cap_polys_index;
for (i = 0; i < cap_npolys; i++, mp++) {
mp->loopstart += cap_loops_index;
}
/* adjust cap loop vertex and edge indices */
- ml = CDDM_get_loops(result) + cap_loops_index;
+ ml = result->mloop + cap_loops_index;
for (i = 0; i < cap_nloops; i++, ml++) {
ml->v += cap_verts_index;
ml->e += cap_edges_index;
}
/* set origindex */
- index_orig = result->getVertDataArray(result, CD_ORIGINDEX);
+ index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX);
if (index_orig) {
copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
}
- index_orig = result->getEdgeDataArray(result, CD_ORIGINDEX);
+ index_orig = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
if (index_orig) {
copy_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE);
}
- index_orig = result->getPolyDataArray(result, CD_ORIGINDEX);
+ index_orig = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
if (index_orig) {
copy_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
}
- index_orig = result->getLoopDataArray(result, CD_ORIGINDEX);
+ index_orig = CustomData_get_layer(&result->ldata, CD_ORIGINDEX);
if (index_orig) {
copy_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
}
}
-static DerivedMesh *arrayModifier_doArray(
- ArrayModifierData *amd,
- Scene *scene, Object *ob, DerivedMesh *dm,
- ModifierApplyFlag flag)
+static Mesh *arrayModifier_doArray(
+ ArrayModifierData *amd, const ModifierEvalContext *ctx, Mesh *mesh)
{
const float eps = 1e-6f;
const MVert *src_mvert;
@@ -407,7 +363,7 @@ static DerivedMesh *arrayModifier_doArray(
int tot_doubles;
const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0;
- const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge;
+ const bool use_recalc_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || use_merge;
const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob);
int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0;
@@ -416,47 +372,50 @@ static DerivedMesh *arrayModifier_doArray(
int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys;
int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts;
- DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL;
+ Mesh *result, *start_cap_mesh = NULL, *end_cap_mesh = NULL;
+ bool start_cap_mesh_free, end_cap_mesh_free;
int *vgroup_start_cap_remap = NULL;
int vgroup_start_cap_remap_len = 0;
int *vgroup_end_cap_remap = NULL;
int vgroup_end_cap_remap_len = 0;
- chunk_nverts = dm->getNumVerts(dm);
- chunk_nedges = dm->getNumEdges(dm);
- chunk_nloops = dm->getNumLoops(dm);
- chunk_npolys = dm->getNumPolys(dm);
+ chunk_nverts = mesh->totvert;
+ chunk_nedges = mesh->totedge;
+ chunk_nloops = mesh->totloop;
+ chunk_npolys = mesh->totpoly;
count = amd->count;
- if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) {
- vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(amd->start_cap, ob, &vgroup_start_cap_remap_len);
+ if (amd->start_cap && amd->start_cap != ctx->object && amd->start_cap->type == OB_MESH) {
+ vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(
+ amd->start_cap, ctx->object, &vgroup_start_cap_remap_len);
- start_cap_dm = get_dm_for_modifier(amd->start_cap, flag);
- if (start_cap_dm) {
- start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm);
- start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm);
- start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm);
- start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm);
+ start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(amd->start_cap, &start_cap_mesh_free);
+ if (start_cap_mesh) {
+ start_cap_nverts = start_cap_mesh->totvert;
+ start_cap_nedges = start_cap_mesh->totedge;
+ start_cap_nloops = start_cap_mesh->totloop;
+ start_cap_npolys = start_cap_mesh->totpoly;
}
}
- if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) {
- vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(amd->end_cap, ob, &vgroup_end_cap_remap_len);
+ if (amd->end_cap && amd->end_cap != ctx->object && amd->end_cap->type == OB_MESH) {
+ vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(
+ amd->end_cap, ctx->object, &vgroup_end_cap_remap_len);
- end_cap_dm = get_dm_for_modifier(amd->end_cap, flag);
- if (end_cap_dm) {
- end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm);
- end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm);
- end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm);
- end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm);
+ end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(amd->end_cap, &end_cap_mesh_free);
+ if (end_cap_mesh) {
+ end_cap_nverts = end_cap_mesh->totvert;
+ end_cap_nedges = end_cap_mesh->totedge;
+ end_cap_nloops = end_cap_mesh->totloop;
+ end_cap_npolys = end_cap_mesh->totpoly;
}
}
/* Build up offset array, cumulating all settings options */
unit_m4(offset);
- src_mvert = dm->getVertArray(dm);
+ src_mvert = mesh->mvert;
if (amd->offset_type & MOD_ARR_OFF_CONST) {
add_v3_v3(offset[3], amd->offset);
@@ -480,8 +439,8 @@ static DerivedMesh *arrayModifier_doArray(
float obinv[4][4];
float result_mat[4][4];
- if (ob)
- invert_m4_m4(obinv, ob->obmat);
+ if (ctx->object)
+ invert_m4_m4(obinv, ctx->object->obmat);
else
unit_m4(obinv);
@@ -497,15 +456,10 @@ static DerivedMesh *arrayModifier_doArray(
if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
Curve *cu = amd->curve_ob->data;
if (cu) {
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (amd->curve_ob->curve_cache == NULL) {
- BKE_displist_make_curveTypes(scene, amd->curve_ob, false);
- }
-#endif
-
- if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) {
+ CurveCache *curve_cache = amd->curve_ob->runtime.curve_cache;
+ if (curve_cache != NULL && curve_cache->path != NULL) {
float scale_fac = mat4_to_scale(amd->curve_ob->obmat);
- length = scale_fac * amd->curve_ob->curve_cache->path->totdist;
+ length = scale_fac * curve_cache->path->totdist;
}
}
}
@@ -536,8 +490,8 @@ static DerivedMesh *arrayModifier_doArray(
result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys;
/* Initialize a result dm */
- result = CDDM_from_template(dm, result_nverts, result_nedges, 0, result_nloops, result_npolys);
- result_dm_verts = CDDM_get_verts(result);
+ result = BKE_mesh_new_nomain_from_template(mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
+ result_dm_verts = result->mvert;
if (use_merge) {
/* Will need full_doubles_map for handling merge */
@@ -546,23 +500,22 @@ static DerivedMesh *arrayModifier_doArray(
}
/* copy customdata to original geometry */
- DM_copy_vert_data(dm, result, 0, 0, chunk_nverts);
- DM_copy_edge_data(dm, result, 0, 0, chunk_nedges);
- DM_copy_loop_data(dm, result, 0, 0, chunk_nloops);
- DM_copy_poly_data(dm, result, 0, 0, chunk_npolys);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, chunk_nverts);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, chunk_nedges);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, chunk_nloops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, chunk_npolys);
/* Subsurf for eg won't have mesh data in the custom data arrays.
* now add mvert/medge/mpoly layers. */
-
- if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) {
- dm->copyVertArray(dm, result_dm_verts);
+ if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
+ memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
}
- if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) {
- dm->copyEdgeArray(dm, CDDM_get_edges(result));
+ if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
+ memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
}
- if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) {
- dm->copyLoopArray(dm, CDDM_get_loops(result));
- dm->copyPolyArray(dm, CDDM_get_polys(result));
+ if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
+ memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
+ memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
}
/* Remember first chunk, in case of cap merge */
@@ -572,10 +525,10 @@ static DerivedMesh *arrayModifier_doArray(
unit_m4(current_offset);
for (c = 1; c < count; c++) {
/* copy customdata to new geometry */
- DM_copy_vert_data(result, result, 0, c * chunk_nverts, chunk_nverts);
- DM_copy_edge_data(result, result, 0, c * chunk_nedges, chunk_nedges);
- DM_copy_loop_data(result, result, 0, c * chunk_nloops, chunk_nloops);
- DM_copy_poly_data(result, result, 0, c * chunk_npolys, chunk_npolys);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, c * chunk_nedges, chunk_nedges);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys);
mv_prev = result_dm_verts;
mv = mv_prev + c * chunk_nverts;
@@ -598,19 +551,19 @@ static DerivedMesh *arrayModifier_doArray(
}
/* adjust edge vertex indices */
- me = CDDM_get_edges(result) + c * chunk_nedges;
+ me = result->medge + c * chunk_nedges;
for (i = 0; i < chunk_nedges; i++, me++) {
me->v1 += c * chunk_nverts;
me->v2 += c * chunk_nverts;
}
- mp = CDDM_get_polys(result) + c * chunk_npolys;
+ mp = result->mpoly + c * chunk_npolys;
for (i = 0; i < chunk_npolys; i++, mp++) {
mp->loopstart += c * chunk_nloops;
}
/* adjust loop vertex and edge indices */
- ml = CDDM_get_loops(result) + c * chunk_nloops;
+ ml = result->mloop + c * chunk_nloops;
for (i = 0; i < chunk_nloops; i++, ml++) {
ml->v += c * chunk_nverts;
ml->e += c * chunk_nedges;
@@ -660,9 +613,9 @@ static DerivedMesh *arrayModifier_doArray(
/* handle UVs */
if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) {
- const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
+ const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
for (i = 0; i < totuv; i++) {
- MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, i);
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, i);
dmloopuv += chunk_nloops;
for (c = 1; c < count; c++) {
const float uv_offset[2] = {
@@ -696,12 +649,12 @@ static DerivedMesh *arrayModifier_doArray(
}
/* start capping */
- if (start_cap_dm) {
+ if (start_cap_mesh) {
float start_offset[4][4];
int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts;
invert_m4_m4(start_offset, offset);
- dm_merge_transform(
- result, start_cap_dm, start_offset,
+ mesh_merge_transform(
+ result, start_cap_mesh, start_offset,
result_nverts - start_cap_nverts - end_cap_nverts,
result_nedges - start_cap_nedges - end_cap_nedges,
result_nloops - start_cap_nloops - end_cap_nloops,
@@ -721,12 +674,12 @@ static DerivedMesh *arrayModifier_doArray(
}
}
- if (end_cap_dm) {
+ if (end_cap_mesh) {
float end_offset[4][4];
int end_cap_start = result_nverts - end_cap_nverts;
mul_m4_m4m4(end_offset, current_offset, offset);
- dm_merge_transform(
- result, end_cap_dm, end_offset,
+ mesh_merge_transform(
+ result, end_cap_mesh, end_offset,
result_nverts - end_cap_nverts,
result_nedges - end_cap_nedges,
result_nloops - end_cap_nloops,
@@ -754,7 +707,7 @@ static DerivedMesh *arrayModifier_doArray(
int new_i = full_doubles_map[i];
if (new_i != -1) {
/* We have to follow chains of doubles (merge start/end especially is likely to create some),
- * those are not supported at all by CDDM_merge_verts! */
+ * those are not supported at all by BKE_mesh_merge_verts! */
while (!ELEM(full_doubles_map[new_i], -1, new_i)) {
new_i = full_doubles_map[new_i];
}
@@ -768,16 +721,16 @@ static DerivedMesh *arrayModifier_doArray(
}
}
if (tot_doubles > 0) {
- result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL);
+ result = BKE_mesh_merge_verts(result, full_doubles_map, tot_doubles, MESH_MERGE_VERTS_DUMP_IF_EQUAL);
}
MEM_freeN(full_doubles_map);
}
- /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new dm!
+ /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new mesh!
* TODO: we may need to set other dirty flags as well?
*/
if (use_recalc_normals) {
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
if (vgroup_start_cap_remap) {
@@ -786,18 +739,23 @@ static DerivedMesh *arrayModifier_doArray(
if (vgroup_end_cap_remap) {
MEM_freeN(vgroup_end_cap_remap);
}
+ if (start_cap_mesh != NULL && start_cap_mesh_free) {
+ BKE_id_free(NULL, start_cap_mesh);
+ }
+ if (end_cap_mesh != NULL && end_cap_mesh_free) {
+ BKE_id_free(NULL, end_cap_mesh);
+ }
return result;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag flag)
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
ArrayModifierData *amd = (ArrayModifierData *) md;
- return arrayModifier_doArray(amd, md->scene, ob, dm, flag);
+ return arrayModifier_doArray(amd, ctx, mesh);
}
@@ -813,17 +771,23 @@ ModifierTypeInfo modifierType_Array = {
eModifierTypeFlag_AcceptsCVs,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index c70870d5671..d9b6cfa1ac5 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -32,14 +32,20 @@
* \ingroup modifiers
*/
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
+#include "BLI_linklist_stack.h"
#include "BLI_math.h"
#include "BLI_string.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "MOD_util.h"
@@ -47,6 +53,8 @@
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "DEG_depsgraph_query.h"
+
static void initData(ModifierData *md)
{
BevelModifierData *bmd = (BevelModifierData *) md;
@@ -57,10 +65,23 @@ static void initData(ModifierData *md)
bmd->val_flags = MOD_BEVEL_AMT_OFFSET;
bmd->lim_flags = 0;
bmd->e_flags = 0;
+ bmd->edge_flags = 0;
bmd->mat = -1;
bmd->profile = 0.5f;
bmd->bevel_angle = DEG2RADF(30.0f);
bmd->defgrp_name[0] = '\0';
+ bmd->hnmode = MOD_BEVEL_HN_NONE;
+ bmd->hn_strength = 0.5f;
+ bmd->clnordata.faceHash = NULL;
+}
+
+static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int UNUSED(flag))
+{
+ BevelModifierData *bmd_src = (BevelModifierData *)md_src;
+ BevelModifierData *bmd_dst = (BevelModifierData *)md_dst;
+
+ *bmd_dst = *bmd_src;
+ bmd_dst->clnordata.faceHash = NULL;
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -74,15 +95,260 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
+static void bevel_set_weighted_normal_face_strength(BMesh *bm, Scene *scene)
+{
+ BMFace *f;
+ BMIter fiter;
+ const char *wn_layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
+ int cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
+
+ if (cd_prop_int_idx == -1) {
+ BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, wn_layer_id);
+ cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
+ }
+ cd_prop_int_idx -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
+ const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_idx);
+
+ const int face_strength = scene->toolsettings->face_strength;
+
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ *strength = face_strength;
+ }
+ }
+}
+
+static void bevel_mod_harden_normals(
+ BevelModifierData *bmd, BMesh *bm, const float hn_strength,
+ const int hnmode, MDeformVert *dvert, int vgroup)
+{
+ if (bmd->res > 20 || bmd->value == 0)
+ return;
+
+ BM_mesh_normals_update(bm);
+ BM_lnorspace_update(bm);
+ BM_normals_loops_edges_tag(bm, true);
+
+ const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ const bool do_normal_to_recon = (hn_strength == 1.0f);
+
+ BMFace *f;
+ BMLoop *l, *l_cur, *l_first;
+ BMIter fiter;
+ GHash *faceHash = bmd->clnordata.faceHash;
+
+ /* Iterate throught all loops of a face */
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+
+ l_cur = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG)) ||
+ (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur)))
+ {
+
+ /* previous and next edge is sharp, accumulate face normals into loop */
+ if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) {
+ const int loop_index = BM_elem_index_get(l_cur);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
+ }
+ else {
+ BMVert *v_pivot = l_cur->v;
+ BMEdge *e_next;
+ const BMEdge *e_org = l_cur->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+ UNUSED_VARS_NDEBUG(v_pivot);
+
+ lfan_pivot = l_cur;
+ e_next = lfan_pivot->e;
+ BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
+ float cn_wght[3] = { 0.0f, 0.0f, 0.0f };
+ int recon_face_count = 0; /* Counts number of reconstructed faces current vert is connected to */
+ BMFace *recon_face = NULL; /* Reconstructed face */
+
+ while (true) {
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
+
+ BLI_SMALLSTACK_PUSH(loops, lfan_pivot);
+
+ if (bmd->lim_flags & MOD_BEVEL_WEIGHT) {
+ int weight = BM_elem_float_data_get(&bm->edata, lfan_pivot->f, CD_BWEIGHT);
+ if (weight) {
+ if (hnmode == MOD_BEVEL_HN_FACE) {
+ float cur[3]; //Add area weighted face normals
+ mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
+ add_v3_v3(cn_wght, cur);
+ }
+ else
+ add_v3_v3(cn_wght, lfan_pivot->f->no); //Else simply add face normals
+ }
+ else
+ add_v3_v3(cn_wght, lfan_pivot->f->no);
+
+ }
+ else if (bmd->lim_flags & MOD_BEVEL_VGROUP) {
+ const bool has_vgroup = dvert != NULL;
+ const bool vert_of_group = (
+ has_vgroup &&
+ (defvert_find_index(&dvert[BM_elem_index_get(lfan_pivot->v)], vgroup) != NULL));
+
+ if (vert_of_group && hnmode == MOD_BEVEL_HN_FACE) {
+ float cur[3];
+ mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
+ add_v3_v3(cn_wght, cur);
+ }
+ else
+ add_v3_v3(cn_wght, lfan_pivot->f->no);
+ }
+ else {
+ float cur[3];
+ mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
+ add_v3_v3(cn_wght, cur);
+ }
+ if (!BLI_ghash_haskey(faceHash, lfan_pivot->f)) {
+ recon_face = f;
+ recon_face_count++;
+ }
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ break;
+ }
+ lfan_pivot = lfan_pivot_next;
+ }
+
+ normalize_v3(cn_wght);
+ mul_v3_fl(cn_wght, hn_strength);
+ float n_final[3];
+
+ while ((l = BLI_SMALLSTACK_POP(loops))) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+
+ /* If vertex is edge vert with 1 reconnected face */
+ if (recon_face_count == 1 || (recon_face != NULL && do_normal_to_recon)) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], recon_face->no, clnors);
+ }
+ else if (vertex_only == false || recon_face_count == 0) {
+ copy_v3_v3(n_final, l->f->no);
+ mul_v3_fl(n_final, 1.0f - hn_strength);
+ add_v3_v3(n_final, cn_wght);
+ normalize_v3(n_final);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
+ }
+ else if (BLI_ghash_haskey(faceHash, l->f)) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], l->v->no, clnors);
+ }
+ }
+ }
+ }
+ } while ((l_cur = l_cur->next) != l_first);
+ }
+}
+
+static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *bm)
+{
+ const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
+ if (bmd->value == 0 || (bmd->clnordata.faceHash == NULL && vertex_only))
+ return;
+
+ BM_mesh_normals_update(bm);
+ BM_lnorspace_update(bm);
+
+ GHash *faceHash = bmd->clnordata.faceHash;
+ BMEdge *e;
+ BMLoop *l;
+ BMIter liter, eiter;
+
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ const float hn_strength = bmd->hn_strength;
+ float ref = 10.0f;
+
+ BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) {
+ BMFace *f_a, *f_b;
+ BM_edge_face_pair(e, &f_a, &f_b);
+
+ bool has_f_a = false, has_f_b = false;
+ if (f_a)
+ has_f_a = BLI_ghash_haskey(faceHash, f_a);
+ if (f_b)
+ has_f_b = BLI_ghash_haskey(faceHash, f_b);
+ if (has_f_a ^ has_f_b) {
+ /* If one of both faces is present in faceHash then we are at a border
+ * between new vmesh created and reconstructed face */
+
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = (i == 0) ? e->v1 : e->v2;
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+
+ if (l->f == f_a || l->f == f_b) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ float n_final[3], pow_a[3], pow_b[3];
+
+ zero_v3(n_final);
+ copy_v3_v3(pow_a, f_a->no);
+ copy_v3_v3(pow_b, f_b->no);
+ if (has_f_a) {
+ mul_v3_fl(pow_a, bmd->res / ref);
+ mul_v3_fl(pow_b, ref / bmd->res);
+ }
+ else {
+ mul_v3_fl(pow_b, bmd->res / ref);
+ mul_v3_fl(pow_a, ref / bmd->res);
+ }
+ add_v3_v3(n_final, pow_a);
+ add_v3_v3(n_final, pow_b);
+ normalize_v3(n_final);
+
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
+ }
+ }
+ }
+ }
+ else if (has_f_a == true && has_f_b == true) {
+ /* Else if both faces are present we assign clnor corresponding
+ * to vert normal and face normal */
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = (i == 0) ? e->v1 : e->v2;
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+
+ if (l->f == f_a || l->f == f_b) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ float n_final[3], cn_wght[3];
+
+ copy_v3_v3(n_final, v->no);
+ mul_v3_fl(n_final, hn_strength);
+
+ copy_v3_v3(cn_wght, l->f->no);
+ mul_v3_fl(cn_wght, 1.0f - hn_strength);
+
+ add_v3_v3(n_final, cn_wght);
+ normalize_v3(n_final);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
+ }
+ }
+ }
+ }
+ }
+}
+
/*
* This calls the new bevel code (added since 2.64)
*/
-static DerivedMesh *applyModifier(
- ModifierData *md, struct Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
- DerivedMesh *result;
+ Mesh *result;
BMesh *bm;
BMIter iter;
BMEdge *e;
@@ -95,12 +361,27 @@ static DerivedMesh *applyModifier(
const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK);
const int offset_type = bmd->val_flags;
- const int mat = CLAMPIS(bmd->mat, -1, ob->totcol - 1);
+ const int mat = CLAMPIS(bmd->mat, -1, ctx->object->totcol - 1);
const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0;
+ const bool mark_seam = (bmd->edge_flags & MOD_BEVEL_MARK_SEAM);
+ const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP);
+ const bool set_wn_strength = (bmd->flags & MOD_BEVEL_SET_WN_STR);
+
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+
+ bm = BKE_mesh_to_bmesh_ex(
+ mesh,
+ &(struct BMeshCreateParams){0},
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .add_key_index = false,
+ .use_shapekey = true,
+ .active_shapekey = ctx->object->shapenr,
+ .cd_mask_extra = CD_MASK_ORIGINDEX,
+ });
- bm = DM_to_bmesh(dm, true);
if ((bmd->lim_flags & MOD_BEVEL_VGROUP) && bmd->defgrp_name[0])
- modifier_get_vgroup(ob, dm, bmd->defgrp_name, &dvert, &vgroup);
+ MOD_get_vgroup(ctx->object, mesh, bmd->defgrp_name, &dvert, &vgroup);
if (vertex_only) {
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -158,16 +439,27 @@ static DerivedMesh *applyModifier(
BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile,
vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp,
- dvert, vgroup, mat, loop_slide);
+ dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, &bmd->clnordata);
+
+ if (bmd->hnmode != BEVEL_HN_FIX_SHA && bmd->hnmode != MOD_BEVEL_HN_NONE) {
+ bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup);
+ }
+ if (bmd->hnmode == BEVEL_HN_FIX_SHA)
+ bevel_fix_normal_shading_continuity(bmd, bm);
+ if (set_wn_strength)
+ bevel_set_weighted_normal_face_strength(bm, scene);
- result = CDDM_from_bmesh(bm, true);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
BLI_assert(bm->vtoolflagpool == NULL &&
bm->etoolflagpool == NULL &&
bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */
BM_mesh_free(bm);
- result->dirty |= DM_DIRTY_NORMALS;
+ if (bmd->clnordata.faceHash)
+ BLI_ghash_free(bmd->clnordata.faceHash, NULL, NULL);
+
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
@@ -184,20 +476,27 @@ ModifierTypeInfo modifierType_Bevel = {
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_SupportsEditmode |
- eModifierTypeFlag_EnableInEditmode,
+ eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs,
+
+ /* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
- /* copyData */ modifier_copyData_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index edbfd0408b5..7c09f86b4ca 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -41,19 +41,24 @@
#include "BLI_utildefines.h"
#include "BLI_math_matrix.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
-
#include "BLI_alloca.h"
#include "BLI_math_geom.h"
-#include "BKE_material.h"
+
#include "BKE_global.h" /* only to check G.debug */
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "DEG_depsgraph_query.h"
+
#include "MEM_guardedalloc.h"
#include "bmesh.h"
@@ -72,7 +77,7 @@ static void initData(ModifierData *md)
bmd->double_threshold = 1e-6f;
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
BooleanModifierData *bmd = (BooleanModifierData *) md;
@@ -88,18 +93,6 @@ static void foreachObjectLink(
walk(userData, ob, &bmd->object, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- BooleanModifierData *bmd = (BooleanModifierData *) md;
-
- if (bmd->object) {
- DagNode *curNode = dag_get_node(ctx->forest, bmd->object);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Boolean Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
@@ -111,25 +104,30 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
}
-static DerivedMesh *get_quick_derivedMesh(
- Object *ob_self, DerivedMesh *dm_self,
- Object *ob_other, DerivedMesh *dm_other,
+static Mesh *get_quick_mesh(
+ Object *ob_self, Mesh *mesh_self,
+ Object *ob_other, Mesh *mesh_other,
int operation)
{
- DerivedMesh *result = NULL;
+ Mesh *result = NULL;
- if (dm_self->getNumPolys(dm_self) == 0 || dm_other->getNumPolys(dm_other) == 0) {
+ if (mesh_self->totpoly == 0 || mesh_other->totpoly == 0) {
switch (operation) {
case eBooleanModifierOp_Intersect:
- result = CDDM_new(0, 0, 0, 0, 0);
+ result = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
break;
case eBooleanModifierOp_Union:
- if (dm_self->getNumPolys(dm_self) != 0) {
- result = dm_self;
+ if (mesh_self->totpoly != 0) {
+ result = mesh_self;
}
else {
- result = CDDM_copy(dm_other);
+ BKE_id_copy_ex(NULL, &mesh_other->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
float imat[4][4];
float omat[4][4];
@@ -137,20 +135,20 @@ static DerivedMesh *get_quick_derivedMesh(
invert_m4_m4(imat, ob_self->obmat);
mul_m4_m4m4(omat, imat, ob_other->obmat);
- const int mverts_len = result->getNumVerts(result);
- MVert *mv = CDDM_get_verts(result);
+ const int mverts_len = result->totvert;
+ MVert *mv = result->mvert;
for (int i = 0; i < mverts_len; i++, mv++) {
mul_m4_v3(omat, mv->co);
}
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
break;
case eBooleanModifierOp_Difference:
- result = dm_self;
+ result = mesh_self;
break;
}
}
@@ -170,32 +168,34 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag flag)
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BooleanModifierData *bmd = (BooleanModifierData *) md;
- DerivedMesh *dm_other;
+ Mesh *result = mesh;
- if (!bmd->object)
- return dm;
+ Mesh *mesh_other;
+ bool mesh_other_free;
- dm_other = get_dm_for_modifier(bmd->object, flag);
+ if (!bmd->object) {
+ return result;
+ }
- if (dm_other) {
- DerivedMesh *result;
+ Object *ob_eval = DEG_get_evaluated_object(ctx->depsgraph, bmd->object);
+ mesh_other = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_eval, &mesh_other_free);
+ if (mesh_other) {
+ Object *object = ctx->object;
+ Object *other = bmd->object;
/* when one of objects is empty (has got no faces) we could speed up
* calculation a bit returning one of objects' derived meshes (or empty one)
* Returning mesh is depended on modifiers operation (sergey) */
- result = get_quick_derivedMesh(ob, dm, bmd->object, dm_other, bmd->operation);
+ result = get_quick_mesh(object, mesh, other, mesh_other, bmd->operation);
if (result == NULL) {
- const bool is_flip = (is_negative_m4(ob->obmat) != is_negative_m4(bmd->object->obmat));
+ const bool is_flip = (is_negative_m4(object->obmat) != is_negative_m4(other->obmat));
BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm, dm_other);
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_other);
#ifdef DEBUG_TIME
TIMEIT_START(boolean_bmesh);
@@ -204,7 +204,7 @@ static DerivedMesh *applyModifier(
&allocsize,
&((struct BMeshCreateParams){.use_toolflags = false,}));
- DM_to_bmesh_ex(dm_other, bm, true);
+ BM_mesh_bm_from_me(bm, mesh_other, &((struct BMeshFromMeshParams){.calc_face_normal = true,}));
if (UNLIKELY(is_flip)) {
const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
@@ -215,7 +215,7 @@ static DerivedMesh *applyModifier(
}
}
- DM_to_bmesh_ex(dm, bm, true);
+ BM_mesh_bm_from_me(bm, mesh, &((struct BMeshFromMeshParams){.calc_face_normal = true,}));
/* main bmesh intersection setup */
{
@@ -233,14 +233,14 @@ static DerivedMesh *applyModifier(
{
BMIter iter;
int i;
- const int i_verts_end = dm_other->getNumVerts(dm_other);
- const int i_faces_end = dm_other->getNumPolys(dm_other);
+ const int i_verts_end = mesh_other->totvert;
+ const int i_faces_end = mesh_other->totpoly;
float imat[4][4];
float omat[4][4];
- invert_m4_m4(imat, ob->obmat);
- mul_m4_m4m4(omat, imat, bmd->object->obmat);
+ invert_m4_m4(imat, object->obmat);
+ mul_m4_m4m4(omat, imat, other->obmat);
BMVert *eve;
i = 0;
@@ -262,10 +262,11 @@ static DerivedMesh *applyModifier(
negate_m3(nmat);
}
- const short ob_src_totcol = bmd->object->totcol;
+ const short ob_src_totcol = other->totcol;
short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1);
- BKE_material_remap_object_calc(ob, bmd->object, material_remap);
+ /* Using original (not evaluated) object here since we are writing to it. */
+ BKE_material_remap_object_calc(ctx->object, other, material_remap);
BMFace *efa;
i = 0;
@@ -317,28 +318,28 @@ static DerivedMesh *applyModifier(
MEM_freeN(looptris);
}
- result = CDDM_from_bmesh(bm, true);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
BM_mesh_free(bm);
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
#ifdef DEBUG_TIME
TIMEIT_END(boolean_bmesh);
#endif
-
- return result;
}
/* if new mesh returned, return it; otherwise there was
* an error, so delete the modifier object */
- if (result)
- return result;
- else
+ if (result == NULL)
modifier_setError(md, "Cannot execute boolean operation");
}
- return dm;
+ if (mesh_other != NULL && mesh_other_free) {
+ BKE_id_free(NULL, mesh_other);
+ }
+
+ return result;
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
@@ -359,17 +360,23 @@ ModifierTypeInfo modifierType_Boolean = {
eModifierTypeFlag_UsesPointCache,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 34b432fe805..e2c13d02827 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -41,18 +41,16 @@
#include "BLI_ghash.h"
#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
-#include "BKE_cdderivedmesh.h"
+#include "DEG_depsgraph_query.h"
+
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
-
-
-#ifdef _OPENMP
-# include "BKE_mesh.h" /* BKE_MESH_OMP_LIMIT */
-#endif
-
static void initData(ModifierData *md)
{
BuildModifierData *bmd = (BuildModifierData *) md;
@@ -66,13 +64,11 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *UNUSED(ob),
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *mesh)
{
- DerivedMesh *dm = derivedData;
- DerivedMesh *result;
+ Mesh *result;
BuildModifierData *bmd = (BuildModifierData *) md;
int i, j, k;
int numFaces_dst, numEdges_dst, numLoops_dst = 0;
@@ -85,16 +81,16 @@ static DerivedMesh *applyModifier(
GHash *vertHash = BLI_ghash_int_new("build ve apply gh");
/* maps edge indices in new mesh to indices in old mesh */
GHash *edgeHash = BLI_ghash_int_new("build ed apply gh");
+ /* maps edge indices in old mesh to indices in new mesh */
GHash *edgeHash2 = BLI_ghash_int_new("build ed apply gh");
- const int numVert_src = dm->getNumVerts(dm);
- const int numEdge_src = dm->getNumEdges(dm);
- const int numPoly_src = dm->getNumPolys(dm);
- MPoly *mpoly_src = dm->getPolyArray(dm);
- MLoop *mloop_src = dm->getLoopArray(dm);
- MEdge *medge_src = dm->getEdgeArray(dm);
- MVert *mvert_src = dm->getVertArray(dm);
-
+ const int numVert_src = mesh->totvert;
+ const int numEdge_src = mesh->totedge;
+ const int numPoly_src = mesh->totpoly;
+ MPoly *mpoly_src = mesh->mpoly;
+ MLoop *mloop_src = mesh->mloop;
+ MEdge *medge_src = mesh->medge;
+ MVert *mvert_src = mesh->mvert;
vertMap = MEM_malloc_arrayN(numVert_src, sizeof(*vertMap), "build modifier vertMap");
edgeMap = MEM_malloc_arrayN(numEdge_src, sizeof(*edgeMap), "build modifier edgeMap");
@@ -104,9 +100,9 @@ static DerivedMesh *applyModifier(
range_vn_i(edgeMap, numEdge_src, 0);
range_vn_i(faceMap, numPoly_src, 0);
- frac = (BKE_scene_frame_get(md->scene) - bmd->start) / bmd->length;
+ struct Scene *scene = DEG_get_input_scene(ctx->depsgraph);
+ frac = (BKE_scene_frame_get(scene) - bmd->start) / bmd->length;
CLAMP(frac, 0.0f, 1.0f);
-
if (bmd->flag & MOD_BUILD_FLAG_REVERSE) {
frac = 1.0f - frac;
}
@@ -118,7 +114,6 @@ static DerivedMesh *applyModifier(
if (numFaces_dst) {
MPoly *mpoly, *mp;
MLoop *ml, *mloop;
- MEdge *medge;
uintptr_t hash_num, hash_num_alt;
if (bmd->flag & MOD_BUILD_FLAG_RANDOMIZE) {
@@ -151,11 +146,10 @@ static DerivedMesh *applyModifier(
/* get the set of edges that will be in the new mesh (i.e. all edges
* that have both verts in the new mesh)
*/
- medge = medge_src;
hash_num = 0;
hash_num_alt = 0;
for (i = 0; i < numEdge_src; i++, hash_num_alt++) {
- MEdge *me = medge + i;
+ MEdge *me = medge_src + i;
if (BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v1)) &&
BLI_ghash_haskey(vertHash, POINTER_FROM_INT(me->v2)))
@@ -165,6 +159,7 @@ static DerivedMesh *applyModifier(
hash_num++;
}
}
+ BLI_assert(hash_num == BLI_ghash_len(edgeHash));
}
else if (numEdges_dst) {
MEdge *medge, *me;
@@ -221,11 +216,10 @@ static DerivedMesh *applyModifier(
}
}
- /* now we know the number of verts, edges and faces, we can create
- * the mesh
- */
- result = CDDM_from_template(dm, BLI_ghash_len(vertHash),
- BLI_ghash_len(edgeHash), 0, numLoops_dst, numFaces_dst);
+ /* now we know the number of verts, edges and faces, we can create the mesh. */
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, BLI_ghash_len(vertHash), BLI_ghash_len(edgeHash),
+ 0, numLoops_dst, numFaces_dst);
/* copy the vertices across */
GHASH_ITER (gh_iter, vertHash) {
@@ -235,9 +229,9 @@ static DerivedMesh *applyModifier(
int newIndex = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter));
source = mvert_src[oldIndex];
- dest = CDDM_get_vert(result, newIndex);
+ dest = &result->mvert[newIndex];
- DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, oldIndex, newIndex, 1);
*dest = source;
}
@@ -248,17 +242,17 @@ static DerivedMesh *applyModifier(
int oldIndex = POINTER_AS_INT(BLI_ghash_lookup(edgeHash, POINTER_FROM_INT(i)));
source = medge_src[oldIndex];
- dest = CDDM_get_edge(result, i);
+ dest = &result->medge[i];
source.v1 = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(source.v1)));
source.v2 = POINTER_AS_INT(BLI_ghash_lookup(vertHash, POINTER_FROM_INT(source.v2)));
- DM_copy_edge_data(dm, result, oldIndex, i, 1);
+ CustomData_copy_data(&mesh->edata, &result->edata, oldIndex, i, 1);
*dest = source;
}
- mpoly_dst = CDDM_get_polys(result);
- /* mloop_dst = */ ml_dst = CDDM_get_loops(result);
+ mpoly_dst = result->mpoly;
+ ml_dst = result->mloop;
/* copy the faces across, remapping indices */
k = 0;
@@ -268,12 +262,11 @@ static DerivedMesh *applyModifier(
source = mpoly_src + faceMap[i];
dest = mpoly_dst + i;
- DM_copy_poly_data(dm, result, faceMap[i], i, 1);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, faceMap[i], i, 1);
*dest = *source;
dest->loopstart = k;
-
- DM_copy_loop_data(dm, result, source->loopstart, dest->loopstart, dest->totloop);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, source->loopstart, dest->loopstart, dest->totloop);
ml_src = mloop_src + source->loopstart;
for (j = 0; j < source->totloop; j++, k++, ml_src++, ml_dst++) {
@@ -290,10 +283,11 @@ static DerivedMesh *applyModifier(
MEM_freeN(edgeMap);
MEM_freeN(faceMap);
- if (dm->dirty & DM_DIRTY_NORMALS) {
- result->dirty |= DM_DIRTY_NORMALS;
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
+ /* TODO(sybren): also copy flags & tags? */
return result;
}
@@ -305,18 +299,25 @@ ModifierTypeInfo modifierType_Build = {
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_AcceptsCVs,
+
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index f09f2d619a2..e79cceb118c 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -33,6 +33,7 @@
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -41,13 +42,12 @@
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
-
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
static void initData(ModifierData *md)
@@ -63,7 +63,7 @@ static void initData(ModifierData *md)
cmd->object = NULL;
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
CastModifierData *cmd = (CastModifierData *) md;
short flag;
@@ -95,18 +95,6 @@ static void foreachObjectLink(
walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- CastModifierData *cmd = (CastModifierData *) md;
-
- if (cmd->object) {
- DagNode *curNode = dag_get_node(ctx->forest, cmd->object);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_OB_DATA,
- "Cast Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
CastModifierData *cmd = (CastModifierData *)md;
@@ -117,7 +105,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
static void sphere_do(
- CastModifierData *cmd, Object *ob, DerivedMesh *dm,
+ CastModifierData *cmd, Object *ob, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
MDeformVert *dvert = NULL;
@@ -165,7 +153,7 @@ static void sphere_do(
/* 3) if we were given a vertex group name,
* only those vertices should be affected */
- modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, cmd->defgrp_name, &dvert, &defgrp_index);
if (flag & MOD_CAST_SIZE_FROM_RADIUS) {
len = cmd->radius;
@@ -238,7 +226,7 @@ static void sphere_do(
}
static void cuboid_do(
- CastModifierData *cmd, Object *ob, DerivedMesh *dm,
+ CastModifierData *cmd, Object *ob, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
MDeformVert *dvert = NULL;
@@ -267,7 +255,7 @@ static void cuboid_do(
/* 3) if we were given a vertex group name,
* only those vertices should be affected */
- modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, cmd->defgrp_name, &dvert, &defgrp_index);
if (ctrl_ob) {
if (flag & MOD_CAST_USE_OB_TRANSFORM) {
@@ -435,44 +423,51 @@ static void cuboid_do(
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
- DerivedMesh *dm = NULL;
CastModifierData *cmd = (CastModifierData *)md;
+ Mesh *mesh_src = NULL;
- dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+ if (ctx->object->type == OB_MESH && cmd->defgrp_name[0] != '\0') {
+ /* mesh_src is only needed for vgroups. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
+ }
if (cmd->type == MOD_CAST_TYPE_CUBOID) {
- cuboid_do(cmd, ob, dm, vertexCos, numVerts);
+ cuboid_do(cmd, ctx->object, mesh_src, vertexCos, numVerts);
}
else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */
- sphere_do(cmd, ob, dm, vertexCos, numVerts);
+ sphere_do(cmd, ctx->object, mesh_src, vertexCos, numVerts);
}
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, false, false);
CastModifierData *cmd = (CastModifierData *)md;
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
+
+ BLI_assert(mesh_src->totvert == numVerts);
if (cmd->type == MOD_CAST_TYPE_CUBOID) {
- cuboid_do(cmd, ob, dm, vertexCos, numVerts);
+ cuboid_do(cmd, ctx->object, mesh_src, vertexCos, numVerts);
}
else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */
- sphere_do(cmd, ob, dm, vertexCos, numVerts);
+ sphere_do(cmd, ctx->object, mesh_src, vertexCos, numVerts);
}
- if (dm != derivedData)
- dm->release(dm);
+ if (mesh_src != mesh) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -486,17 +481,23 @@ ModifierTypeInfo modifierType_Cast = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index ef41c5a270c..636c465d304 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -36,24 +36,27 @@
#include "DNA_cloth_types.h"
#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-
#include "BKE_cloth.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_key.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "MOD_util.h"
@@ -73,11 +76,13 @@ static void initData(ModifierData *md)
}
static void deformVerts(
- ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3],
- int numVerts, ModifierApplyFlag UNUSED(flag))
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh, float (*vertexCos)[3],
+ int numVerts)
{
- DerivedMesh *dm;
+ Mesh *mesh_src;
ClothModifierData *clmd = (ClothModifierData *) md;
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
/* check for alloc failing */
if (!clmd->sim_parms || !clmd->coll_parms) {
@@ -87,9 +92,20 @@ static void deformVerts(
return;
}
- dm = get_dm(ob, NULL, derivedData, NULL, false, false);
- if (dm == derivedData)
- dm = CDDM_copy(dm);
+ if (mesh == NULL) {
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, NULL, numVerts, false, false);
+ }
+ else {
+ /* Not possible to use get_mesh() in this case as we'll modify its vertices
+ * and get_mesh() would return 'mesh' directly. */
+ BKE_id_copy_ex(
+ NULL, (ID *)mesh, (ID **)&mesh_src,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ }
/* TODO(sergey): For now it actually duplicates logic from DerivedMesh.c
* and needs some more generic solution. But starting experimenting with
@@ -97,50 +113,32 @@ static void deformVerts(
*
* Also hopefully new cloth system will arrive soon..
*/
- if (derivedData == NULL && clmd->sim_parms->shapekey_rest) {
- KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob),
+ if (mesh == NULL && clmd->sim_parms->shapekey_rest) {
+ KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ctx->object),
clmd->sim_parms->shapekey_rest);
if (kb && kb->data != NULL) {
float (*layerorco)[3];
- if (!(layerorco = DM_get_vert_data_layer(dm, CD_CLOTH_ORCO))) {
- DM_add_vert_layer(dm, CD_CLOTH_ORCO, CD_CALLOC, NULL);
- layerorco = DM_get_vert_data_layer(dm, CD_CLOTH_ORCO);
+ if (!(layerorco = CustomData_get_layer(&mesh_src->vdata, CD_CLOTH_ORCO))) {
+ layerorco = CustomData_add_layer(&mesh_src->vdata, CD_CLOTH_ORCO, CD_CALLOC, NULL, mesh_src->totvert);
}
memcpy(layerorco, kb->data, sizeof(float) * 3 * numVerts);
}
}
- CDDM_apply_vert_coords(dm, vertexCos);
+ BKE_mesh_apply_vert_coords(mesh_src, vertexCos);
- clothModifier_do(clmd, md->scene, ob, dm, vertexCos);
-
- dm->release(dm);
-}
+ clothModifier_do(clmd, ctx->depsgraph, scene, ctx->object, mesh_src, vertexCos);
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- ClothModifierData *clmd = (ClothModifierData *) md;
-
- if (clmd) {
- /* Actual code uses get_collisionobjects */
-#ifdef WITH_LEGACY_DEPSGRAPH
- dag_add_collision_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, clmd->coll_parms->group, ctx->object->lay | ctx->scene->lay, eModifierType_Collision, NULL, true, "Cloth Collision");
- dag_add_forcefield_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
-#else
- (void)ctx;
-#endif
- }
+ BKE_id_free(NULL, mesh_src);
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ClothModifierData *clmd = (ClothModifierData *)md;
if (clmd != NULL) {
- /* Actual code uses get_collisionobjects */
- DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, clmd->coll_parms->group, ctx->object->lay | ctx->scene->lay, eModifierType_Collision, NULL, true, "Cloth Collision");
-
- DEG_add_forcefield_relations(ctx->node, ctx->scene, ctx->object, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
+ DEG_add_collision_relations(ctx->node, ctx->object, clmd->coll_parms->group, eModifierType_Collision, NULL, "Cloth Collision");
+ DEG_add_forcefield_relations(ctx->node, ctx->object, clmd->sim_parms->effector_weights, true, 0, "Cloth Field");
}
}
@@ -158,7 +156,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const ClothModifierData *clmd = (const ClothModifierData *) md;
ClothModifierData *tclmd = (ClothModifierData *) target;
@@ -173,14 +171,21 @@ static void copyData(const ModifierData *md, ModifierData *target)
MEM_freeN(tclmd->coll_parms);
BKE_ptcache_free_list(&tclmd->ptcaches);
- tclmd->point_cache = NULL;
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* Share the cache with the original object's modifier. */
+ tclmd->modifier.flag |= eModifierFlag_SharedCaches;
+ tclmd->ptcaches = clmd->ptcaches;
+ tclmd->point_cache = clmd->point_cache;
+ }
+ else {
+ tclmd->point_cache = BKE_ptcache_add(&tclmd->ptcaches);
+ tclmd->point_cache->step = 1;
+ }
tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms);
if (clmd->sim_parms->effector_weights)
tclmd->sim_parms->effector_weights = MEM_dupallocN(clmd->sim_parms->effector_weights);
tclmd->coll_parms = MEM_dupallocN(clmd->coll_parms);
- tclmd->point_cache = BKE_ptcache_add(&tclmd->ptcaches);
- tclmd->point_cache->step = 1;
tclmd->clothObject = NULL;
tclmd->hairdata = NULL;
tclmd->solver_result = NULL;
@@ -209,7 +214,12 @@ static void freeData(ModifierData *md)
if (clmd->coll_parms)
MEM_freeN(clmd->coll_parms);
- BKE_ptcache_free_list(&clmd->ptcaches);
+ if (md->flag & eModifierFlag_SharedCaches) {
+ BLI_listbase_clear(&clmd->ptcaches);
+ }
+ else {
+ BKE_ptcache_free_list(&clmd->ptcaches);
+ }
clmd->point_cache = NULL;
if (clmd->hairdata)
@@ -245,17 +255,23 @@ ModifierTypeInfo modifierType_Cloth = {
eModifierTypeFlag_Single,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 4390a5830d8..011635e3012 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -33,6 +33,7 @@
*/
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "MEM_guardedalloc.h"
@@ -41,13 +42,18 @@
#include "BLI_utildefines.h"
#include "BKE_collision.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+
+#include "DEG_depsgraph_query.h"
static void initData(ModifierData *md)
{
@@ -96,150 +102,157 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int UNUSED(numVerts),
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
CollisionModifierData *collmd = (CollisionModifierData *) md;
- DerivedMesh *dm = NULL;
+ Mesh *mesh_src;
MVert *tempVert = NULL;
+ Object *ob = ctx->object;
- /* if possible use/create DerivedMesh */
- if (derivedData) dm = CDDM_copy(derivedData);
- else if (ob->type == OB_MESH) dm = CDDM_from_mesh(ob->data);
+ if (mesh == NULL) {
+ mesh_src = MOD_deform_mesh_eval_get(ob, NULL, NULL, NULL, numVerts, false, false);
+ }
+ else {
+ /* Not possible to use get_mesh() in this case as we'll modify its vertices
+ * and get_mesh() would return 'mesh' directly. */
+ BKE_id_copy_ex(
+ NULL, (ID *)mesh, (ID **)&mesh_src,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ }
if (!ob->pd) {
printf("CollisionModifier deformVerts: Should not happen!\n");
return;
}
- if (dm) {
+ if (mesh_src) {
float current_time = 0;
unsigned int mvert_num = 0;
- CDDM_apply_vert_coords(dm, vertexCos);
- CDDM_calc_normals(dm);
+ BKE_mesh_apply_vert_coords(mesh_src, vertexCos);
+ BKE_mesh_calc_normals(mesh_src);
- current_time = BKE_scene_frame_get(md->scene);
+ current_time = DEG_get_ctime(ctx->depsgraph);
if (G.debug_value > 0)
printf("current_time %f, collmd->time_xnew %f\n", current_time, collmd->time_xnew);
- mvert_num = dm->getNumVerts(dm);
+ mvert_num = mesh_src->totvert;
- if (current_time > collmd->time_xnew) {
- unsigned int i;
-
- /* check if mesh has changed */
- if (collmd->x && (mvert_num != collmd->mvert_num))
+ if (current_time < collmd->time_xnew) {
+ freeData((ModifierData *)collmd);
+ }
+ else if (current_time == collmd->time_xnew) {
+ if (mvert_num != collmd->mvert_num) {
freeData((ModifierData *)collmd);
+ }
+ }
- if (collmd->time_xnew == -1000) { /* first time */
-
- collmd->x = dm->dupVertArray(dm); /* frame start position */
+ /* check if mesh has changed */
+ if (collmd->x && (mvert_num != collmd->mvert_num))
+ freeData((ModifierData *)collmd);
- for (i = 0; i < mvert_num; i++) {
- /* we save global positions */
- mul_m4_v3(ob->obmat, collmd->x[i].co);
- }
+ if (collmd->time_xnew == -1000) { /* first time */
- collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
- collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
- collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
- collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
+ collmd->x = MEM_dupallocN(mesh_src->mvert); /* frame start position */
- collmd->mvert_num = mvert_num;
+ for (uint i = 0; i < mvert_num; i++) {
+ /* we save global positions */
+ mul_m4_v3(ob->obmat, collmd->x[i].co);
+ }
- collmd->tri_num = dm->getNumLoopTri(dm);
- {
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- MVertTri *tri = MEM_malloc_arrayN(collmd->tri_num, sizeof(*tri), __func__);
- DM_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
- collmd->tri = tri;
- }
+ collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
+ collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
+ collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
+ collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
- /* create bounding box hierarchy */
- collmd->bvhtree = bvhtree_build_from_mvert(
- collmd->x,
- collmd->tri, collmd->tri_num,
- ob->pd->pdef_sboft);
+ collmd->mvert_num = mvert_num;
- collmd->time_x = collmd->time_xnew = current_time;
- collmd->is_static = true;
+ {
+ const MLoop *mloop = mesh_src->mloop;
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh_src);
+ collmd->tri_num = BKE_mesh_runtime_looptri_len(mesh_src);
+ MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__);
+ BKE_mesh_runtime_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
+ collmd->tri = tri;
}
- else if (mvert_num == collmd->mvert_num) {
- /* put positions to old positions */
- tempVert = collmd->x;
- collmd->x = collmd->xnew;
- collmd->xnew = tempVert;
- collmd->time_x = collmd->time_xnew;
- memcpy(collmd->xnew, dm->getVertArray(dm), mvert_num * sizeof(MVert));
+ /* create bounding box hierarchy */
+ collmd->bvhtree = bvhtree_build_from_mvert(
+ collmd->x,
+ collmd->tri, collmd->tri_num,
+ ob->pd->pdef_sboft);
- bool is_static = true;
+ collmd->time_x = collmd->time_xnew = current_time;
+ collmd->is_static = true;
+ }
+ else if (mvert_num == collmd->mvert_num) {
+ /* put positions to old positions */
+ tempVert = collmd->x;
+ collmd->x = collmd->xnew;
+ collmd->xnew = tempVert;
+ collmd->time_x = collmd->time_xnew;
- for (i = 0; i < mvert_num; i++) {
- /* we save global positions */
- mul_m4_v3(ob->obmat, collmd->xnew[i].co);
+ memcpy(collmd->xnew, mesh_src->mvert, mvert_num * sizeof(MVert));
- /* detect motion */
- is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co);
- }
+ bool is_static = true;
- memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
- memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
+ for (uint i = 0; i < mvert_num; i++) {
+ /* we save global positions */
+ mul_m4_v3(ob->obmat, collmd->xnew[i].co);
- /* check if GUI setting has changed for bvh */
- if (collmd->bvhtree) {
- if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
- BLI_bvhtree_free(collmd->bvhtree);
- collmd->bvhtree = bvhtree_build_from_mvert(
- collmd->current_x,
- collmd->tri, collmd->tri_num,
- ob->pd->pdef_sboft);
- }
+ /* detect motion */
+ is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co);
+ }
- }
+ memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
+ memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
- /* happens on file load (ONLY when i decomment changes in readfile.c) */
- if (!collmd->bvhtree) {
+ /* check if GUI setting has changed for bvh */
+ if (collmd->bvhtree) {
+ if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
+ BLI_bvhtree_free(collmd->bvhtree);
collmd->bvhtree = bvhtree_build_from_mvert(
collmd->current_x,
collmd->tri, collmd->tri_num,
ob->pd->pdef_sboft);
}
- else if (!collmd->is_static || !is_static) {
- /* recalc static bounding boxes */
- bvhtree_update_from_mvert(
- collmd->bvhtree,
- collmd->current_x, collmd->current_xnew,
- collmd->tri, collmd->tri_num,
- true);
- }
+ }
- collmd->is_static = is_static;
- collmd->time_xnew = current_time;
+ /* happens on file load (ONLY when i decomment changes in readfile.c) */
+ if (!collmd->bvhtree) {
+ collmd->bvhtree = bvhtree_build_from_mvert(
+ collmd->current_x,
+ collmd->tri, collmd->tri_num,
+ ob->pd->pdef_sboft);
}
- else if (mvert_num != collmd->mvert_num) {
- freeData((ModifierData *)collmd);
+ else if (!collmd->is_static || !is_static) {
+ /* recalc static bounding boxes */
+ bvhtree_update_from_mvert(
+ collmd->bvhtree,
+ collmd->current_x, collmd->current_xnew,
+ collmd->tri, collmd->tri_num,
+ true);
}
+ collmd->is_static = is_static;
+ collmd->time_xnew = current_time;
}
- else if (current_time < collmd->time_xnew) {
+ else if (mvert_num != collmd->mvert_num) {
freeData((ModifierData *)collmd);
}
- else {
- if (mvert_num != collmd->mvert_num) {
- freeData((ModifierData *)collmd);
- }
- }
}
- if (dm)
- dm->release(dm);
+ if (mesh_src != mesh) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -252,17 +265,23 @@ ModifierTypeInfo modifierType_Collision = {
eModifierTypeFlag_Single,
/* copyData */ NULL,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index c8369c89716..913ac14f21b 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -41,10 +41,10 @@
#include "MEM_guardedalloc.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
+#include "BKE_library.h"
#include "MOD_modifiertypes.h"
#include "MOD_util.h"
@@ -80,12 +80,12 @@ static void initData(ModifierData *md)
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const CorrectiveSmoothModifierData *csmd = (const CorrectiveSmoothModifierData *)md;
CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
if (csmd->bind_coords) {
tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
@@ -125,7 +125,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
/* check individual weights for changes and cache values */
-static void dm_get_weights(
+static void mesh_get_weights(
MDeformVert *dvert, const int defgrp_index,
const unsigned int numVerts, const bool use_invert_vgroup,
float *smooth_weights)
@@ -145,16 +145,16 @@ static void dm_get_weights(
}
-static void dm_get_boundaries(DerivedMesh *dm, float *smooth_weights)
+static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
{
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const MEdge *medge = dm->getEdgeArray(dm);
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
+ const MEdge *medge = mesh->medge;
unsigned int mpoly_num, medge_num, i;
unsigned short *boundaries;
- mpoly_num = (unsigned int)dm->getNumPolys(dm);
- medge_num = (unsigned int)dm->getNumEdges(dm);
+ mpoly_num = (unsigned int)mesh->totpoly;
+ medge_num = (unsigned int)mesh->totedge;
boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__);
@@ -185,7 +185,7 @@ static void dm_get_boundaries(DerivedMesh *dm, float *smooth_weights)
* (average of surrounding verts)
*/
static void smooth_iter__simple(
- CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ CorrectiveSmoothModifierData *csmd, Mesh *mesh,
float (*vertexCos)[3], unsigned int numVerts,
const float *smooth_weights,
unsigned int iterations)
@@ -193,8 +193,8 @@ static void smooth_iter__simple(
const float lambda = csmd->lambda;
unsigned int i;
- const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
- const MEdge *edges = dm->getEdgeArray(dm);
+ const unsigned int numEdges = (unsigned int)mesh->totedge;
+ const MEdge *edges = mesh->medge;
float *vertex_edge_count_div;
struct SmoothingData_Simple {
@@ -260,17 +260,17 @@ static void smooth_iter__simple(
/* Edge-Length Weighted Smoothing
*/
static void smooth_iter__length_weight(
- CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ CorrectiveSmoothModifierData *csmd, Mesh *mesh,
float (*vertexCos)[3], unsigned int numVerts,
const float *smooth_weights,
unsigned int iterations)
{
const float eps = FLT_EPSILON * 10.0f;
- const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
+ const unsigned int numEdges = (unsigned int)mesh->totedge;
/* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
* and 2.0 rarely spikes, double the value for consistent behavior. */
const float lambda = csmd->lambda * 2.0f;
- const MEdge *edges = dm->getEdgeArray(dm);
+ const MEdge *edges = mesh->medge;
float *vertex_edge_count;
unsigned int i;
@@ -356,25 +356,25 @@ static void smooth_iter__length_weight(
static void smooth_iter(
- CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ CorrectiveSmoothModifierData *csmd, Mesh *mesh,
float (*vertexCos)[3], unsigned int numVerts,
const float *smooth_weights,
unsigned int iterations)
{
switch (csmd->smooth_type) {
case MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT:
- smooth_iter__length_weight(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
+ smooth_iter__length_weight(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations);
break;
/* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
default:
- smooth_iter__simple(csmd, dm, vertexCos, numVerts, smooth_weights, iterations);
+ smooth_iter__simple(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations);
break;
}
}
static void smooth_verts(
- CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ CorrectiveSmoothModifierData *csmd, Mesh *mesh,
MDeformVert *dvert, const int defgrp_index,
float (*vertexCos)[3], unsigned int numVerts)
{
@@ -385,7 +385,7 @@ static void smooth_verts(
smooth_weights = MEM_malloc_arrayN(numVerts, sizeof(float), __func__);
if (dvert) {
- dm_get_weights(
+ mesh_get_weights(
dvert, defgrp_index,
numVerts, (csmd->flag & MOD_CORRECTIVESMOOTH_INVERT_VGROUP) != 0,
smooth_weights);
@@ -395,11 +395,11 @@ static void smooth_verts(
}
if (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY) {
- dm_get_boundaries(dm, smooth_weights);
+ mesh_get_boundaries(mesh, smooth_weights);
}
}
- smooth_iter(csmd, dm, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
+ smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (unsigned int)csmd->repeat);
if (smooth_weights) {
MEM_freeN(smooth_weights);
@@ -463,15 +463,15 @@ static void calc_tangent_loop_accum(
static void calc_tangent_spaces(
- DerivedMesh *dm, float (*vertexCos)[3],
+ Mesh *mesh, float (*vertexCos)[3],
float (*r_tangent_spaces)[3][3])
{
- const unsigned int mpoly_num = (unsigned int)dm->getNumPolys(dm);
+ const unsigned int mpoly_num = (unsigned int)mesh->totpoly;
#ifndef USE_TANGENT_CALC_INLINE
const unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
#endif
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
unsigned int i;
for (i = 0; i < mpoly_num; i++) {
@@ -522,7 +522,7 @@ static void calc_tangent_spaces(
* It's not run on every update (during animation for example).
*/
static void calc_deltas(
- CorrectiveSmoothModifierData *csmd, DerivedMesh *dm,
+ CorrectiveSmoothModifierData *csmd, Mesh *mesh,
MDeformVert *dvert, const int defgrp_index,
const float (*rest_coords)[3], unsigned int numVerts)
{
@@ -542,9 +542,9 @@ static void calc_deltas(
csmd->delta_cache = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
}
- smooth_verts(csmd, dm, dvert, defgrp_index, smooth_vertex_coords, numVerts);
+ smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts);
- calc_tangent_spaces(dm, smooth_vertex_coords, tangent_spaces);
+ calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces);
for (i = 0; i < numVerts; i++) {
float imat[3][3], delta[3];
@@ -566,7 +566,7 @@ static void calc_deltas(
static void correctivesmooth_modifier_do(
- ModifierData *md, Object *ob, DerivedMesh *dm,
+ ModifierData *md, Object *ob, Mesh *mesh,
float (*vertexCos)[3], unsigned int numVerts,
struct BMEditMesh *em)
{
@@ -581,7 +581,7 @@ static void correctivesmooth_modifier_do(
MDeformVert *dvert = NULL;
int defgrp_index;
- modifier_get_vgroup(ob, dm, csmd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index);
/* if rest bind_coords not are defined, set them (only run during bind) */
if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
@@ -595,7 +595,7 @@ static void correctivesmooth_modifier_do(
}
if (UNLIKELY(use_only_smooth)) {
- smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
+ smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
return;
}
@@ -651,7 +651,7 @@ static void correctivesmooth_modifier_do(
TIMEIT_START(corrective_smooth_deltas);
#endif
- calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts);
+ calc_deltas(csmd, mesh, dvert, defgrp_index, rest_coords, numVerts);
#ifdef DEBUG_TIME
TIMEIT_END(corrective_smooth_deltas);
@@ -672,7 +672,7 @@ static void correctivesmooth_modifier_do(
#endif
/* do the actual delta mush */
- smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
+ smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
{
unsigned int i;
@@ -682,7 +682,7 @@ static void correctivesmooth_modifier_do(
/* calloc, since values are accumulated */
tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
- calc_tangent_spaces(dm, vertexCos, tangent_spaces);
+ calc_tangent_spaces(mesh, vertexCos, tangent_spaces);
for (i = 0; i < numVerts; i++) {
float delta[3];
@@ -714,29 +714,29 @@ error:
static void deformVerts(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+ ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
- correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, NULL);
+ correctivesmooth_modifier_do(md, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL);
- if (dm != derivedData) {
- dm->release(dm);
+ if (mesh_src != mesh) {
+ BKE_id_free(NULL, mesh_src);
}
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, false, false);
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
- correctivesmooth_modifier_do(md, ob, dm, vertexCos, (unsigned int)numVerts, editData);
+ correctivesmooth_modifier_do(md, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData);
- if (dm != derivedData) {
- dm->release(dm);
+ if (mesh_src != mesh) {
+ BKE_id_free(NULL, mesh_src);
}
}
@@ -750,17 +750,23 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 90cfc6ba076..e9a3dd3810b 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -34,20 +34,24 @@
#include <string.h>
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
static void initData(ModifierData *md)
{
@@ -67,7 +71,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
-static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams))
+static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams))
{
CurveModifierData *cmd = (CurveModifierData *) md;
@@ -83,19 +87,6 @@ static void foreachObjectLink(
walk(userData, ob, &cmd->object, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- CurveModifierData *cmd = (CurveModifierData *) md;
-
- if (cmd->object) {
- DagNode *curNode = dag_get_node(ctx->forest, cmd->object);
- curNode->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
CurveModifierData *cmd = (CurveModifierData *)md;
@@ -106,40 +97,56 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
/* TODO(sergey): Currently path is evaluated as a part of modifier stack,
* might be changed in the future.
*/
- struct Depsgraph *depsgraph = DEG_get_graph_from_handle(ctx->node);
DEG_add_object_relation(ctx->node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
- DEG_add_special_eval_flag(depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
+ DEG_add_special_eval_flag(ctx->node, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
}
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Curve Modifier");
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
CurveModifierData *cmd = (CurveModifierData *) md;
+ Mesh *mesh_src = NULL;
+
+ if (ctx->object->type == OB_MESH && cmd->name[0] != '\0') {
+ /* mesh_src is only needed for vgroups. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
+ }
+
+ struct MDeformVert *dvert = NULL;
+ int defgrp_index = -1;
+ MOD_get_vgroup(ctx->object, mesh_src, cmd->name, &dvert, &defgrp_index);
/* silly that defaxis and curve_deform_verts are off by 1
* but leave for now to save having to call do_versions */
- curve_deform_verts(md->scene, cmd->object, ob, derivedData, vertexCos, numVerts,
- cmd->name, cmd->defaxis - 1);
+ curve_deform_verts(cmd->object, ctx->object, vertexCos, numVerts, dvert, defgrp_index, cmd->defaxis - 1);
+
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *em,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md,
+ const ModifierEvalContext *ctx,
+ struct BMEditMesh *em,
+ Mesh *mesh,
+ float (*vertexCos)[3],
+ int numVerts)
{
- DerivedMesh *dm = derivedData;
-
- if (!derivedData) dm = CDDM_from_editbmesh(em, false, false);
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
- deformVerts(md, ob, dm, vertexCos, numVerts, 0);
+ deformVerts(md, ctx, mesh_src, vertexCos, numVerts);
- if (!derivedData) dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -153,17 +160,23 @@ ModifierTypeInfo modifierType_Curve = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index b6aa903ba27..d3c0dd783cc 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -37,9 +37,7 @@
#include "DNA_object_types.h"
#include "BKE_customdata.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_data_transfer.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh_mapping.h"
@@ -47,11 +45,11 @@
#include "BKE_modifier.h"
#include "BKE_report.h"
+#include "DEG_depsgraph_query.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
-#include "depsgraph_private.h"
-
/**************************************
* Modifiers functions. *
**************************************/
@@ -127,28 +125,22 @@ static void foreachObjectLink(
walk(userData, ob, &dtmd->ob_source, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
- DagNode *curNode;
-
- if (dtmd->ob_source) {
- curNode = dag_get_node(ctx->forest, dtmd->ob_source);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "DataTransfer Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
if (dtmd->ob_source != NULL) {
- DEG_add_object_relation(ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
+ CustomDataMask mask = BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types);
+
+ DEG_add_object_relation_with_customdata(ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, mask, "DataTransfer Modifier");
+
+ if (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) {
+ DEG_add_object_relation(ctx->node, dtmd->ob_source, DEG_OB_COMP_TRANSFORM, "DataTransfer Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "DataTransfer Modifier");
+ }
}
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
/* If no source object, bypass. */
@@ -163,16 +155,15 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
DT_TYPE_SHARP_FACE \
)
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me_mod)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
- DerivedMesh *dm = derivedData;
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ Mesh *result = me_mod;
ReportList reports;
/* Only used to check wehther we are operating on org data or not... */
- Mesh *me = ob->data;
+ Mesh *me = ctx->object->data;
const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0;
@@ -182,21 +173,27 @@ static DerivedMesh *applyModifier(
SpaceTransform *space_transform = (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) ? &space_transform_data : NULL;
if (space_transform) {
- BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source);
+ BLI_SPACE_TRANSFORM_SETUP(space_transform, ctx->object, dtmd->ob_source);
}
- MVert *mvert = dm->getVertArray(dm);
- MEdge *medge = dm->getEdgeArray(dm);
- if (((me->mvert == mvert) || (me->medge == medge)) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) {
+ if ((result == me_mod || (me->mvert == result->mvert) || (me->medge == result->medge)) &&
+ (dtmd->data_types & DT_TYPES_AFFECT_MESH))
+ {
/* We need to duplicate data here, otherwise setting custom normals, edges' shaprness, etc., could
* modify org mesh, see T43671. */
- dm = CDDM_copy(dm);
+ BKE_id_copy_ex(
+ NULL, &me_mod->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
}
BKE_reports_init(&reports, RPT_STORE);
/* Note: no islands precision for now here. */
- BKE_object_data_transfer_dm(md->scene, dtmd->ob_source, ob, dm, dtmd->data_types, false,
+ BKE_object_data_transfer_ex(ctx->depsgraph, scene, dtmd->ob_source, ctx->object, result, dtmd->data_types, false,
dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode,
space_transform, false, max_dist, dtmd->map_ray_radius, 0.0f,
dtmd->layers_select_src, dtmd->layers_select_dst,
@@ -208,11 +205,11 @@ static DerivedMesh *applyModifier(
else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) {
modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' option in mesh settings");
}
- else if (dm->getNumVerts(dm) > HIGH_POLY_WARNING || ((Mesh *)(dtmd->ob_source->data))->totvert > HIGH_POLY_WARNING) {
+ else if (result->totvert > HIGH_POLY_WARNING || ((Mesh *)(dtmd->ob_source->data))->totvert > HIGH_POLY_WARNING) {
modifier_setError(md, "You are using a rather high poly as source or destination, computation might be slow");
}
- return dm;
+ return result;
}
#undef HIGH_POLY_WARNING
@@ -229,17 +226,23 @@ ModifierTypeInfo modifierType_DataTransfer = {
eModifierTypeFlag_UsesPreview,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 3d0102a8fb9..0159edd069b 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -33,15 +33,17 @@
*/
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
-#include "BKE_modifier.h"
#include "BKE_deform.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_library.h"
#include "bmesh.h"
#include "bmesh_tools.h"
@@ -77,13 +79,12 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *meshData)
{
DecimateModifierData *dmd = (DecimateModifierData *) md;
- DerivedMesh *dm = derivedData, *result = NULL;
+ Mesh *mesh = meshData, *result = NULL;
BMesh *bm;
bool calc_face_normal;
float *vweights = NULL;
@@ -93,34 +94,34 @@ static DerivedMesh *applyModifier(
#endif
/* set up front so we dont show invalid info in the UI */
- dmd->face_count = dm->getNumPolys(dm);
+ dmd->face_count = mesh->totpoly;
switch (dmd->mode) {
case MOD_DECIM_MODE_COLLAPSE:
if (dmd->percent == 1.0f) {
- return dm;
+ return mesh;
}
calc_face_normal = true;
break;
case MOD_DECIM_MODE_UNSUBDIV:
if (dmd->iter == 0) {
- return dm;
+ return mesh;
}
calc_face_normal = false;
break;
case MOD_DECIM_MODE_DISSOLVE:
if (dmd->angle == 0.0f) {
- return dm;
+ return mesh;
}
calc_face_normal = true;
break;
default:
- return dm;
+ return mesh;
}
if (dmd->face_count <= 3) {
modifier_setError(md, "Modifier requires more than 3 input faces");
- return dm;
+ return mesh;
}
if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
@@ -128,10 +129,10 @@ static DerivedMesh *applyModifier(
MDeformVert *dvert;
int defgrp_index;
- modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ctx->object, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
if (dvert) {
- const unsigned int vert_tot = dm->getNumVerts(dm);
+ const unsigned int vert_tot = mesh->totvert;
unsigned int i;
vweights = MEM_malloc_arrayN(vert_tot, sizeof(float), __func__);
@@ -150,7 +151,13 @@ static DerivedMesh *applyModifier(
}
}
- bm = DM_to_bmesh(dm, calc_face_normal);
+ bm = BKE_mesh_to_bmesh_ex(
+ mesh,
+ &(struct BMeshCreateParams){0},
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = calc_face_normal,
+ .cd_mask_extra = CD_MASK_ORIGINDEX,
+ });
switch (dmd->mode) {
case MOD_DECIM_MODE_COLLAPSE:
@@ -182,7 +189,7 @@ static DerivedMesh *applyModifier(
/* update for display only */
dmd->face_count = bm->totface;
- result = CDDM_from_bmesh(bm, false);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
BLI_assert(bm->vtoolflagpool == NULL &&
bm->etoolflagpool == NULL &&
bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */
@@ -196,7 +203,7 @@ static DerivedMesh *applyModifier(
TIMEIT_END(decim);
#endif
- result->dirty = DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
@@ -208,18 +215,25 @@ ModifierTypeInfo modifierType_Decimate = {
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_AcceptsCVs,
+
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index ed78e026a7f..a477191357e 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -33,6 +33,7 @@
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -40,7 +41,8 @@
#include "BLI_math.h"
#include "BLI_task.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_image.h"
@@ -50,7 +52,9 @@
#include "BKE_deform.h"
#include "BKE_object.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
@@ -134,37 +138,17 @@ static void foreachTexLink(
walk(userData, ob, md, "texture");
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
return ((!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) || dmd->strength == 0.0f);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- DisplaceModifierData *dmd = (DisplaceModifierData *) md;
-
- if (dmd->map_object && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
- DagNode *curNode = dag_get_node(ctx->forest, dmd->map_object);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier");
- }
-
-
- if (dmd->texmapping == MOD_DISP_MAP_GLOBAL ||
- (ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
- dmd->space == MOD_DISP_SPACE_GLOBAL))
- {
- dag_add_relation(ctx->forest, ctx->obNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
DisplaceModifierData *dmd = (DisplaceModifierData *)md;
if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
DEG_add_object_relation(ctx->node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
}
if (dmd->texmapping == MOD_DISP_MAP_GLOBAL ||
@@ -177,6 +161,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
typedef struct DisplaceUserdata {
/*const*/ DisplaceModifierData *dmd;
+ struct Scene *scene;
struct ImagePool *pool;
MDeformVert *dvert;
float weight;
@@ -223,7 +208,7 @@ static void displaceModifier_do_task(
if (dmd->texture) {
texres.nor = NULL;
- BKE_texture_get_value_ex(dmd->modifier.scene, dmd->texture, tex_co[iter], &texres, data->pool, false);
+ BKE_texture_get_value_ex(data->scene, dmd->texture, tex_co[iter], &texres, data->pool, false);
delta = texres.tin - dmd->midlevel;
}
else {
@@ -289,11 +274,12 @@ static void displaceModifier_do_task(
}
}
-/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
- DisplaceModifierData *dmd, Object *ob,
- DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
+ DisplaceModifierData *dmd, const ModifierEvalContext *ctx,
+ Mesh *mesh, float (*vertexCos)[3], const int numVerts)
{
+ Object *ob = ctx->object;
+ Depsgraph *depsgraph = ctx->depsgraph;
MVert *mvert;
MDeformVert *dvert;
int direction = dmd->direction;
@@ -307,33 +293,33 @@ static void displaceModifier_do(
if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
if (dmd->strength == 0.0f) return;
- mvert = CDDM_get_verts(dm);
- modifier_get_vgroup(ob, dm, dmd->defgrp_name, &dvert, &defgrp_index);
+ mvert = mesh->mvert;
+ MOD_get_vgroup(ob, mesh, dmd->defgrp_name, &dvert, &defgrp_index);
if (dmd->texture) {
tex_co = MEM_calloc_arrayN((size_t)numVerts, sizeof(*tex_co),
"displaceModifier_do tex_co");
- get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts);
+ MOD_get_texture_coords((MappingInfoModifierData *)dmd, ob, mesh, vertexCos, tex_co);
- modifier_init_texture(dmd->modifier.scene, dmd->texture);
+ MOD_init_texture(depsgraph, dmd->texture);
}
else {
tex_co = NULL;
}
if (direction == MOD_DISP_DIR_CLNOR) {
- CustomData *ldata = dm->getLoopDataLayout(dm);
+ CustomData *ldata = &mesh->ldata;
if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) {
float (*clnors)[3] = NULL;
- if ((dm->dirty & DM_DIRTY_NORMALS) || !CustomData_has_layer(ldata, CD_NORMAL)) {
- dm->calcLoopNormals(dm, true, (float)M_PI);
+ if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || !CustomData_has_layer(ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(mesh);
}
clnors = CustomData_get_layer(ldata, CD_NORMAL);
vert_clnors = MEM_malloc_arrayN(numVerts, sizeof(*vert_clnors), __func__);
- BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm),
+ BKE_mesh_normals_loop_to_vertex(numVerts, mesh->mloop, mesh->totloop,
(const float (*)[3])clnors, vert_clnors);
}
else {
@@ -347,6 +333,7 @@ static void displaceModifier_do(
}
DisplaceUserdata data = {NULL};
+ data.scene = DEG_get_evaluated_scene(ctx->depsgraph);
data.dmd = dmd;
data.dvert = dvert;
data.weight = weight;
@@ -384,32 +371,32 @@ static void displaceModifier_do(
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
- DerivedMesh *dm = get_cddm(ob, NULL, derivedData, vertexCos, dependsOnNormals(md));
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
- displaceModifier_do((DisplaceModifierData *)md, ob, dm,
- vertexCos, numVerts);
+ displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = get_cddm(ob, editData, derivedData, vertexCos, dependsOnNormals(md));
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
- displaceModifier_do((DisplaceModifierData *)md, ob, dm,
- vertexCos, numVerts);
+ displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -422,17 +409,23 @@ ModifierTypeInfo modifierType_Displace = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index 8d3aea2d5c8..c23a65ec23c 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -31,19 +31,21 @@
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
#include "DNA_scene_types.h"
+#include "DNA_mesh_types.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_dynamicpaint.h"
-#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
-#include "BKE_main.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "MOD_modifiertypes.h"
@@ -56,12 +58,12 @@ static void initData(ModifierData *md)
pmd->type = MOD_DYNAMICPAINT_TYPE_CANVAS;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const DynamicPaintModifierData *pmd = (const DynamicPaintModifierData *)md;
DynamicPaintModifierData *tpmd = (DynamicPaintModifierData *)target;
- dynamicPaint_Modifier_copy(pmd, tpmd);
+ dynamicPaint_Modifier_copy(pmd, tpmd, flag);
}
static void freeData(ModifierData *md)
@@ -82,7 +84,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ ||
surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE)
{
- dataMask |= CD_MASK_MLOOPUV | CD_MASK_MTEXPOLY;
+ dataMask |= CD_MASK_MLOOPUV;
}
/* mcol */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT ||
@@ -96,27 +98,21 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
}
}
}
-
- if (pmd->brush) {
- if (pmd->brush->flags & MOD_DPAINT_USE_MATERIAL) {
- dataMask |= CD_MASK_MLOOPUV | CD_MASK_MTEXPOLY;
- }
- }
return dataMask;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag flag)
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *) md;
- /* dont apply dynamic paint on orco dm stack */
- if (!(flag & MOD_APPLY_ORCO)) {
- return dynamicPaint_Modifier_do(G.main, G.main->eval_ctx, pmd, md->scene, ob, dm);
+ /* dont apply dynamic paint on orco mesh stack */
+ if (!(ctx->flag & MOD_APPLY_ORCO)) {
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ return dynamicPaint_Modifier_do(pmd, ctx->depsgraph, scene, ctx->object, mesh);
}
- return dm;
+ return mesh;
}
static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd)
@@ -124,27 +120,6 @@ static bool is_brush_cb(Object *UNUSED(ob), ModifierData *pmd)
return ((DynamicPaintModifierData *)pmd)->brush != NULL;
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *) md;
-
- /* add relation from canvases to all brush objects */
- if (pmd && pmd->canvas) {
-#ifdef WITH_LEGACY_DEPSGRAPH
- for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- dag_add_forcefield_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, surface->effector_weights, true, 0, "Dynamic Paint Field");
- }
-
- /* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */
- dag_add_collision_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, surface->brush_group, -1, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush");
- }
-#else
- (void)ctx;
-#endif
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
@@ -152,11 +127,11 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
if (pmd->canvas != NULL) {
for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- DEG_add_forcefield_relations(ctx->node, ctx->scene, ctx->object, surface->effector_weights, true, 0, "Dynamic Paint Field");
+ DEG_add_forcefield_relations(ctx->node, ctx->object, surface->effector_weights, true, 0, "Dynamic Paint Field");
}
/* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */
- DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, surface->brush_group, -1, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush");
+ DEG_add_collision_relations(ctx->node, ctx->object, surface->brush_group, eModifierType_DynamicPaint, is_brush_cb, "Dynamic Paint Brush");
}
}
}
@@ -183,9 +158,6 @@ static void foreachIDLink(
}
}
}
- if (pmd->brush) {
- walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_CB_USER);
- }
}
static void foreachTexLink(
@@ -207,17 +179,23 @@ ModifierTypeInfo modifierType_DynamicPaint = {
eModifierTypeFlag_UsesPreview,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 1de698a6218..f52632cdcc9 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -40,26 +40,37 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "MOD_modifiertypes.h"
-static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd)
+static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd, const ModifierEvalContext *ctx)
{
- DerivedMesh *result;
+ Mesh *result;
BMesh *bm;
BMIter iter;
BMEdge *e;
float threshold = cosf(emd->split_angle + 0.000000175f);
const bool calc_face_normals = (emd->flags & MOD_EDGESPLIT_FROMANGLE) != 0;
- bm = DM_to_bmesh(dm, calc_face_normals);
+ bm = BKE_mesh_to_bmesh_ex(
+ mesh,
+ &(struct BMeshCreateParams){0},
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = calc_face_normals,
+ .add_key_index = false,
+ .use_shapekey = true,
+ .active_shapekey = ctx->object->shapenr,
+ .cd_mask_extra = CD_MASK_ORIGINDEX,
+ });
if (emd->flags & MOD_EDGESPLIT_FROMANGLE) {
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
@@ -96,10 +107,10 @@ static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd)
/* BM_mesh_validate(bm); */ /* for troubleshooting */
- result = CDDM_from_bmesh(bm, true);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
BM_mesh_free(bm);
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
@@ -112,17 +123,18 @@ static void initData(ModifierData *md)
emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *UNUSED(ob), DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
- DerivedMesh *result;
+ Mesh *result;
EdgeSplitModifierData *emd = (EdgeSplitModifierData *) md;
if (!(emd->flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG)))
- return dm;
+ return mesh;
- result = doEdgeSplit(dm, emd);
+ result = doEdgeSplit(mesh, emd, ctx);
return result;
}
@@ -140,17 +152,23 @@ ModifierTypeInfo modifierType_EdgeSplit = {
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 2fc30f9fddd..f736e44a4cf 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -36,6 +36,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "BLI_utildefines.h"
#include "BLI_kdtree.h"
@@ -43,14 +44,16 @@
#include "BLI_math.h"
#include "BLI_edgehash.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph_query.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_modifiertypes.h"
@@ -68,14 +71,14 @@ static void freeData(ModifierData *md)
MEM_SAFE_FREE(emd->facepa);
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
#if 0
const ExplodeModifierData *emd = (const ExplodeModifierData *) md;
#endif
ExplodeModifierData *temd = (ExplodeModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
temd->facepa = NULL;
}
@@ -97,7 +100,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
static void createFacepa(
ExplodeModifierData *emd,
ParticleSystemModifierData *psmd,
- DerivedMesh *dm)
+ Mesh *mesh)
{
ParticleSystem *psys = psmd->psys;
MFace *fa = NULL, *mface = NULL;
@@ -109,31 +112,32 @@ static void createFacepa(
int *facepa = NULL, *vertpa = NULL, totvert = 0, totface = 0, totpart = 0;
int i, p, v1, v2, v3, v4 = 0;
- mvert = dm->getVertArray(dm);
- mface = dm->getTessFaceArray(dm);
- totface = dm->getNumTessFaces(dm);
- totvert = dm->getNumVerts(dm);
+ mvert = mesh->mvert;
+ mface = mesh->mface;
+ totvert = mesh->totvert;
+ totface = mesh->totface;
totpart = psmd->psys->totpart;
rng = BLI_rng_new_srandom(psys->seed);
- if (emd->facepa)
+ if (emd->facepa) {
MEM_freeN(emd->facepa);
-
+ }
facepa = emd->facepa = MEM_calloc_arrayN(totface, sizeof(int), "explode_facepa");
vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa");
/* initialize all faces & verts to no particle */
- for (i = 0; i < totface; i++)
+ for (i = 0; i < totface; i++) {
facepa[i] = totpart;
-
- for (i = 0; i < totvert; i++)
+ }
+ for (i = 0; i < totvert; i++) {
vertpa[i] = totpart;
+ }
/* set protected verts */
if (emd->vgroup) {
- MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ MDeformVert *dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
if (dvert) {
const int defgrp_index = emd->vgroup - 1;
for (i = 0; i < totvert; i++, dvert++) {
@@ -148,7 +152,7 @@ static void createFacepa(
/* make tree of emitter locations */
tree = BLI_kdtree_new(totpart);
for (p = 0, pa = psys->particles; p < totpart; p++, pa++) {
- psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL, NULL);
+ psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL);
BLI_kdtree_insert(tree, p, co);
}
BLI_kdtree_balance(tree);
@@ -161,27 +165,40 @@ static void createFacepa(
add_v3_v3(center, mvert[fa->v4].co);
mul_v3_fl(center, 0.25);
}
- else
+ else {
mul_v3_fl(center, 1.0f / 3.0f);
+ }
p = BLI_kdtree_find_nearest(tree, center, NULL);
v1 = vertpa[fa->v1];
v2 = vertpa[fa->v2];
v3 = vertpa[fa->v3];
- if (fa->v4)
+ if (fa->v4) {
v4 = vertpa[fa->v4];
+ }
- if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0))
+ if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0)) {
facepa[i] = p;
+ }
- if (v1 >= 0) vertpa[fa->v1] = p;
- if (v2 >= 0) vertpa[fa->v2] = p;
- if (v3 >= 0) vertpa[fa->v3] = p;
- if (fa->v4 && v4 >= 0) vertpa[fa->v4] = p;
+ if (v1 >= 0) {
+ vertpa[fa->v1] = p;
+ }
+ if (v2 >= 0) {
+ vertpa[fa->v2] = p;
+ }
+ if (v3 >= 0) {
+ vertpa[fa->v3] = p;
+ }
+ if (fa->v4 && v4 >= 0) {
+ vertpa[fa->v4] = p;
+ }
}
- if (vertpa) MEM_freeN(vertpa);
+ if (vertpa) {
+ MEM_freeN(vertpa);
+ }
BLI_kdtree_free(tree);
BLI_rng_free(rng);
@@ -200,10 +217,10 @@ static const short add_faces[24] = {
1, 1, 2
};
-static MFace *get_dface(DerivedMesh *dm, DerivedMesh *split, int cur, int i, MFace *mf)
+static MFace *get_dface(Mesh *mesh, Mesh *split, int cur, int i, MFace *mf)
{
- MFace *df = CDDM_get_tessface(split, cur);
- DM_copy_tessface_data(dm, split, i, cur, 1);
+ MFace *df = &split->mface[cur];
+ CustomData_copy_data(&mesh->fdata, &split->fdata, i, cur, 1);
*df = *mf;
return df;
}
@@ -219,11 +236,11 @@ static MFace *get_dface(DerivedMesh *dm, DerivedMesh *split, int cur, int i, MFa
#define GET_ES(v1, v2) edgecut_get(eh, v1, v2)
#define INT_UV(uvf, c0, c1) mid_v2_v2v2(uvf, mf->uv[c0], mf->uv[c1])
-static void remap_faces_3_6_9_12(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
+static void remap_faces_3_6_9_12(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
{
- MFace *df1 = get_dface(dm, split, cur, i, mf);
- MFace *df2 = get_dface(dm, split, cur + 1, i, mf);
- MFace *df3 = get_dface(dm, split, cur + 2, i, mf);
+ MFace *df1 = get_dface(mesh, split, cur, i, mf);
+ MFace *df2 = get_dface(mesh, split, cur + 1, i, mf);
+ MFace *df3 = get_dface(mesh, split, cur + 2, i, mf);
facepa[cur] = vertpa[v1];
df1->v1 = v1;
@@ -247,17 +264,17 @@ static void remap_faces_3_6_9_12(DerivedMesh *dm, DerivedMesh *split, MFace *mf,
df3->flag &= ~ME_FACE_SEL;
}
-static void remap_uvs_3_6_9_12(DerivedMesh *dm, DerivedMesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3)
+static void remap_uvs_3_6_9_12(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3)
{
MTFace *mf, *df1, *df2, *df3;
int l;
for (l = 0; l < numlayer; l++) {
- mf = CustomData_get_layer_n(&split->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l);
df1 = mf + cur;
df2 = df1 + 1;
df3 = df1 + 2;
- mf = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l);
mf += i;
copy_v2_v2(df1->uv[0], mf->uv[c0]);
@@ -275,10 +292,10 @@ static void remap_uvs_3_6_9_12(DerivedMesh *dm, DerivedMesh *split, int numlayer
}
}
-static void remap_faces_5_10(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
+static void remap_faces_5_10(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
{
- MFace *df1 = get_dface(dm, split, cur, i, mf);
- MFace *df2 = get_dface(dm, split, cur + 1, i, mf);
+ MFace *df1 = get_dface(mesh, split, cur, i, mf);
+ MFace *df2 = get_dface(mesh, split, cur + 1, i, mf);
facepa[cur] = vertpa[v1];
df1->v1 = v1;
@@ -295,16 +312,16 @@ static void remap_faces_5_10(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int
df2->flag |= ME_FACE_SEL;
}
-static void remap_uvs_5_10(DerivedMesh *dm, DerivedMesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3)
+static void remap_uvs_5_10(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3)
{
MTFace *mf, *df1, *df2;
int l;
for (l = 0; l < numlayer; l++) {
- mf = CustomData_get_layer_n(&split->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l);
df1 = mf + cur;
df2 = df1 + 1;
- mf = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l);
mf += i;
copy_v2_v2(df1->uv[0], mf->uv[c0]);
@@ -320,12 +337,12 @@ static void remap_uvs_5_10(DerivedMesh *dm, DerivedMesh *split, int numlayer, in
}
}
-static void remap_faces_15(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
+static void remap_faces_15(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
{
- MFace *df1 = get_dface(dm, split, cur, i, mf);
- MFace *df2 = get_dface(dm, split, cur + 1, i, mf);
- MFace *df3 = get_dface(dm, split, cur + 2, i, mf);
- MFace *df4 = get_dface(dm, split, cur + 3, i, mf);
+ MFace *df1 = get_dface(mesh, split, cur, i, mf);
+ MFace *df2 = get_dface(mesh, split, cur + 1, i, mf);
+ MFace *df3 = get_dface(mesh, split, cur + 2, i, mf);
+ MFace *df4 = get_dface(mesh, split, cur + 3, i, mf);
facepa[cur] = vertpa[v1];
df1->v1 = v1;
@@ -356,18 +373,18 @@ static void remap_faces_15(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *
df4->flag |= ME_FACE_SEL;
}
-static void remap_uvs_15(DerivedMesh *dm, DerivedMesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3)
+static void remap_uvs_15(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3)
{
MTFace *mf, *df1, *df2, *df3, *df4;
int l;
for (l = 0; l < numlayer; l++) {
- mf = CustomData_get_layer_n(&split->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l);
df1 = mf + cur;
df2 = df1 + 1;
df3 = df1 + 2;
df4 = df1 + 3;
- mf = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l);
mf += i;
copy_v2_v2(df1->uv[0], mf->uv[c0]);
@@ -392,11 +409,11 @@ static void remap_uvs_15(DerivedMesh *dm, DerivedMesh *split, int numlayer, int
}
}
-static void remap_faces_7_11_13_14(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
+static void remap_faces_7_11_13_14(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
{
- MFace *df1 = get_dface(dm, split, cur, i, mf);
- MFace *df2 = get_dface(dm, split, cur + 1, i, mf);
- MFace *df3 = get_dface(dm, split, cur + 2, i, mf);
+ MFace *df1 = get_dface(mesh, split, cur, i, mf);
+ MFace *df2 = get_dface(mesh, split, cur + 1, i, mf);
+ MFace *df3 = get_dface(mesh, split, cur + 2, i, mf);
facepa[cur] = vertpa[v1];
df1->v1 = v1;
@@ -420,17 +437,17 @@ static void remap_faces_7_11_13_14(DerivedMesh *dm, DerivedMesh *split, MFace *m
df3->flag |= ME_FACE_SEL;
}
-static void remap_uvs_7_11_13_14(DerivedMesh *dm, DerivedMesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3)
+static void remap_uvs_7_11_13_14(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2, int c3)
{
MTFace *mf, *df1, *df2, *df3;
int l;
for (l = 0; l < numlayer; l++) {
- mf = CustomData_get_layer_n(&split->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l);
df1 = mf + cur;
df2 = df1 + 1;
df3 = df1 + 2;
- mf = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l);
mf += i;
copy_v2_v2(df1->uv[0], mf->uv[c0]);
@@ -449,10 +466,10 @@ static void remap_uvs_7_11_13_14(DerivedMesh *dm, DerivedMesh *split, int numlay
}
}
-static void remap_faces_19_21_22(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3)
+static void remap_faces_19_21_22(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3)
{
- MFace *df1 = get_dface(dm, split, cur, i, mf);
- MFace *df2 = get_dface(dm, split, cur + 1, i, mf);
+ MFace *df1 = get_dface(mesh, split, cur, i, mf);
+ MFace *df2 = get_dface(mesh, split, cur + 1, i, mf);
facepa[cur] = vertpa[v1];
df1->v1 = v1;
@@ -469,16 +486,16 @@ static void remap_faces_19_21_22(DerivedMesh *dm, DerivedMesh *split, MFace *mf,
df2->flag |= ME_FACE_SEL;
}
-static void remap_uvs_19_21_22(DerivedMesh *dm, DerivedMesh *split, int numlayer, int i, int cur, int c0, int c1, int c2)
+static void remap_uvs_19_21_22(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2)
{
MTFace *mf, *df1, *df2;
int l;
for (l = 0; l < numlayer; l++) {
- mf = CustomData_get_layer_n(&split->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l);
df1 = mf + cur;
df2 = df1 + 1;
- mf = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l);
mf += i;
copy_v2_v2(df1->uv[0], mf->uv[c0]);
@@ -492,11 +509,11 @@ static void remap_uvs_19_21_22(DerivedMesh *dm, DerivedMesh *split, int numlayer
}
}
-static void remap_faces_23(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3)
+static void remap_faces_23(Mesh *mesh, Mesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3)
{
- MFace *df1 = get_dface(dm, split, cur, i, mf);
- MFace *df2 = get_dface(dm, split, cur + 1, i, mf);
- MFace *df3 = get_dface(dm, split, cur + 2, i, mf);
+ MFace *df1 = get_dface(mesh, split, cur, i, mf);
+ MFace *df2 = get_dface(mesh, split, cur + 1, i, mf);
+ MFace *df3 = get_dface(mesh, split, cur + 2, i, mf);
facepa[cur] = vertpa[v1];
df1->v1 = v1;
@@ -520,16 +537,16 @@ static void remap_faces_23(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *
df3->flag &= ~ME_FACE_SEL;
}
-static void remap_uvs_23(DerivedMesh *dm, DerivedMesh *split, int numlayer, int i, int cur, int c0, int c1, int c2)
+static void remap_uvs_23(Mesh *mesh, Mesh *split, int numlayer, int i, int cur, int c0, int c1, int c2)
{
MTFace *mf, *df1, *df2;
int l;
for (l = 0; l < numlayer; l++) {
- mf = CustomData_get_layer_n(&split->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&split->fdata, CD_MTFACE, l);
df1 = mf + cur;
df2 = df1 + 1;
- mf = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, l);
+ mf = CustomData_get_layer_n(&mesh->fdata, CD_MTFACE, l);
mf += i;
copy_v2_v2(df1->uv[0], mf->uv[c0]);
@@ -547,16 +564,16 @@ static void remap_uvs_23(DerivedMesh *dm, DerivedMesh *split, int numlayer, int
}
}
-static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
+static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
{
- DerivedMesh *splitdm;
+ Mesh *split_m;
MFace *mf = NULL, *df1 = NULL;
- MFace *mface = dm->getTessFaceArray(dm);
+ MFace *mface = mesh->mface;
MVert *dupve, *mv;
EdgeHash *edgehash;
EdgeHashIterator *ehi;
- int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumTessFaces(dm);
+ int totvert = mesh->totvert;
+ int totface = mesh->totface;
int *facesplit = MEM_calloc_arrayN(totface, sizeof(int), "explode_facesplit");
int *vertpa = MEM_calloc_arrayN(totvert, sizeof(int), "explode_vertpa2");
@@ -575,8 +592,9 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
vertpa[mf->v1] = facepa[i];
vertpa[mf->v2] = facepa[i];
vertpa[mf->v3] = facepa[i];
- if (mf->v4)
+ if (mf->v4) {
vertpa[mf->v4] = facepa[i];
+ }
}
/* mark edges for splitting and how to split faces */
@@ -609,8 +627,9 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
}
/* mark center vertex as a fake edge split */
- if (*fs == 15)
+ if (*fs == 15) {
BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL);
+ }
}
else {
(*fs) |= 16; /* mark face as tri */
@@ -635,19 +654,19 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
for (i = 0, fs = facesplit; i < totface; i++, fs++)
totfsplit += add_faces[*fs];
- splitdm = CDDM_from_template_ex(
- dm, totesplit, 0, totface + totfsplit, 0, 0,
- CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS);
- numlayer = CustomData_number_of_layers(&splitdm->faceData, CD_MTFACE);
+ split_m = BKE_mesh_new_nomain_from_template(
+ mesh, totesplit, 0, totface + totfsplit, 0, 0);
+
+ numlayer = CustomData_number_of_layers(&split_m->fdata, CD_MTFACE);
/* copy new faces & verts (is it really this painful with custom data??) */
for (i = 0; i < totvert; i++) {
MVert source;
MVert *dest;
- dm->getVert(dm, i, &source);
- dest = CDDM_get_vert(splitdm, i);
+ source = mesh->mvert[i];
+ dest = &split_m->mvert[i];
- DM_copy_vert_data(dm, splitdm, i, i, 1);
+ CustomData_copy_data(&mesh->vdata, &split_m->vdata, i, i, 1);
*dest = source;
}
@@ -666,14 +685,14 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2);
esplit = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
- mv = CDDM_get_vert(splitdm, ed_v2);
- dupve = CDDM_get_vert(splitdm, esplit);
+ mv = &split_m->mvert[ed_v2];
+ dupve = &split_m->mvert[esplit];
- DM_copy_vert_data(splitdm, splitdm, ed_v2, esplit, 1);
+ CustomData_copy_data(&split_m->vdata, &split_m->vdata, ed_v2, esplit, 1);
*dupve = *mv;
- mv = CDDM_get_vert(splitdm, ed_v1);
+ mv = &split_m->mvert[ed_v1];
mid_v3_v3v3(dupve->co, dupve->co, mv->co);
}
@@ -683,7 +702,7 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
curdupface = 0; //=totface;
//curdupin=totesplit;
for (i = 0, fs = facesplit; i < totface; i++, fs++) {
- mf = dm->getTessFaceData(dm, i, CD_MFACE);
+ mf = &mesh->mface[i];
switch (*fs) {
case 3:
@@ -722,50 +741,58 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
case 6:
case 9:
case 12:
- remap_faces_3_6_9_12(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
- if (numlayer)
- remap_uvs_3_6_9_12(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
+ remap_faces_3_6_9_12(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
+ if (numlayer) {
+ remap_uvs_3_6_9_12(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
+ }
break;
case 5:
case 10:
- remap_faces_5_10(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
- if (numlayer)
- remap_uvs_5_10(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
+ remap_faces_5_10(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
+ if (numlayer) {
+ remap_uvs_5_10(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
+ }
break;
case 15:
- remap_faces_15(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
- if (numlayer)
- remap_uvs_15(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
+ remap_faces_15(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
+ if (numlayer) {
+ remap_uvs_15(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
+ }
break;
case 7:
case 11:
case 13:
case 14:
- remap_faces_7_11_13_14(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
- if (numlayer)
- remap_uvs_7_11_13_14(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
+ remap_faces_7_11_13_14(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
+ if (numlayer) {
+ remap_uvs_7_11_13_14(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
+ }
break;
case 19:
case 21:
case 22:
- remap_faces_19_21_22(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
- if (numlayer)
- remap_uvs_19_21_22(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
+ remap_faces_19_21_22(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
+ if (numlayer) {
+ remap_uvs_19_21_22(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
+ }
break;
case 23:
- remap_faces_23(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
- if (numlayer)
- remap_uvs_23(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
+ remap_faces_23(mesh, split_m, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
+ if (numlayer) {
+ remap_uvs_23(mesh, split_m, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
+ }
break;
case 0:
case 16:
- df1 = get_dface(dm, splitdm, curdupface, i, mf);
+ df1 = get_dface(mesh, split_m, curdupface, i, mf);
facepa[curdupface] = vertpa[mf->v1];
- if (df1->v4)
+ if (df1->v4) {
df1->flag |= ME_FACE_SEL;
- else
+ }
+ else {
df1->flag &= ~ME_FACE_SEL;
+ }
break;
}
@@ -773,25 +800,25 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
}
for (i = 0; i < curdupface; i++) {
- mf = CDDM_get_tessface(splitdm, i);
- test_index_face(mf, &splitdm->faceData, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
+ mf = &split_m->mface[i];
+ test_index_face(mf, &split_m->fdata, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
}
BLI_edgehash_free(edgehash, NULL);
MEM_freeN(facesplit);
MEM_freeN(vertpa);
- CDDM_calc_edges_tessface(splitdm);
- CDDM_tessfaces_to_faces(splitdm); /*builds ngon faces from tess (mface) faces*/
+ BKE_mesh_calc_edges_tessface(split_m);
+ BKE_mesh_convert_mfaces_to_mpolys(split_m);
- return splitdm;
+ return split_m;
}
-static DerivedMesh *explodeMesh(
+static Mesh *explodeMesh(
ExplodeModifierData *emd,
- ParticleSystemModifierData *psmd, Scene *scene, Object *ob,
- DerivedMesh *to_explode)
+ ParticleSystemModifierData *psmd, const ModifierEvalContext *ctx, Scene *scene,
+ Mesh *to_explode)
{
- DerivedMesh *explode, *dm = to_explode;
+ Mesh *explode, *mesh = to_explode;
MFace *mf = NULL, *mface;
/* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */
ParticleSimulationData sim = {NULL};
@@ -809,13 +836,14 @@ static DerivedMesh *explodeMesh(
unsigned int ed_v1, ed_v2, mindex = 0;
MTFace *mtface = NULL, *mtf;
- totface = dm->getNumTessFaces(dm);
- totvert = dm->getNumVerts(dm);
- mface = dm->getTessFaceArray(dm);
+ totface = mesh->totface;
+ totvert = mesh->totvert;
+ mface = mesh->mface;
totpart = psmd->psys->totpart;
+ sim.depsgraph = ctx->depsgraph;
sim.scene = scene;
- sim.ob = ob;
+ sim.ob = ctx->object;
sim.psys = psmd->psys;
sim.psmd = psmd;
@@ -841,10 +869,12 @@ static DerivedMesh *explodeMesh(
/* do mindex + totvert to ensure the vertex index to be the first
* with BLI_edgehashIterator_getKey */
- if (facepa[i] == totpart || cfra < (pars + facepa[i])->time)
+ if (facepa[i] == totpart || cfra < (pars + facepa[i])->time) {
mindex = totvert + totpart;
- else
+ }
+ else {
mindex = totvert + facepa[i];
+ }
mf = &mface[i];
@@ -852,8 +882,9 @@ static DerivedMesh *explodeMesh(
BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, NULL);
BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, NULL);
BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, NULL);
- if (mf->v4)
+ if (mf->v4) {
BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, NULL);
+ }
}
/* make new vertice indexes & count total vertices after duplication */
@@ -865,12 +896,13 @@ static DerivedMesh *explodeMesh(
BLI_edgehashIterator_free(ehi);
/* the final duplicated vertices */
- explode = CDDM_from_template_ex(dm, totdup, 0, totface - delface, 0, 0, CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS);
- mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname);
+ explode = BKE_mesh_new_nomain_from_template(mesh, totdup, 0, totface - delface, 0, 0);
+
+ mtface = CustomData_get_layer_named(&explode->fdata, CD_MTFACE, emd->uvname);
/*dupvert = CDDM_get_verts(explode);*/
/* getting back to object space */
- invert_m4_m4(imat, ob->obmat);
+ invert_m4_m4(imat, ctx->object->obmat);
psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
@@ -885,10 +917,11 @@ static DerivedMesh *explodeMesh(
ed_v2 -= totvert;
v = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
- dm->getVert(dm, ed_v1, &source);
- dest = CDDM_get_vert(explode, v);
+ source = mesh->mvert[ed_v1];
+ dest = &explode->mvert[v];
+
+ CustomData_copy_data(&mesh->vdata, &explode->vdata, ed_v1, v, 1);
- DM_copy_vert_data(dm, explode, ed_v1, v, 1);
*dest = source;
if (ed_v2 != totpart) {
@@ -900,8 +933,8 @@ static DerivedMesh *explodeMesh(
state.time = cfra;
psys_get_particle_state(&sim, ed_v2, &state, 1);
- vertco = CDDM_get_vert(explode, v)->co;
- mul_m4_v3(ob->obmat, vertco);
+ vertco = explode->mvert[v].co;
+ mul_m4_v3(ctx->object->obmat, vertco);
sub_v3_v3(vertco, birth.co);
@@ -909,8 +942,9 @@ static DerivedMesh *explodeMesh(
sub_qt_qtqt(rot, state.rot, birth.rot);
mul_qt_v3(rot, vertco);
- if (emd->flag & eExplodeFlag_PaSize)
+ if (emd->flag & eExplodeFlag_PaSize) {
mul_v3_fl(vertco, pa->size);
+ }
add_v3_v3(vertco, state.co);
@@ -932,23 +966,26 @@ static DerivedMesh *explodeMesh(
if (pa->alive == PARS_DEAD && (emd->flag & eExplodeFlag_Dead) == 0) continue;
}
- dm->getTessFace(dm, i, &source);
- mf = CDDM_get_tessface(explode, u);
+ source = mesh->mface[i];
+ mf = &explode->mface[u];
orig_v4 = source.v4;
- if (facepa[i] != totpart && cfra < pa->time)
+ if (facepa[i] != totpart && cfra < pa->time) {
mindex = totvert + totpart;
- else
+ }
+ else {
mindex = totvert + facepa[i];
+ }
source.v1 = edgecut_get(vertpahash, source.v1, mindex);
source.v2 = edgecut_get(vertpahash, source.v2, mindex);
source.v3 = edgecut_get(vertpahash, source.v3, mindex);
- if (source.v4)
+ if (source.v4) {
source.v4 = edgecut_get(vertpahash, source.v4, mindex);
+ }
- DM_copy_tessface_data(dm, explode, i, u, 1);
+ CustomData_copy_data(&mesh->fdata, &explode->fdata, i, u, 1);
*mf = source;
@@ -964,7 +1001,7 @@ static DerivedMesh *explodeMesh(
mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = 0.5f;
}
- test_index_face(mf, &explode->faceData, u, (orig_v4 ? 4 : 3));
+ test_index_face(mf, &explode->fdata, u, (orig_v4 ? 4 : 3));
u++;
}
@@ -972,9 +1009,9 @@ static DerivedMesh *explodeMesh(
BLI_edgehash_free(vertpahash, NULL);
/* finalization */
- CDDM_calc_edges_tessface(explode);
- CDDM_tessfaces_to_faces(explode);
- explode->dirty |= DM_DIRTY_NORMALS;
+ BKE_mesh_calc_edges_tessface(explode);
+ BKE_mesh_convert_mfaces_to_mpolys(explode);
+ explode->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
if (psmd->psys->lattice_deform_data) {
end_latt_deform(psmd->psys->lattice_deform_data);
@@ -990,61 +1027,67 @@ static ParticleSystemModifierData *findPrecedingParticlesystem(Object *ob, Modif
ParticleSystemModifierData *psmd = NULL;
for (md = ob->modifiers.first; emd != md; md = md->next) {
- if (md->type == eModifierType_ParticleSystem)
+ if (md->type == eModifierType_ParticleSystem) {
psmd = (ParticleSystemModifierData *) md;
+ }
}
return psmd;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
- DerivedMesh *dm = derivedData;
ExplodeModifierData *emd = (ExplodeModifierData *) md;
- ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ob, md);
+ ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ctx->object, md);
if (psmd) {
ParticleSystem *psys = psmd->psys;
- if (psys == NULL || psys->totpart == 0) return derivedData;
- if (psys->part == NULL || psys->particles == NULL) return derivedData;
- if (psmd->dm_final == NULL) return derivedData;
+ if (psys == NULL || psys->totpart == 0) {
+ return mesh;
+ }
+ if (psys->part == NULL || psys->particles == NULL) {
+ return mesh;
+ }
+ if (psmd->mesh_final == NULL) {
+ return mesh;
+ }
- DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+ BKE_mesh_tessface_ensure(mesh); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
/* 1. find faces to be exploded if needed */
if (emd->facepa == NULL ||
psmd->flag & eParticleSystemFlag_Pars ||
emd->flag & eExplodeFlag_CalcFaces ||
- MEM_allocN_len(emd->facepa) / sizeof(int) != dm->getNumTessFaces(dm))
+ MEM_allocN_len(emd->facepa) / sizeof(int) != mesh->totface)
{
- if (psmd->flag & eParticleSystemFlag_Pars)
+ if (psmd->flag & eParticleSystemFlag_Pars) {
psmd->flag &= ~eParticleSystemFlag_Pars;
-
- if (emd->flag & eExplodeFlag_CalcFaces)
+ }
+ if (emd->flag & eExplodeFlag_CalcFaces) {
emd->flag &= ~eExplodeFlag_CalcFaces;
-
- createFacepa(emd, psmd, derivedData);
+ }
+ createFacepa(emd, psmd, mesh);
}
/* 2. create new mesh */
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
if (emd->flag & eExplodeFlag_EdgeCut) {
int *facepa = emd->facepa;
- DerivedMesh *splitdm = cutEdges(emd, dm);
- DerivedMesh *explode = explodeMesh(emd, psmd, md->scene, ob, splitdm);
+ Mesh *split_m = cutEdges(emd, mesh);
+ Mesh *explode = explodeMesh(emd, psmd, ctx, scene, split_m);
MEM_freeN(emd->facepa);
emd->facepa = facepa;
- splitdm->release(splitdm);
+ BKE_id_free(NULL, split_m);
return explode;
}
- else
- return explodeMesh(emd, psmd, md->scene, ob, derivedData);
+ else {
+ return explodeMesh(emd, psmd, ctx, scene, mesh);
+ }
}
- return derivedData;
+ return mesh;
}
-
ModifierTypeInfo modifierType_Explode = {
/* name */ "Explode",
/* structName */ "ExplodeModifierData",
@@ -1052,17 +1095,23 @@ ModifierTypeInfo modifierType_Explode = {
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
index 00b7f245d4c..8b6f25ab0ab 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim.c
@@ -33,17 +33,16 @@
*/
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_fluidsim_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-
-#include "BKE_cdderivedmesh.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MOD_fluidsim_util.h"
@@ -65,70 +64,49 @@ static void freeData(ModifierData *md)
fluidsim_free(fluidmd);
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int UNUSED(flag))
{
const FluidsimModifierData *fluidmd = (const FluidsimModifierData *) md;
FluidsimModifierData *tfluidmd = (FluidsimModifierData *) target;
- if (fluidmd->fss) {
- tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
- if (tfluidmd->fss && (tfluidmd->fss->meshVelocities != NULL)) {
- tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
- }
+ /* Free any FSS that was allocated in initData() */
+ if (tfluidmd->fss) {
+ MEM_SAFE_FREE(tfluidmd->fss->meshVelocities);
+ MEM_freeN(tfluidmd->fss);
+ }
+
+ if (fluidmd->fss == NULL) {
+ tfluidmd->fss = NULL;
+ return;
}
- /* Seems to never be used, but for sqke of consistency... */
- BLI_assert(fluidmd->point_cache == NULL);
- BLI_assert(tfluidmd->point_cache == NULL);
- tfluidmd->point_cache = NULL;
+ tfluidmd->fss = MEM_dupallocN(fluidmd->fss);
+ if (tfluidmd->fss->meshVelocities != NULL) {
+ tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities);
+ }
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag flag)
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
- DerivedMesh *result = NULL;
+ Mesh *result = NULL;
/* check for alloc failing */
if (!fluidmd->fss) {
initData(md);
if (!fluidmd->fss) {
- return dm;
+ return mesh;
}
}
- result = fluidsimModifier_do(fluidmd, md->scene, ob, dm, flag & MOD_APPLY_RENDER, flag & MOD_APPLY_USECACHE);
+ result = fluidsimModifier_do(fluidmd, ctx, mesh);
- return result ? result : dm;
-}
-
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
- Base *base;
-
- if (fluidmd && fluidmd->fss) {
- if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
- for (base = ctx->scene->base.first; base; base = base->next) {
- Object *ob1 = base->object;
- if (ob1 != ctx->object) {
- FluidsimModifierData *fluidmdtmp =
- (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
-
- /* only put dependencies from NON-DOMAIN fluids in here */
- if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
- DagNode *curNode = dag_get_node(ctx->forest, ob1);
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Fluidsim Object");
- }
- }
- }
- }
- }
+ return result ? result : mesh;
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
@@ -136,9 +114,8 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
if (fluidmd && fluidmd->fss) {
if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
- Base *base;
- for (base = ctx->scene->base.first; base; base = base->next) {
- Object *ob1 = base->object;
+ FOREACH_SCENE_OBJECT_BEGIN(ctx->scene, ob1)
+ {
if (ob1 != ctx->object) {
FluidsimModifierData *fluidmdtmp =
(FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
@@ -149,6 +126,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
}
+ FOREACH_SCENE_OBJECT_END;
}
}
}
@@ -170,17 +148,23 @@ ModifierTypeInfo modifierType_Fluidsim = {
eModifierTypeFlag_Single,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c
index 8dd4e289503..23a62f88f77 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c
@@ -47,11 +47,15 @@
#include "BLI_utildefines.h"
#include "BKE_fluidsim.h" /* ensure definitions here match */
-#include "BKE_cdderivedmesh.h"
-#include "BKE_main.h"
#ifdef WITH_MOD_FLUID
# include "BKE_global.h"
#endif
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "MOD_fluidsim_util.h"
#include "MOD_modifiertypes.h"
@@ -157,22 +161,18 @@ void fluidsim_free(FluidsimModifierData *fluidmd)
MEM_SAFE_FREE(fluidmd->fss);
}
- /* Seems to never be used, but for sqke of consistency... */
- BLI_assert(fluidmd->point_cache == NULL);
- fluidmd->point_cache = NULL;
-
return;
}
#ifdef WITH_MOD_FLUID
-/* read .bobj.gz file into a fluidsimDerivedMesh struct */
-static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_example)
+/* read .bobj.gz file into a fluidsimMesh struct */
+static Mesh *fluidsim_read_obj(const char *filename, const MPoly *mp_example)
{
int wri = 0, i;
int gotBytes;
gzFile gzf;
int numverts = 0, numfaces = 0;
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
MPoly *mp;
MLoop *ml;
MVert *mv;
@@ -221,9 +221,9 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_exam
return NULL;
}
- dm = CDDM_new(numverts, 0, 0, numfaces * 3, numfaces);
+ mesh = BKE_mesh_new_nomain(numverts, 0, 0, numfaces * 3, numfaces);
- if (!dm) {
+ if (!mesh) {
gzclose(gzf);
return NULL;
}
@@ -232,7 +232,7 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_exam
gotBytes = gzread(gzf, &wri, sizeof(wri));
/* read vertex position from file */
- mv = CDDM_get_verts(dm);
+ mv = mesh->mvert;
for (i = 0; i < numverts; i++, mv++)
gotBytes = gzread(gzf, mv->co, sizeof(float) * 3);
@@ -240,16 +240,16 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_exam
/* should be the same as numverts */
gotBytes = gzread(gzf, &wri, sizeof(wri));
if (wri != numverts) {
- if (dm)
- dm->release(dm);
+ if (mesh)
+ BKE_id_free(NULL, mesh);
gzclose(gzf);
return NULL;
}
normals = MEM_calloc_arrayN(numverts, 3 * sizeof(short), "fluid_tmp_normals");
if (!normals) {
- if (dm)
- dm->release(dm);
+ if (mesh)
+ BKE_id_free(NULL, mesh);
gzclose(gzf);
return NULL;
}
@@ -265,16 +265,16 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_exam
if (wri != numfaces) {
printf("Fluidsim: error in reading data from file.\n");
- if (dm)
- dm->release(dm);
+ if (mesh)
+ BKE_id_free(NULL, mesh);
gzclose(gzf);
MEM_freeN(normals);
return NULL;
}
/* read triangles from file */
- mp = CDDM_get_polys(dm);
- ml = CDDM_get_loops(dm);
+ mp = mesh->mpoly;
+ ml = mesh->mloop;
for (i = 0; i < numfaces; i++, mp++, ml += 3) {
int face[3];
@@ -295,13 +295,12 @@ static DerivedMesh *fluidsim_read_obj(const char *filename, const MPoly *mp_exam
gzclose(gzf);
- CDDM_calc_edges(dm);
-
- CDDM_apply_vert_normals(dm, (short (*)[3])normals);
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_apply_vert_normals(mesh, (short (*)[3])normals);
MEM_freeN(normals);
// CDDM_calc_normals(result);
- return dm;
+ return mesh;
}
@@ -371,14 +370,14 @@ void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value)
/* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
-static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *dm, char *filename)
+static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, Mesh *mesh, char *filename)
{
int wri, i, j;
float wrf;
gzFile gzf;
FluidsimSettings *fss = fluidmd->fss;
int len = strlen(filename);
- int totvert = dm->getNumVerts(dm);
+ int totvert = mesh->totvert;
FluidVertexVelocity *velarray = NULL;
/* mesh and vverts have to be valid from loading... */
@@ -392,7 +391,7 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *
if (fss->domainNovecgen > 0) return;
- fss->meshVelocities = MEM_calloc_arrayN(dm->getNumVerts(dm), sizeof(FluidVertexVelocity), "Fluidsim_velocities");
+ fss->meshVelocities = MEM_calloc_arrayN(mesh->totvert, sizeof(FluidVertexVelocity), "Fluidsim_velocities");
fss->totvert = totvert;
velarray = fss->meshVelocities;
@@ -427,8 +426,8 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *
gzclose(gzf);
}
-static DerivedMesh *fluidsim_read_cache(
- Object *ob, DerivedMesh *orgdm,
+static Mesh *fluidsim_read_cache(
+ Object *ob, Mesh *orgmesh,
FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
{
int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */
@@ -437,7 +436,7 @@ static DerivedMesh *fluidsim_read_cache(
char targetFile[FILE_MAX];
FluidsimSettings *fss = fluidmd->fss;
- DerivedMesh *dm = NULL;
+ Mesh *newmesh = NULL;
MPoly *mpoly;
MPoly mp_example = {0};
@@ -466,17 +465,17 @@ static DerivedMesh *fluidsim_read_cache(
BLI_path_abs(targetFile, modifier_path_relbase_from_global(ob));
BLI_path_frame(targetFile, curFrame, 0); // fixed #frame-no
- /* assign material + flags to new dm
- * if there's no faces in original dm, keep materials and flags unchanged */
- mpoly = orgdm->getPolyArray(orgdm);
+ /* assign material + flags to new mesh.
+ * if there's no faces in original mesh, keep materials and flags unchanged */
+ mpoly = orgmesh->mpoly;
if (mpoly) {
mp_example = *mpoly;
}
/* else leave NULL'd */
- dm = fluidsim_read_obj(targetFile, &mp_example);
+ newmesh = fluidsim_read_obj(targetFile, &mp_example);
- if (!dm) {
+ if (!newmesh) {
/* switch, abort background rendering when fluidsim mesh is missing */
const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
@@ -491,7 +490,7 @@ static DerivedMesh *fluidsim_read_cache(
}
}
- /* display org. object upon failure which is in dm */
+ /* display org. object upon failure which is in new mesh */
return NULL;
}
@@ -499,7 +498,7 @@ static DerivedMesh *fluidsim_read_cache(
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */
if (displaymode == OB_FSDOM_FINAL) {
- fluidsim_read_vel_cache(fluidmd, dm, targetFile);
+ fluidsim_read_vel_cache(fluidmd, newmesh, targetFile);
}
else {
if (fss->meshVelocities)
@@ -508,30 +507,33 @@ static DerivedMesh *fluidsim_read_cache(
fss->meshVelocities = NULL;
}
- return dm;
+ return newmesh;
}
#endif // WITH_MOD_FLUID
-DerivedMesh *fluidsimModifier_do(
- FluidsimModifierData *fluidmd, Scene *scene,
- Object *ob,
- DerivedMesh *dm,
- int useRenderParams, int UNUSED(isFinalCalc))
+Mesh *fluidsimModifier_do(
+ FluidsimModifierData *fluidmd,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
#ifdef WITH_MOD_FLUID
- DerivedMesh *result = NULL;
+ Object *ob = ctx->object;
+ Depsgraph *depsgraph = ctx->depsgraph;
+ const bool useRenderParams = (ctx->flag & MOD_APPLY_RENDER) != 0;
+// const bool isFinalCalc = (ctx->flag & MOD_APPLY_USECACHE) != 0;
+ Mesh *result = NULL;
int framenr;
FluidsimSettings *fss = NULL;
- framenr = (int)scene->r.cfra;
+ framenr = (int)DEG_get_ctime(depsgraph);
/* only handle fluidsim domains */
if (fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
- return dm;
+ return mesh;
/* sanity check */
if (!fluidmd || !fluidmd->fss)
- return dm;
+ return mesh;
fss = fluidmd->fss;
@@ -546,17 +548,13 @@ DerivedMesh *fluidsimModifier_do(
/* try to read from cache */
/* if the frame is there, fine, otherwise don't do anything */
- if ((result = fluidsim_read_cache(ob, dm, fluidmd, framenr, useRenderParams)))
+ if ((result = fluidsim_read_cache(ob, mesh, fluidmd, framenr, useRenderParams)))
return result;
- return dm;
+ return mesh;
#else
/* unused */
- (void)fluidmd;
- (void)scene;
- (void)ob;
- (void)dm;
- (void)useRenderParams;
+ UNUSED_VARS(fluidmd, ctx, mesh);
return NULL;
#endif
}
diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.h b/source/blender/modifiers/intern/MOD_fluidsim_util.h
index 2bb1da32718..4bb745fbd66 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim_util.h
+++ b/source/blender/modifiers/intern/MOD_fluidsim_util.h
@@ -36,15 +36,16 @@
struct Object;
struct Scene;
struct FluidsimModifierData;
-struct DerivedMesh;
+struct Mesh;
+struct ModifierEvalContext;
/* new fluid-modifier interface */
void fluidsim_init(struct FluidsimModifierData *fluidmd);
void fluidsim_free(struct FluidsimModifierData *fluidmd);
-struct DerivedMesh *fluidsimModifier_do(
+struct Mesh *fluidsimModifier_do(
struct FluidsimModifierData *fluidmd,
- struct Scene *scene, struct Object *ob, struct DerivedMesh *dm,
- int useRenderParams, int isFinalCalc);
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *me);
#endif
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 5bbcaee2caa..9d893630b94 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -33,6 +33,7 @@
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -40,14 +41,14 @@
#include "BLI_utildefines.h"
#include "BKE_action.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_colortools.h"
-
-#include "depsgraph_private.h"
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
@@ -62,12 +63,12 @@ static void initData(ModifierData *md)
hmd->flag = 0;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const HookModifierData *hmd = (const HookModifierData *) md;
HookModifierData *thmd = (HookModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
thmd->curfalloff = curvemapping_copy(hmd->curfalloff);
@@ -95,7 +96,7 @@ static void freeData(ModifierData *md)
MEM_SAFE_FREE(hmd->indexar);
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
HookModifierData *hmd = (HookModifierData *) md;
@@ -111,20 +112,6 @@ static void foreachObjectLink(
walk(userData, ob, &hmd->object, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- HookModifierData *hmd = (HookModifierData *) md;
-
- if (hmd->object) {
- DagNode *curNode = dag_get_node(ctx->forest, hmd->object);
-
- if (hmd->subtarget[0])
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Hook Modifier");
- else
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_OB_DATA, "Hook Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
HookModifierData *hmd = (HookModifierData *)md;
@@ -265,7 +252,7 @@ static void hook_co_apply(struct HookData_cb *hd, const int j)
}
static void deformVerts_do(
- HookModifierData *hmd, Object *ob, DerivedMesh *dm,
+ HookModifierData *hmd, Object *ob, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
@@ -284,7 +271,7 @@ static void deformVerts_do(
/* Generic data needed for applying per-vertex calculations (initialize all members) */
hd.vertexCos = vertexCos;
- modifier_get_vgroup(ob, dm, hmd->name, &hd.dvert, &hd.defgrp_index);
+ MOD_get_vgroup(ob, mesh, hmd->name, &hd.dvert, &hd.defgrp_index);
hd.curfalloff = hmd->curfalloff;
@@ -333,8 +320,8 @@ static void deformVerts_do(
else if (hmd->indexar) { /* vertex indices? */
const int *origindex_ar;
- /* if DerivedMesh is present and has original index data, use it */
- if (dm && (origindex_ar = dm->getVertDataArray(dm, CD_ORIGINDEX))) {
+ /* if mesh is present and has original index data, use it */
+ if (mesh && (origindex_ar = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))) {
for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) {
if (*index_pt < numVerts) {
int j;
@@ -347,7 +334,7 @@ static void deformVerts_do(
}
}
}
- else { /* missing dm or ORIGINDEX */
+ else { /* missing mesh or ORIGINDEX */
for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) {
if (*index_pt < numVerts) {
hook_co_apply(&hd, *index_pt);
@@ -363,39 +350,34 @@ static void deformVerts_do(
}
static void deformVerts(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ struct ModifierData *md, const struct ModifierEvalContext *ctx, struct Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
{
- HookModifierData *hmd = (HookModifierData *) md;
- DerivedMesh *dm = derivedData;
- /* We need a valid dm for meshes when a vgroup is set... */
- if (!dm && ob->type == OB_MESH && hmd->name[0] != '\0')
- dm = get_dm(ob, NULL, dm, NULL, false, false);
+ HookModifierData *hmd = (HookModifierData *)md;
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
- deformVerts_do(hmd, ob, dm, vertexCos, numVerts);
+ deformVerts_do(hmd, ctx->object, mesh_src, vertexCos, numVerts);
- if (derivedData != dm)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ struct Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- HookModifierData *hmd = (HookModifierData *) md;
- DerivedMesh *dm = derivedData;
- /* We need a valid dm for meshes when a vgroup is set... */
- if (!dm && ob->type == OB_MESH && hmd->name[0] != '\0')
- dm = get_dm(ob, editData, dm, NULL, false, false);
+ HookModifierData *hmd = (HookModifierData *)md;
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
- deformVerts_do(hmd, ob, dm, vertexCos, numVerts);
+ deformVerts_do(hmd, ctx->object, mesh_src, vertexCos, numVerts);
- if (derivedData != dm)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
-
ModifierTypeInfo modifierType_Hook = {
/* name */ "Hook",
/* structName */ "HookModifierData",
@@ -405,17 +387,23 @@ ModifierTypeInfo modifierType_Hook = {
eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index 6f963b7f1a4..ba45e6bf848 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -35,10 +35,15 @@
#include "MEM_guardedalloc.h"
+#include "BKE_deform.h"
+#include "BKE_editmesh.h"
+#include "BKE_library.h"
#include "BKE_mesh_mapping.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_particle.h"
-#include "BKE_deform.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "MOD_util.h"
@@ -499,18 +504,18 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
}
}
-static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm)
+static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh)
{
int defgrp_index;
MDeformVert *dvert = NULL;
- modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
return (dvert != NULL);
}
static void initSystem(
- LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm,
+ LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
int i;
@@ -521,7 +526,7 @@ static void initSystem(
MDeformVert *dv = NULL;
LaplacianSystem *sys;
- if (isValidVertexGroup(lmd, ob, dm)) {
+ if (isValidVertexGroup(lmd, ob, mesh)) {
int *index_anchors = MEM_malloc_arrayN(numVerts, sizeof(int), __func__); /* over-alloc */
const MLoopTri *mlooptri;
const MLoop *mloop;
@@ -530,7 +535,7 @@ static void initSystem(
STACK_INIT(index_anchors, numVerts);
- modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
BLI_assert(dvert != NULL);
dv = dvert;
for (i = 0; i < numVerts; i++) {
@@ -542,8 +547,8 @@ static void initSystem(
}
total_anchors = STACK_SIZE(index_anchors);
- lmd->cache_system = initLaplacianSystem(numVerts, dm->getNumEdges(dm), dm->getNumLoopTri(dm),
- total_anchors, lmd->anchor_grp_name, lmd->repeat);
+ lmd->cache_system = initLaplacianSystem(numVerts, mesh->totedge, BKE_mesh_runtime_looptri_len(mesh),
+ total_anchors, lmd->anchor_grp_name, lmd->repeat);
sys = (LaplacianSystem *)lmd->cache_system;
memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors);
memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts);
@@ -553,15 +558,15 @@ static void initSystem(
lmd->total_verts = numVerts;
createFaceRingMap(
- dm->getNumVerts(dm), dm->getLoopTriArray(dm), dm->getNumLoopTri(dm),
- dm->getLoopArray(dm), &sys->ringf_map, &sys->ringf_indices);
+ mesh->totvert, BKE_mesh_runtime_looptri_ensure(mesh), BKE_mesh_runtime_looptri_len(mesh),
+ mesh->mloop, &sys->ringf_map, &sys->ringf_indices);
createVertRingMap(
- dm->getNumVerts(dm), dm->getEdgeArray(dm), dm->getNumEdges(dm),
+ mesh->totvert, mesh->medge, mesh->totedge,
&sys->ringv_map, &sys->ringv_indices);
- mlooptri = dm->getLoopTriArray(dm);
- mloop = dm->getLoopArray(dm);
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ mloop = mesh->mloop;
for (i = 0; i < sys->total_tris; i++) {
sys->tris[i][0] = mloop[mlooptri[i].tri[0]].v;
@@ -571,7 +576,7 @@ static void initSystem(
}
}
-static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm, int numVerts)
+static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, int numVerts)
{
int i;
int defgrp_index;
@@ -584,13 +589,13 @@ static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, Deriv
if (sys->total_verts != numVerts) {
return LAPDEFORM_SYSTEM_CHANGE_VERTEXES;
}
- if (sys->total_edges != dm->getNumEdges(dm)) {
+ if (sys->total_edges != mesh->totedge) {
return LAPDEFORM_SYSTEM_CHANGE_EDGES;
}
if (!STREQ(lmd->anchor_grp_name, sys->anchor_grp_name)) {
return LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP;
}
- modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
if (!dvert) {
return LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP;
}
@@ -610,7 +615,7 @@ static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, Deriv
}
static void LaplacianDeformModifier_do(
- LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm,
+ LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
float (*filevertexCos)[3];
@@ -628,7 +633,7 @@ static void LaplacianDeformModifier_do(
return;
}
if (lmd->cache_system) {
- sysdif = isSystemDifferent(lmd, ob, dm, numVerts);
+ sysdif = isSystemDifferent(lmd, ob, mesh, numVerts);
sys = lmd->cache_system;
if (sysdif) {
if (sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS || sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP) {
@@ -638,7 +643,7 @@ static void LaplacianDeformModifier_do(
lmd->total_verts = 0;
deleteLaplacianSystem(sys);
lmd->cache_system = NULL;
- initSystem(lmd, ob, dm, filevertexCos, numVerts);
+ initSystem(lmd, ob, mesh, filevertexCos, numVerts);
sys = lmd->cache_system; /* may have been reallocated */
MEM_SAFE_FREE(filevertexCos);
if (sys) {
@@ -650,7 +655,7 @@ static void LaplacianDeformModifier_do(
modifier_setError(&lmd->modifier, "Vertices changed from %d to %d", lmd->total_verts, numVerts);
}
else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_EDGES) {
- modifier_setError(&lmd->modifier, "Edges changed from %d to %d", sys->total_edges, dm->getNumEdges(dm));
+ modifier_setError(&lmd->modifier, "Edges changed from %d to %d", sys->total_edges, mesh->totedge);
}
else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP) {
modifier_setError(&lmd->modifier, "Vertex group '%s' is not valid", sys->anchor_grp_name);
@@ -663,7 +668,7 @@ static void LaplacianDeformModifier_do(
}
}
else {
- if (!isValidVertexGroup(lmd, ob, dm)) {
+ if (!isValidVertexGroup(lmd, ob, mesh)) {
modifier_setError(&lmd->modifier, "Vertex group '%s' is not valid", lmd->anchor_grp_name);
lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND;
}
@@ -672,13 +677,13 @@ static void LaplacianDeformModifier_do(
memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
MEM_SAFE_FREE(lmd->vertexco);
lmd->total_verts = 0;
- initSystem(lmd, ob, dm, filevertexCos, numVerts);
+ initSystem(lmd, ob, mesh, filevertexCos, numVerts);
sys = lmd->cache_system;
MEM_SAFE_FREE(filevertexCos);
laplacianDeformPreview(sys, vertexCos);
}
else {
- initSystem(lmd, ob, dm, vertexCos, numVerts);
+ initSystem(lmd, ob, mesh, vertexCos, numVerts);
sys = lmd->cache_system;
laplacianDeformPreview(sys, vertexCos);
}
@@ -699,18 +704,18 @@ static void initData(ModifierData *md)
lmd->flag = 0;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const LaplacianDeformModifierData *lmd = (const LaplacianDeformModifierData *)md;
LaplacianDeformModifierData *tlmd = (LaplacianDeformModifierData *)target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
tlmd->vertexco = MEM_dupallocN(lmd->vertexco);
tlmd->cache_system = NULL;
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
if (lmd->anchor_grp_name[0]) return 0;
@@ -726,26 +731,29 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
}
static void deformVerts(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+ ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
+
+ LaplacianDeformModifier_do((LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);
- LaplacianDeformModifier_do((LaplacianDeformModifierData *)md, ob, dm, vertexCos, numVerts);
- if (dm != derivedData) {
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
}
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, false, false);
- LaplacianDeformModifier_do((LaplacianDeformModifierData *)md, ob, dm,
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
+
+ LaplacianDeformModifier_do((LaplacianDeformModifierData *)md, ctx->object, mesh_src,
vertexCos, numVerts);
- if (dm != derivedData) {
- dm->release(dm);
+
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
}
}
@@ -767,17 +775,23 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 7d26e76832d..1acec1d8b7a 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -29,6 +29,7 @@
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -37,8 +38,10 @@
#include "MEM_guardedalloc.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
+#include "BKE_editmesh.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "MOD_util.h"
@@ -78,7 +81,7 @@ struct BLaplacianSystem {
typedef struct BLaplacianSystem LaplacianSystem;
static CustomDataMask required_data_mask(Object *ob, ModifierData *md);
-static bool is_disabled(ModifierData *md, int useRenderParams);
+static bool is_disabled(const struct Scene *UNUSED(scene), ModifierData *md, bool useRenderParams);
static float compute_volume(const float center[3], float (*vertexCos)[3], const MPoly *mpoly, int numPolys, const MLoop *mloop);
static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numPolys, int a_numLoops, int a_numVerts);
static void delete_laplacian_system(LaplacianSystem *sys);
@@ -330,7 +333,7 @@ static void validate_solution(LaplacianSystem *sys, short flag, float lambda, fl
{
int i;
float lam;
- float vini, vend;
+ float vini = 0.0f, vend = 0.0f;
if (flag & MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME) {
vini = compute_volume(sys->vert_centroid, sys->vertexCos, sys->mpoly, sys->numPolys, sys->mloop);
@@ -356,7 +359,7 @@ static void validate_solution(LaplacianSystem *sys, short flag, float lambda, fl
}
static void laplaciansmoothModifier_do(
- LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm,
+ LaplacianSmoothModifierData *smd, Object *ob, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
LaplacianSystem *sys;
@@ -366,17 +369,17 @@ static void laplaciansmoothModifier_do(
int i, iter;
int defgrp_index;
- sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm), numVerts);
+ sys = init_laplacian_system(mesh->totedge, mesh->totpoly, mesh->totloop, numVerts);
if (!sys) {
return;
}
- sys->mpoly = dm->getPolyArray(dm);
- sys->mloop = dm->getLoopArray(dm);
- sys->medges = dm->getEdgeArray(dm);
+ sys->mpoly = mesh->mpoly;
+ sys->mloop = mesh->mloop;
+ sys->medges = mesh->medge;
sys->vertexCos = vertexCos;
sys->min_area = 0.00001f;
- modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
sys->vert_centroid[0] = 0.0f;
sys->vert_centroid[1] = 0.0f;
@@ -471,7 +474,7 @@ static void init_data(ModifierData *md)
smd->defgrp_name[0] = '\0';
}
-static bool is_disabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool is_disabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md;
short flag;
@@ -496,39 +499,41 @@ static CustomDataMask required_data_mask(Object *UNUSED(ob), ModifierData *md)
}
static void deformVerts(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+ ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm;
+ Mesh *mesh_src;
if (numVerts == 0)
return;
- dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
- laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ob, dm,
+ laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ctx->object, mesh_src,
vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm;
+ Mesh *mesh_src;
if (numVerts == 0)
return;
- dm = get_dm(ob, editData, derivedData, NULL, false, false);
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
- laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ob, dm,
+ laplaciansmoothModifier_do((LaplacianSmoothModifierData *)md, ctx->object, mesh_src,
vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -540,18 +545,24 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_SupportsEditmode,
- /* copy_data */ modifier_copyData_generic,
+ /* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ init_data,
/* requiredDataMask */ required_data_mask,
/* freeData */ NULL,
/* isDisabled */ is_disabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 760e3c0e22a..c183f54098c 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -39,12 +39,14 @@
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
+#include "MEM_guardedalloc.h"
#include "MOD_util.h"
@@ -65,7 +67,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
-static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams))
{
LatticeModifierData *lmd = (LatticeModifierData *) md;
@@ -81,18 +83,6 @@ static void foreachObjectLink(
walk(userData, ob, &lmd->object, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- LatticeModifierData *lmd = (LatticeModifierData *) md;
-
- if (lmd->object) {
- DagNode *latNode = dag_get_node(ctx->forest, lmd->object);
-
- dag_add_relation(ctx->forest, latNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Lattice Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
LatticeModifierData *lmd = (LatticeModifierData *)md;
@@ -104,32 +94,35 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
LatticeModifierData *lmd = (LatticeModifierData *) md;
+ struct Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
+ MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */
- modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
-
- lattice_deform_verts(lmd->object, ob, derivedData,
+ lattice_deform_verts(lmd->object, ctx->object, mesh_src,
vertexCos, numVerts, lmd->name, lmd->strength);
+
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *em,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em,
+ struct Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = derivedData;
+ struct Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
- if (!derivedData) dm = CDDM_from_editbmesh(em, false, false);
+ deformVerts(md, ctx, mesh_src, vertexCos, numVerts);
- deformVerts(md, ob, dm, vertexCos, numVerts, 0);
-
- if (!derivedData) dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -141,18 +134,25 @@ ModifierTypeInfo modifierType_Lattice = {
/* flags */ eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
+
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 75b2352ab2e..7c43545a3d3 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -40,17 +40,19 @@
#include "BLI_ghash.h"
#include "DNA_armature_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_action.h" /* BKE_pose_channel_find_name */
-#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MOD_modifiertypes.h"
@@ -70,20 +72,6 @@ static void foreachObjectLink(
walk(userData, ob, &mmd->ob_arm, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- MaskModifierData *mmd = (MaskModifierData *)md;
-
- if (mmd->ob_arm) {
- bArmature *arm = (bArmature *)mmd->ob_arm->data;
- DagNode *armNode = dag_get_node(ctx->forest, mmd->ob_arm);
-
- /* tag relationship in depsgraph, but also on the armature */
- dag_add_relation(ctx->forest, armNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Mask Modifier");
- arm->flag |= ARM_HAS_VIZ_DEPS;
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MaskModifierData *mmd = (MaskModifierData *)md;
@@ -93,17 +81,16 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
/* TODO(sergey): Is it a proper relation here? */
DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
arm->flag |= ARM_HAS_VIZ_DEPS;
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
}
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
MaskModifierData *mmd = (MaskModifierData *)md;
+ Object *ob = ctx->object;
const bool found_test = (mmd->flag & MOD_MASK_INV) == 0;
- DerivedMesh *result = NULL;
+ Mesh *result = NULL;
GHash *vertHash = NULL, *edgeHash, *polyHash;
GHashIterator gh_iter;
MDeformVert *dvert, *dv;
@@ -123,9 +110,9 @@ static DerivedMesh *applyModifier(
int *loop_mapping;
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
if (dvert == NULL) {
- return found_test ? CDDM_from_template(dm, 0, 0, 0, 0, 0) : dm;
+ return found_test ? BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0) : mesh;
}
/* Overview of Method:
@@ -135,9 +122,9 @@ static DerivedMesh *applyModifier(
*/
/* get original number of verts, edges, and faces */
- maxVerts = dm->getNumVerts(dm);
- maxEdges = dm->getNumEdges(dm);
- maxPolys = dm->getNumPolys(dm);
+ maxVerts = mesh->totvert;
+ maxEdges = mesh->totedge;
+ maxPolys = mesh->totpoly;
/* check if we can just return the original mesh
* - must have verts and therefore verts assigned to vgroups to do anything useful
@@ -145,7 +132,7 @@ static DerivedMesh *applyModifier(
if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) ||
(maxVerts == 0) || BLI_listbase_is_empty(&ob->defbase))
{
- return dm;
+ return mesh;
}
/* if mode is to use selected armature bones, aggregate the bone groups */
@@ -158,8 +145,9 @@ static DerivedMesh *applyModifier(
const int defbase_tot = BLI_listbase_count(&ob->defbase);
/* check that there is armature object with bones to use, otherwise return original mesh */
- if (ELEM(NULL, oba, oba->pose, ob->defbase.first))
- return dm;
+ if (ELEM(NULL, oba, oba->pose, ob->defbase.first)) {
+ return mesh;
+ }
/* determine whether each vertexgroup is associated with a selected bone or not
* - each cell is a boolean saying whether bone corresponding to the ith group is selected
@@ -220,8 +208,9 @@ static DerivedMesh *applyModifier(
int defgrp_index = defgroup_name_index(ob, mmd->vgroup);
/* if no vgroup (i.e. dverts) found, return the initial mesh */
- if (defgrp_index == -1)
- return dm;
+ if (defgrp_index == -1) {
+ return mesh;
+ }
/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts);
@@ -243,10 +232,10 @@ static DerivedMesh *applyModifier(
edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges);
polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys);
- mvert_src = dm->getVertArray(dm);
- medge_src = dm->getEdgeArray(dm);
- mpoly_src = dm->getPolyArray(dm);
- mloop_src = dm->getLoopArray(dm);
+ mvert_src = mesh->mvert;
+ medge_src = mesh->medge;
+ mpoly_src = mesh->mpoly;
+ mloop_src = mesh->mloop;
/* overalloc, assume all polys are seen */
loop_mapping = MEM_malloc_arrayN((size_t)maxPolys, sizeof(int), "mask loopmap");
@@ -291,12 +280,12 @@ static DerivedMesh *applyModifier(
/* now we know the number of verts, edges and faces,
* we can create the new (reduced) mesh
*/
- result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys);
+ result = BKE_mesh_new_nomain_from_template(mesh, numVerts, numEdges, 0, numLoops, numPolys);
- mpoly_dst = CDDM_get_polys(result);
- mloop_dst = CDDM_get_loops(result);
- medge_dst = CDDM_get_edges(result);
- mvert_dst = CDDM_get_verts(result);
+ mpoly_dst = result->mpoly;
+ mloop_dst = result->mloop;
+ medge_dst = result->medge;
+ mvert_dst = result->mvert;
/* using ghash-iterators, map data into new mesh */
/* vertices */
@@ -310,7 +299,7 @@ static DerivedMesh *applyModifier(
v_dst = &mvert_dst[i_dst];
*v_dst = *v_src;
- DM_copy_vert_data(dm, result, i_src, i_dst, 1);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, i_src, i_dst, 1);
}
/* edges */
@@ -323,7 +312,7 @@ static DerivedMesh *applyModifier(
e_src = &medge_src[i_src];
e_dst = &medge_dst[i_dst];
- DM_copy_edge_data(dm, result, i_src, i_dst, 1);
+ CustomData_copy_data(&mesh->edata, &result->edata, i_src, i_dst, 1);
*e_dst = *e_src;
e_dst->v1 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(e_src->v1)));
e_dst->v2 = POINTER_AS_UINT(BLI_ghash_lookup(vertHash, POINTER_FROM_UINT(e_src->v2)));
@@ -340,8 +329,8 @@ static DerivedMesh *applyModifier(
const MLoop *ml_src = &mloop_src[i_ml_src];
MLoop *ml_dst = &mloop_dst[i_ml_dst];
- DM_copy_poly_data(dm, result, i_src, i_dst, 1);
- DM_copy_loop_data(dm, result, i_ml_src, i_ml_dst, mp_src->totloop);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, i_src, i_dst, 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, i_ml_src, i_ml_dst, mp_src->totloop);
*mp_dst = *mp_src;
mp_dst->loopstart = i_ml_dst;
@@ -355,7 +344,7 @@ static DerivedMesh *applyModifier(
/* why is this needed? - campbell */
/* recalculate normals */
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
/* free hashes */
BLI_ghash_free(vertHash, NULL, NULL);
@@ -377,17 +366,23 @@ ModifierTypeInfo modifierType_Mask = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ NULL,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index a1523b33a68..e3aa239a713 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -36,11 +36,13 @@
#include "BLI_path_util.h"
#include "BLI_math.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_scene.h"
#include "BKE_global.h"
-#include "BKE_mesh.h"
+#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
#include "MEM_guardedalloc.h"
@@ -70,7 +72,7 @@ static bool dependsOnTime(ModifierData *md)
return (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA);
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
MeshCacheModifierData *mcmd = (MeshCacheModifierData *) md;
@@ -80,7 +82,7 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
static void meshcache_do(
- MeshCacheModifierData *mcmd, Object *ob, DerivedMesh *UNUSED(dm),
+ MeshCacheModifierData *mcmd, Scene *scene, Object *ob,
float (*vertexCos_Real)[3], int numVerts)
{
const bool use_factor = mcmd->factor < 1.0f;
@@ -88,7 +90,6 @@ static void meshcache_do(
MEM_malloc_arrayN(numVerts, sizeof(*vertexCos_Store), __func__) : NULL;
float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real;
- Scene *scene = mcmd->modifier.scene;
const float fps = FPS;
char filepath[FILE_MAX];
@@ -264,24 +265,28 @@ static void meshcache_do(
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *UNUSED(mesh),
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
- meshcache_do(mcmd, ob, derivedData, vertexCos, numVerts);
+ meshcache_do(mcmd, scene, ctx->object, vertexCos, numVerts);
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *UNUSED(editData),
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *UNUSED(editData),
+ Mesh *UNUSED(mesh),
+ float (*vertexCos)[3],
+ int numVerts)
{
MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
- meshcache_do(mcmd, ob, derivedData, vertexCos, numVerts);
+ meshcache_do(mcmd, scene, ctx->object, vertexCos, numVerts);
}
@@ -295,17 +300,23 @@ ModifierTypeInfo modifierType_MeshCache = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 39a6e9029b4..9af76916788 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -32,6 +32,7 @@
* \ingroup modifiers
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -40,17 +41,19 @@
#include "BLI_task.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
-#include "depsgraph_private.h"
-
#include "MEM_guardedalloc.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_util.h"
#ifdef __SSE2__
@@ -78,12 +81,12 @@ static void freeData(ModifierData *md)
if (mmd->bindcos) MEM_freeN(mmd->bindcos); /* deprecated */
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const MeshDeformModifierData *mmd = (const MeshDeformModifierData *) md;
MeshDeformModifierData *tmmd = (MeshDeformModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
if (mmd->bindinfluences) tmmd->bindinfluences = MEM_dupallocN(mmd->bindinfluences);
if (mmd->bindoffsets) tmmd->bindoffsets = MEM_dupallocN(mmd->bindoffsets);
@@ -106,7 +109,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
@@ -122,19 +125,6 @@ static void foreachObjectLink(
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
-
- if (mmd->object) {
- DagNode *curNode = dag_get_node(ctx->forest, mmd->object);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_OB_OB,
- "Mesh Deform Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
@@ -236,8 +226,8 @@ static void meshdeform_vert_task(
const MDeformVert *dvert = data->dvert;
const int defgrp_index = data->defgrp_index;
const int *offsets = mmd->bindoffsets;
- const MDefInfluence *influences = mmd->bindinfluences;
- /*const*/ float (*dco)[3] = data->dco;
+ const MDefInfluence *__restrict influences = mmd->bindinfluences;
+ /*const*/ float (*__restrict dco)[3] = data->dco;
float (*vertexCos)[3] = data->vertexCos;
float co[3];
float weight, totweight, fac = 1.0f;
@@ -264,11 +254,12 @@ static void meshdeform_vert_task(
totweight = meshdeform_dynamic_bind(mmd, dco, co);
}
else {
- int a;
totweight = 0.0f;
zero_v3(co);
+ int start = offsets[iter];
+ int end = offsets[iter + 1];
- for (a = offsets[iter]; a < offsets[iter + 1]; a++) {
+ for (int a = start; a < end; a++) {
weight = influences[a].weight;
madd_v3_v3fl(co, dco[influences[a].vertex], weight);
totweight += weight;
@@ -286,49 +277,37 @@ static void meshdeform_vert_task(
}
static void meshdeformModifier_do(
- ModifierData *md, Object *ob, DerivedMesh *dm,
+ ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
- DerivedMesh *tmpdm, *cagedm;
+ Object *ob = ctx->object;
+
+ Mesh *cagemesh;
MDeformVert *dvert = NULL;
float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4];
float co[3], (*dco)[3], (*bindcagecos)[3];
int a, totvert, totcagevert, defgrp_index;
float (*cagecos)[3];
MeshdeformUserdata data;
+ bool free_cagemesh = false;
if (!mmd->object || (!mmd->bindcagecos && !mmd->bindfunc))
return;
- /* Get cage derivedmesh.
+ /* Get cage mesh.
*
* Only do this is the target object is in edit mode by itself, meaning
* we don't allow linked edit meshes here.
- * This is because editbmesh_get_derived_cage_and_final() might easily
+ * This is because editbmesh_get_mesh_cage_and_final() might easily
* conflict with the thread which evaluates object which is in the edit
* mode for this mesh.
*
* We'll support this case once granular dependency graph is landed.
*/
- if (mmd->object == md->scene->obedit) {
- BMEditMesh *em = BKE_editmesh_from_object(mmd->object);
- tmpdm = editbmesh_get_derived_cage_and_final(md->scene, mmd->object, em, 0, &cagedm);
- if (tmpdm)
- tmpdm->release(tmpdm);
- }
- else
- cagedm = mmd->object->derivedFinal;
-
- /* if we don't have one computed, use derivedmesh from data
- * without any modifiers */
- if (!cagedm) {
- cagedm = get_dm(mmd->object, NULL, NULL, NULL, false, false);
- if (cagedm)
- cagedm->needsFree = 1;
- }
+ cagemesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(mmd->object, &free_cagemesh);
- if (!cagedm) {
+ if (cagemesh == NULL) {
modifier_setError(md, "Cannot get mesh from cage object");
return;
}
@@ -346,36 +325,42 @@ static void meshdeformModifier_do(
/* progress bar redraw can make this recursive .. */
if (!recursive) {
+ /* Write binding data to original modifier. */
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ Object *ob_orig = DEG_get_original_object(ob);
+ MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)modifiers_findByName(
+ ob_orig, mmd->modifier.name);
+
recursive = 1;
- mmd->bindfunc(md->scene, mmd, cagedm, (float *)vertexCos, numVerts, cagemat);
+ mmd->bindfunc(scene, mmd_orig, cagemesh, (float *)vertexCos, numVerts, cagemat);
recursive = 0;
}
+
+ return;
}
/* verify we have compatible weights */
totvert = numVerts;
- totcagevert = cagedm->getNumVerts(cagedm);
+ totcagevert = cagemesh->totvert;
if (mmd->totvert != totvert) {
modifier_setError(md, "Verts changed from %d to %d", mmd->totvert, totvert);
- cagedm->release(cagedm);
+ if (free_cagemesh) BKE_id_free(NULL, cagemesh);
return;
}
else if (mmd->totcagevert != totcagevert) {
modifier_setError(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert);
- cagedm->release(cagedm);
+ if (free_cagemesh) BKE_id_free(NULL, cagemesh);
return;
}
else if (mmd->bindcagecos == NULL) {
modifier_setError(md, "Bind data missing");
- cagedm->release(cagedm);
+ if (free_cagemesh) BKE_id_free(NULL, cagemesh);
return;
}
- cagecos = MEM_malloc_arrayN(totcagevert, sizeof(*cagecos), "meshdeformModifier vertCos");
-
/* setup deformation data */
- cagedm->getVertCos(cagedm, cagecos);
+ cagecos = BKE_mesh_vertexCos_get(cagemesh, NULL);
bindcagecos = (float(*)[3])mmd->bindcagecos;
/* We allocate 1 element extra to make it possible to
@@ -396,7 +381,7 @@ static void meshdeformModifier_do(
copy_v3_v3(dco[a], co);
}
- modifier_get_vgroup(ob, dm, mmd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, mmd->defgrp_name, &dvert, &defgrp_index);
/* Initialize data to be pass to the for body function. */
data.mmd = mmd;
@@ -416,42 +401,45 @@ static void meshdeformModifier_do(
meshdeform_vert_task,
&settings);
- /* release cage derivedmesh */
+ /* release cage mesh */
MEM_freeN(dco);
MEM_freeN(cagecos);
- cagedm->release(cagedm);
+ if (cagemesh != NULL && free_cagemesh) {
+ BKE_id_free(NULL, cagemesh);
+ }
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
- DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
- modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */
+ MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */
- meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
+ meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts);
- if (dm && dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob,
- struct BMEditMesh *UNUSED(editData),
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ Mesh *mesh,
float (*vertexCos)[3],
int numVerts)
{
- DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
- meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
+ meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts);
- if (dm && dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
#define MESHDEFORM_MIN_INFLUENCE 0.00001f
@@ -527,17 +515,23 @@ ModifierTypeInfo modifierType_MeshDeform = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 4b7b4f63dde..771ccd31e22 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -26,19 +26,18 @@
#include "DNA_cachefile_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_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_cdderivedmesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_scene.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "MOD_modifiertypes.h"
@@ -56,14 +55,14 @@ static void initData(ModifierData *md)
mcmd->read_flag = MOD_MESHSEQ_READ_ALL;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
#if 0
const MeshSeqCacheModifierData *mcmd = (const MeshSeqCacheModifierData *)md;
#endif
MeshSeqCacheModifierData *tmcmd = (MeshSeqCacheModifierData *)target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
tmcmd->reader = NULL;
}
@@ -80,7 +79,7 @@ static void freeData(ModifierData *md)
}
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
@@ -88,68 +87,72 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
#ifdef WITH_ALEMBIC
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
/* Only used to check whether we are operating on org data or not... */
- Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL;
- DerivedMesh *org_dm = dm;
+ Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL;
+ Mesh *org_mesh = mesh;
- Scene *scene = md->scene;
- const float frame = BKE_scene_frame_get(scene);
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ const float frame = DEG_get_ctime(ctx->depsgraph);
const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS);
const char *err_str = NULL;
- CacheFile *cache_file = mcmd->cache_file;
+ CacheFile *cache_file = (CacheFile *)DEG_get_original_id(&mcmd->cache_file->id);
BKE_cachefile_ensure_handle(G.main, cache_file);
if (!mcmd->reader) {
mcmd->reader = CacheReader_open_alembic_object(cache_file->handle,
NULL,
- ob,
+ ctx->object,
mcmd->object_path);
if (!mcmd->reader) {
modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath);
- return dm;
+ return mesh;
}
}
if (me != NULL) {
- MVert *mvert = dm->getVertArray(dm);
- MEdge *medge = dm->getEdgeArray(dm);
- MPoly *mpoly = dm->getPolyArray(dm);
+ MVert *mvert = mesh->mvert;
+ MEdge *medge = mesh->medge;
+ MPoly *mpoly = mesh->mpoly;
if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
/* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
- dm = CDDM_copy(dm);
+ BKE_id_copy_ex(NULL, &mesh->id, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
}
}
- DerivedMesh *result = ABC_read_mesh(mcmd->reader,
- ob,
- dm,
- time,
- &err_str,
- mcmd->read_flag);
+ Mesh *result = ABC_read_mesh(mcmd->reader,
+ ctx->object,
+ mesh,
+ time,
+ &err_str,
+ mcmd->read_flag);
if (err_str) {
modifier_setError(md, "%s", err_str);
}
- if (!ELEM(result, NULL, dm) && (dm != org_dm)) {
- dm->release(dm);
- dm = org_dm;
+ if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) {
+ BKE_id_free(NULL, mesh);
+ mesh = org_mesh;
}
- return result ? result : dm;
+ return result ? result : mesh;
#else
- return dm;
- UNUSED_VARS(md, ob);
+ UNUSED_VARS(ctx, md);
+ return mesh;
#endif
}
@@ -174,18 +177,6 @@ static void foreachIDLink(
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
-
- if (mcmd->cache_file != NULL) {
- DagNode *curNode = dag_get_node(ctx->forest, mcmd->cache_file);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Cache File Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
@@ -196,28 +187,35 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
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,
+ /* name */ "Mesh Sequence Cache",
+ /* structName */ "MeshSeqCacheModifierData",
+ /* structSize */ sizeof(MeshSeqCacheModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_AcceptsCVs,
+
+ /* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ dependsOnTime,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
};
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index aeb28b3ecb0..659ac0dee30 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -33,19 +33,23 @@
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
#include "MEM_guardedalloc.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MOD_modifiertypes.h"
@@ -68,17 +72,6 @@ static void foreachObjectLink(
walk(userData, ob, &mmd->mirror_ob, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- MirrorModifierData *mmd = (MirrorModifierData *) md;
-
- if (mmd->mirror_ob) {
- DagNode *latNode = dag_get_node(ctx->forest, mmd->mirror_ob);
-
- dag_add_relation(ctx->forest, latNode, ctx->obNode, DAG_RL_OB_DATA, "Mirror Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MirrorModifierData *mmd = (MirrorModifierData *)md;
@@ -88,21 +81,90 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
}
-static DerivedMesh *doMirrorOnAxis(
+static Mesh *doBiscetOnMirrorPlane(
MirrorModifierData *mmd,
Object *ob,
- DerivedMesh *dm,
- int axis)
+ const Mesh *mesh,
+ int axis,
+ float mirrormat[4][4])
+{
+ bool do_bisect_flip_axis = (
+ (axis == 0 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_X) ||
+ (axis == 1 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Y) ||
+ (axis == 2 && mmd->flag & MOD_MIR_BISECT_FLIP_AXIS_Z));
+
+ const float bisect_distance = 0.001;
+
+ Mesh *result;
+ BMesh *bm;
+ BMIter viter;
+ BMVert *v, *v_next;
+
+ bm = BKE_mesh_to_bmesh_ex(
+ mesh,
+ &(struct BMeshCreateParams){0},
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .cd_mask_extra = CD_MASK_ORIGINDEX,
+ });
+
+ /* prepare data for bisecting */
+ float plane[4];
+ float plane_co[3] = {0, 0, 0};
+ float plane_no[3];
+ copy_v3_v3(plane_no, mirrormat[axis]);
+
+ if (mmd->mirror_ob) {
+ float tmp[4][4];
+ invert_m4_m4(tmp, ob->obmat);
+ mul_m4_m4m4(tmp, tmp, mmd->mirror_ob->obmat);
+
+ copy_v3_v3(plane_no, tmp[axis]);
+ copy_v3_v3(plane_co, tmp[3]);
+ }
+
+ plane_from_point_normal_v3(plane, plane_co, plane_no);
+
+ BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
+
+ /* Plane definitions for vert killing. */
+ float plane_offset[4];
+ copy_v3_v3(plane_offset, plane);
+ plane_offset[3] = plane[3] - bisect_distance;
+
+ if (do_bisect_flip_axis) {
+ negate_v3(plane_offset);
+ }
+
+ /* Delete verts across the mirror plane. */
+ BM_ITER_MESH_MUTABLE(v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
+ if (plane_point_side_v3(plane_offset, v->co) > 0.0f) {
+ BM_vert_kill(bm, v);
+ }
+ }
+
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
+ BM_mesh_free(bm);
+
+ return result;
+}
+
+static Mesh *doMirrorOnAxis(
+ MirrorModifierData *mmd,
+ Object *ob,
+ const Mesh *mesh,
+ int axis)
{
const float tolerance_sq = mmd->tolerance * mmd->tolerance;
const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
int tot_vtargetmap = 0; /* total merge vertices */
- DerivedMesh *result;
- const int maxVerts = dm->getNumVerts(dm);
- const int maxEdges = dm->getNumEdges(dm);
- const int maxLoops = dm->getNumLoops(dm);
- const int maxPolys = dm->getNumPolys(dm);
+ const bool do_bisect = (
+ (axis == 0 && mmd->flag & MOD_MIR_BISECT_AXIS_X) ||
+ (axis == 1 && mmd->flag & MOD_MIR_BISECT_AXIS_Y) ||
+ (axis == 2 && mmd->flag & MOD_MIR_BISECT_AXIS_Z));
+
+ Mesh *result;
MVert *mv, *mv_prev;
MEdge *me;
MLoop *ml;
@@ -135,35 +197,46 @@ static DerivedMesh *doMirrorOnAxis(
mul_m4_m4m4(mtx, itmp, mtx);
}
- result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
- /*copy customdata to original geometry*/
- DM_copy_vert_data(dm, result, 0, 0, maxVerts);
- DM_copy_edge_data(dm, result, 0, 0, maxEdges);
- DM_copy_loop_data(dm, result, 0, 0, maxLoops);
- DM_copy_poly_data(dm, result, 0, 0, maxPolys);
+ Mesh *mesh_bisect = NULL;
+ if (do_bisect) {
+ mesh_bisect = doBiscetOnMirrorPlane(mmd, ob, mesh, axis, mtx);
+ mesh = mesh_bisect;
+ }
+
+ const int maxVerts = mesh->totvert;
+ const int maxEdges = mesh->totedge;
+ const int maxLoops = mesh->totloop;
+ const int maxPolys = mesh->totpoly;
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);
+
+ /*copy customdata to original geometry*/
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, maxVerts);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, maxEdges);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
/* Subsurf for eg won't have mesh data in the custom data arrays.
* now add mvert/medge/mpoly layers. */
-
- if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) {
- dm->copyVertArray(dm, CDDM_get_verts(result));
+ if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
+ memcpy(result->mvert, mesh->mvert, sizeof(*result->mvert) * mesh->totvert);
}
- if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) {
- dm->copyEdgeArray(dm, CDDM_get_edges(result));
+ if (!CustomData_has_layer(&mesh->edata, CD_MEDGE)) {
+ memcpy(result->medge, mesh->medge, sizeof(*result->medge) * mesh->totedge);
}
- if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) {
- dm->copyLoopArray(dm, CDDM_get_loops(result));
- dm->copyPolyArray(dm, CDDM_get_polys(result));
+ if (!CustomData_has_layer(&mesh->pdata, CD_MPOLY)) {
+ memcpy(result->mloop, mesh->mloop, sizeof(*result->mloop) * mesh->totloop);
+ memcpy(result->mpoly, mesh->mpoly, sizeof(*result->mpoly) * mesh->totpoly);
}
/* copy customdata to new geometry,
* copy from its self because this data may have been created in the checks above */
- DM_copy_vert_data(result, result, 0, maxVerts, maxVerts);
- DM_copy_edge_data(result, result, 0, maxEdges, maxEdges);
+ CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
+ CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
/* loops are copied later */
- DM_copy_poly_data(result, result, 0, maxPolys, maxPolys);
+ CustomData_copy_data(&result->pdata, &result->pdata, 0, maxPolys, maxPolys);
if (do_vtargetmap) {
/* second half is filled with -1 */
@@ -174,7 +247,7 @@ static DerivedMesh *doMirrorOnAxis(
}
/* mirror vertex coordinates */
- mv_prev = CDDM_get_verts(result);
+ mv_prev = result->mvert;
mv = mv_prev + maxVerts;
for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
mul_m4_v3(mtx, mv->co);
@@ -202,33 +275,37 @@ static DerivedMesh *doMirrorOnAxis(
}
/* handle shape keys */
- totshape = CustomData_number_of_layers(&result->vertData, CD_SHAPEKEY);
+ totshape = CustomData_number_of_layers(&result->vdata, CD_SHAPEKEY);
for (a = 0; a < totshape; a++) {
- float (*cos)[3] = CustomData_get_layer_n(&result->vertData, CD_SHAPEKEY, a);
- for (i = maxVerts; i < result->numVertData; i++) {
+ float (*cos)[3] = CustomData_get_layer_n(&result->vdata, CD_SHAPEKEY, a);
+ for (i = maxVerts; i < result->totvert; i++) {
mul_m4_v3(mtx, cos[i]);
}
}
/* adjust mirrored edge vertex indices */
- me = CDDM_get_edges(result) + maxEdges;
+ me = result->medge + maxEdges;
for (i = 0; i < maxEdges; i++, me++) {
me->v1 += maxVerts;
me->v2 += maxVerts;
}
/* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
- mp = CDDM_get_polys(result) + maxPolys;
- ml = CDDM_get_loops(result);
+ mp = result->mpoly + maxPolys;
+ ml = result->mloop;
for (i = 0; i < maxPolys; i++, mp++) {
MLoop *ml2;
int j, e;
/* reverse the loop, but we keep the first vertex in the face the same,
* to ensure that quads are split the same way as on the other side */
- DM_copy_loop_data(result, result, mp->loopstart, mp->loopstart + maxLoops, 1);
+ CustomData_copy_data(&result->ldata, &result->ldata, mp->loopstart, mp->loopstart + maxLoops, 1);
+
for (j = 1; j < mp->totloop; j++)
- DM_copy_loop_data(result, result, mp->loopstart + j, mp->loopstart + maxLoops + mp->totloop - j, 1);
+ CustomData_copy_data(&result->ldata, &result->ldata,
+ mp->loopstart + j,
+ mp->loopstart + maxLoops + mp->totloop - j,
+ 1);
ml2 = ml + mp->loopstart + maxLoops;
e = ml2[0].e;
@@ -241,7 +318,7 @@ static DerivedMesh *doMirrorOnAxis(
}
/* adjust mirrored loop vertex and edge indices */
- ml = CDDM_get_loops(result) + maxLoops;
+ ml = result->mloop + maxLoops;
for (i = 0; i < maxLoops; i++, ml++) {
ml->v += maxVerts;
ml->e += maxEdges;
@@ -253,10 +330,10 @@ static DerivedMesh *doMirrorOnAxis(
const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
- const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
+ const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
for (a = 0; a < totuv; a++) {
- MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, a);
+ MLoopUV *dmloopuv = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, a);
int j = maxLoops;
dmloopuv += j; /* second set of loops only */
for (; j-- > 0; dmloopuv++) {
@@ -269,8 +346,8 @@ static DerivedMesh *doMirrorOnAxis(
}
/* handle vgroup stuff */
- if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vertData, CD_MDEFORMVERT)) {
- MDeformVert *dvert = (MDeformVert *) CustomData_get_layer(&result->vertData, CD_MDEFORMVERT) + maxVerts;
+ if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vdata, CD_MDEFORMVERT)) {
+ MDeformVert *dvert = (MDeformVert *) CustomData_get_layer(&result->vdata, CD_MDEFORMVERT) + maxVerts;
int *flip_map = NULL, flip_map_len = 0;
flip_map = defgroup_flip_map(ob, &flip_map_len, false);
@@ -292,51 +369,60 @@ static DerivedMesh *doMirrorOnAxis(
/* slow - so only call if one or more merge verts are found,
* users may leave this on and not realize there is nothing to merge - campbell */
if (tot_vtargetmap) {
- result = CDDM_merge_verts(result, vtargetmap, tot_vtargetmap, CDDM_MERGE_VERTS_DUMP_IF_MAPPED);
+ result = BKE_mesh_merge_verts(result, vtargetmap, tot_vtargetmap, MESH_MERGE_VERTS_DUMP_IF_MAPPED);
}
MEM_freeN(vtargetmap);
}
+ if (mesh_bisect != NULL) {
+ BKE_id_free(NULL, mesh_bisect);
+ }
+
return result;
}
-static DerivedMesh *mirrorModifier__doMirror(
+static Mesh *mirrorModifier__doMirror(
MirrorModifierData *mmd,
- Object *ob, DerivedMesh *dm)
+ Object *ob, Mesh *mesh)
{
- DerivedMesh *result = dm;
+ Mesh *result = mesh;
/* check which axes have been toggled and mirror accordingly */
if (mmd->flag & MOD_MIR_AXIS_X) {
result = doMirrorOnAxis(mmd, ob, result, 0);
}
if (mmd->flag & MOD_MIR_AXIS_Y) {
- DerivedMesh *tmp = result;
+ Mesh *tmp = result;
result = doMirrorOnAxis(mmd, ob, result, 1);
- if (tmp != dm) tmp->release(tmp); /* free intermediate results */
+ if (tmp != mesh) {
+ /* free intermediate results */
+ BKE_id_free(NULL, tmp);
+ }
}
if (mmd->flag & MOD_MIR_AXIS_Z) {
- DerivedMesh *tmp = result;
+ Mesh *tmp = result;
result = doMirrorOnAxis(mmd, ob, result, 2);
- if (tmp != dm) tmp->release(tmp); /* free intermediate results */
+ if (tmp != mesh) {
+ /* free intermediate results */
+ BKE_id_free(NULL, tmp);
+ }
}
return result;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
- DerivedMesh *result;
+ Mesh *result;
MirrorModifierData *mmd = (MirrorModifierData *) md;
- result = mirrorModifier__doMirror(mmd, ob, derivedData);
-
- if (result != derivedData)
- result->dirty |= DM_DIRTY_NORMALS;
+ result = mirrorModifier__doMirror(mmd, ctx->object, mesh);
+ if (result != mesh) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
return result;
}
@@ -355,17 +441,23 @@ ModifierTypeInfo modifierType_Mirror = {
eModifierTypeFlag_UsesPreview,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index cdbacac97b9..fc8a376d2d7 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -37,15 +37,22 @@
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_modifier.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_mesh.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_modifiertypes.h"
static void initData(ModifierData *md)
@@ -56,84 +63,105 @@ static void initData(ModifierData *md)
mmd->sculptlvl = 0;
mmd->renderlvl = 0;
mmd->totlvl = 0;
+ mmd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ mmd->quality = 3;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob, DerivedMesh *dm,
- ModifierApplyFlag flag)
+/* Subdivide into fully qualified mesh. */
+
+static Mesh *multires_as_mesh(MultiresModifierData *mmd,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ Subdiv *subdiv)
{
- MultiresModifierData *mmd = (MultiresModifierData *)md;
- DerivedMesh *result;
- Mesh *me = (Mesh *)ob->data;
- const bool useRenderParams = (flag & MOD_APPLY_RENDER) != 0;
- const bool ignore_simplify = (flag & MOD_APPLY_IGNORE_SIMPLIFY) != 0;
- MultiresFlags flags = 0;
- const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
-
- if (mmd->totlvl) {
- if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
- /* multires always needs a displacement layer */
- CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop);
- }
+ Mesh *result = mesh;
+ const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
+ const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY);
+ const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ Object *object = ctx->object;
+ SubdivToMeshSettings mesh_settings;
+ BKE_multires_subdiv_mesh_settings_init(
+ &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify);
+ if (mesh_settings.resolution < 3) {
+ return result;
}
+ BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
+ result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
+ return result;
+}
- if (has_mask)
- flags |= MULTIRES_ALLOC_PAINT_MASK;
-
- if (useRenderParams)
- flags |= MULTIRES_USE_RENDER_PARAMS;
-
- if (ignore_simplify)
- flags |= MULTIRES_IGNORE_SIMPLIFY;
-
- result = multires_make_derived_from_derived(dm, mmd, ob, flags);
-
- if (result == dm)
- return dm;
-
- if (useRenderParams || !(flag & MOD_APPLY_USECACHE)) {
- DerivedMesh *cddm;
-
- cddm = CDDM_copy(result);
-
- /* copy hidden/masks to vertices */
- if (!useRenderParams) {
- struct MDisps *mdisps;
- struct GridPaintMask *grid_paint_mask;
-
- mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
- grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK);
-
- if (mdisps) {
- subsurf_copy_grid_hidden(result, me->mpoly,
- cddm->getVertArray(cddm),
- mdisps);
-
- BKE_mesh_flush_hidden_from_verts_ex(cddm->getVertArray(cddm),
- cddm->getLoopArray(cddm),
- cddm->getEdgeArray(cddm),
- cddm->getNumEdges(cddm),
- cddm->getPolyArray(cddm),
- cddm->getNumPolys(cddm));
- }
- if (grid_paint_mask) {
- float *paint_mask = CustomData_add_layer(&cddm->vertData,
- CD_PAINT_MASK,
- CD_CALLOC, NULL,
- cddm->getNumVerts(cddm));
+/* Subdivide into CCG. */
- subsurf_copy_grid_paint_mask(result, me->mpoly,
- paint_mask, grid_paint_mask);
- }
- }
+static void multires_ccg_settings_init(SubdivToCCGSettings *settings,
+ const MultiresModifierData *mmd,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
+{
+ const bool has_mask =
+ CustomData_has_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
+ const bool ignore_simplify = (ctx->flag & MOD_APPLY_IGNORE_SIMPLIFY);
+ const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ Object *object = ctx->object;
+ const int level = multires_get_level(
+ scene, object, mmd, use_render_params, ignore_simplify);
+ settings->resolution = (1 << level) + 1;
+ settings->need_normal = true;
+ settings->need_mask = has_mask;
+}
- result->release(result);
- result = cddm;
+static Mesh *multires_as_ccg(MultiresModifierData *mmd,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ Subdiv *subdiv)
+{
+ Mesh *result = mesh;
+ SubdivToCCGSettings ccg_settings;
+ multires_ccg_settings_init(&ccg_settings, mmd, ctx, mesh);
+ if (ccg_settings.resolution < 3) {
+ return result;
}
-
+ BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
+ result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh);
return result;
}
+static Mesh *applyModifier(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
+{
+ Mesh *result = mesh;
+ MultiresModifierData *mmd = (MultiresModifierData *)md;
+ SubdivSettings subdiv_settings;
+ BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
+ if (subdiv_settings.level == 0) {
+ return result;
+ }
+ /* TODO(sergey): Try to re-use subdiv when possible. */
+ Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, ut also on empty input mesh. */
+ return result;
+ }
+ /* NOTE: Orco needs final coordinates on CPU side, which are expected to be
+ * accessible via MVert. For this reason we do not evaluate multires to
+ * grids when orco is requested.
+ */
+ const bool for_orco = (ctx->flag & MOD_APPLY_ORCO) != 0;
+ if ((ctx->object->mode & OB_MODE_SCULPT) && !for_orco) {
+ /* NOTE: CCG takes ownership over Subdiv. */
+ result = multires_as_ccg(mmd, ctx, mesh, subdiv);
+ result->runtime.subdiv_ccg_tot_level = mmd->totlvl;
+ // BKE_subdiv_stats_print(&subdiv->stats);
+ }
+ else {
+ result = multires_as_mesh(mmd, ctx, mesh, subdiv);
+ /* TODO(sergey): Cache subdiv somehow. */
+ // BKE_subdiv_stats_print(&subdiv->stats);
+ BKE_subdiv_free(subdiv);
+ }
+ return result;
+}
ModifierTypeInfo modifierType_Multires = {
/* name */ "Multires",
@@ -145,17 +173,23 @@ ModifierTypeInfo modifierType_Multires = {
eModifierTypeFlag_RequiresOriginalData,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c
index d9d9ba2966d..3946782b5ef 100644
--- a/source/blender/modifiers/intern/MOD_none.c
+++ b/source/blender/modifiers/intern/MOD_none.c
@@ -43,7 +43,7 @@
* no other functions will be called
*/
-static bool isDisabled(ModifierData *UNUSED(md), int UNUSED(userRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *UNUSED(md), bool UNUSED(userRenderParams))
{
return true;
}
@@ -57,17 +57,23 @@ ModifierTypeInfo modifierType_None = {
eModifierTypeFlag_AcceptsCVs,
/* copyData */ NULL,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ NULL,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 0cf24d312dd..d7126113fe8 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -37,18 +37,16 @@
#include "BLI_utildefines.h"
#include "BLI_bitmap.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
#include "BKE_deform.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
static void generate_vert_coordinates(
- DerivedMesh *dm, Object *ob, Object *ob_center, const float offset[3],
+ Mesh *mesh, Object *ob, Object *ob_center, const float offset[3],
const int num_verts, float (*r_cos)[3], float r_size[3])
{
float min_co[3], max_co[3];
@@ -57,30 +55,37 @@ static void generate_vert_coordinates(
INIT_MINMAX(min_co, max_co);
- dm->getVertCos(dm, r_cos);
+ MVert *mv = mesh->mvert;
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ copy_v3_v3(r_cos[i], mv->co);
+ if (r_size != NULL && ob_center == NULL) {
+ minmax_v3v3_v3(min_co, max_co, r_cos[i]);
+ }
+ }
/* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */
- if (ob_center) {
- /* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */
- abs_v3_v3(r_size, ob_center->size);
- }
- else {
- minmax_v3v3_v3_array(min_co, max_co, r_cos, num_verts);
- /* Set size. */
- sub_v3_v3v3(r_size, max_co, min_co);
- }
+ if (r_size != NULL) {
+ if (ob_center != NULL) {
+ /* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */
+ abs_v3_v3(r_size, ob_center->size);
+ }
+ else {
+ /* Set size. */
+ sub_v3_v3v3(r_size, max_co, min_co);
+ }
- /* Error checks - we do not want one or more of our sizes to be null! */
- if (is_zero_v3(r_size)) {
- r_size[0] = r_size[1] = r_size[2] = 1.0f;
- }
- else {
- CLAMP_MIN(r_size[0], FLT_EPSILON);
- CLAMP_MIN(r_size[1], FLT_EPSILON);
- CLAMP_MIN(r_size[2], FLT_EPSILON);
+ /* Error checks - we do not want one or more of our sizes to be null! */
+ if (is_zero_v3(r_size)) {
+ r_size[0] = r_size[1] = r_size[2] = 1.0f;
+ }
+ else {
+ CLAMP_MIN(r_size[0], FLT_EPSILON);
+ CLAMP_MIN(r_size[1], FLT_EPSILON);
+ CLAMP_MIN(r_size[2], FLT_EPSILON);
+ }
}
- if (ob_center) {
+ if (ob_center != NULL) {
float inv_obmat[4][4];
/* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
@@ -92,7 +97,7 @@ static void generate_vert_coordinates(
do_diff = true;
}
- else if (!is_zero_v3(offset)) {
+ else if (offset != NULL && !is_zero_v3(offset)) {
negate_v3_v3(diff, offset);
do_diff = true;
@@ -188,7 +193,7 @@ static bool polygons_check_flip(
}
static void normalEditModifier_do_radial(
- NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm,
+ NormalEditModifierData *enmd, Object *ob, Mesh *mesh,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
@@ -204,7 +209,7 @@ static void normalEditModifier_do_radial(
BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__);
- generate_vert_coordinates(dm, ob, enmd->target, enmd->offset, num_verts, cos, size);
+ generate_vert_coordinates(mesh, ob, enmd->target, enmd->offset, num_verts, cos, size);
/**
* size gives us our spheroid coefficients ``(A, B, C)``.
@@ -273,10 +278,11 @@ static void normalEditModifier_do_radial(
mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
- if (do_polynors_fix && polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ if (do_polynors_fix && polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
+ /* XXX TODO is this still needed? */
+ // mesh->dirty |= DM_DIRTY_TESS_CDLAYERS;
/* We need to recompute vertex normals! */
- dm->calcNormals(dm);
+ BKE_mesh_calc_normals(mesh);
}
BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
@@ -288,7 +294,7 @@ static void normalEditModifier_do_radial(
}
static void normalEditModifier_do_directional(
- NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm,
+ NormalEditModifierData *enmd, Object *ob, Mesh *mesh,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
@@ -298,22 +304,17 @@ static void normalEditModifier_do_directional(
const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
- float (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__);
float (*nos)[3] = MEM_malloc_arrayN((size_t)num_loops, sizeof(*nos), __func__);
float target_co[3];
int i;
- dm->getVertCos(dm, cos);
-
/* Get target's center coordinates in ob local coordinates. */
- {
- float mat[4][4];
+ float mat[4][4];
- invert_m4_m4(mat, ob->obmat);
- mul_m4_m4m4(mat, mat, enmd->target->obmat);
- copy_v3_v3(target_co, mat[3]);
- }
+ invert_m4_m4(mat, ob->obmat);
+ mul_m4_m4m4(mat, mat, enmd->target->obmat);
+ copy_v3_v3(target_co, mat[3]);
if (use_parallel_normals) {
float no[3];
@@ -326,6 +327,9 @@ static void normalEditModifier_do_directional(
}
}
else {
+ float (*cos)[3] = MEM_malloc_arrayN((size_t)num_verts, sizeof(*cos), __func__);
+ generate_vert_coordinates(mesh, ob, enmd->target, NULL, num_verts, cos, NULL);
+
BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__);
MLoop *ml;
float (*no)[3];
@@ -346,6 +350,7 @@ static void normalEditModifier_do_directional(
}
MEM_freeN(done_verts);
+ MEM_freeN(cos);
}
if (loopnors) {
@@ -353,14 +358,13 @@ static void normalEditModifier_do_directional(
mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
- if (do_polynors_fix && polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ if (do_polynors_fix && polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
mpoly, (const float(*)[3])polynors, num_polys, clnors);
- MEM_freeN(cos);
MEM_freeN(nos);
}
@@ -376,93 +380,112 @@ static bool is_valid_target(NormalEditModifierData *enmd)
return false;
}
-static DerivedMesh *normalEditModifier_do(NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm)
+static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, Object *ob, Mesh *mesh)
{
- Mesh *me = ob->data;
-
- const int num_verts = dm->getNumVerts(dm);
- const int num_edges = dm->getNumEdges(dm);
- const int num_loops = dm->getNumLoops(dm);
- const int num_polys = dm->getNumPolys(dm);
- MVert *mvert;
- MEdge *medge;
- MLoop *mloop;
- MPoly *mpoly;
-
const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
(enmd->mix_factor == 1.0f) &&
(enmd->defgrp_name[0] == '\0') &&
(enmd->mix_limit == (float)M_PI));
+ /* Do not run that modifier at all if autosmooth is disabled! */
+ if (!is_valid_target(enmd) || mesh->totloop == 0) {
+ return mesh;
+ }
+
+ /* XXX TODO ARG GRRR XYQWNMPRXTYY
+ * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy.
+ * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */
+#if 0
+ if (!(mesh->flag & ME_AUTOSMOOTH)) {
+#else
+ if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) {
+#endif
+ modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings");
+ return mesh;
+ }
+
+ Mesh *result;
+ if (mesh->medge == ((Mesh *)ob->data)->medge) {
+ /* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could
+ * modify org mesh, see T43671. */
+ BKE_id_copy_ex(
+ NULL, &mesh->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ }
+ else {
+ result = mesh;
+ }
+
+ const int num_verts = result->totvert;
+ const int num_edges = result->totedge;
+ const int num_loops = result->totloop;
+ const int num_polys = result->totpoly;
+ MVert *mvert = result->mvert;
+ MEdge *medge = result->medge;
+ MLoop *mloop = result->mloop;
+ MPoly *mpoly = result->mpoly;
+
int defgrp_index;
MDeformVert *dvert;
float (*loopnors)[3] = NULL;
- short (*clnors)[2];
+ short (*clnors)[2] = NULL;
float (*polynors)[3];
- bool free_polynors = false;
- /* Do not run that modifier at all if autosmooth is disabled! */
- if (!is_valid_target(enmd) || !num_loops) {
- return dm;
+ CustomData *ldata = &result->ldata;
+ if (CustomData_has_layer(ldata, CD_NORMAL)) {
+ loopnors = CustomData_get_layer(ldata, CD_NORMAL);
}
-
- if (!(me->flag & ME_AUTOSMOOTH)) {
- modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings");
- return dm;
+ else {
+ loopnors = CustomData_add_layer(ldata, CD_NORMAL, CD_CALLOC, NULL, num_loops);
}
- medge = dm->getEdgeArray(dm);
- if (me->medge == medge) {
- /* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could
- * modify org mesh, see T43671. */
- dm = CDDM_copy(dm);
- medge = dm->getEdgeArray(dm);
+ /* Compute poly (always needed) and vert normals. */
+ CustomData *pdata = &result->pdata;
+ polynors = CustomData_get_layer(pdata, CD_NORMAL);
+ if (!polynors) {
+ polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys);
}
- mvert = dm->getVertArray(dm);
- mloop = dm->getLoopArray(dm);
- mpoly = dm->getPolyArray(dm);
+ BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors,
+ (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) ? false : true);
+
+ result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
if (use_current_clnors) {
- dm->calcLoopNormals(dm, true, me->smoothresh);
- loopnors = dm->getLoopDataArray(dm, CD_NORMAL);
- }
+ clnors = CustomData_duplicate_referenced_layer(ldata, CD_CUSTOMLOOPNORMAL, num_loops);
- clnors = CustomData_duplicate_referenced_layer(&dm->loopData, CD_CUSTOMLOOPNORMAL, num_loops);
- if (!clnors) {
- DM_add_loop_layer(dm, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL);
- clnors = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL);
+ BKE_mesh_normals_loop_split(mvert, num_verts, medge, num_edges, mloop, loopnors, num_loops,
+ mpoly, (const float (*)[3])polynors, num_polys,
+ true, result->smoothresh,
+ NULL, clnors, NULL);
}
- polynors = dm->getPolyDataArray(dm, CD_NORMAL);
- if (!polynors) {
- polynors = MEM_malloc_arrayN((size_t)num_polys, sizeof(*polynors), __func__);
- BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false);
- free_polynors = true;
+ if (!clnors) {
+ clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops);
}
- modifier_get_vgroup(ob, dm, enmd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index);
if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
normalEditModifier_do_radial(
- enmd, ob, dm, clnors, loopnors, polynors,
+ enmd, ob, result, clnors, loopnors, polynors,
enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
normalEditModifier_do_directional(
- enmd, ob, dm, clnors, loopnors, polynors,
+ enmd, ob, result, clnors, loopnors, polynors,
enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
- if (free_polynors) {
- MEM_freeN(polynors);
- }
-
- return dm;
+ return result;
}
static void initData(ModifierData *md)
@@ -479,7 +502,7 @@ static void initData(ModifierData *md)
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
NormalEditModifierData *enmd = (NormalEditModifierData *)md;
- CustomDataMask dataMask = CD_CUSTOMLOOPNORMAL;
+ CustomDataMask dataMask = CD_MASK_CUSTOMLOOPNORMAL;
/* Ask for vertexgroups if we need them. */
if (enmd->defgrp_name[0]) {
@@ -501,35 +524,25 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
walk(userData, ob, &enmd->target, IDWALK_CB_NOP);
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
NormalEditModifierData *enmd = (NormalEditModifierData *)md;
return !is_valid_target(enmd);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- NormalEditModifierData *enmd = (NormalEditModifierData *) md;
-
- if (enmd->target) {
- DagNode *Node = dag_get_node(ctx->forest, enmd->target);
-
- dag_add_relation(ctx->forest, Node, ctx->obNode, DAG_RL_OB_DATA, "NormalEdit Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
NormalEditModifierData *enmd = (NormalEditModifierData *) md;
if (enmd->target) {
DEG_add_object_relation(ctx->node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
}
}
-static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
- return normalEditModifier_do((NormalEditModifierData *)md, ob, dm);
+ return normalEditModifier_do((NormalEditModifierData *)md, ctx->object, mesh);
}
ModifierTypeInfo modifierType_NormalEdit = {
@@ -541,18 +554,25 @@ ModifierTypeInfo modifierType_NormalEdit = {
eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
+
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index b845e62c530..8231745aa12 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -31,6 +31,7 @@
#include "DNA_customdata_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
@@ -40,12 +41,15 @@
#include "BLI_task.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_ocean.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_modifiertypes.h"
#ifdef WITH_OCEANSIM
@@ -58,38 +62,8 @@ static void init_cache_data(Object *ob, struct OceanModifierData *omd)
omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
}
-static void clear_cache_data(struct OceanModifierData *omd)
-{
- BKE_ocean_free_cache(omd->oceancache);
- omd->oceancache = NULL;
- omd->cached = false;
-}
-
-/* keep in sync with init_ocean_modifier_bake(), object_modifier.c */
-static void init_ocean_modifier(struct OceanModifierData *omd)
-{
- int do_heightfield, do_chop, do_normals, do_jacobian;
-
- if (!omd || !omd->ocean) return;
-
- do_heightfield = true;
- do_chop = (omd->chop_amount > 0);
- do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
- do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
-
- BKE_ocean_free_data(omd->ocean);
- BKE_ocean_init(omd->ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
- omd->spatial_size, omd->spatial_size,
- omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
- omd->depth, omd->time,
- do_heightfield, do_chop, do_normals, do_jacobian,
- omd->seed);
-}
-
static void simulate_ocean_modifier(struct OceanModifierData *omd)
{
- if (!omd || !omd->ocean) return;
-
BKE_ocean_simulate(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
}
#endif /* WITH_OCEANSIM */
@@ -123,8 +97,6 @@ static void initData(ModifierData *md)
omd->seed = 0;
omd->time = 1.0;
- omd->refresh = 0;
-
omd->size = 1.0;
omd->repeat_x = 1;
omd->repeat_y = 1;
@@ -139,7 +111,7 @@ static void initData(ModifierData *md)
omd->foamlayername[0] = '\0'; /* layer name empty by default */
omd->ocean = BKE_ocean_add();
- init_ocean_modifier(omd);
+ BKE_ocean_init_from_modifier(omd->ocean, omd);
simulate_ocean_modifier(omd);
#else /* WITH_OCEANSIM */
/* unused */
@@ -161,7 +133,7 @@ static void freeData(ModifierData *md)
#endif /* WITH_OCEANSIM */
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
#ifdef WITH_OCEANSIM
#if 0
@@ -169,21 +141,20 @@ static void copyData(const ModifierData *md, ModifierData *target)
#endif
OceanModifierData *tomd = (OceanModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
- tomd->refresh = 0;
-
- /* XXX todo: copy cache runtime too */
- tomd->cached = 0;
+ /* The oceancache object will be recreated for this copy
+ * automatically when cached=true */
tomd->oceancache = NULL;
tomd->ocean = BKE_ocean_add();
- init_ocean_modifier(tomd);
+ BKE_ocean_init_from_modifier(tomd->ocean, tomd);
simulate_ocean_modifier(tomd);
#else /* WITH_OCEANSIM */
/* unused */
(void)md;
(void)target;
+ (void)flag;
#endif /* WITH_OCEANSIM */
}
@@ -213,38 +184,6 @@ static bool dependsOnNormals(ModifierData *md)
return (omd->geometry_mode != MOD_OCEAN_GEOM_GENERATE);
}
-#if 0
-static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy)
-{
- /* get bounding box of underlying dm */
- int v, totvert = dm->getNumVerts(dm);
- float min[3], max[3], delta[3];
-
- MVert *mvert = dm->getVertDataArray(dm, 0);
-
- copy_v3_v3(min, mvert->co);
- copy_v3_v3(max, mvert->co);
-
- for (v = 1; v < totvert; v++, mvert++) {
- min[0] = min_ff(min[0], mvert->co[0]);
- min[1] = min_ff(min[1], mvert->co[1]);
- min[2] = min_ff(min[2], mvert->co[2]);
-
- max[0] = max_ff(max[0], mvert->co[0]);
- max[1] = max_ff(max[1], mvert->co[1]);
- max[2] = max_ff(max[2], mvert->co[2]);
- }
-
- sub_v3_v3v3(delta, max, min);
-
- *sx = delta[0];
- *sy = delta[1];
-
- *ox = min[0];
- *oy = min[1];
-}
-#endif
-
#ifdef WITH_OCEANSIM
typedef struct GenerateOceanGeometryData {
@@ -341,9 +280,9 @@ static void generate_ocean_geometry_uvs(
}
}
-static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
+static Mesh *generate_ocean_geometry(OceanModifierData *omd)
{
- DerivedMesh *result;
+ Mesh *result;
GenerateOceanGeometryData gogd;
@@ -368,13 +307,13 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
gogd.sx /= gogd.rx;
gogd.sy /= gogd.ry;
- result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys);
+ result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys);
- gogd.mverts = CDDM_get_verts(result);
- gogd.mpolys = CDDM_get_polys(result);
- gogd.mloops = CDDM_get_loops(result);
+ gogd.mverts = result->mvert;
+ gogd.mpolys = result->mpoly;
+ gogd.mloops = result->mloop;
- gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
+ gogd.origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
ParallelRangeSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -386,12 +325,11 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
/* create faces */
BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, &settings);
- CDDM_calc_edges(result);
+ BKE_mesh_calc_edges(result, false, false);
/* add uvs */
- if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) {
- gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4);
- CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys);
+ if (CustomData_number_of_layers(&result->ldata, CD_MLOOPUV) < MAX_MTFACE) {
+ gogd.mloopuvs = CustomData_add_layer(&result->ldata, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4);
if (gogd.mloopuvs) { /* unlikely to fail */
gogd.ix = 1.0 / gogd.rx;
@@ -401,24 +339,24 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
}
}
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
-static DerivedMesh *doOcean(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- int UNUSED(useRenderParams))
+static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
OceanModifierData *omd = (OceanModifierData *) md;
+ int cfra_scene = (int)DEG_get_ctime(ctx->depsgraph);
+ Object *ob = ctx->object;
+ bool allocated_ocean = false;
- DerivedMesh *dm = NULL;
+ Mesh *result = NULL;
OceanResult ocr;
MVert *mverts;
- int cfra;
+ int cfra_for_cache;
int i, j;
/* use cached & inverted value for speed
@@ -431,55 +369,57 @@ static DerivedMesh *doOcean(
/* can happen in when size is small, avoid bad array lookups later and quit now */
if (!isfinite(size_co_inv)) {
- return derivedData;
+ return mesh;
}
- /* update modifier */
- if (omd->refresh & MOD_OCEAN_REFRESH_RESET) {
- init_ocean_modifier(omd);
- }
- if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) {
- clear_cache_data(omd);
- }
- omd->refresh = 0;
-
/* do ocean simulation */
if (omd->cached == true) {
if (!omd->oceancache) {
init_cache_data(ob, omd);
}
- BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra);
+ BKE_ocean_simulate_cache(omd->oceancache, cfra_scene);
}
else {
+ /* omd->ocean is NULL on an original object (in contrast to an evaluated one).
+ * We can create a new one, but we have to free it as well once we're done.
+ * This function is only called on an original object when applying the modifier
+ * using the 'Apply Modifier' button, and thus it is not called frequently for
+ * simulation. */
+ allocated_ocean |= BKE_ocean_ensure(omd);
simulate_ocean_modifier(omd);
}
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
- dm = generate_ocean_geometry(omd);
- DM_ensure_normals(dm);
+ result = generate_ocean_geometry(omd);
+ BKE_mesh_ensure_normals(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
- dm = CDDM_copy(derivedData);
+ BKE_id_copy_ex(NULL, &mesh->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
}
- cfra = md->scene->r.cfra;
- CLAMP(cfra, omd->bakestart, omd->bakeend);
- cfra -= omd->bakestart; /* shift to 0 based */
+ cfra_for_cache = cfra_scene;
+ CLAMP(cfra_for_cache, omd->bakestart, omd->bakeend);
+ cfra_for_cache -= omd->bakestart; /* shift to 0 based */
- mverts = dm->getVertArray(dm);
+ mverts = result->mvert;
/* add vcols before displacement - allows lookup based on position */
if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
- if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL) < MAX_MCOL) {
- const int num_polys = dm->getNumPolys(dm);
- const int num_loops = dm->getNumLoops(dm);
- MLoop *mloops = dm->getLoopArray(dm);
+ if (CustomData_number_of_layers(&result->ldata, CD_MLOOPCOL) < MAX_MCOL) {
+ const int num_polys = result->totpoly;
+ const int num_loops = result->totloop;
+ MLoop *mloops = result->mloop;
MLoopCol *mloopcols = CustomData_add_layer_named(
- &dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername);
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername);
if (mloopcols) { /* unlikely to fail */
- MPoly *mpolys = dm->getPolyArray(dm);
+ MPoly *mpolys = result->mpoly;
MPoly *mp;
for (i = 0, mp = mpolys; i < num_polys; i++, mp++) {
@@ -493,7 +433,7 @@ static DerivedMesh *doOcean(
float foam;
if (omd->oceancache && omd->cached == true) {
- BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
+ BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra_for_cache, u, v);
foam = ocr.foam;
CLAMP(foam, 0.0f, 1.0f);
}
@@ -516,7 +456,7 @@ static DerivedMesh *doOcean(
/* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */
{
- const int num_verts = dm->getNumVerts(dm);
+ const int num_verts = result->totvert;
for (i = 0; i < num_verts; i++) {
float *vco = mverts[i].co;
@@ -524,7 +464,7 @@ static DerivedMesh *doOcean(
const float v = OCEAN_CO(size_co_inv, vco[1]);
if (omd->oceancache && omd->cached == true) {
- BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
+ BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra_for_cache, u, v);
}
else {
BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
@@ -539,33 +479,32 @@ static DerivedMesh *doOcean(
}
}
+ if (allocated_ocean) {
+ BKE_ocean_free(omd->ocean);
+ omd->ocean = NULL;
+ }
+
#undef OCEAN_CO
- return dm;
+ return result;
}
#else /* WITH_OCEANSIM */
-static DerivedMesh *doOcean(
- ModifierData *md, Object *UNUSED(ob),
- DerivedMesh *derivedData,
- int UNUSED(useRenderParams))
+static Mesh *doOcean(ModifierData *UNUSED(md), const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
- /* unused */
- (void)md;
- return derivedData;
+ return mesh;
}
#endif /* WITH_OCEANSIM */
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
- DerivedMesh *result;
+ Mesh *result;
- result = doOcean(md, ob, derivedData, 0);
+ result = doOcean(md, ctx, mesh);
- if (result != derivedData)
- result->dirty |= DM_DIRTY_NORMALS;
+ if (result != mesh)
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
@@ -581,17 +520,23 @@ ModifierTypeInfo modifierType_Ocean = {
eModifierTypeFlag_EnableInEditmode,
/* copyData */ copyData,
- /* deformMatrices */ NULL,
+ /* deformMatrices_DM */ NULL,
+
+ /* deformVerts_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index d88526e2845..2d5b520e9ca 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -33,6 +33,7 @@
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "MEM_guardedalloc.h"
@@ -43,17 +44,17 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_lattice.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
static void initData(ModifierData *md)
{
@@ -87,7 +88,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
}
-static bool isDisabled(ModifierData *md, int useRenderParams)
+static bool isDisabled(const struct Scene *scene, ModifierData *md, bool useRenderParams)
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
ParticleSystem *psys;
@@ -112,7 +113,7 @@ static bool isDisabled(ModifierData *md, int useRenderParams)
if (useRenderParams) required_mode = eModifierMode_Render;
else required_mode = eModifierMode_Realtime;
- if (!modifier_isEnabled(md->scene, ob_md, required_mode))
+ if (!modifier_isEnabled(scene, ob_md, required_mode))
return true;
break;
@@ -123,20 +124,6 @@ static bool isDisabled(ModifierData *md, int useRenderParams)
return false;
}
-
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
-
- if (pimd->ob) {
- DagNode *curNode = dag_get_node(ctx->forest, pimd->ob);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "Particle Instance Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
@@ -210,13 +197,13 @@ static void store_float_in_vcol(MLoopCol *vcol, float float_value)
vcol->a = 1.0f;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
- DerivedMesh *dm = derivedData, *result;
+ Mesh *result;
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
ParticleSimulationData sim;
ParticleSystem *psys = NULL;
ParticleData *pa = NULL;
@@ -226,7 +213,7 @@ static DerivedMesh *applyModifier(
int totvert, totpoly, totloop, totedge;
int maxvert, maxpoly, maxloop, maxedge, part_end = 0, part_start;
int k, p, p_skip;
- short track = ob->trackflag % 3, trackneg, axis = pimd->axis;
+ short track = ctx->object->trackflag % 3, trackneg, axis = pimd->axis;
float max_co = 0.0, min_co = 0.0, temp_co[3];
float *size = NULL;
float spacemat[4][4];
@@ -234,20 +221,20 @@ static DerivedMesh *applyModifier(
const bool use_children = pimd->flag & eParticleInstanceFlag_Children;
bool between;
- trackneg = ((ob->trackflag > 2) ? 1 : 0);
+ trackneg = ((ctx->object->trackflag > 2) ? 1 : 0);
- if (pimd->ob == ob) {
+ if (pimd->ob == ctx->object) {
pimd->ob = NULL;
- return derivedData;
+ return mesh;
}
if (pimd->ob) {
psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1);
if (psys == NULL || psys->totpart == 0)
- return derivedData;
+ return mesh;
}
else {
- return derivedData;
+ return mesh;
}
part_start = use_parents ? 0 : psys->totpart;
@@ -259,9 +246,10 @@ static DerivedMesh *applyModifier(
part_end += psys->totchild;
if (part_end == 0)
- return derivedData;
+ return mesh;
- sim.scene = md->scene;
+ sim.depsgraph = ctx->depsgraph;
+ sim.scene = scene;
sim.ob = pimd->ob;
sim.psys = psys;
sim.psmd = psys_get_modifier(pimd->ob, psys);
@@ -300,10 +288,10 @@ static DerivedMesh *applyModifier(
break;
}
- totvert = dm->getNumVerts(dm);
- totpoly = dm->getNumPolys(dm);
- totloop = dm->getNumLoops(dm);
- totedge = dm->getNumEdges(dm);
+ totvert = mesh->totvert;
+ totpoly = mesh->totpoly;
+ totloop = mesh->totloop;
+ totedge = mesh->totedge;
/* count particles */
maxvert = 0;
@@ -326,22 +314,22 @@ static DerivedMesh *applyModifier(
if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) {
float min[3], max[3];
INIT_MINMAX(min, max);
- dm->getMinMax(dm, min, max);
+ BKE_mesh_minmax(mesh, min, max);
min_co = min[track];
max_co = max[track];
}
- result = CDDM_from_template(dm, maxvert, maxedge, 0, maxloop, maxpoly);
+ result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, 0, maxloop, maxpoly);
- mvert = result->getVertArray(result);
- orig_mvert = dm->getVertArray(dm);
- mpoly = result->getPolyArray(result);
- orig_mpoly = dm->getPolyArray(dm);
- mloop = result->getLoopArray(result);
- orig_mloop = dm->getLoopArray(dm);
+ mvert = result->mvert;
+ orig_mvert = mesh->mvert;
+ mpoly = result->mpoly;
+ orig_mpoly = mesh->mpoly;
+ mloop = result->mloop;
+ orig_mloop = mesh->mloop;
- MLoopCol *mloopcols_index = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, pimd->index_layer_name);
- MLoopCol *mloopcols_value = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, pimd->value_layer_name);
+ MLoopCol *mloopcols_index = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, pimd->index_layer_name);
+ MLoopCol *mloopcols_value = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, pimd->value_layer_name);
int *vert_part_index = NULL;
float *vert_part_value = NULL;
if (mloopcols_index != NULL) {
@@ -368,7 +356,7 @@ static DerivedMesh *applyModifier(
MVert *mv = mvert + vindex;
inMV = orig_mvert + k;
- DM_copy_vert_data(dm, result, k, p_skip * totvert + k, 1);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, k, p_skip * totvert + k, 1);
*mv = *inMV;
if (vert_part_index != NULL) {
@@ -420,7 +408,7 @@ static DerivedMesh *applyModifier(
ChildParticle *cpa = psys->child + (p - psys->totpart);
pa = psys->particles + (between ? cpa->pa[0] : cpa->parent);
}
- psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, sim.psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, sim.psys->part->from, pa, hairmat);
copy_m3_m4(mat, hairmat);
/* to quaternion */
mat3_to_quat(frame, mat);
@@ -482,8 +470,8 @@ static DerivedMesh *applyModifier(
}
/* create edges and adjust edge vertex indices*/
- DM_copy_edge_data(dm, result, 0, p_skip * totedge, totedge);
- MEdge *me = CDDM_get_edges(result) + p_skip * totedge;
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, p_skip * totedge, totedge);
+ MEdge *me = &result->medge[p_skip * totedge];
for (k = 0; k < totedge; k++, me++) {
me->v1 += p_skip * totvert;
me->v2 += p_skip * totvert;
@@ -495,7 +483,7 @@ static DerivedMesh *applyModifier(
MPoly *inMP = orig_mpoly + k;
MPoly *mp = mpoly + p_skip * totpoly + k;
- DM_copy_poly_data(dm, result, k, p_skip * totpoly + k, 1);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, k, p_skip * totpoly + k, 1);
*mp = *inMP;
mp->loopstart += p_skip * totloop;
@@ -504,7 +492,7 @@ static DerivedMesh *applyModifier(
MLoop *ml = mloop + mp->loopstart;
int j = mp->totloop;
- DM_copy_loop_data(dm, result, inMP->loopstart, mp->loopstart, j);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, inMP->loopstart, mp->loopstart, j);
for (; j; j--, ml++, inML++) {
ml->v = inML->v + (p_skip * totvert);
ml->e = inML->e + (p_skip * totedge);
@@ -534,7 +522,7 @@ static DerivedMesh *applyModifier(
MEM_SAFE_FREE(vert_part_index);
MEM_SAFE_FREE(vert_part_value);
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
@@ -549,17 +537,23 @@ ModifierTypeInfo modifierType_ParticleInstance = {
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 80b6c16b382..d06986ca80a 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -41,34 +41,34 @@
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_global.h"
+#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
-#include "MOD_util.h"
+#include "DEG_depsgraph_query.h"
+#include "MOD_util.h"
static void initData(ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
psmd->psys = NULL;
- psmd->dm_final = NULL;
- psmd->dm_deformed = NULL;
+ psmd->mesh_final = NULL;
+ psmd->mesh_original = NULL;
psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
}
static void freeData(ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
- if (psmd->dm_final) {
- psmd->dm_final->needsFree = true;
- psmd->dm_final->release(psmd->dm_final);
- psmd->dm_final = NULL;
- if (psmd->dm_deformed) {
- psmd->dm_deformed->needsFree = true;
- psmd->dm_deformed->release(psmd->dm_deformed);
- psmd->dm_deformed = NULL;
+ if (psmd->mesh_final) {
+ BKE_id_free(NULL, psmd->mesh_final);
+ psmd->mesh_final = NULL;
+ if (psmd->mesh_original) {
+ BKE_id_free(NULL, psmd->mesh_original);
+ psmd->mesh_original = NULL;
}
}
psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
@@ -79,17 +79,17 @@ static void freeData(ModifierData *md)
psmd->psys->flag |= PSYS_DELETE;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
#if 0
const ParticleSystemModifierData *psmd = (const ParticleSystemModifierData *) md;
#endif
ParticleSystemModifierData *tpsmd = (ParticleSystemModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
- tpsmd->dm_final = NULL;
- tpsmd->dm_deformed = NULL;
+ tpsmd->mesh_final = NULL;
+ tpsmd->mesh_original = NULL;
tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0;
}
@@ -101,47 +101,42 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
/* saves the current emitter state for a particle system and calculates particles */
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int UNUSED(numVerts),
- ModifierApplyFlag flag)
+ int numVerts)
{
- DerivedMesh *dm = derivedData;
+ Mesh *mesh_src = mesh;
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
ParticleSystem *psys = NULL;
- bool needsFree = false;
/* float cfra = BKE_scene_frame_get(md->scene); */ /* UNUSED */
- if (ob->particlesystem.first)
+ if (ctx->object->particlesystem.first)
psys = psmd->psys;
else
return;
- if (!psys_check_enabled(ob, psys, (flag & MOD_APPLY_RENDER) != 0))
+ if (!psys_check_enabled(ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0))
return;
- if (dm == NULL) {
- dm = get_dm(ob, NULL, NULL, vertexCos, false, true);
-
- if (!dm)
+ if (mesh_src == NULL) {
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, vertexCos, numVerts, false, true);
+ if (mesh_src == NULL) {
return;
-
- needsFree = true;
+ }
}
/* clear old dm */
- if (psmd->dm_final) {
- psmd->dm_final->needsFree = true;
- psmd->dm_final->release(psmd->dm_final);
- if (psmd->dm_deformed) {
- psmd->dm_deformed->needsFree = 1;
- psmd->dm_deformed->release(psmd->dm_deformed);
- psmd->dm_deformed = NULL;
+ if (psmd->mesh_final) {
+ BKE_id_free(NULL, psmd->mesh_final);
+ psmd->mesh_final = NULL;
+ if (psmd->mesh_original) {
+ BKE_id_free(NULL, psmd->mesh_original);
+ psmd->mesh_original = NULL;
}
}
else if (psmd->flag & eParticleSystemFlag_file_loaded) {
- /* in file read dm just wasn't saved in file so no need to reset everything */
+ /* in file read mesh just wasn't saved in file so no need to reset everything */
psmd->flag &= ~eParticleSystemFlag_file_loaded;
}
else {
@@ -149,66 +144,87 @@ static void deformVerts(
psys->recalc |= PSYS_RECALC_RESET;
}
- /* make new dm */
- psmd->dm_final = CDDM_copy(dm);
- CDDM_apply_vert_coords(psmd->dm_final, vertexCos);
- CDDM_calc_normals(psmd->dm_final);
-
- if (needsFree) {
- dm->needsFree = true;
- dm->release(dm);
- }
+ /* make new mesh */
+ psmd->mesh_final = BKE_mesh_copy_for_eval(mesh_src, false);
+ BKE_mesh_apply_vert_coords(psmd->mesh_final, vertexCos);
+ BKE_mesh_calc_normals(psmd->mesh_final);
+
+ BKE_mesh_tessface_ensure(psmd->mesh_final);
+
+ if (!psmd->mesh_final->runtime.deformed_only) {
+ /* Get the original mesh from the object, this is what the particles
+ * are attached to so in case of non-deform modifiers we need to remap
+ * them to the final mesh (typically subdivision surfaces). */
+ Mesh *mesh_original = NULL;
+
+ if (ctx->object->type == OB_MESH) {
+ BMEditMesh *edit_btmesh = BKE_editmesh_from_object(ctx->object);
+
+ if (edit_btmesh) {
+ /* In edit mode get directly from the edit mesh. */
+ psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(edit_btmesh->bm, 0);
+ }
+ else {
+ /* Otherwise get regular mesh. */
+ mesh_original = ctx->object->data;
+ }
+ }
+ else {
+ mesh_original = mesh_src;
+ }
- /* protect dm */
- psmd->dm_final->needsFree = false;
+ if (mesh_original) {
+ /* Make a persistent copy of the mesh. We don't actually need
+ * all this data, just some topology for remapping. Could be
+ * optimized once. */
+ psmd->mesh_original = BKE_mesh_copy_for_eval(mesh_original, false);
+ }
- DM_ensure_tessface(psmd->dm_final);
+ BKE_mesh_tessface_ensure(psmd->mesh_original);
+ }
- if (!psmd->dm_final->deformedOnly) {
- /* XXX Think we can assume here that if current DM is not only-deformed, ob->deformedOnly has been set.
- * This is awfully weak though. :| */
- if (ob->derivedDeform) {
- psmd->dm_deformed = CDDM_copy(ob->derivedDeform);
- }
- else { /* Can happen in some cases, e.g. when rendering from Edit mode... */
- psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data);
- }
- DM_ensure_tessface(psmd->dm_deformed);
+ if (mesh_src != psmd->mesh_final && mesh_src != mesh) {
+ BKE_id_free(NULL, mesh_src);
}
/* report change in mesh structure */
- if (psmd->dm_final->getNumVerts(psmd->dm_final) != psmd->totdmvert ||
- psmd->dm_final->getNumEdges(psmd->dm_final) != psmd->totdmedge ||
- psmd->dm_final->getNumTessFaces(psmd->dm_final) != psmd->totdmface)
+ if (psmd->mesh_final->totvert != psmd->totdmvert ||
+ psmd->mesh_final->totedge != psmd->totdmedge ||
+ psmd->mesh_final->totface != psmd->totdmface)
{
psys->recalc |= PSYS_RECALC_RESET;
- psmd->totdmvert = psmd->dm_final->getNumVerts(psmd->dm_final);
- psmd->totdmedge = psmd->dm_final->getNumEdges(psmd->dm_final);
- psmd->totdmface = psmd->dm_final->getNumTessFaces(psmd->dm_final);
+ psmd->totdmvert = psmd->mesh_final->totvert;
+ psmd->totdmedge = psmd->mesh_final->totedge;
+ psmd->totdmface = psmd->mesh_final->totface;
}
- if (!(ob->transflag & OB_NO_PSYS_UPDATE)) {
+ if (!(ctx->object->transflag & OB_NO_PSYS_UPDATE)) {
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- particle_system_update(G.main, md->scene, ob, psys, (flag & MOD_APPLY_RENDER) != 0);
+ particle_system_update(ctx->depsgraph, scene, ctx->object, psys, (ctx->flag & MOD_APPLY_RENDER) != 0);
psmd->flag |= eParticleSystemFlag_psys_updated;
}
}
-/* disabled particles in editmode for now, until support for proper derivedmesh
+/* disabled particles in editmode for now, until support for proper evaluated mesh
* updates is coded */
#if 0
static void deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, Object *ob, BMEditMesh *editData,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = derivedData;
-
- if (!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+ const bool do_temp_mesh = (mesh == NULL);
+ if (do_temp_mesh) {
+ mesh = BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name);
+ BM_mesh_bm_to_me(NULL, editData->bm, mesh, &((BMeshToMeshParams){0}));
+ }
- deformVerts(md, ob, dm, vertexCos, numVerts);
+ deformVerts(md, ob, mesh, vertexCos, numVerts);
- if (!derivedData) dm->release(dm);
+ if (derivedData) {
+ BKE_id_free(NULL, mesh);
+ }
}
#endif
@@ -225,17 +241,23 @@ ModifierTypeInfo modifierType_ParticleSystem = {
eModifierTypeFlag_EnableInEditmode */,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
- /* deformVertsEM */ NULL,
/* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index bd25f2cc727..6d0f88df492 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -30,15 +30,16 @@
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_DerivedMesh.h"
-
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "MOD_modifiertypes.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@@ -61,28 +62,30 @@ static void initData(ModifierData *md)
#ifdef WITH_MOD_REMESH
-static void init_dualcon_mesh(DualConInput *mesh, DerivedMesh *dm)
+static void init_dualcon_mesh(DualConInput *input, Mesh *mesh)
{
- memset(mesh, 0, sizeof(DualConInput));
+ memset(input, 0, sizeof(DualConInput));
- mesh->co = (void *)dm->getVertArray(dm);
- mesh->co_stride = sizeof(MVert);
- mesh->totco = dm->getNumVerts(dm);
+ input->co = (void *)mesh->mvert;
+ input->co_stride = sizeof(MVert);
+ input->totco = mesh->totvert;
- mesh->mloop = (void *)dm->getLoopArray(dm);
- mesh->loop_stride = sizeof(MLoop);
- mesh->looptri = (void *)dm->getLoopTriArray(dm);
- mesh->tri_stride = sizeof(MLoopTri);
- mesh->tottri = dm->getNumLoopTri(dm);
+ input->mloop = (void *)mesh->mloop;
+ input->loop_stride = sizeof(MLoop);
- INIT_MINMAX(mesh->min, mesh->max);
- dm->getMinMax(dm, mesh->min, mesh->max);
+ BKE_mesh_runtime_looptri_ensure(mesh);
+ input->looptri = (void *)mesh->runtime.looptris.array;
+ input->tri_stride = sizeof(MLoopTri);
+ input->tottri = mesh->runtime.looptris.len;
+
+ INIT_MINMAX(input->min, input->max);
+ BKE_mesh_minmax(mesh, input->min, input->max);
}
/* simple structure to hold the output: a CDDM and two counters to
* keep track of the current elements */
typedef struct {
- DerivedMesh *dm;
+ Mesh *mesh;
int curvert, curface;
} DualConOutput;
@@ -97,33 +100,33 @@ static void *dualcon_alloc_output(int totvert, int totquad)
return NULL;
}
- output->dm = CDDM_new(totvert, 0, 0, 4 * totquad, totquad);
+ output->mesh = BKE_mesh_new_nomain(totvert, 0, 0, 4 * totquad, totquad);
return output;
}
static void dualcon_add_vert(void *output_v, const float co[3])
{
DualConOutput *output = output_v;
- DerivedMesh *dm = output->dm;
+ Mesh *mesh = output->mesh;
- assert(output->curvert < dm->getNumVerts(dm));
+ assert(output->curvert < mesh->totvert);
- copy_v3_v3(CDDM_get_verts(dm)[output->curvert].co, co);
+ copy_v3_v3(mesh->mvert[output->curvert].co, co);
output->curvert++;
}
static void dualcon_add_quad(void *output_v, const int vert_indices[4])
{
DualConOutput *output = output_v;
- DerivedMesh *dm = output->dm;
+ Mesh *mesh = output->mesh;
MLoop *mloop;
MPoly *cur_poly;
int i;
- assert(output->curface < dm->getNumPolys(dm));
+ assert(output->curface < mesh->totpoly);
- mloop = CDDM_get_loops(dm);
- cur_poly = CDDM_get_poly(dm, output->curface);
+ mloop = mesh->mloop;
+ cur_poly = &mesh->mpoly[output->curface];
cur_poly->loopstart = output->curface * 4;
cur_poly->totloop = 4;
@@ -133,22 +136,21 @@ static void dualcon_add_quad(void *output_v, const int vert_indices[4])
output->curface++;
}
-static DerivedMesh *applyModifier(
+static Mesh *applyModifier(
ModifierData *md,
- Object *UNUSED(ob),
- DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh)
{
RemeshModifierData *rmd;
DualConOutput *output;
DualConInput input;
- DerivedMesh *result;
+ Mesh *result;
DualConFlags flags = 0;
DualConMode mode = 0;
rmd = (RemeshModifierData *)md;
- init_dualcon_mesh(&input, dm);
+ init_dualcon_mesh(&input, mesh);
if (rmd->flag & MOD_REMESH_FLOOD_FILL)
flags |= DUALCON_FLOOD_FILL;
@@ -175,12 +177,12 @@ static DerivedMesh *applyModifier(
rmd->hermite_num,
rmd->scale,
rmd->depth);
- result = output->dm;
+ result = output->mesh;
MEM_freeN(output);
if (rmd->flag & MOD_REMESH_SMOOTH_SHADING) {
- MPoly *mpoly = CDDM_get_polys(result);
- int i, totpoly = result->getNumPolys(result);
+ MPoly *mpoly = result->mpoly;
+ int i, totpoly = result->totpoly;
/* Apply smooth shading to output faces */
for (i = 0; i < totpoly; i++) {
@@ -188,19 +190,19 @@ static DerivedMesh *applyModifier(
}
}
- CDDM_calc_edges(result);
- result->dirty |= DM_DIRTY_NORMALS;
+ BKE_mesh_calc_edges(result, true, false);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
#else /* !WITH_MOD_REMESH */
-static DerivedMesh *applyModifier(
- ModifierData *UNUSED(md), Object *UNUSED(ob),
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *UNUSED(md),
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh)
{
- return derivedData;
+ return mesh;
}
#endif /* !WITH_MOD_REMESH */
@@ -213,18 +215,25 @@ ModifierTypeInfo modifierType_Remesh = {
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_SupportsEditmode,
+
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 18a551f6daa..1de2a976fca 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -36,6 +36,7 @@
/* Screw modifier: revolves the edges about an axis */
#include <limits.h>
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -43,10 +44,10 @@
#include "BLI_alloca.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
#include "MOD_modifiertypes.h"
@@ -112,8 +113,8 @@ static void screwvert_iter_step(ScrewVertIter *iter)
}
}
-static DerivedMesh *dm_remove_doubles_on_axis(
- DerivedMesh *result, MVert *mvert_new, const uint totvert, const uint step_tot,
+static Mesh *mesh_remove_doubles_on_axis(
+ Mesh *result, MVert *mvert_new, const uint totvert, const uint step_tot,
const float axis_vec[3], const float axis_offset[3], const float merge_threshold)
{
const float merge_threshold_sq = SQUARE(merge_threshold);
@@ -157,7 +158,7 @@ static DerivedMesh *dm_remove_doubles_on_axis(
}
}
}
- result = CDDM_merge_verts(result, full_doubles_map, (int)(tot_doubles * (step_tot - 1)), CDDM_MERGE_VERTS_DUMP_IF_MAPPED);
+ result = BKE_mesh_merge_verts(result, full_doubles_map, (int)(tot_doubles * (step_tot - 1)), MESH_MERGE_VERTS_DUMP_IF_MAPPED);
MEM_freeN(full_doubles_map);
}
return result;
@@ -176,15 +177,14 @@ static void initData(ModifierData *md)
ltmd->merge_dist = 0.01f;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag flag)
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *meshData)
{
- DerivedMesh *dm = derivedData;
- DerivedMesh *result;
+ Mesh *mesh = meshData;
+ Mesh *result;
ScrewModifierData *ltmd = (ScrewModifierData *) md;
- const bool use_render_params = (flag & MOD_APPLY_RENDER) != 0;
+ const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER) != 0;
int *origindex;
int mpoly_index = 0;
@@ -208,15 +208,15 @@ static DerivedMesh *applyModifier(
};
unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
- const unsigned int totvert = (unsigned int)dm->getNumVerts(dm);
- const unsigned int totedge = (unsigned int)dm->getNumEdges(dm);
- const unsigned int totpoly = (unsigned int)dm->getNumPolys(dm);
+ const unsigned int totvert = (unsigned int)mesh->totvert;
+ const unsigned int totedge = (unsigned int)mesh->totedge;
+ const unsigned int totpoly = (unsigned int)mesh->totpoly;
unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */
unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */
/* UV Coords */
- const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
+ const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot);
float uv_u_scale;
float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX};
@@ -251,7 +251,7 @@ static DerivedMesh *applyModifier(
/* don't do anything? */
if (!totvert)
- return CDDM_from_template(dm, 0, 0, 0, 0, 0);
+ return BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0);
switch (ltmd->axis) {
case 0:
@@ -272,7 +272,7 @@ static DerivedMesh *applyModifier(
if (ltmd->ob_axis) {
/* calc the matrix relative to the axis object */
- invert_m4_m4(mtx_tmp_a, ob->obmat);
+ invert_m4_m4(mtx_tmp_a, ctx->object->obmat);
copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat);
mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv);
@@ -376,24 +376,24 @@ static DerivedMesh *applyModifier(
uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f));
}
- result = CDDM_from_template(dm, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys);
+ result = BKE_mesh_new_nomain_from_template(mesh, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys);
/* copy verts from mesh */
- mvert_orig = dm->getVertArray(dm);
- medge_orig = dm->getEdgeArray(dm);
+ mvert_orig = mesh->mvert;
+ medge_orig = mesh->medge;
- mvert_new = result->getVertArray(result);
- mpoly_new = result->getPolyArray(result);
- mloop_new = result->getLoopArray(result);
- medge_new = result->getEdgeArray(result);
+ mvert_new = result->mvert;
+ mpoly_new = result->mpoly;
+ mloop_new = result->mloop;
+ medge_new = result->medge;
- if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) {
- CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys);
+ if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) {
+ CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys);
}
- origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
+ origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
- DM_copy_vert_data(dm, result, 0, 0, (int)totvert); /* copy first otherwise this overwrites our own vertex normals */
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)totvert);
if (mloopuv_layers_tot) {
float zero_co[3] = {0};
@@ -403,7 +403,7 @@ static DerivedMesh *applyModifier(
if (mloopuv_layers_tot) {
unsigned int uv_lay;
for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
- mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, (int)uv_lay);
+ mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->ldata, CD_MLOOPUV, (int)uv_lay);
}
if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) {
@@ -439,8 +439,8 @@ static DerivedMesh *applyModifier(
if (totpoly) {
MPoly *mp_orig;
- mpoly_orig = dm->getPolyArray(dm);
- mloop_orig = dm->getLoopArray(dm);
+ mpoly_orig = mesh->mpoly;
+ mloop_orig = mesh->mloop;
edge_poly_map = MEM_malloc_arrayN(totedge, sizeof(*edge_poly_map), __func__);
memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge);
@@ -851,7 +851,7 @@ static DerivedMesh *applyModifier(
madd_v3_v3fl(mat[3], axis_vec, screw_ofs * ((float)step / (float)(step_tot - 1)));
/* copy a slice */
- DM_copy_vert_data(dm, result, 0, (int)varray_stride, (int)totvert);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)varray_stride, (int)totvert);
mv_new_base = mvert_new;
mv_new = &mvert_new[varray_stride]; /* advance to the next slice */
@@ -954,7 +954,7 @@ static DerivedMesh *applyModifier(
/* Polygon */
if (has_mpoly_orig) {
- DM_copy_poly_data(dm, result, (int)mpoly_index_orig, (int)mpoly_index, 1);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, (int)mpoly_index_orig, (int)mpoly_index, 1);
origindex[mpoly_index] = (int)mpoly_index_orig;
}
else {
@@ -969,10 +969,11 @@ static DerivedMesh *applyModifier(
/* Loop-Custom-Data */
if (has_mloop_orig) {
int l_index = (int)(ml_new - mloop_new);
- DM_copy_loop_data(dm, result, (int)mloop_index_orig[0], l_index + 0, 1);
- DM_copy_loop_data(dm, result, (int)mloop_index_orig[1], l_index + 1, 1);
- DM_copy_loop_data(dm, result, (int)mloop_index_orig[1], l_index + 2, 1);
- DM_copy_loop_data(dm, result, (int)mloop_index_orig[0], l_index + 3, 1);
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 0, 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[1], l_index + 1, 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[1], l_index + 2, 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, (int)mloop_index_orig[0], l_index + 3, 1);
if (mloopuv_layers_tot) {
unsigned int uv_lay;
@@ -1094,41 +1095,28 @@ static DerivedMesh *applyModifier(
}
if ((ltmd->flag & MOD_SCREW_MERGE) && (screw_ofs == 0.0f)) {
- DerivedMesh *result_prev = result;
- result = dm_remove_doubles_on_axis(
+ Mesh *result_prev = result;
+ result = mesh_remove_doubles_on_axis(
result, mvert_new, totvert, step_tot,
axis_vec, ltmd->ob_axis ? mtx_tx[3] : NULL, ltmd->merge_dist);
if (result != result_prev) {
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
}
if ((ltmd->flag & MOD_SCREW_NORMAL_CALC) == 0) {
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
return result;
}
-
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- ScrewModifierData *ltmd = (ScrewModifierData *) md;
-
- if (ltmd->ob_axis) {
- DagNode *curNode = dag_get_node(ctx->forest, ltmd->ob_axis);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "Screw Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ScrewModifierData *ltmd = (ScrewModifierData *)md;
if (ltmd->ob_axis != NULL) {
DEG_add_object_relation(ctx->node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Screw Modifier");
}
}
@@ -1153,17 +1141,23 @@ ModifierTypeInfo modifierType_Screw = {
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index e7453feef5e..764e99866fd 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -34,40 +34,39 @@
#include "BLI_math.h"
+#include "DNA_mesh_types.h"
#include "DNA_key_types.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_key.h"
#include "BKE_particle.h"
#include "MOD_modifiertypes.h"
static void deformVerts(
- ModifierData *UNUSED(md), Object *ob,
- DerivedMesh *UNUSED(derivedData),
+ ModifierData *UNUSED(md), const ModifierEvalContext *ctx,
+ Mesh *UNUSED(mesh),
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
- Key *key = BKE_key_from_object(ob);
+ Key *key = BKE_key_from_object(ctx->object);
if (key && key->block.first) {
int deformedVerts_tot;
BKE_key_evaluate_object_ex(
- ob, &deformedVerts_tot,
+ ctx->object, &deformedVerts_tot,
(float *)vertexCos, sizeof(*vertexCos) * numVerts);
}
}
static void deformMatrices(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
{
- Key *key = BKE_key_from_object(ob);
- KeyBlock *kb = BKE_keyblock_from_object(ob);
+ Key *key = BKE_key_from_object(ctx->object);
+ KeyBlock *kb = BKE_keyblock_from_object(ctx->object);
float scale[3][3];
(void)vertexCos; /* unused */
@@ -75,39 +74,39 @@ static void deformMatrices(
if (kb && kb->totelem == numVerts && kb != key->refkey) {
int a;
- if (ob->shapeflag & OB_SHAPE_LOCK) scale_m3_fl(scale, 1);
+ if (ctx->object->shapeflag & OB_SHAPE_LOCK) scale_m3_fl(scale, 1);
else scale_m3_fl(scale, kb->curval);
for (a = 0; a < numVerts; a++)
copy_m3_m3(defMats[a], scale);
}
- deformVerts(md, ob, derivedData, vertexCos, numVerts, 0);
+ deformVerts(md, ctx, mesh, vertexCos, numVerts);
}
static void deformVertsEM(
- ModifierData *md, Object *ob,
+ ModifierData *md, const ModifierEvalContext *ctx,
struct BMEditMesh *UNUSED(editData),
- DerivedMesh *derivedData,
+ Mesh *mesh,
float (*vertexCos)[3],
int numVerts)
{
- Key *key = BKE_key_from_object(ob);
+ Key *key = BKE_key_from_object(ctx->object);
if (key && key->type == KEY_RELATIVE)
- deformVerts(md, ob, derivedData, vertexCos, numVerts, 0);
+ deformVerts(md, ctx, mesh, vertexCos, numVerts);
}
static void deformMatricesEM(
- ModifierData *UNUSED(md), Object *ob,
+ ModifierData *UNUSED(md), const ModifierEvalContext *ctx,
struct BMEditMesh *UNUSED(editData),
- DerivedMesh *UNUSED(derivedData),
+ Mesh *UNUSED(mesh),
float (*vertexCos)[3],
float (*defMats)[3][3],
int numVerts)
{
- Key *key = BKE_key_from_object(ob);
- KeyBlock *kb = BKE_keyblock_from_object(ob);
+ Key *key = BKE_key_from_object(ctx->object);
+ KeyBlock *kb = BKE_keyblock_from_object(ctx->object);
float scale[3][3];
(void)vertexCos; /* unused */
@@ -132,17 +131,23 @@ ModifierTypeInfo modifierType_ShapeKey = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ NULL,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ deformMatricesEM,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ NULL,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index c30be7d3a11..dd4530b066f 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -35,17 +35,20 @@
#include <string.h>
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_shrinkwrap.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph_query.h"
#include "MOD_util.h"
@@ -81,7 +84,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md;
return !smd->target;
@@ -97,69 +100,75 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag flag)
+ int numVerts)
{
- DerivedMesh *dm = derivedData;
- CustomDataMask dataMask = requiredDataMask(ob, md);
- bool forRender = (flag & MOD_APPLY_RENDER) != 0;
+ ShrinkwrapModifierData *swmd = (ShrinkwrapModifierData *)md;
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ Mesh *mesh_src = NULL;
- /* ensure we get a CDDM with applied vertex coords */
- if (dataMask) {
- dm = get_cddm(ob, NULL, dm, vertexCos, dependsOnNormals(md));
+ if (ctx->object->type == OB_MESH) {
+ /* mesh_src is only needed for vgroups. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
}
- shrinkwrapModifier_deform((ShrinkwrapModifierData *)md, ob, dm, vertexCos, numVerts, forRender);
+ struct MDeformVert *dvert = NULL;
+ int defgrp_index = -1;
+ MOD_get_vgroup(ctx->object, mesh_src, swmd->vgroup_name, &dvert, &defgrp_index);
- if (dm != derivedData)
- dm->release(dm);
+ shrinkwrapModifier_deform(swmd, scene, ctx->object, mesh_src, dvert, defgrp_index, vertexCos, numVerts);
+
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData, DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = derivedData;
- CustomDataMask dataMask = requiredDataMask(ob, md);
-
- /* ensure we get a CDDM with applied vertex coords */
- if (dataMask) {
- dm = get_cddm(ob, editData, dm, vertexCos, dependsOnNormals(md));
- }
+ ShrinkwrapModifierData *swmd = (ShrinkwrapModifierData *)md;
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
- shrinkwrapModifier_deform((ShrinkwrapModifierData *)md, ob, dm, vertexCos, numVerts, false);
-
- if (dm != derivedData)
- dm->release(dm);
-}
-
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md;
+ struct MDeformVert *dvert = NULL;
+ int defgrp_index = -1;
+ MOD_get_vgroup(ctx->object, mesh_src, swmd->vgroup_name, &dvert, &defgrp_index);
- if (smd->target)
- dag_add_relation(ctx->forest, dag_get_node(ctx->forest, smd->target), ctx->obNode,
- DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
+ shrinkwrapModifier_deform(swmd, scene, ctx->object, mesh_src, dvert, defgrp_index, vertexCos, numVerts);
- if (smd->auxTarget)
- dag_add_relation(ctx->forest, dag_get_node(ctx->forest, smd->auxTarget), ctx->obNode,
- DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
+ CustomDataMask mask = 0;
+
+ if (BKE_shrinkwrap_needs_normals(smd->shrinkType, smd->shrinkMode)) {
+ mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ }
+
if (smd->target != NULL) {
DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
- DEG_add_object_relation(ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_object_relation_with_customdata(ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, mask, "Shrinkwrap Modifier");
+ if (smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ DEG_add_special_eval_flag(ctx->node, &smd->target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
}
if (smd->auxTarget != NULL) {
DEG_add_object_relation(ctx->node, smd->auxTarget, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
- DEG_add_object_relation(ctx->node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ DEG_add_object_relation_with_customdata(ctx->node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, mask, "Shrinkwrap Modifier");
+ if (smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ DEG_add_special_eval_flag(ctx->node, &smd->auxTarget->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
+ }
}
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
}
static bool dependsOnNormals(ModifierData *md)
@@ -184,17 +193,23 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index d14310d9199..f1ad93e7182 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -32,22 +32,24 @@
* \ingroup modifiers
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
-
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
+#include "bmesh.h"
+
#define BEND_EPS 0.000001f
/* Re-maps the indices for X Y Z by shifting them up and wrapping, such that
@@ -184,11 +186,10 @@ static void simpleDeform_bend(const float factor, const int axis, const float dc
/* simple deform modifier */
static void SimpleDeformModifier_do(
- SimpleDeformModifierData *smd, struct Object *ob, struct DerivedMesh *dm,
+ SimpleDeformModifierData *smd, struct Object *ob, struct Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
const float base_limit[2] = {0.0f, 0.0f};
-
int i;
float smd_limit[2], smd_factor;
SpaceTransform *transf = NULL, tmp_transf;
@@ -285,7 +286,7 @@ static void SimpleDeformModifier_do(
}
}
- modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup);
+ MOD_get_vgroup(ob, mesh, smd->vgroup_name, &dvert, &vgroup);
const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0;
const uint *axis_map = axis_map_table[(smd->mode != MOD_SIMPLEDEFORM_MODE_BEND) ? deform_axis : 2];
@@ -370,62 +371,56 @@ static void foreachObjectLink(
walk(userData, ob, &smd->origin, IDWALK_CB_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
-
- if (smd->origin)
- dag_add_relation(ctx->forest, dag_get_node(ctx->forest, smd->origin), ctx->obNode, DAG_RL_OB_DATA, "SimpleDeform Modifier");
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
if (smd->origin != NULL) {
DEG_add_object_relation(ctx->node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier");
}
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
- DerivedMesh *dm = derivedData;
- CustomDataMask dataMask = requiredDataMask(ob, md);
+ SimpleDeformModifierData *sdmd = (SimpleDeformModifierData *)md;
+ Mesh *mesh_src = NULL;
- /* we implement requiredDataMask but thats not really useful since
- * mesh_calc_modifiers pass a NULL derivedData */
- if (dataMask)
- dm = get_dm(ob, NULL, dm, NULL, false, false);
+ if (ctx->object->type == OB_MESH && sdmd->vgroup_name[0] != '\0') {
+ /* mesh_src is only needed for vgroups. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
+ }
- SimpleDeformModifier_do((SimpleDeformModifierData *)md, ob, dm, vertexCos, numVerts);
+ SimpleDeformModifier_do(sdmd, ctx->object, mesh_src, vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob,
+ ModifierData *md, const ModifierEvalContext *ctx,
struct BMEditMesh *editData,
- DerivedMesh *derivedData,
+ struct Mesh *mesh,
float (*vertexCos)[3],
int numVerts)
{
- DerivedMesh *dm = derivedData;
- CustomDataMask dataMask = requiredDataMask(ob, md);
+ SimpleDeformModifierData *sdmd = (SimpleDeformModifierData *)md;
+ Mesh *mesh_src = NULL;
- /* we implement requiredDataMask but thats not really useful since
- * mesh_calc_modifiers pass a NULL derivedData */
- if (dataMask)
- dm = get_dm(ob, editData, dm, NULL, false, false);
+ if (ctx->object->type == OB_MESH && sdmd->vgroup_name[0] != '\0') {
+ /* mesh_src is only needed for vgroups. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
+ }
- SimpleDeformModifier_do((SimpleDeformModifierData *)md, ob, dm, vertexCos, numVerts);
+ SimpleDeformModifier_do(sdmd, ctx->object, mesh_src, vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -442,17 +437,23 @@ ModifierTypeInfo modifierType_SimpleDeform = {
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 13e8f232b78..87d47769cdb 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -59,20 +59,20 @@
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_modifier_types.h"
#include "BLI_utildefines.h"
#include "BLI_array.h"
-#include "BLI_heap.h"
+#include "BLI_heap_simple.h"
#include "BLI_math.h"
#include "BLI_stack.h"
#include "BLI_bitmap.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
@@ -826,11 +826,11 @@ static int calc_edge_subdivisions(
#undef NUM_SUBDIVISIONS_MAX
}
-/* Take a DerivedMesh and subdivide its edges to keep skin nodes
+/* Take a Mesh and subdivide its edges to keep skin nodes
* reasonably close. */
-static DerivedMesh *subdivide_base(DerivedMesh *orig)
+static Mesh *subdivide_base(Mesh *orig)
{
- DerivedMesh *dm;
+ Mesh *result;
MVertSkin *orignode, *outnode;
MVert *origvert, *outvert;
MEdge *origedge, *outedge, *e;
@@ -840,12 +840,12 @@ static DerivedMesh *subdivide_base(DerivedMesh *orig)
int i, j, k, u, v;
float radrat;
- orignode = CustomData_get_layer(&orig->vertData, CD_MVERT_SKIN);
- origvert = orig->getVertArray(orig);
- origedge = orig->getEdgeArray(orig);
- origdvert = orig->getVertDataArray(orig, CD_MDEFORMVERT);
- totorigvert = orig->getNumVerts(orig);
- totorigedge = orig->getNumEdges(orig);
+ orignode = CustomData_get_layer(&orig->vdata, CD_MVERT_SKIN);
+ origvert = orig->mvert;
+ origedge = orig->medge;
+ origdvert = orig->dvert;
+ totorigvert = orig->totvert;
+ totorigedge = orig->totedge;
/* Get degree of all vertices */
degree = MEM_calloc_arrayN(totorigvert, sizeof(int), "degree");
@@ -864,20 +864,21 @@ static DerivedMesh *subdivide_base(DerivedMesh *orig)
MEM_freeN(degree);
- /* Allocate output derivedmesh */
- dm = CDDM_from_template(orig,
- totorigvert + totsubd,
- totorigedge + totsubd,
- 0, 0, 0);
+ /* Allocate output mesh */
+ result = BKE_mesh_new_nomain_from_template(
+ orig,
+ totorigvert + totsubd,
+ totorigedge + totsubd,
+ 0, 0, 0);
- outvert = dm->getVertArray(dm);
- outedge = dm->getEdgeArray(dm);
- outnode = CustomData_get_layer(&dm->vertData, CD_MVERT_SKIN);
- outdvert = CustomData_get_layer(&dm->vertData, CD_MDEFORMVERT);
+ outvert = result->mvert;
+ outedge = result->medge;
+ outnode = CustomData_get_layer(&result->vdata, CD_MVERT_SKIN);
+ outdvert = result->dvert;
/* Copy original vertex data */
- CustomData_copy_data(&orig->vertData,
- &dm->vertData,
+ CustomData_copy_data(&orig->vdata,
+ &result->vdata,
0, 0, totorigvert);
/* Subdivide edges */
@@ -961,7 +962,7 @@ static DerivedMesh *subdivide_base(DerivedMesh *orig)
MEM_freeN(edge_subd);
- return dm;
+ return result;
}
/******************************* Output *******************************/
@@ -1430,10 +1431,10 @@ static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd)
{
BMIter iter;
BMEdge *e;
- Heap *heap;
+ HeapSimple *heap;
float score;
- heap = BLI_heap_new();
+ heap = BLI_heapsimple_new();
BM_mesh_elem_hflag_disable_all(so->bm, BM_FACE, BM_ELEM_TAG, false);
@@ -1476,15 +1477,15 @@ static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd)
continue;
}
- BLI_heap_insert(heap, -score, e);
+ BLI_heapsimple_insert(heap, -score, e);
}
}
}
- while (!BLI_heap_is_empty(heap)) {
+ while (!BLI_heapsimple_is_empty(heap)) {
BMFace *adj[2];
- e = BLI_heap_pop_min(heap);
+ e = BLI_heapsimple_pop_min(heap);
if (BM_edge_face_pair(e, &adj[0], &adj[1])) {
/* If both triangles still free, and if they don't already
@@ -1501,7 +1502,7 @@ static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd)
}
}
- BLI_heap_free(heap, NULL);
+ BLI_heapsimple_free(heap, NULL);
BM_mesh_delete_hflag_tagged(so->bm, BM_ELEM_TAG, BM_EDGE | BM_FACE);
@@ -1819,12 +1820,12 @@ static BMesh *build_skin(SkinNode *skin_nodes,
return so.bm;
}
-static void skin_set_orig_indices(DerivedMesh *dm)
+static void skin_set_orig_indices(Mesh *mesh)
{
int *orig, totpoly;
- totpoly = dm->getNumPolys(dm);
- orig = CustomData_add_layer(&dm->polyData, CD_ORIGINDEX,
+ totpoly = mesh->totpoly;
+ orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX,
CD_CALLOC, NULL, totpoly);
copy_vn_i(orig, totpoly, ORIGINDEX_NONE);
}
@@ -1835,10 +1836,10 @@ static void skin_set_orig_indices(DerivedMesh *dm)
* 2) Generate node frames
* 3) Output vertices and polygons from frames, connections, and hulls
*/
-static DerivedMesh *base_skin(DerivedMesh *origdm,
- SkinModifierData *smd)
+static Mesh *base_skin(Mesh *origmesh,
+ SkinModifierData *smd)
{
- DerivedMesh *result;
+ Mesh *result;
MVertSkin *nodes;
BMesh *bm;
EMat *emat;
@@ -1851,13 +1852,13 @@ static DerivedMesh *base_skin(DerivedMesh *origdm,
int totvert, totedge;
bool has_valid_root = false;
- nodes = CustomData_get_layer(&origdm->vertData, CD_MVERT_SKIN);
+ nodes = CustomData_get_layer(&origmesh->vdata, CD_MVERT_SKIN);
- mvert = origdm->getVertArray(origdm);
- dvert = origdm->getVertDataArray(origdm, CD_MDEFORMVERT);
- medge = origdm->getEdgeArray(origdm);
- totvert = origdm->getNumVerts(origdm);
- totedge = origdm->getNumEdges(origdm);
+ mvert = origmesh->mvert;
+ dvert = origmesh->dvert;
+ medge = origmesh->medge;
+ totvert = origmesh->totvert;
+ totedge = origmesh->totedge;
BKE_mesh_vert_edge_map_create(&emap, &emapmem, medge, totvert, totedge);
@@ -1879,31 +1880,29 @@ static DerivedMesh *base_skin(DerivedMesh *origdm,
if (!bm)
return NULL;
- result = CDDM_from_bmesh(bm, false);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
BM_mesh_free(bm);
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
skin_set_orig_indices(result);
return result;
}
-static DerivedMesh *final_skin(SkinModifierData *smd,
- DerivedMesh *origdm)
+static Mesh *final_skin(SkinModifierData *smd, Mesh *mesh)
{
- DerivedMesh *dm;
+ Mesh *result;
/* Skin node layer is required */
- if (!CustomData_get_layer(&origdm->vertData, CD_MVERT_SKIN))
- return origdm;
-
- origdm = subdivide_base(origdm);
- dm = base_skin(origdm, smd);
+ if (!CustomData_get_layer(&mesh->vdata, CD_MVERT_SKIN))
+ return mesh;
- origdm->release(origdm);
+ mesh = subdivide_base(mesh);
+ result = base_skin(mesh, smd);
- return dm;
+ BKE_id_free(NULL, mesh);
+ return result;
}
@@ -1921,15 +1920,14 @@ static void initData(ModifierData *md)
smd->symmetry_axes = MOD_SKIN_SYMM_X;
}
-static DerivedMesh *applyModifier(ModifierData *md,
- Object *UNUSED(ob),
- DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh)
{
- DerivedMesh *result;
+ Mesh *result;
- if (!(result = final_skin((SkinModifierData *)md, dm)))
- return dm;
+ if (!(result = final_skin((SkinModifierData *)md, mesh)))
+ return mesh;
return result;
}
@@ -1947,17 +1945,23 @@ ModifierTypeInfo modifierType_Skin = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index 5f6d5ba58b5..d0db852550b 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -37,23 +37,27 @@
#include "MEM_guardedalloc.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_smoke_types.h"
#include "DNA_object_force_types.h"
+#include "DNA_mesh_types.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_smoke.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "MOD_modifiertypes.h"
@@ -68,12 +72,13 @@ static void initData(ModifierData *md)
smd->time = -1;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const SmokeModifierData *smd = (const SmokeModifierData *)md;
SmokeModifierData *tsmd = (SmokeModifierData *)target;
- smokeModifier_copy(smd, tsmd);
+ smokeModifier_free(tsmd);
+ smokeModifier_copy(smd, tsmd, flag);
}
static void freeData(ModifierData *md)
@@ -101,17 +106,18 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag flag)
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *me)
{
SmokeModifierData *smd = (SmokeModifierData *) md;
- if (flag & MOD_APPLY_ORCO)
- return dm;
+ if (ctx->flag & MOD_APPLY_ORCO) {
+ return me;
+ }
- return smokeModifier_do(smd, md->scene, ob, dm);
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ return smokeModifier_do(smd, ctx->depsgraph, scene, ctx->object, me);
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -131,32 +137,14 @@ static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md)
return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll;
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- SmokeModifierData *smd = (SmokeModifierData *) md;
-
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- /* Actual code uses get_collisionobjects */
-#ifdef WITH_LEGACY_DEPSGRAPH
- dag_add_collision_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, smd->domain->fluid_group, ctx->object->lay | ctx->scene->lay, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow");
- dag_add_collision_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, smd->domain->coll_group, ctx->object->lay | ctx->scene->lay, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll");
- dag_add_forcefield_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
-#else
- (void)ctx;
-#endif
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
SmokeModifierData *smd = (SmokeModifierData *)md;
if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
- /* Actual code uses get_collisionobjects */
- DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, smd->domain->fluid_group, ctx->object->lay | ctx->scene->lay, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow");
- DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, smd->domain->coll_group, ctx->object->lay | ctx->scene->lay, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll");
-
- DEG_add_forcefield_relations(ctx->node, ctx->scene, ctx->object, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
+ DEG_add_collision_relations(ctx->node, ctx->object, smd->domain->fluid_group, eModifierType_Smoke, is_flow_cb, "Smoke Flow");
+ DEG_add_collision_relations(ctx->node, ctx->object, smd->domain->coll_group, eModifierType_Smoke, is_coll_cb, "Smoke Coll");
+ DEG_add_forcefield_relations(ctx->node, ctx->object, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field");
}
}
@@ -191,17 +179,23 @@ ModifierTypeInfo modifierType_Smoke = {
eModifierTypeFlag_Single,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index 5aa38e2c693..8b62c2c1d7d 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -33,6 +33,7 @@
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_math.h"
@@ -40,7 +41,9 @@
#include "MEM_guardedalloc.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
#include "BKE_particle.h"
#include "BKE_deform.h"
@@ -58,7 +61,7 @@ static void initData(ModifierData *md)
smd->defgrp_name[0] = '\0';
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
SmoothModifierData *smd = (SmoothModifierData *) md;
short flag;
@@ -83,7 +86,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
}
static void smoothModifier_do(
- SmoothModifierData *smd, Object *ob, DerivedMesh *dm,
+ SmoothModifierData *smd, Object *ob, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
MDeformVert *dvert = NULL;
@@ -106,16 +109,16 @@ static void smoothModifier_do(
fac = smd->fac;
facm = 1 - fac;
- if (dm->getNumVerts(dm) == numVerts) {
- medges = dm->getEdgeArray(dm);
- numDMEdges = dm->getNumEdges(dm);
+ if (mesh != NULL) {
+ medges = mesh->medge;
+ numDMEdges = mesh->totedge;
}
else {
medges = NULL;
numDMEdges = 0;
}
- modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
/* NOTICE: this can be optimized a little bit by moving the
* if (dvert) out of the loop, if needed */
@@ -207,29 +210,37 @@ static void smoothModifier_do(
}
static void deformVerts(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+ ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = get_dm(ob, NULL, derivedData, NULL, false, false);
+ SmoothModifierData *smd = (SmoothModifierData *)md;
+ Mesh *mesh_src = NULL;
+
+ /* mesh_src is needed for vgroups, and taking edges into account. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
- smoothModifier_do((SmoothModifierData *)md, ob, dm,
- vertexCos, numVerts);
+ smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = get_dm(ob, editData, derivedData, NULL, false, false);
+ SmoothModifierData *smd = (SmoothModifierData *)md;
+ Mesh *mesh_src = NULL;
- smoothModifier_do((SmoothModifierData *)md, ob, dm,
- vertexCos, numVerts);
+ /* mesh_src is needed for vgroups, and taking edges into account. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
- if (dm != derivedData)
- dm->release(dm);
+ smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts);
+
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -243,17 +254,23 @@ ModifierTypeInfo modifierType_Smooth = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 95aa8f985fa..3f45e37e777 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -35,27 +35,30 @@
#include <stdio.h>
#include "DNA_scene_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_force_types.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_layer.h"
#include "BKE_particle.h"
#include "BKE_softbody.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "MOD_modifiertypes.h"
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *UNUSED(derivedData),
+ ModifierData *UNUSED(md), const ModifierEvalContext *ctx,
+ Mesh *UNUSED(derivedData),
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
- sbObjectStep(md->scene, ob, (float)md->scene->r.cfra, vertexCos, numVerts);
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ sbObjectStep(ctx->depsgraph, scene, ctx->object, DEG_get_ctime(ctx->depsgraph), vertexCos, numVerts);
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -63,27 +66,12 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
-static void updateDepgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgraphContext *ctx)
-{
- if (ctx->object->soft) {
-#ifdef WITH_LEGACY_DEPSGRAPH
- /* Actual code uses ccd_build_deflector_hash */
- dag_add_collision_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, ctx->object->soft->collision_group, ctx->object->lay, eModifierType_Collision, NULL, false, "Softbody Collision");
-
- dag_add_forcefield_relations(ctx->forest, ctx->scene, ctx->object, ctx->obNode, ctx->object->soft->effector_weights, true, 0, "Softbody Field");
-#else
- (void)ctx;
-#endif
- }
-}
-
static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgraphContext *ctx)
{
if (ctx->object->soft) {
/* Actual code uses ccd_build_deflector_hash */
- DEG_add_collision_relations(ctx->node, ctx->scene, ctx->object, ctx->object->soft->collision_group, ctx->object->lay, eModifierType_Collision, NULL, false, "Softbody Collision");
-
- DEG_add_forcefield_relations(ctx->node, ctx->scene, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field");
+ DEG_add_collision_relations(ctx->node, ctx->object, ctx->object->soft->collision_group, eModifierType_Collision, NULL, "Softbody Collision");
+ DEG_add_forcefield_relations(ctx->node, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field");
}
}
@@ -98,17 +86,23 @@ ModifierTypeInfo modifierType_Softbody = {
eModifierTypeFlag_Single,
/* copyData */ NULL,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ NULL,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 8cf288e19ae..f839f8aecf0 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -40,7 +40,6 @@
#include "BLI_bitmap.h"
#include "BLI_math.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
#include "BKE_particle.h"
#include "BKE_deform.h"
@@ -73,7 +72,7 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
* \param face_nors Precalculated face normals.
* \param r_vert_nors Return vert normals.
*/
-static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_vert_nors)[3])
+static void mesh_calc_hq_normal(Mesh *mesh, float (*face_nors)[3], float (*r_vert_nors)[3])
{
int i, numVerts, numEdges, numFaces;
MPoly *mpoly, *mp;
@@ -81,13 +80,13 @@ static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_ver
MEdge *medge, *ed;
MVert *mvert, *mv;
- numVerts = dm->getNumVerts(dm);
- numEdges = dm->getNumEdges(dm);
- numFaces = dm->getNumPolys(dm);
- mpoly = dm->getPolyArray(dm);
- medge = dm->getEdgeArray(dm);
- mvert = dm->getVertArray(dm);
- mloop = dm->getLoopArray(dm);
+ numVerts = mesh->totvert;
+ numEdges = mesh->totedge;
+ numFaces = mesh->totface;
+ mpoly = mesh->mpoly;
+ medge = mesh->medge;
+ mvert = mesh->mvert;
+ mloop = mesh->mloop;
/* we don't want to overwrite any referenced layers */
@@ -195,26 +194,25 @@ BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
r[2] += (float)a[2] * f;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
- DerivedMesh *result;
+ Mesh *result;
const SolidifyModifierData *smd = (SolidifyModifierData *) md;
MVert *mv, *mvert, *orig_mvert;
MEdge *ed, *medge, *orig_medge;
MLoop *ml, *mloop, *orig_mloop;
MPoly *mp, *mpoly, *orig_mpoly;
- const unsigned int numVerts = (unsigned int)dm->getNumVerts(dm);
- const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
- const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm);
- const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm);
+ const unsigned int numVerts = (unsigned int)mesh->totvert;
+ const unsigned int numEdges = (unsigned int)mesh->totedge;
+ const unsigned int numFaces = (unsigned int)mesh->totpoly;
+ const unsigned int numLoops = (unsigned int)mesh->totloop;
unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
/* only use material offsets if we have 2 or more materials */
- const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0;
+ const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0;
const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;
@@ -252,12 +250,12 @@ static DerivedMesh *applyModifier(
/* array size is doubled in case of using a shell */
const unsigned int stride = do_shell ? 2 : 1;
- modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
- orig_mvert = dm->getVertArray(dm);
- orig_medge = dm->getEdgeArray(dm);
- orig_mloop = dm->getLoopArray(dm);
- orig_mpoly = dm->getPolyArray(dm);
+ orig_mvert = mesh->mvert;
+ orig_medge = mesh->medge;
+ orig_mloop = mesh->mloop;
+ orig_mpoly = mesh->mpoly;
if (need_face_normals) {
/* calculate only face normals */
@@ -358,49 +356,50 @@ static DerivedMesh *applyModifier(
if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
vert_nors = MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq");
- dm_calc_normal(dm, face_nors, vert_nors);
+ mesh_calc_hq_normal(mesh, face_nors, vert_nors);
}
- result = CDDM_from_template(dm,
- (int)((numVerts * stride) + newVerts),
- (int)((numEdges * stride) + newEdges + rimVerts), 0,
- (int)((numLoops * stride) + newLoops),
- (int)((numFaces * stride) + newFaces));
+ result = BKE_mesh_new_nomain_from_template(
+ mesh,
+ (int)((numVerts * stride) + newVerts),
+ (int)((numEdges * stride) + newEdges + rimVerts), 0,
+ (int)((numLoops * stride) + newLoops),
+ (int)((numFaces * stride) + newFaces));
- mpoly = CDDM_get_polys(result);
- mloop = CDDM_get_loops(result);
- medge = CDDM_get_edges(result);
- mvert = CDDM_get_verts(result);
+ mpoly = result->mpoly;
+ mloop = result->mloop;
+ medge = result->medge;
+ mvert = result->mvert;
if (do_shell) {
- DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
- DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts);
- DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
- DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, (int)numEdges, (int)numEdges);
- DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
- DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, (int)numLoops, (int)numLoops);
- DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
- DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numFaces);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, (int)numFaces, (int)numFaces);
}
else {
int i, j;
- DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
for (i = 0, j = (int)numVerts; i < numVerts; i++) {
if (old_vert_arr[i] != INVALID_UNUSED) {
- DM_copy_vert_data(dm, result, i, j, 1);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, i, j, 1);
j++;
}
}
- DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges);
for (i = 0, j = (int)numEdges; i < numEdges; i++) {
if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
MEdge *ed_src, *ed_dst;
- DM_copy_edge_data(dm, result, i, j, 1);
+ CustomData_copy_data(&mesh->edata, &result->edata, i, j, 1);
ed_src = &medge[i];
ed_dst = &medge[j];
@@ -411,8 +410,8 @@ static DerivedMesh *applyModifier(
}
/* will be created later */
- DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
- DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numFaces);
}
#undef INVALID_UNUSED
@@ -445,7 +444,7 @@ static DerivedMesh *applyModifier(
unsigned int i;
mp = mpoly + numFaces;
- for (i = 0; i < dm->numPolyData; i++, mp++) {
+ for (i = 0; i < mesh->totpoly; i++, mp++) {
const int loop_end = mp->totloop - 1;
MLoop *ml2;
unsigned int e;
@@ -453,19 +452,19 @@ static DerivedMesh *applyModifier(
/* reverses the loop direction (MLoop.v as well as custom-data)
* MLoop.e also needs to be corrected too, done in a separate loop below. */
- ml2 = mloop + mp->loopstart + dm->numLoopData;
+ ml2 = mloop + mp->loopstart + mesh->totloop;
#if 0
for (j = 0; j < mp->totloop; j++) {
- CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
- mp->loopstart + (loop_end - j) + dm->numLoopData, 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart + j,
+ mp->loopstart + (loop_end - j) + mesh->totloop, 1);
}
#else
/* slightly more involved, keep the first vertex the same for the copy,
* ensures the diagonals in the new face match the original. */
j = 0;
for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) {
- CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
- mp->loopstart + (loop_end - j_prev) + dm->numLoopData, 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart + j,
+ mp->loopstart + (loop_end - j_prev) + mesh->totloop, 1);
}
#endif
@@ -480,7 +479,7 @@ static DerivedMesh *applyModifier(
}
ml2[loop_end].e = e;
- mp->loopstart += dm->numLoopData;
+ mp->loopstart += mesh->totloop;
for (j = 0; j < mp->totloop; j++) {
ml2[j].e += numEdges;
@@ -727,8 +726,8 @@ static DerivedMesh *applyModifier(
MEM_freeN(vert_nors);
/* must recalculate normals with vgroups since they can displace unevenly [#26888] */
- if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
- result->dirty |= DM_DIRTY_NORMALS;
+ if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
else if (do_shell) {
unsigned int i;
@@ -754,7 +753,9 @@ static DerivedMesh *applyModifier(
#define SOLIDIFY_SIDE_NORMALS
#ifdef SOLIDIFY_SIDE_NORMALS
- const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS);
+ /* Note that, due to the code setting cd_dirty_vert a few lines above,
+ * do_side_normals is always false. - Sybren */
+ const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL);
/* annoying to allocate these since we only need the edge verts, */
float (*edge_vert_nos)[3] = do_side_normals ? MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __func__) : NULL;
float nor[3];
@@ -772,7 +773,8 @@ static DerivedMesh *applyModifier(
}
/* add faces & edges */
- origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX);
+ origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
+ BLI_assert((numEdges == 0) || (origindex_edge != NULL));
ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */
orig_ed = &origindex_edge[(numEdges * stride) + newEdges];
for (i = 0; i < rimVerts; i++, ed++, orig_ed++) {
@@ -808,7 +810,7 @@ static DerivedMesh *applyModifier(
ed = medge + eidx;
/* copy most of the face settings */
- DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, (int)fidx, (int)((numFaces * stride) + i), 1);
mp->loopstart = (int)(j + (numLoops * stride));
mp->flag = mpoly[fidx].flag;
@@ -820,10 +822,10 @@ static DerivedMesh *applyModifier(
mp->totloop = 4;
- CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1);
- CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1);
- CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1);
- CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 0), 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 1), 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 2), 1);
+ CustomData_copy_data(&mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 3), 1);
if (flip == false) {
ml[j].v = ed->v1;
@@ -898,6 +900,7 @@ static DerivedMesh *applyModifier(
int k;
/* note, only the first vertex (lower half of the index) is calculated */
+ BLI_assert(ed->v1 < numVerts);
normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]);
for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
@@ -955,17 +958,23 @@ ModifierTypeInfo modifierType_Solidify = {
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 5a965c86a22..9c6bff6b291 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -35,21 +35,22 @@
#include <stddef.h>
-#include "DNA_scene_types.h"
#include "DNA_object_types.h"
-
-#ifdef WITH_OPENSUBDIV
-# include "DNA_userdef_types.h"
-#endif
+#include "DNA_scene_types.h"
+#include "DNA_mesh_types.h"
#include "BLI_utildefines.h"
-
#include "BKE_cdderivedmesh.h"
-#include "BKE_depsgraph.h"
#include "BKE_scene.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_mesh.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_modifiertypes.h"
#include "intern/CCGSubSurf.h"
@@ -60,17 +61,18 @@ static void initData(ModifierData *md)
smd->levels = 1;
smd->renderLevels = 2;
- smd->flags |= eSubsurfModifierFlag_SubsurfUv;
+ smd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ smd->quality = 3;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
#if 0
const SubsurfModifierData *smd = (const SubsurfModifierData *) md;
#endif
SubsurfModifierData *tsmd = (SubsurfModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
tsmd->emCache = tsmd->mCache = NULL;
}
@@ -89,111 +91,125 @@ static void freeData(ModifierData *md)
}
}
-static bool isDisabled(ModifierData *md, int useRenderParams)
+static bool isDisabled(const Scene *scene, ModifierData *md, bool useRenderParams)
{
SubsurfModifierData *smd = (SubsurfModifierData *) md;
int levels = (useRenderParams) ? smd->renderLevels : smd->levels;
- return get_render_subsurf_level(&md->scene->r, levels, useRenderParams != 0) == 0;
+ return get_render_subsurf_level(&scene->r, levels, useRenderParams != 0) == 0;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag flag)
+static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd,
+ const ModifierEvalContext *ctx)
{
- SubsurfModifierData *smd = (SubsurfModifierData *) md;
- SubsurfFlags subsurf_flags = 0;
- DerivedMesh *result;
- const bool useRenderParams = (flag & MOD_APPLY_RENDER) != 0;
- const bool isFinalCalc = (flag & MOD_APPLY_USECACHE) != 0;
-
-#ifdef WITH_OPENSUBDIV
- const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0;
-#endif
- bool do_cddm_convert = useRenderParams || !isFinalCalc;
-
- if (useRenderParams)
- subsurf_flags |= SUBSURF_USE_RENDER_PARAMS;
- if (isFinalCalc)
- subsurf_flags |= SUBSURF_IS_FINAL_CALC;
- if (ob->mode & OB_MODE_EDIT)
- subsurf_flags |= SUBSURF_IN_EDIT_MODE;
-
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): Not entirely correct, modifiers on top of subsurf
- * could be disabled.
- */
- if (md->next == NULL &&
- allow_gpu &&
- do_cddm_convert == false &&
- smd->use_opensubdiv)
- {
- if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
- modifier_setError(md, "OpenSubdiv is disabled in User Preferences");
- }
- else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) {
- modifier_setError(md, "OpenSubdiv is not supported in paint modes");
- }
- else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) {
- subsurf_flags |= SUBSURF_USE_GPU_BACKEND;
- do_cddm_convert = false;
- }
- else {
- modifier_setError(md, "OpenSubdiv is disabled due to dependencies");
- }
- }
-#endif
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
+ const int requested_levels = (use_render_params) ? smd->renderLevels
+ : smd->levels;
+ return get_render_subsurf_level(&scene->r,
+ requested_levels,
+ use_render_params);
+}
- result = subsurf_make_derived_from_derived(derivedData, smd, NULL, subsurf_flags);
- result->cd_flag = derivedData->cd_flag;
+static void subdiv_settings_init(SubdivSettings *settings,
+ const SubsurfModifierData *smd)
+{
+ settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
+ settings->is_adaptive = !settings->is_simple;
+ settings->level = smd->quality;
+ settings->vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY;
+ settings->fvar_linear_interpolation =
+ BKE_subdiv_fvar_interpolation_from_uv_smooth(smd->uv_smooth);
+}
- if (do_cddm_convert) {
- DerivedMesh *cddm = CDDM_copy(result);
- result->release(result);
- result = cddm;
- }
+/* Subdivide into fully qualified mesh. */
- return result;
+static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
+ const SubsurfModifierData *smd,
+ const ModifierEvalContext *ctx)
+{
+ const int level = subdiv_levels_for_modifier_get(smd, ctx);
+ settings->resolution = (1 << level) + 1;
}
-static DerivedMesh *applyModifierEM(
- ModifierData *md, Object *UNUSED(ob),
- struct BMEditMesh *UNUSED(editData),
- DerivedMesh *derivedData,
- ModifierApplyFlag flag)
+static Mesh *subdiv_as_mesh(SubsurfModifierData *smd,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ Subdiv *subdiv)
{
- SubsurfModifierData *smd = (SubsurfModifierData *) md;
- DerivedMesh *result;
- /* 'orco' using editmode flags would cause cache to be used twice in editbmesh_calc_modifiers */
- SubsurfFlags ss_flags = (flag & MOD_APPLY_ORCO) ? 0 : (SUBSURF_FOR_EDIT_MODE | SUBSURF_IN_EDIT_MODE);
-#ifdef WITH_OPENSUBDIV
- const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0;
- if (md->next == NULL && allow_gpu && smd->use_opensubdiv) {
- modifier_setError(md, "OpenSubdiv is not supported in edit mode");
+ Mesh *result = mesh;
+ SubdivToMeshSettings mesh_settings;
+ subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
+ if (mesh_settings.resolution < 3) {
+ return result;
}
-#endif
+ result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
+ return result;
+}
- result = subsurf_make_derived_from_derived(derivedData, smd, NULL, ss_flags);
+/* Subdivide into CCG. */
+static void subdiv_ccg_settings_init(SubdivToCCGSettings *settings,
+ const SubsurfModifierData *smd,
+ const ModifierEvalContext *ctx)
+{
+ const int level = subdiv_levels_for_modifier_get(smd, ctx);
+ settings->resolution = (1 << level) + 1;
+ settings->need_normal = true;
+ settings->need_mask = false;
+}
+
+static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ Subdiv *subdiv)
+{
+ Mesh *result = mesh;
+ SubdivToCCGSettings ccg_settings;
+ subdiv_ccg_settings_init(&ccg_settings, smd, ctx);
+ if (ccg_settings.resolution < 3) {
+ return result;
+ }
+ result = BKE_subdiv_to_ccg_mesh(subdiv, &ccg_settings, mesh);
return result;
}
-static bool dependsOnNormals(ModifierData *md)
+/* Modifier itself. */
+
+static Mesh *applyModifier(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
-#ifdef WITH_OPENSUBDIV
+ Mesh *result = mesh;
SubsurfModifierData *smd = (SubsurfModifierData *) md;
- if (smd->use_opensubdiv && md->next == NULL) {
- return true;
+ SubdivSettings subdiv_settings;
+ subdiv_settings_init(&subdiv_settings, smd);
+ if (subdiv_settings.level == 0) {
+ return result;
}
-#else
- UNUSED_VARS(md);
-#endif
- return false;
+ /* TODO(sergey): Try to re-use subdiv when possible. */
+ Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, ut also on empty input mesh. */
+ return result;
+ }
+ /* TODO(sergey): Decide whether we ever want to use CCG for subsurf,
+ * maybe when it is a last modifier in the stack?
+ */
+ if (true) {
+ result = subdiv_as_mesh(smd, ctx, mesh, subdiv);
+ }
+ else {
+ result = subdiv_as_ccg(smd, ctx, mesh, subdiv);
+ }
+ /* TODO(sergey): Cache subdiv somehow. */
+ // BKE_subdiv_stats_print(&subdiv->stats);
+ BKE_subdiv_free(subdiv);
+ return result;
}
ModifierTypeInfo modifierType_Subsurf = {
- /* name */ "Subsurf",
+ /* name */ "Subdivision",
/* structName */ "SubsurfModifierData",
/* structSize */ sizeof(SubsurfModifierData),
/* type */ eModifierTypeType_Constructive,
@@ -204,20 +220,26 @@ ModifierTypeInfo modifierType_Subsurf = {
eModifierTypeFlag_AcceptsCVs,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ applyModifierEM,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
- /* dependsOnNormals */ dependsOnNormals,
+ /* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index a64e05ffe1e..c5fa510f2e0 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -35,13 +35,18 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "BKE_bvhutils.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
-#include "BKE_cdderivedmesh.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
#include "MOD_modifiertypes.h"
#include "MOD_util.h"
@@ -66,9 +71,9 @@ static void freeData(ModifierData *md)
MEM_SAFE_FREE(surmd->bvhtree);
}
- if (surmd->dm) {
- surmd->dm->release(surmd->dm);
- surmd->dm = NULL;
+ if (surmd->mesh) {
+ BKE_id_free(NULL, surmd->mesh);
+ surmd->mesh = NULL;
}
MEM_SAFE_FREE(surmd->x);
@@ -83,41 +88,53 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int UNUSED(numVerts),
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
SurfaceModifierData *surmd = (SurfaceModifierData *) md;
+ const int cfra = (int)DEG_get_ctime(ctx->depsgraph);
- if (surmd->dm)
- surmd->dm->release(surmd->dm);
+ if (surmd->mesh) {
+ BKE_id_free(NULL, surmd->mesh);
+ }
- /* if possible use/create DerivedMesh */
- if (derivedData) surmd->dm = CDDM_copy(derivedData);
- else surmd->dm = get_dm(ob, NULL, NULL, NULL, false, false);
+ if (mesh) {
+ /* Not possible to use get_mesh() in this case as we'll modify its vertices
+ * and get_mesh() would return 'mesh' directly. */
+ BKE_id_copy_ex(
+ NULL, (ID *)mesh, (ID **)&surmd->mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ }
+ else {
+ surmd->mesh = MOD_deform_mesh_eval_get(ctx->object, NULL, NULL, NULL, numVerts, false, false);
+ }
- if (!ob->pd) {
+ if (!ctx->object->pd) {
printf("SurfaceModifier deformVerts: Should not happen!\n");
return;
}
- if (surmd->dm) {
+ if (surmd->mesh) {
unsigned int numverts = 0, i = 0;
int init = 0;
float *vec;
MVert *x, *v;
- CDDM_apply_vert_coords(surmd->dm, vertexCos);
- CDDM_calc_normals(surmd->dm);
+ BKE_mesh_apply_vert_coords(surmd->mesh, vertexCos);
+ BKE_mesh_calc_normals(surmd->mesh);
- numverts = surmd->dm->getNumVerts(surmd->dm);
+ numverts = surmd->mesh->totvert;
if (numverts != surmd->numverts ||
surmd->x == NULL ||
surmd->v == NULL ||
- md->scene->r.cfra != surmd->cfra + 1)
+ cfra != surmd->cfra + 1)
{
if (surmd->x) {
MEM_freeN(surmd->x);
@@ -138,8 +155,8 @@ static void deformVerts(
/* convert to global coordinates and calculate velocity */
for (i = 0, x = surmd->x, v = surmd->v; i < numverts; i++, x++, v++) {
- vec = CDDM_get_vert(surmd->dm, i)->co;
- mul_m4_v3(ob->obmat, vec);
+ vec = surmd->mesh->mvert[i].co;
+ mul_m4_v3(ctx->object->obmat, vec);
if (init)
v->co[0] = v->co[1] = v->co[2] = 0.0f;
@@ -149,17 +166,17 @@ static void deformVerts(
copy_v3_v3(x->co, vec);
}
- surmd->cfra = md->scene->r.cfra;
+ surmd->cfra = cfra;
if (surmd->bvhtree)
free_bvhtree_from_mesh(surmd->bvhtree);
else
surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh");
- if (surmd->dm->getNumPolys(surmd->dm))
- bvhtree_from_mesh_get(surmd->bvhtree, surmd->dm, BVHTREE_FROM_LOOPTRI, 2);
+ if (surmd->mesh->totpoly)
+ BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_LOOPTRI, 2);
else
- bvhtree_from_mesh_get(surmd->bvhtree, surmd->dm, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(surmd->bvhtree, surmd->mesh, BVHTREE_FROM_EDGES, 2);
}
}
@@ -174,17 +191,23 @@ ModifierTypeInfo modifierType_Surface = {
eModifierTypeFlag_NoUserAdd,
/* copyData */ NULL,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 84e2bf8941d..18bee0d2d59 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -1,3 +1,5 @@
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -6,12 +8,14 @@
#include "BLI_math_geom.h"
#include "BLI_task.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_bvhutils.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_editmesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
#include "MEM_guardedalloc.h"
@@ -132,12 +136,12 @@ static void freeData(ModifierData *md)
}
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const SurfaceDeformModifierData *smd = (const SurfaceDeformModifierData *)md;
SurfaceDeformModifierData *tsmd = (SurfaceDeformModifierData *)target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
if (smd->verts) {
tsmd->verts = MEM_dupallocN(smd->verts);
@@ -167,17 +171,6 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
walk(userData, ob, &smd->target, IDWALK_NOP);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
-
- if (smd->target) {
- DagNode *curNode = dag_get_node(ctx->forest, smd->target);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_DATA_DATA, "Surface Deform Modifier");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
@@ -918,14 +911,14 @@ static void bindVert(
static bool surfacedeformBind(
SurfaceDeformModifierData *smd, float (*vertexCos)[3],
- unsigned int numverts, unsigned int tnumpoly, unsigned int tnumverts, DerivedMesh *tdm)
+ unsigned int numverts, unsigned int tnumpoly, unsigned int tnumverts, Mesh *target)
{
BVHTreeFromMesh treeData = {NULL};
- const MVert *mvert = tdm->getVertArray(tdm);
- const MPoly *mpoly = tdm->getPolyArray(tdm);
- const MEdge *medge = tdm->getEdgeArray(tdm);
- const MLoop *mloop = tdm->getLoopArray(tdm);
- unsigned int tnumedges = tdm->getNumEdges(tdm);
+ const MVert *mvert = target->mvert;
+ const MPoly *mpoly = target->mpoly;
+ const MEdge *medge = target->medge;
+ const MLoop *mloop = target->mloop;
+ unsigned int tnumedges = target->totedge;
int adj_result;
SDefAdjacencyArray *vert_edges;
SDefAdjacency *adj_array;
@@ -959,7 +952,7 @@ static bool surfacedeformBind(
return false;
}
- bvhtree_from_mesh_get(&treeData, tdm, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 2);
if (treeData.tree == NULL) {
modifier_setError((ModifierData *)smd, "Out of memory");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
@@ -988,7 +981,7 @@ static bool surfacedeformBind(
.mpoly = mpoly,
.medge = medge,
.mloop = mloop,
- .looptri = tdm->getLoopTriArray(tdm),
+ .looptri = BKE_mesh_runtime_looptri_ensure(target),
.targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetBindVertArray"),
.bind_verts = smd->verts,
.vertexCos = vertexCos,
@@ -1105,10 +1098,14 @@ static void deformVert(
}
}
-static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], unsigned int numverts, Object *ob)
+static void surfacedeformModifier_do(
+ ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ float (*vertexCos)[3], unsigned int numverts, Object *ob)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
- DerivedMesh *tdm;
+ bool free_target;
+ Mesh *target;
unsigned int tnumverts, tnumpoly;
/* Exit function if bind flag is not set (free bind data if any) */
@@ -1117,22 +1114,14 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
return;
}
- /* Handle target mesh both in and out of edit mode */
- if (smd->target == md->scene->obedit) {
- BMEditMesh *em = BKE_editmesh_from_object(smd->target);
- tdm = em->derivedFinal;
- }
- else {
- tdm = smd->target->derivedFinal;
- }
-
- if (!tdm) {
+ target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(smd->target, &free_target);
+ if (!target) {
modifier_setError(md, "No valid target mesh");
return;
}
- tnumverts = tdm->getNumVerts(tdm);
- tnumpoly = tdm->getNumPolys(tdm);
+ tnumverts = target->totvert;
+ tnumpoly = target->totpoly;
/* If not bound, execute bind */
if (!(smd->verts)) {
@@ -1141,7 +1130,7 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
invert_m4_m4(tmp_mat, ob->obmat);
mul_m4_m4m4(smd->mat, tmp_mat, smd->target->obmat);
- if (!surfacedeformBind(smd, vertexCos, numverts, tnumpoly, tnumverts, tdm)) {
+ if (!surfacedeformBind(smd, vertexCos, numverts, tnumpoly, tnumverts, target)) {
smd->flags &= ~MOD_SDEF_BIND;
return;
}
@@ -1150,10 +1139,12 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
/* Poly count checks */
if (smd->numverts != numverts) {
modifier_setError(md, "Verts changed from %u to %u", smd->numverts, numverts);
+ if (free_target) BKE_id_free(NULL, target);
return;
}
else if (smd->numpoly != tnumpoly) {
modifier_setError(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly);
+ if (free_target) BKE_id_free(NULL, target);
return;
}
@@ -1165,8 +1156,7 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
};
if (data.targetCos != NULL) {
- bool tdm_vert_alloc;
- const MVert * const mvert = DM_get_vert_array(tdm, &tdm_vert_alloc);
+ const MVert * const mvert = target->mvert;
for (int i = 0; i < tnumverts; i++) {
mul_v3_m4v3(data.targetCos[i], smd->mat, mvert[i].co);
@@ -1180,33 +1170,32 @@ static void surfacedeformModifier_do(ModifierData *md, float (*vertexCos)[3], un
deformVert,
&settings);
- if (tdm_vert_alloc) {
- MEM_freeN((void *)mvert);
- }
-
MEM_freeN(data.targetCos);
}
+
+ if (target != NULL && free_target) {
+ BKE_id_free(NULL, target);
+ }
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *UNUSED(derivedData),
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *UNUSED(mesh),
+ float (*vertexCos)[3], int numVerts)
{
- surfacedeformModifier_do(md, vertexCos, numVerts, ob);
+ surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object);
}
static void deformVertsEM(
- ModifierData *md, Object *ob,
+ ModifierData *md, const ModifierEvalContext *ctx,
struct BMEditMesh *UNUSED(editData),
- DerivedMesh *UNUSED(derivedData),
+ Mesh *UNUSED(mesh),
float (*vertexCos)[3], int numVerts)
{
- surfacedeformModifier_do(md, vertexCos, numVerts, ob);
+ surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object);
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
@@ -1222,17 +1211,23 @@ ModifierTypeInfo modifierType_SurfaceDeform = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index cc313ba2d0c..0eba535ca9b 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -25,40 +25,48 @@
* \ingroup modifiers
*/
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_modifier.h"
+#include "BKE_mesh.h"
#include "bmesh.h"
#include "bmesh_tools.h"
#include "MOD_modifiertypes.h"
-static DerivedMesh *triangulate_dm(DerivedMesh *dm, const int quad_method, const int ngon_method)
+static Mesh *triangulate_mesh(Mesh *mesh, const int quad_method, const int ngon_method)
{
- DerivedMesh *result;
+ Mesh *result;
BMesh *bm;
int total_edges, i;
MEdge *me;
- bm = DM_to_bmesh(dm, true);
+ bm = BKE_mesh_to_bmesh_ex(
+ mesh,
+ &((struct BMeshCreateParams){0}),
+ &((struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .cd_mask_extra = CD_MASK_ORIGINDEX,
+ }));
BM_mesh_triangulate(bm, quad_method, ngon_method, false, NULL, NULL, NULL);
- result = CDDM_from_bmesh(bm, false);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
BM_mesh_free(bm);
- total_edges = result->getNumEdges(result);
- me = CDDM_get_edges(result);
+ total_edges = result->totedge;
+ me = result->medge;
/* force drawing of all edges (seems to be omitted in CDDM_from_bmesh) */
for (i = 0; i < total_edges; i++, me++)
me->flag |= ME_EDGEDRAW | ME_EDGERENDER;
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
@@ -74,16 +82,15 @@ static void initData(ModifierData *md)
tmd->ngon_method = MOD_TRIANGULATE_NGON_BEAUTY;
}
-static DerivedMesh *applyModifier(
+static Mesh *applyModifier(
ModifierData *md,
- Object *UNUSED(ob),
- DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh)
{
TriangulateModifierData *tmd = (TriangulateModifierData *)md;
- DerivedMesh *result;
- if (!(result = triangulate_dm(dm, tmd->quad_method, tmd->ngon_method))) {
- return dm;
+ Mesh *result;
+ if (!(result = triangulate_mesh(mesh, tmd->quad_method, tmd->ngon_method))) {
+ return mesh;
}
return result;
@@ -101,17 +108,23 @@ ModifierTypeInfo modifierType_Triangulate = {
eModifierTypeFlag_AcceptsCVs,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ NULL, //requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 3694428d62d..3210105f710 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -34,43 +34,55 @@
#include "DNA_image_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
#include "BLI_math_vector.h"
#include "BLI_math_matrix.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
+#include "BKE_editmesh.h"
#include "BKE_image.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_util.h"
#include "MOD_modifiertypes.h"
#include "MEM_guardedalloc.h"
-void modifier_init_texture(const Scene *scene, Tex *tex)
+#include "bmesh.h"
+
+void MOD_init_texture(const Depsgraph *depsgraph, Tex *tex)
{
if (!tex)
return;
if (tex->ima && BKE_image_is_animated(tex->ima)) {
- BKE_image_user_frame_calc(&tex->iuser, scene->r.cfra, 0);
+ BKE_image_user_frame_calc(&tex->iuser, DEG_get_ctime(depsgraph));
}
}
-void get_texture_coords(
- MappingInfoModifierData *dmd, Object *ob,
- DerivedMesh *dm,
- float (*co)[3], float (*texco)[3],
- int numVerts)
+/* TODO to be renamed to get_texture_coords once we are done with moving modifiers to Mesh. */
+/** \param cos may be NULL, in which case we use directly mesh vertices' coordinates. */
+void MOD_get_texture_coords(
+ MappingInfoModifierData *dmd,
+ Object *ob,
+ Mesh *mesh,
+ float (*cos)[3],
+ float (*r_texco)[3])
{
+ const int numVerts = mesh->totvert;
int i;
int texmapping = dmd->texmapping;
float mapob_imat[4][4];
@@ -84,18 +96,17 @@ void get_texture_coords(
/* UVs need special handling, since they come from faces */
if (texmapping == MOD_DISP_MAP_UV) {
- if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
- MPoly *mpoly = dm->getPolyArray(dm);
+ if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
+ MPoly *mpoly = mesh->mpoly;
MPoly *mp;
- MLoop *mloop = dm->getLoopArray(dm);
- char *done = MEM_calloc_arrayN(numVerts, sizeof(*done),
- "get_texture_coords done");
- int numPolys = dm->getNumPolys(dm);
+ MLoop *mloop = mesh->mloop;
+ BLI_bitmap *done = BLI_BITMAP_NEW(numVerts, __func__);
+ const int numPolys = mesh->totpoly;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
MLoopUV *mloop_uv;
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, dmd->uvlayer_name, uvname);
- mloop_uv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, dmd->uvlayer_name, uvname);
+ mloop_uv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
/* verts are given the UV from the first face that uses them */
for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
@@ -105,11 +116,11 @@ void get_texture_coords(
unsigned int lidx = mp->loopstart + fidx;
unsigned int vidx = mloop[lidx].v;
- if (done[vidx] == 0) {
+ if (!BLI_BITMAP_TEST(done, vidx)) {
/* remap UVs from [0, 1] to [-1, 1] */
- texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f;
- texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f;
- done[vidx] = 1;
+ r_texco[vidx][0] = (mloop_uv[lidx].uv[0] * 2.0f) - 1.0f;
+ r_texco[vidx][1] = (mloop_uv[lidx].uv[1] * 2.0f) - 1.0f;
+ BLI_BITMAP_ENABLE(done, vidx);
}
} while (fidx--);
@@ -118,27 +129,33 @@ void get_texture_coords(
MEM_freeN(done);
return;
}
- else /* if there are no UVs, default to local */
+ else {
+ /* if there are no UVs, default to local */
texmapping = MOD_DISP_MAP_LOCAL;
+ }
}
- for (i = 0; i < numVerts; ++i, ++co, ++texco) {
+ MVert *mv = mesh->mvert;
+ for (i = 0; i < numVerts; ++i, ++mv, ++r_texco) {
switch (texmapping) {
case MOD_DISP_MAP_LOCAL:
- copy_v3_v3(*texco, *co);
+ copy_v3_v3(*r_texco, cos != NULL ? *cos : mv->co);
break;
case MOD_DISP_MAP_GLOBAL:
- mul_v3_m4v3(*texco, ob->obmat, *co);
+ mul_v3_m4v3(*r_texco, ob->obmat, cos != NULL ? *cos : mv->co);
break;
case MOD_DISP_MAP_OBJECT:
- mul_v3_m4v3(*texco, ob->obmat, *co);
- mul_m4_v3(mapob_imat, *texco);
+ mul_v3_m4v3(*r_texco, ob->obmat, cos != NULL ? *cos : mv->co);
+ mul_m4_v3(mapob_imat, *r_texco);
break;
}
+ if (cos != NULL) {
+ cos++;
+ }
}
}
-void modifier_vgroup_cache(ModifierData *md, float (*vertexCos)[3])
+void MOD_previous_vcos_store(ModifierData *md, float (*vertexCos)[3])
{
while ((md = md->next) && md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *) md;
@@ -150,75 +167,68 @@ void modifier_vgroup_cache(ModifierData *md, float (*vertexCos)[3])
/* lattice/mesh modifier too */
}
-/* returns a cdderivedmesh if dm == NULL or is another type of derivedmesh */
-DerivedMesh *get_cddm(Object *ob, struct BMEditMesh *em, DerivedMesh *dm, float (*vertexCos)[3], bool use_normals)
+/* returns a mesh if mesh == NULL, for deforming modifiers that need it */
+Mesh *MOD_deform_mesh_eval_get(
+ Object *ob, struct BMEditMesh *em, Mesh *mesh,
+ float (*vertexCos)[3], const int num_verts,
+ const bool use_normals, const bool use_orco)
{
- if (dm) {
- if (dm->type != DM_TYPE_CDDM) {
- dm = CDDM_copy(dm);
- }
- CDDM_apply_vert_coords(dm, vertexCos);
-
- if (use_normals) {
- DM_ensure_normals(dm);
- }
- }
- else {
- dm = get_dm(ob, em, dm, vertexCos, use_normals, false);
- }
-
- return dm;
-}
-
-/* returns a derived mesh if dm == NULL, for deforming modifiers that need it */
-DerivedMesh *get_dm(
- Object *ob, struct BMEditMesh *em, DerivedMesh *dm,
- float (*vertexCos)[3], bool use_normals, bool use_orco)
-{
- if (dm) {
+ if (mesh != NULL) {
/* pass */
}
else if (ob->type == OB_MESH) {
- if (em) dm = CDDM_from_editbmesh(em, false, false);
- else dm = CDDM_from_mesh((struct Mesh *)(ob->data));
+ if (em) {
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0);
+ }
+ else {
+ /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
+ * we really need a copy here. Maybe the CoW ob->data can be directly used. */
+ BKE_id_copy_ex(
+ NULL, ob->data, (ID **)&mesh,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW |
+ LIB_ID_COPY_CD_REFERENCE),
+ false);
+ mesh->runtime.deformed_only = 1;
+ }
+ /* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
+ * we really need vertexCos here. */
if (vertexCos) {
- CDDM_apply_vert_coords(dm, vertexCos);
- dm->dirty |= DM_DIRTY_NORMALS;
+ BKE_mesh_apply_vert_coords(mesh, vertexCos);
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
if (use_orco) {
- DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob));
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
}
}
else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
- dm = CDDM_from_curve(ob);
+ /* TODO(sybren): get evaluated mesh from depsgraph once that's properly generated for curves. */
+ mesh = BKE_mesh_new_nomain_from_curve(ob);
+
+ /* Currently, that may not be the case everytime
+ * (texts e.g. tend to give issues, also when deforming curve points instead of generated curve geometry... ). */
+ if (mesh != NULL && mesh->totvert != num_verts) {
+ BKE_id_free(NULL, mesh);
+ mesh = NULL;
+ }
}
if (use_normals) {
- if (LIKELY(dm)) {
- DM_ensure_normals(dm);
+ if (LIKELY(mesh)) {
+ BKE_mesh_ensure_normals(mesh);
}
}
- return dm;
-}
+ BLI_assert(mesh == NULL || mesh->totvert == num_verts);
-/* Get derived mesh for other object, which is used as an operand for the modifier,
- * i.e. second operand for boolean modifier.
- */
-DerivedMesh *get_dm_for_modifier(Object *ob, ModifierApplyFlag flag)
-{
- if (flag & MOD_APPLY_RENDER) {
- /* TODO(sergey): Use proper derived render in the future. */
- return ob->derivedFinal;
- }
- else {
- return ob->derivedFinal;
- }
+ return mesh;
}
-void modifier_get_vgroup(Object *ob, DerivedMesh *dm, const char *name, MDeformVert **dvert, int *defgrp_index)
+void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
{
*defgrp_index = defgroup_name_index(ob, name);
*dvert = NULL;
@@ -226,8 +236,8 @@ void modifier_get_vgroup(Object *ob, DerivedMesh *dm, const char *name, MDeformV
if (*defgrp_index != -1) {
if (ob->type == OB_LATTICE)
*dvert = BKE_lattice_deform_verts_get(ob);
- else if (dm)
- *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ else if (mesh)
+ *dvert = mesh->dvert;
}
}
@@ -290,5 +300,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(CorrectiveSmooth);
INIT_TYPE(MeshSequenceCache);
INIT_TYPE(SurfaceDeform);
+ INIT_TYPE(WeightedNormal);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index 0414b8e6d52..4b0e8e3e64a 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -33,27 +33,31 @@
#include "DEG_depsgraph_build.h"
-struct DerivedMesh;
+struct Depsgraph;
struct MDeformVert;
+struct Mesh;
struct ModifierData;
struct Object;
struct Scene;
struct Tex;
-void modifier_init_texture(const struct Scene *scene, struct Tex *texture);
-void get_texture_coords(
- struct MappingInfoModifierData *dmd, struct Object *ob, struct DerivedMesh *dm,
- float (*co)[3], float (*texco)[3], int numVerts);
-void modifier_vgroup_cache(struct ModifierData *md, float (*vertexCos)[3]);
-struct DerivedMesh *get_cddm(
- struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm,
- float (*vertexCos)[3], bool use_normals);
-struct DerivedMesh *get_dm(
- struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm,
- float (*vertexCos)[3], bool use_normals, bool use_orco);
-struct DerivedMesh *get_dm_for_modifier(struct Object *ob, ModifierApplyFlag flag);
-void modifier_get_vgroup(
- struct Object *ob, struct DerivedMesh *dm,
+void MOD_init_texture(const struct Depsgraph *depsgraph, struct Tex *texture);
+void MOD_get_texture_coords(
+ struct MappingInfoModifierData *dmd,
+ struct Object *ob,
+ struct Mesh *mesh,
+ float (*cos)[3],
+ float (*r_texco)[3]);
+
+void MOD_previous_vcos_store(struct ModifierData *md, float (*vertexCos)[3]);
+
+struct Mesh *MOD_deform_mesh_eval_get(
+ struct Object *ob, struct BMEditMesh *em, struct Mesh *mesh,
+ float (*vertexCos)[3], const int num_verts,
+ const bool use_normals, const bool use_orco);
+
+void MOD_get_vgroup(
+ struct Object *ob, struct Mesh *mesh,
const char *name, struct MDeformVert **dvert, int *defgrp_index);
#endif /* __MOD_UTIL_H__ */
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 1089eb1bea4..8c9fbefa27a 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -35,6 +35,7 @@
/* UV Project modifier: Generates UVs projected from an object */
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_camera_types.h"
#include "DNA_object_types.h"
@@ -47,21 +48,22 @@
#include "BKE_camera.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
-#include "BKE_DerivedMesh.h"
#include "MOD_modifiertypes.h"
#include "MEM_guardedalloc.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
static void initData(ModifierData *md)
{
UVProjectModifierData *umd = (UVProjectModifierData *) md;
- umd->flags = 0;
+
umd->num_projectors = 1;
umd->aspectx = umd->aspecty = 1.0f;
umd->scalex = umd->scaley = 1.0f;
@@ -72,7 +74,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(
CustomDataMask dataMask = 0;
/* ask for UV coordinates */
- dataMask |= CD_MLOOPUV | CD_MTEXPOLY;
+ dataMask |= CD_MLOOPUV;
return dataMask;
}
@@ -92,37 +94,26 @@ static void foreachIDLink(
ModifierData *md, Object *ob,
IDWalkFunc walk, void *userData)
{
+#if 0
UVProjectModifierData *umd = (UVProjectModifierData *) md;
-
- walk(userData, ob, (ID **)&umd->image, IDWALK_CB_USER);
+#endif
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- UVProjectModifierData *umd = (UVProjectModifierData *) md;
- int i;
-
- for (i = 0; i < umd->num_projectors; ++i) {
- if (umd->projectors[i]) {
- DagNode *curNode = dag_get_node(ctx->forest, umd->projectors[i]);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode,
- DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "UV Project Modifier");
- }
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
UVProjectModifierData *umd = (UVProjectModifierData *)md;
- int i;
- for (i = 0; i < umd->num_projectors; ++i) {
+ bool do_add_own_transform = false;
+ for (int i = 0; i < umd->num_projectors; ++i) {
if (umd->projectors[i] != NULL) {
DEG_add_object_relation(ctx->node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
+ do_add_own_transform = true;
}
}
+ if (do_add_own_transform) {
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
+ }
}
typedef struct Projector {
@@ -132,18 +123,15 @@ typedef struct Projector {
void *uci; /* optional uv-project info (panorama projection) */
} Projector;
-static DerivedMesh *uvprojectModifier_do(
+static Mesh *uvprojectModifier_do(
UVProjectModifierData *umd,
- Object *ob, DerivedMesh *dm)
+ Object *ob, Mesh *mesh)
{
float (*coords)[3], (*co)[3];
MLoopUV *mloop_uv;
- MTexPoly *mtexpoly, *mt = NULL;
int i, numVerts, numPolys, numLoops;
- Image *image = umd->image;
MPoly *mpoly, *mp;
MLoop *mloop;
- const bool override_image = (umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0;
Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
int num_projectors = 0;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
@@ -157,14 +145,14 @@ static DerivedMesh *uvprojectModifier_do(
if (umd->projectors[i])
projectors[num_projectors++].ob = umd->projectors[i];
- if (num_projectors == 0) return dm;
+ if (num_projectors == 0) return mesh;
/* make sure there are UV Maps available */
- if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) return dm;
+ if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) return mesh;
/* make sure we're using an existing layer */
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname);
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname);
/* calculate a projection matrix and normal for each projector */
for (i = 0; i < num_projectors; ++i) {
@@ -177,7 +165,6 @@ static DerivedMesh *uvprojectModifier_do(
projectors[i].uci = NULL;
if (projectors[i].ob->type == OB_CAMERA) {
-
cam = (Camera *)projectors[i].ob->data;
if (cam->type == CAM_PANO) {
projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy);
@@ -221,22 +208,14 @@ static DerivedMesh *uvprojectModifier_do(
mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
}
- numPolys = dm->getNumPolys(dm);
- numLoops = dm->getNumLoops(dm);
+ numPolys = mesh->totpoly;
+ numLoops = mesh->totloop;
/* make sure we are not modifying the original UV map */
- mloop_uv = CustomData_duplicate_referenced_layer_named(&dm->loopData,
+ mloop_uv = CustomData_duplicate_referenced_layer_named(&mesh->ldata,
CD_MLOOPUV, uvname, numLoops);
- /* can be NULL */
- mt = mtexpoly = CustomData_duplicate_referenced_layer_named(&dm->polyData,
- CD_MTEXPOLY, uvname, numPolys);
-
- numVerts = dm->getNumVerts(dm);
-
- coords = MEM_malloc_arrayN(numVerts, sizeof(*coords),
- "uvprojectModifier_do coords");
- dm->getVertCos(dm, coords);
+ coords = BKE_mesh_vertexCos_get(mesh, &numVerts);
/* convert coords to world space */
for (i = 0, co = coords; i < numVerts; ++i, ++co)
@@ -247,77 +226,70 @@ static DerivedMesh *uvprojectModifier_do(
for (i = 0, co = coords; i < numVerts; ++i, ++co)
mul_project_m4_v3(projectors[0].projmat, *co);
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
-
- /* apply coords as UVs, and apply image if tfaces are new */
- for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp, ++mt) {
- if (override_image || !image || (mtexpoly == NULL || mt->tpage == image)) {
- if (num_projectors == 1) {
- if (projectors[0].uci) {
- unsigned int fidx = mp->totloop - 1;
- do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
- BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
- } while (fidx--);
- }
- else {
- /* apply transformed coords as UVs */
- unsigned int fidx = mp->totloop - 1;
- do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
- copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
- } while (fidx--);
- }
+ mpoly = mesh->mpoly;
+ mloop = mesh->mloop;
+
+ /* apply coords as UVs */
+ for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp) {
+ if (num_projectors == 1) {
+ if (projectors[0].uci) {
+ unsigned int fidx = mp->totloop - 1;
+ do {
+ unsigned int lidx = mp->loopstart + fidx;
+ unsigned int vidx = mloop[lidx].v;
+ BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
+ } while (fidx--);
}
else {
- /* multiple projectors, select the closest to face normal direction */
- float face_no[3];
- int j;
- Projector *best_projector;
- float best_dot;
-
- /* get the untransformed face normal */
- BKE_mesh_calc_poly_normal_coords(mp, mloop + mp->loopstart, (const float (*)[3])coords, face_no);
-
- /* find the projector which the face points at most directly
- * (projector normal with largest dot product is best)
- */
- best_dot = dot_v3v3(projectors[0].normal, face_no);
- best_projector = &projectors[0];
-
- for (j = 1; j < num_projectors; ++j) {
- float tmp_dot = dot_v3v3(projectors[j].normal,
- face_no);
- if (tmp_dot > best_dot) {
- best_dot = tmp_dot;
- best_projector = &projectors[j];
- }
- }
-
- if (best_projector->uci) {
- unsigned int fidx = mp->totloop - 1;
- do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
- BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
- } while (fidx--);
- }
- else {
- unsigned int fidx = mp->totloop - 1;
- do {
- unsigned int lidx = mp->loopstart + fidx;
- unsigned int vidx = mloop[lidx].v;
- mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
- } while (fidx--);
- }
+ /* apply transformed coords as UVs */
+ unsigned int fidx = mp->totloop - 1;
+ do {
+ unsigned int lidx = mp->loopstart + fidx;
+ unsigned int vidx = mloop[lidx].v;
+ copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
+ } while (fidx--);
}
}
+ else {
+ /* multiple projectors, select the closest to face normal direction */
+ float face_no[3];
+ int j;
+ Projector *best_projector;
+ float best_dot;
+
+ /* get the untransformed face normal */
+ BKE_mesh_calc_poly_normal_coords(mp, mloop + mp->loopstart, (const float (*)[3])coords, face_no);
+
+ /* find the projector which the face points at most directly
+ * (projector normal with largest dot product is best)
+ */
+ best_dot = dot_v3v3(projectors[0].normal, face_no);
+ best_projector = &projectors[0];
+
+ for (j = 1; j < num_projectors; ++j) {
+ float tmp_dot = dot_v3v3(projectors[j].normal, face_no);
+ if (tmp_dot > best_dot) {
+ best_dot = tmp_dot;
+ best_projector = &projectors[j];
+ }
+ }
- if (override_image && mtexpoly) {
- mt->tpage = image;
+ if (best_projector->uci) {
+ unsigned int fidx = mp->totloop - 1;
+ do {
+ unsigned int lidx = mp->loopstart + fidx;
+ unsigned int vidx = mloop[lidx].v;
+ BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
+ } while (fidx--);
+ }
+ else {
+ unsigned int fidx = mp->totloop - 1;
+ do {
+ unsigned int lidx = mp->loopstart + fidx;
+ unsigned int vidx = mloop[lidx].v;
+ mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
+ } while (fidx--);
+ }
}
}
@@ -333,20 +305,19 @@ static DerivedMesh *uvprojectModifier_do(
}
/* Mark tessellated CD layers as dirty. */
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ mesh->runtime.cd_dirty_vert |= CD_MASK_TESSLOOPNORMAL;
- return dm;
+ return mesh;
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
- DerivedMesh *result;
+ Mesh *result;
UVProjectModifierData *umd = (UVProjectModifierData *) md;
- result = uvprojectModifier_do(umd, ob, derivedData);
+ result = uvprojectModifier_do(umd, ctx->object, mesh);
return result;
}
@@ -363,17 +334,23 @@ ModifierTypeInfo modifierType_UVProject = {
eModifierTypeFlag_EnableInEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 39c11e34df2..e9947826fb6 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -27,6 +27,7 @@
#include <string.h>
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -35,13 +36,10 @@
#include "BLI_utildefines.h"
#include "BKE_action.h" /* BKE_pose_channel_find_name */
-#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
-#include "depsgraph_private.h"
-
#include "MOD_util.h"
@@ -140,10 +138,9 @@ static void uv_warp_compute(
}
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
UVWarpModifierData *umd = (UVWarpModifierData *) md;
int numPolys, numLoops;
@@ -161,12 +158,12 @@ static DerivedMesh *applyModifier(
const int axis_v = umd->axis_v;
/* make sure there are UV Maps available */
- if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
- return dm;
+ if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
+ return mesh;
}
else if (ELEM(NULL, umd->object_src, umd->object_dst)) {
modifier_setError(md, "From/To objects must be set");
- return dm;
+ return mesh;
}
/* make sure anything moving UVs is available */
@@ -192,16 +189,16 @@ static DerivedMesh *applyModifier(
}
/* make sure we're using an existing layer */
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname);
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, umd->uvlayer_name, uvname);
- numPolys = dm->getNumPolys(dm);
- numLoops = dm->getNumLoops(dm);
+ numPolys = mesh->totpoly;
+ numLoops = mesh->totloop;
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
+ mpoly = mesh->mpoly;
+ mloop = mesh->mloop;
/* make sure we are not modifying the original UV map */
- mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops);
- modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index);
+ mloopuv = CustomData_duplicate_referenced_layer_named(&mesh->ldata, CD_MLOOPUV, uvname, numLoops);
+ MOD_get_vgroup(ctx->object, mesh, umd->vgroup_name, &dvert, &defgrp_index);
UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv,
.dvert = dvert, .defgrp_index = defgrp_index,
@@ -214,9 +211,10 @@ static DerivedMesh *applyModifier(
uv_warp_compute,
&settings);
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ /* XXX TODO is this still needed? */
+// me_eval->dirty |= DM_DIRTY_TESS_CDLAYERS;
- return dm;
+ return mesh;
}
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
@@ -227,28 +225,6 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
walk(userData, ob, &umd->object_src, IDWALK_CB_NOP);
}
-static void uv_warp_deps_object_bone(
- DagForest *forest, DagNode *obNode,
- Object *obj, const char *bonename)
-{
- if (obj) {
- DagNode *curNode = dag_get_node(forest, obj);
-
- if (bonename[0])
- dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "UVWarp Modifier");
- else
- dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, "UVWarp Modifier");
- }
-}
-
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- UVWarpModifierData *umd = (UVWarpModifierData *) md;
-
- uv_warp_deps_object_bone(ctx->forest, ctx->obNode, umd->object_src, umd->bone_src);
- uv_warp_deps_object_bone(ctx->forest, ctx->obNode, umd->object_dst, umd->bone_dst);
-}
-
static void uv_warp_deps_object_bone_new(
struct DepsNodeHandle *node,
Object *object,
@@ -268,6 +244,8 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
uv_warp_deps_object_bone_new(ctx->node, umd->object_src, umd->bone_src);
uv_warp_deps_object_bone_new(ctx->node, umd->object_dst, umd->bone_dst);
+
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "UVWarp Modifier");
}
ModifierTypeInfo modifierType_UVWarp = {
@@ -278,18 +256,25 @@ ModifierTypeInfo modifierType_UVWarp = {
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
+
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 3689b1ae724..aea530e7b6e 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -29,20 +29,24 @@
#include "MEM_guardedalloc.h"
-#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_texture.h"
#include "BKE_colortools.h"
-#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "RE_shader_ext.h"
@@ -61,12 +65,12 @@ static void initData(ModifierData *md)
wmd->flag = 0;
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const WarpModifierData *wmd = (const WarpModifierData *) md;
WarpModifierData *twmd = (WarpModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
twmd->curfalloff = curvemapping_copy(wmd->curfalloff);
}
@@ -105,7 +109,7 @@ static void freeData(ModifierData *md)
}
-static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams))
{
WarpModifierData *wmd = (WarpModifierData *) md;
@@ -135,28 +139,11 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "texture");
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- WarpModifierData *wmd = (WarpModifierData *) md;
-
- if (wmd->object_from && wmd->object_to) {
- DagNode *fromNode = dag_get_node(ctx->forest, wmd->object_from);
- DagNode *toNode = dag_get_node(ctx->forest, wmd->object_to);
-
- dag_add_relation(ctx->forest, fromNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier1");
- dag_add_relation(ctx->forest, toNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier2");
- }
-
- if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object) {
- DagNode *curNode = dag_get_node(ctx->forest, wmd->map_object);
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Warp Modifier3");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WarpModifierData *wmd = (WarpModifierData *) md;
if (wmd->object_from != NULL && wmd->object_to != NULL) {
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Warplace Modifier");
DEG_add_object_relation(ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
}
@@ -166,9 +153,11 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
static void warpModifier_do(
- WarpModifierData *wmd, Object *ob,
- DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
+ WarpModifierData *wmd, const ModifierEvalContext *ctx,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
+ Object *ob = ctx->object;
+ Depsgraph *depsgraph = ctx->depsgraph;
float obinv[4][4];
float mat_from[4][4];
float mat_from_inv[4][4];
@@ -190,7 +179,7 @@ static void warpModifier_do(
if (!(wmd->object_from && wmd->object_to))
return;
- modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index);
if (dvert == NULL) {
defgrp_index = -1;
}
@@ -226,11 +215,11 @@ static void warpModifier_do(
}
weight = strength;
- if (wmd->texture) {
+ if (mesh != NULL && wmd->texture) {
tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co");
- get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
+ MOD_get_texture_coords((MappingInfoModifierData *)wmd, ob, mesh, vertexCos, tex_co);
- modifier_init_texture(wmd->modifier.scene, wmd->texture);
+ MOD_init_texture(depsgraph, wmd->texture);
}
for (i = 0; i < numVerts; i++) {
@@ -284,9 +273,10 @@ static void warpModifier_do(
fac *= weight;
if (tex_co) {
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
TexResult texres;
texres.nor = NULL;
- BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false);
+ BKE_texture_get_value(scene, wmd->texture, tex_co[i], &texres, false);
fac *= texres.tin;
}
@@ -316,50 +306,46 @@ static void warpModifier_do(
}
}
- if (tex_co)
+ if (tex_co) {
MEM_freeN(tex_co);
-
-}
-
-static int warp_needs_dm(WarpModifierData *wmd)
-{
- return wmd->texture || wmd->defgrp_name[0];
+ }
}
static void deformVerts(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts, ModifierApplyFlag UNUSED(flag))
+ ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = NULL;
- int use_dm = warp_needs_dm((WarpModifierData *)md);
+ WarpModifierData *wmd = (WarpModifierData *)md;
+ Mesh *mesh_src = NULL;
- if (use_dm) {
- dm = get_cddm(ob, NULL, derivedData, vertexCos, false);
+ if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) {
+ /* mesh_src is only needed for vgroups and textures. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
}
- warpModifier_do((WarpModifierData *)md, ob, dm, vertexCos, numVerts);
+ warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts);
- if (use_dm) {
- if (dm != derivedData) dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
}
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *em,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *em,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = derivedData;
- int use_dm = warp_needs_dm((WarpModifierData *)md);
+ WarpModifierData *wmd = (WarpModifierData *)md;
+ Mesh *mesh_src = NULL;
- if (use_dm) {
- if (!derivedData)
- dm = CDDM_from_editbmesh(em, false, false);
+ if (wmd->defgrp_name[0] != '\0' || wmd->texture != NULL) {
+ /* mesh_src is only needed for vgroups and textures. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
}
- deformVerts(md, ob, dm, vertexCos, numVerts, 0);
+ warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts);
- if (use_dm) {
- if (!derivedData) dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
}
}
@@ -373,17 +359,23 @@ ModifierTypeInfo modifierType_Warp = {
eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 38123c5e3bb..a517f753791 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -35,28 +35,31 @@
#include "BLI_math.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_editmesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
-#include "depsgraph_private.h"
-
#include "MEM_guardedalloc.h"
#include "RE_shader_ext.h"
#include "MOD_modifiertypes.h"
#include "MOD_util.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
static void initData(ModifierData *md)
{
WaveModifierData *wmd = (WaveModifierData *) md; // whadya know, moved here from Iraq
@@ -111,25 +114,6 @@ static void foreachTexLink(
walk(userData, ob, md, "texture");
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- WaveModifierData *wmd = (WaveModifierData *) md;
-
- if (wmd->objectcenter) {
- DagNode *curNode = dag_get_node(ctx->forest, wmd->objectcenter);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_OB_DATA,
- "Wave Modifier");
- }
-
- if (wmd->map_object) {
- DagNode *curNode = dag_get_node(ctx->forest, wmd->map_object);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_OB_DATA,
- "Wave Modifer");
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WaveModifierData *wmd = (WaveModifierData *)md;
@@ -139,6 +123,9 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
if (wmd->map_object != NULL) {
DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
}
+ if (wmd->objectcenter != NULL || wmd->map_object != NULL) {
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ }
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -158,16 +145,24 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
+static bool dependsOnNormals(ModifierData *md)
+{
+ WaveModifierData *wmd = (WaveModifierData *)md;
+
+ return (wmd->flag & MOD_WAVE_NORM) != 0;
+}
+
static void waveModifier_do(
WaveModifierData *md,
- Scene *scene, Object *ob, DerivedMesh *dm,
+ Depsgraph *depsgraph,
+ Object *ob, Mesh *mesh,
float (*vertexCos)[3], int numVerts)
{
WaveModifierData *wmd = (WaveModifierData *) md;
MVert *mvert = NULL;
MDeformVert *dvert;
int defgrp_index;
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = DEG_get_ctime(depsgraph);
float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
float lifefac = wmd->height;
float (*tex_co)[3] = NULL;
@@ -175,8 +170,9 @@ static void waveModifier_do(
const float falloff = wmd->falloff;
float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */
- if ((wmd->flag & MOD_WAVE_NORM) && (ob->type == OB_MESH))
- mvert = dm->getVertArray(dm);
+ if ((wmd->flag & MOD_WAVE_NORM) && (mesh != NULL)) {
+ mvert = mesh->mvert;
+ }
if (wmd->objectcenter) {
float mat[4][4];
@@ -189,9 +185,11 @@ static void waveModifier_do(
}
/* get the index of the deform group */
- modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);
+ MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index);
- if (wmd->damp == 0) wmd->damp = 10.0f;
+ if (wmd->damp == 0.0f) {
+ wmd->damp = 10.0f;
+ }
if (wmd->lifetime != 0.0f) {
float x = ctime - wmd->timeoffs;
@@ -204,17 +202,16 @@ static void waveModifier_do(
}
}
- if (wmd->texture) {
- tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co),
- "waveModifier_do tex_co");
- get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);
+ if (mesh != NULL && wmd->texture) {
+ tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "waveModifier_do tex_co");
+ MOD_get_texture_coords((MappingInfoModifierData *)wmd, ob, mesh, vertexCos, tex_co);
- modifier_init_texture(wmd->modifier.scene, wmd->texture);
+ MOD_init_texture(depsgraph, wmd->texture);
}
if (lifefac != 0.0f) {
/* avoid divide by zero checks within the loop */
- float falloff_inv = falloff ? 1.0f / falloff : 1.0f;
+ float falloff_inv = falloff != 0.0f ? 1.0f / falloff : 1.0f;
int i;
for (i = 0; i < numVerts; i++) {
@@ -280,9 +277,10 @@ static void waveModifier_do(
/*apply texture*/
if (wmd->texture) {
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
TexResult texres;
texres.nor = NULL;
- BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false);
+ BKE_texture_get_value(scene, wmd->texture, tex_co[i], &texres, false);
amplit *= texres.tin;
}
@@ -309,46 +307,52 @@ static void waveModifier_do(
}
}
- if (wmd->texture) MEM_freeN(tex_co);
+ MEM_SAFE_FREE(tex_co);
}
static void deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *mesh,
float (*vertexCos)[3],
- int numVerts,
- ModifierApplyFlag UNUSED(flag))
+ int numVerts)
{
- DerivedMesh *dm = derivedData;
WaveModifierData *wmd = (WaveModifierData *)md;
+ Mesh *mesh_src = NULL;
- if (wmd->flag & MOD_WAVE_NORM)
- dm = get_cddm(ob, NULL, dm, vertexCos, false);
- else if (wmd->texture || wmd->defgrp_name[0])
- dm = get_dm(ob, NULL, dm, NULL, false, false);
+ if (wmd->flag & MOD_WAVE_NORM) {
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, vertexCos, numVerts, true, false);
+ }
+ else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') {
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
+ }
- waveModifier_do(wmd, md->scene, ob, dm, vertexCos, numVerts);
+ waveModifier_do(wmd, ctx->depsgraph, ctx->object, mesh_src, vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(
- ModifierData *md, Object *ob, struct BMEditMesh *editData,
- DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ Mesh *mesh, float (*vertexCos)[3], int numVerts)
{
- DerivedMesh *dm = derivedData;
WaveModifierData *wmd = (WaveModifierData *)md;
+ Mesh *mesh_src = NULL;
- if (wmd->flag & MOD_WAVE_NORM)
- dm = get_cddm(ob, editData, dm, vertexCos, false);
- else if (wmd->texture || wmd->defgrp_name[0])
- dm = get_dm(ob, editData, dm, NULL, false, false);
+ if (wmd->flag & MOD_WAVE_NORM) {
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, vertexCos, numVerts, true, false);
+ }
+ else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') {
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
+ }
- waveModifier_do(wmd, md->scene, ob, dm, vertexCos, numVerts);
+ waveModifier_do(wmd, ctx->depsgraph, ctx->object, mesh_src, vertexCos, numVerts);
- if (dm != derivedData)
- dm->release(dm);
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
@@ -360,21 +364,28 @@ ModifierTypeInfo modifierType_Wave = {
/* flags */ eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
+
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
/* applyModifier */ NULL,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
- /* dependsOnNormals */ NULL,
+ /* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ foreachTexLink,
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
new file mode 100644
index 00000000000..0e116b2e021
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -0,0 +1,669 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_weighted_normal.c
+ * \ingroup modifiers
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_mesh.h"
+
+#include "BLI_math.h"
+#include "BLI_linklist.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+
+#define CLNORS_VALID_VEC_LEN (1e-6f)
+
+typedef struct ModePair {
+ float val; /* Contains mode based value (face area / corner angle). */
+ int index; /* Index value per poly or per loop. */
+} ModePair;
+
+/* Sorting function used in modifier, sorts in decreasing order. */
+static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
+{
+ ModePair *r1 = (ModePair *)p1;
+ ModePair *r2 = (ModePair *)p2;
+
+ return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0);
+}
+
+/* There will be one of those per vertex (simple case, computing one normal per vertex), or per smooth fan. */
+typedef struct WeightedNormalDataAggregateItem {
+ float normal[3];
+
+ int num_loops; /* Count number of loops using this item so far. */
+ float curr_val; /* Current max val for this item. */
+ int curr_strength; /* Current max strength encountered for this item. */
+} WeightedNormalDataAggregateItem;
+
+#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128
+
+typedef struct WeightedNormalData {
+ const int numVerts;
+ const int numEdges;
+ const int numLoops;
+ const int numPolys;
+
+ MVert *mvert;
+ MEdge *medge;
+
+ MLoop *mloop;
+ short (*clnors)[2];
+ const bool has_clnors; /* True if clnors already existed, false if we had to create them. */
+ const float split_angle;
+
+ MPoly *mpoly;
+ float (*polynors)[3];
+ int *poly_strength;
+
+ MDeformVert *dvert;
+ const int defgrp_index;
+ const bool use_invert_vgroup;
+
+ const float weight;
+ const short mode;
+
+ /* Lower-level, internal processing data. */
+ float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT];
+
+ WeightedNormalDataAggregateItem *items_data;
+
+ ModePair *mode_pair;
+
+ int *loop_to_poly;
+} WeightedNormalData;
+
+/* Check strength of given poly compared to those found so far for that given item (vertex or smooth fan),
+ * and reset matching item_data in case we get a stronger new strength. */
+static bool check_item_poly_strength(
+ WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mp_index)
+{
+ BLI_assert (wn_data->poly_strength != NULL);
+
+ const int mp_strength = wn_data->poly_strength[mp_index];
+
+ if (mp_strength > item_data->curr_strength) {
+ item_data->curr_strength = mp_strength;
+ item_data->curr_val = 0.0f;
+ item_data->num_loops = 0;
+ zero_v3(item_data->normal);
+ }
+
+ return mp_strength == item_data->curr_strength;
+}
+
+static void aggregate_item_normal(
+ WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data,
+ WeightedNormalDataAggregateItem *item_data,
+ const int mv_index, const int mp_index,
+ const float curr_val, const bool use_face_influence)
+{
+ float (*polynors)[3] = wn_data->polynors;
+
+ MDeformVert *dvert = wn_data->dvert;
+ const int defgrp_index = wn_data->defgrp_index;
+ const bool use_invert_vgroup = wn_data->use_invert_vgroup;
+
+ const float weight = wn_data->weight;
+
+ float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight;
+
+ const bool has_vgroup = dvert != NULL;
+ const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[mv_index], defgrp_index) != NULL;
+
+ if (has_vgroup && ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) {
+ return;
+ }
+
+ if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) {
+ return;
+ }
+
+ /* If item's curr_val is 0 init it to present value. */
+ if (item_data->curr_val == 0.0f) {
+ item_data->curr_val = curr_val;
+ }
+ if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) {
+ /* item's curr_val and present value differ more than threshold, update. */
+ item_data->num_loops++;
+ item_data->curr_val = curr_val;
+ }
+
+ /* Exponentially divided weight for each normal (since a few values will be used by most cases, we cache those). */
+ const int num_loops = item_data->num_loops;
+ if (num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT && cached_inverse_powers_of_weight[num_loops] == 0.0f) {
+ cached_inverse_powers_of_weight[num_loops] = 1.0f / powf(weight, num_loops);
+ }
+ const float inverted_n_weight = num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ?
+ cached_inverse_powers_of_weight[num_loops] : 1.0f / powf(weight, num_loops);
+
+ madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight);
+}
+
+static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
+{
+ const int numVerts = wn_data->numVerts;
+ const int numEdges = wn_data->numEdges;
+ const int numLoops = wn_data->numLoops;
+ const int numPolys = wn_data->numPolys;
+
+ MVert *mvert = wn_data->mvert;
+ MEdge *medge = wn_data->medge;
+
+ MLoop *mloop = wn_data->mloop;
+ short (*clnors)[2] = wn_data->clnors;
+ int *loop_to_poly = wn_data->loop_to_poly;
+
+ MPoly *mpoly = wn_data->mpoly;
+ float (*polynors)[3] = wn_data->polynors;
+ int *poly_strength = wn_data->poly_strength;
+
+ MDeformVert *dvert = wn_data->dvert;
+
+ const short mode = wn_data->mode;
+ ModePair *mode_pair = wn_data->mode_pair;
+
+ const bool has_clnors = wn_data->has_clnors;
+ const float split_angle = wn_data->split_angle;
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+
+ const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
+ const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && poly_strength != NULL;
+ const bool has_vgroup = dvert != NULL;
+
+ float (*loop_normals)[3] = NULL;
+
+ WeightedNormalDataAggregateItem *items_data = NULL;
+ int num_items = 0;
+ if (keep_sharp) {
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(numLoops, __func__);
+
+ /* This will give us loop normal spaces, we do not actually care about computed loop_normals for now... */
+ loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
+ BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges,
+ mloop, loop_normals, numLoops, mpoly, polynors, numPolys,
+ true, split_angle, &lnors_spacearr, has_clnors ? clnors : NULL, loop_to_poly);
+
+ num_items = lnors_spacearr.num_spaces;
+ items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
+
+ /* In this first loop, we assign each WeightedNormalDataAggregateItem
+ * to its smooth fan of loops (aka lnor space). */
+ MPoly *mp;
+ int mp_index;
+ int item_index;
+ for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ int ml_index = mp->loopstart;
+ const int ml_end_index = ml_index + mp->totloop;
+
+ for (; ml_index < ml_end_index; ml_index++) {
+ if (BLI_BITMAP_TEST(done_loops, ml_index)) {
+ /* Smooth fan of this loop has already been processed, skip it. */
+ continue;
+ }
+ BLI_assert(item_index < num_items);
+
+ WeightedNormalDataAggregateItem *itdt = &items_data[item_index];
+ itdt->curr_strength = FACE_STRENGTH_WEAK;
+
+ MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index];
+ lnor_space->user_data = itdt;
+
+ if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) {
+ for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) {
+ const int ml_fan_index = POINTER_AS_INT(lnode->link);
+ BLI_BITMAP_ENABLE(done_loops, ml_fan_index);
+ }
+ }
+ else {
+ BLI_BITMAP_ENABLE(done_loops, ml_index);
+ }
+
+ item_index++;
+ }
+ }
+
+ MEM_freeN(done_loops);
+ }
+ else {
+ num_items = numVerts;
+ items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
+ if (use_face_influence) {
+ for (int item_index = 0; item_index < num_items; item_index++) {
+ items_data[item_index].curr_strength = FACE_STRENGTH_WEAK;
+ }
+ }
+ }
+ wn_data->items_data = items_data;
+
+ switch (mode) {
+ case MOD_WEIGHTEDNORMAL_MODE_FACE:
+ for (int i = 0; i < numPolys; i++) {
+ const int mp_index = mode_pair[i].index;
+ const float mp_val = mode_pair[i].val;
+
+ int ml_index = mpoly[mp_index].loopstart;
+ const int ml_index_end = ml_index + mpoly[mp_index].totloop;
+ for (; ml_index < ml_index_end; ml_index++) {
+ const int mv_index = mloop[ml_index].v;
+ WeightedNormalDataAggregateItem *item_data = keep_sharp ?
+ lnors_spacearr.lspacearr[ml_index]->user_data:
+ &items_data[mv_index];
+
+ aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence);
+ }
+ }
+ break;
+ case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
+ case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
+ BLI_assert(loop_to_poly != NULL);
+
+ for (int i = 0; i < numLoops; i++) {
+ const int ml_index = mode_pair[i].index;
+ const float ml_val = mode_pair[i].val;
+
+ const int mp_index = loop_to_poly[ml_index];
+ const int mv_index = mloop[ml_index].v;
+ WeightedNormalDataAggregateItem *item_data = keep_sharp ?
+ lnors_spacearr.lspacearr[ml_index]->user_data:
+ &items_data[mv_index];
+
+ aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence);
+ }
+ break;
+ default:
+ BLI_assert(0);
+ }
+
+ /* Validate computed weighted normals. */
+ for (int item_index = 0; item_index < num_items; item_index++) {
+ if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) {
+ zero_v3(items_data[item_index].normal);
+ }
+ }
+
+ if (keep_sharp) {
+ /* Set loop normals for normal computed for each lnor space (smooth fan).
+ * Note that loop_normals is already populated with clnors (before this modifier is applied, at start of
+ * this function), so no need to recompute them here. */
+ for (int ml_index = 0; ml_index < numLoops; ml_index++) {
+ WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data;
+ if (!is_zero_v3(item_data->normal)) {
+ copy_v3_v3(loop_normals[ml_index], item_data->normal);
+ }
+ }
+
+ BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges,
+ mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors);
+ }
+ else {
+ /* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set() to keep current
+ * clnors instead of resetting them to default autocomputed ones, when given new custom normal is zero-vec.
+ * But this is not exactly trivial change, better to keep this optimization for later...
+ */
+ if (!has_vgroup) {
+ /* Note: in theory, we could avoid this extra allocation & copying... But think we can live with it for now,
+ * and it makes code simpler & cleaner. */
+ float (*vert_normals)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*loop_normals), __func__);
+
+ for (int ml_index = 0; ml_index < numLoops; ml_index++) {
+ const int mv_index = mloop[ml_index].v;
+ copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal);
+ }
+
+ BKE_mesh_normals_loop_custom_from_vertices_set(mvert, vert_normals, numVerts, medge, numEdges,
+ mloop, numLoops, mpoly, polynors, numPolys, clnors);
+
+ MEM_freeN(vert_normals);
+ }
+ else {
+ loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
+
+ BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges,
+ mloop, loop_normals, numLoops, mpoly, polynors, numPolys,
+ true, split_angle, NULL, has_clnors ? clnors : NULL, loop_to_poly);
+
+ for (int ml_index = 0; ml_index < numLoops; ml_index++) {
+ const int item_index = mloop[ml_index].v;
+ if (!is_zero_v3(items_data[item_index].normal)) {
+ copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal);
+ }
+ }
+
+ BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges,
+ mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors);
+ }
+ }
+
+ if (keep_sharp) {
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+ }
+ MEM_SAFE_FREE(loop_normals);
+}
+
+static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
+{
+ const int numPolys = wn_data->numPolys;
+
+ MVert *mvert = wn_data->mvert;
+ MLoop *mloop = wn_data->mloop;
+ MPoly *mpoly = wn_data->mpoly;
+
+ MPoly *mp;
+ int mp_index;
+
+ ModePair *face_area = MEM_malloc_arrayN((size_t)numPolys, sizeof(*face_area), __func__);
+
+ ModePair *f_area = face_area;
+ for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++, f_area++) {
+ f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert);
+ f_area->index = mp_index;
+ }
+
+ qsort(face_area, numPolys, sizeof(*face_area), modepair_cmp_by_val_inverse);
+
+ wn_data->mode_pair = face_area;
+ apply_weights_vertex_normal(wnmd, wn_data);
+}
+
+static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
+{
+ const int numLoops = wn_data->numLoops;
+ const int numPolys = wn_data->numPolys;
+
+ MVert *mvert = wn_data->mvert;
+ MLoop *mloop = wn_data->mloop;
+ MPoly *mpoly = wn_data->mpoly;
+
+ MPoly *mp;
+ int mp_index;
+
+ int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ ModePair *corner_angle = MEM_malloc_arrayN((size_t)numLoops, sizeof(*corner_angle), __func__);
+
+ for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
+ MLoop *ml_start = &mloop[mp->loopstart];
+
+ float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
+ BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
+
+ ModePair *c_angl = &corner_angle[mp->loopstart];
+ float *angl = index_angle;
+ for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, c_angl++, angl++) {
+ c_angl->val = (float)M_PI - *angl;
+ c_angl->index = ml_index;
+
+ loop_to_poly[ml_index] = mp_index;
+ }
+ MEM_freeN(index_angle);
+ }
+
+ qsort(corner_angle, numLoops, sizeof(*corner_angle), modepair_cmp_by_val_inverse);
+
+ wn_data->loop_to_poly = loop_to_poly;
+ wn_data->mode_pair = corner_angle;
+ apply_weights_vertex_normal(wnmd, wn_data);
+}
+
+static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
+{
+ const int numLoops = wn_data->numLoops;
+ const int numPolys = wn_data->numPolys;
+
+ MVert *mvert = wn_data->mvert;
+ MLoop *mloop = wn_data->mloop;
+ MPoly *mpoly = wn_data->mpoly;
+
+ MPoly *mp;
+ int mp_index;
+
+ int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ ModePair *combined = MEM_malloc_arrayN((size_t)numLoops, sizeof(*combined), __func__);
+
+ for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
+ MLoop *ml_start = &mloop[mp->loopstart];
+
+ float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert);
+ float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
+ BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
+
+ ModePair *cmbnd = &combined[mp->loopstart];
+ float *angl = index_angle;
+ for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, cmbnd++, angl++) {
+ /* In this case val is product of corner angle and face area. */
+ cmbnd->val = ((float)M_PI - *angl) * face_area;
+ cmbnd->index = ml_index;
+
+ loop_to_poly[ml_index] = mp_index;
+ }
+ MEM_freeN(index_angle);
+ }
+
+ qsort(combined, numLoops, sizeof(*combined), modepair_cmp_by_val_inverse);
+
+ wn_data->loop_to_poly = loop_to_poly;
+ wn_data->mode_pair = combined;
+ apply_weights_vertex_normal(wnmd, wn_data);
+}
+
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+{
+ WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
+ Object *ob = ctx->object;
+
+ /* XXX TODO ARG GRRR XYQWNMPRXTYY
+ * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy.
+ * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */
+#if 0
+ if (!(mesh->flag & ME_AUTOSMOOTH)) {
+#else
+ if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) {
+#endif
+ modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings");
+ return mesh;
+ }
+
+ Mesh *result;
+ BKE_id_copy_ex(
+ NULL, &mesh->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+
+ const int numVerts = result->totvert;
+ const int numEdges = result->totedge;
+ const int numLoops = result->totloop;
+ const int numPolys = result->totpoly;
+
+ MEdge *medge = result->medge;
+ MPoly *mpoly = result->mpoly;
+ MVert *mvert = result->mvert;
+ MLoop *mloop = result->mloop;
+
+ /* Right now:
+ * If weight = 50 then all faces are given equal weight.
+ * If weight > 50 then more weight given to faces with larger vals (face area / corner angle).
+ * If weight < 50 then more weight given to faces with lesser vals. However current calculation
+ * does not converge to min/max.
+ */
+ float weight = ((float)wnmd->weight) / 50.0f;
+ if (wnmd->weight == 100) {
+ weight = (float)SHRT_MAX;
+ }
+ else if (wnmd->weight == 1) {
+ weight = 1 / (float)SHRT_MAX;
+ }
+ else if ((weight - 1) * 25 > 1) {
+ weight = (weight - 1) * 25;
+ }
+
+ CustomData *pdata = &result->pdata;
+ float (*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
+ if (!polynors) {
+ polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
+ }
+ BKE_mesh_calc_normals_poly(mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false);
+
+
+ const float split_angle = mesh->smoothresh;
+ short (*clnors)[2];
+ CustomData *ldata = &result->ldata;
+ clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+
+ /* Keep info whether we had clnors, it helps when generating clnor spaces and default normals. */
+ const bool has_clnors = clnors != NULL;
+ if (!clnors) {
+ clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numLoops);
+ clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+ }
+
+ MDeformVert *dvert;
+ int defgrp_index;
+ MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index);
+
+ WeightedNormalData wn_data = {
+ .numVerts = numVerts,
+ .numEdges = numEdges,
+ .numLoops = numLoops,
+ .numPolys = numPolys,
+
+ .mvert = mvert,
+ .medge = medge,
+
+ .mloop = mloop,
+ .clnors = clnors,
+ .has_clnors = has_clnors,
+ .split_angle = split_angle,
+
+ .mpoly = mpoly,
+ .polynors = polynors,
+ .poly_strength = CustomData_get_layer_named(
+ &result->pdata, CD_PROP_INT,
+ MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID),
+
+ .dvert = dvert,
+ .defgrp_index = defgrp_index,
+ .use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0,
+
+ .weight = weight,
+ .mode = wnmd->mode,
+ };
+
+ switch (wnmd->mode) {
+ case MOD_WEIGHTEDNORMAL_MODE_FACE:
+ wn_face_area(wnmd, &wn_data);
+ break;
+ case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
+ wn_corner_angle(wnmd, &wn_data);
+ break;
+ case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
+ wn_face_with_angle(wnmd, &wn_data);
+ break;
+ }
+
+ MEM_SAFE_FREE(wn_data.loop_to_poly);
+ MEM_SAFE_FREE(wn_data.mode_pair);
+ MEM_SAFE_FREE(wn_data.items_data);
+
+ return result;
+}
+
+static void initData(ModifierData *md)
+{
+ WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
+ wnmd->mode = MOD_WEIGHTEDNORMAL_MODE_FACE;
+ wnmd->weight = 50;
+ wnmd->thresh = 1e-2f;
+ wnmd->flag = 0;
+}
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
+ CustomDataMask dataMask = CD_MASK_CUSTOMLOOPNORMAL;
+
+ if (wnmd->defgrp_name[0]) {
+ dataMask |= CD_MASK_MDEFORMVERT;
+ }
+
+ if (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) {
+ dataMask |= CD_MASK_PROP_INT;
+ }
+
+ return dataMask;
+}
+
+static bool dependsOnNormals(ModifierData *UNUSED(md))
+{
+ return true;
+}
+
+ModifierTypeInfo modifierType_WeightedNormal = {
+ /* name */ "Weighted Normal",
+ /* structName */ "WeightedNormalModifierData",
+ /* structSize */ sizeof(WeightedNormalModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode |
+ eModifierTypeFlag_EnableInEditmode,
+
+ /* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ dependsOnNormals,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index e512c3fdc95..eed0c41e374 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -34,17 +34,20 @@
#include "BLI_utildefines.h"
#include "DNA_color_types.h" /* CurveMapping. */
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_colortools.h" /* CurveMapping. */
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
+#include "DEG_depsgraph.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_util.h"
#include "MOD_weightvg_util.h"
@@ -115,11 +118,13 @@ void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cm
* XXX The standard "factor" value is assumed in [0.0, 1.0] range. Else, weird results might appear.
*/
void weightvg_do_mask(
- int num, const int *indices, float *org_w, const float *new_w,
- Object *ob, DerivedMesh *dm, float fact, const char defgrp_name[MAX_VGROUP_NAME],
- Scene *scene, Tex *texture, int tex_use_channel, int tex_mapping,
+ const ModifierEvalContext *ctx,
+ const int num, const int *indices, float *org_w, const float *new_w,
+ Object *ob, Mesh *mesh, const float fact, const char defgrp_name[MAX_VGROUP_NAME],
+ Scene *scene, Tex *texture, const int tex_use_channel, const int tex_mapping,
Object *tex_map_object, const char *tex_uvlayer_name)
{
+ Depsgraph *depsgraph = ctx->depsgraph;
int ref_didx;
int i;
@@ -132,8 +137,7 @@ void weightvg_do_mask(
float (*tex_co)[3];
/* See mapping note below... */
MappingInfoModifierData t_map;
- float (*v_co)[3];
- int numVerts = dm->getNumVerts(dm);
+ const int numVerts = mesh->totvert;
/* Use new generic get_texture_coords, but do not modify our DNA struct for it...
* XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
@@ -144,13 +148,11 @@ void weightvg_do_mask(
t_map.map_object = tex_map_object;
BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
t_map.texmapping = tex_mapping;
- v_co = MEM_malloc_arrayN(numVerts, sizeof(*v_co), "WeightVG Modifier, TEX mode, v_co");
- dm->getVertCos(dm, v_co);
+
tex_co = MEM_calloc_arrayN(numVerts, sizeof(*tex_co), "WeightVG Modifier, TEX mode, tex_co");
- get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
- MEM_freeN(v_co);
+ MOD_get_texture_coords(&t_map, ob, mesh, NULL, tex_co);
- modifier_init_texture(scene, texture);
+ MOD_init_texture(depsgraph, texture);
/* For each weight (vertex), make the mix between org and new weights. */
for (i = 0; i < num; ++i) {
@@ -210,9 +212,11 @@ void weightvg_do_mask(
/* Proceed only if vgroup is valid, else use constant factor. */
/* Get actual dverts (ie vertex group data). */
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
/* Proceed only if vgroup is valid, else assume factor = O. */
- if (dvert == NULL) return;
+ if (dvert == NULL) {
+ return;
+ }
/* For each weight (vertex), make the mix between org and new weights. */
for (i = 0; i < num; i++) {
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h
index 4a31f973974..93594fd8b29 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.h
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.h
@@ -32,7 +32,10 @@
#define __MOD_WEIGHTVG_UTIL_H__
struct CurveMapping;
-struct DerivedMesh;
+struct MDeformVert;
+struct MDeformWeight;
+struct Mesh;
+struct ModifierEvalContext;
struct Object;
struct Tex;
struct Scene;
@@ -41,7 +44,7 @@ struct RNG;
/*
* XXX I'd like to make modified weights visible in WeightPaint mode,
* but couldn't figure a way to do this...
- * Maybe this will need changes in mesh_calc_modifiers (DerivedMesh.c)?
+ * Maybe this will need changes in mesh_calc_modifiers?
* Or the WeightPaint mode code itself?
*/
@@ -71,9 +74,10 @@ void weightvg_do_map(int num, float *new_w, short mode, struct CurveMapping *cma
* XXX The standard "factor" value is assumed in [0.0, 1.0] range. Else, weird results might appear.
*/
void weightvg_do_mask(
- int num, const int *indices, float *org_w, const float *new_w, Object *ob,
- DerivedMesh *dm, float fact, const char defgrp_name[MAX_VGROUP_NAME],
- struct Scene *scene, Tex *texture, int tex_use_channel, int tex_mapping,
+ const ModifierEvalContext *ctx,
+ const int num, const int *indices, float *org_w, const float *new_w, Object *ob,
+ struct Mesh *mesh, const float fact, const char defgrp_name[MAX_VGROUP_NAME],
+ struct Scene *scene, Tex *texture, const int tex_use_channel, const int tex_mapping,
Object *tex_map_object, const char *tex_uvlayer_name);
/* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
@@ -81,7 +85,7 @@ void weightvg_do_mask(
* vertex index (in case the weight table does not cover the whole vertices...).
*/
void weightvg_update_vg(
- MDeformVert *dvert, int defgrp_idx, MDeformWeight **dws, int num,
+ struct MDeformVert *dvert, int defgrp_idx, struct MDeformWeight **dws, int num,
const int *indices, const float *weights, const bool do_add,
const float add_thresh, const bool do_rem, const float rem_thresh);
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index e793c8580c9..bf7517ee634 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -34,11 +34,11 @@
#include "BLI_rand.h"
#include "DNA_color_types.h" /* CurveMapping. */
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_colortools.h" /* CurveMapping. */
#include "BKE_deform.h"
#include "BKE_library.h"
@@ -46,8 +46,8 @@
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "MEM_guardedalloc.h"
@@ -81,12 +81,12 @@ static void freeData(ModifierData *md)
curvemapping_free(wmd->cmap_curve);
}
-static void copyData(const ModifierData *md, ModifierData *target)
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
{
const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *) md;
WeightVGEditModifierData *twmd = (WeightVGEditModifierData *) target;
- modifier_copyData_generic(md, target);
+ modifier_copyData_generic(md, target, flag);
twmd->cmap_curve = curvemapping_copy(wmd->cmap_curve);
}
@@ -137,54 +137,40 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- DagNode *curNode;
-
- if (wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- curNode = dag_get_node(ctx->forest, wmd->mask_tex_map_obj);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGEdit Modifier");
- }
-
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
- dag_add_relation(ctx->forest, ctx->obNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGEdit Modifier");
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
}
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
}
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
/* If no vertex group, bypass. */
return (wmd->defgrp_name[0] == '\0');
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
+ BLI_assert(mesh != NULL);
+
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- DerivedMesh *dm = derivedData;
+
MDeformVert *dvert = NULL;
MDeformWeight **dw = NULL;
float *org_w; /* Array original weights. */
float *new_w; /* Array new weights. */
- int numVerts;
- int defgrp_index;
int i;
+
/* Flags. */
const bool do_add = (wmd->edit_flags & MOD_WVG_EDIT_ADD2VG) != 0;
const bool do_rem = (wmd->edit_flags & MOD_WVG_EDIT_REMFVG) != 0;
@@ -194,32 +180,43 @@ static DerivedMesh *applyModifier(
#endif
/* Get number of verts. */
- numVerts = dm->getNumVerts(dm);
+ const int numVerts = mesh->totvert;
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
- if ((numVerts == 0) || BLI_listbase_is_empty(&ob->defbase))
- return dm;
+ if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
+ return mesh;
+ }
/* Get vgroup idx from its name. */
- defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
- if (defgrp_index == -1)
- return dm;
+ const int defgrp_index = defgroup_name_index(ctx->object, wmd->defgrp_name);
+ if (defgrp_index == -1) {
+ return mesh;
+ }
- dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts);
+ const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
/* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
- if (!dvert) {
+ if (!has_mdef) {
/* If this modifier is not allowed to add vertices, just return. */
- if (!do_add)
- return dm;
- /* Else, add a valid data layer! */
- dvert = CustomData_add_layer(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
- /* Ultimate security check. */
- if (!dvert)
- return dm;
+ if (!do_add) {
+ return mesh;
+ }
}
+ if (has_mdef) {
+ dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
+ }
+ else {
+ /* Add a valid data layer! */
+ dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
+ }
+ /* Ultimate security check. */
+ if (!dvert) {
+ return mesh;
+ }
+ mesh->dvert = dvert;
+
/* Get org weights, assuming 0.0 for vertices not in given vgroup. */
org_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, org_w");
new_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, new_w");
@@ -238,18 +235,21 @@ static DerivedMesh *applyModifier(
if (wmd->falloff_type != MOD_WVG_MAPPING_NONE) {
RNG *rng = NULL;
- if (wmd->falloff_type == MOD_WVG_MAPPING_RANDOM)
- rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2));
+ if (wmd->falloff_type == MOD_WVG_MAPPING_RANDOM) {
+ rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ctx->object->id.name + 2));
+ }
weightvg_do_map(numVerts, new_w, wmd->falloff_type, wmd->cmap_curve, rng);
- if (rng)
+ if (rng) {
BLI_rng_free(rng);
+ }
}
/* Do masking. */
- weightvg_do_mask(numVerts, NULL, org_w, new_w, ob, dm, wmd->mask_constant,
- wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture,
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ weightvg_do_mask(ctx, numVerts, NULL, org_w, new_w, ctx->object, mesh, wmd->mask_constant,
+ wmd->mask_defgrp_name, scene, wmd->mask_texture,
wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
@@ -269,7 +269,7 @@ static DerivedMesh *applyModifier(
MEM_freeN(dw);
/* Return the vgroup-modified mesh. */
- return dm;
+ return mesh;
}
@@ -284,17 +284,23 @@ ModifierTypeInfo modifierType_WeightVGEdit = {
eModifierTypeFlag_UsesPreview,
/* copyData */ copyData,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 51341890c51..674ef106737 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -32,26 +32,26 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
#include "MOD_modifiertypes.h"
-
/**
* This mixes the old weight with the new weight factor.
*/
@@ -172,53 +172,36 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- DagNode *curNode;
-
- if (wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- curNode = dag_get_node(ctx->forest, wmd->mask_tex_map_obj);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGMix Modifier");
- }
-
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
- dag_add_relation(ctx->forest, ctx->obNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGMix Modifier");
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
+
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
}
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
}
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
/* If no vertex group, bypass. */
return (wmd->defgrp_name_a[0] == '\0');
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
+ BLI_assert(mesh != NULL);
+
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- DerivedMesh *dm = derivedData;
+
MDeformVert *dvert = NULL;
MDeformWeight **dw1, **tdw1, **dw2, **tdw2;
- int numVerts;
- int defgrp_index, defgrp_index_other = -1;
float *org_w;
float *new_w;
int *tidx, *indices = NULL;
@@ -230,37 +213,51 @@ static DerivedMesh *applyModifier(
#endif
/* Get number of verts. */
- numVerts = dm->getNumVerts(dm);
+ const int numVerts = mesh->totvert;
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
- if ((numVerts == 0) || BLI_listbase_is_empty(&ob->defbase))
- return dm;
+ if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
+ return mesh;
+ }
/* Get vgroup idx from its name. */
- defgrp_index = defgroup_name_index(ob, wmd->defgrp_name_a);
- if (defgrp_index == -1)
- return dm;
+ const int defgrp_index = defgroup_name_index(ctx->object, wmd->defgrp_name_a);
+ if (defgrp_index == -1) {
+ return mesh;
+ }
/* Get second vgroup idx from its name, if given. */
- if (wmd->defgrp_name_b[0] != (char)0) {
- defgrp_index_other = defgroup_name_index(ob, wmd->defgrp_name_b);
- if (defgrp_index_other == -1)
- return dm;
+ int defgrp_index_other = -1;
+ if (wmd->defgrp_name_b[0] != '\0') {
+ defgrp_index_other = defgroup_name_index(ctx->object, wmd->defgrp_name_b);
+ if (defgrp_index_other == -1) {
+ return mesh;
+ }
}
- dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts);
+ const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
/* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
- if (!dvert) {
+ if (!has_mdef) {
/* If not affecting all vertices, just return. */
- if (wmd->mix_set != MOD_WVG_SET_ALL)
- return dm;
- /* Else, add a valid data layer! */
- dvert = CustomData_add_layer(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
- /* Ultimate security check. */
- if (!dvert)
- return dm;
+ if (wmd->mix_set != MOD_WVG_SET_ALL) {
+ return mesh;
+ }
+ }
+
+ if (has_mdef) {
+ dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
}
+ else {
+ /* Add a valid data layer! */
+ dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
+ }
+ /* Ultimate security check. */
+ if (!dvert) {
+ return mesh;
+ }
+ mesh->dvert = dvert;
+
/* Find out which vertices to work on. */
tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGMix Modifier, tidx");
tdw1 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw1");
@@ -327,7 +324,7 @@ static DerivedMesh *applyModifier(
MEM_freeN(tdw1);
MEM_freeN(tdw2);
MEM_freeN(tidx);
- return dm;
+ return mesh;
}
if (numIdx != -1) {
indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGMix Modifier, indices");
@@ -361,8 +358,9 @@ static DerivedMesh *applyModifier(
}
/* Do masking. */
- weightvg_do_mask(numIdx, indices, org_w, new_w, ob, dm, wmd->mask_constant,
- wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture,
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ctx->object, mesh, wmd->mask_constant,
+ wmd->mask_defgrp_name, scene, wmd->mask_texture,
wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
@@ -382,12 +380,10 @@ static DerivedMesh *applyModifier(
MEM_freeN(new_w);
MEM_freeN(dw1);
MEM_freeN(dw2);
-
- if (indices)
- MEM_freeN(indices);
+ MEM_SAFE_FREE(indices);
/* Return the vgroup-modified mesh. */
- return dm;
+ return mesh;
}
@@ -402,17 +398,23 @@ ModifierTypeInfo modifierType_WeightVGMix = {
eModifierTypeFlag_UsesPreview,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index b98036b9913..6facccaf57a 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -40,20 +40,24 @@
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_bvhutils.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
-#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
//#define USE_TIMEIT
@@ -139,7 +143,7 @@ static void vert2geom_task_cb_ex(
static void get_vert2geom_distance(
int numVerts, float (*v_cos)[3],
float *dist_v, float *dist_e, float *dist_f,
- DerivedMesh *target, const SpaceTransform *loc2trgt)
+ Mesh *target, const SpaceTransform *loc2trgt)
{
Vert2GeomData data = {0};
Vert2GeomDataChunk data_chunk = {{{0}}};
@@ -150,7 +154,7 @@ static void get_vert2geom_distance(
if (dist_v) {
/* Create a bvh-tree of the given target's verts. */
- bvhtree_from_mesh_get(&treeData_v, target, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treeData_v, target, BVHTREE_FROM_VERTS, 2);
if (treeData_v.tree == NULL) {
OUT_OF_MEMORY();
return;
@@ -158,7 +162,7 @@ static void get_vert2geom_distance(
}
if (dist_e) {
/* Create a bvh-tree of the given target's edges. */
- bvhtree_from_mesh_get(&treeData_e, target, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treeData_e, target, BVHTREE_FROM_EDGES, 2);
if (treeData_e.tree == NULL) {
OUT_OF_MEMORY();
return;
@@ -166,7 +170,7 @@ static void get_vert2geom_distance(
}
if (dist_f) {
/* Create a bvh-tree of the given target's faces. */
- bvhtree_from_mesh_get(&treeData_f, target, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treeData_f, target, BVHTREE_FROM_LOOPTRI, 2);
if (treeData_f.tree == NULL) {
OUT_OF_MEMORY();
return;
@@ -260,13 +264,15 @@ static void do_map(Object *ob, float *weights, const int nidx, const float min_d
if (!ELEM(mode, MOD_WVG_MAPPING_NONE, MOD_WVG_MAPPING_CURVE)) {
RNG *rng = NULL;
- if (mode == MOD_WVG_MAPPING_RANDOM)
+ if (mode == MOD_WVG_MAPPING_RANDOM) {
rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2));
+ }
weightvg_do_map(nidx, weights, mode, NULL, rng);
- if (rng)
+ if (rng) {
BLI_rng_free(rng);
+ }
}
}
@@ -335,29 +341,6 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
walk(userData, ob, md, "mask_texture");
}
-static void updateDepgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
-{
- WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- DagNode *curNode;
-
- if (wmd->proximity_ob_target) {
- curNode = dag_get_node(ctx->forest, wmd->proximity_ob_target);
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGProximity Modifier");
- }
-
- if (wmd->mask_tex_map_obj && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- curNode = dag_get_node(ctx->forest, wmd->mask_tex_map_obj);
-
- dag_add_relation(ctx->forest, curNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGProximity Modifier");
- }
-
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL)
- dag_add_relation(ctx->forest, ctx->obNode, ctx->obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA,
- "WeightVGProximity Modifier");
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
@@ -369,13 +352,11 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
DEG_add_object_relation(ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
- if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
- DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
- DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
- }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
-static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
/* If no vertex group, bypass. */
@@ -384,16 +365,15 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
return (wmd->proximity_ob_target == NULL);
}
-static DerivedMesh *applyModifier(
- ModifierData *md, Object *ob, DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
+ BLI_assert(mesh != NULL);
+
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- DerivedMesh *dm = derivedData;
MDeformVert *dvert = NULL;
MDeformWeight **dw, **tdw;
- int numVerts;
float (*v_cos)[3] = NULL; /* The vertices coordinates. */
+ Object *ob = ctx->object;
Object *obr = NULL; /* Our target object. */
int defgrp_index;
float *tw = NULL;
@@ -412,32 +392,42 @@ static DerivedMesh *applyModifier(
#endif
/* Get number of verts. */
- numVerts = dm->getNumVerts(dm);
+ const int numVerts = mesh->totvert;
/* Check if we can just return the original mesh.
* Must have verts and therefore verts assigned to vgroups to do anything useful!
*/
- if ((numVerts == 0) || BLI_listbase_is_empty(&ob->defbase))
- return dm;
+ if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
+ return mesh;
+ }
/* Get our target object. */
obr = wmd->proximity_ob_target;
- if (obr == NULL)
- return dm;
+ if (obr == NULL) {
+ return mesh;
+ }
/* Get vgroup idx from its name. */
defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
- if (defgrp_index == -1)
- return dm;
+ if (defgrp_index == -1) {
+ return mesh;
+ }
- dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts);
- /* If no vertices were ever added to an object's vgroup, dvert might be NULL.
- * As this modifier never add vertices to vgroup, just return. */
- if (!dvert)
- return dm;
+ const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
+ /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
+ /* As this modifier never add vertices to vgroup, just return. */
+ if (!has_mdef) {
+ return mesh;
+ }
- /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight.
- */
+ dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
+ /* Ultimate security check. */
+ if (!dvert) {
+ return mesh;
+ }
+ mesh->dvert = dvert;
+
+ /* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight. */
tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGProximity Modifier, tidx");
tw = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGProximity Modifier, tw");
tdw = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGProximity Modifier, tdw");
@@ -454,7 +444,7 @@ static DerivedMesh *applyModifier(
MEM_freeN(tidx);
MEM_freeN(tw);
MEM_freeN(tdw);
- return dm;
+ return mesh;
}
if (numIdx != numVerts) {
indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGProximity Modifier, indices");
@@ -474,25 +464,24 @@ static DerivedMesh *applyModifier(
MEM_freeN(tidx);
/* Get our vertex coordinates. */
- v_cos = MEM_malloc_arrayN(numIdx, sizeof(float[3]), "WeightVGProximity Modifier, v_cos");
if (numIdx != numVerts) {
- /* XXX In some situations, this code can be up to about 50 times more performant
- * than simply using getVertCo for each affected vertex...
- */
- float (*tv_cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "WeightVGProximity Modifier, tv_cos");
- dm->getVertCos(dm, tv_cos);
- for (i = 0; i < numIdx; i++)
+ float (*tv_cos)[3] = BKE_mesh_vertexCos_get(mesh, NULL);
+ v_cos = MEM_malloc_arrayN(numIdx, sizeof(float[3]), "WeightVGProximity Modifier, v_cos");
+ for (i = 0; i < numIdx; i++) {
copy_v3_v3(v_cos[i], tv_cos[indices[i]]);
+ }
MEM_freeN(tv_cos);
}
- else
- dm->getVertCos(dm, v_cos);
+ else {
+ v_cos = BKE_mesh_vertexCos_get(mesh, NULL);
+ }
/* Compute wanted distances. */
if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJECT) {
const float dist = get_ob2ob_distance(ob, obr);
- for (i = 0; i < numIdx; i++)
+ for (i = 0; i < numIdx; i++) {
new_w[i] = dist;
+ }
}
else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) {
const bool use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS) != 0;
@@ -500,23 +489,11 @@ static DerivedMesh *applyModifier(
const bool use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES) != 0;
if (use_trgt_verts || use_trgt_edges || use_trgt_faces) {
- DerivedMesh *target_dm = obr->derivedFinal;
- bool free_target_dm = false;
- if (!target_dm) {
- if (ELEM(obr->type, OB_CURVE, OB_SURF, OB_FONT))
- target_dm = CDDM_from_curve(obr);
- else if (obr->type == OB_MESH) {
- Mesh *me = (Mesh *)obr->data;
- if (me->edit_btmesh)
- target_dm = CDDM_from_editbmesh(me->edit_btmesh, false, false);
- else
- target_dm = CDDM_from_mesh(me);
- }
- free_target_dm = true;
- }
+ bool target_mesh_free;
+ Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(obr, &target_mesh_free);
- /* We must check that we do have a valid target_dm! */
- if (target_dm) {
+ /* We must check that we do have a valid target_mesh! */
+ if (target_mesh != NULL) {
SpaceTransform loc2trgt;
float *dists_v = use_trgt_verts ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_v") : NULL;
float *dists_e = use_trgt_edges ? MEM_malloc_arrayN(numIdx, sizeof(float), "dists_e") : NULL;
@@ -524,7 +501,7 @@ static DerivedMesh *applyModifier(
BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr);
get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f,
- target_dm, &loc2trgt);
+ target_mesh, &loc2trgt);
for (i = 0; i < numIdx; i++) {
new_w[i] = dists_v ? dists_v[i] : FLT_MAX;
if (dists_e)
@@ -532,10 +509,14 @@ static DerivedMesh *applyModifier(
if (dists_f)
new_w[i] = min_ff(dists_f[i], new_w[i]);
}
- if (free_target_dm) target_dm->release(target_dm);
- if (dists_v) MEM_freeN(dists_v);
- if (dists_e) MEM_freeN(dists_e);
- if (dists_f) MEM_freeN(dists_f);
+
+ MEM_SAFE_FREE(dists_v);
+ MEM_SAFE_FREE(dists_e);
+ MEM_SAFE_FREE(dists_f);
+
+ if (target_mesh_free) {
+ BKE_id_free(NULL, target_mesh);
+ }
}
/* Else, fall back to default obj2vert behavior. */
else {
@@ -551,8 +532,9 @@ static DerivedMesh *applyModifier(
do_map(ob, new_w, numIdx, wmd->min_dist, wmd->max_dist, wmd->falloff_type);
/* Do masking. */
- weightvg_do_mask(numIdx, indices, org_w, new_w, ob, dm, wmd->mask_constant,
- wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture,
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ob, mesh, wmd->mask_constant,
+ wmd->mask_defgrp_name, scene, wmd->mask_texture,
wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
@@ -569,16 +551,15 @@ static DerivedMesh *applyModifier(
MEM_freeN(org_w);
MEM_freeN(new_w);
MEM_freeN(dw);
- if (indices)
- MEM_freeN(indices);
MEM_freeN(v_cos);
+ MEM_SAFE_FREE(indices);
#ifdef USE_TIMEIT
TIMEIT_END(perf);
#endif
/* Return the vgroup-modified mesh. */
- return dm;
+ return mesh;
}
@@ -593,17 +574,23 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
eModifierTypeFlag_UsesPreview,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
- /* updateDepgraph */ updateDepgraph,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 84a507cd35c..a47be7b5244 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -23,12 +23,13 @@
* \ingroup modifiers
*/
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
+#include "BKE_mesh.h"
#include "MOD_modifiertypes.h"
@@ -60,14 +61,23 @@ static bool dependsOnNormals(ModifierData *UNUSED(md))
return true;
}
-static DerivedMesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, DerivedMesh *dm)
+static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *mesh)
{
- DerivedMesh *result;
+ Mesh *result;
BMesh *bm;
const int defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
- bm = DM_to_bmesh(dm, true);
+ bm = BKE_mesh_to_bmesh_ex(
+ mesh,
+ &(struct BMeshCreateParams){0},
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .add_key_index = false,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ .cd_mask_extra = CD_MASK_ORIGINDEX,
+ });
BM_mesh_wireframe(
bm,
@@ -84,18 +94,21 @@ static DerivedMesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob,
MAX2(ob->totcol - 1, 0),
false);
- result = CDDM_from_bmesh(bm, true);
+ result = BKE_mesh_from_bmesh_for_eval_nomain(bm, 0);
BM_mesh_free(bm);
- result->dirty |= DM_DIRTY_NORMALS;
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
-static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag))
+static Mesh *applyModifier(
+ ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh)
{
- return WireframeModifier_do((WireframeModifierData *)md, ob, dm);
+ return WireframeModifier_do((WireframeModifierData *)md, ctx->object, mesh);
}
@@ -108,18 +121,24 @@ ModifierTypeInfo modifierType_Wireframe = {
eModifierTypeFlag_SupportsEditmode,
/* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
- /* applyModifierEM */ NULL,
+
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
- /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 7ef41b25de8..8df114afa24 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC
../blenkernel
../blenlib
../blentranslation
+ ../depsgraph
../gpu
../imbuf
../makesdna
@@ -135,22 +136,17 @@ set(SRC
shader/nodes/node_shader_curves.c
shader/nodes/node_shader_gamma.c
shader/nodes/node_shader_brightness.c
- shader/nodes/node_shader_geom.c
shader/nodes/node_shader_hueSatVal.c
shader/nodes/node_shader_invert.c
- shader/nodes/node_shader_lamp.c
shader/nodes/node_shader_mapping.c
- shader/nodes/node_shader_material.c
shader/nodes/node_shader_math.c
shader/nodes/node_shader_mixRgb.c
shader/nodes/node_shader_normal.c
- shader/nodes/node_shader_output.c
shader/nodes/node_shader_rgb.c
shader/nodes/node_shader_sepcombRGB.c
shader/nodes/node_shader_sepcombHSV.c
shader/nodes/node_shader_sepcombXYZ.c
shader/nodes/node_shader_squeeze.c
- shader/nodes/node_shader_texture.c
shader/nodes/node_shader_valToRgb.c
shader/nodes/node_shader_value.c
shader/nodes/node_shader_wireframe.c
@@ -184,9 +180,11 @@ set(SRC
shader/nodes/node_shader_light_falloff.c
shader/nodes/node_shader_light_path.c
shader/nodes/node_shader_mix_shader.c
+ shader/nodes/node_shader_shaderToRgb.c
shader/nodes/node_shader_normal_map.c
shader/nodes/node_shader_object_info.c
shader/nodes/node_shader_hair_info.c
+ shader/nodes/node_shader_eevee_specular.c
shader/nodes/node_shader_output_lamp.c
shader/nodes/node_shader_output_material.c
shader/nodes/node_shader_output_world.c
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 2a82b706de5..a728d1e228d 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -141,7 +141,7 @@ void register_node_type_cmp_planetrackdeform(void);
void register_node_type_cmp_cornerpin(void);
void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node);
-void node_cmp_rlayers_register_pass(struct bNodeTree *ntree, struct bNode *node, struct Scene *scene, struct SceneRenderLayer *srl, const char *name, int type);
+void node_cmp_rlayers_register_pass(struct bNodeTree *ntree, struct bNode *node, struct Scene *scene, struct ViewLayer *view_layer, const char *name, int type);
const char *node_cmp_rlayers_sock_to_pass(int sock_index);
#endif
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index d4134f09597..2f466b0296c 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -44,20 +44,16 @@ void register_node_tree_type_sh(void);
void register_node_type_sh_group(void);
-void register_node_type_sh_output(void);
-void register_node_type_sh_material(void);
void register_node_type_sh_camera(void);
-void register_node_type_sh_lamp(void);
void register_node_type_sh_value(void);
void register_node_type_sh_rgb(void);
void register_node_type_sh_mix_rgb(void);
void register_node_type_sh_valtorgb(void);
void register_node_type_sh_rgbtobw(void);
-void register_node_type_sh_texture(void);
+void register_node_type_sh_shadertorgb(void);
void register_node_type_sh_normal(void);
void register_node_type_sh_gamma(void);
void register_node_type_sh_brightcontrast(void);
-void register_node_type_sh_geom(void);
void register_node_type_sh_mapping(void);
void register_node_type_sh_curve_vec(void);
void register_node_type_sh_curve_rgb(void);
@@ -65,7 +61,6 @@ void register_node_type_sh_math(void);
void register_node_type_sh_vect_math(void);
void register_node_type_sh_squeeze(void);
void register_node_type_sh_dynamic(void);
-void register_node_type_sh_material_ext(void);
void register_node_type_sh_invert(void);
void register_node_type_sh_seprgb(void);
void register_node_type_sh_combrgb(void);
@@ -122,9 +117,12 @@ void register_node_type_sh_mix_shader(void);
void register_node_type_sh_add_shader(void);
void register_node_type_sh_uvmap(void);
void register_node_type_sh_uvalongstroke(void);
+void register_node_type_sh_eevee_metallic(void);
+void register_node_type_sh_eevee_specular(void);
void register_node_type_sh_output_lamp(void);
void register_node_type_sh_output_material(void);
+void register_node_type_sh_output_eevee_material(void);
void register_node_type_sh_output_world(void);
void register_node_type_sh_output_linestyle(void);
diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h
index 42735b21e03..3ff65ce4fd9 100644
--- a/source/blender/nodes/NOD_socket.h
+++ b/source/blender/nodes/NOD_socket.h
@@ -49,7 +49,7 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struc
void node_verify_socket_templates(struct bNodeTree *ntree, struct bNode *node);
void node_socket_init_default_value(struct bNodeSocket *sock);
-void node_socket_copy_default_value(struct bNodeSocket *to, struct bNodeSocket *from);
+void node_socket_copy_default_value(struct bNodeSocket *to, const struct bNodeSocket *from);
void register_standard_node_socket_types(void);
#endif
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 2fa8cda56a5..22c2afcc466 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -40,34 +40,30 @@ DefNode( Node, NODE_GROUP_INPUT, def_group_input, "GROUP
DefNode( Node, NODE_GROUP_OUTPUT, def_group_output, "GROUP_OUTPUT", GroupOutput, "Group Output", "" )
DefNode( Node, NODE_REROUTE, 0, "REROUTE", Reroute, "Reroute", "" )
-DefNode( ShaderNode, SH_NODE_OUTPUT, def_sh_output, "OUTPUT", Output, "Output", "" )
-DefNode( ShaderNode, SH_NODE_MATERIAL, def_sh_material, "MATERIAL", Material, "Material", "" )
DefNode( ShaderNode, SH_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
DefNode( ShaderNode, SH_NODE_VALUE, 0, "VALUE", Value, "Value", "" )
DefNode( ShaderNode, SH_NODE_MIX_RGB, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "" )
DefNode( ShaderNode, SH_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "" )
DefNode( ShaderNode, SH_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "" )
-DefNode( ShaderNode, SH_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" )
+DefNode( ShaderNode, SH_NODE_SHADERTORGB, 0, "SHADERTORGB", ShaderToRGB, "Shader to RGB", "" )
DefNode( ShaderNode, SH_NODE_NORMAL, 0, "NORMAL", Normal, "Normal", "" )
DefNode( ShaderNode, SH_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "" )
DefNode( ShaderNode, SH_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Bright Contrast", "" )
-DefNode( ShaderNode, SH_NODE_GEOMETRY, def_sh_geometry, "GEOMETRY", Geometry, "Geometry", "" )
DefNode( ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPING", Mapping, "Mapping", "" )
DefNode( ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "" )
DefNode( ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "" )
DefNode( ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "" )
-DefNode( ShaderNode, SH_NODE_LAMP, def_sh_lamp, "LAMP", LampData, "Lamp Data", "" )
DefNode( ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode( ShaderNode, SH_NODE_VECT_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode( ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )
-DefNode( ShaderNode, SH_NODE_MATERIAL_EXT, def_sh_material, "MATERIAL_EXT", ExtendedMaterial, "Extended Material", "" )
DefNode( ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
DefNode( ShaderNode, SH_NODE_SEPRGB, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
DefNode( ShaderNode, SH_NODE_COMBRGB, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
DefNode( ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation", "" )
DefNode( ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "" )
-DefNode( ShaderNode, SH_NODE_OUTPUT_LAMP, def_sh_output, "OUTPUT_LAMP", OutputLamp, "Lamp Output", "" )
+DefNode( ShaderNode, SH_NODE_EEVEE_SPECULAR, 0, "EEVEE_SPECULAR", EeveeSpecular, "Specular", "" )
+DefNode( ShaderNode, SH_NODE_OUTPUT_LIGHT, def_sh_output, "OUTPUT_LIGHT", OutputLight, "Light Output", "" )
DefNode( ShaderNode, SH_NODE_OUTPUT_WORLD, def_sh_output, "OUTPUT_WORLD", OutputWorld, "World Output", "" )
DefNode( ShaderNode, SH_NODE_OUTPUT_LINESTYLE, def_sh_output_linestyle,"OUTPUT_LINESTYLE", OutputLineStyle, "Line Style Output", "" )
DefNode( ShaderNode, SH_NODE_FRESNEL, 0, "FRESNEL", Fresnel, "Fresnel", "" )
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index 1312b764546..4f796da58dc 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -261,7 +261,7 @@ void ntreeCompositUpdateRLayers(bNodeTree *ntree)
}
-void ntreeCompositRegisterPass(bNodeTree *ntree, Scene *scene, SceneRenderLayer *srl, const char *name, int type)
+void ntreeCompositRegisterPass(bNodeTree *ntree, Scene *scene, ViewLayer *view_layer, const char *name, int type)
{
bNode *node;
@@ -269,7 +269,7 @@ void ntreeCompositRegisterPass(bNodeTree *ntree, Scene *scene, SceneRenderLayer
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == CMP_NODE_R_LAYERS)
- node_cmp_rlayers_register_pass(ntree, node, scene, srl, name, type);
+ node_cmp_rlayers_register_pass(ntree, node, scene, view_layer, name, type);
}
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
index bf9ab4a5064..af988c0df39 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c
@@ -37,7 +37,7 @@
/* this is taken from the cryptomatte specification 1.0 */
-static inline float hash_to_float(uint32_t hash)
+BLI_INLINE float hash_to_float(uint32_t hash)
{
uint32_t mantissa = hash & ((1 << 23) - 1);
uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index eb48d332f19..3ee4e512d76 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -41,6 +41,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
/* **************** IMAGE (and RenderResult, multilayer image) ******************** */
@@ -190,16 +191,16 @@ typedef struct RLayerUpdateData {
int prev_index;
} RLayerUpdateData;
-void node_cmp_rlayers_register_pass(bNodeTree *ntree, bNode *node, Scene *scene, SceneRenderLayer *srl, const char *name, int type)
+void node_cmp_rlayers_register_pass(bNodeTree *ntree, bNode *node, Scene *scene, ViewLayer *view_layer, const char *name, int type)
{
RLayerUpdateData *data = node->storage;
- if (scene == NULL || srl == NULL || data == NULL || node->id != (ID *)scene) {
+ if (scene == NULL || view_layer == NULL || data == NULL || node->id != (ID *)scene) {
return;
}
- SceneRenderLayer *node_srl = BLI_findlink(&scene->r.layers, node->custom1);
- if (node_srl != srl) {
+ ViewLayer *node_view_layer = BLI_findlink(&scene->view_layers, node->custom1);
+ if (node_view_layer != view_layer) {
return;
}
@@ -220,15 +221,15 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree, bNode *node, LinkNo
if (scene) {
RenderEngineType *engine_type = RE_engines_find(scene->r.engine);
if (engine_type && engine_type->update_render_passes) {
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, node->custom1);
- if (srl) {
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, node->custom1);
+ if (view_layer) {
RLayerUpdateData *data = MEM_mallocN(sizeof(RLayerUpdateData), "render layer update data");
data->available_sockets = available_sockets;
data->prev_index = -1;
node->storage = data;
RenderEngine *engine = RE_engine_create(engine_type);
- engine_type->update_render_passes(engine, scene, srl);
+ engine_type->update_render_passes(engine, scene, view_layer);
RE_engine_free(engine);
MEM_freeN(data);
@@ -305,8 +306,8 @@ static void node_composit_init_image(bNodeTree *ntree, bNode *node)
node->storage = iuser;
iuser->frames = 1;
iuser->sfra = 1;
- iuser->fie_ima = 2;
iuser->ok = 1;
+ iuser->flag |= IMA_ANIM_ALWAYS;
/* setup initial outputs */
cmp_node_image_verify_outputs(ntree, node, false);
@@ -444,6 +445,7 @@ void register_node_type_cmp_rlayers(void)
node_type_storage(&ntype, NULL, node_composit_free_rlayers, node_composit_copy_rlayers);
node_type_update(&ntype, cmp_node_rlayers_update, NULL);
node_type_init(&ntype, node_cmp_rlayers_outputs);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.c b/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
index f7008bc9ae4..863c8af66bb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
+++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
@@ -47,7 +47,6 @@ static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node
ImageUser *iuser = MEM_callocN(sizeof(ImageUser), "node image user");
node->storage = iuser;
iuser->sfra = 1;
- iuser->fie_ima = 2;
iuser->ok = 1;
node->custom1 = 50; /* default 50% split */
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.c b/source/blender/nodes/composite/nodes/node_composite_viewer.c
index f82b0d7206a..6221202398a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.c
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.c
@@ -49,7 +49,6 @@ static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node)
ImageUser *iuser = MEM_callocN(sizeof(ImageUser), "node image user");
node->storage = iuser;
iuser->sfra = 1;
- iuser->fie_ima = 2;
iuser->ok = 1;
node->custom3 = 0.5f;
node->custom4 = 0.5f;
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index cb04b341c26..2dbb573f305 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -210,7 +210,6 @@ void register_node_type_frame(void)
node_type_init(ntype, node_frame_init);
node_type_storage(ntype, "NodeFrame", node_free_standard_storage, node_copy_standard_storage);
node_type_size(ntype, 150, 100, 0);
- node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
ntype->needs_free = 1;
nodeRegisterType(ntype);
@@ -484,7 +483,6 @@ void register_node_type_group_input(void)
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_input_init);
node_type_update(ntype, node_group_input_update, node_group_input_verify);
- node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
ntype->needs_free = 1;
nodeRegisterType(ntype);
@@ -583,7 +581,6 @@ void register_node_type_group_output(void)
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_output_init);
node_type_update(ntype, node_group_output_update, node_group_output_verify);
- node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
ntype->needs_free = 1;
nodeRegisterType(ntype);
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 4f7f5b5ab1c..09c06e00382 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -306,8 +306,6 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call
* If the mute func is not set, assume the node should never be muted,
* and hence execute it!
*/
-// if (node->typeinfo->compatibility == NODE_NEW_SHADING)
-// return false;
if (node->typeinfo->execfunc && !(node->flag & NODE_MUTED))
node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout);
}
diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c
index d1903a53334..23ba51bbe10 100644
--- a/source/blender/nodes/intern/node_socket.c
+++ b/source/blender/nodes/intern/node_socket.c
@@ -267,7 +267,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
}
}
-void node_socket_copy_default_value(bNodeSocket *to, bNodeSocket *from)
+void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from)
{
/* sanity check */
if (to->type != from->type)
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 16fda773040..7fe5b7df37d 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -39,6 +39,7 @@
#include "DNA_space_types.h"
#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
@@ -64,14 +65,18 @@
#include "node_util.h"
#include "node_shader_util.h"
+
+static void ntree_shader_tag_ssr_node(bNodeTree *ntree, bNode *output_node);
+static void ntree_shader_tag_sss_node(bNodeTree *ntree, bNode *output_node);
+
static bool shader_tree_poll(const bContext *C, bNodeTreeType *UNUSED(treetype))
{
Scene *scene = CTX_data_scene(C);
+ const char *engine_id = scene->r.engine;
+
/* allow empty engine string too, this is from older versions that didn't have registerable engines yet */
- return (scene->r.engine[0] == '\0' ||
- STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER) ||
- STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME) ||
- STREQ(scene->r.engine, RE_engine_id_CYCLES) ||
+ return (engine_id[0] == '\0' ||
+ STREQ(engine_id, RE_engine_id_CYCLES) ||
!BKE_scene_use_shading_nodes_custom(scene));
}
@@ -79,11 +84,10 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre
{
SpaceNode *snode = CTX_wm_space_node(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = OBACT;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
- if ((snode->shaderfrom == SNODE_SHADER_OBJECT) ||
- (BKE_scene_use_new_shading_nodes(scene) == false))
- {
+ if (snode->shaderfrom == SNODE_SHADER_OBJECT) {
if (ob) {
*r_from = &ob->id;
if (ob->type == OB_LAMP) {
@@ -101,7 +105,7 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre
}
#ifdef WITH_FREESTYLE
else if (snode->shaderfrom == SNODE_SHADER_LINESTYLE) {
- FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene);
+ FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(view_layer);
if (linestyle) {
*r_from = NULL;
*r_id = &linestyle->id;
@@ -118,16 +122,12 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre
}
}
-static void foreach_nodeclass(Scene *scene, void *calldata, bNodeClassCallback func)
+static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCallback func)
{
func(calldata, NODE_CLASS_INPUT, N_("Input"));
func(calldata, NODE_CLASS_OUTPUT, N_("Output"));
-
- if (BKE_scene_use_new_shading_nodes(scene)) {
- func(calldata, NODE_CLASS_SHADER, N_("Shader"));
- func(calldata, NODE_CLASS_TEXTURE, N_("Texture"));
- }
-
+ func(calldata, NODE_CLASS_SHADER, N_("Shader"));
+ func(calldata, NODE_CLASS_TEXTURE, N_("Texture"));
func(calldata, NODE_CLASS_OP_COLOR, N_("Color"));
func(calldata, NODE_CLASS_OP_VECTOR, N_("Vector"));
func(calldata, NODE_CLASS_CONVERTOR, N_("Convertor"));
@@ -182,7 +182,7 @@ void register_node_tree_type_sh(void)
tt->type = NTREE_SHADER;
strcpy(tt->idname, "ShaderNodeTree");
- strcpy(tt->ui_name, "Shader");
+ strcpy(tt->ui_name, "Shader Editor");
tt->ui_icon = 0; /* defined in drawnode.c */
strcpy(tt->ui_description, "Shader nodes");
@@ -214,16 +214,75 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
* can change in the future and make it a generic function, but for now it stays
* private here.
*/
-static bNode *ntree_shader_output_node(bNodeTree *ntree)
+bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
{
/* Make sure we only have single node tagged as output. */
ntreeSetOutput(ntree);
- for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
- if (node->flag & NODE_DO_OUTPUT) {
- return node;
+
+ /* Find output node that matches type and target. If there are
+ * multiple, we prefer exact target match and active nodes. */
+ bNode *output_node = NULL;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (!ELEM(node->type, SH_NODE_OUTPUT_MATERIAL,
+ SH_NODE_OUTPUT_WORLD,
+ SH_NODE_OUTPUT_LIGHT))
+ {
+ continue;
+ }
+
+ if (node->custom1 == SHD_OUTPUT_ALL) {
+ if (output_node == NULL) {
+ output_node = node;
+ }
+ else if (output_node->custom1 == SHD_OUTPUT_ALL) {
+ if ((node->flag & NODE_DO_OUTPUT) &&
+ !(output_node->flag & NODE_DO_OUTPUT))
+ {
+ output_node = node;
+ }
+ }
+ }
+ else if (node->custom1 == target) {
+ if (output_node == NULL) {
+ output_node = node;
+ }
+ else if (output_node->custom1 == SHD_OUTPUT_ALL) {
+ output_node = node;
+ }
+ else if ((node->flag & NODE_DO_OUTPUT) &&
+ !(output_node->flag & NODE_DO_OUTPUT))
+ {
+ output_node = node;
+ }
}
}
- return NULL;
+
+ return output_node;
+}
+
+/* Find the active output node of a group nodetree.
+ *
+ * Does not return the shading output node but the group output node.
+ */
+static bNode *ntree_group_output_node(bNodeTree *ntree)
+{
+ /* Make sure we only have single node tagged as output. */
+ ntreeSetOutput(ntree);
+
+ /* Find output node that matches type and target. If there are
+ * multiple, we prefer exact target match and active nodes. */
+ bNode *output_node = NULL;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if ((node->type == NODE_GROUP_OUTPUT) &&
+ (node->flag & NODE_DO_OUTPUT))
+ {
+ output_node = node;
+ }
+ }
+
+ return output_node;
}
/* Find socket with a specified identifier. */
@@ -252,6 +311,93 @@ static bNodeSocket *ntree_shader_node_find_output(bNode *node,
return ntree_shader_node_find_socket(&node->outputs, identifier);
}
+static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSocket *isock)
+{
+ bNodeTree *group_ntree = (bNodeTree *)group_node->id;
+ bNode *node;
+ bool removed_link = false;
+
+ for (node = group_ntree->nodes.first; node; node = node->next) {
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ if ((sock->flag & SOCK_HIDE_VALUE) == 0)
+ continue;
+ /* If socket is linked to a group input node and sockets id match. */
+ if (sock && sock->link && sock->link->fromnode->type == NODE_GROUP_INPUT) {
+ if (STREQ(isock->identifier, sock->link->fromsock->identifier)) {
+ nodeRemLink(group_ntree, sock->link);
+ removed_link = true;
+ }
+ }
+ }
+ }
+
+ if (removed_link) {
+ ntreeUpdateTree(G.main, group_ntree);
+ }
+}
+
+/* Node groups once expanded looses their input sockets values.
+ * To fix this, link value/rgba nodes into the sockets and copy the group sockets values. */
+static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
+{
+ bNode *value_node, *group_node;
+ bNodeSocket *value_socket;
+ bNodeSocketValueRGBA *src_rgba, *dst_rgba;
+ bNodeSocketValueFloat *src_float, *dst_float;
+ bool link_added = false;
+
+ for (group_node = localtree->nodes.first; group_node; group_node = group_node->next) {
+
+ if (group_node->type != NODE_GROUP || group_node->id == NULL)
+ continue;
+
+ /* Do it recursively. */
+ ntree_shader_groups_expand_inputs((bNodeTree *)group_node->id);
+
+ bNodeSocket *group_socket = group_node->inputs.first;
+ for (; group_socket; group_socket = group_socket->next) {
+ if (group_socket->link != NULL)
+ continue;
+
+ /* Detect the case where an input is plugged into a hidden value socket.
+ * In this case we should just remove the link to trigger the socket default override. */
+ ntree_shader_unlink_hidden_value_sockets(group_node, group_socket);
+
+ switch (group_socket->type) {
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB);
+ value_socket = ntree_shader_node_find_output(value_node, "Color");
+ BLI_assert(value_socket != NULL);
+ src_rgba = group_socket->default_value;
+ dst_rgba = value_socket->default_value;
+ copy_v4_v4(dst_rgba->value, src_rgba->value);
+ break;
+ case SOCK_FLOAT:
+ value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE);
+ value_socket = ntree_shader_node_find_output(value_node, "Value");
+ BLI_assert(value_socket != NULL);
+ src_float = group_socket->default_value;
+ dst_float = value_socket->default_value;
+ dst_float->value = src_float->value;
+ break;
+ default:
+ continue;
+ }
+
+ nodeAddLink(localtree,
+ value_node, value_socket,
+ group_node, group_socket);
+
+ link_added = true;
+ }
+ }
+
+ if (link_added) {
+ ntreeUpdateTree(G.main, localtree);
+ }
+}
+
/* Check whether shader has a displacement.
*
* Will also return a node and it's socket which is connected to a displacement
@@ -259,11 +405,11 @@ static bNodeSocket *ntree_shader_node_find_output(bNode *node,
* also returned.
*/
static bool ntree_shader_has_displacement(bNodeTree *ntree,
+ bNode *output_node,
bNode **r_node,
bNodeSocket **r_socket,
bNodeLink **r_link)
{
- bNode *output_node = ntree_shader_output_node(ntree);
if (output_node == NULL) {
/* We can't have displacement without output node, apparently. */
return false;
@@ -427,17 +573,13 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
/* Re-link displacement output to unconnected normal sockets via bump node.
* This way material with have proper displacement in the viewport.
*/
-static void ntree_shader_relink_displacement(bNodeTree *ntree,
- short compatibility)
+static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_node)
{
- if (compatibility != NODE_NEW_SHADING) {
- /* We can only deal with new shading system here. */
- return;
- }
bNode *displacement_node;
bNodeSocket *displacement_socket;
bNodeLink *displacement_link;
if (!ntree_shader_has_displacement(ntree,
+ output_node,
&displacement_node,
&displacement_socket,
&displacement_link))
@@ -491,35 +633,125 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree,
ntreeUpdateTree(G.main, ntree);
}
-void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibility)
+static bool ntree_tag_ssr_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata, const bool UNUSED(reversed))
+{
+ switch (fromnode->type) {
+ case NODE_GROUP:
+ /* Recursive */
+ if (fromnode->id != NULL) {
+ bNodeTree *ntree = (bNodeTree *)fromnode->id;
+ bNode *group_output = ntree_group_output_node(ntree);
+ ntree_shader_tag_ssr_node(ntree, group_output);
+ }
+ break;
+ case SH_NODE_BSDF_ANISOTROPIC:
+ case SH_NODE_EEVEE_SPECULAR:
+ case SH_NODE_BSDF_PRINCIPLED:
+ case SH_NODE_BSDF_GLOSSY:
+ case SH_NODE_BSDF_GLASS:
+ fromnode->ssr_id = (*(float *)userdata);
+ (*(float *)userdata) += 1;
+ break;
+ default:
+ /* We could return false here but since we (will)
+ * allow the use of Closure as RGBA, we can have
+ * Bsdf nodes linked to other Bsdf nodes. */
+ break;
+ }
+
+ return true;
+}
+
+/* EEVEE: Scan the ntree to set the Screen Space Reflection
+ * layer id of every specular node.
+ */
+void ntree_shader_tag_ssr_node(bNodeTree *ntree, bNode *output_node)
+{
+ if (output_node == NULL) {
+ return;
+ }
+ /* Make sure sockets links pointers are correct. */
+ ntreeUpdateTree(G.main, ntree);
+
+ float lobe_id = 1;
+ nodeChainIter(ntree, output_node, ntree_tag_ssr_bsdf_cb, &lobe_id, true);
+}
+
+static bool ntree_tag_sss_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata, const bool UNUSED(reversed))
+{
+ switch (fromnode->type) {
+ case NODE_GROUP:
+ /* Recursive */
+ if (fromnode->id != NULL) {
+ bNodeTree *ntree = (bNodeTree *)fromnode->id;
+ bNode *group_output = ntree_group_output_node(ntree);
+ ntree_shader_tag_sss_node(ntree, group_output);
+ }
+ break;
+ case SH_NODE_BSDF_PRINCIPLED:
+ case SH_NODE_SUBSURFACE_SCATTERING:
+ fromnode->sss_id = (*(float *)userdata);
+ (*(float *)userdata) += 1;
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/* EEVEE: Scan the ntree to set the Subsurface Scattering id of every SSS node.
+ */
+void ntree_shader_tag_sss_node(bNodeTree *ntree, bNode *output_node)
+{
+ if (output_node == NULL) {
+ return;
+ }
+ /* Make sure sockets links pointers are correct. */
+ ntreeUpdateTree(G.main, ntree);
+
+ float sss_id = 1;
+ nodeChainIter(ntree, output_node, ntree_tag_sss_bsdf_cb, &sss_id, true);
+}
+
+/* This one needs to work on a local tree. */
+void ntreeGPUMaterialNodes(bNodeTree *localtree, GPUMaterial *mat, bool *has_surface_output, bool *has_volume_output)
{
- /* localize tree to create links for reroute and mute */
- bNodeTree *localtree = ntreeLocalize(ntree);
+ bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
bNodeTreeExec *exec;
+ ntree_shader_groups_expand_inputs(localtree);
+
/* Perform all needed modifications on the tree in order to support
* displacement/bump mapping.
*/
- ntree_shader_relink_displacement(localtree, compatibility);
+ ntree_shader_relink_displacement(localtree, output);
+
+ ntree_shader_tag_ssr_node(localtree, output);
+ ntree_shader_tag_sss_node(localtree, output);
exec = ntreeShaderBeginExecTree(localtree);
- ntreeExecGPUNodes(exec, mat, 1, compatibility);
+ ntreeExecGPUNodes(exec, mat, 1);
ntreeShaderEndExecTree(exec);
- ntreeFreeTree(localtree);
- MEM_freeN(localtree);
-}
+ /* EEVEE: Find which material domain was used (volume, surface ...). */
+ *has_surface_output = false;
+ *has_volume_output = false;
-/* **************** call to switch lamploop for material node ************ */
+ if (output != NULL) {
+ bNodeSocket *surface_sock = ntree_shader_node_find_input(output, "Surface");
+ bNodeSocket *volume_sock = ntree_shader_node_find_input(output, "Volume");
-void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *);
+ if (surface_sock != NULL) {
+ *has_surface_output = (nodeCountSocketLinks(localtree, surface_sock) > 0);
+ }
-void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *))
-{
- node_shader_lamp_loop = lamp_loop_func;
+ if (volume_sock != NULL) {
+ *has_volume_output = (nodeCountSocketLinks(localtree, volume_sock) > 0);
+ }
+ }
}
-
bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context, bNodeTree *ntree, bNodeInstanceKey parent_key)
{
bNodeTreeExec *exec;
@@ -594,26 +826,14 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec)
}
}
-/* only for Blender internal */
-bool ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr)
+/* TODO: left over from Blender Internal, could reuse for new texture nodes. */
+bool ntreeShaderExecTree(bNodeTree *ntree, int thread)
{
ShaderCallData scd;
- /**
- * \note: preserve material from ShadeInput for material id, nodetree execs change it
- * fix for bug "[#28012] Mat ID messy with shader nodes"
- */
- Material *mat = shi->mat;
bNodeThreadStack *nts = NULL;
bNodeTreeExec *exec = ntree->execdata;
int compat;
- /* convert caller data to struct */
- scd.shi = shi;
- scd.shr = shr;
-
- /* each material node has own local shaderesult, with optional copying */
- memset(shr, 0, sizeof(ShadeResult));
-
/* ensure execdata is only initialized once */
if (!exec) {
BLI_thread_lock(LOCK_NODES);
@@ -624,18 +844,10 @@ bool ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr)
exec = ntree->execdata;
}
- nts = ntreeGetThreadStack(exec, shi->thread);
- compat = ntreeExecThreadNodes(exec, nts, &scd, shi->thread);
+ nts = ntreeGetThreadStack(exec, thread);
+ compat = ntreeExecThreadNodes(exec, nts, &scd, thread);
ntreeReleaseThreadStack(nts);
- // \note: set material back to preserved material
- shi->mat = mat;
-
- /* better not allow negative for now */
- if (shr->combined[0] < 0.0f) shr->combined[0] = 0.0f;
- if (shr->combined[1] < 0.0f) shr->combined[1] = 0.0f;
- if (shr->combined[2] < 0.0f) shr->combined[2] = 0.0f;
-
/* if compat is zero, it has been using non-compatible nodes */
return compat;
}
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 90b230a280d..ca8286f1772 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -91,53 +91,6 @@ void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
}
-/* go over all used Geometry and Texture nodes, and return a texco flag */
-/* no group inside needed, this function is called for groups too */
-void ntreeShaderGetTexcoMode(bNodeTree *ntree, int r_mode, short *texco, int *mode)
-{
- bNode *node;
- bNodeSocket *sock;
- int a;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_TEXTURE) {
- if ((r_mode & R_OSA) && node->id) {
- Tex *tex = (Tex *)node->id;
- if (ELEM(tex->type, TEX_IMAGE, TEX_ENVMAP)) {
- *texco |= TEXCO_OSA | NEED_UV;
- }
- }
- /* usability exception... without input we still give the node orcos */
- sock = node->inputs.first;
- if (sock == NULL || sock->link == NULL)
- *texco |= TEXCO_ORCO | NEED_UV;
- }
- else if (node->type == SH_NODE_GEOMETRY) {
- /* note; sockets always exist for the given type! */
- for (a = 0, sock = node->outputs.first; sock; sock = sock->next, a++) {
- if (sock->flag & SOCK_IN_USE) {
- switch (a) {
- case GEOM_OUT_GLOB:
- *texco |= TEXCO_GLOB | NEED_UV; break;
- case GEOM_OUT_VIEW:
- *texco |= TEXCO_VIEW | NEED_UV; break;
- case GEOM_OUT_ORCO:
- *texco |= TEXCO_ORCO | NEED_UV; break;
- case GEOM_OUT_UV:
- *texco |= TEXCO_UV | NEED_UV; break;
- case GEOM_OUT_NORMAL:
- *texco |= TEXCO_NORM | NEED_UV; break;
- case GEOM_OUT_VCOL:
- *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
- case GEOM_OUT_VCOL_ALPHA:
- *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
- }
- }
- }
- }
- }
-}
-
void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
{
memset(gs, 0, sizeof(*gs));
@@ -147,7 +100,6 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
zero_v4(gs->vec);
gs->link = NULL;
gs->type = GPU_NONE;
- gs->name = "";
gs->hasinput = false;
gs->hasoutput = false;
gs->sockettype = type;
@@ -163,11 +115,10 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
else if (type == SOCK_RGBA)
gs->type = GPU_VEC4;
else if (type == SOCK_SHADER)
- gs->type = GPU_VEC4;
+ gs->type = GPU_CLOSURE;
else
gs->type = GPU_NONE;
- gs->name = "";
gs->hasinput = ns->hasinput && ns->data;
/* XXX Commented out the ns->data check here, as it seems it's not always set,
* even though there *is* a valid connection/output... But that might need
@@ -193,7 +144,7 @@ static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeS
for (sock = sockets->first, i = 0; sock; sock = sock->next, i++)
node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
- gs[i].type = GPU_NONE;
+ gs[i].end = true;
}
static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
@@ -256,7 +207,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
return inactivenode;
}
-void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs, short compatibility)
+void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs)
{
bNodeExec *nodeexec;
bNode *node;
@@ -275,9 +226,8 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs, sh
do_it = false;
/* for groups, only execute outputs for edited group */
if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
- if (node->typeinfo->compatibility & compatibility)
- if (do_outputs && (node->flag & NODE_DO_OUTPUT))
- do_it = true;
+ if (do_outputs && (node->flag & NODE_DO_OUTPUT))
+ do_it = true;
}
else {
do_it = true;
@@ -303,13 +253,18 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in
float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
- GPUNodeLink *tmat = GPU_uniform((float *)texmap->mat);
- GPUNodeLink *tmin = GPU_uniform(texmap->min);
- GPUNodeLink *tmax = GPU_uniform(texmap->max);
- GPUNodeLink *tdomin = GPU_uniform(&domin);
- GPUNodeLink *tdomax = GPU_uniform(&domax);
-
- GPU_link(mat, "mapping", in[0].link, tmat, tmin, tmax, tdomin, tdomax, &in[0].link);
+ static float max[3] = { FLT_MAX, FLT_MAX, FLT_MAX};
+ static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
+
+ tmin = GPU_uniform((domin) ? texmap->min : min);
+ tmax = GPU_uniform((domax) ? texmap->max : max);
+ tmat0 = GPU_uniform((float *)texmap->mat[0]);
+ tmat1 = GPU_uniform((float *)texmap->mat[1]);
+ tmat2 = GPU_uniform((float *)texmap->mat[2]);
+ tmat3 = GPU_uniform((float *)texmap->mat[3]);
+
+ GPU_link(mat, "mapping", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
if (texmap->type == TEXMAP_TYPE_NORMAL)
GPU_link(mat, "texco_norm", in[0].link, &in[0].link);
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index e2c1fe7897b..158efc5a6ab 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -64,8 +64,6 @@
#include "BKE_node.h"
#include "BKE_texture.h"
-#include "BKE_library.h"
-
#include "NOD_shader.h"
#include "node_util.h"
@@ -78,6 +76,7 @@
#include "RE_shader_ext.h"
#include "GPU_material.h"
+#include "GPU_uniformbuffer.h"
bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
@@ -87,17 +86,16 @@ void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, shor
/* ********* exec data struct, remains internal *********** */
typedef struct ShaderCallData {
- ShadeInput *shi; /* from render pipe */
- ShadeResult *shr; /* from render pipe */
+ /* Empty for now, may be reused if we convert shader to texture nodes. */
+ int dummy;
} ShaderCallData;
-
void nodestack_get_vec(float *in, short type_in, bNodeStack *ns);
void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, struct bNodeStack *ns);
void node_data_from_gpu_stack(struct bNodeStack *ns, struct GPUNodeStack *gs);
void node_shader_gpu_tex_mapping(struct GPUMaterial *mat, struct bNode *node, struct GPUNodeStack *in, struct GPUNodeStack *out);
-void ntreeExecGPUNodes(struct bNodeTreeExec *exec, struct GPUMaterial *mat, int do_outputs, short compatibility);
+void ntreeExecGPUNodes(struct bNodeTreeExec *exec, struct GPUMaterial *mat, int do_outputs);
#endif
diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.c b/source/blender/nodes/shader/nodes/node_shader_add_shader.c
index 1edac62438e..0661ab59434 100644
--- a/source/blender/nodes/shader/nodes/node_shader_add_shader.c
+++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.c
@@ -40,9 +40,9 @@ static bNodeSocketTemplate sh_node_add_shader_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_add_shader(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_add_shader(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_add_shader", in, out);
+ return GPU_stack_link(mat, node, "node_add_shader", in, out);
}
/* node type definition */
@@ -51,7 +51,6 @@ void register_node_type_sh_add_shader(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_add_shader_in, sh_node_add_shader_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
index 995ff0cfd40..bf5f0ec13c5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
@@ -42,9 +42,14 @@ static bNodeSocketTemplate sh_node_ambient_occlusion_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_ambient_occlusion", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+ if (!in[2].link)
+ GPU_link(mat, "world_normals_get", &in[2].link);
+
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
+
+ return GPU_stack_link(mat, node, "node_ambient_occlusion", in, out);
}
static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *node)
@@ -59,7 +64,6 @@ void register_node_type_sh_ambient_occlusion(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_ambient_occlusion_in, sh_node_ambient_occlusion_out);
node_type_init(&ntype, node_shader_init_ambient_occlusion);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index ba5fa131d3e..aca72ac27cc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -45,9 +45,29 @@ static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_attribute(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
NodeShaderAttribute *attr = node->storage;
- GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
- return GPU_stack_link(mat, "node_attribute", in, out, cd_attr);
+ /* FIXME : if an attribute layer (like vertex color) has one of theses name, it will not work as expected. */
+ if (strcmp(attr->name, "density") == 0) {
+ return GPU_stack_link(mat, node, "node_attribute_volume_density", in, out,
+ GPU_builtin(GPU_VOLUME_DENSITY));
+ }
+ else if (strcmp(attr->name, "color") == 0) {
+ return GPU_stack_link(mat, node, "node_attribute_volume_color", in, out,
+ GPU_builtin(GPU_VOLUME_DENSITY));
+ }
+ else if (strcmp(attr->name, "flame") == 0) {
+ return GPU_stack_link(mat, node, "node_attribute_volume_flame", in, out,
+ GPU_builtin(GPU_VOLUME_FLAME));
+ }
+ else if (strcmp(attr->name, "temperature") == 0) {
+ return GPU_stack_link(mat, node, "node_attribute_volume_temperature", in, out,
+ GPU_builtin(GPU_VOLUME_FLAME),
+ GPU_builtin(GPU_VOLUME_TEMPERATURE));
+ }
+ else {
+ GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
+ return GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
+ }
}
/* node type definition */
@@ -56,7 +76,6 @@ void register_node_type_sh_attribute(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_attribute_out);
node_type_init(&ntype, node_shader_init_attribute);
node_type_storage(&ntype, "NodeShaderAttribute", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_background.c b/source/blender/nodes/shader/nodes/node_shader_background.c
index b387529e456..38b5883bc1e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_background.c
+++ b/source/blender/nodes/shader/nodes/node_shader_background.c
@@ -40,9 +40,9 @@ static bNodeSocketTemplate sh_node_background_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_background(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_background(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_background", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+ return GPU_stack_link(mat, node, "node_background", in, out);
}
/* node type definition */
@@ -51,7 +51,6 @@ void register_node_type_sh_background(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_background_in, sh_node_background_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.c b/source/blender/nodes/shader/nodes/node_shader_bevel.c
index e2e4da21ef3..05161bd453a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bevel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bevel.c
@@ -45,13 +45,13 @@ static void node_shader_init_bevel(bNodeTree *UNUSED(ntree), bNode *node)
node->custom1 = 4; /* samples */
}
-static int gpu_shader_bevel(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_bevel(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[1].link) {
GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[1].link);
}
- return GPU_stack_link(mat, "node_bevel", in, out);
+ return GPU_stack_link(mat, node, "node_bevel", in, out);
}
/* node type definition */
@@ -60,7 +60,6 @@ void register_node_type_sh_bevel(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bevel_in, sh_node_bevel_out);
node_type_init(&ntype, node_shader_init_bevel);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.c b/source/blender/nodes/shader/nodes/node_shader_blackbody.c
index 2006ef890f6..28ba3d2c5c8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_blackbody.c
+++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.c
@@ -38,17 +38,30 @@ static bNodeSocketTemplate sh_node_blackbody_out[] = {
{ -1, 0, "" }
};
+static int node_shader_gpu_blackbody(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ const int size = CM_TABLE + 1;
+ float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+
+ blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
+
+ float layer;
+ GPUNodeLink *ramp_texture = GPU_color_band(mat, size, data, &layer);
+
+ return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_constant(&layer));
+}
+
/* node type definition */
void register_node_type_sh_blackbody(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_socket_templates(&ntype, sh_node_blackbody_in, sh_node_blackbody_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_blackbody);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index 75e258bd27d..d17a5b9ba6e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c
@@ -42,9 +42,9 @@ static bNodeSocketTemplate sh_node_brightcontrast_out[] = {
{ -1, 0, "" }
};
-static int gpu_shader_brightcontrast(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_brightcontrast(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "brightness_contrast", in, out);
+ return GPU_stack_link(mat, node, "brightness_contrast", in, out);
}
void register_node_type_sh_brightcontrast(void)
@@ -52,7 +52,6 @@ void register_node_type_sh_brightcontrast(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
index 6410441797a..6551b20a375 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
@@ -49,14 +49,14 @@ static void node_shader_init_anisotropic(bNodeTree *UNUSED(ntree), bNode *node)
node->custom1 = SHD_GLOSSY_GGX;
}
-static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[4].link)
- in[4].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[4].link, GPU_builtin(GPU_VIEW_MATRIX), &in[4].link);
+ GPU_link(mat, "world_normals_get", &in[4].link);
- return GPU_stack_link(mat, "node_bsdf_anisotropic", in, out);
+ GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY);
+
+ return GPU_stack_link(mat, node, "node_bsdf_anisotropic", in, out);
}
/* node type definition */
@@ -65,7 +65,6 @@ void register_node_type_sh_bsdf_anisotropic(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_anisotropic_in, sh_node_bsdf_anisotropic_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_anisotropic);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
index e86d2677a61..c1b8c748657 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
@@ -41,14 +41,14 @@ static bNodeSocketTemplate sh_node_bsdf_diffuse_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[2].link)
- in[2].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link);
+ GPU_link(mat, "world_normals_get", &in[2].link);
- return GPU_stack_link(mat, "node_bsdf_diffuse", in, out);
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
+
+ return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out);
}
/* node type definition */
@@ -57,7 +57,6 @@ void register_node_type_sh_bsdf_diffuse(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_diffuse_in, sh_node_bsdf_diffuse_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
index 529dfbc3df4..b18dcacb98f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
@@ -47,14 +47,14 @@ static void node_shader_init_glass(bNodeTree *UNUSED(ntree), bNode *node)
node->custom1 = SHD_GLOSSY_BECKMANN;
}
-static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[3].link)
- in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
+ GPU_link(mat, "world_normals_get", &in[3].link);
- return GPU_stack_link(mat, "node_bsdf_glass", in, out);
+ GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT);
+
+ return GPU_stack_link(mat, node, "node_bsdf_glass", in, out, GPU_constant(&node->ssr_id));
}
/* node type definition */
@@ -63,7 +63,6 @@ void register_node_type_sh_bsdf_glass(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_glass_in, sh_node_bsdf_glass_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_glass);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
index fd55ab0ce17..bd1c5e8f348 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
@@ -46,14 +46,17 @@ static void node_shader_init_glossy(bNodeTree *UNUSED(ntree), bNode *node)
node->custom1 = SHD_GLOSSY_GGX;
}
-static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[2].link)
- in[2].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link);
+ GPU_link(mat, "world_normals_get", &in[2].link);
- return GPU_stack_link(mat, "node_bsdf_glossy", in, out);
+ if (node->custom1 == SHD_GLOSSY_SHARP)
+ GPU_link(mat, "set_value_zero", &in[1].link);
+
+ GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY);
+
+ return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out, GPU_constant(&node->ssr_id));
}
/* node type definition */
@@ -62,7 +65,6 @@ void register_node_type_sh_bsdf_glossy(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_glossy_in, sh_node_bsdf_glossy_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_glossy);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
index 7842f1d6b15..d97344ad6a7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
@@ -43,9 +43,9 @@ static bNodeSocketTemplate sh_node_bsdf_hair_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_bsdf_hair(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_hair(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_bsdf_hair", in, out);
+ return GPU_stack_link(mat, node, "node_bsdf_hair", in, out);
}
/* node type definition */
@@ -54,7 +54,6 @@ void register_node_type_sh_bsdf_hair(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_hair_in, sh_node_bsdf_hair_out);
node_type_size(&ntype, 150, 60, 200);
node_type_init(&ntype, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
index aeeb262a5a6..83e4bf1731b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
@@ -122,7 +122,6 @@ void register_node_type_sh_bsdf_hair_principled(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_hair_principled_in, sh_node_bsdf_hair_principled_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, node_shader_init_hair_principled);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index e3b3f0fc9a6..c628fd7a7f5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -64,21 +64,91 @@ static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
node->custom2 = SHD_SUBSURFACE_BURLEY;
}
-static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
+#define socket_not_one(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) < 1.0f - 1e-5f))
+
+static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- // normal
- if (!in[17].link)
- in[17].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link);
-
- // clearcoat normal
- if (!in[18].link)
- in[18].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link);
-
- return GPU_stack_link(mat, "node_bsdf_principled", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ GPUNodeLink *sss_scale;
+
+ /* Normals */
+ if (!in[17].link) {
+ GPU_link(mat, "world_normals_get", &in[17].link);
+ }
+
+ /* Clearcoat Normals */
+ if (!in[18].link) {
+ GPU_link(mat, "world_normals_get", &in[18].link);
+ }
+
+ /* Tangents */
+ if (!in[19].link) {
+ GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
+ GPU_link(mat, "tangent_orco_z", orco, &in[19].link);
+ GPU_link(mat, "node_tangent",
+ GPU_builtin(GPU_VIEW_NORMAL), in[19].link, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
+ &in[19].link);
+ }
+
+ /* SSS Profile */
+ if (node->sss_id == 1) {
+ static short profile = SHD_SUBSURFACE_BURLEY;
+ bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = socket->default_value;
+ /* For some reason it seems that the socket value is in ARGB format. */
+ GPU_material_sss_profile_create(mat, &socket_data->value[1], &profile, NULL);
+ }
+
+ if (in[2].link) {
+ sss_scale = in[2].link;
+ }
+ else {
+ GPU_link(mat, "set_rgb_one", &sss_scale);
+ }
+
+ bool use_diffuse = socket_not_one(4) && socket_not_one(15);
+ bool use_subsurf = socket_not_zero(1) && use_diffuse;
+ bool use_refract = socket_not_one(4) && socket_not_zero(15);
+ bool use_clear = socket_not_zero(12);
+
+ /* Due to the manual effort done per config, we only optimize the most common permutations. */
+ char *node_name;
+ uint flag = 0;
+ if (!use_subsurf && use_diffuse && !use_refract && !use_clear) {
+ static char name[] = "node_bsdf_principled_dielectric";
+ node_name = name;
+ flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY;
+ }
+ else if (!use_subsurf && !use_diffuse && !use_refract && !use_clear) {
+ static char name[] = "node_bsdf_principled_metallic";
+ node_name = name;
+ flag = GPU_MATFLAG_GLOSSY;
+ }
+ else if (!use_subsurf && !use_diffuse && !use_refract && use_clear) {
+ static char name[] = "node_bsdf_principled_clearcoat";
+ node_name = name;
+ flag = GPU_MATFLAG_GLOSSY;
+ }
+ else if (use_subsurf && use_diffuse && !use_refract && !use_clear) {
+ static char name[] = "node_bsdf_principled_subsurface";
+ node_name = name;
+ flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS | GPU_MATFLAG_GLOSSY;
+ }
+ else if (!use_subsurf && !use_diffuse && use_refract && !use_clear && !socket_not_zero(4)) {
+ static char name[] = "node_bsdf_principled_glass";
+ node_name = name;
+ flag = GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT;
+ }
+ else {
+ static char name[] = "node_bsdf_principled";
+ node_name = name;
+ flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_SSS | GPU_MATFLAG_REFRACT;
+ }
+
+ GPU_material_flag_set(mat, flag);
+
+ return GPU_stack_link(mat, node, node_name, in, out, GPU_builtin(GPU_VIEW_POSITION),
+ GPU_constant(&node->ssr_id), GPU_constant(&node->sss_id), sss_scale);
}
static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node)
@@ -103,7 +173,6 @@ void register_node_type_sh_bsdf_principled(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, node_shader_init_principled);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
index 4b16fcab081..0b7b50d0b0a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
@@ -47,14 +47,17 @@ static void node_shader_init_refraction(bNodeTree *UNUSED(ntree), bNode *node)
node->custom1 = SHD_GLOSSY_BECKMANN;
}
-static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[3].link)
- in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
+ GPU_link(mat, "world_normals_get", &in[3].link);
- return GPU_stack_link(mat, "node_bsdf_refraction", in, out);
+ if (node->custom1 == SHD_GLOSSY_SHARP)
+ GPU_link(mat, "set_value_zero", &in[1].link);
+
+ GPU_material_flag_set(mat, GPU_MATFLAG_REFRACT);
+
+ return GPU_stack_link(mat, node, "node_bsdf_refraction", in, out);
}
/* node type definition */
@@ -63,7 +66,6 @@ void register_node_type_sh_bsdf_refraction(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_refraction_in, sh_node_bsdf_refraction_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_refraction);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
index b268779d6bb..0754a7e5a3b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
@@ -42,14 +42,14 @@ static bNodeSocketTemplate sh_node_bsdf_toon_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_bsdf_toon(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_toon(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[3].link)
in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
else
GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
- return GPU_stack_link(mat, "node_bsdf_toon", in, out);
+ return GPU_stack_link(mat, node, "node_bsdf_toon", in, out);
}
/* node type definition */
@@ -58,7 +58,6 @@ void register_node_type_sh_bsdf_toon(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_toon_in, sh_node_bsdf_toon_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
index 3eee8a08fa2..349db30af14 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
@@ -40,14 +40,14 @@ static bNodeSocketTemplate sh_node_bsdf_translucent_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[1].link)
- in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
+ GPU_link(mat, "world_normals_get", &in[1].link);
- return GPU_stack_link(mat, "node_bsdf_translucent", in, out);
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
+
+ return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out);
}
/* node type definition */
@@ -56,7 +56,6 @@ void register_node_type_sh_bsdf_translucent(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_translucent_in, sh_node_bsdf_translucent_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c
index 00aac45e4c8..08ddf221804 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c
@@ -39,9 +39,9 @@ static bNodeSocketTemplate sh_node_bsdf_transparent_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_bsdf_transparent", in, out);
+ return GPU_stack_link(mat, node, "node_bsdf_transparent", in, out);
}
/* node type definition */
@@ -50,7 +50,6 @@ void register_node_type_sh_bsdf_transparent(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_transparent_in, sh_node_bsdf_transparent_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
index 69bc74793e7..59b831c0dab 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
@@ -41,14 +41,14 @@ static bNodeSocketTemplate sh_node_bsdf_velvet_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[2].link)
- in[2].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link);
+ GPU_link(mat, "world_normals_get", &in[2].link);
- return GPU_stack_link(mat, "node_bsdf_velvet", in, out);
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
+
+ return GPU_stack_link(mat, node, "node_bsdf_velvet", in, out);
}
/* node type definition */
@@ -57,7 +57,6 @@ void register_node_type_sh_bsdf_velvet(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_velvet_in, sh_node_bsdf_velvet_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index 41df17cef67..c806827b71d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -47,19 +47,13 @@ static bNodeSocketTemplate sh_node_bump_out[] = {
static int gpu_shader_bump(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[3].link)
- in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
- float invert = node->custom1;
- GPU_stack_link(mat, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_uniform(&invert));
- /* Other nodes are applying view matrix if the input Normal has a link.
- * We don't want normal to have view matrix applied twice, so we cancel it here.
- *
- * TODO(sergey): This is an extra multiplication which cancels each other,
- * better avoid this but that requires bigger refactor.
- */
- return GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link);
+ if (!in[3].link) {
+ GPU_link(mat, "world_normals_get", &in[3].link);
+ }
+
+ float invert = (node->custom1) ? -1.0 : 1.0;
+
+ return GPU_stack_link(mat, node, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_constant(&invert));
}
/* node type definition */
@@ -68,7 +62,6 @@ void register_node_type_sh_bump(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bump_in, sh_node_bump_out);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, gpu_shader_bump);
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.c
index b1c3a817b84..9089d415759 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.c
@@ -40,29 +40,13 @@ static bNodeSocketTemplate sh_node_camera_out[] = {
{ -1, 0, "" }
};
-
-static void node_shader_exec_camera(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
-{
- if (data) {
- ShadeInput *shi = ((ShaderCallData *)data)->shi; /* Data we need for shading. */
-
- copy_v3_v3(out[0]->vec, shi->co); /* get view vector */
- out[1]->vec[0] = fabsf(shi->co[2]); /* get view z-depth */
- out[2]->vec[0] = normalize_v3(out[0]->vec); /* get view distance */
- }
-}
-
-static int gpu_shader_camera(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_camera(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *viewvec;
viewvec = GPU_builtin(GPU_VIEW_POSITION);
-
- /* Blender has negative Z, Cycles positive Z convention */
- if (GPU_material_use_new_shading_nodes(mat))
- GPU_link(mat, "invert_z", viewvec, &viewvec);
-
- return GPU_stack_link(mat, "camera", in, out, viewvec);
+ GPU_link(mat, "invert_z", viewvec, &viewvec);
+ return GPU_stack_link(mat, node, "camera", in, out, viewvec);
}
void register_node_type_sh_camera(void)
@@ -70,10 +54,8 @@ void register_node_type_sh_camera(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_camera_out);
node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_camera);
node_type_gpu(&ntype, gpu_shader_camera);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index 24de03dbda4..23b27fc5008 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -215,11 +215,7 @@ static int gpu_group_execute(GPUMaterial *mat, bNode *node, bNodeExecData *execd
return 0;
group_gpu_copy_inputs(node, in, exec->stack);
-#if 0 /* XXX NODE_GROUP_EDIT is deprecated, depends on node space */
- ntreeExecGPUNodes(exec, mat, (node->flag & NODE_GROUP_EDIT));
-#else
- ntreeExecGPUNodes(exec, mat, 0, NODE_NEW_SHADING | NODE_OLD_SHADING);
-#endif
+ ntreeExecGPUNodes(exec, mat, 0);
group_gpu_move_outputs(node, out, exec->stack);
return 1;
@@ -242,7 +238,6 @@ void register_node_type_sh_group(void)
BLI_assert(ntype.ext.srna != NULL);
RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
node_type_label(&ntype, node_group_label);
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.c b/source/blender/nodes/shader/nodes/node_shader_curves.c
index 0c583ced75f..243d57339ea 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.c
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.c
@@ -62,11 +62,13 @@ static void node_shader_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node)
static int gpu_shader_curve_vec(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- float *array;
+ float *array, layer;
int size;
curvemapping_table_RGBA(node->storage, &array, &size);
- return GPU_stack_link(mat, "curves_vec", in, out, GPU_texture(size, array));
+ GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
+
+ return GPU_stack_link(mat, node, "curves_vec", in, out, tex, GPU_constant(&layer));
}
void register_node_type_sh_curve_vec(void)
@@ -74,7 +76,6 @@ void register_node_type_sh_curve_vec(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_curve_vec_in, sh_node_curve_vec_out);
node_type_init(&ntype, node_shader_init_curve_vec);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
@@ -120,12 +121,14 @@ static void node_shader_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
static int gpu_shader_curve_rgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- float *array;
+ float *array, layer;
int size;
curvemapping_initialize(node->storage);
curvemapping_table_RGBA(node->storage, &array, &size);
- return GPU_stack_link(mat, "curves_rgb", in, out, GPU_texture(size, array));
+ GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
+
+ return GPU_stack_link(mat, node, "curves_rgb", in, out, tex, GPU_constant(&layer));
}
void register_node_type_sh_curve_rgb(void)
@@ -133,7 +136,6 @@ void register_node_type_sh_curve_rgb(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_curve_rgb_in, sh_node_curve_rgb_out);
node_type_init(&ntype, node_shader_init_curve_rgb);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.c
index e259a9e3f6d..4480cbdf56b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_displacement.c
@@ -61,10 +61,10 @@ static int gpu_shader_displacement(GPUMaterial *mat, bNode *node, bNodeExecData
}
if (node->custom1 == SHD_SPACE_OBJECT) {
- return GPU_stack_link(mat, "node_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX));
+ return GPU_stack_link(mat, node, "node_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX));
}
else {
- return GPU_stack_link(mat, "node_displacement_world", in, out, GPU_builtin(GPU_OBJECT_MATRIX));
+ return GPU_stack_link(mat, node, "node_displacement_world", in, out, GPU_builtin(GPU_OBJECT_MATRIX));
}
}
@@ -74,7 +74,6 @@ void register_node_type_sh_displacement(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_displacement_in, sh_node_displacement_out);
node_type_storage(&ntype, "", NULL, NULL);
node_type_init(&ntype, node_shader_init_displacement);
diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c
new file mode 100644
index 00000000000..939cd9f79a2
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c
@@ -0,0 +1,88 @@
+/*
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Clément Foucault.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_eevee_specular_in[] = {
+ { SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f},
+ { SOCK_RGBA, 1, N_("Specular"), 0.03f, 0.03f, 0.03f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Roughness"), 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_RGBA, 1, N_("Emissive Color"), 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Transparency"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { SOCK_FLOAT, 1, N_("Clear Coat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_FLOAT, 1, N_("Clear Coat Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_VECTOR, 1, N_("Clear Coat Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { SOCK_FLOAT, 1, N_("Ambient Occlusion"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_eevee_specular_out[] = {
+ { SOCK_SHADER, 0, N_("BSDF")},
+ { -1, 0, "" }
+};
+
+static int node_shader_gpu_eevee_specular(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ static float one = 1.0f;
+
+ /* Normals */
+ if (!in[5].link) {
+ GPU_link(mat, "world_normals_get", &in[5].link);
+ }
+
+ /* Clearcoat Normals */
+ if (!in[8].link) {
+ GPU_link(mat, "world_normals_get", &in[8].link);
+ }
+
+ /* Occlusion */
+ if (!in[9].link) {
+ GPU_link(mat, "set_value", GPU_constant(&one), &in[9].link);
+ }
+
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY);
+
+ return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&node->ssr_id));
+}
+
+
+/* node type definition */
+void register_node_type_sh_eevee_specular(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular", NODE_CLASS_SHADER, 0);
+ node_type_socket_templates(&ntype, sh_node_eevee_specular_in, sh_node_eevee_specular_out);
+ node_type_init(&ntype, NULL);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_eevee_specular);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.c b/source/blender/nodes/shader/nodes/node_shader_emission.c
index 2838e9dc54d..25194c23d0a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_emission.c
+++ b/source/blender/nodes/shader/nodes/node_shader_emission.c
@@ -40,9 +40,9 @@ static bNodeSocketTemplate sh_node_emission_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_emission(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_emission(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+ return GPU_stack_link(mat, node, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL));
}
/* node type definition */
@@ -51,7 +51,6 @@ void register_node_type_sh_emission(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_emission_in, sh_node_emission_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
index 393d2c5fee0..cb6b35ac4a7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
@@ -39,45 +39,20 @@ static bNodeSocketTemplate sh_node_fresnel_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[1].link) {
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
}
- else if (GPU_material_use_world_space_shading(mat)) {
+ else {
GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
}
- return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ return GPU_stack_link(mat, node, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
-static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+static void node_shader_exec_fresnel(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **UNUSED(out))
{
- ShadeInput *shi = ((ShaderCallData *)data)->shi;
-
- /* Compute IOR. */
- float eta;
- nodestack_get_vec(&eta, SOCK_FLOAT, in[0]);
- eta = max_ff(eta, 0.00001);
- eta = shi->flippednor ? 1 / eta : eta;
-
- /* Get normal from socket, but only if linked. */
- bNodeSocket *sock_normal = node->inputs.first;
- sock_normal = sock_normal->next;
-
- float n[3];
- if (sock_normal->link) {
- nodestack_get_vec(n, SOCK_VECTOR, in[1]);
- }
- else {
- copy_v3_v3(n, shi->vn);
- }
-
- if (shi->use_world_space_shading) {
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n);
- }
-
- out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, eta);
}
/* node type definition */
@@ -86,7 +61,6 @@ void register_node_type_sh_fresnel(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_fresnel_in, sh_node_fresnel_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index 8bf58682ef3..4a946e92778 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c
@@ -52,9 +52,9 @@ static void node_shader_exec_gamma(void *UNUSED(data), int UNUSED(thread), bNode
out[0]->vec[2] = col[2] > 0.0f ? powf(col[2], gamma) : col[2];
}
-static int node_shader_gpu_gamma(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_gamma(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_gamma", in, out);
+ return GPU_stack_link(mat, node, "node_gamma", in, out);
}
void register_node_type_sh_gamma(void)
@@ -62,7 +62,6 @@ void register_node_type_sh_gamma(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c
deleted file mode 100644
index 0a51ee8dc68..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_geom.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * ***** 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) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/nodes/shader/nodes/node_shader_geom.c
- * \ingroup shdnodes
- */
-
-
-#include "node_shader_util.h"
-
-#include "DNA_customdata_types.h"
-
-/* **************** GEOMETRY ******************** */
-
-/* output socket type definition */
-static bNodeSocketTemplate sh_node_geom_out[] = {
- { SOCK_VECTOR, 0, N_("Global")},
- { SOCK_VECTOR, 0, N_("Local")},
- { SOCK_VECTOR, 0, N_("View")},
- { SOCK_VECTOR, 0, N_("Orco")},
- { SOCK_VECTOR, 0, N_("UV")},
- { SOCK_VECTOR, 0, N_("Normal")},
- { SOCK_RGBA, 0, N_("Vertex Color")},
- { SOCK_FLOAT, 0, N_("Vertex Alpha")},
- { SOCK_FLOAT, 0, N_("Front/Back")},
- { -1, 0, "" }
-};
-
-/* node execute callback */
-static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
-{
- if (data) {
- ShadeInput *shi = ((ShaderCallData *)data)->shi;
- NodeGeometry *ngeo = (NodeGeometry *)node->storage;
- ShadeInputUV *suv = &shi->uv[shi->actuv];
- static float defaultvcol[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- int i;
-
- if (ngeo->uvname[0]) {
- /* find uv map by name */
- for (i = 0; i < shi->totuv; i++) {
- if (STREQ(shi->uv[i].name, ngeo->uvname)) {
- suv = &shi->uv[i];
- break;
- }
- }
- }
-
- /* out: global, local, view, orco, uv, normal, vertex color */
- copy_v3_v3(out[GEOM_OUT_GLOB]->vec, shi->gl);
- copy_v3_v3(out[GEOM_OUT_LOCAL]->vec, shi->co);
- copy_v3_v3(out[GEOM_OUT_VIEW]->vec, shi->view);
- copy_v3_v3(out[GEOM_OUT_ORCO]->vec, shi->lo);
- copy_v3_v3(out[GEOM_OUT_UV]->vec, suv->uv);
- copy_v3_v3(out[GEOM_OUT_NORMAL]->vec, shi->vno);
-
- if (shi->use_world_space_shading) {
- negate_v3(out[GEOM_OUT_NORMAL]->vec);
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[GEOM_OUT_NORMAL]->vec);
- }
- if (shi->totcol) {
- /* find vertex color layer by name */
- ShadeInputCol *scol = &shi->col[0];
-
- if (ngeo->colname[0]) {
- for (i = 0; i < shi->totcol; i++) {
- if (STREQ(shi->col[i].name, ngeo->colname)) {
- scol = &shi->col[i];
- break;
- }
- }
- }
-
- srgb_to_linearrgb_v3_v3(out[GEOM_OUT_VCOL]->vec, scol->col);
- out[GEOM_OUT_VCOL]->vec[3] = scol->col[3];
- out[GEOM_OUT_VCOL_ALPHA]->vec[0] = scol->col[3];
- }
- else {
- memcpy(out[GEOM_OUT_VCOL]->vec, defaultvcol, sizeof(defaultvcol));
- out[GEOM_OUT_VCOL_ALPHA]->vec[0] = 1.0f;
- }
-
- if (shi->osatex) {
- out[GEOM_OUT_GLOB]->data = shi->dxgl;
- out[GEOM_OUT_GLOB]->datatype = NS_OSA_VECTORS;
- out[GEOM_OUT_LOCAL]->data = shi->dxco;
- out[GEOM_OUT_LOCAL]->datatype = NS_OSA_VECTORS;
- out[GEOM_OUT_VIEW]->data = &shi->dxview;
- out[GEOM_OUT_VIEW]->datatype = NS_OSA_VALUES;
- out[GEOM_OUT_ORCO]->data = shi->dxlo;
- out[GEOM_OUT_ORCO]->datatype = NS_OSA_VECTORS;
- out[GEOM_OUT_UV]->data = suv->dxuv;
- out[GEOM_OUT_UV]->datatype = NS_OSA_VECTORS;
- out[GEOM_OUT_NORMAL]->data = shi->dxno;
- out[GEOM_OUT_NORMAL]->datatype = NS_OSA_VECTORS;
- }
-
- /* front/back, normal flipping was stored */
- out[GEOM_OUT_FRONTBACK]->vec[0] = (shi->flippednor) ? 0.0f : 1.0f;
- }
-}
-
-static void node_shader_init_geometry(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->storage = MEM_callocN(sizeof(NodeGeometry), "NodeGeometry");
-}
-
-static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
-{
- NodeGeometry *ngeo = (NodeGeometry *)node->storage;
- GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
- GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ngeo->uvname);
- GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname);
-
- bool ret = GPU_stack_link(mat, "geom", in, out,
- GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol);
- if (GPU_material_use_world_space_shading(mat)) {
- GPU_link(mat, "vec_math_negate", out[5].link, &out[5].link);
- ret &= GPU_link(mat, "direction_transform_m4v3", out[5].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[5].link);
- }
- return ret;
-}
-
-/* node type definition */
-void register_node_type_sh_geom(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_GEOMETRY, "Geometry", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING);
- node_type_socket_templates(&ntype, NULL, sh_node_geom_out);
- node_type_init(&ntype, node_shader_init_geometry);
- node_type_storage(&ntype, "NodeGeometry", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_geom);
- node_type_gpu(&ntype, gpu_shader_geom);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c
index d73628ebd67..d004e0e80a1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c
@@ -41,11 +41,12 @@ static bNodeSocketTemplate sh_node_geometry_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_geometry(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_geometry(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_geometry", in, out,
+ return GPU_stack_link(mat, node, "node_geometry", in, out,
GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX));
+ GPU_attribute(CD_ORCO, ""), GPU_builtin(GPU_OBJECT_MATRIX),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_BARYCENTRIC_TEXCO));
}
/* node type definition */
@@ -54,7 +55,6 @@ void register_node_type_sh_geometry(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_geometry_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.c
index 6a15c59aa5b..8b2f4b479ad 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hair_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.c
@@ -37,16 +37,21 @@ static bNodeSocketTemplate outputs[] = {
{ -1, 0, "" }
};
+static int node_shader_gpu_hair_info(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_hair_info", in, out);
+}
+
/* node type definition */
void register_node_type_sh_hair_info(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, outputs);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_hair_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.c b/source/blender/nodes/shader/nodes/node_shader_holdout.c
index 42563f2bfa8..6109022fddf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_holdout.c
+++ b/source/blender/nodes/shader/nodes/node_shader_holdout.c
@@ -45,7 +45,6 @@ void register_node_type_sh_holdout(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_holdout_in, sh_node_holdout_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index 548b3970a89..c017765c8e2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
@@ -82,9 +82,9 @@ static void node_shader_exec_hue_sat(void *UNUSED(data), int UNUSED(thread), bNo
}
-static int gpu_shader_hue_sat(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_hue_sat(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "hue_sat", in, out);
+ return GPU_stack_link(mat, node, "hue_sat", in, out);
}
void register_node_type_sh_hue_sat(void)
@@ -92,7 +92,6 @@ void register_node_type_sh_hue_sat(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_hue_sat_in, sh_node_hue_sat_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_hue_sat);
diff --git a/source/blender/nodes/shader/nodes/node_shader_ies_light.c b/source/blender/nodes/shader/nodes/node_shader_ies_light.c
index 8084f445e34..2714d560862 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ies_light.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ies_light.c
@@ -52,7 +52,6 @@ void register_node_type_sh_tex_ies(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_ies_in, sh_node_tex_ies_out);
node_type_init(&ntype, node_shader_init_tex_ies);
node_type_storage(&ntype, "NodeShaderTexIES", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c
index dc0817782e5..448d305b44e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_invert.c
+++ b/source/blender/nodes/shader/nodes/node_shader_invert.c
@@ -65,9 +65,9 @@ static void node_shader_exec_invert(void *UNUSED(data), int UNUSED(thread), bNod
copy_v3_v3(out[0]->vec, icol);
}
-static int gpu_shader_invert(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_invert(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "invert", in, out);
+ return GPU_stack_link(mat, node, "invert", in, out);
}
void register_node_type_sh_invert(void)
@@ -75,7 +75,6 @@ void register_node_type_sh_invert(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_invert_in, sh_node_invert_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_invert);
node_type_gpu(&ntype, gpu_shader_invert);
diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c
deleted file mode 100644
index 5dd3a9cd507..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_lamp.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ***** 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) 2013 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/nodes/shader/nodes/node_shader_lamp.c
- * \ingroup shdnodes
- */
-
-
-#include "node_shader_util.h"
-
-/* **************** LAMP INFO ******************** */
-static bNodeSocketTemplate sh_node_lamp_out[] = {
- { SOCK_RGBA, 0, N_("Color")},
- { SOCK_VECTOR, 0, N_("Light Vector")},
- { SOCK_FLOAT, 0, N_("Distance")},
- { SOCK_RGBA, 0, N_("Shadow")},
- { SOCK_FLOAT, 0, N_("Visibility Factor")},
- { -1, 0, "" }
-};
-
-
-static void node_shader_exec_lamp(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
-{
- if (data) {
- Object *ob = (Object *)node->id;
-
- if (ob) {
- ShadeInput *shi = ((ShaderCallData *)data)->shi;
-
- shi->nodes = 1; /* temp hack to prevent trashadow recursion */
- out[4]->vec[0] = RE_lamp_get_data(shi, ob, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec);
- shi->nodes = 0;
- if (shi->use_world_space_shading)
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[1]->vec);
- }
- }
-}
-
-static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
-{
- if (node->id) {
- GPULamp *lamp = GPU_lamp_from_blender(GPU_material_scene(mat), (Object *)node->id, NULL);
- GPUNodeLink *col, *lv, *dist, *visifac, *shadow, *energy;
-
- visifac = GPU_lamp_get_data(mat, lamp, &col, &lv, &dist, &shadow, &energy);
-
- bool ret = GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
- if (GPU_material_use_world_space_shading(mat))
- ret &= GPU_link(mat, "direction_transform_m4v3", out[1].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[1].link);
- return ret;
- }
-
- return false;
-}
-
-void register_node_type_sh_lamp(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_LAMP, "Lamp Data", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING);
- node_type_socket_templates(&ntype, NULL, sh_node_lamp_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_lamp);
- node_type_gpu(&ntype, gpu_shader_lamp);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
index 3d27d6bef7f..9c0b0a2f5f6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
+++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
@@ -41,52 +41,20 @@ static bNodeSocketTemplate sh_node_layer_weight_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_layer_weight(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_layer_weight(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[1].link)
+ if (!in[1].link) {
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
- else if (GPU_material_use_world_space_shading(mat)) {
+ }
+ else {
GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
}
- return GPU_stack_link(mat, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ return GPU_stack_link(mat, node, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
-static void node_shader_exec_layer_weight(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+static void node_shader_exec_layer_weight(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **UNUSED(out))
{
- ShadeInput *shi = ((ShaderCallData *)data)->shi;
-
- /* Compute IOR. */
- float blend;
- nodestack_get_vec(&blend, SOCK_FLOAT, in[0]);
- float eta = max_ff(1 - blend, 0.00001);
- eta = shi->flippednor ? eta : 1 / eta;
-
- /* Get normal from socket, but only if linked. */
- bNodeSocket *sock_normal = node->inputs.first;
- sock_normal = sock_normal->next;
-
- float n[3];
- if (sock_normal->link) {
- nodestack_get_vec(n, SOCK_VECTOR, in[1]);
- }
- else {
- copy_v3_v3(n, shi->vn);
- }
-
-
- if (shi->use_world_space_shading)
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n);
-
- out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, eta);
-
- float facing = fabs(dot_v3v3(shi->view, n));
- if (blend != 0.5) {
- CLAMP(blend, 0.0, 0.99999);
- blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
- facing = pow(facing, blend);
- }
- out[1]->vec[0] = 1.0 - facing;
}
/* node type definition */
@@ -95,7 +63,6 @@ void register_node_type_sh_layer_weight(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_layer_weight_in, sh_node_layer_weight_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c b/source/blender/nodes/shader/nodes/node_shader_light_falloff.c
index e28920d6f6e..f32570eaeaa 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_falloff.c
@@ -44,9 +44,9 @@ static bNodeSocketTemplate sh_node_light_falloff_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_light_falloff(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_light_falloff(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_light_falloff", in, out);
+ return GPU_stack_link(mat, node, "node_light_falloff", in, out);
}
/* node type definition */
@@ -55,7 +55,6 @@ void register_node_type_sh_light_falloff(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_light_falloff_in, sh_node_light_falloff_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.c
index 3d4d76a96b3..23d01ad4417 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_path.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_path.c
@@ -46,9 +46,9 @@ static bNodeSocketTemplate sh_node_light_path_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_light_path(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_light_path(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_light_path", in, out);
+ return GPU_stack_link(mat, node, "node_light_path", in, out);
}
/* node type definition */
@@ -57,7 +57,6 @@ void register_node_type_sh_light_path(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_light_path_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index 95d0fa5c951..282c6a4f147 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -88,13 +88,18 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
TexMapping *texmap = node->storage;
float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
- GPUNodeLink *tmat = GPU_uniform((float *)texmap->mat);
- GPUNodeLink *tmin = GPU_uniform(texmap->min);
- GPUNodeLink *tmax = GPU_uniform(texmap->max);
- GPUNodeLink *tdomin = GPU_uniform(&domin);
- GPUNodeLink *tdomax = GPU_uniform(&domax);
+ static float max[3] = { FLT_MAX, FLT_MAX, FLT_MAX};
+ static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
- GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax);
+ tmin = GPU_uniform((domin) ? texmap->min : min);
+ tmax = GPU_uniform((domax) ? texmap->max : max);
+ tmat0 = GPU_uniform((float *)texmap->mat[0]);
+ tmat1 = GPU_uniform((float *)texmap->mat[1]);
+ tmat2 = GPU_uniform((float *)texmap->mat[2]);
+ tmat3 = GPU_uniform((float *)texmap->mat[3]);
+
+ GPU_stack_link(mat, node, "mapping", in, out, tmat0, tmat1, tmat2, tmat3, tmin, tmax);
if (texmap->type == TEXMAP_TYPE_NORMAL)
GPU_link(mat, "texco_norm", out[0].link, &out[0].link);
@@ -107,7 +112,6 @@ void register_node_type_sh_mapping(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
node_type_size(&ntype, 320, 160, 360);
node_type_init(&ntype, node_shader_init_mapping);
diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c
deleted file mode 100644
index 8a73ddc1194..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_material.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * ***** 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) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/nodes/shader/nodes/node_shader_material.c
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** MATERIAL ******************** */
-
-static bNodeSocketTemplate sh_node_material_in[] = {
- { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 1, N_("Spec"), 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 1, N_("DiffuseIntensity"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
- { -1, 0, "" }
-};
-
-static bNodeSocketTemplate sh_node_material_out[] = {
- { SOCK_RGBA, 0, N_("Color")},
- { SOCK_FLOAT, 0, N_("Alpha")},
- { SOCK_VECTOR, 0, N_("Normal")},
- { -1, 0, "" }
-};
-
-/* **************** EXTENDED MATERIAL ******************** */
-
-static bNodeSocketTemplate sh_node_material_ext_in[] = {
- { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_RGBA, 1, N_("Spec"), 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 1, N_("DiffuseIntensity"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
- { SOCK_RGBA, 1, N_("Mirror"), 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 1, N_("Ambient"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- { SOCK_FLOAT, 1, N_("Emit"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
- { SOCK_FLOAT, 1, N_("SpecTra"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- { SOCK_FLOAT, 1, N_("Reflectivity"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- { SOCK_FLOAT, 1, N_("Alpha"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
- { SOCK_FLOAT, 1, N_("Translucency"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
- { -1, 0, "" }
-};
-
-static bNodeSocketTemplate sh_node_material_ext_out[] = {
- { SOCK_RGBA, 0, N_("Color")},
- { SOCK_FLOAT, 0, N_("Alpha")},
- { SOCK_VECTOR, 0, N_("Normal")},
- { SOCK_RGBA, 0, N_("Diffuse")},
- { SOCK_RGBA, 0, N_("Spec")},
- { SOCK_RGBA, 0, N_("AO")},
- { -1, 0, "" }
-};
-
-static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
-{
- if (data && node->id) {
- ShadeResult shrnode;
- ShadeInput *shi;
- ShaderCallData *shcd = data;
- float col[4];
- bNodeSocket *sock;
- char hasinput[NUM_MAT_IN] = {'\0'};
- int i, mode;
-
- /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
- * the constant input stack values (e.g. in case material node is inside a group).
- * we just want to know if a node input uses external data or the material setting.
- * this is an ugly hack, but so is this node as a whole.
- */
- for (sock = node->inputs.first, i = 0; sock; sock = sock->next, ++i)
- hasinput[i] = (sock->link != NULL);
-
- shi = shcd->shi;
- shi->mat = (Material *)node->id;
-
- /* copy all relevant material vars, note, keep this synced with render_types.h */
- memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float));
- shi->har = shi->mat->har;
-
- /* write values */
- if (hasinput[MAT_IN_COLOR])
- nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
-
- if (hasinput[MAT_IN_SPEC])
- nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
-
- if (hasinput[MAT_IN_REFL])
- nodestack_get_vec(&shi->refl, SOCK_FLOAT, in[MAT_IN_REFL]);
-
- /* retrieve normal */
- if (hasinput[MAT_IN_NORMAL]) {
- nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
- if (shi->use_world_space_shading) {
- negate_v3(shi->vn);
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), shi->vn);
- }
- normalize_v3(shi->vn);
- }
- else
- copy_v3_v3(shi->vn, shi->vno);
-
- /* custom option to flip normal */
- if (node->custom1 & SH_NODE_MAT_NEG) {
- negate_v3(shi->vn);
- }
-
- if (node->type == SH_NODE_MATERIAL_EXT) {
- if (hasinput[MAT_IN_MIR])
- nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]);
- if (hasinput[MAT_IN_AMB])
- nodestack_get_vec(&shi->amb, SOCK_FLOAT, in[MAT_IN_AMB]);
- if (hasinput[MAT_IN_EMIT])
- nodestack_get_vec(&shi->emit, SOCK_FLOAT, in[MAT_IN_EMIT]);
- if (hasinput[MAT_IN_SPECTRA])
- nodestack_get_vec(&shi->spectra, SOCK_FLOAT, in[MAT_IN_SPECTRA]);
- if (hasinput[MAT_IN_RAY_MIRROR])
- nodestack_get_vec(&shi->ray_mirror, SOCK_FLOAT, in[MAT_IN_RAY_MIRROR]);
- if (hasinput[MAT_IN_ALPHA])
- nodestack_get_vec(&shi->alpha, SOCK_FLOAT, in[MAT_IN_ALPHA]);
- if (hasinput[MAT_IN_TRANSLUCENCY])
- nodestack_get_vec(&shi->translucency, SOCK_FLOAT, in[MAT_IN_TRANSLUCENCY]);
- }
-
- /* make alpha output give results even if transparency is only enabled on
- * the material linked in this not and not on the parent material */
- mode = shi->mode;
- if (shi->mat->mode & MA_TRANSP)
- shi->mode |= MA_TRANSP;
-
- shi->nodes = 1; /* temp hack to prevent trashadow recursion */
- node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */
- shi->nodes = 0;
-
- shi->mode = mode;
-
- /* write to outputs */
- if (node->custom1 & SH_NODE_MAT_DIFF) {
- copy_v3_v3(col, shrnode.combined);
- if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
- sub_v3_v3(col, shrnode.spec);
- }
- }
- else if (node->custom1 & SH_NODE_MAT_SPEC) {
- copy_v3_v3(col, shrnode.spec);
- }
- else
- col[0] = col[1] = col[2] = 0.0f;
-
- col[3] = shrnode.alpha;
-
- if (shi->do_preview)
- BKE_node_preview_set_pixel(execdata->preview, col, shi->xs, shi->ys, shi->do_manage);
-
- copy_v3_v3(out[MAT_OUT_COLOR]->vec, col);
- out[MAT_OUT_ALPHA]->vec[0] = shrnode.alpha;
-
- if (node->custom1 & SH_NODE_MAT_NEG) {
- shi->vn[0] = -shi->vn[0];
- shi->vn[1] = -shi->vn[1];
- shi->vn[2] = -shi->vn[2];
- }
-
- copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn);
-
- if (shi->use_world_space_shading) {
- negate_v3(out[MAT_OUT_NORMAL]->vec);
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[MAT_OUT_NORMAL]->vec);
- }
- /* Extended material options */
- if (node->type == SH_NODE_MATERIAL_EXT) {
- /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
- * a node tree :( */
- copy_v3_v3(out[MAT_OUT_DIFFUSE]->vec, shrnode.diffshad);
- copy_v3_v3(out[MAT_OUT_SPEC]->vec, shrnode.spec);
- copy_v3_v3(out[MAT_OUT_AO]->vec, shrnode.ao);
- }
-
- /* copy passes, now just active node */
- if (node->flag & NODE_ACTIVE_ID) {
- float combined[4], alpha;
-
- copy_v4_v4(combined, shcd->shr->combined);
- alpha = shcd->shr->alpha;
-
- *(shcd->shr) = shrnode;
-
- copy_v4_v4(shcd->shr->combined, combined);
- shcd->shr->alpha = alpha;
- }
- }
-}
-
-
-static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->custom1 = SH_NODE_MAT_DIFF | SH_NODE_MAT_SPEC;
-}
-
-/* XXX this is also done as a local static function in gpu_codegen.c,
- * but we need this to hack around the crappy material node.
- */
-static GPUNodeLink *gpu_get_input_link(GPUMaterial *mat, GPUNodeStack *in)
-{
- if (in->link) {
- return in->link;
- }
- else {
- GPUNodeLink *result = NULL;
-
- /* note GPU_uniform() is only intended to be used as a parameter to
- * GPU_link(), returning it directly results in leaks or double frees */
- if (in->type == GPU_FLOAT)
- GPU_link(mat, "set_value", GPU_uniform(in->vec), &result);
- else if (in->type == GPU_VEC3)
- GPU_link(mat, "set_rgb", GPU_uniform(in->vec), &result);
- else if (in->type == GPU_VEC4)
- GPU_link(mat, "set_rgba", GPU_uniform(in->vec), &result);
- else
- BLI_assert(0);
-
- return result;
- }
-}
-
-static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
-{
- if (node->id) {
- GPUShadeInput shi;
- GPUShadeResult shr;
- bNodeSocket *sock;
- char hasinput[NUM_MAT_IN] = {'\0'};
- int i;
-
- /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
- * the constant input stack values (e.g. in case material node is inside a group).
- * we just want to know if a node input uses external data or the material setting.
- */
- for (sock = node->inputs.first, i = 0; sock; sock = sock->next, ++i)
- hasinput[i] = (sock->link != NULL);
-
- GPU_shadeinput_set(mat, (Material *)node->id, &shi);
-
- /* write values */
- if (hasinput[MAT_IN_COLOR])
- shi.rgb = gpu_get_input_link(mat, &in[MAT_IN_COLOR]);
-
- if (hasinput[MAT_IN_SPEC])
- shi.specrgb = gpu_get_input_link(mat, &in[MAT_IN_SPEC]);
-
- if (hasinput[MAT_IN_REFL])
- shi.refl = gpu_get_input_link(mat, &in[MAT_IN_REFL]);
-
- /* retrieve normal */
- if (hasinput[MAT_IN_NORMAL]) {
- GPUNodeLink *tmp;
- shi.vn = gpu_get_input_link(mat, &in[MAT_IN_NORMAL]);
- if (GPU_material_use_world_space_shading(mat)) {
- GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
- GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn);
- }
- GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp);
- }
-
- /* custom option to flip normal */
- if (node->custom1 & SH_NODE_MAT_NEG)
- GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
-
- if (node->type == SH_NODE_MATERIAL_EXT) {
- if (hasinput[MAT_IN_MIR])
- shi.mir = gpu_get_input_link(mat, &in[MAT_IN_MIR]);
- if (hasinput[MAT_IN_AMB])
- shi.amb = gpu_get_input_link(mat, &in[MAT_IN_AMB]);
- if (hasinput[MAT_IN_EMIT])
- shi.emit = gpu_get_input_link(mat, &in[MAT_IN_EMIT]);
- if (hasinput[MAT_IN_SPECTRA])
- shi.spectra = gpu_get_input_link(mat, &in[MAT_IN_SPECTRA]);
- if (hasinput[MAT_IN_ALPHA])
- shi.alpha = gpu_get_input_link(mat, &in[MAT_IN_ALPHA]);
- }
-
- GPU_shaderesult_set(&shi, &shr); /* clears shr */
-
- /* write to outputs */
- if (node->custom1 & SH_NODE_MAT_DIFF) {
- out[MAT_OUT_COLOR].link = shr.combined;
-
- if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
- GPUNodeLink *link;
- GPU_link(mat, "vec_math_sub", shr.combined, shr.spec, &out[MAT_OUT_COLOR].link, &link);
- }
- }
- else if (node->custom1 & SH_NODE_MAT_SPEC) {
- out[MAT_OUT_COLOR].link = shr.spec;
- }
- else
- GPU_link(mat, "set_rgb_zero", &out[MAT_OUT_COLOR].link);
-
- GPU_link(mat, "mtex_alpha_to_col", out[MAT_OUT_COLOR].link, shr.alpha, &out[MAT_OUT_COLOR].link);
-
- out[MAT_OUT_ALPHA].link = shr.alpha; //
-
- if (node->custom1 & SH_NODE_MAT_NEG)
- GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
- out[MAT_OUT_NORMAL].link = shi.vn;
- if (GPU_material_use_world_space_shading(mat)) {
- GPU_link(mat, "vec_math_negate", out[MAT_OUT_NORMAL].link, &out[MAT_OUT_NORMAL].link);
- GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link);
- }
-
- if (node->type == SH_NODE_MATERIAL_EXT) {
- out[MAT_OUT_DIFFUSE].link = shr.diff;
- out[MAT_OUT_SPEC].link = shr.spec;
- GPU_link(mat, "set_rgb_one", &out[MAT_OUT_AO].link);
- }
-
- return 1;
- }
-
- return 0;
-}
-
-void register_node_type_sh_material(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_MATERIAL, "Material", NODE_CLASS_INPUT, NODE_PREVIEW);
- node_type_compatibility(&ntype, NODE_OLD_SHADING);
- node_type_socket_templates(&ntype, sh_node_material_in, sh_node_material_out);
- node_type_init(&ntype, node_shader_init_material);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_material);
- node_type_gpu(&ntype, gpu_shader_material);
-
- nodeRegisterType(&ntype);
-}
-
-
-void register_node_type_sh_material_ext(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_MATERIAL_EXT, "Extended Material", NODE_CLASS_INPUT, NODE_PREVIEW);
- node_type_compatibility(&ntype, NODE_OLD_SHADING);
- node_type_socket_templates(&ntype, sh_node_material_ext_in, sh_node_material_ext_out);
- node_type_init(&ntype, node_shader_init_material);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_material);
- node_type_gpu(&ntype, gpu_shader_material);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index 605c869099a..a072c686686 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -296,7 +296,7 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
case NODE_MATH_GREATER:
case NODE_MATH_MOD:
case NODE_MATH_ATAN2:
- GPU_stack_link(mat, names[node->custom1], in, out);
+ GPU_stack_link(mat, node, names[node->custom1], in, out);
break;
case NODE_MATH_SIN:
case NODE_MATH_COS:
@@ -315,14 +315,14 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
GPUNodeStack tmp_in[2];
memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, names[node->custom1], tmp_in, out);
+ GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
}
else {
/* use only second item and terminator */
GPUNodeStack tmp_in[2];
memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, names[node->custom1], tmp_in, out);
+ GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
}
break;
default:
@@ -332,7 +332,7 @@ static int gpu_shader_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
if (node->custom2 & SHD_MATH_CLAMP) {
float min[3] = {0.0f, 0.0f, 0.0f};
float max[3] = {1.0f, 1.0f, 1.0f};
- GPU_link(mat, "clamp_val", out[0].link, GPU_uniform(min), GPU_uniform(max), &out[0].link);
+ GPU_link(mat, "clamp_val", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
}
return 1;
@@ -343,7 +343,6 @@ void register_node_type_sh_math(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
node_type_label(&ntype, node_math_label);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
index 14a9f2c5ea5..5bf5ce69261 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
@@ -71,11 +71,12 @@ static int gpu_shader_mix_rgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
"mix_screen", "mix_div", "mix_diff", "mix_dark", "mix_light",
"mix_overlay", "mix_dodge", "mix_burn", "mix_hue", "mix_sat",
"mix_val", "mix_color", "mix_soft", "mix_linear"};
- int ret = GPU_stack_link(mat, names[node->custom1], in, out);
+
+ int ret = GPU_stack_link(mat, node, names[node->custom1], in, out);
if (ret && node->custom2 & SHD_MIXRGB_CLAMP) {
float min[3] = {0.0f, 0.0f, 0.0f};
float max[3] = {1.0f, 1.0f, 1.0f};
- GPU_link(mat, "clamp_vec3", out[0].link, GPU_uniform(min), GPU_uniform(max), &out[0].link);
+ GPU_link(mat, "clamp_vec3", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
}
return ret;
}
@@ -86,7 +87,6 @@ void register_node_type_sh_mix_rgb(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_mix_rgb_in, sh_node_mix_rgb_out);
node_type_label(&ntype, node_blend_label);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_mix_rgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c b/source/blender/nodes/shader/nodes/node_shader_mix_shader.c
index 0e4d6c9cda6..1d6c76766b3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.c
@@ -41,9 +41,9 @@ static bNodeSocketTemplate sh_node_mix_shader_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_mix_shader(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_mix_shader(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_mix_shader", in, out);
+ return GPU_stack_link(mat, node, "node_mix_shader", in, out);
}
/* node type definition */
@@ -52,7 +52,6 @@ void register_node_type_sh_mix_shader(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_mix_shader_in, sh_node_mix_shader_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.c
index 84d250eed7b..121cb9cc1a5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal.c
@@ -58,15 +58,10 @@ static void node_shader_exec_normal(void *UNUSED(data), int UNUSED(thread), bNod
out[1]->vec[0] = -dot_v3v3(vec, out[0]->vec);
}
-static int gpu_shader_normal(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_normal(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *vec = GPU_uniform(out[0].vec);
- if (GPU_material_use_new_shading_nodes(mat)) {
- return GPU_stack_link(mat, "normal_new_shading", in, out, vec);
- }
- else {
- return GPU_stack_link(mat, "normal", in, out, vec);
- }
+ return GPU_stack_link(mat, node, "normal_new_shading", in, out, vec);
}
void register_node_type_sh_normal(void)
@@ -74,7 +69,6 @@ void register_node_type_sh_normal(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_normal_in, sh_node_normal_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal);
node_type_gpu(&ntype, gpu_shader_normal);
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 7584b5eba4d..c066fea81ad 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -47,80 +47,9 @@ static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
}
static void node_shader_exec_normal_map(
- void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata),
- bNodeStack **in, bNodeStack **out)
+ void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata),
+ bNodeStack **UNUSED(in), bNodeStack **UNUSED(out))
{
- if (data) {
- ShadeInput *shi = ((ShaderCallData *)data)->shi;
-
- NodeShaderNormalMap *nm = node->storage;
-
- float strength, vecIn[3];
- nodestack_get_vec(&strength, SOCK_FLOAT, in[0]);
- nodestack_get_vec(vecIn, SOCK_VECTOR, in[1]);
-
- vecIn[0] = -2 * (vecIn[0] - 0.5f);
- vecIn[1] = 2 * (vecIn[1] - 0.5f);
- vecIn[2] = 2 * (vecIn[2] - 0.5f);
-
- CLAMP_MIN(strength, 0.0f);
-
- float *N = shi->nmapnorm;
- int uv_index = 0;
- switch (nm->space) {
- case SHD_SPACE_TANGENT:
- if (nm->uv_map[0]) {
- /* find uv map by name */
- for (int i = 0; i < shi->totuv; i++) {
- if (STREQ(shi->uv[i].name, nm->uv_map)) {
- uv_index = i;
- break;
- }
- }
- }
- else {
- uv_index = shi->actuv;
- }
-
- float *T = shi->tangents[uv_index];
-
- float B[3];
- cross_v3_v3v3(B, N, T);
- mul_v3_fl(B, T[3]);
-
- for (int j = 0; j < 3; j++)
- out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j];
- interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength);
- if (shi->use_world_space_shading) {
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[0]->vec);
- }
- break;
-
- case SHD_SPACE_OBJECT:
- case SHD_SPACE_BLENDER_OBJECT:
- if (shi->use_world_space_shading) {
- mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB), vecIn);
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N);
- }
- else
- mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
- interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
- break;
-
- case SHD_SPACE_WORLD:
- case SHD_SPACE_BLENDER_WORLD:
- if (shi->use_world_space_shading)
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N);
- else
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
- interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
- break;
- }
- if (shi->use_world_space_shading) {
- negate_v3(out[0]->vec);
- }
- normalize_v3(out[0]->vec);
- }
}
static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
@@ -134,68 +63,50 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U
if (in[0].link)
strength = in[0].link;
+ else if (node->original) {
+ bNodeSocket *socket = BLI_findlink(&node->original->inputs, 0);
+ bNodeSocketValueFloat *socket_data = socket->default_value;
+ strength = GPU_uniform(&socket_data->value);
+ }
else
- strength = GPU_uniform(in[0].vec);
+ strength = GPU_constant(in[0].vec);
if (in[1].link)
realnorm = in[1].link;
+ else if (node->original) {
+ bNodeSocket *socket = BLI_findlink(&node->original->inputs, 1);
+ bNodeSocketValueRGBA *socket_data = socket->default_value;
+ realnorm = GPU_uniform(socket_data->value);
+ }
else
- realnorm = GPU_uniform(in[1].vec);
+ realnorm = GPU_constant(in[1].vec);
negnorm = GPU_builtin(GPU_VIEW_NORMAL);
- GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength);
-
- if (GPU_material_use_world_space_shading(mat)) {
-
- /* ******* CYCLES or BLENDER INTERNAL with world space shading flag ******* */
-
- const char *color_to_normal_fnc_name = "color_to_normal_new_shading";
- if (nm->space == SHD_SPACE_BLENDER_OBJECT || nm->space == SHD_SPACE_BLENDER_WORLD || !GPU_material_use_new_shading_nodes(mat))
- color_to_normal_fnc_name = "color_to_blender_normal_new_shading";
- switch (nm->space) {
- case SHD_SPACE_TANGENT:
- GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
- GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
- GPU_link(mat, "vec_math_mix", strength, realnorm, GPU_builtin(GPU_VIEW_NORMAL), &out[0].link);
- /* for uniform scale this is sufficient to match Cycles */
- GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link);
- GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
- return true;
- case SHD_SPACE_OBJECT:
- case SHD_SPACE_BLENDER_OBJECT:
- GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
- GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
- break;
- case SHD_SPACE_WORLD:
- case SHD_SPACE_BLENDER_WORLD:
- GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
- GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
- break;
- }
-
- }
- else {
-
- /* ************** BLENDER INTERNAL without world space shading flag ******* */
-
- GPU_link(mat, "color_to_normal", realnorm, &realnorm);
- GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
- GPU_link(mat, "vec_math_negate", negnorm, &negnorm);
-
- switch (nm->space) {
- case SHD_SPACE_TANGENT:
- GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
- break;
- case SHD_SPACE_OBJECT:
- case SHD_SPACE_BLENDER_OBJECT:
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &realnorm);
- break;
- case SHD_SPACE_WORLD:
- case SHD_SPACE_BLENDER_WORLD:
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &realnorm);
- break;
- }
+ GPU_link(mat, "math_max", strength, GPU_constant(d), &strength);
+
+ const char *color_to_normal_fnc_name = "color_to_normal_new_shading";
+ if (nm->space == SHD_SPACE_BLENDER_OBJECT || nm->space == SHD_SPACE_BLENDER_WORLD)
+ color_to_normal_fnc_name = "color_to_blender_normal_new_shading";
+ switch (nm->space) {
+ case SHD_SPACE_TANGENT:
+ GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
+ GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
+ GPU_link(mat, "vec_math_mix", strength, realnorm, GPU_builtin(GPU_VIEW_NORMAL), &out[0].link);
+ /* for uniform scale this is sufficient to match Cycles */
+ GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ return true;
+ case SHD_SPACE_OBJECT:
+ case SHD_SPACE_BLENDER_OBJECT:
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
+ GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
+ break;
+ case SHD_SPACE_WORLD:
+ case SHD_SPACE_BLENDER_WORLD:
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
+ GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
+ break;
}
GPU_link(mat, "vec_math_mix", strength, realnorm, negnorm, &out[0].link);
@@ -210,7 +121,6 @@ void register_node_type_sh_normal_map(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_normal_map);
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c
index 9c7ea549ea5..713e2f749f7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c
@@ -37,18 +37,13 @@ static bNodeSocketTemplate sh_node_object_info_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO));
+ return GPU_stack_link(mat, node, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO));
}
-static void node_shader_exec_object_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
+static void node_shader_exec_object_info(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **UNUSED(out))
{
- ShaderCallData *scd = (ShaderCallData *)data;
- copy_v4_v4(out[0]->vec, RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB)[3]);
- out[1]->vec[0] = RE_object_instance_get_object_pass_index(scd->shi->obi);
- out[2]->vec[0] = scd->shi->mat->index;
- out[3]->vec[0] = RE_object_instance_get_random_id(scd->shi->obi) * (1.0f / (float)0xFFFFFFFF);
}
/* node type definition */
@@ -57,7 +52,6 @@ void register_node_type_sh_object_info(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_object_info_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_output.c b/source/blender/nodes/shader/nodes/node_shader_output.c
deleted file mode 100644
index 5b1a68b4bf9..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_output.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * ***** 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) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/nodes/shader/nodes/node_shader_output.c
- * \ingroup shdnodes
- */
-
-
-#include "node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-static bNodeSocketTemplate sh_node_output_in[] = {
- { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- { SOCK_FLOAT, 1, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- { -1, 0, "" }
-};
-
-static void node_shader_exec_output(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **UNUSED(out))
-{
- if (data) {
- ShadeInput *shi = ((ShaderCallData *)data)->shi;
- float col[4];
-
- /* stack order input sockets: col, alpha, normal */
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
- nodestack_get_vec(col + 3, SOCK_FLOAT, in[1]);
-
- if (shi->do_preview) {
- BKE_node_preview_set_pixel(execdata->preview, col, shi->xs, shi->ys, shi->do_manage);
- node->lasty = shi->ys;
- }
-
- if (node->flag & NODE_DO_OUTPUT) {
- ShadeResult *shr = ((ShaderCallData *)data)->shr;
-
- copy_v4_v4(shr->combined, col);
- shr->alpha = col[3];
-
- // copy_v3_v3(shr->nor, in[3]->vec);
- }
- }
-}
-
-static int gpu_shader_output(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
-{
- GPUNodeLink *outlink;
-
-#if 0
- if (in[1].hasinput)
- GPU_material_enable_alpha(mat);
-#endif
-
- GPU_stack_link(mat, "output_node", in, out, &outlink);
- GPU_material_output_link(mat, outlink);
-
- return 1;
-}
-
-void register_node_type_sh_output(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_compatibility(&ntype, NODE_OLD_SHADING);
- node_type_socket_templates(&ntype, sh_node_output_in, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_output);
- node_type_gpu(&ntype, gpu_shader_output);
-
- /* Do not allow muting output node. */
- node_type_internal_links(&ntype, NULL);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_lamp.c b/source/blender/nodes/shader/nodes/node_shader_output_lamp.c
index b08a4b4ff57..f44f5d332cf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_lamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_lamp.c
@@ -39,8 +39,7 @@ void register_node_type_sh_output_lamp(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_LAMP, "Lamp Output", NODE_CLASS_OUTPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT, 0);
node_type_socket_templates(&ntype, sh_node_output_lamp_in, NULL);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
index 2eb68f23912..b56d6eca44b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
@@ -43,7 +43,6 @@ void register_node_type_sh_output_linestyle(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL);
node_type_init(&ntype, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c
index 353ab387075..81a89177351 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c
@@ -27,6 +27,8 @@
#include "../node_shader_util.h"
+#include "BKE_scene.h"
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_output_material_in[] = {
@@ -36,11 +38,11 @@ static bNodeSocketTemplate sh_node_output_material_in[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_output_material(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_output_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *outlink;
- GPU_stack_link(mat, "node_output_material", in, out, &outlink);
+ GPU_stack_link(mat, node, "node_output_material", in, out, &outlink);
GPU_material_output_link(mat, outlink);
return true;
@@ -53,7 +55,6 @@ void register_node_type_sh_output_material(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_output_material_in, NULL);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.c
index 9581153538b..1980e6be5a3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_world.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_world.c
@@ -35,11 +35,11 @@ static bNodeSocketTemplate sh_node_output_world_in[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_output_world(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_output_world(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *outlink;
- GPU_stack_link(mat, "node_output_world", in, out, &outlink);
+ GPU_stack_link(mat, node, "node_output_world", in, out, &outlink);
GPU_material_output_link(mat, outlink);
return true;
@@ -51,7 +51,6 @@ void register_node_type_sh_output_world(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_output_world_in, NULL);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.c b/source/blender/nodes/shader/nodes/node_shader_particle_info.c
index 6dd8fbee3d2..34c4d364fac 100644
--- a/source/blender/nodes/shader/nodes/node_shader_particle_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.c
@@ -42,17 +42,14 @@ static bNodeSocketTemplate outputs[] = {
{ SOCK_VECTOR, 0, "Angular Velocity" },
{ -1, 0, "" }
};
-static void node_shader_exec_particle_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
+static void node_shader_exec_particle_info(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **UNUSED(out))
{
- ShadeInput *shi = ((ShaderCallData *)data)->shi;
-
- RE_instance_get_particle_info(shi->obi, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec, out[4]->vec, out[5]->vec, out[6]->vec, out[7]->vec);
}
-static int gpu_shader_particle_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_particle_info(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "particle_info", in, out,
+ return GPU_stack_link(mat, node, "particle_info", in, out,
GPU_builtin(GPU_PARTICLE_SCALAR_PROPS),
GPU_builtin(GPU_PARTICLE_LOCATION),
GPU_builtin(GPU_PARTICLE_VELOCITY),
@@ -65,7 +62,6 @@ void register_node_type_sh_particle_info(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
node_type_socket_templates(&ntype, NULL, outputs);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_particle_info);
node_type_gpu(&ntype, gpu_shader_particle_info);
diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.c b/source/blender/nodes/shader/nodes/node_shader_rgb.c
index d3ac659c153..0ddad803270 100644
--- a/source/blender/nodes/shader/nodes/node_shader_rgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb.c
@@ -38,10 +38,10 @@ static bNodeSocketTemplate sh_node_rgb_out[] = {
{ -1, 0, "" }
};
-static int gpu_shader_rgb(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_rgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- GPUNodeLink *vec = GPU_uniform(out[0].vec);
- return GPU_stack_link(mat, "set_rgba", in, out, vec);
+ GPUNodeLink *link = GPU_uniformbuffer_link_out(mat, node, out, 0);
+ return GPU_stack_link(mat, node, "set_rgba", in, out, link);
}
void register_node_type_sh_rgb(void)
@@ -49,7 +49,6 @@ void register_node_type_sh_rgb(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_rgb_out);
node_type_gpu(&ntype, gpu_shader_rgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_script.c b/source/blender/nodes/shader/nodes/node_shader_script.c
index 888e502a7f6..2d13fc214be 100644
--- a/source/blender/nodes/shader/nodes/node_shader_script.c
+++ b/source/blender/nodes/shader/nodes/node_shader_script.c
@@ -68,7 +68,6 @@ void register_node_type_sh_script(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_init(&ntype, init);
node_type_storage(&ntype, "NodeShaderScript", node_free_script, node_copy_script);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
index 0a47978431f..09cd997f86b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
@@ -53,9 +53,9 @@ static void node_shader_exec_sephsv(void *UNUSED(data), int UNUSED(thread), bNod
&out[0]->vec[0], &out[1]->vec[0], &out[2]->vec[0]);
}
-static int gpu_shader_sephsv(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_sephsv(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "separate_hsv", in, out);
+ return GPU_stack_link(mat, node, "separate_hsv", in, out);
}
void register_node_type_sh_sephsv(void)
@@ -63,7 +63,6 @@ void register_node_type_sh_sephsv(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv);
node_type_gpu(&ntype, gpu_shader_sephsv);
@@ -94,9 +93,9 @@ static void node_shader_exec_combhsv(void *UNUSED(data), int UNUSED(thread), bNo
hsv_to_rgb(h, s, v, &out[0]->vec[0], &out[0]->vec[1], &out[0]->vec[2]);
}
-static int gpu_shader_combhsv(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_combhsv(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "combine_hsv", in, out);
+ return GPU_stack_link(mat, node, "combine_hsv", in, out);
}
void register_node_type_sh_combhsv(void)
@@ -104,7 +103,6 @@ void register_node_type_sh_combhsv(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv);
node_type_gpu(&ntype, gpu_shader_combhsv);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
index 8748abd5eb6..b4810b95d4b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
@@ -54,9 +54,9 @@ static void node_shader_exec_seprgb(void *UNUSED(data), int UNUSED(thread), bNod
out[2]->vec[0] = col[2];
}
-static int gpu_shader_seprgb(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_seprgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "separate_rgb", in, out);
+ return GPU_stack_link(mat, node, "separate_rgb", in, out);
}
void register_node_type_sh_seprgb(void)
@@ -64,7 +64,6 @@ void register_node_type_sh_seprgb(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_seprgb_in, sh_node_seprgb_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_seprgb);
node_type_gpu(&ntype, gpu_shader_seprgb);
@@ -98,9 +97,9 @@ static void node_shader_exec_combrgb(void *UNUSED(data), int UNUSED(thread), bNo
out[0]->vec[2] = b;
}
-static int gpu_shader_combrgb(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_combrgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "combine_rgb", in, out);
+ return GPU_stack_link(mat, node, "combine_rgb", in, out);
}
void register_node_type_sh_combrgb(void)
@@ -108,7 +107,6 @@ void register_node_type_sh_combrgb(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_combrgb_in, sh_node_combrgb_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_combrgb);
node_type_gpu(&ntype, gpu_shader_combrgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
index 9394dc7215b..bff8e38b8c8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
@@ -44,9 +44,9 @@ static bNodeSocketTemplate sh_node_sepxyz_out[] = {
{ -1, 0, "" }
};
-static int gpu_shader_sepxyz(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_sepxyz(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "separate_xyz", in, out);
+ return GPU_stack_link(mat, node, "separate_xyz", in, out);
}
void register_node_type_sh_sepxyz(void)
@@ -54,7 +54,6 @@ void register_node_type_sh_sepxyz(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_sepxyz_in, sh_node_sepxyz_out);
node_type_gpu(&ntype, gpu_shader_sepxyz);
@@ -75,9 +74,9 @@ static bNodeSocketTemplate sh_node_combxyz_out[] = {
{ -1, 0, "" }
};
-static int gpu_shader_combxyz(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_combxyz(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "combine_xyz", in, out);
+ return GPU_stack_link(mat, node, "combine_xyz", in, out);
}
void register_node_type_sh_combxyz(void)
@@ -85,7 +84,6 @@ void register_node_type_sh_combxyz(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_combxyz_in, sh_node_combxyz_out);
node_type_gpu(&ntype, gpu_shader_combxyz);
diff --git a/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c b/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c
new file mode 100644
index 00000000000..8617e3414b5
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_shaderToRgb.c
@@ -0,0 +1,60 @@
+/*
+ * ***** 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) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kanzaki Wataru, Kinouti Takahiro
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_shadertorgb_in[] = {
+ { SOCK_SHADER, 1, N_("Shader")},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_shadertorgb_out[] = {
+ { SOCK_RGBA, 0, N_("Color")},
+ { SOCK_FLOAT, 0, N_("Alpha")},
+ { -1, 0, "" }
+};
+
+static int node_shader_gpu_shadertorgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_shader_to_rgba", in, out);
+}
+
+/* node type definition */
+void register_node_type_sh_shadertorgb(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, sh_node_shadertorgb_in, sh_node_shadertorgb_out);
+ node_type_init(&ntype, NULL);
+ node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_shadertorgb);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.c
index bba6a56d9e5..51167db857b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_squeeze.c
+++ b/source/blender/nodes/shader/nodes/node_shader_squeeze.c
@@ -56,9 +56,9 @@ static void node_shader_exec_squeeze(void *UNUSED(data), int UNUSED(thread), bNo
out[0]->vec[0] = 1.0f / (1.0f + powf(M_E, -((vec[0] - vec[2]) * vec[1])));
}
-static int gpu_shader_squeeze(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_squeeze(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "squeeze", in, out);
+ return GPU_stack_link(mat, node, "squeeze", in, out);
}
void register_node_type_sh_squeeze(void)
@@ -66,7 +66,6 @@ void register_node_type_sh_squeeze(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_squeeze_in, sh_node_squeeze_out);
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_squeeze);
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index 78757782203..7cc80a0c636 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -49,14 +49,25 @@ static void node_shader_init_subsurface_scattering(bNodeTree *UNUSED(ntree), bNo
node->custom1 = SHD_SUBSURFACE_BURLEY;
}
-static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[5].link)
- in[5].link = GPU_builtin(GPU_VIEW_NORMAL);
- else
- GPU_link(mat, "direction_transform_m4v3", in[5].link, GPU_builtin(GPU_VIEW_MATRIX), &in[5].link);
+ GPU_link(mat, "world_normals_get", &in[5].link);
- return GPU_stack_link(mat, "node_subsurface_scattering", in, out);
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
+
+ if (node->sss_id == 1) {
+ bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = socket->default_value;
+ bNodeSocket *socket_sharp = BLI_findlink(&node->original->inputs, 3);
+ bNodeSocketValueFloat *socket_data_sharp = socket_sharp->default_value;
+ /* For some reason it seems that the socket value is in ARGB format. */
+ GPU_material_sss_profile_create(mat, &socket_data->value[1],
+ &node->original->custom1,
+ &socket_data_sharp->value);
+ }
+
+ return GPU_stack_link(mat, node, "node_subsurface_scattering", in, out, GPU_constant(&node->sss_id));
}
static void node_shader_update_subsurface_scattering(bNodeTree *UNUSED(ntree), bNode *node)
@@ -81,7 +92,6 @@ void register_node_type_sh_subsurface_scattering(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_subsurface_scattering_in, sh_node_subsurface_scattering_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_subsurface_scattering);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.c
index 7aa7fb43221..da3a8e39ccb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tangent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tangent.c
@@ -41,16 +41,38 @@ static void node_shader_init_tangent(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = attr;
}
+static int node_shader_gpu_tangent(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ NodeShaderTangent *attr = node->storage;
+
+ if (attr->direction_type == SHD_TANGENT_UVMAP) {
+ return GPU_stack_link(mat, node, "node_tangentmap", in, out, GPU_attribute(CD_TANGENT, ""), GPU_builtin(GPU_INVERSE_VIEW_MATRIX));
+ }
+ else {
+ GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
+
+ if (attr->axis == SHD_TANGENT_AXIS_X)
+ GPU_link(mat, "tangent_orco_x", orco, &orco);
+ else if (attr->axis == SHD_TANGENT_AXIS_Y)
+ GPU_link(mat, "tangent_orco_y", orco, &orco);
+ else
+ GPU_link(mat, "tangent_orco_z", orco, &orco);
+
+ return GPU_stack_link(mat, node, "node_tangent", in, out, GPU_builtin(GPU_VIEW_NORMAL), orco,
+ GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_INVERSE_VIEW_MATRIX));
+ }
+}
+
/* node type definition */
void register_node_type_sh_tangent(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_tangent_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_tangent);
+ node_type_gpu(&ntype, node_shader_gpu_tangent);
node_type_storage(&ntype, "NodeShaderTangent", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
index ebfb3fc29a1..4f488025a99 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -73,17 +73,17 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, bNodeExecDat
{
if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexBrick *tex = (NodeTexBrick *)node->storage;
float offset_freq = tex->offset_freq;
float squash_freq = tex->squash_freq;
- return GPU_stack_link(mat, "node_tex_brick",
+ return GPU_stack_link(mat, node, "node_tex_brick",
in, out,
- GPU_uniform(&tex->offset), GPU_uniform(&offset_freq),
- GPU_uniform(&tex->squash), GPU_uniform(&squash_freq));
+ GPU_constant(&tex->offset), GPU_constant(&offset_freq),
+ GPU_constant(&tex->squash), GPU_constant(&squash_freq));
}
/* node type definition */
@@ -92,7 +92,6 @@ void register_node_type_sh_tex_brick(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_brick_in, sh_node_tex_brick_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_tex_brick);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
index f700faff200..52aa33c033e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c
@@ -56,12 +56,12 @@ static int node_shader_gpu_tex_checker(GPUMaterial *mat, bNode *node, bNodeExecD
{
if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_checker", in, out);
+ return GPU_stack_link(mat, node, "node_tex_checker", in, out);
}
/* node type definition */
@@ -70,7 +70,6 @@ void register_node_type_sh_tex_checker(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_checker_in, sh_node_tex_checker_out);
node_type_init(&ntype, node_shader_init_tex_checker);
node_type_storage(&ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
index f1721fe5567..58fea60f9f5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
@@ -42,24 +42,17 @@ static bNodeSocketTemplate sh_node_tex_coord_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, "");
- GPUMatType type = GPU_Material_get_type(mat);
- if (type == GPU_MATERIAL_TYPE_MESH) {
- return GPU_stack_link(mat, "node_tex_coord", in, out,
- GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
- GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface);
- }
- else {
- return GPU_stack_link(mat, "node_tex_coord_background", in, out,
- GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
- GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface);
- }
+ GPU_link(mat, "generated_from_orco", orco, &orco);
+
+ return GPU_stack_link(mat, node, "node_tex_coord", in, out,
+ GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+ GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface);
}
/* node type definition */
@@ -68,7 +61,6 @@ void register_node_type_sh_tex_coord(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_tex_coord_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 9b485a30083..ab8ce456b05 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -48,7 +48,6 @@ static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *no
tex->projection = SHD_PROJ_EQUIRECTANGULAR;
tex->iuser.frames = 1;
tex->iuser.sfra = 1;
- tex->iuser.fie_ima = 2;
tex->iuser.ok = 1;
node->storage = tex;
@@ -58,27 +57,44 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
{
Image *ima = (Image *)node->id;
ImageUser *iuser = NULL;
- NodeTexImage *tex = node->storage;
+ NodeTexEnvironment *tex = node->storage;
int isdata = tex->color_space == SHD_COLORSPACE_NONE;
+ GPUNodeLink *outalpha;
if (!ima)
- return GPU_stack_link(mat, "node_tex_environment_empty", in, out);
+ return GPU_stack_link(mat, node, "node_tex_environment_empty", in, out);
if (!in[0].link) {
- GPUMatType type = GPU_Material_get_type(mat);
-
- if (type == GPU_MATERIAL_TYPE_MESH)
- in[0].link = GPU_builtin(GPU_VIEW_POSITION);
- else
- GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &in[0].link);
+ GPU_link(mat, "node_tex_environment_texco", GPU_builtin(GPU_VIEW_POSITION), &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
- if (tex->projection == SHD_PROJ_EQUIRECTANGULAR)
- GPU_stack_link(mat, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata));
- else
- GPU_stack_link(mat, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata));
+ /* Compute texture coordinate. */
+ if (tex->projection == SHD_PROJ_EQUIRECTANGULAR) {
+ /* To fix pole issue we clamp the v coordinate. The clamp value depends on the filter size. */
+ float clamp_size = (ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART)) ? 1.5 : 0.5;
+ GPU_link(mat, "node_tex_environment_equirectangular", in[0].link, GPU_constant(&clamp_size),
+ GPU_image(ima, iuser, isdata), &in[0].link);
+ }
+ else {
+ GPU_link(mat, "node_tex_environment_mirror_ball", in[0].link, &in[0].link);
+ }
+
+ /* Sample texture with correct interpolation. */
+ switch (tex->interpolation) {
+ case SHD_INTERP_LINEAR:
+ /* Force the highest mipmap and don't do anisotropic filtering.
+ * This is to fix the artifact caused by derivatives discontinuity. */
+ GPU_link(mat, "node_tex_image_linear_no_mip", in[0].link, GPU_image(ima, iuser, isdata), &out[0].link, &outalpha);
+ break;
+ case SHD_INTERP_CLOSEST:
+ GPU_link(mat, "node_tex_image_nearest", in[0].link, GPU_image(ima, iuser, isdata), &out[0].link, &outalpha);
+ break;
+ default:
+ GPU_link(mat, "node_tex_image_cubic", in[0].link, GPU_image(ima, iuser, isdata), &out[0].link, &outalpha);
+ break;
+ }
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
@@ -97,12 +113,12 @@ void register_node_type_sh_tex_environment(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_environment_in, sh_node_tex_environment_out);
node_type_init(&ntype, node_shader_init_tex_environment);
node_type_storage(&ntype, "NodeTexEnvironment", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_environment);
node_type_label(&ntype, node_image_label);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
index 9be4f2a719d..404463a8fbe 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c
@@ -54,14 +54,14 @@ static int node_shader_gpu_tex_gradient(GPUMaterial *mat, bNode *node, bNodeExec
{
if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexGradient *tex = (NodeTexGradient *)node->storage;
float gradient_type = tex->gradient_type;
- return GPU_stack_link(mat, "node_tex_gradient", in, out, GPU_uniform(&gradient_type));
+ return GPU_stack_link(mat, node, "node_tex_gradient", in, out, GPU_constant(&gradient_type));
}
/* node type definition */
@@ -70,7 +70,6 @@ void register_node_type_sh_tex_gradient(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_gradient_in, sh_node_tex_gradient_out);
node_type_init(&ntype, node_shader_init_tex_gradient);
node_type_storage(&ntype, "NodeTexGradient", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index ae9124d0588..524f7a5c8e2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -48,7 +48,6 @@ static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
tex->color_space = SHD_COLORSPACE_COLOR;
tex->iuser.frames = 1;
tex->iuser.sfra = 1;
- tex->iuser.fie_ima = 2;
tex->iuser.ok = 1;
node->storage = tex;
@@ -56,17 +55,59 @@ static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
+ static const char *names[] = {
+ "node_tex_image_linear",
+ "node_tex_image_nearest",
+ "node_tex_image_cubic",
+ "node_tex_image_smart"
+ };
+ static const char *names_box[] = {
+ "tex_box_sample_linear",
+ "tex_box_sample_nearest",
+ "tex_box_sample_cubic",
+ "tex_box_sample_smart"
+ };
+ static const char *names_clip[] = {
+ "tex_clip_linear",
+ "tex_clip_nearest",
+ "tex_clip_cubic",
+ "tex_clip_smart"
+ };
+
Image *ima = (Image *)node->id;
ImageUser *iuser = NULL;
NodeTexImage *tex = node->storage;
+ const char *gpu_node_name = (tex->projection == SHD_PROJ_BOX)
+ ? names_box[tex->interpolation]
+ : names[tex->interpolation];
+ bool do_color_correction = false;
+ bool do_texco_extend = (tex->extension != SHD_IMAGE_EXTENSION_REPEAT);
+ const bool do_texco_clip = (tex->extension == SHD_IMAGE_EXTENSION_CLIP);
+
+ if (do_texco_extend && (tex->projection != SHD_PROJ_BOX) &&
+ ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART))
+ {
+ gpu_node_name = "node_tex_image_cubic_extend";
+ /* We do it inside the sampling function */
+ do_texco_extend = false;
+ }
- GPUNodeLink *norm;
+ GPUNodeLink *norm, *col1, *col2, *col3, *input_coords;
int isdata = tex->color_space == SHD_COLORSPACE_NONE;
float blend = tex->projection_blend;
if (!ima)
- return GPU_stack_link(mat, "node_tex_image_empty", in, out);
+ return GPU_stack_link(mat, node, "node_tex_image_empty", in, out);
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
+ ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
+ GPU_material_do_color_management(mat))
+ {
+ do_color_correction = true;
+ }
+ BKE_image_release_ibuf(ima, ibuf, NULL);
if (!in[0].link)
in[0].link = GPU_attribute(CD_MTFACE, "");
@@ -75,7 +116,13 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
switch (tex->projection) {
case SHD_PROJ_FLAT:
- GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ if (do_texco_clip) {
+ GPU_link(mat, "set_rgb", in[0].link, &input_coords);
+ }
+ if (do_texco_extend) {
+ GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link);
+ }
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
break;
case SHD_PROJ_BOX:
GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
@@ -84,8 +131,20 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
GPU_link(mat, "direction_transform_m4v3", norm,
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
&norm);
+ GPU_link(mat, gpu_node_name, in[0].link,
+ norm,
+ GPU_image(ima, iuser, isdata),
+ &col1,
+ &col2,
+ &col3);
+ if (do_color_correction) {
+ GPU_link(mat, "srgb_to_linearrgb", col1, &col1);
+ GPU_link(mat, "srgb_to_linearrgb", col2, &col2);
+ GPU_link(mat, "srgb_to_linearrgb", col3, &col3);
+ }
GPU_link(mat, "node_tex_image_box", in[0].link,
norm,
+ col1, col2, col3,
GPU_image(ima, iuser, isdata),
GPU_uniform(&blend),
&out[0].link,
@@ -94,23 +153,36 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
case SHD_PROJ_SPHERE:
GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
- GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ if (do_texco_clip) {
+ GPU_link(mat, "set_rgb", in[0].link, &input_coords);
+ }
+ if (do_texco_extend) {
+ GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link);
+ }
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
break;
case SHD_PROJ_TUBE:
GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
- GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ if (do_texco_clip) {
+ GPU_link(mat, "set_rgb", in[0].link, &input_coords);
+ }
+ if (do_texco_extend) {
+ GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link);
+ }
+ GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
break;
}
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
- ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
- GPU_material_do_color_management(mat))
- {
+ if (do_texco_clip && (tex->projection != SHD_PROJ_BOX)) {
+ GPU_link(mat, names_clip[tex->interpolation],
+ input_coords, GPU_image(ima, iuser, isdata), out[0].link,
+ &out[0].link, &out[1].link);
+ }
+
+ if (do_color_correction && (tex->projection != SHD_PROJ_BOX)) {
GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
}
- BKE_image_release_ibuf(ima, ibuf, NULL);
return true;
}
@@ -121,12 +193,12 @@ void register_node_type_sh_tex_image(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_image_in, sh_node_tex_image_out);
node_type_init(&ntype, node_shader_init_tex_image);
node_type_storage(&ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_image);
node_type_label(&ntype, node_image_label);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
index 8ab2651e014..e24ef04bc57 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c
@@ -59,12 +59,12 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat, bNode *node, bNodeExecDat
if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_magic", in, out, GPU_uniform(&depth));
+ return GPU_stack_link(mat, node, "node_tex_magic", in, out, GPU_constant(&depth));
}
/* node type definition */
@@ -73,7 +73,6 @@ void register_node_type_sh_tex_magic(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_magic_in, sh_node_tex_magic_out);
node_type_init(&ntype, node_shader_init_tex_magic);
node_type_storage(&ntype, "NodeTexMagic", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index c0584214269..5d4f6b7c578 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -60,7 +60,7 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, bNode *node, bNodeExec
{
if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
@@ -68,7 +68,7 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, bNode *node, bNodeExec
NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
float type = tex->musgrave_type;
- return GPU_stack_link(mat, "node_tex_musgrave", in, out, GPU_uniform(&type));
+ return GPU_stack_link(mat, node, "node_tex_musgrave", in, out, GPU_constant(&type));
}
/* node type definition */
@@ -77,7 +77,6 @@ void register_node_type_sh_tex_musgrave(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_musgrave_in, sh_node_tex_musgrave_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_tex_musgrave);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index 2b8291ba8bb..310e82d2d6b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -56,12 +56,12 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat, bNode *node, bNodeExecDat
{
if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_noise", in, out);
+ return GPU_stack_link(mat, node, "node_tex_noise", in, out);
}
/* node type definition */
@@ -70,7 +70,6 @@ void register_node_type_sh_tex_noise(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_noise_in, sh_node_tex_noise_out);
node_type_init(&ntype, node_shader_init_tex_noise);
node_type_storage(&ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
index 436eeeefb4a..1c5f53132bd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
@@ -85,7 +85,6 @@ void register_node_type_sh_tex_pointdensity(void)
"Point Density",
NODE_CLASS_TEXTURE,
0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype,
sh_node_tex_pointdensity_in,
sh_node_tex_pointdensity_out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
index 4221c10fe50..821d4b41d09 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
@@ -61,7 +61,7 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat, bNode *node, bNodeExecData
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, "node_tex_sky", in, out);
+ return GPU_stack_link(mat, node, "node_tex_sky", in, out);
}
/* node type definition */
@@ -70,7 +70,6 @@ void register_node_type_sh_tex_sky(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_sky_in, sh_node_tex_sky_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_tex_sky);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index e5bf8f49717..059d6348473 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -58,15 +58,17 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat, bNode *node, bNodeExecD
{
if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
float coloring = tex->coloring;
+ float metric = tex->distance;
+ float feature = tex->feature;
- return GPU_stack_link(mat, "node_tex_voronoi", in, out, GPU_uniform(&coloring));
+ return GPU_stack_link(mat, node, "node_tex_voronoi", in, out, GPU_constant(&coloring), GPU_constant(&metric), GPU_constant(&feature));
}
static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
@@ -92,7 +94,6 @@ void register_node_type_sh_tex_voronoi(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_voronoi_in, sh_node_tex_voronoi_out);
node_type_init(&ntype, node_shader_init_tex_voronoi);
node_type_storage(&ntype, "NodeTexVoronoi", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
index c88183bd7dd..db33be2bcb7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -58,7 +58,7 @@ static int node_shader_gpu_tex_wave(GPUMaterial *mat, bNode *node, bNodeExecData
{
if (!in[0].link) {
in[0].link = GPU_attribute(CD_ORCO, "");
- GPU_link(mat, "generated_from_orco", in[0].link, &in[0].link);
+ GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
node_shader_gpu_tex_mapping(mat, node, in, out);
@@ -67,7 +67,7 @@ static int node_shader_gpu_tex_wave(GPUMaterial *mat, bNode *node, bNodeExecData
float wave_type = tex->wave_type;
float wave_profile = tex->wave_profile;
- return GPU_stack_link(mat, "node_tex_wave", in, out, GPU_uniform(&wave_type), GPU_uniform(&wave_profile));
+ return GPU_stack_link(mat, node, "node_tex_wave", in, out, GPU_constant(&wave_type), GPU_constant(&wave_profile));
}
/* node type definition */
@@ -76,7 +76,6 @@ void register_node_type_sh_tex_wave(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_tex_wave_in, sh_node_tex_wave_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_tex_wave);
diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c
deleted file mode 100644
index 737ec7d1c4b..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_texture.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * ***** 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) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/nodes/shader/nodes/node_shader_texture.c
- * \ingroup shdnodes
- */
-
-#include "DNA_texture_types.h"
-
-#include "node_shader_util.h"
-
-#include "GPU_material.h"
-
-/* **************** TEXTURE ******************** */
-static bNodeSocketTemplate sh_node_texture_in[] = {
- { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, /* no limit */
- { -1, 0, "" }
-};
-static bNodeSocketTemplate sh_node_texture_out[] = {
- { SOCK_FLOAT, 0, N_("Value"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- { SOCK_RGBA, 0, N_("Color"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- { SOCK_VECTOR, 0, N_("Normal"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- { -1, 0, "" }
-};
-
-static void node_shader_exec_texture(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
-{
- if (data && node->id) {
- ShadeInput *shi = ((ShaderCallData *)data)->shi;
- TexResult texres;
- bNodeSocket *sock_vector = node->inputs.first;
- float vec[3], nor[3] = {0.0f, 0.0f, 0.0f};
- int retval;
- short which_output = node->custom1;
-
- short thread = shi->thread;
-
- /* out: value, color, normal */
-
- /* we should find out if a normal as output is needed, for now we do all */
- texres.nor = nor;
- texres.tr = texres.tg = texres.tb = 0.0f;
-
- /* don't use in[0]->hasinput, see material node for explanation */
- if (sock_vector->link) {
- nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
-
- if (in[0]->datatype == NS_OSA_VECTORS) {
- float *fp = in[0]->data;
- retval = multitex_nodes((Tex *)node->id, vec, fp, fp + 3, shi->osatex, &texres, thread, which_output, NULL, NULL, NULL);
- }
- else if (in[0]->datatype == NS_OSA_VALUES) {
- const float *fp = in[0]->data;
- float dxt[3], dyt[3];
-
- dxt[0] = fp[0]; dxt[1] = dxt[2] = 0.0f;
- dyt[0] = fp[1]; dyt[1] = dyt[2] = 0.0f;
- retval = multitex_nodes((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres, thread, which_output, NULL, NULL, NULL);
- }
- else
- retval = multitex_nodes((Tex *)node->id, vec, NULL, NULL, 0, &texres, thread, which_output, NULL, NULL, NULL);
- }
- else {
- copy_v3_v3(vec, shi->lo);
- retval = multitex_nodes((Tex *)node->id, vec, NULL, NULL, 0, &texres, thread, which_output, NULL, NULL, NULL);
- }
-
- /* stupid exception */
- if ( ((Tex *)node->id)->type == TEX_STUCCI) {
- texres.tin = 0.5f + 0.7f * texres.nor[0];
- CLAMP(texres.tin, 0.0f, 1.0f);
- }
-
- /* intensity and color need some handling */
- if (texres.talpha)
- out[0]->vec[0] = texres.ta;
- else
- out[0]->vec[0] = texres.tin;
-
- if ((retval & TEX_RGB) == 0) {
- copy_v3_fl(out[1]->vec, out[0]->vec[0]);
- out[1]->vec[3] = 1.0f;
- }
- else {
- copy_v3_v3(out[1]->vec, &texres.tr);
- out[1]->vec[3] = 1.0f;
- }
-
- copy_v3_v3(out[2]->vec, nor);
-
- if (shi->do_preview) {
- BKE_node_preview_set_pixel(execdata->preview, out[1]->vec, shi->xs, shi->ys, shi->do_manage);
- }
-
- }
-}
-
-static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
-{
- Tex *tex = (Tex *)node->id;
-
- if (tex && tex->ima && (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)) {
- if (tex->type == TEX_IMAGE) {
- GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false);
- GPU_stack_link(mat, "texture_image", in, out, texlink);
- }
- else { /* TEX_ENVMAP */
- if (!in[0].link)
- in[0].link = GPU_uniform(in[0].vec);
- if (!GPU_material_use_world_space_shading(mat))
- GPU_link(mat, "direction_transform_m4v3", in[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[0].link);
- GPU_link(mat, "mtex_cube_map_refl_from_refldir",
- GPU_cube_map(tex->ima, &tex->iuser, false), in[0].link, &out[0].link, &out[1].link);
- GPU_link(mat, "color_to_normal", out[1].link, &out[2].link);
- }
-
- ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
- if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
- GPU_material_do_color_management(mat))
- {
- GPU_link(mat, "srgb_to_linearrgb", out[1].link, &out[1].link);
- }
- BKE_image_release_ibuf(tex->ima, ibuf, NULL);
-
- return true;
- }
-
- return false;
-}
-
-void register_node_type_sh_texture(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
- node_type_compatibility(&ntype, NODE_OLD_SHADING);
- node_type_socket_templates(&ntype, sh_node_texture_in, sh_node_texture_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_texture);
- node_type_gpu(&ntype, gpu_shader_texture);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c b/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c
index 67342e1e836..023f5417e22 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c
@@ -40,7 +40,6 @@ void register_node_type_sh_uvalongstroke(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_uvalongstroke_out);
node_type_init(&ntype, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
index 0f96cb45fe0..9da1056b47f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
@@ -47,7 +47,7 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat, bNode *node, bNodeExecData *U
NodeShaderUVMap *attr = node->storage;
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->uv_map);
- return GPU_stack_link(mat, "node_uvmap", in, out, mtface);
+ return GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
}
/* node type definition */
@@ -56,7 +56,6 @@ void register_node_type_sh_uvmap(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_uvmap_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_uvmap);
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
index 5a1f0bd472d..1a1d5658d97 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
@@ -65,11 +65,39 @@ static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
static int gpu_shader_valtorgb(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- float *array;
+ struct ColorBand *coba = node->storage;
+ float *array, layer;
int size;
- BKE_colorband_evaluate_table_rgba(node->storage, &array, &size);
- return GPU_stack_link(mat, "valtorgb", in, out, GPU_texture(size, array));
+ /* Common / easy case optimisation. */
+ if ((coba->tot <= 2) && (coba->color_mode == COLBAND_BLEND_RGB)) {
+ float mul_bias[2];
+ switch (coba->ipotype) {
+ case COLBAND_INTERP_LINEAR:
+ mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
+ mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
+ return GPU_stack_link(mat, node, "valtorgb_opti_linear", in, out, GPU_uniform(mul_bias),
+ GPU_uniform(&coba->data[0].r),
+ GPU_uniform(&coba->data[1].r));
+ case COLBAND_INTERP_CONSTANT:
+ mul_bias[1] = max_ff(coba->data[0].pos, coba->data[1].pos);
+ return GPU_stack_link(mat, node, "valtorgb_opti_constant", in, out, GPU_uniform(&mul_bias[1]),
+ GPU_uniform(&coba->data[0].r),
+ GPU_uniform(&coba->data[1].r));
+ default:
+ break;
+ }
+ }
+
+ BKE_colorband_evaluate_table_rgba(coba, &array, &size);
+ GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
+
+ if (coba->ipotype == COLBAND_INTERP_CONSTANT) {
+ return GPU_stack_link(mat, node, "valtorgb_nearest", in, out, tex, GPU_constant(&layer));
+ }
+ else {
+ return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_constant(&layer));
+ }
}
void register_node_type_sh_valtorgb(void)
@@ -77,7 +105,6 @@ void register_node_type_sh_valtorgb(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_valtorgb_in, sh_node_valtorgb_out);
node_type_init(&ntype, node_shader_init_valtorgb);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
@@ -110,9 +137,9 @@ static void node_shader_exec_rgbtobw(void *UNUSED(data), int UNUSED(thread), bNo
out[0]->vec[0] = IMB_colormanagement_get_luminance(col);
}
-static int gpu_shader_rgbtobw(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_rgbtobw(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "rgbtobw", in, out);
+ return GPU_stack_link(mat, node, "rgbtobw", in, out);
}
void register_node_type_sh_rgbtobw(void)
@@ -120,7 +147,6 @@ void register_node_type_sh_rgbtobw(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_rgbtobw_in, sh_node_rgbtobw_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_rgbtobw);
node_type_gpu(&ntype, gpu_shader_rgbtobw);
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.c b/source/blender/nodes/shader/nodes/node_shader_value.c
index ed57887bdf8..a143b0118e7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.c
+++ b/source/blender/nodes/shader/nodes/node_shader_value.c
@@ -38,10 +38,10 @@ static bNodeSocketTemplate sh_node_value_out[] = {
{ -1, 0, "" }
};
-static int gpu_shader_value(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static int gpu_shader_value(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- GPUNodeLink *vec = GPU_uniform(out[0].vec);
- return GPU_stack_link(mat, "set_value", in, out, vec);
+ GPUNodeLink *link = GPU_uniformbuffer_link_out(mat, node, out, 0);
+ return GPU_stack_link(mat, node, "set_value", in, out, link);
}
void register_node_type_sh_value(void)
@@ -49,7 +49,6 @@ void register_node_type_sh_value(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_value_out);
node_type_gpu(&ntype, gpu_shader_value);
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
index 02cff52e1a0..8087e1cab41 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
@@ -111,7 +111,7 @@ static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UN
case 2:
case 3:
case 4:
- GPU_stack_link(mat, names[node->custom1], in, out);
+ GPU_stack_link(mat, node, names[node->custom1], in, out);
break;
case 5:
if (in[0].hasinput || !in[1].hasinput) {
@@ -119,14 +119,14 @@ static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UN
GPUNodeStack tmp_in[2];
memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, names[node->custom1], tmp_in, out);
+ GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
}
else {
/* use only second item and terminator */
GPUNodeStack tmp_in[2];
memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, names[node->custom1], tmp_in, out);
+ GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
}
break;
default:
@@ -141,7 +141,6 @@ void register_node_type_sh_vect_math(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VECT_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_vect_math_in, sh_node_vect_math_out);
node_type_label(&ntype, node_vect_math_label);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
index af36e7cea22..bce96230403 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
@@ -52,68 +52,8 @@ static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = vect;
}
-static const float (* get_matrix_from_to(ShaderCallData *scd, short from, short to))[4]
+static void node_shader_exec_vect_transform(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **UNUSED(out))
{
- switch (from) {
- case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- switch (to) {
- case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return NULL;
- case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB);
- case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW);
- }
- break;
- case SHD_VECT_TRANSFORM_SPACE_WORLD:
- switch (to) {
- case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return NULL;
- case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return RE_render_current_get_matrix(RE_VIEW_MATRIX);
- case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OBINV);
- }
- break;
- case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- switch (to) {
- case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return NULL;
- case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return RE_render_current_get_matrix(RE_VIEWINV_MATRIX);
- case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV);
- }
- break;
- }
- return NULL;
-}
-
-static void node_shader_exec_vect_transform(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
-{
- float vec[4];
- const float (*mat)[4];
-
- if (data) {
- NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage;
-
- nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
-
- if (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT)
- vec[3] = 1.0f;
- else
- vec[3] = 0.0f;
-
- mat = get_matrix_from_to((ShaderCallData *)data, nodeprop->convert_from, nodeprop->convert_to);
- if (mat) {
- mul_m4_v4((float(*)[4])mat, vec);
- }
-
- if (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_NORMAL)
- normalize_v3(vec);
-
- copy_v4_v4(out[0]->vec, vec);
- }
}
static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
@@ -161,32 +101,25 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, bNode *node, bNodeExecDat
const char *ptransform = "point_transform_m4v3";
const char *func_name = 0;
- bool new_shading = GPU_material_use_new_shading_nodes(mat);
-
NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage;
if (in[0].hasinput)
inputlink = in[0].link;
else
- inputlink = GPU_uniform(in[0].vec);
+ inputlink = GPU_constant(in[0].vec);
fromto = get_gpulink_matrix_from_to(nodeprop->convert_from, nodeprop->convert_to);
func_name = (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT) ? ptransform : vtransform;
if (fromto) {
- if (new_shading) {
- /* For cycles we have inverted Z */
- /* TODO: pass here the correct matrices */
- if (nodeprop->convert_from == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_to != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
- GPU_link(mat, "invert_z", inputlink, &inputlink);
- }
- GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
- if (nodeprop->convert_to == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_from != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
- GPU_link(mat, "invert_z", out[0].link, &out[0].link);
- }
+ /* For cycles we have inverted Z */
+ /* TODO: pass here the correct matrices */
+ if (nodeprop->convert_from == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_to != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
+ GPU_link(mat, "invert_z", inputlink, &inputlink);
}
- else {
- GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
+ GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
+ if (nodeprop->convert_to == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_from != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
+ GPU_link(mat, "invert_z", out[0].link, &out[0].link);
}
}
else
@@ -203,7 +136,6 @@ void register_node_type_sh_vect_transform(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_init(&ntype, node_shader_init_vect_transform);
node_type_socket_templates(&ntype, sh_node_vect_transform_in, sh_node_vect_transform_out);
node_type_storage(&ntype, "NodeShaderVectTransform", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c
index 073bc3110f6..2a40d98baf9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c
@@ -50,6 +50,7 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat, bNode *node, bNodeEx
{
if (node->custom1 == SHD_SPACE_TANGENT) {
return GPU_stack_link(mat,
+ node,
"node_vector_displacement_tangent",
in,
out,
@@ -59,10 +60,10 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat, bNode *node, bNodeEx
GPU_builtin(GPU_VIEW_MATRIX));
}
else if (node->custom1 == SHD_SPACE_OBJECT) {
- return GPU_stack_link(mat, "node_vector_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX));
+ return GPU_stack_link(mat, node, "node_vector_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX));
}
else {
- return GPU_stack_link(mat, "node_vector_displacement_world", in, out);
+ return GPU_stack_link(mat, node, "node_vector_displacement_world", in, out);
}
}
@@ -72,7 +73,6 @@ void register_node_type_sh_vector_displacement(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_vector_displacement_in, sh_node_vector_displacement_out);
node_type_storage(&ntype, "", NULL, NULL);
node_type_init(&ntype, node_shader_init_vector_displacement);
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
index 4861871e8d3..d0ba43d1a15 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
@@ -40,9 +40,9 @@ static bNodeSocketTemplate sh_node_volume_absorption_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_volume_absorption(GPUMaterial *UNUSED(mat), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *UNUSED(in), GPUNodeStack *UNUSED(out))
+static int node_shader_gpu_volume_absorption(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return false;
+ return GPU_stack_link(mat, node, "node_volume_absorption", in, out);
}
/* node type definition */
@@ -51,7 +51,6 @@ void register_node_type_sh_volume_absorption(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_volume_absorption_in, sh_node_volume_absorption_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
index 8aaf84dc2f0..cf458ac8f51 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
@@ -62,9 +62,89 @@ static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode *
}
}
-static int node_shader_gpu_volume_principled(GPUMaterial *UNUSED(mat), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *UNUSED(in), GPUNodeStack *UNUSED(out))
+static void node_shader_gpu_volume_attribute(GPUMaterial *mat, const char *name, GPUNodeLink **outcol, GPUNodeLink **outvec, GPUNodeLink **outf)
{
- return false;
+ if (strcmp(name, "density") == 0) {
+ GPU_link(mat, "node_attribute_volume_density",
+ GPU_builtin(GPU_VOLUME_DENSITY),
+ outcol, outvec, outf);
+ }
+ else if (strcmp(name, "color") == 0) {
+ GPU_link(mat, "node_attribute_volume_color",
+ GPU_builtin(GPU_VOLUME_DENSITY),
+ outcol, outvec, outf);
+ }
+ else if (strcmp(name, "flame") == 0) {
+ GPU_link(mat, "node_attribute_volume_flame",
+ GPU_builtin(GPU_VOLUME_FLAME),
+ outcol, outvec, outf);
+ }
+ else if (strcmp(name, "temperature") == 0) {
+ GPU_link(mat, "node_attribute_volume_temperature",
+ GPU_builtin(GPU_VOLUME_FLAME),
+ GPU_builtin(GPU_VOLUME_TEMPERATURE),
+ outcol, outvec, outf);
+ }
+ else {
+ *outcol = *outvec = *outf = NULL;
+ }
+}
+
+static int node_shader_gpu_volume_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ /* Test if blackbody intensity is enabled. */
+ bool use_blackbody = (in[8].link || in[8].vec[0] != 0.0f);
+
+ /* Get volume attributes. */
+ GPUNodeLink *density = NULL, *color = NULL, *temperature = NULL;
+
+ for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ if (sock->typeinfo->type != SOCK_STRING) {
+ continue;
+ }
+
+ bNodeSocketValueString *value = sock->default_value;
+ GPUNodeLink *outcol, *outvec, *outf;
+
+ if (STREQ(sock->name, "Density Attribute")) {
+ node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &density);
+ }
+ else if (STREQ(sock->name, "Color Attribute")) {
+ node_shader_gpu_volume_attribute(mat, value->value, &color, &outvec, &outf);
+ }
+ else if (use_blackbody && STREQ(sock->name, "Temperature Attribute")) {
+ node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &temperature);
+ }
+ }
+
+ /* Default values if attributes not found. */
+ if (!density) {
+ static float one = 1.0f;
+ density = GPU_constant(&one);
+ }
+ if (!color) {
+ static float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ color = GPU_constant(white);
+ }
+ if (!temperature) {
+ static float one = 1.0f;
+ temperature = GPU_constant(&one);
+ }
+
+ /* Create blackbody spectrum. */
+ const int size = CM_TABLE + 1;
+ float *data, layer;
+ if (use_blackbody) {
+ data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+ blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
+ }
+ else {
+ data = MEM_callocN(sizeof(float) * size * 4, "blackbody black");
+ }
+ GPUNodeLink *spectrummap = GPU_color_band(mat, size, data, &layer);
+
+ return GPU_stack_link(mat, node, "node_volume_principled", in, out, density, color, temperature, spectrummap,
+ GPU_constant(&layer));
}
/* node type definition */
@@ -73,7 +153,6 @@ void register_node_type_sh_volume_principled(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_volume_principled_in, sh_node_volume_principled_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, node_shader_init_volume_principled);
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
index 33180e8ecf1..0f97d08803a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
@@ -41,9 +41,9 @@ static bNodeSocketTemplate sh_node_volume_scatter_out[] = {
{ -1, 0, "" }
};
-static int node_shader_gpu_volume_scatter(GPUMaterial *UNUSED(mat), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *UNUSED(in), GPUNodeStack *UNUSED(out))
+static int node_shader_gpu_volume_scatter(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return false;
+ return GPU_stack_link(mat, node, "node_volume_scatter", in, out);
}
/* node type definition */
@@ -52,7 +52,6 @@ void register_node_type_sh_volume_scatter(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_volume_scatter_in, sh_node_volume_scatter_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_wavelength.c b/source/blender/nodes/shader/nodes/node_shader_wavelength.c
index f903e314edf..edc4333c000 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wavelength.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wavelength.c
@@ -44,7 +44,6 @@ void register_node_type_sh_wavelength(void)
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_socket_templates(&ntype, sh_node_wavelength_in, sh_node_wavelength_out);
node_type_init(&ntype, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.c b/source/blender/nodes/shader/nodes/node_shader_wireframe.c
index 0b9f3ac347a..3592f98d81d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wireframe.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.c
@@ -38,16 +38,27 @@ static bNodeSocketTemplate sh_node_wireframe_out[] = {
{ -1, 0, "" }
};
+static int node_shader_gpu_wireframe(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ /* node->custom1 is use_pixel_size */
+ if (node->custom1) {
+ return GPU_stack_link(mat, node, "node_wireframe_screenspace", in, out, GPU_builtin(GPU_BARYCENTRIC_TEXCO));
+ }
+ else {
+ return GPU_stack_link(mat, node, "node_wireframe", in, out, GPU_builtin(GPU_BARYCENTRIC_TEXCO), GPU_builtin(GPU_BARYCENTRIC_DIST));
+ }
+}
+
/* node type definition */
void register_node_type_sh_wireframe(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_wireframe_in, sh_node_wireframe_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
+ node_type_gpu(&ntype, node_shader_gpu_wireframe);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index abaaf338ed7..6711e644d44 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -53,44 +53,22 @@
#include "NOD_texture.h"
#include "node_texture_util.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#include "RE_shader_ext.h"
-
-static void texture_get_from_context(const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, ID **r_id, ID **r_from)
+static void texture_get_from_context(
+ const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, ID **r_id, ID **r_from)
{
SpaceNode *snode = CTX_wm_space_node(C);
Scene *scene = CTX_data_scene(C);
- Object *ob = OBACT;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
Tex *tx = NULL;
- if (snode->texfrom == SNODE_TEX_OBJECT) {
- if (ob) {
- tx = give_current_object_texture(ob);
- if (tx) {
- if (ob->type == OB_LAMP)
- *r_from = (ID *)ob->data;
- else
- *r_from = (ID *)give_current_material(ob, ob->actcol);
-
- /* from is not set fully for material nodes, should be ID + Node then */
- *r_id = &tx->id;
- *r_ntree = tx->nodetree;
- }
- }
- }
- else if (snode->texfrom == SNODE_TEX_WORLD) {
- if (scene->world) {
- *r_from = (ID *)scene->world;
- tx = give_current_world_texture(scene->world);
- if (tx) {
- *r_id = &tx->id;
- *r_ntree = tx->nodetree;
- }
- }
- }
- else if (snode->texfrom == SNODE_TEX_BRUSH) {
+ if (snode->texfrom == SNODE_TEX_BRUSH) {
struct Brush *brush = NULL;
if (ob && (ob->mode & OB_MODE_SCULPT))
@@ -108,7 +86,7 @@ static void texture_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tr
}
}
else if (snode->texfrom == SNODE_TEX_LINESTYLE) {
- FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene);
+ FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(view_layer);
if (linestyle) {
*r_from = (ID *)linestyle;
tx = give_current_linestyle_texture(linestyle);
@@ -186,7 +164,7 @@ void register_node_tree_type_tex(void)
tt->type = NTREE_TEXTURE;
strcpy(tt->idname, "TextureNodeTree");
- strcpy(tt->ui_name, "Texture");
+ strcpy(tt->ui_name, "Texture Node Editor");
tt->ui_icon = 0; /* defined in drawnode.c */
strcpy(tt->ui_description, "Texture nodes");
@@ -321,7 +299,6 @@ int ntreeTexExecTree(
short which_output,
int cfra,
int preview,
- ShadeInput *shi,
MTex *mtex)
{
TexCallData data;
@@ -336,12 +313,11 @@ int ntreeTexExecTree(
data.osatex = osatex;
data.target = texres;
data.do_preview = preview;
- data.do_manage = (shi) ? shi->do_manage : true;
+ data.do_manage = true;
data.thread = thread;
data.which_output = which_output;
data.cfra = cfra;
data.mtex = mtex;
- data.shi = shi;
/* ensure execdata is only initialized once */
if (!exec) {
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index 6b9f29475b5..ff2e3d20155 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -124,7 +124,6 @@ void params_from_cdata(TexParams *out, TexCallData *in)
out->previewco = in->co;
out->osatex = in->osatex;
out->cfra = in->cfra;
- out->shi = in->shi;
out->mtex = in->mtex;
}
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 389be543d7e..6606915c3f7 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -61,7 +61,6 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_texture.h"
-#include "BKE_library.h"
#include "node_util.h"
#include "NOD_texture.h"
@@ -87,7 +86,6 @@ typedef struct TexCallData {
short which_output;
int cfra;
- ShadeInput *shi;
MTex *mtex;
} TexCallData;
@@ -100,7 +98,6 @@ typedef struct TexParams {
/* optional. we don't really want these here, but image
* textures need to do mapping & color correction */
- ShadeInput *shi;
MTex *mtex;
} TexParams;
diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c
index d6881ca41f0..4fccab27b24 100644
--- a/source/blender/nodes/texture/nodes/node_texture_image.c
+++ b/source/blender/nodes/texture/nodes/node_texture_image.c
@@ -93,8 +93,8 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
ImageUser *iuser = MEM_callocN(sizeof(ImageUser), "node image user");
node->storage = iuser;
iuser->sfra = 1;
- iuser->fie_ima = 2;
iuser->ok = 1;
+ iuser->flag |= IMA_ANIM_ALWAYS;
}
void register_node_type_tex_image(void)
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index 76f5e7d5c5b..47f4683549f 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -69,7 +69,7 @@ static void do_proc(float *result, TexParams *p, const float col1[4], const floa
texres.nor = NULL;
textype = multitex_nodes(tex, p->co, p->dxt, p->dyt, p->osatex,
- &texres, thread, 0, p->shi, p->mtex, NULL);
+ &texres, thread, 0, p->mtex, NULL);
if (is_normal)
return;
diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c
index 57703e3a044..ff405cc9f3e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_texture.c
+++ b/source/blender/nodes/texture/nodes/node_texture_texture.c
@@ -78,7 +78,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
texres.nor = nor;
textype = multitex_nodes(nodetex, co, dxt, dyt, p->osatex,
- &texres, thread, 0, p->shi, p->mtex, NULL);
+ &texres, thread, 0, p->mtex, NULL);
if (textype & TEX_RGB) {
copy_v4_v4(out, &texres.tr);
diff --git a/source/blender/physics/BPH_mass_spring.h b/source/blender/physics/BPH_mass_spring.h
index c650d83c927..f1eb049dd52 100644
--- a/source/blender/physics/BPH_mass_spring.h
+++ b/source/blender/physics/BPH_mass_spring.h
@@ -40,6 +40,7 @@ struct Implicit_Data;
struct Object;
struct ClothModifierData;
struct ListBase;
+struct Depsgraph;
struct VoxelData;
typedef enum eMassSpringSolverStatus {
@@ -55,11 +56,9 @@ int BPH_mass_spring_solver_numvert(struct Implicit_Data *id);
int BPH_cloth_solver_init(struct Object *ob, struct ClothModifierData *clmd);
void BPH_cloth_solver_free(struct ClothModifierData *clmd);
-int BPH_cloth_solve(struct Object *ob, float frame, struct ClothModifierData *clmd, struct ListBase *effectors);
+int BPH_cloth_solve(struct Depsgraph *depsgraph, struct Object *ob, float frame, struct ClothModifierData *clmd, struct ListBase *effectors);
void BKE_cloth_solver_set_positions(struct ClothModifierData *clmd);
-bool BPH_cloth_solver_get_texture_data(struct Object *ob, struct ClothModifierData *clmd, struct VoxelData *vd);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/physics/CMakeLists.txt b/source/blender/physics/CMakeLists.txt
index 0a4ff3fe0f0..b8663a384a7 100644
--- a/source/blender/physics/CMakeLists.txt
+++ b/source/blender/physics/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
intern
../blenlib
../blenkernel
+ ../depsgraph
../imbuf
../makesdna
../../../intern/guardedalloc
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 451959766cb..d43ce37cbfe 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -51,6 +51,9 @@ extern "C" {
#include "BPH_mass_spring.h"
#include "implicit.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
static float I3[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
/* Number of off-diagonal non-zero matrix blocks.
@@ -64,7 +67,7 @@ static int cloth_count_nondiag_blocks(Cloth *cloth)
for (link = cloth->springs; link; link = link->next) {
ClothSpring *spring = (ClothSpring *)link->link;
switch (spring->type) {
- case CLOTH_SPRING_TYPE_BENDING_ANG:
+ case CLOTH_SPRING_TYPE_BENDING_HAIR:
/* angular bending combines 3 vertices */
nondiag += 3;
break;
@@ -338,38 +341,75 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
Cloth *cloth = clmd->clothObject;
ClothSimSettings *parms = clmd->sim_parms;
Implicit_Data *data = cloth->implicit;
-
- bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
+ bool using_angular = parms->bending_model == CLOTH_BENDING_ANGULAR;
+ bool resist_compress = (parms->flags & CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS) && !using_angular;
s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
- // calculate force of structural + shear springs
- if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
-#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
+ /* Calculate force of bending springs. */
+ if ((s->type & CLOTH_SPRING_TYPE_BENDING) && using_angular) {
+#ifdef CLOTH_FORCE_SPRING_BEND
float k, scaling;
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
- scaling = parms->structural + s->stiffness * fabsf(parms->max_struct - parms->structural);
- k = scaling / (parms->avg_spring_len + FLT_EPSILON);
+ scaling = parms->bending + s->ang_stiffness * fabsf(parms->max_bend - parms->bending);
+ k = scaling * s->restlen * 0.1f; /* Multiplying by 0.1, just to scale the forces to more reasonable values. */
+
+ BPH_mass_spring_force_spring_angular(data, s->ij, s->kl, s->pa, s->pb, s->la, s->lb,
+ s->restang, k, parms->bending_damping);
+#endif
+ }
+
+ /* Calculate force of structural + shear springs. */
+ if (s->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SEWING)) {
+#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
+ float k_tension, scaling_tension;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ scaling_tension = parms->tension + s->lin_stiffness * fabsf(parms->max_tension - parms->tension);
+ k_tension = scaling_tension / (parms->avg_spring_len + FLT_EPSILON);
if (s->type & CLOTH_SPRING_TYPE_SEWING) {
// TODO: verify, half verified (couldn't see error)
// sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing);
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen,
+ k_tension, parms->tension_damp,
+ 0.0f, 0.0f, false, false, parms->max_sewing);
}
else {
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f);
+ float k_compression, scaling_compression;
+ scaling_compression = parms->compression + s->lin_stiffness * fabsf(parms->max_compression - parms->compression);
+ k_compression = scaling_compression / (parms->avg_spring_len + FLT_EPSILON);
+
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen,
+ k_tension, parms->tension_damp,
+ k_compression, parms->compression_damp,
+ resist_compress, using_angular, 0.0f);
}
#endif
}
+ else if (s->type & CLOTH_SPRING_TYPE_SHEAR) {
+#ifdef CLOTH_FORCE_SPRING_SHEAR
+ float k, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ scaling = parms->shear + s->lin_stiffness * fabsf(parms->max_shear - parms->shear);
+ k = scaling / (parms->avg_spring_len + FLT_EPSILON);
+
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->shear_damp,
+ 0.0f, 0.0f, resist_compress, false, 0.0f);
+#endif
+ }
else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */
#ifdef CLOTH_FORCE_SPRING_BEND
float kb, cb, scaling;
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
- scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending);
+ scaling = parms->bending + s->lin_stiffness * fabsf(parms->max_bend - parms->bending);
kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
// Fix for [#45084] for cloth stiffness must have cb proportional to kb
@@ -378,7 +418,7 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb);
#endif
}
- else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
+ else if (s->type & CLOTH_SPRING_TYPE_BENDING_HAIR) {
#ifdef CLOTH_FORCE_SPRING_BEND
float kb, cb, scaling;
@@ -388,14 +428,14 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
* this is crap, but needed due to cloth/hair mixing ...
* max_bend factor is not even used for hair, so ...
*/
- scaling = s->stiffness * parms->bending;
+ scaling = s->lin_stiffness * parms->bending;
kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
// Fix for [#45084] for cloth stiffness must have cb proportional to kb
cb = kb * parms->bending_damping;
/* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
- BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
+ BPH_mass_spring_force_spring_bending_hair(data, s->ij, s->kl, s->mn, s->target, kb, cb);
#if 0
{
@@ -433,7 +473,7 @@ static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax
}
}
-static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time)
+static void cloth_calc_force(Scene *scene, ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time)
{
/* Collect forces and derivatives: F, dFdX, dFdV */
Cloth *cloth = clmd->clothObject;
@@ -447,9 +487,9 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
#ifdef CLOTH_FORCE_GRAVITY
/* global acceleration (gravitation) */
- if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
/* scale gravity force */
- mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
+ mul_v3_v3fl(gravity, scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
}
vert = cloth->verts;
@@ -487,8 +527,8 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
EffectedPoint epoint;
BPH_mass_spring_get_motion_state(data, i, x, v);
- pd_point_from_loc(clmd->scene, x, v, i, &epoint);
- pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
+ pd_point_from_loc(scene, x, v, i, &epoint);
+ BKE_effectors_apply(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
}
for (i = 0; i < cloth->tri_num; i++) {
@@ -844,87 +884,41 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
}
#endif
-/* old collision stuff for cloth, use for continuity
- * until a good replacement is ready
- */
-static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, ListBase *effectors, float frame, float step, float dt)
+static void cloth_solve_collisions(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
{
Cloth *cloth = clmd->clothObject;
Implicit_Data *id = cloth->implicit;
ClothVertex *verts = cloth->verts;
int mvert_num = cloth->mvert_num;
- const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
-
- bool do_extra_solve;
+ const float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
int i;
- if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED))
+ if (!(clmd->coll_parms->flags & (CLOTH_COLLSETTINGS_FLAG_ENABLED | CLOTH_COLLSETTINGS_FLAG_SELF)))
return;
+
if (!clmd->clothObject->bvhtree)
return;
- // update verts to current positions
+ BPH_mass_spring_solve_positions(id, dt);
+
+ /* Update verts to current positions. */
for (i = 0; i < mvert_num; i++) {
BPH_mass_spring_get_new_position(id, i, verts[i].tx);
sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
- copy_v3_v3(verts[i].v, verts[i].tv);
+ zero_v3(verts[i].dcvel);
}
-#if 0 /* unused */
- for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) {
- copy_v3_v3(initial_cos[i], cv->tx);
- }
-#endif
-
- // call collision function
- // TODO: check if "step" or "step+dt" is correct - dg
- do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale);
-
- // copy corrected positions back to simulation
- for (i = 0; i < mvert_num; i++) {
- float curx[3];
- BPH_mass_spring_get_position(id, i, curx);
- // correct velocity again, just to be sure we had to change it due to adaptive collisions
- sub_v3_v3v3(verts[i].tv, verts[i].tx, curx);
- }
-
- if (do_extra_solve) {
-// cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
-
+ if (cloth_bvh_collision(depsgraph, ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale)) {
for (i = 0; i < mvert_num; i++) {
-
- float newv[3];
-
- if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED))
+ if ((clmd->sim_parms->vgroup_mass > 0) && (verts[i].flags & CLOTH_VERT_FLAG_PINNED))
continue;
- BPH_mass_spring_set_new_position(id, i, verts[i].tx);
- mul_v3_v3fl(newv, verts[i].tv, spf);
- BPH_mass_spring_set_new_velocity(id, i, newv);
+ BPH_mass_spring_get_new_velocity(id, i, verts[i].tv);
+ madd_v3_v3fl(verts[i].tv, verts[i].dcvel, time_multiplier);
+ BPH_mass_spring_set_new_velocity(id, i, verts[i].tv);
}
}
-
- // X = Xnew;
- BPH_mass_spring_apply_result(id);
-
- if (do_extra_solve) {
- ImplicitSolverResult result;
-
- /* initialize forces to zero */
- BPH_mass_spring_clear_forces(id);
-
- // calculate forces
- cloth_calc_force(clmd, frame, effectors, step);
-
- // calculate new velocity and position
- BPH_mass_spring_solve_velocities(id, dt, &result);
-// cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
-
- /* note: positions are advanced only once in the main solver step! */
-
- BPH_mass_spring_apply_result(id);
- }
}
static void cloth_clear_result(ClothModifierData *clmd)
@@ -937,7 +931,7 @@ static void cloth_clear_result(ClothModifierData *clmd)
sres->avg_iterations = 0.0f;
}
-static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, int steps)
+static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, float dt)
{
ClothSolverResult *sres = clmd->solver_result;
@@ -946,33 +940,34 @@ static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *r
if (result->status == BPH_SOLVER_SUCCESS) {
sres->min_error = min_ff(sres->min_error, result->error);
sres->max_error = max_ff(sres->max_error, result->error);
- sres->avg_error += result->error / (float)steps;
+ sres->avg_error += result->error * dt;
}
sres->min_iterations = min_ii(sres->min_iterations, result->iterations);
sres->max_iterations = max_ii(sres->max_iterations, result->iterations);
- sres->avg_iterations += (float)result->iterations / (float)steps;
+ sres->avg_iterations += (float)result->iterations * dt;
}
else {
/* error only makes sense for successful iterations */
if (result->status == BPH_SOLVER_SUCCESS) {
sres->min_error = sres->max_error = result->error;
- sres->avg_error += result->error / (float)steps;
+ sres->avg_error += result->error * dt;
}
sres->min_iterations = sres->max_iterations = result->iterations;
- sres->avg_iterations += (float)result->iterations / (float)steps;
+ sres->avg_iterations += (float)result->iterations * dt;
}
sres->status |= result->status;
}
-int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
+int BPH_cloth_solve(Depsgraph *depsgraph, Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
{
/* Hair currently is a cloth sim in disguise ...
* Collision detection and volumetrics work differently then.
* Bad design, TODO
*/
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
const bool is_hair = (clmd->hairdata != NULL);
unsigned int i=0;
@@ -980,7 +975,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
Cloth *cloth = clmd->clothObject;
ClothVertex *verts = cloth->verts/*, *cv*/;
unsigned int mvert_num = cloth->mvert_num;
- float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
+ float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale;
Implicit_Data *id = cloth->implicit;
ColliderContacts *contacts = NULL;
int totcolliders = 0;
@@ -991,7 +986,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result");
cloth_clear_result(clmd);
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
+ if (clmd->sim_parms->vgroup_mass > 0) { /* Do goal stuff. */
for (i = 0; i < mvert_num; i++) {
// update velocities with constrained velocities from pinned verts
if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
@@ -1008,16 +1003,10 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
while (step < tf) {
ImplicitSolverResult result;
- /* copy velocities for collision */
- for (i = 0; i < mvert_num; i++) {
- BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
- copy_v3_v3(verts[i].v, verts[i].tv);
- }
-
if (is_hair) {
/* determine contact points */
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
- cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders);
+ cloth_find_point_contacts(depsgraph, ob, clmd, 0.0f, tf, &contacts, &totcolliders);
}
/* setup vertex constraints for pinned vertices and contacts */
@@ -1031,39 +1020,28 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
/* initialize forces to zero */
BPH_mass_spring_clear_forces(id);
- // damping velocity for artistic reasons
- // this is a bad way to do it, should be removed imo - lukas_t
- if (clmd->sim_parms->vel_damping != 1.0f) {
- for (i = 0; i < mvert_num; i++) {
- float v[3];
- BPH_mass_spring_get_motion_state(id, i, NULL, v);
- mul_v3_fl(v, clmd->sim_parms->vel_damping);
- BPH_mass_spring_set_velocity(id, i, v);
- }
- }
-
// calculate forces
- cloth_calc_force(clmd, frame, effectors, step);
+ cloth_calc_force(scene, clmd, frame, effectors, step);
// calculate new velocity and position
BPH_mass_spring_solve_velocities(id, dt, &result);
- cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
+ cloth_record_result(clmd, &result, dt);
+
+ /* Calculate collision impulses. */
+ if (!is_hair) {
+ cloth_solve_collisions(depsgraph, ob, clmd, step, dt);
+ }
if (is_hair) {
cloth_continuum_step(clmd, dt);
}
BPH_mass_spring_solve_positions(id, dt);
-
- if (!is_hair) {
- cloth_collision_solve_extra(ob, clmd, effectors, frame, step, dt);
- }
-
BPH_mass_spring_apply_result(id);
/* move pinned verts to correct position */
for (i = 0; i < mvert_num; i++) {
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
+ if (clmd->sim_parms->vgroup_mass > 0) {
if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
float x[3];
/* divide by time_scale to prevent pinned vertices' delta locations from being multiplied */
@@ -1091,24 +1069,3 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
return 1;
}
-
-bool BPH_cloth_solver_get_texture_data(Object *UNUSED(ob), ClothModifierData *clmd, VoxelData *vd)
-{
- Cloth *cloth = clmd->clothObject;
- HairGrid *grid;
- float gmin[3], gmax[3];
-
- if (!clmd->clothObject || !clmd->clothObject->implicit)
- return false;
-
- hair_get_boundbox(clmd, gmin, gmax);
-
- grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
- cloth_continuum_fill_grid(grid, cloth);
-
- BPH_hair_volume_get_texture_data(grid, vd);
-
- BPH_hair_volume_free_vertex_grid(grid);
-
- return true;
-}
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index cd869046cc1..d2d43882a2d 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -1054,7 +1054,7 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
}
/* gather colliders */
- colliders = get_collider_cache(clmd->scene, NULL, NULL);
+ colliders = BKE_collider_cache_create(depsgraph, NULL, NULL);
if (colliders && collfac > 0.0f) {
for (col = colliders->first; col; col = col->next) {
MVert *loc0 = col->collmd->x;
@@ -1087,7 +1087,7 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
}
}
}
- free_collider_cache(&colliders);
+ BKE_collider_cache_free(&colliders);
/* divide velocity with density */
for (i = 0; i < size; i++) {
@@ -1099,56 +1099,3 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
return collgrid;
}
#endif
-
-bool BPH_hair_volume_get_texture_data(HairGrid *grid, VoxelData *vd)
-{
- int totres, i;
- int depth;
-
- vd->resol[0] = grid->res[0];
- vd->resol[1] = grid->res[1];
- vd->resol[2] = grid->res[2];
-
- totres = hair_grid_size(grid->res);
-
- if (vd->hair_type == TEX_VD_HAIRVELOCITY) {
- depth = 4;
- vd->data_type = TEX_VD_RGBA_PREMUL;
- }
- else {
- depth = 1;
- vd->data_type = TEX_VD_INTENSITY;
- }
-
- if (totres > 0) {
- vd->dataset = (float *)MEM_mapallocN(sizeof(float) * depth * (totres), "hair volume texture data");
-
- for (i = 0; i < totres; ++i) {
- switch (vd->hair_type) {
- case TEX_VD_HAIRDENSITY:
- vd->dataset[i] = grid->verts[i].density;
- break;
-
- case TEX_VD_HAIRRESTDENSITY:
- vd->dataset[i] = 0.0f; // TODO
- break;
-
- case TEX_VD_HAIRVELOCITY: {
- vd->dataset[i + 0*totres] = grid->verts[i].velocity[0];
- vd->dataset[i + 1*totres] = grid->verts[i].velocity[1];
- vd->dataset[i + 2*totres] = grid->verts[i].velocity[2];
- vd->dataset[i + 3*totres] = len_v3(grid->verts[i].velocity);
- break;
- }
- case TEX_VD_HAIRENERGY:
- vd->dataset[i] = 0.0f; // TODO
- break;
- }
- }
- }
- else {
- vd->dataset = NULL;
- }
-
- return true;
-}
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index e2ac6c306b6..f99812a8aa9 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -50,6 +50,7 @@ extern "C" {
#define CLOTH_FORCE_GRAVITY
#define CLOTH_FORCE_DRAG
#define CLOTH_FORCE_SPRING_STRUCTURAL
+#define CLOTH_FORCE_SPRING_SHEAR
#define CLOTH_FORCE_SPRING_BEND
#define CLOTH_FORCE_SPRING_GOAL
#define CLOTH_FORCE_EFFECTORS
@@ -114,11 +115,16 @@ void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2,
void BPH_mass_spring_force_vertex_wind(struct Implicit_Data *data, int v, float radius, const float (*winvec)[3]);
/* Linear spring force between two points */
bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int j, float restlen,
- float stiffness, float damping, bool no_compress, float clamp_force);
+ float stiffness_tension, float damping_tension,
+ float stiffness_compression, float damping_compression,
+ bool resist_compress, bool new_compress, float clamp_force);
+/* Angular spring force between two polygons */
+bool BPH_mass_spring_force_spring_angular(struct Implicit_Data *data, int i, int j, int *i_a, int *i_b, int len_a, int len_b,
+ float restang, float stiffness, float damping);
/* Bending force, forming a triangle at the base of two structural springs */
bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen, float kb, float cb);
/* Angular bending force based on local target vectors */
-bool BPH_mass_spring_force_spring_bending_angular(struct Implicit_Data *data, int i, int j, int k,
+bool BPH_mass_spring_force_spring_bending_hair(struct Implicit_Data *data, int i, int j, int k,
const float target[3], float stiffness, float damping);
/* Global goal spring */
bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
@@ -171,8 +177,6 @@ void BPH_hair_volume_vertex_grid_forces(struct HairGrid *grid, const float x[3],
float smoothfac, float pressurefac, float minpressure,
float f[3], float dfdx[3][3], float dfdv[3][3]);
-bool BPH_hair_volume_get_texture_data(struct HairGrid *grid, struct VoxelData *vd);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 45030524566..20f4a9f3163 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -461,6 +461,13 @@ DO_INLINE void muladd_fmatrix_fvector(float to[3], float matrix[3][3], float fro
to[2] += dot_v3v3(matrix[2], from);
}
+DO_INLINE void muladd_fmatrixT_fvector(float to[3], float matrix[3][3], float from[3])
+{
+ to[0] += matrix[0][0] * from[0] + matrix[1][0] * from[1] + matrix[2][0] * from[2];
+ to[1] += matrix[0][1] * from[0] + matrix[1][1] * from[1] + matrix[2][1] * from[2];
+ to[2] += matrix[0][2] * from[0] + matrix[1][2] * from[1] + matrix[2][2] * from[2];
+}
+
BLI_INLINE void outerproduct(float r[3][3], const float a[3], const float b[3])
{
mul_v3_v3fl(r[0], a, b[0]);
@@ -604,7 +611,9 @@ DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector
#pragma omp section
{
for (i = from[0].vcount; i < from[0].vcount+from[0].scount; i++) {
- muladd_fmatrix_fvector(to[from[i].c], from[i].m, fLongVector[from[i].r]);
+ /* This is the lower triangle of the sparse matrix,
+ * therefore multiplication occurs with transposed submatrices. */
+ muladd_fmatrixT_fvector(to[from[i].c], from[i].m, fLongVector[from[i].r]);
}
}
#pragma omp section
@@ -617,8 +626,6 @@ DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector
add_lfvector_lfvector(to, to, temp, from[0].vcount);
del_lfvector(temp);
-
-
}
/* SPARSE SYMMETRIC sub big matrix with big matrix*/
@@ -1585,9 +1592,13 @@ BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3]
}
bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, float restlen,
- float stiffness, float damping, bool no_compress, float clamp_force)
+ float stiffness_tension, float damping_tension,
+ float stiffness_compression, float damping_compression,
+ bool resist_compress, bool new_compress, float clamp_force)
{
float extent[3], length, dir[3], vel[3];
+ float f[3], dfdx[3][3], dfdv[3][3];
+ float damping = 0;
// calculate elonglation
spring_length(data, i, j, extent, dir, &length, vel);
@@ -1595,29 +1606,41 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
/* This code computes not only the force, but also its derivative.
Zero derivative effectively disables the spring for the implicit solver.
Thus length > restlen makes cloth unconstrained at the start of simulation. */
- if ((length >= restlen && length > 0) || no_compress) {
- float stretch_force, f[3], dfdx[3][3], dfdv[3][3];
+ if ((length >= restlen && length > 0) || resist_compress) {
+ float stretch_force;
+
+ damping = damping_tension;
- stretch_force = stiffness * (length - restlen);
+ stretch_force = stiffness_tension * (length - restlen);
if (clamp_force > 0.0f && stretch_force > clamp_force) {
stretch_force = clamp_force;
}
mul_v3_v3fl(f, dir, stretch_force);
- // Ascher & Boxman, p.21: Damping only during elonglation
- // something wrong with it...
- madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
+ dfdx_spring(dfdx, dir, length, restlen, stiffness_tension);
+ }
+ else if (new_compress) {
+ /* This is based on the Choi and Ko bending model, which works surprisingly well for compression. */
+ float kb = stiffness_compression;
+ float cb = kb; /* cb equal to kb seems to work, but a factor can be added if necessary */
- dfdx_spring(dfdx, dir, length, restlen, stiffness);
- dfdv_damp(dfdv, dir, damping);
+ damping = damping_compression;
- apply_spring(data, i, j, f, dfdx, dfdv);
+ mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb));
- return true;
+ outerproduct(dfdx, dir, dir);
+ mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb));
}
else {
return false;
}
+
+ madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
+ dfdv_damp(dfdv, dir, damping);
+
+ apply_spring(data, i, j, f, dfdx, dfdv);
+
+ return true;
}
/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
@@ -1648,6 +1671,114 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo
}
}
+BLI_INLINE void poly_avg(lfVector *data, int *inds, int len, float r_avg[3])
+{
+ float fact = 1.0f / (float)len;
+
+ zero_v3(r_avg);
+
+ for (int i = 0; i < len; i++) {
+ madd_v3_v3fl(r_avg, data[inds[i]], fact);
+ }
+}
+
+BLI_INLINE void poly_norm(lfVector *data, int i, int j, int *inds, int len, float r_dir[3])
+{
+ float mid[3];
+
+ poly_avg(data, inds, len, mid);
+
+ normal_tri_v3(r_dir, data[i], data[j], mid);
+}
+
+BLI_INLINE void edge_avg(lfVector *data, int i, int j, float r_avg[3])
+{
+ r_avg[0] = (data[i][0] + data[j][0]) * 0.5f;
+ r_avg[1] = (data[i][1] + data[j][1]) * 0.5f;
+ r_avg[2] = (data[i][2] + data[j][2]) * 0.5f;
+}
+
+BLI_INLINE void edge_norm(lfVector *data, int i, int j, float r_dir[3])
+{
+ sub_v3_v3v3(r_dir, data[i], data[j]);
+ normalize_v3(r_dir);
+}
+
+BLI_INLINE float bend_angle(float dir_a[3], float dir_b[3], float dir_e[3])
+{
+ float cos, sin;
+ float tmp[3];
+
+ cos = dot_v3v3(dir_a, dir_b);
+
+ cross_v3_v3v3(tmp, dir_a, dir_b);
+ sin = dot_v3v3(tmp, dir_e);
+
+ return atan2f(sin, cos);
+}
+
+BLI_INLINE void spring_angle(Implicit_Data *data, int i, int j, int *i_a, int *i_b, int len_a, int len_b,
+ float r_dir_a[3], float r_dir_b[3],
+ float *r_angle, float r_vel_a[3], float r_vel_b[3])
+{
+ float dir_e[3], vel_e[3];
+
+ poly_norm(data->X, j, i, i_a, len_a, r_dir_a);
+ poly_norm(data->X, i, j, i_b, len_b, r_dir_b);
+
+ edge_norm(data->X, i, j, dir_e);
+
+ *r_angle = bend_angle(r_dir_a, r_dir_b, dir_e);
+
+ poly_avg(data->V, i_a, len_a, r_vel_a);
+ poly_avg(data->V, i_b, len_b, r_vel_b);
+
+ edge_avg(data->V, i, j, vel_e);
+
+ sub_v3_v3(r_vel_a, vel_e);
+ sub_v3_v3(r_vel_b, vel_e);
+}
+
+/* Angular springs roughly based on the bending model proposed by Baraff and Witkin in "Large Steps in Cloth Simulation". */
+bool BPH_mass_spring_force_spring_angular(Implicit_Data *data, int i, int j, int *i_a, int *i_b, int len_a, int len_b,
+ float restang, float stiffness, float damping)
+{
+ float angle, dir_a[3], dir_b[3], vel_a[3], vel_b[3];
+ float f_a[3], f_b[3], f_e[3];
+ float force;
+ int x;
+
+ spring_angle(data, i, j, i_a, i_b, len_a, len_b,
+ dir_a, dir_b, &angle, vel_a, vel_b);
+
+ /* spring force */
+ force = stiffness * (angle - restang);
+
+ /* damping force */
+ force += -damping * (dot_v3v3(vel_a, dir_a) + dot_v3v3(vel_b, dir_b));
+
+ mul_v3_v3fl(f_a, dir_a, force / len_a);
+ mul_v3_v3fl(f_b, dir_b, force / len_b);
+
+ for (x = 0; x < len_a; x++) {
+ add_v3_v3(data->F[i_a[x]], f_a);
+ }
+
+ for (x = 0; x < len_b; x++) {
+ add_v3_v3(data->F[i_b[x]], f_b);
+ }
+
+ mul_v3_v3fl(f_a, dir_a, force * 0.5f);
+ mul_v3_v3fl(f_b, dir_b, force * 0.5f);
+
+ add_v3_v3v3(f_e, f_a, f_b);
+
+ sub_v3_v3(data->F[i], f_e);
+ sub_v3_v3(data->F[j], f_e);
+
+ return true;
+}
+
/* Jacobian of a direction vector.
* Basically the part of the differential orthogonal to the direction,
* inversely proportional to the length of the edge.
@@ -1671,7 +1802,7 @@ BLI_INLINE void spring_grad_dir(Implicit_Data *data, int i, int j, float edge[3]
}
}
-BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k,
+BLI_INLINE void spring_hairbend_forces(Implicit_Data *data, int i, int j, int k,
const float goal[3],
float stiffness, float damping,
int q, const float dx[3], const float dv[3],
@@ -1720,7 +1851,7 @@ BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k,
}
/* Finite Differences method for estimating the jacobian of the force */
-BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j, int k,
+BLI_INLINE void spring_hairbend_estimate_dfdx(Implicit_Data *data, int i, int j, int k,
const float goal[3],
float stiffness, float damping,
int q, float dfdx[3][3])
@@ -1739,11 +1870,11 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j,
/* XXX TODO offset targets to account for position dependency */
for (a = 0; a < 3; ++a) {
- spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ spring_hairbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_pos[a], dvec_null[a], f);
copy_v3_v3(dfdx[a], f);
- spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ spring_hairbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_neg[a], dvec_null[a], f);
sub_v3_v3(dfdx[a], f);
@@ -1754,7 +1885,7 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j,
}
/* Finite Differences method for estimating the jacobian of the force */
-BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j, int k,
+BLI_INLINE void spring_hairbend_estimate_dfdv(Implicit_Data *data, int i, int j, int k,
const float goal[3],
float stiffness, float damping,
int q, float dfdv[3][3])
@@ -1773,11 +1904,11 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j,
/* XXX TODO offset targets to account for position dependency */
for (a = 0; a < 3; ++a) {
- spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ spring_hairbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_null[a], dvec_pos[a], f);
copy_v3_v3(dfdv[a], f);
- spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ spring_hairbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_null[a], dvec_neg[a], f);
sub_v3_v3(dfdv[a], f);
@@ -1790,7 +1921,7 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j,
/* Angular spring that pulls the vertex toward the local target
* See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
*/
-bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, int j, int k,
+bool BPH_mass_spring_force_spring_bending_hair(Implicit_Data *data, int i, int j, int k,
const float target[3], float stiffness, float damping)
{
float goal[3];
@@ -1806,18 +1937,18 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
world_to_root_v3(data, j, goal, target);
- spring_angbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk);
+ spring_hairbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk);
negate_v3_v3(fj, fk); /* counterforce */
- spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi);
- spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj);
- spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk);
+ spring_hairbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi);
+ spring_hairbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj);
+ spring_hairbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk);
copy_m3_m3(dfj_dxi, dfk_dxi); negate_m3(dfj_dxi);
copy_m3_m3(dfj_dxj, dfk_dxj); negate_m3(dfj_dxj);
- spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi);
- spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj);
- spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk);
+ spring_hairbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi);
+ spring_hairbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj);
+ spring_hairbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk);
copy_m3_m3(dfj_dvi, dfk_dvi); negate_m3(dfj_dvi);
copy_m3_m3(dfj_dvj, dfk_dvj); negate_m3(dfj_dvj);
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 955b1c4e4ed..5a2f15405c1 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -90,7 +90,8 @@ 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 PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
+float BPY_driver_exec(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver,
+ struct ChannelDriver *driver_orig, 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/CMakeLists.txt b/source/blender/python/CMakeLists.txt
index e855f3a3756..030576fefd1 100644
--- a/source/blender/python/CMakeLists.txt
+++ b/source/blender/python/CMakeLists.txt
@@ -18,5 +18,6 @@
add_subdirectory(intern)
add_subdirectory(generic)
+add_subdirectory(gpu)
add_subdirectory(mathutils)
add_subdirectory(bmesh)
diff --git a/source/blender/python/bmesh/CMakeLists.txt b/source/blender/python/bmesh/CMakeLists.txt
index 3b38fead7b9..48213b7eed5 100644
--- a/source/blender/python/bmesh/CMakeLists.txt
+++ b/source/blender/python/bmesh/CMakeLists.txt
@@ -23,6 +23,7 @@ set(INC
../../bmesh
../../blenkernel
../../blenlib
+ ../../depsgraph
../../makesdna
../../../../intern/guardedalloc
)
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index 5819d7ce2bb..012f7b1232d 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -113,30 +113,30 @@ static PyObject *bpy_bm_from_edit_mesh(PyObject *UNUSED(self), PyObject *value)
}
PyDoc_STRVAR(bpy_bm_update_edit_mesh_doc,
-".. method:: update_edit_mesh(mesh, tessface=True, destructive=True)\n"
+".. method:: update_edit_mesh(mesh, loop_triangles=True, destructive=True)\n"
"\n"
" Update the mesh after changes to the BMesh in editmode,\n"
" optionally recalculating n-gon tessellation.\n"
"\n"
" :arg mesh: The editmode mesh.\n"
" :type mesh: :class:`bpy.types.Mesh`\n"
-" :arg tessface: Option to recalculate n-gon tessellation.\n"
-" :type tessface: boolean\n"
+" :arg loop_triangles: Option to recalculate n-gon tessellation.\n"
+" :type loop_triangles: boolean\n"
" :arg destructive: Use when geometry has been added or removed.\n"
" :type destructive: boolean\n"
);
static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {"mesh", "tessface", "destructive", NULL};
+ static const char *kwlist[] = {"mesh", "loop_triangles", "destructive", NULL};
PyObject *py_me;
Mesh *me;
- bool do_tessface = true;
+ bool do_loop_triangles = true;
bool is_destructive = true;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O|O&O&:update_edit_mesh", (char **)kwlist,
&py_me,
- PyC_ParseBool, &do_tessface,
+ PyC_ParseBool, &do_loop_triangles,
PyC_ParseBool, &is_destructive))
{
return NULL;
@@ -156,13 +156,8 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args,
{
extern void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive);
- BMEditMesh *em = me->edit_btmesh;
- BMesh *bm = em->bm;
- /* python won't ensure matching uv/mtex */
- BM_mesh_cd_validate(bm);
-
- EDBM_update_generic(me->edit_btmesh, do_tessface, is_destructive);
+ EDBM_update_generic(me->edit_btmesh, do_loop_triangles, is_destructive);
}
Py_RETURN_NONE;
@@ -208,21 +203,17 @@ PyObject *BPyInit_bmesh(void)
/* bmesh.types */
PyModule_AddObject(mod, "types", (submodule = BPyInit_bmesh_types()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
/* bmesh.ops (not a real module, exposes module like access). */
PyModule_AddObject(mod, "ops", (submodule = BPyInit_bmesh_ops()));
/* PyDict_SetItemString(sys_modules, PyModule_GetNameObject(submodule), submodule); */
PyDict_SetItemString(sys_modules, "bmesh.ops", submodule); /* fake module */
- Py_INCREF(submodule);
PyModule_AddObject(mod, "utils", (submodule = BPyInit_bmesh_utils()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
PyModule_AddObject(mod, "geometry", (submodule = BPyInit_bmesh_geometry()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
return mod;
}
diff --git a/source/blender/python/bmesh/bmesh_py_ops.c b/source/blender/python/bmesh/bmesh_py_ops.c
index ee96c859858..49e71da3bc3 100644
--- a/source/blender/python/bmesh/bmesh_py_ops.c
+++ b/source/blender/python/bmesh/bmesh_py_ops.c
@@ -75,10 +75,14 @@ static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], c
{
DynStr *dyn_str = BLI_dynstr_new();
char *ret;
+ bool quoted;
+ bool set;
int i = 0;
while (*slot_types[i].name) {
+ quoted = false;
+ set = false;
/* cut off '.out' by using a string size arg */
const int name_len = is_out ?
(strchr(slot_types[i].name, '.') - slot_types[i].name) :
@@ -86,7 +90,19 @@ static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], c
const char *value = "<Unknown>";
switch (slot_types[i].type) {
case BMO_OP_SLOT_BOOL: value = "False"; break;
- case BMO_OP_SLOT_INT: value = "0"; break;
+ case BMO_OP_SLOT_INT:
+ if (slot_types[i].subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_ENUM) {
+ value = slot_types[i].enum_flags[0].identifier;
+ quoted = true;
+ }
+ else if (slot_types[i].subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_FLAG) {
+ value = "";
+ set = true;
+ }
+ else {
+ value = "0";
+ }
+ break;
case BMO_OP_SLOT_FLT: value = "0.0"; break;
case BMO_OP_SLOT_PTR: value = "None"; break;
case BMO_OP_SLOT_MAT: value = "Matrix()"; break;
@@ -95,7 +111,12 @@ static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], c
(slot_types[i].subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) ? "None" : "[]"; break;
case BMO_OP_SLOT_MAPPING: value = "{}"; break;
}
- BLI_dynstr_appendf(dyn_str, i ? ", %.*s=%s" : "%.*s=%s", name_len, slot_types[i].name, value);
+ BLI_dynstr_appendf(
+ dyn_str, i ? ", %.*s=%s%s%s%s%s" : "%.*s=%s%s%s%s%s",
+ name_len, slot_types[i].name,
+ set ? "{" : "", quoted ? "'" : "",
+ value,
+ quoted ? "'" : "", set ? "}" : "");
i++;
}
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 013a22fd563..b523d1d879d 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -46,6 +46,8 @@
#include "../generic/python_utildefines.h"
#include "../generic/py_capi_utils.h"
+BLI_STATIC_ASSERT(sizeof(PyC_FlagSet) == sizeof(BMO_FlagSet), "size mismatch");
+
static int bpy_bm_op_as_py_error(BMesh *bm)
{
if (BMO_error_occurred(bm)) {
@@ -169,16 +171,46 @@ static int bpy_slot_from_py(
}
case BMO_OP_SLOT_INT:
{
- const int param = PyC_Long_AsI32(value);
+ if (slot->slot_subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_ENUM) {
+ int enum_val = -1;
+ PyC_FlagSet *items = (PyC_FlagSet *)slot->data.enum_flags;
+ const char *enum_str = _PyUnicode_AsString(value);
- if (param == -1 && PyErr_Occurred()) {
- PyErr_Format(PyExc_TypeError,
- "%.200s: keyword \"%.200s\" expected an int, not %.200s",
- opname, slot_name, Py_TYPE(value)->tp_name);
- return -1;
+ if (enum_str == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s: keyword \"%.200s\" expected a string, not %.200s",
+ opname, slot_name, Py_TYPE(value)->tp_name);
+ return -1;
+ }
+
+ if (PyC_FlagSet_ValueFromID(items, enum_str, &enum_val, slot_name) == -1) {
+ return -1;
+ }
+
+ BMO_SLOT_AS_INT(slot) = enum_val;
+ }
+ else if (slot->slot_subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_FLAG) {
+ int flag = 0;
+ PyC_FlagSet *items = (PyC_FlagSet *)slot->data.enum_flags;
+
+ if (PyC_FlagSet_ToBitfield(items, value, &flag, slot_name) == -1) {
+ return -1;
+ }
+
+ BMO_SLOT_AS_INT(slot) = flag;
}
else {
- BMO_SLOT_AS_INT(slot) = param;
+ const int param = PyC_Long_AsI32(value);
+
+ if (param == -1 && PyErr_Occurred()) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s: keyword \"%.200s\" expected an int, not %.200s",
+ opname, slot_name, Py_TYPE(value)->tp_name);
+ return -1;
+ }
+ else {
+ BMO_SLOT_AS_INT(slot) = param;
+ }
}
break;
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index 9cd8eeb0aab..3950f623f54 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -34,12 +34,12 @@
#include "DNA_object_types.h"
#include "DNA_material_types.h"
-#include "BKE_depsgraph.h"
#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "DEG_depsgraph.h"
+
#include "bmesh.h"
#include <Python.h>
@@ -903,10 +903,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
bm = self->bm;
- /* python won't ensure matching uv/mtex */
- BM_mesh_cd_validate(bm);
-
- BLI_assert(BKE_id_is_in_gobal_main(&me->id));
+ BLI_assert(BKE_id_is_in_global_main(&me->id));
BM_mesh_bm_to_me(
G_MAIN, /* XXX UGLY! */
bm, me,
@@ -916,7 +913,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
/* we could have the user do this but if they forget blender can easy crash
* since the references arrays for the objects derived meshes are now invalid */
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
Py_RETURN_NONE;
}
@@ -939,6 +936,8 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc,
);
static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
+ /* TODO: This doesn't work currently because of missing depsgraph. */
+#if 0
static const char *kwlist[] = {"object", "scene", "deform", "render", "cage", "face_normals", NULL};
PyObject *py_object;
PyObject *py_scene;
@@ -1031,6 +1030,10 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
dm->release(dm);
Py_RETURN_NONE;
+#else
+ UNUSED_VARS(self, args, kw);
+#endif
+ return NULL;
}
@@ -1243,15 +1246,15 @@ static PyObject *bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObjec
}
}
-PyDoc_STRVAR(bpy_bmesh_calc_tessface_doc,
-".. method:: calc_tessface()\n"
+PyDoc_STRVAR(bpy_bmesh_calc_loop_triangles_doc,
+".. method:: calc_loop_triangles()\n"
"\n"
" Calculate triangle tessellation from quads/ngons.\n"
"\n"
" :return: The triangulated faces.\n"
" :rtype: list of :class:`BMLoop` tuples\n"
);
-static PyObject *bpy_bmesh_calc_tessface(BPy_BMElem *self)
+static PyObject *bpy_bmesh_calc_loop_triangles(BPy_BMElem *self)
{
BMesh *bm;
@@ -2730,7 +2733,7 @@ static struct PyMethodDef bpy_bmesh_methods[] = {
/* calculations */
{"calc_volume", (PyCFunction)bpy_bmesh_calc_volume, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_calc_volume_doc},
- {"calc_tessface", (PyCFunction)bpy_bmesh_calc_tessface, METH_NOARGS, bpy_bmesh_calc_tessface_doc},
+ {"calc_loop_triangles", (PyCFunction)bpy_bmesh_calc_loop_triangles, METH_NOARGS, bpy_bmesh_calc_loop_triangles_doc},
{NULL, NULL, 0, NULL}
};
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index ecf5cce8bd2..f49766c93ab 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -105,9 +105,6 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__bevel_weight_doc,
PyDoc_STRVAR(bpy_bmlayeraccess_collection__crease_doc,
"Edge crease for subsurf - float in [0 - 1].\n\n:type: :class:`BMLayerCollection`"
);
-PyDoc_STRVAR(bpy_bmlayeraccess_collection__tex_doc,
-"Accessor for :class:`BMTexPoly` layer (TODO).\n\ntype: :class:`BMLayerCollection`" // TYPE DOESN'T EXIST YET
-);
PyDoc_STRVAR(bpy_bmlayeraccess_collection__uv_doc,
"Accessor for :class:`BMLoopUV` UV (as a 2D Vector).\n\ntype: :class:`BMLayerCollection`"
);
@@ -120,6 +117,9 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__skin_doc,
PyDoc_STRVAR(bpy_bmlayeraccess_collection__paint_mask_doc,
"Accessor for paint mask layer.\n\ntype: :class:`BMLayerCollection`"
);
+PyDoc_STRVAR(bpy_bmlayeraccess_collection__face_map_doc,
+"FaceMap custom-data layer.\n\ntype: :class:`BMLayerCollection`"
+);
#ifdef WITH_FREESTYLE
PyDoc_STRVAR(bpy_bmlayeraccess_collection__freestyle_edge_doc,
"Accessor for Freestyle edge layer.\n\ntype: :class:`BMLayerCollection`"
@@ -222,8 +222,7 @@ static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = {
{(char *)"float", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__float_doc, (void *)CD_PROP_FLT},
{(char *)"int", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT},
{(char *)"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__string_doc, (void *)CD_PROP_STR},
-
- {(char *)"tex", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__tex_doc, (void *)CD_MTEXPOLY},
+ {(char *)"face_map", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__face_map_doc, (void *)CD_FACEMAP},
#ifdef WITH_FREESTYLE
{(char *)"freestyle", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__freestyle_face_doc, (void *)CD_FREESTYLE_FACE},
@@ -989,6 +988,7 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
break;
}
case CD_PROP_INT:
+ case CD_FACEMAP:
{
ret = PyLong_FromLong(*(int *)value);
break;
@@ -999,11 +999,6 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
ret = PyBytes_FromStringAndSize(mstring->s, mstring->s_len);
break;
}
- case CD_MTEXPOLY:
- {
- ret = BPy_BMTexPoly_CreatePyObject(value);
- break;
- }
case CD_MLOOPUV:
{
ret = BPy_BMLoopUV_CreatePyObject(value);
@@ -1074,6 +1069,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj
break;
}
case CD_PROP_INT:
+ case CD_FACEMAP:
{
int tmp_val = PyC_Long_AsI32(py_value);
if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) {
@@ -1102,11 +1098,6 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj
}
break;
}
- case CD_MTEXPOLY:
- {
- ret = BPy_BMTexPoly_AssignPyObject(value, py_value);
- break;
- }
case CD_MLOOPUV:
{
ret = BPy_BMLoopUV_AssignPyObject(value, py_value);
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
index d2ea87dd03f..2a0f3817f35 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c
@@ -42,103 +42,12 @@
#include "BLI_math_vector.h"
#include "BKE_deform.h"
-#include "BKE_library.h"
#include "bmesh_py_types_meshdata.h"
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
-
-/* Mesh BMTexPoly
- * ************** */
-
-#define BPy_BMTexPoly_Check(v) (Py_TYPE(v) == &BPy_BMTexPoly_Type)
-
-typedef struct BPy_BMTexPoly {
- PyObject_VAR_HEAD
- MTexPoly *data;
-} BPy_BMTexPoly;
-
-extern PyObject *pyrna_id_CreatePyObject(ID *id);
-extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
-
-PyDoc_STRVAR(bpy_bmtexpoly_image_doc,
-"Image or None.\n\n:type: :class:`bpy.types.Image`"
-);
-static PyObject *bpy_bmtexpoly_image_get(BPy_BMTexPoly *self, void *UNUSED(closure))
-{
- return pyrna_id_CreatePyObject((ID *)self->data->tpage);
-}
-
-static int bpy_bmtexpoly_image_set(BPy_BMTexPoly *self, PyObject *value, void *UNUSED(closure))
-{
- ID *id;
-
- if (value == Py_None) {
- id = NULL;
- }
- else if (pyrna_id_FromPyObject(value, &id) && id && GS(id->name) == ID_IM) {
- /* pass */
- }
- else {
- PyErr_Format(PyExc_KeyError, "BMTexPoly.image = x"
- "expected an image or None, not '%.200s'",
- Py_TYPE(value)->tp_name);
- return -1;
- }
-
- id_lib_extern(id);
- self->data->tpage = (struct Image *)id;
-
- return 0;
-}
-
-static PyGetSetDef bpy_bmtexpoly_getseters[] = {
- /* attributes match rna_def_mtpoly */
- {(char *)"image", (getter)bpy_bmtexpoly_image_get, (setter)bpy_bmtexpoly_image_set, (char *)bpy_bmtexpoly_image_doc, NULL},
-
- {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
-};
-
-static PyTypeObject BPy_BMTexPoly_Type; /* bm.loops.layers.uv.active */
-
-static void bm_init_types_bmtexpoly(void)
-{
- BPy_BMTexPoly_Type.tp_basicsize = sizeof(BPy_BMTexPoly);
-
- BPy_BMTexPoly_Type.tp_name = "BMTexPoly";
-
- BPy_BMTexPoly_Type.tp_doc = NULL; // todo
-
- BPy_BMTexPoly_Type.tp_getset = bpy_bmtexpoly_getseters;
-
- BPy_BMTexPoly_Type.tp_flags = Py_TPFLAGS_DEFAULT;
-
- PyType_Ready(&BPy_BMTexPoly_Type);
-}
-
-int BPy_BMTexPoly_AssignPyObject(struct MTexPoly *mtpoly, PyObject *value)
-{
- if (UNLIKELY(!BPy_BMTexPoly_Check(value))) {
- PyErr_Format(PyExc_TypeError, "expected BMTexPoly, not a %.200s", Py_TYPE(value)->tp_name);
- return -1;
- }
- else {
- *((MTexPoly *)mtpoly) = *(((BPy_BMTexPoly *)value)->data);
- return 0;
- }
-}
-
-PyObject *BPy_BMTexPoly_CreatePyObject(struct MTexPoly *mtpoly)
-{
- BPy_BMTexPoly *self = PyObject_New(BPy_BMTexPoly, &BPy_BMTexPoly_Type);
- self->data = mtpoly;
- return (PyObject *)self;
-}
-
-/* --- End Mesh BMTexPoly --- */
-
/* Mesh Loop UV
* ************ */
@@ -797,7 +706,6 @@ PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert)
/* call to init all types */
void BPy_BM_init_types_meshdata(void)
{
- bm_init_types_bmtexpoly();
bm_init_types_bmloopuv();
bm_init_types_bmloopcol();
bm_init_types_bmdvert();
diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.h b/source/blender/python/bmesh/bmesh_py_types_meshdata.h
index 07d8a46cc65..c8ae2596f99 100644
--- a/source/blender/python/bmesh/bmesh_py_types_meshdata.h
+++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.h
@@ -40,15 +40,11 @@ typedef struct BPy_BMGenericMeshData {
void *data;
} BPy_BMGenericMeshData;
-struct MTexPoly;
struct MLoopUV;
struct MLoopCol;
struct MDeformVert;
struct MVertSkin;
-int BPy_BMTexPoly_AssignPyObject(struct MTexPoly *mloopuv, PyObject *value);
-PyObject *BPy_BMTexPoly_CreatePyObject(struct MTexPoly *mloopuv);
-
int BPy_BMLoopUV_AssignPyObject(struct MLoopUV *data, PyObject *value);
PyObject *BPy_BMLoopUV_CreatePyObject(struct MLoopUV *data);
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 7b9292827b0..6e1c28e1310 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -37,6 +37,8 @@
#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
+#include "../generic/py_capi_utils.h"
+
#include "bgl.h"
@@ -185,11 +187,13 @@
#define GLbitfield_ref(num) &bgl_var##num
#define GLbitfield_def(num) /* unsigned */ int GLbitfield_var(num)
+#if 0
/* typedef signed char GLbyte; */
#define GLbyte_str "b"
#define GLbyte_var(num) bgl_var##num
#define GLbyte_ref(num) &bgl_var##num
#define GLbyte_def(num) signed char GLbyte_var(num)
+#endif
/* typedef short GLshort; */
#define GLshort_str "h"
@@ -227,11 +231,13 @@
#define GLubyte_ref(num) &bgl_var##num
#define GLubyte_def(num) /* unsigned */ char GLubyte_var(num)
+#if 0
/* typedef unsigned short GLushort; */
#define GLushort_str "H"
#define GLushort_var(num) bgl_var##num
#define GLushort_ref(num) &bgl_var##num
#define GLushort_def(num) /* unsigned */ short GLushort_var(num)
+#endif
/* typedef unsigned int GLuint; */
#define GLuint_str "I"
@@ -474,29 +480,21 @@ int BGL_typeSize(int type)
static int gl_buffer_type_from_py_buffer(Py_buffer *pybuffer)
{
- char *typestr = pybuffer->format;
+ const char format = PyC_StructFmt_type_from_str(pybuffer->format);
Py_ssize_t itemsize = pybuffer->itemsize;
- if (ELEM(typestr[0], '<', '>', '|')) {
- typestr += 1;
+ if (PyC_StructFmt_type_is_float_any(format)) {
+ if (itemsize == 4) return GL_FLOAT;
+ if (itemsize == 8) return GL_DOUBLE;
}
-
- switch (typestr[0]) {
- case 't':
- case 'b':
- case 'h':
- case 'i':
- case 'l':
- if (itemsize == 1) return GL_BYTE;
- if (itemsize == 2) return GL_SHORT;
- if (itemsize == 4) return GL_INT;
- break;
- case 'f':
- case 'd':
- if (itemsize == 4) return GL_FLOAT;
- if (itemsize == 8) return GL_DOUBLE;
- break;
+ if (PyC_StructFmt_type_is_byte(format) ||
+ PyC_StructFmt_type_is_int_any(format))
+ {
+ if (itemsize == 1) return GL_BYTE;
+ if (itemsize == 2) return GL_SHORT;
+ if (itemsize == 4) return GL_INT;
}
+
return -1; /* UNKNOWN */
}
@@ -1073,358 +1071,71 @@ static PyObject *Method_##funcname (PyObject *UNUSED(self), PyObject *args) \
ret_ret_##ret; \
}
-#define BGLU_Wrap(funcname, ret, arg_list) \
-static PyObject *Method_##funcname (PyObject *UNUSED(self), PyObject *args) \
-{ \
- arg_def arg_list; \
- ret_def_##ret; \
- if (!PyArg_ParseTuple(args, arg_str arg_list, arg_ref arg_list)) { \
- return NULL; \
- } \
- ret_set_##ret glu##funcname (arg_var arg_list); \
- ret_ret_##ret; \
-}
-
/* GL_VERSION_1_0 */
-BGL_Wrap(Accum, void, (GLenum, GLfloat))
-BGL_Wrap(AlphaFunc, void, (GLenum, GLfloat))
-BGL_Wrap(Begin, void, (GLenum))
-BGL_Wrap(Bitmap, void, (GLsizei, GLsizei, GLfloat, GLfloat, GLfloat, GLfloat, GLubyteP))
BGL_Wrap(BlendFunc, void, (GLenum, GLenum))
-BGL_Wrap(CallList, void, (GLuint))
-BGL_Wrap(CallLists, void, (GLsizei, GLenum, GLvoidP))
BGL_Wrap(Clear, void, (GLbitfield))
-BGL_Wrap(ClearAccum, void, (GLfloat, GLfloat, GLfloat, GLfloat))
BGL_Wrap(ClearColor, void, (GLfloat, GLfloat, GLfloat, GLfloat))
BGL_Wrap(ClearDepth, void, (GLdouble))
-BGL_Wrap(ClearIndex, void, (GLfloat))
BGL_Wrap(ClearStencil, void, (GLint))
-BGL_Wrap(ClipPlane, void, (GLenum, GLdoubleP))
-BGL_Wrap(Color3b, void, (GLbyte, GLbyte, GLbyte))
-BGL_Wrap(Color3bv, void, (GLbyteP))
-BGL_Wrap(Color3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Color3dv, void, (GLdoubleP))
-BGL_Wrap(Color3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(Color3fv, void, (GLfloatP))
-BGL_Wrap(Color3i, void, (GLint, GLint, GLint))
-BGL_Wrap(Color3iv, void, (GLintP))
-BGL_Wrap(Color3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(Color3sv, void, (GLshortP))
-BGL_Wrap(Color3ub, void, (GLubyte, GLubyte, GLubyte))
-BGL_Wrap(Color3ubv, void, (GLubyteP))
-BGL_Wrap(Color3ui, void, (GLuint, GLuint, GLuint))
-BGL_Wrap(Color3uiv, void, (GLuintP))
-BGL_Wrap(Color3us, void, (GLushort, GLushort, GLushort))
-BGL_Wrap(Color3usv, void, (GLushortP))
-BGL_Wrap(Color4b, void, (GLbyte, GLbyte, GLbyte, GLbyte))
-BGL_Wrap(Color4bv, void, (GLbyteP))
-BGL_Wrap(Color4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Color4dv, void, (GLdoubleP))
-BGL_Wrap(Color4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(Color4fv, void, (GLfloatP))
-BGL_Wrap(Color4i, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(Color4iv, void, (GLintP))
-BGL_Wrap(Color4s, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(Color4sv, void, (GLshortP))
-BGL_Wrap(Color4ub, void, (GLubyte, GLubyte, GLubyte, GLubyte))
-BGL_Wrap(Color4ubv, void, (GLubyteP))
-BGL_Wrap(Color4ui, void, (GLuint, GLuint, GLuint, GLuint))
-BGL_Wrap(Color4uiv, void, (GLuintP))
-BGL_Wrap(Color4us, void, (GLushort, GLushort, GLushort, GLushort))
-BGL_Wrap(Color4usv, void, (GLushortP))
BGL_Wrap(ColorMask, void, (GLboolean, GLboolean, GLboolean, GLboolean))
-BGL_Wrap(ColorMaterial, void, (GLenum, GLenum))
-BGL_Wrap(CopyPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum))
BGL_Wrap(CullFace, void, (GLenum))
-BGL_Wrap(DeleteLists, void, (GLuint, GLsizei))
BGL_Wrap(DepthFunc, void, (GLenum))
BGL_Wrap(DepthMask, void, (GLboolean))
BGL_Wrap(DepthRange, void, (GLdouble, GLdouble))
BGL_Wrap(Disable, void, (GLenum))
BGL_Wrap(DrawBuffer, void, (GLenum))
-BGL_Wrap(DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP))
-BGL_Wrap(EdgeFlag, void, (GLboolean))
-BGL_Wrap(EdgeFlagv, void, (GLbooleanP))
BGL_Wrap(Enable, void, (GLenum))
-BGL_Wrap(End, void, (void))
-BGL_Wrap(EndList, void, (void))
-BGL_Wrap(EvalCoord1d, void, (GLdouble))
-BGL_Wrap(EvalCoord1dv, void, (GLdoubleP))
-BGL_Wrap(EvalCoord1f, void, (GLfloat))
-BGL_Wrap(EvalCoord1fv, void, (GLfloatP))
-BGL_Wrap(EvalCoord2d, void, (GLdouble, GLdouble))
-BGL_Wrap(EvalCoord2dv, void, (GLdoubleP))
-BGL_Wrap(EvalCoord2f, void, (GLfloat, GLfloat))
-BGL_Wrap(EvalCoord2fv, void, (GLfloatP))
-BGL_Wrap(EvalMesh1, void, (GLenum, GLint, GLint))
-BGL_Wrap(EvalMesh2, void, (GLenum, GLint, GLint, GLint, GLint))
-BGL_Wrap(EvalPoint1, void, (GLint))
-BGL_Wrap(EvalPoint2, void, (GLint, GLint))
-BGL_Wrap(FeedbackBuffer, void, (GLsizei, GLenum, GLfloatP))
BGL_Wrap(Finish, void, (void))
BGL_Wrap(Flush, void, (void))
-BGL_Wrap(Fogf, void, (GLenum, GLfloat))
-BGL_Wrap(Fogfv, void, (GLenum, GLfloatP))
-BGL_Wrap(Fogi, void, (GLenum, GLint))
-BGL_Wrap(Fogiv, void, (GLenum, GLintP))
BGL_Wrap(FrontFace, void, (GLenum))
-BGL_Wrap(Frustum, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(GenLists, GLuint, (GLsizei))
BGL_Wrap(GetBooleanv, void, (GLenum, GLbooleanP))
-BGL_Wrap(GetClipPlane, void, (GLenum, GLdoubleP))
BGL_Wrap(GetDoublev, void, (GLenum, GLdoubleP))
BGL_Wrap(GetError, GLenum, (void))
BGL_Wrap(GetFloatv, void, (GLenum, GLfloatP))
BGL_Wrap(GetIntegerv, void, (GLenum, GLintP))
-BGL_Wrap(GetLightfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(GetLightiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(GetMapdv, void, (GLenum, GLenum, GLdoubleP))
-BGL_Wrap(GetMapfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(GetMapiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(GetMaterialfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(GetMaterialiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(GetPixelMapfv, void, (GLenum, GLfloatP))
-BGL_Wrap(GetPixelMapuiv, void, (GLenum, GLuintP))
-BGL_Wrap(GetPixelMapusv, void, (GLenum, GLushortP))
-BGL_Wrap(GetPolygonStipple, void, (GLubyteP))
BGL_Wrap(GetString, GLstring, (GLenum))
-BGL_Wrap(GetTexEnvfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(GetTexEnviv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(GetTexGendv, void, (GLenum, GLenum, GLdoubleP))
-BGL_Wrap(GetTexGenfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(GetTexGeniv, void, (GLenum, GLenum, GLintP))
BGL_Wrap(GetTexImage, void, (GLenum, GLint, GLenum, GLenum, GLvoidP))
BGL_Wrap(GetTexLevelParameterfv, void, (GLenum, GLint, GLenum, GLfloatP))
BGL_Wrap(GetTexLevelParameteriv, void, (GLenum, GLint, GLenum, GLintP))
BGL_Wrap(GetTexParameterfv, void, (GLenum, GLenum, GLfloatP))
BGL_Wrap(GetTexParameteriv, void, (GLenum, GLenum, GLintP))
BGL_Wrap(Hint, void, (GLenum, GLenum))
-BGL_Wrap(IndexMask, void, (GLuint))
-BGL_Wrap(Indexd, void, (GLdouble))
-BGL_Wrap(Indexdv, void, (GLdoubleP))
-BGL_Wrap(Indexf, void, (GLfloat))
-BGL_Wrap(Indexfv, void, (GLfloatP))
-BGL_Wrap(Indexi, void, (GLint))
-BGL_Wrap(Indexiv, void, (GLintP))
-BGL_Wrap(Indexs, void, (GLshort))
-BGL_Wrap(Indexsv, void, (GLshortP))
-BGL_Wrap(InitNames, void, (void))
BGL_Wrap(IsEnabled, GLboolean, (GLenum))
-BGL_Wrap(IsList, GLboolean, (GLuint))
-BGL_Wrap(LightModelf, void, (GLenum, GLfloat))
-BGL_Wrap(LightModelfv, void, (GLenum, GLfloatP))
-BGL_Wrap(LightModeli, void, (GLenum, GLint))
-BGL_Wrap(LightModeliv, void, (GLenum, GLintP))
-BGL_Wrap(Lightf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(Lightfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(Lighti, void, (GLenum, GLenum, GLint))
-BGL_Wrap(Lightiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(LineStipple, void, (GLint, GLushort))
BGL_Wrap(LineWidth, void, (GLfloat))
-BGL_Wrap(ListBase, void, (GLuint))
-BGL_Wrap(LoadIdentity, void, (void))
-BGL_Wrap(LoadMatrixd, void, (GLdoubleP))
-BGL_Wrap(LoadMatrixf, void, (GLfloatP))
-BGL_Wrap(LoadName, void, (GLuint))
BGL_Wrap(LogicOp, void, (GLenum))
-BGL_Wrap(Map1d, void, (GLenum, GLdouble, GLdouble, GLint, GLint, GLdoubleP))
-BGL_Wrap(Map1f, void, (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloatP))
-BGL_Wrap(Map2d, void, (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdoubleP))
-BGL_Wrap(Map2f, void, (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloatP))
-BGL_Wrap(MapGrid1d, void, (GLint, GLdouble, GLdouble))
-BGL_Wrap(MapGrid1f, void, (GLint, GLfloat, GLfloat))
-BGL_Wrap(MapGrid2d, void, (GLint, GLdouble, GLdouble, GLint, GLdouble, GLdouble))
-BGL_Wrap(MapGrid2f, void, (GLint, GLfloat, GLfloat, GLint, GLfloat, GLfloat))
-BGL_Wrap(Materialf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(Materialfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(Materiali, void, (GLenum, GLenum, GLint))
-BGL_Wrap(Materialiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(MatrixMode, void, (GLenum))
-BGL_Wrap(MultMatrixd, void, (GLdoubleP))
-BGL_Wrap(MultMatrixf, void, (GLfloatP))
-BGL_Wrap(NewList, void, (GLuint, GLenum))
-BGL_Wrap(Normal3b, void, (GLbyte, GLbyte, GLbyte))
-BGL_Wrap(Normal3bv, void, (GLbyteP))
-BGL_Wrap(Normal3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Normal3dv, void, (GLdoubleP))
-BGL_Wrap(Normal3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(Normal3fv, void, (GLfloatP))
-BGL_Wrap(Normal3i, void, (GLint, GLint, GLint))
-BGL_Wrap(Normal3iv, void, (GLintP))
-BGL_Wrap(Normal3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(Normal3sv, void, (GLshortP))
-BGL_Wrap(Ortho, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(PassThrough, void, (GLfloat))
-BGL_Wrap(PixelMapfv, void, (GLenum, GLsizei, GLfloatP))
-BGL_Wrap(PixelMapuiv, void, (GLenum, GLsizei, GLuintP))
-BGL_Wrap(PixelMapusv, void, (GLenum, GLsizei, GLushortP))
BGL_Wrap(PixelStoref, void, (GLenum, GLfloat))
BGL_Wrap(PixelStorei, void, (GLenum, GLint))
-BGL_Wrap(PixelTransferf, void, (GLenum, GLfloat))
-BGL_Wrap(PixelTransferi, void, (GLenum, GLint))
-BGL_Wrap(PixelZoom, void, (GLfloat, GLfloat))
BGL_Wrap(PointSize, void, (GLfloat))
BGL_Wrap(PolygonMode, void, (GLenum, GLenum))
-BGL_Wrap(PolygonStipple, void, (GLubyteP))
-BGL_Wrap(PopAttrib, void, (void))
-BGL_Wrap(PopMatrix, void, (void))
-BGL_Wrap(PopName, void, (void))
-BGL_Wrap(PushAttrib, void, (GLbitfield))
-BGL_Wrap(PushMatrix, void, (void))
-BGL_Wrap(PushName, void, (GLuint))
-BGL_Wrap(RasterPos2d, void, (GLdouble, GLdouble))
-BGL_Wrap(RasterPos2dv, void, (GLdoubleP))
-BGL_Wrap(RasterPos2f, void, (GLfloat, GLfloat))
-BGL_Wrap(RasterPos2fv, void, (GLfloatP))
-BGL_Wrap(RasterPos2i, void, (GLint, GLint))
-BGL_Wrap(RasterPos2iv, void, (GLintP))
-BGL_Wrap(RasterPos2s, void, (GLshort, GLshort))
-BGL_Wrap(RasterPos2sv, void, (GLshortP))
-BGL_Wrap(RasterPos3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(RasterPos3dv, void, (GLdoubleP))
-BGL_Wrap(RasterPos3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(RasterPos3fv, void, (GLfloatP))
-BGL_Wrap(RasterPos3i, void, (GLint, GLint, GLint))
-BGL_Wrap(RasterPos3iv, void, (GLintP))
-BGL_Wrap(RasterPos3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(RasterPos3sv, void, (GLshortP))
-BGL_Wrap(RasterPos4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(RasterPos4dv, void, (GLdoubleP))
-BGL_Wrap(RasterPos4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(RasterPos4fv, void, (GLfloatP))
-BGL_Wrap(RasterPos4i, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(RasterPos4iv, void, (GLintP))
-BGL_Wrap(RasterPos4s, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(RasterPos4sv, void, (GLshortP))
BGL_Wrap(ReadBuffer, void, (GLenum))
BGL_Wrap(ReadPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoidP))
-BGL_Wrap(Rectd, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Rectdv, void, (GLdoubleP, GLdoubleP))
-BGL_Wrap(Rectf, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(Rectfv, void, (GLfloatP, GLfloatP))
-BGL_Wrap(Recti, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(Rectiv, void, (GLintP, GLintP))
-BGL_Wrap(Rects, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(Rectsv, void, (GLshortP, GLshortP))
-BGL_Wrap(RenderMode, GLint, (GLenum))
-BGL_Wrap(Rotated, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Rotatef, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(Scaled, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Scalef, void, (GLfloat, GLfloat, GLfloat))
BGL_Wrap(Scissor, void, (GLint, GLint, GLsizei, GLsizei))
-BGL_Wrap(SelectBuffer, void, (GLsizei, GLuintP))
-BGL_Wrap(ShadeModel, void, (GLenum))
BGL_Wrap(StencilFunc, void, (GLenum, GLint, GLuint))
BGL_Wrap(StencilMask, void, (GLuint))
BGL_Wrap(StencilOp, void, (GLenum, GLenum, GLenum))
-BGL_Wrap(TexCoord1d, void, (GLdouble))
-BGL_Wrap(TexCoord1dv, void, (GLdoubleP))
-BGL_Wrap(TexCoord1f, void, (GLfloat))
-BGL_Wrap(TexCoord1fv, void, (GLfloatP))
-BGL_Wrap(TexCoord1i, void, (GLint))
-BGL_Wrap(TexCoord1iv, void, (GLintP))
-BGL_Wrap(TexCoord1s, void, (GLshort))
-BGL_Wrap(TexCoord1sv, void, (GLshortP))
-BGL_Wrap(TexCoord2d, void, (GLdouble, GLdouble))
-BGL_Wrap(TexCoord2dv, void, (GLdoubleP))
-BGL_Wrap(TexCoord2f, void, (GLfloat, GLfloat))
-BGL_Wrap(TexCoord2fv, void, (GLfloatP))
-BGL_Wrap(TexCoord2i, void, (GLint, GLint))
-BGL_Wrap(TexCoord2iv, void, (GLintP))
-BGL_Wrap(TexCoord2s, void, (GLshort, GLshort))
-BGL_Wrap(TexCoord2sv, void, (GLshortP))
-BGL_Wrap(TexCoord3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(TexCoord3dv, void, (GLdoubleP))
-BGL_Wrap(TexCoord3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(TexCoord3fv, void, (GLfloatP))
-BGL_Wrap(TexCoord3i, void, (GLint, GLint, GLint))
-BGL_Wrap(TexCoord3iv, void, (GLintP))
-BGL_Wrap(TexCoord3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(TexCoord3sv, void, (GLshortP))
-BGL_Wrap(TexCoord4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(TexCoord4dv, void, (GLdoubleP))
-BGL_Wrap(TexCoord4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(TexCoord4fv, void, (GLfloatP))
-BGL_Wrap(TexCoord4i, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(TexCoord4iv, void, (GLintP))
-BGL_Wrap(TexCoord4s, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(TexCoord4sv, void, (GLshortP))
-BGL_Wrap(TexEnvf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(TexEnvfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(TexEnvi, void, (GLenum, GLenum, GLint))
-BGL_Wrap(TexEnviv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(TexGend, void, (GLenum, GLenum, GLdouble))
-BGL_Wrap(TexGendv, void, (GLenum, GLenum, GLdoubleP))
-BGL_Wrap(TexGenf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(TexGenfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(TexGeni, void, (GLenum, GLenum, GLint))
-BGL_Wrap(TexGeniv, void, (GLenum, GLenum, GLintP))
BGL_Wrap(TexImage1D, void, (GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, GLvoidP))
BGL_Wrap(TexImage2D, void, (GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP))
BGL_Wrap(TexParameterf, void, (GLenum, GLenum, GLfloat))
BGL_Wrap(TexParameterfv, void, (GLenum, GLenum, GLfloatP))
BGL_Wrap(TexParameteri, void, (GLenum, GLenum, GLint))
BGL_Wrap(TexParameteriv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(Translated, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Translatef, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(Vertex2d, void, (GLdouble, GLdouble))
-BGL_Wrap(Vertex2dv, void, (GLdoubleP))
-BGL_Wrap(Vertex2f, void, (GLfloat, GLfloat))
-BGL_Wrap(Vertex2fv, void, (GLfloatP))
-BGL_Wrap(Vertex2i, void, (GLint, GLint))
-BGL_Wrap(Vertex2iv, void, (GLintP))
-BGL_Wrap(Vertex2s, void, (GLshort, GLshort))
-BGL_Wrap(Vertex2sv, void, (GLshortP))
-BGL_Wrap(Vertex3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Vertex3dv, void, (GLdoubleP))
-BGL_Wrap(Vertex3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(Vertex3fv, void, (GLfloatP))
-BGL_Wrap(Vertex3i, void, (GLint, GLint, GLint))
-BGL_Wrap(Vertex3iv, void, (GLintP))
-BGL_Wrap(Vertex3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(Vertex3sv, void, (GLshortP))
-BGL_Wrap(Vertex4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(Vertex4dv, void, (GLdoubleP))
-BGL_Wrap(Vertex4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(Vertex4fv, void, (GLfloatP))
-BGL_Wrap(Vertex4i, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(Vertex4iv, void, (GLintP))
-BGL_Wrap(Vertex4s, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(Vertex4sv, void, (GLshortP))
BGL_Wrap(Viewport, void, (GLint, GLint, GLsizei, GLsizei))
/* GL_VERSION_1_1 */
-BGL_Wrap(AreTexturesResident, GLboolean, (GLsizei, GLuintP, GLbooleanP))
-BGL_Wrap(ArrayElement, void, (GLint))
BGL_Wrap(BindTexture, void, (GLenum, GLuint))
-BGL_Wrap(ColorPointer, void, (GLint, GLenum, GLsizei, GLvoidP))
BGL_Wrap(CopyTexImage1D, void, (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint))
BGL_Wrap(CopyTexImage2D, void, (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint))
BGL_Wrap(CopyTexSubImage1D, void, (GLenum, GLint, GLint, GLint, GLint, GLsizei))
BGL_Wrap(CopyTexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei))
BGL_Wrap(DeleteTextures, void, (GLsizei, GLuintP))
-BGL_Wrap(DisableClientState, void, (GLenum))
BGL_Wrap(DrawArrays, void, (GLenum, GLint, GLsizei))
BGL_Wrap(DrawElements, void, (GLenum, GLsizei, GLenum, GLvoidP))
-BGL_Wrap(EdgeFlagPointer, void, (GLsizei, GLvoidP))
-BGL_Wrap(EnableClientState, void, (GLenum))
BGL_Wrap(GenTextures, void, (GLsizei, GLuintP))
-BGL_Wrap(GetPointerv, void, (GLenum, GLvoidP))
-BGL_Wrap(IndexPointer, void, (GLenum, GLsizei, GLvoidP))
-BGL_Wrap(Indexub, void, (GLubyte))
-BGL_Wrap(Indexubv, void, (GLubyteP))
-BGL_Wrap(InterleavedArrays, void, (GLenum, GLsizei, GLvoidP))
BGL_Wrap(IsTexture, GLboolean, (GLuint))
-BGL_Wrap(NormalPointer, void, (GLenum, GLsizei, GLvoidP))
BGL_Wrap(PolygonOffset, void, (GLfloat, GLfloat))
-BGL_Wrap(PopClientAttrib, void, (void))
-BGL_Wrap(PrioritizeTextures, void, (GLsizei, GLuintP, GLfloatP))
-BGL_Wrap(PushClientAttrib, void, (GLbitfield))
-BGL_Wrap(TexCoordPointer, void, (GLint, GLenum, GLsizei, GLvoidP))
BGL_Wrap(TexSubImage1D, void, (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, GLvoidP))
BGL_Wrap(TexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoidP))
-BGL_Wrap(VertexPointer, void, (GLint, GLenum, GLsizei, GLvoidP))
/* GL_VERSION_1_2 */
@@ -1436,7 +1147,6 @@ BGL_Wrap(TexSubImage3D, void, (GLenum, GLint, GLint, GLint, GLi
/* GL_VERSION_1_3 */
BGL_Wrap(ActiveTexture, void, (GLenum))
-BGL_Wrap(ClientActiveTexture, void, (GLenum))
BGL_Wrap(CompressedTexImage1D, void, (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, GLvoidP))
BGL_Wrap(CompressedTexImage2D, void, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, GLvoidP))
BGL_Wrap(CompressedTexImage3D, void, (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, GLvoidP))
@@ -1444,42 +1154,6 @@ BGL_Wrap(CompressedTexSubImage1D, void, (GLenum, GLint, GLint, GLsizei, G
BGL_Wrap(CompressedTexSubImage2D, void, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, GLvoidP))
BGL_Wrap(CompressedTexSubImage3D, void, (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, GLvoidP))
BGL_Wrap(GetCompressedTexImage, void, (GLenum, GLint, GLvoidP))
-BGL_Wrap(LoadTransposeMatrixd, void, (GLdoubleP))
-BGL_Wrap(LoadTransposeMatrixf, void, (GLfloatP))
-BGL_Wrap(MultTransposeMatrixd, void, (GLdoubleP))
-BGL_Wrap(MultTransposeMatrixf, void, (GLfloatP))
-BGL_Wrap(MultiTexCoord1d, void, (GLenum, GLdouble))
-BGL_Wrap(MultiTexCoord1dv, void, (GLenum, GLdoubleP))
-BGL_Wrap(MultiTexCoord1f, void, (GLenum, GLfloat))
-BGL_Wrap(MultiTexCoord1fv, void, (GLenum, GLfloatP))
-BGL_Wrap(MultiTexCoord1i, void, (GLenum, GLint))
-BGL_Wrap(MultiTexCoord1iv, void, (GLenum, GLintP))
-BGL_Wrap(MultiTexCoord1s, void, (GLenum, GLshort))
-BGL_Wrap(MultiTexCoord1sv, void, (GLenum, GLshortP))
-BGL_Wrap(MultiTexCoord2d, void, (GLenum, GLdouble, GLdouble))
-BGL_Wrap(MultiTexCoord2dv, void, (GLenum, GLdoubleP))
-BGL_Wrap(MultiTexCoord2f, void, (GLenum, GLfloat, GLfloat))
-BGL_Wrap(MultiTexCoord2fv, void, (GLenum, GLfloatP))
-BGL_Wrap(MultiTexCoord2i, void, (GLenum, GLint, GLint))
-BGL_Wrap(MultiTexCoord2iv, void, (GLenum, GLintP))
-BGL_Wrap(MultiTexCoord2s, void, (GLenum, GLshort, GLshort))
-BGL_Wrap(MultiTexCoord2sv, void, (GLenum, GLshortP))
-BGL_Wrap(MultiTexCoord3d, void, (GLenum, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(MultiTexCoord3dv, void, (GLenum, GLdoubleP))
-BGL_Wrap(MultiTexCoord3f, void, (GLenum, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(MultiTexCoord3fv, void, (GLenum, GLfloatP))
-BGL_Wrap(MultiTexCoord3i, void, (GLenum, GLint, GLint, GLint))
-BGL_Wrap(MultiTexCoord3iv, void, (GLenum, GLintP))
-BGL_Wrap(MultiTexCoord3s, void, (GLenum, GLshort, GLshort, GLshort))
-BGL_Wrap(MultiTexCoord3sv, void, (GLenum, GLshortP))
-BGL_Wrap(MultiTexCoord4d, void, (GLenum, GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(MultiTexCoord4dv, void, (GLenum, GLdoubleP))
-BGL_Wrap(MultiTexCoord4f, void, (GLenum, GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(MultiTexCoord4fv, void, (GLenum, GLfloatP))
-BGL_Wrap(MultiTexCoord4i, void, (GLenum, GLint, GLint, GLint, GLint))
-BGL_Wrap(MultiTexCoord4iv, void, (GLenum, GLintP))
-BGL_Wrap(MultiTexCoord4s, void, (GLenum, GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(MultiTexCoord4sv, void, (GLenum, GLshortP))
BGL_Wrap(SampleCoverage, void, (GLfloat, GLboolean))
@@ -1615,10 +1289,21 @@ BGL_Wrap(UniformMatrix4x3fv, void, (GLint, GLsizei, GLboolean, GLflo
/* GL_VERSION_3_0 */
+BGL_Wrap(BindFramebuffer, void, (GLenum, GLuint))
+BGL_Wrap(BindRenderbuffer, void, (GLenum, GLuint))
BGL_Wrap(BindVertexArray, void, (GLuint))
+BGL_Wrap(BlitFramebuffer, void, (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum))
+BGL_Wrap(CheckFramebufferStatus, GLenum, (GLenum))
+BGL_Wrap(DeleteFramebuffers, void, (GLsizei, GLuintP))
+BGL_Wrap(DeleteRenderbuffers, void, (GLsizei, GLuintP))
BGL_Wrap(DeleteVertexArrays, void, (GLsizei, GLuintP))
+BGL_Wrap(FramebufferRenderbuffer, void, (GLenum, GLenum, GLenum, GLuint))
+BGL_Wrap(GenFramebuffers, void, (GLsizei, GLuintP))
+BGL_Wrap(GenRenderbuffers, void, (GLsizei, GLuintP))
BGL_Wrap(GenVertexArrays, void, (GLsizei, GLuintP))
+BGL_Wrap(GetStringi, GLstring, (GLenum, GLuint))
BGL_Wrap(IsVertexArray, GLboolean, (GLuint))
+BGL_Wrap(RenderbufferStorage, void, (GLenum, GLenum, GLsizei, GLsizei))
/* GL_VERSION_3_1 */
@@ -1645,44 +1330,7 @@ BGL_Wrap(TexImage3DMultisample, void, (GLenum, GLsizei, GLenum, GLsizei
/* GL_VERSION_3_3 */
-BGL_Wrap(ColorP3ui, void, (GLenum, GLuint))
-BGL_Wrap(ColorP3uiv, void, (GLenum, GLuintP))
-BGL_Wrap(ColorP4ui, void, (GLenum, GLuint))
-BGL_Wrap(ColorP4uiv, void, (GLenum, GLuintP))
-BGL_Wrap(MultiTexCoordP1ui, void, (GLenum, GLenum, GLuint))
-BGL_Wrap(MultiTexCoordP1uiv, void, (GLenum, GLenum, GLuintP))
-BGL_Wrap(MultiTexCoordP2ui, void, (GLenum, GLenum, GLuint))
-BGL_Wrap(MultiTexCoordP2uiv, void, (GLenum, GLenum, GLuintP))
-BGL_Wrap(MultiTexCoordP3ui, void, (GLenum, GLenum, GLuint))
-BGL_Wrap(MultiTexCoordP3uiv, void, (GLenum, GLenum, GLuintP))
-BGL_Wrap(MultiTexCoordP4ui, void, (GLenum, GLenum, GLuint))
-BGL_Wrap(MultiTexCoordP4uiv, void, (GLenum, GLenum, GLuintP))
-BGL_Wrap(NormalP3ui, void, (GLenum, GLuint))
-BGL_Wrap(NormalP3uiv, void, (GLenum, GLuintP))
-BGL_Wrap(SecondaryColorP3ui, void, (GLenum, GLuint))
-BGL_Wrap(SecondaryColorP3uiv, void, (GLenum, GLuintP))
-BGL_Wrap(TexCoordP1ui, void, (GLenum, GLuint))
-BGL_Wrap(TexCoordP1uiv, void, (GLenum, GLuintP))
-BGL_Wrap(TexCoordP2ui, void, (GLenum, GLuint))
-BGL_Wrap(TexCoordP2uiv, void, (GLenum, GLuintP))
-BGL_Wrap(TexCoordP3ui, void, (GLenum, GLuint))
-BGL_Wrap(TexCoordP3uiv, void, (GLenum, GLuintP))
-BGL_Wrap(TexCoordP4ui, void, (GLenum, GLuint))
-BGL_Wrap(TexCoordP4uiv, void, (GLenum, GLuintP))
-BGL_Wrap(VertexP2ui, void, (GLenum, GLuint))
-BGL_Wrap(VertexP2uiv, void, (GLenum, GLuintP))
-BGL_Wrap(VertexP3ui, void, (GLenum, GLuint))
-BGL_Wrap(VertexP3uiv, void, (GLenum, GLuintP))
-BGL_Wrap(VertexP4ui, void, (GLenum, GLuint))
-BGL_Wrap(VertexP4uiv, void, (GLenum, GLuintP))
-
-
-BGLU_Wrap(Perspective, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGLU_Wrap(LookAt, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble))
-BGLU_Wrap(Ortho2D, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGLU_Wrap(PickMatrix, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLintP))
-BGLU_Wrap(Project, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP))
-BGLU_Wrap(UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP))
+/* no new functions besides packed immediate mode (not part of core profile) */
/** \} */
@@ -1692,26 +1340,12 @@ BGLU_Wrap(UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdouble
/** \name Module Definition
* \{ */
-#define MethodDefu(func) {"glu"#func, Method_##func, METH_VARARGS, NULL}
-
-static struct PyMethodDef BGL_methods[] = {
- MethodDefu(Perspective),
- MethodDefu(LookAt),
- MethodDefu(Ortho2D),
- MethodDefu(PickMatrix),
- MethodDefu(Project),
- MethodDefu(UnProject),
- {NULL, NULL, 0, NULL}
-};
-
-#undef MethodDefu
-
static struct PyModuleDef BGL_module_def = {
PyModuleDef_HEAD_INIT,
"bgl", /* m_name */
NULL, /* m_doc */
0, /* m_size */
- BGL_methods, /* m_methods */
+ NULL, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
@@ -1745,9 +1379,6 @@ static void py_module_dict_add_method(PyObject *submodule, PyObject *dict, PyMet
}
}
-/* TODO, expose to users */
-static bool use_deprecated = true;
-
PyObject *BPyInit_bgl(void)
{
PyObject *submodule, *dict;
@@ -1822,268 +1453,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(TexParameteriv);
PY_MOD_ADD_METHOD(Viewport);
}
- /* adding in GL_VERSION_1_0 removed from core profile */
- if (use_deprecated == true) {
- PY_MOD_ADD_METHOD(Accum);
- PY_MOD_ADD_METHOD(AlphaFunc);
- PY_MOD_ADD_METHOD(Begin);
- PY_MOD_ADD_METHOD(Bitmap);
- PY_MOD_ADD_METHOD(CallList);
- PY_MOD_ADD_METHOD(CallLists);
- PY_MOD_ADD_METHOD(ClearAccum);
- PY_MOD_ADD_METHOD(ClearIndex);
- PY_MOD_ADD_METHOD(ClipPlane);
- PY_MOD_ADD_METHOD(Color3b);
- PY_MOD_ADD_METHOD(Color3bv);
- PY_MOD_ADD_METHOD(Color3d);
- PY_MOD_ADD_METHOD(Color3dv);
- PY_MOD_ADD_METHOD(Color3f);
- PY_MOD_ADD_METHOD(Color3fv);
- PY_MOD_ADD_METHOD(Color3i);
- PY_MOD_ADD_METHOD(Color3iv);
- PY_MOD_ADD_METHOD(Color3s);
- PY_MOD_ADD_METHOD(Color3sv);
- PY_MOD_ADD_METHOD(Color3ub);
- PY_MOD_ADD_METHOD(Color3ubv);
- PY_MOD_ADD_METHOD(Color3ui);
- PY_MOD_ADD_METHOD(Color3uiv);
- PY_MOD_ADD_METHOD(Color3us);
- PY_MOD_ADD_METHOD(Color3usv);
- PY_MOD_ADD_METHOD(Color4b);
- PY_MOD_ADD_METHOD(Color4bv);
- PY_MOD_ADD_METHOD(Color4d);
- PY_MOD_ADD_METHOD(Color4dv);
- PY_MOD_ADD_METHOD(Color4f);
- PY_MOD_ADD_METHOD(Color4fv);
- PY_MOD_ADD_METHOD(Color4i);
- PY_MOD_ADD_METHOD(Color4iv);
- PY_MOD_ADD_METHOD(Color4s);
- PY_MOD_ADD_METHOD(Color4sv);
- PY_MOD_ADD_METHOD(Color4ub);
- PY_MOD_ADD_METHOD(Color4ubv);
- PY_MOD_ADD_METHOD(Color4ui);
- PY_MOD_ADD_METHOD(Color4uiv);
- PY_MOD_ADD_METHOD(Color4us);
- PY_MOD_ADD_METHOD(Color4usv);
- PY_MOD_ADD_METHOD(ColorMaterial);
- PY_MOD_ADD_METHOD(CopyPixels);
- PY_MOD_ADD_METHOD(DeleteLists);
- PY_MOD_ADD_METHOD(DrawPixels);
- PY_MOD_ADD_METHOD(EdgeFlag);
- PY_MOD_ADD_METHOD(EdgeFlagv);
- PY_MOD_ADD_METHOD(End);
- PY_MOD_ADD_METHOD(EndList);
- PY_MOD_ADD_METHOD(EvalCoord1d);
- PY_MOD_ADD_METHOD(EvalCoord1dv);
- PY_MOD_ADD_METHOD(EvalCoord1f);
- PY_MOD_ADD_METHOD(EvalCoord1fv);
- PY_MOD_ADD_METHOD(EvalCoord2d);
- PY_MOD_ADD_METHOD(EvalCoord2dv);
- PY_MOD_ADD_METHOD(EvalCoord2f);
- PY_MOD_ADD_METHOD(EvalCoord2fv);
- PY_MOD_ADD_METHOD(EvalMesh1);
- PY_MOD_ADD_METHOD(EvalMesh2);
- PY_MOD_ADD_METHOD(EvalPoint1);
- PY_MOD_ADD_METHOD(EvalPoint2);
- PY_MOD_ADD_METHOD(FeedbackBuffer);
- PY_MOD_ADD_METHOD(Fogf);
- PY_MOD_ADD_METHOD(Fogfv);
- PY_MOD_ADD_METHOD(Fogi);
- PY_MOD_ADD_METHOD(Fogiv);
- PY_MOD_ADD_METHOD(Frustum);
- PY_MOD_ADD_METHOD(GenLists);
- PY_MOD_ADD_METHOD(GetClipPlane);
- PY_MOD_ADD_METHOD(GetLightfv);
- PY_MOD_ADD_METHOD(GetLightiv);
- PY_MOD_ADD_METHOD(GetMapdv);
- PY_MOD_ADD_METHOD(GetMapfv);
- PY_MOD_ADD_METHOD(GetMapiv);
- PY_MOD_ADD_METHOD(GetMaterialfv);
- PY_MOD_ADD_METHOD(GetMaterialiv);
- PY_MOD_ADD_METHOD(GetPixelMapfv);
- PY_MOD_ADD_METHOD(GetPixelMapuiv);
- PY_MOD_ADD_METHOD(GetPixelMapusv);
- PY_MOD_ADD_METHOD(GetPolygonStipple);
- PY_MOD_ADD_METHOD(GetTexEnvfv);
- PY_MOD_ADD_METHOD(GetTexEnviv);
- PY_MOD_ADD_METHOD(GetTexGendv);
- PY_MOD_ADD_METHOD(GetTexGenfv);
- PY_MOD_ADD_METHOD(GetTexGeniv);
- PY_MOD_ADD_METHOD(IndexMask);
- PY_MOD_ADD_METHOD(Indexd);
- PY_MOD_ADD_METHOD(Indexdv);
- PY_MOD_ADD_METHOD(Indexf);
- PY_MOD_ADD_METHOD(Indexfv);
- PY_MOD_ADD_METHOD(Indexi);
- PY_MOD_ADD_METHOD(Indexiv);
- PY_MOD_ADD_METHOD(Indexs);
- PY_MOD_ADD_METHOD(Indexsv);
- PY_MOD_ADD_METHOD(InitNames);
- PY_MOD_ADD_METHOD(IsList);
- PY_MOD_ADD_METHOD(LightModelf);
- PY_MOD_ADD_METHOD(LightModelfv);
- PY_MOD_ADD_METHOD(LightModeli);
- PY_MOD_ADD_METHOD(LightModeliv);
- PY_MOD_ADD_METHOD(Lightf);
- PY_MOD_ADD_METHOD(Lightfv);
- PY_MOD_ADD_METHOD(Lighti);
- PY_MOD_ADD_METHOD(Lightiv);
- PY_MOD_ADD_METHOD(LineStipple);
- PY_MOD_ADD_METHOD(ListBase);
- PY_MOD_ADD_METHOD(LoadIdentity);
- PY_MOD_ADD_METHOD(LoadMatrixd);
- PY_MOD_ADD_METHOD(LoadMatrixf);
- PY_MOD_ADD_METHOD(LoadName);
- PY_MOD_ADD_METHOD(Map1d);
- PY_MOD_ADD_METHOD(Map1f);
- PY_MOD_ADD_METHOD(Map2d);
- PY_MOD_ADD_METHOD(Map2f);
- PY_MOD_ADD_METHOD(MapGrid1d);
- PY_MOD_ADD_METHOD(MapGrid1f);
- PY_MOD_ADD_METHOD(MapGrid2d);
- PY_MOD_ADD_METHOD(MapGrid2f);
- PY_MOD_ADD_METHOD(Materialf);
- PY_MOD_ADD_METHOD(Materialfv);
- PY_MOD_ADD_METHOD(Materiali);
- PY_MOD_ADD_METHOD(Materialiv);
- PY_MOD_ADD_METHOD(MatrixMode);
- PY_MOD_ADD_METHOD(MultMatrixd);
- PY_MOD_ADD_METHOD(MultMatrixf);
- PY_MOD_ADD_METHOD(NewList);
- PY_MOD_ADD_METHOD(Normal3b);
- PY_MOD_ADD_METHOD(Normal3bv);
- PY_MOD_ADD_METHOD(Normal3d);
- PY_MOD_ADD_METHOD(Normal3dv);
- PY_MOD_ADD_METHOD(Normal3f);
- PY_MOD_ADD_METHOD(Normal3fv);
- PY_MOD_ADD_METHOD(Normal3i);
- PY_MOD_ADD_METHOD(Normal3iv);
- PY_MOD_ADD_METHOD(Normal3s);
- PY_MOD_ADD_METHOD(Normal3sv);
- PY_MOD_ADD_METHOD(Ortho);
- PY_MOD_ADD_METHOD(PassThrough);
- PY_MOD_ADD_METHOD(PixelMapfv);
- PY_MOD_ADD_METHOD(PixelMapuiv);
- PY_MOD_ADD_METHOD(PixelMapusv);
- PY_MOD_ADD_METHOD(PixelTransferf);
- PY_MOD_ADD_METHOD(PixelTransferi);
- PY_MOD_ADD_METHOD(PixelZoom);
- PY_MOD_ADD_METHOD(PolygonStipple);
- PY_MOD_ADD_METHOD(PopAttrib);
- PY_MOD_ADD_METHOD(PopMatrix);
- PY_MOD_ADD_METHOD(PopName);
- PY_MOD_ADD_METHOD(PushAttrib);
- PY_MOD_ADD_METHOD(PushMatrix);
- PY_MOD_ADD_METHOD(PushName);
- PY_MOD_ADD_METHOD(RasterPos2d);
- PY_MOD_ADD_METHOD(RasterPos2dv);
- PY_MOD_ADD_METHOD(RasterPos2f);
- PY_MOD_ADD_METHOD(RasterPos2fv);
- PY_MOD_ADD_METHOD(RasterPos2i);
- PY_MOD_ADD_METHOD(RasterPos2iv);
- PY_MOD_ADD_METHOD(RasterPos2s);
- PY_MOD_ADD_METHOD(RasterPos2sv);
- PY_MOD_ADD_METHOD(RasterPos3d);
- PY_MOD_ADD_METHOD(RasterPos3dv);
- PY_MOD_ADD_METHOD(RasterPos3f);
- PY_MOD_ADD_METHOD(RasterPos3fv);
- PY_MOD_ADD_METHOD(RasterPos3i);
- PY_MOD_ADD_METHOD(RasterPos3iv);
- PY_MOD_ADD_METHOD(RasterPos3s);
- PY_MOD_ADD_METHOD(RasterPos3sv);
- PY_MOD_ADD_METHOD(RasterPos4d);
- PY_MOD_ADD_METHOD(RasterPos4dv);
- PY_MOD_ADD_METHOD(RasterPos4f);
- PY_MOD_ADD_METHOD(RasterPos4fv);
- PY_MOD_ADD_METHOD(RasterPos4i);
- PY_MOD_ADD_METHOD(RasterPos4iv);
- PY_MOD_ADD_METHOD(RasterPos4s);
- PY_MOD_ADD_METHOD(RasterPos4sv);
- PY_MOD_ADD_METHOD(Rectd);
- PY_MOD_ADD_METHOD(Rectdv);
- PY_MOD_ADD_METHOD(Rectf);
- PY_MOD_ADD_METHOD(Rectfv);
- PY_MOD_ADD_METHOD(Recti);
- PY_MOD_ADD_METHOD(Rectiv);
- PY_MOD_ADD_METHOD(Rects);
- PY_MOD_ADD_METHOD(Rectsv);
- PY_MOD_ADD_METHOD(RenderMode);
- PY_MOD_ADD_METHOD(Rotated);
- PY_MOD_ADD_METHOD(Rotatef);
- PY_MOD_ADD_METHOD(Scaled);
- PY_MOD_ADD_METHOD(Scalef);
- PY_MOD_ADD_METHOD(SelectBuffer);
- PY_MOD_ADD_METHOD(ShadeModel);
- PY_MOD_ADD_METHOD(TexCoord1d);
- PY_MOD_ADD_METHOD(TexCoord1dv);
- PY_MOD_ADD_METHOD(TexCoord1f);
- PY_MOD_ADD_METHOD(TexCoord1fv);
- PY_MOD_ADD_METHOD(TexCoord1i);
- PY_MOD_ADD_METHOD(TexCoord1iv);
- PY_MOD_ADD_METHOD(TexCoord1s);
- PY_MOD_ADD_METHOD(TexCoord1sv);
- PY_MOD_ADD_METHOD(TexCoord2d);
- PY_MOD_ADD_METHOD(TexCoord2dv);
- PY_MOD_ADD_METHOD(TexCoord2f);
- PY_MOD_ADD_METHOD(TexCoord2fv);
- PY_MOD_ADD_METHOD(TexCoord2i);
- PY_MOD_ADD_METHOD(TexCoord2iv);
- PY_MOD_ADD_METHOD(TexCoord2s);
- PY_MOD_ADD_METHOD(TexCoord2sv);
- PY_MOD_ADD_METHOD(TexCoord3d);
- PY_MOD_ADD_METHOD(TexCoord3dv);
- PY_MOD_ADD_METHOD(TexCoord3f);
- PY_MOD_ADD_METHOD(TexCoord3fv);
- PY_MOD_ADD_METHOD(TexCoord3i);
- PY_MOD_ADD_METHOD(TexCoord3iv);
- PY_MOD_ADD_METHOD(TexCoord3s);
- PY_MOD_ADD_METHOD(TexCoord3sv);
- PY_MOD_ADD_METHOD(TexCoord4d);
- PY_MOD_ADD_METHOD(TexCoord4dv);
- PY_MOD_ADD_METHOD(TexCoord4f);
- PY_MOD_ADD_METHOD(TexCoord4fv);
- PY_MOD_ADD_METHOD(TexCoord4i);
- PY_MOD_ADD_METHOD(TexCoord4iv);
- PY_MOD_ADD_METHOD(TexCoord4s);
- PY_MOD_ADD_METHOD(TexCoord4sv);
- PY_MOD_ADD_METHOD(TexEnvf);
- PY_MOD_ADD_METHOD(TexEnvfv);
- PY_MOD_ADD_METHOD(TexEnvi);
- PY_MOD_ADD_METHOD(TexEnviv);
- PY_MOD_ADD_METHOD(TexGend);
- PY_MOD_ADD_METHOD(TexGendv);
- PY_MOD_ADD_METHOD(TexGenf);
- PY_MOD_ADD_METHOD(TexGenfv);
- PY_MOD_ADD_METHOD(TexGeni);
- PY_MOD_ADD_METHOD(TexGeniv);
- PY_MOD_ADD_METHOD(Translated);
- PY_MOD_ADD_METHOD(Translatef);
- PY_MOD_ADD_METHOD(Vertex2d);
- PY_MOD_ADD_METHOD(Vertex2dv);
- PY_MOD_ADD_METHOD(Vertex2f);
- PY_MOD_ADD_METHOD(Vertex2fv);
- PY_MOD_ADD_METHOD(Vertex2i);
- PY_MOD_ADD_METHOD(Vertex2iv);
- PY_MOD_ADD_METHOD(Vertex2s);
- PY_MOD_ADD_METHOD(Vertex2sv);
- PY_MOD_ADD_METHOD(Vertex3d);
- PY_MOD_ADD_METHOD(Vertex3dv);
- PY_MOD_ADD_METHOD(Vertex3f);
- PY_MOD_ADD_METHOD(Vertex3fv);
- PY_MOD_ADD_METHOD(Vertex3i);
- PY_MOD_ADD_METHOD(Vertex3iv);
- PY_MOD_ADD_METHOD(Vertex3s);
- PY_MOD_ADD_METHOD(Vertex3sv);
- PY_MOD_ADD_METHOD(Vertex4d);
- PY_MOD_ADD_METHOD(Vertex4dv);
- PY_MOD_ADD_METHOD(Vertex4f);
- PY_MOD_ADD_METHOD(Vertex4fv);
- PY_MOD_ADD_METHOD(Vertex4i);
- PY_MOD_ADD_METHOD(Vertex4iv);
- PY_MOD_ADD_METHOD(Vertex4s);
- PY_MOD_ADD_METHOD(Vertex4sv);
- }
-
/* GL_VERSION_1_1 */
{
@@ -2101,27 +1470,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(TexSubImage1D);
PY_MOD_ADD_METHOD(TexSubImage2D);
}
- /* adding in GL_VERSION_1_1 removed from core profile */
- if (use_deprecated == true) {
- PY_MOD_ADD_METHOD(AreTexturesResident);
- PY_MOD_ADD_METHOD(ArrayElement);
- PY_MOD_ADD_METHOD(ColorPointer);
- PY_MOD_ADD_METHOD(DisableClientState);
- PY_MOD_ADD_METHOD(EdgeFlagPointer);
- PY_MOD_ADD_METHOD(EnableClientState);
- PY_MOD_ADD_METHOD(GetPointerv);
- PY_MOD_ADD_METHOD(IndexPointer);
- PY_MOD_ADD_METHOD(Indexub);
- PY_MOD_ADD_METHOD(Indexubv);
- PY_MOD_ADD_METHOD(InterleavedArrays);
- PY_MOD_ADD_METHOD(NormalPointer);
- PY_MOD_ADD_METHOD(PopClientAttrib);
- PY_MOD_ADD_METHOD(PrioritizeTextures);
- PY_MOD_ADD_METHOD(PushClientAttrib);
- PY_MOD_ADD_METHOD(TexCoordPointer);
- PY_MOD_ADD_METHOD(VertexPointer);
- }
-
/* GL_VERSION_1_2 */
{
@@ -2131,7 +1479,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(TexSubImage3D);
}
-
/* GL_VERSION_1_3 */
{
PY_MOD_ADD_METHOD(ActiveTexture);
@@ -2144,47 +1491,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(GetCompressedTexImage);
PY_MOD_ADD_METHOD(SampleCoverage);
}
- /* adding in GL_VERSION_1_3 removed from core profile */
- if (use_deprecated == true) {
- PY_MOD_ADD_METHOD(ClientActiveTexture);
- PY_MOD_ADD_METHOD(LoadTransposeMatrixd);
- PY_MOD_ADD_METHOD(LoadTransposeMatrixf);
- PY_MOD_ADD_METHOD(MultTransposeMatrixd);
- PY_MOD_ADD_METHOD(MultTransposeMatrixf);
- PY_MOD_ADD_METHOD(MultiTexCoord1d);
- PY_MOD_ADD_METHOD(MultiTexCoord1dv);
- PY_MOD_ADD_METHOD(MultiTexCoord1f);
- PY_MOD_ADD_METHOD(MultiTexCoord1fv);
- PY_MOD_ADD_METHOD(MultiTexCoord1i);
- PY_MOD_ADD_METHOD(MultiTexCoord1iv);
- PY_MOD_ADD_METHOD(MultiTexCoord1s);
- PY_MOD_ADD_METHOD(MultiTexCoord1sv);
- PY_MOD_ADD_METHOD(MultiTexCoord2d);
- PY_MOD_ADD_METHOD(MultiTexCoord2dv);
- PY_MOD_ADD_METHOD(MultiTexCoord2f);
- PY_MOD_ADD_METHOD(MultiTexCoord2fv);
- PY_MOD_ADD_METHOD(MultiTexCoord2i);
- PY_MOD_ADD_METHOD(MultiTexCoord2iv);
- PY_MOD_ADD_METHOD(MultiTexCoord2s);
- PY_MOD_ADD_METHOD(MultiTexCoord2sv);
- PY_MOD_ADD_METHOD(MultiTexCoord3d);
- PY_MOD_ADD_METHOD(MultiTexCoord3dv);
- PY_MOD_ADD_METHOD(MultiTexCoord3f);
- PY_MOD_ADD_METHOD(MultiTexCoord3fv);
- PY_MOD_ADD_METHOD(MultiTexCoord3i);
- PY_MOD_ADD_METHOD(MultiTexCoord3iv);
- PY_MOD_ADD_METHOD(MultiTexCoord3s);
- PY_MOD_ADD_METHOD(MultiTexCoord3sv);
- PY_MOD_ADD_METHOD(MultiTexCoord4d);
- PY_MOD_ADD_METHOD(MultiTexCoord4dv);
- PY_MOD_ADD_METHOD(MultiTexCoord4f);
- PY_MOD_ADD_METHOD(MultiTexCoord4fv);
- PY_MOD_ADD_METHOD(MultiTexCoord4i);
- PY_MOD_ADD_METHOD(MultiTexCoord4iv);
- PY_MOD_ADD_METHOD(MultiTexCoord4s);
- PY_MOD_ADD_METHOD(MultiTexCoord4sv);
- }
-
/* GL_VERSION_1_4 */
{
@@ -2192,7 +1498,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(BlendEquation);
}
-
/* GL_VERSION_1_5 */
{
PY_MOD_ADD_METHOD(BeginQuery);
@@ -2216,7 +1521,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(UnmapBuffer);
}
-
/* GL_VERSION_2_0 */
{
PY_MOD_ADD_METHOD(AttachShader);
@@ -2314,7 +1618,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(VertexAttribPointer);
}
-
/* GL_VERSION_2_1 */
{
PY_MOD_ADD_METHOD(UniformMatrix2x3fv);
@@ -2325,16 +1628,25 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(UniformMatrix4x3fv);
}
-
/* GL_VERSION_3_0 */
{
+ PY_MOD_ADD_METHOD(BindFramebuffer);
+ PY_MOD_ADD_METHOD(BindRenderbuffer);
PY_MOD_ADD_METHOD(BindVertexArray);
+ PY_MOD_ADD_METHOD(BlitFramebuffer);
+ PY_MOD_ADD_METHOD(CheckFramebufferStatus);
+ PY_MOD_ADD_METHOD(DeleteFramebuffers);
+ PY_MOD_ADD_METHOD(DeleteRenderbuffers);
PY_MOD_ADD_METHOD(DeleteVertexArrays);
+ PY_MOD_ADD_METHOD(FramebufferRenderbuffer);
+ PY_MOD_ADD_METHOD(GenFramebuffers);
+ PY_MOD_ADD_METHOD(GenRenderbuffers);
PY_MOD_ADD_METHOD(GenVertexArrays);
+ PY_MOD_ADD_METHOD(GetStringi);
PY_MOD_ADD_METHOD(IsVertexArray);
+ PY_MOD_ADD_METHOD(RenderbufferStorage);
}
-
/* GL_VERSION_3_1 */
{
PY_MOD_ADD_METHOD(BindBufferBase);
@@ -2349,7 +1661,6 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(UniformBlockBinding);
}
-
/* GL_VERSION_3_2 */
{
PY_MOD_ADD_METHOD(FramebufferTexture);
@@ -2361,39 +1672,8 @@ PyObject *BPyInit_bgl(void)
PY_MOD_ADD_METHOD(TexImage3DMultisample);
}
-
/* GL_VERSION_3_3 */
{
- PY_MOD_ADD_METHOD(ColorP3ui);
- PY_MOD_ADD_METHOD(ColorP3uiv);
- PY_MOD_ADD_METHOD(ColorP4ui);
- PY_MOD_ADD_METHOD(ColorP4uiv);
- PY_MOD_ADD_METHOD(MultiTexCoordP1ui);
- PY_MOD_ADD_METHOD(MultiTexCoordP1uiv);
- PY_MOD_ADD_METHOD(MultiTexCoordP2ui);
- PY_MOD_ADD_METHOD(MultiTexCoordP2uiv);
- PY_MOD_ADD_METHOD(MultiTexCoordP3ui);
- PY_MOD_ADD_METHOD(MultiTexCoordP3uiv);
- PY_MOD_ADD_METHOD(MultiTexCoordP4ui);
- PY_MOD_ADD_METHOD(MultiTexCoordP4uiv);
- PY_MOD_ADD_METHOD(NormalP3ui);
- PY_MOD_ADD_METHOD(NormalP3uiv);
- PY_MOD_ADD_METHOD(SecondaryColorP3ui);
- PY_MOD_ADD_METHOD(SecondaryColorP3uiv);
- PY_MOD_ADD_METHOD(TexCoordP1ui);
- PY_MOD_ADD_METHOD(TexCoordP1uiv);
- PY_MOD_ADD_METHOD(TexCoordP2ui);
- PY_MOD_ADD_METHOD(TexCoordP2uiv);
- PY_MOD_ADD_METHOD(TexCoordP3ui);
- PY_MOD_ADD_METHOD(TexCoordP3uiv);
- PY_MOD_ADD_METHOD(TexCoordP4ui);
- PY_MOD_ADD_METHOD(TexCoordP4uiv);
- PY_MOD_ADD_METHOD(VertexP2ui);
- PY_MOD_ADD_METHOD(VertexP2uiv);
- PY_MOD_ADD_METHOD(VertexP3ui);
- PY_MOD_ADD_METHOD(VertexP3uiv);
- PY_MOD_ADD_METHOD(VertexP4ui);
- PY_MOD_ADD_METHOD(VertexP4uiv);
}
#define PY_DICT_ADD_INT(x) py_module_dict_add_int(dict, #x, x)
@@ -2511,8 +1791,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_POINT);
PY_DICT_ADD_INT(GL_POINTS);
PY_DICT_ADD_INT(GL_POINT_SIZE);
- PY_DICT_ADD_INT(GL_POINT_SIZE_GRANULARITY);
- PY_DICT_ADD_INT(GL_POINT_SIZE_RANGE);
PY_DICT_ADD_INT(GL_POLYGON_MODE);
PY_DICT_ADD_INT(GL_POLYGON_OFFSET_FACTOR);
PY_DICT_ADD_INT(GL_POLYGON_OFFSET_FILL);
@@ -2602,338 +1880,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_XOR);
PY_DICT_ADD_INT(GL_ZERO);
}
- /* adding in GL_VERSION_1_1 removed from core profile */
- if (use_deprecated == true) {
- PY_DICT_ADD_INT(GL_2D);
- PY_DICT_ADD_INT(GL_2_BYTES);
- PY_DICT_ADD_INT(GL_3D);
- PY_DICT_ADD_INT(GL_3D_COLOR);
- PY_DICT_ADD_INT(GL_3D_COLOR_TEXTURE);
- PY_DICT_ADD_INT(GL_3_BYTES);
- PY_DICT_ADD_INT(GL_4D_COLOR_TEXTURE);
- PY_DICT_ADD_INT(GL_4_BYTES);
- PY_DICT_ADD_INT(GL_ACCUM);
- PY_DICT_ADD_INT(GL_ACCUM_ALPHA_BITS);
- PY_DICT_ADD_INT(GL_ACCUM_BLUE_BITS);
- PY_DICT_ADD_INT(GL_ACCUM_BUFFER_BIT);
- PY_DICT_ADD_INT(GL_ACCUM_CLEAR_VALUE);
- PY_DICT_ADD_INT(GL_ACCUM_GREEN_BITS);
- PY_DICT_ADD_INT(GL_ACCUM_RED_BITS);
- PY_DICT_ADD_INT(GL_ADD);
- PY_DICT_ADD_INT(GL_ALL_ATTRIB_BITS);
- PY_DICT_ADD_INT(GL_ALPHA12);
- PY_DICT_ADD_INT(GL_ALPHA16);
- PY_DICT_ADD_INT(GL_ALPHA4);
- PY_DICT_ADD_INT(GL_ALPHA8);
- PY_DICT_ADD_INT(GL_ALPHA_BIAS);
- PY_DICT_ADD_INT(GL_ALPHA_BITS);
- PY_DICT_ADD_INT(GL_ALPHA_SCALE);
- PY_DICT_ADD_INT(GL_ALPHA_TEST);
- PY_DICT_ADD_INT(GL_ALPHA_TEST_FUNC);
- PY_DICT_ADD_INT(GL_ALPHA_TEST_REF);
- PY_DICT_ADD_INT(GL_AMBIENT);
- PY_DICT_ADD_INT(GL_AMBIENT_AND_DIFFUSE);
- PY_DICT_ADD_INT(GL_ATTRIB_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_AUTO_NORMAL);
- PY_DICT_ADD_INT(GL_AUX0);
- PY_DICT_ADD_INT(GL_AUX1);
- PY_DICT_ADD_INT(GL_AUX2);
- PY_DICT_ADD_INT(GL_AUX3);
- PY_DICT_ADD_INT(GL_AUX_BUFFERS);
- PY_DICT_ADD_INT(GL_BITMAP);
- PY_DICT_ADD_INT(GL_BITMAP_TOKEN);
- PY_DICT_ADD_INT(GL_BLUE_BIAS);
- PY_DICT_ADD_INT(GL_BLUE_BITS);
- PY_DICT_ADD_INT(GL_BLUE_SCALE);
- PY_DICT_ADD_INT(GL_C3F_V3F);
- PY_DICT_ADD_INT(GL_C4F_N3F_V3F);
- PY_DICT_ADD_INT(GL_C4UB_V2F);
- PY_DICT_ADD_INT(GL_C4UB_V3F);
- PY_DICT_ADD_INT(GL_CLAMP);
- PY_DICT_ADD_INT(GL_CLIENT_ALL_ATTRIB_BITS);
- PY_DICT_ADD_INT(GL_CLIENT_ATTRIB_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_CLIENT_PIXEL_STORE_BIT);
- PY_DICT_ADD_INT(GL_CLIENT_VERTEX_ARRAY_BIT);
- PY_DICT_ADD_INT(GL_CLIP_PLANE0);
- PY_DICT_ADD_INT(GL_CLIP_PLANE1);
- PY_DICT_ADD_INT(GL_CLIP_PLANE2);
- PY_DICT_ADD_INT(GL_CLIP_PLANE3);
- PY_DICT_ADD_INT(GL_CLIP_PLANE4);
- PY_DICT_ADD_INT(GL_CLIP_PLANE5);
- PY_DICT_ADD_INT(GL_COEFF);
- PY_DICT_ADD_INT(GL_COLOR_ARRAY);
- PY_DICT_ADD_INT(GL_COLOR_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_COLOR_ARRAY_SIZE);
- PY_DICT_ADD_INT(GL_COLOR_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_COLOR_ARRAY_TYPE);
- PY_DICT_ADD_INT(GL_COLOR_INDEX);
- PY_DICT_ADD_INT(GL_COLOR_INDEXES);
- PY_DICT_ADD_INT(GL_COLOR_MATERIAL);
- PY_DICT_ADD_INT(GL_COLOR_MATERIAL_FACE);
- PY_DICT_ADD_INT(GL_COLOR_MATERIAL_PARAMETER);
- PY_DICT_ADD_INT(GL_COMPILE);
- PY_DICT_ADD_INT(GL_COMPILE_AND_EXECUTE);
- PY_DICT_ADD_INT(GL_CONSTANT_ATTENUATION);
- PY_DICT_ADD_INT(GL_COPY_PIXEL_TOKEN);
- PY_DICT_ADD_INT(GL_CURRENT_BIT);
- PY_DICT_ADD_INT(GL_CURRENT_COLOR);
- PY_DICT_ADD_INT(GL_CURRENT_INDEX);
- PY_DICT_ADD_INT(GL_CURRENT_NORMAL);
- PY_DICT_ADD_INT(GL_CURRENT_RASTER_COLOR);
- PY_DICT_ADD_INT(GL_CURRENT_RASTER_DISTANCE);
- PY_DICT_ADD_INT(GL_CURRENT_RASTER_INDEX);
- PY_DICT_ADD_INT(GL_CURRENT_RASTER_POSITION);
- PY_DICT_ADD_INT(GL_CURRENT_RASTER_POSITION_VALID);
- PY_DICT_ADD_INT(GL_CURRENT_RASTER_TEXTURE_COORDS);
- PY_DICT_ADD_INT(GL_CURRENT_TEXTURE_COORDS);
- PY_DICT_ADD_INT(GL_DECAL);
- PY_DICT_ADD_INT(GL_DEPTH_BIAS);
- PY_DICT_ADD_INT(GL_DEPTH_BITS);
- PY_DICT_ADD_INT(GL_DEPTH_SCALE);
- PY_DICT_ADD_INT(GL_DIFFUSE);
- PY_DICT_ADD_INT(GL_DOMAIN);
- PY_DICT_ADD_INT(GL_DRAW_PIXEL_TOKEN);
- PY_DICT_ADD_INT(GL_EDGE_FLAG);
- PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY);
- PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_EMISSION);
- PY_DICT_ADD_INT(GL_ENABLE_BIT);
- PY_DICT_ADD_INT(GL_EVAL_BIT);
- PY_DICT_ADD_INT(GL_EXP);
- PY_DICT_ADD_INT(GL_EXP2);
- PY_DICT_ADD_INT(GL_EYE_LINEAR);
- PY_DICT_ADD_INT(GL_EYE_PLANE);
- PY_DICT_ADD_INT(GL_FEEDBACK);
- PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_POINTER);
- PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_SIZE);
- PY_DICT_ADD_INT(GL_FEEDBACK_BUFFER_TYPE);
- PY_DICT_ADD_INT(GL_FLAT);
- PY_DICT_ADD_INT(GL_FOG);
- PY_DICT_ADD_INT(GL_FOG_BIT);
- PY_DICT_ADD_INT(GL_FOG_COLOR);
- PY_DICT_ADD_INT(GL_FOG_DENSITY);
- PY_DICT_ADD_INT(GL_FOG_END);
- PY_DICT_ADD_INT(GL_FOG_HINT);
- PY_DICT_ADD_INT(GL_FOG_INDEX);
- PY_DICT_ADD_INT(GL_FOG_MODE);
- PY_DICT_ADD_INT(GL_FOG_START);
- PY_DICT_ADD_INT(GL_GREEN_BIAS);
- PY_DICT_ADD_INT(GL_GREEN_BITS);
- PY_DICT_ADD_INT(GL_GREEN_SCALE);
- PY_DICT_ADD_INT(GL_HINT_BIT);
- PY_DICT_ADD_INT(GL_INDEX_ARRAY);
- PY_DICT_ADD_INT(GL_INDEX_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_INDEX_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_INDEX_ARRAY_TYPE);
- PY_DICT_ADD_INT(GL_INDEX_BITS);
- PY_DICT_ADD_INT(GL_INDEX_CLEAR_VALUE);
- PY_DICT_ADD_INT(GL_INDEX_LOGIC_OP);
- PY_DICT_ADD_INT(GL_INDEX_MODE);
- PY_DICT_ADD_INT(GL_INDEX_OFFSET);
- PY_DICT_ADD_INT(GL_INDEX_SHIFT);
- PY_DICT_ADD_INT(GL_INDEX_WRITEMASK);
- PY_DICT_ADD_INT(GL_INTENSITY);
- PY_DICT_ADD_INT(GL_INTENSITY12);
- PY_DICT_ADD_INT(GL_INTENSITY16);
- PY_DICT_ADD_INT(GL_INTENSITY4);
- PY_DICT_ADD_INT(GL_INTENSITY8);
- PY_DICT_ADD_INT(GL_LIGHT0);
- PY_DICT_ADD_INT(GL_LIGHT1);
- PY_DICT_ADD_INT(GL_LIGHT2);
- PY_DICT_ADD_INT(GL_LIGHT3);
- PY_DICT_ADD_INT(GL_LIGHT4);
- PY_DICT_ADD_INT(GL_LIGHT5);
- PY_DICT_ADD_INT(GL_LIGHT6);
- PY_DICT_ADD_INT(GL_LIGHT7);
- PY_DICT_ADD_INT(GL_LIGHTING);
- PY_DICT_ADD_INT(GL_LIGHTING_BIT);
- PY_DICT_ADD_INT(GL_LIGHT_MODEL_AMBIENT);
- PY_DICT_ADD_INT(GL_LIGHT_MODEL_LOCAL_VIEWER);
- PY_DICT_ADD_INT(GL_LIGHT_MODEL_TWO_SIDE);
- PY_DICT_ADD_INT(GL_LINEAR_ATTENUATION);
- PY_DICT_ADD_INT(GL_LINE_BIT);
- PY_DICT_ADD_INT(GL_LINE_RESET_TOKEN);
- PY_DICT_ADD_INT(GL_LINE_STIPPLE);
- PY_DICT_ADD_INT(GL_LINE_STIPPLE_PATTERN);
- PY_DICT_ADD_INT(GL_LINE_STIPPLE_REPEAT);
- PY_DICT_ADD_INT(GL_LINE_TOKEN);
- PY_DICT_ADD_INT(GL_LIST_BASE);
- PY_DICT_ADD_INT(GL_LIST_BIT);
- PY_DICT_ADD_INT(GL_LIST_INDEX);
- PY_DICT_ADD_INT(GL_LIST_MODE);
- PY_DICT_ADD_INT(GL_LOAD);
- PY_DICT_ADD_INT(GL_LOGIC_OP);
- PY_DICT_ADD_INT(GL_LUMINANCE);
- PY_DICT_ADD_INT(GL_LUMINANCE12);
- PY_DICT_ADD_INT(GL_LUMINANCE12_ALPHA12);
- PY_DICT_ADD_INT(GL_LUMINANCE12_ALPHA4);
- PY_DICT_ADD_INT(GL_LUMINANCE16);
- PY_DICT_ADD_INT(GL_LUMINANCE16_ALPHA16);
- PY_DICT_ADD_INT(GL_LUMINANCE4);
- PY_DICT_ADD_INT(GL_LUMINANCE4_ALPHA4);
- PY_DICT_ADD_INT(GL_LUMINANCE6_ALPHA2);
- PY_DICT_ADD_INT(GL_LUMINANCE8);
- PY_DICT_ADD_INT(GL_LUMINANCE8_ALPHA8);
- PY_DICT_ADD_INT(GL_LUMINANCE_ALPHA);
- PY_DICT_ADD_INT(GL_MAP1_COLOR_4);
- PY_DICT_ADD_INT(GL_MAP1_GRID_DOMAIN);
- PY_DICT_ADD_INT(GL_MAP1_GRID_SEGMENTS);
- PY_DICT_ADD_INT(GL_MAP1_INDEX);
- PY_DICT_ADD_INT(GL_MAP1_NORMAL);
- PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_1);
- PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_2);
- PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_3);
- PY_DICT_ADD_INT(GL_MAP1_TEXTURE_COORD_4);
- PY_DICT_ADD_INT(GL_MAP1_VERTEX_3);
- PY_DICT_ADD_INT(GL_MAP1_VERTEX_4);
- PY_DICT_ADD_INT(GL_MAP2_COLOR_4);
- PY_DICT_ADD_INT(GL_MAP2_GRID_DOMAIN);
- PY_DICT_ADD_INT(GL_MAP2_GRID_SEGMENTS);
- PY_DICT_ADD_INT(GL_MAP2_INDEX);
- PY_DICT_ADD_INT(GL_MAP2_NORMAL);
- PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_1);
- PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_2);
- PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_3);
- PY_DICT_ADD_INT(GL_MAP2_TEXTURE_COORD_4);
- PY_DICT_ADD_INT(GL_MAP2_VERTEX_3);
- PY_DICT_ADD_INT(GL_MAP2_VERTEX_4);
- PY_DICT_ADD_INT(GL_MAP_COLOR);
- PY_DICT_ADD_INT(GL_MAP_STENCIL);
- PY_DICT_ADD_INT(GL_MATRIX_MODE);
- PY_DICT_ADD_INT(GL_MAX_ATTRIB_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_MAX_CLIP_PLANES);
- PY_DICT_ADD_INT(GL_MAX_EVAL_ORDER);
- PY_DICT_ADD_INT(GL_MAX_LIGHTS);
- PY_DICT_ADD_INT(GL_MAX_LIST_NESTING);
- PY_DICT_ADD_INT(GL_MAX_MODELVIEW_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_MAX_NAME_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_MAX_PIXEL_MAP_TABLE);
- PY_DICT_ADD_INT(GL_MAX_PROJECTION_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_MAX_TEXTURE_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_MODELVIEW);
- PY_DICT_ADD_INT(GL_MODELVIEW_MATRIX);
- PY_DICT_ADD_INT(GL_MODELVIEW_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_MODULATE);
- PY_DICT_ADD_INT(GL_MULT);
- PY_DICT_ADD_INT(GL_N3F_V3F);
- PY_DICT_ADD_INT(GL_NAME_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_NORMALIZE);
- PY_DICT_ADD_INT(GL_NORMAL_ARRAY);
- PY_DICT_ADD_INT(GL_NORMAL_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_NORMAL_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_NORMAL_ARRAY_TYPE);
- PY_DICT_ADD_INT(GL_OBJECT_LINEAR);
- PY_DICT_ADD_INT(GL_OBJECT_PLANE);
- PY_DICT_ADD_INT(GL_ORDER);
- PY_DICT_ADD_INT(GL_PASS_THROUGH_TOKEN);
- PY_DICT_ADD_INT(GL_PERSPECTIVE_CORRECTION_HINT);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_A_TO_A);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_A_TO_A_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_B_TO_B);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_B_TO_B_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_G_TO_G);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_G_TO_G_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_A);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_A_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_B);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_B_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_G);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_G_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_I);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_I_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_R);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_I_TO_R_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_R_TO_R);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_R_TO_R_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_S_TO_S);
- PY_DICT_ADD_INT(GL_PIXEL_MAP_S_TO_S_SIZE);
- PY_DICT_ADD_INT(GL_PIXEL_MODE_BIT);
- PY_DICT_ADD_INT(GL_POINT_BIT);
- PY_DICT_ADD_INT(GL_POINT_SMOOTH);
- PY_DICT_ADD_INT(GL_POINT_SMOOTH_HINT);
- PY_DICT_ADD_INT(GL_POINT_TOKEN);
- PY_DICT_ADD_INT(GL_POLYGON);
- PY_DICT_ADD_INT(GL_POLYGON_BIT);
- PY_DICT_ADD_INT(GL_POLYGON_STIPPLE);
- PY_DICT_ADD_INT(GL_POLYGON_STIPPLE_BIT);
- PY_DICT_ADD_INT(GL_POLYGON_TOKEN);
- PY_DICT_ADD_INT(GL_POSITION);
- PY_DICT_ADD_INT(GL_PROJECTION);
- PY_DICT_ADD_INT(GL_PROJECTION_MATRIX);
- PY_DICT_ADD_INT(GL_PROJECTION_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_Q);
- PY_DICT_ADD_INT(GL_QUADRATIC_ATTENUATION);
- PY_DICT_ADD_INT(GL_QUADS);
- PY_DICT_ADD_INT(GL_QUAD_STRIP);
- PY_DICT_ADD_INT(GL_R);
- PY_DICT_ADD_INT(GL_RED_BIAS);
- PY_DICT_ADD_INT(GL_RED_BITS);
- PY_DICT_ADD_INT(GL_RED_SCALE);
- PY_DICT_ADD_INT(GL_RENDER);
- PY_DICT_ADD_INT(GL_RENDER_MODE);
- PY_DICT_ADD_INT(GL_RETURN);
- PY_DICT_ADD_INT(GL_RGBA_MODE);
- PY_DICT_ADD_INT(GL_S);
- PY_DICT_ADD_INT(GL_SCISSOR_BIT);
- PY_DICT_ADD_INT(GL_SELECT);
- PY_DICT_ADD_INT(GL_SELECTION_BUFFER_POINTER);
- PY_DICT_ADD_INT(GL_SELECTION_BUFFER_SIZE);
- PY_DICT_ADD_INT(GL_SHADE_MODEL);
- PY_DICT_ADD_INT(GL_SHININESS);
- PY_DICT_ADD_INT(GL_SMOOTH);
- PY_DICT_ADD_INT(GL_SPECULAR);
- PY_DICT_ADD_INT(GL_SPHERE_MAP);
- PY_DICT_ADD_INT(GL_SPOT_CUTOFF);
- PY_DICT_ADD_INT(GL_SPOT_DIRECTION);
- PY_DICT_ADD_INT(GL_SPOT_EXPONENT);
- PY_DICT_ADD_INT(GL_STACK_OVERFLOW);
- PY_DICT_ADD_INT(GL_STACK_UNDERFLOW);
- PY_DICT_ADD_INT(GL_STENCIL_BITS);
- PY_DICT_ADD_INT(GL_T);
- PY_DICT_ADD_INT(GL_T2F_C3F_V3F);
- PY_DICT_ADD_INT(GL_T2F_C4F_N3F_V3F);
- PY_DICT_ADD_INT(GL_T2F_C4UB_V3F);
- PY_DICT_ADD_INT(GL_T2F_N3F_V3F);
- PY_DICT_ADD_INT(GL_T2F_V3F);
- PY_DICT_ADD_INT(GL_T4F_C4F_N3F_V4F);
- PY_DICT_ADD_INT(GL_T4F_V4F);
- PY_DICT_ADD_INT(GL_TEXTURE_BIT);
- PY_DICT_ADD_INT(GL_TEXTURE_BORDER);
- PY_DICT_ADD_INT(GL_TEXTURE_COMPONENTS);
- PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY);
- PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_SIZE);
- PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_TYPE);
- PY_DICT_ADD_INT(GL_TEXTURE_ENV);
- PY_DICT_ADD_INT(GL_TEXTURE_ENV_COLOR);
- PY_DICT_ADD_INT(GL_TEXTURE_ENV_MODE);
- PY_DICT_ADD_INT(GL_TEXTURE_GEN_MODE);
- PY_DICT_ADD_INT(GL_TEXTURE_GEN_Q);
- PY_DICT_ADD_INT(GL_TEXTURE_GEN_R);
- PY_DICT_ADD_INT(GL_TEXTURE_GEN_S);
- PY_DICT_ADD_INT(GL_TEXTURE_GEN_T);
- PY_DICT_ADD_INT(GL_TEXTURE_INTENSITY_SIZE);
- PY_DICT_ADD_INT(GL_TEXTURE_LUMINANCE_SIZE);
- PY_DICT_ADD_INT(GL_TEXTURE_MATRIX);
- PY_DICT_ADD_INT(GL_TEXTURE_PRIORITY);
- PY_DICT_ADD_INT(GL_TEXTURE_RESIDENT);
- PY_DICT_ADD_INT(GL_TEXTURE_STACK_DEPTH);
- PY_DICT_ADD_INT(GL_TRANSFORM_BIT);
- PY_DICT_ADD_INT(GL_V2F);
- PY_DICT_ADD_INT(GL_V3F);
- PY_DICT_ADD_INT(GL_VERTEX_ARRAY);
- PY_DICT_ADD_INT(GL_VERTEX_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_VERTEX_ARRAY_SIZE);
- PY_DICT_ADD_INT(GL_VERTEX_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_VERTEX_ARRAY_TYPE);
- PY_DICT_ADD_INT(GL_VIEWPORT_BIT);
- PY_DICT_ADD_INT(GL_ZOOM_X);
- PY_DICT_ADD_INT(GL_ZOOM_Y);
- }
-
/* GL_VERSION_1_2 */
{
@@ -2974,15 +1920,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_UNSIGNED_SHORT_5_6_5);
PY_DICT_ADD_INT(GL_UNSIGNED_SHORT_5_6_5_REV);
}
- /* adding in GL_VERSION_1_2 removed from core profile */
- if (use_deprecated == true) {
- PY_DICT_ADD_INT(GL_ALIASED_POINT_SIZE_RANGE);
- PY_DICT_ADD_INT(GL_LIGHT_MODEL_COLOR_CONTROL);
- PY_DICT_ADD_INT(GL_RESCALE_NORMAL);
- PY_DICT_ADD_INT(GL_SEPARATE_SPECULAR_COLOR);
- PY_DICT_ADD_INT(GL_SINGLE_COLOR);
- }
-
/* GL_VERSION_1_3 */
{
@@ -3046,47 +1983,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y);
PY_DICT_ADD_INT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z);
}
- /* adding in GL_VERSION_1_3 removed from core profile */
- if (use_deprecated == true) {
- PY_DICT_ADD_INT(GL_ADD_SIGNED);
- PY_DICT_ADD_INT(GL_CLIENT_ACTIVE_TEXTURE);
- PY_DICT_ADD_INT(GL_COMBINE);
- PY_DICT_ADD_INT(GL_COMBINE_ALPHA);
- PY_DICT_ADD_INT(GL_COMBINE_RGB);
- PY_DICT_ADD_INT(GL_COMPRESSED_ALPHA);
- PY_DICT_ADD_INT(GL_COMPRESSED_INTENSITY);
- PY_DICT_ADD_INT(GL_COMPRESSED_LUMINANCE);
- PY_DICT_ADD_INT(GL_COMPRESSED_LUMINANCE_ALPHA);
- PY_DICT_ADD_INT(GL_CONSTANT);
- PY_DICT_ADD_INT(GL_DOT3_RGB);
- PY_DICT_ADD_INT(GL_DOT3_RGBA);
- PY_DICT_ADD_INT(GL_INTERPOLATE);
- PY_DICT_ADD_INT(GL_MAX_TEXTURE_UNITS);
- PY_DICT_ADD_INT(GL_MULTISAMPLE_BIT);
- PY_DICT_ADD_INT(GL_NORMAL_MAP);
- PY_DICT_ADD_INT(GL_OPERAND0_ALPHA);
- PY_DICT_ADD_INT(GL_OPERAND0_RGB);
- PY_DICT_ADD_INT(GL_OPERAND1_ALPHA);
- PY_DICT_ADD_INT(GL_OPERAND1_RGB);
- PY_DICT_ADD_INT(GL_OPERAND2_ALPHA);
- PY_DICT_ADD_INT(GL_OPERAND2_RGB);
- PY_DICT_ADD_INT(GL_PREVIOUS);
- PY_DICT_ADD_INT(GL_PRIMARY_COLOR);
- PY_DICT_ADD_INT(GL_REFLECTION_MAP);
- PY_DICT_ADD_INT(GL_RGB_SCALE);
- PY_DICT_ADD_INT(GL_SOURCE0_ALPHA);
- PY_DICT_ADD_INT(GL_SOURCE0_RGB);
- PY_DICT_ADD_INT(GL_SOURCE1_ALPHA);
- PY_DICT_ADD_INT(GL_SOURCE1_RGB);
- PY_DICT_ADD_INT(GL_SOURCE2_ALPHA);
- PY_DICT_ADD_INT(GL_SOURCE2_RGB);
- PY_DICT_ADD_INT(GL_SUBTRACT);
- PY_DICT_ADD_INT(GL_TRANSPOSE_COLOR_MATRIX);
- PY_DICT_ADD_INT(GL_TRANSPOSE_MODELVIEW_MATRIX);
- PY_DICT_ADD_INT(GL_TRANSPOSE_PROJECTION_MATRIX);
- PY_DICT_ADD_INT(GL_TRANSPOSE_TEXTURE_MATRIX);
- }
-
/* GL_VERSION_1_4 */
{
@@ -3116,33 +2012,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_TEXTURE_DEPTH_SIZE);
PY_DICT_ADD_INT(GL_TEXTURE_LOD_BIAS);
}
- /* adding in GL_VERSION_1_4 removed from core profile */
- if (use_deprecated == true) {
- PY_DICT_ADD_INT(GL_COLOR_SUM);
- PY_DICT_ADD_INT(GL_COMPARE_R_TO_TEXTURE);
- PY_DICT_ADD_INT(GL_CURRENT_FOG_COORDINATE);
- PY_DICT_ADD_INT(GL_CURRENT_SECONDARY_COLOR);
- PY_DICT_ADD_INT(GL_DEPTH_TEXTURE_MODE);
- PY_DICT_ADD_INT(GL_FOG_COORDINATE);
- PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY);
- PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_TYPE);
- PY_DICT_ADD_INT(GL_FOG_COORDINATE_SOURCE);
- PY_DICT_ADD_INT(GL_FRAGMENT_DEPTH);
- PY_DICT_ADD_INT(GL_GENERATE_MIPMAP);
- PY_DICT_ADD_INT(GL_GENERATE_MIPMAP_HINT);
- PY_DICT_ADD_INT(GL_POINT_DISTANCE_ATTENUATION);
- PY_DICT_ADD_INT(GL_POINT_SIZE_MAX);
- PY_DICT_ADD_INT(GL_POINT_SIZE_MIN);
- PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY);
- PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_SIZE);
- PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_TYPE);
- PY_DICT_ADD_INT(GL_TEXTURE_FILTER_CONTROL);
- }
-
/* GL_VERSION_1_5 */
{
@@ -3165,7 +2034,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_READ_ONLY);
PY_DICT_ADD_INT(GL_READ_WRITE);
PY_DICT_ADD_INT(GL_SAMPLES_PASSED);
- PY_DICT_ADD_INT(GL_SRC1_ALPHA);
PY_DICT_ADD_INT(GL_STATIC_COPY);
PY_DICT_ADD_INT(GL_STATIC_DRAW);
PY_DICT_ADD_INT(GL_STATIC_READ);
@@ -3175,32 +2043,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
PY_DICT_ADD_INT(GL_WRITE_ONLY);
}
- /* adding in GL_VERSION_1_5 removed from core profile */
- if (use_deprecated == true) {
- PY_DICT_ADD_INT(GL_COLOR_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_CURRENT_FOG_COORD);
- PY_DICT_ADD_INT(GL_EDGE_FLAG_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_FOG_COORD);
- PY_DICT_ADD_INT(GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY);
- PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_POINTER);
- PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_STRIDE);
- PY_DICT_ADD_INT(GL_FOG_COORD_ARRAY_TYPE);
- PY_DICT_ADD_INT(GL_FOG_COORD_SRC);
- PY_DICT_ADD_INT(GL_INDEX_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_NORMAL_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_SRC0_ALPHA);
- PY_DICT_ADD_INT(GL_SRC0_RGB);
- PY_DICT_ADD_INT(GL_SRC1_RGB);
- PY_DICT_ADD_INT(GL_SRC2_ALPHA);
- PY_DICT_ADD_INT(GL_SRC2_RGB);
- PY_DICT_ADD_INT(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_VERTEX_ARRAY_BUFFER_BINDING);
- PY_DICT_ADD_INT(GL_WEIGHT_ARRAY_BUFFER_BINDING);
- }
-
/* GL_VERSION_2_0 */
{
@@ -3285,14 +2127,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_VERTEX_PROGRAM_POINT_SIZE);
PY_DICT_ADD_INT(GL_VERTEX_SHADER);
}
- /* adding in GL_VERSION_2_0 removed from core profile */
- if (use_deprecated == true) {
- PY_DICT_ADD_INT(GL_COORD_REPLACE);
- PY_DICT_ADD_INT(GL_MAX_TEXTURE_COORDS);
- PY_DICT_ADD_INT(GL_POINT_SPRITE);
- PY_DICT_ADD_INT(GL_VERTEX_PROGRAM_TWO_SIDE);
- }
-
/* GL_VERSION_2_1 */
{
@@ -3313,16 +2147,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_SRGB8_ALPHA8);
PY_DICT_ADD_INT(GL_SRGB_ALPHA);
}
- /* adding in GL_VERSION_2_1 removed from core profile */
- if (use_deprecated == true) {
- PY_DICT_ADD_INT(GL_COMPRESSED_SLUMINANCE);
- PY_DICT_ADD_INT(GL_COMPRESSED_SLUMINANCE_ALPHA);
- PY_DICT_ADD_INT(GL_CURRENT_RASTER_SECONDARY_COLOR);
- PY_DICT_ADD_INT(GL_SLUMINANCE);
- PY_DICT_ADD_INT(GL_SLUMINANCE8);
- PY_DICT_ADD_INT(GL_SLUMINANCE8_ALPHA8);
- PY_DICT_ADD_INT(GL_SLUMINANCE_ALPHA);
- }
/* GL_VERSION_3_0 */
{
@@ -3563,14 +2387,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_VERTEX_ARRAY_BINDING);
PY_DICT_ADD_INT(GL_VERTEX_ATTRIB_ARRAY_INTEGER);
}
- /* adding in GL_VERSION_3_0 removed from core profile */
- if (use_deprecated == true) {
- PY_DICT_ADD_INT(GL_ALPHA_INTEGER);
- PY_DICT_ADD_INT(GL_CLAMP_FRAGMENT_COLOR);
- PY_DICT_ADD_INT(GL_CLAMP_VERTEX_COLOR);
- PY_DICT_ADD_INT(GL_TEXTURE_INTENSITY_TYPE);
- PY_DICT_ADD_INT(GL_TEXTURE_LUMINANCE_TYPE);
- }
/* GL_VERSION_3_1 */
{
@@ -3637,7 +2453,6 @@ PyObject *BPyInit_bgl(void)
PY_DICT_ADD_INT(GL_UNSIGNED_INT_SAMPLER_BUFFER);
}
-
/* GL_VERSION_3_2 */
{
PY_DICT_ADD_INT(GL_ALREADY_SIGNALED);
diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c
index 7d124966334..7337706639f 100644
--- a/source/blender/python/generic/blf_py_api.c
+++ b/source/blender/python/generic/blf_py_api.c
@@ -114,6 +114,41 @@ static PyObject *py_blf_aspect(PyObject *UNUSED(self), PyObject *args)
}
+PyDoc_STRVAR(py_blf_color_doc,
+".. function:: color(fontid, r, g, b, a)\n"
+"\n"
+" Set the color for drawing text.\n"
+"\n"
+" :arg fontid: The id of the typeface as returned by :func:`blf.load`, for default font use 0.\n"
+" :type fontid: int\n"
+" :arg r: red channel 0.0 - 1.0.\n"
+" :type r: float\n"
+" :arg g: green channel 0.0 - 1.0.\n"
+" :type g: float\n"
+" :arg b: blue channel 0.0 - 1.0.\n"
+" :type b: float\n"
+" :arg a: alpha channel 0.0 - 1.0.\n"
+" :type a: float\n"
+);
+static PyObject *py_blf_color(PyObject *UNUSED(self), PyObject *args)
+{
+ int fontid;
+ float rgba[4];
+
+ if (!PyArg_ParseTuple(
+ args, "iffff:blf.color",
+ &fontid, &rgba[0], &rgba[1], &rgba[2], &rgba[3]))
+ {
+ return NULL;
+ }
+
+ BLF_color4fv(fontid, rgba);
+
+ Py_RETURN_NONE;
+}
+
+
+#if BLF_BLUR_ENABLE
PyDoc_STRVAR(py_blf_blur_doc,
".. function:: blur(fontid, radius)\n"
"\n"
@@ -135,6 +170,7 @@ static PyObject *py_blf_blur(PyObject *UNUSED(self), PyObject *args)
Py_RETURN_NONE;
}
+#endif
PyDoc_STRVAR(py_blf_draw_doc,
@@ -418,7 +454,9 @@ static PyObject *py_blf_unload(PyObject *UNUSED(self), PyObject *args)
/*----------------------------MODULE INIT-------------------------*/
static PyMethodDef BLF_methods[] = {
{"aspect", (PyCFunction) py_blf_aspect, METH_VARARGS, py_blf_aspect_doc},
+#if BLF_BLUR_ENABLE
{"blur", (PyCFunction) py_blf_blur, METH_VARARGS, py_blf_blur_doc},
+#endif
{"clipping", (PyCFunction) py_blf_clipping, METH_VARARGS, py_blf_clipping_doc},
{"word_wrap", (PyCFunction) py_blf_word_wrap, METH_VARARGS, py_blf_word_wrap_doc},
{"disable", (PyCFunction) py_blf_disable, METH_VARARGS, py_blf_disable_doc},
@@ -430,6 +468,7 @@ static PyMethodDef BLF_methods[] = {
{"shadow", (PyCFunction) py_blf_shadow, METH_VARARGS, py_blf_shadow_doc},
{"shadow_offset", (PyCFunction) py_blf_shadow_offset, METH_VARARGS, py_blf_shadow_offset_doc},
{"size", (PyCFunction) py_blf_size, METH_VARARGS, py_blf_size_doc},
+ {"color", (PyCFunction) py_blf_color, METH_VARARGS, py_blf_color_doc},
{"load", (PyCFunction) py_blf_load, METH_VARARGS, py_blf_load_doc},
{"unload", (PyCFunction) py_blf_unload, METH_VARARGS, py_blf_unload_doc},
{NULL, NULL, 0, NULL}
diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c
index 553f7e43e45..926de79d0ff 100644
--- a/source/blender/python/generic/bpy_internal_import.c
+++ b/source/blender/python/generic/bpy_internal_import.c
@@ -43,9 +43,9 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_main.h"
/* UNUSED */
#include "BKE_text.h" /* txt_to_buf */
-#include "BKE_main.h"
#include "py_capi_utils.h"
@@ -116,16 +116,6 @@ void bpy_import_main_set(struct Main *maggie)
bpy_import_main = maggie;
}
-void bpy_import_main_extra_add(struct Main *maggie)
-{
- BLI_addhead(&bpy_import_main_list, maggie);
-}
-
-void bpy_import_main_extra_remove(struct Main *maggie)
-{
- BLI_remlink_safe(&bpy_import_main_list, maggie);
-}
-
/* returns a dummy filename for a textblock so we can tell what file a text block comes from */
void bpy_text_filename_get(char *fn, size_t fn_len, Text *text)
{
diff --git a/source/blender/python/generic/bpy_internal_import.h b/source/blender/python/generic/bpy_internal_import.h
index 29b11fbe8ff..8de1436ed48 100644
--- a/source/blender/python/generic/bpy_internal_import.h
+++ b/source/blender/python/generic/bpy_internal_import.h
@@ -51,12 +51,7 @@ PyObject *bpy_text_reimport(PyObject *module, int *found);
void bpy_text_filename_get(char *fn, size_t fn_len, struct Text *text);
-/* The game engine has its own Main struct, if this is set search this rather than G_MAIN */
struct Main *bpy_import_main_get(void);
void bpy_import_main_set(struct Main *maggie);
-/* This is used for importing text from dynamically loaded libraries in the game engine */
-void bpy_import_main_extra_add(struct Main *maggie);
-void bpy_import_main_extra_remove(struct Main *maggie);
-
#endif /* __BPY_INTERNAL_IMPORT_H__ */
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 918ec8fa018..072c11b14e5 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -422,11 +422,18 @@ static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob)
return IDP_New(IDP_STRING, &val, name);
}
-static int idp_array_type_from_format_char(char format)
+static int idp_array_type_from_formatstr_and_size(const char *typestr, Py_ssize_t itemsize)
{
- if (format == 'i') return IDP_INT;
- if (format == 'f') return IDP_FLOAT;
- if (format == 'd') return IDP_DOUBLE;
+ char format = PyC_StructFmt_type_from_str(typestr);
+
+ if (PyC_StructFmt_type_is_float_any(format)) {
+ if (itemsize == 4) return IDP_FLOAT;
+ if (itemsize == 8) return IDP_DOUBLE;
+ }
+ if (PyC_StructFmt_type_is_int_any(format)) {
+ if (itemsize == 4) return IDP_INT;
+ }
+
return -1;
}
@@ -443,13 +450,13 @@ static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffe
IDProperty *prop;
IDPropertyTemplate val = {0};
- int format = idp_array_type_from_format_char(*buffer->format);
- if (format == -1) {
+ int id_type = idp_array_type_from_formatstr_and_size(buffer->format, buffer->itemsize);
+ if (id_type == -1) {
/* should never happen as the type has been checked before */
return NULL;
}
else {
- val.array.type = format;
+ val.array.type = id_type;
val.array.len = buffer->len / buffer->itemsize;
}
prop = IDP_New(IDP_ARRAY, &val, name);
@@ -533,8 +540,10 @@ static IDProperty *idp_from_PySequence(const char *name, PyObject *ob)
if (PyObject_CheckBuffer(ob)) {
PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT);
- char format = *buffer.format;
- if (ELEM(format, 'i', 'f', 'd')) {
+ char format = PyC_StructFmt_type_from_str(buffer.format);
+ if (PyC_StructFmt_type_is_float_any(format) ||
+ (PyC_StructFmt_type_is_int_any(format) && buffer.itemsize == 4))
+ {
use_buffer = true;
}
else {
@@ -1802,7 +1811,6 @@ PyObject *BPyInit_idprop(void)
/* idprop.types */
PyModule_AddObject(mod, "types", (submodule = BPyInit_idprop_types()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
return mod;
}
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 62b24618d3f..991a035f683 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -1327,6 +1327,84 @@ uint32_t PyC_Long_AsU32(PyObject *value)
* PyC_Long_AsU64
*/
+/* -------------------------------------------------------------------- */
+
+/** \name Py_buffer Utils
+ *
+ * \{ */
+
+char PyC_StructFmt_type_from_str(const char *typestr)
+{
+ switch (typestr[0]) {
+ case '!':
+ case '<':
+ case '=':
+ case '>':
+ case '@':
+ return typestr[1];
+ default:
+ return typestr[0];
+ }
+}
+
+bool PyC_StructFmt_type_is_float_any(char format)
+{
+ switch (format) {
+ case 'f':
+ case 'd':
+ case 'e':
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool PyC_StructFmt_type_is_int_any(char format)
+{
+ switch (format) {
+ case 'i':
+ case 'I':
+ case 'l':
+ case 'L':
+ case 'h':
+ case 'H':
+ case 'b':
+ case 'B':
+ case 'q':
+ case 'Q':
+ case 'n':
+ case 'N':
+ case 'P':
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool PyC_StructFmt_type_is_byte(char format)
+{
+ switch (format) {
+ case 'c':
+ case 's':
+ case 'p':
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool PyC_StructFmt_type_is_bool(char format)
+{
+ switch (format) {
+ case '?':
+ return true;
+ default:
+ return false;
+ }
+}
+
+/** \} */
+
#ifdef __GNUC__
# pragma warning(pop)
#endif
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 4cf6d6b26de..21e4ecf2e86 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -76,7 +76,7 @@ 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 */
+/* name namespace function for bpy */
PyObject *PyC_DefaultNameSpace(const char *filename);
void PyC_RunQuicky(const char *filepath, int n, ...);
bool PyC_NameSpace_ImportArray(PyObject *py_dict, const char *imports[]);
@@ -131,4 +131,11 @@ Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value) { return (int32_t)_PyL
Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value) { return (int64_t)PyLong_AsLongLong(value); }
Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value) { return (uint64_t)PyLong_AsUnsignedLongLong(value); }
+/* utils for format string in `struct` module style syntax */
+char PyC_StructFmt_type_from_str(const char *typestr);
+bool PyC_StructFmt_type_is_float_any(char format);
+bool PyC_StructFmt_type_is_int_any(char format);
+bool PyC_StructFmt_type_is_byte(char format);
+bool PyC_StructFmt_type_is_bool(char format);
+
#endif /* __PY_CAPI_UTILS_H__ */
diff --git a/source/blender/python/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt
new file mode 100644
index 00000000000..0d4dedf7c76
--- /dev/null
+++ b/source/blender/python/gpu/CMakeLists.txt
@@ -0,0 +1,64 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Contributor(s): Campbell Barton
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../../blenkernel
+ ../../blenlib
+ ../../gpu
+ ../../makesdna
+ ../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
+)
+
+set(INC_SYS
+ ${GLEW_INCLUDE_PATH}
+ ${PYTHON_INCLUDE_DIRS}
+)
+
+set(SRC
+ gpu_py_api.c
+ gpu_py_batch.c
+ gpu_py_element.c
+ gpu_py_matrix.c
+ gpu_py_offscreen.c
+ gpu_py_primitive.c
+ gpu_py_select.c
+ gpu_py_shader.c
+ gpu_py_types.c
+ gpu_py_vertex_buffer.c
+ gpu_py_vertex_format.c
+
+ gpu_py_api.h
+ gpu_py_batch.h
+ gpu_py_element.h
+ gpu_py_matrix.h
+ gpu_py_offscreen.h
+ gpu_py_primitive.h
+ gpu_py_select.h
+ gpu_py_shader.h
+ gpu_py_types.h
+ gpu_py_vertex_buffer.h
+ gpu_py_vertex_format.h
+)
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_python_gpu "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c
new file mode 100644
index 00000000000..373bce160b7
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_api.c
@@ -0,0 +1,85 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_api.c
+ * \ingroup bpygpu
+ *
+ * Experimental Python API, not considered public yet (called '_gpu'),
+ * we may re-expose as public later.
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "BLI_utildefines.h"
+
+#include "../generic/python_utildefines.h"
+
+#include "gpu_py_matrix.h"
+#include "gpu_py_select.h"
+#include "gpu_py_types.h"
+
+#include "gpu_py_api.h" /* own include */
+
+PyDoc_STRVAR(GPU_doc,
+"This module provides Python wrappers for the GPU implementation in Blender. "
+"Some higher level functions can be found in the `gpu_extras` module. "
+"\n\n"
+"Submodules:\n"
+"\n"
+".. toctree::\n"
+" :maxdepth: 1\n"
+"\n"
+" gpu.types.rst\n"
+" gpu.shader.rst\n"
+" gpu.matrix.rst\n"
+" gpu.select.rst\n"
+"\n"
+);
+static struct PyModuleDef GPU_module_def = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "gpu",
+ .m_doc = GPU_doc,
+};
+
+PyObject *BPyInit_gpu(void)
+{
+ PyObject *sys_modules = PyImport_GetModuleDict();
+ PyObject *submodule;
+ PyObject *mod;
+
+ mod = PyModule_Create(&GPU_module_def);
+
+ PyModule_AddObject(mod, "types", (submodule = BPyInit_gpu_types()));
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
+
+ PyModule_AddObject(mod, "matrix", (submodule = BPyInit_gpu_matrix()));
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
+
+ PyModule_AddObject(mod, "select", (submodule = BPyInit_gpu_select()));
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
+
+ PyModule_AddObject(mod, "shader", (submodule = BPyInit_gpu_shader()));
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
+
+ return mod;
+}
diff --git a/source/blender/render/intern/include/texture_ocean.h b/source/blender/python/gpu/gpu_py_api.h
index 6d7bc6fe7b0..20eafb3d140 100644
--- a/source/blender/render/intern/include/texture_ocean.h
+++ b/source/blender/python/gpu/gpu_py_api.h
@@ -15,21 +15,16 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributors: Matt Ebb
- *
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __TEXTURE_OCEAN_H__
-#define __TEXTURE_OCEAN_H__
-
-/** \file blender/render/intern/include/texture_ocean.h
- * \ingroup render
+/** \file blender/python/gpu/gpu_py_api.h
+ * \ingroup bpygpu
*/
-int ocean_texture(struct Tex *tex, const float texvec[2], struct TexResult *texres);
+#ifndef __GPU_PY_API_H__
+#define __GPU_PY_API_H__
+
+PyObject *BPyInit_gpu(void);
-#endif /* __TEXTURE_OCEAN_H__ */
+#endif /* __GPU_PY_API_H__ */
diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c
new file mode 100644
index 00000000000..ffbd2a17e34
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_batch.c
@@ -0,0 +1,384 @@
+/*
+ * ***** 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.
+ *
+ * Copyright 2015, Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_batch.c
+ * \ingroup bpygpu
+ *
+ * This file defines the offscreen functionalities of the 'gpu' module
+ * used for off-screen OpenGL rendering.
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+
+#include "GPU_batch.h"
+
+#include "../mathutils/mathutils.h"
+
+#include "../generic/py_capi_utils.h"
+
+#include "gpu_py_primitive.h"
+#include "gpu_py_shader.h"
+#include "gpu_py_vertex_buffer.h"
+#include "gpu_py_element.h"
+#include "gpu_py_batch.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Utility Functions
+ * \{ */
+
+static bool bpygpu_batch_is_program_or_error(BPyGPUBatch *self)
+{
+ if (!glIsProgram(self->batch->program)) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "batch does not have any program assigned to it");
+ return false;
+ }
+ return true;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name GPUBatch Type
+ * \{ */
+
+static PyObject *bpygpu_Batch_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
+{
+ const char *exc_str_missing_arg = "GPUBatch.__new__() missing required argument '%s' (pos %d)";
+
+ struct {
+ GPUPrimType type_id;
+ BPyGPUVertBuf *py_vertbuf;
+ BPyGPUIndexBuf *py_indexbuf;
+ } params = {GPU_PRIM_NONE, NULL, NULL};
+
+ static const char *_keywords[] = {"type", "buf", "elem", NULL};
+ static _PyArg_Parser _parser = {"|$O&O!O!:GPUBatch.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ bpygpu_ParsePrimType, &params.type_id,
+ &BPyGPUVertBuf_Type, &params.py_vertbuf,
+ &BPyGPUIndexBuf_Type, &params.py_indexbuf))
+ {
+ return NULL;
+ }
+
+ if (params.type_id == GPU_PRIM_NONE) {
+ PyErr_Format(PyExc_TypeError,
+ exc_str_missing_arg, _keywords[0], 1);
+ return NULL;
+ }
+
+ if (params.py_vertbuf == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ exc_str_missing_arg, _keywords[1], 2);
+ return NULL;
+ }
+
+ GPUBatch *batch = GPU_batch_create(
+ params.type_id,
+ params.py_vertbuf->buf,
+ params.py_indexbuf ? params.py_indexbuf->elem : NULL);
+
+ BPyGPUBatch *ret = (BPyGPUBatch *)BPyGPUBatch_CreatePyObject(batch);
+
+#ifdef USE_GPU_PY_REFERENCES
+ ret->references = PyList_New(params.py_indexbuf ? 2 : 1);
+ PyList_SET_ITEM(ret->references, 0, (PyObject *)params.py_vertbuf);
+ Py_INCREF(params.py_vertbuf);
+
+ if (params.py_indexbuf != NULL) {
+ PyList_SET_ITEM(ret->references, 1, (PyObject *)params.py_indexbuf);
+ Py_INCREF(params.py_indexbuf);
+ }
+
+ PyObject_GC_Track(ret);
+#endif
+
+ return (PyObject *)ret;
+}
+
+PyDoc_STRVAR(bpygpu_Batch_vertbuf_add_doc,
+".. method:: vertbuf_add(buf)\n"
+"\n"
+" Add another vertex buffer to the Batch.\n"
+" It is not possible to add more vertices to the batch using this method.\n"
+" Instead it can be used to add more attributes to the existing vertices.\n"
+" A good use case would be when you have a separate vertex buffer for vertex positions and vertex normals.\n"
+" Current a batch can have at most " STRINGIFY(GPU_BATCH_VBO_MAX_LEN) " vertex buffers.\n"
+"\n"
+" :param buf: The vertex buffer that will be added to the batch.\n"
+" :type buf: :class:`gpu.types.GPUVertBuf`\n"
+);
+static PyObject *bpygpu_Batch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_buf)
+{
+ if (!BPyGPUVertBuf_Check(py_buf)) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected a GPUVertBuf, got %s",
+ Py_TYPE(py_buf)->tp_name);
+ return NULL;
+ }
+
+ if (self->batch->verts[0]->vertex_len != py_buf->buf->vertex_len) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected %d length, got %d",
+ self->batch->verts[0]->vertex_len, py_buf->buf->vertex_len);
+ return NULL;
+ }
+
+ if (self->batch->verts[GPU_BATCH_VBO_MAX_LEN - 1] != NULL) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "Maximum number of vertex buffers exceeded: " STRINGIFY(GPU_BATCH_VBO_MAX_LEN));
+ return NULL;
+ }
+
+#ifdef USE_GPU_PY_REFERENCES
+ /* Hold user */
+ PyList_Append(self->references, (PyObject *)py_buf);
+#endif
+
+ GPU_batch_vertbuf_add(self->batch, py_buf->buf);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_Batch_program_set_doc,
+".. method:: program_set(program)\n"
+"\n"
+" Assign a shader to this batch that will be used for drawing when not overwritten later.\n"
+" Note: This method has to be called in the draw context that the batch will be drawn in.\n"
+" This function does not need to be called when you always set the shader when calling `batch.draw`.\n"
+"\n"
+" :param program: The program/shader the batch will use in future draw calls.\n"
+" :type program: :class:`gpu.types.GPUShader`\n"
+);
+static PyObject *bpygpu_Batch_program_set(BPyGPUBatch *self, BPyGPUShader *py_shader)
+{
+ if (!BPyGPUShader_Check(py_shader)) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected a GPUShader, got %s",
+ Py_TYPE(py_shader)->tp_name);
+ return NULL;
+ }
+
+ GPUShader *shader = py_shader->shader;
+ GPU_batch_program_set(
+ self->batch,
+ GPU_shader_get_program(shader),
+ GPU_shader_get_interface(shader));
+
+#ifdef USE_GPU_PY_REFERENCES
+ /* Remove existing user (if any), hold new user. */
+ int i = PyList_GET_SIZE(self->references);
+ while (--i != -1) {
+ PyObject *py_shader_test = PyList_GET_ITEM(self->references, i);
+ if (BPyGPUShader_Check(py_shader_test)) {
+ PyList_SET_ITEM(self->references, i, (PyObject *)py_shader);
+ Py_INCREF(py_shader);
+ Py_DECREF(py_shader_test);
+ /* Only ever reference one shader. */
+ break;
+ }
+ }
+ if (i != -1) {
+ PyList_Append(self->references, (PyObject *)py_shader);
+ }
+#endif
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_Batch_draw_doc,
+".. method:: draw(program=None)\n"
+"\n"
+" Run the drawing program with the parameters assigned to the batch.\n"
+"\n"
+" :param program: Program that performs the drawing operations.\n"
+" If ``None`` is passed, the last program setted to this batch will run.\n"
+" :type program: :class:`gpu.types.GPUShader`\n"
+);
+static PyObject *bpygpu_Batch_draw(BPyGPUBatch *self, PyObject *args)
+{
+ BPyGPUShader *py_program = NULL;
+
+ if (!PyArg_ParseTuple(
+ args, "|O!:GPUBatch.draw",
+ &BPyGPUShader_Type, &py_program))
+ {
+ return NULL;
+ }
+ else if (py_program == NULL) {
+ if (!bpygpu_batch_is_program_or_error(self)) {
+ return NULL;
+ }
+ }
+ else if (self->batch->program != GPU_shader_get_program(py_program->shader)) {
+ GPU_batch_program_set(
+ self->batch,
+ GPU_shader_get_program(py_program->shader),
+ GPU_shader_get_interface(py_program->shader));
+ }
+
+ GPU_batch_draw(self->batch);
+ Py_RETURN_NONE;
+}
+
+static PyObject *bpygpu_Batch_program_use_begin(BPyGPUBatch *self)
+{
+ if (!bpygpu_batch_is_program_or_error(self)) {
+ return NULL;
+ }
+ GPU_batch_program_use_begin(self->batch);
+ Py_RETURN_NONE;
+}
+
+static PyObject *bpygpu_Batch_program_use_end(BPyGPUBatch *self)
+{
+ if (!bpygpu_batch_is_program_or_error(self)) {
+ return NULL;
+ }
+ GPU_batch_program_use_end(self->batch);
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef bpygpu_Batch_methods[] = {
+ {"vertbuf_add", (PyCFunction)bpygpu_Batch_vertbuf_add,
+ METH_O, bpygpu_Batch_vertbuf_add_doc},
+ {"program_set", (PyCFunction)bpygpu_Batch_program_set,
+ METH_O, bpygpu_Batch_program_set_doc},
+ {"draw", (PyCFunction) bpygpu_Batch_draw,
+ METH_VARARGS, bpygpu_Batch_draw_doc},
+ {"_program_use_begin", (PyCFunction)bpygpu_Batch_program_use_begin,
+ METH_NOARGS, ""},
+ {"_program_use_end", (PyCFunction)bpygpu_Batch_program_use_end,
+ METH_NOARGS, ""},
+ {NULL, NULL, 0, NULL}
+};
+
+#ifdef USE_GPU_PY_REFERENCES
+
+static int bpygpu_Batch_traverse(BPyGPUBatch *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->references);
+ return 0;
+}
+
+static int bpygpu_Batch_clear(BPyGPUBatch *self)
+{
+ Py_CLEAR(self->references);
+ return 0;
+}
+
+#endif
+
+static void bpygpu_Batch_dealloc(BPyGPUBatch *self)
+{
+ GPU_batch_discard(self->batch);
+
+#ifdef USE_GPU_PY_REFERENCES
+ if (self->references) {
+ PyObject_GC_UnTrack(self);
+ bpygpu_Batch_clear(self);
+ Py_XDECREF(self->references);
+ }
+#endif
+
+ Py_TYPE(self)->tp_free(self);
+}
+
+PyDoc_STRVAR(py_gpu_batch_doc,
+".. class:: GPUBatch(type, buf, elem=None)\n"
+"\n"
+" Reusable container for drawable geometry.\n"
+"\n"
+" :arg type: One of these primitive types: {\n"
+" `POINTS`,\n"
+" `LINES`,\n"
+" `TRIS`,\n"
+" `LINE_STRIP`,\n"
+" `LINE_LOOP`,\n"
+" `TRI_STRIP`,\n"
+" `TRI_FAN`,\n"
+" `LINES_ADJ`,\n"
+" `TRIS_ADJ`,\n"
+" `LINE_STRIP_ADJ` }\n"
+" :type type: `str`\n"
+" :arg buf: Vertex buffer containing all or some of the attributes required for drawing.\n"
+" :type buf: :class:`gpu.types.GPUVertBuf`\n"
+" :arg elem: An optional index buffer.\n"
+" :type elem: :class:`gpu.types.GPUIndexBuf`\n"
+);
+PyTypeObject BPyGPUBatch_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "GPUBatch",
+ .tp_basicsize = sizeof(BPyGPUBatch),
+ .tp_dealloc = (destructor)bpygpu_Batch_dealloc,
+#ifdef USE_GPU_PY_REFERENCES
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+ .tp_doc = py_gpu_batch_doc,
+ .tp_traverse = (traverseproc)bpygpu_Batch_traverse,
+ .tp_clear = (inquiry)bpygpu_Batch_clear,
+#else
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+#endif
+ .tp_methods = bpygpu_Batch_methods,
+ .tp_new = bpygpu_Batch_new,
+};
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Public API
+* \{ */
+
+PyObject *BPyGPUBatch_CreatePyObject(GPUBatch *batch)
+{
+ BPyGPUBatch *self;
+
+#ifdef USE_GPU_PY_REFERENCES
+ self = (BPyGPUBatch *)_PyObject_GC_New(&BPyGPUBatch_Type);
+ self->references = NULL;
+#else
+ self = PyObject_New(BPyGPUBatch, &BPyGPUBatch_Type);
+#endif
+
+ self->batch = batch;
+
+ return (PyObject *)self;
+}
+
+/** \} */
+
+#undef BPY_GPU_BATCH_CHECK_OBJ
diff --git a/source/blender/python/gpu/gpu_py_batch.h b/source/blender/python/gpu/gpu_py_batch.h
new file mode 100644
index 00000000000..c77574428db
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_batch.h
@@ -0,0 +1,48 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_batch.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_BATCH_H__
+#define __GPU_PY_BATCH_H__
+
+#include "BLI_compiler_attrs.h"
+
+#define USE_GPU_PY_REFERENCES
+
+extern PyTypeObject BPyGPUBatch_Type;
+
+#define BPyGPUBatch_Check(v) (Py_TYPE(v) == &BPyGPUBatch_Type)
+
+typedef struct BPyGPUBatch {
+ PyObject_VAR_HEAD
+ /* The batch is owned, we may support thin wrapped batches later. */
+ struct GPUBatch *batch;
+#ifdef USE_GPU_PY_REFERENCES
+ /* Just to keep a user to prevent freeing buf's we're using */
+ PyObject *references;
+#endif
+} BPyGPUBatch;
+
+PyObject *BPyGPUBatch_CreatePyObject(struct GPUBatch *batch) ATTR_NONNULL(1);
+
+#endif /* __GPU_PY_BATCH_H__ */
diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c
new file mode 100644
index 00000000000..12027d2e2b8
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_element.c
@@ -0,0 +1,242 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_element.c
+ * \ingroup bpygpu
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "GPU_element.h"
+
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+#include "gpu_py_primitive.h"
+#include "gpu_py_element.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name IndexBuf Type
+ * \{ */
+
+static PyObject *bpygpu_IndexBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
+{
+ const char *error_prefix = "IndexBuf.__new__";
+ bool ok = true;
+
+ struct {
+ GPUPrimType type_id;
+ PyObject *seq;
+ } params;
+
+ uint verts_per_prim;
+ uint index_len;
+ GPUIndexBufBuilder builder;
+
+ static const char *_keywords[] = {"type", "seq", NULL};
+ static _PyArg_Parser _parser = {"$O&O:IndexBuf.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ bpygpu_ParsePrimType, &params.type_id,
+ &params.seq))
+ {
+ return NULL;
+ }
+
+ verts_per_prim = GPU_indexbuf_primitive_len(params.type_id);
+ if (verts_per_prim == -1) {
+ PyErr_Format(PyExc_ValueError,
+ "The argument 'type' must be "
+ "'POINTS', 'LINES', 'TRIS' or 'LINES_ADJ'");
+ return NULL;
+ }
+
+ if (PyObject_CheckBuffer(params.seq)) {
+ Py_buffer pybuffer;
+
+ if (PyObject_GetBuffer(params.seq, &pybuffer, PyBUF_FORMAT | PyBUF_ND) == -1) {
+ /* PyObject_GetBuffer already handles error messages. */
+ return NULL;
+ }
+
+ if (pybuffer.ndim != 1 && pybuffer.shape[1] != verts_per_prim) {
+ PyErr_Format(PyExc_ValueError,
+ "Each primitive must exactly %d indices",
+ verts_per_prim);
+ return NULL;
+ }
+
+ if (pybuffer.itemsize != 4 ||
+ PyC_StructFmt_type_is_float_any(PyC_StructFmt_type_from_str(pybuffer.format)))
+ {
+ PyErr_Format(PyExc_ValueError,
+ "Each index must be an 4-bytes integer value");
+ return NULL;
+ }
+
+ index_len = pybuffer.shape[0];
+ if (pybuffer.ndim != 1) {
+ index_len *= pybuffer.shape[1];
+ }
+
+ /* The `vertex_len` parameter is only used for asserts in the Debug build. */
+ /* Not very useful in python since scripts are often tested in Release build. */
+ /* Use `INT_MAX` instead of the actual number of vertices. */
+ GPU_indexbuf_init(
+ &builder, params.type_id, index_len, INT_MAX);
+
+#if 0
+ uint *buf = pybuffer.buf;
+ for (uint i = index_len; i--; buf++) {
+ GPU_indexbuf_add_generic_vert(&builder, *buf);
+ }
+#else
+ memcpy(builder.data, pybuffer.buf, index_len * sizeof(*builder.data));
+ builder.index_len = index_len;
+#endif
+ PyBuffer_Release(&pybuffer);
+ }
+ else {
+ PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
+
+ if (seq_fast == NULL) {
+ return false;
+ }
+
+ const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast);
+
+ PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast);
+
+ index_len = seq_len * verts_per_prim;
+
+ /* The `vertex_len` parameter is only used for asserts in the Debug build. */
+ /* Not very useful in python since scripts are often tested in Release build. */
+ /* Use `INT_MAX` instead of the actual number of vertices. */
+ GPU_indexbuf_init(
+ &builder, params.type_id, index_len, INT_MAX);
+
+ if (verts_per_prim == 1) {
+ for (uint i = 0; i < seq_len; i++) {
+ GPU_indexbuf_add_generic_vert(
+ &builder, PyC_Long_AsU32(seq_items[i]));
+ }
+ }
+ else {
+ int values[4];
+ for (uint i = 0; i < seq_len; i++) {
+ PyObject *seq_fast_item = PySequence_Fast(seq_items[i], error_prefix);
+ if (seq_fast_item == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%s: expected a sequence, got %s",
+ error_prefix, Py_TYPE(seq_items[i])->tp_name);
+ ok = false;
+ goto finally;
+ }
+
+ ok = PyC_AsArray_FAST(
+ values, seq_fast_item, verts_per_prim,
+ &PyLong_Type, false, error_prefix) == 0;
+
+ if (ok) {
+ for (uint j = 0; j < verts_per_prim; j++) {
+ GPU_indexbuf_add_generic_vert(&builder, values[j]);
+ }
+ }
+ Py_DECREF(seq_fast_item);
+ }
+ }
+
+ if (PyErr_Occurred()) {
+ ok = false;
+ }
+
+finally:
+
+ Py_DECREF(seq_fast);
+ }
+
+ if (ok == false) {
+ MEM_freeN(builder.data);
+ return NULL;
+ }
+
+ return BPyGPUIndexBuf_CreatePyObject(GPU_indexbuf_build(&builder));
+}
+
+static void bpygpu_IndexBuf_dealloc(BPyGPUIndexBuf *self)
+{
+ GPU_indexbuf_discard(self->elem);
+ Py_TYPE(self)->tp_free(self);
+}
+
+PyDoc_STRVAR(py_gpu_element_doc,
+".. class:: GPUIndexBuf(type, seq)\n"
+"\n"
+" Contains an index buffer.\n"
+"\n"
+" :param type: One of these primitive types: {\n"
+" `POINTS`,\n"
+" `LINES`,\n"
+" `TRIS`,\n"
+" `LINE_STRIP_ADJ` }\n"
+" :type type: `str`\n"
+" :param seq: Indices this index buffer will contain.\n"
+" Whether a 1D or 2D sequence is required depends on the type.\n"
+" Optionally the sequence can support the buffer protocol.\n"
+" :type seq: 1D or 2D sequence\n"
+);
+PyTypeObject BPyGPUIndexBuf_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "GPUIndexBuf",
+ .tp_basicsize = sizeof(BPyGPUIndexBuf),
+ .tp_dealloc = (destructor)bpygpu_IndexBuf_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = py_gpu_element_doc,
+ .tp_new = bpygpu_IndexBuf_new,
+};
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public API
+ * \{ */
+
+PyObject *BPyGPUIndexBuf_CreatePyObject(GPUIndexBuf *elem)
+{
+ BPyGPUIndexBuf *self;
+
+ self = PyObject_New(BPyGPUIndexBuf, &BPyGPUIndexBuf_Type);
+ self->elem = elem;
+
+ return (PyObject *)self;
+}
+
+/** \} */
diff --git a/source/blender/python/gpu/gpu_py_element.h b/source/blender/python/gpu/gpu_py_element.h
new file mode 100644
index 00000000000..e201a767582
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_element.h
@@ -0,0 +1,39 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_element.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_ELEMENT_H__
+#define __GPU_PY_ELEMENT_H__
+
+extern PyTypeObject BPyGPUIndexBuf_Type;
+
+#define BPyGPUIndexBuf_Check(v) (Py_TYPE(v) == &BPyGPUIndexBuf_Type)
+
+typedef struct BPyGPUIndexBuf {
+ PyObject_VAR_HEAD
+ struct GPUIndexBuf *elem;
+} BPyGPUIndexBuf;
+
+PyObject *BPyGPUIndexBuf_CreatePyObject(struct GPUIndexBuf *elem);
+
+#endif /* __GPU_PY_ELEMENT_H__ */
diff --git a/source/blender/python/gpu/gpu_py_matrix.c b/source/blender/python/gpu/gpu_py_matrix.c
new file mode 100644
index 00000000000..6c77f2ee02b
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_matrix.c
@@ -0,0 +1,575 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_matrix.c
+ * \ingroup bpygpu
+ *
+ * This file defines the gpu.matrix stack API.
+ *
+ * \warning While these functions attempt to ensure correct stack usage.
+ * Mixing Python and C functions may still crash on invalid use.
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+
+#include "BLI_utildefines.h"
+
+#include "../mathutils/mathutils.h"
+
+#include "../generic/py_capi_utils.h"
+
+#define USE_GPU_PY_MATRIX_API
+#include "GPU_matrix.h"
+#undef USE_GPU_PY_MATRIX_API
+
+#include "gpu_py_matrix.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper Functions
+ * \{ */
+
+static bool bpygpu_stack_is_push_model_view_ok_or_error(void)
+{
+ if (GPU_matrix_stack_level_get_model_view() >= GPU_PY_MATRIX_STACK_LEN) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Maximum model-view stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached");
+ return false;
+ }
+ return true;
+}
+
+static bool bpygpu_stack_is_push_projection_ok_or_error(void)
+{
+ if (GPU_matrix_stack_level_get_projection() >= GPU_PY_MATRIX_STACK_LEN) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Maximum projection stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached");
+ return false;
+ }
+ return true;
+}
+
+static bool bpygpu_stack_is_pop_model_view_ok_or_error(void)
+{
+ if (GPU_matrix_stack_level_get_model_view() == 0) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Minimum model-view stack depth reached");
+ return false;
+ }
+ return true;
+}
+
+static bool bpygpu_stack_is_pop_projection_ok_or_error(void)
+{
+ if (GPU_matrix_stack_level_get_projection() == 0) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Minimum projection stack depth reached");
+ return false;
+ }
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Manage Stack
+ * \{ */
+
+PyDoc_STRVAR(bpygpu_matrix_push_doc,
+".. function:: push()\n"
+"\n"
+" Add to the model-view matrix stack.\n"
+);
+static PyObject *bpygpu_matrix_push(PyObject *UNUSED(self))
+{
+ if (!bpygpu_stack_is_push_model_view_ok_or_error()) {
+ return NULL;
+ }
+ GPU_matrix_push();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_pop_doc,
+".. function:: pop()\n"
+"\n"
+" Remove the last model-view matrix from the stack.\n"
+);
+static PyObject *bpygpu_matrix_pop(PyObject *UNUSED(self))
+{
+ if (!bpygpu_stack_is_pop_model_view_ok_or_error()) {
+ return NULL;
+ }
+ GPU_matrix_pop();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_push_projection_doc,
+".. function:: push_projection()\n"
+"\n"
+" Add to the projection matrix stack.\n"
+);
+static PyObject *bpygpu_matrix_push_projection(PyObject *UNUSED(self))
+{
+ if (!bpygpu_stack_is_push_projection_ok_or_error()) {
+ return NULL;
+ }
+ GPU_matrix_push_projection();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_pop_projection_doc,
+".. function:: pop_projection()\n"
+"\n"
+" Remove the last projection matrix from the stack.\n"
+);
+static PyObject *bpygpu_matrix_pop_projection(PyObject *UNUSED(self))
+{
+ if (!bpygpu_stack_is_pop_projection_ok_or_error()) {
+ return NULL;
+ }
+ GPU_matrix_pop_projection();
+ Py_RETURN_NONE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stack (Context Manager)
+ *
+ * Safer alternative to ensure balanced push/pop calls.
+ *
+ * \{ */
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ int type;
+ int level;
+} BPyGPU_MatrixStackContext;
+
+enum {
+ PYGPU_MATRIX_TYPE_MODEL_VIEW = 1,
+ PYGPU_MATRIX_TYPE_PROJECTION = 2,
+};
+
+static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self);
+static PyObject *bpygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *args);
+
+static PyMethodDef bpygpu_matrix_stack_context_methods[] = {
+ {"__enter__", (PyCFunction)bpygpu_matrix_stack_context_enter, METH_NOARGS},
+ {"__exit__", (PyCFunction)bpygpu_matrix_stack_context_exit, METH_VARARGS},
+ {NULL}
+};
+
+static PyTypeObject BPyGPU_matrix_stack_context_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "GPUMatrixStackContext",
+ .tp_basicsize = sizeof(BPyGPU_MatrixStackContext),
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_methods = bpygpu_matrix_stack_context_methods,
+};
+
+static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self)
+{
+ /* sanity - should never happen */
+ if (self->level != -1) {
+ PyErr_SetString(PyExc_RuntimeError, "Already in use");
+ return NULL;
+ }
+
+ if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) {
+ if (!bpygpu_stack_is_push_model_view_ok_or_error()) {
+ return NULL;
+ }
+ GPU_matrix_push();
+ self->level = GPU_matrix_stack_level_get_model_view();
+ }
+ else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) {
+ if (!bpygpu_stack_is_push_projection_ok_or_error()) {
+ return NULL;
+ }
+ GPU_matrix_push_projection();
+ self->level = GPU_matrix_stack_level_get_projection();
+ }
+ else {
+ BLI_assert(0);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *bpygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *UNUSED(args))
+{
+ /* sanity - should never happen */
+ if (self->level == -1) {
+ fprintf(stderr, "Not yet in use\n");
+ goto finally;
+ }
+
+ if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) {
+ const int level = GPU_matrix_stack_level_get_model_view();
+ if (level != self->level) {
+ fprintf(stderr, "Level push/pop mismatch, expected %d, got %d\n", self->level, level);
+ }
+ if (level != 0) {
+ GPU_matrix_pop();
+ }
+ }
+ else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) {
+ const int level = GPU_matrix_stack_level_get_projection();
+ if (level != self->level) {
+ fprintf(stderr, "Level push/pop mismatch, expected %d, got %d", self->level, level);
+ }
+ if (level != 0) {
+ GPU_matrix_pop_projection();
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+finally:
+ Py_RETURN_NONE;
+}
+
+static PyObject *bpygpu_matrix_push_pop_impl(int type)
+{
+ BPyGPU_MatrixStackContext *ret = PyObject_New(BPyGPU_MatrixStackContext, &BPyGPU_matrix_stack_context_Type);
+ ret->type = type;
+ ret->level = -1;
+ return (PyObject *)ret;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_push_pop_doc,
+".. function:: push_pop()\n"
+"\n"
+" Context manager to ensure balanced push/pop calls, even in the case of an error.\n"
+);
+static PyObject *bpygpu_matrix_push_pop(PyObject *UNUSED(self))
+{
+ return bpygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_MODEL_VIEW);
+}
+
+PyDoc_STRVAR(bpygpu_matrix_push_pop_projection_doc,
+".. function:: push_pop_projection()\n"
+"\n"
+" Context manager to ensure balanced push/pop calls, even in the case of an error.\n"
+);
+static PyObject *bpygpu_matrix_push_pop_projection(PyObject *UNUSED(self))
+{
+ return bpygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_PROJECTION);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Manipulate State
+ * \{ */
+
+PyDoc_STRVAR(bpygpu_matrix_multiply_matrix_doc,
+".. function:: multiply_matrix(matrix)\n"
+"\n"
+" Multiply the current stack matrix.\n"
+"\n"
+" :param matrix: A 4x4 matrix.\n"
+" :type matrix: :class:`mathutils.Matrix`\n"
+);
+static PyObject *bpygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value)
+{
+ MatrixObject *pymat;
+ if (!Matrix_Parse4x4(value, &pymat)) {
+ return NULL;
+ }
+ GPU_matrix_mul(pymat->matrix);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_scale_doc,
+".. function:: scale(scale)\n"
+"\n"
+" Scale the current stack matrix.\n"
+"\n"
+" :param scale: Scale the current stack matrix.\n"
+" :type scale: sequence of 2 or 3 floats\n"
+);
+static PyObject *bpygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value)
+{
+ float scale[3];
+ int len;
+ if ((len = mathutils_array_parse(scale, 2, 3, value, "gpu.matrix.scale(): invalid vector arg")) == -1) {
+ return NULL;
+ }
+ if (len == 2) {
+ GPU_matrix_scale_2fv(scale);
+ }
+ else {
+ GPU_matrix_scale_3fv(scale);
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_scale_uniform_doc,
+".. function:: scale_uniform(scale)\n"
+"\n"
+" :param scale: Scale the current stack matrix.\n"
+" :type scale: float\n"
+);
+static PyObject *bpygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value)
+{
+ float scalar;
+ if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) {
+ PyErr_Format(PyExc_TypeError,
+ "expected a number, not %.200s",
+ Py_TYPE(value)->tp_name);
+ return NULL;
+ }
+ GPU_matrix_scale_1f(scalar);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_translate_doc,
+".. function:: translate(offset)\n"
+"\n"
+" Scale the current stack matrix.\n"
+"\n"
+" :param offset: Translate the current stack matrix.\n"
+" :type offset: sequence of 2 or 3 floats\n"
+);
+static PyObject *bpygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value)
+{
+ float offset[3];
+ int len;
+ if ((len = mathutils_array_parse(offset, 2, 3, value, "gpu.matrix.translate(): invalid vector arg")) == -1) {
+ return NULL;
+ }
+ if (len == 2) {
+ GPU_matrix_translate_2fv(offset);
+ }
+ else {
+ GPU_matrix_translate_3fv(offset);
+ }
+ Py_RETURN_NONE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Write State
+ * \{ */
+
+PyDoc_STRVAR(bpygpu_matrix_reset_doc,
+".. function:: reset()\n"
+"\n"
+" Empty stack and set to identity.\n"
+);
+static PyObject *bpygpu_matrix_reset(PyObject *UNUSED(self))
+{
+ GPU_matrix_reset();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_load_identity_doc,
+".. function:: load_identity()\n"
+"\n"
+" Empty stack and set to identity.\n"
+);
+static PyObject *bpygpu_matrix_load_identity(PyObject *UNUSED(self))
+{
+ GPU_matrix_identity_set();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_load_matrix_doc,
+".. function:: load_matrix(matrix)\n"
+"\n"
+" Load a matrix into the stack.\n"
+"\n"
+" :param matrix: A 4x4 matrix.\n"
+" :type matrix: :class:`mathutils.Matrix`\n"
+);
+static PyObject *bpygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value)
+{
+ MatrixObject *pymat;
+ if (!Matrix_Parse4x4(value, &pymat)) {
+ return NULL;
+ }
+ GPU_matrix_set(pymat->matrix);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_matrix_load_projection_matrix_doc,
+".. function:: load_projection_matrix(matrix)\n"
+"\n"
+" Load a projection matrix into the stack.\n"
+"\n"
+" :param matrix: A 4x4 matrix.\n"
+" :type matrix: :class:`mathutils.Matrix`\n"
+);
+static PyObject *bpygpu_matrix_load_projection_matrix(PyObject *UNUSED(self), PyObject *value)
+{
+ MatrixObject *pymat;
+ if (!Matrix_Parse4x4(value, &pymat)) {
+ return NULL;
+ }
+ GPU_matrix_projection_set(pymat->matrix);
+ Py_RETURN_NONE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Read State
+ * \{ */
+
+PyDoc_STRVAR(bpygpu_matrix_get_projection_matrix_doc,
+".. function:: get_projection_matrix()\n"
+"\n"
+" Return a copy of the projection matrix.\n"
+"\n"
+" :return: A 4x4 projection matrix.\n"
+" :rtype: :class:`mathutils.Matrix`\n"
+);
+static PyObject *bpygpu_matrix_get_projection_matrix(PyObject *UNUSED(self))
+{
+ float matrix[4][4];
+ GPU_matrix_projection_get(matrix);
+ return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL);
+}
+
+
+PyDoc_STRVAR(bpygpu_matrix_get_model_view_matrix_doc,
+".. function:: get_model_view_matrix()\n"
+"\n"
+" Return a copy of the model-view matrix.\n"
+"\n"
+" :return: A 4x4 view matrix.\n"
+" :rtype: :class:`mathutils.Matrix`\n"
+);
+static PyObject *bpygpu_matrix_get_model_view_matrix(PyObject *UNUSED(self))
+{
+ float matrix[4][4];
+ GPU_matrix_model_view_get(matrix);
+ return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL);
+}
+
+PyDoc_STRVAR(bpygpu_matrix_get_normal_matrix_doc,
+".. function:: get_normal_matrix()\n"
+"\n"
+" Return a copy of the normal matrix.\n"
+"\n"
+" :return: A 3x3 normal matrix.\n"
+" :rtype: :class:`mathutils.Matrix`\n"
+);
+static PyObject *bpygpu_matrix_get_normal_matrix(PyObject *UNUSED(self))
+{
+ float matrix[3][3];
+ GPU_matrix_normal_get(matrix);
+ return Matrix_CreatePyObject(&matrix[0][0], 3, 3, NULL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Module
+ * \{ */
+
+static struct PyMethodDef bpygpu_matrix_methods[] = {
+ /* Manage Stack */
+ {"push", (PyCFunction)bpygpu_matrix_push,
+ METH_NOARGS, bpygpu_matrix_push_doc},
+ {"pop", (PyCFunction)bpygpu_matrix_pop,
+ METH_NOARGS, bpygpu_matrix_pop_doc},
+
+ {"push_projection", (PyCFunction)bpygpu_matrix_push_projection,
+ METH_NOARGS, bpygpu_matrix_push_projection_doc},
+ {"pop_projection", (PyCFunction)bpygpu_matrix_pop_projection,
+ METH_NOARGS, bpygpu_matrix_pop_projection_doc},
+
+ /* Stack (Context Manager) */
+ {"push_pop", (PyCFunction)bpygpu_matrix_push_pop,
+ METH_NOARGS, bpygpu_matrix_push_pop_doc},
+ {"push_pop_projection", (PyCFunction)bpygpu_matrix_push_pop_projection,
+ METH_NOARGS, bpygpu_matrix_push_pop_projection_doc},
+
+ /* Manipulate State */
+ {"multiply_matrix", (PyCFunction)bpygpu_matrix_multiply_matrix,
+ METH_O, bpygpu_matrix_multiply_matrix_doc},
+ {"scale", (PyCFunction)bpygpu_matrix_scale,
+ METH_O, bpygpu_matrix_scale_doc},
+ {"scale_uniform", (PyCFunction)bpygpu_matrix_scale_uniform,
+ METH_O, bpygpu_matrix_scale_uniform_doc},
+ {"translate", (PyCFunction)bpygpu_matrix_translate,
+ METH_O, bpygpu_matrix_translate_doc},
+
+ /* TODO */
+#if 0
+ {"rotate", (PyCFunction)bpygpu_matrix_rotate,
+ METH_O, bpygpu_matrix_rotate_doc},
+ {"rotate_axis", (PyCFunction)bpygpu_matrix_rotate_axis,
+ METH_O, bpygpu_matrix_rotate_axis_doc},
+ {"look_at", (PyCFunction)bpygpu_matrix_look_at,
+ METH_O, bpygpu_matrix_look_at_doc},
+#endif
+
+ /* Write State */
+ {"reset", (PyCFunction)bpygpu_matrix_reset,
+ METH_NOARGS, bpygpu_matrix_reset_doc},
+ {"load_identity", (PyCFunction)bpygpu_matrix_load_identity,
+ METH_NOARGS, bpygpu_matrix_load_identity_doc},
+ {"load_matrix", (PyCFunction)bpygpu_matrix_load_matrix,
+ METH_O, bpygpu_matrix_load_matrix_doc},
+ {"load_projection_matrix", (PyCFunction)bpygpu_matrix_load_projection_matrix,
+ METH_O, bpygpu_matrix_load_projection_matrix_doc},
+
+ /* Read State */
+ {"get_projection_matrix", (PyCFunction)bpygpu_matrix_get_projection_matrix,
+ METH_NOARGS, bpygpu_matrix_get_projection_matrix_doc},
+ {"get_model_view_matrix", (PyCFunction)bpygpu_matrix_get_model_view_matrix,
+ METH_NOARGS, bpygpu_matrix_get_model_view_matrix_doc},
+ {"get_normal_matrix", (PyCFunction)bpygpu_matrix_get_normal_matrix,
+ METH_NOARGS, bpygpu_matrix_get_normal_matrix_doc},
+
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(bpygpu_matrix_doc,
+"This module provides access to the matrix stack."
+);
+static PyModuleDef BPyGPU_matrix_module_def = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "gpu.matrix",
+ .m_doc = bpygpu_matrix_doc,
+ .m_methods = bpygpu_matrix_methods,
+};
+
+PyObject *BPyInit_gpu_matrix(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&BPyGPU_matrix_module_def);
+
+ if (PyType_Ready(&BPyGPU_matrix_stack_context_Type) < 0) {
+ return NULL;
+ }
+
+ return submodule;
+}
+
+/** \} */
diff --git a/source/blender/python/gpu/gpu_py_matrix.h b/source/blender/python/gpu/gpu_py_matrix.h
new file mode 100644
index 00000000000..7bd6318611d
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_matrix.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_matrix.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_MATRIX_H__
+#define __GPU_PY_MATRIX_H__
+
+PyObject *BPyInit_gpu_matrix(void);
+
+#endif /* __GPU_PY_MATRIX_H__ */
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
new file mode 100644
index 00000000000..c51a356d900
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -0,0 +1,371 @@
+/*
+ * ***** 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.
+ *
+ * Copyright 2015, Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_offscreen.c
+ * \ingroup bpygpu
+ *
+ * This file defines the offscreen functionalities of the 'gpu' module
+ * used for off-screen OpenGL rendering.
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_scene.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
+
+#include "../editors/include/ED_view3d.h"
+
+#include "../mathutils/mathutils.h"
+
+#include "../generic/py_capi_utils.h"
+
+#include "gpu_py_offscreen.h" /* own include */
+
+
+ /* -------------------------------------------------------------------- */
+
+ /** \name GPUOffScreen Common Utilities
+ * \{ */
+
+static int bpygpu_offscreen_valid_check(BPyGPUOffScreen *bpygpu_ofs)
+{
+ if (UNLIKELY(bpygpu_ofs->ofs == NULL)) {
+ PyErr_SetString(PyExc_ReferenceError, "GPU offscreen was freed, no further access is valid");
+ return -1;
+ }
+ return 0;
+}
+
+#define BPY_GPU_OFFSCREEN_CHECK_OBJ(bpygpu) { \
+ if (UNLIKELY(bpygpu_offscreen_valid_check(bpygpu) == -1)) { \
+ return NULL; \
+ } \
+} ((void)0)
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name GPUOffscreen Type
+ * \{ */
+
+
+static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ GPUOffScreen *ofs;
+ int width, height, samples = 0;
+ char err_out[256];
+
+ static const char *_keywords[] = {"width", "height", "samples", NULL};
+ static _PyArg_Parser _parser = {"ii|i:GPUOffScreen.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ &width, &height, &samples))
+ {
+ return NULL;
+ }
+
+ ofs = GPU_offscreen_create(width, height, samples, true, false, err_out);
+
+ if (ofs == NULL) {
+ PyErr_Format(PyExc_RuntimeError,
+ "gpu.offscreen.new(...) failed with '%s'",
+ err_out[0] ? err_out : "unknown error");
+ return NULL;
+ }
+
+ return BPyGPUOffScreen_CreatePyObject(ofs);
+}
+
+PyDoc_STRVAR(bpygpu_offscreen_width_doc, "Width of the texture.\n\n:type: `int`");
+static PyObject *bpygpu_offscreen_width_get(BPyGPUOffScreen *self, void *UNUSED(type))
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ return PyLong_FromLong(GPU_offscreen_width(self->ofs));
+}
+
+PyDoc_STRVAR(bpygpu_offscreen_height_doc, "Height of the texture.\n\n:type: `int`");
+static PyObject *bpygpu_offscreen_height_get(BPyGPUOffScreen *self, void *UNUSED(type))
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ return PyLong_FromLong(GPU_offscreen_height(self->ofs));
+}
+
+PyDoc_STRVAR(bpygpu_offscreen_color_texture_doc, "OpenGL bindcode for the color texture.\n\n:type: `int`");
+static PyObject *bpygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void *UNUSED(type))
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ GPUTexture *texture = GPU_offscreen_color_texture(self->ofs);
+ return PyLong_FromLong(GPU_texture_opengl_bindcode(texture));
+}
+
+PyDoc_STRVAR(bpygpu_offscreen_bind_doc,
+".. method:: bind(save=True)\n"
+"\n"
+" Bind the offscreen object.\n"
+" To make sure that the offscreen gets unbind whether an exception occurs or not, pack it into a `with` statement.\n"
+"\n"
+" :arg save: Save the current OpenGL state, so that it can be restored when unbinding.\n"
+" :type save: `bool`\n"
+);
+static PyObject *bpygpu_offscreen_bind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ bool save = true;
+
+ static const char *_keywords[] = {"save", NULL};
+ static _PyArg_Parser _parser = {"|O&:bind", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ PyC_ParseBool, &save))
+ {
+ return NULL;
+ }
+
+ GPU_offscreen_bind(self->ofs, save);
+
+ self->is_saved = save;
+ Py_INCREF(self);
+
+ return (PyObject *)self;
+}
+
+PyDoc_STRVAR(bpygpu_offscreen_unbind_doc,
+".. method:: unbind(restore=True)\n"
+"\n"
+" Unbind the offscreen object.\n"
+"\n"
+" :arg restore: Restore the OpenGL state, can only be used when the state has been saved before.\n"
+" :type restore: `bool`\n"
+);
+static PyObject *bpygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
+{
+ bool restore = true;
+
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+
+ static const char *_keywords[] = {"restore", NULL};
+ static _PyArg_Parser _parser = {"|O&:unbind", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ PyC_ParseBool, &restore))
+ {
+ return NULL;
+ }
+
+ GPU_offscreen_unbind(self->ofs, restore);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_offscreen_draw_view3d_doc,
+".. method:: draw_view3d(scene, view3d, region, view_matrix, projection_matrix)\n"
+"\n"
+" Draw the 3d viewport in the offscreen object.\n"
+"\n"
+" :arg scene: Scene to draw.\n"
+" :type scene: :class:`bpy.types.Scene`\n"
+" :arg view_layer: View layer to draw.\n"
+" :type view_layer: :class:`bpy.types.ViewLayer`\n"
+" :arg view3d: 3D View to get the drawing settings from.\n"
+" :type view3d: :class:`bpy.types.SpaceView3D`\n"
+" :arg region: Region of the 3D View (required as temporary draw target).\n"
+" :type region: :class:`bpy.types.Region`\n"
+" :arg view_matrix: View Matrix (e.g. ``camera.matrix_world.inverted()``).\n"
+" :type view_matrix: :class:`mathutils.Matrix`\n"
+" :arg projection_matrix: Projection Matrix (e.g. ``camera.calc_matrix_camera(...)``).\n"
+" :type projection_matrix: :class:`mathutils.Matrix`\n"
+);
+static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds)
+{
+ MatrixObject *py_mat_view, *py_mat_projection;
+ PyObject *py_scene, *py_view_layer, *py_region, *py_view3d;
+
+ struct Depsgraph *depsgraph;
+ struct Scene *scene;
+ struct ViewLayer *view_layer;
+ View3D *v3d;
+ ARegion *ar;
+ struct RV3DMatrixStore *rv3d_mats;
+
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+
+ static const char *_keywords[] = {
+ "scene", "view_layer", "view3d", "region",
+ "view_matrix", "projection_matrix", NULL};
+
+ static _PyArg_Parser _parser = {"OOOOO&O&:draw_view3d", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ &py_scene, &py_view_layer, &py_view3d, &py_region,
+ Matrix_Parse4x4, &py_mat_view,
+ Matrix_Parse4x4, &py_mat_projection) ||
+ (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) ||
+ !(view_layer = PyC_RNA_AsPointer(py_view_layer, "ViewLayer")) ||
+ !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) ||
+ !(ar = PyC_RNA_AsPointer(py_region, "Region"))))
+ {
+ return NULL;
+ }
+
+ BLI_assert(BKE_id_is_in_global_main(&scene->id));
+
+ depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+
+ rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata);
+
+ GPU_offscreen_bind(self->ofs, true);
+
+ ED_view3d_draw_offscreen(depsgraph,
+ scene,
+ v3d->shading.type,
+ v3d,
+ ar,
+ GPU_offscreen_width(self->ofs),
+ GPU_offscreen_height(self->ofs),
+ (float(*)[4])py_mat_view->matrix,
+ (float(*)[4])py_mat_projection->matrix,
+ false,
+ true,
+ "",
+ NULL,
+ self->ofs,
+ NULL);
+
+ GPU_offscreen_unbind(self->ofs, true);
+
+ ED_view3d_mats_rv3d_restore(ar->regiondata, rv3d_mats);
+ MEM_freeN(rv3d_mats);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_offscreen_free_doc,
+".. method:: free()\n"
+"\n"
+" Free the offscreen object.\n"
+" The framebuffer, texture and render objects will no longer be accessible.\n"
+);
+static PyObject *bpygpu_offscreen_free(BPyGPUOffScreen *self)
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+
+ GPU_offscreen_free(self->ofs);
+ self->ofs = NULL;
+ Py_RETURN_NONE;
+}
+
+static PyObject *bpygpu_offscreen_bind_context_enter(BPyGPUOffScreen *UNUSED(self))
+{
+ Py_RETURN_NONE;
+}
+
+static PyObject *bpygpu_offscreen_bind_context_exit(BPyGPUOffScreen *self, PyObject *UNUSED(args))
+{
+ GPU_offscreen_unbind(self->ofs, self->is_saved);
+ Py_RETURN_NONE;
+}
+
+static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self)
+{
+ if (self->ofs)
+ GPU_offscreen_free(self->ofs);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyGetSetDef bpygpu_offscreen_getseters[] = {
+ {(char *)"color_texture", (getter)bpygpu_offscreen_color_texture_get, (setter)NULL, bpygpu_offscreen_color_texture_doc, NULL},
+ {(char *)"width", (getter)bpygpu_offscreen_width_get, (setter)NULL, bpygpu_offscreen_width_doc, NULL},
+ {(char *)"height", (getter)bpygpu_offscreen_height_get, (setter)NULL, bpygpu_offscreen_height_doc, NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
+
+static struct PyMethodDef bpygpu_offscreen_methods[] = {
+ {"bind", (PyCFunction)bpygpu_offscreen_bind, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_bind_doc},
+ {"unbind", (PyCFunction)bpygpu_offscreen_unbind, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_unbind_doc},
+ {"draw_view3d", (PyCFunction)bpygpu_offscreen_draw_view3d, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_draw_view3d_doc},
+ {"free", (PyCFunction)bpygpu_offscreen_free, METH_NOARGS, bpygpu_offscreen_free_doc},
+ {"__enter__", (PyCFunction)bpygpu_offscreen_bind_context_enter, METH_NOARGS},
+ {"__exit__", (PyCFunction)bpygpu_offscreen_bind_context_exit, METH_VARARGS},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(bpygpu_offscreen_doc,
+".. class:: GPUOffScreen(width, height, samples=0)\n"
+"\n"
+" This object gives access to off screen buffers.\n"
+"\n"
+" :arg width: Horizontal dimension of the buffer.\n"
+" :type width: `int`\n"
+" :arg height: Vertical dimension of the buffer.\n"
+" :type height: `int`\n"
+" :arg samples: OpenGL samples to use for MSAA or zero to disable.\n"
+" :type samples: `int`\n"
+);
+PyTypeObject BPyGPUOffScreen_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "GPUOffScreen",
+ .tp_basicsize = sizeof(BPyGPUOffScreen),
+ .tp_dealloc = (destructor)BPyGPUOffScreen__tp_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = bpygpu_offscreen_doc,
+ .tp_methods = bpygpu_offscreen_methods,
+ .tp_getset = bpygpu_offscreen_getseters,
+ .tp_new = bpygpu_offscreen_new,
+};
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public API
+ * \{ */
+
+PyObject *BPyGPUOffScreen_CreatePyObject(GPUOffScreen *ofs)
+{
+ BPyGPUOffScreen *self;
+
+ self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type);
+ self->ofs = ofs;
+
+ return (PyObject *)self;
+}
+
+/** \} */
+
+#undef BPY_GPU_OFFSCREEN_CHECK_OBJ
diff --git a/source/blender/python/gpu/gpu_py_offscreen.h b/source/blender/python/gpu/gpu_py_offscreen.h
new file mode 100644
index 00000000000..c4a2d02a694
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_offscreen.h
@@ -0,0 +1,42 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_offscreen.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_OFFSCREEN_H__
+#define __GPU_PY_OFFSCREEN_H__
+
+#include "BLI_compiler_attrs.h"
+
+extern PyTypeObject BPyGPUOffScreen_Type;
+
+#define BPyGPUOffScreen_Check(v) (Py_TYPE(v) == &BPyGPUOffScreen_Type)
+
+typedef struct BPyGPUOffScreen {
+ PyObject_HEAD
+ struct GPUOffScreen *ofs;
+ bool is_saved;
+} BPyGPUOffScreen;
+
+PyObject *BPyGPUOffScreen_CreatePyObject(struct GPUOffScreen *ofs) ATTR_NONNULL(1);
+
+#endif /* __GPU_PY_OFFSCREEN_H__ */
diff --git a/source/blender/python/gpu/gpu_py_primitive.c b/source/blender/python/gpu/gpu_py_primitive.c
new file mode 100644
index 00000000000..798dfc050f6
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_primitive.c
@@ -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.
+ *
+ * Copyright 2015, Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_primitive.c
+ * \ingroup bpygpu
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "BLI_utildefines.h"
+
+#include "GPU_primitive.h"
+
+#include "gpu_py_primitive.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Primitive Utils
+ * \{ */
+
+int bpygpu_ParsePrimType(PyObject *o, void *p)
+{
+ Py_ssize_t mode_id_len;
+ const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len);
+ if (mode_id == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "expected a string, got %s",
+ Py_TYPE(o)->tp_name);
+ return 0;
+ }
+#define MATCH_ID(id) \
+ if (mode_id_len == strlen(STRINGIFY(id))) { \
+ if (STREQ(mode_id, STRINGIFY(id))) { \
+ mode = GPU_PRIM_##id; \
+ goto success; \
+ } \
+ } ((void)0)
+
+ GPUPrimType mode;
+ MATCH_ID(POINTS);
+ MATCH_ID(LINES);
+ MATCH_ID(TRIS);
+ MATCH_ID(LINE_STRIP);
+ MATCH_ID(LINE_LOOP);
+ MATCH_ID(TRI_STRIP);
+ MATCH_ID(TRI_FAN);
+ MATCH_ID(LINE_STRIP_ADJ);
+
+#undef MATCH_ID
+ PyErr_Format(PyExc_ValueError,
+ "unknown type literal: '%s'",
+ mode_id);
+ return 0;
+
+success:
+ (*(GPUPrimType *)p) = mode;
+ return 1;
+}
diff --git a/source/blender/python/gpu/gpu_py_primitive.h b/source/blender/python/gpu/gpu_py_primitive.h
new file mode 100644
index 00000000000..d10ee01c8ad
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_primitive.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_primitive.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_PRIMITIVE_H__
+#define __GPU_PY_PRIMITIVE_H__
+
+int bpygpu_ParsePrimType(PyObject *o, void *p);
+
+#endif /* __GPU_PY_PRIMITIVE_H__ */
diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c
new file mode 100644
index 00000000000..56b8b904464
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_select.c
@@ -0,0 +1,95 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_select.c
+ * \ingroup bpygpu
+ *
+ * This file defines the gpu.select API.
+ *
+ * \note Currently only used for gizmo selection,
+ * will need to add begin/end and a way to access the hits.
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "BLI_utildefines.h"
+
+#include "../generic/py_capi_utils.h"
+
+#include "GPU_select.h"
+
+#include "gpu_py_select.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+/** \name Methods
+ * \{ */
+
+PyDoc_STRVAR(bpygpu_select_load_id_doc,
+"load_id(id)\n"
+"\n"
+" Set the selection ID.\n"
+"\n"
+" :param id: Number (32-bit unsigned int).\n"
+" :type select: int\n"
+);
+static PyObject *bpygpu_select_load_id(PyObject *UNUSED(self), PyObject *value)
+{
+ uint id;
+ if ((id = PyC_Long_AsU32(value)) == (uint)-1) {
+ return NULL;
+ }
+ GPU_select_load_id(id);
+ Py_RETURN_NONE;
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Module
+ * \{ */
+
+static struct PyMethodDef bpygpu_select_methods[] = {
+ /* Manage Stack */
+ {"load_id", (PyCFunction)bpygpu_select_load_id, METH_O, bpygpu_select_load_id_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(bpygpu_select_doc,
+"This module provides access to selection."
+);
+static PyModuleDef BPyGPU_select_module_def = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "gpu.select",
+ .m_doc = bpygpu_select_doc,
+ .m_methods = bpygpu_select_methods,
+};
+
+PyObject *BPyInit_gpu_select(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&BPyGPU_select_module_def);
+
+ return submodule;
+}
+
+/** \} */
diff --git a/source/blender/python/gpu/gpu_py_select.h b/source/blender/python/gpu/gpu_py_select.h
new file mode 100644
index 00000000000..11daf2ade64
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_select.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_select.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_SELECT_H__
+#define __GPU_PY_SELECT_H__
+
+PyObject *BPyInit_gpu_select(void);
+
+#endif /* __GPU_PY_SELECT_H__ */
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
new file mode 100644
index 00000000000..5f1ea7a33ce
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -0,0 +1,834 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_shader.c
+ * \ingroup bpygpu
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "BLI_utildefines.h"
+
+#include "GPU_shader.h"
+#include "GPU_shader_interface.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+#include "../mathutils/mathutils.h"
+
+#include "gpu_py_shader.h" /* own include */
+#include "gpu_py_vertex_format.h"
+
+
+ /* -------------------------------------------------------------------- */
+
+ /** \name Enum Conversion.
+ * \{ */
+
+static int bpygpu_ParseBultinShaderEnum(PyObject *o, void *p)
+{
+ Py_ssize_t mode_id_len;
+ const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len);
+ if (mode_id == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "expected a string, got %s",
+ Py_TYPE(o)->tp_name);
+ return 0;
+ }
+#define MATCH_ID(id) \
+ if (mode_id_len == (Py_ssize_t)strlen(STRINGIFY(id))) { \
+ if (STREQ(mode_id, STRINGIFY(id))) { \
+ mode = GPU_SHADER_##id; \
+ goto success; \
+ } \
+ } ((void)0)
+
+ GPUBuiltinShader mode;
+ MATCH_ID(2D_UNIFORM_COLOR);
+ MATCH_ID(2D_FLAT_COLOR);
+ MATCH_ID(2D_SMOOTH_COLOR);
+ MATCH_ID(2D_IMAGE);
+ MATCH_ID(3D_UNIFORM_COLOR);
+ MATCH_ID(3D_FLAT_COLOR);
+ MATCH_ID(3D_SMOOTH_COLOR);
+
+#undef MATCH_ID
+ PyErr_Format(PyExc_ValueError,
+ "unknown type literal: '%s'",
+ mode_id);
+ return 0;
+
+success:
+ (*(GPUBuiltinShader *)p) = mode;
+ return 1;
+}
+
+static int bpygpu_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix)
+{
+ int uniform = GPU_shader_get_uniform(shader, name);
+
+ if (uniform == -1) {
+ PyErr_Format(PyExc_ValueError, "%s: uniform %.32s %.32s not found", error_prefix, name);
+ }
+
+ return uniform;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Shader Type
+ * \{ */
+
+static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
+{
+ struct {
+ const char *vertexcode;
+ const char *fragcode;
+ const char *geocode;
+ const char *libcode;
+ const char *defines;
+ } params = {0};
+
+ static const char *_keywords[] = {
+ "vertexcode", "fragcode", "geocode",
+ "libcode", "defines", NULL};
+
+ static _PyArg_Parser _parser = {"ss|$sss:GPUShader.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ &params.vertexcode, &params.fragcode, &params.geocode,
+ &params.libcode, &params.defines))
+ {
+ return NULL;
+ }
+
+ GPUShader *shader = GPU_shader_create(
+ params.vertexcode,
+ params.fragcode,
+ params.geocode,
+ params.libcode,
+ params.defines,
+ NULL);
+
+ if (shader == NULL) {
+ PyErr_SetString(PyExc_Exception,
+ "Shader Compile Error, see console for more details");
+ return NULL;
+ }
+
+ return BPyGPUShader_CreatePyObject(shader, false);
+}
+
+PyDoc_STRVAR(bpygpu_shader_bind_doc,
+".. method:: bind()\n"
+"\n"
+" Bind the shader object. Required to be able to change uniforms of this shader.\n"
+);
+static PyObject *bpygpu_shader_bind(BPyGPUShader *self)
+{
+ GPU_shader_bind(self->shader);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_shader_uniform_from_name_doc,
+".. method:: uniform_from_name(name)\n"
+"\n"
+" Get uniform location by name.\n"
+"\n"
+" :param name: Name of the uniform variable whose location is to be queried.\n"
+" :type name: `str`\n"
+" :return: Location of the uniform variable.\n"
+" :rtype: `int`\n"
+);
+static PyObject *bpygpu_shader_uniform_from_name(
+ BPyGPUShader *self, PyObject *arg)
+{
+ const char *name = PyUnicode_AsUTF8(arg);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ int uniform = bpygpu_uniform_location_get(
+ self->shader, name, "GPUShader.get_uniform");
+
+ if (uniform == -1) {
+ return NULL;
+ }
+
+ return PyLong_FromLong(uniform);
+}
+
+PyDoc_STRVAR(bpygpu_shader_uniform_block_from_name_doc,
+".. method:: uniform_block_from_name(name)\n"
+"\n"
+" Get uniform block location by name.\n"
+"\n"
+" :param name: Name of the uniform block variable whose location is to be queried.\n"
+" :type name: `str`\n"
+" :return: The location of the uniform block variable.\n"
+" :rtype: `int`\n"
+);
+static PyObject *bpygpu_shader_uniform_block_from_name(
+ BPyGPUShader *self, PyObject *arg)
+{
+ const char *name = PyUnicode_AsUTF8(arg);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ int uniform = GPU_shader_get_uniform_block(self->shader, name);
+
+ if (uniform == -1) {
+ PyErr_Format(PyExc_ValueError,
+ "GPUShader.get_uniform_block: uniform %.32s not found", name);
+ return NULL;
+ }
+
+ return PyLong_FromLong(uniform);
+}
+
+static bool bpygpu_shader_uniform_vector_imp(
+ PyObject *args, int elem_size,
+ int *r_location, int *r_length, int *r_count, Py_buffer *r_pybuffer)
+{
+ PyObject *buffer;
+
+ *r_count = 1;
+ if (!PyArg_ParseTuple(
+ args, "iOi|i:GPUShader.uniform_vector_*",
+ r_location, &buffer, r_length, r_count))
+ {
+ return false;
+ }
+
+ if (PyObject_GetBuffer(buffer, r_pybuffer, PyBUF_SIMPLE) == -1) {
+ /* PyObject_GetBuffer raise a PyExc_BufferError */
+ return false;
+ }
+
+ if (r_pybuffer->len != (*r_length * *r_count * elem_size)) {
+ PyErr_SetString(
+ PyExc_BufferError,
+ "GPUShader.uniform_vector_*: buffer size does not match.");
+ return false;
+ }
+
+ return true;
+}
+
+PyDoc_STRVAR(bpygpu_shader_uniform_vector_float_doc,
+".. method:: uniform_vector_float(location, buffer, length, count)\n"
+"\n"
+" Set the buffer to fill the uniform.\n"
+"\n"
+" :param location: Location of the uniform variable to be modified.\n"
+" :type location: int\n"
+" :param buffer: The data that should be set. Can support the buffer protocol.\n"
+" :type buffer: sequence of floats\n"
+" :param length: Size of the uniform data type:\n"
+"\n"
+" - 1: float\n"
+" - 2: vec2 or float[2]\n"
+" - 3: vec3 or float[3]\n"
+" - 4: vec4 or float[4]\n"
+" - 9: mat3\n"
+" - 16: mat4\n"
+"\n"
+" :type length: int\n"
+" :param count: Specifies the number of elements, vector or matrices that are to be modified.\n"
+" :type count: int\n"
+);
+static PyObject *bpygpu_shader_uniform_vector_float(
+ BPyGPUShader *self, PyObject *args)
+{
+ int location, length, count;
+
+ Py_buffer pybuffer;
+
+ if (!bpygpu_shader_uniform_vector_imp(
+ args, sizeof(float),
+ &location, &length, &count, &pybuffer))
+ {
+ return NULL;
+ }
+
+ GPU_shader_uniform_vector(
+ self->shader, location, length,
+ count, pybuffer.buf);
+
+ PyBuffer_Release(&pybuffer);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_shader_uniform_vector_int_doc,
+".. method:: uniform_vector_int(location, buffer, length, count)\n"
+"\n"
+" See GPUShader.uniform_vector_float(...) description.\n"
+);
+static PyObject *bpygpu_shader_uniform_vector_int(
+ BPyGPUShader *self, PyObject *args)
+{
+ int location, length, count;
+
+ Py_buffer pybuffer;
+
+ if (!bpygpu_shader_uniform_vector_imp(
+ args, sizeof(int),
+ &location, &length, &count, &pybuffer))
+ {
+ return NULL;
+ }
+
+ GPU_shader_uniform_vector_int(
+ self->shader, location, length,
+ count, pybuffer.buf);
+
+ PyBuffer_Release(&pybuffer);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_shader_uniform_bool_doc,
+".. method:: uniform_bool(name, seq)\n"
+"\n"
+" Specify the value of a uniform variable for the current program object.\n"
+"\n"
+" :param name: Name of the uniform variable whose value is to be changed.\n"
+" :type name: str\n"
+" :param seq: Value that will be used to update the specified uniform variable.\n"
+" :type seq: sequence of bools\n"
+);
+static PyObject *bpygpu_shader_uniform_bool(
+ BPyGPUShader *self, PyObject *args)
+{
+ const char *error_prefix = "GPUShader.uniform_bool";
+
+ struct {
+ const char *id;
+ PyObject *seq;
+ } params;
+
+ if (!PyArg_ParseTuple(
+ args, "sO:GPUShader.uniform_bool",
+ &params.id, &params.seq))
+ {
+ return NULL;
+ }
+
+ int values[4];
+ int length;
+ int ret;
+ {
+ PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
+ if (seq_fast == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%s: expected a sequence, got %s",
+ error_prefix, Py_TYPE(params.seq)->tp_name);
+ ret = -1;
+ }
+ else {
+ length = PySequence_Fast_GET_SIZE(seq_fast);
+ if (length == 0 || length > 4) {
+ PyErr_Format(PyExc_TypeError,
+ "%s: invalid sequence length. expected 1..4, got %d",
+ error_prefix, length);
+ ret = -1;
+ }
+ else {
+ ret = PyC_AsArray_FAST(
+ values, seq_fast, length, &PyLong_Type,
+ false, error_prefix);
+ }
+ Py_DECREF(seq_fast);
+ }
+ }
+ if (ret == -1) {
+ return NULL;
+ }
+
+ const int location = bpygpu_uniform_location_get(
+ self->shader, params.id, error_prefix);
+
+ if (location == -1) {
+ return NULL;
+ }
+
+ GPU_shader_uniform_vector_int(self->shader, location, length, 1, values);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_shader_uniform_float_doc,
+".. method:: uniform_float(name, value)\n"
+"\n"
+" Specify the value of a uniform variable for the current program object.\n"
+"\n"
+" :param name: Name of the uniform variable whose value is to be changed.\n"
+" :type name: str\n"
+" :param value: Value that will be used to update the specified uniform variable.\n"
+" :type value: single number or sequence of numbers\n"
+);
+static PyObject *bpygpu_shader_uniform_float(
+ BPyGPUShader *self, PyObject *args)
+{
+ const char *error_prefix = "GPUShader.uniform_float";
+
+ struct {
+ const char *id;
+ PyObject *seq;
+ } params;
+
+ if (!PyArg_ParseTuple(
+ args, "sO:GPUShader.uniform_float",
+ &params.id, &params.seq))
+ {
+ return NULL;
+ }
+
+ float values[16];
+ int length;
+
+ if (PyFloat_Check(params.seq)) {
+ values[0] = (float)PyFloat_AsDouble(params.seq);
+ length = 1;
+ }
+ else if (PyLong_Check(params.seq)) {
+ values[0] = (float)PyLong_AsDouble(params.seq);
+ length = 1;
+ }
+ else if (MatrixObject_Check(params.seq)) {
+ MatrixObject *mat = (MatrixObject *)params.seq;
+ if (BaseMath_ReadCallback(mat) == -1) {
+ return NULL;
+ }
+ if ((mat->num_row != mat->num_col) || !ELEM(mat->num_row, 3, 4)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Expected 3x3 or 4x4 matrix");
+ return NULL;
+ }
+ length = mat->num_row * mat->num_col;
+ memcpy(values, mat->matrix, sizeof(float) * length);
+ }
+ else {
+ length = mathutils_array_parse(values, 2, 16, params.seq, "");
+ if (length == -1) {
+ return NULL;
+ }
+ }
+
+ if (!ELEM(length, 1, 2, 3, 4, 9, 16)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Expected a single float or a sequence of floats of length 1..4, 9 or 16.");
+ return NULL;
+ }
+
+ const int location = bpygpu_uniform_location_get(
+ self->shader, params.id, error_prefix);
+
+ if (location == -1) {
+ return NULL;
+ }
+
+ GPU_shader_uniform_vector(self->shader, location, length, 1, values);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_shader_uniform_int_doc,
+".. method:: uniform_int(name, seq)\n"
+"\n"
+" Specify the value of a uniform variable for the current program object.\n"
+"\n"
+" :param name: name of the uniform variable whose value is to be changed.\n"
+" :type name: str\n"
+" :param seq: Value that will be used to update the specified uniform variable.\n"
+" :type seq: sequence of numbers\n"
+);
+static PyObject *bpygpu_shader_uniform_int(
+ BPyGPUShader *self, PyObject *args)
+{
+ const char *error_prefix = "GPUShader.uniform_int";
+
+ struct {
+ const char *id;
+ PyObject *seq;
+ } params;
+
+ if (!PyArg_ParseTuple(
+ args, "sO:GPUShader.uniform_int",
+ &params.id, &params.seq))
+ {
+ return NULL;
+ }
+
+ int values[4];
+ int length;
+ int ret;
+
+ if (PyLong_Check(params.seq)) {
+ values[0] = PyC_Long_AsI32(params.seq);
+ length = 1;
+ ret = 0;
+ }
+ else {
+ PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
+ if (seq_fast == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%s: expected a sequence, got %s",
+ error_prefix, Py_TYPE(params.seq)->tp_name);
+ ret = -1;
+ }
+ else {
+ length = PySequence_Fast_GET_SIZE(seq_fast);
+ if (length == 0 || length > 4) {
+ PyErr_Format(PyExc_TypeError,
+ "%s: invalid sequence length. expected 1..4, got %d",
+ error_prefix, length);
+ ret = -1;
+ }
+ else {
+ ret = PyC_AsArray_FAST(
+ values, seq_fast, length, &PyLong_Type,
+ false, error_prefix);
+ }
+ Py_DECREF(seq_fast);
+ }
+ }
+ if (ret == -1) {
+ return NULL;
+ }
+
+ const int location = bpygpu_uniform_location_get(
+ self->shader, params.id, error_prefix);
+
+ if (location == -1) {
+ return NULL;
+ }
+
+ GPU_shader_uniform_vector_int(self->shader, location, length, 1, values);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_shader_attr_from_name_doc,
+".. method:: attr_from_name(name)\n"
+"\n"
+" Get attribute location by name.\n"
+"\n"
+" :param name: The name of the attribute variable whose location is to be queried.\n"
+" :type name: str\n"
+" :return: The location of an attribute variable.\n"
+" :rtype: int\n"
+);
+static PyObject *bpygpu_shader_attr_from_name(
+ BPyGPUShader *self, PyObject *arg)
+{
+ const char *name = PyUnicode_AsUTF8(arg);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ int attr = GPU_shader_get_attribute(self->shader, name);
+
+ if (attr == -1) {
+ PyErr_Format(PyExc_ValueError,
+ "GPUShader.attr_from_name: attribute %.32s not found", name);
+ return NULL;
+ }
+
+ return PyLong_FromLong(attr);
+}
+
+PyDoc_STRVAR(bpygpu_shader_calc_format_doc,
+".. method:: calc_format()\n"
+"\n"
+" Build a new format based on the attributes of the shader.\n"
+"\n"
+" :return: vertex attribute format for the shader\n"
+" :rtype: GPUVertFormat\n"
+);
+static PyObject *bpygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg))
+{
+ BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL);
+ GPU_vertformat_from_interface(&ret->fmt, GPU_shader_get_interface(self->shader));
+ return (PyObject *)ret;
+}
+
+static struct PyMethodDef bpygpu_shader_methods[] = {
+ {"bind", (PyCFunction)bpygpu_shader_bind,
+ METH_NOARGS, bpygpu_shader_bind_doc},
+ {"uniform_from_name",
+ (PyCFunction)bpygpu_shader_uniform_from_name,
+ METH_O, bpygpu_shader_uniform_from_name_doc},
+ {"uniform_block_from_name",
+ (PyCFunction)bpygpu_shader_uniform_block_from_name,
+ METH_O, bpygpu_shader_uniform_block_from_name_doc},
+ {"uniform_vector_float",
+ (PyCFunction)bpygpu_shader_uniform_vector_float,
+ METH_VARARGS, bpygpu_shader_uniform_vector_float_doc},
+ {"uniform_vector_int",
+ (PyCFunction)bpygpu_shader_uniform_vector_int,
+ METH_VARARGS, bpygpu_shader_uniform_vector_int_doc},
+ {"uniform_bool",
+ (PyCFunction)bpygpu_shader_uniform_bool,
+ METH_VARARGS, bpygpu_shader_uniform_bool_doc},
+ {"uniform_float",
+ (PyCFunction)bpygpu_shader_uniform_float,
+ METH_VARARGS, bpygpu_shader_uniform_float_doc},
+ {"uniform_int",
+ (PyCFunction)bpygpu_shader_uniform_int,
+ METH_VARARGS, bpygpu_shader_uniform_int_doc},
+ {"attr_from_name",
+ (PyCFunction)bpygpu_shader_attr_from_name,
+ METH_O, bpygpu_shader_attr_from_name_doc},
+ {"format_calc",
+ (PyCFunction)bpygpu_shader_calc_format,
+ METH_NOARGS, bpygpu_shader_calc_format_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(bpygpu_shader_program_doc,
+"The name of the program object for use by the OpenGL API (read-only).\n\n:type: int"
+);
+static PyObject *bpygpu_shader_program_get(BPyGPUShader *self, void *UNUSED(closure))
+{
+ return PyLong_FromLong(GPU_shader_get_program(self->shader));
+}
+
+static PyGetSetDef bpygpu_shader_getseters[] = {
+ {(char *)"program",
+ (getter)bpygpu_shader_program_get, (setter)NULL,
+ bpygpu_shader_program_doc, NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
+
+
+static void bpygpu_shader_dealloc(BPyGPUShader *self)
+{
+ if (self->is_builtin == false) {
+ GPU_shader_free(self->shader);
+ }
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+
+PyDoc_STRVAR(bpygpu_shader_doc,
+".. class:: GPUShader(vertexcode, fragcode, geocode=None, libcode=None, defines=None)\n"
+"\n"
+" GPUShader combines multiple GLSL shaders into a program used for drawing.\n"
+" It must contain a vertex and fragment shaders, with an optional geometry shader.\n"
+"\n"
+" The GLSL #version directive is automatically included at the top of shaders, and set to 330.\n"
+" Some preprocessor directives are automatically added according to the Operating System or availability:\n"
+" ``GPU_ATI``, ``GPU_NVIDIA`` and ``GPU_INTEL``.\n"
+"\n"
+" The following extensions are enabled by default if supported by the GPU:\n"
+" ``GL_ARB_texture_gather`` and ``GL_ARB_texture_query_lod``.\n"
+"\n"
+" To debug shaders, use the --debug-gpu-shaders command line option"
+" to see full GLSL shader compilation and linking errors.\n"
+"\n"
+" :param vertexcode: Vertex shader code.\n"
+" :type vertexcode: str\n"
+" :param fragcode: Fragment shader code.\n"
+" :type value: str\n"
+" :param geocode: Geometry shader code.\n"
+" :type value: str\n"
+" :param libcode: Code with functions and presets to be shared between shaders.\n"
+" :type value: str\n"
+" :param defines: Preprocessor directives.\n"
+" :type value: str\n"
+);
+PyTypeObject BPyGPUShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "GPUShader",
+ .tp_basicsize = sizeof(BPyGPUShader),
+ .tp_dealloc = (destructor)bpygpu_shader_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = bpygpu_shader_doc,
+ .tp_methods = bpygpu_shader_methods,
+ .tp_getset = bpygpu_shader_getseters,
+ .tp_new = bpygpu_shader_new,
+};
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name gpu.shader Module API
+ * \{ */
+
+PyDoc_STRVAR(bpygpu_shader_unbind_doc,
+".. function:: unbind()\n"
+"\n"
+" Unbind the bound shader object.\n"
+);
+static PyObject *bpygpu_shader_unbind(BPyGPUShader *UNUSED(self))
+{
+ GPU_shader_unbind();
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpygpu_shader_from_builtin_doc,
+".. function:: from_builtin(shader_name)\n"
+"\n"
+" Shaders that are embedded in the blender internal code.\n"
+" They all read the uniform 'mat4 ModelViewProjectionMatrix', which can be edited by the 'gpu.matrix' module.\n"
+" For more details, you can check the shader code with the function 'gpu.shader.code_from_builtin';\n"
+"\n"
+" :param shader_name: One of these builtin shader names: {\n"
+" '2D_UNIFORM_COLOR',\n"
+" '2D_FLAT_COLOR',\n"
+" '2D_SMOOTH_COLOR',\n"
+" '2D_IMAGE',\n"
+" '3D_UNIFORM_COLOR',\n"
+" '3D_FLAT_COLOR',\n"
+" '3D_SMOOTH_COLOR'}\n"
+" :type shader_name: str\n"
+" :return: Shader object corresponding to the given name.\n"
+" :rtype: :class:`bpy.types.GPUShader`\n"
+);
+static PyObject *bpygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *arg)
+{
+ GPUBuiltinShader shader_id;
+
+ if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) {
+ return NULL;
+ }
+
+ GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
+
+ return BPyGPUShader_CreatePyObject(shader, true);
+}
+
+PyDoc_STRVAR(bpygpu_shader_code_from_builtin_doc,
+".. function:: code_from_builtin(shader_name)\n"
+"\n"
+" Exposes the internal shader code for query.\n"
+"\n"
+" :param shader_name: One of these builtin shader names: {\n"
+" '2D_UNIFORM_COLOR',\n"
+" '2D_FLAT_COLOR',\n"
+" '2D_SMOOTH_COLOR',\n"
+" '2D_IMAGE',\n"
+" '3D_UNIFORM_COLOR',\n"
+" '3D_FLAT_COLOR',\n"
+" '3D_SMOOTH_COLOR'}\n"
+" :type shader_name: str\n"
+" :return: Vertex, fragment and geometry shader codes.\n"
+" :rtype: dict\n"
+);
+static PyObject *bpygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyObject *arg)
+{
+ GPUBuiltinShader shader_id;
+
+ const char *vert;
+ const char *frag;
+ const char *geom;
+ const char *defines;
+
+ PyObject *item, *r_dict;
+
+ if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) {
+ return NULL;
+ }
+
+ GPU_shader_get_builtin_shader_code(
+ shader_id, &vert, &frag, &geom, &defines);
+
+ r_dict = PyDict_New();
+
+ PyDict_SetItemString(r_dict, "vertex_shader", item = PyUnicode_FromString(vert));
+ Py_DECREF(item);
+
+ PyDict_SetItemString(r_dict, "fragment_shader", item = PyUnicode_FromString(frag));
+ Py_DECREF(item);
+
+ if (geom) {
+ PyDict_SetItemString(r_dict, "geometry_shader", item = PyUnicode_FromString(geom));
+ Py_DECREF(item);
+ }
+ if (defines) {
+ PyDict_SetItemString(r_dict, "defines", item = PyUnicode_FromString(defines));
+ Py_DECREF(item);
+ }
+ return r_dict;
+}
+
+static struct PyMethodDef bpygpu_shader_module_methods[] = {
+ {"unbind",
+ (PyCFunction)bpygpu_shader_unbind,
+ METH_NOARGS, bpygpu_shader_unbind_doc},
+ {"from_builtin",
+ (PyCFunction)bpygpu_shader_from_builtin,
+ METH_O, bpygpu_shader_from_builtin_doc},
+ {"code_from_builtin",
+ (PyCFunction)bpygpu_shader_code_from_builtin,
+ METH_O, bpygpu_shader_code_from_builtin_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(bpygpu_shader_module_doc,
+"This module provides access to GPUShader internal functions."
+);
+static PyModuleDef BPyGPU_shader_module_def = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "gpu.shader",
+ .m_doc = bpygpu_shader_module_doc,
+ .m_methods = bpygpu_shader_module_methods,
+};
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public API
+ * \{ */
+
+PyObject *BPyGPUShader_CreatePyObject(GPUShader *shader, bool is_builtin)
+{
+ BPyGPUShader *self;
+
+ self = PyObject_New(BPyGPUShader, &BPyGPUShader_Type);
+ self->shader = shader;
+ self->is_builtin = is_builtin;
+
+ return (PyObject *)self;
+}
+
+PyObject *BPyInit_gpu_shader(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&BPyGPU_shader_module_def);
+
+ return submodule;
+}
+
+/** \} */
diff --git a/source/blender/python/gpu/gpu_py_shader.h b/source/blender/python/gpu/gpu_py_shader.h
new file mode 100644
index 00000000000..c038cf63e40
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_shader.h
@@ -0,0 +1,41 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_shader.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_SHADER_H__
+#define __GPU_PY_SHADER_H__
+
+extern PyTypeObject BPyGPUShader_Type;
+
+#define BPyGPUShader_Check(v) (Py_TYPE(v) == &BPyGPUShader_Type)
+
+typedef struct BPyGPUShader {
+ PyObject_VAR_HEAD
+ struct GPUShader *shader;
+ bool is_builtin;
+} BPyGPUShader;
+
+PyObject *BPyGPUShader_CreatePyObject(struct GPUShader *shader, bool is_builtin);
+PyObject *BPyInit_gpu_shader(void);
+
+#endif /* __GPU_PY_SHADER_H__ */
diff --git a/source/blender/python/gpu/gpu_py_types.c b/source/blender/python/gpu/gpu_py_types.c
new file mode 100644
index 00000000000..d9ef0736f8e
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_types.c
@@ -0,0 +1,80 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_types.c
+ * \ingroup bpygpu
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+#include "gpu_py_types.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+
+
+/** \name GPU Types Module
+ * \{ */
+
+static struct PyModuleDef BPyGPU_types_module_def = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "gpu.types",
+};
+
+PyObject *BPyInit_gpu_types(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&BPyGPU_types_module_def);
+
+ if (PyType_Ready(&BPyGPUVertFormat_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&BPyGPUVertBuf_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&BPyGPUIndexBuf_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&BPyGPUBatch_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&BPyGPUOffScreen_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&BPyGPUShader_Type) < 0)
+ return NULL;
+
+#define MODULE_TYPE_ADD(s, t) \
+ PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t)
+
+ MODULE_TYPE_ADD(submodule, BPyGPUVertFormat_Type);
+ MODULE_TYPE_ADD(submodule, BPyGPUVertBuf_Type);
+ MODULE_TYPE_ADD(submodule, BPyGPUIndexBuf_Type);
+ MODULE_TYPE_ADD(submodule, BPyGPUBatch_Type);
+ MODULE_TYPE_ADD(submodule, BPyGPUOffScreen_Type);
+ MODULE_TYPE_ADD(submodule, BPyGPUShader_Type);
+
+#undef MODULE_TYPE_ADD
+
+ return submodule;
+}
+
+/** \} */
diff --git a/source/blender/python/gpu/gpu_py_types.h b/source/blender/python/gpu/gpu_py_types.h
new file mode 100644
index 00000000000..dc91c579aaf
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_types.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_types.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_TYPES_H__
+#define __GPU_PY_TYPES_H__
+
+#include "gpu_py_vertex_format.h"
+#include "gpu_py_vertex_buffer.h"
+#include "gpu_py_element.h"
+#include "gpu_py_batch.h"
+#include "gpu_py_offscreen.h"
+#include "gpu_py_shader.h"
+
+PyObject *BPyInit_gpu_types(void);
+
+#endif /* __GPU_PY_TYPES_H__ */
diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c
new file mode 100644
index 00000000000..c13e3f2195e
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c
@@ -0,0 +1,352 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_vertex_buffer.c
+ * \ingroup bpygpu
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "GPU_vertex_buffer.h"
+
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+#include "gpu_py_vertex_format.h"
+#include "gpu_py_vertex_buffer.h" /* own include */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Utility Functions
+ * \{ */
+
+#define PY_AS_NATIVE_SWITCH(attr) \
+ switch (attr->comp_type) { \
+ case GPU_COMP_I8: { PY_AS_NATIVE(int8_t, PyC_Long_AsI8); break; } \
+ case GPU_COMP_U8: { PY_AS_NATIVE(uint8_t, PyC_Long_AsU8); break; } \
+ case GPU_COMP_I16: { PY_AS_NATIVE(int16_t, PyC_Long_AsI16); break; } \
+ case GPU_COMP_U16: { PY_AS_NATIVE(uint16_t, PyC_Long_AsU16); break; } \
+ case GPU_COMP_I32: { PY_AS_NATIVE(int32_t, PyC_Long_AsI32); break; } \
+ case GPU_COMP_U32: { PY_AS_NATIVE(uint32_t, PyC_Long_AsU32); break; } \
+ case GPU_COMP_F32: { PY_AS_NATIVE(float, PyFloat_AsDouble); break; } \
+ default: \
+ BLI_assert(0); \
+ } ((void)0)
+
+/* No error checking, callers must run PyErr_Occurred */
+static void fill_format_elem(void *data_dst_void, PyObject *py_src, const GPUVertAttr *attr)
+{
+#define PY_AS_NATIVE(ty_dst, py_as_native) \
+{ \
+ ty_dst *data_dst = data_dst_void; \
+ *data_dst = py_as_native(py_src); \
+} ((void)0)
+
+ PY_AS_NATIVE_SWITCH(attr);
+
+#undef PY_AS_NATIVE
+}
+
+/* No error checking, callers must run PyErr_Occurred */
+static void fill_format_sequence(void *data_dst_void, PyObject *py_seq_fast, const GPUVertAttr *attr)
+{
+ const uint len = attr->comp_len;
+ PyObject **value_fast_items = PySequence_Fast_ITEMS(py_seq_fast);
+
+/**
+ * Args are constants, so range checks will be optimized out if they're nop's.
+ */
+#define PY_AS_NATIVE(ty_dst, py_as_native) \
+ ty_dst *data_dst = data_dst_void; \
+ for (uint i = 0; i < len; i++) { \
+ data_dst[i] = py_as_native(value_fast_items[i]); \
+ } ((void)0)
+
+ PY_AS_NATIVE_SWITCH(attr);
+
+#undef PY_AS_NATIVE
+}
+
+#undef PY_AS_NATIVE_SWITCH
+#undef WARN_TYPE_LIMIT_PUSH
+#undef WARN_TYPE_LIMIT_POP
+
+static bool bpygpu_vertbuf_fill_impl(
+ GPUVertBuf *vbo,
+ uint data_id, PyObject *seq, const char *error_prefix)
+{
+ const char *exc_str_size_mismatch = "Expected a %s of size %d, got %u";
+
+ bool ok = true;
+ const GPUVertAttr *attr = &vbo->format.attribs[data_id];
+
+ if (PyObject_CheckBuffer(seq)) {
+ Py_buffer pybuffer;
+
+ if (PyObject_GetBuffer(seq, &pybuffer, PyBUF_STRIDES | PyBUF_ND) == -1) {
+ /* PyObject_GetBuffer raise a PyExc_BufferError */
+ return false;
+ }
+
+ uint comp_len = pybuffer.ndim == 1 ? 1 : (uint)pybuffer.shape[1];
+
+ if (pybuffer.shape[0] != vbo->vertex_len) {
+ PyErr_Format(PyExc_ValueError, exc_str_size_mismatch,
+ "sequence", vbo->vertex_len, pybuffer.shape[0]);
+ ok = false;
+ }
+ else if (comp_len != attr->comp_len) {
+ PyErr_Format(PyExc_ValueError, exc_str_size_mismatch,
+ "component", attr->comp_len, comp_len);
+ ok = false;
+ }
+ else {
+ GPU_vertbuf_attr_fill_stride(vbo, data_id, pybuffer.strides[0], pybuffer.buf);
+ }
+
+ PyBuffer_Release(&pybuffer);
+ }
+ else {
+ GPUVertBufRaw data_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, data_id, &data_step);
+
+ PyObject *seq_fast = PySequence_Fast(seq, "Vertex buffer fill");
+ if (seq_fast == NULL) {
+ return false;
+ }
+
+ const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast);
+
+ if (seq_len != vbo->vertex_len) {
+ PyErr_Format(PyExc_ValueError, exc_str_size_mismatch,
+ "sequence", vbo->vertex_len, seq_len);
+ }
+
+ PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast);
+
+ if (attr->comp_len == 1) {
+ for (uint i = 0; i < seq_len; i++) {
+ uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step);
+ PyObject *item = seq_items[i];
+ fill_format_elem(data, item, attr);
+ }
+ }
+ else {
+ for (uint i = 0; i < seq_len; i++) {
+ uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step);
+ PyObject *seq_fast_item = PySequence_Fast(seq_items[i], error_prefix);
+
+ if (seq_fast_item == NULL) {
+ ok = false;
+ goto finally;
+ }
+ if (PySequence_Fast_GET_SIZE(seq_fast_item) != attr->comp_len) {
+ PyErr_Format(PyExc_ValueError, exc_str_size_mismatch,
+ "sequence", attr->comp_len, PySequence_Fast_GET_SIZE(seq_fast_item));
+ ok = false;
+ Py_DECREF(seq_fast_item);
+ goto finally;
+ }
+
+ /* May trigger error, check below */
+ fill_format_sequence(data, seq_fast_item, attr);
+ Py_DECREF(seq_fast_item);
+ }
+ }
+
+ if (PyErr_Occurred()) {
+ ok = false;
+ }
+
+finally:
+
+ Py_DECREF(seq_fast);
+ }
+ return ok;
+}
+
+static int bpygpu_attr_fill(GPUVertBuf *buf, int id, PyObject *py_seq_data, const char *error_prefix)
+{
+ if (id < 0 || id >= buf->format.attr_len) {
+ PyErr_Format(PyExc_ValueError,
+ "Format id %d out of range",
+ id);
+ return 0;
+ }
+
+ if (buf->data == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "Can't fill, static buffer already in use");
+ return 0;
+ }
+
+ if (!bpygpu_vertbuf_fill_impl(buf, (uint)id, py_seq_data, error_prefix)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name VertBuf Type
+ * \{ */
+
+static PyObject *bpygpu_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
+{
+ struct {
+ PyObject *py_fmt;
+ uint len;
+ } params;
+
+ static const char *_keywords[] = {"format", "len", NULL};
+ static _PyArg_Parser _parser = {"O!I:GPUVertBuf.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ &BPyGPUVertFormat_Type, &params.py_fmt,
+ &params.len))
+ {
+ return NULL;
+ }
+
+ const GPUVertFormat *fmt = &((BPyGPUVertFormat *)params.py_fmt)->fmt;
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(fmt);
+
+ GPU_vertbuf_data_alloc(vbo, params.len);
+
+ return BPyGPUVertBuf_CreatePyObject(vbo);
+}
+
+PyDoc_STRVAR(bpygpu_VertBuf_attr_fill_doc,
+".. method:: attr_fill(id, data)\n"
+"\n"
+" Insert data into the buffer for a single attribute.\n"
+"\n"
+" :param id: Either the name or the id of the attribute.\n"
+" :type id: int or str\n"
+" :param data: Sequence of data that should be stored in the buffer\n"
+" :type data: sequence of values or tuples\n"
+);
+static PyObject *bpygpu_VertBuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *data;
+ PyObject *identifier;
+
+ static const char *_keywords[] = {"id", "data", NULL};
+ static _PyArg_Parser _parser = {"OO:attr_fill", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ &identifier, &data))
+ {
+ return NULL;
+ }
+
+ int id;
+
+ if (PyLong_Check(identifier)) {
+ id = PyLong_AsLong(identifier);
+ }
+ else if (PyUnicode_Check(identifier)) {
+ const char *name = PyUnicode_AsUTF8(identifier);
+ id = GPU_vertformat_attr_id_get(&self->buf->format, name);
+ if (id == -1) {
+ PyErr_SetString(PyExc_ValueError,
+ "Unknown attribute name");
+ return NULL;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "expected int or str type as identifier");
+ return NULL;
+ }
+
+
+ if (!bpygpu_attr_fill(self->buf, id, data, "GPUVertBuf.attr_fill")) {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+static struct PyMethodDef bpygpu_VertBuf_methods[] = {
+ {"attr_fill", (PyCFunction) bpygpu_VertBuf_attr_fill,
+ METH_VARARGS | METH_KEYWORDS, bpygpu_VertBuf_attr_fill_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static void bpygpu_VertBuf_dealloc(BPyGPUVertBuf *self)
+{
+ GPU_vertbuf_discard(self->buf);
+ Py_TYPE(self)->tp_free(self);
+}
+
+PyDoc_STRVAR(py_gpu_vertex_buffer_doc,
+".. class:: GPUVertBuf(len, format)\n"
+"\n"
+" Contains a VBO.\n"
+"\n"
+" :param len: Amount of vertices that will fit into this buffer.\n"
+" :type type: `int`\n"
+" :param format: Vertex format.\n"
+" :type buf: :class:`gpu.types.GPUVertFormat`\n"
+);
+PyTypeObject BPyGPUVertBuf_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "GPUVertBuf",
+ .tp_basicsize = sizeof(BPyGPUVertBuf),
+ .tp_dealloc = (destructor)bpygpu_VertBuf_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = py_gpu_vertex_buffer_doc,
+ .tp_methods = bpygpu_VertBuf_methods,
+ .tp_new = bpygpu_VertBuf_new,
+};
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public API
+ * \{ */
+
+PyObject *BPyGPUVertBuf_CreatePyObject(GPUVertBuf *buf)
+{
+ BPyGPUVertBuf *self;
+
+ self = PyObject_New(BPyGPUVertBuf, &BPyGPUVertBuf_Type);
+ self->buf = buf;
+
+ return (PyObject *)self;
+}
+
+/** \} */
diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.h b/source/blender/python/gpu/gpu_py_vertex_buffer.h
new file mode 100644
index 00000000000..6751956298c
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_vertex_buffer.h
@@ -0,0 +1,42 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_vertex_buffer.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_VERTEX_BUFFER_H__
+#define __GPU_PY_VERTEX_BUFFER_H__
+
+#include "BLI_compiler_attrs.h"
+
+extern PyTypeObject BPyGPUVertBuf_Type;
+
+#define BPyGPUVertBuf_Check(v) (Py_TYPE(v) == &BPyGPUVertBuf_Type)
+
+typedef struct BPyGPUVertBuf {
+ PyObject_VAR_HEAD
+ /* The buf is owned, we may support thin wrapped batches later. */
+ struct GPUVertBuf *buf;
+} BPyGPUVertBuf;
+
+PyObject *BPyGPUVertBuf_CreatePyObject(struct GPUVertBuf *vbo) ATTR_NONNULL(1);
+
+#endif /* __GPU_PY_VERTEX_BUFFER_H__ */
diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c
new file mode 100644
index 00000000000..27f3791ec15
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_vertex_format.c
@@ -0,0 +1,263 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_vertex_format.c
+ * \ingroup bpygpu
+ *
+ * - Use ``bpygpu_`` for local API.
+ * - Use ``BPyGPU`` for public API.
+ */
+
+#include <Python.h>
+
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+#include "gpu_py_vertex_format.h" /* own include */
+
+#ifdef __BIG_ENDIAN__
+ /* big endian */
+# define MAKE_ID2(c, d) ((c) << 8 | (d))
+# define MAKE_ID3(a, b, c) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 )
+# define MAKE_ID4(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) )
+#else
+ /* little endian */
+# define MAKE_ID2(c, d) ((d) << 8 | (c))
+# define MAKE_ID3(a, b, c) ( (int)(c) << 16 | (b) << 8 | (a) )
+# define MAKE_ID4(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) )
+#endif
+
+/* -------------------------------------------------------------------- */
+
+/** \name Enum Conversion
+ *
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ * \{ */
+
+static int bpygpu_parse_component_type(const char *str, int length)
+{
+ if (length == 2) {
+ switch (*((ushort *)str)) {
+ case MAKE_ID2('I', '8'): return GPU_COMP_I8;
+ case MAKE_ID2('U', '8'): return GPU_COMP_U8;
+ default: break;
+ }
+ }
+ else if (length == 3) {
+ switch (*((uint *)str)) {
+ case MAKE_ID3('I', '1', '6'): return GPU_COMP_I16;
+ case MAKE_ID3('U', '1', '6'): return GPU_COMP_U16;
+ case MAKE_ID3('I', '3', '2'): return GPU_COMP_I32;
+ case MAKE_ID3('U', '3', '2'): return GPU_COMP_U32;
+ case MAKE_ID3('F', '3', '2'): return GPU_COMP_F32;
+ case MAKE_ID3('I', '1', '0'): return GPU_COMP_I10;
+ default: break;
+ }
+ }
+ return -1;
+}
+
+static int bpygpu_parse_fetch_mode(const char *str, int length)
+{
+#define MATCH_ID(id) \
+ if (length == strlen(STRINGIFY(id))) { \
+ if (STREQ(str, STRINGIFY(id))) { \
+ return GPU_FETCH_##id; \
+ } \
+ } ((void)0)
+
+ MATCH_ID(FLOAT);
+ MATCH_ID(INT);
+ MATCH_ID(INT_TO_FLOAT_UNIT);
+ MATCH_ID(INT_TO_FLOAT);
+#undef MATCH_ID
+
+ return -1;
+}
+
+static int bpygpu_ParseVertCompType(PyObject *o, void *p)
+{
+ Py_ssize_t length;
+ const char *str = _PyUnicode_AsStringAndSize(o, &length);
+
+ if (str == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "expected a string, got %s",
+ Py_TYPE(o)->tp_name);
+ return 0;
+ }
+
+ int comp_type = bpygpu_parse_component_type(str, length);
+ if (comp_type == -1) {
+ PyErr_Format(PyExc_ValueError,
+ "unkown component type: '%s",
+ str);
+ return 0;
+ }
+
+ *((GPUVertCompType *)p) = comp_type;
+ return 1;
+}
+
+static int bpygpu_ParseVertFetchMode(PyObject *o, void *p)
+{
+ Py_ssize_t length;
+ const char *str = _PyUnicode_AsStringAndSize(o, &length);
+
+ if (str == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "expected a string, got %s",
+ Py_TYPE(o)->tp_name);
+ return 0;
+ }
+
+ int fetch_mode = bpygpu_parse_fetch_mode(str, length);
+ if (fetch_mode == -1) {
+ PyErr_Format(PyExc_ValueError,
+ "unknown type literal: '%s'",
+ str);
+ return 0;
+ }
+
+ (*(GPUVertFetchMode *)p) = fetch_mode;
+ return 1;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name VertFormat Type
+ * \{ */
+
+static PyObject *bpygpu_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
+{
+ if (PyTuple_GET_SIZE(args) || (kwds && PyDict_Size(kwds))) {
+ PyErr_SetString(PyExc_ValueError, "This function takes no arguments");
+ return NULL;
+ }
+ return BPyGPUVertFormat_CreatePyObject(NULL);
+}
+
+PyDoc_STRVAR(bpygpu_VertFormat_attr_add_doc,
+".. method:: attr_add(id, comp_type, len, fetch_mode)\n"
+"\n"
+" Add a new attribute to the format.\n"
+"\n"
+" :param id: Name the attribute. Often `position`, `normal`, ...\n"
+" :type id: str\n"
+" :param comp_type: The data type that will be used store the value in memory.\n"
+" Possible values are `I8`, `U8`, `I16`, `U16`, `I32`, `U32`, `F32` and `I10`.\n"
+" :type comp_type: `str`\n"
+" :param len: How many individual values the attribute consists of (e.g. 2 for uv coordinates).\n"
+" :type len: int\n"
+" :param fetch_mode: How values from memory will be converted when used in the shader.\n"
+" This is mainly useful for memory optimizations when you want to store values with reduced precision.\n"
+" E.g. you can store a float in only 1 byte but it will be converted to a normal 4 byte float when used.\n"
+" Possible values are `FLOAT`, `INT`, `INT_TO_FLOAT_UNIT` and `INT_TO_FLOAT`.\n"
+" :type fetch_mode: `str`\n"
+);
+static PyObject *bpygpu_VertFormat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds)
+{
+ struct {
+ const char *id;
+ GPUVertCompType comp_type;
+ uint len;
+ GPUVertFetchMode fetch_mode;
+ } params;
+
+ if (self->fmt.attr_len == GPU_VERT_ATTR_MAX_LEN) {
+ PyErr_SetString(PyExc_ValueError, "Maxumum attr reached " STRINGIFY(GPU_VERT_ATTR_MAX_LEN));
+ return NULL;
+ }
+
+ static const char *_keywords[] = {"id", "comp_type", "len", "fetch_mode", NULL};
+ static _PyArg_Parser _parser = {"$sO&IO&:attr_add", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser,
+ &params.id,
+ bpygpu_ParseVertCompType, &params.comp_type,
+ &params.len,
+ bpygpu_ParseVertFetchMode, &params.fetch_mode))
+ {
+ return NULL;
+ }
+
+ uint attr_id = GPU_vertformat_attr_add(&self->fmt, params.id, params.comp_type, params.len, params.fetch_mode);
+ return PyLong_FromLong(attr_id);
+}
+
+static struct PyMethodDef bpygpu_VertFormat_methods[] = {
+ {"attr_add", (PyCFunction)bpygpu_VertFormat_attr_add,
+ METH_VARARGS | METH_KEYWORDS, bpygpu_VertFormat_attr_add_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+
+static void bpygpu_VertFormat_dealloc(BPyGPUVertFormat *self)
+{
+ Py_TYPE(self)->tp_free(self);
+}
+
+PyDoc_STRVAR(bpygpu_VertFormat_doc,
+".. class:: GPUVertFormat()\n"
+"\n"
+" This object contains information about the structure of a vertex buffer.\n"
+);
+PyTypeObject BPyGPUVertFormat_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "GPUVertFormat",
+ .tp_basicsize = sizeof(BPyGPUVertFormat),
+ .tp_dealloc = (destructor)bpygpu_VertFormat_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = bpygpu_VertFormat_doc,
+ .tp_methods = bpygpu_VertFormat_methods,
+ .tp_new = bpygpu_VertFormat_new,
+};
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Public API
+ * \{ */
+
+PyObject *BPyGPUVertFormat_CreatePyObject(GPUVertFormat *fmt)
+{
+ BPyGPUVertFormat *self;
+
+ self = PyObject_New(BPyGPUVertFormat, &BPyGPUVertFormat_Type);
+ if (fmt) {
+ self->fmt = *fmt;
+ }
+ else {
+ memset(&self->fmt, 0, sizeof(self->fmt));
+ }
+
+ return (PyObject *)self;
+}
+
+/** \} */
diff --git a/source/blender/python/gpu/gpu_py_vertex_format.h b/source/blender/python/gpu/gpu_py_vertex_format.h
new file mode 100644
index 00000000000..5b0bf1addc2
--- /dev/null
+++ b/source/blender/python/gpu/gpu_py_vertex_format.h
@@ -0,0 +1,41 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/gpu/gpu_py_vertex_format.h
+ * \ingroup bpygpu
+ */
+
+#ifndef __GPU_PY_VERTEX_FORMAT_H__
+#define __GPU_PY_VERTEX_FORMAT_H__
+
+#include "GPU_vertex_format.h"
+
+extern PyTypeObject BPyGPUVertFormat_Type;
+
+#define BPyGPUVertFormat_Check(v) (Py_TYPE(v) == &BPyGPUVertFormat_Type)
+
+typedef struct BPyGPUVertFormat {
+ PyObject_VAR_HEAD
+ struct GPUVertFormat fmt;
+} BPyGPUVertFormat;
+
+PyObject *BPyGPUVertFormat_CreatePyObject(struct GPUVertFormat *fmt);
+
+#endif /* __GPU_PY_VERTEX_FORMAT_H__ */
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 357cb175769..bd7306cddf2 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -52,11 +52,13 @@ set(SRC
bpy_app_build_options.c
bpy_app_ffmpeg.c
bpy_app_handlers.c
+ bpy_app_icons.c
bpy_app_ocio.c
bpy_app_oiio.c
bpy_app_opensubdiv.c
bpy_app_openvdb.c
bpy_app_sdl.c
+ bpy_app_timers.c
bpy_app_translations.c
bpy_capi_utils.c
bpy_driver.c
@@ -65,6 +67,8 @@ set(SRC
bpy_intern_string.c
bpy_library_load.c
bpy_library_write.c
+ bpy_gizmo_wrap.c
+ bpy_msgbus.c
bpy_operator.c
bpy_operator_wrap.c
bpy_path.c
@@ -75,11 +79,10 @@ set(SRC
bpy_rna_callback.c
bpy_rna_driver.c
bpy_rna_id_collection.c
+ bpy_rna_gizmo.c
bpy_traceback.c
bpy_utils_previews.c
bpy_utils_units.c
- gpu.c
- gpu_offscreen.c
stubs.c
bpy.h
@@ -88,16 +91,20 @@ set(SRC
bpy_app_build_options.h
bpy_app_ffmpeg.h
bpy_app_handlers.h
+ bpy_app_icons.h
bpy_app_ocio.h
bpy_app_oiio.h
bpy_app_opensubdiv.h
bpy_app_openvdb.h
bpy_app_sdl.h
+ bpy_app_timers.h
bpy_app_translations.h
bpy_capi_utils.h
bpy_driver.h
bpy_intern_string.h
bpy_library.h
+ bpy_gizmo_wrap.h
+ bpy_msgbus.h
bpy_operator.h
bpy_operator_wrap.h
bpy_path.h
@@ -107,10 +114,10 @@ set(SRC
bpy_rna_callback.h
bpy_rna_driver.h
bpy_rna_id_collection.h
+ bpy_rna_gizmo.h
bpy_traceback.h
bpy_utils_previews.h
bpy_utils_units.h
- gpu.h
../BPY_extern.h
../BPY_extern_clog.h
)
@@ -176,10 +183,6 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
-if(WITH_GAMEENGINE)
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
if(WITH_IMAGE_CINEON)
add_definitions(-DWITH_CINEON)
endif()
@@ -188,10 +191,6 @@ if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
-if(WITH_IMAGE_FRAMESERVER)
- add_definitions(-DWITH_FRAMESERVER)
-endif()
-
if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
@@ -302,10 +301,6 @@ if(WITH_OPENSUBDIV)
)
endif()
-if(WITH_PLAYER)
- add_definitions(-DWITH_PLAYER)
-endif()
-
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_python "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 82f710e4acf..07ad8274f11 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -46,6 +46,7 @@
#include "bpy_rna.h"
#include "bpy_app.h"
#include "bpy_rna_id_collection.h"
+#include "bpy_rna_gizmo.h"
#include "bpy_props.h"
#include "bpy_library.h"
#include "bpy_operator.h"
@@ -57,6 +58,7 @@
/* external util modules */
#include "../generic/idprop_py_api.h"
+#include "bpy_msgbus.h"
#ifdef WITH_FREESTYLE
# include "BPy_Freestyle.h"
@@ -338,6 +340,8 @@ void BPy_init_modules(void)
BPY_rna_id_collection_module(mod);
+ BPY_rna_gizmo_module(mod);
+
bpy_import_test("bpy_types");
PyModule_AddObject(mod, "data", BPY_rna_module()); /* imports bpy_types by running this */
bpy_import_test("bpy_types");
@@ -347,6 +351,7 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, "app", BPY_app_struct());
PyModule_AddObject(mod, "_utils_units", BPY_utils_units());
PyModule_AddObject(mod, "_utils_previews", BPY_utils_previews_module());
+ PyModule_AddObject(mod, "msgbus", BPY_msgbus_module());
/* bpy context */
RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr);
@@ -371,6 +376,9 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, meth_bpy_register_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_register_class, NULL));
PyModule_AddObject(mod, meth_bpy_unregister_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unregister_class, NULL));
+ PyModule_AddObject(mod, meth_bpy_owner_id_get.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_owner_id_get, NULL));
+ PyModule_AddObject(mod, meth_bpy_owner_id_set.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_owner_id_set, NULL));
+
/* add our own modules dir, this is a python package */
bpy_package_py = bpy_import_test("bpy");
}
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 928e14c09bf..bba9eee0316 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -47,11 +47,16 @@
#include "bpy_app_handlers.h"
#include "bpy_driver.h"
+/* modules */
+#include "bpy_app_icons.h"
+#include "bpy_app_timers.h"
+
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
#include "BKE_global.h"
+#include "BKE_library_override.h"
#include "DNA_ID.h"
@@ -117,6 +122,10 @@ static PyStructSequence_Field app_info_fields[] = {
{(char *)"build_options", (char *)"A set containing most important enabled optional build features"},
{(char *)"handlers", (char *)"Application handler callbacks"},
{(char *)"translations", (char *)"Application and addons internationalization API"},
+
+ /* Modules (not struct sequence). */
+ {(char *)"icons", (char *)"Manage custom icons"},
+ {(char *)"timers", (char *)"Manage timers"},
{NULL},
};
@@ -129,6 +138,8 @@ PyDoc_STRVAR(bpy_app_doc,
" :maxdepth: 1\n"
"\n"
" bpy.app.handlers.rst\n"
+" bpy.app.icons.rst\n"
+" bpy.app.timers.rst\n"
" bpy.app.translations.rst\n"
);
@@ -210,6 +221,10 @@ static PyObject *make_app_info(void)
SetObjItem(BPY_app_handlers_struct());
SetObjItem(BPY_app_translations_struct());
+ /* modules */
+ SetObjItem(BPY_app_icons_module());
+ SetObjItem(BPY_app_timers_module());
+
#undef SetIntItem
#undef SetStrItem
#undef SetBytesItem
@@ -348,6 +363,29 @@ static PyObject *bpy_app_autoexec_fail_message_get(PyObject *UNUSED(self), void
}
+PyDoc_STRVAR(bpy_app_use_static_override_doc,
+"Boolean, whether static override is exposed in UI or not."
+);
+static PyObject *bpy_app_use_static_override_get(PyObject *UNUSED(self), void *UNUSED(closure))
+{
+ return PyBool_FromLong((long)BKE_override_static_is_enabled());
+}
+
+static int bpy_app_use_static_override_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure))
+{
+ const int param = PyC_Long_AsBool(value);
+
+ if (param == -1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "bpy.app.use_static_override must be a boolean");
+ return -1;
+ }
+
+ BKE_override_static_enable((const bool)param);
+
+ return 0;
+}
+
+
static PyGetSetDef bpy_app_getsets[] = {
{(char *)"debug", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG},
{(char *)"debug_ffmpeg", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_FFMPEG},
@@ -366,6 +404,8 @@ static PyGetSetDef bpy_app_getsets[] = {
{(char *)"debug_gpumem", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_GPU_MEM},
{(char *)"debug_io", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_IO},
+ {(char *)"use_static_override", bpy_app_use_static_override_get, bpy_app_use_static_override_set, (char *)bpy_app_use_static_override_doc, NULL},
+
{(char *)"binary_path_python", bpy_app_binary_path_python_get, NULL, (char *)bpy_app_binary_path_python_doc, NULL},
{(char *)"debug_value", bpy_app_debug_value_get, bpy_app_debug_value_set, (char *)bpy_app_debug_value_doc, NULL},
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index d5c325e4317..70c52b8860c 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -42,10 +42,8 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"cycles", NULL},
{(char *)"cycles_osl", NULL},
{(char *)"freestyle", NULL},
- {(char *)"gameengine", NULL},
{(char *)"image_cineon", NULL},
{(char *)"image_dds", NULL},
- {(char *)"image_frameserver", NULL},
{(char *)"image_hdr", NULL},
{(char *)"image_openexr", NULL},
{(char *)"image_openjpeg", NULL},
@@ -64,7 +62,6 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"mod_smoke", NULL},
{(char *)"collada", NULL},
{(char *)"opencolorio", NULL},
- {(char *)"player", NULL},
{(char *)"openmp", NULL},
{(char *)"openvdb", NULL},
{(char *)"alembic", NULL},
@@ -140,12 +137,6 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
-#ifdef WITH_GAMEENGINE
- SetObjIncref(Py_True);
-#else
- SetObjIncref(Py_False);
-#endif
-
#ifdef WITH_CINEON
SetObjIncref(Py_True);
#else
@@ -158,12 +149,6 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
-#ifdef WITH_FRAMESERVER
- SetObjIncref(Py_True);
-#else
- SetObjIncref(Py_False);
-#endif
-
#ifdef WITH_HDR
SetObjIncref(Py_True);
#else
@@ -272,12 +257,6 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
-#ifdef WITH_PLAYER
- SetObjIncref(Py_True);
-#else
- SetObjIncref(Py_False);
-#endif
-
#ifdef _OPENMP
SetObjIncref(Py_True);
#else
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index 8453808d6ec..a251bdeb15b 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -46,32 +46,27 @@ void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg);
static PyTypeObject BlenderAppCbType;
static PyStructSequence_Field app_cb_info_fields[] = {
- {(char *)"frame_change_pre", (char *)"on frame change for playback and rendering (before)"},
- {(char *)"frame_change_post", (char *)"on frame change for playback and rendering (after)"},
- {(char *)"render_pre", (char *)"on render (before)"},
- {(char *)"render_post", (char *)"on render (after)"},
- {(char *)"render_write", (char *)"on writing a render frame (directly after the frame is written)"},
- {(char *)"render_stats", (char *)"on printing render statistics"},
- {(char *)"render_init", (char *)"on initialization of a render job"},
- {(char *)"render_complete", (char *)"on completion of render job"},
- {(char *)"render_cancel", (char *)"on canceling a render job"},
- {(char *)"load_pre", (char *)"on loading a new blend file (before)"},
- {(char *)"load_post", (char *)"on loading a new blend file (after)"},
- {(char *)"save_pre", (char *)"on saving a blend file (before)"},
- {(char *)"save_post", (char *)"on saving a blend file (after)"},
- {(char *)"undo_pre", (char *)"on loading an undo step (before)"},
- {(char *)"undo_post", (char *)"on loading an undo step (after)"},
- {(char *)"redo_pre", (char *)"on loading a redo step (before)"},
- {(char *)"redo_post", (char *)"on loading a redo step (after)"},
- {(char *)"scene_update_pre", (char *)"on every scene data update. Does not imply that anything changed in the "
- "scene, just that the dependency graph is about to be reevaluated, and the "
- "scene is about to be updated by Blender's animation system."},
- {(char *)"scene_update_post", (char *)"on every scene data update. Does not imply that anything changed in the "
- "scene, just that the dependency graph was reevaluated, and the scene was "
- "possibly updated by Blender's animation system."},
- {(char *)"game_pre", (char *)"on starting the game engine"},
- {(char *)"game_post", (char *)"on ending the game engine"},
- {(char *)"version_update", (char *)"on ending the versioning code"},
+ {(char *)"frame_change_pre", (char *)"on frame change for playback and rendering (before)"},
+ {(char *)"frame_change_post", (char *)"on frame change for playback and rendering (after)"},
+ {(char *)"render_pre", (char *)"on render (before)"},
+ {(char *)"render_post", (char *)"on render (after)"},
+ {(char *)"render_write", (char *)"on writing a render frame (directly after the frame is written)"},
+ {(char *)"render_stats", (char *)"on printing render statistics"},
+ {(char *)"render_init", (char *)"on initialization of a render job"},
+ {(char *)"render_complete", (char *)"on completion of render job"},
+ {(char *)"render_cancel", (char *)"on canceling a render job"},
+ {(char *)"load_pre", (char *)"on loading a new blend file (before)"},
+ {(char *)"load_post", (char *)"on loading a new blend file (after)"},
+ {(char *)"save_pre", (char *)"on saving a blend file (before)"},
+ {(char *)"save_post", (char *)"on saving a blend file (after)"},
+ {(char *)"undo_pre", (char *)"on loading an undo step (before)"},
+ {(char *)"undo_post", (char *)"on loading an undo step (after)"},
+ {(char *)"redo_pre", (char *)"on loading a redo step (before)"},
+ {(char *)"redo_post", (char *)"on loading a redo step (after)"},
+ {(char *)"depsgraph_update_pre", (char *)"on depsgraph update (pre)"},
+ {(char *)"depsgraph_update_post", (char *)"on depsgraph update (post)"},
+ {(char *)"version_update", (char *)"on ending the versioning code"},
+ {(char *)"load_factory_startup_post", (char *)"on loading factory startup (after)"},
/* sets the permanent tag */
# define APP_CB_OTHER_FIELDS 1
diff --git a/source/blender/python/intern/bpy_app_icons.c b/source/blender/python/intern/bpy_app_icons.c
new file mode 100644
index 00000000000..12315a6e112
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_icons.c
@@ -0,0 +1,187 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_icons.c
+ * \ingroup pythonintern
+ *
+ * Runtime defined icons.
+ */
+
+#include <Python.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_icons.h"
+
+#include "../generic/py_capi_utils.h"
+
+#include "bpy_app_icons.h"
+
+/* We may want to load direct from file. */
+PyDoc_STRVAR(bpy_app_icons_new_triangles_doc,
+".. function:: new_triangles(range, coords, colors)"
+"\n"
+" Create a new icon from triangle geometry.\n"
+"\n"
+" :arg range: Pair of ints.\n"
+" :type range: tuple.\n"
+" :arg coords: Sequence of bytes (6 floats for one triangle) for (X, Y) coordinates.\n"
+" :type coords: byte sequence.\n"
+" :arg colors: Sequence of ints (12 for one triangles) for RGBA.\n"
+" :type colors: byte sequence.\n"
+" :return: Unique icon value (pass to interface ``icon_value`` argument).\n"
+" :rtype: int\n"
+);
+static PyObject *bpy_app_icons_new_triangles(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ /* bytes */
+ uchar coords_range[2];
+ PyObject *py_coords, *py_colors;
+
+ static const char *_keywords[] = {"range", "coords", "colors", NULL};
+ static _PyArg_Parser _parser = {"(BB)SS:new_triangles", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &coords_range[0], &coords_range[1], &py_coords, &py_colors))
+ {
+ return NULL;
+ }
+
+ const int coords_len = PyBytes_GET_SIZE(py_coords);
+ const int tris_len = coords_len / 6;
+ if (tris_len * 6 != coords_len) {
+ PyErr_SetString(PyExc_ValueError, "coords must be multiple of 6");
+ return NULL;
+ }
+ if (PyBytes_GET_SIZE(py_colors) != 2 * coords_len) {
+ PyErr_SetString(PyExc_ValueError, "colors must be twice size of coords");
+ return NULL;
+ }
+
+ int coords_size = sizeof(uchar[2]) * tris_len * 3;
+ int colors_size = sizeof(uchar[4]) * tris_len * 3;
+ uchar (*coords)[2] = MEM_mallocN(coords_size, __func__);
+ uchar (*colors)[4] = MEM_mallocN(colors_size, __func__);
+
+ memcpy(coords, PyBytes_AS_STRING(py_coords), coords_size);
+ memcpy(colors, PyBytes_AS_STRING(py_colors), colors_size);
+
+ struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__);
+ geom->coords_len = tris_len;
+ geom->coords_range[0] = coords_range[0];
+ geom->coords_range[1] = coords_range[1];
+ geom->coords = coords;
+ geom->colors = colors;
+ geom->icon_id = 0;
+ int icon_id = BKE_icon_geom_ensure(geom);
+ return PyLong_FromLong(icon_id);
+}
+
+PyDoc_STRVAR(bpy_app_icons_new_triangles_from_file_doc,
+".. function:: new_triangles_from_file(filename)"
+"\n"
+" Create a new icon from triangle geometry.\n"
+"\n"
+" :arg filename: File path.\n"
+" :type filename: string.\n"
+" :return: Unique icon value (pass to interface ``icon_value`` argument).\n"
+" :rtype: int\n"
+);
+static PyObject *bpy_app_icons_new_triangles_from_file(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ /* bytes */
+ char *filename;
+
+ static const char *_keywords[] = {"filename", NULL};
+ static _PyArg_Parser _parser = {"s:new_triangles_from_file", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &filename))
+ {
+ return NULL;
+ }
+
+ struct Icon_Geom *geom = BKE_icon_geom_from_file(filename);
+ if (geom == NULL) {
+ PyErr_SetString(PyExc_ValueError, "Unable to load from file");
+ return NULL;
+ }
+ int icon_id = BKE_icon_geom_ensure(geom);
+ return PyLong_FromLong(icon_id);
+}
+
+PyDoc_STRVAR(bpy_app_icons_release_doc,
+".. function:: release(icon_id)"
+"\n"
+" Release the icon.\n"
+);
+static PyObject *bpy_app_icons_release(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ int icon_id;
+ static const char *_keywords[] = {"icon_id", NULL};
+ static _PyArg_Parser _parser = {"i:release", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &icon_id))
+ {
+ return NULL;
+ }
+
+ if (!BKE_icon_delete_unmanaged(icon_id)) {
+ PyErr_SetString(PyExc_ValueError, "invalid icon_id");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef M_AppIcons_methods[] = {
+ {"new_triangles", (PyCFunction)bpy_app_icons_new_triangles,
+ METH_VARARGS | METH_KEYWORDS, bpy_app_icons_new_triangles_doc},
+ {"new_triangles_from_file", (PyCFunction)bpy_app_icons_new_triangles_from_file,
+ METH_VARARGS | METH_KEYWORDS, bpy_app_icons_new_triangles_from_file_doc},
+ {"release", (PyCFunction)bpy_app_icons_release,
+ METH_VARARGS | METH_KEYWORDS, bpy_app_icons_release_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef M_AppIcons_module_def = {
+ PyModuleDef_HEAD_INIT,
+ "bpy.app.icons", /* m_name */
+ NULL, /* m_doc */
+ 0, /* m_size */
+ M_AppIcons_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+PyObject *BPY_app_icons_module(void)
+{
+ PyObject *sys_modules = PyImport_GetModuleDict();
+
+ PyObject *mod = PyModule_Create(&M_AppIcons_module_def);
+
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(mod), mod);
+
+ return mod;
+}
diff --git a/source/blender/python/intern/bpy_app_icons.h b/source/blender/python/intern/bpy_app_icons.h
new file mode 100644
index 00000000000..309c7ed222f
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_icons.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_icons.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_APP_ICONS_H__
+#define __BPY_APP_ICONS_H__
+
+PyObject *BPY_app_icons_module(void);
+
+#endif /* __BPY_APP_ICONS_H__ */
diff --git a/source/blender/python/intern/bpy_app_timers.c b/source/blender/python/intern/bpy_app_timers.c
new file mode 100644
index 00000000000..cd0e57200ec
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_timers.c
@@ -0,0 +1,199 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_timers.c
+ * \ingroup pythonintern
+ */
+
+#include <Python.h>
+#include "BLI_utildefines.h"
+#include "BLI_timer.h"
+#include "PIL_time.h"
+
+#include "BPY_extern.h"
+#include "bpy_app_timers.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+
+static double handle_returned_value(PyObject *function, PyObject *ret)
+{
+ if (ret == NULL) {
+ PyErr_PrintEx(0);
+ PyErr_Clear();
+ return -1;
+ }
+
+ if (ret == Py_None) {
+ return -1;
+ }
+
+ double value = PyFloat_AsDouble(ret);
+ if (value == -1.0f && PyErr_Occurred()) {
+ PyErr_Clear();
+ printf("Error: 'bpy.app.timers' callback ");
+ PyObject_Print(function, stdout, Py_PRINT_RAW);
+ printf(" did not return None or float.\n");
+ return -1;
+ }
+
+ if (value < 0.0) {
+ value = 0.0;
+ }
+
+ return value;
+}
+
+static double py_timer_execute(uintptr_t UNUSED(uuid), void *user_data)
+{
+ PyObject *function = user_data;
+
+ PyGILState_STATE gilstate;
+ gilstate = PyGILState_Ensure();
+
+ PyObject *py_ret = PyObject_CallObject(function, NULL);
+ double ret = handle_returned_value(function, py_ret);
+
+ PyGILState_Release(gilstate);
+
+ return ret;
+}
+
+static void py_timer_free(uintptr_t UNUSED(uuid), void *user_data)
+{
+ PyObject *function = user_data;
+
+ PyGILState_STATE gilstate;
+ gilstate = PyGILState_Ensure();
+
+ Py_DECREF(function);
+
+ PyGILState_Release(gilstate);
+}
+
+
+PyDoc_STRVAR(bpy_app_timers_register_doc,
+".. function:: register(function, first_interval=0, persistent=False)\n"
+"\n"
+" Add a new function that will be called after the specified amount of seconds.\n"
+" The function gets no arguments and is expected to return either None or a float.\n"
+" If ``None`` is returned, the timer will be unregistered.\n"
+" A returned number specifies the delay until the function is called again.\n"
+" ``functools.partial`` can be used to assign some parameters.\n"
+"\n"
+" :arg function: The function that should called.\n"
+" :type function: Callable[[], Union[float, None]]\n"
+" :arg first_interval: Seconds until the callback should be called the first time.\n"
+" :type first_interval: float\n"
+" :arg persistent: Don't remove timer when a new file is loaded.\n"
+" :type persistent: bool\n"
+);
+static PyObject *bpy_app_timers_register(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ PyObject *function;
+ double first_interval = 0;
+ int persistent = false;
+
+ static const char *_keywords[] = {"function", "first_interval", "persistent", NULL};
+ static _PyArg_Parser _parser = {"O|$dp:register", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &function, &first_interval, &persistent))
+ {
+ return NULL;
+ }
+
+ if (!PyCallable_Check(function)) {
+ PyErr_SetString(PyExc_TypeError, "function is not callable");
+ return NULL;
+ }
+
+ Py_INCREF(function);
+ BLI_timer_register(
+ (intptr_t)function,
+ py_timer_execute, function, py_timer_free,
+ first_interval, persistent);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpy_app_timers_unregister_doc,
+".. function:: unregister(function)\n"
+"\n"
+" Unregister timer.\n"
+"\n"
+" :arg function: Function to unregister.\n"
+" :type function: function\n"
+);
+static PyObject *bpy_app_timers_unregister(PyObject *UNUSED(self), PyObject *function)
+{
+ if (!BLI_timer_unregister((intptr_t)function)) {
+ PyErr_SetString(PyExc_ValueError, "Error: function is not registered");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpy_app_timers_is_registered_doc,
+".. function:: is_registered(function)\n"
+"\n"
+" Check if this function is registered as a timer.\n"
+"\n"
+" :arg function: Function to check.\n"
+" :type function: int\n"
+" :return: True when this function is registered, otherwise False.\n"
+" :rtype: bool\n"
+);
+static PyObject *bpy_app_timers_is_registered(PyObject *UNUSED(self), PyObject *function)
+{
+ bool ret = BLI_timer_is_registered((intptr_t)function);
+ return PyBool_FromLong(ret);
+}
+
+
+static struct PyMethodDef M_AppTimers_methods[] = {
+ {"register", (PyCFunction)bpy_app_timers_register,
+ METH_VARARGS | METH_KEYWORDS, bpy_app_timers_register_doc},
+ {"unregister", (PyCFunction)bpy_app_timers_unregister,
+ METH_O, bpy_app_timers_unregister_doc},
+ {"is_registered", (PyCFunction)bpy_app_timers_is_registered,
+ METH_O, bpy_app_timers_is_registered_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef M_AppTimers_module_def = {
+ PyModuleDef_HEAD_INIT,
+ "bpy.app.timers", /* m_name */
+ NULL, /* m_doc */
+ 0, /* m_size */
+ M_AppTimers_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+PyObject *BPY_app_timers_module(void)
+{
+ PyObject *sys_modules = PyImport_GetModuleDict();
+ PyObject *mod = PyModule_Create(&M_AppTimers_module_def);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(mod), mod);
+ return mod;
+}
diff --git a/source/blender/python/intern/bpy_app_timers.h b/source/blender/python/intern/bpy_app_timers.h
new file mode 100644
index 00000000000..ddf0e258e67
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_timers.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_timers.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_APP_TIMERS_H__
+#define __BPY_APP_TIMERS_H__
+
+PyObject *BPY_app_timers_module(void);
+
+#endif /* __BPY_APP_TIMERS_H__ */
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index e7608e93f58..f098a28d679 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -48,6 +48,8 @@
#include "bpy_driver.h"
+#include "BPY_extern.h"
+
extern void BPY_update_rna_module(void);
#define USE_RNA_AS_PYOBJECT
@@ -381,8 +383,12 @@ static bool bpy_driver_secure_bytecode_validate(PyObject *expr_code, PyObject *d
* (new)note: checking if python is running is not threadsafe [#28114]
* now release the GIL on python operator execution instead, using
* PyEval_SaveThread() / PyEval_RestoreThread() so we don't lock up blender.
+ *
+ * For copy-on-write we always cache expressions and write errors in the
+ * original driver, otherwise these would get freed while editing. Due to
+ * the GIL this is thread-safe.
*/
-float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
+float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime)
{
PyObject *driver_vars = NULL;
PyObject *retval = NULL;
@@ -398,7 +404,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c
int i;
/* get the py expression to be evaluated */
- expr = driver->expression;
+ expr = driver_orig->expression;
if (expr[0] == '\0')
return 0.0f;
@@ -438,50 +444,50 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c
/* update global namespace */
bpy_pydriver_namespace_update_frame(evaltime);
- if (driver->flag & DRIVER_FLAG_USE_SELF) {
+ if (driver_orig->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;
+ if (driver_orig->expr_comp == NULL)
+ driver_orig->flag |= DRIVER_FLAG_RECOMPILE;
/* compile the expression first if it hasn't been compiled or needs to be rebuilt */
- if (driver->flag & DRIVER_FLAG_RECOMPILE) {
- Py_XDECREF(driver->expr_comp);
- driver->expr_comp = PyTuple_New(2);
+ if (driver_orig->flag & DRIVER_FLAG_RECOMPILE) {
+ Py_XDECREF(driver_orig->expr_comp);
+ driver_orig->expr_comp = PyTuple_New(2);
expr_code = Py_CompileString(expr, "<bpy driver>", Py_eval_input);
- PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 0, expr_code);
+ PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, expr_code);
- driver->flag &= ~DRIVER_FLAG_RECOMPILE;
- driver->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */
+ driver_orig->flag &= ~DRIVER_FLAG_RECOMPILE;
+ driver_orig->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */
#ifdef USE_BYTECODE_WHITELIST
is_recompile = true;
#endif
}
else {
- expr_code = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 0);
+ expr_code = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 0);
}
- if (driver->flag & DRIVER_FLAG_RENAMEVAR) {
+ if (driver_orig->flag & DRIVER_FLAG_RENAMEVAR) {
/* may not be set */
- expr_vars = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1);
+ expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1);
Py_XDECREF(expr_vars);
- expr_vars = PyTuple_New(BLI_listbase_count(&driver->variables));
- PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 1, expr_vars);
+ expr_vars = PyTuple_New(BLI_listbase_count(&driver_orig->variables));
+ PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 1, expr_vars);
- for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
+ for (dvar = driver_orig->variables.first, i = 0; dvar; dvar = dvar->next) {
PyTuple_SET_ITEM(expr_vars, i++, PyUnicode_FromString(dvar->name));
}
- driver->flag &= ~DRIVER_FLAG_RENAMEVAR;
+ driver_orig->flag &= ~DRIVER_FLAG_RENAMEVAR;
}
else {
- expr_vars = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1);
+ expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1);
}
/* add target values to a dict that will be used as '__locals__' dict */
@@ -543,7 +549,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c
}
#ifdef USE_BYTECODE_WHITELIST
- if (is_recompile) {
+ if (is_recompile && expr_code) {
if (!(G.f & G_SCRIPT_AUTOEXEC)) {
if (!bpy_driver_secure_bytecode_validate(
expr_code, (PyObject *[]){
@@ -555,7 +561,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c
{
Py_DECREF(expr_code);
expr_code = NULL;
- PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 0, NULL);
+ PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, NULL);
}
}
}
@@ -595,7 +601,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, c
return (float)result;
}
else {
- fprintf(stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", dvar->name, result);
+ fprintf(stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", driver->expression, result);
return 0.0f;
}
}
diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h
index 017a6fe89c5..971cbdf901f 100644
--- a/source/blender/python/intern/bpy_driver.h
+++ b/source/blender/python/intern/bpy_driver.h
@@ -27,14 +27,7 @@
#ifndef __BPY_DRIVER_H__
#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 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_gizmo_wrap.c b/source/blender/python/intern/bpy_gizmo_wrap.c
new file mode 100644
index 00000000000..411822ee4da
--- /dev/null
+++ b/source/blender/python/intern/bpy_gizmo_wrap.c
@@ -0,0 +1,228 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_gizmo_wrap.c
+ * \ingroup pythonintern
+ *
+ * This file is so Python can define widget-group's that C can call into.
+ * The generic callback functions for Python widget-group are defines in
+ * 'rna_wm.c', some calling into functions here to do python specific
+ * functionality.
+ *
+ * \note This follows 'bpy_operator_wrap.c' very closely.
+ * Keep in sync unless there is good reason not to!
+ */
+
+#include <Python.h>
+
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "bpy_rna.h"
+#include "bpy_intern_string.h"
+#include "bpy_gizmo_wrap.h" /* own include */
+
+/* we may want to add, but not now */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Gizmo
+ * \{ */
+
+
+static bool bpy_gizmotype_target_property_def(
+ wmGizmoType *gzt, PyObject *item)
+{
+ /* Note: names based on 'rna_rna.c' */
+ PyObject *empty_tuple = PyTuple_New(0);
+
+ struct {
+ char *id;
+ char *type_id; int type;
+ int array_length;
+ } params = {
+ .id = NULL, /* not optional */
+ .type = PROP_FLOAT,
+ .type_id = NULL,
+ .array_length = 1,
+ };
+
+ static const char * const _keywords[] = {"id", "type", "array_length", NULL};
+ static _PyArg_Parser _parser = {"|$ssi:register_class", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ empty_tuple, item,
+ &_parser,
+ &params.id,
+ &params.type_id,
+ &params.array_length))
+ {
+ goto fail;
+ }
+
+ if (params.id == NULL) {
+ PyErr_SetString(PyExc_ValueError, "'id' argument not given");
+ goto fail;
+ }
+
+ if ((params.type_id != NULL) &&
+ pyrna_enum_value_from_id(
+ rna_enum_property_type_items, params.type_id, &params.type, "'type' enum value") == -1)
+ {
+ goto fail;
+ }
+ else {
+ params.type = rna_enum_property_type_items[params.type].value;
+ }
+
+ if ((params.array_length < 1 || params.array_length > RNA_MAX_ARRAY_LENGTH)) {
+ PyErr_SetString(PyExc_ValueError, "'array_length' out of range");
+ goto fail;
+ }
+
+ WM_gizmotype_target_property_def(gzt, params.id, params.type, params.array_length);
+ Py_DECREF(empty_tuple);
+ return true;
+
+fail:
+ Py_DECREF(empty_tuple);
+ return false;
+}
+
+static void gizmo_properties_init(wmGizmoType *gzt)
+{
+ PyTypeObject *py_class = gzt->ext.data;
+ RNA_struct_blender_type_set(gzt->ext.srna, gzt);
+
+ /* only call this so pyrna_deferred_register_class gives a useful error
+ * WM_operatortype_append_ptr will call RNA_def_struct_identifier
+ * later */
+ RNA_def_struct_identifier_no_struct_map(gzt->srna, gzt->idname);
+
+ if (pyrna_deferred_register_class(gzt->srna, py_class) != 0) {
+ PyErr_Print(); /* failed to register operator props */
+ PyErr_Clear();
+ }
+
+ /* Extract target property definitions from 'bl_target_properties' */
+ {
+ /* picky developers will notice that 'bl_targets' won't work with inheritance
+ * get direct from the dict to avoid raising a load of attribute errors (yes this isnt ideal) - campbell */
+ PyObject *py_class_dict = py_class->tp_dict;
+ PyObject *bl_target_properties = PyDict_GetItem(py_class_dict, bpy_intern_str_bl_target_properties);
+
+ /* Some widgets may only exist to activate operators. */
+ if (bl_target_properties != NULL) {
+ PyObject *bl_target_properties_fast;
+ if (!(bl_target_properties_fast = PySequence_Fast(
+ bl_target_properties, "bl_target_properties sequence")))
+ {
+ /* PySequence_Fast sets the error */
+ PyErr_Print();
+ PyErr_Clear();
+ return;
+ }
+
+ const uint items_len = PySequence_Fast_GET_SIZE(bl_target_properties_fast);
+ PyObject **items = PySequence_Fast_ITEMS(bl_target_properties_fast);
+
+ for (uint i = 0; i < items_len; i++) {
+ if (!bpy_gizmotype_target_property_def(gzt, items[i])) {
+ PyErr_Print();
+ PyErr_Clear();
+ break;
+ }
+ }
+
+ Py_DECREF(bl_target_properties_fast);
+ }
+ }
+}
+
+void BPY_RNA_gizmo_wrapper(wmGizmoType *gzt, void *userdata)
+{
+ /* take care not to overwrite anything set in
+ * WM_gizmomaptype_group_link_ptr before opfunc() is called */
+ StructRNA *srna = gzt->srna;
+ *gzt = *((wmGizmoType *)userdata);
+ gzt->srna = srna; /* restore */
+
+ /* don't do translations here yet */
+#if 0
+ /* Use i18n context from ext.srna if possible (py gizmogroups). */
+ if (gt->ext.srna) {
+ RNA_def_struct_translation_context(gt->srna, RNA_struct_translation_context(gt->ext.srna));
+ }
+#endif
+
+ gzt->struct_size = sizeof(wmGizmo);
+
+ gizmo_properties_init(gzt);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Gizmo Group
+ * \{ */
+
+static void gizmogroup_properties_init(wmGizmoGroupType *gzgt)
+{
+ PyTypeObject *py_class = gzgt->ext.data;
+ RNA_struct_blender_type_set(gzgt->ext.srna, gzgt);
+
+ /* only call this so pyrna_deferred_register_class gives a useful error
+ * WM_operatortype_append_ptr will call RNA_def_struct_identifier
+ * later */
+ RNA_def_struct_identifier_no_struct_map(gzgt->srna, gzgt->idname);
+
+ if (pyrna_deferred_register_class(gzgt->srna, py_class) != 0) {
+ PyErr_Print(); /* failed to register operator props */
+ PyErr_Clear();
+ }
+}
+
+void BPY_RNA_gizmogroup_wrapper(wmGizmoGroupType *gzgt, void *userdata)
+{
+ /* take care not to overwrite anything set in
+ * WM_gizmomaptype_group_link_ptr before opfunc() is called */
+ StructRNA *srna = gzgt->srna;
+ *gzgt = *((wmGizmoGroupType *)userdata);
+ gzgt->srna = srna; /* restore */
+
+ /* don't do translations here yet */
+#if 0
+ /* Use i18n context from ext.srna if possible (py gizmogroups). */
+ if (gzgt->ext.srna) {
+ RNA_def_struct_translation_context(gzgt->srna, RNA_struct_translation_context(gzgt->ext.srna));
+ }
+#endif
+
+ gizmogroup_properties_init(gzgt);
+}
+
+/** \} */
diff --git a/source/blender/python/intern/bpy_gizmo_wrap.h b/source/blender/python/intern/bpy_gizmo_wrap.h
new file mode 100644
index 00000000000..96f15312a4e
--- /dev/null
+++ b/source/blender/python/intern/bpy_gizmo_wrap.h
@@ -0,0 +1,35 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_gizmo_wrap.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_GIZMO_WRAP_H__
+#define __BPY_GIZMO_WRAP_H__
+
+struct wmGizmoType;
+struct wmGizmoGroupType;
+
+/* exposed to rna/wm api */
+void BPY_RNA_gizmo_wrapper(struct wmGizmoType *gzt, void *userdata);
+void BPY_RNA_gizmogroup_wrapper(struct wmGizmoGroupType *gzgt, void *userdata);
+
+#endif /* __BPY_GIZMO_WRAP_H__ */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 1ae3106aa76..e17e7562f2a 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -46,7 +46,6 @@
#include "RNA_types.h"
#include "bpy.h"
-#include "gpu.h"
#include "bpy_rna.h"
#include "bpy_path.h"
#include "bpy_capi_utils.h"
@@ -59,9 +58,9 @@
#include "BKE_appdir.h"
#include "BKE_context.h"
-#include "BKE_text.h"
-#include "BKE_main.h"
#include "BKE_global.h" /* only for script checking */
+#include "BKE_main.h"
+#include "BKE_text.h"
#include "CCL_api.h"
@@ -75,6 +74,7 @@
#include "../generic/blf_py_api.h"
#include "../generic/idprop_py_api.h"
#include "../generic/imbuf_py_api.h"
+#include "../gpu/gpu_py_api.h"
#include "../bmesh/bmesh_py_api.h"
#include "../mathutils/mathutils.h"
@@ -233,7 +233,7 @@ static struct _inittab bpy_internal_modules[] = {
#ifdef WITH_CYCLES
{"_cycles", CCL_initPython},
#endif
- {"gpu", GPU_initPython},
+ {"gpu", BPyInit_gpu},
{"idprop", BPyInit_idprop},
{NULL, NULL}
};
@@ -537,7 +537,8 @@ static bool python_script_exec(
if (py_dict) {
#ifdef PYMODULE_CLEAR_WORKAROUND
- PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItemString(PyImport_GetModuleDict(), "__main__");
+ PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItem(
+ PyImport_GetModuleDict(), bpy_intern_str___main__);
PyObject *dict_back = mmod->md_dict;
/* freeing the module will clear the namespace,
* gives problems running classes defined in this namespace being used later. */
diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c
index ac0100fa75d..41276963fc9 100644
--- a/source/blender/python/intern/bpy_intern_string.c
+++ b/source/blender/python/intern/bpy_intern_string.c
@@ -34,21 +34,24 @@
#include "BLI_utildefines.h"
-static PyObject *bpy_intern_str_arr[13];
+static PyObject *bpy_intern_str_arr[16];
-PyObject *bpy_intern_str_register;
-PyObject *bpy_intern_str_unregister;
-PyObject *bpy_intern_str_bl_rna;
+PyObject *bpy_intern_str___annotations__;
+PyObject *bpy_intern_str___doc__;
+PyObject *bpy_intern_str___main__;
+PyObject *bpy_intern_str___module__;
+PyObject *bpy_intern_str___name__;
+PyObject *bpy_intern_str___slots__;
+PyObject *bpy_intern_str_attr;
PyObject *bpy_intern_str_bl_property;
+PyObject *bpy_intern_str_bl_rna;
+PyObject *bpy_intern_str_bl_target_properties;
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__;
-PyObject *bpy_intern_str___module__;
+PyObject *bpy_intern_str_properties;
+PyObject *bpy_intern_str_register;
+PyObject *bpy_intern_str_self;
+PyObject *bpy_intern_str_unregister;
void bpy_intern_string_init(void)
{
@@ -57,19 +60,22 @@ void bpy_intern_string_init(void)
#define BPY_INTERN_STR(var, str) \
{ var = bpy_intern_str_arr[i++] = PyUnicode_FromString(str); } (void)0
- BPY_INTERN_STR(bpy_intern_str_register, "register");
- BPY_INTERN_STR(bpy_intern_str_unregister, "unregister");
- BPY_INTERN_STR(bpy_intern_str_bl_rna, "bl_rna");
+ BPY_INTERN_STR(bpy_intern_str___annotations__, "__annotations__");
+ BPY_INTERN_STR(bpy_intern_str___doc__, "__doc__");
+ BPY_INTERN_STR(bpy_intern_str___main__, "__main__");
+ BPY_INTERN_STR(bpy_intern_str___module__, "__module__");
+ BPY_INTERN_STR(bpy_intern_str___name__, "__name__");
+ BPY_INTERN_STR(bpy_intern_str___slots__, "__slots__");
+ BPY_INTERN_STR(bpy_intern_str_attr, "attr");
BPY_INTERN_STR(bpy_intern_str_bl_property, "bl_property");
+ BPY_INTERN_STR(bpy_intern_str_bl_rna, "bl_rna");
+ BPY_INTERN_STR(bpy_intern_str_bl_target_properties, "bl_target_properties");
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__");
- BPY_INTERN_STR(bpy_intern_str___module__, "__module__");
+ BPY_INTERN_STR(bpy_intern_str_properties, "properties");
+ BPY_INTERN_STR(bpy_intern_str_register, "register");
+ BPY_INTERN_STR(bpy_intern_str_self, "self");
+ BPY_INTERN_STR(bpy_intern_str_unregister, "unregister");
#undef BPY_INTERN_STR
diff --git a/source/blender/python/intern/bpy_intern_string.h b/source/blender/python/intern/bpy_intern_string.h
index 394e84d89bd..41cd58f9c3d 100644
--- a/source/blender/python/intern/bpy_intern_string.h
+++ b/source/blender/python/intern/bpy_intern_string.h
@@ -30,18 +30,21 @@
void bpy_intern_string_init(void);
void bpy_intern_string_exit(void);
-extern PyObject *bpy_intern_str_register;
-extern PyObject *bpy_intern_str_unregister;
-extern PyObject *bpy_intern_str_bl_rna;
+extern PyObject *bpy_intern_str___annotations__;
+extern PyObject *bpy_intern_str___doc__;
+extern PyObject *bpy_intern_str___main__;
+extern PyObject *bpy_intern_str___module__;
+extern PyObject *bpy_intern_str___name__;
+extern PyObject *bpy_intern_str___slots__;
+extern PyObject *bpy_intern_str_attr;
extern PyObject *bpy_intern_str_bl_property;
+extern PyObject *bpy_intern_str_bl_rna;
+extern PyObject *bpy_intern_str_bl_target_properties;
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__;
-extern PyObject *bpy_intern_str___module__;
+extern PyObject *bpy_intern_str_properties;
+extern PyObject *bpy_intern_str_register;
+extern PyObject *bpy_intern_str_self;
+extern PyObject *bpy_intern_str_unregister;
#endif /* __BPY_INTERN_STRING_H__ */
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index e66b4e834dc..f9cd3338cde 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -38,16 +38,16 @@
#include "BLI_linklist.h"
#include "BLI_path_util.h"
-#include "BLO_readfile.h"
-
-#include "BKE_main.h"
-#include "BKE_library.h"
+#include "BKE_context.h"
#include "BKE_idcode.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_report.h"
-#include "BKE_context.h"
#include "DNA_space_types.h" /* FILE_LINK, FILE_RELPATH */
+#include "BLO_readfile.h"
+
#include "bpy_capi_utils.h"
#include "bpy_library.h"
@@ -332,6 +332,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
Main *bmain = CTX_data_main(BPy_GetContext());
Main *mainl = NULL;
int err = 0;
+ const bool do_append = ((self->flag & FILE_LINK) == 0);
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
@@ -341,7 +342,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
int idcode_step = 0, idcode;
while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
- if (BKE_idcode_is_linkable(idcode)) {
+ if (BKE_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
const char *name_plural = BKE_idcode_to_name_plural(idcode);
PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
// printf("lib: %s\n", name_plural);
@@ -402,7 +403,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
}
else {
Library *lib = mainl->curlib; /* newly added lib, assign before append end */
- BLO_library_link_end(mainl, &(self->blo_handle), self->flag, NULL, NULL);
+ BLO_library_link_end(mainl, &(self->blo_handle), self->flag, NULL, NULL, NULL);
BLO_blendhandle_close(self->blo_handle);
self->blo_handle = NULL;
@@ -414,7 +415,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
BKE_main_lib_objects_recalc_all(bmain);
/* append, rather than linking */
- if ((self->flag & FILE_LINK) == 0) {
+ if (do_append) {
BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
}
}
@@ -427,7 +428,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
int idcode_step = 0, idcode;
while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
- if (BKE_idcode_is_linkable(idcode)) {
+ if (BKE_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
const char *name_plural = BKE_idcode_to_name_plural(idcode);
PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
if (ls && PyList_Check(ls)) {
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index 76b7ccf72fa..07a81a3bddb 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -34,7 +34,6 @@
#include "BLI_string.h"
#include "BLI_path_util.h"
-#include "BKE_library.h"
#include "BKE_blendfile.h"
#include "BKE_global.h"
#include "BKE_main.h"
diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c
new file mode 100644
index 00000000000..101cc8b41a3
--- /dev/null
+++ b/source/blender/python/intern/bpy_msgbus.c
@@ -0,0 +1,399 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_msgbus.c
+ * \ingroup pythonintern
+ * This file defines '_bpy_msgbus' module, exposed as 'bpy.msgbus'.
+ */
+
+#include <Python.h>
+
+#include "../generic/python_utildefines.h"
+#include "../generic/py_capi_utils.h"
+#include "../mathutils/mathutils.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "bpy_capi_utils.h"
+#include "bpy_rna.h"
+#include "bpy_intern_string.h"
+#include "bpy_gizmo_wrap.h" /* own include */
+
+
+#include "bpy_msgbus.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utils
+ * \{ */
+
+#define BPY_MSGBUS_RNA_MSGKEY_DOC \
+" :arg key: Represents the type of data being subscribed to\n" \
+"\n" \
+" Arguments include\n" \
+" - :class:`bpy.types.Property` instance.\n" \
+" - :class:`bpy.types.Struct` type.\n" \
+" - (:class:`bpy.types.Struct`, str) type and property name.\n" \
+" :type key: Muliple\n"
+
+/**
+ * There are multiple ways we can get RNA from Python,
+ * it's also possible to register a type instead of an instance.
+ *
+ * This function handles converting Python to RNA subscription information.
+ *
+ * \param py_sub: See #BPY_MSGBUS_RNA_MSGKEY_DOC for description.
+ * \param msg_key_params: Message key with all members zeroed out.
+ * \return -1 on failure, 0 on success.
+ */
+static int py_msgbus_rna_key_from_py(
+ PyObject *py_sub,
+ wmMsgParams_RNA *msg_key_params,
+ const char *error_prefix)
+{
+
+ /* Allow common case, object rotation, location - etc. */
+ if (BaseMathObject_CheckExact(py_sub)) {
+ BaseMathObject *py_sub_math = (BaseMathObject *)py_sub;
+ if (py_sub_math->cb_user == NULL) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s: math argument has no owner",
+ error_prefix);
+ return -1;
+ }
+ py_sub = py_sub_math->cb_user;
+ /* Common case will use BPy_PropertyRNA_Check below. */
+ }
+
+ if (BPy_PropertyRNA_Check(py_sub)) {
+ BPy_PropertyRNA *data_prop = (BPy_PropertyRNA *)py_sub;
+ PYRNA_PROP_CHECK_INT(data_prop);
+ msg_key_params->ptr = data_prop->ptr;
+ msg_key_params->prop = data_prop->prop;
+ }
+ else if (BPy_StructRNA_Check(py_sub)) {
+ /* note, this isn't typically used since we don't edit structs directly. */
+ BPy_StructRNA *data_srna = (BPy_StructRNA *)py_sub;
+ PYRNA_STRUCT_CHECK_INT(data_srna);
+ msg_key_params->ptr = data_srna->ptr;
+ }
+ /* TODO - property / type, not instance. */
+ else if (PyType_Check(py_sub)) {
+ StructRNA *data_type = pyrna_struct_as_srna(py_sub, false, error_prefix);
+ if (data_type == NULL) {
+ return -1;
+ }
+ msg_key_params->ptr.type = data_type;
+ }
+ else if (PyTuple_CheckExact(py_sub)) {
+ if (PyTuple_GET_SIZE(py_sub) == 2) {
+ PyObject *data_type_py = PyTuple_GET_ITEM(py_sub, 0);
+ PyObject *data_prop_py = PyTuple_GET_ITEM(py_sub, 1);
+ StructRNA *data_type = pyrna_struct_as_srna(data_type_py, false, error_prefix);
+ if (data_type == NULL) {
+ return -1;
+ }
+ if (!PyUnicode_CheckExact(data_prop_py)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s: expected property to be a string",
+ error_prefix);
+ return -1;
+ }
+ PointerRNA data_type_ptr = { .type = data_type, };
+ const char *data_prop_str = _PyUnicode_AsString(data_prop_py);
+ PropertyRNA *data_prop = RNA_struct_find_property(&data_type_ptr, data_prop_str);
+
+ if (data_prop == NULL) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s: struct %.200s does not contain property %.200s",
+ error_prefix,
+ RNA_struct_identifier(data_type),
+ data_prop_str);
+ return -1;
+ }
+
+ msg_key_params->ptr.type = data_type;
+ msg_key_params->prop = data_prop;
+ }
+ else {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: Expected a pair (type, property_id)",
+ error_prefix);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Callbacks
+ * \{ */
+
+#define BPY_MSGBUS_USER_DATA_LEN 2
+
+/* Follow wmMsgNotifyFn spec */
+static void bpy_msgbus_notify(
+ bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ PyGILState_STATE gilstate;
+ bpy_context_set(C, &gilstate);
+
+ PyObject *user_data = msg_val->user_data;
+ BLI_assert(PyTuple_GET_SIZE(user_data) == BPY_MSGBUS_USER_DATA_LEN);
+
+ PyObject *callback_args = PyTuple_GET_ITEM(user_data, 0);
+ PyObject *callback_notify = PyTuple_GET_ITEM(user_data, 1);
+
+ const bool is_write_ok = pyrna_write_check();
+ if (!is_write_ok) {
+ pyrna_write_set(true);
+ }
+
+ PyObject *ret = PyObject_CallObject(callback_notify, callback_args);
+
+ if (ret == NULL) {
+ PyC_Err_PrintWithFunc(callback_notify);
+ }
+ else {
+ if (ret != Py_None) {
+ PyErr_SetString(PyExc_ValueError, "the return value must be None");
+ PyC_Err_PrintWithFunc(callback_notify);
+ }
+ Py_DECREF(ret);
+ }
+
+ bpy_context_clear(C, &gilstate);
+
+ if (!is_write_ok) {
+ pyrna_write_set(false);
+ }
+}
+
+/* Follow wmMsgSubscribeValueFreeDataFn spec */
+static void bpy_msgbus_subscribe_value_free_data(
+ struct wmMsgSubscribeKey *UNUSED(msg_key), struct wmMsgSubscribeValue *msg_val)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ Py_DECREF(msg_val->owner);
+ Py_DECREF(msg_val->user_data);
+ PyGILState_Release(gilstate);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Message Bus API
+ * \{ */
+
+PyDoc_STRVAR(bpy_msgbus_subscribe_rna_doc,
+".. function:: subscribe_rna(data, owner, args, notify)\n"
+"\n"
+BPY_MSGBUS_RNA_MSGKEY_DOC
+" :arg owner: Handle for this subscription (compared by identity).\n"
+" :type owner: Any type.\n"
+"\n"
+" Returns a new vector int property definition.\n"
+);
+static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ const char *error_prefix = "subscribe_rna";
+ PyObject *py_sub = NULL;
+ PyObject *py_owner = NULL;
+ PyObject *callback_args = NULL;
+ PyObject *callback_notify = NULL;
+
+ enum {
+ IS_PERSISTENT = (1 << 0),
+ };
+ PyObject *py_options = NULL;
+ EnumPropertyItem py_options_enum[] = {
+ {IS_PERSISTENT, "PERSISTENT", 0, ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ int options = 0;
+
+ static const char *_keywords[] = {
+ "key",
+ "owner",
+ "args",
+ "notify",
+ "options",
+ NULL,
+ };
+ static _PyArg_Parser _parser = {"$OOO!OO!:subscribe_rna", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &py_sub, &py_owner,
+ &PyTuple_Type, &callback_args,
+ &callback_notify,
+ &PySet_Type, &py_options))
+ {
+ return NULL;
+ }
+
+ if (py_options &&
+ (pyrna_set_to_enum_bitfield(py_options_enum, py_options, &options, error_prefix)) == -1)
+ {
+ return NULL;
+ }
+
+ /* Note: we may want to have a way to pass this in. */
+ bContext *C = (bContext *)BPy_GetContext();
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ wmMsgParams_RNA msg_key_params = {{{0}}};
+
+ wmMsgSubscribeValue msg_val_params = {0};
+
+ if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) {
+ return NULL;
+ }
+
+ if (!PyFunction_Check(callback_notify)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "notify expects a function, found %.200s",
+ Py_TYPE(callback_notify)->tp_name);
+ return NULL;
+ }
+
+ if (options != 0) {
+ if (options & IS_PERSISTENT) {
+ msg_val_params.is_persistent = true;
+ }
+ }
+
+ /* owner can be anything. */
+ {
+ msg_val_params.owner = py_owner;
+ Py_INCREF(py_owner);
+ }
+
+ {
+ PyObject *user_data = PyTuple_New(2);
+ PyTuple_SET_ITEMS(
+ user_data,
+ Py_INCREF_RET(callback_args),
+ Py_INCREF_RET(callback_notify));
+ msg_val_params.user_data = user_data;
+ }
+
+ msg_val_params.notify = bpy_msgbus_notify;
+ msg_val_params.free_data = bpy_msgbus_subscribe_value_free_data;
+
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params, &msg_val_params, __func__);
+
+ WM_msg_dump(mbus, __func__);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpy_msgbus_publish_rna_doc,
+".. function:: publish_rna(data, owner, args, notify)\n"
+"\n"
+BPY_MSGBUS_RNA_MSGKEY_DOC
+"\n"
+" Notify subscribers of changes to this property\n"
+" (this typically doesn't need to be called explicitly since changes will automatically publish updates).\n"
+" In some cases it may be useful to publish changes explicitly using more general keys.\n"
+);
+static PyObject *bpy_msgbus_publish_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ const char *error_prefix = "publish_rna";
+ PyObject *py_sub = NULL;
+
+ static const char *_keywords[] = {
+ "key",
+ NULL,
+ };
+ static _PyArg_Parser _parser = {"$O:publish_rna", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &py_sub))
+ {
+ return NULL;
+ }
+
+ /* Note: we may want to have a way to pass this in. */
+ bContext *C = (bContext *)BPy_GetContext();
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ wmMsgParams_RNA msg_key_params = {{{0}}};
+
+ if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) {
+ return NULL;
+ }
+
+ WM_msg_publish_rna_params(mbus, &msg_key_params);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpy_msgbus_clear_by_owner_doc,
+".. function:: clear_by_owner(owner)\n"
+"\n"
+" Clear all subscribers using this owner.\n"
+);
+static PyObject *bpy_msgbus_clear_by_owner(PyObject *UNUSED(self), PyObject *py_owner)
+{
+ bContext *C = (bContext *)BPy_GetContext();
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msgbus_clear_by_owner(mbus, py_owner);
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef BPy_msgbus_methods[] = {
+ {"subscribe_rna", (PyCFunction)bpy_msgbus_subscribe_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_subscribe_rna_doc},
+ {"publish_rna", (PyCFunction)bpy_msgbus_publish_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_publish_rna_doc},
+ {"clear_by_owner", (PyCFunction)bpy_msgbus_clear_by_owner, METH_O, bpy_msgbus_clear_by_owner_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef _bpy_msgbus_def = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "msgbus",
+ .m_methods = BPy_msgbus_methods,
+};
+
+
+PyObject *BPY_msgbus_module(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&_bpy_msgbus_def);
+
+ return submodule;
+}
+
+/** \} */
diff --git a/source/blender/python/intern/bpy_msgbus.h b/source/blender/python/intern/bpy_msgbus.h
new file mode 100644
index 00000000000..97b20e9b926
--- /dev/null
+++ b/source/blender/python/intern/bpy_msgbus.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_msgbus.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_MSGBUS_H__
+#define __BPY_MSGBUS_H__
+
+PyObject *BPY_msgbus_module(void);
+
+#endif /* __BPY_MSGBUS_H__ */
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 0db2fc189c1..fef3a0703d2 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -3203,11 +3203,6 @@ PyObject *BPY_rna_props(void)
submodule = PyModule_Create(&props_module);
PyDict_SetItemString(PyImport_GetModuleDict(), props_module.m_name, submodule);
- /* INCREF since its its assumed that all these functions return the
- * module with a new ref like PyDict_New, since they are passed to
- * PyModule_AddObject which steals a ref */
- Py_INCREF(submodule);
-
/* api needs the PyObjects internally */
submodule_dict = PyModule_GetDict(submodule);
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index 614c1b4b708..fa2594f94d2 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -34,6 +34,6 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);
StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix);
-#define PYRNA_STACK_ARRAY 32
+#define PYRNA_STACK_ARRAY RNA_STACK_ARRAY
#endif
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 9837017b8b1..00d2a3e5fa7 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -315,7 +315,7 @@ static bool rna_id_write_error(PointerRNA *ptr, PyObject *key)
ID *id = ptr->id.data;
if (id) {
const short idcode = GS(id->name);
- if (!ELEM(idcode, ID_WM, ID_SCR)) { /* may need more added here */
+ if (!ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { /* may need more added here */
const char *idtype = BKE_idcode_to_name(idcode);
const char *pyname;
if (key && PyUnicode_Check(key)) pyname = _PyUnicode_AsString(key);
@@ -1729,7 +1729,25 @@ static int pyrna_py_to_prop(
const int subtype = RNA_property_subtype(prop);
const char *param;
- if (subtype == PROP_BYTESTRING) {
+ if (value == Py_None) {
+ if ((RNA_property_flag(prop) & PROP_NEVER_NULL) == 0) {
+ if (data) {
+ *((char **)data) = (char *)NULL;
+ }
+ else {
+ RNA_property_string_set(ptr, prop, NULL);
+ }
+ }
+ else {
+ PyC_Err_Format_Prefix(
+ PyExc_TypeError,
+ "%.200s %.200s.%.200s doesn't support None from string types",
+ error_prefix, RNA_struct_identifier(ptr->type),
+ RNA_property_identifier(prop));
+ return -1;
+ }
+ }
+ else if (subtype == PROP_BYTESTRING) {
/* Byte String */
@@ -1849,19 +1867,28 @@ static int pyrna_py_to_prop(
* class mixing if this causes problems in the future it should be removed.
*/
if ((ptr_type == &RNA_AnyType) &&
- (BPy_StructRNA_Check(value)) &&
- (RNA_struct_is_a(((BPy_StructRNA *)value)->ptr.type, &RNA_Operator)))
+ (BPy_StructRNA_Check(value)))
{
- value = PyObject_GetAttrString(value, "properties");
- value_new = value;
+ const StructRNA *base_type =
+ RNA_struct_base_child_of(((const BPy_StructRNA *)value)->ptr.type, NULL);
+ if (ELEM(base_type, &RNA_Operator, &RNA_Gizmo)) {
+ value = PyObject_GetAttr(value, bpy_intern_str_properties);
+ value_new = value;
+ }
}
-
- /* if property is an OperatorProperties pointer and value is a map,
+ /* if property is an OperatorProperties/GizmoProperties pointer and value is a map,
* forward back to pyrna_pydict_to_props */
- if (RNA_struct_is_a(ptr_type, &RNA_OperatorProperties) && PyDict_Check(value)) {
- PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
- return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
+ if (PyDict_Check(value)) {
+ const StructRNA *base_type = RNA_struct_base_child_of(ptr_type, NULL);
+ if (base_type == &RNA_OperatorProperties) {
+ PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
+ return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
+ }
+ else if (base_type == &RNA_GizmoProperties) {
+ PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
+ return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
+ }
}
/* another exception, allow to pass a collection as an RNA property */
@@ -3500,6 +3527,68 @@ static PyObject *pyrna_struct_is_property_readonly(BPy_StructRNA *self, PyObject
return PyBool_FromLong(!RNA_property_editable(&self->ptr, prop));
}
+
+PyDoc_STRVAR(pyrna_struct_is_property_overridable_static_doc,
+".. method:: is_property_overridable_static(property)\n"
+"\n"
+" Check if a property is statically overridable.\n"
+"\n"
+" :return: True when the property is statically overridable.\n"
+" :rtype: boolean\n"
+);
+static PyObject *pyrna_struct_is_property_overridable_static(BPy_StructRNA *self, PyObject *args)
+{
+ PropertyRNA *prop;
+ const char *name;
+
+ PYRNA_STRUCT_CHECK_OBJ(self);
+
+ if (!PyArg_ParseTuple(args, "s:is_property_overridable_static", &name)) {
+ return NULL;
+ }
+
+ if ((prop = RNA_struct_find_property(&self->ptr, name)) == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s.is_property_overridable_static(\"%.200s\") not found",
+ RNA_struct_identifier(self->ptr.type), name);
+ return NULL;
+ }
+
+ return PyBool_FromLong((long)RNA_property_overridable_get(&self->ptr, prop));
+}
+
+PyDoc_STRVAR(pyrna_struct_property_overridable_static_set_doc,
+".. method:: property_overridable_static_set(property)\n"
+"\n"
+" Define a property as statically overridable or not (only for custom properties!).\n"
+"\n"
+" :return: True when the overridable status of the property was successfully set.\n"
+" :rtype: boolean\n"
+);
+static PyObject *pyrna_struct_property_overridable_static_set(BPy_StructRNA *self, PyObject *args)
+{
+ PropertyRNA *prop;
+ const char *name;
+ int is_overridable;
+
+ PYRNA_STRUCT_CHECK_OBJ(self);
+
+ if (!PyArg_ParseTuple(args, "sp:property_overridable_static_set", &name, &is_overridable)) {
+ return NULL;
+ }
+
+ if ((prop = RNA_struct_find_property(&self->ptr, name)) == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s.property_overridable_static_set(\"%.200s\") not found",
+ RNA_struct_identifier(self->ptr.type), name);
+ return NULL;
+ }
+
+ return PyBool_FromLong((long)RNA_property_overridable_static_set(&self->ptr, prop, (bool)is_overridable));
+}
+
+
+
PyDoc_STRVAR(pyrna_struct_path_resolve_doc,
".. method:: path_resolve(path, coerce=True)\n"
"\n"
@@ -5172,6 +5261,8 @@ static struct PyMethodDef pyrna_struct_methods[] = {
{"property_unset", (PyCFunction)pyrna_struct_property_unset, METH_VARARGS, pyrna_struct_property_unset_doc},
{"is_property_hidden", (PyCFunction)pyrna_struct_is_property_hidden, METH_VARARGS, pyrna_struct_is_property_hidden_doc},
{"is_property_readonly", (PyCFunction)pyrna_struct_is_property_readonly, METH_VARARGS, pyrna_struct_is_property_readonly_doc},
+ {"is_property_overridable_static", (PyCFunction)pyrna_struct_is_property_overridable_static, METH_VARARGS, pyrna_struct_is_property_overridable_static_doc},
+ {"property_overridable_static_set", (PyCFunction)pyrna_struct_property_overridable_static_set, METH_VARARGS, pyrna_struct_property_overridable_static_set_doc},
{"path_resolve", (PyCFunction)pyrna_struct_path_resolve, METH_VARARGS, pyrna_struct_path_resolve_doc},
{"path_from_id", (PyCFunction)pyrna_struct_path_from_id, METH_VARARGS, pyrna_struct_path_from_id_doc},
{"type_recast", (PyCFunction)pyrna_struct_type_recast, METH_NOARGS, pyrna_struct_type_recast_doc},
@@ -5581,6 +5672,17 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
item = NULL;
if (i < pyargs_len) {
+ /* New in 2.8x, optional arguments must be keywords. */
+ if (UNLIKELY((flag_parameter & PARM_REQUIRED) == 0)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s.%.200s(): required parameter \"%.200s\" to be a keyword argument!",
+ RNA_struct_identifier(self_ptr->type),
+ RNA_function_identifier(self_func),
+ RNA_property_identifier(parm));
+ err = -1;
+ break;
+ }
+
item = PyTuple_GET_ITEM(args, i);
kw_arg = false;
}
@@ -7353,29 +7455,40 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
static int pyrna_deferred_register_props(StructRNA *srna, PyObject *class_dict)
{
+ PyObject *annotations_dict;
PyObject *item, *key;
- PyObject *order;
Py_ssize_t pos = 0;
int ret = 0;
/* in both cases PyDict_CheckExact(class_dict) will be true even
* though Operators have a metaclass dict namespace */
+ if ((annotations_dict = PyDict_GetItem(class_dict, bpy_intern_str___annotations__)) &&
+ PyDict_CheckExact(annotations_dict))
+ {
+ while (PyDict_Next(annotations_dict, &pos, &key, &item)) {
+ ret = deferred_register_prop(srna, key, item);
- if ((order = PyDict_GetItem(class_dict, bpy_intern_str_order)) && PyList_CheckExact(order)) {
- for (pos = 0; pos < PyList_GET_SIZE(order); pos++) {
- key = PyList_GET_ITEM(order, pos);
- /* however unlikely its possible
- * fails in py 3.3 beta with __qualname__ */
- if ((item = PyDict_GetItem(class_dict, key))) {
- ret = deferred_register_prop(srna, key, item);
- if (ret != 0) {
- break;
- }
+ if (ret != 0) {
+ break;
}
}
}
- else {
+
+ {
+ /* This block can be removed once 2.8x is released and annotations are in use. */
+ bool has_warning = false;
while (PyDict_Next(class_dict, &pos, &key, &item)) {
+ if (pyrna_is_deferred_prop(item)) {
+ if (!has_warning) {
+ printf("Warning: class %.200s "
+ "contains a properties which should be an annotation!\n",
+ RNA_struct_identifier(srna));
+ PyC_LineSpit();
+ has_warning = true;
+ }
+ printf(" make annotation: %.200s.%.200s\n",
+ RNA_struct_identifier(srna), _PyUnicode_AsString(key));
+ }
ret = deferred_register_prop(srna, key, item);
if (ret != 0)
@@ -7658,7 +7771,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
PyGILState_STATE gilstate;
#ifdef USE_PEDANTIC_WRITE
- const bool is_readonly_init = !RNA_struct_is_a(ptr->type, &RNA_Operator);
+ const bool is_readonly_init = !(RNA_struct_is_a(ptr->type, &RNA_Operator) ||
+ RNA_struct_is_a(ptr->type, &RNA_Gizmo));
// const char *func_id = RNA_function_identifier(func); /* UNUSED */
/* testing, for correctness, not operator and not draw function */
const bool is_readonly = !(RNA_function_flag(func) & FUNC_ALLOW_WRITE);
@@ -8316,6 +8430,43 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
Py_RETURN_NONE;
}
+/* Access to 'owner_id' internal global. */
+
+static PyObject *pyrna_bl_owner_id_get(PyObject *UNUSED(self))
+{
+ const char *name = RNA_struct_state_owner_get();
+ if (name) {
+ return PyUnicode_FromString(name);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *pyrna_bl_owner_id_set(PyObject *UNUSED(self), PyObject *value)
+{
+ const char *name;
+ if (value == Py_None) {
+ name = NULL;
+ }
+ else if (PyUnicode_Check(value)) {
+ name = _PyUnicode_AsString(value);
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "owner_set(...): "
+ "expected None or a string, not '%.200s'", Py_TYPE(value)->tp_name);
+ return NULL;
+ }
+ RNA_struct_state_owner_set(name);
+ Py_RETURN_NONE;
+}
+
+PyMethodDef meth_bpy_owner_id_get = {
+ "_bl_owner_id_get", (PyCFunction)pyrna_bl_owner_id_get, METH_NOARGS, NULL,
+};
+PyMethodDef meth_bpy_owner_id_set = {
+ "_bl_owner_id_set", (PyCFunction)pyrna_bl_owner_id_set, METH_O, NULL,
+};
+
/* currently this is fairly limited, we would need to make some way to split up
* pyrna_callback_classmethod_... if we want more than one callback per type */
typedef struct BPyRNA_CallBack {
@@ -8326,6 +8477,9 @@ typedef struct BPyRNA_CallBack {
static struct BPyRNA_CallBack pyrna_cb_methods[] = {
{{"draw_handler_add", (PyCFunction)pyrna_callback_classmethod_add, METH_VARARGS | METH_STATIC, ""}, &RNA_Space},
{{"draw_handler_remove", (PyCFunction)pyrna_callback_classmethod_remove, METH_VARARGS | METH_STATIC, ""}, &RNA_Space},
+
+ {{"draw_cursor_add", (PyCFunction)pyrna_callback_classmethod_add, METH_VARARGS | METH_STATIC, ""}, &RNA_WindowManager},
+ {{"draw_cursor_remove", (PyCFunction)pyrna_callback_classmethod_remove, METH_VARARGS | METH_STATIC, ""}, &RNA_WindowManager},
{{NULL, NULL, 0, NULL}, NULL}
};
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index f666294666e..32a63acde40 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -225,4 +225,8 @@ int pyrna_prop_validity_check(BPy_PropertyRNA *self);
extern PyMethodDef meth_bpy_register_class;
extern PyMethodDef meth_bpy_unregister_class;
+/* bpy.utils._bl_owner_(get/set) */
+extern PyMethodDef meth_bpy_owner_id_set;
+extern PyMethodDef meth_bpy_owner_id_get;
+
#endif
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 73809e96560..3ba604d5271 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -233,6 +233,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
* strips themselves. These are stored separately or else the properties will
* not have any effect.
*/
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(BPy_GetContext());
ReportList reports;
short result = 0;
@@ -254,7 +255,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
NlaStrip *strip = (NlaStrip *)ptr.data;
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
- result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, options);
+ result = insert_keyframe_direct(depsgraph, &reports, ptr, prop, fcu, cfra, keytype, options);
}
else {
BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full);
@@ -268,13 +269,14 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
}
else {
ID *id = self->ptr.id.data;
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(BPy_GetContext());
ReportList reports;
short result;
BKE_reports_init(&reports, RPT_STORE);
- BLI_assert(BKE_id_is_in_gobal_main(id));
- result = insert_keyframe(G_MAIN, &reports, id, NULL, group_name, path_full, index, cfra, keytype, options);
+ BLI_assert(BKE_id_is_in_global_main(id));
+ result = insert_keyframe(G_MAIN, depsgraph, &reports, id, NULL, group_name, path_full, index, cfra, keytype, options);
MEM_freeN((void *)path_full);
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
@@ -384,7 +386,7 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb
BKE_reports_init(&reports, RPT_STORE);
- result = delete_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
+ result = delete_keyframe(G.main, &reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
MEM_freeN((void *)path_full);
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c
index fbdcc03ddd0..3a20ba385c6 100644
--- a/source/blender/python/intern/bpy_rna_callback.c
+++ b/source/blender/python/intern/bpy_rna_callback.c
@@ -33,6 +33,7 @@
#include "RNA_types.h"
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "bpy_rna.h"
#include "bpy_rna_callback.h"
@@ -47,8 +48,12 @@
#include "BKE_context.h"
#include "BKE_screen.h"
+#include "WM_api.h"
+
#include "ED_space_api.h"
+#include "../generic/python_utildefines.h"
+
/* use this to stop other capsules from being mis-used */
#define RNA_CAPSULE_ID "RNA_HANDLE"
#define RNA_CAPSULE_ID_INVALID "RNA_HANDLE_REMOVED"
@@ -82,6 +87,53 @@ static void cb_region_draw(const bContext *C, ARegion *UNUSED(ar), void *customd
bpy_context_clear((bContext *)C, &gilstate);
}
+/* We could make generic utility */
+static PyObject *PyC_Tuple_CopySized(PyObject *src, int len_dst)
+{
+ PyObject *dst = PyTuple_New(len_dst);
+ int len_src = PyTuple_GET_SIZE(src);
+ BLI_assert(len_src <= len_dst);
+ for (int i = 0; i < len_src; i++) {
+ PyObject *item = PyTuple_GET_ITEM(src, i);
+ PyTuple_SET_ITEM(dst, i, item);
+ Py_INCREF(item);
+ }
+ return dst;
+}
+
+static void cb_wm_cursor_draw(bContext *C, int x, int y, void *customdata)
+{
+ PyObject *cb_func, *cb_args, *result;
+ PyGILState_STATE gilstate;
+
+ bpy_context_set((bContext *)C, &gilstate);
+
+ cb_func = PyTuple_GET_ITEM((PyObject *)customdata, 1);
+ cb_args = PyTuple_GET_ITEM((PyObject *)customdata, 2);
+
+ const int cb_args_len = PyTuple_GET_SIZE(cb_args);
+
+ PyObject *cb_args_xy = PyTuple_New(2);
+ PyTuple_SET_ITEMS(cb_args_xy, PyLong_FromLong(x), PyLong_FromLong(y));
+
+ PyObject *cb_args_with_xy = PyC_Tuple_CopySized(cb_args, cb_args_len + 1);
+ PyTuple_SET_ITEM(cb_args_with_xy, cb_args_len, cb_args_xy);
+
+ result = PyObject_CallObject(cb_func, cb_args_with_xy);
+
+ Py_DECREF(cb_args_with_xy);
+
+ if (result) {
+ Py_DECREF(result);
+ }
+ else {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ bpy_context_clear((bContext *)C, &gilstate);
+}
+
#if 0
PyObject *pyrna_callback_add(BPy_StructRNA *self, PyObject *args)
{
@@ -171,9 +223,7 @@ static eSpace_Type rna_Space_refine_reverse(StructRNA *srna)
if (srna == &RNA_SpaceTextEditor) return SPACE_TEXT;
if (srna == &RNA_SpaceDopeSheetEditor) return SPACE_ACTION;
if (srna == &RNA_SpaceNLA) return SPACE_NLA;
- if (srna == &RNA_SpaceTimeline) return SPACE_TIME;
if (srna == &RNA_SpaceNodeEditor) return SPACE_NODE;
- if (srna == &RNA_SpaceLogicEditor) return SPACE_LOGIC;
if (srna == &RNA_SpaceConsole) return SPACE_CONSOLE;
if (srna == &RNA_SpaceUserPreferences) return SPACE_USERPREF;
if (srna == &RNA_SpaceClipEditor) return SPACE_CLIP;
@@ -185,10 +235,6 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
void *handle;
PyObject *cls;
PyObject *cb_func, *cb_args;
- const char *cb_regiontype_str;
- const char *cb_event_str;
- int cb_event;
- int cb_regiontype;
StructRNA *srna;
if (PyTuple_GET_SIZE(args) < 2) {
@@ -207,23 +253,78 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
}
/* class specific callbacks */
- if (RNA_struct_is_a(srna, &RNA_Space)) {
- if (!PyArg_ParseTuple(args, "OOO!ss:Space.draw_handler_add",
- &cls, &cb_func, /* already assigned, no matter */
- &PyTuple_Type, &cb_args, &cb_regiontype_str, &cb_event_str))
+
+ if (srna == &RNA_WindowManager) {
+ const char *error_prefix = "WindowManager.draw_cursor_add";
+ struct {
+ const char *space_type_str;
+ const char *region_type_str;
+
+ int space_type;
+ int region_type;
+ } params = {
+ .space_type_str = NULL,
+ .region_type_str = NULL,
+ .space_type = SPACE_TYPE_ANY,
+ .region_type = RGN_TYPE_ANY,
+ };
+
+ if (!PyArg_ParseTuple(
+ args, "OOO!|ss:WindowManager.draw_cursor_add",
+ &cls, &cb_func, /* already assigned, no matter */
+ &PyTuple_Type, &cb_args, &params.space_type_str, &params.region_type_str))
+ {
+ return NULL;
+ }
+
+ if (params.space_type_str && pyrna_enum_value_from_id(
+ rna_enum_space_type_items, params.space_type_str,
+ &params.space_type, error_prefix) == -1)
+ {
+ return NULL;
+ }
+ else if (params.region_type_str && pyrna_enum_value_from_id(
+ rna_enum_region_type_items, params.region_type_str,
+ &params.region_type, error_prefix) == -1)
+ {
+ return NULL;
+ }
+
+ bContext *C = BPy_GetContext();
+ struct wmWindowManager *wm = CTX_wm_manager(C);
+ handle = WM_paint_cursor_activate(
+ wm,
+ params.space_type, params.region_type,
+ NULL, cb_wm_cursor_draw, (void *)args);
+ }
+ else if (RNA_struct_is_a(srna, &RNA_Space)) {
+ const char *error_prefix = "Space.draw_handler_add";
+ struct {
+ const char *region_type_str;
+ const char *event_str;
+
+ int region_type;
+ int event;
+ } params;
+
+ if (!PyArg_ParseTuple(
+ args, "OOO!ss:Space.draw_handler_add",
+ &cls, &cb_func, /* already assigned, no matter */
+ &PyTuple_Type, &cb_args,
+ &params.region_type_str, &params.event_str))
{
return NULL;
}
if (pyrna_enum_value_from_id(
- region_draw_mode_items, cb_event_str,
- &cb_event, "bpy_struct.callback_add()") == -1)
+ region_draw_mode_items, params.event_str,
+ &params.event, error_prefix) == -1)
{
return NULL;
}
else if (pyrna_enum_value_from_id(
- rna_enum_region_type_items, cb_regiontype_str,
- &cb_regiontype, "bpy_struct.callback_add()") == -1)
+ rna_enum_region_type_items, params.region_type_str,
+ &params.region_type, error_prefix) == -1)
{
return NULL;
}
@@ -235,13 +336,12 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
}
else {
SpaceType *st = BKE_spacetype_from_id(spaceid);
- ARegionType *art = BKE_regiontype_from_id(st, cb_regiontype);
+ ARegionType *art = BKE_regiontype_from_id(st, params.region_type);
if (art == NULL) {
- PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", cb_regiontype_str);
+ PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", params.region_type_str);
return NULL;
}
- handle = ED_region_draw_cb_activate(art, cb_region_draw, (void *)args, cb_event);
- Py_INCREF(args);
+ handle = ED_region_draw_cb_activate(art, cb_region_draw, (void *)args, params.event);
}
}
}
@@ -250,7 +350,14 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
- return PyCapsule_New((void *)handle, RNA_CAPSULE_ID, NULL);
+ PyObject *ret = PyCapsule_New((void *)handle, RNA_CAPSULE_ID, NULL);
+
+ /* Store 'args' in context as well as the handler custom-data,
+ * because the handle may be freed by Blender (new file, new window... etc) */
+ PyCapsule_SetContext(ret, args);
+ Py_INCREF(args);
+
+ return ret;
}
PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *args)
@@ -258,10 +365,8 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
PyObject *cls;
PyObject *py_handle;
void *handle;
- void *customdata;
StructRNA *srna;
- const char *cb_regiontype_str;
- int cb_regiontype;
+ bool capsule_clear = false;
if (PyTuple_GET_SIZE(args) < 2) {
PyErr_SetString(PyExc_ValueError, "callback_remove(handler): expected at least 2 args");
@@ -278,21 +383,39 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
PyErr_SetString(PyExc_ValueError, "callback_remove(handler): NULL handler given, invalid or already removed");
return NULL;
}
+ PyObject *handle_args = PyCapsule_GetContext(py_handle);
- if (RNA_struct_is_a(srna, &RNA_Space)) {
- if (!PyArg_ParseTuple(args, "OO!s:Space.draw_handler_remove",
- &cls, &PyCapsule_Type, &py_handle, /* already assigned, no matter */
- &cb_regiontype_str))
+ if (srna == &RNA_WindowManager) {
+ if (!PyArg_ParseTuple(
+ args, "OO!:WindowManager.draw_cursor_remove",
+ &cls, &PyCapsule_Type, &py_handle))
+ {
+ return NULL;
+ }
+ bContext *C = BPy_GetContext();
+ struct wmWindowManager *wm = CTX_wm_manager(C);
+ WM_paint_cursor_end(wm, handle);
+ capsule_clear = true;
+ }
+ else if (RNA_struct_is_a(srna, &RNA_Space)) {
+ const char *error_prefix = "Space.draw_handler_remove";
+ struct {
+ const char *region_type_str;
+
+ int region_type;
+ } params;
+
+ if (!PyArg_ParseTuple(
+ args, "OO!s:Space.draw_handler_remove",
+ &cls, &PyCapsule_Type, &py_handle, /* already assigned, no matter */
+ &params.region_type_str))
{
return NULL;
}
-
- customdata = ED_region_draw_cb_customdata(handle);
- Py_DECREF((PyObject *)customdata);
if (pyrna_enum_value_from_id(
- rna_enum_region_type_items, cb_regiontype_str,
- &cb_regiontype, "bpy_struct.callback_remove()") == -1)
+ rna_enum_region_type_items, params.region_type_str,
+ &params.region_type, error_prefix) == -1)
{
return NULL;
}
@@ -304,12 +427,13 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
}
else {
SpaceType *st = BKE_spacetype_from_id(spaceid);
- ARegionType *art = BKE_regiontype_from_id(st, cb_regiontype);
+ ARegionType *art = BKE_regiontype_from_id(st, params.region_type);
if (art == NULL) {
- PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", cb_regiontype_str);
+ PyErr_Format(PyExc_TypeError, "region type '%.200s' not in space", params.region_type_str);
return NULL;
}
ED_region_draw_cb_exit(art, handle);
+ capsule_clear = true;
}
}
}
@@ -319,7 +443,10 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
}
/* don't allow reuse */
- PyCapsule_SetName(py_handle, RNA_CAPSULE_ID_INVALID);
+ if (capsule_clear) {
+ Py_DECREF(handle_args);
+ PyCapsule_SetName(py_handle, RNA_CAPSULE_ID_INVALID);
+ }
Py_RETURN_NONE;
}
diff --git a/source/blender/python/intern/bpy_rna_gizmo.c b/source/blender/python/intern/bpy_rna_gizmo.c
new file mode 100644
index 00000000000..8189431dfc9
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_gizmo.c
@@ -0,0 +1,564 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_rna_gizmo.c
+ * \ingroup pythonintern
+ *
+ * .
+ */
+
+#include <Python.h>
+#include <stddef.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_alloca.h"
+
+#include "BKE_main.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "bpy_capi_utils.h"
+#include "bpy_rna_gizmo.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+#include "RNA_enum_types.h"
+
+#include "bpy_rna.h"
+
+
+/* -------------------------------------------------------------------- */
+/** \name Gizmo Target Property Define API
+ * \{ */
+
+enum {
+ BPY_GIZMO_FN_SLOT_GET = 0,
+ BPY_GIZMO_FN_SLOT_SET,
+ BPY_GIZMO_FN_SLOT_RANGE_GET,
+};
+#define BPY_GIZMO_FN_SLOT_LEN (BPY_GIZMO_FN_SLOT_RANGE_GET + 1)
+
+struct BPyGizmoHandlerUserData {
+
+ PyObject *fn_slots[BPY_GIZMO_FN_SLOT_LEN];
+};
+
+static void py_rna_gizmo_handler_get_cb(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data;
+ PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_GET], NULL);
+ if (ret == NULL) {
+ goto fail;
+ }
+
+ if (gz_prop->type->data_type == PROP_FLOAT) {
+ float *value = value_p;
+ if (gz_prop->type->array_length == 1) {
+ if ((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) {
+ goto fail;
+ }
+ }
+ else {
+ if (PyC_AsArray(value, ret, gz_prop->type->array_length, &PyFloat_Type, false,
+ "Gizmo get callback: ") == -1)
+ {
+ goto fail;
+ }
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
+ goto fail;
+ }
+
+ Py_DECREF(ret);
+
+ PyGILState_Release(gilstate);
+ return;
+
+fail:
+ PyErr_Print();
+ PyErr_Clear();
+
+ PyGILState_Release(gilstate);
+}
+
+static void py_rna_gizmo_handler_set_cb(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ const void *value_p)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data;
+
+ PyObject *args = PyTuple_New(1);
+
+ if (gz_prop->type->data_type == PROP_FLOAT) {
+ const float *value = value_p;
+ PyObject *py_value;
+ if (gz_prop->type->array_length == 1) {
+ py_value = PyFloat_FromDouble(*value);
+ }
+ else {
+ py_value = PyC_Tuple_PackArray_F32(value, gz_prop->type->array_length);
+ }
+ if (py_value == NULL) {
+ goto fail;
+ }
+ PyTuple_SET_ITEM(args, 0, py_value);
+ }
+ else {
+ PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
+ goto fail;
+ }
+
+ PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_SET], args);
+ if (ret == NULL) {
+ goto fail;
+ }
+ Py_DECREF(ret);
+
+ PyGILState_Release(gilstate);
+ return;
+
+fail:
+ PyErr_Print();
+ PyErr_Clear();
+
+ Py_DECREF(args);
+
+ PyGILState_Release(gilstate);
+}
+
+static void py_rna_gizmo_handler_range_get_cb(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
+ void *value_p)
+{
+ struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data;
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET], NULL);
+ if (ret == NULL) {
+ goto fail;
+ }
+
+ if (!PyTuple_Check(ret)) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected a tuple, not %.200s",
+ Py_TYPE(ret)->tp_name);
+ goto fail;
+ }
+
+ if (PyTuple_GET_SIZE(ret) != 2) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected a tuple of size 2, not %d",
+ PyTuple_GET_SIZE(ret));
+ goto fail;
+ }
+
+ if (gz_prop->type->data_type == PROP_FLOAT) {
+ float range[2];
+ for (int i = 0; i < 2; i++) {
+ if (((range[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(ret, i))) == -1.0f && PyErr_Occurred()) == 0) {
+ /* pass */
+ }
+ else {
+ goto fail;
+ }
+ }
+ memcpy(value_p, range, sizeof(range));
+ }
+ else {
+ PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
+ goto fail;
+ }
+
+ Py_DECREF(ret);
+ PyGILState_Release(gilstate);
+ return;
+
+fail:
+ Py_XDECREF(ret);
+
+ PyErr_Print();
+ PyErr_Clear();
+
+ PyGILState_Release(gilstate);
+}
+
+static void py_rna_gizmo_handler_free_cb(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop)
+{
+ struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data;
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
+ Py_XDECREF(data->fn_slots[i]);
+ }
+ PyGILState_Release(gilstate);
+
+ MEM_freeN(data);
+
+}
+
+PyDoc_STRVAR(bpy_gizmo_target_set_handler_doc,
+".. method:: target_set_handler(target, get, set, range=None):\n"
+"\n"
+" Assigns callbacks to a gizmos property.\n"
+"\n"
+" :arg get: Function that returns the value for this property (single value or sequence).\n"
+" :type get: callable\n"
+" :arg set: Function that takes a single value argument and applies it.\n"
+" :type set: callable\n"
+" :arg range: Function that returns a (min, max) tuple for gizmos that use a range.\n"
+" :type range: callable\n"
+);
+static PyObject *bpy_gizmo_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct {
+ PyObject *self;
+ char *target;
+ PyObject *py_fn_slots[BPY_GIZMO_FN_SLOT_LEN];
+ } params = {
+ .self = NULL,
+ .target = NULL,
+ .py_fn_slots = {NULL},
+ };
+
+ /* Note: this is a counter-part to functions:
+ * 'Gizmo.target_set_prop & target_set_operator'
+ * (see: rna_wm_gizmo_api.c). conventions should match. */
+ static const char * const _keywords[] = {"self", "target", "get", "set", "range", NULL};
+ static _PyArg_Parser _parser = {"Os|$OOO:target_set_handler", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &params.self,
+ &params.target,
+ &params.py_fn_slots[BPY_GIZMO_FN_SLOT_GET],
+ &params.py_fn_slots[BPY_GIZMO_FN_SLOT_SET],
+ &params.py_fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET]))
+ {
+ goto fail;
+ }
+
+ wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data;
+
+ const wmGizmoPropertyType *gz_prop_type =
+ WM_gizmotype_target_property_find(gz->type, params.target);
+ if (gz_prop_type == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Gizmo target property '%s.%s' not found",
+ gz->type->idname, params.target);
+ goto fail;
+ }
+
+ {
+ const int slots_required = 2;
+ const int slots_start = 2;
+ for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
+ if (params.py_fn_slots[i] == NULL) {
+ if (i < slots_required) {
+ PyErr_Format(PyExc_ValueError, "Argument '%s' not given", _keywords[slots_start + i]);
+ goto fail;
+ }
+ }
+ else if (!PyCallable_Check(params.py_fn_slots[i])) {
+ PyErr_Format(PyExc_ValueError, "Argument '%s' not callable", _keywords[slots_start + i]);
+ goto fail;
+ }
+ }
+ }
+
+ struct BPyGizmoHandlerUserData *data = MEM_callocN(sizeof(*data), __func__);
+
+ for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
+ data->fn_slots[i] = params.py_fn_slots[i];
+ Py_XINCREF(params.py_fn_slots[i]);
+ }
+
+ WM_gizmo_target_property_def_func_ptr(
+ gz, gz_prop_type,
+ &(const struct wmGizmoPropertyFnParams) {
+ .value_get_fn = py_rna_gizmo_handler_get_cb,
+ .value_set_fn = py_rna_gizmo_handler_set_cb,
+ .range_get_fn = py_rna_gizmo_handler_range_get_cb,
+ .free_fn = py_rna_gizmo_handler_free_cb,
+ .user_data = data,
+ });
+
+ PyGILState_Release(gilstate);
+
+ Py_RETURN_NONE;
+
+fail:
+ PyGILState_Release(gilstate);
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Gizmo Target Property Access API
+ * \{ */
+
+PyDoc_STRVAR(bpy_gizmo_target_get_value_doc,
+".. method:: target_get_value(target):\n"
+"\n"
+" Get the value of this target property.\n"
+"\n"
+" :arg target: Target property name.\n"
+" :type target: string\n"
+" :return: The value of the target property.\n"
+" :rtype: Single value or array based on the target type\n"
+);
+static PyObject *bpy_gizmo_target_get_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ struct {
+ PyObject *self;
+ char *target;
+ } params = {
+ .self = NULL,
+ .target = NULL,
+ };
+
+ static const char * const _keywords[] = {"self", "target", NULL};
+ static _PyArg_Parser _parser = {"Os:target_get_value", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &params.self,
+ &params.target))
+ {
+ goto fail;
+ }
+
+ wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data;
+
+ wmGizmoProperty *gz_prop =
+ WM_gizmo_target_property_find(gz, params.target);
+ if (gz_prop == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Gizmo target property '%s.%s' not found",
+ gz->type->idname, params.target);
+ goto fail;
+ }
+
+ const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
+ switch (gz_prop->type->data_type) {
+ case PROP_FLOAT:
+ {
+ if (array_len != 0) {
+ float *value = BLI_array_alloca(value, array_len);
+ WM_gizmo_target_property_float_get_array(gz, gz_prop, value);
+ return PyC_Tuple_PackArray_F32(value, array_len);
+ }
+ else {
+ float value = WM_gizmo_target_property_float_get(gz, gz_prop);
+ return PyFloat_FromDouble(value);
+ }
+ break;
+ }
+ default:
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
+ goto fail;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+PyDoc_STRVAR(bpy_gizmo_target_set_value_doc,
+".. method:: target_set_value(target):\n"
+"\n"
+" Set the value of this target property.\n"
+"\n"
+" :arg target: Target property name.\n"
+" :type target: string\n"
+);
+static PyObject *bpy_gizmo_target_set_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ struct {
+ PyObject *self;
+ char *target;
+ PyObject *value;
+ } params = {
+ .self = NULL,
+ .target = NULL,
+ .value = NULL,
+ };
+
+ static const char * const _keywords[] = {"self", "target", "value", NULL};
+ static _PyArg_Parser _parser = {"OsO:target_set_value", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &params.self,
+ &params.target,
+ &params.value))
+ {
+ goto fail;
+ }
+
+ wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data;
+
+ wmGizmoProperty *gz_prop =
+ WM_gizmo_target_property_find(gz, params.target);
+ if (gz_prop == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Gizmo target property '%s.%s' not found",
+ gz->type->idname, params.target);
+ goto fail;
+ }
+
+ const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
+ switch (gz_prop->type->data_type) {
+ case PROP_FLOAT:
+ {
+ if (array_len != 0) {
+ float *value = BLI_array_alloca(value, array_len);
+ if (PyC_AsArray(value, params.value, gz_prop->type->array_length, &PyFloat_Type, false,
+ "Gizmo target property array") == -1)
+ {
+ goto fail;
+ }
+ WM_gizmo_target_property_float_set_array(BPy_GetContext(), gz, gz_prop, value);
+ }
+ else {
+ float value;
+ if ((value = PyFloat_AsDouble(params.value)) == -1.0f && PyErr_Occurred()) {
+ goto fail;
+ }
+ WM_gizmo_target_property_float_set(BPy_GetContext(), gz, gz_prop, value);
+ }
+ Py_RETURN_NONE;
+ }
+ default:
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
+ goto fail;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+
+PyDoc_STRVAR(bpy_gizmo_target_get_range_doc,
+".. method:: target_get_range(target):\n"
+"\n"
+" Get the range for this target property.\n"
+"\n"
+" :arg target: Target property name.\n"
+" :return: The range of this property (min, max).\n"
+" :rtype: tuple pair.\n"
+);
+static PyObject *bpy_gizmo_target_get_range(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ struct {
+ PyObject *self;
+ char *target;
+ } params = {
+ .self = NULL,
+ .target = NULL,
+ };
+
+ static const char * const _keywords[] = {"self", "target", NULL};
+ static _PyArg_Parser _parser = {"Os:target_get_range", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &params.self,
+ &params.target))
+ {
+ goto fail;
+ }
+
+ wmGizmo *gz = ((BPy_StructRNA *)params.self)->ptr.data;
+
+ wmGizmoProperty *gz_prop =
+ WM_gizmo_target_property_find(gz, params.target);
+ if (gz_prop == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Gizmo target property '%s.%s' not found",
+ gz->type->idname, params.target);
+ goto fail;
+ }
+
+ switch (gz_prop->type->data_type) {
+ case PROP_FLOAT:
+ {
+ float range[2];
+ WM_gizmo_target_property_float_range_get(gz, gz_prop, range);
+ return PyC_Tuple_PackArray_F32(range, 2);
+ }
+ default:
+ {
+ PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
+ goto fail;
+ }
+ }
+
+fail:
+ return NULL;
+}
+
+/** \} */
+
+int BPY_rna_gizmo_module(PyObject *mod_par)
+{
+ static PyMethodDef method_def_array[] = {
+ /* Gizmo Target Property Define API */
+ {"target_set_handler", (PyCFunction)bpy_gizmo_target_set_handler,
+ METH_VARARGS | METH_KEYWORDS, bpy_gizmo_target_set_handler_doc},
+ /* Gizmo Target Property Access API */
+ {"target_get_value", (PyCFunction)bpy_gizmo_target_get_value,
+ METH_VARARGS | METH_KEYWORDS, bpy_gizmo_target_get_value_doc},
+ {"target_set_value", (PyCFunction)bpy_gizmo_target_set_value,
+ METH_VARARGS | METH_KEYWORDS, bpy_gizmo_target_set_value_doc},
+ {"target_get_range", (PyCFunction)bpy_gizmo_target_get_range,
+ METH_VARARGS | METH_KEYWORDS, bpy_gizmo_target_get_range_doc},
+ /* no sentinel needed. */
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(method_def_array); i++) {
+ PyMethodDef *m = &method_def_array[i];
+ PyObject *func = PyCFunction_New(m, NULL);
+ PyObject *func_inst = PyInstanceMethod_New(func);
+ char name_prefix[128];
+ PyOS_snprintf(name_prefix, sizeof(name_prefix), "_rna_gizmo_%s", m->ml_name);
+ /* TODO, return a type that binds nearly to a method. */
+ PyModule_AddObject(mod_par, name_prefix, func_inst);
+ }
+
+ return 0;
+}
diff --git a/source/blender/python/intern/gpu.h b/source/blender/python/intern/bpy_rna_gizmo.h
index 0da44a4eb87..68d8c1e052a 100644
--- a/source/blender/python/intern/gpu.h
+++ b/source/blender/python/intern/bpy_rna_gizmo.h
@@ -15,27 +15,18 @@
* 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) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Benoit Bolsee.
+ * Contributor(s): Bastien Montagne
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/python/intern/gpu.h
+/** \file blender/python/intern/bpy_rna_gizmo.h
* \ingroup pythonintern
- *
- * Initializes the gpu Python module.
*/
-#ifndef __GPU_H__
-#define __GPU_H__
-
-PyObject *GPU_initPython(void);
+#ifndef __BPY_RNA_GIZMO_H__
+#define __BPY_RNA_GIZMO_H__
-PyObject *BPyInit_gpu_offscreen(void);
+int BPY_rna_gizmo_module(PyObject *);
-#endif /* __GPU_H__ */
+#endif /* __BPY_RNA_GIZMO_H__ */
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 4806c2266ba..0aed853c66b 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -35,9 +35,8 @@
#include "BLI_bitmap.h"
#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_main.h"
#include "DNA_ID.h"
/* Those folowing are only to support hack of not listing some internal 'backward' pointers in generated user_map... */
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index cbd8b67d1ce..1d1108e1af0 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -323,7 +323,6 @@ PyObject *BPY_utils_units(void)
submodule = PyModule_Create(&bpyunits_module);
PyDict_SetItemString(PyImport_GetModuleDict(), bpyunits_module.m_name, submodule);
- Py_INCREF(submodule);
/* Finalize our unit systems and types structseq definitions! */
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
deleted file mode 100644
index d902b6838f4..00000000000
--- a/source/blender/python/intern/gpu.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * ***** 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): Benoit Bolsee.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/python/intern/gpu.c
- * \ingroup pythonintern
- *
- * This file defines the 'gpu' module, used to get GLSL shader code and data
- * from blender materials.
- */
-
-#include <Python.h>
-
-#include "DNA_scene_types.h"
-#include "DNA_material_types.h"
-#include "DNA_ID.h"
-#include "DNA_customdata_types.h"
-
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-
-#include "RNA_access.h"
-
-#include "bpy_rna.h"
-
-#include "../generic/py_capi_utils.h"
-
-#include "GPU_material.h"
-
-#include "gpu.h"
-
-#define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, # name, name)
-
-PyDoc_STRVAR(M_gpu_doc,
-"This module provides access to the GLSL shader and Offscreen rendering functionalities."
-);
-static struct PyModuleDef gpumodule = {
- PyModuleDef_HEAD_INIT,
- "gpu", /* name of module */
- M_gpu_doc, /* module documentation */
- -1, /* size of per-interpreter state of the module,
- * or -1 if the module keeps state in global variables. */
- NULL, NULL, NULL, NULL, NULL
-};
-
-static PyObject *PyInit_gpu(void)
-{
- PyObject *m;
-
- m = PyModule_Create(&gpumodule);
- if (m == NULL)
- return NULL;
-
-
- /* Take care to update docs when editing: 'doc/python_api/rst/gpu.rst' */
-
-
- /* -------------------------------------------------------------------- */
- /* GPUDynamicType */
-
- /* device constant groups */
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MISC);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_LAMP);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_OBJECT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_SAMPLER);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MIST);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_WORLD);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_GROUP_MAT);
-
- /* device constants */
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_NONE);
- /* GPU_DYNAMIC_GROUP_OBJECT */
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWMAT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_MAT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWIMAT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_IMAT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_COLOR);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE);
- /* GPU_DYNAMIC_GROUP_LAMP */
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNVEC);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCO);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNIMAT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNPERSMAT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNENERGY);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCOL);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT1);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT2);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSCALE);
- /* GPU_DYNAMIC_GROUP_SAMPLER */
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DSHADOW);
- /* GPU_DYNAMIC_GROUP_MIST */
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_ENABLE);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_START);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_DISTANCE);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_INTENSITY);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_TYPE);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MIST_COLOR);
- /* GPU_DYNAMIC_GROUP_WORLD */
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_HORIZON_COLOR);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_AMBIENT_COLOR);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_ZENITH_COLOR);
- /* GPU_DYNAMIC_GROUP_MAT */
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_DIFFRGB);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_REF);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPECRGB);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPEC);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_HARD);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_EMIT);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA);
- PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_MIR);
-
-
- /* -------------------------------------------------------------------- */
- /* GPUDataType */
-
- PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1I);
- PY_MODULE_ADD_CONSTANT(m, GPU_DATA_1F);
- PY_MODULE_ADD_CONSTANT(m, GPU_DATA_2F);
- PY_MODULE_ADD_CONSTANT(m, GPU_DATA_3F);
- PY_MODULE_ADD_CONSTANT(m, GPU_DATA_4F);
- PY_MODULE_ADD_CONSTANT(m, GPU_DATA_9F);
- PY_MODULE_ADD_CONSTANT(m, GPU_DATA_16F);
- PY_MODULE_ADD_CONSTANT(m, GPU_DATA_4UB);
-
-
- /* -------------------------------------------------------------------- */
- /* CustomDataType
- *
- * Intentionally only include the subset used by the GPU API.
- */
- PY_MODULE_ADD_CONSTANT(m, CD_MTFACE);
- PY_MODULE_ADD_CONSTANT(m, CD_ORCO);
- PY_MODULE_ADD_CONSTANT(m, CD_TANGENT);
- PY_MODULE_ADD_CONSTANT(m, CD_MCOL);
- return m;
-}
-
-#define PY_DICT_ADD_STRING(d, s, f) \
- val = PyUnicode_FromString(s->f); \
- PyDict_SetItemString(d, # f, val); \
- Py_DECREF(val)
-
-#define PY_DICT_ADD_LONG(d, s, f) \
- val = PyLong_FromLong(s->f); \
- PyDict_SetItemString(d, # f, val); \
- Py_DECREF(val)
-
-#define PY_DICT_ADD_ID(d, s, f) \
- RNA_id_pointer_create((struct ID *)s->f, &tptr); \
- val = pyrna_struct_CreatePyObject(&tptr); \
- PyDict_SetItemString(d, # f, val); \
- Py_DECREF(val)
-
-#if 0 /* UNUSED */
-#define PY_OBJ_ADD_ID(d, s, f) \
- val = PyUnicode_FromString(&s->f->id.name[2]); \
- PyObject_SetAttrString(d, # f, val); \
- Py_DECREF(val)
-
-#define PY_OBJ_ADD_LONG(d, s, f) \
- val = PyLong_FromLong(s->f); \
- PyObject_SetAttrString(d, # f, val); \
- Py_DECREF(val)
-
-#define PY_OBJ_ADD_STRING(d, s, f) \
- val = PyUnicode_FromString(s->f); \
- PyObject_SetAttrString(d, # f, val); \
- Py_DECREF(val)
-#endif
-
-PyDoc_STRVAR(GPU_export_shader_doc,
-"export_shader(scene, material)\n"
-"\n"
-" Returns the GLSL shader that produces the visual effect of material in scene.\n"
-"\n"
-" :return: Dictionary defining the shader, uniforms and attributes.\n"
-" :rtype: Dict"
-);
-static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
-{
- PyObject *pyscene;
- PyObject *pymat;
- PyObject *result;
- PyObject *dict;
- PyObject *val;
- PyObject *seq;
-
- int i;
- Scene *scene;
- PointerRNA tptr;
- Material *material;
- GPUShaderExport *shader;
- GPUInputUniform *uniform;
- GPUInputAttribute *attribute;
-
- static const char *_keywords[] = {"scene", "material", NULL};
- static _PyArg_Parser _parser = {"OO:export_shader", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(
- args, kw, &_parser,
- &pyscene, &pymat))
- {
- return NULL;
- }
- scene = (Scene *)PyC_RNA_AsPointer(pyscene, "Scene");
- if (scene == NULL) {
- return NULL;
- }
-
- material = (Material *)PyC_RNA_AsPointer(pymat, "Material");
- if (material == NULL) {
- return NULL;
- }
-
- /* we can call our internal function at last: */
- shader = GPU_shader_export(scene, material);
- if (!shader) {
- PyErr_SetString(PyExc_RuntimeError, "cannot export shader");
- return NULL;
- }
- /* build a dictionary */
- result = PyDict_New();
- if (shader->fragment) {
- PY_DICT_ADD_STRING(result, shader, fragment);
- }
- if (shader->vertex) {
- PY_DICT_ADD_STRING(result, shader, vertex);
- }
- seq = PyList_New(BLI_listbase_count(&shader->uniforms));
- for (i = 0, uniform = shader->uniforms.first; uniform; uniform = uniform->next, i++) {
- dict = PyDict_New();
- PY_DICT_ADD_STRING(dict, uniform, varname);
- PY_DICT_ADD_LONG(dict, uniform, datatype);
- PY_DICT_ADD_LONG(dict, uniform, type);
- if (uniform->lamp) {
- PY_DICT_ADD_ID(dict, uniform, lamp);
- }
- if (uniform->material) {
- PY_DICT_ADD_ID(dict, uniform, material);
- }
- if (uniform->image) {
- PY_DICT_ADD_ID(dict, uniform, image);
- }
- if (uniform->type == GPU_DYNAMIC_SAMPLER_2DBUFFER ||
- uniform->type == GPU_DYNAMIC_SAMPLER_2DIMAGE ||
- uniform->type == GPU_DYNAMIC_SAMPLER_2DSHADOW)
- {
- PY_DICT_ADD_LONG(dict, uniform, texnumber);
- }
- if (uniform->texpixels) {
- val = PyByteArray_FromStringAndSize((const char *)uniform->texpixels, uniform->texsize * 4);
- PyDict_SetItemString(dict, "texpixels", val);
- Py_DECREF(val);
- PY_DICT_ADD_LONG(dict, uniform, texsize);
- }
- PyList_SET_ITEM(seq, i, dict);
- }
- PyDict_SetItemString(result, "uniforms", seq);
- Py_DECREF(seq);
-
- seq = PyList_New(BLI_listbase_count(&shader->attributes));
- for (i = 0, attribute = shader->attributes.first; attribute; attribute = attribute->next, i++) {
- dict = PyDict_New();
- PY_DICT_ADD_STRING(dict, attribute, varname);
- PY_DICT_ADD_LONG(dict, attribute, datatype);
- PY_DICT_ADD_LONG(dict, attribute, type);
- PY_DICT_ADD_LONG(dict, attribute, number);
- if (attribute->name) {
- if (attribute->name[0] != 0) {
- PY_DICT_ADD_STRING(dict, attribute, name);
- }
- else {
- val = PyLong_FromLong(0);
- PyDict_SetItemString(dict, "name", val);
- Py_DECREF(val);
- }
- }
- PyList_SET_ITEM(seq, i, dict);
- }
- PyDict_SetItemString(result, "attributes", seq);
- Py_DECREF(seq);
-
- GPU_free_shader_export(shader);
-
- return result;
-}
-
-static PyMethodDef meth_export_shader[] = {
- {"export_shader", (PyCFunction)GPU_export_shader, METH_VARARGS | METH_KEYWORDS, GPU_export_shader_doc}
-};
-
-/* -------------------------------------------------------------------- */
-/* Initialize Module */
-
-PyObject *GPU_initPython(void)
-{
- PyObject *module;
- PyObject *submodule;
- PyObject *sys_modules = PyImport_GetModuleDict();
-
- module = PyInit_gpu();
-
- PyModule_AddObject(module, "export_shader", (PyObject *)PyCFunction_New(meth_export_shader, NULL));
-
- /* gpu.offscreen */
- PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen()));
- PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
-
- PyDict_SetItem(sys_modules, PyModule_GetNameObject(module), module);
- return module;
-}
diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c
deleted file mode 100644
index 3b9b3c70ead..00000000000
--- a/source/blender/python/intern/gpu_offscreen.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * ***** 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.
- *
- * Copyright 2015, Blender Foundation.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/python/intern/gpu_offscreen.c
- * \ingroup pythonintern
- *
- * This file defines the offscreen functionalities of the 'gpu' module
- * used for off-screen OpenGL rendering.
- */
-
-#include <Python.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-
-#include "WM_types.h"
-
-#include "BKE_global.h"
-#include "BKE_library.h"
-
-#include "ED_screen.h"
-
-#include "GPU_compositing.h"
-#include "GPU_framebuffer.h"
-
-#include "../mathutils/mathutils.h"
-
-#include "../generic/py_capi_utils.h"
-
-#include "gpu.h"
-
-#include "ED_view3d.h"
-
-/* -------------------------------------------------------------------- */
-/* GPU Offscreen PyObject */
-
-typedef struct {
- PyObject_HEAD
- GPUOffScreen *ofs;
-} BPy_GPUOffScreen;
-
-static int bpy_gpu_offscreen_valid_check(BPy_GPUOffScreen *py_gpu_ofs)
-{
- if (UNLIKELY(py_gpu_ofs->ofs == NULL)) {
- PyErr_SetString(PyExc_ReferenceError, "GPU offscreen was freed, no further access is valid");
- return -1;
- }
- return 0;
-}
-
-#define BPY_GPU_OFFSCREEN_CHECK_OBJ(pygpu) { \
- if (UNLIKELY(bpy_gpu_offscreen_valid_check(pygpu) == -1)) { \
- return NULL; \
- } \
-} ((void)0)
-
-PyDoc_STRVAR(pygpu_offscreen_width_doc, "Texture width.\n\n:type: int");
-static PyObject *pygpu_offscreen_width_get(BPy_GPUOffScreen *self, void *UNUSED(type))
-{
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
- return PyLong_FromLong(GPU_offscreen_width(self->ofs));
-}
-
-PyDoc_STRVAR(pygpu_offscreen_height_doc, "Texture height.\n\n:type: int");
-static PyObject *pygpu_offscreen_height_get(BPy_GPUOffScreen *self, void *UNUSED(type))
-{
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
- return PyLong_FromLong(GPU_offscreen_height(self->ofs));
-}
-
-PyDoc_STRVAR(pygpu_offscreen_color_texture_doc, "Color texture.\n\n:type: int");
-static PyObject *pygpu_offscreen_color_texture_get(BPy_GPUOffScreen *self, void *UNUSED(type))
-{
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
- return PyLong_FromLong(GPU_offscreen_color_texture(self->ofs));
-}
-
-PyDoc_STRVAR(pygpu_offscreen_bind_doc,
-"bind(save=True)\n"
-"\n"
-" Bind the offscreen object.\n"
-"\n"
-" :param save: save OpenGL current states.\n"
-" :type save: bool\n"
-);
-static PyObject *pygpu_offscreen_bind(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"save", NULL};
- bool save = true;
-
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "|O&:bind", (char **)(kwlist),
- PyC_ParseBool, &save))
- {
- return NULL;
- }
-
- GPU_offscreen_bind(self->ofs, save);
- Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(pygpu_offscreen_unbind_doc,
-"unbind(restore=True)\n"
-"\n"
-" Unbind the offscreen object.\n"
-"\n"
-" :param restore: restore OpenGL previous states.\n"
-" :type restore: bool\n"
-);
-static PyObject *pygpu_offscreen_unbind(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"restore", NULL};
- bool restore = true;
-
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "|O&:unbind", (char **)(kwlist),
- PyC_ParseBool, &restore))
- {
- return NULL;
- }
-
- GPU_offscreen_unbind(self->ofs, restore);
- Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc,
-"draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n"
-"\n"
-" Draw the 3d viewport in the offscreen object.\n"
-"\n"
-" :param scene: Scene to draw.\n"
-" :type scene: :class:`bpy.types.Scene`\n"
-" :param view3d: 3D View to get the drawing settings from.\n"
-" :type view3d: :class:`bpy.types.SpaceView3D`\n"
-" :param region: Region of the 3D View.\n"
-" :type region: :class:`bpy.types.Region`\n"
-" :param modelview_matrix: ModelView Matrix.\n"
-" :type modelview_matrix: :class:`mathutils.Matrix`\n"
-" :param projection_matrix: Projection Matrix.\n"
-" :type projection_matrix: :class:`mathutils.Matrix`\n"
-);
-static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"scene", "view3d", "region", "projection_matrix", "modelview_matrix", NULL};
-
- MatrixObject *py_mat_modelview, *py_mat_projection;
- PyObject *py_scene, *py_region, *py_view3d;
-
- struct Main *bmain = G_MAIN; /* XXX UGLY! */
- Scene *scene;
- View3D *v3d;
- ARegion *ar;
- GPUFX *fx;
- GPUFXSettings fx_settings;
- struct RV3DMatrixStore *rv3d_mats;
-
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "OOOO&O&:draw_view3d", (char **)(kwlist),
- &py_scene, &py_view3d, &py_region,
- Matrix_Parse4x4, &py_mat_projection,
- Matrix_Parse4x4, &py_mat_modelview) ||
- (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) ||
- !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) ||
- !(ar = PyC_RNA_AsPointer(py_region, "Region"))))
- {
- return NULL;
- }
-
- BLI_assert(BKE_id_is_in_gobal_main(&scene->id));
-
- fx = GPU_fx_compositor_create();
-
- fx_settings = v3d->fx_settings; /* full copy */
-
- ED_view3d_draw_offscreen_init(bmain, scene, v3d);
-
- rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata);
-
- GPU_offscreen_bind(self->ofs, true); /* bind */
-
- ED_view3d_draw_offscreen(
- bmain, scene, v3d, ar, GPU_offscreen_width(self->ofs), GPU_offscreen_height(self->ofs),
- (float(*)[4])py_mat_modelview->matrix, (float(*)[4])py_mat_projection->matrix,
- false, true, true, "",
- fx, &fx_settings,
- self->ofs);
-
- GPU_fx_compositor_destroy(fx);
- GPU_offscreen_unbind(self->ofs, true); /* unbind */
-
- ED_view3d_mats_rv3d_restore(ar->regiondata, rv3d_mats);
- MEM_freeN(rv3d_mats);
-
- Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(pygpu_offscreen_free_doc,
-"free()\n"
-"\n"
-" Free the offscreen object\n"
-" The framebuffer, texture and render objects will no longer be accessible.\n"
-);
-static PyObject *pygpu_offscreen_free(BPy_GPUOffScreen *self)
-{
- BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
-
- GPU_offscreen_free(self->ofs);
- self->ofs = NULL;
- Py_RETURN_NONE;
-}
-
-static void BPy_GPUOffScreen__tp_dealloc(BPy_GPUOffScreen *self)
-{
- if (self->ofs)
- GPU_offscreen_free(self->ofs);
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-static PyGetSetDef bpy_gpu_offscreen_getseters[] = {
- {(char *)"color_texture", (getter)pygpu_offscreen_color_texture_get, (setter)NULL, pygpu_offscreen_color_texture_doc, NULL},
- {(char *)"width", (getter)pygpu_offscreen_width_get, (setter)NULL, pygpu_offscreen_width_doc, NULL},
- {(char *)"height", (getter)pygpu_offscreen_height_get, (setter)NULL, pygpu_offscreen_height_doc, NULL},
- {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
-};
-
-static struct PyMethodDef bpy_gpu_offscreen_methods[] = {
- {"bind", (PyCFunction)pygpu_offscreen_bind, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_bind_doc},
- {"unbind", (PyCFunction)pygpu_offscreen_unbind, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_unbind_doc},
- {"draw_view3d", (PyCFunction)pygpu_offscreen_draw_view3d, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_draw_view3d_doc},
- {"free", (PyCFunction)pygpu_offscreen_free, METH_NOARGS, pygpu_offscreen_free_doc},
- {NULL, NULL, 0, NULL}
-};
-
-PyDoc_STRVAR(py_gpu_offscreen_doc,
-".. class:: GPUOffscreen"
-"\n"
-" This object gives access to off screen buffers.\n"
-);
-static PyTypeObject BPy_GPUOffScreen_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "GPUOffScreen", /* tp_name */
- sizeof(BPy_GPUOffScreen), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)BPy_GPUOffScreen__tp_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
- NULL, /* tp_getattr */
- NULL, /* tp_setattr */
- NULL, /* tp_compare */
- NULL, /* tp_repr */
- NULL, /* tp_as_number */
- NULL, /* tp_as_sequence */
- NULL, /* tp_as_mapping */
- NULL, /* tp_hash */
- NULL, /* tp_call */
- NULL, /* tp_str */
- NULL, /* tp_getattro */
- NULL, /* tp_setattro */
- NULL, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- py_gpu_offscreen_doc, /* Documentation string */
- NULL, /* tp_traverse */
- NULL, /* tp_clear */
- NULL, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- NULL, /* tp_iter */
- NULL, /* tp_iternext */
- bpy_gpu_offscreen_methods, /* tp_methods */
- NULL, /* tp_members */
- bpy_gpu_offscreen_getseters, /* tp_getset */
- NULL, /* tp_base */
- NULL, /* tp_dict */
- NULL, /* tp_descr_get */
- NULL, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- NULL, /* tp_alloc */
- NULL, /* tp_new */
- (freefunc)0, /* tp_free */
- NULL, /* tp_is_gc */
- NULL, /* tp_bases */
- NULL, /* tp_mro */
- NULL, /* tp_cache */
- NULL, /* tp_subclasses */
- NULL, /* tp_weaklist */
- (destructor) NULL /* tp_del */
-};
-
-/* -------------------------------------------------------------------- */
-/* GPU offscreen methods */
-
-static PyObject *BPy_GPU_OffScreen_CreatePyObject(GPUOffScreen *ofs)
-{
- BPy_GPUOffScreen *self;
- self = PyObject_New(BPy_GPUOffScreen, &BPy_GPUOffScreen_Type);
- self->ofs = ofs;
- return (PyObject *)self;
-}
-
-PyDoc_STRVAR(pygpu_offscreen_new_doc,
-"new(width, height, samples=0)\n"
-"\n"
-" Return a GPUOffScreen.\n"
-"\n"
-" :param width: Horizontal dimension of the buffer.\n"
-" :type width: int`\n"
-" :param height: Vertical dimension of the buffer.\n"
-" :type height: int`\n"
-" :param samples: OpenGL samples to use for MSAA or zero to disable.\n"
-" :type samples: int\n"
-" :return: Newly created off-screen buffer.\n"
-" :rtype: :class:`gpu.GPUOffscreen`\n"
-);
-static PyObject *pygpu_offscreen_new(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"width", "height", "samples", NULL};
-
- GPUOffScreen *ofs;
- int width, height, samples = 0;
- char err_out[256];
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "ii|i:new", (char **)(kwlist),
- &width, &height, &samples))
- {
- return NULL;
- }
-
- ofs = GPU_offscreen_create(width, height, samples, err_out);
-
- if (ofs == NULL) {
- PyErr_Format(PyExc_RuntimeError,
- "gpu.offscreen.new(...) failed with '%s'",
- err_out[0] ? err_out : "unknown error");
- return NULL;
- }
-
- return BPy_GPU_OffScreen_CreatePyObject(ofs);
-}
-
-static struct PyMethodDef BPy_GPU_offscreen_methods[] = {
- {"new", (PyCFunction)pygpu_offscreen_new, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_new_doc},
- {NULL, NULL, 0, NULL}
-};
-
-PyDoc_STRVAR(BPy_GPU_offscreen_doc,
-"This module provides access to offscreen rendering functions."
-);
-static PyModuleDef BPy_GPU_offscreen_module_def = {
- PyModuleDef_HEAD_INIT,
- "gpu.offscreen", /* m_name */
- BPy_GPU_offscreen_doc, /* m_doc */
- 0, /* m_size */
- BPy_GPU_offscreen_methods, /* m_methods */
- NULL, /* m_reload */
- NULL, /* m_traverse */
- NULL, /* m_clear */
- NULL, /* m_free */
-};
-
-PyObject *BPyInit_gpu_offscreen(void)
-{
- PyObject *submodule;
-
- /* Register the 'GPUOffscreen' class */
- if (PyType_Ready(&BPy_GPUOffScreen_Type)) {
- return NULL;
- }
-
- submodule = PyModule_Create(&BPy_GPU_offscreen_module_def);
-
-#define MODULE_TYPE_ADD(s, t) \
- PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t)
-
- MODULE_TYPE_ADD(submodule, BPy_GPUOffScreen_Type);
-
-#undef MODULE_TYPE_ADD
-
- return submodule;
-}
-
-#undef BPY_GPU_OFFSCREEN_CHECK_OBJ
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 566bac9cb09..07905d2be89 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -645,30 +645,25 @@ PyMODINIT_FUNC PyInit_mathutils(void)
* 'from mathutils.geometry import PolyFill'
* ...fails without this. */
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate()));
/* XXX, python doesnt do imports with this usefully yet
* 'from mathutils.geometry import PolyFill'
* ...fails without this. */
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
#ifndef MATH_STANDALONE
/* Noise submodule */
PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
/* BVHTree submodule */
PyModule_AddObject(mod, "bvhtree", (submodule = PyInit_mathutils_bvhtree()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
/* KDTree submodule */
PyModule_AddObject(mod, "kdtree", (submodule = PyInit_mathutils_kdtree()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
- Py_INCREF(submodule);
#endif
mathutils_matrix_row_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_row_cb);
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index 286dd9f0750..ab78009ff89 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -62,7 +62,7 @@ enum {
float *_data; /* array of data (alias), wrapped status depends on wrapped status */ \
PyObject *cb_user; /* if this vector references another object, otherwise NULL, \
* *Note* this owns its reference */ \
- unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ \
+ unsigned char cb_type; /* which user funcs do we adhere to, RNA, etc */ \
unsigned char cb_subtype; /* subtype: location, rotation... \
* to avoid defining many new functions for every attribute of the same type */ \
unsigned char flag /* wrapped data type? */ \
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 951c094ec40..de8deca35a1 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -2321,7 +2321,7 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
return Matrix_CreatePyObject(mat, mat1->num_col, mat1->num_row, Py_TYPE(mat1));
}
/*------------------------obj * obj------------------------------
- * multiplication */
+ * element-wise multiplication */
static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
{
float tmat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
@@ -2332,7 +2332,6 @@ static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar)
static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
{
float scalar;
- int vec_size;
MatrixObject *mat1 = NULL, *mat2 = NULL;
@@ -2348,9 +2347,118 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
}
if (mat1 && mat2) {
+#ifdef USE_MATHUTILS_ELEM_MUL
/* MATRIX * MATRIX */
float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+ if ((mat1->num_row != mat2->num_row) || (mat1->num_col != mat2->num_col)) {
+ PyErr_SetString(PyExc_ValueError,
+ "matrix1 * matrix2: matrix1 number of rows/columns "
+ "and the matrix2 number of rows/columns must be the same");
+ return NULL;
+ }
+
+ mul_vn_vnvn(mat, mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
+
+ return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1));
+#endif
+ }
+ else if (mat2) {
+ /*FLOAT/INT * MATRIX */
+ if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
+ return matrix_mul_float(mat2, scalar);
+ }
+ }
+ else if (mat1) {
+ /* MATRIX * FLOAT/INT */
+ if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
+ return matrix_mul_float(mat1, scalar);
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "Element-wise multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
+ return NULL;
+}
+/*------------------------obj *= obj------------------------------
+ * Inplace element-wise multiplication */
+static PyObject *Matrix_imul(PyObject *m1, PyObject *m2)
+{
+ float scalar;
+
+ MatrixObject *mat1 = NULL, *mat2 = NULL;
+
+ if (MatrixObject_Check(m1)) {
+ mat1 = (MatrixObject *)m1;
+ if (BaseMath_ReadCallback(mat1) == -1)
+ return NULL;
+ }
+ if (MatrixObject_Check(m2)) {
+ mat2 = (MatrixObject *)m2;
+ if (BaseMath_ReadCallback(mat2) == -1)
+ return NULL;
+ }
+
+ if (mat1 && mat2) {
+#ifdef USE_MATHUTILS_ELEM_MUL
+ /* MATRIX *= MATRIX */
+ if ((mat1->num_row != mat2->num_row) || (mat1->num_col != mat2->num_col)) {
+ PyErr_SetString(PyExc_ValueError,
+ "matrix1 *= matrix2: matrix1 number of rows/columns "
+ "and the matrix2 number of rows/columns must be the same");
+ return NULL;
+ }
+
+ mul_vn_vn(mat1->matrix, mat2->matrix, mat1->num_col * mat1->num_row);
+#else
+ PyErr_Format(PyExc_TypeError,
+ "Inplace element-wise multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
+ return NULL;
+#endif
+ }
+ else if (mat1 && (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0)) {
+ /* MATRIX *= FLOAT/INT */
+ mul_vn_fl(mat1->matrix, mat1->num_row * mat1->num_col, scalar);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "Inplace element-wise multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
+ return NULL;
+ }
+
+ (void)BaseMath_WriteCallback(mat1);
+ Py_INCREF(m1);
+ return m1;
+}
+/*------------------------obj @ obj------------------------------
+ * matrix multiplication */
+static PyObject *Matrix_matmul(PyObject *m1, PyObject *m2)
+{
+ int vec_size;
+
+ MatrixObject *mat1 = NULL, *mat2 = NULL;
+
+ if (MatrixObject_Check(m1)) {
+ mat1 = (MatrixObject *)m1;
+ if (BaseMath_ReadCallback(mat1) == -1)
+ return NULL;
+ }
+ if (MatrixObject_Check(m2)) {
+ mat2 = (MatrixObject *)m2;
+ if (BaseMath_ReadCallback(mat2) == -1)
+ return NULL;
+ }
+
+ if (mat1 && mat2) {
+ /* MATRIX @ MATRIX */
+ float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+
int col, row, item;
if (mat1->num_col != mat2->num_row) {
@@ -2372,14 +2480,8 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
return Matrix_CreatePyObject(mat, mat2->num_col, mat1->num_row, Py_TYPE(mat1));
}
- else if (mat2) {
- /*FLOAT/INT * MATRIX */
- if (((scalar = PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred()) == 0) {
- return matrix_mul_float(mat2, scalar);
- }
- }
else if (mat1) {
- /* MATRIX * VECTOR */
+ /* MATRIX @ VECTOR */
if (VectorObject_Check(m2)) {
VectorObject *vec2 = (VectorObject *)m2;
float tvec[MATRIX_MAX_DIM];
@@ -2398,13 +2500,6 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(m2));
}
- /*FLOAT/INT * MATRIX */
- else if (((scalar = PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred()) == 0) {
- return matrix_mul_float(mat1, scalar);
- }
- }
- else {
- BLI_assert(!"internal error");
}
PyErr_Format(PyExc_TypeError,
@@ -2413,6 +2508,62 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2)
Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
return NULL;
}
+/*------------------------obj @= obj------------------------------
+ * inplace matrix multiplication */
+static PyObject *Matrix_imatmul(PyObject *m1, PyObject *m2)
+{
+ MatrixObject *mat1 = NULL, *mat2 = NULL;
+
+ if (MatrixObject_Check(m1)) {
+ mat1 = (MatrixObject *)m1;
+ if (BaseMath_ReadCallback(mat1) == -1)
+ return NULL;
+ }
+ if (MatrixObject_Check(m2)) {
+ mat2 = (MatrixObject *)m2;
+ if (BaseMath_ReadCallback(mat2) == -1)
+ return NULL;
+ }
+
+ if (mat1 && mat2) {
+ /* MATRIX @= MATRIX */
+ float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+ int col, row, item;
+
+ if (mat1->num_col != mat2->num_row) {
+ PyErr_SetString(PyExc_ValueError,
+ "matrix1 * matrix2: matrix1 number of columns "
+ "and the matrix2 number of rows must be the same");
+ return NULL;
+ }
+
+ for (col = 0; col < mat2->num_col; col++) {
+ for (row = 0; row < mat1->num_row; row++) {
+ double dot = 0.0f;
+ for (item = 0; item < mat1->num_col; item++) {
+ dot += (double)(MATRIX_ITEM(mat1, row, item) * MATRIX_ITEM(mat2, item, col));
+ }
+ /* store in new matrix as overwriting original at this point will cause
+ * subsequent iterations to use incorrect values */
+ mat[(col * mat1->num_row) + row] = (float)dot;
+ }
+ }
+
+ /* copy matrix back */
+ memcpy(mat1->matrix, mat, mat1->num_row * mat1->num_col);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "Inplace matrix multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name);
+ return NULL;
+ }
+
+ (void)BaseMath_WriteCallback(mat1);
+ Py_INCREF(m1);
+ return m1;
+}
/*-----------------PROTOCOL DECLARATIONS--------------------------*/
static PySequenceMethods Matrix_SeqMethods = {
@@ -2527,7 +2678,7 @@ static PyNumberMethods Matrix_NumMethods = {
NULL, /*nb_float*/
NULL, /* nb_inplace_add */
NULL, /* nb_inplace_subtract */
- NULL, /* nb_inplace_multiply */
+ (binaryfunc) Matrix_imul, /* nb_inplace_multiply */
NULL, /* nb_inplace_remainder */
NULL, /* nb_inplace_power */
NULL, /* nb_inplace_lshift */
@@ -2540,6 +2691,8 @@ static PyNumberMethods Matrix_NumMethods = {
NULL, /* nb_inplace_floor_divide */
NULL, /* nb_inplace_true_divide */
NULL, /* nb_index */
+ (binaryfunc) Matrix_matmul, /* nb_matrix_multiply */
+ (binaryfunc) Matrix_imatmul, /* nb_inplace_matrix_multiply */
};
PyDoc_STRVAR(Matrix_translation_doc,
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 645fa96c22e..a2b4480584a 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -834,7 +834,7 @@ static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
* multiplication */
static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
{
- float quat[QUAT_SIZE], scalar;
+ float scalar;
QuaternionObject *quat1 = NULL, *quat2 = NULL;
if (QuaternionObject_Check(q1)) {
@@ -848,9 +848,12 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
return NULL;
}
- if (quat1 && quat2) { /* QUAT * QUAT (cross product) */
- mul_qt_qtqt(quat, quat1->quat, quat2->quat);
+ if (quat1 && quat2) { /* QUAT * QUAT (element-wise product) */
+#ifdef USE_MATHUTILS_ELEM_MUL
+ float quat[QUAT_SIZE];
+ mul_vn_vnvn(quat, quat1->quat, quat2->quat, QUAT_SIZE);
return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
+#endif
}
/* the only case this can happen (for a supported type is "FLOAT * QUAT") */
else if (quat2) { /* FLOAT * QUAT */
@@ -858,8 +861,87 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
return quat_mul_float(quat2, scalar);
}
}
+ else if (quat1) { /* QUAT * FLOAT */
+ if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
+ return quat_mul_float(quat1, scalar);
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "Element-wise multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
+ return NULL;
+}
+/*------------------------obj *= obj------------------------------
+ * inplace multiplication */
+static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
+{
+ float scalar;
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+
+ if (QuaternionObject_Check(q1)) {
+ quat1 = (QuaternionObject *)q1;
+ if (BaseMath_ReadCallback(quat1) == -1)
+ return NULL;
+ }
+ if (QuaternionObject_Check(q2)) {
+ quat2 = (QuaternionObject *)q2;
+ if (BaseMath_ReadCallback(quat2) == -1)
+ return NULL;
+ }
+
+ if (quat1 && quat2) { /* QUAT *= QUAT (inplace element-wise product) */
+#ifdef USE_MATHUTILS_ELEM_MUL
+ mul_vn_vn(quat1->quat, quat2->quat, QUAT_SIZE);
+#else
+ PyErr_Format(PyExc_TypeError,
+ "Inplace element-wise multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
+ return NULL;
+#endif
+ }
+ else if (quat1 && (((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
+ /* QUAT *= FLOAT */
+ mul_qt_fl(quat1->quat, scalar);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "Element-wise multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
+ return NULL;
+ }
+
+ (void)BaseMath_WriteCallback(quat1);
+ Py_INCREF(q1);
+ return q1;
+}
+/*------------------------obj @ obj------------------------------
+ * quaternion multiplication */
+static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
+{
+ float quat[QUAT_SIZE];
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+
+ if (QuaternionObject_Check(q1)) {
+ quat1 = (QuaternionObject *)q1;
+ if (BaseMath_ReadCallback(quat1) == -1)
+ return NULL;
+ }
+ if (QuaternionObject_Check(q2)) {
+ quat2 = (QuaternionObject *)q2;
+ if (BaseMath_ReadCallback(quat2) == -1)
+ return NULL;
+ }
+
+ if (quat1 && quat2) { /* QUAT @ QUAT (cross product) */
+ mul_qt_qtqt(quat, quat1->quat, quat2->quat);
+ return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
+ }
else if (quat1) {
- /* QUAT * VEC */
+ /* QUAT @ VEC */
if (VectorObject_Check(q2)) {
VectorObject *vec2 = (VectorObject *)q2;
float tvec[3];
@@ -880,13 +962,6 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec2));
}
- /* QUAT * FLOAT */
- else if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
- return quat_mul_float(quat1, scalar);
- }
- }
- else {
- BLI_assert(!"internal error");
}
PyErr_Format(PyExc_TypeError,
@@ -895,6 +970,40 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
return NULL;
}
+/*------------------------obj @= obj------------------------------
+ * inplace quaternion multiplication */
+static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
+{
+ float quat[QUAT_SIZE];
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+
+ if (QuaternionObject_Check(q1)) {
+ quat1 = (QuaternionObject *)q1;
+ if (BaseMath_ReadCallback(quat1) == -1)
+ return NULL;
+ }
+ if (QuaternionObject_Check(q2)) {
+ quat2 = (QuaternionObject *)q2;
+ if (BaseMath_ReadCallback(quat2) == -1)
+ return NULL;
+ }
+
+ if (quat1 && quat2) { /* QUAT @ QUAT (cross product) */
+ mul_qt_qtqt(quat, quat1->quat, quat2->quat);
+ copy_qt_qt(quat1->quat, quat);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "Inplace quaternion multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
+ return NULL;
+ }
+
+ (void)BaseMath_WriteCallback(quat1);
+ Py_INCREF(q1);
+ return q1;
+}
/* -obj
* returns the negative of this object*/
@@ -952,7 +1061,7 @@ static PyNumberMethods Quaternion_NumMethods = {
NULL, /*nb_float*/
NULL, /* nb_inplace_add */
NULL, /* nb_inplace_subtract */
- NULL, /* nb_inplace_multiply */
+ (binaryfunc) Quaternion_imul, /* nb_inplace_multiply */
NULL, /* nb_inplace_remainder */
NULL, /* nb_inplace_power */
NULL, /* nb_inplace_lshift */
@@ -965,6 +1074,8 @@ static PyNumberMethods Quaternion_NumMethods = {
NULL, /* nb_inplace_floor_divide */
NULL, /* nb_inplace_true_divide */
NULL, /* nb_index */
+ (binaryfunc) Quaternion_matmul, /* nb_matrix_multiply */
+ (binaryfunc) Quaternion_imatmul, /* nb_inplace_matrix_multiply */
};
PyDoc_STRVAR(Quaternion_axis_doc,
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index e7776f836aa..16a242fc718 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -1706,12 +1706,25 @@ static PyObject *vector_mul_float(VectorObject *vec, const float scalar)
mul_vn_vn_fl(tvec, vec->vec, vec->size, scalar);
return Vector_CreatePyObject_alloc(tvec, vec->size, Py_TYPE(vec));
}
+#ifdef USE_MATHUTILS_ELEM_MUL
+static PyObject *vector_mul_vec(VectorObject *vec1, VectorObject *vec2)
+{
+ float *tvec = PyMem_Malloc(vec1->size * sizeof(float));
+ if (tvec == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "vec * vec: "
+ "problem allocating pointer space");
+ return NULL;
+ }
+ mul_vn_vnvn(tvec, vec1->vec, vec2->vec, vec1->size);
+ return Vector_CreatePyObject_alloc(tvec, vec1->size, Py_TYPE(vec1));
+}
+#endif
static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
float scalar;
- int vec_size;
if (VectorObject_Check(v1)) {
vec1 = (VectorObject *)v1;
@@ -1729,6 +1742,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
/* make sure v1 is always the vector */
if (vec1 && vec2) {
+#ifdef USE_MATHUTILS_ELEM_MUL
if (vec1->size != vec2->size) {
PyErr_SetString(PyExc_ValueError,
"Vector multiplication: "
@@ -1736,30 +1750,12 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
return NULL;
}
- /*dot product*/
- return PyFloat_FromDouble(dot_vn_vn(vec1->vec, vec2->vec, vec1->size));
+ /* element-wise product */
+ return vector_mul_vec(vec1, vec2);
+#endif
}
else if (vec1) {
- if (MatrixObject_Check(v2)) {
- /* VEC * MATRIX */
- float tvec[MAX_DIMENSIONS];
-
- if (BaseMath_ReadCallback((MatrixObject *)v2) == -1)
- return NULL;
- if (row_vector_multiplication(tvec, vec1, (MatrixObject *)v2) == -1) {
- return NULL;
- }
-
- if (((MatrixObject *)v2)->num_row == 4 && vec1->size == 3) {
- vec_size = 3;
- }
- else {
- vec_size = ((MatrixObject *)v2)->num_col;
- }
-
- return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(vec1));
- }
- else if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC * FLOAT */
+ if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC * FLOAT */
return vector_mul_float(vec1, scalar);
}
}
@@ -1768,12 +1764,9 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
return vector_mul_float(vec2, scalar);
}
}
- else {
- BLI_assert(!"internal error");
- }
PyErr_Format(PyExc_TypeError,
- "Vector multiplication: "
+ "Element-wise multiplication: "
"not supported between '%.200s' and '%.200s' types",
Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
return NULL;
@@ -1782,32 +1775,129 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
/* multiplication in-place: obj *= obj */
static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
{
- VectorObject *vec = (VectorObject *)v1;
+ VectorObject *vec1 = NULL, *vec2 = NULL;
float scalar;
- if (BaseMath_ReadCallback_ForWrite(vec) == -1)
+ if (VectorObject_Check(v1)) {
+ vec1 = (VectorObject *)v1;
+ if (BaseMath_ReadCallback(vec1) == -1)
+ return NULL;
+ }
+ if (VectorObject_Check(v2)) {
+ vec2 = (VectorObject *)v2;
+ if (BaseMath_ReadCallback(vec2) == -1)
+ return NULL;
+ }
+
+ if (BaseMath_ReadCallback_ForWrite(vec1) == -1)
return NULL;
/* Intentionally don't support (Quaternion, Matrix) here, uses reverse order instead. */
- /* only support 'vec *= float'
- * vec*=vec result is a float so that wont work */
- if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC *= FLOAT */
- mul_vn_fl(vec->vec, vec->size, scalar);
+ if (vec1 && vec2) {
+#ifdef USE_MATHUTILS_ELEM_MUL
+ if (vec1->size != vec2->size) {
+ PyErr_SetString(PyExc_ValueError,
+ "Vector multiplication: "
+ "vectors must have the same dimensions for this operation");
+ return NULL;
+ }
+
+ /* element-wise product inplace */
+ mul_vn_vn(vec1->vec, vec2->vec, vec1->size);
+#else
+ PyErr_Format(PyExc_TypeError,
+ "Inplace element-wise multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
+ return NULL;
+#endif
+ }
+ else if (vec1 && (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0)) { /* VEC *= FLOAT */
+ mul_vn_fl(vec1->vec, vec1->size, scalar);
}
else {
PyErr_Format(PyExc_TypeError,
- "Vector multiplication: (%s *= %s) "
- "invalid type for this operation",
+ "Inplace element-wise multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
return NULL;
}
- (void)BaseMath_WriteCallback(vec);
+ (void)BaseMath_WriteCallback(vec1);
Py_INCREF(v1);
return v1;
}
+static PyObject *Vector_matmul(PyObject *v1, PyObject *v2)
+{
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+ int vec_size;
+
+ if (VectorObject_Check(v1)) {
+ vec1 = (VectorObject *)v1;
+ if (BaseMath_ReadCallback(vec1) == -1)
+ return NULL;
+ }
+ if (VectorObject_Check(v2)) {
+ vec2 = (VectorObject *)v2;
+ if (BaseMath_ReadCallback(vec2) == -1)
+ return NULL;
+ }
+
+
+ /* Intentionally don't support (Quaternion) here, uses reverse order instead. */
+
+ /* make sure v1 is always the vector */
+ if (vec1 && vec2) {
+ if (vec1->size != vec2->size) {
+ PyErr_SetString(PyExc_ValueError,
+ "Vector multiplication: "
+ "vectors must have the same dimensions for this operation");
+ return NULL;
+ }
+
+ /*dot product*/
+ return PyFloat_FromDouble(dot_vn_vn(vec1->vec, vec2->vec, vec1->size));
+ }
+ else if (vec1) {
+ if (MatrixObject_Check(v2)) {
+ /* VEC @ MATRIX */
+ float tvec[MAX_DIMENSIONS];
+
+ if (BaseMath_ReadCallback((MatrixObject *)v2) == -1)
+ return NULL;
+ if (row_vector_multiplication(tvec, vec1, (MatrixObject *)v2) == -1) {
+ return NULL;
+ }
+
+ if (((MatrixObject *)v2)->num_row == 4 && vec1->size == 3) {
+ vec_size = 3;
+ }
+ else {
+ vec_size = ((MatrixObject *)v2)->num_col;
+ }
+
+ return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(vec1));
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "Vector multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
+ return NULL;
+}
+
+static PyObject *Vector_imatmul(PyObject *v1, PyObject *v2)
+{
+ PyErr_Format(PyExc_TypeError,
+ "Inplace vector multiplication: "
+ "not supported between '%.200s' and '%.200s' types",
+ Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name);
+ return NULL;
+}
+
/* divid: obj / obj */
static PyObject *Vector_div(PyObject *v1, PyObject *v2)
{
@@ -2119,6 +2209,8 @@ static PyNumberMethods Vector_NumMethods = {
NULL, /* nb_inplace_floor_divide */
Vector_idiv, /* nb_inplace_true_divide */
NULL, /* nb_index */
+ (binaryfunc) Vector_matmul, /* nb_matrix_multiply */
+ (binaryfunc) Vector_imatmul, /* nb_inplace_matrix_multiply */
};
/*------------------PY_OBECT DEFINITION--------------------------*/
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index 36727fb91ae..dba5d52846b 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -48,10 +48,14 @@
#ifndef MATH_STANDALONE
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_editmesh_bvh.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "bmesh.h"
@@ -1045,10 +1049,12 @@ static PyObject *C_BVHTree_FromBMesh(PyObject *UNUSED(cls), PyObject *args, PyOb
}
/* return various derived meshes based on requested settings */
-static DerivedMesh *bvh_get_derived_mesh(
+static Mesh *bvh_get_mesh(
const char *funcname, struct Scene *scene, Object *ob,
bool use_deform, bool use_render, bool use_cage)
{
+ /* TODO: This doesn't work currently because of missing depsgraph. */
+#if 0
/* we only need minimum mesh data for topology and vertex locations */
CustomDataMask mask = CD_MASK_BAREMESH;
@@ -1096,6 +1102,11 @@ static DerivedMesh *bvh_get_derived_mesh(
}
}
}
+#else
+ UNUSED_VARS(funcname, scene, ob, use_deform, use_render, use_cage);
+#endif
+
+ return NULL;
}
PyDoc_STRVAR(C_BVHTree_FromObject_doc,
@@ -1123,7 +1134,7 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO
PyObject *py_ob, *py_scene;
Object *ob;
struct Scene *scene;
- DerivedMesh *dm;
+ Mesh *mesh;
bool use_deform = true;
bool use_render = false;
bool use_cage = false;
@@ -1149,24 +1160,27 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO
return NULL;
}
- dm = bvh_get_derived_mesh("BVHTree", scene, ob, use_deform, use_render, use_cage);
- if (dm == NULL) {
+ mesh = bvh_get_mesh("BVHTree", scene, ob, use_deform, use_render, use_cage);
+ if (mesh == NULL) {
return NULL;
}
/* Get data for tessellation */
{
- lt = dm->getLoopTriArray(dm);
+ lt = BKE_mesh_runtime_looptri_ensure(mesh);
- tris_len = (unsigned int)dm->getNumLoopTri(dm);
- coords_len = (unsigned int)dm->getNumVerts(dm);
+ tris_len = (unsigned int)BKE_mesh_runtime_looptri_len(mesh);
+ coords_len = (unsigned int)mesh->totvert;
coords = MEM_mallocN(sizeof(*coords) * (size_t)coords_len, __func__);
tris = MEM_mallocN(sizeof(*tris) * (size_t)tris_len, __func__);
- dm->getVertCos(dm, coords);
+ MVert *mv = mesh->mvert;
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ copy_v3_v3(coords[i], mv->co);
+ }
- mloop = dm->getLoopArray(dm);
+ mloop = mesh->mloop;
}
{
@@ -1179,7 +1193,8 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO
tree = BLI_bvhtree_new((int)tris_len, epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT);
if (tree) {
orig_index = MEM_mallocN(sizeof(*orig_index) * (size_t)tris_len, __func__);
- orig_normal = dm->getPolyDataArray(dm, CD_NORMAL); /* can be NULL */
+ CustomData *pdata = &mesh->pdata;
+ orig_normal = CustomData_get_layer(pdata, CD_NORMAL); /* can be NULL */
if (orig_normal) {
orig_normal = MEM_dupallocN(orig_normal);
}
@@ -1202,7 +1217,7 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO
BLI_bvhtree_balance(tree);
}
- dm->release(dm);
+ BKE_id_free(NULL, mesh);
return bvhtree_CreatePyObject(
tree, epsilon,
diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c
index 834322c0aed..5e3e86c8ddf 100644
--- a/source/blender/python/mathutils/mathutils_noise.c
+++ b/source/blender/python/mathutils/mathutils_noise.c
@@ -40,18 +40,11 @@
#include "DNA_texture_types.h"
+#include "../generic/py_capi_utils.h"
+
#include "mathutils.h"
#include "mathutils_noise.h"
-/* 2.6 update
- * Moved to submodule of mathutils.
- * All vector functions now return mathutils.Vector
- * Updated docs to be compatible with autodocs generation.
- * Updated vector functions to use nD array functions.
- * noise.vl_vector --> noise.variable_lacunarity
- * noise.vector --> noise.noise_vector
- */
-
/*-----------------------------------------*/
/* 'mersenne twister' random number generator */
@@ -198,6 +191,48 @@ static float frand(void)
/* Utility Functions */
/*------------------------------------------------------------*/
+#define BPY_NOISE_BASIS_ENUM_DOC \
+" :arg noise_basis: Enumerator in ['BLENDER', 'PERLIN_ORIGINAL', 'PERLIN_NEW', 'VORONOI_F1', 'VORONOI_F2', " \
+ "'VORONOI_F3', 'VORONOI_F4', 'VORONOI_F2F1', 'VORONOI_CRACKLE', " \
+ "'CELLNOISE'].\n" \
+" :type noise_basis: string\n" \
+
+#define BPY_NOISE_METRIC_ENUM_DOC \
+" :arg distance_metric: Enumerator in ['DISTANCE', 'DISTANCE_SQUARED', 'MANHATTAN', 'CHEBYCHEV', " \
+ "'MINKOVSKY', 'MINKOVSKY_HALF', 'MINKOVSKY_FOUR'].\n" \
+" :type distance_metric: string\n" \
+
+/* Noise basis enum */
+#define DEFAULT_NOISE_TYPE TEX_STDPERLIN
+
+static PyC_FlagSet bpy_noise_types[] = {
+ {TEX_BLENDER, "BLENDER"},
+ {TEX_STDPERLIN, "PERLIN_ORIGINAL"},
+ {TEX_NEWPERLIN, "PERLIN_NEW"},
+ {TEX_VORONOI_F1, "VORONOI_F1"},
+ {TEX_VORONOI_F2, "VORONOI_F2"},
+ {TEX_VORONOI_F3, "VORONOI_F3"},
+ {TEX_VORONOI_F4, "VORONOI_F4"},
+ {TEX_VORONOI_F2F1, "VORONOI_F2F1"},
+ {TEX_VORONOI_CRACKLE, "VORONOI_CRACKLE"},
+ {TEX_CELLNOISE, "CELLNOISE"},
+ {0, NULL}
+};
+
+/* Metric basis enum */
+#define DEFAULT_METRIC_TYPE TEX_DISTANCE
+
+static PyC_FlagSet bpy_noise_metrics[] = {
+ {TEX_DISTANCE, "DISTANCE"},
+ {TEX_DISTANCE_SQUARED, "DISTANCE_SQUARED"},
+ {TEX_MANHATTAN, "MANHATTAN"},
+ {TEX_CHEBYCHEV, "CHEBYCHEV"},
+ {TEX_MINKOVSKY, "MINKOVSKY"},
+ {TEX_MINKOVSKY_HALF, "MINKOVSKY_HALF"},
+ {TEX_MINKOVSKY_FOUR, "MINKOVSKY_FOUR"},
+ {0, NULL}
+};
+
/* Fills an array of length size with random numbers in the range (-1, 1)*/
static void rand_vn(float *array_tar, const int size)
{
@@ -218,8 +253,9 @@ static void noise_vector(float x, float y, float z, int nb, float v[3])
}
/* Returns a turbulence value for a given position (x, y, z) */
-static float turb(float x, float y, float z, int oct, int hard, int nb,
- float ampscale, float freqscale)
+static float turb(
+ float x, float y, float z, int oct, int hard, int nb,
+ float ampscale, float freqscale)
{
float amp, out, t;
int i;
@@ -242,8 +278,9 @@ static float turb(float x, float y, float z, int oct, int hard, int nb,
/* Fills an array of length 3 with the turbulence vector for a given
* position (x, y, z) */
-static void vTurb(float x, float y, float z, int oct, int hard, int nb,
- float ampscale, float freqscale, float v[3])
+static void vTurb(
+ float x, float y, float z, int oct, int hard, int nb,
+ float ampscale, float freqscale, float v[3])
{
float amp, t[3];
int i;
@@ -283,7 +320,7 @@ PyDoc_STRVAR(M_Noise_doc,
PyDoc_STRVAR(M_Noise_random_doc,
".. function:: random()\n"
"\n"
-" Returns a random number in the range [0, 1].\n"
+" Returns a random number in the range [0, 1).\n"
"\n"
" :return: The random number.\n"
" :rtype: float\n"
@@ -298,71 +335,81 @@ PyDoc_STRVAR(M_Noise_random_unit_vector_doc,
"\n"
" Returns a unit vector with random entries.\n"
"\n"
-" :arg size: The size of the vector to be produced.\n"
-" :type size: Int\n"
+" :arg size: The size of the vector to be produced, in the range [2, 4].\n"
+" :type size: int\n"
" :return: The random unit vector.\n"
" :rtype: :class:`mathutils.Vector`\n"
);
-static PyObject *M_Noise_random_unit_vector(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_random_unit_vector(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"size", NULL};
float vec[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float norm = 2.0f;
int size = 3;
- if (!PyArg_ParseTuple(args, "|i:random_vector", &size))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|$i:random_unit_vector", (char **)kwlist,
+ &size))
+ {
return NULL;
+ }
if (size > 4 || size < 2) {
PyErr_SetString(PyExc_ValueError, "Vector(): invalid size");
return NULL;
}
- while (norm == 0.0f || norm >= 1.0f) {
+ while (norm == 0.0f || norm > 1.0f) {
rand_vn(vec, size);
norm = normalize_vn(vec, size);
}
return Vector_CreatePyObject(vec, size, NULL);
}
-/* This is dumb, most people will want a unit vector anyway, since this doesn't have uniform distribution over a sphere*/
-#if 0
+
PyDoc_STRVAR(M_Noise_random_vector_doc,
".. function:: random_vector(size=3)\n"
"\n"
-" Returns a vector with random entries in the range [0, 1).\n"
+" Returns a vector with random entries in the range (-1, 1).\n"
"\n"
" :arg size: The size of the vector to be produced.\n"
-" :type size: Int\n"
+" :type size: int\n"
" :return: The random vector.\n"
" :rtype: :class:`mathutils.Vector`\n"
);
-static PyObject *M_Noise_random_vector(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_random_vector(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- float vec[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ static const char *kwlist[] = {"size", NULL};
+ float *vec = NULL;
int size = 3;
- if (!PyArg_ParseTuple(args, "|i:random_vector", &size))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "|$i:random_vector", (char **)kwlist,
+ &size))
+ {
return NULL;
+ }
- if (size > 4 || size < 2) {
+ if (size < 2) {
PyErr_SetString(PyExc_ValueError, "Vector(): invalid size");
return NULL;
}
+ vec = PyMem_New(float, size);
+
rand_vn(vec, size);
- return Vector_CreatePyObject(vec, size, NULL);
+ return Vector_CreatePyObject_alloc(vec, size, NULL);
}
-#endif
PyDoc_STRVAR(M_Noise_seed_set_doc,
".. function:: seed_set(seed)\n"
"\n"
-" Sets the random seed used for random_unit_vector, random_vector and random.\n"
+" Sets the random seed used for random_unit_vector, and random.\n"
"\n"
" :arg seed: Seed used for the random generator.\n"
" When seed is zero, the current time will be used instead.\n"
-" :type seed: Int\n"
+" :type seed: int\n"
);
static PyObject *M_Noise_seed_set(PyObject *UNUSED(self), PyObject *args)
{
@@ -374,139 +421,198 @@ static PyObject *M_Noise_seed_set(PyObject *UNUSED(self), PyObject *args)
}
PyDoc_STRVAR(M_Noise_noise_doc,
-".. function:: noise(position, noise_basis=noise.types.STDPERLIN)\n"
+".. function:: noise(position, noise_basis='PERLIN_ORIGINAL')\n"
"\n"
" Returns noise value from the noise basis at the position specified.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in noise.types or int\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :return: The noise value.\n"
" :rtype: float\n"
);
-static PyObject *M_Noise_noise(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_noise(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "noise_basis", NULL};
PyObject *value;
float vec[3];
- int nb = 1;
- if (!PyArg_ParseTuple(args, "O|i:noise", &value, &nb))
+ const char *noise_basis_str = NULL;
+ int noise_basis_enum = DEFAULT_NOISE_TYPE;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O|$s:noise", (char **)kwlist,
+ &value, &noise_basis_str))
+ {
+ return NULL;
+ }
+
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "noise") == -1)
+ {
return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "noise: invalid 'position' arg") == -1)
return NULL;
- return PyFloat_FromDouble((2.0f * BLI_gNoise(1.0f, vec[0], vec[1], vec[2], 0, nb) - 1.0f));
+ return PyFloat_FromDouble((2.0f * BLI_gNoise(1.0f, vec[0], vec[1], vec[2], 0, noise_basis_enum) - 1.0f));
}
PyDoc_STRVAR(M_Noise_noise_vector_doc,
-".. function:: noise_vector(position, noise_basis=noise.types.STDPERLIN)\n"
+".. function:: noise_vector(position, noise_basis='PERLIN_ORIGINAL')\n"
"\n"
" Returns the noise vector from the noise basis at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in noise.types or int\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :return: The noise vector.\n"
" :rtype: :class:`mathutils.Vector`\n"
);
-static PyObject *M_Noise_noise_vector(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_noise_vector(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "noise_basis", NULL};
PyObject *value;
float vec[3], r_vec[3];
- int nb = 1;
+ const char *noise_basis_str = NULL;
+ int noise_basis_enum = DEFAULT_NOISE_TYPE;
- if (!PyArg_ParseTuple(args, "O|i:noise_vector", &value, &nb))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O|$s:noise_vector", (char **)kwlist,
+ &value, &noise_basis_str))
+ {
+ return NULL;
+ }
+
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "noise_vector") == -1)
+ {
return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "noise_vector: invalid 'position' arg") == -1)
return NULL;
- noise_vector(vec[0], vec[1], vec[2], nb, r_vec);
+ noise_vector(vec[0], vec[1], vec[2], noise_basis_enum, r_vec);
return Vector_CreatePyObject(r_vec, 3, NULL);
}
PyDoc_STRVAR(M_Noise_turbulence_doc,
-".. function:: turbulence(position, octaves, hard, noise_basis=noise.types.STDPERLIN, amplitude_scale=0.5, frequency_scale=2.0)\n"
+".. function:: turbulence(position, octaves, hard, noise_basis='PERLIN_ORIGINAL', amplitude_scale=0.5, frequency_scale=2.0)\n"
"\n"
" Returns the turbulence value from the noise basis at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :arg octaves: The number of different noise frequencies used.\n"
" :type octaves: int\n"
" :arg hard: Specifies whether returned turbulence is hard (sharp transitions) or soft (smooth transitions).\n"
-" :type hard: :boolean\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in mathutils.noise.types or int\n"
+" :type hard: boolean\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :arg amplitude_scale: The amplitude scaling factor.\n"
" :type amplitude_scale: float\n"
" :arg frequency_scale: The frequency scaling factor\n"
-" :type frequency_scale: Value in noise.types or int\n"
+" :type frequency_scale: float\n"
" :return: The turbulence value.\n"
" :rtype: float\n"
);
-static PyObject *M_Noise_turbulence(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_turbulence(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "", "", "noise_basis", "amplitude_scale", "frequency_scale", NULL};
PyObject *value;
float vec[3];
- int oct, hd, nb = 1;
+ const char *noise_basis_str = NULL;
+ int oct, hd, noise_basis_enum = DEFAULT_NOISE_TYPE;
float as = 0.5f, fs = 2.0f;
- if (!PyArg_ParseTuple(args, "Oii|iff:turbulence", &value, &oct, &hd, &nb, &as, &fs))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "Oii|$sff:turbulence", (char **)kwlist,
+ &value, &oct, &hd, &noise_basis_str, &as, &fs))
+ {
return NULL;
+ }
+
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "turbulence") == -1)
+ {
+ return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "turbulence: invalid 'position' arg") == -1)
return NULL;
- return PyFloat_FromDouble(turb(vec[0], vec[1], vec[2], oct, hd, nb, as, fs));
+ return PyFloat_FromDouble(turb(vec[0], vec[1], vec[2], oct, hd, noise_basis_enum, as, fs));
}
PyDoc_STRVAR(M_Noise_turbulence_vector_doc,
-".. function:: turbulence_vector(position, octaves, hard, noise_basis=noise.types.STDPERLIN, amplitude_scale=0.5, frequency_scale=2.0)\n"
+".. function:: turbulence_vector(position, octaves, hard, noise_basis='PERLIN_ORIGINAL', amplitude_scale=0.5, frequency_scale=2.0)\n"
"\n"
" Returns the turbulence vector from the noise basis at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :arg octaves: The number of different noise frequencies used.\n"
" :type octaves: int\n"
" :arg hard: Specifies whether returned turbulence is hard (sharp transitions) or soft (smooth transitions).\n"
" :type hard: :boolean\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in mathutils.noise.types or int\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :arg amplitude_scale: The amplitude scaling factor.\n"
" :type amplitude_scale: float\n"
" :arg frequency_scale: The frequency scaling factor\n"
-" :type frequency_scale: Value in noise.types or int\n"
+" :type frequency_scale: float\n"
" :return: The turbulence vector.\n"
" :rtype: :class:`mathutils.Vector`\n"
);
-static PyObject *M_Noise_turbulence_vector(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_turbulence_vector(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "", "", "noise_basis", "amplitude_scale", "frequency_scale", NULL};
PyObject *value;
float vec[3], r_vec[3];
- int oct, hd, nb = 1;
+ const char *noise_basis_str = NULL;
+ int oct, hd, noise_basis_enum = DEFAULT_NOISE_TYPE;
float as = 0.5f, fs = 2.0f;
- if (!PyArg_ParseTuple(args, "Oii|iff:turbulence_vector", &value, &oct, &hd, &nb, &as, &fs))
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "Oii|$sff:turbulence_vector", (char **)kwlist,
+ &value, &oct, &hd, &noise_basis_str, &as, &fs))
+ {
return NULL;
+ }
+
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "turbulence_vector") == -1)
+ {
+ return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "turbulence_vector: invalid 'position' arg") == -1)
return NULL;
- vTurb(vec[0], vec[1], vec[2], oct, hd, nb, as, fs, r_vec);
+ vTurb(vec[0], vec[1], vec[2], oct, hd, noise_basis_enum, as, fs, r_vec);
+
return Vector_CreatePyObject(r_vec, 3, NULL);
}
/* F. Kenton Musgrave's fractal functions */
PyDoc_STRVAR(M_Noise_fractal_doc,
-".. function:: fractal(position, H, lacunarity, octaves, noise_basis=noise.types.STDPERLIN)\n"
+".. function:: fractal(position, H, lacunarity, octaves, noise_basis='PERLIN_ORIGINAL')\n"
"\n"
" Returns the fractal Brownian motion (fBm) noise value from the noise basis at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :arg H: The fractal increment factor.\n"
" :type H: float\n"
@@ -514,33 +620,47 @@ PyDoc_STRVAR(M_Noise_fractal_doc,
" :type lacunarity: float\n"
" :arg octaves: The number of different noise frequencies used.\n"
" :type octaves: int\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in noise.types or int\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :return: The fractal Brownian motion noise value.\n"
" :rtype: float\n"
);
-static PyObject *M_Noise_fractal(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_fractal(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "", "", "", "noise_basis", NULL};
PyObject *value;
float vec[3];
+ const char *noise_basis_str = NULL;
float H, lac, oct;
- int nb = 1;
+ int noise_basis_enum = DEFAULT_NOISE_TYPE;
- if (!PyArg_ParseTuple(args, "Offf|i:fractal", &value, &H, &lac, &oct, &nb))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "Offf|$s:fractal", (char **)kwlist,
+ &value, &H, &lac, &oct, &noise_basis_str))
+ {
return NULL;
+ }
+
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "fractal") == -1)
+ {
+ return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "fractal: invalid 'position' arg") == -1)
return NULL;
- return PyFloat_FromDouble(mg_fBm(vec[0], vec[1], vec[2], H, lac, oct, nb));
+ return PyFloat_FromDouble(mg_fBm(vec[0], vec[1], vec[2], H, lac, oct, noise_basis_enum));
}
PyDoc_STRVAR(M_Noise_multi_fractal_doc,
-".. function:: multi_fractal(position, H, lacunarity, octaves, noise_basis=noise.types.STDPERLIN)\n"
+".. function:: multi_fractal(position, H, lacunarity, octaves, noise_basis='PERLIN_ORIGINAL')\n"
"\n"
" Returns multifractal noise value from the noise basis at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :arg H: The fractal increment factor.\n"
" :type H: float\n"
@@ -548,65 +668,107 @@ PyDoc_STRVAR(M_Noise_multi_fractal_doc,
" :type lacunarity: float\n"
" :arg octaves: The number of different noise frequencies used.\n"
" :type octaves: int\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in noise.types or int\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :return: The multifractal noise value.\n"
" :rtype: float\n"
);
-static PyObject *M_Noise_multi_fractal(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_multi_fractal(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "", "", "", "noise_basis", NULL};
PyObject *value;
float vec[3];
+ const char *noise_basis_str = NULL;
float H, lac, oct;
- int nb = 1;
+ int noise_basis_enum = DEFAULT_NOISE_TYPE;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "Offf|$s:multi_fractal", (char **)kwlist,
+ &value, &H, &lac, &oct, &noise_basis_str))
+ {
+ return NULL;
+ }
- if (!PyArg_ParseTuple(args, "Offf|i:multi_fractal", &value, &H, &lac, &oct, &nb))
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "multi_fractal") == -1)
+ {
return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "multi_fractal: invalid 'position' arg") == -1)
return NULL;
- return PyFloat_FromDouble(mg_MultiFractal(vec[0], vec[1], vec[2], H, lac, oct, nb));
+ return PyFloat_FromDouble(mg_MultiFractal(vec[0], vec[1], vec[2], H, lac, oct, noise_basis_enum));
}
PyDoc_STRVAR(M_Noise_variable_lacunarity_doc,
-".. function:: variable_lacunarity(position, distortion, noise_type1=noise.types.STDPERLIN, noise_type2=noise.types.STDPERLIN)\n"
+".. function:: variable_lacunarity(position, distortion, noise_type1='PERLIN_ORIGINAL', noise_type2='PERLIN_ORIGINAL')\n"
"\n"
" Returns variable lacunarity noise value, a distorted variety of noise, from noise type 1 distorted by noise type 2 at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :arg distortion: The amount of distortion.\n"
" :type distortion: float\n"
-" :arg noise_type1: The type of noise to be distorted.\n"
-" :type noise_type1: Value in noise.types or int\n"
-" :arg noise_type2: The type of noise used to distort noise_type1.\n"
-" :type noise_type2: Value in noise.types or int\n"
+" :arg noise_type1: Enumerator in ['BLENDER', 'PERLIN_ORIGINAL', 'PERLIN_NEW', 'VORONOI_F1', 'VORONOI_F2', " \
+ "'VORONOI_F3', 'VORONOI_F4', 'VORONOI_F2F1', 'VORONOI_CRACKLE', " \
+ "'CELLNOISE'].\n"
+" :type noise_type1: string\n"
+" :arg noise_type2: Enumerator in ['BLENDER', 'PERLIN_ORIGINAL', 'PERLIN_NEW', 'VORONOI_F1', 'VORONOI_F2', " \
+ "'VORONOI_F3', 'VORONOI_F4', 'VORONOI_F2F1', 'VORONOI_CRACKLE', " \
+ "'CELLNOISE'].\n"
+" :type noise_type2: string\n"
" :return: The variable lacunarity noise value.\n"
" :rtype: float\n"
);
-static PyObject *M_Noise_variable_lacunarity(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_variable_lacunarity(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "", "noise_type1", "noise_type2", NULL};
PyObject *value;
float vec[3];
+ const char *noise_type1_str = NULL, *noise_type2_str = NULL;
float d;
- int nt1 = 1, nt2 = 1;
+ int noise_type1_enum = DEFAULT_NOISE_TYPE, noise_type2_enum = DEFAULT_NOISE_TYPE;
- if (!PyArg_ParseTuple(args, "Of|ii:variable_lacunarity", &value, &d, &nt1, &nt2))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "Of|$ss:variable_lacunarity", (char **)kwlist,
+ &value, &d, &noise_type1_str, &noise_type2_str))
+ {
return NULL;
+ }
+
+ if (!noise_type1_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_type1_str, &noise_type1_enum, "variable_lacunarity") == -1)
+ {
+ return NULL;
+ }
+
+ if (!noise_type2_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_type2_str, &noise_type2_enum, "variable_lacunarity") == -1)
+ {
+ return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "variable_lacunarity: invalid 'position' arg") == -1)
return NULL;
- return PyFloat_FromDouble(mg_VLNoise(vec[0], vec[1], vec[2], d, nt1, nt2));
+ return PyFloat_FromDouble(mg_VLNoise(vec[0], vec[1], vec[2], d, noise_type1_enum, noise_type2_enum));
}
PyDoc_STRVAR(M_Noise_hetero_terrain_doc,
-".. function:: hetero_terrain(position, H, lacunarity, octaves, offset, noise_basis=noise.types.STDPERLIN)\n"
+".. function:: hetero_terrain(position, H, lacunarity, octaves, offset, noise_basis='PERLIN_ORIGINAL')\n"
"\n"
" Returns the heterogeneous terrain value from the noise basis at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :arg H: The fractal dimension of the roughest areas.\n"
" :type H: float\n"
@@ -616,33 +778,47 @@ PyDoc_STRVAR(M_Noise_hetero_terrain_doc,
" :type octaves: int\n"
" :arg offset: The height of the terrain above 'sea level'.\n"
" :type offset: float\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in noise.types or int\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :return: The heterogeneous terrain value.\n"
" :rtype: float\n"
);
-static PyObject *M_Noise_hetero_terrain(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_hetero_terrain(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "", "", "", "", "noise_basis", NULL};
PyObject *value;
float vec[3];
+ const char *noise_basis_str = NULL;
float H, lac, oct, ofs;
- int nb = 1;
+ int noise_basis_enum = DEFAULT_NOISE_TYPE;
- if (!PyArg_ParseTuple(args, "Offff|i:hetero_terrain", &value, &H, &lac, &oct, &ofs, &nb))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "Offff|$s:hetero_terrain", (char **)kwlist,
+ &value, &H, &lac, &oct, &ofs, &noise_basis_str))
+ {
+ return NULL;
+ }
+
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "hetero_terrain") == -1)
+ {
return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "hetero_terrain: invalid 'position' arg") == -1)
return NULL;
- return PyFloat_FromDouble(mg_HeteroTerrain(vec[0], vec[1], vec[2], H, lac, oct, ofs, nb));
+ return PyFloat_FromDouble(mg_HeteroTerrain(vec[0], vec[1], vec[2], H, lac, oct, ofs, noise_basis_enum));
}
PyDoc_STRVAR(M_Noise_hybrid_multi_fractal_doc,
-".. function:: hybrid_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis=noise.types.STDPERLIN)\n"
+".. function:: hybrid_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis='PERLIN_ORIGINAL')\n"
"\n"
" Returns hybrid multifractal value from the noise basis at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :arg H: The fractal dimension of the roughest areas.\n"
" :type H: float\n"
@@ -654,33 +830,47 @@ PyDoc_STRVAR(M_Noise_hybrid_multi_fractal_doc,
" :type offset: float\n"
" :arg gain: Scaling applied to the values.\n"
" :type gain: float\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in noise.types or int\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :return: The hybrid multifractal value.\n"
" :rtype: float\n"
);
-static PyObject *M_Noise_hybrid_multi_fractal(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_hybrid_multi_fractal(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "", "", "", "", "", "noise_basis", NULL};
PyObject *value;
float vec[3];
+ const char *noise_basis_str = NULL;
float H, lac, oct, ofs, gn;
- int nb = 1;
+ int noise_basis_enum = DEFAULT_NOISE_TYPE;
- if (!PyArg_ParseTuple(args, "Offfff|i:hybrid_multi_fractal", &value, &H, &lac, &oct, &ofs, &gn, &nb))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "Offfff|$s:hybrid_multi_fractal", (char **)kwlist,
+ &value, &H, &lac, &oct, &ofs, &gn, &noise_basis_str))
+ {
return NULL;
+ }
+
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "hybrid_multi_fractal") == -1)
+ {
+ return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "hybrid_multi_fractal: invalid 'position' arg") == -1)
return NULL;
- return PyFloat_FromDouble(mg_HybridMultiFractal(vec[0], vec[1], vec[2], H, lac, oct, ofs, gn, nb));
+ return PyFloat_FromDouble(mg_HybridMultiFractal(vec[0], vec[1], vec[2], H, lac, oct, ofs, gn, noise_basis_enum));
}
PyDoc_STRVAR(M_Noise_ridged_multi_fractal_doc,
-".. function:: ridged_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis=noise.types.STDPERLIN)\n"
+".. function:: ridged_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis='PERLIN_ORIGINAL')\n"
"\n"
" Returns ridged multifractal value from the noise basis at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :arg H: The fractal dimension of the roughest areas.\n"
" :type H: float\n"
@@ -692,67 +882,94 @@ PyDoc_STRVAR(M_Noise_ridged_multi_fractal_doc,
" :type offset: float\n"
" :arg gain: Scaling applied to the values.\n"
" :type gain: float\n"
-" :arg noise_basis: The type of noise to be evaluated.\n"
-" :type noise_basis: Value in noise.types or int\n"
+BPY_NOISE_BASIS_ENUM_DOC
" :return: The ridged multifractal value.\n"
" :rtype: float\n"
);
-static PyObject *M_Noise_ridged_multi_fractal(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_ridged_multi_fractal(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "", "", "", "", "", "noise_basis", NULL};
PyObject *value;
float vec[3];
+ const char *noise_basis_str = NULL;
float H, lac, oct, ofs, gn;
- int nb = 1;
+ int noise_basis_enum = DEFAULT_NOISE_TYPE;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "Offfff|$s:ridged_multi_fractal", (char **)kwlist,
+ &value, &H, &lac, &oct, &ofs, &gn, &noise_basis_str))
+ {
+ return NULL;
+ }
- if (!PyArg_ParseTuple(args, "Offfff|i:ridged_multi_fractal", &value, &H, &lac, &oct, &ofs, &gn, &nb))
+ if (!noise_basis_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_types, noise_basis_str, &noise_basis_enum, "ridged_multi_fractal") == -1)
+ {
return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "ridged_multi_fractal: invalid 'position' arg") == -1)
return NULL;
- return PyFloat_FromDouble(mg_RidgedMultiFractal(vec[0], vec[1], vec[2], H, lac, oct, ofs, gn, nb));
+ return PyFloat_FromDouble(mg_RidgedMultiFractal(vec[0], vec[1], vec[2], H, lac, oct, ofs, gn, noise_basis_enum));
}
PyDoc_STRVAR(M_Noise_voronoi_doc,
-".. function:: voronoi(position, distance_metric=noise.distance_metrics.DISTANCE, exponent=2.5)\n"
+".. function:: voronoi(position, distance_metric='DISTANCE', exponent=2.5)\n"
"\n"
" Returns a list of distances to the four closest features and their locations.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
-" :arg distance_metric: Method of measuring distance.\n"
-" :type distance_metric: Value in noise.distance_metrics or int\n"
+BPY_NOISE_METRIC_ENUM_DOC
" :arg exponent: The exponent for Minkowski distance metric.\n"
" :type exponent: float\n"
" :return: A list of distances to the four closest features and their locations.\n"
" :rtype: list of four floats, list of four :class:`mathutils.Vector` types\n"
);
-static PyObject *M_Noise_voronoi(PyObject *UNUSED(self), PyObject *args)
+static PyObject *M_Noise_voronoi(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"", "distance_metric", "exponent", NULL};
PyObject *value;
PyObject *list;
PyObject *ret;
float vec[3];
+ const char *metric_str = NULL;
float da[4], pa[12];
- int dtype = 0;
+ int metric_enum = DEFAULT_METRIC_TYPE;
float me = 2.5f; /* default minkowski exponent */
int i;
- if (!PyArg_ParseTuple(args, "O|if:voronoi", &value, &dtype, &me))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "O|$sf:voronoi", (char **)kwlist,
+ &value, &metric_str, &me))
+ {
return NULL;
+ }
+
+ if (!metric_str) {
+ /* pass through */
+ }
+ else if (PyC_FlagSet_ValueFromID(
+ bpy_noise_metrics, metric_str, &metric_enum, "voronoi") == -1)
+ {
+ return NULL;
+ }
if (mathutils_array_parse(vec, 3, 3, value, "voronoi: invalid 'position' arg") == -1)
return NULL;
list = PyList_New(4);
- voronoi(vec[0], vec[1], vec[2], da, pa, me, dtype);
+ voronoi(vec[0], vec[1], vec[2], da, pa, me, metric_enum);
for (i = 0; i < 4; i++) {
PyObject *v = Vector_CreatePyObject(pa + 3 * i, 3, NULL);
PyList_SET_ITEM(list, i, v);
- Py_DECREF(v);
}
ret = Py_BuildValue("[[ffff]O]", da[0], da[1], da[2], da[3], list);
@@ -765,7 +982,7 @@ PyDoc_STRVAR(M_Noise_cell_doc,
"\n"
" Returns cell noise value at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :return: The cell noise value.\n"
" :rtype: float\n"
@@ -789,7 +1006,7 @@ PyDoc_STRVAR(M_Noise_cell_vector_doc,
"\n"
" Returns cell noise vector at the specified position.\n"
"\n"
-" :arg position: The position to evaluate the selected noise function at.\n"
+" :arg position: The position to evaluate the selected noise function.\n"
" :type position: :class:`mathutils.Vector`\n"
" :return: The cell noise vector.\n"
" :rtype: :class:`mathutils.Vector`\n"
@@ -812,19 +1029,19 @@ static PyObject *M_Noise_cell_vector(PyObject *UNUSED(self), PyObject *args)
static PyMethodDef M_Noise_methods[] = {
{"seed_set", (PyCFunction) M_Noise_seed_set, METH_VARARGS, M_Noise_seed_set_doc},
{"random", (PyCFunction) M_Noise_random, METH_NOARGS, M_Noise_random_doc},
- {"random_unit_vector", (PyCFunction) M_Noise_random_unit_vector, METH_VARARGS, M_Noise_random_unit_vector_doc},
- /*{"random_vector", (PyCFunction) M_Noise_random_vector, METH_VARARGS, M_Noise_random_vector_doc},*/
- {"noise", (PyCFunction) M_Noise_noise, METH_VARARGS, M_Noise_noise_doc},
- {"noise_vector", (PyCFunction) M_Noise_noise_vector, METH_VARARGS, M_Noise_noise_vector_doc},
- {"turbulence", (PyCFunction) M_Noise_turbulence, METH_VARARGS, M_Noise_turbulence_doc},
- {"turbulence_vector", (PyCFunction) M_Noise_turbulence_vector, METH_VARARGS, M_Noise_turbulence_vector_doc},
- {"fractal", (PyCFunction) M_Noise_fractal, METH_VARARGS, M_Noise_fractal_doc},
- {"multi_fractal", (PyCFunction) M_Noise_multi_fractal, METH_VARARGS, M_Noise_multi_fractal_doc},
- {"variable_lacunarity", (PyCFunction) M_Noise_variable_lacunarity, METH_VARARGS, M_Noise_variable_lacunarity_doc},
- {"hetero_terrain", (PyCFunction) M_Noise_hetero_terrain, METH_VARARGS, M_Noise_hetero_terrain_doc},
- {"hybrid_multi_fractal", (PyCFunction) M_Noise_hybrid_multi_fractal, METH_VARARGS, M_Noise_hybrid_multi_fractal_doc},
- {"ridged_multi_fractal", (PyCFunction) M_Noise_ridged_multi_fractal, METH_VARARGS, M_Noise_ridged_multi_fractal_doc},
- {"voronoi", (PyCFunction) M_Noise_voronoi, METH_VARARGS, M_Noise_voronoi_doc},
+ {"random_unit_vector", (PyCFunction) M_Noise_random_unit_vector, METH_VARARGS | METH_KEYWORDS, M_Noise_random_unit_vector_doc},
+ {"random_vector", (PyCFunction) M_Noise_random_vector, METH_VARARGS | METH_KEYWORDS, M_Noise_random_vector_doc},
+ {"noise", (PyCFunction) M_Noise_noise, METH_VARARGS | METH_KEYWORDS, M_Noise_noise_doc},
+ {"noise_vector", (PyCFunction) M_Noise_noise_vector, METH_VARARGS | METH_KEYWORDS, M_Noise_noise_vector_doc},
+ {"turbulence", (PyCFunction) M_Noise_turbulence, METH_VARARGS | METH_KEYWORDS, M_Noise_turbulence_doc},
+ {"turbulence_vector", (PyCFunction) M_Noise_turbulence_vector, METH_VARARGS | METH_KEYWORDS, M_Noise_turbulence_vector_doc},
+ {"fractal", (PyCFunction) M_Noise_fractal, METH_VARARGS | METH_KEYWORDS, M_Noise_fractal_doc},
+ {"multi_fractal", (PyCFunction) M_Noise_multi_fractal, METH_VARARGS | METH_KEYWORDS, M_Noise_multi_fractal_doc},
+ {"variable_lacunarity", (PyCFunction) M_Noise_variable_lacunarity, METH_VARARGS | METH_KEYWORDS, M_Noise_variable_lacunarity_doc},
+ {"hetero_terrain", (PyCFunction) M_Noise_hetero_terrain, METH_VARARGS | METH_KEYWORDS, M_Noise_hetero_terrain_doc},
+ {"hybrid_multi_fractal", (PyCFunction) M_Noise_hybrid_multi_fractal, METH_VARARGS | METH_KEYWORDS, M_Noise_hybrid_multi_fractal_doc},
+ {"ridged_multi_fractal", (PyCFunction) M_Noise_ridged_multi_fractal, METH_VARARGS | METH_KEYWORDS, M_Noise_ridged_multi_fractal_doc},
+ {"voronoi", (PyCFunction) M_Noise_voronoi, METH_VARARGS | METH_KEYWORDS, M_Noise_voronoi_doc},
{"cell", (PyCFunction) M_Noise_cell, METH_VARARGS, M_Noise_cell_doc},
{"cell_vector", (PyCFunction) M_Noise_cell_vector, METH_VARARGS, M_Noise_cell_vector_doc},
{NULL, NULL, 0, NULL}
@@ -845,78 +1062,10 @@ static struct PyModuleDef M_Noise_module_def = {
/*----------------------------MODULE INIT-------------------------*/
PyMODINIT_FUNC PyInit_mathutils_noise(void)
{
- PyObject *sys_modules = PyImport_GetModuleDict();
PyObject *submodule = PyModule_Create(&M_Noise_module_def);
- PyObject *item_types, *item_metrics;
/* use current time as seed for random number generator by default */
setRndSeed(0);
- PyModule_AddObject(submodule, "types", (item_types = PyInit_mathutils_noise_types()));
- PyDict_SetItemString(sys_modules, "noise.types", item_types);
- Py_INCREF(item_types);
-
- PyModule_AddObject(submodule, "distance_metrics", (item_metrics = PyInit_mathutils_noise_metrics()));
- PyDict_SetItemString(sys_modules, "noise.distance_metrics", item_metrics);
- Py_INCREF(item_metrics);
-
- return submodule;
-}
-
-/*----------------------------SUBMODULE INIT-------------------------*/
-static struct PyModuleDef M_NoiseTypes_module_def = {
- PyModuleDef_HEAD_INIT,
- "mathutils.noise.types", /* m_name */
- NULL, /* m_doc */
- 0, /* m_size */
- NULL, /* m_methods */
- NULL, /* m_reload */
- NULL, /* m_traverse */
- NULL, /* m_clear */
- NULL, /* m_free */
-};
-
-PyMODINIT_FUNC PyInit_mathutils_noise_types(void)
-{
- PyObject *submodule = PyModule_Create(&M_NoiseTypes_module_def);
-
- PyModule_AddIntConstant(submodule, "BLENDER", TEX_BLENDER);
- PyModule_AddIntConstant(submodule, "STDPERLIN", TEX_STDPERLIN);
- PyModule_AddIntConstant(submodule, "NEWPERLIN", TEX_NEWPERLIN);
- PyModule_AddIntConstant(submodule, "VORONOI_F1", TEX_VORONOI_F1);
- PyModule_AddIntConstant(submodule, "VORONOI_F2", TEX_VORONOI_F2);
- PyModule_AddIntConstant(submodule, "VORONOI_F3", TEX_VORONOI_F3);
- PyModule_AddIntConstant(submodule, "VORONOI_F4", TEX_VORONOI_F4);
- PyModule_AddIntConstant(submodule, "VORONOI_F2F1", TEX_VORONOI_F2F1);
- PyModule_AddIntConstant(submodule, "VORONOI_CRACKLE", TEX_VORONOI_CRACKLE);
- PyModule_AddIntConstant(submodule, "CELLNOISE", TEX_CELLNOISE);
-
- return submodule;
-}
-
-static struct PyModuleDef M_NoiseMetrics_module_def = {
- PyModuleDef_HEAD_INIT,
- "mathutils.noise.distance_metrics", /* m_name */
- NULL, /* m_doc */
- 0, /* m_size */
- NULL, /* m_methods */
- NULL, /* m_reload */
- NULL, /* m_traverse */
- NULL, /* m_clear */
- NULL, /* m_free */
-};
-
-PyMODINIT_FUNC PyInit_mathutils_noise_metrics(void)
-{
- PyObject *submodule = PyModule_Create(&M_NoiseMetrics_module_def);
-
- PyModule_AddIntConstant(submodule, "DISTANCE", TEX_DISTANCE);
- PyModule_AddIntConstant(submodule, "DISTANCE_SQUARED", TEX_DISTANCE_SQUARED);
- PyModule_AddIntConstant(submodule, "MANHATTAN", TEX_MANHATTAN);
- PyModule_AddIntConstant(submodule, "CHEBYCHEV", TEX_CHEBYCHEV);
- PyModule_AddIntConstant(submodule, "MINKOVSKY_HALF", TEX_MINKOVSKY_HALF);
- PyModule_AddIntConstant(submodule, "MINKOVSKY_FOUR", TEX_MINKOVSKY_FOUR);
- PyModule_AddIntConstant(submodule, "MINKOVSKY", TEX_MINKOVSKY);
-
return submodule;
}
diff --git a/source/blender/python/simple_enum_gen.py b/source/blender/python/simple_enum_gen.py
index 4f3159b9b25..3a9c1847fc7 100644
--- a/source/blender/python/simple_enum_gen.py
+++ b/source/blender/python/simple_enum_gen.py
@@ -34,7 +34,7 @@ defs = """
SPACE_ACTION,
SPACE_NLA,
SPACE_SCRIPT, #Deprecated
- SPACE_TIME,
+ SPACE_TIME, #Deprecated
SPACE_NODE,
SPACEICONMAX
"""
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 36e18da00c7..8f921d7850a 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -36,6 +36,8 @@ set(INC
../makesrna
../nodes
../physics
+ ../draw
+ ../gpu
../../../intern/atomic
../../../intern/guardedalloc
../../../intern/mikktspace
@@ -43,47 +45,19 @@ set(INC
)
set(INC_SYS
-
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
- intern/raytrace/rayobject.cpp
- intern/raytrace/rayobject_empty.cpp
- intern/raytrace/rayobject_octree.cpp
- intern/raytrace/rayobject_raycounter.cpp
- intern/raytrace/rayobject_svbvh.cpp
- intern/raytrace/rayobject_instance.cpp
- intern/raytrace/rayobject_qbvh.cpp
- intern/raytrace/rayobject_rtbuild.cpp
- intern/raytrace/rayobject_vbvh.cpp
- intern/source/bake.c
intern/source/bake_api.c
- intern/source/convertblender.c
- intern/source/envmap.c
intern/source/external_engine.c
intern/source/imagetexture.c
intern/source/initrender.c
intern/source/multires_bake.c
- intern/source/occlusion.c
intern/source/pipeline.c
- intern/source/pixelblending.c
- intern/source/pixelshading.c
intern/source/pointdensity.c
- intern/source/rayshade.c
- intern/source/rendercore.c
intern/source/render_result.c
intern/source/render_texture.c
- intern/source/renderdatabase.c
- intern/source/shadbuf.c
- intern/source/shadeinput.c
- intern/source/shadeoutput.c
- intern/source/sss.c
- intern/source/strand.c
- intern/source/sunsky.c
- intern/source/texture_ocean.c
- intern/source/volume_precache.c
- intern/source/volumetric.c
- intern/source/voxeldata.c
intern/source/zbuf.c
extern/include/RE_engine.h
@@ -92,38 +66,12 @@ set(SRC
extern/include/RE_pipeline.h
extern/include/RE_render_ext.h
extern/include/RE_shader_ext.h
- intern/include/envmap.h
intern/include/initrender.h
- intern/include/occlusion.h
- intern/include/pixelblending.h
- intern/include/pixelshading.h
- intern/include/pointdensity.h
- intern/include/raycounter.h
- intern/include/rayobject.h
- intern/include/rayintersection.h
intern/include/render_types.h
intern/include/render_result.h
- intern/include/rendercore.h
- intern/include/renderdatabase.h
intern/include/renderpipeline.h
- intern/include/shadbuf.h
- intern/include/shading.h
- intern/include/sss.h
- intern/include/strand.h
- intern/include/sunsky.h
intern/include/texture.h
- intern/include/texture_ocean.h
- intern/include/volume_precache.h
- intern/include/volumetric.h
- intern/include/voxeldata.h
intern/include/zbuf.h
- intern/raytrace/bvh.h
- intern/raytrace/rayobject_hint.h
- intern/raytrace/rayobject_internal.h
- intern/raytrace/rayobject_rtbuild.h
- intern/raytrace/reorganize.h
- intern/raytrace/svbvh.h
- intern/raytrace/vbvh.h
)
if(WITH_PYTHON)
@@ -148,10 +96,6 @@ if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
-if(WITH_GAMEENGINE)
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h
index ad4d7485acc..e7f446f07a7 100644
--- a/source/blender/render/extern/include/RE_bake.h
+++ b/source/blender/render/extern/include/RE_bake.h
@@ -35,6 +35,7 @@
struct ImBuf;
struct Render;
struct Mesh;
+struct Depsgraph;
typedef struct BakeImage {
struct Image *image;
@@ -71,14 +72,11 @@ typedef struct BakeHighPolyData {
bool RE_bake_has_engine(struct Render *re);
bool RE_bake_engine(
- struct Render *re, struct Object *object, const int object_id, const BakePixel pixel_array[],
+ struct Render *re, struct Depsgraph *depsgraph, struct Object *object, const int object_id, const BakePixel pixel_array[],
const size_t num_pixels, const int depth, const eScenePassType pass_type, const int pass_filter, float result[]);
/* bake.c */
int RE_pass_depth(const eScenePassType pass_type);
-bool RE_bake_internal(
- struct Render *re, struct Object *object, const BakePixel pixel_array[],
- const size_t num_pixels, const int depth, const eScenePassType pass_type, float result[]);
bool RE_bake_pixels_populate_from_objects(
struct Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[],
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index 5c1dc468b8f..faa4c8b3184 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -39,6 +39,10 @@
struct bNode;
struct bNodeTree;
+struct BakePixel;
+struct Depsgraph;
+struct IDProperty;
+struct Main;
struct Object;
struct Render;
struct RenderData;
@@ -48,13 +52,13 @@ struct RenderLayer;
struct RenderResult;
struct ReportList;
struct Scene;
-struct BakePixel;
+struct ViewLayer;
/* External Engine */
/* RenderEngineType.flag */
#define RE_INTERNAL 1
-#define RE_GAME 2
+/* #define RE_FLAG_DEPRECATED 2 */
#define RE_USE_PREVIEW 4
#define RE_USE_POSTPROCESS 8
#define RE_USE_SHADING_NODES 16
@@ -88,15 +92,20 @@ typedef struct RenderEngineType {
char name[64];
int flag;
- void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Scene *scene);
- void (*render)(struct RenderEngine *engine, struct Scene *scene);
- void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const int pass_filter, const int object_id, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result);
+ void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Depsgraph *depsgraph);
+ void (*render)(struct RenderEngine *engine, struct Depsgraph *depsgraph);
+ void (*bake)(struct RenderEngine *engine, struct Depsgraph *depsgraph,
+ struct Object *object, const int pass_type,
+ const int pass_filter, const int object_id, const struct BakePixel *pixel_array, const int num_pixels,
+ const int depth, void *result);
void (*view_update)(struct RenderEngine *engine, const struct bContext *context);
void (*view_draw)(struct RenderEngine *engine, const struct bContext *context);
void (*update_script_node)(struct RenderEngine *engine, struct bNodeTree *ntree, struct bNode *node);
- void (*update_render_passes)(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl);
+ void (*update_render_passes)(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer);
+
+ struct DrawEngineType *draw_engine;
/* RNA integration */
ExtensionRNA ext;
@@ -121,6 +130,9 @@ typedef struct RenderEngine {
struct ReportList *reports;
+ /* Depsgraph */
+ struct Depsgraph *depsgraph;
+
/* for blender internal only */
int update_flag;
int job_update_flag;
@@ -163,18 +175,24 @@ bool RE_engine_is_external(struct Render *re);
void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe);
-void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl,
+void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer,
const char *name, int channels, const char *chanid, int type);
/* Engine Types */
void RE_engines_init(void);
void RE_engines_exit(void);
+void RE_engines_register(RenderEngineType *render_type);
+
+bool RE_engine_is_opengl(RenderEngineType *render_type);
RenderEngineType *RE_engines_find(const char *idname);
rcti* RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free);
struct RenderData *RE_engine_get_render_data(struct Render *re);
-void RE_bake_engine_set_engine_parameters(struct Render *re, struct Main *bmain, struct Scene *scene);
+void RE_bake_engine_set_engine_parameters(
+ struct Render *re, struct Main *bmain, struct Scene *scene);
+
+void RE_engine_free_blender_memory(struct RenderEngine *engine);
#endif /* __RE_ENGINE_H__ */
diff --git a/source/blender/render/extern/include/RE_multires_bake.h b/source/blender/render/extern/include/RE_multires_bake.h
index d3c04b84981..983e95639b4 100644
--- a/source/blender/render/extern/include/RE_multires_bake.h
+++ b/source/blender/render/extern/include/RE_multires_bake.h
@@ -34,8 +34,10 @@
#define __RE_MULTIRES_BAKE_H__
struct MultiresBakeRender;
+struct Scene;
typedef struct MultiresBakeRender {
+ Scene *scene;
DerivedMesh *lores_dm, *hires_dm;
bool simple;
int bake_filter; /* Bake-filter, aka margin */
@@ -43,6 +45,12 @@ typedef struct MultiresBakeRender {
short mode;
bool use_lores_mesh; /* Use low-resolution mesh when baking displacement maps */
+ /* material aligned image array (for per-face bake image) */
+ struct {
+ Image **array;
+ int len;
+ } ob_image;
+
int number_of_rays; /* Number of rays to be cast when doing AO baking */
float bias; /* Bias between object and start ray point when doing AO baking */
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 95c87b52043..614a1735f44 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -34,9 +34,11 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
+#include "DEG_depsgraph.h"
struct bMovieHandle;
struct bNodeTree;
+struct Depsgraph;
struct Image;
struct ImageFormatData;
struct Main;
@@ -46,8 +48,7 @@ struct RenderData;
struct RenderResult;
struct ReportList;
struct Scene;
-struct SceneRenderLayer;
-struct EnvMap;
+struct ViewLayer;
struct StampData;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -105,12 +106,8 @@ typedef struct RenderLayer {
/* copy of RenderData */
char name[RE_MAXNAME];
- unsigned int lay, lay_zmask, lay_exclude;
int layflag, passflag, pass_xor;
- struct Material *mat_override;
- struct Group *light_override;
-
/* MULTIVIEW_TODO: acolrect and scolrect are not supported by multiview at the moment.
* If they are really required they should be in RenderView instead */
@@ -224,6 +221,7 @@ void RE_ReleaseResultImageViews(struct Render *re, struct RenderResult *rr);
void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, const int view_id);
void RE_ReleaseResultImage(struct Render *re);
void RE_SwapResult(struct Render *re, struct RenderResult **rr);
+void RE_ClearResult(struct Render *re);
struct RenderStats *RE_GetStats(struct Render *re);
void RE_ResultGet32(struct Render *re, unsigned int *rect);
@@ -243,7 +241,7 @@ struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layern
/* obligatory initialize call, disprect is optional */
void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd,
- struct SceneRenderLayer *srl,
+ struct ListBase *render_layers, struct ViewLayer *single_layer,
int winx, int winy, rcti *disprect);
void RE_ChangeResolution(struct Render *re, int winx, int winy, rcti *disprect);
void RE_ChangeModeFlag(struct Render *re, int flag, bool clear);
@@ -252,10 +250,8 @@ void RE_ChangeModeFlag(struct Render *re, int flag, bool clear);
struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */
void RE_SetOverrideCamera(struct Render *re, struct Object *camera);
void RE_SetCamera(struct Render *re, struct Object *camera);
-void RE_SetEnvmapCamera(struct Render *re, struct Object *cam_ob, float viewscale, float clipsta, float clipend);
void RE_SetWindow(struct Render *re, const rctf *viewplane, float clipsta, float clipend);
void RE_SetOrtho(struct Render *re, const rctf *viewplane, float clipsta, float clipend);
-void RE_SetPixelSize(struct Render *re, float pixsize);
/* option to set viewmatrix before making dbase */
void RE_SetView(struct Render *re, float mat[4][4]);
@@ -265,23 +261,13 @@ void RE_GetView(struct Render *re, float mat[4][4]);
void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
/* make or free the dbase */
-void RE_Database_FromScene(
+void RE_Database_CameraOnly(
struct Render *re, struct Main *bmain, struct Scene *scene,
- unsigned int lay, int use_camera_view);
-void RE_Database_Preprocess(struct Render *re);
-void RE_Database_Free(struct Render *re);
-
-/* project dbase again, when viewplane/perspective changed */
-void RE_DataBase_ApplyWindow(struct Render *re);
-/* rotate scene again, for incremental render */
-void RE_DataBase_IncrementalView(struct Render *re, float viewmat[4][4], int restore);
+ int use_camera_view);
/* set the render threads based on the commandline and autothreads setting */
void RE_init_threadcount(Render *re);
-/* the main processor, assumes all was set OK! */
-void RE_TileProcessor(struct Render *re);
-
bool RE_WriteRenderViewsImage(
struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, const bool stamp, char *name);
bool RE_WriteRenderViewsMovie(
@@ -291,10 +277,11 @@ bool RE_WriteRenderViewsMovie(
/* only RE_NewRender() needed, main Blender render calls */
void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene,
- struct SceneRenderLayer *srl, struct Object *camera_override,
- unsigned int lay_override, int frame, const bool write_still);
-void RE_BlenderAnim(struct Render *re, struct Main *bmain, struct Scene *scene, struct Object *camera_override,
- unsigned int lay_override, int sfra, int efra, int tfra);
+ struct ViewLayer *single_layer, struct Object *camera_override,
+ int frame, const bool write_still);
+void RE_BlenderAnim(struct Render *re, struct Main *bmain, struct Scene *scene,
+ struct ViewLayer *single_layer, struct Object *camera_override,
+ int sfra, int efra, int tfra);
#ifdef WITH_FREESTYLE
void RE_RenderFreestyleStrokes(struct Render *re, struct Main *bmain, struct Scene *scene, int render);
void RE_RenderFreestyleExternal(struct Render *re);
@@ -316,14 +303,6 @@ bool RE_WriteRenderResult(
struct RenderResult *RE_MultilayerConvert(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
-extern const float default_envmap_layout[];
-bool RE_WriteEnvmapResult(
- struct ReportList *reports, struct Scene *scene, struct EnvMap *env,
- const char *relpath, const char imtype, float layout[12]);
-
-/* do a full sample buffer compo */
-void RE_MergeFullSample(struct Render *re, struct Main *bmain, struct Scene *sce, struct bNodeTree *ntree);
-
/* display and event callbacks */
void RE_display_init_cb (struct Render *re, void *handle, void (*f)(void *handle, RenderResult *rr));
void RE_display_clear_cb(struct Render *re, void *handle, void (*f)(void *handle, RenderResult *rr));
@@ -334,6 +313,11 @@ void RE_draw_lock_cb (struct Render *re, void *handle, void (*f)(void *handle,
void RE_test_break_cb (struct Render *re, void *handle, int (*f)(void *handle));
void RE_current_scene_update_cb(struct Render *re, void *handle, void (*f)(void *handle, struct Scene *scene));
+void RE_gl_context_create(Render *re);
+void RE_gl_context_destroy(Render *re);
+void *RE_gl_context_get(Render *re);
+void *RE_gpu_context_get(Render *re);
+
/* should move to kernel once... still unsure on how/where */
float RE_filter_value(int type, float x);
@@ -346,43 +330,20 @@ struct RenderPass *RE_pass_find_by_name(volatile struct RenderLayer *rl, const c
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname);
/* shaded view or baking options */
-#define RE_BAKE_LIGHT 0 /* not listed in rna_scene.c -> can't be enabled! */
-#define RE_BAKE_ALL 1
+#define RE_BAKE_NORMALS 0
+#define RE_BAKE_DISPLACEMENT 1
#define RE_BAKE_AO 2
-#define RE_BAKE_NORMALS 3
-#define RE_BAKE_TEXTURE 4
-#define RE_BAKE_DISPLACEMENT 5
-#define RE_BAKE_SHADOW 6
-#define RE_BAKE_SPEC_COLOR 7
-#define RE_BAKE_SPEC_INTENSITY 8
-#define RE_BAKE_MIRROR_COLOR 9
-#define RE_BAKE_MIRROR_INTENSITY 10
-#define RE_BAKE_ALPHA 11
-#define RE_BAKE_EMIT 12
-#define RE_BAKE_DERIVATIVE 13
-#define RE_BAKE_VERTEX_COLORS 14
-
-void RE_Database_Baking(
- struct Render *re, struct Main *bmain, struct Scene *scene,
- unsigned int lay, const int type, struct Object *actob);
-void RE_DataBase_GetView(struct Render *re, float mat[4][4]);
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]);
+void RE_GetCameraWindowWithOverscan(struct Render *re, float mat[4][4], float overscan);
void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_mat[4][4]);
struct Scene *RE_GetScene(struct Render *re);
+void RE_SetScene(struct Render *re, struct Scene *sce);
-bool RE_force_single_renderlayer(struct Scene *scene);
-bool RE_is_rendering_allowed(struct Scene *scene, struct Object *camera_override, struct ReportList *reports);
+bool RE_is_rendering_allowed(struct Scene *scene, struct ViewLayer *single_layer, struct Object *camera_override, struct ReportList *reports);
bool RE_allow_render_generic_object(struct Object *ob);
-/* RE_updateRenderInstances flag */
-enum {
- RE_OBJECT_INSTANCES_UPDATE_VIEW = (1 << 0),
- RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1)
-};
-void RE_updateRenderInstances(Render *re, int flag);
-
/******* defined in render_result.c *********/
bool RE_HasCombinedLayer(RenderResult *res);
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index 6bd40746773..dad88cf06fa 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -37,10 +37,12 @@
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* called by meshtools */
-struct DerivedMesh;
+struct Depsgraph;
struct ImagePool;
struct MTex;
struct Scene;
+struct ViewLayer;
+struct Render;
/* render_texture.c */
/* used by particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
@@ -53,12 +55,6 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
void RE_texture_rng_init(void);
void RE_texture_rng_exit(void);
-struct Material *RE_sample_material_init(struct Material *orig_mat, struct Scene *scene);
-void RE_sample_material_free(struct Material *mat);
-void RE_sample_material_color(
- struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
- int tri_index, struct DerivedMesh *orcoDm, struct Object *ob);
-
/* imagetexture.c */
void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]);
@@ -66,23 +62,22 @@ void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, flo
struct PointDensity;
void RE_point_density_cache(
- struct Scene *scene,
- struct PointDensity *pd,
- const bool use_render_params);
+ struct Depsgraph *depsgraph,
+ struct PointDensity *pd);
void RE_point_density_minmax(
- struct Scene *scene,
+ struct Depsgraph *depsgraph,
struct PointDensity *pd,
- const bool use_render_params,
float r_min[3], float r_max[3]);
void RE_point_density_sample(
- struct Scene *scene,
+ struct Depsgraph *depsgraph,
struct PointDensity *pd,
const int resolution,
- const bool use_render_params,
float *values);
void RE_point_density_free(struct PointDensity *pd);
+void RE_point_density_fix_linking(void);
+
#endif /* __RE_RENDER_EXT_H__ */
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 838f7031d14..52d4961352d 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -33,7 +33,7 @@
#define __RE_SHADER_EXT_H__
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* this include is for shading and texture exports */
+/* this include is for texture exports */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* localized texture result data */
@@ -44,150 +44,6 @@ typedef struct TexResult {
float *nor;
} TexResult;
-/* localized shade result data */
-typedef struct ShadeResult {
- float combined[4];
- float col[4];
- float alpha, mist, z;
- float emit[3];
- float diff[3]; /* diffuse with no ramps, shadow, etc */
- float diffshad[3]; /* diffuse with shadow */
- float spec[3]; /* specular with shadow */
- float shad[4]; /* shad[3] is shadow intensity */
- float ao[3];
- float env[3];
- float indirect[3];
- float refl[3];
- float refr[3];
- float nor[3];
- float winspeed[4];
- float rayhits[4];
-} ShadeResult;
-
-/* only here for quick copy */
-struct ShadeInputCopy {
-
- struct Material *mat;
- struct VlakRen *vlr;
- struct StrandRen *strand;
- struct ObjectInstanceRen *obi;
- struct ObjectRen *obr;
- int facenr;
- float facenor[3]; /* copy from face */
- short flippednor; /* is facenor flipped? */
- struct VertRen *v1, *v2, *v3; /* vertices can be in any order for quads... */
- short i1, i2, i3; /* original vertex indices */
- short puno;
- short osatex;
- float vn[3], vno[3]; /* actual render normal, and a copy to restore it */
- float n1[3], n2[3], n3[3]; /* vertex normals, corrected */
- int mode, mode2; /* base material mode (OR-ed result of entire node tree) */
-};
-
-typedef struct ShadeInputUV {
- float dxuv[3], dyuv[3], uv[3];
- const char *name;
-} ShadeInputUV;
-
-typedef struct ShadeInputCol {
- float col[4];
- const char *name;
-} ShadeInputCol;
-
-/* localized renderloop data */
-typedef struct ShadeInput {
- /* copy from face, also to extract tria from quad */
- /* note it mirrors a struct above for quick copy */
-
- struct Material *mat;
- struct VlakRen *vlr;
- struct StrandRen *strand;
- struct ObjectInstanceRen *obi;
- struct ObjectRen *obr;
- int facenr;
- float facenor[3]; /* copy from face */
- short flippednor; /* is facenor flipped? */
- struct VertRen *v1, *v2, *v3; /* vertices can be in any order for quads... */
- short i1, i2, i3; /* original vertex indices */
- short puno;
- short osatex;
- float vn[3], vno[3]; /* actual render normal, and a copy to restore it */
- float n1[3], n2[3], n3[3]; /* vertex normals, corrected */
- int mode, mode2; /* base material mode (OR-ed result of entire node tree) */
-
- /* internal face coordinates */
- float u, v, dx_u, dx_v, dy_u, dy_v;
- float co[3], view[3], camera_co[3];
-
- /* copy from material, keep synced so we can do memcopy */
- /* current size: 23*4 */
- float r, g, b;
- float specr, specg, specb;
- float mirr, mirg, mirb;
- float ambr, ambb, ambg;
-
- float amb, emit, ang, spectra, ray_mirror;
- float alpha, refl, spec, zoffs, add;
- float translucency;
- /* end direct copy from material */
-
- /* individual copies: */
- int har; /* hardness */
-
- /* texture coordinates */
- float lo[3], gl[3], ref[3], orn[3], winco[3], vcol[4];
- float refcol[4], displace[3];
- float strandco, tang[3], nmapnorm[3], nmaptang[4], stress, winspeed[4];
- float duplilo[3], dupliuv[3];
- float tangents[8][4]; /* 8 = MAX_MTFACE */
-
- ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */
- ShadeInputCol col[8]; /* 8 = MAX_MCOL */
- int totuv, totcol, actuv, actcol;
-
- /* dx/dy OSA coordinates */
- float dxco[3], dyco[3];
- float dxlo[3], dylo[3], dxgl[3], dygl[3];
- float dxref[3], dyref[3], dxorn[3], dyorn[3];
- float dxno[3], dyno[3], dxview, dyview;
- float dxlv[3], dylv[3];
- float dxwin[3], dywin[3];
- float dxrefract[3], dyrefract[3];
- float dxstrand, dystrand;
-
- /* AO is a pre-process now */
- float ao[3], indirect[3], env[3];
-
- int xs, ys; /* pixel to be rendered */
- int mask; /* subsample mask */
- float scanco[3]; /* original scanline coordinate without jitter */
-
- int samplenr; /* sample counter, to detect if we should do shadow again */
- int depth; /* 1 or larger on raytrace shading */
- int volume_depth; /* number of intersections through volumes */
-
- /* for strand shading, normal at the surface */
- float surfnor[3], surfdist;
-
- /* from initialize, part or renderlayer */
- bool do_preview; /* for nodes, in previewrender */
- bool do_manage; /* color management flag */
- bool use_world_space_shading;
- short thread, sample; /* sample: ShadeSample array index */
- short nodes; /* indicate node shading, temp hack to prevent recursion */
-
- unsigned int lay;
- int layflag, passflag, combinedflag;
- short object_pass_index;
- struct Group *light_override;
- struct Material *mat_override;
-
-#ifdef RE_RAYCOUNTER
- RayCounter raycounter;
-#endif
-
-} ShadeInput;
-
typedef struct BakeImBufuserData {
float *displacement_buffer;
char *mask_buffer;
@@ -214,46 +70,6 @@ int multitex_ext(struct Tex *tex,
int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image);
/* only for internal node usage */
int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres,
- const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex,
- struct ImagePool *pool);
-float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]);
-void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]);
-
-float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta);
-
-/* shaded view and bake */
-struct Render;
-struct Image;
-
-int RE_bake_shade_all_selected(struct Render *re, int type, struct Object *actob, short *do_update, float *progress);
-struct Image *RE_bake_shade_get_image(void);
-void RE_bake_ibuf_filter(struct ImBuf *ibuf, char *mask, const int filter);
-void RE_bake_ibuf_normalize_displacement(struct ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max);
-float RE_bake_make_derivative(struct ImBuf *ibuf, float *heights_buffer, const char *mask,
- const float height_min, const float height_max,
- const float fmult);
-
-enum {
- RE_OBJECT_INSTANCE_MATRIX_OB,
- RE_OBJECT_INSTANCE_MATRIX_OBINV,
- RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW,
- RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV,
-};
-
-const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4];
-
-float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi);
-float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi);
-
-enum {
- RE_VIEW_MATRIX,
- RE_VIEWINV_MATRIX,
-};
-
-const float (*RE_render_current_get_matrix(int matrix_id))[4];
-
-#define BAKE_RESULT_OK 0
-#define BAKE_RESULT_NO_OBJECTS 1
-#define BAKE_RESULT_FEEDBACK_LOOP 2
+ const short thread, short which_output, struct MTex *mtex, struct ImagePool *pool);
#endif /* __RE_SHADER_EXT_H__ */
diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h
index 36773b4c73e..22a2176e16c 100644
--- a/source/blender/render/intern/include/initrender.h
+++ b/source/blender/render/intern/include/initrender.h
@@ -33,15 +33,10 @@
#ifndef __INITRENDER_H__
#define __INITRENDER_H__
-
/* Functions */
-void free_sample_tables(Render *re);
-void make_sample_tables(Render *re);
-
-void RE_parts_init(Render *re, bool do_crop);
+void RE_parts_init(Render *re);
void RE_parts_free(Render *re);
void RE_parts_clamp(Render *re);
-
#endif /* __INITRENDER_H__ */
diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h
deleted file mode 100644
index 022510c7132..00000000000
--- a/source/blender/render/intern/include/pixelblending.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): 2004-2006 Blender Foundation, full recode
- *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/pixelblending.h
- * \ingroup render
- */
-
-
-#ifndef __PIXELBLENDING_H__
-#define __PIXELBLENDING_H__
-
-
-/**
- * add 1 pixel to into filtered three lines
- * (float vecs to float vec)
- */
-void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w);
-void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize);
-void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask);
-void mask_array(unsigned int mask, float filt[3][3]);
-
-/**
- * Alpha-over blending for floats.
- */
-void addAlphaOverFloat(float dest[4], const float source[4]);
-
-/**
- * Alpha-under blending for floats.
- */
-void addAlphaUnderFloat(float dest[4], const float source[4]);
-
-
-/**
- * Same for floats
- */
-void addalphaAddfacFloat(float dest[4], const float source[4], char addfac);
-
-/**
- * dest = dest + source
- */
-void addalphaAddFloat(float dest[4], const float source[4]);
-
-#endif /* __PIXELBLENDING_H__ */
diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h
deleted file mode 100644
index ff4f705a617..00000000000
--- a/source/blender/render/intern/include/pixelshading.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): 2004-2006, Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/pixelshading.h
- * \ingroup render
- *
- * These functions determine what actual color a pixel will have.
- */
-
-#ifndef __PIXELSHADING_H__
-#define __PIXELSHADING_H__
-
-
-/**
- * Render the pixel at (x,y) for object ap. Apply the jitter mask.
- * Output is given in float collector[4]. The type vector:
- * t[0] - min. distance
- * t[1] - face/halo index
- * t[2] - jitter mask
- * t[3] - type ZB_POLY or ZB_HALO
- * t[4] - max. distance
- * mask is pixel coverage in bits
- * \return pointer to the object
- */
-int shadeHaloFloat(HaloRen *har,
- float *col, int zz,
- float dist, float xn,
- float yn, short flarec);
-
-/**
- * Render the sky at pixel (x, y).
- */
-void shadeSkyPixel(float collector[4], float fx, float fy, short thread);
-void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread);
-void shadeAtmPixel(struct SunSky *sunsky, float *collector, float fx, float fy, float distance);
-void shadeSunView(float col_r[3], const float view[3]);
-/* ------------------------------------------------------------------------- */
-
-#endif
diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h
deleted file mode 100644
index 18289d009d5..00000000000
--- a/source/blender/render/intern/include/pointdensity.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/pointdensity.h
- * \ingroup render
- */
-
-
-#ifndef __POINTDENSITY_H__
-#define __POINTDENSITY_H__
-
-/**
- * Make point density kd-trees for all point density textures in the scene
- */
-
-struct PointDensity;
-struct Render;
-struct TexResult;
-
-void free_pointdensity(struct PointDensity *pd);
-void cache_pointdensity(struct Render *re, struct PointDensity *pd);
-void make_pointdensities(struct Render *re);
-void free_pointdensities(struct Render *re);
-int pointdensitytex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
-
-#endif /* __POINTDENSITY_H__ */
diff --git a/source/blender/render/intern/include/raycounter.h b/source/blender/render/intern/include/raycounter.h
deleted file mode 100644
index e16c6e13c7e..00000000000
--- a/source/blender/render/intern/include/raycounter.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/raycounter.h
- * \ingroup render
- */
-
-
-#ifndef __RAYCOUNTER_H__
-#define __RAYCOUNTER_H__
-
-//#define RE_RAYCOUNTER /* enable counters per ray, useful for measuring raytrace structures performance */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef RE_RAYCOUNTER
-
-/* ray counter functions */
-
-typedef struct RayCounter {
- struct {
- unsigned long long test, hit;
- } faces, bb, simd_bb, raycast, raytrace_hint, rayshadow_last_hit;
-} RayCounter;
-
-#define RE_RC_INIT(isec, shi) (isec).raycounter = &((shi).shading.raycounter)
-void RE_RC_INFO(RayCounter *rc);
-void RE_RC_MERGE(RayCounter *rc, RayCounter *tmp);
-#define RE_RC_COUNT(var) (var)++
-
-extern RayCounter re_rc_counter[];
-
-#else
-
-/* ray counter stubs */
-
-#define RE_RC_INIT(isec,shi)
-#define RE_RC_INFO(rc)
-#define RE_RC_MERGE(dest,src)
-#define RE_RC_COUNT(var)
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h
deleted file mode 100644
index aab511d6191..00000000000
--- a/source/blender/render/intern/include/rayintersection.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * ***** 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) 2007 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- * RE_raytrace.h: ray tracing api, can be used independently from the renderer.
- */
-
-/** \file blender/render/intern/include/rayintersection.h
- * \ingroup render
- */
-
-
-#ifndef __RAYINTERSECTION_H__
-#define __RAYINTERSECTION_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "BLI_math_geom.h"
-
-struct RayObject;
-
-/* Ray Hints */
-
-#define RE_RAY_LCTS_MAX_SIZE 256
-#define RT_USE_LAST_HIT /* last shadow hit is reused before raycasting on whole tree */
-//#define RT_USE_HINT /* last hit object is reused before raycasting on whole tree */
-
-typedef struct LCTSHint {
- int size;
- struct RayObject *stack[RE_RAY_LCTS_MAX_SIZE];
-} LCTSHint;
-
-typedef struct RayHint {
- union { LCTSHint lcts; } data;
-} RayHint;
-
-/* Ray Intersection */
-
-typedef struct Isect {
- /* ray start, direction (normalized vector), and max distance. on hit,
- * the distance is modified to be the distance to the hit point. */
- float start[3];
- float dir[3];
- float dist;
-
- /* for envmap and incremental view update renders */
- float origstart[3];
- float origdir[3];
-
- /* precomputed values to accelerate bounding box intersection */
- int bv_index[6];
- float idot_axis[3];
-
- /* intersection options */
- int mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
- int lay; /* -1 default, set for layer lamps */
- int skip; /* skip flags */
- int check; /* check flags */
- void *userdata; /* used by bake check */
-
- /* hit information */
- float u, v;
- int isect; /* which half of quad */
-
- struct {
- void *ob;
- void *face;
- } hit, orig;
-
- /* last hit optimization */
- struct RayObject *last_hit;
-
- /* hints */
-#ifdef RT_USE_HINT
- RayTraceHint *hint, *hit_hint;
-#endif
- RayHint *hint;
-
- /* ray counter */
-#ifdef RE_RAYCOUNTER
- RayCounter *raycounter;
-#endif
-
- /* Precalculated coefficients for watertight intersection check. */
- struct IsectRayPrecalc isect_precalc;
-} Isect;
-
-/* ray types */
-#define RE_RAY_SHADOW 0
-#define RE_RAY_MIRROR 1
-#define RE_RAY_SHADOW_TRA 2
-
-/* skip options */
-#define RE_SKIP_CULLFACE (1 << 0)
-/* if using this flag then *face should be a pointer to a VlakRen */
-#define RE_SKIP_VLR_NEIGHBOUR (1 << 1)
-
-/* check options */
-#define RE_CHECK_VLR_NONE 0
-#define RE_CHECK_VLR_RENDER 1
-#define RE_CHECK_VLR_NON_SOLID_MATERIAL 2
-#define RE_CHECK_VLR_BAKE 3
-
-/* arbitrary, but can't use e.g. FLT_MAX because of precision issues */
-#define RE_RAYTRACE_MAXDIST 1e15f
-#define RE_RAYTRACE_EPSILON 0.0f
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RAYINTERSECTION_H__ */
diff --git a/source/blender/render/intern/include/rayobject.h b/source/blender/render/intern/include/rayobject.h
deleted file mode 100644
index 4042d183e5f..00000000000
--- a/source/blender/render/intern/include/rayobject.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/rayobject.h
- * \ingroup render
- */
-
-
-#ifndef __RAYOBJECT_H__
-#define __RAYOBJECT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct Isect;
-struct ObjectInstanceRen;
-struct RayHint;
-struct VlakRen;
-
-/* RayObject
- * Can be a face/triangle, bvh tree, object instance, etc. This is the
- * public API used by the renderer, see rayobject_internal.h for the
- * internal implementation details.
- * */
-typedef struct RayObject RayObject;
-
-/* Intersection, see rayintersection.h */
-
-int RE_rayobject_raycast(RayObject *r, struct Isect *i);
-
-/* Acceleration Structures */
-
-RayObject *RE_rayobject_octree_create(int ocres, int size);
-RayObject *RE_rayobject_instance_create(RayObject *target, float transform[4][4], void *ob, void *target_ob);
-RayObject *RE_rayobject_empty_create(void);
-
-RayObject *RE_rayobject_vbvh_create(int size); /* raytrace/rayobject_vbvh.c */
-RayObject *RE_rayobject_svbvh_create(int size); /* raytrace/rayobject_svbvh.c */
-RayObject *RE_rayobject_qbvh_create(int size); /* raytrace/rayobject_qbvh.c */
-
-/* Building */
-
-void RE_rayobject_add(RayObject *r, RayObject *);
-void RE_rayobject_done(RayObject *r);
-void RE_rayobject_free(RayObject *r);
-
-void RE_rayobject_set_control(RayObject *r, void *data, int (*test_break)(void *data));
-
-/* RayObject representing faces, all data is locally available instead
- * of referring to some external data structure, for possibly faster
- * intersection tests. */
-
-typedef struct RayFace {
- float v1[4], v2[4], v3[4], v4[3];
- int quad;
- void *ob;
- void *face;
-} RayFace;
-
-#define RE_rayface_isQuad(a) ((a)->quad)
-
-RayObject *RE_rayface_from_vlak(RayFace *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
-
-RayObject *RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4);
-
-/* RayObject representing faces directly from a given VlakRen structure. Thus
- * allowing to save memory, but making code triangle intersection dependent on
- * render structures. */
-
-typedef struct VlakPrimitive {
- struct ObjectInstanceRen *ob;
- struct VlakRen *face;
-} VlakPrimitive;
-
-RayObject *RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
-
-/* Bounding Box */
-
-/* extend min/max coords so that the rayobject is inside them */
-void RE_rayobject_merge_bb(RayObject *ob, float *min, float *max);
-
-/* initializes an hint for optimizing raycast where it is know that a ray will pass by the given BB often the origin point */
-void RE_rayobject_hint_bb(RayObject *r, struct RayHint *hint, float min[3], float max[3]);
-
-/* initializes an hint for optimizing raycast where it is know that a ray will be contained inside the given cone*/
-/* void RE_rayobject_hint_cone(RayObject *r, struct RayHint *hint, float *); */
-
-/* Internals */
-
-#include "../raytrace/rayobject_internal.h"
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 7713c9c7fba..ab7eee128f0 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -55,8 +55,6 @@ struct ColorManagedViewSettings;
struct RenderResult *render_result_new(struct Render *re,
struct rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname);
-struct RenderResult *render_result_new_full_sample(struct Render *re,
- struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers, const char *viewname);
struct RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
@@ -117,4 +115,27 @@ void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResu
void render_result_views_shallowdelete(struct RenderResult *rr);
bool render_result_has_views(struct RenderResult *rr);
+#define FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re_, iter_) \
+{ \
+ int nr_; \
+ ViewLayer *iter_; \
+ for (nr_ = 0, iter_ = (re_)->view_layers.first; \
+ iter_ != NULL; \
+ iter_ = iter_->next, nr_++) \
+ { \
+ if (!G.background && (re_)->r.scemode & R_SINGLE_LAYER) { \
+ if (nr_ != re->active_view_layer) { \
+ continue; \
+ } \
+ } \
+ else { \
+ if ((iter_->flag & VIEW_LAYER_RENDER) == 0) { \
+ continue; \
+ } \
+ }
+
+#define FOREACH_VIEW_LAYER_TO_RENDER_END \
+ } \
+} ((void)0)
+
#endif /* __RENDER_RESULT_H__ */
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 64e6aa54a9e..1467f8d9804 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -35,58 +35,19 @@
/* exposed internal in render module only! */
/* ------------------------------------------------------------------------- */
-#include "DNA_color_types.h"
-#include "DNA_customdata_types.h"
#include "DNA_scene_types.h"
-#include "DNA_world_types.h"
#include "DNA_object_types.h"
-#include "DNA_vec_types.h"
#include "BLI_threads.h"
#include "BKE_main.h"
#include "RE_pipeline.h"
-#include "RE_shader_ext.h" /* TexResult, ShadeResult, ShadeInput */
-#include "sunsky.h"
-#include "BLI_sys_types.h" // for intptr_t support
-
-struct EvaluationContext;
struct Object;
-struct MemArena;
-struct VertTableNode;
-struct VlakTableNode;
-struct GHash;
-struct ObjectInstanceRen;
-struct RayObject;
-struct RayFace;
struct RenderEngine;
struct ReportList;
struct Main;
-struct ImagePool;
-
-#define TABLEINITSIZE 1024
-
-typedef struct SampleTables {
- float centLut[16];
- float *fmask1[9], *fmask2[9];
- char cmask[256], *centmask;
-
-} SampleTables;
-
-typedef struct QMCSampler {
- struct QMCSampler *next, *prev;
- int type;
- int tot;
- int used;
- double *samp2d;
- double offs[BLENDER_MAX_THREADS][2];
-} QMCSampler;
-
-// #define SAMP_TYPE_JITTERED 0 // UNUSED
-#define SAMP_TYPE_HALTON 1
-#define SAMP_TYPE_HAMMERSLEY 2
/* this is handed over to threaded hiding/passes/shading engine */
typedef struct RenderPart {
@@ -95,24 +56,10 @@ typedef struct RenderPart {
RenderResult *result; /* result of part rendering */
ListBase fullresult; /* optional full sample buffers */
- int *recto; /* object table for objects */
- int *rectp; /* polygon index table */
- int *rectz; /* zbuffer */
- int *rectmask; /* negative zmask */
- intptr_t *rectdaps; /* delta acum buffer for pixel structs */
- int *rectbacko; /* object table for backside sss */
- int *rectbackp; /* polygon index table for backside sss */
- int *rectbackz; /* zbuffer for backside sss */
- intptr_t *rectall; /* buffer for all faces for sss */
-
rcti disprect; /* part coordinates within total picture */
int rectx, recty; /* the size */
int nr; /* nr is partnr */
- short crop, status; /* crop is amount of pixels we crop, for filter */
- short sample; /* sample can be used by zbuffers */
- short thread; /* thread id */
-
- char *clipflag; /* clipflags for part zbuffering */
+ short status;
} RenderPart;
enum {
@@ -129,10 +76,7 @@ struct Render {
int slot;
/* state settings */
- short flag, osa, ok, result_ok;
-
- /* due to performance issues, getting initialized from color management settings once on Render initialization */
- bool scene_color_manage;
+ short flag, ok, result_ok;
/* result of rendering */
RenderResult *result;
@@ -150,8 +94,6 @@ struct Render {
* without border & crop. convert to long before multiplying together to avoid overflow. */
rcti disprect; /* part within winx winy */
rctf viewplane; /* mapped on winx winy */
- float viewdx, viewdy; /* size of 1 pixel */
- float clipcrop; /* 2 pixel boundary to prevent clip when filter used */
/* final picture width and height (within disprect) */
int rectx, recty;
@@ -160,14 +102,7 @@ struct Render {
* partx*xparts can be larger than rectx, in that case last part is smaller */
int partx, party;
- /* values for viewing */
- float ycor; /* (scene->xasp / scene->yasp), multiplied with 'winy' */
-
- float panophi, panosi, panoco, panodxp, panodxv;
-
- /* Matrices */
- float grvec[3]; /* for world */
- float imat[3][3]; /* copy of viewinv */
+ /* Camera transform, only used by Freestyle. */
float viewmat[4][4], viewinv[4][4];
float viewmat_orig[4][4]; /* for incremental render */
float winmat[4][4];
@@ -176,23 +111,13 @@ struct Render {
float clipsta;
float clipend;
- /* samples */
- SampleTables *samples;
- float jit[32][2];
- float mblur_jit[32][2];
- ListBase *qmcsamplers;
- int num_qmc_samplers;
-
- /* shadow counter, detect shadow-reuse for shaders */
- int shadowsamplenr[BLENDER_MAX_THREADS];
-
/* main, scene, and its full copy of renderdata and world */
struct Main *main;
Scene *scene;
RenderData r;
- World wrld;
+ ListBase view_layers;
+ int active_view_layer;
struct Object *camera_override;
- unsigned int lay, layer_override;
ThreadRWMutex partsmutex;
ListBase parts;
@@ -200,56 +125,11 @@ struct Render {
/* render engine */
struct RenderEngine *engine;
- /* octree tables and variables for raytrace */
- struct RayObject *raytree;
- struct RayFace *rayfaces;
- struct VlakPrimitive *rayprimitives;
- float maxdist; /* needed for keeping an incorrect behavior of SUN and HEMI lights (avoid breaking old scenes) */
-
- /* occlusion tree */
- void *occlusiontree;
- ListBase strandsurface;
-
- /* use this instead of R.r.cfra */
- float mblur_offs, field_offs;
-
- /* render database */
- int totvlak, totvert, tothalo, totstrand, totlamp;
- struct HaloRen **sortedhalos;
-
- ListBase lights; /* GroupObject pointers */
- ListBase lampren; /* storage, for free */
-
- ListBase objecttable;
-
- struct ObjectInstanceRen *objectinstance;
- ListBase instancetable;
- int totinstance;
-
- struct Image *bakebuf;
-
- struct GHash *orco_hash;
-
- struct GHash *sss_hash;
- ListBase *sss_points;
- struct Material *sss_mat;
-
- ListBase customdata_names;
-
- struct Object *excludeob;
- ListBase render_volumes_inside;
- ListBase volumes;
-
#ifdef WITH_FREESTYLE
struct Main *freestyle_bmain;
ListBase freestyle_renders;
#endif
- /* arena for allocating data for use during render, for
- * example dynamic TFaces to go in the VlakRen structure.
- */
- struct MemArena *memArena;
-
/* callbacks */
void (*display_init)(void *handle, RenderResult *rr);
void *dih;
@@ -274,414 +154,17 @@ struct Render {
struct ReportList *reports;
- struct ImagePool *pool;
- struct EvaluationContext *eval_ctx;
-
void **movie_ctx_arr;
char viewname[MAX_NAME];
-};
-
-/* ------------------------------------------------------------------------- */
-
-struct ISBData;
-
-typedef struct DeepSample {
- int z;
- float v;
-} DeepSample;
-
-typedef struct ShadSampleBuf {
- struct ShadSampleBuf *next, *prev;
- intptr_t *zbuf;
- char *cbuf;
- DeepSample **deepbuf;
- int *totbuf;
-} ShadSampleBuf;
-
-typedef struct ShadBuf {
- /* regular shadowbuffer */
- short samp, shadhalostep, totbuf;
- float persmat[4][4];
- float viewmat[4][4];
- float winmat[4][4];
- float *jit, *weight;
- float d, clipend, pixsize, soft, compressthresh;
- int co[3];
- int size, bias;
- ListBase buffers;
-
- /* irregular shadowbufer, result stored per thread */
- struct ISBData *isb_result[BLENDER_MAX_THREADS];
-} ShadBuf;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct ObjectRen {
- struct ObjectRen *next, *prev;
- struct Object *ob, *par;
- struct Scene *sce;
- int index, psysindex, flag, lay;
-
- float boundbox[2][3];
-
- int totvert, totvlak, totstrand, tothalo;
- int vertnodeslen, vlaknodeslen, strandnodeslen, blohalen;
- struct VertTableNode *vertnodes;
- struct VlakTableNode *vlaknodes;
- struct StrandTableNode *strandnodes;
- struct HaloRen **bloha;
- struct StrandBuffer *strandbuf;
-
- char (*mtface)[MAX_CUSTOMDATA_LAYER_NAME];
- char (*mcol)[MAX_CUSTOMDATA_LAYER_NAME];
- int actmtface, actmcol, bakemtface;
-
- short tangent_mask; /* which tangent layer should be calculated */
-
- float obmat[4][4]; /* only used in convertblender.c, for instancing */
-
- /* used on makeraytree */
- struct RayObject *raytree;
- struct RayFace *rayfaces;
- struct VlakPrimitive *rayprimitives;
- struct ObjectInstanceRen *rayobi;
-
-} ObjectRen;
-
-typedef struct ObjectInstanceRen {
- struct ObjectInstanceRen *next, *prev;
-
- ObjectRen *obr;
- Object *ob, *par;
- int index, psysindex, lay;
-
- float mat[4][4], imat[4][4];
- float nmat[3][3]; /* nmat is inverse mat tranposed */
-
- float obmat[4][4], obinvmat[4][4];
- float localtoviewmat[4][4], localtoviewinvmat[4][4];
-
- short flag;
- float dupliorco[3], dupliuv[2];
- float (*duplitexmat)[4];
-
- struct VolumePrecache *volume_precache;
-
- float *vectors; /* (RE_WINSPEED_ELEMS * VertRen.index) */
- int totvector;
-
- /* used on makeraytree */
- struct RayObject *raytree;
- int transform_primitives;
-
- /* Particle info */
- float part_index;
- float part_age;
- float part_lifetime;
- float part_size;
- float part_co[3];
- float part_vel[3];
- float part_avel[3];
-
- unsigned int random_id;
-} ObjectInstanceRen;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct VertRen {
- float co[3];
- float n[3];
- float *orco;
- unsigned int flag; /* in use for clipping zbuffer parts, temp setting stuff in convertblender.c
- * only an 'int' because of alignment, could be a char too */
- float accum; /* accum for radio weighting, and for strand texco static particles */
- int index; /* index allows extending vertren with any property */
-} VertRen;
-
-/* ------------------------------------------------------------------------- */
-
-struct halosort {
- struct HaloRen *har;
- int z;
+ /* TODO replace by a whole draw manager. */
+ void *gl_context;
+ void *gpu_context;
};
-/* ------------------------------------------------------------------------- */
-struct Material;
-struct ImagePool;
-
-typedef struct RadFace {
- float unshot[3], totrad[3];
- float norm[3], cent[3], area;
- int flag;
-} RadFace;
-
-typedef struct VlakRen {
- struct VertRen *v1, *v2, *v3, *v4; /* keep in order for ** addressing */
- float n[3];
- struct Material *mat;
- char puno;
- char flag, ec;
-#ifdef WITH_FREESTYLE
- char freestyle_edge_mark;
- char freestyle_face_mark;
-#endif
- int index;
-} VlakRen;
-
-typedef struct HaloRen {
- short miny, maxy;
- float alfa, xs, ys, rad, radsq, sin, cos, co[3], no[3];
- float hard, b, g, r;
- int zs, zd;
- int zBufDist; /* depth in the z-buffer coordinate system */
- char starpoints, type, add, tex;
- char linec, ringc, seed;
- short flarec; /* used to be a char. why ?*/
- float hasize;
- int pixels;
- unsigned int lay;
- struct Material *mat;
- struct ImagePool *pool;
- bool skip_load_image, texnode_preview;
-} HaloRen;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct StrandVert {
- float co[3];
- float strandco;
-} StrandVert;
-
-typedef struct StrandSurface {
- struct StrandSurface *next, *prev;
- ObjectRen obr;
- int (*face)[4];
- float (*co)[3];
- /* for occlusion caching */
- float (*ao)[3];
- float (*env)[3];
- float (*indirect)[3];
- /* for speedvectors */
- float (*prevco)[3], (*nextco)[3];
- int totvert, totface;
-} StrandSurface;
-
-typedef struct StrandBound {
- int start, end;
- float boundbox[2][3];
-} StrandBound;
-
-typedef struct StrandBuffer {
- struct StrandBuffer *next, *prev;
- struct StrandVert *vert;
- struct StrandBound *bound;
- int totvert, totbound;
-
- struct ObjectRen *obr;
- struct Material *ma;
- struct StrandSurface *surface;
- unsigned int lay;
- int overrideuv;
- int flag, maxdepth;
- float adaptcos, minwidth, widthfade;
-
- float maxwidth; /* for cliptest of strands in blender unit */
-
- float winmat[4][4];
- int winx, winy;
-} StrandBuffer;
-
-typedef struct StrandRen {
- StrandVert *vert;
- StrandBuffer *buffer;
- int totvert, flag;
- int clip, index;
- float orco[3];
-} StrandRen;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct VolumeOb {
- struct VolumeOb *next, *prev;
- struct Material *ma;
- struct ObjectRen *obr;
-} VolumeOb;
-
-typedef struct MatInside {
- struct MatInside *next, *prev;
- struct Material *ma;
- struct ObjectInstanceRen *obi;
-} MatInside;
-
-typedef struct VolPrecachePart {
- struct VolPrecachePart *next, *prev;
- struct RayObject *tree;
- struct ShadeInput *shi;
- struct ObjectInstanceRen *obi;
- float viewmat[4][4];
- int num;
- int minx, maxx;
- int miny, maxy;
- int minz, maxz;
- int res[3];
- float bbmin[3];
- float voxel[3];
- struct Render *re;
-} VolPrecachePart;
-
-typedef struct VolumePrecache {
- int res[3];
- float *bbmin, *bbmax;
- float *data_r;
- float *data_g;
- float *data_b;
-} VolumePrecache;
-
-/* ------------------------------------------------------------------------- */
-
-struct LampRen;
-struct MTex;
-
-/**
- * For each lamp in a scene, a LampRen is created. It determines the
- * properties of a lightsource.
- */
-
-typedef struct LampShadowSubSample {
- int samplenr;
- float shadfac[4]; /* rgba shadow */
-} LampShadowSubSample;
-
-typedef struct LampShadowSample {
- LampShadowSubSample s[16]; /* MAX OSA */
-} LampShadowSample;
-
-typedef struct LampRen {
- struct LampRen *next, *prev;
-
- float xs, ys, dist;
- float co[3];
- short type;
- int mode;
- float r, g, b, k;
- float shdwr, shdwg, shdwb;
- float energy, haint;
- int lay;
- float spotsi, spotbl;
- float vec[3];
- float xsp, ysp, distkw, inpr;
- float halokw, halo;
-
- short falloff_type;
- float ld1, ld2;
- float coeff_const, coeff_lin, coeff_quad;
- struct CurveMapping *curfalloff;
-
- /* copied from Lamp, to decouple more rendering stuff */
- /** Size of the shadowbuffer */
- short bufsize;
- /** Number of samples for the shadows */
- short samp;
- /** Softness factor for shadow */
- float soft;
- /** amount of subsample buffers and type of filter for sampling */
- short buffers, filtertype;
- /** shadow buffer type (regular, irregular) */
- short buftype;
- /** autoclip */
- short bufflag;
- /** shadow plus halo: detail level */
- short shadhalostep;
- /** Near clip of the lamp */
- float clipsta;
- /** Far clip of the lamp */
- float clipend;
- /** A small depth offset to prevent self-shadowing. */
- float bias;
- /* Compression threshold for deep shadow maps */
- float compressthresh;
-
- short ray_samp, ray_sampy, ray_sampz, ray_samp_method, ray_samp_type, area_shape, ray_totsamp;
- short xold[BLENDER_MAX_THREADS], yold[BLENDER_MAX_THREADS]; /* last jitter table for area lights */
- float area_size, area_sizey, area_sizez;
- float adapt_thresh;
-
- /* sun/sky */
- struct SunSky *sunsky;
-
- struct ShadBuf *shb;
- float *jitter;
-
- float imat[3][3];
- float spottexfac;
- float sh_invcampos[3], sh_zfac; /* sh_= spothalo */
-
- float lampmat[4][4]; /* worls space lamp matrix, used for scene rotation */
-
- float mat[3][3]; /* 3x3 part from lampmat x viewmat */
- float area[8][3], areasize;
-
- /* passes & node shader support: all shadow info for a pixel */
- LampShadowSample *shadsamp;
-
- /* ray optim */
- struct RayObject *last_hit[BLENDER_MAX_THREADS];
-
- struct MTex *mtex[MAX_MTEX];
-
- /* threading */
- int thread_assigned;
- int thread_ready;
-} LampRen;
-
/* **************** defines ********************* */
-/* R.r.mode flag is same as for renderdata */
-
/* R.flag */
-#define R_ZTRA 1
-#define R_HALO 2
-#define R_SEC_FIELD 4
-#define R_LAMPHALO 8
-#define R_NEED_TANGENT 16
-#define R_BAKE_TRACE 32
-#define R_BAKING 64
-#define R_ANIMATION 128
-#define R_NEED_VCOL 256
-
-/* vlakren->flag (vlak = face in dutch) char!!! */
-#define R_SMOOTH 1
-#define R_HIDDEN 2
-/* strand flag, means special handling */
-#define R_STRAND 4
-#define R_FULL_OSA 8
-#define R_FACE_SPLIT 16
-/* Tells render to divide face other way. */
-#define R_DIVIDE_24 32
-/* vertex normals are tangent or view-corrected vector, for hair strands */
-#define R_TANGENT 64
-#define R_TRACEBLE 128
-
-/* vlakren->freestyle_edge_mark */
-#ifdef WITH_FREESTYLE
-# define R_EDGE_V1V2 1
-# define R_EDGE_V2V3 2
-# define R_EDGE_V3V4 4
-# define R_EDGE_V3V1 4
-# define R_EDGE_V4V1 8
-#endif
-
-/* strandbuffer->flag */
-#define R_STRAND_BSPLINE 1
-#define R_STRAND_B_UNITS 2
-
-/* objectren->flag */
-#define R_INSTANCEABLE 1
-
-/* objectinstance->flag */
-#define R_DUPLI_TRANSFORMED 1
-#define R_ENV_TRANSFORMED 2
-#define R_TRANSFORMED (1|2)
+#define R_ANIMATION 1
#endif /* __RENDER_TYPES_H__ */
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
deleted file mode 100644
index aa3efca9e5b..00000000000
--- a/source/blender/render/intern/include/rendercore.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __RENDERCORE_H__
-#define __RENDERCORE_H__
-
-/** \file blender/render/intern/include/rendercore.h
- * \ingroup render
- */
-
-#include "render_types.h"
-
-#include "RE_engine.h"
-
-#include "DNA_node_types.h"
-
-#include "NOD_composite.h"
-
-struct ShadeInput;
-struct ShadeResult;
-struct World;
-struct RenderPart;
-struct RenderLayer;
-struct RayObject;
-
-/* ------------------------------------------------------------------------- */
-
-typedef struct PixStr {
- struct PixStr *next;
- int obi, facenr, z, maskz;
- unsigned short mask;
- short shadfac;
-} PixStr;
-
-typedef struct PixStrMain {
- struct PixStrMain *next, *prev;
- struct PixStr *ps;
- int counter;
-} PixStrMain;
-
-/* ------------------------------------------------------------------------- */
-
-
-void calc_view_vector(float view[3], float x, float y);
-float mistfactor(float zcor, const float co[3]); /* dist and height, return alpha */
-
-void renderspothalo(struct ShadeInput *shi, float col[4], float alpha);
-void add_halo_flare(Render *re);
-
-void calc_renderco_zbuf(float co[3], const float view[3], int z);
-void calc_renderco_ortho(float co[3], float x, float y, int z);
-
-int count_mask(unsigned short mask);
-
-void zbufshade_tile(struct RenderPart *pa);
-void zbufshadeDA_tile(struct RenderPart *pa);
-
-void zbufshade_sss_tile(struct RenderPart *pa);
-
-int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct RenderLayer **rlpp);
-
-void render_internal_update_passes(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl);
-
-
-/* -------- ray.c ------- */
-
-struct RayObject *RE_rayobject_create(int type, int size, int octree_resolution);
-
-extern void freeraytree(Render *re);
-extern void makeraytree(Render *re);
-struct RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi);
-
-extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]);
-extern void ray_trace(ShadeInput *shi, ShadeResult *);
-extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]);
-extern void init_jitter_plane(LampRen *lar);
-extern void init_ao_sphere(Render *re, struct World *wrld);
-extern void init_render_qmcsampler(Render *re);
-extern void free_render_qmcsampler(Render *re);
-
-#endif /* __RENDERCORE_H__ */
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
deleted file mode 100644
index 1840ec493c8..00000000000
--- a/source/blender/render/intern/include/renderdatabase.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * ***** 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): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/renderdatabase.h
- * \ingroup render
- */
-
-
-#ifndef __RENDERDATABASE_H__
-#define __RENDERDATABASE_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct Object;
-struct VlakRen;
-struct VertRen;
-struct HaloRen;
-struct Main;
-struct Material;
-struct Render;
-struct MCol;
-struct MTFace;
-struct CustomData;
-struct StrandBuffer;
-struct StrandRen;
-struct ObjectInstanceRen;
-struct RadFace;
-struct Isect;
-
-#define RE_QUAD_MASK 0x7FFFFFF
-#define RE_QUAD_OFFS 0x8000000
-
-/* render allocates totvert/256 of these nodes, for lookup and quick alloc */
-typedef struct VertTableNode {
- struct VertRen *vert;
- float *rad;
- float *strand;
- float *tangent;
- float *stress;
- float *winspeed;
- /* Index of vertex in source mesh (before modifiers). */
- int *origindex;
-} VertTableNode;
-
-typedef struct VlakTableNode {
- struct VlakRen *vlak;
- struct MTFace *mtface;
- struct MCol *mcol;
- /* Index of mpoly in source mesh (before tessellation). */
- int *origindex;
- int totmtface, totmcol;
- float *surfnor;
- float *tangent_arrays[MAX_MTFACE];
- struct RadFace **radface;
-} VlakTableNode;
-
-typedef struct StrandTableNode {
- struct StrandRen *strand;
- float *winspeed;
- float *surfnor;
- float *simplify;
- int *face;
- struct MCol *mcol;
- float *uv;
- int totuv, totmcol;
-} StrandTableNode;
-
-/* renderdatabase.c */
-void free_renderdata_tables(struct Render *re);
-void free_renderdata_vertnodes(struct VertTableNode *vertnodes);
-void free_renderdata_vlaknodes(struct VlakTableNode *vlaknodes);
-
-void project_renderdata(struct Render *re, void (*projectfunc)(const float *, float mat[4][4], float *), bool do_pano, float xoffs, bool do_buckets);
-int clip_render_object(float boundbox[2][3], float bounds[4], float mat[4][4]);
-
-/* functions are not exported... so wrong names */
-
-struct VlakRen *RE_findOrAddVlak(struct ObjectRen *obr, int nr);
-struct VertRen *RE_findOrAddVert(struct ObjectRen *obr, int nr);
-struct StrandRen *RE_findOrAddStrand(struct ObjectRen *obr, int nr);
-struct HaloRen *RE_findOrAddHalo(struct ObjectRen *obr, int nr);
-struct HaloRen *RE_inithalo(struct Render *re, struct ObjectRen *obr, struct Material *ma,
- const float vec[3], const float vec1[3],
- const float *orco, float hasize, float vectsize, int seed);
-struct HaloRen *RE_inithalo_particle(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, struct Material *ma,
- const float vec[3], const float vec1[3],
- const float *orco, const float *uvco, float hasize, float vectsize, int seed,
- const float pa_co[3]);
-struct StrandBuffer *RE_addStrandBuffer(struct ObjectRen *obr, int totvert);
-
-struct ObjectRen *RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int psysindex, int lay);
-struct ObjectInstanceRen *RE_addRenderInstance(
- struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par,
- int index, int psysindex, float mat[4][4], int lay, const struct DupliObject *dob);
-void RE_makeRenderInstances(struct Render *re);
-void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag);
-
-void RE_instance_rotate_ray_start(struct ObjectInstanceRen *obi, struct Isect *is);
-void RE_instance_rotate_ray_dir(struct ObjectInstanceRen *obi, struct Isect *is);
-void RE_instance_rotate_ray(struct ObjectInstanceRen *obi, struct Isect *is);
-void RE_instance_rotate_ray_restore(struct ObjectInstanceRen *obi, struct Isect *is);
-
-float *RE_vertren_get_stress(struct ObjectRen *obr, struct VertRen *ver, int verify);
-float *RE_vertren_get_rad(struct ObjectRen *obr, struct VertRen *ver, int verify);
-float *RE_vertren_get_strand(struct ObjectRen *obr, struct VertRen *ver, int verify);
-float *RE_vertren_get_tangent(struct ObjectRen *obr, struct VertRen *ver, int verify);
-float *RE_vertren_get_winspeed(struct ObjectInstanceRen *obi, struct VertRen *ver, int verify);
-int *RE_vertren_get_origindex(struct ObjectRen *obr, VertRen *ver, int verify);
-
-struct MTFace *RE_vlakren_get_tface(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify);
-struct MCol *RE_vlakren_get_mcol(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify);
-int *RE_vlakren_get_origindex(struct ObjectRen *obr, VlakRen *vlak, int verify);
-float *RE_vlakren_get_surfnor(struct ObjectRen *obr, VlakRen *ren, int verify);
-float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify);
-RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify);
-void RE_vlakren_get_normal(struct Render *re, struct ObjectInstanceRen *obi, struct VlakRen *vlr, float *nor);
-
-float *RE_strandren_get_surfnor(struct ObjectRen *obr, struct StrandRen *strand, int verify);
-float *RE_strandren_get_uv(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify);
-struct MCol *RE_strandren_get_mcol(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify);
-float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify);
-int *RE_strandren_get_face(struct ObjectRen *obr, struct StrandRen *strand, int verify);
-float *RE_strandren_get_winspeed(struct ObjectInstanceRen *obi, struct StrandRen *strand, int verify);
-
-struct VertRen *RE_vertren_copy(struct ObjectRen *obr, struct VertRen *ver);
-struct VlakRen *RE_vlakren_copy(struct ObjectRen *obr, struct VlakRen *vlr);
-
-void RE_set_customdata_names(struct ObjectRen *obr, struct CustomData *data);
-
-void area_lamp_vectors(struct LampRen *lar);
-
-
-/* haloren->type: flags */
-#define HA_ONLYSKY 1
-#define HA_VECT 2
-#define HA_XALPHA 4
-#define HA_FLARECIRC 8
-
-/* convertblender.c */
-void init_render_world(Render *re);
-void RE_Database_FromScene_Vectors(Render *re, struct Main *bmain, struct Scene *sce, unsigned int lay);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RENDERDATABASE_H__ */
diff --git a/source/blender/render/intern/include/renderpipeline.h b/source/blender/render/intern/include/renderpipeline.h
index 925924499cd..ef7094633a1 100644
--- a/source/blender/render/intern/include/renderpipeline.h
+++ b/source/blender/render/intern/include/renderpipeline.h
@@ -33,14 +33,14 @@
#ifndef __RENDERPIPELINE_H__
#define __RENDERPIPELINE_H__
+struct ListBase;
struct Render;
struct RenderData;
struct RenderLayer;
struct RenderResult;
struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr);
-float panorama_pixel_rot(struct Render *re);
-void render_update_anim_renderdata(struct Render *re, struct RenderData *rd);
+void render_update_anim_renderdata(struct Render *re, struct RenderData *rd, struct ListBase *render_layers);
void render_copy_renderdata(struct RenderData *to, struct RenderData *from);
#endif /* __RENDERPIPELINE_H__ */
diff --git a/source/blender/render/intern/include/shadbuf.h b/source/blender/render/intern/include/shadbuf.h
deleted file mode 100644
index 5901d2187dc..00000000000
--- a/source/blender/render/intern/include/shadbuf.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __SHADBUF_H__
-#define __SHADBUF_H__
-
-/** \file blender/render/intern/include/shadbuf.h
- * \ingroup render
- */
-
-#include "render_types.h"
-
-
-/**
- * Calculates shadowbuffers for a vector of shadow-giving lamps
- * \param lar The vector of lamps
- */
-void makeshadowbuf(struct Render *re, LampRen *lar);
-void freeshadowbuf(struct LampRen *lar);
-
-void threaded_makeshadowbufs(struct Render *re);
-
-/**
- * Determines the shadow factor for a face and lamp. There is some
- * communication with global variables here.
- * \return The shadow factors: 1.0 for no shadow, 0.0 for complete
- * shadow.
- * \param shb The shadowbuffer to find the shadow factor in.
- * \param inp The inproduct between viewvector and ?
- *
- */
-float testshadowbuf(struct Render *re, struct ShadBuf *shb, const float rco[3], const float dxco[3], const float dyco[3], float inp, float mat_bias);
-
-/**
- * Determines the shadow factor for lamp \a lar, between \a p1 and \a p2. (Which CS?)
- */
-float shadow_halo(LampRen *lar, const float p1[3], const float p2[3]);
-
-/**
- * Irregular shadowbuffer
- */
-
-struct MemArena;
-struct APixstr;
-
-void ISB_create(RenderPart *pa, struct APixstr *apixbuf);
-void ISB_free(RenderPart *pa);
-float ISB_getshadow(ShadeInput *shi, ShadBuf *shb);
-
-/* data structures have to be accessible both in camview(x, y) as in lampview(x, y) */
-/* since they're created per tile rendered, speed goes over memory requirements */
-
-
-/* buffer samples, allocated in camera buffer and pointed to in lampbuffer nodes */
-typedef struct ISBSample {
- float zco[3]; /* coordinate in lampview projection */
- short *shadfac; /* initialized zero = full lighted */
- int obi; /* object for face lookup */
- int facenr; /* index in faces list */
-} ISBSample;
-
-/* transparent version of buffer sample */
-typedef struct ISBSampleA {
- float zco[3]; /* coordinate in lampview projection */
- short *shadfac; /* NULL = full lighted */
- int obi; /* object for face lookup */
- int facenr; /* index in faces list */
- struct ISBSampleA *next; /* in end, we want the first items to align with ISBSample */
-} ISBSampleA;
-
-/* used for transparent storage only */
-typedef struct ISBShadfacA {
- struct ISBShadfacA *next;
- int obi;
- int facenr;
- float shadfac;
-} ISBShadfacA;
-
-/* What needs to be stored to evaluate shadow, for each thread in ShadBuf */
-typedef struct ISBData {
- short *shadfacs; /* simple storage for solid only */
- ISBShadfacA **shadfaca;
- struct MemArena *memarena;
- int minx, miny, rectx, recty; /* copy from part disprect */
-} ISBData;
-
-#endif /* __SHADBUF_H__ */
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
deleted file mode 100644
index e306c3c075c..00000000000
--- a/source/blender/render/intern/include/shading.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * ***** 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.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/shading.h
- * \ingroup render
- */
-
-
-struct ShadeInput;
-struct ShadeResult;
-struct RenderPart;
-struct RenderLayer;
-struct PixStr;
-struct LampRen;
-struct VlakRen;
-struct StrandPoint;
-struct ObjectInstanceRen;
-struct Isect;
-
-/* shadeinput.c */
-
-#define RE_MAX_OSA 16
-
-/* needed to calculate shadow and AO for an entire pixel */
-typedef struct ShadeSample {
- int tot; /* amount of shi in use, can be 1 for not FULL_OSA */
-
- RenderLayer *rlpp[RE_MAX_OSA]; /* fast lookup from sample to renderlayer (fullsample buf) */
-
- /* could be malloced once */
- ShadeInput shi[RE_MAX_OSA];
- ShadeResult shr[RE_MAX_OSA];
-} ShadeSample;
-
-
- /* also the node shader callback */
-void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr);
-
-void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3);
-void shade_input_set_triangle(struct ShadeInput *shi, int obi, int facenr, int normal_flip);
-void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from);
-void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]);
-void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z);
-void shade_input_set_uv(struct ShadeInput *shi);
-void shade_input_set_normals(struct ShadeInput *shi);
-void shade_input_set_vertex_normals(struct ShadeInput *shi);
-void shade_input_flip_normals(struct ShadeInput *shi);
-void shade_input_set_shade_texco(struct ShadeInput *shi);
-void shade_input_set_strand(struct ShadeInput *shi, struct StrandRen *strand, struct StrandPoint *spoint);
-void shade_input_set_strand_texco(struct ShadeInput *shi, struct StrandRen *strand, struct StrandVert *svert, struct StrandPoint *spoint);
-void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr);
-
-void shade_input_init_material(struct ShadeInput *shi);
-void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struct RenderLayer *rl, int sample);
-
-void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl);
-void shade_samples_do_AO(struct ShadeSample *ssamp);
-void shade_samples_fill_with_ps(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
-int shade_samples(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
-
-void vlr_set_uv_indices(struct VlakRen *vlr, int *i1, int *i2, int *i3);
-
-void calc_R_ref(struct ShadeInput *shi);
-
-void barycentric_differentials_from_position(
- const float co[3], const float v1[3], const float v2[3], const float v3[3],
- const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
- float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v);
-
-/* shadeoutput. */
-void shade_lamp_loop(struct ShadeInput *shi, struct ShadeResult *shr);
-
-void shade_color(struct ShadeInput *shi, ShadeResult *shr);
-
-void ambient_occlusion(struct ShadeInput *shi);
-void environment_lighting_apply(struct ShadeInput *shi, struct ShadeResult *shr);
-
-ListBase *get_lights(struct ShadeInput *shi);
-float lamp_get_visibility(struct LampRen *lar, const float co[3], float lv[3], float *dist);
-void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real);
-
-float fresnel_fac(const float view[3], const float vn[3], float fresnel, float fac);
-
-/* rayshade.c */
-extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr);
diff --git a/source/blender/render/intern/include/sss.h b/source/blender/render/intern/include/sss.h
deleted file mode 100644
index e01dfe73851..00000000000
--- a/source/blender/render/intern/include/sss.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * ***** 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) 2007 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/sss.h
- * \ingroup render
- */
-
-
-#ifndef __SSS_H__
-#define __SSS_H__
-
-/* Generic multiple scattering API */
-
-struct ScatterSettings;
-typedef struct ScatterSettings ScatterSettings;
-
-struct ScatterTree;
-typedef struct ScatterTree ScatterTree;
-
-ScatterSettings *scatter_settings_new(float refl, float radius, float ior,
- float reflfac, float frontweight, float backweight);
-void scatter_settings_free(ScatterSettings *ss);
-
-ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error,
- float (*co)[3], float (*color)[3], float *area, int totpoint);
-void scatter_tree_build(ScatterTree *tree);
-void scatter_tree_sample(ScatterTree *tree, const float co[3], float color[3]);
-void scatter_tree_free(ScatterTree *tree);
-
-/* Internal renderer API */
-
-struct Render;
-struct Material;
-
-void make_sss_tree(struct Render *re);
-void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint);
-void free_sss(struct Render *re);
-
-int sample_sss(struct Render *re, struct Material *mat, const float co[3], float color[3]);
-int sss_pass_done(struct Render *re, struct Material *mat);
-
-#endif /*__SSS_H__*/
diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h
deleted file mode 100644
index 354ba3f0f07..00000000000
--- a/source/blender/render/intern/include/strand.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * ***** 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): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/strand.h
- * \ingroup render
- */
-
-
-#ifndef __STRAND_H__
-#define __STRAND_H__
-
-struct StrandVert;
-struct StrandRen;
-struct StrandBuffer;
-struct ShadeSample;
-struct StrandPart;
-struct Render;
-struct ZSpan;
-struct ObjectInstanceRen;
-struct StrandSurface;
-struct DerivedMesh;
-struct ObjectRen;
-
-typedef struct StrandPoint {
- /* position within segment */
- float t;
-
- /* camera space */
- float co[3];
- float nor[3];
- float tan[3];
- float strandco;
- float width;
-
- /* derivatives */
- float dtco[3], dsco[3];
- float dtstrandco;
-
- /* outer points */
- float co1[3], co2[3];
- float hoco1[4], hoco2[4];
- float zco1[3], zco2[3];
- int clip1, clip2;
-
- /* screen space */
- float hoco[4];
- float x, y;
-
- /* simplification */
- float alpha;
-} StrandPoint;
-
-typedef struct StrandSegment {
- struct StrandVert *v[4];
- struct StrandRen *strand;
- struct StrandBuffer *buffer;
- struct ObjectInstanceRen *obi;
- float sqadaptcos;
-
- StrandPoint point1, point2;
- int shaded;
-} StrandSegment;
-
-struct StrandShadeCache;
-typedef struct StrandShadeCache StrandShadeCache;
-
-void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint);
-void render_strand_segment(struct Render *re, float winmat[4][4], struct StrandPart *spart, struct ZSpan *zspan, int totzspan, StrandSegment *sseg);
-void strand_minmax(struct StrandRen *strand, float min[3], float max[3], const float width);
-
-struct StrandSurface *cache_strand_surface(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[4][4], int timeoffset);
-void free_strand_surface(struct Render *re);
-
-struct StrandShadeCache *strand_shade_cache_create(void);
-void strand_shade_cache_free(struct StrandShadeCache *cache);
-void strand_shade_segment(struct Render *re, struct StrandShadeCache *cache, struct StrandSegment *sseg, struct ShadeSample *ssamp, float t, float s, int addpassflag);
-void strand_shade_unref(struct StrandShadeCache *cache, struct ObjectInstanceRen *obi, struct StrandVert *svert);
-
-#endif
diff --git a/source/blender/render/intern/include/sunsky.h b/source/blender/render/intern/include/sunsky.h
deleted file mode 100644
index c608f9fc48c..00000000000
--- a/source/blender/render/intern/include/sunsky.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * ***** 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): zaghaghi
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/sunsky.h
- * \ingroup render
- */
-
-#ifndef __SUNSKY_H__
-#define __SUNSKY_H__
-
-// #define SPECTRUM_MAX_COMPONENTS 100
-
-typedef struct SunSky {
- short effect_type, skyblendtype, sky_colorspace;
- float turbidity;
- float theta, phi;
-
- float toSun[3];
-
- /*float sunSpectralRaddata[SPECTRUM_MAX_COMPONENTS];*/
- float sunSolidAngle;
-
- float zenith_Y, zenith_x, zenith_y;
-
- float perez_Y[5], perez_x[5], perez_y[5];
-
- /* suggested by glome in patch [#8063] */
- float horizon_brightness;
- float spread;
- float sun_brightness;
- float sun_size;
- float backscattered_light;
- float skyblendfac;
- float sky_exposure;
-
- float atm_HGg;
-
- float atm_SunIntensity;
- float atm_InscatteringMultiplier;
- float atm_ExtinctionMultiplier;
- float atm_BetaRayMultiplier;
- float atm_BetaMieMultiplier;
- float atm_DistanceMultiplier;
-
- float atm_BetaRay[3];
- float atm_BetaDashRay[3];
- float atm_BetaMie[3];
- float atm_BetaDashMie[3];
- float atm_BetaRM[3];
-} SunSky;
-
-void InitSunSky(struct SunSky *sunsky, float turb, const float toSun[3], float horizon_brightness,
- float spread, float sun_brightness, float sun_size, float back_scatter,
- float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace);
-
-void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float color_out[3]);
-void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_out[3]);
-void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf, float inscattf, float extincf, float disf);
-void AtmospherePixleShader(struct SunSky *sunSky, float view[3], float s, float rgb[3]);
-void ClipColor(float c[3]);
-
-#endif /*__SUNSKY_H__*/
diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h
index f6d39b81f2a..04a456c0850 100644
--- a/source/blender/render/intern/include/texture.h
+++ b/source/blender/render/intern/include/texture.h
@@ -63,29 +63,12 @@
} \
} \
-struct HaloRen;
-struct ShadeInput;
struct TexResult;
struct Tex;
struct Image;
struct ImBuf;
struct ImagePool;
-/* texture.h */
-
-void do_halo_tex(struct HaloRen *har, float xn, float yn, float col_r[4]);
-void do_sky_tex(
- const float rco[3], const float view[3], const float lo[3], const float dxyview[2],
- float hor[3], float zen[3], float *blend, int skyflag, short thread);
-void do_material_tex(struct ShadeInput *shi, struct Render *re);
-void do_lamp_tex(LampRen *la, const float lavec[3], struct ShadeInput *shi, float col_r[3], int effect);
-void do_volume_tex(struct ShadeInput *shi, const float xyz[3], int mapto_flag, float col_r[3], float *val, struct Render *re);
-
-void init_render_textures(Render *re);
-void end_render_textures(Render *re);
-
-void render_realtime_texture(struct ShadeInput *shi, struct Image *ima);
-
/* imagetexture.h */
int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres, struct ImagePool *pool, const bool skip_load_image);
diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h
deleted file mode 100644
index 3805478fed0..00000000000
--- a/source/blender/render/intern/include/volumetric.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/include/volumetric.h
- * \ingroup render
- */
-
-
-struct Isect;
-struct ShadeInput;
-struct ShadeResult;
-
-float vol_get_density(struct ShadeInput *shi, const float co[3]);
-void vol_get_scattering(ShadeInput *shi, float scatter_col[3], const float co[3], const float view[3]);
-
-void shade_volume_outside(ShadeInput *shi, ShadeResult *shr);
-void shade_volume_inside(ShadeInput *shi, ShadeResult *shr);
-void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is);
-
-#define VOL_IS_BACKFACE 1
-#define VOL_IS_SAMEMATERIAL 2
-
-#define VOL_BOUNDS_DEPTH 0
-#define VOL_BOUNDS_SS 1
-
-#define VOL_SHADE_OUTSIDE 0
-#define VOL_SHADE_INSIDE 1
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index 50ad78b5be7..0acc7d091e3 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -33,57 +33,6 @@
#ifndef __ZBUF_H__
#define __ZBUF_H__
-struct RenderPart;
-struct RenderLayer;
-struct LampRen;
-struct ListBase;
-struct ZSpan;
-struct APixstrand;
-struct APixstr;
-struct StrandShadeCache;
-
-void fillrect(int *rect, int x, int y, int val);
-
-/**
- * Converts a world coordinate into a homogeneous coordinate in view
- * coordinates.
- */
-void projectvert(const float v1[3], float winmat[4][4], float adr[4]);
-void projectverto(const float v1[3], float winmat[4][4], float adr[4]);
-int testclip(const float v[3]);
-
-void zbuffer_shadow(struct Render *re, float winmat[4][4], struct LampRen *lar, int *rectz, int size, float jitx, float jity);
-void zbuffer_abuf_shadow(struct Render *re, struct LampRen *lar, float winmat[4][4], struct APixstr *APixbuf, struct APixstrand *apixbuf, struct ListBase *apsmbase, int size, int samples, float (*jit)[2]);
-void zbuffer_solid(struct RenderPart *pa, struct RenderLayer *rl, void (*fillfunc)(struct RenderPart *, struct ZSpan *, int, void *), void *data);
-
-unsigned short *zbuffer_transp_shade(struct RenderPart *pa, struct RenderLayer *rl, float *pass, struct ListBase *psmlist);
-void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(void *, int, int, int, int, int));
-int zbuffer_strands_abuf(struct Render *re, struct RenderPart *pa, struct APixstrand *apixbuf, struct ListBase *apsmbase, unsigned int lay, int negzmask, float winmat[4][4], int winx, int winy, int sample, float (*jit)[2], float clipcrop, int shadow, struct StrandShadeCache *cache);
-
-typedef struct APixstr {
- unsigned short mask[4]; /* jitter mask */
- int z[4]; /* distance */
- int p[4]; /* index */
- int obi[4]; /* object instance */
- short shadfac[4]; /* optimize storage for irregular shadow */
- struct APixstr *next;
-} APixstr;
-
-typedef struct APixstrand {
- unsigned short mask[4]; /* jitter mask */
- int z[4]; /* distance */
- int p[4]; /* index */
- int obi[4]; /* object instance */
- int seg[4]; /* for strands, segment number */
- float u[4], v[4]; /* for strands, u,v coordinate in segment */
- struct APixstrand *next;
-} APixstrand;
-
-typedef struct APixstrMain {
- struct APixstrMain *next, *prev;
- void *ps;
-} APixstrMain;
-
/* span fill in method, is also used to localize data for zbuffering */
typedef struct ZSpan {
int rectx, recty; /* range for clipping */
@@ -91,60 +40,12 @@ typedef struct ZSpan {
int miny1, maxy1, miny2, maxy2; /* actual filled in range */
const float *minp1, *maxp1, *minp2, *maxp2; /* vertex pointers detect min/max range in */
float *span1, *span2;
-
- float zmulx, zmuly, zofsx, zofsy; /* transform from hoco to zbuf co */
-
- int *rectz, *arectz; /* zbuffers, arectz is for transparent */
- int *rectz1; /* secondary z buffer for shadowbuffer (2nd closest z) */
- int *rectp; /* polygon index buffer */
- int *recto; /* object buffer */
- int *rectmask; /* negative zmask buffer */
- APixstr *apixbuf, *curpstr; /* apixbuf for transparent */
- APixstrand *curpstrand; /* same for strands */
- struct ListBase *apsmbase;
-
- int polygon_offset; /* offset in Z */
- float shad_alpha; /* copy from material, used by irregular shadbuf */
- int mask, apsmcounter; /* in use by apixbuf */
- int apstrandmcounter;
-
- float clipcrop; /* for shadow, was in R global before */
-
- void *sss_handle; /* used by sss */
- void (*sss_func)(void *, int, int, int, int, int);
-
- void (*zbuffunc)(struct ZSpan *, int, int, const float *, const float *, const float *, const float *);
- void (*zbuflinefunc)(struct ZSpan *, int, int, const float *, const float *);
-
} ZSpan;
-/* exported to shadbuf.c */
-void zbufclip4(struct ZSpan *zspan, int obi, int zvlnr,
- const float f1[4], const float f2[4], const float f3[4], const float f4[4],
- const int c1, const int c2, const int c3, const int c4);
+void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty);
void zbuf_free_span(struct ZSpan *zspan);
-void freepsA(struct ListBase *lb);
-/* to rendercore.c */
void zspan_scanconvert(struct ZSpan *zpan, void *handle, float *v1, float *v2, float *v3,
void (*func)(void *, int, int, float, float) );
-/* exported to edge render... */
-void zbufclip(struct ZSpan *zspan, int obi, int zvlnr,
- const float f1[4], const float f2[4], const float f3[4],
- const int c1, const int c2, const int c3);
-void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty, float clipcrop);
-void zbufclipwire(struct ZSpan *zspan, int obi, int zvlnr, int ec,
- const float ho1[4], const float ho2[4], const float ho3[4], const float ho4[4],
- const int c1, const int c2, const int c3, const int c4);
-
-/* exported to shadeinput.c */
-void zbuf_make_winmat(Render *re, float winmat[4][4]);
-void zbuf_render_project(float winmat[4][4], const float co[3], float ho[4]);
-
-/* should not really be exposed, bad! */
-void hoco_to_zco(ZSpan *zspan, float zco[3], const float hoco[4]);
-void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) );
-void zbufsinglewire(ZSpan *zspan, int obi, int zvlnr, const float ho1[4], const float ho2[4]);
-
#endif
diff --git a/source/blender/render/intern/raytrace/bvh.h b/source/blender/render/intern/raytrace/bvh.h
deleted file mode 100644
index 0f9a506762b..00000000000
--- a/source/blender/render/intern/raytrace/bvh.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/bvh.h
- * \ingroup render
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-
-#include "raycounter.h"
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "rayobject_hint.h"
-#include "rayobject_rtbuild.h"
-
-#include <assert.h>
-
-#ifdef __SSE__
-#include <xmmintrin.h>
-#endif
-
-#ifndef __BVH_H__
-#define __BVH_H__
-
-#ifdef __SSE__
-inline int test_bb_group4(__m128 *bb_group, const Isect *isec)
-{
- const __m128 tmin0 = _mm_setzero_ps();
- const __m128 tmax0 = _mm_set_ps1(isec->dist);
-
- float start[3], idot_axis[3];
- copy_v3_v3(start, isec->start);
- copy_v3_v3(idot_axis, isec->idot_axis);
-
- const __m128 tmin1 = _mm_max_ps(tmin0, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[0]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) );
- const __m128 tmax1 = _mm_min_ps(tmax0, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[1]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) );
- const __m128 tmin2 = _mm_max_ps(tmin1, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[2]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) );
- const __m128 tmax2 = _mm_min_ps(tmax1, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[3]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) );
- const __m128 tmin3 = _mm_max_ps(tmin2, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[4]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) );
- const __m128 tmax3 = _mm_min_ps(tmax2, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[5]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) );
-
- return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3));
-}
-#endif
-
-/*
- * Determines the distance that the ray must travel to hit the bounding volume of the given node
- * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe
- * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9]
- */
-static inline int rayobject_bb_intersect_test(const Isect *isec, const float *_bb)
-{
- const float *bb = _bb;
-
- float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
- float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
- float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
- float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
- float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
- float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
-
- RE_RC_COUNT(isec->raycounter->bb.test);
-
- if (t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
- if (t2x < 0.0f || t2y < 0.0f || t2z < 0.0f) return 0;
- if (t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0;
- RE_RC_COUNT(isec->raycounter->bb.hit);
-
- return 1;
-}
-
-/* bvh tree generics */
-template<class Tree> static void bvh_add(Tree *obj, RayObject *ob)
-{
- rtbuild_add(obj->builder, ob);
-}
-
-template<class Node>
-inline bool is_leaf(Node *node)
-{
- return !RE_rayobject_isAligned(node);
-}
-
-template<class Tree> static void bvh_done(Tree *obj);
-
-template<class Tree>
-static void bvh_free(Tree *obj)
-{
- if (obj->builder)
- rtbuild_free(obj->builder);
-
- if (obj->node_arena)
- BLI_memarena_free(obj->node_arena);
-
- MEM_freeN(obj);
-}
-
-template<class Tree>
-static void bvh_bb(Tree *obj, float *min, float *max)
-{
- if (obj->root)
- bvh_node_merge_bb(obj->root, min, max);
-}
-
-
-template<class Tree>
-static float bvh_cost(Tree *obj)
-{
- assert(obj->cost >= 0.0f);
- return obj->cost;
-}
-
-
-
-/* bvh tree nodes generics */
-template<class Node> static inline int bvh_node_hit_test(Node *node, Isect *isec)
-{
- return rayobject_bb_intersect_test(isec, (const float *)node->bb);
-}
-
-
-template<class Node>
-static inline void bvh_node_merge_bb(Node *node, float min[3], float max[3])
-{
- if (is_leaf(node)) {
- RE_rayobject_merge_bb((RayObject *)node, min, max);
- }
- else {
- DO_MIN(node->bb, min);
- DO_MAX(node->bb + 3, max);
- }
-}
-
-
-
-/*
- * recursively transverse a BVH looking for a rayhit using a local stack
- */
-template<class Node> static inline void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos);
-
-template<class Node, int MAX_STACK_SIZE, bool TEST_ROOT, bool SHADOW>
-static int bvh_node_stack_raycast(Node *root, Isect *isec)
-{
- Node *stack[MAX_STACK_SIZE];
- int hit = 0, stack_pos = 0;
-
- if (!TEST_ROOT && !is_leaf(root))
- bvh_node_push_childs(root, isec, stack, stack_pos);
- else
- stack[stack_pos++] = root;
-
- while (stack_pos) {
- Node *node = stack[--stack_pos];
- if (!is_leaf(node)) {
- if (bvh_node_hit_test(node, isec)) {
- bvh_node_push_childs(node, isec, stack, stack_pos);
- assert(stack_pos <= MAX_STACK_SIZE);
- }
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)node, isec);
- if (SHADOW && hit) return hit;
- }
- }
- return hit;
-}
-
-
-#ifdef __SSE__
-/*
- * Generic SIMD bvh recursion
- * this was created to be able to use any simd (with the cost of some memmoves)
- * it can take advantage of any SIMD width and doens't needs any special tree care
- */
-template<class Node, int MAX_STACK_SIZE, bool TEST_ROOT>
-static int bvh_node_stack_raycast_simd(Node *root, Isect *isec)
-{
- Node *stack[MAX_STACK_SIZE];
-
- int hit = 0, stack_pos = 0;
-
- if (!TEST_ROOT) {
- if (!is_leaf(root)) {
- if (!is_leaf(root->child))
- bvh_node_push_childs(root, isec, stack, stack_pos);
- else
- return RE_rayobject_intersect( (RayObject *)root->child, isec);
- }
- else
- return RE_rayobject_intersect( (RayObject *)root, isec);
- }
- else {
- if (!is_leaf(root))
- stack[stack_pos++] = root;
- else
- return RE_rayobject_intersect( (RayObject *)root, isec);
- }
-
- while (true) {
- //Use SIMD 4
- if (stack_pos >= 4) {
- __m128 t_bb[6];
- Node *t_node[4];
-
- stack_pos -= 4;
-
- /* prepare the 4BB for SIMD */
- t_node[0] = stack[stack_pos + 0]->child;
- t_node[1] = stack[stack_pos + 1]->child;
- t_node[2] = stack[stack_pos + 2]->child;
- t_node[3] = stack[stack_pos + 3]->child;
-
- const float *bb0 = stack[stack_pos + 0]->bb;
- const float *bb1 = stack[stack_pos + 1]->bb;
- const float *bb2 = stack[stack_pos + 2]->bb;
- const float *bb3 = stack[stack_pos + 3]->bb;
-
- const __m128 x0y0x1y1 = _mm_shuffle_ps(_mm_load_ps(bb0), _mm_load_ps(bb1), _MM_SHUFFLE(1, 0, 1, 0) );
- const __m128 x2y2x3y3 = _mm_shuffle_ps(_mm_load_ps(bb2), _mm_load_ps(bb3), _MM_SHUFFLE(1, 0, 1, 0) );
- t_bb[0] = _mm_shuffle_ps(x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(2, 0, 2, 0) );
- t_bb[1] = _mm_shuffle_ps(x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(3, 1, 3, 1) );
-
- const __m128 z0X0z1X1 = _mm_shuffle_ps(_mm_load_ps(bb0), _mm_load_ps(bb1), _MM_SHUFFLE(3, 2, 3, 2) );
- const __m128 z2X2z3X3 = _mm_shuffle_ps(_mm_load_ps(bb2), _mm_load_ps(bb3), _MM_SHUFFLE(3, 2, 3, 2) );
- t_bb[2] = _mm_shuffle_ps(z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(2, 0, 2, 0) );
- t_bb[3] = _mm_shuffle_ps(z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(3, 1, 3, 1) );
-
- const __m128 Y0Z0Y1Z1 = _mm_shuffle_ps(_mm_load_ps(bb0 + 4), _mm_load_ps(bb1 + 4), _MM_SHUFFLE(1, 0, 1, 0) );
- const __m128 Y2Z2Y3Z3 = _mm_shuffle_ps(_mm_load_ps(bb2 + 4), _mm_load_ps(bb3 + 4), _MM_SHUFFLE(1, 0, 1, 0) );
- t_bb[4] = _mm_shuffle_ps(Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(2, 0, 2, 0) );
- t_bb[5] = _mm_shuffle_ps(Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(3, 1, 3, 1) );
-#if 0
- for (int i = 0; i < 4; i++)
- {
- Node *t = stack[stack_pos + i];
- assert(!is_leaf(t));
-
- float *bb = ((float *)t_bb) + i;
- bb[4 * 0] = t->bb[0];
- bb[4 * 1] = t->bb[1];
- bb[4 * 2] = t->bb[2];
- bb[4 * 3] = t->bb[3];
- bb[4 * 4] = t->bb[4];
- bb[4 * 5] = t->bb[5];
- t_node[i] = t->child;
- }
-#endif
- RE_RC_COUNT(isec->raycounter->simd_bb.test);
- int res = test_bb_group4(t_bb, isec);
-
- for (int i = 0; i < 4; i++)
- if (res & (1 << i)) {
- RE_RC_COUNT(isec->raycounter->simd_bb.hit);
- if (!is_leaf(t_node[i])) {
- for (Node *t = t_node[i]; t; t = t->sibling) {
- assert(stack_pos < MAX_STACK_SIZE);
- stack[stack_pos++] = t;
- }
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)t_node[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- }
- else if (stack_pos > 0) {
- Node *node = stack[--stack_pos];
- assert(!is_leaf(node));
-
- if (bvh_node_hit_test(node, isec)) {
- if (!is_leaf(node->child)) {
- bvh_node_push_childs(node, isec, stack, stack_pos);
- assert(stack_pos <= MAX_STACK_SIZE);
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)node->child, isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- }
- else break;
- }
- return hit;
-}
-#endif
-
-/*
- * recursively transverse a BVH looking for a rayhit using system stack
- */
-#if 0
-template<class Node>
-static int bvh_node_raycast(Node *node, Isect *isec)
-{
- int hit = 0;
- if (bvh_test_node(node, isec))
- {
- if (isec->idot_axis[node->split_axis] > 0.0f)
- {
- int i;
- for (i = 0; i < BVH_NCHILDS; i++)
- if (!is_leaf(node->child[i]))
- {
- if (node->child[i] == 0) break;
-
- hit |= bvh_node_raycast(node->child[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)node->child[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- else {
- int i;
- for (i = BVH_NCHILDS - 1; i >= 0; i--)
- if (!is_leaf(node->child[i]))
- {
- if (node->child[i])
- {
- hit |= dfs_raycast(node->child[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- else {
- hit |= RE_rayobject_intersect( (RayObject *)node->child[i], isec);
- if (hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- }
- return hit;
-}
-#endif
-
-template<class Node, class HintObject>
-static void bvh_dfs_make_hint(Node *node, LCTSHint *hint, int reserve_space, HintObject *hintObject)
-{
- assert(hint->size + reserve_space + 1 <= RE_RAY_LCTS_MAX_SIZE);
-
- if (is_leaf(node)) {
- hint->stack[hint->size++] = (RayObject *)node;
- }
- else {
- int childs = count_childs(node);
- if (hint->size + reserve_space + childs <= RE_RAY_LCTS_MAX_SIZE) {
- int result = hint_test_bb(hintObject, node->bb, node->bb + 3);
- if (result == HINT_RECURSE) {
- /* We are 100% sure the ray will be pass inside this node */
- bvh_dfs_make_hint_push_siblings(node->child, hint, reserve_space, hintObject);
- }
- else if (result == HINT_ACCEPT) {
- hint->stack[hint->size++] = (RayObject *)node;
- }
- }
- else {
- hint->stack[hint->size++] = (RayObject *)node;
- }
- }
-}
-
-
-template<class Tree>
-static RayObjectAPI *bvh_get_api(int maxstacksize);
-
-
-template<class Tree, int DFS_STACK_SIZE>
-static inline RayObject *bvh_create_tree(int size)
-{
- Tree *obj = (Tree *)MEM_callocN(sizeof(Tree), "BVHTree");
- assert(RE_rayobject_isAligned(obj)); /* RayObject API assumes real data to be 4-byte aligned */
-
- obj->rayobj.api = bvh_get_api<Tree>(DFS_STACK_SIZE);
- obj->root = NULL;
-
- obj->node_arena = NULL;
- obj->builder = rtbuild_create(size);
-
- return RE_rayobject_unalignRayAPI((RayObject *) obj);
-}
-
-#endif
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
deleted file mode 100644
index bb429dc77a4..00000000000
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject.cpp
- * \ingroup render
- */
-
-
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_material_types.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "raycounter.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-
-/* RayFace
- *
- * note we force always inline here, because compiler refuses to otherwise
- * because function is too long. Since this is code that is called billions
- * of times we really do want to inline. */
-
-MALWAYS_INLINE RayObject *rayface_from_coords(RayFace *rayface, void *ob, void *face,
- float *v1, float *v2, float *v3, float *v4)
-{
- rayface->ob = ob;
- rayface->face = face;
-
- copy_v3_v3(rayface->v1, v1);
- copy_v3_v3(rayface->v2, v2);
- copy_v3_v3(rayface->v3, v3);
-
- if (v4) {
- copy_v3_v3(rayface->v4, v4);
- rayface->quad = 1;
- }
- else {
- rayface->quad = 0;
- }
-
- return RE_rayobject_unalignRayFace(rayface);
-}
-
-MALWAYS_INLINE void rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
-{
- rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : NULL);
-
- if (obi->transform_primitives) {
- mul_m4_v3(obi->mat, rayface->v1);
- mul_m4_v3(obi->mat, rayface->v2);
- mul_m4_v3(obi->mat, rayface->v3);
-
- if (RE_rayface_isQuad(rayface))
- mul_m4_v3(obi->mat, rayface->v4);
- }
-}
-
-RayObject *RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
-{
- return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : NULL);
-}
-
-RayObject *RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4)
-{
- return rayface_from_coords(rayface, ob, face, v1, v2, v3, v4);
-}
-
-/* VlakPrimitive */
-
-RayObject *RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr)
-{
- face->ob = obi;
- face->face = vlr;
-
- return RE_rayobject_unalignVlakPrimitive(face);
-}
-
-/* Checks for ignoring faces or materials */
-
-MALWAYS_INLINE int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr)
-{
- /* for baking selected to active non-traceable materials might still
- * be in the raytree */
- if (!(vlr->flag & R_TRACEBLE))
- return 0;
-
- /* I know... cpu cycle waste, might do smarter once */
- if (is->mode == RE_RAY_MIRROR)
- return !(vlr->mat->mode & MA_ONLYCAST);
- else
- return (vlr->mat->mode2 & MA_CASTSHADOW) && (is->lay & obi->lay);
-}
-
-MALWAYS_INLINE int vlr_check_intersect_solid(Isect *UNUSED(is), ObjectInstanceRen *UNUSED(obi), VlakRen *vlr)
-{
- /* solid material types only */
- if (vlr->mat->material_type == MA_TYPE_SURFACE)
- return 1;
- else
- return 0;
-}
-
-MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UNUSED(vlr))
-{
- return (obi->obr->ob != is->userdata) && (obi->obr->ob->flag & SELECT);
-}
-
-/* Ray Triangle/Quad Intersection */
-
-static bool isect_ray_tri_watertight_no_sign_check_v3(
- const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc,
- const float v0[3], const float v1[3], const float v2[3],
- float *r_lambda, float r_uv[2])
-{
- const int kx = isect_precalc->kx;
- const int ky = isect_precalc->ky;
- const int kz = isect_precalc->kz;
- const float sx = isect_precalc->sx;
- const float sy = isect_precalc->sy;
- const float sz = isect_precalc->sz;
-
- /* Calculate vertices relative to ray origin. */
- const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]};
- const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]};
- const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]};
-
- const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz];
- const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz];
- const float c_kx = c[kx], c_ky = c[ky], c_kz = c[kz];
-
- /* Perform shear and scale of vertices. */
- const float ax = a_kx - sx * a_kz;
- const float ay = a_ky - sy * a_kz;
- const float bx = b_kx - sx * b_kz;
- const float by = b_ky - sy * b_kz;
- const float cx = c_kx - sx * c_kz;
- const float cy = c_ky - sy * c_kz;
-
- /* Calculate scaled barycentric coordinates. */
- const float u = cx * by - cy * bx;
- const float v = ax * cy - ay * cx;
- const float w = bx * ay - by * ax;
- float det;
-
- if ((u < 0.0f || v < 0.0f || w < 0.0f) &&
- (u > 0.0f || v > 0.0f || w > 0.0f))
- {
- return false;
- }
-
- /* Calculate determinant. */
- det = u + v + w;
- if (UNLIKELY(det == 0.0f)) {
- return false;
- }
- else {
- /* Calculate scaled z-coordinates of vertices and use them to calculate
- * the hit distance.
- */
- const float t = (u * a_kz + v * b_kz + w * c_kz) * sz;
- /* Normalize u, v and t. */
- const float inv_det = 1.0f / det;
- if (r_uv) {
- r_uv[0] = u * inv_det;
- r_uv[1] = v * inv_det;
- }
- *r_lambda = t * inv_det;
- return true;
- }
-}
-
-MALWAYS_INLINE int isec_tri_quad(const float start[3],
- const struct IsectRayPrecalc *isect_precalc,
- const RayFace *face,
- float r_uv[2], float *r_lambda)
-{
- float uv[2], l;
-
- if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
- /* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
- r_uv[0] = -uv[0];
- r_uv[1] = -uv[1];
- *r_lambda = l;
- return 1;
- }
- }
-
- /* intersect second triangle in quad */
- if (RE_rayface_isQuad(face)) {
- if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
- /* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
- r_uv[0] = -uv[0];
- r_uv[1] = -uv[1];
- *r_lambda = l;
- return 2;
- }
- }
- }
-
- return 0;
-}
-
-/* Simpler yes/no Ray Triangle/Quad Intersection */
-
-MALWAYS_INLINE int isec_tri_quad_neighbour(const float start[3],
- const float dir[3],
- const RayFace *face)
-{
- float r[3];
- struct IsectRayPrecalc isect_precalc;
- float uv[2], l;
-
- negate_v3_v3(r, dir); /* note, different than above function */
-
- isect_ray_tri_watertight_v3_precalc(&isect_precalc, r);
-
- if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
- return 1;
- }
-
- /* intersect second triangle in quad */
- if (RE_rayface_isQuad(face)) {
- if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
- return 2;
- }
- }
-
- return 0;
-}
-
-/* RayFace intersection with checks and neighbor verifaction included,
- * Isect is modified if the face is hit. */
-
-MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is)
-{
- float dist, uv[2];
- int ok = 0;
-
- /* avoid self-intersection */
- if (is->orig.ob == face->ob && is->orig.face == face->face)
- return 0;
-
- /* check if we should intersect this face */
- if (is->check == RE_CHECK_VLR_RENDER) {
- if (vlr_check_intersect(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
- return 0;
- }
- else if (is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL) {
- if (vlr_check_intersect(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
- return 0;
- if (vlr_check_intersect_solid(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
- return 0;
- }
- else if (is->check == RE_CHECK_VLR_BAKE) {
- if (vlr_check_bake(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
- return 0;
- }
-
- /* ray counter */
- RE_RC_COUNT(is->raycounter->faces.test);
-
- dist = is->dist;
- ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist);
-
- if (ok) {
-
- /* when a shadow ray leaves a face, it can be little outside the edges
- * of it, causing intersection to be detected in its neighbor face */
- if (is->skip & RE_SKIP_VLR_NEIGHBOUR) {
- if (dist < 0.1f && is->orig.ob == face->ob) {
- VlakRen *a = (VlakRen *)is->orig.face;
- VlakRen *b = (VlakRen *)face->face;
- ObjectRen *obr = ((ObjectInstanceRen *)face->ob)->obr;
-
- VertRen **va, **vb;
- int *org_idx_a, *org_idx_b;
- int i, j;
- bool is_neighbor = false;
-
- /* "same" vertex means either the actual same VertRen, or the same 'final org index', if available
- * (autosmooth only, currently). */
- for (i = 0, va = &a->v1; !is_neighbor && i < 4 && *va; ++i, ++va) {
- org_idx_a = RE_vertren_get_origindex(obr, *va, false);
- for (j = 0, vb = &b->v1; !is_neighbor && j < 4 && *vb; ++j, ++vb) {
- if (*va == *vb) {
- is_neighbor = true;
- }
- else if (org_idx_a) {
- org_idx_b = RE_vertren_get_origindex(obr, *vb, 0);
- if (org_idx_b && *org_idx_a == *org_idx_b) {
- is_neighbor = true;
- }
- }
- }
- }
-
- /* So there's a shared edge or vertex, let's intersect ray with self, if that's true
- * we can safely return 1, otherwise we assume the intersection is invalid, 0 */
- if (is_neighbor) {
- /* create RayFace from original face, transformed if necessary */
- RayFace origface;
- ObjectInstanceRen *ob = (ObjectInstanceRen *)is->orig.ob;
- rayface_from_vlak(&origface, ob, (VlakRen *)is->orig.face);
-
- if (!isec_tri_quad_neighbour(is->start, is->dir, &origface)) {
- return 0;
- }
- }
- }
- }
-
- RE_RC_COUNT(is->raycounter->faces.hit);
-
- is->isect = ok; // which half of the quad
- is->dist = dist;
- is->u = uv[0]; is->v = uv[1];
-
- is->hit.ob = face->ob;
- is->hit.face = face->face;
-#ifdef RT_USE_LAST_HIT
- is->last_hit = hit_obj;
-#endif
- return 1;
- }
-
- return 0;
-}
-
-/* Intersection */
-
-int RE_rayobject_raycast(RayObject *r, Isect *isec)
-{
- int i;
-
- /* Pre-calculate orientation for watertight intersection checks. */
- isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
-
- RE_RC_COUNT(isec->raycounter->raycast.test);
-
- /* setup vars used on raycast */
- for (i = 0; i < 3; i++) {
- isec->idot_axis[i] = 1.0f / isec->dir[i];
-
- isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
- isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
-
- isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
- isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
- }
-
-#ifdef RT_USE_LAST_HIT
- /* last hit heuristic */
- if (isec->mode == RE_RAY_SHADOW && isec->last_hit) {
- RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test);
-
- if (RE_rayobject_intersect(isec->last_hit, isec)) {
- RE_RC_COUNT(isec->raycounter->raycast.hit);
- RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.hit);
- return 1;
- }
- }
-#endif
-
-#ifdef RT_USE_HINT
- isec->hit_hint = 0;
-#endif
-
- if (RE_rayobject_intersect(r, isec)) {
- RE_RC_COUNT(isec->raycounter->raycast.hit);
-
-#ifdef RT_USE_HINT
- isec->hint = isec->hit_hint;
-#endif
- return 1;
- }
-
- return 0;
-}
-
-int RE_rayobject_intersect(RayObject *r, Isect *i)
-{
- if (RE_rayobject_isRayFace(r)) {
- return intersect_rayface(r, (RayFace *) RE_rayobject_align(r), i);
- }
- else if (RE_rayobject_isVlakPrimitive(r)) {
- //TODO optimize (useless copy to RayFace to avoid duplicate code)
- VlakPrimitive *face = (VlakPrimitive *) RE_rayobject_align(r);
- RayFace nface;
- rayface_from_vlak(&nface, face->ob, face->face);
-
- return intersect_rayface(r, &nface, i);
- }
- else if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- return r->api->raycast(r, i);
- }
- else {
- assert(0);
- return 0;
- }
-}
-
-/* Building */
-
-void RE_rayobject_add(RayObject *r, RayObject *o)
-{
- r = RE_rayobject_align(r);
- return r->api->add(r, o);
-}
-
-void RE_rayobject_done(RayObject *r)
-{
- r = RE_rayobject_align(r);
- r->api->done(r);
-}
-
-void RE_rayobject_free(RayObject *r)
-{
- r = RE_rayobject_align(r);
- r->api->free(r);
-}
-
-float RE_rayobject_cost(RayObject *r)
-{
- if (RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) {
- return 1.0f;
- }
- else if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- return r->api->cost(r);
- }
- else {
- assert(0);
- return 1.0f;
- }
-}
-
-/* Bounding Boxes */
-
-void RE_rayobject_merge_bb(RayObject *r, float min[3], float max[3])
-{
- if (RE_rayobject_isRayFace(r)) {
- RayFace *face = (RayFace *) RE_rayobject_align(r);
-
- DO_MINMAX(face->v1, min, max);
- DO_MINMAX(face->v2, min, max);
- DO_MINMAX(face->v3, min, max);
- if (RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max);
- }
- else if (RE_rayobject_isVlakPrimitive(r)) {
- VlakPrimitive *face = (VlakPrimitive *) RE_rayobject_align(r);
- RayFace nface;
- rayface_from_vlak(&nface, face->ob, face->face);
-
- DO_MINMAX(nface.v1, min, max);
- DO_MINMAX(nface.v2, min, max);
- DO_MINMAX(nface.v3, min, max);
- if (RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max);
- }
- else if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- r->api->bb(r, min, max);
- }
- else
- assert(0);
-}
-
-/* Hints */
-
-void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max)
-{
- if (RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) {
- return;
- }
- else if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- return r->api->hint_bb(r, hint, min, max);
- }
- else
- assert(0);
-}
-
-/* RayObjectControl */
-
-int RE_rayobjectcontrol_test_break(RayObjectControl *control)
-{
- if (control->test_break)
- return control->test_break(control->data);
-
- return 0;
-}
-
-void RE_rayobject_set_control(RayObject *r, void *data, RE_rayobjectcontrol_test_break_callback test_break)
-{
- if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- r->control.data = data;
- r->control.test_break = test_break;
- }
-}
diff --git a/source/blender/render/intern/raytrace/rayobject_empty.cpp b/source/blender/render/intern/raytrace/rayobject_empty.cpp
deleted file mode 100644
index b0531601640..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_empty.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * ***** 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) 1990-1998 NeoGeo BV.
- * All rights reserved.
- *
- * Contributors: 2004/2005 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_empty.cpp
- * \ingroup render
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "rayobject.h"
-
-#include "BLI_utildefines.h"
-
-/*
- * Empty raytree
- */
-
-static int RE_rayobject_empty_intersect(RayObject *UNUSED(o), Isect *UNUSED(is))
-{
- return 0;
-}
-
-static void RE_rayobject_empty_free(RayObject *UNUSED(o))
-{
-}
-
-static void RE_rayobject_empty_bb(RayObject *UNUSED(o), float *UNUSED(min), float *UNUSED(max))
-{
- return;
-}
-
-static float RE_rayobject_empty_cost(RayObject *UNUSED(o))
-{
- return 0.0;
-}
-
-static void RE_rayobject_empty_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
- float *UNUSED(min), float *UNUSED(max))
-{}
-
-static RayObjectAPI empty_api =
-{
- RE_rayobject_empty_intersect,
- NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
- NULL, //static void RE_rayobject_instance_done(RayObject *o);
- RE_rayobject_empty_free,
- RE_rayobject_empty_bb,
- RE_rayobject_empty_cost,
- RE_rayobject_empty_hint_bb
-};
-
-static RayObject empty_raytree = { &empty_api, {NULL, NULL} };
-
-RayObject *RE_rayobject_empty_create()
-{
- return RE_rayobject_unalignRayAPI( &empty_raytree );
-}
diff --git a/source/blender/render/intern/raytrace/rayobject_hint.h b/source/blender/render/intern/raytrace/rayobject_hint.h
deleted file mode 100644
index 88a32819bd2..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_hint.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_hint.h
- * \ingroup render
- */
-
-
-#ifndef __RAYOBJECT_HINT_H__
-#define __RAYOBJECT_HINT_H__
-
-#define HINT_RECURSE 1
-#define HINT_ACCEPT 0
-#define HINT_DISCARD -1
-
-struct HintBB {
- float bb[6];
-};
-
-inline int hint_test_bb(HintBB *obj, float *Nmin, float *Nmax)
-{
- if (bb_fits_inside(Nmin, Nmax, obj->bb, obj->bb + 3) )
- return HINT_RECURSE;
- else
- return HINT_ACCEPT;
-}
-#if 0
-struct HintFrustum {
- float co[3];
- float no[4][3];
-};
-
-inline int hint_test_bb(HintFrustum &obj, float *Nmin, float *Nmax)
-{
- //if frustum inside BB
- {
- return HINT_RECURSE;
- }
- //if BB outside frustum
- {
- return HINT_DISCARD;
- }
-
- return HINT_ACCEPT;
-}
-#endif
-
-#endif /* __RAYOBJECT_HINT_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp
deleted file mode 100644
index 4497f34cebd..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_instance.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_instance.cpp
- * \ingroup render
- */
-
-
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-
-#define RE_COST_INSTANCE (1.0f)
-
-static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec);
-static void RE_rayobject_instance_free(RayObject *o);
-static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max);
-static float RE_rayobject_instance_cost(RayObject *o);
-
-static void RE_rayobject_instance_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
- float *UNUSED(min), float *UNUSED(max))
-{}
-
-static RayObjectAPI instance_api =
-{
- RE_rayobject_instance_intersect,
- NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
- NULL, //static void RE_rayobject_instance_done(RayObject *o);
- RE_rayobject_instance_free,
- RE_rayobject_instance_bb,
- RE_rayobject_instance_cost,
- RE_rayobject_instance_hint_bb
-};
-
-typedef struct InstanceRayObject {
- RayObject rayobj;
- RayObject *target;
-
- void *ob; //Object represented by this instance
- void *target_ob; //Object represented by the inner RayObject, needed to handle self-intersection
-
- float global2target[4][4];
- float target2global[4][4];
-
-} InstanceRayObject;
-
-
-RayObject *RE_rayobject_instance_create(RayObject *target, float transform[4][4], void *ob, void *target_ob)
-{
- InstanceRayObject *obj = (InstanceRayObject *)MEM_callocN(sizeof(InstanceRayObject), "InstanceRayObject");
- assert(RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
-
- obj->rayobj.api = &instance_api;
- obj->target = target;
- obj->ob = ob;
- obj->target_ob = target_ob;
-
- copy_m4_m4(obj->target2global, transform);
- invert_m4_m4(obj->global2target, obj->target2global);
-
- return RE_rayobject_unalignRayAPI((RayObject *) obj);
-}
-
-static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
-{
- InstanceRayObject *obj = (InstanceRayObject *)o;
- float start[3], dir[3], idot_axis[3], dist;
- int changed = 0, i, res;
-
- // TODO - this is disabling self intersection on instances
- if (isec->orig.ob == obj->ob && obj->ob) {
- changed = 1;
- isec->orig.ob = obj->target_ob;
- }
-
- // backup old values
- copy_v3_v3(start, isec->start);
- copy_v3_v3(dir, isec->dir);
- copy_v3_v3(idot_axis, isec->idot_axis);
- dist = isec->dist;
-
- // transform to target coordinates system
- mul_m4_v3(obj->global2target, isec->start);
- mul_mat3_m4_v3(obj->global2target, isec->dir);
- isec->dist *= normalize_v3(isec->dir);
-
- // update idot_axis and bv_index
- for (i = 0; i < 3; i++) {
- isec->idot_axis[i] = 1.0f / isec->dir[i];
-
- isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
- isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
-
- isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
- isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
- }
-
- // Pre-calculate orientation for watertight intersection checks.
- isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
-
- // raycast
- res = RE_rayobject_intersect(obj->target, isec);
-
- // map dist into original coordinate space
- if (res == 0) {
- isec->dist = dist;
- }
- else {
- // note we don't just multiply dist, because of possible
- // non-uniform scaling in the transform matrix
- float vec[3];
-
- mul_v3_v3fl(vec, isec->dir, isec->dist);
- mul_mat3_m4_v3(obj->target2global, vec);
-
- isec->dist = len_v3(vec);
- isec->hit.ob = obj->ob;
-
-#ifdef RT_USE_LAST_HIT
- // TODO support for last hit optimization in instances that can jump
- // directly to the last hit face.
- // For now it jumps directly to the last-hit instance root node.
- isec->last_hit = RE_rayobject_unalignRayAPI((RayObject *) obj);
-#endif
- }
-
- // restore values
- copy_v3_v3(isec->start, start);
- copy_v3_v3(isec->dir, dir);
- copy_v3_v3(isec->idot_axis, idot_axis);
-
- if (changed)
- isec->orig.ob = obj->ob;
-
- // restore bv_index
- for (i = 0; i < 3; i++) {
- isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
- isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
-
- isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
- isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
- }
-
- // Pre-calculate orientation for watertight intersection checks.
- isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
-
- return res;
-}
-
-static void RE_rayobject_instance_free(RayObject *o)
-{
- InstanceRayObject *obj = (InstanceRayObject *)o;
- MEM_freeN(obj);
-}
-
-static float RE_rayobject_instance_cost(RayObject *o)
-{
- InstanceRayObject *obj = (InstanceRayObject *)o;
- return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE;
-}
-
-static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
-{
- //TODO:
- // *better bb.. calculated without rotations of bb
- // *maybe cache that better-fitted-BB at the InstanceRayObject
- InstanceRayObject *obj = (InstanceRayObject *)o;
-
- float m[3], M[3], t[3];
- int i, j;
- INIT_MINMAX(m, M);
- RE_rayobject_merge_bb(obj->target, m, M);
-
- //There must be a faster way than rotating all the 8 vertexs of the BB
- for (i = 0; i < 8; i++) {
- for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j];
- mul_m4_v3(obj->target2global, t);
- DO_MINMAX(t, min, max);
- }
-}
diff --git a/source/blender/render/intern/raytrace/rayobject_internal.h b/source/blender/render/intern/raytrace/rayobject_internal.h
deleted file mode 100644
index e24ce568c6b..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_internal.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __RAYOBJECT_INTERNAL_H__
-#define __RAYOBJECT_INTERNAL_H__
-
-/** \file blender/render/intern/raytrace/rayobject_internal.h
- * \ingroup render
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* RayObjectControl
- *
- * This class is intended as a place holder for control, configuration of the
- * rayobject like:
- * - stop building (TODO maybe when porting build to threads this could be
- * implemented with some thread_cancel function)
- * - max number of threads and threads callback to use during build
- * ...
- */
-
-typedef int (*RE_rayobjectcontrol_test_break_callback)(void *data);
-
-typedef struct RayObjectControl {
- void *data;
- RE_rayobjectcontrol_test_break_callback test_break;
-} RayObjectControl;
-
-/* Returns true if for some reason a heavy processing function should stop
- * (eg.: user asked to stop during a tree a build)
- */
-
-int RE_rayobjectcontrol_test_break(RayObjectControl *c);
-
-/* RayObject
- *
- * A ray object is everything where we can cast rays like:
- * * a face/triangle
- * * an octree
- * * a bvh tree
- * * an octree of bvh's
- * * a bvh of bvh's
- *
- *
- * All types of RayObjects can be created by implementing the
- * callbacks of the RayObject.
- *
- * Due to high computing time evolved with casting on faces
- * there is a special type of RayObject (named RayFace)
- * which won't use callbacks like other generic nodes.
- *
- * In order to allow a mixture of RayFace+RayObjects,
- * all RayObjects must be 4byte aligned, allowing us to use the
- * 2 least significant bits (with the mask 0x03) to define the
- * type of RayObject.
- *
- * This leads to 4 possible types of RayObject:
- *
- * addr&3 - type of object
- * 0 Self (reserved for each structure)
- * 1 RayFace (tri/quad primitive)
- * 2 RayObject (generic with API callbacks)
- * 3 VlakPrimitive
- * (vlak primitive - to be used when we have a vlak describing the data
- * eg.: on render code)
- *
- * 0 means it's reserved and has it own meaning inside each ray acceleration structure
- * (this way each structure can use the align offset to determine if a node represents a
- * RayObject primitive, which can be used to save memory)
- */
-
-/* used to test the type of ray object */
-#define RE_rayobject_isAligned(o) ((((intptr_t)o)&3) == 0)
-#define RE_rayobject_isRayFace(o) ((((intptr_t)o)&3) == 1)
-#define RE_rayobject_isRayAPI(o) ((((intptr_t)o)&3) == 2)
-#define RE_rayobject_isVlakPrimitive(o) ((((intptr_t)o)&3) == 3)
-
-/* used to align a given ray object */
-#define RE_rayobject_align(o) ((RayObject *)(((intptr_t)o)&(~3)))
-
-/* used to unalign a given ray object */
-#define RE_rayobject_unalignRayFace(o) ((RayObject *)(((intptr_t)o)|1))
-#define RE_rayobject_unalignRayAPI(o) ((RayObject *)(((intptr_t)o)|2))
-#define RE_rayobject_unalignVlakPrimitive(o) ((RayObject *)(((intptr_t)o)|3))
-
-/*
- * This rayobject represents a generic object. With it's own callbacks for raytrace operations.
- * It's suitable to implement things like LOD.
- */
-
-struct RayObject {
- struct RayObjectAPI *api;
- struct RayObjectControl control;
-};
-
-typedef int (*RE_rayobject_raycast_callback)(RayObject *, struct Isect *);
-typedef void (*RE_rayobject_add_callback)(RayObject *raytree, RayObject *rayobject);
-typedef void (*RE_rayobject_done_callback)(RayObject *);
-typedef void (*RE_rayobject_free_callback)(RayObject *);
-typedef void (*RE_rayobject_merge_bb_callback)(RayObject *, float min[3], float max[3]);
-typedef float (*RE_rayobject_cost_callback)(RayObject *);
-typedef void (*RE_rayobject_hint_bb_callback)(RayObject *, struct RayHint *, float min[3], float max[3]);
-
-typedef struct RayObjectAPI {
- RE_rayobject_raycast_callback raycast;
- RE_rayobject_add_callback add;
- RE_rayobject_done_callback done;
- RE_rayobject_free_callback free;
- RE_rayobject_merge_bb_callback bb;
- RE_rayobject_cost_callback cost;
- RE_rayobject_hint_bb_callback hint_bb;
-} RayObjectAPI;
-
-/*
- * Returns the expected cost of raycast on this node, primitives have a cost of 1
- */
-float RE_rayobject_cost(RayObject *r);
-
-/*
- * This function differs from RE_rayobject_raycast
- * RE_rayobject_intersect does NOT perform last-hit optimization
- * So this is probably a function to call inside raytrace structures
- */
-int RE_rayobject_intersect(RayObject *r, struct Isect *i);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RAYOBJECT_INTERNAL_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_octree.cpp b/source/blender/render/intern/raytrace/rayobject_octree.cpp
deleted file mode 100644
index 466d5e28b24..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_octree.cpp
+++ /dev/null
@@ -1,1098 +0,0 @@
-/*
- * ***** 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) 1990-1998 NeoGeo BV.
- * All rights reserved.
- *
- * Contributors: 2004/2005 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_octree.cpp
- * \ingroup render
- */
-
-
-/* IMPORTANT NOTE: this code must be independent of any other render code
- * to use it outside the renderer! */
-
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <float.h>
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_material_types.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-
-/* ********** structs *************** */
-#define BRANCH_ARRAY 1024
-#define NODE_ARRAY 4096
-
-typedef struct Branch {
- struct Branch *b[8];
-} Branch;
-
-typedef struct OcVal {
- short ocx, ocy, ocz;
-} OcVal;
-
-typedef struct Node {
- struct RayFace *v[8];
- struct OcVal ov[8];
- struct Node *next;
-} Node;
-
-typedef struct Octree {
- RayObject rayobj;
-
- struct Branch **adrbranch;
- struct Node **adrnode;
- float ocsize; /* ocsize: mult factor, max size octree */
- float ocfacx, ocfacy, ocfacz;
- float min[3], max[3];
- int ocres;
- int branchcount, nodecount;
-
- /* during building only */
- char *ocface;
-
- RayFace **ro_nodes;
- int ro_nodes_size, ro_nodes_used;
-
-} Octree;
-
-static int RE_rayobject_octree_intersect(RayObject *o, Isect *isec);
-static void RE_rayobject_octree_add(RayObject *o, RayObject *ob);
-static void RE_rayobject_octree_done(RayObject *o);
-static void RE_rayobject_octree_free(RayObject *o);
-static void RE_rayobject_octree_bb(RayObject *o, float *min, float *max);
-
-/*
- * This function is not expected to be called by current code state.
- */
-static float RE_rayobject_octree_cost(RayObject *UNUSED(o))
-{
- return 1.0;
-}
-
-static void RE_rayobject_octree_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
- float *UNUSED(min), float *UNUSED(max))
-{
- return;
-}
-
-static RayObjectAPI octree_api =
-{
- RE_rayobject_octree_intersect,
- RE_rayobject_octree_add,
- RE_rayobject_octree_done,
- RE_rayobject_octree_free,
- RE_rayobject_octree_bb,
- RE_rayobject_octree_cost,
- RE_rayobject_octree_hint_bb
-};
-
-/* **************** ocval method ******************* */
-/* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */
-
-#define OCVALRES 15
-#define BROW16(min, max) \
- (((max) >= OCVALRES ? 0xFFFF : (1 << ((max) + 1)) - 1) - (((min) > 0) ? ((1 << (min)) - 1) : 0))
-
-static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov)
-{
- float min[3], max[3];
- int ocmin, ocmax;
-
- copy_v3_v3(min, v1);
- copy_v3_v3(max, v1);
- DO_MINMAX(v2, min, max);
- DO_MINMAX(v3, min, max);
- if (v4) {
- DO_MINMAX(v4, min, max);
- }
-
- ocmin = OCVALRES * (min[0] - x);
- ocmax = OCVALRES * (max[0] - x);
- ov->ocx = BROW16(ocmin, ocmax);
-
- ocmin = OCVALRES * (min[1] - y);
- ocmax = OCVALRES * (max[1] - y);
- ov->ocy = BROW16(ocmin, ocmax);
-
- ocmin = OCVALRES * (min[2] - z);
- ocmax = OCVALRES * (max[2] - z);
- ov->ocz = BROW16(ocmin, ocmax);
-
-}
-
-static void calc_ocval_ray(OcVal *ov, float xo, float yo, float zo, float *vec1, float *vec2)
-{
- int ocmin, ocmax;
-
- if (vec1[0] < vec2[0]) {
- ocmin = OCVALRES * (vec1[0] - xo);
- ocmax = OCVALRES * (vec2[0] - xo);
- }
- else {
- ocmin = OCVALRES * (vec2[0] - xo);
- ocmax = OCVALRES * (vec1[0] - xo);
- }
- ov->ocx = BROW16(ocmin, ocmax);
-
- if (vec1[1] < vec2[1]) {
- ocmin = OCVALRES * (vec1[1] - yo);
- ocmax = OCVALRES * (vec2[1] - yo);
- }
- else {
- ocmin = OCVALRES * (vec2[1] - yo);
- ocmax = OCVALRES * (vec1[1] - yo);
- }
- ov->ocy = BROW16(ocmin, ocmax);
-
- if (vec1[2] < vec2[2]) {
- ocmin = OCVALRES * (vec1[2] - zo);
- ocmax = OCVALRES * (vec2[2] - zo);
- }
- else {
- ocmin = OCVALRES * (vec2[2] - zo);
- ocmax = OCVALRES * (vec1[2] - zo);
- }
- ov->ocz = BROW16(ocmin, ocmax);
-}
-
-/* ************* octree ************** */
-
-static Branch *addbranch(Octree *oc, Branch *br, short ocb)
-{
- int index;
-
- if (br->b[ocb]) return br->b[ocb];
-
- oc->branchcount++;
- index = oc->branchcount >> 12;
-
- if (oc->adrbranch[index] == NULL)
- oc->adrbranch[index] = (Branch *)MEM_callocN(4096 * sizeof(Branch), "new oc branch");
-
- if (oc->branchcount >= BRANCH_ARRAY * 4096) {
- printf("error; octree branches full\n");
- oc->branchcount = 0;
- }
-
- return br->b[ocb] = oc->adrbranch[index] + (oc->branchcount & 4095);
-}
-
-static Node *addnode(Octree *oc)
-{
- int index;
-
- oc->nodecount++;
- index = oc->nodecount >> 12;
-
- if (oc->adrnode[index] == NULL)
- oc->adrnode[index] = (Node *)MEM_callocN(4096 * sizeof(Node), "addnode");
-
- if (oc->nodecount > NODE_ARRAY * NODE_ARRAY) {
- printf("error; octree nodes full\n");
- oc->nodecount = 0;
- }
-
- return oc->adrnode[index] + (oc->nodecount & 4095);
-}
-
-static bool face_in_node(RayFace *face, short x, short y, short z, float rtf[4][3])
-{
- static float nor[3], d;
- float fx, fy, fz;
-
- // init static vars
- if (face) {
- normal_tri_v3(nor, rtf[0], rtf[1], rtf[2]);
- d = -nor[0] * rtf[0][0] - nor[1] * rtf[0][1] - nor[2] * rtf[0][2];
- return 0;
- }
-
- fx = x;
- fy = y;
- fz = z;
-
- if ((fx) * nor[0] + (fy) * nor[1] + (fz) * nor[2] + d > 0.0f) {
- if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
- if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
-
- if ((fx ) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
- if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
- }
- else {
- if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
- if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
-
- if ((fx ) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
- if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
- if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
- }
-
- return 0;
-}
-
-static void ocwrite(Octree *oc, RayFace *face, int quad, short x, short y, short z, float rtf[4][3])
-{
- Branch *br;
- Node *no;
- short a, oc0, oc1, oc2, oc3, oc4, oc5;
-
- x <<= 2;
- y <<= 1;
-
- br = oc->adrbranch[0];
-
- if (oc->ocres == 512) {
- oc0 = ((x & 1024) + (y & 512) + (z & 256)) >> 8;
- br = addbranch(oc, br, oc0);
- }
- if (oc->ocres >= 256) {
- oc0 = ((x & 512) + (y & 256) + (z & 128)) >> 7;
- br = addbranch(oc, br, oc0);
- }
- if (oc->ocres >= 128) {
- oc0 = ((x & 256) + (y & 128) + (z & 64)) >> 6;
- br = addbranch(oc, br, oc0);
- }
-
- oc0 = ((x & 128) + (y & 64) + (z & 32)) >> 5;
- oc1 = ((x & 64) + (y & 32) + (z & 16)) >> 4;
- oc2 = ((x & 32) + (y & 16) + (z & 8)) >> 3;
- oc3 = ((x & 16) + (y & 8) + (z & 4)) >> 2;
- oc4 = ((x & 8) + (y & 4) + (z & 2)) >> 1;
- oc5 = ((x & 4) + (y & 2) + (z & 1));
-
- br = addbranch(oc, br, oc0);
- br = addbranch(oc, br, oc1);
- br = addbranch(oc, br, oc2);
- br = addbranch(oc, br, oc3);
- br = addbranch(oc, br, oc4);
- no = (Node *)br->b[oc5];
- if (no == NULL) br->b[oc5] = (Branch *)(no = addnode(oc));
-
- while (no->next) no = no->next;
-
- a = 0;
- if (no->v[7]) { /* node full */
- no->next = addnode(oc);
- no = no->next;
- }
- else {
- while (no->v[a] != NULL) a++;
- }
-
- no->v[a] = (RayFace *) RE_rayobject_align(face);
-
- if (quad)
- calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x >> 2, y >> 1, z, &no->ov[a]);
- else
- calc_ocval_face(rtf[0], rtf[1], rtf[2], NULL, x >> 2, y >> 1, z, &no->ov[a]);
-}
-
-static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocface, short rts[4][3], float rtf[4][3])
-{
- int ocx1, ocx2, ocy1, ocy2;
- int x, y, dx = 0, dy = 0;
- float ox1, ox2, oy1, oy2;
- float lambda, lambda_o, lambda_x, lambda_y, ldx, ldy;
-
- ocx1 = rts[b1][c1];
- ocy1 = rts[b1][c2];
- ocx2 = rts[b2][c1];
- ocy2 = rts[b2][c2];
-
- if (ocx1 == ocx2 && ocy1 == ocy2) {
- ocface[oc->ocres * ocx1 + ocy1] = 1;
- return;
- }
-
- ox1 = rtf[b1][c1];
- oy1 = rtf[b1][c2];
- ox2 = rtf[b2][c1];
- oy2 = rtf[b2][c2];
-
- if (ox1 != ox2) {
- if (ox2 - ox1 > 0.0f) {
- lambda_x = (ox1 - ocx1 - 1.0f) / (ox1 - ox2);
- ldx = -1.0f / (ox1 - ox2);
- dx = 1;
- }
- else {
- lambda_x = (ox1 - ocx1) / (ox1 - ox2);
- ldx = 1.0f / (ox1 - ox2);
- dx = -1;
- }
- }
- else {
- lambda_x = 1.0f;
- ldx = 0;
- }
-
- if (oy1 != oy2) {
- if (oy2 - oy1 > 0.0f) {
- lambda_y = (oy1 - ocy1 - 1.0f) / (oy1 - oy2);
- ldy = -1.0f / (oy1 - oy2);
- dy = 1;
- }
- else {
- lambda_y = (oy1 - ocy1) / (oy1 - oy2);
- ldy = 1.0f / (oy1 - oy2);
- dy = -1;
- }
- }
- else {
- lambda_y = 1.0f;
- ldy = 0;
- }
-
- x = ocx1; y = ocy1;
- lambda = MIN2(lambda_x, lambda_y);
-
- while (true) {
-
- if (x < 0 || y < 0 || x >= oc->ocres || y >= oc->ocres) {
- /* pass*/
- }
- else {
- ocface[oc->ocres * x + y] = 1;
- }
-
- lambda_o = lambda;
- if (lambda_x == lambda_y) {
- lambda_x += ldx;
- x += dx;
- lambda_y += ldy;
- y += dy;
- }
- else {
- if (lambda_x < lambda_y) {
- lambda_x += ldx;
- x += dx;
- }
- else {
- lambda_y += ldy;
- y += dy;
- }
- }
- lambda = MIN2(lambda_x, lambda_y);
- if (lambda == lambda_o) break;
- if (lambda >= 1.0f) break;
- }
- ocface[oc->ocres * ocx2 + ocy2] = 1;
-}
-
-static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin, short *ocmax)
-{
- int a, x, y, y1, y2;
-
- for (x = ocmin[c1]; x <= ocmax[c1]; x++) {
- a = oc->ocres * x;
- for (y = ocmin[c2]; y <= ocmax[c2]; y++) {
- if (ocface[a + y]) {
- y++;
- while (ocface[a + y] && y != ocmax[c2]) y++;
- for (y1 = ocmax[c2]; y1 > y; y1--) {
- if (ocface[a + y1]) {
- for (y2 = y; y2 <= y1; y2++) ocface[a + y2] = 1;
- y1 = 0;
- }
- }
- y = ocmax[c2];
- }
- }
- }
-}
-
-static void RE_rayobject_octree_free(RayObject *tree)
-{
- Octree *oc = (Octree *)tree;
-
-#if 0
- printf("branches %d nodes %d\n", oc->branchcount, oc->nodecount);
- printf("raycount %d\n", raycount);
- printf("ray coherent %d\n", coherent_ray);
- printf("accepted %d rejected %d\n", accepted, rejected);
-#endif
- if (oc->ocface)
- MEM_freeN(oc->ocface);
-
- if (oc->adrbranch) {
- int a = 0;
- while (oc->adrbranch[a]) {
- MEM_freeN(oc->adrbranch[a]);
- oc->adrbranch[a] = NULL;
- a++;
- }
- MEM_freeN(oc->adrbranch);
- oc->adrbranch = NULL;
- }
- oc->branchcount = 0;
-
- if (oc->adrnode) {
- int a = 0;
- while (oc->adrnode[a]) {
- MEM_freeN(oc->adrnode[a]);
- oc->adrnode[a] = NULL;
- a++;
- }
- MEM_freeN(oc->adrnode);
- oc->adrnode = NULL;
- }
- oc->nodecount = 0;
-
- MEM_freeN(oc);
-}
-
-
-RayObject *RE_rayobject_octree_create(int ocres, int size)
-{
- Octree *oc = (Octree *)MEM_callocN(sizeof(Octree), "Octree");
- assert(RE_rayobject_isAligned(oc) ); /* RayObject API assumes real data to be 4-byte aligned */
-
- oc->rayobj.api = &octree_api;
-
- oc->ocres = ocres;
-
- oc->ro_nodes = (RayFace **)MEM_callocN(sizeof(RayFace *) * size, "octree rayobject nodes");
- oc->ro_nodes_size = size;
- oc->ro_nodes_used = 0;
-
-
- return RE_rayobject_unalignRayAPI((RayObject *) oc);
-}
-
-
-static void RE_rayobject_octree_add(RayObject *tree, RayObject *node)
-{
- Octree *oc = (Octree *)tree;
-
- assert(RE_rayobject_isRayFace(node) );
- assert(oc->ro_nodes_used < oc->ro_nodes_size);
- oc->ro_nodes[oc->ro_nodes_used++] = (RayFace *)RE_rayobject_align(node);
-}
-
-static void octree_fill_rayface(Octree *oc, RayFace *face)
-{
- float ocfac[3], rtf[4][3];
- float co1[3], co2[3], co3[3], co4[3];
- short rts[4][3];
- short ocmin[3], ocmax[3];
- char *ocface = oc->ocface; // front, top, size view of face, to fill in
- int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2;
-
- ocfac[0] = oc->ocfacx;
- ocfac[1] = oc->ocfacy;
- ocfac[2] = oc->ocfacz;
-
- ocres2 = oc->ocres * oc->ocres;
-
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
- if (RE_rayface_isQuad(face))
- copy_v3_v3(co4, face->v4);
-
- for (c = 0; c < 3; c++) {
- rtf[0][c] = (co1[c] - oc->min[c]) * ocfac[c];
- rts[0][c] = (short)rtf[0][c];
- rtf[1][c] = (co2[c] - oc->min[c]) * ocfac[c];
- rts[1][c] = (short)rtf[1][c];
- rtf[2][c] = (co3[c] - oc->min[c]) * ocfac[c];
- rts[2][c] = (short)rtf[2][c];
- if (RE_rayface_isQuad(face)) {
- rtf[3][c] = (co4[c] - oc->min[c]) * ocfac[c];
- rts[3][c] = (short)rtf[3][c];
- }
- }
-
- for (c = 0; c < 3; c++) {
- oc1 = rts[0][c];
- oc2 = rts[1][c];
- oc3 = rts[2][c];
- if (!RE_rayface_isQuad(face)) {
- ocmin[c] = min_iii(oc1, oc2, oc3);
- ocmax[c] = max_iii(oc1, oc2, oc3);
- }
- else {
- oc4 = rts[3][c];
- ocmin[c] = min_iiii(oc1, oc2, oc3, oc4);
- ocmax[c] = max_iiii(oc1, oc2, oc3, oc4);
- }
- if (ocmax[c] > oc->ocres - 1) ocmax[c] = oc->ocres - 1;
- if (ocmin[c] < 0) ocmin[c] = 0;
- }
-
- if (ocmin[0] == ocmax[0] && ocmin[1] == ocmax[1] && ocmin[2] == ocmax[2]) {
- ocwrite(oc, face, RE_rayface_isQuad(face), ocmin[0], ocmin[1], ocmin[2], rtf);
- }
- else {
-
- d2dda(oc, 0, 1, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 0, 1, 0, 2, ocface, rts, rtf);
- d2dda(oc, 0, 1, 1, 2, ocface + 2 * ocres2, rts, rtf);
- d2dda(oc, 1, 2, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 1, 2, 0, 2, ocface, rts, rtf);
- d2dda(oc, 1, 2, 1, 2, ocface + 2 * ocres2, rts, rtf);
- if (!RE_rayface_isQuad(face)) {
- d2dda(oc, 2, 0, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 2, 0, 0, 2, ocface, rts, rtf);
- d2dda(oc, 2, 0, 1, 2, ocface + 2 * ocres2, rts, rtf);
- }
- else {
- d2dda(oc, 2, 3, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 2, 3, 0, 2, ocface, rts, rtf);
- d2dda(oc, 2, 3, 1, 2, ocface + 2 * ocres2, rts, rtf);
- d2dda(oc, 3, 0, 0, 1, ocface + ocres2, rts, rtf);
- d2dda(oc, 3, 0, 0, 2, ocface, rts, rtf);
- d2dda(oc, 3, 0, 1, 2, ocface + 2 * ocres2, rts, rtf);
- }
- /* nothing todo with triangle..., just fills :) */
- filltriangle(oc, 0, 1, ocface + ocres2, ocmin, ocmax);
- filltriangle(oc, 0, 2, ocface, ocmin, ocmax);
- filltriangle(oc, 1, 2, ocface + 2 * ocres2, ocmin, ocmax);
-
- /* init static vars here */
- face_in_node(face, 0, 0, 0, rtf);
-
- for (x = ocmin[0]; x <= ocmax[0]; x++) {
- a = oc->ocres * x;
- for (y = ocmin[1]; y <= ocmax[1]; y++) {
- if (ocface[a + y + ocres2]) {
- b = oc->ocres * y + 2 * ocres2;
- for (z = ocmin[2]; z <= ocmax[2]; z++) {
- if (ocface[b + z] && ocface[a + z]) {
- if (face_in_node(NULL, x, y, z, rtf))
- ocwrite(oc, face, RE_rayface_isQuad(face), x, y, z, rtf);
- }
- }
- }
- }
- }
-
- /* same loops to clear octree, doubt it can be done smarter */
- for (x = ocmin[0]; x <= ocmax[0]; x++) {
- a = oc->ocres * x;
- for (y = ocmin[1]; y <= ocmax[1]; y++) {
- /* x-y */
- ocface[a + y + ocres2] = 0;
-
- b = oc->ocres * y + 2 * ocres2;
- for (z = ocmin[2]; z <= ocmax[2]; z++) {
- /* y-z */
- ocface[b + z] = 0;
- /* x-z */
- ocface[a + z] = 0;
- }
- }
- }
- }
-}
-
-static void RE_rayobject_octree_done(RayObject *tree)
-{
- Octree *oc = (Octree *)tree;
- int c;
- float t00, t01, t02;
- int ocres2 = oc->ocres * oc->ocres;
-
- INIT_MINMAX(oc->min, oc->max);
-
- /* Calculate Bounding Box */
- for (c = 0; c < oc->ro_nodes_used; c++)
- RE_rayobject_merge_bb(RE_rayobject_unalignRayFace(oc->ro_nodes[c]), oc->min, oc->max);
-
- /* Alloc memory */
- oc->adrbranch = (Branch **)MEM_callocN(sizeof(void *) * BRANCH_ARRAY, "octree branches");
- oc->adrnode = (Node **)MEM_callocN(sizeof(void *) * NODE_ARRAY, "octree nodes");
-
- oc->adrbranch[0] = (Branch *)MEM_callocN(4096 * sizeof(Branch), "makeoctree");
-
- /* the lookup table, per face, for which nodes to fill in */
- oc->ocface = (char *)MEM_callocN(3 * ocres2 + 8, "ocface");
- memset(oc->ocface, 0, 3 * ocres2);
-
- for (c = 0; c < 3; c++) { /* octree enlarge, still needed? */
- oc->min[c] -= 0.01f;
- oc->max[c] += 0.01f;
- }
-
- t00 = oc->max[0] - oc->min[0];
- t01 = oc->max[1] - oc->min[1];
- t02 = oc->max[2] - oc->min[2];
-
- /* this minus 0.1 is old safety... seems to be needed? */
- oc->ocfacx = (oc->ocres - 0.1f) / t00;
- oc->ocfacy = (oc->ocres - 0.1f) / t01;
- oc->ocfacz = (oc->ocres - 0.1f) / t02;
-
- oc->ocsize = sqrtf(t00 * t00 + t01 * t01 + t02 * t02); /* global, max size octree */
-
- for (c = 0; c < oc->ro_nodes_used; c++) {
- octree_fill_rayface(oc, oc->ro_nodes[c]);
- }
-
- MEM_freeN(oc->ocface);
- oc->ocface = NULL;
- MEM_freeN(oc->ro_nodes);
- oc->ro_nodes = NULL;
-
-#if 0
- printf("%f %f - %f\n", oc->min[0], oc->max[0], oc->ocfacx);
- printf("%f %f - %f\n", oc->min[1], oc->max[1], oc->ocfacy);
- printf("%f %f - %f\n", oc->min[2], oc->max[2], oc->ocfacz);
-#endif
-}
-
-static void RE_rayobject_octree_bb(RayObject *tree, float *min, float *max)
-{
- Octree *oc = (Octree *)tree;
- DO_MINMAX(oc->min, min, max);
- DO_MINMAX(oc->max, min, max);
-}
-
-/* check all faces in this node */
-static int testnode(Octree *UNUSED(oc), Isect *is, Node *no, OcVal ocval)
-{
- short nr = 0;
-
- /* return on any first hit */
- if (is->mode == RE_RAY_SHADOW) {
-
- for (; no; no = no->next) {
- for (nr = 0; nr < 8; nr++) {
- RayFace *face = no->v[nr];
- OcVal *ov = no->ov + nr;
-
- if (!face) break;
-
- if ( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
- if (RE_rayobject_intersect(RE_rayobject_unalignRayFace(face), is) )
- return 1;
- }
- }
- }
- }
- else {
- /* else mirror or glass or shadowtra, return closest face */
- int found = 0;
-
- for (; no; no = no->next) {
- for (nr = 0; nr < 8; nr++) {
- RayFace *face = no->v[nr];
- OcVal *ov = no->ov + nr;
-
- if (!face) break;
-
- if ( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
- if (RE_rayobject_intersect(RE_rayobject_unalignRayFace(face), is) ) {
- found = 1;
- }
- }
- }
- }
-
- return found;
- }
-
- return 0;
-}
-
-/* find the Node for the octree coord x y z */
-static Node *ocread(Octree *oc, int x, int y, int z)
-{
- Branch *br;
- int oc1;
-
- x <<= 2;
- y <<= 1;
-
- br = oc->adrbranch[0];
-
- if (oc->ocres == 512) {
- oc1 = ((x & 1024) + (y & 512) + (z & 256)) >> 8;
- br = br->b[oc1];
- if (br == NULL) {
- return NULL;
- }
- }
- if (oc->ocres >= 256) {
- oc1 = ((x & 512) + (y & 256) + (z & 128)) >> 7;
- br = br->b[oc1];
- if (br == NULL) {
- return NULL;
- }
- }
- if (oc->ocres >= 128) {
- oc1 = ((x & 256) + (y & 128) + (z & 64)) >> 6;
- br = br->b[oc1];
- if (br == NULL) {
- return NULL;
- }
- }
-
- oc1 = ((x & 128) + (y & 64) + (z & 32)) >> 5;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 64) + (y & 32) + (z & 16)) >> 4;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 32) + (y & 16) + (z & 8)) >> 3;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 16) + (y & 8) + (z & 4)) >> 2;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 8) + (y & 4) + (z & 2)) >> 1;
- br = br->b[oc1];
- if (br) {
- oc1 = ((x & 4) + (y & 2) + (z & 1));
- return (Node *)br->b[oc1];
- }
- }
- }
- }
- }
-
- return NULL;
-}
-
-static int cliptest(float p, float q, float *u1, float *u2)
-{
- float r;
-
- if (p < 0.0f) {
- if (q < p) return 0;
- else if (q < 0.0f) {
- r = q / p;
- if (r > *u2) return 0;
- else if (r > *u1) *u1 = r;
- }
- }
- else {
- if (p > 0.0f) {
- if (q < 0.0f) return 0;
- else if (q < p) {
- r = q / p;
- if (r < *u1) return 0;
- else if (r < *u2) *u2 = r;
- }
- }
- else if (q < 0.0f) return 0;
- }
- return 1;
-}
-
-/* extensive coherence checks/storage cancels out the benefit of it, and gives errors... we
- * need better methods, sample code commented out below (ton) */
-
-#if 0
-
-in top : static int coh_nodes[16 * 16 * 16][6];
-in makeoctree : memset(coh_nodes, 0, sizeof(coh_nodes));
-
-static void add_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
-{
- short *sp;
-
- sp = coh_nodes[(ocx2 & 15) + 16 * (ocy2 & 15) + 256 * (ocz2 & 15)];
- sp[0] = ocx1; sp[1] = ocy1; sp[2] = ocz1;
- sp[3] = ocx2; sp[4] = ocy2; sp[5] = ocz2;
-
-}
-
-static int do_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
-{
- short *sp;
-
- sp = coh_nodes[(ocx2 & 15) + 16 * (ocy2 & 15) + 256 * (ocz2 & 15)];
- if (sp[0] == ocx1 && sp[1] == ocy1 && sp[2] == ocz1 &&
- sp[3] == ocx2 && sp[4] == ocy2 && sp[5] == ocz2) return 1;
- return 0;
-}
-
-#endif
-
-/* return 1: found valid intersection */
-/* starts with is->orig.face */
-static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is)
-{
- Octree *oc = (Octree *)tree;
- Node *no;
- OcVal ocval;
- float vec1[3], vec2[3], start[3], end[3];
- float u1, u2, ox1, ox2, oy1, oy2, oz1, oz2;
- float lambda_o, lambda_x, ldx, lambda_y, ldy, lambda_z, ldz, dda_lambda;
- float o_lambda = 0;
- int dx, dy, dz;
- int xo, yo, zo, c1 = 0;
- int ocx1, ocx2, ocy1, ocy2, ocz1, ocz2;
-
- /* clip with octree */
- if (oc->branchcount == 0) return 0;
-
- /* do this before intersect calls */
-#if 0
- is->facecontr = NULL; /* to check shared edge */
- is->obcontr = 0;
- is->faceisect = is->isect = 0; /* shared edge, quad half flag */
- is->userdata = oc->userdata;
-#endif
-
- copy_v3_v3(start, is->start);
- madd_v3_v3v3fl(end, is->start, is->dir, is->dist);
- ldx = is->dir[0] * is->dist;
- o_lambda = is->dist;
- u1 = 0.0f;
- u2 = 1.0f;
-
- /* clip with octree cube */
- if (cliptest(-ldx, start[0] - oc->min[0], &u1, &u2)) {
- if (cliptest(ldx, oc->max[0] - start[0], &u1, &u2)) {
- ldy = is->dir[1] * is->dist;
- if (cliptest(-ldy, start[1] - oc->min[1], &u1, &u2)) {
- if (cliptest(ldy, oc->max[1] - start[1], &u1, &u2)) {
- ldz = is->dir[2] * is->dist;
- if (cliptest(-ldz, start[2] - oc->min[2], &u1, &u2)) {
- if (cliptest(ldz, oc->max[2] - start[2], &u1, &u2)) {
- c1 = 1;
- if (u2 < 1.0f) {
- end[0] = start[0] + u2 * ldx;
- end[1] = start[1] + u2 * ldy;
- end[2] = start[2] + u2 * ldz;
- }
-
- if (u1 > 0.0f) {
- start[0] += u1 * ldx;
- start[1] += u1 * ldy;
- start[2] += u1 * ldz;
- }
- }
- }
- }
- }
- }
- }
-
- if (c1 == 0) return 0;
-
- /* reset static variables in ocread */
- //ocread(oc, oc->ocres, 0, 0);
-
- /* setup 3dda to traverse octree */
- ox1 = (start[0] - oc->min[0]) * oc->ocfacx;
- oy1 = (start[1] - oc->min[1]) * oc->ocfacy;
- oz1 = (start[2] - oc->min[2]) * oc->ocfacz;
- ox2 = (end[0] - oc->min[0]) * oc->ocfacx;
- oy2 = (end[1] - oc->min[1]) * oc->ocfacy;
- oz2 = (end[2] - oc->min[2]) * oc->ocfacz;
-
- ocx1 = (int)ox1;
- ocy1 = (int)oy1;
- ocz1 = (int)oz1;
- ocx2 = (int)ox2;
- ocy2 = (int)oy2;
- ocz2 = (int)oz2;
-
- if (ocx1 == ocx2 && ocy1 == ocy2 && ocz1 == ocz2) {
- no = ocread(oc, ocx1, ocy1, ocz1);
- if (no) {
- /* exact intersection with node */
- vec1[0] = ox1; vec1[1] = oy1; vec1[2] = oz1;
- vec2[0] = ox2; vec2[1] = oy2; vec2[2] = oz2;
- calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2);
- if (testnode(oc, is, no, ocval) ) return 1;
- }
- }
- else {
- int found = 0;
- //static int coh_ocx1, coh_ocx2, coh_ocy1, coh_ocy2, coh_ocz1, coh_ocz2;
- float dox, doy, doz;
- int eqval;
-
- /* calc lambda en ld */
- dox = ox1 - ox2;
- doy = oy1 - oy2;
- doz = oz1 - oz2;
-
- if (dox < -FLT_EPSILON) {
- ldx = -1.0f / dox;
- lambda_x = (ocx1 - ox1 + 1.0f) * ldx;
- dx = 1;
- }
- else if (dox > FLT_EPSILON) {
- ldx = 1.0f / dox;
- lambda_x = (ox1 - ocx1) * ldx;
- dx = -1;
- }
- else {
- lambda_x = 1.0f;
- ldx = 0;
- dx = 0;
- }
-
- if (doy < -FLT_EPSILON) {
- ldy = -1.0f / doy;
- lambda_y = (ocy1 - oy1 + 1.0f) * ldy;
- dy = 1;
- }
- else if (doy > FLT_EPSILON) {
- ldy = 1.0f / doy;
- lambda_y = (oy1 - ocy1) * ldy;
- dy = -1;
- }
- else {
- lambda_y = 1.0f;
- ldy = 0;
- dy = 0;
- }
-
- if (doz < -FLT_EPSILON) {
- ldz = -1.0f / doz;
- lambda_z = (ocz1 - oz1 + 1.0f) * ldz;
- dz = 1;
- }
- else if (doz > FLT_EPSILON) {
- ldz = 1.0f / doz;
- lambda_z = (oz1 - ocz1) * ldz;
- dz = -1;
- }
- else {
- lambda_z = 1.0f;
- ldz = 0;
- dz = 0;
- }
-
- xo = ocx1; yo = ocy1; zo = ocz1;
- dda_lambda = min_fff(lambda_x, lambda_y, lambda_z);
-
- vec2[0] = ox1;
- vec2[1] = oy1;
- vec2[2] = oz1;
-
- /* this loop has been constructed to make sure the first and last node of ray
- * are always included, even when dda_lambda==1.0f or larger */
-
- while (true) {
-
- no = ocread(oc, xo, yo, zo);
- if (no) {
-
- /* calculate ray intersection with octree node */
- copy_v3_v3(vec1, vec2);
- // dox, y, z is negative
- vec2[0] = ox1 - dda_lambda * dox;
- vec2[1] = oy1 - dda_lambda * doy;
- vec2[2] = oz1 - dda_lambda * doz;
- calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2);
-
- //is->dist = (u1 + dda_lambda * (u2 - u1)) * o_lambda;
- if (testnode(oc, is, no, ocval) )
- found = 1;
-
- if (is->dist < (u1 + dda_lambda * (u2 - u1)) * o_lambda)
- return found;
- }
-
-
- lambda_o = dda_lambda;
-
- /* traversing octree nodes need careful detection of smallest values, with proper
- * exceptions for equal lambdas */
- eqval = (lambda_x == lambda_y);
- if (lambda_y == lambda_z) eqval += 2;
- if (lambda_x == lambda_z) eqval += 4;
-
- if (eqval) { // only 4 cases exist!
- if (eqval == 7) { // x=y=z
- xo += dx; lambda_x += ldx;
- yo += dy; lambda_y += ldy;
- zo += dz; lambda_z += ldz;
- }
- else if (eqval == 1) { // x=y
- if (lambda_y < lambda_z) {
- xo += dx; lambda_x += ldx;
- yo += dy; lambda_y += ldy;
- }
- else {
- zo += dz; lambda_z += ldz;
- }
- }
- else if (eqval == 2) { // y=z
- if (lambda_x < lambda_y) {
- xo += dx; lambda_x += ldx;
- }
- else {
- yo += dy; lambda_y += ldy;
- zo += dz; lambda_z += ldz;
- }
- }
- else { // x=z
- if (lambda_y < lambda_x) {
- yo += dy; lambda_y += ldy;
- }
- else {
- xo += dx; lambda_x += ldx;
- zo += dz; lambda_z += ldz;
- }
- }
- }
- else { // all three different, just three cases exist
- eqval = (lambda_x < lambda_y);
- if (lambda_y < lambda_z) eqval += 2;
- if (lambda_x < lambda_z) eqval += 4;
-
- if (eqval == 7 || eqval == 5) { // x smallest
- xo += dx; lambda_x += ldx;
- }
- else if (eqval == 2 || eqval == 6) { // y smallest
- yo += dy; lambda_y += ldy;
- }
- else { // z smallest
- zo += dz; lambda_z += ldz;
- }
-
- }
-
- dda_lambda = min_fff(lambda_x, lambda_y, lambda_z);
- if (dda_lambda == lambda_o) break;
- /* to make sure the last node is always checked */
- if (lambda_o >= 1.0f) break;
- }
- }
-
- /* reached end, no intersections found */
- return 0;
-}
diff --git a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
deleted file mode 100644
index 8e3dd87efd1..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_qbvh.cpp
- * \ingroup render
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-
-#include "vbvh.h"
-#include "svbvh.h"
-#include "reorganize.h"
-
-#ifdef __SSE__
-
-#define DFS_STACK_SIZE 256
-
-struct QBVHTree {
- RayObject rayobj;
-
- SVBVHNode *root;
- MemArena *node_arena;
-
- float cost;
- RTBuilder *builder;
-};
-
-
-template<>
-void bvh_done<QBVHTree>(QBVHTree *obj)
-{
- rtbuild_done(obj->builder, &obj->rayobj.control);
-
- //TODO find a away to exactly calculate the needed memory
- MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "qbvh arena");
- BLI_memarena_use_malloc(arena1);
-
- MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "qbvh arena 2");
- BLI_memarena_use_malloc(arena2);
- BLI_memarena_use_align(arena2, 16);
-
- //Build and optimize the tree
- //TODO do this in 1 pass (half memory usage during building)
- VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
-
- if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
- BLI_memarena_free(arena1);
- BLI_memarena_free(arena2);
- return;
- }
-
- if (root) {
- pushup_simd<VBVHNode, 4>(root);
- obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
- }
- else
- obj->root = NULL;
-
- //Free data
- BLI_memarena_free(arena1);
-
- obj->node_arena = arena2;
- obj->cost = 1.0;
-
- rtbuild_free(obj->builder);
- obj->builder = NULL;
-}
-
-template<int StackSize>
-static int intersect(QBVHTree *obj, Isect *isec)
-{
- //TODO renable hint support
- if (RE_rayobject_isAligned(obj->root)) {
- if (isec->mode == RE_RAY_SHADOW)
- return svbvh_node_stack_raycast<StackSize, true>(obj->root, isec);
- else
- return svbvh_node_stack_raycast<StackSize, false>(obj->root, isec);
- }
- else
- return RE_rayobject_intersect((RayObject *)obj->root, isec);
-}
-
-template<class Tree>
-static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
-{
- //TODO renable hint support
- {
- hint->size = 0;
- hint->stack[hint->size++] = (RayObject *)tree->root;
- }
-}
-/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
-template<class Tree, int STACK_SIZE>
-static RayObjectAPI make_api()
-{
- static RayObjectAPI api =
- {
- (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
- (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
- (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
- (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
- (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
- (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
- (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
- };
-
- return api;
-}
-
-template<class Tree>
-RayObjectAPI *bvh_get_api(int maxstacksize)
-{
- static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
-
- if (maxstacksize <= 1024) return &bvh_api256;
- assert(maxstacksize <= 256);
- return NULL;
-}
-
-RayObject *RE_rayobject_qbvh_create(int size)
-{
- return bvh_create_tree<QBVHTree, DFS_STACK_SIZE>(size);
-}
-
-#else
-
-RayObject *RE_rayobject_qbvh_create(int UNUSED(size))
-{
- puts("WARNING: SSE disabled at compile time\n");
- return NULL;
-}
-
-#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_raycounter.cpp b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp
deleted file mode 100644
index 429c47f1c0f..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_raycounter.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_raycounter.cpp
- * \ingroup render
- */
-
-
-#include "rayobject.h"
-#include "raycounter.h"
-
-#ifdef RE_RAYCOUNTER
-
-void RE_RC_INFO(RayCounter *info)
-{
- printf("----------- Raycast counter --------\n");
- printf("Rays total: %llu\n", info->raycast.test );
- printf("Rays hit: %llu\n", info->raycast.hit );
- printf("\n");
- printf("BB tests: %llu\n", info->bb.test );
- printf("BB hits: %llu\n", info->bb.hit );
- printf("\n");
- printf("SIMD BB tests: %llu\n", info->simd_bb.test );
- printf("SIMD BB hits: %llu\n", info->simd_bb.hit );
- printf("\n");
- printf("Primitives tests: %llu\n", info->faces.test );
- printf("Primitives hits: %llu\n", info->faces.hit );
- printf("------------------------------------\n");
- printf("Shadow last-hit tests per ray: %f\n", info->rayshadow_last_hit.test / ((float)info->raycast.test) );
- printf("Shadow last-hit hits per ray: %f\n", info->rayshadow_last_hit.hit / ((float)info->raycast.test) );
- printf("\n");
- printf("Hint tests per ray: %f\n", info->raytrace_hint.test / ((float)info->raycast.test) );
- printf("Hint hits per ray: %f\n", info->raytrace_hint.hit / ((float)info->raycast.test) );
- printf("\n");
- printf("BB tests per ray: %f\n", info->bb.test / ((float)info->raycast.test) );
- printf("BB hits per ray: %f\n", info->bb.hit / ((float)info->raycast.test) );
- printf("\n");
- printf("SIMD tests per ray: %f\n", info->simd_bb.test / ((float)info->raycast.test) );
- printf("SIMD hits per ray: %f\n", info->simd_bb.hit / ((float)info->raycast.test) );
- printf("\n");
- printf("Primitives tests per ray: %f\n", info->faces.test / ((float)info->raycast.test) );
- printf("Primitives hits per ray: %f\n", info->faces.hit / ((float)info->raycast.test) );
- printf("------------------------------------\n");
-}
-
-void RE_RC_MERGE(RayCounter *dest, RayCounter *tmp)
-{
- dest->faces.test += tmp->faces.test;
- dest->faces.hit += tmp->faces.hit;
-
- dest->bb.test += tmp->bb.test;
- dest->bb.hit += tmp->bb.hit;
-
- dest->simd_bb.test += tmp->simd_bb.test;
- dest->simd_bb.hit += tmp->simd_bb.hit;
-
- dest->raycast.test += tmp->raycast.test;
- dest->raycast.hit += tmp->raycast.hit;
-
- dest->rayshadow_last_hit.test += tmp->rayshadow_last_hit.test;
- dest->rayshadow_last_hit.hit += tmp->rayshadow_last_hit.hit;
-
- dest->raytrace_hint.test += tmp->raytrace_hint.test;
- dest->raytrace_hint.hit += tmp->raytrace_hint.hit;
-}
-
-#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
deleted file mode 100644
index 51f89784674..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_rtbuild.cpp
- * \ingroup render
- */
-
-
-#include <assert.h>
-#include <stdlib.h>
-#include <algorithm>
-
-#if __cplusplus >= 201103L
-#include <cmath>
-using std::isfinite;
-#else
-#include <math.h>
-#endif
-
-#include "rayobject_rtbuild.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-static bool selected_node(RTBuilder::Object *node)
-{
- return node->selected;
-}
-
-static void rtbuild_init(RTBuilder *b)
-{
- b->split_axis = -1;
- b->primitives.begin = NULL;
- b->primitives.end = NULL;
- b->primitives.maxsize = 0;
- b->depth = 0;
-
- for (int i = 0; i < RTBUILD_MAX_CHILDS; i++)
- b->child_offset[i] = 0;
-
- for (int i = 0; i < 3; i++)
- b->sorted_begin[i] = b->sorted_end[i] = NULL;
-
- INIT_MINMAX(b->bb, b->bb + 3);
-}
-
-RTBuilder *rtbuild_create(int size)
-{
- RTBuilder *builder = (RTBuilder *) MEM_mallocN(sizeof(RTBuilder), "RTBuilder");
- RTBuilder::Object *memblock = (RTBuilder::Object *)MEM_mallocN(sizeof(RTBuilder::Object) * size, "RTBuilder.objects");
-
-
- rtbuild_init(builder);
-
- builder->primitives.begin = builder->primitives.end = memblock;
- builder->primitives.maxsize = size;
-
- for (int i = 0; i < 3; i++) {
- builder->sorted_begin[i] = (RTBuilder::Object **)MEM_mallocN(sizeof(RTBuilder::Object *) * size, "RTBuilder.sorted_objects");
- builder->sorted_end[i] = builder->sorted_begin[i];
- }
-
-
- return builder;
-}
-
-void rtbuild_free(RTBuilder *b)
-{
- if (b->primitives.begin) MEM_freeN(b->primitives.begin);
-
- for (int i = 0; i < 3; i++)
- if (b->sorted_begin[i])
- MEM_freeN(b->sorted_begin[i]);
-
- MEM_freeN(b);
-}
-
-void rtbuild_add(RTBuilder *b, RayObject *o)
-{
- float bb[6];
-
- assert(b->primitives.begin + b->primitives.maxsize != b->primitives.end);
-
- INIT_MINMAX(bb, bb + 3);
- RE_rayobject_merge_bb(o, bb, bb + 3);
-
- /* skip objects with invalid bounding boxes, nan causes DO_MINMAX
- * to do nothing, so we get these invalid values. this shouldn't
- * happen usually, but bugs earlier in the pipeline can cause it. */
- if (bb[0] > bb[3] || bb[1] > bb[4] || bb[2] > bb[5])
- return;
- /* skip objects with inf bounding boxes */
- if (!isfinite(bb[0]) || !isfinite(bb[1]) || !isfinite(bb[2]))
- return;
- if (!isfinite(bb[3]) || !isfinite(bb[4]) || !isfinite(bb[5]))
- return;
- /* skip objects with zero bounding box, they are of no use, and
- * will give problems in rtbuild_heuristic_object_split later */
- if (bb[0] == bb[3] && bb[1] == bb[4] && bb[2] == bb[5])
- return;
-
- copy_v3_v3(b->primitives.end->bb, bb);
- copy_v3_v3(b->primitives.end->bb + 3, bb + 3);
- b->primitives.end->obj = o;
- b->primitives.end->cost = RE_rayobject_cost(o);
-
- for (int i = 0; i < 3; i++) {
- *(b->sorted_end[i]) = b->primitives.end;
- b->sorted_end[i]++;
- }
- b->primitives.end++;
-}
-
-int rtbuild_size(RTBuilder *b)
-{
- return b->sorted_end[0] - b->sorted_begin[0];
-}
-
-
-template<class Obj, int Axis>
-static bool obj_bb_compare(const Obj &a, const Obj &b)
-{
- if (a->bb[Axis] != b->bb[Axis])
- return a->bb[Axis] < b->bb[Axis];
- return a->obj < b->obj;
-}
-
-template<class Item>
-static void object_sort(Item *begin, Item *end, int axis)
-{
- if (axis == 0) return std::sort(begin, end, obj_bb_compare<Item, 0> );
- if (axis == 1) return std::sort(begin, end, obj_bb_compare<Item, 1> );
- if (axis == 2) return std::sort(begin, end, obj_bb_compare<Item, 2> );
- assert(false);
-}
-
-void rtbuild_done(RTBuilder *b, RayObjectControl *ctrl)
-{
- for (int i = 0; i < 3; i++) {
- if (b->sorted_begin[i]) {
- if (RE_rayobjectcontrol_test_break(ctrl)) break;
- object_sort(b->sorted_begin[i], b->sorted_end[i], i);
- }
- }
-}
-
-RayObject *rtbuild_get_primitive(RTBuilder *b, int index)
-{
- return b->sorted_begin[0][index]->obj;
-}
-
-RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp)
-{
- rtbuild_init(tmp);
-
- tmp->depth = b->depth + 1;
-
- for (int i = 0; i < 3; i++)
- if (b->sorted_begin[i]) {
- tmp->sorted_begin[i] = b->sorted_begin[i] + b->child_offset[child];
- tmp->sorted_end[i] = b->sorted_begin[i] + b->child_offset[child + 1];
- }
- else {
- tmp->sorted_begin[i] = NULL;
- tmp->sorted_end[i] = NULL;
- }
-
- return tmp;
-}
-
-static void rtbuild_calc_bb(RTBuilder *b)
-{
- if (b->bb[0] == 1.0e30f) {
- for (RTBuilder::Object **index = b->sorted_begin[0]; index != b->sorted_end[0]; index++)
- RE_rayobject_merge_bb( (*index)->obj, b->bb, b->bb + 3);
- }
-}
-
-void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3])
-{
- rtbuild_calc_bb(b);
- DO_MIN(b->bb, min);
- DO_MAX(b->bb + 3, max);
-}
-
-#if 0
-int rtbuild_get_largest_axis(RTBuilder *b)
-{
- rtbuild_calc_bb(b);
- return bb_largest_axis(b->bb, b->bb + 3);
-}
-
-//Left balanced tree
-int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis)
-{
- int i;
- int mleafs_per_child, Mleafs_per_child;
- int tot_leafs = rtbuild_size(b);
- int missing_leafs;
-
- long long s;
-
- assert(nchilds <= RTBUILD_MAX_CHILDS);
-
- //TODO optimize calc of leafs_per_child
- for (s = nchilds; s < tot_leafs; s *= nchilds) ;
- Mleafs_per_child = s / nchilds;
- mleafs_per_child = Mleafs_per_child / nchilds;
-
- //split min leafs per child
- b->child_offset[0] = 0;
- for (i = 1; i <= nchilds; i++)
- b->child_offset[i] = mleafs_per_child;
-
- //split remaining leafs
- missing_leafs = tot_leafs - mleafs_per_child * nchilds;
- for (i = 1; i <= nchilds; i++)
- {
- if (missing_leafs > Mleafs_per_child - mleafs_per_child)
- {
- b->child_offset[i] += Mleafs_per_child - mleafs_per_child;
- missing_leafs -= Mleafs_per_child - mleafs_per_child;
- }
- else {
- b->child_offset[i] += missing_leafs;
- missing_leafs = 0;
- break;
- }
- }
-
- //adjust for accumulative offsets
- for (i = 1; i <= nchilds; i++)
- b->child_offset[i] += b->child_offset[i - 1];
-
- //Count created childs
- for (i = nchilds; b->child_offset[i] == b->child_offset[i - 1]; i--) ;
- split_leafs(b, b->child_offset, i, axis);
-
- assert(b->child_offset[0] == 0 && b->child_offset[i] == tot_leafs);
- return i;
-}
-
-
-int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds)
-{
- int axis = rtbuild_get_largest_axis(b);
- return rtbuild_mean_split(b, nchilds, axis);
-}
-#endif
-
-/*
- * "separators" is an array of dim NCHILDS-1
- * and indicates where to cut the childs
- */
-#if 0
-int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis)
-{
- int size = rtbuild_size(b);
-
- assert(nchilds <= RTBUILD_MAX_CHILDS);
- if (size <= nchilds)
- {
- return rtbuild_mean_split(b, nchilds, axis);
- }
- else {
- int i;
-
- b->split_axis = axis;
-
- //Calculate child offsets
- b->child_offset[0] = 0;
- for (i = 0; i < nchilds - 1; i++)
- b->child_offset[i + 1] = split_leafs_by_plane(b, b->child_offset[i], size, separators[i]);
- b->child_offset[nchilds] = size;
-
- for (i = 0; i < nchilds; i++)
- if (b->child_offset[i + 1] - b->child_offset[i] == size)
- return rtbuild_mean_split(b, nchilds, axis);
-
- return nchilds;
- }
-}
-
-int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds)
-{
- int la, i;
- float separators[RTBUILD_MAX_CHILDS];
-
- rtbuild_calc_bb(b);
-
- la = bb_largest_axis(b->bb, b->bb + 3);
- for (i = 1; i < nchilds; i++)
- separators[i - 1] = (b->bb[la + 3] - b->bb[la]) * i / nchilds;
-
- return rtbuild_median_split(b, separators, nchilds, la);
-}
-#endif
-
-//Heuristics Object Splitter
-
-
-struct SweepCost {
- float bb[6];
- float cost;
-};
-
-/* Object Surface Area Heuristic splitter */
-int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds)
-{
- int size = rtbuild_size(b);
- assert(nchilds == 2);
- assert(size > 1);
- int baxis = -1, boffset = 0;
-
- if (size > nchilds) {
- if (b->depth > RTBUILD_MAX_SAH_DEPTH) {
- // for degenerate cases we avoid running out of stack space
- // by simply splitting the children in the middle
- b->child_offset[0] = 0;
- b->child_offset[1] = (size+1)/2;
- b->child_offset[2] = size;
- return 2;
- }
-
- float bcost = FLT_MAX;
- baxis = -1;
- boffset = size / 2;
-
- SweepCost *sweep = (SweepCost *)MEM_mallocN(sizeof(SweepCost) * size, "RTBuilder.HeuristicSweep");
-
- for (int axis = 0; axis < 3; axis++) {
- SweepCost sweep_left;
-
- RTBuilder::Object **obj = b->sorted_begin[axis];
-
-// float right_cost = 0;
- for (int i = size - 1; i >= 0; i--) {
- if (i == size - 1) {
- copy_v3_v3(sweep[i].bb, obj[i]->bb);
- copy_v3_v3(sweep[i].bb + 3, obj[i]->bb + 3);
- sweep[i].cost = obj[i]->cost;
- }
- else {
- sweep[i].bb[0] = min_ff(obj[i]->bb[0], sweep[i + 1].bb[0]);
- sweep[i].bb[1] = min_ff(obj[i]->bb[1], sweep[i + 1].bb[1]);
- sweep[i].bb[2] = min_ff(obj[i]->bb[2], sweep[i + 1].bb[2]);
- sweep[i].bb[3] = max_ff(obj[i]->bb[3], sweep[i + 1].bb[3]);
- sweep[i].bb[4] = max_ff(obj[i]->bb[4], sweep[i + 1].bb[4]);
- sweep[i].bb[5] = max_ff(obj[i]->bb[5], sweep[i + 1].bb[5]);
- sweep[i].cost = obj[i]->cost + sweep[i + 1].cost;
- }
-// right_cost += obj[i]->cost;
- }
-
- sweep_left.bb[0] = obj[0]->bb[0];
- sweep_left.bb[1] = obj[0]->bb[1];
- sweep_left.bb[2] = obj[0]->bb[2];
- sweep_left.bb[3] = obj[0]->bb[3];
- sweep_left.bb[4] = obj[0]->bb[4];
- sweep_left.bb[5] = obj[0]->bb[5];
- sweep_left.cost = obj[0]->cost;
-
-// right_cost -= obj[0]->cost; if (right_cost < 0) right_cost = 0;
-
- for (int i = 1; i < size; i++) {
- //Worst case heuristic (cost of each child is linear)
- float hcost, left_side, right_side;
-
- // not using log seems to have no impact on raytracing perf, but
- // makes tree construction quicker, left out for now to test (brecht)
- // left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost + logf((float)i));
- // right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost + logf((float)size - i));
- left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost);
- right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost);
- hcost = left_side + right_side;
-
- assert(left_side >= 0);
- assert(right_side >= 0);
-
- if (left_side > bcost) break; //No way we can find a better heuristic in this axis
-
- assert(hcost >= 0);
- // this makes sure the tree built is the same whatever is the order of the sorting axis
- if (hcost < bcost || (hcost == bcost && axis < baxis)) {
- bcost = hcost;
- baxis = axis;
- boffset = i;
- }
- DO_MIN(obj[i]->bb, sweep_left.bb);
- DO_MAX(obj[i]->bb + 3, sweep_left.bb + 3);
-
- sweep_left.cost += obj[i]->cost;
-// right_cost -= obj[i]->cost; if (right_cost < 0) right_cost = 0;
- }
-
- //assert(baxis >= 0 && baxis < 3);
- if (!(baxis >= 0 && baxis < 3))
- baxis = 0;
- }
-
-
- MEM_freeN(sweep);
- }
- else if (size == 2) {
- baxis = 0;
- boffset = 1;
- }
- else if (size == 1) {
- b->child_offset[0] = 0;
- b->child_offset[1] = 1;
- return 1;
- }
-
- b->child_offset[0] = 0;
- b->child_offset[1] = boffset;
- b->child_offset[2] = size;
-
-
- /* Adjust sorted arrays for childs */
- for (int i = 0; i < boffset; i++) b->sorted_begin[baxis][i]->selected = true;
- for (int i = boffset; i < size; i++) b->sorted_begin[baxis][i]->selected = false;
- for (int i = 0; i < 3; i++)
- std::stable_partition(b->sorted_begin[i], b->sorted_end[i], selected_node);
-
- return nchilds;
-}
-
-/*
- * Helper code
- * PARTITION code / used on mean-split
- * basically this a std::nth_element (like on C++ STL algorithm)
- */
-#if 0
-static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis)
-{
- int i;
- b->split_axis = split_axis;
-
- for (i = 0; i < partitions - 1; i++)
- {
- assert(nth[i] < nth[i + 1] && nth[i + 1] < nth[partitions]);
-
- if (split_axis == 0) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 0>);
- if (split_axis == 1) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 1>);
- if (split_axis == 2) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 2>);
- }
-}
-#endif
-
-/*
- * Bounding Box utils
- */
-float bb_volume(const float min[3], const float max[3])
-{
- return (max[0] - min[0]) * (max[1] - min[1]) * (max[2] - min[2]);
-}
-
-float bb_area(const float min[3], const float max[3])
-{
- float sub[3], a;
- sub[0] = max[0] - min[0];
- sub[1] = max[1] - min[1];
- sub[2] = max[2] - min[2];
-
- a = (sub[0] * sub[1] + sub[0] * sub[2] + sub[1] * sub[2]) * 2.0f;
- /* used to have an assert() here on negative results
- * however, in this case its likely some overflow or ffast math error.
- * so just return 0.0f instead. */
- return a < 0.0f ? 0.0f : a;
-}
-
-int bb_largest_axis(const float min[3], const float max[3])
-{
- float sub[3];
-
- sub[0] = max[0] - min[0];
- sub[1] = max[1] - min[1];
- sub[2] = max[2] - min[2];
- if (sub[0] > sub[1]) {
- if (sub[0] > sub[2])
- return 0;
- else
- return 2;
- }
- else {
- if (sub[1] > sub[2])
- return 1;
- else
- return 2;
- }
-}
-
-/* only returns 0 if merging inner and outerbox would create a box larger than outer box */
-int bb_fits_inside(const float outer_min[3], const float outer_max[3],
- const float inner_min[3], const float inner_max[3])
-{
- int i;
- for (i = 0; i < 3; i++)
- if (outer_min[i] > inner_min[i]) return 0;
-
- for (i = 0; i < 3; i++)
- if (outer_max[i] < inner_max[i]) return 0;
-
- return 1;
-}
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.h b/source/blender/render/intern/raytrace/rayobject_rtbuild.h
deleted file mode 100644
index d4510fe245d..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_rtbuild.h
- * \ingroup render
- */
-
-#ifndef __RAYOBJECT_RTBUILD_H__
-#define __RAYOBJECT_RTBUILD_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "rayobject.h"
-
-
-/*
- * Ray Tree Builder:
- * this structs helps building any type of tree
- * it contains several methods to organize/split nodes
- * allowing to create a given tree on the fly.
- *
- * Idea is that other trees BVH, BIH can use this code to
- * generate with simple calls, and then convert to the theirs
- * specific structure on the fly.
- */
-#define RTBUILD_MAX_CHILDS 32
-#define RTBUILD_MAX_SAH_DEPTH 256
-
-
-typedef struct RTBuilder {
- struct Object {
- RayObject *obj;
- float cost;
- float bb[6];
- int selected;
- };
-
- /* list to all primitives added in this tree */
- struct {
- Object *begin, *end;
- int maxsize;
- } primitives;
-
- /* sorted list of rayobjects */
- struct Object **sorted_begin[3], **sorted_end[3];
-
- /* axis used (if any) on the split method */
- int split_axis;
-
- /* child partitions calculated during splitting */
- int child_offset[RTBUILD_MAX_CHILDS + 1];
-
-// int child_sorted_axis; /* -1 if not sorted */
-
- float bb[6];
-
- /* current depth */
- int depth;
-} RTBuilder;
-
-/* used during creation */
-RTBuilder *rtbuild_create(int size);
-void rtbuild_free(RTBuilder *b);
-void rtbuild_add(RTBuilder *b, RayObject *o);
-void rtbuild_done(RTBuilder *b, RayObjectControl *c);
-void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3]);
-int rtbuild_size(RTBuilder *b);
-
-RayObject *rtbuild_get_primitive(RTBuilder *b, int offset);
-
-/* used during tree reorganization */
-RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp);
-
-/* Calculates child partitions and returns number of efectively needed partitions */
-int rtbuild_get_largest_axis(RTBuilder *b);
-
-//Object partition
-int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis);
-int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds);
-
-int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds);
-
-//Space partition
-int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis);
-int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds);
-
-
-/* bb utils */
-float bb_area(const float min[3], const float max[3]);
-float bb_volume(const float min[3], const float max[3]);
-int bb_largest_axis(const float min[3], const float max[3]);
-int bb_fits_inside(const float outer_min[3], const float outer_max[3],
- const float inner_min[3], const float inner_max[3]);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __RAYOBJECT_RTBUILD_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
deleted file mode 100644
index fcd692fac02..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_svbvh.cpp
- * \ingroup render
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-
-#include "vbvh.h"
-#include "svbvh.h"
-#include "reorganize.h"
-
-#ifdef __SSE__
-
-#define DFS_STACK_SIZE 256
-
-struct SVBVHTree {
- RayObject rayobj;
-
- SVBVHNode *root;
- MemArena *node_arena;
-
- float cost;
- RTBuilder *builder;
-};
-
-/*
- * Cost to test N childs
- */
-struct PackCost {
- float operator()(int n)
- {
- return (n / 4) + ((n % 4) > 2 ? 1 : n % 4);
- }
-};
-
-
-template<>
-void bvh_done<SVBVHTree>(SVBVHTree *obj)
-{
- rtbuild_done(obj->builder, &obj->rayobj.control);
-
- //TODO find a away to exactly calculate the needed memory
- MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena");
- BLI_memarena_use_malloc(arena1);
-
- MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena2");
- BLI_memarena_use_malloc(arena2);
- BLI_memarena_use_align(arena2, 16);
-
- //Build and optimize the tree
- if (0) {
- VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
-
- if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
- BLI_memarena_free(arena1);
- BLI_memarena_free(arena2);
- return;
- }
-
- reorganize(root);
- remove_useless(root, &root);
- bvh_refit(root);
-
- pushup(root);
- pushdown(root);
- pushup_simd<VBVHNode, 4>(root);
-
- obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
- }
- else {
- //Finds the optimal packing of this tree using a given cost model
- //TODO this uses quite a lot of memory, find ways to reduce memory usage during building
- OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
-
- if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
- BLI_memarena_free(arena1);
- BLI_memarena_free(arena2);
- return;
- }
-
- if (root) {
- VBVH_optimalPackSIMD<OVBVHNode, PackCost>(PackCost()).transform(root);
- obj->root = Reorganize_SVBVH<OVBVHNode>(arena2).transform(root);
- }
- else
- obj->root = NULL;
- }
-
- //Free data
- BLI_memarena_free(arena1);
-
- obj->node_arena = arena2;
- obj->cost = 1.0;
-
- rtbuild_free(obj->builder);
- obj->builder = NULL;
-}
-
-template<int StackSize>
-static int intersect(SVBVHTree *obj, Isect *isec)
-{
- //TODO renable hint support
- if (RE_rayobject_isAligned(obj->root)) {
- if (isec->mode == RE_RAY_SHADOW)
- return svbvh_node_stack_raycast<StackSize, true>(obj->root, isec);
- else
- return svbvh_node_stack_raycast<StackSize, false>(obj->root, isec);
- }
- else
- return RE_rayobject_intersect( (RayObject *) obj->root, isec);
-}
-
-template<class Tree>
-static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
-{
- //TODO renable hint support
- {
- hint->size = 0;
- hint->stack[hint->size++] = (RayObject *)tree->root;
- }
-}
-/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
-template<class Tree, int STACK_SIZE>
-static RayObjectAPI make_api()
-{
- static RayObjectAPI api =
- {
- (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
- (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
- (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
- (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
- (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
- (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
- (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
- };
-
- return api;
-}
-
-template<class Tree>
-static RayObjectAPI *bvh_get_api(int maxstacksize)
-{
- static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
-
- if (maxstacksize <= 1024) return &bvh_api256;
- assert(maxstacksize <= 256);
- return NULL;
-}
-
-RayObject *RE_rayobject_svbvh_create(int size)
-{
- return bvh_create_tree<SVBVHTree, DFS_STACK_SIZE>(size);
-}
-
-#else
-
-RayObject *RE_rayobject_svbvh_create(int UNUSED(size))
-{
- puts("WARNING: SSE disabled at compile time\n");
- return NULL;
-}
-
-#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
deleted file mode 100644
index b63a11047dd..00000000000
--- a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/rayobject_vbvh.cpp
- * \ingroup render
- */
-
-
-int tot_pushup = 0;
-int tot_pushdown = 0;
-int tot_hints = 0;
-
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_memarena.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_global.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "rayobject_rtbuild.h"
-
-#include "reorganize.h"
-#include "bvh.h"
-#include "vbvh.h"
-
-#include <queue>
-#include <algorithm>
-
-#define DFS_STACK_SIZE 256
-
-struct VBVHTree {
- RayObject rayobj;
- VBVHNode *root;
- MemArena *node_arena;
- float cost;
- RTBuilder *builder;
-};
-
-/*
- * Cost to test N childs
- */
-struct PackCost {
- float operator()(int n)
- {
- return n;
- }
-};
-
-template<>
-void bvh_done<VBVHTree>(VBVHTree *obj)
-{
- rtbuild_done(obj->builder, &obj->rayobj.control);
-
- //TODO find a away to exactly calculate the needed memory
- MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vbvh arena");
- BLI_memarena_use_malloc(arena1);
-
- //Build and optimize the tree
- if (1) {
- VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
- if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
- BLI_memarena_free(arena1);
- return;
- }
-
- if (root) {
- reorganize(root);
- remove_useless(root, &root);
- bvh_refit(root);
-
- pushup(root);
- pushdown(root);
- obj->root = root;
- }
- else
- obj->root = NULL;
- }
- else {
- /* TODO */
-#if 0
- MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vbvh arena2");
- BLI_memarena_use_malloc(arena2);
-
- //Finds the optimal packing of this tree using a given cost model
- //TODO this uses quite a lot of memory, find ways to reduce memory usage during building
- OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena2).transform(obj->builder);
- VBVH_optimalPackSIMD<OVBVHNode, PackCost>(PackCost()).transform(root);
- obj->root = Reorganize_VBVH<OVBVHNode>(arena1).transform(root);
-
- BLI_memarena_free(arena2);
-#endif
- }
-
- //Cleanup
- rtbuild_free(obj->builder);
- obj->builder = NULL;
-
- obj->node_arena = arena1;
- obj->cost = 1.0;
-}
-
-template<int StackSize>
-static int intersect(VBVHTree *obj, Isect *isec)
-{
- //TODO renable hint support
- if (RE_rayobject_isAligned(obj->root)) {
- if (isec->mode == RE_RAY_SHADOW)
- return bvh_node_stack_raycast<VBVHNode, StackSize, false, true>(obj->root, isec);
- else
- return bvh_node_stack_raycast<VBVHNode, StackSize, false, false>(obj->root, isec);
- }
- else
- return RE_rayobject_intersect( (RayObject *) obj->root, isec);
-}
-
-template<class Tree>
-static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
-{
- //TODO renable hint support
- {
- hint->size = 0;
- hint->stack[hint->size++] = (RayObject *)tree->root;
- }
-}
-
-#if 0 /* UNUSED */
-static void bfree(VBVHTree *tree)
-{
- if (tot_pushup + tot_pushdown + tot_hints + tot_moves) {
- if (G.debug & G_DEBUG) {
- printf("tot pushups: %d\n", tot_pushup);
- printf("tot pushdowns: %d\n", tot_pushdown);
- printf("tot moves: %d\n", tot_moves);
- printf("tot hints created: %d\n", tot_hints);
- }
-
- tot_pushup = 0;
- tot_pushdown = 0;
- tot_hints = 0;
- tot_moves = 0;
- }
- bvh_free(tree);
-}
-#endif
-
-/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
-template<class Tree, int STACK_SIZE>
-static RayObjectAPI make_api()
-{
- static RayObjectAPI api =
- {
- (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
- (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
- (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
- (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
- (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
- (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
- (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
- };
-
- return api;
-}
-
-template<class Tree>
-RayObjectAPI *bvh_get_api(int maxstacksize)
-{
- static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
-
- if (maxstacksize <= 1024) return &bvh_api256;
- assert(maxstacksize <= 256);
- return 0;
-}
-
-RayObject *RE_rayobject_vbvh_create(int size)
-{
- return bvh_create_tree<VBVHTree, DFS_STACK_SIZE>(size);
-}
diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h
deleted file mode 100644
index 8cdd2547de3..00000000000
--- a/source/blender/render/intern/raytrace/reorganize.h
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/reorganize.h
- * \ingroup render
- */
-
-
-#include <float.h>
-#include <math.h>
-#include <stdio.h>
-
-#include <algorithm>
-#include <queue>
-#include <vector>
-
-#include "BKE_global.h"
-
-#ifdef _WIN32
-# ifdef INFINITY
-# undef INFINITY
-# endif
-# define INFINITY FLT_MAX // in mingw math.h: (1.0F/0.0F). This generates compile error, though.
-#endif
-
-extern int tot_pushup;
-extern int tot_pushdown;
-
-#if !defined(INFINITY) && defined(HUGE_VAL)
-#define INFINITY HUGE_VAL
-#endif
-
-template<class Node>
-static bool node_fits_inside(Node *a, Node *b)
-{
- return bb_fits_inside(b->bb, b->bb + 3, a->bb, a->bb + 3);
-}
-
-template<class Node>
-static void reorganize_find_fittest_parent(Node *tree, Node *node, std::pair<float, Node *> &cost)
-{
- std::queue<Node *> q;
- q.push(tree);
-
- while (!q.empty()) {
- Node *parent = q.front();
- q.pop();
-
- if (parent == node) continue;
- if (node_fits_inside(node, parent) && RE_rayobject_isAligned(parent->child) ) {
- float pcost = bb_area(parent->bb, parent->bb + 3);
- cost = std::min(cost, std::make_pair(pcost, parent) );
- for (Node *child = parent->child; child; child = child->sibling)
- q.push(child);
- }
- }
-}
-
-template<class Node>
-static void reorganize(Node *root)
-{
- std::queue<Node *> q;
-
- q.push(root);
- while (!q.empty()) {
- Node *node = q.front();
- q.pop();
-
- if (RE_rayobject_isAligned(node->child)) {
- for (Node **prev = &node->child; *prev; ) {
- assert(RE_rayobject_isAligned(*prev));
- q.push(*prev);
-
- std::pair<float, Node *> best(FLT_MAX, root);
- reorganize_find_fittest_parent(root, *prev, best);
-
- if (best.second == node) {
- //Already inside the fitnest BB
- prev = &(*prev)->sibling;
- }
- else {
- Node *tmp = *prev;
- *prev = (*prev)->sibling;
-
- tmp->sibling = best.second->child;
- best.second->child = tmp;
- }
-
-
- }
- }
- if (node != root) {
- }
- }
-}
-
-/*
- * Prunes useless nodes from trees:
- * erases nodes with total amount of primitives = 0
- * prunes nodes with only one child (except if that child is a primitive)
- */
-template<class Node>
-static void remove_useless(Node *node, Node **new_node)
-{
- if (RE_rayobject_isAligned(node->child) ) {
-
- for (Node **prev = &node->child; *prev; ) {
- Node *next = (*prev)->sibling;
- remove_useless(*prev, prev);
- if (*prev == NULL)
- *prev = next;
- else {
- (*prev)->sibling = next;
- prev = &((*prev)->sibling);
- }
- }
- }
- if (node->child) {
- if (RE_rayobject_isAligned(node->child) && node->child->sibling == 0)
- *new_node = node->child;
- }
- else if (node->child == NULL) {
- *new_node = NULL;
- }
-}
-
-/*
- * Minimizes expected number of BBtest by colapsing nodes
- * it uses surface area heuristic for determining whether a node should be colapsed
- */
-template<class Node>
-static void pushup(Node *parent)
-{
- if (is_leaf(parent)) return;
-
- float p_area = bb_area(parent->bb, parent->bb + 3);
- Node **prev = &parent->child;
- for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; ) {
- const float c_area = bb_area(child->bb, child->bb + 3);
- const int nchilds = count_childs(child);
- float original_cost = ((p_area != 0.0f) ? (c_area / p_area) * nchilds : 1.0f) + 1;
- float flatten_cost = nchilds;
- if (flatten_cost < original_cost && nchilds >= 2) {
- append_sibling(child, child->child);
- child = child->sibling;
- *prev = child;
-
-// *prev = child->child;
-// append_sibling( *prev, child->sibling );
-// child = *prev;
- tot_pushup++;
- }
- else {
- *prev = child;
- prev = &(*prev)->sibling;
- child = *prev;
- }
- }
-
- for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; child = child->sibling)
- pushup(child);
-}
-
-/*
- * try to optimize number of childs to be a multiple of SSize
- */
-template<class Node, int SSize>
-static void pushup_simd(Node *parent)
-{
- if (is_leaf(parent)) return;
-
- int n = count_childs(parent);
-
- Node **prev = &parent->child;
- for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; ) {
- int cn = count_childs(child);
- if (cn - 1 <= (SSize - (n % SSize) ) % SSize && RE_rayobject_isAligned(child->child) ) {
- n += (cn - 1);
- append_sibling(child, child->child);
- child = child->sibling;
- *prev = child;
- }
- else {
- *prev = child;
- prev = &(*prev)->sibling;
- child = *prev;
- }
- }
-
- for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; child = child->sibling)
- pushup_simd<Node, SSize>(child);
-}
-
-
-/*
- * Pushdown
- * makes sure no child fits inside any of its sibling
- */
-template<class Node>
-static void pushdown(Node *parent)
-{
- Node **s_child = &parent->child;
- Node *child = parent->child;
-
- while (child && RE_rayobject_isAligned(child)) {
- Node *next = child->sibling;
- Node **next_s_child = &child->sibling;
-
- //assert(bb_fits_inside(parent->bb, parent->bb+3, child->bb, child->bb+3));
-
- for (Node *i = parent->child; RE_rayobject_isAligned(i) && i; i = i->sibling)
- if (child != i && bb_fits_inside(i->bb, i->bb + 3, child->bb, child->bb + 3) && RE_rayobject_isAligned(i->child)) {
-// todo optimize (should the one with the smallest area?)
-// float ia = bb_area(i->bb, i->bb+3)
-// if (child->i)
- *s_child = child->sibling;
- child->sibling = i->child;
- i->child = child;
- next_s_child = s_child;
-
- tot_pushdown++;
- break;
- }
- child = next;
- s_child = next_s_child;
- }
-
- for (Node *i = parent->child; RE_rayobject_isAligned(i) && i; i = i->sibling) {
- pushdown(i);
- }
-}
-
-
-/*
- * BVH refit
- * readjust nodes BB (useful if nodes childs where modified)
- */
-template<class Node>
-static float bvh_refit(Node *node)
-{
- if (is_leaf(node)) return 0;
- if (is_leaf(node->child)) return 0;
-
- float total = 0;
-
- for (Node *child = node->child; child; child = child->sibling)
- total += bvh_refit(child);
-
- float old_area = bb_area(node->bb, node->bb + 3);
- INIT_MINMAX(node->bb, node->bb + 3);
- for (Node *child = node->child; child; child = child->sibling) {
- DO_MIN(child->bb, node->bb);
- DO_MAX(child->bb + 3, node->bb + 3);
- }
- total += old_area - bb_area(node->bb, node->bb + 3);
- return total;
-}
-
-
-/*
- * this finds the best way to packing a tree according to a given test cost function
- * with the purpose to reduce the expected cost (eg.: number of BB tests).
- */
-#include <vector>
-#define MAX_CUT_SIZE 4 /* svbvh assumes max 4 children! */
-#define MAX_OPTIMIZE_CHILDS MAX_CUT_SIZE
-
-#define CUT_SIZE_IS_VALID(cut_size) ((cut_size) < MAX_CUT_SIZE && (cut_size) >= 0)
-#define CUT_SIZE_INVALID -1
-
-
-struct OVBVHNode {
- float bb[6];
-
- OVBVHNode *child;
- OVBVHNode *sibling;
-
- /*
- * Returns min cost to represent the subtree starting at the given node,
- * allowing it to have a given cutsize
- */
- float cut_cost[MAX_CUT_SIZE];
- float get_cost(int cutsize)
- {
- assert(CUT_SIZE_IS_VALID(cutsize - 1));
- return cut_cost[cutsize - 1];
- }
-
- /*
- * This saves the cut size of this child, when parent is reaching
- * its minimum cut with the given cut size
- */
- int cut_size[MAX_CUT_SIZE];
- int get_cut_size(int parent_cut_size)
- {
- assert(CUT_SIZE_IS_VALID(parent_cut_size - 1));
- return cut_size[parent_cut_size - 1];
- }
-
- /*
- * Reorganize the node based on calculated cut costs
- */
- int best_cutsize;
- void set_cut(int cutsize, OVBVHNode ***cut)
- {
- if (cutsize == 1) {
- **cut = this;
- *cut = &(**cut)->sibling;
- }
- else {
- if (cutsize > MAX_CUT_SIZE) {
- for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- child->set_cut(1, cut);
- cutsize--;
- }
- assert(cutsize == 0);
- }
- else {
- for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- child->set_cut(child->get_cut_size(cutsize), cut);
- }
- }
- }
- }
-
- void optimize()
- {
- if (RE_rayobject_isAligned(this->child)) {
- //Calc new childs
- if (this->best_cutsize != CUT_SIZE_INVALID) {
- OVBVHNode **cut = &(this->child);
- set_cut(this->best_cutsize, &cut);
- *cut = NULL;
- }
-
- //Optimize new childs
- for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling)
- child->optimize();
- }
- }
-};
-
-/*
- * Calculates an optimal SIMD packing
- *
- */
-template<class Node, class TestCost>
-struct VBVH_optimalPackSIMD {
- TestCost testcost;
-
- VBVH_optimalPackSIMD(TestCost testcost)
- {
- this->testcost = testcost;
- }
-
- /*
- * calc best cut on a node
- */
- struct calc_best {
- Node *child[MAX_OPTIMIZE_CHILDS];
- float child_hit_prob[MAX_OPTIMIZE_CHILDS];
-
- calc_best(Node *node)
- {
- int nchilds = 0;
- //Fetch childs and needed data
- {
- float parent_area = bb_area(node->bb, node->bb + 3);
- for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- this->child[nchilds] = child;
- this->child_hit_prob[nchilds] = (parent_area != 0.0f) ? bb_area(child->bb, child->bb + 3) / parent_area : 1.0f;
- nchilds++;
- }
-
- assert(nchilds >= 2 && nchilds <= MAX_OPTIMIZE_CHILDS);
- }
-
-
- //Build DP table to find minimum cost to represent this node with a given cutsize
- int bt[MAX_OPTIMIZE_CHILDS + 1][MAX_CUT_SIZE + 1]; //backtrace table
- float cost[MAX_OPTIMIZE_CHILDS + 1][MAX_CUT_SIZE + 1]; //cost table (can be reduced to float[2][MAX_CUT_COST])
-
- for (int i = 0; i <= nchilds; i++) {
- for (int j = 0; j <= MAX_CUT_SIZE; j++) {
- cost[i][j] = INFINITY;
- }
- }
-
- cost[0][0] = 0;
-
- for (int i = 1; i <= nchilds; i++) {
- for (int size = i - 1; size /*+(nchilds-i)*/ <= MAX_CUT_SIZE; size++) {
- for (int cut = 1; cut + size /*+(nchilds-i)*/ <= MAX_CUT_SIZE; cut++) {
- float new_cost = cost[i - 1][size] + child_hit_prob[i - 1] * child[i - 1]->get_cost(cut);
- if (new_cost < cost[i][size + cut]) {
- cost[i][size + cut] = new_cost;
- bt[i][size + cut] = cut;
- }
- }
- }
- }
-
- /* Save the ways to archive the minimum cost with a given cutsize */
- for (int i = nchilds; i <= MAX_CUT_SIZE; i++) {
- node->cut_cost[i - 1] = cost[nchilds][i];
- if (cost[nchilds][i] < INFINITY) {
- int current_size = i;
- for (int j = nchilds; j > 0; j--) {
- child[j - 1]->cut_size[i - 1] = bt[j][current_size];
- current_size -= bt[j][current_size];
- }
- }
- }
- }
- };
-
- void calc_costs(Node *node)
- {
-
- if (RE_rayobject_isAligned(node->child) ) {
- int nchilds = 0;
- for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- calc_costs(child);
- nchilds++;
- }
-
- for (int i = 0; i < MAX_CUT_SIZE; i++)
- node->cut_cost[i] = INFINITY;
-
- //We are not allowed to look on nodes with with so many childs
- if (nchilds > MAX_CUT_SIZE) {
- float cost = 0;
-
- float parent_area = bb_area(node->bb, node->bb + 3);
- for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
- cost += ((parent_area != 0.0f) ? (bb_area(child->bb, child->bb + 3) / parent_area) : 1.0f) * child->get_cost(1);
- }
-
- cost += testcost(nchilds);
- node->cut_cost[0] = cost;
- node->best_cutsize = nchilds;
- }
- else {
- calc_best calc(node);
-
- //calc expected cost if we optimaly pack this node
- for (int cutsize = nchilds; cutsize <= MAX_CUT_SIZE; cutsize++) {
- float m = node->get_cost(cutsize) + testcost(cutsize);
- if (m < node->cut_cost[0]) {
- node->cut_cost[0] = m;
- node->best_cutsize = cutsize;
- }
- }
- }
-
- if (node->cut_cost[0] == INFINITY) {
- node->best_cutsize = CUT_SIZE_INVALID;
- }
- }
- else {
- node->cut_cost[0] = 1.0f;
- for (int i = 1; i < MAX_CUT_SIZE; i++)
- node->cut_cost[i] = INFINITY;
-
- /* node->best_cutsize can remain unset here */
- }
- }
-
- Node *transform(Node *node)
- {
- if (RE_rayobject_isAligned(node->child)) {
-#ifdef DEBUG
- static int num = 0;
- bool first = false;
- if (num == 0) { num++; first = true; }
-#endif
-
- calc_costs(node);
-
-#ifdef DEBUG
- if (first && G.debug) {
- printf("expected cost = %f (%d)\n", node->cut_cost[0], node->best_cutsize);
- }
-#endif
- node->optimize();
- }
- return node;
- }
-};
diff --git a/source/blender/render/intern/raytrace/svbvh.h b/source/blender/render/intern/raytrace/svbvh.h
deleted file mode 100644
index 0a5690deb46..00000000000
--- a/source/blender/render/intern/raytrace/svbvh.h
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/svbvh.h
- * \ingroup render
- */
-
-#ifndef __SVBVH_H__
-#define __SVBVH_H__
-
-#ifdef __SSE__
-
-#include "bvh.h"
-#include "BLI_memarena.h"
-#include <algorithm>
-
-struct SVBVHNode {
- float child_bb[24];
- SVBVHNode *child[4];
- int nchilds;
-};
-
-static int svbvh_bb_intersect_test_simd4(const Isect *isec, const __m128 *bb_group)
-{
- const __m128 tmin0 = _mm_setzero_ps();
- const __m128 tmax0 = _mm_set_ps1(isec->dist);
-
- const __m128 start0 = _mm_set_ps1(isec->start[0]);
- const __m128 start1 = _mm_set_ps1(isec->start[1]);
- const __m128 start2 = _mm_set_ps1(isec->start[2]);
- const __m128 sub0 = _mm_sub_ps(bb_group[isec->bv_index[0]], start0);
- const __m128 sub1 = _mm_sub_ps(bb_group[isec->bv_index[1]], start0);
- const __m128 sub2 = _mm_sub_ps(bb_group[isec->bv_index[2]], start1);
- const __m128 sub3 = _mm_sub_ps(bb_group[isec->bv_index[3]], start1);
- const __m128 sub4 = _mm_sub_ps(bb_group[isec->bv_index[4]], start2);
- const __m128 sub5 = _mm_sub_ps(bb_group[isec->bv_index[5]], start2);
- const __m128 idot_axis0 = _mm_set_ps1(isec->idot_axis[0]);
- const __m128 idot_axis1 = _mm_set_ps1(isec->idot_axis[1]);
- const __m128 idot_axis2 = _mm_set_ps1(isec->idot_axis[2]);
- const __m128 mul0 = _mm_mul_ps(sub0, idot_axis0);
- const __m128 mul1 = _mm_mul_ps(sub1, idot_axis0);
- const __m128 mul2 = _mm_mul_ps(sub2, idot_axis1);
- const __m128 mul3 = _mm_mul_ps(sub3, idot_axis1);
- const __m128 mul4 = _mm_mul_ps(sub4, idot_axis2);
- const __m128 mul5 = _mm_mul_ps(sub5, idot_axis2);
- const __m128 tmin1 = _mm_max_ps(tmin0, mul0);
- const __m128 tmax1 = _mm_min_ps(tmax0, mul1);
- const __m128 tmin2 = _mm_max_ps(tmin1, mul2);
- const __m128 tmax2 = _mm_min_ps(tmax1, mul3);
- const __m128 tmin3 = _mm_max_ps(tmin2, mul4);
- const __m128 tmax3 = _mm_min_ps(tmax2, mul5);
-
- return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3));
-}
-
-static int svbvh_bb_intersect_test(const Isect *isec, const float *_bb)
-{
- const float *bb = _bb;
-
- float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
- float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
- float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
- float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
- float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
- float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
-
- RE_RC_COUNT(isec->raycounter->bb.test);
-
- if (t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
- if (t2x < 0.0f || t2y < 0.0f || t2z < 0.0f) return 0;
- if (t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0;
-
- RE_RC_COUNT(isec->raycounter->bb.hit);
-
- return 1;
-}
-
-static bool svbvh_node_is_leaf(const SVBVHNode *node)
-{
- return !RE_rayobject_isAligned(node);
-}
-
-template<int MAX_STACK_SIZE, bool SHADOW>
-static int svbvh_node_stack_raycast(SVBVHNode *root, Isect *isec)
-{
- SVBVHNode *stack[MAX_STACK_SIZE], *node;
- int hit = 0, stack_pos = 0;
-
- stack[stack_pos++] = root;
-
- while (stack_pos) {
- node = stack[--stack_pos];
-
- if (!svbvh_node_is_leaf(node)) {
- int nchilds = node->nchilds;
-
- if (nchilds == 4) {
- float *child_bb = node->child_bb;
- int res = svbvh_bb_intersect_test_simd4(isec, ((__m128 *) (child_bb)));
- SVBVHNode **child = node->child;
-
- RE_RC_COUNT(isec->raycounter->simd_bb.test);
-
- if (res & 1) { stack[stack_pos++] = child[0]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if (res & 2) { stack[stack_pos++] = child[1]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if (res & 4) { stack[stack_pos++] = child[2]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if (res & 8) { stack[stack_pos++] = child[3]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- }
- else {
- float *child_bb = node->child_bb;
- SVBVHNode **child = node->child;
- int i;
-
- for (i = 0; i < nchilds; i++) {
- if (svbvh_bb_intersect_test(isec, (float *)child_bb + 6 * i)) {
- stack[stack_pos++] = child[i];
- }
- }
- }
- }
- else {
- hit |= RE_rayobject_intersect((RayObject *)node, isec);
- if (SHADOW && hit) break;
- }
- }
-
- return hit;
-}
-
-
-template<>
-inline void bvh_node_merge_bb<SVBVHNode>(SVBVHNode *node, float min[3], float max[3])
-{
- if (is_leaf(node)) {
- RE_rayobject_merge_bb((RayObject *)node, min, max);
- }
- else {
- int i;
- for (i = 0; i + 4 <= node->nchilds; i += 4) {
- float *res = node->child_bb + 6 * i;
- for (int j = 0; j < 3; j++) {
- min[j] = min_ff(min[j],
- min_ffff(res[4 * j + 0],
- res[4 * j + 1],
- res[4 * j + 2],
- res[4 * j + 3]));
- }
- for (int j = 0; j < 3; j++) {
- max[j] = max_ff(max[j],
- max_ffff(res[4 * (j + 3) + 0],
- res[4 * (j + 3) + 1],
- res[4 * (j + 3) + 2],
- res[4 * (j + 3) + 3]));
- }
- }
-
- for (; i < node->nchilds; i++) {
- DO_MIN(node->child_bb + 6 * i, min);
- DO_MAX(node->child_bb + 3 + 6 * i, max);
- }
- }
-}
-
-
-
-/*
- * Builds a SVBVH tree form a VBVHTree
- */
-template<class OldNode>
-struct Reorganize_SVBVH {
- MemArena *arena;
-
- float childs_per_node;
- int nodes_with_childs[16];
- int useless_bb;
- int nodes;
-
- Reorganize_SVBVH(MemArena *a)
- {
- arena = a;
- nodes = 0;
- childs_per_node = 0;
- useless_bb = 0;
-
- for (int i = 0; i < 16; i++) {
- nodes_with_childs[i] = 0;
- }
- }
-
- ~Reorganize_SVBVH()
- {
-#if 0
- {
- printf("%f childs per node\n", childs_per_node / nodes);
- printf("%d childs BB are useless\n", useless_bb);
- for (int i = 0; i < 16; i++) {
- printf("%i childs per node: %d/%d = %f\n", i, nodes_with_childs[i], nodes, nodes_with_childs[i] / float(nodes));
- }
- }
-#endif
- }
-
- SVBVHNode *create_node(int nchilds)
- {
- SVBVHNode *node = (SVBVHNode *)BLI_memarena_alloc(arena, sizeof(SVBVHNode));
- node->nchilds = nchilds;
-
- return node;
- }
-
- void copy_bb(float bb[6], const float old_bb[6])
- {
- std::copy(old_bb, old_bb + 6, bb);
- }
-
- void prepare_for_simd(SVBVHNode *node)
- {
- int i = 0;
- while (i + 4 <= node->nchilds) {
- float vec_tmp[4 * 6];
- float *res = node->child_bb + 6 * i;
- std::copy(res, res + 6 * 4, vec_tmp);
-
- for (int j = 0; j < 6; j++) {
- res[4 * j + 0] = vec_tmp[6 * 0 + j];
- res[4 * j + 1] = vec_tmp[6 * 1 + j];
- res[4 * j + 2] = vec_tmp[6 * 2 + j];
- res[4 * j + 3] = vec_tmp[6 * 3 + j];
- }
-
- i += 4;
- }
- }
-
- /* amt must be power of two */
- inline int padup(int num, int amt)
- {
- return ((num + (amt - 1)) & ~(amt - 1));
- }
-
- SVBVHNode *transform(OldNode *old)
- {
- if (is_leaf(old))
- return (SVBVHNode *)old;
- if (is_leaf(old->child))
- return (SVBVHNode *)old->child;
-
- int nchilds = count_childs(old);
- int alloc_childs = nchilds;
- if (nchilds % 4 > 2)
- alloc_childs = padup(nchilds, 4);
-
- SVBVHNode *node = create_node(alloc_childs);
-
- childs_per_node += nchilds;
- nodes++;
- if (nchilds < 16)
- nodes_with_childs[nchilds]++;
-
- useless_bb += alloc_childs - nchilds;
- while (alloc_childs > nchilds) {
- const static float def_bb[6] = {FLT_MAX, FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX};
- alloc_childs--;
- node->child[alloc_childs] = NULL;
- copy_bb(node->child_bb + alloc_childs * 6, def_bb);
- }
-
- int i = nchilds;
- for (OldNode *o_child = old->child; o_child; o_child = o_child->sibling) {
- i--;
- node->child[i] = transform(o_child);
- if (is_leaf(o_child)) {
- float bb[6];
- INIT_MINMAX(bb, bb + 3);
- RE_rayobject_merge_bb((RayObject *)o_child, bb, bb + 3);
- copy_bb(node->child_bb + i * 6, bb);
- break;
- }
- else {
- copy_bb(node->child_bb + i * 6, o_child->bb);
- }
- }
- assert(i == 0);
-
- prepare_for_simd(node);
-
- return node;
- }
-};
-
-#endif /* __SSE__ */
-
-#endif /* __SVBVH_H__ */
diff --git a/source/blender/render/intern/raytrace/vbvh.h b/source/blender/render/intern/raytrace/vbvh.h
deleted file mode 100644
index 0b0bbd19116..00000000000
--- a/source/blender/render/intern/raytrace/vbvh.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * ***** 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) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/raytrace/vbvh.h
- * \ingroup render
- */
-
-
-#include <assert.h>
-#include <algorithm>
-
-#include "BLI_memarena.h"
-
-#include "rayobject_rtbuild.h"
-
-/*
- * VBVHNode represents a BVHNode with support for a variable number of childrens
- */
-struct VBVHNode {
- float bb[6];
-
- VBVHNode *child;
- VBVHNode *sibling;
-};
-
-
-/*
- * Push nodes (used on dfs)
- */
-template<class Node>
-inline static void bvh_node_push_childs(Node *node, Isect *UNUSED(isec), Node **stack, int &stack_pos)
-{
- Node *child = node->child;
-
- if (is_leaf(child)) {
- stack[stack_pos++] = child;
- }
- else {
- while (child) {
- /* Skips BB tests on primitives */
-#if 0
- if (is_leaf(child->child)) {
- stack[stack_pos++] = child->child;
- }
- else
-#endif
- {
- stack[stack_pos++] = child;
- }
-
- child = child->sibling;
- }
- }
-}
-
-
-template<class Node>
-static int count_childs(Node *parent)
-{
- int n = 0;
- for (Node *i = parent->child; i; i = i->sibling) {
- n++;
- if (is_leaf(i))
- break;
- }
-
- return n;
-}
-
-
-template<class Node>
-static void append_sibling(Node *node, Node *sibling)
-{
- while (node->sibling)
- node = node->sibling;
-
- node->sibling = sibling;
-}
-
-
-/*
- * Builds a binary VBVH from a rtbuild
- */
-template<class Node>
-struct BuildBinaryVBVH {
- MemArena *arena;
- RayObjectControl *control;
-
- void test_break()
- {
- if (RE_rayobjectcontrol_test_break(control))
- throw "Stop";
- }
-
- BuildBinaryVBVH(MemArena *a, RayObjectControl *c)
- {
- arena = a;
- control = c;
- }
-
- Node *create_node()
- {
- Node *node = (Node *)BLI_memarena_alloc(arena, sizeof(Node) );
- assert(RE_rayobject_isAligned(node));
-
- node->sibling = NULL;
- node->child = NULL;
-
- return node;
- }
-
- int rtbuild_split(RTBuilder *builder)
- {
- return ::rtbuild_heuristic_object_split(builder, 2);
- }
-
- Node *transform(RTBuilder *builder)
- {
- try
- {
- return _transform(builder);
-
- } catch (...)
- {
- }
- return NULL;
- }
-
- Node *_transform(RTBuilder *builder)
- {
- int size = rtbuild_size(builder);
-
- if (size == 0) {
- return NULL;
- }
- else if (size == 1) {
- Node *node = create_node();
- INIT_MINMAX(node->bb, node->bb + 3);
- rtbuild_merge_bb(builder, node->bb, node->bb + 3);
- node->child = (Node *) rtbuild_get_primitive(builder, 0);
- return node;
- }
- else {
- test_break();
-
- Node *node = create_node();
-
- Node **child = &node->child;
-
- int nc = rtbuild_split(builder);
- INIT_MINMAX(node->bb, node->bb + 3);
-
- assert(nc == 2);
- for (int i = 0; i < nc; i++) {
- RTBuilder tmp;
- rtbuild_get_child(builder, i, &tmp);
-
- *child = _transform(&tmp);
- DO_MIN((*child)->bb, node->bb);
- DO_MAX((*child)->bb + 3, node->bb + 3);
- child = &((*child)->sibling);
- }
-
- *child = NULL;
- return node;
- }
- }
-};
-
-#if 0
-template<class Tree, class OldNode>
-struct Reorganize_VBVH {
- Tree *tree;
-
- Reorganize_VBVH(Tree *t)
- {
- tree = t;
- }
-
- VBVHNode *create_node()
- {
- VBVHNode *node = (VBVHNode *)BLI_memarena_alloc(tree->node_arena, sizeof(VBVHNode));
- return node;
- }
-
- void copy_bb(VBVHNode *node, OldNode *old)
- {
- std::copy(old->bb, old->bb + 6, node->bb);
- }
-
- VBVHNode *transform(OldNode *old)
- {
- if (is_leaf(old))
- return (VBVHNode *)old;
-
- VBVHNode *node = create_node();
- VBVHNode **child_ptr = &node->child;
- node->sibling = 0;
-
- copy_bb(node, old);
-
- for (OldNode *o_child = old->child; o_child; o_child = o_child->sibling)
- {
- VBVHNode *n_child = transform(o_child);
- *child_ptr = n_child;
- if (is_leaf(n_child)) return node;
- child_ptr = &n_child->sibling;
- }
- *child_ptr = 0;
-
- return node;
- }
-};
-#endif
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
deleted file mode 100644
index 4a7962b1776..00000000000
--- a/source/blender/render/intern/source/bake.c
+++ /dev/null
@@ -1,1342 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributors: 2004/2005/2006 Blender Foundation, full recode
- * Contributors: Vertex color baking, Copyright 2011 AutoCRC
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/bake.c
- * \ingroup render
- */
-
-
-/* system includes */
-#include <stdio.h>
-#include <string.h>
-
-/* External modules: */
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_rand.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_image_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BKE_customdata.h"
-#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_main.h"
-#include "BKE_node.h"
-#include "BKE_scene.h"
-#include "BKE_library.h"
-
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-#include "IMB_colormanagement.h"
-
-/* local include */
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "shading.h"
-#include "zbuf.h"
-
-#include "PIL_time.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
-/* ************************* bake ************************ */
-
-
-typedef struct BakeShade {
- int thread;
-
- ShadeSample ssamp;
- ObjectInstanceRen *obi;
- VlakRen *vlr;
-
- ZSpan *zspan;
- Image *ima;
- ImBuf *ibuf;
-
- int rectx, recty, quad, type, vdone;
- bool ready;
-
- float dir[3];
- Object *actob;
-
- /* Output: vertex color or image data. If vcol is not NULL, rect and
- * rect_float should be NULL. */
- MPoly *mpoly;
- MLoop *mloop;
- MLoopCol *vcol;
-
- unsigned int *rect;
- float *rect_float;
-
- /* displacement buffer used for normalization with unknown maximal distance */
- bool use_displacement_buffer;
- float *displacement_buffer;
- float displacement_min, displacement_max;
-
- bool use_mask;
- char *rect_mask; /* bake pixel mask */
-
- float dxco[3], dyco[3];
-
- short *do_update;
-
- struct ColorSpace *rect_colorspace;
-} BakeShade;
-
-static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int UNUSED(isect), int x, int y, float u, float v)
-{
- if (quad)
- shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-
- /* cache for shadow */
- shi->samplenr = R.shadowsamplenr[shi->thread]++;
-
- shi->mask = 0xFFFF; /* all samples */
-
- shi->u = -u;
- shi->v = -v;
- shi->xs = x;
- shi->ys = y;
-
- shade_input_set_uv(shi);
- shade_input_set_normals(shi);
-
- /* no normal flip */
- if (shi->flippednor)
- shade_input_flip_normals(shi);
-
- /* set up view vector to look right at the surface (note that the normal
- * is negated in the renderer so it does not need to be done here) */
- shi->view[0] = shi->vn[0];
- shi->view[1] = shi->vn[1];
- shi->view[2] = shi->vn[2];
-}
-
-static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang)
-{
- BakeShade *bs = handle;
- ShadeSample *ssamp = &bs->ssamp;
- ShadeResult shr;
- VlakRen *vlr = shi->vlr;
-
- shade_input_init_material(shi);
-
- if (bs->type == RE_BAKE_AO) {
- ambient_occlusion(shi);
-
- if (R.r.bake_flag & R_BAKE_NORMALIZE) {
- copy_v3_v3(shr.combined, shi->ao);
- }
- else {
- zero_v3(shr.combined);
- environment_lighting_apply(shi, &shr);
- }
- }
- else {
- if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */
- shi->r = shi->g = shi->b = 1.0f;
-
- shade_input_set_shade_texco(shi);
-
- /* only do AO for a full bake (and obviously AO bakes)
- * AO for light bakes is a leftover and might not be needed */
- if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT))
- shade_samples_do_AO(ssamp);
-
- if (shi->mat->nodetree && shi->mat->use_nodes) {
- ntreeShaderExecTree(shi->mat->nodetree, shi, &shr);
- shi->mat = vlr->mat; /* shi->mat is being set in nodetree */
- }
- else
- shade_material_loop(shi, &shr);
-
- if (bs->type == RE_BAKE_NORMALS) {
- float nor[3];
-
- copy_v3_v3(nor, shi->vn);
-
- if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) {
- /* pass */
- }
- else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) {
- float mat[3][3], imat[3][3];
-
- /* bitangent */
- if (tvn && ttang) {
- copy_v3_v3(mat[0], ttang);
- cross_v3_v3v3(mat[1], tvn, ttang);
- mul_v3_fl(mat[1], ttang[3]);
- copy_v3_v3(mat[2], tvn);
- }
- else {
- copy_v3_v3(mat[0], shi->nmaptang);
- cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang);
- mul_v3_fl(mat[1], shi->nmaptang[3]);
- copy_v3_v3(mat[2], shi->nmapnorm);
- }
-
- invert_m3_m3(imat, mat);
- mul_m3_v3(imat, nor);
- }
- else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT)
- mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */
- else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD)
- mul_mat3_m4_v3(R.viewinv, nor);
-
- normalize_v3(nor); /* in case object has scaling */
-
- /* The invert of the red channel is to make
- * the normal map compliant with the outside world.
- * It needs to be done because in Blender
- * the normal used in the renderer points inward. It is generated
- * this way in calc_vertexnormals(). Should this ever change
- * this negate must be removed.
- *
- * there is also a small 1e-5f bias for precision issues. otherwise
- * we randomly get 127 or 128 for neutral colors. we choose 128
- * because it is the convention flat color. * */
- shr.combined[0] = (-nor[0]) / 2.0f + 0.5f + 1e-5f;
- shr.combined[1] = nor[1] / 2.0f + 0.5f + 1e-5f;
- shr.combined[2] = nor[2] / 2.0f + 0.5f + 1e-5f;
- }
- else if (bs->type == RE_BAKE_TEXTURE) {
- copy_v3_v3(shr.combined, &shi->r);
- shr.alpha = shi->alpha;
- }
- else if (bs->type == RE_BAKE_SHADOW) {
- copy_v3_v3(shr.combined, shr.shad);
- shr.alpha = shi->alpha;
- }
- else if (bs->type == RE_BAKE_SPEC_COLOR) {
- copy_v3_v3(shr.combined, &shi->specr);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_SPEC_INTENSITY) {
- copy_v3_fl(shr.combined, shi->spec);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_MIRROR_COLOR) {
- copy_v3_v3(shr.combined, &shi->mirr);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_MIRROR_INTENSITY) {
- copy_v3_fl(shr.combined, shi->ray_mirror);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_ALPHA) {
- copy_v3_fl(shr.combined, shi->alpha);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_EMIT) {
- copy_v3_fl(shr.combined, shi->emit);
- shr.alpha = 1.0f;
- }
- else if (bs->type == RE_BAKE_VERTEX_COLORS) {
- copy_v3_v3(shr.combined, shi->vcol);
- shr.alpha = shi->vcol[3];
- }
- }
-
- if (bs->rect_float && !bs->vcol) {
- float *col = bs->rect_float + 4 * (bs->rectx * y + x);
- copy_v3_v3(col, shr.combined);
- if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE || bs->type == RE_BAKE_VERTEX_COLORS) {
- col[3] = shr.alpha;
- }
- else {
- col[3] = 1.0;
- }
- }
- else {
- /* Target is char (LDR). */
- unsigned char col[4];
-
- if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
- float rgb[3];
-
- copy_v3_v3(rgb, shr.combined);
- if (R.scene_color_manage) {
- /* Vertex colors have no way to specify color space, so they
- * default to sRGB. */
- if (!bs->vcol)
- IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace);
- else
- linearrgb_to_srgb_v3_v3(rgb, rgb);
- }
- rgb_float_to_uchar(col, rgb);
- }
- else {
- rgb_float_to_uchar(col, shr.combined);
- }
-
- if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) {
- col[3] = unit_float_to_uchar_clamp(shr.alpha);
- }
- else {
- col[3] = 255;
- }
-
- if (bs->vcol) {
- /* Vertex color baking. Vcol has no useful alpha channel (it exists
- * but is used only for vertex painting). */
- bs->vcol->r = col[0];
- bs->vcol->g = col[1];
- bs->vcol->b = col[2];
- }
- else {
- unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x);
- copy_v4_v4_uchar(imcol, col);
- }
-
- }
-
- if (bs->rect_mask) {
- bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED;
- }
-
- if (bs->do_update) {
- *bs->do_update = true;
- }
-}
-
-static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, int x, int y)
-{
- BakeShade *bs = handle;
- float disp;
-
- if (R.r.bake_flag & R_BAKE_NORMALIZE) {
- if (R.r.bake_maxdist)
- disp = (dist + R.r.bake_maxdist) / (R.r.bake_maxdist * 2); /* alter the range from [-bake_maxdist, bake_maxdist] to [0, 1]*/
- else
- disp = dist;
- }
- else {
- disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/
- }
-
- if (bs->displacement_buffer) {
- float *displacement = bs->displacement_buffer + (bs->rectx * y + x);
- *displacement = disp;
- bs->displacement_min = min_ff(bs->displacement_min, disp);
- bs->displacement_max = max_ff(bs->displacement_max, disp);
- }
-
- if (bs->rect_float && !bs->vcol) {
- float *col = bs->rect_float + 4 * (bs->rectx * y + x);
- col[0] = col[1] = col[2] = disp;
- col[3] = 1.0f;
- }
- else {
- /* Target is char (LDR). */
- unsigned char col[4];
- col[0] = col[1] = col[2] = unit_float_to_uchar_clamp(disp);
- col[3] = 255;
-
- if (bs->vcol) {
- /* Vertex color baking. Vcol has no useful alpha channel (it exists
- * but is used only for vertex painting). */
- bs->vcol->r = col[0];
- bs->vcol->g = col[1];
- bs->vcol->b = col[2];
- }
- else {
- unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x);
- copy_v4_v4_uchar(imcol, col);
- }
- }
- if (bs->rect_mask) {
- bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED;
- }
-}
-
-static int bake_intersect_tree(RayObject *raytree, Isect *isect, float *start, float *dir, float sign, float *hitco, float *dist)
-{
- float maxdist;
- int hit;
-
- /* might be useful to make a user setting for maxsize*/
- if (R.r.bake_maxdist > 0.0f)
- maxdist = R.r.bake_maxdist;
- else
- maxdist = RE_RAYTRACE_MAXDIST + R.r.bake_biasdist;
-
- /* 'dir' is always normalized */
- madd_v3_v3v3fl(isect->start, start, dir, -R.r.bake_biasdist);
-
- mul_v3_v3fl(isect->dir, dir, sign);
-
- isect->dist = maxdist;
-
- hit = RE_rayobject_raycast(raytree, isect);
- if (hit) {
- madd_v3_v3v3fl(hitco, isect->start, isect->dir, isect->dist);
-
- *dist = isect->dist;
- }
-
- return hit;
-}
-
-static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3)
-{
- VlakRen *vlr = bs->vlr;
- float A, d1, d2, d3, *v1, *v2, *v3;
-
- if (bs->quad) {
- v1 = vlr->v1->co;
- v2 = vlr->v3->co;
- v3 = vlr->v4->co;
- }
- else {
- v1 = vlr->v1->co;
- v2 = vlr->v2->co;
- v3 = vlr->v3->co;
- }
-
- /* formula derived from barycentric coordinates:
- * (uvArea1*v1 + uvArea2*v2 + uvArea3*v3)/uvArea
- * then taking u and v partial derivatives to get dxco and dyco */
- A = (uv2[0] - uv1[0]) * (uv3[1] - uv1[1]) - (uv3[0] - uv1[0]) * (uv2[1] - uv1[1]);
-
- if (fabsf(A) > FLT_EPSILON) {
- A = 0.5f / A;
-
- d1 = uv2[1] - uv3[1];
- d2 = uv3[1] - uv1[1];
- d3 = uv1[1] - uv2[1];
- bs->dxco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A;
- bs->dxco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A;
- bs->dxco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A;
-
- d1 = uv3[0] - uv2[0];
- d2 = uv1[0] - uv3[0];
- d3 = uv2[0] - uv1[0];
- bs->dyco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A;
- bs->dyco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A;
- bs->dyco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A;
- }
- else {
- bs->dxco[0] = bs->dxco[1] = bs->dxco[2] = 0.0f;
- bs->dyco[0] = bs->dyco[1] = bs->dyco[2] = 0.0f;
- }
-
- if (bs->obi->flag & R_TRANSFORMED) {
- mul_m3_v3(bs->obi->nmat, bs->dxco);
- mul_m3_v3(bs->obi->nmat, bs->dyco);
- }
-}
-
-static void do_bake_shade(void *handle, int x, int y, float u, float v)
-{
- BakeShade *bs = handle;
- VlakRen *vlr = bs->vlr;
- ObjectInstanceRen *obi = bs->obi;
- Object *ob = obi->obr->ob;
- float l, *v1, *v2, *v3, tvn[3], ttang[4];
- int quad;
- ShadeSample *ssamp = &bs->ssamp;
- ShadeInput *shi = ssamp->shi;
-
- /* fast threadsafe break test */
- if (R.test_break(R.tbh))
- return;
-
- /* setup render coordinates */
- if (bs->quad) {
- v1 = vlr->v1->co;
- v2 = vlr->v3->co;
- v3 = vlr->v4->co;
- }
- else {
- v1 = vlr->v1->co;
- v2 = vlr->v2->co;
- v3 = vlr->v3->co;
- }
-
- l = 1.0f - u - v;
-
- /* shrink barycentric coordinates inwards slightly to avoid some issues
- * where baking selected to active might just miss the other face at the
- * near the edge of a face */
- if (bs->actob) {
- const float eps = 1.0f - 1e-4f;
- float invsum;
-
- u = (u - 0.5f) * eps + 0.5f;
- v = (v - 0.5f) * eps + 0.5f;
- l = (l - 0.5f) * eps + 0.5f;
-
- invsum = 1.0f / (u + v + l);
-
- u *= invsum;
- v *= invsum;
- l *= invsum;
- }
-
- /* renderco */
- shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0];
- shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1];
- shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2];
-
- /* avoid self shadow with vertex bake from adjacent faces [#33729] */
- if ((bs->vcol != NULL) && (bs->actob == NULL)) {
- madd_v3_v3fl(shi->co, vlr->n, 0.0001f);
- }
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, shi->co);
-
- copy_v3_v3(shi->dxco, bs->dxco);
- copy_v3_v3(shi->dyco, bs->dyco);
-
- quad = bs->quad;
- bake_set_shade_input(obi, vlr, shi, quad, 0, x, y, u, v);
-
- if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) {
- shade_input_set_shade_texco(shi);
- copy_v3_v3(tvn, shi->nmapnorm);
- copy_v4_v4(ttang, shi->nmaptang);
- }
-
- /* if we are doing selected to active baking, find point on other face */
- if (bs->actob) {
- Isect isec, minisec;
- float co[3], minco[3], dist, mindist = 0.0f;
- int hit, sign, dir = 1;
-
- /* intersect with ray going forward and backward*/
- hit = 0;
- memset(&minisec, 0, sizeof(minisec));
- minco[0] = minco[1] = minco[2] = 0.0f;
-
- copy_v3_v3(bs->dir, shi->vn);
-
- for (sign = -1; sign <= 1; sign += 2) {
- memset(&isec, 0, sizeof(isec));
- isec.mode = RE_RAY_MIRROR;
-
- isec.orig.ob = obi;
- isec.orig.face = vlr;
- isec.userdata = bs->actob;
- isec.check = RE_CHECK_VLR_BAKE;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
-
- if (bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) {
- if (!hit || len_squared_v3v3(shi->co, co) < len_squared_v3v3(shi->co, minco)) {
- minisec = isec;
- mindist = dist;
- copy_v3_v3(minco, co);
- hit = 1;
- dir = sign;
- }
- }
- }
-
- if (ELEM(bs->type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
- if (hit)
- bake_displacement(handle, shi, (dir == -1) ? mindist : -mindist, x, y);
- else
- bake_displacement(handle, shi, 0.0f, x, y);
- return;
- }
-
- /* if hit, we shade from the new point, otherwise from point one starting face */
- if (hit) {
- obi = (ObjectInstanceRen *)minisec.hit.ob;
- vlr = (VlakRen *)minisec.hit.face;
- quad = (minisec.isect == 2);
- copy_v3_v3(shi->co, minco);
-
- u = -minisec.u;
- v = -minisec.v;
- bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v);
- }
- }
-
- if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT)
- bake_shade(handle, ob, shi, quad, x, y, u, v, tvn, ttang);
- else
- bake_shade(handle, ob, shi, quad, x, y, u, v, NULL, NULL);
-}
-
-static int get_next_bake_face(BakeShade *bs)
-{
- ObjectRen *obr;
- VlakRen *vlr;
- MTFace *tface;
- static int v = 0, vdone = false;
- static ObjectInstanceRen *obi = NULL;
-
- if (bs == NULL) {
- vlr = NULL;
- v = vdone = false;
- obi = R.instancetable.first;
- return 0;
- }
-
- BLI_thread_lock(LOCK_CUSTOM1);
-
- for (; obi; obi = obi->next, v = 0) {
- obr = obi->obr;
-
- /* only allow non instances here */
- if (obr->flag & R_INSTANCEABLE)
- continue;
-
- for (; v < obr->totvlak; v++) {
- vlr = RE_findOrAddVlak(obr, v);
-
- if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) {
- if (R.r.bake_flag & R_BAKE_VCOL) {
- /* Gather face data for vertex color bake */
- Mesh *me;
- int *origindex, vcollayer;
- CustomDataLayer *cdl;
-
- if (obr->ob->type != OB_MESH)
- continue;
- me = obr->ob->data;
-
- origindex = RE_vlakren_get_origindex(obr, vlr, 0);
- if (origindex == NULL)
- continue;
- if (*origindex >= me->totpoly) {
- /* Small hack for Array modifier, which gives false
- * original indices - z0r */
- continue;
- }
-#if 0
- /* Only shade selected faces. */
- if ((me->mface[*origindex].flag & ME_FACE_SEL) == 0)
- continue;
-#endif
-
- vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL);
- if (vcollayer == -1)
- continue;
-
- cdl = &me->ldata.layers[vcollayer];
- bs->mpoly = me->mpoly + *origindex;
- bs->vcol = ((MLoopCol *)cdl->data) + bs->mpoly->loopstart;
- bs->mloop = me->mloop + bs->mpoly->loopstart;
-
- /* Tag mesh for reevaluation. */
- me->id.tag |= LIB_TAG_DOIT;
- }
- else {
- Image *ima = NULL;
- ImBuf *ibuf = NULL;
- const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f};
- const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f};
- const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f};
- const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};
-
- tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
-
- if (!tface || !tface->tpage)
- continue;
-
- ima = tface->tpage;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- if (ibuf == NULL)
- continue;
-
- if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ima->flag & IMA_USED_FOR_RENDER) {
- ima->id.tag &= ~LIB_TAG_DOIT;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- /* find the image for the first time? */
- if (ima->id.tag & LIB_TAG_DOIT) {
- ima->id.tag &= ~LIB_TAG_DOIT;
-
- /* we either fill in float or char, this ensures things go fine */
- if (ibuf->rect_float)
- imb_freerectImBuf(ibuf);
- /* clear image */
- if (R.r.bake_flag & R_BAKE_CLEAR) {
- if (R.r.bake_mode == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT)
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
- else if (ELEM(R.r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE))
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid);
- else
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
- }
- /* might be read by UI to set active image for display */
- R.bakebuf = ima;
- }
-
- /* Tag image for redraw. */
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- bs->obi = obi;
- bs->vlr = vlr;
- bs->vdone++; /* only for error message if nothing was rendered */
- v++;
- BLI_thread_unlock(LOCK_CUSTOM1);
- return 1;
- }
- }
- }
-
- BLI_thread_unlock(LOCK_CUSTOM1);
- return 0;
-}
-
-static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v)
-{
- int *origindex, i;
- MLoopCol *basevcol;
- MLoop *mloop;
-
- /* per vertex fixed seed */
- BLI_thread_srandom(bs->thread, vert->index);
-
- origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0);
- if (!origindex || *origindex == ORIGINDEX_NONE)
- return;
-
- /* Search for matching vertex index and apply shading. */
- for (i = 0; i < bs->mpoly->totloop; i++) {
- mloop = bs->mloop + i;
- if (mloop->v != *origindex)
- continue;
- basevcol = bs->vcol;
- bs->vcol = basevcol + i;
- do_bake_shade(bs, 0, 0, u, v);
- bs->vcol = basevcol;
- break;
- }
-}
-
-/* Bake all vertices of a face. Actually, this still works on a face-by-face
- * basis, and each vertex on each face is shaded. Vertex colors are a property
- * of loops, not vertices. */
-static void shade_verts(BakeShade *bs)
-{
- VlakRen *vlr = bs->vlr;
-
- /* Disable baking to image; write to vcol instead. vcol pointer is set in
- * bake_single_vertex. */
- bs->ima = NULL;
- bs->rect = NULL;
- bs->rect_float = NULL;
- bs->displacement_buffer = NULL;
- bs->displacement_min = FLT_MAX;
- bs->displacement_max = -FLT_MAX;
-
- bs->quad = 0;
-
- /* No anti-aliasing for vertices. */
- zero_v3(bs->dxco);
- zero_v3(bs->dyco);
-
- /* Shade each vertex of the face. u and v are barycentric coordinates; since
- * we're only interested in vertices, these will be 0 or 1. */
- if ((vlr->flag & R_FACE_SPLIT) == 0) {
- /* Processing triangle face, whole quad, or first half of split quad. */
-
- bake_single_vertex(bs, bs->vlr->v1, 1.0f, 0.0f);
- bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f);
- bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f);
-
- if (vlr->v4) {
- bs->quad = 1;
- bake_single_vertex(bs, bs->vlr->v4, 0.0f, 0.0f);
- }
- }
- else {
- /* Processing second half of split quad. Only one vertex to go. */
- if (vlr->flag & R_DIVIDE_24) {
- bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f);
- }
- else {
- bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f);
- }
- }
-}
-
-/* already have tested for tface and ima and zspan */
-static void shade_tface(BakeShade *bs)
-{
- VlakRen *vlr = bs->vlr;
- ObjectInstanceRen *obi = bs->obi;
- ObjectRen *obr = obi->obr;
- MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
- Image *ima = tface->tpage;
- float vec[4][2];
- int a, i1, i2, i3;
-
- /* per face fixed seed */
- BLI_thread_srandom(bs->thread, vlr->index);
-
- /* check valid zspan */
- if (ima != bs->ima) {
- BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL);
-
- bs->ima = ima;
- bs->ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- /* note, these calls only free/fill contents of zspan struct, not zspan itself */
- zbuf_free_span(bs->zspan);
- zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop);
- }
-
- bs->rectx = bs->ibuf->x;
- bs->recty = bs->ibuf->y;
- bs->rect = bs->ibuf->rect;
- bs->rect_colorspace = bs->ibuf->rect_colorspace;
- bs->rect_float = bs->ibuf->rect_float;
- bs->vcol = NULL;
- bs->quad = 0;
- bs->rect_mask = NULL;
- bs->displacement_buffer = NULL;
-
- if (bs->use_mask || bs->use_displacement_buffer) {
- BakeImBufuserData *userdata = bs->ibuf->userdata;
- if (userdata == NULL) {
- BLI_thread_lock(LOCK_CUSTOM1);
- userdata = bs->ibuf->userdata;
- if (userdata == NULL) /* since the thread was locked, its possible another thread alloced the value */
- userdata = MEM_callocN(sizeof(BakeImBufuserData), "BakeImBufuserData");
-
- if (bs->use_mask) {
- if (userdata->mask_buffer == NULL) {
- userdata->mask_buffer = MEM_callocN(sizeof(char) * bs->rectx * bs->recty, "BakeMask");
- }
- }
-
- if (bs->use_displacement_buffer) {
- if (userdata->displacement_buffer == NULL) {
- userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp");
- }
- }
-
- bs->ibuf->userdata = userdata;
-
- BLI_thread_unlock(LOCK_CUSTOM1);
- }
-
- bs->rect_mask = userdata->mask_buffer;
- bs->displacement_buffer = userdata->displacement_buffer;
- }
-
- /* get pixel level vertex coordinates */
- for (a = 0; a < 4; a++) {
- /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests
- * where a pixel gets in between 2 faces or the middle of a quad,
- * camera aligned quads also have this problem but they are less common.
- * Add a small offset to the UVs, fixes bug #18685 - Campbell */
- vec[a][0] = tface->uv[a][0] * (float)bs->rectx - (0.5f + 0.001f);
- vec[a][1] = tface->uv[a][1] * (float)bs->recty - (0.5f + 0.002f);
- }
-
- /* UV indices have to be corrected for possible quad->tria splits */
- i1 = 0; i2 = 1; i3 = 2;
- vlr_set_uv_indices(vlr, &i1, &i2, &i3);
- bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]);
- zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade);
-
- if (vlr->v4) {
- bs->quad = 1;
- bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]);
- zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade);
- }
-}
-
-static void *do_bake_thread(void *bs_v)
-{
- BakeShade *bs = bs_v;
-
- while (get_next_bake_face(bs)) {
- if (R.r.bake_flag & R_BAKE_VCOL) {
- shade_verts(bs);
- }
- else {
- shade_tface(bs);
- }
-
- /* fast threadsafe break test */
- if (R.test_break(R.tbh))
- break;
-
- /* access is not threadsafe but since its just true/false probably ok
- * only used for interactive baking */
- if (bs->do_update) {
- *bs->do_update = true;
- }
- }
- bs->ready = true;
-
- BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL);
-
- return NULL;
-}
-
-void RE_bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
-{
- /* must check before filtering */
- const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
-
- /* Margin */
- if (filter) {
- IMB_filter_extend(ibuf, mask, filter);
- }
-
- /* if the bake results in new alpha then change the image setting */
- if (is_new_alpha) {
- ibuf->planes = R_IMF_PLANES_RGBA;
- }
- else {
- if (filter && ibuf->planes != R_IMF_PLANES_RGBA) {
- /* clear alpha added by filtering */
- IMB_rectfill_alpha(ibuf, 1.0f);
- }
- }
-}
-
-void RE_bake_ibuf_normalize_displacement(ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max)
-{
- int i;
- const float *current_displacement = displacement;
- const char *current_mask = mask;
- float max_distance;
-
- max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max));
-
- for (i = 0; i < ibuf->x * ibuf->y; i++) {
- if (*current_mask == FILTER_MASK_USED) {
- float normalized_displacement;
-
- if (max_distance > 1e-5f)
- normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2);
- else
- normalized_displacement = 0.5f;
-
- if (ibuf->rect_float) {
- /* currently baking happens to RGBA only */
- float *fp = ibuf->rect_float + i * 4;
- fp[0] = fp[1] = fp[2] = normalized_displacement;
- fp[3] = 1.0f;
- }
-
- if (ibuf->rect) {
- unsigned char *cp = (unsigned char *) (ibuf->rect + i);
- cp[0] = cp[1] = cp[2] = unit_float_to_uchar_clamp(normalized_displacement);
- cp[3] = 255;
- }
- }
-
- current_displacement++;
- current_mask++;
- }
-}
-
-/* using object selection tags, the faces with UV maps get baked */
-/* render should have been setup */
-/* returns 0 if nothing was handled */
-int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress)
-{
- BakeShade *handles;
- ListBase threads;
- Image *ima;
- int a, vdone = false, result = BAKE_RESULT_OK;
- bool use_mask = false;
- bool use_displacement_buffer = false;
- bool do_manage = false;
-
- if (ELEM(type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
- do_manage = BKE_scene_check_color_management_enabled(re->scene);
- }
-
- re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene);
-
- /* initialize render global */
- R = *re;
- R.bakebuf = NULL;
-
- /* initialize static vars */
- get_next_bake_face(NULL);
-
- /* do we need a mask? */
- if (re->r.bake_filter)
- use_mask = true;
-
- /* do we need buffer to store displacements */
- if (ELEM(type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
- if (((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) ||
- (type == RE_BAKE_DERIVATIVE))
- {
- use_displacement_buffer = true;
- use_mask = true;
- }
- }
-
- /* baker uses this flag to detect if image was initialized */
- if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
- for (ima = G.main->image.first; ima; ima = ima->id.next) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- ima->id.tag |= LIB_TAG_DOIT;
- ima->flag &= ~IMA_USED_FOR_RENDER;
- if (ibuf) {
- ibuf->userdata = NULL; /* use for masking if needed */
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
- }
-
- if (R.r.bake_flag & R_BAKE_VCOL) {
- /* untag all meshes */
- BKE_main_id_tag_listbase(&G.main->mesh, LIB_TAG_DOIT, false);
- }
-
- BLI_threadpool_init(&threads, do_bake_thread, re->r.threads);
-
- handles = MEM_callocN(sizeof(BakeShade) * re->r.threads, "BakeShade");
-
- /* get the threads running */
- for (a = 0; a < re->r.threads; a++) {
- handles[a].thread = a;
-
- /* set defaults in handles */
- handles[a].ssamp.shi[0].lay = re->lay;
-
- if (type == RE_BAKE_SHADOW) {
- handles[a].ssamp.shi[0].passflag = SCE_PASS_SHADOW;
- }
- else {
- handles[a].ssamp.shi[0].passflag = SCE_PASS_COMBINED;
- }
- handles[a].ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC);
- handles[a].ssamp.shi[0].thread = a;
- handles[a].ssamp.shi[0].do_manage = do_manage;
- handles[a].ssamp.tot = 1;
-
- handles[a].type = type;
- handles[a].actob = actob;
- if (R.r.bake_flag & R_BAKE_VCOL)
- handles[a].zspan = NULL;
- else
- handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake");
-
- handles[a].use_mask = use_mask;
- handles[a].use_displacement_buffer = use_displacement_buffer;
-
- handles[a].do_update = do_update; /* use to tell the view to update */
-
- handles[a].displacement_min = FLT_MAX;
- handles[a].displacement_max = -FLT_MAX;
-
- BLI_threadpool_insert(&threads, &handles[a]);
- }
-
- /* wait for everything to be done */
- a = 0;
- while (a != re->r.threads) {
- PIL_sleep_ms(50);
-
- /* calculate progress */
- for (vdone = false, a = 0; a < re->r.threads; a++)
- vdone += handles[a].vdone;
- if (progress)
- *progress = (float)(vdone / (float)re->totvlak);
-
- for (a = 0; a < re->r.threads; a++) {
- if (handles[a].ready == false) {
- break;
- }
- }
- }
-
- /* filter and refresh images */
- if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
- float displacement_min = FLT_MAX, displacement_max = -FLT_MAX;
-
- if (use_displacement_buffer) {
- for (a = 0; a < re->r.threads; a++) {
- displacement_min = min_ff(displacement_min, handles[a].displacement_min);
- displacement_max = max_ff(displacement_max, handles[a].displacement_max);
- }
- }
-
- for (ima = G.main->image.first; ima; ima = ima->id.next) {
- if ((ima->id.tag & LIB_TAG_DOIT) == 0) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- BakeImBufuserData *userdata;
-
- if (ima->flag & IMA_USED_FOR_RENDER)
- result = BAKE_RESULT_FEEDBACK_LOOP;
-
- if (!ibuf)
- continue;
-
- userdata = (BakeImBufuserData *)ibuf->userdata;
- if (userdata) {
- if (use_displacement_buffer) {
- if (type == RE_BAKE_DERIVATIVE) {
- float user_scale = (R.r.bake_flag & R_BAKE_USERSCALE) ? R.r.bake_user_scale : -1.0f;
- RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
- displacement_min, displacement_max, user_scale);
- }
- else {
- RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
- displacement_min, displacement_max);
- }
- }
-
- RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter);
- }
-
- ibuf->userflags |= IB_BITMAPDIRTY;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
- }
-
- /* calculate return value */
- for (a = 0; a < re->r.threads; a++) {
- zbuf_free_span(handles[a].zspan);
- MEM_freeN(handles[a].zspan);
- }
- }
-
- MEM_freeN(handles);
-
- BLI_threadpool_end(&threads);
-
- if (vdone == 0) {
- result = BAKE_RESULT_NO_OBJECTS;
- }
-
- return result;
-}
-
-struct Image *RE_bake_shade_get_image(void)
-{
- return R.bakebuf;
-}
-
-/* **************** Derivative Maps Baker **************** */
-
-static void add_single_heights_margin(const ImBuf *ibuf, const char *mask, float *heights_buffer)
-{
- int x, y;
-
- for (y = 0; y < ibuf->y; y++) {
- for (x = 0; x < ibuf->x; x++) {
- int index = ibuf->x * y + x;
-
- /* If unassigned pixel, look for neighbors. */
- if (mask[index] != FILTER_MASK_USED) {
- float height_acc = 0;
- int denom = 0;
- int i, j;
-
- for (j = -1; j <= 1; j++)
- for (i = -1; i <= 1; i++) {
- int w = (i == 0 ? 1 : 0) + (j == 0 ? 1 : 0) + 1;
-
- if (i != 0 || j != 0) {
- int index2 = 0;
- int x0 = x + i;
- int y0 = y + j;
-
- CLAMP(x0, 0, ibuf->x - 1);
- CLAMP(y0, 0, ibuf->y - 1);
-
- index2 = ibuf->x * y0 + x0;
-
- if (mask[index2] == FILTER_MASK_USED) {
- height_acc += w * heights_buffer[index2];
- denom += w;
- }
- }
- }
-
- /* Insert final value. */
- if (denom > 0) {
- heights_buffer[index] = height_acc / denom;
- }
- }
- }
- }
-}
-
-/* returns user-scale */
-float RE_bake_make_derivative(ImBuf *ibuf, float *heights_buffer, const char *mask,
- const float height_min, const float height_max,
- const float fmult)
-{
- const float delta_height = height_max - height_min;
- const float denom = delta_height > 0.0f ? (8 * delta_height) : 1.0f;
- bool auto_range_fit = fmult <= 0.0f;
- float max_num_deriv = -1.0f;
- int x, y, index;
-
- /* Need a single margin to calculate good derivatives. */
- add_single_heights_margin(ibuf, mask, heights_buffer);
-
- if (auto_range_fit) {
- /* If automatic range fitting is enabled. */
- for (y = 0; y < ibuf->y; y++) {
- const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1);
- const int Yc = y;
- const int Yd = y == 0 ? 0 : (y - 1);
-
- for (x = 0; x < ibuf->x; x++) {
- const int Xl = x == 0 ? 0 : (x - 1);
- const int Xc = x;
- const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1);
-
- const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl];
- const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl];
- const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl];
-
- const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl];
- const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc];
- const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr];
-
- /* This corresponds to using the sobel kernel on the heights buffer
- * to obtain the derivative multiplied by 8.
- */
- const float deriv_x = Hu + 2 * Hcy + Hd;
- const float deriv_y = Hr + 2 * Hcx + Hl;
-
- /* early out */
- index = ibuf->x * y + x;
- if (mask[index] != FILTER_MASK_USED) {
- continue;
- }
-
- /* Widen bound. */
- if (fabsf(deriv_x) > max_num_deriv) {
- max_num_deriv = fabsf(deriv_x);
- }
-
- if (fabsf(deriv_y) > max_num_deriv) {
- max_num_deriv = fabsf(deriv_y);
- }
- }
- }
- }
-
- /* Output derivatives. */
- auto_range_fit &= (max_num_deriv > 0);
- for (y = 0; y < ibuf->y; y++) {
- const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1);
- const int Yc = y;
- const int Yd = y == 0 ? 0 : (y - 1);
-
- for (x = 0; x < ibuf->x; x++) {
- const int Xl = x == 0 ? 0 : (x - 1);
- const int Xc = x;
- const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1);
-
- const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl];
- const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl];
- const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl];
-
- const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl];
- const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc];
- const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr];
-
- /* This corresponds to using the sobel kernel on the heights buffer
- * to obtain the derivative multiplied by 8.
- */
- float deriv_x = Hu + 2 * Hcy + Hd;
- float deriv_y = Hr + 2 * Hcx + Hl;
-
- /* Early out. */
- index = ibuf->x * y + x;
- if (mask[index] != FILTER_MASK_USED) {
- continue;
- }
-
- if (auto_range_fit) {
- deriv_x /= max_num_deriv;
- deriv_y /= max_num_deriv;
- }
- else {
- deriv_x *= (fmult / denom);
- deriv_y *= (fmult / denom);
- }
-
- deriv_x = deriv_x * 0.5f + 0.5f;
- deriv_y = deriv_y * 0.5f + 0.5f;
-
- /* Clamp. */
- CLAMP(deriv_x, 0.0f, 1.0f);
- CLAMP(deriv_y, 0.0f, 1.0f);
-
- /* Write out derivatives. */
- if (ibuf->rect_float) {
- float *rrgbf = ibuf->rect_float + index * 4;
-
- rrgbf[0] = deriv_x;
- rrgbf[1] = deriv_y;
- rrgbf[2] = 0.0f;
- rrgbf[3] = 1.0f;
- }
- else {
- char *rrgb = (char *)ibuf->rect + index * 4;
-
- rrgb[0] = unit_float_to_uchar_clamp(deriv_x);
- rrgb[1] = unit_float_to_uchar_clamp(deriv_y);
- rrgb[2] = 0;
- rrgb[3] = 255;
- }
- }
- }
-
- /* Eeturn user-scale (for rendering). */
- return auto_range_fit ? (max_num_deriv / denom) : (fmult > 0.0f ? (1.0f / fmult) : 0.0f);
-}
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 4d5a8458897..ca3907e8b73 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -71,11 +71,16 @@
#include "BLI_math.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_bvhutils.h"
+#include "BKE_customdata.h"
#include "BKE_image.h"
-#include "BKE_node.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_node.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -84,19 +89,8 @@
/* local include */
#include "render_types.h"
-#include "shading.h"
#include "zbuf.h"
-/* Remove when Cycles moves from MFace to MLoopTri */
-#define USE_MFACE_WORKAROUND
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
typedef struct BakeDataZSpan {
BakePixel *pixel_array;
int primitive_id;
@@ -263,6 +257,36 @@ static void calc_point_from_barycentric_extrusion(
copy_v3_v3(r_dir, dir);
}
+static void barycentric_differentials_from_position(
+ const float co[3], const float v1[3], const float v2[3], const float v3[3],
+ const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
+ float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v)
+{
+ /* find most stable axis to project */
+ int axis1, axis2;
+ axis_dominant_v3(&axis1, &axis2, facenor);
+
+ /* compute u,v and derivatives */
+ float t00 = v3[axis1] - v1[axis1];
+ float t01 = v3[axis2] - v1[axis2];
+ float t10 = v3[axis1] - v2[axis1];
+ float t11 = v3[axis2] - v2[axis2];
+
+ float detsh = (t00 * t11 - t10 * t01);
+ detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
+ t00 *= detsh; t01 *= detsh;
+ t10 *= detsh; t11 *= detsh;
+
+ *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10;
+ *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01;
+ if (differentials) {
+ *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10;
+ *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01;
+ *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10;
+ *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01;
+ }
+}
+
/**
* This function populates pixel_array and returns TRUE if things are correct
*/
@@ -371,33 +395,12 @@ static bool cast_ray_highpoly(
return hit_mesh != -1;
}
-#ifdef USE_MFACE_WORKAROUND
-/**
- * Until cycles moves to #MLoopTri, we need to keep face-rotation in sync with #test_index_face
- *
- * We only need to consider quads since #BKE_mesh_recalc_tessellation doesn't execute this on triangles.
- */
-static void test_index_face_looptri(const MPoly *mp, MLoop *mloop, MLoopTri *lt)
-{
- if (mp->totloop == 4) {
- if (UNLIKELY((mloop[mp->loopstart + 2].v == 0) ||
- (mloop[mp->loopstart + 3].v == 0)))
- {
- /* remap: (2, 3, 0, 1) */
- unsigned int l = mp->loopstart;
- ARRAY_SET_ITEMS(lt[0].tri, l + 2, l + 3, l + 0);
- ARRAY_SET_ITEMS(lt[1].tri, l + 2, l + 0, l + 1);
- }
- }
-}
-#endif
-
/**
* This function populates an array of verts for the triangles of a mesh
* Tangent and Normals are also stored
*/
static TriTessFace *mesh_calc_tri_tessface(
- Mesh *me, bool tangent, DerivedMesh *dm)
+ Mesh *me, bool tangent, Mesh *me_eval)
{
int i;
MVert *mvert;
@@ -411,19 +414,15 @@ static TriTessFace *mesh_calc_tri_tessface(
unsigned int mpoly_prev = UINT_MAX;
float no[3];
-#ifdef USE_MFACE_WORKAROUND
- unsigned int mpoly_prev_testindex = UINT_MAX;
-#endif
-
mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
triangles = MEM_mallocN(sizeof(TriTessFace) * tottri, __func__);
if (tangent) {
- DM_ensure_normals(dm);
- DM_calc_loop_tangents(dm, true, NULL, 0);
+ BKE_mesh_ensure_normals_for_display(me_eval);
+ BKE_mesh_calc_loop_tangents(me_eval, true, NULL, 0);
- tspace = dm->getLoopDataArray(dm, CD_TANGENT);
+ tspace = CustomData_get_layer(&me_eval->ldata, CD_TANGENT);
BLI_assert(tspace);
}
@@ -434,20 +433,13 @@ static TriTessFace *mesh_calc_tri_tessface(
looptri);
- const float *precomputed_normals = dm ? dm->getPolyDataArray(dm, CD_NORMAL) : NULL;
+ const float *precomputed_normals = me_eval ? CustomData_get_layer(&me_eval->pdata, CD_NORMAL) : NULL;
const bool calculate_normal = precomputed_normals ? false : true;
for (i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
const MPoly *mp = &me->mpoly[lt->poly];
-#ifdef USE_MFACE_WORKAROUND
- if (lt->poly != mpoly_prev_testindex) {
- test_index_face_looptri(mp, me->mloop, &looptri[i]);
- mpoly_prev_testindex = lt->poly;
- }
-#endif
-
triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v];
@@ -488,8 +480,8 @@ bool RE_bake_pixels_populate_from_objects(
bool is_cage = me_cage != NULL;
bool result = true;
- DerivedMesh *dm_low = NULL;
- DerivedMesh **dm_highpoly;
+ Mesh *me_eval_low = NULL;
+ Mesh **me_highpoly;
BVHTreeFromMesh *treeData;
/* Note: all coordinates are in local space */
@@ -501,12 +493,12 @@ bool RE_bake_pixels_populate_from_objects(
tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array");
/* assume all highpoly tessfaces are triangles */
- dm_highpoly = MEM_mallocN(sizeof(DerivedMesh *) * tot_highpoly, "Highpoly Derived Meshes");
+ me_highpoly = MEM_mallocN(sizeof(Mesh *) * tot_highpoly, "Highpoly Derived Meshes");
treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees");
if (!is_cage) {
- dm_low = CDDM_from_mesh(me_low);
- tris_low = mesh_calc_tri_tessface(me_low, true, dm_low);
+ me_eval_low = BKE_mesh_copy_for_eval(me_low, false);
+ tris_low = mesh_calc_tri_tessface(me_low, true, me_eval_low);
}
else if (is_custom_cage) {
tris_low = mesh_calc_tri_tessface(me_low, false, NULL);
@@ -521,12 +513,12 @@ bool RE_bake_pixels_populate_from_objects(
for (i = 0; i < tot_highpoly; i++) {
tris_high[i] = mesh_calc_tri_tessface(highpoly[i].me, false, NULL);
- dm_highpoly[i] = CDDM_from_mesh(highpoly[i].me);
- DM_ensure_tessface(dm_highpoly[i]);
+ me_highpoly[i] = highpoly[i].me;
+ BKE_mesh_tessface_ensure(me_highpoly[i]);
- if (dm_highpoly[i]->getNumTessFaces(dm_highpoly[i]) != 0) {
+ if (me_highpoly[i]->totface != 0) {
/* Create a bvh-tree for each highpoly object */
- bvhtree_from_mesh_get(&treeData[i], dm_highpoly[i], BVHTREE_FROM_FACES, 2);
+ BKE_bvhtree_from_mesh_get(&treeData[i], me_highpoly[i], BVHTREE_FROM_FACES, 2);
if (treeData[i].tree == NULL) {
printf("Baking: out of memory while creating BHVTree for object \"%s\"\n", highpoly[i].ob->id.name + 2);
@@ -581,10 +573,6 @@ cleanup:
for (i = 0; i < tot_highpoly; i++) {
free_bvhtree_from_mesh(&treeData[i]);
- if (dm_highpoly[i]) {
- dm_highpoly[i]->release(dm_highpoly[i]);
- }
-
if (tris_high[i]) {
MEM_freeN(tris_high[i]);
}
@@ -592,10 +580,10 @@ cleanup:
MEM_freeN(tris_high);
MEM_freeN(treeData);
- MEM_freeN(dm_highpoly);
+ MEM_freeN(me_highpoly);
- if (dm_low) {
- dm_low->release(dm_low);
+ if (me_eval_low) {
+ BKE_id_free(NULL, me_eval_low);
}
if (tris_low) {
MEM_freeN(tris_low);
@@ -640,9 +628,6 @@ void RE_bake_pixels_populate(
const MLoopUV *mloopuv;
const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
-#ifdef USE_MFACE_WORKAROUND
- unsigned int mpoly_prev_testindex = UINT_MAX;
-#endif
if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
@@ -666,7 +651,7 @@ void RE_bake_pixels_populate(
}
for (i = 0; i < bake_images->size; i++) {
- zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop);
+ zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height);
}
looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
@@ -692,13 +677,6 @@ void RE_bake_pixels_populate(
bd.bk_image = &bake_images->data[image_id];
bd.primitive_id = ++p_id;
-#ifdef USE_MFACE_WORKAROUND
- if (lt->poly != mpoly_prev_testindex) {
- test_index_face_looptri(mp, me->mloop, &looptri[i]);
- mpoly_prev_testindex = lt->poly;
- }
-#endif
-
for (a = 0; a < 3; a++) {
const float *uv = mloopuv[lt->tri[a]].uv;
@@ -785,9 +763,9 @@ void RE_bake_normal_world_to_tangent(
TriTessFace *triangles;
- DerivedMesh *dm = CDDM_from_mesh(me);
+ Mesh *me_eval = BKE_mesh_copy_for_eval(me, false);
- triangles = mesh_calc_tri_tessface(me, true, dm);
+ triangles = mesh_calc_tri_tessface(me, true, me_eval);
BLI_assert(num_pixels >= 3);
@@ -883,8 +861,9 @@ void RE_bake_normal_world_to_tangent(
/* garbage collection */
MEM_freeN(triangles);
- if (dm)
- dm->release(dm);
+ if (me_eval) {
+ BKE_id_free(NULL, me_eval);
+ }
}
void RE_bake_normal_world_to_object(
@@ -959,36 +938,6 @@ void RE_bake_ibuf_clear(Image *image, const bool is_tangent)
/* ************************************************************* */
-/**
- * not the real UV, but the internal per-face UV instead
- * I'm using it to test if everything is correct */
-static bool bake_uv(const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[])
-{
- size_t i;
-
- for (i=0; i < num_pixels; i++) {
- size_t offset = i * depth;
- copy_v2_v2(&result[offset], pixel_array[i].uv);
- }
-
- return true;
-}
-
-bool RE_bake_internal(
- Render *UNUSED(re), Object *UNUSED(object), const BakePixel pixel_array[],
- const size_t num_pixels, const int depth, const eScenePassType pass_type, float result[])
-{
- switch (pass_type) {
- case SCE_PASS_UV:
- {
- return bake_uv(pixel_array, num_pixels, depth, result);
- }
- default:
- break;
- }
- return false;
-}
-
int RE_pass_depth(const eScenePassType pass_type)
{
/* IMB_buffer_byte_from_float assumes 4 channels
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
deleted file mode 100644
index 15432af4915..00000000000
--- a/source/blender/render/intern/source/convertblender.c
+++ /dev/null
@@ -1,6014 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributors: 2004/2005/2006 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/convertblender.c
- * \ingroup render
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <limits.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_rand.h"
-#include "BLI_memarena.h"
-#ifdef WITH_FREESTYLE
-# include "BLI_edgehash.h"
-#endif
-
-#include "BLT_translation.h"
-
-#include "DNA_material_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_image_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_object_fluidsim_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-
-#include "BKE_anim.h"
-#include "BKE_curve.h"
-#include "BKE_customdata.h"
-#include "BKE_colortools.h"
-#include "BKE_displist.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
-#include "BKE_key.h"
-#include "BKE_image.h"
-#include "BKE_lattice.h"
-#include "BKE_material.h"
-#include "BKE_main.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_modifier.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_scene.h"
-
-#include "PIL_time.h"
-
-#include "envmap.h"
-#include "occlusion.h"
-#include "pointdensity.h"
-#include "voxeldata.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "renderpipeline.h"
-#include "shadbuf.h"
-#include "shading.h"
-#include "strand.h"
-#include "texture.h"
-#include "volume_precache.h"
-#include "sss.h"
-#include "zbuf.h"
-#include "sunsky.h"
-
-/* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp (for quad detection) */
-/* or for checking vertex normal flips */
-#define FLT_EPSILON10 1.19209290e-06F
-
-/* could enable at some point but for now there are far too many conversions */
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wdouble-promotion"
-#endif
-
-/* ------------------------------------------------------------------------- */
-/* tool functions/defines for ad hoc simplification and possible future
- * cleanup */
-/* ------------------------------------------------------------------------- */
-
-#define UVTOINDEX(u, v) (startvlak + (u) * sizev + (v))
-/*
- *
- * NOTE THAT U/V COORDINATES ARE SOMETIMES SWAPPED !!
- *
- * ^ ()----p4----p3----()
- * | | | | |
- * u | | F1 | F2 |
- * | | | |
- * ()----p1----p2----()
- * v ->
- */
-
-/* ------------------------------------------------------------------------- */
-
-#define CD_MASK_RENDER_INTERNAL \
- (CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL)
-
-static void split_v_renderfaces(ObjectRen *obr, int startvlak, int UNUSED(startvert), int UNUSED(usize), int vsize, int uIndex, int UNUSED(cyclu), int cyclv)
-{
- int vLen = vsize-1+(!!cyclv);
- int v;
-
- for (v=0; v<vLen; v++) {
- VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v);
- VlakRen *vlr_other;
- VertRen *vert = RE_vertren_copy(obr, vlr->v2);
-
- if (cyclv) {
- vlr->v2 = vert;
-
- if (v == vLen - 1) {
- vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + 0);
- vlr_other->v1 = vert;
- }
- else {
- vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
- vlr_other->v1 = vert;
- }
- }
- else {
- vlr->v2 = vert;
-
- if (v < vLen - 1) {
- vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
- vlr_other->v1 = vert;
- }
-
- if (v == 0) {
- vlr->v1 = RE_vertren_copy(obr, vlr->v1);
- }
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Stress, tangents and normals */
-/* ------------------------------------------------------------------------- */
-
-static void calc_edge_stress_add(float *accum, VertRen *v1, VertRen *v2)
-{
- float len= len_v3v3(v1->co, v2->co)/len_v3v3(v1->orco, v2->orco);
- float *acc;
-
- acc= accum + 2*v1->index;
- acc[0]+= len;
- acc[1]+= 1.0f;
-
- acc= accum + 2*v2->index;
- acc[0]+= len;
- acc[1]+= 1.0f;
-}
-
-static void calc_edge_stress(Render *UNUSED(re), ObjectRen *obr, Mesh *me)
-{
- float loc[3], size[3], *accum, *acc, *accumoffs, *stress;
- int a;
-
- if (obr->totvert==0) return;
-
- BKE_mesh_texspace_get(me, loc, NULL, size);
-
- accum= MEM_callocN(2*sizeof(float)*obr->totvert, "temp accum for stress");
-
- /* de-normalize orco */
- for (a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- if (ver->orco) {
- ver->orco[0]= ver->orco[0]*size[0] +loc[0];
- ver->orco[1]= ver->orco[1]*size[1] +loc[1];
- ver->orco[2]= ver->orco[2]*size[2] +loc[2];
- }
- }
-
- /* add stress values */
- accumoffs= accum; /* so we can use vertex index */
- for (a=0; a<obr->totvlak; a++) {
- VlakRen *vlr= RE_findOrAddVlak(obr, a);
-
- if (vlr->v1->orco && vlr->v4) {
- calc_edge_stress_add(accumoffs, vlr->v1, vlr->v2);
- calc_edge_stress_add(accumoffs, vlr->v2, vlr->v3);
- calc_edge_stress_add(accumoffs, vlr->v3, vlr->v1);
- if (vlr->v4) {
- calc_edge_stress_add(accumoffs, vlr->v3, vlr->v4);
- calc_edge_stress_add(accumoffs, vlr->v4, vlr->v1);
- calc_edge_stress_add(accumoffs, vlr->v2, vlr->v4);
- }
- }
- }
-
- for (a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- if (ver->orco) {
- /* find stress value */
- acc= accumoffs + 2*ver->index;
- if (acc[1]!=0.0f)
- acc[0]/= acc[1];
- stress= RE_vertren_get_stress(obr, ver, 1);
- *stress= *acc;
-
- /* restore orcos */
- ver->orco[0] = (ver->orco[0]-loc[0])/size[0];
- ver->orco[1] = (ver->orco[1]-loc[1])/size[1];
- ver->orco[2] = (ver->orco[2]-loc[2])/size[2];
- }
- }
-
- MEM_freeN(accum);
-}
-
-/* gets tangent from tface or orco */
-static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent)
-{
- MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0);
- VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4;
- float tang[3], *tav;
- float *uv1, *uv2, *uv3, *uv4;
- float uv[4][2];
-
- if (tface) {
- uv1= tface->uv[0];
- uv2= tface->uv[1];
- uv3= tface->uv[2];
- uv4= tface->uv[3];
- }
- else if (v1->orco) {
- uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
- map_to_sphere(&uv[0][0], &uv[0][1], v1->orco[0], v1->orco[1], v1->orco[2]);
- map_to_sphere(&uv[1][0], &uv[1][1], v2->orco[0], v2->orco[1], v2->orco[2]);
- map_to_sphere(&uv[2][0], &uv[2][1], v3->orco[0], v3->orco[1], v3->orco[2]);
- if (v4)
- map_to_sphere(&uv[3][0], &uv[3][1], v4->orco[0], v4->orco[1], v4->orco[2]);
- }
- else return;
-
- tangent_from_uv_v3(uv1, uv2, uv3, v1->co, v2->co, v3->co, vlr->n, tang);
-
- if (do_tangent) {
- tav= RE_vertren_get_tangent(obr, v1, 1);
- add_v3_v3(tav, tang);
- tav= RE_vertren_get_tangent(obr, v2, 1);
- add_v3_v3(tav, tang);
- tav= RE_vertren_get_tangent(obr, v3, 1);
- add_v3_v3(tav, tang);
- }
-
- if (v4) {
- tangent_from_uv_v3(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang);
-
- if (do_tangent) {
- tav= RE_vertren_get_tangent(obr, v1, 1);
- add_v3_v3(tav, tang);
- tav= RE_vertren_get_tangent(obr, v3, 1);
- add_v3_v3(tav, tang);
- tav= RE_vertren_get_tangent(obr, v4, 1);
- add_v3_v3(tav, tang);
- }
- }
-}
-
-
-
-/****************************************************************
- ************ tangent space generation interface ****************
- ****************************************************************/
-
-typedef struct {
- ObjectRen *obr;
- int mtface_index;
-} SRenderMeshToTangent;
-
-/* interface */
-#include "mikktspace.h"
-
-static int GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- return pMesh->obr->totvlak;
-}
-
-static int GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
- return vlr->v4!=NULL ? 4 : 3;
-}
-
-static void GetPosition(const SMikkTSpaceContext *pContext, float r_co[3], const int face_num, const int vert_index)
-{
- //assert(vert_index>=0 && vert_index<4);
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
- const float *co = (&vlr->v1)[vert_index]->co;
- copy_v3_v3(r_co, co);
-}
-
-static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_num, const int vert_index)
-{
- //assert(vert_index>=0 && vert_index<4);
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
- MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->mtface_index, NULL, 0);
- const float *coord;
-
- if (tface != NULL) {
- coord= tface->uv[vert_index];
- copy_v2_v2(r_uv, coord);
- }
- else if ((coord = (&vlr->v1)[vert_index]->orco)) {
- map_to_sphere(&r_uv[0], &r_uv[1], coord[0], coord[1], coord[2]);
- }
- else { /* else we get un-initialized value, 0.0 ok default? */
- zero_v2(r_uv);
- }
-}
-
-static void GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_num, const int vert_index)
-{
- //assert(vert_index>=0 && vert_index<4);
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
-
- if (vlr->flag & ME_SMOOTH) {
- const float *n = (&vlr->v1)[vert_index]->n;
- copy_v3_v3(r_no, n);
- }
- else {
- negate_v3_v3(r_no, vlr->n);
- }
-}
-static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, const int face_num, const int iVert)
-{
- //assert(vert_index>=0 && vert_index<4);
- SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
- VlakRen *vlr = RE_findOrAddVlak(pMesh->obr, face_num);
- float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, pMesh->mtface_index, true);
- if (ftang!=NULL) {
- copy_v3_v3(&ftang[iVert*4+0], fvTangent);
- ftang[iVert*4+3]=fSign;
- }
-}
-
-static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_vertex_normal, bool do_tangent, bool do_nmap_tangent)
-{
- int a;
-
- /* clear all vertex normals */
- if (do_vertex_normal) {
- for (a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- ver->n[0]=ver->n[1]=ver->n[2]= 0.0f;
- }
- }
-
- /* calculate cos of angles and point-masses, use as weight factor to
- * add face normal to vertex */
- for (a=0; a<obr->totvlak; a++) {
- VlakRen *vlr= RE_findOrAddVlak(obr, a);
- if (do_vertex_normal && vlr->flag & ME_SMOOTH) {
- float *n4= (vlr->v4)? vlr->v4->n: NULL;
- const float *c4= (vlr->v4)? vlr->v4->co: NULL;
-
- accumulate_vertex_normals_v3(vlr->v1->n, vlr->v2->n, vlr->v3->n, n4,
- vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co, c4);
- }
- if (do_tangent) {
- /* tangents still need to be calculated for flat faces too */
- /* weighting removed, they are not vertexnormals */
- calc_tangent_vector(obr, vlr, do_tangent);
- }
- }
-
- /* do solid faces */
- for (a=0; a<obr->totvlak; a++) {
- VlakRen *vlr= RE_findOrAddVlak(obr, a);
-
- if (do_vertex_normal && (vlr->flag & ME_SMOOTH)==0) {
- if (is_zero_v3(vlr->v1->n)) copy_v3_v3(vlr->v1->n, vlr->n);
- if (is_zero_v3(vlr->v2->n)) copy_v3_v3(vlr->v2->n, vlr->n);
- if (is_zero_v3(vlr->v3->n)) copy_v3_v3(vlr->v3->n, vlr->n);
- if (vlr->v4 && is_zero_v3(vlr->v4->n)) copy_v3_v3(vlr->v4->n, vlr->n);
- }
- }
-
- /* normalize vertex normals */
- for (a=0; a<obr->totvert; a++) {
- VertRen *ver= RE_findOrAddVert(obr, a);
- normalize_v3(ver->n);
- if (do_tangent) {
- float *tav= RE_vertren_get_tangent(obr, ver, 0);
- if (tav) {
- /* orthonorm. */
- const float tdn = dot_v3v3(tav, ver->n);
- tav[0] -= ver->n[0]*tdn;
- tav[1] -= ver->n[1]*tdn;
- tav[2] -= ver->n[2]*tdn;
- normalize_v3(tav);
- }
- }
- }
-
- /* normal mapping tangent with mikktspace */
- if (do_nmap_tangent != false) {
- SRenderMeshToTangent mesh2tangent;
- SMikkTSpaceContext sContext;
- SMikkTSpaceInterface sInterface;
- memset(&mesh2tangent, 0, sizeof(SRenderMeshToTangent));
- memset(&sContext, 0, sizeof(SMikkTSpaceContext));
- memset(&sInterface, 0, sizeof(SMikkTSpaceInterface));
-
- mesh2tangent.obr = obr;
-
- sContext.m_pUserData = &mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = GetNumFaces;
- sInterface.m_getNumVerticesOfFace = GetNumVertsOfFace;
- sInterface.m_getPosition = GetPosition;
- sInterface.m_getTexCoord = GetTextureCoordinate;
- sInterface.m_getNormal = GetNormal;
- sInterface.m_setTSpaceBasic = SetTSpace;
-
- for (a = 0; a < MAX_MTFACE; a++) {
- if (obr->tangent_mask & 1 << a) {
- mesh2tangent.mtface_index = a;
- genTangSpaceDefault(&sContext);
- }
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Autosmoothing: */
-/* ------------------------------------------------------------------------- */
-
-typedef struct ASvert {
- int totface;
- ListBase faces;
-} ASvert;
-
-typedef struct ASface {
- struct ASface *next, *prev;
- VlakRen *vlr[4];
- VertRen *nver[4];
-} ASface;
-
-static int as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
-{
- ASface *asf;
- int a = -1;
-
- if (v1 == NULL)
- return a;
-
- asf = asv->faces.last;
- if (asf) {
- for (a = 0; a < 4 && asf->vlr[a]; a++) {
- }
- }
- else {
- a = 4;
- }
-
- /* new face struct */
- if (a == 4) {
- a = 0;
- asf = MEM_callocN(sizeof(ASface), "asface");
- BLI_addtail(&asv->faces, asf);
- }
-
- asf->vlr[a] = vlr;
- asv->totface++;
-
- return a;
-}
-
-static VertRen *as_findvertex_lnor(VlakRen *vlr, VertRen *ver, ASvert *asv, const float lnor[3])
-{
- /* return when new vertex already was made, or existing one is OK */
- ASface *asf;
- int a;
-
- /* First face, we can use existing vert and assign it current lnor! */
- if (asv->totface == 1) {
- copy_v3_v3(ver->n, lnor);
- return ver;
- }
-
- /* In case existing ver has same normal as current lnor, we can simply use it! */
- if (equals_v3v3(lnor, ver->n)) {
- return ver;
- }
-
- asf = asv->faces.first;
- while (asf) {
- for (a = 0; a < 4; a++) {
- if (asf->vlr[a] && asf->vlr[a] != vlr) {
- /* this face already made a copy for this vertex! */
- if (asf->nver[a]) {
- if (equals_v3v3(lnor, asf->nver[a]->n)) {
- return asf->nver[a];
- }
- }
- }
- }
- asf = asf->next;
- }
-
- return NULL;
-}
-
-static void as_addvert_lnor(ObjectRen *obr, ASvert *asv, VertRen *ver, VlakRen *vlr, const short _lnor[3])
-{
- VertRen *v1;
- ASface *asf;
- int asf_idx;
- float lnor[3];
-
- normal_short_to_float_v3(lnor, _lnor);
-
- asf_idx = as_addvert(asv, ver, vlr);
- if (asf_idx < 0) {
- return;
- }
- asf = asv->faces.last;
-
- /* already made a new vertex within threshold? */
- v1 = as_findvertex_lnor(vlr, ver, asv, lnor);
- if (v1 == NULL) {
- /* make a new vertex */
- v1 = RE_vertren_copy(obr, ver);
- copy_v3_v3(v1->n, lnor);
- }
- if (v1 != ver) {
- asf->nver[asf_idx] = v1;
- if (vlr->v1 == ver) vlr->v1 = v1;
- if (vlr->v2 == ver) vlr->v2 = v1;
- if (vlr->v3 == ver) vlr->v3 = v1;
- if (vlr->v4 == ver) vlr->v4 = v1;
- }
-}
-
-/* note; autosmooth happens in object space still, after applying autosmooth we rotate */
-/* note2; actually, when original mesh and displist are equal sized, face normals are from original mesh */
-static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], short (*lnors)[4][3])
-{
- ASvert *asverts;
- VertRen *ver;
- VlakRen *vlr;
- int a, totvert;
-
- float rot[3][3];
-
- /* Note: For normals, we only want rotation, not scaling component.
- * Negative scales (aka mirroring) give wrong results, see T44102. */
- if (lnors) {
- float mat3[3][3], size[3];
-
- copy_m3_m4(mat3, mat);
- mat3_to_rot_size(rot, size, mat3);
- }
-
- if (obr->totvert == 0)
- return;
-
- totvert = obr->totvert;
- asverts = MEM_callocN(sizeof(ASvert) * totvert, "all smooth verts");
-
- if (lnors) {
- /* We construct listbase of all vertices and pointers to faces, and add new verts when needed
- * (i.e. when existing ones do not share the same (loop)normal).
- */
- for (a = 0; a < obr->totvlak; a++, lnors++) {
- vlr = RE_findOrAddVlak(obr, a);
- /* skip wire faces */
- if (vlr->v2 != vlr->v3) {
- as_addvert_lnor(obr, asverts+vlr->v1->index, vlr->v1, vlr, (const short*)lnors[0][0]);
- as_addvert_lnor(obr, asverts+vlr->v2->index, vlr->v2, vlr, (const short*)lnors[0][1]);
- as_addvert_lnor(obr, asverts+vlr->v3->index, vlr->v3, vlr, (const short*)lnors[0][2]);
- if (vlr->v4)
- as_addvert_lnor(obr, asverts+vlr->v4->index, vlr->v4, vlr, (const short*)lnors[0][3]);
- }
- }
- }
-
- /* free */
- for (a = 0; a < totvert; a++) {
- BLI_freelistN(&asverts[a].faces);
- }
- MEM_freeN(asverts);
-
- /* rotate vertices and calculate normal of faces */
- for (a = 0; a < obr->totvert; a++) {
- ver = RE_findOrAddVert(obr, a);
- mul_m4_v3(mat, ver->co);
- if (lnors) {
- mul_m3_v3(rot, ver->n);
- negate_v3(ver->n);
- }
- }
- for (a = 0; a < obr->totvlak; a++) {
- vlr = RE_findOrAddVlak(obr, a);
-
- /* skip wire faces */
- if (vlr->v2 != vlr->v3) {
- if (vlr->v4)
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- else
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Orco hash and Materials */
-/* ------------------------------------------------------------------------- */
-
-static float *get_object_orco(Render *re, void *ob)
-{
- if (!re->orco_hash) {
- return NULL;
- }
-
- return BLI_ghash_lookup(re->orco_hash, ob);
-}
-
-static void set_object_orco(Render *re, void *ob, float *orco)
-{
- if (!re->orco_hash)
- re->orco_hash = BLI_ghash_ptr_new("set_object_orco gh");
-
- BLI_ghash_insert(re->orco_hash, ob, orco);
-}
-
-static void free_mesh_orco_hash(Render *re)
-{
- if (re->orco_hash) {
- BLI_ghash_free(re->orco_hash, NULL, MEM_freeN);
- re->orco_hash = NULL;
- }
-}
-
-static void check_material_mapto(Material *ma)
-{
- int a;
- ma->mapto_textured = 0;
-
- /* cache which inputs are actually textured.
- * this can avoid a bit of time spent iterating through all the texture slots, map inputs and map tos
- * every time a property which may or may not be textured is accessed */
-
- for (a=0; a<MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex) {
- /* currently used only in volume render, so we'll check for those flags */
- if (ma->mtex[a]->mapto & MAP_DENSITY) ma->mapto_textured |= MAP_DENSITY;
- if (ma->mtex[a]->mapto & MAP_EMISSION) ma->mapto_textured |= MAP_EMISSION;
- if (ma->mtex[a]->mapto & MAP_EMISSION_COL) ma->mapto_textured |= MAP_EMISSION_COL;
- if (ma->mtex[a]->mapto & MAP_SCATTERING) ma->mapto_textured |= MAP_SCATTERING;
- if (ma->mtex[a]->mapto & MAP_TRANSMISSION_COL) ma->mapto_textured |= MAP_TRANSMISSION_COL;
- if (ma->mtex[a]->mapto & MAP_REFLECTION) ma->mapto_textured |= MAP_REFLECTION;
- if (ma->mtex[a]->mapto & MAP_REFLECTION_COL) ma->mapto_textured |= MAP_REFLECTION_COL;
- }
- }
-}
-static void flag_render_node_material(Render *re, bNodeTree *ntree)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name)==ID_MA) {
- Material *ma= (Material *)node->id;
-
- if ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP))
- re->flag |= R_ZTRA;
-
- ma->flag |= MA_IS_USED;
- }
- else if (node->type==NODE_GROUP)
- flag_render_node_material(re, (bNodeTree *)node->id);
- }
- }
-}
-
-static Material *give_render_material(Render *re, Object *ob, short nr)
-{
- extern Material defmaterial; /* material.c */
- Material *ma;
-
- ma= give_current_material(ob, nr);
- if (ma==NULL)
- ma= &defmaterial;
-
- if (re->r.mode & R_SPEED) ma->texco |= NEED_UV;
-
- if (ma->material_type == MA_TYPE_VOLUME) {
- ma->mode |= MA_TRANSP;
- ma->mode &= ~MA_SHADBUF;
- }
- if ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP))
- re->flag |= R_ZTRA;
-
- /* for light groups and SSS */
- ma->flag |= MA_IS_USED;
-
- if (ma->nodetree && ma->use_nodes)
- flag_render_node_material(re, ma->nodetree);
-
- check_material_mapto(ma);
-
- return ma;
-}
-
-/* ------------------------------------------------------------------------- */
-/* Particles */
-/* ------------------------------------------------------------------------- */
-typedef struct ParticleStrandData {
- struct MCol *mcol;
- float *orco, *uvco, *surfnor;
- float time, adapt_angle, adapt_pix, size;
- int totuv, totcol;
- int first, line, adapt, override_uv;
-}
-ParticleStrandData;
-/* future thread problem... */
-static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, ParticleStrandData *sd, const float vec[3], const float vec1[3])
-{
- static VertRen *v1= NULL, *v2= NULL;
- VlakRen *vlr= NULL;
- float nor[3], cross[3], crosslen, w, dx, dy, width;
- static float anor[3], avec[3];
- int flag, i;
- static int second=0;
-
- sub_v3_v3v3(nor, vec, vec1);
- normalize_v3(nor); /* nor needed as tangent */
- cross_v3_v3v3(cross, vec, nor);
-
- /* turn cross in pixelsize */
- w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
- dx= re->winx*cross[0]*re->winmat[0][0];
- dy= re->winy*cross[1]*re->winmat[1][1];
- w = sqrtf(dx * dx + dy * dy) / w;
-
- if (w!=0.0f) {
- float fac;
- if (ma->strand_ease!=0.0f) {
- if (ma->strand_ease<0.0f)
- fac= pow(sd->time, 1.0f+ma->strand_ease);
- else
- fac= pow(sd->time, 1.0f/(1.0f-ma->strand_ease));
- }
- else fac= sd->time;
-
- width= ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
-
- /* use actual Blender units for strand width and fall back to minimum width */
- if (ma->mode & MA_STR_B_UNITS) {
- crosslen= len_v3(cross);
- w= 2.0f*crosslen*ma->strand_min/w;
-
- if (width < w)
- width= w;
-
- /*cross is the radius of the strand so we want it to be half of full width */
- mul_v3_fl(cross, 0.5f/crosslen);
- }
- else
- width/=w;
-
- mul_v3_fl(cross, width);
- }
-
- if (ma->mode & MA_TANGENT_STR)
- flag= R_SMOOTH|R_TANGENT;
- else
- flag= R_SMOOTH;
-
- /* only 1 pixel wide strands filled in as quads now, otherwise zbuf errors */
- if (ma->strand_sta==1.0f)
- flag |= R_STRAND;
-
- /* single face line */
- if (sd->line) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->flag= flag;
- vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
-
- copy_v3_v3(vlr->v1->co, vec);
- add_v3_v3(vlr->v1->co, cross);
- copy_v3_v3(vlr->v1->n, nor);
- vlr->v1->orco= sd->orco;
- vlr->v1->accum = -1.0f; /* accum abuse for strand texco */
-
- copy_v3_v3(vlr->v2->co, vec);
- sub_v3_v3v3(vlr->v2->co, vlr->v2->co, cross);
- copy_v3_v3(vlr->v2->n, nor);
- vlr->v2->orco= sd->orco;
- vlr->v2->accum= vlr->v1->accum;
-
- copy_v3_v3(vlr->v4->co, vec1);
- add_v3_v3(vlr->v4->co, cross);
- copy_v3_v3(vlr->v4->n, nor);
- vlr->v4->orco= sd->orco;
- vlr->v4->accum = 1.0f; /* accum abuse for strand texco */
-
- copy_v3_v3(vlr->v3->co, vec1);
- sub_v3_v3v3(vlr->v3->co, vlr->v3->co, cross);
- copy_v3_v3(vlr->v3->n, nor);
- vlr->v3->orco= sd->orco;
- vlr->v3->accum= vlr->v4->accum;
-
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- vlr->mat= ma;
- vlr->ec= ME_V2V3;
-
- if (sd->surfnor) {
- float *snor= RE_vlakren_get_surfnor(obr, vlr, 1);
- copy_v3_v3(snor, sd->surfnor);
- }
-
- if (sd->uvco) {
- for (i=0; i<sd->totuv; i++) {
- MTFace *mtf;
- mtf=RE_vlakren_get_tface(obr, vlr, i, NULL, 1);
- mtf->uv[0][0]=mtf->uv[1][0]=
- mtf->uv[2][0]=mtf->uv[3][0]=(sd->uvco+2*i)[0];
- mtf->uv[0][1]=mtf->uv[1][1]=
- mtf->uv[2][1]=mtf->uv[3][1]=(sd->uvco+2*i)[1];
- }
- if (sd->override_uv>=0) {
- MTFace *mtf;
- mtf=RE_vlakren_get_tface(obr, vlr, sd->override_uv, NULL, 0);
-
- mtf->uv[0][0]=mtf->uv[3][0]=0.0f;
- mtf->uv[1][0]=mtf->uv[2][0]=1.0f;
-
- mtf->uv[0][1]=mtf->uv[1][1]=0.0f;
- mtf->uv[2][1]=mtf->uv[3][1]=1.0f;
- }
- }
- if (sd->mcol) {
- for (i=0; i<sd->totcol; i++) {
- MCol *mc;
- mc=RE_vlakren_get_mcol(obr, vlr, i, NULL, 1);
- mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
- mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
- }
- }
- }
- /* first two vertices of a strand */
- else if (sd->first) {
- if (sd->adapt) {
- copy_v3_v3(anor, nor);
- copy_v3_v3(avec, vec);
- second=1;
- }
-
- v1= RE_findOrAddVert(obr, obr->totvert++);
- v2= RE_findOrAddVert(obr, obr->totvert++);
-
- copy_v3_v3(v1->co, vec);
- add_v3_v3(v1->co, cross);
- copy_v3_v3(v1->n, nor);
- v1->orco= sd->orco;
- v1->accum = -1.0f; /* accum abuse for strand texco */
-
- copy_v3_v3(v2->co, vec);
- sub_v3_v3v3(v2->co, v2->co, cross);
- copy_v3_v3(v2->n, nor);
- v2->orco= sd->orco;
- v2->accum= v1->accum;
- }
- /* more vertices & faces to strand */
- else {
- if (sd->adapt==0 || second) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->flag= flag;
- vlr->v1= v1;
- vlr->v2= v2;
- vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
-
- v1= vlr->v4; /* cycle */
- v2= vlr->v3; /* cycle */
-
-
- if (sd->adapt) {
- second=0;
- copy_v3_v3(anor, nor);
- copy_v3_v3(avec, vec);
- }
-
- }
- else if (sd->adapt) {
- float dvec[3], pvec[3];
- sub_v3_v3v3(dvec, avec, vec);
- project_v3_v3v3(pvec, dvec, vec);
- sub_v3_v3v3(dvec, dvec, pvec);
-
- w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
- dx= re->winx*dvec[0]*re->winmat[0][0]/w;
- dy= re->winy*dvec[1]*re->winmat[1][1]/w;
- w = sqrtf(dx * dx + dy * dy);
- if (dot_v3v3(anor, nor)<sd->adapt_angle && w>sd->adapt_pix) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->flag= flag;
- vlr->v1= v1;
- vlr->v2= v2;
- vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
-
- v1= vlr->v4; /* cycle */
- v2= vlr->v3; /* cycle */
-
- copy_v3_v3(anor, nor);
- copy_v3_v3(avec, vec);
- }
- else {
- vlr= RE_findOrAddVlak(obr, obr->totvlak-1);
- }
- }
-
- copy_v3_v3(vlr->v4->co, vec);
- add_v3_v3(vlr->v4->co, cross);
- copy_v3_v3(vlr->v4->n, nor);
- vlr->v4->orco= sd->orco;
- vlr->v4->accum= -1.0f + 2.0f * sd->time; /* accum abuse for strand texco */
-
- copy_v3_v3(vlr->v3->co, vec);
- sub_v3_v3v3(vlr->v3->co, vlr->v3->co, cross);
- copy_v3_v3(vlr->v3->n, nor);
- vlr->v3->orco= sd->orco;
- vlr->v3->accum= vlr->v4->accum;
-
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- vlr->mat= ma;
- vlr->ec= ME_V2V3;
-
- if (sd->surfnor) {
- float *snor= RE_vlakren_get_surfnor(obr, vlr, 1);
- copy_v3_v3(snor, sd->surfnor);
- }
-
- if (sd->uvco) {
- for (i=0; i<sd->totuv; i++) {
- MTFace *mtf;
- mtf=RE_vlakren_get_tface(obr, vlr, i, NULL, 1);
- mtf->uv[0][0]=mtf->uv[1][0]=
- mtf->uv[2][0]=mtf->uv[3][0]=(sd->uvco+2*i)[0];
- mtf->uv[0][1]=mtf->uv[1][1]=
- mtf->uv[2][1]=mtf->uv[3][1]=(sd->uvco+2*i)[1];
- }
- if (sd->override_uv>=0) {
- MTFace *mtf;
- mtf=RE_vlakren_get_tface(obr, vlr, sd->override_uv, NULL, 0);
-
- mtf->uv[0][0]=mtf->uv[3][0]=0.0f;
- mtf->uv[1][0]=mtf->uv[2][0]=1.0f;
-
- mtf->uv[0][1]=mtf->uv[1][1]=(vlr->v1->accum+1.0f)/2.0f;
- mtf->uv[2][1]=mtf->uv[3][1]=(vlr->v3->accum+1.0f)/2.0f;
- }
- }
- if (sd->mcol) {
- for (i=0; i<sd->totcol; i++) {
- MCol *mc;
- mc=RE_vlakren_get_mcol(obr, vlr, i, NULL, 1);
- mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
- mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
- }
- }
- }
-}
-
-static void static_particle_wire(ObjectRen *obr, Material *ma, const float vec[3], const float vec1[3], int first, int line)
-{
- VlakRen *vlr;
- static VertRen *v1;
-
- if (line) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v3= vlr->v2;
- vlr->v4= NULL;
-
- copy_v3_v3(vlr->v1->co, vec);
- copy_v3_v3(vlr->v2->co, vec1);
-
- sub_v3_v3v3(vlr->n, vec, vec1);
- normalize_v3(vlr->n);
- copy_v3_v3(vlr->v1->n, vlr->n);
- copy_v3_v3(vlr->v2->n, vlr->n);
-
- vlr->mat= ma;
- vlr->ec= ME_V1V2;
-
- }
- else if (first) {
- v1= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(v1->co, vec);
- }
- else {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= v1;
- vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v3= vlr->v2;
- vlr->v4= NULL;
-
- v1= vlr->v2; /* cycle */
- copy_v3_v3(v1->co, vec);
-
- sub_v3_v3v3(vlr->n, vec, vec1);
- normalize_v3(vlr->n);
- copy_v3_v3(v1->n, vlr->n);
-
- vlr->mat= ma;
- vlr->ec= ME_V1V2;
- }
-
-}
-
-static void particle_curve(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd,
- const float loc[3], const float loc1[3], int seed, float *pa_co)
-{
- HaloRen *har = NULL;
-
- if (ma->material_type == MA_TYPE_WIRE)
- static_particle_wire(obr, ma, loc, loc1, sd->first, sd->line);
- else if (ma->material_type == MA_TYPE_HALO) {
- har= RE_inithalo_particle(re, obr, dm, ma, loc, loc1, sd->orco, sd->uvco, sd->size, 1.0, seed, pa_co);
- if (har) har->lay= obr->ob->lay;
- }
- else
- static_particle_strand(re, obr, ma, sd, loc, loc1);
-}
-static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, ParticleBillboardData *bb)
-{
- VlakRen *vlr;
- MTFace *mtf;
- float xvec[3], yvec[3], zvec[3], bb_center[3];
- /* Number of tiles */
- int totsplit = bb->uv_split * bb->uv_split;
- int tile, x, y;
- /* Tile offsets */
- float uvx = 0.0f, uvy = 0.0f, uvdx = 1.0f, uvdy = 1.0f, time = 0.0f;
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
- vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
-
- psys_make_billboard(bb, xvec, yvec, zvec, bb_center);
-
- add_v3_v3v3(vlr->v1->co, bb_center, xvec);
- add_v3_v3(vlr->v1->co, yvec);
- mul_m4_v3(re->viewmat, vlr->v1->co);
-
- sub_v3_v3v3(vlr->v2->co, bb_center, xvec);
- add_v3_v3(vlr->v2->co, yvec);
- mul_m4_v3(re->viewmat, vlr->v2->co);
-
- sub_v3_v3v3(vlr->v3->co, bb_center, xvec);
- sub_v3_v3v3(vlr->v3->co, vlr->v3->co, yvec);
- mul_m4_v3(re->viewmat, vlr->v3->co);
-
- add_v3_v3v3(vlr->v4->co, bb_center, xvec);
- sub_v3_v3(vlr->v4->co, yvec);
- mul_m4_v3(re->viewmat, vlr->v4->co);
-
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- copy_v3_v3(vlr->v1->n, vlr->n);
- copy_v3_v3(vlr->v2->n, vlr->n);
- copy_v3_v3(vlr->v3->n, vlr->n);
- copy_v3_v3(vlr->v4->n, vlr->n);
-
- vlr->mat= ma;
- vlr->ec= ME_V2V3;
-
- if (bb->uv_split > 1) {
- uvdx = uvdy = 1.0f / (float)bb->uv_split;
-
- if (ELEM(bb->anim, PART_BB_ANIM_AGE, PART_BB_ANIM_FRAME)) {
- if (bb->anim == PART_BB_ANIM_FRAME)
- time = ((int)(bb->time * bb->lifetime) % totsplit)/(float)totsplit;
- else
- time = bb->time;
- }
- else if (bb->anim == PART_BB_ANIM_ANGLE) {
- if (bb->align == PART_BB_VIEW) {
- time = (float)fmod((bb->tilt + 1.0f) / 2.0f, 1.0);
- }
- else {
- float axis1[3] = {0.0f, 0.0f, 0.0f};
- float axis2[3] = {0.0f, 0.0f, 0.0f};
-
- axis1[(bb->align + 1) % 3] = 1.0f;
- axis2[(bb->align + 2) % 3] = 1.0f;
-
- if (bb->lock == 0) {
- zvec[bb->align] = 0.0f;
- normalize_v3(zvec);
- }
-
- time = saacos(dot_v3v3(zvec, axis1)) / (float)M_PI;
-
- if (dot_v3v3(zvec, axis2) < 0.0f)
- time = 1.0f - time / 2.0f;
- else
- time /= 2.0f;
- }
- }
-
- if (bb->split_offset == PART_BB_OFF_LINEAR)
- time = (float)fmod(time + (float)bb->num / (float)totsplit, 1.0f);
- else if (bb->split_offset==PART_BB_OFF_RANDOM)
- time = (float)fmod(time + bb->random, 1.0f);
-
- /* Find the coordinates in tile space (integer), then convert to UV
- * space (float). Note that Y is flipped. */
- tile = (int)((time + FLT_EPSILON10) * totsplit);
- x = tile % bb->uv_split;
- y = tile / bb->uv_split;
- y = (bb->uv_split - 1) - y;
- uvx = uvdx * x;
- uvy = uvdy * y;
- }
-
- /* normal UVs */
- if (bb->uv[0] >= 0) {
- mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[0], NULL, 1);
- mtf->uv[0][0] = 1.0f;
- mtf->uv[0][1] = 1.0f;
- mtf->uv[1][0] = 0.0f;
- mtf->uv[1][1] = 1.0f;
- mtf->uv[2][0] = 0.0f;
- mtf->uv[2][1] = 0.0f;
- mtf->uv[3][0] = 1.0f;
- mtf->uv[3][1] = 0.0f;
- }
-
- /* time-index UVs */
- if (bb->uv[1] >= 0) {
- mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[1], NULL, 1);
- mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = bb->time;
- mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = (float)bb->num/(float)bb->totnum;
- }
-
- /* split UVs */
- if (bb->uv_split > 1 && bb->uv[2] >= 0) {
- mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[2], NULL, 1);
- mtf->uv[0][0] = uvx + uvdx;
- mtf->uv[0][1] = uvy + uvdy;
- mtf->uv[1][0] = uvx;
- mtf->uv[1][1] = uvy + uvdy;
- mtf->uv[2][0] = uvx;
- mtf->uv[2][1] = uvy;
- mtf->uv[3][0] = uvx + uvdx;
- mtf->uv[3][1] = uvy;
- }
-}
-static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, ParticleBillboardData *bb, ParticleKey *state, int seed, float hasize, float *pa_co)
-{
- float loc[3], loc0[3], loc1[3], vel[3];
-
- copy_v3_v3(loc, state->co);
-
- if (ren_as != PART_DRAW_BB)
- mul_m4_v3(re->viewmat, loc);
-
- switch (ren_as) {
- case PART_DRAW_LINE:
- sd->line = 1;
- sd->time = 0.0f;
- sd->size = hasize;
-
- mul_v3_mat3_m4v3(vel, re->viewmat, state->vel);
- normalize_v3(vel);
-
- if (part->draw & PART_DRAW_VEL_LENGTH)
- mul_v3_fl(vel, len_v3(state->vel));
-
- madd_v3_v3v3fl(loc0, loc, vel, -part->draw_line[0]);
- madd_v3_v3v3fl(loc1, loc, vel, part->draw_line[1]);
-
- particle_curve(re, obr, dm, ma, sd, loc0, loc1, seed, pa_co);
-
- break;
-
- case PART_DRAW_BB:
-
- copy_v3_v3(bb->vec, loc);
- copy_v3_v3(bb->vel, state->vel);
-
- particle_billboard(re, obr, ma, bb);
-
- break;
-
- default:
- {
- HaloRen *har = NULL;
-
- har = RE_inithalo_particle(re, obr, dm, ma, loc, NULL, sd->orco, sd->uvco, hasize, 0.0, seed, pa_co);
-
- if (har) har->lay= obr->ob->lay;
-
- break;
- }
- }
-}
-static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int num, ParticleStrandData *sd)
-{
- int i;
-
- /* get uvco */
- if (sd->uvco && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
- for (i=0; i<sd->totuv; i++) {
- if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
- MTFace *mtface = (MTFace*)CustomData_get_layer_n(&dm->faceData, CD_MTFACE, i);
- mtface += num;
-
- psys_interpolate_uvs(mtface, mface->v4, fuv, sd->uvco + 2 * i);
- }
- else {
- sd->uvco[2*i] = 0.0f;
- sd->uvco[2*i + 1] = 0.0f;
- }
- }
- }
-
- /* get mcol */
- if (sd->mcol && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
- for (i=0; i<sd->totcol; i++) {
- if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
- MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i);
- mc += num * 4;
-
- psys_interpolate_mcol(mc, mface->v4, fuv, sd->mcol + i);
- }
- else
- memset(&sd->mcol[i], 0, sizeof(MCol));
- }
- }
-}
-static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys, int timeoffset)
-{
- Object *ob= obr->ob;
-// Object *tob=0;
- Material *ma = NULL;
- ParticleSystemModifierData *psmd;
- ParticleSystem *tpsys = NULL;
- ParticleSettings *part, *tpart = NULL;
- ParticleData *pars, *pa = NULL, *tpa = NULL;
- ParticleKey *states = NULL;
- ParticleKey state;
- ParticleCacheKey *cache = NULL;
- ParticleBillboardData bb;
- ParticleSimulationData sim = {NULL};
- ParticleStrandData sd;
- StrandBuffer *strandbuf = NULL;
- StrandVert *svert = NULL;
- StrandBound *sbound = NULL;
- StrandRen *strand = NULL;
- RNG *rng = NULL;
- float loc[3], loc1[3], loc0[3], mat[4][4], nmat[3][3], co[3], nor[3], duplimat[4][4];
- float strandlen=0.0f, curlen=0.0f;
- float hasize, pa_size, r_tilt, r_length;
- float pa_time, pa_birthtime, pa_dietime;
- float random, simplify[2], pa_co[3];
- const float cfra= BKE_scene_frame_get(re->scene);
- int i, a, k, max_k=0, totpart;
- bool do_simplify = false, do_surfacecache = false, use_duplimat = false;
- int totchild=0, step_nbr;
- int seed, path_nbr=0, orco1=0, num;
- int totface;
-
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
-
-/* 1. check that everything is ok & updated */
- if (psys==NULL)
- return 0;
-
- part=psys->part;
- pars=psys->particles;
-
- if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys, G.is_rendering))
- return 0;
-
- if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT)
- return 1;
-
- if ((re->r.scemode & R_VIEWPORT_PREVIEW) && (ob->mode & OB_MODE_PARTICLE_EDIT))
- return 0;
-
- if (part->ren_as == PART_DRAW_BB && part->bb_ob == NULL && RE_GetCamera(re) == NULL)
- return 0;
-
-/* 2. start initializing things */
-
- /* last possibility to bail out! */
- psmd = psys_get_modifier(ob, psys);
- if (!(psmd->modifier.mode & eModifierMode_Render))
- return 0;
-
- sim.scene= re->scene;
- sim.ob= ob;
- sim.psys= psys;
- sim.psmd= psmd;
-
- if (part->phystype==PART_PHYS_KEYED)
- psys_count_keyed_targets(&sim);
-
- totchild=psys->totchild;
-
- /* can happen for disconnected/global hair */
- if (part->type==PART_HAIR && !psys->childcache)
- totchild= 0;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW) { /* preview render */
- totchild = (int)((float)totchild * (float)part->disp / 100.0f);
- step_nbr = 1 << part->draw_step;
- }
- else {
- step_nbr = 1 << part->ren_step;
- }
- if (ELEM(part->kink, PART_KINK_SPIRAL))
- step_nbr += part->kink_extra_steps;
-
- psys->flag |= PSYS_DRAWING;
-
- rng= BLI_rng_new(psys->seed);
-
- totpart=psys->totpart;
-
- memset(&sd, 0, sizeof(ParticleStrandData));
- sd.override_uv = -1;
-
-/* 2.1 setup material stff */
- ma= give_render_material(re, ob, part->omat);
-
-#if 0 /* XXX old animation system */
- if (ma->ipo) {
- calc_ipo(ma->ipo, cfra);
- execute_ipo((ID *)ma, ma->ipo);
- }
-#endif /* XXX old animation system */
-
- hasize = ma->hasize;
- seed = ma->seed1;
-
- re->flag |= R_HALO;
-
- RE_set_customdata_names(obr, &psmd->dm_final->faceData);
- sd.totuv = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MTFACE);
- sd.totcol = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MCOL);
-
- if (ma->texco & TEXCO_UV && sd.totuv) {
- sd.uvco = MEM_callocN(sd.totuv * 2 * sizeof(float), "particle_uvs");
-
- if (ma->strand_uvname[0]) {
- sd.override_uv = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, ma->strand_uvname);
- sd.override_uv -= CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
- }
- }
- else
- sd.uvco = NULL;
-
- if (sd.totcol)
- sd.mcol = MEM_callocN(sd.totcol * sizeof(MCol), "particle_mcols");
-
-/* 2.2 setup billboards */
- if (part->ren_as == PART_DRAW_BB) {
- int first_uv = CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
-
- bb.uv[0] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[0]);
- if (bb.uv[0] < 0)
- bb.uv[0] = CustomData_get_active_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
-
- bb.uv[1] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[1]);
-
- bb.uv[2] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[2]);
-
- if (first_uv >= 0) {
- bb.uv[0] -= first_uv;
- bb.uv[1] -= first_uv;
- bb.uv[2] -= first_uv;
- }
-
- bb.align = part->bb_align;
- bb.anim = part->bb_anim;
- bb.lock = part->draw & PART_DRAW_BB_LOCK;
- bb.ob = (part->bb_ob ? part->bb_ob : RE_GetCamera(re));
- bb.split_offset = part->bb_split_offset;
- bb.totnum = totpart+totchild;
- bb.uv_split = part->bb_uv_split;
- }
-
-/* 2.5 setup matrices */
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat); /* need to be that way, for imat texture */
- transpose_m3_m4(nmat, ob->imat);
-
- if (psys->flag & PSYS_USE_IMAT) {
- /* psys->imat is the original emitter's inverse matrix, ob->obmat is the duplicated object's matrix */
- mul_m4_m4m4(duplimat, ob->obmat, psys->imat);
- use_duplimat = true;
- }
-
-/* 2.6 setup strand rendering */
- if (part->ren_as == PART_DRAW_PATH && psys->pathcache) {
- path_nbr = step_nbr;
-
- if (path_nbr) {
- if (!ELEM(ma->material_type, MA_TYPE_HALO, MA_TYPE_WIRE)) {
- sd.orco = get_object_orco(re, psys);
- if (!sd.orco) {
- sd.orco = MEM_mallocN(3*sizeof(float)*(totpart+totchild), "particle orcos");
- set_object_orco(re, psys, sd.orco);
- }
- }
- }
-
- if (part->draw & PART_DRAW_REN_ADAPT) {
- sd.adapt = 1;
- sd.adapt_pix = (float)part->adapt_pix;
- sd.adapt_angle = cosf(DEG2RADF((float)part->adapt_angle));
- }
-
- if (part->draw & PART_DRAW_REN_STRAND) {
- strandbuf= RE_addStrandBuffer(obr, (totpart+totchild)*(path_nbr+1));
- strandbuf->ma= ma;
- strandbuf->lay= ob->lay;
- copy_m4_m4(strandbuf->winmat, re->winmat);
- strandbuf->winx= re->winx;
- strandbuf->winy= re->winy;
- strandbuf->maxdepth= 2;
- strandbuf->adaptcos= cosf(DEG2RADF((float)part->adapt_angle));
- strandbuf->overrideuv= sd.override_uv;
- strandbuf->minwidth= ma->strand_min;
-
- if (ma->strand_widthfade == 0.0f)
- strandbuf->widthfade= -1.0f;
- else if (ma->strand_widthfade >= 1.0f)
- strandbuf->widthfade= 2.0f - ma->strand_widthfade;
- else
- strandbuf->widthfade= 1.0f/MAX2(ma->strand_widthfade, 1e-5f);
-
- if (part->flag & PART_HAIR_BSPLINE)
- strandbuf->flag |= R_STRAND_BSPLINE;
- if (ma->mode & MA_STR_B_UNITS)
- strandbuf->flag |= R_STRAND_B_UNITS;
-
- svert= strandbuf->vert;
-
- if (re->r.mode & R_SPEED)
- do_surfacecache = true;
- else if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX))
- if (ma->amb != 0.0f)
- do_surfacecache = true;
-
- totface= psmd->dm_final->getNumTessFaces(psmd->dm_final);
- index_mf_to_mpoly = psmd->dm_final->getTessFaceDataArray(psmd->dm_final, CD_ORIGINDEX);
- index_mp_to_orig = psmd->dm_final->getPolyDataArray(psmd->dm_final, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
- for (a=0; a<totface; a++)
- strandbuf->totbound = max_ii(strandbuf->totbound, (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a): a);
-
- strandbuf->totbound++;
- strandbuf->bound= MEM_callocN(sizeof(StrandBound)*strandbuf->totbound, "StrandBound");
- sbound= strandbuf->bound;
- sbound->start= sbound->end= 0;
- }
- }
-
- if (sd.orco == NULL) {
- sd.orco = MEM_mallocN(3 * sizeof(float), "particle orco");
- orco1 = 1;
- }
-
- if (path_nbr == 0)
- psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
-
-/* 3. start creating renderable things */
- for (a=0, pa=pars; a<totpart+totchild; a++, pa++, seed++) {
- random = BLI_rng_get_float(rng);
- /* setup per particle individual stuff */
- if (a<totpart) {
- if (pa->flag & PARS_UNEXIST) continue;
-
- pa_time=(cfra-pa->time)/pa->lifetime;
- pa_birthtime = pa->time;
- pa_dietime = pa->dietime;
-
- hasize = ma->hasize;
-
- /* XXX 'tpsys' is alwyas NULL, this code won't run! */
- /* get orco */
- if (tpsys && part->phystype == PART_PHYS_NO) {
- tpa = tpsys->particles + pa->num;
- psys_particle_on_emitter(
- psmd,
- tpart->from, tpa->num, pa->num_dmcache, tpa->fuv,
- tpa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
- }
- else {
- psys_particle_on_emitter(
- psmd,
- part->from, pa->num, pa->num_dmcache,
- pa->fuv, pa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
- }
-
- /* get uvco & mcol */
- num= pa->num_dmcache;
-
- if (num == DMCACHE_NOTFOUND)
- if (pa->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
- num= pa->num;
-
- get_particle_uvco_mcol(part->from, psmd->dm_final, pa->fuv, num, &sd);
-
- pa_size = pa->size;
-
- r_tilt = 2.0f*(psys_frand(psys, a) - 0.5f);
- r_length = psys_frand(psys, a+1);
-
- if (path_nbr) {
- cache = psys->pathcache[a];
- max_k = (int)cache->segments;
- }
-
- if (totchild && (part->draw&PART_DRAW_PARENT)==0) continue;
- }
- else {
- ChildParticle *cpa= psys->child+a-totpart;
-
- if (path_nbr) {
- cache = psys->childcache[a-totpart];
-
- if (cache->segments < 0)
- continue;
-
- max_k = (int)cache->segments;
- }
-
- pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
- pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time);
-
- r_tilt = 2.0f*(psys_frand(psys, a + 21) - 0.5f);
- r_length = psys_frand(psys, a + 22);
-
- num = cpa->num;
-
- /* get orco */
- if (part->childtype == PART_CHILD_FACES) {
- psys_particle_on_emitter(
- psmd,
- PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD,
- cpa->fuv, cpa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
- }
- else {
- ParticleData *par = psys->particles + cpa->parent;
- psys_particle_on_emitter(
- psmd,
- part->from, par->num, DMCACHE_ISCHILD, par->fuv,
- par->foffset, co, nor, NULL, NULL, sd.orco, NULL);
- }
-
- /* get uvco & mcol */
- if (part->childtype==PART_CHILD_FACES) {
- get_particle_uvco_mcol(PART_FROM_FACE, psmd->dm_final, cpa->fuv, cpa->num, &sd);
- }
- else {
- ParticleData *parent = psys->particles + cpa->parent;
- num = parent->num_dmcache;
-
- if (num == DMCACHE_NOTFOUND)
- if (parent->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
- num = parent->num;
-
- get_particle_uvco_mcol(part->from, psmd->dm_final, parent->fuv, num, &sd);
- }
-
- do_simplify = psys_render_simplify_params(psys, cpa, simplify);
-
- if (strandbuf) {
- int orignum = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, cpa->num) : cpa->num;
-
- if ((orignum > sbound - strandbuf->bound) &&
- (orignum < strandbuf->totbound))
- {
- sbound = &strandbuf->bound[orignum];
- sbound->start = sbound->end = obr->totstrand;
- }
- }
- }
-
- /* TEXCO_PARTICLE */
- pa_co[0] = pa_time;
- pa_co[1] = 0.f;
- pa_co[2] = 0.f;
-
- /* surface normal shading setup */
- if (ma->mode_l & MA_STR_SURFDIFF) {
- mul_m3_v3(nmat, nor);
- sd.surfnor= nor;
- }
- else
- sd.surfnor= NULL;
-
- /* strand render setup */
- if (strandbuf) {
- strand= RE_findOrAddStrand(obr, obr->totstrand++);
- strand->buffer= strandbuf;
- strand->vert= svert;
- copy_v3_v3(strand->orco, sd.orco);
-
- if (do_simplify) {
- float *ssimplify= RE_strandren_get_simplify(obr, strand, 1);
- ssimplify[0]= simplify[0];
- ssimplify[1]= simplify[1];
- }
-
- if (sd.surfnor) {
- float *snor= RE_strandren_get_surfnor(obr, strand, 1);
- copy_v3_v3(snor, sd.surfnor);
- }
-
- if (do_surfacecache && num >= 0) {
- int *facenum= RE_strandren_get_face(obr, strand, 1);
- *facenum= num;
- }
-
- if (sd.uvco) {
- for (i=0; i<sd.totuv; i++) {
- if (i != sd.override_uv) {
- float *uv= RE_strandren_get_uv(obr, strand, i, NULL, 1);
-
- uv[0]= sd.uvco[2*i];
- uv[1]= sd.uvco[2*i+1];
- }
- }
- }
- if (sd.mcol) {
- for (i=0; i<sd.totcol; i++) {
- MCol *mc= RE_strandren_get_mcol(obr, strand, i, NULL, 1);
- *mc = sd.mcol[i];
- }
- }
-
- sbound->end++;
- }
-
- /* strandco computation setup */
- if (path_nbr) {
- strandlen= 0.0f;
- curlen= 0.0f;
- for (k=1; k<=path_nbr; k++)
- if (k<=max_k)
- strandlen += len_v3v3((cache+k-1)->co, (cache+k)->co);
- }
-
- if (path_nbr) {
- /* render strands */
- for (k=0; k<=path_nbr; k++) {
- float time;
-
- if (k<=max_k) {
- copy_v3_v3(state.co, (cache+k)->co);
- copy_v3_v3(state.vel, (cache+k)->vel);
- }
- else
- continue;
-
- if (k > 0)
- curlen += len_v3v3((cache+k-1)->co, (cache+k)->co);
- time= curlen/strandlen;
-
- copy_v3_v3(loc, state.co);
- mul_m4_v3(re->viewmat, loc);
-
- if (strandbuf) {
- copy_v3_v3(svert->co, loc);
- svert->strandco= -1.0f + 2.0f*time;
- svert++;
- strand->totvert++;
- }
- else {
- sd.size = hasize;
-
- if (k==1) {
- sd.first = 1;
- sd.time = 0.0f;
- sub_v3_v3v3(loc0, loc1, loc);
- add_v3_v3v3(loc0, loc1, loc0);
-
- particle_curve(re, obr, psmd->dm_final, ma, &sd, loc1, loc0, seed, pa_co);
- }
-
- sd.first = 0;
- sd.time = time;
-
- if (k)
- particle_curve(re, obr, psmd->dm_final, ma, &sd, loc, loc1, seed, pa_co);
-
- copy_v3_v3(loc1, loc);
- }
- }
-
- }
- else {
- /* render normal particles */
- if (part->trail_count > 1) {
- float length = part->path_end * (1.0f - part->randlength * r_length);
- int trail_count = part->trail_count * (1.0f - part->randlength * r_length);
- float ct = (part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time;
- float dt = length / (trail_count ? (float)trail_count : 1.0f);
-
- /* make sure we have pointcache in memory before getting particle on path */
- psys_make_temp_pointcache(ob, psys);
-
- for (i=0; i < trail_count; i++, ct -= dt) {
- if (part->draw & PART_ABS_PATH_TIME) {
- if (ct < pa_birthtime || ct > pa_dietime)
- continue;
- }
- else if (ct < 0.0f || ct > 1.0f)
- continue;
-
- state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct;
- psys_get_particle_on_path(&sim, a, &state, 1);
-
- if (psys->parent)
- mul_m4_v3(psys->parent->obmat, state.co);
-
- if (use_duplimat)
- mul_m4_v4(duplimat, state.co);
-
- if (part->ren_as == PART_DRAW_BB) {
- bb.random = random;
- bb.offset[0] = part->bb_offset[0];
- bb.offset[1] = part->bb_offset[1];
- bb.size[0] = part->bb_size[0] * pa_size;
- if (part->bb_align==PART_BB_VEL) {
- float pa_vel = len_v3(state.vel);
- float head = part->bb_vel_head*pa_vel;
- float tail = part->bb_vel_tail*pa_vel;
- bb.size[1] = part->bb_size[1]*pa_size + head + tail;
- /* use offset to adjust the particle center. this is relative to size, so need to divide! */
- if (bb.size[1] > 0.0f)
- bb.offset[1] += (head-tail) / bb.size[1];
- }
- else
- bb.size[1] = part->bb_size[1] * pa_size;
- bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
- bb.time = ct;
- bb.num = a;
- }
-
- pa_co[0] = (part->draw & PART_ABS_PATH_TIME) ? (ct-pa_birthtime)/(pa_dietime-pa_birthtime) : ct;
- pa_co[1] = (float)i/(float)(trail_count-1);
-
- particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
- }
- }
- else {
- state.time=cfra;
- if (psys_get_particle_state(&sim, a, &state, 0)==0)
- continue;
-
- if (psys->parent)
- mul_m4_v3(psys->parent->obmat, state.co);
-
- if (use_duplimat)
- mul_m4_v3(duplimat, state.co);
-
- if (part->ren_as == PART_DRAW_BB) {
- bb.random = random;
- bb.offset[0] = part->bb_offset[0];
- bb.offset[1] = part->bb_offset[1];
- bb.size[0] = part->bb_size[0] * pa_size;
- if (part->bb_align==PART_BB_VEL) {
- float pa_vel = len_v3(state.vel);
- float head = part->bb_vel_head*pa_vel;
- float tail = part->bb_vel_tail*pa_vel;
- bb.size[1] = part->bb_size[1]*pa_size + head + tail;
- /* use offset to adjust the particle center. this is relative to size, so need to divide! */
- if (bb.size[1] > 0.0f)
- bb.offset[1] += (head-tail) / bb.size[1];
- }
- else
- bb.size[1] = part->bb_size[1] * pa_size;
- bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
- bb.time = pa_time;
- bb.num = a;
- bb.lifetime = pa_dietime-pa_birthtime;
- }
-
- particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
- }
- }
-
- if (orco1==0)
- sd.orco+=3;
-
- if (re->test_break(re->tbh))
- break;
- }
-
- if (do_surfacecache)
- strandbuf->surface= cache_strand_surface(re, obr, psmd->dm_final, mat, timeoffset);
-
-/* 4. clean up */
-#if 0 /* XXX old animation system */
- if (ma) do_mat_ipo(re->scene, ma);
-#endif /* XXX old animation system */
-
- if (orco1)
- MEM_freeN(sd.orco);
-
- if (sd.uvco)
- MEM_freeN(sd.uvco);
-
- if (sd.mcol)
- MEM_freeN(sd.mcol);
-
- if (states)
- MEM_freeN(states);
-
- BLI_rng_free(rng);
-
- psys->flag &= ~PSYS_DRAWING;
-
- if (psys->lattice_deform_data) {
- end_latt_deform(psys->lattice_deform_data);
- psys->lattice_deform_data = NULL;
- }
-
- if (path_nbr && (ma->mode_l & MA_TANGENT_STR)==0)
- calc_vertexnormals(re, obr, 1, 0, 0);
-
- return 1;
-}
-
-/* ------------------------------------------------------------------------- */
-/* Halo's */
-/* ------------------------------------------------------------------------- */
-
-static void make_render_halos(Render *re, ObjectRen *obr, Mesh *UNUSED(me), int totvert, MVert *mvert, Material *ma, float *orco)
-{
- Object *ob= obr->ob;
- HaloRen *har;
- float xn, yn, zn, nor[3], view[3];
- float vec[3], hasize, mat[4][4], imat[3][3];
- int a, ok, seed= ma->seed1;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- copy_m3_m4(imat, ob->imat);
-
- re->flag |= R_HALO;
-
- for (a=0; a<totvert; a++, mvert++) {
- ok= 1;
-
- if (ok) {
- hasize= ma->hasize;
-
- copy_v3_v3(vec, mvert->co);
- mul_m4_v3(mat, vec);
-
- if (ma->mode & MA_HALOPUNO) {
- xn= mvert->no[0];
- yn= mvert->no[1];
- zn= mvert->no[2];
-
- /* transpose ! */
- nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
- nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
- nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
- normalize_v3(nor);
-
- copy_v3_v3(view, vec);
- normalize_v3(view);
-
- zn = dot_v3v3(nor, view);
- if (zn>=0.0f) hasize= 0.0f;
- else hasize*= zn*zn*zn*zn;
- }
-
- if (orco) har= RE_inithalo(re, obr, ma, vec, NULL, orco, hasize, 0.0, seed);
- else har= RE_inithalo(re, obr, ma, vec, NULL, mvert->co, hasize, 0.0, seed);
- if (har) har->lay= ob->lay;
- }
- if (orco) orco+= 3;
- seed++;
- }
-}
-
-static int verghalo(const void *a1, const void *a2)
-{
- const HaloRen *har1= *(const HaloRen**)a1;
- const HaloRen *har2= *(const HaloRen**)a2;
-
- if (har1->zs < har2->zs) return 1;
- else if (har1->zs > har2->zs) return -1;
- return 0;
-}
-
-static void sort_halos(Render *re, int totsort)
-{
- ObjectRen *obr;
- HaloRen *har= NULL, **haso;
- int a;
-
- if (re->tothalo==0) return;
-
- re->sortedhalos= MEM_callocN(sizeof(HaloRen*)*re->tothalo, "sorthalos");
- haso= re->sortedhalos;
-
- for (obr=re->objecttable.first; obr; obr=obr->next) {
- for (a=0; a<obr->tothalo; a++) {
- if ((a & 255)==0) har= obr->bloha[a>>8];
- else har++;
-
- *(haso++)= har;
- }
- }
-
- qsort(re->sortedhalos, totsort, sizeof(HaloRen*), verghalo);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Displacement Mapping */
-/* ------------------------------------------------------------------------- */
-
-static short test_for_displace(Render *re, Object *ob)
-{
- /* return 1 when this object uses displacement textures. */
- Material *ma;
- int i;
-
- for (i=1; i<=ob->totcol; i++) {
- ma=give_render_material(re, ob, i);
- /* ma->mapto is ORed total of all mapto channels */
- if (ma && (ma->mapto & MAP_DISPLACE)) return 1;
- }
- return 0;
-}
-
-static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale)
-{
- MTFace *tface;
- short texco= shi->mat->texco;
- float sample=0, displace[3];
- char *name;
- int i;
-
- /* shi->co is current render coord, just make sure at least some vector is here */
- copy_v3_v3(shi->co, vr->co);
- /* vertex normal is used for textures type 'col' and 'var' */
- copy_v3_v3(shi->vn, vr->n);
-
- if (texco & TEXCO_UV) {
- shi->totuv= 0;
- shi->actuv= obr->actmtface;
-
- for (i=0; (tface=RE_vlakren_get_tface(obr, shi->vlr, i, &name, 0)); i++) {
- ShadeInputUV *suv= &shi->uv[i];
-
- /* shi.uv needs scale correction from tface uv */
- suv->uv[0]= 2*tface->uv[vindex][0]-1.0f;
- suv->uv[1]= 2*tface->uv[vindex][1]-1.0f;
- suv->uv[2]= 0.0f;
- suv->name= name;
- shi->totuv++;
- }
- }
-
- /* set all rendercoords, 'texco' is an ORed value for all textures needed */
- if ((texco & TEXCO_ORCO) && (vr->orco)) {
- copy_v3_v3(shi->lo, vr->orco);
- }
- if (texco & TEXCO_GLOB) {
- copy_v3_v3(shi->gl, shi->co);
- mul_m4_v3(re->viewinv, shi->gl);
- }
- if (texco & TEXCO_NORM) {
- copy_v3_v3(shi->orn, shi->vn);
- }
- if (texco & TEXCO_REFL) {
- /* not (yet?) */
- }
- if (texco & TEXCO_STRESS) {
- const float *s= RE_vertren_get_stress(obr, vr, 0);
-
- if (s) {
- shi->stress= *s;
- if (shi->stress<1.0f) shi->stress-= 1.0f;
- else shi->stress= (shi->stress-1.0f)/shi->stress;
- }
- else
- shi->stress= 0.0f;
- }
-
- shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0;
-
- do_material_tex(shi, re);
-
- //printf("no=%f, %f, %f\nbefore co=%f, %f, %f\n", vr->n[0], vr->n[1], vr->n[2],
- //vr->co[0], vr->co[1], vr->co[2]);
-
- displace[0]= shi->displace[0] * scale[0];
- displace[1]= shi->displace[1] * scale[1];
- displace[2]= shi->displace[2] * scale[2];
-
- /* 0.5 could become button once? */
- vr->co[0] += displace[0];
- vr->co[1] += displace[1];
- vr->co[2] += displace[2];
-
- //printf("after co=%f, %f, %f\n", vr->co[0], vr->co[1], vr->co[2]);
-
- /* we just don't do this vertex again, bad luck for other face using same vertex with
- * different material... */
- vr->flag |= 1;
-
- /* Pass sample back so displace_face can decide which way to split the quad */
- sample = shi->displace[0]*shi->displace[0];
- sample += shi->displace[1]*shi->displace[1];
- sample += shi->displace[2]*shi->displace[2];
-
- vr->accum=sample;
- /* Should be sqrt(sample), but I'm only looking for "bigger". Save the cycles. */
- return;
-}
-
-static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale)
-{
- ShadeInput shi;
-
- /* Warning, This is not that nice, and possibly a bit slow,
- * however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */
- memset(&shi, 0, sizeof(ShadeInput));
- /* end warning! - Campbell */
-
- /* set up shadeinput struct for multitex() */
-
- /* memset above means we don't need this */
- /*shi.osatex= 0;*/ /* signal not to use dx[] and dy[] texture AA vectors */
-
- shi.obr= obr;
- shi.vlr= vlr; /* current render face */
- shi.mat= vlr->mat; /* current input material */
- shi.thread= 0;
-
- /* TODO, assign these, displacement with new bumpmap is skipped without - campbell */
-#if 0
- /* order is not known ? */
- shi.v1= vlr->v1;
- shi.v2= vlr->v2;
- shi.v3= vlr->v3;
-#endif
-
- /* Displace the verts, flag is set when done */
- if (!vlr->v1->flag)
- displace_render_vert(re, obr, &shi, vlr->v1, 0, scale);
-
- if (!vlr->v2->flag)
- displace_render_vert(re, obr, &shi, vlr->v2, 1, scale);
-
- if (!vlr->v3->flag)
- displace_render_vert(re, obr, &shi, vlr->v3, 2, scale);
-
- if (vlr->v4) {
- if (!vlr->v4->flag)
- displace_render_vert(re, obr, &shi, vlr->v4, 3, scale);
-
- /* closest in displace value. This will help smooth edges. */
- if (fabsf(vlr->v1->accum - vlr->v3->accum) > fabsf(vlr->v2->accum - vlr->v4->accum)) vlr->flag |= R_DIVIDE_24;
- else vlr->flag &= ~R_DIVIDE_24;
- }
-
- /* Recalculate the face normal - if flipped before, flip now */
- if (vlr->v4) {
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- }
- else {
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- }
-}
-
-static void displace(Render *re, ObjectRen *obr)
-{
- VertRen *vr;
- VlakRen *vlr;
-// float min[3]={1e30, 1e30, 1e30}, max[3]={-1e30, -1e30, -1e30};
- float scale[3]={1.0f, 1.0f, 1.0f}, temp[3];//, xn
- int i; //, texflag=0;
- Object *obt;
-
- /* Object Size with parenting */
- obt=obr->ob;
- while (obt) {
- mul_v3_v3v3(temp, obt->size, obt->dscale);
- scale[0]*=temp[0]; scale[1]*=temp[1]; scale[2]*=temp[2];
- obt=obt->parent;
- }
-
- /* Clear all flags */
- for (i=0; i<obr->totvert; i++) {
- vr= RE_findOrAddVert(obr, i);
- vr->flag= 0;
- }
-
- for (i=0; i<obr->totvlak; i++) {
- vlr=RE_findOrAddVlak(obr, i);
- displace_render_face(re, obr, vlr, scale);
- }
-
- /* Recalc vertex normals */
- calc_vertexnormals(re, obr, 1, 0, 0);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Metaball */
-/* ------------------------------------------------------------------------- */
-
-static void init_render_mball(Render *re, ObjectRen *obr)
-{
- Object *ob= obr->ob;
- DispList *dl;
- VertRen *ver;
- VlakRen *vlr, *vlr1;
- Material *ma;
- float *data, *nors, *orco=NULL, mat[4][4], imat[3][3], xn, yn, zn;
- int a, need_orco, vlakindex, *index, negative_scale;
- ListBase dispbase= {NULL, NULL};
-
- if (ob!=BKE_mball_basis_find(re->main, re->eval_ctx, re->scene, ob))
- return;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- copy_m3_m4(imat, ob->imat);
- negative_scale = is_negative_m4(mat);
-
- ma= give_render_material(re, ob, 1);
-
- need_orco= 0;
- if (ma->texco & TEXCO_ORCO) {
- need_orco= 1;
- }
-
- BKE_displist_make_mball_forRender(re->main, re->eval_ctx, re->scene, ob, &dispbase);
- dl= dispbase.first;
- if (dl == NULL) return;
-
- data= dl->verts;
- nors= dl->nors;
- if (need_orco) {
- orco= get_object_orco(re, ob);
-
- if (!orco) {
- /* orco hasn't been found in cache - create new one and add to cache */
- orco= BKE_mball_make_orco(ob, &dispbase);
- set_object_orco(re, ob, orco);
- }
- }
-
- for (a=0; a<dl->nr; a++, data+=3, nors+=3) {
-
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, data);
- mul_m4_v3(mat, ver->co);
-
- /* render normals are inverted */
- xn= -nors[0];
- yn= -nors[1];
- zn= -nors[2];
-
- /* transpose ! */
- ver->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
- ver->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
- ver->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
- normalize_v3(ver->n);
- //if (ob->transflag & OB_NEG_SCALE) negate_v3(ver->n);
-
- if (need_orco) {
- ver->orco= orco;
- orco+=3;
- }
- }
-
- index= dl->index;
- for (a=0; a<dl->parts; a++, index+=4) {
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, index[0]);
- vlr->v2= RE_findOrAddVert(obr, index[1]);
- vlr->v3= RE_findOrAddVert(obr, index[2]);
- vlr->v4 = NULL;
-
- if (negative_scale)
- normal_tri_v3(vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co);
- else
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- vlr->mat= ma;
- vlr->flag= ME_SMOOTH;
- vlr->ec= 0;
-
- /* mball -too bad- always has triangles, because quads can be non-planar */
- if (index[3] && index[3]!=index[2]) {
- vlr1= RE_findOrAddVlak(obr, obr->totvlak++);
- vlakindex= vlr1->index;
- *vlr1= *vlr;
- vlr1->index= vlakindex;
- vlr1->v2= vlr1->v3;
- vlr1->v3= RE_findOrAddVert(obr, index[3]);
- if (negative_scale)
- normal_tri_v3(vlr1->n, vlr1->v1->co, vlr1->v2->co, vlr1->v3->co);
- else
- normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
- }
- }
-
- /* enforce display lists remade */
- BKE_displist_free(&dispbase);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Surfaces and Curves */
-/* ------------------------------------------------------------------------- */
-
-/* returns amount of vertices added for orco */
-static int dl_surf_to_renderdata(ObjectRen *obr, DispList *dl, Material **matar, float *orco, float mat[4][4])
-{
- VertRen *v1, *v2, *v3, *v4, *ver;
- VlakRen *vlr, *vlr1, *vlr2, *vlr3;
- float *data, n1[3];
- int u, v, orcoret= 0;
- int p1, p2, p3, p4, a;
- int sizeu, nsizeu, sizev, nsizev;
- int startvert, startvlak;
-
- startvert= obr->totvert;
- nsizeu = sizeu = dl->parts; nsizev = sizev = dl->nr;
-
- data= dl->verts;
- for (u = 0; u < sizeu; u++) {
- v1 = RE_findOrAddVert(obr, obr->totvert++); /* save this for possible V wrapping */
- copy_v3_v3(v1->co, data); data += 3;
- if (orco) {
- v1->orco= orco; orco+= 3; orcoret++;
- }
- mul_m4_v3(mat, v1->co);
-
- for (v = 1; v < sizev; v++) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, data); data += 3;
- if (orco) {
- ver->orco= orco; orco+= 3; orcoret++;
- }
- mul_m4_v3(mat, ver->co);
- }
- /* if V-cyclic, add extra vertices at end of the row */
- if (dl->flag & DL_CYCL_U) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, v1->co);
- if (orco) {
- ver->orco= orco; orco+=3; orcoret++; //orcobase + 3*(u*sizev + 0);
- }
- }
- }
-
- /* Done before next loop to get corner vert */
- if (dl->flag & DL_CYCL_U) nsizev++;
- if (dl->flag & DL_CYCL_V) nsizeu++;
-
- /* if U cyclic, add extra row at end of column */
- if (dl->flag & DL_CYCL_V) {
- for (v = 0; v < nsizev; v++) {
- v1= RE_findOrAddVert(obr, startvert + v);
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, v1->co);
- if (orco) {
- ver->orco= orco; orco+=3; orcoret++; //ver->orco= orcobase + 3*(0*sizev + v);
- }
- }
- }
-
- sizeu = nsizeu;
- sizev = nsizev;
-
- startvlak= obr->totvlak;
-
- for (u = 0; u < sizeu - 1; u++) {
- p1 = startvert + u * sizev; /* walk through face list */
- p2 = p1 + 1;
- p3 = p2 + sizev;
- p4 = p3 - 1;
-
- for (v = 0; v < sizev - 1; v++) {
- v1= RE_findOrAddVert(obr, p1);
- v2= RE_findOrAddVert(obr, p2);
- v3= RE_findOrAddVert(obr, p3);
- v4= RE_findOrAddVert(obr, p4);
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= v1; vlr->v2= v2; vlr->v3= v3; vlr->v4= v4;
-
- normal_quad_v3(n1, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- copy_v3_v3(vlr->n, n1);
-
- vlr->mat= matar[ dl->col];
- vlr->ec= ME_V1V2+ME_V2V3;
- vlr->flag= dl->rt;
-
- add_v3_v3(v1->n, n1);
- add_v3_v3(v2->n, n1);
- add_v3_v3(v3->n, n1);
- add_v3_v3(v4->n, n1);
-
- p1++; p2++; p3++; p4++;
- }
- }
- /* fix normals for U resp. V cyclic faces */
- sizeu--; sizev--; /* dec size for face array */
- if (dl->flag & DL_CYCL_V) {
-
- for (v = 0; v < sizev; v++) {
- /* optimize! :*/
- vlr= RE_findOrAddVlak(obr, UVTOINDEX(sizeu - 1, v));
- vlr1= RE_findOrAddVlak(obr, UVTOINDEX(0, v));
- add_v3_v3(vlr1->v1->n, vlr->n);
- add_v3_v3(vlr1->v2->n, vlr->n);
- add_v3_v3(vlr->v3->n, vlr1->n);
- add_v3_v3(vlr->v4->n, vlr1->n);
- }
- }
- if (dl->flag & DL_CYCL_U) {
-
- for (u = 0; u < sizeu; u++) {
- /* optimize! :*/
- vlr= RE_findOrAddVlak(obr, UVTOINDEX(u, 0));
- vlr1= RE_findOrAddVlak(obr, UVTOINDEX(u, sizev-1));
- add_v3_v3(vlr1->v2->n, vlr->n);
- add_v3_v3(vlr1->v3->n, vlr->n);
- add_v3_v3(vlr->v1->n, vlr1->n);
- add_v3_v3(vlr->v4->n, vlr1->n);
- }
- }
-
- /* last vertex is an extra case:
- *
- * ^ ()----()----()----()
- * | | | || |
- * u | |(0,n)||(0,0)|
- * | | || |
- * ()====()====[]====()
- * | | || |
- * | |(m,n)||(m,0)|
- * | | || |
- * ()----()----()----()
- * v ->
- *
- * vertex [] is no longer shared, therefore distribute
- * normals of the surrounding faces to all of the duplicates of []
- */
-
- if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U)) {
- vlr= RE_findOrAddVlak(obr, UVTOINDEX(sizeu - 1, sizev - 1)); /* (m, n) */
- vlr1= RE_findOrAddVlak(obr, UVTOINDEX(0, 0)); /* (0, 0) */
- add_v3_v3v3(n1, vlr->n, vlr1->n);
- vlr2= RE_findOrAddVlak(obr, UVTOINDEX(0, sizev-1)); /* (0, n) */
- add_v3_v3(n1, vlr2->n);
- vlr3= RE_findOrAddVlak(obr, UVTOINDEX(sizeu-1, 0)); /* (m, 0) */
- add_v3_v3(n1, vlr3->n);
- copy_v3_v3(vlr->v3->n, n1);
- copy_v3_v3(vlr1->v1->n, n1);
- copy_v3_v3(vlr2->v2->n, n1);
- copy_v3_v3(vlr3->v4->n, n1);
- }
- for (a = startvert; a < obr->totvert; a++) {
- ver= RE_findOrAddVert(obr, a);
- normalize_v3(ver->n);
- }
-
-
- return orcoret;
-}
-
-static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
- int timeoffset, float *orco, float mat[4][4])
-{
- Object *ob= obr->ob;
- int a, end, totvert, vertofs;
- short mat_iter;
- VertRen *ver;
- VlakRen *vlr;
- MVert *mvert = NULL;
- MFace *mface;
- Material *ma;
-#ifdef WITH_FREESTYLE
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
- FreestyleFace *ffa = NULL;
-#endif
- /* Curve *cu= ELEM(ob->type, OB_FONT, OB_CURVE) ? ob->data : NULL; */
-
- mvert= dm->getVertArray(dm);
- totvert= dm->getNumVerts(dm);
-
- for (a=0; a<totvert; a++, mvert++) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, mvert->co);
- mul_m4_v3(mat, ver->co);
-
- if (orco) {
- ver->orco= orco;
- orco+=3;
- }
- }
-
- if (!timeoffset) {
- /* store customdata names, because DerivedMesh is freed */
- RE_set_customdata_names(obr, &dm->faceData);
-
- /* still to do for keys: the correct local texture coordinate */
-
- /* faces in order of color blocks */
- vertofs= obr->totvert - totvert;
- for (mat_iter= 0; (mat_iter < ob->totcol || (mat_iter==0 && ob->totcol==0)); mat_iter++) {
-
- ma= give_render_material(re, ob, mat_iter+1);
- end= dm->getNumTessFaces(dm);
- mface= dm->getTessFaceArray(dm);
-
-#ifdef WITH_FREESTYLE
- if (ob->type == OB_MESH) {
- Mesh *me= ob->data;
- index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX);
- ffa= CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
- }
-#endif
-
- for (a=0; a<end; a++, mface++) {
- int v1, v2, v3, v4, flag;
-
- if (mface->mat_nr == mat_iter) {
- float len;
-
- v1= mface->v1;
- v2= mface->v2;
- v3= mface->v3;
- v4= mface->v4;
- flag= mface->flag & ME_SMOOTH;
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
- vlr->v2= RE_findOrAddVert(obr, vertofs+v2);
- vlr->v3= RE_findOrAddVert(obr, vertofs+v3);
- if (v4) vlr->v4= RE_findOrAddVert(obr, vertofs+v4);
- else vlr->v4 = NULL;
-
- /* render normals are inverted in render */
- if (vlr->v4)
- len= normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- else
- len= normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-
- vlr->mat= ma;
- vlr->flag= flag;
- vlr->ec= 0; /* mesh edges rendered separately */
-#ifdef WITH_FREESTYLE
- if (ffa) {
- int index = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
- vlr->freestyle_face_mark= (ffa[index].flag & FREESTYLE_FACE_MARK) ? 1 : 0;
- }
- else {
- vlr->freestyle_face_mark= 0;
- }
-#endif
-
- if (len==0) obr->totvlak--;
- else {
- CustomDataLayer *layer;
- MTFace *mtface, *mtf;
- MCol *mcol, *mc;
- int index, mtfn= 0, mcn= 0;
- char *name;
-
- for (index=0; index<dm->faceData.totlayer; index++) {
- layer= &dm->faceData.layers[index];
- name= layer->name;
-
- if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
- mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
- mtface= (MTFace*)layer->data;
- *mtf= mtface[a];
- }
- else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
- mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
- mcol= (MCol*)layer->data;
- memcpy(mc, &mcol[a*4], sizeof(MCol)*4);
- }
- }
- }
- }
- }
- }
-
- /* Normals */
- calc_vertexnormals(re, obr, 1, 0, 0);
- }
-
-}
-
-static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- Nurb *nu = NULL;
- Curve *cu;
- ListBase displist= {NULL, NULL};
- DispList *dl;
- Material **matar;
- float *orco=NULL, mat[4][4];
- int a, totmat;
- bool need_orco = false;
- DerivedMesh *dm= NULL;
-
- cu= ob->data;
- nu= cu->nurb.first;
- if (nu == NULL) return;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
-
- /* material array */
- totmat= ob->totcol+1;
- matar= MEM_callocN(sizeof(Material*)*totmat, "init_render_surf matar");
-
- for (a=0; a<totmat; a++) {
- matar[a]= give_render_material(re, ob, a+1);
-
- if (matar[a] && matar[a]->texco & TEXCO_ORCO)
- need_orco= 1;
- }
-
- if (ob->parent && (ob->parent->type==OB_LATTICE)) need_orco= 1;
-
- BKE_displist_make_surf(re->scene, ob, &displist, &dm, 1, 0, 1);
-
- if (dm) {
- if (need_orco) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco= BKE_displist_make_orco(re->scene, ob, dm, true, true);
- if (orco) {
- set_object_orco(re, ob, orco);
- }
- }
- }
-
- init_render_dm(dm, re, obr, timeoffset, orco, mat);
- dm->release(dm);
- }
- else {
- if (need_orco) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco = BKE_curve_surf_make_orco(ob);
- set_object_orco(re, ob, orco);
- }
- }
-
- /* walk along displaylist and create rendervertices/-faces */
- for (dl=displist.first; dl; dl=dl->next) {
- /* watch out: u ^= y, v ^= x !! */
- if (dl->type==DL_SURF)
- orco+= 3*dl_surf_to_renderdata(obr, dl, matar, orco, mat);
- }
- }
-
- BKE_displist_free(&displist);
-
- MEM_freeN(matar);
-}
-
-static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- Curve *cu;
- VertRen *ver;
- VlakRen *vlr;
- DispList *dl;
- DerivedMesh *dm = NULL;
- ListBase disp={NULL, NULL};
- Material **matar;
- float *data, *fp, *orco=NULL;
- float n[3], mat[4][4], nmat[4][4];
- int nr, startvert, a, b, negative_scale;
- bool need_orco = false;
- int totmat;
-
- cu= ob->data;
- if (ob->type==OB_FONT && cu->str==NULL) return;
- else if (ob->type==OB_CURVE && cu->nurb.first==NULL) return;
-
- BKE_displist_make_curveTypes_forRender(re->scene, ob, &disp, &dm, false, true);
- dl= disp.first;
- if (dl==NULL) return;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- negative_scale = is_negative_m4(mat);
-
- /* local object -> world space transform for normals */
- transpose_m4_m4(nmat, mat);
- invert_m4(nmat);
-
- /* material array */
- totmat= ob->totcol+1;
- matar= MEM_callocN(sizeof(Material*)*totmat, "init_render_surf matar");
-
- for (a=0; a<totmat; a++) {
- matar[a]= give_render_material(re, ob, a+1);
-
- if (matar[a] && matar[a]->texco & TEXCO_ORCO)
- need_orco= 1;
- }
-
- if (dm) {
- if (need_orco) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco = BKE_displist_make_orco(re->scene, ob, dm, true, true);
- if (orco) {
- set_object_orco(re, ob, orco);
- }
- }
- }
-
- init_render_dm(dm, re, obr, timeoffset, orco, mat);
- dm->release(dm);
- }
- else {
- if (need_orco) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco = BKE_curve_make_orco(re->scene, ob, NULL);
- set_object_orco(re, ob, orco);
- }
- }
-
- while (dl) {
- if (dl->col > ob->totcol) {
- /* pass */
- }
- else if (dl->type==DL_INDEX3) {
- const int *index;
-
- startvert= obr->totvert;
- data= dl->verts;
-
- for (a=0; a<dl->nr; a++, data+=3) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, data);
-
- mul_m4_v3(mat, ver->co);
-
- if (orco) {
- ver->orco = orco;
- orco += 3;
- }
- }
-
- if (timeoffset==0) {
- float tmp[3];
- const int startvlak= obr->totvlak;
-
- zero_v3(n);
- index= dl->index;
- for (a=0; a<dl->parts; a++, index+=3) {
- int v1 = index[0], v2 = index[2], v3 = index[1];
- float *co1 = &dl->verts[v1 * 3],
- *co2 = &dl->verts[v2 * 3],
- *co3 = &dl->verts[v3 * 3];
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, startvert + v1);
- vlr->v2= RE_findOrAddVert(obr, startvert + v2);
- vlr->v3= RE_findOrAddVert(obr, startvert + v3);
- vlr->v4= NULL;
-
- /* to prevent float accuracy issues, we calculate normal in local object space (not world) */
- if (normal_tri_v3(tmp, co1, co2, co3) > FLT_EPSILON) {
- if (negative_scale == false) {
- add_v3_v3(n, tmp);
- }
- else {
- sub_v3_v3(n, tmp);
- }
- }
-
- vlr->mat= matar[ dl->col ];
- vlr->flag= 0;
- vlr->ec= 0;
- }
-
- /* transform normal to world space */
- mul_m4_v3(nmat, n);
- normalize_v3(n);
-
- /* vertex normals */
- for (a= startvlak; a<obr->totvlak; a++) {
- vlr= RE_findOrAddVlak(obr, a);
-
- copy_v3_v3(vlr->n, n);
- add_v3_v3(vlr->v1->n, vlr->n);
- add_v3_v3(vlr->v3->n, vlr->n);
- add_v3_v3(vlr->v2->n, vlr->n);
- }
- for (a=startvert; a<obr->totvert; a++) {
- ver= RE_findOrAddVert(obr, a);
- normalize_v3(ver->n);
- }
- }
- }
- else if (dl->type==DL_SURF) {
-
- /* cyclic U means an extruded full circular curve, we skip bevel splitting then */
- if (dl->flag & DL_CYCL_U) {
- orco+= 3*dl_surf_to_renderdata(obr, dl, matar, orco, mat);
- }
- else {
- int p1, p2, p3, p4;
-
- fp= dl->verts;
- startvert= obr->totvert;
- nr= dl->nr*dl->parts;
-
- while (nr--) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
-
- copy_v3_v3(ver->co, fp);
- mul_m4_v3(mat, ver->co);
- fp+= 3;
-
- if (orco) {
- ver->orco = orco;
- orco += 3;
- }
- }
-
- if (dl->flag & DL_CYCL_V && orco) {
- fp = dl->verts;
- nr = dl->nr;
- while (nr--) {
- ver = RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, fp);
- mul_m4_v3(mat, ver->co);
- ver->orco = orco;
- fp += 3;
- orco += 3;
- }
- }
-
- if (dl->bevel_split || timeoffset == 0) {
- const int startvlak= obr->totvlak;
-
- for (a=0; a<dl->parts; a++) {
-
- if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4)==0)
- break;
-
- p1+= startvert;
- p2+= startvert;
- p3+= startvert;
- p4+= startvert;
-
- if (dl->flag & DL_CYCL_V && orco && a == dl->parts - 1) {
- p3 = p1 + dl->nr;
- p4 = p2 + dl->nr;
- }
-
- for (; b<dl->nr; b++) {
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- /* important 1 offset in order is kept [#24913] */
- vlr->v1= RE_findOrAddVert(obr, p2);
- vlr->v2= RE_findOrAddVert(obr, p1);
- vlr->v3= RE_findOrAddVert(obr, p3);
- vlr->v4= RE_findOrAddVert(obr, p4);
- vlr->ec= ME_V2V3+ME_V3V4;
- if (a==0) vlr->ec+= ME_V1V2;
-
- vlr->flag= dl->rt;
-
- normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- vlr->mat= matar[ dl->col ];
-
- p4= p3;
- p3++;
- p2= p1;
- p1++;
- }
- }
-
- if (dl->bevel_split) {
- for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) {
- if (BLI_BITMAP_TEST(dl->bevel_split, a)) {
- split_v_renderfaces(
- obr, startvlak, startvert, dl->parts, dl->nr, a,
- /* intentionally swap (v, u) --> (u, v) */
- dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U);
- }
- }
- }
-
- /* vertex normals */
- for (a= startvlak; a<obr->totvlak; a++) {
- vlr= RE_findOrAddVlak(obr, a);
-
- add_v3_v3(vlr->v1->n, vlr->n);
- add_v3_v3(vlr->v3->n, vlr->n);
- add_v3_v3(vlr->v2->n, vlr->n);
- add_v3_v3(vlr->v4->n, vlr->n);
- }
- for (a=startvert; a<obr->totvert; a++) {
- ver= RE_findOrAddVert(obr, a);
- normalize_v3(ver->n);
- }
- }
- }
- }
-
- dl= dl->next;
- }
- }
-
- BKE_displist_free(&disp);
-
- MEM_freeN(matar);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Mesh */
-/* ------------------------------------------------------------------------- */
-
-struct edgesort {
- unsigned int v1, v2;
- int f;
- unsigned int i1, i2;
-};
-
-/* edges have to be added with lowest index first for sorting */
-static void to_edgesort(struct edgesort *ed,
- unsigned int i1, unsigned int i2,
- unsigned int v1, unsigned int v2, int f)
-{
- if (v1 > v2) {
- SWAP(unsigned int, v1, v2);
- SWAP(unsigned int, i1, i2);
- }
-
- ed->v1= v1;
- ed->v2= v2;
- ed->i1= i1;
- ed->i2= i2;
- ed->f = f;
-}
-
-static int vergedgesort(const void *v1, const void *v2)
-{
- const struct edgesort *x1=v1, *x2=v2;
-
- if ( x1->v1 > x2->v1) return 1;
- else if ( x1->v1 < x2->v1) return -1;
- else if ( x1->v2 > x2->v2) return 1;
- else if ( x1->v2 < x2->v2) return -1;
-
- return 0;
-}
-
-static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
-{
- MFace *mf, *mface;
- MTFace *tface=NULL;
- struct edgesort *edsort, *ed;
- unsigned int *mcol=NULL;
- int a, totedge=0, totface;
-
- mface= dm->getTessFaceArray(dm);
- totface= dm->getNumTessFaces(dm);
- tface= dm->getTessFaceDataArray(dm, CD_MTFACE);
- mcol= dm->getTessFaceDataArray(dm, CD_MCOL);
-
- if (mcol==NULL && tface==NULL) return NULL;
-
- /* make sorted table with edges and face indices in it */
- for (a= totface, mf= mface; a>0; a--, mf++) {
- totedge += mf->v4 ? 4 : 3;
- }
-
- if (totedge==0)
- return NULL;
-
- ed= edsort= MEM_callocN(totedge*sizeof(struct edgesort), "edgesort");
-
- for (a=0, mf=mface; a<totface; a++, mf++) {
- to_edgesort(ed++, 0, 1, mf->v1, mf->v2, a);
- to_edgesort(ed++, 1, 2, mf->v2, mf->v3, a);
- if (mf->v4) {
- to_edgesort(ed++, 2, 3, mf->v3, mf->v4, a);
- to_edgesort(ed++, 3, 0, mf->v4, mf->v1, a);
- }
- else {
- to_edgesort(ed++, 2, 3, mf->v3, mf->v1, a);
- }
- }
-
- qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort);
-
- *totedgesort= totedge;
-
- return edsort;
-}
-
-static void use_mesh_edge_lookup(ObjectRen *obr, DerivedMesh *dm, MEdge *medge, VlakRen *vlr, struct edgesort *edgetable, int totedge)
-{
- struct edgesort ed, *edp;
- CustomDataLayer *layer;
- MTFace *mtface, *mtf;
- MCol *mcol, *mc;
- int index, mtfn, mcn;
- char *name;
-
- if (medge->v1 < medge->v2) {
- ed.v1= medge->v1;
- ed.v2= medge->v2;
- }
- else {
- ed.v1= medge->v2;
- ed.v2= medge->v1;
- }
-
- edp= bsearch(&ed, edgetable, totedge, sizeof(struct edgesort), vergedgesort);
-
- /* since edges have different index ordering, we have to duplicate mcol and tface */
- if (edp) {
- mtfn= mcn= 0;
-
- for (index=0; index<dm->faceData.totlayer; index++) {
- layer= &dm->faceData.layers[index];
- name= layer->name;
-
- if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
- mtface= &((MTFace*)layer->data)[edp->f];
- mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
-
- *mtf= *mtface;
-
- memcpy(mtf->uv[0], mtface->uv[edp->i1], sizeof(float)*2);
- memcpy(mtf->uv[1], mtface->uv[edp->i2], sizeof(float)*2);
- memcpy(mtf->uv[2], mtface->uv[1], sizeof(float)*2);
- memcpy(mtf->uv[3], mtface->uv[1], sizeof(float)*2);
- }
- else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
- mcol= &((MCol*)layer->data)[edp->f*4];
- mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
-
- mc[0]= mcol[edp->i1];
- mc[1]= mc[2]= mc[3]= mcol[edp->i2];
- }
- }
- }
-}
-
-static void free_camera_inside_volumes(Render *re)
-{
- BLI_freelistN(&re->render_volumes_inside);
-}
-
-static void init_camera_inside_volumes(Render *re)
-{
- ObjectInstanceRen *obi;
- VolumeOb *vo;
- /* coordinates are all in camera space, so camera coordinate is zero. we also
- * add an offset for the clip start, however note that with clip start it's
- * actually impossible to do a single 'inside' test, since there will not be
- * a single point where all camera rays start from, though for small clip start
- * they will be close together. */
- float co[3] = {0.f, 0.f, -re->clipsta};
-
- for (vo= re->volumes.first; vo; vo= vo->next) {
- for (obi= re->instancetable.first; obi; obi= obi->next) {
- if (obi->obr == vo->obr) {
- if (point_inside_volume_objectinstance(re, obi, co)) {
- MatInside *mi;
-
- mi = MEM_mallocN(sizeof(MatInside), "camera inside material");
- mi->ma = vo->ma;
- mi->obi = obi;
-
- BLI_addtail(&(re->render_volumes_inside), mi);
- }
- }
- }
- }
-
-
-#if 0 /* debug */
- {
- MatInside *m;
- for (m = re->render_volumes_inside.first; m; m = m->next) {
- printf("matinside: ma: %s\n", m->ma->id.name + 2);
- }
- }
-#endif
-}
-
-static void add_volume(Render *re, ObjectRen *obr, Material *ma)
-{
- struct VolumeOb *vo;
-
- vo = MEM_mallocN(sizeof(VolumeOb), "volume object");
-
- vo->ma = ma;
- vo->obr = obr;
-
- BLI_addtail(&re->volumes, vo);
-}
-
-#ifdef WITH_FREESTYLE
-static EdgeHash *make_freestyle_edge_mark_hash(DerivedMesh *dm)
-{
- EdgeHash *edge_hash= NULL;
- FreestyleEdge *fed;
- MEdge *medge;
- int totedge, a;
-
- medge = dm->getEdgeArray(dm);
- totedge = dm->getNumEdges(dm);
- fed = dm->getEdgeDataArray(dm, CD_FREESTYLE_EDGE);
- if (fed) {
- edge_hash = BLI_edgehash_new(__func__);
- for (a = 0; a < totedge; a++) {
- if (fed[a].flag & FREESTYLE_EDGE_MARK)
- BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
- }
- }
- return edge_hash;
-}
-
-static bool has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2)
-{
- MEdge *medge= BLI_edgehash_lookup(edge_hash, v1, v2);
- return (!medge) ? 0 : 1;
-}
-#endif
-
-static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- Mesh *me;
- MVert *mvert = NULL;
- MFace *mface;
- VlakRen *vlr; //, *vlr1;
- VertRen *ver;
- Material *ma;
- DerivedMesh *dm;
- CustomDataMask mask;
- float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3],
- float *orco = NULL;
- short (*loop_nors)[4][3] = NULL;
- bool need_orco = false, need_stress = false, need_tangent = false, need_origindex = false;
- bool need_nmap_tangent_concrete = false;
- int a, a1, ok, vertofs;
- int end, totvert = 0;
- bool do_autosmooth = false, do_displace = false;
- bool use_original_normals = false;
- int recalc_normals = 0; /* false by default */
- int negative_scale;
-#ifdef WITH_FREESTYLE
- FreestyleFace *ffa;
-#endif
-
- me= ob->data;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- copy_m3_m4(imat, ob->imat);
- negative_scale= is_negative_m4(mat);
-
- need_orco= 0;
- for (a=1; a<=ob->totcol; a++) {
- ma= give_render_material(re, ob, a);
- if (ma) {
- if (ma->texco & (TEXCO_ORCO|TEXCO_STRESS))
- need_orco= 1;
- if (ma->texco & TEXCO_STRESS)
- need_stress= 1;
- /* normalmaps, test if tangents needed, separated from shading */
- if (ma->mode_l & MA_TANGENT_V) {
- need_tangent= 1;
- if (me->mtpoly==NULL)
- need_orco= 1;
- }
- if (ma->mode_l & MA_NORMAP_TANG) {
- if (me->mtpoly==NULL) {
- need_orco= 1;
- }
- need_tangent= 1;
- }
- if (ma->mode2_l & MA_TANGENT_CONCRETE) {
- need_nmap_tangent_concrete = true;
- }
- }
- }
-
- if (re->flag & R_NEED_TANGENT) {
- /* exception for tangent space baking */
- if (me->mtpoly==NULL) {
- need_orco= 1;
- }
- need_tangent= 1;
- }
-
- /* check autosmooth and displacement, we then have to skip only-verts optimize
- * Note: not sure what we want to give higher priority, currently do_displace
- * takes precedence over do_autosmooth.
- */
- do_displace = test_for_displace(re, ob);
- do_autosmooth = ((me->flag & ME_AUTOSMOOTH) != 0) && !do_displace;
- if (do_autosmooth || do_displace)
- timeoffset = 0;
-
- /* origindex currently used when using autosmooth, or baking to vertex colors. */
- need_origindex = (do_autosmooth || ((re->flag & R_BAKING) && (re->r.bake_flag & R_BAKE_VCOL)));
-
- mask = CD_MASK_RENDER_INTERNAL;
- if (!timeoffset)
- if (need_orco)
- mask |= CD_MASK_ORCO;
-
-#ifdef WITH_FREESTYLE
- mask |= CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
-#endif
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- dm= mesh_create_derived_view(re->scene, ob, mask);
- else
- dm= mesh_create_derived_render(re->scene, ob, mask);
- if (dm==NULL) return; /* in case duplicated object fails? */
-
- mvert= dm->getVertArray(dm);
- totvert= dm->getNumVerts(dm);
-
- if (totvert == 0) {
- dm->release(dm);
- return;
- }
-
- if (mask & CD_MASK_ORCO) {
- orco = get_object_orco(re, ob);
- if (!orco) {
- orco= dm->getVertDataArray(dm, CD_ORCO);
- if (orco) {
- orco= MEM_dupallocN(orco);
- set_object_orco(re, ob, orco);
- }
- }
- }
-
- /* attempt to autsmooth on original mesh, only without subsurf */
- if (do_autosmooth && me->totvert==totvert && me->totface==dm->getNumTessFaces(dm))
- use_original_normals= true;
-
- ma= give_render_material(re, ob, 1);
-
-
- if (ma->material_type == MA_TYPE_HALO) {
- make_render_halos(re, obr, me, totvert, mvert, ma, orco);
- }
- else {
- const int *index_vert_orig = NULL;
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
- if (need_origindex) {
- index_vert_orig = dm->getVertDataArray(dm, CD_ORIGINDEX);
- /* double lookup for faces -> polys */
-#ifdef WITH_FREESTYLE
- index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-#endif
- }
-
- for (a=0; a<totvert; a++, mvert++) {
- ver= RE_findOrAddVert(obr, obr->totvert++);
- copy_v3_v3(ver->co, mvert->co);
- if (do_autosmooth == false) { /* autosmooth on original unrotated data to prevent differences between frames */
- normal_short_to_float_v3(ver->n, mvert->no);
- mul_m4_v3(mat, ver->co);
- mul_transposed_m3_v3(imat, ver->n);
- normalize_v3(ver->n);
- negate_v3(ver->n);
- }
-
- if (orco) {
- ver->orco= orco;
- orco+=3;
- }
-
- if (need_origindex) {
- int *origindex;
- origindex = RE_vertren_get_origindex(obr, ver, 1);
-
- /* Use orig index array if it's available (e.g. in the presence
- * of modifiers). */
- if (index_vert_orig)
- *origindex = index_vert_orig[a];
- else
- *origindex = a;
- }
- }
-
- if (!timeoffset) {
- short (*lnp)[4][3] = NULL;
-#ifdef WITH_FREESTYLE
- EdgeHash *edge_hash;
-
- /* create a hash table of Freestyle edge marks */
- edge_hash = make_freestyle_edge_mark_hash(dm);
-#endif
-
- /* store customdata names, because DerivedMesh is freed */
- RE_set_customdata_names(obr, &dm->faceData);
-
- /* add tangent layers if we need */
- if ((ma->nmap_tangent_names_count && need_nmap_tangent_concrete) || need_tangent) {
- dm->calcLoopTangents(
- dm, need_tangent,
- (const char (*)[MAX_NAME])ma->nmap_tangent_names, ma->nmap_tangent_names_count);
- obr->tangent_mask = dm->tangent_mask;
- DM_generate_tangent_tessface_data(dm, need_nmap_tangent_concrete || need_tangent);
- }
-
- /* still to do for keys: the correct local texture coordinate */
-
- /* faces in order of color blocks */
- vertofs= obr->totvert - totvert;
- for (a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) {
-
- ma= give_render_material(re, ob, a1+1);
-
- /* test for 100% transparent */
- ok = 1;
- if ((ma->alpha == 0.0f) &&
- (ma->spectra == 0.0f) &&
- /* No need to test filter here, it's only active with MA_RAYTRANSP and we check against it below. */
- /* (ma->filter == 0.0f) && */
- (ma->mode & MA_TRANSP) &&
- (ma->mode & (MA_RAYTRANSP | MA_RAYMIRROR)) == 0)
- {
- ok = 0;
- /* texture on transparency? */
- for (a=0; a<MAX_MTEX; a++) {
- if (ma->mtex[a] && ma->mtex[a]->tex) {
- if (ma->mtex[a]->mapto & MAP_ALPHA) ok= 1;
- }
- }
- }
-
- /* if wire material, and we got edges, don't do the faces */
- if (ma->material_type == MA_TYPE_WIRE) {
- end= dm->getNumEdges(dm);
- if (end) ok= 0;
- }
-
- if (ok) {
- end= dm->getNumTessFaces(dm);
- mface= dm->getTessFaceArray(dm);
- if (!loop_nors && do_autosmooth &&
- (dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL) != NULL))
- {
- lnp = loop_nors = MEM_mallocN(sizeof(*loop_nors) * end, __func__);
- }
-#ifdef WITH_FREESTYLE
- index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX);
- ffa= CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
-#endif
-
- for (a=0; a<end; a++, mface++) {
- int v1, v2, v3, v4, flag;
-
- if ( mface->mat_nr==a1 ) {
- float len;
- bool reverse_verts = (negative_scale != 0 && do_autosmooth == false);
- int rev_tab[] = {reverse_verts==0 ? 0 : 2, 1, reverse_verts==0 ? 2 : 0, 3};
- v1= reverse_verts==0 ? mface->v1 : mface->v3;
- v2= mface->v2;
- v3= reverse_verts==0 ? mface->v3 : mface->v1;
- v4= mface->v4;
- flag = do_autosmooth ? ME_SMOOTH : mface->flag & ME_SMOOTH;
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
- vlr->v2= RE_findOrAddVert(obr, vertofs+v2);
- vlr->v3= RE_findOrAddVert(obr, vertofs+v3);
- if (v4) vlr->v4 = RE_findOrAddVert(obr, vertofs+v4);
- else vlr->v4 = NULL;
-
-#ifdef WITH_FREESTYLE
- /* Freestyle edge/face marks */
- if (edge_hash) {
- int edge_mark = 0;
-
- if (has_freestyle_edge_mark(edge_hash, v1, v2)) edge_mark |= R_EDGE_V1V2;
- if (has_freestyle_edge_mark(edge_hash, v2, v3)) edge_mark |= R_EDGE_V2V3;
- if (!v4) {
- if (has_freestyle_edge_mark(edge_hash, v3, v1)) edge_mark |= R_EDGE_V3V1;
- }
- else {
- if (has_freestyle_edge_mark(edge_hash, v3, v4)) edge_mark |= R_EDGE_V3V4;
- if (has_freestyle_edge_mark(edge_hash, v4, v1)) edge_mark |= R_EDGE_V4V1;
- }
- vlr->freestyle_edge_mark= edge_mark;
- }
- if (ffa) {
- int index = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
- vlr->freestyle_face_mark= (ffa[index].flag & FREESTYLE_FACE_MARK) ? 1 : 0;
- }
- else {
- vlr->freestyle_face_mark= 0;
- }
-#endif
-
- /* render normals are inverted in render */
- if (use_original_normals) {
- MFace *mf= me->mface+a;
- MVert *mv= me->mvert;
-
- if (vlr->v4)
- len= normal_quad_v3(vlr->n, mv[mf->v4].co, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co);
- else
- len= normal_tri_v3(vlr->n, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co);
- }
- else {
- if (vlr->v4)
- len= normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- else
- len= normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- }
-
- vlr->mat= ma;
- vlr->flag= flag;
- vlr->ec= 0; /* mesh edges rendered separately */
-
- if (len==0) obr->totvlak--;
- else {
- CustomDataLayer *layer;
- MTFace *mtface, *mtf;
- MCol *mcol, *mc;
- int index, mtfn= 0, mcn= 0, mln = 0, vindex;
- char *name;
- int nr_verts = v4!=0 ? 4 : 3;
-
- for (index=0; index<dm->faceData.totlayer; index++) {
- layer= &dm->faceData.layers[index];
- name= layer->name;
-
- if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
- int t;
- mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
- mtface= (MTFace*)layer->data;
- *mtf = mtface[a]; /* copy face info */
- for (vindex=0; vindex<nr_verts; vindex++)
- for (t=0; t<2; t++)
- mtf->uv[vindex][t]=mtface[a].uv[rev_tab[vindex]][t];
- }
- else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
- mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
- mcol= (MCol*)layer->data;
- for (vindex=0; vindex<nr_verts; vindex++)
- mc[vindex]=mcol[a*4+rev_tab[vindex]];
- }
- else if (layer->type == CD_TANGENT) {
- if (need_nmap_tangent_concrete || need_tangent) {
- int uv_start = CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
- int uv_index = CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, layer->name);
-
- /* if there are no UVs, orco tangents are in first slot */
- int n = (uv_start >= 0 && uv_index >= 0) ? uv_index - uv_start : 0;
-
- const float *tangent = (const float *) layer->data;
- float *ftang = RE_vlakren_get_nmap_tangent(obr, vlr, n, true);
-
- for (vindex=0; vindex<nr_verts; vindex++) {
- copy_v4_v4(ftang+vindex*4, tangent+a*16+rev_tab[vindex]*4);
- mul_mat3_m4_v3(mat, ftang+vindex*4);
- normalize_v3(ftang+vindex*4);
- }
- }
- }
- else if (layer->type == CD_TESSLOOPNORMAL && mln < 1) {
- if (loop_nors) {
- const short (*lnors)[4][3] = (const short (*)[4][3])layer->data;
- for (vindex = 0; vindex < 4; vindex++) {
- //print_v3("lnors[a][rev_tab[vindex]]", lnors[a][rev_tab[vindex]]);
- copy_v3_v3_short((short *)lnp[0][vindex], lnors[a][rev_tab[vindex]]);
- /* If we copy loop normals, we are doing autosmooth, so we are still
- * in object space, no need to multiply with mat!
- */
- }
- lnp++;
- }
- mln++;
- }
- }
-
- if (need_origindex) {
- /* Find original index of mpoly for this tessface. Options:
- * - Modified mesh; two-step look up from tessface -> modified mpoly -> original mpoly
- * - OR Tesselated mesh; look up from tessface -> mpoly
- * - OR Failsafe; tessface == mpoly. Could probably assert(false) in this case? */
- int *origindex;
- origindex = RE_vlakren_get_origindex(obr, vlr, 1);
- if (index_mf_to_mpoly && index_mp_to_orig)
- *origindex = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a);
- else if (index_mf_to_mpoly)
- *origindex = index_mf_to_mpoly[a];
- else
- *origindex = a;
- }
- }
- }
- }
- }
- }
-
-#ifdef WITH_FREESTYLE
- /* release the hash table of Freestyle edge marks */
- if (edge_hash)
- BLI_edgehash_free(edge_hash, NULL);
-#endif
-
- /* exception... we do edges for wire mode. potential conflict when faces exist... */
- end= dm->getNumEdges(dm);
- mvert= dm->getVertArray(dm);
- ma= give_render_material(re, ob, 1);
- if (end && (ma->material_type == MA_TYPE_WIRE)) {
- MEdge *medge;
- struct edgesort *edgetable;
- int totedge= 0;
- recalc_normals= 1;
-
- medge= dm->getEdgeArray(dm);
-
- /* we want edges to have UV and vcol too... */
- edgetable= make_mesh_edge_lookup(dm, &totedge);
-
- for (a1=0; a1<end; a1++, medge++) {
- if (medge->flag&ME_EDGERENDER) {
- MVert *v0 = &mvert[medge->v1];
- MVert *v1 = &mvert[medge->v2];
-
- vlr= RE_findOrAddVlak(obr, obr->totvlak++);
- vlr->v1= RE_findOrAddVert(obr, vertofs+medge->v1);
- vlr->v2= RE_findOrAddVert(obr, vertofs+medge->v2);
- vlr->v3= vlr->v2;
- vlr->v4= NULL;
-
- if (edgetable)
- use_mesh_edge_lookup(obr, dm, medge, vlr, edgetable, totedge);
-
- xn= -(v0->no[0]+v1->no[0]);
- yn= -(v0->no[1]+v1->no[1]);
- zn= -(v0->no[2]+v1->no[2]);
- /* transpose ! */
- vlr->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
- vlr->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
- vlr->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
- normalize_v3(vlr->n);
-
- vlr->mat= ma;
- vlr->flag= 0;
- vlr->ec= ME_V1V2;
- }
- }
- if (edgetable)
- MEM_freeN(edgetable);
- }
- }
- }
-
- if (!timeoffset) {
- if (need_stress)
- calc_edge_stress(re, obr, me);
-
- if (do_displace) {
- calc_vertexnormals(re, obr, 1, 0, 0);
- displace(re, obr);
- recalc_normals = 0; /* Already computed by displace! */
- }
- else if (do_autosmooth) {
- recalc_normals = (loop_nors == NULL); /* Should never happen, but better be safe than sorry. */
- autosmooth(re, obr, mat, loop_nors);
- }
-
- if (recalc_normals!=0 || need_tangent!=0)
- calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent_concrete);
- }
-
- MEM_SAFE_FREE(loop_nors);
-
- dm->release(dm);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Lamps and Shadowbuffers */
-/* ------------------------------------------------------------------------- */
-
-static void initshadowbuf(Render *re, LampRen *lar, float mat[4][4])
-{
- struct ShadBuf *shb;
- float viewinv[4][4];
-
- /* if (la->spsi<16) return; */
-
- /* memory alloc */
- shb= (struct ShadBuf *)MEM_callocN(sizeof(struct ShadBuf), "initshadbuf");
- lar->shb= shb;
-
- if (shb==NULL) return;
-
- VECCOPY(shb->co, lar->co); /* int copy */
-
- /* percentage render: keep track of min and max */
- shb->size= (lar->bufsize*re->r.size)/100;
-
- if (shb->size<512) shb->size= 512;
- else if (shb->size > lar->bufsize) shb->size= lar->bufsize;
-
- shb->size &= ~15; /* make sure its multiples of 16 */
-
- shb->samp= lar->samp;
- shb->soft= lar->soft;
- shb->shadhalostep= lar->shadhalostep;
-
- normalize_m4(mat);
- invert_m4_m4(shb->winmat, mat); /* winmat is temp */
-
- /* matrix: combination of inverse view and lampmat */
- /* calculate again: the ortho-render has no correct viewinv */
- invert_m4_m4(viewinv, re->viewmat);
- mul_m4_m4m4(shb->viewmat, shb->winmat, viewinv);
-
- /* projection */
- shb->d= lar->clipsta;
- shb->clipend= lar->clipend;
-
- /* bias is percentage, made 2x larger because of correction for angle of incidence */
- /* when a ray is closer to parallel of a face, bias value is increased during render */
- shb->bias= (0.02f*lar->bias)*0x7FFFFFFF;
-
- /* halfway method (average of first and 2nd z) reduces bias issues */
- if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
- shb->bias= 0.1f*shb->bias;
-
- shb->compressthresh= lar->compressthresh;
-}
-
-void area_lamp_vectors(LampRen *lar)
-{
- float xsize= 0.5f*lar->area_size, ysize= 0.5f*lar->area_sizey, multifac;
-
- /* make it smaller, so area light can be multisampled */
- multifac= 1.0f/sqrtf((float)lar->ray_totsamp);
- xsize *= multifac;
- ysize *= multifac;
-
- /* corner vectors */
- lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
- lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
- lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
-
- /* corner vectors */
- lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
- lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
- lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
-
- /* corner vectors */
- lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
- lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
- lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
-
- /* corner vectors */
- lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
- lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
- lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
- /* only for correction button size, matrix size works on energy */
- lar->areasize= lar->dist*lar->dist/(4.0f*xsize*ysize);
-}
-
-/* If lar takes more lamp data, the decoupling will be better. */
-static GroupObject *add_render_lamp(Render *re, Object *ob)
-{
- Lamp *la= ob->data;
- LampRen *lar;
- GroupObject *go;
- float mat[4][4], angle, xn, yn;
- float vec[3];
- int c;
-
- /* previewrender sets this to zero... prevent accidents */
- if (la==NULL) return NULL;
-
- /* prevent only shadow from rendering light */
- if (la->mode & LA_ONLYSHADOW)
- if ((re->r.mode & R_SHADOW)==0)
- return NULL;
-
- re->totlamp++;
-
- /* groups is used to unify support for lightgroups, this is the global lightgroup */
- go= MEM_callocN(sizeof(GroupObject), "groupobject");
- BLI_addtail(&re->lights, go);
- go->ob= ob;
- /* lamprens are in own list, for freeing */
- lar= (LampRen *)MEM_callocN(sizeof(LampRen), "lampren");
- BLI_addtail(&re->lampren, lar);
- go->lampren= lar;
-
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
-
- copy_m4_m4(lar->lampmat, ob->obmat);
- copy_m3_m4(lar->mat, mat);
- copy_m3_m4(lar->imat, ob->imat);
-
- lar->bufsize = la->bufsize;
- lar->samp = la->samp;
- lar->buffers= la->buffers;
- if (lar->buffers==0) lar->buffers= 1;
- lar->buftype= la->buftype;
- lar->filtertype= la->filtertype;
- lar->soft = la->soft;
- lar->shadhalostep = la->shadhalostep;
- lar->clipsta = la->clipsta;
- lar->clipend = la->clipend;
-
- lar->bias = la->bias;
- lar->compressthresh = la->compressthresh;
-
- lar->type= la->type;
- lar->mode= la->mode;
-
- lar->energy= la->energy;
- if (la->mode & LA_NEG) lar->energy= -lar->energy;
-
- lar->vec[0]= -mat[2][0];
- lar->vec[1]= -mat[2][1];
- lar->vec[2]= -mat[2][2];
- normalize_v3(lar->vec);
- lar->co[0]= mat[3][0];
- lar->co[1]= mat[3][1];
- lar->co[2]= mat[3][2];
- lar->dist= la->dist;
- lar->haint= la->haint;
- lar->distkw= lar->dist*lar->dist;
- lar->r= lar->energy*la->r;
- lar->g= lar->energy*la->g;
- lar->b= lar->energy*la->b;
- lar->shdwr= la->shdwr;
- lar->shdwg= la->shdwg;
- lar->shdwb= la->shdwb;
- lar->k= la->k;
-
- /* area */
- lar->ray_samp= la->ray_samp;
- lar->ray_sampy= la->ray_sampy;
- lar->ray_sampz= la->ray_sampz;
-
- lar->area_size= la->area_size;
- lar->area_sizey= la->area_sizey;
- lar->area_sizez= la->area_sizez;
-
- lar->area_shape= la->area_shape;
-
- /* Annoying, lamp UI does this, but the UI might not have been used? - add here too.
- * make sure this matches buttons_shading.c's logic */
- if (ELEM(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY))
- if (ELEM(la->type, LA_SPOT, LA_SUN, LA_LOCAL))
- if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON;
-
- lar->ray_samp_method= la->ray_samp_method;
- lar->ray_samp_type= la->ray_samp_type;
-
- lar->adapt_thresh= la->adapt_thresh;
- lar->sunsky = NULL;
-
- if ( ELEM(lar->type, LA_SPOT, LA_LOCAL)) {
- lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
- lar->area_shape = LA_AREA_SQUARE;
- lar->area_sizey= lar->area_size;
- }
- else if (lar->type==LA_AREA) {
- switch (lar->area_shape) {
- case LA_AREA_SQUARE:
- lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
- lar->ray_sampy= lar->ray_samp;
- lar->area_sizey= lar->area_size;
- break;
- case LA_AREA_RECT:
- lar->ray_totsamp= lar->ray_samp*lar->ray_sampy;
- break;
- case LA_AREA_CUBE:
- lar->ray_totsamp= lar->ray_samp*lar->ray_samp*lar->ray_samp;
- lar->ray_sampy= lar->ray_samp;
- lar->ray_sampz= lar->ray_samp;
- lar->area_sizey= lar->area_size;
- lar->area_sizez= lar->area_size;
- break;
- case LA_AREA_BOX:
- lar->ray_totsamp= lar->ray_samp*lar->ray_sampy*lar->ray_sampz;
- break;
- }
-
- area_lamp_vectors(lar);
- init_jitter_plane(lar); /* subsamples */
- }
- else if (lar->type==LA_SUN) {
- lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
- lar->area_shape = LA_AREA_SQUARE;
- lar->area_sizey= lar->area_size;
-
- if ((la->sun_effect_type & LA_SUN_EFFECT_SKY) ||
- (la->sun_effect_type & LA_SUN_EFFECT_AP))
- {
- lar->sunsky = (struct SunSky*)MEM_callocN(sizeof(struct SunSky), "sunskyren");
- lar->sunsky->effect_type = la->sun_effect_type;
-
- copy_v3_v3(vec, ob->obmat[2]);
- normalize_v3(vec);
-
- InitSunSky(
- lar->sunsky, la->atm_turbidity, vec, la->horizon_brightness,
- la->spread, la->sun_brightness, la->sun_size, la->backscattered_light,
- la->skyblendfac, la->skyblendtype, la->sky_exposure, la->sky_colorspace);
- InitAtmosphere(
- lar->sunsky, la->sun_intensity, 1.0, 1.0, la->atm_inscattering_factor, la->atm_extinction_factor,
- la->atm_distance_factor);
- }
- }
- else lar->ray_totsamp= 0;
-
- lar->spotsi= la->spotsize;
- if (lar->mode & LA_HALO) {
- if (lar->spotsi > DEG2RADF(170.0f)) lar->spotsi = DEG2RADF(170.0f);
- }
- lar->spotsi= cosf(lar->spotsi * 0.5f);
- lar->spotbl= (1.0f-lar->spotsi)*la->spotblend;
-
- memcpy(lar->mtex, la->mtex, MAX_MTEX*sizeof(void *));
-
- lar->lay = ob->lay & 0xFFFFFF; /* higher 8 bits are localview layers */
-
- lar->falloff_type = la->falloff_type;
- lar->ld1= la->att1;
- lar->ld2= la->att2;
- lar->coeff_const= la->coeff_const;
- lar->coeff_lin= la->coeff_lin;
- lar->coeff_quad= la->coeff_quad;
- lar->curfalloff = curvemapping_copy(la->curfalloff);
-
- if (lar->curfalloff) {
- /* so threads don't conflict on init */
- curvemapping_initialize(lar->curfalloff);
- }
-
- if (lar->type==LA_SPOT) {
-
- normalize_v3(lar->imat[0]);
- normalize_v3(lar->imat[1]);
- normalize_v3(lar->imat[2]);
-
- xn = saacos(lar->spotsi);
- xn = sinf(xn) / cosf(xn);
- lar->spottexfac= 1.0f/(xn);
-
- if (lar->mode & LA_ONLYSHADOW) {
- if ((lar->mode & (LA_SHAD_BUF|LA_SHAD_RAY))==0) lar->mode -= LA_ONLYSHADOW;
- }
-
- }
-
- /* set flag for spothalo en initvars */
- if ((la->type == LA_SPOT) && (la->mode & LA_HALO) &&
- (!(la->mode & LA_SHAD_BUF) || la->buftype != LA_SHADBUF_DEEP))
- {
- if (la->haint>0.0f) {
- re->flag |= R_LAMPHALO;
-
- /* camera position (0, 0, 0) rotate around lamp */
- lar->sh_invcampos[0]= -lar->co[0];
- lar->sh_invcampos[1]= -lar->co[1];
- lar->sh_invcampos[2]= -lar->co[2];
- mul_m3_v3(lar->imat, lar->sh_invcampos);
-
- /* z factor, for a normalized volume */
- angle= saacos(lar->spotsi);
- xn= lar->spotsi;
- yn = sinf(angle);
- lar->sh_zfac= yn/xn;
- /* pre-scale */
- lar->sh_invcampos[2]*= lar->sh_zfac;
-
- /* halfway shadow buffer doesn't work for volumetric effects */
- if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
- lar->buftype = LA_SHADBUF_REGULAR;
-
- }
- }
- else if (la->type==LA_HEMI) {
- lar->mode &= ~(LA_SHAD_RAY|LA_SHAD_BUF);
- }
-
- for (c=0; c<MAX_MTEX; c++) {
- if (la->mtex[c] && la->mtex[c]->tex) {
- if (la->mtex[c]->mapto & LAMAP_COL)
- lar->mode |= LA_TEXTURE;
- if (la->mtex[c]->mapto & LAMAP_SHAD)
- lar->mode |= LA_SHAD_TEX;
-
- if (G.is_rendering) {
- if (re->osa) {
- if (la->mtex[c]->tex->type==TEX_IMAGE) lar->mode |= LA_OSATEX;
- }
- }
- }
- }
-
- /* old code checked for internal render (aka not yafray) */
- {
- /* to make sure we can check ray shadow easily in the render code */
- if (lar->mode & LA_SHAD_RAY) {
- if ( (re->r.mode & R_RAYTRACE)==0)
- lar->mode &= ~LA_SHAD_RAY;
- }
-
-
- if (re->r.mode & R_SHADOW) {
-
- if (la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) && (lar->ray_samp_method == LA_SAMP_CONSTANT)) {
- init_jitter_plane(lar);
- }
- else if (la->type==LA_SPOT && (lar->mode & LA_SHAD_BUF) ) {
- /* Per lamp, one shadow buffer is made. */
- lar->bufflag= la->bufflag;
- copy_m4_m4(mat, ob->obmat);
- initshadowbuf(re, lar, mat); /* mat is altered */
- }
-
-
- /* this is the way used all over to check for shadow */
- if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
- LampShadowSample *ls;
- LampShadowSubSample *lss;
- int a, b;
-
- memset(re->shadowsamplenr, 0, sizeof(re->shadowsamplenr));
-
- lar->shadsamp= MEM_mallocN(re->r.threads*sizeof(LampShadowSample), "lamp shadow sample");
- ls= lar->shadsamp;
-
- /* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */
- for (a=0; a<re->r.threads; a++, ls++) {
- lss= ls->s;
- for (b=0; b<re->r.osa; b++, lss++) {
- lss->samplenr= -1; /* used to detect whether we store or read */
- lss->shadfac[0]= 1.0f;
- lss->shadfac[1]= 1.0f;
- lss->shadfac[2]= 1.0f;
- lss->shadfac[3]= 1.0f;
- }
- }
- }
- }
- }
-
- return go;
-}
-
-static bool is_object_restricted(Render *re, Object *ob)
-{
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- return (ob->restrictflag & OB_RESTRICT_VIEW) != 0;
- else
- return (ob->restrictflag & OB_RESTRICT_RENDER) != 0;
-}
-
-static bool is_object_hidden(Render *re, Object *ob)
-{
- if (is_object_restricted(re, ob))
- return true;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW) {
- /* Mesh deform cages and so on mess up the preview. To avoid the problem,
- * viewport doesn't show mesh object if its draw type is bounding box or wireframe.
- * Unless it's an active smoke domain!
- */
- ModifierData *md = NULL;
-
- if ((md = modifiers_findByType(ob, eModifierType_Smoke)) &&
- (modifier_isEnabled(re->scene, md, eModifierMode_Realtime)))
- {
- return false;
- }
- return ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE);
- }
- else {
- return false;
- }
-}
-
-/* layflag: allows material group to ignore layerflag */
-static void add_lightgroup(Render *re, Group *group, int exclusive)
-{
- GroupObject *go, *gol;
-
- group->id.tag &= ~LIB_TAG_DOIT;
-
- /* it's a bit too many loops in loops... but will survive */
- /* note that 'exclusive' will remove it from the global list */
- for (go= group->gobject.first; go; go= go->next) {
- go->lampren= NULL;
-
- if (is_object_hidden(re, go->ob))
- continue;
-
- if (go->ob->lay & re->lay) {
- if (go->ob && go->ob->type==OB_LAMP) {
- for (gol= re->lights.first; gol; gol= gol->next) {
- if (gol->ob==go->ob) {
- go->lampren= gol->lampren;
- break;
- }
- }
- if (go->lampren==NULL)
- gol= add_render_lamp(re, go->ob);
- if (gol && exclusive) {
- BLI_remlink(&re->lights, gol);
- MEM_freeN(gol);
- }
- }
- }
- }
-}
-
-static void set_material_lightgroups(Render *re)
-{
- Group *group;
- Material *ma;
-
- /* not for preview render */
- if (re->scene->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))
- return;
-
- for (group= re->main->group.first; group; group=group->id.next)
- group->id.tag |= LIB_TAG_DOIT;
-
- /* it's a bit too many loops in loops... but will survive */
- /* hola! materials not in use...? */
- for (ma= re->main->mat.first; ma; ma=ma->id.next) {
- if (ma->group && (ma->group->id.tag & LIB_TAG_DOIT))
- add_lightgroup(re, ma->group, ma->mode & MA_GROUP_NOLAY);
- }
-}
-
-static void set_renderlayer_lightgroups(Render *re, Scene *sce)
-{
- SceneRenderLayer *srl;
-
- for (srl= sce->r.layers.first; srl; srl= srl->next) {
- if (srl->light_override)
- add_lightgroup(re, srl->light_override, 0);
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* World */
-/* ------------------------------------------------------------------------- */
-
-void init_render_world(Render *re)
-{
- void *wrld_prev[2] = {
- re->wrld.aotables,
- re->wrld.aosphere,
- };
-
- int a;
-
- if (re->scene && re->scene->world) {
- re->wrld = *(re->scene->world);
-
- copy_v3_v3(re->grvec, re->viewmat[2]);
- normalize_v3(re->grvec);
- copy_m3_m4(re->imat, re->viewinv);
-
- for (a=0; a<MAX_MTEX; a++)
- if (re->wrld.mtex[a] && re->wrld.mtex[a]->tex) re->wrld.skytype |= WO_SKYTEX;
-
- /* AO samples should be OSA minimum */
- if (re->osa)
- while (re->wrld.aosamp*re->wrld.aosamp < re->osa)
- re->wrld.aosamp++;
- if (!(re->r.mode & R_RAYTRACE) && (re->wrld.ao_gather_method == WO_AOGATHER_RAYTRACE))
- re->wrld.mode &= ~(WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT);
- }
- else {
- memset(&re->wrld, 0, sizeof(World));
- re->wrld.exp= 0.0f;
- re->wrld.range= 1.0f;
-
- /* for mist pass */
- re->wrld.miststa= re->clipsta;
- re->wrld.mistdist= re->clipend-re->clipsta;
- re->wrld.misi= 1.0f;
- }
-
- re->wrld.linfac= 1.0f + powf((2.0f*re->wrld.exp + 0.5f), -10);
- re->wrld.logfac= logf((re->wrld.linfac-1.0f)/re->wrld.linfac) / re->wrld.range;
-
- /* restore runtime vars, needed for viewport rendering [#36005] */
- re->wrld.aotables = wrld_prev[0];
- re->wrld.aosphere = wrld_prev[1];
-}
-
-
-
-/* ------------------------------------------------------------------------- */
-/* Object Finalization */
-/* ------------------------------------------------------------------------- */
-
-/* prevent phong interpolation for giving ray shadow errors (terminator problem) */
-static void set_phong_threshold(ObjectRen *obr)
-{
-// VertRen *ver;
- VlakRen *vlr;
- float thresh= 0.0, dot;
- int tot=0, i;
-
- /* Added check for 'pointy' situations, only dotproducts of 0.9 and larger
- * are taken into account. This threshold is meant to work on smooth geometry, not
- * for extreme cases (ton) */
-
- for (i=0; i<obr->totvlak; i++) {
- vlr= RE_findOrAddVlak(obr, i);
- if ((vlr->flag & R_SMOOTH) && (vlr->flag & R_STRAND)==0) {
- dot= dot_v3v3(vlr->n, vlr->v1->n);
- dot= ABS(dot);
- if (dot>0.9f) {
- thresh+= dot; tot++;
- }
- dot= dot_v3v3(vlr->n, vlr->v2->n);
- dot= ABS(dot);
- if (dot>0.9f) {
- thresh+= dot; tot++;
- }
-
- dot= dot_v3v3(vlr->n, vlr->v3->n);
- dot= ABS(dot);
- if (dot>0.9f) {
- thresh+= dot; tot++;
- }
-
- if (vlr->v4) {
- dot= dot_v3v3(vlr->n, vlr->v4->n);
- dot= ABS(dot);
- if (dot>0.9f) {
- thresh+= dot; tot++;
- }
- }
- }
- }
-
- if (tot) {
- thresh/= (float)tot;
- obr->ob->smoothresh= cosf(0.5f*(float)M_PI-saacos(thresh));
- }
-}
-
-/* per face check if all samples should be taken.
- * if raytrace or multisample, do always for raytraced material, or when material full_osa set */
-static void set_fullsample_trace_flag(Render *re, ObjectRen *obr)
-{
- VlakRen *vlr;
- int a, trace, mode, osa;
-
- osa= re->osa;
- trace= re->r.mode & R_RAYTRACE;
-
- for (a=obr->totvlak-1; a>=0; a--) {
- vlr= RE_findOrAddVlak(obr, a);
- mode= vlr->mat->mode;
-
- if (trace && (mode & MA_TRACEBLE))
- vlr->flag |= R_TRACEBLE;
-
- if (osa) {
- if (mode & MA_FULL_OSA) {
- vlr->flag |= R_FULL_OSA;
- }
- else if (trace) {
- if (mode & MA_SHLESS) {
- /* pass */
- }
- else if (vlr->mat->material_type == MA_TYPE_VOLUME) {
- /* pass */
- }
- else if ((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP))) {
- /* for blurry reflect/refract, better to take more samples
- * inside the raytrace than as OSA samples */
- if ((vlr->mat->gloss_mir == 1.0f) && (vlr->mat->gloss_tra == 1.0f))
- vlr->flag |= R_FULL_OSA;
- }
- }
- }
- }
-}
-
-/* split quads for predictable baking
- * dir 1 == (0, 1, 2) (0, 2, 3), 2 == (1, 3, 0) (1, 2, 3)
- */
-static void split_quads(ObjectRen *obr, int dir)
-{
- VlakRen *vlr, *vlr1;
- int a;
-
- for (a=obr->totvlak-1; a>=0; a--) {
- vlr= RE_findOrAddVlak(obr, a);
-
- /* test if rendering as a quad or triangle, skip wire */
- if ((vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
-
- if (vlr->v4) {
-
- vlr1= RE_vlakren_copy(obr, vlr);
- vlr1->flag |= R_FACE_SPLIT;
-
- if ( dir==2 ) vlr->flag |= R_DIVIDE_24;
- else vlr->flag &= ~R_DIVIDE_24;
-
- /* new vertex pointers */
- if (vlr->flag & R_DIVIDE_24) {
- vlr1->v1= vlr->v2;
- vlr1->v2= vlr->v3;
- vlr1->v3= vlr->v4;
-
- vlr->v3 = vlr->v4;
-
- vlr1->flag |= R_DIVIDE_24;
- }
- else {
- vlr1->v1= vlr->v1;
- vlr1->v2= vlr->v3;
- vlr1->v3= vlr->v4;
-
- vlr1->flag &= ~R_DIVIDE_24;
- }
- vlr->v4 = vlr1->v4 = NULL;
-
-#ifdef WITH_FREESTYLE
- /* Freestyle edge marks */
- if (vlr->flag & R_DIVIDE_24) {
- vlr1->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0);
- vlr->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
- }
- else {
- vlr1->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
- vlr->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0);
- }
-#endif
-
- /* new normals */
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
- }
- /* clear the flag when not divided */
- else vlr->flag &= ~R_DIVIDE_24;
- }
- }
-}
-
-static void check_non_flat_quads(ObjectRen *obr)
-{
- VlakRen *vlr, *vlr1;
- VertRen *v1, *v2, *v3, *v4;
- float nor[3], xn, flen;
- int a;
-
- for (a=obr->totvlak-1; a>=0; a--) {
- vlr= RE_findOrAddVlak(obr, a);
-
- /* test if rendering as a quad or triangle, skip wire */
- if (vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
-
- /* check if quad is actually triangle */
- v1= vlr->v1;
- v2= vlr->v2;
- v3= vlr->v3;
- v4= vlr->v4;
- sub_v3_v3v3(nor, v1->co, v2->co);
- if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
- vlr->v1= v2;
- vlr->v2= v3;
- vlr->v3= v4;
- vlr->v4= NULL;
- vlr->flag |= (R_DIVIDE_24 | R_FACE_SPLIT);
- }
- else {
- sub_v3_v3v3(nor, v2->co, v3->co);
- if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
- vlr->v2= v3;
- vlr->v3= v4;
- vlr->v4= NULL;
- vlr->flag |= R_FACE_SPLIT;
- }
- else {
- sub_v3_v3v3(nor, v3->co, v4->co);
- if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
- vlr->v4= NULL;
- }
- else {
- sub_v3_v3v3(nor, v4->co, v1->co);
- if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
- vlr->v4= NULL;
- }
- }
- }
- }
-
- if (vlr->v4) {
-
- /* Face is divided along edge with the least gradient */
- /* Flagged with R_DIVIDE_24 if divide is from vert 2 to 4 */
- /* 4---3 4---3 */
- /* |\ 1| or |1 /| */
- /* |0\ | |/ 0| */
- /* 1---2 1---2 0 = orig face, 1 = new face */
-
- /* render normals are inverted in render! we calculate normal of single tria here */
- flen= normal_tri_v3(nor, vlr->v4->co, vlr->v3->co, vlr->v1->co);
- if (flen==0.0f) normal_tri_v3(nor, vlr->v4->co, vlr->v2->co, vlr->v1->co);
-
- xn = dot_v3v3(nor, vlr->n);
-
- if (ABS(xn) < 0.999995f ) { /* checked on noisy fractal grid */
-
- float d1, d2;
-
- vlr1= RE_vlakren_copy(obr, vlr);
- vlr1->flag |= R_FACE_SPLIT;
-
- /* split direction based on vnorms */
- normal_tri_v3(nor, vlr->v1->co, vlr->v2->co, vlr->v3->co);
- d1 = dot_v3v3(nor, vlr->v1->n);
-
- normal_tri_v3(nor, vlr->v2->co, vlr->v3->co, vlr->v4->co);
- d2 = dot_v3v3(nor, vlr->v2->n);
-
- if (fabsf(d1) < fabsf(d2) ) vlr->flag |= R_DIVIDE_24;
- else vlr->flag &= ~R_DIVIDE_24;
-
- /* new vertex pointers */
- if (vlr->flag & R_DIVIDE_24) {
- vlr1->v1= vlr->v2;
- vlr1->v2= vlr->v3;
- vlr1->v3= vlr->v4;
-
- vlr->v3 = vlr->v4;
-
- vlr1->flag |= R_DIVIDE_24;
- }
- else {
- vlr1->v1= vlr->v1;
- vlr1->v2= vlr->v3;
- vlr1->v3= vlr->v4;
-
- vlr1->flag &= ~R_DIVIDE_24;
- }
- vlr->v4 = vlr1->v4 = NULL;
-
- /* new normals */
- normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
- normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
-
-#ifdef WITH_FREESTYLE
- /* Freestyle edge marks */
- if (vlr->flag & R_DIVIDE_24) {
- vlr1->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0);
- vlr->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
- }
- else {
- vlr1->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
- vlr->freestyle_edge_mark=
- ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
- ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0);
- }
-#endif
- }
- /* clear the flag when not divided */
- else vlr->flag &= ~R_DIVIDE_24;
- }
- }
- }
-}
-
-static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- VertRen *ver= NULL;
- StrandRen *strand= NULL;
- StrandBound *sbound= NULL;
- float min[3], max[3], smin[3], smax[3];
- int a, b;
-
- if (obr->totvert || obr->totvlak || obr->tothalo || obr->totstrand) {
- /* the exception below is because displace code now is in init_render_mesh call,
- * I will look at means to have autosmooth enabled for all object types
- * and have it as general postprocess, like displace */
- if (ob->type!=OB_MESH && test_for_displace(re, ob))
- displace(re, obr);
-
- if (!timeoffset) {
- /* phong normal interpolation can cause error in tracing
- * (terminator problem) */
- ob->smoothresh= 0.0;
- if ((re->r.mode & R_RAYTRACE) && (re->r.mode & R_SHADOW))
- set_phong_threshold(obr);
-
- if (re->flag & R_BAKING && re->r.bake_quad_split != 0) {
- /* Baking lets us define a quad split order */
- split_quads(obr, re->r.bake_quad_split);
- }
- else if (BKE_object_is_animated(re->scene, ob))
- split_quads(obr, 1);
- else {
- if ((re->r.mode & R_SIMPLIFY && re->r.simplify_flag & R_SIMPLE_NO_TRIANGULATE) == 0)
- check_non_flat_quads(obr);
- }
-
- set_fullsample_trace_flag(re, obr);
-
- /* compute bounding boxes for clipping */
- INIT_MINMAX(min, max);
- for (a=0; a<obr->totvert; a++) {
- if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
- else ver++;
-
- minmax_v3v3_v3(min, max, ver->co);
- }
-
- if (obr->strandbuf) {
- float width;
-
- /* compute average bounding box of strandpoint itself (width) */
- if (obr->strandbuf->flag & R_STRAND_B_UNITS)
- obr->strandbuf->maxwidth = max_ff(obr->strandbuf->ma->strand_sta, obr->strandbuf->ma->strand_end);
- else
- obr->strandbuf->maxwidth= 0.0f;
-
- width= obr->strandbuf->maxwidth;
- sbound= obr->strandbuf->bound;
- for (b=0; b<obr->strandbuf->totbound; b++, sbound++) {
-
- INIT_MINMAX(smin, smax);
-
- for (a=sbound->start; a<sbound->end; a++) {
- strand= RE_findOrAddStrand(obr, a);
- strand_minmax(strand, smin, smax, width);
- }
-
- copy_v3_v3(sbound->boundbox[0], smin);
- copy_v3_v3(sbound->boundbox[1], smax);
-
- minmax_v3v3_v3(min, max, smin);
- minmax_v3v3_v3(min, max, smax);
- }
- }
-
- copy_v3_v3(obr->boundbox[0], min);
- copy_v3_v3(obr->boundbox[1], max);
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* Database */
-/* ------------------------------------------------------------------------- */
-
-static int render_object_type(short type)
-{
- return OB_TYPE_SUPPORT_MATERIAL(type);
-}
-
-static void find_dupli_instances(Render *re, ObjectRen *obr, DupliObject *dob)
-{
- ObjectInstanceRen *obi;
- float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3];
- int first = 1;
-
- mul_m4_m4m4(obmat, re->viewmat, obr->obmat);
- invert_m4_m4(imat, obmat);
-
- /* for objects instanced by dupliverts/faces/particles, we go over the
- * list of instances to find ones that instance obr, and setup their
- * matrices and obr pointer */
- for (obi=re->instancetable.last; obi; obi=obi->prev) {
- if (!obi->obr && obi->ob == obr->ob && obi->psysindex == obr->psysindex) {
- obi->obr= obr;
-
- /* compute difference between object matrix and
- * object matrix with dupli transform, in viewspace */
- copy_m4_m4(obimat, obi->mat);
- mul_m4_m4m4(obi->mat, obimat, imat);
-
- copy_m3_m4(nmat, obi->mat);
- invert_m3_m3(obi->nmat, nmat);
- transpose_m3(obi->nmat);
-
- if (dob) {
- copy_v3_v3(obi->dupliorco, dob->orco);
- obi->dupliuv[0]= dob->uv[0];
- obi->dupliuv[1]= dob->uv[1];
- }
-
- if (!first) {
- re->totvert += obr->totvert;
- re->totvlak += obr->totvlak;
- re->tothalo += obr->tothalo;
- re->totstrand += obr->totstrand;
- }
- else
- first= 0;
- }
- }
-}
-
-static void assign_dupligroup_dupli(Render *re, ObjectInstanceRen *obi, ObjectRen *obr, DupliObject *dob)
-{
- float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3];
-
- mul_m4_m4m4(obmat, re->viewmat, obr->obmat);
- invert_m4_m4(imat, obmat);
-
- obi->obr= obr;
-
- /* compute difference between object matrix and
- * object matrix with dupli transform, in viewspace */
- copy_m4_m4(obimat, obi->mat);
- mul_m4_m4m4(obi->mat, obimat, imat);
-
- copy_m3_m4(nmat, obi->mat);
- invert_m3_m3(obi->nmat, nmat);
- transpose_m3(obi->nmat);
-
- if (dob) {
- copy_v3_v3(obi->dupliorco, dob->orco);
- obi->dupliuv[0]= dob->uv[0];
- obi->dupliuv[1]= dob->uv[1];
- }
-
- re->totvert += obr->totvert;
- re->totvlak += obr->totvlak;
- re->tothalo += obr->tothalo;
- re->totstrand += obr->totstrand;
-}
-
-static ObjectRen *find_dupligroup_dupli(Render *re, Object *ob, int psysindex)
-{
- ObjectRen *obr;
-
- /* if the object is itself instanced, we don't want to create an instance
- * for it */
- if (ob->transflag & OB_RENDER_DUPLI)
- return NULL;
-
- /* try to find an object that was already created so we can reuse it
- * and save memory */
- for (obr=re->objecttable.first; obr; obr=obr->next)
- if (obr->ob == ob && obr->psysindex == psysindex && (obr->flag & R_INSTANCEABLE))
- return obr;
-
- return NULL;
-}
-
-static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *dob, float omat[4][4])
-{
- /* For duplis we need to have a matrix that transform the coordinate back
- * to it's original position, without the dupli transforms. We also check
- * the matrix is actually needed, to save memory on lots of dupliverts for
- * example */
- static Object *lastob= NULL;
- static int needtexmat= 0;
-
- /* init */
- if (!re) {
- lastob= NULL;
- needtexmat= 0;
- return;
- }
-
- /* check if we actually need it */
- if (lastob != dob->ob) {
- Material ***material;
- short a, *totmaterial;
-
- lastob= dob->ob;
- needtexmat= 0;
-
- totmaterial= give_totcolp(dob->ob);
- material= give_matarar(dob->ob);
-
- if (totmaterial && material)
- for (a= 0; a<*totmaterial; a++)
- if ((*material)[a] && (*material)[a]->texco & TEXCO_OBJECT)
- needtexmat= 1;
- }
-
- if (needtexmat) {
- float imat[4][4];
-
- obi->duplitexmat= BLI_memarena_alloc(re->memArena, sizeof(float)*4*4);
- invert_m4_m4(imat, dob->mat);
- mul_m4_series(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv);
- }
-
- copy_v3_v3(obi->dupliorco, dob->orco);
- copy_v2_v2(obi->dupliuv, dob->uv);
-}
-
-static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
-{
- Object *ob= obr->ob;
- ParticleSystem *psys;
- int i;
-
- if (obr->psysindex) {
- if ((!obr->prev || obr->prev->ob != ob || (obr->prev->flag & R_INSTANCEABLE)==0) && ob->type==OB_MESH) {
- /* the emitter mesh wasn't rendered so the modifier stack wasn't
- * evaluated with render settings */
- DerivedMesh *dm;
- const CustomDataMask mask = CD_MASK_RENDER_INTERNAL;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- dm = mesh_create_derived_view(re->scene, ob, mask);
- else
- dm = mesh_create_derived_render(re->scene, ob, mask);
- dm->release(dm);
- }
-
- for (psys=ob->particlesystem.first, i=0; i<obr->psysindex-1; i++)
- psys= psys->next;
-
- render_new_particle_system(re, obr, psys, timeoffset);
- }
- else {
- if (ELEM(ob->type, OB_FONT, OB_CURVE))
- init_render_curve(re, obr, timeoffset);
- else if (ob->type==OB_SURF)
- init_render_surf(re, obr, timeoffset);
- else if (ob->type==OB_MESH)
- init_render_mesh(re, obr, timeoffset);
- else if (ob->type==OB_MBALL)
- init_render_mball(re, obr);
- }
-
- finalize_render_object(re, obr, timeoffset);
-
- re->totvert += obr->totvert;
- re->totvlak += obr->totvlak;
- re->tothalo += obr->tothalo;
- re->totstrand += obr->totstrand;
-}
-
-static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset)
-{
- ObjectRen *obr;
- ObjectInstanceRen *obi;
- ParticleSystem *psys;
- int show_emitter, allow_render= 1, index, psysindex, i;
-
- index= (dob)? dob->persistent_id[0]: 0;
-
- /* It seems that we may generate psys->renderdata recursively in some nasty intricated cases of
- * several levels of bupliobject (see T51524).
- * For now, basic rule is, do not restore psys if it was already in 'render state'.
- * Another, more robust solution could be to add some reference counting to that renderdata... */
- bool psys_has_renderdata = false;
-
- /* the emitter has to be processed first (render levels of modifiers) */
- /* so here we only check if the emitter should be rendered */
- if (ob->particlesystem.first) {
- show_emitter= 0;
- for (psys=ob->particlesystem.first; psys; psys=psys->next) {
- show_emitter += psys->part->draw & PART_DRAW_EMITTER;
- if (!(re->r.scemode & R_VIEWPORT_PREVIEW)) {
- psys_has_renderdata |= (psys->renderdata != NULL);
- psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
- }
- }
-
- /* if no psys has "show emitter" selected don't render emitter */
- if (show_emitter == 0)
- allow_render= 0;
- }
-
- /* one render object for the data itself */
- if (allow_render) {
- obr= RE_addRenderObject(re, ob, par, index, 0, ob->lay);
- if ((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) {
- obr->flag |= R_INSTANCEABLE;
- copy_m4_m4(obr->obmat, ob->obmat);
- }
- init_render_object_data(re, obr, timeoffset);
-
- /* only add instance for objects that have not been used for dupli */
- if (!(ob->transflag & OB_RENDER_DUPLI)) {
- obi = RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay, dob);
- if (dob) set_dupli_tex_mat(re, obi, dob, omat);
- }
- else
- find_dupli_instances(re, obr, dob);
-
- for (i=1; i<=ob->totcol; i++) {
- Material* ma = give_render_material(re, ob, i);
- if (ma && ma->material_type == MA_TYPE_VOLUME)
- add_volume(re, obr, ma);
- }
- }
-
- /* and one render object per particle system */
- if (ob->particlesystem.first) {
- psysindex= 1;
- for (psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) {
- if (!psys_check_enabled(ob, psys, G.is_rendering))
- continue;
-
- obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay);
- if ((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) {
- obr->flag |= R_INSTANCEABLE;
- copy_m4_m4(obr->obmat, ob->obmat);
- }
- if (dob)
- psys->flag |= PSYS_USE_IMAT;
- init_render_object_data(re, obr, timeoffset);
- if (!(re->r.scemode & R_VIEWPORT_PREVIEW) && !psys_has_renderdata) {
- psys_render_restore(ob, psys);
- }
- psys->flag &= ~PSYS_USE_IMAT;
-
- /* only add instance for objects that have not been used for dupli */
- if (!(ob->transflag & OB_RENDER_DUPLI)) {
- obi = RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay, dob);
- if (dob) set_dupli_tex_mat(re, obi, dob, omat);
- }
- else
- find_dupli_instances(re, obr, dob);
- }
- }
-}
-
-/* par = pointer to duplicator parent, needed for object lookup table */
-/* index = when duplicater copies same object (particle), the counter */
-static void init_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset)
-{
- static double lasttime= 0.0;
- double time;
- float mat[4][4];
-
- if (ob->type==OB_LAMP)
- add_render_lamp(re, ob);
- else if (render_object_type(ob->type))
- add_render_object(re, ob, par, dob, omat, timeoffset);
- else {
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat, mat);
- }
-
- time= PIL_check_seconds_timer();
- if (time - lasttime > 1.0) {
- lasttime= time;
- /* clumsy copying still */
- re->i.totvert= re->totvert;
- re->i.totface= re->totvlak;
- re->i.totstrand= re->totstrand;
- re->i.tothalo= re->tothalo;
- re->i.totlamp= re->totlamp;
- re->stats_draw(re->sdh, &re->i);
- }
-
- ob->flag |= OB_DONE;
-}
-
-void RE_Database_Free(Render *re)
-{
- LampRen *lar;
-
- /* will crash if we try to free empty database */
- if (!re->i.convertdone)
- return;
-
- /* statistics for debugging render memory usage */
- if ((G.debug & G_DEBUG) && (G.is_rendering)) {
- if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
- BKE_image_print_memlist(re->main);
- MEM_printmemlist_stats();
- }
- }
-
- /* FREE */
-
- for (lar= re->lampren.first; lar; lar= lar->next) {
- freeshadowbuf(lar);
- if (lar->jitter) MEM_freeN(lar->jitter);
- if (lar->shadsamp) MEM_freeN(lar->shadsamp);
- if (lar->sunsky) MEM_freeN(lar->sunsky);
- curvemapping_free(lar->curfalloff);
- }
-
- free_volume_precache(re);
-
- BLI_freelistN(&re->lampren);
- BLI_freelistN(&re->lights);
-
- free_renderdata_tables(re);
-
- /* free orco */
- free_mesh_orco_hash(re);
-
- if (re->main) {
- end_render_materials(re->main);
- end_render_textures(re);
- free_pointdensities(re);
- }
-
- free_camera_inside_volumes(re);
-
- if (re->wrld.aosphere) {
- MEM_freeN(re->wrld.aosphere);
- re->wrld.aosphere= NULL;
- if (re->scene && re->scene->world)
- re->scene->world->aosphere= NULL;
- }
- if (re->wrld.aotables) {
- MEM_freeN(re->wrld.aotables);
- re->wrld.aotables= NULL;
- if (re->scene && re->scene->world)
- re->scene->world->aotables= NULL;
- }
- if (re->r.mode & R_RAYTRACE)
- free_render_qmcsampler(re);
-
- if (re->r.mode & R_RAYTRACE) freeraytree(re);
-
- free_sss(re);
- free_occ(re);
- free_strand_surface(re);
-
- re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
- re->i.convertdone = false;
-
- re->bakebuf= NULL;
-
- if (re->scene)
- if (re->scene->r.scemode & R_FREE_IMAGE)
- if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0)
- BKE_image_free_all_textures(re->main);
-
- if (re->memArena) {
- BLI_memarena_free(re->memArena);
- re->memArena = NULL;
- }
-}
-
-static int allow_render_object(Render *re, Object *ob, int nolamps, int onlyselected, Object *actob)
-{
- if (is_object_hidden(re, ob))
- return 0;
-
- /* Only handle dupli-hiding here if there is no particle systems. Else, let those handle show/noshow. */
- if (!ob->particlesystem.first) {
- if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) {
- return 0;
- }
- }
-
- /* don't add non-basic meta objects, ends up having renderobjects with no geometry */
- if (ob->type == OB_MBALL && ob != BKE_mball_basis_find(re->main, re->eval_ctx, re->scene, ob))
- return 0;
-
- if (nolamps && (ob->type==OB_LAMP))
- return 0;
-
- if (onlyselected && (ob!=actob && !(ob->flag & SELECT)))
- return 0;
-
- return 1;
-}
-
-static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Object *obd)
-{
- ParticleSystem *psys;
- Material *ma;
- short a, *totmaterial;
-
- /* don't allow objects with halos. we need to have
- * all halo's to sort them globally in advance */
- totmaterial= give_totcolp(obd);
-
- if (totmaterial) {
- for (a= 0; a<*totmaterial; a++) {
- ma= give_current_material(obd, a + 1);
- if (ma && (ma->material_type == MA_TYPE_HALO))
- return 0;
- }
- }
-
- for (psys=obd->particlesystem.first; psys; psys=psys->next)
- if (!ELEM(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR))
- return 0;
-
- /* don't allow lamp, animated duplis, or radio render */
- return (render_object_type(obd->type) &&
- (!(dob->type == OB_DUPLIGROUP) || !dob->animated));
-}
-
-static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, int level, int enable)
-{
- /* ugly function, but we need to set particle systems to their render
- * settings before calling object_duplilist, to get render level duplis */
- Group *group;
- GroupObject *go;
- ParticleSystem *psys;
- DerivedMesh *dm;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- return;
-
- if (level >= MAX_DUPLI_RECUR)
- return;
-
- if (ob->transflag & OB_DUPLIPARTS) {
- for (psys=ob->particlesystem.first; psys; psys=psys->next) {
- if (ELEM(psys->part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
- if (enable)
- psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
- else
- psys_render_restore(ob, psys);
- }
- }
-
- if (enable) {
- /* this is to make sure we get render level duplis in groups:
- * the derivedmesh must be created before init_render_mesh,
- * since object_duplilist does dupliparticles before that */
- dm = mesh_create_derived_render(re->scene, ob, CD_MASK_RENDER_INTERNAL);
- dm->release(dm);
-
- for (psys=ob->particlesystem.first; psys; psys=psys->next)
- psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
- }
- }
-
- if (ob->dup_group==NULL) return;
- group= ob->dup_group;
-
- for (go= group->gobject.first; go; go= go->next)
- dupli_render_particle_set(re, go->ob, timeoffset, level+1, enable);
-}
-
-static int get_vector_renderlayers(Scene *sce)
-{
- SceneRenderLayer *srl;
- unsigned int lay= 0;
-
- for (srl= sce->r.layers.first; srl; srl= srl->next)
- if (srl->passflag & SCE_PASS_VECTOR)
- lay |= srl->lay;
-
- return lay;
-}
-
-static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, int onlyselected, Object *actob, int timeoffset, int level)
-{
- GroupObject *go;
- Object *ob;
-
- /* simple preventing of too deep nested groups */
- if (level>MAX_DUPLI_RECUR) return;
-
- /* recursively go into dupligroups to find objects with OB_RENDER_DUPLI
- * that were not created yet */
- for (go= group->gobject.first; go; go= go->next) {
- ob= go->ob;
-
- if (ob->flag & OB_DONE) {
- if (ob->transflag & OB_RENDER_DUPLI) {
- if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
- init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
- ob->transflag &= ~OB_RENDER_DUPLI;
-
- if (ob->dup_group)
- add_group_render_dupli_obs(re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, level+1);
- }
- }
- }
- }
-}
-
-static void database_init_objects(Render *re, unsigned int renderlay, int nolamps, int onlyselected, Object *actob, int timeoffset)
-{
- Base *base;
- Object *ob;
- Group *group;
- ObjectInstanceRen *obi;
- Scene *sce_iter;
- int lay, vectorlay;
-
- /* for duplis we need the Object texture mapping to work as if
- * untransformed, set_dupli_tex_mat sets the matrix to allow that
- * NULL is just for init */
- set_dupli_tex_mat(NULL, NULL, NULL, NULL);
-
- /* loop over all objects rather then using SETLOOPER because we may
- * reference an mtex-mapped object which isn't rendered or is an
- * empty in a dupli group. We could scan all render material/lamp/world
- * mtex's for mapto objects but its easier just to set the
- * 'imat' / 'imat_ren' on all and unlikely to be a performance hit
- * See bug: [#28744] - campbell */
- for (ob= re->main->object.first; ob; ob= ob->id.next) {
- float mat[4][4];
-
- /* imat objects has to be done here, since displace can have texture using Object map-input */
- mul_m4_m4m4(mat, re->viewmat, ob->obmat);
- invert_m4_m4(ob->imat_ren, mat);
- copy_m4_m4(ob->imat, ob->imat_ren);
- /* each object should only be rendered once */
- ob->flag &= ~OB_DONE;
- ob->transflag &= ~OB_RENDER_DUPLI;
- }
-
- for (SETLOOPER(re->scene, sce_iter, base)) {
- ob= base->object;
-
- /* in the prev/next pass for making speed vectors, avoid creating
- * objects that are not on a renderlayer with a vector pass, can
- * save a lot of time in complex scenes */
- vectorlay= get_vector_renderlayers(re->scene);
- lay= (timeoffset)? renderlay & vectorlay: renderlay;
-
- /* if the object has been restricted from rendering in the outliner, ignore it */
- if (is_object_restricted(re, ob)) continue;
-
- /* OB_DONE means the object itself got duplicated, so was already converted */
- if (ob->flag & OB_DONE) {
- /* OB_RENDER_DUPLI means instances for it were already created, now
- * it still needs to create the ObjectRen containing the data */
- if (ob->transflag & OB_RENDER_DUPLI) {
- if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
- init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
- ob->transflag &= ~OB_RENDER_DUPLI;
- }
- }
- }
- else if ((base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->lay)) ) {
- if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) {
- DupliObject *dob;
- ListBase *duplilist;
- DupliApplyData *duplilist_apply_data = NULL;
- int i;
-
- /* create list of duplis generated by this object, particle
- * system need to have render settings set for dupli particles */
- dupli_render_particle_set(re, ob, timeoffset, 0, 1);
- duplilist = object_duplilist(re->main, re->eval_ctx, re->scene, ob);
- duplilist_apply_data = duplilist_apply(ob, NULL, duplilist);
- /* postpone 'dupli_render_particle_set', since RE_addRenderInstance reads
- * index values from 'dob->persistent_id[0]', referencing 'psys->child' which
- * may be smaller once the particle system is restored, see: T45563. */
-
- for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
- DupliExtraData *dob_extra = &duplilist_apply_data->extra[i];
- Object *obd= dob->ob;
-
- copy_m4_m4(obd->obmat, dob->mat);
-
- /* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */
- if (!(obd->transflag & OB_RENDER_DUPLI) && dob->no_draw)
- continue;
-
- if (is_object_hidden(re, obd))
- continue;
-
- if (obd->type==OB_MBALL)
- continue;
-
- if (!allow_render_object(re, obd, nolamps, onlyselected, actob))
- continue;
-
- if (allow_render_dupli_instance(re, dob, obd)) {
- ParticleSystem *psys;
- ObjectRen *obr = NULL;
- int psysindex;
- float mat[4][4];
-
- obi=NULL;
-
- /* instances instead of the actual object are added in two cases, either
- * this is a duplivert/face/particle, or it is a non-animated object in
- * a dupligroup that has already been created before */
- if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, 0))) {
- mul_m4_m4m4(mat, re->viewmat, dob->mat);
- /* ob = particle system, use that layer */
- obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay, dob);
-
- /* fill in instance variables for texturing */
- set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
- if (dob->type != OB_DUPLIGROUP) {
- copy_v3_v3(obi->dupliorco, dob->orco);
- obi->dupliuv[0]= dob->uv[0];
- obi->dupliuv[1]= dob->uv[1];
- }
- else {
- /* for the second case, setup instance to point to the already
- * created object, and possibly setup instances if this object
- * itself was duplicated. for the first case find_dupli_instances
- * will be called later. */
- assign_dupligroup_dupli(re, obi, obr, dob);
- if (obd->transflag & OB_RENDER_DUPLI)
- find_dupli_instances(re, obr, dob);
- }
- }
-
- /* same logic for particles, each particle system has it's own object, so
- * need to go over them separately */
- psysindex= 1;
- for (psys=obd->particlesystem.first; psys; psys=psys->next) {
- if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) {
- if (obi == NULL)
- mul_m4_m4m4(mat, re->viewmat, dob->mat);
- obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay, dob);
-
- set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
- if (dob->type != OB_DUPLIGROUP) {
- copy_v3_v3(obi->dupliorco, dob->orco);
- obi->dupliuv[0]= dob->uv[0];
- obi->dupliuv[1]= dob->uv[1];
- }
- else {
- assign_dupligroup_dupli(re, obi, obr, dob);
- if (obd->transflag & OB_RENDER_DUPLI)
- find_dupli_instances(re, obr, dob);
- }
- }
- }
-
- if (obi==NULL)
- /* can't instance, just create the object */
- init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
-
- if (dob->type != OB_DUPLIGROUP) {
- obd->flag |= OB_DONE;
- obd->transflag |= OB_RENDER_DUPLI;
- }
- }
- else
- init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
-
- if (re->test_break(re->tbh)) break;
- }
-
- /* restore particle system */
- dupli_render_particle_set(re, ob, timeoffset, 0, false);
-
- if (duplilist_apply_data) {
- duplilist_restore(duplilist, duplilist_apply_data);
- duplilist_free_apply_data(duplilist_apply_data);
- }
- free_object_duplilist(duplilist);
-
- if (allow_render_object(re, ob, nolamps, onlyselected, actob))
- init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
- }
- else if (allow_render_object(re, ob, nolamps, onlyselected, actob))
- init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
- }
-
- if (re->test_break(re->tbh)) break;
- }
-
- /* objects in groups with OB_RENDER_DUPLI set still need to be created,
- * since they may not be part of the scene */
- for (group= re->main->group.first; group; group=group->id.next)
- add_group_render_dupli_obs(re, group, nolamps, onlyselected, actob, timeoffset, 0);
-
- if (!re->test_break(re->tbh))
- RE_makeRenderInstances(re);
-}
-
-/* used to be 'rotate scene' */
-void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int lay, int use_camera_view)
-{
- Scene *sce;
- Object *camera;
- float mat[4][4];
- float amb[3];
-
- re->main= bmain;
- re->scene= scene;
- re->lay= lay;
-
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
-
- /* scene needs to be set to get camera */
- camera= RE_GetCamera(re);
-
- /* per second, per object, stats print this */
- re->i.infostr= "Preparing Scene data";
- re->i.cfra= scene->r.cfra;
- BLI_strncpy(re->i.scene_name, scene->id.name + 2, sizeof(re->i.scene_name));
-
- /* XXX add test if dbase was filled already? */
-
- re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "render db arena");
- re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
- re->lights.first= re->lights.last= NULL;
- re->lampren.first= re->lampren.last= NULL;
-
- re->i.partsdone = false; /* signal now in use for previewrender */
-
- /* in localview, lamps are using normal layers, objects only local bits */
- if (re->lay & 0xFF000000)
- lay &= 0xFF000000;
-
- /* applies changes fully */
- if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
- BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
- render_update_anim_renderdata(re, &re->scene->r);
- }
-
- /* if no camera, viewmat should have been set! */
- if (use_camera_view && camera) {
- /* called before but need to call again in case of lens animation from the
- * above call to BKE_scene_update_for_newframe, fixes bug. [#22702].
- * following calls don't depend on 'RE_SetCamera' */
- RE_SetCamera(re, camera);
- RE_GetCameraModelMatrix(re, camera, mat);
- invert_m4(mat);
- RE_SetView(re, mat);
-
- /* force correct matrix for scaled cameras */
- DAG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
- }
-
- /* store for incremental render, viewmat rotates dbase */
- copy_m4_m4(re->viewmat_orig, re->viewmat);
-
- init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
- if (re->r.mode & R_RAYTRACE) {
- init_render_qmcsampler(re);
-
- if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
- if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(re, &re->wrld);
- }
-
- /* still bad... doing all */
- init_render_textures(re);
- copy_v3_v3(amb, &re->wrld.ambr);
- init_render_materials(re->main, re->r.mode, amb, (re->r.scemode & R_BUTS_PREVIEW) == 0);
- set_node_shader_lamp_loop(shade_material_loop);
-
- /* MAKE RENDER DATA */
- database_init_objects(re, lay, 0, 0, NULL, 0);
-
- if (!re->test_break(re->tbh)) {
- set_material_lightgroups(re);
- for (sce= re->scene; sce; sce= sce->set)
- set_renderlayer_lightgroups(re, sce);
-
- /* for now some clumsy copying still */
- re->i.totvert= re->totvert;
- re->i.totface= re->totvlak;
- re->i.totstrand= re->totstrand;
- re->i.tothalo= re->tothalo;
- re->i.totlamp= re->totlamp;
- re->stats_draw(re->sdh, &re->i);
- }
-}
-
-void RE_Database_Preprocess(Render *re)
-{
- if (!re->test_break(re->tbh)) {
- int tothalo;
-
- tothalo= re->tothalo;
- sort_halos(re, tothalo);
-
- init_camera_inside_volumes(re);
-
- re->i.infostr = IFACE_("Creating Shadowbuffers");
- re->stats_draw(re->sdh, &re->i);
-
- /* SHADOW BUFFER */
- threaded_makeshadowbufs(re);
-
- /* old code checked for internal render (aka not yafray) */
- {
- /* raytree */
- if (!re->test_break(re->tbh)) {
- if (re->r.mode & R_RAYTRACE) {
- makeraytree(re);
- }
- }
- /* ENVIRONMENT MAPS */
- if (!re->test_break(re->tbh))
- make_envmaps(re);
-
- /* point density texture */
- if (!re->test_break(re->tbh))
- make_pointdensities(re);
- /* voxel data texture */
- if (!re->test_break(re->tbh))
- make_voxeldata(re);
- }
-
- if (!re->test_break(re->tbh))
- project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
-
- /* Occlusion */
- if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh))
- if (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
- if (re->r.mode & R_SHADOW)
- make_occ_tree(re);
-
- /* SSS */
- if ((re->r.mode & R_SSS) && !re->test_break(re->tbh))
- make_sss_tree(re);
-
- if (!re->test_break(re->tbh))
- if (re->r.mode & R_RAYTRACE)
- volume_precache(re);
- }
-
- re->i.convertdone = true;
-
- if (re->test_break(re->tbh))
- RE_Database_Free(re);
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-}
-
-/* exported call to recalculate hoco for vertices, when winmat changed */
-void RE_DataBase_ApplyWindow(Render *re)
-{
- project_renderdata(re, projectverto, 0, 0, 0);
-}
-
-/* exported call to rotate render data again, when viewmat changed */
-void RE_DataBase_IncrementalView(Render *re, float viewmat[4][4], int restore)
-{
- float oldviewinv[4][4], tmat[4][4];
-
- invert_m4_m4(oldviewinv, re->viewmat_orig);
-
- /* we have to correct for the already rotated vertexcoords */
- mul_m4_m4m4(tmat, viewmat, oldviewinv);
-
- copy_m4_m4(re->viewmat, viewmat);
- invert_m4_m4(re->viewinv, re->viewmat);
-
- init_camera_inside_volumes(re);
-
- env_rotate_scene(re, tmat, !restore);
-
- /* SSS points distribution depends on view */
- if ((re->r.mode & R_SSS) && !re->test_break(re->tbh))
- make_sss_tree(re);
-}
-
-
-void RE_DataBase_GetView(Render *re, float mat[4][4])
-{
- copy_m4_m4(mat, re->viewmat);
-}
-
-/* ------------------------------------------------------------------------- */
-/* Speed Vectors */
-/* ------------------------------------------------------------------------- */
-
-static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int lay, int timeoffset)
-{
- Object *camera= RE_GetCamera(re);
- float mat[4][4];
-
- re->scene= scene;
- re->lay= lay;
-
- /* XXX add test if dbase was filled already? */
-
- re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vector render db arena");
- re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
- re->i.totface=re->i.totvert=re->i.totstrand=re->i.totlamp=re->i.tothalo= 0;
- re->lights.first= re->lights.last= NULL;
-
- /* in localview, lamps are using normal layers, objects only local bits */
- if (re->lay & 0xFF000000)
- lay &= 0xFF000000;
-
- /* applies changes fully */
- scene->r.cfra += timeoffset;
- BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
-
- /* if no camera, viewmat should have been set! */
- if (camera) {
- RE_GetCameraModelMatrix(re, camera, mat);
- normalize_m4(mat);
- invert_m4(mat);
- RE_SetView(re, mat);
- }
-
- /* MAKE RENDER DATA */
- database_init_objects(re, lay, 0, 0, NULL, timeoffset);
-
- if (!re->test_break(re->tbh))
- project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
-
- /* do this in end, particles for example need cfra */
- scene->r.cfra -= timeoffset;
-}
-
-/* choose to use static, to prevent giving too many args to this call */
-static void speedvector_project(Render *re, float zco[2], const float co[3], const float ho[4])
-{
- static float pixelphix=0.0f, pixelphiy=0.0f, zmulx=0.0f, zmuly=0.0f;
- static int pano= 0;
- float div;
-
- /* initialize */
- if (re) {
- pano= re->r.mode & R_PANORAMA;
-
- /* precalculate amount of radians 1 pixel rotates */
- if (pano) {
- /* size of 1 pixel mapped to viewplane coords */
- float psize;
-
- psize = BLI_rctf_size_x(&re->viewplane) / (float)re->winx;
- /* x angle of a pixel */
- pixelphix = atan(psize / re->clipsta);
-
- psize = BLI_rctf_size_y(&re->viewplane) / (float)re->winy;
- /* y angle of a pixel */
- pixelphiy = atan(psize / re->clipsta);
- }
- zmulx= re->winx/2;
- zmuly= re->winy/2;
-
- return;
- }
-
- /* now map hocos to screenspace, uses very primitive clip still */
- if (ho[3]<0.1f) div= 10.0f;
- else div= 1.0f/ho[3];
-
- /* use cylinder projection */
- if (pano) {
- float vec[3], ang;
- /* angle between (0, 0, -1) and (co) */
- copy_v3_v3(vec, co);
-
- ang= saacos(-vec[2]/sqrtf(vec[0]*vec[0] + vec[2]*vec[2]));
- if (vec[0]<0.0f) ang= -ang;
- zco[0]= ang/pixelphix + zmulx;
-
- ang= 0.5f*(float)M_PI - saacos(vec[1] / len_v3(vec));
- zco[1]= ang/pixelphiy + zmuly;
-
- }
- else {
- zco[0]= zmulx*(1.0f+ho[0]*div);
- zco[1]= zmuly*(1.0f+ho[1]*div);
- }
-}
-
-static void calculate_speedvector(const float vectors[2], int step, float winsq, float winroot, const float co[3], const float ho[4], float speed[4])
-{
- float zco[2], len;
-
- speedvector_project(NULL, zco, co, ho);
-
- zco[0]= vectors[0] - zco[0];
- zco[1]= vectors[1] - zco[1];
-
- /* enable nice masks for hardly moving stuff or float inaccuracy */
- if (zco[0]<0.1f && zco[0]>-0.1f && zco[1]<0.1f && zco[1]>-0.1f ) {
- zco[0]= 0.0f;
- zco[1]= 0.0f;
- }
-
- /* maximize speed for image width, otherwise it never looks good */
- len= zco[0]*zco[0] + zco[1]*zco[1];
- if (len > winsq) {
- len= winroot/sqrtf(len);
- zco[0]*= len;
- zco[1]*= len;
- }
-
- /* note; in main vecblur loop speedvec is negated again */
- if (step) {
- speed[2]= -zco[0];
- speed[3]= -zco[1];
- }
- else {
- speed[0]= zco[0];
- speed[1]= zco[1];
- }
-}
-
-static float *calculate_strandsurface_speedvectors(Render *re, ObjectInstanceRen *obi, StrandSurface *mesh)
-{
- if (mesh->co && mesh->prevco && mesh->nextco) {
- float winsq= (float)re->winx*(float)re->winy; /* int's can wrap on large images */
- float winroot= sqrtf(winsq);
- float (*winspeed)[4];
- float ho[4], prevho[4], nextho[4], winmat[4][4], vec[2];
- int a;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, re->winmat, obi->mat);
- else
- copy_m4_m4(winmat, re->winmat);
-
- winspeed= MEM_callocN(sizeof(float)*4*mesh->totvert, "StrandSurfWin");
-
- for (a=0; a<mesh->totvert; a++) {
- projectvert(mesh->co[a], winmat, ho);
-
- projectvert(mesh->prevco[a], winmat, prevho);
- speedvector_project(NULL, vec, mesh->prevco[a], prevho);
- calculate_speedvector(vec, 0, winsq, winroot, mesh->co[a], ho, winspeed[a]);
-
- projectvert(mesh->nextco[a], winmat, nextho);
- speedvector_project(NULL, vec, mesh->nextco[a], nextho);
- calculate_speedvector(vec, 1, winsq, winroot, mesh->co[a], ho, winspeed[a]);
- }
-
- return (float *)winspeed;
- }
-
- return NULL;
-}
-
-static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *vectors, int step)
-{
- ObjectRen *obr= obi->obr;
- VertRen *ver= NULL;
- StrandRen *strand= NULL;
- StrandBuffer *strandbuf;
- StrandSurface *mesh= NULL;
- float *speed, (*winspeed)[4]=NULL, ho[4], winmat[4][4];
- float *co1, *co2, *co3, *co4, w[4];
- float winsq = (float)re->winx * (float)re->winy, winroot = sqrtf(winsq); /* int's can wrap on large images */
- int a, *face, *index;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, re->winmat, obi->mat);
- else
- copy_m4_m4(winmat, re->winmat);
-
- if (obr->vertnodes) {
- for (a=0; a<obr->totvert; a++, vectors+=2) {
- if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
- else ver++;
-
- speed= RE_vertren_get_winspeed(obi, ver, 1);
- projectvert(ver->co, winmat, ho);
- calculate_speedvector(vectors, step, winsq, winroot, ver->co, ho, speed);
- }
- }
-
- if (obr->strandnodes) {
- strandbuf= obr->strandbuf;
- mesh= (strandbuf)? strandbuf->surface: NULL;
-
- /* compute speed vectors at surface vertices */
- if (mesh)
- winspeed= (float(*)[4])calculate_strandsurface_speedvectors(re, obi, mesh);
-
- if (winspeed) {
- for (a=0; a<obr->totstrand; a++, vectors+=2) {
- if ((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
- else strand++;
-
- index= RE_strandren_get_face(obr, strand, 0);
- if (index && *index < mesh->totface) {
- speed= RE_strandren_get_winspeed(obi, strand, 1);
-
- /* interpolate speed vectors from strand surface */
- face= mesh->face[*index];
-
- co1 = mesh->co[face[0]];
- co2 = mesh->co[face[1]];
- co3 = mesh->co[face[2]];
-
- if (face[3]) {
- co4 = mesh->co[face[3]];
- interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
- }
- else {
- interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
- }
-
- zero_v4(speed);
- madd_v4_v4fl(speed, winspeed[face[0]], w[0]);
- madd_v4_v4fl(speed, winspeed[face[1]], w[1]);
- madd_v4_v4fl(speed, winspeed[face[2]], w[2]);
- if (face[3])
- madd_v4_v4fl(speed, winspeed[face[3]], w[3]);
- }
- }
-
- MEM_freeN(winspeed);
- }
- }
-}
-
-static int load_fluidsimspeedvectors(Render *re, ObjectInstanceRen *obi, float *vectors, int step)
-{
- ObjectRen *obr= obi->obr;
- Object *fsob= obr->ob;
- VertRen *ver= NULL;
- float *speed, div, zco[2], avgvel[4] = {0.0, 0.0, 0.0, 0.0};
- float zmulx= re->winx/2, zmuly= re->winy/2, len;
- float winsq = (float)re->winx * (float)re->winy, winroot= sqrtf(winsq); /* int's can wrap on large images */
- int a, j;
- float hoco[4], ho[4], fsvec[4], camco[4];
- float mat[4][4], winmat[4][4];
- float imat[4][4];
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsob, eModifierType_Fluidsim);
- FluidsimSettings *fss;
- FluidVertexVelocity *velarray = NULL;
-
- /* only one step needed */
- if (step) return 1;
-
- if (fluidmd)
- fss = fluidmd->fss;
- else
- return 0;
-
- copy_m4_m4(mat, re->viewmat);
- invert_m4_m4(imat, mat);
-
- /* set first vertex OK */
- if (!fss->meshVelocities) return 0;
-
- if ( obr->totvert != fss->totvert) {
- //fprintf(stderr, "load_fluidsimspeedvectors - modified fluidsim mesh, not using speed vectors (%d,%d)...\n", obr->totvert, fsob->fluidsimSettings->meshSurface->totvert); // DEBUG
- return 0;
- }
-
- velarray = fss->meshVelocities;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, re->winmat, obi->mat);
- else
- copy_m4_m4(winmat, re->winmat);
-
- /* (bad) HACK calculate average velocity */
- /* better solution would be fixing getVelocityAt() in intern/elbeem/intern/solver_util.cpp
- * so that also small drops/little water volumes return a velocity != 0.
- * But I had no luck in fixing that function - DG */
- for (a=0; a<obr->totvert; a++) {
- for (j=0;j<3;j++) avgvel[j] += velarray[a].vel[j];
-
- }
- for (j=0;j<3;j++) avgvel[j] /= (float)(obr->totvert);
-
-
- for (a=0; a<obr->totvert; a++, vectors+=2) {
- if ((a & 255)==0)
- ver= obr->vertnodes[a>>8].vert;
- else
- ver++;
-
- /* get fluid velocity */
- fsvec[3] = 0.0f;
- //fsvec[0] = fsvec[1] = fsvec[2] = fsvec[3] = 0.0; fsvec[2] = 2.0f; // NT fixed test
- for (j=0;j<3;j++) fsvec[j] = velarray[a].vel[j];
-
- /* (bad) HACK insert average velocity if none is there (see previous comment) */
- if ((fsvec[0] == 0.0f) && (fsvec[1] == 0.0f) && (fsvec[2] == 0.0f)) {
- fsvec[0] = avgvel[0];
- fsvec[1] = avgvel[1];
- fsvec[2] = avgvel[2];
- }
-
- /* transform (=rotate) to cam space */
- camco[0] = dot_v3v3(imat[0], fsvec);
- camco[1] = dot_v3v3(imat[1], fsvec);
- camco[2] = dot_v3v3(imat[2], fsvec);
-
- /* get homogeneous coordinates */
- projectvert(camco, winmat, hoco);
- projectvert(ver->co, winmat, ho);
-
- /* now map hocos to screenspace, uses very primitive clip still */
- /* use ho[3] of original vertex, xy component of vel. direction */
- if (ho[3]<0.1f) div= 10.0f;
- else div= 1.0f/ho[3];
- zco[0]= zmulx*hoco[0]*div;
- zco[1]= zmuly*hoco[1]*div;
-
- /* maximize speed as usual */
- len= zco[0]*zco[0] + zco[1]*zco[1];
- if (len > winsq) {
- len= winroot/sqrtf(len);
- zco[0]*= len; zco[1]*= len;
- }
-
- speed= RE_vertren_get_winspeed(obi, ver, 1);
- /* set both to the same value */
- speed[0]= speed[2]= zco[0];
- speed[1]= speed[3]= zco[1];
- //if (a < 20) fprintf(stderr,"speed %d %f,%f | camco %f,%f,%f | hoco %f,%f,%f,%f\n", a, speed[0], speed[1], camco[0],camco[1], camco[2], hoco[0],hoco[1], hoco[2],hoco[3]); // NT DEBUG
- }
-
- return 1;
-}
-
-/* makes copy per object of all vectors */
-/* result should be that we can free entire database */
-static void copy_dbase_object_vectors(Render *re, ListBase *lb)
-{
- ObjectInstanceRen *obi, *obilb;
- ObjectRen *obr;
- VertRen *ver= NULL;
- float *vec, ho[4], winmat[4][4];
- int a, totvector;
-
- for (obi= re->instancetable.first; obi; obi= obi->next) {
- obr= obi->obr;
-
- obilb= MEM_mallocN(sizeof(ObjectInstanceRen), "ObInstanceVector");
- memcpy(obilb, obi, sizeof(ObjectInstanceRen));
- BLI_addtail(lb, obilb);
-
- obilb->totvector= totvector= obr->totvert;
-
- if (totvector > 0) {
- vec= obilb->vectors= MEM_mallocN(2*sizeof(float)*totvector, "vector array");
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, re->winmat, obi->mat);
- else
- copy_m4_m4(winmat, re->winmat);
-
- for (a=0; a<obr->totvert; a++, vec+=2) {
- if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
- else ver++;
-
- projectvert(ver->co, winmat, ho);
- speedvector_project(NULL, vec, ver->co, ho);
- }
- }
- }
-}
-
-static void free_dbase_object_vectors(ListBase *lb)
-{
- ObjectInstanceRen *obi;
-
- for (obi= lb->first; obi; obi= obi->next)
- if (obi->vectors)
- MEM_freeN(obi->vectors);
- BLI_freelistN(lb);
-}
-
-void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned int lay)
-{
- ObjectInstanceRen *obi, *oldobi;
- StrandSurface *mesh;
- ListBase *table;
- ListBase oldtable= {NULL, NULL}, newtable= {NULL, NULL};
- ListBase strandsurface;
- int step;
-
- re->i.infostr = IFACE_("Calculating previous frame vectors");
- re->r.mode |= R_SPEED;
-
- speedvector_project(re, NULL, NULL, NULL); /* initializes projection code */
-
- /* creates entire dbase */
- database_fromscene_vectors(re, sce, lay, -1);
-
- /* copy away vertex info */
- copy_dbase_object_vectors(re, &oldtable);
-
- /* free dbase and make the future one */
- strandsurface= re->strandsurface;
- memset(&re->strandsurface, 0, sizeof(ListBase));
- re->i.convertdone = true;
- RE_Database_Free(re);
- re->strandsurface= strandsurface;
-
- if (!re->test_break(re->tbh)) {
- /* creates entire dbase */
- re->i.infostr = IFACE_("Calculating next frame vectors");
-
- database_fromscene_vectors(re, sce, lay, +1);
- }
- /* copy away vertex info */
- copy_dbase_object_vectors(re, &newtable);
-
- /* free dbase and make the real one */
- strandsurface= re->strandsurface;
- memset(&re->strandsurface, 0, sizeof(ListBase));
- re->i.convertdone = true;
- RE_Database_Free(re);
- re->strandsurface= strandsurface;
-
- if (!re->test_break(re->tbh)) {
- RE_Database_FromScene(re, bmain, sce, lay, 1);
- RE_Database_Preprocess(re);
- }
-
- if (!re->test_break(re->tbh)) {
- int vectorlay= get_vector_renderlayers(re->scene);
-
- for (step= 0; step<2; step++) {
-
- if (step)
- table= &newtable;
- else
- table= &oldtable;
-
- oldobi= table->first;
- for (obi= re->instancetable.first; obi && oldobi; obi= obi->next) {
- int ok= 1;
- FluidsimModifierData *fluidmd;
-
- if (!(obi->lay & vectorlay))
- continue;
-
- obi->totvector= obi->obr->totvert;
-
- /* find matching object in old table */
- if (oldobi->ob!=obi->ob || oldobi->par!=obi->par || oldobi->index!=obi->index || oldobi->psysindex!=obi->psysindex) {
- ok= 0;
- for (oldobi= table->first; oldobi; oldobi= oldobi->next)
- if (oldobi->ob==obi->ob && oldobi->par==obi->par && oldobi->index==obi->index && oldobi->psysindex==obi->psysindex)
- break;
- if (oldobi==NULL)
- oldobi= table->first;
- else
- ok= 1;
- }
- if (ok==0) {
- printf("speed table: missing object %s\n", obi->ob->id.name + 2);
- continue;
- }
-
- /* NT check for fluidsim special treatment */
- fluidmd = (FluidsimModifierData *)modifiers_findByType(obi->ob, eModifierType_Fluidsim);
- if (fluidmd && fluidmd->fss && (fluidmd->fss->type & OB_FLUIDSIM_DOMAIN)) {
- /* use preloaded per vertex simulation data, only does calculation for step=1 */
- /* NOTE/FIXME - velocities and meshes loaded unnecessarily often during the database_fromscene_vectors calls... */
- load_fluidsimspeedvectors(re, obi, oldobi->vectors, step);
- }
- else {
- /* check if both have same amounts of vertices */
- if (obi->totvector==oldobi->totvector)
- calculate_speedvectors(re, obi, oldobi->vectors, step);
- else
- printf("Warning: object %s has different amount of vertices or strands on other frame\n", obi->ob->id.name + 2);
- } /* not fluidsim */
-
- oldobi= oldobi->next;
- }
- }
- }
-
- free_dbase_object_vectors(&oldtable);
- free_dbase_object_vectors(&newtable);
-
- for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
- if (mesh->prevco) {
- MEM_freeN(mesh->prevco);
- mesh->prevco= NULL;
- }
- if (mesh->nextco) {
- MEM_freeN(mesh->nextco);
- mesh->nextco= NULL;
- }
- }
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-}
-
-
-/* ------------------------------------------------------------------------- */
-/* Baking */
-/* ------------------------------------------------------------------------- */
-
-/* setup for shaded view or bake, so only lamps and materials are initialized */
-/* type:
- * RE_BAKE_LIGHT: for shaded view, only add lamps
- * RE_BAKE_ALL: for baking, all lamps and objects
- * RE_BAKE_NORMALS:for baking, no lamps and only selected objects
- * RE_BAKE_AO: for baking, no lamps, but all objects
- * RE_BAKE_TEXTURE:for baking, no lamps, only selected objects
- * RE_BAKE_VERTEX_COLORS:for baking, no lamps, only selected objects
- * RE_BAKE_DISPLACEMENT:for baking, no lamps, only selected objects
- * RE_BAKE_DERIVATIVE:for baking, no lamps, only selected objects
- * RE_BAKE_SHADOW: for baking, only shadows, but all objects
- */
-void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, const int type, Object *actob)
-{
- Object *camera;
- float mat[4][4];
- float amb[3];
- const short onlyselected= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS);
- const short nolamps= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS);
-
- re->main= bmain;
- re->scene= scene;
- re->lay= lay;
-
- /* renderdata setup and exceptions */
- render_copy_renderdata(&re->r, &scene->r);
-
- RE_init_threadcount(re);
-
- re->flag |= R_BAKING;
- re->excludeob= actob;
- if (actob)
- re->flag |= R_BAKE_TRACE;
-
- if (type==RE_BAKE_NORMALS && re->r.bake_normal_space==R_BAKE_SPACE_TANGENT)
- re->flag |= R_NEED_TANGENT;
-
- if (type==RE_BAKE_VERTEX_COLORS)
- re->flag |= R_NEED_VCOL;
-
- if (!actob && ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) {
- re->r.mode &= ~R_SHADOW;
- re->r.mode &= ~R_RAYTRACE;
- }
-
- if (!actob && (type==RE_BAKE_SHADOW)) {
- re->r.mode |= R_SHADOW;
- }
-
- /* setup render stuff */
- re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bake db arena");
-
- re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
- re->lights.first= re->lights.last= NULL;
- re->lampren.first= re->lampren.last= NULL;
-
- /* in localview, lamps are using normal layers, objects only local bits */
- if (re->lay & 0xFF000000)
- lay &= 0xFF000000;
-
- camera= RE_GetCamera(re);
-
- /* if no camera, set unit */
- if (camera) {
- normalize_m4_m4(mat, camera->obmat);
- invert_m4(mat);
- RE_SetView(re, mat);
- }
- else {
- unit_m4(mat);
- RE_SetView(re, mat);
- }
- copy_m3_m4(re->imat, re->viewinv);
-
- /* TODO: deep shadow maps + baking + strands */
- /* strands use the window matrix and view size, there is to correct
- * window matrix but at least avoids malloc and crash loop [#27807] */
- unit_m4(re->winmat);
- re->winx= re->winy= 256;
- /* done setting dummy values */
-
- init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
- if (re->r.mode & R_RAYTRACE) {
- init_render_qmcsampler(re);
-
- if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
- if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(re, &re->wrld);
- }
-
- /* still bad... doing all */
- init_render_textures(re);
-
- copy_v3_v3(amb, &re->wrld.ambr);
- init_render_materials(re->main, re->r.mode, amb, true);
-
- set_node_shader_lamp_loop(shade_material_loop);
-
- /* MAKE RENDER DATA */
- database_init_objects(re, lay, nolamps, onlyselected, actob, 0);
-
- set_material_lightgroups(re);
-
- /* SHADOW BUFFER */
- if (type!=RE_BAKE_LIGHT)
- if (re->r.mode & R_SHADOW)
- threaded_makeshadowbufs(re);
-
- /* raytree */
- if (!re->test_break(re->tbh))
- if (re->r.mode & R_RAYTRACE)
- makeraytree(re);
-
- /* point density texture */
- if (!re->test_break(re->tbh))
- make_pointdensities(re);
-
- /* voxel data texture */
- if (!re->test_break(re->tbh))
- make_voxeldata(re);
-
- /* occlusion */
- if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh))
- if (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
- if (re->r.mode & R_SHADOW)
- make_occ_tree(re);
-
- re->i.convertdone = true;
-}
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
deleted file mode 100644
index 85a6af92a28..00000000000
--- a/source/blender/render/intern/source/envmap.c
+++ /dev/null
@@ -1,822 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributors: 2004/2005/2006 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/envmap.c
- * \ingroup render
- */
-
-#include <math.h>
-#include <string.h>
-
-/* external modules: */
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h" /* for rectcpy */
-
-#include "DNA_group_types.h"
-#include "DNA_image_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-
-#include "BKE_main.h"
-#include "BKE_image.h" /* BKE_imbuf_write */
-#include "BKE_texture.h"
-#include "BKE_scene.h"
-
-/* this module */
-#include "render_types.h"
-#include "envmap.h"
-#include "renderdatabase.h"
-#include "renderpipeline.h"
-#include "texture.h"
-#include "zbuf.h"
-#include "render_result.h"
-
-/* ------------------------------------------------------------------------- */
-
-static void envmap_split_ima(EnvMap *env, ImBuf *ibuf)
-{
- int dx, part;
-
- /* after lock we test cube[1], if set the other thread has done it fine */
- BLI_thread_lock(LOCK_IMAGE);
- if (env->cube[1] == NULL) {
-
- BKE_texture_envmap_free_data(env);
-
- dx = ibuf->y;
- dx /= 2;
- if (3 * dx == ibuf->x) {
- env->type = ENV_CUBE;
- env->ok = ENV_OSA;
- }
- else if (ibuf->x == ibuf->y) {
- env->type = ENV_PLANE;
- env->ok = ENV_OSA;
- }
- else {
- printf("Incorrect envmap size\n");
- env->ok = 0;
- env->ima->ok = 0;
- }
-
- if (env->ok) {
- if (env->type == ENV_CUBE) {
- for (part = 0; part < 6; part++) {
- env->cube[part] = IMB_allocImBuf(dx, dx, 24, IB_rect | IB_rectfloat);
- }
- IMB_float_from_rect(ibuf);
-
- IMB_rectcpy(env->cube[0], ibuf,
- 0, 0, 0, 0, dx, dx);
- IMB_rectcpy(env->cube[1], ibuf,
- 0, 0, dx, 0, dx, dx);
- IMB_rectcpy(env->cube[2], ibuf,
- 0, 0, 2 * dx, 0, dx, dx);
- IMB_rectcpy(env->cube[3], ibuf,
- 0, 0, 0, dx, dx, dx);
- IMB_rectcpy(env->cube[4], ibuf,
- 0, 0, dx, dx, dx, dx);
- IMB_rectcpy(env->cube[5], ibuf,
- 0, 0, 2 * dx, dx, dx, dx);
-
- }
- else { /* ENV_PLANE */
- env->cube[1] = IMB_dupImBuf(ibuf);
- IMB_float_from_rect(env->cube[1]);
- }
- }
- }
- BLI_thread_unlock(LOCK_IMAGE);
-}
-
-/* ------------------------------------------------------------------------- */
-/* ****************** RENDER ********************** */
-
-/* copy current render */
-static Render *envmap_render_copy(Render *re, EnvMap *env)
-{
- Render *envre;
- float viewscale;
- int cuberes;
-
- envre = RE_NewRender("Envmap");
-
- env->lastsize = re->r.size;
- cuberes = (env->cuberes * re->r.size) / 100;
- cuberes &= 0xFFFC;
-
- /* this flag has R_ZTRA in it for example */
- envre->flag = re->flag;
-
- /* set up renderdata */
- render_copy_renderdata(&envre->r, &re->r);
- envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
- BLI_freelistN(&envre->r.layers);
- BLI_freelistN(&envre->r.views);
- envre->r.filtertype = 0;
- envre->r.tilex = envre->r.xsch / 2;
- envre->r.tiley = envre->r.ysch / 2;
- envre->r.size = 100;
- envre->r.yasp = envre->r.xasp = 1;
-
- RE_InitState(envre, NULL, &envre->r, NULL, cuberes, cuberes, NULL);
- envre->main = re->main;
- envre->scene = re->scene; /* unsure about this... */
- envre->scene_color_manage = re->scene_color_manage;
- envre->lay = re->lay;
-
- /* view stuff in env render */
- viewscale = (env->type == ENV_PLANE) ? env->viewscale : 1.0f;
- RE_SetEnvmapCamera(envre, env->object, viewscale, env->clipsta, env->clipend);
- copy_m4_m4(envre->viewmat_orig, re->viewmat_orig);
-
- /* callbacks */
- envre->display_update = re->display_update;
- envre->duh = re->duh;
- envre->test_break = re->test_break;
- envre->tbh = re->tbh;
- envre->current_scene_update = re->current_scene_update;
- envre->suh = re->suh;
-
- /* and for the evil stuff; copy the database... */
- envre->totvlak = re->totvlak;
- envre->totvert = re->totvert;
- envre->tothalo = re->tothalo;
- envre->totstrand = re->totstrand;
- envre->totlamp = re->totlamp;
- envre->sortedhalos = re->sortedhalos;
- envre->lights = re->lights;
- envre->objecttable = re->objecttable;
- envre->customdata_names = re->customdata_names;
- envre->raytree = re->raytree;
- envre->totinstance = re->totinstance;
- envre->instancetable = re->instancetable;
- envre->objectinstance = re->objectinstance;
- envre->qmcsamplers = re->qmcsamplers;
-
- return envre;
-}
-
-static void envmap_free_render_copy(Render *envre)
-{
-
- envre->totvlak = 0;
- envre->totvert = 0;
- envre->tothalo = 0;
- envre->totstrand = 0;
- envre->totlamp = 0;
- envre->totinstance = 0;
- envre->sortedhalos = NULL;
- BLI_listbase_clear(&envre->lights);
- BLI_listbase_clear(&envre->objecttable);
- BLI_listbase_clear(&envre->customdata_names);
- envre->raytree = NULL;
- BLI_listbase_clear(&envre->instancetable);
- envre->objectinstance = NULL;
- envre->qmcsamplers = NULL;
-
- RE_FreeRender(envre);
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void envmap_transmatrix(float mat[4][4], int part)
-{
- float tmat[4][4], eul[3], rotmat[4][4];
-
- eul[0] = eul[1] = eul[2] = 0.0;
-
- if (part == 0) { /* neg z */
- /* pass */
- }
- else if (part == 1) { /* pos z */
- eul[0] = M_PI;
- }
- else if (part == 2) { /* pos y */
- eul[0] = M_PI / 2.0;
- }
- else if (part == 3) { /* neg x */
- eul[0] = M_PI / 2.0;
- eul[2] = M_PI / 2.0;
- }
- else if (part == 4) { /* neg y */
- eul[0] = M_PI / 2.0;
- eul[2] = M_PI;
- }
- else { /* pos x */
- eul[0] = M_PI / 2.0;
- eul[2] = -M_PI / 2.0;
- }
-
- copy_m4_m4(tmat, mat);
- eul_to_mat4(rotmat, eul);
- mul_m4_m4m4(mat, tmat, rotmat);
-}
-/* ------------------------------------------------------------------------- */
-
-static void env_set_imats(Render *re)
-{
- Base *base;
- float mat[4][4];
-
- base = re->scene->base.first;
- while (base) {
- mul_m4_m4m4(mat, re->viewmat, base->object->obmat);
- invert_m4_m4(base->object->imat, mat);
-
- base = base->next;
- }
-
-}
-
-/* ------------------------------------------------------------------------- */
-
-void env_rotate_scene(Render *re, float mat[4][4], int do_rotate)
-{
- ObjectRen *obr;
- ObjectInstanceRen *obi;
- LampRen *lar = NULL;
- HaloRen *har = NULL;
- float imat[3][3], mat_inverse[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4];
- int a;
-
- if (do_rotate == 0) {
- invert_m4_m4(tmat, mat);
- copy_m3_m4(imat, tmat);
-
- copy_m4_m4(mat_inverse, mat);
- }
- else {
- copy_m4_m4(tmat, mat);
- copy_m3_m4(imat, mat);
-
- invert_m4_m4(mat_inverse, tmat);
- }
-
- for (obi = re->instancetable.first; obi; obi = obi->next) {
- /* append or set matrix depending on dupli */
- if (obi->flag & R_DUPLI_TRANSFORMED) {
- copy_m4_m4(tmpmat, obi->mat);
- mul_m4_m4m4(obi->mat, tmat, tmpmat);
- }
- else if (do_rotate == 1)
- copy_m4_m4(obi->mat, tmat);
- else
- unit_m4(obi->mat);
-
- copy_m3_m4(cmat, obi->mat);
- invert_m3_m3(obi->nmat, cmat);
- transpose_m3(obi->nmat);
-
- /* indicate the renderer has to use transform matrices */
- if (do_rotate == 0)
- obi->flag &= ~R_ENV_TRANSFORMED;
- else {
- obi->flag |= R_ENV_TRANSFORMED;
- copy_m4_m4(obi->imat, mat_inverse);
- }
- }
-
-
- for (obr = re->objecttable.first; obr; obr = obr->next) {
- for (a = 0; a < obr->tothalo; a++) {
- if ((a & 255) == 0) har = obr->bloha[a >> 8];
- else har++;
-
- mul_m4_v3(tmat, har->co);
- }
-
- /* imat_ren is needed for correct texture coordinates */
- mul_m4_m4m4(obr->ob->imat_ren, re->viewmat, obr->ob->obmat);
- invert_m4(obr->ob->imat_ren);
- }
-
- for (lar = re->lampren.first; lar; lar = lar->next) {
- float lamp_imat[4][4];
-
- /* copy from add_render_lamp */
- if (do_rotate == 1)
- mul_m4_m4m4(tmpmat, re->viewmat, lar->lampmat);
- else
- mul_m4_m4m4(tmpmat, re->viewmat_orig, lar->lampmat);
-
- invert_m4_m4(lamp_imat, tmpmat);
- copy_m3_m4(lar->mat, tmpmat);
- copy_m3_m4(lar->imat, lamp_imat);
-
- lar->vec[0]= -tmpmat[2][0];
- lar->vec[1]= -tmpmat[2][1];
- lar->vec[2]= -tmpmat[2][2];
- normalize_v3(lar->vec);
- lar->co[0]= tmpmat[3][0];
- lar->co[1]= tmpmat[3][1];
- lar->co[2]= tmpmat[3][2];
-
- if (lar->type == LA_AREA) {
- area_lamp_vectors(lar);
- }
- else if (lar->type == LA_SPOT) {
- normalize_v3(lar->imat[0]);
- normalize_v3(lar->imat[1]);
- normalize_v3(lar->imat[2]);
-
- lar->sh_invcampos[0] = -lar->co[0];
- lar->sh_invcampos[1] = -lar->co[1];
- lar->sh_invcampos[2] = -lar->co[2];
- mul_m3_v3(lar->imat, lar->sh_invcampos);
- lar->sh_invcampos[2] *= lar->sh_zfac;
-
- if (lar->shb) {
- if (do_rotate == 1) {
- mul_m4_m4m4(smat, lar->shb->viewmat, mat_inverse);
- mul_m4_m4m4(lar->shb->persmat, lar->shb->winmat, smat);
- }
- else mul_m4_m4m4(lar->shb->persmat, lar->shb->winmat, lar->shb->viewmat);
- }
- }
- }
-
- if (do_rotate) {
- init_render_world(re);
- env_set_imats(re);
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void env_layerflags(Render *re, unsigned int notlay)
-{
- ObjectRen *obr;
- VlakRen *vlr = NULL;
- int a;
-
- /* invert notlay, so if face is in multiple layers it will still be visible,
- * unless all 'notlay' bits match the face bits.
- * face: 0110
- * not: 0100
- * ~not: 1011
- * now (face & ~not) is true
- */
-
- notlay = ~notlay;
-
- for (obr = re->objecttable.first; obr; obr = obr->next) {
- if ((obr->lay & notlay) == 0) {
- for (a = 0; a < obr->totvlak; a++) {
- if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
- else vlr++;
-
- vlr->flag |= R_HIDDEN;
- }
- }
- }
-}
-
-static void env_hideobject(Render *re, Object *ob)
-{
- ObjectRen *obr;
- VlakRen *vlr = NULL;
- int a;
-
- for (obr = re->objecttable.first; obr; obr = obr->next) {
- for (a = 0; a < obr->totvlak; a++) {
- if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
- else vlr++;
-
- if (obr->ob == ob)
- vlr->flag |= R_HIDDEN;
- }
- }
-}
-
-static void env_showobjects(Render *re)
-{
- ObjectRen *obr;
- VlakRen *vlr = NULL;
- int a;
-
- for (obr = re->objecttable.first; obr; obr = obr->next) {
- for (a = 0; a < obr->totvlak; a++) {
- if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
- else vlr++;
-
- vlr->flag &= ~R_HIDDEN;
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void render_envmap(Render *re, EnvMap *env)
-{
- /* only the cubemap and planar map is implemented */
- Render *envre;
- ImBuf *ibuf;
- float orthmat[4][4];
- float oldviewinv[4][4], mat[4][4], tmat[4][4];
- short part;
-
- /* need a recalc: ortho-render has no correct viewinv */
- invert_m4_m4(oldviewinv, re->viewmat);
-
- envre = envmap_render_copy(re, env);
-
- /* precalc orthmat for object */
- copy_m4_m4(orthmat, env->object->obmat);
- normalize_m4(orthmat);
-
- /* need imat later for texture imat */
- mul_m4_m4m4(mat, re->viewmat, orthmat);
- invert_m4_m4(tmat, mat);
- copy_m3_m4(env->obimat, tmat);
-
- for (part = 0; part < 6; part++) {
- if (env->type == ENV_PLANE && part != 1)
- continue;
-
- re->display_clear(re->dch, envre->result);
-
- copy_m4_m4(tmat, orthmat);
- envmap_transmatrix(tmat, part);
- invert_m4_m4(mat, tmat);
- /* mat now is the camera 'viewmat' */
-
- copy_m4_m4(envre->viewmat, mat);
- copy_m4_m4(envre->viewinv, tmat);
-
- /* we have to correct for the already rotated vertexcoords */
- mul_m4_m4m4(tmat, envre->viewmat, oldviewinv);
- invert_m4_m4(env->imat, tmat);
-
- env_rotate_scene(envre, tmat, 1);
- project_renderdata(envre, projectverto, 0, 0, 1);
- env_layerflags(envre, env->notlay);
- env_hideobject(envre, env->object);
-
- if (re->test_break(re->tbh) == 0) {
- RE_TileProcessor(envre);
- }
-
- /* rotate back */
- env_showobjects(envre);
- env_rotate_scene(envre, tmat, 0);
-
- if (re->test_break(re->tbh) == 0) {
- int y;
- float *alpha;
- float *rect;
-
- if (envre->result->do_exr_tile) {
- BLI_rw_mutex_lock(&envre->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_end(envre);
- BLI_rw_mutex_unlock(&envre->resultmutex);
- }
-
- RenderLayer *rl = envre->result->layers.first;
-
- /* envmap is rendered independently of multiview */
- rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, "");
- ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat);
- memcpy(ibuf->rect_float, rect, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
-
- /* envmap renders without alpha */
- alpha = ibuf->rect_float + 3;
- for (y = ibuf->x * ibuf->y - 1; y >= 0; y--, alpha += 4)
- *alpha = 1.0;
-
- env->cube[part] = ibuf;
- }
-
- if (re->test_break(re->tbh)) break;
-
- }
-
- if (re->test_break(re->tbh)) BKE_texture_envmap_free_data(env);
- else {
- if (envre->r.mode & R_OSA) env->ok = ENV_OSA;
- else env->ok = ENV_NORMAL;
- env->lastframe = re->scene->r.cfra;
- }
-
- /* restore */
- envmap_free_render_copy(envre);
- env_set_imats(re);
-
-}
-
-/* ------------------------------------------------------------------------- */
-
-void make_envmaps(Render *re)
-{
- Tex *tex;
- bool do_init = false;
- int depth = 0, trace;
-
- if (!(re->r.mode & R_ENVMAP)) return;
-
- /* we don't raytrace, disabling the flag will cause ray_transp render solid */
- trace = (re->r.mode & R_RAYTRACE);
- re->r.mode &= ~R_RAYTRACE;
-
- re->i.infostr = IFACE_("Creating Environment maps");
- re->stats_draw(re->sdh, &re->i);
-
- /* 5 = hardcoded max recursion level */
- while (depth < 5) {
- tex = re->main->tex.first;
- while (tex) {
- if (tex->id.us && tex->type == TEX_ENVMAP) {
- if (tex->env && tex->env->object) {
- EnvMap *env = tex->env;
-
- if (env->object->lay & re->lay) {
- if (env->stype == ENV_LOAD) {
- float orthmat[4][4], mat[4][4], tmat[4][4];
-
- /* precalc orthmat for object */
- copy_m4_m4(orthmat, env->object->obmat);
- normalize_m4(orthmat);
-
- /* need imat later for texture imat */
- mul_m4_m4m4(mat, re->viewmat, orthmat);
- invert_m4_m4(tmat, mat);
- copy_m3_m4(env->obimat, tmat);
- }
- else {
-
- /* decide if to render an envmap (again) */
- if (env->depth >= depth) {
-
- /* set 'recalc' to make sure it does an entire loop of recalcs */
-
- if (env->ok) {
- /* free when OSA, and old one isn't OSA */
- if ((re->r.mode & R_OSA) && env->ok == ENV_NORMAL)
- BKE_texture_envmap_free_data(env);
- /* free when size larger */
- else if (env->lastsize < re->r.size)
- BKE_texture_envmap_free_data(env);
- /* free when env is in recalcmode */
- else if (env->recalc)
- BKE_texture_envmap_free_data(env);
- }
-
- if (env->ok == 0 && depth == 0) env->recalc = 1;
-
- if (env->ok == 0) {
- do_init = true;
- render_envmap(re, env);
-
- if (depth == env->depth) env->recalc = 0;
- }
- }
- }
- }
- }
- }
- tex = tex->id.next;
- }
- depth++;
- }
-
- if (do_init) {
- re->display_init(re->dih, re->result);
- re->display_clear(re->dch, re->result);
- // re->flag |= R_REDRAW_PRV;
- }
- /* restore */
- re->r.mode |= trace;
-
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int envcube_isect(EnvMap *env, const float vec[3], float answ[2])
-{
- float lambda;
- int face;
-
- if (env->type == ENV_PLANE) {
- face = 1;
-
- lambda = 1.0f / vec[2];
- answ[0] = env->viewscale * lambda * vec[0];
- answ[1] = -env->viewscale * lambda * vec[1];
- }
- else {
- /* which face */
- if (vec[2] <= -fabsf(vec[0]) && vec[2] <= -fabsf(vec[1]) ) {
- face = 0;
- lambda = -1.0f / vec[2];
- answ[0] = lambda * vec[0];
- answ[1] = lambda * vec[1];
- }
- else if (vec[2] >= fabsf(vec[0]) && vec[2] >= fabsf(vec[1])) {
- face = 1;
- lambda = 1.0f / vec[2];
- answ[0] = lambda * vec[0];
- answ[1] = -lambda * vec[1];
- }
- else if (vec[1] >= fabsf(vec[0])) {
- face = 2;
- lambda = 1.0f / vec[1];
- answ[0] = lambda * vec[0];
- answ[1] = lambda * vec[2];
- }
- else if (vec[0] <= -fabsf(vec[1])) {
- face = 3;
- lambda = -1.0f / vec[0];
- answ[0] = lambda * vec[1];
- answ[1] = lambda * vec[2];
- }
- else if (vec[1] <= -fabsf(vec[0])) {
- face = 4;
- lambda = -1.0f / vec[1];
- answ[0] = -lambda * vec[0];
- answ[1] = lambda * vec[2];
- }
- else {
- face = 5;
- lambda = 1.0f / vec[0];
- answ[0] = -lambda * vec[1];
- answ[1] = lambda * vec[2];
- }
- }
-
- answ[0] = 0.5f + 0.5f * answ[0];
- answ[1] = 0.5f + 0.5f * answ[1];
- return face;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void set_dxtdyt(float r_dxt[3], float r_dyt[3], const float dxt[3], const float dyt[3], int face)
-{
- if (face == 2 || face == 4) {
- r_dxt[0] = dxt[0];
- r_dyt[0] = dyt[0];
- r_dxt[1] = dxt[2];
- r_dyt[1] = dyt[2];
- }
- else if (face == 3 || face == 5) {
- r_dxt[0] = dxt[1];
- r_dxt[1] = dxt[2];
- r_dyt[0] = dyt[1];
- r_dyt[1] = dyt[2];
- }
- else {
- r_dxt[0] = dxt[0];
- r_dyt[0] = dyt[0];
- r_dxt[1] = dxt[1];
- r_dyt[1] = dyt[1];
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
-{
- extern Render R; /* only in this call */
- /* texvec should be the already reflected normal */
- EnvMap *env;
- ImBuf *ibuf;
- float fac, vec[3], sco[3], dxts[3], dyts[3];
- int face, face1;
-
- env = tex->env;
- if (env == NULL || (env->stype != ENV_LOAD && env->object == NULL)) {
- texres->tin = 0.0;
- return 0;
- }
-
- if (env->stype == ENV_LOAD) {
- env->ima = tex->ima;
- if (env->ima && env->ima->ok) {
- if (env->cube[1] == NULL) {
- ImBuf *ibuf_ima = BKE_image_pool_acquire_ibuf(env->ima, NULL, pool);
- if (ibuf_ima)
- envmap_split_ima(env, ibuf_ima);
- else
- env->ok = 0;
-
- if (env->type == ENV_PLANE)
- tex->extend = TEX_EXTEND;
-
- BKE_image_pool_release_ibuf(env->ima, ibuf_ima, pool);
- }
- }
- }
-
- if (env->ok == 0) {
- texres->tin = 0.0;
- return 0;
- }
-
- /* rotate to envmap space, if object is set */
- copy_v3_v3(vec, texvec);
- if (env->object) {
- mul_m3_v3(env->obimat, vec);
- if (osatex) {
- mul_m3_v3(env->obimat, dxt);
- mul_m3_v3(env->obimat, dyt);
- }
- }
- else {
- if (!BKE_scene_use_world_space_shading(R.scene)) {
- // texvec is in view space
- mul_mat3_m4_v3(R.viewinv, vec);
- if (osatex) {
- mul_mat3_m4_v3(R.viewinv, dxt);
- mul_mat3_m4_v3(R.viewinv, dyt);
- }
- }
- }
-
- face = envcube_isect(env, vec, sco);
- ibuf = env->cube[face];
-
- if (osatex) {
- set_dxtdyt(dxts, dyts, dxt, dyt, face);
- imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image);
-
- /* edges? */
-
- if (texres->ta < 1.0f) {
- TexResult texr1, texr2;
-
- texr1.nor = texr2.nor = NULL;
- texr1.talpha = texr2.talpha = texres->talpha; /* boxclip expects this initialized */
-
- add_v3_v3(vec, dxt);
- face1 = envcube_isect(env, vec, sco);
- sub_v3_v3(vec, dxt);
-
- if (face != face1) {
- ibuf = env->cube[face1];
- set_dxtdyt(dxts, dyts, dxt, dyt, face1);
- imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool, skip_load_image);
- }
- else texr1.tr = texr1.tg = texr1.tb = texr1.ta = 0.0;
-
- /* here was the nasty bug! results were not zero-ed. FPE! */
-
- add_v3_v3(vec, dyt);
- face1 = envcube_isect(env, vec, sco);
- sub_v3_v3(vec, dyt);
-
- if (face != face1) {
- ibuf = env->cube[face1];
- set_dxtdyt(dxts, dyts, dxt, dyt, face1);
- imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool, skip_load_image);
- }
- else texr2.tr = texr2.tg = texr2.tb = texr2.ta = 0.0;
-
- fac = (texres->ta + texr1.ta + texr2.ta);
- if (fac != 0.0f) {
- fac = 1.0f / fac;
-
- texres->tr = fac * (texres->ta * texres->tr + texr1.ta * texr1.tr + texr2.ta * texr2.tr);
- texres->tg = fac * (texres->ta * texres->tg + texr1.ta * texr1.tg + texr2.ta * texr2.tg);
- texres->tb = fac * (texres->ta * texres->tb + texr1.ta * texr1.tb + texr2.ta * texr2.tb);
- }
- texres->ta = 1.0;
- }
- }
- else {
- imagewrap(tex, NULL, ibuf, sco, texres, pool, skip_load_image);
- }
-
- return 1;
-}
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 3404a2eeb8b..758600e89aa 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -41,12 +41,20 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "DNA_object_types.h"
+
#include "BKE_camera.h"
#include "BKE_global.h"
#include "BKE_colortools.h"
+#include "BKE_layer.h"
+#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#ifdef WITH_PYTHON
@@ -57,46 +65,28 @@
#include "RE_pipeline.h"
#include "RE_bake.h"
+#include "DRW_engine.h"
+
#include "initrender.h"
#include "renderpipeline.h"
#include "render_types.h"
#include "render_result.h"
-#include "rendercore.h"
/* Render Engine Types */
-static RenderEngineType internal_render_type = {
- NULL, NULL,
- "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
- NULL, NULL, NULL, NULL, NULL, NULL, render_internal_update_passes,
- {NULL, NULL, NULL}
-};
-
-#ifdef WITH_GAMEENGINE
-
-static RenderEngineType internal_game_type = {
- NULL, NULL,
- "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- {NULL, NULL, NULL}
-};
-
-#endif
-
ListBase R_engines = {NULL, NULL};
void RE_engines_init(void)
{
- BLI_addtail(&R_engines, &internal_render_type);
-#ifdef WITH_GAMEENGINE
- BLI_addtail(&R_engines, &internal_game_type);
-#endif
+ DRW_engines_register();
}
void RE_engines_exit(void)
{
RenderEngineType *type, *next;
+ DRW_engines_free();
+
for (type = R_engines.first; type; type = next) {
next = type->next;
@@ -111,21 +101,35 @@ void RE_engines_exit(void)
}
}
+void RE_engines_register(RenderEngineType *render_type)
+{
+ if (render_type->draw_engine) {
+ DRW_engine_register(render_type->draw_engine);
+ }
+ BLI_addtail(&R_engines, render_type);
+}
+
RenderEngineType *RE_engines_find(const char *idname)
{
RenderEngineType *type;
type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
if (!type)
- type = &internal_render_type;
+ type = BLI_findstring(&R_engines, "BLENDER_EEVEE", offsetof(RenderEngineType, idname));
return type;
}
bool RE_engine_is_external(Render *re)
{
- RenderEngineType *type = RE_engines_find(re->r.engine);
- return (type && type->render);
+ return (re->engine && re->engine->type && re->engine->type->render);
+}
+
+bool RE_engine_is_opengl(RenderEngineType *render_type)
+{
+ /* TODO refine? Can we have ogl render engine without ogl render pipeline? */
+ return (render_type->draw_engine != NULL) &&
+ DRW_engine_render_support(render_type->draw_engine);
}
/* Create, Free */
@@ -183,7 +187,8 @@ static RenderPart *get_part_from_result(Render *re, RenderResult *result)
return NULL;
}
-RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
+RenderResult *RE_engine_begin_result(
+ RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
{
Render *re = engine->re;
RenderResult *result;
@@ -413,7 +418,8 @@ float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, bool us
return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname);
}
-void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, bool use_spherical_stereo, float *r_modelmat)
+void RE_engine_get_camera_model_matrix(
+ RenderEngine *engine, Object *camera, bool use_spherical_stereo, float *r_modelmat)
{
Render *re = engine->re;
@@ -469,13 +475,6 @@ rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_
}
tiles[total_tiles] = pa->disprect;
- if (pa->crop) {
- tiles[total_tiles].xmin += pa->crop;
- tiles[total_tiles].ymin += pa->crop;
- tiles[total_tiles].xmax -= pa->crop;
- tiles[total_tiles].ymax -= pa->crop;
- }
-
total_tiles++;
}
}
@@ -489,6 +488,49 @@ RenderData *RE_engine_get_render_data(Render *re)
return &re->r;
}
+/* Depsgraph */
+static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
+{
+ Main *bmain = engine->re->main;
+ Scene *scene = engine->re->scene;
+
+ engine->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
+ DEG_debug_name_set(engine->depsgraph, "RENDER");
+
+ BKE_scene_graph_update_for_newframe(engine->depsgraph, bmain);
+}
+
+static void engine_depsgraph_free(RenderEngine *engine)
+{
+ DEG_graph_free(engine->depsgraph);
+
+ engine->depsgraph = NULL;
+}
+
+void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
+{
+ if(!engine->depsgraph) {
+ return;
+ }
+
+#ifdef WITH_PYTHON
+ BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+ Render *re = engine->re;
+ double cfra = (double)frame + (double)subframe;
+
+ CLAMP(cfra, MINAFRAME, MAXFRAME);
+ BKE_scene_frame_set(re->scene, cfra);
+ BKE_scene_graph_update_for_newframe(engine->depsgraph, re->main);
+
+ BKE_scene_camera_switch_update(re->scene);
+
+#ifdef WITH_PYTHON
+ BPy_END_ALLOW_THREADS;
+#endif
+}
+
/* Bake */
void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
{
@@ -504,7 +546,7 @@ bool RE_bake_has_engine(Render *re)
}
bool RE_bake_engine(
- Render *re, Object *object,
+ Render *re, Depsgraph *depsgraph, Object *object,
const int object_id, const BakePixel pixel_array[],
const size_t num_pixels, const int depth,
const eScenePassType pass_type, const int pass_filter,
@@ -535,16 +577,30 @@ bool RE_bake_engine(
engine->resolution_x = re->winx;
engine->resolution_y = re->winy;
- RE_parts_init(re, false);
+ RE_parts_init(re);
engine->tile_x = re->r.tilex;
engine->tile_y = re->r.tiley;
- /* update is only called so we create the engine.session */
- if (type->update)
- type->update(engine, re->main, re->scene);
-
- if (type->bake)
- type->bake(engine, re->scene, object, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result);
+ if (type->bake) {
+ engine->depsgraph = depsgraph;
+
+ /* update is only called so we create the engine.session */
+ if (type->update)
+ type->update(engine, re->main, engine->depsgraph);
+
+ type->bake(engine,
+ engine->depsgraph,
+ object,
+ pass_type,
+ pass_filter,
+ object_id,
+ pixel_array,
+ num_pixels,
+ depth,
+ result);
+
+ engine->depsgraph = NULL;
+ }
engine->tile_x = 0;
engine->tile_y = 0;
@@ -567,42 +623,8 @@ bool RE_bake_engine(
return true;
}
-void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
-{
- Render *re = engine->re;
- Scene *scene = re->scene;
- double cfra = (double)frame + (double)subframe;
-
- CLAMP(cfra, MINAFRAME, MAXFRAME);
- BKE_scene_frame_set(scene, cfra);
-
-#ifdef WITH_PYTHON
- BPy_BEGIN_ALLOW_THREADS;
-#endif
-
- /* It's possible that here we're including layers which were never visible before. */
- BKE_scene_update_for_newframe_ex(re->eval_ctx, re->main, scene, (1 << 20) - 1, true);
-
-#ifdef WITH_PYTHON
- BPy_END_ALLOW_THREADS;
-#endif
-
- BKE_scene_camera_switch_update(scene);
-}
-
/* Render */
-static bool render_layer_exclude_animated(Scene *scene, SceneRenderLayer *srl)
-{
- PointerRNA ptr;
- PropertyRNA *prop;
-
- RNA_pointer_create(&scene->id, &RNA_SceneRenderLayer, srl, &ptr);
- prop = RNA_struct_find_property(&ptr, "layers_exclude");
-
- return RNA_property_animated(&ptr, prop);
-}
-
int RE_engine_render(Render *re, int do_all)
{
RenderEngineType *type = RE_engines_find(re->r.engine);
@@ -627,41 +649,7 @@ int RE_engine_render(Render *re, int do_all)
/* update animation here so any render layer animation is applied before
* creating the render result */
if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_BUTS_PREVIEW)) == 0) {
- unsigned int lay = re->lay;
-
- /* don't update layers excluded on all render layers */
- if (type->flag & RE_USE_EXCLUDE_LAYERS) {
- SceneRenderLayer *srl;
- unsigned int non_excluded_lay = 0;
-
- if (re->r.scemode & R_SINGLE_LAYER) {
- srl = BLI_findlink(&re->r.layers, re->r.actlay);
- if (srl) {
- non_excluded_lay |= ~(srl->lay_exclude & ~srl->lay_zmask);
-
- /* in this case we must update all because animation for
- * the scene has not been updated yet, and so may not be
- * up to date until after BKE_scene_update_for_newframe */
- if (render_layer_exclude_animated(re->scene, srl))
- non_excluded_lay |= ~0;
- }
- }
- else {
- for (srl = re->r.layers.first; srl; srl = srl->next) {
- if (!(srl->layflag & SCE_LAY_DISABLE)) {
- non_excluded_lay |= ~(srl->lay_exclude & ~srl->lay_zmask);
-
- if (render_layer_exclude_animated(re->scene, srl))
- non_excluded_lay |= ~0;
- }
- }
- }
-
- lay &= non_excluded_lay;
- }
-
- BKE_scene_update_for_newframe_ex(re->eval_ctx, re->main, re->scene, lay, true);
- render_update_anim_renderdata(re, &re->scene->r);
+ render_update_anim_renderdata(re, &re->scene->r, &re->scene->view_layers);
}
/* create render result */
@@ -714,28 +702,60 @@ int RE_engine_render(Render *re, int do_all)
if (re->r.scemode & R_BUTS_PREVIEW)
engine->flag |= RE_ENGINE_PREVIEW;
engine->camera_override = re->camera_override;
- engine->layer_override = re->layer_override;
engine->resolution_x = re->winx;
engine->resolution_y = re->winy;
- RE_parts_init(re, false);
+ RE_parts_init(re);
engine->tile_x = re->partx;
engine->tile_y = re->party;
if (re->result->do_exr_tile)
render_result_exr_file_begin(re);
- if (type->update)
- type->update(engine, re->main, re->scene);
-
/* Clear UI drawing locks. */
if (re->draw_lock) {
re->draw_lock(re->dlh, 0);
}
- if (type->render)
- type->render(engine, re->scene);
+ if (type->render) {
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re, view_layer_iter)
+ {
+ if (re->draw_lock) {
+ re->draw_lock(re->dlh, 1);
+ }
+
+ ViewLayer *view_layer = BLI_findstring(&re->scene->view_layers, view_layer_iter->name, offsetof(ViewLayer, name));
+ engine_depsgraph_init(engine, view_layer);
+
+ if (type->update) {
+ type->update(engine, re->main, engine->depsgraph);
+ }
+
+ if (re->draw_lock) {
+ re->draw_lock(re->dlh, 0);
+ }
+
+ type->render(engine, engine->depsgraph);
+
+ /* Grease pencil render over previous render result.
+ *
+ * NOTE: External engine might have been requested to free its
+ * dependency graph, which is only allowed if there is no grease
+ * pencil (pipeline is taking care of that).
+ */
+ if (!RE_engine_test_break(engine) && engine->depsgraph != NULL) {
+ DRW_render_gpencil(engine, engine->depsgraph);
+ }
+
+ engine_depsgraph_free(engine);
+
+ if (RE_engine_test_break(engine)) {
+ break;
+ }
+ }
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
+ }
engine->tile_x = 0;
engine->tile_y = 0;
@@ -778,12 +798,12 @@ int RE_engine_render(Render *re, int do_all)
return 1;
}
-void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl,
+void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer,
const char *name, int UNUSED(channels), const char *UNUSED(chanid), int type)
{
/* The channel information is currently not used, but is part of the API in case it's needed in the future. */
- if (!(scene && srl && engine)) {
+ if (!(scene && view_layer && engine)) {
return;
}
@@ -794,7 +814,22 @@ void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, s
* unless we want to register that for every other temp Main we could generate??? */
for (Scene *sce = G_MAIN->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree) {
- ntreeCompositRegisterPass(sce->nodetree, scene, srl, name, type);
+ ntreeCompositRegisterPass(sce->nodetree, scene, view_layer, name, type);
}
}
}
+
+void RE_engine_free_blender_memory(RenderEngine *engine)
+{
+ /* Weak way to save memory, but not crash grease pencil.
+ *
+ * TODO(sergey): Find better solution for this.
+ * TODO(sergey): Try to find solution which does not involve looping over
+ * all the objects.
+ */
+ if (DRW_render_check_grease_pencil(engine->depsgraph)) {
+ return;
+ }
+ DEG_graph_free(engine->depsgraph);
+ engine->depsgraph = NULL;
+}
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 1f1e900ba04..3a31413c5cd 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -53,16 +53,11 @@
#include "BKE_image.h"
#include "RE_render_ext.h"
+#include "RE_shader_ext.h"
#include "render_types.h"
#include "texture.h"
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float maxy, TexResult *texres, const short imaprepeat, const short imapextend);
/* *********** IMAGEWRAPPING ****************** */
@@ -211,11 +206,6 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
}
}
- /* warning, no return before setting back! */
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
- ibuf->rect+= (ibuf->x*ibuf->y);
- }
-
/* keep this before interpolation [#29761] */
if (ima) {
if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
@@ -243,10 +233,6 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
ibuf_get_color(&texres->tr, ibuf, x, y);
}
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
- ibuf->rect-= (ibuf->x*ibuf->y);
- }
-
if (texres->nor) {
if (tex->imaflag & TEX_NORMALMAP) {
/* qdn: normal from color
@@ -887,29 +873,25 @@ static void alpha_clip_aniso(ImBuf *ibuf, float minx, float miny, float maxx, fl
static void image_mipmap_test(Tex *tex, ImBuf *ibuf)
{
if (tex->imaflag & TEX_MIPMAP) {
- if ((ibuf->flags & IB_fields) == 0) {
-
- if (ibuf->mipmap[0] && (ibuf->userflags & IB_MIPMAP_INVALID)) {
- BLI_thread_lock(LOCK_IMAGE);
- if (ibuf->userflags & IB_MIPMAP_INVALID) {
- IMB_remakemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP);
- ibuf->userflags &= ~IB_MIPMAP_INVALID;
- }
- BLI_thread_unlock(LOCK_IMAGE);
- }
- if (ibuf->mipmap[0] == NULL) {
- BLI_thread_lock(LOCK_IMAGE);
- if (ibuf->mipmap[0] == NULL)
- IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP);
- BLI_thread_unlock(LOCK_IMAGE);
- }
- /* if no mipmap could be made, fall back on non-mipmap render */
- if (ibuf->mipmap[0] == NULL) {
- tex->imaflag &= ~TEX_MIPMAP;
+ if (ibuf->mipmap[0] && (ibuf->userflags & IB_MIPMAP_INVALID)) {
+ BLI_thread_lock(LOCK_IMAGE);
+ if (ibuf->userflags & IB_MIPMAP_INVALID) {
+ IMB_remakemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP);
+ ibuf->userflags &= ~IB_MIPMAP_INVALID;
}
+ BLI_thread_unlock(LOCK_IMAGE);
+ }
+ if (ibuf->mipmap[0] == NULL) {
+ BLI_thread_lock(LOCK_IMAGE);
+ if (ibuf->mipmap[0] == NULL)
+ IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP);
+ BLI_thread_unlock(LOCK_IMAGE);
+ }
+ /* if no mipmap could be made, fall back on non-mipmap render */
+ if (ibuf->mipmap[0] == NULL) {
+ tex->imaflag &= ~TEX_MIPMAP;
}
}
-
}
static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
@@ -979,17 +961,6 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
fy = texvec[1];
}
- if (ibuf->flags & IB_fields) {
- if (R.r.mode & R_FIELDS) { /* field render */
- if (R.flag & R_SEC_FIELD) { /* correction for 2nd field */
- /* fac1= 0.5/( (float)ibuf->y ); */
- /* fy-= fac1; */
- }
- else /* first field */
- fy += 0.5f/( (float)ibuf->y );
- }
- }
-
/* pixel coordinates */
minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
maxx = max_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
@@ -1129,10 +1100,6 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
intpol = tex->imaflag & TEX_INTERPOL;
- /* warning no return! */
- if ((R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields))
- ibuf->rect += ibuf->x*ibuf->y;
-
/* struct common data */
copy_v2_v2(AFD.dxt, dxt);
copy_v2_v2(AFD.dyt, dyt);
@@ -1311,9 +1278,6 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
texres->tin = texres->ta;
if (tex->flag & TEX_NEGALPHA) texres->ta = 1.f - texres->ta;
- if ((R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields))
- ibuf->rect -= ibuf->x*ibuf->y;
-
if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { /* normal from color */
/* The invert of the red channel is to make
* the normal map compliant with the outside world.
@@ -1411,18 +1375,6 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
fy= texvec[1];
}
- if (ibuf->flags & IB_fields) {
- if (R.r.mode & R_FIELDS) { /* field render */
- if (R.flag & R_SEC_FIELD) { /* correction for 2nd field */
- /* fac1= 0.5/( (float)ibuf->y ); */
- /* fy-= fac1; */
- }
- else { /* first field */
- fy+= 0.5f/( (float)ibuf->y );
- }
- }
- }
-
/* pixel coordinates */
minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
@@ -1580,11 +1532,6 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
}
}
- /* warning no return! */
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
- ibuf->rect+= (ibuf->x*ibuf->y);
- }
-
/* choice: */
if (tex->imaflag & TEX_MIPMAP) {
ImBuf *previbuf, *curibuf;
@@ -1731,10 +1678,6 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
- ibuf->rect-= (ibuf->x*ibuf->y);
- }
-
if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) {
/* qdn: normal from color
* The invert of the red channel is to make
@@ -1772,16 +1715,10 @@ void image_sample(Image *ima, float fx, float fy, float dx, float dy, float resu
return;
}
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
- ibuf->rect+= (ibuf->x*ibuf->y);
-
texres.talpha = true; /* boxsample expects to be initialized */
boxsample(ibuf, fx, fy, fx + dx, fy + dy, &texres, 0, 1);
copy_v4_v4(result, &texres.tr);
- if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
- ibuf->rect-= (ibuf->x*ibuf->y);
-
ima->flag|= IMA_USED_FOR_RENDER;
BKE_image_pool_release_ibuf(ima, ibuf, pool);
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index b834a3afbf0..1420b8feef7 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -38,13 +38,9 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_jitter_2d.h"
#include "BLI_utildefines.h"
#include "DNA_camera_types.h"
-#include "DNA_image_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BKE_camera.h"
@@ -56,31 +52,6 @@
#include "initrender.h"
-/* ********************** */
-
-static void init_render_jit(Render *re)
-{
- static float jit[32][2]; /* simple caching */
- static float mblur_jit[32][2]; /* simple caching */
- static int lastjit = 0;
- static int last_mblur_jit = 0;
-
- if (lastjit != re->r.osa || last_mblur_jit != re->r.mblur_samples) {
- memset(jit, 0, sizeof(jit));
- BLI_jitter_init(jit, re->r.osa);
-
- memset(mblur_jit, 0, sizeof(mblur_jit));
- BLI_jitter_init(mblur_jit, re->r.mblur_samples);
- }
-
- lastjit = re->r.osa;
- memcpy(re->jit, jit, sizeof(jit));
-
- last_mblur_jit = re->r.mblur_samples;
- memcpy(re->mblur_jit, mblur_jit, sizeof(mblur_jit));
-}
-
-
/* ****************** MASKS and LUTS **************** */
static float filt_quadratic(float x)
@@ -171,256 +142,6 @@ float RE_filter_value(int type, float x)
return 0.0f;
}
-static float calc_weight(Render *re, float *weight, int i, int j)
-{
- float x, y, dist, totw = 0.0;
- int a;
-
- for (a = 0; a < re->osa; a++) {
- x = re->jit[a][0] + i;
- y = re->jit[a][1] + j;
- dist = sqrtf(x * x + y * y);
-
- weight[a] = 0.0;
-
- /* Weighting choices */
- switch (re->r.filtertype) {
- case R_FILTER_BOX:
- if (i == 0 && j == 0) weight[a] = 1.0;
- break;
-
- case R_FILTER_TENT:
- if (dist < re->r.gauss)
- weight[a] = re->r.gauss - dist;
- break;
-
- case R_FILTER_GAUSS:
- x = dist * re->r.gauss;
- weight[a] = (1.0f / expf(x * x) - 1.0f / expf(re->r.gauss * re->r.gauss * 2.25f));
- break;
-
- case R_FILTER_MITCH:
- weight[a] = filt_mitchell(dist * re->r.gauss);
- break;
-
- case R_FILTER_QUAD:
- weight[a] = filt_quadratic(dist * re->r.gauss);
- break;
-
- case R_FILTER_CUBIC:
- weight[a] = filt_cubic(dist * re->r.gauss);
- break;
-
- case R_FILTER_CATROM:
- weight[a] = filt_catrom(dist * re->r.gauss);
- break;
-
- }
-
- totw += weight[a];
-
- }
- return totw;
-}
-
-void free_sample_tables(Render *re)
-{
- int a;
-
- if (re->samples) {
- for (a = 0; a < 9; a++) {
- MEM_freeN(re->samples->fmask1[a]);
- MEM_freeN(re->samples->fmask2[a]);
- }
-
- MEM_freeN(re->samples->centmask);
- MEM_freeN(re->samples);
- re->samples = NULL;
- }
-}
-
-/* based on settings in render, it makes the lookup tables */
-void make_sample_tables(Render *re)
-{
- static int firsttime = 1;
- SampleTables *st;
- float flweight[32];
- float weight[32], totw, val, *fpx1, *fpx2, *fpy1, *fpy2, *m3, *m4;
- int i, j, a, centmasksize;
-
- /* optimization tables, only once */
- if (firsttime) {
- firsttime = 0;
- }
-
- free_sample_tables(re);
-
- init_render_jit(re); /* needed for mblur too */
-
- if (re->osa == 0) {
- /* just prevents cpu cycles for larger render and copying */
- re->r.filtertype = 0;
- return;
- }
-
- st = re->samples = MEM_callocN(sizeof(SampleTables), "sample tables");
-
- for (a = 0; a < 9; a++) {
- st->fmask1[a] = MEM_callocN(256 * sizeof(float), "initfilt");
- st->fmask2[a] = MEM_callocN(256 * sizeof(float), "initfilt");
- }
- for (a = 0; a < 256; a++) {
- st->cmask[a] = 0;
- if (a & 1) st->cmask[a]++;
- if (a & 2) st->cmask[a]++;
- if (a & 4) st->cmask[a]++;
- if (a & 8) st->cmask[a]++;
- if (a & 16) st->cmask[a]++;
- if (a & 32) st->cmask[a]++;
- if (a & 64) st->cmask[a]++;
- if (a & 128) st->cmask[a]++;
- }
-
- centmasksize = (1 << re->osa);
- st->centmask = MEM_mallocN(centmasksize, "Initfilt3");
-
- for (a = 0; a < 16; a++) {
- st->centLut[a] = -0.45f + ((float)a) / 16.0f;
- }
-
- /* calculate totw */
- totw = 0.0;
- for (j = -1; j < 2; j++) {
- for (i = -1; i < 2; i++) {
- totw += calc_weight(re, weight, i, j);
- }
- }
-
- for (j = -1; j < 2; j++) {
- for (i = -1; i < 2; i++) {
- /* calculate using jit, with offset the weights */
-
- memset(weight, 0, sizeof(weight));
- calc_weight(re, weight, i, j);
-
- for (a = 0; a < 16; a++) flweight[a] = weight[a] * (1.0f / totw);
-
- m3 = st->fmask1[3 * (j + 1) + i + 1];
- m4 = st->fmask2[3 * (j + 1) + i + 1];
-
- for (a = 0; a < 256; a++) {
- if (a & 1) {
- m3[a] += flweight[0];
- m4[a] += flweight[8];
- }
- if (a & 2) {
- m3[a] += flweight[1];
- m4[a] += flweight[9];
- }
- if (a & 4) {
- m3[a] += flweight[2];
- m4[a] += flweight[10];
- }
- if (a & 8) {
- m3[a] += flweight[3];
- m4[a] += flweight[11];
- }
- if (a & 16) {
- m3[a] += flweight[4];
- m4[a] += flweight[12];
- }
- if (a & 32) {
- m3[a] += flweight[5];
- m4[a] += flweight[13];
- }
- if (a & 64) {
- m3[a] += flweight[6];
- m4[a] += flweight[14];
- }
- if (a & 128) {
- m3[a] += flweight[7];
- m4[a] += flweight[15];
- }
- }
- }
- }
-
- /* centmask: the correct subpixel offset per mask */
-
- fpx1 = MEM_mallocN(256 * sizeof(float), "initgauss4");
- fpx2 = MEM_mallocN(256 * sizeof(float), "initgauss4");
- fpy1 = MEM_mallocN(256 * sizeof(float), "initgauss4");
- fpy2 = MEM_mallocN(256 * sizeof(float), "initgauss4");
- for (a = 0; a < 256; a++) {
- fpx1[a] = fpx2[a] = 0.0;
- fpy1[a] = fpy2[a] = 0.0;
- if (a & 1) {
- fpx1[a] += re->jit[0][0];
- fpy1[a] += re->jit[0][1];
- fpx2[a] += re->jit[8][0];
- fpy2[a] += re->jit[8][1];
- }
- if (a & 2) {
- fpx1[a] += re->jit[1][0];
- fpy1[a] += re->jit[1][1];
- fpx2[a] += re->jit[9][0];
- fpy2[a] += re->jit[9][1];
- }
- if (a & 4) {
- fpx1[a] += re->jit[2][0];
- fpy1[a] += re->jit[2][1];
- fpx2[a] += re->jit[10][0];
- fpy2[a] += re->jit[10][1];
- }
- if (a & 8) {
- fpx1[a] += re->jit[3][0];
- fpy1[a] += re->jit[3][1];
- fpx2[a] += re->jit[11][0];
- fpy2[a] += re->jit[11][1];
- }
- if (a & 16) {
- fpx1[a] += re->jit[4][0];
- fpy1[a] += re->jit[4][1];
- fpx2[a] += re->jit[12][0];
- fpy2[a] += re->jit[12][1];
- }
- if (a & 32) {
- fpx1[a] += re->jit[5][0];
- fpy1[a] += re->jit[5][1];
- fpx2[a] += re->jit[13][0];
- fpy2[a] += re->jit[13][1];
- }
- if (a & 64) {
- fpx1[a] += re->jit[6][0];
- fpy1[a] += re->jit[6][1];
- fpx2[a] += re->jit[14][0];
- fpy2[a] += re->jit[14][1];
- }
- if (a & 128) {
- fpx1[a] += re->jit[7][0];
- fpy1[a] += re->jit[7][1];
- fpx2[a] += re->jit[15][0];
- fpy2[a] += re->jit[15][1];
- }
- }
-
- for (a = centmasksize - 1; a > 0; a--) {
- val = st->cmask[a & 255] + st->cmask[a >> 8];
- i = 8 + (15.9f * (fpy1[a & 255] + fpy2[a >> 8]) / val);
- CLAMP(i, 0, 15);
- j = 8 + (15.9f * (fpx1[a & 255] + fpx2[a >> 8]) / val);
- CLAMP(j, 0, 15);
- i = j + (i << 4);
- st->centmask[a] = i;
- }
-
- MEM_freeN(fpx1);
- MEM_freeN(fpx2);
- MEM_freeN(fpy1);
- MEM_freeN(fpy2);
-}
-
-
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
struct Object *RE_GetCamera(Render *re)
{
@@ -428,42 +149,14 @@ struct Object *RE_GetCamera(Render *re)
return BKE_camera_multiview_render(re->scene, camera, re->viewname);
}
-static void re_camera_params_get(Render *re, CameraParams *params, Object *cam_ob)
+static void re_camera_params_get(Render *re, CameraParams *params)
{
copy_m4_m4(re->winmat, params->winmat);
re->clipsta = params->clipsta;
re->clipend = params->clipend;
- re->ycor = params->ycor;
- re->viewdx = params->viewdx;
- re->viewdy = params->viewdy;
re->viewplane = params->viewplane;
-
- BKE_camera_object_mode(&re->r, cam_ob);
-}
-
-void RE_SetEnvmapCamera(Render *re, Object *cam_ob, float viewscale, float clipsta, float clipend)
-{
- CameraParams params;
-
- /* setup parameters */
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, cam_ob);
-
- params.lens = 16.0f * viewscale;
- params.sensor_x = 32.0f;
- params.sensor_y = 32.0f;
- params.sensor_fit = CAMERA_SENSOR_FIT_AUTO;
- params.clipsta = clipsta;
- params.clipend = clipend;
-
- /* compute matrix, viewplane, .. */
- BKE_camera_params_compute_viewplane(&params, re->winx, re->winy, 1.0f, 1.0f);
- BKE_camera_params_compute_matrix(&params);
-
- /* extract results */
- re_camera_params_get(re, &params, cam_ob);
}
void RE_SetOverrideCamera(Render *re, Object *camera)
@@ -487,22 +180,12 @@ void RE_SetCamera(Render *re, Object *cam_ob)
BKE_camera_params_from_object(&params, cam_ob);
re_camera_params_stereo3d(re, &params, cam_ob);
- params.use_fields = (re->r.mode & R_FIELDS);
- params.field_second = (re->flag & R_SEC_FIELD);
- params.field_odd = (re->r.mode & R_ODDFIELD);
-
/* compute matrix, viewplane, .. */
BKE_camera_params_compute_viewplane(&params, re->winx, re->winy, re->r.xasp, re->r.yasp);
BKE_camera_params_compute_matrix(&params);
/* extract results */
- re_camera_params_get(re, &params, cam_ob);
-}
-
-void RE_SetPixelSize(Render *re, float pixsize)
-{
- re->viewdx = pixsize;
- re->viewdy = re->ycor * pixsize;
+ re_camera_params_get(re, &params);
}
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4])
@@ -512,6 +195,25 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, flo
copy_m4_m4(mat, re->winmat);
}
+/* Must be called after RE_GetCameraWindow(), does not change re->winmat. */
+void RE_GetCameraWindowWithOverscan(struct Render *re, float mat[4][4], float overscan)
+{
+ CameraParams params;
+ params.is_ortho = re->winmat[3][3] != 0.0f;
+ params.clipsta = re->clipsta;
+ params.clipend = re->clipend;
+ params.viewplane = re->viewplane;
+
+ overscan *= max_ff(BLI_rctf_size_x(&params.viewplane), BLI_rctf_size_y(&params.viewplane));
+
+ params.viewplane.xmin -= overscan;
+ params.viewplane.xmax += overscan;
+ params.viewplane.ymin -= overscan;
+ params.viewplane.ymax += overscan;
+ BKE_camera_params_compute_matrix(&params);
+ copy_m4_m4(mat, params.winmat);
+}
+
void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4])
{
BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_mat);
@@ -522,13 +224,6 @@ void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4
void RE_parts_free(Render *re)
{
- RenderPart *part = re->parts.first;
-
- while (part) {
- if (part->rectp) MEM_freeN(part->rectp);
- if (part->rectz) MEM_freeN(part->rectz);
- part = part->next;
- }
BLI_freelistN(&re->parts);
}
@@ -539,7 +234,7 @@ void RE_parts_clamp(Render *re)
re->party = max_ii(1, min_ii(re->r.tiley, re->recty));
}
-void RE_parts_init(Render *re, bool do_crop)
+void RE_parts_init(Render *re)
{
int nr, xd, yd, partx, party, xparts, yparts;
int xminb, xmaxb, yminb, ymaxb;
@@ -565,10 +260,6 @@ void RE_parts_init(Render *re, bool do_crop)
xparts = (re->rectx + partx - 1) / partx;
yparts = (re->recty + party - 1) / party;
- /* calculate rotation factor of 1 pixel */
- if (re->r.mode & R_PANORAMA)
- re->panophi = panorama_pixel_rot(re);
-
for (nr = 0; nr < xparts * yparts; nr++) {
rcti disprect;
int rectx, recty;
@@ -601,16 +292,6 @@ void RE_parts_init(Render *re, bool do_crop)
if (rectx > 0 && recty > 0) {
RenderPart *pa = MEM_callocN(sizeof(RenderPart), "new part");
- /* Non-box filters need 2 pixels extra to work */
- if (do_crop && (re->r.filtertype || (re->r.mode & R_EDGE))) {
- pa->crop = 2;
- disprect.xmin -= pa->crop;
- disprect.ymin -= pa->crop;
- disprect.xmax += pa->crop;
- disprect.ymax += pa->crop;
- rectx += 2 * pa->crop;
- recty += 2 * pa->crop;
- }
pa->disprect = disprect;
pa->rectx = rectx;
pa->recty = recty;
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 6f66f6d3520..a5d2a359472 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -36,20 +36,23 @@
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BKE_ccg.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_modifier.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+
#include "RE_multires_bake.h"
#include "RE_pipeline.h"
#include "RE_shader_ext.h"
@@ -57,10 +60,6 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "rendercore.h"
-
typedef void (*MPassKnownData)(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *thread_data,
void *bake_data, ImBuf *ibuf, const int face_index, const int lvl,
const float st[2], float tangmat[3][3], const int x, const int y);
@@ -78,7 +77,6 @@ typedef struct {
MLoop *mloop;
MLoopUV *mloopuv;
const MLoopTri *mlooptri;
- MTexPoly *mtpoly;
float *pvtangent;
const float *precomputed_normals;
int w, h;
@@ -89,6 +87,8 @@ typedef struct {
void *bake_data;
ImBuf *ibuf;
MPassKnownData pass_data;
+ /* material aligned UV array */
+ Image **image_array;
} MResolvePixelData;
typedef void (*MFlushPixel)(const MResolvePixelData *data, const int x, const int y);
@@ -112,19 +112,6 @@ typedef struct {
const int *orig_index_mp_to_orig;
} MNormalBakeData;
-typedef struct {
- int number_of_rays;
- float bias;
-
- unsigned short *permutation_table_1;
- unsigned short *permutation_table_2;
-
- RayObject *raytree;
- RayFace *rayfaces;
-
- const int *orig_index_mp_to_orig;
-} MAOBakeData;
-
static void multiresbake_get_normal(const MResolvePixelData *data, float norm[],const int tri_num, const int vert_index)
{
const int poly_index = data->mlooptri[tri_num].poly;
@@ -373,13 +360,15 @@ static void *do_multires_bake_thread(void *data_v)
while ((tri_index = multires_bake_queue_next_tri(handle->queue)) >= 0) {
const MLoopTri *lt = &data->mlooptri[tri_index];
- MTexPoly *mtpoly = &data->mtpoly[lt->poly];
- MLoopUV *mloopuv = data->mloopuv;
+ const MPoly *mp = &data->mpoly[lt->poly];
+ const short mat_nr = mp->mat_nr;
+ const MLoopUV *mloopuv = data->mloopuv;
if (multiresbake_test_break(bkr))
break;
- if (mtpoly->tpage != handle->image)
+ Image *tri_image = mat_nr < bkr->ob_image.len ? bkr->ob_image.array[mat_nr] : NULL;
+ if (tri_image != handle->image)
continue;
data->tri_index = tri_index;
@@ -445,7 +434,6 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t
MPoly *mpoly = dm->getPolyArray(dm);
MLoop *mloop = dm->getLoopArray(dm);
MLoopUV *mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV);
- MTexPoly *mtpoly = dm->getPolyDataArray(dm, CD_MTEXPOLY);
const float *precomputed_normals = dm->getPolyDataArray(dm, CD_NORMAL);
float *pvtangent = NULL;
@@ -489,7 +477,6 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t
handle->data.mvert = mvert;
handle->data.mloopuv = mloopuv;
handle->data.mlooptri = mlooptri;
- handle->data.mtpoly = mtpoly;
handle->data.mloop = mloop;
handle->data.pvtangent = pvtangent;
handle->data.precomputed_normals = precomputed_normals; /* don't strictly need this */
@@ -696,12 +683,13 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima)
if (ss_lvl > 0) {
smd.levels = smd.renderLevels = ss_lvl;
- smd.flags |= eSubsurfModifierFlag_SubsurfUv;
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ smd.quality = 3;
if (bkr->simple)
smd.subdivType = ME_SIMPLE_SUBSURF;
- height_data->ssdm = subsurf_make_derived_from_derived(bkr->lores_dm, &smd, NULL, 0);
+ height_data->ssdm = subsurf_make_derived_from_derived(bkr->lores_dm, &smd, bkr->scene, NULL, 0);
init_ccgdm_arrays(height_data->ssdm);
}
}
@@ -881,6 +869,8 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm,
}
}
+/* TODO: restore ambient occlusion baking support, using BLI BVH? */
+#if 0
/* **************** Ambient Occlusion Baker **************** */
// must be a power of two
@@ -1173,35 +1163,101 @@ static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void
rrgb[3] = 255;
}
}
+#endif
+
+/* ******$***************** Post processing ************************* */
+
+static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
+{
+ /* must check before filtering */
+ const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
+
+ /* Margin */
+ if (filter) {
+ IMB_filter_extend(ibuf, mask, filter);
+ }
+
+ /* if the bake results in new alpha then change the image setting */
+ if (is_new_alpha) {
+ ibuf->planes = R_IMF_PLANES_RGBA;
+ }
+ else {
+ if (filter && ibuf->planes != R_IMF_PLANES_RGBA) {
+ /* clear alpha added by filtering */
+ IMB_rectfill_alpha(ibuf, 1.0f);
+ }
+ }
+}
+
+static void bake_ibuf_normalize_displacement(ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max)
+{
+ int i;
+ const float *current_displacement = displacement;
+ const char *current_mask = mask;
+ float max_distance;
+
+ max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max));
+
+ for (i = 0; i < ibuf->x * ibuf->y; i++) {
+ if (*current_mask == FILTER_MASK_USED) {
+ float normalized_displacement;
+
+ if (max_distance > 1e-5f)
+ normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2);
+ else
+ normalized_displacement = 0.5f;
+
+ if (ibuf->rect_float) {
+ /* currently baking happens to RGBA only */
+ float *fp = ibuf->rect_float + i * 4;
+ fp[0] = fp[1] = fp[2] = normalized_displacement;
+ fp[3] = 1.0f;
+ }
+
+ if (ibuf->rect) {
+ unsigned char *cp = (unsigned char *) (ibuf->rect + i);
+ cp[0] = cp[1] = cp[2] = unit_float_to_uchar_clamp(normalized_displacement);
+ cp[3] = 255;
+ }
+ }
+
+ current_displacement++;
+ current_mask++;
+ }
+}
/* **************** Common functions public API relates on **************** */
static void count_images(MultiresBakeRender *bkr)
{
- int a, totpoly;
- DerivedMesh *dm = bkr->lores_dm;
- MTexPoly *mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY);
-
BLI_listbase_clear(&bkr->image);
bkr->tot_image = 0;
- totpoly = dm->getNumPolys(dm);
-
- for (a = 0; a < totpoly; a++)
- mtexpoly[a].tpage->id.tag &= ~LIB_TAG_DOIT;
+ for (int i = 0; i < bkr->ob_image.len; i++) {
+ Image *ima = bkr->ob_image.array[i];
+ if (ima) {
+ ima->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
- for (a = 0; a < totpoly; a++) {
- Image *ima = mtexpoly[a].tpage;
- if ((ima->id.tag & LIB_TAG_DOIT) == 0) {
- LinkData *data = BLI_genericNodeN(ima);
- BLI_addtail(&bkr->image, data);
- bkr->tot_image++;
- ima->id.tag |= LIB_TAG_DOIT;
+ for (int i = 0; i < bkr->ob_image.len; i++) {
+ Image *ima = bkr->ob_image.array[i];
+ if (ima) {
+ if ((ima->id.tag & LIB_TAG_DOIT) == 0) {
+ LinkData *data = BLI_genericNodeN(ima);
+ BLI_addtail(&bkr->image, data);
+ bkr->tot_image++;
+ ima->id.tag |= LIB_TAG_DOIT;
+ }
}
}
- for (a = 0; a < totpoly; a++)
- mtexpoly[a].tpage->id.tag &= ~LIB_TAG_DOIT;
+ for (int i = 0; i < bkr->ob_image.len; i++) {
+ Image *ima = bkr->ob_image.array[i];
+ if (ima) {
+ ima->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
}
static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
@@ -1222,12 +1278,14 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
do_multires_bake(bkr, ima, true, apply_tangmat_callback, init_normal_data, free_normal_data, result);
break;
case RE_BAKE_DISPLACEMENT:
- case RE_BAKE_DERIVATIVE:
do_multires_bake(bkr, ima, false, apply_heights_callback, init_heights_data, free_heights_data, result);
break;
+/* TODO: restore ambient occlusion baking support. */
+#if 0
case RE_BAKE_AO:
do_multires_bake(bkr, ima, false, apply_ao_callback, init_ao_data, free_ao_data, result);
break;
+#endif
}
}
@@ -1240,7 +1298,7 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
{
LinkData *link;
- bool use_displacement_buffer = ELEM(bkr->mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE);
+ bool use_displacement_buffer = bkr->mode == RE_BAKE_DISPLACEMENT;
for (link = bkr->image.first; link; link = link->next) {
Image *ima = (Image *)link->data;
@@ -1251,17 +1309,11 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
continue;
if (use_displacement_buffer) {
- if (bkr->mode == RE_BAKE_DERIVATIVE) {
- RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
- result->height_min, result->height_max, bkr->user_scale);
- }
- else {
- RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
- result->height_min, result->height_max);
- }
+ bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
+ result->height_min, result->height_max);
}
- RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter);
+ bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter);
ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID;
@@ -1283,7 +1335,7 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
}
BKE_image_release_ibuf(ima, ibuf, NULL);
- DAG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
}
}
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
deleted file mode 100644
index 9b9a5aabca6..00000000000
--- a/source/blender/render/intern/source/occlusion.c
+++ /dev/null
@@ -1,1532 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/occlusion.c
- * \ingroup render
- */
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_material_types.h"
-
-#include "BLI_math.h"
-#include "BLI_memarena.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "BKE_node.h"
-#include "BKE_scene.h"
-
-
-#include "RE_shader_ext.h"
-
-/* local includes */
-#include "occlusion.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "shading.h"
-
-/* ------------------------- Declarations --------------------------- */
-
-#define INVPI ((float)M_1_PI)
-#define TOTCHILD 8
-#define CACHE_STEP 3
-
-typedef struct OcclusionCacheSample {
- float co[3], n[3], ao[3], env[3], indirect[3], intensity, dist2;
- int x, y, filled;
-} OcclusionCacheSample;
-
-typedef struct OcclusionCache {
- OcclusionCacheSample *sample;
- int x, y, w, h, step;
-} OcclusionCache;
-
-typedef struct OccFace {
- int obi;
- int facenr;
-} OccFace;
-
-typedef struct OccNode {
- float co[3], area;
- float sh[9], dco;
- float occlusion, rad[3];
- int childflag;
- union {
- //OccFace face;
- int face;
- struct OccNode *node;
- } child[TOTCHILD];
-} OccNode;
-
-typedef struct OcclusionTree {
- MemArena *arena;
-
- float (*co)[3]; /* temporary during build */
-
- OccFace *face; /* instance and face indices */
- float *occlusion; /* occlusion for faces */
- float (*rad)[3]; /* radiance for faces */
-
- OccNode *root;
-
- OccNode **stack[BLENDER_MAX_THREADS];
- int maxdepth;
-
- int totface;
-
- float error;
- float distfac;
-
- int dothreadedbuild;
- int totbuildthread;
- int doindirect;
-
- OcclusionCache *cache;
-
- int num_threads;
-} OcclusionTree;
-
-typedef struct OcclusionThread {
- Render *re;
- StrandSurface *mesh;
- float (*faceao)[3];
- float (*faceenv)[3];
- float (*faceindirect)[3];
- int begin, end;
- int thread;
-} OcclusionThread;
-
-typedef struct OcclusionBuildThread {
- OcclusionTree *tree;
- int begin, end, depth;
- OccNode *node;
-} OcclusionBuildThread;
-
-/* ------------------------- Shading --------------------------- */
-
-extern Render R; /* meh */
-
-static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad)
-{
- ShadeInput *shi = ssamp->shi;
- ShadeResult *shr = ssamp->shr;
- float l, u, v, *v1, *v2, *v3;
-
- /* init */
- if (vlr->v4) {
- shi->u = u = 0.5f;
- shi->v = v = 0.5f;
- }
- else {
- shi->u = u = 1.0f / 3.0f;
- shi->v = v = 1.0f / 3.0f;
- }
-
- /* setup render coordinates */
- v1 = vlr->v1->co;
- v2 = vlr->v2->co;
- v3 = vlr->v3->co;
-
- /* renderco */
- l = 1.0f - u - v;
-
- shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0];
- shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1];
- shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2];
-
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-
- /* set up view vector */
- copy_v3_v3(shi->view, shi->co);
- normalize_v3(shi->view);
-
- /* cache for shadow */
- shi->samplenr++;
-
- shi->xs = 0; /* TODO */
- shi->ys = 0;
-
- shade_input_set_normals(shi);
-
- /* no normal flip */
- if (shi->flippednor)
- shade_input_flip_normals(shi);
-
- madd_v3_v3fl(shi->co, shi->facenor, -0.0001f); /* ugly.. */
-
- /* not a pretty solution, but fixes common cases */
- if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
- negate_v3(shi->vn);
- negate_v3(shi->vno);
- negate_v3(shi->nmapnorm);
- }
-
- /* init material vars */
- shade_input_init_material(shi);
-
- /* render */
- shade_input_set_shade_texco(shi);
-
- if (shi->mat->nodetree && shi->mat->use_nodes) {
- ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
- shi->mat = vlr->mat; /* shi->mat is being set in nodetree */
- }
- else {
- shade_material_loop(shi, shr);
- }
-
- copy_v3_v3(rad, shr->combined);
-}
-
-static void occ_build_shade(Render *re, OcclusionTree *tree)
-{
- ShadeSample ssamp;
- ObjectInstanceRen *obi;
- VlakRen *vlr;
- int a;
-
- R = *re;
-
- /* setup shade sample with correct passes */
- memset(&ssamp, 0, sizeof(ShadeSample));
- ssamp.shi[0].lay = re->lay;
- ssamp.shi[0].passflag = SCE_PASS_DIFFUSE | SCE_PASS_RGBA;
- ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC);
- ssamp.tot = 1;
-
- for (a = 0; a < tree->totface; a++) {
- obi = &R.objectinstance[tree->face[a].obi];
- vlr = RE_findOrAddVlak(obi->obr, tree->face[a].facenr);
-
- occ_shade(&ssamp, obi, vlr, tree->rad[a]);
-
- if (re->test_break(re->tbh))
- break;
- }
-}
-
-/* ------------------------- Spherical Harmonics --------------------------- */
-
-/* Use 2nd order SH => 9 coefficients, stored in this order:
- * 0 = (0,0),
- * 1 = (1,-1), 2 = (1,0), 3 = (1,1),
- * 4 = (2,-2), 5 = (2,-1), 6 = (2,0), 7 = (2,1), 8 = (2,2) */
-
-static void sh_copy(float *shresult, float *sh)
-{
- memcpy(shresult, sh, sizeof(float) * 9);
-}
-
-static void sh_mul(float *sh, float f)
-{
- int i;
-
- for (i = 0; i < 9; i++)
- sh[i] *= f;
-}
-
-static void sh_add(float *shresult, float *sh1, float *sh2)
-{
- int i;
-
- for (i = 0; i < 9; i++)
- shresult[i] = sh1[i] + sh2[i];
-}
-
-static void sh_from_disc(float *n, float area, float *shresult)
-{
- /* See formula (3) in:
- * "An Efficient Representation for Irradiance Environment Maps" */
- float sh[9], x, y, z;
-
- x = n[0];
- y = n[1];
- z = n[2];
-
- sh[0] = 0.282095f;
-
- sh[1] = 0.488603f * y;
- sh[2] = 0.488603f * z;
- sh[3] = 0.488603f * x;
-
- sh[4] = 1.092548f * x * y;
- sh[5] = 1.092548f * y * z;
- sh[6] = 0.315392f * (3.0f * z * z - 1.0f);
- sh[7] = 1.092548f * x * z;
- sh[8] = 0.546274f * (x * x - y * y);
-
- sh_mul(sh, area);
- sh_copy(shresult, sh);
-}
-
-static float sh_eval(float *sh, float *v)
-{
- /* See formula (13) in:
- * "An Efficient Representation for Irradiance Environment Maps" */
- static const float c1 = 0.429043f, c2 = 0.511664f, c3 = 0.743125f;
- static const float c4 = 0.886227f, c5 = 0.247708f;
- float x, y, z, sum;
-
- x = v[0];
- y = v[1];
- z = v[2];
-
- sum = c1 * sh[8] * (x * x - y * y);
- sum += c3 * sh[6] * z * z;
- sum += c4 * sh[0];
- sum += -c5 * sh[6];
- sum += 2.0f * c1 * (sh[4] * x * y + sh[7] * x * z + sh[5] * y * z);
- sum += 2.0f * c2 * (sh[3] * x + sh[1] * y + sh[2] * z);
-
- return sum;
-}
-
-/* ------------------------------ Building --------------------------------- */
-
-static void occ_face(const OccFace *face, float co[3], float normal[3], float *area)
-{
- ObjectInstanceRen *obi;
- VlakRen *vlr;
- float v1[3], v2[3], v3[3], v4[3];
-
- obi = &R.objectinstance[face->obi];
- vlr = RE_findOrAddVlak(obi->obr, face->facenr);
-
- if (co) {
- if (vlr->v4)
- mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co);
- else
- mid_v3_v3v3v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co);
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, co);
- }
-
- if (normal) {
- normal[0] = -vlr->n[0];
- normal[1] = -vlr->n[1];
- normal[2] = -vlr->n[2];
-
- if (obi->flag & R_TRANSFORMED)
- mul_m3_v3(obi->nmat, normal);
- }
-
- if (area) {
- copy_v3_v3(v1, vlr->v1->co);
- copy_v3_v3(v2, vlr->v2->co);
- copy_v3_v3(v3, vlr->v3->co);
- if (vlr->v4) copy_v3_v3(v4, vlr->v4->co);
-
- if (obi->flag & R_TRANSFORMED) {
- mul_m4_v3(obi->mat, v1);
- mul_m4_v3(obi->mat, v2);
- mul_m4_v3(obi->mat, v3);
- if (vlr->v4) mul_m4_v3(obi->mat, v4);
- }
-
- /* todo: correct area for instances */
- if (vlr->v4)
- *area = area_quad_v3(v1, v2, v3, v4);
- else
- *area = area_tri_v3(v1, v2, v3);
- }
-}
-
-static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node)
-{
- OccNode *child;
- float occ, area, totarea, rad[3];
- int a, b, indirect = tree->doindirect;
-
- occ = 0.0f;
- totarea = 0.0f;
- if (indirect) zero_v3(rad);
-
- for (b = 0; b < TOTCHILD; b++) {
- if (node->childflag & (1 << b)) {
- a = node->child[b].face;
- occ_face(&tree->face[a], NULL, NULL, &area);
- occ += area * tree->occlusion[a];
- if (indirect) madd_v3_v3fl(rad, tree->rad[a], area);
- totarea += area;
- }
- else if (node->child[b].node) {
- child = node->child[b].node;
- occ_sum_occlusion(tree, child);
-
- occ += child->area * child->occlusion;
- if (indirect) madd_v3_v3fl(rad, child->rad, child->area);
- totarea += child->area;
- }
- }
-
- if (totarea != 0.0f) {
- occ /= totarea;
- if (indirect) mul_v3_fl(rad, 1.0f / totarea);
- }
-
- node->occlusion = occ;
- if (indirect) copy_v3_v3(node->rad, rad);
-}
-
-static int occ_find_bbox_axis(OcclusionTree *tree, int begin, int end, float *min, float *max)
-{
- float len, maxlen = -1.0f;
- int a, axis = 0;
-
- INIT_MINMAX(min, max);
-
- for (a = begin; a < end; a++) {
- minmax_v3v3_v3(min, max, tree->co[a]);
- }
-
- for (a = 0; a < 3; a++) {
- len = max[a] - min[a];
-
- if (len > maxlen) {
- maxlen = len;
- axis = a;
- }
- }
-
- return axis;
-}
-
-static void occ_node_from_face(OccFace *face, OccNode *node)
-{
- float n[3];
-
- occ_face(face, node->co, n, &node->area);
- node->dco = 0.0f;
- sh_from_disc(n, node->area, node->sh);
-}
-
-static void occ_build_dco(OcclusionTree *tree, OccNode *node, const float co[3], float *dco)
-{
- int b;
- for (b = 0; b < TOTCHILD; b++) {
- float dist, d[3], nco[3];
-
- if (node->childflag & (1 << b)) {
- occ_face(tree->face + node->child[b].face, nco, NULL, NULL);
- }
- else if (node->child[b].node) {
- OccNode *child = node->child[b].node;
- occ_build_dco(tree, child, co, dco);
- copy_v3_v3(nco, child->co);
- }
- else {
- continue;
- }
-
- sub_v3_v3v3(d, nco, co);
- dist = dot_v3v3(d, d);
- if (dist > *dco)
- *dco = dist;
- }
-}
-
-static void occ_build_split(OcclusionTree *tree, int begin, int end, int *split)
-{
- float min[3], max[3], mid;
- int axis, a, enda;
-
- /* split in middle of boundbox. this seems faster than median split
- * on complex scenes, possibly since it avoids two distant faces to
- * be in the same node better? */
- axis = occ_find_bbox_axis(tree, begin, end, min, max);
- mid = 0.5f * (min[axis] + max[axis]);
-
- a = begin;
- enda = end;
- while (a < enda) {
- if (tree->co[a][axis] > mid) {
- enda--;
- SWAP(OccFace, tree->face[a], tree->face[enda]);
- swap_v3_v3(tree->co[a], tree->co[enda]);
- }
- else
- a++;
- }
-
- *split = enda;
-}
-
-static void occ_build_8_split(OcclusionTree *tree, int begin, int end, int *offset, int *count)
-{
- /* split faces into eight groups */
- int b, splitx, splity[2], splitz[4];
-
- occ_build_split(tree, begin, end, &splitx);
-
- /* force split if none found, to deal with degenerate geometry */
- if (splitx == begin || splitx == end)
- splitx = (begin + end) / 2;
-
- occ_build_split(tree, begin, splitx, &splity[0]);
- occ_build_split(tree, splitx, end, &splity[1]);
-
- occ_build_split(tree, begin, splity[0], &splitz[0]);
- occ_build_split(tree, splity[0], splitx, &splitz[1]);
- occ_build_split(tree, splitx, splity[1], &splitz[2]);
- occ_build_split(tree, splity[1], end, &splitz[3]);
-
- offset[0] = begin;
- offset[1] = splitz[0];
- offset[2] = splity[0];
- offset[3] = splitz[1];
- offset[4] = splitx;
- offset[5] = splitz[2];
- offset[6] = splity[1];
- offset[7] = splitz[3];
-
- for (b = 0; b < 7; b++)
- count[b] = offset[b + 1] - offset[b];
- count[7] = end - offset[7];
-}
-
-static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth);
-
-static void *exec_occ_build(void *data)
-{
- OcclusionBuildThread *othread = (OcclusionBuildThread *)data;
-
- occ_build_recursive(othread->tree, othread->node, othread->begin, othread->end, othread->depth);
-
- return NULL;
-}
-
-static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth)
-{
- ListBase threads;
- OcclusionBuildThread othreads[BLENDER_MAX_THREADS];
- OccNode *child, tmpnode;
- /* OccFace *face; */
- int a, b, totthread = 0, offset[TOTCHILD], count[TOTCHILD];
-
- /* add a new node */
- node->occlusion = 1.0f;
-
- /* leaf node with only children */
- if (end - begin <= TOTCHILD) {
- for (a = begin, b = 0; a < end; a++, b++) {
- /* face= &tree->face[a]; */
- node->child[b].face = a;
- node->childflag |= (1 << b);
- }
- }
- else {
- /* order faces */
- occ_build_8_split(tree, begin, end, offset, count);
-
- if (depth == 1 && tree->dothreadedbuild)
- BLI_threadpool_init(&threads, exec_occ_build, tree->totbuildthread);
-
- for (b = 0; b < TOTCHILD; b++) {
- if (count[b] == 0) {
- node->child[b].node = NULL;
- }
- else if (count[b] == 1) {
- /* face= &tree->face[offset[b]]; */
- node->child[b].face = offset[b];
- node->childflag |= (1 << b);
- }
- else {
- if (tree->dothreadedbuild)
- BLI_thread_lock(LOCK_CUSTOM1);
-
- child = BLI_memarena_alloc(tree->arena, sizeof(OccNode));
- node->child[b].node = child;
-
- /* keep track of maximum depth for stack */
- if (depth >= tree->maxdepth)
- tree->maxdepth = depth + 1;
-
- if (tree->dothreadedbuild)
- BLI_thread_unlock(LOCK_CUSTOM1);
-
- if (depth == 1 && tree->dothreadedbuild) {
- othreads[totthread].tree = tree;
- othreads[totthread].node = child;
- othreads[totthread].begin = offset[b];
- othreads[totthread].end = offset[b] + count[b];
- othreads[totthread].depth = depth + 1;
- BLI_threadpool_insert(&threads, &othreads[totthread]);
- totthread++;
- }
- else
- occ_build_recursive(tree, child, offset[b], offset[b] + count[b], depth + 1);
- }
- }
-
- if (depth == 1 && tree->dothreadedbuild)
- BLI_threadpool_end(&threads);
- }
-
- /* combine area, position and sh */
- for (b = 0; b < TOTCHILD; b++) {
- if (node->childflag & (1 << b)) {
- child = &tmpnode;
- occ_node_from_face(tree->face + node->child[b].face, &tmpnode);
- }
- else {
- child = node->child[b].node;
- }
-
- if (child) {
- node->area += child->area;
- sh_add(node->sh, node->sh, child->sh);
- madd_v3_v3fl(node->co, child->co, child->area);
- }
- }
-
- if (node->area != 0.0f)
- mul_v3_fl(node->co, 1.0f / node->area);
-
- /* compute maximum distance from center */
- node->dco = 0.0f;
- if (node->area > 0.0f)
- occ_build_dco(tree, node, node->co, &node->dco);
-}
-
-static void occ_build_sh_normalize(OccNode *node)
-{
- /* normalize spherical harmonics to not include area, so
- * we can clamp the dot product and then multiply by area */
- int b;
-
- if (node->area != 0.0f)
- sh_mul(node->sh, 1.0f / node->area);
-
- for (b = 0; b < TOTCHILD; b++) {
- if (node->childflag & (1 << b)) {
- /* pass */
- }
- else if (node->child[b].node) {
- occ_build_sh_normalize(node->child[b].node);
- }
- }
-}
-
-static OcclusionTree *occ_tree_build(Render *re)
-{
- const int num_threads = re->r.threads;
- OcclusionTree *tree;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- Material *ma;
- VlakRen *vlr = NULL;
- int a, b, c, totface;
-
- /* count */
- totface = 0;
- for (obi = re->instancetable.first; obi; obi = obi->next) {
- obr = obi->obr;
- for (a = 0; a < obr->totvlak; a++) {
- if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
- else vlr++;
-
- ma = vlr->mat;
-
- if ((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE))
- totface++;
- }
- }
-
- if (totface == 0)
- return NULL;
-
- tree = MEM_callocN(sizeof(OcclusionTree), "OcclusionTree");
- tree->totface = totface;
-
- /* parameters */
- tree->error = get_render_aosss_error(&re->r, re->wrld.ao_approx_error);
- tree->distfac = (re->wrld.aomode & WO_AODIST) ? re->wrld.aodistfac : 0.0f;
- tree->doindirect = (re->wrld.ao_indirect_energy > 0.0f && re->wrld.ao_indirect_bounces > 0);
-
- /* allocation */
- tree->arena = BLI_memarena_new(0x8000 * sizeof(OccNode), "occ tree arena");
- BLI_memarena_use_calloc(tree->arena);
-
- if (re->wrld.aomode & WO_AOCACHE)
- tree->cache = MEM_callocN(sizeof(OcclusionCache) * num_threads, "OcclusionCache");
-
- tree->face = MEM_callocN(sizeof(OccFace) * totface, "OcclusionFace");
- tree->co = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionCo");
- tree->occlusion = MEM_callocN(sizeof(float) * totface, "OcclusionOcclusion");
-
- if (tree->doindirect)
- tree->rad = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionRad");
-
- /* make array of face pointers */
- for (b = 0, c = 0, obi = re->instancetable.first; obi; obi = obi->next, c++) {
- obr = obi->obr;
- for (a = 0; a < obr->totvlak; a++) {
- if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
- else vlr++;
-
- ma = vlr->mat;
-
- if ((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE)) {
- tree->face[b].obi = c;
- tree->face[b].facenr = a;
- tree->occlusion[b] = 1.0f;
- occ_face(&tree->face[b], tree->co[b], NULL, NULL);
- b++;
- }
- }
- }
-
- /* threads */
- tree->totbuildthread = (re->r.threads > 1 && totface > 10000) ? 8 : 1;
- tree->dothreadedbuild = (tree->totbuildthread > 1);
-
- /* recurse */
- tree->root = BLI_memarena_alloc(tree->arena, sizeof(OccNode));
- tree->maxdepth = 1;
- occ_build_recursive(tree, tree->root, 0, totface, 1);
-
- if (tree->doindirect) {
- if (!(re->test_break(re->tbh)))
- occ_build_shade(re, tree);
-
- if (!(re->test_break(re->tbh)))
- occ_sum_occlusion(tree, tree->root);
- }
-
- MEM_freeN(tree->co);
- tree->co = NULL;
-
- if (!(re->test_break(re->tbh)))
- occ_build_sh_normalize(tree->root);
-
- for (a = 0; a < num_threads; a++)
- tree->stack[a] = MEM_callocN(sizeof(OccNode) * TOTCHILD * (tree->maxdepth + 1), "OccStack");
-
- tree->num_threads = num_threads;
-
- return tree;
-}
-
-static void occ_free_tree(OcclusionTree *tree)
-{
- int a;
-
- if (tree) {
- if (tree->arena) BLI_memarena_free(tree->arena);
- for (a = 0; a < tree->num_threads; a++)
- if (tree->stack[a])
- MEM_freeN(tree->stack[a]);
- if (tree->occlusion) MEM_freeN(tree->occlusion);
- if (tree->cache) MEM_freeN(tree->cache);
- if (tree->face) MEM_freeN(tree->face);
- if (tree->rad) MEM_freeN(tree->rad);
- MEM_freeN(tree);
- }
-}
-
-/* ------------------------- Traversal --------------------------- */
-
-static float occ_solid_angle(OccNode *node, const float v[3], float d2, float invd2, const float receivenormal[3])
-{
- float dotreceive, dotemit;
- float ev[3];
-
- ev[0] = -v[0] * invd2;
- ev[1] = -v[1] * invd2;
- ev[2] = -v[2] * invd2;
- dotemit = sh_eval(node->sh, ev);
- dotreceive = dot_v3v3(receivenormal, v) * invd2;
-
- CLAMP(dotemit, 0.0f, 1.0f);
- CLAMP(dotreceive, 0.0f, 1.0f);
-
- return ((node->area * dotemit * dotreceive) / (d2 + node->area * INVPI)) * INVPI;
-}
-
-static float occ_form_factor(OccFace *face, float *p, float *n)
-{
- ObjectInstanceRen *obi;
- VlakRen *vlr;
- float v1[3], v2[3], v3[3], v4[3], q0[3], q1[3], q2[3], q3[3], contrib = 0.0f;
-
- obi = &R.objectinstance[face->obi];
- vlr = RE_findOrAddVlak(obi->obr, face->facenr);
-
- copy_v3_v3(v1, vlr->v1->co);
- copy_v3_v3(v2, vlr->v2->co);
- copy_v3_v3(v3, vlr->v3->co);
-
- if (obi->flag & R_TRANSFORMED) {
- mul_m4_v3(obi->mat, v1);
- mul_m4_v3(obi->mat, v2);
- mul_m4_v3(obi->mat, v3);
- }
-
- if (form_factor_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
- contrib += form_factor_quad(p, n, q0, q1, q2, q3);
-
- if (vlr->v4) {
- copy_v3_v3(v4, vlr->v4->co);
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, v4);
-
- if (form_factor_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
- contrib += form_factor_quad(p, n, q0, q1, q2, q3);
- }
-
- return contrib;
-}
-
-static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude,
- const float pp[3], const float pn[3], float *occ, float rad[3], float bentn[3])
-{
- OccNode *node, **stack;
- OccFace *face;
- float resultocc, resultrad[3], v[3], p[3], n[3], co[3], invd2;
- float distfac, fac, error, d2, weight, emitarea;
- int b, f, totstack;
-
- /* init variables */
- copy_v3_v3(p, pp);
- copy_v3_v3(n, pn);
- madd_v3_v3fl(p, n, 1e-4f);
-
- if (bentn)
- copy_v3_v3(bentn, n);
-
- error = tree->error;
- distfac = tree->distfac;
-
- resultocc = 0.0f;
- zero_v3(resultrad);
-
- /* init stack */
- stack = tree->stack[thread];
- stack[0] = tree->root;
- totstack = 1;
-
- while (totstack) {
- /* pop point off the stack */
- node = stack[--totstack];
-
- sub_v3_v3v3(v, node->co, p);
- d2 = dot_v3v3(v, v) + 1e-16f;
- emitarea = MAX2(node->area, node->dco);
-
- if (d2 * error > emitarea) {
- if (distfac != 0.0f) {
- fac = 1.0f / (1.0f + distfac * d2);
- if (fac < 0.01f)
- continue;
- }
- else
- fac = 1.0f;
-
- /* accumulate occlusion from spherical harmonics */
- invd2 = 1.0f / sqrtf(d2);
- weight = occ_solid_angle(node, v, d2, invd2, n);
-
- if (rad)
- madd_v3_v3fl(resultrad, node->rad, weight * fac);
-
- weight *= node->occlusion;
-
- if (bentn) {
- bentn[0] -= weight * invd2 * v[0];
- bentn[1] -= weight * invd2 * v[1];
- bentn[2] -= weight * invd2 * v[2];
- }
-
- resultocc += weight * fac;
- }
- else {
- /* traverse into children */
- for (b = 0; b < TOTCHILD; b++) {
- if (node->childflag & (1 << b)) {
- f = node->child[b].face;
- face = &tree->face[f];
-
- /* accumulate occlusion with face form factor */
- if (!exclude || !(face->obi == exclude->obi && face->facenr == exclude->facenr)) {
- if (bentn || distfac != 0.0f) {
- occ_face(face, co, NULL, NULL);
- sub_v3_v3v3(v, co, p);
- d2 = dot_v3v3(v, v) + 1e-16f;
-
- fac = (distfac == 0.0f) ? 1.0f : 1.0f / (1.0f + distfac * d2);
- if (fac < 0.01f)
- continue;
- }
- else
- fac = 1.0f;
-
- weight = occ_form_factor(face, p, n);
-
- if (rad)
- madd_v3_v3fl(resultrad, tree->rad[f], weight * fac);
-
- weight *= tree->occlusion[f];
-
- if (bentn) {
- invd2 = 1.0f / sqrtf(d2);
- bentn[0] -= weight * invd2 * v[0];
- bentn[1] -= weight * invd2 * v[1];
- bentn[2] -= weight * invd2 * v[2];
- }
-
- resultocc += weight * fac;
- }
- }
- else if (node->child[b].node) {
- /* push child on the stack */
- stack[totstack++] = node->child[b].node;
- }
- }
- }
- }
-
- if (occ) *occ = resultocc;
- if (rad) copy_v3_v3(rad, resultrad);
-#if 0
- if (rad && exclude) {
- int a;
- for (a = 0; a < tree->totface; a++)
- if ((tree->face[a].obi == exclude->obi && tree->face[a].facenr == exclude->facenr))
- copy_v3_v3(rad, tree->rad[a]);
- }
-#endif
- if (bentn) normalize_v3(bentn);
-}
-
-static void occ_compute_bounces(Render *re, OcclusionTree *tree, int totbounce)
-{
- float (*rad)[3], (*sum)[3], (*tmp)[3], co[3], n[3], occ;
- int bounce, i;
-
- rad = MEM_callocN(sizeof(float) * 3 * tree->totface, "OcclusionBounceRad");
- sum = MEM_dupallocN(tree->rad);
-
- for (bounce = 1; bounce < totbounce; bounce++) {
- for (i = 0; i < tree->totface; i++) {
- occ_face(&tree->face[i], co, n, NULL);
- madd_v3_v3fl(co, n, 1e-8f);
-
- occ_lookup(tree, 0, &tree->face[i], co, n, &occ, rad[i], NULL);
- rad[i][0] = MAX2(rad[i][0], 0.0f);
- rad[i][1] = MAX2(rad[i][1], 0.0f);
- rad[i][2] = MAX2(rad[i][2], 0.0f);
- add_v3_v3(sum[i], rad[i]);
-
- if (re->test_break(re->tbh))
- break;
- }
-
- if (re->test_break(re->tbh))
- break;
-
- tmp = tree->rad;
- tree->rad = rad;
- rad = tmp;
-
- occ_sum_occlusion(tree, tree->root);
- }
-
- MEM_freeN(rad);
- MEM_freeN(tree->rad);
- tree->rad = sum;
-
- if (!re->test_break(re->tbh))
- occ_sum_occlusion(tree, tree->root);
-}
-
-static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass)
-{
- float *occ, co[3], n[3];
- int pass, i;
-
- occ = MEM_callocN(sizeof(float) * tree->totface, "OcclusionPassOcc");
-
- for (pass = 0; pass < totpass; pass++) {
- for (i = 0; i < tree->totface; i++) {
- occ_face(&tree->face[i], co, n, NULL);
- negate_v3(n);
- madd_v3_v3fl(co, n, 1e-8f);
-
- occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL, NULL);
- if (re->test_break(re->tbh))
- break;
- }
-
- if (re->test_break(re->tbh))
- break;
-
- for (i = 0; i < tree->totface; i++) {
- tree->occlusion[i] -= occ[i]; //MAX2(1.0f-occ[i], 0.0f);
- if (tree->occlusion[i] < 0.0f)
- tree->occlusion[i] = 0.0f;
- }
-
- occ_sum_occlusion(tree, tree->root);
- }
-
- MEM_freeN(occ);
-}
-
-static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude,
- const float co[3], const float n[3], int thread, int onlyshadow,
- float *ao, float *env, float *indirect)
-{
- float nn[3], bn[3], fac, occ, occlusion, correction, rad[3];
- int envcolor;
-
- envcolor = re->wrld.aocolor;
- if (onlyshadow)
- envcolor = WO_AOPLAIN;
-
- negate_v3_v3(nn, n);
-
- occ_lookup(tree, thread, exclude, co, nn, &occ, (tree->doindirect) ? rad : NULL, (env && envcolor) ? bn : NULL);
-
- correction = re->wrld.ao_approx_correction;
-
- occlusion = (1.0f - correction) * (1.0f - occ);
- CLAMP(occlusion, 0.0f, 1.0f);
- if (correction != 0.0f)
- occlusion += correction * expf(-occ);
-
- if (env) {
- /* sky shading using bent normal */
- if (ELEM(envcolor, WO_AOSKYCOL, WO_AOSKYTEX)) {
- fac = 0.5f * (1.0f + dot_v3v3(bn, re->grvec));
- env[0] = (1.0f - fac) * re->wrld.horr + fac * re->wrld.zenr;
- env[1] = (1.0f - fac) * re->wrld.horg + fac * re->wrld.zeng;
- env[2] = (1.0f - fac) * re->wrld.horb + fac * re->wrld.zenb;
-
- mul_v3_fl(env, occlusion);
- }
- else {
- env[0] = occlusion;
- env[1] = occlusion;
- env[2] = occlusion;
- }
-#if 0
- else { /* WO_AOSKYTEX */
- float dxyview[3];
- bn[0] = -bn[0];
- bn[1] = -bn[1];
- bn[2] = -bn[2];
- dxyview[0] = 1.0f;
- dxyview[1] = 1.0f;
- dxyview[2] = 0.0f;
- shadeSkyView(ao, co, bn, dxyview);
- }
-#endif
- }
-
- if (ao) {
- ao[0] = occlusion;
- ao[1] = occlusion;
- ao[2] = occlusion;
- }
-
- if (tree->doindirect) copy_v3_v3(indirect, rad);
- else zero_v3(indirect);
-}
-
-/* ---------------------------- Caching ------------------------------- */
-
-static OcclusionCacheSample *find_occ_sample(OcclusionCache *cache, int x, int y)
-{
- x -= cache->x;
- y -= cache->y;
-
- x /= cache->step;
- y /= cache->step;
- x *= cache->step;
- y *= cache->step;
-
- if (x < 0 || x >= cache->w || y < 0 || y >= cache->h)
- return NULL;
- else
- return &cache->sample[y * cache->w + x];
-}
-
-static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *ao, float *env, float *indirect)
-{
- OcclusionCache *cache;
- OcclusionCacheSample *samples[4], *sample;
- float wn[4], wz[4], wb[4], tx, ty, w, totw, mino, maxo;
- float d[3], dist2;
- int i, x1, y1, x2, y2;
-
- if (!tree->cache)
- return 0;
-
- /* first try to find a sample in the same pixel */
- cache = &tree->cache[thread];
-
- if (cache->sample && cache->step) {
- sample = &cache->sample[(y - cache->y) * cache->w + (x - cache->x)];
- if (sample->filled) {
- sub_v3_v3v3(d, sample->co, co);
- dist2 = dot_v3v3(d, d);
- if (dist2 < 0.5f * sample->dist2 && dot_v3v3(sample->n, n) > 0.98f) {
- copy_v3_v3(ao, sample->ao);
- copy_v3_v3(env, sample->env);
- copy_v3_v3(indirect, sample->indirect);
- return 1;
- }
- }
- }
- else
- return 0;
-
- /* try to interpolate between 4 neighboring pixels */
- samples[0] = find_occ_sample(cache, x, y);
- samples[1] = find_occ_sample(cache, x + cache->step, y);
- samples[2] = find_occ_sample(cache, x, y + cache->step);
- samples[3] = find_occ_sample(cache, x + cache->step, y + cache->step);
-
- for (i = 0; i < 4; i++)
- if (!samples[i] || !samples[i]->filled)
- return 0;
-
- /* require intensities not being too different */
- mino = min_ffff(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity);
- maxo = max_ffff(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity);
-
- if (maxo - mino > 0.05f)
- return 0;
-
- /* compute weighted interpolation between samples */
- zero_v3(ao);
- zero_v3(env);
- zero_v3(indirect);
- totw = 0.0f;
-
- x1 = samples[0]->x;
- y1 = samples[0]->y;
- x2 = samples[3]->x;
- y2 = samples[3]->y;
-
- tx = (float)(x2 - x) / (float)(x2 - x1);
- ty = (float)(y2 - y) / (float)(y2 - y1);
-
- wb[3] = (1.0f - tx) * (1.0f - ty);
- wb[2] = (tx) * (1.0f - ty);
- wb[1] = (1.0f - tx) * (ty);
- wb[0] = tx * ty;
-
- for (i = 0; i < 4; i++) {
- sub_v3_v3v3(d, samples[i]->co, co);
- //dist2 = dot_v3v3(d, d);
-
- wz[i] = 1.0f; //(samples[i]->dist2/(1e-4f + dist2));
- wn[i] = pow(dot_v3v3(samples[i]->n, n), 32.0f);
-
- w = wb[i] * wn[i] * wz[i];
-
- totw += w;
- madd_v3_v3fl(ao, samples[i]->ao, w);
- madd_v3_v3fl(env, samples[i]->env, w);
- madd_v3_v3fl(indirect, samples[i]->indirect, w);
- }
-
- if (totw >= 0.9f) {
- totw = 1.0f / totw;
- mul_v3_fl(ao, totw);
- mul_v3_fl(env, totw);
- mul_v3_fl(indirect, totw);
- return 1;
- }
-
- return 0;
-}
-
-static void sample_occ_surface(ShadeInput *shi)
-{
- StrandRen *strand = shi->strand;
- StrandSurface *mesh = strand->buffer->surface;
- const int *face, *index = RE_strandren_get_face(shi->obr, strand, 0);
- float w[4], *co1, *co2, *co3, *co4;
-
- if (mesh && mesh->face && mesh->co && mesh->ao && index) {
- face = mesh->face[*index];
-
- co1 = mesh->co[face[0]];
- co2 = mesh->co[face[1]];
- co3 = mesh->co[face[2]];
-
- if (face[3]) {
- co4 = mesh->co[face[3]];
- interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
- }
- else {
- interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
- }
-
- zero_v3(shi->ao);
- zero_v3(shi->env);
- zero_v3(shi->indirect);
-
- madd_v3_v3fl(shi->ao, mesh->ao[face[0]], w[0]);
- madd_v3_v3fl(shi->env, mesh->env[face[0]], w[0]);
- madd_v3_v3fl(shi->indirect, mesh->indirect[face[0]], w[0]);
- madd_v3_v3fl(shi->ao, mesh->ao[face[1]], w[1]);
- madd_v3_v3fl(shi->env, mesh->env[face[1]], w[1]);
- madd_v3_v3fl(shi->indirect, mesh->indirect[face[1]], w[1]);
- madd_v3_v3fl(shi->ao, mesh->ao[face[2]], w[2]);
- madd_v3_v3fl(shi->env, mesh->env[face[2]], w[2]);
- madd_v3_v3fl(shi->indirect, mesh->indirect[face[2]], w[2]);
- if (face[3]) {
- madd_v3_v3fl(shi->ao, mesh->ao[face[3]], w[3]);
- madd_v3_v3fl(shi->env, mesh->env[face[3]], w[3]);
- madd_v3_v3fl(shi->indirect, mesh->indirect[face[3]], w[3]);
- }
- }
- else {
- shi->ao[0] = 1.0f;
- shi->ao[1] = 1.0f;
- shi->ao[2] = 1.0f;
- zero_v3(shi->env);
- zero_v3(shi->indirect);
- }
-}
-
-/* ------------------------- External Functions --------------------------- */
-
-static void *exec_strandsurface_sample(void *data)
-{
- OcclusionThread *othread = (OcclusionThread *)data;
- Render *re = othread->re;
- StrandSurface *mesh = othread->mesh;
- float ao[3], env[3], indirect[3], co[3], n[3], *co1, *co2, *co3, *co4;
- int a, *face;
-
- for (a = othread->begin; a < othread->end; a++) {
- face = mesh->face[a];
- co1 = mesh->co[face[0]];
- co2 = mesh->co[face[1]];
- co3 = mesh->co[face[2]];
-
- if (face[3]) {
- co4 = mesh->co[face[3]];
-
- mid_v3_v3v3(co, co1, co3);
- normal_quad_v3(n, co1, co2, co3, co4);
- }
- else {
- mid_v3_v3v3v3(co, co1, co2, co3);
- normal_tri_v3(n, co1, co2, co3);
- }
- negate_v3(n);
-
- sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, env, indirect);
- copy_v3_v3(othread->faceao[a], ao);
- copy_v3_v3(othread->faceenv[a], env);
- copy_v3_v3(othread->faceindirect[a], indirect);
- }
-
- return NULL;
-}
-
-void make_occ_tree(Render *re)
-{
- OcclusionThread othreads[BLENDER_MAX_THREADS];
- OcclusionTree *tree;
- StrandSurface *mesh;
- ListBase threads;
- float ao[3], env[3], indirect[3], (*faceao)[3], (*faceenv)[3], (*faceindirect)[3];
- int a, totface, totthread, *face, *count;
-
- /* ugly, needed for occ_face */
- R = *re;
-
- re->i.infostr = IFACE_("Occlusion preprocessing");
- re->stats_draw(re->sdh, &re->i);
-
- re->occlusiontree = tree = occ_tree_build(re);
-
- if (tree && !re->test_break(re->tbh)) {
- if (re->wrld.ao_approx_passes > 0)
- occ_compute_passes(re, tree, re->wrld.ao_approx_passes);
- if (tree->doindirect && (re->wrld.mode & WO_INDIRECT_LIGHT))
- occ_compute_bounces(re, tree, re->wrld.ao_indirect_bounces);
-
- for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) {
- if (!mesh->face || !mesh->co || !mesh->ao)
- continue;
-
- count = MEM_callocN(sizeof(int) * mesh->totvert, "OcclusionCount");
- faceao = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceAO");
- faceenv = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceEnv");
- faceindirect = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceIndirect");
-
- totthread = (mesh->totface > 10000) ? re->r.threads : 1;
- totface = mesh->totface / totthread;
- for (a = 0; a < totthread; a++) {
- othreads[a].re = re;
- othreads[a].faceao = faceao;
- othreads[a].faceenv = faceenv;
- othreads[a].faceindirect = faceindirect;
- othreads[a].thread = a;
- othreads[a].mesh = mesh;
- othreads[a].begin = a * totface;
- othreads[a].end = (a == totthread - 1) ? mesh->totface : (a + 1) * totface;
- }
-
- if (totthread == 1) {
- exec_strandsurface_sample(&othreads[0]);
- }
- else {
- BLI_threadpool_init(&threads, exec_strandsurface_sample, totthread);
-
- for (a = 0; a < totthread; a++)
- BLI_threadpool_insert(&threads, &othreads[a]);
-
- BLI_threadpool_end(&threads);
- }
-
- for (a = 0; a < mesh->totface; a++) {
- face = mesh->face[a];
-
- copy_v3_v3(ao, faceao[a]);
- copy_v3_v3(env, faceenv[a]);
- copy_v3_v3(indirect, faceindirect[a]);
-
- add_v3_v3(mesh->ao[face[0]], ao);
- add_v3_v3(mesh->env[face[0]], env);
- add_v3_v3(mesh->indirect[face[0]], indirect);
- count[face[0]]++;
- add_v3_v3(mesh->ao[face[1]], ao);
- add_v3_v3(mesh->env[face[1]], env);
- add_v3_v3(mesh->indirect[face[1]], indirect);
- count[face[1]]++;
- add_v3_v3(mesh->ao[face[2]], ao);
- add_v3_v3(mesh->env[face[2]], env);
- add_v3_v3(mesh->indirect[face[2]], indirect);
- count[face[2]]++;
-
- if (face[3]) {
- add_v3_v3(mesh->ao[face[3]], ao);
- add_v3_v3(mesh->env[face[3]], env);
- add_v3_v3(mesh->indirect[face[3]], indirect);
- count[face[3]]++;
- }
- }
-
- for (a = 0; a < mesh->totvert; a++) {
- if (count[a]) {
- mul_v3_fl(mesh->ao[a], 1.0f / count[a]);
- mul_v3_fl(mesh->env[a], 1.0f / count[a]);
- mul_v3_fl(mesh->indirect[a], 1.0f / count[a]);
- }
- }
-
- MEM_freeN(count);
- MEM_freeN(faceao);
- MEM_freeN(faceenv);
- MEM_freeN(faceindirect);
- }
- }
-}
-
-void free_occ(Render *re)
-{
- if (re->occlusiontree) {
- occ_free_tree(re->occlusiontree);
- re->occlusiontree = NULL;
- }
-}
-
-void sample_occ(Render *re, ShadeInput *shi)
-{
- OcclusionTree *tree = re->occlusiontree;
- OcclusionCache *cache;
- OcclusionCacheSample *sample;
- OccFace exclude;
- int onlyshadow;
-
- if (tree) {
- if (shi->strand) {
- sample_occ_surface(shi);
- }
- /* try to get result from the cache if possible */
- else if (shi->depth != 0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao, shi->env, shi->indirect)) {
- /* no luck, let's sample the occlusion */
- exclude.obi = shi->obi - re->objectinstance;
- exclude.facenr = shi->vlr->index;
- onlyshadow = (shi->mat->mode & MA_ONLYSHADOW);
- sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect);
-
- /* fill result into sample, each time */
- if (tree->cache) {
- cache = &tree->cache[shi->thread];
-
- if (cache->sample && cache->step) {
- sample = &cache->sample[(shi->ys - cache->y) * cache->w + (shi->xs - cache->x)];
- copy_v3_v3(sample->co, shi->co);
- copy_v3_v3(sample->n, shi->vno);
- copy_v3_v3(sample->ao, shi->ao);
- copy_v3_v3(sample->env, shi->env);
- copy_v3_v3(sample->indirect, shi->indirect);
- sample->intensity = max_fff(sample->ao[0], sample->ao[1], sample->ao[2]);
- sample->intensity = max_ff(sample->intensity, max_fff(sample->env[0], sample->env[1], sample->env[2]));
- sample->intensity = max_ff(sample->intensity, max_fff(sample->indirect[0], sample->indirect[1], sample->indirect[2]));
- sample->dist2 = dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco);
- sample->filled = 1;
- }
- }
- }
- }
- else {
- shi->ao[0] = 1.0f;
- shi->ao[1] = 1.0f;
- shi->ao[2] = 1.0f;
-
- shi->env[0] = 0.0f;
- shi->env[1] = 0.0f;
- shi->env[2] = 0.0f;
-
- shi->indirect[0] = 0.0f;
- shi->indirect[1] = 0.0f;
- shi->indirect[2] = 0.0f;
- }
-}
-
-void cache_occ_samples(Render *re, RenderPart *pa, ShadeSample *ssamp)
-{
- OcclusionTree *tree = re->occlusiontree;
- PixStr ps;
- OcclusionCache *cache;
- OcclusionCacheSample *sample;
- OccFace exclude;
- ShadeInput *shi;
- intptr_t *rd = NULL;
- int *ro = NULL, *rp = NULL, *rz = NULL, onlyshadow;
- int x, y, step = CACHE_STEP;
-
- if (!tree->cache)
- return;
-
- cache = &tree->cache[pa->thread];
- cache->w = pa->rectx;
- cache->h = pa->recty;
- cache->x = pa->disprect.xmin;
- cache->y = pa->disprect.ymin;
- cache->step = step;
- cache->sample = MEM_callocN(sizeof(OcclusionCacheSample) * cache->w * cache->h, "OcclusionCacheSample");
- sample = cache->sample;
-
- if (re->osa) {
- rd = pa->rectdaps;
- }
- else {
- /* fake pixel struct for non-osa */
- ps.next = NULL;
- ps.mask = 0xFFFF;
-
- ro = pa->recto;
- rp = pa->rectp;
- rz = pa->rectz;
- }
-
- /* compute a sample at every step pixels */
- for (y = pa->disprect.ymin; y < pa->disprect.ymax; y++) {
- for (x = pa->disprect.xmin; x < pa->disprect.xmax; x++, sample++, rd++, ro++, rp++, rz++) {
- if (!(((x - pa->disprect.xmin + step) % step) == 0 || x == pa->disprect.xmax - 1))
- continue;
- if (!(((y - pa->disprect.ymin + step) % step) == 0 || y == pa->disprect.ymax - 1))
- continue;
-
- if (re->osa) {
- if (!*rd) continue;
-
- shade_samples_fill_with_ps(ssamp, (PixStr *)(*rd), x, y);
- }
- else {
- if (!*rp) continue;
-
- ps.obi = *ro;
- ps.facenr = *rp;
- ps.z = *rz;
- shade_samples_fill_with_ps(ssamp, &ps, x, y);
- }
-
- shi = ssamp->shi;
- if (shi->vlr) {
- onlyshadow = (shi->mat->mode & MA_ONLYSHADOW);
- exclude.obi = shi->obi - re->objectinstance;
- exclude.facenr = shi->vlr->index;
- sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect);
-
- copy_v3_v3(sample->co, shi->co);
- copy_v3_v3(sample->n, shi->vno);
- copy_v3_v3(sample->ao, shi->ao);
- copy_v3_v3(sample->env, shi->env);
- copy_v3_v3(sample->indirect, shi->indirect);
- sample->intensity = max_fff(sample->ao[0], sample->ao[1], sample->ao[2]);
- sample->intensity = max_ff(sample->intensity, max_fff(sample->env[0], sample->env[1], sample->env[2]));
- sample->intensity = max_ff(sample->intensity, max_fff(sample->indirect[0], sample->indirect[1], sample->indirect[2]));
- sample->dist2 = dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco);
- sample->x = shi->xs;
- sample->y = shi->ys;
- sample->filled = 1;
- }
-
- if (re->test_break(re->tbh))
- break;
- }
- }
-}
-
-void free_occ_samples(Render *re, RenderPart *pa)
-{
- OcclusionTree *tree = re->occlusiontree;
- OcclusionCache *cache;
-
- if (tree->cache) {
- cache = &tree->cache[pa->thread];
-
- if (cache->sample)
- MEM_freeN(cache->sample);
-
- cache->w = 0;
- cache->h = 0;
- cache->step = 0;
- }
-}
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 4f2f8d67f45..a30a72d9dc8 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -37,7 +37,7 @@
#include <errno.h>
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_image_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -64,21 +64,25 @@
#include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */
#include "BKE_camera.h"
#include "BKE_colortools.h"
-#include "BKE_depsgraph.h"
+#include "BKE_context.h" /* XXX needed by wm_window.h */
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
-#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
+#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
-#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "PIL_time.h"
#include "IMB_colormanagement.h"
@@ -88,6 +92,11 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
+#include "RE_render_ext.h"
+
+#include "../../../windowmanager/WM_api.h" /* XXX */
+#include "../../../windowmanager/wm_window.h" /* XXX */
+#include "GPU_context.h"
#ifdef WITH_FREESTYLE
# include "FRS_freestyle.h"
@@ -96,14 +105,10 @@
#include "DEG_depsgraph.h"
/* internal */
+#include "initrender.h"
+#include "renderpipeline.h"
#include "render_result.h"
#include "render_types.h"
-#include "renderpipeline.h"
-#include "renderdatabase.h"
-#include "rendercore.h"
-#include "initrender.h"
-#include "pixelblending.h"
-#include "zbuf.h"
/* render flow
*
@@ -138,19 +143,10 @@ static struct {
ListBase renderlist;
} RenderGlobal = {{NULL, NULL}};
-/* hardcopy of current render, used while rendering for speed */
-Render R;
-
/* ********* alloc and free ******** */
static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const int totvideos, const char *name_override);
-static volatile int g_break = 0;
-static int thread_break(void *UNUSED(arg))
-{
- return g_break;
-}
-
/* default callbacks, set in each new render */
static void result_nothing(void *UNUSED(arg), RenderResult *UNUSED(rr)) {}
static void result_rcti_nothing(void *UNUSED(arg), RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect)) {}
@@ -271,11 +267,11 @@ RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool
RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
{
- SceneRenderLayer *srl = BLI_findlink(&re->r.layers, re->r.actlay);
+ ViewLayer *view_layer = BLI_findlink(&re->view_layers, re->active_view_layer);
- if (srl) {
+ if (view_layer) {
RenderLayer *rl = BLI_findstring(&rr->layers,
- srl->name,
+ view_layer->name,
offsetof(RenderLayer, name));
if (rl) {
@@ -286,23 +282,15 @@ RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
return rr->layers.first;
}
-static int render_scene_needs_vector(Render *re)
+static bool render_scene_has_layers_to_render(Scene *scene, ViewLayer *single_layer)
{
- SceneRenderLayer *srl;
-
- for (srl = re->r.layers.first; srl; srl = srl->next)
- if (!(srl->layflag & SCE_LAY_DISABLE))
- if (srl->passflag & SCE_PASS_VECTOR)
- return 1;
-
- return 0;
-}
+ if (single_layer) {
+ return true;
+ }
-static bool render_scene_has_layers_to_render(Scene *scene)
-{
- SceneRenderLayer *srl;
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
- if (!(srl->layflag & SCE_LAY_DISABLE)) {
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (view_layer->flag & VIEW_LAYER_RENDER) {
return true;
}
}
@@ -344,6 +332,14 @@ RenderResult *RE_AcquireResultWrite(Render *re)
return NULL;
}
+void RE_ClearResult(Render *re)
+{
+ if (re) {
+ render_result_free(re->result);
+ re->result = NULL;
+ }
+}
+
void RE_SwapResult(Render *re, RenderResult **rr)
{
/* for keeping render buffers */
@@ -367,6 +363,13 @@ Scene *RE_GetScene(Render *re)
return NULL;
}
+void RE_SetScene(Render *re, Scene* sce)
+{
+ if (re) {
+ re->scene = sce;
+ }
+}
+
/**
* Same as #RE_AcquireResultImage but creating the necessary views to store the result
* fill provided result struct with a copy of thew views of what is done so far the
@@ -518,14 +521,10 @@ Render *RE_NewRender(const char *name)
BLI_strncpy(re->name, name, RE_MAXNAME);
BLI_rw_mutex_init(&re->resultmutex);
BLI_rw_mutex_init(&re->partsmutex);
- re->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
}
RE_InitRenderCB(re);
- /* init some variables */
- re->ycor = 1.0f;
-
return re;
}
@@ -587,7 +586,7 @@ void RE_FreeRender(Render *re)
BLI_rw_mutex_end(&re->resultmutex);
BLI_rw_mutex_end(&re->partsmutex);
- BLI_freelistN(&re->r.layers);
+ BLI_freelistN(&re->view_layers);
BLI_freelistN(&re->r.views);
curvemapping_free_data(&re->r.mblur_shutter_curve);
@@ -596,14 +595,10 @@ void RE_FreeRender(Render *re)
re->main = NULL;
re->scene = NULL;
- RE_Database_Free(re); /* view render can still have full database */
- free_sample_tables(re);
-
render_result_free(re->result);
render_result_free(re->pushedresult);
BLI_remlink(&RenderGlobal.renderlist, re);
- MEM_freeN(re->eval_ctx);
MEM_freeN(re);
}
@@ -668,14 +663,8 @@ static int check_mode_full_sample(RenderData *rd)
{
int scemode = rd->scemode;
- if (!STREQ(rd->engine, RE_engine_id_BLENDER_RENDER) &&
- !STREQ(rd->engine, RE_engine_id_BLENDER_GAME))
- {
- scemode &= ~R_FULL_SAMPLE;
- }
-
- if ((rd->mode & R_OSA) == 0)
- scemode &= ~R_FULL_SAMPLE;
+ /* not supported by any current renderer */
+ scemode &= ~R_FULL_SAMPLE;
#ifdef WITH_OPENEXR
if (scemode & R_FULL_SAMPLE)
@@ -695,7 +684,7 @@ static void re_init_resolution(Render *re, Render *source,
re->winy = winy;
if (source && (source->r.mode & R_BORDER)) {
/* eeh, doesn't seem original bordered disprect is storing anywhere
- * after insertion on black happening in do_render_fields_blur_3d(),
+ * after insertion on black happening in do_render(),
* so for now simply re-calculate disprect using border from source
* renderer (sergey)
*/
@@ -724,20 +713,15 @@ static void re_init_resolution(Render *re, Render *source,
re->rectx = winx;
re->recty = winy;
}
-
- /* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
- re->clipcrop = 1.0f + 2.0f / (float)(re->winx > re->winy ? re->winy : re->winx);
}
void render_copy_renderdata(RenderData *to, RenderData *from)
{
- BLI_freelistN(&to->layers);
BLI_freelistN(&to->views);
curvemapping_free_data(&to->mblur_shutter_curve);
*to = *from;
- BLI_duplicatelist(&to->layers, &from->layers);
BLI_duplicatelist(&to->views, &from->views);
curvemapping_copy_data(&to->mblur_shutter_curve, &from->mblur_shutter_curve);
}
@@ -745,7 +729,7 @@ void render_copy_renderdata(RenderData *to, RenderData *from)
/* what doesn't change during entire render sequence */
/* disprect is optional, if NULL it assumes full window render */
void RE_InitState(Render *re, Render *source, RenderData *rd,
- SceneRenderLayer *srl,
+ ListBase *render_layers, ViewLayer *single_layer,
int winx, int winy, rcti *disprect)
{
bool had_freestyle = (re->r.mode & R_EDGE_FRS) != 0;
@@ -756,6 +740,9 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
/* copy render data and render layers for thread safety */
render_copy_renderdata(&re->r, rd);
+ BLI_freelistN(&re->view_layers);
+ BLI_duplicatelist(&re->view_layers, render_layers);
+ re->active_view_layer = 0;
if (source) {
/* reuse border flags from source renderer */
@@ -787,50 +774,30 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.scemode = check_mode_full_sample(&re->r);
- /* fullsample wants uniform osa levels */
- if (source && (re->r.scemode & R_FULL_SAMPLE)) {
- /* but, if source has no full sample we disable it */
- if ((source->r.scemode & R_FULL_SAMPLE) == 0)
- re->r.scemode &= ~R_FULL_SAMPLE;
- else
- re->r.osa = re->osa = source->osa;
- }
- else {
- /* check state variables, osa? */
- if (re->r.mode & (R_OSA)) {
- re->osa = re->r.osa;
- if (re->osa > 16) re->osa = 16;
- }
- else re->osa = 0;
- }
-
- if (srl) {
- int index = BLI_findindex(&rd->layers, srl);
+ if (single_layer) {
+ int index = BLI_findindex(render_layers, single_layer);
if (index != -1) {
- re->r.actlay = index;
+ re->active_view_layer = index;
re->r.scemode |= R_SINGLE_LAYER;
}
}
- /* always call, checks for gamma, gamma tables and jitter too */
- make_sample_tables(re);
-
/* if preview render, we try to keep old result */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- if (re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)) {
+ if (re->r.scemode & R_BUTS_PREVIEW) {
if (had_freestyle || (re->r.mode & R_EDGE_FRS)) {
/* freestyle manipulates render layers so always have to free */
render_result_free(re->result);
re->result = NULL;
}
else if (re->result) {
- SceneRenderLayer *actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
+ ViewLayer *active_render_layer = BLI_findlink(&re->view_layers, re->active_view_layer);
RenderLayer *rl;
bool have_layer = false;
for (rl = re->result->layers.first; rl; rl = rl->next)
- if (STREQ(rl->name, actsrl->name))
+ if (STREQ(rl->name, active_render_layer->name))
have_layer = true;
if (re->result->rectx == re->rectx && re->result->recty == re->recty &&
@@ -856,19 +823,14 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
render_result_view_new(re->result, "");
}
- if (re->r.scemode & R_VIEWPORT_PREVIEW)
- re->eval_ctx->mode = DAG_EVAL_PREVIEW;
- else
- re->eval_ctx->mode = DAG_EVAL_RENDER;
-
/* ensure renderdatabase can use part settings correct */
RE_parts_clamp(re);
BLI_rw_mutex_unlock(&re->resultmutex);
- re->mblur_offs = re->field_offs = 0.f;
-
RE_init_threadcount(re);
+
+ RE_point_density_fix_linking();
}
/* This function is only called by view3d rendering, which doesn't support
@@ -955,13 +917,12 @@ void RE_ChangeModeFlag(Render *re, int flag, bool clear)
/* update some variables that can be animated, and otherwise wouldn't be due to
* RenderData getting copied once at the start of animation render */
-void render_update_anim_renderdata(Render *re, RenderData *rd)
+void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_layers)
{
/* filter */
re->r.gauss = rd->gauss;
/* motion blur */
- re->r.mblur_samples = rd->mblur_samples;
re->r.blurfac = rd->blurfac;
/* freestyle */
@@ -969,8 +930,8 @@ void render_update_anim_renderdata(Render *re, RenderData *rd)
re->r.unit_line_thickness = rd->unit_line_thickness;
/* render layers */
- BLI_freelistN(&re->r.layers);
- BLI_duplicatelist(&re->r.layers, &rd->layers);
+ BLI_freelistN(&re->view_layers);
+ BLI_duplicatelist(&re->view_layers, render_layers);
/* render views */
BLI_freelistN(&re->r.views);
@@ -984,7 +945,6 @@ void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipen
re->viewplane = *viewplane;
re->clipsta = clipsta;
re->clipend = clipend;
- re->r.mode &= ~R_ORTHO;
perspective_m4(re->winmat,
re->viewplane.xmin, re->viewplane.xmax,
@@ -999,7 +959,6 @@ void RE_SetOrtho(Render *re, const rctf *viewplane, float clipsta, float clipend
re->viewplane = *viewplane;
re->clipsta = clipsta;
re->clipend = clipend;
- re->r.mode |= R_ORTHO;
orthographic_m4(re->winmat,
re->viewplane.xmin, re->viewplane.xmax,
@@ -1075,447 +1034,57 @@ void RE_test_break_cb(Render *re, void *handle, int (*f)(void *handle))
re->tbh = handle;
}
+/* ********* GL Context ******** */
-/* ********* add object data (later) ******** */
-
-/* object is considered fully prepared on correct time etc */
-/* includes lights */
-#if 0
-void RE_AddObject(Render *UNUSED(re), Object *UNUSED(ob))
+void RE_gl_context_create(Render *re)
{
-
+ /* Needs to be created in the main ogl thread. */
+ re->gl_context = WM_opengl_context_create();
+ /* So we activate the window's one afterwards. */
+ wm_window_reset_drawable();
}
-#endif
-/* *************************************** */
-
-static int render_display_update_enabled(Render *re)
+void RE_gl_context_destroy(Render *re)
{
- /* don't show preprocess for previewrender sss */
- if (re->sss_points)
- return !(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW));
- else
- return 1;
-}
-
-/* the main thread call, renders an entire part */
-static void *do_part_thread(void *pa_v)
-{
- RenderPart *pa = pa_v;
-
- pa->status = PART_STATUS_IN_PROGRESS;
-
- /* need to return nicely all parts on esc */
- if (R.test_break(R.tbh) == 0) {
-
- if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE))
- pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM, R.viewname);
- else
- pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS, R.viewname);
-
- /* Copy EXR tile settings, so pipeline knows whether this is a result
- * for Save Buffers enabled rendering.
- *
- * TODO(sergey): This actually duplicates logic with external engine, so
- * worth looking into more generic solution.
- */
- pa->result->do_exr_tile = R.result->do_exr_tile;
-
- if (R.sss_points)
- zbufshade_sss_tile(pa);
- else if (R.osa)
- zbufshadeDA_tile(pa);
- else
- zbufshade_tile(pa);
-
- /* we do actually write pixels, but don't allocate/deallocate anything,
- * so it is safe with other threads reading at the same time */
- BLI_rw_mutex_lock(&R.resultmutex, THREAD_LOCK_READ);
-
- /* merge too on break! */
- if (R.result->do_exr_tile) {
- render_result_exr_file_merge(R.result, pa->result, R.viewname);
- }
- else if (render_display_update_enabled(&R)) {
- /* on break, don't merge in result for preview renders, looks nicer */
- if (R.test_break(R.tbh) && (R.r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
- /* pass */
- }
- else {
- render_result_merge(R.result, pa->result);
- }
+ /* Needs to be called from the thread which used the ogl context for rendering. */
+ if (re->gl_context) {
+ if (re->gpu_context) {
+ WM_opengl_context_activate(re->gl_context);
+ GPU_context_active_set(re->gpu_context);
+ GPU_context_discard(re->gpu_context);
+ re->gpu_context = NULL;
}
- BLI_rw_mutex_unlock(&R.resultmutex);
+ WM_opengl_context_dispose(re->gl_context);
+ re->gl_context = NULL;
}
-
- pa->status = PART_STATUS_MERGED;
-
- return NULL;
}
-/* calculus for how much 1 pixel rendered should rotate the 3d geometry */
-/* is not that simple, needs to be corrected for errors of larger viewplane sizes */
-/* called in initrender.c, RE_parts_init() and convertblender.c, for speedvectors */
-float panorama_pixel_rot(Render *re)
+void *RE_gl_context_get(Render *re)
{
- float psize, phi, xfac;
- float borderfac = (float)BLI_rcti_size_x(&re->disprect) / (float)re->winx;
- int xparts = (re->rectx + re->partx - 1) / re->partx;
-
- /* size of 1 pixel mapped to viewplane coords */
- psize = BLI_rctf_size_x(&re->viewplane) / (float)re->winx;
- /* angle of a pixel */
- phi = atan(psize / re->clipsta);
-
- /* correction factor for viewplane shifting, first calculate how much the viewplane angle is */
- xfac = borderfac * BLI_rctf_size_x(&re->viewplane) / (float)xparts;
- xfac = atan(0.5f * xfac / re->clipsta);
- /* and how much the same viewplane angle is wrapped */
- psize = 0.5f * phi * ((float)re->partx);
-
- /* the ratio applied to final per-pixel angle */
- phi *= xfac / psize;
-
- return phi;
+ return re->gl_context;
}
-/* for panorama, we render per Y slice, and update
- * camera parameters when we go the next slice */
-static bool find_next_pano_slice(Render *re, int *slice, int *minx, rctf *viewplane)
+void *RE_gpu_context_get(Render *re)
{
- RenderPart *pa, *best = NULL;
- bool found = false;
-
- *minx = re->winx;
-
- if (!(re->r.mode & R_PANORAMA)) {
- /* for regular render, just one 'slice' */
- found = (*slice == 0);
- (*slice)++;
- return found;
+ if (re->gpu_context == NULL) {
+ re->gpu_context = GPU_context_create();
}
-
- /* most left part of the non-rendering parts */
- for (pa = re->parts.first; pa; pa = pa->next) {
- if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
- if (pa->disprect.xmin < *minx) {
- found = true;
- best = pa;
- *minx = pa->disprect.xmin;
- }
- }
- }
-
- if (best) {
- float phi = panorama_pixel_rot(re);
-
- R.panodxp = (re->winx - (best->disprect.xmin + best->disprect.xmax) ) / 2;
- R.panodxv = (BLI_rctf_size_x(viewplane) * R.panodxp) / (float)(re->winx);
-
- /* shift viewplane */
- R.viewplane.xmin = viewplane->xmin + R.panodxv;
- R.viewplane.xmax = viewplane->xmax + R.panodxv;
- RE_SetWindow(re, &R.viewplane, R.clipsta, R.clipend);
- copy_m4_m4(R.winmat, re->winmat);
-
- /* rotate database according to part coordinates */
- project_renderdata(re, projectverto, 1, -R.panodxp * phi, 1);
- R.panosi = sinf(R.panodxp * phi);
- R.panoco = cosf(R.panodxp * phi);
- }
-
- (*slice)++;
-
- return found;
-}
-
-typedef struct SortRenderPart {
- RenderPart *pa;
- long long int dist;
-} SortRenderPart;
-
-static int sort_render_part(const void *pa1, const void *pa2) {
- const SortRenderPart *rpa1 = pa1;
- const SortRenderPart *rpa2 = pa2;
-
- if (rpa1->dist > rpa2->dist) return 1;
- else if (rpa1->dist < rpa2->dist) return -1;
-
- return 0;
-}
-
-static int sort_and_queue_parts(Render *re, int minx, ThreadQueue *workqueue)
-{
- RenderPart *pa;
-
- /* long long int's needed because of overflow [#24414] */
- long long int centx = re->winx / 2, centy = re->winy / 2, tot = 1;
- int totsort = 0;
-
- /* find center of rendered parts, image center counts for 1 too */
- for (pa = re->parts.first; pa; pa = pa->next) {
- if (pa->status >= PART_STATUS_RENDERED) {
- centx += BLI_rcti_cent_x(&pa->disprect);
- centy += BLI_rcti_cent_y(&pa->disprect);
- tot++;
- }
- else if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
- if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) {
- totsort++;
- }
- }
- }
- centx /= tot;
- centy /= tot;
-
- if (totsort > 0) {
- SortRenderPart *sortlist = MEM_mallocN(sizeof(*sortlist) * totsort, "renderpartsort");
- long int i = 0;
-
- /* prepare the list */
- for (pa = re->parts.first; pa; pa = pa->next) {
- if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
- if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) {
- long long int distx = centx - BLI_rcti_cent_x(&pa->disprect);
- long long int disty = centy - BLI_rcti_cent_y(&pa->disprect);
- sortlist[i].dist = (long long int)sqrt(distx * distx + disty * disty);
- sortlist[i].pa = pa;
- i++;
- }
- }
- }
-
- /* Now sort it */
- qsort(sortlist, totsort, sizeof(*sortlist), sort_render_part);
-
- /* Finally flush it to the workqueue */
- for (i = 0; i < totsort; i++) {
- pa = sortlist[i].pa;
- pa->nr = i + 1; /* for nicest part, and for stats */
- BLI_thread_queue_push(workqueue, pa);
- }
-
- MEM_freeN(sortlist);
-
- return totsort;
- }
-
- return 0;
-}
-
-static void print_part_stats(Render *re, RenderPart *pa)
-{
- char str[64];
-
- BLI_snprintf(str, sizeof(str), IFACE_("%s, Part %d-%d"), re->scene->id.name + 2, pa->nr, re->i.totpart);
- re->i.infostr = str;
- re->stats_draw(re->sdh, &re->i);
- re->i.infostr = NULL;
+ return re->gpu_context;
}
-typedef struct RenderThread {
- ThreadQueue *workqueue;
- ThreadQueue *donequeue;
-
- int number;
-
- void (*display_update)(void *handle, RenderResult *rr, volatile rcti *rect);
- void *duh;
-} RenderThread;
-
-static void *do_render_thread(void *thread_v)
-{
- RenderThread *thread = thread_v;
- RenderPart *pa;
-
- while ((pa = BLI_thread_queue_pop(thread->workqueue))) {
- pa->thread = thread->number;
- do_part_thread(pa);
-
- if (thread->display_update) {
- thread->display_update(thread->duh, pa->result, NULL);
- }
-
- BLI_thread_queue_push(thread->donequeue, pa);
-
- if (R.test_break(R.tbh))
- break;
- }
-
- return NULL;
-}
+/* ********* add object data (later) ******** */
-static void main_render_result_end(Render *re)
+/* object is considered fully prepared on correct time etc */
+/* includes lights */
+#if 0
+void RE_AddObject(Render *UNUSED(re), Object *UNUSED(ob))
{
- if (re->result->do_exr_tile) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_end(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
- if (re->r.scemode & R_EXR_CACHE_FILE) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_cache_write(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
}
+#endif
-static void main_render_result_new(Render *re)
-{
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
-
- /* first step; free the entire render result, make new, and/or prepare exr buffer saving */
- if (re->result == NULL || !(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
- render_result_free(re->result);
-
- if (re->sss_points && render_display_update_enabled(re))
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
- else if (re->r.scemode & R_FULL_SAMPLE)
- re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR, RR_ALL_VIEWS);
- else
- re->result = render_result_new(re, &re->disprect, 0,
- (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
- }
-
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- if (re->result) {
- if (re->result->do_exr_tile) {
- render_result_exr_file_begin(re);
- }
- }
-}
-
-static void threaded_tile_processor(Render *re)
-{
- RenderThread thread[BLENDER_MAX_THREADS];
- ThreadQueue *workqueue, *donequeue;
- ListBase threads;
- RenderPart *pa;
- rctf viewplane = re->viewplane;
- double lastdraw, elapsed, redrawtime = 1.0f;
- int totpart = 0, minx = 0, slice = 0, a, wait;
-
- if (re->result == NULL)
- return;
-
- /* warning; no return here without closing exr file */
- RE_parts_init(re, true);
-
- /* assuming no new data gets added to dbase... */
- R = *re;
-
- /* set threadsafe break */
- R.test_break = thread_break;
-
- /* create and fill work queue */
- workqueue = BLI_thread_queue_init();
- donequeue = BLI_thread_queue_init();
-
- /* for panorama we loop over slices */
- while (find_next_pano_slice(re, &slice, &minx, &viewplane)) {
- /* gather parts into queue */
- totpart = sort_and_queue_parts(re, minx, workqueue);
-
- BLI_thread_queue_nowait(workqueue);
-
- /* start all threads */
- BLI_threadpool_init(&threads, do_render_thread, re->r.threads);
-
- for (a = 0; a < re->r.threads; a++) {
- thread[a].workqueue = workqueue;
- thread[a].donequeue = donequeue;
- thread[a].number = a;
-
- if (render_display_update_enabled(re)) {
- thread[a].display_update = re->display_update;
- thread[a].duh = re->duh;
- }
- else {
- thread[a].display_update = NULL;
- thread[a].duh = NULL;
- }
-
- BLI_threadpool_insert(&threads, &thread[a]);
- }
-
- /* wait for results to come back */
- lastdraw = PIL_check_seconds_timer();
-
- while (1) {
- elapsed = PIL_check_seconds_timer() - lastdraw;
- wait = (redrawtime - elapsed)*1000;
-
- /* handle finished part */
- if ((pa=BLI_thread_queue_pop_timeout(donequeue, wait))) {
- if (pa->result) {
- print_part_stats(re, pa);
-
- render_result_free_list(&pa->fullresult, pa->result);
- pa->result = NULL;
- re->i.partsdone++;
- re->progress(re->prh, re->i.partsdone / (float)re->i.totpart);
- }
-
- totpart--;
- }
-
- /* check for render cancel */
- if ((g_break=re->test_break(re->tbh)))
- break;
-
- /* or done with parts */
- if (totpart == 0)
- break;
-
- /* redraw in progress parts */
- elapsed = PIL_check_seconds_timer() - lastdraw;
- if (elapsed > redrawtime) {
- if (render_display_update_enabled(re))
- for (pa = re->parts.first; pa; pa = pa->next)
- if ((pa->status == PART_STATUS_IN_PROGRESS) && pa->nr && pa->result)
- re->display_update(re->duh, pa->result, &pa->result->renrect);
-
- lastdraw = PIL_check_seconds_timer();
- }
- }
-
- BLI_threadpool_end(&threads);
-
- if ((g_break=re->test_break(re->tbh)))
- break;
- }
-
- if (g_break) {
- /* review the done queue and handle all the render parts,
- * so no unfreed render result are lurking around
- */
- BLI_thread_queue_nowait(donequeue);
- while ((pa = BLI_thread_queue_pop(donequeue))) {
- if (pa->result) {
- render_result_free_list(&pa->fullresult, pa->result);
- pa->result = NULL;
- }
- }
- }
-
- BLI_thread_queue_free(donequeue);
- BLI_thread_queue_free(workqueue);
-
- if (re->result->do_exr_tile) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_save_empty_result_tiles(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-
- /* unset threadsafety */
- g_break = 0;
- BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
- RE_parts_free(re);
- BLI_rw_mutex_unlock(&re->partsmutex);
- re->viewplane = viewplane; /* restore viewplane, modified by pano render */
-}
+/* *************************************** */
#ifdef WITH_FREESTYLE
static void init_freestyle(Render *re);
@@ -1523,349 +1092,13 @@ static void add_freestyle(Render *re, int render);
static void free_all_freestyle_renders(void);
#endif
-/* currently only called by preview renders and envmap */
-void RE_TileProcessor(Render *re)
-{
- main_render_result_new(re);
- threaded_tile_processor(re);
-
- re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
- re->stats_draw(re->sdh, &re->i);
-
-#ifdef WITH_FREESTYLE
- /* Freestyle */
- if (re->r.mode & R_EDGE_FRS) {
- if (!re->test_break(re->tbh)) {
- init_freestyle(re);
- add_freestyle(re, 1);
- free_all_freestyle_renders();
-
- re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
- re->stats_draw(re->sdh, &re->i);
- }
- }
-#endif
-
-}
/* ************ This part uses API, for rendering Blender scenes ********** */
static void do_render_3d(Render *re)
{
- RenderView *rv;
-
re->current_scene_update(re->suh, re->scene);
-
- /* try external */
- if (RE_engine_render(re, 0))
- return;
-
- /* internal */
- RE_parts_clamp(re);
-
- /* add motion blur and fields offset to frames */
- const int cfra_backup = re->scene->r.cfra;
- const float subframe_backup = re->scene->r.subframe;
-
- BKE_scene_frame_set(
- re->scene, (double)re->scene->r.cfra + (double)re->scene->r.subframe +
- (double)re->mblur_offs + (double)re->field_offs);
-
- /* init main render result */
- main_render_result_new(re);
- if (re->result == NULL) {
- BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
- G.is_break = true;
- return;
- }
-
-#ifdef WITH_FREESTYLE
- if (re->r.mode & R_EDGE_FRS) {
- init_freestyle(re);
- }
-#endif
-
- /* we need a new database for each view */
- for (rv = re->result->views.first; rv; rv = rv->next) {
- RE_SetActiveRenderView(re, rv->name);
-
- /* lock drawing in UI during data phase */
- if (re->draw_lock)
- re->draw_lock(re->dlh, 1);
-
- /* make render verts/faces/halos/lamps */
- if (render_scene_needs_vector(re))
- RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay);
- else {
- RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
- RE_Database_Preprocess(re);
- }
-
- /* clear UI drawing locks */
- if (re->draw_lock)
- re->draw_lock(re->dlh, 0);
-
- threaded_tile_processor(re);
-
-#ifdef WITH_FREESTYLE
- /* Freestyle */
- if (re->r.mode & R_EDGE_FRS)
- if (!re->test_break(re->tbh))
- add_freestyle(re, 1);
-#endif
-
- /* do left-over 3d post effects (flares) */
- if (re->flag & R_HALO)
- if (!re->test_break(re->tbh))
- add_halo_flare(re);
-
- /* free all render verts etc */
- RE_Database_Free(re);
- }
-
- main_render_result_end(re);
-
- re->scene->r.cfra = cfra_backup;
- re->scene->r.subframe = subframe_backup;
-}
-
-/* called by blur loop, accumulate RGBA key alpha */
-static void addblur_rect_key(RenderResult *rr, float *rectf, float *rectf1, float blurfac)
-{
- float mfac = 1.0f - blurfac;
- int a, b, stride = 4 * rr->rectx;
- int len = stride * sizeof(float);
-
- for (a = 0; a < rr->recty; a++) {
- if (blurfac == 1.0f) {
- memcpy(rectf, rectf1, len);
- }
- else {
- float *rf = rectf, *rf1 = rectf1;
-
- for (b = rr->rectx; b > 0; b--, rf += 4, rf1 += 4) {
- if (rf1[3] < 0.01f)
- rf[3] = mfac * rf[3];
- else if (rf[3] < 0.01f) {
- rf[0] = rf1[0];
- rf[1] = rf1[1];
- rf[2] = rf1[2];
- rf[3] = blurfac * rf1[3];
- }
- else {
- rf[0] = mfac * rf[0] + blurfac * rf1[0];
- rf[1] = mfac * rf[1] + blurfac * rf1[1];
- rf[2] = mfac * rf[2] + blurfac * rf1[2];
- rf[3] = mfac * rf[3] + blurfac * rf1[3];
- }
- }
- }
- rectf += stride;
- rectf1 += stride;
- }
-}
-
-/* called by blur loop, accumulate renderlayers */
-static void addblur_rect(RenderResult *rr, float *rectf, float *rectf1, float blurfac, int channels)
-{
- float mfac = 1.0f - blurfac;
- int a, b, stride = channels * rr->rectx;
- int len = stride * sizeof(float);
-
- for (a = 0; a < rr->recty; a++) {
- if (blurfac == 1.0f) {
- memcpy(rectf, rectf1, len);
- }
- else {
- float *rf = rectf, *rf1 = rectf1;
-
- for (b = rr->rectx * channels; b > 0; b--, rf++, rf1++) {
- rf[0] = mfac * rf[0] + blurfac * rf1[0];
- }
- }
- rectf += stride;
- rectf1 += stride;
- }
-}
-
-
-/* called by blur loop, accumulate renderlayers */
-static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float blurfac, bool key_alpha)
-{
- RenderLayer *rl, *rl1;
- RenderPass *rpass, *rpass1;
-
- rl1 = brr->layers.first;
- for (rl = rr->layers.first; rl && rl1; rl = rl->next, rl1 = rl1->next) {
- /* passes are allocated in sync */
- rpass1 = rl1->passes.first;
- for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) {
- if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && key_alpha)
- addblur_rect_key(rr, rpass->rect, rpass1->rect, blurfac);
- else
- addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
- }
- }
-}
-
-/* main blur loop, can be called by fields too */
-static void do_render_blur_3d(Render *re)
-{
- RenderResult *rres;
- float blurfac;
- int blur = re->r.mblur_samples;
-
- /* create accumulation render result */
- rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
-
- /* do the blur steps */
- while (blur--) {
- re->mblur_offs = re->r.blurfac * ((float)(re->r.mblur_samples - blur)) / (float)re->r.mblur_samples;
-
- re->i.curblur = re->r.mblur_samples - blur; /* stats */
-
- do_render_3d(re);
-
- blurfac = 1.0f / (float)(re->r.mblur_samples - blur);
-
- merge_renderresult_blur(rres, re->result, blurfac, false);
- if (re->test_break(re->tbh)) break;
- }
-
- /* swap results */
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_free(re->result);
- re->result = rres;
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- re->mblur_offs = 0.0f;
- re->i.curblur = 0; /* stats */
-
- /* make sure motion blur changes get reset to current frame */
- if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
- BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay);
- }
-
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
- re->display_update(re->duh, re->result, NULL);
-}
-
-
-/* function assumes rectf1 and rectf2 to be half size of rectf */
-static void interleave_rect(RenderResult *rr, float *rectf, float *rectf1, float *rectf2, int channels)
-{
- int a, stride = channels * rr->rectx;
- int len = stride * sizeof(float);
-
- for (a = 0; a < rr->recty; a += 2) {
- memcpy(rectf, rectf1, len);
- rectf += stride;
- rectf1 += stride;
- memcpy(rectf, rectf2, len);
- rectf += stride;
- rectf2 += stride;
- }
-}
-
-/* merge render results of 2 fields */
-static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, RenderResult *rr2)
-{
- RenderLayer *rl, *rl1, *rl2;
- RenderPass *rpass, *rpass1, *rpass2;
-
- rl1 = rr1->layers.first;
- rl2 = rr2->layers.first;
- for (rl = rr->layers.first; rl && rl1 && rl2; rl = rl->next, rl1 = rl1->next, rl2 = rl2->next) {
-
- /* passes are allocated in sync */
- rpass1 = rl1->passes.first;
- rpass2 = rl2->passes.first;
- for (rpass = rl->passes.first;
- rpass && rpass1 && rpass2;
- rpass = rpass->next, rpass1 = rpass1->next, rpass2 = rpass2->next)
- {
- interleave_rect(rr, rpass->rect, rpass1->rect, rpass2->rect, rpass->channels);
- }
- }
-}
-
-
-/* interleaves 2 frames */
-static void do_render_fields_3d(Render *re)
-{
- Object *camera = RE_GetCamera(re);
- RenderResult *rr1, *rr2 = NULL;
-
- /* no render result was created, we can safely halve render y */
- re->winy /= 2;
- re->recty /= 2;
- re->disprect.ymin /= 2;
- re->disprect.ymax /= 2;
-
- re->i.curfield = 1; /* stats */
-
- /* first field, we have to call camera routine for correct aspect and subpixel offset */
- RE_SetCamera(re, camera);
- if (re->r.mode & R_MBLUR && (re->r.scemode & R_FULL_SAMPLE) == 0)
- do_render_blur_3d(re);
- else
- do_render_3d(re);
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- rr1 = re->result;
- re->result = NULL;
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- /* second field */
- if (!re->test_break(re->tbh)) {
-
- re->i.curfield = 2; /* stats */
-
- re->flag |= R_SEC_FIELD;
- if ((re->r.mode & R_FIELDSTILL) == 0) {
- re->field_offs = 0.5f;
- }
- RE_SetCamera(re, camera);
- if (re->r.mode & R_MBLUR && (re->r.scemode & R_FULL_SAMPLE) == 0)
- do_render_blur_3d(re);
- else
- do_render_3d(re);
- re->flag &= ~R_SEC_FIELD;
-
- re->field_offs = 0.0f;
-
- rr2 = re->result;
- }
-
- /* allocate original height new buffers */
- re->winy *= 2;
- re->recty *= 2;
- re->disprect.ymin *= 2;
- re->disprect.ymax *= 2;
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
-
- if (rr2) {
- if (re->r.mode & R_ODDFIELD)
- merge_renderresult_fields(re->result, rr2, rr1);
- else
- merge_renderresult_fields(re->result, rr1, rr2);
-
- render_result_free(rr2);
- }
-
- render_result_free(rr1);
-
- re->i.curfield = 0; /* stats */
-
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
-
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- re->display_update(re->duh, re->result, NULL);
+ RE_engine_render(re, 0);
}
/* make sure disprect is not affected by the render border */
@@ -1928,7 +1161,7 @@ static void render_result_uncrop(Render *re)
}
/* main render routine, no compositing */
-static void do_render_fields_blur_3d(Render *re)
+static void do_render(Render *re)
{
Object *camera = RE_GetCamera(re);
/* also check for camera here */
@@ -1941,12 +1174,7 @@ static void do_render_fields_blur_3d(Render *re)
/* now use renderdata and camera to set viewplane */
RE_SetCamera(re, camera);
- if (re->r.mode & R_FIELDS)
- do_render_fields_3d(re);
- else if (re->r.mode & R_MBLUR && (re->r.scemode & R_FULL_SAMPLE) == 0)
- do_render_blur_3d(re);
- else
- do_render_3d(re);
+ do_render_3d(re);
/* when border render, check if we have to insert it in black */
render_result_uncrop(re);
@@ -1972,7 +1200,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
}
/* initial setup */
- RE_InitState(resc, re, &sce->r, NULL, winx, winy, &re->disprect);
+ RE_InitState(resc, re, &sce->r, &sce->view_layers, NULL, winx, winy, &re->disprect);
/* We still want to use 'rendercache' setting from org (main) scene... */
resc->r.scemode = (resc->r.scemode & ~R_EXR_CACHE_FILE) | (re->r.scemode & R_EXR_CACHE_FILE);
@@ -1980,8 +1208,6 @@ static void render_scene(Render *re, Scene *sce, int cfra)
/* still unsure entity this... */
resc->main = re->main;
resc->scene = sce;
- resc->lay = sce->lay;
- resc->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
/* ensure scene has depsgraph, base flags etc OK */
BKE_scene_set_background(re->main, sce);
@@ -1996,7 +1222,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
resc->current_scene_update = re->current_scene_update;
resc->suh = re->suh;
- do_render_fields_blur_3d(resc);
+ do_render(resc);
}
/* helper call to detect if this scene needs a render, or if there's a any render layer to render */
@@ -2017,19 +1243,6 @@ static int composite_needs_render(Scene *sce, int this_scene)
return 0;
}
-static bool rlayer_node_uses_alpha(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *sock;
-
- for (sock = node->outputs.first; sock; sock = sock->next) {
- /* Weak! but how to make it better? */
- if (STREQ(sock->name, "Alpha") && nodeCountSocketLinks(ntree, sock) > 0)
- return true;
- }
-
- return false;
-}
-
bool RE_allow_render_generic_object(Object *ob)
{
/* override not showing object when duplis are used with particles */
@@ -2042,196 +1255,6 @@ bool RE_allow_render_generic_object(Object *ob)
return true;
}
-/* Issue here is that it's possible that object which is used by boolean,
- * array or shrinkwrap modifiers weren't displayed in the viewport before
- * rendering. This leads to situations when apply() of this modifiers
- * could not get ob->derivedFinal and modifiers are not being applied.
- *
- * This was worked around by direct call of get_derived_final() from those
- * modifiers, but such approach leads to write conflicts with threaded
- * update.
- *
- * Here we make sure derivedFinal will be calculated by update_for_newframe
- * function later in the pipeline and all the modifiers are applied
- * properly without hacks from their side.
- * - sergey -
- */
-#define DEPSGRAPH_WORKAROUND_HACK
-
-#ifdef DEPSGRAPH_WORKAROUND_HACK
-static void tag_dependend_object_for_render(Scene *scene, Object *object);
-
-static void tag_dependend_group_for_render(Scene *scene, Group *group)
-{
- if (group->id.tag & LIB_TAG_DOIT) {
- return;
- }
- group->id.tag |= LIB_TAG_DOIT;
-
- for (GroupObject *go = group->gobject.first; go != NULL; go = go->next) {
- Object *object = go->ob;
- tag_dependend_object_for_render(scene, object);
- }
-}
-
-static void tag_dependend_object_for_render(Scene *scene, Object *object)
-{
- if (object->type == OB_MESH) {
- if (RE_allow_render_generic_object(object)) {
- ModifierData *md;
- VirtualModifierData virtualModifierData;
-
- if (object->particlesystem.first) {
- DAG_id_tag_update(&object->id, OB_RECALC_DATA);
- }
-
- for (md = modifiers_getVirtualModifierList(object, &virtualModifierData);
- md;
- md = md->next)
- {
- if (!modifier_isEnabled(scene, md, eModifierMode_Render)) {
- continue;
- }
-
- if (md->type == eModifierType_Boolean) {
- BooleanModifierData *bmd = (BooleanModifierData *)md;
- if (bmd->object && bmd->object->type == OB_MESH) {
- DAG_id_tag_update(&bmd->object->id, OB_RECALC_DATA);
- }
- }
- else if (md->type == eModifierType_Array) {
- ArrayModifierData *amd = (ArrayModifierData *)md;
- if (amd->start_cap && amd->start_cap->type == OB_MESH) {
- DAG_id_tag_update(&amd->start_cap->id, OB_RECALC_DATA);
- }
- if (amd->end_cap && amd->end_cap->type == OB_MESH) {
- DAG_id_tag_update(&amd->end_cap->id, OB_RECALC_DATA);
- }
- }
- else if (md->type == eModifierType_Shrinkwrap) {
- ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
- if (smd->target && smd->target->type == OB_MESH) {
- DAG_id_tag_update(&smd->target->id, OB_RECALC_DATA);
- }
- }
- else if (md->type == eModifierType_ParticleSystem) {
- ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
- ParticleSystem *psys = psmd->psys;
- ParticleSettings *part = psys->part;
- switch (part->ren_as) {
- case PART_DRAW_OB:
- if (part->dup_ob != NULL) {
- DAG_id_tag_update(&part->dup_ob->id, OB_RECALC_DATA);
- }
- break;
- case PART_DRAW_GR:
- if (part->dup_group != NULL) {
- for (GroupObject *go = part->dup_group->gobject.first;
- go != NULL;
- go = go->next)
- {
- DAG_id_tag_update(&go->ob->id, OB_RECALC_DATA);
- }
- }
- break;
- }
- }
- }
- }
- }
- if (object->dup_group != NULL) {
- tag_dependend_group_for_render(scene, object->dup_group);
- }
-}
-
-static void tag_dependend_objects_for_render(Main *bmain, Scene *scene, int renderlay)
-{
- Scene *sce_iter;
- Base *base;
- BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
- for (SETLOOPER(scene, sce_iter, base)) {
- Object *object = base->object;
- if ((base->lay & renderlay) == 0) {
- continue;
- }
- tag_dependend_object_for_render(scene, object);
- }
-}
-#endif
-
-static void tag_scenes_for_render(Render *re)
-{
- bNode *node;
- Scene *sce;
-#ifdef DEPSGRAPH_WORKAROUND_HACK
- int renderlay = re->lay;
-#endif
-
- for (sce = re->main->scene.first; sce; sce = sce->id.next) {
- sce->id.tag &= ~LIB_TAG_DOIT;
-#ifdef DEPSGRAPH_WORKAROUND_HACK
- tag_dependend_objects_for_render(re->main, sce, renderlay);
-#endif
- }
-
-#ifdef WITH_FREESTYLE
- if (re->freestyle_bmain) {
- for (sce = re->freestyle_bmain->scene.first; sce; sce = sce->id.next) {
- sce->id.tag &= ~LIB_TAG_DOIT;
-#ifdef DEPSGRAPH_WORKAROUND_HACK
- tag_dependend_objects_for_render(re->freestyle_bmain, sce, renderlay);
-#endif
- }
- }
-#endif
-
- if (RE_GetCamera(re) && composite_needs_render(re->scene, 1)) {
- re->scene->id.tag |= LIB_TAG_DOIT;
-#ifdef DEPSGRAPH_WORKAROUND_HACK
- tag_dependend_objects_for_render(re->main, re->scene, renderlay);
-#endif
- }
-
- if (re->scene->nodetree == NULL) return;
-
- /* check for render-layers nodes using other scenes, we tag them LIB_TAG_DOIT */
- for (node = re->scene->nodetree->nodes.first; node; node = node->next) {
- node->flag &= ~NODE_TEST;
- if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
- if (node->id) {
- if (!MAIN_VERSION_ATLEAST(re->main, 265, 5)) {
- if (rlayer_node_uses_alpha(re->scene->nodetree, node)) {
- Scene *scene = (Scene *)node->id;
-
- if (scene->r.alphamode != R_ALPHAPREMUL) {
- BKE_reportf(re->reports, RPT_WARNING, "Setting scene %s alpha mode to Premul", scene->id.name + 2);
-
- /* also print, so feedback is immediate */
- printf("2.66 versioning fix: setting scene %s alpha mode to Premul\n", scene->id.name + 2);
-
- scene->r.alphamode = R_ALPHAPREMUL;
- }
- }
- }
-
- if (node->id != (ID *)re->scene) {
- if ((node->id->tag & LIB_TAG_DOIT) == 0) {
- Scene *scene = (Scene *) node->id;
- if (render_scene_has_layers_to_render(scene)) {
- node->flag |= NODE_TEST;
- node->id->tag |= LIB_TAG_DOIT;
-#ifdef DEPSGRAPH_WORKAROUND_HACK
- tag_dependend_objects_for_render(re->main, scene, renderlay);
-#endif
- }
- }
- }
- }
- }
- }
-
-}
-
static void ntree_render_scenes(Render *re)
{
bNode *node;
@@ -2241,8 +1264,6 @@ static void ntree_render_scenes(Render *re)
if (re->scene->nodetree == NULL) return;
- tag_scenes_for_render(re);
-
/* now foreach render-result node tagged we do a full render */
/* results are stored in a way compisitor will find it */
for (node = re->scene->nodetree->nodes.first; node; node = node->next) {
@@ -2267,12 +1288,14 @@ static void ntree_render_scenes(Render *re)
}
/* bad call... need to think over proper method still */
-static void render_composit_stats(void *UNUSED(arg), const char *str)
+static void render_composit_stats(void *arg, const char *str)
{
+ Render *re = (Render*)arg;
+
RenderStats i;
- memcpy(&i, &R.i, sizeof(i));
+ memcpy(&i, &re->i, sizeof(i));
i.infostr = str;
- R.stats_draw(R.sdh, &i);
+ re->stats_draw(re->sdh, &i);
}
#ifdef WITH_FREESTYLE
@@ -2296,66 +1319,27 @@ static void init_freestyle(Render *re)
/* invokes Freestyle stroke rendering */
static void add_freestyle(Render *re, int render)
{
- SceneRenderLayer *srl, *actsrl;
+ ViewLayer *view_layer, *active_view_layer;
LinkData *link;
Render *r;
- const bool do_link = (re->r.mode & R_MBLUR) == 0 || re->i.curblur == re->r.mblur_samples;
- actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
+ active_view_layer = BLI_findlink(&re->view_layers, re->active_view_layer);
FRS_begin_stroke_rendering(re);
- for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) {
- if (do_link) {
- link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render");
- BLI_addtail(&re->freestyle_renders, link);
- }
- if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
+ for (view_layer = (ViewLayer *)re->view_layers.first; view_layer; view_layer = view_layer->next) {
+ link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render");
+ BLI_addtail(&re->freestyle_renders, link);
+
+ if ((re->r.scemode & R_SINGLE_LAYER) && view_layer != active_view_layer)
continue;
- if (FRS_is_freestyle_enabled(srl)) {
- r = FRS_do_stroke_rendering(re, srl, render);
- if (do_link)
- link->data = (void *)r;
+ if (FRS_is_freestyle_enabled(view_layer)) {
+ r = FRS_do_stroke_rendering(re, view_layer, render);
+ link->data = (void *)r;
}
}
FRS_end_stroke_rendering(re);
-
- /* restore the global R value (invalidated by nested execution of the internal renderer) */
- R = *re;
-}
-
-/* merges the results of Freestyle stroke rendering into a given render result */
-static void composite_freestyle_renders(Render *re, int sample)
-{
- Render *freestyle_render;
- RenderView *rv;
- SceneRenderLayer *srl, *actsrl;
- LinkData *link;
-
- actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
-
- link = (LinkData *)re->freestyle_renders.first;
-
- for (rv = re->result->views.first; rv; rv = rv->next) {
- for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) {
- if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
- continue;
-
- if (FRS_is_freestyle_enabled(srl)) {
- freestyle_render = (Render *)link->data;
-
- /* may be NULL in case of empty render layer */
- if (freestyle_render) {
- render_result_exr_file_read_sample(freestyle_render, sample);
- FRS_composite_result(re, srl, freestyle_render);
- RE_FreeRenderResult(freestyle_render->result);
- freestyle_render->result = NULL;
- }
- }
- link = link->next;
- }
- }
}
/* releases temporary scenes and renders for Freestyle stroke rendering */
@@ -2391,243 +1375,12 @@ static void free_all_freestyle_renders(void)
}
#endif
-/* reads all buffers, calls optional composite, merges in first result->views rectf */
-static void do_merge_fullsample(Render *re, bNodeTree *ntree)
-{
- ListBase *rectfs;
- RenderView *rv;
- rcti filter_mask = re->disprect;
- float *rectf, filt[3][3];
- int x, y, sample;
- int nr, numviews;
-
- /* interaction callbacks */
- if (ntree) {
- ntree->stats_draw = render_composit_stats;
- ntree->test_break = re->test_break;
- ntree->progress = re->progress;
- ntree->sdh = re->sdh;
- ntree->tbh = re->tbh;
- ntree->prh = re->prh;
- }
-
- /* filtmask needs it */
- R = *re;
-
- /* temporary storage of the acccumulation buffers */
- rectfs = MEM_callocN(sizeof(ListBase), "fullsample accumulation buffers");
-
- numviews = BLI_listbase_count(&re->result->views);
- for (nr = 0; nr < numviews; nr++) {
- rv = MEM_callocN(sizeof(RenderView), "fullsample renderview");
-
- /* we accumulate in here */
- rv->rectf = MEM_mapallocN(re->result->rectx * re->result->recty * sizeof(float) * 4, "fullsample rgba");
- BLI_addtail(rectfs, rv);
- }
-
- for (sample = 0; sample < re->r.osa; sample++) {
- Scene *sce;
- Render *re1;
- RenderResult rres;
- int mask;
-
- /* enable full sample print */
- R.i.curfsa = sample + 1;
-
- /* set all involved renders on the samplebuffers (first was done by render itself, but needs tagged) */
- /* also function below assumes this */
-
- tag_scenes_for_render(re);
- for (sce = re->main->scene.first; sce; sce = sce->id.next) {
- if (sce->id.tag & LIB_TAG_DOIT) {
- re1 = RE_GetSceneRender(sce);
-
- if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) {
- if (sample) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_read_sample(re1, sample);
-#ifdef WITH_FREESTYLE
- if (re1->r.mode & R_EDGE_FRS)
- composite_freestyle_renders(re1, sample);
-#endif
- BLI_rw_mutex_unlock(&re->resultmutex);
- render_result_uncrop(re1);
- }
-#ifdef WITH_FREESTYLE
- else if (re1->r.mode & R_EDGE_FRS) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- composite_freestyle_renders(re1, 0);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-#endif
- ntreeCompositTagRender(re1->scene); /* ensure node gets exec to put buffers on stack */
- }
- }
- }
-
- /* composite */
- if (ntree) {
- ntreeCompositTagRender(re->scene);
- ntreeCompositTagAnimated(ntree);
-
- for (rv = re->result->views.first; rv; rv = rv->next) {
- ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
- }
- }
-
- for (nr = 0, rv = rectfs->first; rv; rv = rv->next, nr++) {
- rectf = rv->rectf;
-
- /* ensure we get either composited result or the active layer */
- RE_AcquireResultImage(re, &rres, nr);
-
- /* accumulate with filter, and clip */
- mask = (1 << sample);
- mask_array(mask, filt);
-
- for (y = 0; y < re->result->recty; y++) {
- float *rf = rectf + 4 * y * re->result->rectx;
- float *col = rres.rectf + 4 * y * re->result->rectx;
-
- for (x = 0; x < re->result->rectx; x++, rf += 4, col += 4) {
- /* clamping to 1.0 is needed for correct AA */
- CLAMP(col[0], 0.0f, 1.0f);
- CLAMP(col[1], 0.0f, 1.0f);
- CLAMP(col[2], 0.0f, 1.0f);
-
- add_filt_fmask_coord(filt, col, rf, re->result->rectx, x, y, &filter_mask);
- }
- }
-
- RE_ReleaseResultImage(re);
-
- /* show stuff */
- if (sample != re->osa - 1) {
- /* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
- RE_SetActiveRenderView(re, rv->name);
- re->display_update(re->duh, re->result, NULL);
- }
- }
- }
-
- for (nr = 0; nr < numviews; nr++) {
- rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf;
-
- /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
- for (y = 0; y < re->result->recty; y++) {
- float *rf = rectf + 4 * y * re->result->rectx;
-
- for (x = 0; x < re->result->rectx; x++, rf += 4) {
- rf[0] = MAX2(rf[0], 0.0f);
- rf[1] = MAX2(rf[1], 0.0f);
- rf[2] = MAX2(rf[2], 0.0f);
- CLAMP(rf[3], 0.0f, 1.0f);
- }
- }
-
- /* store the final result */
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- rv = RE_RenderViewGetById(re->result, nr);
- if (rv->rectf)
- MEM_freeN(rv->rectf);
- rv->rectf = rectf;
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-
- /* clear interaction callbacks */
- if (ntree) {
- ntree->stats_draw = NULL;
- ntree->test_break = NULL;
- ntree->progress = NULL;
- ntree->tbh = ntree->sdh = ntree->prh = NULL;
- }
-
- /* disable full sample print */
- R.i.curfsa = 0;
-
- /* garbage collection */
- while (rectfs->first) {
- rv = rectfs->first;
- BLI_remlink(rectfs, rv);
- MEM_freeN(rv);
- }
- MEM_freeN(rectfs);
-}
-
-/* called externally, via compositor */
-void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
-{
- Scene *scene;
- bNode *node;
-
- /* default start situation */
- G.is_break = false;
-
- re->main = bmain;
- re->scene = sce;
- re->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
-
- /* first call RE_ReadRenderResult on every renderlayer scene. this creates Render structs */
-
- /* tag scenes unread */
- for (scene = re->main->scene.first; scene; scene = scene->id.next)
- scene->id.tag |= LIB_TAG_DOIT;
-
-#ifdef WITH_FREESTYLE
- if (re->freestyle_bmain) {
- for (scene = re->freestyle_bmain->scene.first; scene; scene = scene->id.next)
- scene->id.tag &= ~LIB_TAG_DOIT;
- }
-#endif
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
- Scene *nodescene = (Scene *)node->id;
-
- if (nodescene == NULL) nodescene = sce;
- if (nodescene->id.tag & LIB_TAG_DOIT) {
- nodescene->r.mode |= R_OSA; /* render struct needs tables */
- RE_ReadRenderResult(sce, nodescene);
- nodescene->id.tag &= ~LIB_TAG_DOIT;
- }
- }
- }
-
- /* own render result should be read/allocated */
- if (re->scene->id.tag & LIB_TAG_DOIT) {
- RE_ReadRenderResult(re->scene, re->scene);
- re->scene->id.tag &= ~LIB_TAG_DOIT;
- }
-
- /* and now we can draw (result is there) */
- re->display_init(re->dih, re->result);
- re->display_clear(re->dch, re->result);
-
-#ifdef WITH_FREESTYLE
- if (re->r.mode & R_EDGE_FRS) {
- init_freestyle(re);
- add_freestyle(re, 0);
- }
-#endif
-
- do_merge_fullsample(re, ntree);
-
-#ifdef WITH_FREESTYLE
- free_all_freestyle_renders();
-#endif
-}
-
/* returns fully composited render-result on given time step (in RenderData) */
-static void do_render_composite_fields_blur_3d(Render *re)
+static void do_render_composite(Render *re)
{
bNodeTree *ntree = re->scene->nodetree;
int update_newframe = 0;
- /* INIT seeding, compositor can use random texture */
- BLI_srandom(re->r.cfra);
-
if (composite_needs_render(re->scene, 1)) {
/* save memory... free all cached images */
ntreeFreeCache(ntree);
@@ -2636,7 +1389,7 @@ static void do_render_composite_fields_blur_3d(Render *re)
* it could be optimized to render only the needed view
* but what if a scene has a different number of views
* than the main scene? */
- do_render_fields_blur_3d(re);
+ do_render(re);
}
else {
re->i.cfra = re->r.cfra;
@@ -2679,26 +1432,17 @@ static void do_render_composite_fields_blur_3d(Render *re)
ntree->stats_draw = render_composit_stats;
ntree->test_break = re->test_break;
ntree->progress = re->progress;
- ntree->sdh = re->sdh;
+ ntree->sdh = re;
ntree->tbh = re->tbh;
ntree->prh = re->prh;
- /* in case it was never initialized */
- R.sdh = re->sdh;
- R.stats_draw = re->stats_draw;
- R.i.starttime = re->i.starttime;
- R.i.cfra = re->i.cfra;
-
- if (update_newframe)
- BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay);
+ if (update_newframe) {
+ /* If we have consistent depsgraph now would be a time to update them. */
+ }
- if (re->r.scemode & R_FULL_SAMPLE)
- do_merge_fullsample(re, ntree);
- else {
- RenderView *rv;
- for (rv = re->result->views.first; rv; rv = rv->next) {
- ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
- }
+ RenderView *rv;
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name);
}
ntree->stats_draw = NULL;
@@ -2707,8 +1451,6 @@ static void do_render_composite_fields_blur_3d(Render *re)
ntree->tbh = ntree->sdh = ntree->prh = NULL;
}
}
- else if (re->r.scemode & R_FULL_SAMPLE)
- do_merge_fullsample(re, NULL);
}
#ifdef WITH_FREESTYLE
@@ -2777,7 +1519,12 @@ static void do_render_seq(Render *re)
if (recurs_depth == 0) {
/* otherwise sequencer animation isn't updated */
- BKE_animsys_evaluate_all_animation(re->main, re->scene, (float)cfra); // XXX, was BKE_scene_frame_get(re->scene)
+ /* TODO(sergey): Currently depsgraph is only used to check whether it is an active
+ * edit window or not to deal with unkeyed changes. We don't have depsgraph here yet,
+ * but we also dont' deal with unkeyed changes. But still nice to get proper depsgraph
+ * within tjhe render pipeline, somehow.
+ */
+ BKE_animsys_evaluate_all_animation(re->main, NULL, re->scene, (float)cfra); // XXX, was BKE_scene_frame_get(re->scene)
}
recurs_depth++;
@@ -2796,9 +1543,14 @@ static void do_render_seq(Render *re)
tot_views = BKE_scene_multiview_num_views_get(&re->r);
ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * tot_views, "Sequencer Views ImBufs");
+ /* TODO(sergey): Currently depsgraph is only used to check whether it is an active
+ * edit window or not to deal with unkeyed changes. We don't have depsgraph here yet,
+ * but we also dont' deal with unkeyed changes. But still nice to get proper depsgraph
+ * within tjhe render pipeline, somehow.
+ */
BKE_sequencer_new_render_data(
- re->eval_ctx, re->main, re->scene,
- re_x, re_y, 100,
+ re->main, NULL, re->scene,
+ re_x, re_y, 100, true,
&context);
/* the renderresult gets destroyed during the rendering, so we first collect all ibufs
@@ -2874,7 +1626,7 @@ static void do_render_seq(Render *re)
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* main loop: doing sequence + fields + blur + 3d render + compositing */
+/* main loop: doing sequence + 3d render + compositing */
static void do_render_all_options(Render *re)
{
Object *camera;
@@ -2904,12 +1656,7 @@ static void do_render_all_options(Render *re)
re->display_update(re->duh, re->result, NULL);
}
else {
- re->pool = BKE_image_pool_new();
-
- do_render_composite_fields_blur_3d(re);
-
- BKE_image_pool_free(re->pool);
- re->pool = NULL;
+ do_render_composite(re);
}
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -2931,20 +1678,6 @@ static void do_render_all_options(Render *re)
}
}
-bool RE_force_single_renderlayer(Scene *scene)
-{
- int scemode = check_mode_full_sample(&scene->r);
- if (scemode & R_SINGLE_LAYER) {
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- /* force layer to be enabled */
- if (srl->layflag & SCE_LAY_DISABLE) {
- srl->layflag &= ~SCE_LAY_DISABLE;
- return true;
- }
- }
- return false;
-}
-
static bool check_valid_compositing_camera(Scene *scene, Object *camera_override)
{
if (scene->r.scemode & R_DOCOMP && scene->use_nodes) {
@@ -2954,7 +1687,7 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override
if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
Scene *sce = node->id ? (Scene *)node->id : scene;
if (sce->camera == NULL) {
- sce->camera = BKE_scene_camera_find(sce);
+ sce->camera = BKE_view_layer_camera_find(BKE_view_layer_default_render(sce));
}
if (sce->camera == NULL) {
/* all render layers nodes need camera */
@@ -3012,7 +1745,7 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList
const char *err_msg = "No camera found in scene \"%s\"";
if (camera_override == NULL && scene->camera == NULL)
- scene->camera = BKE_scene_camera_find(scene);
+ scene->camera = BKE_view_layer_camera_find(BKE_view_layer_default_render(scene));
if (!check_valid_camera_multiview(scene, scene->camera, reports))
return false;
@@ -3027,7 +1760,9 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList
(seq->scene != NULL))
{
if (!seq->scene_camera) {
- if (!seq->scene->camera && !BKE_scene_camera_find(seq->scene)) {
+ if (!seq->scene->camera &&
+ !BKE_view_layer_camera_find(BKE_view_layer_default_render(seq->scene)))
+ {
/* camera could be unneeded due to composite nodes */
Object *override = (seq->scene == scene) ? camera_override : NULL;
@@ -3078,7 +1813,7 @@ static int check_composite_output(Scene *scene)
return node_tree_has_composite_output(scene->nodetree);
}
-bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *reports)
+bool RE_is_rendering_allowed(Scene *scene, ViewLayer *single_layer, Object *camera_override, ReportList *reports)
{
int scemode = check_mode_full_sample(&scene->r);
@@ -3100,13 +1835,6 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
BKE_report(reports, RPT_ERROR, "Cannot save render buffers, check the temp default path");
return 0;
}
-
- /* no fullsample and edge */
- if ((scemode & R_FULL_SAMPLE) && (scene->r.mode & R_EDGE)) {
- BKE_report(reports, RPT_ERROR, "Full sample does not support edge enhance");
- return 0;
- }
-
}
if (scemode & R_DOCOMP) {
@@ -3135,33 +1863,6 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
return 0;
}
- /* get panorama & ortho, only after camera is set */
- BKE_camera_object_mode(&scene->r, camera_override ? camera_override : scene->camera);
-
- /* forbidden combinations */
- if (scene->r.mode & R_PANORAMA) {
- if (scene->r.mode & R_ORTHO) {
- BKE_report(reports, RPT_ERROR, "No ortho render possible for panorama");
- return 0;
- }
-
-#ifdef WITH_FREESTYLE
- if (scene->r.mode & R_EDGE_FRS) {
- BKE_report(reports, RPT_ERROR, "Panoramic camera not supported in Freestyle");
- return 0;
- }
-#endif
- }
-
-#ifdef WITH_FREESTYLE
- if (scene->r.mode & R_EDGE_FRS) {
- if (scene->r.mode & R_FIELDS) {
- BKE_report(reports, RPT_ERROR, "Fields not supported in Freestyle");
- return false;
- }
- }
-#endif
-
if (RE_seq_render_active(scene, &scene->r)) {
if (scene->r.mode & R_BORDER) {
BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer");
@@ -3170,7 +1871,7 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
}
/* layer flag tests */
- if (!render_scene_has_layers_to_render(scene)) {
+ if (!render_scene_has_layers_to_render(scene, single_layer)) {
BKE_report(reports, RPT_ERROR, "All render layers are disabled");
return 0;
}
@@ -3180,26 +1881,21 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
static void validate_render_settings(Render *re)
{
- if (re->r.scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) {
- /* no osa + fullsample won't work... */
- if (re->r.osa == 0)
- re->r.scemode &= ~R_FULL_SAMPLE;
- }
-
if (RE_engine_is_external(re)) {
/* not supported yet */
re->r.scemode &= ~(R_FULL_SAMPLE);
- re->r.mode &= ~(R_FIELDS | R_MBLUR);
}
}
-static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init))
+static void update_physics_cache(Render *re, Scene *scene, ViewLayer *view_layer, int UNUSED(anim_init))
{
PTCacheBaker baker;
memset(&baker, 0, sizeof(baker));
baker.bmain = re->main;
baker.scene = scene;
+ baker.view_layer = view_layer;
+ baker.depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
baker.bake = 0;
baker.render = 1;
baker.anim_init = 1;
@@ -3219,8 +1915,9 @@ const char *RE_GetActiveRenderView(Render *re)
}
/* evaluating scene options for general Blender render */
-static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, Scene *scene, SceneRenderLayer *srl,
- Object *camera_override, unsigned int lay_override, int anim, int anim_init)
+static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, Scene *scene,
+ ViewLayer *single_layer, Object *camera_override,
+ int anim, int anim_init)
{
int winx, winy;
rcti disprect;
@@ -3248,23 +1945,16 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
re->main = bmain;
re->scene = scene;
- re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
re->camera_override = camera_override;
- re->lay = lay_override ? lay_override : scene->lay;
- re->layer_override = lay_override;
- re->i.localview = (re->lay & 0xFF000000) != 0;
re->viewname[0] = '\0';
/* not too nice, but it survives anim-border render */
if (anim) {
- render_update_anim_renderdata(re, &scene->r);
+ render_update_anim_renderdata(re, &scene->r, &scene->view_layers);
re->disprect = disprect;
return 1;
}
- /* check all scenes involved */
- tag_scenes_for_render(re);
-
/*
* Disabled completely for now,
* can be later set as render profile option
@@ -3272,16 +1962,17 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
*/
if (0) {
/* make sure dynamics are up to date */
- update_physics_cache(re, scene, anim_init);
+ ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene);
+ update_physics_cache(re, scene, view_layer, anim_init);
}
- if (srl || scene->r.scemode & R_SINGLE_LAYER) {
+ if (single_layer || scene->r.scemode & R_SINGLE_LAYER) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
render_result_single_layer_begin(re);
BLI_rw_mutex_unlock(&re->resultmutex);
}
- RE_InitState(re, NULL, &scene->r, srl, winx, winy, &disprect);
+ RE_InitState(re, NULL, &scene->r, &scene->view_layers, single_layer, winx, winy, &disprect);
if (!re->ok) /* if an error was printed, abort */
return 0;
@@ -3302,8 +1993,8 @@ void RE_SetReports(Render *re, ReportList *reports)
}
/* general Blender frame render call */
-void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override,
- unsigned int lay_override, int frame, const bool write_still)
+void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, ViewLayer *single_layer, Object *camera_override,
+ int frame, const bool write_still)
{
BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
@@ -3312,7 +2003,9 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
scene->r.cfra = frame;
- if (render_initialize_from_main(re, &scene->r, bmain, scene, srl, camera_override, lay_override, 0, 0)) {
+ if (render_initialize_from_main(re, &scene->r, bmain, scene, single_layer,
+ camera_override, 0, 0))
+ {
MEM_reset_peak_memory();
BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
@@ -3343,6 +2036,9 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
BLI_callback_exec(re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE);
+ /* Destroy the opengl context in the correct thread. */
+ RE_gl_context_destroy(re);
+
/* UGLY WARNING */
G.is_rendering = false;
}
@@ -3351,9 +2047,9 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render)
{
re->result_ok= 0;
- if (render_initialize_from_main(re, &scene->r, bmain, scene, NULL, NULL, scene->lay, 0, 0)) {
+ if (render_initialize_from_main(re, &scene->r, bmain, scene, NULL, NULL, 0, 0)) {
if (render)
- do_render_fields_blur_3d(re);
+ do_render_3d(re);
}
re->result_ok = 1;
}
@@ -3367,10 +2063,29 @@ void RE_RenderFreestyleExternal(Render *re)
for (rv = re->result->views.first; rv; rv = rv->next) {
RE_SetActiveRenderView(re, rv->name);
- RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
- RE_Database_Preprocess(re);
+
+ /* scene needs to be set to get camera */
+ Object *camera = RE_GetCamera(re);
+
+ /* if no camera, viewmat should have been set! */
+ if (camera) {
+ /* called before but need to call again in case of lens animation from the
+ * above call to BKE_scene_graph_update_for_newframe, fixes bug. [#22702].
+ * following calls don't depend on 'RE_SetCamera' */
+ float mat[4][4];
+
+ RE_SetCamera(re, camera);
+ RE_GetCameraModelMatrix(re, camera, mat);
+ invert_m4(mat);
+ RE_SetView(re, mat);
+
+ /* force correct matrix for scaled cameras */
+ DEG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
+ }
+
+ printf("add freestyle\n");
+
add_freestyle(re, 1);
- RE_Database_Free(re);
}
}
}
@@ -3633,8 +2348,8 @@ static void re_movie_free_all(Render *re, bMovieHandle *mh, int totvideos)
}
/* saves images to disk */
-void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override,
- unsigned int lay_override, int sfra, int efra, int tfra)
+void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, ViewLayer *single_layer, Object *camera_override,
+ int sfra, int efra, int tfra)
{
RenderData rd = scene->r;
bMovieHandle *mh = NULL;
@@ -3648,18 +2363,9 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
/* do not fully call for each frame, it initializes & pops output window */
- if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1))
+ if (!render_initialize_from_main(re, &rd, bmain, scene, single_layer, camera_override, 0, 1))
return;
- /* MULTIVIEW_TODO:
- * in case a new video format is added that implements get_next_frame multiview has to be addressed
- * or the error throwing for R_IMF_IMTYPE_FRAMESERVER has to be extended for those cases as well
- */
- if ((rd.im_format.imtype == R_IMF_IMTYPE_FRAMESERVER) && (totvideos > 1)) {
- BKE_report(re->reports, RPT_ERROR, "Frame Server only support stereo output for multiview rendering");
- return;
- }
-
if (is_movie) {
size_t width, height;
int i;
@@ -3734,26 +2440,20 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
{
float ctime = BKE_scene_frame_get(scene);
AnimData *adt = BKE_animdata_from_id(&scene->id);
- BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, ADT_RECALC_ALL);
+ /* TODO(sergey): Currently depsgraph is only used to check whether it is an active
+ * edit window or not to deal with unkeyed changes. We don't have depsgraph here yet,
+ * but we also dont' deal with unkeyed changes. But still nice to get proper depsgraph
+ * within tjhe render pipeline, somehow.
+ */
+ BKE_animsys_evaluate_animdata(NULL, scene, &scene->id, adt, ctime, ADT_RECALC_ALL);
}
/* only border now, todo: camera lens. (ton) */
- render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 1, 0);
+ render_initialize_from_main(re, &rd, bmain, scene,
+ single_layer, camera_override, 1, 0);
if (nfra != scene->r.cfra) {
- /*
- * Skip this frame, but update for physics and particles system.
- * From convertblender.c:
- * in localview, lamps are using normal layers, objects only local bits.
- */
- unsigned int updatelay;
-
- if (re->lay & 0xFF000000)
- updatelay = re->lay & 0xFF000000;
- else
- updatelay = re->lay;
-
- BKE_scene_update_for_newframe(re->eval_ctx, bmain, scene, updatelay);
+ /* Skip this frame, but could update for physics and particles system. */
continue;
}
else
@@ -3895,6 +2595,9 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
BLI_callback_exec(re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE);
BKE_sound_reset_scene_specs(scene);
+ /* Destroy the opengl context in the correct thread. */
+ RE_gl_context_destroy(re);
+
/* UGLY WARNING */
G.is_rendering = false;
}
@@ -3907,22 +2610,15 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
winx = (sce->r.size * sce->r.xsch) / 100;
winy = (sce->r.size * sce->r.ysch) / 100;
- RE_InitState(re, NULL, &sce->r, NULL, winx, winy, NULL);
-
- re->pool = BKE_image_pool_new();
+ RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, winx, winy, NULL);
re->main = bmain;
re->scene = sce;
- re->scene_color_manage = BKE_scene_check_color_management_enabled(sce);
- re->lay = sce->lay;
camera = RE_GetCamera(re);
RE_SetCamera(re, camera);
do_render_3d(re);
-
- BKE_image_pool_free(re->pool);
- re->pool = NULL;
}
/* note; repeated win/disprect calc... solve that nicer, also in compo */
@@ -3960,9 +2656,8 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
re = RE_GetSceneRender(scene);
if (re == NULL)
re = RE_NewSceneRender(scene);
- RE_InitState(re, NULL, &scene->r, NULL, winx, winy, &disprect);
+ RE_InitState(re, NULL, &scene->r, &scene->view_layers, NULL, winx, winy, &disprect);
re->scene = scene;
- re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
success = render_result_exr_file_cache_read(re);
@@ -4039,67 +2734,6 @@ void RE_result_load_from_file(RenderResult *result, ReportList *reports, const c
}
}
-const float default_envmap_layout[] = { 0, 0, 1, 0, 2, 0, 0, 1, 1, 1, 2, 1 };
-
-bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env, const char *relpath, const char imtype, float layout[12])
-{
- ImageFormatData imf;
- ImBuf *ibuf = NULL;
- int ok;
- int dx;
- int maxX = 0, maxY = 0, i = 0;
- char filepath[FILE_MAX];
-
- if (env->cube[1] == NULL) {
- BKE_report(reports, RPT_ERROR, "There is no generated environment map available to save");
- return 0;
- }
-
- imf = scene->r.im_format;
- imf.imtype = imtype;
-
- dx = env->cube[1]->x;
-
- if (env->type == ENV_CUBE) {
- for (i = 0; i < 12; i += 2) {
- maxX = max_ii(maxX, (int)layout[i] + 1);
- maxY = max_ii(maxY, (int)layout[i + 1] + 1);
- }
-
- ibuf = IMB_allocImBuf(maxX * dx, maxY * dx, 24, IB_rectfloat);
-
- for (i = 0; i < 12; i += 2)
- if (layout[i] > -1 && layout[i + 1] > -1)
- IMB_rectcpy(ibuf, env->cube[i / 2], layout[i] * dx, layout[i + 1] * dx, 0, 0, dx, dx);
- }
- else if (env->type == ENV_PLANE) {
- ibuf = IMB_allocImBuf(dx, dx, 24, IB_rectfloat);
- IMB_rectcpy(ibuf, env->cube[1], 0, 0, 0, 0, dx, dx);
- }
- else {
- BKE_report(reports, RPT_ERROR, "Invalid environment map type");
- return 0;
- }
-
- IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf);
-
- /* to save, we first get absolute path */
- BLI_strncpy(filepath, relpath, sizeof(filepath));
- BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());
-
- ok = BKE_imbuf_write(ibuf, filepath, &imf);
-
- IMB_freeImBuf(ibuf);
-
- if (ok) {
- return true;
- }
- else {
- BKE_report(reports, RPT_ERROR, "Error writing environment map");
- return false;
- }
-}
-
/* Used in the interface to decide whether to show layers or passes. */
bool RE_layers_have_name(struct RenderResult *rr)
{
@@ -4193,7 +2827,6 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
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;
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c
deleted file mode 100644
index c7cfe765f5b..00000000000
--- a/source/blender/render/intern/source/pixelblending.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Full recode, 2004-2006 Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/pixelblending.c
- * \ingroup render
- *
- * Functions to blend pixels with or without alpha, in various formats
- * nzc - June 2000
- */
-
-
-#include <math.h>
-#include <string.h>
-
-/* global includes */
-
-/* own includes */
-#include "render_types.h"
-#include "pixelblending.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
-/* ------------------------------------------------------------------------- */
-/* Debug/behavior defines */
-/* if defined: alpha blending with floats clips color, as with shorts */
-/* #define RE_FLOAT_COLOR_CLIPPING */
-/* if defined: alpha values are clipped */
-/* For now, we just keep alpha clipping. We run into thresholding and */
-/* blending difficulties otherwise. Be careful here. */
-#define RE_ALPHA_CLIPPING
-
-
-
-/* Threshold for a 'full' pixel: pixels with alpha above this level are */
-/* considered opaque This is the decimal value for 0xFFF0 / 0xFFFF */
-#define RE_FULL_COLOR_FLOAT 0.9998f
-/* Threshold for an 'empty' pixel: pixels with alpha above this level are */
-/* considered completely transparent. This is the decimal value */
-/* for 0x000F / 0xFFFF */
-#define RE_EMPTY_COLOR_FLOAT 0.0002f
-
-
-/* ------------------------------------------------------------------------- */
-
-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];
-
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-void addAlphaUnderFloat(float dest[4], const float source[4])
-{
- float mul;
-
- mul = 1.0f - dest[3];
-
- dest[0] += (mul * source[0]);
- dest[1] += (mul * source[1]);
- dest[2] += (mul * source[2]);
- dest[3] += (mul * source[3]);
-}
-
-
-/* ------------------------------------------------------------------------- */
-void addalphaAddfacFloat(float dest[4], const float source[4], char addfac)
-{
- float m; /* weiging factor of destination */
- float c; /* intermediate color */
-
- /* Addfac is a number between 0 and 1: rescale */
- /* final target is to diminish the influence of dest when addfac rises */
- m = 1.0f - (source[3] * ((255 - addfac) / 255.0f));
-
- /* blend colors*/
- c = (m * dest[0]) + source[0];
-#ifdef RE_FLOAT_COLOR_CLIPPING
- if (c >= RE_FULL_COLOR_FLOAT) dest[0] = RE_FULL_COLOR_FLOAT;
- else
-#endif
- dest[0] = c;
-
- c = (m * dest[1]) + source[1];
-#ifdef RE_FLOAT_COLOR_CLIPPING
- if (c >= RE_FULL_COLOR_FLOAT) dest[1] = RE_FULL_COLOR_FLOAT;
- else
-#endif
- dest[1] = c;
-
- c = (m * dest[2]) + source[2];
-#ifdef RE_FLOAT_COLOR_CLIPPING
- if (c >= RE_FULL_COLOR_FLOAT) dest[2] = RE_FULL_COLOR_FLOAT;
- else
-#endif
- dest[2] = c;
-
- c = (m * dest[3]) + source[3];
-#ifdef RE_ALPHA_CLIPPING
- if (c >= RE_FULL_COLOR_FLOAT) dest[3] = RE_FULL_COLOR_FLOAT;
- else
-#endif
- dest[3] = c;
-
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/* filtered adding to scanlines */
-void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w)
-{
- /* calc the value of mask */
- float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
- float *rb1, *rb2, *rb3;
- float val, r, g, b, al;
- unsigned int a, maskand, maskshift;
- int j;
-
- r = col[0];
- g = col[1];
- b = col[2];
- al = col[3];
-
- rb2 = rowbuf - 4;
- rb3 = rb2 - 4 * row_w;
- rb1 = rb2 + 4 * row_w;
-
- maskand = (mask & 255);
- maskshift = (mask >> 8);
-
- for (j = 2; j >= 0; j--) {
-
- a = j;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- rb1[0] += val * r;
- rb1[1] += val * g;
- rb1[2] += val * b;
- rb1[3] += val * al;
- }
- a += 3;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- rb2[0] += val * r;
- rb2[1] += val * g;
- rb2[2] += val * b;
- rb2[3] += val * al;
- }
- a += 3;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- rb3[0] += val * r;
- rb3[1] += val * g;
- rb3[2] += val * b;
- rb3[3] += val * al;
- }
-
- rb1 += 4;
- rb2 += 4;
- rb3 += 4;
- }
-}
-
-
-void mask_array(unsigned int mask, float filt[3][3])
-{
- float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
- unsigned int maskand = (mask & 255);
- unsigned int maskshift = (mask >> 8);
- int a, j;
-
- for (j = 2; j >= 0; j--) {
-
- a = j;
-
- filt[2][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
-
- a += 3;
-
- filt[1][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
-
- a += 3;
-
- filt[0][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- }
-}
-
-
-/**
- * Index ordering, scanline based:
- *
- * <pre>
- * --- --- ---
- * | 2,0 | 2,1 | 2,2 |
- * --- --- ---
- * | 1,0 | 1,1 | 1,2 |
- * --- --- ---
- * | 0,0 | 0,1 | 0,2 |
- * --- --- ---
- * </pre>
- */
-
-void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask)
-{
- float *fpoin[3][3];
- float val, r, g, b, al, lfilt[3][3];
-
- r = col[0];
- g = col[1];
- b = col[2];
- al = col[3];
-
- memcpy(lfilt, filt, sizeof(lfilt));
-
- fpoin[0][1] = rowbuf - 4 * row_stride;
- fpoin[1][1] = rowbuf;
- fpoin[2][1] = rowbuf + 4 * row_stride;
-
- fpoin[0][0] = fpoin[0][1] - 4;
- fpoin[1][0] = fpoin[1][1] - 4;
- fpoin[2][0] = fpoin[2][1] - 4;
-
- fpoin[0][2] = fpoin[0][1] + 4;
- fpoin[1][2] = fpoin[1][1] + 4;
- fpoin[2][2] = fpoin[2][1] + 4;
-
- /* limit filtering to withing a mask for border rendering, so pixels don't
- * leak outside of the border */
- if (y <= mask->ymin) {
- fpoin[0][0] = fpoin[1][0];
- fpoin[0][1] = fpoin[1][1];
- fpoin[0][2] = fpoin[1][2];
- /* filter needs the opposite value yes! */
- lfilt[0][0] = filt[2][0];
- lfilt[0][1] = filt[2][1];
- lfilt[0][2] = filt[2][2];
- }
- else if (y >= mask->ymax - 1) {
- fpoin[2][0] = fpoin[1][0];
- fpoin[2][1] = fpoin[1][1];
- fpoin[2][2] = fpoin[1][2];
-
- lfilt[2][0] = filt[0][0];
- lfilt[2][1] = filt[0][1];
- lfilt[2][2] = filt[0][2];
- }
-
- if (x <= mask->xmin) {
- fpoin[2][0] = fpoin[2][1];
- fpoin[1][0] = fpoin[1][1];
- fpoin[0][0] = fpoin[0][1];
-
- lfilt[2][0] = filt[2][2];
- lfilt[1][0] = filt[1][2];
- lfilt[0][0] = filt[0][2];
- }
- else if (x >= mask->xmax - 1) {
- fpoin[2][2] = fpoin[2][1];
- fpoin[1][2] = fpoin[1][1];
- fpoin[0][2] = fpoin[0][1];
-
- lfilt[2][2] = filt[2][0];
- lfilt[1][2] = filt[1][0];
- lfilt[0][2] = filt[0][0];
- }
-
-
- /* loop unroll */
-#define MASKFILT(i, j) \
- val = lfilt[i][j]; \
- if (val != 0.0f) { \
- float *fp = fpoin[i][j]; \
- fp[0] += val * r; \
- fp[1] += val * g; \
- fp[2] += val * b; \
- fp[3] += val * al; \
- } (void)0
-
- MASKFILT(0, 0);
- MASKFILT(0, 1);
- MASKFILT(0, 2);
- MASKFILT(1, 0);
- MASKFILT(1, 1);
- MASKFILT(1, 2);
- MASKFILT(2, 0);
- MASKFILT(2, 1);
- MASKFILT(2, 2);
-
-#undef MASKFILT
-}
-
-void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize)
-{
- /* calc the value of mask */
- float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
- float *rb1, *rb2, *rb3;
- float val;
- unsigned int a, maskand, maskshift;
- int i, j;
-
- rb2 = rowbuf - pixsize;
- rb3 = rb2 - pixsize * row_w;
- rb1 = rb2 + pixsize * row_w;
-
- maskand = (mask & 255);
- maskshift = (mask >> 8);
-
- for (j = 2; j >= 0; j--) {
-
- a = j;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- for (i = 0; i < pixsize; i++)
- rb1[i] += val * in[i];
- }
- a += 3;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- for (i = 0; i < pixsize; i++)
- rb2[i] += val * in[i];
- }
- a += 3;
-
- val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
- if (val != 0.0f) {
- for (i = 0; i < pixsize; i++)
- rb3[i] += val * in[i];
- }
-
- rb1 += pixsize;
- rb2 += pixsize;
- rb3 += pixsize;
- }
-}
-
-/* ------------------------------------------------------------------------- */
-void addalphaAddFloat(float dest[4], const float source[4])
-{
-
- /* Makes me wonder whether this is required... */
- if (dest[3] < RE_EMPTY_COLOR_FLOAT) {
- dest[0] = source[0];
- dest[1] = source[1];
- dest[2] = source[2];
- dest[3] = source[3];
- return;
- }
-
- /* no clipping! */
- dest[0] = dest[0] + source[0];
- dest[1] = dest[1] + source[1];
- dest[2] = dest[2] + source[2];
- dest[3] = dest[3] + source[3];
-
-}
-
-
-/* ---------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
deleted file mode 100644
index 7f202629ce4..00000000000
--- a/source/blender/render/intern/source/pixelshading.c
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): 2004-2006, Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/pixelshading.c
- * \ingroup render
- */
-
-
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-/* External modules: */
-
-#include "DNA_group_types.h"
-#include "DNA_material_types.h"
-#include "DNA_object_types.h"
-#include "DNA_image_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_lamp_types.h"
-
-#include "BKE_material.h"
-
-
-/* own module */
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "texture.h"
-#include "rendercore.h"
-#include "shadbuf.h"
-#include "pixelshading.h"
-#include "sunsky.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
-extern const float hashvectf[];
-
-static void render_lighting_halo(HaloRen *har, float col_r[3])
-{
- GroupObject *go;
- LampRen *lar;
- float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
- float ir, ig, ib, shadfac, soft, lacol[3];
-
- ir= ig= ib= 0.0;
-
- copy_v3_v3(rco, har->co);
- dco[0]=dco[1]=dco[2]= 1.0f/har->rad;
-
- vn= har->no;
-
- for (go=R.lights.first; go; go= go->next) {
- lar= go->lampren;
-
- /* test for lamplayer */
- if (lar->mode & LA_LAYER) if ((lar->lay & har->lay)==0) continue;
-
- /* lampdist cacluation */
- if (lar->type==LA_SUN || lar->type==LA_HEMI) {
- copy_v3_v3(lv, lar->vec);
- lampdist= 1.0;
- }
- else {
- lv[0]= rco[0]-lar->co[0];
- lv[1]= rco[1]-lar->co[1];
- lv[2]= rco[2]-lar->co[2];
- ld = len_v3(lv);
- lv[0]/= ld;
- lv[1]/= ld;
- lv[2]/= ld;
-
- /* ld is re-used further on (texco's) */
-
- if (lar->mode & LA_QUAD) {
- t= 1.0;
- if (lar->ld1>0.0f)
- t= lar->dist/(lar->dist+lar->ld1*ld);
- if (lar->ld2>0.0f)
- t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
-
- lampdist= t;
- }
- else {
- lampdist= (lar->dist/(lar->dist+ld));
- }
-
- if (lar->mode & LA_SPHERE) {
- t= lar->dist - ld;
- if (t<0.0f) continue;
-
- t/= lar->dist;
- lampdist*= (t);
- }
-
- }
-
- lacol[0]= lar->r;
- lacol[1]= lar->g;
- lacol[2]= lar->b;
-
- if (lar->mode & LA_TEXTURE) {
- ShadeInput shi;
-
- /* Warning, This is not that nice, and possibly a bit slow,
- * however some variables were not initialized properly in, unless using shade_input_initialize(...),
- * we need to do a memset */
- memset(&shi, 0, sizeof(ShadeInput));
- /* end warning! - Campbell */
-
- copy_v3_v3(shi.co, rco);
- shi.osatex= 0;
- do_lamp_tex(lar, lv, &shi, lacol, LA_TEXTURE);
- }
-
- if (lar->type==LA_SPOT) {
-
- if (lar->mode & LA_SQUARE) {
- if (lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) {
- float x, lvrot[3];
-
- /* rotate view to lampspace */
- copy_v3_v3(lvrot, lv);
- mul_m3_v3(lar->imat, lvrot);
-
- x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
- /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
-
- inpr = 1.0f / (sqrtf(1.0f + x * x));
- }
- else inpr= 0.0;
- }
- else {
- inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
- }
-
- t= lar->spotsi;
- if (inpr<t) continue;
- else {
- t= inpr-t;
- soft= 1.0;
- if (t<lar->spotbl && lar->spotbl!=0.0f) {
- /* soft area */
- i= t/lar->spotbl;
- t= i*i;
- soft= (3.0f*t-2.0f*t*i);
- inpr*= soft;
- }
- if (lar->mode & LA_ONLYSHADOW) {
- /* if (ma->mode & MA_SHADOW) { */
- /* dot product positive: front side face! */
- inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
- if (inp>0.0f) {
- /* testshadowbuf==0.0 : 100% shadow */
- shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
- if ( shadfac>0.0f ) {
- shadfac*= inp*soft*lar->energy;
- ir -= shadfac;
- ig -= shadfac;
- ib -= shadfac;
-
- continue;
- }
- }
- /* } */
- }
- lampdist*=inpr;
- }
- if (lar->mode & LA_ONLYSHADOW) continue;
-
- }
-
- /* dot product and reflectivity*/
-
- inp = 1.0f - fabsf(dot_v3v3(vn, lv));
-
- /* inp= cos(0.5*M_PI-acos(inp)); */
-
- i= inp;
-
- if (lar->type==LA_HEMI) {
- i= 0.5f*i+0.5f;
- }
- if (i>0.0f) {
- i*= lampdist;
- }
-
- /* shadow */
- if (i> -0.41f) { /* heuristic valua! */
- if (lar->shb) {
- shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
- if (shadfac==0.0f) continue;
- i*= shadfac;
- }
- }
-
- if (i>0.0f) {
- ir+= i*lacol[0];
- ig+= i*lacol[1];
- ib+= i*lacol[2];
- }
- }
-
- if (ir<0.0f) ir= 0.0f;
- if (ig<0.0f) ig= 0.0f;
- if (ib<0.0f) ib= 0.0f;
-
- col_r[0]*= ir;
- col_r[1]*= ig;
- col_r[2]*= ib;
-
-}
-
-
-/**
- * Converts a halo z-buffer value to distance from the camera's near plane
- * \param z The z-buffer value to convert
- * \return a distance from the camera's near plane in blender units
- */
-static float haloZtoDist(int z)
-{
- float zco = 0;
-
- if (z >= 0x7FFFFF)
- return 10e10;
- else {
- zco = (float)z/(float)0x7FFFFF;
- if (R.r.mode & R_ORTHO)
- return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
- else
- return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
- }
-}
-
-/**
- * \param col (float[4]) Store the rgb color here (with alpha)
- * The alpha is used to blend the color to the background
- * color_new = (1-alpha)*color_background + color
- * \param zz The current zbuffer value at the place of this pixel
- * \param dist Distance of the pixel from the center of the halo squared. Given in pixels
- * \param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels
- * \param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels
- */
-int shadeHaloFloat(HaloRen *har, float col[4], int zz,
- float dist, float xn, float yn, short flarec)
-{
- /* fill in col */
- float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
- int a;
-
- if (R.wrld.mode & WO_MIST) {
- if (har->type & HA_ONLYSKY) {
- alpha= har->alfa;
- }
- else {
- /* a bit patchy... */
- alpha= mistfactor(-har->co[2], har->co)*har->alfa;
- }
- }
- else alpha= har->alfa;
-
- if (alpha==0.0f)
- return 0;
-
- /* soften the halo if it intersects geometry */
- if (har->mat && har->mat->mode & MA_HALO_SOFT) {
- float segment_length, halo_depth, distance_from_z /* , visible_depth */ /* UNUSED */, soften;
-
- /* calculate halo depth */
- segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad));
- halo_depth= 2.0f*segment_length;
-
- if (halo_depth < FLT_EPSILON)
- return 0;
-
- /* calculate how much of this depth is visible */
- distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs);
- /* visible_depth = halo_depth; */ /* UNUSED */
- if (distance_from_z < segment_length) {
- soften= (segment_length + distance_from_z)/halo_depth;
-
- /* apply softening to alpha */
- if (soften < 1.0f)
- alpha *= soften;
- if (alpha <= 0.0f)
- return 0;
- }
- }
- else {
- /* not a soft halo. use the old softening code */
- /* halo being intersected? */
- if (har->zs> zz-har->zd) {
- t= ((float)(zz-har->zs))/(float)har->zd;
- alpha*= sqrtf(sqrtf(t));
- }
- }
-
- radist = sqrtf(dist);
-
- /* watch it: not used nicely: flarec is set at zero in pixstruct */
- if (flarec) har->pixels+= (int)(har->rad-radist);
-
- if (har->ringc) {
- const float *rc;
- float fac;
- int ofs;
-
- /* per ring an antialised circle */
- ofs= har->seed;
-
- for (a= har->ringc; a>0; a--, ofs+=2) {
-
- rc= hashvectf + (ofs % 768);
-
- fac = fabsf(rc[1] * (har->rad * fabsf(rc[0]) - radist));
-
- if (fac< 1.0f) {
- ringf+= (1.0f-fac);
- }
- }
- }
-
- if (har->type & HA_VECT) {
- dist= fabsf(har->cos * (yn) - har->sin * (xn)) / har->rad;
- if (dist>1.0f) dist= 1.0f;
- if (har->tex) {
- zn= har->sin*xn - har->cos*yn;
- yn= har->cos*xn + har->sin*yn;
- xn= zn;
- }
- }
- else dist= dist/har->radsq;
-
- if (har->type & HA_FLARECIRC) {
- dist = 0.5f + fabsf(dist - 0.5f);
- }
-
- if (har->hard>=30) {
- dist = sqrtf(dist);
- if (har->hard>=40) {
- dist = sinf(dist*(float)M_PI_2);
- if (har->hard>=50) {
- dist = sqrtf(dist);
- }
- }
- }
- else if (har->hard<20) dist*=dist;
-
- if (dist < 1.0f)
- dist= (1.0f-dist);
- else
- dist= 0.0f;
-
- if (har->linec) {
- const float *rc;
- float fac;
- int ofs;
-
- /* per starpoint an antialiased line */
- ofs= har->seed;
-
- for (a= har->linec; a>0; a--, ofs+=3) {
-
- rc= hashvectf + (ofs % 768);
-
- fac = fabsf((xn) * rc[0] + (yn) * rc[1]);
-
- if (fac< 1.0f )
- linef+= (1.0f-fac);
- }
-
- linef*= dist;
- }
-
- if (har->starpoints) {
- float ster, angle;
- /* rotation */
- angle = atan2f(yn, xn);
- angle *= (1.0f+0.25f*har->starpoints);
-
- co= cosf(angle);
- si= sinf(angle);
-
- angle= (co*xn+si*yn)*(co*yn-si*xn);
-
- ster = fabsf(angle);
- if (ster>1.0f) {
- ster= (har->rad)/(ster);
-
- if (ster<1.0f) dist*= sqrtf(ster);
- }
- }
-
- /* disputable optimize... (ton) */
- if (dist<=0.00001f)
- return 0;
-
- dist*= alpha;
- ringf*= dist;
- linef*= alpha;
-
- /* The color is either the rgb spec-ed by the user, or extracted from */
- /* the texture */
- if (har->tex) {
- col[0]= har->r;
- col[1]= har->g;
- col[2]= har->b;
- col[3]= dist;
-
- do_halo_tex(har, xn, yn, col);
-
- col[0]*= col[3];
- col[1]*= col[3];
- col[2]*= col[3];
-
- }
- else {
- col[0]= dist*har->r;
- col[1]= dist*har->g;
- col[2]= dist*har->b;
- if (har->type & HA_XALPHA) col[3]= dist*dist;
- else col[3]= dist;
- }
-
- if (har->mat) {
- if (har->mat->mode & MA_HALO_SHADE) {
- /* we test for lights because of preview... */
- if (R.lights.first) render_lighting_halo(har, col);
- }
-
- /* Next, we do the line and ring factor modifications. */
- if (linef!=0.0f) {
- Material *ma= har->mat;
-
- col[0]+= linef * ma->specr;
- col[1]+= linef * ma->specg;
- col[2]+= linef * ma->specb;
-
- if (har->type & HA_XALPHA) col[3]+= linef*linef;
- else col[3]+= linef;
- }
- if (ringf!=0.0f) {
- Material *ma= har->mat;
-
- col[0]+= ringf * ma->mirr;
- col[1]+= ringf * ma->mirg;
- col[2]+= ringf * ma->mirb;
-
- if (har->type & HA_XALPHA) col[3]+= ringf*ringf;
- else col[3]+= ringf;
- }
- }
-
- /* alpha requires clip, gives black dots */
- if (col[3] > 1.0f)
- col[3]= 1.0f;
-
- return 1;
-}
-
-/* ------------------------------------------------------------------------- */
-
-/* Only view vector is important here. Result goes to col_r[3] */
-void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread)
-{
- float zen[3], hor[3], blend, blendm;
- int skyflag;
-
- /* flag indicating if we render the top hemisphere */
- skyflag = WO_ZENUP;
-
- /* Some view vector stuff. */
- if (R.wrld.skytype & WO_SKYREAL) {
-
- blend = dot_v3v3(view, R.grvec);
-
- if (blend<0.0f) skyflag= 0;
-
- blend = fabsf(blend);
- }
- else if (R.wrld.skytype & WO_SKYPAPER) {
- blend= 0.5f + 0.5f * view[1];
- }
- else {
- /* the fraction of how far we are above the bottom of the screen */
- blend = fabsf(0.5f + view[1]);
- }
-
- copy_v3_v3(hor, &R.wrld.horr);
- copy_v3_v3(zen, &R.wrld.zenr);
-
- /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
- /* SKYBLEND is active, the texture and color blend are added. */
- if (R.wrld.skytype & WO_SKYTEX) {
- float lo[3];
- copy_v3_v3(lo, view);
- if (R.wrld.skytype & WO_SKYREAL) {
-
- mul_m3_v3(R.imat, lo);
-
- SWAP(float, lo[1], lo[2]);
-
- }
- do_sky_tex(rco, view, lo, dxyview, hor, zen, &blend, skyflag, thread);
- }
-
- if (blend>1.0f) blend= 1.0f;
- blendm= 1.0f-blend;
-
- /* No clipping, no conversion! */
- if (R.wrld.skytype & WO_SKYBLEND) {
- col_r[0] = (blendm*hor[0] + blend*zen[0]);
- col_r[1] = (blendm*hor[1] + blend*zen[1]);
- col_r[2] = (blendm*hor[2] + blend*zen[2]);
- }
- else {
- /* Done when a texture was grabbed. */
- col_r[0]= hor[0];
- col_r[1]= hor[1];
- col_r[2]= hor[2];
- }
-}
-
-/* shade sky according to sun lamps, all parameters are like shadeSkyView except sunsky*/
-void shadeSunView(float col_r[3], const float view[3])
-{
- GroupObject *go;
- LampRen *lar;
- float sview[3];
- bool do_init = true;
-
- for (go=R.lights.first; go; go= go->next) {
- lar= go->lampren;
- if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_SKY)) {
- float sun_collector[3];
- float colorxyz[3];
-
- if (do_init) {
-
- normalize_v3_v3(sview, view);
- mul_m3_v3(R.imat, sview);
- if (sview[2] < 0.0f)
- sview[2] = 0.0f;
- normalize_v3(sview);
- do_init = false;
- }
-
- GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz);
- xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2],
- lar->sunsky->sky_colorspace);
-
- ramp_blend(lar->sunsky->skyblendtype, col_r, lar->sunsky->skyblendfac, sun_collector);
- }
- }
-}
-
-
-/*
- * Stuff the sky color into the collector.
- */
-void shadeSkyPixel(float collector[4], float fx, float fy, short thread)
-{
- float view[3], dxyview[2];
-
- /*
- * The rules for sky:
- * 1. Draw an image, if a background image was provided. Stop
- * 2. get texture and color blend, and combine these.
- */
-
- float fac;
-
- if ((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
- /* 1. solid color */
- copy_v3_v3(collector, &R.wrld.horr);
-
- collector[3] = 0.0f;
- }
- else {
- /* 2. */
-
- /* This one true because of the context of this routine */
- if (R.wrld.skytype & WO_SKYPAPER) {
- view[0]= -1.0f + 2.0f*(fx/(float)R.winx);
- view[1]= -1.0f + 2.0f*(fy/(float)R.winy);
- view[2]= 0.0;
-
- dxyview[0]= 1.0f/(float)R.winx;
- dxyview[1]= 1.0f/(float)R.winy;
- }
- else {
- calc_view_vector(view, fx, fy);
- fac= normalize_v3(view);
-
- if (R.wrld.skytype & WO_SKYTEX) {
- dxyview[0]= -R.viewdx/fac;
- dxyview[1]= -R.viewdy/fac;
- }
- }
-
- /* get sky color in the collector */
- shadeSkyView(collector, NULL, view, dxyview, thread);
- collector[3] = 0.0f;
- }
-
- calc_view_vector(view, fx, fy);
- shadeSunView(collector, view);
-}
-
-/* aerial perspective */
-void shadeAtmPixel(struct SunSky *sunsky, float collector[3], float fx, float fy, float distance)
-{
- float view[3];
-
- calc_view_vector(view, fx, fy);
- normalize_v3(view);
- /*mul_m3_v3(R.imat, view);*/
- AtmospherePixleShader(sunsky, view, distance, collector);
-}
-
-/* eof */
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 635bfc58425..f51c472da8f 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -43,6 +43,7 @@
#include "BLT_translation.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
@@ -50,7 +51,6 @@
#include "BKE_colorband.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -58,17 +58,14 @@
#include "BKE_scene.h"
#include "BKE_colortools.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "render_types.h"
#include "texture.h"
-#include "pointdensity.h"
#include "RE_render_ext.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include "RE_shader_ext.h"
static ThreadMutex sample_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -77,15 +74,13 @@ static int point_data_used(PointDensity *pd)
int pd_bitflag = 0;
if (pd->source == TEX_PD_PSYS) {
- if ((pd->noise_influence == TEX_PD_NOISE_VEL) ||
- (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) ||
+ if ((pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) ||
(pd->color_source == TEX_PD_COLOR_PARTVEL) ||
(pd->color_source == TEX_PD_COLOR_PARTSPEED))
{
pd_bitflag |= POINT_DATA_VEL;
}
- if ((pd->noise_influence == TEX_PD_NOISE_AGE) ||
- (pd->color_source == TEX_PD_COLOR_PARTAGE) ||
+ if ((pd->color_source == TEX_PD_COLOR_PARTAGE) ||
(pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE))
{
pd_bitflag |= POINT_DATA_LIFE;
@@ -167,16 +162,11 @@ static void alloc_point_data(PointDensity *pd)
}
}
-static void pointdensity_cache_psys(Scene *scene,
+static void pointdensity_cache_psys(Depsgraph *depsgraph, Scene *scene,
PointDensity *pd,
Object *ob,
- ParticleSystem *psys,
- float viewmat[4][4],
- float winmat[4][4],
- int winx, int winy,
- const bool use_render_params)
+ ParticleSystem *psys)
{
- DerivedMesh *dm;
ParticleKey state;
ParticleCacheKey *cache;
ParticleSimulationData sim = {NULL};
@@ -187,35 +177,15 @@ static void pointdensity_cache_psys(Scene *scene,
int data_used;
float *data_vel, *data_life;
float partco[3];
-
- /* init everything */
- if (!psys || !ob || !pd) {
- return;
- }
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
data_used = point_data_used(pd);
- /* Just to create a valid rendering context for particles */
- if (use_render_params) {
- psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0);
- }
-
- if (use_render_params) {
- dm = mesh_create_derived_render(scene,
- ob,
- CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
- }
- else {
- dm = mesh_get_derived_final(scene,
- ob,
- CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
- }
-
if (!psys_check_enabled(ob, psys, use_render_params)) {
- psys_render_restore(ob, psys);
return;
}
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -298,33 +268,28 @@ static void pointdensity_cache_psys(Scene *scene,
}
BLI_bvhtree_balance(pd->point_tree);
- dm->release(dm);
if (psys->lattice_deform_data) {
end_latt_deform(psys->lattice_deform_data);
psys->lattice_deform_data = NULL;
}
-
- if (use_render_params) {
- psys_render_restore(ob, psys);
- }
}
-static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob), DerivedMesh *dm, float *data_color)
+static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob), Mesh *mesh, float *data_color)
{
- const MLoop *mloop = dm->getLoopArray(dm);
- const int totloop = dm->getNumLoops(dm);
+ const MLoop *mloop = mesh->mloop;
+ const int totloop = mesh->totloop;
const MLoopCol *mcol;
char layername[MAX_CUSTOMDATA_LAYER_NAME];
int i;
BLI_assert(data_color);
- if (!CustomData_has_layer(&dm->loopData, CD_MLOOPCOL))
+ if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPCOL))
return;
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPCOL, pd->vertex_attribute_name, layername);
- mcol = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, layername);
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPCOL, pd->vertex_attribute_name, layername);
+ mcol = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, layername);
if (!mcol)
return;
@@ -357,16 +322,16 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob)
MEM_freeN(mcorners);
}
-static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, DerivedMesh *dm, float *data_color)
+static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, Mesh *mesh, float *data_color)
{
- const int totvert = dm->getNumVerts(dm);
+ const int totvert = mesh->totvert;
const MDeformVert *mdef, *dv;
int mdef_index;
int i;
BLI_assert(data_color);
- mdef = CustomData_get_layer(&dm->vertData, CD_MDEFORMVERT);
+ mdef = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
if (!mdef)
return;
mdef_index = defgroup_name_index(ob, pd->vertex_attribute_name);
@@ -388,9 +353,9 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, Deriv
}
}
-static void pointdensity_cache_vertex_normal(PointDensity *pd, Object *UNUSED(ob), DerivedMesh *dm, float *data_color)
+static void pointdensity_cache_vertex_normal(PointDensity *pd, Object *UNUSED(ob), Mesh *mesh, float *data_color)
{
- MVert *mvert = dm->getVertArray(dm), *mv;
+ MVert *mvert = mesh->mvert, *mv;
int i;
BLI_assert(data_color);
@@ -400,16 +365,14 @@ static void pointdensity_cache_vertex_normal(PointDensity *pd, Object *UNUSED(ob
}
}
-static void pointdensity_cache_object(Scene *scene,
- PointDensity *pd,
- Object *ob,
- const bool use_render_params)
+static void pointdensity_cache_object(PointDensity *pd,
+ Object *ob)
{
float *data_color;
int i;
- DerivedMesh *dm;
CustomDataMask mask = CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL;
MVert *mvert = NULL, *mv;
+ Mesh *mesh = ob->data;
switch (pd->ob_color_source) {
case TEX_PD_COLOR_VERTCOL:
@@ -420,15 +383,8 @@ static void pointdensity_cache_object(Scene *scene,
break;
}
- if (use_render_params) {
- dm = mesh_create_derived_render(scene, ob, mask);
- }
- else {
- dm = mesh_get_derived_final(scene, ob, mask);
- }
-
- mvert = dm->getVertArray(dm); /* local object space */
- pd->totpoints = dm->getNumVerts(dm);
+ mvert = mesh->mvert; /* local object space */
+ pd->totpoints = mesh->totvert;
if (pd->totpoints == 0) {
return;
}
@@ -460,27 +416,22 @@ static void pointdensity_cache_object(Scene *scene,
switch (pd->ob_color_source) {
case TEX_PD_COLOR_VERTCOL:
- pointdensity_cache_vertex_color(pd, ob, dm, data_color);
+ pointdensity_cache_vertex_color(pd, ob, mesh, data_color);
break;
case TEX_PD_COLOR_VERTWEIGHT:
- pointdensity_cache_vertex_weight(pd, ob, dm, data_color);
+ pointdensity_cache_vertex_weight(pd, ob, mesh, data_color);
break;
case TEX_PD_COLOR_VERTNOR:
- pointdensity_cache_vertex_normal(pd, ob, dm, data_color);
+ pointdensity_cache_vertex_normal(pd, ob, mesh, data_color);
break;
}
BLI_bvhtree_balance(pd->point_tree);
- dm->release(dm);
-
}
-static void cache_pointdensity_ex(Scene *scene,
- PointDensity *pd,
- float viewmat[4][4],
- float winmat[4][4],
- int winx, int winy,
- const bool use_render_params)
+static void cache_pointdensity(Depsgraph *depsgraph,
+ Scene *scene,
+ PointDensity *pd)
{
if (pd == NULL) {
return;
@@ -504,31 +455,20 @@ static void cache_pointdensity_ex(Scene *scene,
return;
}
- pointdensity_cache_psys(scene,
+ pointdensity_cache_psys(depsgraph,
+ scene,
pd,
ob,
- psys,
- viewmat, winmat,
- winx, winy,
- use_render_params);
+ psys);
}
else if (pd->source == TEX_PD_OBJECT) {
Object *ob = pd->object;
if (ob && ob->type == OB_MESH)
- pointdensity_cache_object(scene, pd, ob, use_render_params);
+ pointdensity_cache_object(pd, ob);
}
}
-void cache_pointdensity(Render *re, PointDensity *pd)
-{
- cache_pointdensity_ex(re->scene,
- pd,
- re->viewmat, re->winmat,
- re->winx, re->winy,
- true);
-}
-
-void free_pointdensity(PointDensity *pd)
+static void free_pointdensity(PointDensity *pd)
{
if (pd == NULL) {
return;
@@ -546,41 +486,6 @@ void free_pointdensity(PointDensity *pd)
pd->totpoints = 0;
}
-void make_pointdensities(Render *re)
-{
- Tex *tex;
-
- if (re->scene->r.scemode & R_BUTS_PREVIEW) {
- return;
- }
-
- re->i.infostr = IFACE_("Caching Point Densities");
- re->stats_draw(re->sdh, &re->i);
-
- for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
- if (tex->id.us && tex->type == TEX_POINTDENSITY) {
- cache_pointdensity(re, tex->pd);
- }
- }
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-}
-
-void free_pointdensities(Render *re)
-{
- Tex *tex;
-
- if (re->scene->r.scemode & R_BUTS_PREVIEW)
- return;
-
- for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
- if (tex->id.us && tex->type == TEX_POINTDENSITY) {
- free_pointdensity(tex->pd);
- }
- }
-}
-
typedef struct PointDensityRangeData {
float *density;
float squared_radius;
@@ -691,16 +596,13 @@ static int pointdensity(PointDensity *pd,
{
int retval = TEX_INT;
PointDensityRangeData pdr;
- float density = 0.0f, age = 0.0f, time = 0.0f;
+ float density = 0.0f, age = 0.0f;
float vec[3] = {0.0f, 0.0f, 0.0f}, col[3] = {0.0f, 0.0f, 0.0f}, co[3];
float turb, noise_fac;
int num = 0;
texres->tin = 0.0f;
- if ((!pd) || (!pd->point_tree))
- return 0;
-
init_pointdensityrangedata(pd, &pdr, &density, vec, &age, col,
(pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL),
pd->falloff_speed_scale * 0.001f);
@@ -725,21 +627,8 @@ static int pointdensity(PointDensity *pd,
}
if (pd->flag & TEX_PD_TURBULENCE) {
-
- if (pd->noise_influence == TEX_PD_NOISE_AGE) {
- turb = BLI_gTurbulence(pd->noise_size, texvec[0] + age, texvec[1] + age, texvec[2] + age,
- pd->noise_depth, 0, pd->noise_basis);
- }
- else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
- time = R.r.cfra / (float)R.r.efra;
- turb = BLI_gTurbulence(pd->noise_size, texvec[0] + time, texvec[1] + time, texvec[2] + time,
- pd->noise_depth, 0, pd->noise_basis);
- //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
- }
- else {
- turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2],
- pd->noise_depth, 0, pd->noise_basis);
- }
+ turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2],
+ pd->noise_depth, 0, pd->noise_basis);
turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
@@ -771,9 +660,9 @@ static int pointdensity(PointDensity *pd,
return retval;
}
-static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3], const float col[3])
+static void pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3], const float col[3])
{
- int retval = TEX_RGB;
+ texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
if (pd->source == TEX_PD_PSYS) {
float rgba[4];
@@ -810,8 +699,6 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co
break;
case TEX_PD_COLOR_CONSTANT:
default:
- texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
- retval = TEX_INT;
break;
}
}
@@ -842,33 +729,9 @@ static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, co
break;
case TEX_PD_COLOR_CONSTANT:
default:
- texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
- retval = TEX_INT;
break;
}
}
-
- return retval;
-}
-
-int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
-{
- PointDensity *pd = tex->pd;
- float age = 0.0f;
- float vec[3] = {0.0f, 0.0f, 0.0f};
- float col[3] = {0.0f, 0.0f, 0.0f};
- int retval = pointdensity(pd, texvec, texres, vec, &age, col);
-
- retval |= pointdensity_color(pd, texres, age, vec, col);
- BRICONTRGB;
-
- return retval;
-
-#if 0
- if (texres->nor!=NULL) {
- texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
- }
-#endif
}
static void sample_dummy_point_density(int resolution, float *values)
@@ -876,11 +739,11 @@ static void sample_dummy_point_density(int resolution, float *values)
memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution);
}
-static void particle_system_minmax(Scene *scene,
+static void particle_system_minmax(Depsgraph *depsgraph,
+ Scene *scene,
Object *object,
ParticleSystem *psys,
float radius,
- const bool use_render_params,
float min[3], float max[3])
{
const float size[3] = {radius, radius, radius};
@@ -899,10 +762,8 @@ static void particle_system_minmax(Scene *scene,
}
unit_m4(mat);
- if (use_render_params) {
- psys_render_set(object, psys, mat, mat, 1, 1, 0);
- }
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = object;
sim.psys = psys;
@@ -930,31 +791,26 @@ static void particle_system_minmax(Scene *scene,
end_latt_deform(psys->lattice_deform_data);
psys->lattice_deform_data = NULL;
}
-
- if (use_render_params) {
- psys_render_restore(object, psys);
- }
}
void RE_point_density_cache(
- Scene *scene,
- PointDensity *pd,
- const bool use_render_params)
+ struct Depsgraph *depsgraph,
+ PointDensity *pd)
{
- float mat[4][4];
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+
/* Same matricies/resolution as dupli_render_particle_set(). */
- unit_m4(mat);
BLI_mutex_lock(&sample_mutex);
- cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params);
+ cache_pointdensity(depsgraph, scene, pd);
BLI_mutex_unlock(&sample_mutex);
}
void RE_point_density_minmax(
- struct Scene *scene,
+ struct Depsgraph *depsgraph,
struct PointDensity *pd,
- const bool use_render_params,
float r_min[3], float r_max[3])
{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
Object *object = pd->object;
if (object == NULL) {
zero_v3(r_min);
@@ -963,6 +819,7 @@ void RE_point_density_minmax(
}
if (pd->source == TEX_PD_PSYS) {
ParticleSystem *psys;
+
if (pd->psys == 0) {
zero_v3(r_min);
zero_v3(r_max);
@@ -974,11 +831,12 @@ void RE_point_density_minmax(
zero_v3(r_max);
return;
}
- particle_system_minmax(scene,
+
+ particle_system_minmax(depsgraph,
+ scene,
object,
psys,
pd->radius,
- use_render_params,
r_min, r_max);
}
else {
@@ -1020,6 +878,10 @@ static void point_density_sample_func(
PointDensity *pd = data->pd;
float *values = data->values;
+ if (!pd || !pd->point_tree) {
+ return;
+ }
+
size_t z = (size_t)iter;
for (size_t y = 0; y < resolution; ++y) {
for (size_t x = 0; x < resolution; ++x) {
@@ -1046,10 +908,9 @@ static void point_density_sample_func(
* NOTE 2: Frees point density structure after sampling.
*/
void RE_point_density_sample(
- Scene *scene,
+ Depsgraph *depsgraph,
PointDensity *pd,
const int resolution,
- const bool use_render_params,
float *values)
{
Object *object = pd->object;
@@ -1065,9 +926,8 @@ void RE_point_density_sample(
}
BLI_mutex_lock(&sample_mutex);
- RE_point_density_minmax(scene,
+ RE_point_density_minmax(depsgraph,
pd,
- use_render_params,
min,
max);
BLI_mutex_unlock(&sample_mutex);
@@ -1099,3 +959,7 @@ void RE_point_density_free(struct PointDensity *pd)
{
free_pointdensity(pd);
}
+
+void RE_point_density_fix_linking(void)
+{
+}
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
deleted file mode 100644
index 608275cdb4d..00000000000
--- a/source/blender/render/intern/source/rayshade.c
+++ /dev/null
@@ -1,2502 +0,0 @@
-/*
- * ***** 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) 1990-1998 NeoGeo BV.
- * All rights reserved.
- *
- * Contributors: 2004/2005 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/rayshade.c
- * \ingroup render
- */
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <float.h>
-#include <assert.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_material_types.h"
-#include "DNA_lamp_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_system.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "BKE_node.h"
-
-#include "render_result.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "pixelshading.h"
-#include "shading.h"
-#include "volumetric.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "raycounter.h"
-
-#define RAY_TRA 1
-#define RAY_INSIDE 2
-
-#define DEPTH_SHADOW_TRA 10
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-static int test_break(void *data)
-{
- Render *re = (Render *)data;
- return re->test_break(re->tbh);
-}
-
-static void RE_rayobject_config_control(RayObject *r, Render *re)
-{
- if (RE_rayobject_isRayAPI(r)) {
- r = RE_rayobject_align(r);
- r->control.data = re;
- r->control.test_break = test_break;
- }
-}
-
-RayObject *RE_rayobject_create(int type, int size, int octree_resolution)
-{
- RayObject *res = NULL;
-
- if (type == R_RAYSTRUCTURE_AUTO) {
- /* TODO */
- //if (detect_simd())
-#ifdef __SSE__
- type = BLI_cpu_support_sse2()? R_RAYSTRUCTURE_SIMD_SVBVH: R_RAYSTRUCTURE_VBVH;
-#else
- type = R_RAYSTRUCTURE_VBVH;
-#endif
- }
-
-#ifndef __SSE__
- if (type == R_RAYSTRUCTURE_SIMD_SVBVH || type == R_RAYSTRUCTURE_SIMD_QBVH) {
- puts("Warning: Using VBVH (SSE was disabled at compile time)");
- type = R_RAYSTRUCTURE_VBVH;
- }
-#endif
-
-
- if (type == R_RAYSTRUCTURE_OCTREE) //TODO dynamic ocres
- res = RE_rayobject_octree_create(octree_resolution, size);
- else if (type == R_RAYSTRUCTURE_VBVH)
- res = RE_rayobject_vbvh_create(size);
- else if (type == R_RAYSTRUCTURE_SIMD_SVBVH)
- res = RE_rayobject_svbvh_create(size);
- else if (type == R_RAYSTRUCTURE_SIMD_QBVH)
- res = RE_rayobject_qbvh_create(size);
- else
- res = RE_rayobject_vbvh_create(size); //Fallback
-
- return res;
-}
-
-static RayObject* rayobject_create(Render *re, int type, int size)
-{
- RayObject *res = NULL;
-
- res = RE_rayobject_create(type, size, re->r.ocres);
-
- if (res)
- RE_rayobject_config_control(res, re);
-
- return res;
-}
-
-#ifdef RE_RAYCOUNTER
-RayCounter re_rc_counter[BLENDER_MAX_THREADS];
-#endif
-
-
-void freeraytree(Render *re)
-{
- ObjectInstanceRen *obi;
-
- if (re->raytree) {
- RE_rayobject_free(re->raytree);
- re->raytree = NULL;
- }
- if (re->rayfaces) {
- MEM_freeN(re->rayfaces);
- re->rayfaces = NULL;
- }
- if (re->rayprimitives) {
- MEM_freeN(re->rayprimitives);
- re->rayprimitives = NULL;
- }
-
- for (obi=re->instancetable.first; obi; obi=obi->next) {
- ObjectRen *obr = obi->obr;
- if (obr->raytree) {
- RE_rayobject_free(obr->raytree);
- obr->raytree = NULL;
- }
- if (obr->rayfaces) {
- MEM_freeN(obr->rayfaces);
- obr->rayfaces = NULL;
- }
- if (obi->raytree) {
- RE_rayobject_free(obi->raytree);
- obi->raytree = NULL;
- }
- }
-
-#ifdef RE_RAYCOUNTER
- {
- const int num_threads = re->r.threads;
- RayCounter sum;
- memset(&sum, 0, sizeof(sum));
- int i;
- for (i=0; i<num_threads; i++)
- RE_RC_MERGE(&sum, re_rc_counter+i);
- RE_RC_INFO(&sum);
- }
-#endif
-}
-
-static bool is_raytraceable_vlr(Render *re, VlakRen *vlr)
-{
- /* note: volumetric must be tracable, wire must not */
- if ((re->flag & R_BAKE_TRACE) || (vlr->flag & R_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME))
- if (vlr->mat->material_type != MA_TYPE_WIRE)
- return 1;
- return 0;
-}
-
-static bool is_raytraceable(Render *re, ObjectInstanceRen *obi)
-{
- int v;
- ObjectRen *obr = obi->obr;
-
- if (re->excludeob && obr->ob == re->excludeob)
- return 0;
-
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
-
- if (is_raytraceable_vlr(re, vlr))
- return 1;
- }
-
- return 0;
-}
-
-
-RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi)
-{
- /*TODO
- * out-of-memory safeproof
- * break render
- * update render stats */
- ObjectRen *obr = obi->obr;
-
- if (obr->raytree == NULL) {
- RayObject *raytree;
- RayFace *face = NULL;
- VlakPrimitive *vlakprimitive = NULL;
- int v;
-
- //Count faces
- int faces = 0;
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr))
- faces++;
- }
-
- if (faces == 0)
- return NULL;
-
- //Create Ray cast accelaration structure
- raytree = rayobject_create( re, re->r.raytrace_structure, faces );
- if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) )
- vlakprimitive = obr->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "ObjectRen primitives");
- else
- face = obr->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "ObjectRen faces");
-
- obr->rayobi = obi;
-
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr)) {
- if ((re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS)) {
- RE_rayobject_add(raytree, RE_vlakprimitive_from_vlak(vlakprimitive, obi, vlr));
- vlakprimitive++;
- }
- else {
- RE_rayface_from_vlak(face, obi, vlr);
- RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face));
- face++;
- }
- }
- }
- RE_rayobject_done(raytree);
-
- /* in case of cancel during build, raytree is not usable */
- if (test_break(re))
- RE_rayobject_free(raytree);
- else
- obr->raytree= raytree;
- }
-
- if (obr->raytree) {
- if ((obi->flag & R_TRANSFORMED) && obi->raytree == NULL) {
- obi->transform_primitives = 0;
- obi->raytree = RE_rayobject_instance_create( obr->raytree, obi->mat, obi, obi->obr->rayobi );
- }
- }
-
- if (obi->raytree) return obi->raytree;
- return obi->obr->raytree;
-}
-
-static bool has_special_rayobject(Render *re, ObjectInstanceRen *obi)
-{
- if ( (obi->flag & R_TRANSFORMED) && (re->r.raytrace_options & R_RAYTRACE_USE_INSTANCES) ) {
- ObjectRen *obr = obi->obr;
- int v, faces = 0;
-
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr)) {
- faces++;
- if (faces > 4)
- return 1;
- }
- }
- }
- return 0;
-}
-/*
- * create a single raytrace structure with all faces
- */
-static void makeraytree_single(Render *re)
-{
- ObjectInstanceRen *obi;
- RayObject *raytree;
- RayFace *face = NULL;
- VlakPrimitive *vlakprimitive = NULL;
- int faces = 0, special = 0;
-
- for (obi = re->instancetable.first; obi; obi = obi->next) {
- if (is_raytraceable(re, obi)) {
- ObjectRen *obr = obi->obr;
-
- if (has_special_rayobject(re, obi)) {
- special++;
- }
- else {
- int v;
- for (v = 0;v < obr->totvlak; v++) {
- VlakRen *vlr = obr->vlaknodes[v >> 8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr)) {
- faces++;
- }
- }
- }
- }
- }
-
- if (faces + special == 0) {
- re->raytree = RE_rayobject_empty_create();
- return;
- }
-
- //Create raytree
- raytree = re->raytree = rayobject_create( re, re->r.raytrace_structure, faces+special );
-
- if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) ) {
- vlakprimitive = re->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "Raytrace vlak-primitives");
- }
- else {
- face = re->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "Render ray faces");
- }
-
- for (obi=re->instancetable.first; obi; obi=obi->next)
- if (is_raytraceable(re, obi)) {
- if (test_break(re))
- break;
-
- if (has_special_rayobject(re, obi)) {
- RayObject *obj = makeraytree_object(re, obi);
-
- if (test_break(re))
- break;
-
- if (obj)
- RE_rayobject_add(re->raytree, obj);
- }
- else {
- int v;
- ObjectRen *obr = obi->obr;
-
- if (obi->flag & R_TRANSFORMED) {
- obi->transform_primitives = 1;
- }
-
- for (v=0;v<obr->totvlak;v++) {
- VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
- if (is_raytraceable_vlr(re, vlr)) {
- if ((re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS)) {
- RayObject *obj = RE_vlakprimitive_from_vlak( vlakprimitive, obi, vlr );
- RE_rayobject_add(raytree, obj);
- vlakprimitive++;
- }
- else {
- RE_rayface_from_vlak(face, obi, vlr);
- if ((obi->flag & R_TRANSFORMED)) {
- mul_m4_v3(obi->mat, face->v1);
- mul_m4_v3(obi->mat, face->v2);
- mul_m4_v3(obi->mat, face->v3);
- if (RE_rayface_isQuad(face))
- mul_m4_v3(obi->mat, face->v4);
- }
-
- RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face));
- face++;
- }
- }
- }
- }
- }
-
- if (!test_break(re)) {
- re->i.infostr = IFACE_("Raytree.. building");
- re->stats_draw(re->sdh, &re->i);
-
- RE_rayobject_done(raytree);
- }
-}
-
-void makeraytree(Render *re)
-{
- float min[3], max[3], sub[3];
- int i;
-
- re->i.infostr = IFACE_("Raytree.. preparing");
- re->stats_draw(re->sdh, &re->i);
-
- /* disable options not yet supported by octree,
- * they might actually never be supported (unless people really need it) */
- if (re->r.raytrace_structure == R_RAYSTRUCTURE_OCTREE)
- re->r.raytrace_options &= ~( R_RAYTRACE_USE_INSTANCES | R_RAYTRACE_USE_LOCAL_COORDS);
-
- makeraytree_single(re);
-
- if (test_break(re)) {
- freeraytree(re);
-
- re->i.infostr = IFACE_("Raytree building canceled");
- re->stats_draw(re->sdh, &re->i);
- }
- else {
- /* Calculate raytree max_size
- * This is ONLY needed to kept a bogus behavior of SUN and HEMI lights */
- INIT_MINMAX(min, max);
- RE_rayobject_merge_bb(re->raytree, min, max);
- if (min[0] > max[0]) { /* empty raytree */
- zero_v3(min);
- zero_v3(max);
- }
- for (i=0; i<3; i++) {
- /* TODO: explain why add top both min and max??? */
- min[i] += 0.01f;
- max[i] += 0.01f;
- sub[i] = max[i]-min[i];
- }
-
- re->maxdist = len_v3(sub);
-
- re->i.infostr = IFACE_("Raytree finished");
- re->stats_draw(re->sdh, &re->i);
- }
-
-#ifdef RE_RAYCOUNTER
- memset(re_rc_counter, 0, sizeof(re_rc_counter));
-#endif
-}
-
-/* if (shi->osatex) */
-static void shade_ray_set_derivative(ShadeInput *shi)
-{
- float detsh, t00, t10, t01, t11;
- int axis1, axis2;
-
- /* find most stable axis to project */
- axis_dominant_v3(&axis1, &axis2, shi->facenor);
-
- /* compute u,v and derivatives */
- if (shi->obi->flag & R_TRANSFORMED) {
- float v1[3], v2[3], v3[3];
-
- mul_v3_m3v3(v1, shi->obi->nmat, shi->v1->co);
- mul_v3_m3v3(v2, shi->obi->nmat, shi->v2->co);
- mul_v3_m3v3(v3, shi->obi->nmat, shi->v3->co);
-
- /* same as below */
- t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2];
- t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2];
- }
- else {
- const float *v1= shi->v1->co;
- const float *v2= shi->v2->co;
- const float *v3= shi->v3->co;
-
- /* same as above */
- t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2];
- t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2];
- }
-
- detsh= 1.0f/(t00*t11-t10*t01);
- t00*= detsh; t01*=detsh;
- t10*=detsh; t11*=detsh;
-
- shi->dx_u= shi->dxco[axis1]*t11- shi->dxco[axis2]*t10;
- shi->dx_v= shi->dxco[axis2]*t00- shi->dxco[axis1]*t01;
- shi->dy_u= shi->dyco[axis1]*t11- shi->dyco[axis2]*t10;
- shi->dy_v= shi->dyco[axis2]*t00- shi->dyco[axis1]*t01;
-
-}
-
-/* main ray shader */
-void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
-{
- ObjectInstanceRen *obi = (ObjectInstanceRen *)is->hit.ob;
- VlakRen *vlr = (VlakRen *)is->hit.face;
-
- /* set up view vector */
- copy_v3_v3(shi->view, is->dir);
-
- /* render co */
- shi->co[0]= is->start[0]+is->dist*(shi->view[0]);
- shi->co[1]= is->start[1]+is->dist*(shi->view[1]);
- shi->co[2]= is->start[2]+is->dist*(shi->view[2]);
-
- normalize_v3(shi->view);
-
- shi->obi= obi;
- shi->obr= obi->obr;
- shi->vlr= vlr;
- shi->mat= vlr->mat;
- shade_input_init_material(shi);
-
- if (is->isect==2)
- shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-
- shi->u= is->u;
- shi->v= is->v;
- shi->dx_u= shi->dx_v= shi->dy_u= shi->dy_v= 0.0f;
-
- if (shi->osatex)
- shade_ray_set_derivative(shi);
- shade_input_set_normals(shi);
-
- shade_input_set_shade_texco(shi);
- if (shi->mat->material_type == MA_TYPE_VOLUME) {
- if (ELEM(is->mode, RE_RAY_SHADOW, RE_RAY_SHADOW_TRA)) {
- shade_volume_shadow(shi, shr, is);
- }
- else {
- shade_volume_outside(shi, shr);
- }
- }
- else if (is->mode==RE_RAY_SHADOW_TRA) {
- /* temp hack to prevent recursion */
- if (shi->nodes==0 && shi->mat->nodetree && shi->mat->use_nodes) {
- ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
- shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
- }
- else
- shade_color(shi, shr);
- }
- else {
- if (shi->mat->nodetree && shi->mat->use_nodes) {
- ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
- shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
- }
- else {
- shade_material_loop(shi, shr);
- }
-
- /* raytrace likes to separate the spec color */
- sub_v3_v3v3(shr->diff, shr->combined, shr->spec);
- copy_v3_v3(shr->diffshad, shr->diff);
- }
-
-}
-
-static int refraction(float refract[3], const float n[3], const float view[3], float index)
-{
- float dot, fac;
-
- copy_v3_v3(refract, view);
-
- dot = dot_v3v3(view, n);
-
- if (dot>0.0f) {
- index = 1.0f/index;
- fac= 1.0f - (1.0f - dot*dot)*index*index;
- if (fac <= 0.0f) return 0;
- fac= -dot*index + sqrtf(fac);
- }
- else {
- fac= 1.0f - (1.0f - dot*dot)*index*index;
- if (fac <= 0.0f) return 0;
- fac= -dot*index - sqrtf(fac);
- }
-
- refract[0]= index*view[0] + fac*n[0];
- refract[1]= index*view[1] + fac*n[1];
- refract[2]= index*view[2] + fac*n[2];
-
- return 1;
-}
-
-static void reflection_simple(float ref[3], float n[3], const float view[3])
-{
- const float f1= -2.0f * dot_v3v3(n, view);
- madd_v3_v3v3fl(ref, view, n, f1);
-}
-
-/* orn = original face normal */
-static void reflection(float ref[3], float n[3], const float view[3], const float orn[3])
-{
- float f1;
-
- reflection_simple(ref, n, view);
-
- /* test phong normals, then we should prevent vector going to the back */
- f1= dot_v3v3(ref, orn);
- if (f1>0.0f) {
- f1+= 0.01f;
- ref[0]-= f1*orn[0];
- ref[1]-= f1*orn[1];
- ref[2]-= f1*orn[2];
- }
-}
-
-#if 0
-static void color_combine(float *result, float fac1, float fac2, float col1[3], float col2[3])
-{
- float col1t[3], col2t[3];
-
- col1t[0]= sqrt(col1[0]);
- col1t[1]= sqrt(col1[1]);
- col1t[2]= sqrt(col1[2]);
- col2t[0]= sqrt(col2[0]);
- col2t[1]= sqrt(col2[1]);
- col2t[2]= sqrt(col2[2]);
-
- result[0]= (fac1*col1t[0] + fac2*col2t[0]);
- result[0]*= result[0];
- result[1]= (fac1*col1t[1] + fac2*col2t[1]);
- result[1]*= result[1];
- result[2]= (fac1*col1t[2] + fac2*col2t[2]);
- result[2]*= result[2];
-}
-#endif
-
-static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr)
-{
- float d;
- if (0 == (shi->mat->mode & MA_TRANSP))
- return -1;
-
- if (shi->mat->tx_limit <= 0.0f) {
- d= 1.0f;
- }
- else {
- float p;
-
- /* shi.co[] calculated by shade_ray() */
- const float dx= shi->co[0] - is->start[0];
- const float dy= shi->co[1] - is->start[1];
- const float dz= shi->co[2] - is->start[2];
- d = sqrtf(dx * dx + dy * dy + dz * dz);
- if (d > shi->mat->tx_limit)
- d= shi->mat->tx_limit;
-
- p = shi->mat->tx_falloff;
- if (p < 0.0f) p= 0.0f;
- else if (p > 10.0f) p= 10.0f;
-
- shr->alpha *= powf(d, p);
- if (shr->alpha > 1.0f)
- shr->alpha= 1.0f;
- }
-
- return d;
-}
-
-static void ray_fadeout_endcolor(float col[3], ShadeInput *origshi, ShadeInput *shi, ShadeResult *shr, Isect *isec, const float vec[3])
-{
- /* un-intersected rays get either rendered material color or sky color */
- if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOMAT) {
- copy_v3_v3(col, shr->combined);
- }
- else if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOSKY) {
- copy_v3_v3(shi->view, vec);
- normalize_v3(shi->view);
-
- shadeSkyView(col, isec->start, shi->view, NULL, shi->thread);
- shadeSunView(col, shi->view);
- }
-}
-
-static void ray_fadeout(Isect *is, ShadeInput *shi, float col[3], const float blendcol[3], float dist_mir)
-{
- /* if fading out, linear blend against fade color */
- float blendfac;
-
- blendfac = 1.0f - len_v3v3(shi->co, is->start)/dist_mir;
-
- col[0] = col[0]*blendfac + (1.0f - blendfac)*blendcol[0];
- col[1] = col[1]*blendfac + (1.0f - blendfac)*blendcol[1];
- col[2] = col[2]*blendfac + (1.0f - blendfac)*blendcol[2];
-}
-
-/* the main recursive tracer itself
- * note: 'col' must be initialized */
-static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, const float start[3], const float dir[3], float col[4], ObjectInstanceRen *obi, VlakRen *vlr, int traflag)
-{
- ShadeInput shi = {NULL};
- Isect isec;
- float dist_mir = origshi->mat->dist_mir;
-
- /* with high depth the number of rays can explode due to the path splitting
- * in two each time, giving 2^depth rays. we need to be able to cancel such
- * a render to avoid hanging, a better solution would be random picking
- * between directions and russian roulette termination */
- if (R.test_break(R.tbh)) {
- zero_v4(col);
- return;
- }
-
- copy_v3_v3(isec.start, start);
- copy_v3_v3(isec.dir, dir);
- isec.dist = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST;
- isec.mode= RE_RAY_MIRROR;
- isec.check = RE_CHECK_VLR_RENDER;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
- isec.hint = NULL;
-
- isec.orig.ob = obi;
- isec.orig.face = vlr;
- RE_RC_INIT(isec, shi);
-
- /* database is in original view, obi->imat transforms current position back to original */
- RE_instance_rotate_ray(origshi->obi, &isec);
-
- if (RE_rayobject_raycast(R.raytree, &isec)) {
- ShadeResult shr= {{0}};
- float d= 1.0f;
-
- RE_instance_rotate_ray_restore(origshi->obi, &isec);
-
- /* for as long we don't have proper dx/dy transform for rays we copy over original */
- copy_v3_v3(shi.dxco, origshi->dxco);
- copy_v3_v3(shi.dyco, origshi->dyco);
-
- shi.mask= origshi->mask;
- shi.osatex= origshi->osatex;
- shi.depth= origshi->depth + 1; /* only used to indicate tracing */
- shi.thread= origshi->thread;
- //shi.sample= 0; // memset above, so don't need this
- shi.xs= origshi->xs;
- shi.ys= origshi->ys;
- shi.do_manage= origshi->do_manage;
- shi.lay= origshi->lay;
- shi.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
- shi.combinedflag= 0xFFFFFF; /* ray trace does all options */
- //shi.do_preview = false; // memset above, so don't need this
- shi.light_override= origshi->light_override;
- shi.mat_override= origshi->mat_override;
-
- shade_ray(&isec, &shi, &shr);
- /* ray has traveled inside the material, so shade by transmission */
- if (traflag & RAY_INSIDE)
- d= shade_by_transmission(&isec, &shi, &shr);
-
- if (depth>0) {
- float fr, fg, fb, f1;
-
- if ((shi.mat->mode_l & MA_TRANSP) && shr.alpha < 1.0f && (shi.mat->mode_l & (MA_ZTRANSP | MA_RAYTRANSP))) {
- float nf, f, refract[3], tracol[4];
-
- tracol[0]= shi.r;
- tracol[1]= shi.g;
- tracol[2]= shi.b;
- tracol[3]= col[3]; /* we pass on and accumulate alpha */
-
- if ((shi.mat->mode & MA_TRANSP) && (shi.mat->mode & MA_RAYTRANSP)) {
- /* don't overwrite traflag, it's value is used in mirror reflection */
- int new_traflag = traflag;
-
- if (new_traflag & RAY_INSIDE) {
- /* inside the material, so use inverse normal */
- float norm[3];
- norm[0]= - shi.vn[0];
- norm[1]= - shi.vn[1];
- norm[2]= - shi.vn[2];
-
- if (refraction(refract, norm, shi.view, shi.ang)) {
- /* ray comes out from the material into air */
- new_traflag &= ~RAY_INSIDE;
- }
- else {
- /* total internal reflection (ray stays inside the material) */
- reflection(refract, norm, shi.view, shi.vn);
- }
- }
- else {
- if (refraction(refract, shi.vn, shi.view, shi.ang)) {
- /* ray goes in to the material from air */
- new_traflag |= RAY_INSIDE;
- }
- else {
- /* total external reflection (ray doesn't enter the material) */
- reflection(refract, shi.vn, shi.view, shi.vn);
- }
- }
- traceray(origshi, origshr, depth-1, shi.co, refract, tracol, shi.obi, shi.vlr, new_traflag);
- }
- else
- traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.obi, shi.vlr, 0);
-
- f= shr.alpha; f1= 1.0f-f;
- nf= (shi.mat->mode & MA_RAYTRANSP) ? d * shi.mat->filter : 0.0f;
- fr= 1.0f+ nf*(shi.r-1.0f);
- fg= 1.0f+ nf*(shi.g-1.0f);
- fb= 1.0f+ nf*(shi.b-1.0f);
- shr.diff[0]= f*shr.diff[0] + f1*fr*tracol[0];
- shr.diff[1]= f*shr.diff[1] + f1*fg*tracol[1];
- shr.diff[2]= f*shr.diff[2] + f1*fb*tracol[2];
-
- shr.spec[0] *=f;
- shr.spec[1] *=f;
- shr.spec[2] *=f;
-
- col[3]= f1*tracol[3] + f;
- }
- else {
- col[3]= 1.0f;
- }
-
- float f;
- if (shi.mat->mode_l & MA_RAYMIRROR) {
- f= shi.ray_mirror;
- if (f!=0.0f) f*= fresnel_fac(shi.view, shi.vn, shi.mat->fresnel_mir_i, shi.mat->fresnel_mir);
- }
- else f= 0.0f;
-
- if (f!=0.0f) {
- float mircol[4];
- float ref[3];
-
- reflection_simple(ref, shi.vn, shi.view);
- traceray(origshi, origshr, depth-1, shi.co, ref, mircol, shi.obi, shi.vlr, traflag);
-
- f1= 1.0f-f;
-
- /* combine */
- //color_combine(col, f*fr*(1.0f-shr.spec[0]), f1, col, shr.diff);
- //col[0]+= shr.spec[0];
- //col[1]+= shr.spec[1];
- //col[2]+= shr.spec[2];
-
- fr= shi.mirr;
- fg= shi.mirg;
- fb= shi.mirb;
-
- col[0]= f*fr*(1.0f-shr.spec[0])*mircol[0] + f1*shr.diff[0] + shr.spec[0];
- col[1]= f*fg*(1.0f-shr.spec[1])*mircol[1] + f1*shr.diff[1] + shr.spec[1];
- col[2]= f*fb*(1.0f-shr.spec[2])*mircol[2] + f1*shr.diff[2] + shr.spec[2];
- }
- else {
- col[0]= shr.diff[0] + shr.spec[0];
- col[1]= shr.diff[1] + shr.spec[1];
- col[2]= shr.diff[2] + shr.spec[2];
- }
-
- if (dist_mir > 0.0f) {
- float blendcol[3];
-
- /* max ray distance set, but found an intersection, so fade this color
- * out towards the sky/material color for a smooth transition */
- ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, dir);
- ray_fadeout(&isec, &shi, col, blendcol, dist_mir);
- }
- }
- else {
- col[0]= shr.diff[0] + shr.spec[0];
- col[1]= shr.diff[1] + shr.spec[1];
- col[2]= shr.diff[2] + shr.spec[2];
- }
-
- }
- else {
- ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, dir);
- }
- RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
-}
-
-/* **************** jitter blocks ********** */
-
-/* calc distributed planar energy */
-
-static void DP_energy(float *table, float vec[2], int tot, float xsize, float ysize)
-{
- int x, y, a;
- float *fp, force[3], result[3];
- float dx, dy, dist, min;
-
- min= MIN2(xsize, ysize);
- min*= min;
- result[0]= result[1]= 0.0f;
-
- for (y= -1; y<2; y++) {
- dy= ysize*y;
- for (x= -1; x<2; x++) {
- dx= xsize*x;
- fp= table;
- for (a=0; a<tot; a++, fp+= 2) {
- force[0]= vec[0] - fp[0]-dx;
- force[1]= vec[1] - fp[1]-dy;
- dist= force[0]*force[0] + force[1]*force[1];
- if (dist < min && dist>0.0f) {
- result[0]+= force[0]/dist;
- result[1]+= force[1]/dist;
- }
- }
- }
- }
- vec[0] += 0.1f*min*result[0]/(float)tot;
- vec[1] += 0.1f*min*result[1]/(float)tot;
- /* cyclic clamping */
- vec[0]= vec[0] - xsize*floorf(vec[0]/xsize + 0.5f);
- vec[1]= vec[1] - ysize*floorf(vec[1]/ysize + 0.5f);
-}
-
-/* random offset of 1 in 2 */
-static void jitter_plane_offset(float *jitter1, float *jitter2, int tot, float sizex, float sizey, float ofsx, float ofsy)
-{
- float dsizex= sizex*ofsx;
- float dsizey= sizey*ofsy;
- float hsizex= 0.5f*sizex, hsizey= 0.5f*sizey;
- int x;
-
- for (x=tot; x>0; x--, jitter1+=2, jitter2+=2) {
- jitter2[0]= jitter1[0] + dsizex;
- jitter2[1]= jitter1[1] + dsizey;
- if (jitter2[0] > hsizex) jitter2[0]-= sizex;
- if (jitter2[1] > hsizey) jitter2[1]-= sizey;
- }
-}
-
-/* called from convertBlenderScene.c */
-/* we do this in advance to get consistent random, not alter the render seed, and be threadsafe */
-void init_jitter_plane(LampRen *lar)
-{
- float *fp;
- int x, tot= lar->ray_totsamp;
-
- /* test if already initialized */
- if (lar->jitter) return;
-
- /* at least 4, or max threads+1 tables */
- if (BLENDER_MAX_THREADS < 4) x= 4;
- else x= BLENDER_MAX_THREADS+1;
- fp= lar->jitter= MEM_callocN(x*tot*2*sizeof(float), "lamp jitter tab");
-
- /* if 1 sample, we leave table to be zero's */
- if (tot>1) {
- /* set per-lamp fixed seed */
- RNG *rng = BLI_rng_new_srandom(tot);
- int iter=12;
-
- /* fill table with random locations, area_size large */
- for (x=0; x<tot; x++, fp+=2) {
- fp[0]= (BLI_rng_get_float(rng)-0.5f)*lar->area_size;
- fp[1]= (BLI_rng_get_float(rng)-0.5f)*lar->area_sizey;
- }
-
- while (iter--) {
- fp= lar->jitter;
- for (x=tot; x>0; x--, fp+=2) {
- DP_energy(lar->jitter, fp, tot, lar->area_size, lar->area_sizey);
- }
- }
-
- BLI_rng_free(rng);
- }
- /* create the dithered tables (could just check lamp type!) */
- jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.0f);
- jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.5f);
- jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0f, 0.5f);
-}
-
-/* table around origin, -0.5*size to 0.5*size */
-static float *give_jitter_plane(LampRen *lar, int thread, int xs, int ys)
-{
- int tot;
-
- tot= lar->ray_totsamp;
-
- if (lar->ray_samp_type & LA_SAMP_JITTER) {
- /* made it threadsafe */
-
- if (lar->xold[thread]!=xs || lar->yold[thread]!=ys) {
- jitter_plane_offset(lar->jitter, lar->jitter+2*(thread+1)*tot, tot, lar->area_size, lar->area_sizey, BLI_thread_frand(thread), BLI_thread_frand(thread));
- lar->xold[thread]= xs;
- lar->yold[thread]= ys;
- }
- return lar->jitter+2*(thread+1)*tot;
- }
- if (lar->ray_samp_type & LA_SAMP_DITHER) {
- return lar->jitter + 2*tot*((xs & 1)+2*(ys & 1));
- }
-
- return lar->jitter;
-}
-
-
-/* **************** QMC sampling *************** */
-
-static void halton_sample(double *ht_invprimes, double *ht_nums, double *v)
-{
- /* incremental halton sequence generator, from:
- * "Instant Radiosity", Keller A. */
- unsigned int i;
-
- for (i = 0; i < 2; i++) {
- double r = fabs((1.0 - ht_nums[i]) - 1e-10);
-
- if (ht_invprimes[i] >= r) {
- double lasth;
- double h = ht_invprimes[i];
-
- do {
- lasth = h;
- h *= ht_invprimes[i];
- } while (h >= r);
-
- ht_nums[i] += ((lasth + h) - 1.0);
- }
- else
- ht_nums[i] += ht_invprimes[i];
-
- v[i] = (float)ht_nums[i];
- }
-}
-
-/* Generate Hammersley points in [0,1)^2
- * From Lucille renderer */
-static void hammersley_create(double *out, int n)
-{
- double p, t;
- int k, kk;
-
- for (k = 0; k < n; k++) {
- t = 0;
- for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1) {
- if (kk & 1) { /* kk mod 2 = 1 */
- t += p;
- }
- }
-
- out[2 * k + 0] = (double)k / (double)n;
- out[2 * k + 1] = t;
- }
-}
-
-static struct QMCSampler *QMC_initSampler(int type, int tot)
-{
- QMCSampler *qsa = MEM_callocN(sizeof(QMCSampler), "qmc sampler");
- qsa->samp2d = MEM_callocN(2*sizeof(double)*tot, "qmc sample table");
-
- qsa->tot = tot;
- qsa->type = type;
-
- if (qsa->type==SAMP_TYPE_HAMMERSLEY)
- hammersley_create(qsa->samp2d, qsa->tot);
-
- return qsa;
-}
-
-static void QMC_initPixel(QMCSampler *qsa, int thread)
-{
- if (qsa->type==SAMP_TYPE_HAMMERSLEY) {
- /* hammersley sequence is fixed, already created in QMCSampler init.
- * per pixel, gets a random offset. We create separate offsets per thread, for write-safety */
- qsa->offs[thread][0] = 0.5f * BLI_thread_frand(thread);
- qsa->offs[thread][1] = 0.5f * BLI_thread_frand(thread);
- }
- else { /* SAMP_TYPE_HALTON */
-
- /* generate a new randomized halton sequence per pixel
- * to alleviate qmc artifacts and make it reproducible
- * between threads/frames */
- double ht_invprimes[2], ht_nums[2];
- double r[2];
- int i;
-
- ht_nums[0] = BLI_thread_frand(thread);
- ht_nums[1] = BLI_thread_frand(thread);
- ht_invprimes[0] = 0.5;
- ht_invprimes[1] = 1.0/3.0;
-
- for (i=0; i< qsa->tot; i++) {
- halton_sample(ht_invprimes, ht_nums, r);
- qsa->samp2d[2*i+0] = r[0];
- qsa->samp2d[2*i+1] = r[1];
- }
- }
-}
-
-static void QMC_freeSampler(QMCSampler *qsa)
-{
- MEM_freeN(qsa->samp2d);
- MEM_freeN(qsa);
-}
-
-static void QMC_getSample(double *s, QMCSampler *qsa, int thread, int num)
-{
- if (qsa->type == SAMP_TYPE_HAMMERSLEY) {
- s[0] = fmod(qsa->samp2d[2*num+0] + qsa->offs[thread][0], 1.0f);
- s[1] = fmod(qsa->samp2d[2*num+1] + qsa->offs[thread][1], 1.0f);
- }
- else { /* SAMP_TYPE_HALTON */
- s[0] = qsa->samp2d[2*num+0];
- s[1] = qsa->samp2d[2*num+1];
- }
-}
-
-/* phong weighted disc using 'blur' for exponent, centred on 0,0 */
-static void QMC_samplePhong(float vec[3], QMCSampler *qsa, int thread, int num, float blur)
-{
- double s[2];
- float phi, pz, sqr;
-
- QMC_getSample(s, qsa, thread, num);
-
- phi = s[0]*2*M_PI;
- pz = pow(s[1], blur);
- sqr = sqrtf(1.0f - pz * pz);
-
- vec[0] = (float)(cosf(phi)*sqr);
- vec[1] = (float)(sinf(phi)*sqr);
- vec[2] = 0.0f;
-}
-
-/* rect of edge lengths sizex, sizey, centred on 0.0,0.0 i.e. ranging from -sizex/2 to +sizey/2 */
-static void QMC_sampleRect(float vec[3], QMCSampler *qsa, int thread, int num, float sizex, float sizey)
-{
- double s[2];
-
- QMC_getSample(s, qsa, thread, num);
-
- vec[0] = (float)(s[0] - 0.5) * sizex;
- vec[1] = (float)(s[1] - 0.5) * sizey;
- vec[2] = 0.0f;
-}
-
-/* disc of radius 'radius', centred on 0,0 */
-static void QMC_sampleDisc(float vec[3], QMCSampler *qsa, int thread, int num, float radius)
-{
- double s[2];
- float phi, sqr;
-
- QMC_getSample(s, qsa, thread, num);
-
- phi = s[0]*2*M_PI;
- sqr = sqrt(s[1]);
-
- vec[0] = cosf(phi)*sqr* radius/2.0f;
- vec[1] = sinf(phi)*sqr* radius/2.0f;
- vec[2] = 0.0f;
-}
-
-/* uniform hemisphere sampling */
-static void QMC_sampleHemi(float vec[3], QMCSampler *qsa, int thread, int num)
-{
- double s[2];
- float phi, sqr;
-
- QMC_getSample(s, qsa, thread, num);
-
- phi = s[0]*2.0*M_PI;
- sqr = sqrt(s[1]);
-
- vec[0] = cosf(phi)*sqr;
- vec[1] = sinf(phi)*sqr;
- vec[2] = (float)(1.0 - s[1]*s[1]);
-}
-
-#if 0 /* currently not used */
-/* cosine weighted hemisphere sampling */
-static void QMC_sampleHemiCosine(float vec[3], QMCSampler *qsa, int thread, int num)
-{
- double s[2];
- float phi, sqr;
-
- QMC_getSample(s, qsa, thread, num);
-
- phi = s[0]*2.f*M_PI;
- sqr = s[1]*sqrt(2-s[1]*s[1]);
-
- vec[0] = cos(phi)*sqr;
- vec[1] = sin(phi)*sqr;
- vec[2] = 1.f - s[1]*s[1];
-
-}
-#endif
-
-/* called from convertBlenderScene.c */
-void init_render_qmcsampler(Render *re)
-{
- const int num_threads = re->r.threads;
- re->qmcsamplers= MEM_callocN(sizeof(ListBase)*num_threads, "QMCListBase");
- re->num_qmc_samplers = num_threads;
-}
-
-static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot)
-{
- QMCSampler *qsa;
-
- /* create qmc samplers as needed, since recursion makes it hard to
- * predict how many are needed */
-
- for (qsa=re->qmcsamplers[thread].first; qsa; qsa=qsa->next) {
- if (qsa->type == type && qsa->tot == tot && !qsa->used) {
- qsa->used = true;
- return qsa;
- }
- }
-
- qsa= QMC_initSampler(type, tot);
- qsa->used = true;
- BLI_addtail(&re->qmcsamplers[thread], qsa);
-
- return qsa;
-}
-
-static void release_thread_qmcsampler(Render *UNUSED(re), int UNUSED(thread), QMCSampler *qsa)
-{
- qsa->used= 0;
-}
-
-void free_render_qmcsampler(Render *re)
-{
- if (re->qmcsamplers) {
- QMCSampler *qsa, *next;
- int a;
- for (a = 0; a < re->num_qmc_samplers; a++) {
- for (qsa=re->qmcsamplers[a].first; qsa; qsa=next) {
- next= qsa->next;
- QMC_freeSampler(qsa);
- }
-
- re->qmcsamplers[a].first= re->qmcsamplers[a].last= NULL;
- }
-
- MEM_freeN(re->qmcsamplers);
- re->qmcsamplers= NULL;
- }
-}
-
-static int adaptive_sample_variance(int samples, const float col[3], const float colsq[3], float thresh)
-{
- float var[3], mean[3];
-
- /* scale threshold just to give a bit more precision in input rather than dealing with
- * tiny tiny numbers in the UI */
- thresh /= 2;
-
- mean[0] = col[0] / (float)samples;
- mean[1] = col[1] / (float)samples;
- mean[2] = col[2] / (float)samples;
-
- var[0] = (colsq[0] / (float)samples) - (mean[0]*mean[0]);
- var[1] = (colsq[1] / (float)samples) - (mean[1]*mean[1]);
- var[2] = (colsq[2] / (float)samples) - (mean[2]*mean[2]);
-
- if ((var[0] * 0.4f < thresh) && (var[1] * 0.3f < thresh) && (var[2] * 0.6f < thresh))
- return 1;
- else
- return 0;
-}
-
-static int adaptive_sample_contrast_val(int samples, float prev, float val, float thresh)
-{
- /* if the last sample's contribution to the total value was below a small threshold
- * (i.e. the samples taken are very similar), then taking more samples that are probably
- * going to be the same is wasting effort */
- if (fabsf(prev / (float)(samples - 1) - val / (float)samples ) < thresh) {
- return 1;
- }
- else
- return 0;
-}
-
-static float get_avg_speed(ShadeInput *shi)
-{
- float pre_x, pre_y, post_x, post_y, speedavg;
-
- pre_x = (shi->winspeed[0] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[0];
- pre_y = (shi->winspeed[1] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[1];
- post_x = (shi->winspeed[2] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[2];
- post_y = (shi->winspeed[3] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[3];
-
- speedavg = (sqrtf(pre_x * pre_x + pre_y * pre_y) + sqrtf(post_x * post_x + post_y * post_y)) / 2.0f;
-
- return speedavg;
-}
-
-/* ***************** main calls ************** */
-
-
-static void trace_refract(float col[4], ShadeInput *shi, ShadeResult *shr)
-{
- QMCSampler *qsa=NULL;
- int samp_type;
- int traflag=0;
-
- float samp3d[3], orthx[3], orthy[3];
- float v_refract[3], v_refract_new[3];
- float sampcol[4], colsq[4];
-
- float blur = pow3f(1.0f - shi->mat->gloss_tra);
- short max_samples = shi->mat->samp_gloss_tra;
- float adapt_thresh = shi->mat->adapt_thresh_tra;
-
- int samples=0;
-
- colsq[0] = colsq[1] = colsq[2] = 0.0;
- col[0] = col[1] = col[2] = 0.0;
- col[3]= shr->alpha;
-
- if (blur > 0.0f) {
- if (adapt_thresh != 0.0f) samp_type = SAMP_TYPE_HALTON;
- else samp_type = SAMP_TYPE_HAMMERSLEY;
-
- /* all samples are generated per pixel */
- qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples);
- QMC_initPixel(qsa, shi->thread);
- }
- else
- max_samples = 1;
-
-
- while (samples < max_samples) {
- if (refraction(v_refract, shi->vn, shi->view, shi->ang)) {
- traflag |= RAY_INSIDE;
- }
- else {
- /* total external reflection can happen for materials with IOR < 1.0 */
- if ((shi->vlr->flag & R_SMOOTH))
- reflection(v_refract, shi->vn, shi->view, shi->facenor);
- else
- reflection_simple(v_refract, shi->vn, shi->view);
-
- /* can't blur total external reflection */
- max_samples = 1;
- }
-
- if (max_samples > 1) {
- /* get a quasi-random vector from a phong-weighted disc */
- QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur);
-
- ortho_basis_v3v3_v3(orthx, orthy, v_refract);
- mul_v3_fl(orthx, samp3d[0]);
- mul_v3_fl(orthy, samp3d[1]);
-
- /* and perturb the refraction vector in it */
- add_v3_v3v3(v_refract_new, v_refract, orthx);
- add_v3_v3(v_refract_new, orthy);
-
- normalize_v3(v_refract_new);
- }
- else {
- /* no blurriness, use the original normal */
- copy_v3_v3(v_refract_new, v_refract);
- }
-
- sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f;
-
- traceray(shi, shr, shi->mat->ray_depth_tra, shi->co, v_refract_new, sampcol, shi->obi, shi->vlr, traflag);
-
- col[0] += sampcol[0];
- col[1] += sampcol[1];
- col[2] += sampcol[2];
- col[3] += sampcol[3];
-
- /* for variance calc */
- colsq[0] += sampcol[0]*sampcol[0];
- colsq[1] += sampcol[1]*sampcol[1];
- colsq[2] += sampcol[2]*sampcol[2];
-
- samples++;
-
- /* adaptive sampling */
- if (adapt_thresh < 1.0f && samples > max_samples/2) {
- if (adaptive_sample_variance(samples, col, colsq, adapt_thresh))
- break;
-
- /* if the pixel so far is very dark, we can get away with less samples */
- if ( (col[0] + col[1] + col[2])/3.0f/(float)samples < 0.01f )
- max_samples--;
- }
- }
-
- col[0] /= (float)samples;
- col[1] /= (float)samples;
- col[2] /= (float)samples;
- col[3] /= (float)samples;
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
-}
-
-static void trace_reflect(float col[3], ShadeInput *shi, ShadeResult *shr, float fresnelfac)
-{
- QMCSampler *qsa=NULL;
- int samp_type;
-
- float samp3d[3], orthx[3], orthy[3];
- float v_nor_new[3], v_reflect[3];
- float sampcol[4], colsq[4];
-
- float blur = pow3f(1.0f - shi->mat->gloss_mir);
- short max_samples = shi->mat->samp_gloss_mir;
- float adapt_thresh = shi->mat->adapt_thresh_mir;
- float aniso = 1.0f - shi->mat->aniso_gloss_mir;
-
- int samples=0;
-
- col[0] = col[1] = col[2] = 0.0;
- colsq[0] = colsq[1] = colsq[2] = 0.0;
-
- if (blur > 0.0f) {
- if (adapt_thresh != 0.0f) samp_type = SAMP_TYPE_HALTON;
- else samp_type = SAMP_TYPE_HAMMERSLEY;
-
- /* all samples are generated per pixel */
- qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples);
- QMC_initPixel(qsa, shi->thread);
- }
- else
- max_samples = 1;
-
- while (samples < max_samples) {
-
- if (max_samples > 1) {
- /* get a quasi-random vector from a phong-weighted disc */
- QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur);
-
- /* find the normal's perpendicular plane, blurring along tangents
- * if tangent shading enabled */
- if (shi->mat->mode & (MA_TANGENT_V)) {
- cross_v3_v3v3(orthx, shi->vn, shi->tang); // bitangent
- copy_v3_v3(orthy, shi->tang);
- mul_v3_fl(orthx, samp3d[0]);
- mul_v3_fl(orthy, samp3d[1]*aniso);
- }
- else {
- ortho_basis_v3v3_v3(orthx, orthy, shi->vn);
- mul_v3_fl(orthx, samp3d[0]);
- mul_v3_fl(orthy, samp3d[1]);
- }
-
- /* and perturb the normal in it */
- add_v3_v3v3(v_nor_new, shi->vn, orthx);
- add_v3_v3(v_nor_new, orthy);
- normalize_v3(v_nor_new);
- }
- else {
- /* no blurriness, use the original normal */
- copy_v3_v3(v_nor_new, shi->vn);
- }
-
- if ((shi->vlr->flag & R_SMOOTH))
- reflection(v_reflect, v_nor_new, shi->view, shi->facenor);
- else
- reflection_simple(v_reflect, v_nor_new, shi->view);
-
- sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f;
-
- traceray(shi, shr, shi->mat->ray_depth, shi->co, v_reflect, sampcol, shi->obi, shi->vlr, 0);
-
-
- col[0] += sampcol[0];
- col[1] += sampcol[1];
- col[2] += sampcol[2];
-
- /* for variance calc */
- colsq[0] += sampcol[0]*sampcol[0];
- colsq[1] += sampcol[1]*sampcol[1];
- colsq[2] += sampcol[2]*sampcol[2];
-
- samples++;
-
- /* adaptive sampling */
- if (adapt_thresh > 0.0f && samples > max_samples/3) {
- if (adaptive_sample_variance(samples, col, colsq, adapt_thresh))
- break;
-
- /* if the pixel so far is very dark, we can get away with less samples */
- if ( (col[0] + col[1] + col[2])/3.0f/(float)samples < 0.01f )
- max_samples--;
-
- /* reduce samples when reflection is dim due to low ray mirror blend value or fresnel factor
- * and when reflection is blurry */
- if (fresnelfac < 0.1f * (blur+1)) {
- max_samples--;
-
- /* even more for very dim */
- if (fresnelfac < 0.05f * (blur+1))
- max_samples--;
- }
- }
- }
-
- col[0] /= (float)samples;
- col[1] /= (float)samples;
- col[2] /= (float)samples;
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
-}
-
-/* extern call from render loop */
-void ray_trace(ShadeInput *shi, ShadeResult *shr)
-{
- float f1, fr, fg, fb;
- float mircol[4], tracol[4];
- float diff[3];
- int do_tra, do_mir;
-
- do_tra = ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP) && shr->alpha != 1.0f && (shi->depth <= shi->mat->ray_depth_tra));
- do_mir = ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror != 0.0f && (shi->depth <= shi->mat->ray_depth));
-
- /* raytrace mirror and refract like to separate the spec color */
- if (shi->combinedflag & SCE_PASS_SPEC)
- sub_v3_v3v3(diff, shr->combined, shr->spec);
- else
- copy_v3_v3(diff, shr->combined);
-
- if (do_tra) {
- float olddiff[3], f;
-
- trace_refract(tracol, shi, shr);
-
- f= shr->alpha; f1= 1.0f-f;
- fr= 1.0f+ shi->mat->filter*(shi->r-1.0f);
- fg= 1.0f+ shi->mat->filter*(shi->g-1.0f);
- fb= 1.0f+ shi->mat->filter*(shi->b-1.0f);
-
- /* for refract pass */
- copy_v3_v3(olddiff, diff);
-
- diff[0]= f*diff[0] + f1*fr*tracol[0];
- diff[1]= f*diff[1] + f1*fg*tracol[1];
- diff[2]= f*diff[2] + f1*fb*tracol[2];
-
- if (shi->passflag & SCE_PASS_REFRACT)
- sub_v3_v3v3(shr->refr, diff, olddiff);
-
- if (!(shi->combinedflag & SCE_PASS_REFRACT))
- sub_v3_v3v3(diff, diff, shr->refr);
-
- shr->alpha = min_ff(1.0f, tracol[3]);
- }
-
- if (do_mir) {
- const float i= shi->ray_mirror*fresnel_fac(shi->view, shi->vn, shi->mat->fresnel_mir_i, shi->mat->fresnel_mir);
- if (i!=0.0f) {
-
- trace_reflect(mircol, shi, shr, i);
-
- fr= i*shi->mirr;
- fg= i*shi->mirg;
- fb= i*shi->mirb;
-
- if (shi->passflag & SCE_PASS_REFLECT) {
- /* mirror pass is not blocked out with spec */
- shr->refl[0]= fr*mircol[0] - fr*diff[0];
- shr->refl[1]= fg*mircol[1] - fg*diff[1];
- shr->refl[2]= fb*mircol[2] - fb*diff[2];
- }
-
- if (shi->combinedflag & SCE_PASS_REFLECT) {
- /* values in shr->spec can be greater than 1.0.
- * In this case the mircol uses a zero blending factor, so ignoring it is ok.
- * Fixes bug #18837 - when the spec is higher then 1.0,
- * diff can become a negative color - Campbell */
-
- f1= 1.0f-i;
-
- diff[0] *= f1;
- diff[1] *= f1;
- diff[2] *= f1;
-
- if (shr->spec[0]<1.0f) diff[0] += mircol[0] * (fr*(1.0f-shr->spec[0]));
- if (shr->spec[1]<1.0f) diff[1] += mircol[1] * (fg*(1.0f-shr->spec[1]));
- if (shr->spec[2]<1.0f) diff[2] += mircol[2] * (fb*(1.0f-shr->spec[2]));
- }
- }
- }
- /* put back together */
- if (shi->combinedflag & SCE_PASS_SPEC)
- add_v3_v3v3(shr->combined, diff, shr->spec);
- else
- copy_v3_v3(shr->combined, diff);
-}
-
-/* color 'shadfac' passes through 'col' with alpha and filter */
-/* filter is only applied on alpha defined transparent part */
-static void addAlphaLight(float shadfac[4], const float col[3], float alpha, float filter)
-{
- float fr, fg, fb;
-
- fr= 1.0f+ filter*(col[0]-1.0f);
- fg= 1.0f+ filter*(col[1]-1.0f);
- fb= 1.0f+ filter*(col[2]-1.0f);
-
- shadfac[0]= alpha*col[0] + fr*(1.0f-alpha)*shadfac[0];
- shadfac[1]= alpha*col[1] + fg*(1.0f-alpha)*shadfac[1];
- shadfac[2]= alpha*col[2] + fb*(1.0f-alpha)*shadfac[2];
-
- shadfac[3]= (1.0f-alpha)*shadfac[3];
-}
-
-static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int traflag, float col[4])
-{
- /* ray to lamp, find first face that intersects, check alpha properties,
- * if it has col[3]>0.0f continue. so exit when alpha is full */
- const float initial_dist = is->dist;
-
- if (RE_rayobject_raycast(R.raytree, is)) {
- /* Warning regarding initializing to zero's, This is not that nice,
- * and possibly a bit slow for every ray, however some variables were
- * not initialized properly in, unless using
- * shade_input_initialize(...), we need to zero them. */
- ShadeInput shi= {NULL};
- /* end warning! - Campbell */
-
- ShadeResult shr;
-
- /* we got a face */
-
- shi.depth= origshi->depth + 1; /* only used to indicate tracing */
- shi.mask= origshi->mask;
- shi.thread= origshi->thread;
- shi.passflag= SCE_PASS_COMBINED;
- shi.combinedflag= 0xFFFFFF; /* ray trace does all options */
-
- shi.xs= origshi->xs;
- shi.ys= origshi->ys;
- shi.do_manage= origshi->do_manage;
- shi.lay= origshi->lay;
- shi.nodes= origshi->nodes;
-
- RE_instance_rotate_ray_restore(origshi->obi, is);
-
- shade_ray(is, &shi, &shr);
- if (shi.mat->material_type == MA_TYPE_SURFACE) {
- const float d = (shi.mat->mode & MA_RAYTRANSP) ?
- ((traflag & RAY_TRA) ? shade_by_transmission(is, &shi, &shr) : 1.0f) :
- 0.0f;
- /* mix colors based on shadfac (rgb + amount of light factor) */
- addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter);
- }
- else if (shi.mat->material_type == MA_TYPE_VOLUME) {
- const float a = col[3];
-
- col[0] = a*col[0] + shr.alpha*shr.combined[0];
- col[1] = a*col[1] + shr.alpha*shr.combined[1];
- col[2] = a*col[2] + shr.alpha*shr.combined[2];
-
- col[3] = (1.0f - shr.alpha)*a;
- }
-
- if (depth>0 && col[3]>0.0f) {
-
- /* adapt isect struct */
- copy_v3_v3(is->start, shi.co);
- is->dist = initial_dist-is->dist;
- is->orig.ob = shi.obi;
- is->orig.face = shi.vlr;
-
- ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA, col);
- }
-
- RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
- }
-}
-
-
-/* aolight: function to create random unit sphere vectors for total random sampling */
-
-/* calc distributed spherical energy */
-static void DS_energy(float *sphere, int tot, float vec[3])
-{
- float *fp, fac, force[3], res[3];
- int a;
-
- res[0]= res[1]= res[2]= 0.0f;
-
- for (a=0, fp=sphere; a<tot; a++, fp+=3) {
- sub_v3_v3v3(force, vec, fp);
- fac = dot_v3v3(force, force);
- if (fac!=0.0f) {
- fac= 1.0f/fac;
- res[0]+= fac*force[0];
- res[1]+= fac*force[1];
- res[2]+= fac*force[2];
- }
- }
-
- mul_v3_fl(res, 0.5);
- add_v3_v3(vec, res);
- normalize_v3(vec);
-
-}
-
-/* called from convertBlenderScene.c */
-/* creates an equally distributed spherical sample pattern */
-/* and allocates threadsafe memory */
-void init_ao_sphere(Render *re, World *wrld)
-{
- /* fixed random */
- const int num_threads = re->r.threads;
- RNG *rng;
- float *fp;
- int a, tot, iter= 16;
-
- /* we make twice the amount of samples, because only a hemisphere is used */
- tot= 2*wrld->aosamp*wrld->aosamp;
-
- wrld->aosphere= MEM_mallocN(3*tot*sizeof(float), "AO sphere");
- rng = BLI_rng_new_srandom(tot);
-
- /* init */
- fp= wrld->aosphere;
- for (a=0; a<tot; a++, fp+= 3) {
- BLI_rng_get_float_unit_v3(rng, fp);
- }
-
- while (iter--) {
- for (a=0, fp= wrld->aosphere; a<tot; a++, fp+= 3) {
- DS_energy(wrld->aosphere, tot, fp);
- }
- }
-
- /* tables */
- wrld->aotables= MEM_mallocN(num_threads*3*tot*sizeof(float), "AO tables");
-
- BLI_rng_free(rng);
-}
-
-/* give per thread a table, we have to compare xs ys because of way OSA works... */
-static float *threadsafe_table_sphere(int test, int thread, int xs, int ys, int tot)
-{
- static int xso[BLENDER_MAX_THREADS], yso[BLENDER_MAX_THREADS];
- static int firsttime= 1;
-
- if (firsttime) {
- memset(xso, 255, sizeof(xso));
- memset(yso, 255, sizeof(yso));
- firsttime= 0;
- }
-
- if (xs==xso[thread] && ys==yso[thread]) return R.wrld.aotables+ thread*tot*3;
- if (test) return NULL;
- xso[thread]= xs; yso[thread]= ys;
- return R.wrld.aotables+ thread*tot*3;
-}
-
-static float *sphere_sampler(int type, int resol, int thread, int xs, int ys, int reset)
-{
- int tot;
- float *vec;
-
- tot= 2*resol*resol;
-
- if (type & WO_AORNDSMP) {
- /* total random sampling. NOT THREADSAFE! (should be removed, is not useful) */
- RNG *rng = BLI_rng_new(BLI_thread_rand(thread));
- float *sphere;
- int a;
-
- /* always returns table */
- sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
-
- vec= sphere;
- for (a=0; a<tot; a++, vec+=3) {
- BLI_rng_get_float_unit_v3(rng, vec);
- }
-
- BLI_rng_free(rng);
-
- return sphere;
- }
- else {
- float *sphere;
- float *vec1;
-
- /* returns table if xs and ys were equal to last call, and not resetting */
- sphere= (reset)? NULL: threadsafe_table_sphere(1, thread, xs, ys, tot);
- if (sphere==NULL) {
- float cosfi, sinfi, cost, sint;
- float ang;
- int a;
-
- sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
-
- /* random rotation */
- ang = BLI_thread_frand(thread);
- sinfi = sinf(ang); cosfi = cosf(ang);
- ang = BLI_thread_frand(thread);
- sint = sinf(ang); cost = cosf(ang);
-
- vec= R.wrld.aosphere;
- vec1= sphere;
- for (a=0; a<tot; a++, vec+=3, vec1+=3) {
- vec1[0]= cost*cosfi*vec[0] - sinfi*vec[1] + sint*cosfi*vec[2];
- vec1[1]= cost*sinfi*vec[0] + cosfi*vec[1] + sint*sinfi*vec[2];
- vec1[2]= -sint*vec[0] + cost*vec[2];
- }
- }
- return sphere;
- }
-}
-
-static void ray_ao_qmc(ShadeInput *shi, float ao[3], float env[3])
-{
- Isect isec;
- RayHint point_hint;
- QMCSampler *qsa=NULL;
- float samp3d[3];
- float up[3], side[3], dir[3], nrm[3];
-
- float maxdist = R.wrld.aodist;
- float fac=0.0f, prev=0.0f;
- float adapt_thresh = R.wrld.ao_adapt_thresh;
- float adapt_speed_fac = R.wrld.ao_adapt_speed_fac;
-
- int samples=0;
- int max_samples = R.wrld.aosamp*R.wrld.aosamp;
-
- float dxyview[3], skyadded=0;
- int envcolor;
-
- RE_RC_INIT(isec, *shi);
- isec.orig.ob = shi->obi;
- isec.orig.face = shi->vlr;
- isec.check = RE_CHECK_VLR_NON_SOLID_MATERIAL;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
- isec.hint = NULL;
-
- isec.hit.ob = NULL;
- isec.hit.face = NULL;
-
- isec.last_hit = NULL;
-
- isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
- isec.lay= -1;
-
- copy_v3_v3(isec.start, shi->co);
-
- RE_instance_rotate_ray_start(shi->obi, &isec);
-
- RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start);
- isec.hint = &point_hint;
-
- zero_v3(ao);
- zero_v3(env);
-
- /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
- envcolor= R.wrld.aocolor;
- if (shi->mat->mode & MA_ONLYSHADOW)
- envcolor= WO_AOPLAIN;
-
- if (envcolor == WO_AOSKYTEX) {
- dxyview[0]= 1.0f/(float)R.wrld.aosamp;
- dxyview[1]= 1.0f/(float)R.wrld.aosamp;
- dxyview[2]= 0.0f;
- }
-
- if (shi->vlr->flag & R_SMOOTH) {
- copy_v3_v3(nrm, shi->vn);
- }
- else {
- copy_v3_v3(nrm, shi->facenor);
- }
-
- ortho_basis_v3v3_v3(up, side, nrm);
-
- /* sampling init */
- if (R.wrld.ao_samp_method==WO_AOSAMP_HALTON) {
- float speedfac;
-
- speedfac = get_avg_speed(shi) * adapt_speed_fac;
- CLAMP(speedfac, 1.0f, 1000.0f);
- max_samples /= speedfac;
- if (max_samples < 5) max_samples = 5;
-
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
- }
- else if (R.wrld.ao_samp_method==WO_AOSAMP_HAMMERSLEY)
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
-
- QMC_initPixel(qsa, shi->thread);
-
- while (samples < max_samples) {
-
- /* sampling, returns quasi-random vector in unit hemisphere */
- QMC_sampleHemi(samp3d, qsa, shi->thread, samples);
-
- dir[0] = (samp3d[0]*up[0] + samp3d[1]*side[0] + samp3d[2]*nrm[0]);
- dir[1] = (samp3d[0]*up[1] + samp3d[1]*side[1] + samp3d[2]*nrm[1]);
- dir[2] = (samp3d[0]*up[2] + samp3d[1]*side[2] + samp3d[2]*nrm[2]);
-
- normalize_v3(dir);
-
- isec.dir[0] = -dir[0];
- isec.dir[1] = -dir[1];
- isec.dir[2] = -dir[2];
- isec.dist = maxdist;
-
- RE_instance_rotate_ray_dir(shi->obi, &isec);
-
- prev = fac;
-
- if (RE_rayobject_raycast(R.raytree, &isec)) {
- if (R.wrld.aomode & WO_AODIST) fac+= expf(-isec.dist*R.wrld.aodistfac);
- else fac+= 1.0f;
- }
- else if (envcolor!=WO_AOPLAIN) {
- float skycol[4];
- float view[3];
-
- view[0]= -dir[0];
- view[1]= -dir[1];
- view[2]= -dir[2];
- normalize_v3(view);
-
- if (envcolor==WO_AOSKYCOL) {
- const float skyfac= 0.5f * (1.0f + dot_v3v3(view, R.grvec));
- env[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr;
- env[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng;
- env[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb;
- }
- else { /* WO_AOSKYTEX */
- shadeSkyView(skycol, isec.start, view, dxyview, shi->thread);
- shadeSunView(skycol, shi->view);
- env[0]+= skycol[0];
- env[1]+= skycol[1];
- env[2]+= skycol[2];
- }
- skyadded++;
- }
-
- samples++;
-
- if (qsa && qsa->type == SAMP_TYPE_HALTON) {
- /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
- if (adapt_thresh > 0.0f && (samples > max_samples/2) ) {
-
- if (adaptive_sample_contrast_val(samples, prev, fac, adapt_thresh)) {
- break;
- }
- }
- }
- }
-
- /* average color times distances/hits formula */
- ao[0]= ao[1]= ao[2]= 1.0f - fac/(float)samples;
-
- if (envcolor!=WO_AOPLAIN && skyadded)
- mul_v3_fl(env, (1.0f - fac/(float)samples)/((float)skyadded));
- else
- copy_v3_v3(env, ao);
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
-}
-
-/* extern call from shade_lamp_loop, ambient occlusion calculus */
-static void ray_ao_spheresamp(ShadeInput *shi, float ao[3], float env[3])
-{
- Isect isec;
- RayHint point_hint;
- float *vec, *nrm, bias, sh=0.0f;
- float maxdist = R.wrld.aodist;
- float dxyview[3];
- int j= -1, tot, actual=0, skyadded=0, envcolor, resol= R.wrld.aosamp;
-
- RE_RC_INIT(isec, *shi);
- isec.orig.ob = shi->obi;
- isec.orig.face = shi->vlr;
- isec.check = RE_CHECK_VLR_RENDER;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
- isec.hint = NULL;
-
- isec.hit.ob = NULL;
- isec.hit.face = NULL;
-
- isec.last_hit = NULL;
-
- isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
- isec.lay= -1;
-
- copy_v3_v3(isec.start, shi->co);
- RE_instance_rotate_ray_start(shi->obi, &isec);
-
- RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start);
- isec.hint = &point_hint;
-
- zero_v3(ao);
- zero_v3(env);
-
- /* bias prevents smoothed faces to appear flat */
- if (shi->vlr->flag & R_SMOOTH) {
- bias= R.wrld.aobias;
- nrm= shi->vn;
- }
- else {
- bias= 0.0f;
- nrm= shi->facenor;
- }
-
- /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
- envcolor= R.wrld.aocolor;
- if (shi->mat->mode & MA_ONLYSHADOW)
- envcolor= WO_AOPLAIN;
-
- if (resol>32) resol= 32;
-
- /* get sphere samples. for faces we get the same samples for sample x/y values,
- * for strand render we always require a new sampler because x/y are not set */
- vec= sphere_sampler(R.wrld.aomode, resol, shi->thread, shi->xs, shi->ys, shi->strand != NULL);
-
- /* warning: since we use full sphere now, and dotproduct is below, we do twice as much */
- tot= 2*resol*resol;
-
- if (envcolor == WO_AOSKYTEX) {
- dxyview[0]= 1.0f/(float)resol;
- dxyview[1]= 1.0f/(float)resol;
- dxyview[2]= 0.0f;
- }
-
- while (tot--) {
-
- if (dot_v3v3(vec, nrm) > bias) {
- /* only ao samples for mask */
- if (R.r.mode & R_OSA) {
- j++;
- if (j==R.osa) j= 0;
- if (!(shi->mask & (1<<j))) {
- vec+=3;
- continue;
- }
- }
-
- actual++;
-
- /* always set start/vec/dist */
- isec.dir[0] = -vec[0];
- isec.dir[1] = -vec[1];
- isec.dir[2] = -vec[2];
- isec.dist = maxdist;
-
- RE_instance_rotate_ray_dir(shi->obi, &isec);
-
- /* do the trace */
- if (RE_rayobject_raycast(R.raytree, &isec)) {
- if (R.wrld.aomode & WO_AODIST) sh+= expf(-isec.dist*R.wrld.aodistfac);
- else sh+= 1.0f;
- }
- else if (envcolor!=WO_AOPLAIN) {
- float skycol[4];
- float view[3];
-
- view[0]= -vec[0];
- view[1]= -vec[1];
- view[2]= -vec[2];
- normalize_v3(view);
-
- if (envcolor==WO_AOSKYCOL) {
- const float fac = 0.5f * (1.0f + dot_v3v3(view, R.grvec));
- env[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr;
- env[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng;
- env[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb;
- }
- else { /* WO_AOSKYTEX */
- shadeSkyView(skycol, isec.start, view, dxyview, shi->thread);
- shadeSunView(skycol, shi->view);
- env[0]+= skycol[0];
- env[1]+= skycol[1];
- env[2]+= skycol[2];
- }
- skyadded++;
- }
- }
- /* samples */
- vec+= 3;
- }
-
- if (actual==0) sh= 1.0f;
- else sh = 1.0f - sh/((float)actual);
-
- /* average color times distances/hits formula */
- ao[0]= ao[1]= ao[2]= sh;
-
- if (envcolor!=WO_AOPLAIN && skyadded)
- mul_v3_fl(env, sh/((float)skyadded));
- else
- copy_v3_v3(env, ao);
-}
-
-void ray_ao(ShadeInput *shi, float ao[3], float env[3])
-{
- /* Unfortunately, the unusual way that the sphere sampler calculates roughly twice as many
- * samples as are actually traced, and skips them based on bias and OSA settings makes it very difficult
- * to reuse code between these two functions. This is the easiest way I can think of to do it
- * --broken */
- if (ELEM(R.wrld.ao_samp_method, WO_AOSAMP_HAMMERSLEY, WO_AOSAMP_HALTON))
- ray_ao_qmc(shi, ao, env);
- else if (R.wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- ray_ao_spheresamp(shi, ao, env);
-}
-
-static void ray_shadow_jittered_coords(ShadeInput *shi, int max, float jitco[RE_MAX_OSA][3], int *totjitco)
-{
- /* magic numbers for reordering sample positions to give better
- * results with adaptive sample, when it usually only takes 4 samples */
- int order8[8] = {0, 1, 5, 6, 2, 3, 4, 7};
- int order11[11] = {1, 3, 8, 10, 0, 2, 4, 5, 6, 7, 9};
- int order16[16] = {1, 3, 9, 12, 0, 6, 7, 8, 13, 2, 4, 5, 10, 11, 14, 15};
- int count = count_mask(shi->mask);
-
- /* for better antialising shadow samples are distributed over the subpixel
- * sample coordinates, this only works for raytracing depth 0 though */
- if (!shi->strand && shi->depth == 0 && count > 1 && count <= max) {
- float xs, ys, zs, view[3];
- int samp, ordsamp, tot= 0;
-
- for (samp=0; samp<R.osa; samp++) {
- if (R.osa == 8) ordsamp = order8[samp];
- else if (R.osa == 11) ordsamp = order11[samp];
- else if (R.osa == 16) ordsamp = order16[samp];
- else ordsamp = samp;
-
- if (shi->mask & (1<<ordsamp)) {
- /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
- xs= (float)shi->scanco[0] + R.jit[ordsamp][0] + 0.5f;
- ys= (float)shi->scanco[1] + R.jit[ordsamp][1] + 0.5f;
- zs= shi->scanco[2];
-
- shade_input_calc_viewco(shi, xs, ys, zs, view, NULL, jitco[tot], NULL, NULL);
- tot++;
- }
- }
-
- *totjitco= tot;
- }
- else {
- copy_v3_v3(jitco[0], shi->co);
- *totjitco= 1;
- }
-}
-
-static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], float shadfac[4], Isect *isec)
-{
- QMCSampler *qsa=NULL;
- int samples=0;
- float samp3d[3];
-
- float fac=0.0f, vec[3], end[3];
- float colsq[4];
- float adapt_thresh = lar->adapt_thresh;
- int min_adapt_samples=4, max_samples = lar->ray_totsamp;
- float start[3];
- bool do_soft = true, full_osa = false;
- int i;
-
- float min[3], max[3];
- RayHint bb_hint;
-
- float jitco[RE_MAX_OSA][3];
- int totjitco;
-
- colsq[0] = colsq[1] = colsq[2] = 0.0;
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
- }
- else
- shadfac[3]= 1.0f;
-
- if (lar->ray_totsamp < 2) do_soft = false;
- if ((R.r.mode & R_OSA) && (R.osa > 0) && (shi->vlr->flag & R_FULL_OSA)) full_osa = true;
-
- if (full_osa) {
- if (do_soft) max_samples = max_samples/R.osa + 1;
- else max_samples = 1;
- }
- else {
- if (do_soft) max_samples = lar->ray_totsamp;
- else if (shi->depth == 0) max_samples = (R.osa > 4)?R.osa:5;
- else max_samples = 1;
- }
-
- ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco);
-
- /* sampling init */
- if (lar->ray_samp_method==LA_SAMP_HALTON)
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
- else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY)
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
-
- QMC_initPixel(qsa, shi->thread);
-
- INIT_MINMAX(min, max);
- for (i = 0; i < totjitco; i++) {
- minmax_v3v3_v3(min, max, jitco[i]);
- }
- if (shi->obi->flag & R_ENV_TRANSFORMED) {
- mul_m4_v3(shi->obi->imat, min);
- mul_m4_v3(shi->obi->imat, max);
- }
- RE_rayobject_hint_bb(R.raytree, &bb_hint, min, max);
-
- isec->hint = &bb_hint;
- isec->check = RE_CHECK_VLR_RENDER;
- isec->skip = RE_SKIP_VLR_NEIGHBOUR;
- copy_v3_v3(vec, lampco);
-
- while (samples < max_samples) {
-
- isec->orig.ob = shi->obi;
- isec->orig.face = shi->vlr;
-
- /* manually jitter the start shading co-ord per sample
- * based on the pre-generated OSA texture sampling offsets,
- * for anti-aliasing sharp shadow edges. */
- copy_v3_v3(start, jitco[samples % totjitco]);
-
- if (do_soft) {
- /* sphere shadow source */
- if (lar->type == LA_LOCAL) {
- float ru[3], rv[3], v[3], s[3];
-
- /* calc tangent plane vectors */
- sub_v3_v3v3(v, start, lampco);
- normalize_v3(v);
- ortho_basis_v3v3_v3(ru, rv, v);
-
- /* sampling, returns quasi-random vector in area_size disc */
- QMC_sampleDisc(samp3d, qsa, shi->thread, samples, lar->area_size);
-
- /* distribute disc samples across the tangent plane */
- s[0] = samp3d[0]*ru[0] + samp3d[1]*rv[0];
- s[1] = samp3d[0]*ru[1] + samp3d[1]*rv[1];
- s[2] = samp3d[0]*ru[2] + samp3d[1]*rv[2];
-
- copy_v3_v3(samp3d, s);
- }
- else {
- /* sampling, returns quasi-random vector in [sizex,sizey]^2 plane */
- QMC_sampleRect(samp3d, qsa, shi->thread, samples, lar->area_size, lar->area_sizey);
-
- /* align samples to lamp vector */
- mul_m3_v3(lar->mat, samp3d);
- }
- end[0] = vec[0]+samp3d[0];
- end[1] = vec[1]+samp3d[1];
- end[2] = vec[2]+samp3d[2];
- }
- else {
- copy_v3_v3(end, vec);
- }
-
- if (shi->strand) {
- /* bias away somewhat to avoid self intersection */
- float jitbias= 0.5f*(len_v3(shi->dxco) + len_v3(shi->dyco));
- float v[3];
-
- sub_v3_v3v3(v, start, end);
- normalize_v3(v);
-
- start[0] -= jitbias*v[0];
- start[1] -= jitbias*v[1];
- start[2] -= jitbias*v[2];
- }
-
- copy_v3_v3(isec->start, start);
- sub_v3_v3v3(isec->dir, end, start);
- isec->dist = normalize_v3(isec->dir);
-
- RE_instance_rotate_ray(shi->obi, isec);
-
- /* trace the ray */
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
- ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col);
- shadfac[0] += col[0];
- shadfac[1] += col[1];
- shadfac[2] += col[2];
- shadfac[3] += col[3];
-
- /* for variance calc */
- colsq[0] += col[0]*col[0];
- colsq[1] += col[1]*col[1];
- colsq[2] += col[2]*col[2];
- }
- else {
- if ( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
- }
-
- samples++;
-
- if (lar->ray_samp_method == LA_SAMP_HALTON) {
-
- /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
- if ((max_samples > min_adapt_samples) && (adapt_thresh > 0.0f) && (samples > max_samples / 3)) {
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- if ((shadfac[3] / samples > (1.0f-adapt_thresh)) || (shadfac[3] / samples < adapt_thresh))
- break;
- else if (adaptive_sample_variance(samples, shadfac, colsq, adapt_thresh))
- break;
- }
- else {
- if ((fac / samples > (1.0f-adapt_thresh)) || (fac / samples < adapt_thresh))
- break;
- }
- }
- }
- }
-
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- shadfac[0] /= samples;
- shadfac[1] /= samples;
- shadfac[2] /= samples;
- shadfac[3] /= samples;
- }
- else
- shadfac[3]= 1.0f-fac/samples;
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
-}
-
-static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[3], float shadfac[4], Isect *isec)
-{
- /* area soft shadow */
- const float *jitlamp;
- float fac=0.0f, div=0.0f, vec[3];
- int a, j= -1, mask;
- RayHint point_hint;
-
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
- }
- else shadfac[3]= 1.0f;
-
- fac= 0.0f;
- jitlamp= give_jitter_plane(lar, shi->thread, shi->xs, shi->ys);
-
- a= lar->ray_totsamp;
-
- /* this correction to make sure we always take at least 1 sample */
- mask= shi->mask;
- if (a==4) mask |= (mask>>4)|(mask>>8);
- else if (a==9) mask |= (mask>>9);
-
- copy_v3_v3(isec->start, shi->co);
- RE_instance_rotate_ray_start(shi->obi, isec);
-
- isec->orig.ob = shi->obi;
- isec->orig.face = shi->vlr;
- RE_rayobject_hint_bb(R.raytree, &point_hint, isec->start, isec->start);
- isec->hint = &point_hint;
-
- while (a--) {
-
- if (R.r.mode & R_OSA) {
- j++;
- if (j>=R.osa) j= 0;
- if (!(mask & (1<<j))) {
- jitlamp+= 2;
- continue;
- }
- }
-
- vec[0]= jitlamp[0];
- vec[1]= jitlamp[1];
- vec[2]= 0.0f;
- mul_m3_v3(lar->mat, vec);
-
- /* set start and vec */
- isec->dir[0] = vec[0]+lampco[0]-shi->co[0];
- isec->dir[1] = vec[1]+lampco[1]-shi->co[1];
- isec->dir[2] = vec[2]+lampco[2]-shi->co[2];
-
- RE_instance_rotate_ray_dir(shi->obi, isec);
-
- isec->dist = 1.0f;
- isec->check = RE_CHECK_VLR_RENDER;
- isec->skip = RE_SKIP_VLR_NEIGHBOUR;
-
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
- ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col);
- shadfac[0] += col[0];
- shadfac[1] += col[1];
- shadfac[2] += col[2];
- shadfac[3] += col[3];
- }
- else if ( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
-
- div+= 1.0f;
- jitlamp+= 2;
- }
-
- if (isec->mode==RE_RAY_SHADOW_TRA) {
- shadfac[0] /= div;
- shadfac[1] /= div;
- shadfac[2] /= div;
- shadfac[3] /= div;
- }
- else {
- /* sqrt makes nice umbra effect */
- if (lar->ray_samp_type & LA_SAMP_UMBRA)
- shadfac[3] = sqrtf(1.0f - fac / div);
- else
- shadfac[3] = 1.0f - fac / div;
- }
-}
-/* extern call from shade_lamp_loop */
-void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4])
-{
- Isect isec;
- float lampco[3];
-
- /* setup isec */
- RE_RC_INIT(isec, *shi);
- if (shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA;
- else isec.mode= RE_RAY_SHADOW;
- isec.hint = NULL;
-
- if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW))
- isec.lay= lar->lay;
- else
- isec.lay= -1;
-
- /* only when not mir tracing, first hit optimm */
- if (shi->depth==0) {
- isec.last_hit = lar->last_hit[shi->thread];
- }
- else {
- isec.last_hit = NULL;
- }
-
- if (lar->type==LA_SUN || lar->type==LA_HEMI) {
- /* jitter and QMC sampling add a displace vector to the lamp position
- * that's incorrect because a SUN lamp does not has an exact position
- * and the displace should be done at the ray vector instead of the
- * lamp position.
- * This is easily verified by noticing that shadows of SUN lights change
- * with the scene BB.
- *
- * This was detected during SoC 2009 - Raytrace Optimization, but to keep
- * consistency with older render code it wasn't removed.
- *
- * If the render code goes through some recode/serious bug-fix then this
- * is something to consider!
- */
- lampco[0]= shi->co[0] - R.maxdist*lar->vec[0];
- lampco[1]= shi->co[1] - R.maxdist*lar->vec[1];
- lampco[2]= shi->co[2] - R.maxdist*lar->vec[2];
- }
- else {
- copy_v3_v3(lampco, lar->co);
- }
-
- if (ELEM(lar->ray_samp_method, LA_SAMP_HALTON, LA_SAMP_HAMMERSLEY)) {
-
- ray_shadow_qmc(shi, lar, lampco, shadfac, &isec);
-
- }
- else {
- if (lar->ray_totsamp<2) {
-
- isec.orig.ob = shi->obi;
- isec.orig.face = shi->vlr;
-
- shadfac[3]= 1.0f; /* 1.0=full light */
-
- /* set up isec.dir */
- copy_v3_v3(isec.start, shi->co);
- sub_v3_v3v3(isec.dir, lampco, isec.start);
- isec.dist = normalize_v3(isec.dir);
-
- RE_instance_rotate_ray(shi->obi, &isec);
-
- if (isec.mode==RE_RAY_SHADOW_TRA) {
- /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
- float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
- ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0, col);
- copy_v4_v4(shadfac, col);
- }
- else if (RE_rayobject_raycast(R.raytree, &isec))
- shadfac[3]= 0.0f;
- }
- else {
- ray_shadow_jitter(shi, lar, lampco, shadfac, &isec);
- }
- }
-
- /* for first hit optim, set last interesected shadow face */
- if (shi->depth==0) {
- lar->last_hit[shi->thread] = isec.last_hit;
- }
-
-}
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 4f2b0980762..ea5ca18d58a 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -45,11 +45,10 @@
#include "BLI_threads.h"
#include "BKE_appdir.h"
-#include "BKE_image.h"
+#include "BKE_camera.h"
#include "BKE_global.h"
-#include "BKE_main.h"
+#include "BKE_image.h"
#include "BKE_report.h"
-#include "BKE_camera.h"
#include "BKE_scene.h"
#include "IMB_imbuf.h"
@@ -266,9 +265,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
RenderResult *rr;
RenderLayer *rl;
RenderView *rv;
- SceneRenderLayer *srl;
int rectx, recty;
- int nr;
rectx = BLI_rcti_size_x(partrct);
recty = BLI_rcti_size_y(partrct);
@@ -296,33 +293,21 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
render_result_views_new(rr, &re->r);
/* check renderdata for amount of layers */
- for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
-
- if (layername && layername[0])
- if (!STREQ(srl->name, layername))
- continue;
-
- if (re->r.scemode & R_SINGLE_LAYER) {
- if (nr != re->r.actlay)
- continue;
- }
- else {
- if (srl->layflag & SCE_LAY_DISABLE)
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re, view_layer)
+ {
+ if (layername && layername[0]) {
+ if (!STREQ(view_layer->name, layername)) {
continue;
+ }
}
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
BLI_addtail(&rr->layers, rl);
- BLI_strncpy(rl->name, srl->name, sizeof(rl->name));
- rl->lay = srl->lay;
- rl->lay_zmask = srl->lay_zmask;
- rl->lay_exclude = srl->lay_exclude;
- rl->layflag = srl->layflag;
- rl->passflag = srl->passflag; /* for debugging: srl->passflag | SCE_PASS_RAYHITS; */
- rl->pass_xor = srl->pass_xor;
- rl->light_override = srl->light_override;
- rl->mat_override = srl->mat_override;
+ BLI_strncpy(rl->name, view_layer->name, sizeof(rl->name));
+ rl->layflag = view_layer->layflag;
+ rl->passflag = view_layer->passflag; /* for debugging: view_layer->passflag | SCE_PASS_RAYHITS; */
+ rl->pass_xor = view_layer->pass_xor;
rl->rectx = rectx;
rl->recty = recty;
@@ -357,70 +342,72 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
/* a renderlayer should always have a Combined pass*/
render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA");
- if (srl->passflag & SCE_PASS_Z)
+ if (view_layer->passflag & SCE_PASS_Z)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_Z, view, "Z");
- if (srl->passflag & SCE_PASS_VECTOR)
+ if (view_layer->passflag & SCE_PASS_VECTOR)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_VECTOR, view, "XYZW");
- if (srl->passflag & SCE_PASS_NORMAL)
+ if (view_layer->passflag & SCE_PASS_NORMAL)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_NORMAL, view, "XYZ");
- if (srl->passflag & SCE_PASS_UV)
+ if (view_layer->passflag & SCE_PASS_UV)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_UV, view, "UVA");
- if (srl->passflag & SCE_PASS_RGBA)
+ if (view_layer->passflag & SCE_PASS_RGBA)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_RGBA, view, "RGBA");
- if (srl->passflag & SCE_PASS_EMIT)
+ if (view_layer->passflag & SCE_PASS_EMIT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_EMIT, view, "RGB");
- if (srl->passflag & SCE_PASS_DIFFUSE)
+ if (view_layer->passflag & SCE_PASS_DIFFUSE)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE, view, "RGB");
- if (srl->passflag & SCE_PASS_SPEC)
+ if (view_layer->passflag & SCE_PASS_SPEC)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SPEC, view, "RGB");
- if (srl->passflag & SCE_PASS_AO)
+ if (view_layer->passflag & SCE_PASS_AO)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_AO, view, "RGB");
- if (srl->passflag & SCE_PASS_ENVIRONMENT)
+ if (view_layer->passflag & SCE_PASS_ENVIRONMENT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_ENVIRONMENT, view, "RGB");
- if (srl->passflag & SCE_PASS_INDIRECT)
+ if (view_layer->passflag & SCE_PASS_INDIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_INDIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_SHADOW)
+ if (view_layer->passflag & SCE_PASS_SHADOW)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SHADOW, view, "RGB");
- if (srl->passflag & SCE_PASS_REFLECT)
+ if (view_layer->passflag & SCE_PASS_REFLECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_REFLECT, view, "RGB");
- if (srl->passflag & SCE_PASS_REFRACT)
+ if (view_layer->passflag & SCE_PASS_REFRACT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_REFRACT, view, "RGB");
- if (srl->passflag & SCE_PASS_INDEXOB)
+ if (view_layer->passflag & SCE_PASS_INDEXOB)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXOB, view, "X");
- if (srl->passflag & SCE_PASS_INDEXMA)
+ if (view_layer->passflag & SCE_PASS_INDEXMA)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_INDEXMA, view, "X");
- if (srl->passflag & SCE_PASS_MIST)
+ if (view_layer->passflag & SCE_PASS_MIST)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, RE_PASSNAME_MIST, view, "Z");
if (rl->passflag & SCE_PASS_RAYHITS)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, RE_PASSNAME_RAYHITS, view, "RGB");
- if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
+ if (view_layer->passflag & SCE_PASS_DIFFUSE_DIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_DIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
+ if (view_layer->passflag & SCE_PASS_DIFFUSE_INDIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_INDIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
+ if (view_layer->passflag & SCE_PASS_DIFFUSE_COLOR)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_DIFFUSE_COLOR, view, "RGB");
- if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
+ if (view_layer->passflag & SCE_PASS_GLOSSY_DIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_DIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
+ if (view_layer->passflag & SCE_PASS_GLOSSY_INDIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_INDIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
+ if (view_layer->passflag & SCE_PASS_GLOSSY_COLOR)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_GLOSSY_COLOR, view, "RGB");
- if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
+ if (view_layer->passflag & SCE_PASS_TRANSM_DIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_DIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
+ if (view_layer->passflag & SCE_PASS_TRANSM_INDIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_INDIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_TRANSM_COLOR)
+ if (view_layer->passflag & SCE_PASS_TRANSM_COLOR)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_TRANSM_COLOR, view, "RGB");
- if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
+ if (view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_DIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
+ if (view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_INDIRECT, view, "RGB");
- if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
+ if (view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR)
RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, RE_PASSNAME_SUBSURFACE_COLOR, view, "RGB");
#undef RENDER_LAYER_ADD_PASS_SAFE
}
}
- /* sss, previewrender and envmap don't do layers, so we make a default one */
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
+
+ /* previewrender doesn't do layers, so we make a default one */
if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) {
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
BLI_addtail(&rr->layers, rl);
@@ -449,11 +436,10 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
}
/* note, this has to be in sync with scene.c */
- rl->lay = (1 << 20) - 1;
rl->layflag = 0x7FFF; /* solid ztra halo strand */
rl->passflag = SCE_PASS_COMBINED;
- re->r.actlay = 0;
+ re->active_view_layer = 0;
}
/* border render; calculate offset for use in compositor. compo is centralized coords */
@@ -518,23 +504,6 @@ void render_result_add_pass(RenderResult *rr, const char *name, int channels, co
}
}
-/* allocate osa new results for samples */
-RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers, const char *viewname)
-{
- int a;
-
- if (re->osa == 0)
- return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
-
- for (a = 0; a < re->osa; a++) {
- RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname);
- BLI_addtail(lb, rr);
- rr->sample_nr = a;
- }
-
- return lb->first;
-}
-
static int passtype_from_name(const char *name)
{
const char delim[] = {'.', '\0'};
@@ -995,7 +964,7 @@ void render_result_single_layer_begin(Render *re)
/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
void render_result_single_layer_end(Render *re)
{
- SceneRenderLayer *srl;
+ ViewLayer *view_layer;
RenderLayer *rlpush;
RenderLayer *rl;
int nr;
@@ -1016,12 +985,12 @@ void render_result_single_layer_end(Render *re)
BLI_remlink(&re->result->layers, rl);
/* reconstruct render result layers */
- for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
- if (nr == re->r.actlay) {
+ for (nr = 0, view_layer = re->view_layers.first; view_layer; view_layer = view_layer->next, nr++) {
+ if (nr == re->active_view_layer) {
BLI_addtail(&re->result->layers, rl);
}
else {
- rlpush = RE_GetRenderLayer(re->pushedresult, srl->name);
+ rlpush = RE_GetRenderLayer(re->pushedresult, view_layer->name);
if (rlpush) {
BLI_remlink(&re->pushedresult->layers, rlpush);
BLI_addtail(&re->result->layers, rlpush);
@@ -1104,8 +1073,8 @@ void render_result_save_empty_result_tiles(Render *re)
for (rl = rr->layers.first; rl; rl = rl->next) {
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->status != PART_STATUS_MERGED) {
- int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
- int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
+ int party = pa->disprect.ymin - re->disprect.ymin;
+ int partx = pa->disprect.xmin - re->disprect.xmin;
IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname, true);
}
}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 103dbbacd22..b41e2d7fae4 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -55,7 +55,6 @@
#include "BKE_animsys.h"
#include "BKE_colorband.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -65,23 +64,11 @@
#include "MEM_guardedalloc.h"
-#include "envmap.h"
-#include "pointdensity.h"
-#include "voxeldata.h"
#include "render_types.h"
-#include "shading.h"
#include "texture.h"
-#include "texture_ocean.h"
-
-#include "renderdatabase.h" /* needed for UV */
#include "RE_render_ext.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+#include "RE_shader_ext.h"
static RNG_THREAD_ARRAY *random_tex_array;
@@ -97,63 +84,6 @@ void RE_texture_rng_exit(void)
}
-static void init_render_texture(Render *re, Tex *tex)
-{
- /* imap test */
- if (tex->ima && BKE_image_is_animated(tex->ima)) {
- BKE_image_user_frame_calc(&tex->iuser, re ? re->r.cfra : 0, re ? re->flag & R_SEC_FIELD:0);
- }
-
- else if (tex->type==TEX_ENVMAP) {
- /* just in case */
- tex->imaflag |= TEX_INTERPOL | TEX_MIPMAP;
- tex->extend= TEX_CLIP;
-
- if (tex->env) {
- if (tex->env->type==ENV_PLANE)
- tex->extend= TEX_EXTEND;
-
- /* only free envmap when rendermode was set to render envmaps, for previewrender */
- if (G.is_rendering && re) {
- if (re->r.mode & R_ENVMAP)
- if (tex->env->stype==ENV_ANIM)
- BKE_texture_envmap_free_data(tex->env);
- }
- }
- }
-
- if (tex->nodetree && tex->use_nodes) {
- ntreeTexBeginExecTree(tex->nodetree); /* has internal flag to detect it only does it once */
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-void init_render_textures(Render *re)
-{
- Tex *tex;
-
- tex= re->main->tex.first;
- while (tex) {
- if (tex->id.us) init_render_texture(re, tex);
- tex= tex->id.next;
- }
-}
-
-static void end_render_texture(Tex *tex)
-{
- if (tex && tex->use_nodes && tex->nodetree && tex->nodetree->execdata)
- ntreeTexEndExecTree(tex->nodetree->execdata);
-}
-
-void end_render_textures(Render *re)
-{
- Tex *tex;
- for (tex= re->main->tex.first; tex; tex= tex->id.next)
- if (tex->id.us)
- end_render_texture(tex);
-}
-
/* ------------------------------------------------------------------------- */
@@ -755,7 +685,6 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1
else {
copy_v3_v3(nor, n);
}
- mul_mat3_m4_v3(R.viewinv, nor);
x1 = fabsf(nor[0]);
y1 = fabsf(nor[1]);
@@ -781,115 +710,20 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1
/* ------------------------------------------------------------------------- */
-/* mtex argument only for projection switches */
-static int cubemap(
- const MTex *mtex, VlakRen *vlr, const float n[3], float x, float y, float z, float *adr1, float *adr2)
-{
- int proj[4]={0, ME_PROJXY, ME_PROJXZ, ME_PROJYZ}, ret= 0;
-
- if (vlr) {
- int index;
-
- /* Mesh vertices have such flags, for others we calculate it once based on orco */
- if ((vlr->puno & (ME_PROJXY|ME_PROJXZ|ME_PROJYZ))==0) {
- /* test for v1, vlr can be faked for baking */
- if (vlr->v1 && vlr->v1->orco) {
- float nor[3];
- normal_tri_v3(nor, vlr->v1->orco, vlr->v2->orco, vlr->v3->orco);
-
- if (fabsf(nor[0]) < fabsf(nor[2]) && fabsf(nor[1]) < fabsf(nor[2])) vlr->puno |= ME_PROJXY;
- else if (fabsf(nor[0]) < fabsf(nor[1]) && fabsf(nor[2]) < fabsf(nor[1])) vlr->puno |= ME_PROJXZ;
- else vlr->puno |= ME_PROJYZ;
- }
- else return cubemap_glob(n, x, y, z, adr1, adr2);
- }
-
- if (mtex) {
- /* the mtex->proj{xyz} have type char. maybe this should be wider? */
- /* casting to int ensures that the index type is right. */
- index = (int) mtex->projx;
- proj[index]= ME_PROJXY;
-
- index = (int) mtex->projy;
- proj[index]= ME_PROJXZ;
-
- index = (int) mtex->projz;
- proj[index]= ME_PROJYZ;
- }
-
- if (vlr->puno & proj[1]) {
- *adr1 = (x + 1.0f) / 2.0f;
- *adr2 = (y + 1.0f) / 2.0f;
- }
- else if (vlr->puno & proj[2]) {
- *adr1 = (x + 1.0f) / 2.0f;
- *adr2 = (z + 1.0f) / 2.0f;
- ret= 1;
- }
- else {
- *adr1 = (y + 1.0f) / 2.0f;
- *adr2 = (z + 1.0f) / 2.0f;
- ret= 2;
- }
- }
- else {
- return cubemap_glob(n, x, y, z, adr1, adr2);
- }
-
- return ret;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int cubemap_ob(Object *ob, const float n[3], float x, float y, float z, float *adr1, float *adr2)
-{
- float x1, y1, z1, nor[3];
- int ret;
-
- if (n==NULL) return 0;
-
- copy_v3_v3(nor, n);
- if (ob) mul_mat3_m4_v3(ob->imat, nor);
-
- x1 = fabsf(nor[0]);
- y1 = fabsf(nor[1]);
- z1 = fabsf(nor[2]);
-
- if (z1>=x1 && z1>=y1) {
- *adr1 = (x + 1.0f) / 2.0f;
- *adr2 = (y + 1.0f) / 2.0f;
- ret= 0;
- }
- else if (y1>=x1 && y1>=z1) {
- *adr1 = (x + 1.0f) / 2.0f;
- *adr2 = (z + 1.0f) / 2.0f;
- ret= 1;
- }
- else {
- *adr1 = (y + 1.0f) / 2.0f;
- *adr2 = (z + 1.0f) / 2.0f;
- ret= 2;
- }
- return ret;
-}
-
/* ------------------------------------------------------------------------- */
static void do_2d_mapping(
- const MTex *mtex, float texvec[3], VlakRen *vlr, const float n[3], float dxt[3], float dyt[3])
+ const MTex *mtex, float texvec[3], const float n[3], float dxt[3], float dyt[3])
{
Tex *tex;
- Object *ob= NULL;
float fx, fy, fac1, area[8];
- int ok, proj, areaflag= 0, wrap, texco;
+ int ok, proj, areaflag= 0, wrap;
/* mtex variables localized, only cubemap doesn't cooperate yet... */
wrap= mtex->mapping;
tex= mtex->tex;
- ob= mtex->object;
- texco= mtex->texco;
- if (R.osa==0) {
+ if (!(dxt && dyt)) {
if (wrap==MTEX_FLAT) {
fx = (texvec[0] + 1.0f) / 2.0f;
@@ -898,9 +732,7 @@ static void do_2d_mapping(
else if (wrap == MTEX_TUBE) map_to_tube( &fx, &fy, texvec[0], texvec[1], texvec[2]);
else if (wrap == MTEX_SPHERE) map_to_sphere(&fx, &fy, texvec[0], texvec[1], texvec[2]);
else {
- if (texco == TEXCO_OBJECT) cubemap_ob(ob, n, texvec[0], texvec[1], texvec[2], &fx, &fy);
- else if (texco == TEXCO_GLOB) cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
- else cubemap(mtex, vlr, n, texvec[0], texvec[1], texvec[2], &fx, &fy);
+ cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
}
/* repeat */
@@ -996,9 +828,7 @@ static void do_2d_mapping(
}
else {
- if (texco==TEXCO_OBJECT) proj = cubemap_ob(ob, n, texvec[0], texvec[1], texvec[2], &fx, &fy);
- else if (texco==TEXCO_GLOB) proj = cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
- else proj = cubemap(mtex, vlr, n, texvec[0], texvec[1], texvec[2], &fx, &fy);
+ proj = cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
if (proj==1) {
SWAP(float, dxt[1], dxt[2]);
@@ -1124,8 +954,9 @@ static int multitex(Tex *tex,
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
if (use_nodes && tex->use_nodes && tex->nodetree) {
+ const float cfra = 1.0f; /* This was only set for Blender Internal render before. */
retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread,
- tex, which_output, R.r.cfra, texnode_preview, NULL, NULL);
+ tex, which_output, cfra, texnode_preview, NULL);
}
else {
switch (tex->type) {
@@ -1160,9 +991,6 @@ static int multitex(Tex *tex,
BKE_image_tag_time(tex->ima);
}
break;
- case TEX_ENVMAP:
- retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres, pool, skip_load_image);
- break;
case TEX_MUSGRAVE:
/* newnoise: musgrave types */
@@ -1205,15 +1033,6 @@ static int multitex(Tex *tex,
retval = mg_distNoiseTex(tex, tmpvec, texres);
break;
- case TEX_POINTDENSITY:
- retval = pointdensitytex(tex, texvec, texres);
- break;
- case TEX_VOXELDATA:
- retval = voxeldatatex(tex, texvec, texres);
- break;
- case TEX_OCEAN:
- retval = ocean_texture(tex, texvec, texres);
- break;
}
}
@@ -1238,7 +1057,6 @@ static int multitex_nodes_intern(Tex *tex,
TexResult *texres,
const short thread,
short which_output,
- ShadeInput *shi,
MTex *mtex, struct
ImagePool *pool,
const bool scene_color_manage,
@@ -1259,7 +1077,7 @@ static int multitex_nodes_intern(Tex *tex,
if (mtex) {
/* we have mtex, use it for 2d mapping images only */
- do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
+ do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
rgbnor = multitex(tex,
texvec,
dxt, dyt,
@@ -1272,7 +1090,7 @@ static int multitex_nodes_intern(Tex *tex,
texnode_preview,
use_nodes);
- if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) {
+ if (mtex->mapto & (MAP_COL)) {
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
/* don't linearize float buffers, assumed to be linear */
@@ -1307,7 +1125,7 @@ static int multitex_nodes_intern(Tex *tex,
zero_v3(dyt_l);
}
- do_2d_mapping(&localmtex, texvec_l, NULL, NULL, dxt_l, dyt_l);
+ do_2d_mapping(&localmtex, texvec_l, NULL, dxt_l, dyt_l);
rgbnor = multitex(tex,
texvec_l,
dxt_l, dyt_l,
@@ -1357,41 +1175,15 @@ static int multitex_nodes_intern(Tex *tex,
* Use it from render pipeline only!
*/
int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres,
- const short thread, short which_output, ShadeInput *shi, MTex *mtex, struct ImagePool *pool)
+ const short thread, short which_output, MTex *mtex, struct ImagePool *pool)
{
return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres,
- thread, which_output, shi, mtex, pool, R.scene_color_manage,
- (R.r.scemode & R_NO_IMAGE_LOAD) != 0,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
+ thread, which_output, mtex, pool, true,
+ false,
+ false,
true);
}
-/* this is called for surface shading */
-static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
-{
- Tex *tex = mtex->tex;
- /* TODO(sergey): Texture preview should become an argument? */
- if (tex->use_nodes && tex->nodetree) {
- /* stupid exception here .. but we have to pass shi and mtex to
- * textures nodes for 2d mapping and color management for images */
- return ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, shi->osatex, shi->thread,
- tex, mtex->which_output, R.r.cfra, (R.r.scemode & R_TEXNODE_PREVIEW) != 0, shi, mtex);
- }
- else {
- return multitex(mtex->tex,
- texvec,
- dxt, dyt,
- shi->osatex,
- texres,
- shi->thread,
- mtex->which_output,
- pool,
- skip_load_image,
- (R.r.scemode & R_TEXNODE_PREVIEW) != 0,
- true);
- }
-}
-
/* Warning, if the texres's values are not declared zero, check the return value to be sure
* the color values are set before using the r/g/b values, otherwise you may use uninitialized values - Campbell
*
@@ -1414,7 +1206,7 @@ int multitex_ext(Tex *tex,
texres,
thread,
0,
- NULL, NULL,
+ NULL,
pool,
scene_color_manage,
skip_load_image,
@@ -1435,7 +1227,7 @@ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct Image
texres,
0,
0,
- NULL, NULL,
+ NULL,
pool,
scene_color_manage,
skip_load_image,
@@ -1652,1949 +1444,6 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
return in;
}
-static void texco_mapping(ShadeInput *shi, Tex *tex, MTex *mtex,
- const float co[3], const float dx[3], const float dy[3], float texvec[3], float dxt[3], float dyt[3])
-{
- /* new: first swap coords, then map, then trans/scale */
- if (tex->type == TEX_IMAGE) {
- /* placement */
- texvec[0] = mtex->projx ? co[mtex->projx - 1] : 0.f;
- texvec[1] = mtex->projy ? co[mtex->projy - 1] : 0.f;
- texvec[2] = mtex->projz ? co[mtex->projz - 1] : 0.f;
-
- if (shi->osatex) {
- if (mtex->projx) {
- dxt[0] = dx[mtex->projx - 1];
- dyt[0] = dy[mtex->projx - 1];
- }
- else dxt[0] = dyt[0] = 0.f;
- if (mtex->projy) {
- dxt[1] = dx[mtex->projy - 1];
- dyt[1] = dy[mtex->projy - 1];
- }
- else dxt[1] = dyt[1] = 0.f;
- if (mtex->projz) {
- dxt[2] = dx[mtex->projz - 1];
- dyt[2] = dy[mtex->projz - 1];
- }
- else dxt[2] = dyt[2] = 0.f;
- }
- do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
-
- /* translate and scale */
- texvec[0] = mtex->size[0]*(texvec[0] - 0.5f) + mtex->ofs[0] + 0.5f;
- texvec[1] = mtex->size[1]*(texvec[1] - 0.5f) + mtex->ofs[1] + 0.5f;
- if (shi->osatex) {
- dxt[0] = mtex->size[0] * dxt[0];
- dxt[1] = mtex->size[1] * dxt[1];
- dyt[0] = mtex->size[0] * dyt[0];
- dyt[1] = mtex->size[1] * dyt[1];
- }
-
- /* problem: repeat-mirror is not a 'repeat' but 'extend' in imagetexture.c */
- /* TXF: bug was here, only modify texvec when repeat mode set, old code affected other modes too.
- * New texfilters solve mirroring differently so that it also works correctly when
- * textures are scaled (sizeXYZ) as well as repeated. See also modification in do_2d_mapping().
- * (since currently only done in osa mode, results will look incorrect without osa TODO) */
- if (tex->extend == TEX_REPEAT && (tex->flag & TEX_REPEAT_XMIR)) {
- if (tex->texfilter == TXF_BOX)
- texvec[0] -= floorf(texvec[0]); /* this line equivalent to old code, same below */
- else if (texvec[0] < 0.f || texvec[0] > 1.f) {
- const float tx = 0.5f*texvec[0];
- texvec[0] = 2.f*(tx - floorf(tx));
- if (texvec[0] > 1.f) texvec[0] = 2.f - texvec[0];
- }
- }
- if (tex->extend == TEX_REPEAT && (tex->flag & TEX_REPEAT_YMIR)) {
- if (tex->texfilter == TXF_BOX)
- texvec[1] -= floorf(texvec[1]);
- else if (texvec[1] < 0.f || texvec[1] > 1.f) {
- const float ty = 0.5f*texvec[1];
- texvec[1] = 2.f*(ty - floorf(ty));
- if (texvec[1] > 1.f) texvec[1] = 2.f - texvec[1];
- }
- }
-
- }
- else { /* procedural */
- /* placement */
- texvec[0] = mtex->size[0]*(mtex->projx ? (co[mtex->projx - 1] + mtex->ofs[0]) : mtex->ofs[0]);
- texvec[1] = mtex->size[1]*(mtex->projy ? (co[mtex->projy - 1] + mtex->ofs[1]) : mtex->ofs[1]);
- texvec[2] = mtex->size[2]*(mtex->projz ? (co[mtex->projz - 1] + mtex->ofs[2]) : mtex->ofs[2]);
-
- if (shi->osatex) {
- if (mtex->projx) {
- dxt[0] = mtex->size[0]*dx[mtex->projx - 1];
- dyt[0] = mtex->size[0]*dy[mtex->projx - 1];
- }
- else dxt[0] = dyt[0] = 0.f;
- if (mtex->projy) {
- dxt[1] = mtex->size[1]*dx[mtex->projy - 1];
- dyt[1] = mtex->size[1]*dy[mtex->projy - 1];
- }
- else dxt[1] = dyt[1] = 0.f;
- if (mtex->projz) {
- dxt[2] = mtex->size[2]*dx[mtex->projz - 1];
- dyt[2] = mtex->size[2]*dy[mtex->projz - 1];
- }
- else dxt[2]= dyt[2] = 0.f;
- }
-
- if (mtex->tex->type == TEX_ENVMAP) {
- EnvMap *env = tex->env;
- if (!env->object) {
- // env->object is a view point for envmap rendering
- // if it's not set, return the result depending on the world_space_shading flag
- if (BKE_scene_use_world_space_shading(R.scene)) {
- mul_mat3_m4_v3(R.viewinv, texvec);
- if (shi->osatex) {
- mul_mat3_m4_v3(R.viewinv, dxt);
- mul_mat3_m4_v3(R.viewinv, dyt);
- }
- }
- }
- }
- }
-}
-
-/* Bump code from 2.5 development cycle, has a number of bugs, but here for compatibility */
-
-typedef struct CompatibleBump {
- float nu[3], nv[3], nn[3];
- float dudnu, dudnv, dvdnu, dvdnv;
- bool nunvdone;
-} CompatibleBump;
-
-static void compatible_bump_init(CompatibleBump *compat_bump)
-{
- memset(compat_bump, 0, sizeof(*compat_bump));
-
- compat_bump->dudnu = 1.0f;
- compat_bump->dvdnv = 1.0f;
-}
-
-static void compatible_bump_uv_derivs(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, int i)
-{
- /* uvmapping only, calculation of normal tangent u/v partial derivatives
- * (should not be here, dudnu, dudnv, dvdnu & dvdnv should probably be part of ShadeInputUV struct,
- * nu/nv in ShadeInput and this calculation should then move to shadeinput.c,
- * shade_input_set_shade_texco() func.) */
-
- /* NOTE: test for shi->obr->ob here,
- * since vlr/obr/obi can be 'fake' when called from fastshade(), another reason to move it.. */
-
- /* NOTE: shi->v1 is NULL when called from displace_render_vert,
- * assigning verts in this case is not trivial because the shi quad face side is not know. */
- if ((mtex->texflag & MTEX_COMPAT_BUMP) && shi->obr && shi->obr->ob && shi->v1) {
- if (mtex->mapto & (MAP_NORM|MAP_WARP) && !((mtex->tex->type==TEX_IMAGE) && (mtex->tex->imaflag & TEX_NORMALMAP))) {
- MTFace* tf = RE_vlakren_get_tface(shi->obr, shi->vlr, i, NULL, 0);
- int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
-
- vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
-
- /* compute ortho basis around normal */
- if (!compat_bump->nunvdone) {
- /* render normal is negated */
- compat_bump->nn[0] = -shi->vn[0];
- compat_bump->nn[1] = -shi->vn[1];
- compat_bump->nn[2] = -shi->vn[2];
- ortho_basis_v3v3_v3(compat_bump->nu, compat_bump->nv, compat_bump->nn);
- compat_bump->nunvdone = true;
- }
-
- if (tf) {
- const float *uv1 = tf->uv[j1], *uv2 = tf->uv[j2], *uv3 = tf->uv[j3];
- const float an[3] = {fabsf(compat_bump->nn[0]), fabsf(compat_bump->nn[1]), fabsf(compat_bump->nn[2])};
- const int a1 = (an[0] > an[1] && an[0] > an[2]) ? 1 : 0;
- const int a2 = (an[2] > an[0] && an[2] > an[1]) ? 1 : 2;
- const float dp1_a1 = shi->v1->co[a1] - shi->v3->co[a1];
- const float dp1_a2 = shi->v1->co[a2] - shi->v3->co[a2];
- const float dp2_a1 = shi->v2->co[a1] - shi->v3->co[a1];
- const float dp2_a2 = shi->v2->co[a2] - shi->v3->co[a2];
- const float du1 = uv1[0] - uv3[0], du2 = uv2[0] - uv3[0];
- const float dv1 = uv1[1] - uv3[1], dv2 = uv2[1] - uv3[1];
- const float dpdu_a1 = dv2*dp1_a1 - dv1*dp2_a1;
- const float dpdu_a2 = dv2*dp1_a2 - dv1*dp2_a2;
- const float dpdv_a1 = du1*dp2_a1 - du2*dp1_a1;
- const float dpdv_a2 = du1*dp2_a2 - du2*dp1_a2;
- float d = dpdu_a1*dpdv_a2 - dpdv_a1*dpdu_a2;
- float uvd = du1*dv2 - dv1*du2;
-
- if (uvd == 0.f) uvd = 1e-5f;
- if (d == 0.f) d = 1e-5f;
- d = uvd / d;
-
- compat_bump->dudnu = (dpdv_a2*compat_bump->nu[a1] - dpdv_a1*compat_bump->nu[a2])*d;
- compat_bump->dvdnu = (dpdu_a1*compat_bump->nu[a2] - dpdu_a2*compat_bump->nu[a1])*d;
- compat_bump->dudnv = (dpdv_a2*compat_bump->nv[a1] - dpdv_a1*compat_bump->nv[a2])*d;
- compat_bump->dvdnv = (dpdu_a1*compat_bump->nv[a2] - dpdu_a2*compat_bump->nv[a1])*d;
- }
- }
- }
-}
-
-static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres,
- float Tnor, const float co[3], const float dx[3], const float dy[3], float texvec[3], float dxt[3], float dyt[3],
- struct ImagePool *pool, const bool skip_load_image)
-{
- TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */
- float tco[3], texv[3], cd, ud, vd, du, dv, idu, idv;
- const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0));
- const float bf = -0.04f*Tnor*mtex->norfac;
- int rgbnor;
- /* disable internal bump eval */
- float *nvec = texres->nor;
- texres->nor = NULL;
- /* du & dv estimates, constant value defaults */
- du = dv = 0.01f;
-
- /* compute ortho basis around normal */
- if (!compat_bump->nunvdone) {
- /* render normal is negated */
- negate_v3_v3(compat_bump->nn, shi->vn);
- ortho_basis_v3v3_v3(compat_bump->nu, compat_bump->nv, compat_bump->nn);
- compat_bump->nunvdone = true;
- }
-
- /* two methods, either constant based on main image resolution,
- * (which also works without osa, though of course not always good (or even very bad) results),
- * or based on tex derivative max values (osa only). Not sure which is best... */
-
- if (!shi->osatex && (tex->type == TEX_IMAGE) && tex->ima) {
- /* in case we have no proper derivatives, fall back to
- * computing du/dv it based on image size */
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
- if (ibuf) {
- du = 1.f/(float)ibuf->x;
- dv = 1.f/(float)ibuf->y;
- }
- BKE_image_pool_release_ibuf(tex->ima, ibuf, pool);
- }
- else if (shi->osatex) {
- /* we have derivatives, can compute proper du/dv */
- if (tex->type == TEX_IMAGE) { /* 2d image, use u & v max. of dx/dy 2d vecs */
- const float adx[2] = {fabsf(dx[0]), fabsf(dx[1])};
- const float ady[2] = {fabsf(dy[0]), fabsf(dy[1])};
- du = MAX2(adx[0], ady[0]);
- dv = MAX2(adx[1], ady[1]);
- }
- else { /* 3d procedural, estimate from all dx/dy elems */
- const float adx[3] = {fabsf(dx[0]), fabsf(dx[1]), fabsf(dx[2])};
- const float ady[3] = {fabsf(dy[0]), fabsf(dy[1]), fabsf(dy[2])};
- du = max_fff(adx[0], adx[1], adx[2]);
- dv = max_fff(ady[0], ady[1], ady[2]);
- }
- }
-
- /* center, main return value */
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool, skip_load_image);
- cd = fromrgb ? (texres->tr + texres->tg + texres->tb) / 3.0f : texres->tin;
-
- if (mtex->texco == TEXCO_UV) {
- /* for the uv case, use the same value for both du/dv,
- * since individually scaling the normal derivatives makes them useless... */
- du = min_ff(du, dv);
- idu = (du < 1e-5f) ? bf : (bf/du);
-
- /* +u val */
- tco[0] = co[0] + compat_bump->dudnu*du;
- tco[1] = co[1] + compat_bump->dvdnu*du;
- tco[2] = 0.f;
- texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
- ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
-
- /* +v val */
- tco[0] = co[0] + compat_bump->dudnv*du;
- tco[1] = co[1] + compat_bump->dvdnv*du;
- tco[2] = 0.f;
- texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
- vd = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
- }
- else {
- float tu[3], tv[3];
-
- copy_v3_v3(tu, compat_bump->nu);
- copy_v3_v3(tv, compat_bump->nv);
-
- idu = (du < 1e-5f) ? bf : (bf/du);
- idv = (dv < 1e-5f) ? bf : (bf/dv);
-
- if ((mtex->texco == TEXCO_ORCO) && shi->obr && shi->obr->ob) {
- mul_mat3_m4_v3(shi->obr->ob->imat_ren, tu);
- mul_mat3_m4_v3(shi->obr->ob->imat_ren, tv);
- normalize_v3(tu);
- normalize_v3(tv);
- }
- else if (mtex->texco == TEXCO_GLOB) {
- mul_mat3_m4_v3(R.viewinv, tu);
- mul_mat3_m4_v3(R.viewinv, tv);
- }
- else if (mtex->texco == TEXCO_OBJECT && mtex->object) {
- mul_mat3_m4_v3(mtex->object->imat_ren, tu);
- mul_mat3_m4_v3(mtex->object->imat_ren, tv);
- normalize_v3(tu);
- normalize_v3(tv);
- }
-
- /* +u val */
- tco[0] = co[0] + tu[0]*du;
- tco[1] = co[1] + tu[1]*du;
- tco[2] = co[2] + tu[2]*du;
- texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
- ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
-
- /* +v val */
- tco[0] = co[0] + tv[0]*dv;
- tco[1] = co[1] + tv[1]*dv;
- tco[2] = co[2] + tv[2]*dv;
- texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
- vd = idv*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
- }
-
- /* bumped normal */
- compat_bump->nu[0] += ud*compat_bump->nn[0];
- compat_bump->nu[1] += ud*compat_bump->nn[1];
- compat_bump->nu[2] += ud*compat_bump->nn[2];
- compat_bump->nv[0] += vd*compat_bump->nn[0];
- compat_bump->nv[1] += vd*compat_bump->nn[1];
- compat_bump->nv[2] += vd*compat_bump->nn[2];
- cross_v3_v3v3(nvec, compat_bump->nu, compat_bump->nv);
-
- nvec[0] = -nvec[0];
- nvec[1] = -nvec[1];
- nvec[2] = -nvec[2];
- texres->nor = nvec;
-
- rgbnor |= TEX_NOR;
- return rgbnor;
-}
-
-/* Improved bump code from later in 2.5 development cycle */
-
-typedef struct NTapBump {
- int init_done;
- int iPrevBumpSpace; /* 0: uninitialized, 1: objectspace, 2: texturespace, 4: viewspace */
- /* bumpmapping */
- float vNorg[3]; /* backup copy of shi->vn */
- float vNacc[3]; /* original surface normal minus the surface gradient of every bump map which is encountered */
- float vR1[3], vR2[3]; /* cross products (sigma_y, original_normal), (original_normal, sigma_x) */
- float sgn_det; /* sign of the determinant of the matrix {sigma_x, sigma_y, original_normal} */
- float fPrevMagnitude; /* copy of previous magnitude, used for multiple bumps in different spaces */
-} NTapBump;
-
-static void ntap_bump_init(NTapBump *ntap_bump)
-{
- memset(ntap_bump, 0, sizeof(*ntap_bump));
-}
-
-static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres,
- float Tnor, const float co[3], const float dx[3], const float dy[3],
- float texvec[3], float dxt[3], float dyt[3], struct ImagePool *pool,
- const bool skip_load_image)
-{
- TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */
-
- const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0));
-
- /* The negate on Hscale is done because the
- * normal in the renderer points inward which corresponds
- * to inverting the bump map. The normals are generated
- * this way in calc_vertexnormals(). Should this ever change
- * this negate must be removed. */
- float Hscale = -Tnor*mtex->norfac;
-
- int dimx=512, dimy=512;
- const int imag_tspace_dimension_x = 1024; /* only used for texture space variant */
- float aspect = 1.0f;
-
- /* 2 channels for 2D texture and 3 for 3D textures. */
- const int nr_channels = (mtex->texco == TEXCO_UV)? 2 : 3;
- int c, rgbnor, iBumpSpace;
- float dHdx, dHdy;
- int found_deriv_map = (tex->type==TEX_IMAGE) && (tex->imaflag & TEX_DERIVATIVEMAP);
-
- /* disable internal bump eval in sampler, save pointer */
- float *nvec = texres->nor;
- texres->nor = NULL;
-
- if (found_deriv_map==0) {
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) {
- if (tex->ima)
- Hscale *= 13.0f; /* appears to be a sensible default value */
- }
- else
- Hscale *= 0.1f; /* factor 0.1 proved to look like the previous bump code */
- }
-
- if ( !ntap_bump->init_done ) {
- copy_v3_v3(ntap_bump->vNacc, shi->vn);
- copy_v3_v3(ntap_bump->vNorg, shi->vn);
- ntap_bump->fPrevMagnitude = 1.0f;
- ntap_bump->iPrevBumpSpace = 0;
-
- ntap_bump->init_done = true;
- }
-
- /* resolve image dimensions */
- if (found_deriv_map || (mtex->texflag&MTEX_BUMP_TEXTURESPACE)!=0) {
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
- if (ibuf) {
- dimx = ibuf->x;
- dimy = ibuf->y;
- aspect = ((float) dimy) / dimx;
- }
- BKE_image_pool_release_ibuf(tex->ima, ibuf, pool);
- }
-
- if (found_deriv_map) {
- float dBdu, dBdv, auto_bump = 1.0f;
- float s = 1; /* negate this if flipped texture coordinate */
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool, skip_load_image);
-
- if (shi->obr->ob->derivedFinal) {
- auto_bump = shi->obr->ob->derivedFinal->auto_bump_scale;
- }
-
- {
- float fVirtDim = sqrtf(fabsf((float) (dimx*dimy)*mtex->size[0]*mtex->size[1]));
- auto_bump /= MAX2(fVirtDim, FLT_EPSILON);
- }
-
- /* this variant using a derivative map is described here
- * http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html */
- dBdu = auto_bump*Hscale*dimx*(2*texres->tr-1);
- dBdv = auto_bump*Hscale*dimy*(2*texres->tg-1);
-
- dHdx = dBdu*dxt[0] + s * dBdv*dxt[1];
- dHdy = dBdu*dyt[0] + s * dBdv*dyt[1];
- }
- else if (!(mtex->texflag & MTEX_5TAP_BUMP)) {
- /* compute height derivatives with respect to output image pixel coordinates x and y */
- float STll[3], STlr[3], STul[3];
- float Hll, Hlr, Hul;
-
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
-
- for (c=0; c<nr_channels; c++) {
- /* dx contains the derivatives (du/dx, dv/dx)
- * dy contains the derivatives (du/dy, dv/dy) */
- STll[c] = texvec[c];
- STlr[c] = texvec[c]+dxt[c];
- STul[c] = texvec[c]+dyt[c];
- }
-
- /* clear unused derivatives */
- for (c=nr_channels; c<3; c++) {
- STll[c] = 0.0f;
- STlr[c] = 0.0f;
- STul[c] = 0.0f;
- }
-
- /* use texres for the center sample, set rgbnor */
- rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool, skip_load_image);
- Hll = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin;
-
- /* use ttexr for the other 2 taps */
- multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool, skip_load_image);
- Hlr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
-
- multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool, skip_load_image);
- Hul = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
-
- dHdx = Hscale*(Hlr - Hll);
- dHdy = Hscale*(Hul - Hll);
- }
- else {
- /* same as above, but doing 5 taps, increasing quality at cost of speed */
- float STc[3], STl[3], STr[3], STd[3], STu[3];
- float /* Hc, */ /* UNUSED */ Hl, Hr, Hd, Hu;
-
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
-
- for (c=0; c<nr_channels; c++) {
- STc[c] = texvec[c];
- STl[c] = texvec[c] - 0.5f*dxt[c];
- STr[c] = texvec[c] + 0.5f*dxt[c];
- STd[c] = texvec[c] - 0.5f*dyt[c];
- STu[c] = texvec[c] + 0.5f*dyt[c];
- }
-
- /* clear unused derivatives */
- for (c=nr_channels; c<3; c++) {
- STc[c] = 0.0f;
- STl[c] = 0.0f;
- STr[c] = 0.0f;
- STd[c] = 0.0f;
- STu[c] = 0.0f;
- }
-
- /* use texres for the center sample, set rgbnor */
- rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool, skip_load_image);
- /* Hc = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin; */ /* UNUSED */
-
- /* use ttexr for the other taps */
- multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool, skip_load_image);
- Hl = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool, skip_load_image);
- Hr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool, skip_load_image);
- Hd = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool, skip_load_image);
- Hu = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin;
-
- dHdx = Hscale*(Hr - Hl);
- dHdy = Hscale*(Hu - Hd);
- }
-
- /* restore pointer */
- texres->nor = nvec;
-
- /* replaced newbump with code based on listing 1 and 2 of
- * [Mik10] Mikkelsen M. S.: Bump Mapping Unparameterized Surfaces on the GPU.
- * -> http://jbit.net/~sparky/sfgrad_bump/mm_sfgrad_bump.pdf */
-
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE )
- iBumpSpace = 1;
- else if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE )
- iBumpSpace = 2;
- else
- iBumpSpace = 4; /* ViewSpace */
-
- if ( ntap_bump->iPrevBumpSpace != iBumpSpace ) {
-
- /* initialize normal perturbation vectors */
- int xyz;
- float fDet, abs_fDet, fMagnitude;
- /* object2view and inverted matrix */
- float obj2view[3][3], view2obj[3][3], tmp[4][4];
- /* local copies of derivatives and normal */
- float dPdx[3], dPdy[3], vN[3];
- copy_v3_v3(dPdx, shi->dxco);
- copy_v3_v3(dPdy, shi->dyco);
- copy_v3_v3(vN, ntap_bump->vNorg);
-
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE ) {
- /* TODO: these calculations happen for every pixel!
- * -> move to shi->obi */
- mul_m4_m4m4(tmp, R.viewmat, shi->obr->ob->obmat);
- copy_m3_m4(obj2view, tmp); /* use only upper left 3x3 matrix */
- invert_m3_m3(view2obj, obj2view);
-
- /* generate the surface derivatives in object space */
- mul_m3_v3(view2obj, dPdx);
- mul_m3_v3(view2obj, dPdy);
- /* generate the unit normal in object space */
- mul_transposed_m3_v3(obj2view, vN);
- normalize_v3(vN);
- }
-
- cross_v3_v3v3(ntap_bump->vR1, dPdy, vN);
- cross_v3_v3v3(ntap_bump->vR2, vN, dPdx);
- fDet = dot_v3v3(dPdx, ntap_bump->vR1);
- ntap_bump->sgn_det = (fDet < 0)? -1.0f: 1.0f;
- abs_fDet = ntap_bump->sgn_det * fDet;
-
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) {
- if (tex->ima) {
- /* crazy hack solution that gives results similar to normal mapping - part 1 */
- normalize_v3(ntap_bump->vR1);
- normalize_v3(ntap_bump->vR2);
- abs_fDet = 1.0f;
- }
- }
-
- fMagnitude = abs_fDet;
- if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE ) {
- /* pre do transform of texres->nor by the inverse transposed of obj2view */
- mul_transposed_m3_v3(view2obj, vN);
- mul_transposed_m3_v3(view2obj, ntap_bump->vR1);
- mul_transposed_m3_v3(view2obj, ntap_bump->vR2);
-
- fMagnitude *= len_v3(vN);
- }
-
- if (ntap_bump->fPrevMagnitude > 0.0f)
- for (xyz=0; xyz<3; xyz++)
- ntap_bump->vNacc[xyz] *= fMagnitude / ntap_bump->fPrevMagnitude;
-
- ntap_bump->fPrevMagnitude = fMagnitude;
- ntap_bump->iPrevBumpSpace = iBumpSpace;
- }
-
- if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) {
- if (tex->ima) {
- /* crazy hack solution that gives results similar to normal mapping - part 2 */
- float vec[2];
- const float imag_tspace_dimension_y = aspect*imag_tspace_dimension_x;
-
- vec[0] = imag_tspace_dimension_x*dxt[0];
- vec[1] = imag_tspace_dimension_y*dxt[1];
- dHdx *= 1.0f/len_v2(vec);
- vec[0] = imag_tspace_dimension_x*dyt[0];
- vec[1] = imag_tspace_dimension_y*dyt[1];
- dHdy *= 1.0f/len_v2(vec);
- }
- }
-
- /* subtract the surface gradient from vNacc */
- for (c=0; c<3; c++) {
- float vSurfGrad_compi = ntap_bump->sgn_det * (dHdx * ntap_bump->vR1[c] + dHdy * ntap_bump->vR2[c]);
- ntap_bump->vNacc[c] -= vSurfGrad_compi;
- texres->nor[c] = ntap_bump->vNacc[c]; /* copy */
- }
-
- rgbnor |= TEX_NOR;
- return rgbnor;
-}
-
-void do_material_tex(ShadeInput *shi, Render *re)
-{
- const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
- CompatibleBump compat_bump;
- NTapBump ntap_bump;
- MTex *mtex;
- Tex *tex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float *co = NULL, *dx = NULL, *dy = NULL;
- float fact, facm, factt, facmm, stencilTin=1.0;
- float texvec[3], dxt[3], dyt[3], tempvec[3], norvec[3], warpvec[3]={0.0f, 0.0f, 0.0f}, Tnor=1.0;
- int tex_nr, rgbnor= 0;
- bool warp_done = false, use_compat_bump = false, use_ntap_bump = false;
- bool found_nmapping = false, found_deriv_map = false;
- bool iFirstTimeNMap = true;
-
- compatible_bump_init(&compat_bump);
- ntap_bump_init(&ntap_bump);
-
- if (re->r.scemode & R_NO_TEX) return;
- /* here: test flag if there's a tex (todo) */
-
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
-
- /* separate tex switching */
- if (shi->mat->septex & (1<<tex_nr)) continue;
-
- if (shi->mat->mtex[tex_nr]) {
- mtex= shi->mat->mtex[tex_nr];
-
- tex= mtex->tex;
- if (tex == NULL) continue;
-
- found_deriv_map = (tex->type==TEX_IMAGE) && (tex->imaflag & TEX_DERIVATIVEMAP);
- use_compat_bump= (mtex->texflag & MTEX_COMPAT_BUMP) != 0;
- use_ntap_bump = ((mtex->texflag & (MTEX_3TAP_BUMP|MTEX_5TAP_BUMP|MTEX_BICUBIC_BUMP))!=0 || found_deriv_map!=0) ? true : false;
-
- /* XXX texture node trees don't work for this yet */
- if (tex->nodetree && tex->use_nodes) {
- use_compat_bump = false;
- use_ntap_bump = false;
- }
-
- /* case displacement mapping */
- if (shi->osatex == 0 && use_ntap_bump) {
- use_ntap_bump = false;
- use_compat_bump = true;
- }
-
- /* case ocean */
- if (tex->type == TEX_OCEAN) {
- use_ntap_bump = false;
- use_compat_bump = false;
- }
-
- /* which coords */
- if (mtex->texco==TEXCO_ORCO) {
- if (mtex->texflag & MTEX_DUPLI_MAPTO) {
- co= shi->duplilo; dx= dxt; dy= dyt;
- dxt[0]= dxt[1]= dxt[2]= 0.0f;
- dyt[0]= dyt[1]= dyt[2]= 0.0f;
- }
- else {
- co= shi->lo; dx= shi->dxlo; dy= shi->dylo;
- }
- }
- else if (mtex->texco==TEXCO_OBJECT) {
- Object *ob= mtex->object;
- if (ob) {
- co= tempvec;
- dx= dxt;
- dy= dyt;
- copy_v3_v3(tempvec, shi->co);
- if (mtex->texflag & MTEX_OB_DUPLI_ORIG)
- if (shi->obi && shi->obi->duplitexmat)
- mul_m4_v3(shi->obi->duplitexmat, tempvec);
- mul_m4_v3(ob->imat_ren, tempvec);
- if (shi->osatex) {
- copy_v3_v3(dxt, shi->dxco);
- copy_v3_v3(dyt, shi->dyco);
- mul_mat3_m4_v3(ob->imat_ren, dxt);
- mul_mat3_m4_v3(ob->imat_ren, dyt);
- }
- }
- else {
- /* if object doesn't exist, do not use orcos (not initialized) */
- co= shi->co;
- dx= shi->dxco; dy= shi->dyco;
- }
- }
- else if (mtex->texco==TEXCO_REFL) {
- calc_R_ref(shi);
- co= shi->ref; dx= shi->dxref; dy= shi->dyref;
- }
- else if (mtex->texco==TEXCO_NORM) {
- co= shi->orn; dx= shi->dxno; dy= shi->dyno;
- }
- else if (mtex->texco==TEXCO_TANGENT) {
- co= shi->tang; dx= shi->dxno; dy= shi->dyno;
- }
- else if (mtex->texco==TEXCO_GLOB) {
- co= shi->gl; dx= shi->dxgl; dy= shi->dygl;
- }
- else if (mtex->texco==TEXCO_UV) {
- if (mtex->texflag & MTEX_DUPLI_MAPTO) {
- co= shi->dupliuv; dx= dxt; dy= dyt;
- dxt[0]= dxt[1]= dxt[2]= 0.0f;
- dyt[0]= dyt[1]= dyt[2]= 0.0f;
- }
- else {
- ShadeInputUV *suv= &shi->uv[shi->actuv];
- int i = shi->actuv;
-
- if (mtex->uvname[0] != 0) {
- for (i = 0; i < shi->totuv; i++) {
- if (STREQ(shi->uv[i].name, mtex->uvname)) {
- suv= &shi->uv[i];
- break;
- }
- }
- }
-
- co= suv->uv;
- dx= suv->dxuv;
- dy= suv->dyuv;
-
- compatible_bump_uv_derivs(&compat_bump, shi, mtex, i);
- }
- }
- else if (mtex->texco==TEXCO_WINDOW) {
- co= shi->winco; dx= shi->dxwin; dy= shi->dywin;
- }
- else if (mtex->texco==TEXCO_STRAND) {
- co= tempvec; dx= dxt; dy= dyt;
- co[0]= shi->strandco;
- co[1]= co[2]= 0.0f;
- dx[0]= shi->dxstrand;
- dx[1]= dx[2]= 0.0f;
- dy[0]= shi->dystrand;
- dy[1]= dy[2]= 0.0f;
- }
- else if (mtex->texco==TEXCO_STRESS) {
- co= tempvec; dx= dxt; dy= dyt;
- co[0]= shi->stress;
- co[1]= co[2]= 0.0f;
- dx[0]= 0.0f;
- dx[1]= dx[2]= 0.0f;
- dy[0]= 0.0f;
- dy[1]= dy[2]= 0.0f;
- }
- else {
- continue; /* can happen when texco defines disappear and it renders old files */
- }
-
- /* the pointer defines if bumping happens */
- if (mtex->mapto & (MAP_NORM|MAP_WARP)) {
- texres.nor= norvec;
- norvec[0]= norvec[1]= norvec[2]= 0.0;
- }
- else texres.nor= NULL;
-
- if (warp_done) {
- add_v3_v3v3(tempvec, co, warpvec);
- co= tempvec;
- }
-
- /* XXX texture node trees don't work for this yet */
- if (texres.nor && !((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP))) {
- if (use_compat_bump) {
- rgbnor = compatible_bump_compute(&compat_bump, shi, mtex, tex,
- &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt,
- re->pool, skip_load_image);
- }
- else if (use_ntap_bump) {
- rgbnor = ntap_bump_compute(&ntap_bump, shi, mtex, tex,
- &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt,
- re->pool, skip_load_image);
- }
- else {
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool, skip_load_image);
- }
- }
- else {
- texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool, skip_load_image);
- }
-
- /* texture output */
-
- if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgbnor -= TEX_RGB;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgbnor & TEX_RGB) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- texres.tin= 1.0f-texres.tin;
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgbnor & TEX_RGB) {
- fact= texres.ta;
- texres.ta*= stencilTin;
- stencilTin*= fact;
- }
- else {
- fact= texres.tin;
- texres.tin*= stencilTin;
- stencilTin*= fact;
- }
- }
- else {
- Tnor*= stencilTin;
- }
-
- if (texres.nor) {
- if ((rgbnor & TEX_NOR)==0) {
- /* make our own normal */
- if (rgbnor & TEX_RGB) {
- copy_v3_v3(texres.nor, &texres.tr);
- }
- else {
- float co_nor= 0.5f * cosf(texres.tin - 0.5f);
- float si = 0.5f * sinf(texres.tin - 0.5f);
- float f1, f2;
-
- f1= shi->vn[0];
- f2= shi->vn[1];
- texres.nor[0]= f1*co_nor+f2*si;
- f1= shi->vn[1];
- f2= shi->vn[2];
- texres.nor[1]= f1*co_nor+f2*si;
- texres.nor[2]= f2*co_nor-f1*si;
- }
- }
- /* warping, local space */
- if (mtex->mapto & MAP_WARP) {
- float *warpnor= texres.nor, warpnor_[3];
-
- if (use_ntap_bump) {
- copy_v3_v3(warpnor_, texres.nor);
- warpnor= warpnor_;
- normalize_v3(warpnor_);
- }
- warpvec[0]= mtex->warpfac*warpnor[0];
- warpvec[1]= mtex->warpfac*warpnor[1];
- warpvec[2]= mtex->warpfac*warpnor[2];
- warp_done = true;
- }
-#if 0
- if (mtex->texflag & MTEX_VIEWSPACE) {
- /* rotate to global coords */
- if (mtex->texco==TEXCO_ORCO || mtex->texco==TEXCO_UV) {
- if (shi->vlr && shi->obr && shi->obr->ob) {
- float len= normalize_v3(texres.nor);
- /* can be optimized... (ton) */
- mul_mat3_m4_v3(shi->obr->ob->obmat, texres.nor);
- mul_mat3_m4_v3(re->viewmat, texres.nor);
- normalize_v3_length(texres.nor, len);
- }
- }
- }
-#endif
- }
-
- /* mapping */
- if (mtex->mapto & (MAP_COL | MAP_COLSPEC | MAP_COLMIR)) {
- float tcol[3];
-
- /* stencil maps on the texture control slider, not texture intensity value */
- copy_v3_v3(tcol, &texres.tr);
-
- if ((rgbnor & TEX_RGB) == 0) {
- copy_v3_v3(tcol, &mtex->r);
- }
- else if (mtex->mapto & MAP_ALPHA) {
- texres.tin = stencilTin;
- }
- else {
- texres.tin = texres.ta;
- }
-
- /* inverse gamma correction */
- if (tex->type==TEX_IMAGE) {
- Image *ima = tex->ima;
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, re->pool);
-
- /* don't linearize float buffers, assumed to be linear */
- if (ibuf != NULL &&
- ibuf->rect_float == NULL &&
- (rgbnor & TEX_RGB) &&
- R.scene_color_manage)
- {
- IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace);
- }
-
- BKE_image_pool_release_ibuf(ima, ibuf, re->pool);
- }
-
- if (mtex->mapto & MAP_COL) {
- float colfac= mtex->colfac*stencilTin;
- texture_rgb_blend(&shi->r, tcol, &shi->r, texres.tin, colfac, mtex->blendtype);
- }
- if (mtex->mapto & MAP_COLSPEC) {
- float colspecfac= mtex->colspecfac*stencilTin;
- texture_rgb_blend(&shi->specr, tcol, &shi->specr, texres.tin, colspecfac, mtex->blendtype);
- }
- if (mtex->mapto & MAP_COLMIR) {
- float mirrfac= mtex->mirrfac*stencilTin;
-
- /* exception for envmap only */
- if (tex->type==TEX_ENVMAP && mtex->blendtype==MTEX_BLEND) {
- fact= texres.tin*mirrfac;
- facm= 1.0f- fact;
- shi->refcol[0]= fact + facm*shi->refcol[0];
- shi->refcol[1]= fact*tcol[0] + facm*shi->refcol[1];
- shi->refcol[2]= fact*tcol[1] + facm*shi->refcol[2];
- shi->refcol[3]= fact*tcol[2] + facm*shi->refcol[3];
- }
- else {
- texture_rgb_blend(&shi->mirr, tcol, &shi->mirr, texres.tin, mirrfac, mtex->blendtype);
- }
- }
- }
- if ( (mtex->mapto & MAP_NORM) ) {
- if (texres.nor) {
- float norfac= mtex->norfac;
-
- /* we need to code blending modes for normals too once.. now 1 exception hardcoded */
-
- if ((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP)) {
-
- found_nmapping = 1;
-
- /* qdn: for normalmaps, to invert the normalmap vector,
- * it is better to negate x & y instead of subtracting the vector as was done before */
- if (norfac < 0.0f) {
- texres.nor[0] = -texres.nor[0];
- texres.nor[1] = -texres.nor[1];
- }
- fact = Tnor*fabsf(norfac);
- if (fact>1.f) fact = 1.f;
- facm = 1.f-fact;
- if (mtex->normapspace == MTEX_NSPACE_TANGENT) {
- /* qdn: tangent space */
- float B[3], tv[3];
- const float *no = iFirstTimeNMap ? shi->nmapnorm : shi->vn;
- iFirstTimeNMap = false;
- cross_v3_v3v3(B, no, shi->nmaptang); /* bitangent */
- mul_v3_fl(B, shi->nmaptang[3]);
- /* transform norvec from tangent space to object surface in camera space */
- tv[0] = texres.nor[0]*shi->nmaptang[0] + texres.nor[1]*B[0] + texres.nor[2]*no[0];
- tv[1] = texres.nor[0]*shi->nmaptang[1] + texres.nor[1]*B[1] + texres.nor[2]*no[1];
- tv[2] = texres.nor[0]*shi->nmaptang[2] + texres.nor[1]*B[2] + texres.nor[2]*no[2];
- shi->vn[0]= facm*no[0] + fact*tv[0];
- shi->vn[1]= facm*no[1] + fact*tv[1];
- shi->vn[2]= facm*no[2] + fact*tv[2];
- }
- else {
- float nor[3];
-
- copy_v3_v3(nor, texres.nor);
-
- if (mtex->normapspace == MTEX_NSPACE_CAMERA) {
- /* pass */
- }
- else if (mtex->normapspace == MTEX_NSPACE_WORLD) {
- mul_mat3_m4_v3(re->viewmat, nor);
- }
- else if (mtex->normapspace == MTEX_NSPACE_OBJECT) {
- if (shi->obr && shi->obr->ob)
- mul_mat3_m4_v3(shi->obr->ob->obmat, nor);
- mul_mat3_m4_v3(re->viewmat, nor);
- }
-
- normalize_v3(nor);
-
- /* qdn: worldspace */
- shi->vn[0]= facm*shi->vn[0] + fact*nor[0];
- shi->vn[1]= facm*shi->vn[1] + fact*nor[1];
- shi->vn[2]= facm*shi->vn[2] + fact*nor[2];
- }
- }
- else {
- /* XXX texture node trees don't work for this yet */
- if (use_compat_bump || use_ntap_bump) {
- shi->vn[0] = texres.nor[0];
- shi->vn[1] = texres.nor[1];
- shi->vn[2] = texres.nor[2];
- }
- else {
- float nor[3], dot;
-
- if (shi->mat->mode & MA_TANGENT_V) {
- shi->tang[0]+= Tnor*norfac*texres.nor[0];
- shi->tang[1]+= Tnor*norfac*texres.nor[1];
- shi->tang[2]+= Tnor*norfac*texres.nor[2];
- }
-
- /* prevent bump to become negative normal */
- nor[0]= Tnor*norfac*texres.nor[0];
- nor[1]= Tnor*norfac*texres.nor[1];
- nor[2]= Tnor*norfac*texres.nor[2];
-
- dot= 0.5f + 0.5f * dot_v3v3(nor, shi->vn);
-
- shi->vn[0]+= dot*nor[0];
- shi->vn[1]+= dot*nor[1];
- shi->vn[2]+= dot*nor[2];
- }
- }
- normalize_v3(shi->vn);
-
- /* this makes sure the bump is passed on to the next texture */
- shi->orn[0]= -shi->vn[0];
- shi->orn[1]= -shi->vn[1];
- shi->orn[2]= -shi->vn[2];
- }
- }
-
- if ( mtex->mapto & MAP_DISPLACE ) {
- /* Now that most textures offer both Nor and Intensity, allow */
- /* both to work, and let user select with slider. */
- if (texres.nor) {
- float norfac= mtex->norfac;
-
- shi->displace[0]+= 0.2f*Tnor*norfac*texres.nor[0];
- shi->displace[1]+= 0.2f*Tnor*norfac*texres.nor[1];
- shi->displace[2]+= 0.2f*Tnor*norfac*texres.nor[2];
- }
-
- if (rgbnor & TEX_RGB) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- }
-
- factt= (0.5f-texres.tin)*mtex->dispfac*stencilTin; facmm= 1.0f-factt;
-
- if (mtex->blendtype==MTEX_BLEND) {
- shi->displace[0]= factt*shi->vn[0] + facmm*shi->displace[0];
- shi->displace[1]= factt*shi->vn[1] + facmm*shi->displace[1];
- shi->displace[2]= factt*shi->vn[2] + facmm*shi->displace[2];
- }
- else if (mtex->blendtype==MTEX_MUL) {
- shi->displace[0]*= factt*shi->vn[0];
- shi->displace[1]*= factt*shi->vn[1];
- shi->displace[2]*= factt*shi->vn[2];
- }
- else { /* add or sub */
- if (mtex->blendtype==MTEX_SUB) factt= -factt;
- shi->displace[0]+= factt*shi->vn[0];
- shi->displace[1]+= factt*shi->vn[1];
- shi->displace[2]+= factt*shi->vn[2];
- }
- }
-
- if (mtex->mapto & MAP_VARS) {
- /* stencil maps on the texture control slider, not texture intensity value */
-
- if (rgbnor & TEX_RGB) {
- if (texres.talpha) texres.tin = texres.ta;
- else texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- }
-
- if (mtex->mapto & MAP_REF) {
- float difffac= mtex->difffac*stencilTin;
-
- shi->refl= texture_value_blend(mtex->def_var, shi->refl, texres.tin, difffac, mtex->blendtype);
- if (shi->refl<0.0f) shi->refl= 0.0f;
- }
- if (mtex->mapto & MAP_SPEC) {
- float specfac= mtex->specfac*stencilTin;
-
- shi->spec= texture_value_blend(mtex->def_var, shi->spec, texres.tin, specfac, mtex->blendtype);
- if (shi->spec<0.0f) shi->spec= 0.0f;
- }
- if (mtex->mapto & MAP_EMIT) {
- float emitfac= mtex->emitfac*stencilTin;
-
- shi->emit= texture_value_blend(mtex->def_var, shi->emit, texres.tin, emitfac, mtex->blendtype);
- if (shi->emit<0.0f) shi->emit= 0.0f;
- }
- if (mtex->mapto & MAP_ALPHA) {
- float alphafac= mtex->alphafac*stencilTin;
-
- shi->alpha= texture_value_blend(mtex->def_var, shi->alpha, texres.tin, alphafac, mtex->blendtype);
- if (shi->alpha<0.0f) shi->alpha= 0.0f;
- else if (shi->alpha>1.0f) shi->alpha= 1.0f;
- }
- if (mtex->mapto & MAP_HAR) {
- float har; /* have to map to 0-1 */
- float hardfac= mtex->hardfac*stencilTin;
-
- har= ((float)shi->har)/128.0f;
- har= 128.0f*texture_value_blend(mtex->def_var, har, texres.tin, hardfac, mtex->blendtype);
-
- if (har<1.0f) shi->har= 1;
- else if (har>511) shi->har= 511;
- else shi->har= (int)har;
- }
- if (mtex->mapto & MAP_RAYMIRR) {
- float raymirrfac= mtex->raymirrfac*stencilTin;
-
- shi->ray_mirror= texture_value_blend(mtex->def_var, shi->ray_mirror, texres.tin, raymirrfac, mtex->blendtype);
- if (shi->ray_mirror<0.0f) shi->ray_mirror= 0.0f;
- else if (shi->ray_mirror>1.0f) shi->ray_mirror= 1.0f;
- }
- if (mtex->mapto & MAP_TRANSLU) {
- float translfac= mtex->translfac*stencilTin;
-
- shi->translucency= texture_value_blend(mtex->def_var, shi->translucency, texres.tin, translfac, mtex->blendtype);
- if (shi->translucency<0.0f) shi->translucency= 0.0f;
- else if (shi->translucency>1.0f) shi->translucency= 1.0f;
- }
- if (mtex->mapto & MAP_AMB) {
- float ambfac= mtex->ambfac*stencilTin;
-
- shi->amb= texture_value_blend(mtex->def_var, shi->amb, texres.tin, ambfac, mtex->blendtype);
- if (shi->amb<0.0f) shi->amb= 0.0f;
- else if (shi->amb>1.0f) shi->amb= 1.0f;
-
- shi->ambr= shi->amb*re->wrld.ambr;
- shi->ambg= shi->amb*re->wrld.ambg;
- shi->ambb= shi->amb*re->wrld.ambb;
- }
- }
- }
- }
- if ((use_compat_bump || use_ntap_bump || found_nmapping) && (shi->mat->mode & MA_TANGENT_V) != 0) {
- const float fnegdot = -dot_v3v3(shi->vn, shi->tang);
- /* apply Gram-Schmidt projection */
- madd_v3_v3fl(shi->tang, shi->vn, fnegdot);
- normalize_v3(shi->tang);
- }
-}
-
-
-void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_r[3], float *val, Render *re)
-{
- const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
- MTex *mtex;
- Tex *tex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- int tex_nr, rgbnor= 0;
- float co[3], texvec[3];
- float fact, stencilTin=1.0;
-
- if (re->r.scemode & R_NO_TEX) return;
- /* here: test flag if there's a tex (todo) */
-
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
- /* separate tex switching */
- if (shi->mat->septex & (1<<tex_nr)) continue;
-
- if (shi->mat->mtex[tex_nr]) {
- mtex= shi->mat->mtex[tex_nr];
- tex= mtex->tex;
- if (tex == NULL) continue;
-
- /* only process if this texture is mapped
- * to one that we're interested in */
- if (!(mtex->mapto & mapto_flag)) continue;
-
- /* which coords */
- if (mtex->texco==TEXCO_OBJECT) {
- Object *ob= mtex->object;
- if (ob) {
- copy_v3_v3(co, xyz);
- if (mtex->texflag & MTEX_OB_DUPLI_ORIG) {
- if (shi->obi && shi->obi->duplitexmat)
- mul_m4_v3(shi->obi->duplitexmat, co);
- }
- mul_m4_v3(ob->imat_ren, co);
-
- if (mtex->texflag & MTEX_MAPTO_BOUNDS && ob->bb) {
- /* use bb vec[0] as min and bb vec[6] as max */
- co[0] = (co[0] - ob->bb->vec[0][0]) / (ob->bb->vec[6][0]-ob->bb->vec[0][0]) * 2.0f - 1.0f;
- co[1] = (co[1] - ob->bb->vec[0][1]) / (ob->bb->vec[6][1]-ob->bb->vec[0][1]) * 2.0f - 1.0f;
- co[2] = (co[2] - ob->bb->vec[0][2]) / (ob->bb->vec[6][2]-ob->bb->vec[0][2]) * 2.0f - 1.0f;
- }
- }
- }
- /* not really orco, but 'local' */
- else if (mtex->texco==TEXCO_ORCO) {
-
- if (mtex->texflag & MTEX_DUPLI_MAPTO) {
- copy_v3_v3(co, shi->duplilo);
- }
- else {
- Object *ob= shi->obi->ob;
- copy_v3_v3(co, xyz);
- mul_m4_v3(ob->imat_ren, co);
-
- if (mtex->texflag & MTEX_MAPTO_BOUNDS && ob->bb) {
- /* use bb vec[0] as min and bb vec[6] as max */
- co[0] = (co[0] - ob->bb->vec[0][0]) / (ob->bb->vec[6][0]-ob->bb->vec[0][0]) * 2.0f - 1.0f;
- co[1] = (co[1] - ob->bb->vec[0][1]) / (ob->bb->vec[6][1]-ob->bb->vec[0][1]) * 2.0f - 1.0f;
- co[2] = (co[2] - ob->bb->vec[0][2]) / (ob->bb->vec[6][2]-ob->bb->vec[0][2]) * 2.0f - 1.0f;
- }
- }
- }
- else if (mtex->texco==TEXCO_GLOB) {
- copy_v3_v3(co, xyz);
- mul_m4_v3(re->viewinv, co);
- }
- else {
- continue; /* can happen when texco defines disappear and it renders old files */
- }
-
- texres.nor= NULL;
-
- if (tex->type == TEX_IMAGE) {
- continue; /* not supported yet */
- //do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
- }
- else {
- /* placement */
- if (mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
- else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
- if (mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
- else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
- if (mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
- else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
- }
-
- rgbnor = multitex(tex,
- texvec,
- NULL, NULL,
- 0,
- &texres,
- shi->thread,
- mtex->which_output,
- re->pool,
- skip_load_image,
- texnode_preview,
- true); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
-
- /* texture output */
-
- if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgbnor -= TEX_RGB;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgbnor & TEX_RGB) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- texres.tin= 1.0f-texres.tin;
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgbnor & TEX_RGB) {
- fact= texres.ta;
- texres.ta*= stencilTin;
- stencilTin*= fact;
- }
- else {
- fact= texres.tin;
- texres.tin*= stencilTin;
- stencilTin*= fact;
- }
- }
-
-
- if ((mapto_flag & (MAP_EMISSION_COL+MAP_TRANSMISSION_COL+MAP_REFLECTION_COL)) && (mtex->mapto & (MAP_EMISSION_COL+MAP_TRANSMISSION_COL+MAP_REFLECTION_COL))) {
- float tcol[3];
-
- /* stencil maps on the texture control slider, not texture intensity value */
-
- if ((rgbnor & TEX_RGB) == 0) {
- copy_v3_v3(tcol, &mtex->r);
- }
- else if (mtex->mapto & MAP_DENSITY) {
- copy_v3_v3(tcol, &texres.tr);
- if (texres.talpha) {
- texres.tin = stencilTin;
- }
- }
- else {
- copy_v3_v3(tcol, &texres.tr);
- if (texres.talpha) {
- texres.tin= texres.ta;
- }
- }
-
- /* used for emit */
- if ((mapto_flag & MAP_EMISSION_COL) && (mtex->mapto & MAP_EMISSION_COL)) {
- float colemitfac= mtex->colemitfac*stencilTin;
- texture_rgb_blend(col_r, tcol, col_r, texres.tin, colemitfac, mtex->blendtype);
- }
-
- if ((mapto_flag & MAP_REFLECTION_COL) && (mtex->mapto & MAP_REFLECTION_COL)) {
- float colreflfac= mtex->colreflfac*stencilTin;
- texture_rgb_blend(col_r, tcol, col_r, texres.tin, colreflfac, mtex->blendtype);
- }
-
- if ((mapto_flag & MAP_TRANSMISSION_COL) && (mtex->mapto & MAP_TRANSMISSION_COL)) {
- float coltransfac= mtex->coltransfac*stencilTin;
- texture_rgb_blend(col_r, tcol, col_r, texres.tin, coltransfac, mtex->blendtype);
- }
- }
-
- if ((mapto_flag & MAP_VARS) && (mtex->mapto & MAP_VARS)) {
- /* stencil maps on the texture control slider, not texture intensity value */
-
- /* convert RGB to intensity if intensity info isn't provided */
- if (rgbnor & TEX_RGB) {
- if (texres.talpha) texres.tin = texres.ta;
- else texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- }
-
- if ((mapto_flag & MAP_EMISSION) && (mtex->mapto & MAP_EMISSION)) {
- float emitfac= mtex->emitfac*stencilTin;
-
- *val = texture_value_blend(mtex->def_var, *val, texres.tin, emitfac, mtex->blendtype);
- if (*val<0.0f) *val= 0.0f;
- }
- if ((mapto_flag & MAP_DENSITY) && (mtex->mapto & MAP_DENSITY)) {
- float densfac= mtex->densfac*stencilTin;
-
- *val = texture_value_blend(mtex->def_var, *val, texres.tin, densfac, mtex->blendtype);
- CLAMP(*val, 0.0f, 1.0f);
- }
- if ((mapto_flag & MAP_SCATTERING) && (mtex->mapto & MAP_SCATTERING)) {
- float scatterfac= mtex->scatterfac*stencilTin;
-
- *val = texture_value_blend(mtex->def_var, *val, texres.tin, scatterfac, mtex->blendtype);
- CLAMP(*val, 0.0f, 1.0f);
- }
- if ((mapto_flag & MAP_REFLECTION) && (mtex->mapto & MAP_REFLECTION)) {
- float reflfac= mtex->reflfac*stencilTin;
-
- *val = texture_value_blend(mtex->def_var, *val, texres.tin, reflfac, mtex->blendtype);
- CLAMP(*val, 0.0f, 1.0f);
- }
- }
- }
- }
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
-{
- const bool skip_load_image = har->skip_load_image;
- const bool texnode_preview = har->texnode_preview;
- MTex *mtex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float texvec[3], dxt[3], dyt[3], fact, facm, dx;
- int rgb, osatex;
-
- if (R.r.scemode & R_NO_TEX) return;
-
- mtex= har->mat->mtex[0];
- if (har->mat->septex & (1<<0)) return;
- if (mtex->tex==NULL) return;
-
- /* no normal mapping */
- texres.nor= NULL;
-
- texvec[0]= xn/har->rad;
- texvec[1]= yn/har->rad;
- texvec[2]= 0.0;
-
- osatex= (har->mat->texco & TEXCO_OSA);
-
- /* placement */
- if (mtex->projx) texvec[0]= mtex->size[0]*(texvec[mtex->projx-1]+mtex->ofs[0]);
- else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
- if (mtex->projy) texvec[1]= mtex->size[1]*(texvec[mtex->projy-1]+mtex->ofs[1]);
- else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
- if (mtex->projz) texvec[2]= mtex->size[2]*(texvec[mtex->projz-1]+mtex->ofs[2]);
- else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
-
- if (osatex) {
-
- dx= 1.0f/har->rad;
-
- if (mtex->projx) {
- dxt[0]= mtex->size[0]*dx;
- dyt[0]= mtex->size[0]*dx;
- }
- else dxt[0]= dyt[0]= 0.0;
-
- if (mtex->projy) {
- dxt[1]= mtex->size[1]*dx;
- dyt[1]= mtex->size[1]*dx;
- }
- else dxt[1]= dyt[1]= 0.0;
-
- if (mtex->projz) {
- dxt[2]= 0.0;
- dyt[2]= 0.0;
- }
- else dxt[2]= dyt[2]= 0.0;
-
- }
-
- if (mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
-
- rgb = multitex(mtex->tex,
- texvec,
- dxt, dyt,
- osatex,
- &texres,
- 0,
- mtex->which_output,
- har->pool,
- skip_load_image,
- texnode_preview,
- true);
-
- /* texture output */
- if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgb= 0;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgb) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- else texres.tin= 1.0f-texres.tin;
- }
-
- /* mapping */
- if (mtex->mapto & MAP_COL) {
-
- if (rgb==0) {
- texres.tr= mtex->r;
- texres.tg= mtex->g;
- texres.tb= mtex->b;
- }
- else if (mtex->mapto & MAP_ALPHA) {
- texres.tin= 1.0;
- }
- else texres.tin= texres.ta;
-
- /* inverse gamma correction */
- if (mtex->tex->type==TEX_IMAGE) {
- Image *ima = mtex->tex->ima;
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &mtex->tex->iuser, har->pool);
-
- /* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && R.scene_color_manage)
- IMB_colormanagement_colorspace_to_scene_linear_v3(&texres.tr, ibuf->rect_colorspace);
-
- BKE_image_pool_release_ibuf(ima, ibuf, har->pool);
- }
-
- fact= texres.tin*mtex->colfac;
- facm= 1.0f-fact;
-
- if (mtex->blendtype==MTEX_MUL) {
- facm= 1.0f-mtex->colfac;
- }
-
- if (mtex->blendtype==MTEX_SUB) fact= -fact;
-
- if (mtex->blendtype==MTEX_BLEND) {
- col_r[0]= (fact*texres.tr + facm*har->r);
- col_r[1]= (fact*texres.tg + facm*har->g);
- col_r[2]= (fact*texres.tb + facm*har->b);
- }
- else if (mtex->blendtype==MTEX_MUL) {
- col_r[0]= (facm+fact*texres.tr)*har->r;
- col_r[1]= (facm+fact*texres.tg)*har->g;
- col_r[2]= (facm+fact*texres.tb)*har->b;
- }
- else {
- col_r[0]= (fact*texres.tr + har->r);
- col_r[1]= (fact*texres.tg + har->g);
- col_r[2]= (fact*texres.tb + har->b);
-
- CLAMP(col_r[0], 0.0f, 1.0f);
- CLAMP(col_r[1], 0.0f, 1.0f);
- CLAMP(col_r[2], 0.0f, 1.0f);
- }
- }
- if (mtex->mapto & MAP_ALPHA) {
- if (rgb) {
- if (texres.talpha) {
- texres.tin = texres.ta;
- }
- else {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- }
- }
-
- col_r[3]*= texres.tin;
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-/* hor and zen are RGB vectors, blend is 1 float, should all be initialized */
-void do_sky_tex(
- const float rco[3], const float view[3], const float lo[3], const float dxyview[2],
- float hor[3], float zen[3], float *blend, int skyflag, short thread)
-{
- const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (R.r.scemode & R_TEXNODE_PREVIEW) != 0;
- MTex *mtex;
- Tex *tex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float fact, stencilTin=1.0;
- float tempvec[3], texvec[3], dxt[3], dyt[3];
- int tex_nr, rgb= 0;
-
- if (R.r.scemode & R_NO_TEX) return;
- /* todo: add flag to test if there's a tex */
- texres.nor= NULL;
-
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
- if (R.wrld.mtex[tex_nr]) {
- const float *co;
-
- mtex= R.wrld.mtex[tex_nr];
-
- tex= mtex->tex;
- if (tex == NULL) continue;
- /* if (mtex->mapto==0) continue; */
-
- /* which coords */
- co= lo;
-
- /* dxt dyt just from 1 value */
- if (dxyview) {
- dxt[0]= dxt[1]= dxt[2]= dxyview[0];
- dyt[0]= dyt[1]= dyt[2]= dxyview[1];
- }
- else {
- dxt[0]= dxt[1]= dxt[2]= 0.0;
- dyt[0]= dyt[1]= dyt[2]= 0.0;
- }
-
- /* Grab the mapping settings for this texture */
- switch (mtex->texco) {
- case TEXCO_ANGMAP:
- /* only works with texture being "real" */
- /* use saacos(), fixes bug [#22398], float precision caused lo[2] to be slightly less than -1.0 */
- if (lo[0] || lo[1]) { /* check for zero case [#24807] */
- fact= (1.0f/(float)M_PI)*saacos(lo[2])/(sqrtf(lo[0]*lo[0] + lo[1]*lo[1]));
- tempvec[0]= lo[0]*fact;
- tempvec[1]= lo[1]*fact;
- tempvec[2]= 0.0;
- }
- else {
- /* this value has no angle, the vector is directly along the view.
- * avoid divide by zero and use a dummy value. */
- tempvec[0]= 1.0f;
- tempvec[1]= 0.0;
- tempvec[2]= 0.0;
- }
- co= tempvec;
- break;
-
- case TEXCO_H_SPHEREMAP:
- case TEXCO_H_TUBEMAP:
- if (skyflag & WO_ZENUP) {
- if (mtex->texco==TEXCO_H_TUBEMAP) map_to_tube( tempvec, tempvec+1, lo[0], lo[2], lo[1]);
- else map_to_sphere(tempvec, tempvec+1, lo[0], lo[2], lo[1]);
- /* tube/spheremap maps for outside view, not inside */
- tempvec[0]= 1.0f-tempvec[0];
- /* only top half */
- tempvec[1]= 2.0f*tempvec[1]-1.0f;
- tempvec[2]= 0.0;
- /* and correction for do_2d_mapping */
- tempvec[0]= 2.0f*tempvec[0]-1.0f;
- tempvec[1]= 2.0f*tempvec[1]-1.0f;
- co= tempvec;
- }
- else {
- /* potentially dangerous... check with multitex! */
- continue;
- }
- break;
- case TEXCO_EQUIRECTMAP:
- tempvec[0]= -atan2f(lo[2], lo[0]) / (float)M_PI;
- tempvec[1]= atan2f(lo[1], hypot(lo[0], lo[2])) / (float)M_PI_2;
- tempvec[2]= 0.0f;
- co= tempvec;
- break;
- case TEXCO_OBJECT:
- if (mtex->object) {
- copy_v3_v3(tempvec, lo);
- mul_m4_v3(mtex->object->imat_ren, tempvec);
- co= tempvec;
- }
- break;
-
- case TEXCO_GLOB:
- if (rco) {
- copy_v3_v3(tempvec, rco);
- mul_m4_v3(R.viewinv, tempvec);
- co= tempvec;
- }
- else
- co= lo;
-
-// copy_v3_v3(shi->dxgl, shi->dxco);
-// mul_m3_v3(R.imat, shi->dxco);
-// copy_v3_v3(shi->dygl, shi->dyco);
-// mul_m3_v3(R.imat, shi->dyco);
- break;
- case TEXCO_VIEW:
- co = view;
- break;
- }
-
- /* placement */
- if (mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
- else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
- if (mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
- else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
- if (mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
- else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
-
- /* texture */
- if (tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
-
- rgb = multitex(mtex->tex,
- texvec,
- dxt, dyt,
- R.osa,
- &texres,
- thread,
- mtex->which_output,
- R.pool,
- skip_load_image,
- texnode_preview,
- true);
-
- /* texture output */
- if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgb= 0;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgb) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- else texres.tin= 1.0f-texres.tin;
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgb) {
- fact= texres.ta;
- texres.ta*= stencilTin;
- stencilTin*= fact;
- }
- else {
- fact= texres.tin;
- texres.tin*= stencilTin;
- stencilTin*= fact;
- }
- }
- else {
- if (rgb) texres.ta *= stencilTin;
- else texres.tin*= stencilTin;
- }
-
- /* color mapping */
- if (mtex->mapto & (WOMAP_HORIZ+WOMAP_ZENUP+WOMAP_ZENDOWN)) {
- float tcol[3];
-
- if (rgb==0) {
- texres.tr= mtex->r;
- texres.tg= mtex->g;
- texres.tb= mtex->b;
- }
- else texres.tin= texres.ta;
-
- tcol[0]= texres.tr; tcol[1]= texres.tg; tcol[2]= texres.tb;
-
- /* inverse gamma correction */
- if (tex->type==TEX_IMAGE) {
- Image *ima = tex->ima;
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, R.pool);
-
- /* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && R.scene_color_manage)
- IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace);
-
- BKE_image_pool_release_ibuf(ima, ibuf, R.pool);
- }
-
- if (mtex->mapto & WOMAP_HORIZ) {
- texture_rgb_blend(hor, tcol, hor, texres.tin, mtex->colfac, mtex->blendtype);
- }
- if (mtex->mapto & (WOMAP_ZENUP+WOMAP_ZENDOWN)) {
- float zenfac = 0.0f;
-
- if (R.wrld.skytype & WO_SKYREAL) {
- if ((skyflag & WO_ZENUP)) {
- if (mtex->mapto & WOMAP_ZENUP) zenfac= mtex->zenupfac;
- }
- else if (mtex->mapto & WOMAP_ZENDOWN) zenfac= mtex->zendownfac;
- }
- else {
- if (mtex->mapto & WOMAP_ZENUP) zenfac= mtex->zenupfac;
- else if (mtex->mapto & WOMAP_ZENDOWN) zenfac= mtex->zendownfac;
- }
-
- if (zenfac != 0.0f)
- texture_rgb_blend(zen, tcol, zen, texres.tin, zenfac, mtex->blendtype);
- }
- }
- if (mtex->mapto & WOMAP_BLEND) {
- if (rgb) texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
-
- *blend= texture_value_blend(mtex->def_var, *blend, texres.tin, mtex->blendfac, mtex->blendtype);
- }
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-/* col_r supposed to be initialized with la->r,g,b */
-
-void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r[3], int effect)
-{
- const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (R.r.scemode & R_TEXNODE_PREVIEW) != 0;
- Object *ob;
- MTex *mtex;
- Tex *tex;
- TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float *co = NULL, *dx = NULL, *dy = NULL, fact, stencilTin=1.0;
- float texvec[3], dxt[3], dyt[3], tempvec[3];
- int i, tex_nr, rgb= 0;
-
- if (R.r.scemode & R_NO_TEX) return;
- tex_nr= 0;
-
- for (; tex_nr<MAX_MTEX; tex_nr++) {
-
- if (la->mtex[tex_nr]) {
- mtex= la->mtex[tex_nr];
-
- tex= mtex->tex;
- if (tex==NULL) continue;
- texres.nor= NULL;
-
- /* which coords */
- if (mtex->texco==TEXCO_OBJECT) {
- ob= mtex->object;
- if (ob) {
- co= tempvec;
- dx= dxt;
- dy= dyt;
- copy_v3_v3(tempvec, shi->co);
- mul_m4_v3(ob->imat_ren, tempvec);
- if (shi->osatex) {
- copy_v3_v3(dxt, shi->dxco);
- copy_v3_v3(dyt, shi->dyco);
- mul_mat3_m4_v3(ob->imat_ren, dxt);
- mul_mat3_m4_v3(ob->imat_ren, dyt);
- }
- }
- else {
- co= shi->co;
- dx= shi->dxco; dy= shi->dyco;
- }
- }
- else if (mtex->texco==TEXCO_GLOB) {
- co= shi->gl; dx= shi->dxco; dy= shi->dyco;
- copy_v3_v3(shi->gl, shi->co);
- mul_m4_v3(R.viewinv, shi->gl);
- }
- else if (mtex->texco==TEXCO_VIEW) {
-
- copy_v3_v3(tempvec, lavec);
- mul_m3_v3(la->imat, tempvec);
-
- if (la->type==LA_SPOT) {
- tempvec[0]*= la->spottexfac;
- tempvec[1]*= la->spottexfac;
- /* project from 3d to 2d */
- tempvec[0] /= -tempvec[2];
- tempvec[1] /= -tempvec[2];
- }
- co= tempvec;
-
- dx= dxt; dy= dyt;
- if (shi->osatex) {
- copy_v3_v3(dxt, shi->dxlv);
- copy_v3_v3(dyt, shi->dylv);
- /* need some matrix conversion here? la->imat is a [3][3] matrix!!! **/
- mul_m3_v3(la->imat, dxt);
- mul_m3_v3(la->imat, dyt);
-
- mul_v3_fl(dxt, la->spottexfac);
- mul_v3_fl(dyt, la->spottexfac);
- }
- }
-
-
- /* placement */
- if (mtex->projx && co) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
- else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
- if (mtex->projy && co) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
- else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
- if (mtex->projz && co) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
- else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
-
- if (shi->osatex) {
- if (!dx) {
- for (i=0;i<2;i++) {
- dxt[i] = dyt[i] = 0.0;
- }
- }
- else {
- if (mtex->projx) {
- dxt[0]= mtex->size[0]*dx[mtex->projx-1];
- dyt[0]= mtex->size[0]*dy[mtex->projx-1];
- }
- else {
- dxt[0]= 0.0;
- dyt[0]= 0.0;
- }
- if (mtex->projy) {
- dxt[1]= mtex->size[1]*dx[mtex->projy-1];
- dyt[1]= mtex->size[1]*dy[mtex->projy-1];
- }
- else {
- dxt[1]= 0.0;
- dyt[1]= 0.0;
- }
- if (mtex->projz) {
- dxt[2]= mtex->size[2]*dx[mtex->projz-1];
- dyt[2]= mtex->size[2]*dy[mtex->projz-1];
- }
- else {
- dxt[2]= 0.0;
- dyt[2]= 0.0;
- }
- }
- }
-
- /* texture */
- if (tex->type==TEX_IMAGE) {
- do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
- }
-
- rgb = multitex(tex,
- texvec,
- dxt, dyt,
- shi->osatex,
- &texres,
- shi->thread,
- mtex->which_output,
- R.pool,
- skip_load_image,
- texnode_preview,
- true);
-
- /* texture output */
- if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
- texres.tin = IMB_colormanagement_get_luminance(&texres.tr);
- rgb= 0;
- }
- if (mtex->texflag & MTEX_NEGATIVE) {
- if (rgb) {
- texres.tr= 1.0f-texres.tr;
- texres.tg= 1.0f-texres.tg;
- texres.tb= 1.0f-texres.tb;
- }
- else texres.tin= 1.0f-texres.tin;
- }
- if (mtex->texflag & MTEX_STENCIL) {
- if (rgb) {
- fact= texres.ta;
- texres.ta*= stencilTin;
- stencilTin*= fact;
- }
- else {
- fact= texres.tin;
- texres.tin*= stencilTin;
- stencilTin*= fact;
- }
- }
- else {
- if (rgb) texres.ta*= stencilTin;
- else texres.tin*= stencilTin;
- }
-
- /* mapping */
- if (((mtex->mapto & LAMAP_COL) && (effect & LA_TEXTURE))||((mtex->mapto & LAMAP_SHAD) && (effect & LA_SHAD_TEX))) {
- float col[3];
-
- if (rgb==0) {
- texres.tr= mtex->r;
- texres.tg= mtex->g;
- texres.tb= mtex->b;
- }
- else if (mtex->mapto & MAP_ALPHA) {
- texres.tin= stencilTin;
- }
- else texres.tin= texres.ta;
-
- /* inverse gamma correction */
- if (tex->type==TEX_IMAGE) {
- Image *ima = tex->ima;
- ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, R.pool);
-
- /* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && R.scene_color_manage)
- IMB_colormanagement_colorspace_to_scene_linear_v3(&texres.tr, ibuf->rect_colorspace);
-
- BKE_image_pool_release_ibuf(ima, ibuf, R.pool);
- }
-
- /* lamp colors were premultiplied with this */
- col[0]= texres.tr*la->energy;
- col[1]= texres.tg*la->energy;
- col[2]= texres.tb*la->energy;
-
- if (effect & LA_SHAD_TEX)
- texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->shadowfac, mtex->blendtype);
- else
- texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->colfac, mtex->blendtype);
- }
- }
- }
-}
-
/* ------------------------------------------------------------------------- */
int externtex(const MTex *mtex,
@@ -3626,7 +1475,7 @@ int externtex(const MTex *mtex,
/* texture */
if (tex->type==TEX_IMAGE) {
- do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
+ do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
}
rgb = multitex(tex,
@@ -3657,328 +1506,3 @@ int externtex(const MTex *mtex,
return (rgb != 0);
}
-
-
-/* ------------------------------------------------------------------------- */
-
-void render_realtime_texture(ShadeInput *shi, Image *ima)
-{
- const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
- TexResult texr;
- static Tex imatex[BLENDER_MAX_THREADS]; /* threadsafe */
- static int firsttime= 1;
- Tex *tex;
- float texvec[3], dx[2], dy[2];
- ShadeInputUV *suv= &shi->uv[shi->actuv];
- int a;
-
- if (R.r.scemode & R_NO_TEX) return;
-
- if (firsttime) {
- BLI_thread_lock(LOCK_IMAGE);
- if (firsttime) {
- const int num_threads = BLI_system_thread_count();
- for (a = 0; a < num_threads; a++) {
- memset(&imatex[a], 0, sizeof(Tex));
- BKE_texture_default(&imatex[a]);
- imatex[a].type= TEX_IMAGE;
- }
-
- firsttime= 0;
- }
- BLI_thread_unlock(LOCK_IMAGE);
- }
-
- tex= &imatex[shi->thread];
- tex->iuser.ok= ima->ok;
- tex->ima = ima;
-
- texvec[0]= 0.5f+0.5f*suv->uv[0];
- texvec[1]= 0.5f+0.5f*suv->uv[1];
- texvec[2] = 0.0f; /* initalize it because imagewrap looks at it. */
- if (shi->osatex) {
- dx[0]= 0.5f*suv->dxuv[0];
- dx[1]= 0.5f*suv->dxuv[1];
- dy[0]= 0.5f*suv->dyuv[0];
- dy[1]= 0.5f*suv->dyuv[1];
- }
-
- texr.nor= NULL;
-
- if (shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr, R.pool, skip_load_image);
- else imagewrap(tex, ima, NULL, texvec, &texr, R.pool, skip_load_image);
-
- shi->vcol[0]*= texr.tr;
- shi->vcol[1]*= texr.tg;
- shi->vcol[2]*= texr.tb;
- shi->vcol[3]*= texr.ta;
-}
-
-/* A modified part of shadeinput.c -> shade_input_set_uv()
- * Used for sampling UV mapped texture color */
-static void textured_face_generate_uv(
- const float normal[3], const float hit[3],
- const float v1[3], const float v2[3], const float v3[3],
- float r_uv[2])
-{
-
- float detsh, t00, t10, t01, t11;
- int axis1, axis2;
-
- /* find most stable axis to project */
- axis_dominant_v3(&axis1, &axis2, normal);
-
- /* compute u,v and derivatives */
- t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2];
- t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2];
-
- detsh= 1.0f/(t00*t11-t10*t01);
- t00*= detsh; t01*=detsh;
- t10*=detsh; t11*=detsh;
-
- r_uv[0] = (hit[axis1] - v3[axis1]) * t11 - (hit[axis2] - v3[axis2]) * t10;
- r_uv[1] = (hit[axis2] - v3[axis2]) * t00 - (hit[axis1] - v3[axis1]) * t01;
-
- /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */
- CLAMP(r_uv[0], -2.0f, 1.0f);
- CLAMP(r_uv[1], -2.0f, 1.0f);
-}
-
-/* Generate an updated copy of material to use for color sampling. */
-Material *RE_sample_material_init(Material *orig_mat, Scene *scene)
-{
- Tex *tex = NULL;
- Material *mat;
- int tex_nr;
-
- if (!orig_mat) return NULL;
-
- /* copy material */
- mat = BKE_material_localize(orig_mat);
-
- /* update material anims */
- BKE_animsys_evaluate_animdata(scene, &mat->id, mat->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
-
- /* strip material copy from unsupported flags */
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
-
- if (mat->mtex[tex_nr]) {
- MTex *mtex = mat->mtex[tex_nr];
-
- /* just in case make all non-used mtexes empty*/
- Tex *cur_tex = mtex->tex;
- mtex->tex = NULL;
-
- if (mat->septex & (1<<tex_nr) || !cur_tex) continue;
-
- /* only keep compatible texflags */
- mtex->texflag = mtex->texflag & (MTEX_RGBTOINT | MTEX_STENCIL | MTEX_NEGATIVE | MTEX_ALPHAMIX);
-
- /* depending of material type, strip non-compatible mapping modes */
- if (mat->material_type == MA_TYPE_SURFACE) {
- if (!ELEM(mtex->texco, TEXCO_ORCO, TEXCO_OBJECT, TEXCO_GLOB, TEXCO_UV)) {
- /* ignore this texture */
- mtex->texco = 0;
- continue;
- }
- /* strip all mapto flags except color and alpha */
- mtex->mapto = (mtex->mapto & MAP_COL) | (mtex->mapto & MAP_ALPHA);
- }
- else if (mat->material_type == MA_TYPE_VOLUME) {
- if (!ELEM(mtex->texco, TEXCO_OBJECT, TEXCO_ORCO, TEXCO_GLOB)) {
- /* ignore */
- mtex->texco = 0;
- continue;
- }
- /* strip all mapto flags except color and alpha */
- mtex->mapto = mtex->mapto & (MAP_TRANSMISSION_COL | MAP_REFLECTION_COL | MAP_DENSITY);
- }
-
- /* if mapped to an object, calculate inverse matrices */
- if (mtex->texco==TEXCO_OBJECT) {
- Object *ob= mtex->object;
- if (ob) {
- invert_m4_m4(ob->imat, ob->obmat);
- copy_m4_m4(ob->imat_ren, ob->imat);
- }
- }
-
- /* copy texture */
- tex= mtex->tex = BKE_texture_localize(cur_tex);
-
- /* update texture anims */
- BKE_animsys_evaluate_animdata(scene, &tex->id, tex->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
-
- /* update texture cache if required */
- if (tex->type==TEX_VOXELDATA) {
- cache_voxeldata(tex, (int)scene->r.cfra);
- }
- if (tex->type==TEX_POINTDENSITY) {
- /* set dummy values for render and do cache */
- Render dummy_re = {NULL};
- dummy_re.scene = scene;
- unit_m4(dummy_re.viewinv);
- unit_m4(dummy_re.viewmat);
- unit_m4(dummy_re.winmat);
- dummy_re.winx = dummy_re.winy = 128;
- cache_pointdensity(&dummy_re, tex->pd);
- }
-
- /* update image sequences and movies */
- if (tex->ima && BKE_image_is_animated(tex->ima)) {
- BKE_image_user_check_frame_calc(&tex->iuser, (int)scene->r.cfra, 0);
- }
- }
- }
- return mat;
-}
-
-/* free all duplicate data allocated by RE_sample_material_init() */
-void RE_sample_material_free(Material *mat)
-{
- int tex_nr;
-
- /* free textures */
- for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
- if (mat->septex & (1<<tex_nr)) continue;
- if (mat->mtex[tex_nr]) {
- MTex *mtex= mat->mtex[tex_nr];
-
- if (mtex->tex) {
- /* don't update user counts as we are freeing a duplicate */
- BKE_texture_free(mtex->tex);
- MEM_freeN(mtex->tex);
- mtex->tex = NULL;
- }
- }
- }
-
- /* don't update user counts as we are freeing a duplicate */
- BKE_material_free(mat);
- MEM_freeN(mat);
-}
-
-/*
- * Get material diffuse color and alpha (including linked textures) in given coordinates
- *
- * color,alpha : input/output color values
- * volume_co : sample coordinate in global space. used by volumetric materials
- * surface_co : sample surface coordinate in global space. used by "surface" materials
- * tri_index : surface tri index
- * orcoDm : orco state derived mesh
- */
-void RE_sample_material_color(
- Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
- int tri_index, DerivedMesh *orcoDm, Object *ob)
-{
- int v1, v2, v3;
- MVert *mvert;
- MLoop *mloop;
- const MLoopTri *mlooptri;
- float normal[3];
- ShadeInput shi = {NULL};
- Render re = {NULL};
-
- /* Get face data */
- mvert = orcoDm->getVertArray(orcoDm);
- mloop = orcoDm->getLoopArray(orcoDm);
- mlooptri = orcoDm->getLoopTriArray(orcoDm);
-
- if (!mvert || !mlooptri || !mat) {
- return;
- }
-
- v1 = mloop[mlooptri[tri_index].tri[0]].v;
- v2 = mloop[mlooptri[tri_index].tri[1]].v;
- v3 = mloop[mlooptri[tri_index].tri[2]].v;
- normal_tri_v3(normal, mvert[v1].co, mvert[v2].co, mvert[v3].co);
-
- /* generate shadeinput with data required */
- shi.mat = mat;
-
- /* fill shadeinput data depending on material type */
- if (mat->material_type == MA_TYPE_SURFACE) {
- /* global coordinates */
- copy_v3_v3(shi.gl, surface_co);
- /* object space coordinates */
- copy_v3_v3(shi.co, surface_co);
- mul_m4_v3(ob->imat, shi.co);
- /* orco coordinates */
- {
- float uv[2];
- float l;
- /* Get generated UV */
- textured_face_generate_uv(normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co, uv);
- l= 1.0f+uv[0]+uv[1];
-
- /* calculate generated coordinate */
- shi.lo[0]= l*mvert[v3].co[0]-uv[0]*mvert[v1].co[0]-uv[1]*mvert[v2].co[0];
- shi.lo[1]= l*mvert[v3].co[1]-uv[0]*mvert[v1].co[1]-uv[1]*mvert[v2].co[1];
- shi.lo[2]= l*mvert[v3].co[2]-uv[0]*mvert[v1].co[2]-uv[1]*mvert[v2].co[2];
- }
- /* uv coordinates */
- {
- const int layers = CustomData_number_of_layers(&orcoDm->loopData, CD_MLOOPUV);
- const int layer_index = CustomData_get_layer_index(&orcoDm->loopData, CD_MLOOPUV);
- int i;
-
- /* for every uv map set coords and name */
- for (i=0; i<layers; i++) {
- if (layer_index >= 0) {
- const float *uv1, *uv2, *uv3;
- const CustomData *data = &orcoDm->loopData;
- const MLoopUV *mloopuv = data->layers[layer_index + i].data;
- float uv[2];
- float l;
-
- /* point layer name from actual layer data */
- shi.uv[i].name = data->layers[i].name;
- /* Get generated coordinates to calculate UV from */
- textured_face_generate_uv(normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co, uv);
- /* Get UV mapping coordinate */
- l= 1.0f+uv[0]+uv[1];
-
- uv1 = mloopuv[mlooptri[tri_index].tri[0]].uv;
- uv2 = mloopuv[mlooptri[tri_index].tri[1]].uv;
- uv3 = mloopuv[mlooptri[tri_index].tri[2]].uv;
-
- shi.uv[i].uv[0]= -1.0f + 2.0f*(l*uv3[0]-uv[0]*uv1[0]-uv[1]*uv2[0]);
- shi.uv[i].uv[1]= -1.0f + 2.0f*(l*uv3[1]-uv[0]*uv1[1]-uv[1]*uv2[1]);
- shi.uv[i].uv[2]= 0.0f; /* texture.c assumes there are 3 coords */
- }
- }
- /* active uv map */
- shi.actuv = CustomData_get_active_layer_index(&orcoDm->loopData, CD_MLOOPUV) - layer_index;
- shi.totuv = layers;
- }
-
- /* apply initial values from material */
- shi.r = mat->r;
- shi.g = mat->g;
- shi.b = mat->b;
- shi.alpha = mat->alpha;
-
- /* do texture */
- do_material_tex(&shi, &re);
-
- /* apply result */
- color[0] = shi.r;
- color[1] = shi.g;
- color[2] = shi.b;
- *alpha = shi.alpha;
- }
- else if (mat->material_type == MA_TYPE_VOLUME) {
- ObjectInstanceRen obi = {NULL};
- obi.ob = ob;
- shi.obi = &obi;
- unit_m4(re.viewinv);
- copy_v3_v3(color, mat->vol.reflection_col);
- *alpha = mat->vol.density;
-
- /* do texture */
- do_volume_tex(&shi, volume_co, (MAP_TRANSMISSION_COL | MAP_REFLECTION_COL | MAP_DENSITY),
- color, alpha, &re);
- }
-}
-
-/* eof */
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
deleted file mode 100644
index cfbf199c94d..00000000000
--- a/source/blender/render/intern/source/rendercore.c
+++ /dev/null
@@ -1,2030 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributors: Hos, Robert Wenzlaff.
- * Contributors: 2004/2005/2006 Blender Foundation, full recode
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/rendercore.c
- * \ingroup render
- */
-
-
-/* system includes */
-#include <stdio.h>
-#include <math.h>
-#include <float.h>
-#include <string.h>
-#include <assert.h>
-
-/* External modules: */
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_rand.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_image_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-#include "DNA_group_types.h"
-
-/* local include */
-#include "renderpipeline.h"
-#include "render_result.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "occlusion.h"
-#include "pixelblending.h"
-#include "pixelshading.h"
-#include "shadbuf.h"
-#include "shading.h"
-#include "sss.h"
-#include "zbuf.h"
-
-/* own include */
-#include "rendercore.h"
-
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* x and y are current pixels in rect to be rendered */
-/* do not normalize! */
-void calc_view_vector(float view[3], float x, float y)
-{
-
- view[2]= -ABS(R.clipsta);
-
- if (R.r.mode & R_ORTHO) {
- view[0]= view[1]= 0.0f;
- }
- else {
-
- if (R.r.mode & R_PANORAMA) {
- x-= R.panodxp;
- }
-
- /* move x and y to real viewplane coords */
- x = (x / (float)R.winx);
- view[0] = R.viewplane.xmin + x * BLI_rctf_size_x(&R.viewplane);
-
- y = (y / (float)R.winy);
- view[1] = R.viewplane.ymin + y * BLI_rctf_size_y(&R.viewplane);
-
-// if (R.flag & R_SEC_FIELD) {
-// if (R.r.mode & R_ODDFIELD) view[1]= (y+R.ystart)*R.ycor;
-// else view[1]= (y+R.ystart+1.0)*R.ycor;
-// }
-// else view[1]= (y+R.ystart+R.bluroffsy+0.5)*R.ycor;
-
- if (R.r.mode & R_PANORAMA) {
- float u= view[0] + R.panodxv; float v= view[2];
- view[0]= R.panoco*u + R.panosi*v;
- view[2]= -R.panosi*u + R.panoco*v;
- }
- }
-}
-
-void calc_renderco_ortho(float co[3], float x, float y, int z)
-{
- /* x and y 3d coordinate can be derived from pixel coord and winmat */
- float fx= 2.0f/(R.winx*R.winmat[0][0]);
- float fy= 2.0f/(R.winy*R.winmat[1][1]);
- float zco;
-
- co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
- co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
-
- zco= ((float)z)/2147483647.0f;
- co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] );
-}
-
-void calc_renderco_zbuf(float co[3], const float view[3], int z)
-{
- float fac, zco;
-
- /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */
- zco= ((float)z)/2147483647.0f;
- co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] );
-
- fac= co[2]/view[2];
- co[0]= fac*view[0];
- co[1]= fac*view[1];
-}
-
-/* also used in zbuf.c and shadbuf.c */
-int count_mask(unsigned short mask)
-{
- if (R.samples)
- return (R.samples->cmask[mask & 255]+R.samples->cmask[mask>>8]);
- return 0;
-}
-
-static int calchalo_z(HaloRen *har, int zz)
-{
-
- if (har->type & HA_ONLYSKY) {
- if (zz < 0x7FFFFFF0) zz= - 0x7FFFFF; /* edge render messes zvalues */
- }
- else {
- zz= (zz>>8);
- }
- return zz;
-}
-
-
-
-static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, int od, float dist, float xn, float yn, PixStr *ps)
-{
- float col[4], accol[4], fac;
- int amount, amountm, zz, flarec, sample, fullsample, mask=0;
-
- fullsample= (totsample > 1);
- amount= 0;
- accol[0] = accol[1] = accol[2] = accol[3]= 0.0f;
- col[0] = col[1] = col[2] = col[3]= 0.0f;
- flarec= har->flarec;
-
- while (ps) {
- amountm= count_mask(ps->mask);
- amount+= amountm;
-
- zz= calchalo_z(har, ps->z);
- if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) {
- if (shadeHaloFloat(har, col, zz, dist, xn, yn, flarec)) {
- flarec= 0;
-
- if (fullsample) {
- for (sample=0; sample<totsample; sample++) {
- if (ps->mask & (1 << sample)) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- addalphaAddfacFloat(pass + od*4, col, har->add);
- }
- }
- }
- else {
- fac= ((float)amountm)/(float)R.osa;
- accol[0]+= fac*col[0];
- accol[1]+= fac*col[1];
- accol[2]+= fac*col[2];
- accol[3]+= fac*col[3];
- }
- }
- }
-
- mask |= ps->mask;
- ps= ps->next;
- }
-
- /* now do the sky sub-pixels */
- amount= R.osa-amount;
- if (amount) {
- if (shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec)) {
- if (!fullsample) {
- fac= ((float)amount)/(float)R.osa;
- accol[0]+= fac*col[0];
- accol[1]+= fac*col[1];
- accol[2]+= fac*col[2];
- accol[3]+= fac*col[3];
- }
- }
- }
-
- if (fullsample) {
- for (sample=0; sample<totsample; sample++) {
- if (!(mask & (1 << sample))) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- addalphaAddfacFloat(pass + od*4, col, har->add);
- }
- }
- }
- else {
- col[0]= accol[0];
- col[1]= accol[1];
- col[2]= accol[2];
- col[3]= accol[3];
-
- for (sample=0; sample<totsample; sample++) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- addalphaAddfacFloat(pass + od*4, col, har->add);
- }
- }
-}
-
-static void halo_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderLayer *rlpp[RE_MAX_OSA];
- HaloRen *har;
- rcti disprect= pa->disprect, testrect= pa->disprect;
- float dist, xsq, ysq, xn, yn;
- float col[4];
- intptr_t *rd= NULL;
- int a, *rz, zz, y, sample, totsample, od;
- short minx, maxx, miny, maxy, x;
- unsigned int lay= rl->lay;
-
- /* we don't render halos in the cropped area, gives errors in flare counter */
- if (pa->crop) {
- testrect.xmin+= pa->crop;
- testrect.xmax-= pa->crop;
- testrect.ymin+= pa->crop;
- testrect.ymax-= pa->crop;
- }
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- for (a=0; a<R.tothalo; a++) {
- har= R.sortedhalos[a];
-
- /* layer test, clip halo with y */
- if ((har->lay & lay) == 0) {
- /* pass */
- }
- else if (testrect.ymin > har->maxy) {
- /* pass */
- }
- else if (testrect.ymax < har->miny) {
- /* pass */
- }
- else {
-
- minx= floor(har->xs-har->rad);
- maxx= ceil(har->xs+har->rad);
-
- if (testrect.xmin > maxx) {
- /* pass */
- }
- else if (testrect.xmax < minx) {
- /* pass */
- }
- else {
-
- minx = max_ii(minx, testrect.xmin);
- maxx = min_ii(maxx, testrect.xmax);
-
- miny = max_ii(har->miny, testrect.ymin);
- maxy = min_ii(har->maxy, testrect.ymax);
-
- for (y=miny; y<maxy; y++) {
- int rectofs= (y-disprect.ymin)*pa->rectx + (minx - disprect.xmin);
- rz= pa->rectz + rectofs;
- od= rectofs;
-
- if (pa->rectdaps)
- rd= pa->rectdaps + rectofs;
-
- yn= (y-har->ys)*R.ycor;
- ysq= yn*yn;
-
- for (x=minx; x<maxx; x++, rz++, od++) {
- xn= x- har->xs;
- xsq= xn*xn;
- dist= xsq+ysq;
- if (dist<har->radsq) {
- if (rd && *rd) {
- halo_pixelstruct(har, rlpp, totsample, od, dist, xn, yn, (PixStr *)*rd);
- }
- else {
- zz= calchalo_z(har, *rz);
- if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) {
- if (shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) {
- for (sample=0; sample<totsample; sample++) {
- float *rect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- addalphaAddfacFloat(rect + od*4, col, har->add);
- }
- }
- }
- }
- }
- if (rd) rd++;
- }
- }
- }
- }
- if (R.test_break(R.tbh) ) break;
- }
-}
-
-static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderLayer *rlpp[RE_MAX_OSA];
- ShadeInput shi;
- float *pass;
- float fac, col[4];
- intptr_t *rd= pa->rectdaps;
- const int *rz= pa->rectz;
- int x, y, sample, totsample, fullsample, od;
-
- totsample= get_sample_layers(pa, rl, rlpp);
- fullsample= (totsample > 1);
-
- shade_input_initialize(&shi, pa, rl, 0); /* this zero's ShadeInput for us */
-
- for (od=0, y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, od++) {
-
- calc_view_vector(shi.view, x, y);
-
- if (rd && *rd) {
- PixStr *ps= (PixStr *)*rd;
- int count, totsamp= 0, mask= 0;
-
- while (ps) {
- if (R.r.mode & R_ORTHO)
- calc_renderco_ortho(shi.co, (float)x, (float)y, ps->z);
- else
- calc_renderco_zbuf(shi.co, shi.view, ps->z);
-
- totsamp+= count= count_mask(ps->mask);
- mask |= ps->mask;
-
- col[0]= col[1]= col[2]= col[3]= 0.0f;
- renderspothalo(&shi, col, 1.0f);
-
- if (fullsample) {
- for (sample=0; sample<totsample; sample++) {
- if (ps->mask & (1 << sample)) {
- pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= col[0];
- pass[1]+= col[1];
- pass[2]+= col[2];
- pass[3]+= col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
- }
- }
- else {
- fac= ((float)count)/(float)R.osa;
- pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= fac*col[0];
- pass[1]+= fac*col[1];
- pass[2]+= fac*col[2];
- pass[3]+= fac*col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
-
- ps= ps->next;
- }
-
- if (totsamp<R.osa) {
- shi.co[2]= 0.0f;
-
- col[0]= col[1]= col[2]= col[3]= 0.0f;
- renderspothalo(&shi, col, 1.0f);
-
- if (fullsample) {
- for (sample=0; sample<totsample; sample++) {
- if (!(mask & (1 << sample))) {
-
- pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= col[0];
- pass[1]+= col[1];
- pass[2]+= col[2];
- pass[3]+= col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
- }
- }
- else {
- fac= ((float)R.osa-totsamp)/(float)R.osa;
- pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= fac*col[0];
- pass[1]+= fac*col[1];
- pass[2]+= fac*col[2];
- pass[3]+= fac*col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
- }
- }
- else {
- if (R.r.mode & R_ORTHO)
- calc_renderco_ortho(shi.co, (float)x, (float)y, *rz);
- else
- calc_renderco_zbuf(shi.co, shi.view, *rz);
-
- col[0]= col[1]= col[2]= col[3]= 0.0f;
- renderspothalo(&shi, col, 1.0f);
-
- for (sample=0; sample<totsample; sample++) {
- pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- pass += od * 4;
- pass[0]+= col[0];
- pass[1]+= col[1];
- pass[2]+= col[2];
- pass[3]+= col[3];
- if (pass[3]>1.0f) pass[3]= 1.0f;
- }
- }
-
- if (rd) rd++;
- }
- if (y&1)
- if (R.test_break(R.tbh)) break;
- }
-}
-
-
-/* ********************* MAINLOOPS ******************** */
-
-/* osa version */
-static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, ShadeInput *shi, ShadeResult *shr)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *fp, *col= NULL;
- int pixsize= 3;
-
- if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
- add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx);
- }
- else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
- fp = rpass->rect + offset;
- *fp = shr->z;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
- col = shr->col;
- pixsize = 4;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
- col = shr->emit;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
- col = shr->diff;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
- col = shr->spec;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
- col = shr->shad;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
- col = shr->ao;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
- col = shr->env;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
- col = shr->indirect;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
- col = shr->refl;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
- col = shr->refr;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
- col = shr->nor;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_UV)) {
- /* box filter only, gauss will screwup UV too much */
- if (shi->totuv) {
- float mult = (float)count_mask(curmask)/(float)R.osa;
- fp = rpass->rect + 3*offset;
- fp[0]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[0]);
- fp[1]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[1]);
- fp[2]+= mult;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
- /* no filter */
- if (shi->vlr) {
- fp = rpass->rect + offset;
- if (*fp==0.0f)
- *fp = (float)shi->obr->ob->index;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
- /* no filter */
- if (shi->vlr) {
- fp = rpass->rect + offset;
- if (*fp==0.0f)
- *fp = (float)shi->mat->index;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
- /* */
- col = &shr->mist;
- pixsize = 1;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
- /* add minimum speed in pixel, no filter */
- fp = rpass->rect + 4*offset;
- if ( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
- fp[0] = shr->winspeed[0];
- fp[1] = shr->winspeed[1];
- }
- if ( (ABS(shr->winspeed[2]) + ABS(shr->winspeed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
- fp[2] = shr->winspeed[2];
- fp[3] = shr->winspeed[3];
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) {
- /* */
- col = shr->rayhits;
- pixsize= 4;
- }
-
- if (col) {
- fp= rpass->rect + pixsize*offset;
- add_filt_fmask_pixsize(curmask, col, fp, rectx, pixsize);
- }
- }
-}
-
-/* non-osa version */
-static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult *shr)
-{
- RenderPass *rpass;
- float *fp;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *col= NULL, uvcol[3];
- int a, pixsize= 3;
-
- if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
- /* copy combined to use for preview */
- copy_v4_v4(rpass->rect + 4*offset, shr->combined);
- }
- else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
- fp = rpass->rect + offset;
- *fp = shr->z;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
- col = shr->col;
- pixsize = 4;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
- col = shr->emit;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
- col = shr->diff;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
- col = shr->spec;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
- col = shr->shad;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
- col = shr->ao;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
- col = shr->env;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
- col = shr->indirect;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
- col = shr->refl;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
- col = shr->refr;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
- col = shr->nor;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_UV)) {
- if (shi->totuv) {
- uvcol[0] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[0];
- uvcol[1] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[1];
- uvcol[2] = 1.0f;
- col = uvcol;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
- col = shr->winspeed;
- pixsize = 4;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
- if (shi->vlr) {
- fp = rpass->rect + offset;
- *fp = (float)shi->obr->ob->index;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
- if (shi->vlr) {
- fp = rpass->rect + offset;
- *fp = (float)shi->mat->index;
- }
- }
- else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
- fp = rpass->rect + offset;
- *fp = shr->mist;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) {
- col = shr->rayhits;
- pixsize = 4;
- }
-
- if (col) {
- fp = rpass->rect + pixsize*offset;
- for (a=0; a<pixsize; a++)
- fp[a] = col[a];
- }
- }
-}
-
-int get_sample_layers(RenderPart *pa, RenderLayer *rl, RenderLayer **rlpp)
-{
-
- if (pa->fullresult.first) {
- int sample, nr= BLI_findindex(&pa->result->layers, rl);
-
- for (sample=0; sample<R.osa; sample++) {
- RenderResult *rr= BLI_findlink(&pa->fullresult, sample);
-
- rlpp[sample]= BLI_findlink(&rr->layers, nr);
- }
- return R.osa;
- }
- else {
- rlpp[0]= rl;
- return 1;
- }
-}
-
-
-/* only do sky, is default in the solid layer (shade_tile) btw */
-static void sky_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderLayer *rlpp[RE_MAX_OSA];
- int x, y, od=0, totsample;
-
- if (R.r.alphamode!=R_ADDSKY)
- return;
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od+=4) {
- float col[4];
- int sample;
- bool done = false;
-
- for (sample= 0; sample<totsample; sample++) {
- float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
- pass += od;
-
- if (pass[3]<1.0f) {
-
- if (done==0) {
- shadeSkyPixel(col, x, y, pa->thread);
- done = true;
- }
-
- if (pass[3]==0.0f) {
- copy_v4_v4(pass, col);
- pass[3] = 1.0f;
- }
- else {
- addAlphaUnderFloat(pass, col);
- pass[3] = 1.0f;
- }
- }
- }
- }
-
- if (y&1)
- if (R.test_break(R.tbh)) break;
- }
-}
-
-static void atm_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderPass *zpass;
- GroupObject *go;
- LampRen *lar;
- RenderLayer *rlpp[RE_MAX_OSA];
- int totsample;
- int x, y, od= 0;
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- /* check that z pass is enabled */
- if (pa->rectz==NULL) return;
- for (zpass= rl->passes.first; zpass; zpass= zpass->next)
- if (STREQ(zpass->name, RE_PASSNAME_Z))
- break;
-
- if (zpass==NULL) return;
-
- /* check for at least one sun lamp that its atmosphere flag is enabled */
- for (go=R.lights.first; go; go= go->next) {
- lar= go->lampren;
- if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_AP))
- break;
- }
- /* do nothign and return if there is no sun lamp */
- if (go==NULL)
- return;
-
- /* for each x,y and each sample, and each sun lamp*/
- for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od++) {
- int sample;
-
- for (sample=0; sample<totsample; sample++) {
- const float *zrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_Z, R.viewname) + od;
- float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname) + 4*od;
- float rgb[3] = {0};
- bool done = false;
-
- for (go=R.lights.first; go; go= go->next) {
-
-
- lar= go->lampren;
- if (lar->type==LA_SUN && lar->sunsky) {
-
- /* if it's sky continue and don't apply atmosphere effect on it */
- if (*zrect >= 9.9e10f || rgbrect[3]==0.0f) {
- continue;
- }
-
- if ((lar->sunsky->effect_type & LA_SUN_EFFECT_AP)) {
- float tmp_rgb[3];
-
- /* skip if worldspace lamp vector is below horizon */
- if (go->ob->obmat[2][2] < 0.f) {
- continue;
- }
-
- copy_v3_v3(tmp_rgb, rgbrect);
- if (rgbrect[3]!=1.0f) { /* de-premul */
- mul_v3_fl(tmp_rgb, 1.0f/rgbrect[3]);
- }
- shadeAtmPixel(lar->sunsky, tmp_rgb, x, y, *zrect);
- if (rgbrect[3]!=1.0f) { /* premul */
- mul_v3_fl(tmp_rgb, rgbrect[3]);
- }
-
- if (done==0) {
- copy_v3_v3(rgb, tmp_rgb);
- done = true;
- }
- else {
- rgb[0] = 0.5f*rgb[0] + 0.5f*tmp_rgb[0];
- rgb[1] = 0.5f*rgb[1] + 0.5f*tmp_rgb[1];
- rgb[2] = 0.5f*rgb[2] + 0.5f*tmp_rgb[2];
- }
- }
- }
- }
-
- /* if at least for one sun lamp aerial perspective was applied*/
- if (done) {
- copy_v3_v3(rgbrect, rgb);
- }
- }
- }
- }
-}
-
-static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
-{
- RenderResult *rr= pa->result;
- ShadeSample ssamp;
- intptr_t *rd, *rectdaps= pa->rectdaps;
- int samp;
- int x, y, seed, crop=0, offs=0, od;
-
- if (R.test_break(R.tbh)) return;
-
- /* irregular shadowb buffer creation */
- if (R.r.mode & R_SHADOW)
- ISB_create(pa, NULL);
-
- /* we set per pixel a fixed seed, for random AO and shadow samples */
- seed= pa->rectx*pa->disprect.ymin;
-
- /* general shader info, passes */
- shade_sample_initialize(&ssamp, pa, rl);
-
- /* occlusion caching */
- if (R.occlusiontree)
- cache_occ_samples(&R, pa, &ssamp);
-
- /* filtered render, for now we assume only 1 filter size */
- if (pa->crop) {
- crop= 1;
- rectdaps+= pa->rectx + 1;
- offs= pa->rectx + 1;
- }
-
- /* scanline updates have to be 2 lines behind */
- rr->renrect.ymin = 0;
- rr->renrect.ymax = -2*crop;
- rr->renlay= rl;
-
- for (y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
- rd= rectdaps;
- od= offs;
-
- for (x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, rd++, od++) {
- BLI_thread_srandom(pa->thread, seed++);
-
- if (*rd) {
- if (shade_samples(&ssamp, (PixStr *)(*rd), x, y)) {
-
- /* multisample buffers or filtered mask filling? */
- if (pa->fullresult.first) {
- int a;
- for (samp=0; samp<ssamp.tot; samp++) {
- int smask= ssamp.shi[samp].mask;
- for (a=0; a<R.osa; a++) {
- int mask= 1<<a;
- if (smask & mask)
- add_passes(ssamp.rlpp[a], od, &ssamp.shi[samp], &ssamp.shr[samp]);
- }
- }
- }
- else {
- for (samp=0; samp<ssamp.tot; samp++)
- add_filt_passes(rl, ssamp.shi[samp].mask, pa->rectx, od, &ssamp.shi[samp], &ssamp.shr[samp]);
- }
- }
- }
- }
-
- rectdaps+= pa->rectx;
- offs+= pa->rectx;
-
- if (y&1) if (R.test_break(R.tbh)) break;
- }
-
- /* disable scanline updating */
- rr->renlay= NULL;
-
- if (R.r.mode & R_SHADOW)
- ISB_free(pa);
-
- if (R.occlusiontree)
- free_occ_samples(&R, pa);
-}
-
-/* ************* pixel struct ******** */
-
-
-static PixStrMain *addpsmain(ListBase *lb)
-{
- PixStrMain *psm;
-
- psm= (PixStrMain *)MEM_mallocN(sizeof(PixStrMain), "pixstrMain");
- BLI_addtail(lb, psm);
-
- psm->ps= (PixStr *)MEM_mallocN(4096*sizeof(PixStr), "pixstr");
- psm->counter= 0;
-
- return psm;
-}
-
-static void freeps(ListBase *lb)
-{
- PixStrMain *psm, *psmnext;
-
- for (psm= lb->first; psm; psm= psmnext) {
- psmnext= psm->next;
- if (psm->ps)
- MEM_freeN(psm->ps);
- MEM_freeN(psm);
- }
- BLI_listbase_clear(lb);
-}
-
-static void addps(ListBase *lb, intptr_t *rd, int obi, int facenr, int z, int maskz, unsigned short mask)
-{
- PixStrMain *psm;
- PixStr *ps, *last= NULL;
-
- if (*rd) {
- ps= (PixStr *)(*rd);
-
- while (ps) {
- if ( ps->obi == obi && ps->facenr == facenr ) {
- ps->mask |= mask;
- return;
- }
- last= ps;
- ps= ps->next;
- }
- }
-
- /* make new PS (pixel struct) */
- psm= lb->last;
-
- if (psm->counter==4095)
- psm= addpsmain(lb);
-
- ps= psm->ps + psm->counter++;
-
- if (last) last->next= ps;
- else *rd= (intptr_t)ps;
-
- ps->next= NULL;
- ps->obi= obi;
- ps->facenr= facenr;
- ps->z= z;
- ps->maskz= maskz;
- ps->mask = mask;
- ps->shadfac= 0;
-}
-
-static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect)
-{
- float addcol[4];
- int pix;
-
- if (arect==NULL)
- return;
-
- for (pix= pa->rectx*pa->recty; pix>0; pix--, arect++, rectf+=4) {
- if (*arect != 0.0f) {
- addcol[0]= *arect * R.r.edgeR;
- addcol[1]= *arect * R.r.edgeG;
- addcol[2]= *arect * R.r.edgeB;
- addcol[3]= *arect;
- addAlphaOverFloat(rectf, addcol);
- }
- }
-}
-
-/* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
-static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl)
-{
- RenderLayer *rlpp[RE_MAX_OSA];
- int y, sample, totsample;
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- /* not for full sample, there we clamp after compositing */
- if (totsample > 1)
- return;
-
- for (sample= 0; sample<totsample; sample++) {
- float *rectf = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
-
- for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
- rectf[0] = MAX2(rectf[0], 0.0f);
- rectf[1] = MAX2(rectf[1], 0.0f);
- rectf[2] = MAX2(rectf[2], 0.0f);
- CLAMP(rectf[3], 0.0f, 1.0f);
- }
- }
-}
-
-/* adds only alpha values */
-static void edge_enhance_tile(RenderPart *pa, float *rectf, int *rectz)
-{
- /* use zbuffer to define edges, add it to the image */
- int y, x, col, *rz, *rz1, *rz2, *rz3;
- int zval1, zval2, zval3;
- float *rf;
-
- /* shift values in zbuffer 4 to the right (anti overflows), for filter we need multiplying with 12 max */
- rz= rectz;
- if (rz==NULL) return;
-
- for (y=0; y<pa->recty; y++)
- for (x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4;
-
- rz1= rectz;
- rz2= rz1+pa->rectx;
- rz3= rz2+pa->rectx;
-
- rf= rectf+pa->rectx+1;
-
- for (y=0; y<pa->recty-2; y++) {
- for (x=0; x<pa->rectx-2; x++, rz1++, rz2++, rz3++, rf++) {
-
- /* prevent overflow with sky z values */
- zval1= rz1[0] + 2*rz1[1] + rz1[2];
- zval2= 2*rz2[0] + 2*rz2[2];
- zval3= rz3[0] + 2*rz3[1] + rz3[2];
-
- col= ( 4*rz2[1] - (zval1 + zval2 + zval3)/3 );
- if (col<0) col= -col;
-
- col >>= 5;
- if (col > (1<<16)) col= (1<<16);
- else col= (R.r.edgeint*col)>>8;
-
- if (col>0) {
- float fcol;
-
- if (col>255) fcol= 1.0f;
- else fcol= (float)col/255.0f;
-
- if (R.osa)
- *rf+= fcol/(float)R.osa;
- else
- *rf= fcol;
- }
- }
- rz1+= 2;
- rz2+= 2;
- rz3+= 2;
- rf+= 2;
- }
-
- /* shift back zbuf values, we might need it still */
- rz= rectz;
- for (y=0; y<pa->recty; y++)
- for (x=0; x<pa->rectx; x++, rz++) (*rz)<<= 4;
-
-}
-
-static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
-{
- /* for all pixels with max speed, set to zero */
- RenderLayer *rlpp[RE_MAX_OSA];
- float *fp;
- int a, sample, totsample;
-
- totsample= get_sample_layers(pa, rl, rlpp);
-
- for (sample= 0; sample<totsample; sample++) {
- fp= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_VECTOR, R.viewname);
- if (fp==NULL) break;
-
- for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--)
- if (fp[a] == PASS_VECTOR_MAX) fp[a]= 0.0f;
- }
-}
-
-static unsigned short *make_solid_mask(RenderPart *pa)
-{
- intptr_t *rd= pa->rectdaps;
- unsigned short *solidmask, *sp;
- int x;
-
- if (rd==NULL) return NULL;
-
- sp=solidmask= MEM_mallocN(sizeof(short)*pa->rectx*pa->recty, "solidmask");
-
- for (x=pa->rectx*pa->recty; x>0; x--, rd++, sp++) {
- if (*rd) {
- PixStr *ps= (PixStr *)*rd;
-
- *sp= ps->mask;
- for (ps= ps->next; ps; ps= ps->next)
- *sp |= ps->mask;
- }
- else
- *sp= 0;
- }
-
- return solidmask;
-}
-
-static void addAlphaOverFloatMask(float *dest, float *source, unsigned short dmask, unsigned short smask)
-{
- unsigned short shared= dmask & smask;
- float mul= 1.0f - source[3];
-
- if (shared) { /* overlapping masks */
-
- /* masks differ, we make a mixture of 'add' and 'over' */
- if (shared!=dmask) {
- float shared_bits= (float)count_mask(shared); /* alpha over */
- float tot_bits= (float)count_mask(smask|dmask); /* alpha add */
-
- float add= (tot_bits - shared_bits)/tot_bits; /* add level */
- mul= add + (1.0f-add)*mul;
- }
- }
- else if (dmask && smask) {
- /* works for premul only, of course */
- dest[0]+= source[0];
- dest[1]+= source[1];
- dest[2]+= source[2];
- dest[3]+= source[3];
-
- return;
- }
-
- 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];
-}
-
-typedef struct ZbufSolidData {
- RenderLayer *rl;
- ListBase *psmlist;
- float *edgerect;
-} ZbufSolidData;
-
-static void make_pixelstructs(RenderPart *pa, ZSpan *zspan, int sample, void *data)
-{
- ZbufSolidData *sdata = (ZbufSolidData *)data;
- ListBase *lb= sdata->psmlist;
- intptr_t *rd= pa->rectdaps;
- const int *ro= zspan->recto;
- const int *rp= zspan->rectp;
- const int *rz= zspan->rectz;
- const int *rm= zspan->rectmask;
- int x, y;
- int mask= 1<<sample;
-
- for (y=0; y<pa->recty; y++) {
- for (x=0; x<pa->rectx; x++, rd++, rp++, ro++, rz++, rm++) {
- if (*rp) {
- addps(lb, rd, *ro, *rp, *rz, (zspan->rectmask)? *rm: 0, mask);
- }
- }
- }
-
- if (sdata->rl->layflag & SCE_LAY_EDGE)
- if (R.r.mode & R_EDGE)
- edge_enhance_tile(pa, sdata->edgerect, zspan->rectz);
-}
-
-/* main call for shading Delta Accum, for OSA */
-/* supposed to be fully threadable! */
-void zbufshadeDA_tile(RenderPart *pa)
-{
- RenderResult *rr= pa->result;
- RenderLayer *rl;
- ListBase psmlist= {NULL, NULL};
- float *edgerect= NULL;
-
- /* allocate the necessary buffers */
- /* zbuffer inits these rects */
- pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
- pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
- pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
- for (rl= rr->layers.first; rl; rl= rl->next) {
- float *rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
-
- if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
- pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
-
- /* initialize pixelstructs and edge buffer */
- addpsmain(&psmlist);
- pa->rectdaps= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "zbufDArectd");
-
- if (rl->layflag & SCE_LAY_EDGE)
- if (R.r.mode & R_EDGE)
- edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge");
-
- /* always fill visibility */
- for (pa->sample=0; pa->sample<R.osa; pa->sample+=4) {
- ZbufSolidData sdata;
-
- sdata.rl= rl;
- sdata.psmlist= &psmlist;
- sdata.edgerect= edgerect;
- zbuffer_solid(pa, rl, make_pixelstructs, &sdata);
- if (R.test_break(R.tbh)) break;
- }
-
- /* shades solid */
- if (rl->layflag & SCE_LAY_SOLID)
- shadeDA_tile(pa, rl);
-
- /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
- if (R.flag & R_LAMPHALO)
- if (rl->layflag & SCE_LAY_HALO)
- lamphalo_tile(pa, rl);
-
- /* halo before ztra, because ztra fills in zbuffer now */
- if (R.flag & R_HALO)
- if (rl->layflag & SCE_LAY_HALO)
- halo_tile(pa, rl);
-
- /* transp layer */
- if (R.flag & R_ZTRA || R.totstrand) {
- if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
- if (pa->fullresult.first) {
- zbuffer_transp_shade(pa, rl, rect, &psmlist);
- }
- else {
- unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */
-
- /* allocate, but not free here, for asynchronous display of this rect in main thread */
- rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
-
- /* swap for live updates, and it is used in zbuf.c!!! */
- SWAP(float *, rl->acolrect, rect);
- ztramask = zbuffer_transp_shade(pa, rl, rect, &psmlist);
- SWAP(float *, rl->acolrect, rect);
-
- /* zbuffer transp only returns ztramask if there's solid rendered */
- if (ztramask)
- solidmask= make_solid_mask(pa);
-
- if (ztramask && solidmask) {
- unsigned short *sps= solidmask, *spz= ztramask;
- unsigned short fullmask= (1<<R.osa)-1;
- float *fcol= rect;
- float *acol= rl->acolrect;
- int x;
-
- for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) {
- if (*sps == fullmask)
- addAlphaOverFloat(fcol, acol);
- else
- addAlphaOverFloatMask(fcol, acol, *sps, *spz);
- }
- }
- else {
- float *fcol= rect;
- float *acol= rl->acolrect;
- int x;
- for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
- addAlphaOverFloat(fcol, acol);
- }
- }
- if (solidmask) MEM_freeN(solidmask);
- if (ztramask) MEM_freeN(ztramask);
- }
- }
- }
-
- /* sun/sky */
- if (rl->layflag & SCE_LAY_SKY)
- atm_tile(pa, rl);
-
- /* sky before edge */
- if (rl->layflag & SCE_LAY_SKY)
- sky_tile(pa, rl);
-
- /* extra layers */
- if (rl->layflag & SCE_LAY_EDGE)
- if (R.r.mode & R_EDGE)
- edge_enhance_add(pa, rect, edgerect);
-
- if (rl->passflag & SCE_PASS_VECTOR)
- reset_sky_speed(pa, rl);
-
- /* clamp alpha to 0..1 range, can go outside due to filter */
- clamp_alpha_rgb_range(pa, rl);
-
- /* free stuff within loop! */
- MEM_freeN(pa->rectdaps); pa->rectdaps= NULL;
- freeps(&psmlist);
-
- if (edgerect) MEM_freeN(edgerect);
- edgerect= NULL;
-
- if (pa->rectmask) {
- MEM_freeN(pa->rectmask);
- pa->rectmask= NULL;
- }
- }
-
- /* free all */
- MEM_freeN(pa->recto); pa->recto= NULL;
- MEM_freeN(pa->rectp); pa->rectp= NULL;
- MEM_freeN(pa->rectz); pa->rectz= NULL;
-
- /* display active layer */
- rr->renrect.ymin=rr->renrect.ymax = 0;
- rr->renlay= render_get_active_layer(&R, rr);
-}
-
-
-/* ------------------------------------------------------------------------ */
-
-/* non OSA case, full tile render */
-/* supposed to be fully threadable! */
-void zbufshade_tile(RenderPart *pa)
-{
- ShadeSample ssamp;
- RenderResult *rr= pa->result;
- RenderLayer *rl;
- PixStr ps;
- float *edgerect= NULL;
-
- /* fake pixel struct, to comply to osa render */
- ps.next= NULL;
- ps.mask= 0xFFFF;
-
- /* zbuffer code clears/inits rects */
- pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
- pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
- pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
-
- for (rl= rr->layers.first; rl; rl= rl->next) {
- float *rect= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
- if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
- pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
-
- /* general shader info, passes */
- shade_sample_initialize(&ssamp, pa, rl);
-
- zbuffer_solid(pa, rl, NULL, NULL);
-
- if (!R.test_break(R.tbh)) { /* NOTE: this if () is not consistent */
-
- /* edges only for solid part, ztransp doesn't support it yet anti-aliased */
- if (rl->layflag & SCE_LAY_EDGE) {
- if (R.r.mode & R_EDGE) {
- edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge");
- edge_enhance_tile(pa, edgerect, pa->rectz);
- }
- }
-
- /* initialize scanline updates for main thread */
- rr->renrect.ymin = 0;
- rr->renlay= rl;
-
- if (rl->layflag & SCE_LAY_SOLID) {
- const float *fcol = rect;
- const int *ro= pa->recto, *rp= pa->rectp, *rz= pa->rectz;
- int x, y, offs=0, seed;
-
- /* we set per pixel a fixed seed, for random AO and shadow samples */
- seed= pa->rectx*pa->disprect.ymin;
-
- /* irregular shadowb buffer creation */
- if (R.r.mode & R_SHADOW)
- ISB_create(pa, NULL);
-
- if (R.occlusiontree)
- cache_occ_samples(&R, pa, &ssamp);
-
- for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, ro++, rz++, rp++, fcol+=4, offs++) {
- /* per pixel fixed seed */
- BLI_thread_srandom(pa->thread, seed++);
-
- if (*rp) {
- ps.obi= *ro;
- ps.facenr= *rp;
- ps.z= *rz;
- if (shade_samples(&ssamp, &ps, x, y)) {
- /* combined and passes */
- add_passes(rl, offs, ssamp.shi, ssamp.shr);
- }
- }
- }
- if (y&1)
- if (R.test_break(R.tbh)) break;
- }
-
- if (R.occlusiontree)
- free_occ_samples(&R, pa);
-
- if (R.r.mode & R_SHADOW)
- ISB_free(pa);
- }
-
- /* disable scanline updating */
- rr->renlay= NULL;
- }
-
- /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
- if (R.flag & R_LAMPHALO)
- if (rl->layflag & SCE_LAY_HALO)
- lamphalo_tile(pa, rl);
-
- /* halo before ztra, because ztra fills in zbuffer now */
- if (R.flag & R_HALO)
- if (rl->layflag & SCE_LAY_HALO)
- halo_tile(pa, rl);
-
- if (R.flag & R_ZTRA || R.totstrand) {
- if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
- float *fcol, *acol;
- int x;
-
- /* allocate, but not free here, for asynchronous display of this rect in main thread */
- rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
-
- /* swap for live updates */
- SWAP(float *, rl->acolrect, rect);
- zbuffer_transp_shade(pa, rl, rect, NULL);
- SWAP(float *, rl->acolrect, rect);
-
- fcol= rect; acol= rl->acolrect;
- for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
- addAlphaOverFloat(fcol, acol);
- }
- }
- }
-
- /* sun/sky */
- if (rl->layflag & SCE_LAY_SKY)
- atm_tile(pa, rl);
-
- /* sky before edge */
- if (rl->layflag & SCE_LAY_SKY)
- sky_tile(pa, rl);
-
- if (!R.test_break(R.tbh)) {
- if (rl->layflag & SCE_LAY_EDGE)
- if (R.r.mode & R_EDGE)
- edge_enhance_add(pa, rect, edgerect);
- }
-
- if (rl->passflag & SCE_PASS_VECTOR)
- reset_sky_speed(pa, rl);
-
- if (edgerect) MEM_freeN(edgerect);
- edgerect= NULL;
-
- if (pa->rectmask) {
- MEM_freeN(pa->rectmask);
- pa->rectmask= NULL;
- }
- }
-
- /* display active layer */
- rr->renrect.ymin=rr->renrect.ymax = 0;
- rr->renlay= render_get_active_layer(&R, rr);
-
- MEM_freeN(pa->recto); pa->recto= NULL;
- MEM_freeN(pa->rectp); pa->rectp= NULL;
- MEM_freeN(pa->rectz); pa->rectz= NULL;
-}
-
-/* SSS preprocess tile render, fully threadable */
-typedef struct ZBufSSSHandle {
- RenderPart *pa;
- ListBase psmlist;
- int totps;
-} ZBufSSSHandle;
-
-static void addps_sss(void *cb_handle, int obi, int facenr, int x, int y, int z)
-{
- ZBufSSSHandle *handle = cb_handle;
- RenderPart *pa= handle->pa;
-
- /* extra border for filter gives double samples on part edges,
- * don't use those */
- if (x<pa->crop || x>=pa->rectx-pa->crop)
- return;
- if (y<pa->crop || y>=pa->recty-pa->crop)
- return;
-
- if (pa->rectall) {
- intptr_t *rs= pa->rectall + pa->rectx*y + x;
-
- addps(&handle->psmlist, rs, obi, facenr, z, 0, 0);
- handle->totps++;
- }
- if (pa->rectz) {
- int *rz= pa->rectz + pa->rectx*y + x;
- int *rp= pa->rectp + pa->rectx*y + x;
- int *ro= pa->recto + pa->rectx*y + x;
-
- if (z < *rz) {
- if (*rp == 0)
- handle->totps++;
- *rz= z;
- *rp= facenr;
- *ro= obi;
- }
- }
- if (pa->rectbackz) {
- int *rz= pa->rectbackz + pa->rectx*y + x;
- int *rp= pa->rectbackp + pa->rectx*y + x;
- int *ro= pa->rectbacko + pa->rectx*y + x;
-
- if (z >= *rz) {
- if (*rp == 0)
- handle->totps++;
- *rz= z;
- *rp= facenr;
- *ro= obi;
- }
- }
-}
-
-static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRen *obi, VlakRen *vlr, int quad, float x, float y, float z, float *co, float color[3], float *area)
-{
- ShadeInput *shi= ssamp->shi;
- ShadeResult shr;
- float /* texfac,*/ /* UNUSED */ orthoarea, nor[3], alpha, sx, sy;
-
- /* cache for shadow */
- shi->samplenr= R.shadowsamplenr[shi->thread]++;
-
- if (quad)
- shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
-
- /* center pixel */
- sx = x + 0.5f;
- sy = y + 0.5f;
-
- /* we estimate the area here using shi->dxco and shi->dyco. we need to
- * enabled shi->osatex these are filled. we compute two areas, one with
- * the normal pointed at the camera and one with the original normal, and
- * then clamp to avoid a too large contribution from a single pixel */
- shi->osatex= 1;
-
- copy_v3_v3(nor, shi->facenor);
- calc_view_vector(shi->facenor, sx, sy);
- normalize_v3(shi->facenor);
- shade_input_set_viewco(shi, x, y, sx, sy, z);
- orthoarea= len_v3(shi->dxco)*len_v3(shi->dyco);
-
- copy_v3_v3(shi->facenor, nor);
- shade_input_set_viewco(shi, x, y, sx, sy, z);
- *area = min_ff(len_v3(shi->dxco) * len_v3(shi->dyco), 2.0f * orthoarea);
-
- shade_input_set_uv(shi);
- shade_input_set_normals(shi);
-
- /* we don't want flipped normals, they screw up back scattering */
- if (shi->flippednor)
- shade_input_flip_normals(shi);
-
- /* not a pretty solution, but fixes common cases */
- if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
- negate_v3(shi->vn);
- negate_v3(shi->vno);
- negate_v3(shi->nmapnorm);
- }
-
- /* if nodetree, use the material that we are currently preprocessing
- * instead of the node material */
- if (shi->mat->nodetree && shi->mat->use_nodes)
- shi->mat= mat;
-
- /* init material vars */
- shade_input_init_material(shi);
-
- /* render */
- shade_input_set_shade_texco(shi);
-
- shade_samples_do_AO(ssamp);
- shade_material_loop(shi, &shr);
-
- copy_v3_v3(co, shi->co);
- copy_v3_v3(color, shr.combined);
-
- /* texture blending */
- /* texfac= shi->mat->sss_texfac; */ /* UNUSED */
-
- alpha= shr.combined[3];
- *area *= alpha;
-}
-
-static void zbufshade_sss_free(RenderPart *pa)
-{
-#if 0
- MEM_freeN(pa->rectall); pa->rectall= NULL;
- freeps(&handle.psmlist);
-#else
- MEM_freeN(pa->rectz); pa->rectz= NULL;
- MEM_freeN(pa->rectp); pa->rectp= NULL;
- MEM_freeN(pa->recto); pa->recto= NULL;
- MEM_freeN(pa->rectbackz); pa->rectbackz= NULL;
- MEM_freeN(pa->rectbackp); pa->rectbackp= NULL;
- MEM_freeN(pa->rectbacko); pa->rectbacko= NULL;
-#endif
-}
-
-void zbufshade_sss_tile(RenderPart *pa)
-{
- Render *re= &R;
- ShadeSample ssamp;
- ZBufSSSHandle handle;
- RenderResult *rr= pa->result;
- RenderLayer *rl;
- VlakRen *vlr;
- Material *mat= re->sss_mat;
- float (*co)[3], (*color)[3], *area, *fcol;
- int x, y, seed, quad, totpoint;
- const bool display = (re->r.scemode & (R_BUTS_PREVIEW | R_VIEWPORT_PREVIEW)) == 0;
- int *ro, *rz, *rp, *rbo, *rbz, *rbp, lay;
-#if 0
- PixStr *ps;
- intptr_t *rs;
- int z;
-#endif
-
- /* setup pixelstr list and buffer for zbuffering */
- handle.pa= pa;
- handle.totps= 0;
-
-#if 0
- handle.psmlist.first= handle.psmlist.last= NULL;
- addpsmain(&handle.psmlist);
-
- pa->rectall= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "rectall");
-#else
- pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
- pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
- pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
- pa->rectbacko= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbacko");
- pa->rectbackp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackp");
- pa->rectbackz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackz");
-#endif
-
- /* setup shade sample with correct passes */
- memset(&ssamp, 0, sizeof(ssamp));
- shade_sample_initialize(&ssamp, pa, rr->layers.first);
- ssamp.tot= 1;
-
- for (rl=rr->layers.first; rl; rl=rl->next) {
- ssamp.shi[0].lay |= rl->lay;
- ssamp.shi[0].layflag |= rl->layflag;
- ssamp.shi[0].passflag |= rl->passflag;
- ssamp.shi[0].combinedflag |= ~rl->pass_xor;
- }
-
- rl= rr->layers.first;
- ssamp.shi[0].passflag |= SCE_PASS_RGBA|SCE_PASS_COMBINED;
- ssamp.shi[0].combinedflag &= ~(SCE_PASS_SPEC);
- ssamp.shi[0].mat_override= NULL;
- ssamp.shi[0].light_override= NULL;
- lay= ssamp.shi[0].lay;
-
- /* create the pixelstrs to be used later */
- zbuffer_sss(pa, lay, &handle, addps_sss);
-
- if (handle.totps==0) {
- zbufshade_sss_free(pa);
- return;
- }
-
- fcol= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
-
- co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo");
- color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor");
- area= MEM_mallocN(sizeof(float)*handle.totps, "SSSArea");
-
-#if 0
- /* create ISB (does not work currently!) */
- if (re->r.mode & R_SHADOW)
- ISB_create(pa, NULL);
-#endif
-
- if (display) {
- /* initialize scanline updates for main thread */
- rr->renrect.ymin = 0;
- rr->renlay= rl;
- }
-
- seed= pa->rectx*pa->disprect.ymin;
-#if 0
- rs= pa->rectall;
-#else
- rz= pa->rectz;
- rp= pa->rectp;
- ro= pa->recto;
- rbz= pa->rectbackz;
- rbp= pa->rectbackp;
- rbo= pa->rectbacko;
-#endif
- totpoint= 0;
-
- for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
- for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, fcol+=4) {
- /* per pixel fixed seed */
- BLI_thread_srandom(pa->thread, seed++);
-
-#if 0
- if (rs) {
- /* for each sample in this pixel, shade it */
- for (ps = (PixStr *)(*rs); ps; ps=ps->next) {
- ObjectInstanceRen *obi= &re->objectinstance[ps->obi];
- ObjectRen *obr= obi->obr;
- vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK);
- quad= (ps->facenr & RE_QUAD_OFFS);
- z= ps->z;
-
- shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, z,
- co[totpoint], color[totpoint], &area[totpoint]);
-
- totpoint++;
-
- add_v3_v3(fcol, color);
- fcol[3]= 1.0f;
- }
-
- rs++;
- }
-#else
- if (rp) {
- if (*rp != 0) {
- ObjectInstanceRen *obi= &re->objectinstance[*ro];
- ObjectRen *obr= obi->obr;
-
- /* shade front */
- vlr= RE_findOrAddVlak(obr, (*rp-1) & RE_QUAD_MASK);
- quad= ((*rp) & RE_QUAD_OFFS);
-
- shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, *rz,
- co[totpoint], color[totpoint], &area[totpoint]);
-
- add_v3_v3(fcol, color[totpoint]);
- fcol[3]= 1.0f;
- totpoint++;
- }
-
- rp++; rz++; ro++;
- }
-
- if (rbp) {
- if (*rbp != 0 && !(*rbp == *(rp-1) && *rbo == *(ro-1))) {
- ObjectInstanceRen *obi= &re->objectinstance[*rbo];
- ObjectRen *obr= obi->obr;
-
- /* shade back */
- vlr= RE_findOrAddVlak(obr, (*rbp-1) & RE_QUAD_MASK);
- quad= ((*rbp) & RE_QUAD_OFFS);
-
- shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, *rbz,
- co[totpoint], color[totpoint], &area[totpoint]);
-
- /* to indicate this is a back sample */
- area[totpoint]= -area[totpoint];
-
- add_v3_v3(fcol, color[totpoint]);
- fcol[3]= 1.0f;
- totpoint++;
- }
-
- rbz++; rbp++; rbo++;
- }
-#endif
- }
-
- if (y&1)
- if (re->test_break(re->tbh)) break;
- }
-
- /* note: after adding we do not free these arrays, sss keeps them */
- if (totpoint > 0) {
- sss_add_points(re, co, color, area, totpoint);
- }
- else {
- MEM_freeN(co);
- MEM_freeN(color);
- MEM_freeN(area);
- }
-
-#if 0
- if (re->r.mode & R_SHADOW)
- ISB_free(pa);
-#endif
-
- if (display) {
- /* display active layer */
- rr->renrect.ymin=rr->renrect.ymax = 0;
- rr->renlay= render_get_active_layer(&R, rr);
- }
-
- zbufshade_sss_free(pa);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void renderhalo_post(RenderResult *rr, float *rectf, HaloRen *har) /* postprocess version */
-{
- float dist, xsq, ysq, xn, yn, colf[4], *rectft, *rtf;
- float haloxs, haloys;
- int minx, maxx, miny, maxy, x, y;
-
- /* calculate the disprect mapped coordinate for halo. note: rectx is disprect corrected */
- haloxs= har->xs - R.disprect.xmin;
- haloys= har->ys - R.disprect.ymin;
-
- har->miny= miny= haloys - har->rad/R.ycor;
- har->maxy= maxy= haloys + har->rad/R.ycor;
-
- if (maxy < 0) {
- /* pass */
- }
- else if (rr->recty < miny) {
- /* pass */
- }
- else {
- minx = floor(haloxs - har->rad);
- maxx = ceil(haloxs + har->rad);
-
- if (maxx < 0) {
- /* pass */
- }
- else if (rr->rectx < minx) {
- /* pass */
- }
- else {
- if (minx<0) minx= 0;
- if (maxx>=rr->rectx) maxx= rr->rectx-1;
- if (miny<0) miny= 0;
- if (maxy>rr->recty) maxy= rr->recty;
-
- rectft= rectf+ 4*rr->rectx*miny;
-
- for (y=miny; y<maxy; y++) {
-
- rtf= rectft+4*minx;
-
- yn= (y - haloys)*R.ycor;
- ysq= yn*yn;
-
- for (x=minx; x<=maxx; x++) {
- xn= x - haloxs;
- xsq= xn*xn;
- dist= xsq+ysq;
- if (dist<har->radsq) {
-
- if (shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec))
- addalphaAddfacFloat(rtf, colf, har->add);
- }
- rtf+=4;
- }
-
- rectft+= 4*rr->rectx;
-
- if (R.test_break(R.tbh)) break;
- }
- }
- }
-}
-/* ------------------------------------------------------------------------ */
-
-static void renderflare(RenderResult *rr, float *rectf, HaloRen *har)
-{
- extern const float hashvectf[];
- HaloRen fla;
- Material *ma;
- const float *rc;
- float rad, alfa, visifac, vec[3];
- int b, type;
-
- fla= *har;
- fla.linec= fla.ringc= fla.flarec= 0;
-
- rad= har->rad;
- alfa= har->alfa;
-
- visifac= R.ycor*(har->pixels);
- /* all radials added / r^3 == 1.0f! */
- visifac /= (har->rad*har->rad*har->rad);
- visifac*= visifac;
-
- ma= har->mat;
-
- /* first halo: just do */
-
- har->rad= rad*ma->flaresize*visifac;
- har->radsq= har->rad*har->rad;
- har->zs= fla.zs= 0;
-
- har->alfa= alfa*visifac;
-
- renderhalo_post(rr, rectf, har);
-
- /* next halo's: the flares */
- rc= hashvectf + ma->seed2;
-
- for (b=1; b<har->flarec; b++) {
-
- fla.r = fabsf(rc[0]);
- fla.g = fabsf(rc[1]);
- fla.b = fabsf(rc[2]);
- fla.alfa= ma->flareboost*fabsf(alfa*visifac*rc[3]);
- fla.hard= 20.0f + fabsf(70.0f*rc[7]);
- fla.tex= 0;
-
- type= (int)(fabsf(3.9f*rc[6]));
-
- fla.rad = ma->subsize * sqrtf(fabsf(2.0f * har->rad * rc[4]));
-
- if (type==3) {
- fla.rad*= 3.0f;
- fla.rad+= R.rectx/10;
- }
-
- fla.radsq= fla.rad*fla.rad;
-
- vec[0]= 1.4f*rc[5]*(har->xs-R.winx/2);
- vec[1]= 1.4f*rc[5]*(har->ys-R.winy/2);
- vec[2]= 32.0f*sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + 1.0f);
-
- fla.xs= R.winx/2 + vec[0] + (1.2f+rc[8])*R.rectx*vec[0]/vec[2];
- fla.ys= R.winy/2 + vec[1] + (1.2f+rc[8])*R.rectx*vec[1]/vec[2];
-
- if (R.flag & R_SEC_FIELD) {
- if (R.r.mode & R_ODDFIELD) fla.ys += 0.5f;
- else fla.ys -= 0.5f;
- }
- if (type & 1) fla.type= HA_FLARECIRC;
- else fla.type= 0;
- renderhalo_post(rr, rectf, &fla);
-
- fla.alfa*= 0.5f;
- if (type & 2) fla.type= HA_FLARECIRC;
- else fla.type= 0;
- renderhalo_post(rr, rectf, &fla);
-
- rc+= 7;
- }
-}
-
-/* needs recode... integrate this better! */
-void add_halo_flare(Render *re)
-{
- RenderResult *rr= re->result;
- RenderLayer *rl;
- HaloRen *har;
- int a, mode;
- float *rect;
-
- /* for now, we get the first renderlayer in list with halos set */
- for (rl= rr->layers.first; rl; rl= rl->next) {
- bool do_draw = false;
-
- if ((rl->layflag & SCE_LAY_HALO) == 0)
- continue;
-
- rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
-
- if (rect==NULL)
- continue;
-
- mode= R.r.mode;
- R.r.mode &= ~R_PANORAMA;
-
- project_renderdata(&R, projectverto, 0, 0, 0);
-
- for (a=0; a<R.tothalo; a++) {
- har= R.sortedhalos[a];
-
- if (har->flarec && (har->lay & rl->lay)) {
- do_draw = true;
- renderflare(rr, rect, har);
- }
- }
-
- if (do_draw) {
- /* weak... the display callback wants an active renderlayer pointer... */
- rr->renlay= rl;
- re->display_update(re->duh, rr, NULL);
- }
-
- R.r.mode= mode;
- }
-}
-
-void render_internal_update_passes(RenderEngine *engine, Scene *scene, SceneRenderLayer *srl)
-{
- int type;
-
- RE_engine_register_pass(engine, scene, srl, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
-
-#define CHECK_PASS(name, channels, chanid) \
- if (srl->passflag & (SCE_PASS_ ## name)) { \
- if (channels == 4) type = SOCK_RGBA; \
- else if (channels == 3) type = SOCK_VECTOR; \
- else type = SOCK_FLOAT; \
- RE_engine_register_pass(engine, scene, srl, RE_PASSNAME_ ## name, channels, chanid, type); \
- }
-
- CHECK_PASS(Z, 1, "Z");
- CHECK_PASS(VECTOR, 4, "XYZW");
- CHECK_PASS(NORMAL, 3, "XYZ");
- CHECK_PASS(UV, 3, "UVA");
- CHECK_PASS(RGBA, 4, "RGBA");
- CHECK_PASS(EMIT, 3, "RGB");
- CHECK_PASS(DIFFUSE, 3, "RGB");
- CHECK_PASS(SPEC, 3, "RGB");
- CHECK_PASS(AO, 3, "RGB");
- CHECK_PASS(ENVIRONMENT, 3, "RGB");
- CHECK_PASS(INDIRECT, 3, "RGB");
- CHECK_PASS(SHADOW, 3, "RGB");
- CHECK_PASS(REFLECT, 3, "RGB");
- CHECK_PASS(REFRACT, 3, "RGB");
- CHECK_PASS(INDEXOB, 1, "X");
- CHECK_PASS(INDEXMA, 1, "X");
- CHECK_PASS(MIST, 1, "Z");
-
-#undef CHECK_PASS
-}
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
deleted file mode 100644
index 831f94138df..00000000000
--- a/source/blender/render/intern/source/renderdatabase.c
+++ /dev/null
@@ -1,1602 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): 2004-2006, Blender Foundation, full recode
- *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/renderdatabase.c
- * \ingroup render
- */
-
-
-/*
- * Storage, retrieval and query of render specific data.
- *
- * All data from a Blender scene is converted by the renderconverter/
- * into a special format that is used by the render module to make
- * images out of. These functions interface to the render-specific
- * database.
- *
- * The blo{ha/ve/vl} arrays store pointers to blocks of 256 data
- * entries each.
- *
- * The index of an entry is >>8 (the highest 24 * bits), to find an
- * offset in a 256-entry block.
- *
- * - If the 256-entry block entry has an entry in the
- * vertnodes/vlaknodes/bloha array of the current block, the i-th entry in
- * that block is allocated to this entry.
- *
- * - If the entry has no block allocated for it yet, memory is
- * allocated.
- *
- * The pointer to the correct entry is returned. Memory is guaranteed
- * to exist (as long as the malloc does not break). Since guarded
- * allocation is used, memory _must_ be available. Otherwise, an
- * exit(0) would occur.
- *
- */
-
-#include <limits.h>
-#include <math.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_hash.h"
-
-#include "DNA_material_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_listBase.h"
-#include "DNA_particle_types.h"
-
-#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
-
-#include "RE_render_ext.h" /* externtex */
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "zbuf.h"
-
-/* ------------------------------------------------------------------------- */
-
-/* More dynamic allocation of options for render vertices and faces, so we don't
- * have to reserve this space inside vertices.
- * Important; vertices and faces, should have been created already (to get tables
- * checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not
- * the index */
-
-/* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */
-#define RE_STRESS_ELEMS 1
-#define RE_RAD_ELEMS 4
-#define RE_STRAND_ELEMS 1
-#define RE_TANGENT_ELEMS 3
-#define RE_WINSPEED_ELEMS 4
-#define RE_MTFACE_ELEMS 1
-#define RE_MCOL_ELEMS 4
-#define RE_UV_ELEMS 2
-#define RE_VLAK_ORIGINDEX_ELEMS 1
-#define RE_VERT_ORIGINDEX_ELEMS 1
-#define RE_SURFNOR_ELEMS 3
-#define RE_RADFACE_ELEMS 1
-#define RE_SIMPLIFY_ELEMS 2
-#define RE_FACE_ELEMS 1
-#define RE_NMAP_TANGENT_ELEMS 16
-
-float *RE_vertren_get_stress(ObjectRen *obr, VertRen *ver, int verify)
-{
- float *stress;
- int nr= ver->index>>8;
-
- stress= obr->vertnodes[nr].stress;
- if (stress==NULL) {
- if (verify)
- stress= obr->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table");
- else
- return NULL;
- }
- return stress + (ver->index & 255)*RE_STRESS_ELEMS;
-}
-
-/* this one callocs! */
-float *RE_vertren_get_rad(ObjectRen *obr, VertRen *ver, int verify)
-{
- float *rad;
- int nr= ver->index>>8;
-
- rad= obr->vertnodes[nr].rad;
- if (rad==NULL) {
- if (verify)
- rad= obr->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table");
- else
- return NULL;
- }
- return rad + (ver->index & 255)*RE_RAD_ELEMS;
-}
-
-float *RE_vertren_get_strand(ObjectRen *obr, VertRen *ver, int verify)
-{
- float *strand;
- int nr= ver->index>>8;
-
- strand= obr->vertnodes[nr].strand;
- if (strand==NULL) {
- if (verify)
- strand= obr->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table");
- else
- return NULL;
- }
- return strand + (ver->index & 255)*RE_STRAND_ELEMS;
-}
-
-/* needs calloc */
-float *RE_vertren_get_tangent(ObjectRen *obr, VertRen *ver, int verify)
-{
- float *tangent;
- int nr= ver->index>>8;
-
- tangent= obr->vertnodes[nr].tangent;
- if (tangent==NULL) {
- if (verify)
- tangent= obr->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table");
- else
- return NULL;
- }
- return tangent + (ver->index & 255)*RE_TANGENT_ELEMS;
-}
-
-/* needs calloc! not all renderverts have them */
-/* also winspeed is exception, it is stored per instance */
-float *RE_vertren_get_winspeed(ObjectInstanceRen *obi, VertRen *ver, int verify)
-{
- float *winspeed;
- int totvector;
-
- winspeed= obi->vectors;
- if (winspeed==NULL) {
- if (verify) {
- totvector= obi->obr->totvert + obi->obr->totstrand;
- winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
- }
- else
- return NULL;
- }
- return winspeed + ver->index*RE_WINSPEED_ELEMS;
-}
-
-int *RE_vertren_get_origindex(ObjectRen *obr, VertRen *ver, int verify)
-{
- int *origindex;
- int nr= ver->index>>8;
-
- origindex= obr->vertnodes[nr].origindex;
- if (origindex==NULL) {
- if (verify)
- origindex= obr->vertnodes[nr].origindex= MEM_mallocN(256*RE_VERT_ORIGINDEX_ELEMS*sizeof(int), "origindex table");
- else
- return NULL;
- }
- return origindex + (ver->index & 255)*RE_VERT_ORIGINDEX_ELEMS;
-}
-
-VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver)
-{
- VertRen *v1= RE_findOrAddVert(obr, obr->totvert++);
- float *fp1, *fp2;
- int *int1, *int2;
- int index= v1->index;
-
- *v1= *ver;
- v1->index= index;
-
- fp1= RE_vertren_get_stress(obr, ver, 0);
- if (fp1) {
- fp2= RE_vertren_get_stress(obr, v1, 1);
- memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float));
- }
- fp1= RE_vertren_get_rad(obr, ver, 0);
- if (fp1) {
- fp2= RE_vertren_get_rad(obr, v1, 1);
- memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float));
- }
- fp1= RE_vertren_get_strand(obr, ver, 0);
- if (fp1) {
- fp2= RE_vertren_get_strand(obr, v1, 1);
- memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float));
- }
- fp1= RE_vertren_get_tangent(obr, ver, 0);
- if (fp1) {
- fp2= RE_vertren_get_tangent(obr, v1, 1);
- memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float));
- }
- int1= RE_vertren_get_origindex(obr, ver, 0);
- if (int1) {
- int2= RE_vertren_get_origindex(obr, v1, 1);
- memcpy(int2, int1, RE_VERT_ORIGINDEX_ELEMS*sizeof(int));
- }
- return v1;
-}
-
-VertRen *RE_findOrAddVert(ObjectRen *obr, int nr)
-{
- VertTableNode *temp;
- VertRen *v;
- int a;
-
- if (nr<0) {
- printf("error in findOrAddVert: %d\n", nr);
- return NULL;
- }
- a= nr>>8;
-
- if (a>=obr->vertnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
- temp= obr->vertnodes;
-
- obr->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(obr->vertnodeslen+TABLEINITSIZE), "vertnodes");
- if (temp) memcpy(obr->vertnodes, temp, obr->vertnodeslen*sizeof(VertTableNode));
- memset(obr->vertnodes+obr->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode));
-
- obr->vertnodeslen+=TABLEINITSIZE;
- if (temp) MEM_freeN(temp);
- }
-
- v= obr->vertnodes[a].vert;
- if (v==NULL) {
- int i;
-
- v= (VertRen *)MEM_callocN(256*sizeof(VertRen), "findOrAddVert");
- obr->vertnodes[a].vert= v;
-
- for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) {
- v[a].index= i;
- }
- }
- v+= (nr & 255);
- return v;
-}
-
-/* ------------------------------------------------------------------------ */
-
-MTFace *RE_vlakren_get_tface(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify)
-{
- VlakTableNode *node;
- int nr= vlr->index>>8, vlakindex= (vlr->index&255);
- int index= (n<<8) + vlakindex;
-
- node= &obr->vlaknodes[nr];
-
- if (verify) {
- if (n>=node->totmtface) {
- MTFace *mtface= node->mtface;
- int size= (n+1)*256;
-
- node->mtface= MEM_callocN(size*sizeof(MTFace), "Vlak mtface");
-
- if (mtface) {
- size= node->totmtface*256;
- memcpy(node->mtface, mtface, size*sizeof(MTFace));
- MEM_freeN(mtface);
- }
-
- node->totmtface= n+1;
- }
- }
- else {
- if (n>=node->totmtface)
- return NULL;
-
- if (name) *name= obr->mtface[n];
- }
-
- return node->mtface + index;
-}
-
-MCol *RE_vlakren_get_mcol(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify)
-{
- VlakTableNode *node;
- int nr= vlr->index>>8, vlakindex= (vlr->index&255);
- int index= (n<<8) + vlakindex;
-
- node= &obr->vlaknodes[nr];
-
- if (verify) {
- if (n>=node->totmcol) {
- MCol *mcol= node->mcol;
- int size= (n+1)*256;
-
- node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "Vlak mcol");
-
- if (mcol) {
- size= node->totmcol*256;
- memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS);
- MEM_freeN(mcol);
- }
-
- node->totmcol= n+1;
- }
- }
- else {
- if (n>=node->totmcol)
- return NULL;
-
- if (name) *name= obr->mcol[n];
- }
-
- return node->mcol + index*RE_MCOL_ELEMS;
-}
-
-int *RE_vlakren_get_origindex(ObjectRen *obr, VlakRen *vlak, int verify)
-{
- int *origindex;
- int nr= vlak->index>>8;
-
- origindex= obr->vlaknodes[nr].origindex;
- if (origindex==NULL) {
- if (verify)
- origindex= obr->vlaknodes[nr].origindex= MEM_callocN(256*RE_VLAK_ORIGINDEX_ELEMS*sizeof(int), "origindex table");
- else
- return NULL;
- }
- return origindex + (vlak->index & 255)*RE_VLAK_ORIGINDEX_ELEMS;
-}
-
-float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify)
-{
- float *surfnor;
- int nr= vlak->index>>8;
-
- surfnor= obr->vlaknodes[nr].surfnor;
- if (surfnor==NULL) {
- if (verify)
- surfnor= obr->vlaknodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
- else
- return NULL;
- }
- return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
-}
-
-float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify)
-{
- float **tangents;
- int nr= vlak->index>>8;
-
- tangents = obr->vlaknodes[nr].tangent_arrays;
-
- if (index + 1 > 8) {
- return NULL;
- }
-
- index = index < 0 ? 0: index;
-
- if (tangents[index] == NULL) {
- if (verify) {
- tangents[index] = MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
- }
- else
- return NULL;
- }
-
- return tangents[index] + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
-}
-
-RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify)
-{
- RadFace **radface;
- int nr= vlak->index>>8;
-
- radface= obr->vlaknodes[nr].radface;
- if (radface==NULL) {
- if (verify)
- radface = obr->vlaknodes[nr].radface= MEM_callocN(256 * RE_RADFACE_ELEMS * sizeof(void *), "radface table");
- else
- return NULL;
- }
- return radface + (vlak->index & 255)*RE_RADFACE_ELEMS;
-}
-
-VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
-{
- VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++);
- MTFace *mtface, *mtface1;
- MCol *mcol, *mcol1;
- float *surfnor, *surfnor1;
- float *tangent, *tangent1;
- int *origindex, *origindex1;
- RadFace **radface, **radface1;
- int i, index = vlr1->index;
- char *name;
-
- *vlr1= *vlr;
- vlr1->index= index;
-
- for (i=0; (mtface=RE_vlakren_get_tface(obr, vlr, i, &name, 0)) != NULL; i++) {
- mtface1= RE_vlakren_get_tface(obr, vlr1, i, &name, 1);
- memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS);
- }
-
- for (i=0; (mcol=RE_vlakren_get_mcol(obr, vlr, i, &name, 0)) != NULL; i++) {
- mcol1= RE_vlakren_get_mcol(obr, vlr1, i, &name, 1);
- memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
- }
-
- origindex= RE_vlakren_get_origindex(obr, vlr, 0);
- if (origindex) {
- origindex1= RE_vlakren_get_origindex(obr, vlr1, 1);
- /* Just an int, but memcpy for consistency. */
- memcpy(origindex1, origindex, sizeof(int)*RE_VLAK_ORIGINDEX_ELEMS);
- }
-
- surfnor= RE_vlakren_get_surfnor(obr, vlr, 0);
- if (surfnor) {
- surfnor1= RE_vlakren_get_surfnor(obr, vlr1, 1);
- copy_v3_v3(surfnor1, surfnor);
- }
-
- for (i=0; i < MAX_MTFACE; i++) {
- tangent = RE_vlakren_get_nmap_tangent(obr, vlr, i, false);
- if (!tangent)
- continue;
- tangent1 = RE_vlakren_get_nmap_tangent(obr, vlr1, i, true);
- memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS);
- }
-
- radface= RE_vlakren_get_radface(obr, vlr, 0);
- if (radface) {
- radface1= RE_vlakren_get_radface(obr, vlr1, 1);
- *radface1= *radface;
- }
-
- return vlr1;
-}
-
-void RE_vlakren_get_normal(Render *UNUSED(re), ObjectInstanceRen *obi, VlakRen *vlr, float r_nor[3])
-{
- float (*nmat)[3]= obi->nmat;
-
- if (obi->flag & R_TRANSFORMED) {
- mul_v3_m3v3(r_nor, nmat, vlr->n);
- normalize_v3(r_nor);
- }
- else {
- copy_v3_v3(r_nor, vlr->n);
- }
-}
-
-void RE_set_customdata_names(ObjectRen *obr, CustomData *data)
-{
- /* CustomData layer names are stored per object here, because the
- * DerivedMesh which stores the layers is freed */
-
- CustomDataLayer *layer;
- int numtf = 0, numcol = 0, i, mtfn, mcn;
-
- if (CustomData_has_layer(data, CD_MTFACE)) {
- numtf= CustomData_number_of_layers(data, CD_MTFACE);
- obr->mtface= MEM_callocN(sizeof(*obr->mtface)*numtf, "mtfacenames");
- }
-
- if (CustomData_has_layer(data, CD_MCOL)) {
- numcol= CustomData_number_of_layers(data, CD_MCOL);
- obr->mcol= MEM_callocN(sizeof(*obr->mcol)*numcol, "mcolnames");
- }
-
- for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) {
- layer= &data->layers[i];
-
- if (layer->type == CD_MTFACE) {
- BLI_strncpy(obr->mtface[mtfn++], layer->name, sizeof(layer->name));
- obr->actmtface= CLAMPIS(layer->active_rnd, 0, numtf);
- obr->bakemtface= layer->active;
- }
- else if (layer->type == CD_MCOL) {
- BLI_strncpy(obr->mcol[mcn++], layer->name, sizeof(layer->name));
- obr->actmcol= CLAMPIS(layer->active_rnd, 0, numcol);
- }
- }
-}
-
-VlakRen *RE_findOrAddVlak(ObjectRen *obr, int nr)
-{
- VlakTableNode *temp;
- VlakRen *v;
- int a;
-
- if (nr<0) {
- printf("error in findOrAddVlak: %d\n", nr);
- return obr->vlaknodes[0].vlak;
- }
- a= nr>>8;
-
- if (a>=obr->vlaknodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
- temp= obr->vlaknodes;
-
- obr->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(obr->vlaknodeslen+TABLEINITSIZE), "vlaknodes");
- if (temp) memcpy(obr->vlaknodes, temp, obr->vlaknodeslen*sizeof(VlakTableNode));
- memset(obr->vlaknodes+obr->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode));
-
- obr->vlaknodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
- if (temp) MEM_freeN(temp);
- }
-
- v= obr->vlaknodes[a].vlak;
-
- if (v==NULL) {
- int i;
-
- v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen), "findOrAddVlak");
- obr->vlaknodes[a].vlak= v;
-
- for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
- v[a].index= i;
- }
- v+= (nr & 255);
- return v;
-}
-
-/* ------------------------------------------------------------------------ */
-
-float *RE_strandren_get_surfnor(ObjectRen *obr, StrandRen *strand, int verify)
-{
- float *surfnor;
- int nr= strand->index>>8;
-
- surfnor= obr->strandnodes[nr].surfnor;
- if (surfnor==NULL) {
- if (verify)
- surfnor= obr->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor strand table");
- else
- return NULL;
- }
- return surfnor + (strand->index & 255)*RE_SURFNOR_ELEMS;
-}
-
-float *RE_strandren_get_uv(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify)
-{
- StrandTableNode *node;
- int nr= strand->index>>8, strandindex= (strand->index&255);
- int index= (n<<8) + strandindex;
-
- node= &obr->strandnodes[nr];
-
- if (verify) {
- if (n>=node->totuv) {
- float *uv= node->uv;
- int size= (n+1)*256;
-
- node->uv= MEM_callocN(size*sizeof(float)*RE_UV_ELEMS, "strand uv table");
-
- if (uv) {
- size= node->totuv*256;
- memcpy(node->uv, uv, size*sizeof(float)*RE_UV_ELEMS);
- MEM_freeN(uv);
- }
-
- node->totuv= n+1;
- }
- }
- else {
- if (n>=node->totuv)
- return NULL;
-
- if (name) *name= obr->mtface[n];
- }
-
- return node->uv + index*RE_UV_ELEMS;
-}
-
-MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify)
-{
- StrandTableNode *node;
- int nr= strand->index>>8, strandindex= (strand->index&255);
- int index= (n<<8) + strandindex;
-
- node= &obr->strandnodes[nr];
-
- if (verify) {
- if (n>=node->totmcol) {
- MCol *mcol= node->mcol;
- int size= (n+1)*256;
-
- node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "strand mcol table");
-
- if (mcol) {
- size= node->totmcol*256;
- memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS);
- MEM_freeN(mcol);
- }
-
- node->totmcol= n+1;
- }
- }
- else {
- if (n>=node->totmcol)
- return NULL;
-
- if (name) *name= obr->mcol[n];
- }
-
- return node->mcol + index*RE_MCOL_ELEMS;
-}
-
-float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify)
-{
- float *simplify;
- int nr= strand->index>>8;
-
- simplify= obr->strandnodes[nr].simplify;
- if (simplify==NULL) {
- if (verify)
- simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify strand table");
- else
- return NULL;
- }
- return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS;
-}
-
-int *RE_strandren_get_face(ObjectRen *obr, StrandRen *strand, int verify)
-{
- int *face;
- int nr= strand->index>>8;
-
- face= obr->strandnodes[nr].face;
- if (face==NULL) {
- if (verify)
- face= obr->strandnodes[nr].face= MEM_callocN(256*RE_FACE_ELEMS*sizeof(int), "face strand table");
- else
- return NULL;
- }
- return face + (strand->index & 255)*RE_FACE_ELEMS;
-}
-
-/* winspeed is exception, it is stored per instance */
-float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify)
-{
- float *winspeed;
- int totvector;
-
- winspeed= obi->vectors;
- if (winspeed==NULL) {
- if (verify) {
- totvector= obi->obr->totvert + obi->obr->totstrand;
- winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed strand table");
- }
- else
- return NULL;
- }
- return winspeed + (obi->obr->totvert + strand->index)*RE_WINSPEED_ELEMS;
-}
-
-StrandRen *RE_findOrAddStrand(ObjectRen *obr, int nr)
-{
- StrandTableNode *temp;
- StrandRen *v;
- int a;
-
- if (nr<0) {
- printf("error in findOrAddStrand: %d\n", nr);
- return obr->strandnodes[0].strand;
- }
- a= nr>>8;
-
- if (a>=obr->strandnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
- temp= obr->strandnodes;
-
- obr->strandnodes= MEM_mallocN(sizeof(StrandTableNode)*(obr->strandnodeslen+TABLEINITSIZE), "strandnodes");
- if (temp) memcpy(obr->strandnodes, temp, obr->strandnodeslen*sizeof(StrandTableNode));
- memset(obr->strandnodes+obr->strandnodeslen, 0, TABLEINITSIZE*sizeof(StrandTableNode));
-
- obr->strandnodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
- if (temp) MEM_freeN(temp);
- }
-
- v= obr->strandnodes[a].strand;
-
- if (v==NULL) {
- int i;
-
- v= (StrandRen *)MEM_callocN(256*sizeof(StrandRen), "findOrAddStrand");
- obr->strandnodes[a].strand= v;
-
- for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
- v[a].index= i;
- }
- v+= (nr & 255);
- return v;
-}
-
-StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert)
-{
- StrandBuffer *strandbuf;
-
- strandbuf= MEM_callocN(sizeof(StrandBuffer), "StrandBuffer");
- strandbuf->vert= MEM_callocN(sizeof(StrandVert)*totvert, "StrandVert");
- strandbuf->totvert= totvert;
- strandbuf->obr= obr;
-
- obr->strandbuf= strandbuf;
-
- return strandbuf;
-}
-
-/* ------------------------------------------------------------------------ */
-
-ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int psysindex, int lay)
-{
- ObjectRen *obr= MEM_callocN(sizeof(ObjectRen), "object render struct");
-
- BLI_addtail(&re->objecttable, obr);
- obr->ob= ob;
- obr->par= par;
- obr->index= index;
- obr->psysindex= psysindex;
- obr->lay= lay;
-
- return obr;
-}
-
-void free_renderdata_vertnodes(VertTableNode *vertnodes)
-{
- int a;
-
- if (vertnodes==NULL) return;
-
- for (a=0; vertnodes[a].vert; a++) {
- MEM_freeN(vertnodes[a].vert);
-
- if (vertnodes[a].rad)
- MEM_freeN(vertnodes[a].rad);
- if (vertnodes[a].strand)
- MEM_freeN(vertnodes[a].strand);
- if (vertnodes[a].tangent)
- MEM_freeN(vertnodes[a].tangent);
- if (vertnodes[a].stress)
- MEM_freeN(vertnodes[a].stress);
- if (vertnodes[a].winspeed)
- MEM_freeN(vertnodes[a].winspeed);
- if (vertnodes[a].origindex)
- MEM_freeN(vertnodes[a].origindex);
- }
-
- MEM_freeN(vertnodes);
-}
-
-void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
-{
- int a;
-
- if (vlaknodes==NULL) return;
-
- for (a=0; vlaknodes[a].vlak; a++) {
- MEM_freeN(vlaknodes[a].vlak);
-
- if (vlaknodes[a].mtface)
- MEM_freeN(vlaknodes[a].mtface);
- if (vlaknodes[a].mcol)
- MEM_freeN(vlaknodes[a].mcol);
- if (vlaknodes[a].origindex)
- MEM_freeN(vlaknodes[a].origindex);
- if (vlaknodes[a].surfnor)
- MEM_freeN(vlaknodes[a].surfnor);
- for (int b = 0; b < MAX_MTFACE; b++) {
- if (vlaknodes[a].tangent_arrays[b])
- MEM_freeN(vlaknodes[a].tangent_arrays[b]);
- }
- if (vlaknodes[a].radface)
- MEM_freeN(vlaknodes[a].radface);
- }
-
- MEM_freeN(vlaknodes);
-}
-
-static void free_renderdata_strandnodes(StrandTableNode *strandnodes)
-{
- int a;
-
- if (strandnodes==NULL) return;
-
- for (a=0; strandnodes[a].strand; a++) {
- MEM_freeN(strandnodes[a].strand);
-
- if (strandnodes[a].uv)
- MEM_freeN(strandnodes[a].uv);
- if (strandnodes[a].mcol)
- MEM_freeN(strandnodes[a].mcol);
- if (strandnodes[a].winspeed)
- MEM_freeN(strandnodes[a].winspeed);
- if (strandnodes[a].surfnor)
- MEM_freeN(strandnodes[a].surfnor);
- if (strandnodes[a].simplify)
- MEM_freeN(strandnodes[a].simplify);
- if (strandnodes[a].face)
- MEM_freeN(strandnodes[a].face);
- }
-
- MEM_freeN(strandnodes);
-}
-
-void free_renderdata_tables(Render *re)
-{
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- StrandBuffer *strandbuf;
- int a=0;
-
- for (obr=re->objecttable.first; obr; obr=obr->next) {
- if (obr->vertnodes) {
- free_renderdata_vertnodes(obr->vertnodes);
- obr->vertnodes= NULL;
- obr->vertnodeslen= 0;
- }
-
- if (obr->vlaknodes) {
- free_renderdata_vlaknodes(obr->vlaknodes);
- obr->vlaknodes= NULL;
- obr->vlaknodeslen= 0;
- obr->totvlak= 0;
- }
-
- if (obr->bloha) {
- for (a=0; obr->bloha[a]; a++)
- MEM_freeN(obr->bloha[a]);
-
- MEM_freeN(obr->bloha);
- obr->bloha= NULL;
- obr->blohalen= 0;
- }
-
- if (obr->strandnodes) {
- free_renderdata_strandnodes(obr->strandnodes);
- obr->strandnodes= NULL;
- obr->strandnodeslen= 0;
- }
-
- strandbuf= obr->strandbuf;
- if (strandbuf) {
- if (strandbuf->vert) MEM_freeN(strandbuf->vert);
- if (strandbuf->bound) MEM_freeN(strandbuf->bound);
- MEM_freeN(strandbuf);
- }
-
- if (obr->mtface)
- MEM_freeN(obr->mtface);
-
- if (obr->mcol)
- MEM_freeN(obr->mcol);
-
- if (obr->rayfaces) {
- MEM_freeN(obr->rayfaces);
- obr->rayfaces = NULL;
- }
-
- if (obr->rayprimitives) {
- MEM_freeN(obr->rayprimitives);
- obr->rayprimitives = NULL;
- }
-
- if (obr->raytree) {
- RE_rayobject_free(obr->raytree);
- obr->raytree = NULL;
- }
- }
-
- if (re->objectinstance) {
- for (obi=re->instancetable.first; obi; obi=obi->next) {
- if (obi->vectors)
- MEM_freeN(obi->vectors);
-
- if (obi->raytree)
- RE_rayobject_free(obi->raytree);
- }
-
- MEM_freeN(re->objectinstance);
- re->objectinstance= NULL;
- re->totinstance= 0;
- re->instancetable.first= re->instancetable.last= NULL;
- }
-
- if (re->sortedhalos) {
- MEM_freeN(re->sortedhalos);
- re->sortedhalos= NULL;
- }
-
- BLI_freelistN(&re->customdata_names);
- BLI_freelistN(&re->objecttable);
- BLI_freelistN(&re->instancetable);
-}
-
-/* ------------------------------------------------------------------------ */
-
-HaloRen *RE_findOrAddHalo(ObjectRen *obr, int nr)
-{
- HaloRen *h, **temp;
- int a;
-
- if (nr<0) {
- printf("error in findOrAddHalo: %d\n", nr);
- return NULL;
- }
- a= nr>>8;
-
- if (a>=obr->blohalen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
- //printf("Allocating %i more halo groups. %i total.\n",
- // TABLEINITSIZE, obr->blohalen+TABLEINITSIZE );
- temp=obr->bloha;
-
- obr->bloha = (HaloRen **)MEM_callocN(sizeof(void *) * (obr->blohalen + TABLEINITSIZE), "Bloha");
- if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void *));
- memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE * sizeof(void *));
- obr->blohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
- if (temp) MEM_freeN(temp);
- }
-
- h= obr->bloha[a];
- if (h==NULL) {
- h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen), "findOrAdHalo");
- obr->bloha[a]= h;
- }
- h+= (nr & 255);
- return h;
-}
-
-/* ------------------------------------------------------------------------- */
-
-HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
- const float vec[3], const float vec1[3],
- const float *orco, float hasize, float vectsize, int seed)
-{
- const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
- HaloRen *har;
- MTex *mtex;
- float tin, tr, tg, tb, ta;
- float xn, yn, zn, texvec[3], hoco[4], hoco1[4];
-
- if (hasize==0.0f) return NULL;
-
- projectverto(vec, re->winmat, hoco);
- if (hoco[3]==0.0f) return NULL;
- if (vec1) {
- projectverto(vec1, re->winmat, hoco1);
- if (hoco1[3]==0.0f) return NULL;
- }
-
- har= RE_findOrAddHalo(obr, obr->tothalo++);
- copy_v3_v3(har->co, vec);
- har->hasize= hasize;
-
- /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
- /* we do it here for sorting of halos */
- zn= hoco[3];
- har->xs= 0.5f*re->winx*(hoco[0]/zn);
- har->ys= 0.5f*re->winy*(hoco[1]/zn);
- har->zs= 0x7FFFFF*(hoco[2]/zn);
-
- har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
-
- /* halovect */
- if (vec1) {
-
- har->type |= HA_VECT;
-
- xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
- yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
- else zn = atan2f(yn, xn);
-
- har->sin = sinf(zn);
- har->cos = cosf(zn);
- zn= len_v3v3(vec1, vec);
-
- har->hasize= vectsize*zn + (1.0f-vectsize)*hasize;
-
- sub_v3_v3v3(har->no, vec, vec1);
- normalize_v3(har->no);
- }
-
- if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
-
- har->alfa= ma->alpha;
- har->r= ma->r;
- har->g= ma->g;
- har->b= ma->b;
- har->add= (255.0f*ma->add);
- har->mat= ma;
- har->hard= ma->har;
- har->seed= seed % 256;
-
- if (ma->mode & MA_STAR) har->starpoints= ma->starc;
- if (ma->mode & MA_HALO_LINES) har->linec= ma->linec;
- if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
- if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
-
-
- if (ma->mtex[0]) {
-
- if (ma->mode & MA_HALOTEX) {
- har->tex = 1;
- }
- else if (har->mat->septex & (1 << 0)) {
- /* only 1 level textures */
- }
- else {
- mtex= ma->mtex[0];
- copy_v3_v3(texvec, vec);
-
- if (mtex->texco & TEXCO_NORM) {
- ;
- }
- else if (mtex->texco & TEXCO_OBJECT) {
- /* texvec[0]+= imatbase->ivec[0]; */
- /* texvec[1]+= imatbase->ivec[1]; */
- /* texvec[2]+= imatbase->ivec[2]; */
- /* mul_m3_v3(imatbase->imat, texvec); */
- }
- else {
- if (orco) {
- copy_v3_v3(texvec, orco);
- }
- }
-
- externtex(mtex,
- texvec,
- &tin, &tr, &tg, &tb, &ta,
- 0,
- re->pool,
- skip_load_image,
- texnode_preview);
-
- yn= tin*mtex->colfac;
- //zn= tin*mtex->alphafac;
-
- if (mtex->mapto & MAP_COL) {
- zn= 1.0f-yn;
- har->r= (yn*tr+ zn*ma->r);
- har->g= (yn*tg+ zn*ma->g);
- har->b= (yn*tb+ zn*ma->b);
- }
- if (mtex->texco & TEXCO_UV) {
- har->alfa= tin;
- }
- if (mtex->mapto & MAP_ALPHA)
- har->alfa= tin;
- }
- }
-
- har->pool = re->pool;
- har->skip_load_image = skip_load_image;
- har->texnode_preview = texnode_preview;
-
- return har;
-}
-
-HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma,
- const float vec[3], const float vec1[3],
- const float *orco, const float *uvco, float hasize, float vectsize, int seed, const float pa_co[3])
-{
- const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
- const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
- HaloRen *har;
- MTex *mtex;
- float tin, tr, tg, tb, ta;
- float xn, yn, zn, texvec[3], hoco[4], hoco1[4], in[3], tex[3], out[3];
- int i, hasrgb;
-
- if (hasize==0.0f) return NULL;
-
- projectverto(vec, re->winmat, hoco);
- if (hoco[3]==0.0f) return NULL;
- if (vec1) {
- projectverto(vec1, re->winmat, hoco1);
- if (hoco1[3]==0.0f) return NULL;
- }
-
- har= RE_findOrAddHalo(obr, obr->tothalo++);
- copy_v3_v3(har->co, vec);
- har->hasize= hasize;
-
- /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
- /* we do it here for sorting of halos */
- zn= hoco[3];
- har->xs= 0.5f*re->winx*(hoco[0]/zn);
- har->ys= 0.5f*re->winy*(hoco[1]/zn);
- har->zs= 0x7FFFFF*(hoco[2]/zn);
-
- har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
-
- /* halovect */
- if (vec1) {
-
- har->type |= HA_VECT;
-
- xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
- yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
- else zn = atan2f(yn, xn);
-
- har->sin = sinf(zn);
- har->cos = cosf(zn);
- zn= len_v3v3(vec1, vec)*0.5f;
-
- har->hasize= vectsize*zn + (1.0f-vectsize)*hasize;
-
- sub_v3_v3v3(har->no, vec, vec1);
- normalize_v3(har->no);
- }
-
- if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
-
- har->alfa= ma->alpha;
- har->r= ma->r;
- har->g= ma->g;
- har->b= ma->b;
- har->add= (255.0f*ma->add);
- har->mat= ma;
- har->hard= ma->har;
- har->seed= seed % 256;
-
- if (ma->mode & MA_STAR) har->starpoints= ma->starc;
- if (ma->mode & MA_HALO_LINES) har->linec= ma->linec;
- if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
- if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
-
- if ((ma->mode & MA_HALOTEX) && ma->mtex[0])
- har->tex= 1;
-
- for (i=0; i<MAX_MTEX; i++)
- if (ma->mtex[i] && (ma->septex & (1<<i))==0) {
- mtex= ma->mtex[i];
- copy_v3_v3(texvec, vec);
-
- if (mtex->texco & TEXCO_NORM) {
- ;
- }
- else if (mtex->texco & TEXCO_OBJECT) {
- if (mtex->object)
- mul_m4_v3(mtex->object->imat_ren, texvec);
- }
- else if (mtex->texco & TEXCO_GLOB) {
- copy_v3_v3(texvec, vec);
- }
- else if (mtex->texco & TEXCO_UV && uvco) {
- int uv_index=CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, mtex->uvname);
- if (uv_index<0)
- uv_index=CustomData_get_active_layer_index(&dm->faceData, CD_MTFACE);
-
- uv_index-=CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
-
- texvec[0]=2.0f*uvco[2*uv_index]-1.0f;
- texvec[1]=2.0f*uvco[2*uv_index+1]-1.0f;
- texvec[2]=0.0f;
- }
- else if (mtex->texco & TEXCO_PARTICLE) {
- /* particle coordinates in range [0, 1] */
- texvec[0] = 2.f * pa_co[0] - 1.f;
- texvec[1] = 2.f * pa_co[1] - 1.f;
- texvec[2] = pa_co[2];
- }
- else if (orco) {
- copy_v3_v3(texvec, orco);
- }
-
- hasrgb = externtex(mtex,
- texvec,
- &tin, &tr, &tg, &tb, &ta,
- 0,
- re->pool,
- skip_load_image,
- texnode_preview);
-
- //yn= tin*mtex->colfac;
- //zn= tin*mtex->alphafac;
- if (mtex->mapto & MAP_COL) {
- tex[0]=tr;
- tex[1]=tg;
- tex[2]=tb;
- out[0]=har->r;
- out[1]=har->g;
- out[2]=har->b;
-
- texture_rgb_blend(in, tex, out, tin, mtex->colfac, mtex->blendtype);
- // zn= 1.0-yn;
- //har->r= (yn*tr+ zn*ma->r);
- //har->g= (yn*tg+ zn*ma->g);
- //har->b= (yn*tb+ zn*ma->b);
- har->r= in[0];
- har->g= in[1];
- har->b= in[2];
- }
-
- /* alpha returned, so let's use it instead of intensity */
- if (hasrgb)
- tin = ta;
-
- if (mtex->mapto & MAP_ALPHA)
- har->alfa = texture_value_blend(mtex->def_var, har->alfa, tin, mtex->alphafac, mtex->blendtype);
- if (mtex->mapto & MAP_HAR)
- har->hard = 1.0f+126.0f*texture_value_blend(mtex->def_var, ((float)har->hard)/127.0f, tin, mtex->hardfac, mtex->blendtype);
- if (mtex->mapto & MAP_RAYMIRR)
- har->hasize = 100.0f*texture_value_blend(mtex->def_var, har->hasize/100.0f, tin, mtex->raymirrfac, mtex->blendtype);
- if (mtex->mapto & MAP_TRANSLU) {
- float add = texture_value_blend(mtex->def_var, (float)har->add/255.0f, tin, mtex->translfac, mtex->blendtype);
- CLAMP(add, 0.f, 1.f);
- har->add = 255.0f*add;
- }
- /* now what on earth is this good for?? */
- //if (mtex->texco & 16) {
- // har->alfa= tin;
- //}
- }
-
- har->pool = re->pool;
- har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
- har->texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
-
- return har;
-}
-
-/* -------------------------- operations on entire database ----------------------- */
-
-/* ugly function for halos in panorama */
-static int panotestclip(Render *re, bool do_pano, float v[4])
-{
- /* part size (ensure we run RE_parts_clamp first) */
- BLI_assert(re->partx == min_ii(re->r.tilex, re->rectx));
- BLI_assert(re->party == min_ii(re->r.tiley, re->recty));
-
- if (do_pano == false) {
- return testclip(v);
- }
- else {
- /* to be used for halos en infos */
- float abs4;
- short c = 0;
-
- int xparts = (re->rectx + re->partx - 1) / re->partx;
-
- abs4= fabsf(v[3]);
-
- if (v[2]< -abs4) c=16; /* this used to be " if (v[2]<0) ", see clippz() */
- else if (v[2]> abs4) c+= 32;
-
- if ( v[1]>abs4) c+=4;
- else if ( v[1]< -abs4) c+=8;
-
- abs4*= xparts;
- if ( v[0]>abs4) c+=2;
- else if ( v[0]< -abs4) c+=1;
-
- return c;
- }
-}
-
-/**
- * This adds the hcs coordinates to vertices. It iterates over all
- * vertices, halos and faces. After the conversion, we clip in hcs.
- *
- * Elsewhere, all primites are converted to vertices.
- * Called in
- * - envmapping (envmap.c)
- * - shadow buffering (shadbuf.c)
- */
-
-void project_renderdata(Render *re,
- void (*projectfunc)(const float *, float mat[4][4], float *),
- bool do_pano, float xoffs, bool UNUSED(do_buckets))
-{
- ObjectRen *obr;
- HaloRen *har = NULL;
- float zn, vec[3], hoco[4];
- int a;
-
- if (do_pano) {
- float panophi= xoffs;
-
- re->panosi = sinf(panophi);
- re->panoco = cosf(panophi);
- }
-
- for (obr=re->objecttable.first; obr; obr=obr->next) {
- /* calculate view coordinates (and zbuffer value) */
- for (a=0; a<obr->tothalo; a++) {
- if ((a & 255)==0) har= obr->bloha[a>>8];
- else har++;
-
- if (do_pano) {
- vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2];
- vec[1]= har->co[1];
- vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2];
- }
- else {
- copy_v3_v3(vec, har->co);
- }
-
- projectfunc(vec, re->winmat, hoco);
-
- /* we clip halos less critical, but not for the Z */
- hoco[0]*= 0.5f;
- hoco[1]*= 0.5f;
-
- if ( panotestclip(re, do_pano, hoco) ) {
- har->miny= har->maxy= -10000; /* that way render clips it */
- }
- else if (hoco[3]<0.0f) {
- har->miny= har->maxy= -10000; /* render clips it */
- }
- else { /* do the projection...*/
- /* bring back hocos */
- hoco[0]*= 2.0f;
- hoco[1]*= 2.0f;
-
- zn= hoco[3];
- har->xs= 0.5f*re->winx*(1.0f+hoco[0]/zn); /* the 0.5 negates the previous 2...*/
- har->ys= 0.5f*re->winy*(1.0f+hoco[1]/zn);
-
- /* this should be the zbuffer coordinate */
- har->zs= 0x7FFFFF*(hoco[2]/zn);
- /* taking this from the face clip functions? seems ok... */
- har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
-
- vec[0]+= har->hasize;
- projectfunc(vec, re->winmat, hoco);
- vec[0]-= har->hasize;
- zn= hoco[3];
- har->rad= fabsf(har->xs- 0.5f*re->winx*(1.0f+hoco[0]/zn));
-
- /* this clip is not really OK, to prevent stars to become too large */
- if (har->type & HA_ONLYSKY) {
- if (har->rad>3.0f) har->rad= 3.0f;
- }
-
- har->radsq= har->rad*har->rad;
-
- har->miny= har->ys - har->rad/re->ycor;
- har->maxy= har->ys + har->rad/re->ycor;
-
- /* the Zd value is still not really correct for pano */
-
- vec[2] -= har->hasize; /* z negative, otherwise it's clipped */
- projectfunc(vec, re->winmat, hoco);
- zn = hoco[3];
- zn = fabsf((float)har->zs - 0x7FFFFF * (hoco[2] / zn));
- har->zd = CLAMPIS(zn, 0, INT_MAX);
-
- }
-
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag)
-{
- /* flag specifies what things have changed. */
- if (flag & RE_OBJECT_INSTANCES_UPDATE_OBMAT) {
- copy_m4_m4(obi->obmat, obi->ob->obmat);
- invert_m4_m4(obi->obinvmat, obi->obmat);
- }
- if (flag & RE_OBJECT_INSTANCES_UPDATE_VIEW) {
- mul_m4_m4m4(obi->localtoviewmat, re->viewmat, obi->obmat);
- mul_m4_m4m4(obi->localtoviewinvmat, obi->obinvmat, re->viewinv);
- }
-}
-
-void RE_updateRenderInstances(Render *re, int flag)
-{
- int i = 0;
- for (i = 0; i < re->totinstance; i++)
- RE_updateRenderInstance(re, &re->objectinstance[i], flag);
-}
-
-ObjectInstanceRen *RE_addRenderInstance(
- Render *re, ObjectRen *obr, Object *ob, Object *par,
- int index, int psysindex, float mat[4][4], int lay, const DupliObject *dob)
-{
- ObjectInstanceRen *obi;
- float mat3[3][3];
-
- obi= MEM_callocN(sizeof(ObjectInstanceRen), "ObjectInstanceRen");
- obi->obr= obr;
- obi->ob= ob;
- obi->par= par;
- obi->index= index;
- obi->psysindex= psysindex;
- obi->lay= lay;
-
- /* Fill particle info */
- if (par && dob) {
- const ParticleSystem *psys = dob->particle_system;
- if (psys) {
- int part_index;
- if (obi->index < psys->totpart) {
- part_index = obi->index;
- }
- else if (psys->child) {
- part_index = psys->child[obi->index - psys->totpart].parent;
- }
- else {
- part_index = -1;
- }
-
- if (part_index >= 0) {
- const ParticleData *p = &psys->particles[part_index];
- obi->part_index = part_index;
- obi->part_size = p->size;
- obi->part_age = RE_GetStats(re)->cfra - p->time;
- obi->part_lifetime = p->lifetime;
-
- copy_v3_v3(obi->part_co, p->state.co);
- copy_v3_v3(obi->part_vel, p->state.vel);
- copy_v3_v3(obi->part_avel, p->state.ave);
- }
- }
- }
-
- /* Fill object info */
- if (dob) {
- obi->random_id = dob->random_id;
- }
- else {
- obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0);
- }
-
- RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW);
-
- if (mat) {
- copy_m4_m4(obi->mat, mat);
- copy_m3_m4(mat3, mat);
- invert_m3_m3(obi->nmat, mat3);
- transpose_m3(obi->nmat);
- obi->flag |= R_DUPLI_TRANSFORMED;
- }
-
- BLI_addtail(&re->instancetable, obi);
-
- return obi;
-}
-
-void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3])
-{
- *index = obi->part_index;
- *random = BLI_hash_int_01(obi->part_index);
- *age = obi->part_age;
- *lifetime = obi->part_lifetime;
- copy_v3_v3(co, obi->part_co);
- *size = obi->part_size;
- copy_v3_v3(vel, obi->part_vel);
- copy_v3_v3(angvel, obi->part_avel);
-}
-
-
-void RE_makeRenderInstances(Render *re)
-{
- ObjectInstanceRen *obi, *oldobi;
- ListBase newlist;
- int tot;
-
- /* convert list of object instances to an array for index based lookup */
- tot= BLI_listbase_count(&re->instancetable);
- re->objectinstance= MEM_callocN(sizeof(ObjectInstanceRen)*tot, "ObjectInstance");
- re->totinstance= tot;
- newlist.first= newlist.last= NULL;
-
- obi= re->objectinstance;
- for (oldobi=re->instancetable.first; oldobi; oldobi=oldobi->next) {
- *obi= *oldobi;
-
- if (obi->obr) {
- obi->prev= obi->next= NULL;
- BLI_addtail(&newlist, obi);
- obi++;
- }
- else
- re->totinstance--;
- }
-
- BLI_freelistN(&re->instancetable);
- re->instancetable= newlist;
-}
-
-/* four functions to facilitate envmap rotation for raytrace */
-void RE_instance_rotate_ray_start(ObjectInstanceRen *obi, Isect *is)
-{
- if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
- copy_v3_v3(is->origstart, is->start);
- mul_m4_v3(obi->imat, is->start);
- }
-}
-
-void RE_instance_rotate_ray_dir(ObjectInstanceRen *obi, Isect *is)
-{
- if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
- float end[3];
-
- copy_v3_v3(is->origdir, is->dir);
- add_v3_v3v3(end, is->origstart, is->dir);
-
- mul_m4_v3(obi->imat, end);
- sub_v3_v3v3(is->dir, end, is->start);
- }
-}
-
-void RE_instance_rotate_ray(ObjectInstanceRen *obi, Isect *is)
-{
- RE_instance_rotate_ray_start(obi, is);
- RE_instance_rotate_ray_dir(obi, is);
-}
-
-void RE_instance_rotate_ray_restore(ObjectInstanceRen *obi, Isect *is)
-{
- if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
- copy_v3_v3(is->start, is->origstart);
- copy_v3_v3(is->dir, is->origdir);
- }
-}
-
-int clip_render_object(float boundbox[2][3], float bounds[4], float winmat[4][4])
-{
- float mat[4][4], vec[4];
- int a, fl, flag = -1;
-
- copy_m4_m4(mat, winmat);
-
- for (a=0; a < 8; a++) {
- vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0];
- vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1];
- vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2];
- vec[3]= 1.0;
- mul_m4_v4(mat, vec);
-
- fl = 0;
- if (bounds) {
- if (vec[0] < bounds[0] * vec[3]) fl |= 1;
- else if (vec[0] > bounds[1] * vec[3]) fl |= 2;
-
- if (vec[1] > bounds[3] * vec[3]) fl |= 4;
- else if (vec[1] < bounds[2] * vec[3]) fl |= 8;
- }
- else {
- if (vec[0] < -vec[3]) fl |= 1;
- else if (vec[0] > vec[3]) fl |= 2;
-
- if (vec[1] > vec[3]) fl |= 4;
- else if (vec[1] < -vec[3]) fl |= 8;
- }
- if (vec[2] < -vec[3]) fl |= 16;
- else if (vec[2] > vec[3]) fl |= 32;
-
- flag &= fl;
- if (flag == 0) {
- return 0;
- }
- }
-
- return flag;
-}
diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c
deleted file mode 100644
index 3f2ed75f5a4..00000000000
--- a/source/blender/render/intern/source/shadbuf.c
+++ /dev/null
@@ -1,2647 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): 2004-2006, Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/shadbuf.c
- * \ingroup render
- */
-
-
-#include <math.h>
-#include <string.h>
-
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_jitter_2d.h"
-#include "BLI_memarena.h"
-#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_global.h"
-#include "BKE_scene.h"
-
-#include "PIL_time.h"
-
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "rendercore.h"
-#include "shadbuf.h"
-#include "shading.h"
-#include "zbuf.h"
-
-/* XXX, could be better implemented... this is for endian issues */
-#ifdef __BIG_ENDIAN__
-//# define RCOMP 3
-# define GCOMP 2
-# define BCOMP 1
-# define ACOMP 0
-#else
-//# define RCOMP 0
-# define GCOMP 1
-# define BCOMP 2
-# define ACOMP 3
-#endif
-
-#define RCT_SIZE_X(rct) ((rct)->xmax - (rct)->xmin)
-#define RCT_SIZE_Y(rct) ((rct)->ymax - (rct)->ymin)
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* ------------------------------------------------------------------------- */
-
-/* initshadowbuf() in convertBlenderScene.c */
-
-/* ------------------------------------------------------------------------- */
-
-static void copy_to_ztile(int *rectz, int size, int x1, int y1, int tile, char *r1)
-{
- int len4, *rz;
- int x2, y2;
-
- x2= x1+tile;
- y2= y1+tile;
- if (x2>=size) x2= size-1;
- if (y2>=size) y2= size-1;
-
- if (x1>=x2 || y1>=y2) return;
-
- len4= 4*(x2- x1);
- rz= rectz + size*y1 + x1;
- for (; y1<y2; y1++) {
- memcpy(r1, rz, len4);
- rz+= size;
- r1+= len4;
- }
-}
-
-#if 0
-static int sizeoflampbuf(ShadBuf *shb)
-{
- int num, count=0;
- char *cp;
-
- cp= shb->cbuf;
- num= (shb->size*shb->size)/256;
-
- while (num--) count+= *(cp++);
-
- return 256*count;
-}
-#endif
-
-/* not threadsafe... */
-static float *give_jitter_tab(int samp)
-{
- /* these are all possible jitter tables, takes up some
- * 12k, not really bad!
- * For soft shadows, it saves memory and render time
- */
- static int tab[17]={1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256};
- static float jit[1496][2];
- static char ctab[17]= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- int a, offset=0;
-
- if (samp<2) samp= 2;
- else if (samp>16) samp= 16;
-
- for (a=0; a<samp-1; a++) offset+= tab[a];
-
- if (ctab[samp]==0) {
- ctab[samp]= 1;
- BLI_jitter_init((float (*)[2])jit[offset], samp*samp);
- }
-
- return jit[offset];
-
-}
-
-static void make_jitter_weight_tab(Render *re, ShadBuf *shb, short filtertype)
-{
- float *jit, totw= 0.0f;
- int samp= get_render_shadow_samples(&re->r, shb->samp);
- int a, tot=samp*samp;
-
- shb->weight= MEM_mallocN(sizeof(float)*tot, "weight tab lamp");
-
- for (jit= shb->jit, a=0; a<tot; a++, jit+=2) {
- if (filtertype==LA_SHADBUF_TENT)
- shb->weight[a] = 0.71f - sqrtf(jit[0] * jit[0] + jit[1] * jit[1]);
- else if (filtertype==LA_SHADBUF_GAUSS)
- shb->weight[a] = RE_filter_value(R_FILTER_GAUSS, 1.8f * sqrtf(jit[0] * jit[0] + jit[1] * jit[1]));
- else
- shb->weight[a]= 1.0f;
-
- totw+= shb->weight[a];
- }
-
- totw= 1.0f/totw;
- for (a=0; a<tot; a++) {
- shb->weight[a]*= totw;
- }
-}
-
-static int verg_deepsample(const void *poin1, const void *poin2)
-{
- const DeepSample *ds1= (const DeepSample*)poin1;
- const DeepSample *ds2= (const DeepSample*)poin2;
-
- if (ds1->z < ds2->z) return -1;
- else if (ds1->z == ds2->z) return 0;
- else return 1;
-}
-
-static int compress_deepsamples(DeepSample *dsample, int tot, float epsilon)
-{
- /* uses doubles to avoid overflows and other numerical issues,
- * could be improved */
- DeepSample *ds, *newds;
- float v;
- double slope, slopemin, slopemax, min, max, div, newmin, newmax;
- int a, first, z, newtot= 0;
-
-#if 0
- if (print) {
- for (a=0, ds=dsample; a<tot; a++, ds++)
- printf("%lf, %f ", ds->z/(double)0x7FFFFFFF, ds->v);
- printf("\n");
- }
-#endif
-
- /* read from and write into same array */
- ds= dsample;
- newds= dsample;
- a= 0;
-
- /* as long as we are not at the end of the array */
- for (a++, ds++; a<tot; a++, ds++) {
- slopemin= 0.0f;
- slopemax= 0.0f;
- first= 1;
-
- for (; a<tot; a++, ds++) {
- //dz= ds->z - newds->z;
- if (ds->z == newds->z) {
- /* still in same z position, simply check
- * visibility difference against epsilon */
- if (!(fabsf(newds->v - ds->v) <= epsilon)) {
- break;
- }
- }
- else {
- /* compute slopes */
- div= (double)0x7FFFFFFF / ((double)ds->z - (double)newds->z);
- min= (double)((ds->v - epsilon) - newds->v) * div;
- max= (double)((ds->v + epsilon) - newds->v) * div;
-
- /* adapt existing slopes */
- if (first) {
- newmin= min;
- newmax= max;
- first= 0;
- }
- else {
- newmin= MAX2(slopemin, min);
- newmax= MIN2(slopemax, max);
-
- /* verify if there is still space between the slopes */
- if (newmin > newmax) {
- ds--;
- a--;
- break;
- }
- }
-
- slopemin= newmin;
- slopemax= newmax;
- }
- }
-
- if (a == tot) {
- ds--;
- a--;
- }
-
- /* always previous z */
- z= ds->z;
-
- if (first || a==tot-1) {
- /* if slopes were not initialized, use last visibility */
- v= ds->v;
- }
- else {
- /* compute visibility at center between slopes at z */
- slope = (slopemin + slopemax) * 0.5;
- v = (double)newds->v + slope * ((double)(z - newds->z) / (double)0x7FFFFFFF);
- }
-
- newds++;
- newtot++;
-
- newds->z= z;
- newds->v= v;
- }
-
- if (newtot == 0 || (newds->v != (newds-1)->v))
- newtot++;
-
-#if 0
- if (print) {
- for (a=0, ds=dsample; a<newtot; a++, ds++)
- printf("%lf, %f ", ds->z/(double)0x7FFFFFFF, ds->v);
- printf("\n");
- }
-#endif
-
- return newtot;
-}
-
-static float deep_alpha(Render *re, int obinr, int facenr, bool use_strand)
-{
- ObjectInstanceRen *obi= &re->objectinstance[obinr];
- Material *ma;
-
- if (use_strand) {
- StrandRen *strand= RE_findOrAddStrand(obi->obr, facenr-1);
- ma= strand->buffer->ma;
- }
- else {
- VlakRen *vlr= RE_findOrAddVlak(obi->obr, (facenr-1) & RE_QUAD_MASK);
- ma= vlr->mat;
- }
-
- return ma->shad_alpha;
-}
-
-static void compress_deepshadowbuf(Render *re, ShadBuf *shb, APixstr *apixbuf, APixstrand *apixbufstrand)
-{
- ShadSampleBuf *shsample;
- DeepSample *ds[RE_MAX_OSA], *sampleds[RE_MAX_OSA], *dsb, *newbuf;
- APixstr *ap, *apn;
- APixstrand *aps, *apns;
- float visibility;
-
- const int totbuf= shb->totbuf;
- const float totbuf_f= (float)shb->totbuf;
- const float totbuf_f_inv= 1.0f/totbuf_f;
- const int size= shb->size;
-
- int a, b, c, tot, minz, found, prevtot, newtot;
- int sampletot[RE_MAX_OSA], totsample = 0, totsamplec = 0;
-
- shsample= MEM_callocN(sizeof(ShadSampleBuf), "shad sample buf");
- BLI_addtail(&shb->buffers, shsample);
-
- shsample->totbuf = MEM_callocN(sizeof(int) * size * size, "deeptotbuf");
- shsample->deepbuf = MEM_callocN(sizeof(DeepSample *) * size * size, "deepbuf");
-
- ap= apixbuf;
- aps= apixbufstrand;
- for (a=0; a<size*size; a++, ap++, aps++) {
- /* count number of samples */
- for (c=0; c<totbuf; c++)
- sampletot[c]= 0;
-
- tot= 0;
- for (apn=ap; apn; apn=apn->next)
- for (b=0; b<4; b++)
- if (apn->p[b])
- for (c=0; c<totbuf; c++)
- if (apn->mask[b] & (1<<c))
- sampletot[c]++;
-
- if (apixbufstrand) {
- for (apns=aps; apns; apns=apns->next)
- for (b=0; b<4; b++)
- if (apns->p[b])
- for (c=0; c<totbuf; c++)
- if (apns->mask[b] & (1<<c))
- sampletot[c]++;
- }
-
- for (c=0; c<totbuf; c++)
- tot += sampletot[c];
-
- if (tot == 0) {
- shsample->deepbuf[a]= NULL;
- shsample->totbuf[a]= 0;
- continue;
- }
-
- /* fill samples */
- ds[0]= sampleds[0]= MEM_callocN(sizeof(DeepSample)*tot*2, "deepsample");
- for (c=1; c<totbuf; c++)
- ds[c]= sampleds[c]= sampleds[c-1] + sampletot[c-1]*2;
-
- for (apn=ap; apn; apn=apn->next) {
- for (b=0; b<4; b++) {
- if (apn->p[b]) {
- for (c=0; c<totbuf; c++) {
- if (apn->mask[b] & (1<<c)) {
- /* two entries to create step profile */
- ds[c]->z= apn->z[b];
- ds[c]->v= 1.0f; /* not used */
- ds[c]++;
- ds[c]->z= apn->z[b];
- ds[c]->v= deep_alpha(re, apn->obi[b], apn->p[b], 0);
- ds[c]++;
- }
- }
- }
- }
- }
-
- if (apixbufstrand) {
- for (apns=aps; apns; apns=apns->next) {
- for (b=0; b<4; b++) {
- if (apns->p[b]) {
- for (c=0; c<totbuf; c++) {
- if (apns->mask[b] & (1<<c)) {
- /* two entries to create step profile */
- ds[c]->z= apns->z[b];
- ds[c]->v= 1.0f; /* not used */
- ds[c]++;
- ds[c]->z= apns->z[b];
- ds[c]->v= deep_alpha(re, apns->obi[b], apns->p[b], 1);
- ds[c]++;
- }
- }
- }
- }
- }
- }
-
- for (c=0; c<totbuf; c++) {
- /* sort by increasing z */
- qsort(sampleds[c], sampletot[c], sizeof(DeepSample)*2, verg_deepsample);
-
- /* sum visibility, replacing alpha values */
- visibility= 1.0f;
- ds[c]= sampleds[c];
-
- for (b=0; b<sampletot[c]; b++) {
- /* two entries creating step profile */
- ds[c]->v= visibility;
- ds[c]++;
-
- visibility *= 1.0f-ds[c]->v;
- ds[c]->v= visibility;
- ds[c]++;
- }
-
- /* halfway trick, probably won't work well for volumes? */
- ds[c]= sampleds[c];
- for (b=0; b<sampletot[c]; b++) {
- if (b+1 < sampletot[c]) {
- ds[c]->z= (ds[c]->z>>1) + ((ds[c]+2)->z>>1);
- ds[c]++;
- ds[c]->z= (ds[c]->z>>1) + ((ds[c]+2)->z>>1);
- ds[c]++;
- }
- else {
- ds[c]->z= (ds[c]->z>>1) + (0x7FFFFFFF>>1);
- ds[c]++;
- ds[c]->z= (ds[c]->z>>1) + (0x7FFFFFFF>>1);
- ds[c]++;
- }
- }
-
- /* init for merge loop */
- ds[c]= sampleds[c];
- sampletot[c] *= 2;
- }
-
- shsample->deepbuf[a]= MEM_callocN(sizeof(DeepSample)*tot*2, "deepsample");
- shsample->totbuf[a]= 0;
-
- /* merge buffers */
- dsb= shsample->deepbuf[a];
- while (1) {
- minz= 0;
- found= 0;
-
- for (c=0; c<totbuf; c++) {
- if (sampletot[c] && (!found || ds[c]->z < minz)) {
- minz= ds[c]->z;
- found= 1;
- }
- }
-
- if (!found)
- break;
-
- dsb->z= minz;
- dsb->v= 0.0f;
-
- visibility= 0.0f;
- for (c=0; c<totbuf; c++) {
- if (sampletot[c] && ds[c]->z == minz) {
- ds[c]++;
- sampletot[c]--;
- }
-
- if (sampleds[c] == ds[c])
- visibility += totbuf_f_inv;
- else
- visibility += (ds[c]-1)->v / totbuf_f;
- }
-
- dsb->v= visibility;
- dsb++;
- shsample->totbuf[a]++;
- }
-
- prevtot= shsample->totbuf[a];
- totsample += prevtot;
-
- newtot= compress_deepsamples(shsample->deepbuf[a], prevtot, shb->compressthresh);
- shsample->totbuf[a]= newtot;
- totsamplec += newtot;
-
- if (newtot < prevtot) {
- newbuf= MEM_mallocN(sizeof(DeepSample)*newtot, "cdeepsample");
- memcpy(newbuf, shsample->deepbuf[a], sizeof(DeepSample)*newtot);
- MEM_freeN(shsample->deepbuf[a]);
- shsample->deepbuf[a]= newbuf;
- }
-
- MEM_freeN(sampleds[0]);
- }
-
- //printf("%d -> %d, ratio %f\n", totsample, totsamplec, (float)totsamplec/(float)totsample);
-}
-
-/* create Z tiles (for compression): this system is 24 bits!!! */
-static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
-{
- ShadSampleBuf *shsample;
- float dist;
- uintptr_t *ztile;
- int *rz, *rz1, verg, verg1, size= shb->size;
- int a, x, y, minx, miny, byt1, byt2;
- char *rc, *rcline, *ctile, *zt;
-
- shsample= MEM_callocN(sizeof(ShadSampleBuf), "shad sample buf");
- BLI_addtail(&shb->buffers, shsample);
-
- shsample->zbuf= MEM_mallocN(sizeof(uintptr_t)*(size*size)/256, "initshadbuf2");
- shsample->cbuf= MEM_callocN((size*size)/256, "initshadbuf3");
-
- ztile= (uintptr_t *)shsample->zbuf;
- ctile= shsample->cbuf;
-
- /* help buffer */
- rcline= MEM_mallocN(256*4+sizeof(int), "makeshadbuf2");
-
- for (y=0; y<size; y+=16) {
- if (y< size/2) miny= y+15-size/2;
- else miny= y-size/2;
-
- for (x=0; x<size; x+=16) {
-
- /* is tile within spotbundle? */
- a= size/2;
- if (x< a) minx= x+15-a;
- else minx= x-a;
-
- dist = sqrtf((float)(minx * minx + miny * miny));
-
- if (square==0 && dist>(float)(a+12)) { /* 12, tested with a onlyshadow lamp */
- a= 256; verg= 0; /* 0x80000000; */ /* 0x7FFFFFFF; */
- rz1= (&verg)+1;
- }
- else {
- copy_to_ztile(rectz, size, x, y, 16, rcline);
- rz1= (int *)rcline;
-
- verg= (*rz1 & 0xFFFFFF00);
-
- for (a=0;a<256;a++, rz1++) {
- if ( (*rz1 & 0xFFFFFF00) !=verg) break;
- }
- }
- if (a==256) { /* complete empty tile */
- *ctile= 0;
- *ztile= *(rz1-1);
- }
- else {
-
- /* ACOMP etc. are defined to work L/B endian */
-
- rc= rcline;
- rz1= (int *)rcline;
- verg= rc[ACOMP];
- verg1= rc[BCOMP];
- rc+= 4;
- byt1= 1; byt2= 1;
- for (a=1;a<256;a++, rc+=4) {
- byt1 &= (verg==rc[ACOMP]);
- byt2 &= (verg1==rc[BCOMP]);
-
- if (byt1==0) break;
- }
- if (byt1 && byt2) { /* only store byte */
- *ctile= 1;
- *ztile= (uintptr_t)MEM_mallocN(256+4, "tile1");
- rz= (int *)*ztile;
- *rz= *rz1;
-
- zt= (char *)(rz+1);
- rc= rcline;
- for (a=0; a<256; a++, zt++, rc+=4) *zt= rc[GCOMP];
- }
- else if (byt1) { /* only store short */
- *ctile= 2;
- *ztile= (uintptr_t)MEM_mallocN(2*256+4, "Tile2");
- rz= (int *)*ztile;
- *rz= *rz1;
-
- zt= (char *)(rz+1);
- rc= rcline;
- for (a=0; a<256; a++, zt+=2, rc+=4) {
- zt[0]= rc[BCOMP];
- zt[1]= rc[GCOMP];
- }
- }
- else { /* store triple */
- *ctile= 3;
- *ztile= (uintptr_t)MEM_mallocN(3*256, "Tile3");
-
- zt= (char *)*ztile;
- rc= rcline;
- for (a=0; a<256; a++, zt+=3, rc+=4) {
- zt[0]= rc[ACOMP];
- zt[1]= rc[BCOMP];
- zt[2]= rc[GCOMP];
- }
- }
- }
- ztile++;
- ctile++;
- }
- }
-
- MEM_freeN(rcline);
-}
-
-/* sets start/end clipping. lar->shb should be initialized */
-static void shadowbuf_autoclip(Render *re, LampRen *lar)
-{
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr= NULL;
- VertRen *ver= NULL;
- Material *ma= NULL;
- float minz, maxz, vec[3], viewmat[4][4], obviewmat[4][4];
- unsigned int lay = -1;
- int i, a, maxtotvert, ok= 1;
- char *clipflag;
-
- minz= 1.0e30f; maxz= -1.0e30f;
- copy_m4_m4(viewmat, lar->shb->viewmat);
-
- if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
-
- maxtotvert= 0;
- for (obr=re->objecttable.first; obr; obr=obr->next)
- maxtotvert = max_ii(obr->totvert, maxtotvert);
-
- clipflag= MEM_callocN(sizeof(char)*maxtotvert, "autoclipflag");
-
- /* set clip in vertices when face visible */
- for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obviewmat, viewmat, obi->mat);
- else
- copy_m4_m4(obviewmat, viewmat);
-
- memset(clipflag, 0, sizeof(char)*obr->totvert);
-
- /* clear clip, is being set if face is visible (clip is calculated for real later) */
- for (a=0; a<obr->totvlak; a++) {
- if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
- else vlr++;
-
- /* note; these conditions are copied from zbuffer_shadow() */
- if (vlr->mat!= ma) {
- ma= vlr->mat;
- ok= 1;
- if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
- }
-
- if (ok && (obi->lay & lay)) {
- clipflag[vlr->v1->index]= 1;
- clipflag[vlr->v2->index]= 1;
- clipflag[vlr->v3->index]= 1;
- if (vlr->v4) clipflag[vlr->v4->index]= 1;
- }
- }
-
- /* calculate min and max */
- for (a=0; a< obr->totvert;a++) {
- if ((a & 255)==0) ver= RE_findOrAddVert(obr, a);
- else ver++;
-
- if (clipflag[a]) {
- copy_v3_v3(vec, ver->co);
- mul_m4_v3(obviewmat, vec);
- /* Z on visible side of lamp space */
- if (vec[2] < 0.0f) {
- float inpr, z= -vec[2];
-
- /* since vec is rotated in lampspace, this is how to get the cosine of angle */
- /* precision is set 20% larger */
- vec[2]*= 1.2f;
- normalize_v3(vec);
- inpr= - vec[2];
-
- if (inpr>=lar->spotsi) {
- if (z<minz) minz= z;
- if (z>maxz) maxz= z;
- }
- }
- }
- }
- }
-
- MEM_freeN(clipflag);
-
- /* set clipping min and max */
- if (minz < maxz) {
- float delta= (maxz - minz); /* threshold to prevent precision issues */
-
- //printf("minz %f maxz %f delta %f\n", minz, maxz, delta);
- if (lar->bufflag & LA_SHADBUF_AUTO_START)
- lar->shb->d= minz - delta*0.02f; /* 0.02 is arbitrary... needs more thinking! */
- if (lar->bufflag & LA_SHADBUF_AUTO_END)
- lar->shb->clipend= maxz + delta*0.1f;
-
- /* bias was calculated as percentage, we scale it to prevent animation issues */
- delta= (lar->clipend-lar->clipsta)/(lar->shb->clipend-lar->shb->d);
- //printf("bias delta %f\n", delta);
- lar->shb->bias= (int) (delta*(float)lar->shb->bias);
- }
-}
-
-static void makeflatshadowbuf(Render *re, LampRen *lar, float *jitbuf)
-{
- ShadBuf *shb= lar->shb;
- int *rectz, samples;
-
- /* zbuffering */
- rectz= MEM_mapallocN(sizeof(int)*shb->size*shb->size, "makeshadbuf");
-
- for (samples=0; samples<shb->totbuf; samples++) {
- zbuffer_shadow(re, shb->persmat, lar, rectz, shb->size, jitbuf[2*samples], jitbuf[2*samples+1]);
- /* create Z tiles (for compression): this system is 24 bits!!! */
- compress_shadowbuf(shb, rectz, lar->mode & LA_SQUARE);
-
- if (re->test_break(re->tbh))
- break;
- }
-
- MEM_freeN(rectz);
-}
-
-static void makedeepshadowbuf(Render *re, LampRen *lar, float *jitbuf)
-{
- ShadBuf *shb= lar->shb;
- APixstr *apixbuf;
- APixstrand *apixbufstrand= NULL;
- ListBase apsmbase= {NULL, NULL};
-
- /* zbuffering */
- apixbuf= MEM_callocN(sizeof(APixstr)*shb->size*shb->size, "APixbuf");
- if (re->totstrand)
- apixbufstrand= MEM_callocN(sizeof(APixstrand)*shb->size*shb->size, "APixbufstrand");
-
- zbuffer_abuf_shadow(re, lar, shb->persmat, apixbuf, apixbufstrand, &apsmbase, shb->size,
- shb->totbuf, (float(*)[2])jitbuf);
-
- /* create Z tiles (for compression): this system is 24 bits!!! */
- compress_deepshadowbuf(re, shb, apixbuf, apixbufstrand);
-
- MEM_freeN(apixbuf);
- if (apixbufstrand)
- MEM_freeN(apixbufstrand);
- freepsA(&apsmbase);
-}
-
-void makeshadowbuf(Render *re, LampRen *lar)
-{
- ShadBuf *shb= lar->shb;
- float wsize, *jitbuf, twozero[2]= {0.0f, 0.0f}, angle, temp;
-
- if (lar->bufflag & (LA_SHADBUF_AUTO_START|LA_SHADBUF_AUTO_END))
- shadowbuf_autoclip(re, lar);
-
- /* just to enforce identical behavior of all irregular buffers */
- if (lar->buftype==LA_SHADBUF_IRREGULAR)
- shb->size= 1024;
-
- /* matrices and window: in winmat the transformation is being put,
- * transforming from observer view to lamp view, including lamp window matrix */
-
- angle= saacos(lar->spotsi);
- temp = 0.5f * shb->size * cosf(angle) / sinf(angle);
- shb->pixsize= (shb->d)/temp;
- wsize= shb->pixsize*(shb->size/2.0f);
-
- perspective_m4(shb->winmat, -wsize, wsize, -wsize, wsize, shb->d, shb->clipend);
- mul_m4_m4m4(shb->persmat, shb->winmat, shb->viewmat);
-
- if (ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) {
- shb->totbuf= lar->buffers;
-
- /* jitter, weights - not threadsafe! */
- BLI_thread_lock(LOCK_CUSTOM1);
- shb->jit= give_jitter_tab(get_render_shadow_samples(&re->r, shb->samp));
- make_jitter_weight_tab(re, shb, lar->filtertype);
- BLI_thread_unlock(LOCK_CUSTOM1);
-
- if (shb->totbuf==4) jitbuf= give_jitter_tab(2);
- else if (shb->totbuf==9) jitbuf= give_jitter_tab(3);
- else jitbuf= twozero;
-
- /* zbuffering */
- if (lar->buftype == LA_SHADBUF_DEEP) {
- makedeepshadowbuf(re, lar, jitbuf);
- shb->totbuf= 1;
- }
- else
- makeflatshadowbuf(re, lar, jitbuf);
-
- /* printf("lampbuf %d\n", sizeoflampbuf(shb)); */
- }
-}
-
-static void *do_shadow_thread(void *re_v)
-{
- Render *re = (Render *)re_v;
- LampRen *lar;
-
- do {
- BLI_thread_lock(LOCK_CUSTOM1);
- for (lar=re->lampren.first; lar; lar=lar->next) {
- if (lar->shb && !lar->thread_assigned) {
- lar->thread_assigned= 1;
- break;
- }
- }
- BLI_thread_unlock(LOCK_CUSTOM1);
-
- /* if type is irregular, this only sets the perspective matrix and autoclips */
- if (lar) {
- makeshadowbuf(re, lar);
- BLI_thread_lock(LOCK_CUSTOM1);
- lar->thread_ready= 1;
- BLI_thread_unlock(LOCK_CUSTOM1);
- }
- } while (lar && !re->test_break(re->tbh));
-
- return NULL;
-}
-
-static volatile int g_break= 0;
-static int thread_break(void *UNUSED(arg))
-{
- return g_break;
-}
-
-void threaded_makeshadowbufs(Render *re)
-{
- ListBase threads;
- LampRen *lar;
- int a, totthread= 0;
- int (*test_break)(void *);
-
- /* count number of threads to use */
- if (G.is_rendering) {
- for (lar=re->lampren.first; lar; lar= lar->next)
- if (lar->shb)
- totthread++;
-
- totthread = min_ii(totthread, re->r.threads);
- }
- else
- totthread = 1; /* preview render */
-
- if (totthread <= 1) {
- for (lar=re->lampren.first; lar; lar= lar->next) {
- if (re->test_break(re->tbh)) break;
- if (lar->shb) {
- /* if type is irregular, this only sets the perspective matrix and autoclips */
- makeshadowbuf(re, lar);
- }
- }
- }
- else {
- /* swap test break function */
- test_break= re->test_break;
- re->test_break= thread_break;
-
- for (lar=re->lampren.first; lar; lar= lar->next) {
- lar->thread_assigned= 0;
- lar->thread_ready= 0;
- }
-
- BLI_threadpool_init(&threads, do_shadow_thread, totthread);
-
- for (a=0; a<totthread; a++)
- BLI_threadpool_insert(&threads, re);
-
- /* keep rendering as long as there are shadow buffers not ready */
- do {
- if ((g_break=test_break(re->tbh)))
- break;
-
- PIL_sleep_ms(50);
-
- BLI_thread_lock(LOCK_CUSTOM1);
- for (lar=re->lampren.first; lar; lar= lar->next)
- if (lar->shb && !lar->thread_ready)
- break;
- BLI_thread_unlock(LOCK_CUSTOM1);
- } while (lar);
-
- BLI_threadpool_end(&threads);
-
- /* unset threadsafety */
- re->test_break= test_break;
- g_break= 0;
- }
-}
-
-void freeshadowbuf(LampRen *lar)
-{
- if (lar->shb) {
- ShadBuf *shb= lar->shb;
- ShadSampleBuf *shsample;
- int b, v;
-
- for (shsample= shb->buffers.first; shsample; shsample= shsample->next) {
- if (shsample->deepbuf) {
- v= shb->size*shb->size;
- for (b=0; b<v; b++)
- if (shsample->deepbuf[b])
- MEM_freeN(shsample->deepbuf[b]);
-
- MEM_freeN(shsample->deepbuf);
- MEM_freeN(shsample->totbuf);
- }
- else {
- intptr_t *ztile= shsample->zbuf;
- const char *ctile= shsample->cbuf;
-
- v= (shb->size*shb->size)/256;
- for (b=0; b<v; b++, ztile++, ctile++)
- if (*ctile) MEM_freeN((void *) *ztile);
-
- MEM_freeN(shsample->zbuf);
- MEM_freeN(shsample->cbuf);
- }
- }
- BLI_freelistN(&shb->buffers);
-
- if (shb->weight) MEM_freeN(shb->weight);
- MEM_freeN(lar->shb);
-
- lar->shb= NULL;
- }
-}
-
-
-static int firstreadshadbuf(ShadBuf *shb, ShadSampleBuf *shsample, int **rz, int xs, int ys, int nr)
-{
- /* return a 1 if fully compressed shadbuf-tile && z==const */
- int ofs;
- const char *ct;
-
- if (shsample->deepbuf)
- return 0;
-
- /* always test borders of shadowbuffer */
- if (xs<0) xs= 0; else if (xs>=shb->size) xs= shb->size-1;
- if (ys<0) ys= 0; else if (ys>=shb->size) ys= shb->size-1;
-
- /* calc z */
- ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
- ct= shsample->cbuf+ofs;
- if (*ct==0) {
- if (nr==0) {
- *rz= *( (int **)(shsample->zbuf+ofs) );
- return 1;
- }
- else if (*rz!= *( (int **)(shsample->zbuf+ofs) )) return 0;
-
- return 1;
- }
-
- return 0;
-}
-
-static float readdeepvisibility(DeepSample *dsample, int tot, int z, int bias, float *biast)
-{
- DeepSample *ds, *prevds;
- float t;
- int a;
-
- /* tricky stuff here; we use ints which can overflow easily with bias values */
-
- ds= dsample;
- for (a=0; a<tot && (z-bias > ds->z); a++, ds++) {}
-
- if (a == tot) {
- if (biast)
- *biast= 0.0f;
- return (ds-1)->v; /* completely behind all samples */
- }
-
- /* check if this read needs bias blending */
- if (biast) {
- if (z > ds->z)
- *biast= (float)(z - ds->z)/(float)bias;
- else
- *biast= 0.0f;
- }
-
- if (a == 0)
- return 1.0f; /* completely in front of all samples */
-
- /* converting to float early here because ds->z - prevds->z can overflow */
- prevds= ds-1;
- t= ((float)(z-bias) - (float)prevds->z)/((float)ds->z - (float)prevds->z);
- return t*ds->v + (1.0f-t)*prevds->v;
-}
-
-static float readdeepshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs)
-{
- float v, biasv, biast;
- int ofs, tot;
-
- if (zs < - 0x7FFFFE00 + bias)
- return 1.0; /* extreme close to clipstart */
-
- /* calc z */
- ofs= ys*shb->size + xs;
- tot= shsample->totbuf[ofs];
- if (tot == 0)
- return 1.0f;
-
- v= readdeepvisibility(shsample->deepbuf[ofs], tot, zs, bias, &biast);
-
- if (biast != 0.0f) {
- /* in soft bias area */
- biasv = readdeepvisibility(shsample->deepbuf[ofs], tot, zs, 0, NULL);
-
- biast= biast*biast;
- return (1.0f-biast)*v + biast*biasv;
- }
-
- return v;
-}
-
-/* return 1.0 : fully in light */
-static float readshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs)
-{
- float temp;
- int *rz, ofs;
- int zsamp=0;
- char *ct, *cz;
-
- /* simpleclip */
- /* if (xs<0 || ys<0) return 1.0; */
- /* if (xs>=shb->size || ys>=shb->size) return 1.0; */
-
- /* always test borders of shadowbuffer */
- if (xs<0) xs= 0; else if (xs>=shb->size) xs= shb->size-1;
- if (ys<0) ys= 0; else if (ys>=shb->size) ys= shb->size-1;
-
- if (shsample->deepbuf)
- return readdeepshadowbuf(shb, shsample, bias, xs, ys, zs);
-
- /* calc z */
- ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
- ct= shsample->cbuf+ofs;
- rz= *( (int **)(shsample->zbuf+ofs) );
-
- if (*ct==3) {
- ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15);
- cz= (char *)&zsamp;
- cz[ACOMP]= ct[0];
- cz[BCOMP]= ct[1];
- cz[GCOMP]= ct[2];
- }
- else if (*ct==2) {
- ct= ((char *)rz);
- ct+= 4+2*16*(ys & 15)+2*(xs & 15);
- zsamp= *rz;
-
- cz= (char *)&zsamp;
- cz[BCOMP]= ct[0];
- cz[GCOMP]= ct[1];
- }
- else if (*ct==1) {
- ct= ((char *)rz);
- ct+= 4+16*(ys & 15)+(xs & 15);
- zsamp= *rz;
-
- cz= (char *)&zsamp;
- cz[GCOMP]= ct[0];
-
- }
- else {
- /* got warning on this for 64 bits.... */
- /* but it's working code! in this case rz is not a pointer but zvalue (ton) */
- zsamp= POINTER_AS_INT(rz);
- }
-
- /* tricky stuff here; we use ints which can overflow easily with bias values */
-
- if (zsamp > zs) return 1.0; /* absolute no shadow */
- else if (zs < - 0x7FFFFE00 + bias) return 1.0; /* extreme close to clipstart */
- else if (zsamp < zs-bias) return 0.0; /* absolute in shadow */
- else { /* soft area */
-
- temp= ( (float)(zs- zsamp) )/(float)bias;
- return 1.0f - temp*temp;
-
- }
-}
-
-static void shadowbuf_project_co(float *x, float *y, float *z, ShadBuf *shb, const float co[3])
-{
- float hco[4], size= 0.5f*(float)shb->size;
-
- copy_v3_v3(hco, co);
- hco[3]= 1.0f;
-
- mul_m4_v4(shb->persmat, hco);
-
- *x= size*(1.0f+hco[0]/hco[3]);
- *y= size*(1.0f+hco[1]/hco[3]);
- if (z) *z= (hco[2]/hco[3]);
-}
-
-/* the externally called shadow testing (reading) function */
-/* return 1.0: no shadow at all */
-float testshadowbuf(Render *re, ShadBuf *shb, const float co[3], const float dxco[3], const float dyco[3], float inp, float mat_bias)
-{
- ShadSampleBuf *shsample;
- float fac, dco[3], dx[3], dy[3], shadfac=0.0f;
- float xs1, ys1, zs1, *jit, *weight, xres, yres, biasf;
- int xs, ys, zs, bias, *rz;
- short a, num;
-
- /* crash preventer */
- if (shb->buffers.first==NULL)
- return 1.0f;
-
- /* when facing away, assume fully in shadow */
- if (inp <= 0.0f)
- return 0.0f;
-
- /* project coordinate to pixel space */
- shadowbuf_project_co(&xs1, &ys1, &zs1, shb, co);
-
- /* clip z coordinate, z is projected so that (-1.0, 1.0) matches
- * (clipstart, clipend), so we can do this simple test */
- if (zs1>=1.0f)
- return 0.0f;
- else if (zs1<= -1.0f)
- return 1.0f;
-
- zs= ((float)0x7FFFFFFF)*zs1;
-
- /* take num*num samples, increase area with fac */
- num= get_render_shadow_samples(&re->r, shb->samp);
- num= num*num;
- fac= shb->soft;
-
- /* compute z bias */
- if (mat_bias!=0.0f) biasf= shb->bias*mat_bias;
- else biasf= shb->bias;
- /* with inp==1.0, bias is half the size. correction value was 1.1, giving errors
- * on cube edges, with one side being almost frontal lighted (ton) */
- bias= (1.5f-inp*inp)*biasf;
-
- /* in case of no filtering we can do things simpler */
- if (num==1) {
- for (shsample= shb->buffers.first; shsample; shsample= shsample->next)
- shadfac += readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs);
-
- return shadfac/(float)shb->totbuf;
- }
-
- /* calculate filter size */
- add_v3_v3v3(dco, co, dxco);
- shadowbuf_project_co(&dx[0], &dx[1], NULL, shb, dco);
- dx[0]= xs1 - dx[0];
- dx[1]= ys1 - dx[1];
-
- add_v3_v3v3(dco, co, dyco);
- shadowbuf_project_co(&dy[0], &dy[1], NULL, shb, dco);
- dy[0]= xs1 - dy[0];
- dy[1]= ys1 - dy[1];
-
- xres = fac * (fabsf(dx[0]) + fabsf(dy[0]));
- yres = fac * (fabsf(dx[1]) + fabsf(dy[1]));
- if (xres<1.0f) xres= 1.0f;
- if (yres<1.0f) yres= 1.0f;
-
- /* make xs1/xs1 corner of sample area */
- xs1 -= xres*0.5f;
- ys1 -= yres*0.5f;
-
- /* in case we have a constant value in a tile, we can do quicker lookup */
- if (xres<16.0f && yres<16.0f) {
- shsample= shb->buffers.first;
- if (firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)ys1, 0)) {
- if (firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)ys1, 1)) {
- if (firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)(ys1+yres), 1)) {
- if (firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)(ys1+yres), 1)) {
- return readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs);
- }
- }
- }
- }
- }
-
- /* full jittered shadow buffer lookup */
- for (shsample= shb->buffers.first; shsample; shsample= shsample->next) {
- jit= shb->jit;
- weight= shb->weight;
-
- for (a=num; a>0; a--, jit+=2, weight++) {
- /* instead of jit i tried random: ugly! */
- /* note: the plus 0.5 gives best sampling results, jit goes from -0.5 to 0.5 */
- /* xs1 and ys1 are already corrected to be corner of sample area */
- xs= xs1 + xres*(jit[0] + 0.5f);
- ys= ys1 + yres*(jit[1] + 0.5f);
-
- shadfac+= *weight * readshadowbuf(shb, shsample, bias, xs, ys, zs);
- }
- }
-
- /* Renormalizes for the sample number: */
- return shadfac/(float)shb->totbuf;
-}
-
-/* different function... sampling behind clipend can be LIGHT, bias is negative! */
-/* return: light */
-static float readshadowbuf_halo(ShadBuf *shb, ShadSampleBuf *shsample, int xs, int ys, int zs)
-{
- float temp;
- int *rz, ofs;
- int bias, zbias, zsamp;
- char *ct, *cz;
-
- /* negative! The other side is more important */
- bias= -shb->bias;
-
- /* simpleclip */
- if (xs<0 || ys<0) return 0.0;
- if (xs>=shb->size || ys>=shb->size) return 0.0;
-
- /* calc z */
- ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
- ct= shsample->cbuf+ofs;
- rz= *( (int **)(shsample->zbuf+ofs) );
-
- if (*ct==3) {
- ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15);
- cz= (char *)&zsamp;
- zsamp= 0;
- cz[ACOMP]= ct[0];
- cz[BCOMP]= ct[1];
- cz[GCOMP]= ct[2];
- }
- else if (*ct==2) {
- ct= ((char *)rz);
- ct+= 4+2*16*(ys & 15)+2*(xs & 15);
- zsamp= *rz;
-
- cz= (char *)&zsamp;
- cz[BCOMP]= ct[0];
- cz[GCOMP]= ct[1];
- }
- else if (*ct==1) {
- ct= ((char *)rz);
- ct+= 4+16*(ys & 15)+(xs & 15);
- zsamp= *rz;
-
- cz= (char *)&zsamp;
- cz[GCOMP]= ct[0];
-
- }
- else {
- /* same as before */
- /* still working code! (ton) */
- zsamp= POINTER_AS_INT(rz);
- }
-
- /* NO schadow when sampled at 'eternal' distance */
-
- if (zsamp >= 0x7FFFFE00) return 1.0;
-
- if (zsamp > zs) return 1.0; /* absolute no shadww */
- else {
- /* bias is negative, so the (zs-bias) can be beyond 0x7fffffff */
- zbias= 0x7fffffff - zs;
- if (zbias > -bias) {
- if ( zsamp < zs-bias) return 0.0; /* absolute in shadow */
- }
- else return 0.0; /* absolute shadow */
- }
-
- /* soft area */
-
- temp= ( (float)(zs- zsamp) )/(float)bias;
- return 1.0f - temp*temp;
-}
-
-
-float shadow_halo(LampRen *lar, const float p1[3], const float p2[3])
-{
- /* p1 p2 already are rotated in spot-space */
- ShadBuf *shb= lar->shb;
- ShadSampleBuf *shsample;
- float co[4], siz;
- float lambda, lambda_o, lambda_x, lambda_y, ldx, ldy;
- float zf, xf1, yf1, zf1, xf2, yf2, zf2;
- float count, lightcount;
- int x, y, z, xs1, ys1;
- int dx = 0, dy = 0;
-
- siz= 0.5f*(float)shb->size;
-
- co[0]= p1[0];
- co[1]= p1[1];
- co[2]= p1[2]/lar->sh_zfac;
- co[3]= 1.0;
- mul_m4_v4(shb->winmat, co); /* rational hom co */
- xf1= siz*(1.0f+co[0]/co[3]);
- yf1= siz*(1.0f+co[1]/co[3]);
- zf1= (co[2]/co[3]);
-
-
- co[0]= p2[0];
- co[1]= p2[1];
- co[2]= p2[2]/lar->sh_zfac;
- co[3]= 1.0;
- mul_m4_v4(shb->winmat, co); /* rational hom co */
- xf2= siz*(1.0f+co[0]/co[3]);
- yf2= siz*(1.0f+co[1]/co[3]);
- zf2= (co[2]/co[3]);
-
- /* the 2dda (a pixel line formula) */
-
- xs1= (int)xf1;
- ys1= (int)yf1;
-
- if (xf1 != xf2) {
- if (xf2-xf1 > 0.0f) {
- lambda_x= (xf1-xs1-1.0f)/(xf1-xf2);
- ldx= -shb->shadhalostep/(xf1-xf2);
- dx= shb->shadhalostep;
- }
- else {
- lambda_x= (xf1-xs1)/(xf1-xf2);
- ldx= shb->shadhalostep/(xf1-xf2);
- dx= -shb->shadhalostep;
- }
- }
- else {
- lambda_x= 1.0;
- ldx= 0.0;
- }
-
- if (yf1 != yf2) {
- if (yf2-yf1 > 0.0f) {
- lambda_y= (yf1-ys1-1.0f)/(yf1-yf2);
- ldy= -shb->shadhalostep/(yf1-yf2);
- dy= shb->shadhalostep;
- }
- else {
- lambda_y= (yf1-ys1)/(yf1-yf2);
- ldy= shb->shadhalostep/(yf1-yf2);
- dy= -shb->shadhalostep;
- }
- }
- else {
- lambda_y= 1.0;
- ldy= 0.0;
- }
-
- x= xs1;
- y= ys1;
- lambda= count= lightcount= 0.0;
-
-/* printf("start %x %x \n", (int)(0x7FFFFFFF*zf1), (int)(0x7FFFFFFF*zf2)); */
-
- do {
- lambda_o= lambda;
-
- if (lambda_x==lambda_y) {
- lambda_x+= ldx;
- x+= dx;
- lambda_y+= ldy;
- y+= dy;
- }
- else {
- if (lambda_x<lambda_y) {
- lambda_x+= ldx;
- x+= dx;
- }
- else {
- lambda_y+= ldy;
- y+= dy;
- }
- }
-
- lambda = min_ff(lambda_x, lambda_y);
-
- /* not making any progress? */
- if (lambda==lambda_o) break;
-
- /* clip to end of volume */
- lambda = min_ff(lambda, 1.0f);
-
- zf= zf1 + lambda*(zf2-zf1);
- count+= (float)shb->totbuf;
-
- if (zf<= -1.0f) lightcount += 1.0f; /* close to the spot */
- else {
-
- /* make sure, behind the clipend we extend halolines. */
- if (zf>=1.0f) z= 0x7FFFF000;
- else z= (int)(0x7FFFF000*zf);
-
- for (shsample= shb->buffers.first; shsample; shsample= shsample->next)
- lightcount+= readshadowbuf_halo(shb, shsample, x, y, z);
-
- }
- }
- while (lambda < 1.0f);
-
- if (count!=0.0f) return (lightcount/count);
- return 0.0f;
-
-}
-
-
-/* ********************* Irregular Shadow Buffer (ISB) ************* */
-/* ********** storage of all view samples in a raster of lists ***** */
-
-/* based on several articles describing this method, like:
- * The Irregular Z-Buffer and its Application to Shadow Mapping
- * Gregory S. Johnson - William R. Mark - Christopher A. Burns
- * and
- * Alias-Free Shadow Maps
- * Timo Aila and Samuli Laine
- */
-
-/* bsp structure (actually kd tree) */
-
-#define BSPMAX_SAMPLE 128
-#define BSPMAX_DEPTH 32
-
-/* aligned with struct rctf */
-typedef struct Boxf {
- float xmin, xmax;
- float ymin, ymax;
- float zmin, zmax;
-} Boxf;
-
-typedef struct ISBBranch {
- struct ISBBranch *left, *right;
- float divider[2];
- Boxf box;
- short totsamp, index, full, unused;
- ISBSample **samples;
-} ISBBranch;
-
-typedef struct BSPFace {
- Boxf box;
- const float *v1, *v2, *v3, *v4;
- int obi; /* object for face lookup */
- int facenr; /* index to retrieve VlakRen */
- int type; /* only for strand now */
- short shad_alpha, is_full;
-
- /* strand caching data, optimize for point_behind_strand() */
- float radline, radline_end, len;
- float vec1[3], vec2[3], rc[3];
-} BSPFace;
-
-/* boxes are in lamp projection */
-static void init_box(Boxf *box)
-{
- box->xmin = 1000000.0f;
- box->xmax = 0;
- box->ymin = 1000000.0f;
- box->ymax = 0;
- box->zmin= 0x7FFFFFFF;
- box->zmax= - 0x7FFFFFFF;
-}
-
-/* use v1 to calculate boundbox */
-static void bound_boxf(Boxf *box, const float v1[3])
-{
- if (v1[0] < box->xmin) box->xmin = v1[0];
- if (v1[0] > box->xmax) box->xmax = v1[0];
- if (v1[1] < box->ymin) box->ymin = v1[1];
- if (v1[1] > box->ymax) box->ymax = v1[1];
- if (v1[2] < box->zmin) box->zmin= v1[2];
- if (v1[2] > box->zmax) box->zmax= v1[2];
-}
-
-/* use v1 to calculate boundbox */
-static void bound_rectf(rctf *box, const float v1[2])
-{
- if (v1[0] < box->xmin) box->xmin = v1[0];
- if (v1[0] > box->xmax) box->xmax = v1[0];
- if (v1[1] < box->ymin) box->ymin = v1[1];
- if (v1[1] > box->ymax) box->ymax = v1[1];
-}
-
-
-/* halfway splitting, for initializing a more regular tree */
-static void isb_bsp_split_init(ISBBranch *root, MemArena *mem, int level)
-{
-
- /* if level > 0 we create new branches and go deeper */
- if (level > 0) {
- ISBBranch *left, *right;
- int i;
-
- /* splitpoint */
- root->divider[0]= 0.5f*(root->box.xmin+root->box.xmax);
- root->divider[1]= 0.5f*(root->box.ymin+root->box.ymax);
-
- /* find best splitpoint */
- if (RCT_SIZE_X(&root->box) > RCT_SIZE_Y(&root->box))
- i = root->index = 0;
- else
- i = root->index = 1;
-
- left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch));
- right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch));
-
- /* box info */
- left->box= root->box;
- right->box= root->box;
- if (i==0) {
- left->box.xmax = root->divider[0];
- right->box.xmin = root->divider[0];
- }
- else {
- left->box.ymax = root->divider[1];
- right->box.ymin = root->divider[1];
- }
- isb_bsp_split_init(left, mem, level-1);
- isb_bsp_split_init(right, mem, level-1);
- }
- else {
- /* we add sample array */
- root->samples= BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *));
- }
-}
-
-/* note; if all samples on same location we just spread them over 2 new branches */
-static void isb_bsp_split(ISBBranch *root, MemArena *mem)
-{
- ISBBranch *left, *right;
- ISBSample *samples[BSPMAX_SAMPLE];
- int a, i;
-
- /* splitpoint */
- root->divider[0]= root->divider[1]= 0.0f;
- for (a=BSPMAX_SAMPLE-1; a>=0; a--) {
- root->divider[0]+= root->samples[a]->zco[0];
- root->divider[1]+= root->samples[a]->zco[1];
- }
- root->divider[0]/= BSPMAX_SAMPLE;
- root->divider[1]/= BSPMAX_SAMPLE;
-
- /* find best splitpoint */
- if (RCT_SIZE_X(&root->box) > RCT_SIZE_Y(&root->box))
- i = root->index = 0;
- else
- i = root->index = 1;
-
- /* new branches */
- left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch));
- right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch));
-
- /* new sample array */
- left->samples = BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *));
- right->samples = samples; /* tmp */
-
- /* split samples */
- for (a=BSPMAX_SAMPLE-1; a>=0; a--) {
- int comp= 0;
- /* this prevents adding samples all to 1 branch when divider is equal to samples */
- if (root->samples[a]->zco[i] == root->divider[i])
- comp= a & 1;
- else if (root->samples[a]->zco[i] < root->divider[i])
- comp= 1;
-
- if (comp==1) {
- left->samples[left->totsamp]= root->samples[a];
- left->totsamp++;
- }
- else {
- right->samples[right->totsamp]= root->samples[a];
- right->totsamp++;
- }
- }
-
- /* copy samples from tmp */
- memcpy(root->samples, samples, right->totsamp*(sizeof(void *)));
- right->samples= root->samples;
- root->samples= NULL;
-
- /* box info */
- left->box= root->box;
- right->box= root->box;
- if (i==0) {
- left->box.xmax = root->divider[0];
- right->box.xmin = root->divider[0];
- }
- else {
- left->box.ymax = root->divider[1];
- right->box.ymin = root->divider[1];
- }
-}
-
-/* inserts sample in main tree, also splits on threshold */
-/* returns 1 if error */
-static int isb_bsp_insert(ISBBranch *root, MemArena *memarena, ISBSample *sample)
-{
- ISBBranch *bspn= root;
- const float *zco= sample->zco;
- int i= 0;
-
- /* debug counter, also used to check if something was filled in ever */
- root->totsamp++;
-
- /* going over branches until last one found */
- while (bspn->left) {
- if (zco[bspn->index] <= bspn->divider[bspn->index])
- bspn= bspn->left;
- else
- bspn= bspn->right;
- i++;
- }
- /* bspn now is the last branch */
-
- if (bspn->totsamp==BSPMAX_SAMPLE) {
- printf("error in bsp branch\n"); /* only for debug, cannot happen */
- return 1;
- }
-
- /* insert */
- bspn->samples[bspn->totsamp]= sample;
- bspn->totsamp++;
-
- /* split if allowed and needed */
- if (bspn->totsamp==BSPMAX_SAMPLE) {
- if (i==BSPMAX_DEPTH) {
- bspn->totsamp--; /* stop filling in... will give errors */
- return 1;
- }
- isb_bsp_split(bspn, memarena);
- }
- return 0;
-}
-
-/* initialize vars in face, for optimal point-in-face test */
-static void bspface_init_strand(BSPFace *face)
-{
-
- face->radline= 0.5f* len_v2v2(face->v1, face->v2);
-
- mid_v3_v3v3(face->vec1, face->v1, face->v2);
- if (face->v4)
- mid_v3_v3v3(face->vec2, face->v3, face->v4);
- else
- copy_v3_v3(face->vec2, face->v3);
-
- face->rc[0]= face->vec2[0]-face->vec1[0];
- face->rc[1]= face->vec2[1]-face->vec1[1];
- face->rc[2]= face->vec2[2]-face->vec1[2];
-
- face->len= face->rc[0]*face->rc[0]+ face->rc[1]*face->rc[1];
-
- if (face->len != 0.0f) {
- face->radline_end = face->radline / sqrtf(face->len);
- face->len = 1.0f / face->len;
- }
-}
-
-/* brought back to a simple 2d case */
-static int point_behind_strand(const float p[3], BSPFace *face)
-{
- /* v1 - v2 is radius, v1 - v3 length */
- float dist, rc[2], pt[2];
-
- /* using code from dist_to_line_segment_v2(), distance vec to line-piece */
-
- if (face->len==0.0f) {
- rc[0]= p[0]-face->vec1[0];
- rc[1]= p[1]-face->vec1[1];
- dist = len_v2(rc);
-
- if (dist < face->radline)
- return 1;
- }
- else {
- float lambda= ( face->rc[0]*(p[0]-face->vec1[0]) + face->rc[1]*(p[1]-face->vec1[1]) )*face->len;
-
- if (lambda > -face->radline_end && lambda < 1.0f+face->radline_end) {
- /* hesse for dist: */
- //dist= (float)(fabs( (p[0]-vec2[0])*rc[1] + (p[1]-vec2[1])*rc[0])/len);
-
- pt[0]= lambda*face->rc[0]+face->vec1[0];
- pt[1]= lambda*face->rc[1]+face->vec1[1];
-
- rc[0]= pt[0]-p[0];
- rc[1]= pt[1]-p[1];
- dist = len_v2(rc);
-
- if (dist < face->radline) {
- float zval= face->vec1[2] + lambda*face->rc[2];
- if (p[2] > zval)
- return 1;
- }
- }
- }
- return 0;
-}
-
-
-/* return 1 if inside. code derived from src/parametrizer.c */
-static int point_behind_tria2d(const float p[3], const float v1[3], const float v2[3], const float v3[3])
-{
- float a[2], c[2], h[2], div;
- float u, v;
-
- a[0] = v2[0] - v1[0];
- a[1] = v2[1] - v1[1];
- c[0] = v3[0] - v1[0];
- c[1] = v3[1] - v1[1];
-
- div = a[0]*c[1] - a[1]*c[0];
- if (div==0.0f)
- return 0;
-
- h[0] = p[0] - v1[0];
- h[1] = p[1] - v1[1];
-
- div = 1.0f/div;
-
- u = (h[0]*c[1] - h[1]*c[0])*div;
- if (u >= 0.0f) {
- v = (a[0]*h[1] - a[1]*h[0])*div;
- if (v >= 0.0f) {
- if ( u + v <= 1.0f) {
- /* inside, now check if point p is behind */
- float z= (1.0f-u-v)*v1[2] + u*v2[2] + v*v3[2];
- if (z <= p[2])
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-#if 0
-/* tested these calls, but it gives inaccuracy, 'side' cannot be found reliably using v3 */
-
-/* check if line v1-v2 has all rect points on other side of point v3 */
-static int rect_outside_line(rctf *rect, const float v1[3], const float v2[3], const float v3[3])
-{
- float a, b, c;
- int side;
-
- /* line formula for v1-v2 */
- a= v2[1]-v1[1];
- b= v1[0]-v2[0];
- c= -a*v1[0] - b*v1[1];
- side= a*v3[0] + b*v3[1] + c < 0.0f;
-
- /* the four quad points */
- if ( side==(rect->xmin*a + rect->ymin*b + c >= 0.0f) )
- if ( side==(rect->xmax*a + rect->ymin*b + c >= 0.0f) )
- if ( side==(rect->xmax*a + rect->ymax*b + c >= 0.0f) )
- if ( side==(rect->xmin*a + rect->ymax*b + c >= 0.0f) )
- return 1;
- return 0;
-}
-
-/* check if one of the triangle edges separates all rect points on 1 side */
-static int rect_isect_tria(rctf *rect, const float v1[3], const float v2[3], const float v3[3])
-{
- if (rect_outside_line(rect, v1, v2, v3))
- return 0;
- if (rect_outside_line(rect, v2, v3, v1))
- return 0;
- if (rect_outside_line(rect, v3, v1, v2))
- return 0;
- return 1;
-}
-#endif
-
-/* if face overlaps a branch, it executes func. recursive */
-static void isb_bsp_face_inside(ISBBranch *bspn, BSPFace *face)
-{
-
- /* are we descending? */
- if (bspn->left) {
- /* hrmf, the box struct cannot be addressed with index */
- if (bspn->index==0) {
- if (face->box.xmin <= bspn->divider[0])
- isb_bsp_face_inside(bspn->left, face);
- if (face->box.xmax > bspn->divider[0])
- isb_bsp_face_inside(bspn->right, face);
- }
- else {
- if (face->box.ymin <= bspn->divider[1])
- isb_bsp_face_inside(bspn->left, face);
- if (face->box.ymax > bspn->divider[1])
- isb_bsp_face_inside(bspn->right, face);
- }
- }
- else {
- /* else: end branch reached */
- int a;
-
- if (bspn->totsamp==0) return;
-
- /* check for nodes entirely in shadow, can be skipped */
- if (bspn->totsamp==bspn->full)
- return;
-
- /* if bsp node is entirely in front of face, give up */
- if (bspn->box.zmax < face->box.zmin)
- return;
-
- /* if face boundbox is outside of branch rect, give up */
- if (0==BLI_rctf_isect((rctf *)&face->box, (rctf *)&bspn->box, NULL))
- return;
-
- /* test all points inside branch */
- for (a=bspn->totsamp-1; a>=0; a--) {
- ISBSample *samp= bspn->samples[a];
-
- if ((samp->facenr!=face->facenr || samp->obi!=face->obi) && samp->shadfac) {
- if (face->box.zmin < samp->zco[2]) {
- if (BLI_rctf_isect_pt_v((rctf *)&face->box, samp->zco)) {
- int inshadow= 0;
-
- if (face->type) {
- if (point_behind_strand(samp->zco, face))
- inshadow= 1;
- }
- else if ( point_behind_tria2d(samp->zco, face->v1, face->v2, face->v3))
- inshadow= 1;
- else if (face->v4 && point_behind_tria2d(samp->zco, face->v1, face->v3, face->v4))
- inshadow= 1;
-
- if (inshadow) {
- *(samp->shadfac) += face->shad_alpha;
- /* optimize; is_full means shad_alpha==4096 */
- if (*(samp->shadfac) >= 4096 || face->is_full) {
- bspn->full++;
- samp->shadfac= NULL;
- }
- }
- }
- }
- }
- }
- }
-}
-
-/* based on available samples, recalculate the bounding box for bsp nodes, recursive */
-static void isb_bsp_recalc_box(ISBBranch *root)
-{
- if (root->left) {
- isb_bsp_recalc_box(root->left);
- isb_bsp_recalc_box(root->right);
- }
- else if (root->totsamp) {
- int a;
-
- init_box(&root->box);
- for (a=root->totsamp-1; a>=0; a--)
- bound_boxf(&root->box, root->samples[a]->zco);
- }
-}
-
-/* callback function for zbuf clip */
-static void isb_bsp_test_strand(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- BSPFace face;
-
- face.v1= v1;
- face.v2= v2;
- face.v3= v3;
- face.v4= v4;
- face.obi= obi;
- face.facenr= zvlnr & ~RE_QUAD_OFFS;
- face.type= R_STRAND;
- if (R.osa)
- face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa);
- else
- face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha);
-
- face.is_full= (zspan->shad_alpha==1.0f);
-
- /* setup boundbox */
- init_box(&face.box);
- bound_boxf(&face.box, v1);
- bound_boxf(&face.box, v2);
- bound_boxf(&face.box, v3);
- if (v4)
- bound_boxf(&face.box, v4);
-
- /* optimize values */
- bspface_init_strand(&face);
-
- isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face);
-
-}
-
-/* callback function for zbuf clip */
-static void isb_bsp_test_face(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- BSPFace face;
-
- face.v1= v1;
- face.v2= v2;
- face.v3= v3;
- face.v4= v4;
- face.obi= obi;
- face.facenr= zvlnr & ~RE_QUAD_OFFS;
- face.type= 0;
- if (R.osa)
- face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa);
- else
- face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha);
-
- face.is_full= (zspan->shad_alpha==1.0f);
-
- /* setup boundbox */
- init_box(&face.box);
- bound_boxf(&face.box, v1);
- bound_boxf(&face.box, v2);
- bound_boxf(&face.box, v3);
- if (v4)
- bound_boxf(&face.box, v4);
-
- isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face);
-}
-
-static int testclip_minmax(const float ho[4], const float minmax[4])
-{
- float wco= ho[3];
- int flag= 0;
-
- if ( ho[0] > minmax[1]*wco) flag = 1;
- else if ( ho[0]< minmax[0]*wco) flag = 2;
-
- if ( ho[1] > minmax[3]*wco) flag |= 4;
- else if ( ho[1]< minmax[2]*wco) flag |= 8;
-
- return flag;
-}
-
-/* main loop going over all faces and check in bsp overlaps, fill in shadfac values */
-static void isb_bsp_fillfaces(Render *re, LampRen *lar, ISBBranch *root)
-{
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- ShadBuf *shb= lar->shb;
- ZSpan zspan, zspanstrand;
- VlakRen *vlr= NULL;
- Material *ma= NULL;
- float minmaxf[4], winmat[4][4];
- int size= shb->size;
- int i, a, ok=1, lay= -1;
-
- /* further optimize, also sets minz maxz */
- isb_bsp_recalc_box(root);
-
- /* extra clipping for minmax */
- minmaxf[0]= (2.0f*root->box.xmin - size-2.0f)/size;
- minmaxf[1]= (2.0f*root->box.xmax - size+2.0f)/size;
- minmaxf[2]= (2.0f*root->box.ymin - size-2.0f)/size;
- minmaxf[3]= (2.0f*root->box.ymax - size+2.0f)/size;
-
- if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
-
- /* (ab)use zspan, since we use zbuffer clipping code */
- zbuf_alloc_span(&zspan, size, size, re->clipcrop);
-
- zspan.zmulx= ((float)size)/2.0f;
- zspan.zmuly= ((float)size)/2.0f;
- zspan.zofsx= -0.5f;
- zspan.zofsy= -0.5f;
-
- /* pass on bsp root to zspan */
- zspan.rectz= (int *)root;
-
- /* filling methods */
- zspanstrand= zspan;
- // zspan.zbuflinefunc= zbufline_onlyZ;
- zspan.zbuffunc= isb_bsp_test_face;
- zspanstrand.zbuffunc= isb_bsp_test_strand;
-
- for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(winmat, shb->persmat, obi->mat);
- else
- copy_m4_m4(winmat, shb->persmat);
-
- for (a=0; a<obr->totvlak; a++) {
-
- if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
- else vlr++;
-
- /* note, these conditions are copied in shadowbuf_autoclip() */
- if (vlr->mat!= ma) {
- ma= vlr->mat;
- ok= 1;
- if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
- if (ma->material_type == MA_TYPE_WIRE) ok= 0;
- zspanstrand.shad_alpha= zspan.shad_alpha= ma->shad_alpha;
- }
-
- if (ok && (obi->lay & lay)) {
- float hoco[4][4];
- int c1, c2, c3, c4=0;
- int d1, d2, d3, d4=0;
- int partclip;
-
- /* create hocos per face, it is while render */
- projectvert(vlr->v1->co, winmat, hoco[0]); d1= testclip_minmax(hoco[0], minmaxf);
- projectvert(vlr->v2->co, winmat, hoco[1]); d2= testclip_minmax(hoco[1], minmaxf);
- projectvert(vlr->v3->co, winmat, hoco[2]); d3= testclip_minmax(hoco[2], minmaxf);
- if (vlr->v4) {
- projectvert(vlr->v4->co, winmat, hoco[3]); d4= testclip_minmax(hoco[3], minmaxf);
- }
-
- /* minmax clipping */
- if (vlr->v4) partclip= d1 & d2 & d3 & d4;
- else partclip= d1 & d2 & d3;
-
- if (partclip==0) {
-
- /* window clipping */
- c1= testclip(hoco[0]);
- c2= testclip(hoco[1]);
- c3= testclip(hoco[2]);
- if (vlr->v4)
- c4= testclip(hoco[3]);
-
- /* ***** NO WIRE YET */
- if (ma->material_type == MA_TYPE_WIRE) {
- if (vlr->v4)
- zbufclipwire(&zspan, i, a+1, vlr->ec, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
- else
- zbufclipwire(&zspan, i, a+1, vlr->ec, hoco[0], hoco[1], hoco[2], NULL, c1, c2, c3, 0);
- }
- else if (vlr->v4) {
- if (vlr->flag & R_STRAND)
- zbufclip4(&zspanstrand, i, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
- else
- zbufclip4(&zspan, i, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
- }
- else
- zbufclip(&zspan, i, a+1, hoco[0], hoco[1], hoco[2], c1, c2, c3);
-
- }
- }
- }
- }
-
- zbuf_free_span(&zspan);
-}
-
-/* returns 1 when the viewpixel is visible in lampbuffer */
-static int viewpixel_to_lampbuf(ShadBuf *shb, ObjectInstanceRen *obi, VlakRen *vlr, float x, float y, float co_r[3])
-{
- float hoco[4], v1[3], nor[3];
- float dface, fac, siz;
-
- RE_vlakren_get_normal(&R, obi, vlr, nor);
- copy_v3_v3(v1, vlr->v1->co);
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, v1);
-
- /* from shadepixel() */
- dface = dot_v3v3(v1, nor);
- hoco[3]= 1.0f;
-
- /* ortho viewplane cannot intersect using view vector originating in (0, 0, 0) */
- if (R.r.mode & R_ORTHO) {
- /* x and y 3d coordinate can be derived from pixel coord and winmat */
- float fx= 2.0f/(R.winx*R.winmat[0][0]);
- float fy= 2.0f/(R.winy*R.winmat[1][1]);
-
- hoco[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
- hoco[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
-
- /* using a*x + b*y + c*z = d equation, (a b c) is normal */
- if (nor[2]!=0.0f)
- hoco[2]= (dface - nor[0]*hoco[0] - nor[1]*hoco[1])/nor[2];
- else
- hoco[2]= 0.0f;
- }
- else {
- float div, view[3];
-
- calc_view_vector(view, x, y);
-
- div = dot_v3v3(nor, view);
- if (div==0.0f)
- return 0;
-
- fac= dface/div;
-
- hoco[0]= fac*view[0];
- hoco[1]= fac*view[1];
- hoco[2]= fac*view[2];
- }
-
- /* move 3d vector to lampbuf */
- mul_m4_v4(shb->persmat, hoco); /* rational hom co */
-
- /* clip We can test for -1.0/1.0 because of the properties of the
- * coordinate transformations. */
- fac = fabsf(hoco[3]);
- if (hoco[0]<-fac || hoco[0]>fac)
- return 0;
- if (hoco[1]<-fac || hoco[1]>fac)
- return 0;
- if (hoco[2]<-fac || hoco[2]>fac)
- return 0;
-
- siz= 0.5f*(float)shb->size;
- co_r[0]= siz*(1.0f+hoco[0]/hoco[3]) -0.5f;
- co_r[1]= siz*(1.0f+hoco[1]/hoco[3]) -0.5f;
- co_r[2]= ((float)0x7FFFFFFF)*(hoco[2]/hoco[3]);
-
- /* XXXX bias, much less than normal shadbuf, or do we need a constant? */
- co_r[2] -= 0.05f*shb->bias;
-
- return 1;
-}
-
-/* storage of shadow results, solid osa and transp case */
-static void isb_add_shadfac(ISBShadfacA **isbsapp, MemArena *mem, int obi, int facenr, short shadfac, short samples)
-{
- ISBShadfacA *new;
- float shadfacf;
-
- /* in osa case, the samples were filled in with factor 1.0/R.osa. if fewer samples we have to correct */
- if (R.osa)
- shadfacf= ((float)shadfac*R.osa)/(4096.0f*samples);
- else
- shadfacf= ((float)shadfac)/(4096.0f);
-
- new= BLI_memarena_alloc(mem, sizeof(ISBShadfacA));
- new->obi= obi;
- new->facenr= facenr & ~RE_QUAD_OFFS;
- new->shadfac= shadfacf;
- if (*isbsapp)
- new->next= (*isbsapp);
- else
- new->next= NULL;
-
- *isbsapp= new;
-}
-
-/* adding samples, solid case */
-static int isb_add_samples(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSample **samplebuf)
-{
- int xi, yi, *xcos, *ycos;
- int sample, bsp_err= 0;
-
- /* bsp split doesn't like to handle regular sequences */
- xcos= MEM_mallocN(pa->rectx*sizeof(int), "xcos");
- ycos= MEM_mallocN(pa->recty*sizeof(int), "ycos");
- for (xi=0; xi<pa->rectx; xi++)
- xcos[xi]= xi;
- for (yi=0; yi<pa->recty; yi++)
- ycos[yi]= yi;
- BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345);
- BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321);
-
- for (sample=0; sample<(R.osa?R.osa:1); sample++) {
- ISBSample *samp= samplebuf[sample], *samp1;
-
- for (yi=0; yi<pa->recty; yi++) {
- int y= ycos[yi];
- for (xi=0; xi<pa->rectx; xi++) {
- int x= xcos[xi];
- samp1= samp + y*pa->rectx + x;
- if (samp1->facenr)
- bsp_err |= isb_bsp_insert(root, memarena, samp1);
- }
- if (bsp_err) break;
- }
- }
-
- MEM_freeN(xcos);
- MEM_freeN(ycos);
-
- return bsp_err;
-}
-
-/* solid version */
-/* lar->shb, pa->rectz and pa->rectp should exist */
-static void isb_make_buffer(RenderPart *pa, LampRen *lar)
-{
- ShadBuf *shb= lar->shb;
- ISBData *isbdata;
- ISBSample *samp, *samplebuf[16]; /* should be RE_MAX_OSA */
- ISBBranch root;
- MemArena *memarena;
- intptr_t *rd;
- int *recto, *rectp, x, y, sindex, sample, bsp_err=0;
-
- /* storage for shadow, per thread */
- isbdata= shb->isb_result[pa->thread];
-
- /* to map the shi->xs and ys coordinate */
- isbdata->minx= pa->disprect.xmin;
- isbdata->miny= pa->disprect.ymin;
- isbdata->rectx= pa->rectx;
- isbdata->recty= pa->recty;
-
- /* branches are added using memarena (32k branches) */
- memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch), "isb arena");
- BLI_memarena_use_calloc(memarena);
-
- /* samplebuf is in camera view space (pixels) */
- for (sample=0; sample<(R.osa?R.osa:1); sample++)
- samplebuf[sample]= MEM_callocN(sizeof(ISBSample)*pa->rectx*pa->recty, "isb samplebuf");
-
- /* for end result, ISBSamples point to this in non OSA case, otherwise to pixstruct->shadfac */
- if (R.osa==0)
- isbdata->shadfacs= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "isb shadfacs");
-
- /* setup bsp root */
- memset(&root, 0, sizeof(ISBBranch));
- root.box.xmin = (float)shb->size;
- root.box.ymin = (float)shb->size;
-
- /* create the sample buffers */
- for (sindex=0, y=0; y<pa->recty; y++) {
- for (x=0; x<pa->rectx; x++, sindex++) {
-
- /* this makes it a long function, but splitting it out would mean 10+ arguments */
- /* first check OSA case */
- if (R.osa) {
- rd= pa->rectdaps + sindex;
- if (*rd) {
- float xs= (float)(x + pa->disprect.xmin);
- float ys= (float)(y + pa->disprect.ymin);
-
- for (sample=0; sample<R.osa; sample++) {
- PixStr *ps= (PixStr *)(*rd);
- int mask= (1<<sample);
-
- while (ps) {
- if (ps->mask & mask)
- break;
- ps= ps->next;
- }
- if (ps && ps->facenr>0) {
- ObjectInstanceRen *obi= &R.objectinstance[ps->obi];
- ObjectRen *obr= obi->obr;
- VlakRen *vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK);
-
- samp= samplebuf[sample] + sindex;
- /* convert image plane pixel location to lamp buffer space */
- if (viewpixel_to_lampbuf(shb, obi, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], samp->zco)) {
- samp->obi= ps->obi;
- samp->facenr= ps->facenr & ~RE_QUAD_OFFS;
- ps->shadfac= 0;
- samp->shadfac= &ps->shadfac;
- bound_rectf((rctf *)&root.box, samp->zco);
- }
- }
- }
- }
- }
- else {
- rectp= pa->rectp + sindex;
- recto= pa->recto + sindex;
- if (*rectp>0) {
- ObjectInstanceRen *obi= &R.objectinstance[*recto];
- ObjectRen *obr= obi->obr;
- VlakRen *vlr= RE_findOrAddVlak(obr, (*rectp-1) & RE_QUAD_MASK);
- float xs= (float)(x + pa->disprect.xmin);
- float ys= (float)(y + pa->disprect.ymin);
-
- samp= samplebuf[0] + sindex;
- /* convert image plane pixel location to lamp buffer space */
- if (viewpixel_to_lampbuf(shb, obi, vlr, xs, ys, samp->zco)) {
- samp->obi= *recto;
- samp->facenr= *rectp & ~RE_QUAD_OFFS;
- samp->shadfac= isbdata->shadfacs + sindex;
- bound_rectf((rctf *)&root.box, samp->zco);
- }
- }
- }
- }
- }
-
- /* simple method to see if we have samples */
- if (root.box.xmin != (float)shb->size) {
- /* now create a regular split, root.box has the initial bounding box of all pixels */
- /* split bsp 8 levels deep, in regular grid (16 x 16) */
- isb_bsp_split_init(&root, memarena, 8);
-
- /* insert all samples in BSP now */
- bsp_err= isb_add_samples(pa, &root, memarena, samplebuf);
-
- if (bsp_err==0) {
- /* go over all faces and fill in shadow values */
-
- isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */
-
- /* copy shadow samples to persistent buffer, reduce memory overhead */
- if (R.osa) {
- ISBShadfacA **isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs");
-
- isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA), "isb arena");
- BLI_memarena_use_calloc(isbdata->memarena);
-
- for (rd= pa->rectdaps, x=pa->rectx*pa->recty; x>0; x--, rd++, isbsa++) {
-
- if (*rd) {
- PixStr *ps= (PixStr *)(*rd);
- while (ps) {
- if (ps->shadfac)
- isb_add_shadfac(isbsa, isbdata->memarena, ps->obi, ps->facenr, ps->shadfac, count_mask(ps->mask));
- ps= ps->next;
- }
- }
- }
- }
- }
- }
- else {
- if (isbdata->shadfacs) {
- MEM_freeN(isbdata->shadfacs);
- isbdata->shadfacs= NULL;
- }
- }
-
- /* free BSP */
- BLI_memarena_free(memarena);
-
- /* free samples */
- for (x=0; x<(R.osa?R.osa:1); x++)
- MEM_freeN(samplebuf[x]);
-
- if (bsp_err) printf("error in filling bsp\n");
-}
-
-/* add sample to buffer, isbsa is the root sample in a buffer */
-static ISBSampleA *isb_alloc_sample_transp(ISBSampleA **isbsa, MemArena *mem)
-{
- ISBSampleA *new;
-
- new= BLI_memarena_alloc(mem, sizeof(ISBSampleA));
- if (*isbsa)
- new->next= (*isbsa);
- else
- new->next= NULL;
-
- *isbsa= new;
- return new;
-}
-
-/* adding samples in BSP, transparent case */
-static int isb_add_samples_transp(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSampleA ***samplebuf)
-{
- int xi, yi, *xcos, *ycos;
- int sample, bsp_err= 0;
-
- /* bsp split doesn't like to handle regular sequences */
- xcos= MEM_mallocN(pa->rectx*sizeof(int), "xcos");
- ycos= MEM_mallocN(pa->recty*sizeof(int), "ycos");
- for (xi=0; xi<pa->rectx; xi++)
- xcos[xi]= xi;
- for (yi=0; yi<pa->recty; yi++)
- ycos[yi]= yi;
- BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345);
- BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321);
-
- for (sample=0; sample<(R.osa?R.osa:1); sample++) {
- ISBSampleA **samp= samplebuf[sample], *samp1;
-
- for (yi=0; yi<pa->recty; yi++) {
- int y= ycos[yi];
- for (xi=0; xi<pa->rectx; xi++) {
- int x= xcos[xi];
-
- samp1= *(samp + y*pa->rectx + x);
- while (samp1) {
- bsp_err |= isb_bsp_insert(root, memarena, (ISBSample *)samp1);
- samp1= samp1->next;
- }
- }
- if (bsp_err) break;
- }
- }
-
- MEM_freeN(xcos);
- MEM_freeN(ycos);
-
- return bsp_err;
-}
-
-
-/* Ztransp version */
-/* lar->shb, pa->rectz and pa->rectp should exist */
-static void isb_make_buffer_transp(RenderPart *pa, APixstr *apixbuf, LampRen *lar)
-{
- ShadBuf *shb= lar->shb;
- ISBData *isbdata;
- ISBSampleA *samp, **samplebuf[16]; /* MAX_OSA */
- ISBBranch root;
- MemArena *memarena;
- APixstr *ap;
- int x, y, sindex, sample, bsp_err=0;
-
- /* storage for shadow, per thread */
- isbdata= shb->isb_result[pa->thread];
-
- /* to map the shi->xs and ys coordinate */
- isbdata->minx= pa->disprect.xmin;
- isbdata->miny= pa->disprect.ymin;
- isbdata->rectx= pa->rectx;
- isbdata->recty= pa->recty;
-
- /* branches are added using memarena (32k branches) */
- memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch), "isb arena");
- BLI_memarena_use_calloc(memarena);
-
- /* samplebuf is in camera view space (pixels) */
- for (sample=0; sample<(R.osa?R.osa:1); sample++)
- samplebuf[sample]= MEM_callocN(sizeof(void *)*pa->rectx*pa->recty, "isb alpha samplebuf");
-
- /* setup bsp root */
- memset(&root, 0, sizeof(ISBBranch));
- root.box.xmin = (float)shb->size;
- root.box.ymin = (float)shb->size;
-
- /* create the sample buffers */
- for (ap= apixbuf, sindex=0, y=0; y<pa->recty; y++) {
- for (x=0; x<pa->rectx; x++, sindex++, ap++) {
-
- if (ap->p[0]) {
- APixstr *apn;
- float xs= (float)(x + pa->disprect.xmin);
- float ys= (float)(y + pa->disprect.ymin);
-
- for (apn=ap; apn; apn= apn->next) {
- int a;
- for (a=0; a<4; a++) {
- if (apn->p[a]) {
- ObjectInstanceRen *obi= &R.objectinstance[apn->obi[a]];
- ObjectRen *obr= obi->obr;
- VlakRen *vlr= RE_findOrAddVlak(obr, (apn->p[a]-1) & RE_QUAD_MASK);
- float zco[3];
-
- /* here we store shadfac, easier to create the end storage buffer. needs zero'ed, multiple shadowbufs use it */
- apn->shadfac[a]= 0;
-
- if (R.osa) {
- for (sample=0; sample<R.osa; sample++) {
- int mask= (1<<sample);
-
- if (apn->mask[a] & mask) {
-
- /* convert image plane pixel location to lamp buffer space */
- if (viewpixel_to_lampbuf(shb, obi, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], zco)) {
- samp= isb_alloc_sample_transp(samplebuf[sample] + sindex, memarena);
- samp->obi= apn->obi[a];
- samp->facenr= apn->p[a] & ~RE_QUAD_OFFS;
- samp->shadfac= &apn->shadfac[a];
-
- copy_v3_v3(samp->zco, zco);
- bound_rectf((rctf *)&root.box, samp->zco);
- }
- }
- }
- }
- else {
-
- /* convert image plane pixel location to lamp buffer space */
- if (viewpixel_to_lampbuf(shb, obi, vlr, xs, ys, zco)) {
-
- samp= isb_alloc_sample_transp(samplebuf[0] + sindex, memarena);
- samp->obi= apn->obi[a];
- samp->facenr= apn->p[a] & ~RE_QUAD_OFFS;
- samp->shadfac= &apn->shadfac[a];
-
- copy_v3_v3(samp->zco, zco);
- bound_rectf((rctf *)&root.box, samp->zco);
- }
- }
- }
- }
- }
- }
- }
- }
-
- /* simple method to see if we have samples */
- if (root.box.xmin != (float)shb->size) {
- /* now create a regular split, root.box has the initial bounding box of all pixels */
- /* split bsp 8 levels deep, in regular grid (16 x 16) */
- isb_bsp_split_init(&root, memarena, 8);
-
- /* insert all samples in BSP now */
- bsp_err= isb_add_samples_transp(pa, &root, memarena, samplebuf);
-
- if (bsp_err==0) {
- ISBShadfacA **isbsa;
-
- /* go over all faces and fill in shadow values */
- isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */
-
- /* copy shadow samples to persistent buffer, reduce memory overhead */
- isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs");
-
- isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA), "isb arena");
-
- for (ap= apixbuf, x=pa->rectx*pa->recty; x>0; x--, ap++, isbsa++) {
-
- if (ap->p[0]) {
- APixstr *apn;
- for (apn=ap; apn; apn= apn->next) {
- int a;
- for (a=0; a<4; a++) {
- if (apn->p[a] && apn->shadfac[a]) {
- if (R.osa)
- isb_add_shadfac(isbsa, isbdata->memarena, apn->obi[a], apn->p[a], apn->shadfac[a], count_mask(apn->mask[a]));
- else
- isb_add_shadfac(isbsa, isbdata->memarena, apn->obi[a], apn->p[a], apn->shadfac[a], 0);
- }
- }
- }
- }
- }
- }
- }
-
- /* free BSP */
- BLI_memarena_free(memarena);
-
- /* free samples */
- for (x=0; x<(R.osa?R.osa:1); x++)
- MEM_freeN(samplebuf[x]);
-
- if (bsp_err) printf("error in filling bsp\n");
-}
-
-
-
-/* exported */
-
-/* returns amount of light (1.0 = no shadow) */
-/* note, shadepixel() rounds the coordinate, not the real sample info */
-float ISB_getshadow(ShadeInput *shi, ShadBuf *shb)
-{
- /* if raytracing, we can't accept irregular shadow */
- if (shi->depth==0) {
- ISBData *isbdata= shb->isb_result[shi->thread];
-
- if (isbdata) {
- if (isbdata->shadfacs || isbdata->shadfaca) {
- int x= shi->xs - isbdata->minx;
-
- if (x >= 0 && x < isbdata->rectx) {
- int y= shi->ys - isbdata->miny;
-
- if (y >= 0 && y < isbdata->recty) {
- if (isbdata->shadfacs) {
- const short *sp= isbdata->shadfacs + y*isbdata->rectx + x;
- return *sp>=4096?0.0f:1.0f - ((float)*sp)/4096.0f;
- }
- else {
- int sindex= y*isbdata->rectx + x;
- int obi= shi->obi - R.objectinstance;
- ISBShadfacA *isbsa= *(isbdata->shadfaca + sindex);
-
- while (isbsa) {
- if (isbsa->facenr==shi->facenr+1 && isbsa->obi==obi)
- return isbsa->shadfac>=1.0f?0.0f:1.0f - isbsa->shadfac;
- isbsa= isbsa->next;
- }
- }
- }
- }
- }
- }
- }
- return 1.0f;
-}
-
-/* part is supposed to be solid zbuffered (apixbuf==NULL) or transparent zbuffered */
-void ISB_create(RenderPart *pa, APixstr *apixbuf)
-{
- GroupObject *go;
-
- /* go over all lamps, and make the irregular buffers */
- for (go=R.lights.first; go; go= go->next) {
- LampRen *lar= go->lampren;
-
- if (lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) {
-
- /* create storage for shadow, per thread */
- lar->shb->isb_result[pa->thread]= MEM_callocN(sizeof(ISBData), "isb data");
-
- if (apixbuf)
- isb_make_buffer_transp(pa, apixbuf, lar);
- else
- isb_make_buffer(pa, lar);
- }
- }
-}
-
-
-/* end of part rendering, free stored shadow data for this thread from all lamps */
-void ISB_free(RenderPart *pa)
-{
- GroupObject *go;
-
- /* go over all lamps, and free the irregular buffers */
- for (go=R.lights.first; go; go= go->next) {
- LampRen *lar= go->lampren;
-
- if (lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) {
- ISBData *isbdata= lar->shb->isb_result[pa->thread];
-
- if (isbdata) {
- if (isbdata->shadfacs)
- MEM_freeN(isbdata->shadfacs);
- if (isbdata->shadfaca)
- MEM_freeN(isbdata->shadfaca);
-
- if (isbdata->memarena)
- BLI_memarena_free(isbdata->memarena);
-
- MEM_freeN(isbdata);
- lar->shb->isb_result[pa->thread]= NULL;
- }
- }
- }
-}
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
deleted file mode 100644
index 407f0b14578..00000000000
--- a/source/blender/render/intern/source/shadeinput.c
+++ /dev/null
@@ -1,1489 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributors: Hos, Robert Wenzlaff.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/shadeinput.c
- * \ingroup render
- */
-
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_lamp_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_material_types.h"
-#include "DNA_particle_types.h"
-
-#include "BKE_scene.h"
-
-#include "BKE_node.h"
-
-/* local include */
-#include "raycounter.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "rendercore.h"
-#include "shading.h"
-#include "strand.h"
-#include "texture.h"
-#include "volumetric.h"
-#include "zbuf.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* Shade Sample order:
- *
- * - shade_samples_fill_with_ps()
- * - for each sample
- * - shade_input_set_triangle() <- if prev sample-face is same, use shade_input_copy_triangle()
- * - if vlr
- * - shade_input_set_viewco() <- not for ray or bake
- * - shade_input_set_uv() <- not for ray or bake
- * - shade_input_set_normals()
- * - shade_samples()
- * - if AO
- * - shade_samples_do_AO()
- * - if shading happens
- * - for each sample
- * - shade_input_set_shade_texco()
- * - shade_samples_do_shade()
- * - OSA: distribute sample result with filter masking
- *
- */
-
-/* initialize material variables in shadeinput,
- * doing inverse gamma correction where applicable */
-void shade_input_init_material(ShadeInput *shi)
-{
- /* note, keep this synced with render_types.h */
- memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float));
- shi->har = shi->mat->har;
-}
-
-/* also used as callback for nodes */
-/* delivers a fully filled in ShadeResult, for all passes */
-void shade_material_loop(ShadeInput *shi, ShadeResult *shr)
-{
-
- shade_lamp_loop(shi, shr); /* clears shr */
-
- if (shi->translucency != 0.0f) {
- ShadeResult shr_t;
- float fac = shi->translucency;
-
- shade_input_init_material(shi);
- negate_v3_v3(shi->vn, shi->vno);
- negate_v3(shi->facenor);
- shi->depth++; /* hack to get real shadow now */
- shade_lamp_loop(shi, &shr_t);
- shi->depth--;
-
- /* a couple of passes */
- madd_v3_v3fl(shr->combined, shr_t.combined, fac);
- if (shi->passflag & SCE_PASS_SPEC)
- madd_v3_v3fl(shr->spec, shr_t.spec, fac);
- if (shi->passflag & SCE_PASS_DIFFUSE) {
- madd_v3_v3fl(shr->diff, shr_t.diff, fac);
- madd_v3_v3fl(shr->diffshad, shr_t.diffshad, fac);
- }
- if (shi->passflag & SCE_PASS_SHADOW)
- madd_v3_v3fl(shr->shad, shr_t.shad, fac);
-
- negate_v3(shi->vn);
- negate_v3(shi->facenor);
- }
-
- /* depth >= 1 when ray-shading */
- if (shi->depth == 0 || shi->volume_depth > 0) {
- if (R.r.mode & R_RAYTRACE) {
- if (shi->ray_mirror != 0.0f || ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP) && shr->alpha != 1.0f)) {
- /* ray trace works on combined, but gives pass info */
- ray_trace(shi, shr);
- }
- }
- /* disable adding of sky for raytransp */
- if ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP))
- if ((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode == R_ADDSKY))
- shr->alpha = 1.0f;
- }
-
- if (R.r.mode & R_RAYTRACE) {
- if (R.render_volumes_inside.first)
- shade_volume_inside(shi, shr);
- }
-}
-
-
-/* do a shade, finish up some passes, apply mist */
-void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
-{
- bool compat = false;
- float alpha;
-
- /* ------ main shading loop -------- */
-#ifdef RE_RAYCOUNTER
- memset(&shi->raycounter, 0, sizeof(shi->raycounter));
-#endif
-
- if (shi->mat->nodetree && shi->mat->use_nodes) {
- compat = ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
- }
-
- /* also run this when node shaders fail, due to incompatible shader nodes */
- if (compat == false) {
- /* copy all relevant material vars, note, keep this synced with render_types.h */
- shade_input_init_material(shi);
-
- if (shi->mat->material_type == MA_TYPE_VOLUME) {
- if (R.r.mode & R_RAYTRACE) {
- shade_volume_outside(shi, shr);
- }
- }
- else { /* MA_TYPE_SURFACE, MA_TYPE_WIRE */
- shade_material_loop(shi, shr);
- }
- }
-
- /* copy additional passes */
- if (shi->passflag & (SCE_PASS_VECTOR | SCE_PASS_NORMAL)) {
- copy_v4_v4(shr->winspeed, shi->winspeed);
- copy_v3_v3(shr->nor, shi->vn);
- }
-
- /* MIST */
- if ((shi->passflag & SCE_PASS_MIST) || ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0)) {
- if (R.r.mode & R_ORTHO)
- shr->mist = mistfactor(-shi->co[2], shi->co);
- else
- shr->mist = mistfactor(len_v3(shi->co), shi->co);
- }
- else shr->mist = 0.0f;
-
- if ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0) {
- alpha = shr->mist;
- }
- else alpha = 1.0f;
-
- /* add mist and premul color */
- if (shr->alpha != 1.0f || alpha != 1.0f) {
- float fac = alpha * (shr->alpha);
- shr->combined[3] = fac;
-
- if (shi->mat->material_type != MA_TYPE_VOLUME)
- mul_v3_fl(shr->combined, fac);
- }
- else
- shr->combined[3] = 1.0f;
-
- /* add z */
- shr->z = -shi->co[2];
-
- /* RAYHITS */
-#if 0
- if (1 || shi->passflag & SCE_PASS_RAYHITS) {
- shr->rayhits[0] = (float)shi->raycounter.faces.test;
- shr->rayhits[1] = (float)shi->raycounter.bb.hit;
- shr->rayhits[2] = 0.0;
- shr->rayhits[3] = 1.0;
- }
-#endif
-
- RE_RC_MERGE(&re_rc_counter[shi->thread], &shi->raycounter);
-}
-
-/* **************************************************************************** */
-/* ShadeInput */
-/* **************************************************************************** */
-
-
-void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3)
-{
- /* to prevent storing new tfaces or vcols, we check a split runtime */
- /* 4---3 4---3 */
- /* |\ 1| or |1 /| */
- /* |0\ | |/ 0| */
- /* 1---2 1---2 0 = orig face, 1 = new face */
-
- /* Update vert nums to point to correct verts of original face */
- if (vlr->flag & R_DIVIDE_24) {
- if (vlr->flag & R_FACE_SPLIT) {
- (*i1)++; (*i2)++; (*i3)++;
- }
- else {
- (*i3)++;
- }
- }
- else if (vlr->flag & R_FACE_SPLIT) {
- (*i2)++; (*i3)++;
- }
-}
-
-/* copy data from face to ShadeInput, general case */
-/* indices 0 1 2 3 only */
-void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen *vlr, short i1, short i2, short i3)
-{
- VertRen **vpp = &vlr->v1;
-
- shi->vlr = vlr;
- shi->obi = obi;
- shi->obr = obi->obr;
-
- shi->v1 = vpp[i1];
- shi->v2 = vpp[i2];
- shi->v3 = vpp[i3];
-
- shi->i1 = i1;
- shi->i2 = i2;
- shi->i3 = i3;
-
- /* note, shi->mat is set in node shaders */
- shi->mat = shi->mat_override ? shi->mat_override : vlr->mat;
-
- shi->osatex = (shi->mat->texco & TEXCO_OSA);
- shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */
- shi->mode2 = shi->mat->mode2_l;
-
- /* facenormal copy, can get flipped */
- shi->flippednor = 0;
- RE_vlakren_get_normal(&R, obi, vlr, shi->facenor);
-
- /* calculate vertexnormals */
- if (vlr->flag & R_SMOOTH) {
- copy_v3_v3(shi->n1, shi->v1->n);
- copy_v3_v3(shi->n2, shi->v2->n);
- copy_v3_v3(shi->n3, shi->v3->n);
-
- if (obi->flag & R_TRANSFORMED) {
- mul_m3_v3(obi->nmat, shi->n1); normalize_v3(shi->n1);
- mul_m3_v3(obi->nmat, shi->n2); normalize_v3(shi->n2);
- mul_m3_v3(obi->nmat, shi->n3); normalize_v3(shi->n3);
- }
- }
-}
-
-/* copy data from face to ShadeInput, scanline case */
-void shade_input_set_triangle(ShadeInput *shi, int obi, int facenr, int UNUSED(normal_flip))
-{
- if (facenr > 0) {
- shi->obi = &R.objectinstance[obi];
- shi->obr = shi->obi->obr;
- shi->facenr = (facenr - 1) & RE_QUAD_MASK;
- if (shi->facenr < shi->obr->totvlak) {
- VlakRen *vlr = RE_findOrAddVlak(shi->obr, shi->facenr);
-
- if (facenr & RE_QUAD_OFFS)
- shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 1, 2);
- }
- else
- shi->vlr = NULL; /* general signal we got sky */
- }
- else
- shi->vlr = NULL; /* general signal we got sky */
-}
-
-/* full osa case: copy static info */
-void shade_input_copy_triangle(ShadeInput *shi, ShadeInput *from)
-{
- /* not so nice, but works... warning is in RE_shader_ext.h */
- memcpy(shi, from, sizeof(struct ShadeInputCopy));
-}
-
-/* copy data from strand to shadeinput */
-void shade_input_set_strand(ShadeInput *shi, StrandRen *strand, StrandPoint *spoint)
-{
- /* note, shi->mat is set in node shaders */
- shi->mat = shi->mat_override ? shi->mat_override : strand->buffer->ma;
-
- shi->osatex = (shi->mat->texco & TEXCO_OSA);
- shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */
-
- /* shade_input_set_viewco equivalent */
- copy_v3_v3(shi->co, spoint->co);
- copy_v3_v3(shi->view, shi->co);
- normalize_v3(shi->view);
-
- shi->xs = (int)spoint->x;
- shi->ys = (int)spoint->y;
-
- if (shi->osatex || (R.r.mode & R_SHADOW)) {
- copy_v3_v3(shi->dxco, spoint->dtco);
- copy_v3_v3(shi->dyco, spoint->dsco);
- }
-
- /* dxview, dyview, not supported */
-
- /* facenormal, simply viewco flipped */
- copy_v3_v3(shi->facenor, spoint->nor);
-
- /* shade_input_set_normals equivalent */
- if (shi->mat->mode & MA_TANGENT_STR) {
- copy_v3_v3(shi->vn, spoint->tan);
- }
- else {
- float cross[3];
-
- cross_v3_v3v3(cross, spoint->co, spoint->tan);
- cross_v3_v3v3(shi->vn, cross, spoint->tan);
- normalize_v3(shi->vn);
-
- if (dot_v3v3(shi->vn, shi->view) < 0.0f)
- negate_v3(shi->vn);
- }
-
- copy_v3_v3(shi->vno, shi->vn);
-}
-
-void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert *svert, StrandPoint *spoint)
-{
- StrandBuffer *strandbuf = strand->buffer;
- ObjectRen *obr = strandbuf->obr;
- StrandVert *sv;
- int mode = shi->mode; /* or-ed result for all nodes */
- short texco = shi->mat->texco;
-
- if ((shi->mat->texco & TEXCO_REFL)) {
- /* shi->dxview, shi->dyview, not supported */
- }
-
- if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL))) {
- /* not supported */
- }
-
- if (mode & (MA_TANGENT_V | MA_NORMAP_TANG)) {
- copy_v3_v3(shi->tang, spoint->tan);
- copy_v3_v3(shi->nmaptang, spoint->tan);
- }
-
- if (mode & MA_STR_SURFDIFF) {
- const float *surfnor = RE_strandren_get_surfnor(obr, strand, 0);
-
- if (surfnor)
- copy_v3_v3(shi->surfnor, surfnor);
- else
- copy_v3_v3(shi->surfnor, shi->vn);
-
- if (shi->mat->strand_surfnor > 0.0f) {
- shi->surfdist = 0.0f;
- for (sv = strand->vert; sv != svert; sv++)
- shi->surfdist += len_v3v3(sv->co, (sv + 1)->co);
- shi->surfdist += spoint->t * len_v3v3(sv->co, (sv + 1)->co);
- }
- }
-
- if (R.r.mode & R_SPEED) {
- const float *speed;
-
- speed = RE_strandren_get_winspeed(shi->obi, strand, 0);
- if (speed)
- copy_v4_v4(shi->winspeed, speed);
- else
- shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f;
- }
-
- /* shade_input_set_shade_texco equivalent */
- if (texco & NEED_UV) {
- if (texco & TEXCO_ORCO) {
- copy_v3_v3(shi->lo, strand->orco);
- /* no shi->osatex, orco derivatives are zero */
- }
-
- if (texco & TEXCO_GLOB) {
- mul_v3_m4v3(shi->gl, R.viewinv, shi->co);
-
- if (shi->osatex) {
- mul_v3_mat3_m4v3(shi->dxgl, R.viewinv, shi->dxco);
- mul_v3_mat3_m4v3(shi->dygl, R.viewinv, shi->dyco);
- }
- }
-
- if (texco & TEXCO_STRAND) {
- shi->strandco = spoint->strandco;
-
- if (shi->osatex) {
- shi->dxstrand = spoint->dtstrandco;
- shi->dystrand = 0.0f;
- }
- }
-
- if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE))) {
- MCol *mcol;
- const float *uv;
- char *name;
- int i;
-
- shi->totuv = 0;
- shi->totcol = 0;
- shi->actuv = obr->actmtface;
- shi->actcol = obr->actmcol;
-
- if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) {
- for (i = 0; (mcol = RE_strandren_get_mcol(obr, strand, i, &name, 0)); i++) {
- ShadeInputCol *scol = &shi->col[i];
- const char *cp = (char *)mcol;
-
- shi->totcol++;
- scol->name = name;
-
- scol->col[0] = cp[3] / 255.0f;
- scol->col[1] = cp[2] / 255.0f;
- scol->col[2] = cp[1] / 255.0f;
- scol->col[3] = cp[0] / 255.0f;
- }
-
- if (shi->totcol) {
- shi->vcol[0] = shi->col[shi->actcol].col[0];
- shi->vcol[1] = shi->col[shi->actcol].col[1];
- shi->vcol[2] = shi->col[shi->actcol].col[2];
- shi->vcol[3] = shi->col[shi->actcol].col[3];
- }
- else {
- shi->vcol[0] = 0.0f;
- shi->vcol[1] = 0.0f;
- shi->vcol[2] = 0.0f;
- shi->vcol[3] = 0.0f;
- }
- }
-
- for (i = 0; (uv = RE_strandren_get_uv(obr, strand, i, &name, 0)); i++) {
- ShadeInputUV *suv = &shi->uv[i];
-
- shi->totuv++;
- suv->name = name;
-
- if (strandbuf->overrideuv == i) {
- suv->uv[0] = -1.0f;
- suv->uv[1] = spoint->strandco;
- suv->uv[2] = 0.0f;
- }
- else {
- suv->uv[0] = -1.0f + 2.0f * uv[0];
- suv->uv[1] = -1.0f + 2.0f * uv[1];
- suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
- }
-
- if (shi->osatex) {
- suv->dxuv[0] = 0.0f;
- suv->dxuv[1] = 0.0f;
- suv->dyuv[0] = 0.0f;
- suv->dyuv[1] = 0.0f;
- }
-
- if ((mode & MA_FACETEXTURE) && i == obr->actmtface) {
- if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == 0) {
- shi->vcol[0] = 1.0f;
- shi->vcol[1] = 1.0f;
- shi->vcol[2] = 1.0f;
- shi->vcol[3] = 1.0f;
- }
- }
- }
-
- if (shi->totuv == 0) {
- ShadeInputUV *suv = &shi->uv[0];
-
- suv->uv[0] = 0.0f;
- suv->uv[1] = spoint->strandco;
- suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
-
- if (mode & MA_FACETEXTURE) {
- /* no tface? set at 1.0f */
- shi->vcol[0] = 1.0f;
- shi->vcol[1] = 1.0f;
- shi->vcol[2] = 1.0f;
- shi->vcol[3] = 1.0f;
- }
- }
-
- }
-
- if (texco & TEXCO_NORM) {
- shi->orn[0] = -shi->vn[0];
- shi->orn[1] = -shi->vn[1];
- shi->orn[2] = -shi->vn[2];
- }
-
- if (texco & TEXCO_STRESS) {
- /* not supported */
- }
-
- if (texco & TEXCO_TANGENT) {
- if ((mode & MA_TANGENT_V) == 0) {
- /* just prevent surprises */
- shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
- shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
- }
- }
- }
-
- /* this only avalailable for scanline renders */
- if (shi->depth == 0) {
- if (texco & TEXCO_WINDOW) {
- shi->winco[0] = -1.0f + 2.0f * spoint->x / (float)R.winx;
- shi->winco[1] = -1.0f + 2.0f * spoint->y / (float)R.winy;
- shi->winco[2] = 0.0f;
-
- /* not supported */
- if (shi->osatex) {
- shi->dxwin[0] = 0.0f;
- shi->dywin[1] = 0.0f;
- shi->dxwin[0] = 0.0f;
- shi->dywin[1] = 0.0f;
- }
- }
- }
-
- if (shi->do_manage) {
- if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) {
- srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
- }
- }
-
-}
-
-/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */
-void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3])
-{
- /* returns not normalized, so is in viewplane coords */
- calc_view_vector(view, x, y);
-
- if (shi->mat->material_type == MA_TYPE_WIRE) {
- /* wire cannot use normal for calculating shi->co, so
- * we reconstruct the coordinate less accurate */
- if (R.r.mode & R_ORTHO)
- calc_renderco_ortho(co, x, y, z);
- else
- calc_renderco_zbuf(co, view, z);
- }
- else {
- /* for non-wire, intersect with the triangle to get the exact coord */
- float fac, dface, v1[3];
-
- copy_v3_v3(v1, shi->v1->co);
- if (shi->obi->flag & R_TRANSFORMED)
- mul_m4_v3(shi->obi->mat, v1);
-
- dface = dot_v3v3(v1, shi->facenor);
-
- /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */
- if (R.r.mode & R_ORTHO) {
- /* x and y 3d coordinate can be derived from pixel coord and winmat */
- float fx = 2.0f / (R.winx * R.winmat[0][0]);
- float fy = 2.0f / (R.winy * R.winmat[1][1]);
-
- co[0] = (x - 0.5f * R.winx) * fx - R.winmat[3][0] / R.winmat[0][0];
- co[1] = (y - 0.5f * R.winy) * fy - R.winmat[3][1] / R.winmat[1][1];
-
- /* using a*x + b*y + c*z = d equation, (a b c) is normal */
- if (shi->facenor[2] != 0.0f)
- co[2] = (dface - shi->facenor[0] * co[0] - shi->facenor[1] * co[1]) / shi->facenor[2];
- else
- co[2] = 0.0f;
-
- if (dxco && dyco) {
- dxco[0] = fx;
- dxco[1] = 0.0f;
- if (shi->facenor[2] != 0.0f)
- dxco[2] = -(shi->facenor[0] * fx) / shi->facenor[2];
- else
- dxco[2] = 0.0f;
-
- dyco[0] = 0.0f;
- dyco[1] = fy;
- if (shi->facenor[2] != 0.0f)
- dyco[2] = -(shi->facenor[1] * fy) / shi->facenor[2];
- else
- dyco[2] = 0.0f;
-
- if (dxyview) {
- fac = (co[2] != 0.0f) ? (1.0f / co[2]) : 0.0f;
- dxyview[0] = -R.viewdx * fac;
- dxyview[1] = -R.viewdy * fac;
- }
- }
- }
- else {
- float div;
-
- div = dot_v3v3(shi->facenor, view);
- if (div != 0.0f) fac = dface / div;
- else fac = 0.0f;
-
- co[0] = fac * view[0];
- co[1] = fac * view[1];
- co[2] = fac * view[2];
-
- /* pixel dx/dy for render coord */
- if (dxco && dyco) {
- float u = dface / (div - R.viewdx * shi->facenor[0]);
- float v = dface / (div - R.viewdy * shi->facenor[1]);
-
- dxco[0] = co[0] - (view[0] - R.viewdx) * u;
- dxco[1] = co[1] - (view[1]) * u;
- dxco[2] = co[2] - (view[2]) * u;
-
- dyco[0] = co[0] - (view[0]) * v;
- dyco[1] = co[1] - (view[1] - R.viewdy) * v;
- dyco[2] = co[2] - (view[2]) * v;
-
- if (dxyview) {
- if (fac != 0.0f) fac = 1.0f / fac;
- dxyview[0] = -R.viewdx * fac;
- dxyview[1] = -R.viewdy * fac;
- }
- }
- }
- }
-
- /* set camera coords - for scanline, it's always 0.0,0.0,0.0 (render is in camera space)
- * however for raytrace it can be different - the position of the last intersection */
- shi->camera_co[0] = shi->camera_co[1] = shi->camera_co[2] = 0.0f;
-
- /* cannot normalize earlier, code above needs it at viewplane level */
- normalize_v3(view);
-}
-
-/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */
-void shade_input_set_viewco(ShadeInput *shi, float x, float y, float xs, float ys, float z)
-{
- float *dxyview = NULL, *dxco = NULL, *dyco = NULL;
-
- /* currently in use for dithering (soft shadow), node preview, irregular shad */
- shi->xs = (int)xs;
- shi->ys = (int)ys;
-
- /* original scanline coordinate without jitter */
- shi->scanco[0] = x;
- shi->scanco[1] = y;
- shi->scanco[2] = z;
-
- /* check if we need derivatives */
- if (shi->osatex || (R.r.mode & R_SHADOW)) {
- dxco = shi->dxco;
- dyco = shi->dyco;
-
- if ((shi->mat->texco & TEXCO_REFL))
- dxyview = &shi->dxview;
- }
-
- shade_input_calc_viewco(shi, xs, ys, z, shi->view, dxyview, shi->co, dxco, dyco);
-}
-
-void barycentric_differentials_from_position(
- const float co[3], const float v1[3], const float v2[3], const float v3[3],
- const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
- float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v)
-{
- /* find most stable axis to project */
- int axis1, axis2;
- axis_dominant_v3(&axis1, &axis2, facenor);
-
- /* compute u,v and derivatives */
- float t00 = v3[axis1] - v1[axis1];
- float t01 = v3[axis2] - v1[axis2];
- float t10 = v3[axis1] - v2[axis1];
- float t11 = v3[axis2] - v2[axis2];
-
- float detsh = (t00 * t11 - t10 * t01);
- detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
- t00 *= detsh; t01 *= detsh;
- t10 *= detsh; t11 *= detsh;
-
- *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10;
- *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01;
- if (differentials) {
- *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10;
- *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01;
- *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10;
- *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01;
- }
-}
-/* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */
-void shade_input_set_uv(ShadeInput *shi)
-{
- VlakRen *vlr = shi->vlr;
-
- if ((vlr->flag & R_SMOOTH) || (shi->mat->texco & NEED_UV) || (shi->passflag & SCE_PASS_UV)) {
- float v1[3], v2[3], v3[3];
-
- copy_v3_v3(v1, shi->v1->co);
- copy_v3_v3(v2, shi->v2->co);
- copy_v3_v3(v3, shi->v3->co);
-
- if (shi->obi->flag & R_TRANSFORMED) {
- mul_m4_v3(shi->obi->mat, v1);
- mul_m4_v3(shi->obi->mat, v2);
- mul_m4_v3(shi->obi->mat, v3);
- }
-
- /* exception case for wire render of edge */
- if (vlr->v2 == vlr->v3) {
- float lend, lenc;
-
- lend = len_v3v3(v2, v1);
- lenc = len_v3v3(shi->co, v1);
-
- if (lend == 0.0f) {
- shi->u = shi->v = 0.0f;
- }
- else {
- shi->u = -(1.0f - lenc / lend);
- shi->v = 0.0f;
- }
-
- if (shi->osatex) {
- shi->dx_u = 0.0f;
- shi->dx_v = 0.0f;
- shi->dy_u = 0.0f;
- shi->dy_v = 0.0f;
- }
- }
- else {
- barycentric_differentials_from_position(
- shi->co, v1, v2, v3, shi->dxco, shi->dyco, shi->facenor, shi->osatex,
- &shi->u, &shi->v, &shi->dx_u, &shi->dx_v, &shi->dy_u, &shi->dy_v);
-
- shi->u = -shi->u;
- shi->v = -shi->v;
-
- /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */
- CLAMP(shi->u, -2.0f, 1.0f);
- CLAMP(shi->v, -2.0f, 1.0f);
- }
- }
-}
-
-void shade_input_set_normals(ShadeInput *shi)
-{
- float u = shi->u, v = shi->v;
- float l = 1.0f + u + v;
-
- shi->flippednor = 0;
-
- /* test flip normals to viewing direction */
- if (!(shi->vlr->flag & R_TANGENT)) {
- if (dot_v3v3(shi->facenor, shi->view) < 0.0f) {
- negate_v3(shi->facenor);
- shi->flippednor = 1;
- }
- }
-
- /* calculate vertexnormals */
- if (shi->vlr->flag & R_SMOOTH) {
- float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
-
- if (shi->flippednor) {
- negate_v3(n1);
- negate_v3(n2);
- negate_v3(n3);
- }
-
- shi->vn[0] = l * n3[0] - u * n1[0] - v * n2[0];
- shi->vn[1] = l * n3[1] - u * n1[1] - v * n2[1];
- shi->vn[2] = l * n3[2] - u * n1[2] - v * n2[2];
-
- /* use unnormalized normal (closer to games) */
- copy_v3_v3(shi->nmapnorm, shi->vn);
-
- normalize_v3(shi->vn);
- }
- else {
- copy_v3_v3(shi->vn, shi->facenor);
- copy_v3_v3(shi->nmapnorm, shi->vn);
- }
-
- /* used in nodes */
- copy_v3_v3(shi->vno, shi->vn);
-
- /* flip normals to viewing direction */
- if (!(shi->vlr->flag & R_TANGENT))
- if (dot_v3v3(shi->facenor, shi->view) < 0.0f)
- shade_input_flip_normals(shi);
-}
-
-/* XXX shi->flippednor messes up otherwise */
-void shade_input_set_vertex_normals(ShadeInput *shi)
-{
- float u = shi->u, v = shi->v;
- float l = 1.0f + u + v;
-
- /* calculate vertexnormals */
- if (shi->vlr->flag & R_SMOOTH) {
- const float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
-
- shi->vn[0] = l * n3[0] - u * n1[0] - v * n2[0];
- shi->vn[1] = l * n3[1] - u * n1[1] - v * n2[1];
- shi->vn[2] = l * n3[2] - u * n1[2] - v * n2[2];
-
- /* use unnormalized normal (closer to games) */
- copy_v3_v3(shi->nmapnorm, shi->vn);
-
- normalize_v3(shi->vn);
- }
- else {
- copy_v3_v3(shi->vn, shi->facenor);
- copy_v3_v3(shi->nmapnorm, shi->vn);
- }
-
- /* used in nodes */
- copy_v3_v3(shi->vno, shi->vn);
-}
-
-
-/* use by raytrace, sss, bake to flip into the right direction */
-void shade_input_flip_normals(ShadeInput *shi)
-{
- negate_v3(shi->facenor);
- negate_v3(shi->vn);
- negate_v3(shi->vno);
- negate_v3(shi->nmapnorm);
- shi->flippednor = !shi->flippednor;
-}
-
-void shade_input_set_shade_texco(ShadeInput *shi)
-{
- ObjectInstanceRen *obi = shi->obi;
- ObjectRen *obr = shi->obr;
- VertRen *v1 = shi->v1, *v2 = shi->v2, *v3 = shi->v3;
- float u = shi->u, v = shi->v;
- float l = 1.0f + u + v, dl;
- int mode = shi->mode; /* or-ed result for all nodes */
- int mode2 = shi->mode2;
- short texco = shi->mat->texco;
- const bool need_mikk_tangent = (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT);
- const bool need_mikk_tangent_concrete = (mode2 & MA_TANGENT_CONCRETE) != 0;
-
- /* calculate dxno */
- if (shi->vlr->flag & R_SMOOTH) {
-
- if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL)) ) {
- const float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
-
- dl = shi->dx_u + shi->dx_v;
- shi->dxno[0] = dl * n3[0] - shi->dx_u * n1[0] - shi->dx_v * n2[0];
- shi->dxno[1] = dl * n3[1] - shi->dx_u * n1[1] - shi->dx_v * n2[1];
- shi->dxno[2] = dl * n3[2] - shi->dx_u * n1[2] - shi->dx_v * n2[2];
- dl = shi->dy_u + shi->dy_v;
- shi->dyno[0] = dl * n3[0] - shi->dy_u * n1[0] - shi->dy_v * n2[0];
- shi->dyno[1] = dl * n3[1] - shi->dy_u * n1[1] - shi->dy_v * n2[1];
- shi->dyno[2] = dl * n3[2] - shi->dy_u * n1[2] - shi->dy_v * n2[2];
-
- }
- }
-
- /* calc tangents */
- if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || mode2 & MA_TANGENT_CONCRETE || R.flag & R_NEED_TANGENT) {
- const float *s1, *s2, *s3;
- float tl, tu, tv;
-
- if (shi->vlr->flag & R_SMOOTH) {
- tl = l;
- tu = u;
- tv = v;
- }
- else {
- /* qdn: flat faces have tangents too,
- * could pick either one, using average here */
- tl = 1.0f / 3.0f;
- tu = -1.0f / 3.0f;
- tv = -1.0f / 3.0f;
- }
-
- shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
- shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
-
- if (mode & MA_TANGENT_V) {
- s1 = RE_vertren_get_tangent(obr, v1, 0);
- s2 = RE_vertren_get_tangent(obr, v2, 0);
- s3 = RE_vertren_get_tangent(obr, v3, 0);
-
- if (s1 && s2 && s3) {
- shi->tang[0] = (tl * s3[0] - tu * s1[0] - tv * s2[0]);
- shi->tang[1] = (tl * s3[1] - tu * s1[1] - tv * s2[1]);
- shi->tang[2] = (tl * s3[2] - tu * s1[2] - tv * s2[2]);
-
- if (obi->flag & R_TRANSFORMED)
- mul_m3_v3(obi->nmat, shi->tang);
-
- normalize_v3(shi->tang);
- copy_v3_v3(shi->nmaptang, shi->tang);
- }
- }
-
- if (need_mikk_tangent || need_mikk_tangent_concrete) {
- int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
- float c0[3], c1[3], c2[3];
- int acttang = obr->actmtface;
-
- vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
-
- /* cycle through all tangent in vlakren */
- for (int i = 0; i < MAX_MTFACE; i++) {
- const float *tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, i, false);
- if (!tangent)
- continue;
-
- copy_v3_v3(c0, &tangent[j1 * 4]);
- copy_v3_v3(c1, &tangent[j2 * 4]);
- copy_v3_v3(c2, &tangent[j3 * 4]);
-
- /* keeping tangents normalized at vertex level
- * corresponds better to how it's done in game engines */
- if (obi->flag & R_TRANSFORMED) {
- mul_mat3_m4_v3(obi->mat, c0); normalize_v3(c0);
- mul_mat3_m4_v3(obi->mat, c1); normalize_v3(c1);
- mul_mat3_m4_v3(obi->mat, c2); normalize_v3(c2);
- }
-
- /* we don't normalize the interpolated TBN tangent
- * corresponds better to how it's done in game engines */
- shi->tangents[i][0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
- shi->tangents[i][1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
- shi->tangents[i][2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
-
- /* the sign is the same for all 3 vertices of any
- * non degenerate triangle. */
- shi->tangents[i][3] = tangent[j1 * 4 + 3];
-
- if (acttang == i && need_mikk_tangent) {
- for (int m = 0; m < 4; m++) {
- shi->nmaptang[m] = shi->tangents[i][m];
- }
- }
- }
- }
- }
-
- if (mode & MA_STR_SURFDIFF) {
- const float *surfnor = RE_vlakren_get_surfnor(obr, shi->vlr, 0);
-
- if (surfnor) {
- copy_v3_v3(shi->surfnor, surfnor);
- if (obi->flag & R_TRANSFORMED)
- mul_m3_v3(obi->nmat, shi->surfnor);
- }
- else
- copy_v3_v3(shi->surfnor, shi->vn);
-
- shi->surfdist = 0.0f;
- }
-
- if (R.r.mode & R_SPEED) {
- const float *s1, *s2, *s3;
-
- s1 = RE_vertren_get_winspeed(obi, v1, 0);
- s2 = RE_vertren_get_winspeed(obi, v2, 0);
- s3 = RE_vertren_get_winspeed(obi, v3, 0);
- if (s1 && s2 && s3) {
- shi->winspeed[0] = (l * s3[0] - u * s1[0] - v * s2[0]);
- shi->winspeed[1] = (l * s3[1] - u * s1[1] - v * s2[1]);
- shi->winspeed[2] = (l * s3[2] - u * s1[2] - v * s2[2]);
- shi->winspeed[3] = (l * s3[3] - u * s1[3] - v * s2[3]);
- }
- else {
- shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f;
- }
- }
-
- /* pass option forces UV calc */
- if ((shi->passflag & SCE_PASS_UV) || (R.flag & R_NEED_VCOL))
- texco |= (NEED_UV | TEXCO_UV);
-
- /* texture coordinates. shi->dxuv shi->dyuv have been set */
- if (texco & NEED_UV) {
-
- if (texco & TEXCO_ORCO) {
- if (v1->orco) {
- const float *o1, *o2, *o3;
-
- o1 = v1->orco;
- o2 = v2->orco;
- o3 = v3->orco;
-
- shi->lo[0] = l * o3[0] - u * o1[0] - v * o2[0];
- shi->lo[1] = l * o3[1] - u * o1[1] - v * o2[1];
- shi->lo[2] = l * o3[2] - u * o1[2] - v * o2[2];
-
- if (shi->osatex) {
- dl = shi->dx_u + shi->dx_v;
- shi->dxlo[0] = dl * o3[0] - shi->dx_u * o1[0] - shi->dx_v * o2[0];
- shi->dxlo[1] = dl * o3[1] - shi->dx_u * o1[1] - shi->dx_v * o2[1];
- shi->dxlo[2] = dl * o3[2] - shi->dx_u * o1[2] - shi->dx_v * o2[2];
- dl = shi->dy_u + shi->dy_v;
- shi->dylo[0] = dl * o3[0] - shi->dy_u * o1[0] - shi->dy_v * o2[0];
- shi->dylo[1] = dl * o3[1] - shi->dy_u * o1[1] - shi->dy_v * o2[1];
- shi->dylo[2] = dl * o3[2] - shi->dy_u * o1[2] - shi->dy_v * o2[2];
- }
- }
-
- copy_v3_v3(shi->duplilo, obi->dupliorco);
- }
-
- if (texco & TEXCO_GLOB) {
- copy_v3_v3(shi->gl, shi->co);
- mul_m4_v3(R.viewinv, shi->gl);
- if (shi->osatex) {
- copy_v3_v3(shi->dxgl, shi->dxco);
- mul_mat3_m4_v3(R.viewinv, shi->dxgl);
- copy_v3_v3(shi->dygl, shi->dyco);
- mul_mat3_m4_v3(R.viewinv, shi->dygl);
- }
- }
-
- if (texco & TEXCO_STRAND) {
- shi->strandco = (l * v3->accum - u * v1->accum - v * v2->accum);
- if (shi->osatex) {
- dl = shi->dx_u + shi->dx_v;
- shi->dxstrand = dl * v3->accum - shi->dx_u * v1->accum - shi->dx_v * v2->accum;
- dl = shi->dy_u + shi->dy_v;
- shi->dystrand = dl * v3->accum - shi->dy_u * v1->accum - shi->dy_v * v2->accum;
- }
- }
-
- if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) {
- VlakRen *vlr = shi->vlr;
- MTFace *tface;
- MCol *mcol;
- char *name;
- int i, j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
-
- /* uv and vcols are not copied on split, so set them according vlr divide flag */
- vlr_set_uv_indices(vlr, &j1, &j2, &j3);
-
- shi->totuv = 0;
- shi->totcol = 0;
- shi->actuv = obr->actmtface;
- shi->actcol = obr->actmcol;
-
- if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) {
- for (i = 0; (mcol = RE_vlakren_get_mcol(obr, vlr, i, &name, 0)); i++) {
- ShadeInputCol *scol = &shi->col[i];
- const char *cp1, *cp2, *cp3;
- float a[3];
-
- shi->totcol++;
- scol->name = name;
-
- cp1 = (char *)(mcol + j1);
- cp2 = (char *)(mcol + j2);
- cp3 = (char *)(mcol + j3);
-
- /* alpha values */
- a[0] = ((float)cp1[0]) / 255.f;
- a[1] = ((float)cp2[0]) / 255.f;
- a[2] = ((float)cp3[0]) / 255.f;
- scol->col[3] = l * a[2] - u * a[0] - v * a[1];
-
- /* sample premultiplied color value */
- scol->col[0] = (l * ((float)cp3[3]) * a[2] - u * ((float)cp1[3]) * a[0] - v * ((float)cp2[3]) * a[1]) / 255.f;
- scol->col[1] = (l * ((float)cp3[2]) * a[2] - u * ((float)cp1[2]) * a[0] - v * ((float)cp2[2]) * a[1]) / 255.f;
- scol->col[2] = (l * ((float)cp3[1]) * a[2] - u * ((float)cp1[1]) * a[0] - v * ((float)cp2[1]) * a[1]) / 255.f;
-
- /* if not zero alpha, restore non-multiplied color */
- if (scol->col[3]) {
- mul_v3_fl(scol->col, 1.0f / scol->col[3]);
- }
- }
-
- if (shi->totcol) {
- shi->vcol[0] = shi->col[shi->actcol].col[0];
- shi->vcol[1] = shi->col[shi->actcol].col[1];
- shi->vcol[2] = shi->col[shi->actcol].col[2];
- shi->vcol[3] = shi->col[shi->actcol].col[3];
- }
- else {
- shi->vcol[0] = 0.0f;
- shi->vcol[1] = 0.0f;
- shi->vcol[2] = 0.0f;
- shi->vcol[3] = 1.0f;
- }
- }
-
- for (i = 0; (tface = RE_vlakren_get_tface(obr, vlr, i, &name, 0)); i++) {
- ShadeInputUV *suv = &shi->uv[i];
- const float *uv1 = tface->uv[j1];
- const float *uv2 = tface->uv[j2];
- const float *uv3 = tface->uv[j3];
-
- shi->totuv++;
- suv->name = name;
-
- if ((shi->mat->mapflag & MA_MAPFLAG_UVPROJECT) && (shi->depth == 0)) {
- float x = shi->xs;
- float y = shi->ys;
-
- float s1[2] = {-1.0f + 2.0f * uv1[0], -1.0f + 2.0f * uv1[1]};
- float s2[2] = {-1.0f + 2.0f * uv2[0], -1.0f + 2.0f * uv2[1]};
- float s3[2] = {-1.0f + 2.0f * uv3[0], -1.0f + 2.0f * uv3[1]};
-
-
- float obwinmat[4][4], winmat[4][4], ho1[4], ho2[4], ho3[4];
- float Zmulx, Zmuly;
- float hox, hoy, l_proj, dl_proj, u_proj, v_proj;
- float s00, s01, s10, s11, detsh;
-
- /* old globals, localized now */
- Zmulx = ((float)R.winx) / 2.0f;
- Zmuly = ((float)R.winy) / 2.0f;
-
- zbuf_make_winmat(&R, winmat);
- if (shi->obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- zbuf_render_project(obwinmat, v1->co, ho1);
- zbuf_render_project(obwinmat, v2->co, ho2);
- zbuf_render_project(obwinmat, v3->co, ho3);
-
- s00 = ho3[0] / ho3[3] - ho1[0] / ho1[3];
- s01 = ho3[1] / ho3[3] - ho1[1] / ho1[3];
- s10 = ho3[0] / ho3[3] - ho2[0] / ho2[3];
- s11 = ho3[1] / ho3[3] - ho2[1] / ho2[3];
-
- detsh = s00 * s11 - s10 * s01;
- detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
- s00 *= detsh; s01 *= detsh;
- s10 *= detsh; s11 *= detsh;
-
- /* recalc u and v again */
- hox = x / Zmulx - 1.0f;
- hoy = y / Zmuly - 1.0f;
- u_proj = (hox - ho3[0] / ho3[3]) * s11 - (hoy - ho3[1] / ho3[3]) * s10;
- v_proj = (hoy - ho3[1] / ho3[3]) * s00 - (hox - ho3[0] / ho3[3]) * s01;
- l_proj = 1.0f + u_proj + v_proj;
-
- suv->uv[0] = l_proj * s3[0] - u_proj * s1[0] - v_proj * s2[0];
- suv->uv[1] = l_proj * s3[1] - u_proj * s1[1] - v_proj * s2[1];
- suv->uv[2] = 0.0f;
-
- if (shi->osatex) {
- float dxuv[2], dyuv[2];
- dxuv[0] = s11 / Zmulx;
- dxuv[1] = -s01 / Zmulx;
- dyuv[0] = -s10 / Zmuly;
- dyuv[1] = s00 / Zmuly;
-
- dl_proj = dxuv[0] + dxuv[1];
- suv->dxuv[0] = dl_proj * s3[0] - dxuv[0] * s1[0] - dxuv[1] * s2[0];
- suv->dxuv[1] = dl_proj * s3[1] - dxuv[0] * s1[1] - dxuv[1] * s2[1];
- dl_proj = dyuv[0] + dyuv[1];
- suv->dyuv[0] = dl_proj * s3[0] - dyuv[0] * s1[0] - dyuv[1] * s2[0];
- suv->dyuv[1] = dl_proj * s3[1] - dyuv[0] * s1[1] - dyuv[1] * s2[1];
- }
- }
- else {
-
- suv->uv[0] = -1.0f + 2.0f * (l * uv3[0] - u * uv1[0] - v * uv2[0]);
- suv->uv[1] = -1.0f + 2.0f * (l * uv3[1] - u * uv1[1] - v * uv2[1]);
- suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
-
- if (shi->osatex) {
- float duv[2];
-
- dl = shi->dx_u + shi->dx_v;
- duv[0] = shi->dx_u;
- duv[1] = shi->dx_v;
-
- suv->dxuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]);
- suv->dxuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]);
-
- dl = shi->dy_u + shi->dy_v;
- duv[0] = shi->dy_u;
- duv[1] = shi->dy_v;
-
- suv->dyuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]);
- suv->dyuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]);
- }
-
- if ((mode & MA_FACETEXTURE) && i == obr->actmtface) {
- if (((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == 0) && ((R.flag & R_NEED_VCOL) == 0)) {
- shi->vcol[0] = 1.0f;
- shi->vcol[1] = 1.0f;
- shi->vcol[2] = 1.0f;
- shi->vcol[3] = 1.0f;
- }
- if (tface->tpage) {
- render_realtime_texture(shi, tface->tpage);
- }
- }
- }
- }
-
- shi->dupliuv[0] = -1.0f + 2.0f * obi->dupliuv[0];
- shi->dupliuv[1] = -1.0f + 2.0f * obi->dupliuv[1];
- shi->dupliuv[2] = 0.0f;
-
- if (shi->totuv == 0) {
- ShadeInputUV *suv = &shi->uv[0];
-
- suv->uv[0] = 2.0f * (u + .5f);
- suv->uv[1] = 2.0f * (v + .5f);
- suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
-
- if (mode & MA_FACETEXTURE) {
- /* no tface? set at 1.0f */
- shi->vcol[0] = 1.0f;
- shi->vcol[1] = 1.0f;
- shi->vcol[2] = 1.0f;
- shi->vcol[3] = 1.0f;
- }
- }
- }
-
- if (texco & TEXCO_NORM) {
- shi->orn[0] = -shi->vn[0];
- shi->orn[1] = -shi->vn[1];
- shi->orn[2] = -shi->vn[2];
- }
-
- if (texco & TEXCO_STRESS) {
- const float *s1, *s2, *s3;
-
- s1 = RE_vertren_get_stress(obr, v1, 0);
- s2 = RE_vertren_get_stress(obr, v2, 0);
- s3 = RE_vertren_get_stress(obr, v3, 0);
- if (s1 && s2 && s3) {
- shi->stress = l * s3[0] - u * s1[0] - v * s2[0];
- if (shi->stress < 1.0f) shi->stress -= 1.0f;
- else shi->stress = (shi->stress - 1.0f) / shi->stress;
- }
- else shi->stress = 0.0f;
- }
-
- if (texco & TEXCO_TANGENT) {
- if ((mode & MA_TANGENT_V) == 0) {
- /* just prevent surprises */
- shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
- shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
- }
- }
- }
-
- /* this only avalailable for scanline renders */
- if (shi->depth == 0) {
- float x = shi->xs;
- float y = shi->ys;
-
- if (texco & TEXCO_WINDOW) {
- shi->winco[0] = -1.0f + 2.0f * x / (float)R.winx;
- shi->winco[1] = -1.0f + 2.0f * y / (float)R.winy;
- shi->winco[2] = 0.0f;
- if (shi->osatex) {
- shi->dxwin[0] = 2.0f / (float)R.winx;
- shi->dywin[1] = 2.0f / (float)R.winy;
- shi->dxwin[1] = shi->dxwin[2] = 0.0f;
- shi->dywin[0] = shi->dywin[2] = 0.0f;
- }
- }
- }
- /* else {
- * Note! For raytracing winco is not set,
- * important because thus means all shader input's need to have their variables set to zero
- * else un-initialized values are used
- */
- if (shi->do_manage) {
- if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) {
- srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
- }
- }
-
-}
-
-/* ****************** ShadeSample ************************************** */
-
-/* initialize per part, not per pixel! */
-void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample)
-{
-
- memset(shi, 0, sizeof(ShadeInput));
-
- shi->sample = sample;
- shi->thread = pa->thread;
- shi->do_preview = (R.r.scemode & R_MATNODE_PREVIEW) != 0;
-
- shi->do_manage = BKE_scene_check_color_management_enabled(R.scene);
- shi->use_world_space_shading = BKE_scene_use_world_space_shading(R.scene);
-
- shi->lay = rl->lay;
- shi->layflag = rl->layflag;
- shi->passflag = rl->passflag;
- shi->combinedflag = ~rl->pass_xor;
- shi->mat_override = rl->mat_override;
- shi->light_override = rl->light_override;
-// shi->rl= rl;
- /* note shi.depth==0 means first hit, not raytracing */
-
-}
-
-/* initialize per part, not per pixel! */
-void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl)
-{
- int a, tot;
-
- tot = R.osa == 0 ? 1 : R.osa;
-
- for (a = 0; a < tot; a++) {
- shade_input_initialize(&ssamp->shi[a], pa, rl, a);
- memset(&ssamp->shr[a], 0, sizeof(ShadeResult));
- }
-
- get_sample_layers(pa, rl, ssamp->rlpp);
-}
-
-/* Do AO or (future) GI */
-void shade_samples_do_AO(ShadeSample *ssamp)
-{
- if (!(R.r.mode & R_SHADOW))
- return;
- if (!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
- return;
-
- if (R.wrld.mode & (WO_AMB_OCC | WO_ENV_LIGHT | WO_INDIRECT_LIGHT)) {
- ShadeInput *shi = &ssamp->shi[0];
- int sample;
-
- if (((shi->passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT))) ||
- (shi->passflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT)))
- {
- for (sample = 0; sample < ssamp->tot; shi++, sample++)
- if (!(shi->mode & MA_SHLESS))
- ambient_occlusion(shi); /* stores in shi->ao[] */
- }
- }
-}
-
-
-void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
-{
- ShadeInput *shi;
- float xs, ys;
-
- ssamp->tot = 0;
-
- for (shi = ssamp->shi; ps; ps = ps->next) {
- shade_input_set_triangle(shi, ps->obi, ps->facenr, 1);
-
- if (shi->vlr) { /* NULL happens for env material or for 'all z' */
- unsigned short curmask = ps->mask;
-
- /* full osa is only set for OSA renders */
- if (shi->vlr->flag & R_FULL_OSA) {
- short shi_cp = 0, samp;
-
- for (samp = 0; samp < R.osa; samp++) {
- if (curmask & (1 << samp)) {
- /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
- xs = (float)x + R.jit[samp][0] + 0.5f;
- ys = (float)y + R.jit[samp][1] + 0.5f;
-
- if (shi_cp)
- shade_input_copy_triangle(shi, shi - 1);
-
- shi->mask = (1 << samp);
-// shi->rl= ssamp->rlpp[samp];
- shi->samplenr = R.shadowsamplenr[shi->thread]++; /* this counter is not being reset per pixel */
- shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z);
- shade_input_set_uv(shi);
- if (shi_cp == 0)
- shade_input_set_normals(shi);
- else /* XXX shi->flippednor messes up otherwise */
- shade_input_set_vertex_normals(shi);
-
- shi_cp = 1;
- shi++;
- }
- }
- }
- else {
- if (R.osa) {
- short b = R.samples->centmask[curmask];
- xs = (float)x + R.samples->centLut[b & 15] + 0.5f;
- ys = (float)y + R.samples->centLut[b >> 4] + 0.5f;
- }
- else if (R.i.curblur) {
- xs= (float)x + R.mblur_jit[R.i.curblur-1][0] + 0.5f;
- ys= (float)y + R.mblur_jit[R.i.curblur-1][1] + 0.5f;
- }
- else {
- xs = (float)x + 0.5f;
- ys = (float)y + 0.5f;
- }
-
- shi->mask = curmask;
- shi->samplenr = R.shadowsamplenr[shi->thread]++;
- shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z);
- shade_input_set_uv(shi);
- shade_input_set_normals(shi);
- shi++;
- }
-
- /* total sample amount, shi->sample is static set in initialize */
- if (shi != ssamp->shi)
- ssamp->tot = (shi - 1)->sample + 1;
- }
- }
-}
-
-/* shades samples, returns true if anything happened */
-int shade_samples(ShadeSample *ssamp, PixStr *ps, int x, int y)
-{
- shade_samples_fill_with_ps(ssamp, ps, x, y);
-
- if (ssamp->tot) {
- ShadeInput *shi = ssamp->shi;
- ShadeResult *shr = ssamp->shr;
- int samp;
-
- /* if shadow or AO? */
- shade_samples_do_AO(ssamp);
-
- /* if shade (all shadepinputs have same passflag) */
- if (ssamp->shi[0].passflag & ~(SCE_PASS_Z | SCE_PASS_INDEXOB | SCE_PASS_INDEXMA)) {
-
- for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++) {
- shade_input_set_shade_texco(shi);
- shade_input_do_shade(shi, shr);
- }
- }
- else if (shi->passflag & SCE_PASS_Z) {
- for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++)
- shr->z = -shi->co[2];
- }
-
- return 1;
- }
- return 0;
-}
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
deleted file mode 100644
index b9c703a0528..00000000000
--- a/source/blender/render/intern/source/shadeoutput.c
+++ /dev/null
@@ -1,2183 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributors: Hos, Robert Wenzlaff.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/shadeoutput.c
- * \ingroup render
- */
-
-#include <stdio.h>
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_colorband.h"
-#include "BKE_colortools.h"
-#include "BKE_material.h"
-
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-
-/* local include */
-#include "occlusion.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "shadbuf.h"
-#include "sss.h"
-#include "texture.h"
-
-#include "shading.h" /* own include */
-
-#include "IMB_colormanagement.h"
-
-/* could enable at some point but for now there are far too many conversions */
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wdouble-promotion"
-#endif
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-ListBase *get_lights(ShadeInput *shi)
-{
-
- if (R.r.scemode & R_BUTS_PREVIEW)
- return &R.lights;
- if (shi->light_override)
- return &shi->light_override->gobject;
- if (shi->mat && shi->mat->group)
- return &shi->mat->group->gobject;
-
- return &R.lights;
-}
-
-#if 0
-static void fogcolor(const float colf[3], float *rco, float *view)
-{
- float alpha, stepsize, startdist, dist, hor[4], zen[3], vec[3], dview[3];
- float div=0.0f, distfac;
-
- hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
- zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb;
-
- copy_v3_v3(vec, rco);
-
- /* we loop from cur coord to mist start in steps */
- stepsize= 1.0f;
-
- div= ABS(view[2]);
- dview[0]= view[0]/(stepsize*div);
- dview[1]= view[1]/(stepsize*div);
- dview[2]= -stepsize;
-
- startdist= -rco[2] + BLI_frand();
- for (dist= startdist; dist>R.wrld.miststa; dist-= stepsize) {
-
- hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
- alpha= 1.0f;
- do_sky_tex(vec, vec, NULL, hor, zen, &alpha);
-
- distfac= (dist-R.wrld.miststa)/R.wrld.mistdist;
-
- hor[3]= hor[0]*distfac*distfac;
-
- /* premul! */
- alpha= hor[3];
- hor[0]= hor[0]*alpha;
- hor[1]= hor[1]*alpha;
- hor[2]= hor[2]*alpha;
- addAlphaOverFloat(colf, hor);
-
- sub_v3_v3(vec, dview);
- }
-}
-#endif
-
-/* zcor is distance, co the 3d coordinate in eye space, return alpha */
-float mistfactor(float zcor, float const co[3])
-{
- float fac, hi;
-
- fac = zcor - R.wrld.miststa; /* zcor is calculated per pixel */
-
- /* fac= -co[2]-R.wrld.miststa; */
-
- if (fac > 0.0f) {
- if (fac < R.wrld.mistdist) {
-
- fac = (fac / R.wrld.mistdist);
-
- if (R.wrld.mistype == 0) {
- fac *= fac;
- }
- else if (R.wrld.mistype == 1) {
- /* pass */
- }
- else {
- fac = sqrtf(fac);
- }
- }
- else {
- fac = 1.0f;
- }
- }
- else {
- fac = 0.0f;
- }
-
- /* height switched off mist */
- if (R.wrld.misthi!=0.0f && fac!=0.0f) {
- /* at height misthi the mist is completely gone */
-
- hi = R.viewinv[0][2] * co[0] +
- R.viewinv[1][2] * co[1] +
- R.viewinv[2][2] * co[2] +
- R.viewinv[3][2];
-
- if (hi > R.wrld.misthi) {
- fac = 0.0f;
- }
- else if (hi>0.0f) {
- hi= (R.wrld.misthi-hi)/R.wrld.misthi;
- fac*= hi*hi;
- }
- }
-
- return (1.0f-fac)* (1.0f-R.wrld.misi);
-}
-
-static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
-{
- double a, b, c, disc, nray[3], npos[3];
- double t0, t1 = 0.0f, t2= 0.0f, t3;
- float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f, haint;
- int cuts;
- bool do_clip = true, use_yco = false;
-
- *intens= 0.0f;
- haint= lar->haint;
-
- if (R.r.mode & R_ORTHO) {
- /* camera pos (view vector) cannot be used... */
- /* camera position (cox,coy,0) rotate around lamp */
- p1[0]= shi->co[0]-lar->co[0];
- p1[1]= shi->co[1]-lar->co[1];
- p1[2]= -lar->co[2];
- mul_m3_v3(lar->imat, p1);
- copy_v3db_v3fl(npos, p1); /* npos is double! */
-
- /* pre-scale */
- npos[2] *= (double)lar->sh_zfac;
- }
- else {
- copy_v3db_v3fl(npos, lar->sh_invcampos); /* in initlamp calculated */
- }
-
- /* rotate view */
- copy_v3db_v3fl(nray, shi->view);
- mul_m3_v3_double(lar->imat, nray);
-
- if (R.wrld.mode & WO_MIST) {
- /* patchy... */
- haint *= mistfactor(-lar->co[2], lar->co);
- if (haint==0.0f) {
- return;
- }
- }
-
-
- /* rotate maxz */
- if (shi->co[2]==0.0f) {
- do_clip = false; /* for when halo at sky */
- }
- else {
- p1[0]= shi->co[0]-lar->co[0];
- p1[1]= shi->co[1]-lar->co[1];
- p1[2]= shi->co[2]-lar->co[2];
-
- maxz= lar->imat[0][2]*p1[0]+lar->imat[1][2]*p1[1]+lar->imat[2][2]*p1[2];
- maxz*= lar->sh_zfac;
- maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2];
-
- if (fabs(nray[2]) < FLT_EPSILON) {
- use_yco = true;
- }
- }
-
- /* scale z to make sure volume is normalized */
- nray[2] *= (double)lar->sh_zfac;
- /* nray does not need normalization */
-
- ladist= lar->sh_zfac*lar->dist;
-
- /* solve */
- a = nray[0] * nray[0] + nray[1] * nray[1] - nray[2]*nray[2];
- b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2];
- c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2];
-
- cuts= 0;
- if (fabs(a) < DBL_EPSILON) {
- /*
- * Only one intersection point...
- */
- return;
- }
- else {
- disc = b*b - a*c;
-
- if (disc==0.0) {
- t1=t2= (-b)/ a;
- cuts= 2;
- }
- else if (disc > 0.0) {
- disc = sqrt(disc);
- t1 = (-b + disc) / a;
- t2 = (-b - disc) / a;
- cuts= 2;
- }
- }
- if (cuts==2) {
- int ok1=0, ok2=0;
-
- /* sort */
- if (t1>t2) {
- a= t1; t1= t2; t2= a;
- }
-
- /* z of intersection points with diabolo */
- p1[2]= npos[2] + t1*nray[2];
- p2[2]= npos[2] + t2*nray[2];
-
- /* evaluate both points */
- if (p1[2]<=0.0f) ok1= 1;
- if (p2[2]<=0.0f && t1!=t2) ok2= 1;
-
- /* at least 1 point with negative z */
- if (ok1==0 && ok2==0) return;
-
- /* intersction point with -ladist, the bottom of the cone */
- if (use_yco == false) {
- t3= ((double)(-ladist)-npos[2])/nray[2];
-
- /* de we have to replace one of the intersection points? */
- if (ok1) {
- if (p1[2]<-ladist) t1= t3;
- }
- else {
- t1= t3;
- }
- if (ok2) {
- if (p2[2]<-ladist) t2= t3;
- }
- else {
- t2= t3;
- }
- }
- else if (ok1==0 || ok2==0) return;
-
- /* at least 1 visible interesction point */
- if (t1<0.0 && t2<0.0) return;
-
- if (t1<0.0) t1= 0.0;
- if (t2<0.0) t2= 0.0;
-
- if (t1==t2) return;
-
- /* sort again to be sure */
- if (t1>t2) {
- a= t1; t1= t2; t2= a;
- }
-
- /* calculate t0: is the maximum visible z (when halo is intersected by face) */
- if (do_clip) {
- if (use_yco == false) t0 = ((double)maxz - npos[2]) / nray[2];
- else t0 = ((double)maxy - npos[1]) / nray[1];
-
- if (t0 < t1) return;
- if (t0 < t2) t2= t0;
- }
-
- /* calc points */
- p1[0]= npos[0] + t1*nray[0];
- p1[1]= npos[1] + t1*nray[1];
- p1[2]= npos[2] + t1*nray[2];
- p2[0]= npos[0] + t2*nray[0];
- p2[1]= npos[1] + t2*nray[1];
- p2[2]= npos[2] + t2*nray[2];
-
-
- /* now we have 2 points, make three lengths with it */
-
- a = len_v3(p1);
- b = len_v3(p2);
- c = len_v3v3(p1, p2);
-
- a/= ladist;
- a= sqrt(a);
- b/= ladist;
- b= sqrt(b);
- c/= ladist;
-
- *intens= c*( (1.0-a)+(1.0-b) );
-
- /* WATCH IT: do not clip a,b en c at 1.0, this gives nasty little overflows
- * at the edges (especially with narrow halos) */
- if (*intens<=0.0f) return;
-
- /* soft area */
- /* not needed because t0 has been used for p1/p2 as well */
- /* if (doclip && t0<t2) { */
- /* *intens *= (t0-t1)/(t2-t1); */
- /* } */
-
- *intens *= haint;
-
- if (lar->shb && lar->shb->shadhalostep) {
- *intens *= shadow_halo(lar, p1, p2);
- }
-
- }
-}
-
-void renderspothalo(ShadeInput *shi, float col[4], float alpha)
-{
- ListBase *lights;
- GroupObject *go;
- LampRen *lar;
- float i;
-
- if (alpha==0.0f) return;
-
- lights= get_lights(shi);
- for (go=lights->first; go; go= go->next) {
- lar= go->lampren;
- if (lar==NULL) continue;
-
- if (lar->type==LA_SPOT && (lar->mode & LA_HALO) && (lar->buftype != LA_SHADBUF_DEEP) && lar->haint>0) {
-
- if (lar->mode & LA_LAYER)
- if (shi->vlr && (lar->lay & shi->obi->lay)==0)
- continue;
- if ((lar->lay & shi->lay)==0)
- continue;
-
- spothalo(lar, shi, &i);
- if (i > 0.0f) {
- const float i_alpha = i * alpha;
- col[0] += i_alpha * lar->r;
- col[1] += i_alpha * lar->g;
- col[2] += i_alpha * lar->b;
- col[3] += i_alpha; /* all premul */
- }
- }
- }
- /* clip alpha, is needed for unified 'alpha threshold' (vanillaRenderPipe.c) */
- if (col[3]>1.0f) col[3]= 1.0f;
-}
-
-
-
-/* ---------------- shaders ----------------------- */
-
-static double Normalize_d(double *n)
-{
- double d;
-
- d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
-
- if (d>0.00000000000000001) {
- d= sqrt(d);
-
- n[0]/=d;
- n[1]/=d;
- n[2]/=d;
- }
- else {
- n[0]=n[1]=n[2]= 0.0;
- d= 0.0;
- }
- return d;
-}
-
-/* mix of 'real' fresnel and allowing control. grad defines blending gradient */
-float fresnel_fac(const float view[3], const float vn[3], float grad, float fac)
-{
- float t1, t2;
-
- if (fac==0.0f) return 1.0f;
-
- t1 = dot_v3v3(view, vn);
- if (t1>0.0f) t2= 1.0f+t1;
- else t2= 1.0f-t1;
-
- t2= grad + (1.0f-grad)*powf(t2, fac);
-
- if (t2<0.0f) return 0.0f;
- else if (t2>1.0f) return 1.0f;
- return t2;
-}
-
-static double saacos_d(double fac)
-{
- if (fac<= -1.0) return M_PI;
- else if (fac>=1.0) return 0.0;
- else return acos(fac);
-}
-
-/* Stoke's form factor. Need doubles here for extreme small area sizes */
-static float area_lamp_energy(float (*area)[3], const float co[3], const float vn[3])
-{
- double fac;
- double vec[4][3]; /* vectors of rendered co to vertices lamp */
- double cross[4][3]; /* cross products of this */
- double rad[4]; /* angles between vecs */
-
- VECSUB(vec[0], co, area[0]);
- VECSUB(vec[1], co, area[1]);
- VECSUB(vec[2], co, area[2]);
- VECSUB(vec[3], co, area[3]);
-
- Normalize_d(vec[0]);
- Normalize_d(vec[1]);
- Normalize_d(vec[2]);
- Normalize_d(vec[3]);
-
- /* cross product */
-#define CROSS(dest, a, b) \
- { \
- dest[0]= a[1] * b[2] - a[2] * b[1]; \
- dest[1]= a[2] * b[0] - a[0] * b[2]; \
- dest[2]= a[0] * b[1] - a[1] * b[0]; \
- } (void)0
-
- CROSS(cross[0], vec[0], vec[1]);
- CROSS(cross[1], vec[1], vec[2]);
- CROSS(cross[2], vec[2], vec[3]);
- CROSS(cross[3], vec[3], vec[0]);
-
-#undef CROSS
-
- Normalize_d(cross[0]);
- Normalize_d(cross[1]);
- Normalize_d(cross[2]);
- Normalize_d(cross[3]);
-
- /* angles */
- rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
- rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2];
- rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2];
- rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2];
-
- rad[0]= saacos_d(rad[0]);
- rad[1]= saacos_d(rad[1]);
- rad[2]= saacos_d(rad[2]);
- rad[3]= saacos_d(rad[3]);
-
- /* Stoke formula */
- fac= rad[0]*(vn[0]*cross[0][0]+ vn[1]*cross[0][1]+ vn[2]*cross[0][2]);
- fac+= rad[1]*(vn[0]*cross[1][0]+ vn[1]*cross[1][1]+ vn[2]*cross[1][2]);
- fac+= rad[2]*(vn[0]*cross[2][0]+ vn[1]*cross[2][1]+ vn[2]*cross[2][2]);
- fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]);
-
- if (fac<=0.0) return 0.0;
- return fac;
-}
-
-static float area_lamp_energy_multisample(LampRen *lar, const float co[3], float *vn)
-{
- /* corner vectors are moved around according lamp jitter */
- float *jitlamp= lar->jitter, vec[3];
- float area[4][3], intens= 0.0f;
- int a= lar->ray_totsamp;
-
- /* test if co is behind lamp */
- sub_v3_v3v3(vec, co, lar->co);
- if (dot_v3v3(vec, lar->vec) < 0.0f)
- return 0.0f;
-
- while (a--) {
- vec[0]= jitlamp[0];
- vec[1]= jitlamp[1];
- vec[2]= 0.0f;
- mul_m3_v3(lar->mat, vec);
-
- add_v3_v3v3(area[0], lar->area[0], vec);
- add_v3_v3v3(area[1], lar->area[1], vec);
- add_v3_v3v3(area[2], lar->area[2], vec);
- add_v3_v3v3(area[3], lar->area[3], vec);
-
- intens+= area_lamp_energy(area, co, vn);
-
- jitlamp+= 2;
- }
- intens /= (float)lar->ray_totsamp;
-
- return pow(intens * lar->areasize, lar->k); /* corrected for buttons size and lar->dist^2 */
-}
-
-static float spec(float inp, int hard)
-{
- float b1;
-
- if (inp>=1.0f) return 1.0f;
- else if (inp<=0.0f) return 0.0f;
-
- b1= inp*inp;
- /* avoid FPE */
- if (b1<0.01f) b1= 0.01f;
-
- if ((hard & 1)==0) inp= 1.0f;
- if (hard & 2) inp*= b1;
- b1*= b1;
- if (hard & 4) inp*= b1;
- b1*= b1;
- if (hard & 8) inp*= b1;
- b1*= b1;
- if (hard & 16) inp*= b1;
- b1*= b1;
-
- /* avoid FPE */
- if (b1<0.001f) b1= 0.0f;
-
- if (hard & 32) inp*= b1;
- b1*= b1;
- if (hard & 64) inp*=b1;
- b1*= b1;
- if (hard & 128) inp*=b1;
-
- if (b1<0.001f) b1= 0.0f;
-
- if (hard & 256) {
- b1*= b1;
- inp*=b1;
- }
-
- return inp;
-}
-
-static float Phong_Spec(const float n[3], const float l[3], const float v[3], int hard, int tangent )
-{
- float h[3];
- float rslt;
-
- h[0] = l[0] + v[0];
- h[1] = l[1] + v[1];
- h[2] = l[2] + v[2];
- normalize_v3(h);
-
- rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
- if (tangent) rslt= sasqrt(1.0f - rslt*rslt);
-
- if ( rslt > 0.0f ) rslt= spec(rslt, hard);
- else rslt = 0.0f;
-
- return rslt;
-}
-
-
-/* reduced cook torrance spec (for off-specular peak) */
-static float CookTorr_Spec(const float n[3], const float l[3], const float v[3], int hard, int tangent)
-{
- float i, nh, nv, h[3];
-
- h[0]= v[0]+l[0];
- h[1]= v[1]+l[1];
- h[2]= v[2]+l[2];
- normalize_v3(h);
-
- nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2];
- if (tangent) nh= sasqrt(1.0f - nh*nh);
- else if (nh<0.0f) return 0.0f;
-
- nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2];
- if (tangent) nv= sasqrt(1.0f - nv*nv);
- else if (nv<0.0f) nv= 0.0f;
-
- i= spec(nh, hard);
-
- i= i/(0.1f+nv);
- return i;
-}
-
-/* Blinn spec */
-static float Blinn_Spec(const float n[3], const float l[3], const float v[3], float refrac, float spec_power, int tangent)
-{
- float i, nh, nv, nl, vh, h[3];
- float a, b, c, g=0.0f, p, f, ang;
-
- if (refrac < 1.0f) return 0.0f;
- if (spec_power == 0.0f) return 0.0f;
-
- /* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */
- if (spec_power<100.0f)
- spec_power = sqrtf(1.0f / spec_power);
- else spec_power= 10.0f/spec_power;
-
- h[0]= v[0]+l[0];
- h[1]= v[1]+l[1];
- h[2]= v[2]+l[2];
- normalize_v3(h);
-
- nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
- if (tangent) nh= sasqrt(1.0f - nh*nh);
- else if (nh<0.0f) return 0.0f;
-
- nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
- if (tangent) nv= sasqrt(1.0f - nv*nv);
- if (nv<=0.01f) nv= 0.01f; /* hrms... */
-
- nl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
- if (tangent) nl= sasqrt(1.0f - nl*nl);
- if (nl<=0.01f) {
- return 0.0f;
- }
-
- vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and half-way vector */
- if (vh<=0.0f) vh= 0.01f;
-
- a = 1.0f;
- b = (2.0f*nh*nv)/vh;
- c = (2.0f*nh*nl)/vh;
-
- if ( a < b && a < c ) g = a;
- else if ( b < a && b < c ) g = b;
- else if ( c < a && c < b ) g = c;
-
- p = sqrt((double)((refrac * refrac)+(vh * vh) - 1.0f));
- f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1+((((vh*(p+vh))-1.0f)*((vh*(p+vh))-1.0f))/(((vh*(p-vh))+1.0f)*((vh*(p-vh))+1.0f))));
- ang = saacos(nh);
-
- i= f * g * exp((double)(-(ang*ang) / (2.0f*spec_power*spec_power)));
- if (i<0.0f) i= 0.0f;
-
- return i;
-}
-
-/* cartoon render spec */
-static float Toon_Spec(const float n[3], const float l[3], const float v[3], float size, float smooth, int tangent)
-{
- float h[3];
- float ang;
- float rslt;
-
- h[0] = l[0] + v[0];
- h[1] = l[1] + v[1];
- h[2] = l[2] + v[2];
- normalize_v3(h);
-
- rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
- if (tangent) rslt = sasqrt(1.0f - rslt*rslt);
-
- ang = saacos( rslt );
-
- if ( ang < size ) rslt = 1.0f;
- else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
- else rslt = 1.0f - ((ang - size) / smooth);
-
- return rslt;
-}
-
-/* Ward isotropic gaussian spec */
-static float WardIso_Spec(const float n[3], const float l[3], const float v[3], float rms, int tangent)
-{
- float i, nh, nv, nl, h[3], angle, alpha;
-
-
- /* half-way vector */
- h[0] = l[0] + v[0];
- h[1] = l[1] + v[1];
- h[2] = l[2] + v[2];
- normalize_v3(h);
-
- nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
- if (tangent) nh = sasqrt(1.0f - nh*nh);
- if (nh<=0.0f) nh = 0.001f;
-
- nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
- if (tangent) nv = sasqrt(1.0f - nv*nv);
- if (nv<=0.0f) nv = 0.001f;
-
- nl = n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
- if (tangent) nl = sasqrt(1.0f - nl*nl);
- if (nl<=0.0f) nl = 0.001f;
-
- angle = tanf(saacos(nh));
- alpha = MAX2(rms, 0.001f);
-
- i= nl * (1.0f/(4.0f*(float)M_PI*alpha*alpha)) * (expf( -(angle*angle)/(alpha*alpha))/(sqrtf(nv*nl)));
-
- return i;
-}
-
-/* cartoon render diffuse */
-static float Toon_Diff(const float n[3], const float l[3], const float UNUSED(v[3]), float size, float smooth)
-{
- float rslt, ang;
-
- rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
-
- ang = saacos(rslt);
-
- if ( ang < size ) rslt = 1.0f;
- else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
- else rslt = 1.0f - ((ang - size) / smooth);
-
- return rslt;
-}
-
-/* Oren Nayar diffuse */
-
-/* 'nl' is either dot product, or return value of area light */
-/* in latter case, only last multiplication uses 'nl' */
-static float OrenNayar_Diff(float nl, const float n[3], const float l[3], const float v[3], float rough )
-{
- float i/*, nh*/, nv /*, vh */, realnl, h[3];
- float a, b, t, A, B;
- float Lit_A, View_A, Lit_B[3], View_B[3];
-
- h[0]= v[0]+l[0];
- h[1]= v[1]+l[1];
- h[2]= v[2]+l[2];
- normalize_v3(h);
-
- /* nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; */ /* Dot product between surface normal and half-way vector */
- /* if (nh<0.0f) nh = 0.0f; */
-
- nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
- if (nv<=0.0f) nv= 0.0f;
-
- realnl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
- if (realnl<=0.0f) return 0.0f;
- if (nl<0.0f) return 0.0f; /* value from area light */
-
- /* vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; */ /* Dot product between view vector and halfway vector */
- /* if (vh<=0.0f) vh= 0.0f; */
-
- Lit_A = saacos(realnl);
- View_A = saacos( nv );
-
- Lit_B[0] = l[0] - (realnl * n[0]);
- Lit_B[1] = l[1] - (realnl * n[1]);
- Lit_B[2] = l[2] - (realnl * n[2]);
- normalize_v3(Lit_B);
-
- View_B[0] = v[0] - (nv * n[0]);
- View_B[1] = v[1] - (nv * n[1]);
- View_B[2] = v[2] - (nv * n[2]);
- normalize_v3(View_B);
-
- t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2];
- if ( t < 0 ) t = 0;
-
- if ( Lit_A > View_A ) {
- a = Lit_A;
- b = View_A;
- }
- else {
- a = View_A;
- b = Lit_A;
- }
-
- A = 1.0f - (0.5f * ((rough * rough) / ((rough * rough) + 0.33f)));
- B = 0.45f * ((rough * rough) / ((rough * rough) + 0.09f));
-
- b*= 0.95f; /* prevent tangens from shooting to inf, 'nl' can be not a dot product here. */
- /* overflow only happens with extreme size area light, and higher roughness */
- i = nl * ( A + ( B * t * sinf(a) * tanf(b) ) );
-
- return i;
-}
-
-/* Minnaert diffuse */
-static float Minnaert_Diff(float nl, const float n[3], const float v[3], float darkness)
-{
- float i, nv;
-
- /* nl = dot product between surface normal and light vector */
- if (nl <= 0.0f)
- return 0.0f;
-
- /* nv = dot product between surface normal and view vector */
- nv = dot_v3v3(n, v);
- if (nv < 0.0f)
- nv = 0.0f;
-
- if (darkness <= 1.0f)
- i = nl * pow(max_ff(nv * nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/
- else
- i = nl * pow( (1.001f - nv), (darkness - 1.0f) ); /*Nvidia model*/
-
- return i;
-}
-
-static float Fresnel_Diff(float *vn, float *lv, float *UNUSED(view), float fac_i, float fac)
-{
- return fresnel_fac(lv, vn, fac_i, fac);
-}
-
-/* --------------------------------------------- */
-/* also called from texture.c */
-void calc_R_ref(ShadeInput *shi)
-{
- float i;
-
- /* shi->vn dot shi->view */
- i= -2*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]);
-
- shi->ref[0]= (shi->view[0]+i*shi->vn[0]);
- shi->ref[1]= (shi->view[1]+i*shi->vn[1]);
- shi->ref[2]= (shi->view[2]+i*shi->vn[2]);
- if (shi->osatex) {
- if (shi->vlr->flag & R_SMOOTH) {
- i= -2*( (shi->vn[0]+shi->dxno[0])*(shi->view[0]+shi->dxview) +
- (shi->vn[1]+shi->dxno[1])*shi->view[1]+ (shi->vn[2]+shi->dxno[2])*shi->view[2] );
-
- shi->dxref[0]= shi->ref[0]- ( shi->view[0]+shi->dxview+i*(shi->vn[0]+shi->dxno[0]));
- shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*(shi->vn[1]+shi->dxno[1]));
- shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dxno[2]));
-
- i= -2*( (shi->vn[0]+shi->dyno[0])*shi->view[0]+
- (shi->vn[1]+shi->dyno[1])*(shi->view[1]+shi->dyview)+ (shi->vn[2]+shi->dyno[2])*shi->view[2] );
-
- shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*(shi->vn[0]+shi->dyno[0]));
- shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*(shi->vn[1]+shi->dyno[1]));
- shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dyno[2]));
-
- }
- else {
-
- i= -2*( shi->vn[0]*(shi->view[0]+shi->dxview) +
- shi->vn[1]*shi->view[1]+ shi->vn[2]*shi->view[2] );
-
- shi->dxref[0]= shi->ref[0]- (shi->view[0]+shi->dxview+i*shi->vn[0]);
- shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*shi->vn[1]);
- shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
-
- i= -2*( shi->vn[0]*shi->view[0]+
- shi->vn[1]*(shi->view[1]+shi->dyview)+ shi->vn[2]*shi->view[2] );
-
- shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*shi->vn[0]);
- shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*shi->vn[1]);
- shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
- }
- }
-
-}
-
-/* called from rayshade.c */
-void shade_color(ShadeInput *shi, ShadeResult *shr)
-{
- Material *ma= shi->mat;
-
- if (ma->mode & (MA_FACETEXTURE)) {
- shi->r= shi->vcol[0];
- shi->g= shi->vcol[1];
- shi->b= shi->vcol[2];
- if (ma->mode & (MA_FACETEXTURE_ALPHA))
- shi->alpha= shi->vcol[3];
- }
- else if (ma->mode & (MA_VERTEXCOLP)) {
- float neg_alpha = 1.0f - shi->vcol[3];
- shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3];
- shi->g= shi->g*neg_alpha + shi->vcol[1]*shi->vcol[3];
- shi->b= shi->b*neg_alpha + shi->vcol[2]*shi->vcol[3];
- }
-
- if (ma->texco)
- do_material_tex(shi, &R);
-
- if (ma->fresnel_tra!=0.0f)
- shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
-
- if (!(shi->mode & MA_TRANSP)) shi->alpha= 1.0f;
-
- shr->diff[0]= shi->r;
- shr->diff[1]= shi->g;
- shr->diff[2]= shi->b;
- shr->alpha= shi->alpha;
-
- /* modulate by the object color */
- if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
- float obcol[4];
-
- copy_v4_v4(obcol, shi->obr->ob->col);
- CLAMP(obcol[3], 0.0f, 1.0f);
-
- shr->diff[0] *= obcol[0];
- shr->diff[1] *= obcol[1];
- shr->diff[2] *= obcol[2];
- if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
- }
-
- copy_v3_v3(shr->diffshad, shr->diff);
-}
-
-/* ramp for at end of shade */
-static void ramp_diffuse_result(float *diff, ShadeInput *shi)
-{
- Material *ma= shi->mat;
- float col[4];
-
- if (ma->ramp_col) {
- if (ma->rampin_col==MA_RAMP_IN_RESULT) {
- float fac = IMB_colormanagement_get_luminance(diff);
- BKE_colorband_evaluate(ma->ramp_col, fac, col);
-
- /* blending method */
- fac= col[3]*ma->rampfac_col;
-
- ramp_blend(ma->rampblend_col, diff, fac, col);
- }
- }
-}
-
-/* r,g,b denote energy, ramp is used with different values to make new material color */
-static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is, const float rgb[3])
-{
- Material *ma= shi->mat;
-
- if (ma->ramp_col && (ma->mode & MA_RAMP_COL)) {
-
- /* MA_RAMP_IN_RESULT is exceptional */
- if (ma->rampin_col==MA_RAMP_IN_RESULT) {
- /* normal add */
- diff[0] += rgb[0] * shi->r;
- diff[1] += rgb[1] * shi->g;
- diff[2] += rgb[2] * shi->b;
- }
- else {
- float colt[3], col[4];
- float fac;
-
- /* input */
- switch (ma->rampin_col) {
- case MA_RAMP_IN_ENERGY:
- fac = IMB_colormanagement_get_luminance(rgb);
- break;
- case MA_RAMP_IN_SHADER:
- fac = is;
- break;
- case MA_RAMP_IN_NOR:
- fac = dot_v3v3(shi->view, shi->vn);
- break;
- default:
- fac = 0.0f;
- break;
- }
-
- BKE_colorband_evaluate(ma->ramp_col, fac, col);
-
- /* blending method */
- fac = col[3] * ma->rampfac_col;
- copy_v3_v3(colt, &shi->r);
-
- ramp_blend(ma->rampblend_col, colt, fac, col);
-
- /* output to */
- diff[0] += rgb[0] * colt[0];
- diff[1] += rgb[1] * colt[1];
- diff[2] += rgb[2] * colt[2];
- }
- }
- else {
- diff[0] += rgb[0] * shi->r;
- diff[1] += rgb[1] * shi->g;
- diff[2] += rgb[2] * shi->b;
- }
-}
-
-static void ramp_spec_result(float spec_col[3], ShadeInput *shi)
-{
- Material *ma= shi->mat;
-
- if (ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) {
- float col[4];
- float fac = IMB_colormanagement_get_luminance(spec_col);
-
- BKE_colorband_evaluate(ma->ramp_spec, fac, col);
-
- /* blending method */
- fac= col[3]*ma->rampfac_spec;
-
- ramp_blend(ma->rampblend_spec, spec_col, fac, col);
-
- }
-}
-
-/* is = dot product shade, t = spec energy */
-static void do_specular_ramp(ShadeInput *shi, float is, float t, float spec[3])
-{
- Material *ma= shi->mat;
-
- spec[0]= shi->specr;
- spec[1]= shi->specg;
- spec[2]= shi->specb;
-
- /* MA_RAMP_IN_RESULT is exception */
- if (ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) {
- float fac;
- float col[4];
-
- /* input */
- switch (ma->rampin_spec) {
- case MA_RAMP_IN_ENERGY:
- fac= t;
- break;
- case MA_RAMP_IN_SHADER:
- fac= is;
- break;
- case MA_RAMP_IN_NOR:
- fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
- break;
- default:
- fac= 0.0f;
- break;
- }
-
- BKE_colorband_evaluate(ma->ramp_spec, fac, col);
-
- /* blending method */
- fac= col[3]*ma->rampfac_spec;
-
- ramp_blend(ma->rampblend_spec, spec, fac, col);
- }
-}
-
-/* pure AO, check for raytrace and world should have been done */
-/* preprocess, textures were not done, don't use shi->amb for that reason */
-void ambient_occlusion(ShadeInput *shi)
-{
- if ((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f) {
- sample_occ(&R, shi);
- }
- else if ((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) {
- ray_ao(shi, shi->ao, shi->env);
- }
- else {
- shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
- zero_v3(shi->env);
- zero_v3(shi->indirect);
- }
-}
-
-
-/* wrld mode was checked for */
-static void ambient_occlusion_apply(ShadeInput *shi, ShadeResult *shr)
-{
- float f= R.wrld.aoenergy;
- float tmp[3], tmpspec[3];
-
- if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
- return;
- if (f == 0.0f)
- return;
-
- if (R.wrld.aomix==WO_AOADD) {
- shr->combined[0] += shi->ao[0]*shi->r*shi->refl*f;
- shr->combined[1] += shi->ao[1]*shi->g*shi->refl*f;
- shr->combined[2] += shi->ao[2]*shi->b*shi->refl*f;
- }
- else if (R.wrld.aomix==WO_AOMUL) {
- mul_v3_v3v3(tmp, shr->combined, shi->ao);
- mul_v3_v3v3(tmpspec, shr->spec, shi->ao);
-
- if (f == 1.0f) {
- copy_v3_v3(shr->combined, tmp);
- copy_v3_v3(shr->spec, tmpspec);
- }
- else {
- interp_v3_v3v3(shr->combined, shr->combined, tmp, f);
- interp_v3_v3v3(shr->spec, shr->spec, tmpspec, f);
- }
- }
-}
-
-void environment_lighting_apply(ShadeInput *shi, ShadeResult *shr)
-{
- float f= R.wrld.ao_env_energy*shi->amb;
-
- if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
- return;
- if (f == 0.0f)
- return;
-
- shr->combined[0] += shi->env[0]*shi->r*shi->refl*f;
- shr->combined[1] += shi->env[1]*shi->g*shi->refl*f;
- shr->combined[2] += shi->env[2]*shi->b*shi->refl*f;
-}
-
-static void indirect_lighting_apply(ShadeInput *shi, ShadeResult *shr)
-{
- float f= R.wrld.ao_indirect_energy;
-
- if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
- return;
- if (f == 0.0f)
- return;
-
- shr->combined[0] += shi->indirect[0]*shi->r*shi->refl*f;
- shr->combined[1] += shi->indirect[1]*shi->g*shi->refl*f;
- shr->combined[2] += shi->indirect[2]*shi->b*shi->refl*f;
-}
-
-/* result written in shadfac */
-void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real)
-{
- LampShadowSubSample *lss= &(lar->shadsamp[shi->thread].s[shi->sample]);
-
- if (do_real || lss->samplenr!=shi->samplenr) {
-
- shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
-
- if (lar->shb) {
- if (lar->buftype==LA_SHADBUF_IRREGULAR)
- shadfac[3]= ISB_getshadow(shi, lar->shb);
- else
- shadfac[3] = testshadowbuf(&R, lar->shb, shi->co, shi->dxco, shi->dyco, inp, shi->mat->lbias);
- }
- else if (lar->mode & LA_SHAD_RAY) {
- ray_shadow(shi, lar, shadfac);
- }
-
- if (shi->depth==0) {
- copy_v4_v4(lss->shadfac, shadfac);
- lss->samplenr= shi->samplenr;
- }
- }
- else {
- copy_v4_v4(shadfac, lss->shadfac);
- }
-}
-
-/* lampdistance and spot angle, writes in lv and dist */
-float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *dist)
-{
- if (lar->type==LA_SUN || lar->type==LA_HEMI) {
- *dist= 1.0f;
- copy_v3_v3(lv, lar->vec);
- return 1.0f;
- }
- else {
- float visifac= 1.0f, visifac_r;
-
- sub_v3_v3v3(lv, co, lar->co);
- mul_v3_fl(lv, 1.0f / (*dist = len_v3(lv)));
-
- /* area type has no quad or sphere option */
- if (lar->type==LA_AREA) {
- /* area is single sided */
- //if (dot_v3v3(lv, lar->vec) > 0.0f)
- // visifac= 1.0f;
- //else
- // visifac= 0.0f;
- }
- else {
- switch (lar->falloff_type) {
- case LA_FALLOFF_CONSTANT:
- visifac = 1.0f;
- break;
- case LA_FALLOFF_INVLINEAR:
- visifac = lar->dist/(lar->dist + dist[0]);
- break;
- case LA_FALLOFF_INVSQUARE:
- /* NOTE: This seems to be a hack since commit r12045 says this
- * option is similar to old Quad, but with slight changes.
- * Correct inv square would be (which would be old Quad):
- * visifac = lar->distkw / (lar->distkw + dist[0]*dist[0]);
- */
- visifac = lar->dist / (lar->dist + dist[0]*dist[0]);
- break;
- case LA_FALLOFF_SLIDERS:
- if (lar->ld1>0.0f)
- visifac= lar->dist/(lar->dist+lar->ld1*dist[0]);
- if (lar->ld2>0.0f)
- visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
- break;
- case LA_FALLOFF_INVCOEFFICIENTS:
- visifac_r = lar->coeff_const +
- lar->coeff_lin * dist[0] +
- lar->coeff_quad * dist[0] * dist[0];
- if (visifac_r > 0.0)
- visifac = 1.0 / visifac_r;
- else
- visifac = 0.0;
- break;
- case LA_FALLOFF_CURVE:
- /* curvemapping_initialize is called from #add_render_lamp */
- visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist);
- break;
- }
-
- if (lar->mode & LA_SPHERE) {
- float t= lar->dist - dist[0];
- if (t<=0.0f)
- visifac= 0.0f;
- else
- visifac*= t/lar->dist;
- }
-
- if (visifac > 0.0f) {
- if (lar->type==LA_SPOT) {
- float inpr, t;
-
- if (lar->mode & LA_SQUARE) {
- if (dot_v3v3(lv, lar->vec) > 0.0f) {
- float lvrot[3], x;
-
- /* rotate view to lampspace */
- copy_v3_v3(lvrot, lv);
- mul_m3_v3(lar->imat, lvrot);
-
- x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
- /* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
-
- inpr = 1.0f / (sqrtf(1.0f + x * x));
- }
- else inpr= 0.0f;
- }
- else {
- inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
- }
-
- t= lar->spotsi;
- if (inpr<=t)
- visifac= 0.0f;
- else {
- t= inpr-t;
- if (t<lar->spotbl && lar->spotbl!=0.0f) {
- /* soft area */
- float i= t/lar->spotbl;
- t= i*i;
- inpr*= (3.0f*t-2.0f*t*i);
- }
- visifac*= inpr;
- }
- }
- }
- }
- if (visifac <= 0.001f) visifac = 0.0f;
- return visifac;
- }
-}
-
-/* function returns raw diff, spec and full shadowed diff in the 'shad' pass */
-static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int passflag)
-{
- Material *ma= shi->mat;
- VlakRen *vlr= shi->vlr;
- float lv[3], lampdist, lacol[3], shadfac[4], lashdw[3];
- float i, is, i_noshad, inp, *vn, *view, vnor[3], phongcorr=1.0f;
- float visifac;
-
- vn= shi->vn;
- view= shi->view;
-
-
- if (lar->energy == 0.0f) return;
- /* only shadow lamps shouldn't affect shadow-less materials at all */
- if ((lar->mode & LA_ONLYSHADOW) && (!(ma->mode & MA_SHADOW) || !(R.r.mode & R_SHADOW)))
- return;
- /* optimization, don't render fully black lamps */
- if (!(lar->mode & LA_TEXTURE) && (lar->r + lar->g + lar->b == 0.0f))
- return;
-
- /* lampdist, spot angle, area side, ... */
- visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
- if (visifac==0.0f)
- return;
-
- if (lar->type==LA_SPOT) {
- if (lar->mode & LA_OSATEX) {
- shi->osatex= 1; /* signal for multitex() */
-
- shi->dxlv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dxco[0])/lampdist;
- shi->dxlv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dxco[1])/lampdist;
- shi->dxlv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dxco[2])/lampdist;
-
- shi->dylv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dyco[0])/lampdist;
- shi->dylv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dyco[1])/lampdist;
- shi->dylv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dyco[2])/lampdist;
- }
- }
-
- /* lamp color texture */
- lacol[0]= lar->r;
- lacol[1]= lar->g;
- lacol[2]= lar->b;
-
- lashdw[0]= lar->shdwr;
- lashdw[1]= lar->shdwg;
- lashdw[2]= lar->shdwb;
-
- if (lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
- if (lar->mode & LA_SHAD_TEX) do_lamp_tex(lar, lv, shi, lashdw, LA_SHAD_TEX);
-
- /* tangent case; calculate fake face normal, aligned with lampvector */
- /* note, vnor==vn is used as tangent trigger for buffer shadow */
- if (vlr->flag & R_TANGENT) {
- float cross[3], nstrand[3], blend;
-
- if (ma->mode & MA_STR_SURFDIFF) {
- cross_v3_v3v3(cross, shi->surfnor, vn);
- cross_v3_v3v3(nstrand, vn, cross);
-
- blend= dot_v3v3(nstrand, shi->surfnor);
- blend= 1.0f - blend;
- CLAMP(blend, 0.0f, 1.0f);
-
- interp_v3_v3v3(vnor, nstrand, shi->surfnor, blend);
- normalize_v3(vnor);
- }
- else {
- cross_v3_v3v3(cross, lv, vn);
- cross_v3_v3v3(vnor, cross, vn);
- normalize_v3(vnor);
- }
-
- if (ma->strand_surfnor > 0.0f) {
- if (ma->strand_surfnor > shi->surfdist) {
- blend= (ma->strand_surfnor - shi->surfdist)/ma->strand_surfnor;
- interp_v3_v3v3(vnor, vnor, shi->surfnor, blend);
- normalize_v3(vnor);
- }
- }
-
- vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
- vn= vnor;
- }
- else if (ma->mode & MA_TANGENT_V) {
- float cross[3];
- cross_v3_v3v3(cross, lv, shi->tang);
- cross_v3_v3v3(vnor, cross, shi->tang);
- normalize_v3(vnor);
- vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
- vn= vnor;
- }
-
- /* dot product and reflectivity */
- /* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */
- inp= dot_v3v3(vn, lv);
-
- /* phong threshold to prevent backfacing faces having artifacts on ray shadow (terminator problem) */
- /* this complex construction screams for a nicer implementation! (ton) */
- if (R.r.mode & R_SHADOW) {
- if (ma->mode & MA_SHADOW) {
- if (lar->type == LA_HEMI || lar->type == LA_AREA) {
- /* pass */
- }
- else if ((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) {
- float thresh= shi->obr->ob->smoothresh;
- if (inp>thresh)
- phongcorr= (inp-thresh)/(inp*(1.0f-thresh));
- else
- phongcorr= 0.0f;
- }
- else if (ma->sbias!=0.0f && ((lar->mode & LA_SHAD_RAY) || lar->shb)) {
- if (inp>ma->sbias)
- phongcorr= (inp-ma->sbias)/(inp*(1.0f-ma->sbias));
- else
- phongcorr= 0.0f;
- }
- }
- }
-
- /* diffuse shaders */
- if (lar->mode & LA_NO_DIFF) {
- is = 0.0f; /* skip shaders */
- }
- else if (lar->type==LA_HEMI) {
- is = 0.5f * inp + 0.5f;
- }
- else {
-
- if (lar->type==LA_AREA)
- inp= area_lamp_energy_multisample(lar, shi->co, vn);
-
- /* diffuse shaders (oren nayer gets inp from area light) */
- if (ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness);
- else if (ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);
- else if (ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness);
- else if (ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]);
- else is= inp; /* Lambert */
- }
-
- /* 'is' is diffuse */
- if ((ma->shade_flag & MA_CUBIC) && is > 0.0f && is < 1.0f) {
- is= 3.0f * is * is - 2.0f * is * is * is; /* nicer termination of shades */
- }
-
- i= is*phongcorr;
-
- if (i>0.0f) {
- i*= visifac*shi->refl;
- }
- i_noshad= i;
-
- vn = shi->vn; /* bring back original vector, we use special specular shaders for tangent */
- if (ma->mode & MA_TANGENT_V)
- vn= shi->tang;
-
- /* init transp shadow */
- shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
-
- /* shadow and spec, (visifac==0 outside spot) */
- if (visifac> 0.0f) {
-
- if ((R.r.mode & R_SHADOW)) {
- if (ma->mode & MA_SHADOW) {
- if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
-
- if (vn==vnor) /* tangent trigger */
- lamp_get_shadow(lar, shi, dot_v3v3(shi->vn, lv), shadfac, shi->depth);
- else
- lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
-
- /* warning, here it skips the loop */
- if ((lar->mode & LA_ONLYSHADOW) && i>0.0f) {
-
- shadfac[3]= i*lar->energy*(1.0f-shadfac[3]);
- shr->shad[0] -= shadfac[3]*shi->r*(1.0f-lashdw[0]);
- shr->shad[1] -= shadfac[3]*shi->g*(1.0f-lashdw[1]);
- shr->shad[2] -= shadfac[3]*shi->b*(1.0f-lashdw[2]);
-
- if (!(lar->mode & LA_NO_SPEC)) {
- shr->spec[0] -= shadfac[3]*shi->specr*(1.0f-lashdw[0]);
- shr->spec[1] -= shadfac[3]*shi->specg*(1.0f-lashdw[1]);
- shr->spec[2] -= shadfac[3]*shi->specb*(1.0f-lashdw[2]);
- }
-
- return;
- }
-
- i*= shadfac[3];
- shr->shad[3] = shadfac[3]; /* store this for possible check in troublesome cases */
- }
- else {
- shr->shad[3] = 1.0f; /* No shadow at all! */
- }
- }
- }
-
- /* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/
- if (!(lar->mode & LA_NO_DIFF)) {
- if (i>0.0f) {
- if (ma->mode & MA_SHADOW_TRA) {
- const float tcol[3] = {
- i * shadfac[0] * lacol[0],
- i * shadfac[1] * lacol[1],
- i * shadfac[2] * lacol[2],
- };
- add_to_diffuse(shr->shad, shi, is, tcol);
- }
- else {
- const float tcol[3] = {
- i * lacol[0],
- i * lacol[1],
- i * lacol[2],
- };
- add_to_diffuse(shr->shad, shi, is, tcol);
- }
- }
- /* add light for colored shadow */
- if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) {
- const float tcol[3] = {
- lashdw[0] * (i_noshad - i) * lacol[0],
- lashdw[1] * (i_noshad - i) * lacol[1],
- lashdw[2] * (i_noshad - i) * lacol[2],
- };
- add_to_diffuse(shr->shad, shi, is, tcol);
- }
- if (i_noshad>0.0f) {
- if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW) ||
- ((passflag & SCE_PASS_COMBINED) && !(shi->combinedflag & SCE_PASS_SHADOW)))
- {
- const float tcol[3] = {
- i_noshad * lacol[0],
- i_noshad * lacol[1],
- i_noshad * lacol[2]
- };
- add_to_diffuse(shr->diff, shi, is, tcol);
- }
- else {
- copy_v3_v3(shr->diff, shr->shad);
- }
- }
- }
-
- /* specularity */
- shadfac[3]*= phongcorr; /* note, shadfac not allowed to be stored nonlocal */
-
- if (shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC) && !(lar->mode & LA_ONLYSHADOW)) {
-
- if (!(passflag & (SCE_PASS_COMBINED | SCE_PASS_SPEC))) {
- /* pass */
- }
- else if (lar->type == LA_HEMI) {
- float t;
- /* hemi uses no spec shaders (yet) */
-
- lv[0]+= view[0];
- lv[1]+= view[1];
- lv[2]+= view[2];
-
- normalize_v3(lv);
-
- t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2];
-
- if (lar->type==LA_HEMI) {
- t= 0.5f*t+0.5f;
- }
-
- t= shadfac[3]*shi->spec*spec(t, shi->har);
-
- shr->spec[0]+= t*(lacol[0] * shi->specr);
- shr->spec[1]+= t*(lacol[1] * shi->specg);
- shr->spec[2]+= t*(lacol[2] * shi->specb);
- }
- else {
- /* specular shaders */
- float specfac, t;
-
- if (ma->spec_shader==MA_SPEC_PHONG)
- specfac= Phong_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
- else if (ma->spec_shader==MA_SPEC_COOKTORR)
- specfac= CookTorr_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
- else if (ma->spec_shader==MA_SPEC_BLINN)
- specfac= Blinn_Spec(vn, lv, view, ma->refrac, (float)shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
- else if (ma->spec_shader==MA_SPEC_WARDISO)
- specfac= WardIso_Spec( vn, lv, view, ma->rms, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
- else
- specfac= Toon_Spec(vn, lv, view, ma->param[2], ma->param[3], (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
-
- /* area lamp correction */
- if (lar->type==LA_AREA) specfac*= inp;
-
- t= shadfac[3]*shi->spec*visifac*specfac;
-
- if (ma->mode & MA_RAMP_SPEC) {
- float spec[3];
- do_specular_ramp(shi, specfac, t, spec);
- shr->spec[0]+= t*(lacol[0] * spec[0]);
- shr->spec[1]+= t*(lacol[1] * spec[1]);
- shr->spec[2]+= t*(lacol[2] * spec[2]);
- }
- else {
- shr->spec[0]+= t*(lacol[0] * shi->specr);
- shr->spec[1]+= t*(lacol[1] * shi->specg);
- shr->spec[2]+= t*(lacol[2] * shi->specb);
- }
- }
- }
- }
-}
-
-static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
-{
-
- if (R.r.mode & R_SHADOW) {
- ListBase *lights;
- LampRen *lar;
- GroupObject *go;
- float inpr, lv[3];
- float /* *view, */ shadfac[4];
- float ir, accum, visifac, lampdist;
- float shaded = 0.0f, lightness = 0.0f;
-
-
- /* view= shi->view; */ /* UNUSED */
- accum= ir= 0.0f;
-
- lights= get_lights(shi);
- for (go=lights->first; go; go= go->next) {
- lar= go->lampren;
- if (lar==NULL) continue;
-
- if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue;
- if ((lar->lay & shi->lay)==0) continue;
-
- if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
- visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
- ir+= 1.0f;
-
- if (visifac <= 0.0f) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD)
- accum+= 1.0f;
-
- continue;
- }
- inpr= dot_v3v3(shi->vn, lv);
- if (inpr <= 0.0f) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD)
- accum+= 1.0f;
-
- continue;
- }
-
- lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth);
-
- if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- /* Old "Shadows Only" */
- accum+= (1.0f-visifac) + (visifac)*IMB_colormanagement_get_luminance(shadfac)*shadfac[3];
- }
- else {
- shaded += IMB_colormanagement_get_luminance(shadfac)*shadfac[3] * visifac * lar->energy;
-
- if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
- lightness += visifac * lar->energy;
- }
- }
- }
- }
-
- /* Apply shadows as alpha */
- if (ir>0.0f) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- accum = 1.0f - accum/ir;
- }
- else {
- if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
- if (lightness > 0.0f) {
- /* Get shadow value from between 0.0f and non-shadowed lightness */
- accum = (lightness - shaded) / (lightness);
- }
- else {
- accum = 0.0f;
- }
- }
- else { /* shadowonly_flag == MA_SO_SHADED */
- /* Use shaded value */
- accum = 1.0f - shaded;
- }
- }
-
- shr->alpha= (shi->alpha)*(accum);
- if (shr->alpha<0.0f) shr->alpha=0.0f;
- }
- else {
- /* If "fully shaded", use full alpha even on areas that have no lights */
- if (shi->mat->shadowonly_flag == MA_SO_SHADED) shr->alpha=shi->alpha;
- else shr->alpha= 0.f;
- }
- }
-
- /* quite disputable this... also note it doesn't mirror-raytrace */
- if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT)) && shi->amb!=0.0f) {
- float f;
-
- if (R.wrld.mode & WO_AMB_OCC) {
- f= R.wrld.aoenergy*shi->amb;
-
- if (R.wrld.aomix==WO_AOADD) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- f= f*(1.0f - IMB_colormanagement_get_luminance(shi->ao));
- shr->alpha= (shr->alpha + f)*f;
- }
- else {
- shr->alpha -= f*IMB_colormanagement_get_luminance(shi->ao);
- if (shr->alpha<0.0f) shr->alpha=0.0f;
- }
- }
- else /* AO Multiply */
- shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*IMB_colormanagement_get_luminance(shi->ao));
- }
-
- if (R.wrld.mode & WO_ENV_LIGHT) {
- if (shi->mat->shadowonly_flag == MA_SO_OLD) {
- f= R.wrld.ao_env_energy*shi->amb*(1.0f - IMB_colormanagement_get_luminance(shi->env));
- shr->alpha= (shr->alpha + f)*f;
- }
- else {
- f= R.wrld.ao_env_energy*shi->amb;
- shr->alpha -= f*IMB_colormanagement_get_luminance(shi->env);
- if (shr->alpha<0.0f) shr->alpha=0.0f;
- }
- }
- }
-}
-
-/* let's map negative light as if it mirrors positive light, otherwise negative values disappear */
-static void wrld_exposure_correct(float diff[3])
-{
-
- diff[0]= R.wrld.linfac*(1.0f-expf( diff[0]*R.wrld.logfac) );
- diff[1]= R.wrld.linfac*(1.0f-expf( diff[1]*R.wrld.logfac) );
- diff[2]= R.wrld.linfac*(1.0f-expf( diff[2]*R.wrld.logfac) );
-}
-
-void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
-{
- /* Passes which might need to know material color.
- *
- * It seems to be faster to just calculate material color
- * even if the pass doesn't really need it than trying to
- * figure out whether color is really needed or not.
- */
- const int color_passes =
- SCE_PASS_COMBINED | SCE_PASS_RGBA | SCE_PASS_DIFFUSE | SCE_PASS_SPEC |
- SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT | SCE_PASS_SHADOW;
-
- Material *ma= shi->mat;
- int passflag= shi->passflag;
-
- memset(shr, 0, sizeof(ShadeResult));
-
- if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
-
- /* separate loop */
- if (ma->mode & MA_ONLYSHADOW) {
- shade_lamp_loop_only_shadow(shi, shr);
- return;
- }
-
- /* envmap hack, always reset */
- shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f;
-
- /* material color itself */
- if (passflag & color_passes) {
- if (ma->mode & (MA_FACETEXTURE)) {
- shi->r= shi->vcol[0];
- shi->g= shi->vcol[1];
- shi->b= shi->vcol[2];
- if (ma->mode & (MA_FACETEXTURE_ALPHA))
- shi->alpha= shi->vcol[3];
- }
-#ifdef WITH_FREESTYLE
- else if (ma->vcol_alpha) {
- shi->r= shi->vcol[0];
- shi->g= shi->vcol[1];
- shi->b= shi->vcol[2];
- shi->alpha= shi->vcol[3];
- }
-#endif
- else if (ma->mode & (MA_VERTEXCOLP)) {
- float neg_alpha = 1.0f - shi->vcol[3];
- shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3];
- shi->g= shi->g*neg_alpha + shi->vcol[1]*shi->vcol[3];
- shi->b= shi->b*neg_alpha + shi->vcol[2]*shi->vcol[3];
- }
- if (ma->texco) {
- do_material_tex(shi, &R);
- if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
- }
-
- shr->col[0]= shi->r*shi->alpha;
- shr->col[1]= shi->g*shi->alpha;
- shr->col[2]= shi->b*shi->alpha;
- shr->col[3]= shi->alpha;
-
- if ((ma->sss_flag & MA_DIFF_SSS) && !sss_pass_done(&R, ma)) {
- if (ma->sss_texfac == 0.0f) {
- shi->r= shi->g= shi->b= shi->alpha= 1.0f;
- shr->col[0]= shr->col[1]= shr->col[2]= shr->col[3]= 1.0f;
- }
- else {
- shi->r= pow(max_ff(shi->r, 0.0f), ma->sss_texfac);
- shi->g= pow(max_ff(shi->g, 0.0f), ma->sss_texfac);
- shi->b= pow(max_ff(shi->b, 0.0f), ma->sss_texfac);
- shi->alpha= pow(max_ff(shi->alpha, 0.0f), ma->sss_texfac);
-
- shr->col[0]= pow(max_ff(shr->col[0], 0.0f), ma->sss_texfac);
- shr->col[1]= pow(max_ff(shr->col[1], 0.0f), ma->sss_texfac);
- shr->col[2]= pow(max_ff(shr->col[2], 0.0f), ma->sss_texfac);
- shr->col[3]= pow(max_ff(shr->col[3], 0.0f), ma->sss_texfac);
- }
- }
- }
-
- if (ma->mode & MA_SHLESS) {
- shr->combined[0]= shi->r;
- shr->combined[1]= shi->g;
- shr->combined[2]= shi->b;
- shr->alpha= shi->alpha;
- goto finally_shadeless;
- }
-
- if ( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { /* vertexcolor light */
- shr->emit[0]= shi->r*(shi->emit+shi->vcol[0]*shi->vcol[3]);
- shr->emit[1]= shi->g*(shi->emit+shi->vcol[1]*shi->vcol[3]);
- shr->emit[2]= shi->b*(shi->emit+shi->vcol[2]*shi->vcol[3]);
- }
- else {
- shr->emit[0]= shi->r*shi->emit;
- shr->emit[1]= shi->g*shi->emit;
- shr->emit[2]= shi->b*shi->emit;
- }
-
- /* AO pass */
- if (((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) ||
- (passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT)))
- {
- if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (R.r.mode & R_SHADOW)) {
- /* AO was calculated for scanline already */
- if (shi->depth || shi->volume_depth)
- ambient_occlusion(shi);
- copy_v3_v3(shr->ao, shi->ao);
- copy_v3_v3(shr->env, shi->env); /* XXX multiply */
- copy_v3_v3(shr->indirect, shi->indirect); /* XXX multiply */
- }
- else {
- shr->ao[0]= shr->ao[1]= shr->ao[2]= 1.0f;
- zero_v3(shr->env);
- zero_v3(shr->indirect);
- }
- }
-
- /* lighting pass */
- if (passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) {
- GroupObject *go;
- ListBase *lights;
- LampRen *lar;
-
- lights= get_lights(shi);
- for (go=lights->first; go; go= go->next) {
- lar= go->lampren;
- if (lar==NULL) continue;
-
- /* test for lamp layer */
- if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue;
- if ((lar->lay & shi->lay)==0) continue;
-
- /* accumulates in shr->diff and shr->spec and shr->shad (diffuse with shadow!) */
- shade_one_light(lar, shi, shr, passflag);
- }
-
- /* this check is to prevent only shadow lamps from producing negative
- * colors.*/
- if (shr->spec[0] < 0) shr->spec[0] = 0;
- if (shr->spec[1] < 0) shr->spec[1] = 0;
- if (shr->spec[2] < 0) shr->spec[2] = 0;
-
- if (shr->shad[0] < 0) shr->shad[0] = 0;
- if (shr->shad[1] < 0) shr->shad[1] = 0;
- if (shr->shad[2] < 0) shr->shad[2] = 0;
-
- if (ma->sss_flag & MA_DIFF_SSS) {
- float sss[3], col[3], invalpha, texfac= ma->sss_texfac;
-
- /* this will return false in the preprocess stage */
- if (sample_sss(&R, ma, shi->co, sss)) {
- invalpha= (shr->col[3] > FLT_EPSILON)? 1.0f/shr->col[3]: 1.0f;
-
- if (texfac==0.0f) {
- copy_v3_v3(col, shr->col);
- mul_v3_fl(col, invalpha);
- }
- else if (texfac==1.0f) {
- col[0]= col[1]= col[2]= 1.0f;
- mul_v3_fl(col, invalpha);
- }
- else {
- copy_v3_v3(col, shr->col);
- mul_v3_fl(col, invalpha);
- col[0]= pow(max_ff(col[0], 0.0f), 1.0f-texfac);
- col[1]= pow(max_ff(col[1], 0.0f), 1.0f-texfac);
- col[2]= pow(max_ff(col[2], 0.0f), 1.0f-texfac);
- }
-
- shr->diff[0]= sss[0]*col[0];
- shr->diff[1]= sss[1]*col[1];
- shr->diff[2]= sss[2]*col[2];
-
- if (shi->combinedflag & SCE_PASS_SHADOW) {
- shr->shad[0]= shr->diff[0];
- shr->shad[1]= shr->diff[1];
- shr->shad[2]= shr->diff[2];
- }
- }
- }
-
- if (shi->combinedflag & SCE_PASS_SHADOW)
- copy_v3_v3(shr->diffshad, shr->shad);
- else
- copy_v3_v3(shr->diffshad, shr->diff);
-
- copy_v3_v3(shr->combined, shr->diffshad);
-
- /* calculate shadow pass, we use a multiplication mask */
- /* Even if diff = 0,0,0, it does matter what the shadow pass is, since we may want it 'for itself'! */
- if (passflag & SCE_PASS_SHADOW) {
- if (shr->diff[0]!=0.0f) shr->shad[0]= shr->shad[0]/shr->diff[0];
- /* can't determine proper shadow from shad/diff (0/0), so use shadow intensity */
- else if (shr->shad[0]==0.0f) shr->shad[0]= shr->shad[3];
-
- if (shr->diff[1]!=0.0f) shr->shad[1]= shr->shad[1]/shr->diff[1];
- else if (shr->shad[1]==0.0f) shr->shad[1]= shr->shad[3];
-
- if (shr->diff[2]!=0.0f) shr->shad[2]= shr->shad[2]/shr->diff[2];
- else if (shr->shad[2]==0.0f) shr->shad[2]= shr->shad[3];
- }
-
- /* exposure correction */
- if ((R.wrld.exp!=0.0f || R.wrld.range!=1.0f) && !R.sss_points) {
- wrld_exposure_correct(shr->combined); /* has no spec! */
- wrld_exposure_correct(shr->spec);
- }
- }
-
- /* alpha in end, spec can influence it */
- if (passflag & (SCE_PASS_COMBINED)) {
- if ((ma->fresnel_tra!=0.0f) && (shi->mode & MA_TRANSP))
- shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
-
- /* note: shi->mode! */
- if (shi->mode & MA_TRANSP && (shi->mode & (MA_ZTRANSP|MA_RAYTRANSP))) {
- if (shi->spectra!=0.0f) {
- float t = max_fff(shr->spec[0], shr->spec[1], shr->spec[2]);
- t *= shi->spectra;
- if (t>1.0f) t= 1.0f;
- shi->alpha= (1.0f-t)*shi->alpha+t;
- }
- }
- }
- shr->alpha= shi->alpha;
-
- /* from now stuff everything in shr->combined: ambient, AO, ramps, exposure */
- if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
- if (R.r.mode & R_SHADOW) {
- /* add AO in combined? */
- if (R.wrld.mode & WO_AMB_OCC)
- if (shi->combinedflag & SCE_PASS_AO)
- ambient_occlusion_apply(shi, shr);
-
- if (R.wrld.mode & WO_ENV_LIGHT)
- if (shi->combinedflag & SCE_PASS_ENVIRONMENT)
- environment_lighting_apply(shi, shr);
-
- if (R.wrld.mode & WO_INDIRECT_LIGHT)
- if (shi->combinedflag & SCE_PASS_INDIRECT)
- indirect_lighting_apply(shi, shr);
- }
-
- shr->combined[0]+= shi->ambr;
- shr->combined[1]+= shi->ambg;
- shr->combined[2]+= shi->ambb;
-
- if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi);
- }
-
- if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shi);
-
- /* refcol is for envmap only */
- if (shi->refcol[0]!=0.0f) {
- float result[3];
-
- result[0]= shi->mirr*shi->refcol[1] + (1.0f - shi->mirr*shi->refcol[0])*shr->combined[0];
- result[1]= shi->mirg*shi->refcol[2] + (1.0f - shi->mirg*shi->refcol[0])*shr->combined[1];
- result[2]= shi->mirb*shi->refcol[3] + (1.0f - shi->mirb*shi->refcol[0])*shr->combined[2];
-
- if (passflag & SCE_PASS_REFLECT)
- sub_v3_v3v3(shr->refl, result, shr->combined);
-
- if (shi->combinedflag & SCE_PASS_REFLECT)
- copy_v3_v3(shr->combined, result);
-
- }
-
- /* and add emit and spec */
- if (shi->combinedflag & SCE_PASS_EMIT)
- add_v3_v3(shr->combined, shr->emit);
- if (shi->combinedflag & SCE_PASS_SPEC)
- add_v3_v3(shr->combined, shr->spec);
-
-
- /* Last section of this function applies to shadeless colors too */
-finally_shadeless:
-
- /* modulate by the object color */
- if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
- if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
- float obcol[4];
-
- copy_v4_v4(obcol, shi->obr->ob->col);
- CLAMP(obcol[3], 0.0f, 1.0f);
-
- shr->combined[0] *= obcol[0];
- shr->combined[1] *= obcol[1];
- shr->combined[2] *= obcol[2];
- if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
- }
- }
-
- shr->combined[3]= shr->alpha;
-}
-
-/* used for "Lamp Data" shader node */
-static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[4], float lv[3], float *dist, float shadow[4])
-{
- LampRen *lar = go->lampren;
- float visifac, inp;
-
- if (!lar
- || ((lar->mode & LA_LAYER) && (lar->lay & shi->obi->lay) == 0)
- || (lar->lay & shi->lay) == 0)
- return 0.0f;
-
- if (lar->mode & LA_TEXTURE)
- do_lamp_tex(lar, lv, shi, col, LA_TEXTURE);
-
- visifac = lamp_get_visibility(lar, shi->co, lv, dist);
-
- if (visifac == 0.0f
- || lar->type == LA_HEMI
- || (lar->type != LA_SPOT && !(lar->mode & LA_SHAD_RAY))
- || (R.r.scemode & R_BUTS_PREVIEW))
- return visifac;
-
- inp = dot_v3v3(shi->vn, lv);
-
- if (inp > 0.0f) {
- float shadfac[4];
-
- shadow[0] = lar->shdwr;
- shadow[1] = lar->shdwg;
- shadow[2] = lar->shdwb;
-
- if (lar->mode & LA_SHAD_TEX)
- do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX);
-
- if (R.r.mode & R_SHADOW) {
- lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
-
- shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0]));
- shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1]));
- shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2]));
- }
- }
-
- return visifac;
-}
-
-float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4])
-{
- col[0] = col[1] = col[2] = 0.0f;
- col[3] = 1.0f;
- copy_v3_v3(lv, shi->vn);
- *dist = 1.0f;
- shadow[0] = shadow[1] = shadow[2] = shadow[3] = 1.0f;
-
- if (lamp_obj->type == OB_LAMP) {
- GroupObject *go;
- Lamp *lamp = (Lamp *)lamp_obj->data;
-
- col[0] = lamp->r * lamp->energy;
- col[1] = lamp->g * lamp->energy;
- col[2] = lamp->b * lamp->energy;
-
- if (R.r.scemode & R_BUTS_PREVIEW) {
- for (go = R.lights.first; go; go = go->next) {
- /* "Lamp.002" is main key light of material preview */
- if (STREQ(go->ob->id.name + 2, "Lamp.002"))
- return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
- }
- return 0.0f;
- }
-
- if (shi->light_override) {
- for (go = shi->light_override->gobject.first; go; go = go->next) {
- if (go->ob == lamp_obj)
- return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
- }
- }
-
- if (shi->mat && shi->mat->group) {
- for (go = shi->mat->group->gobject.first; go; go = go->next) {
- if (go->ob == lamp_obj)
- return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
- }
- }
-
- for (go = R.lights.first; go; go = go->next) {
- if (go->ob == lamp_obj)
- return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
- }
- }
-
- return 0.0f;
-}
-
-const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4]
-{
- if (obi) {
- switch (matrix_id) {
- case RE_OBJECT_INSTANCE_MATRIX_OB:
- return (const float(*)[4])obi->obmat;
- case RE_OBJECT_INSTANCE_MATRIX_OBINV:
- return (const float(*)[4])obi->obinvmat;
- case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW:
- return (const float(*)[4])obi->localtoviewmat;
- case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV:
- return (const float(*)[4])obi->localtoviewinvmat;
- }
- }
- return NULL;
-}
-
-float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi)
-{
- return obi->ob->index;
-}
-
-float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi)
-{
- return obi->random_id;
-}
-
-const float (*RE_render_current_get_matrix(int matrix_id))[4]
-{
- switch (matrix_id) {
- case RE_VIEW_MATRIX:
- return (const float(*)[4])R.viewmat;
- case RE_VIEWINV_MATRIX:
- return (const float(*)[4])R.viewinv;
- }
- return NULL;
-}
-
-float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta)
-{
- /* compute fresnel reflectance without explicitly computing
- * the refracted direction */
- float c = fabs(dot_v3v3(incoming, normal));
- float g = eta * eta - 1.0 + c * c;
- float result;
-
- if (g > 0.0) {
- g = sqrtf(g);
- float A = (g - c) / (g + c);
- float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
- result = 0.5 * A * A * (1.0 + B * B);
- }
- else {
- result = 1.0; /* TIR (no refracted component) */
- }
-
- return result;
-}
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
deleted file mode 100644
index 6c180c47152..00000000000
--- a/source/blender/render/intern/source/sss.c
+++ /dev/null
@@ -1,1073 +0,0 @@
-/*
- * ***** 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) 2007 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/sss.c
- * \ingroup render
- */
-
-/* Possible Improvements:
- * - add fresnel terms
- * - adapt Rd table to scale, now with small scale there are a lot of misses?
- * - possible interesting method: perform sss on all samples in the tree,
- * and then use those values interpolated somehow later. can also do this
- * filtering on demand for speed. since we are doing things in screen
- * space now there is an exact correspondence
- * - avoid duplicate shading (filtering points in advance, irradiance cache
- * like lookup?)
- * - lower resolution samples
- */
-
-#include <math.h>
-#include <string.h>
-#include <stdio.h>
-#include <string.h>
-
-/* external modules: */
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_memarena.h"
-
-#include "BLT_translation.h"
-
-
-#include "DNA_material_types.h"
-
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_scene.h"
-
-
-/* this module */
-#include "render_types.h"
-#include "sss.h"
-
-/* Generic Multiple Scattering API */
-
-/* Relevant papers:
- * [1] A Practical Model for Subsurface Light Transport
- * [2] A Rapid Hierarchical Rendering Technique for Translucent Materials
- * [3] Efficient Rendering of Local Subsurface Scattering
- * [4] Implementing a skin BSSRDF (or several...)
- */
-
-/* Defines */
-
-#define RD_TABLE_RANGE 100.0f
-#define RD_TABLE_RANGE_2 10000.0f
-#define RD_TABLE_SIZE 10000
-
-#define MAX_OCTREE_NODE_POINTS 8
-#define MAX_OCTREE_DEPTH 15
-
-/* Struct Definitions */
-
-struct ScatterSettings {
- float eta; /* index of refraction */
- float sigma_a; /* absorption coefficient */
- float sigma_s_; /* reduced scattering coefficient */
- float sigma_t_; /* reduced extinction coefficient */
- float sigma; /* effective extinction coefficient */
- float Fdr; /* diffuse fresnel reflectance */
- float D; /* diffusion constant */
- float A;
- float alpha_; /* reduced albedo */
- float zr; /* distance of virtual lightsource above surface */
- float zv; /* distance of virtual lightsource below surface */
- float ld; /* mean free path */
- float ro; /* diffuse reflectance */
- float color;
- float invsigma_t_;
- float frontweight;
- float backweight;
-
- float *tableRd; /* lookup table to avoid computing Rd */
- float *tableRd2; /* lookup table to avoid computing Rd for bigger values */
-};
-
-typedef struct ScatterPoint {
- float co[3];
- float rad[3];
- float area;
- int back;
-} ScatterPoint;
-
-typedef struct ScatterNode {
- float co[3];
- float rad[3];
- float backrad[3];
- float area, backarea;
-
- int totpoint;
- ScatterPoint *points;
-
- float split[3];
- struct ScatterNode *child[8];
-} ScatterNode;
-
-struct ScatterTree {
- MemArena *arena;
-
- ScatterSettings *ss[3];
- float error, scale;
-
- ScatterNode *root;
- ScatterPoint *points;
- ScatterPoint **refpoints;
- ScatterPoint **tmppoints;
- int totpoint;
- float min[3], max[3];
-};
-
-typedef struct ScatterResult {
- float rad[3];
- float backrad[3];
- float rdsum[3];
- float backrdsum[3];
-} ScatterResult;
-
-/* Functions for BSSRDF reparametrization in to more intuitive parameters,
- * see [2] section 4 for more info. */
-
-static float f_Rd(float alpha_, float A, float ro)
-{
- float sq;
-
- sq = sqrtf(3.0f * (1.0f - alpha_));
- return (alpha_/2.0f)*(1.0f + expf((-4.0f/3.0f)*A*sq))*expf(-sq) - ro;
-}
-
-static float compute_reduced_albedo(ScatterSettings *ss)
-{
- const float tolerance= 1e-8;
- const int max_iteration_count= 20;
- float d, fsub, xn_1= 0.0f, xn= 1.0f, fxn, fxn_1;
- int i;
-
- /* use secant method to compute reduced albedo using Rd function inverse
- * with a given reflectance */
- fxn= f_Rd(xn, ss->A, ss->ro);
- fxn_1= f_Rd(xn_1, ss->A, ss->ro);
-
- for (i= 0; i < max_iteration_count; i++) {
- fsub= (fxn - fxn_1);
- if (fabsf(fsub) < tolerance)
- break;
- d= ((xn - xn_1)/fsub)*fxn;
- if (fabsf(d) < tolerance)
- break;
-
- xn_1= xn;
- fxn_1= fxn;
- xn= xn - d;
-
- if (xn > 1.0f) xn= 1.0f;
- if (xn_1 > 1.0f) xn_1= 1.0f;
-
- fxn= f_Rd(xn, ss->A, ss->ro);
- }
-
- /* avoid division by zero later */
- if (xn <= 0.0f)
- xn= 0.00001f;
-
- return xn;
-}
-
-/* Exponential falloff functions */
-
-static float Rd_rsquare(ScatterSettings *ss, float rr)
-{
- float sr, sv, Rdr, Rdv;
-
- sr = sqrtf(rr + ss->zr * ss->zr);
- sv = sqrtf(rr + ss->zv * ss->zv);
-
- Rdr= ss->zr*(1.0f + ss->sigma*sr)*expf(-ss->sigma*sr)/(sr*sr*sr);
- Rdv= ss->zv*(1.0f + ss->sigma*sv)*expf(-ss->sigma*sv)/(sv*sv*sv);
-
- return /*ss->alpha_*/(1.0f/(4.0f*(float)M_PI))*(Rdr + Rdv);
-}
-
-static float Rd(ScatterSettings *ss, float r)
-{
- return Rd_rsquare(ss, r*r);
-}
-
-/* table lookups for Rd. this avoids expensive exp calls. we use two
- * separate tables as well for lower and higher numbers to improve
- * precision, since the number are poorly distributed because we do
- * a lookup with the squared distance for smaller distances, saving
- * another sqrt. */
-
-static void approximate_Rd_rgb(ScatterSettings **ss, float rr, float *rd)
-{
- float indexf, t, idxf;
- int index;
-
- if (rr > (RD_TABLE_RANGE_2 * RD_TABLE_RANGE_2)) {
- /* pass */
- }
- else if (rr > RD_TABLE_RANGE) {
- rr = sqrtf(rr);
- indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE_2);
- index= (int)indexf;
- idxf= (float)index;
- t= indexf - idxf;
-
- if (index >= 0 && index < RD_TABLE_SIZE) {
- rd[0]= (ss[0]->tableRd2[index]*(1-t) + ss[0]->tableRd2[index+1]*t);
- rd[1]= (ss[1]->tableRd2[index]*(1-t) + ss[1]->tableRd2[index+1]*t);
- rd[2]= (ss[2]->tableRd2[index]*(1-t) + ss[2]->tableRd2[index+1]*t);
- return;
- }
- }
- else {
- indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE);
- index= (int)indexf;
- idxf= (float)index;
- t= indexf - idxf;
-
- if (index >= 0 && index < RD_TABLE_SIZE) {
- rd[0]= (ss[0]->tableRd[index]*(1-t) + ss[0]->tableRd[index+1]*t);
- rd[1]= (ss[1]->tableRd[index]*(1-t) + ss[1]->tableRd[index+1]*t);
- rd[2]= (ss[2]->tableRd[index]*(1-t) + ss[2]->tableRd[index+1]*t);
- return;
- }
- }
-
- /* fallback to slow Rd computation */
- rd[0]= Rd_rsquare(ss[0], rr);
- rd[1]= Rd_rsquare(ss[1], rr);
- rd[2]= Rd_rsquare(ss[2], rr);
-}
-
-static void build_Rd_table(ScatterSettings *ss)
-{
- float r;
- int i, size = RD_TABLE_SIZE+1;
-
- ss->tableRd= MEM_mallocN(sizeof(float)*size, "scatterTableRd");
- ss->tableRd2= MEM_mallocN(sizeof(float)*size, "scatterTableRd");
-
- for (i= 0; i < size; i++) {
- r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE);
-#if 0
- if (r < ss->invsigma_t_*ss->invsigma_t_) {
- r= ss->invsigma_t_*ss->invsigma_t_;
- }
-#endif
- ss->tableRd[i]= Rd(ss, sqrtf(r));
-
- r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE);
-#if 0
- if (r < ss->invsigma_t_) {
- r= ss->invsigma_t_;
- }
-#endif
- ss->tableRd2[i]= Rd(ss, r);
- }
-}
-
-ScatterSettings *scatter_settings_new(float refl, float radius, float ior, float reflfac, float frontweight, float backweight)
-{
- ScatterSettings *ss;
-
- ss= MEM_callocN(sizeof(ScatterSettings), "ScatterSettings");
-
- /* see [1] and [3] for these formulas */
- ss->eta= ior;
- ss->Fdr= -1.440f/ior*ior + 0.710f/ior + 0.668f + 0.0636f*ior;
- ss->A= (1.0f + ss->Fdr)/(1.0f - ss->Fdr);
- ss->ld= radius;
- ss->ro= min_ff(refl, 0.99f);
- ss->color= ss->ro*reflfac + (1.0f-reflfac);
-
- ss->alpha_= compute_reduced_albedo(ss);
-
- ss->sigma= 1.0f/ss->ld;
- ss->sigma_t_= ss->sigma/sqrtf(3.0f*(1.0f - ss->alpha_));
- ss->sigma_s_= ss->alpha_*ss->sigma_t_;
- ss->sigma_a= ss->sigma_t_ - ss->sigma_s_;
-
- ss->D= 1.0f/(3.0f*ss->sigma_t_);
-
- ss->zr= 1.0f/ss->sigma_t_;
- ss->zv= ss->zr + 4.0f*ss->A*ss->D;
-
- ss->invsigma_t_= 1.0f/ss->sigma_t_;
-
- ss->frontweight= frontweight;
- ss->backweight= backweight;
-
- /* precompute a table of Rd values for quick lookup */
- build_Rd_table(ss);
-
- return ss;
-}
-
-void scatter_settings_free(ScatterSettings *ss)
-{
- MEM_freeN(ss->tableRd);
- MEM_freeN(ss->tableRd2);
- MEM_freeN(ss);
-}
-
-/* Hierarchical method as in [2]. */
-
-/* traversal */
-
-#define SUBNODE_INDEX(co, split) \
- ((co[0]>=split[0]) + (co[1]>=split[1])*2 + (co[2]>=split[2])*4)
-
-static void add_radiance(ScatterTree *tree, float *frontrad, float *backrad, float area, float backarea, float rr, ScatterResult *result)
-{
- float rd[3], frontrd[3], backrd[3];
-
- approximate_Rd_rgb(tree->ss, rr, rd);
-
- if (frontrad && area) {
- frontrd[0] = rd[0]*area;
- frontrd[1] = rd[1]*area;
- frontrd[2] = rd[2]*area;
-
- result->rad[0] += frontrad[0]*frontrd[0];
- result->rad[1] += frontrad[1]*frontrd[1];
- result->rad[2] += frontrad[2]*frontrd[2];
-
- result->rdsum[0] += frontrd[0];
- result->rdsum[1] += frontrd[1];
- result->rdsum[2] += frontrd[2];
- }
- if (backrad && backarea) {
- backrd[0] = rd[0]*backarea;
- backrd[1] = rd[1]*backarea;
- backrd[2] = rd[2]*backarea;
-
- result->backrad[0] += backrad[0]*backrd[0];
- result->backrad[1] += backrad[1]*backrd[1];
- result->backrad[2] += backrad[2]*backrd[2];
-
- result->backrdsum[0] += backrd[0];
- result->backrdsum[1] += backrd[1];
- result->backrdsum[2] += backrd[2];
- }
-}
-
-static void traverse_octree(ScatterTree *tree, ScatterNode *node, const float co[3], int self, ScatterResult *result)
-{
- float sub[3], dist;
- int i, index = 0;
-
- if (node->totpoint > 0) {
- /* leaf - add radiance from all samples */
- for (i=0; i<node->totpoint; i++) {
- ScatterPoint *p= &node->points[i];
-
- sub_v3_v3v3(sub, co, p->co);
- dist= dot_v3v3(sub, sub);
-
- if (p->back)
- add_radiance(tree, NULL, p->rad, 0.0f, p->area, dist, result);
- else
- add_radiance(tree, p->rad, NULL, p->area, 0.0f, dist, result);
- }
- }
- else {
- /* branch */
- if (self)
- index = SUBNODE_INDEX(co, node->split);
-
- for (i=0; i<8; i++) {
- if (node->child[i]) {
- ScatterNode *subnode= node->child[i];
-
- if (self && index == i) {
- /* always traverse node containing the point */
- traverse_octree(tree, subnode, co, 1, result);
- }
- else {
- /* decide subnode traversal based on maximum solid angle */
- sub_v3_v3v3(sub, co, subnode->co);
- dist= dot_v3v3(sub, sub);
-
- /* actually area/dist > error, but this avoids division */
- if (subnode->area+subnode->backarea>tree->error*dist) {
- traverse_octree(tree, subnode, co, 0, result);
- }
- else {
- add_radiance(tree, subnode->rad, subnode->backrad,
- subnode->area, subnode->backarea, dist, result);
- }
- }
- }
- }
- }
-}
-
-static void compute_radiance(ScatterTree *tree, const float co[3], float *rad)
-{
- ScatterResult result;
- float rdsum[3], backrad[3], backrdsum[3];
-
- memset(&result, 0, sizeof(result));
-
- traverse_octree(tree, tree->root, co, 1, &result);
-
- /* the original paper doesn't do this, but we normalize over the
- * sampled area and multiply with the reflectance. this is because
- * our point samples are incomplete, there are no samples on parts
- * of the mesh not visible from the camera. this can not only make
- * it darker, but also lead to ugly color shifts */
-
- mul_v3_fl(result.rad, tree->ss[0]->frontweight);
- mul_v3_fl(result.backrad, tree->ss[0]->backweight);
-
- copy_v3_v3(rad, result.rad);
- add_v3_v3v3(backrad, result.rad, result.backrad);
-
- copy_v3_v3(rdsum, result.rdsum);
- add_v3_v3v3(backrdsum, result.rdsum, result.backrdsum);
-
- if (rdsum[0] > 1e-16f) rad[0]= tree->ss[0]->color*rad[0]/rdsum[0];
- if (rdsum[1] > 1e-16f) rad[1]= tree->ss[1]->color*rad[1]/rdsum[1];
- if (rdsum[2] > 1e-16f) rad[2]= tree->ss[2]->color*rad[2]/rdsum[2];
-
- if (backrdsum[0] > 1e-16f) backrad[0]= tree->ss[0]->color*backrad[0]/backrdsum[0];
- if (backrdsum[1] > 1e-16f) backrad[1]= tree->ss[1]->color*backrad[1]/backrdsum[1];
- if (backrdsum[2] > 1e-16f) backrad[2]= tree->ss[2]->color*backrad[2]/backrdsum[2];
-
- rad[0]= MAX2(rad[0], backrad[0]);
- rad[1]= MAX2(rad[1], backrad[1]);
- rad[2]= MAX2(rad[2], backrad[2]);
-}
-
-/* building */
-
-static void sum_leaf_radiance(ScatterTree *UNUSED(tree), ScatterNode *node)
-{
- ScatterPoint *p;
- float rad, totrad= 0.0f, inv;
- int i;
-
- node->co[0]= node->co[1]= node->co[2]= 0.0;
- node->rad[0]= node->rad[1]= node->rad[2]= 0.0;
- node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0;
-
- /* compute total rad, rad weighted average position,
- * and total area */
- for (i=0; i<node->totpoint; i++) {
- p= &node->points[i];
-
- rad= p->area*fabsf(p->rad[0] + p->rad[1] + p->rad[2]);
- totrad += rad;
-
- node->co[0] += rad*p->co[0];
- node->co[1] += rad*p->co[1];
- node->co[2] += rad*p->co[2];
-
- if (p->back) {
- node->backrad[0] += p->rad[0]*p->area;
- node->backrad[1] += p->rad[1]*p->area;
- node->backrad[2] += p->rad[2]*p->area;
-
- node->backarea += p->area;
- }
- else {
- node->rad[0] += p->rad[0]*p->area;
- node->rad[1] += p->rad[1]*p->area;
- node->rad[2] += p->rad[2]*p->area;
-
- node->area += p->area;
- }
- }
-
- if (node->area > 1e-16f) {
- inv= 1.0f/node->area;
- node->rad[0] *= inv;
- node->rad[1] *= inv;
- node->rad[2] *= inv;
- }
- if (node->backarea > 1e-16f) {
- inv= 1.0f/node->backarea;
- node->backrad[0] *= inv;
- node->backrad[1] *= inv;
- node->backrad[2] *= inv;
- }
-
- if (totrad > 1e-16f) {
- inv= 1.0f/totrad;
- node->co[0] *= inv;
- node->co[1] *= inv;
- node->co[2] *= inv;
- }
- else {
- /* make sure that if radiance is 0.0f, we still have these points in
- * the tree at a good position, they count for rdsum too */
- for (i=0; i<node->totpoint; i++) {
- p= &node->points[i];
-
- node->co[0] += p->co[0];
- node->co[1] += p->co[1];
- node->co[2] += p->co[2];
- }
-
- node->co[0] /= node->totpoint;
- node->co[1] /= node->totpoint;
- node->co[2] /= node->totpoint;
- }
-}
-
-static void sum_branch_radiance(ScatterTree *UNUSED(tree), ScatterNode *node)
-{
- ScatterNode *subnode;
- float rad, totrad= 0.0f, inv;
- int i, totnode;
-
- node->co[0]= node->co[1]= node->co[2]= 0.0;
- node->rad[0]= node->rad[1]= node->rad[2]= 0.0;
- node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0;
-
- /* compute total rad, rad weighted average position,
- * and total area */
- for (i=0; i<8; i++) {
- if (node->child[i] == NULL)
- continue;
-
- subnode= node->child[i];
-
- rad= subnode->area*fabsf(subnode->rad[0] + subnode->rad[1] + subnode->rad[2]);
- rad += subnode->backarea*fabsf(subnode->backrad[0] + subnode->backrad[1] + subnode->backrad[2]);
- totrad += rad;
-
- node->co[0] += rad*subnode->co[0];
- node->co[1] += rad*subnode->co[1];
- node->co[2] += rad*subnode->co[2];
-
- node->rad[0] += subnode->rad[0]*subnode->area;
- node->rad[1] += subnode->rad[1]*subnode->area;
- node->rad[2] += subnode->rad[2]*subnode->area;
-
- node->backrad[0] += subnode->backrad[0]*subnode->backarea;
- node->backrad[1] += subnode->backrad[1]*subnode->backarea;
- node->backrad[2] += subnode->backrad[2]*subnode->backarea;
-
- node->area += subnode->area;
- node->backarea += subnode->backarea;
- }
-
- if (node->area > 1e-16f) {
- inv= 1.0f/node->area;
- node->rad[0] *= inv;
- node->rad[1] *= inv;
- node->rad[2] *= inv;
- }
- if (node->backarea > 1e-16f) {
- inv= 1.0f/node->backarea;
- node->backrad[0] *= inv;
- node->backrad[1] *= inv;
- node->backrad[2] *= inv;
- }
-
- if (totrad > 1e-16f) {
- inv= 1.0f/totrad;
- node->co[0] *= inv;
- node->co[1] *= inv;
- node->co[2] *= inv;
- }
- else {
- /* make sure that if radiance is 0.0f, we still have these points in
- * the tree at a good position, they count for rdsum too */
- totnode= 0;
-
- for (i=0; i<8; i++) {
- if (node->child[i]) {
- subnode= node->child[i];
-
- node->co[0] += subnode->co[0];
- node->co[1] += subnode->co[1];
- node->co[2] += subnode->co[2];
-
- totnode++;
- }
- }
-
- node->co[0] /= totnode;
- node->co[1] /= totnode;
- node->co[2] /= totnode;
- }
-}
-
-static void sum_radiance(ScatterTree *tree, ScatterNode *node)
-{
- if (node->totpoint > 0) {
- sum_leaf_radiance(tree, node);
- }
- else {
- int i;
-
- for (i=0; i<8; i++)
- if (node->child[i])
- sum_radiance(tree, node->child[i]);
-
- sum_branch_radiance(tree, node);
- }
-}
-
-static void subnode_middle(int i, float *mid, float *subsize, float *submid)
-{
- int x= i & 1, y= i & 2, z= i & 4;
-
- submid[0]= mid[0] + ((x)? subsize[0]: -subsize[0]);
- submid[1]= mid[1] + ((y)? subsize[1]: -subsize[1]);
- submid[2]= mid[2] + ((z)? subsize[2]: -subsize[2]);
-}
-
-static void create_octree_node(ScatterTree *tree, ScatterNode *node, float *mid, float *size, ScatterPoint **refpoints, int depth)
-{
- ScatterNode *subnode;
- ScatterPoint **subrefpoints, **tmppoints= tree->tmppoints;
- int index, nsize[8], noffset[8], i, subco, used_nodes, usedi;
- float submid[3], subsize[3];
-
- /* stopping condition */
- if (node->totpoint <= MAX_OCTREE_NODE_POINTS || depth == MAX_OCTREE_DEPTH) {
- for (i=0; i<node->totpoint; i++)
- node->points[i]= *(refpoints[i]);
-
- return;
- }
-
- subsize[0]= size[0]*0.5f;
- subsize[1]= size[1]*0.5f;
- subsize[2]= size[2]*0.5f;
-
- node->split[0]= mid[0];
- node->split[1]= mid[1];
- node->split[2]= mid[2];
-
- memset(nsize, 0, sizeof(nsize));
- memset(noffset, 0, sizeof(noffset));
-
- /* count points in subnodes */
- for (i=0; i<node->totpoint; i++) {
- index= SUBNODE_INDEX(refpoints[i]->co, node->split);
- tmppoints[i]= refpoints[i];
- nsize[index]++;
- }
-
- /* here we check if only one subnode is used. if this is the case, we don't
- * create a new node, but rather call this function again, with different
- * size and middle position for the same node. */
- for (usedi=0, used_nodes=0, i=0; i<8; i++) {
- if (nsize[i]) {
- used_nodes++;
- usedi = i;
- }
- if (i != 0)
- noffset[i]= noffset[i-1]+nsize[i-1];
- }
-
- if (used_nodes <= 1) {
- subnode_middle(usedi, mid, subsize, submid);
- create_octree_node(tree, node, submid, subsize, refpoints, depth+1);
- return;
- }
-
- /* reorder refpoints by subnode */
- for (i=0; i<node->totpoint; i++) {
- index= SUBNODE_INDEX(tmppoints[i]->co, node->split);
- refpoints[noffset[index]]= tmppoints[i];
- noffset[index]++;
- }
-
- /* create subnodes */
- for (subco=0, i=0; i<8; subco+=nsize[i], i++) {
- if (nsize[i] > 0) {
- subnode= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode));
- node->child[i]= subnode;
- subnode->points= node->points + subco;
- subnode->totpoint= nsize[i];
- subrefpoints= refpoints + subco;
-
- subnode_middle(i, mid, subsize, submid);
-
- create_octree_node(tree, subnode, submid, subsize, subrefpoints,
- depth+1);
- }
- else
- node->child[i]= NULL;
- }
-
- node->points= NULL;
- node->totpoint= 0;
-}
-
-/* public functions */
-
-ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error,
- float (*co)[3], float (*color)[3], float *area, int totpoint)
-{
- ScatterTree *tree;
- ScatterPoint *points, **refpoints;
- int i;
-
- /* allocate tree */
- tree= MEM_callocN(sizeof(ScatterTree), "ScatterTree");
- tree->scale= scale;
- tree->error= error;
- tree->totpoint= totpoint;
-
- tree->ss[0]= ss[0];
- tree->ss[1]= ss[1];
- tree->ss[2]= ss[2];
-
- points = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints");
- refpoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterRefPoints");
-
- tree->points= points;
- tree->refpoints= refpoints;
-
- /* build points */
- INIT_MINMAX(tree->min, tree->max);
-
- for (i=0; i<totpoint; i++) {
- copy_v3_v3(points[i].co, co[i]);
- copy_v3_v3(points[i].rad, color[i]);
- points[i].area= fabsf(area[i])/(tree->scale*tree->scale);
- points[i].back= (area[i] < 0.0f);
-
- mul_v3_fl(points[i].co, 1.0f / tree->scale);
- minmax_v3v3_v3(tree->min, tree->max, points[i].co);
-
- refpoints[i]= points + i;
- }
-
- return tree;
-}
-
-void scatter_tree_build(ScatterTree *tree)
-{
- ScatterPoint *newpoints, **tmppoints;
- float mid[3], size[3];
- int totpoint= tree->totpoint;
-
- newpoints = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints");
- tmppoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterTmpPoints");
- tree->tmppoints= tmppoints;
-
- tree->arena= BLI_memarena_new(0x8000 * sizeof(ScatterNode), "sss tree arena");
- BLI_memarena_use_calloc(tree->arena);
-
- /* build tree */
- tree->root= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode));
- tree->root->points= newpoints;
- tree->root->totpoint= totpoint;
-
- mid[0]= (tree->min[0]+tree->max[0])*0.5f;
- mid[1]= (tree->min[1]+tree->max[1])*0.5f;
- mid[2]= (tree->min[2]+tree->max[2])*0.5f;
-
- size[0]= (tree->max[0]-tree->min[0])*0.5f;
- size[1]= (tree->max[1]-tree->min[1])*0.5f;
- size[2]= (tree->max[2]-tree->min[2])*0.5f;
-
- create_octree_node(tree, tree->root, mid, size, tree->refpoints, 0);
-
- MEM_freeN(tree->points);
- MEM_freeN(tree->refpoints);
- MEM_freeN(tree->tmppoints);
- tree->refpoints= NULL;
- tree->tmppoints= NULL;
- tree->points= newpoints;
-
- /* sum radiance at nodes */
- sum_radiance(tree, tree->root);
-}
-
-void scatter_tree_sample(ScatterTree *tree, const float co[3], float color[3])
-{
- float sco[3];
-
- copy_v3_v3(sco, co);
- mul_v3_fl(sco, 1.0f / tree->scale);
-
- compute_radiance(tree, sco, color);
-}
-
-void scatter_tree_free(ScatterTree *tree)
-{
- if (tree->arena) BLI_memarena_free(tree->arena);
- if (tree->points) MEM_freeN(tree->points);
- if (tree->refpoints) MEM_freeN(tree->refpoints);
-
- MEM_freeN(tree);
-}
-
-/* Internal Renderer API */
-
-/* sss tree building */
-
-typedef struct SSSData {
- ScatterTree *tree;
- ScatterSettings *ss[3];
-} SSSData;
-
-typedef struct SSSPoints {
- struct SSSPoints *next, *prev;
-
- float (*co)[3];
- float (*color)[3];
- float *area;
- int totpoint;
-} SSSPoints;
-
-static void sss_create_tree_mat(Render *re, Material *mat)
-{
- SSSPoints *p;
- RenderResult *rr;
- ListBase points;
- float (*co)[3] = NULL, (*color)[3] = NULL, *area = NULL;
- int totpoint = 0, osa, osaflag, frsflag, partsdone;
-
- if (re->test_break(re->tbh))
- return;
-
- points.first= points.last= NULL;
-
- /* TODO: this is getting a bit ugly, copying all those variables and
- * setting them back, maybe we need to create our own Render? */
-
- /* do SSS preprocessing render */
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- rr= re->result;
- osa= re->osa;
- osaflag= re->r.mode & R_OSA;
- frsflag= re->r.mode & R_EDGE_FRS;
- partsdone= re->i.partsdone;
-
- re->osa= 0;
- re->r.mode &= ~(R_OSA | R_EDGE_FRS);
- re->sss_points= &points;
- re->sss_mat= mat;
- re->i.partsdone = 0;
-
- if (!(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)))
- re->result= NULL;
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- RE_TileProcessor(re);
-
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- if (!(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
- RE_FreeRenderResult(re->result);
- re->result= rr;
- }
- BLI_rw_mutex_unlock(&re->resultmutex);
-
- re->i.partsdone= partsdone;
- re->sss_mat= NULL;
- re->sss_points= NULL;
- re->osa= osa;
- if (osaflag) re->r.mode |= R_OSA;
- if (frsflag) re->r.mode |= R_EDGE_FRS;
-
- /* no points? no tree */
- if (!points.first)
- return;
-
- /* merge points together into a single buffer */
- if (!re->test_break(re->tbh)) {
- for (totpoint=0, p=points.first; p; p=p->next)
- totpoint += p->totpoint;
-
- co= MEM_mallocN(sizeof(*co)*totpoint, "SSSCo");
- color= MEM_mallocN(sizeof(*color)*totpoint, "SSSColor");
- area= MEM_mallocN(sizeof(*area)*totpoint, "SSSArea");
-
- for (totpoint=0, p=points.first; p; p=p->next) {
- memcpy(co+totpoint, p->co, sizeof(*co)*p->totpoint);
- memcpy(color+totpoint, p->color, sizeof(*color)*p->totpoint);
- memcpy(area+totpoint, p->area, sizeof(*area)*p->totpoint);
- totpoint += p->totpoint;
- }
- }
-
- /* free points */
- for (p=points.first; p; p=p->next) {
- MEM_freeN(p->co);
- MEM_freeN(p->color);
- MEM_freeN(p->area);
- }
- BLI_freelistN(&points);
-
- /* build tree */
- if (!re->test_break(re->tbh)) {
- SSSData *sss= MEM_callocN(sizeof(*sss), "SSSData");
- float ior= mat->sss_ior, cfac= mat->sss_colfac;
- const float *radius = mat->sss_radius;
- float fw= mat->sss_front, bw= mat->sss_back;
- float error = mat->sss_error;
-
- error= get_render_aosss_error(&re->r, error);
- if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)) && error < 0.5f)
- error= 0.5f;
-
- sss->ss[0]= scatter_settings_new(mat->sss_col[0], radius[0], ior, cfac, fw, bw);
- sss->ss[1]= scatter_settings_new(mat->sss_col[1], radius[1], ior, cfac, fw, bw);
- sss->ss[2]= scatter_settings_new(mat->sss_col[2], radius[2], ior, cfac, fw, bw);
- sss->tree= scatter_tree_new(sss->ss, mat->sss_scale, error,
- co, color, area, totpoint);
-
- MEM_freeN(co);
- MEM_freeN(color);
- MEM_freeN(area);
-
- scatter_tree_build(sss->tree);
-
- BLI_ghash_insert(re->sss_hash, mat, sss);
- }
- else {
- if (co) MEM_freeN(co);
- if (color) MEM_freeN(color);
- if (area) MEM_freeN(area);
- }
-}
-
-void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint)
-{
- SSSPoints *p;
-
- if (totpoint > 0) {
- p= MEM_callocN(sizeof(SSSPoints), "SSSPoints");
-
- p->co= co;
- p->color= color;
- p->area= area;
- p->totpoint= totpoint;
-
- BLI_thread_lock(LOCK_CUSTOM1);
- BLI_addtail(re->sss_points, p);
- BLI_thread_unlock(LOCK_CUSTOM1);
- }
-}
-
-static void sss_free_tree(SSSData *sss)
-{
- scatter_tree_free(sss->tree);
- scatter_settings_free(sss->ss[0]);
- scatter_settings_free(sss->ss[1]);
- scatter_settings_free(sss->ss[2]);
- MEM_freeN(sss);
-}
-
-/* public functions */
-
-void make_sss_tree(Render *re)
-{
- Material *mat;
- bool infostr_set = false;
- const char *prevstr = NULL;
-
- free_sss(re);
-
- re->sss_hash= BLI_ghash_ptr_new("make_sss_tree gh");
-
- re->stats_draw(re->sdh, &re->i);
-
- for (mat= re->main->mat.first; mat; mat= mat->id.next) {
- if (mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS)) {
- if (!infostr_set) {
- prevstr = re->i.infostr;
- re->i.infostr = IFACE_("SSS preprocessing");
- infostr_set = true;
- }
-
- sss_create_tree_mat(re, mat);
- }
- }
-
- /* XXX preview exception */
- /* localizing preview render data is not fun for node trees :( */
- if (re->main!=G.main) {
- for (mat= G.main->mat.first; mat; mat= mat->id.next) {
- if (mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS)) {
- if (!infostr_set) {
- prevstr = re->i.infostr;
- re->i.infostr = IFACE_("SSS preprocessing");
- infostr_set = true;
- }
-
- sss_create_tree_mat(re, mat);
- }
- }
- }
-
- if (infostr_set)
- re->i.infostr = prevstr;
-}
-
-void free_sss(Render *re)
-{
- if (re->sss_hash) {
- GHashIterator gh_iter;
-
- GHASH_ITER (gh_iter, re->sss_hash) {
- sss_free_tree(BLI_ghashIterator_getValue(&gh_iter));
- }
-
- BLI_ghash_free(re->sss_hash, NULL, NULL);
- re->sss_hash= NULL;
- }
-}
-
-int sample_sss(Render *re, Material *mat, const float co[3], float color[3])
-{
- if (re->sss_hash) {
- SSSData *sss= BLI_ghash_lookup(re->sss_hash, mat);
-
- if (sss) {
- scatter_tree_sample(sss->tree, co, color);
- return 1;
- }
- else {
- color[0]= 0.0f;
- color[1]= 0.0f;
- color[2]= 0.0f;
- }
- }
-
- return 0;
-}
-
-int sss_pass_done(struct Render *re, struct Material *mat)
-{
- return ((re->flag & R_BAKING) || !(re->r.mode & R_SSS) || (re->sss_hash && BLI_ghash_lookup(re->sss_hash, mat)));
-}
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
deleted file mode 100644
index 8f07b339929..00000000000
--- a/source/blender/render/intern/source/strand.c
+++ /dev/null
@@ -1,1068 +0,0 @@
-/*
- * ***** 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.
- *
- * Contributors: Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/strand.c
- * \ingroup render
- */
-
-
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_key_types.h"
-#include "DNA_material_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_memarena.h"
-#include "BLI_rand.h"
-
-#include "BKE_DerivedMesh.h"
-#include "BKE_key.h"
-
-
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "shading.h"
-#include "strand.h"
-#include "zbuf.h"
-
-/* *************** */
-
-static float strand_eval_width(Material *ma, float strandco)
-{
- float fac;
-
- strandco= 0.5f*(strandco + 1.0f);
-
- if (ma->strand_ease!=0.0f) {
- if (ma->strand_ease<0.0f)
- fac= pow(strandco, 1.0f+ma->strand_ease);
- else
- fac= pow(strandco, 1.0f/(1.0f-ma->strand_ease));
- }
- else fac= strandco;
-
- return ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
-}
-
-void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
-{
- Material *ma;
- StrandBuffer *strandbuf;
- const float *simplify;
- float p[4][3], data[4], cross[3], w, dx, dy, t;
- int type;
-
- strandbuf= sseg->buffer;
- ma= sseg->buffer->ma;
- t= spoint->t;
- type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL;
-
- copy_v3_v3(p[0], sseg->v[0]->co);
- copy_v3_v3(p[1], sseg->v[1]->co);
- copy_v3_v3(p[2], sseg->v[2]->co);
- copy_v3_v3(p[3], sseg->v[3]->co);
-
- if (sseg->obi->flag & R_TRANSFORMED) {
- mul_m4_v3(sseg->obi->mat, p[0]);
- mul_m4_v3(sseg->obi->mat, p[1]);
- mul_m4_v3(sseg->obi->mat, p[2]);
- mul_m4_v3(sseg->obi->mat, p[3]);
- }
-
- if (t == 0.0f) {
- copy_v3_v3(spoint->co, p[1]);
- spoint->strandco= sseg->v[1]->strandco;
-
- spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco);
- if (sseg->v[0] != sseg->v[1])
- spoint->dtstrandco *= 0.5f;
- }
- else if (t == 1.0f) {
- copy_v3_v3(spoint->co, p[2]);
- spoint->strandco= sseg->v[2]->strandco;
-
- spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco);
- if (sseg->v[3] != sseg->v[2])
- spoint->dtstrandco *= 0.5f;
- }
- else {
- key_curve_position_weights(t, data, type);
- spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
- spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
- spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
- spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco;
- }
-
- key_curve_tangent_weights(t, data, type);
- spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
- spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
- spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
-
- normalize_v3_v3(spoint->tan, spoint->dtco);
- normalize_v3_v3(spoint->nor, spoint->co);
- negate_v3(spoint->nor);
-
- spoint->width= strand_eval_width(ma, spoint->strandco);
-
- /* simplification */
- simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0);
- spoint->alpha= (simplify)? simplify[1]: 1.0f;
-
- /* outer points */
- cross_v3_v3v3(cross, spoint->co, spoint->tan);
-
- w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3];
- dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w;
- dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w;
- w = sqrtf(dx * dx + dy * dy);
-
- if (w > 0.0f) {
- if (strandbuf->flag & R_STRAND_B_UNITS) {
- const float crosslen= len_v3(cross);
- w= 2.0f*crosslen*strandbuf->minwidth/w;
-
- if (spoint->width < w) {
- spoint->alpha= spoint->width/w;
- spoint->width= w;
- }
-
- if (simplify)
- /* squared because we only change width, not length */
- spoint->width *= simplify[0]*simplify[0];
-
- mul_v3_fl(cross, spoint->width*0.5f/crosslen);
- }
- else
- mul_v3_fl(cross, spoint->width/w);
- }
-
- sub_v3_v3v3(spoint->co1, spoint->co, cross);
- add_v3_v3v3(spoint->co2, spoint->co, cross);
-
- copy_v3_v3(spoint->dsco, cross);
-}
-
-/* *************** */
-
-static void interpolate_vec1(float *v1, float *v2, float t, float negt, float *v)
-{
- v[0]= negt*v1[0] + t*v2[0];
-}
-
-static void interpolate_vec3(float *v1, float *v2, float t, float negt, float *v)
-{
- v[0]= negt*v1[0] + t*v2[0];
- v[1]= negt*v1[1] + t*v2[1];
- v[2]= negt*v1[2] + t*v2[2];
-}
-
-static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v)
-{
- v[0]= negt*v1[0] + t*v2[0];
- v[1]= negt*v1[1] + t*v2[1];
- v[2]= negt*v1[2] + t*v2[2];
- v[3]= negt*v1[3] + t*v2[3];
-}
-
-static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag)
-{
- float negt= 1.0f - t;
-
- interpolate_vec4(shr1->combined, shr2->combined, t, negt, shr->combined);
-
- if (addpassflag & SCE_PASS_VECTOR) {
- interpolate_vec4(shr1->winspeed, shr2->winspeed, t, negt, shr->winspeed);
- }
- /* optim... */
- if (addpassflag & ~(SCE_PASS_VECTOR)) {
- if (addpassflag & SCE_PASS_Z)
- interpolate_vec1(&shr1->z, &shr2->z, t, negt, &shr->z);
- if (addpassflag & SCE_PASS_RGBA)
- interpolate_vec4(shr1->col, shr2->col, t, negt, shr->col);
- if (addpassflag & SCE_PASS_NORMAL) {
- interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor);
- normalize_v3(shr->nor);
- }
- if (addpassflag & SCE_PASS_EMIT)
- interpolate_vec3(shr1->emit, shr2->emit, t, negt, shr->emit);
- if (addpassflag & SCE_PASS_DIFFUSE) {
- interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff);
- interpolate_vec3(shr1->diffshad, shr2->diffshad, t, negt, shr->diffshad);
- }
- if (addpassflag & SCE_PASS_SPEC)
- interpolate_vec3(shr1->spec, shr2->spec, t, negt, shr->spec);
- if (addpassflag & SCE_PASS_SHADOW)
- interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad);
- if (addpassflag & SCE_PASS_AO)
- interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao);
- if (addpassflag & SCE_PASS_ENVIRONMENT)
- interpolate_vec3(shr1->env, shr2->env, t, negt, shr->env);
- if (addpassflag & SCE_PASS_INDIRECT)
- interpolate_vec3(shr1->indirect, shr2->indirect, t, negt, shr->indirect);
- if (addpassflag & SCE_PASS_REFLECT)
- interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl);
- if (addpassflag & SCE_PASS_REFRACT)
- interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr);
- if (addpassflag & SCE_PASS_MIST)
- interpolate_vec1(&shr1->mist, &shr2->mist, t, negt, &shr->mist);
- }
-}
-
-static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha)
-{
- if (alpha < 1.0f) {
- shr->combined[0] *= alpha;
- shr->combined[1] *= alpha;
- shr->combined[2] *= alpha;
- shr->combined[3] *= alpha;
-
- shr->col[0] *= alpha;
- shr->col[1] *= alpha;
- shr->col[2] *= alpha;
- shr->col[3] *= alpha;
-
- shr->alpha *= alpha;
- }
-}
-
-static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert, StrandPoint *spoint)
-{
- ShadeInput *shi= ssamp->shi;
- ShadeResult *shr= ssamp->shr;
- VlakRen vlr;
- int seed;
-
- memset(&vlr, 0, sizeof(vlr));
- vlr.flag= R_SMOOTH;
- if (sseg->buffer->ma->mode & MA_TANGENT_STR)
- vlr.flag |= R_TANGENT;
-
- shi->vlr= &vlr;
- shi->v1= NULL;
- shi->v2= NULL;
- shi->v3= NULL;
- shi->strand= sseg->strand;
- shi->obi= sseg->obi;
- shi->obr= sseg->obi->obr;
-
- /* cache for shadow */
- shi->samplenr= re->shadowsamplenr[shi->thread]++;
-
- /* all samples */
- shi->mask= 0xFFFF;
-
- /* seed RNG for consistent results across tiles */
- seed = shi->strand->index + (svert - shi->strand->vert);
- BLI_thread_srandom(shi->thread, seed);
-
- shade_input_set_strand(shi, sseg->strand, spoint);
- shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint);
-
- /* init material vars */
- shade_input_init_material(shi);
-
- /* shade */
- shade_samples_do_AO(ssamp);
- shade_input_do_shade(shi, shr);
-
- /* apply simplification */
- strand_apply_shaderesult_alpha(shr, spoint->alpha);
-
- /* include lamphalos for strand, since halo layer was added already */
- if (re->flag & R_LAMPHALO)
- if (shi->layflag & SCE_LAY_HALO)
- renderspothalo(shi, shr->combined, shr->combined[3]);
-
- shi->strand= NULL;
-}
-
-/* *************** */
-
-struct StrandShadeCache {
- GHash *resulthash;
- GHash *refcounthash;
- MemArena *memarena;
-};
-
-typedef struct StrandCacheEntry {
- GHashPair pair;
- ShadeResult shr;
-} StrandCacheEntry;
-
-StrandShadeCache *strand_shade_cache_create(void)
-{
- StrandShadeCache *cache;
-
- cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache");
- cache->resulthash= BLI_ghash_pair_new("strand_shade_cache_create1 gh");
- cache->refcounthash= BLI_ghash_pair_new("strand_shade_cache_create2 gh");
- cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand shade cache arena");
-
- return cache;
-}
-
-void strand_shade_cache_free(StrandShadeCache *cache)
-{
- BLI_ghash_free(cache->refcounthash, NULL, NULL);
- BLI_ghash_free(cache->resulthash, MEM_freeN, NULL);
- BLI_memarena_free(cache->memarena);
- MEM_freeN(cache);
-}
-
-static GHashPair strand_shade_hash_pair(ObjectInstanceRen *obi, StrandVert *svert)
-{
- GHashPair pair = {obi, svert};
- return pair;
-}
-
-static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert)
-{
- StrandCacheEntry *entry;
- StrandPoint p;
- int *refcount;
- GHashPair pair = strand_shade_hash_pair(sseg->obi, svert);
-
- entry= BLI_ghash_lookup(cache->resulthash, &pair);
- refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
-
- if (!entry) {
- /* not shaded yet, shade and insert into hash */
- p.t= (sseg->v[1] == svert)? 0.0f: 1.0f;
- strand_eval_point(sseg, &p);
- strand_shade_point(re, ssamp, sseg, svert, &p);
-
- entry= MEM_callocN(sizeof(StrandCacheEntry), "StrandCacheEntry");
- entry->pair = pair;
- entry->shr = ssamp->shr[0];
- BLI_ghash_insert(cache->resulthash, entry, entry);
- }
- else
- /* already shaded, just copy previous result from hash */
- ssamp->shr[0]= entry->shr;
-
- /* lower reference count and remove if not needed anymore by any samples */
- (*refcount)--;
- if (*refcount == 0) {
- BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL);
- BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL);
- }
-}
-
-void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag)
-{
- ShadeResult shr1, shr2;
-
- /* get shading for two endpoints and interpolate */
- strand_shade_get(re, cache, ssamp, sseg, sseg->v[1]);
- shr1= ssamp->shr[0];
- strand_shade_get(re, cache, ssamp, sseg, sseg->v[2]);
- shr2= ssamp->shr[0];
-
- interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag);
-
- /* apply alpha along width */
- if (sseg->buffer->widthfade != -1.0f) {
- s = 1.0f - powf(fabsf(s), sseg->buffer->widthfade);
-
- strand_apply_shaderesult_alpha(ssamp->shr, s);
- }
-}
-
-void strand_shade_unref(StrandShadeCache *cache, ObjectInstanceRen *obi, StrandVert *svert)
-{
- GHashPair pair = strand_shade_hash_pair(obi, svert);
- int *refcount;
-
- /* lower reference count and remove if not needed anymore by any samples */
- refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
-
- (*refcount)--;
- if (*refcount == 0) {
- BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL);
- BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL);
- }
-}
-
-static void strand_shade_refcount(StrandShadeCache *cache, StrandSegment *sseg, StrandVert *svert)
-{
- GHashPair pair = strand_shade_hash_pair(sseg->obi, svert);
- GHashPair *key;
- int *refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
-
- if (!refcount) {
- key= BLI_memarena_alloc(cache->memarena, sizeof(GHashPair));
- *key = pair;
- refcount= BLI_memarena_alloc(cache->memarena, sizeof(int));
- *refcount= 1;
- BLI_ghash_insert(cache->refcounthash, key, refcount);
- }
- else
- (*refcount)++;
-}
-
-/* *************** */
-
-typedef struct StrandPart {
- Render *re;
- ZSpan *zspan;
-
- APixstrand *apixbuf;
- int *totapixbuf;
- int *rectz;
- int *rectmask;
- intptr_t *rectdaps;
- int rectx, recty;
- int sample;
- int shadow;
- float (*jit)[2];
- int samples;
-
- StrandSegment *segment;
- float t[3], s[3];
-
- StrandShadeCache *cache;
-} StrandPart;
-
-typedef struct StrandSortSegment {
- struct StrandSortSegment *next;
- int obi, strand, segment;
- float z;
-} StrandSortSegment;
-
-static int compare_strand_segment(const void *poin1, const void *poin2)
-{
- const StrandSortSegment *seg1= (const StrandSortSegment*)poin1;
- const StrandSortSegment *seg2= (const StrandSortSegment*)poin2;
-
- if (seg1->z < seg2->z)
- return -1;
- else if (seg1->z == seg2->z)
- return 0;
- else
- return 1;
-}
-
-static void do_strand_point_project(float winmat[4][4], ZSpan *zspan, float *co, float *hoco, float *zco)
-{
- projectvert(co, winmat, hoco);
- hoco_to_zco(zspan, zco, hoco);
-}
-
-static void strand_project_point(float winmat[4][4], float winx, float winy, StrandPoint *spoint)
-{
- float div;
-
- projectvert(spoint->co, winmat, spoint->hoco);
-
- div= 1.0f/spoint->hoco[3];
- spoint->x= spoint->hoco[0]*div*winx*0.5f;
- spoint->y= spoint->hoco[1]*div*winy*0.5f;
-}
-
-static APixstrand *addpsmainAstrand(ListBase *lb)
-{
- APixstrMain *psm;
-
- psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA");
- BLI_addtail(lb, psm);
- psm->ps = MEM_callocN(4096 * sizeof(APixstrand), "pixstr");
-
- return psm->ps;
-}
-
-static APixstrand *addpsAstrand(ZSpan *zspan)
-{
- /* make new PS */
- if (zspan->apstrandmcounter==0) {
- zspan->curpstrand= addpsmainAstrand(zspan->apsmbase);
- zspan->apstrandmcounter= 4095;
- }
- else {
- zspan->curpstrand++;
- zspan->apstrandmcounter--;
- }
- return zspan->curpstrand;
-}
-
-#define MAX_ZROW 2000
-
-static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z)
-{
- StrandPart *spart= (StrandPart *)handle;
- StrandShadeCache *cache= spart->cache;
- StrandSegment *sseg= spart->segment;
- APixstrand *apn, *apnew;
- float t, s;
- int offset, mask, obi, strnr, seg, zverg, bufferz, maskz=0;
-
- offset = y*spart->rectx + x;
- obi= sseg->obi - spart->re->objectinstance;
- strnr= sseg->strand->index + 1;
- seg= sseg->v[1] - sseg->strand->vert;
- mask= (1<<spart->sample);
-
- /* check against solid z-buffer */
- zverg= (int)z;
-
- if (spart->rectdaps) {
- /* find the z of the sample */
- PixStr *ps;
- intptr_t *rd= spart->rectdaps + offset;
-
- bufferz= 0x7FFFFFFF;
- if (spart->rectmask) maskz= 0x7FFFFFFF;
-
- if (*rd) {
- for (ps= (PixStr *)(*rd); ps; ps= ps->next) {
- if (mask & ps->mask) {
- bufferz= ps->z;
- if (spart->rectmask)
- maskz= ps->maskz;
- break;
- }
- }
- }
- }
- else {
- bufferz= (spart->rectz)? spart->rectz[offset]: 0x7FFFFFFF;
- if (spart->rectmask)
- maskz= spart->rectmask[offset];
- }
-
-#define CHECK_ADD(n) \
- if (apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \
- { if (!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; } (void)0
-#define CHECK_ASSIGN(n) \
- if (apn->p[n]==0) \
- {apn->obi[n]= obi; apn->p[n]= strnr; apn->z[n]= zverg; apn->mask[n]= mask; apn->v[n]= t; apn->u[n]= s; apn->seg[n]= seg; break; } (void)0
-
- /* add to pixel list */
- if (zverg < bufferz && (spart->totapixbuf[offset] < MAX_ZROW)) {
- if (!spart->rectmask || zverg > maskz) {
- t = u * spart->t[0] + v * spart->t[1] + (1.0f - u - v) * spart->t[2];
- s = fabsf(u * spart->s[0] + v * spart->s[1] + (1.0f - u - v) * spart->s[2]);
-
- apn= spart->apixbuf + offset;
- while (apn) {
- CHECK_ADD(0);
- CHECK_ADD(1);
- CHECK_ADD(2);
- CHECK_ADD(3);
- CHECK_ASSIGN(0);
- CHECK_ASSIGN(1);
- CHECK_ASSIGN(2);
- CHECK_ASSIGN(3);
-
- apnew= addpsAstrand(spart->zspan);
- SWAP(APixstrand, *apnew, *apn);
- apn->next= apnew;
- CHECK_ASSIGN(0);
- }
-
- if (cache) {
- strand_shade_refcount(cache, sseg, sseg->v[1]);
- strand_shade_refcount(cache, sseg, sseg->v[2]);
- }
- spart->totapixbuf[offset]++;
- }
- }
-}
-
-/* width is calculated in hoco space, to ensure strands are visible */
-static int strand_test_clip(float winmat[4][4], ZSpan *UNUSED(zspan), float *bounds, float *co, float *zcomp, float widthx, float widthy)
-{
- float hoco[4];
- int clipflag= 0;
-
- projectvert(co, winmat, hoco);
-
- /* we compare z without perspective division for segment sorting */
- *zcomp= hoco[2];
-
- if (hoco[0]+widthx < bounds[0]*hoco[3]) clipflag |= 1;
- else if (hoco[0]-widthx > bounds[1]*hoco[3]) clipflag |= 2;
-
- if (hoco[1]-widthy > bounds[3]*hoco[3]) clipflag |= 4;
- else if (hoco[1]+widthy < bounds[2]*hoco[3]) clipflag |= 8;
-
- clipflag |= testclip(hoco);
-
- return clipflag;
-}
-
-static void do_scanconvert_strand(Render *UNUSED(re), StrandPart *spart, ZSpan *zspan, float t, float dt, float *co1, float *co2, float *co3, float *co4, int sample)
-{
- float jco1[3], jco2[3], jco3[3], jco4[3], jx, jy;
-
- copy_v3_v3(jco1, co1);
- copy_v3_v3(jco2, co2);
- copy_v3_v3(jco3, co3);
- copy_v3_v3(jco4, co4);
-
- if (spart->jit) {
- jx= -spart->jit[sample][0];
- jy= -spart->jit[sample][1];
-
- jco1[0] += jx; jco1[1] += jy;
- jco2[0] += jx; jco2[1] += jy;
- jco3[0] += jx; jco3[1] += jy;
- jco4[0] += jx; jco4[1] += jy;
-
- /* XXX mblur? */
- }
-
- spart->sample= sample;
-
- spart->t[0]= t-dt;
- spart->s[0]= -1.0f;
- spart->t[1]= t-dt;
- spart->s[1]= 1.0f;
- spart->t[2]= t;
- spart->s[2]= 1.0f;
- zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_fillac);
- spart->t[0]= t-dt;
- spart->s[0]= -1.0f;
- spart->t[1]= t;
- spart->s[1]= 1.0f;
- spart->t[2]= t;
- spart->s[2]= -1.0f;
- zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac);
-}
-
-static void strand_render(Render *re, StrandSegment *sseg, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2)
-{
- if (spart) {
- float t= p2->t;
- float dt= p2->t - p1->t;
- int a;
-
- for (a=0; a<spart->samples; a++)
- do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, a);
- }
- else {
- float hoco1[4], hoco2[4];
- int a, obi, index;
-
- obi= sseg->obi - re->objectinstance;
- index= sseg->strand->index;
-
- projectvert(p1->co, winmat, hoco1);
- projectvert(p2->co, winmat, hoco2);
-
-
- for (a=0; a<totzspan; a++) {
-#if 0
- /* render both strand and single pixel wire to counter aliasing */
- zbufclip4(re, &zspan[a], obi, index, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, p1->clip2, p1->clip1, p2->clip1, p2->clip2);
-#endif
- /* only render a line for now, which makes the shadow map more
- * similar across frames, and so reduces flicker */
- zbufsinglewire(&zspan[a], obi, index, hoco1, hoco2);
- }
- }
-}
-
-static int strand_segment_recursive(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth)
-{
- StrandPoint p;
- StrandBuffer *buffer= sseg->buffer;
- float dot, d1[2], d2[2], len1, len2;
-
- if (depth == buffer->maxdepth)
- return 0;
-
- p.t= (p1->t + p2->t)*0.5f;
- strand_eval_point(sseg, &p);
- strand_project_point(buffer->winmat, buffer->winx, buffer->winy, &p);
-
- d1[0]= (p.x - p1->x);
- d1[1]= (p.y - p1->y);
- len1= d1[0]*d1[0] + d1[1]*d1[1];
-
- d2[0]= (p2->x - p.x);
- d2[1]= (p2->y - p.y);
- len2= d2[0]*d2[0] + d2[1]*d2[1];
-
- if (len1 == 0.0f || len2 == 0.0f)
- return 0;
-
- dot= d1[0]*d2[0] + d1[1]*d2[1];
- if (dot*dot > sseg->sqadaptcos*len1*len2)
- return 0;
-
- if (spart) {
- do_strand_point_project(winmat, zspan, p.co1, p.hoco1, p.zco1);
- do_strand_point_project(winmat, zspan, p.co2, p.hoco2, p.zco2);
- }
- else {
-#if 0
- projectvert(p.co1, winmat, p.hoco1);
- projectvert(p.co2, winmat, p.hoco2);
- p.clip1= testclip(p.hoco1);
- p.clip2= testclip(p.hoco2);
-#endif
- }
-
- if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, &p, depth+1))
- strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, &p);
- if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, &p, p2, depth+1))
- strand_render(re, sseg, winmat, spart, zspan, totzspan, &p, p2);
-
- return 1;
-}
-
-void render_strand_segment(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg)
-{
- StrandBuffer *buffer= sseg->buffer;
- StrandPoint *p1= &sseg->point1;
- StrandPoint *p2= &sseg->point2;
-
- p1->t= 0.0f;
- p2->t= 1.0f;
-
- strand_eval_point(sseg, p1);
- strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p1);
- strand_eval_point(sseg, p2);
- strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p2);
-
- if (spart) {
- do_strand_point_project(winmat, zspan, p1->co1, p1->hoco1, p1->zco1);
- do_strand_point_project(winmat, zspan, p1->co2, p1->hoco2, p1->zco2);
- do_strand_point_project(winmat, zspan, p2->co1, p2->hoco1, p2->zco1);
- do_strand_point_project(winmat, zspan, p2->co2, p2->hoco2, p2->zco2);
- }
- else {
-#if 0
- projectvert(p1->co1, winmat, p1->hoco1);
- projectvert(p1->co2, winmat, p1->hoco2);
- projectvert(p2->co1, winmat, p2->hoco1);
- projectvert(p2->co2, winmat, p2->hoco2);
- p1->clip1= testclip(p1->hoco1);
- p1->clip2= testclip(p1->hoco2);
- p2->clip1= testclip(p2->hoco1);
- p2->clip2= testclip(p2->hoco2);
-#endif
- }
-
- if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, p2, 0))
- strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, p2);
-}
-
-/* render call to fill in strands */
-int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[4][4], int winx, int winy, int samples, float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache)
-{
- ObjectRen *obr;
- ObjectInstanceRen *obi;
- ZSpan zspan;
- StrandRen *strand = NULL;
- StrandVert *svert;
- StrandBound *sbound;
- StrandPart spart;
- StrandSegment sseg;
- StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg;
- MemArena *memarena;
- float z[4], bounds[4], obwinmat[4][4];
- int a, b, c, i, totsegment, clip[4];
-
- if (re->test_break(re->tbh))
- return 0;
- if (re->totstrand == 0)
- return 0;
-
- /* setup StrandPart */
- memset(&spart, 0, sizeof(spart));
-
- spart.re= re;
- spart.rectx= pa->rectx;
- spart.recty= pa->recty;
- spart.apixbuf= apixbuf;
- spart.zspan= &zspan;
- spart.rectdaps= pa->rectdaps;
- spart.rectz= pa->rectz;
- spart.rectmask= pa->rectmask;
- spart.cache= cache;
- spart.shadow= shadow;
- spart.jit= jit;
- spart.samples= samples;
-
- zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop);
-
- /* needed for transform from hoco to zbuffer co */
- zspan.zmulx= ((float)winx)/2.0f;
- zspan.zmuly= ((float)winy)/2.0f;
-
- zspan.zofsx= -pa->disprect.xmin;
- zspan.zofsy= -pa->disprect.ymin;
-
- /* to center the sample position */
- if (!shadow) {
- zspan.zofsx -= 0.5f;
- zspan.zofsy -= 0.5f;
- }
-
- zspan.apsmbase= apsmbase;
-
- /* clipping setup */
- bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx;
- bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx;
- bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy;
- bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy;
-
- memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena");
- firstseg= NULL;
- totsegment= 0;
-
- /* for all object instances */
- for (obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) {
- Material *ma;
- float widthx, widthy;
-
- obr= obi->obr;
-
- if (!obr->strandbuf || !(obr->strandbuf->lay & lay))
- continue;
-
- /* compute matrix and try clipping whole object */
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- /* test if we should skip it */
- ma = obr->strandbuf->ma;
-
- if (shadow && (!(ma->mode2 & MA_CASTSHADOW) || !(ma->mode & MA_SHADBUF)))
- continue;
- else if (!shadow && (ma->mode & MA_ONLYCAST))
- continue;
-
- if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
- continue;
-
- widthx= obr->strandbuf->maxwidth*obwinmat[0][0];
- widthy= obr->strandbuf->maxwidth*obwinmat[1][1];
-
- /* for each bounding box containing a number of strands */
- sbound= obr->strandbuf->bound;
- for (c=0; c<obr->strandbuf->totbound; c++, sbound++) {
- if (clip_render_object(sbound->boundbox, bounds, obwinmat))
- continue;
-
- /* for each strand in this bounding box */
- for (a=sbound->start; a<sbound->end; a++) {
- strand= RE_findOrAddStrand(obr, a);
- svert= strand->vert;
-
- /* keep clipping and z depth for 4 control points */
- clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy);
- clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy);
- clip[0]= clip[1]; z[0]= z[1];
-
- for (b=0; b<strand->totvert-1; b++, svert++) {
- /* compute 4th point clipping and z depth */
- if (b < strand->totvert-2) {
- clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy);
- }
- else {
- clip[3]= clip[2]; z[3]= z[2];
- }
-
- /* check clipping and add to sortsegments buffer */
- if (!(clip[0] & clip[1] & clip[2] & clip[3])) {
- sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment));
- sortseg->obi= i;
- sortseg->strand= strand->index;
- sortseg->segment= b;
-
- sortseg->z= 0.5f*(z[1] + z[2]);
-
- sortseg->next= firstseg;
- firstseg= sortseg;
- totsegment++;
- }
-
- /* shift clipping and z depth */
- clip[0]= clip[1]; z[0]= z[1];
- clip[1]= clip[2]; z[1]= z[2];
- clip[2]= clip[3]; z[2]= z[3];
- }
- }
- }
- }
-
- if (!re->test_break(re->tbh)) {
- /* convert list to array and sort */
- sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment");
- for (a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next)
- sortsegments[a]= *sortseg;
- qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment);
- }
-
- BLI_memarena_free(memarena);
-
- spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf");
-
- if (!re->test_break(re->tbh)) {
- /* render segments in sorted order */
- sortseg= sortsegments;
- for (a=0; a<totsegment; a++, sortseg++) {
- if (re->test_break(re->tbh))
- break;
-
- obi= &re->objectinstance[sortseg->obi];
- obr= obi->obr;
-
- sseg.obi= obi;
- sseg.strand= RE_findOrAddStrand(obr, sortseg->strand);
- sseg.buffer= sseg.strand->buffer;
- sseg.sqadaptcos= sseg.buffer->adaptcos;
- sseg.sqadaptcos *= sseg.sqadaptcos;
-
- svert= sseg.strand->vert + sortseg->segment;
- sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert;
- sseg.v[1]= svert;
- sseg.v[2]= svert+1;
- sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1;
- sseg.shaded= 0;
-
- spart.segment= &sseg;
-
- render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg);
- }
- }
-
- if (sortsegments)
- MEM_freeN(sortsegments);
- MEM_freeN(spart.totapixbuf);
-
- zbuf_free_span(&zspan);
-
- return totsegment;
-}
-
-/* *************** */
-
-StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[4][4], int timeoffset)
-{
- StrandSurface *mesh;
- MFace *mface;
- MVert *mvert;
- float (*co)[3];
- int a, totvert, totface;
-
- totvert= dm->getNumVerts(dm);
- totface= dm->getNumTessFaces(dm);
-
- for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) {
- if ((mesh->obr.ob == obr->ob) &&
- (mesh->obr.par == obr->par) &&
- (mesh->obr.index == obr->index) &&
- (mesh->totvert == totvert) &&
- (mesh->totface == totface))
- {
- break;
- }
- }
-
- if (!mesh) {
- mesh= MEM_callocN(sizeof(StrandSurface), "StrandSurface");
- mesh->obr= *obr;
- mesh->totvert= totvert;
- mesh->totface= totface;
- mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces");
- mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO");
- mesh->env= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfEnv");
- mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect");
- BLI_addtail(&re->strandsurface, mesh);
- }
-
- if (timeoffset == -1 && !mesh->prevco)
- mesh->prevco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
- else if (timeoffset == 0 && !mesh->co)
- mesh->co= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
- else if (timeoffset == 1 && !mesh->nextco)
- mesh->nextco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
- else
- return mesh;
-
- mvert= dm->getVertArray(dm);
- for (a=0; a<mesh->totvert; a++, mvert++) {
- copy_v3_v3(co[a], mvert->co);
- mul_m4_v3(mat, co[a]);
- }
-
- mface= dm->getTessFaceArray(dm);
- for (a=0; a<mesh->totface; a++, mface++) {
- mesh->face[a][0]= mface->v1;
- mesh->face[a][1]= mface->v2;
- mesh->face[a][2]= mface->v3;
- mesh->face[a][3]= mface->v4;
- }
-
- return mesh;
-}
-
-void free_strand_surface(Render *re)
-{
- StrandSurface *mesh;
-
- for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
- if (mesh->co) MEM_freeN(mesh->co);
- if (mesh->prevco) MEM_freeN(mesh->prevco);
- if (mesh->nextco) MEM_freeN(mesh->nextco);
- if (mesh->ao) MEM_freeN(mesh->ao);
- if (mesh->env) MEM_freeN(mesh->env);
- if (mesh->indirect) MEM_freeN(mesh->indirect);
- if (mesh->face) MEM_freeN(mesh->face);
- }
-
- BLI_freelistN(&re->strandsurface);
-}
-
-void strand_minmax(StrandRen *strand, float min[3], float max[3], const float width)
-{
- StrandVert *svert;
- const float width2 = width * 2.0f;
- float vec[3];
- int a;
-
- for (a=0, svert=strand->vert; a<strand->totvert; a++, svert++) {
- copy_v3_v3(vec, svert->co);
- minmax_v3v3_v3(min, max, vec);
-
- if (width!=0.0f) {
- add_v3_fl(vec, width);
- minmax_v3v3_v3(min, max, vec);
- add_v3_fl(vec, -width2);
- minmax_v3v3_v3(min, max, vec);
- }
- }
-}
diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c
deleted file mode 100644
index 80dd52c220c..00000000000
--- a/source/blender/render/intern/source/sunsky.c
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/sunsky.c
- * \ingroup render
- *
- * This feature comes from Preetham paper on "A Practical Analytic Model for Daylight"
- * and example code from Brian Smits, another author of that paper in
- * http://www.cs.utah.edu/vissim/papers/sunsky/code/
- */
-
-#include "sunsky.h"
-#include "BLI_math.h"
-
-/**
- * These macros are defined for vector operations
- * */
-
-/**
- * compute v1 = v2 op v3
- * v1, v2 and v3 are vectors contains 3 float
- * */
-#define VEC3OPV(v1, v2, op, v3) \
- { \
- v1[0] = (v2[0] op v3[0]); \
- v1[1] = (v2[1] op v3[1]); \
- v1[2] = (v2[2] op v3[2]); \
- } (void)0
-
-/**
- * compute v1 = v2 op f1
- * v1, v2 are vectors contains 3 float
- * and f1 is a float
- * */
-#define VEC3OPF(v1, v2, op, f1) \
- { \
- v1[0] = (v2[0] op(f1)); \
- v1[1] = (v2[1] op(f1)); \
- v1[2] = (v2[2] op(f1)); \
- } (void)0
-
-/**
- * compute v1 = f1 op v2
- * v1, v2 are vectors contains 3 float
- * and f1 is a float
- * */
-#define FOPVEC3(v1, f1, op, v2) \
- { \
- v1[0] = ((f1) op v2[0]); \
- v1[1] = ((f1) op v2[1]); \
- v1[2] = ((f1) op v2[2]); \
- } (void)0
-
-/**
- * ClipColor:
- * clip a color to range [0, 1];
- * */
-void ClipColor(float c[3])
-{
- if (c[0] > 1.0f) c[0] = 1.0f;
- if (c[0] < 0.0f) c[0] = 0.0f;
- if (c[1] > 1.0f) c[1] = 1.0f;
- if (c[1] < 0.0f) c[1] = 0.0f;
- if (c[2] > 1.0f) c[2] = 1.0f;
- if (c[2] < 0.0f) c[2] = 0.0f;
-}
-
-/**
- * AngleBetween:
- * compute angle between to direction
- * all angles are in radians
- * */
-static float AngleBetween(float thetav, float phiv, float theta, float phi)
-{
- float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta);
-
- if (cospsi > 1.0f)
- return 0;
- if (cospsi < -1.0f)
- return M_PI;
-
- return acosf(cospsi);
-}
-
-/**
- * DirectionToThetaPhi:
- * this function convert a direction to it's theta and phi value
- * parameters:
- * toSun: contains direction information
- * theta, phi, are return values from this conversion
- * */
-static void DirectionToThetaPhi(float *toSun, float *theta, float *phi)
-{
- *theta = acosf(toSun[2]);
- if (fabsf(*theta) < 1e-5f)
- *phi = 0;
- else
- *phi = atan2f(toSun[1], toSun[0]);
-}
-
-/**
- * PerezFunction:
- * compute perez function value based on input parameters
- */
-static float PerezFunction(struct SunSky *sunsky, const float *lam, float theta, float gamma, float lvz)
-{
- float den, num;
-
- den = ((1 + lam[0] * expf(lam[1])) *
- (1 + lam[2] * expf(lam[3] * sunsky->theta) + lam[4] * cosf(sunsky->theta) * cosf(sunsky->theta)));
-
- num = ((1 + lam[0] * expf(lam[1] / cosf(theta))) *
- (1 + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma)));
-
- return(lvz * num / den);
-}
-
-/**
- * InitSunSky:
- * this function compute some sun,sky parameters according to input parameters and also initiate some other sun, sky parameters
- * parameters:
- * sunSky, is a structure that contains information about sun, sky and atmosphere, in this function, most of its values initiated
- * turb, is atmosphere turbidity
- * toSun, contains sun direction
- * horizon_brighness, controls the brightness of the horizon colors
- * spread, controls colors spreed at horizon
- * sun_brightness, controls sun's brightness
- * sun_size, controls sun's size
- * back_scatter, controls back scatter light
- * */
-void InitSunSky(struct SunSky *sunsky, float turb, const float toSun[3], float horizon_brightness,
- float spread, float sun_brightness, float sun_size, float back_scatter,
- float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace)
-{
- float theta2;
- float theta3;
- float T;
- float T2;
- float chi;
-
- sunsky->turbidity = turb;
-
- sunsky->horizon_brightness = horizon_brightness;
- sunsky->spread = spread;
- sunsky->sun_brightness = sun_brightness;
- sunsky->sun_size = sun_size;
- sunsky->backscattered_light = back_scatter;
- sunsky->skyblendfac = skyblendfac;
- sunsky->skyblendtype = skyblendtype;
- sunsky->sky_exposure = -sky_exposure;
- sunsky->sky_colorspace = sky_colorspace;
-
- sunsky->toSun[0] = toSun[0];
- sunsky->toSun[1] = toSun[1];
- sunsky->toSun[2] = toSun[2];
-
- DirectionToThetaPhi(sunsky->toSun, &sunsky->theta, &sunsky->phi);
-
- sunsky->sunSolidAngle = 0.25 * M_PI * 1.39 * 1.39 / (150 * 150); /* = 6.7443e-05 */
-
- theta2 = sunsky->theta * sunsky->theta;
- theta3 = theta2 * sunsky->theta;
- T = turb;
- T2 = turb * turb;
-
- chi = (4.0f / 9.0f - T / 120.0f) * ((float)M_PI - 2.0f * sunsky->theta);
- sunsky->zenith_Y = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
- sunsky->zenith_Y *= 1000; /* conversion from kcd/m^2 to cd/m^2 */
-
- if (sunsky->zenith_Y <= 0)
- sunsky->zenith_Y = 1e-6;
-
- sunsky->zenith_x =
- (+0.00165f * theta3 - 0.00374f * theta2 + 0.00208f * sunsky->theta + 0.0f) * T2 +
- (-0.02902f * theta3 + 0.06377f * theta2 - 0.03202f * sunsky->theta + 0.00394f) * T +
- (+0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * sunsky->theta + 0.25885f);
-
- sunsky->zenith_y =
- (+0.00275f * theta3 - 0.00610f * theta2 + 0.00316f * sunsky->theta + 0.0f) * T2 +
- (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * sunsky->theta + 0.00515f) * T +
- (+0.15346f * theta3 - 0.26756f * theta2 + 0.06669f * sunsky->theta + 0.26688f);
-
-
- sunsky->perez_Y[0] = 0.17872f * T - 1.46303f;
- sunsky->perez_Y[1] = -0.35540f * T + 0.42749f;
- sunsky->perez_Y[2] = -0.02266f * T + 5.32505f;
- sunsky->perez_Y[3] = 0.12064f * T - 2.57705f;
- sunsky->perez_Y[4] = -0.06696f * T + 0.37027f;
-
- sunsky->perez_x[0] = -0.01925f * T - 0.25922f;
- sunsky->perez_x[1] = -0.06651f * T + 0.00081f;
- sunsky->perez_x[2] = -0.00041f * T + 0.21247f;
- sunsky->perez_x[3] = -0.06409f * T - 0.89887f;
- sunsky->perez_x[4] = -0.00325f * T + 0.04517f;
-
- sunsky->perez_y[0] = -0.01669f * T - 0.26078f;
- sunsky->perez_y[1] = -0.09495f * T + 0.00921f;
- sunsky->perez_y[2] = -0.00792f * T + 0.21023f;
- sunsky->perez_y[3] = -0.04405f * T - 1.65369f;
- sunsky->perez_y[4] = -0.01092f * T + 0.05291f;
-
- /* suggested by glome in patch [#8063] */
- sunsky->perez_Y[0] *= sunsky->horizon_brightness;
- sunsky->perez_x[0] *= sunsky->horizon_brightness;
- sunsky->perez_y[0] *= sunsky->horizon_brightness;
-
- sunsky->perez_Y[1] *= sunsky->spread;
- sunsky->perez_x[1] *= sunsky->spread;
- sunsky->perez_y[1] *= sunsky->spread;
-
- sunsky->perez_Y[2] *= sunsky->sun_brightness;
- sunsky->perez_x[2] *= sunsky->sun_brightness;
- sunsky->perez_y[2] *= sunsky->sun_brightness;
-
- sunsky->perez_Y[3] *= sunsky->sun_size;
- sunsky->perez_x[3] *= sunsky->sun_size;
- sunsky->perez_y[3] *= sunsky->sun_size;
-
- sunsky->perez_Y[4] *= sunsky->backscattered_light;
- sunsky->perez_x[4] *= sunsky->backscattered_light;
- sunsky->perez_y[4] *= sunsky->backscattered_light;
-}
-
-/**
- * GetSkyXYZRadiance:
- * this function compute sky radiance according to a view parameters `theta' and `phi'and sunSky values
- * parameters:
- * sunSky, sontains sun and sky parameters
- * theta, is sun's theta
- * phi, is sun's phi
- * color_out, is computed color that shows sky radiance in XYZ color format
- * */
-void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float color_out[3])
-{
- float gamma;
- float x, y, Y, X, Z;
- float hfade = 1, nfade = 1;
-
-
- if (theta > (float)M_PI_2) {
- hfade = 1.0f - (theta * (float)M_1_PI - 0.5f) * 2.0f;
- hfade = hfade * hfade * (3.0f - 2.0f * hfade);
- theta = M_PI_2;
- }
-
- if (sunsky->theta > (float)M_PI_2) {
- if (theta <= (float)M_PI_2) {
- nfade = 1.0f - (0.5f - theta * (float)M_1_PI) * 2.0f;
- nfade *= 1.0f - (sunsky->theta * (float)M_1_PI - 0.5f) * 2.0f;
- nfade = nfade * nfade * (3.0f - 2.0f * nfade);
- }
- }
-
- gamma = AngleBetween(theta, phi, sunsky->theta, sunsky->phi);
-
- /* Compute xyY values */
- x = PerezFunction(sunsky, sunsky->perez_x, theta, gamma, sunsky->zenith_x);
- y = PerezFunction(sunsky, sunsky->perez_y, theta, gamma, sunsky->zenith_y);
- Y = 6.666666667e-5f * nfade * hfade * PerezFunction(sunsky, sunsky->perez_Y, theta, gamma, sunsky->zenith_Y);
-
- if (sunsky->sky_exposure != 0.0f)
- Y = 1.0 - exp(Y * sunsky->sky_exposure);
-
- X = (x / y) * Y;
- Z = ((1 - x - y) / y) * Y;
-
- color_out[0] = X;
- color_out[1] = Y;
- color_out[2] = Z;
-}
-
-/**
- * GetSkyXYZRadiancef:
- * this function compute sky radiance according to a view direction `varg' and sunSky values
- * parameters:
- * sunSky, sontains sun and sky parameters
- * varg, shows direction
- * color_out, is computed color that shows sky radiance in XYZ color format
- * */
-void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_out[3])
-{
- float theta, phi;
- float v[3];
-
- normalize_v3_v3(v, varg);
-
- if (v[2] < 0.001f) {
- v[2] = 0.001f;
- normalize_v3(v);
- }
-
- DirectionToThetaPhi(v, &theta, &phi);
- GetSkyXYZRadiance(sunsky, theta, phi, color_out);
-}
-
-/**
- * ComputeAttenuatedSunlight:
- * this function compute attenuated sun light based on sun's theta and atmosphere turbidity
- * parameters:
- * theta, is sun's theta
- * turbidity: is atmosphere turbidity
- * fTau: contains computed attenuated sun light
- * */
-static void ComputeAttenuatedSunlight(float theta, int turbidity, float fTau[3])
-{
- float fBeta;
- float fTauR, fTauA;
- float m;
- float fAlpha;
-
- int i;
- float fLambda[3];
- fLambda[0] = 0.65f;
- fLambda[1] = 0.57f;
- fLambda[2] = 0.475f;
-
- fAlpha = 1.3f;
- fBeta = 0.04608365822050f * turbidity - 0.04586025928522f;
-
- m = 1.0f / (cosf(theta) + 0.15f * powf(93.885f - theta / (float)M_PI * 180.0f, -1.253f));
-
- for (i = 0; i < 3; i++) {
- /* Rayleigh Scattering */
- fTauR = expf(-m * 0.008735f * powf(fLambda[i], (float)(-4.08f)));
-
- /* Aerosal (water + dust) attenuation */
- fTauA = exp(-m * fBeta * powf(fLambda[i], -fAlpha));
-
- fTau[i] = fTauR * fTauA;
- }
-}
-
-/**
- * InitAtmosphere:
- * this function initiate sunSky structure with user input parameters.
- * parameters:
- * sunSky, contains information about sun, and in this function some atmosphere parameters will initiated
- * sun_intens, shows sun intensity value
- * mief, Mie scattering factor this factor currently call with 1.0
- * rayf, Rayleigh scattering factor, this factor currently call with 1.0
- * inscattf, inscatter light factor that range from 0.0 to 1.0, 0.0 means no inscatter light and 1.0 means full inscatter light
- * extincf, extinction light factor that range from 0.0 to 1.0, 0.0 means no extinction and 1.0 means full extinction
- * disf, is distance factor, multiplied to pixle's z value to compute each pixle's distance to camera,
- * */
-void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf,
- float inscattf, float extincf, float disf)
-{
- const float pi = M_PI;
- const float n = 1.003f; /* refractive index */
- const float N = 2.545e25;
- const float pn = 0.035f;
- const float T = 2.0f;
- float fTemp, fTemp2, fTemp3, fBeta, fBetaDash;
- float c = (6.544f * T - 6.51f) * 1e-17f;
- float K[3] = {0.685f, 0.679f, 0.670f};
- float vBetaMieTemp[3];
-
- float fLambda[3], fLambda2[3], fLambda4[3];
- float vLambda2[3];
- float vLambda4[3];
-
- int i;
-
- sunSky->atm_SunIntensity = sun_intens;
- sunSky->atm_BetaMieMultiplier = mief;
- sunSky->atm_BetaRayMultiplier = rayf;
- sunSky->atm_InscatteringMultiplier = inscattf;
- sunSky->atm_ExtinctionMultiplier = extincf;
- sunSky->atm_DistanceMultiplier = disf;
-
- sunSky->atm_HGg = 0.8;
-
- fLambda[0] = 1 / 650e-9f;
- fLambda[1] = 1 / 570e-9f;
- fLambda[2] = 1 / 475e-9f;
- for (i = 0; i < 3; i++) {
- fLambda2[i] = fLambda[i] * fLambda[i];
- fLambda4[i] = fLambda2[i] * fLambda2[i];
- }
-
- vLambda2[0] = fLambda2[0];
- vLambda2[1] = fLambda2[1];
- vLambda2[2] = fLambda2[2];
-
- vLambda4[0] = fLambda4[0];
- vLambda4[1] = fLambda4[1];
- vLambda4[2] = fLambda4[2];
-
- /* Rayleigh scattering constants. */
- fTemp = pi * pi * (n * n - 1) * (n * n - 1) * (6 + 3 * pn) / (6 - 7 * pn) / N;
- fBeta = 8 * fTemp * pi / 3;
-
- VEC3OPF(sunSky->atm_BetaRay, vLambda4, *, fBeta);
- fBetaDash = fTemp / 2;
- VEC3OPF(sunSky->atm_BetaDashRay, vLambda4, *, fBetaDash);
-
-
- /* Mie scattering constants. */
- fTemp2 = 0.434f * c * (2 * pi) * (2 * pi) * 0.5f;
- VEC3OPF(sunSky->atm_BetaDashMie, vLambda2, *, fTemp2);
-
- fTemp3 = 0.434f * c * pi * (2 * pi) * (2 * pi);
-
- VEC3OPV(vBetaMieTemp, K, *, fLambda);
- VEC3OPF(sunSky->atm_BetaMie, vBetaMieTemp, *, fTemp3);
-
-}
-
-/**
- * AtmospherePixleShader:
- * this function apply atmosphere effect on a pixle color `rgb' at distance `s'
- * parameters:
- * sunSky, contains information about sun parameters and user values
- * view, is camera view vector
- * s, is distance
- * rgb, contains rendered color value for a pixle
- * */
-void AtmospherePixleShader(struct SunSky *sunSky, float view[3], float s, float rgb[3])
-{
- float costheta;
- float Phase_1;
- float Phase_2;
- float sunColor[3];
-
- float E[3];
- float E1[3];
-
-
- float I[3];
- float fTemp;
- float vTemp1[3], vTemp2[3];
-
- float sunDirection[3];
-
- s *= sunSky->atm_DistanceMultiplier;
-
- sunDirection[0] = sunSky->toSun[0];
- sunDirection[1] = sunSky->toSun[1];
- sunDirection[2] = sunSky->toSun[2];
-
- costheta = dot_v3v3(view, sunDirection); /* cos(theta) */
- Phase_1 = 1 + (costheta * costheta); /* Phase_1 */
-
- VEC3OPF(sunSky->atm_BetaRay, sunSky->atm_BetaRay, *, sunSky->atm_BetaRayMultiplier);
- VEC3OPF(sunSky->atm_BetaMie, sunSky->atm_BetaMie, *, sunSky->atm_BetaMieMultiplier);
- VEC3OPV(sunSky->atm_BetaRM, sunSky->atm_BetaRay, +, sunSky->atm_BetaMie);
-
- /* e^(-(beta_1 + beta_2) * s) = E1 */
- VEC3OPF(E1, sunSky->atm_BetaRM, *, -s / (float)M_LN2);
- E1[0] = exp(E1[0]);
- E1[1] = exp(E1[1]);
- E1[2] = exp(E1[2]);
-
- copy_v3_v3(E, E1);
-
- /* Phase2(theta) = (1-g^2)/(1+g-2g*cos(theta))^(3/2) */
- fTemp = 1 + sunSky->atm_HGg - 2 * sunSky->atm_HGg * costheta;
- fTemp = fTemp * sqrtf(fTemp);
- Phase_2 = (1 - sunSky->atm_HGg * sunSky->atm_HGg) / fTemp;
-
- VEC3OPF(vTemp1, sunSky->atm_BetaDashRay, *, Phase_1);
- VEC3OPF(vTemp2, sunSky->atm_BetaDashMie, *, Phase_2);
-
- VEC3OPV(vTemp1, vTemp1, +, vTemp2);
- FOPVEC3(vTemp2, 1.0f, -, E1);
- VEC3OPV(vTemp1, vTemp1, *, vTemp2);
-
- FOPVEC3(vTemp2, 1.0f, /, sunSky->atm_BetaRM);
-
- VEC3OPV(I, vTemp1, *, vTemp2);
-
- VEC3OPF(I, I, *, sunSky->atm_InscatteringMultiplier);
- VEC3OPF(E, E, *, sunSky->atm_ExtinctionMultiplier);
-
- /* scale to color sun */
- ComputeAttenuatedSunlight(sunSky->theta, sunSky->turbidity, sunColor);
- VEC3OPV(E, E, *, sunColor);
-
- VEC3OPF(I, I, *, sunSky->atm_SunIntensity);
-
- VEC3OPV(rgb, rgb, *, E);
- VEC3OPV(rgb, rgb, +, I);
-}
-
-#undef VEC3OPV
-#undef VEC3OPF
-#undef FOPVEC3
-
-/* EOF */
diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c
deleted file mode 100644
index a932123243d..00000000000
--- a/source/blender/render/intern/source/texture_ocean.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributors: Matt Ebb
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/texture_ocean.c
- * \ingroup bke
- */
-
-#include <stddef.h>
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_texture_types.h"
-
-#include "BKE_global.h" /* XXX */
-
-#include "BKE_modifier.h"
-#include "BKE_ocean.h"
-
-#include "render_types.h"
-#include "RE_shader_ext.h"
-
-#include "texture.h"
-
-#include "texture_ocean.h" /* own include */
-
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
-/* ***** actual texture sampling ***** */
-int ocean_texture(Tex *tex, const float texvec[2], TexResult *texres)
-{
- OceanTex *ot = tex->ot;
- ModifierData *md;
- OceanModifierData *omd;
-
- texres->tin = 0.0f;
-
- if ( !(ot) ||
- !(ot->object) ||
- !(md = (ModifierData *)modifiers_findByType(ot->object, eModifierType_Ocean)) ||
- !(omd = (OceanModifierData *)md)->ocean)
- {
- return 0;
- }
- else {
- const bool do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS) != 0;
- int cfra = R.r.cfra;
- int retval = TEX_INT;
-
- OceanResult ocr;
- const float u = 0.5f + 0.5f * texvec[0];
- const float v = 0.5f + 0.5f * texvec[1];
-
- if (omd->oceancache && omd->cached == true) {
-
- CLAMP(cfra, omd->bakestart, omd->bakeend);
- cfra -= omd->bakestart; /* shift to 0 based */
-
- BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
-
- }
- else { /* non-cached */
-
- if (G.is_rendering)
- BKE_ocean_eval_uv_catrom(omd->ocean, &ocr, u, v);
- else
- BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
-
- ocr.foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
- }
-
- switch (ot->output) {
- case TEX_OCN_DISPLACEMENT:
- /* XYZ displacement */
- texres->tr = 0.5f + 0.5f * ocr.disp[0];
- texres->tg = 0.5f + 0.5f * ocr.disp[2];
- texres->tb = 0.5f + 0.5f * ocr.disp[1];
-
- texres->tr = MAX2(0.0f, texres->tr);
- texres->tg = MAX2(0.0f, texres->tg);
- texres->tb = MAX2(0.0f, texres->tb);
-
- BRICONTRGB;
-
- retval = TEX_RGB;
- break;
-
- case TEX_OCN_EMINUS:
- /* -ve eigenvectors ? */
- texres->tr = ocr.Eminus[0];
- texres->tg = ocr.Eminus[2];
- texres->tb = ocr.Eminus[1];
- retval = TEX_RGB;
- break;
-
- case TEX_OCN_EPLUS:
- /* -ve eigenvectors ? */
- texres->tr = ocr.Eplus[0];
- texres->tg = ocr.Eplus[2];
- texres->tb = ocr.Eplus[1];
- retval = TEX_RGB;
- break;
-
- case TEX_OCN_JPLUS:
- texres->tin = ocr.Jplus;
- retval = TEX_INT;
- break;
-
- case TEX_OCN_FOAM:
-
- texres->tin = ocr.foam;
-
- BRICONT;
-
- retval = TEX_INT;
- break;
- }
-
- /* if normals needed */
-
- if (texres->nor && do_normals) {
- normalize_v3_v3(texres->nor, ocr.normal);
- retval |= TEX_NOR;
- }
-
- texres->ta = 1.0f;
-
- return retval;
- }
-}
diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c
deleted file mode 100644
index 54a0e67eef0..00000000000
--- a/source/blender/render/intern/source/volume_precache.c
+++ /dev/null
@@ -1,854 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb, Ra˙l Fern·ndez Hern·ndez (Farsthary).
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/volume_precache.c
- * \ingroup render
- */
-
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <float.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_task.h"
-#include "BLI_threads.h"
-#include "BLI_voxel.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "PIL_time.h"
-
-#include "RE_shader_ext.h"
-
-#include "DNA_material_types.h"
-
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "render_types.h"
-#include "rendercore.h"
-#include "renderdatabase.h"
-#include "volumetric.h"
-#include "volume_precache.h"
-
-#include "atomic_ops.h"
-
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* *** utility code to set up an individual raytree for objectinstance, for checking inside/outside *** */
-
-/* Recursive test for intersections, from a point inside the mesh, to outside
- * Number of intersections (depth) determine if a point is inside or outside the mesh */
-static int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int limit, int depth)
-{
- if (limit == 0) return depth;
-
- if (RE_rayobject_raycast(tree, isect)) {
-
- isect->start[0] = isect->start[0] + isect->dist*isect->dir[0];
- isect->start[1] = isect->start[1] + isect->dist*isect->dir[1];
- isect->start[2] = isect->start[2] + isect->dist*isect->dir[2];
-
- isect->dist = FLT_MAX;
- isect->skip = RE_SKIP_VLR_NEIGHBOUR;
- isect->orig.face= isect->hit.face;
- isect->orig.ob= isect->hit.ob;
-
- return intersect_outside_volume(tree, isect, offset, limit-1, depth+1);
- }
- else {
- return depth;
- }
-}
-
-/* Uses ray tracing to check if a point is inside or outside an ObjectInstanceRen */
-static int point_inside_obi(RayObject *tree, ObjectInstanceRen *obi, const float co[3])
-{
- Isect isect= {{0}};
- float dir[3] = {0.0f, 0.0f, 1.0f};
- int final_depth=0, depth=0, limit=20;
-
- /* set up the isect */
- copy_v3_v3(isect.start, co);
- copy_v3_v3(isect.dir, dir);
- isect.mode= RE_RAY_MIRROR;
- isect.last_hit= NULL;
- isect.lay= -1;
-
- isect.dist = FLT_MAX;
- isect.orig.face= NULL;
- isect.orig.ob = NULL;
-
- RE_instance_rotate_ray(obi, &isect);
- final_depth = intersect_outside_volume(tree, &isect, dir, limit, depth);
- RE_instance_rotate_ray_restore(obi, &isect);
-
- /* even number of intersections: point is outside
- * odd number: point is inside */
- if (final_depth % 2 == 0) return 0;
- else return 1;
-}
-
-/* find the bounding box of an objectinstance in global space */
-void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float bbmin[3], float bbmax[3])
-{
- ObjectRen *obr = obi->obr;
- VolumePrecache *vp = obi->volume_precache;
- VertRen *ver= NULL;
- float co[3];
- int a;
-
- if (vp->bbmin != NULL && vp->bbmax != NULL) {
- copy_v3_v3(bbmin, vp->bbmin);
- copy_v3_v3(bbmax, vp->bbmax);
- return;
- }
-
- vp->bbmin = MEM_callocN(sizeof(float)*3, "volume precache min boundbox corner");
- vp->bbmax = MEM_callocN(sizeof(float)*3, "volume precache max boundbox corner");
-
- INIT_MINMAX(bbmin, bbmax);
-
- for (a=0; a<obr->totvert; a++) {
- if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
- else ver++;
-
- copy_v3_v3(co, ver->co);
-
- /* transformed object instance in camera space */
- if (obi->flag & R_TRANSFORMED)
- mul_m4_v3(obi->mat, co);
-
- /* convert to global space */
- mul_m4_v3(re->viewinv, co);
-
- minmax_v3v3_v3(vp->bbmin, vp->bbmax, co);
- }
-
- copy_v3_v3(bbmin, vp->bbmin);
- copy_v3_v3(bbmax, vp->bbmax);
-
-}
-
-/* *** light cache filtering *** */
-
-static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
-{
- int x, y, z, x_, y_, z_;
- int added=0;
- float tot=0.0f;
-
- for (z=-1; z <= 1; z++) {
- z_ = zz+z;
- if (z_ >= 0 && z_ <= res[2]-1) {
-
- for (y=-1; y <= 1; y++) {
- y_ = yy+y;
- if (y_ >= 0 && y_ <= res[1]-1) {
-
- for (x=-1; x <= 1; x++) {
- x_ = xx+x;
- if (x_ >= 0 && x_ <= res[0]-1) {
- const int64_t i = BLI_VOXEL_INDEX(x_, y_, z_, res);
-
- if (cache[i] > 0.0f) {
- tot += cache[i];
- added++;
- }
-
- }
- }
- }
- }
- }
- }
-
- if (added > 0) tot /= added;
-
- return tot;
-}
-
-/* function to filter the edges of the light cache, where there was no volume originally.
- * For each voxel which was originally external to the mesh, it finds the average values of
- * the surrounding internal voxels and sets the original external voxel to that average amount.
- * Works almost a bit like a 'dilate' filter */
-static void lightcache_filter(VolumePrecache *vp)
-{
- int x, y, z;
-
- for (z=0; z < vp->res[2]; z++) {
- for (y=0; y < vp->res[1]; y++) {
- for (x=0; x < vp->res[0]; x++) {
- /* trigger for outside mesh */
- const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res);
-
- if (vp->data_r[i] < -0.f)
- vp->data_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
- if (vp->data_g[i] < -0.f)
- vp->data_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
- if (vp->data_b[i] < -0.f)
- vp->data_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
- }
- }
- }
-}
-
-#if 0
-static void lightcache_filter2(VolumePrecache *vp)
-{
- int x, y, z;
- float *new_r, *new_g, *new_b;
- int field_size = vp->res[0]*vp->res[1]*vp->res[2]*sizeof(float);
-
- new_r = MEM_mallocN(field_size, "temp buffer for light cache filter r channel");
- new_g = MEM_mallocN(field_size, "temp buffer for light cache filter g channel");
- new_b = MEM_mallocN(field_size, "temp buffer for light cache filter b channel");
-
- memcpy(new_r, vp->data_r, field_size);
- memcpy(new_g, vp->data_g, field_size);
- memcpy(new_b, vp->data_b, field_size);
-
- for (z=0; z < vp->res[2]; z++) {
- for (y=0; y < vp->res[1]; y++) {
- for (x=0; x < vp->res[0]; x++) {
- /* trigger for outside mesh */
- const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res);
- if (vp->data_r[i] < -0.f)
- new_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
- if (vp->data_g[i] < -0.f)
- new_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
- if (vp->data_b[i] < -0.f)
- new_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
- }
- }
- }
-
- SWAP(float *, vp->data_r, new_r);
- SWAP(float *, vp->data_g, new_g);
- SWAP(float *, vp->data_b, new_b);
-
- if (new_r) { MEM_freeN(new_r); new_r=NULL; }
- if (new_g) { MEM_freeN(new_g); new_g=NULL; }
- if (new_b) { MEM_freeN(new_b); new_b=NULL; }
-}
-#endif
-
-/* has a pad of 1 voxel surrounding the core for boundary simulation */
-BLI_INLINE int64_t ms_I(int x, int y, int z, const int *n)
-{
- /* different ordering to light cache */
- return ((int64_t)x * (int64_t)(n[1] + 2) * (int64_t)(n[2] + 2) +
- (int64_t)y * (int64_t)(n[2] + 2) +
- (int64_t)z);
-}
-
-/* has a pad of 1 voxel surrounding the core for boundary simulation */
-BLI_INLINE int64_t v_I_pad(int x, int y, int z, const int *n)
-{
- /* same ordering to light cache, with padding */
- return ((int64_t)z * (int64_t)(n[1] + 2) * (int64_t)(n[0] + 2) +
- (int64_t)y * (int64_t)(n[0] + 2) +
- (int64_t)x);
-}
-
-BLI_INLINE int64_t lc_to_ms_I(int x, int y, int z, const int *n)
-{
- /* converting light cache index to multiple scattering index */
- return ((int64_t)(x - 1) * ((int64_t)n[1] * (int64_t)n[2]) +
- (int64_t)(y - 1) * ((int64_t)n[2]) +
- (int64_t)(z - 1));
-}
-
-/* *** multiple scattering approximation *** */
-
-/* get the total amount of light energy in the light cache. used to normalize after multiple scattering */
-static float total_ss_energy(Render *re, int do_test_break, VolumePrecache *vp)
-{
- int x, y, z;
- const int *res = vp->res;
- float energy=0.f;
-
- for (z=0; z < res[2]; z++) {
- for (y=0; y < res[1]; y++) {
- for (x=0; x < res[0]; x++) {
- const int64_t i = BLI_VOXEL_INDEX(x, y, z, res);
-
- if (vp->data_r[i] > 0.f) energy += vp->data_r[i];
- if (vp->data_g[i] > 0.f) energy += vp->data_g[i];
- if (vp->data_b[i] > 0.f) energy += vp->data_b[i];
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- return energy;
-}
-
-static float total_ms_energy(Render *re, int do_test_break, float *sr, float *sg, float *sb, const int res[3])
-{
- int x, y, z;
- float energy=0.f;
-
- for (z=1;z<=res[2];z++) {
- for (y=1;y<=res[1];y++) {
- for (x=1;x<=res[0];x++) {
- const int64_t i = ms_I(x, y, z, res);
-
- if (sr[i] > 0.f) energy += sr[i];
- if (sg[i] > 0.f) energy += sg[i];
- if (sb[i] > 0.f) energy += sb[i];
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- return energy;
-}
-
-/**
- * \param n: the unpadded resolution
- */
-static void ms_diffuse(Render *re, int do_test_break, const float *x0, float *x, float diff, const int n[3])
-{
- int i, j, k, l;
- const float dt = VOL_MS_TIMESTEP;
- int64_t size = (int64_t)n[0] * (int64_t)n[1] * (int64_t)n[2];
- const float a = dt * diff * size;
-
- for (l=0; l<20; l++) {
- for (k=1; k<=n[2]; k++) {
- for (j=1; j<=n[1]; j++) {
- for (i=1; i<=n[0]; i++) {
- x[v_I_pad(i, j, k, n)] =
- ((x0[v_I_pad(i, j, k, n)]) + (
- (x0[v_I_pad(i - 1, j, k, n)] +
- x0[v_I_pad(i + 1, j, k, n)] +
- x0[v_I_pad(i, j - 1, k, n)] +
- x0[v_I_pad(i, j + 1, k, n)] +
- x0[v_I_pad(i, j, k - 1, n)] +
- x0[v_I_pad(i, j, k + 1, n)]) * a) / (1 + 6 * a));
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- if (re->test_break(re->tbh)) break;
- }
-}
-
-static void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
-{
- const float diff = ma->vol.ms_diff * 0.001f; /* compensate for scaling for a nicer UI range */
- const int simframes = (int)(ma->vol.ms_spread * (float)max_iii(vp->res[0], vp->res[1], vp->res[2]));
- const int shade_type = ma->vol.shade_type;
- float fac = ma->vol.ms_intensity;
-
- int x, y, z, m;
- const int *n = vp->res;
- const int size = (n[0]+2)*(n[1]+2)*(n[2]+2);
- const int do_test_break = (size > 100000);
- double time, lasttime= PIL_check_seconds_timer();
- float total;
- float c=1.0f;
- float origf; /* factor for blending in original light cache */
- float energy_ss, energy_ms;
-
- float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
- float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
-
- total = (float)(n[0]*n[1]*n[2]*simframes);
-
- energy_ss = total_ss_energy(re, do_test_break, vp);
-
- /* Scattering as diffusion pass */
- for (m=0; m<simframes; m++) {
- /* add sources */
- for (z=1; z<=n[2]; z++) {
- for (y=1; y<=n[1]; y++) {
- for (x=1; x<=n[0]; x++) {
- const int64_t i = lc_to_ms_I(x, y, z, n); //lc index
- const int64_t j = ms_I(x, y, z, n); //ms index
-
- time= PIL_check_seconds_timer();
- c++;
- if (vp->data_r[i] > 0.0f)
- sr[j] += vp->data_r[i];
- if (vp->data_g[i] > 0.0f)
- sg[j] += vp->data_g[i];
- if (vp->data_b[i] > 0.0f)
- sb[j] += vp->data_b[i];
-
- /* Displays progress every second */
- if (time-lasttime>1.0) {
- char str[64];
- BLI_snprintf(str, sizeof(str), IFACE_("Simulating multiple scattering: %d%%"),
- (int)(100.0f * (c / total)));
- re->i.infostr = str;
- re->stats_draw(re->sdh, &re->i);
- re->i.infostr = NULL;
- lasttime= time;
- }
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- if (re->test_break(re->tbh)) break;
-
- SWAP(float *, sr, sr0);
- SWAP(float *, sg, sg0);
- SWAP(float *, sb, sb0);
-
- /* main diffusion simulation */
- ms_diffuse(re, do_test_break, sr0, sr, diff, n);
- ms_diffuse(re, do_test_break, sg0, sg, diff, n);
- ms_diffuse(re, do_test_break, sb0, sb, diff, n);
-
- if (re->test_break(re->tbh)) break;
- }
-
- /* normalization factor to conserve energy */
- energy_ms = total_ms_energy(re, do_test_break, sr, sg, sb, n);
- fac *= (energy_ss / energy_ms);
-
- /* blend multiple scattering back in the light cache */
- if (shade_type == MA_VOL_SHADE_SHADEDPLUSMULTIPLE) {
- /* conserve energy - half single, half multiple */
- origf = 0.5f;
- fac *= 0.5f;
- }
- else {
- origf = 0.0f;
- }
-
- for (z=1;z<=n[2];z++) {
- for (y=1;y<=n[1];y++) {
- for (x=1;x<=n[0];x++) {
- const int64_t i = lc_to_ms_I(x, y, z, n); //lc index
- const int64_t j = ms_I(x, y, z, n); //ms index
-
- vp->data_r[i] = origf * vp->data_r[i] + fac * sr[j];
- vp->data_g[i] = origf * vp->data_g[i] + fac * sg[j];
- vp->data_b[i] = origf * vp->data_b[i] + fac * sb[j];
- }
- }
-
- if (do_test_break && re->test_break(re->tbh)) break;
- }
-
- MEM_freeN(sr0);
- MEM_freeN(sr);
- MEM_freeN(sg0);
- MEM_freeN(sg);
- MEM_freeN(sb0);
- MEM_freeN(sb);
-}
-
-
-
-#if 0 /* debug stuff */
-static void *vol_precache_part_test(void *data)
-{
- VolPrecachePart *pa = data;
-
- printf("part number: %d\n", pa->num);
- printf("done: %d\n", pa->done);
- printf("x min: %d x max: %d\n", pa->minx, pa->maxx);
- printf("y min: %d y max: %d\n", pa->miny, pa->maxy);
- printf("z min: %d z max: %d\n", pa->minz, pa->maxz);
-
- return NULL;
-}
-#endif
-
-/* Iterate over the 3d voxel grid, and fill the voxels with scattering information
- *
- * It's stored in memory as 3 big float grids next to each other, one for each RGB channel.
- * I'm guessing the memory alignment may work out better this way for the purposes
- * of doing linear interpolation, but I haven't actually tested this theory! :)
- */
-typedef struct VolPrecacheState {
- double lasttime;
- unsigned int doneparts;
- unsigned int totparts;
-} VolPrecacheState;
-
-static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
-{
- VolPrecacheState *state = (VolPrecacheState *)BLI_task_pool_userdata(pool);
- VolPrecachePart *pa = (VolPrecachePart *)taskdata;
- Render *re = pa->re;
-
- ObjectInstanceRen *obi = pa->obi;
- RayObject *tree = pa->tree;
- ShadeInput *shi = pa->shi;
- float scatter_col[3] = {0.f, 0.f, 0.f};
- float co[3], cco[3], view[3];
- int x, y, z;
- int res[3];
- double time;
-
- if (re->test_break && re->test_break(re->tbh))
- return;
-
- //printf("thread id %d\n", threadid);
-
- res[0]= pa->res[0];
- res[1]= pa->res[1];
- res[2]= pa->res[2];
-
- for (z= pa->minz; z < pa->maxz; z++) {
- co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f));
-
- for (y= pa->miny; y < pa->maxy; y++) {
- co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f));
-
- for (x=pa->minx; x < pa->maxx; x++) {
- int64_t i;
- co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f));
-
- if (re->test_break && re->test_break(re->tbh))
- break;
-
- /* convert from world->camera space for shading */
- mul_v3_m4v3(cco, pa->viewmat, co);
-
- i = BLI_VOXEL_INDEX(x, y, z, res);
-
- /* don't bother if the point is not inside the volume mesh */
- if (!point_inside_obi(tree, obi, cco)) {
- obi->volume_precache->data_r[i] = -1.0f;
- obi->volume_precache->data_g[i] = -1.0f;
- obi->volume_precache->data_b[i] = -1.0f;
- continue;
- }
-
- copy_v3_v3(view, cco);
- normalize_v3(view);
- vol_get_scattering(shi, scatter_col, cco, view);
-
- obi->volume_precache->data_r[i] = scatter_col[0];
- obi->volume_precache->data_g[i] = scatter_col[1];
- obi->volume_precache->data_b[i] = scatter_col[2];
-
- }
- }
- }
-
- unsigned int doneparts = atomic_add_and_fetch_u(&state->doneparts, 1);
-
- time = PIL_check_seconds_timer();
- if (time - state->lasttime > 1.0) {
- ThreadMutex *mutex = BLI_task_pool_user_mutex(pool);
-
- if (BLI_mutex_trylock(mutex)) {
- char str[64];
- float ratio = (float)doneparts/(float)state->totparts;
- BLI_snprintf(str, sizeof(str), IFACE_("Precaching volume: %d%%"), (int)(100.0f * ratio));
- re->i.infostr = str;
- re->stats_draw(re->sdh, &re->i);
- re->i.infostr = NULL;
- state->lasttime = time;
-
- BLI_mutex_unlock(mutex);
- }
- }
-}
-
-static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
-{
- memset(shi, 0, sizeof(ShadeInput));
- shi->depth= 1;
- shi->mask= 1;
- shi->mat = ma;
- shi->vlr = NULL;
- memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); /* note, keep this synced with render_types.h */
- shi->har= shi->mat->har;
- shi->obi= obi;
- shi->obr= obi->obr;
- shi->lay = re->lay;
-}
-
-static void precache_launch_parts(Render *re, RayObject *tree, ShadeInput *shi, ObjectInstanceRen *obi)
-{
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
- VolumePrecache *vp = obi->volume_precache;
- VolPrecacheState state;
- int i=0, x, y, z;
- float voxel[3];
- int sizex, sizey, sizez;
- float bbmin[3], bbmax[3];
- const int *res;
- int minx, maxx;
- int miny, maxy;
- int minz, maxz;
- int totthread = re->r.threads;
- int parts[3];
-
- if (!vp) return;
-
- /* currently we just subdivide the box, number of threads per side */
- parts[0] = parts[1] = parts[2] = totthread;
- res = vp->res;
-
- /* setup task scheduler */
- memset(&state, 0, sizeof(state));
- state.doneparts = 0;
- state.totparts = parts[0]*parts[1]*parts[2];
- state.lasttime = PIL_check_seconds_timer();
-
- task_scheduler = BLI_task_scheduler_create(totthread);
- task_pool = BLI_task_pool_create(task_scheduler, &state);
-
- /* using boundbox in worldspace */
- global_bounds_obi(re, obi, bbmin, bbmax);
- sub_v3_v3v3(voxel, bbmax, bbmin);
-
- voxel[0] /= (float)res[0];
- voxel[1] /= (float)res[1];
- voxel[2] /= (float)res[2];
-
- for (x=0; x < parts[0]; x++) {
- sizex = ceil(res[0] / (float)parts[0]);
- minx = x * sizex;
- maxx = minx + sizex;
- maxx = (maxx>res[0])?res[0]:maxx;
-
- for (y=0; y < parts[1]; y++) {
- sizey = ceil(res[1] / (float)parts[1]);
- miny = y * sizey;
- maxy = miny + sizey;
- maxy = (maxy>res[1])?res[1]:maxy;
-
- for (z=0; z < parts[2]; z++) {
- VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part");
-
- sizez = ceil(res[2] / (float)parts[2]);
- minz = z * sizez;
- maxz = minz + sizez;
- maxz = (maxz>res[2])?res[2]:maxz;
-
- pa->re = re;
- pa->num = i;
- pa->tree = tree;
- pa->shi = shi;
- pa->obi = obi;
- copy_m4_m4(pa->viewmat, re->viewmat);
-
- copy_v3_v3(pa->bbmin, bbmin);
- copy_v3_v3(pa->voxel, voxel);
- copy_v3_v3_int(pa->res, res);
-
- pa->minx = minx; pa->maxx = maxx;
- pa->miny = miny; pa->maxy = maxy;
- pa->minz = minz; pa->maxz = maxz;
-
- BLI_task_pool_push(task_pool, vol_precache_part, pa, true, TASK_PRIORITY_HIGH);
-
- i++;
- }
- }
- }
-
- /* work and wait until tasks are done */
- BLI_task_pool_work_and_wait(task_pool);
-
- /* free */
- BLI_task_pool_free(task_pool);
- BLI_task_scheduler_free(task_scheduler);
-}
-
-/* calculate resolution from bounding box in world space */
-static int precache_resolution(Render *re, VolumePrecache *vp, ObjectInstanceRen *obi, int res)
-{
- float dim[3], div;
- float bbmin[3], bbmax[3];
-
- /* bound box in global space */
- global_bounds_obi(re, obi, bbmin, bbmax);
- sub_v3_v3v3(dim, bbmax, bbmin);
-
- div = max_fff(dim[0], dim[1], dim[2]);
- dim[0] /= div;
- dim[1] /= div;
- dim[2] /= div;
-
- vp->res[0] = ceil(dim[0] * res);
- vp->res[1] = ceil(dim[1] * res);
- vp->res[2] = ceil(dim[2] * res);
-
- if ((vp->res[0] < 1) || (vp->res[1] < 1) || (vp->res[2] < 1))
- return 0;
-
- return 1;
-}
-
-/* Precache a volume into a 3D voxel grid.
- * The voxel grid is stored in the ObjectInstanceRen,
- * in camera space, aligned with the ObjectRen's bounding box.
- * Resolution is defined by the user.
- */
-static void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma)
-{
- VolumePrecache *vp;
- RayObject *tree;
- ShadeInput shi;
-
- R = *re;
-
- /* create a raytree with just the faces of the instanced ObjectRen,
- * used for checking if the cached point is inside or outside. */
- tree = makeraytree_object(&R, obi);
- if (!tree) return;
-
- vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache");
- obi->volume_precache = vp;
-
- if (!precache_resolution(re, vp, obi, ma->vol.precache_resolution)) {
- MEM_freeN(vp);
- vp = NULL;
- return;
- }
-
- vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel");
- vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel");
- vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel");
- if (vp->data_r==NULL || vp->data_g==NULL || vp->data_b==NULL) {
- MEM_freeN(vp);
- return;
- }
-
- /* Need a shadeinput to calculate scattering */
- precache_setup_shadeinput(re, obi, ma, &shi);
-
- precache_launch_parts(re, tree, &shi, obi);
-
- if (tree) {
- /* TODO: makeraytree_object creates a tree and saves it on OBI,
- * if we free this tree we should also clear other pointers to it */
- //RE_rayobject_free(tree);
- //tree= NULL;
- }
-
- if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
- /* this should be before the filtering */
- multiple_scattering_diffusion(re, obi->volume_precache, ma);
- }
-
- lightcache_filter(obi->volume_precache);
-}
-
-static int using_lightcache(Material *ma)
-{
- return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SHADED)) ||
- (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)));
-}
-
-/* loop through all objects (and their associated materials)
- * marked for pre-caching in convertblender.c, and pre-cache them */
-void volume_precache(Render *re)
-{
- ObjectInstanceRen *obi;
- VolumeOb *vo;
-
- re->i.infostr = IFACE_("Volume preprocessing");
- re->stats_draw(re->sdh, &re->i);
-
- for (vo= re->volumes.first; vo; vo= vo->next) {
- if (using_lightcache(vo->ma)) {
- for (obi= re->instancetable.first; obi; obi= obi->next) {
- if (obi->obr == vo->obr) {
- vol_precache_objectinstance_threads(re, obi, vo->ma);
-
- if (re->test_break && re->test_break(re->tbh))
- break;
- }
- }
-
- if (re->test_break && re->test_break(re->tbh))
- break;
- }
- }
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-}
-
-void free_volume_precache(Render *re)
-{
- ObjectInstanceRen *obi;
-
- for (obi= re->instancetable.first; obi; obi= obi->next) {
- if (obi->volume_precache != NULL) {
- MEM_freeN(obi->volume_precache->data_r);
- MEM_freeN(obi->volume_precache->data_g);
- MEM_freeN(obi->volume_precache->data_b);
- MEM_freeN(obi->volume_precache->bbmin);
- MEM_freeN(obi->volume_precache->bbmax);
- MEM_freeN(obi->volume_precache);
- obi->volume_precache = NULL;
- }
- }
-
- BLI_freelistN(&re->volumes);
-}
-
-int point_inside_volume_objectinstance(Render *re, ObjectInstanceRen *obi, const float co[3])
-{
- RayObject *tree;
- int inside=0;
-
- tree = makeraytree_object(re, obi);
- if (!tree) return 0;
-
- inside = point_inside_obi(tree, obi, co);
-
- //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it
- //RE_rayobject_free(tree);
- //tree= NULL;
-
- return inside;
-}
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
deleted file mode 100644
index 583353ed8cf..00000000000
--- a/source/blender/render/intern/source/volumetric.c
+++ /dev/null
@@ -1,836 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary)
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/volumetric.c
- * \ingroup render
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <float.h>
-
-#include "BLI_math.h"
-#include "BLI_rand.h"
-#include "BLI_voxel.h"
-#include "BLI_utildefines.h"
-
-#include "RE_shader_ext.h"
-
-#include "IMB_colormanagement.h"
-
-#include "DNA_material_types.h"
-#include "DNA_group_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_meta_types.h"
-
-
-#include "render_types.h"
-#include "pixelshading.h"
-#include "rayintersection.h"
-#include "rayobject.h"
-#include "renderdatabase.h"
-#include "shading.h"
-#include "shadbuf.h"
-#include "texture.h"
-#include "volumetric.h"
-#include "volume_precache.h"
-
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-/* tracing */
-static float vol_get_shadow(ShadeInput *shi, LampRen *lar, const float co[3])
-{
- float visibility = 1.f;
-
- if (lar->shb) {
- float dxco[3] = {0.f, 0.f, 0.f}, dyco[3] = {0.f, 0.f, 0.f};
-
- visibility = testshadowbuf(&R, lar->shb, co, dxco, dyco, 1.0, 0.0);
- }
- else if (lar->mode & LA_SHAD_RAY) {
- /* trace shadow manually, no good lamp api atm */
- Isect is;
-
- copy_v3_v3(is.start, co);
- if (lar->type == LA_SUN || lar->type == LA_HEMI) {
- is.dir[0] = -lar->vec[0];
- is.dir[1] = -lar->vec[1];
- is.dir[2] = -lar->vec[2];
- is.dist = R.maxdist;
- }
- else {
- sub_v3_v3v3(is.dir, lar->co, is.start);
- is.dist = normalize_v3(is.dir);
- }
-
- is.mode = RE_RAY_MIRROR;
- is.check = RE_CHECK_VLR_NON_SOLID_MATERIAL;
- is.skip = 0;
-
- if (lar->mode & (LA_LAYER | LA_LAYER_SHADOW))
- is.lay = lar->lay;
- else
- is.lay = -1;
-
- is.orig.ob = NULL;
- is.orig.face = NULL;
- is.last_hit = lar->last_hit[shi->thread];
-
- RE_instance_rotate_ray(shi->obi, &is);
-
- if (RE_rayobject_raycast(R.raytree, &is)) {
- RE_instance_rotate_ray_restore(shi->obi, &is);
-
- visibility = 0.f;
- }
-
- lar->last_hit[shi->thread] = is.last_hit;
- }
- return visibility;
-}
-
-static int vol_get_bounds(ShadeInput *shi, const float co[3], const float vec[3], float hitco[3], Isect *isect, int intersect_type)
-{
-
- copy_v3_v3(isect->start, co);
- copy_v3_v3(isect->dir, vec);
- isect->dist = FLT_MAX;
- isect->mode = RE_RAY_MIRROR;
- isect->last_hit = NULL;
- isect->lay = -1;
- isect->check = RE_CHECK_VLR_NONE;
-
- if (intersect_type == VOL_BOUNDS_DEPTH) {
- isect->skip = RE_SKIP_VLR_NEIGHBOUR;
- isect->orig.face = (void *)shi->vlr;
- isect->orig.ob = (void *)shi->obi;
- }
- else { // if (intersect_type == VOL_BOUNDS_SS) {
- isect->skip = 0;
- isect->orig.face = NULL;
- isect->orig.ob = NULL;
- }
-
- RE_instance_rotate_ray(shi->obi, isect);
-
- if (RE_rayobject_raycast(R.raytree, isect)) {
- RE_instance_rotate_ray_restore(shi->obi, isect);
-
- hitco[0] = isect->start[0] + isect->dist * isect->dir[0];
- hitco[1] = isect->start[1] + isect->dist * isect->dir[1];
- hitco[2] = isect->start[2] + isect->dist * isect->dir[2];
- return 1;
- }
- else {
- return 0;
- }
-}
-
-static void shade_intersection(ShadeInput *shi, float col_r[4], Isect *is)
-{
- ShadeInput shi_new;
- ShadeResult shr_new;
-
- memset(&shi_new, 0, sizeof(ShadeInput));
-
- shi_new.mask = shi->mask;
- shi_new.osatex = shi->osatex;
- shi_new.thread = shi->thread;
- shi_new.depth = shi->depth + 1;
- shi_new.volume_depth = shi->volume_depth + 1;
- shi_new.xs = shi->xs;
- shi_new.ys = shi->ys;
- shi_new.lay = shi->lay;
- shi_new.passflag = SCE_PASS_COMBINED; /* result of tracing needs no pass info */
- shi_new.combinedflag = 0xFFFFFF; /* ray trace does all options */
- shi_new.light_override = shi->light_override;
- shi_new.mat_override = shi->mat_override;
-
- copy_v3_v3(shi_new.camera_co, is->start);
-
- memset(&shr_new, 0, sizeof(ShadeResult));
-
- /* hardcoded limit of 100 for now - prevents problems in weird geometry */
- if (shi->volume_depth < 100) {
- shade_ray(is, &shi_new, &shr_new);
- }
-
- copy_v3_v3(col_r, shr_new.combined);
- col_r[3] = shr_new.alpha;
-}
-
-static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, const float co[3], float col_r[4])
-{
- Isect isect;
-
- copy_v3_v3(isect.start, co);
- copy_v3_v3(isect.dir, shi->view);
- isect.dist = FLT_MAX;
-
- isect.mode = RE_RAY_MIRROR;
- isect.check = RE_CHECK_VLR_NONE;
- isect.skip = RE_SKIP_VLR_NEIGHBOUR;
- isect.orig.ob = (void *) shi->obi;
- isect.orig.face = (void *)vlr;
- isect.last_hit = NULL;
- isect.lay = -1;
-
- /* check to see if there's anything behind the volume, otherwise shade the sky */
- RE_instance_rotate_ray(shi->obi, &isect);
-
- if (RE_rayobject_raycast(R.raytree, &isect)) {
- RE_instance_rotate_ray_restore(shi->obi, &isect);
-
- shade_intersection(shi, col_r, &isect);
- }
- else {
- shadeSkyView(col_r, co, shi->view, NULL, shi->thread);
- shadeSunView(col_r, shi->view);
- }
-}
-
-
-/* trilinear interpolation */
-static void vol_get_precached_scattering(Render *re, ShadeInput *shi, float scatter_col[3], const float co[3])
-{
- VolumePrecache *vp = shi->obi->volume_precache;
- float bbmin[3], bbmax[3], dim[3];
- float world_co[3], sample_co[3];
-
- if (!vp) return;
-
- /* find sample point in global space bounding box 0.0-1.0 */
- global_bounds_obi(re, shi->obi, bbmin, bbmax);
- sub_v3_v3v3(dim, bbmax, bbmin);
- mul_v3_m4v3(world_co, re->viewinv, co);
-
- /* sample_co in 0.0-1.0 */
- sample_co[0] = (world_co[0] - bbmin[0]) / dim[0];
- sample_co[1] = (world_co[1] - bbmin[1]) / dim[1];
- sample_co[2] = (world_co[2] - bbmin[2]) / dim[2];
-
- scatter_col[0] = BLI_voxel_sample_triquadratic(vp->data_r, vp->res, sample_co);
- scatter_col[1] = BLI_voxel_sample_triquadratic(vp->data_g, vp->res, sample_co);
- scatter_col[2] = BLI_voxel_sample_triquadratic(vp->data_b, vp->res, sample_co);
-}
-
-/* Meta object density, brute force for now
- * (might be good enough anyway, don't need huge number of metaobs to model volumetric objects */
-static float metadensity(Object *ob, const float co[3])
-{
- float mat[4][4], imat[4][4], dens = 0.f;
- MetaBall *mb = (MetaBall *)ob->data;
- MetaElem *ml;
-
- /* transform co to meta-element */
- float tco[3] = {co[0], co[1], co[2]};
- mul_m4_m4m4(mat, R.viewmat, ob->obmat);
- invert_m4_m4(imat, mat);
- mul_m4_v3(imat, tco);
-
- for (ml = mb->elems.first; ml; ml = ml->next) {
- float bmat[3][3], dist2;
-
- /* element rotation transform */
- float tp[3] = {ml->x - tco[0], ml->y - tco[1], ml->z - tco[2]};
- quat_to_mat3(bmat, ml->quat);
- transpose_m3(bmat); /* rot.only, so inverse == transpose */
- mul_m3_v3(bmat, tp);
-
- /* MB_BALL default */
- switch (ml->type) {
- case MB_ELIPSOID:
- tp[0] /= ml->expx;
- tp[1] /= ml->expy;
- tp[2] /= ml->expz;
- break;
- case MB_CUBE:
- tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f);
- /* no break, xy as plane */
- ATTR_FALLTHROUGH;
- case MB_PLANE:
- tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f);
- /* no break, x as tube */
- ATTR_FALLTHROUGH;
- case MB_TUBE:
- tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f);
- }
-
- /* ml->rad2 is not set */
- dist2 = 1.0f - (dot_v3v3(tp, tp) / (ml->rad * ml->rad));
- if (dist2 > 0.f)
- dens += (ml->flag & MB_NEGATIVE) ? -ml->s * dist2 * dist2 * dist2 : ml->s * dist2 * dist2 * dist2;
- }
-
- dens -= mb->thresh;
- return (dens < 0.f) ? 0.f : dens;
-}
-
-float vol_get_density(struct ShadeInput *shi, const float co[3])
-{
- float density = shi->mat->vol.density;
- float density_scale = shi->mat->vol.density_scale;
-
- if (shi->mat->mapto_textured & MAP_DENSITY)
- do_volume_tex(shi, co, MAP_DENSITY, NULL, &density, &R);
-
- /* if meta-object, modulate by metadensity without increasing it */
- if (shi->obi->obr->ob->type == OB_MBALL) {
- const float md = metadensity(shi->obi->obr->ob, co);
- if (md < 1.f) density *= md;
- }
-
- return density * density_scale;
-}
-
-
-/* Color of light that gets scattered out by the volume */
-/* Uses same physically based scattering parameter as in transmission calculations,
- * along with artificial reflection scale/reflection color tint */
-static void vol_get_reflection_color(ShadeInput *shi, float ref_col[3], const float co[3])
-{
- float scatter = shi->mat->vol.scattering;
- float reflection = shi->mat->vol.reflection;
- copy_v3_v3(ref_col, shi->mat->vol.reflection_col);
-
- if (shi->mat->mapto_textured & (MAP_SCATTERING + MAP_REFLECTION_COL))
- do_volume_tex(shi, co, MAP_SCATTERING + MAP_REFLECTION_COL, ref_col, &scatter, &R);
-
- /* only one single float parameter at a time... :s */
- if (shi->mat->mapto_textured & (MAP_REFLECTION))
- do_volume_tex(shi, co, MAP_REFLECTION, NULL, &reflection, &R);
-
- ref_col[0] = reflection * ref_col[0] * scatter;
- ref_col[1] = reflection * ref_col[1] * scatter;
- ref_col[2] = reflection * ref_col[2] * scatter;
-}
-
-/* compute emission component, amount of radiance to add per segment
- * can be textured with 'emit' */
-static void vol_get_emission(ShadeInput *shi, float emission_col[3], const float co[3])
-{
- float emission = shi->mat->vol.emission;
- copy_v3_v3(emission_col, shi->mat->vol.emission_col);
-
- if (shi->mat->mapto_textured & (MAP_EMISSION + MAP_EMISSION_COL))
- do_volume_tex(shi, co, MAP_EMISSION + MAP_EMISSION_COL, emission_col, &emission, &R);
-
- emission_col[0] = emission_col[0] * emission;
- emission_col[1] = emission_col[1] * emission;
- emission_col[2] = emission_col[2] * emission;
-}
-
-
-/* A combination of scattering and absorption -> known as sigma T.
- * This can possibly use a specific scattering color,
- * and absorption multiplier factor too, but these parameters are left out for simplicity.
- * It's easy enough to get a good wide range of results with just these two parameters. */
-static void vol_get_sigma_t(ShadeInput *shi, float sigma_t[3], const float co[3])
-{
- /* technically absorption, but named transmission color
- * since it describes the effect of the coloring *after* absorption */
- float transmission_col[3] = {shi->mat->vol.transmission_col[0], shi->mat->vol.transmission_col[1], shi->mat->vol.transmission_col[2]};
- float scattering = shi->mat->vol.scattering;
-
- if (shi->mat->mapto_textured & (MAP_SCATTERING + MAP_TRANSMISSION_COL))
- do_volume_tex(shi, co, MAP_SCATTERING + MAP_TRANSMISSION_COL, transmission_col, &scattering, &R);
-
- sigma_t[0] = (1.0f - transmission_col[0]) + scattering;
- sigma_t[1] = (1.0f - transmission_col[1]) + scattering;
- sigma_t[2] = (1.0f - transmission_col[2]) + scattering;
-}
-
-/* phase function - determines in which directions the light
- * is scattered in the volume relative to incoming direction
- * and view direction */
-static float vol_get_phasefunc(ShadeInput *UNUSED(shi), float g, const float w[3], const float wp[3])
-{
- const float normalize = 0.25f; // = 1.f/4.f = M_PI/(4.f*M_PI)
-
- /* normalization constant is 1/4 rather than 1/4pi, since
- * Blender's shading system doesn't normalize for
- * energy conservation - eg. multiplying by pdf ( 1/pi for a lambert brdf ).
- * This means that lambert surfaces in Blender are pi times brighter than they 'should be'
- * and therefore, with correct energy conservation, volumes will darker than other solid objects,
- * for the same lighting intensity.
- * To correct this, scale up the phase function values by pi
- * until Blender's shading system supports this better. --matt
- */
-
- if (g == 0.f) { /* isotropic */
- return normalize * 1.f;
- }
- else { /* schlick */
- const float k = 1.55f * g - 0.55f * g * g * g;
- const float kcostheta = k * dot_v3v3(w, wp);
- return normalize * (1.f - k * k) / ((1.f - kcostheta) * (1.f - kcostheta));
- }
-
- /* not used, but here for reference: */
-#if 0
- switch (phasefunc_type) {
- case MA_VOL_PH_MIEHAZY:
- return normalize * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f));
- case MA_VOL_PH_MIEMURKY:
- return normalize * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f));
- case MA_VOL_PH_RAYLEIGH:
- return normalize * 3.f / 4.f * (1 + costheta * costheta);
- case MA_VOL_PH_HG:
- return normalize * (1.f - g * g) / powf(1.f + g * g - 2.f * g * costheta, 1.5f);
- case MA_VOL_PH_SCHLICK:
- {
- const float k = 1.55f * g - 0.55f * g * g * g;
- const float kcostheta = k * costheta;
- return normalize * (1.f - k * k) / ((1.f - kcostheta) * (1.f - kcostheta));
- }
- case MA_VOL_PH_ISOTROPIC:
- default:
- return normalize * 1.f;
- }
-#endif
-}
-
-/* Compute transmittance = e^(-attenuation) */
-static void vol_get_transmittance_seg(ShadeInput *shi, float tr[3], float stepsize, const float co[3], float density)
-{
- /* input density = density at co */
- float tau[3] = {0.f, 0.f, 0.f};
- const float stepd = density * stepsize;
- float sigma_t[3];
-
- vol_get_sigma_t(shi, sigma_t, co);
-
- /* homogeneous volume within the sampled distance */
- tau[0] += stepd * sigma_t[0];
- tau[1] += stepd * sigma_t[1];
- tau[2] += stepd * sigma_t[2];
-
- tr[0] *= expf(-tau[0]);
- tr[1] *= expf(-tau[1]);
- tr[2] *= expf(-tau[2]);
-}
-
-/* Compute transmittance = e^(-attenuation) */
-static void vol_get_transmittance(ShadeInput *shi, float tr[3], const float co[3], const float endco[3])
-{
- float p[3] = {co[0], co[1], co[2]};
- float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
- float tau[3] = {0.f, 0.f, 0.f};
-
- float t0 = 0.f;
- float t1 = normalize_v3(step_vec);
- float pt0 = t0;
-
- t0 += shi->mat->vol.stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
- p[0] += t0 * step_vec[0];
- p[1] += t0 * step_vec[1];
- p[2] += t0 * step_vec[2];
- mul_v3_fl(step_vec, shi->mat->vol.stepsize);
-
- for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.stepsize) {
- const float d = vol_get_density(shi, p);
- const float stepd = (t0 - pt0) * d;
- float sigma_t[3];
-
- vol_get_sigma_t(shi, sigma_t, p);
-
- tau[0] += stepd * sigma_t[0];
- tau[1] += stepd * sigma_t[1];
- tau[2] += stepd * sigma_t[2];
-
- add_v3_v3(p, step_vec);
- }
-
- /* return transmittance */
- tr[0] = expf(-tau[0]);
- tr[1] = expf(-tau[1]);
- tr[2] = expf(-tau[2]);
-}
-
-static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const float view[3], LampRen *lar, float lacol[3])
-{
- float visifac, lv[3], lampdist;
- float tr[3] = {1.0, 1.0, 1.0};
- float hitco[3], *atten_co;
- float p, ref_col[3];
-
- if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay) == 0) return;
- if ((lar->lay & shi->lay) == 0) return;
- if (lar->energy == 0.0f) return;
-
- if ((visifac = lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
-
- copy_v3_v3(lacol, &lar->r);
-
- if (lar->mode & LA_TEXTURE) {
- shi->osatex = 0;
- do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
- }
-
- mul_v3_fl(lacol, visifac);
-
- if (ELEM(lar->type, LA_SUN, LA_HEMI))
- copy_v3_v3(lv, lar->vec);
- negate_v3(lv);
-
- if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
- mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
- }
- else if (ELEM(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
- Isect is;
-
- if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
- mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
- if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
- }
-
- /* find minimum of volume bounds, or lamp coord */
- if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
- float dist = len_v3v3(co, hitco);
- VlakRen *vlr = (VlakRen *)is.hit.face;
-
- /* simple internal shadowing */
- if (vlr->mat->material_type == MA_TYPE_SURFACE) {
- lacol[0] = lacol[1] = lacol[2] = 0.0f;
- return;
- }
-
- if (ELEM(lar->type, LA_SUN, LA_HEMI))
- /* infinite lights, can never be inside volume */
- atten_co = hitco;
- else if (lampdist < dist) {
- atten_co = lar->co;
- }
- else
- atten_co = hitco;
-
- vol_get_transmittance(shi, tr, co, atten_co);
-
- mul_v3_v3v3(lacol, lacol, tr);
- }
- else {
- /* Point is on the outside edge of the volume,
- * therefore no attenuation, full transmission.
- * Radiance from lamp remains unchanged */
- }
- }
-
- if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
-
- normalize_v3(lv);
- p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv);
-
- /* physically based scattering with non-physically based RGB gain */
- vol_get_reflection_color(shi, ref_col, co);
-
- lacol[0] *= p * ref_col[0];
- lacol[1] *= p * ref_col[1];
- lacol[2] *= p * ref_col[2];
-}
-
-/* single scattering only for now */
-void vol_get_scattering(ShadeInput *shi, float scatter_col[3], const float co[3], const float view[3])
-{
- ListBase *lights;
- GroupObject *go;
- LampRen *lar;
-
- zero_v3(scatter_col);
-
- lights = get_lights(shi);
- for (go = lights->first; go; go = go->next) {
- float lacol[3] = {0.f, 0.f, 0.f};
- lar = go->lampren;
-
- if (lar) {
- vol_shade_one_lamp(shi, co, view, lar, lacol);
- add_v3_v3(scatter_col, lacol);
- }
- }
-}
-
-
-/*
- * The main volumetric integrator, using an emission/absorption/scattering model.
- *
- * Incoming radiance =
- *
- * outgoing radiance from behind surface * beam transmittance/attenuation
- * + added radiance from all points along the ray due to participating media
- * --> radiance for each segment =
- * (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation
- */
-
-/* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't
- * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light
- * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct,
- * it also makes it harder to control the overall look of the volume since coloring the outscattered light results
- * in the inverse color being transmitted through the rest of the volume.
- */
-static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co[3], const float endco[3])
-{
- float radiance[3] = {0.f, 0.f, 0.f};
- float tr[3] = {1.f, 1.f, 1.f};
- float p[3] = {co[0], co[1], co[2]};
- float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
- const float stepsize = shi->mat->vol.stepsize;
-
- float t0 = 0.f;
- float pt0 = t0;
- float t1 = normalize_v3(step_vec); /* returns vector length */
-
- t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
- p[0] += t0 * step_vec[0];
- p[1] += t0 * step_vec[1];
- p[2] += t0 * step_vec[2];
- mul_v3_fl(step_vec, stepsize);
-
- for (; t0 < t1; pt0 = t0, t0 += stepsize) {
- const float density = vol_get_density(shi, p);
-
- if (density > 0.00001f) {
- float scatter_col[3] = {0.f, 0.f, 0.f}, emit_col[3];
- const float stepd = (t0 - pt0) * density;
-
- /* transmittance component (alpha) */
- vol_get_transmittance_seg(shi, tr, stepsize, co, density);
-
- if (t0 > t1 * 0.25f) {
- /* only use depth cutoff after we've traced a little way into the volume */
- if (IMB_colormanagement_get_luminance(tr) < shi->mat->vol.depth_cutoff) break;
- }
-
- vol_get_emission(shi, emit_col, p);
-
- if (shi->obi->volume_precache) {
- float p2[3];
-
- p2[0] = p[0] + (step_vec[0] * 0.5f);
- p2[1] = p[1] + (step_vec[1] * 0.5f);
- p2[2] = p[2] + (step_vec[2] * 0.5f);
-
- vol_get_precached_scattering(&R, shi, scatter_col, p2);
- }
- else
- vol_get_scattering(shi, scatter_col, p, shi->view);
-
- radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]);
- radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]);
- radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]);
- }
- add_v3_v3(p, step_vec);
- }
-
- /* multiply original color (from behind volume) with transmittance over entire distance */
- mul_v3_v3v3(col, tr, col);
- add_v3_v3(col, radiance);
-
- /* alpha <-- transmission luminance */
- col[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
-}
-
-/* the main entry point for volume shading */
-static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume)
-{
- float hitco[3], col[4] = {0.f, 0.f, 0.f, 0.f};
- const float *startco, *endco;
- int trace_behind = 1;
- const int ztransp = ((shi->depth == 0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP));
- Isect is;
-
- /* check for shading an internal face a volume object directly */
- if (inside_volume == VOL_SHADE_INSIDE)
- trace_behind = 0;
- else if (inside_volume == VOL_SHADE_OUTSIDE) {
- if (shi->flippednor)
- inside_volume = VOL_SHADE_INSIDE;
- }
-
- if (ztransp && inside_volume == VOL_SHADE_INSIDE) {
- MatInside *mi;
- int render_this = 0;
-
- /* don't render the backfaces of ztransp volume materials.
- *
- * volume shading renders the internal volume from between the
- * ' view intersection of the solid volume to the
- * intersection on the other side, as part of the shading of
- * the front face.
- *
- * Because ztransp renders both front and back faces independently
- * this will double up, so here we prevent rendering the backface as well,
- * which would otherwise render the volume in between the camera and the backface
- * --matt */
-
- for (mi = R.render_volumes_inside.first; mi; mi = mi->next) {
- /* weak... */
- if (mi->ma == shi->mat) render_this = 1;
- }
- if (!render_this) return;
- }
-
-
- if (inside_volume == VOL_SHADE_INSIDE) {
- startco = shi->camera_co;
- endco = shi->co;
-
- if (trace_behind) {
- if (!ztransp)
- /* trace behind the volume object */
- vol_trace_behind(shi, shi->vlr, endco, col);
- }
- else {
- /* we're tracing through the volume between the camera
- * and a solid surface, so use that pre-shaded radiance */
- copy_v4_v4(col, shr->combined);
- }
-
- /* shade volume from 'camera' to 1st hit point */
- volumeintegrate(shi, col, startco, endco);
- }
- /* trace to find a backface, the other side bounds of the volume */
- /* (ray intersect ignores front faces here) */
- else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
- VlakRen *vlr = (VlakRen *)is.hit.face;
-
- startco = shi->co;
- endco = hitco;
-
- if (!ztransp) {
- /* if it's another face in the same material */
- if (vlr->mat == shi->mat) {
- /* trace behind the 2nd (raytrace) hit point */
- vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col);
- }
- else {
- shade_intersection(shi, col, &is);
- }
- }
-
- /* shade volume from 1st hit point to 2nd hit point */
- volumeintegrate(shi, col, startco, endco);
- }
-
- if (ztransp)
- col[3] = col[3] > 1.f ? 1.f : col[3];
- else
- col[3] = 1.f;
-
- copy_v3_v3(shr->combined, col);
- shr->alpha = col[3];
-
- copy_v3_v3(shr->diff, shr->combined);
- copy_v3_v3(shr->diffshad, shr->diff);
-}
-
-/* Traces a shadow through the object,
- * pretty much gets the transmission over a ray path */
-void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
-{
- float hitco[3];
- float tr[3] = {1.0, 1.0, 1.0};
- Isect is = {{0}};
- const float *startco, *endco;
-
- memset(shr, 0, sizeof(ShadeResult));
-
- /* if 1st hit normal is facing away from the camera,
- * then we're inside the volume already. */
- if (shi->flippednor) {
- startco = last_is->start;
- endco = shi->co;
- }
-
- /* trace to find a backface, the other side bounds of the volume */
- /* (ray intersect ignores front faces here) */
- else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
- startco = shi->co;
- endco = hitco;
- }
- else {
- shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
- shr->alpha = shr->combined[3] = 1.f;
- return;
- }
-
- vol_get_transmittance(shi, tr, startco, endco);
-
-
- /* if we hit another face in the same volume bounds */
- /* shift raytrace coordinates to the hit point, to avoid shading volume twice */
- /* due to idiosyncracy in ray_trace_shadow_tra() */
- if (is.hit.ob == shi->obi) {
- copy_v3_v3(shi->co, hitco);
- last_is->dist += is.dist;
- shi->vlr = (VlakRen *)is.hit.face;
- }
-
-
- copy_v3_v3(shr->combined, tr);
- shr->combined[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
- shr->alpha = shr->combined[3];
-}
-
-
-/* delivers a fully filled in ShadeResult, for all passes */
-void shade_volume_outside(ShadeInput *shi, ShadeResult *shr)
-{
- memset(shr, 0, sizeof(ShadeResult));
- volume_trace(shi, shr, VOL_SHADE_OUTSIDE);
-}
-
-
-void shade_volume_inside(ShadeInput *shi, ShadeResult *shr)
-{
- MatInside *m;
- Material *mat_backup;
- ObjectInstanceRen *obi_backup;
- float prev_alpha = shr->alpha;
-
- /* XXX: extend to multiple volumes perhaps later */
- mat_backup = shi->mat;
- obi_backup = shi->obi;
-
- m = R.render_volumes_inside.first;
- shi->mat = m->ma;
- shi->obi = m->obi;
- shi->obr = m->obi->obr;
-
- volume_trace(shi, shr, VOL_SHADE_INSIDE);
-
- shr->alpha = shr->alpha + prev_alpha;
- CLAMP(shr->alpha, 0.0f, 1.0f);
-
- shi->mat = mat_backup;
- shi->obi = obi_backup;
- shi->obr = obi_backup->obr;
-}
diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c
deleted file mode 100644
index 2daa4123536..00000000000
--- a/source/blender/render/intern/source/voxeldata.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/render/intern/source/voxeldata.c
- * \ingroup render
- */
-
-
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifdef WIN32
-#include "BLI_winstuff.h"
-#endif
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_threads.h"
-#include "BLI_voxel.h"
-#include "BLI_utildefines.h"
-
-#include "BLT_translation.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BKE_cloth.h"
-#include "BKE_global.h"
-#include "BKE_image.h"
-#include "BKE_main.h"
-#include "BKE_modifier.h"
-
-#include "smoke_API.h"
-#include "BPH_mass_spring.h"
-
-#include "DNA_texture_types.h"
-#include "DNA_object_force_types.h"
-#include "DNA_object_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_smoke_types.h"
-
-
-#include "render_types.h"
-#include "texture.h"
-#include "voxeldata.h"
-
-static bool is_vd_res_ok(VoxelData *vd)
-{
- /* arbitrary large value so corrupt headers don't break */
- const int min = 1, max = 100000;
- return (vd->resol[0] >= min && vd->resol[0] <= max) &&
- (vd->resol[1] >= min && vd->resol[1] <= max) &&
- (vd->resol[2] >= min && vd->resol[2] <= max);
-}
-
-/* use size_t because the result may exceed INT_MAX */
-static size_t vd_resol_size(VoxelData *vd)
-{
- return (size_t)vd->resol[0] * (size_t)vd->resol[1] * (size_t)vd->resol[2];
-}
-
-static int load_frame_blendervoxel(VoxelData *vd, FILE *fp, int frame)
-{
- const size_t size = vd_resol_size(vd);
- size_t offset = sizeof(VoxelDataHeader);
-
- if (is_vd_res_ok(vd) == false)
- return 0;
-
- vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
- if (vd->dataset == NULL) return 0;
-
- if (fseek(fp, frame * size * sizeof(float) + offset, 0) == -1)
- return 0;
- if (fread(vd->dataset, sizeof(float), size, fp) != size)
- return 0;
-
- vd->cachedframe = frame;
- vd->ok = 1;
- return 1;
-}
-
-static int load_frame_raw8(VoxelData *vd, FILE *fp, int frame)
-{
- const size_t size = vd_resol_size(vd);
- size_t i;
- char *data_c;
-
- if (is_vd_res_ok(vd) == false)
- return 0;
-
- vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
- if (vd->dataset == NULL) return 0;
- data_c = (char *)MEM_mallocN(sizeof(char) * size, "temporary voxel file reading storage");
- if (data_c == NULL) {
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- return 0;
- }
-
- if (fseek(fp, (frame - 1) * size * sizeof(char), 0) == -1) {
- MEM_freeN(data_c);
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- return 0;
- }
- if (fread(data_c, sizeof(char), size, fp) != size) {
- MEM_freeN(data_c);
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- return 0;
- }
-
- for (i = 0; i < size; i++) {
- vd->dataset[i] = (float)data_c[i] / 255.f;
- }
- MEM_freeN(data_c);
-
- vd->cachedframe = frame;
- vd->ok = 1;
- return 1;
-}
-
-static void load_frame_image_sequence(VoxelData *vd, Tex *tex)
-{
- ImBuf *ibuf;
- Image *ima = tex->ima;
- ImageUser *tiuser = &tex->iuser;
- ImageUser iuser = *(tiuser);
- int x = 0, y = 0, z = 0;
- const float *rf;
-
- if (!ima) return;
- if (iuser.frames == 0) return;
-
- ima->source = IMA_SRC_SEQUENCE;
- iuser.framenr = 1 + iuser.offset;
-
- /* find the first valid ibuf and use it to initialize the resolution of the data set */
- /* need to do this in advance so we know how much memory to allocate */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- while (!ibuf && (iuser.framenr < iuser.frames)) {
- iuser.framenr++;
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- }
- if (!ibuf) return;
- if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
-
- vd->flag |= TEX_VD_STILL;
- vd->resol[0] = ibuf->x;
- vd->resol[1] = ibuf->y;
- vd->resol[2] = iuser.frames;
- vd->dataset = MEM_mapallocN(sizeof(float) * vd_resol_size(vd), "voxel dataset");
-
- for (z = 0; z < iuser.frames; z++) {
- /* get a new ibuf for each frame */
- if (z > 0) {
- iuser.framenr++;
- BKE_image_release_ibuf(ima, ibuf, NULL);
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (!ibuf) break;
- if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
- }
- rf = ibuf->rect_float;
-
- for (y = 0; y < ibuf->y; y++) {
- for (x = 0; x < ibuf->x; x++) {
- /* currently averaged to monchrome */
- vd->dataset[BLI_VOXEL_INDEX(x, y, z, vd->resol)] = (rf[0] + rf[1] + rf[2]) / 3.0f;
- rf += 4;
- }
- }
-
- BKE_image_free_anim_ibufs(ima, iuser.framenr);
- }
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- vd->ok = 1;
- return;
-}
-
-static int read_voxeldata_header(FILE *fp, struct VoxelData *vd)
-{
- VoxelDataHeader *h = (VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header");
-
- rewind(fp);
- if (fread(h, sizeof(VoxelDataHeader), 1, fp) != 1) {
- MEM_freeN(h);
- return 0;
- }
-
- vd->resol[0] = h->resolX;
- vd->resol[1] = h->resolY;
- vd->resol[2] = h->resolZ;
-
- MEM_freeN(h);
- return 1;
-}
-
-static void init_frame_smoke(VoxelData *vd, int cfra)
-{
-#ifdef WITH_SMOKE
- Object *ob;
- ModifierData *md;
-
- vd->dataset = NULL;
- if (vd->object == NULL) return;
- ob = vd->object;
-
- /* draw code for smoke */
- if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))) {
- SmokeModifierData *smd = (SmokeModifierData *)md;
- SmokeDomainSettings *sds = smd->domain;
-
- if (sds && sds->fluid) {
- BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
-
- if (!sds->fluid) {
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- return;
- }
-
- if (cfra < sds->point_cache[0]->startframe)
- ; /* don't show smoke before simulation starts, this could be made an option in the future */
- else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
- size_t totRes;
- size_t i;
- float *heat;
-
- if (!smoke_has_heat(sds->fluid)) {
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- return;
- }
-
- copy_v3_v3_int(vd->resol, sds->res);
- totRes = vd_resol_size(vd);
- vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
- /* get heat data */
- heat = smoke_get_heat(sds->fluid);
-
- /* scale heat values from -2.0-2.0 to 0.0-1.0 */
- for (i = 0; i < totRes; i++) {
- vd->dataset[i] = (heat[i] + 2.0f) / 4.0f;
- }
- }
- else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
- size_t totRes;
- size_t i;
- float *xvel, *yvel, *zvel;
-
- copy_v3_v3_int(vd->resol, sds->res);
- totRes = vd_resol_size(vd);
- vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
- /* get velocity data */
- xvel = smoke_get_velocity_x(sds->fluid);
- yvel = smoke_get_velocity_y(sds->fluid);
- zvel = smoke_get_velocity_z(sds->fluid);
-
- /* map velocities between 0 and 0.3f */
- for (i = 0; i < totRes; i++) {
- vd->dataset[i] = sqrtf(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f;
- }
-
- }
- else if (vd->smoked_type == TEX_VD_SMOKEFLAME) {
- size_t totRes;
- float *flame;
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- if (!smoke_turbulence_has_fuel(sds->wt)) {
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- return;
- }
- smoke_turbulence_get_res(sds->wt, vd->resol);
- flame = smoke_turbulence_get_flame(sds->wt);
- }
- else {
- if (!smoke_has_fuel(sds->fluid)) {
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- return;
- }
- copy_v3_v3_int(vd->resol, sds->res);
- flame = smoke_get_flame(sds->fluid);
- }
-
- /* always store copy, as smoke internal data can change */
- totRes = vd_resol_size(vd);
- vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
- memcpy(vd->dataset, flame, sizeof(float)*totRes);
- }
- else {
- size_t totCells;
- int depth = 4;
- vd->data_type = TEX_VD_RGBA_PREMUL;
-
- /* data resolution */
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- smoke_turbulence_get_res(sds->wt, vd->resol);
- }
- else {
- copy_v3_v3_int(vd->resol, sds->res);
- }
-
- /* TODO: is_vd_res_ok(rvd) doesnt check this resolution */
- totCells = vd_resol_size(vd) * depth;
- /* always store copy, as smoke internal data can change */
- vd->dataset = MEM_mapallocN(sizeof(float) * totCells, "smoke data");
-
- if (sds->flags & MOD_SMOKE_HIGHRES) {
- if (smoke_turbulence_has_colors(sds->wt)) {
- smoke_turbulence_get_rgba(sds->wt, vd->dataset, 1);
- }
- else {
- smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, vd->dataset, 1);
- }
- }
- else {
- if (smoke_has_colors(sds->fluid)) {
- smoke_get_rgba(sds->fluid, vd->dataset, 1);
- }
- else {
- smoke_get_rgba_from_density(sds->fluid, sds->active_color, vd->dataset, 1);
- }
- }
- } /* end of fluid condition */
-
- BLI_rw_mutex_unlock(sds->fluid_mutex);
- }
- }
-
- vd->ok = 1;
-
-#else // WITH_SMOKE
- (void)vd;
- (void)cfra;
-
- vd->dataset = NULL;
-#endif
-}
-
-static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
-{
- Object *ob;
- ModifierData *md;
-
- vd->dataset = NULL;
- if (vd->object == NULL) return;
- ob = vd->object;
-
- if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) {
- ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
-
- if (pmd->psys && pmd->psys->clmd) {
- vd->ok |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
- }
- }
-}
-
-void cache_voxeldata(Tex *tex, int scene_frame)
-{
- VoxelData *vd = tex->vd;
- FILE *fp;
- int curframe;
- char path[sizeof(vd->source_path)];
-
- /* only re-cache if dataset needs updating */
- if ((vd->flag & TEX_VD_STILL) || (vd->cachedframe == scene_frame))
- if (vd->ok) return;
-
- /* clear out old cache, ready for new */
- if (vd->dataset) {
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- }
- /* reset data_type */
- vd->data_type = TEX_VD_INTENSITY;
-
- if (vd->flag & TEX_VD_STILL)
- curframe = vd->still_frame;
- else
- curframe = scene_frame;
-
- BLI_strncpy(path, vd->source_path, sizeof(path));
-
- /* each type is responsible for setting to true */
- vd->ok = false;
-
- switch (vd->file_format) {
- case TEX_VD_IMAGE_SEQUENCE:
- load_frame_image_sequence(vd, tex);
- return;
- case TEX_VD_SMOKE:
- init_frame_smoke(vd, scene_frame);
- return;
- case TEX_VD_HAIR:
- init_frame_hair(vd, scene_frame);
- return;
- case TEX_VD_BLENDERVOXEL:
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
- fp = BLI_fopen(path, "rb");
- if (!fp) return;
-
- if (read_voxeldata_header(fp, vd))
- load_frame_blendervoxel(vd, fp, curframe - 1);
-
- fclose(fp);
- return;
- case TEX_VD_RAW_8BIT:
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
- fp = BLI_fopen(path, "rb");
- if (!fp) return;
-
- load_frame_raw8(vd, fp, curframe);
- fclose(fp);
- return;
- }
-}
-
-void make_voxeldata(struct Render *re)
-{
- Tex *tex;
-
- re->i.infostr = IFACE_("Loading voxel datasets");
- re->stats_draw(re->sdh, &re->i);
-
- /* XXX: should be doing only textures used in this render */
- for (tex = re->main->tex.first; tex; tex = tex->id.next) {
- if (tex->id.us && tex->type == TEX_VOXELDATA) {
- cache_voxeldata(tex, re->r.cfra);
- }
- }
-
- re->i.infostr = NULL;
- re->stats_draw(re->sdh, &re->i);
-
-}
-
-int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres)
-{
- VoxelData *vd = tex->vd;
- float co[3], offset[3] = {0.5, 0.5, 0.5}, a;
- int retval = (vd->data_type == TEX_VD_RGBA_PREMUL) ? TEX_RGB : TEX_INT;
- int depth = (vd->data_type == TEX_VD_RGBA_PREMUL) ? 4 : 1;
- int ch;
-
- if (vd->dataset == NULL) {
- texres->tin = 0.0f;
- return 0;
- }
-
- /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */
- /* in implementation this works backwards, bringing sample locations from -1.0, 1.0
- * to the range 0.0, 1.0, before looking up in the voxel structure. */
- copy_v3_v3(co, texvec);
- mul_v3_fl(co, 0.5f);
- add_v3_v3(co, offset);
-
- /* co is now in the range 0.0, 1.0 */
- switch (vd->extend) {
- case TEX_CLIP:
- {
- if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) {
- texres->tin = 0.f;
- return retval;
- }
- break;
- }
- case TEX_REPEAT:
- {
- co[0] = co[0] - floorf(co[0]);
- co[1] = co[1] - floorf(co[1]);
- co[2] = co[2] - floorf(co[2]);
- break;
- }
- case TEX_EXTEND:
- {
- CLAMP(co[0], 0.f, 1.f);
- CLAMP(co[1], 0.f, 1.f);
- CLAMP(co[2], 0.f, 1.f);
- break;
- }
- }
-
- for (ch = 0; ch < depth; ch++) {
- float *dataset = vd->dataset + ch*vd->resol[0]*vd->resol[1]*vd->resol[2];
- float *result = &texres->tin;
-
- if (vd->data_type == TEX_VD_RGBA_PREMUL) {
- switch (ch) {
- case 0:
- result = &texres->tr;
- break;
- case 1:
- result = &texres->tg;
- break;
- case 2:
- result = &texres->tb;
- break;
- }
- }
-
- switch (vd->interp_type) {
- case TEX_VD_NEARESTNEIGHBOR:
- *result = BLI_voxel_sample_nearest(dataset, vd->resol, co);
- break;
- case TEX_VD_LINEAR:
- *result = BLI_voxel_sample_trilinear(dataset, vd->resol, co);
- break;
- case TEX_VD_QUADRATIC:
- *result = BLI_voxel_sample_triquadratic(dataset, vd->resol, co);
- break;
- case TEX_VD_TRICUBIC_CATROM:
- case TEX_VD_TRICUBIC_BSPLINE:
- *result = BLI_voxel_sample_tricubic(dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
- break;
- }
- }
-
- a = texres->tin;
- texres->tin *= vd->int_multiplier;
- BRICONT;
-
- if (vd->data_type == TEX_VD_RGBA_PREMUL) {
- /* unmultiply */
- if (a>0.001f) {
- texres->tr /= a;
- texres->tg /= a;
- texres->tb /= a;
- }
- texres->talpha = 1;
- }
- else {
- texres->tr = texres->tin;
- texres->tg = texres->tin;
- texres->tb = texres->tin;
- }
-
- texres->ta = texres->tin;
- BRICONTRGB;
-
- return retval;
-}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 6c11dee5dde..436ee590f5c 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -34,40 +34,11 @@
/* Common includes */
/*---------------------------------------------------------------------------*/
-#include <math.h>
-#include <float.h>
-#include <stdlib.h>
-#include <limits.h>
#include <string.h>
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_jitter_2d.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
#include "MEM_guardedalloc.h"
-#include "DNA_lamp_types.h"
-#include "DNA_node_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_material_types.h"
-
-#include "BKE_global.h"
-#include "BKE_material.h"
-
-
-#include "RE_render_ext.h"
-
-/* local includes */
-#include "pixelblending.h"
-#include "render_result.h"
-#include "render_types.h"
-#include "renderdatabase.h"
-#include "rendercore.h"
-#include "shadbuf.h"
-#include "shading.h"
-#include "strand.h"
+#include "BLI_math_base.h"
/* own includes */
#include "zbuf.h"
@@ -77,17 +48,10 @@
# pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
-/* only to be used here in this file, it's for speed */
-extern struct Render R;
-/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-
-
/* ****************** Spans ******************************* */
/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */
-void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop)
+void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
{
memset(zspan, 0, sizeof(ZSpan));
@@ -96,8 +60,6 @@ void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop)
zspan->span1= MEM_mallocN(recty*sizeof(float), "zspan");
zspan->span2= MEM_mallocN(recty*sizeof(float), "zspan");
-
- zspan->clipcrop= clipcrop;
}
void zbuf_free_span(ZSpan *zspan)
@@ -200,1312 +162,6 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
/* Functions */
/*-----------------------------------------------------------*/
-void fillrect(int *rect, int x, int y, int val)
-{
- int len, *drect;
-
- len= x*y;
- drect= rect;
- while (len>0) {
- len--;
- *drect= val;
- drect++;
- }
-}
-
-/* based on Liang&Barsky, for clipping of pyramidical volume */
-static short cliptestf(float a, float b, float c, float d, float *u1, float *u2)
-{
- float p= a + b, q= c + d, r;
-
- if (p<0.0f) {
- if (q<p) return 0;
- else if (q<0.0f) {
- r= q/p;
- if (r>*u2) return 0;
- else if (r>*u1) *u1=r;
- }
- }
- else {
- if (p>0.0f) {
- if (q<0.0f) return 0;
- else if (q<p) {
- r= q/p;
- if (r<*u1) return 0;
- else if (r<*u2) *u2=r;
- }
- }
- else if (q<0.0f) return 0;
- }
- return 1;
-}
-
-int testclip(const float v[4])
-{
- float abs4; /* WATCH IT: this function should do the same as cliptestf, otherwise troubles in zbufclip()*/
- short c=0;
-
- /* if we set clip flags, the clipping should be at least larger than epsilon.
- * prevents issues with vertices lying exact on borders */
- abs4= fabsf(v[3]) + FLT_EPSILON;
-
- if ( v[0] < -abs4) c+=1;
- else if ( v[0] > abs4) c+=2;
-
- if ( v[1] > abs4) c+=4;
- else if ( v[1] < -abs4) c+=8;
-
- if (v[2] < -abs4) c+=16; /* this used to be " if (v[2]<0) ", see clippz() */
- else if (v[2]> abs4) c+= 32;
-
- return c;
-}
-
-
-
-/* ************* ACCUMULATION ZBUF ************ */
-
-
-static APixstr *addpsmainA(ListBase *lb)
-{
- APixstrMain *psm;
-
- psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA");
- BLI_addtail(lb, psm);
- psm->ps= MEM_callocN(4096*sizeof(APixstr), "pixstr");
-
- return psm->ps;
-}
-
-void freepsA(ListBase *lb)
-{
- APixstrMain *psm, *psmnext;
-
- for (psm= lb->first; psm; psm= psmnext) {
- psmnext= psm->next;
- if (psm->ps)
- MEM_freeN(psm->ps);
- MEM_freeN(psm);
- }
-}
-
-static APixstr *addpsA(ZSpan *zspan)
-{
- /* make new PS */
- if (zspan->apsmcounter==0) {
- zspan->curpstr= addpsmainA(zspan->apsmbase);
- zspan->apsmcounter= 4095;
- }
- else {
- zspan->curpstr++;
- zspan->apsmcounter--;
- }
- return zspan->curpstr;
-}
-
-static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- APixstr *ap, *apofs, *apn;
- double zxd, zyd, zy0, zverg;
- float x0, y0, z0;
- float x1, y1, z1, x2, y2, z2, xx1;
- const float *span1, *span2;
- int *rz, *rm, x, y;
- int sn1, sn2, rectx, *rectzofs, *rectmaskofs, my0, my2, mask;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- if (my2<my0) return;
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
-
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* start-offset in rect */
- rectx= zspan->rectx;
- rectzofs= (int *)(zspan->arectz+rectx*(my2));
- rectmaskofs= (int *)(zspan->rectmask+rectx*(my2));
- apofs= (zspan->apixbuf+ rectx*(my2));
- mask= zspan->mask;
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- if (sn2>=sn1) {
- int intzverg;
-
- zverg= (double)sn1*zxd + zy0;
- rz= rectzofs+sn1;
- rm= rectmaskofs+sn1;
- ap= apofs+sn1;
- x= sn2-sn1;
-
- zverg-= zspan->polygon_offset;
-
- while (x>=0) {
- intzverg = round_db_to_int_clamp(zverg);
-
- if ( intzverg < *rz) {
- if (!zspan->rectmask || intzverg > *rm) {
-
- apn= ap;
- while (apn) {
- if (apn->p[0]==0) {apn->obi[0]= obi; apn->p[0]= zvlnr; apn->z[0]= intzverg; apn->mask[0]= mask; break; }
- if (apn->p[0]==zvlnr && apn->obi[0]==obi) {apn->mask[0]|= mask; break; }
- if (apn->p[1]==0) {apn->obi[1]= obi; apn->p[1]= zvlnr; apn->z[1]= intzverg; apn->mask[1]= mask; break; }
- if (apn->p[1]==zvlnr && apn->obi[1]==obi) {apn->mask[1]|= mask; break; }
- if (apn->p[2]==0) {apn->obi[2]= obi; apn->p[2]= zvlnr; apn->z[2]= intzverg; apn->mask[2]= mask; break; }
- if (apn->p[2]==zvlnr && apn->obi[2]==obi) {apn->mask[2]|= mask; break; }
- if (apn->p[3]==0) {apn->obi[3]= obi; apn->p[3]= zvlnr; apn->z[3]= intzverg; apn->mask[3]= mask; break; }
- if (apn->p[3]==zvlnr && apn->obi[3]==obi) {apn->mask[3]|= mask; break; }
- if (apn->next==NULL) apn->next= addpsA(zspan);
- apn= apn->next;
- }
- }
- }
- zverg+= zxd;
- rz++;
- rm++;
- ap++;
- x--;
- }
- }
-
- zy0-=zyd;
- rectzofs-= rectx;
- rectmaskofs-= rectx;
- apofs-= rectx;
- }
-}
-
-
-
-static void zbuflineAc(ZSpan *zspan, int obi, int zvlnr, const float vec1[3], const float vec2[3])
-{
- APixstr *ap, *apn;
- const int *rectz, *rectmask;
- int start, end, x, y, oldx, oldy, ofs;
- int dz, vergz, mask, maxtest=0;
- float dx, dy;
- float v1[3], v2[3];
-
- dx= vec2[0]-vec1[0];
- dy= vec2[1]-vec1[1];
-
- mask= zspan->mask;
-
- if (fabsf(dx) > fabsf(dy)) {
-
- /* all lines from left to right */
- if (vec1[0]<vec2[0]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[0]);
- end= start+floor(dx);
- if (end>=zspan->rectx) end= zspan->rectx-1;
-
- oldy= floor(v1[1]);
- dy/= dx;
-
- vergz= v1[2];
- vergz-= zspan->polygon_offset;
- dz= (v2[2]-v1[2])/dx;
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= (int *)(zspan->arectz+zspan->rectx*(oldy) +start);
- rectmask= (int *)(zspan->rectmask+zspan->rectx*(oldy) +start);
- ap= (zspan->apixbuf+ zspan->rectx*(oldy) +start);
-
- if (dy<0) ofs= -zspan->rectx;
- else ofs= zspan->rectx;
-
- for (x= start; x<=end; x++, rectz++, rectmask++, ap++) {
-
- y= floor(v1[1]);
- if (y!=oldy) {
- oldy= y;
- rectz+= ofs;
- rectmask+= ofs;
- ap+= ofs;
- }
-
- if (x>=0 && y>=0 && y<zspan->recty) {
- if (vergz<*rectz) {
- if (!zspan->rectmask || vergz>*rectmask) {
-
- apn= ap;
- while (apn) { /* loop unrolled */
- if (apn->p[0]==0) {apn->obi[0]= obi; apn->p[0]= zvlnr; apn->z[0]= vergz; apn->mask[0]= mask; break; }
- if (apn->p[0]==zvlnr && apn->obi[0]==obi) {apn->mask[0]|= mask; break; }
- if (apn->p[1]==0) {apn->obi[1]= obi; apn->p[1]= zvlnr; apn->z[1]= vergz; apn->mask[1]= mask; break; }
- if (apn->p[1]==zvlnr && apn->obi[1]==obi) {apn->mask[1]|= mask; break; }
- if (apn->p[2]==0) {apn->obi[2]= obi; apn->p[2]= zvlnr; apn->z[2]= vergz; apn->mask[2]= mask; break; }
- if (apn->p[2]==zvlnr && apn->obi[2]==obi) {apn->mask[2]|= mask; break; }
- if (apn->p[3]==0) {apn->obi[3]= obi; apn->p[3]= zvlnr; apn->z[3]= vergz; apn->mask[3]= mask; break; }
- if (apn->p[3]==zvlnr && apn->obi[3]==obi) {apn->mask[3]|= mask; break; }
- if (apn->next == NULL) apn->next = addpsA(zspan);
- apn= apn->next;
- }
- }
- }
- }
-
- v1[1]+= dy;
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
- }
- }
- else {
-
- /* all lines from top to bottom */
- if (vec1[1]<vec2[1]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[1]);
- end= start+floor(dy);
-
- if (start>=zspan->recty || end<0) return;
-
- if (end>=zspan->recty) end= zspan->recty-1;
-
- oldx= floor(v1[0]);
- dx/= dy;
-
- vergz= v1[2];
- vergz-= zspan->polygon_offset;
- dz= (v2[2]-v1[2])/dy;
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= (int *)( zspan->arectz+ (start)*zspan->rectx+ oldx );
- rectmask= (int *)( zspan->rectmask+ (start)*zspan->rectx+ oldx );
- ap= (zspan->apixbuf+ zspan->rectx*(start) +oldx);
-
- if (dx<0) ofs= -1;
- else ofs= 1;
-
- for (y= start; y<=end; y++, rectz+=zspan->rectx, rectmask+=zspan->rectx, ap+=zspan->rectx) {
-
- x= floor(v1[0]);
- if (x!=oldx) {
- oldx= x;
- rectz+= ofs;
- rectmask+= ofs;
- ap+= ofs;
- }
-
- if (x>=0 && y>=0 && x<zspan->rectx) {
- if (vergz<*rectz) {
- if (!zspan->rectmask || vergz>*rectmask) {
-
- apn= ap;
- while (apn) { /* loop unrolled */
- if (apn->p[0]==0) {apn->obi[0]= obi; apn->p[0]= zvlnr; apn->z[0]= vergz; apn->mask[0]= mask; break; }
- if (apn->p[0]==zvlnr) {apn->mask[0]|= mask; break; }
- if (apn->p[1]==0) {apn->obi[1]= obi; apn->p[1]= zvlnr; apn->z[1]= vergz; apn->mask[1]= mask; break; }
- if (apn->p[1]==zvlnr) {apn->mask[1]|= mask; break; }
- if (apn->p[2]==0) {apn->obi[2]= obi; apn->p[2]= zvlnr; apn->z[2]= vergz; apn->mask[2]= mask; break; }
- if (apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; }
- if (apn->p[3]==0) {apn->obi[3]= obi; apn->p[3]= zvlnr; apn->z[3]= vergz; apn->mask[3]= mask; break; }
- if (apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; }
- if (apn->next == NULL) apn->next = addpsA(zspan);
- apn= apn->next;
- }
- }
- }
- }
-
- v1[0]+= dx;
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
- }
- }
-}
-
-/* ************* NORMAL ZBUFFER ************ */
-
-static void zbufline(ZSpan *zspan, int obi, int zvlnr, const float vec1[3], const float vec2[3])
-{
- int *rectz, *rectp, *recto, *rectmask;
- int start, end, x, y, oldx, oldy, ofs;
- int dz, vergz, maxtest= 0;
- float dx, dy;
- float v1[3], v2[3];
-
- dx= vec2[0]-vec1[0];
- dy= vec2[1]-vec1[1];
-
- if (fabsf(dx) > fabsf(dy)) {
-
- /* all lines from left to right */
- if (vec1[0]<vec2[0]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[0]);
- end= start+floor(dx);
- if (end>=zspan->rectx) end= zspan->rectx-1;
-
- oldy= floor(v1[1]);
- dy/= dx;
-
- vergz= floor(v1[2]);
- dz= floor((v2[2]-v1[2])/dx);
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= zspan->rectz + oldy*zspan->rectx+ start;
- rectp= zspan->rectp + oldy*zspan->rectx+ start;
- recto= zspan->recto + oldy*zspan->rectx+ start;
- rectmask= zspan->rectmask + oldy*zspan->rectx+ start;
-
- if (dy<0) ofs= -zspan->rectx;
- else ofs= zspan->rectx;
-
- for (x= start; x<=end; x++, rectz++, rectp++, recto++, rectmask++) {
-
- y= floor(v1[1]);
- if (y!=oldy) {
- oldy= y;
- rectz+= ofs;
- rectp+= ofs;
- recto+= ofs;
- rectmask+= ofs;
- }
-
- if (x>=0 && y>=0 && y<zspan->recty) {
- if (vergz<*rectz) {
- if (!zspan->rectmask || vergz>*rectmask) {
- *recto= obi;
- *rectz= vergz;
- *rectp= zvlnr;
- }
- }
- }
-
- v1[1]+= dy;
-
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
- }
- }
- else {
- /* all lines from top to bottom */
- if (vec1[1]<vec2[1]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[1]);
- end= start+floor(dy);
-
- if (end>=zspan->recty) end= zspan->recty-1;
-
- oldx= floor(v1[0]);
- dx/= dy;
-
- vergz= floor(v1[2]);
- dz= floor((v2[2]-v1[2])/dy);
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= zspan->rectz + start*zspan->rectx+ oldx;
- rectp= zspan->rectp + start*zspan->rectx+ oldx;
- recto= zspan->recto + start*zspan->rectx+ oldx;
- rectmask= zspan->rectmask + start*zspan->rectx+ oldx;
-
- if (dx<0) ofs= -1;
- else ofs= 1;
-
- for (y= start; y<=end; y++, rectz+=zspan->rectx, rectp+=zspan->rectx, recto+=zspan->rectx, rectmask+=zspan->rectx) {
-
- x= floor(v1[0]);
- if (x!=oldx) {
- oldx= x;
- rectz+= ofs;
- rectp+= ofs;
- recto+= ofs;
- rectmask+= ofs;
- }
-
- if (x>=0 && y>=0 && x<zspan->rectx) {
- if (vergz<*rectz) {
- if (!zspan->rectmask || vergz>*rectmask) {
- *rectz= vergz;
- *rectp= zvlnr;
- *recto= obi;
- }
- }
- }
-
- v1[0]+= dx;
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
- }
- }
-}
-
-static void zbufline_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr), const float vec1[3], const float vec2[3])
-{
- int *rectz, *rectz1= NULL;
- int start, end, x, y, oldx, oldy, ofs;
- int dz, vergz, maxtest= 0;
- float dx, dy;
- float v1[3], v2[3];
-
- dx= vec2[0]-vec1[0];
- dy= vec2[1]-vec1[1];
-
- if (fabsf(dx) > fabsf(dy)) {
-
- /* all lines from left to right */
- if (vec1[0]<vec2[0]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[0]);
- end= start+floor(dx);
- if (end>=zspan->rectx) end= zspan->rectx-1;
-
- oldy= floor(v1[1]);
- dy/= dx;
-
- vergz= floor(v1[2]);
- dz= floor((v2[2]-v1[2])/dx);
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= zspan->rectz + oldy*zspan->rectx+ start;
- if (zspan->rectz1)
- rectz1= zspan->rectz1 + oldy*zspan->rectx+ start;
-
- if (dy<0) ofs= -zspan->rectx;
- else ofs= zspan->rectx;
-
- for (x= start; x<=end; x++, rectz++) {
-
- y= floor(v1[1]);
- if (y!=oldy) {
- oldy= y;
- rectz+= ofs;
- if (rectz1) rectz1+= ofs;
- }
-
- if (x>=0 && y>=0 && y<zspan->recty) {
- if (vergz < *rectz) {
- if (rectz1) *rectz1= *rectz;
- *rectz= vergz;
- }
- else if (rectz1 && vergz < *rectz1)
- *rectz1= vergz;
- }
-
- v1[1]+= dy;
-
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
-
- if (rectz1) rectz1++;
- }
- }
- else {
- /* all lines from top to bottom */
- if (vec1[1]<vec2[1]) {
- copy_v3_v3(v1, vec1);
- copy_v3_v3(v2, vec2);
- }
- else {
- copy_v3_v3(v2, vec1);
- copy_v3_v3(v1, vec2);
- dx= -dx; dy= -dy;
- }
-
- start= floor(v1[1]);
- end= start+floor(dy);
-
- if (end>=zspan->recty) end= zspan->recty-1;
-
- oldx= floor(v1[0]);
- dx/= dy;
-
- vergz= floor(v1[2]);
- dz= floor((v2[2]-v1[2])/dy);
- if (vergz>0x50000000 && dz>0) maxtest= 1; /* prevent overflow */
-
- rectz= zspan->rectz + start*zspan->rectx+ oldx;
- if (zspan->rectz1)
- rectz1= zspan->rectz1 + start*zspan->rectx+ oldx;
-
- if (dx<0) ofs= -1;
- else ofs= 1;
-
- for (y= start; y<=end; y++, rectz+=zspan->rectx) {
-
- x= floor(v1[0]);
- if (x!=oldx) {
- oldx= x;
- rectz+= ofs;
- if (rectz1) rectz1+= ofs;
- }
-
- if (x>=0 && y>=0 && x<zspan->rectx) {
- if (vergz < *rectz) {
- if (rectz1) *rectz1= *rectz;
- *rectz= vergz;
- }
- else if (rectz1 && vergz < *rectz1)
- *rectz1= vergz;
- }
-
- v1[0]+= dx;
- if (maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
- else vergz+= dz;
-
- if (rectz1)
- rectz1+=zspan->rectx;
- }
- }
-}
-
-
-static int clipline(float v1[4], float v2[4]) /* return 0: do not draw */
-{
- float dz, dw, u1=0.0, u2=1.0;
- float dx, dy, v13;
-
- dz= v2[2]-v1[2];
- dw= v2[3]-v1[3];
-
- /* this 1.01 is for clipping x and y just a tinsy larger. that way it is
- * filled in with zbufwire correctly when rendering in parts. otherwise
- * you see line endings at edges... */
-
- if (cliptestf(-dz, -dw, v1[3], v1[2], &u1, &u2)) {
- if (cliptestf(dz, -dw, v1[3], -v1[2], &u1, &u2)) {
-
- dx= v2[0]-v1[0];
- dz= 1.01f*(v2[3]-v1[3]);
- v13= 1.01f*v1[3];
-
- if (cliptestf(-dx, -dz, v1[0], v13, &u1, &u2)) {
- if (cliptestf(dx, -dz, v13, -v1[0], &u1, &u2)) {
-
- dy= v2[1]-v1[1];
-
- if (cliptestf(-dy, -dz, v1[1], v13, &u1, &u2)) {
- if (cliptestf(dy, -dz, v13, -v1[1], &u1, &u2)) {
-
- if (u2<1.0f) {
- v2[0]= v1[0]+u2*dx;
- v2[1]= v1[1]+u2*dy;
- v2[2]= v1[2]+u2*dz;
- v2[3]= v1[3]+u2*dw;
- }
- if (u1>0.0f) {
- v1[0]= v1[0]+u1*dx;
- v1[1]= v1[1]+u1*dy;
- v1[2]= v1[2]+u1*dz;
- v1[3]= v1[3]+u1*dw;
- }
- return 1;
- }
- }
- }
- }
- }
- }
-
- return 0;
-}
-
-void hoco_to_zco(ZSpan *zspan, float zco[3], const float hoco[4])
-{
- float div;
-
- div= 1.0f/hoco[3];
- zco[0]= zspan->zmulx*(1.0f+hoco[0]*div) + zspan->zofsx;
- zco[1]= zspan->zmuly*(1.0f+hoco[1]*div) + zspan->zofsy;
- zco[2]= 0x7FFFFFFF *(hoco[2]*div);
-}
-
-void zbufclipwire(ZSpan *zspan, int obi, int zvlnr, int ec,
- const float ho1[4], const float ho2[4], const float ho3[4], const float ho4[4],
- const int c1, const int c2, const int c3, const int c4)
-{
- float vez[20];
- int and, or;
-
- /* edgecode: 1= draw */
- if (ec==0) return;
-
- if (ho4) {
- and= (c1 & c2 & c3 & c4);
- or= (c1 | c2 | c3 | c4);
- }
- else {
- and= (c1 & c2 & c3);
- or= (c1 | c2 | c3);
- }
-
- if (or) { /* not in the middle */
- if (and) { /* out completely */
- return;
- }
- else { /* clipping */
-
- if (ec & ME_V1V2) {
- copy_v4_v4(vez, ho1);
- copy_v4_v4(vez+4, ho2);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- if (ec & ME_V2V3) {
- copy_v4_v4(vez, ho2);
- copy_v4_v4(vez+4, ho3);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- if (ho4) {
- if (ec & ME_V3V4) {
- copy_v4_v4(vez, ho3);
- copy_v4_v4(vez+4, ho4);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- if (ec & ME_V4V1) {
- copy_v4_v4(vez, ho4);
- copy_v4_v4(vez+4, ho1);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- }
- else {
- if (ec & ME_V3V1) {
- copy_v4_v4(vez, ho3);
- copy_v4_v4(vez+4, ho1);
- if ( clipline(vez, vez+4)) {
- hoco_to_zco(zspan, vez, vez);
- hoco_to_zco(zspan, vez+4, vez+4);
- zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- }
- }
- }
-
- return;
- }
- }
-
- hoco_to_zco(zspan, vez, ho1);
- hoco_to_zco(zspan, vez+4, ho2);
- hoco_to_zco(zspan, vez+8, ho3);
- if (ho4) {
- hoco_to_zco(zspan, vez+12, ho4);
-
- if (ec & ME_V3V4) zspan->zbuflinefunc(zspan, obi, zvlnr, vez+8, vez+12);
- if (ec & ME_V4V1) zspan->zbuflinefunc(zspan, obi, zvlnr, vez+12, vez);
- }
- else {
- if (ec & ME_V3V1) zspan->zbuflinefunc(zspan, obi, zvlnr, vez+8, vez);
- }
-
- if (ec & ME_V1V2) zspan->zbuflinefunc(zspan, obi, zvlnr, vez, vez+4);
- if (ec & ME_V2V3) zspan->zbuflinefunc(zspan, obi, zvlnr, vez+4, vez+8);
-
-}
-
-void zbufsinglewire(ZSpan *zspan, int obi, int zvlnr, const float ho1[4], const float ho2[4])
-{
- float f1[4], f2[4];
- int c1, c2;
-
- c1= testclip(ho1);
- c2= testclip(ho2);
-
- if (c1 | c2) { /* not in the middle */
- if (!(c1 & c2)) { /* not out completely */
- copy_v4_v4(f1, ho1);
- copy_v4_v4(f2, ho2);
-
- if (clipline(f1, f2)) {
- hoco_to_zco(zspan, f1, f1);
- hoco_to_zco(zspan, f2, f2);
- zspan->zbuflinefunc(zspan, obi, zvlnr, f1, f2);
- }
- }
- }
- else {
- hoco_to_zco(zspan, f1, ho1);
- hoco_to_zco(zspan, f2, ho2);
-
- zspan->zbuflinefunc(zspan, obi, zvlnr, f1, f2);
- }
-}
-
-/**
- * Fill the z buffer, but invert z order, and add the face index to
- * the corresponding face buffer.
- *
- * This is one of the z buffer fill functions called in zbufclip() and
- * zbufwireclip().
- *
- * \param v1 [4 floats, world coordinates] first vertex
- * \param v2 [4 floats, world coordinates] second vertex
- * \param v3 [4 floats, world coordinates] third vertex
- */
-
-/* WATCH IT: zbuffillGLinv4 and zbuffillGL4 are identical except for a 2 lines,
- * commented below */
-static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- double zxd, zyd, zy0, zverg;
- float x0, y0, z0;
- float x1, y1, z1, x2, y2, z2, xx1;
- const float *span1, *span2;
- int *rectoofs, *ro;
- int *rectpofs, *rp;
- const int *rectmaskofs, *rm;
- int *rz, x, y;
- int sn1, sn2, rectx, *rectzofs, my0, my2;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- // printf("my %d %d\n", my0, my2);
- if (my2<my0) return;
-
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
-
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* start-offset in rect */
- rectx= zspan->rectx;
- rectzofs= (zspan->rectz+rectx*my2);
- rectpofs= (zspan->rectp+rectx*my2);
- rectoofs= (zspan->recto+rectx*my2);
- rectmaskofs= (zspan->rectmask+rectx*my2);
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- if (sn2>=sn1) {
- int intzverg;
-
- zverg= (double)sn1*zxd + zy0;
- rz= rectzofs+sn1;
- rp= rectpofs+sn1;
- ro= rectoofs+sn1;
- rm= rectmaskofs+sn1;
- x= sn2-sn1;
-
- while (x>=0) {
- intzverg = round_db_to_int_clamp(zverg);
-
- if ( intzverg > *rz || *rz==0x7FFFFFFF) { /* UNIQUE LINE: see comment above */
- if (!zspan->rectmask || intzverg > *rm) {
- *ro= obi; /* UNIQUE LINE: see comment above (order differs) */
- *rz= intzverg;
- *rp= zvlnr;
- }
- }
- zverg+= zxd;
- rz++;
- rp++;
- ro++;
- rm++;
- x--;
- }
- }
-
- zy0-=zyd;
- rectzofs-= rectx;
- rectpofs-= rectx;
- rectoofs-= rectx;
- rectmaskofs-= rectx;
- }
-}
-
-/* uses spanbuffers */
-
-/* WATCH IT: zbuffillGLinv4 and zbuffillGL4 are identical except for a 2 lines,
- * commented below */
-static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- double zxd, zyd, zy0, zverg;
- float x0, y0, z0;
- float x1, y1, z1, x2, y2, z2, xx1;
- const float *span1, *span2;
- int *rectoofs, *ro;
- int *rectpofs, *rp;
- const int *rectmaskofs, *rm;
- int *rz, x, y;
- int sn1, sn2, rectx, *rectzofs, my0, my2;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- // printf("my %d %d\n", my0, my2);
- if (my2<my0) return;
-
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
-
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* start-offset in rect */
- rectx= zspan->rectx;
- rectzofs= (zspan->rectz+rectx*my2);
- rectpofs= (zspan->rectp+rectx*my2);
- rectoofs= (zspan->recto+rectx*my2);
- rectmaskofs= (zspan->rectmask+rectx*my2);
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- if (sn2>=sn1) {
- int intzverg;
-
- zverg= (double)sn1*zxd + zy0;
- rz= rectzofs+sn1;
- rp= rectpofs+sn1;
- ro= rectoofs+sn1;
- rm= rectmaskofs+sn1;
- x= sn2-sn1;
-
- while (x>=0) {
- intzverg = round_db_to_int_clamp(zverg);
-
- if (intzverg < *rz) { /* ONLY UNIQUE LINE: see comment above */
- if (!zspan->rectmask || intzverg > *rm) {
- *rz= intzverg;
- *rp= zvlnr;
- *ro= obi; /* UNIQUE LINE: see comment above (order differs) */
- }
- }
- zverg+= zxd;
- rz++;
- rp++;
- ro++;
- rm++;
- x--;
- }
- }
-
- zy0-=zyd;
- rectzofs-= rectx;
- rectpofs-= rectx;
- rectoofs-= rectx;
- rectmaskofs-= rectx;
- }
-}
-
-/**
- * Fill the z buffer. The face buffer is not operated on!
- *
- * This is one of the z buffer fill functions called in zbufclip() and
- * zbufwireclip().
- *
- * \param v1 [4 floats, world coordinates] first vertex
- * \param v2 [4 floats, world coordinates] second vertex
- * \param v3 [4 floats, world coordinates] third vertex
- */
-
-/* now: filling two Z values, the closest and 2nd closest */
-static void zbuffillGL_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr),
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- double zxd, zyd, zy0, zverg;
- float x0, y0, z0;
- float x1, y1, z1, x2, y2, z2, xx1;
- const float *span1, *span2;
- int *rz, *rz1, x, y;
- int sn1, sn2, rectx, *rectzofs, *rectzofs1= NULL, my0, my2;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- // printf("my %d %d\n", my0, my2);
- if (my2<my0) return;
-
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
-
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* start-offset in rect */
- rectx= zspan->rectx;
- rectzofs= (zspan->rectz+rectx*my2);
- if (zspan->rectz1)
- rectzofs1= (zspan->rectz1+rectx*my2);
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- if (sn2>=sn1) {
- zverg= (double)sn1*zxd + zy0;
- rz= rectzofs+sn1;
- rz1= rectzofs1+sn1;
- x= sn2-sn1;
-
- while (x>=0) {
- int zvergi = round_db_to_int_clamp(zverg);
-
- /* option: maintain two depth values, closest and 2nd closest */
- if (zvergi < *rz) {
- if (rectzofs1) *rz1= *rz;
- *rz= zvergi;
- }
- else if (rectzofs1 && zvergi < *rz1)
- *rz1= zvergi;
-
- zverg+= zxd;
-
- rz++;
- rz1++;
- x--;
- }
- }
-
- zy0-=zyd;
- rectzofs-= rectx;
- if (rectzofs1) rectzofs1-= rectx;
- }
-}
-
-/* 2d scanconvert for tria, calls func for each x, y coordinate and gives UV barycentrics */
-void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) )
-{
- float x0, y0, x1, y1, x2, y2, z0, z1, z2, z;
- float u, v, uxd, uyd, vxd, vyd, uy0, vy0, zxd, zyd, zy0, xx1;
- const float *span1, *span2;
- int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
-
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- // printf("my %d %d\n", my0, my2);
- if (my2<my0) return;
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
-
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- z1= 1.0f; /* (u1 - u2) */
- z2= 0.0f; /* (u2 - u3) */
-
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + 1.0f;
- uxd= -(double)x0/(double)z0;
- uyd= -(double)y0/(double)z0;
- uy0= ((double)my2)*uyd + (double)xx1;
-
- z1= -1.0f; /* (v1 - v2) */
- z2= 1.0f; /* (v2 - v3) */
-
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0;
- vxd= -(double)x0/(double)z0;
- vyd= -(double)y0/(double)z0;
- vy0= ((double)my2)*vyd + (double)xx1;
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
-
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- u= (double)sn1*uxd + uy0;
- v= (double)sn1*vxd + vy0;
- z= (double)sn1*zxd + zy0;
-
- for (x= sn1; x<=sn2; x++, u+=uxd, v+=vxd, z+=zxd)
- func(handle, x, y, u, v, z);
-
- uy0 -= uyd;
- vy0 -= vyd;
- zy0 -= zyd;
- }
-}
-
/* scanconvert for strand triangles, calls func for each x, y coordinate and gives UV barycentrics and z */
void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float) )
@@ -1585,2154 +241,4 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
}
}
-
-
-/**
- * (clip pyramid)
- * Sets lambda: flag, and parametrize the clipping of vertices in
- * viewspace coordinates. lambda = -1 means no clipping, lambda in [0, 1] means a clipping.
- * Note: uses globals.
- * \param v1 start coordinate s
- * \param v2 target coordinate t
- * \param b2
- * \param b3
- * \param a index for coordinate (x, y, or z)
- */
-
-static void clippyra(float *lambda, float *v1, float *v2, int *b2, int *b3, int a, float clipcrop)
-{
- float da, dw, u1=0.0, u2=1.0;
- float v13;
-
- lambda[0]= -1.0;
- lambda[1]= -1.0;
-
- da= v2[a]-v1[a];
- /* prob; we clip slightly larger, osa renders add 2 pixels on edges, should become variable? */
- /* or better; increase r.winx/y size, but thats quite a complex one. do it later */
- if (a==2) {
- dw= (v2[3]-v1[3]);
- v13= v1[3];
- }
- else {
- dw= clipcrop*(v2[3]-v1[3]);
- v13= clipcrop*v1[3];
- }
- /* according the original article by Liang&Barsky, for clipping of
- * homogeneous coordinates with viewplane, the value of "0" is used instead of "-w" .
- * This differs from the other clipping cases (like left or top) and I considered
- * it to be not so 'homogenic'. But later it has proven to be an error,
- * who would have thought that of L&B!
- */
-
- if (cliptestf(-da, -dw, v13, v1[a], &u1, &u2)) {
- if (cliptestf(da, -dw, v13, -v1[a], &u1, &u2)) {
- *b3=1;
- if (u2<1.0f) {
- lambda[1]= u2;
- *b2=1;
- }
- else lambda[1]=1.0; /* u2 */
- if (u1>0.0f) {
- lambda[0] = u1;
- *b2 = 1;
- }
- else {
- lambda[0] = 0.0;
- }
- }
- }
-}
-
-/**
- * (make vertex pyramide clip)
- * Checks lambda and uses this to make decision about clipping the line
- * segment from v1 to v2. lambda is the factor by which the vector is
- * cut. ( calculate s + l * ( t - s )). The result is appended to the
- * vertex list of this face.
- *
- *
- * \param v1 start coordinate s
- * \param v2 target coordinate t
- * \param b1
- * \param b2
- * \param clve vertex vector.
- */
-
-static void makevertpyra(float *vez, float *lambda, float **trias, float *v1, float *v2, int *b1, int *clve)
-{
- float l1, l2, *adr;
-
- l1= lambda[0];
- l2= lambda[1];
-
- if (l1!= -1.0f) {
- if (l1!= 0.0f) {
- adr= vez+4*(*clve);
- trias[*b1]=adr;
- (*clve)++;
- adr[0]= v1[0]+l1*(v2[0]-v1[0]);
- adr[1]= v1[1]+l1*(v2[1]-v1[1]);
- adr[2]= v1[2]+l1*(v2[2]-v1[2]);
- adr[3]= v1[3]+l1*(v2[3]-v1[3]);
- }
- else trias[*b1]= v1;
-
- (*b1)++;
- }
- if (l2!= -1.0f) {
- if (l2!= 1.0f) {
- adr= vez+4*(*clve);
- trias[*b1]=adr;
- (*clve)++;
- adr[0]= v1[0]+l2*(v2[0]-v1[0]);
- adr[1]= v1[1]+l2*(v2[1]-v1[1]);
- adr[2]= v1[2]+l2*(v2[2]-v1[2]);
- adr[3]= v1[3]+l2*(v2[3]-v1[3]);
- (*b1)++;
- }
- }
-}
-
-/* ------------------------------------------------------------------------- */
-
-void projectverto(const float v1[3], float winmat[4][4], float adr[4])
-{
- /* calcs homogenic coord of vertex v1 */
- float x, y, z;
-
- x = v1[0];
- y = v1[1];
- z = v1[2];
- adr[0] = x * winmat[0][0] + z * winmat[2][0] + winmat[3][0];
- adr[1] = y * winmat[1][1] + z * winmat[2][1] + winmat[3][1];
- adr[2] = z * winmat[2][2] + winmat[3][2];
- adr[3] = z * winmat[2][3] + winmat[3][3];
-
- //printf("hoco %f %f %f %f\n", adr[0], adr[1], adr[2], adr[3]);
-}
-
-/* ------------------------------------------------------------------------- */
-
-void projectvert(const float v1[3], float winmat[4][4], float adr[4])
-{
- /* calcs homogenic coord of vertex v1 */
- float x, y, z;
-
- x = v1[0];
- y = v1[1];
- z = v1[2];
- adr[0] = x * winmat[0][0] + y * winmat[1][0] + z * winmat[2][0] + winmat[3][0];
- adr[1] = x * winmat[0][1] + y * winmat[1][1] + z * winmat[2][1] + winmat[3][1];
- adr[2] = x * winmat[0][2] + y * winmat[1][2] + z * winmat[2][2] + winmat[3][2];
- adr[3] = x * winmat[0][3] + y * winmat[1][3] + z * winmat[2][3] + winmat[3][3];
-}
-
-/* ------------------------------------------------------------------------- */
-
-#define ZBUF_PROJECT_CACHE_SIZE 256
-
-typedef struct ZbufProjectCache {
- int index, clip;
- float ho[4];
-} ZbufProjectCache;
-
-static void zbuf_project_cache_clear(ZbufProjectCache *cache, int size)
-{
- int i;
-
- if (size > ZBUF_PROJECT_CACHE_SIZE)
- size= ZBUF_PROJECT_CACHE_SIZE;
-
- memset(cache, 0, sizeof(ZbufProjectCache)*size);
- for (i=0; i<size; i++)
- cache[i].index= -1;
-}
-
-static int zbuf_shadow_project(ZbufProjectCache *cache, int index, float winmat[4][4], float *co, float *ho)
-{
- int cindex= index & 255;
-
- if (cache[cindex].index == index) {
- copy_v4_v4(ho, cache[cindex].ho);
- return cache[cindex].clip;
- }
- else {
- int clipflag;
- projectvert(co, winmat, ho);
- clipflag= testclip(ho);
-
- copy_v4_v4(cache[cindex].ho, ho);
- cache[cindex].clip= clipflag;
- cache[cindex].index= index;
-
- return clipflag;
- }
-}
-
-static void zbuffer_part_bounds(int winx, int winy, RenderPart *pa, float *bounds)
-{
- bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx;
- bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx;
- bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy;
- bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy;
-}
-
-static int zbuf_part_project(ZbufProjectCache *cache, int index, float winmat[4][4], float *bounds, float *co, float *ho)
-{
- float vec[3];
- int cindex= index & 255;
-
- if (cache[cindex].index == index) {
- copy_v4_v4(ho, cache[cindex].ho);
- return cache[cindex].clip;
- }
- else {
- float wco;
- int clipflag= 0;
- copy_v3_v3(vec, co);
- projectvert(co, winmat, ho);
-
- wco= ho[3];
- if (ho[0] < bounds[0]*wco) clipflag |= 1;
- else if (ho[0] > bounds[1]*wco) clipflag |= 2;
- if (ho[1] > bounds[3]*wco) clipflag |= 4;
- else if (ho[1] < bounds[2]*wco) clipflag |= 8;
-
- copy_v4_v4(cache[cindex].ho, ho);
- cache[cindex].clip= clipflag;
- cache[cindex].index= index;
-
- return clipflag;
- }
-}
-
-void zbuf_render_project(float winmat[4][4], const float co[3], float ho[4])
-{
- float vec[3];
-
- copy_v3_v3(vec, co);
- projectvert(vec, winmat, ho);
-}
-
-void zbuf_make_winmat(Render *re, float winmat[4][4])
-{
- if (re->r.mode & R_PANORAMA) {
- float panomat[4][4];
-
- unit_m4(panomat);
-
- panomat[0][0]= re->panoco;
- panomat[0][2]= re->panosi;
- panomat[2][0]= -re->panosi;
- panomat[2][2]= re->panoco;
-
- mul_m4_m4m4(winmat, re->winmat, panomat);
- }
- else
- copy_m4_m4(winmat, re->winmat);
-}
-
-/* do zbuffering and clip, f1 f2 f3 are hocos, c1 c2 c3 are clipping flags */
-
-void zbufclip(ZSpan *zspan, int obi, int zvlnr,
- const float f1[4], const float f2[4], const float f3[4],
- const int c1, const int c2, const int c3)
-{
- float *vlzp[32][3], lambda[3][2];
- float vez[400], *trias[40];
-
- if (c1 | c2 | c3) { /* not in middle */
- if (c1 & c2 & c3) { /* completely out */
- return;
- }
- else { /* clipping */
- int arg, v, b, clipflag[3], b1, b2, b3, c4, clve=3, clvlo, clvl=1;
- float *fp;
-
- vez[0]= f1[0]; vez[1]= f1[1]; vez[2]= f1[2]; vez[3]= f1[3];
- vez[4]= f2[0]; vez[5]= f2[1]; vez[6]= f2[2]; vez[7]= f2[3];
- vez[8]= f3[0]; vez[9]= f3[1]; vez[10]= f3[2];vez[11]= f3[3];
-
- vlzp[0][0]= vez;
- vlzp[0][1]= vez+4;
- vlzp[0][2]= vez+8;
-
- clipflag[0]= ( (c1 & 48) | (c2 & 48) | (c3 & 48) );
- if (clipflag[0]==0) { /* othwerwise it needs to be calculated again, after the first (z) clip */
- clipflag[1]= ( (c1 & 3) | (c2 & 3) | (c3 & 3) );
- clipflag[2]= ( (c1 & 12) | (c2 & 12) | (c3 & 12) );
- }
- else clipflag[1]=clipflag[2]= 0;
-
- for (b=0;b<3;b++) {
-
- if (clipflag[b]) {
-
- clvlo= clvl;
-
- for (v=0; v<clvlo; v++) {
-
- if (vlzp[v][0]!=NULL) { /* face is still there */
- b2= b3 =0; /* clip flags */
-
- if (b==0) arg= 2;
- else if (b==1) arg= 0;
- else arg= 1;
-
- clippyra(lambda[0], vlzp[v][0], vlzp[v][1], &b2, &b3, arg, zspan->clipcrop);
- clippyra(lambda[1], vlzp[v][1], vlzp[v][2], &b2, &b3, arg, zspan->clipcrop);
- clippyra(lambda[2], vlzp[v][2], vlzp[v][0], &b2, &b3, arg, zspan->clipcrop);
-
- if (b2==0 && b3==1) {
- /* completely 'in', but we copy because of last for () loop in this section */;
- vlzp[clvl][0]= vlzp[v][0];
- vlzp[clvl][1]= vlzp[v][1];
- vlzp[clvl][2]= vlzp[v][2];
- vlzp[v][0]= NULL;
- clvl++;
- }
- else if (b3==0) {
- vlzp[v][0]= NULL;
- /* completely 'out' */;
- }
- else {
- b1=0;
- makevertpyra(vez, lambda[0], trias, vlzp[v][0], vlzp[v][1], &b1, &clve);
- makevertpyra(vez, lambda[1], trias, vlzp[v][1], vlzp[v][2], &b1, &clve);
- makevertpyra(vez, lambda[2], trias, vlzp[v][2], vlzp[v][0], &b1, &clve);
-
- /* after front clip done: now set clip flags */
- if (b==0) {
- clipflag[1]= clipflag[2]= 0;
- f1= vez;
- for (b3=0; b3<clve; b3++) {
- c4= testclip(f1);
- clipflag[1] |= (c4 & 3);
- clipflag[2] |= (c4 & 12);
- f1+= 4;
- }
- }
-
- vlzp[v][0]= NULL;
- if (b1>2) {
- for (b3=3; b3<=b1; b3++) {
- vlzp[clvl][0]= trias[0];
- vlzp[clvl][1]= trias[b3-2];
- vlzp[clvl][2]= trias[b3-1];
- clvl++;
- }
- }
- }
- }
- }
- }
- }
-
- /* warning, clip overflow, this should never happen! */
- BLI_assert(!(clve > 38 || clvl > 31));
-
- /* perspective division */
- fp = vez;
- for (b = 0; b < clve; b++) {
- hoco_to_zco(zspan, fp, fp);
- fp += 4;
- }
- for (b = 1; b < clvl; b++) {
- if (vlzp[b][0]) {
- zspan->zbuffunc(zspan, obi, zvlnr, vlzp[b][0], vlzp[b][1], vlzp[b][2], NULL);
- }
- }
- return;
- }
- }
-
- /* perspective division: HCS to ZCS */
- hoco_to_zco(zspan, vez, f1);
- hoco_to_zco(zspan, vez+4, f2);
- hoco_to_zco(zspan, vez+8, f3);
- zspan->zbuffunc(zspan, obi, zvlnr, vez, vez+4, vez+8, NULL);
-}
-
-void zbufclip4(ZSpan *zspan, int obi, int zvlnr,
- const float f1[4], const float f2[4], const float f3[4], const float f4[4],
- const int c1, const int c2, const int c3, const int c4)
-{
- float vez[16];
-
- if (c1 | c2 | c3 | c4) { /* not in middle */
- if (c1 & c2 & c3 & c4) { /* completely out */
- return;
- }
- else { /* clipping */
- zbufclip(zspan, obi, zvlnr, f1, f2, f3, c1, c2, c3);
- zbufclip(zspan, obi, zvlnr, f1, f3, f4, c1, c3, c4);
- }
- return;
- }
-
- /* perspective division: HCS to ZCS */
- hoco_to_zco(zspan, vez, f1);
- hoco_to_zco(zspan, vez+4, f2);
- hoco_to_zco(zspan, vez+8, f3);
- hoco_to_zco(zspan, vez+12, f4);
-
- zspan->zbuffunc(zspan, obi, zvlnr, vez, vez+4, vez+8, vez+12);
-}
-
-/* ************** ZMASK ******************************** */
-
-#define EXTEND_PIXEL(a) if (temprectp[a]) { z += rectz[a]; tot++; } (void)0
-
-/* changes the zbuffer to be ready for z-masking: applies an extend-filter, and then clears */
-static void zmask_rect(int *rectz, int *rectp, int xs, int ys, int neg)
-{
- int len=0, x, y;
- int *temprectp;
- int row1, row2, row3, *curp, *curz;
-
- temprectp= MEM_dupallocN(rectp);
-
- /* extend: if pixel is not filled in, we check surrounding pixels and average z value */
-
- for (y=1; y<=ys; y++) {
- /* setup row indices */
- row1= (y-2)*xs;
- row2= row1 + xs;
- row3= row2 + xs;
- if (y==1)
- row1= row2;
- else if (y==ys)
- row3= row2;
-
- curp= rectp + (y-1)*xs;
- curz= rectz + (y-1)*xs;
-
- for (x=0; x<xs; x++, curp++, curz++) {
- if (curp[0]==0) {
- int tot= 0;
- float z= 0.0f;
-
- EXTEND_PIXEL(row1);
- EXTEND_PIXEL(row2);
- EXTEND_PIXEL(row3);
- EXTEND_PIXEL(row1 + 1);
- EXTEND_PIXEL(row3 + 1);
- if (x!=xs-1) {
- EXTEND_PIXEL(row1 + 2);
- EXTEND_PIXEL(row2 + 2);
- EXTEND_PIXEL(row3 + 2);
- }
- if (tot) {
- len++;
- curz[0]= (int)(z/(float)tot);
- curp[0]= -1; /* env */
- }
- }
-
- if (x!=0) {
- row1++; row2++; row3++;
- }
- }
- }
-
- MEM_freeN(temprectp);
-
- if (neg) {
- /* z values for negative are already correct */
- }
- else {
- /* clear not filled z values */
- for (len= xs*ys -1; len>=0; len--) {
- if (rectp[len]==0) {
- rectz[len] = -0x7FFFFFFF;
- rectp[len]= -1; /* env code */
- }
- }
- }
-}
-
-
-/* ***************** ZBUFFER MAIN ROUTINES **************** */
-
-void zbuffer_solid(RenderPart *pa, RenderLayer *rl, void(*fillfunc)(RenderPart *, ZSpan *, int, void *), void *data)
-{
- ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
- ZSpan zspans[16], *zspan; /* 16 = RE_MAX_OSA */
- VlakRen *vlr= NULL;
- VertRen *v1, *v2, *v3, *v4;
- Material *ma = NULL;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- float obwinmat[4][4], winmat[4][4], bounds[4];
- float ho1[4], ho2[4], ho3[4], ho4[4]={0};
- unsigned int lay= rl->lay, lay_zmask= rl->lay_zmask;
- int i, v, zvlnr, zsample, samples, c1, c2, c3, c4=0;
- short nofill=0, env=0, wire=0, zmaskpass=0;
- const bool all_z = (rl->layflag & SCE_LAY_ALL_Z) && !(rl->layflag & SCE_LAY_ZMASK);
- const bool neg_zmask = (rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK);
-
- zbuf_make_winmat(&R, winmat);
-
- samples= (R.osa? R.osa: 1);
- samples= MIN2(4, samples-pa->sample);
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- zbuffer_part_bounds(R.winx, R.winy, pa, bounds);
- zbuf_alloc_span(zspan, pa->rectx, pa->recty, R.clipcrop);
-
- /* needed for transform from hoco to zbuffer co */
- zspan->zmulx= ((float)R.winx)/2.0f;
- zspan->zmuly= ((float)R.winy)/2.0f;
-
- if (R.osa) {
- zspan->zofsx= -pa->disprect.xmin - R.jit[pa->sample+zsample][0];
- zspan->zofsy= -pa->disprect.ymin - R.jit[pa->sample+zsample][1];
- }
- else if (R.i.curblur) {
- zspan->zofsx= -pa->disprect.xmin - R.mblur_jit[R.i.curblur-1][0];
- zspan->zofsy= -pa->disprect.ymin - R.mblur_jit[R.i.curblur-1][1];
- }
- else {
- zspan->zofsx= -pa->disprect.xmin;
- zspan->zofsy= -pa->disprect.ymin;
- }
- /* to center the sample position */
- zspan->zofsx -= 0.5f;
- zspan->zofsy -= 0.5f;
-
- /* the buffers */
- if (zsample == samples-1) {
- zspan->rectp= pa->rectp;
- zspan->recto= pa->recto;
-
- if (neg_zmask)
- zspan->rectz= pa->rectmask;
- else
- zspan->rectz= pa->rectz;
- }
- else {
- zspan->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
- zspan->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
- zspan->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
- }
-
- fillrect(zspan->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
- fillrect(zspan->rectp, pa->rectx, pa->recty, 0);
- fillrect(zspan->recto, pa->rectx, pa->recty, 0);
- }
-
- /* in case zmask we fill Z for objects in lay_zmask first, then clear Z, and then do normal zbuffering */
- if (rl->layflag & SCE_LAY_ZMASK)
- zmaskpass= 1;
-
- for (; zmaskpass >=0; zmaskpass--) {
- ma= NULL;
-
- /* filling methods */
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- if (zmaskpass && neg_zmask)
- zspan->zbuffunc= zbuffillGLinv4;
- else
- zspan->zbuffunc= zbuffillGL4;
- zspan->zbuflinefunc= zbufline;
- }
-
- /* regular zbuffering loop, does all sample buffers */
- for (i=0, obi=R.instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- /* continue happens in 2 different ways... zmaskpass only does lay_zmask stuff */
- if (zmaskpass) {
- if ((obi->lay & lay_zmask)==0)
- continue;
- }
- else if (!all_z && !(obi->lay & (lay|lay_zmask)))
- continue;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
- continue;
-
- zbuf_project_cache_clear(cache, obr->totvert);
-
- for (v=0; v<obr->totvlak; v++) {
- if ((v & 255)==0) vlr= obr->vlaknodes[v>>8].vlak;
- else vlr++;
-
- /* the cases: visible for render, only z values, zmask, nothing */
- if (obi->lay & lay) {
- if (vlr->mat!=ma) {
- ma= vlr->mat;
- nofill= (ma->mode & MA_ONLYCAST) || ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP));
- env= (ma->mode & MA_ENV);
- wire= (ma->material_type == MA_TYPE_WIRE);
-
- for (zsample=0; zsample<samples; zsample++) {
- if (ma->mode & MA_ZINV || (zmaskpass && neg_zmask))
- zspans[zsample].zbuffunc= zbuffillGLinv4;
- else
- zspans[zsample].zbuffunc= zbuffillGL4;
- }
- }
- }
- else if (all_z || (obi->lay & lay_zmask)) {
- env= 1;
- nofill= 0;
- ma= NULL;
- }
- else {
- nofill= 1;
- ma= NULL; /* otherwise nofill can hang */
- }
-
- if (!(vlr->flag & R_HIDDEN) && nofill==0) {
- unsigned short partclip;
-
- v1= vlr->v1;
- v2= vlr->v2;
- v3= vlr->v3;
- v4= vlr->v4;
-
- c1= zbuf_part_project(cache, v1->index, obwinmat, bounds, v1->co, ho1);
- c2= zbuf_part_project(cache, v2->index, obwinmat, bounds, v2->co, ho2);
- c3= zbuf_part_project(cache, v3->index, obwinmat, bounds, v3->co, ho3);
-
- /* partclipping doesn't need viewplane clipping */
- partclip= c1 & c2 & c3;
- if (v4) {
- c4= zbuf_part_project(cache, v4->index, obwinmat, bounds, v4->co, ho4);
- partclip &= c4;
- }
-
- if (partclip==0) {
-
- if (env) zvlnr= -1;
- else zvlnr= v+1;
-
- c1= testclip(ho1);
- c2= testclip(ho2);
- c3= testclip(ho3);
- if (v4)
- c4= testclip(ho4);
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- if (wire) {
- if (v4)
- zbufclipwire(zspan, i, zvlnr, vlr->ec, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- else
- zbufclipwire(zspan, i, zvlnr, vlr->ec, ho1, ho2, ho3, NULL, c1, c2, c3, 0);
- }
- else {
- /* strands allow to be filled in as quad */
- if (v4 && (vlr->flag & R_STRAND)) {
- zbufclip4(zspan, i, zvlnr, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- }
- else {
- zbufclip(zspan, i, zvlnr, ho1, ho2, ho3, c1, c2, c3);
- if (v4)
- zbufclip(zspan, i, (env)? zvlnr: zvlnr+RE_QUAD_OFFS, ho1, ho3, ho4, c1, c3, c4);
- }
- }
- }
- }
- }
- }
- }
-
- /* clear all z to close value, so it works as mask for next passes (ztra+strand) */
- if (zmaskpass) {
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- if (neg_zmask) {
- zspan->rectmask= zspan->rectz;
- if (zsample == samples-1)
- zspan->rectz= pa->rectz;
- else
- zspan->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
- fillrect(zspan->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
-
- zmask_rect(zspan->rectmask, zspan->rectp, pa->rectx, pa->recty, 1);
- }
- else
- zmask_rect(zspan->rectz, zspan->rectp, pa->rectx, pa->recty, 0);
- }
- }
- }
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- if (fillfunc)
- fillfunc(pa, zspan, pa->sample+zsample, data);
-
- if (zsample != samples-1) {
- MEM_freeN(zspan->rectz);
- MEM_freeN(zspan->rectp);
- MEM_freeN(zspan->recto);
- if (zspan->rectmask)
- MEM_freeN(zspan->rectmask);
- }
-
- zbuf_free_span(zspan);
- }
-}
-
-void zbuffer_shadow(Render *re, float winmat[4][4], LampRen *lar, int *rectz, int size, float jitx, float jity)
-{
- ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
- ZSpan zspan;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr= NULL;
- Material *ma= NULL;
- StrandSegment sseg;
- StrandRen *strand= NULL;
- StrandVert *svert;
- StrandBound *sbound;
- float obwinmat[4][4], ho1[4], ho2[4], ho3[4], ho4[4];
- int a, b, c, i, c1, c2, c3, c4, ok=1, lay= -1;
-
- if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
-
- /* 1.0f for clipping in clippyra()... bad stuff actually */
- zbuf_alloc_span(&zspan, size, size, 1.0f);
- zspan.zmulx= ((float)size)/2.0f;
- zspan.zmuly= ((float)size)/2.0f;
- /* -0.5f to center the sample position */
- zspan.zofsx= jitx - 0.5f;
- zspan.zofsy= jity - 0.5f;
-
- /* the buffers */
- zspan.rectz= rectz;
- fillrect(rectz, size, size, 0x7FFFFFFE);
- if (lar->buftype==LA_SHADBUF_HALFWAY) {
- zspan.rectz1= MEM_mallocN(size*size*sizeof(int), "seconday z buffer");
- fillrect(zspan.rectz1, size, size, 0x7FFFFFFE);
- }
-
- /* filling methods */
- zspan.zbuflinefunc= zbufline_onlyZ;
- zspan.zbuffunc= zbuffillGL_onlyZ;
-
- for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (obr->ob==re->excludeob)
- continue;
- else if (!(obi->lay & lay))
- continue;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- if (clip_render_object(obi->obr->boundbox, NULL, obwinmat))
- continue;
-
- zbuf_project_cache_clear(cache, obr->totvert);
-
- /* faces */
- for (a=0; a<obr->totvlak; a++) {
-
- if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
- else vlr++;
-
- /* note, these conditions are copied in shadowbuf_autoclip() */
- if (vlr->mat!= ma) {
- ma= vlr->mat;
- ok= 1;
- if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
- }
-
- if (ok && (obi->lay & lay) && !(vlr->flag & R_HIDDEN)) {
- c1= zbuf_shadow_project(cache, vlr->v1->index, obwinmat, vlr->v1->co, ho1);
- c2= zbuf_shadow_project(cache, vlr->v2->index, obwinmat, vlr->v2->co, ho2);
- c3= zbuf_shadow_project(cache, vlr->v3->index, obwinmat, vlr->v3->co, ho3);
-
- if ((ma->material_type == MA_TYPE_WIRE) || (vlr->flag & R_STRAND)) {
- if (vlr->v4) {
- c4= zbuf_shadow_project(cache, vlr->v4->index, obwinmat, vlr->v4->co, ho4);
- zbufclipwire(&zspan, 0, a+1, vlr->ec, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- }
- else
- zbufclipwire(&zspan, 0, a+1, vlr->ec, ho1, ho2, ho3, NULL, c1, c2, c3, 0);
- }
- else {
- if (vlr->v4) {
- c4= zbuf_shadow_project(cache, vlr->v4->index, obwinmat, vlr->v4->co, ho4);
- zbufclip4(&zspan, 0, 0, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- }
- else
- zbufclip(&zspan, 0, 0, ho1, ho2, ho3, c1, c2, c3);
- }
- }
-
- if ((a & 255)==255 && re->test_break(re->tbh))
- break;
- }
-
- /* strands */
- if (obr->strandbuf) {
- /* for each bounding box containing a number of strands */
- sbound= obr->strandbuf->bound;
- for (c=0; c<obr->strandbuf->totbound; c++, sbound++) {
- if (clip_render_object(sbound->boundbox, NULL, obwinmat))
- continue;
-
- /* for each strand in this bounding box */
- for (a=sbound->start; a<sbound->end; a++) {
- strand= RE_findOrAddStrand(obr, a);
-
- sseg.obi= obi;
- sseg.buffer= strand->buffer;
- sseg.sqadaptcos= sseg.buffer->adaptcos;
- sseg.sqadaptcos *= sseg.sqadaptcos;
- sseg.strand= strand;
- svert= strand->vert;
-
- /* note, these conditions are copied in shadowbuf_autoclip() */
- if (sseg.buffer->ma!= ma) {
- ma= sseg.buffer->ma;
- ok= 1;
- if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
- }
-
- if (ok && (sseg.buffer->lay & lay)) {
- zbuf_project_cache_clear(cache, strand->totvert);
-
- for (b=0; b<strand->totvert-1; b++, svert++) {
- sseg.v[0]= (b > 0)? (svert-1): svert;
- sseg.v[1]= svert;
- sseg.v[2]= svert+1;
- sseg.v[3]= (b < strand->totvert-2)? svert+2: svert+1;
-
- c1= zbuf_shadow_project(cache, sseg.v[0]-strand->vert, obwinmat, sseg.v[0]->co, ho1);
- c2= zbuf_shadow_project(cache, sseg.v[1]-strand->vert, obwinmat, sseg.v[1]->co, ho2);
- c3= zbuf_shadow_project(cache, sseg.v[2]-strand->vert, obwinmat, sseg.v[2]->co, ho3);
- c4= zbuf_shadow_project(cache, sseg.v[3]-strand->vert, obwinmat, sseg.v[3]->co, ho4);
-
- if (!(c1 & c2 & c3 & c4))
- render_strand_segment(re, winmat, NULL, &zspan, 1, &sseg);
- }
- }
-
- if ((a & 255)==255 && re->test_break(re->tbh))
- break;
- }
- }
- }
-
- if (re->test_break(re->tbh))
- break;
- }
-
- /* merge buffers */
- if (lar->buftype==LA_SHADBUF_HALFWAY) {
- for (a=size*size -1; a>=0; a--)
- rectz[a]= (rectz[a]>>1) + (zspan.rectz1[a]>>1);
-
- MEM_freeN(zspan.rectz1);
- }
-
- zbuf_free_span(&zspan);
-}
-
-static void zbuffill_sss(ZSpan *zspan, int obi, int zvlnr,
- const float *v1, const float *v2, const float *v3, const float *v4)
-{
- double zxd, zyd, zy0, z;
- float x0, y0, x1, y1, x2, y2, z0, z1, z2, xx1, *span1, *span2;
- int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
- /* init */
- zbuf_init_span(zspan);
-
- /* set spans */
- zbuf_add_to_span(zspan, v1, v2);
- zbuf_add_to_span(zspan, v2, v3);
- if (v4) {
- zbuf_add_to_span(zspan, v3, v4);
- zbuf_add_to_span(zspan, v4, v1);
- }
- else
- zbuf_add_to_span(zspan, v3, v1);
-
- /* clipped */
- if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
- my0 = max_ii(zspan->miny1, zspan->miny2);
- my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
- if (my2<my0) return;
-
- /* ZBUF DX DY, in floats still */
- x1= v1[0]- v2[0];
- x2= v2[0]- v3[0];
- y1= v1[1]- v2[1];
- y2= v2[1]- v3[1];
- z1= v1[2]- v2[2];
- z2= v2[2]- v3[2];
-
- x0= y1*z2-z1*y2;
- y0= z1*x2-x1*z2;
- z0= x1*y2-y1*x2;
-
- if (z0==0.0f) return;
-
- xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
- zxd= -(double)x0/(double)z0;
- zyd= -(double)y0/(double)z0;
- zy0= ((double)my2)*zyd + (double)xx1;
-
- /* correct span */
- sn1= (my0 + my2)/2;
- if (zspan->span1[sn1] < zspan->span2[sn1]) {
- span1= zspan->span1+my2;
- span2= zspan->span2+my2;
- }
- else {
- span1= zspan->span2+my2;
- span2= zspan->span1+my2;
- }
-
- for (y=my2; y>=my0; y--, span1--, span2--) {
- sn1= floor(*span1);
- sn2= floor(*span2);
- sn1++;
-
- if (sn2>=rectx) sn2= rectx-1;
- if (sn1<0) sn1= 0;
-
- z= (double)sn1*zxd + zy0;
-
- for (x= sn1; x<=sn2; x++, z+=zxd)
- zspan->sss_func(zspan->sss_handle, obi, zvlnr, x, y, z);
-
- zy0 -= zyd;
- }
-}
-
-void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(void *, int, int, int, int, int))
-{
- ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
- ZSpan zspan;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr= NULL;
- VertRen *v1, *v2, *v3, *v4;
- Material *ma = NULL, *sss_ma = R.sss_mat;
- float obwinmat[4][4], winmat[4][4], bounds[4];
- float ho1[4], ho2[4], ho3[4], ho4[4]={0};
- int i, v, zvlnr, c1, c2, c3, c4=0;
- short nofill=0, env=0, wire=0;
-
- zbuf_make_winmat(&R, winmat);
- zbuffer_part_bounds(R.winx, R.winy, pa, bounds);
- zbuf_alloc_span(&zspan, pa->rectx, pa->recty, R.clipcrop);
-
- zspan.sss_handle= handle;
- zspan.sss_func= func;
-
- /* needed for transform from hoco to zbuffer co */
- zspan.zmulx= ((float)R.winx)/2.0f;
- zspan.zmuly= ((float)R.winy)/2.0f;
-
- /* -0.5f to center the sample position */
- zspan.zofsx= -pa->disprect.xmin - 0.5f;
- zspan.zofsy= -pa->disprect.ymin - 0.5f;
-
- /* filling methods */
- zspan.zbuffunc= zbuffill_sss;
-
- /* fill front and back zbuffer */
- if (pa->rectz) {
- fillrect(pa->recto, pa->rectx, pa->recty, 0);
- fillrect(pa->rectp, pa->rectx, pa->recty, 0);
- fillrect(pa->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
- }
- if (pa->rectbackz) {
- fillrect(pa->rectbacko, pa->rectx, pa->recty, 0);
- fillrect(pa->rectbackp, pa->rectx, pa->recty, 0);
- fillrect(pa->rectbackz, pa->rectx, pa->recty, -0x7FFFFFFF);
- }
-
- for (i=0, obi=R.instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (!(obi->lay & lay))
- continue;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
- continue;
-
- zbuf_project_cache_clear(cache, obr->totvert);
-
- for (v=0; v<obr->totvlak; v++) {
- if ((v & 255)==0) vlr= obr->vlaknodes[v>>8].vlak;
- else vlr++;
-
- if (material_in_material(vlr->mat, sss_ma)) {
- /* three cases, visible for render, only z values and nothing */
- if (obi->lay & lay) {
- if (vlr->mat!=ma) {
- ma= vlr->mat;
- nofill= ma->mode & MA_ONLYCAST;
- env= (ma->mode & MA_ENV);
- wire= (ma->material_type == MA_TYPE_WIRE);
- }
- }
- else {
- nofill= 1;
- ma= NULL; /* otherwise nofill can hang */
- }
-
- if (nofill==0 && wire==0 && env==0) {
- unsigned short partclip;
-
- v1= vlr->v1;
- v2= vlr->v2;
- v3= vlr->v3;
- v4= vlr->v4;
-
- c1= zbuf_part_project(cache, v1->index, obwinmat, bounds, v1->co, ho1);
- c2= zbuf_part_project(cache, v2->index, obwinmat, bounds, v2->co, ho2);
- c3= zbuf_part_project(cache, v3->index, obwinmat, bounds, v3->co, ho3);
-
- /* partclipping doesn't need viewplane clipping */
- partclip= c1 & c2 & c3;
- if (v4) {
- c4= zbuf_part_project(cache, v4->index, obwinmat, bounds, v4->co, ho4);
- partclip &= c4;
- }
-
- if (partclip==0) {
- c1= testclip(ho1);
- c2= testclip(ho2);
- c3= testclip(ho3);
-
- zvlnr= v+1;
- zbufclip(&zspan, i, zvlnr, ho1, ho2, ho3, c1, c2, c3);
- if (v4) {
- c4= testclip(ho4);
- zbufclip(&zspan, i, zvlnr+RE_QUAD_OFFS, ho1, ho3, ho4, c1, c3, c4);
- }
- }
- }
- }
- }
- }
-
- zbuf_free_span(&zspan);
-}
-
-/* ******************** ABUF ************************* */
-
-/**
- * Copy results from the solid face z buffering to the transparent
- * buffer.
- */
-static void copyto_abufz(RenderPart *pa, int *arectz, int *rectmask, int sample)
-{
- PixStr *ps;
- int x, y, *rza, *rma;
- intptr_t *rd;
-
- if (R.osa==0) {
- if (!pa->rectz)
- fillrect(arectz, pa->rectx, pa->recty, 0x7FFFFFFE);
- else
- memcpy(arectz, pa->rectz, sizeof(int)*pa->rectx*pa->recty);
-
- if (rectmask && pa->rectmask)
- memcpy(rectmask, pa->rectmask, sizeof(int)*pa->rectx*pa->recty);
-
- return;
- }
- else if (!pa->rectdaps) {
- fillrect(arectz, pa->rectx, pa->recty, 0x7FFFFFFE);
- return;
- }
-
- rza= arectz;
- rma= rectmask;
- rd= pa->rectdaps;
-
- sample= (1<<sample);
-
- for (y=0; y<pa->recty; y++) {
- for (x=0; x<pa->rectx; x++) {
-
- *rza= 0x7FFFFFFF;
- if (rectmask) *rma= 0x7FFFFFFF;
- if (*rd) {
- /* when there's a sky pixstruct, fill in sky-Z, otherwise solid Z */
- for (ps= (PixStr *)(*rd); ps; ps= ps->next) {
- if (sample & ps->mask) {
- *rza= ps->z;
- if (rectmask) *rma= ps->maskz;
- break;
- }
- }
- }
-
- rza++;
- rma++;
- rd++;
- }
- }
-}
-
-
-/* ------------------------------------------------------------------------ */
-
-/**
- * Do accumulation z buffering.
- */
-
-static int zbuffer_abuf(Render *re, RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, unsigned int lay, int negzmask, float winmat[4][4], int winx, int winy, int samples, float (*jit)[2], float UNUSED(clipcrop), int shadow)
-{
- ZbufProjectCache cache[ZBUF_PROJECT_CACHE_SIZE];
- ZSpan zspans[16], *zspan; /* MAX_OSA */
- Material *ma=NULL;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- VlakRen *vlr=NULL;
- VertRen *v1, *v2, *v3, *v4;
- float vec[3], hoco[4], mul, zval, fval;
- float obwinmat[4][4], bounds[4], ho1[4], ho2[4], ho3[4], ho4[4]={0};
- int i, v, zvlnr, c1, c2, c3, c4=0, dofill= 0;
- int zsample, polygon_offset;
-
- zbuffer_part_bounds(winx, winy, pa, bounds);
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
-
- zbuf_alloc_span(zspan, pa->rectx, pa->recty, re->clipcrop);
-
- /* needed for transform from hoco to zbuffer co */
- zspan->zmulx= ((float)winx)/2.0f;
- zspan->zmuly= ((float)winy)/2.0f;
-
- /* the buffers */
- zspan->arectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "Arectz");
- zspan->apixbuf= APixbuf;
- zspan->apsmbase= apsmbase;
-
- if (negzmask)
- zspan->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "Arectmask");
-
- /* filling methods */
- zspan->zbuffunc= zbuffillAc4;
- zspan->zbuflinefunc= zbuflineAc;
-
- copyto_abufz(pa, zspan->arectz, zspan->rectmask, zsample); /* init zbuffer */
- zspan->mask= 1<<zsample;
-
- if (jit) {
- zspan->zofsx= -pa->disprect.xmin - jit[zsample][0];
- zspan->zofsy= -pa->disprect.ymin - jit[zsample][1];
- }
- else {
- zspan->zofsx= -pa->disprect.xmin;
- zspan->zofsy= -pa->disprect.ymin;
- }
-
- /* to center the sample position */
- zspan->zofsx -= 0.5f;
- zspan->zofsy -= 0.5f;
- }
-
- /* we use this to test if nothing was filled in */
- zvlnr= 0;
-
- for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
- obr= obi->obr;
-
- if (!(obi->lay & lay))
- continue;
-
- if (obi->flag & R_TRANSFORMED)
- mul_m4_m4m4(obwinmat, winmat, obi->mat);
- else
- copy_m4_m4(obwinmat, winmat);
-
- if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
- continue;
-
- zbuf_project_cache_clear(cache, obr->totvert);
-
- for (v=0; v<obr->totvlak; v++) {
- if ((v & 255)==0)
- vlr= obr->vlaknodes[v>>8].vlak;
- else vlr++;
-
- if (vlr->mat!=ma) {
- ma= vlr->mat;
- if (shadow)
- dofill= (ma->mode2 & MA_CASTSHADOW) && (ma->mode & MA_SHADBUF);
- else
- dofill= (((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP)) && !(ma->mode & MA_ONLYCAST));
- }
-
- if (dofill) {
- if (!(vlr->flag & R_HIDDEN) && (obi->lay & lay)) {
- unsigned short partclip;
-
- v1= vlr->v1;
- v2= vlr->v2;
- v3= vlr->v3;
- v4= vlr->v4;
-
- c1= zbuf_part_project(cache, v1->index, obwinmat, bounds, v1->co, ho1);
- c2= zbuf_part_project(cache, v2->index, obwinmat, bounds, v2->co, ho2);
- c3= zbuf_part_project(cache, v3->index, obwinmat, bounds, v3->co, ho3);
-
- /* partclipping doesn't need viewplane clipping */
- partclip= c1 & c2 & c3;
- if (v4) {
- c4= zbuf_part_project(cache, v4->index, obwinmat, bounds, v4->co, ho4);
- partclip &= c4;
- }
-
- if (partclip==0) {
- /* a little advantage for transp rendering (a z offset) */
- if (!shadow && ma->zoffs != 0.0f) {
- mul= 0x7FFFFFFF;
- zval= mul*(1.0f+ho1[2]/ho1[3]);
-
- copy_v3_v3(vec, v1->co);
- /* z is negative, otherwise its being clipped */
- vec[2]-= ma->zoffs;
- projectverto(vec, obwinmat, hoco);
- fval= mul*(1.0f+hoco[2]/hoco[3]);
-
- polygon_offset= (int)fabsf(zval - fval);
- }
- else polygon_offset= 0;
-
- zvlnr= v+1;
-
- c1= testclip(ho1);
- c2= testclip(ho2);
- c3= testclip(ho3);
- if (v4)
- c4= testclip(ho4);
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
- zspan->polygon_offset= polygon_offset;
-
- if (ma->material_type == MA_TYPE_WIRE) {
- if (v4)
- zbufclipwire(zspan, i, zvlnr, vlr->ec, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- else
- zbufclipwire(zspan, i, zvlnr, vlr->ec, ho1, ho2, ho3, NULL, c1, c2, c3, 0);
- }
- else {
- if (v4 && (vlr->flag & R_STRAND)) {
- zbufclip4(zspan, i, zvlnr, ho1, ho2, ho3, ho4, c1, c2, c3, c4);
- }
- else {
- zbufclip(zspan, i, zvlnr, ho1, ho2, ho3, c1, c2, c3);
- if (v4)
- zbufclip(zspan, i, zvlnr+RE_QUAD_OFFS, ho1, ho3, ho4, c1, c3, c4);
- }
- }
- }
- }
- if ((v & 255)==255)
- if (re->test_break(re->tbh))
- break;
- }
- }
- }
-
- if (re->test_break(re->tbh)) break;
- }
-
- for (zsample=0; zsample<samples; zsample++) {
- zspan= &zspans[zsample];
- MEM_freeN(zspan->arectz);
- if (zspan->rectmask)
- MEM_freeN(zspan->rectmask);
- zbuf_free_span(zspan);
- }
-
- return zvlnr;
-}
-
-static int zbuffer_abuf_render(RenderPart *pa, APixstr *APixbuf, APixstrand *APixbufstrand, ListBase *apsmbase, RenderLayer *rl, StrandShadeCache *sscache)
-{
- float winmat[4][4], (*jit)[2];
- int samples, negzmask, doztra= 0;
-
- samples= (R.osa)? R.osa: 1;
- negzmask= ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK));
-
- if (R.osa)
- jit= R.jit;
- else if (R.i.curblur)
- jit= &R.mblur_jit[R.i.curblur-1];
- else
- jit= NULL;
-
- zbuf_make_winmat(&R, winmat);
-
- if (rl->layflag & SCE_LAY_ZTRA)
- doztra+= zbuffer_abuf(&R, pa, APixbuf, apsmbase, rl->lay, negzmask, winmat, R.winx, R.winy, samples, jit, R.clipcrop, 0);
- if ((rl->layflag & SCE_LAY_STRAND) && APixbufstrand)
- doztra+= zbuffer_strands_abuf(&R, pa, APixbufstrand, apsmbase, rl->lay, negzmask, winmat, R.winx, R.winy, samples, jit, R.clipcrop, 0, sscache);
-
- return doztra;
-}
-
-void zbuffer_abuf_shadow(Render *re, LampRen *lar, float winmat[4][4], APixstr *APixbuf, APixstrand *APixbufstrand, ListBase *apsmbase, int size, int samples, float (*jit)[2])
-{
- RenderPart pa;
- int lay= -1;
-
- if (lar->mode & LA_LAYER) lay= lar->lay;
-
- memset(&pa, 0, sizeof(RenderPart));
- pa.rectx= size;
- pa.recty= size;
- pa.disprect.xmin = 0;
- pa.disprect.ymin = 0;
- pa.disprect.xmax = size;
- pa.disprect.ymax = size;
-
- zbuffer_abuf(re, &pa, APixbuf, apsmbase, lay, 0, winmat, size, size, samples, jit, 1.0f, 1);
- if (APixbufstrand)
- zbuffer_strands_abuf(re, &pa, APixbufstrand, apsmbase, lay, 0, winmat, size, size, samples, jit, 1.0f, 1, NULL);
-}
-
-/* different rules for speed in transparent pass... */
-/* speed pointer NULL = sky, we clear */
-/* else if either alpha is full or no solid was filled in: copy speed */
-/* else fill in minimum speed */
-static void add_transp_speed(RenderLayer *rl, int offset, float speed[4], float alpha, intptr_t *rdrect)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
- float *fp= rpass->rect + 4*offset;
-
- if (speed==NULL) {
- /* clear */
- if (fp[0]==PASS_VECTOR_MAX) fp[0]= 0.0f;
- if (fp[1]==PASS_VECTOR_MAX) fp[1]= 0.0f;
- if (fp[2]==PASS_VECTOR_MAX) fp[2]= 0.0f;
- if (fp[3]==PASS_VECTOR_MAX) fp[3]= 0.0f;
- }
- else if (rdrect==NULL || rdrect[offset]==0 || alpha>0.95f) {
- copy_v4_v4(fp, speed);
- }
- else {
- /* add minimum speed in pixel */
- if ( (ABS(speed[0]) + ABS(speed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
- fp[0]= speed[0];
- fp[1]= speed[1];
- }
- if ( (ABS(speed[2]) + ABS(speed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
- fp[2]= speed[2];
- fp[3]= speed[3];
- }
- }
- break;
- }
- }
-}
-
-static void add_transp_obindex(RenderLayer *rl, int offset, Object *ob)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
- float *fp= rpass->rect + offset;
- *fp= (float)ob->index;
- break;
- }
- }
-}
-
-static void add_transp_material_index(RenderLayer *rl, int offset, Material *mat)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
- float *fp= rpass->rect + offset;
- *fp= (float)mat->index;
- break;
- }
- }
-}
-
-/* ONLY OSA! merge all shaderesult samples to one */
-/* target should have been cleared */
-static void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
-{
- RenderPass *rpass;
- float weight= 1.0f/((float)R.osa);
- int delta= sizeof(ShadeResult)/4;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *col = NULL;
- int pixsize = 3;
-
- if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
- col = shr->col;
- pixsize = 4;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
- col = shr->emit;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
- col = shr->diff;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
- col = shr->spec;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
- col = shr->shad;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
- col = shr->ao;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
- col = shr->env;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
- col = shr->indirect;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
- col = shr->refl;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
- col = shr->refr;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
- col = shr->nor;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
- col = &shr->mist;
- pixsize = 1;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
- col = &shr->z;
- pixsize = 1;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
- ShadeResult *shr_t = shr+1;
- float *fp = shr->winspeed; /* was initialized */
- int samp;
-
- /* add minimum speed in pixel */
- for (samp = 1; samp<R.osa; samp++, shr_t++) {
-
- if (shr_t->combined[3] > 0.0f) {
- const float *speed = shr_t->winspeed;
-
- if ( (ABS(speed[0]) + ABS(speed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
- fp[0] = speed[0];
- fp[1] = speed[1];
- }
- if ( (ABS(speed[2]) + ABS(speed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
- fp[2] = speed[2];
- fp[3] = speed[3];
- }
- }
- }
- }
-
- if (col) {
- const float *fp= col+delta;
- int samp;
-
- for (samp= 1; samp<R.osa; samp++, fp+=delta) {
- col[0]+= fp[0];
- if (pixsize>1) {
- col[1]+= fp[1];
- col[2]+= fp[2];
- if (pixsize==4) col[3]+= fp[3];
- }
- }
- col[0]*= weight;
- if (pixsize>1) {
- col[1]*= weight;
- col[2]*= weight;
- if (pixsize==4) col[3]*= weight;
- }
- }
- }
-
-}
-
-static void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alpha)
-{
- RenderPass *rpass;
-
- for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
- float *fp, *col= NULL;
- int pixsize= 3;
-
- if (STREQ(rpass->name, RE_PASSNAME_Z)) {
- fp = rpass->rect + offset;
- if (shr->z < *fp)
- *fp = shr->z;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
- fp = rpass->rect + 4*offset;
- addAlphaOverFloat(fp, shr->col);
- }
- else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
- col = shr->emit;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
- col = shr->diff;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
- col = shr->spec;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
- col = shr->shad;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
- col = shr->ao;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
- col = shr->env;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
- col = shr->indirect;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
- col = shr->refl;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
- col = shr->refr;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
- col = shr->nor;
- }
- else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
- col = &shr->mist;
- pixsize = 1;
- }
-
- if (col) {
- fp= rpass->rect + pixsize*offset;
- fp[0]= col[0] + (1.0f-alpha)*fp[0];
- if (pixsize==3) {
- fp[1]= col[1] + (1.0f-alpha)*fp[1];
- fp[2]= col[2] + (1.0f-alpha)*fp[2];
- }
- }
- }
-}
-
-typedef struct ZTranspRow {
- int obi;
- int z;
- int p;
- int mask;
- int segment;
- float u, v;
-} ZTranspRow;
-
-static int vergzvlak(const void *a1, const void *a2)
-{
- const ZTranspRow *r1 = a1, *r2 = a2;
-
- if (r1->z < r2->z) return 1;
- else if (r1->z > r2->z) return -1;
- return 0;
-}
-
-static void shade_strand_samples(StrandShadeCache *cache, ShadeSample *ssamp, int UNUSED(x), int UNUSED(y), ZTranspRow *row, int addpassflag)
-{
- StrandSegment sseg;
- StrandVert *svert;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
-
- obi= R.objectinstance + row->obi;
- obr= obi->obr;
-
- sseg.obi= obi;
- sseg.strand= RE_findOrAddStrand(obr, row->p-1);
- sseg.buffer= sseg.strand->buffer;
-
- svert= sseg.strand->vert + row->segment;
- sseg.v[0]= (row->segment > 0)? (svert-1): svert;
- sseg.v[1]= svert;
- sseg.v[2]= svert+1;
- sseg.v[3]= (row->segment < sseg.strand->totvert-2)? svert+2: svert+1;
-
- ssamp->tot= 1;
- strand_shade_segment(&R, cache, &sseg, ssamp, row->v, row->u, addpassflag);
- ssamp->shi[0].mask= row->mask;
-}
-
-static void unref_strand_samples(StrandShadeCache *cache, ZTranspRow *row, int totface)
-{
- StrandVert *svert;
- ObjectInstanceRen *obi;
- ObjectRen *obr;
- StrandRen *strand;
-
- /* remove references to samples that are not being rendered, but we still
- * need to remove them so that the reference count of strand vertex shade
- * samples correctly drops to zero */
- while (totface > 0) {
- totface--;
-
- if (row[totface].segment != -1) {
- obi= R.objectinstance + row[totface].obi;
- obr= obi->obr;
- strand= RE_findOrAddStrand(obr, row[totface].p-1);
- svert= strand->vert + row[totface].segment;
-
- strand_shade_unref(cache, obi, svert);
- strand_shade_unref(cache, obi, svert+1);
- }
- }
-}
-
-static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int obi, int facenr, int curmask)
-{
- ShadeInput *shi= ssamp->shi;
- float xs, ys;
-
- ssamp->tot= 0;
-
- shade_input_set_triangle(shi, obi, facenr, 1);
-
- /* officially should always be true... we have no sky info */
- if (shi->vlr) {
-
- /* full osa is only set for OSA renders */
- if (shi->vlr->flag & R_FULL_OSA) {
- short shi_inc= 0, samp;
-
- for (samp=0; samp<R.osa; samp++) {
- if (curmask & (1<<samp)) {
- xs= (float)x + R.jit[samp][0] + 0.5f; /* zbuffer has this inverse corrected, ensures (xs, ys) are inside pixel */
- ys= (float)y + R.jit[samp][1] + 0.5f;
-
- if (shi_inc) {
- shade_input_copy_triangle(shi+1, shi);
- shi++;
- }
- shi->mask= (1<<samp);
- shi->samplenr= R.shadowsamplenr[shi->thread]++;
- shade_input_set_viewco(shi, x, y, xs, ys, (float)z);
- shade_input_set_uv(shi);
- if (shi_inc==0)
- shade_input_set_normals(shi);
- else /* XXX shi->flippednor messes up otherwise */
- shade_input_set_vertex_normals(shi);
-
- shi_inc= 1;
- }
- }
- }
- else {
- if (R.osa) {
- short b= R.samples->centmask[curmask];
- xs= (float)x + R.samples->centLut[b & 15] + 0.5f;
- ys= (float)y + R.samples->centLut[b>>4] + 0.5f;
- }
- else if (R.i.curblur) {
- xs= (float)x + R.mblur_jit[R.i.curblur-1][0] + 0.5f;
- ys= (float)y + R.mblur_jit[R.i.curblur-1][1] + 0.5f;
- }
- else {
- xs= (float)x + 0.5f;
- ys= (float)y + 0.5f;
- }
- shi->mask= curmask;
- shi->samplenr= R.shadowsamplenr[shi->thread]++;
- shade_input_set_viewco(shi, x, y, xs, ys, (float)z);
- shade_input_set_uv(shi);
- shade_input_set_normals(shi);
- }
-
- /* total sample amount, shi->sample is static set in initialize */
- ssamp->tot= shi->sample+1;
- }
-}
-
-static int shade_tra_samples(ShadeSample *ssamp, StrandShadeCache *cache, int x, int y, ZTranspRow *row, int addpassflag)
-{
- if (row->segment != -1) {
- shade_strand_samples(cache, ssamp, x, y, row, addpassflag);
- return 1;
- }
-
- shade_tra_samples_fill(ssamp, x, y, row->z, row->obi, row->p, row->mask);
-
- if (ssamp->tot) {
- ShadeInput *shi= ssamp->shi;
- ShadeResult *shr= ssamp->shr;
- int samp;
-
- /* if AO? */
- shade_samples_do_AO(ssamp);
-
- /* if shade (all shadepinputs have same passflag) */
- if (shi->passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB|SCE_PASS_INDEXMA)) {
- for (samp=0; samp<ssamp->tot; samp++, shi++, shr++) {
- shade_input_set_shade_texco(shi);
- shade_input_do_shade(shi, shr);
-
- /* include lamphalos for ztra, since halo layer was added already */
- if (R.flag & R_LAMPHALO)
- if (shi->layflag & SCE_LAY_HALO)
- renderspothalo(shi, shr->combined, shr->combined[3]);
- }
- }
- else if (shi->passflag & SCE_PASS_Z) {
- for (samp=0; samp<ssamp->tot; samp++, shi++, shr++)
- shr->z= -shi->co[2];
- }
-
- return 1;
- }
- return 0;
-}
-
-static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
-{
- int a, sample, osa = (R.osa? R.osa: 1), retval = osa;
-
- for (a=0; a < osa; a++, samp_shr++) {
- ShadeInput *shi= ssamp->shi;
- ShadeResult *shr= ssamp->shr;
-
- for (sample=0; sample<ssamp->tot; sample++, shi++, shr++) {
-
- if (shi->mask & (1<<a)) {
- float fac= (1.0f - samp_shr->combined[3])*shr->combined[3];
-
- addAlphaUnderFloat(samp_shr->combined, shr->combined);
-
- samp_shr->z = min_ff(samp_shr->z, shr->z);
-
- if (addpassflag & SCE_PASS_VECTOR) {
- copy_v4_v4(samp_shr->winspeed, shr->winspeed);
- }
- /* optim... */
- if (addpassflag & ~(SCE_PASS_VECTOR)) {
-
- if (addpassflag & SCE_PASS_RGBA)
- addAlphaUnderFloat(samp_shr->col, shr->col);
-
- if (addpassflag & SCE_PASS_NORMAL)
- madd_v3_v3fl(samp_shr->nor, shr->nor, fac);
-
- if (addpassflag & SCE_PASS_EMIT)
- madd_v3_v3fl(samp_shr->emit, shr->emit, fac);
-
- if (addpassflag & SCE_PASS_DIFFUSE)
- madd_v3_v3fl(samp_shr->diff, shr->diff, fac);
-
- if (addpassflag & SCE_PASS_SPEC)
- madd_v3_v3fl(samp_shr->spec, shr->spec, fac);
-
- if (addpassflag & SCE_PASS_SHADOW)
- madd_v3_v3fl(samp_shr->shad, shr->shad, fac);
-
- if (addpassflag & SCE_PASS_AO)
- madd_v3_v3fl(samp_shr->ao, shr->ao, fac);
-
- if (addpassflag & SCE_PASS_ENVIRONMENT)
- madd_v3_v3fl(samp_shr->env, shr->env, fac);
-
- if (addpassflag & SCE_PASS_INDIRECT)
- madd_v3_v3fl(samp_shr->indirect, shr->indirect, fac);
-
- if (addpassflag & SCE_PASS_REFLECT)
- madd_v3_v3fl(samp_shr->refl, shr->refl, fac);
-
- if (addpassflag & SCE_PASS_REFRACT)
- madd_v3_v3fl(samp_shr->refr, shr->refr, fac);
-
- if (addpassflag & SCE_PASS_MIST)
- samp_shr->mist= samp_shr->mist+fac*shr->mist;
-
- }
- }
- }
-
- if (samp_shr->combined[3]>0.999f) retval--;
- }
- return retval;
-}
-
-static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf)
-{
- /* speed vector exception... if solid render was done, sky pixels are set to zero already */
- /* for all pixels with alpha zero, we re-initialize speed again then */
- float *fp, *col;
- int a;
-
- fp = RE_RenderLayerGetPass(rl, RE_PASSNAME_VECTOR, R.viewname);
- if (fp==NULL) return;
- col= rectf+3;
-
- for (a= 4*pa->rectx*pa->recty -4; a>=0; a-=4) {
- if (col[a]==0.0f) {
- fp[a]= PASS_VECTOR_MAX;
- fp[a+1]= PASS_VECTOR_MAX;
- fp[a+2]= PASS_VECTOR_MAX;
- fp[a+3]= PASS_VECTOR_MAX;
- }
- }
-}
-
-#define MAX_ZROW 2000
-
-/* main render call to do the z-transparent layer */
-/* returns a mask, only if a) transp rendered and b) solid was rendered */
-unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass, ListBase *UNUSED(psmlist))
-{
- RenderResult *rr= pa->result;
- ShadeSample ssamp;
- APixstr *APixbuf; /* Zbuffer: linked list of face samples */
- APixstrand *APixbufstrand = NULL;
- APixstr *ap, *aprect, *apn;
- APixstrand *apstrand, *aprectstrand, *apnstrand;
- ListBase apsmbase={NULL, NULL};
- ShadeResult samp_shr[16]; /* MAX_OSA */
- ZTranspRow zrow[MAX_ZROW];
- StrandShadeCache *sscache= NULL;
- RenderLayer *rlpp[RE_MAX_OSA];
- float sampalpha, alpha, *passrect= pass;
- intptr_t *rdrect;
- int x, y, crop=0, a, b, totface, totfullsample, totsample, doztra;
- int addpassflag, offs= 0, od, osa = (R.osa? R.osa: 1);
- unsigned short *ztramask= NULL, filled;
-
- /* looks nicer for calling code */
- if (R.test_break(R.tbh))
- return NULL;
-
- if (R.osa > 16) { /* MAX_OSA */
- printf("zbuffer_transp_shade: osa too large\n");
- G.is_break = true;
- return NULL;
- }
-
- APixbuf= MEM_callocN(pa->rectx*pa->recty*sizeof(APixstr), "APixbuf");
- if (R.totstrand && (rl->layflag & SCE_LAY_STRAND)) {
- APixbufstrand= MEM_callocN(pa->rectx*pa->recty*sizeof(APixstrand), "APixbufstrand");
- sscache= strand_shade_cache_create();
- }
-
- /* general shader info, passes */
- shade_sample_initialize(&ssamp, pa, rl);
- addpassflag= rl->passflag & ~(SCE_PASS_COMBINED);
-
- if (R.osa)
- sampalpha= 1.0f/(float)R.osa;
- else
- sampalpha= 1.0f;
-
- /* fill the Apixbuf */
- doztra= zbuffer_abuf_render(pa, APixbuf, APixbufstrand, &apsmbase, rl, sscache);
-
- if (doztra == 0) {
- /* nothing filled in */
- MEM_freeN(APixbuf);
- if (APixbufstrand)
- MEM_freeN(APixbufstrand);
- if (sscache)
- strand_shade_cache_free(sscache);
- freepsA(&apsmbase);
- return NULL;
- }
-
- aprect= APixbuf;
- aprectstrand= APixbufstrand;
- rdrect= pa->rectdaps;
-
- /* needed for correct zbuf/index pass */
- totfullsample= get_sample_layers(pa, rl, rlpp);
-
- /* irregular shadowb buffer creation */
- if (R.r.mode & R_SHADOW)
- ISB_create(pa, APixbuf);
-
- /* masks, to have correct alpha combine */
- if (R.osa && (rl->layflag & SCE_LAY_SOLID) && pa->fullresult.first==NULL)
- ztramask= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "ztramask");
-
- /* zero alpha pixels get speed vector max again */
- if (addpassflag & SCE_PASS_VECTOR)
- if (rl->layflag & SCE_LAY_SOLID) {
- float *rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
- reset_sky_speedvectors(pa, rl, rl->acolrect ? rl->acolrect : rect); /* if acolrect is set we use it */
- }
- /* filtered render, for now we assume only 1 filter size */
- if (pa->crop) {
- crop= 1;
- offs= pa->rectx + 1;
- passrect+= 4*offs;
- aprect+= offs;
- aprectstrand+= offs;
- }
-
- /* init scanline updates */
- rr->renrect.ymin = 0;
- rr->renrect.ymax = -pa->crop;
- rr->renlay= rl;
-
- /* render the tile */
- for (y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
- pass= passrect;
- ap= aprect;
- apstrand= aprectstrand;
- od= offs;
-
- if (R.test_break(R.tbh))
- break;
-
- for (x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, ap++, apstrand++, pass+=4, od++) {
-
- if (ap->p[0]==0 && (!APixbufstrand || apstrand->p[0]==0)) {
- if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, NULL, 0.0f, rdrect);
- }
- else {
- /* sort in z */
- totface= 0;
- apn= ap;
- while (apn) {
- for (a=0; a<4; a++) {
- if (apn->p[a]) {
- zrow[totface].obi= apn->obi[a];
- zrow[totface].z= apn->z[a];
- zrow[totface].p= apn->p[a];
- zrow[totface].mask= apn->mask[a];
- zrow[totface].segment= -1;
- totface++;
- if (totface>=MAX_ZROW) totface= MAX_ZROW-1;
- }
- else break;
- }
- apn= apn->next;
- }
-
- apnstrand= (APixbufstrand)? apstrand: NULL;
- while (apnstrand) {
- for (a=0; a<4; a++) {
- if (apnstrand->p[a]) {
- zrow[totface].obi= apnstrand->obi[a];
- zrow[totface].z= apnstrand->z[a];
- zrow[totface].p= apnstrand->p[a];
- zrow[totface].mask= apnstrand->mask[a];
- zrow[totface].segment= apnstrand->seg[a];
-
- if (R.osa) {
- totsample= 0;
- for (b=0; b<R.osa; b++)
- if (zrow[totface].mask & (1<<b))
- totsample++;
- }
- else
- totsample= 1;
-
- zrow[totface].u= apnstrand->u[a]/totsample;
- zrow[totface].v= apnstrand->v[a]/totsample;
- totface++;
- if (totface>=MAX_ZROW) totface= MAX_ZROW-1;
- }
- }
- apnstrand= apnstrand->next;
- }
-
- if (totface==2) {
- if (zrow[0].z < zrow[1].z) {
- SWAP(ZTranspRow, zrow[0], zrow[1]);
- }
-
- }
- else if (totface>2) {
- qsort(zrow, totface, sizeof(ZTranspRow), vergzvlak);
- }
-
- /* front face does index pass for transparent, no AA or filters, but yes FSA */
- if (addpassflag & SCE_PASS_INDEXOB) {
- ObjectRen *obr= R.objectinstance[zrow[totface-1].obi].obr;
- if (obr->ob) {
- for (a= 0; a<totfullsample; a++)
- add_transp_obindex(rlpp[a], od, obr->ob);
- }
- }
- if (addpassflag & SCE_PASS_INDEXMA) {
- ObjectRen *obr = R.objectinstance[zrow[totface-1].obi].obr;
- int p = zrow[totface-1].p;
- Material *mat = NULL;
-
- if (zrow[totface-1].segment == -1) {
- int facenr = (p - 1) & RE_QUAD_MASK;
- VlakRen *vlr = NULL;
-
- if (facenr >= 0 && facenr < obr->totvlak)
- vlr = RE_findOrAddVlak(obr, facenr);
-
- if (vlr)
- mat = vlr->mat;
- }
- else {
- StrandRen *strand = RE_findOrAddStrand(obr, p - 1);
-
- if (strand)
- mat = strand->buffer->ma;
- }
-
- if (mat) {
- for (a= 0; a<totfullsample; a++)
- add_transp_material_index(rlpp[a], od, mat);
- }
- }
-
- /* for each mask-sample we alpha-under colors. then in end it's added using filter */
- memset(samp_shr, 0, sizeof(ShadeResult)*osa);
- for (a=0; a<osa; a++) {
- samp_shr[a].z= 10e10f;
- if (addpassflag & SCE_PASS_VECTOR) {
- samp_shr[a].winspeed[0]= PASS_VECTOR_MAX;
- samp_shr[a].winspeed[1]= PASS_VECTOR_MAX;
- samp_shr[a].winspeed[2]= PASS_VECTOR_MAX;
- samp_shr[a].winspeed[3]= PASS_VECTOR_MAX;
- }
- }
-
- if (R.osa==0) {
- while (totface>0) {
- totface--;
-
- if (shade_tra_samples(&ssamp, sscache, x, y, &zrow[totface], addpassflag)) {
- filled= addtosamp_shr(samp_shr, &ssamp, addpassflag);
- addAlphaUnderFloat(pass, ssamp.shr[0].combined);
-
- if (filled == 0) {
- if (sscache)
- unref_strand_samples(sscache, zrow, totface);
- break;
- }
- }
- }
-
- alpha= samp_shr->combined[3];
- if (alpha!=0.0f) {
- add_transp_passes(rl, od, samp_shr, alpha);
- if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, samp_shr->winspeed, alpha, rdrect);
- }
- }
- else {
- short *sp= (short *)(ztramask+od);
-
- while (totface>0) {
- totface--;
-
- if (shade_tra_samples(&ssamp, sscache, x, y, &zrow[totface], addpassflag)) {
- filled= addtosamp_shr(samp_shr, &ssamp, addpassflag);
-
- if (ztramask)
- *sp |= zrow[totface].mask;
- if (filled==0) {
- if (sscache)
- unref_strand_samples(sscache, zrow, totface);
- break;
- }
- }
- }
-
- /* multisample buffers or filtered mask filling? */
- if (pa->fullresult.first) {
- for (a=0; a<R.osa; a++) {
- alpha= samp_shr[a].combined[3];
- if (alpha != 0.0f) {
- RenderLayer *rl_other = ssamp.rlpp[a];
-
- float *rect = RE_RenderLayerGetPass(rl_other , RE_PASSNAME_COMBINED, R.viewname);
- addAlphaOverFloat(rect + 4 * od, samp_shr[a].combined);
-
- add_transp_passes(rl_other , od, &samp_shr[a], alpha);
- if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl_other , od, samp_shr[a].winspeed, alpha, rdrect);
- }
- }
- }
- else {
- alpha= 0.0f;
-
- /* note; cannot use pass[3] for alpha due to filtermask */
- for (a=0; a<R.osa; a++) {
- add_filt_fmask(1<<a, samp_shr[a].combined, pass, rr->rectx);
- alpha+= samp_shr[a].combined[3];
- }
-
- if (addpassflag) {
- alpha*= sampalpha;
-
- /* merge all in one, and then add */
- merge_transp_passes(rl, samp_shr);
- add_transp_passes(rl, od, samp_shr, alpha);
-
- if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, samp_shr[0].winspeed, alpha, rdrect);
- }
- }
- }
- }
- }
-
- aprect+= pa->rectx;
- aprectstrand+= pa->rectx;
- passrect+= 4*pa->rectx;
- offs+= pa->rectx;
- }
-
- /* disable scanline updating */
- rr->renlay= NULL;
-
- MEM_freeN(APixbuf);
- if (APixbufstrand)
- MEM_freeN(APixbufstrand);
- if (sscache)
- strand_shade_cache_free(sscache);
- freepsA(&apsmbase);
-
- if (R.r.mode & R_SHADOW)
- ISB_free(pa);
-
- return ztramask;
-}
-
-
/* end of zbuf.c */
diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt
new file mode 100644
index 00000000000..1807635aa8d
--- /dev/null
+++ b/source/blender/shader_fx/CMakeLists.txt
@@ -0,0 +1,66 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2018, Blender Foundation
+# All rights reserved.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ ../blenkernel
+ ../blenlib
+ ../blenfont
+ ../depsgraph
+ ../makesdna
+ ../makesrna
+ ../bmesh
+ ../render/extern/include
+ ../../../intern/elbeem/extern
+ ../../../intern/guardedalloc
+ ../../../intern/eigen
+)
+
+set(INC_SYS
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ intern/FX_shader_util.h
+
+ intern/FX_shader_util.c
+ intern/FX_shader_blur.c
+ intern/FX_shader_colorize.c
+ intern/FX_shader_flip.c
+ intern/FX_shader_glow.c
+ intern/FX_shader_light.c
+ intern/FX_shader_pixel.c
+ intern/FX_shader_rim.c
+ intern/FX_shader_shadow.c
+ intern/FX_shader_swirl.c
+ intern/FX_shader_wave.c
+
+ FX_shader_types.h
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_shader_fx "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/shader_fx/FX_shader_types.h b/source/blender/shader_fx/FX_shader_types.h
new file mode 100644
index 00000000000..311f5ec52e8
--- /dev/null
+++ b/source/blender/shader_fx/FX_shader_types.h
@@ -0,0 +1,49 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Ben Batt
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file FX_shader_types.h
+ * \ingroup shader_fx
+ */
+
+#ifndef __FX_SHADER_TYPES_H__
+#define __FX_SHADER_TYPES_H__
+
+#include "BKE_shader_fx.h"
+
+/* ****************** Type structures for all effects ****************** */
+
+extern ShaderFxTypeInfo shaderfx_Type_None;
+extern ShaderFxTypeInfo shaderfx_Type_Blur;
+extern ShaderFxTypeInfo shaderfx_Type_Colorize;
+extern ShaderFxTypeInfo shaderfx_Type_Flip;
+extern ShaderFxTypeInfo shaderfx_Type_Glow;
+extern ShaderFxTypeInfo shaderfx_Type_Light;
+extern ShaderFxTypeInfo shaderfx_Type_Pixel;
+extern ShaderFxTypeInfo shaderfx_Type_Rim;
+extern ShaderFxTypeInfo shaderfx_Type_Shadow;
+extern ShaderFxTypeInfo shaderfx_Type_Swirl;
+extern ShaderFxTypeInfo shaderfx_Type_Wave;
+
+/* FX_shaderfx_util.c */
+void shaderfx_type_init(ShaderFxTypeInfo *types[]);
+
+#endif /* __FX_SHADER_TYPES_H__ */
diff --git a/source/blender/shader_fx/intern/FX_shader_blur.c b/source/blender/shader_fx/intern/FX_shader_blur.c
new file mode 100644
index 00000000000..128ebba8875
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_blur.c
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_blur.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ BlurShaderFxData *gpfx = (BlurShaderFxData *)fx;
+ ARRAY_SET_ITEMS(gpfx->radius, 1, 1);
+ gpfx->samples = 4;
+ gpfx->coc = 0.025f;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Blur = {
+ /* name */ "Blur",
+ /* structName */ "BlurShaderFxData",
+ /* structSize */ sizeof(BlurShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ eShaderFxTypeFlag_Single,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_colorize.c b/source/blender/shader_fx/intern/FX_shader_colorize.c
new file mode 100644
index 00000000000..edf276b842c
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_colorize.c
@@ -0,0 +1,69 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_colorize.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_shader_fx_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ ColorizeShaderFxData *gpfx = (ColorizeShaderFxData *)fx;
+ ARRAY_SET_ITEMS(gpfx->low_color, 0.0f, 0.0f, 0.0f, 1.0f);
+ ARRAY_SET_ITEMS(gpfx->high_color, 1.0f, 1.0f, 1.0f, 1.0f);
+ gpfx->mode = eShaderFxColorizeMode_GrayScale;
+ gpfx->factor = 0.5f;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Colorize = {
+ /* name */ "Colorize",
+ /* structName */ "ColorizeShaderFxData",
+ /* structSize */ sizeof(ColorizeShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_flip.c b/source/blender/shader_fx/intern/FX_shader_flip.c
new file mode 100644
index 00000000000..404e2f8160e
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_flip.c
@@ -0,0 +1,69 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_flip.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ FlipShaderFxData *gpfx = (FlipShaderFxData *)fx;
+ gpfx->flag |= FX_FLIP_HORIZONTAL;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Flip = {
+ /* name */ "Flip",
+ /* structName */ "FlipShaderFxData",
+ /* structSize */ sizeof(FlipShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ eShaderFxTypeFlag_Single,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_glow.c b/source/blender/shader_fx/intern/FX_shader_glow.c
new file mode 100644
index 00000000000..cd513ed1f0a
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_glow.c
@@ -0,0 +1,78 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_glow.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_library_query.h"
+#include "BKE_modifier.h"
+#include "BKE_shader_fx.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *md)
+{
+ GlowShaderFxData *gpfx = (GlowShaderFxData *)md;
+ ARRAY_SET_ITEMS(gpfx->glow_color, 0.75f, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gpfx->select_color, 0.0f, 0.0f, 0.0f);
+ gpfx->threshold = 0.1f;
+
+ ARRAY_SET_ITEMS(gpfx->blur, 50, 0);
+ gpfx->samples = 16;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Glow = {
+ /* name */ "Glow",
+ /* structName */ "GlowShaderFxData",
+ /* structSize */ sizeof(GlowShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_light.c b/source/blender/shader_fx/intern/FX_shader_light.c
new file mode 100644
index 00000000000..9a17ea8ae5f
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_light.c
@@ -0,0 +1,104 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_light.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_library_query.h"
+#include "BKE_modifier.h"
+#include "BKE_shader_fx.h"
+
+#include "FX_shader_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static void initData(ShaderFxData *fx)
+{
+ LightShaderFxData *gpfx = (LightShaderFxData *)fx;
+ gpfx->energy = 10.0f;
+ gpfx->ambient = 5.0f;
+ gpfx->object = NULL;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+static void updateDepsgraph(ShaderFxData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ LightShaderFxData *fxd = (LightShaderFxData *)md;
+ if (fxd->object != NULL) {
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_GEOMETRY, "Light ShaderFx");
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_TRANSFORM, "Light ShaderFx");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Light ShaderFx");
+}
+
+static bool isDisabled(ShaderFxData *fx, int UNUSED(userRenderParams))
+{
+ LightShaderFxData *fxd = (LightShaderFxData *)fx;
+
+ return !fxd->object;
+}
+
+static void foreachObjectLink(
+ ShaderFxData *fx, Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData)
+{
+ LightShaderFxData *fxd = (LightShaderFxData *)fx;
+
+ walk(userData, ob, &fxd->object, IDWALK_CB_NOP);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Light = {
+ /* name */ "Light",
+ /* structName */ "LightShaderFxData",
+ /* structSize */ sizeof(LightShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_pixel.c b/source/blender/shader_fx/intern/FX_shader_pixel.c
new file mode 100644
index 00000000000..8c5c38d6aa7
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_pixel.c
@@ -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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_pixel.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ PixelShaderFxData *gpfx = (PixelShaderFxData *)fx;
+ ARRAY_SET_ITEMS(gpfx->size, 5, 5);
+ ARRAY_SET_ITEMS(gpfx->rgba, 0.0f, 0.0f, 0.0f, 0.9f);
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Pixel = {
+ /* name */ "Pixelate",
+ /* structName */ "PixelShaderFxData",
+ /* structSize */ sizeof(PixelShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ eShaderFxTypeFlag_Single,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_rim.c b/source/blender/shader_fx/intern/FX_shader_rim.c
new file mode 100644
index 00000000000..f3bec9a9571
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_rim.c
@@ -0,0 +1,72 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_rim.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_shader_fx_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ RimShaderFxData *gpfx = (RimShaderFxData *)fx;
+ ARRAY_SET_ITEMS(gpfx->offset, 50, -100);
+ ARRAY_SET_ITEMS(gpfx->rim_rgb, 1.0f, 1.0f, 0.5f);
+ ARRAY_SET_ITEMS(gpfx->mask_rgb, 0.0f, 0.0f, 0.0f);
+ gpfx->mode = eShaderFxRimMode_Multiply;
+
+ ARRAY_SET_ITEMS(gpfx->blur, 0, 0);
+ gpfx->samples = 2;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Rim = {
+ /* name */ "Rim",
+ /* structName */ "RimShaderFxData",
+ /* structSize */ sizeof(RimShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_shadow.c b/source/blender/shader_fx/intern/FX_shader_shadow.c
new file mode 100644
index 00000000000..e3a9543fcb4
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_shadow.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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_shadow.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_library_query.h"
+#include "BKE_modifier.h"
+#include "BKE_shader_fx.h"
+
+#include "FX_shader_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static void initData(ShaderFxData *md)
+{
+ ShadowShaderFxData *gpfx = (ShadowShaderFxData *)md;
+ gpfx->rotation = 0.0f;
+ ARRAY_SET_ITEMS(gpfx->offset, 15, 20);
+ ARRAY_SET_ITEMS(gpfx->scale, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gpfx->shadow_rgba, 0.54f, 0.62f, 1.0f, 0.9f);
+
+ gpfx->amplitude = 10.0f;
+ gpfx->period = 20.0f;
+ gpfx->phase = 0.0f;
+ gpfx->orientation = 1;
+
+ ARRAY_SET_ITEMS(gpfx->blur, 5, 5);
+ gpfx->samples = 2;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+static void updateDepsgraph(ShaderFxData *fx, const ModifierUpdateDepsgraphContext *ctx)
+{
+ ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
+ if (fxd->object != NULL) {
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_GEOMETRY, "Shadow ShaderFx");
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_TRANSFORM, "Shadow ShaderFx");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Shadow ShaderFx");
+}
+
+static bool isDisabled(ShaderFxData *fx, int UNUSED(userRenderParams))
+{
+ ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
+
+ return (!fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT);
+}
+
+static void foreachObjectLink(
+ ShaderFxData *fx, Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData)
+{
+ ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
+
+ walk(userData, ob, &fxd->object, IDWALK_CB_NOP);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Shadow = {
+ /* name */ "Shadow",
+ /* structName */ "ShadowShaderFxData",
+ /* structSize */ sizeof(ShadowShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_swirl.c b/source/blender/shader_fx/intern/FX_shader_swirl.c
new file mode 100644
index 00000000000..9667f466eec
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_swirl.c
@@ -0,0 +1,103 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_swirl.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math_base.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_library_query.h"
+#include "BKE_modifier.h"
+#include "BKE_shader_fx.h"
+
+#include "FX_shader_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+static void initData(ShaderFxData *md)
+{
+ SwirlShaderFxData *gpmd = (SwirlShaderFxData *)md;
+ gpmd->radius = 100;
+ gpmd->angle = M_PI_2;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+static void updateDepsgraph(ShaderFxData *fx, const ModifierUpdateDepsgraphContext *ctx)
+{
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+ if (fxd->object != NULL) {
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_GEOMETRY, "Swirl ShaderFx");
+ DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_TRANSFORM, "Swirl ShaderFx");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Swirl ShaderFx");
+}
+
+static bool isDisabled(ShaderFxData *fx, int UNUSED(userRenderParams))
+{
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+
+ return !fxd->object;
+}
+
+static void foreachObjectLink(
+ ShaderFxData *fx, Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData)
+{
+ SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
+
+ walk(userData, ob, &fxd->object, IDWALK_CB_NOP);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Swirl = {
+ /* name */ "Swirl",
+ /* structName */ "SwirlShaderFxData",
+ /* structSize */ sizeof(SwirlShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/shader_fx/intern/FX_shader_util.c b/source/blender/shader_fx/intern/FX_shader_util.c
new file mode 100644
index 00000000000..b74ff45b991
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_util.c
@@ -0,0 +1,57 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_util.c
+ * \ingroup shader_fx
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_shader_fx.h"
+
+#include "FX_shader_types.h"
+#include "FX_shader_util.h"
+
+void shaderfx_type_init(ShaderFxTypeInfo *types[])
+{
+#define INIT_FX_TYPE(typeName) (types[eShaderFxType_##typeName] = &shaderfx_Type_##typeName)
+ INIT_FX_TYPE(Blur);
+ INIT_FX_TYPE(Colorize);
+ INIT_FX_TYPE(Flip);
+ INIT_FX_TYPE(Glow);
+ INIT_FX_TYPE(Light);
+ INIT_FX_TYPE(Pixel);
+ INIT_FX_TYPE(Rim);
+ INIT_FX_TYPE(Shadow);
+ INIT_FX_TYPE(Swirl);
+ INIT_FX_TYPE(Wave);
+#undef INIT_FX_TYPE
+}
diff --git a/source/blender/blenkernel/BKE_bullet.h b/source/blender/shader_fx/intern/FX_shader_util.h
index 84fcd20374f..e2fdcd6fb4c 100644
--- a/source/blender/blenkernel/BKE_bullet.h
+++ b/source/blender/shader_fx/intern/FX_shader_util.h
@@ -24,20 +24,13 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __BKE_BULLET_H__
-#define __BKE_BULLET_H__
-/** \file BKE_bullet.h
- * \ingroup bke
+/** \file blender/shader_fx/intern/FX_shader_util.h
+ * \ingroup shader_fx
*/
-struct BulletSoftBody;
+#ifndef __FX_SHADER_UTIL_H__
+#define __FX_SHADER_UTIL_H__
-/* allocates and initializes general main data */
-extern struct BulletSoftBody *bsbNew(void);
-
-/* frees internal data and softbody itself */
-extern void bsbFree(struct BulletSoftBody *sb);
-
-#endif
+#endif /* __FX_SHADER_UTIL_H__ */
diff --git a/source/blender/shader_fx/intern/FX_shader_wave.c b/source/blender/shader_fx/intern/FX_shader_wave.c
new file mode 100644
index 00000000000..ea4563a00e1
--- /dev/null
+++ b/source/blender/shader_fx/intern/FX_shader_wave.c
@@ -0,0 +1,71 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/shader_fx/intern/FX_shader_wave.c
+ * \ingroup shader_fx
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "FX_shader_types.h"
+
+static void initData(ShaderFxData *fx)
+{
+ WaveShaderFxData *gpfx = (WaveShaderFxData *)fx;
+ gpfx->amplitude = 10.0f;
+ gpfx->period = 20.0f;
+ gpfx->phase = 0.0f;
+ gpfx->orientation = 1;
+}
+
+static void copyData(const ShaderFxData *md, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_generic(md, target);
+}
+
+ShaderFxTypeInfo shaderfx_Type_Wave = {
+ /* name */ "Wave Distorsion",
+ /* structName */ "WaveShaderFxData",
+ /* structSize */ sizeof(WaveShaderFxData),
+ /* type */ eShaderFxType_GpencilType,
+ /* flags */ eShaderFxTypeFlag_Single,
+
+ /* copyData */ copyData,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+};
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index ebf55c64906..173e32ea0bb 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -25,20 +25,23 @@
set(INC
.
+ gizmo
+ gizmo/intern
../blenfont
../blenkernel
../blenlib
../blenloader
../blentranslation
../compositor
+ ../depsgraph
../editors/include
+ ../draw
../gpu
../imbuf
../makesdna
../makesrna
../nodes
../render/extern/include
- ../../gameengine/BlenderRoutines
../../../intern/clog
../../../intern/ghost
../../../intern/guardedalloc
@@ -69,15 +72,28 @@ set(SRC
intern/wm_operator_props.c
intern/wm_operator_type.c
intern/wm_operators.c
+ intern/wm_panel_type.c
intern/wm_playanim.c
intern/wm_stereo.c
intern/wm_subwindow.c
+ intern/wm_toolsystem.c
intern/wm_tooltip.c
intern/wm_uilist_type.c
intern/wm_window.c
+ gizmo/intern/wm_gizmo.c
+ gizmo/intern/wm_gizmo_group.c
+ gizmo/intern/wm_gizmo_group_type.c
+ gizmo/intern/wm_gizmo_map.c
+ gizmo/intern/wm_gizmo_target_props.c
+ gizmo/intern/wm_gizmo_type.c
+ message_bus/intern/wm_message_bus.c
+ message_bus/intern/wm_message_bus_rna.c
+ message_bus/intern/wm_message_bus_static.c
WM_api.h
WM_keymap.h
+ WM_message.h
+ WM_toolsystem.h
WM_types.h
wm.h
wm_cursors.h
@@ -85,12 +101,18 @@ set(SRC
wm_event_system.h
wm_event_types.h
wm_files.h
- wm_subwindow.h
wm_window.h
+ gizmo/WM_gizmo_api.h
+ gizmo/WM_gizmo_types.h
+ gizmo/wm_gizmo_fn.h
+ gizmo/wm_gizmo_wmapi.h
+ gizmo/intern/wm_gizmo_intern.h
+ message_bus/intern/wm_message_bus_intern.h
+ message_bus/wm_message_bus.h
)
if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+ add_definitions(-DWITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
@@ -127,10 +149,6 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
-if(WITH_GAMEENGINE)
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
if(WITH_BUILDINFO)
add_definitions(-DWITH_BUILDINFO)
endif()
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 5ee7763272b..adf082982b7 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -47,12 +47,15 @@ extern "C" {
#endif
struct bContext;
+struct bToolRef_Runtime;
struct GHashIterator;
struct IDProperty;
struct wmEvent;
struct wmEventHandler;
struct wmGesture;
struct wmJob;
+struct wmMsgSubscribeKey;
+struct wmMsgSubscribeValue;
struct wmOperatorType;
struct wmOperator;
struct wmPaintCursor;
@@ -65,12 +68,19 @@ struct wmDrag;
struct ImBuf;
struct ImageFormatData;
struct ARegion;
+struct ScrArea;
+struct Main;
+struct ViewLayer;
+struct GPUViewport;
#ifdef WITH_INPUT_NDOF
struct wmNDOFMotionData;
#endif
typedef struct wmJob wmJob;
+typedef struct wmGizmo wmGizmo;
+typedef struct wmGizmoMap wmGizmoMap;
+typedef struct wmGizmoMapType wmGizmoMapType;
/* general API */
void WM_init_state_app_template_set(const char *app_template);
@@ -89,20 +99,49 @@ void WM_exit (struct bContext *C) ATTR_NORETURN;
void WM_main (struct bContext *C) ATTR_NORETURN;
-bool WM_init_game (struct bContext *C);
void WM_init_splash (struct bContext *C);
+void WM_init_opengl (struct Main *bmain);
void WM_check (struct bContext *C);
-int WM_window_pixels_x (struct wmWindow *win);
-int WM_window_pixels_y (struct wmWindow *win);
-bool WM_window_is_fullscreen (struct wmWindow *win);
+int WM_window_pixels_x(const struct wmWindow *win);
+int WM_window_pixels_y(const struct wmWindow *win);
+void WM_window_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
+void WM_window_screen_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
+bool WM_window_is_fullscreen(struct wmWindow *win);
+
+void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATTR_NONNULL();
+struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+struct WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+
+struct Scene *WM_window_get_active_scene(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_set_active_scene(struct Main *bmain, struct bContext *C, struct wmWindow *win,
+ struct Scene *scene_new) ATTR_NONNULL();
+struct WorkSpace *WM_window_get_active_workspace(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_set_active_workspace(struct bContext *C, struct wmWindow *win, struct WorkSpace *workspace) ATTR_NONNULL(1);
+struct WorkSpaceLayout *WM_window_get_active_layout(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_set_active_layout(
+ struct wmWindow *win, struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL(1);
+struct bScreen *WM_window_get_active_screen(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void WM_window_set_active_screen(struct wmWindow *win, struct WorkSpace *workspace, struct bScreen *screen) ATTR_NONNULL(1);
+
+struct ViewLayer *WM_window_get_active_view_layer(const struct wmWindow *win) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
+void WM_window_set_active_view_layer(struct wmWindow *win, struct ViewLayer *view_layer) ATTR_NONNULL(1);
+void WM_window_ensure_active_view_layer(struct wmWindow *win) ATTR_NONNULL(1);
+
+bool WM_window_is_temp_screen(const struct wmWindow *win) ATTR_WARN_UNUSED_RESULT;
+
+void *WM_opengl_context_create(void);
+void WM_opengl_context_dispose(void *context);
+void WM_opengl_context_activate(void *context);
+void WM_opengl_context_release(void *context);
/* defines for 'type' WM_window_open_temp */
enum {
WM_WINDOW_RENDER = 1,
WM_WINDOW_USERPREFS,
+ WM_WINDOW_DRIVERS,
// WM_WINDOW_FILESEL // UNUSED
};
@@ -110,9 +149,6 @@ struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
struct wmWindow *WM_window_open_temp(struct bContext *C, int x, int y, int sizex, int sizey, int type);
void WM_window_set_dpi(wmWindow *win);
- /* returns true if draw method is triple buffer */
-bool WM_is_draw_triple(struct wmWindow *win);
-
bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test);
@@ -127,6 +163,7 @@ void WM_lib_reload(struct Library *lib, struct bContext *C, struct Report
/* mouse cursors */
void WM_cursor_set(struct wmWindow *win, int curs);
+bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const ARegion *ar);
void WM_cursor_modal_set(struct wmWindow *win, int curs);
void WM_cursor_modal_restore(struct wmWindow *win);
void WM_cursor_wait (bool val);
@@ -136,12 +173,12 @@ void WM_cursor_time (struct wmWindow *win, int nr);
struct wmPaintCursor *WM_paint_cursor_activate(
struct wmWindowManager *wm,
+ short space_type, short region_type,
bool (*poll)(struct bContext *C),
void (*draw)(struct bContext *C, int, int, void *customdata),
void *customdata);
bool WM_paint_cursor_end(struct wmWindowManager *wm, struct wmPaintCursor *handle);
-void *WM_paint_cursor_customdata_get(struct wmPaintCursor *pc);
void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *ar);
@@ -163,6 +200,11 @@ struct wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers,
void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap);
+void WM_event_set_keymap_handler_callback(
+ struct wmEventHandler *handler,
+ void (keymap_tag)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data),
+ void *user_data);
+
typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata);
typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);
@@ -181,6 +223,9 @@ void WM_event_free_ui_handler_all(
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove);
struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
+void WM_event_modal_handler_area_replace(wmWindow *win, const struct ScrArea *old_area, struct ScrArea *new_area);
+void WM_event_modal_handler_region_replace(wmWindow *win, const struct ARegion *old_region, struct ARegion *new_region);
+
void WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
/* handler flag */
@@ -239,9 +284,11 @@ int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext);
int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
void WM_menu_name_call(struct bContext *C, const char *menu_name, short context);
+int WM_enum_search_invoke_previews(struct bContext *C, struct wmOperator *op, short prv_cols, short prv_rows);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
/* invoke callback, confirm menu + exec */
-int WM_operator_confirm (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+int WM_operator_confirm(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+int WM_operator_confirm_or_exec(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
/* invoke callback, file selector "filepath" unset + exec */
int WM_operator_filesel (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFormatData *im_format);
@@ -289,7 +336,11 @@ void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperato
void WM_operator_properties_clear(struct PointerRNA *ptr);
void WM_operator_properties_free(struct PointerRNA *ptr);
+bool WM_operator_check_ui_empty(struct wmOperatorType *ot);
bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname);
+
+IDProperty *WM_operator_last_properties_ensure_idprops(struct wmOperatorType *ot);
+void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct PointerRNA *ptr);
wmOperator *WM_operator_last_redo(const struct bContext *C);
ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, const short idcode);
@@ -298,16 +349,17 @@ bool WM_operator_last_properties_store(struct wmOperator *op);
/* wm_operator_props.c */
+void WM_operator_properties_confirm_or_exec(struct wmOperatorType *ot);
void WM_operator_properties_filesel(
struct wmOperatorType *ot, int filter, short type, short action,
short flag, short display, short sort);
void WM_operator_properties_border(struct wmOperatorType *ot);
void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect);
void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect);
-void WM_operator_properties_gesture_border_ex(struct wmOperatorType *ot, bool deselect, bool extend);
-void WM_operator_properties_gesture_border(struct wmOperatorType *ot);
-void WM_operator_properties_gesture_border_select(struct wmOperatorType *ot);
-void WM_operator_properties_gesture_border_zoom(struct wmOperatorType *ot);
+void WM_operator_properties_gesture_box_ex(struct wmOperatorType *ot, bool deselect, bool extend);
+void WM_operator_properties_gesture_box(struct wmOperatorType *ot);
+void WM_operator_properties_gesture_box_select(struct wmOperatorType *ot);
+void WM_operator_properties_gesture_box_zoom(struct wmOperatorType *ot);
void WM_operator_properties_gesture_lasso_ex(struct wmOperatorType *ot, bool deselect, bool extend);
void WM_operator_properties_gesture_lasso(struct wmOperatorType *ot);
void WM_operator_properties_gesture_lasso_select(struct wmOperatorType *ot);
@@ -321,6 +373,8 @@ void WM_operator_properties_select_action(struct wmOperatorType *ot, int
void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int default_action);
void WM_operator_properties_select_random(struct wmOperatorType *ot);
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op);
+void WM_operator_properties_select_operation(struct wmOperatorType *ot);
+void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot);
struct CheckerIntervalParams {
int nth; /* bypass when set to zero */
int skip;
@@ -332,14 +386,6 @@ void WM_operator_properties_checker_interval_from_op(
bool WM_operator_properties_checker_interval_test(
const struct CheckerIntervalParams *op_params, int depth);
-
-/* MOVE THIS SOMEWHERE ELSE */
-#define SEL_TOGGLE 0
-#define SEL_SELECT 1
-#define SEL_DESELECT 2
-#define SEL_INVERT 3
-
-
/* flags for WM_operator_properties_filesel */
#define WM_FILESEL_RELPATH (1 << 0)
@@ -348,7 +394,6 @@ bool WM_operator_properties_checker_interval_test(
#define WM_FILESEL_FILEPATH (1 << 3)
#define WM_FILESEL_FILES (1 << 4)
-
/* operator as a python command (resultuing string must be freed) */
char *WM_operator_pystring_ex(struct bContext *C, struct wmOperator *op,
const bool all_args, const bool macro_args,
@@ -360,7 +405,7 @@ char *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struc
void WM_operator_bl_idname(char *to, const char *from);
void WM_operator_py_idname(char *to, const char *from);
bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname);
-
+const char *WM_context_member_from_ptr(struct bContext *C, const struct PointerRNA *ptr);
/* wm_operator_type.c */
struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet);
@@ -371,6 +416,14 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, vo
void WM_operatortype_remove_ptr(struct wmOperatorType *ot);
bool WM_operatortype_remove(const char *idname);
void WM_operatortype_last_properties_clear_all(void);
+void WM_operatortype_props_advanced_begin(struct wmOperatorType *ot);
+void WM_operatortype_props_advanced_end(struct wmOperatorType *ot);
+
+#define WM_operatortype_prop_tag(property, tags) \
+ { \
+ CHECK_TYPE(tags, eOperatorPropTags); \
+ RNA_def_property_tags(prop, tags); \
+ } (void)0
struct wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag);
struct wmOperatorTypeMacro *WM_operatortype_macro_define(struct wmOperatorType *ot, const char *idname);
@@ -390,10 +443,17 @@ void WM_menutype_freelink(struct MenuType *mt);
void WM_menutype_free(void);
bool WM_menutype_poll(struct bContext *C, struct MenuType *mt);
+/* wm_panel_type.c */
+void WM_paneltype_init(void);
+void WM_paneltype_clear(void);
+struct PanelType *WM_paneltype_find(const char *idname, bool quiet);
+bool WM_paneltype_add(struct PanelType *mt);
+void WM_paneltype_remove(struct PanelType *mt);
+
/* wm_gesture_ops.c */
-int WM_gesture_border_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
-int WM_gesture_border_modal (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
-void WM_gesture_border_cancel(struct bContext *C, struct wmOperator *op);
+int WM_gesture_box_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+int WM_gesture_box_modal (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+void WM_gesture_box_cancel(struct bContext *C, struct wmOperator *op);
int WM_gesture_circle_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_gesture_circle_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
void WM_gesture_circle_cancel(struct bContext *C, struct wmOperator *op);
@@ -427,21 +487,27 @@ void WM_drag_free(struct wmDrag *drag);
void WM_drag_free_list(struct ListBase *lb);
struct wmDropBox *WM_dropbox_add(
- ListBase *lb, const char *idname, bool (*poll)(struct bContext *, struct wmDrag *, const struct wmEvent *event),
+ ListBase *lb, const char *idname,
+ bool (*poll)(struct bContext *, struct wmDrag *, const struct wmEvent *event, const char **),
void (*copy)(struct wmDrag *, struct wmDropBox *));
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
- /* Set a subwindow active in pixelspace view, with optional scissor subset */
-void wmSubWindowSet (struct wmWindow *win, int swinid);
-void wmSubWindowScissorSet (struct wmWindow *win, int swinid, const struct rcti *srct, bool srct_pad);
+ /* ID drag and drop */
+void WM_drag_add_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent);
+struct ID *WM_drag_ID(const struct wmDrag *drag, short idcode);
+struct ID *WM_drag_ID_from_event(const struct wmEvent *event, short idcode);
+
+ /* Set OpenGL viewport and scissor */
+void wmViewport(const struct rcti *rect);
+void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct);
+void wmWindowViewport(struct wmWindow *win);
- /* OpenGL utilities with safety check + working in modelview matrix mode */
-void wmFrustum (float x1, float x2, float y1, float y2, float n, float f);
-void wmOrtho (float x1, float x2, float y1, float y2, float n, float f);
+ /* OpenGL utilities with safety check */
void wmOrtho2 (float x1, float x2, float y1, float y2);
/* use for conventions (avoid hard-coded offsets all over) */
void wmOrtho2_region_pixelspace(const struct ARegion *ar);
void wmOrtho2_pixelspace(const float x, const float y);
+void wmGetProjectionMatrix(float mat[4][4], const struct rcti *winrct);
/* threaded Jobs Manager */
enum {
@@ -471,7 +537,10 @@ enum {
WM_JOB_TYPE_POINTCACHE,
WM_JOB_TYPE_DPAINT_BAKE,
WM_JOB_TYPE_ALEMBIC,
- /* add as needed, seq proxy build
+ WM_JOB_TYPE_SHADER_COMPILATION,
+ WM_JOB_TYPE_STUDIOLIGHT,
+ WM_JOB_TYPE_LIGHT_BAKE,
+ /* add as needed, screencast, seq proxy build
* if having hard coded values is a problem */
};
@@ -519,11 +588,16 @@ void WM_progress_clear(struct wmWindow *win);
/* Draw (for screenshot) */
void *WM_draw_cb_activate(
struct wmWindow *win,
- void(*draw)(const struct wmWindow *, void *),
+ void (*draw)(const struct wmWindow *, void *),
void *customdata);
void WM_draw_cb_exit(struct wmWindow *win, void *handle);
void WM_redraw_windows(struct bContext *C);
+ /* Region drawing */
+void WM_draw_region_free(struct ARegion *ar);
+struct GPUViewport *WM_draw_region_get_viewport(struct ARegion *ar, int view);
+struct GPUViewport *WM_draw_region_get_bound_viewport(struct ARegion *ar);
+
void WM_main_playanim(int argc, const char **argv);
/* debugging only, convenience function to write on crash */
@@ -547,9 +621,26 @@ bool WM_event_is_tablet(const struct wmEvent *event);
bool WM_event_is_ime_switch(const struct wmEvent *event);
#endif
+const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win, int button_index, int type_index);
+void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win);
+
+void WM_window_status_area_tag_redraw(struct wmWindow *win);
+struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc);
+bool WM_window_modal_keymap_status_draw(
+ struct bContext *C, struct wmWindow *win,
+ struct uiLayout *layout);
+
/* wm_tooltip.c */
-typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *, struct ARegion *, bool *);
+typedef struct ARegion *(*wmTooltipInitFn)(
+ struct bContext *C, struct ARegion *ar,
+ int *pass, double *r_pass_delay, bool *r_exit_on_event);
+void WM_tooltip_immediate_init(
+ struct bContext *C, struct wmWindow *win, struct ARegion *ar,
+ wmTooltipInitFn init);
+void WM_tooltip_timer_init_ex(
+ struct bContext *C, struct wmWindow *win, struct ARegion *ar,
+ wmTooltipInitFn init, double delay);
void WM_tooltip_timer_init(
struct bContext *C, struct wmWindow *win, struct ARegion *ar,
wmTooltipInitFn init);
@@ -557,6 +648,7 @@ void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win);
void WM_tooltip_clear(struct bContext *C, struct wmWindow *win);
void WM_tooltip_init(struct bContext *C, struct wmWindow *win);
void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win);
+double WM_tooltip_time_closed(void);
#ifdef __cplusplus
}
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 0538df83c60..7f7612cea35 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -42,9 +42,13 @@ struct EnumPropertyItem;
/* Key Configuration */
-wmKeyConfig *WM_keyconfig_new (struct wmWindowManager *wm, const char *idname);
+void WM_keyconfig_init (struct bContext *C);
+void WM_keyconfig_reload (struct bContext *C);
+
+wmKeyConfig *WM_keyconfig_new (struct wmWindowManager *wm, const char *idname, bool user_defined);
wmKeyConfig *WM_keyconfig_new_user(struct wmWindowManager *wm, const char *idname);
bool WM_keyconfig_remove (struct wmWindowManager *wm, struct wmKeyConfig *keyconf);
+void WM_keyconfig_clear (struct wmKeyConfig *keyconf);
void WM_keyconfig_free (struct wmKeyConfig *keyconf);
void WM_keyconfig_set_active(struct wmWindowManager *wm, const char *idname);
@@ -55,8 +59,7 @@ void WM_keyconfig_update_operatortype(void);
/* Keymap */
-void WM_keymap_init (struct bContext *C);
-void WM_keymap_free (struct wmKeyMap *keymap);
+void WM_keymap_clear (struct wmKeyMap *keymap);
wmKeyMapItem *WM_keymap_verify_item(
struct wmKeyMap *keymap, const char *idname, int type,
@@ -64,13 +67,17 @@ wmKeyMapItem *WM_keymap_verify_item(
wmKeyMapItem *WM_keymap_add_item(
struct wmKeyMap *keymap, const char *idname, int type,
int val, int modifier, int keymodifier);
+wmKeyMapItem *WM_keymap_add_item_copy(
+ struct wmKeyMap *keymap, wmKeyMapItem *kmi_src);
bool WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
int WM_keymap_item_to_string(wmKeyMapItem *kmi, const bool compact, char *result, const int result_len);
wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid);
+wmKeyMap *WM_keymap_list_find_spaceid_or_empty(ListBase *lb, const char *idname, int spaceid, int regionid);
wmKeyMap *WM_keymap_ensure(struct wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid);
wmKeyMap *WM_keymap_find_all(const struct bContext *C, const char *idname, int spaceid, int regionid);
+wmKeyMap *WM_keymap_find_all_spaceid_or_empty(const struct bContext *C, const char *idname, int spaceid, int regionid);
wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap);
bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap);
bool WM_keymap_poll(struct bContext *C, struct wmKeyMap *keymap);
@@ -87,9 +94,22 @@ wmKeyMapItem *WM_keymap_add_menu(
wmKeyMapItem *WM_keymap_add_menu_pie(
struct wmKeyMap *keymap, const char *idname, int type,
int val, int modifier, int keymodifier);
+wmKeyMapItem *WM_keymap_add_panel(
+ struct wmKeyMap *keymap, const char *idname, int type,
+ int val, int modifier, int keymodifier);
+wmKeyMapItem *WM_keymap_add_tool(
+ struct wmKeyMap *keymap, const char *idname, int type,
+ int val, int modifier, int keymodifier);
+
+void WM_keymap_add_context_enum_set_items(
+ wmKeyMap *keymap, const struct EnumPropertyItem *items, const char *data_path,
+ int type_start, int val, int modifier, int keymodifier);
+wmKeyMap *WM_keymap_guess_from_context(const struct bContext *C);
wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname);
+void WM_keymap_fix_linking(void);
+
/* Modal Keymap */
int WM_modalkeymap_items_to_string(
diff --git a/source/blender/windowmanager/WM_message.h b/source/blender/windowmanager/WM_message.h
new file mode 100644
index 00000000000..48197ae99cd
--- /dev/null
+++ b/source/blender/windowmanager/WM_message.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/WM_message.h
+ * \ingroup wm
+ */
+
+#ifndef __WM_MESSAGE_H__
+#define __WM_MESSAGE_H__
+
+#include "message_bus/wm_message_bus.h"
+
+#endif /* __WM_MESSAGE_H__ */
diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h
new file mode 100644
index 00000000000..4318179c203
--- /dev/null
+++ b/source/blender/windowmanager/WM_toolsystem.h
@@ -0,0 +1,121 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __WM_TOOLSYSTEM_H__
+#define __WM_TOOLSYSTEM_H__
+
+/** \file blender/windowmanager/WM_toolsystem.h
+ * \ingroup wm
+ */
+
+/* dna-savable wmStructs here */
+#include "BLI_compiler_attrs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bContext;
+struct bToolRef_Runtime;
+struct IDProperty;
+struct wmMsgSubscribeKey;
+struct wmMsgSubscribeValue;
+struct wmOperatorType;
+struct PointerRNA;
+struct ScrArea;
+struct Main;
+struct StructRNA;
+struct WorkSpace;
+
+/* wm_toolsystem.c */
+
+#define WM_TOOLSYSTEM_SPACE_MASK ( \
+ (1 << SPACE_IMAGE) | \
+ (1 << SPACE_NODE) | \
+ (1 << SPACE_VIEW3D) )
+
+/* Values that define a categoey of active tool. */
+typedef struct bToolKey { int space_type; int mode; } bToolKey;
+
+struct bToolRef *WM_toolsystem_ref_from_context(struct bContext *C);
+struct bToolRef *WM_toolsystem_ref_find(struct WorkSpace *workspace, const bToolKey *tkey);
+bool WM_toolsystem_ref_ensure(
+ struct WorkSpace *workspace, const bToolKey *tkey,
+ struct bToolRef **r_tref);
+struct bToolRef *WM_toolsystem_ref_set_by_name(
+ struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey,
+ const char *name, bool cycle);
+
+struct bToolRef_Runtime *WM_toolsystem_runtime_from_context(struct bContext *C);
+struct bToolRef_Runtime *WM_toolsystem_runtime_find(struct WorkSpace *workspace, const bToolKey *tkey);
+
+void WM_toolsystem_unlink(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
+void WM_toolsystem_refresh(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
+void WM_toolsystem_reinit(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey);
+
+void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace);
+void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace);
+void WM_toolsystem_reinit_all(struct bContext *C, struct wmWindow *win);
+
+void WM_toolsystem_ref_set_from_runtime(
+ struct bContext *C, struct WorkSpace *workspace, struct bToolRef *tref,
+ const struct bToolRef_Runtime *tool, const char *idname);
+
+void WM_toolsystem_ref_sync_from_context(
+ struct Main *bmain, struct WorkSpace *workspace, struct bToolRef *tref);
+
+void WM_toolsystem_init(struct bContext *C);
+
+int WM_toolsystem_mode_from_spacetype(
+ struct ViewLayer *view_layer, struct ScrArea *sa, int space_type);
+bool WM_toolsystem_key_from_context(
+ struct ViewLayer *view_layer, struct ScrArea *sa, bToolKey *tkey);
+
+void WM_toolsystem_update_from_context_view3d(struct bContext *C);
+void WM_toolsystem_update_from_context(
+ struct bContext *C, struct WorkSpace *workspace, struct ViewLayer *view_layer,
+ struct ScrArea *sa);
+
+bool WM_toolsystem_active_tool_is_brush(const struct bContext *C);
+
+void WM_toolsystem_do_msg_notify_tag_refresh(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+
+struct IDProperty *WM_toolsystem_ref_properties_ensure_idprops(struct bToolRef *tref);
+void WM_toolsystem_ref_properties_ensure_ex(
+ struct bToolRef *tref, const char *idname, struct StructRNA *type, struct PointerRNA *r_ptr);
+
+#define WM_toolsystem_ref_properties_ensure_from_operator(tref, ot, r_ptr) \
+ WM_toolsystem_ref_properties_ensure_ex(tref, (ot)->idname, (ot)->srna, r_ptr)
+#define WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, ot, r_ptr) \
+ WM_toolsystem_ref_properties_ensure_ex(tref, (ot)->idname, (ot)->srna, r_ptr)
+
+void WM_toolsystem_ref_properties_init_for_keymap(
+ struct bToolRef *tref, struct PointerRNA *dst_ptr, struct PointerRNA *src_ptr, struct wmOperatorType *ot);
+
+void WM_toolsystem_refresh_active(struct bContext *C);
+
+void WM_toolsystem_refresh_screen_area(struct WorkSpace *workspace, struct ViewLayer *view_layer, struct ScrArea *sa);
+void WM_toolsystem_refresh_screen_all(struct Main *bmain);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WM_TOOLSYSTEM_API_H__ */
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 918188117eb..0036ae7834d 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -109,16 +109,23 @@ extern "C" {
struct bContext;
struct wmEvent;
struct wmWindowManager;
+struct wmMsgBus;
struct wmOperator;
+struct ID;
struct ImBuf;
#include "RNA_types.h"
#include "DNA_listBase.h"
+#include "DNA_vec_types.h"
#include "BLI_compiler_attrs.h"
/* exported types for WM */
#include "wm_cursors.h"
#include "wm_event_types.h"
+#include "gizmo/WM_gizmo_types.h"
+
+/* Include external gizmo API's */
+#include "gizmo/WM_gizmo_api.h"
/* ************** wmOperatorType ************************ */
@@ -139,6 +146,7 @@ enum {
OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */
OPTYPE_UNDO_GROUPED = (1 << 8), /* Special type of undo which doesn't store itself multiple times */
+ OPTYPE_USE_EVAL_DATA = (1 << 9), /* Need evaluated data (i.e. a valid, up-to-date depsgraph for current context) */
};
/* context to call operator in for WM_operator_name_call */
@@ -160,6 +168,12 @@ enum {
WM_OP_EXEC_SCREEN
};
+/* property tags for RNA_OperatorProperties */
+typedef enum eOperatorPropTags {
+ OP_PROP_TAG_ADVANCED = (1 << 0),
+} eOperatorPropTags;
+#define OP_PROP_TAG_ADVANCED ((eOperatorPropTags)OP_PROP_TAG_ADVANCED)
+
/* ************** wmKeyMap ************************ */
/* modifier */
@@ -204,7 +218,6 @@ typedef struct wmNotifier {
struct wmWindowManager *wm;
struct wmWindow *window;
- int swinid; /* can't rely on this, notifiers can be added without context, swinid of 0 */
unsigned int category, data, subtype, action;
void *reference;
@@ -224,7 +237,7 @@ typedef struct wmNotifier {
#define NOTE_CATEGORY 0xFF000000
#define NC_WM (1<<24)
#define NC_WINDOW (2<<24)
-#define NC_SCREEN (3<<24)
+#define NC_SCREEN (3<<24)
#define NC_SCENE (4<<24)
#define NC_OBJECT (5<<24)
#define NC_MATERIAL (6<<24)
@@ -246,6 +259,7 @@ typedef struct wmNotifier {
#define NC_GPENCIL (22<<24)
#define NC_LINESTYLE (23<<24)
#define NC_CAMERA (24<<24)
+#define NC_LIGHTPROBE (25<<24)
/* data type, 256 entries is enough, it can overlap */
#define NOTE_DATA 0x00FF0000
@@ -258,14 +272,16 @@ typedef struct wmNotifier {
#define ND_JOB (5<<16)
#define ND_UNDO (6<<16)
- /* NC_SCREEN screen */
-#define ND_SCREENBROWSE (1<<16)
-#define ND_SCREENDELETE (2<<16)
+ /* NC_SCREEN */
+#define ND_LAYOUTBROWSE (1<<16)
+#define ND_LAYOUTDELETE (2<<16)
#define ND_ANIMPLAY (4<<16)
#define ND_GPENCIL (5<<16)
#define ND_EDITOR_CHANGED (6<<16) /*sent to new editors after switching to them*/
-#define ND_SCREENSET (7<<16)
+#define ND_LAYOUTSET (7<<16)
#define ND_SKETCH (8<<16)
+#define ND_WORKSPACE_SET (9<<16)
+#define ND_WORKSPACE_DELETE (10<<16)
/* NC_SCENE Scene */
#define ND_SCENEBROWSE (1<<16)
@@ -410,7 +426,7 @@ typedef struct wmGesture {
struct wmGesture *next, *prev;
int event_type; /* event->type */
int type; /* gesture type define */
- int swinid; /* initial subwindow id where it started */
+ rcti winrct; /* bounds of region to draw gesture within */
int points; /* optional, amount of points stored */
int points_alloc; /* optional, maximum amount of points stored */
int modal_state;
@@ -645,6 +661,12 @@ typedef enum wmDragFlags {
/* note: structs need not exported? */
+typedef struct wmDragID {
+ struct wmDragID *next, *prev;
+ struct ID *id;
+ struct ID *from_parent;
+} wmDragID;
+
typedef struct wmDrag {
struct wmDrag *next, *prev;
@@ -659,6 +681,8 @@ typedef struct wmDrag {
char opname[200]; /* if set, draws operator name*/
unsigned int flags;
+
+ ListBase ids; /* List of wmDragIDs, all are guaranteed to have the same ID type. */
} wmDrag;
/* dropboxes are like keymaps, part of the screen/area/region definition */
@@ -667,7 +691,7 @@ typedef struct wmDropBox {
struct wmDropBox *next, *prev;
/* test if the dropbox is active, then can print optype name */
- bool (*poll)(struct bContext *, struct wmDrag *, const wmEvent *);
+ bool (*poll)(struct bContext *, struct wmDrag *, const wmEvent *, const char **);
/* before exec, this copies drag info to wmDrop properties */
void (*copy)(struct wmDrag *, struct wmDropBox *);
@@ -694,9 +718,13 @@ typedef struct wmTooltipState {
/** The tooltip region. */
struct ARegion *region;
/** Create the tooltip region (assign to 'region'). */
- struct ARegion *(*init)(struct bContext *, struct ARegion *, bool *r_exit_on_event);
+ struct ARegion *(*init)(
+ struct bContext *C, struct ARegion *ar,
+ int *pass, double *pass_delay, bool *r_exit_on_event);
/** Exit on any event, not needed for buttons since their highlight state is used. */
bool exit_on_event;
+ /** Pass, use when we want multiple tips, count down to zero. */
+ int pass;
} wmTooltipState;
/* *************** migrated stuff, clean later? ************** */
@@ -713,6 +741,9 @@ extern struct CLG_LogRef *WM_LOG_OPERATORS;
extern struct CLG_LogRef *WM_LOG_HANDLERS;
extern struct CLG_LogRef *WM_LOG_EVENTS;
extern struct CLG_LogRef *WM_LOG_KEYMAPS;
+extern struct CLG_LogRef *WM_LOG_TOOLS;
+extern struct CLG_LogRef *WM_LOG_MSGBUS_PUB;
+extern struct CLG_LogRef *WM_LOG_MSGBUS_SUB;
#ifdef __cplusplus
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
new file mode 100644
index 00000000000..9f05437eaa8
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -0,0 +1,354 @@
+/*
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/WM_gizmo_api.h
+ * \ingroup wm
+ *
+ * \name Gizmo API
+ * \brief API for external use of wmGizmo types.
+ *
+ * Only included in WM_api.h
+ */
+
+
+#ifndef __WM_GIZMO_API_H__
+#define __WM_GIZMO_API_H__
+
+struct ARegion;
+struct GHashIterator;
+struct IDProperty;
+struct Main;
+struct PropertyRNA;
+struct wmKeyConfig;
+struct wmGizmo;
+struct wmGizmoProperty;
+struct wmGizmoPropertyType;
+struct wmGizmoType;
+struct wmGizmoGroup;
+struct wmGizmoGroupType;
+struct wmGizmoMap;
+struct wmGizmoMapType;
+struct wmGizmoMapType_Params;
+struct wmMsgSubscribeKey;
+struct wmMsgSubscribeValue;
+
+#include "wm_gizmo_fn.h"
+
+/* -------------------------------------------------------------------- */
+/* wmGizmo */
+
+struct wmGizmo *WM_gizmo_new_ptr(
+ const struct wmGizmoType *gzt, struct wmGizmoGroup *gzgroup,
+ struct PointerRNA *properties);
+struct wmGizmo *WM_gizmo_new(
+ const char *idname, struct wmGizmoGroup *gzgroup,
+ struct PointerRNA *properties);
+void WM_gizmo_free(struct wmGizmo *gz);
+void WM_gizmo_unlink(
+ ListBase *gizmolist, struct wmGizmoMap *gzmap, struct wmGizmo *gz,
+ struct bContext *C);
+
+void WM_gizmo_name_set(struct wmGizmoGroup *gzgroup, struct wmGizmo *gz, const char *name);
+
+bool WM_gizmo_select_unlink(struct wmGizmoMap *gzmap, struct wmGizmo *gz);
+bool WM_gizmo_select_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select);
+void WM_gizmo_highlight_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz);
+
+void WM_gizmo_modal_set_from_setup(
+ struct wmGizmoMap *gzmap, struct bContext *C,
+ struct wmGizmo *gz, int part_index, const struct wmEvent *event);
+
+struct wmGizmoOpElem *WM_gizmo_operator_get(
+ struct wmGizmo *gz, int part_index);
+struct PointerRNA *WM_gizmo_operator_set(
+ struct wmGizmo *gz, int part_index,
+ struct wmOperatorType *ot, struct IDProperty *properties);
+
+/* callbacks */
+void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn);
+
+void WM_gizmo_set_matrix_location(
+ struct wmGizmo *gz, const float origin[3]);
+void WM_gizmo_set_matrix_rotation_from_z_axis(
+ struct wmGizmo *gz, const float z_axis[3]);
+void WM_gizmo_set_matrix_rotation_from_yz_axis(
+ struct wmGizmo *gz, const float y_axis[3], const float z_axis[3]);
+
+void WM_gizmo_set_matrix_offset_location(
+ struct wmGizmo *gz, const float origin[3]);
+void WM_gizmo_set_matrix_offset_rotation_from_z_axis(
+ struct wmGizmo *gz, const float z_axis[3]);
+void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(
+ struct wmGizmo *gz, const float y_axis[3], const float z_axis[3]);
+
+void WM_gizmo_set_flag(struct wmGizmo *gz, const int flag, const bool enable);
+void WM_gizmo_set_scale(struct wmGizmo *gz, const float scale);
+void WM_gizmo_set_line_width(struct wmGizmo *gz, const float line_width);
+
+void WM_gizmo_get_color(const struct wmGizmo *gz, float color[4]);
+void WM_gizmo_set_color(struct wmGizmo *gz, const float color[4]);
+void WM_gizmo_get_color_highlight(const struct wmGizmo *gz, float color_hi[4]);
+void WM_gizmo_set_color_highlight(struct wmGizmo *gz, const float color[4]);
+
+/**
+ * Leaving values NULL use values from #wmGizmo.
+ */
+struct WM_GizmoMatrixParams {
+ const float(*matrix_space)[4];
+ const float(*matrix_basis)[4];
+ const float(*matrix_offset)[4];
+ const float *scale_final;
+};
+
+void WM_gizmo_calc_matrix_final_params(
+ const struct wmGizmo *gz, const struct WM_GizmoMatrixParams *params,
+ float r_mat[4][4]);
+void WM_gizmo_calc_matrix_final_no_offset(
+ const struct wmGizmo *gz, float r_mat[4][4]);
+
+void WM_gizmo_calc_matrix_final(
+ const struct wmGizmo *gz, float r_mat[4][4]);
+
+/* properties */
+void WM_gizmo_properties_create_ptr(struct PointerRNA *ptr, struct wmGizmoType *gzt);
+void WM_gizmo_properties_create(struct PointerRNA *ptr, const char *opstring);
+void WM_gizmo_properties_alloc(struct PointerRNA **ptr, struct IDProperty **properties, const char *wtstring);
+void WM_gizmo_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+bool WM_gizmo_properties_default(struct PointerRNA *ptr, const bool do_update);
+void WM_gizmo_properties_reset(struct wmGizmo *op);
+void WM_gizmo_properties_clear(struct PointerRNA *ptr);
+void WM_gizmo_properties_free(struct PointerRNA *ptr);
+
+
+/* wm_gizmo_type.c */
+const struct wmGizmoType *WM_gizmotype_find(const char *idname, bool quiet);
+void WM_gizmotype_append(void (*wtfunc)(struct wmGizmoType *));
+void WM_gizmotype_append_ptr(void (*mnpfunc)(struct wmGizmoType *, void *), void *userdata);
+bool WM_gizmotype_remove(struct bContext *C, struct Main *bmain, const char *idname);
+void WM_gizmotype_remove_ptr(struct bContext *C, struct Main *bmain, struct wmGizmoType *gzt);
+void WM_gizmotype_iter(struct GHashIterator *ghi);
+
+/* wm_gizmo_group_type.c */
+struct wmGizmoGroupType *WM_gizmogrouptype_find(const char *idname, bool quiet);
+struct wmGizmoGroupType *WM_gizmogrouptype_append(void (*wtfunc)(struct wmGizmoGroupType *));
+struct wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*mnpfunc)(struct wmGizmoGroupType *, void *), void *userdata);
+bool WM_gizmogrouptype_free(const char *idname);
+void WM_gizmogrouptype_free_ptr(struct wmGizmoGroupType *wt);
+void WM_gizmogrouptype_iter(struct GHashIterator *ghi);
+
+struct wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(
+ struct wmGizmoMapType *gzmap_type,
+ void (*wtfunc)(struct wmGizmoGroupType *));
+
+/* wm_gizmo_map.c */
+
+/* Dynamic Updates (for RNA runtime registration) */
+void WM_gizmoconfig_update_tag_init(struct wmGizmoMapType *gzmap_type, struct wmGizmoGroupType *gzgt);
+void WM_gizmoconfig_update_tag_remove(struct wmGizmoMapType *gzmap_type, struct wmGizmoGroupType *gzgt);
+void WM_gizmoconfig_update(struct Main *bmain);
+
+
+/* wm_maniulator_target_props.c */
+struct wmGizmoProperty *WM_gizmo_target_property_array(struct wmGizmo *gz);
+struct wmGizmoProperty *WM_gizmo_target_property_at_index(
+ struct wmGizmo *gz, int index);
+struct wmGizmoProperty *WM_gizmo_target_property_find(
+ struct wmGizmo *gz, const char *idname);
+
+void WM_gizmo_target_property_def_rna_ptr(
+ struct wmGizmo *gz, const struct wmGizmoPropertyType *gz_prop_type,
+ struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
+void WM_gizmo_target_property_def_rna(
+ struct wmGizmo *gz, const char *idname,
+ struct PointerRNA *ptr, const char *propname, int index);
+
+void WM_gizmo_target_property_def_func_ptr(
+ struct wmGizmo *gz, const struct wmGizmoPropertyType *gz_prop_type,
+ const struct wmGizmoPropertyFnParams *params);
+void WM_gizmo_target_property_def_func(
+ struct wmGizmo *gz, const char *idname,
+ const struct wmGizmoPropertyFnParams *params);
+
+void WM_gizmo_target_property_clear_rna_ptr(
+ struct wmGizmo *gz, const struct wmGizmoPropertyType *gz_prop_type);
+void WM_gizmo_target_property_clear_rna(
+ struct wmGizmo *gz, const char *idname);
+
+bool WM_gizmo_target_property_is_valid_any(struct wmGizmo *gz);
+bool WM_gizmo_target_property_is_valid(
+ const struct wmGizmoProperty *gz_prop);
+float WM_gizmo_target_property_float_get(
+ const struct wmGizmo *gz, struct wmGizmoProperty *gz_prop);
+void WM_gizmo_target_property_float_set(
+ struct bContext *C, const struct wmGizmo *gz, struct wmGizmoProperty *gz_prop,
+ const float value);
+
+void WM_gizmo_target_property_float_get_array(
+ const struct wmGizmo *gz, struct wmGizmoProperty *gz_prop,
+ float *value);
+void WM_gizmo_target_property_float_set_array(
+ struct bContext *C, const struct wmGizmo *gz, struct wmGizmoProperty *gz_prop,
+ const float *value);
+
+bool WM_gizmo_target_property_float_range_get(
+ const struct wmGizmo *gz, struct wmGizmoProperty *gz_prop,
+ float range[2]);
+
+int WM_gizmo_target_property_array_length(
+ const struct wmGizmo *gz, struct wmGizmoProperty *gz_prop);
+
+/* definitions */
+const struct wmGizmoPropertyType *WM_gizmotype_target_property_find(
+ const struct wmGizmoType *gzt, const char *idname);
+void WM_gizmotype_target_property_def(
+ struct wmGizmoType *gzt, const char *idname, int data_type, int array_length);
+
+/* utilities */
+void WM_gizmo_do_msg_notify_tag_refresh(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+void WM_gizmo_target_property_subscribe_all(
+ struct wmGizmo *gz, struct wmMsgBus *mbus, struct ARegion *ar);
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoGroup */
+
+/* Callbacks for 'wmGizmoGroupType.setup_keymap' */
+struct wmKeyMap *WM_gizmogroup_keymap_common(
+ const struct wmGizmoGroupType *gzgt, struct wmKeyConfig *config);
+struct wmKeyMap *WM_gizmogroup_keymap_common_select(
+ const struct wmGizmoGroupType *gzgt, struct wmKeyConfig *config);
+
+/* Sort utilities for use with 'BLI_listbase_sort'. */
+int WM_gizmo_cmp_temp_fl(const void *gz_a_ptr, const void *gz_b_ptr);
+int WM_gizmo_cmp_temp_fl_reverse(const void *gz_a_ptr, const void *gz_b_ptr);
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoMap */
+
+struct wmGizmoMap *WM_gizmomap_new_from_type(
+ const struct wmGizmoMapType_Params *gzmap_params);
+const struct ListBase *WM_gizmomap_group_list(struct wmGizmoMap *gzmap);
+struct wmGizmoGroup *WM_gizmomap_group_find(
+ struct wmGizmoMap *gzmap,
+ const char *idname);
+struct wmGizmoGroup *WM_gizmomap_group_find_ptr(
+ struct wmGizmoMap *gzmap,
+ const struct wmGizmoGroupType *gzgt);
+void WM_gizmomap_tag_refresh(struct wmGizmoMap *gzmap);
+void WM_gizmomap_draw(
+ struct wmGizmoMap *gzmap, const struct bContext *C, const eWM_GizmoFlagMapDrawStep drawstep);
+void WM_gizmomap_add_handlers(struct ARegion *ar, struct wmGizmoMap *gzmap);
+bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, const int action);
+bool WM_gizmomap_cursor_set(const struct wmGizmoMap *gzmap, struct wmWindow *win);
+void WM_gizmomap_message_subscribe(
+ struct bContext *C, struct wmGizmoMap *gzmap, struct ARegion *ar, struct wmMsgBus *mbus);
+bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap);
+bool WM_gizmomap_minmax(
+ const struct wmGizmoMap *gzmap, bool use_hidden, bool use_select,
+ float r_min[3], float r_max[3]);
+
+struct ARegion *WM_gizmomap_tooltip_init(
+ struct bContext *C, struct ARegion *ar, int *pass, double *pass_delay, bool *r_exit_on_event);
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoMapType */
+
+struct wmGizmoMapType *WM_gizmomaptype_find(
+ const struct wmGizmoMapType_Params *gzmap_params);
+struct wmGizmoMapType *WM_gizmomaptype_ensure(
+ const struct wmGizmoMapType_Params *gzmap_params);
+
+struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(
+ struct wmGizmoMapType *gzmap_type,
+ const char *idname);
+struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find_ptr(
+ struct wmGizmoMapType *gzmap_type,
+ const struct wmGizmoGroupType *gzgt);
+struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(
+ struct wmGizmoMapType *gzmap_type,
+ const char *idname);
+struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link_ptr(
+ struct wmGizmoMapType *gzmap_type,
+ struct wmGizmoGroupType *gzgt);
+
+void WM_gizmomaptype_group_init_runtime_keymap(
+ const struct Main *bmain,
+ struct wmGizmoGroupType *gzgt);
+void WM_gizmomaptype_group_init_runtime(
+ const struct Main *bmain, struct wmGizmoMapType *gzmap_type,
+ struct wmGizmoGroupType *gzgt);
+void WM_gizmomaptype_group_unlink(
+ struct bContext *C, struct Main *bmain, struct wmGizmoMapType *gzmap_type,
+ const struct wmGizmoGroupType *gzgt);
+
+void WM_gizmomaptype_group_free(struct wmGizmoGroupTypeRef *gzgt);
+
+/* -------------------------------------------------------------------- */
+/* GizmoGroup */
+
+/* Add/Ensure/Remove (High level API) */
+
+void WM_gizmo_group_type_add_ptr_ex(
+ struct wmGizmoGroupType *gzgt,
+ struct wmGizmoMapType *gzmap_type);
+void WM_gizmo_group_type_add_ptr(
+ struct wmGizmoGroupType *gzgt);
+void WM_gizmo_group_type_add(const char *idname);
+
+bool WM_gizmo_group_type_ensure_ptr_ex(
+ struct wmGizmoGroupType *gzgt,
+ struct wmGizmoMapType *gzmap_type);
+bool WM_gizmo_group_type_ensure_ptr(
+ struct wmGizmoGroupType *gzgt);
+bool WM_gizmo_group_type_ensure(const char *idname);
+
+void WM_gizmo_group_type_remove_ptr_ex(
+ struct Main *bmain, struct wmGizmoGroupType *gzgt,
+ struct wmGizmoMapType *gzmap_type);
+void WM_gizmo_group_type_remove_ptr(
+ struct Main *bmain, struct wmGizmoGroupType *gzgt);
+void WM_gizmo_group_type_remove(struct Main *bmain, const char *idname);
+
+void WM_gizmo_group_type_unlink_delayed_ptr_ex(
+ struct wmGizmoGroupType *gzgt,
+ struct wmGizmoMapType *gzmap_type);
+void WM_gizmo_group_type_unlink_delayed_ptr(
+ struct wmGizmoGroupType *gzgt);
+void WM_gizmo_group_type_unlink_delayed(const char *idname);
+
+/* Has the result of unlinking and linking (re-initializes gizmo's). */
+void WM_gizmo_group_type_reinit_ptr_ex(
+ struct Main *bmain, struct wmGizmoGroupType *gzgt,
+ struct wmGizmoMapType *gzmap_type);
+void WM_gizmo_group_type_reinit_ptr(
+ struct Main *bmain, struct wmGizmoGroupType *gzgt);
+void WM_gizmo_group_type_reinit(struct Main *bmain, const char *idname);
+
+/* Utilities */
+bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapDrawStep step);
+
+bool WM_gizmo_group_type_poll(const struct bContext *C, const struct wmGizmoGroupType *gzgt);
+
+#endif /* __WM_GIZMO_API_H__ */
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
new file mode 100644
index 00000000000..c92172dff15
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
@@ -0,0 +1,441 @@
+/*
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/WM_gizmo_types.h
+ * \ingroup wm
+ *
+ * \name Gizmo Types
+ * \brief Gizmo defines for external use.
+ *
+ * Only included in WM_types.h and lower level files.
+ */
+
+
+#ifndef __WM_GIZMO_TYPES_H__
+#define __WM_GIZMO_TYPES_H__
+
+#include "BLI_compiler_attrs.h"
+
+struct wmGizmoMapType;
+struct wmGizmoGroupType;
+struct wmGizmoGroup;
+struct wmGizmo;
+struct wmGizmoProperty;
+struct wmKeyConfig;
+
+#include "DNA_listBase.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Enum Typedef's */
+
+
+/**
+ * #wmGizmo.state
+ */
+typedef enum eWM_GizmoFlagState {
+ WM_GIZMO_STATE_HIGHLIGHT = (1 << 0), /* while hovered */
+ WM_GIZMO_STATE_MODAL = (1 << 1), /* while dragging */
+ WM_GIZMO_STATE_SELECT = (1 << 2),
+} eWM_GizmoFlagState;
+
+
+/**
+ * #wmGizmo.flag
+ * Flags for individual gizmos.
+ */
+typedef enum eWM_GizmoFlag {
+ WM_GIZMO_DRAW_HOVER = (1 << 0), /* draw *only* while hovering */
+ WM_GIZMO_DRAW_MODAL = (1 << 1), /* draw while dragging */
+ WM_GIZMO_DRAW_VALUE = (1 << 2), /* draw an indicator for the current value while dragging */
+ WM_GIZMO_HIDDEN = (1 << 3),
+ WM_GIZMO_HIDDEN_SELECT = (1 << 4),
+ /**
+ * When set 'scale_final' value also scales the offset.
+ * Use when offset is to avoid screen-space overlap instead of absolute positioning. */
+ WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 5),
+ /**
+ * User should still use 'scale_final' for any handles and UI elements.
+ * This simply skips scale when calculating the final matrix.
+ * Needed when the gizmo needs to align with the interface underneath it. */
+ WM_GIZMO_DRAW_NO_SCALE = (1 << 6),
+ /**
+ * Hide the cursor and lock it's position while interacting with this gizmo.
+ */
+ WM_GIZMO_MOVE_CURSOR = (1 << 7),
+ /** Don't write into the depth buffer when selecting. */
+ WM_GIZMO_SELECT_BACKGROUND = (1 << 8),
+} eWM_GizmoFlag;
+
+/**
+ * #wmGizmoGroupType.flag
+ * Flags that influence the behavior of all gizmos in the group.
+ */
+typedef enum eWM_GizmoFlagGroupTypeFlag {
+ /** Mark gizmo-group as being 3D */
+ WM_GIZMOGROUPTYPE_3D = (1 << 0),
+ /** Scale gizmos as 3D object that respects zoom (otherwise zoom independent draw size).
+ * note: currently only for 3D views, 2D support needs adding. */
+ WM_GIZMOGROUPTYPE_SCALE = (1 << 1),
+ /** Gizmos can be depth culled with scene objects (covered by other geometry - TODO) */
+ WM_GIZMOGROUPTYPE_DEPTH_3D = (1 << 2),
+ /** Gizmos can be selected */
+ WM_GIZMOGROUPTYPE_SELECT = (1 << 3),
+ /** The gizmo group is to be kept (not removed on loading a new file for eg). */
+ WM_GIZMOGROUPTYPE_PERSISTENT = (1 << 4),
+ /** Show all other gizmos when interacting. */
+ WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL = (1 << 5),
+ /**
+ * When used with tool, only run when activating the tool,
+ * instead of linking the gizmo while the tool is active.
+ *
+ * \warning this option has some limitations, we might even re-implement this differently.
+ * Currently it's quite minimal so we can see how it works out.
+ * The main issue is controlling how a gizmo is activated with a tool
+ * when a tool can activate multiple operators based on the key-map.
+ * We could even move the options into the key-map item.
+ * ~ campbell */
+ WM_GIZMOGROUPTYPE_TOOL_INIT = (1 << 6),
+} eWM_GizmoFlagGroupTypeFlag;
+
+
+/**
+ * #wmGizmoGroup.init_flag
+ */
+typedef enum eWM_GizmoFlagGroupInitFlag {
+ /* mgroup has been initialized */
+ WM_GIZMOGROUP_INIT_SETUP = (1 << 0),
+ WM_GIZMOGROUP_INIT_REFRESH = (1 << 1),
+} eWM_GizmoFlagGroupInitFlag;
+
+/**
+ * #wmGizmoMapType.type_update_flag
+ * Gizmo-map type update flag
+ */
+typedef enum eWM_GizmoFlagMapTypeUpdateFlag {
+ /* A new type has been added, needs to be initialized for all views. */
+ WM_GIZMOMAPTYPE_UPDATE_INIT = (1 << 0),
+ WM_GIZMOMAPTYPE_UPDATE_REMOVE = (1 << 1),
+
+ /* Needed because keymap may be registered before and after window initialization.
+ * So we need to keep track of keymap initialization separately. */
+ WM_GIZMOMAPTYPE_KEYMAP_INIT = (1 << 2),
+} eWM_GizmoFlagMapTypeUpdateFlag;
+
+/* -------------------------------------------------------------------- */
+/* wmGizmo */
+
+/**
+ * \brief Gizmo tweak flag.
+ * Bitflag passed to gizmo while tweaking.
+ *
+ * \note Gizmos are responsible for handling this #wmGizmo.modal callback!.
+ */
+typedef enum {
+ /* Drag with extra precision (Shift). */
+ WM_GIZMO_TWEAK_PRECISE = (1 << 0),
+ /* Drag with snap enabled (Ctrl). */
+ WM_GIZMO_TWEAK_SNAP = (1 << 1),
+} eWM_GizmoFlagTweak;
+
+#include "wm_gizmo_fn.h"
+
+typedef struct wmGizmoOpElem {
+ struct wmOperatorType *type;
+ /* operator properties if gizmo spawns and controls an operator,
+ * or owner pointer if gizmo spawns and controls a property */
+ PointerRNA ptr;
+
+ bool is_redo;
+} wmGizmoOpElem;
+
+/* gizmos are set per region by registering them on gizmo-maps */
+struct wmGizmo {
+ struct wmGizmo *next, *prev;
+
+ /* While we don't have a real type, use this to put type-like vars. */
+ const struct wmGizmoType *type;
+
+ /* Overrides 'type->modal' when set.
+ * Note that this is a workaround, remove if we can. */
+ wmGizmoFnModal custom_modal;
+
+ /* pointer back to group this gizmo is in (just for quick access) */
+ struct wmGizmoGroup *parent_gzgroup;
+
+ void *py_instance;
+
+ /* rna pointer to access properties */
+ struct PointerRNA *ptr;
+
+ /* flags that influence the behavior or how the gizmos are drawn */
+ eWM_GizmoFlag flag;
+ /* state flags (active, highlighted, selected) */
+ eWM_GizmoFlagState state;
+
+ /* Optional ID for highlighting different parts of this gizmo.
+ * -1 when unset, otherwise a valid index. (Used as index to 'op_data'). */
+ int highlight_part;
+ /* For single click button gizmos, use a different part as a fallback, -1 when unused. */
+ int drag_part;
+
+ /* Transformation of the gizmo in 2d or 3d space.
+ * - Matrix axis are expected to be unit length (scale is applied after).
+ * - Behavior when axis aren't orthogonal depends on each gizmo.
+ * - Typically the +Z is the primary axis for gizmos to use.
+ * - 'matrix[3]' must be used for location,
+ * besides this it's up to the gizmos internal code how the
+ * rotation components are used for drawing and interaction.
+ */
+
+ /* The space this gizmo is being modified in. */
+ float matrix_space[4][4];
+ /* Transformation of this gizmo. */
+ float matrix_basis[4][4];
+ /* custom offset from origin */
+ float matrix_offset[4][4];
+ /* runtime property, set the scale while drawing on the viewport */
+ float scale_final;
+ /* user defined scale, in addition to the original one */
+ float scale_basis;
+ /* user defined width for line drawing */
+ float line_width;
+ /* gizmo colors (uses default fallbacks if not defined) */
+ float color[4], color_hi[4];
+
+ /* data used during interaction */
+ void *interaction_data;
+
+ /* Operator to spawn when activating the gizmo (overrides property editing),
+ * an array of items (aligned with #wmGizmo.highlight_part). */
+ wmGizmoOpElem *op_data;
+ int op_data_len;
+
+ struct IDProperty *properties;
+
+ /* Temporary data (assume dirty). */
+ union {
+ float f;
+ } temp;
+
+ /* over alloc target_properties after 'wmGizmoType.struct_size' */
+};
+
+/* Similar to PropertyElemRNA, but has an identifier. */
+typedef struct wmGizmoProperty {
+ const struct wmGizmoPropertyType *type;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+
+ /* Optional functions for converting to/from RNA */
+ struct {
+ wmGizmoPropertyFnGet value_get_fn;
+ wmGizmoPropertyFnSet value_set_fn;
+ wmGizmoPropertyFnRangeGet range_get_fn;
+ wmGizmoPropertyFnFree free_fn;
+ void *user_data;
+ } custom_func;
+} wmGizmoProperty;
+
+typedef struct wmGizmoPropertyType {
+ struct wmGizmoPropertyType *next, *prev;
+ /* PropertyType, typically 'PROP_FLOAT' */
+ int data_type;
+ int array_length;
+
+ /* index within 'wmGizmoType' */
+ int index_in_type;
+
+ /* over alloc */
+ char idname[0];
+} wmGizmoPropertyType;
+
+
+/**
+ * Simple utility wrapper for storing a single gizmo as wmGizmoGroup.customdata (which gets freed).
+ */
+typedef struct wmGizmoWrapper {
+ struct wmGizmo *gizmo;
+} wmGizmoWrapper;
+
+struct wmGizmoMapType_Params {
+ short spaceid;
+ short regionid;
+};
+
+typedef struct wmGizmoType {
+
+ const char *idname; /* MAX_NAME */
+
+ /* Set to 'sizeof(wmGizmo)' or larger for instances of this type,
+ * use so we can cant to other types without the hassle of a custom-data pointer. */
+ uint struct_size;
+
+ /* Initialize struct (calloc'd 'struct_size' region). */
+ wmGizmoFnSetup setup;
+
+ /* draw gizmo */
+ wmGizmoFnDraw draw;
+
+ /* determines 3d intersection by rendering the gizmo in a selection routine. */
+ wmGizmoFnDrawSelect draw_select;
+
+ /* Determine if the mouse intersects with the gizmo.
+ * The calculation should be done in the callback itself, -1 for no seleciton. */
+ wmGizmoFnTestSelect test_select;
+
+ /* handler used by the gizmo. Usually handles interaction tied to a gizmo type */
+ wmGizmoFnModal modal;
+
+ /* gizmo-specific handler to update gizmo attributes based on the property value */
+ wmGizmoFnPropertyUpdate property_update;
+
+ /* Returns the final transformation which may be different from the 'matrix',
+ * depending on the gizmo.
+ * Notes:
+ * - Scale isn't applied (wmGizmo.scale/user_scale).
+ * - Offset isn't applied (wmGizmo.matrix_offset).
+ */
+ wmGizmoFnMatrixBasisGet matrix_basis_get;
+
+ /* activate a gizmo state when the user clicks on it */
+ wmGizmoFnInvoke invoke;
+
+ /* called when gizmo tweaking is done - used to free data and reset property when cancelling */
+ wmGizmoFnExit exit;
+
+ wmGizmoFnCursorGet cursor_get;
+
+ /* called when gizmo selection state changes */
+ wmGizmoFnSelectRefresh select_refresh;
+
+ /* Free data (not the gizmo it's self), use when the gizmo allocates it's own members. */
+ wmGizmoFnFree free;
+
+ /* RNA for properties */
+ struct StructRNA *srna;
+
+ /* RNA integration */
+ ExtensionRNA ext;
+
+ ListBase target_property_defs;
+ int target_property_defs_len;
+
+} wmGizmoType;
+
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoGroup */
+
+/* factory class for a gizmo-group type, gets called every time a new area is spawned */
+typedef struct wmGizmoGroupTypeRef {
+ struct wmGizmoGroupTypeRef *next, *prev;
+ struct wmGizmoGroupType *type;
+} wmGizmoGroupTypeRef;
+
+/* factory class for a gizmo-group type, gets called every time a new area is spawned */
+typedef struct wmGizmoGroupType {
+ const char *idname; /* MAX_NAME */
+ const char *name; /* gizmo-group name - displayed in UI (keymap editor) */
+ char owner_id[64]; /* MAX_NAME */
+
+ /* poll if gizmo-map should be visible */
+ wmGizmoGroupFnPoll poll;
+ /* initially create gizmos and set permanent data - stuff you only need to do once */
+ wmGizmoGroupFnInit setup;
+ /* refresh data, only called if recreate flag is set (WM_gizmomap_tag_refresh) */
+ wmGizmoGroupFnRefresh refresh;
+ /* refresh data for drawing, called before each redraw */
+ wmGizmoGroupFnDrawPrepare draw_prepare;
+ /* Initialize data for before invoke. */
+ wmGizmoGroupFnInvokePrepare invoke_prepare;
+
+ /* Keymap init callback for this gizmo-group (optional),
+ * will fall back to default tweak keymap when left NULL. */
+ wmGizmoGroupFnSetupKeymap setup_keymap;
+
+ /* Optionally subscribe to wmMsgBus events,
+ * these are calculated automatically from RNA properties,
+ * only needed if gizmos depend indirectly on properties. */
+ wmGizmoGroupFnMsgBusSubscribe message_subscribe;
+
+ /* keymap created with callback from above */
+ struct wmKeyMap *keymap;
+ /* Only for convenient removal. */
+ struct wmKeyConfig *keyconf;
+
+ /* Note: currently gizmo-group instances don't store properties,
+ * they're kept in the tool properties. */
+
+ /* RNA for properties */
+ struct StructRNA *srna;
+
+ /* RNA integration */
+ ExtensionRNA ext;
+
+ eWM_GizmoFlagGroupTypeFlag flag;
+
+ /* So we know which group type to update. */
+ eWM_GizmoFlagMapTypeUpdateFlag type_update_flag;
+
+ /* same as gizmo-maps, so registering/unregistering goes to the correct region */
+ struct wmGizmoMapType_Params gzmap_params;
+
+} wmGizmoGroupType;
+
+typedef struct wmGizmoGroup {
+ struct wmGizmoGroup *next, *prev;
+
+ struct wmGizmoGroupType *type;
+ ListBase gizmos;
+
+ struct wmGizmoMap *parent_gzmap;
+
+ void *py_instance; /* python stores the class instance here */
+ struct ReportList *reports; /* errors and warnings storage */
+
+ void *customdata;
+ void (*customdata_free)(void *); /* for freeing customdata from above */
+ eWM_GizmoFlagGroupInitFlag init_flag;
+} wmGizmoGroup;
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoMap */
+
+/**
+ * Pass a value of this enum to #WM_gizmomap_draw to tell it what to draw.
+ */
+typedef enum eWM_GizmoFlagMapDrawStep {
+ /** Draw 2D gizmo-groups (#WM_GIZMOGROUPTYPE_3D not set). */
+ WM_GIZMOMAP_DRAWSTEP_2D = 0,
+ /** Draw 3D gizmo-groups (#WM_GIZMOGROUPTYPE_3D set). */
+ WM_GIZMOMAP_DRAWSTEP_3D,
+} eWM_GizmoFlagMapDrawStep;
+#define WM_GIZMOMAP_DRAWSTEP_MAX 2
+
+#endif /* __WM_GIZMO_TYPES_H__ */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
new file mode 100644
index 00000000000..123857f3251
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c
@@ -0,0 +1,800 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/intern/wm_gizmo.c
+ * \ingroup wm
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_context.h"
+
+#include "GPU_batch.h"
+#include "GPU_glew.h"
+#include "GPU_immediate.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_idprop.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "UI_interface.h"
+
+#ifdef WITH_PYTHON
+#include "BPY_extern.h"
+#endif
+
+/* only for own init/exit calls (wm_gizmotype_init/wm_gizmotype_free) */
+#include "wm.h"
+
+/* own includes */
+#include "wm_gizmo_wmapi.h"
+#include "wm_gizmo_intern.h"
+
+static void wm_gizmo_register(
+ wmGizmoGroup *gzgroup, wmGizmo *gz);
+
+/**
+ * \note Follow #wm_operator_create convention.
+ */
+static wmGizmo *wm_gizmo_create(
+ const wmGizmoType *gzt,
+ PointerRNA *properties)
+{
+ BLI_assert(gzt != NULL);
+ BLI_assert(gzt->struct_size >= sizeof(wmGizmo));
+
+ wmGizmo *gz = MEM_callocN(
+ gzt->struct_size + (sizeof(wmGizmoProperty) * gzt->target_property_defs_len), __func__);
+ gz->type = gzt;
+
+ /* initialize properties, either copy or create */
+ gz->ptr = MEM_callocN(sizeof(PointerRNA), "wmGizmoPtrRNA");
+ if (properties && properties->data) {
+ gz->properties = IDP_CopyProperty(properties->data);
+ }
+ else {
+ IDPropertyTemplate val = {0};
+ gz->properties = IDP_New(IDP_GROUP, &val, "wmGizmoProperties");
+ }
+ RNA_pointer_create(G_MAIN->wm.first, gzt->srna, gz->properties, gz->ptr);
+
+ WM_gizmo_properties_sanitize(gz->ptr, 0);
+
+ unit_m4(gz->matrix_space);
+ unit_m4(gz->matrix_basis);
+ unit_m4(gz->matrix_offset);
+
+ gz->drag_part = -1;
+
+ return gz;
+}
+
+wmGizmo *WM_gizmo_new_ptr(
+ const wmGizmoType *gzt, wmGizmoGroup *gzgroup,
+ PointerRNA *properties)
+{
+ wmGizmo *gz = wm_gizmo_create(gzt, properties);
+
+ wm_gizmo_register(gzgroup, gz);
+
+ if (gz->type->setup != NULL) {
+ gz->type->setup(gz);
+ }
+
+ return gz;
+}
+
+/**
+ * \param gt: Must be valid,
+ * if you need to check it exists use #WM_gizmo_new_ptr
+ * because callers of this function don't NULL check the return value.
+ */
+wmGizmo *WM_gizmo_new(
+ const char *idname, wmGizmoGroup *gzgroup,
+ PointerRNA *properties)
+{
+ const wmGizmoType *gzt = WM_gizmotype_find(idname, false);
+ return WM_gizmo_new_ptr(gzt, gzgroup, properties);
+}
+
+/**
+ * Initialize default values and allocate needed memory for members.
+ */
+static void gizmo_init(wmGizmo *gz)
+{
+ const float color_default[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ gz->scale_basis = 1.0f;
+ gz->line_width = 1.0f;
+
+ /* defaults */
+ copy_v4_v4(gz->color, color_default);
+ copy_v4_v4(gz->color_hi, color_default);
+}
+
+/**
+ * Register \a gizmo.
+ *
+ * \param name: name used to create a unique idname for \a gizmo in \a gzgroup
+ *
+ * \note Not to be confused with type registration from RNA.
+ */
+static void wm_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
+{
+ gizmo_init(gz);
+ wm_gizmogroup_gizmo_register(gzgroup, gz);
+}
+
+/**
+ * \warning this doesn't check #wmGizmoMap (highlight, selection etc).
+ * Typical use is when freeing the windowing data,
+ * where caller can manage clearing selection, highlight... etc.
+ */
+void WM_gizmo_free(wmGizmo *gz)
+{
+ if (gz->type->free != NULL) {
+ gz->type->free(gz);
+ }
+
+#ifdef WITH_PYTHON
+ if (gz->py_instance) {
+ /* do this first in case there are any __del__ functions or
+ * similar that use properties */
+ BPY_DECREF_RNA_INVALIDATE(gz->py_instance);
+ }
+#endif
+
+ if (gz->op_data) {
+ for (int i = 0; i < gz->op_data_len; i++) {
+ WM_operator_properties_free(&gz->op_data[i].ptr);
+ }
+ MEM_freeN(gz->op_data);
+ }
+
+ if (gz->ptr != NULL) {
+ WM_gizmo_properties_free(gz->ptr);
+ MEM_freeN(gz->ptr);
+ }
+
+ if (gz->type->target_property_defs_len != 0) {
+ wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);
+ for (int i = 0; i < gz->type->target_property_defs_len; i++) {
+ wmGizmoProperty *gz_prop = &gz_prop_array[i];
+ if (gz_prop->custom_func.free_fn) {
+ gz_prop->custom_func.free_fn(gz, gz_prop);
+ }
+ }
+ }
+
+ MEM_freeN(gz);
+}
+
+/**
+ * Free \a gizmo and unlink from \a gizmolist.
+ * \a gizmolist is allowed to be NULL.
+ */
+void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C)
+{
+ if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
+ wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
+ }
+ if (gz->state & WM_GIZMO_STATE_MODAL) {
+ wm_gizmomap_modal_set(gzmap, C, gz, NULL, false);
+ }
+ /* Unlink instead of setting so we don't run callbacks. */
+ if (gz->state & WM_GIZMO_STATE_SELECT) {
+ WM_gizmo_select_unlink(gzmap, gz);
+ }
+
+ if (gizmolist) {
+ BLI_remlink(gizmolist, gz);
+ }
+
+ BLI_assert(gzmap->gzmap_context.highlight != gz);
+ BLI_assert(gzmap->gzmap_context.modal != gz);
+
+ WM_gizmo_free(gz);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Gizmo Creation API
+ *
+ * API for defining data on gizmo creation.
+ *
+ * \{ */
+
+struct wmGizmoOpElem *WM_gizmo_operator_get(
+ wmGizmo *gz, int part_index)
+{
+ if (gz->op_data && ((part_index >= 0) && (part_index < gz->op_data_len))) {
+ return &gz->op_data[part_index];
+ }
+ return NULL;
+}
+
+PointerRNA *WM_gizmo_operator_set(
+ wmGizmo *gz, int part_index,
+ wmOperatorType *ot, IDProperty *properties)
+{
+ BLI_assert(part_index < 255);
+ /* We could pre-allocate these but using multiple is such a rare thing. */
+ if (part_index >= gz->op_data_len) {
+ gz->op_data_len = part_index + 1;
+ gz->op_data = MEM_recallocN(gz->op_data, sizeof(*gz->op_data) * gz->op_data_len);
+ }
+ wmGizmoOpElem *gzop = &gz->op_data[part_index];
+ gzop->type = ot;
+
+ if (gzop->ptr.data) {
+ WM_operator_properties_free(&gzop->ptr);
+ }
+ WM_operator_properties_create_ptr(&gzop->ptr, ot);
+
+ if (properties) {
+ gzop->ptr.data = properties;
+ }
+
+ return &gzop->ptr;
+}
+
+static void wm_gizmo_set_matrix_rotation_from_z_axis__internal(
+ float matrix[4][4], const float z_axis[3])
+{
+ /* old code, seems we can use simpler method */
+#if 0
+ const float z_global[3] = {0.0f, 0.0f, 1.0f};
+ float rot[3][3];
+
+ rotation_between_vecs_to_mat3(rot, z_global, z_axis);
+ copy_v3_v3(matrix[0], rot[0]);
+ copy_v3_v3(matrix[1], rot[1]);
+ copy_v3_v3(matrix[2], rot[2]);
+#else
+ normalize_v3_v3(matrix[2], z_axis);
+ ortho_basis_v3v3_v3(matrix[0], matrix[1], matrix[2]);
+#endif
+
+}
+
+static void wm_gizmo_set_matrix_rotation_from_yz_axis__internal(
+ float matrix[4][4], const float y_axis[3], const float z_axis[3])
+{
+ normalize_v3_v3(matrix[1], y_axis);
+ normalize_v3_v3(matrix[2], z_axis);
+ cross_v3_v3v3(matrix[0], matrix[1], matrix[2]);
+ normalize_v3(matrix[0]);
+}
+
+/**
+ * wmGizmo.matrix utils.
+ */
+void WM_gizmo_set_matrix_rotation_from_z_axis(
+ wmGizmo *gz, const float z_axis[3])
+{
+ wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_basis, z_axis);
+}
+void WM_gizmo_set_matrix_rotation_from_yz_axis(
+ wmGizmo *gz, const float y_axis[3], const float z_axis[3])
+{
+ wm_gizmo_set_matrix_rotation_from_yz_axis__internal(gz->matrix_basis, y_axis, z_axis);
+}
+void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
+{
+ copy_v3_v3(gz->matrix_basis[3], origin);
+}
+
+/**
+ * wmGizmo.matrix_offset utils.
+ */
+void WM_gizmo_set_matrix_offset_rotation_from_z_axis(
+ wmGizmo *gz, const float z_axis[3])
+{
+ wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_offset, z_axis);
+}
+void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(
+ wmGizmo *gz, const float y_axis[3], const float z_axis[3])
+{
+ wm_gizmo_set_matrix_rotation_from_yz_axis__internal(gz->matrix_offset, y_axis, z_axis);
+}
+void WM_gizmo_set_matrix_offset_location(wmGizmo *gz, const float offset[3])
+{
+ copy_v3_v3(gz->matrix_offset[3], offset);
+}
+
+void WM_gizmo_set_flag(wmGizmo *gz, const int flag, const bool enable)
+{
+ if (enable) {
+ gz->flag |= flag;
+ }
+ else {
+ gz->flag &= ~flag;
+ }
+}
+
+void WM_gizmo_set_scale(wmGizmo *gz, const float scale)
+{
+ gz->scale_basis = scale;
+}
+
+void WM_gizmo_set_line_width(wmGizmo *gz, const float line_width)
+{
+ gz->line_width = line_width;
+}
+
+/**
+ * Set gizmo rgba colors.
+ *
+ * \param col Normal state color.
+ * \param col_hi Highlighted state color.
+ */
+void WM_gizmo_get_color(const wmGizmo *gz, float color[4])
+{
+ copy_v4_v4(color, gz->color);
+}
+void WM_gizmo_set_color(wmGizmo *gz, const float color[4])
+{
+ copy_v4_v4(gz->color, color);
+}
+
+void WM_gizmo_get_color_highlight(const wmGizmo *gz, float color_hi[4])
+{
+ copy_v4_v4(color_hi, gz->color_hi);
+}
+void WM_gizmo_set_color_highlight(wmGizmo *gz, const float color_hi[4])
+{
+ copy_v4_v4(gz->color_hi, color_hi);
+}
+
+
+/** \} */ // Gizmo Creation API
+
+
+/* -------------------------------------------------------------------- */
+/** \name Gizmo Callback Assignment
+ *
+ * \{ */
+
+void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn)
+{
+ gz->custom_modal = fn;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/**
+ * Add/Remove \a gizmo to selection.
+ * Reallocates memory for selected gizmos so better not call for selecting multiple ones.
+ *
+ * \return if the selection has changed.
+ */
+bool wm_gizmo_select_set_ex(
+ wmGizmoMap *gzmap, wmGizmo *gz, bool select,
+ bool use_array, bool use_callback)
+{
+ bool changed = false;
+
+ if (select) {
+ if ((gz->state & WM_GIZMO_STATE_SELECT) == 0) {
+ if (use_array) {
+ wm_gizmomap_select_array_push_back(gzmap, gz);
+ }
+ gz->state |= WM_GIZMO_STATE_SELECT;
+ changed = true;
+ }
+ }
+ else {
+ if (gz->state & WM_GIZMO_STATE_SELECT) {
+ if (use_array) {
+ wm_gizmomap_select_array_remove(gzmap, gz);
+ }
+ gz->state &= ~WM_GIZMO_STATE_SELECT;
+ changed = true;
+ }
+ }
+
+ /* In the case of unlinking we only want to remove from the array
+ * and not write to the external state */
+ if (use_callback && changed) {
+ if (gz->type->select_refresh) {
+ gz->type->select_refresh(gz);
+ }
+ }
+
+ return changed;
+}
+
+/* Remove from selection array without running callbacks. */
+bool WM_gizmo_select_unlink(wmGizmoMap *gzmap, wmGizmo *gz)
+{
+ return wm_gizmo_select_set_ex(gzmap, gz, false, true, false);
+}
+
+bool WM_gizmo_select_set(wmGizmoMap *gzmap, wmGizmo *gz, bool select)
+{
+ return wm_gizmo_select_set_ex(gzmap, gz, select, true, true);
+}
+
+void WM_gizmo_highlight_set(wmGizmoMap *gzmap, wmGizmo *gz)
+{
+ wm_gizmomap_highlight_set(gzmap, NULL, gz, gz ? gz->highlight_part : 0);
+}
+
+bool wm_gizmo_select_and_highlight(bContext *C, wmGizmoMap *gzmap, wmGizmo *gz)
+{
+ if (WM_gizmo_select_set(gzmap, gz, true)) {
+ wm_gizmomap_highlight_set(gzmap, C, gz, gz->highlight_part);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/**
+ * Special function to run from setup so gizmos start out interactive.
+ *
+ * We could do this when linking them, but this complicates things since the window update code needs to run first.
+ */
+void WM_gizmo_modal_set_from_setup(
+ struct wmGizmoMap *gzmap, struct bContext *C,
+ struct wmGizmo *gz, int part_index, const wmEvent *event)
+{
+ gz->highlight_part = part_index;
+ WM_gizmo_highlight_set(gzmap, gz);
+ if (false) {
+ wm_gizmomap_modal_set(gzmap, C, gz, event, true);
+ }
+ else {
+ /* WEAK: but it works. */
+ WM_operator_name_call(C, "GIZMOGROUP_OT_gizmo_tweak", WM_OP_INVOKE_DEFAULT, NULL);
+ }
+}
+
+void wm_gizmo_calculate_scale(wmGizmo *gz, const bContext *C)
+{
+ const RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ float scale = UI_DPI_FAC;
+
+ if ((gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_SCALE) == 0) {
+ scale *= U.gizmo_size;
+ if (rv3d) {
+ /* 'ED_view3d_pixel_size' includes 'U.pixelsize', remove it. */
+ float matrix_world[4][4];
+ if (gz->type->matrix_basis_get) {
+ float matrix_basis[4][4];
+ gz->type->matrix_basis_get(gz, matrix_basis);
+ mul_m4_m4m4(matrix_world, gz->matrix_space, matrix_basis);
+ }
+ else {
+ mul_m4_m4m4(matrix_world, gz->matrix_space, gz->matrix_basis);
+ }
+
+ /* Exclude matrix_offset from scale. */
+ scale *= ED_view3d_pixel_size_no_ui_scale(rv3d, matrix_world[3]);
+ }
+ else {
+ scale *= 0.02f;
+ }
+ }
+
+ gz->scale_final = gz->scale_basis * scale;
+}
+
+static void gizmo_update_prop_data(wmGizmo *gz)
+{
+ /* gizmo property might have been changed, so update gizmo */
+ if (gz->type->property_update) {
+ wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);
+ for (int i = 0; i < gz->type->target_property_defs_len; i++) {
+ wmGizmoProperty *gz_prop = &gz_prop_array[i];
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ gz->type->property_update(gz, gz_prop);
+ }
+ }
+ }
+}
+
+void wm_gizmo_update(wmGizmo *gz, const bContext *C, const bool refresh_map)
+{
+ if (refresh_map) {
+ gizmo_update_prop_data(gz);
+ }
+ wm_gizmo_calculate_scale(gz, C);
+}
+
+int wm_gizmo_is_visible(wmGizmo *gz)
+{
+ if (gz->flag & WM_GIZMO_HIDDEN) {
+ return 0;
+ }
+ if ((gz->state & WM_GIZMO_STATE_MODAL) &&
+ !(gz->flag & (WM_GIZMO_DRAW_MODAL | WM_GIZMO_DRAW_VALUE)))
+ {
+ /* don't draw while modal (dragging) */
+ return 0;
+ }
+ if ((gz->flag & WM_GIZMO_DRAW_HOVER) &&
+ !(gz->state & WM_GIZMO_STATE_HIGHLIGHT) &&
+ !(gz->state & WM_GIZMO_STATE_SELECT)) /* still draw selected gizmos */
+ {
+ /* update but don't draw */
+ return WM_GIZMO_IS_VISIBLE_UPDATE;
+ }
+
+ return WM_GIZMO_IS_VISIBLE_UPDATE | WM_GIZMO_IS_VISIBLE_DRAW;
+}
+
+void WM_gizmo_calc_matrix_final_params(
+ const wmGizmo *gz,
+ const struct WM_GizmoMatrixParams *params,
+ float r_mat[4][4])
+{
+ const float (* const matrix_space)[4] = params->matrix_space ? params->matrix_space : gz->matrix_space;
+ const float (* const matrix_basis)[4] = params->matrix_basis ? params->matrix_basis : gz->matrix_basis;
+ const float (* const matrix_offset)[4] = params->matrix_offset ? params->matrix_offset : gz->matrix_offset;
+ const float *scale_final = params->scale_final ? params->scale_final : &gz->scale_final;
+
+ float final_matrix[4][4];
+ if (params->matrix_basis == NULL && gz->type->matrix_basis_get) {
+ gz->type->matrix_basis_get(gz, final_matrix);
+ }
+ else {
+ copy_m4_m4(final_matrix, matrix_basis);
+ }
+
+ if (gz->flag & WM_GIZMO_DRAW_NO_SCALE) {
+ mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
+ }
+ else {
+ if (gz->flag & WM_GIZMO_DRAW_OFFSET_SCALE) {
+ mul_mat3_m4_fl(final_matrix, *scale_final);
+ mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
+ }
+ else {
+ mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
+ mul_mat3_m4_fl(final_matrix, *scale_final);
+ }
+ }
+
+ mul_m4_m4m4(r_mat, matrix_space, final_matrix);
+}
+
+void WM_gizmo_calc_matrix_final_no_offset(const wmGizmo *gz, float r_mat[4][4])
+{
+ float mat_identity[4][4];
+ unit_m4(mat_identity);
+
+ WM_gizmo_calc_matrix_final_params(
+ gz,
+ &((struct WM_GizmoMatrixParams) {
+ .matrix_space = NULL,
+ .matrix_basis = NULL,
+ .matrix_offset = mat_identity,
+ .scale_final = NULL,
+ }), r_mat
+ );
+}
+
+void WM_gizmo_calc_matrix_final(const wmGizmo *gz, float r_mat[4][4])
+{
+ WM_gizmo_calc_matrix_final_params(
+ gz,
+ &((struct WM_GizmoMatrixParams) {
+ .matrix_space = NULL,
+ .matrix_basis = NULL,
+ .matrix_offset = NULL,
+ .scale_final = NULL,
+ }), r_mat
+ );
+}
+
+/** \name Gizmo Property Access
+ *
+ * Matches `WM_operator_properties` conventions.
+ *
+ * \{ */
+
+
+void WM_gizmo_properties_create_ptr(PointerRNA *ptr, wmGizmoType *gzt)
+{
+ RNA_pointer_create(NULL, gzt->srna, NULL, ptr);
+}
+
+void WM_gizmo_properties_create(PointerRNA *ptr, const char *gtstring)
+{
+ const wmGizmoType *gzt = WM_gizmotype_find(gtstring, false);
+
+ if (gzt)
+ WM_gizmo_properties_create_ptr(ptr, (wmGizmoType *)gzt);
+ else
+ RNA_pointer_create(NULL, &RNA_GizmoProperties, NULL, ptr);
+}
+
+/* similar to the function above except its uses ID properties
+ * used for keymaps and macros */
+void WM_gizmo_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *gtstring)
+{
+ if (*properties == NULL) {
+ IDPropertyTemplate val = {0};
+ *properties = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
+ }
+
+ if (*ptr == NULL) {
+ *ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
+ WM_gizmo_properties_create(*ptr, gtstring);
+ }
+
+ (*ptr)->data = *properties;
+
+}
+
+void WM_gizmo_properties_sanitize(PointerRNA *ptr, const bool no_context)
+{
+ RNA_STRUCT_BEGIN (ptr, prop)
+ {
+ switch (RNA_property_type(prop)) {
+ case PROP_ENUM:
+ if (no_context)
+ RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
+ else
+ RNA_def_property_clear_flag(prop, PROP_ENUM_NO_CONTEXT);
+ break;
+ case PROP_POINTER:
+ {
+ StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
+
+ /* recurse into gizmo properties */
+ if (RNA_struct_is_a(ptype, &RNA_GizmoProperties)) {
+ PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
+ WM_gizmo_properties_sanitize(&opptr, no_context);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ RNA_STRUCT_END;
+}
+
+
+/** set all props to their default,
+ * \param do_update Only update un-initialized props.
+ *
+ * \note, there's nothing specific to gizmos here.
+ * this could be made a general function.
+ */
+bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
+{
+ bool changed = false;
+ RNA_STRUCT_BEGIN (ptr, prop)
+ {
+ switch (RNA_property_type(prop)) {
+ case PROP_POINTER:
+ {
+ StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
+ if (ptype != &RNA_Struct) {
+ PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
+ changed |= WM_gizmo_properties_default(&opptr, do_update);
+ }
+ break;
+ }
+ default:
+ if ((do_update == false) || (RNA_property_is_set(ptr, prop) == false)) {
+ if (RNA_property_reset(ptr, prop, -1)) {
+ changed = true;
+ }
+ }
+ break;
+ }
+ }
+ RNA_STRUCT_END;
+
+ return changed;
+}
+
+/* remove all props without PROP_SKIP_SAVE */
+void WM_gizmo_properties_reset(wmGizmo *gz)
+{
+ if (gz->ptr->data) {
+ PropertyRNA *iterprop;
+ iterprop = RNA_struct_iterator_property(gz->type->srna);
+
+ RNA_PROP_BEGIN (gz->ptr, itemptr, iterprop)
+ {
+ PropertyRNA *prop = itemptr.data;
+
+ if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
+ const char *identifier = RNA_property_identifier(prop);
+ RNA_struct_idprops_unset(gz->ptr, identifier);
+ }
+ }
+ RNA_PROP_END;
+ }
+}
+
+void WM_gizmo_properties_clear(PointerRNA *ptr)
+{
+ IDProperty *properties = ptr->data;
+
+ if (properties) {
+ IDP_ClearProperty(properties);
+ }
+}
+
+void WM_gizmo_properties_free(PointerRNA *ptr)
+{
+ IDProperty *properties = ptr->data;
+
+ if (properties) {
+ IDP_FreeProperty(properties);
+ MEM_freeN(properties);
+ ptr->data = NULL; /* just in case */
+ }
+}
+
+/** \} */
+
+/** \name General Utilities
+ *
+ * \{ */
+
+bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapDrawStep step)
+{
+ switch (step) {
+ case WM_GIZMOMAP_DRAWSTEP_2D:
+ {
+ break;
+ }
+ case WM_GIZMOMAP_DRAWSTEP_3D:
+ {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (ED_screen_animation_playing(wm)) {
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
new file mode 100644
index 00000000000..67b7149c0bd
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -0,0 +1,1004 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+ * \ingroup wm
+ *
+ * \name Gizmo-Group
+ *
+ * Gizmo-groups store and manage groups of gizmos. They can be
+ * attached to modal handlers and have own keymaps.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_workspace.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm_event_system.h"
+
+#include "ED_screen.h"
+#include "ED_undo.h"
+
+/* own includes */
+#include "wm_gizmo_wmapi.h"
+#include "wm_gizmo_intern.h"
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+/* Allow gizmo part's to be single click only,
+ * dragging falls back to activating their 'drag_part' action. */
+#define USE_DRAG_DETECT
+#define DRAG_THRESHOLD (U.tweak_threshold * U.dpi_fac)
+
+/* -------------------------------------------------------------------- */
+/** \name wmGizmoGroup
+ *
+ * \{ */
+
+/**
+ * Create a new gizmo-group from \a gzgt.
+ */
+wmGizmoGroup *wm_gizmogroup_new_from_type(
+ wmGizmoMap *gzmap, wmGizmoGroupType *gzgt)
+{
+ wmGizmoGroup *gzgroup = MEM_callocN(sizeof(*gzgroup), "gizmo-group");
+ gzgroup->type = gzgt;
+
+ /* keep back-link */
+ gzgroup->parent_gzmap = gzmap;
+
+ BLI_addtail(&gzmap->groups, gzgroup);
+
+ return gzgroup;
+}
+
+void wm_gizmogroup_free(bContext *C, wmGizmoGroup *gzgroup)
+{
+ wmGizmoMap *gzmap = gzgroup->parent_gzmap;
+
+ /* Similar to WM_gizmo_unlink, but only to keep gzmap state correct,
+ * we don't want to run callbacks. */
+ if (gzmap->gzmap_context.highlight && gzmap->gzmap_context.highlight->parent_gzgroup == gzgroup) {
+ wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
+ }
+ if (gzmap->gzmap_context.modal && gzmap->gzmap_context.modal->parent_gzgroup == gzgroup) {
+ wm_gizmomap_modal_set(gzmap, C, gzmap->gzmap_context.modal, NULL, false);
+ }
+
+ for (wmGizmo *gz = gzgroup->gizmos.first, *gz_next; gz; gz = gz_next) {
+ gz_next = gz->next;
+ if (gzmap->gzmap_context.select.len) {
+ WM_gizmo_select_unlink(gzmap, gz);
+ }
+ WM_gizmo_free(gz);
+ }
+ BLI_listbase_clear(&gzgroup->gizmos);
+
+#ifdef WITH_PYTHON
+ if (gzgroup->py_instance) {
+ /* do this first in case there are any __del__ functions or
+ * similar that use properties */
+ BPY_DECREF_RNA_INVALIDATE(gzgroup->py_instance);
+ }
+#endif
+
+ if (gzgroup->reports && (gzgroup->reports->flag & RPT_FREE)) {
+ BKE_reports_clear(gzgroup->reports);
+ MEM_freeN(gzgroup->reports);
+ }
+
+ if (gzgroup->customdata_free) {
+ gzgroup->customdata_free(gzgroup->customdata);
+ }
+ else {
+ MEM_SAFE_FREE(gzgroup->customdata);
+ }
+
+ BLI_remlink(&gzmap->groups, gzgroup);
+
+ MEM_freeN(gzgroup);
+}
+
+/**
+ * Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
+ */
+void wm_gizmogroup_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
+{
+ BLI_assert(BLI_findindex(&gzgroup->gizmos, gz) == -1);
+ BLI_addtail(&gzgroup->gizmos, gz);
+ gz->parent_gzgroup = gzgroup;
+}
+
+int WM_gizmo_cmp_temp_fl(const void *gz_a_ptr, const void *gz_b_ptr)
+{
+ const wmGizmo *gz_a = gz_a_ptr;
+ const wmGizmo *gz_b = gz_b_ptr;
+ if (gz_a->temp.f < gz_b->temp.f) return -1;
+ else if (gz_a->temp.f > gz_b->temp.f) return 1;
+ else return 0;
+}
+
+int WM_gizmo_cmp_temp_fl_reverse(const void *gz_a_ptr, const void *gz_b_ptr)
+{
+ const wmGizmo *gz_a = gz_a_ptr;
+ const wmGizmo *gz_b = gz_b_ptr;
+ if (gz_a->temp.f < gz_b->temp.f) return 1;
+ else if (gz_a->temp.f > gz_b->temp.f) return -1;
+ else return 0;
+}
+
+wmGizmo *wm_gizmogroup_find_intersected_gizmo(
+ const wmGizmoGroup *gzgroup, bContext *C, const wmEvent *event,
+ int *r_part)
+{
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ if (gz->type->test_select && (gz->flag & (WM_GIZMO_HIDDEN | WM_GIZMO_HIDDEN_SELECT)) == 0) {
+ if ((*r_part = gz->type->test_select(C, gz, event->mval)) != -1) {
+ return gz;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase. Added items need freeing!
+ */
+void wm_gizmogroup_intersectable_gizmos_to_list(const wmGizmoGroup *gzgroup, ListBase *listbase)
+{
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ if ((gz->flag & (WM_GIZMO_HIDDEN | WM_GIZMO_HIDDEN_SELECT)) == 0) {
+ if (((gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) && (gz->type->draw_select || gz->type->test_select)) ||
+ ((gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) == 0 && gz->type->test_select))
+ {
+ BLI_addhead(listbase, BLI_genericNodeN(gz));
+ }
+ }
+ }
+}
+
+void wm_gizmogroup_ensure_initialized(wmGizmoGroup *gzgroup, const bContext *C)
+{
+ /* prepare for first draw */
+ if (UNLIKELY((gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0)) {
+ gzgroup->type->setup(C, gzgroup);
+
+ /* Not ideal, initialize keymap here, needed for RNA runtime generated gizmos. */
+ wmGizmoGroupType *gzgt = gzgroup->type;
+ if (gzgt->keymap == NULL) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wm_gizmogrouptype_setup_keymap(gzgt, wm->defaultconf);
+ BLI_assert(gzgt->keymap != NULL);
+ }
+ gzgroup->init_flag |= WM_GIZMOGROUP_INIT_SETUP;
+ }
+
+ /* refresh may be called multiple times, this just ensures its called at least once before we draw. */
+ if (UNLIKELY((gzgroup->init_flag & WM_GIZMOGROUP_INIT_REFRESH) == 0)) {
+ if (gzgroup->type->refresh) {
+ gzgroup->type->refresh(C, gzgroup);
+ }
+ gzgroup->init_flag |= WM_GIZMOGROUP_INIT_REFRESH;
+ }
+}
+
+bool WM_gizmo_group_type_poll(const bContext *C, const struct wmGizmoGroupType *gzgt)
+{
+ /* If we're tagged, only use compatible. */
+ if (gzgt->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, gzgt->owner_id) == false) {
+ return false;
+ }
+ }
+ /* Check for poll function, if gizmo-group belongs to an operator, also check if the operator is running. */
+ return (!gzgt->poll || gzgt->poll(C, (wmGizmoGroupType *)gzgt));
+}
+
+bool wm_gizmogroup_is_visible_in_drawstep(
+ const wmGizmoGroup *gzgroup, const eWM_GizmoFlagMapDrawStep drawstep)
+{
+ switch (drawstep) {
+ case WM_GIZMOMAP_DRAWSTEP_2D:
+ return (gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) == 0;
+ case WM_GIZMOMAP_DRAWSTEP_3D:
+ return (gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D);
+ default:
+ BLI_assert(0);
+ return false;
+ }
+}
+
+bool wm_gizmogroup_is_any_selected(const wmGizmoGroup *gzgroup)
+{
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_SELECT) {
+ for (const wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ if (gz->state & WM_GIZMO_STATE_SELECT) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/** \} */
+
+/** \name Gizmo operators
+ *
+ * Basic operators for gizmo interaction with user configurable keymaps.
+ *
+ * \{ */
+
+static int gizmo_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
+ wmGizmo *highlight = gzmap->gzmap_context.highlight;
+
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ bool deselect = RNA_boolean_get(op->ptr, "deselect");
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+
+ /* deselect all first */
+ if (extend == false && deselect == false && toggle == false) {
+ wm_gizmomap_deselect_all(gzmap);
+ BLI_assert(msel->items == NULL && msel->len == 0);
+ UNUSED_VARS_NDEBUG(msel);
+ }
+
+ if (highlight) {
+ const bool is_selected = (highlight->state & WM_GIZMO_STATE_SELECT);
+ bool redraw = false;
+
+ if (toggle) {
+ /* toggle: deselect if already selected, else select */
+ deselect = is_selected;
+ }
+
+ if (deselect) {
+ if (is_selected && WM_gizmo_select_set(gzmap, highlight, false)) {
+ redraw = true;
+ }
+ }
+ else if (wm_gizmo_select_and_highlight(C, gzmap, highlight)) {
+ redraw = true;
+ }
+
+ if (redraw) {
+ ED_region_tag_redraw(ar);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BLI_assert(0);
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+}
+
+void GIZMOGROUP_OT_gizmo_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Gizmo Select";
+ ot->description = "Select the currently highlighted gizmo";
+ ot->idname = "GIZMOGROUP_OT_gizmo_select";
+
+ /* api callbacks */
+ ot->invoke = gizmo_select_invoke;
+
+ ot->flag = OPTYPE_UNDO;
+
+ WM_operator_properties_mouse_select(ot);
+}
+
+typedef struct GizmoTweakData {
+ wmGizmoMap *gzmap;
+ wmGizmoGroup *gzgroup;
+ wmGizmo *gz_modal;
+
+ int init_event; /* initial event type */
+ int flag; /* tweak flags */
+
+#ifdef USE_DRAG_DETECT
+ /* True until the mouse is moved (only use when the operator has no modal).
+ * this allows some gizmos to be click-only. */
+ enum {
+ /* Don't detect dragging. */
+ DRAG_NOP = 0,
+ /* Detect dragging (wait until a drag or click is detected). */
+ DRAG_DETECT,
+ /* Drag has started, idle until there is no active modal operator.
+ * This is needed because finishing the modal operator also exits
+ * the modal gizmo state (un-grabbs the cursor).
+ * Ideally this workaround could be removed later. */
+ DRAG_IDLE,
+ } drag_state;
+#endif
+
+} GizmoTweakData;
+
+static bool gizmo_tweak_start(
+ bContext *C, wmGizmoMap *gzmap, wmGizmo *gz, const wmEvent *event)
+{
+ /* activate highlighted gizmo */
+ wm_gizmomap_modal_set(gzmap, C, gz, event, true);
+
+ return (gz->state & WM_GIZMO_STATE_MODAL);
+}
+
+static bool gizmo_tweak_start_and_finish(
+ bContext *C, wmGizmoMap *gzmap, wmGizmo *gz, const wmEvent *event, bool *r_is_modal)
+{
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, gz->highlight_part);
+ if (r_is_modal) {
+ *r_is_modal = false;
+ }
+ if (gzop && gzop->type) {
+
+ /* Undo/Redo */
+ if (gzop->is_redo) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmOperator *op = WM_operator_last_redo(C);
+
+ /* We may want to enable this, for now the gizmo can manage it's own properties. */
+#if 0
+ IDP_MergeGroup(gzop->ptr.data, op->properties, false);
+#endif
+
+ WM_operator_free_all_after(wm, op);
+ ED_undo_pop_op(C, op);
+ }
+
+ /* XXX temporary workaround for modal gizmo operator
+ * conflicting with modal operator attached to gizmo */
+ if (gzop->type->modal) {
+ /* activate highlighted gizmo */
+ wm_gizmomap_modal_set(gzmap, C, gz, event, true);
+ if (r_is_modal) {
+ *r_is_modal = true;
+ }
+ }
+ else {
+ if (gz->parent_gzgroup->type->invoke_prepare) {
+ gz->parent_gzgroup->type->invoke_prepare(C, gz->parent_gzgroup, gz);
+ }
+ /* Allow for 'button' gizmos, single click to run an action. */
+ WM_operator_name_call_ptr(C, gzop->type, WM_OP_INVOKE_DEFAULT, &gzop->ptr);
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static void gizmo_tweak_finish(bContext *C, wmOperator *op, const bool cancel, bool clear_modal)
+{
+ GizmoTweakData *mtweak = op->customdata;
+ if (mtweak->gz_modal->type->exit) {
+ mtweak->gz_modal->type->exit(C, mtweak->gz_modal, cancel);
+ }
+ if (clear_modal) {
+ /* The gizmo may have been removed. */
+ if ((BLI_findindex(&mtweak->gzmap->groups, mtweak->gzgroup) != -1) &&
+ (BLI_findindex(&mtweak->gzgroup->gizmos, mtweak->gz_modal) != -1))
+ {
+ wm_gizmomap_modal_set(mtweak->gzmap, C, mtweak->gz_modal, NULL, false);
+ }
+ }
+ MEM_freeN(mtweak);
+}
+
+static int gizmo_tweak_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ GizmoTweakData *mtweak = op->customdata;
+ wmGizmo *gz = mtweak->gz_modal;
+ int retval = OPERATOR_PASS_THROUGH;
+ bool clear_modal = true;
+
+ if (gz == NULL) {
+ BLI_assert(0);
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
+#ifdef USE_DRAG_DETECT
+ wmGizmoMap *gzmap = mtweak->gzmap;
+ if (mtweak->drag_state == DRAG_DETECT) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (len_manhattan_v2v2_int(&event->x, gzmap->gzmap_context.event_xy) >= DRAG_THRESHOLD) {
+ mtweak->drag_state = DRAG_IDLE;
+ gz->highlight_part = gz->drag_part;
+ }
+ }
+ else if (event->type == mtweak->init_event && event->val == KM_RELEASE) {
+ mtweak->drag_state = DRAG_NOP;
+ retval = OPERATOR_FINISHED;
+ }
+
+ if (mtweak->drag_state != DRAG_DETECT) {
+ /* Follow logic in 'gizmo_tweak_invoke' */
+ bool is_modal = false;
+ if (gizmo_tweak_start_and_finish(C, gzmap, gz, event, &is_modal)) {
+ if (is_modal) {
+ clear_modal = false;
+ }
+ }
+ else {
+ if (!gizmo_tweak_start(C, gzmap, gz, event)) {
+ retval = OPERATOR_FINISHED;
+ }
+ }
+ }
+ }
+ if (mtweak->drag_state == DRAG_IDLE) {
+ if (gzmap->gzmap_context.modal != NULL) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ else {
+ gizmo_tweak_finish(C, op, false, false);
+ return OPERATOR_FINISHED;
+ }
+ }
+#endif /* USE_DRAG_DETECT */
+
+ if (retval == OPERATOR_FINISHED) {
+ /* pass */
+ }
+ else if (event->type == mtweak->init_event && event->val == KM_RELEASE) {
+ retval = OPERATOR_FINISHED;
+ }
+ else if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case TWEAK_MODAL_CANCEL:
+ retval = OPERATOR_CANCELLED;
+ break;
+ case TWEAK_MODAL_CONFIRM:
+ retval = OPERATOR_FINISHED;
+ break;
+ case TWEAK_MODAL_PRECISION_ON:
+ mtweak->flag |= WM_GIZMO_TWEAK_PRECISE;
+ break;
+ case TWEAK_MODAL_PRECISION_OFF:
+ mtweak->flag &= ~WM_GIZMO_TWEAK_PRECISE;
+ break;
+
+ case TWEAK_MODAL_SNAP_ON:
+ mtweak->flag |= WM_GIZMO_TWEAK_SNAP;
+ break;
+ case TWEAK_MODAL_SNAP_OFF:
+ mtweak->flag &= ~WM_GIZMO_TWEAK_SNAP;
+ break;
+ }
+ }
+
+ if (retval != OPERATOR_PASS_THROUGH) {
+ gizmo_tweak_finish(C, op, retval != OPERATOR_FINISHED, clear_modal);
+ return retval;
+ }
+
+ /* handle gizmo */
+ wmGizmoFnModal modal_fn = gz->custom_modal ? gz->custom_modal : gz->type->modal;
+ if (modal_fn) {
+ int modal_retval = modal_fn(C, gz, event, mtweak->flag);
+
+ if ((modal_retval & OPERATOR_RUNNING_MODAL) == 0) {
+ gizmo_tweak_finish(C, op, (modal_retval & OPERATOR_CANCELLED) != 0, true);
+ return OPERATOR_FINISHED;
+ }
+
+ /* Ugly hack to send gizmo events */
+ ((wmEvent *)event)->type = EVT_GIZMO_UPDATE;
+ }
+
+ /* always return PASS_THROUGH so modal handlers
+ * with gizmos attached can update */
+ BLI_assert(retval == OPERATOR_PASS_THROUGH);
+ return OPERATOR_PASS_THROUGH;
+}
+
+static int gizmo_tweak_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ wmGizmo *gz = gzmap->gzmap_context.highlight;
+
+ /* Needed for single click actions which don't enter modal state. */
+ WM_tooltip_clear(C, CTX_wm_window(C));
+
+ if (!gz) {
+ /* wm_handlers_do_intern shouldn't let this happen */
+ BLI_assert(0);
+ return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
+ }
+
+ bool use_drag_fallback = false;
+
+#ifdef USE_DRAG_DETECT
+ use_drag_fallback = !ELEM(gz->drag_part, -1, gz->highlight_part);
+#endif
+
+ if (use_drag_fallback == false) {
+ if (gizmo_tweak_start_and_finish(C, gzmap, gz, event, NULL)) {
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ bool use_drag_detect = false;
+#ifdef USE_DRAG_DETECT
+ if (use_drag_fallback) {
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, gz->highlight_part);
+ if (gzop && gzop->type) {
+ if (gzop->type->modal == NULL) {
+ use_drag_detect = true;
+ }
+ }
+ }
+#endif
+
+ if (use_drag_detect == false) {
+ if (!gizmo_tweak_start(C, gzmap, gz, event)) {
+ /* failed to start */
+ return OPERATOR_PASS_THROUGH;
+ }
+ }
+
+ GizmoTweakData *mtweak = MEM_mallocN(sizeof(GizmoTweakData), __func__);
+
+ mtweak->init_event = WM_userdef_event_type_from_keymap_type(event->type);
+ mtweak->gz_modal = gzmap->gzmap_context.highlight;
+ mtweak->gzgroup = mtweak->gz_modal->parent_gzgroup;
+ mtweak->gzmap = gzmap;
+ mtweak->flag = 0;
+
+#ifdef USE_DRAG_DETECT
+ mtweak->drag_state = use_drag_detect ? DRAG_DETECT : DRAG_NOP;
+#endif
+
+ op->customdata = mtweak;
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void GIZMOGROUP_OT_gizmo_tweak(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Gizmo Tweak";
+ ot->description = "Tweak the active gizmo";
+ ot->idname = "GIZMOGROUP_OT_gizmo_tweak";
+
+ /* api callbacks */
+ ot->invoke = gizmo_tweak_invoke;
+ ot->modal = gizmo_tweak_modal;
+
+ /* TODO(campbell) This causes problems tweaking settings for operators,
+ * need to find a way to support this. */
+#if 0
+ ot->flag = OPTYPE_UNDO;
+#endif
+}
+
+/** \} */
+
+
+static wmKeyMap *gizmogroup_tweak_modal_keymap(wmKeyConfig *keyconf, const char *gzgroupname)
+{
+ wmKeyMap *keymap;
+ char name[KMAP_MAX_NAME];
+
+ static EnumPropertyItem modal_items[] = {
+ {TWEAK_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {TWEAK_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
+ {TWEAK_MODAL_PRECISION_ON, "PRECISION_ON", 0, "Enable Precision", ""},
+ {TWEAK_MODAL_PRECISION_OFF, "PRECISION_OFF", 0, "Disable Precision", ""},
+ {TWEAK_MODAL_SNAP_ON, "SNAP_ON", 0, "Enable Snap", ""},
+ {TWEAK_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Disable Snap", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+
+ BLI_snprintf(name, sizeof(name), "%s Tweak Modal Map", gzgroupname);
+ keymap = WM_modalkeymap_get(keyconf, name);
+
+ /* this function is called for each spacetype, only needs to add map once */
+ if (keymap && keymap->modal_items)
+ return NULL;
+
+ keymap = WM_modalkeymap_add(keyconf, name, modal_items);
+
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL);
+ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL);
+
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM);
+
+ WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON);
+ WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF);
+ WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON);
+ WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF);
+
+ WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_SNAP_ON);
+ WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_SNAP_OFF);
+ WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_SNAP_ON);
+ WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_SNAP_OFF);
+
+ WM_modalkeymap_assign(keymap, "GIZMOGROUP_OT_gizmo_tweak");
+
+ return keymap;
+}
+
+/**
+ * Common default keymap for gizmo groups
+ */
+wmKeyMap *WM_gizmogroup_keymap_common(
+ const wmGizmoGroupType *gzgt, wmKeyConfig *config)
+{
+ /* Use area and region id since we might have multiple gizmos with the same name in different areas/regions */
+ wmKeyMap *km = WM_keymap_ensure(config, gzgt->name, gzgt->gzmap_params.spaceid, gzgt->gzmap_params.regionid);
+
+ WM_keymap_add_item(km, "GIZMOGROUP_OT_gizmo_tweak", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
+ gizmogroup_tweak_modal_keymap(config, gzgt->name);
+
+ return km;
+}
+
+/**
+ * Variation of #WM_gizmogroup_keymap_common but with keymap items for selection
+ */
+wmKeyMap *WM_gizmogroup_keymap_common_select(
+ const wmGizmoGroupType *gzgt, wmKeyConfig *config)
+{
+ /* Use area and region id since we might have multiple gizmos with the same name in different areas/regions */
+ wmKeyMap *km = WM_keymap_ensure(config, gzgt->name, gzgt->gzmap_params.spaceid, gzgt->gzmap_params.regionid);
+ /* FIXME(campbell) */
+#if 0
+ const int select_mouse = (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
+ const int select_tweak = (U.flag & USER_LMOUSESELECT) ? EVT_TWEAK_L : EVT_TWEAK_R;
+ const int action_mouse = (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
+#else
+ const int select_mouse = RIGHTMOUSE;
+ const int select_tweak = EVT_TWEAK_R;
+ const int action_mouse = LEFTMOUSE;
+#endif
+
+ WM_keymap_add_item(km, "GIZMOGROUP_OT_gizmo_tweak", action_mouse, KM_PRESS, KM_ANY, 0);
+ WM_keymap_add_item(km, "GIZMOGROUP_OT_gizmo_tweak", select_tweak, KM_ANY, 0, 0);
+ gizmogroup_tweak_modal_keymap(config, gzgt->name);
+
+ wmKeyMapItem *kmi = WM_keymap_add_item(km, "GIZMOGROUP_OT_gizmo_select", select_mouse, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "extend", false);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ RNA_boolean_set(kmi->ptr, "toggle", false);
+ kmi = WM_keymap_add_item(km, "GIZMOGROUP_OT_gizmo_select", select_mouse, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "extend", false);
+ RNA_boolean_set(kmi->ptr, "deselect", false);
+ RNA_boolean_set(kmi->ptr, "toggle", true);
+
+ return km;
+}
+
+/** \} */ /* wmGizmoGroup */
+
+/* -------------------------------------------------------------------- */
+/** \name wmGizmoGroupType
+ *
+ * \{ */
+
+struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find_ptr(
+ struct wmGizmoMapType *gzmap_type,
+ const wmGizmoGroupType *gzgt)
+{
+ /* could use hash lookups as operator types do, for now simple search. */
+ for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first;
+ gzgt_ref;
+ gzgt_ref = gzgt_ref->next)
+ {
+ if (gzgt_ref->type == gzgt) {
+ return gzgt_ref;
+ }
+ }
+ return NULL;
+}
+
+struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(
+ struct wmGizmoMapType *gzmap_type,
+ const char *idname)
+{
+ /* could use hash lookups as operator types do, for now simple search. */
+ for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first;
+ gzgt_ref;
+ gzgt_ref = gzgt_ref->next)
+ {
+ if (STREQ(idname, gzgt_ref->type->idname)) {
+ return gzgt_ref;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Use this for registering gizmos on startup. For runtime, use #WM_gizmomaptype_group_link_runtime.
+ */
+wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(
+ wmGizmoMapType *gzmap_type, const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ BLI_assert(gzgt != NULL);
+ return WM_gizmomaptype_group_link_ptr(gzmap_type, gzgt);
+}
+
+wmGizmoGroupTypeRef *WM_gizmomaptype_group_link_ptr(
+ wmGizmoMapType *gzmap_type, wmGizmoGroupType *gzgt)
+{
+ wmGizmoGroupTypeRef *gzgt_ref = MEM_callocN(sizeof(wmGizmoGroupTypeRef), "gizmo-group-ref");
+ gzgt_ref->type = gzgt;
+ BLI_addtail(&gzmap_type->grouptype_refs, gzgt_ref);
+ return gzgt_ref;
+}
+
+void WM_gizmomaptype_group_init_runtime_keymap(
+ const Main *bmain,
+ wmGizmoGroupType *gzgt)
+{
+ /* init keymap - on startup there's an extra call to init keymaps for 'permanent' gizmo-groups */
+ wm_gizmogrouptype_setup_keymap(gzgt, ((wmWindowManager *)bmain->wm.first)->defaultconf);
+}
+
+void WM_gizmomaptype_group_init_runtime(
+ const Main *bmain, wmGizmoMapType *gzmap_type,
+ wmGizmoGroupType *gzgt)
+{
+ /* now create a gizmo for all existing areas */
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ for (ARegion *ar = lb->first; ar; ar = ar->next) {
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ if (gzmap && gzmap->type == gzmap_type) {
+ wm_gizmogroup_new_from_type(gzmap, gzgt);
+
+ /* just add here, drawing will occur on next update */
+ wm_gizmomap_highlight_set(gzmap, NULL, NULL, 0);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free.
+ */
+void WM_gizmomaptype_group_free(wmGizmoGroupTypeRef *gzgt_ref)
+{
+ MEM_freeN(gzgt_ref);
+}
+
+void WM_gizmomaptype_group_unlink(
+ bContext *C, Main *bmain, wmGizmoMapType *gzmap_type,
+ const wmGizmoGroupType *gzgt)
+{
+ /* Free instances. */
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ for (ARegion *ar = lb->first; ar; ar = ar->next) {
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ if (gzmap && gzmap->type == gzmap_type) {
+ wmGizmoGroup *gzgroup, *gzgroup_next;
+ for (gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup_next) {
+ gzgroup_next = gzgroup->next;
+ if (gzgroup->type == gzgt) {
+ BLI_assert(gzgroup->parent_gzmap == gzmap);
+ wm_gizmogroup_free(C, gzgroup);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Free types. */
+ wmGizmoGroupTypeRef *gzgt_ref = WM_gizmomaptype_group_find_ptr(gzmap_type, gzgt);
+ if (gzgt_ref) {
+ BLI_remlink(&gzmap_type->grouptype_refs, gzgt_ref);
+ WM_gizmomaptype_group_free(gzgt_ref);
+ }
+
+ /* Note, we may want to keep this keymap for editing */
+ WM_keymap_remove(gzgt->keyconf, gzgt->keymap);
+
+ BLI_assert(WM_gizmomaptype_group_find_ptr(gzmap_type, gzgt) == NULL);
+}
+
+void wm_gizmogrouptype_setup_keymap(
+ wmGizmoGroupType *gzgt, wmKeyConfig *keyconf)
+{
+ /* Use flag since setup_keymap may return NULL,
+ * in that case we better not keep calling it. */
+ if (gzgt->type_update_flag & WM_GIZMOMAPTYPE_KEYMAP_INIT) {
+ gzgt->keymap = gzgt->setup_keymap(gzgt, keyconf);
+ gzgt->keyconf = keyconf;
+ gzgt->type_update_flag &= ~WM_GIZMOMAPTYPE_KEYMAP_INIT;
+ }
+}
+
+/** \} */ /* wmGizmoGroupType */
+
+/* -------------------------------------------------------------------- */
+/** \name High Level Add/Remove API
+ *
+ * For use directly from operators & RNA registration.
+ *
+ * \note In context of gizmo API these names are a bit misleading,
+ * but for general use terms its OK.
+ * `WM_gizmo_group_type_add` would be more correctly called:
+ * `WM_gizmomaptype_grouptype_reference_link`
+ * but for general purpose API this is too detailed & annoying.
+ *
+ * \note We may want to return a value if there is nothing to remove.
+ *
+ * \{ */
+
+void WM_gizmo_group_type_add_ptr_ex(
+ wmGizmoGroupType *gzgt,
+ wmGizmoMapType *gzmap_type)
+{
+ WM_gizmomaptype_group_link_ptr(gzmap_type, gzgt);
+
+ WM_gizmoconfig_update_tag_init(gzmap_type, gzgt);
+}
+void WM_gizmo_group_type_add_ptr(
+ wmGizmoGroupType *gzgt)
+{
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
+ WM_gizmo_group_type_add_ptr_ex(gzgt, gzmap_type);
+}
+void WM_gizmo_group_type_add(const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ BLI_assert(gzgt != NULL);
+ WM_gizmo_group_type_add_ptr(gzgt);
+}
+
+bool WM_gizmo_group_type_ensure_ptr_ex(
+ wmGizmoGroupType *gzgt,
+ wmGizmoMapType *gzmap_type)
+{
+ wmGizmoGroupTypeRef *gzgt_ref = WM_gizmomaptype_group_find_ptr(gzmap_type, gzgt);
+ if (gzgt_ref == NULL) {
+ WM_gizmo_group_type_add_ptr_ex(gzgt, gzmap_type);
+ return true;
+ }
+ return false;
+}
+bool WM_gizmo_group_type_ensure_ptr(
+ wmGizmoGroupType *gzgt)
+{
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
+ return WM_gizmo_group_type_ensure_ptr_ex(gzgt, gzmap_type);
+}
+bool WM_gizmo_group_type_ensure(const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ BLI_assert(gzgt != NULL);
+ return WM_gizmo_group_type_ensure_ptr(gzgt);
+}
+
+void WM_gizmo_group_type_remove_ptr_ex(
+ struct Main *bmain, wmGizmoGroupType *gzgt,
+ wmGizmoMapType *gzmap_type)
+{
+ WM_gizmomaptype_group_unlink(NULL, bmain, gzmap_type, gzgt);
+ WM_gizmogrouptype_free_ptr(gzgt);
+}
+void WM_gizmo_group_type_remove_ptr(
+ struct Main *bmain, wmGizmoGroupType *gzgt)
+{
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
+ WM_gizmo_group_type_remove_ptr_ex(bmain, gzgt, gzmap_type);
+}
+void WM_gizmo_group_type_remove(struct Main *bmain, const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ BLI_assert(gzgt != NULL);
+ WM_gizmo_group_type_remove_ptr(bmain, gzgt);
+}
+
+void WM_gizmo_group_type_reinit_ptr_ex(
+ struct Main *bmain, wmGizmoGroupType *gzgt,
+ wmGizmoMapType *gzmap_type)
+{
+ wmGizmoGroupTypeRef *gzgt_ref = WM_gizmomaptype_group_find_ptr(gzmap_type, gzgt);
+ BLI_assert(gzgt_ref != NULL);
+ UNUSED_VARS_NDEBUG(gzgt_ref);
+ WM_gizmomaptype_group_unlink(NULL, bmain, gzmap_type, gzgt);
+ WM_gizmo_group_type_add_ptr_ex(gzgt, gzmap_type);
+}
+void WM_gizmo_group_type_reinit_ptr(
+ struct Main *bmain, wmGizmoGroupType *gzgt)
+{
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
+ WM_gizmo_group_type_reinit_ptr_ex(bmain, gzgt, gzmap_type);
+}
+void WM_gizmo_group_type_reinit(struct Main *bmain, const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ BLI_assert(gzgt != NULL);
+ WM_gizmo_group_type_reinit_ptr(bmain, gzgt);
+}
+
+/* delayed versions */
+
+void WM_gizmo_group_type_unlink_delayed_ptr_ex(
+ wmGizmoGroupType *gzgt,
+ wmGizmoMapType *gzmap_type)
+{
+ WM_gizmoconfig_update_tag_remove(gzmap_type, gzgt);
+}
+
+void WM_gizmo_group_type_unlink_delayed_ptr(
+ wmGizmoGroupType *gzgt)
+{
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
+ WM_gizmo_group_type_unlink_delayed_ptr_ex(gzgt, gzmap_type);
+}
+
+void WM_gizmo_group_type_unlink_delayed(const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ BLI_assert(gzgt != NULL);
+ WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
new file mode 100644
index 00000000000..655d38a5206
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
@@ -0,0 +1,205 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
+ * \ingroup wm
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_context.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* only for own init/exit calls (wm_gizmogrouptype_init/wm_gizmogrouptype_free) */
+#include "wm.h"
+
+/* own includes */
+#include "wm_gizmo_wmapi.h"
+#include "wm_gizmo_intern.h"
+
+
+/** \name GizmoGroup Type Append
+ *
+ * \note This follows conventions from #WM_operatortype_find #WM_operatortype_append & friends.
+ * \{ */
+
+static GHash *global_gizmogrouptype_hash = NULL;
+
+wmGizmoGroupType *WM_gizmogrouptype_find(const char *idname, bool quiet)
+{
+ if (idname[0]) {
+ wmGizmoGroupType *gzgt;
+
+ gzgt = BLI_ghash_lookup(global_gizmogrouptype_hash, idname);
+ if (gzgt) {
+ return gzgt;
+ }
+
+ if (!quiet) {
+ printf("search for unknown gizmo group '%s'\n", idname);
+ }
+ }
+ else {
+ if (!quiet) {
+ printf("search for empty gizmo group\n");
+ }
+ }
+
+ return NULL;
+}
+
+/* caller must free */
+void WM_gizmogrouptype_iter(GHashIterator *ghi)
+{
+ BLI_ghashIterator_init(ghi, global_gizmogrouptype_hash);
+}
+
+static wmGizmoGroupType *wm_gizmogrouptype_append__begin(void)
+{
+ wmGizmoGroupType *gzgt = MEM_callocN(sizeof(wmGizmoGroupType), "gizmogrouptype");
+ gzgt->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_GizmoGroupProperties);
+#if 0
+ /* Set the default i18n context now, so that opfunc can redefine it if needed! */
+ RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
+#endif
+ return gzgt;
+}
+static void wm_gizmogrouptype_append__end(wmGizmoGroupType *gzgt)
+{
+ BLI_assert(gzgt->name != NULL);
+ BLI_assert(gzgt->idname != NULL);
+
+ RNA_def_struct_identifier(&BLENDER_RNA, gzgt->srna, gzgt->idname);
+
+ gzgt->type_update_flag |= WM_GIZMOMAPTYPE_KEYMAP_INIT;
+
+ /* if not set, use default */
+ if (gzgt->setup_keymap == NULL) {
+ if (gzgt->flag & WM_GIZMOGROUPTYPE_SELECT) {
+ gzgt->setup_keymap = WM_gizmogroup_keymap_common_select;
+ }
+ else {
+ gzgt->setup_keymap = WM_gizmogroup_keymap_common;
+ }
+ }
+
+ BLI_ghash_insert(global_gizmogrouptype_hash, (void *)gzgt->idname, gzgt);
+}
+
+wmGizmoGroupType *WM_gizmogrouptype_append(
+ void (*wtfunc)(struct wmGizmoGroupType *))
+{
+ wmGizmoGroupType *gzgt = wm_gizmogrouptype_append__begin();
+ wtfunc(gzgt);
+ wm_gizmogrouptype_append__end(gzgt);
+ return gzgt;
+}
+
+wmGizmoGroupType *WM_gizmogrouptype_append_ptr(
+ void (*wtfunc)(struct wmGizmoGroupType *, void *), void *userdata)
+{
+ wmGizmoGroupType *gzgt = wm_gizmogrouptype_append__begin();
+ wtfunc(gzgt, userdata);
+ wm_gizmogrouptype_append__end(gzgt);
+ return gzgt;
+}
+
+/**
+ * Append and insert into a gizmo typemap.
+ * This is most common for C gizmos which are enabled by default.
+ */
+wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(
+ wmGizmoMapType *gzmap_type,
+ void (*wtfunc)(struct wmGizmoGroupType *))
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_append(wtfunc);
+
+ gzgt->gzmap_params.spaceid = gzmap_type->spaceid;
+ gzgt->gzmap_params.regionid = gzmap_type->regionid;
+
+ return WM_gizmomaptype_group_link_ptr(gzmap_type, gzgt);
+}
+
+/**
+ * Free but don't remove from ghash.
+ */
+static void gizmogrouptype_free(wmGizmoGroupType *gzgt)
+{
+ if (gzgt->ext.srna) { /* python gizmo group, allocs own string */
+ MEM_freeN((void *)gzgt->idname);
+ }
+
+ MEM_freeN(gzgt);
+}
+
+void WM_gizmogrouptype_free_ptr(wmGizmoGroupType *gzgt)
+{
+ BLI_assert(gzgt == WM_gizmogrouptype_find(gzgt->idname, false));
+
+ BLI_ghash_remove(global_gizmogrouptype_hash, gzgt->idname, NULL, NULL);
+
+ gizmogrouptype_free(gzgt);
+
+ /* XXX, TODO, update the world! */
+}
+
+bool WM_gizmogrouptype_free(const char *idname)
+{
+ wmGizmoGroupType *gzgt = BLI_ghash_lookup(global_gizmogrouptype_hash, idname);
+
+ if (gzgt == NULL) {
+ return false;
+ }
+
+ WM_gizmogrouptype_free_ptr(gzgt);
+
+ return true;
+}
+
+static void wm_gizmogrouptype_ghash_free_cb(wmGizmoGroupType *gzgt)
+{
+ gizmogrouptype_free(gzgt);
+}
+
+void wm_gizmogrouptype_free(void)
+{
+ BLI_ghash_free(global_gizmogrouptype_hash, NULL, (GHashValFreeFP)wm_gizmogrouptype_ghash_free_cb);
+ global_gizmogrouptype_hash = NULL;
+}
+
+/* called on initialize WM_init() */
+void wm_gizmogrouptype_init(void)
+{
+ /* reserve size is set based on blender default setup */
+ global_gizmogrouptype_hash = BLI_ghash_str_new_ex("wm_gizmogrouptype_init gh", 128);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
new file mode 100644
index 00000000000..a580a063aaf
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
@@ -0,0 +1,144 @@
+/*
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
+ * \ingroup wm
+ */
+
+
+#ifndef __WM_GIZMO_INTERN_H__
+#define __WM_GIZMO_INTERN_H__
+
+struct wmKeyConfig;
+struct wmGizmoMap;
+struct GizmoGeomInfo;
+struct GHashIterator;
+
+#include "wm_gizmo_fn.h"
+
+/* -------------------------------------------------------------------- */
+/* wmGizmo */
+
+
+bool wm_gizmo_select_set_ex(
+ struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select,
+ bool use_array, bool use_callback);
+bool wm_gizmo_select_and_highlight(bContext *C, struct wmGizmoMap *gzmap, struct wmGizmo *gz);
+
+void wm_gizmo_calculate_scale(struct wmGizmo *gz, const bContext *C);
+void wm_gizmo_update(struct wmGizmo *gz, const bContext *C, const bool refresh_map);
+
+int wm_gizmo_is_visible(struct wmGizmo *gz);
+enum {
+ WM_GIZMO_IS_VISIBLE_UPDATE = (1 << 0),
+ WM_GIZMO_IS_VISIBLE_DRAW = (1 << 1),
+};
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoGroup */
+
+enum {
+ TWEAK_MODAL_CANCEL = 1,
+ TWEAK_MODAL_CONFIRM,
+ TWEAK_MODAL_PRECISION_ON,
+ TWEAK_MODAL_PRECISION_OFF,
+ TWEAK_MODAL_SNAP_ON,
+ TWEAK_MODAL_SNAP_OFF,
+};
+
+struct wmGizmoGroup *wm_gizmogroup_new_from_type(
+ struct wmGizmoMap *gzmap, struct wmGizmoGroupType *gzgt);
+void wm_gizmogroup_free(bContext *C, struct wmGizmoGroup *gzgroup);
+void wm_gizmogroup_gizmo_register(struct wmGizmoGroup *gzgroup, struct wmGizmo *gz);
+struct wmGizmo *wm_gizmogroup_find_intersected_gizmo(
+ const struct wmGizmoGroup *gzgroup, struct bContext *C, const struct wmEvent *event,
+ int *r_part);
+void wm_gizmogroup_intersectable_gizmos_to_list(
+ const struct wmGizmoGroup *gzgroup, struct ListBase *listbase);
+void wm_gizmogroup_ensure_initialized(struct wmGizmoGroup *gzgroup, const struct bContext *C);
+bool wm_gizmogroup_is_visible_in_drawstep(
+ const struct wmGizmoGroup *gzgroup, const eWM_GizmoFlagMapDrawStep drawstep);
+
+void wm_gizmogrouptype_setup_keymap(
+ struct wmGizmoGroupType *gzgt, struct wmKeyConfig *keyconf);
+
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoMap */
+
+typedef struct wmGizmoMapSelectState {
+ struct wmGizmo **items;
+ int len, len_alloc;
+} wmGizmoMapSelectState;
+
+struct wmGizmoMap {
+
+ struct wmGizmoMapType *type;
+ ListBase groups; /* wmGizmoGroup */
+
+ /* private, update tagging (enum defined in C source). */
+ char update_flag[WM_GIZMOMAP_DRAWSTEP_MAX];
+
+ /**
+ * \brief Gizmo map runtime context
+ *
+ * Contains information about this gizmo-map. Currently
+ * highlighted gizmo, currently selected gizmos, ...
+ */
+ struct {
+ /* we redraw the gizmo-map when this changes */
+ struct wmGizmo *highlight;
+ /* User has clicked this gizmo and it gets all input. */
+ struct wmGizmo *modal;
+ /* array for all selected gizmos */
+ struct wmGizmoMapSelectState select;
+ /* cursor location at point of entering modal (see: WM_GIZMO_MOVE_CURSOR) */
+ int event_xy[2];
+ short event_grabcursor;
+ /* until we have nice cursor push/pop API. */
+ int last_cursor;
+ } gzmap_context;
+};
+
+/**
+ * This is a container for all gizmo types that can be instantiated in a region.
+ * (similar to dropboxes).
+ *
+ * \note There is only ever one of these for every (area, region) combination.
+ */
+struct wmGizmoMapType {
+ struct wmGizmoMapType *next, *prev;
+ short spaceid, regionid;
+ /* types of gizmo-groups for this gizmo-map type */
+ ListBase grouptype_refs;
+
+ /* eGizmoMapTypeUpdateFlags */
+ eWM_GizmoFlagMapTypeUpdateFlag type_update_flag;
+};
+
+void wm_gizmomap_select_array_clear(struct wmGizmoMap *gzmap);
+bool wm_gizmomap_deselect_all(struct wmGizmoMap *gzmap);
+void wm_gizmomap_select_array_shrink(struct wmGizmoMap *gzmap, int len_subtract);
+void wm_gizmomap_select_array_push_back(struct wmGizmoMap *gzmap, wmGizmo *gz);
+void wm_gizmomap_select_array_remove(struct wmGizmoMap *gzmap, wmGizmo *gz);
+
+#endif
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
new file mode 100644
index 00000000000..ec8e012b1a7
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -0,0 +1,1242 @@
+/*
+ * ***** 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) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+ * \ingroup wm
+ */
+
+#include <string.h>
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "ED_screen.h"
+#include "ED_select_utils.h"
+#include "ED_view3d.h"
+
+#include "GPU_glew.h"
+#include "GPU_matrix.h"
+#include "GPU_select.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm_event_system.h"
+
+/* for tool-tips */
+#include "UI_interface.h"
+
+#include "DEG_depsgraph.h"
+
+/* own includes */
+#include "wm_gizmo_wmapi.h"
+#include "wm_gizmo_intern.h"
+
+/**
+ * Store all gizmo-maps here. Anyone who wants to register a gizmo for a certain
+ * area type can query the gizmo-map to do so.
+ */
+static ListBase gizmomaptypes = {NULL, NULL};
+
+/**
+ * Update when gizmo-map types change.
+ */
+/* so operator removal can trigger update */
+typedef enum eWM_GizmoFlagGroupTypeGlobalFlag {
+ WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT = (1 << 0),
+ WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE = (1 << 1),
+} eWM_GizmoFlagGroupTypeGlobalFlag;
+
+static eWM_GizmoFlagGroupTypeGlobalFlag wm_gzmap_type_update_flag = 0;
+
+/**
+ * Gizmo-map update tagging.
+ */
+enum {
+ /** #gizmomap_prepare_drawing has run */
+ GIZMOMAP_IS_PREPARE_DRAW = (1 << 0),
+ GIZMOMAP_IS_REFRESH_CALLBACK = (1 << 1),
+};
+
+
+/* -------------------------------------------------------------------- */
+/** \name wmGizmoMap Selection Array API
+ *
+ * Just handle ``wm_gizmomap_select_array_*``, not flags or callbacks.
+ *
+ * \{ */
+
+static void wm_gizmomap_select_array_ensure_len_alloc(wmGizmoMap *gzmap, int len)
+{
+ wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
+ if (len <= msel->len_alloc) {
+ return;
+ }
+ msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * len);
+ msel->len_alloc = len;
+}
+
+void wm_gizmomap_select_array_clear(wmGizmoMap *gzmap)
+{
+ wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
+ MEM_SAFE_FREE(msel->items);
+ msel->len = 0;
+ msel->len_alloc = 0;
+}
+
+void wm_gizmomap_select_array_shrink(wmGizmoMap *gzmap, int len_subtract)
+{
+ wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
+ msel->len -= len_subtract;
+ if (msel->len <= 0) {
+ wm_gizmomap_select_array_clear(gzmap);
+ }
+ else {
+ if (msel->len < msel->len_alloc / 2) {
+ msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * msel->len);
+ msel->len_alloc = msel->len;
+ }
+ }
+}
+
+void wm_gizmomap_select_array_push_back(wmGizmoMap *gzmap, wmGizmo *gz)
+{
+ wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
+ BLI_assert(msel->len <= msel->len_alloc);
+ if (msel->len == msel->len_alloc) {
+ msel->len_alloc = (msel->len + 1) * 2;
+ msel->items = MEM_reallocN(msel->items, sizeof(*msel->items) * msel->len_alloc);
+ }
+ msel->items[msel->len++] = gz;
+}
+
+void wm_gizmomap_select_array_remove(wmGizmoMap *gzmap, wmGizmo *gz)
+{
+ wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
+ /* remove gizmo from selected_gizmos array */
+ for (int i = 0; i < msel->len; i++) {
+ if (msel->items[i] == gz) {
+ for (int j = i; j < (msel->len - 1); j++) {
+ msel->items[j] = msel->items[j + 1];
+ }
+ wm_gizmomap_select_array_shrink(gzmap, 1);
+ break;
+ }
+ }
+
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name wmGizmoMap
+ *
+ * \{ */
+
+/**
+ * Creates a gizmo-map with all registered gizmos for that type
+ */
+wmGizmoMap *WM_gizmomap_new_from_type(
+ const struct wmGizmoMapType_Params *gzmap_params)
+{
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(gzmap_params);
+ wmGizmoMap *gzmap;
+
+ gzmap = MEM_callocN(sizeof(wmGizmoMap), "GizmoMap");
+ gzmap->type = gzmap_type;
+ WM_gizmomap_tag_refresh(gzmap);
+
+ /* create all gizmo-groups for this gizmo-map. We may create an empty one
+ * too in anticipation of gizmos from operators etc */
+ for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; gzgt_ref = gzgt_ref->next) {
+ wm_gizmogroup_new_from_type(gzmap, gzgt_ref->type);
+ }
+
+ return gzmap;
+}
+
+void wm_gizmomap_remove(wmGizmoMap *gzmap)
+{
+ /* Clear first so further calls don't waste time trying to maintain correct array state. */
+ wm_gizmomap_select_array_clear(gzmap);
+
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first, *gzgroup_next; gzgroup; gzgroup = gzgroup_next) {
+ gzgroup_next = gzgroup->next;
+ BLI_assert(gzgroup->parent_gzmap == gzmap);
+ wm_gizmogroup_free(NULL, gzgroup);
+ }
+ BLI_assert(BLI_listbase_is_empty(&gzmap->groups));
+
+ MEM_freeN(gzmap);
+}
+
+
+wmGizmoGroup *WM_gizmomap_group_find(
+ struct wmGizmoMap *gzmap,
+ const char *idname)
+{
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ if (gzgt) {
+ return WM_gizmomap_group_find_ptr(gzmap, gzgt);
+ }
+ return NULL;
+}
+
+wmGizmoGroup *WM_gizmomap_group_find_ptr(
+ struct wmGizmoMap *gzmap,
+ const struct wmGizmoGroupType *gzgt)
+{
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ if (gzgroup->type == gzgt) {
+ return gzgroup;
+ }
+ }
+ return NULL;
+}
+
+const ListBase *WM_gizmomap_group_list(wmGizmoMap *gzmap)
+{
+ return &gzmap->groups;
+}
+
+bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
+{
+ return gzmap->gzmap_context.select.len != 0;
+}
+
+/**
+ * \note We could use a callback to define bounds, for now just use matrix location.
+ */
+bool WM_gizmomap_minmax(
+ const wmGizmoMap *gzmap, bool UNUSED(use_hidden), bool use_select,
+ float r_min[3], float r_max[3])
+{
+ if (use_select) {
+ int i;
+ for (i = 0; i < gzmap->gzmap_context.select.len; i++) {
+ minmax_v3v3_v3(r_min, r_max, gzmap->gzmap_context.select.items[i]->matrix_basis[3]);
+ }
+ return i != 0;
+ }
+ else {
+ bool ok = false;
+ BLI_assert(!"TODO");
+ return ok;
+ }
+}
+
+/**
+ * Creates and returns idname hash table for (visible) gizmos in \a gzmap
+ *
+ * \param poll Polling function for excluding gizmos.
+ * \param data Custom data passed to \a poll
+ *
+ * TODO(campbell): this uses unreliable order,
+ * best we use an iterator function instead of a hash.
+ */
+static GHash *WM_gizmomap_gizmo_hash_new(
+ const bContext *C, wmGizmoMap *gzmap,
+ bool (*poll)(const wmGizmo *, void *),
+ void *data, const eWM_GizmoFlag flag_exclude)
+{
+ GHash *hash = BLI_ghash_ptr_new(__func__);
+
+ /* collect gizmos */
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ if (((flag_exclude == 0) || ((gz->flag & flag_exclude) == 0)) &&
+ (!poll || poll(gz, data)))
+ {
+ BLI_ghash_insert(hash, gz, gz);
+ }
+ }
+ }
+ }
+
+ return hash;
+}
+
+void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
+{
+ if (gzmap) {
+ /* We might want only to refresh some, for tag all steps. */
+ for (int i = 0; i < WM_GIZMOMAP_DRAWSTEP_MAX; i++) {
+ gzmap->update_flag[i] |= (
+ GIZMOMAP_IS_PREPARE_DRAW |
+ GIZMOMAP_IS_REFRESH_CALLBACK);
+ }
+ }
+}
+
+static bool gizmo_prepare_drawing(
+ wmGizmoMap *gzmap, wmGizmo *gz,
+ const bContext *C, ListBase *draw_gizmos,
+ const eWM_GizmoFlagMapDrawStep drawstep)
+{
+ int do_draw = wm_gizmo_is_visible(gz);
+ if (do_draw == 0) {
+ /* skip */
+ }
+ else {
+ /* Ensure we get RNA updates */
+ if (do_draw & WM_GIZMO_IS_VISIBLE_UPDATE) {
+ /* hover gizmos need updating, even if we don't draw them */
+ wm_gizmo_update(gz, C, (gzmap->update_flag[drawstep] & GIZMOMAP_IS_PREPARE_DRAW) != 0);
+ }
+ if (do_draw & WM_GIZMO_IS_VISIBLE_DRAW) {
+ BLI_addhead(draw_gizmos, BLI_genericNodeN(gz));
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Update gizmos of \a gzmap to prepare for drawing. Adds all gizmos that
+ * should be drawn to list \a draw_gizmos, note that added items need freeing.
+ */
+static void gizmomap_prepare_drawing(
+ wmGizmoMap *gzmap, const bContext *C, ListBase *draw_gizmos,
+ const eWM_GizmoFlagMapDrawStep drawstep)
+{
+ if (!gzmap || BLI_listbase_is_empty(&gzmap->groups))
+ return;
+ wmGizmo *gz_modal = gzmap->gzmap_context.modal;
+
+ /* only active gizmo needs updating */
+ if (gz_modal) {
+ if ((gz_modal->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL) == 0) {
+ if (wm_gizmogroup_is_visible_in_drawstep(gz_modal->parent_gzgroup, drawstep)) {
+ if (gizmo_prepare_drawing(gzmap, gz_modal, C, draw_gizmos, drawstep)) {
+ gzmap->update_flag[drawstep] &= ~GIZMOMAP_IS_PREPARE_DRAW;
+ }
+ }
+ /* don't draw any other gizmos */
+ return;
+ }
+ }
+
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ /* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
+ if (!wm_gizmogroup_is_visible_in_drawstep(gzgroup, drawstep) ||
+ !WM_gizmo_group_type_poll(C, gzgroup->type))
+ {
+ continue;
+ }
+
+ /* needs to be initialized on first draw */
+ /* XXX weak: Gizmo-group may skip refreshing if it's invisible (map gets untagged nevertheless) */
+ if (gzmap->update_flag[drawstep] & GIZMOMAP_IS_REFRESH_CALLBACK) {
+ /* force refresh again. */
+ gzgroup->init_flag &= ~WM_GIZMOGROUP_INIT_REFRESH;
+ }
+ /* Calls `setup`, `setup_keymap` and `refresh` if they're defined. */
+ wm_gizmogroup_ensure_initialized(gzgroup, C);
+
+ /* prepare drawing */
+ if (gzgroup->type->draw_prepare) {
+ gzgroup->type->draw_prepare(C, gzgroup);
+ }
+
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ gizmo_prepare_drawing(gzmap, gz, C, draw_gizmos, drawstep);
+ }
+ }
+
+ gzmap->update_flag[drawstep] &=
+ ~(GIZMOMAP_IS_REFRESH_CALLBACK |
+ GIZMOMAP_IS_PREPARE_DRAW);
+}
+
+/**
+ * Draw all visible gizmos in \a gzmap.
+ * Uses global draw_gizmos listbase.
+ */
+static void gizmos_draw_list(const wmGizmoMap *gzmap, const bContext *C, ListBase *draw_gizmos)
+{
+ /* Can be empty if we're dynamically added and removed. */
+ if ((gzmap == NULL) || BLI_listbase_is_empty(&gzmap->groups)) {
+ return;
+ }
+
+ /* TODO this will need it own shader probably? don't think it can be handled from that point though. */
+/* const bool use_lighting = (U.gizmo_flag & V3D_GIZMO_SHADED) != 0; */
+
+ bool is_depth_prev = false;
+
+ /* draw_gizmos contains all visible gizmos - draw them */
+ for (LinkData *link = draw_gizmos->first, *link_next; link; link = link_next) {
+ wmGizmo *gz = link->data;
+ link_next = link->next;
+
+ bool is_depth = (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_DEPTH_3D) != 0;
+
+ /* Weak! since we don't 100% support depth yet (select ignores depth) always show highlighted */
+ if (is_depth && (gz->state & WM_GIZMO_STATE_HIGHLIGHT)) {
+ is_depth = false;
+ }
+
+ if (is_depth == is_depth_prev) {
+ /* pass */
+ }
+ else {
+ if (is_depth) {
+ glEnable(GL_DEPTH_TEST);
+ }
+ else {
+ glDisable(GL_DEPTH_TEST);
+ }
+ is_depth_prev = is_depth;
+ }
+
+ /* XXX force AntiAlias Gizmos. */
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_POLYGON_SMOOTH);
+
+ gz->type->draw(C, gz);
+
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_POLYGON_SMOOTH);
+
+ /* free/remove gizmo link after drawing */
+ BLI_freelinkN(draw_gizmos, link);
+ }
+
+ if (is_depth_prev) {
+ glDisable(GL_DEPTH_TEST);
+ }
+}
+
+void WM_gizmomap_draw(
+ wmGizmoMap *gzmap, const bContext *C,
+ const eWM_GizmoFlagMapDrawStep drawstep)
+{
+ if (!WM_gizmo_context_check_drawstep(C, drawstep)) {
+ return;
+ }
+
+ ListBase draw_gizmos = {NULL};
+
+ gizmomap_prepare_drawing(gzmap, C, &draw_gizmos, drawstep);
+ gizmos_draw_list(gzmap, C, &draw_gizmos);
+ BLI_assert(BLI_listbase_is_empty(&draw_gizmos));
+}
+
+static void gizmo_draw_select_3D_loop(
+ const bContext *C, ListBase *visible_gizmos,
+ const wmGizmo *gz_stop)
+{
+ int select_id = 0;
+ wmGizmo *gz;
+
+ /* TODO(campbell): this depends on depth buffer being written to, currently broken for the 3D view. */
+ bool is_depth_prev = false;
+ bool is_depth_skip_prev = false;
+
+ for (LinkData *link = visible_gizmos->first; link; link = link->next, select_id++) {
+ gz = link->data;
+ if (gz == gz_stop) {
+ break;
+ }
+ if (gz->type->draw_select == NULL) {
+ continue;
+ }
+
+ bool is_depth = (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_DEPTH_3D) != 0;
+ if (is_depth == is_depth_prev) {
+ /* pass */
+ }
+ else {
+ if (is_depth) {
+ glEnable(GL_DEPTH_TEST);
+ }
+ else {
+ glDisable(GL_DEPTH_TEST);
+ }
+ is_depth_prev = is_depth;
+ }
+ bool is_depth_skip = (gz->flag & WM_GIZMO_SELECT_BACKGROUND) != 0;
+ if (is_depth_skip == is_depth_skip_prev) {
+ /* pass */
+ }
+ else {
+ glDepthMask(!is_depth_skip);
+ is_depth_skip_prev = is_depth_skip;
+ }
+
+ /* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */
+
+ gz->type->draw_select(C, gz, select_id << 8);
+ }
+
+ if (is_depth_prev) {
+ glDisable(GL_DEPTH_TEST);
+ }
+ if (is_depth_skip_prev) {
+ glDepthMask(true);
+ }
+}
+
+static int gizmo_find_intersected_3d_intern(
+ ListBase *visible_gizmos, const bContext *C, const int co[2],
+ const int hotspot, const wmGizmo *gz_stop)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = sa->spacedata.first;
+ rcti rect;
+ /* Almost certainly overkill, but allow for many custom gizmos. */
+ GLuint buffer[MAXPICKBUF];
+ short hits;
+ const bool do_passes = GPU_select_query_check_active();
+
+ BLI_rcti_init_pt_radius(&rect, co, hotspot);
+
+ ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, v3d, NULL, NULL, &rect);
+
+ if (do_passes)
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ else
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_ALL, 0);
+ /* do the drawing */
+ gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop);
+
+ hits = GPU_select_end();
+
+ if (do_passes && (hits > 0)) {
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+ gizmo_draw_select_3D_loop(C, visible_gizmos, gz_stop);
+ GPU_select_end();
+ }
+
+ ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, v3d, NULL, NULL, NULL);
+
+ const GLuint *hit_near = GPU_select_buffer_near(buffer, hits);
+
+ return hit_near ? hit_near[3] : -1;
+}
+
+/**
+ * Try to find a 3D gizmo at screen-space coordinate \a co. Uses OpenGL picking.
+ */
+static wmGizmo *gizmo_find_intersected_3d(
+ bContext *C, const int co[2], ListBase *visible_gizmos,
+ int *r_part)
+{
+ wmGizmo *result = NULL;
+ int hit = -1;
+
+ *r_part = 0;
+
+ /* set up view matrices */
+ view3d_operator_needs_opengl(C);
+
+ /* Search for 3D gizmo's that use the 2D callback for checking intersections. */
+ bool has_3d = false;
+ {
+ int select_id = 0;
+ for (LinkData *link = visible_gizmos->first; link; link = link->next, select_id++) {
+ wmGizmo *gz = link->data;
+ /* With both defined, favor the 3D, incase the gizmo can be used in 2D or 3D views. */
+ if (gz->type->test_select && (gz->type->draw_select == NULL)) {
+ if ((*r_part = gz->type->test_select(C, gz, co)) != -1) {
+ hit = select_id;
+ result = gz;
+ break;
+ }
+ }
+ else {
+ has_3d = true;
+ }
+ }
+ }
+
+ /* Search for 3D intersections if they're before 2D that have been found (if any).
+ * This way we always use the first hit. */
+ if (has_3d) {
+ const int hotspot_radii[] = {
+ 3 * U.pixelsize,
+ /* This runs on mouse move, careful doing too many tests! */
+ 10 * U.pixelsize,
+ };
+ for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
+ hit = gizmo_find_intersected_3d_intern(visible_gizmos, C, co, hotspot_radii[i], result);
+ if (hit != -1) {
+ break;
+ }
+ }
+
+ if (hit != -1) {
+ LinkData *link = BLI_findlink(visible_gizmos, hit >> 8);
+ if (link != NULL) {
+ *r_part = hit & 255;
+ result = link->data;
+ }
+ else {
+ /* All gizmos should use selection ID they're given as part of the callback,
+ * if they don't it will attempt tp lookup non-existing index. */
+ BLI_assert(0);
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Try to find a gizmo under the mouse position. 2D intersections have priority over
+ * 3D ones (could check for smallest screen-space distance but not needed right now).
+ */
+wmGizmo *wm_gizmomap_highlight_find(
+ wmGizmoMap *gzmap, bContext *C, const wmEvent *event,
+ int *r_part)
+{
+ wmGizmo *gz = NULL;
+ ListBase visible_3d_gizmos = {NULL};
+ bool do_step[WM_GIZMOMAP_DRAWSTEP_MAX];
+
+ for (int i = 0; i < ARRAY_SIZE(do_step); i++) {
+ do_step[i] = WM_gizmo_context_check_drawstep(C, i);
+ }
+
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+
+ /* If it were important we could initialize here,
+ * but this only happens when events are handled before drawing,
+ * just skip to keep code-path for initializing gizmos simple. */
+ if ((gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0) {
+ continue;
+ }
+
+ if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
+ eWM_GizmoFlagMapDrawStep step;
+ if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
+ step = WM_GIZMOMAP_DRAWSTEP_3D;
+ }
+ else {
+ step = WM_GIZMOMAP_DRAWSTEP_2D;
+ }
+
+ if (do_step[step]) {
+ if ((gzmap->update_flag[step] & GIZMOMAP_IS_REFRESH_CALLBACK) &&
+ (gzgroup->type->refresh != NULL))
+ {
+ gzgroup->type->refresh(C, gzgroup);
+ /* cleared below */
+ }
+ if (step == WM_GIZMOMAP_DRAWSTEP_3D) {
+ wm_gizmogroup_intersectable_gizmos_to_list(gzgroup, &visible_3d_gizmos);
+ }
+ else if (step == WM_GIZMOMAP_DRAWSTEP_2D) {
+ if ((gz = wm_gizmogroup_find_intersected_gizmo(gzgroup, C, event, r_part))) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!BLI_listbase_is_empty(&visible_3d_gizmos)) {
+ /* 2D gizmos get priority. */
+ if (gz == NULL) {
+ gz = gizmo_find_intersected_3d(C, event->mval, &visible_3d_gizmos, r_part);
+ }
+ BLI_freelistN(&visible_3d_gizmos);
+ }
+
+ gzmap->update_flag[WM_GIZMOMAP_DRAWSTEP_3D] &= ~GIZMOMAP_IS_REFRESH_CALLBACK;
+ gzmap->update_flag[WM_GIZMOMAP_DRAWSTEP_2D] &= ~GIZMOMAP_IS_REFRESH_CALLBACK;
+
+ return gz;
+}
+
+void WM_gizmomap_add_handlers(ARegion *ar, wmGizmoMap *gzmap)
+{
+ wmEventHandler *handler;
+
+ for (handler = ar->handlers.first; handler; handler = handler->next) {
+ if (handler->gizmo_map == gzmap) {
+ return;
+ }
+ }
+
+ handler = MEM_callocN(sizeof(wmEventHandler), "gizmo handler");
+
+ BLI_assert(gzmap == ar->gizmo_map);
+ handler->gizmo_map = gzmap;
+ BLI_addtail(&ar->handlers, handler);
+}
+
+void wm_gizmomaps_handled_modal_update(
+ bContext *C, wmEvent *event, wmEventHandler *handler)
+{
+ const bool modal_running = (handler->op != NULL);
+
+ /* happens on render or when joining areas */
+ if (!handler->op_region || !handler->op_region->gizmo_map) {
+ return;
+ }
+
+ wmGizmoMap *gzmap = handler->op_region->gizmo_map;
+ wmGizmo *gz = wm_gizmomap_modal_get(gzmap);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+
+ wm_gizmomap_handler_context(C, handler);
+
+ /* regular update for running operator */
+ if (modal_running) {
+ wmGizmoOpElem *gzop = gz ? WM_gizmo_operator_get(gz, gz->highlight_part) : NULL;
+ if (gz && gzop && (gzop->type != NULL) && (gzop->type == handler->op->type)) {
+ wmGizmoFnModal modal_fn = gz->custom_modal ? gz->custom_modal : gz->type->modal;
+ if (modal_fn != NULL) {
+ int retval = modal_fn(C, gz, event, 0);
+ /* The gizmo is tried to the operator, we can't choose when to exit. */
+ BLI_assert(retval & OPERATOR_RUNNING_MODAL);
+ UNUSED_VARS_NDEBUG(retval);
+ }
+ }
+ }
+ /* operator not running anymore */
+ else {
+ wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
+ if (gz) {
+ /* This isn't defined if it ends because of success of cancel, we may want to change. */
+ bool cancel = true;
+ if (gz->type->exit) {
+ gz->type->exit(C, gz, cancel);
+ }
+ wm_gizmomap_modal_set(gzmap, C, gz, NULL, false);
+ }
+ }
+
+ /* restore the area */
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+}
+
+/**
+ * Deselect all selected gizmos in \a gzmap.
+ * \return if selection has changed.
+ */
+bool wm_gizmomap_deselect_all(wmGizmoMap *gzmap)
+{
+ wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
+
+ if (msel->items == NULL || msel->len == 0) {
+ return false;
+ }
+
+ for (int i = 0; i < msel->len; i++) {
+ wm_gizmo_select_set_ex(gzmap, msel->items[i], false, false, true);
+ }
+
+ wm_gizmomap_select_array_clear(gzmap);
+
+ /* always return true, we already checked
+ * if there's anything to deselect */
+ return true;
+}
+
+BLI_INLINE bool gizmo_selectable_poll(const wmGizmo *gz, void *UNUSED(data))
+{
+ return (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_SELECT);
+}
+
+/**
+ * Select all selectable gizmos in \a gzmap.
+ * \return if selection has changed.
+ */
+static bool wm_gizmomap_select_all_intern(
+ bContext *C, wmGizmoMap *gzmap)
+{
+ wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select;
+ /* GHash is used here to avoid having to loop over all gizmos twice (once to
+ * get tot_sel for allocating, once for actually selecting). Instead we collect
+ * selectable gizmos in hash table and use this to get tot_sel and do selection */
+
+ GHash *hash = WM_gizmomap_gizmo_hash_new(
+ C, gzmap, gizmo_selectable_poll, NULL, WM_GIZMO_HIDDEN | WM_GIZMO_HIDDEN_SELECT);
+ GHashIterator gh_iter;
+ int i;
+ bool changed = false;
+
+ wm_gizmomap_select_array_ensure_len_alloc(gzmap, BLI_ghash_len(hash));
+
+ GHASH_ITER_INDEX (gh_iter, hash, i) {
+ wmGizmo *gz_iter = BLI_ghashIterator_getValue(&gh_iter);
+ WM_gizmo_select_set(gzmap, gz_iter, true);
+ }
+ /* highlight first gizmo */
+ wm_gizmomap_highlight_set(gzmap, C, msel->items[0], msel->items[0]->highlight_part);
+
+ BLI_assert(BLI_ghash_len(hash) == msel->len);
+
+ BLI_ghash_free(hash, NULL, NULL);
+ return changed;
+}
+
+/**
+ * Select/Deselect all selectable gizmos in \a gzmap.
+ * \return if selection has changed.
+ *
+ * TODO select all by type
+ */
+bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action)
+{
+ bool changed = false;
+
+ switch (action) {
+ case SEL_SELECT:
+ changed = wm_gizmomap_select_all_intern(C, gzmap);
+ break;
+ case SEL_DESELECT:
+ changed = wm_gizmomap_deselect_all(gzmap);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ if (changed)
+ WM_event_add_mousemove(C);
+
+ return changed;
+}
+
+/**
+ * Prepare context for gizmo handling (but only if area/region is
+ * part of screen). Version of #wm_handler_op_context for gizmos.
+ */
+void wm_gizmomap_handler_context(bContext *C, wmEventHandler *handler)
+{
+ bScreen *screen = CTX_wm_screen(C);
+
+ if (screen) {
+ if (handler->op_area == NULL) {
+ /* do nothing in this context */
+ }
+ else {
+ ScrArea *sa;
+
+ for (sa = screen->areabase.first; sa; sa = sa->next)
+ if (sa == handler->op_area)
+ break;
+ if (sa == NULL) {
+ /* when changing screen layouts with running modal handlers (like render display), this
+ * is not an error to print */
+ if (handler->gizmo_map == NULL)
+ printf("internal error: modal gizmo-map handler has invalid area\n");
+ }
+ else {
+ ARegion *ar;
+ CTX_wm_area_set(C, sa);
+ for (ar = sa->regionbase.first; ar; ar = ar->next)
+ if (ar == handler->op_region)
+ break;
+ /* XXX no warning print here, after full-area and back regions are remade */
+ if (ar)
+ CTX_wm_region_set(C, ar);
+ }
+ }
+ }
+}
+
+bool WM_gizmomap_cursor_set(const wmGizmoMap *gzmap, wmWindow *win)
+{
+ wmGizmo *gz = gzmap->gzmap_context.highlight;
+ if (gz && gz->type->cursor_get) {
+ WM_cursor_set(win, gz->type->cursor_get(gz));
+ return true;
+ }
+
+ return false;
+}
+
+bool wm_gizmomap_highlight_set(
+ wmGizmoMap *gzmap, const bContext *C, wmGizmo *gz, int part)
+{
+ if ((gz != gzmap->gzmap_context.highlight) ||
+ (gz && part != gz->highlight_part))
+ {
+ if (gzmap->gzmap_context.highlight) {
+ gzmap->gzmap_context.highlight->state &= ~WM_GIZMO_STATE_HIGHLIGHT;
+ gzmap->gzmap_context.highlight->highlight_part = -1;
+ }
+
+ gzmap->gzmap_context.highlight = gz;
+
+ if (gz) {
+ gz->state |= WM_GIZMO_STATE_HIGHLIGHT;
+ gz->highlight_part = part;
+ gzmap->gzmap_context.last_cursor = -1;
+
+ if (C && gz->type->cursor_get) {
+ wmWindow *win = CTX_wm_window(C);
+ gzmap->gzmap_context.last_cursor = win->cursor;
+ WM_cursor_set(win, gz->type->cursor_get(gz));
+ }
+ }
+ else {
+ if (C && gzmap->gzmap_context.last_cursor != -1) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, gzmap->gzmap_context.last_cursor);
+ }
+ }
+
+ /* tag the region for redraw */
+ if (C) {
+ ARegion *ar = CTX_wm_region(C);
+ ED_region_tag_redraw(ar);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+wmGizmo *wm_gizmomap_highlight_get(wmGizmoMap *gzmap)
+{
+ return gzmap->gzmap_context.highlight;
+}
+
+/**
+ * Caller should call exit when (enable == False).
+ */
+void wm_gizmomap_modal_set(
+ wmGizmoMap *gzmap, bContext *C, wmGizmo *gz, const wmEvent *event, bool enable)
+{
+ if (enable) {
+ BLI_assert(gzmap->gzmap_context.modal == NULL);
+ wmWindow *win = CTX_wm_window(C);
+
+ WM_tooltip_clear(C, win);
+
+ /* Use even if we don't have invoke, so we can setup data before an operator runs. */
+ if (gz->parent_gzgroup->type->invoke_prepare) {
+ gz->parent_gzgroup->type->invoke_prepare(C, gz->parent_gzgroup, gz);
+ }
+
+ if (gz->type->invoke &&
+ (gz->type->modal || gz->custom_modal))
+ {
+ const int retval = gz->type->invoke(C, gz, event);
+ if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
+ return;
+ }
+ }
+
+ gz->state |= WM_GIZMO_STATE_MODAL;
+ gzmap->gzmap_context.modal = gz;
+
+ if ((gz->flag & WM_GIZMO_MOVE_CURSOR) &&
+ (event->is_motion_absolute == false))
+ {
+ WM_cursor_grab_enable(win, true, true, NULL);
+ copy_v2_v2_int(gzmap->gzmap_context.event_xy, &event->x);
+ gzmap->gzmap_context.event_grabcursor = win->grabcursor;
+ }
+ else {
+ gzmap->gzmap_context.event_xy[0] = INT_MAX;
+ }
+
+ struct wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, gz->highlight_part);
+ if (gzop && gzop->type) {
+ const int retval = WM_operator_name_call_ptr(C, gzop->type, WM_OP_INVOKE_DEFAULT, &gzop->ptr);
+ if ((retval & OPERATOR_RUNNING_MODAL) == 0) {
+ wm_gizmomap_modal_set(gzmap, C, gz, event, false);
+ }
+
+ /* we failed to hook the gizmo to the operator handler or operator was cancelled, return */
+ if (!gzmap->gzmap_context.modal) {
+ gz->state &= ~WM_GIZMO_STATE_MODAL;
+ MEM_SAFE_FREE(gz->interaction_data);
+ }
+ return;
+ }
+ }
+ else {
+ BLI_assert(ELEM(gzmap->gzmap_context.modal, NULL, gz));
+
+ /* deactivate, gizmo but first take care of some stuff */
+ if (gz) {
+ gz->state &= ~WM_GIZMO_STATE_MODAL;
+ MEM_SAFE_FREE(gz->interaction_data);
+ }
+ gzmap->gzmap_context.modal = NULL;
+
+ if (C) {
+ wmWindow *win = CTX_wm_window(C);
+ if (gzmap->gzmap_context.event_xy[0] != INT_MAX) {
+ /* Check if some other part of Blender (typically operators)
+ * have adjusted the grab mode since it was set.
+ * If so: warp, so we have a predictable outcome. */
+ if (gzmap->gzmap_context.event_grabcursor == win->grabcursor) {
+ WM_cursor_grab_disable(win, gzmap->gzmap_context.event_xy);
+ }
+ else {
+ WM_cursor_warp(win, UNPACK2(gzmap->gzmap_context.event_xy));
+ }
+ }
+ ED_region_tag_redraw(CTX_wm_region(C));
+ WM_event_add_mousemove(C);
+ }
+
+ gzmap->gzmap_context.event_xy[0] = INT_MAX;
+ }
+}
+
+wmGizmo *wm_gizmomap_modal_get(wmGizmoMap *gzmap)
+{
+ return gzmap->gzmap_context.modal;
+}
+
+wmGizmo **wm_gizmomap_selected_get(wmGizmoMap *gzmap, int *r_selected_len)
+{
+ *r_selected_len = gzmap->gzmap_context.select.len;
+ return gzmap->gzmap_context.select.items;
+}
+
+ListBase *wm_gizmomap_groups_get(wmGizmoMap *gzmap)
+{
+ return &gzmap->groups;
+}
+
+void WM_gizmomap_message_subscribe(
+ bContext *C, wmGizmoMap *gzmap, ARegion *ar, struct wmMsgBus *mbus)
+{
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ if (!WM_gizmo_group_type_poll(C, gzgroup->type)) {
+ continue;
+ }
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ if (gz->flag & WM_GIZMO_HIDDEN) {
+ continue;
+ }
+ WM_gizmo_target_property_subscribe_all(gz, mbus, ar);
+ }
+ if (gzgroup->type->message_subscribe != NULL) {
+ gzgroup->type->message_subscribe(C, gzgroup, mbus);
+ }
+ }
+}
+
+/** \} */ /* wmGizmoMap */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Tooltip Handling
+ *
+ * \{ */
+
+struct ARegion *WM_gizmomap_tooltip_init(
+ struct bContext *C, struct ARegion *ar, int *UNUSED(r_pass), double *UNUSED(pass_delay), bool *r_exit_on_event)
+{
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ *r_exit_on_event = true;
+ if (gzmap) {
+ wmGizmo *gz = gzmap->gzmap_context.highlight;
+ if (gz) {
+ return UI_tooltip_create_from_gizmo(C, gz);
+ }
+ }
+ return NULL;
+}
+
+/** \} */ /* wmGizmoMapType */
+
+/* -------------------------------------------------------------------- */
+/** \name wmGizmoMapType
+ *
+ * \{ */
+
+wmGizmoMapType *WM_gizmomaptype_find(
+ const struct wmGizmoMapType_Params *gzmap_params)
+{
+ for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; gzmap_type = gzmap_type->next) {
+ if (gzmap_type->spaceid == gzmap_params->spaceid &&
+ gzmap_type->regionid == gzmap_params->regionid)
+ {
+ return gzmap_type;
+ }
+ }
+
+ return NULL;
+}
+
+wmGizmoMapType *WM_gizmomaptype_ensure(
+ const struct wmGizmoMapType_Params *gzmap_params)
+{
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_find(gzmap_params);
+
+ if (gzmap_type) {
+ return gzmap_type;
+ }
+
+ gzmap_type = MEM_callocN(sizeof(wmGizmoMapType), "gizmotype list");
+ gzmap_type->spaceid = gzmap_params->spaceid;
+ gzmap_type->regionid = gzmap_params->regionid;
+ BLI_addhead(&gizmomaptypes, gzmap_type);
+
+ return gzmap_type;
+}
+
+void wm_gizmomaptypes_free(void)
+{
+ for (wmGizmoMapType *gzmap_type = gizmomaptypes.first, *gzmap_type_next;
+ gzmap_type;
+ gzmap_type = gzmap_type_next)
+ {
+ gzmap_type_next = gzmap_type->next;
+ for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first, *gzgt_next;
+ gzgt_ref;
+ gzgt_ref = gzgt_next)
+ {
+ gzgt_next = gzgt_ref->next;
+ WM_gizmomaptype_group_free(gzgt_ref);
+ }
+ MEM_freeN(gzmap_type);
+ }
+}
+
+/**
+ * Initialize keymaps for all existing gizmo-groups
+ */
+void wm_gizmos_keymap(wmKeyConfig *keyconf)
+{
+ /* we add this item-less keymap once and use it to group gizmo-group keymaps into it */
+ WM_keymap_ensure(keyconf, "Gizmos", 0, 0);
+
+ for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; gzmap_type = gzmap_type->next) {
+ for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; gzgt_ref = gzgt_ref->next) {
+ wm_gizmogrouptype_setup_keymap(gzgt_ref->type, keyconf);
+ }
+ }
+}
+
+/** \} */ /* wmGizmoMapType */
+
+/* -------------------------------------------------------------------- */
+/** \name Updates for Dynamic Type Registraion
+ *
+ * \{ */
+
+
+void WM_gizmoconfig_update_tag_init(
+ wmGizmoMapType *gzmap_type, wmGizmoGroupType *gzgt)
+{
+ /* tag for update on next use */
+ gzmap_type->type_update_flag |= (WM_GIZMOMAPTYPE_UPDATE_INIT | WM_GIZMOMAPTYPE_KEYMAP_INIT);
+ gzgt->type_update_flag |= (WM_GIZMOMAPTYPE_UPDATE_INIT | WM_GIZMOMAPTYPE_KEYMAP_INIT);
+
+ wm_gzmap_type_update_flag |= WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT;
+}
+
+void WM_gizmoconfig_update_tag_remove(
+ wmGizmoMapType *gzmap_type, wmGizmoGroupType *gzgt)
+{
+ /* tag for update on next use */
+ gzmap_type->type_update_flag |= WM_GIZMOMAPTYPE_UPDATE_REMOVE;
+ gzgt->type_update_flag |= WM_GIZMOMAPTYPE_UPDATE_REMOVE;
+
+ wm_gzmap_type_update_flag |= WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE;
+}
+
+/**
+ * Run incase new types have been added (runs often, early exit where possible).
+ * Follows #WM_keyconfig_update concentions.
+ */
+void WM_gizmoconfig_update(struct Main *bmain)
+{
+ if (G.background)
+ return;
+
+ if (wm_gzmap_type_update_flag == 0)
+ return;
+
+ if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) {
+ for (wmGizmoMapType *gzmap_type = gizmomaptypes.first;
+ gzmap_type;
+ gzmap_type = gzmap_type->next)
+ {
+ if (gzmap_type->type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) {
+ gzmap_type->type_update_flag &= ~WM_GIZMOMAPTYPE_UPDATE_REMOVE;
+ for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first, *gzgt_ref_next;
+ gzgt_ref;
+ gzgt_ref = gzgt_ref_next)
+ {
+ gzgt_ref_next = gzgt_ref->next;
+ if (gzgt_ref->type->type_update_flag & WM_GIZMOMAPTYPE_UPDATE_REMOVE) {
+ gzgt_ref->type->type_update_flag &= ~WM_GIZMOMAPTYPE_UPDATE_REMOVE;
+ WM_gizmomaptype_group_unlink(NULL, bmain, gzmap_type, gzgt_ref->type);
+ }
+ }
+ }
+ }
+
+ wm_gzmap_type_update_flag &= ~WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE;
+ }
+
+ if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT) {
+ for (wmGizmoMapType *gzmap_type = gizmomaptypes.first;
+ gzmap_type;
+ gzmap_type = gzmap_type->next)
+ {
+ const uchar type_update_all = WM_GIZMOMAPTYPE_UPDATE_INIT | WM_GIZMOMAPTYPE_KEYMAP_INIT;
+ if (gzmap_type->type_update_flag & type_update_all) {
+ gzmap_type->type_update_flag &= ~type_update_all;
+ for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first;
+ gzgt_ref;
+ gzgt_ref = gzgt_ref->next)
+ {
+ if (gzgt_ref->type->type_update_flag & WM_GIZMOMAPTYPE_KEYMAP_INIT) {
+ WM_gizmomaptype_group_init_runtime_keymap(bmain, gzgt_ref->type);
+ gzgt_ref->type->type_update_flag &= ~WM_GIZMOMAPTYPE_KEYMAP_INIT;
+ }
+
+ if (gzgt_ref->type->type_update_flag & WM_GIZMOMAPTYPE_UPDATE_INIT) {
+ WM_gizmomaptype_group_init_runtime(bmain, gzmap_type, gzgt_ref->type);
+ gzgt_ref->type->type_update_flag &= ~WM_GIZMOMAPTYPE_UPDATE_INIT;
+ }
+ }
+ }
+ }
+
+ wm_gzmap_type_update_flag &= ~WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT;
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
new file mode 100644
index 00000000000..12f9b529c15
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -0,0 +1,364 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+ * \ingroup wm
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_context.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+
+#include "wm.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+/* own includes */
+#include "wm_gizmo_wmapi.h"
+#include "wm_gizmo_intern.h"
+
+/* -------------------------------------------------------------------- */
+
+/** \name Property Definition
+ * \{ */
+
+BLI_INLINE wmGizmoProperty *wm_gizmo_target_property_array(wmGizmo *gz)
+{
+ return (wmGizmoProperty *)(POINTER_OFFSET(gz, gz->type->struct_size));
+}
+
+wmGizmoProperty *WM_gizmo_target_property_array(wmGizmo *gz)
+{
+ return wm_gizmo_target_property_array(gz);
+}
+
+wmGizmoProperty *WM_gizmo_target_property_at_index(wmGizmo *gz, int index)
+{
+ BLI_assert(index < gz->type->target_property_defs_len);
+ BLI_assert(index != -1);
+ wmGizmoProperty *gz_prop_array = wm_gizmo_target_property_array(gz);
+ return &gz_prop_array[index];
+}
+
+wmGizmoProperty *WM_gizmo_target_property_find(wmGizmo *gz, const char *idname)
+{
+ int index = BLI_findstringindex(
+ &gz->type->target_property_defs, idname, offsetof(wmGizmoPropertyType, idname));
+ if (index != -1) {
+ return WM_gizmo_target_property_at_index(gz, index);
+ }
+ else {
+ return NULL;
+ }
+}
+
+void WM_gizmo_target_property_def_rna_ptr(
+ wmGizmo *gz, const wmGizmoPropertyType *gz_prop_type,
+ PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_at_index(gz, gz_prop_type->index_in_type);
+
+ /* if gizmo evokes an operator we cannot use it for property manipulation */
+ BLI_assert(gz->op_data == NULL);
+
+ gz_prop->type = gz_prop_type;
+
+ gz_prop->ptr = *ptr;
+ gz_prop->prop = prop;
+ gz_prop->index = index;
+
+ if (gz->type->property_update) {
+ gz->type->property_update(gz, gz_prop);
+ }
+}
+
+void WM_gizmo_target_property_def_rna(
+ wmGizmo *gz, const char *idname,
+ PointerRNA *ptr, const char *propname, int index)
+{
+ const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ WM_gizmo_target_property_def_rna_ptr(gz, gz_prop_type, ptr, prop, index);
+}
+
+void WM_gizmo_target_property_def_func_ptr(
+ wmGizmo *gz, const wmGizmoPropertyType *gz_prop_type,
+ const wmGizmoPropertyFnParams *params)
+{
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_at_index(gz, gz_prop_type->index_in_type);
+
+ /* if gizmo evokes an operator we cannot use it for property manipulation */
+ BLI_assert(gz->op_data == NULL);
+
+ gz_prop->type = gz_prop_type;
+
+ gz_prop->custom_func.value_get_fn = params->value_get_fn;
+ gz_prop->custom_func.value_set_fn = params->value_set_fn;
+ gz_prop->custom_func.range_get_fn = params->range_get_fn;
+ gz_prop->custom_func.free_fn = params->free_fn;
+ gz_prop->custom_func.user_data = params->user_data;
+
+ if (gz->type->property_update) {
+ gz->type->property_update(gz, gz_prop);
+ }
+}
+
+void WM_gizmo_target_property_def_func(
+ wmGizmo *gz, const char *idname,
+ const wmGizmoPropertyFnParams *params)
+{
+ const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
+ WM_gizmo_target_property_def_func_ptr(gz, gz_prop_type, params);
+}
+
+void WM_gizmo_target_property_clear_rna_ptr(
+ wmGizmo *gz, const wmGizmoPropertyType *gz_prop_type)
+{
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_at_index(gz, gz_prop_type->index_in_type);
+
+ /* if gizmo evokes an operator we cannot use it for property manipulation */
+ BLI_assert(gz->op_data == NULL);
+
+ gz_prop->type = NULL;
+
+ gz_prop->ptr = PointerRNA_NULL;
+ gz_prop->prop = NULL;
+ gz_prop->index = -1;
+}
+
+void WM_gizmo_target_property_clear_rna(
+ wmGizmo *gz, const char *idname)
+{
+ const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
+ WM_gizmo_target_property_clear_rna_ptr(gz, gz_prop_type);
+}
+
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Property Access
+ * \{ */
+
+bool WM_gizmo_target_property_is_valid_any(wmGizmo *gz)
+{
+ wmGizmoProperty *gz_prop_array = wm_gizmo_target_property_array(gz);
+ for (int i = 0; i < gz->type->target_property_defs_len; i++) {
+ wmGizmoProperty *gz_prop = &gz_prop_array[i];
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool WM_gizmo_target_property_is_valid(const wmGizmoProperty *gz_prop)
+{
+ return ((gz_prop->prop != NULL) ||
+ (gz_prop->custom_func.value_get_fn && gz_prop->custom_func.value_set_fn));
+}
+
+float WM_gizmo_target_property_float_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop)
+{
+ if (gz_prop->custom_func.value_get_fn) {
+ float value = 0.0f;
+ BLI_assert(gz_prop->type->array_length == 1);
+ gz_prop->custom_func.value_get_fn(gz, gz_prop, &value);
+ return value;
+ }
+
+ if (gz_prop->index == -1) {
+ return RNA_property_float_get(&gz_prop->ptr, gz_prop->prop);
+ }
+ else {
+ return RNA_property_float_get_index(&gz_prop->ptr, gz_prop->prop, gz_prop->index);
+ }
+}
+
+void WM_gizmo_target_property_float_set(
+ bContext *C, const wmGizmo *gz,
+ wmGizmoProperty *gz_prop, const float value)
+{
+ if (gz_prop->custom_func.value_set_fn) {
+ BLI_assert(gz_prop->type->array_length == 1);
+ gz_prop->custom_func.value_set_fn(gz, gz_prop, &value);
+ return;
+ }
+
+ /* reset property */
+ if (gz_prop->index == -1) {
+ RNA_property_float_set(&gz_prop->ptr, gz_prop->prop, value);
+ }
+ else {
+ RNA_property_float_set_index(&gz_prop->ptr, gz_prop->prop, gz_prop->index, value);
+ }
+ RNA_property_update(C, &gz_prop->ptr, gz_prop->prop);
+}
+
+void WM_gizmo_target_property_float_get_array(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ float *value)
+{
+ if (gz_prop->custom_func.value_get_fn) {
+ gz_prop->custom_func.value_get_fn(gz, gz_prop, value);
+ return;
+ }
+ RNA_property_float_get_array(&gz_prop->ptr, gz_prop->prop, value);
+}
+
+void WM_gizmo_target_property_float_set_array(
+ bContext *C, const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ const float *value)
+{
+ if (gz_prop->custom_func.value_set_fn) {
+ gz_prop->custom_func.value_set_fn(gz, gz_prop, value);
+ return;
+ }
+ RNA_property_float_set_array(&gz_prop->ptr, gz_prop->prop, value);
+
+ RNA_property_update(C, &gz_prop->ptr, gz_prop->prop);
+}
+
+bool WM_gizmo_target_property_float_range_get(
+ const wmGizmo *gz, wmGizmoProperty *gz_prop,
+ float range[2])
+{
+ if (gz_prop->custom_func.value_get_fn) {
+ if (gz_prop->custom_func.range_get_fn) {
+ gz_prop->custom_func.range_get_fn(gz, gz_prop, range);
+ return true;
+ }
+ else {
+ return false;
+
+ }
+ }
+
+ float step, precision;
+ RNA_property_float_ui_range(&gz_prop->ptr, gz_prop->prop, &range[0], &range[1], &step, &precision);
+ return true;
+}
+
+int WM_gizmo_target_property_array_length(
+ const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop)
+{
+ if (gz_prop->custom_func.value_get_fn) {
+ return gz_prop->type->array_length;
+ }
+ return RNA_property_array_length(&gz_prop->ptr, gz_prop->prop);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Property Define
+ * \{ */
+
+const wmGizmoPropertyType *WM_gizmotype_target_property_find(
+ const wmGizmoType *gzt, const char *idname)
+{
+ return BLI_findstring(&gzt->target_property_defs, idname, offsetof(wmGizmoPropertyType, idname));
+}
+
+void WM_gizmotype_target_property_def(
+ wmGizmoType *gzt, const char *idname, int data_type, int array_length)
+{
+ wmGizmoPropertyType *mpt;
+
+ BLI_assert(WM_gizmotype_target_property_find(gzt, idname) == NULL);
+
+ const uint idname_size = strlen(idname) + 1;
+ mpt = MEM_callocN(sizeof(wmGizmoPropertyType) + idname_size, __func__);
+ memcpy(mpt->idname, idname, idname_size);
+ mpt->data_type = data_type;
+ mpt->array_length = array_length;
+ mpt->index_in_type = gzt->target_property_defs_len;
+ gzt->target_property_defs_len += 1;
+ BLI_addtail(&gzt->target_property_defs, mpt);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Property Utilities
+ * \{ */
+
+void WM_gizmo_do_msg_notify_tag_refresh(
+ bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ ARegion *ar = msg_val->owner;
+ wmGizmoMap *gzmap = msg_val->user_data;
+
+ ED_region_tag_redraw(ar);
+ WM_gizmomap_tag_refresh(gzmap);
+}
+
+/**
+ * Runs on the "prepare draw" pass,
+ * drawing the region clears.
+ */
+void WM_gizmo_target_property_subscribe_all(
+ wmGizmo *gz, struct wmMsgBus *mbus, ARegion *ar)
+{
+ if (gz->type->target_property_defs_len) {
+ wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);
+ for (int i = 0; i < gz->type->target_property_defs_len; i++) {
+ wmGizmoProperty *gz_prop = &gz_prop_array[i];
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ if (gz_prop->prop) {
+ WM_msg_subscribe_rna(
+ mbus, &gz_prop->ptr, gz_prop->prop,
+ &(const wmMsgSubscribeValue){
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ }, __func__);
+ WM_msg_subscribe_rna(
+ mbus, &gz_prop->ptr, gz_prop->prop,
+ &(const wmMsgSubscribeValue){
+ .owner = ar,
+ .user_data = gz->parent_gzgroup->parent_gzmap,
+ .notify = WM_gizmo_do_msg_notify_tag_refresh,
+ }, __func__);
+ }
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
new file mode 100644
index 00000000000..2ff0148044c
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
@@ -0,0 +1,212 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/intern/wm_gizmo_type.c
+ * \ingroup wm
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+
+/* only for own init/exit calls (wm_gizmotype_init/wm_gizmotype_free) */
+#include "wm.h"
+
+/* own includes */
+#include "wm_gizmo_wmapi.h"
+#include "wm_gizmo_intern.h"
+
+
+/** \name Gizmo Type Append
+ *
+ * \note This follows conventions from #WM_operatortype_find #WM_operatortype_append & friends.
+ * \{ */
+
+static GHash *global_gizmotype_hash = NULL;
+
+const wmGizmoType *WM_gizmotype_find(const char *idname, bool quiet)
+{
+ if (idname[0]) {
+ wmGizmoType *gzt;
+
+ gzt = BLI_ghash_lookup(global_gizmotype_hash, idname);
+ if (gzt) {
+ return gzt;
+ }
+
+ if (!quiet) {
+ printf("search for unknown gizmo '%s'\n", idname);
+ }
+ }
+ else {
+ if (!quiet) {
+ printf("search for empty gizmo\n");
+ }
+ }
+
+ return NULL;
+}
+
+/* caller must free */
+void WM_gizmotype_iter(GHashIterator *ghi)
+{
+ BLI_ghashIterator_init(ghi, global_gizmotype_hash);
+}
+
+static wmGizmoType *wm_gizmotype_append__begin(void)
+{
+ wmGizmoType *gzt = MEM_callocN(sizeof(wmGizmoType), "gizmotype");
+ gzt->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_GizmoProperties);
+#if 0
+ /* Set the default i18n context now, so that opfunc can redefine it if needed! */
+ RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
+#endif
+ return gzt;
+}
+static void wm_gizmotype_append__end(wmGizmoType *gzt)
+{
+ BLI_assert(gzt->struct_size >= sizeof(wmGizmo));
+
+ RNA_def_struct_identifier(&BLENDER_RNA, gzt->srna, gzt->idname);
+
+ BLI_ghash_insert(global_gizmotype_hash, (void *)gzt->idname, gzt);
+}
+
+void WM_gizmotype_append(void (*gtfunc)(struct wmGizmoType *))
+{
+ wmGizmoType *gzt = wm_gizmotype_append__begin();
+ gtfunc(gzt);
+ wm_gizmotype_append__end(gzt);
+}
+
+void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void *userdata)
+{
+ wmGizmoType *mt = wm_gizmotype_append__begin();
+ gtfunc(mt, userdata);
+ wm_gizmotype_append__end(mt);
+}
+
+/**
+ * Free but don't remove from ghash.
+ */
+static void gizmotype_free(wmGizmoType *gzt)
+{
+ if (gzt->ext.srna) { /* python gizmo, allocs own string */
+ MEM_freeN((void *)gzt->idname);
+ }
+
+ BLI_freelistN(&gzt->target_property_defs);
+ MEM_freeN(gzt);
+}
+
+/**
+ * \param C: May be NULL.
+ */
+static void gizmotype_unlink(
+ bContext *C, Main *bmain, wmGizmoType *gzt)
+{
+ /* Free instances. */
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ for (ARegion *ar = lb->first; ar; ar = ar->next) {
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ if (gzmap) {
+ wmGizmoGroup *gzgroup;
+ for (gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ for (wmGizmo *gz = gzgroup->gizmos.first, *gz_next; gz; gz = gz_next) {
+ gz_next = gz->next;
+ BLI_assert(gzgroup->parent_gzmap == gzmap);
+ if (gz->type == gzt) {
+ WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, gz, C);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void WM_gizmotype_remove_ptr(bContext *C, Main *bmain, wmGizmoType *gzt)
+{
+ BLI_assert(gzt == WM_gizmotype_find(gzt->idname, false));
+
+ BLI_ghash_remove(global_gizmotype_hash, gzt->idname, NULL, NULL);
+
+ gizmotype_unlink(C, bmain, gzt);
+
+ gizmotype_free(gzt);
+}
+
+bool WM_gizmotype_remove(bContext *C, Main *bmain, const char *idname)
+{
+ wmGizmoType *gzt = BLI_ghash_lookup(global_gizmotype_hash, idname);
+
+ if (gzt == NULL) {
+ return false;
+ }
+
+ WM_gizmotype_remove_ptr(C, bmain, gzt);
+
+ return true;
+}
+
+static void wm_gizmotype_ghash_free_cb(wmGizmoType *mt)
+{
+ gizmotype_free(mt);
+}
+
+void wm_gizmotype_free(void)
+{
+ BLI_ghash_free(global_gizmotype_hash, NULL, (GHashValFreeFP)wm_gizmotype_ghash_free_cb);
+ global_gizmotype_hash = NULL;
+}
+
+/* called on initialize WM_init() */
+void wm_gizmotype_init(void)
+{
+ /* reserve size is set based on blender default setup */
+ global_gizmotype_hash = BLI_ghash_str_new_ex("wm_gizmotype_init gh", 128);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/gizmo/wm_gizmo_fn.h b/source/blender/windowmanager/gizmo/wm_gizmo_fn.h
new file mode 100644
index 00000000000..3361932c6e3
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/wm_gizmo_fn.h
@@ -0,0 +1,90 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/wm_gizmo_fn.h
+ * \ingroup wm
+ *
+ * Callback function definitions, needed for both Types & API headers.
+ */
+
+#ifndef __WM_GIZMO_FN_H__
+#define __WM_GIZMO_FN_H__
+
+#include "BLI_compiler_attrs.h"
+
+/* wmGizmoGroup */
+typedef bool (*wmGizmoGroupFnPoll)(
+ const struct bContext *, struct wmGizmoGroupType *)
+ ATTR_WARN_UNUSED_RESULT;
+typedef void (*wmGizmoGroupFnInit)(
+ const struct bContext *, struct wmGizmoGroup *);
+typedef void (*wmGizmoGroupFnRefresh)(
+ const struct bContext *, struct wmGizmoGroup *);
+typedef void (*wmGizmoGroupFnDrawPrepare)(
+ const struct bContext *, struct wmGizmoGroup *);
+typedef void (*wmGizmoGroupFnInvokePrepare)(
+ const struct bContext *, struct wmGizmoGroup *, struct wmGizmo *);
+typedef struct wmKeyMap *(*wmGizmoGroupFnSetupKeymap)(
+ const struct wmGizmoGroupType *, struct wmKeyConfig *)
+ ATTR_WARN_UNUSED_RESULT;
+typedef void (*wmGizmoGroupFnMsgBusSubscribe)(
+ const struct bContext *, struct wmGizmoGroup *, struct wmMsgBus *);
+
+/* wmGizmo */
+/* See: wmGizmoType for docs on each type. */
+
+typedef void (*wmGizmoFnSetup)(struct wmGizmo *);
+typedef void (*wmGizmoFnDraw)(const struct bContext *, struct wmGizmo *);
+typedef void (*wmGizmoFnDrawSelect)(const struct bContext *, struct wmGizmo *, int);
+typedef int (*wmGizmoFnTestSelect)(struct bContext *, struct wmGizmo *, const int mval[2]);
+typedef int (*wmGizmoFnModal)(struct bContext *, struct wmGizmo *, const struct wmEvent *, eWM_GizmoFlagTweak);
+typedef void (*wmGizmoFnPropertyUpdate)(struct wmGizmo *, struct wmGizmoProperty *);
+typedef void (*wmGizmoFnMatrixBasisGet)(const struct wmGizmo *, float[4][4]);
+typedef int (*wmGizmoFnInvoke)(struct bContext *, struct wmGizmo *, const struct wmEvent *);
+typedef void (*wmGizmoFnExit)(struct bContext *, struct wmGizmo *, const bool);
+typedef int (*wmGizmoFnCursorGet)(struct wmGizmo *);
+typedef void (*wmGizmoFnSelectRefresh)(struct wmGizmo *);
+typedef void (*wmGizmoFnFree)(struct wmGizmo *);
+
+/* wmGizmoProperty ('value' type defined by 'wmGizmoProperty.data_type') */
+typedef void (*wmGizmoPropertyFnGet)(
+ const struct wmGizmo *, struct wmGizmoProperty *,
+ /* typically 'float *' */
+ void *value);
+typedef void (*wmGizmoPropertyFnSet)(
+ const struct wmGizmo *, struct wmGizmoProperty *,
+ /* typically 'const float *' */
+ const void *value);
+typedef void (*wmGizmoPropertyFnRangeGet)(
+ const struct wmGizmo *, struct wmGizmoProperty *,
+ /* typically 'float[2]' */
+ void *range);
+typedef void (*wmGizmoPropertyFnFree)(
+ const struct wmGizmo *, struct wmGizmoProperty *);
+
+typedef struct wmGizmoPropertyFnParams {
+ wmGizmoPropertyFnGet value_get_fn;
+ wmGizmoPropertyFnSet value_set_fn;
+ wmGizmoPropertyFnRangeGet range_get_fn;
+ wmGizmoPropertyFnFree free_fn;
+ void *user_data;
+} wmGizmoPropertyFnParams;
+
+#endif /* __WM_GIZMO_FN_H__ */
diff --git a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
new file mode 100644
index 00000000000..414109e89e5
--- /dev/null
+++ b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h
@@ -0,0 +1,97 @@
+/*
+ * ***** 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): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/gizmo/wm_gizmo_wmapi.h
+ * \ingroup wm
+ *
+ * \name Gizmos Window Manager API
+ * API for usage in window manager code only. It should contain all functionality
+ * needed to hook up the gizmo system with Blender's window manager. It's
+ * mostly the event system that needs to communicate with gizmo code.
+ *
+ * Only included in wm.h and lower level files.
+ */
+
+
+#ifndef __WM_GIZMO_WMAPI_H__
+#define __WM_GIZMO_WMAPI_H__
+
+struct wmEventHandler;
+struct wmGizmoMap;
+struct wmOperatorType;
+struct wmOperator;
+
+
+/* -------------------------------------------------------------------- */
+/* wmGizmo */
+
+/* wm_gizmo_type.c, for init/exit */
+void wm_gizmotype_free(void);
+void wm_gizmotype_init(void);
+
+/* wm_gizmogroup_type.c, for init/exit */
+void wm_gizmogrouptype_free(void);
+void wm_gizmogrouptype_init(void);
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoGroup */
+
+void GIZMOGROUP_OT_gizmo_select(struct wmOperatorType *ot);
+void GIZMOGROUP_OT_gizmo_tweak(struct wmOperatorType *ot);
+
+bool wm_gizmogroup_is_any_selected(const struct wmGizmoGroup *gzgroup);
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoMap */
+
+void wm_gizmomap_remove(struct wmGizmoMap *gzmap);
+
+void wm_gizmos_keymap(struct wmKeyConfig *keyconf);
+
+void wm_gizmomaps_handled_modal_update(
+ bContext *C, struct wmEvent *event, struct wmEventHandler *handler);
+void wm_gizmomap_handler_context(bContext *C, struct wmEventHandler *handler);
+
+struct wmGizmo *wm_gizmomap_highlight_find(
+ struct wmGizmoMap *gzmap, bContext *C, const struct wmEvent *event,
+ int *r_part);
+bool wm_gizmomap_highlight_set(
+ struct wmGizmoMap *gzmap, const bContext *C,
+ struct wmGizmo *gz, int part);
+struct wmGizmo *wm_gizmomap_highlight_get(struct wmGizmoMap *gzmap);
+void wm_gizmomap_modal_set(
+ struct wmGizmoMap *gzmap, bContext *C, struct wmGizmo *gz,
+ const struct wmEvent *event, bool enable);
+
+struct wmGizmo *wm_gizmomap_modal_get(struct wmGizmoMap *gzmap);
+struct wmGizmo **wm_gizmomap_selected_get(wmGizmoMap *gzmap, int *r_selected_len);
+struct ListBase *wm_gizmomap_groups_get(wmGizmoMap *gzmap);
+
+/* -------------------------------------------------------------------- */
+/* wmGizmoMapType */
+
+void wm_gizmomaptypes_free(void);
+
+#endif /* __WM_GIZMO_WMAPI_H__ */
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 132789aade4..866c846810b 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -46,15 +46,17 @@
#include "BLI_ghash.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_screen.h"
#include "BKE_report.h"
-#include "BKE_global.h"
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm_window.h"
#include "wm_event_system.h"
#include "wm_draw.h"
@@ -221,37 +223,51 @@ void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
}
}
-/* ************ uiListType handling ************** */
/* ****************************************** */
-void WM_keymap_init(bContext *C)
+void WM_keyconfig_reload(bContext *C)
+{
+ if (CTX_py_init_get(C) && !G.background) {
+ BPY_execute_string(
+ C, (const char *[]){"bpy", NULL},
+ "bpy.utils.keyconfig_init()");
+ }
+}
+
+void WM_keyconfig_init(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
/* create standard key configs */
- if (!wm->defaultconf)
- wm->defaultconf = WM_keyconfig_new(wm, "Blender");
- if (!wm->addonconf)
- wm->addonconf = WM_keyconfig_new(wm, "Blender Addon");
- if (!wm->userconf)
- wm->userconf = WM_keyconfig_new(wm, "Blender User");
+ if (wm->defaultconf == NULL) {
+ /* Keep lowercase to match the preset filename. */
+ wm->defaultconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT, false);
+ }
+ if (wm->addonconf == NULL) {
+ wm->addonconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT " addon", false);
+ }
+ if (wm->userconf == NULL) {
+ wm->userconf = WM_keyconfig_new(wm, WM_KEYCONFIG_STR_DEFAULT " user", false);
+ }
/* initialize only after python init is done, for keymaps that
* use python operators */
- if (CTX_py_init_get(C) && (wm->initialized & WM_INIT_KEYMAP) == 0) {
+ if (CTX_py_init_get(C) && (wm->initialized & WM_KEYCONFIG_IS_INITIALIZED) == 0) {
/* create default key config, only initialize once,
* it's persistent across sessions */
if (!(wm->defaultconf->flag & KEYCONF_INIT_DEFAULT)) {
wm_window_keymap(wm->defaultconf);
ED_spacetypes_keymap(wm->defaultconf);
+ WM_keyconfig_reload(C);
+
wm->defaultconf->flag |= KEYCONF_INIT_DEFAULT;
}
WM_keyconfig_update_tag(NULL, NULL);
WM_keyconfig_update(wm);
- wm->initialized |= WM_INIT_KEYMAP;
+ wm->initialized |= WM_KEYCONFIG_IS_INITIALIZED;
}
}
@@ -272,8 +288,8 @@ void WM_check(bContext *C)
if (!G.background) {
/* case: fileread */
- if ((wm->initialized & WM_INIT_WINDOW) == 0) {
- WM_keymap_init(C);
+ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
+ WM_keyconfig_init(C);
WM_autosave_init(wm);
}
@@ -281,11 +297,15 @@ void WM_check(bContext *C)
wm_window_ghostwindows_ensure(wm);
}
+ if (wm->message_bus == NULL) {
+ wm->message_bus = WM_msgbus_create();
+ }
+
/* case: fileread */
/* note: this runs in bg mode to set the screen context cb */
- if ((wm->initialized & WM_INIT_WINDOW) == 0) {
+ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
ED_screens_initialize(bmain, wm);
- wm->initialized |= WM_INIT_WINDOW;
+ wm->initialized |= WM_WINDOW_IS_INITIALIZED;
}
}
@@ -314,17 +334,21 @@ void wm_clear_default_size(bContext *C)
}
/* on startup, it adds all data, for matching */
-void wm_add_default(bContext *C)
+void wm_add_default(Main *bmain, bContext *C)
{
- wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan", 0);
+ wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0);
wmWindow *win;
bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
+ WorkSpace *workspace;
+ WorkSpaceLayout *layout = BKE_workspace_layout_find_global(bmain, screen, &workspace);
CTX_wm_manager_set(C, wm);
- win = wm_window_new(C);
- win->screen = screen;
+ win = wm_window_new(C, NULL);
+ win->scene = CTX_data_scene(C);
+ STRNCPY(win->view_layer_name, CTX_data_view_layer(C)->name);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
screen->winid = win->winid;
- BLI_strncpy(win->screenname, screen->id.name + 2, sizeof(win->screenname));
wm->winactive = win;
wm->file_saved = 1;
@@ -343,8 +367,8 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
wm_autosave_timer_ended(wm);
while ((win = BLI_pophead(&wm->windows))) {
- win->screen = NULL; /* prevent draw clear to use screen */
- wm_draw_window_clear(win);
+ /* prevent draw clear to use screen */
+ BKE_workspace_active_set(win->workspace_hook, NULL);
wm_window_free(C, wm, win);
}
@@ -358,6 +382,10 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
BLI_freelistN(&wm->queue);
+ if (wm->message_bus != NULL) {
+ WM_msgbus_destroy(wm->message_bus);
+ }
+
BLI_freelistN(&wm->paintcursors);
WM_drag_free_list(&wm->drags);
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index e789099c799..1a1da1ed5dd 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -42,6 +42,7 @@
#include "DNA_listBase.h"
#include "DNA_userdef_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -156,6 +157,23 @@ void WM_cursor_set(wmWindow *win, int curs)
}
}
+bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const ARegion *ar)
+{
+ if (ar && (ar->regiontype != RGN_TYPE_WINDOW)) {
+ return false;
+ }
+
+ bToolRef_Runtime *tref_rt = (sa && sa->runtime.tool) ? sa->runtime.tool->runtime : NULL;
+ if (tref_rt && tref_rt->cursor != CURSOR_STD) {
+ if (win->modalcursor == 0) {
+ WM_cursor_set(win, tref_rt->cursor);
+ win->cursor = tref_rt->cursor;
+ return true;
+ }
+ }
+ return false;
+}
+
void WM_cursor_modal_set(wmWindow *win, int val)
{
if (win->lastcursor == 0)
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 8bb4bf4f304..77e2cd772db 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -45,6 +45,9 @@
#include "BIF_glutil.h"
#include "BKE_context.h"
+#include "BKE_idcode.h"
+
+#include "GPU_shader.h"
#include "IMB_imbuf_types.h"
@@ -96,7 +99,8 @@ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
wmDropBox *WM_dropbox_add(
- ListBase *lb, const char *idname, bool (*poll)(bContext *, wmDrag *, const wmEvent *),
+ ListBase *lb, const char *idname,
+ bool (*poll)(bContext *, wmDrag *, const wmEvent *, const char **),
void (*copy)(wmDrag *, wmDropBox *))
{
wmDropBox *drop = MEM_callocN(sizeof(wmDropBox), "wmDropBox");
@@ -152,10 +156,17 @@ wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin,
drag->flags = flags;
drag->icon = icon;
drag->type = type;
- if (type == WM_DRAG_PATH)
+ if (type == WM_DRAG_PATH) {
BLI_strncpy(drag->path, poin, FILE_MAX);
- else
+ }
+ else if (type == WM_DRAG_ID) {
+ if (poin) {
+ WM_drag_add_ID(drag, poin, NULL);
+ }
+ }
+ else {
drag->poin = poin;
+ }
drag->value = value;
return drag;
@@ -175,6 +186,7 @@ void WM_drag_free(wmDrag *drag)
MEM_freeN(drag->poin);
}
+ BLI_freelistN(&drag->ids);
MEM_freeN(drag);
}
@@ -186,6 +198,7 @@ void WM_drag_free_list(struct ListBase *lb)
}
}
+
static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, const wmEvent *event)
{
wmEventHandler *handler = handlers->first;
@@ -193,10 +206,12 @@ static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag,
if (handler->dropboxes) {
wmDropBox *drop = handler->dropboxes->first;
for (; drop; drop = drop->next) {
- if (drop->poll(C, drag, event))
+ const char *tooltip = NULL;
+ if (drop->poll(C, drag, event, &tooltip)) {
/* XXX Doing translation here might not be ideal, but later we have no more
* access to ot (and hence op context)... */
- return RNA_struct_ui_name(drop->ot->srna);
+ return (tooltip) ? tooltip : RNA_struct_ui_name(drop->ot->srna);
+ }
}
}
}
@@ -264,15 +279,66 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event)
}
}
+/* ************** IDs ***************** */
+
+void WM_drag_add_ID(wmDrag *drag, ID *id, ID *from_parent)
+{
+ /* Don't drag the same ID twice. */
+ for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
+ if (drag_id->id == id) {
+ if (drag_id->from_parent == NULL) {
+ drag_id->from_parent = from_parent;
+ }
+ return;
+ }
+ else if (GS(drag_id->id->name) != GS(id->name)) {
+ BLI_assert(!"All dragged IDs must have the same type");
+ return;
+ }
+ }
+
+ /* Add to list. */
+ wmDragID *drag_id = MEM_callocN(sizeof(wmDragID), __func__);
+ drag_id->id = id;
+ drag_id->from_parent = from_parent;
+ BLI_addtail(&drag->ids, drag_id);
+}
+
+ID *WM_drag_ID(const wmDrag *drag, short idcode)
+{
+ if (drag->type != WM_DRAG_ID) {
+ return NULL;
+ }
+
+ wmDragID *drag_id = drag->ids.first;
+ if (!drag_id) {
+ return NULL;
+ }
+
+ ID *id = drag_id->id;
+ return (idcode == 0 || GS(id->name) == idcode) ? id : NULL;
+
+}
+
+ID *WM_drag_ID_from_event(const wmEvent *event, short idcode)
+{
+ if (event->custom != EVT_DATA_DRAGDROP) {
+ return NULL;
+ }
+
+ ListBase *lb = event->customdata;
+ return WM_drag_ID(lb->first, idcode);
+}
+
/* ************** draw ***************** */
static void wm_drop_operator_draw(const char *name, int x, int y)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- const unsigned char fg[4] = {255, 255, 255, 255};
- const unsigned char bg[4] = {0, 0, 0, 50};
+ const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
- UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg);
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg);
}
static const char *wm_drag_name(wmDrag *drag)
@@ -280,8 +346,16 @@ static const char *wm_drag_name(wmDrag *drag)
switch (drag->type) {
case WM_DRAG_ID:
{
- ID *id = drag->poin;
- return id->name + 2;
+ ID *id = WM_drag_ID(drag, 0);
+ bool single = (BLI_listbase_count_at_most(&drag->ids, 2) == 1);
+
+ if (single) {
+ return id->name + 2;
+ }
+ else if (id) {
+ return BKE_idcode_to_name_plural(GS(id->name));
+ }
+ break;
}
case WM_DRAG_PATH:
case WM_DRAG_NAME:
@@ -322,6 +396,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
/* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */
glEnable(GL_BLEND);
for (drag = wm->drags.first; drag; drag = drag->next) {
+ const char text_col[] = {255, 255, 255, 255};
int iconsize = UI_DPI_ICON_SIZE;
int padding = 4 * UI_DPI_FAC;
@@ -333,8 +408,10 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
if (rect)
drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy);
else {
- glColor4f(1.0, 1.0, 1.0, 0.65); /* this blends texture */
- glaDrawPixelsTexScaled(x, y, drag->imb->x, drag->imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, drag->imb->rect, drag->scale, drag->scale);
+ float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTexScaled(&state, x, y, drag->imb->x, drag->imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST,
+ drag->imb->rect, drag->scale, drag->scale, 1.0f, 1.0f, col);
}
}
else {
@@ -344,7 +421,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
if (rect)
drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize);
else
- UI_icon_draw_aspect(x, y, drag->icon, 1.0f / UI_DPI_FAC, 0.8);
+ UI_icon_draw_aspect(x, y, drag->icon, 1.0f / UI_DPI_FAC, 0.8, text_col);
}
/* item name */
@@ -362,8 +439,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
drag_rect_minmax(rect, x, y, x + w, y + iconsize);
}
else {
- glColor4ub(255, 255, 255, 255);
- UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag));
+ UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag), (uchar *)text_col);
}
/* operator name with roundbox */
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index d18337ee80c..00364489af7 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -34,6 +34,8 @@
#include <string.h>
#include "DNA_listBase.h"
+#include "DNA_object_types.h"
+#include "DNA_camera_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_userdef_types.h"
@@ -49,6 +51,9 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "GHOST_C-api.h"
@@ -58,13 +63,17 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
-#include "GPU_glew.h"
-#include "GPU_basic_shader.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_texture.h"
+#include "GPU_viewport.h"
#include "RE_engine.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_toolsystem.h"
#include "wm.h"
#include "wm_draw.h"
#include "wm_window.h"
@@ -74,87 +83,139 @@
# include "BKE_subsurf.h"
#endif
-/* swap */
-#define WIN_NONE_OK 0
-#define WIN_BACK_OK 1
-#define WIN_FRONT_OK 2
-#define WIN_BOTH_OK 3
-/* ******************* drawing, overlays *************** */
+/* ******************* paint cursor *************** */
-
-static void wm_paintcursor_draw(bContext *C, ARegion *ar)
+static void wm_paintcursor_draw(bContext *C, ScrArea *sa, ARegion *ar)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *screen = WM_window_get_active_screen(win);
+ wmPaintCursor *pc;
- if (wm->paintcursors.first) {
- wmWindow *win = CTX_wm_window(C);
- bScreen *screen = win->screen;
- wmPaintCursor *pc;
-
- if (ar->swinid && screen->subwinactive == ar->swinid) {
- for (pc = wm->paintcursors.first; pc; pc = pc->next) {
- if (pc->poll == NULL || pc->poll(C)) {
- ARegion *ar_other = CTX_wm_region(C);
- if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
- int x = 0, y = 0;
- wm_get_cursor_position(win, &x, &y);
- pc->draw(C,
- x - ar_other->winrct.xmin,
- y - ar_other->winrct.ymin,
- pc->customdata);
- }
- else {
- pc->draw(C,
- win->eventstate->x - ar_other->winrct.xmin,
- win->eventstate->y - ar_other->winrct.ymin,
- pc->customdata);
- }
+ if (ar->visible && ar == screen->active_region) {
+ for (pc = wm->paintcursors.first; pc; pc = pc->next) {
+
+ if ((pc->space_type != SPACE_TYPE_ANY) && (sa->spacetype != pc->space_type)) {
+ continue;
+ }
+
+ if ((pc->region_type != RGN_TYPE_ANY) && (ar->regiontype != pc->region_type)) {
+ continue;
+ }
+
+ if (pc->poll == NULL || pc->poll(C)) {
+ /* Prevent drawing outside region. */
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(ar->winrct.xmin,
+ ar->winrct.ymin,
+ BLI_rcti_size_x(&ar->winrct) + 1,
+ BLI_rcti_size_y(&ar->winrct) + 1);
+
+ if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
+ int x = 0, y = 0;
+ wm_get_cursor_position(win, &x, &y);
+ pc->draw(C, x, y, pc->customdata);
+ }
+ else {
+ pc->draw(C, win->eventstate->x, win->eventstate->y, pc->customdata);
}
+
+ glDisable(GL_SCISSOR_TEST);
}
}
}
}
-/* ********************* drawing, swap ****************** */
-static void wm_area_mark_invalid_backbuf(ScrArea *sa)
+static bool wm_draw_region_stereo_set(Main *bmain, ScrArea *sa, ARegion *ar, eStereoViews sview)
{
- if (sa->spacetype == SPACE_VIEW3D)
- ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
+ /* We could detect better when stereo is actually needed, by inspecting the
+ * image in the image editor and sequencer. */
+ if (ar->regiontype != RGN_TYPE_WINDOW) {
+ return false;
+ }
+
+ switch (sa->spacetype) {
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = sa->spacedata.first;
+ sima->iuser.multiview_eye = sview;
+ return true;
+ }
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = sa->spacedata.first;
+ if (v3d->camera && v3d->camera->type == OB_CAMERA) {
+ Camera *cam = v3d->camera->data;
+ CameraBGImage *bgpic = cam->bg_images.first;
+ v3d->multiview_eye = sview;
+ if (bgpic) bgpic->iuser.multiview_eye = sview;
+ return true;
+ }
+ return false;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode = sa->spacedata.first;
+ if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
+ Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ima->eye = sview;
+ return true;
+ }
+ return false;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = sa->spacedata.first;
+ sseq->multiview_eye = sview;
+ return true;
+ }
+ }
+
+ return false;
}
-static bool wm_area_test_invalid_backbuf(ScrArea *sa)
+/* ********************* drawing ****************** */
+
+static void wm_area_mark_invalid_backbuf(ScrArea *sa)
{
if (sa->spacetype == SPACE_VIEW3D)
- return (((View3D *)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF) != 0;
- else
- return true;
+ ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
}
-static void wm_region_test_render_do_draw(const bScreen *screen, ScrArea *sa, ARegion *ar)
+static void wm_region_test_render_do_draw(const Scene *scene, struct Depsgraph *depsgraph,
+ ScrArea *sa, ARegion *ar)
{
/* tag region for redraw from render engine preview running inside of it */
- if (sa->spacetype == SPACE_VIEW3D) {
+ if (sa->spacetype == SPACE_VIEW3D && ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = ar->regiondata;
- RenderEngine *engine = (rv3d) ? rv3d->render_engine : NULL;
+ RenderEngine *engine = rv3d->render_engine;
+ GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
- Scene *scene = screen->scene;
View3D *v3d = sa->spacedata.first;
rcti border_rect;
/* do partial redraw when possible */
- if (ED_view3d_calc_render_border(scene, v3d, ar, &border_rect))
+ if (ED_view3d_calc_render_border(scene, depsgraph, v3d, ar, &border_rect))
ED_region_tag_redraw_partial(ar, &border_rect);
else
ED_region_tag_redraw(ar);
engine->flag &= ~RE_ENGINE_DO_DRAW;
}
+ else if (viewport && GPU_viewport_do_update(viewport)) {
+ ED_region_tag_redraw(ar);
+ }
}
}
+static bool wm_region_use_viewport(ScrArea *sa, ARegion *ar)
+{
+ return (sa->spacetype == SPACE_VIEW3D && ar->regiontype == RGN_TYPE_WINDOW);
+}
+
/********************** draw all **************************/
/* - reference method, draw all each time */
@@ -198,614 +259,403 @@ static void wm_draw_callbacks(wmWindow *win)
}
}
-static void wm_method_draw_full(bContext *C, wmWindow *win)
-{
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
- /* draw area regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
+/************************* Region drawing. ********************************
+ *
+ * Each region draws into its own framebuffer, which is then blit on the
+ * window draw buffer. This helps with fast redrawing if only some regions
+ * change. It also means we can share a single context for multiple windows,
+ * so that for example VAOs can be shared between windows. */
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- wm_paintcursor_draw(C, ar);
- CTX_wm_region_set(C, NULL);
+static void wm_draw_region_buffer_free(ARegion *ar)
+{
+ if (ar->draw_buffer) {
+ for (int view = 0; view < 2; view++) {
+ if (ar->draw_buffer->offscreen[view]) {
+ GPU_offscreen_free(ar->draw_buffer->offscreen[view]);
+ }
+ if (ar->draw_buffer->viewport[view]) {
+ GPU_viewport_free(ar->draw_buffer->viewport[view]);
}
}
- wm_area_mark_invalid_backbuf(sa);
- CTX_wm_area_set(C, NULL);
+ MEM_freeN(ar->draw_buffer);
+ ar->draw_buffer = NULL;
}
-
- ED_screen_draw_edges(win);
- screen->do_draw = false;
- wm_draw_callbacks(win);
-
- /* draw overlapping regions */
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
- CTX_wm_menu_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- CTX_wm_menu_set(C, NULL);
- }
- }
-
- if (screen->do_draw_gesture)
- wm_gesture_draw(win);
}
-/****************** draw overlap all **********************/
-/* - redraw marked areas, and anything that overlaps it */
-/* - it also handles swap exchange optionally, assuming */
-/* that on swap no clearing happens and we get back the */
-/* same buffer as we swapped to the front */
-
-/* mark area-regions to redraw if overlapped with rect */
-static void wm_flush_regions_down(bScreen *screen, rcti *dirty)
+static void wm_draw_offscreen_texture_parameters(GPUOffScreen *offscreen)
{
- ScrArea *sa;
- ARegion *ar;
+ /* Setup offscreen color texture for drawing. */
+ GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (BLI_rcti_isect(dirty, &ar->winrct, NULL)) {
- ar->do_draw = RGN_DRAW;
- memset(&ar->drawrct, 0, sizeof(ar->drawrct));
- ar->swap = WIN_NONE_OK;
- }
- }
- }
-}
+ /* We don't support multisample textures here. */
+ BLI_assert(GPU_texture_target(texture) == GL_TEXTURE_2D);
-/* mark menu-regions to redraw if overlapped with rect */
-static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
-{
- ARegion *ar;
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (BLI_rcti_isect(dirty, &ar->winrct, NULL)) {
- ar->do_draw = RGN_DRAW;
- memset(&ar->drawrct, 0, sizeof(ar->drawrct));
- ar->swap = WIN_NONE_OK;
- }
- }
+ /* No mipmaps or filtering. */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ /* GL_TEXTURE_BASE_LEVEL = 0 by default */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
}
-static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
+static void wm_draw_region_buffer_create(ARegion *ar, bool stereo, bool use_viewport)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
- static rcti rect = {0, 0, 0, 0};
-
- /* after backbuffer selection draw, we need to redraw */
- for (sa = screen->areabase.first; sa; sa = sa->next)
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->swinid && !wm_area_test_invalid_backbuf(sa))
- ED_region_tag_redraw(ar);
-
- /* flush overlapping regions */
- if (screen->regionbase.first) {
- /* flush redraws of area regions up to overlapping regions */
- for (sa = screen->areabase.first; sa; sa = sa->next)
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->swinid && ar->do_draw)
- wm_flush_regions_up(screen, &ar->winrct);
-
- /* flush between overlapping regions */
- for (ar = screen->regionbase.last; ar; ar = ar->prev)
- if (ar->swinid && ar->do_draw)
- wm_flush_regions_up(screen, &ar->winrct);
-
- /* flush redraws of overlapping regions down to area regions */
- for (ar = screen->regionbase.last; ar; ar = ar->prev)
- if (ar->swinid && ar->do_draw)
- wm_flush_regions_down(screen, &ar->winrct);
+ if (ar->draw_buffer) {
+ if (ar->draw_buffer->stereo != stereo) {
+ /* Free draw buffer on stereo changes. */
+ wm_draw_region_buffer_free(ar);
+ }
+ else {
+ /* Free offscreen buffer on size changes. Viewport auto resizes. */
+ GPUOffScreen *offscreen = ar->draw_buffer->offscreen[0];
+ if (offscreen && (GPU_offscreen_width(offscreen) != ar->winx ||
+ GPU_offscreen_height(offscreen) != ar->winy))
+ {
+ wm_draw_region_buffer_free(ar);
+ }
+ }
}
- /* flush drag item */
- if (rect.xmin != rect.xmax) {
- wm_flush_regions_down(screen, &rect);
- rect.xmin = rect.xmax = 0;
- }
- if (wm->drags.first) {
- /* doesnt draw, fills rect with boundbox */
- wm_drags_draw(C, win, &rect);
- }
+ if (!ar->draw_buffer) {
+ if (use_viewport) {
+ /* Allocate viewport which includes an offscreen buffer with depth
+ * multisample, etc. */
+ ar->draw_buffer = MEM_callocN(sizeof(wmDrawBuffer), "wmDrawBuffer");
+ ar->draw_buffer->viewport[0] = GPU_viewport_create();
+ ar->draw_buffer->viewport[1] = (stereo) ? GPU_viewport_create() : NULL;
+ }
+ else {
+ /* Allocate offscreen buffer if it does not exist. This one has no
+ * depth or multisample buffers. 3D view creates own buffers with
+ * the data it needs. */
+ GPUOffScreen *offscreen = GPU_offscreen_create(ar->winx, ar->winy, 0, false, false, NULL);
+ if (!offscreen) {
+ return;
+ }
- /* draw marked area regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
+ wm_draw_offscreen_texture_parameters(offscreen);
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
- if (ar->do_draw) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- wm_paintcursor_draw(C, ar);
- CTX_wm_region_set(C, NULL);
+ GPUOffScreen *offscreen_right = NULL;
+ if (stereo) {
+ offscreen_right = GPU_offscreen_create(ar->winx, ar->winy, 0, false, false, NULL);
- if (exchange)
- ar->swap = WIN_FRONT_OK;
+ if (!offscreen_right) {
+ GPU_offscreen_free(offscreen);
+ return;
}
- else if (exchange) {
- if (ar->swap == WIN_FRONT_OK) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- wm_paintcursor_draw(C, ar);
- CTX_wm_region_set(C, NULL);
- ar->swap = WIN_BOTH_OK;
- }
- else if (ar->swap == WIN_BACK_OK)
- ar->swap = WIN_FRONT_OK;
- else if (ar->swap == WIN_BOTH_OK)
- ar->swap = WIN_BOTH_OK;
- }
+ wm_draw_offscreen_texture_parameters(offscreen_right);
}
+
+ ar->draw_buffer = MEM_callocN(sizeof(wmDrawBuffer), "wmDrawBuffer");
+ ar->draw_buffer->offscreen[0] = offscreen;
+ ar->draw_buffer->offscreen[1] = offscreen_right;
}
- wm_area_mark_invalid_backbuf(sa);
- CTX_wm_area_set(C, NULL);
+ ar->draw_buffer->bound_view = -1;
+ ar->draw_buffer->stereo = stereo;
}
+}
- /* after area regions so we can do area 'overlay' drawing */
- if (screen->do_draw) {
- ED_screen_draw_edges(win);
- screen->do_draw = false;
- wm_draw_callbacks(win);
-
- if (exchange)
- screen->swap = WIN_FRONT_OK;
- }
- else if (exchange) {
- if (screen->swap == WIN_FRONT_OK) {
- ED_screen_draw_edges(win);
- screen->do_draw = false;
- screen->swap = WIN_BOTH_OK;
- wm_draw_callbacks(win);
- }
- else if (screen->swap == WIN_BACK_OK)
- screen->swap = WIN_FRONT_OK;
- else if (screen->swap == WIN_BOTH_OK)
- screen->swap = WIN_BOTH_OK;
+static void wm_draw_region_bind(ARegion *ar, int view)
+{
+ if (!ar->draw_buffer) {
+ return;
}
- /* draw marked overlapping regions */
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->do_draw) {
- CTX_wm_menu_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- CTX_wm_menu_set(C, NULL);
- }
+ if (ar->draw_buffer->viewport[view]) {
+ GPU_viewport_bind(ar->draw_buffer->viewport[view], &ar->winrct);
}
+ else {
+ GPU_offscreen_bind(ar->draw_buffer->offscreen[view], false);
- if (screen->do_draw_gesture)
- wm_gesture_draw(win);
-
- /* needs pixel coords in screen */
- if (wm->drags.first) {
- wm_drags_draw(C, win, NULL);
+ /* For now scissor is expected by region drawing, we could disable it
+ * and do the enable/disable in the specific cases that setup scissor. */
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, 0, ar->winx, ar->winy);
}
-}
-/****************** draw triple buffer ********************/
-/* - area regions are written into a texture, without any */
-/* of the overlapping menus, brushes, gestures. these */
-/* are redrawn each time. */
+ ar->draw_buffer->bound_view = view;
+}
-static void wm_draw_triple_free(wmDrawTriple *triple)
+static void wm_draw_region_unbind(ARegion *ar, int view)
{
- if (triple) {
- glDeleteTextures(1, &triple->bind);
- MEM_freeN(triple);
+ if (!ar->draw_buffer) {
+ return;
}
-}
-static void wm_draw_triple_fail(bContext *C, wmWindow *win)
-{
- wm_draw_window_clear(win);
+ ar->draw_buffer->bound_view = -1;
- win->drawfail = 1;
- wm_method_draw_overlap_all(C, win, 0);
+ if (ar->draw_buffer->viewport[view]) {
+ GPU_viewport_unbind(ar->draw_buffer->viewport[view]);
+ }
+ else {
+ glDisable(GL_SCISSOR_TEST);
+ GPU_offscreen_unbind(ar->draw_buffer->offscreen[view], false);
+ }
}
-static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
+static void wm_draw_region_blit(ARegion *ar, int view)
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
- GLint maxsize;
+ if (!ar->draw_buffer) {
+ return;
+ }
- /* compute texture sizes */
- if (GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) {
- triple->target = GL_TEXTURE_RECTANGLE_ARB;
+ if (ar->draw_buffer->viewport[view]) {
+ GPU_viewport_draw_to_screen(ar->draw_buffer->viewport[view], &ar->winrct);
}
else {
- triple->target = GL_TEXTURE_2D;
+ GPU_offscreen_draw_to_screen(ar->draw_buffer->offscreen[view], ar->winrct.xmin, ar->winrct.ymin);
}
+}
- triple->x = winsize_x;
- triple->y = winsize_y;
-
- /* generate texture names */
- glGenTextures(1, &triple->bind);
-
- if (!triple->bind) {
- /* not the typical failure case but we handle it anyway */
- printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n");
- return 0;
+GPUTexture *wm_draw_region_texture(ARegion *ar, int view)
+{
+ if (!ar->draw_buffer) {
+ return NULL;
}
- /* proxy texture is only guaranteed to test for the cases that
- * there is only one texture in use, which may not be the case */
- maxsize = GPU_max_texture_size();
-
- if (triple->x > maxsize || triple->y > maxsize) {
- glBindTexture(triple->target, 0);
- printf("WM: failed to allocate texture for triple buffer drawing "
- "(texture too large for graphics card).\n");
- return 0;
+ if (ar->draw_buffer->viewport[view]) {
+ return GPU_viewport_color_texture(ar->draw_buffer->viewport[view]);
}
-
- /* setup actual texture */
- glBindTexture(triple->target, triple->bind);
- glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
- glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glBindTexture(triple->target, 0);
-
- /* not sure if this works everywhere .. */
- if (glGetError() == GL_OUT_OF_MEMORY) {
- printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n");
- return 0;
+ else {
+ return GPU_offscreen_color_texture(ar->draw_buffer->offscreen[view]);
}
-
- return 1;
}
-void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha, bool is_interlace)
+void wm_draw_region_blend(ARegion *ar, int view, bool blend)
{
- const int sizex = WM_window_pixels_x(win);
- const int sizey = WM_window_pixels_y(win);
-
- float halfx, halfy, ratiox, ratioy;
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x;
- ratioy /= triple->y;
- halfx /= triple->x;
- halfy /= triple->y;
+ if (!ar->draw_buffer) {
+ return;
}
- /* interlace stereo buffer bind the shader before calling wm_triple_draw_textures */
- if (is_interlace) {
- glEnable(triple->target);
+ /* Alpha is always 1, except when blend timer is running. */
+ float alpha = ED_region_blend_alpha(ar);
+ if (alpha <= 0.0f) {
+ return;
}
- else {
- GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+
+ if (!blend) {
+ alpha = 1.0f;
}
- glBindTexture(triple->target, triple->bind);
+ /* setup actual texture */
+ GPUTexture *texture = wm_draw_region_texture(ar, view);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
+
+ /* wmOrtho for the screen has this same offset */
+ const float halfx = GLA_PIXEL_OFS / (BLI_rcti_size_x(&ar->winrct) + 1);
+ const float halfy = GLA_PIXEL_OFS / (BLI_rcti_size_y(&ar->winrct) + 1);
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(0, 0);
+ if (blend) {
+ /* GL_ONE because regions drawn offscreen have premultiplied alpha. */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(sizex, 0);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
+ GPU_shader_bind(shader);
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(sizex, sizey);
+ rcti rect_geo = ar->winrct;
+ rect_geo.xmax += 1;
+ rect_geo.ymax += 1;
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(0, sizey);
- glEnd();
+ rctf rect_tex;
+ rect_tex.xmin = halfx;
+ rect_tex.ymin = halfy;
+ rect_tex.xmax = 1.0f + halfx;
+ rect_tex.ymax = 1.0f + halfy;
- glBindTexture(triple->target, 0);
+ float alpha_easing = 1.0f - alpha;
+ alpha_easing = 1.0f - alpha_easing * alpha_easing;
- if (is_interlace) {
- glDisable(triple->target);
+ /* Slide vertical panels */
+ float ofs_x = BLI_rcti_size_x(&ar->winrct) * (1.0f - alpha_easing);
+ if (ar->alignment == RGN_ALIGN_RIGHT) {
+ rect_geo.xmin += ofs_x;
+ rect_tex.xmax *= alpha_easing;
+ alpha = 1.0f;
}
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ else if (ar->alignment == RGN_ALIGN_LEFT) {
+ rect_geo.xmax -= ofs_x;
+ rect_tex.xmin += 1.0f - alpha_easing;
+ alpha = 1.0f;
}
-}
-static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
-{
- const int sizex = WM_window_pixels_x(win);
- const int sizey = WM_window_pixels_y(win);
+ glUniform1i(GPU_shader_get_uniform(shader, "image"), 0);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), rect_tex.xmin, rect_tex.ymin, rect_tex.xmax, rect_tex.ymax);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), rect_geo.xmin, rect_geo.ymin, rect_geo.xmax, rect_geo.ymax);
+ glUniform4f(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), alpha, alpha, alpha, alpha);
- glBindTexture(triple->target, triple->bind);
- glCopyTexSubImage2D(triple->target, 0, 0, 0, 0, 0, sizex, sizey);
+ GPU_draw_primitive(GPU_PRIM_TRI_STRIP, 4);
- glBindTexture(triple->target, 0);
-}
-
-static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *triple)
-{
- float fac = ED_region_blend_factor(ar);
+ glBindTexture(GL_TEXTURE_2D, 0);
- /* region blend always is 1, except when blend timer is running */
- if (fac < 1.0f) {
- wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
-
- glEnable(GL_BLEND);
- wm_triple_draw_textures(win, triple, 1.0f - fac, false);
+ if (blend) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
}
}
-static void wm_method_draw_triple(bContext *C, wmWindow *win)
+GPUViewport *WM_draw_region_get_viewport(ARegion *ar, int view)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first;
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
- int copytex = false;
-
- if (drawdata && drawdata->triple) {
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- wmSubWindowSet(win, screen->mainwin);
-
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
+ if (!ar->draw_buffer) {
+ return NULL;
}
- else {
- /* we run it when we start OR when we turn stereo on */
- if (drawdata == NULL) {
- drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
- BLI_addhead(&win->drawdata, drawdata);
- }
- drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
+ return ar->draw_buffer->viewport[view];
+}
- if (!wm_triple_gen_textures(win, drawdata->triple)) {
- wm_draw_triple_fail(C, win);
- return;
- }
+GPUViewport *WM_draw_region_get_bound_viewport(ARegion *ar)
+{
+ if (!ar->draw_buffer || ar->draw_buffer->bound_view == -1) {
+ return NULL;
}
- /* it means stereo was just turned off */
- /* note: we are removing all drawdatas that are not the first */
- for (dd = drawdata->next; dd; dd = dd_next) {
- dd_next = dd->next;
-
- BLI_remlink(&win->drawdata, dd);
- wm_draw_triple_free(dd->triple);
- MEM_freeN(dd);
- }
+ int view = ar->draw_buffer->bound_view;
+ return ar->draw_buffer->viewport[view];
+}
- wmDrawTriple *triple = drawdata->triple;
+static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ bScreen *screen = WM_window_get_active_screen(win);
- /* draw marked area regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ /* Draw screen areas into own frame buffer. */
+ ED_screen_areas_iter(win, screen, sa) {
CTX_wm_area_set(C, sa);
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->do_draw) {
- if (ar->overlap == false) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- CTX_wm_region_set(C, NULL);
- copytex = true;
- }
+ /* Compute UI layouts for dynamically size regions. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar->do_draw && ar->type && ar->type->layout) {
+ CTX_wm_region_set(C, ar);
+ ED_region_do_layout(C, ar);
+ CTX_wm_region_set(C, NULL);
}
}
- wm_area_mark_invalid_backbuf(sa);
- CTX_wm_area_set(C, NULL);
- }
+ ED_area_update_region_sizes(wm, win, sa);
- if (copytex) {
- wmSubWindowSet(win, screen->mainwin);
-
- wm_triple_copy_textures(win, triple);
- }
-
- if (wm->paintcursors.first) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->swinid == screen->subwinactive) {
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- /* make region ready for draw, scissor, pixelspace */
- ED_region_set(C, ar);
- wm_paintcursor_draw(C, ar);
-
- CTX_wm_region_set(C, NULL);
- CTX_wm_area_set(C, NULL);
- }
+ if (sa->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) {
+ if ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
+ WM_toolsystem_update_from_context(C, CTX_wm_workspace(C), CTX_data_view_layer(C), sa);
}
+ sa->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE;
}
- wmSubWindowSet(win, screen->mainwin);
- }
-
- /* draw overlapping area regions (always like popups) */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
-
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->overlap) {
+ /* Then do actual drawing of regions. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar->do_draw) {
CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
+ bool use_viewport = wm_region_use_viewport(sa, ar);
+
+ if (stereo && wm_draw_region_stereo_set(bmain, sa, ar, STEREO_LEFT_ID)) {
+ wm_draw_region_buffer_create(ar, true, use_viewport);
+
+ for (int view = 0; view < 2; view++) {
+ eStereoViews sview;
+ if (view == 0) {
+ sview = STEREO_LEFT_ID;
+ }
+ else {
+ sview = STEREO_RIGHT_ID;
+ wm_draw_region_stereo_set(bmain, sa, ar, sview);
+ }
+
+ wm_draw_region_bind(ar, view);
+ ED_region_do_draw(C, ar);
+ wm_draw_region_unbind(ar, view);
+ }
+ }
+ else {
+ wm_draw_region_buffer_create(ar, false, use_viewport);
+ wm_draw_region_bind(ar, 0);
+ ED_region_do_draw(C, ar);
+ wm_draw_region_unbind(ar, 0);
+ }
+
ar->do_draw = false;
CTX_wm_region_set(C, NULL);
-
- wm_draw_region_blend(win, ar, triple);
}
}
+ wm_area_mark_invalid_backbuf(sa);
CTX_wm_area_set(C, NULL);
}
- /* after area regions so we can do area 'overlay' drawing */
- ED_screen_draw_edges(win);
- win->screen->do_draw = false;
- wm_draw_callbacks(win);
-
- /* draw floating regions (menus) */
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
+ /* Draw menus into their own framebuffer. */
+ for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible) {
CTX_wm_menu_set(C, ar);
+
+ if (ar->type && ar->type->layout) {
+ /* UI code reads the OpenGL state, but we have to refresh
+ * the UI layout beforehand in case the menu size changes. */
+ wmViewport(&ar->winrct);
+ ar->type->layout(C, ar);
+ }
+
+ wm_draw_region_buffer_create(ar, false, false);
+ wm_draw_region_bind(ar, 0);
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
ED_region_do_draw(C, ar);
+ wm_draw_region_unbind(ar, 0);
+
ar->do_draw = false;
CTX_wm_menu_set(C, NULL);
}
}
-
- /* always draw, not only when screen tagged */
- if (win->gesture.first)
- wm_gesture_draw(win);
-
- /* needs pixel coords in screen */
- if (wm->drags.first) {
- wm_drags_draw(C, win, NULL);
- }
}
-static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoViews sview)
+static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
{
- Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
- wmDrawData *drawdata;
- wmDrawTriple *triple_data, *triple_all;
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
- int copytex = false;
- int id;
-
- /* we store the triple_data in sequence to triple_all */
- for (id = 0; id < 2; id++) {
- drawdata = BLI_findlink(&win->drawdata, (sview * 2) + id);
-
- if (drawdata && drawdata->triple) {
- if (id == 0) {
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- wmSubWindowSet(win, screen->mainwin);
-
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
- }
- }
- else {
- /* we run it when we start OR when we turn stereo on */
- if (drawdata == NULL) {
- drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
- BLI_addtail(&win->drawdata, drawdata);
- }
-
- drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
-
- if (!wm_triple_gen_textures(win, drawdata->triple)) {
- wm_draw_triple_fail(C, win);
- return;
- }
- }
- }
-
- triple_data = ((wmDrawData *) BLI_findlink(&win->drawdata, sview * 2))->triple;
- triple_all = ((wmDrawData *) BLI_findlink(&win->drawdata, (sview * 2) + 1))->triple;
-
- /* draw marked area regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
-
- switch (sa->spacetype) {
- case SPACE_IMAGE:
- {
- SpaceImage *sima = sa->spacedata.first;
- sima->iuser.multiview_eye = sview;
- break;
- }
- case SPACE_VIEW3D:
- {
- View3D *v3d = sa->spacedata.first;
- BGpic *bgpic = v3d->bgpicbase.first;
- v3d->multiview_eye = sview;
- if (bgpic) bgpic->iuser.multiview_eye = sview;
- break;
- }
- case SPACE_NODE:
- {
- SpaceNode *snode = sa->spacedata.first;
- if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
- Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
- ima->eye = sview;
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ /* Draw into the window framebuffer, in full window coordinates. */
+ wmWindowViewport(win);
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* Blit non-overlapping area regions. */
+ ED_screen_areas_iter(win, screen, sa) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar->overlap == false) {
+ if (view == -1 && ar->draw_buffer && ar->draw_buffer->stereo) {
+ /* Stereo drawing from textures. */
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_ANAGLYPH) {
+ wm_stereo3d_draw_anaglyph(win, ar);
+ }
+ else {
+ wm_stereo3d_draw_interlace(win, ar);
+ }
}
- break;
- }
- case SPACE_SEQ:
- {
- SpaceSeq *sseq = sa->spacedata.first;
- sseq->multiview_eye = sview;
- break;
- }
- }
-
- /* draw marked area regions */
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->do_draw) {
-
- if (ar->overlap == false) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
-
- if (sview == STEREO_RIGHT_ID)
- ar->do_draw = false;
-
- CTX_wm_region_set(C, NULL);
- copytex = true;
+ else {
+ /* Blit from offscreen buffer. */
+ wm_draw_region_blit(ar, 0);
}
}
}
-
- wm_area_mark_invalid_backbuf(sa);
- CTX_wm_area_set(C, NULL);
- }
-
- if (copytex) {
- wmSubWindowSet(win, screen->mainwin);
-
- wm_triple_copy_textures(win, triple_data);
}
+ /* Draw paint cursors. */
if (wm->paintcursors.first) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->swinid == screen->subwinactive) {
+ ED_screen_areas_iter(win, screen, sa) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar == screen->active_region) {
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, ar);
/* make region ready for draw, scissor, pixelspace */
- ED_region_set(C, ar);
- wm_paintcursor_draw(C, ar);
+ wm_paintcursor_draw(C, sa, ar);
CTX_wm_region_set(C, NULL);
CTX_wm_area_set(C, NULL);
@@ -813,42 +663,26 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV
}
}
- wmSubWindowSet(win, screen->mainwin);
+ wmWindowViewport(win);
}
- /* draw overlapping area regions (always like popups) */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
-
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->overlap) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- if (sview == STEREO_RIGHT_ID)
- ar->do_draw = false;
- CTX_wm_region_set(C, NULL);
-
- wm_draw_region_blend(win, ar, triple_data);
+ /* Blend in overlapping area regions */
+ ED_screen_areas_iter(win, screen, sa) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar->overlap) {
+ wm_draw_region_blend(ar, 0, true);
}
}
-
- CTX_wm_area_set(C, NULL);
}
- /* after area regions so we can do area 'overlay' drawing */
+ /* After area regions so we can do area 'overlay' drawing. */
ED_screen_draw_edges(win);
- if (sview == STEREO_RIGHT_ID)
- win->screen->do_draw = false;
wm_draw_callbacks(win);
- /* draw floating regions (menus) */
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
- CTX_wm_menu_set(C, ar);
- ED_region_do_draw(C, ar);
- if (sview == STEREO_RIGHT_ID)
- ar->do_draw = false;
- CTX_wm_menu_set(C, NULL);
+ /* Blend in floating regions (menus). */
+ for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible) {
+ wm_draw_region_blend(ar, 0, true);
}
}
@@ -860,10 +694,76 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV
if (wm->drags.first) {
wm_drags_draw(C, win, NULL);
}
+}
+
+static void wm_draw_window(bContext *C, wmWindow *win)
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+ bool stereo = WM_stereo3d_enabled(win, false);
+
+ /* Draw area regions into their own framebuffer. This way we can redraw
+ * the areas that need it, and blit the rest from existing framebuffers. */
+ wm_draw_window_offscreen(C, win, stereo);
+
+ /* Now we draw into the window framebuffer, in full window coordinates. */
+ if (!stereo) {
+ /* Regular mono drawing. */
+ wm_draw_window_onscreen(C, win, -1);
+ }
+ else if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
+ /* For pageflip we simply draw to both back buffers. */
+ glDrawBuffer(GL_BACK_LEFT);
+ wm_draw_window_onscreen(C, win, 0);
+ glDrawBuffer(GL_BACK_RIGHT);
+ wm_draw_window_onscreen(C, win, 1);
+ glDrawBuffer(GL_BACK);
+ }
+ else if (ELEM(win->stereo3d_format->display_mode, S3D_DISPLAY_ANAGLYPH, S3D_DISPLAY_INTERLACE)) {
+ /* For anaglyph and interlace, we draw individual regions with
+ * stereo framebuffers using different shaders. */
+ wm_draw_window_onscreen(C, win, -1);
+ }
+ else {
+ /* For side-by-side and top-bottom, we need to render each view to an
+ * an offscreen texture and then draw it. This used to happen for all
+ * stereo methods, but it's less efficient than drawing directly. */
+ const int width = WM_window_pixels_x(win);
+ const int height = WM_window_pixels_y(win);
+ GPUOffScreen *offscreen = GPU_offscreen_create(width, height, 0, false, false, NULL);
+
+ if (offscreen) {
+ GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
+ wm_draw_offscreen_texture_parameters(offscreen);
+
+ for (int view = 0; view < 2; view++) {
+ /* Draw view into offscreen buffer. */
+ GPU_offscreen_bind(offscreen, false);
+ wm_draw_window_onscreen(C, win, view);
+ GPU_offscreen_unbind(offscreen, false);
+
+ /* Draw offscreen buffer to screen. */
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
+
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) {
+ wm_stereo3d_draw_sidebyside(win, view);
+ }
+ else {
+ wm_stereo3d_draw_topbottom(win, view);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ GPU_offscreen_free(offscreen);
+ }
+ else {
+ /* Still draw something in case of allocation failure. */
+ wm_draw_window_onscreen(C, win, 0);
+ }
+ }
- /* copy the ui + overlays */
- wmSubWindowSet(win, screen->mainwin);
- wm_triple_copy_textures(win, triple_all);
+ screen->do_draw = false;
}
/****************** main update call **********************/
@@ -871,25 +771,27 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV
/* quick test to prevent changing window drawable */
static bool wm_draw_update_test_window(wmWindow *win)
{
- const bScreen *screen = win->screen;
- ScrArea *sa;
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ bScreen *screen = WM_window_get_active_screen(win);
ARegion *ar;
bool do_draw = false;
for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->do_draw_overlay) {
- wm_tag_redraw_overlay(win, ar);
+ screen->do_draw_paintcursor = true;
ar->do_draw_overlay = false;
}
- if (ar->swinid && ar->do_draw)
+ if (ar->visible && ar->do_draw)
do_draw = true;
}
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, sa) {
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- wm_region_test_render_do_draw(screen, sa, ar);
+ wm_region_test_render_do_draw(scene, depsgraph, sa, ar);
- if (ar->swinid && ar->do_draw)
+ if (ar->visible && ar->do_draw)
do_draw = true;
}
}
@@ -911,41 +813,14 @@ static bool wm_draw_update_test_window(wmWindow *win)
return false;
}
-static int wm_automatic_draw_method(wmWindow *win)
+void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *UNUSED(ar))
{
- /* We assume all supported GPUs now support triple buffer well. */
- if (win->drawmethod == USER_DRAW_AUTOMATIC) {
- return USER_DRAW_TRIPLE;
- }
- else {
- return win->drawmethod;
- }
-}
-
-bool WM_is_draw_triple(wmWindow *win)
-{
- /* function can get called before this variable is set in drawing code below */
- if (win->drawmethod != U.wmdrawmethod)
- win->drawmethod = U.wmdrawmethod;
- return (USER_DRAW_TRIPLE == wm_automatic_draw_method(win));
-}
-
-void wm_tag_redraw_overlay(wmWindow *win, ARegion *ar)
-{
- /* for draw triple gestures, paint cursors don't need region redraw */
- if (ar && win) {
- if (wm_automatic_draw_method(win) != USER_DRAW_TRIPLE)
- ED_region_tag_redraw(ar);
- win->screen->do_draw_paintcursor = true;
+ if (win) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ screen->do_draw_paintcursor = true;
}
}
-void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *ar)
-{
- win->screen->do_draw_paintcursor = true;
- wm_tag_redraw_overlay(win, ar);
-}
-
void wm_draw_update(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -970,13 +845,9 @@ void wm_draw_update(bContext *C)
continue;
}
#endif
- if (win->drawmethod != U.wmdrawmethod) {
- wm_draw_window_clear(win);
- win->drawmethod = U.wmdrawmethod;
- }
if (wm_draw_update_test_window(win)) {
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
CTX_wm_window_set(C, win);
@@ -984,29 +855,9 @@ void wm_draw_update(bContext *C)
wm_window_make_drawable(wm, win);
/* notifiers for screen redraw */
- if (screen->do_refresh)
- ED_screen_refresh(wm, win);
-
- int drawmethod = wm_automatic_draw_method(win);
-
- if (win->drawfail)
- wm_method_draw_overlap_all(C, win, 0);
- else if (drawmethod == USER_DRAW_FULL)
- wm_method_draw_full(C, win);
- else if (drawmethod == USER_DRAW_OVERLAP)
- wm_method_draw_overlap_all(C, win, 0);
- else if (drawmethod == USER_DRAW_OVERLAP_FLIP)
- wm_method_draw_overlap_all(C, win, 1);
- else { /* USER_DRAW_TRIPLE */
- if ((WM_stereo3d_enabled(win, false)) == false) {
- wm_method_draw_triple(C, win);
- }
- else {
- wm_method_draw_triple_multiview(C, win, STEREO_LEFT_ID);
- wm_method_draw_triple_multiview(C, win, STEREO_RIGHT_ID);
- wm_method_draw_stereo3d(C, win);
- }
- }
+ ED_screen_ensure_updated(wm, win, screen);
+
+ wm_draw_window(C, win);
screen->do_draw_gesture = false;
screen->do_draw_paintcursor = false;
@@ -1019,42 +870,16 @@ void wm_draw_update(bContext *C)
}
}
-void wm_draw_data_free(wmWindow *win)
+void wm_draw_region_clear(wmWindow *win, ARegion *UNUSED(ar))
{
- wmDrawData *dd;
-
- for (dd = win->drawdata.first; dd; dd = dd->next) {
- wm_draw_triple_free(dd->triple);
- }
- BLI_freelistN(&win->drawdata);
+ bScreen *screen = WM_window_get_active_screen(win);
+ screen->do_draw = true;
}
-void wm_draw_window_clear(wmWindow *win)
+void WM_draw_region_free(ARegion *ar)
{
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
-
- wm_draw_data_free(win);
-
- /* clear screen swap flags */
- if (screen) {
- for (sa = screen->areabase.first; sa; sa = sa->next)
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- ar->swap = WIN_NONE_OK;
-
- screen->swap = WIN_NONE_OK;
- }
-}
-
-void wm_draw_region_clear(wmWindow *win, ARegion *ar)
-{
- int drawmethod = wm_automatic_draw_method(win);
-
- if (ELEM(drawmethod, USER_DRAW_OVERLAP, USER_DRAW_OVERLAP_FLIP))
- wm_flush_regions_down(win->screen, &ar->winrct);
-
- win->screen->do_draw = true;
+ wm_draw_region_buffer_free(ar);
+ ar->visible = 0;
}
void WM_redraw_windows(bContext *C)
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 0084c3a5407..23c149b46b5 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -51,14 +51,17 @@
#include "BLI_dynstr.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
+#include "BLI_timer.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BKE_sound.h"
@@ -71,14 +74,15 @@
#include "RNA_access.h"
-#include "GPU_debug.h"
-
#include "UI_interface.h"
#include "PIL_time.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+
#include "wm.h"
#include "wm_window.h"
#include "wm_event_system.h"
@@ -86,14 +90,17 @@
#include "RNA_enum_types.h"
-/* Motion in pixels allowed before we don't consider single/double click. */
-#define WM_EVENT_CLICK_WIGGLE_ROOM 2
+#include "DEG_depsgraph.h"
+
+/* Motion in pixels allowed before we don't consider single/double click,
+ * or detect the start of a tweak event. */
+#define WM_EVENT_CLICK_TWEAK_THRESHOLD (U.tweak_threshold * U.dpi_fac)
static void wm_notifier_clear(wmNotifier *note);
static void update_tablet_data(wmWindow *win, wmEvent *event);
static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
- const short context, const bool poll_only);
+ const short context, const bool poll_only, wmEvent *event);
/* ************ event management ************** */
@@ -182,7 +189,6 @@ static bool wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, v
/* XXX: in future, which notifiers to send to other windows? */
void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
{
- ARegion *ar;
wmWindowManager *wm = CTX_wm_manager(C);
wmNotifier *note;
@@ -196,10 +202,6 @@ void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference
note->window = CTX_wm_window(C);
- ar = CTX_wm_region(C);
- if (ar)
- note->swinid = ar->swinid;
-
note->category = type & NOTE_CATEGORY;
note->data = type & NOTE_DATA;
note->subtype = type & NOTE_SUBTYPE;
@@ -250,6 +252,14 @@ void WM_main_remove_notifier_reference(const void *reference)
wm_notifier_clear(note);
}
}
+
+ /* Remap instead. */
+#if 0
+ if (wm->message_bus) {
+ WM_msg_id_remove(wm->message_bus, reference);
+ }
+#endif
+
}
}
@@ -269,6 +279,17 @@ void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
}
}
}
+
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm && wm->message_bus) {
+ struct wmMsgBus *mbus = wm->message_bus;
+ if (new_id != NULL) {
+ WM_msg_id_update(mbus, old_id, new_id);
+ }
+ else {
+ WM_msg_id_remove(mbus, old_id);
+ }
+ }
}
static void wm_notifier_clear(wmNotifier *note)
@@ -277,47 +298,68 @@ static void wm_notifier_clear(wmNotifier *note)
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
}
-/**
- * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop.
- * This ensures operators don't run before the UI and depsgraph are initialized.
- */
-void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
+void wm_event_do_depsgraph(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ /* The whole idea of locked interface is to prevent viewport and whatever
+ * thread to modify the same data. Because of this, we can not perform
+ * dependency graph update.
+ */
+ if (wm->is_interface_locked) {
+ return;
+ }
+ /* Combine datamasks so 1 win doesn't disable UV's in another [#26448]. */
uint64_t win_combine_v3d_datamask = 0;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const Scene *scene = WM_window_get_active_scene(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
- /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
+ win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen);
+ }
+ /* Update all the dependency graphs of visible vew layers. */
for (wmWindow *win = wm->windows.first; win; win = win->next) {
- win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Main *bmain = CTX_data_main(C);
+ /* Copied to set's in scene_update_tagged_recursive() */
+ scene->customdata_mask = win_combine_v3d_datamask;
+ /* XXX, hack so operators can enforce datamasks [#26482], gl render */
+ scene->customdata_mask |= scene->customdata_mask_modal;
+ /* TODO(sergey): For now all dependency graphs which are evaluated from
+ * workspace are considered active. This will work all fine with "locked"
+ * view layer and time across windows. This is to be granted separately,
+ * and for until then we have to accept ambiguities when object is shared
+ * across visible view layers and has overrides on it.
+ */
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ DEG_make_active(depsgraph);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
}
+}
+/**
+ * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop.
+ * This ensures operators don't run before the UI and depsgraph are initialized.
+ */
+void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
/* cached: editor refresh callbacks now, they get context */
for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa;
CTX_wm_window_set(C, win);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
if (sa->do_refresh) {
CTX_wm_area_set(C, sa);
ED_area_do_refresh(C, sa);
}
}
-
- /* XXX make lock in future, or separated derivedmesh users in scene */
- if (G.is_rendering == false) {
- /* depsgraph & animation: update tagged datablocks */
- Main *bmain = CTX_data_main(C);
-
- /* copied to set's in scene_update_tagged_recursive() */
- win->screen->scene->customdata_mask = win_combine_v3d_datamask;
-
- /* XXX, hack so operators can enforce datamasks [#26482], gl render */
- win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
-
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
- }
}
+ wm_event_do_depsgraph(C);
+
CTX_wm_window_set(C, NULL);
}
@@ -331,8 +373,13 @@ void wm_event_do_notifiers(bContext *C)
if (wm == NULL)
return;
+ BLI_timer_execute();
+
+ /* disable? - keep for now since its used for window level notifiers. */
+#if 1
/* cache & catch WM level notifiers, such as frame change, scene/screen set */
for (win = wm->windows.first; win; win = win->next) {
+ Scene *scene = WM_window_get_active_scene(win);
bool do_anim = false;
CTX_wm_window_set(C, win);
@@ -350,23 +397,46 @@ void wm_event_do_notifiers(bContext *C)
}
if (note->window == win) {
if (note->category == NC_SCREEN) {
- if (note->data == ND_SCREENBROWSE) {
+ if (note->data == ND_WORKSPACE_SET) {
+ WorkSpace *ref_ws = note->reference;
+
+ UI_popup_handlers_remove_all(C, &win->modalhandlers);
+
+ WM_window_set_active_workspace(C, win, ref_ws);
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: Workspace set %p\n", __func__, note->reference);
+ }
+ else if (note->data == ND_WORKSPACE_DELETE) {
+ WorkSpace *workspace = note->reference;
+
+ ED_workspace_delete(workspace, CTX_data_main(C), C, wm); // XXX hrms, think this over!
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: Workspace delete %p\n", __func__, workspace);
+ }
+ else if (note->data == ND_LAYOUTBROWSE) {
+ bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
+
/* free popup handlers only [#35434] */
UI_popup_handlers_remove_all(C, &win->modalhandlers);
- ED_screen_set(C, note->reference); // XXX hrms, think this over!
- CLOG_INFO(WM_LOG_EVENTS, 1, "screen set %p", note->reference);
+ ED_screen_change(C, ref_screen); /* XXX hrms, think this over! */
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: screen set %p\n", __func__, note->reference);
}
- else if (note->data == ND_SCREENDELETE) {
- ED_screen_delete(C, note->reference); // XXX hrms, think this over!
- CLOG_INFO(WM_LOG_EVENTS, 1, "screen delete %p", note->reference);
+ else if (note->data == ND_LAYOUTDELETE) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = note->reference;
+
+ ED_workspace_layout_delete(workspace, layout, C); // XXX hrms, think this over!
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: screen delete %p\n", __func__, note->reference);
}
}
}
if (note->window == win ||
- (note->window == NULL && (note->reference == NULL || note->reference == win->screen->scene)))
+ (note->window == NULL && (note->reference == NULL || note->reference == scene)))
{
if (note->category == NC_SCENE) {
if (note->data == ND_FRAME)
@@ -374,19 +444,20 @@ void wm_event_do_notifiers(bContext *C)
}
}
if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
- ED_info_stats_clear(win->screen->scene);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ED_info_stats_clear(view_layer);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
}
if (do_anim) {
/* XXX, quick frame changes can cause a crash if framechange and rendering
- * collide (happens on slow scenes), BKE_scene_update_for_newframe can be called
+ * collide (happens on slow scenes), BKE_scene_graph_update_for_newframe can be called
* twice which can depgraph update the same object at once */
if (G.is_rendering == false) {
-
/* depsgraph gets called, might send more notifiers */
- ED_update_for_newframe(CTX_data_main(C), win->screen->scene, 1);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_update_for_newframe(CTX_data_main(C), depsgraph);
}
}
}
@@ -394,16 +465,23 @@ void wm_event_do_notifiers(bContext *C)
/* the notifiers are sent without context, to keep it clean */
while ((note = BLI_pophead(&wm->queue))) {
for (win = wm->windows.first; win; win = win->next) {
+ Scene *scene = WM_window_get_active_scene(win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
/* filter out notifiers */
- if (note->category == NC_SCREEN && note->reference && note->reference != win->screen) {
+ if (note->category == NC_SCREEN &&
+ note->reference &&
+ note->reference != screen &&
+ note->reference != workspace &&
+ note->reference != WM_window_get_active_layout(win))
+ {
/* pass */
}
- else if (note->category == NC_SCENE && note->reference && note->reference != win->screen->scene) {
+ else if (note->category == NC_SCENE && note->reference && note->reference != scene) {
/* pass */
}
else {
- ScrArea *sa;
ARegion *ar;
/* XXX context in notifiers? */
@@ -412,14 +490,14 @@ void wm_event_do_notifiers(bContext *C)
/* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name + 2, note->category); */
ED_screen_do_listen(C, note);
- for (ar = win->screen->regionbase.first; ar; ar = ar->next) {
- ED_region_do_listen(win->screen, NULL, ar, note);
+ for (ar = screen->regionbase.first; ar; ar = ar->next) {
+ ED_region_do_listen(win, NULL, ar, note, scene);
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- ED_area_do_listen(win->screen, sa, note);
+ ED_screen_areas_iter(win, screen, sa) {
+ ED_area_do_listen(win, sa, note, scene);
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- ED_region_do_listen(win->screen, sa, ar, note);
+ ED_region_do_listen(win, sa, ar, note, scene);
}
}
}
@@ -427,8 +505,29 @@ void wm_event_do_notifiers(bContext *C)
MEM_freeN(note);
}
+#endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */
+
+ /* Handle message bus. */
+ {
+ for (win = wm->windows.first; win; win = win->next) {
+ CTX_wm_window_set(C, win);
+ WM_msgbus_handle(wm->message_bus, C);
+ }
+ CTX_wm_window_set(C, NULL);
+ }
wm_event_do_refresh_wm_and_depsgraph(C);
+
+ /* Status bar */
+ if (wm->winactive) {
+ win = wm->winactive;
+ CTX_wm_window_set(C, win);
+ WM_window_cursor_keymap_status_refresh(C, win);
+ CTX_wm_window_set(C, NULL);
+ }
+
+ /* Autorun warning */
+ wm_test_autorun_warning(C);
}
static int wm_event_always_pass(const wmEvent *event)
@@ -543,7 +642,40 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
/* sets up the new context and calls 'wm_operator_invoke()' with poll_only */
bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
{
- return wm_operator_call_internal(C, ot, NULL, NULL, context, true);
+ return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL);
+}
+
+bool WM_operator_check_ui_empty(wmOperatorType *ot)
+{
+ if (ot->macro.first != NULL) {
+ /* for macros, check all have exec() we can call */
+ wmOperatorTypeMacro *otmacro;
+ for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
+ wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
+ if (otm && !WM_operator_check_ui_empty(otm)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* Assume a ui callback will draw something. */
+ if (ot->ui) {
+ return false;
+ }
+
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_STRUCT_BEGIN (&ptr, prop)
+ {
+ int flag = RNA_property_flag(prop);
+ if (flag & PROP_HIDDEN) {
+ continue;
+ }
+ return false;
+ }
+ RNA_STRUCT_END;
+ return true;
}
/**
@@ -687,7 +819,7 @@ void WM_reportf(ReportType type, const char *format, ...)
/* (caller_owns_reports == true) when called from python */
static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
{
- if (caller_owns_reports == false) { /* popup */
+ if (G.background == 0 && caller_owns_reports == false) { /* popup */
if (op->reports->list.first) {
/* FIXME, temp setting window, see other call to UI_popup_menu_reports for why */
wmWindow *win_prev = CTX_wm_window(C);
@@ -740,6 +872,7 @@ static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, const bool store)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ enum { NOP, SET, CLEAR, } hud_status = NOP;
op->customdata = NULL;
@@ -751,10 +884,19 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
* called from operators that already do an undo push. usually
* this will happen for python operators that call C operators */
if (wm->op_undo_depth == 0) {
- if (op->type->flag & OPTYPE_UNDO)
+ if (op->type->flag & OPTYPE_UNDO) {
ED_undo_push_op(C, op);
- else if (op->type->flag & OPTYPE_UNDO_GROUPED)
+ if (repeat == 0) {
+ hud_status = CLEAR;
+ }
+ }
+ else if (op->type->flag & OPTYPE_UNDO_GROUPED) {
ED_undo_grouped_push_op(C, op);
+ if (repeat == 0) {
+ hud_status = CLEAR;
+ }
+ }
+
}
if (repeat == 0) {
@@ -770,11 +912,31 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
wm_operator_register(C, op);
WM_operator_region_active_win_set(C);
+
+ if (WM_operator_last_redo(C) == op) {
+ /* Show the redo panel. */
+ hud_status = SET;
+ }
}
else {
WM_operator_free(op);
}
}
+
+ if (hud_status != NOP) {
+ if (hud_status == SET) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa) {
+ ED_area_type_hud_ensure(C, sa);
+ }
+ }
+ else if (hud_status == CLEAR) {
+ ED_area_type_hud_clear(wm, NULL);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
}
/* if repeat is true, it doesn't register again, nor does it free */
@@ -1127,7 +1289,8 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
*/
static int wm_operator_invoke(
bContext *C, wmOperatorType *ot, wmEvent *event,
- PointerRNA *properties, ReportList *reports, const bool poll_only)
+ PointerRNA *properties, ReportList *reports,
+ const bool poll_only, bool use_last_properties)
{
int retval = OPERATOR_PASS_THROUGH;
@@ -1145,14 +1308,14 @@ static int wm_operator_invoke(
}
/* initialize setting from previous run */
- if (!is_nested_call) { /* not called by py script */
+ if (!is_nested_call && use_last_properties) { /* not called by py script */
WM_operator_last_properties_init(op);
}
if ((event == NULL) || (event->type != MOUSEMOVE)) {
CLOG_INFO(WM_LOG_HANDLERS, 2,
- "handle evt %d win %d op %s",
- event ? event->type : 0, CTX_wm_screen(C)->subwinactive, ot->idname);
+ "handle evt %d win %p op %s",
+ event ? event->type : 0, CTX_wm_screen(C)->active_region, ot->idname);
}
if (op->type->invoke && event) {
@@ -1193,7 +1356,7 @@ static int wm_operator_invoke(
/* do nothing, wm_operator_exec() has been called somewhere */
}
else if (retval & OPERATOR_FINISHED) {
- const bool store = !is_nested_call;
+ const bool store = !is_nested_call && use_last_properties;
wm_operator_finished(C, op, false, store);
}
else if (retval & OPERATOR_RUNNING_MODAL) {
@@ -1274,10 +1437,8 @@ static int wm_operator_invoke(
*/
static int wm_operator_call_internal(
bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports,
- const short context, const bool poll_only)
+ const short context, const bool poll_only, wmEvent *event)
{
- wmEvent *event;
-
int retval;
CTX_wm_operator_poll_msg_set(C, NULL);
@@ -1286,31 +1447,45 @@ static int wm_operator_call_internal(
if (ot) {
wmWindow *window = CTX_wm_window(C);
- switch (context) {
- case WM_OP_INVOKE_DEFAULT:
- case WM_OP_INVOKE_REGION_WIN:
- case WM_OP_INVOKE_REGION_PREVIEW:
- case WM_OP_INVOKE_REGION_CHANNELS:
- case WM_OP_INVOKE_AREA:
- case WM_OP_INVOKE_SCREEN:
- /* window is needed for invoke, cancel operator */
- if (window == NULL) {
- if (poll_only) {
- CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context");
+ if (event == NULL) {
+ switch (context) {
+ case WM_OP_INVOKE_DEFAULT:
+ case WM_OP_INVOKE_REGION_WIN:
+ case WM_OP_INVOKE_REGION_PREVIEW:
+ case WM_OP_INVOKE_REGION_CHANNELS:
+ case WM_OP_INVOKE_AREA:
+ case WM_OP_INVOKE_SCREEN:
+ /* window is needed for invoke, cancel operator */
+ if (window == NULL) {
+ if (poll_only) {
+ CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context");
+ }
+ return 0;
}
- return 0;
- }
- else {
- event = window->eventstate;
- }
- break;
- default:
- event = NULL;
- break;
+ else {
+ event = window->eventstate;
+ }
+ break;
+ default:
+ event = NULL;
+ break;
+ }
+ }
+ else {
+ switch (context) {
+ case WM_OP_EXEC_DEFAULT:
+ case WM_OP_EXEC_REGION_WIN:
+ case WM_OP_EXEC_REGION_PREVIEW:
+ case WM_OP_EXEC_REGION_CHANNELS:
+ case WM_OP_EXEC_AREA:
+ case WM_OP_EXEC_SCREEN:
+ event = NULL;
+ default:
+ break;
+ }
}
switch (context) {
-
case WM_OP_EXEC_REGION_WIN:
case WM_OP_INVOKE_REGION_WIN:
case WM_OP_EXEC_REGION_CHANNELS:
@@ -1356,7 +1531,7 @@ static int wm_operator_call_internal(
CTX_wm_region_set(C, ar1);
}
- retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
+ retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
/* set region back */
CTX_wm_region_set(C, ar);
@@ -1370,7 +1545,7 @@ static int wm_operator_call_internal(
ARegion *ar = CTX_wm_region(C);
CTX_wm_region_set(C, NULL);
- retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
+ retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_region_set(C, ar);
return retval;
@@ -1384,7 +1559,7 @@ static int wm_operator_call_internal(
CTX_wm_region_set(C, NULL);
CTX_wm_area_set(C, NULL);
- retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
+ retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, ar);
@@ -1392,7 +1567,7 @@ static int wm_operator_call_internal(
}
case WM_OP_EXEC_DEFAULT:
case WM_OP_INVOKE_DEFAULT:
- return wm_operator_invoke(C, ot, event, properties, reports, poll_only);
+ return wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
}
}
@@ -1404,7 +1579,7 @@ static int wm_operator_call_internal(
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties)
{
BLI_assert(ot == WM_operatortype_find(ot->idname, true));
- return wm_operator_call_internal(C, ot, properties, NULL, context, false);
+ return wm_operator_call_internal(C, ot, properties, NULL, context, false, NULL);
}
int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)
{
@@ -1470,7 +1645,7 @@ int WM_operator_call_py(
wmWindowManager *wm = CTX_wm_manager(C);
if (!is_undo && wm) wm->op_undo_depth++;
- retval = wm_operator_call_internal(C, ot, properties, reports, context, false);
+ retval = wm_operator_call_internal(C, ot, properties, reports, context, false, NULL);
if (!is_undo && wm && (wm == CTX_wm_manager(C))) wm->op_undo_depth--;
@@ -1489,17 +1664,22 @@ void wm_event_free_handler(wmEventHandler *handler)
/* only set context when area/region is part of screen */
static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wmEvent *event)
{
+ wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
if (screen && handler->op) {
if (handler->op_area == NULL)
CTX_wm_area_set(C, NULL);
else {
- ScrArea *sa;
+ ScrArea *sa = NULL;
- for (sa = screen->areabase.first; sa; sa = sa->next)
- if (sa == handler->op_area)
+ ED_screen_areas_iter(win, screen, sa_iter) {
+ if (sa_iter == handler->op_area) {
+ sa = sa_iter;
break;
+ }
+ }
+
if (sa == NULL) {
/* when changing screen layouts with running modal handlers (like render display), this
* is not an error to print */
@@ -1593,14 +1773,6 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
int WM_userdef_event_map(int kmitype)
{
switch (kmitype) {
- case SELECTMOUSE:
- return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
- case ACTIONMOUSE:
- return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
- case EVT_TWEAK_A:
- return (U.flag & USER_LMOUSESELECT) ? EVT_TWEAK_R : EVT_TWEAK_L;
- case EVT_TWEAK_S:
- return (U.flag & USER_LMOUSESELECT) ? EVT_TWEAK_L : EVT_TWEAK_R;
case WHEELOUTMOUSE:
return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELUPMOUSE : WHEELDOWNMOUSE;
case WHEELINMOUSE:
@@ -1618,14 +1790,6 @@ int WM_userdef_event_map(int kmitype)
int WM_userdef_event_type_from_keymap_type(int kmitype)
{
switch (kmitype) {
- case SELECTMOUSE:
- return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
- case ACTIONMOUSE:
- return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
- case EVT_TWEAK_S:
- return (U.flag & USER_LMOUSESELECT) ? LEFTMOUSE : RIGHTMOUSE;
- case EVT_TWEAK_A:
- return (U.flag & USER_LMOUSESELECT) ? RIGHTMOUSE : LEFTMOUSE;
case EVT_TWEAK_L:
return LEFTMOUSE;
case EVT_TWEAK_M:
@@ -1709,13 +1873,15 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve
for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
if (wm_eventmatch(event, kmi)) {
-
- event->prevtype = event->type;
- event->prevval = event->val;
- event->type = EVT_MODAL_MAP;
- event->val = kmi->propvalue;
-
- break;
+ if ((keymap->poll_modal_item == NULL) ||
+ (keymap->poll_modal_item(op, kmi->propvalue)))
+ {
+ event->prevtype = event->type;
+ event->prevval = event->val;
+ event->type = EVT_MODAL_MAP;
+ event->val = kmi->propvalue;
+ break;
+ }
}
}
}
@@ -1808,6 +1974,11 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
wm_operator_reports(C, op, retval, false);
+
+ if (op->type->modalkeymap) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_window_status_area_tag_redraw(win);
+ }
}
else {
/* not very common, but modal operators may report before finishing */
@@ -1837,6 +2008,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
CTX_wm_region_set(C, NULL);
}
+ /* update gizmos during modal handlers */
+ wm_gizmomaps_handled_modal_update(C, event, handler);
+
/* remove modal handler, operator itself should have been canceled and freed */
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
WM_cursor_grab_disable(CTX_wm_window(C), NULL);
@@ -1856,10 +2030,40 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
else {
wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0);
- if (ot) {
- if (wm_operator_check_locked_interface(C, ot)) {
- retval = wm_operator_invoke(C, ot, event, properties, NULL, false);
+ if (ot && wm_operator_check_locked_interface(C, ot)) {
+ bool use_last_properties = true;
+ PointerRNA tool_properties = {{0}};
+ const bool is_tool = (handler->keymap_tool != NULL);
+ const bool use_tool_properties = is_tool;
+
+ if (use_tool_properties) {
+ WM_toolsystem_ref_properties_init_for_keymap(handler->keymap_tool, &tool_properties, properties, ot);
+ properties = &tool_properties;
+ use_last_properties = false;
}
+
+ retval = wm_operator_invoke(C, ot, event, properties, NULL, false, use_last_properties);
+
+ if (use_tool_properties) {
+ WM_operator_properties_free(&tool_properties);
+ }
+
+ /* Link gizmo if 'WM_GIZMOGROUPTYPE_TOOL_INIT' is set. */
+ if (retval & OPERATOR_FINISHED) {
+ if (is_tool) {
+ bToolRef_Runtime *tref_rt = handler->keymap_tool->runtime;
+ if (tref_rt->gizmo_group[0]) {
+ const char *idname = tref_rt->gizmo_group;
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ if (gzgt != NULL) {
+ if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) != 0) {
+ WM_gizmo_group_type_ensure_ptr(gzgt);
+ }
+ }
+ }
+ }
+ }
+ /* Done linking gizmo. */
}
}
/* Finished and pass through flag as handled */
@@ -1890,9 +2094,10 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
{
ScrArea *sa;
- /* sa can be null when window A is active, but mouse is over window B */
- /* in this case, open file select in original window A */
- if (handler->op_area == NULL) {
+ /* sa can be null when window A is active, but mouse is over window B
+ * in this case, open file select in original window A. Also don't
+ * use global areas. */
+ if (handler->op_area == NULL || ED_area_is_global(handler->op_area)) {
bScreen *screen = CTX_wm_screen(C);
sa = (ScrArea *)screen->areabase.first;
}
@@ -2132,6 +2337,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
if (wm_eventmatch(event, kmi)) {
+ struct wmEventHandler_KeymapFn keymap_callback = handler->keymap_callback;
PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
@@ -2139,9 +2345,13 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
event->keymap_idname = kmi->idname;
action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
+
if (action & WM_HANDLER_BREAK) {
/* not always_pass here, it denotes removed handler */
CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname);
+ if (keymap_callback.handle_post_fn != NULL) {
+ keymap_callback.handle_post_fn(keymap, kmi, keymap_callback.user_data);
+ }
break;
}
else {
@@ -2180,18 +2390,28 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
wmDrag *drag;
for (drag = lb->first; drag; drag = drag->next) {
- if (drop->poll(C, drag, event)) {
- drop->copy(drag, drop);
+ const char *tooltip = NULL;
+ if (drop->poll(C, drag, event, &tooltip)) {
+ /* Optionally copy drag information to operator properties. */
+ if (drop->copy) {
+ drop->copy(drag, drop);
+ }
+
+ /* Pass single matched wmDrag onto the operator. */
+ BLI_remlink(lb, drag);
+ ListBase single_lb = {drag, drag};
+ event->customdata = &single_lb;
- /* free the drags before calling operator */
+ wm_operator_call_internal(C, drop->ot, drop->ptr, NULL, drop->opcontext, false, event);
+ action |= WM_HANDLER_BREAK;
+
+ /* free the drags */
WM_drag_free_list(lb);
+ WM_drag_free_list(&single_lb);
event->customdata = NULL;
event->custom = 0;
- WM_operator_name_call_ptr(C, drop->ot, drop->opcontext, drop->ptr);
- action |= WM_HANDLER_BREAK;
-
/* XXX fileread case */
if (CTX_wm_window(C) == NULL)
return action;
@@ -2204,6 +2424,145 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
}
}
}
+ else if (handler->gizmo_map) {
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ wmGizmoMap *gzmap = handler->gizmo_map;
+ wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
+
+ if (region->gizmo_map != handler->gizmo_map) {
+ WM_gizmomap_tag_refresh(handler->gizmo_map);
+ }
+
+ wm_gizmomap_handler_context(C, handler);
+ wm_region_mouse_co(C, event);
+
+ /* handle gizmo highlighting */
+ if (event->type == MOUSEMOVE && !wm_gizmomap_modal_get(gzmap)) {
+ int part;
+ gz = wm_gizmomap_highlight_find(gzmap, C, event, &part);
+ if (wm_gizmomap_highlight_set(gzmap, C, gz, part) && gz != NULL) {
+ if (U.flag & USER_TOOLTIPS) {
+ WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_gizmomap_tooltip_init);
+ }
+ }
+ }
+ else {
+ /* Either we operate on a single highlighted item
+ * or groups attached to the selected gizmos.
+ * To simplify things both cases loop over an array of items. */
+ wmGizmoGroup *gzgroup_first;
+ bool is_gzgroup_single;
+
+ if (ISMOUSE(event->type)) {
+ /* Keep gz set as-is, just fake single selection. */
+ if (gz) {
+ gzgroup_first = gz->parent_gzgroup;
+ }
+ else {
+ gzgroup_first = NULL;
+ }
+ is_gzgroup_single = true;
+ }
+ else {
+ if (WM_gizmomap_is_any_selected(gzmap)) {
+ const ListBase *groups = WM_gizmomap_group_list(gzmap);
+ gzgroup_first = groups->first;
+ }
+ else {
+ gzgroup_first = NULL;
+ }
+ is_gzgroup_single = false;
+ }
+
+ /* Don't use from now on. */
+ gz = NULL;
+
+ for (wmGizmoGroup *gzgroup = gzgroup_first; gzgroup; gzgroup = gzgroup->next) {
+ /* get user customized keymap from default one */
+
+ if ((is_gzgroup_single == false) &&
+ /* We might want to change the logic here and use some kind of gizmo edit-mode.
+ * For now just use keymap when a selection exists. */
+ wm_gizmogroup_is_any_selected(gzgroup) == false)
+ {
+ continue;
+ }
+
+ wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
+ wmKeyMapItem *kmi;
+
+ PRINT("%s: checking '%s' ...", __func__, keymap->idname);
+
+ if (WM_keymap_poll(C, keymap)) {
+ PRINT("pass\n");
+ for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (wm_eventmatch(event, kmi)) {
+ struct wmEventHandler_KeymapFn keymap_callback = handler->keymap_callback;
+ wmOperator *op = handler->op;
+
+ PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
+
+ /* weak, but allows interactive callback to not use rawkey */
+ event->keymap_idname = kmi->idname;
+
+ CTX_wm_gizmo_group_set(C, gzgroup);
+
+ /* handler->op is called later, we want keymap op to be triggered here */
+ handler->op = NULL;
+ action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
+ handler->op = op;
+
+ CTX_wm_gizmo_group_set(C, NULL);
+
+ if (action & WM_HANDLER_BREAK) {
+ if (keymap_callback.handle_post_fn != NULL) {
+ keymap_callback.handle_post_fn(keymap, kmi, keymap_callback.user_data);
+ }
+
+ if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
+ printf("%s: handled - and pass on! '%s'\n",
+ __func__, kmi->idname);
+ }
+ break;
+ }
+ else {
+ if (action & WM_HANDLER_HANDLED) {
+ if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
+ printf("%s: handled - and pass on! '%s'\n",
+ __func__, kmi->idname);
+ }
+ }
+ else {
+ PRINT("%s: un-handled '%s'\n",
+ __func__, kmi->idname);
+ }
+ }
+ }
+ }
+ }
+ else {
+ PRINT("fail\n");
+ }
+
+ if (action & WM_HANDLER_BREAK) {
+ break;
+ }
+
+ if (is_gzgroup_single) {
+ break;
+ }
+ }
+ }
+
+ /* restore the area */
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+
+ if (handler->op) {
+ action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
+ }
+ }
else {
/* modal, swallows all */
action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
@@ -2257,11 +2616,16 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
if (wm_action_not_handled(action)) {
if (event->check_drag) {
wmWindow *win = CTX_wm_window(C);
- if ((abs(event->x - win->eventstate->prevclickx)) >= U.tweak_threshold ||
- (abs(event->y - win->eventstate->prevclicky)) >= U.tweak_threshold)
+ if ((abs(event->x - win->eventstate->prevclickx)) >= WM_EVENT_CLICK_TWEAK_THRESHOLD ||
+ (abs(event->y - win->eventstate->prevclicky)) >= WM_EVENT_CLICK_TWEAK_THRESHOLD)
{
+ int x = event->x;
+ int y = event->y;
short val = event->val;
short type = event->type;
+
+ event->x = win->eventstate->prevclickx;
+ event->y = win->eventstate->prevclicky;
event->val = KM_CLICK_DRAG;
event->type = win->eventstate->type;
@@ -2271,16 +2635,18 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
event->val = val;
event->type = type;
+ event->x = x;
+ event->y = y;
- win->eventstate->check_click = 0;
- win->eventstate->check_drag = 0;
+ win->eventstate->check_click = false;
+ win->eventstate->check_drag = false;
}
}
}
else {
wmWindow *win = CTX_wm_window(C);
if (win) {
- win->eventstate->check_drag = 0;
+ win->eventstate->check_drag = false;
}
}
}
@@ -2310,9 +2676,16 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
(win->eventstate->prevval == KM_PRESS) &&
(win->eventstate->check_click == true))
{
- if ((abs(event->x - win->eventstate->prevclickx)) <= WM_EVENT_CLICK_WIGGLE_ROOM &&
- (abs(event->y - win->eventstate->prevclicky)) <= WM_EVENT_CLICK_WIGGLE_ROOM)
+ if ((abs(event->x - win->eventstate->prevclickx)) < WM_EVENT_CLICK_TWEAK_THRESHOLD &&
+ (abs(event->y - win->eventstate->prevclicky)) < WM_EVENT_CLICK_TWEAK_THRESHOLD)
{
+ /* Position is where the actual click happens, for more
+ * accurate selecting in case the mouse drifts a little. */
+ int x = event->x;
+ int y = event->y;
+
+ event->x = win->eventstate->prevclickx;
+ event->y = win->eventstate->prevclicky;
event->val = KM_CLICK;
CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK");
@@ -2320,6 +2693,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
action |= wm_handlers_do_intern(C, event, handlers);
event->val = KM_RELEASE;
+ event->x = x;
+ event->y = y;
}
else {
win->eventstate->check_click = 0;
@@ -2360,13 +2735,15 @@ static int wm_event_inside_i(wmEvent *event, rcti *rect)
static ScrArea *area_event_inside(bContext *C, const int xy[2])
{
+ wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa;
- if (screen)
- for (sa = screen->areabase.first; sa; sa = sa->next)
+ if (screen) {
+ ED_screen_areas_iter(win, screen, sa) {
if (BLI_rcti_isect_pt_v(&sa->totrct, xy))
return sa;
+ }
+ }
return NULL;
}
@@ -2424,17 +2801,19 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
{
+ bScreen *screen = WM_window_get_active_screen(win);
+
if (BLI_listbase_is_empty(&wm->drags)) {
return;
}
if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
}
else if (event->type == ESCKEY) {
WM_drag_free_list(&wm->drags);
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
}
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
event->type = EVT_DROP;
@@ -2450,17 +2829,11 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
event->customdatafree = 1;
/* clear drop icon */
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
/* restore cursor (disabled, see wm_dragdrop.c) */
// WM_cursor_modal_restore(win);
}
-
- /* overlap fails otherwise */
- if (win->screen->do_draw_drag)
- if (win->drawmethod == USER_DRAW_OVERLAP)
- win->screen->do_draw = true;
-
}
/* filter out all events of the pie that spawned the last pie unless it's a release event */
@@ -2480,6 +2853,45 @@ static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
}
}
+#ifdef USE_WORKSPACE_TOOL
+static void wm_event_temp_tool_handler_apply(
+ bContext *C, ScrArea *sa, ARegion *ar, wmEventHandler *sneaky_handler)
+{
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
+ if (tref_rt && tref_rt->keymap[0]) {
+ wmKeyMap *km = WM_keymap_find_all_spaceid_or_empty(
+ C, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW);
+ /* We shouldn't use keymaps from unrelated spaces. */
+ if (km != NULL) {
+ // printf("Keymap: '%s' -> '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ sneaky_handler->keymap = km;
+ sneaky_handler->keymap_tool = sa->runtime.tool;
+
+ /* Handle widgets first. */
+ wmEventHandler *handler_last = ar->handlers.last;
+ while (handler_last && handler_last->gizmo_map == NULL) {
+ handler_last = handler_last->prev;
+ }
+ /* Head of list or after last gizmo. */
+ BLI_insertlinkafter(&ar->handlers, handler_last, sneaky_handler);
+ }
+ else {
+ printf("Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ }
+ }
+ }
+}
+
+static void wm_event_temp_tool_handler_clear(
+ bContext *UNUSED(C), ScrArea *UNUSED(sa), ARegion *ar, wmEventHandler *sneaky_handler)
+{
+ if (sneaky_handler->keymap) {
+ BLI_remlink(&ar->handlers, sneaky_handler);
+ }
+}
+#endif /* USE_WORKSPACE_TOOL */
+
/* called in main loop */
/* goes over entire hierarchy: events -> window -> screen -> area -> region */
void wm_event_do_handlers(bContext *C)
@@ -2489,22 +2901,28 @@ void wm_event_do_handlers(bContext *C)
/* update key configuration before handling events */
WM_keyconfig_update(wm);
+ WM_gizmoconfig_update(CTX_data_main(C));
for (win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
wmEvent *event;
- if (win->screen == NULL)
+ /* some safety checks - these should always be set! */
+ BLI_assert(WM_window_get_active_scene(win));
+ BLI_assert(WM_window_get_active_screen(win));
+ BLI_assert(WM_window_get_active_workspace(win));
+
+ if (screen == NULL)
wm_event_free_all(win);
else {
- Scene *scene = win->screen->scene;
+ Scene *scene = WM_window_get_active_scene(win);
if (scene) {
- int is_playing_sound = BKE_sound_scene_playing(win->screen->scene);
+ int is_playing_sound = BKE_sound_scene_playing(scene);
if (is_playing_sound != -1) {
bool is_playing_screen;
CTX_wm_window_set(C, win);
- CTX_wm_screen_set(C, win->screen);
CTX_data_scene_set(C, scene);
is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
@@ -2521,7 +2939,8 @@ void wm_event_do_handlers(bContext *C)
int ncfra = time * (float)FPS + 0.5f;
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
- ED_update_for_newframe(CTX_data_main(C), scene, 1);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_update_for_newframe(CTX_data_main(C), depsgraph);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
}
@@ -2537,9 +2956,11 @@ void wm_event_do_handlers(bContext *C)
while ( (event = win->queue.first) ) {
int action = WM_HANDLER_CONTINUE;
+ /* active screen might change during handlers, update pointer */
+ screen = WM_window_get_active_screen(win);
+
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);
}
@@ -2556,7 +2977,7 @@ void wm_event_do_handlers(bContext *C)
CTX_wm_window_set(C, win);
/* Clear tool-tip on mouse move. */
- if (win->screen->tool_tip && win->screen->tool_tip->exit_on_event) {
+ if (screen->tool_tip && screen->tool_tip->exit_on_event) {
if (ISMOUSE(event->type)) {
WM_tooltip_clear(C, win);
}
@@ -2580,8 +3001,7 @@ void wm_event_do_handlers(bContext *C)
return;
/* check for a tooltip */
- {
- bScreen *screen = CTX_wm_window(C)->screen;
+ if (screen == WM_window_get_active_screen(win)) {
if (screen->tool_tip && screen->tool_tip->timer) {
if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) {
WM_tooltip_init(C, win);
@@ -2596,13 +3016,12 @@ void wm_event_do_handlers(bContext *C)
wm_tweakevent_test(C, event, action);
if ((action & WM_HANDLER_BREAK) == 0) {
- ScrArea *sa;
ARegion *ar;
/* Note: setting subwin active should be done here, after modal handlers have been done */
if (event->type == MOUSEMOVE) {
/* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */
- ED_screen_set_subwinactive(C, event);
+ ED_screen_set_active_region(C, win, &event->x);
/* for regions having custom cursors */
wm_paintcursor_test(C, event);
}
@@ -2612,12 +3031,12 @@ void wm_event_do_handlers(bContext *C)
}
#endif
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, sa) {
/* after restoring a screen from SCREENMAXIMIZED we have to wait
* with the screen handling till the region coordinates are updated */
- if (win->screen->skip_handling == true) {
+ if (screen->skip_handling == true) {
/* restore for the next iteration of wm_event_do_handlers */
- win->screen->skip_handling = false;
+ screen->skip_handling = false;
break;
}
@@ -2645,8 +3064,27 @@ void wm_event_do_handlers(bContext *C)
}
}
+#ifdef USE_WORKSPACE_TOOL
+ /* How to solve properly?
+ *
+ * Handlers are stored in each region,
+ * however the tool-system swaps keymaps often and isn't stored
+ * per region.
+ *
+ * Need to investigate how this could be done better.
+ * We might need to add a more dynamic handler type that uses a callback
+ * to fetch its current keymap.
+ */
+ wmEventHandler sneaky_handler = {NULL};
+ wm_event_temp_tool_handler_apply(C, sa, ar, &sneaky_handler);
+#endif /* USE_WORKSPACE_TOOL */
+
action |= wm_handlers_do(C, event, &ar->handlers);
+#ifdef USE_WORKSPACE_TOOL
+ wm_event_temp_tool_handler_clear(C, sa, ar, &sneaky_handler);
+#endif /* USE_WORKSPACE_TOOL */
+
/* fileread case (python), [#29489] */
if (CTX_wm_window(C) == NULL)
return;
@@ -2685,6 +3123,12 @@ void wm_event_do_handlers(bContext *C)
}
+ /* If press was handled, we don't want to do click. This way
+ * press in tool keymap can override click in editor keymap.*/
+ if (event->val == KM_PRESS && !wm_action_not_handled(action)) {
+ win->eventstate->check_click = false;
+ }
+
/* update previous mouse position for following events to use */
win->eventstate->prevx = event->x;
win->eventstate->prevy = event->y;
@@ -2711,8 +3155,7 @@ void wm_event_do_handlers(bContext *C)
/* update key configuration after handling events */
WM_keyconfig_update(wm);
-
- GPU_ASSERT_NO_GL_ERRORS("wm_event_do_handlers");
+ WM_gizmoconfig_update(CTX_data_main(C));
}
/* ********** filesector handling ************ */
@@ -2748,30 +3191,35 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
+ /* Close any popups, like when opening a file browser from the splash. */
+ UI_popup_handlers_remove_all(C, &win->modalhandlers);
+
/* only allow 1 file selector open per window */
for (handler = win->modalhandlers.first; handler; handler = handlernext) {
handlernext = handler->next;
if (handler->type == WM_HANDLER_FILESELECT) {
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa;
+ bool cancel_handler = true;
/* find the area with the file selector for this handler */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, sa) {
if (sa->spacetype == SPACE_FILE) {
SpaceFile *sfile = sa->spacedata.first;
if (sfile->op == handler->op) {
CTX_wm_area_set(C, sa);
wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
+ cancel_handler = false;
break;
}
}
}
/* if not found we stop the handler without changing the screen */
- if (!sa)
+ if (cancel_handler) {
wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ }
}
}
@@ -2822,9 +3270,41 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
BLI_addhead(&win->modalhandlers, handler);
+ if (op->type->modalkeymap) {
+ WM_window_status_area_tag_redraw(win);
+ }
+
return handler;
}
+/**
+ * Modal handlers store a pointer to an area which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_area.
+ */
+void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
+{
+ for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
+ /* fileselect handler is quite special... it needs to keep old area stored in handler, so don't change it */
+ if ((handler->op_area == old_area) && (handler->type != WM_HANDLER_FILESELECT)) {
+ handler->op_area = new_area;
+ }
+ }
+}
+
+/**
+ * Modal handlers store a pointer to a region which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_region.
+ */
+void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
+{
+ for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
+ if (handler->op_region == old_region) {
+ handler->op_region = new_region;
+ handler->op_region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW;
+ }
+ }
+}
+
wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
{
wmEventHandler *handler;
@@ -2884,6 +3364,15 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
}
}
+void WM_event_set_keymap_handler_callback(
+ wmEventHandler *handler,
+ void (keymap_tag)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data),
+ void *user_data)
+{
+ handler->keymap_callback.handle_post_fn = keymap_tag;
+ handler->keymap_callback.user_data = user_data;
+}
+
wmEventHandler *WM_event_add_ui_handler(
const bContext *C, ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
@@ -3188,6 +3677,22 @@ static void wm_eventemulation(wmEvent *event)
}
}
+/* applies the global tablet pressure correction curve */
+float wm_pressure_curve(float pressure)
+{
+ if (U.pressure_threshold_max != 0.0f) {
+ pressure /= U.pressure_threshold_max;
+ }
+
+ CLAMP(pressure, 0.0f, 1.0f);
+
+ if (U.pressure_softness != 0.0f) {
+ pressure = powf(pressure, powf(4.0f, -U.pressure_softness));
+ }
+
+ return pressure;
+}
+
/* adds customdata to event */
static void update_tablet_data(wmWindow *win, wmEvent *event)
{
@@ -3198,7 +3703,7 @@ static void update_tablet_data(wmWindow *win, wmEvent *event)
struct wmTabletData *wmtab = MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
wmtab->Active = (int)td->Active;
- wmtab->Pressure = td->Pressure;
+ wmtab->Pressure = wm_pressure_curve(td->Pressure);
wmtab->Xtilt = td->Xtilt;
wmtab->Ytilt = td->Ytilt;
@@ -3293,8 +3798,8 @@ static bool wm_event_is_double_click(wmEvent *event, const wmEvent *event_state)
(event->val == KM_PRESS))
{
if ((ISMOUSE(event->type) == false) ||
- ((abs(event->x - event_state->prevclickx)) <= WM_EVENT_CLICK_WIGGLE_ROOM &&
- (abs(event->y - event_state->prevclicky)) <= WM_EVENT_CLICK_WIGGLE_ROOM))
+ ((abs(event->x - event_state->prevclickx)) < WM_EVENT_CLICK_TWEAK_THRESHOLD &&
+ (abs(event->y - event_state->prevclicky)) < WM_EVENT_CLICK_TWEAK_THRESHOLD))
{
if ((PIL_check_seconds_timer() - event_state->prevclicktime) * 1000 < U.dbl_click_time) {
return true;
@@ -3829,3 +4334,352 @@ bool WM_event_is_ime_switch(const struct wmEvent *event)
#endif
/** \} */
+
+
+static wmKeyMapItem *wm_kmi_from_event(
+ bContext *C, wmWindowManager *wm,
+ ListBase *handlers, const wmEvent *event)
+{
+ for (wmEventHandler *handler = handlers->first; handler; handler = handler->next) {
+ /* during this loop, ui handlers for nested menus can tag multiple handlers free */
+ if (handler->flag & WM_HANDLER_DO_FREE) {
+ /* pass */
+ }
+ else if (handler_boundbox_test(handler, event)) { /* optional boundbox */
+ if (handler->keymap) {
+ wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap);
+ if (WM_keymap_poll(C, keymap)) {
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (wm_eventmatch(event, kmi)) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
+ return kmi;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Keymap Status
+ *
+ * Show cursor keys in the status bar.
+ * This is done by detecting changes to the state - full keymap lookups are expensive
+ * so only perform this on changing tools, space types, pressing different modifier keys... etc.
+ * \{ */
+
+/** State storage to detect changes between calls to refresh the information. */
+struct CursorKeymapInfo_State {
+ struct {
+ short shift, ctrl, alt, oskey;
+ } modifiers;
+ short space_type;
+ short region_type;
+ /* Never use, just compare memory for changes. */
+ bToolRef tref;
+};
+
+struct CursorKeymapInfo {
+ /* 0: mouse button index
+ * 1: event type (click/press, drag)
+ * 2: text.
+ */
+ char text[3][2][128];
+ wmEvent state_event;
+ struct CursorKeymapInfo_State state;
+};
+
+static void wm_event_cursor_store(
+ struct CursorKeymapInfo_State *state,
+ const wmEvent *event,
+ short space_type, short region_type,
+ const bToolRef *tref)
+{
+ state->modifiers.shift = event->shift;
+ state->modifiers.ctrl = event->ctrl;
+ state->modifiers.alt = event->alt;
+ state->modifiers.oskey = event->oskey;
+ state->space_type = space_type;
+ state->region_type = region_type;
+ state->tref = tref ? *tref : (bToolRef){0};
+}
+
+const char *WM_window_cursor_keymap_status_get(const wmWindow *win, int button_index, int type_index)
+{
+ if (win->cursor_keymap_status != NULL) {
+ struct CursorKeymapInfo *cd = win->cursor_keymap_status;
+ const char *msg = cd->text[button_index][type_index];
+ if (*msg) {
+ return msg;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Similar to #BKE_screen_area_map_find_area_xy and related functions,
+ * use here since the ara is stored in the window manager.
+ */
+ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
+{
+ if (screen->state == SCREENFULL) {
+ return NULL;
+ }
+ ScrArea *sa_statusbar = NULL;
+ for (ScrArea *sa = win->global_areas.areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_STATUSBAR) {
+ sa_statusbar = sa;
+ break;
+ }
+ }
+ return sa_statusbar;
+}
+
+void WM_window_status_area_tag_redraw(wmWindow *win)
+{
+ bScreen *sc = WM_window_get_active_screen(win);
+ ScrArea *sa = WM_window_status_area_find(win, sc);
+ if (sa != NULL) {
+ ED_area_tag_redraw(sa);
+ }
+}
+
+void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *sa_statusbar = WM_window_status_area_find(win, screen);
+ if (sa_statusbar == NULL) {
+ MEM_SAFE_FREE(win->cursor_keymap_status);
+ return;
+ }
+
+ struct CursorKeymapInfo *cd;
+ if (UNLIKELY(win->cursor_keymap_status == NULL)) {
+ win->cursor_keymap_status = MEM_callocN(sizeof(struct CursorKeymapInfo), __func__);
+ }
+ cd = win->cursor_keymap_status;
+
+ /* Detect unchanged state (early exit). */
+ if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) {
+ return;
+ }
+
+ /* Now perform more comprehensive check,
+ * still keep this fast since it happens on mouse-move. */
+ struct CursorKeymapInfo cd_prev = *((struct CursorKeymapInfo *)win->cursor_keymap_status);
+ cd->state_event = *win->eventstate;
+
+ /* Find active region and associated area. */
+ ARegion *ar = screen->active_region;
+ if (ar == NULL) {
+ return;
+ }
+
+ ScrArea *sa = NULL;
+ ED_screen_areas_iter(win, screen, sa_iter) {
+ if (BLI_findindex(&sa_iter->regionbase, ar) != -1) {
+ sa = sa_iter;
+ break;
+ }
+ }
+ if (sa == NULL) {
+ return;
+ }
+
+ /* Keep as-is. */
+ if (ELEM(sa->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) {
+ return;
+ }
+ if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TEMPORARY, RGN_TYPE_HUD)) {
+ return;
+ }
+ /* Fallback to window. */
+ if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
+ ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ }
+
+ /* Detect changes to the state. */
+ {
+ bToolRef *tref = NULL;
+ if ((ar->regiontype == RGN_TYPE_WINDOW) &&
+ ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK))
+ {
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ const bToolKey tkey = {
+ .space_type = sa->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ tref = WM_toolsystem_ref_find(workspace, &tkey);
+ }
+ wm_event_cursor_store(&cd->state, win->eventstate, sa->spacetype, ar->regiontype, tref);
+ if (memcmp(&cd->state, &cd_prev.state, sizeof(cd->state)) == 0) {
+ return;
+ }
+ }
+
+ /* Changed context found, detect changes to keymap and refresh the status bar. */
+ const struct {
+ int button_index;
+ int type_index; /* 0: press or click, 1: drag. */
+ int event_type;
+ int event_value;
+ } event_data[] = {
+ {0, 0, LEFTMOUSE, KM_PRESS},
+ {0, 0, LEFTMOUSE, KM_CLICK},
+ {0, 1, EVT_TWEAK_L, KM_ANY},
+
+ {1, 0, MIDDLEMOUSE, KM_PRESS},
+ {1, 0, MIDDLEMOUSE, KM_CLICK},
+ {1, 1, EVT_TWEAK_M, KM_ANY},
+
+ {2, 0, RIGHTMOUSE, KM_PRESS},
+ {2, 0, RIGHTMOUSE, KM_CLICK},
+ {2, 1, EVT_TWEAK_R, KM_ANY},
+ };
+
+ for (int button_index = 0; button_index < 3; button_index++) {
+ cd->text[button_index][0][0] = '\0';
+ cd->text[button_index][1][0] = '\0';
+ }
+
+ CTX_wm_window_set(C, win);
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+#ifdef USE_WORKSPACE_TOOL
+ wmEventHandler sneaky_handler = {NULL};
+ wm_event_temp_tool_handler_apply(C, sa, ar, &sneaky_handler);
+#endif
+
+ ListBase *handlers[] = {
+ &ar->handlers,
+ &sa->handlers,
+ &win->handlers,
+ };
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ for (int data_index = 0; data_index < ARRAY_SIZE(event_data); data_index++) {
+ const int button_index = event_data[data_index].button_index;
+ const int type_index = event_data[data_index].type_index;
+ if (cd->text[button_index][type_index][0] != 0) {
+ continue;
+ }
+ wmEvent test_event = *win->eventstate;
+ test_event.type = event_data[data_index].event_type;
+ test_event.val = event_data[data_index].event_value;
+ wmKeyMapItem *kmi = NULL;
+ for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
+ kmi = wm_kmi_from_event(C, wm, handlers[handler_index], &test_event);
+ if (kmi) {
+ break;
+ }
+ }
+ if (kmi) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ STRNCPY(cd->text[button_index][type_index], ot ? ot->name : kmi->idname);
+ }
+ }
+
+#ifdef USE_WORKSPACE_TOOL
+ wm_event_temp_tool_handler_clear(C, sa, ar, &sneaky_handler);
+#endif
+
+ if (memcmp(&cd_prev.text, &cd->text, sizeof(cd_prev.text)) != 0) {
+ ED_area_tag_redraw(sa_statusbar);
+ }
+
+ CTX_wm_window_set(C, NULL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modal Keymap Status
+ *
+ * \{ */
+
+bool WM_window_modal_keymap_status_draw(
+ bContext *UNUSED(C), wmWindow *win,
+ uiLayout *layout)
+{
+ wmKeyMap *keymap = NULL;
+ wmOperator *op = NULL;
+ for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
+ if (handler->op) {
+ /* 'handler->keymap' could be checked too, seems not to be used. */
+ wmKeyMap *keymap_test = handler->op->type->modalkeymap;
+ if (keymap_test && keymap_test->modal_items) {
+ keymap = keymap_test;
+ op = handler->op;
+ break;
+ }
+ }
+ }
+ if (keymap == NULL || keymap->modal_items == NULL) {
+ return false;
+ }
+ const EnumPropertyItem *items = keymap->modal_items;
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ for (int i = 0; items[i].identifier; i++) {
+ if (!items[i].identifier[0]) {
+ continue;
+ }
+ if ((keymap->poll_modal_item != NULL) &&
+ (keymap->poll_modal_item(op, items[i].value) == false))
+ {
+ continue;
+ }
+
+ bool show_text = true;
+
+ {
+ /* warning: O(n^2) */
+ wmKeyMapItem *kmi = NULL;
+ for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (kmi->propvalue == items[i].value) {
+ break;
+ }
+ }
+ if (kmi != NULL) {
+ if (kmi->val == KM_RELEASE) {
+ /* Assume release events just disable something which was toggled on. */
+ continue;
+ }
+ int icon_mod[4];
+#ifdef WITH_HEADLESS
+ int icon = 0;
+#else
+ int icon = UI_icon_from_keymap_item(kmi, icon_mod);
+#endif
+ if (icon != 0) {
+ for (int j = 0; j < ARRAY_SIZE(icon_mod) && icon_mod[j]; j++) {
+ uiItemL(row, "", icon_mod[j]);
+ }
+ uiItemL(row, items[i].name, icon);
+ show_text = false;
+ }
+ }
+ }
+ if (show_text) {
+ char buf[UI_MAX_DRAW_STR];
+ int available_len = sizeof(buf);
+ char *p = buf;
+ WM_modalkeymap_operator_items_to_string_buf(
+ op->type, items[i].value, true, UI_MAX_SHORTCUT_STR, &available_len, &p);
+ p -= 1;
+ if (p > buf) {
+ BLI_snprintf(p, available_len, ": %s", items[i].name);
+ uiItemL(row, buf, 0);
+ }
+ }
+ }
+ return true;
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index effd1c89077..73254678c6d 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -70,6 +70,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_appdir.h"
#include "BKE_autoexec.h"
@@ -77,9 +78,7 @@
#include "BKE_blendfile.h"
#include "BKE_blender_undo.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
-#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
@@ -87,6 +86,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_undo_system.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -122,8 +122,13 @@
#include "BPY_extern.h"
#endif
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+
#include "wm.h"
#include "wm_files.h"
#include "wm_window.h"
@@ -162,7 +167,7 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
CTX_wm_window_set(C, win); /* needed by operator close callbacks */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
- ED_screen_exit(C, win, win->screen);
+ ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
}
@@ -177,36 +182,26 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
CTX_wm_menu_set(C, NULL);
ED_editors_exit(C);
-
- /* just had return; here from r12991, this code could just get removed?*/
-#if 0
- if (wm == NULL) return;
- if (G.fileflags & G_FILE_NO_UI) return;
-
- /* we take apart the used screens from non-active window */
- for (win = wm->windows.first; win; win = win->next) {
- BLI_strncpy(win->screenname, win->screen->id.name, MAX_ID_NAME);
- if (win != wm->winactive) {
- BLI_remlink(&G_MAIN->screen, win->screen);
- //BLI_addtail(screenbase, win->screen);
- }
- }
-#endif
}
-static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
+static void wm_window_substitute_old(wmWindowManager *oldwm, wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
{
win->ghostwin = oldwin->ghostwin;
- win->multisamples = oldwin->multisamples;
+ win->gpuctx = oldwin->gpuctx;
win->active = oldwin->active;
- if (win->active)
+ if (win->active) {
wm->winactive = win;
+ }
+ if (oldwm->windrawable == oldwin) {
+ oldwm->windrawable = NULL;
+ wm->windrawable = win;
+ }
if (!G.background) /* file loading in background mode still calls this */
GHOST_SetWindowUserData(win->ghostwin, win); /* pointer back */
oldwin->ghostwin = NULL;
- oldwin->multisamples = 0;
+ oldwin->gpuctx = NULL;
win->eventstate = oldwin->eventstate;
oldwin->eventstate = NULL;
@@ -218,102 +213,132 @@ static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWi
win->posy = oldwin->posy;
}
-/* match old WM with new, 4 cases:
- * 1- no current wm, no read wm: make new default
- * 2- no current wm, but read wm: that's OK, do nothing
- * 3- current wm, but not in file: try match screen names
- * 4- current wm, and wm in file: try match ghostwin
- */
-
-static void wm_window_match_do(Main *bmain, bContext *C, ListBase *oldwmlist)
+static void wm_window_match_keep_current_wm(
+ const bContext *C, ListBase *current_wm_list,
+ const bool load_ui,
+ ListBase *r_new_wm_list)
{
- wmWindowManager *oldwm, *wm;
- wmWindow *oldwin, *win;
-
- /* cases 1 and 2 */
- if (BLI_listbase_is_empty(oldwmlist)) {
- if (bmain->wm.first) {
- /* nothing todo */
- }
- else {
- wm_add_default(C);
- }
- }
- else {
- /* cases 3 and 4 */
-
- /* we've read file without wm..., keep current one entirely alive */
- if (BLI_listbase_is_empty(&bmain->wm)) {
- bScreen *screen = NULL;
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = current_wm_list->first;
+ bScreen *screen = NULL;
- /* when loading without UI, no matching needed */
- if (!(G.fileflags & G_FILE_NO_UI) && (screen = CTX_wm_screen(C))) {
+ /* match oldwm to new dbase, only old files */
+ wm->initialized &= ~WM_WINDOW_IS_INITIALIZED;
- /* match oldwm to new dbase, only old files */
- for (wm = oldwmlist->first; wm; wm = wm->id.next) {
+ /* when loading without UI, no matching needed */
+ if (load_ui && (screen = CTX_wm_screen(C))) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace;
- for (win = wm->windows.first; win; win = win->next) {
- /* all windows get active screen from file */
- if (screen->winid == 0)
- win->screen = screen;
- else
- win->screen = ED_screen_duplicate(bmain, win, screen);
+ BKE_workspace_layout_find_global(bmain, screen, &workspace);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ win->scene = CTX_data_scene(C);
- BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
- win->screen->winid = win->winid;
- }
- }
+ /* all windows get active screen from file */
+ if (screen->winid == 0) {
+ WM_window_set_active_screen(win, workspace, screen);
}
+ else {
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
- bmain->wm = *oldwmlist;
+ WM_window_set_active_layout(win, workspace, layout_new);
+ }
- /* screens were read from file! */
- ED_screens_initialize(bmain, bmain->wm.first);
+ bScreen *win_screen = WM_window_get_active_screen(win);
+ win_screen->winid = win->winid;
}
- else {
- bool has_match = false;
+ }
+
+ *r_new_wm_list = *current_wm_list;
+}
- /* what if old was 3, and loaded 1? */
- /* this code could move to setup_appdata */
- oldwm = oldwmlist->first;
- wm = bmain->wm.first;
+static void wm_window_match_replace_by_file_wm(
+ bContext *C, ListBase *current_wm_list, ListBase *readfile_wm_list,
+ ListBase *r_new_wm_list)
+{
+ wmWindowManager *oldwm = current_wm_list->first;
+ wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */
+ bool has_match = false;
- /* preserve key configurations in new wm, to preserve their keymaps */
- wm->keyconfigs = oldwm->keyconfigs;
- wm->addonconf = oldwm->addonconf;
- wm->defaultconf = oldwm->defaultconf;
- wm->userconf = oldwm->userconf;
+ /* this code could move to setup_appdata */
- BLI_listbase_clear(&oldwm->keyconfigs);
- oldwm->addonconf = NULL;
- oldwm->defaultconf = NULL;
- oldwm->userconf = NULL;
+ /* preserve key configurations in new wm, to preserve their keymaps */
+ wm->keyconfigs = oldwm->keyconfigs;
+ wm->addonconf = oldwm->addonconf;
+ wm->defaultconf = oldwm->defaultconf;
+ wm->userconf = oldwm->userconf;
- /* ensure making new keymaps and set space types */
- wm->initialized = 0;
- wm->winactive = NULL;
+ BLI_listbase_clear(&oldwm->keyconfigs);
+ oldwm->addonconf = NULL;
+ oldwm->defaultconf = NULL;
+ oldwm->userconf = NULL;
- /* only first wm in list has ghostwins */
- for (win = wm->windows.first; win; win = win->next) {
- for (oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
+ /* ensure making new keymaps and set space types */
+ wm->initialized = 0;
+ wm->winactive = NULL;
- if (oldwin->winid == win->winid) {
- has_match = true;
+ /* Clearing drawable of before deleting any context
+ * to avoid clearing the wrong wm. */
+ wm_window_clear_drawable(oldwm);
- wm_window_substitute_old(wm, oldwin, win);
- }
- }
+ /* only first wm in list has ghostwins */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ for (wmWindow *oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
+ if (oldwin->winid == win->winid) {
+ has_match = true;
+
+ wm_window_substitute_old(oldwm, wm, oldwin, win);
}
+ }
+ }
+ /* make sure at least one window is kept open so we don't lose the context, check T42303 */
+ if (!has_match) {
+ wm_window_substitute_old(oldwm, wm, oldwm->windows.first, wm->windows.first);
+ }
- /* make sure at least one window is kept open so we don't lose the context, check T42303 */
- if (!has_match) {
- oldwin = oldwm->windows.first;
- win = wm->windows.first;
+ wm_close_and_free_all(C, current_wm_list);
- wm_window_substitute_old(wm, oldwin, win);
- }
+ *r_new_wm_list = *readfile_wm_list;
+}
- wm_close_and_free_all(C, oldwmlist);
+/**
+ * Match old WM with new, 4 cases:
+ * 1) No current WM, no WM in file: Make new default.
+ * 2) No current WM, but WM in file: Keep current WM, do nothing else.
+ * 3) Current WM, but not in file: Keep current WM, update windows with screens from file.
+ * 4) Current WM, and WM in file: Try to keep current GHOST windows, use WM from file.
+ *
+ * \param r_new_wm_list: Return argument for the wm list to be used from now on.
+ */
+static void wm_window_match_do(
+ bContext *C,
+ ListBase *current_wm_list, ListBase *readfile_wm_list,
+ ListBase *r_new_wm_list)
+{
+ if (BLI_listbase_is_empty(current_wm_list)) {
+ /* case 1 */
+ if (BLI_listbase_is_empty(readfile_wm_list)) {
+ Main *bmain = CTX_data_main(C);
+ /* Neither current, no newly read file have a WM -> add the default one. */
+ wm_add_default(bmain, C);
+ *r_new_wm_list = bmain->wm;
+ }
+ /* case 2 */
+ else {
+ *r_new_wm_list = *readfile_wm_list;
+ }
+ }
+ else {
+ /* case 3 */
+ if (BLI_listbase_is_empty(readfile_wm_list)) {
+ /* We've read file without wm, keep current one entirely alive.
+ * Happens when reading pre 2.5 files (no WM back then) */
+ wm_window_match_keep_current_wm(C, current_wm_list, (G.fileflags & G_FILE_NO_UI) == 0, r_new_wm_list);
+ }
+ /* case 4 */
+ else {
+ wm_window_match_replace_by_file_wm(C, current_wm_list, readfile_wm_list, r_new_wm_list);
}
}
}
@@ -450,9 +475,9 @@ void wm_file_read_report(bContext *C, Main *bmain)
* Logic shared between #WM_file_read & #wm_homefile_read,
* updates to make after reading a file.
*/
-static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool use_userdef)
+static void wm_file_read_post(
+ bContext *C, const bool is_startup_file, const bool is_factory_startup, const bool reset_app_template)
{
- Main *bmain = CTX_data_main(C);
bool addons_loaded = false;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -463,14 +488,17 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
CTX_wm_window_set(C, wm->windows.first);
+ Main *bmain = CTX_data_main(C);
+ DEG_on_visible_update(bmain, true);
+ wm_event_do_depsgraph(C);
+
ED_editors_init(C);
- DAG_on_visible_update(bmain, true);
#ifdef WITH_PYTHON
if (is_startup_file) {
/* possible python hasn't been initialized */
if (CTX_py_init_get(C)) {
- if (use_userdef) {
+ if (reset_app_template) {
/* Only run when we have a template path found. */
if (BKE_appdir_app_template_any()) {
BPY_execute_string(
@@ -492,7 +520,7 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
addons_loaded = true;
}
#else
- UNUSED_VARS(use_userdef);
+ UNUSED_VARS(is_startup_file, reset_app_template);
#endif /* WITH_PYTHON */
WM_operatortype_last_properties_clear_all();
@@ -500,17 +528,15 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
/* important to do before NULL'ing the context */
BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
-
- /* Would otherwise be handled by event loop.
- *
- * Disabled for startup file, since it causes problems when PyDrivers are used in the startup file.
- * While its possible state of startup file may be wrong,
- * in this case users nearly always load a file to replace the startup file. */
- if (G.background && (is_startup_file == false)) {
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
+ if (is_factory_startup) {
+ BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST);
}
+#if 1
WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
+#else
+ WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ);
+#endif
/* report any errors.
* currently disabled if addons aren't yet loaded */
@@ -534,6 +560,9 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
* a blend file and do anything since the screen
* won't be set to a valid value again */
CTX_wm_window_set(C, NULL); /* exits queues */
+
+ /* Ensure tools are registered. */
+ WM_toolsystem_init(C);
}
}
@@ -594,7 +623,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
/* match the read WM with current WM */
- wm_window_match_do(bmain, C, &wmbase);
+ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
WM_check(C); /* opens window(s), checks keymaps */
if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
@@ -608,10 +637,14 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
}
- wm_file_read_post(C, false, false);
+ wm_file_read_post(C, false, false, false);
success = true;
}
+#if 0
+ else if (retval == BKE_READ_EXOTIC_OK_OTHER)
+ BKE_undo_write(C, "Import file");
+#endif
else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unable to open the file"));
@@ -673,6 +706,25 @@ const char *WM_init_state_app_template_get(void)
return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL;
}
+
+static bool wm_app_template_has_userpref(const char *app_template)
+{
+ /* Test if app template provides a userpref.blend. If not, we will
+ * share user preferences with the rest of Blender. */
+ if (!app_template && app_template[0]) {
+ return false;
+ }
+
+ char app_template_path[FILE_MAX];
+ if (!BKE_appdir_app_template_id_search(app_template, app_template_path, sizeof(app_template_path))) {
+ return false;
+ }
+
+ char userpref_path[FILE_MAX];
+ BLI_path_join(userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL);
+ return BLI_exists(userpref_path);
+}
+
/**
* Called on startup, (context entirely filled with NULLs)
* or called for 'New File' both startup.blend and userpref.blend are checked.
@@ -688,12 +740,14 @@ const char *WM_init_state_app_template_get(void)
void wm_homefile_read(
bContext *C, ReportList *reports,
bool use_factory_settings, bool use_empty_data, bool use_userdef,
- const char *filepath_startup_override, const char *app_template_override)
+ const char *filepath_startup_override, const char *app_template_override,
+ bool *r_is_factory_startup)
{
Main *bmain = G_MAIN; /* Context does not always have valid main pointer here... */
ListBase wmbase;
bool success = false;
+ bool filepath_startup_is_factory = true;
char filepath_startup[FILE_MAX];
char filepath_userdef[FILE_MAX];
@@ -714,6 +768,9 @@ void wm_homefile_read(
bool read_userdef_from_memory = false;
eBLOReadSkip skip_flags = use_userdef ? 0 : BLO_READ_SKIP_USERDEF;
+ /* True if we load startup.blend from memory or use app-template startup.blend which the user hasn't saved. */
+ bool is_factory_startup = true;
+
/* options exclude eachother */
BLI_assert((use_factory_settings && filepath_startup_override) == 0);
@@ -739,6 +796,7 @@ void wm_homefile_read(
if (!use_factory_settings) {
if (cfgdir) {
BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
+ filepath_startup_is_factory = false;
if (use_userdef) {
BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
}
@@ -749,6 +807,7 @@ void wm_homefile_read(
if (filepath_startup_override) {
BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX);
+ filepath_startup_is_factory = false;
}
}
@@ -767,6 +826,8 @@ void wm_homefile_read(
}
const char *app_template = NULL;
+ bool update_defaults = false;
+ bool reset_app_template = false;
if (filepath_startup_override != NULL) {
/* pass */
@@ -779,8 +840,18 @@ void wm_homefile_read(
app_template = U.app_template;
}
+ if ((!app_template && U.app_template[0]) ||
+ (app_template && !STREQ(app_template, U.app_template)))
+ {
+ /* Always load UI when switching to another template. */
+ G.fileflags &= ~G_FILE_NO_UI;
+ reset_app_template = true;
+ }
+
if ((app_template != NULL) && (app_template[0] != '\0')) {
- if (!BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system))) {
+ if (!BKE_appdir_app_template_id_search(
+ app_template, app_template_system, sizeof(app_template_system)))
+ {
/* Can safely continue with code below, just warn it's not found. */
BKE_reportf(reports, RPT_WARNING, "Application Template '%s' not found.", app_template);
}
@@ -792,6 +863,7 @@ void wm_homefile_read(
if (!use_factory_settings) {
BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE, NULL);
+ filepath_startup_is_factory = false;
if (BLI_access(filepath_startup, R_OK) != 0) {
filepath_startup[0] = '\0';
}
@@ -802,6 +874,10 @@ void wm_homefile_read(
if (filepath_startup[0] == '\0') {
BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE, NULL);
+ filepath_startup_is_factory = true;
+
+ /* Update defaults only for system templates. */
+ update_defaults = true;
}
}
@@ -820,6 +896,12 @@ void wm_homefile_read(
printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", filepath_startup);
success = false;
}
+ if (success) {
+ if (update_defaults) {
+ BLO_update_defaults_startup_blend(CTX_data_main(C), app_template);
+ }
+ is_factory_startup = filepath_startup_is_factory;
+ }
}
if (success == false && filepath_startup_override && reports) {
@@ -900,27 +982,34 @@ void wm_homefile_read(
if (use_userdef) {
/* check userdef before open window, keymaps etc */
wm_init_userdef(bmain, read_userdef_from_memory);
+ reset_app_template = true;
}
/* match the read WM with current WM */
- wm_window_match_do(bmain, C, &wmbase);
+ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
+
+ if (use_factory_settings) {
+ /* Clear keymaps because the current default keymap may have been initialized from user preferences,
+ * which have been reset. */
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ if (wm->defaultconf) {
+ wm->defaultconf->flag &= ~KEYCONF_INIT_DEFAULT;
+ }
+ }
+ }
+
WM_check(C); /* opens window(s), checks keymaps */
bmain->name[0] = '\0';
- if (use_userdef) {
- /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
- if (!G.background) {
- GPU_default_lights();
- }
- }
-
/* start with save preference untitled.blend */
G.save_over = 0;
- /* disable auto-play in startup.blend... */
- G.fileflags &= ~G_FILE_AUTOPLAY;
- wm_file_read_post(C, true, use_userdef);
+ wm_file_read_post(C, true, is_factory_startup, reset_app_template);
+
+ if (r_is_factory_startup) {
+ *r_is_factory_startup = is_factory_startup;
+ }
}
/** \name WM History File API
@@ -1049,7 +1138,7 @@ static void wm_history_file_update(void)
/* screen can be NULL */
-static ImBuf *blend_file_thumb(Main *bmain, Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
+static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
{
/* will be scaled down, but gives some nice oversampling */
ImBuf *ibuf;
@@ -1084,19 +1173,21 @@ static ImBuf *blend_file_thumb(Main *bmain, Scene *scene, bScreen *screen, Blend
}
/* gets scaled to BLEN_THUMB_SIZE */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(
- bmain, scene, scene->camera,
+ depsgraph, scene, OB_SOLID, scene->camera,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, V3D_OFSDRAW_NONE, OB_SOLID, R_ALPHAPREMUL, 0, NULL,
- NULL, NULL, err_out);
+ IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
+ NULL, err_out);
}
else {
ibuf = ED_view3d_draw_offscreen_imbuf(
- bmain, scene, v3d, ar,
+ depsgraph, scene, OB_SOLID, v3d, ar,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
- NULL, NULL, err_out);
+ NULL, err_out);
}
if (ibuf) {
@@ -1187,10 +1278,10 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
/* blend file thumbnail */
/* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */
- /* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */
+ /* Main now can store a .blend thumbnail, useful for background mode or thumbnail customization. */
main_thumb = thumb = bmain->blen_thumb;
if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
- ibuf_thumb = blend_file_thumb(bmain, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
+ ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
}
/* operator now handles overwrite checks */
@@ -1226,7 +1317,6 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
}
SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
- SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_AUTOPLAY, G_FILE_AUTOPLAY);
/* prevent background mode scripts from clobbering history */
if (do_history) {
@@ -1335,7 +1425,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
}
else {
/* save as regular blend file */
- int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+ int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
ED_editors_flush_edits(C, false);
@@ -1451,7 +1541,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_PRE);
/* check current window and close it if temp */
- if (win && win->screen->temp)
+ if (win && WM_window_is_temp_screen(win))
wm_window_close(C, wm, win);
/* update keymaps in user preferences */
@@ -1459,12 +1549,12 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL);
- printf("trying to save homefile at %s ", filepath);
+ printf("Writing homefile: '%s' ", filepath);
ED_editors_flush_edits(C, false);
/* force save as regular blend file */
- fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+ fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
if (BLO_write_file(bmain, filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
printf("fail\n");
@@ -1484,7 +1574,7 @@ void WM_OT_save_homefile(wmOperatorType *ot)
{
ot->name = "Save Startup File";
ot->idname = "WM_OT_save_homefile";
- ot->description = "Make the current file the default .blend file, includes preferences";
+ ot->description = "Make the current file the default .blend file";
ot->invoke = WM_operator_confirm;
ot->exec = wm_homefile_write_exec;
@@ -1538,6 +1628,7 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op)
char filepath[FILE_MAX];
const char *cfgdir;
bool ok = true;
+ bool use_template_userpref = wm_app_template_has_userpref(U.app_template);
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
@@ -1545,9 +1636,9 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op)
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
bool ok_write;
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
- printf("trying to save userpref at %s ", filepath);
- if (U.app_template[0]) {
+ printf("Writing userprefs: '%s' ", filepath);
+ if (use_template_userpref) {
ok_write = BKE_blendfile_userdef_write_app_template(filepath, op->reports);
}
else {
@@ -1566,11 +1657,12 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path");
}
- if (U.app_template[0]) {
+ if (use_template_userpref) {
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
/* Also save app-template prefs */
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
- printf("trying to save app-template userpref at %s ", filepath);
+
+ printf("Writing userprefs app-template: '%s' ", filepath);
if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) {
printf("ok\n");
}
@@ -1590,7 +1682,7 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op)
void WM_OT_save_userpref(wmOperatorType *ot)
{
- ot->name = "Save User Settings";
+ ot->name = "Save Preferences";
ot->idname = "WM_OT_save_userpref";
ot->description = "Save user preferences separately, overrides startup file preferences";
@@ -1659,8 +1751,9 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
app_template = app_template_buf;
- /* Always load preferences when switching templates. */
- use_userdef = true;
+ /* Always load preferences when switching templates with own preferences. */
+ use_userdef = wm_app_template_has_userpref(app_template) ||
+ wm_app_template_has_userpref(U.app_template);
/* Turn override off, since we're explicitly loading a different app-template. */
WM_init_state_app_template_set(NULL);
@@ -1670,13 +1763,29 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
app_template = WM_init_state_app_template_get();
}
- wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, use_userdef, filepath, app_template);
+ wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, use_userdef, filepath, app_template, NULL);
if (use_splash) {
WM_init_splash(C);
}
return OPERATOR_FINISHED;
}
+static int wm_homefile_read_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+ /* Draw menu which includes default startup and application templates. */
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("New File"), ICON_FILE_NEW);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ MenuType *mt = WM_menutype_find("TOPBAR_MT_file_new", false);
+ if (mt) {
+ UI_menutype_draw(C, mt, layout);
+ }
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
void WM_OT_read_homefile(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1684,7 +1793,7 @@ void WM_OT_read_homefile(wmOperatorType *ot)
ot->idname = "WM_OT_read_homefile";
ot->description = "Open the default file (doesn't save the current file)";
- ot->invoke = WM_operator_confirm;
+ ot->invoke = wm_homefile_read_invoke;
ot->exec = wm_homefile_read_exec;
prop = RNA_def_string_file_path(ot->srna, "filepath", NULL,
@@ -2259,3 +2368,121 @@ void WM_OT_save_mainfile(wmOperatorType *ot)
}
/** \} */
+
+/** \name Auto-execution of scripts warning popup
+ *
+ * \{ */
+
+static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *UNUSED(arg))
+{
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
+}
+
+static void wm_block_autorun_warning_allow(bContext *C, void *arg_block, void *UNUSED(arg))
+{
+ PointerRNA props_ptr;
+ wmWindow *win = CTX_wm_window(C);
+
+ UI_popup_block_close(C, win, arg_block);
+
+ /* Save user preferences for permanent execution. */
+ if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
+ WM_operator_name_call(C, "WM_OT_save_userpref", WM_OP_EXEC_DEFAULT, NULL);
+ }
+
+ /* Load file again with scripts enabled. */
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_revert_mainfile", false);
+
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_boolean_set(&props_ptr, "use_scripts", true);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr);
+ WM_operator_properties_free(&props_ptr);
+}
+
+/* Build the autorun warning dialog UI */
+static uiBlock *block_create_autorun_warning(struct bContext *C, struct ARegion *ar, void *UNUSED(arg1))
+{
+ uiStyle *style = UI_style_get();
+ uiBlock *block = UI_block_begin(C, ar, "autorun_warning_popup", UI_EMBOSS);
+
+ UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ uiLayout *layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.widget_unit * 24, U.widget_unit * 6, 0, style);
+
+ /* Text and some vertical space */
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemL(col, IFACE_("For security reasons, automatic execution of Python scripts in this file was disabled:"), ICON_ERROR);
+ uiLayout *sub = uiLayoutRow(col, true);
+ uiLayoutSetRedAlert(sub, true);
+ uiItemL(sub, G.autoexec_fail, ICON_BLANK1);
+ uiItemL(col, IFACE_("This may lead to unexpected behavior."), ICON_BLANK1);
+
+ uiItemS(layout);
+
+ PointerRNA userpref_ptr;
+ RNA_pointer_create(NULL, &RNA_UserPreferencesSystem, &U, &userpref_ptr);
+ uiItemR(layout, &userpref_ptr, "use_scripts_auto_execute", 0, IFACE_("Permanently allow execution of scripts"), ICON_NONE);
+
+ uiItemS(layout);
+
+ /* Buttons */
+ uiBut *but;
+ uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
+ col = uiLayoutColumn(split, false);
+
+ /* Allow reload if we have a saved file. */
+ if (G.relbase_valid) {
+ but = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, ICON_NONE, IFACE_("Allow Execution"), 0, 0, 50, UI_UNIT_Y,
+ NULL, 0, 0, 0, 0, TIP_("Reload file with execution of Python scripts enabled"));
+ UI_but_func_set(but, wm_block_autorun_warning_allow, block, NULL);
+ }
+ else {
+ uiItemS(col);
+ }
+
+ /* empty space between buttons */
+ col = uiLayoutColumn(split, false);
+ uiItemS(col);
+
+ col = uiLayoutColumn(split, 1);
+ but = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, ICON_NONE, IFACE_("Ignore"), 0, 0, 50, UI_UNIT_Y,
+ NULL, 0, 0, 0, 0, TIP_("Continue using file without Python scripts"));
+ UI_but_func_set(but, wm_block_autorun_warning_ignore, block, NULL);
+
+ UI_block_bounds_set_centered(block, 10);
+
+ return block;
+}
+
+void wm_test_autorun_warning(bContext *C)
+{
+ /* Test if any auto-execution of scripts failed. */
+ if ((G.f & G_SCRIPT_AUTOEXEC_FAIL) == 0) {
+ return;
+ }
+
+ /* Only show the warning once. */
+ if (G.f & G_SCRIPT_AUTOEXEC_FAIL_QUIET) {
+ return;
+ }
+
+ G.f |= G_SCRIPT_AUTOEXEC_FAIL_QUIET;
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = (wm->winactive) ? wm->winactive : wm->windows.first;
+
+ if (win) {
+ wmWindow *prevwin = CTX_wm_window(C);
+ CTX_wm_window_set(C, win);
+ UI_popup_block_invoke(C, block_create_autorun_warning, NULL);
+ CTX_wm_window_set(C, prevwin);
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index d8cc5b37b7d..0b1ba6cf32d 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -59,23 +59,24 @@
#include "BLO_readfile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
-#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_idcode.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "IMB_colormanagement.h"
+#include "ED_datafiles.h"
#include "ED_screen.h"
-#include "GPU_material.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
@@ -105,11 +106,7 @@ static bool wm_link_append_poll(bContext *C)
static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- return WM_operator_call_notest(C, op);
- }
- else {
- /* XXX TODO solve where to get last linked library from */
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
if (G.lib[0] != '\0') {
RNA_string_set(op->ptr, "filepath", G.lib);
}
@@ -119,9 +116,10 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
BLI_parent_dir(path);
RNA_string_set(op->ptr, "filepath", path);
}
- WM_event_add_fileselect(C, op);
- return OPERATOR_RUNNING_MODAL;
}
+
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
}
static short wm_link_append_flag(wmOperator *op)
@@ -131,13 +129,13 @@ static short wm_link_append_flag(wmOperator *op)
if (RNA_boolean_get(op->ptr, "autoselect"))
flag |= FILE_AUTOSELECT;
- if (RNA_boolean_get(op->ptr, "active_layer"))
- flag |= FILE_ACTIVELAY;
+ if (RNA_boolean_get(op->ptr, "active_collection"))
+ flag |= FILE_ACTIVE_COLLECTION;
if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop))
flag |= FILE_RELPATH;
if (RNA_boolean_get(op->ptr, "link"))
flag |= FILE_LINK;
- if (RNA_boolean_get(op->ptr, "instance_groups"))
+ if (RNA_boolean_get(op->ptr, "instance_collections"))
flag |= FILE_GROUP_INSTANCE;
return flag;
@@ -211,7 +209,8 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add(
return item;
}
-static void wm_link_do(WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d)
+static void wm_link_do(
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Main *mainl;
BlendHandle *bh;
@@ -227,7 +226,12 @@ static void wm_link_do(WMLinkAppendData *lapp_data, ReportList *reports, Main *b
for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) {
char *libname = liblink->link;
- bh = BLO_blendhandle_from_file(libname, reports);
+ if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
+ bh = BLO_blendhandle_from_memory(datatoc_startup_blend, datatoc_startup_blend_size);
+ }
+ else {
+ bh = BLO_blendhandle_from_file(libname, reports);
+ }
if (bh == NULL) {
/* Unlikely since we just browsed it, but possible
@@ -258,7 +262,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data, ReportList *reports, Main *b
continue;
}
- new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d);
+ new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, bmain, scene, view_layer);
if (new_id) {
/* If the link is successful, clear item's libs 'todo' flags.
@@ -268,15 +272,50 @@ static void wm_link_do(WMLinkAppendData *lapp_data, ReportList *reports, Main *b
}
}
- BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer);
BLO_blendhandle_close(bh);
}
}
+/**
+ * Check if an item defined by \a name and \a group can be appended/linked.
+ *
+ * \param reports: Optionally report an error when an item can't be appended/linked.
+ */
+static bool wm_link_append_item_poll(
+ ReportList *reports, const char *path, const char *group, const char *name, const bool do_append)
+{
+ short idcode;
+
+ if (!group || !name) {
+ printf("skipping %s\n", path);
+ return false;
+ }
+
+ idcode = BKE_idcode_from_name(group);
+
+ /* XXX For now, we do a nasty exception for workspace, forbid linking them.
+ * Not nice, ultimately should be solved! */
+ if (!BKE_idcode_is_linkable(idcode) && (do_append || idcode != ID_WS)) {
+ if (reports) {
+ if (do_append) {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Can't append data-block '%s' of type '%s'", name, group);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Can't link data-block '%s' of type '%s'", name, group);
+ }
+ }
+ return false;
+ }
+
+ return true;
+}
+
static int wm_link_append_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
PropertyRNA *prop;
WMLinkAppendData *lapp_data;
char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
@@ -319,6 +358,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
}
short flag = wm_link_append_flag(op);
+ const bool do_append = (flag & FILE_LINK) == 0;
/* sanity checks for flag */
if (scene && scene->id.lib) {
@@ -332,8 +372,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* from here down, no error returns */
- if (scene && RNA_boolean_get(op->ptr, "autoselect")) {
- BKE_scene_base_deselect_all(scene);
+ if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) {
+ BKE_view_layer_base_deselect_all(view_layer);
}
/* tag everything, all untagged data can be made local
@@ -356,7 +396,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_join_dirfile(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, libname, &group, &name)) {
- if (!group || !name) {
+ if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) {
continue;
}
@@ -377,8 +417,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (BLO_library_path_explode(path, libname, &group, &name)) {
WMLinkAppendDataItem *item;
- if (!group || !name) {
- printf("skipping %s\n", path);
+
+ if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) {
continue;
}
@@ -409,7 +449,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* XXX We'd need re-entrant locking on Main for this to work... */
/* BKE_main_lock(bmain); */
- wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C));
+ wm_link_do(lapp_data, op->reports, bmain, scene, view_layer);
/* BKE_main_unlock(bmain); */
@@ -418,7 +458,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
IMB_colormanagement_check_file_config(bmain);
/* append, rather than linking */
- if ((flag & FILE_LINK) == 0) {
+ if (do_append) {
const bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive");
@@ -449,13 +489,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
* link into other scenes from this blend file */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- /* recreate dependency graph to include new objects */
- if (scene) {
- DAG_scene_relations_rebuild(bmain, scene);
- }
+ /* TODO(sergey): Use proper flag for tagging here. */
+
+ /* TODO (dalai): Temporary solution!
+ * Ideally we only need to tag the new objects themselves, not the scene. This way we'll avoid flush of
+ * collection properties to all objects and limit update to the particular object only.
+ * But afraid first we need to change collection evaluation in DEG according to depsgraph manifesto.
+ */
+ DEG_id_tag_update(&scene->id, 0);
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free(bmain);
+ /* recreate dependency graph to include new objects */
+ DEG_relations_tag_update(bmain);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, root, FILE_MAX);
@@ -477,11 +521,11 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
prop = RNA_def_boolean(ot->srna, "autoselect", true,
"Select", "Select new objects");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "active_layer", true,
- "Active Layer", "Put new objects on the active layer");
+ prop = RNA_def_boolean(ot->srna, "active_collection", true,
+ "Active Collection", "Put new objects on the active collection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
- "Instance Groups", "Create Dupli-Group instances for each group");
+ prop = RNA_def_boolean(ot->srna, "instance_collections", is_link,
+ "Instance Collections", "Create instances for collections, rather than adding them directly to the scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -558,7 +602,7 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN
}
static void lib_relocate_do(
- Main *bmain, Scene *scene,
+ Main *bmain,
Library *library, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload)
{
ListBase *lbarray[MAX_LIBARRAY];
@@ -748,10 +792,7 @@ static void lib_relocate_do(
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
/* recreate dependency graph to include new objects */
- DAG_scene_relations_rebuild(bmain, scene);
-
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free(bmain);
+ DEG_relations_tag_update(bmain);
}
void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
@@ -771,7 +812,7 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
wm_link_append_data_library_add(lapp_data, lib->filepath);
- lib_relocate_do(CTX_data_main(C), CTX_data_scene(C), lib, lapp_data, reports, true);
+ lib_relocate_do(CTX_data_main(C), lib, lapp_data, reports, true);
wm_link_append_data_free(lapp_data);
@@ -788,7 +829,6 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
if (lib) {
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
PropertyRNA *prop;
WMLinkAppendData *lapp_data;
@@ -882,7 +922,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT;
}
- lib_relocate_do(bmain, scene, lib, lapp_data, op->reports, do_reload);
+ lib_relocate_do(bmain, lib, lapp_data, op->reports, do_reload);
wm_link_append_data_free(lapp_data);
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index a0a38c5bc3f..70150e40142 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -45,15 +45,14 @@
#include "BKE_context.h"
-
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
-#include "wm_subwindow.h"
#include "wm_draw.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
#include "BIF_glutil.h"
@@ -64,40 +63,37 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture");
wmWindow *window = CTX_wm_window(C);
ARegion *ar = CTX_wm_region(C);
- int sx, sy;
BLI_addtail(&window->gesture, gesture);
gesture->type = type;
gesture->event_type = event->type;
- gesture->swinid = ar->swinid; /* means only in area-region context! */
+ gesture->winrct = ar->winrct;
gesture->userdata_free = true; /* Free if userdata is set. */
gesture->modal_state = GESTURE_MODAL_NOP;
- wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
-
if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK,
WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE))
{
rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
gesture->customdata = rect;
- rect->xmin = event->x - sx;
- rect->ymin = event->y - sy;
+ rect->xmin = event->x - gesture->winrct.xmin;
+ rect->ymin = event->y - gesture->winrct.ymin;
if (type == WM_GESTURE_CIRCLE) {
/* caller is responsible for initializing 'xmax' to radius. */
}
else {
- rect->xmax = event->x - sx;
- rect->ymax = event->y - sy;
+ rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymax = event->y - gesture->winrct.ymin;
}
}
else if (ELEM(type, WM_GESTURE_LINES, WM_GESTURE_LASSO)) {
short *lasso;
gesture->points_alloc = 1024;
gesture->customdata = lasso = MEM_mallocN(sizeof(short[2]) * gesture->points_alloc, "lasso points");
- lasso[0] = event->x - sx;
- lasso[1] = event->y - sy;
+ lasso[0] = event->x - gesture->winrct.xmin;
+ lasso[1] = event->y - gesture->winrct.ymin;
gesture->points = 1;
}
@@ -134,7 +130,8 @@ int wm_gesture_evaluate(wmGesture *gesture)
rcti *rect = gesture->customdata;
int dx = BLI_rcti_size_x(rect);
int dy = BLI_rcti_size_y(rect);
- if (abs(dx) + abs(dy) > U.tweak_threshold) {
+ float tweak_threshold = U.tweak_threshold * U.dpi_fac;
+ if (abs(dx) + abs(dy) > tweak_threshold) {
int theta = round_fl_to_int(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
int val = EVT_GESTURE_W;
@@ -166,69 +163,99 @@ int wm_gesture_evaluate(wmGesture *gesture)
/* ******************* gesture draw ******************* */
-static void wm_gesture_draw_rect(wmGesture *gt)
+static void wm_gesture_draw_line(wmGesture *gt)
{
rcti *rect = (rcti *)gt->customdata;
- glEnable(GL_BLEND);
- glColor4f(1.0, 1.0, 1.0, 0.05);
- glBegin(GL_QUADS);
- glVertex2s(rect->xmax, rect->ymin);
- glVertex2s(rect->xmax, rect->ymax);
- glVertex2s(rect->xmin, rect->ymax);
- glVertex2s(rect->xmin, rect->ymin);
- glEnd();
- glDisable(GL_BLEND);
+ uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xCCCC);
- sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x3333);
- sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 8.0f);
+
+ float xmin = (float)rect->xmin;
+ float ymin = (float)rect->ymin;
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(shdr_pos, xmin, ymin);
+ immVertex2f(shdr_pos, (float)rect->xmax, (float)rect->ymax);
+ immEnd();
+
+ immUnbindProgram();
}
-static void wm_gesture_draw_line(wmGesture *gt)
+static void wm_gesture_draw_rect(wmGesture *gt)
{
rcti *rect = (rcti *)gt->customdata;
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xAAAA);
- sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x5555);
- sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+
+ glEnable(GL_BLEND);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immRecti(shdr_pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ immUnbindProgram();
+
+ glDisable(GL_BLEND);
+
+ shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 8.0f);
+
+ imm_draw_box_wire_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, (float)rect->ymax);
+
+ immUnbindProgram();
+
+ // wm_gesture_draw_line(gt); // draws a diagonal line in the lined box to test wm_gesture_draw_line
}
static void wm_gesture_draw_circle(wmGesture *gt)
{
rcti *rect = (rcti *)gt->customdata;
- glTranslatef((float)rect->xmin, (float)rect->ymin, 0.0f);
-
glEnable(GL_BLEND);
- glColor4f(1.0, 1.0, 1.0, 0.05);
- glutil_draw_filled_arc(0.0, M_PI * 2.0, rect->xmax, 40);
+
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f);
+ imm_draw_circle_fill_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
- // for USE_GLSL works bad because of no relation between lines
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xAAAA);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x5555);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glTranslatef(-rect->xmin, -rect->ymin, 0.0f);
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 4.0f);
+ imm_draw_circle_wire_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
+
+ immUnbindProgram();
}
struct LassoFillData {
@@ -243,14 +270,14 @@ static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
memset(col, 0x10, x_end - x);
}
-static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
+static void draw_filled_lasso(wmGesture *gt)
{
const short *lasso = (short *)gt->customdata;
const int tot = gt->points;
int (*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__);
int i;
rcti rect;
- rcti rect_win;
+ float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
for (i = 0; i < tot; i++, lasso += 2) {
moves[i][0] = lasso[0];
@@ -259,10 +286,9 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
BLI_lasso_boundbox(&rect, (const int (*)[2])moves, tot);
- wm_subwindow_rect_get(win, gt->swinid, &rect_win);
- BLI_rcti_translate(&rect, rect_win.xmin, rect_win.ymin);
- BLI_rcti_isect(&rect_win, &rect, &rect);
- BLI_rcti_translate(&rect, -rect_win.xmin, -rect_win.ymin);
+ BLI_rcti_translate(&rect, gt->winrct.xmin, gt->winrct.ymin);
+ BLI_rcti_isect(&gt->winrct, &rect, &rect);
+ BLI_rcti_translate(&rect, -gt->winrct.xmin, -gt->winrct.ymin);
/* highly unlikely this will fail, but could crash if (tot == 0) */
if (BLI_rcti_is_empty(&rect) == false) {
@@ -276,66 +302,72 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
(const int (*)[2])moves, tot,
draw_filled_lasso_px_cb, &lasso_fill_data);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ /* Additive Blending */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
- glColor4f(1, 1, 1, 1);
- glPixelTransferf(GL_RED_BIAS, 1);
- glPixelTransferf(GL_GREEN_BIAS, 1);
- glPixelTransferf(GL_BLUE_BIAS, 1);
+ GLint unpack_alignment;
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glEnable(GL_BLEND);
- glaDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf);
- glDisable(GL_BLEND);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
+ GPU_shader_bind(state.shader);
+ GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immDrawPixelsTex(&state, rect.xmin, rect.ymin, w, h, GL_RED, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf, 1.0f, 1.0f, NULL);
- glPixelTransferf(GL_RED_BIAS, 0);
- glPixelTransferf(GL_GREEN_BIAS, 0);
- glPixelTransferf(GL_BLUE_BIAS, 0);
+ GPU_shader_unbind();
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment);
MEM_freeN(pixel_buf);
+
+ glDisable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
MEM_freeN(moves);
}
-static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
+static void wm_gesture_draw_lasso(wmGesture *gt, bool filled)
{
const short *lasso = (short *)gt->customdata;
int i;
if (filled) {
- draw_filled_lasso(win, gt);
+ draw_filled_lasso(gt);
+ }
+
+ const int numverts = gt->points;
+
+ /* Nothing to draw, do early output. */
+ if (numverts < 2) {
+ return;
+ }
+
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 2.0f);
+
+ immBegin((gt->type == WM_GESTURE_LASSO) ? GPU_PRIM_LINE_LOOP : GPU_PRIM_LINE_STRIP, numverts);
+
+ for (i = 0; i < gt->points; i++, lasso += 2) {
+ immVertex2f(shdr_pos, (float)lasso[0], (float)lasso[1]);
}
- // for USE_GLSL can't check this yet
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xAAAA);
- glBegin(GL_LINE_STRIP);
- for (i = 0; i < gt->points; i++, lasso += 2)
- glVertex2sv(lasso);
- if (gt->type == WM_GESTURE_LASSO)
- glVertex2sv((short *)gt->customdata);
- glEnd();
-
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x5555);
- glBegin(GL_LINE_STRIP);
- lasso = (short *)gt->customdata;
- for (i = 0; i < gt->points; i++, lasso += 2)
- glVertex2sv(lasso);
- if (gt->type == WM_GESTURE_LASSO)
- glVertex2sv((short *)gt->customdata);
- glEnd();
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immEnd();
+ immUnbindProgram();
}
static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
@@ -344,17 +376,41 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xCCCC);
- sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
- sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
-
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x3333);
- sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
- sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ float x1, x2, y1, y2;
+
+ const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 8.0f);
+
+ immBegin(GPU_PRIM_LINES, 4);
+
+ x1 = (float)(rect->xmin - winsize_x);
+ y1 = (float)rect->ymin;
+ x2 = (float)(rect->xmin + winsize_x);
+ y2 = y1;
+
+ immVertex2f(shdr_pos, x1, y1);
+ immVertex2f(shdr_pos, x2, y2);
+
+ x1 = (float)rect->xmin;
+ y1 = (float)(rect->ymin - winsize_y);
+ x2 = x1;
+ y2 = (float)(rect->ymin + winsize_y);
+
+ immVertex2f(shdr_pos, x1, y1);
+ immVertex2f(shdr_pos, x2, y2);
+
+ immEnd();
+
+ immUnbindProgram();
}
/* called in wm_draw.c */
@@ -362,10 +418,10 @@ void wm_gesture_draw(wmWindow *win)
{
wmGesture *gt = (wmGesture *)win->gesture.first;
- GPU_basic_shader_line_width(1);
+ glLineWidth(1.0f);
for (; gt; gt = gt->next) {
/* all in subwindow space */
- wmSubWindowSet(win, gt->swinid);
+ wmViewport(&gt->winrct);
if (gt->type == WM_GESTURE_RECT)
wm_gesture_draw_rect(gt);
@@ -382,9 +438,9 @@ void wm_gesture_draw(wmWindow *win)
}
}
else if (gt->type == WM_GESTURE_LINES)
- wm_gesture_draw_lasso(win, gt, false);
+ wm_gesture_draw_lasso(gt, false);
else if (gt->type == WM_GESTURE_LASSO)
- wm_gesture_draw_lasso(win, gt, true);
+ wm_gesture_draw_lasso(gt, true);
else if (gt->type == WM_GESTURE_STRAIGHTLINE)
wm_gesture_draw_line(gt);
}
@@ -392,12 +448,8 @@ void wm_gesture_draw(wmWindow *win)
void wm_gesture_tag_redraw(bContext *C)
{
- wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
- ARegion *ar = CTX_wm_region(C);
if (screen)
screen->do_draw_gesture = true;
-
- wm_tag_redraw_overlay(win, ar);
}
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index a554727cacd..b29da15a334 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -47,9 +47,9 @@
#include "wm.h"
#include "wm_event_types.h"
#include "wm_event_system.h"
-#include "wm_subwindow.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -87,13 +87,22 @@ static void gesture_modal_state_to_operator(wmOperator *op, int modal_state)
case GESTURE_MODAL_SELECT:
case GESTURE_MODAL_DESELECT:
if ((prop = RNA_struct_find_property(op->ptr, "deselect"))) {
- RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT));
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT));
+ }
+ }
+ if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_enum_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT) ? SEL_OP_SUB : SEL_OP_ADD);
+ }
}
break;
case GESTURE_MODAL_IN:
case GESTURE_MODAL_OUT:
if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) {
- RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_OUT));
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_OUT));
+ }
}
break;
}
@@ -108,6 +117,11 @@ static int gesture_modal_state_from_operator(wmOperator *op)
return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_DESELECT : GESTURE_MODAL_SELECT;
}
}
+ if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
+ if (RNA_property_is_set(op->ptr, prop)) {
+ return RNA_property_enum_get(op->ptr, prop) == SEL_OP_SUB ? GESTURE_MODAL_DESELECT : GESTURE_MODAL_SELECT;
+ }
+ }
if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) {
if (RNA_property_is_set(op->ptr, prop)) {
return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_OUT : GESTURE_MODAL_IN;
@@ -129,7 +143,7 @@ static int gesture_modal_state_from_operator(wmOperator *op)
*
* \{ */
-static bool gesture_border_apply_rect(wmOperator *op)
+static bool gesture_box_apply_rect(wmOperator *op)
{
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
@@ -147,13 +161,13 @@ static bool gesture_border_apply_rect(wmOperator *op)
return 1;
}
-static bool gesture_border_apply(bContext *C, wmOperator *op)
+static bool gesture_box_apply(bContext *C, wmOperator *op)
{
wmGesture *gesture = op->customdata;
int retval;
- if (!gesture_border_apply_rect(op)) {
+ if (!gesture_box_apply_rect(op)) {
return 0;
}
@@ -165,7 +179,7 @@ static bool gesture_border_apply(bContext *C, wmOperator *op)
return 1;
}
-int WM_gesture_border_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int modal_state = gesture_modal_state_from_operator(op);
@@ -194,24 +208,21 @@ int WM_gesture_border_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-int WM_gesture_border_modal(bContext *C, wmOperator *op, const wmEvent *event)
+int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
- int sx, sy;
if (event->type == MOUSEMOVE) {
- wm_subwindow_origin_get(CTX_wm_window(C), gesture->swinid, &sx, &sy);
-
if (gesture->type == WM_GESTURE_CROSS_RECT && gesture->is_active == false) {
- rect->xmin = rect->xmax = event->x - sx;
- rect->ymin = rect->ymax = event->y - sy;
+ rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
}
else {
- rect->xmax = event->x - sx;
- rect->ymax = event->y - sy;
+ rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymax = event->y - gesture->winrct.ymin;
}
- gesture_border_apply_rect(op);
+ gesture_box_apply_rect(op);
wm_gesture_tag_redraw(C);
}
@@ -230,7 +241,7 @@ int WM_gesture_border_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (gesture->wait_for_input) {
gesture->modal_state = event->val;
}
- if (gesture_border_apply(C, op)) {
+ if (gesture_box_apply(C, op)) {
gesture_modal_end(C, op);
return OPERATOR_FINISHED;
}
@@ -259,7 +270,7 @@ int WM_gesture_border_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-void WM_gesture_border_cancel(bContext *C, wmOperator *op)
+void WM_gesture_box_cancel(bContext *C, wmOperator *op)
{
gesture_modal_end(C, op);
}
@@ -333,13 +344,11 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
- int sx, sy;
if (event->type == MOUSEMOVE) {
- wm_subwindow_origin_get(CTX_wm_window(C), gesture->swinid, &sx, &sy);
- rect->xmin = event->x - sx;
- rect->ymin = event->y - sy;
+ rect->xmin = event->x - gesture->winrct.xmin;
+ rect->ymin = event->y - gesture->winrct.ymin;
wm_gesture_tag_redraw(C);
@@ -418,7 +427,7 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
#if 0
/* Allow view navigation??? */
/* note, this gives issues:
- * 1) other modal ops run on top (border select),
+ * 1) other modal ops run on top (box select),
* 2) middlemouse is used now 3) tablet/trackpad? */
else {
return OPERATOR_PASS_THROUGH;
@@ -464,24 +473,22 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
wmWindow *window = CTX_wm_window(C);
wmGesture *gesture = window->tweak;
rcti *rect = gesture->customdata;
- int sx, sy, val;
+ int val;
switch (event->type) {
case MOUSEMOVE:
case INBETWEEN_MOUSEMOVE:
- wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
-
- rect->xmax = event->x - sx;
- rect->ymax = event->y - sy;
+ rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymax = event->y - gesture->winrct.ymin;
if ((val = wm_gesture_evaluate(gesture))) {
wmEvent tevent;
wm_event_init_from_window(window, &tevent);
/* We want to get coord from start of drag, not from point where it becomes a tweak event, see T40549 */
- tevent.x = rect->xmin + sx;
- tevent.y = rect->ymin + sy;
+ tevent.x = rect->xmin + gesture->winrct.xmin;
+ tevent.y = rect->ymin + gesture->winrct.ymin;
if (gesture->event_type == LEFTMOUSE)
tevent.type = EVT_TWEAK_L;
else if (gesture->event_type == RIGHTMOUSE)
@@ -617,7 +624,6 @@ static void gesture_lasso_apply(bContext *C, wmOperator *op)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
- int sx, sy;
switch (event->type) {
case MOUSEMOVE:
@@ -625,8 +631,6 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
wm_gesture_tag_redraw(C);
- wm_subwindow_origin_get(CTX_wm_window(C), gesture->swinid, &sx, &sy);
-
if (gesture->points == gesture->points_alloc) {
gesture->points_alloc *= 2;
gesture->customdata = MEM_reallocN(gesture->customdata, sizeof(short[2]) * gesture->points_alloc);
@@ -637,15 +641,15 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
short *lasso = gesture->customdata;
lasso += (2 * gesture->points - 2);
- x = (event->x - sx - lasso[0]);
- y = (event->y - sy - lasso[1]);
+ x = (event->x - gesture->winrct.xmin - lasso[0]);
+ y = (event->y - gesture->winrct.ymin - lasso[1]);
/* make a simple distance check to get a smoother lasso
* add only when at least 2 pixels between this and previous location */
if ((x * x + y * y) > 4) {
lasso += 2;
- lasso[0] = event->x - sx;
- lasso[1] = event->y - sy;
+ lasso[0] = event->x - gesture->winrct.xmin;
+ lasso[1] = event->y - gesture->winrct.ymin;
gesture->points++;
}
}
@@ -813,18 +817,15 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev
{
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
- int sx, sy;
if (event->type == MOUSEMOVE) {
- wm_subwindow_origin_get(CTX_wm_window(C), gesture->swinid, &sx, &sy);
-
if (gesture->is_active == false) {
- rect->xmin = rect->xmax = event->x - sx;
- rect->ymin = rect->ymax = event->y - sy;
+ rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
}
else {
- rect->xmax = event->x - sx;
- rect->ymax = event->y - sy;
+ rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymax = event->y - gesture->winrct.ymin;
gesture_straightline_apply(C, op);
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index d254a83fcc2..e4ae9495c61 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -35,6 +35,7 @@
#include <string.h>
#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
@@ -53,6 +54,7 @@
#include "BLI_string.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_timer.h"
#include "BLO_writefile.h"
#include "BLO_undofile.h"
@@ -60,21 +62,21 @@
#include "BKE_blender.h"
#include "BKE_blender_undo.h"
#include "BKE_context.h"
-#include "BKE_screen.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_icons.h"
-#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_mball_tessellate.h"
#include "BKE_node.h"
#include "BKE_report.h"
-#include "BKE_font.h"
+#include "BKE_screen.h"
+#include "BKE_keyconfig.h"
#include "BKE_addon.h"
#include "BKE_appdir.h"
#include "BKE_sequencer.h" /* free seq clipboard */
+#include "BKE_studiolight.h"
#include "BKE_material.h" /* clear_matcopybuf */
#include "BKE_tracking.h" /* free tracking clipboard */
#include "BKE_mask.h" /* free mask clipboard */
@@ -86,9 +88,6 @@
#include "BPY_extern.h"
#endif
-#ifdef WITH_GAMEENGINE
-# include "BL_System.h"
-#endif
#include "GHOST_Path-api.h"
#include "GHOST_C-api.h"
@@ -96,6 +95,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm_cursors.h"
#include "wm_event_system.h"
@@ -116,17 +116,22 @@
#include "ED_undo.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "BLF_api.h"
#include "BLT_lang.h"
-#include "GPU_buffers.h"
+#include "GPU_material.h"
#include "GPU_draw.h"
+#include "GPU_immediate.h"
#include "GPU_init_exit.h"
-#include "BKE_depsgraph.h"
#include "BKE_sound.h"
#include "COM_compositor.h"
+#include "DEG_depsgraph.h"
+
+#include "DRW_engine.h"
+
#ifdef WITH_OPENSUBDIV
# include "BKE_subsurf.h"
#endif
@@ -135,6 +140,9 @@ CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_OPERATORS, "wm.operator");
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_HANDLERS, "wm.handler");
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_EVENTS, "wm.event");
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_KEYMAPS, "wm.keymap");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_TOOLS, "wm.tool");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_MSGBUS_PUB, "wm.msgbus.pub");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_MSGBUS_SUB, "wm.msgbus.sub");
static void wm_init_reports(bContext *C)
{
@@ -153,6 +161,42 @@ static void wm_free_reports(bContext *C)
bool wm_start_with_console = false; /* used in creator.c */
+/**
+ * Since we cannot know in advance if we will require the draw manager
+ * context when starting blender in background mode (specially true with
+ * scripts) we deferre the ghost initialization the most as possible
+ * so that it does not break anything that can run in headless mode (as in
+ * without display server attached).
+ **/
+static bool opengl_is_init = false;
+
+void WM_init_opengl(Main *bmain)
+{
+ /* must be called only once */
+ BLI_assert(opengl_is_init == false);
+
+ if (G.background) {
+ /* Ghost is still not init elsewhere in background mode. */
+ wm_ghost_init(NULL);
+ }
+
+ /* Needs to be first to have an ogl context bound. */
+ DRW_opengl_context_create();
+
+ GPU_init();
+ GPU_set_mipmap(bmain, true);
+ GPU_set_linear_mipmap(true);
+ GPU_set_anisotropic(bmain, U.anisotropic_filter);
+ GPU_set_gpu_mipmapping(bmain, U.use_gpu_mipmap);
+
+ GPU_pass_cache_init();
+
+#ifdef WITH_OPENSUBDIV
+ BKE_subsurf_osd_init();
+#endif
+ opengl_is_init = true;
+}
+
/* only called once, for startup */
void WM_init(bContext *C, int argc, const char **argv)
{
@@ -161,44 +205,60 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_ghost_init(C); /* note: it assigns C to ghost! */
wm_init_cursor_data();
}
+
GHOST_CreateSystemPaths();
BKE_addon_pref_type_init();
+ BKE_keyconfig_pref_type_init();
wm_operatortype_init();
wm_operatortypes_register();
+ WM_paneltype_init(); /* Lookup table only. */
WM_menutype_init();
WM_uilisttype_init();
+ wm_gizmotype_init();
+ wm_gizmogrouptype_init();
ED_undosys_type_init();
BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
+ BKE_region_callback_free_gizmomap_set(wm_gizmomap_remove); /* screen.c */
+ BKE_region_callback_refresh_tag_gizmomap_set(WM_gizmomap_tag_refresh);
BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */
BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */
- DAG_editors_update_cb(ED_render_id_flush_update,
- ED_render_scene_update,
- ED_render_scene_update_pre); /* depsgraph.c */
+ DEG_editors_set_update_cb(ED_render_id_flush_update,
+ ED_render_scene_update);
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
ED_file_init(); /* for fsmenu */
ED_node_init_butfuncs();
- BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
+ BLF_init();
BLT_lang_init();
/* Must call first before doing any .blend file reading, since versionning code may create new IDs... See T57066. */
BLT_lang_set(NULL);
+ /* Init icons before reading .blend files for preview icons, which can
+ * get triggered by the depsgraph. This is also done in background mode
+ * for scripts that do background processing with preview icons. */
+ BKE_icons_init(BIFICONID_LAST);
+
/* reports cant be initialized before the wm,
* but keep before file reading, since that may report errors */
wm_init_reports(C);
+ WM_msgbus_types_init();
+
/* get the default database, plus a wm */
- wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, WM_init_state_app_template_get());
+ bool is_factory_startup = true;
+ wm_homefile_read(
+ C, NULL, G.factory_startup, false, true, NULL, WM_init_state_app_template_get(),
+ &is_factory_startup);
/* Call again to set from userpreferences... */
BLT_lang_set(NULL);
@@ -209,29 +269,12 @@ void WM_init(bContext *C, int argc, const char **argv)
/* sets 3D mouse deadzone */
WM_ndof_deadzone_set(U.ndof_deadzone);
#endif
-
- GPU_init();
-
- GPU_set_mipmap(G_MAIN, !(U.gameflags & USER_DISABLE_MIPMAP));
- GPU_set_linear_mipmap(true);
- GPU_set_anisotropic(G_MAIN, U.anisotropic_filter);
- GPU_set_gpu_mipmapping(G_MAIN, U.use_gpu_mipmap);
-
-#ifdef WITH_OPENSUBDIV
- BKE_subsurf_osd_init();
-#endif
+ WM_init_opengl(G_MAIN);
UI_init();
- }
- else {
- /* Note: Currently only inits icons, which we now want in background mode too
- * (scripts could use those in background processing...).
- * In case we do more later, we may need to pass a 'background' flag.
- * Called from 'UI_init' above */
- BKE_icons_init(1);
+ BKE_studiolight_init();
}
-
ED_spacemacros_init();
/* note: there is a bug where python needs initializing before loading the
@@ -258,7 +301,7 @@ void WM_init(bContext *C, int argc, const char **argv)
clear_matcopybuf();
ED_render_clear_mtex_copybuf();
- // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ // glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
wm_history_file_read();
@@ -296,6 +339,9 @@ void WM_init(bContext *C, int argc, const char **argv)
BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
+ if (is_factory_startup) {
+ BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST);
+ }
wm_file_read_report(C, bmain);
@@ -319,96 +365,6 @@ void WM_init_splash(bContext *C)
}
}
-bool WM_init_game(bContext *C)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win;
-
- ScrArea *sa;
- ARegion *ar = NULL;
-
- Scene *scene = CTX_data_scene(C);
-
- if (!scene) {
- /* XXX, this should not be needed. */
- Main *bmain = CTX_data_main(C);
- scene = bmain->scene.first;
- }
-
- win = wm->windows.first;
-
- /* first to get a valid window */
- if (win)
- CTX_wm_window_set(C, win);
-
- sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0);
- ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
-
- /* if we have a valid 3D view */
- if (sa && ar) {
- ARegion *arhide;
-
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- /* disable quad view */
- if (ar->alignment == RGN_ALIGN_QSPLIT)
- WM_operator_name_call(C, "SCREEN_OT_region_quadview", WM_OP_EXEC_DEFAULT, NULL);
-
- /* toolbox, properties panel and header are hidden */
- for (arhide = sa->regionbase.first; arhide; arhide = arhide->next) {
- if (arhide->regiontype != RGN_TYPE_WINDOW) {
- if (!(arhide->flag & RGN_FLAG_HIDDEN)) {
- ED_region_toggle_hidden(C, arhide);
- }
- }
- }
-
- /* full screen the area */
- if (!sa->full) {
- ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
- }
-
- /* Fullscreen */
- if ((scene->gm.playerflag & GAME_PLAYER_FULLSCREEN)) {
- WM_operator_name_call(C, "WM_OT_window_fullscreen_toggle", WM_OP_EXEC_DEFAULT, NULL);
- wm_get_screensize(&ar->winrct.xmax, &ar->winrct.ymax);
- ar->winx = ar->winrct.xmax + 1;
- ar->winy = ar->winrct.ymax + 1;
- }
- else {
- GHOST_RectangleHandle rect = GHOST_GetClientBounds(win->ghostwin);
- ar->winrct.ymax = GHOST_GetHeightRectangle(rect);
- ar->winrct.xmax = GHOST_GetWidthRectangle(rect);
- ar->winx = ar->winrct.xmax + 1;
- ar->winy = ar->winrct.ymax + 1;
- GHOST_DisposeRectangle(rect);
- }
-
- WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL);
-
- BKE_sound_exit();
-
- return true;
- }
- else {
- ReportTimerInfo *rti;
-
- BKE_report(&wm->reports, RPT_ERROR, "No valid 3D View found, game auto start is not possible");
-
- /* After adding the report to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
-
- /* Records time since last report was added */
- wm->reports.reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER, 0.02);
-
- rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
- wm->reports.reporttimer->customdata = rti;
-
- return false;
- }
-}
-
/* free strings of open recent files */
static void free_openrecent(void)
{
@@ -486,7 +442,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
/* save the undo state as quit.blend */
char filename[FILE_MAX];
bool has_edited;
- int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+ int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE);
@@ -507,11 +463,17 @@ void WM_exit_ext(bContext *C, const bool do_python)
CTX_wm_window_set(C, win); /* needed by operator close callbacks */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
- ED_screen_exit(C, win, win->screen);
+ ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
}
+ BLI_timer_free();
+
+ WM_paneltype_clear();
+
BKE_addon_pref_type_free();
+ BKE_keyconfig_pref_type_free();
+
wm_operatortype_free();
wm_dropbox_free();
WM_menutype_free();
@@ -523,11 +485,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_undosys_type_free();
-// XXX
-// BIF_GlobalReebFree();
-// BIF_freeRetarget();
- BIF_freeTemplates(C);
-
free_openrecent();
BKE_mball_cubeTable_free();
@@ -550,6 +507,14 @@ void WM_exit_ext(bContext *C, const bool do_python)
COM_deinitialize();
#endif
+ if (opengl_is_init) {
+#ifdef WITH_OPENSUBDIV
+ BKE_subsurf_osd_cleanup();
+#endif
+
+ GPU_free_unused_buffers(G_MAIN);
+ }
+
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
// free_matcopybuf();
ANIM_fcurves_copybuf_free();
@@ -560,8 +525,21 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_gpencil_strokes_copybuf_free();
BKE_node_clipboard_clear();
+ /* free gizmo-maps after freeing blender, so no deleted data get accessed during cleaning up of areas */
+ wm_gizmomaptypes_free();
+ wm_gizmogrouptype_free();
+ wm_gizmotype_free();
+
BLF_exit();
+ if (opengl_is_init) {
+ DRW_opengl_context_enable_ex(false);
+ GPU_pass_cache_free();
+ GPU_exit();
+ DRW_opengl_context_disable_ex(false);
+ DRW_opengl_context_destroy();
+ }
+
#ifdef WITH_INTERNATIONAL
BLF_free_unifont();
BLF_free_unifont_mono();
@@ -589,17 +567,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
(void)do_python;
#endif
- if (!G.background) {
-#ifdef WITH_OPENSUBDIV
- BKE_subsurf_osd_cleanup();
-#endif
-
- GPU_global_buffer_pool_free();
- GPU_free_unused_buffers(G_MAIN);
-
- GPU_exit();
- }
-
ED_file_exit(); /* for fsmenu */
UI_exit();
@@ -610,9 +577,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
wm_ghost_exit();
CTX_free(C);
-#ifdef WITH_GAMEENGINE
- SYS_DeleteSystem(SYS_GetSystem());
-#endif
GHOST_DisposeSystemPaths();
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 2834e95527a..4c00b99e13e 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -38,6 +38,7 @@
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
#include "CLG_log.h"
@@ -51,6 +52,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLT_translation.h"
@@ -164,7 +166,8 @@ static void wm_keyconfig_properties_update_ot(ListBase *km_lb)
static bool wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
{
return (STREQ(a->idname, b->idname) &&
- RNA_struct_equals(a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE) &&
+ /* We do not really care about which Main we pass here, tbh. */
+ RNA_struct_equals(G_MAIN, a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE) &&
(a->flag & KMI_INACTIVE) == (b->flag & KMI_INACTIVE) &&
a->propvalue == b->propvalue);
}
@@ -256,24 +259,40 @@ static void wm_keymap_diff_item_free(wmKeyMapDiffItem *kmdi)
* List of keymaps for all editors, modes, ... . There is a builtin default key
* configuration, a user key configuration, and other preset configurations. */
-wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname)
+wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname, bool user_defined)
{
- wmKeyConfig *keyconf;
+ wmKeyConfig *keyconf = BLI_findstring(&wm->keyconfigs, idname, offsetof(wmKeyConfig, idname));
+ if (keyconf) {
+ if (keyconf == wm->defaultconf) {
+ /* For default configuration, we need to keep keymap
+ * modal items and poll functions intact. */
+ for (wmKeyMap *km = keyconf->keymaps.first; km; km = km->next) {
+ WM_keymap_clear(km);
+ }
+ }
+ else {
+ /* For user defined key configuration, clear all keymaps. */
+ WM_keyconfig_clear(keyconf);
+ }
+
+ return keyconf;
+ }
+ /* Create new configuration. */
keyconf = MEM_callocN(sizeof(wmKeyConfig), "wmKeyConfig");
BLI_strncpy(keyconf->idname, idname, sizeof(keyconf->idname));
BLI_addtail(&wm->keyconfigs, keyconf);
+ if (user_defined) {
+ keyconf->flag |= KEYCONF_USER;
+ }
+
return keyconf;
}
wmKeyConfig *WM_keyconfig_new_user(wmWindowManager *wm, const char *idname)
{
- wmKeyConfig *keyconf = WM_keyconfig_new(wm, idname);
-
- keyconf->flag |= KEYCONF_USER;
-
- return keyconf;
+ return WM_keyconfig_new(wm, idname, true);
}
bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
@@ -294,15 +313,18 @@ bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
}
}
-void WM_keyconfig_free(wmKeyConfig *keyconf)
+void WM_keyconfig_clear(wmKeyConfig *keyconf)
{
- wmKeyMap *km;
-
- while ((km = keyconf->keymaps.first)) {
- WM_keymap_free(km);
- BLI_freelinkN(&keyconf->keymaps, km);
+ for (wmKeyMap *km = keyconf->keymaps.first; km; km = km->next) {
+ WM_keymap_clear(km);
}
+ BLI_freelistN(&keyconf->keymaps);
+}
+
+void WM_keyconfig_free(wmKeyConfig *keyconf)
+{
+ WM_keyconfig_clear(keyconf);
MEM_freeN(keyconf);
}
@@ -343,6 +365,12 @@ static wmKeyMap *wm_keymap_new(const char *idname, int spaceid, int regionid)
km->spaceid = spaceid;
km->regionid = regionid;
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(km->owner_id, owner_id, sizeof(km->owner_id));
+ }
+ }
return km;
}
@@ -370,7 +398,7 @@ static wmKeyMap *wm_keymap_copy(wmKeyMap *keymap)
return keymapn;
}
-void WM_keymap_free(wmKeyMap *keymap)
+void WM_keymap_clear(wmKeyMap *keymap)
{
wmKeyMapItem *kmi;
wmKeyMapDiffItem *kmdi;
@@ -389,7 +417,7 @@ bool WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap)
{
if (BLI_findindex(&keyconf->keymaps, keymap) != -1) {
- WM_keymap_free(keymap);
+ WM_keymap_clear(keymap);
BLI_remlink(&keyconf->keymaps, keymap);
MEM_freeN(keymap);
@@ -403,6 +431,14 @@ bool WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap)
bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
{
+ /* If we're tagged, only use compatible. */
+ if (keymap->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, keymap->owner_id) == false) {
+ return false;
+ }
+ }
+
if (keymap->poll != NULL) {
return keymap->poll(C);
}
@@ -477,6 +513,20 @@ wmKeyMapItem *WM_keymap_add_item(wmKeyMap *keymap, const char *idname, int type,
return kmi;
}
+wmKeyMapItem *WM_keymap_add_item_copy(
+ struct wmKeyMap *keymap, wmKeyMapItem *kmi_src)
+{
+ wmKeyMapItem *kmi_dst = wm_keymap_item_copy(kmi_src);
+
+ BLI_addtail(&keymap->items, kmi_dst);
+
+ keymap_item_set_id(keymap, kmi_dst);
+
+ WM_keyconfig_update_tag(keymap, kmi_dst);
+
+ return kmi_dst;
+}
+
bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
{
if (BLI_findindex(&keymap->items, kmi) != -1) {
@@ -648,7 +698,7 @@ static wmKeyMap *wm_keymap_patch_update(ListBase *lb, wmKeyMap *defaultmap, wmKe
km = WM_keymap_list_find(lb, defaultmap->idname, defaultmap->spaceid, defaultmap->regionid);
if (km) {
expanded = (km->flag & (KEYMAP_EXPANDED | KEYMAP_CHILDREN_EXPANDED));
- WM_keymap_free(km);
+ WM_keymap_clear(km);
BLI_freelinkN(lb, km);
}
@@ -711,7 +761,7 @@ static void wm_keymap_diff_update(ListBase *lb, wmKeyMap *defaultmap, wmKeyMap *
/* remove previous diff keymap in list, we will replace it */
prevmap = WM_keymap_list_find(lb, km->idname, km->spaceid, km->regionid);
if (prevmap) {
- WM_keymap_free(prevmap);
+ WM_keymap_clear(prevmap);
BLI_freelinkN(lb, prevmap);
}
@@ -727,13 +777,13 @@ static void wm_keymap_diff_update(ListBase *lb, wmKeyMap *defaultmap, wmKeyMap *
BLI_addtail(lb, diffmap);
}
else {
- WM_keymap_free(diffmap);
+ WM_keymap_clear(diffmap);
MEM_freeN(diffmap);
}
/* free temporary default map */
if (addonmap) {
- WM_keymap_free(defaultmap);
+ WM_keymap_clear(defaultmap);
MEM_freeN(defaultmap);
}
}
@@ -756,6 +806,18 @@ wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int
return NULL;
}
+wmKeyMap *WM_keymap_list_find_spaceid_or_empty(ListBase *lb, const char *idname, int spaceid, int regionid)
+{
+ wmKeyMap *km;
+
+ for (km = lb->first; km; km = km->next)
+ if (ELEM(km->spaceid, spaceid, SPACE_EMPTY) && km->regionid == regionid)
+ if (STREQLEN(idname, km->idname, KMAP_MAX_NAME))
+ return km;
+
+ return NULL;
+}
+
wmKeyMap *WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
{
wmKeyMap *km = WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
@@ -777,6 +839,13 @@ wmKeyMap *WM_keymap_find_all(const bContext *C, const char *idname, int spaceid,
return WM_keymap_list_find(&wm->userconf->keymaps, idname, spaceid, regionid);
}
+wmKeyMap *WM_keymap_find_all_spaceid_or_empty(const bContext *C, const char *idname, int spaceid, int regionid)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ return WM_keymap_list_find_spaceid_or_empty(&wm->userconf->keymaps, idname, spaceid, regionid);
+}
+
/* ****************** modal keymaps ************ */
/* modal maps get linked to a running operator, and filter the keys before sending to modal() callback */
@@ -785,21 +854,22 @@ wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf, const char *idname, const Enu
{
wmKeyMap *km = WM_keymap_ensure(keyconf, idname, 0, 0);
km->flag |= KEYMAP_MODAL;
- km->modal_items = items;
- if (!items) {
- /* init modal items from default config */
- wmWindowManager *wm = G_MAIN->wm.first;
- if (wm->defaultconf) {
- wmKeyMap *defaultkm = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, 0, 0);
+ /* init modal items from default config */
+ wmWindowManager *wm = G_MAIN->wm.first;
+ if (wm->defaultconf && wm->defaultconf != keyconf) {
+ wmKeyMap *defaultkm = WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, 0, 0);
- if (defaultkm) {
- km->modal_items = defaultkm->modal_items;
- km->poll = defaultkm->poll;
- }
+ if (defaultkm) {
+ km->modal_items = defaultkm->modal_items;
+ km->poll = defaultkm->poll;
}
}
+ if (items) {
+ km->modal_items = items;
+ }
+
return km;
}
@@ -903,11 +973,13 @@ static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km)
km->modal_items = defaultkm->modal_items;
km->poll = defaultkm->poll;
- for (kmi = km->items.first; kmi; kmi = kmi->next) {
- if (kmi->propvalue_str[0]) {
- if (RNA_enum_value_from_id(km->modal_items, kmi->propvalue_str, &propvalue))
- kmi->propvalue = propvalue;
- kmi->propvalue_str[0] = '\0';
+ if (km->modal_items) {
+ for (kmi = km->items.first; kmi; kmi = kmi->next) {
+ if (kmi->propvalue_str[0]) {
+ if (RNA_enum_value_from_id(km->modal_items, kmi->propvalue_str, &propvalue))
+ kmi->propvalue = propvalue;
+ kmi->propvalue_str[0] = '\0';
+ }
}
}
}
@@ -953,11 +1025,7 @@ int WM_keymap_item_raw_to_string(
alt == KM_ANY &&
oskey == KM_ANY)
{
- /* make it implicit in case of compact result expected. */
- if (!compact) {
- ADD_SEP;
- p += BLI_strcpy_rlen(p, IFACE_("Any"));
- }
+ /* Don't show anything for any mapping. */
}
else {
if (shift) {
@@ -1614,7 +1682,7 @@ void WM_keymap_restore_item_to_default(bContext *C, wmKeyMap *keymap, wmKeyMapIt
/* free temporary keymap */
if (addonmap) {
- WM_keymap_free(defaultmap);
+ WM_keymap_clear(defaultmap);
MEM_freeN(defaultmap);
}
}
@@ -1628,7 +1696,7 @@ void WM_keymap_restore_to_default(wmKeyMap *keymap, bContext *C)
usermap = WM_keymap_list_find(&U.user_keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
if (usermap) {
- WM_keymap_free(usermap);
+ WM_keymap_clear(usermap);
BLI_freelinkN(&U.user_keymaps, usermap);
WM_keyconfig_update_tag(NULL, NULL);
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 1774b876f38..e3fe1b7abdd 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -46,6 +46,7 @@
/** \name Wrappers for #WM_keymap_add_item
* \{ */
+/* menu wrapper for WM_keymap_add_item */
wmKeyMapItem *WM_keymap_add_menu(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
wmKeyMapItem *kmi = WM_keymap_add_item(keymap, "WM_OT_call_menu", type, val, modifier, keymodifier);
@@ -60,12 +61,93 @@ wmKeyMapItem *WM_keymap_add_menu_pie(wmKeyMap *keymap, const char *idname, int t
return kmi;
}
+wmKeyMapItem *WM_keymap_add_panel(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
+{
+ wmKeyMapItem *kmi = WM_keymap_add_item(keymap, "WM_OT_call_panel", type, val, modifier, keymodifier);
+ RNA_string_set(kmi->ptr, "name", idname);
+ /* TODO: we might want to disable this. */
+ RNA_boolean_set(kmi->ptr, "keep_open", false);
+ return kmi;
+}
+
+/* tool wrapper for WM_keymap_add_item */
+wmKeyMapItem *WM_keymap_add_tool(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
+{
+ wmKeyMapItem *kmi = WM_keymap_add_item(keymap, "WM_OT_tool_set_by_name", type, val, modifier, keymodifier);
+ RNA_string_set(kmi->ptr, "name", idname);
+ return kmi;
+}
+
+/** Useful for mapping numbers to an enum. */
+void WM_keymap_add_context_enum_set_items(
+ wmKeyMap *keymap, const EnumPropertyItem *items, const char *data_path,
+ int type_start, int val, int modifier, int keymodifier)
+{
+ for (int i = 0, type_offset = 0; items[i].identifier; i++) {
+ if (items[i].identifier[0] == '\0') {
+ continue;
+ }
+ wmKeyMapItem *kmi = WM_keymap_add_item(
+ keymap, "WM_OT_context_set_enum",
+ type_start + type_offset, val, modifier, keymodifier);
+ RNA_string_set(kmi->ptr, "data_path", data_path);
+ RNA_string_set(kmi->ptr, "value", items[i].identifier);
+ type_offset += 1;
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Introspection
* \{ */
+wmKeyMap *WM_keymap_guess_from_context(const bContext *C)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ const char *km_id = NULL;
+ if (sl->spacetype == SPACE_VIEW3D) {
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ switch (mode) {
+ case CTX_MODE_EDIT_MESH: km_id = "Mesh"; break;
+ case CTX_MODE_EDIT_CURVE: km_id = "Curve"; break;
+ case CTX_MODE_EDIT_SURFACE: km_id = "Curve"; break;
+ case CTX_MODE_EDIT_TEXT: km_id = "Font"; break;
+ case CTX_MODE_EDIT_ARMATURE: km_id = "Armature"; break;
+ case CTX_MODE_EDIT_METABALL: km_id = "Metaball"; break;
+ case CTX_MODE_EDIT_LATTICE: km_id = "Lattice"; break;
+ case CTX_MODE_POSE: km_id = "Pose"; break;
+ case CTX_MODE_SCULPT: km_id = "Sculpt"; break;
+ case CTX_MODE_PAINT_WEIGHT: km_id = "Weight Paint"; break;
+ case CTX_MODE_PAINT_VERTEX: km_id = "Vertex Paint"; break;
+ case CTX_MODE_PAINT_TEXTURE: km_id = "Image Paint"; break;
+ case CTX_MODE_PARTICLE: km_id = "Particle"; break;
+ case CTX_MODE_OBJECT: km_id = "Object Mode"; break;
+ case CTX_MODE_GPENCIL_PAINT: km_id = "Grease Pencil Stroke Paint Mode"; break;
+ case CTX_MODE_GPENCIL_EDIT: km_id = "Grease Pencil Stroke Edit Mode"; break;
+ case CTX_MODE_GPENCIL_SCULPT: km_id = "Grease Pencil Stroke Sculpt Mode"; break;
+ case CTX_MODE_GPENCIL_WEIGHT: km_id = "Grease Pencil Stroke Weight Mode"; break;
+ }
+ }
+ else if (sl->spacetype == SPACE_IMAGE) {
+ const SpaceImage *sima = (SpaceImage *)sl;
+ const eSpaceImage_Mode mode = sima->mode;
+ switch (mode) {
+ case SI_MODE_VIEW: km_id = "Image"; break;
+ case SI_MODE_PAINT: km_id = "Image Paint"; break;
+ case SI_MODE_MASK: km_id = "Mask Editing"; break;
+ case SI_MODE_UV: km_id = "UV Editor"; break;
+ }
+ }
+ else {
+ return NULL;
+ }
+
+ wmKeyMap *km = WM_keymap_find_all(C, km_id, 0, 0);
+ BLI_assert(km);
+ return km;
+}
+
/* Guess an appropriate keymap from the operator name */
/* Needs to be kept up to date with Keymap and Operator naming */
wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
@@ -89,7 +171,13 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
/* Window */
if (STRPREFIX(opname, "WM_OT")) {
- km = WM_keymap_find_all(C, "Window", 0, 0);
+ if (STREQ(opname, "WM_OT_tool_set_by_name")) {
+ km = WM_keymap_guess_from_context(C);
+ }
+
+ if (km == NULL) {
+ km = WM_keymap_find_all(C, "Window", 0, 0);
+ }
}
/* Screen & Render */
else if (STRPREFIX(opname, "SCREEN_OT") ||
@@ -209,10 +297,6 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
- /* Timeline */
- else if (STRPREFIX(opname, "TIME_OT")) {
- km = WM_keymap_find_all(C, "Timeline", sl->spacetype, 0);
- }
/* Image Editor */
else if (STRPREFIX(opname, "IMAGE_OT")) {
km = WM_keymap_find_all(C, "Image", sl->spacetype, 0);
@@ -325,4 +409,8 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
return km;
}
+void WM_keymap_fix_linking(void)
+{
+}
+
/** \} */
diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c
index 4e71001990d..020d08f35fa 100644
--- a/source/blender/windowmanager/intern/wm_menu_type.c
+++ b/source/blender/windowmanager/intern/wm_menu_type.c
@@ -27,6 +27,7 @@
#include "BLI_sys_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
@@ -34,8 +35,8 @@
#include "BLI_ghash.h"
#include "BKE_context.h"
-#include "BKE_library.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -99,6 +100,14 @@ void WM_menutype_free(void)
bool WM_menutype_poll(bContext *C, MenuType *mt)
{
+ /* If we're tagged, only use compatible. */
+ if (mt->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, mt->owner_id) == false) {
+ return false;
+ }
+ }
+
if (mt->poll != NULL) {
return mt->poll(C, mt);
}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index cfad1db132c..cb69d584372 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -39,9 +39,20 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "ED_select_utils.h"
+
#include "WM_api.h"
#include "WM_types.h"
+
+void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(ot->srna, "confirm", true, "Confirm", "Prompt for confirmation");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
/* default properties for fileselect */
void WM_operator_properties_filesel(
wmOperatorType *ot, int filter, short type, short action,
@@ -130,7 +141,9 @@ void WM_operator_properties_filesel(
static void wm_operator_properties_select_action_ex(wmOperatorType *ot, int default_action,
const EnumPropertyItem *select_actions)
{
- RNA_def_enum(ot->srna, "action", select_actions, default_action, "Action", "Selection action to execute");
+ PropertyRNA *prop;
+ prop = RNA_def_enum(ot->srna, "action", select_actions, default_action, "Action", "Selection action to execute");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void WM_operator_properties_select_action(wmOperatorType *ot, int default_action)
@@ -225,30 +238,61 @@ void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
}
/**
- * Use with #WM_gesture_border_invoke
+ * Use with #WM_gesture_box_invoke
*/
-void WM_operator_properties_gesture_border_ex(wmOperatorType *ot, bool deselect, bool extend)
+void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bool extend)
{
+ PropertyRNA *prop;
+
WM_operator_properties_border(ot);
if (deselect) {
- RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ prop = RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
if (extend) {
- RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
+ prop = RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
}
-void WM_operator_properties_gesture_border_select(wmOperatorType *ot)
+void WM_operator_properties_gesture_box_select(wmOperatorType *ot)
{
- WM_operator_properties_gesture_border_ex(ot, true, true);
+ WM_operator_properties_gesture_box_ex(ot, true, true);
}
-void WM_operator_properties_gesture_border(wmOperatorType *ot)
+void WM_operator_properties_gesture_box(wmOperatorType *ot)
{
- WM_operator_properties_gesture_border_ex(ot, false, false);
+ WM_operator_properties_gesture_box_ex(ot, false, false);
}
-void WM_operator_properties_gesture_border_zoom(wmOperatorType *ot)
+void WM_operator_properties_select_operation(wmOperatorType *ot)
+{
+ static const EnumPropertyItem select_mode_items[] = {
+ {SEL_OP_SET, "SET", 0, "New", ""},
+ {SEL_OP_ADD, "ADD", 0, "Add", ""},
+ {SEL_OP_SUB, "SUB", 0, "Subtract", ""},
+ {SEL_OP_XOR, "XOR", 0, "Difference", ""},
+ {SEL_OP_AND, "AND", 0, "Intersect", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ PropertyRNA *prop = RNA_def_enum(ot->srna, "mode", select_mode_items, SEL_OP_SET, "Mode", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* Some tools don't support XOR/AND. */
+void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
+{
+ static const EnumPropertyItem select_mode_items[] = {
+ {SEL_OP_SET, "SET", 0, "New", ""},
+ {SEL_OP_ADD, "ADD", 0, "Add", ""},
+ {SEL_OP_SUB, "SUB", 0, "Subtract", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ PropertyRNA *prop = RNA_def_enum(ot->srna, "mode", select_mode_items, SEL_OP_SET, "Mode", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot)
{
WM_operator_properties_border(ot);
@@ -322,7 +366,8 @@ void WM_operator_properties_gesture_circle_ex(wmOperatorType *ot, bool deselect)
RNA_def_int(ot->srna, "radius", radius_default, 1, INT_MAX, "Radius", "", 1, INT_MAX);
if (deselect) {
- RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ prop = RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
}
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index e9287d83a9a..54a09f7ce9a 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -42,10 +42,10 @@
#include "BKE_context.h"
#include "BKE_idprop.h"
-#include "BKE_library.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -62,6 +62,8 @@ static void wm_operatortype_free_macro(wmOperatorType *ot);
* \{ */
static GHash *global_ops_hash = NULL;
+/** Counter for operator-properties that should not be tagged with #OP_PROP_TAG_ADVANCED. */
+static int ot_prop_basic_count = -1;
wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
{
@@ -96,28 +98,33 @@ void WM_operatortype_iter(GHashIterator *ghi)
BLI_ghashIterator_init(ghi, global_ops_hash);
}
-/** \} */
-
/** \name Operator Type Append
* \{ */
-/* all ops in 1 list (for time being... needs evaluation later) */
-void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
+static wmOperatorType *wm_operatortype_append__begin(void)
{
- wmOperatorType *ot;
+ wmOperatorType *ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
+
+ BLI_assert(ot_prop_basic_count == -1);
- ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
+ RNA_def_struct_property_tags(ot->srna, rna_enum_operator_property_tags);
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
- opfunc(ot);
+ return ot;
+}
+static void wm_operatortype_append__end(wmOperatorType *ot)
+{
if (ot->name == NULL) {
CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname);
}
BLI_assert((ot->description == NULL) || (ot->description[0]));
+ /* Allow calling _begin without _end in operatortype creation. */
+ WM_operatortype_props_advanced_end(ot);
+
/* XXX All ops should have a description but for now allow them not to. */
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
@@ -125,23 +132,23 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
-void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
+/* all ops in 1 list (for time being... needs evaluation later) */
+void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
{
- wmOperatorType *ot;
+ wmOperatorType *ot = wm_operatortype_append__begin();
+ opfunc(ot);
+ wm_operatortype_append__end(ot);
+}
- ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
- ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
- /* Set the default i18n context now, so that opfunc can redefine it if needed! */
- RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
- ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
+void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
+{
+ wmOperatorType *ot = wm_operatortype_append__begin();
opfunc(ot, userdata);
- BLI_assert((ot->description == NULL) || (ot->description[0]));
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
- RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
-
- BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
+ wm_operatortype_append__end(ot);
}
+/** \} */
+
/* called on initialize WM_exit() */
void WM_operatortype_remove_ptr(wmOperatorType *ot)
@@ -207,6 +214,55 @@ void wm_operatortype_free(void)
}
/**
+ * Tag all operator-properties of \a ot defined after calling this, until
+ * the next #WM_operatortype_props_advanced_end call (if available), with
+ * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
+ *
+ * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
+ * all calls after the first one are ignored. Meaning all propereties defined after the
+ * first call are tagged as advanced.
+ *
+ * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
+ * called for all operators during registration (see #wm_operatortype_append__end).
+ */
+void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
+{
+ if (ot_prop_basic_count == -1) { /* Don't do anything if _begin was called before, but not _end */
+ ot_prop_basic_count = RNA_struct_count_properties(ot->srna);
+ }
+}
+
+/**
+ * Tags all operator-properties of \ot defined since the first #WM_operatortype_props_advanced_begin
+ * call, or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
+ * Note that this is called for all operators during registration (see #wm_operatortype_append__end).
+ * So it does not need to be explicitly called in operator-type definition.
+ */
+void WM_operatortype_props_advanced_end(wmOperatorType *ot)
+{
+ PointerRNA struct_ptr;
+ int counter = 0;
+
+ if (ot_prop_basic_count == -1) {
+ /* WM_operatortype_props_advanced_begin was not called. Don't do anything. */
+ return;
+ }
+
+ RNA_pointer_create(NULL, ot->srna, NULL, &struct_ptr);
+
+ RNA_STRUCT_BEGIN (&struct_ptr, prop)
+ {
+ counter++;
+ if (counter > ot_prop_basic_count) {
+ WM_operatortype_prop_tag(prop, OP_PROP_TAG_ADVANCED);
+ }
+ }
+ RNA_STRUCT_END;
+
+ ot_prop_basic_count = -1;
+}
+
+/**
* Remove memory of all previously executed tools.
*/
void WM_operatortype_last_properties_clear_all(void)
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 2008d388ad3..423d335c78b 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -54,6 +54,7 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BLT_translation.h"
@@ -72,13 +73,12 @@
#include "BKE_blender_version.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
-#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_report.h"
@@ -88,9 +88,12 @@
#include "BKE_idcode.h"
-#include "BIF_glutil.h" /* for paint cursor */
#include "BLF_api.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -99,8 +102,6 @@
#include "ED_undo.h"
#include "ED_view3d.h"
-#include "GPU_basic_shader.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -336,7 +337,7 @@ bool WM_operator_pystring_abbreviate(char *str, int str_len_max)
/* return NULL if no match is found */
#if 0
-static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
+static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
{
/* loop over all context items and do 2 checks
*
@@ -391,7 +392,7 @@ static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
/* use hard coded checks for now */
-static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
+static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
{
const char *member_id = NULL;
@@ -439,7 +440,7 @@ static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
switch (GS(((ID *)ptr->id.data)->name)) {
case ID_SCE:
{
- CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_GPencilBrush, ptr, CTX_data_active_gpencil_brush(C));
+ CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_Brush, ptr, CTX_data_active_gpencil_brush(C));
CTX_TEST_PTR_ID(C, "scene", ptr->id.data);
break;
}
@@ -477,6 +478,8 @@ static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
SpaceLink *space_data = CTX_wm_space_data(C);
CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data);
+ CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_View3DOverlay, ptr, space_data);
+ CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_View3DShading, ptr, space_data);
CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C));
CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C));
@@ -514,6 +517,11 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
return ret;
}
+const char *WM_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
+{
+ return wm_context_member_from_ptr(C, ptr);
+}
+
char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index)
{
char *lhs, *rhs, *ret;
@@ -755,47 +763,71 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN);
}
+struct EnumSearchMenu {
+ wmOperator *op; /* the operator that will be executed when selecting an item */
+
+ bool use_previews;
+ short prv_cols, prv_rows;
+};
/* generic enum search invoke popup */
-static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
+static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg)
{
- static char search[256] = "";
- wmEvent event;
+ struct EnumSearchMenu *search_menu = arg;
wmWindow *win = CTX_wm_window(C);
+ wmOperator *op = search_menu->op;
+ /* template_ID uses 4 * widget_unit for width, we use a bit more, some items may have a suffix to show */
+ const int width = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_cols : UI_searchbox_size_x();
+ const int height = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_rows : UI_searchbox_size_y();
+ static char search[256] = "";
uiBlock *block;
uiBut *but;
- wmOperator *op = (wmOperator *)arg_op;
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
search[0] = '\0';
+ BLI_assert(search_menu->use_previews || (search_menu->prv_cols == 0 && search_menu->prv_rows == 0));
#if 0 /* ok, this isn't so easy... */
uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_struct_ui_name(op->type->srna), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
#endif
but = uiDefSearchButO_ptr(block, op->type, op->ptr->data, search, 0, ICON_VIEWZOOM, sizeof(search),
- 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, "");
+ 10, 10, width, UI_UNIT_Y, search_menu->prv_rows, search_menu->prv_cols, "");
/* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), width, height, NULL, 0, 0, 0, 0, NULL);
UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
-
- wm_event_init_from_window(win, &event);
- event.type = EVT_BUT_OPEN;
- event.val = KM_PRESS;
- event.customdata = but;
- event.customdatafree = false;
- wm_event_add(win, &event);
+ UI_but_focus_on_enter_event(win, but);
return block;
}
+/**
+ * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
+ * be used as invoke callback directly since it needs additional info.
+ */
+int WM_enum_search_invoke_previews(
+ bContext *C, wmOperator *op, short prv_cols, short prv_rows)
+{
+ static struct EnumSearchMenu search_menu;
+
+ search_menu.op = op;
+ search_menu.use_previews = true;
+ search_menu.prv_cols = prv_cols;
+ search_menu.prv_rows = prv_rows;
+
+ UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu);
+
+ return OPERATOR_INTERFACE;
+}
int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- UI_popup_block_invoke(C, wm_enum_search_menu, op);
+ static struct EnumSearchMenu search_menu;
+ search_menu.op = op;
+ UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu);
return OPERATOR_INTERFACE;
}
@@ -831,6 +863,18 @@ int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event
return WM_operator_confirm_message(C, op, NULL);
}
+int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ const bool confirm = RNA_boolean_get(op->ptr, "confirm");
+ if (confirm) {
+ return WM_operator_confirm_message(C, op, NULL);
+ }
+ else {
+ return op->type->exec(C, op);
+ }
+}
+
+
/* op->invoke, opens fileselect if path property not set, otherwise executes */
int WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
@@ -888,6 +932,21 @@ wmOperator *WM_operator_last_redo(const bContext *C)
return op;
}
+IDProperty *WM_operator_last_properties_ensure_idprops(wmOperatorType *ot)
+{
+ if (ot->last_properties == NULL) {
+ IDPropertyTemplate val = {0};
+ ot->last_properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ }
+ return ot->last_properties;
+}
+
+void WM_operator_last_properties_ensure(wmOperatorType *ot, PointerRNA *ptr)
+{
+ IDProperty *props = WM_operator_last_properties_ensure_idprops(ot);
+ RNA_pointer_create(NULL, ot->srna, props, ptr);
+}
+
/**
* Use for drag & drop a path or name with operators invoke() function.
*/
@@ -999,13 +1058,17 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
if (op->type->flag & OPTYPE_MACRO) {
for (op = op->macro.first; op; op = op->next) {
- uiTemplateOperatorPropertyButs(C, layout, op, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ uiTemplateOperatorPropertyButs(
+ C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
+ UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
if (op->next)
uiItemS(layout);
}
}
else {
- uiTemplateOperatorPropertyButs(C, layout, op, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ uiTemplateOperatorPropertyButs(
+ C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
+ UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
}
UI_block_bounds_set_popup(block, 4, 0, 0);
@@ -1075,7 +1138,9 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
- uiTemplateOperatorPropertyButs(C, layout, op, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ uiTemplateOperatorPropertyButs(
+ C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
+ UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
/* clear so the OK button is left alone */
UI_block_func_set(block, NULL, NULL, NULL);
@@ -1115,7 +1180,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
/* since ui is defined the auto-layout args are not used */
- uiTemplateOperatorPropertyButs(C, layout, op, 'V', 0);
+ uiTemplateOperatorPropertyButs(C, layout, op, UI_BUT_LABEL_ALIGN_COLUMN, 0);
UI_block_func_set(block, NULL, NULL, NULL);
@@ -1188,7 +1253,7 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
/* if we don't have global undo, we can't do undo push for automatic redo,
* so we require manual OK clicking in this popup */
if (!do_redo || !(U.uiflag & USER_GLOBALUNDO))
- return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y);
+ return WM_operator_props_dialog_popup(C, op, 300, 20);
UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op, op);
@@ -1227,8 +1292,8 @@ int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int h
wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_props_dialog_popup");
data->op = op;
- data->width = width;
- data->height = height;
+ data->width = width * U.dpi_fac;
+ data->height = height * U.dpi_fac;
data->free_op = true; /* if this runs and gets registered we may want not to free it */
/* op is not executed until popup OK but is clicked */
@@ -1269,7 +1334,7 @@ static int wm_debug_menu_exec(bContext *C, wmOperator *op)
static int wm_debug_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
RNA_int_set(op->ptr, "debug_value", G.debug_value);
- return WM_operator_props_dialog_popup(C, op, 9 * UI_UNIT_X, UI_UNIT_Y);
+ return WM_operator_props_dialog_popup(C, op, 180, 20);
}
static void WM_OT_debug_menu(wmOperatorType *ot)
@@ -1327,40 +1392,11 @@ static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), vo
ED_region_tag_refresh_ui(ar_menu);
}
-static int wm_resource_check_prev(void)
-{
-
- const char *res = BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION, true);
-
- // if (res) printf("USER: %s\n", res);
-
-#if 0 /* ignore the local folder */
- if (res == NULL) {
- /* with a local dir, copying old files isn't useful since local dir get priority for config */
- res = BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_LOCAL, BLENDER_VERSION, true);
- }
-#endif
-
- // if (res) printf("LOCAL: %s\n", res);
- if (res) {
- return false;
- }
- else {
- return (BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION - 1, true) != NULL);
- }
-}
-
static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg))
{
uiBlock *block;
uiBut *but;
- uiLayout *layout, *split, *col;
uiStyle *style = UI_style_get();
- const struct RecentFile *recent;
- int i;
- MenuType *mt = WM_menutype_find("USERPREF_MT_splash", true);
- char url[96];
- const char *version_suffix = NULL;
#ifndef WITH_HEADLESS
extern char datatoc_splash_png[];
@@ -1391,7 +1427,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
#endif /* WITH_BUILDINFO */
#ifndef WITH_HEADLESS
- if (U.pixelsize == 2) {
+ if (U.dpi_fac > 1.0) {
ibuf = IMB_ibImageFromMemory((unsigned char *)datatoc_splash_2x_png,
datatoc_splash_2x_png_size, IB_rect, NULL, "<splash screen>");
}
@@ -1416,7 +1452,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
if (ibuf_template) {
const int x_expect = ibuf->x;
- const int y_expect = 230 * (int)U.pixelsize;
+ const int y_expect = 250 * (int)U.dpi_fac;
/* don't cover the header text */
if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4]));
@@ -1432,7 +1468,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
}
#endif
- block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
+ block = UI_block_begin(C, ar, "splash", UI_EMBOSS);
/* note on UI_BLOCK_NO_WIN_CLIP, the window size is not always synchronized
* with the OS when the splash shows, window clipping in this case gives
@@ -1440,112 +1476,85 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
- /* XXX splash scales with pixelsize, should become widget-units */
- but = uiDefBut(block, UI_BTYPE_IMAGE, 0, "", 0, 0.5f * U.widget_unit, U.pixelsize * 501, U.pixelsize * 282, ibuf, 0.0, 0.0, 0, 0, ""); /* button owns the imbuf now */
+ but = uiDefBut(block, UI_BTYPE_IMAGE, 0, "", 0, 0.5f * U.widget_unit, U.dpi_fac * 501, U.dpi_fac * 250, ibuf, 0.0, 0.0, 0, 0, ""); /* button owns the imbuf now */
UI_but_func_set(but, wm_block_splash_close, block, NULL);
UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL);
/* label for 'a' bugfix releases, or 'Release Candidate 1'...
- * avoids recreating splash for version updates */
- if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
- version_suffix = "Release Candidate";
+ * avoids recreating splash for version updates */
+ const char *version_suffix = NULL;
+
+ if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
+ version_suffix = " Alpha";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
+ version_suffix = " Beta";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
+ version_suffix = " Release Candidate";
}
else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
version_suffix = STRINGIFY(BLENDER_VERSION_CHAR);
}
- if (version_suffix != NULL && version_suffix[0]) {
+
+ char *version = BLI_sprintfN("Version %d.%d%s", BLENDER_VERSION / 100, BLENDER_VERSION % 100, version_suffix);
+
+ if (version != NULL && version[0]) {
/* placed after the version number in the image,
* placing y is tricky to match baseline */
- int x = 260 * U.pixelsize - (2 * UI_DPI_FAC);
- int y = 242 * U.pixelsize + (4 * UI_DPI_FAC);
- int w = 240 * U.pixelsize;
-
/* hack to have text draw 'text_sel' */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- but = uiDefBut(block, UI_BTYPE_LABEL, 0, version_suffix, x, y, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ int x = 202 * U.dpi_fac;
+ int y = 130 * U.dpi_fac;
+ int w = 240 * U.dpi_fac;
+
+
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, version, x, y, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
/* XXX, set internal flag - UI_SELECT */
UI_but_flag_enable(but, 1);
UI_block_emboss_set(block, UI_EMBOSS);
}
+ MEM_freeN(version);
+
#ifdef WITH_BUILDINFO
if (build_commit_timestamp != 0) {
- uiDefBut(block, UI_BTYPE_LABEL, 0, date_buf, U.pixelsize * 494 - date_width, U.pixelsize * 270, date_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, date_buf,
+ U.dpi_fac * 502 - date_width, U.dpi_fac * 237,
+ date_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 0);
label_delta = 12;
}
- uiDefBut(block, UI_BTYPE_LABEL, 0, hash_buf, U.pixelsize * 494 - hash_width, U.pixelsize * (270 - label_delta), hash_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, hash_buf,
+ U.dpi_fac * 502 - hash_width, U.dpi_fac * (237 - label_delta),
+ hash_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 0);
if (!STREQ(build_branch, "master")) {
char branch_buf[128] = "\0";
int branch_width;
BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch);
branch_width = (int)BLF_width(style->widgetlabel.uifont_id, branch_buf, sizeof(branch_buf)) + U.widget_unit;
- uiDefBut(block, UI_BTYPE_LABEL, 0, branch_buf, U.pixelsize * 494 - branch_width, U.pixelsize * (258 - label_delta), branch_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, branch_buf,
+ U.dpi_fac * 502 - branch_width, U.dpi_fac * (225 - label_delta),
+ branch_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 0);
}
#endif /* WITH_BUILDINFO */
- layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.pixelsize * 480, U.pixelsize * 110, 0, style);
+ uiLayout *layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, U.dpi_fac * 40, 0,
+ U.dpi_fac * 450, U.dpi_fac * 110, 0, style);
- UI_block_emboss_set(block, UI_EMBOSS);
- /* show the splash menu (containing interaction presets), using python */
+ MenuType *mt = WM_menutype_find("WM_MT_splash", true);
if (mt) {
UI_menutype_draw(C, mt, layout);
-
-// uiItemM(layout, "USERPREF_MT_keyconfigs", U.keyconfigstr, ICON_NONE);
- }
-
- UI_block_emboss_set(block, UI_EMBOSS_PULLDOWN);
- uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
-
- split = uiLayoutSplit(layout, 0.0f, false);
- col = uiLayoutColumn(split, false);
- uiItemL(col, IFACE_("Links"), ICON_NONE);
-#if 0
- uiItemStringO(col, IFACE_("Support an Open Animation Movie"), ICON_URL, "WM_OT_url_open", "url",
- "https://cloud.blender.org/join");
-#endif
- uiItemStringO(col, IFACE_("Donations"), ICON_URL, "WM_OT_url_open", "url",
- "http://www.blender.org/foundation/donation-payment/");
- uiItemStringO(col, IFACE_("Credits"), ICON_URL, "WM_OT_url_open", "url",
- "http://www.blender.org/about/credits/");
- BLI_snprintf(url, sizeof(url), "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d",
- BLENDER_VERSION / 100, BLENDER_VERSION % 100);
- uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url);
- uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url",
- "https://docs.blender.org/manual/en/dev/");
- uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org");
- if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
- BLI_snprintf(url, sizeof(url), "https://docs.blender.org/api/%d.%d"STRINGIFY(BLENDER_VERSION_CHAR),
- BLENDER_VERSION / 100, BLENDER_VERSION % 100);
- }
- else {
- BLI_snprintf(url, sizeof(url), "https://docs.blender.org/api/master");
- }
- uiItemStringO(col, IFACE_("Python API Reference"), ICON_URL, "WM_OT_url_open", "url", url);
- uiItemL(col, "", ICON_NONE);
-
- col = uiLayoutColumn(split, false);
-
- if (wm_resource_check_prev()) {
- uiItemO(col, NULL, ICON_NEW, "WM_OT_copy_prev_settings");
- uiItemS(col);
- }
-
- uiItemL(col, IFACE_("Recent"), ICON_NONE);
- for (recent = G.recent_files.first, i = 0; (i < 5) && (recent); recent = recent->next, i++) {
- const char *filename = BLI_path_basename(recent->filepath);
- uiItemStringO(col, filename,
- BLO_has_bfile_extension(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP,
- "WM_OT_open_mainfile", "filepath", recent->filepath);
- }
-
- uiItemS(col);
- uiItemO(col, NULL, ICON_RECOVER_LAST, "WM_OT_recover_last_session");
- uiItemL(col, "", ICON_NONE);
-
- mt = WM_menutype_find("USERPREF_MT_splash_footer", false);
- if (mt) {
- UI_menutype_draw(C, mt, uiLayoutColumn(layout, false));
}
UI_block_bounds_set_centered(block, 0);
@@ -1712,6 +1721,34 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot)
RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
}
+static int wm_call_panel_exec(bContext *C, wmOperator *op)
+{
+ char idname[BKE_ST_MAXNAME];
+ RNA_string_get(op->ptr, "name", idname);
+ const bool keep_open = RNA_boolean_get(op->ptr, "keep_open");
+
+ return UI_popover_panel_invoke(C, idname, keep_open, op->reports);
+}
+
+static void WM_OT_call_panel(wmOperatorType *ot)
+{
+ ot->name = "Call Panel";
+ ot->idname = "WM_OT_call_panel";
+ ot->description = "Call (draw) a pre-defined panel";
+
+ ot->exec = wm_call_panel_exec;
+ ot->poll = WM_operator_winactive;
+
+ ot->flag = OPTYPE_INTERNAL;
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "keep_open", true, "Keep Open", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/* ************ window / screen operator definitions ************** */
/* this poll functions is needed in place of WM_operator_winactive
@@ -1719,8 +1756,11 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot)
static bool wm_operator_winactive_normal(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
+ bScreen *screen;
- if (win == NULL || win->screen == NULL || win->screen->state != SCREENNORMAL)
+ if (win == NULL)
+ return 0;
+ if (!((screen = WM_window_get_active_screen(win)) && (screen->state == SCREENNORMAL)))
return 0;
return 1;
@@ -1731,19 +1771,29 @@ static void WM_OT_window_close(wmOperatorType *ot)
{
ot->name = "Close Window";
ot->idname = "WM_OT_window_close";
- ot->description = "Close the current Blender window";
+ ot->description = "Close the current window";
ot->exec = wm_window_close_exec;
ot->poll = WM_operator_winactive;
}
-static void WM_OT_window_duplicate(wmOperatorType *ot)
+static void WM_OT_window_new(wmOperatorType *ot)
{
- ot->name = "Duplicate Window";
- ot->idname = "WM_OT_window_duplicate";
- ot->description = "Duplicate the current Blender window";
+ ot->name = "New Window";
+ ot->idname = "WM_OT_window_new";
+ ot->description = "Create a new window";
- ot->exec = wm_window_duplicate_exec;
+ ot->exec = wm_window_new_exec;
+ ot->poll = wm_operator_winactive_normal;
+}
+
+static void WM_OT_window_new_main(wmOperatorType *ot)
+{
+ ot->name = "New Main Window";
+ ot->idname = "WM_OT_window_new_main";
+ ot->description = "Create a new main window with its own workspace and scene selection";
+
+ ot->exec = wm_window_new_main_exec;
ot->poll = wm_operator_winactive_normal;
}
@@ -1814,7 +1864,9 @@ static void WM_OT_console_toggle(wmOperatorType *ot)
*/
wmPaintCursor *WM_paint_cursor_activate(
- wmWindowManager *wm, bool (*poll)(bContext *C),
+ wmWindowManager *wm,
+ short space_type, short region_type,
+ bool (*poll)(bContext *C),
wmPaintCursorDraw draw, void *customdata)
{
wmPaintCursor *pc = MEM_callocN(sizeof(wmPaintCursor), "paint cursor");
@@ -1825,6 +1877,9 @@ wmPaintCursor *WM_paint_cursor_activate(
pc->poll = poll;
pc->draw = draw;
+ pc->space_type = space_type;
+ pc->region_type = region_type;
+
return pc;
}
@@ -1842,11 +1897,6 @@ bool WM_paint_cursor_end(wmWindowManager *wm, wmPaintCursor *handle)
return false;
}
-void *WM_paint_cursor_customdata_get(wmPaintCursor *pc)
-{
- return pc->customdata;
-}
-
/* *********************** radial control ****************** */
#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * UI_DPI_FAC)
@@ -1881,38 +1931,37 @@ static void radial_control_update_header(wmOperator *op, bContext *C)
ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
- if (sa) {
- if (hasNumInput(&rc->num_input)) {
- char num_str[NUM_STR_REP_LEN];
- outputNumInput(&rc->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, sizeof(msg), "%s: %s", RNA_property_ui_name(rc->prop), num_str);
- }
- else {
- const char *ui_name = RNA_property_ui_name(rc->prop);
- switch (rc->subtype) {
- case PROP_NONE:
- case PROP_DISTANCE:
- BLI_snprintf(msg, sizeof(msg), "%s: %0.4f", ui_name, rc->current_value);
- break;
- case PROP_PIXEL:
- BLI_snprintf(msg, sizeof(msg), "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
- break;
- case PROP_PERCENTAGE:
- BLI_snprintf(msg, sizeof(msg), "%s: %3.1f%%", ui_name, rc->current_value);
- break;
- case PROP_FACTOR:
- BLI_snprintf(msg, sizeof(msg), "%s: %1.3f", ui_name, rc->current_value);
- break;
- case PROP_ANGLE:
- BLI_snprintf(msg, sizeof(msg), "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
- break;
- default:
- BLI_snprintf(msg, sizeof(msg), "%s", ui_name); /* XXX: No value? */
- break;
- }
+ if (hasNumInput(&rc->num_input)) {
+ char num_str[NUM_STR_REP_LEN];
+ outputNumInput(&rc->num_input, num_str, &scene->unit);
+ BLI_snprintf(msg, sizeof(msg), "%s: %s", RNA_property_ui_name(rc->prop), num_str);
+ }
+ else {
+ const char *ui_name = RNA_property_ui_name(rc->prop);
+ switch (rc->subtype) {
+ case PROP_NONE:
+ case PROP_DISTANCE:
+ BLI_snprintf(msg, sizeof(msg), "%s: %0.4f", ui_name, rc->current_value);
+ break;
+ case PROP_PIXEL:
+ BLI_snprintf(msg, sizeof(msg), "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
+ break;
+ case PROP_PERCENTAGE:
+ BLI_snprintf(msg, sizeof(msg), "%s: %3.1f%%", ui_name, rc->current_value);
+ break;
+ case PROP_FACTOR:
+ BLI_snprintf(msg, sizeof(msg), "%s: %1.3f", ui_name, rc->current_value);
+ break;
+ case PROP_ANGLE:
+ BLI_snprintf(msg, sizeof(msg), "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
+ break;
+ default:
+ BLI_snprintf(msg, sizeof(msg), "%s", ui_name); /* XXX: No value? */
+ break;
}
- ED_area_headerprint(sa, msg);
}
+
+ ED_area_status_text(sa, msg);
}
static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *event)
@@ -1962,8 +2011,9 @@ static void radial_control_set_tex(RadialControl *rc)
if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data, rc->use_secondary_tex))) {
glGenTextures(1, &rc->gltex);
glBindTexture(GL_TEXTURE_2D, rc->gltex);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, ibuf->x, ibuf->y, 0,
- GL_ALPHA, GL_FLOAT, ibuf->rect_float);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, ibuf->x, ibuf->y, 0,
+ GL_RED, GL_FLOAT, ibuf->rect_float);
+ glBindTexture(GL_TEXTURE_2D, 0);
MEM_freeN(ibuf->rect_float);
MEM_freeN(ibuf);
}
@@ -1996,49 +2046,69 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
RNA_property_float_get_array(fill_ptr, fill_prop, col);
}
- glColor4f(col[0], col[1], col[2], alpha);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (rc->gltex) {
+
+ uint texCoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rc->gltex);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ GLint swizzleMask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR);
+
+ immUniformColor3fvAlpha(col, alpha);
+ immUniform1i("image", 0);
/* set up rotation if available */
if (rc->rot_prop) {
rot = RNA_property_float_get(&rc->rot_ptr, rc->rot_prop);
- glPushMatrix();
- glRotatef(RAD2DEGF(rot), 0, 0, 1);
+ GPU_matrix_push();
+ GPU_matrix_rotate_2d(RAD2DEGF(rot));
}
/* draw textured quad */
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex2f(-radius, -radius);
- glTexCoord2f(1, 0);
- glVertex2f(radius, -radius);
- glTexCoord2f(1, 1);
- glVertex2f(radius, radius);
- glTexCoord2f(0, 1);
- glVertex2f(-radius, radius);
- glEnd();
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+
+ immAttr2f(texCoord, 0, 0);
+ immVertex2f(pos, -radius, -radius);
+
+ immAttr2f(texCoord, 1, 0);
+ immVertex2f(pos, radius, -radius);
+
+ immAttr2f(texCoord, 1, 1);
+ immVertex2f(pos, radius, radius);
+
+ immAttr2f(texCoord, 0, 1);
+ immVertex2f(pos, -radius, radius);
+
+ immEnd();
/* undo rotation */
if (rc->rot_prop)
- glPopMatrix();
+ GPU_matrix_pop();
}
else {
/* flat color if no texture available */
- glutil_draw_filled_arc(0, M_PI * 2, radius, 40);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(col, alpha);
+ imm_draw_circle_fill_2d(pos, 0.0f, 0.0f, radius, 40);
}
+
+ immUnbindProgram();
}
-static void radial_control_paint_cursor(bContext *C, int x, int y, void *customdata)
+static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void *customdata)
{
RadialControl *rc = customdata;
- ARegion *ar = CTX_wm_region(C);
uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
const int fontid = fstyle->uifont_id;
@@ -2089,9 +2159,9 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
}
/* Keep cursor in the original place */
- x = rc->initial_mouse[0] - ar->winrct.xmin;
- y = rc->initial_mouse[1] - ar->winrct.ymin;
- glTranslatef((float)x, (float)y, 0.0f);
+ x = rc->initial_mouse[0];
+ y = rc->initial_mouse[1];
+ GPU_matrix_translate_2f((float)x, (float)y);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
@@ -2099,7 +2169,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
/* apply zoom if available */
if (rc->zoom_prop) {
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
- glScalef(zoom[0], zoom[1], 1);
+ GPU_matrix_scale_2fv(zoom);
}
/* draw rotated texture */
@@ -2108,24 +2178,39 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
/* set line color */
if (rc->col_prop)
RNA_property_float_get_array(&rc->col_ptr, rc->col_prop, col);
- glColor4f(col[0], col[1], col[2], 0.5);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(col, 0.5f);
if (rc->subtype == PROP_ANGLE) {
- glPushMatrix();
+ GPU_matrix_push();
+
/* draw original angle line */
- glRotatef(RAD2DEGF(rc->initial_value), 0, 0, 1);
- fdrawline((float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
+ GPU_matrix_rotate_2d(RAD2DEGF(rc->initial_value));
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f);
+ immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
+ immEnd();
+
/* draw new angle line */
- glRotatef(RAD2DEGF(rc->current_value - rc->initial_value), 0, 0, 1);
- fdrawline((float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
- glPopMatrix();
+ GPU_matrix_rotate_2d(RAD2DEGF(rc->current_value - rc->initial_value));
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f);
+ immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
+ immEnd();
+
+ GPU_matrix_pop();
}
/* draw circles on top */
- glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), r1, 40);
- glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), r2, 40);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 40);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 40);
if (rmin > 0.0f)
- glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), rmin, 40);
+ imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 40);
+ immUnbindProgram();
BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi);
BLF_enable(fontid, BLF_SHADOW);
@@ -2141,6 +2226,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
+
}
typedef enum {
@@ -2376,8 +2462,11 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve
BLI_listbase_clear(&wm->paintcursors);
/* add radial control paint cursor */
- rc->cursor = WM_paint_cursor_activate(wm, op->type->poll,
- radial_control_paint_cursor, rc);
+ rc->cursor = WM_paint_cursor_activate(
+ wm,
+ SPACE_TYPE_ANY, RGN_TYPE_ANY,
+ op->type->poll,
+ radial_control_paint_cursor, rc);
WM_event_add_modal_handler(C, op);
@@ -2409,9 +2498,7 @@ static void radial_control_cancel(bContext *C, wmOperator *op)
rc->dial = NULL;
}
- if (sa) {
- ED_area_headerprint(sa, NULL);
- }
+ ED_area_status_text(sa, NULL);
WM_paint_cursor_end(wm, rc->cursor);
@@ -2713,6 +2800,7 @@ static const EnumPropertyItem redraw_timer_type_items[] = {
static void redraw_timer_step(
bContext *C, Main *bmain, Scene *scene,
+ struct Depsgraph *depsgraph,
wmWindow *win, ScrArea *sa, ARegion *ar,
const int type, const int cfra)
{
@@ -2731,16 +2819,17 @@ static void redraw_timer_step(
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
}
else if (type == eRTDrawWindow) {
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa_iter;
CTX_wm_menu_set(C, NULL);
- for (sa_iter = win->screen->areabase.first; sa_iter; sa_iter = sa_iter->next) {
+ for (sa_iter = screen->areabase.first; sa_iter; sa_iter = sa_iter->next) {
ARegion *ar_iter;
CTX_wm_area_set(C, sa_iter);
for (ar_iter = sa_iter->regionbase.first; ar_iter; ar_iter = ar_iter->next) {
- if (ar_iter->swinid) {
+ if (ar_iter->visible) {
CTX_wm_region_set(C, ar_iter);
ED_region_do_draw(C, ar_iter);
ar_iter->do_draw = false;
@@ -2758,7 +2847,7 @@ static void redraw_timer_step(
}
else if (type == eRTAnimationStep) {
scene->r.cfra += (cfra == scene->r.cfra) ? 1 : -1;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
else if (type == eRTAnimationPlay) {
/* play anim, return on same frame as started with */
@@ -2770,7 +2859,7 @@ static void redraw_timer_step(
if (scene->r.cfra > scene->r.efra)
scene->r.cfra = scene->r.sfra;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
redraw_timer_window_swap(C);
}
}
@@ -2794,13 +2883,14 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
const int cfra = scene->r.cfra;
int a, iter_steps = 0;
const char *infostr = "";
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
WM_cursor_wait(1);
time_start = PIL_check_seconds_timer();
for (a = 0; a < iter; a++) {
- redraw_timer_step(C, bmain, scene, win, sa, ar, type, cfra);
+ redraw_timer_step(C, bmain, scene, depsgraph, win, sa, ar, type, cfra);
iter_steps += 1;
if (time_limit != 0.0) {
@@ -2858,28 +2948,6 @@ static void WM_OT_memory_statistics(wmOperatorType *ot)
ot->exec = memory_statistics_exec;
}
-/* ************************** memory statistics for testing ***************** */
-
-static int dependency_relations_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
-
- DAG_print_dependencies(bmain, scene, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_dependency_relations(wmOperatorType *ot)
-{
- ot->name = "Dependency Relations";
- ot->idname = "WM_OT_dependency_relations";
- ot->description = "Print dependency graph relations to the console";
-
- ot->exec = dependency_relations_exec;
-}
-
/* *************************** Mat/tex/etc. previews generation ************* */
typedef struct PreviewsIDEnsureData {
@@ -2972,7 +3040,7 @@ static const EnumPropertyItem preview_id_type_items[] = {
{FILTER_ID_GR, "GROUP", 0, "Groups", ""},
{FILTER_ID_OB, "OBJECT", 0, "Objects", ""},
{FILTER_ID_MA, "MATERIAL", 0, "Materials", ""},
- {FILTER_ID_LA, "LAMP", 0, "Lamps", ""},
+ {FILTER_ID_LA, "LIGHT", 0, "Lights", ""},
{FILTER_ID_WO, "WORLD", 0, "Worlds", ""},
{FILTER_ID_TE, "TEXTURE", 0, "Textures", ""},
{FILTER_ID_IM, "IMAGE", 0, "Images", ""},
@@ -2985,7 +3053,7 @@ static const EnumPropertyItem preview_id_type_items[] = {
static int previews_clear_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- ListBase *lb[] = {&bmain->object, &bmain->group,
+ ListBase *lb[] = {&bmain->object, &bmain->collection,
&bmain->mat, &bmain->world, &bmain->lamp, &bmain->tex, &bmain->image, NULL};
int i;
@@ -3063,8 +3131,6 @@ static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot)
}
/* ******************************************************* */
-
-/* ******************************************************* */
/* toggle 3D for current window, turning it fullscreen if needed */
static void WM_OT_stereo3d_set(wmOperatorType *ot)
{
@@ -3098,7 +3164,8 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
void wm_operatortypes_register(void)
{
WM_operatortype_append(WM_OT_window_close);
- WM_operatortype_append(WM_OT_window_duplicate);
+ WM_operatortype_append(WM_OT_window_new);
+ WM_operatortype_append(WM_OT_window_new_main);
WM_operatortype_append(WM_OT_read_history);
WM_operatortype_append(WM_OT_read_homefile);
WM_operatortype_append(WM_OT_read_factory_settings);
@@ -3120,13 +3187,13 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_save_mainfile);
WM_operatortype_append(WM_OT_redraw_timer);
WM_operatortype_append(WM_OT_memory_statistics);
- WM_operatortype_append(WM_OT_dependency_relations);
WM_operatortype_append(WM_OT_debug_menu);
WM_operatortype_append(WM_OT_operator_defaults);
WM_operatortype_append(WM_OT_splash);
WM_operatortype_append(WM_OT_search_menu);
WM_operatortype_append(WM_OT_call_menu);
WM_operatortype_append(WM_OT_call_menu_pie);
+ WM_operatortype_append(WM_OT_call_panel);
WM_operatortype_append(WM_OT_radial_control);
WM_operatortype_append(WM_OT_stereo3d_set);
#if defined(WIN32)
@@ -3135,6 +3202,10 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_previews_ensure);
WM_operatortype_append(WM_OT_previews_clear);
WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
+
+ /* gizmos */
+ WM_operatortype_append(GIZMOGROUP_OT_gizmo_select);
+ WM_operatortype_append(GIZMOGROUP_OT_gizmo_tweak);
}
/* circleselect-like modal operators */
@@ -3162,41 +3233,15 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "View3D Gesture Circle", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
-
- WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CONFIRM);
- WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, 0, 0, GESTURE_MODAL_CONFIRM);
-
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_SELECT);
-
- /* Note: use 'KM_ANY' for release, so the circle exits on any mouse release,
- * this is needed when circle select is activated as a tool. */
-
- /* left mouse shift for deselect too */
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_DESELECT);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_NOP);
-
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_DESELECT); // default 2.4x
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_NOP); // default 2.4x
-
- WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB);
- WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB);
- WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_ADD);
- WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_ADD);
- WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, GESTURE_MODAL_CIRCLE_SIZE);
-
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_circle");
- WM_modalkeymap_assign(keymap, "UV_OT_circle_select");
+ WM_modalkeymap_assign(keymap, "UV_OT_select_circle");
WM_modalkeymap_assign(keymap, "CLIP_OT_select_circle");
WM_modalkeymap_assign(keymap, "MASK_OT_select_circle");
WM_modalkeymap_assign(keymap, "NODE_OT_select_circle");
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle");
WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle");
WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle");
-
}
/* straight line modal operators */
@@ -3216,13 +3261,6 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "Gesture Straight Line", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
-
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT);
-
/* assign map to operators */
WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line");
WM_modalkeymap_assign(keymap, "PAINT_OT_weight_gradient");
@@ -3230,8 +3268,8 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf)
}
-/* borderselect-like modal operators */
-static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
+/* box_select-like modal operators */
+static void gesture_box_modal_keymap(wmKeyConfig *keyconf)
{
static const EnumPropertyItem modal_items[] = {
{GESTURE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
@@ -3241,59 +3279,41 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL}
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Border");
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Box");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) return;
- keymap = WM_modalkeymap_add(keyconf, "Gesture Border", modal_items);
-
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
-
- /* Note: cancel only on press otherwise you cannot map this to RMB-gesture */
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT);
-
- /* allow shift leftclick for deselect too */
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_BEGIN);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_SHIFT, 0, GESTURE_MODAL_DESELECT);
-
- /* any unhandled leftclick release handles select */
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT);
-
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_DESELECT);
+ keymap = WM_modalkeymap_add(keyconf, "Gesture Box", modal_items);
/* assign map to operators */
- WM_modalkeymap_assign(keymap, "ACTION_OT_select_border");
- WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_border");
+ WM_modalkeymap_assign(keymap, "ACTION_OT_select_box");
+ WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_box");
WM_modalkeymap_assign(keymap, "ANIM_OT_previewrange_set");
- WM_modalkeymap_assign(keymap, "INFO_OT_select_border");
- WM_modalkeymap_assign(keymap, "FILE_OT_select_border");
- WM_modalkeymap_assign(keymap, "GRAPH_OT_select_border");
- WM_modalkeymap_assign(keymap, "MARKER_OT_select_border");
- WM_modalkeymap_assign(keymap, "NLA_OT_select_border");
- WM_modalkeymap_assign(keymap, "NODE_OT_select_border");
+ WM_modalkeymap_assign(keymap, "INFO_OT_select_box");
+ WM_modalkeymap_assign(keymap, "FILE_OT_select_box");
+ WM_modalkeymap_assign(keymap, "GRAPH_OT_select_box");
+ WM_modalkeymap_assign(keymap, "MARKER_OT_select_box");
+ WM_modalkeymap_assign(keymap, "NLA_OT_select_box");
+ WM_modalkeymap_assign(keymap, "NODE_OT_select_box");
WM_modalkeymap_assign(keymap, "NODE_OT_viewer_border");
WM_modalkeymap_assign(keymap, "PAINT_OT_hide_show");
- WM_modalkeymap_assign(keymap, "OUTLINER_OT_select_border");
-// WM_modalkeymap_assign(keymap, "SCREEN_OT_border_select"); // template
- WM_modalkeymap_assign(keymap, "SEQUENCER_OT_select_border");
+ WM_modalkeymap_assign(keymap, "OUTLINER_OT_select_box");
+// WM_modalkeymap_assign(keymap, "SCREEN_OT_box_select"); // template
+ WM_modalkeymap_assign(keymap, "SEQUENCER_OT_select_box");
WM_modalkeymap_assign(keymap, "SEQUENCER_OT_view_ghost_border");
- WM_modalkeymap_assign(keymap, "UV_OT_select_border");
- WM_modalkeymap_assign(keymap, "CLIP_OT_select_border");
- WM_modalkeymap_assign(keymap, "CLIP_OT_graph_select_border");
- WM_modalkeymap_assign(keymap, "MASK_OT_select_border");
+ WM_modalkeymap_assign(keymap, "UV_OT_select_box");
+ WM_modalkeymap_assign(keymap, "CLIP_OT_select_box");
+ WM_modalkeymap_assign(keymap, "CLIP_OT_graph_select_box");
+ WM_modalkeymap_assign(keymap, "MASK_OT_select_box");
WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
- WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
+// WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border"); /* TODO */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
- WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border");
+ WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_box");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */
WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
- WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_border");
+ WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_box");
}
/* zoom to border modal operators */
@@ -3314,16 +3334,6 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
keymap = WM_modalkeymap_add(keyconf, "Gesture Zoom Border", modal_items);
- /* items for modal map */
- WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
- WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
-
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_IN);
-
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
- WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_OUT);
-
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
@@ -3333,118 +3343,15 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
/* default keymap for windows and screens, only call once per WM */
void wm_window_keymap(wmKeyConfig *keyconf)
{
- wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Window", 0, 0);
- wmKeyMapItem *kmi;
-
- /* note, this doesn't replace existing keymap items */
- WM_keymap_verify_item(keymap, "WM_OT_window_duplicate", WKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
-#ifdef __APPLE__
- WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0);
- WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_OSKEY, 0);
-#endif
- WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "WM_OT_link", OKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_add_item(keymap, "WM_OT_append", F1KEY, KM_PRESS, KM_SHIFT, 0);
-
- WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "WM_OT_save_mainfile", WKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
- WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", F2KEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "copy", true);
-
- WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", F11KEY, KM_PRESS, KM_ALT, 0);
- WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_CTRL, 0);
-
- WM_keymap_add_item(keymap, "WM_OT_doc_view_manual_ui_context", F1KEY, KM_PRESS, KM_ALT, 0);
-
- /* debug/testing */
- WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
- WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
-
- /* menus that can be accessed anywhere in blender */
- WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0);
-#ifdef WITH_INPUT_NDOF
- WM_keymap_add_menu(keymap, "USERPREF_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0);
-#endif
-
- /* Space switching */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F2KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was DXF export */
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "LOGIC_EDITOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F3KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "NODE_EDITOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F4KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was data browser */
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "CONSOLE");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F5KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "VIEW_3D");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F6KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "GRAPH_EDITOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F7KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "PROPERTIES");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F8KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "SEQUENCE_EDITOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F9KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "OUTLINER");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F10KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "IMAGE_EDITOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F11KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "TEXT_EDITOR");
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F12KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "DOPESHEET_EDITOR");
-
-#ifdef WITH_INPUT_NDOF
- /* ndof speed */
- const char *data_path = "user_preferences.inputs.ndof_sensitivity";
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_scale_float", NDOF_BUTTON_PLUS, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", data_path);
- RNA_float_set(kmi->ptr, "value", 1.1f);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_scale_float", NDOF_BUTTON_MINUS, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", data_path);
- RNA_float_set(kmi->ptr, "value", 1.0f / 1.1f);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_scale_float", NDOF_BUTTON_PLUS, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", data_path);
- RNA_float_set(kmi->ptr, "value", 1.5f);
-
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_scale_float", NDOF_BUTTON_MINUS, KM_PRESS, KM_SHIFT, 0);
- RNA_string_set(kmi->ptr, "data_path", data_path);
- RNA_float_set(kmi->ptr, "value", 1.0f / 1.5f);
-#endif /* WITH_INPUT_NDOF */
+ WM_keymap_ensure(keyconf, "Window", 0, 0);
+ wm_gizmos_keymap(keyconf);
gesture_circle_modal_keymap(keyconf);
- gesture_border_modal_keymap(keyconf);
+ gesture_box_modal_keymap(keyconf);
gesture_zoom_border_modal_keymap(keyconf);
gesture_straightline_modal_keymap(keyconf);
+
+ WM_keymap_fix_linking();
}
/**
@@ -3496,13 +3403,13 @@ const EnumPropertyItem *RNA_action_local_itemf(bContext *C, PointerRNA *ptr, Pro
}
#endif
-const EnumPropertyItem *RNA_group_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+const EnumPropertyItem *RNA_collection_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
- return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->group.first : NULL, false, NULL, NULL);
+ return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->collection.first : NULL, false, NULL, NULL);
}
-const EnumPropertyItem *RNA_group_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+const EnumPropertyItem *RNA_collection_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
- return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->group.first : NULL, true, NULL, NULL);
+ return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->collection.first : NULL, true, NULL, NULL);
}
const EnumPropertyItem *RNA_image_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
diff --git a/source/blender/windowmanager/intern/wm_panel_type.c b/source/blender/windowmanager/intern/wm_panel_type.c
new file mode 100644
index 00000000000..2c541db55a6
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_panel_type.c
@@ -0,0 +1,88 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_panel_type.c
+ * \ingroup wm
+ *
+ * Panel Registry.
+ *
+ * \note Unlike menu, and other registries, this doesn't *own* the PanelType.
+ *
+ * For popups/popovers only, regions handle panel types by including them in local lists.
+ */
+
+#include <stdio.h>
+
+#include "BLI_sys_types.h"
+
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "BKE_screen.h"
+
+#include "WM_api.h"
+
+static GHash *g_paneltypes_hash = NULL;
+
+PanelType *WM_paneltype_find(const char *idname, bool quiet)
+{
+ PanelType *pt;
+
+ if (idname[0]) {
+ pt = BLI_ghash_lookup(g_paneltypes_hash, idname);
+ if (pt)
+ return pt;
+ }
+
+ if (!quiet)
+ printf("search for unknown paneltype %s\n", idname);
+
+ return NULL;
+}
+
+bool WM_paneltype_add(PanelType *pt)
+{
+ BLI_ghash_insert(g_paneltypes_hash, pt->idname, pt);
+ return true;
+}
+
+void WM_paneltype_remove(PanelType *pt)
+{
+ bool ok;
+
+ ok = BLI_ghash_remove(g_paneltypes_hash, pt->idname, NULL, NULL);
+
+ BLI_assert(ok);
+ (void)ok;
+}
+
+/* called on initialize WM_init() */
+void WM_paneltype_init(void)
+{
+ /* reserve size is set based on blender default setup */
+ g_paneltypes_hash = BLI_ghash_str_new_ex("g_paneltypes_hash gh", 512);
+}
+
+void WM_paneltype_clear(void)
+{
+ BLI_ghash_free(g_paneltypes_hash, NULL, NULL);
+}
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index f2c24858e17..6317cca8094 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -61,24 +61,31 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_matrix.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_context.h"
+#include "GPU_init_exit.h"
+
#include "DNA_scene_types.h"
#include "ED_datafiles.h" /* for fonts */
#include "GHOST_C-api.h"
#include "BLF_api.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h" /* only for WM_main_playanim */
#ifdef WITH_AUDASPACE
-# include AUD_DEVICE_H
-# include AUD_HANDLE_H
-# include AUD_SOUND_H
-# include AUD_SPECIAL_H
+# include <AUD_Device.h>
+# include <AUD_Handle.h>
+# include <AUD_Sound.h>
+# include <AUD_Special.h>
static AUD_Sound *source = NULL;
static AUD_Handle *playback_handle = NULL;
@@ -180,6 +187,7 @@ typedef enum eWS_Qual {
static struct WindowStateGlobal {
GHOST_SystemHandle ghost_system;
void *ghost_window;
+ GPUContext *gpu_context;
/* events */
eWS_Qual qual;
@@ -196,10 +204,8 @@ static void playanim_window_get_size(int *r_width, int *r_height)
static void playanim_gl_matrix(void)
{
/* unified matrix, note it affects offset for drawing */
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
- glMatrixMode(GL_MODELVIEW);
+ /* note! cannot use GPU_matrix_ortho_2d_set here because shader ignores. */
+ GPU_matrix_ortho_set(0.0f, 1.0f, 0.0f, 1.0f, -1.0, 1.0f);
}
/* implementation */
@@ -314,7 +320,6 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
CLAMP(offs_x, 0.0f, 1.0f);
CLAMP(offs_y, 0.0f, 1.0f);
- glRasterPos2f(offs_x, offs_y);
glClearColor(0.1, 0.1, 0.1, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
@@ -322,18 +327,22 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
/* checkerboard for case alpha */
if (ibuf->planes == 32) {
glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- fdrawcheckerboard(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
+ imm_draw_box_checker_2d(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
}
- glRasterPos2f(offs_x + (ps->draw_flip[0] ? span_x : 0.0f),
- offs_y + (ps->draw_flip[1] ? span_y : 0.0f));
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- glPixelZoom(ps->zoom * (ps->draw_flip[0] ? -1.0f : 1.0f),
- ps->zoom * (ps->draw_flip[1] ? -1.0f : 1.0f));
-
- glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ immDrawPixelsTex(
+ &state,
+ offs_x + (ps->draw_flip[0] ? span_x : 0.0f),
+ offs_y + (ps->draw_flip[1] ? span_y : 0.0f),
+ ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST,
+ ibuf->rect,
+ ((ps->draw_flip[0] ? -1.0f : 1.0f)) * (ps->zoom / (float)ps->win_x),
+ ((ps->draw_flip[1] ? -1.0f : 1.0f)) * (ps->zoom / (float)ps->win_y),
+ NULL);
glDisable(GL_BLEND);
@@ -343,13 +352,13 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
int sizex, sizey;
float fsizex_inv, fsizey_inv;
char str[32 + FILE_MAX];
- cpack(-1);
BLI_snprintf(str, sizeof(str), "%s | %.2f frames/s", picture->name, fstep / swaptime);
playanim_window_get_size(&sizex, &sizey);
fsizex_inv = 1.0f / sizex;
fsizey_inv = 1.0f / sizey;
+ BLF_color4f(fontid, 1.0, 1.0, 1.0, 1.0);
BLF_enable(fontid, BLF_ASPECT);
BLF_aspect(fontid, fsizex_inv, fsizey_inv, 1.0f);
BLF_position(fontid, 10.0f * fsizex_inv, 10.0f * fsizey_inv, 0.0f);
@@ -360,24 +369,25 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
float fac = ps->picture->frame / (double)(((PlayAnimPict *)picsbase.last)->frame - ((PlayAnimPict *)picsbase.first)->frame);
fac = 2.0f * fac - 1.0f;
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
-
- glBegin(GL_LINES);
- glVertex2f(fac, -1.0f);
- glVertex2f(fac, 1.0f);
- glEnd();
-
- glPopMatrix();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ GPU_matrix_push_projection();
+ GPU_matrix_identity_projection_set();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(0, 255, 0);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, fac, -1.0f);
+ immVertex2f(pos, fac, 1.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
}
GHOST_SwapWindowBuffers(g_WS.ghost_window);
@@ -1273,6 +1283,11 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
//GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
+ /* initialize OpenGL immediate mode */
+ g_WS.gpu_context = GPU_context_create();
+ GPU_init();
+ immActivate();
+
/* initialize the font */
BLF_init();
ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
@@ -1538,8 +1553,19 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
/* we still miss freeing a lot!,
* but many areas could skip initialization too for anim play */
+ GPU_shader_free_builtin_shaders();
+
+ if (g_WS.gpu_context) {
+ GPU_context_active_set(g_WS.gpu_context);
+ GPU_context_discard(g_WS.gpu_context);
+ g_WS.gpu_context = NULL;
+ }
+
BLF_exit();
+ immDeactivate();
+ GPU_exit();
+
GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);
/* early exit, IMB and BKE should be exited only in end */
@@ -1550,7 +1576,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
IMB_exit();
BKE_images_exit();
- DAG_exit();
+ DEG_free_node_types();
totblock = MEM_get_memory_blocks_in_use();
if (totblock != 0) {
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 55fe2ec846c..6b6b3bc3cbb 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -52,90 +52,86 @@
#include "ED_screen.h"
-#include "GPU_glew.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
-#include "wm_draw.h" /* wmDrawTriple */
+#include "wm_draw.h"
#include "wm_window.h"
#include "UI_interface.h"
#include "UI_resources.h"
-static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
+static GPUInterlaceShader interlace_gpu_id_from_type(eStereo3dInterlaceType interlace_type)
{
- wmDrawData *drawdata;
- int view;
+ switch (interlace_type) {
+ case S3D_INTERLACE_ROW:
+ return GPU_SHADER_INTERLACE_ROW;
+ case S3D_INTERLACE_COLUMN:
+ return GPU_SHADER_INTERLACE_COLUMN;
+ case S3D_INTERLACE_CHECKERBOARD:
+ default:
+ return GPU_SHADER_INTERLACE_CHECKER;
+ }
+}
+
+void wm_stereo3d_draw_interlace(wmWindow *win, ARegion *ar)
+{
+ bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0;
+ enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type;
- for (view = 0; view < 2; view ++) {
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+ /* wmOrtho for the screen has this same offset */
+ float halfx = GLA_PIXEL_OFS / ar->winx;
+ float halfy = GLA_PIXEL_OFS / ar->winy;
- if (view == STEREO_LEFT_ID)
- glDrawBuffer(GL_BACK_LEFT);
- else //STEREO_RIGHT_ID
- glDrawBuffer(GL_BACK_RIGHT);
+ GPUVertFormat *format = immVertexFormat();
+ uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
+ /* leave GL_TEXTURE0 as the latest active texture */
+ for (int view = 1; view >= 0; view--) {
+ GPUTexture *texture = wm_draw_region_texture(ar, view);
+ glActiveTexture(GL_TEXTURE0 + view);
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
}
- glDrawBuffer(GL_BACK);
-}
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_INTERLACE);
+ immUniform1i("image_a", (swap) ? 1 : 0);
+ immUniform1i("image_b", (swap) ? 0 : 1);
-static enum eStereo3dInterlaceType interlace_prev_type = -1;
-static char interlace_prev_swap = -1;
+ immUniform1i("interlace_id", interlace_gpu_id_from_type(interlace_type));
-static void wm_method_draw_stereo3d_interlace(wmWindow *win)
-{
- wmDrawData *drawdata;
- int view;
- bool flag;
- bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0;
- enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type;
+ immBegin(GPU_PRIM_TRI_FAN, 4);
- for (view = 0; view < 2; view ++) {
- flag = swap ? !view : view;
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE);
- switch (interlace_type) {
- case S3D_INTERLACE_ROW:
- if (flag)
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP);
- else
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW);
- break;
- case S3D_INTERLACE_COLUMN:
- if (flag)
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP);
- else
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN);
- break;
- case S3D_INTERLACE_CHECKERBOARD:
- default:
- if (flag)
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP);
- else
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER);
- break;
- }
+ immAttr2f(texcoord, halfx, halfy);
+ immVertex2f(pos, ar->winrct.xmin, ar->winrct.ymin);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, true);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immAttr2f(texcoord, 1.0f + halfx, halfy);
+ immVertex2f(pos, ar->winrct.xmax + 1, ar->winrct.ymin);
+
+ immAttr2f(texcoord, 1.0f + halfx, 1.0f + halfy);
+ immVertex2f(pos, ar->winrct.xmax + 1, ar->winrct.ymax + 1);
+
+ immAttr2f(texcoord, halfx, 1.0f + halfy);
+ immVertex2f(pos, ar->winrct.xmin, ar->winrct.ymax + 1);
+
+ immEnd();
+ immUnbindProgram();
+
+ for (int view = 1; view >= 0; view--) {
+ glActiveTexture(GL_TEXTURE0 + view);
+ glBindTexture(GL_TEXTURE_2D, 0);
}
- interlace_prev_type = interlace_type;
- interlace_prev_swap = swap;
}
-static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
+void wm_stereo3d_draw_anaglyph(wmWindow *win, ARegion *ar)
{
- wmDrawData *drawdata;
- int view, bit;
+ for (int view = 0; view < 2; view ++) {
+ int bit = view + 1;
- for (view = 0; view < 2; view ++) {
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
-
- bit = view + 1;
switch (win->stereo3d_format->anaglyph_type) {
case S3D_ANAGLYPH_REDCYAN:
glColorMask((1&bit) ? GL_TRUE : GL_FALSE,
@@ -157,162 +153,110 @@ static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
break;
}
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
-
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ wm_draw_region_blend(ar, view, false);
}
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
-static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
+void wm_stereo3d_draw_sidebyside(wmWindow *win, int view)
{
- wmDrawData *drawdata;
- wmDrawTriple *triple;
- float halfx, halfy, ratiox, ratioy;
- int view;
- int soffx;
bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0;
- for (view = 0; view < 2; view ++) {
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
- triple = drawdata->triple;
+ GPUVertFormat *format = immVertexFormat();
+ uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- soffx = WM_window_pixels_x(win) * 0.5f;
- if (view == STEREO_LEFT_ID) {
- if (!cross_eyed)
- soffx = 0;
- }
- else { //RIGHT_LEFT_ID
- if (cross_eyed)
- soffx = 0;
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE);
- const int sizex = triple->x;
- const int sizey = triple->y;
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x;
- ratioy /= triple->y;
- halfx /= triple->x;
- halfy /= triple->y;
- }
+ int soffx = WM_window_pixels_x(win) * 0.5f;
+ if (view == STEREO_LEFT_ID) {
+ if (!cross_eyed)
+ soffx = 0;
+ }
+ else { //RIGHT_LEFT_ID
+ if (cross_eyed)
+ soffx = 0;
+ }
- glEnable(triple->target);
- glBindTexture(triple->target, triple->bind);
+ const int sizex = WM_window_pixels_x(win);
+ const int sizey = WM_window_pixels_y(win);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(soffx, 0);
+ /* wmOrtho for the screen has this same offset */
+ const float halfx = GLA_PIXEL_OFS / sizex;
+ const float halfy = GLA_PIXEL_OFS / sizex;
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(soffx + (sizex * 0.5f), 0);
+ immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(soffx + (sizex * 0.5f), sizey);
+ immBegin(GPU_PRIM_TRI_FAN, 4);
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(soffx, sizey);
- glEnd();
+ immAttr2f(texcoord, halfx, halfy);
+ immVertex2f(pos, soffx, 0.0f);
- glBindTexture(triple->target, 0);
- glDisable(triple->target);
- }
+ immAttr2f(texcoord, 1.0f + halfx, halfy);
+ immVertex2f(pos, soffx + (sizex * 0.5f), 0.0f);
+
+ immAttr2f(texcoord, 1.0f + halfx, 1.0f + halfy);
+ immVertex2f(pos, soffx + (sizex * 0.5f), sizey);
+
+ immAttr2f(texcoord, halfx, 1.0f + halfy);
+ immVertex2f(pos, soffx, sizey);
+
+ immEnd();
+
+ immUnbindProgram();
}
-static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
+void wm_stereo3d_draw_topbottom(wmWindow *win, int view)
{
- wmDrawData *drawdata;
- wmDrawTriple *triple;
- float halfx, halfy, ratiox, ratioy;
- int view;
+ GPUVertFormat *format = immVertexFormat();
+ uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE);
+
int soffy;
+ if (view == STEREO_LEFT_ID) {
+ soffy = WM_window_pixels_y(win) * 0.5f;
+ }
+ else { /* STEREO_RIGHT_ID */
+ soffy = 0;
+ }
- for (view = 0; view < 2; view ++) {
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
- triple = drawdata->triple;
+ const int sizex = WM_window_pixels_x(win);
+ const int sizey = WM_window_pixels_y(win);
- if (view == STEREO_LEFT_ID) {
- soffy = WM_window_pixels_y(win) * 0.5f;
- }
- else { /* STEREO_RIGHT_ID */
- soffy = 0;
- }
+ /* wmOrtho for the screen has this same offset */
+ const float halfx = GLA_PIXEL_OFS / sizex;
+ const float halfy = GLA_PIXEL_OFS / sizex;
- const int sizex = triple->x;
- const int sizey = triple->y;
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x;
- ratioy /= triple->y;
- halfx /= triple->x;
- halfy /= triple->y;
- }
+ immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
- glEnable(triple->target);
- glBindTexture(triple->target, triple->bind);
+ immBegin(GPU_PRIM_TRI_FAN, 4);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(0, soffy);
+ immAttr2f(texcoord, halfx, halfy);
+ immVertex2f(pos, 0.0f, soffy);
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(sizex, soffy);
+ immAttr2f(texcoord, 1.0f + halfx, halfy);
+ immVertex2f(pos, sizex, soffy);
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(sizex, soffy + (sizey * 0.5f));
+ immAttr2f(texcoord, 1.0f + halfx, 1.0f + halfy);
+ immVertex2f(pos, sizex, soffy + (sizey * 0.5f));
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(0, soffy + (sizey * 0.5f));
- glEnd();
+ immAttr2f(texcoord, halfx, 1.0f + halfy);
+ immVertex2f(pos, 0.0f, soffy + (sizey * 0.5f));
- glBindTexture(triple->target, 0);
- glDisable(triple->target);
- }
-}
+ immEnd();
-void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win)
-{
- switch (win->stereo3d_format->display_mode) {
- case S3D_DISPLAY_ANAGLYPH:
- wm_method_draw_stereo3d_anaglyph(win);
- break;
- case S3D_DISPLAY_INTERLACE:
- wm_method_draw_stereo3d_interlace(win);
- break;
- case S3D_DISPLAY_PAGEFLIP:
- wm_method_draw_stereo3d_pageflip(win);
- break;
- case S3D_DISPLAY_SIDEBYSIDE:
- wm_method_draw_stereo3d_sidebyside(win);
- break;
- case S3D_DISPLAY_TOPBOTTOM:
- wm_method_draw_stereo3d_topbottom(win);
- break;
- default:
- break;
- }
+ immUnbindProgram();
}
+
static bool wm_stereo3d_quadbuffer_supported(void)
{
- int gl_stereo = 0;
- glGetBooleanv(GL_STEREO, (GLboolean *)&gl_stereo);
- return gl_stereo != 0;
+ GLboolean stereo = GL_FALSE;
+ glGetBooleanv(GL_STEREO, &stereo);
+ return stereo == GL_TRUE;
}
static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display)
@@ -324,7 +268,8 @@ static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display
bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
{
- bScreen *screen = win->screen;
+ const bScreen *screen = WM_window_get_active_screen(win);
+ const Scene *scene = WM_window_get_active_scene(win);
/* some 3d methods change the window arrangement, thus they shouldn't
* toggle on/off just because there is no 3d elements being drawn */
@@ -332,7 +277,7 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return GHOST_GetWindowState(win->ghostwin) == GHOST_kWindowStateFullScreen;
}
- if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen) == false)) {
+ if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen, scene) == false)) {
return false;
}
@@ -458,8 +403,8 @@ int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
if (prev_display_mode == S3D_DISPLAY_PAGEFLIP &&
prev_display_mode != win_src->stereo3d_format->display_mode)
{
- /* in case the hardward supports pageflip but not the display */
- if ((win_dst = wm_window_copy_test(C, win_src))) {
+ /* in case the hardware supports pageflip but not the display */
+ if ((win_dst = wm_window_copy_test(C, win_src, false, false))) {
/* pass */
}
else {
@@ -469,14 +414,16 @@ int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
}
}
else if (win_src->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
- /* ED_screen_duplicate() can't handle other cases yet T44688 */
- if (win_src->screen->state != SCREENNORMAL) {
+ const bScreen *screen = WM_window_get_active_screen(win_src);
+
+ /* ED_workspace_layout_duplicate() can't handle other cases yet T44688 */
+ if (screen->state != SCREENNORMAL) {
BKE_report(op->reports, RPT_ERROR,
"Failed to switch to Time Sequential mode when in fullscreen");
ok = false;
}
/* pageflip requires a new window to be created with the proper OS flags */
- else if ((win_dst = wm_window_copy_test(C, win_src))) {
+ else if ((win_dst = wm_window_copy_test(C, win_src, false, false))) {
if (wm_stereo3d_quadbuffer_supported()) {
BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created");
}
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 214e8bd84ce..ff3c712dae0 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -21,334 +21,87 @@
* Contributor(s): 2007 Blender Foundation (refactor)
*
* ***** END GPL LICENSE BLOCK *****
- *
- *
- * Subwindow opengl handling.
- * BTW: subwindows open/close in X11 are way too slow, tried it, and choose for my own system... (ton)
- *
*/
/** \file blender/windowmanager/intern/wm_subwindow.c
* \ingroup wm
*
- * Internal subwindows used for OpenGL state, used for regions and screens.
+ * OpenGL utilities for setting up 2D viewport for window and regions.
*/
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
-#include "DNA_windowmanager_types.h"
#include "DNA_screen_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "DNA_windowmanager_types.h"
#include "BIF_gl.h"
-#include "GPU_extensions.h"
-#include "GPU_basic_shader.h"
+#include "GPU_matrix.h"
#include "WM_api.h"
-#include "wm_subwindow.h"
-
-/**
- * \note #wmSubWindow stored in #wmWindow but not exposed outside this C file,
- * it seems a bit redundant (area regions can store it too, but we keep it
- * because we can store all kind of future opengl fanciness here.
- *
- * We use indices and array because:
- * - index has safety, no pointers from this C file hanging around
- * - fast lookups of indices with array, list would give overhead
- * - old code used it this way...
- * - keep option open to have 2 screens using same window
- */
-
-typedef struct wmSubWindow {
- struct wmSubWindow *next, *prev;
-
- rcti winrct;
- int swinid;
-} wmSubWindow;
-
-
-/* ******************* open, free, set, get data ******************** */
-
-/* not subwindow itself */
-static void wm_subwindow_free(wmSubWindow *UNUSED(swin))
-{
- /* future fancy stuff */
-}
-
-void wm_subwindows_free(wmWindow *win)
-{
- wmSubWindow *swin;
-
- for (swin = win->subwindows.first; swin; swin = swin->next)
- wm_subwindow_free(swin);
-
- BLI_freelistN(&win->subwindows);
-}
-
-
-int wm_subwindow_get_id(wmWindow *win)
-{
- if (win->curswin)
- return win->curswin->swinid;
- return 0;
-}
-
-static wmSubWindow *swin_from_swinid(wmWindow *win, int swinid)
-{
- wmSubWindow *swin;
-
- for (swin = win->subwindows.first; swin; swin = swin->next)
- if (swin->swinid == swinid)
- break;
- return swin;
-}
-
-
-static void wm_swin_size_get(wmSubWindow *swin, int *x, int *y)
-{
- *x = BLI_rcti_size_x(&swin->winrct) + 1;
- *y = BLI_rcti_size_y(&swin->winrct) + 1;
-}
-void wm_subwindow_size_get(wmWindow *win, int swinid, int *x, int *y)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
-
- if (swin) {
- wm_swin_size_get(swin, x, y);
- }
-}
-
-
-static void wm_swin_origin_get(wmSubWindow *swin, int *x, int *y)
-{
- *x = swin->winrct.xmin;
- *y = swin->winrct.ymin;
-}
-void wm_subwindow_origin_get(wmWindow *win, int swinid, int *x, int *y)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
-
- if (swin) {
- wm_swin_origin_get(swin, x, y);
- }
-}
-
-
-static void wm_swin_matrix_get(wmWindow *win, wmSubWindow *swin, float mat[4][4])
-{
- /* used by UI, should find a better way to get the matrix there */
- if (swin->swinid == win->screen->mainwin) {
- int width, height;
-
- wm_swin_size_get(swin, &width, &height);
- orthographic_m4(mat, -GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS, -100, 100);
- }
- else {
- glGetFloatv(GL_PROJECTION_MATRIX, (float *)mat);
- }
-}
-void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4])
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
- if (swin) {
- wm_swin_matrix_get(win, swin, mat);
- }
-}
-
-
-static void wm_swin_rect_get(wmSubWindow *swin, rcti *r_rect)
+void wmViewport(const rcti *winrct)
{
- *r_rect = swin->winrct;
-}
-void wm_subwindow_rect_get(wmWindow *win, int swinid, rcti *r_rect)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
+ int width = BLI_rcti_size_x(winrct) + 1;
+ int height = BLI_rcti_size_y(winrct) + 1;
- if (swin) {
- wm_swin_rect_get(swin, r_rect);
- }
-}
-
-
-static void wm_swin_rect_set(wmSubWindow *swin, const rcti *rect)
-{
- swin->winrct = *rect;
-}
-void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
-
- if (swin) {
- wm_swin_rect_set(swin, rect);
- }
-}
-
-
-/* always sets pixel-precise 2D window/view matrices */
-/* coords is in whole pixels. xmin = 15, xmax = 16: means window is 2 pix big */
-int wm_subwindow_open(wmWindow *win, const rcti *winrct, bool activate)
-{
- wmSubWindow *swin;
- int width, height;
- int freewinid = 1;
-
- for (swin = win->subwindows.first; swin; swin = swin->next)
- if (freewinid <= swin->swinid)
- freewinid = swin->swinid + 1;
-
- win->curswin = swin = MEM_callocN(sizeof(wmSubWindow), "swinopen");
- BLI_addtail(&win->subwindows, swin);
-
- swin->swinid = freewinid;
- swin->winrct = *winrct;
-
- if (activate) {
- /* and we appy it all right away */
- wmSubWindowSet(win, swin->swinid);
-
- /* extra service */
- wm_swin_size_get(swin, &width, &height);
- wmOrtho2_pixelspace(width, height);
- glLoadIdentity();
- }
-
- return swin->swinid;
-}
-
-void wm_subwindow_close(wmWindow *win, int swinid)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
+ glViewport(winrct->xmin, winrct->ymin, width, height);
+ glScissor(winrct->xmin, winrct->ymin, width, height);
- if (swin) {
- if (swin == win->curswin)
- win->curswin = NULL;
- wm_subwindow_free(swin);
- BLI_remlink(&win->subwindows, swin);
- MEM_freeN(swin);
- }
- else {
- printf("%s: Internal error, bad winid: %d\n", __func__, swinid);
- }
+ wmOrtho2_pixelspace(width, height);
+ GPU_matrix_identity_set();
}
-/* pixels go from 0-99 for a 100 pixel window */
-void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct, bool activate)
+void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct)
{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
-
- if (swin) {
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
- int width, height;
-
- swin->winrct = *winrct;
+ /* Setup part of the viewport for partial redraw. */
+ bool scissor_pad;
- /* CRITICAL, this clamping ensures that
- * the viewport never goes outside the screen
- * edges (assuming the x, y coords aren't
- * outside). This caused a hardware lock
- * on Matrox cards if it happens.
- *
- * Really Blender should never _ever_ try
- * to do such a thing, but just to be safe
- * clamp it anyway (or fix the bScreen
- * scaling routine, and be damn sure you
- * fixed it). - zr (2001!)
- */
-
- if (swin->winrct.xmax > winsize_x)
- swin->winrct.xmax = winsize_x;
- if (swin->winrct.ymax > winsize_y)
- swin->winrct.ymax = winsize_y;
-
- if (activate) {
- /* extra service */
- wmSubWindowSet(win, swinid);
- wm_swin_size_get(swin, &width, &height);
- wmOrtho2_pixelspace(width, height);
- }
+ if (partialrct->xmin == partialrct->xmax) {
+ /* Full region. */
+ *drawrct = *winrct;
+ scissor_pad = true;
}
else {
- printf("%s: Internal error, bad winid: %d\n", __func__, swinid);
+ /* Partial redraw, clipped to region. */
+ BLI_rcti_isect(winrct, partialrct, drawrct);
+ scissor_pad = false;
}
-}
-/* ---------------- WM versions of OpenGL style API calls ------------------------ */
-/* ----------------- exported in WM_api.h ------------------------------------------------------ */
+ int x = drawrct->xmin - winrct->xmin;
+ int y = drawrct->ymin - winrct->ymin;
+ int width = BLI_rcti_size_x(winrct) + 1;
+ int height = BLI_rcti_size_y(winrct) + 1;
-/* internal state, no threaded opengl! XXX */
-static wmWindow *_curwindow = NULL;
-static wmSubWindow *_curswin = NULL;
+ int scissor_width = BLI_rcti_size_x(drawrct);
+ int scissor_height = BLI_rcti_size_y(drawrct);
-void wmSubWindowScissorSet(wmWindow *win, int swinid, const rcti *srct, bool srct_pad)
-{
- int width, height;
- _curswin = swin_from_swinid(win, swinid);
-
- if (_curswin == NULL) {
- printf("%s %d: doesn't exist\n", __func__, swinid);
- return;
+ /* Partial redraw rect uses different convention than region rect,
+ * so compensate for that here. One pixel offset is noticeable with
+ * viewport border render. */
+ if (scissor_pad) {
+ scissor_width += 1;
+ scissor_height += 1;
}
- win->curswin = _curswin;
- _curwindow = win;
-
- width = BLI_rcti_size_x(&_curswin->winrct) + 1;
- height = BLI_rcti_size_y(&_curswin->winrct) + 1;
- glViewport(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
-
- if (srct) {
- int scissor_width = BLI_rcti_size_x(srct);
- int scissor_height = BLI_rcti_size_y(srct);
-
- /* typically a single pixel doesn't matter,
- * but one pixel offset is noticeable with viewport border render */
- if (srct_pad) {
- scissor_width += 1;
- scissor_height += 1;
- }
-
- glScissor(srct->xmin, srct->ymin, scissor_width, scissor_height);
- }
- else
- glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
+ glViewport(0, 0, width, height);
+ glScissor(x, y, scissor_width, scissor_height);
wmOrtho2_pixelspace(width, height);
- glLoadIdentity();
-
- glFlush();
-}
-
-/* enable the WM versions of opengl calls */
-void wmSubWindowSet(wmWindow *win, int swinid)
-{
- wmSubWindowScissorSet(win, swinid, NULL, true);
+ GPU_matrix_identity_set();
}
-void wmFrustum(float x1, float x2, float y1, float y2, float n, float f)
+void wmWindowViewport(wmWindow *win)
{
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glFrustum(x1, x2, y1, y2, n, f);
- glMatrixMode(GL_MODELVIEW);
-}
-
-void wmOrtho(float x1, float x2, float y1, float y2, float n, float f)
-{
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
+ int width = WM_window_pixels_x(win);
+ int height = WM_window_pixels_y(win);
- glOrtho(x1, x2, y1, y2, n, f);
+ glViewport(0, 0, width, height);
+ glScissor(0, 0, width, height);
- glMatrixMode(GL_MODELVIEW);
+ wmOrtho2_pixelspace(width, height);
+ GPU_matrix_identity_set();
}
void wmOrtho2(float x1, float x2, float y1, float y2)
@@ -357,7 +110,7 @@ void wmOrtho2(float x1, float x2, float y1, float y2)
if (x1 == x2) x2 += 1.0f;
if (y1 == y2) y2 += 1.0f;
- wmOrtho(x1, x2, y1, y2, -100, 100);
+ GPU_matrix_ortho_set(x1, x2, y1, y2, -100, 100);
}
static void wmOrtho2_offset(const float x, const float y, const float ofs)
@@ -365,9 +118,7 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs)
wmOrtho2(ofs, x + ofs, ofs, y + ofs);
}
-/**
- * default pixel alignment.
- */
+/* Default pixel alignment for regions. */
void wmOrtho2_region_pixelspace(const ARegion *ar)
{
wmOrtho2_offset(ar->winx, ar->winy, -0.01f);
@@ -378,4 +129,9 @@ void wmOrtho2_pixelspace(const float x, const float y)
wmOrtho2_offset(x, y, -GLA_PIXEL_OFS);
}
-/* ********** END MY WINDOW ************** */
+void wmGetProjectionMatrix(float mat[4][4], const rcti *winrct)
+{
+ int width = BLI_rcti_size_x(winrct) + 1;
+ int height = BLI_rcti_size_y(winrct) + 1;
+ orthographic_m4(mat, -GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS, -100, 100);
+}
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
new file mode 100644
index 00000000000..3b91b351b25
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -0,0 +1,904 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_toolsystem.c
+ * \ingroup wm
+ *
+ * Experimental tool-system>
+ */
+
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_listbase.h"
+
+#include "DNA_ID.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_paint.h"
+#include "BKE_workspace.h"
+
+#include "RNA_access.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h" /* own include */
+
+static void toolsystem_reinit_with_toolref(
+ bContext *C, WorkSpace *UNUSED(workspace), bToolRef *tref);
+static bToolRef *toolsystem_reinit_ensure_toolref(
+ bContext *C, WorkSpace *workspace, const bToolKey *tkey, const char *default_tool);
+static void toolsystem_refresh_screen_from_active_tool(
+ Main *bmain, WorkSpace *workspace, bToolRef *tref);
+
+/* -------------------------------------------------------------------- */
+/** \name Tool Reference API
+ * \{ */
+
+struct bToolRef *WM_toolsystem_ref_from_context(struct bContext *C)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ScrArea *sa = CTX_wm_area(C);
+ if (((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) {
+ return NULL;
+ }
+ const bToolKey tkey = {
+ .space_type = sa->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
+ /* We could return 'sa->runtime.tool' in this case. */
+ if (sa->runtime.is_tool_set) {
+ BLI_assert(tref == sa->runtime.tool);
+ }
+ return tref;
+}
+
+struct bToolRef_Runtime *WM_toolsystem_runtime_from_context(struct bContext *C)
+{
+ bToolRef *tref = WM_toolsystem_ref_from_context(C);
+ return tref ? tref->runtime : NULL;
+}
+
+bToolRef *WM_toolsystem_ref_find(WorkSpace *workspace, const bToolKey *tkey)
+{
+ BLI_assert((1 << tkey->space_type) & WM_TOOLSYSTEM_SPACE_MASK);
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ if ((tref->space_type == tkey->space_type) &&
+ (tref->mode == tkey->mode))
+ {
+ return tref;
+ }
+ }
+ return NULL;
+}
+
+bToolRef_Runtime *WM_toolsystem_runtime_find(WorkSpace *workspace, const bToolKey *tkey)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ return tref ? tref->runtime : NULL;
+}
+
+bool WM_toolsystem_ref_ensure(
+ struct WorkSpace *workspace, const bToolKey *tkey,
+ bToolRef **r_tref)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ if (tref) {
+ *r_tref = tref;
+ return false;
+ }
+ tref = MEM_callocN(sizeof(*tref), __func__);
+ BLI_addhead(&workspace->tools, tref);
+ tref->space_type = tkey->space_type;
+ tref->mode = tkey->mode;
+ *r_tref = tref;
+ return true;
+}
+
+/** \} */
+
+
+static void toolsystem_unlink_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ bToolRef_Runtime *tref_rt = tref->runtime;
+
+ if (tref_rt->gizmo_group[0]) {
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(tref_rt->gizmo_group, false);
+ if (gzgt != NULL) {
+ bool found = false;
+
+ /* TODO(campbell) */
+ Main *bmain = CTX_data_main(C);
+#if 0
+ wmWindowManager *wm = bmain->wm.first;
+ /* Check another workspace isn't using this tool. */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const WorkSpace *workspace_iter = WM_window_get_active_workspace(win);
+ if (workspace != workspace_iter) {
+ if (STREQ(workspace->tool.gizmo_group, workspace_iter->tool.gizmo_group)) {
+ found = true;
+ break;
+ }
+ }
+ }
+#else
+ UNUSED_VARS(workspace);
+#endif
+ if (!found) {
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
+ WM_gizmomaptype_group_unlink(C, bmain, gzmap_type, gzgt);
+ }
+ }
+ }
+}
+void WM_toolsystem_unlink(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ if (tref && tref->runtime) {
+ toolsystem_unlink_ref(C, workspace, tref);
+ }
+}
+
+static void toolsystem_ref_link__refresh_image_uv_sculpt(bContext *C, Scene *scene)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &ptr);
+ PropertyRNA *prop = RNA_struct_find_property(&ptr, "use_uv_sculpt");
+ RNA_property_update(C, &ptr, prop);
+}
+
+/**
+ * \see #toolsystem_ref_link
+ */
+static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ bToolRef_Runtime *tref_rt = tref->runtime;
+ if (tref_rt->gizmo_group[0]) {
+ const char *idname = tref_rt->gizmo_group;
+ wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
+ if (gzgt != NULL) {
+ if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) == 0) {
+ WM_gizmo_group_type_ensure_ptr(gzgt);
+ }
+ }
+ else {
+ CLOG_WARN(WM_LOG_TOOLS, "'%s' widget not found", idname);
+ }
+ }
+
+ if (tref_rt->data_block[0]) {
+ Main *bmain = CTX_data_main(C);
+
+ if ((tref->space_type == SPACE_VIEW3D) &&
+ (tref->mode == CTX_MODE_GPENCIL_SCULPT))
+ {
+ const EnumPropertyItem *items = rna_enum_gpencil_sculpt_brush_items;
+ const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
+ if (i != -1) {
+ const int value = items[i].value;
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ Scene *scene = WM_window_get_active_scene(win);
+ ToolSettings *ts = scene->toolsettings;
+ ts->gp_sculpt.brushtype = value;
+ }
+ }
+ }
+ }
+ else if ((tref->space_type == SPACE_VIEW3D) &&
+ (tref->mode == CTX_MODE_GPENCIL_WEIGHT))
+ {
+ const EnumPropertyItem *items = rna_enum_gpencil_weight_brush_items;
+ const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
+ if (i != -1) {
+ const int value = items[i].value;
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ Scene *scene = WM_window_get_active_scene(win);
+ ToolSettings *ts = scene->toolsettings;
+ ts->gp_sculpt.weighttype = value;
+ }
+ }
+ }
+ }
+ else if ((tref->space_type == SPACE_VIEW3D) &&
+ (tref->mode == CTX_MODE_PARTICLE))
+ {
+ const EnumPropertyItem *items = rna_enum_particle_edit_hair_brush_items;
+ const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
+ if (i != -1) {
+ const int value = items[i].value;
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ Scene *scene = WM_window_get_active_scene(win);
+ ToolSettings *ts = scene->toolsettings;
+ ts->particle.brushtype = value;
+ }
+ }
+ }
+ }
+ else if ((tref->space_type == SPACE_IMAGE) &&
+ (tref->mode == SI_MODE_UV))
+ {
+ /* Note that switching uv-sculpt boolean is a hack at the moment.
+ * It would be best to make this either an operator or a higher level mode (like mesh-object sculpt mode). */
+ const EnumPropertyItem *items = rna_enum_uv_sculpt_tool_items;
+ const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
+ if (i != -1) {
+ const int value = items[i].value;
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ Scene *scene = WM_window_get_active_scene(win);
+ ToolSettings *ts = scene->toolsettings;
+ ts->uv_sculpt_tool = value;
+
+ if (ts->use_uv_sculpt == false) {
+ ts->use_uv_sculpt = true;
+ toolsystem_ref_link__refresh_image_uv_sculpt(C, scene);
+ }
+ }
+ }
+ }
+ }
+ else {
+ const ePaintMode paint_mode = BKE_paintmode_get_from_tool(tref);
+ BLI_assert(paint_mode != PAINT_MODE_INVALID);
+ const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ BLI_assert(items != NULL);
+
+ const int i = items ? RNA_enum_from_identifier(items, tref_rt->data_block) : -1;
+ if (i != -1) {
+ const int slot_index = items[i].value;
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ Scene *scene = WM_window_get_active_scene(win);
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
+ struct Brush *brush = BKE_paint_toolslots_brush_get(paint, slot_index);
+ if (brush == NULL) {
+ /* Could make into a function. */
+ brush = (struct Brush *)BKE_libblock_find_name(bmain, ID_BR, items[i].name);
+ if (brush && slot_index == BKE_brush_tool_get(brush, paint)) {
+ /* pass */
+ }
+ else {
+ brush = BKE_brush_add(bmain, items[i].name, paint->runtime.ob_mode);
+ BKE_brush_tool_set(brush, paint, slot_index);
+ }
+ BKE_paint_brush_set(paint, brush);
+ }
+ BKE_paint_brush_set(paint, brush);
+ }
+ }
+ }
+ }
+ }
+ else {
+ /* XXX, this part is weak, disables uv_sculpt when non uv-tool set. */
+ if ((tref->space_type == SPACE_IMAGE) &&
+ (tref->mode == SI_MODE_UV))
+ {
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ Scene *scene = WM_window_get_active_scene(win);
+ ToolSettings *ts = scene->toolsettings;
+ if (ts->use_uv_sculpt == true) {
+ ts->use_uv_sculpt = false;
+ toolsystem_ref_link__refresh_image_uv_sculpt(C, scene);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void toolsystem_refresh_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ if (tref->runtime == NULL) {
+ return;
+ }
+ /* currently same operation. */
+ toolsystem_ref_link(C, workspace, tref);
+}
+void WM_toolsystem_refresh(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ if (tref) {
+ toolsystem_refresh_ref(C, workspace, tref);
+ }
+}
+
+static void toolsystem_reinit_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ toolsystem_reinit_with_toolref(C, workspace, tref);
+}
+void WM_toolsystem_reinit(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ if (tref) {
+ toolsystem_reinit_ref(C, workspace, tref);
+ }
+}
+
+/* Operate on all active tools. */
+void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace)
+{
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ tref->tag = 0;
+ }
+
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ if (tref->runtime) {
+ if (tref->tag == 0) {
+ toolsystem_unlink_ref(C, workspace, tref);
+ tref->tag = 1;
+ }
+ }
+ }
+}
+
+void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace)
+{
+ BLI_assert(0);
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ toolsystem_refresh_ref(C, workspace, tref);
+ }
+}
+void WM_toolsystem_reinit_all(struct bContext *C, wmWindow *win)
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) {
+ continue;
+ }
+
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ const bToolKey tkey = {
+ .space_type = sa->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
+ if (tref) {
+ if (tref->tag == 0) {
+ toolsystem_reinit_ref(C, workspace, tref);
+ tref->tag = 1;
+ }
+ }
+ }
+}
+
+void WM_toolsystem_ref_set_from_runtime(
+ struct bContext *C, struct WorkSpace *workspace, bToolRef *tref,
+ const bToolRef_Runtime *tref_rt, const char *idname)
+{
+ Main *bmain = CTX_data_main(C);
+
+ if (tref->runtime) {
+ toolsystem_unlink_ref(C, workspace, tref);
+ }
+
+ STRNCPY(tref->idname, idname);
+
+ /* BAD DESIGN WARNING: used for topbar. */
+ workspace->tools_space_type = tref->space_type;
+ workspace->tools_mode = tref->mode;
+
+ if (tref->runtime == NULL) {
+ tref->runtime = MEM_callocN(sizeof(*tref->runtime), __func__);
+ }
+
+ if (tref_rt != tref->runtime) {
+ *tref->runtime = *tref_rt;
+ }
+
+ toolsystem_ref_link(C, workspace, tref);
+
+ toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
+
+ {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(
+ mbus, &workspace->id, workspace, WorkSpace, tools);
+ }
+}
+
+/**
+ * Sync the internal active state of a tool back into the tool system,
+ * this is needed for active brushes where the real active state is not stored in the tool system.
+ *
+ * \see #toolsystem_ref_link
+ */
+void WM_toolsystem_ref_sync_from_context(
+ Main *bmain, WorkSpace *workspace, bToolRef *tref)
+{
+ bToolRef_Runtime *tref_rt = tref->runtime;
+ if ((tref_rt == NULL) || (tref_rt->data_block[0] == '\0')) {
+ return;
+ }
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace != WM_window_get_active_workspace(win)) {
+ continue;
+ }
+
+ Scene *scene = WM_window_get_active_scene(win);
+ ToolSettings *ts = scene->toolsettings;
+ const ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ const Object *ob = OBACT(view_layer);
+ if (ob == NULL) {
+ /* pass */
+ }
+ else if ((tref->space_type == SPACE_VIEW3D) &&
+ (tref->mode == CTX_MODE_GPENCIL_SCULPT))
+ {
+ if (ob->mode & OB_MODE_GPENCIL_SCULPT) {
+ const EnumPropertyItem *items = rna_enum_gpencil_sculpt_brush_items;
+ const int i = RNA_enum_from_value(items, ts->gp_sculpt.brushtype);
+ const EnumPropertyItem *item = &items[i];
+ if (!STREQ(tref_rt->data_block, item->identifier)) {
+ STRNCPY(tref_rt->data_block, item->identifier);
+ STRNCPY(tref->idname, item->name);
+ }
+ }
+ }
+ else if ((tref->space_type == SPACE_VIEW3D) &&
+ (tref->mode == CTX_MODE_GPENCIL_WEIGHT))
+ {
+ if (ob->mode & OB_MODE_GPENCIL_WEIGHT) {
+ const EnumPropertyItem *items = rna_enum_gpencil_weight_brush_items;
+ const int i = RNA_enum_from_value(items, ts->gp_sculpt.weighttype);
+ const EnumPropertyItem *item = &items[i];
+ if (!STREQ(tref_rt->data_block, item->identifier)) {
+ STRNCPY(tref_rt->data_block, item->identifier);
+ STRNCPY(tref->idname, item->name);
+ }
+ }
+ }
+ else if ((tref->space_type == SPACE_VIEW3D) &&
+ (tref->mode == CTX_MODE_PARTICLE))
+ {
+ if (ob->mode & OB_MODE_PARTICLE_EDIT) {
+ const EnumPropertyItem *items = rna_enum_particle_edit_hair_brush_items;
+ const int i = RNA_enum_from_value(items, ts->particle.brushtype);
+ const EnumPropertyItem *item = &items[i];
+ if (!STREQ(tref_rt->data_block, item->identifier)) {
+ STRNCPY(tref_rt->data_block, item->identifier);
+ STRNCPY(tref->idname, item->name);
+ }
+ }
+ }
+ else if ((tref->space_type == SPACE_IMAGE) &&
+ (tref->mode == SI_MODE_UV))
+ {
+ if (ob->mode & OB_MODE_EDIT) {
+ const EnumPropertyItem *items = rna_enum_uv_sculpt_tool_items;
+ const int i = RNA_enum_from_value(items, ts->uv_sculpt_tool);
+ const EnumPropertyItem *item = &items[i];
+ if (!STREQ(tref_rt->data_block, item->identifier)) {
+ STRNCPY(tref_rt->data_block, item->identifier);
+ STRNCPY(tref->idname, item->name);
+ }
+ }
+ }
+ else {
+ const ePaintMode paint_mode = BKE_paintmode_get_from_tool(tref);
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
+ const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ if (paint && paint->brush && items) {
+ const ID *brush = (ID *)paint->brush;
+ const char tool_type = BKE_brush_tool_get((struct Brush *)brush, paint);
+ const int i = RNA_enum_from_value(items, tool_type);
+ /* Possible when loading files from the future. */
+ if (i != -1) {
+ const char *name = items[i].name;
+ const char *identifier = items[i].identifier;
+ if (!STREQ(tref_rt->data_block, identifier)) {
+ STRNCPY(tref_rt->data_block, identifier);
+ STRNCPY(tref->idname, name);
+ }
+ }
+ }
+ }
+ }
+}
+
+void WM_toolsystem_init(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+
+ BLI_assert(CTX_wm_window(C) == NULL);
+
+ LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ MEM_SAFE_FREE(tref->runtime);
+ }
+ }
+
+ /* Rely on screen initialization for gizmos. */
+}
+
+int WM_toolsystem_mode_from_spacetype(
+ ViewLayer *view_layer, ScrArea *sa, int spacetype)
+{
+ int mode = -1;
+ switch (spacetype) {
+ case SPACE_VIEW3D:
+ {
+ /* 'sa' may be NULL in this case. */
+ Object *obact = OBACT(view_layer);
+ if (obact != NULL) {
+ Object *obedit = OBEDIT_FROM_OBACT(obact);
+ mode = CTX_data_mode_enum_ex(obedit, obact, obact->mode);
+ }
+ else {
+ mode = CTX_MODE_OBJECT;
+ }
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = sa->spacedata.first;
+ mode = sima->mode;
+ break;
+ }
+ case SPACE_NODE:
+ {
+ mode = 0;
+ break;
+ }
+ }
+ return mode;
+}
+
+bool WM_toolsystem_key_from_context(
+ ViewLayer *view_layer, ScrArea *sa, bToolKey *tkey)
+{
+ int space_type = SPACE_EMPTY;
+ int mode = -1;
+
+ if (sa != NULL) {
+ space_type = sa->spacetype;
+ mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, space_type);
+ }
+
+ if (mode != -1) {
+ tkey->space_type = space_type;
+ tkey->mode = mode;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Use to update the active tool (shown in the top bar) in the least disruptive way.
+ *
+ * This is a little involved since there may be multiple valid active tools depending on the mode and space type.
+ *
+ * Used when undoing since the active mode may have changed.
+ */
+void WM_toolsystem_refresh_active(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ int mode_other = 0;
+ enum { UNSET = -1, CHANGE = 0, MATCH = 1 } mode_match = UNSET;
+ /* Could skip loop for modes that don't depend on space type. */
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ /* Don't change the space type of the active tool, only update it's mode. */
+ if (sa->spacetype == workspace->tools_space_type) {
+ const int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype);
+ if (workspace->tools_mode == mode) {
+ mode_match = MATCH;
+ break;
+ }
+ else if (mode_match == -1) {
+ mode_match = CHANGE;
+ mode_other = mode;
+ }
+ }
+ }
+
+ if (mode_match == CHANGE) {
+ const bToolKey tkey = {
+ .space_type = workspace->tools_space_type,
+ .mode = mode_other,
+ };
+ toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
+ }
+ }
+ }
+}
+
+void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *sa)
+{
+ sa->runtime.tool = NULL;
+ sa->runtime.is_tool_set = true;
+ const int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype);
+ for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ if (tref->space_type == sa->spacetype) {
+ if (tref->mode == mode) {
+ sa->runtime.tool = tref;
+ break;
+ }
+ }
+ }
+}
+
+void WM_toolsystem_refresh_screen_all(Main *bmain)
+{
+ /* Update all ScrArea's tools */
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ bool space_type_has_tools[SPACE_TYPE_LAST + 1] = {0};
+ for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ space_type_has_tools[tref->space_type] = true;
+ }
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ sa->runtime.tool = NULL;
+ sa->runtime.is_tool_set = true;
+ if (space_type_has_tools[sa->spacetype]) {
+ WM_toolsystem_refresh_screen_area(workspace, view_layer, sa);
+ }
+ }
+ }
+ }
+}
+
+static void toolsystem_refresh_screen_from_active_tool(
+ Main *bmain, WorkSpace *workspace, bToolRef *tref)
+{
+ /* Update all ScrArea's tools */
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == tref->space_type) {
+ int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype);
+ if (mode == tref->mode) {
+ sa->runtime.tool = tref;
+ sa->runtime.is_tool_set = true;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+bToolRef *WM_toolsystem_ref_set_by_name(
+ bContext *C, WorkSpace *workspace, const bToolKey *tkey,
+ const char *name, bool cycle)
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_tool_set_by_name", false);
+ /* On startup, Python operatores are not yet loaded. */
+ if (ot == NULL) {
+ return NULL;
+ }
+ PointerRNA op_props;
+ WM_operator_properties_create_ptr(&op_props, ot);
+ RNA_string_set(&op_props, "name", name);
+
+ /* Will get from context if not set. */
+ bToolKey tkey_from_context;
+ if (tkey == NULL) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ScrArea *sa = CTX_wm_area(C);
+ WM_toolsystem_key_from_context(view_layer, sa, &tkey_from_context);
+ tkey = &tkey_from_context;
+ }
+
+ BLI_assert((1 << tkey->space_type) & WM_TOOLSYSTEM_SPACE_MASK);
+
+ RNA_enum_set(&op_props, "space_type", tkey->space_type);
+ RNA_boolean_set(&op_props, "cycle", cycle);
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ WM_operator_properties_free(&op_props);
+
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+
+ if (tref) {
+ Main *bmain = CTX_data_main(C);
+ toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
+ }
+
+ return (tref && STREQ(tref->idname, name)) ? tref : NULL;
+}
+
+static void toolsystem_reinit_with_toolref(
+ bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ bToolKey tkey = {
+ .space_type = tref->space_type,
+ .mode = tref->mode,
+ };
+ WM_toolsystem_ref_set_by_name(C, workspace, &tkey, tref->idname, false);
+}
+
+static const char *toolsystem_default_tool(const bToolKey *tkey)
+{
+ switch (tkey->space_type) {
+ case SPACE_VIEW3D:
+ switch (tkey->mode) {
+ /* Use the names of the enums for each brush tool. */
+ case CTX_MODE_SCULPT:
+ case CTX_MODE_PAINT_VERTEX:
+ case CTX_MODE_PAINT_WEIGHT:
+ case CTX_MODE_GPENCIL_WEIGHT:
+ case CTX_MODE_PAINT_TEXTURE:
+ case CTX_MODE_GPENCIL_PAINT:
+ return "Draw";
+ case CTX_MODE_GPENCIL_SCULPT:
+ return "Push";
+ /* end temporary hack. */
+
+ case CTX_MODE_PARTICLE:
+ return "Comb";
+ }
+ break;
+ }
+
+ return "Select Box";
+}
+
+/**
+ * Run after changing modes.
+ */
+static bToolRef *toolsystem_reinit_ensure_toolref(
+ bContext *C, WorkSpace *workspace, const bToolKey *tkey, const char *default_tool)
+{
+ bToolRef *tref;
+ if (WM_toolsystem_ref_ensure(workspace, tkey, &tref)) {
+ if (default_tool == NULL) {
+ default_tool = toolsystem_default_tool(tkey);
+ }
+ STRNCPY(tref->idname, default_tool);
+ }
+ toolsystem_reinit_with_toolref(C, workspace, tref);
+ return tref;
+}
+
+void WM_toolsystem_update_from_context_view3d(bContext *C)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int space_type = SPACE_VIEW3D;
+ const bToolKey tkey = {
+ .space_type = space_type,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, NULL, space_type),
+ };
+ toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
+}
+
+void WM_toolsystem_update_from_context(
+ bContext *C, WorkSpace *workspace, ViewLayer *view_layer,
+ ScrArea *sa)
+{
+ const bToolKey tkey = {
+ .space_type = sa->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
+}
+
+
+/**
+ * For paint modes to support non-brush tools.
+ */
+bool WM_toolsystem_active_tool_is_brush(const bContext *C)
+{
+ bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
+ return tref_rt && (tref_rt->data_block[0] != '\0');
+}
+
+/* Follow wmMsgNotifyFn spec */
+void WM_toolsystem_do_msg_notify_tag_refresh(
+ bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ScrArea *sa = msg_val->user_data;
+ int space_type = sa->spacetype;
+ const bToolKey tkey = {
+ .space_type = space_type,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ WM_toolsystem_refresh(C, workspace, &tkey);
+}
+
+IDProperty *WM_toolsystem_ref_properties_ensure_idprops(bToolRef *tref)
+{
+ if (tref->properties == NULL) {
+ IDPropertyTemplate val = {0};
+ tref->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ }
+ return tref->properties;
+}
+
+
+void WM_toolsystem_ref_properties_ensure_ex(bToolRef *tref, const char *idname, StructRNA *type, PointerRNA *r_ptr)
+{
+ IDProperty *group = WM_toolsystem_ref_properties_ensure_idprops(tref);
+ IDProperty *prop = IDP_GetPropertyFromGroup(group, idname);
+ if (prop == NULL) {
+ IDPropertyTemplate val = {0};
+ prop = IDP_New(IDP_GROUP, &val, "wmGenericProperties");
+ STRNCPY(prop->name, idname);
+ IDP_ReplaceInGroup_ex(group, prop, NULL);
+ }
+ else {
+ BLI_assert(prop->type == IDP_GROUP);
+ }
+
+ RNA_pointer_create(NULL, type, prop, r_ptr);
+}
+
+void WM_toolsystem_ref_properties_init_for_keymap(
+ bToolRef *tref, PointerRNA *dst_ptr, PointerRNA *src_ptr, wmOperatorType *ot)
+{
+ *dst_ptr = *src_ptr;
+ if (dst_ptr->data) {
+ dst_ptr->data = IDP_CopyProperty(dst_ptr->data);
+ }
+ else {
+ IDPropertyTemplate val = {0};
+ dst_ptr->data = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
+ }
+ if (tref->properties != NULL) {
+ IDProperty *prop = IDP_GetPropertyFromGroup(tref->properties, ot->idname);
+ if (prop) {
+ IDP_MergeGroup(dst_ptr->data, prop, true);
+ }
+ }
+}
diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c
index 0d02b4fc4e3..b0d621c2e44 100644
--- a/source/blender/windowmanager/intern/wm_tooltip.c
+++ b/source/blender/windowmanager/intern/wm_tooltip.c
@@ -37,24 +37,56 @@
#include "WM_api.h"
#include "WM_types.h"
-void WM_tooltip_timer_init(
+#include "PIL_time.h"
+
+static double g_tooltip_time_closed;
+double WM_tooltip_time_closed(void)
+{
+ return g_tooltip_time_closed;
+}
+
+void WM_tooltip_immediate_init(
bContext *C, wmWindow *win, ARegion *ar,
wmTooltipInitFn init)
{
- bScreen *screen = win->screen;
+ WM_tooltip_timer_clear(C, win);
+
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen->tool_tip == NULL) {
+ screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
+ }
+ screen->tool_tip->region_from = ar;
+ screen->tool_tip->init = init;
+ WM_tooltip_init(C, win);
+}
+
+void WM_tooltip_timer_init_ex(
+ bContext *C, wmWindow *win, ARegion *ar,
+ wmTooltipInitFn init, double delay)
+{
+ WM_tooltip_timer_clear(C, win);
+
+ bScreen *screen = WM_window_get_active_screen(win);
wmWindowManager *wm = CTX_wm_manager(C);
if (screen->tool_tip == NULL) {
screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
}
screen->tool_tip->region_from = ar;
- screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, UI_TOOLTIP_DELAY);
+ screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, delay);
screen->tool_tip->init = init;
}
+void WM_tooltip_timer_init(
+ bContext *C, wmWindow *win, ARegion *ar,
+ wmTooltipInitFn init)
+{
+ WM_tooltip_timer_init_ex(C, win, ar, init, UI_TOOLTIP_DELAY);
+}
+
void WM_tooltip_timer_clear(bContext *C, wmWindow *win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
if (screen->tool_tip != NULL) {
if (screen->tool_tip->timer != NULL) {
WM_event_remove_timer(wm, win, screen->tool_tip->timer);
@@ -66,11 +98,12 @@ void WM_tooltip_timer_clear(bContext *C, wmWindow *win)
void WM_tooltip_clear(bContext *C, wmWindow *win)
{
WM_tooltip_timer_clear(C, win);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
if (screen->tool_tip != NULL) {
if (screen->tool_tip->region) {
UI_tooltip_free(C, screen, screen->tool_tip->region);
screen->tool_tip->region = NULL;
+ g_tooltip_time_closed = PIL_check_seconds_timer();
}
MEM_freeN(screen->tool_tip);
screen->tool_tip = NULL;
@@ -80,13 +113,21 @@ void WM_tooltip_clear(bContext *C, wmWindow *win)
void WM_tooltip_init(bContext *C, wmWindow *win)
{
WM_tooltip_timer_clear(C, win);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
if (screen->tool_tip->region) {
UI_tooltip_free(C, screen, screen->tool_tip->region);
screen->tool_tip->region = NULL;
}
+ const int pass_prev = screen->tool_tip->pass;
+ double pass_delay = 0.0;
screen->tool_tip->region = screen->tool_tip->init(
- C, screen->tool_tip->region_from, &screen->tool_tip->exit_on_event);
+ C, screen->tool_tip->region_from,
+ &screen->tool_tip->pass, &pass_delay, &screen->tool_tip->exit_on_event);
+ if (pass_prev != screen->tool_tip->pass) {
+ /* The pass changed, add timer for next pass. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, pass_delay);
+ }
if (screen->tool_tip->region == NULL) {
WM_tooltip_clear(C, win);
}
@@ -95,7 +136,7 @@ void WM_tooltip_init(bContext *C, wmWindow *win)
void WM_tooltip_refresh(bContext *C, wmWindow *win)
{
WM_tooltip_timer_clear(C, win);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
if (screen->tool_tip != NULL) {
if (screen->tool_tip->region) {
UI_tooltip_free(C, screen, screen->tool_tip->region);
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c
index 52619a09218..f0ffa5905fc 100644
--- a/source/blender/windowmanager/intern/wm_uilist_type.c
+++ b/source/blender/windowmanager/intern/wm_uilist_type.c
@@ -34,7 +34,6 @@
#include "BLI_ghash.h"
#include "BKE_context.h"
-#include "BKE_library.h"
#include "BKE_screen.h"
#include "WM_api.h"
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 04a236e5d66..53db8f931a5 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -38,6 +38,7 @@
#include "DNA_listBase.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
@@ -51,35 +52,48 @@
#include "BKE_blender.h"
#include "BKE_context.h"
-#include "BKE_library.h"
#include "BKE_global.h"
+#include "BKE_icons.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
-
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
#include "wm_draw.h"
#include "wm_window.h"
-#include "wm_subwindow.h"
#include "wm_event_system.h"
+#include "ED_anim_api.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_fileselect.h"
#include "UI_interface.h"
-#include "UI_resources.h"
+#include "UI_interface_icons.h"
#include "PIL_time.h"
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
#include "GPU_init_exit.h"
-#include "GPU_glew.h"
+#include "GPU_immediate.h"
+#include "GPU_material.h"
+#include "GPU_texture.h"
+#include "GPU_context.h"
#include "BLF_api.h"
+#include "UI_resources.h"
+
/* for assert */
#ifndef NDEBUG
# include "BLI_threads.h"
@@ -108,6 +122,8 @@ static struct WMInitStruct {
/* ******** win open & close ************ */
+static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
+
/* XXX this one should correctly check for apple top header...
* done for Cocoa : returns window contents (and not frame) max size*/
void wm_get_screensize(int *r_width, int *r_height)
@@ -162,13 +178,29 @@ static void wm_window_check_position(rcti *rect)
if (rect->ymin < 0) rect->ymin = 0;
}
-
-static void wm_ghostwindow_destroy(wmWindow *win)
+static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
{
if (win->ghostwin) {
+ /* Prevents non-drawable state of main windows (bugs #22967,
+ * #25071 and possibly #22477 too). Always clear it even if
+ * this window was not the drawable one, because we mess with
+ * drawing context to discard the GW context. */
+ wm_window_clear_drawable(wm);
+
+ if (win == wm->winactive) {
+ wm->winactive = NULL;
+ }
+
+ /* We need this window's opengl context active to discard it. */
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ GPU_context_active_set(win->gpuctx);
+
+ /* Delete local gpu context. */
+ GPU_context_discard(win->gpuctx);
+
GHOST_DisposeWindow(g_system, win->ghostwin);
win->ghostwin = NULL;
- win->multisamples = 0;
+ win->gpuctx = NULL;
}
}
@@ -187,10 +219,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
CTX_wm_window_set(C, NULL);
}
- /* always set drawable and active to NULL,
- * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
- wm->windrawable = NULL;
- wm->winactive = NULL;
+ BKE_screen_area_map_free(&win->global_areas);
/* end running jobs, a job end also removes its timer */
for (wt = wm->timers.first; wt; wt = wtnext) {
@@ -208,13 +237,15 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
if (win->eventstate) MEM_freeN(win->eventstate);
- wm_event_free_all(win);
- wm_subwindows_free(win);
+ if (win->cursor_keymap_status) {
+ MEM_freeN(win->cursor_keymap_status);
+ }
- wm_draw_data_free(win);
+ wm_event_free_all(win);
- wm_ghostwindow_destroy(win);
+ wm_ghostwindow_destroy(wm, win);
+ BKE_workspace_instance_hook_free(G_MAIN, win->workspace_hook);
MEM_freeN(win->stereo3d_format);
MEM_freeN(win);
@@ -233,42 +264,42 @@ static int find_free_winid(wmWindowManager *wm)
}
/* don't change context itself */
-wmWindow *wm_window_new(bContext *C)
+wmWindow *wm_window_new(bContext *C, wmWindow *parent)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
BLI_addtail(&wm->windows, win);
win->winid = find_free_winid(wm);
+ win->parent = (parent && parent->parent) ? parent->parent : parent;
win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
+ win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
return win;
}
-
/* part of wm_window.c api */
-wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
+wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child)
{
Main *bmain = CTX_data_main(C);
- wmWindow *win_dst = wm_window_new(C);
+ wmWindow *win_parent = (child) ? win_src : win_src->parent;
+ wmWindow *win_dst = wm_window_new(C, win_parent);
+ WorkSpace *workspace = WM_window_get_active_workspace(win_src);
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
+ WorkSpaceLayout *layout_new;
win_dst->posx = win_src->posx + 10;
win_dst->posy = win_src->posy;
win_dst->sizex = win_src->sizex;
win_dst->sizey = win_src->sizey;
- /* duplicate assigns to window */
- win_dst->screen = ED_screen_duplicate(bmain, win_dst, win_src->screen);
- BLI_strncpy(win_dst->screenname, win_dst->screen->id.name + 2, sizeof(win_dst->screenname));
- win_dst->screen->winid = win_dst->winid;
-
- win_dst->screen->do_refresh = true;
- win_dst->screen->do_draw = true;
-
- win_dst->drawmethod = U.wmdrawmethod;
-
- BLI_listbase_clear(&win_dst->drawdata);
+ win_dst->scene = win_src->scene;
+ STRNCPY(win_dst->view_layer_name, win_src->view_layer_name);
+ BKE_workspace_active_set(win_dst->workspace_hook, workspace);
+ layout_new = duplicate_layout ? ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) : layout_old;
+ BKE_workspace_hook_layout_for_workspace_set(win_dst->workspace_hook, workspace, layout_new);
*win_dst->stereo3d_format = *win_src->stereo3d_format;
@@ -279,12 +310,12 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
* A higher level version of copy that tests the new window can be added.
* (called from the operator directly)
*/
-wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src)
+wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win_dst;
- win_dst = wm_window_copy(C, win_src);
+ win_dst = wm_window_copy(C, win_src, duplicate_layout, child);
WM_check(C);
@@ -451,50 +482,59 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
/* this is event from ghost, or exit-blender op */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
- wmWindow *tmpwin;
-
- /* first check if we have to quit (there are non-temp remaining windows) */
- for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
- if (tmpwin == win)
- continue;
- if (tmpwin->screen->temp == 0)
+ /* First check if there is another main window remaining. */
+ wmWindow *win_other;
+ for (win_other = wm->windows.first; win_other; win_other = win_other->next) {
+ if (win_other != win &&
+ win_other->parent == NULL &&
+ !WM_window_is_temp_screen(win_other))
+ {
break;
+ }
}
- if (tmpwin == NULL) {
+ if (win->parent == NULL && win_other == NULL) {
wm_quit_with_optional_confirmation_prompt(C, win);
+ return;
}
- else {
- /* We're just closing a window */
- bScreen *screen = win->screen;
- BLI_remlink(&wm->windows, win);
+ /* close child windows */
+ for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ if (win_child->parent == win) {
+ wm_window_close(C, wm, win_child);
+ }
+ }
- wm_draw_window_clear(win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook);
- CTX_wm_window_set(C, win); /* needed by handlers */
- WM_event_remove_handlers(C, &win->handlers);
- WM_event_remove_handlers(C, &win->modalhandlers);
+ BLI_remlink(&wm->windows, win);
- /* for regular use this will _never_ be NULL,
- * however we may be freeing an improperly initialized window. */
- if (win->screen) {
- ED_screen_exit(C, win, win->screen);
- }
+ CTX_wm_window_set(C, win); /* needed by handlers */
+ WM_event_remove_handlers(C, &win->handlers);
+ WM_event_remove_handlers(C, &win->modalhandlers);
+
+ /* for regular use this will _never_ be NULL,
+ * however we may be freeing an improperly initialized window. */
+ if (screen) {
+ ED_screen_exit(C, win, screen);
+ }
- wm_window_free(C, wm, win);
+ wm_window_free(C, wm, win);
- /* if temp screen, delete it after window free (it stops jobs that can access it) */
- if (screen && screen->temp) {
- Main *bmain = CTX_data_main(C);
- BKE_libblock_free(bmain, screen);
- }
+ /* if temp screen, delete it after window free (it stops jobs that can access it) */
+ if (screen && screen->temp) {
+ Main *bmain = CTX_data_main(C);
+
+ BLI_assert(BKE_workspace_layout_screen_get(layout) == screen);
+ BKE_workspace_layout_remove(bmain, workspace, layout);
}
}
void wm_window_title(wmWindowManager *wm, wmWindow *win)
{
- if (win->screen && win->screen->temp) {
+ if (WM_window_is_temp_screen(win)) {
/* nothing to do for 'temp' windows,
* because WM_window_open_temp always sets window title */
}
@@ -558,26 +598,29 @@ void WM_window_set_dpi(wmWindow *win)
U.dpi = dpi / pixelsize;
U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
+ U.dpi_fac = ((U.pixelsize * (float)U.dpi) / 72.0f);
/* update font drawing */
BLF_default_dpi(U.pixelsize * U.dpi);
}
+static void wm_window_ensure_eventstate(wmWindow *win)
+{
+ if (win->eventstate) {
+ return;
+ }
+
+ win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
+ wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y);
+}
+
/* belongs to below */
static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win)
{
GHOST_WindowHandle ghostwin;
GHOST_GLSettings glSettings = {0};
- static int multisamples = -1;
int scr_w, scr_h, posy;
- /* force setting multisamples only once, it requires restart - and you cannot
- * mix it, either all windows have it, or none (tested in OSX opengl) */
- if (multisamples == -1)
- multisamples = U.ogl_multisamples;
-
- glSettings.numOfAASamples = multisamples;
-
/* a new window is created when pageflip mode is required for a window */
if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP)
glSettings.flags |= GHOST_glStereoVisual;
@@ -589,6 +632,10 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
wm_get_screensize(&scr_w, &scr_h);
posy = (scr_h - win->posy - win->sizey);
+ /* Clear drawable so we can set the new window. */
+ wmWindow *prev_windrawable = wm->windrawable;
+ wm_window_clear_drawable(wm);
+
ghostwin = GHOST_CreateWindow(g_system, title,
win->posx, posy, win->sizex, win->sizey,
(GHOST_TWindowState)win->windowstate,
@@ -598,20 +645,19 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
if (ghostwin) {
GHOST_RectangleHandle bounds;
- /* the new window has already been made drawable upon creation */
- wm->windrawable = win;
+ win->gpuctx = GPU_context_create();
/* needed so we can detect the graphics card below */
GPU_init();
+ /* Set window as drawable upon creation. Note this has already been
+ * it has already been activated by GHOST_CreateWindow. */
+ wm_window_set_drawable(wm, win, false);
+
win->ghostwin = ghostwin;
GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
- if (win->eventstate == NULL)
- win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
-
- /* store multisamples window was created with, in case user prefs change */
- win->multisamples = multisamples;
+ wm_window_ensure_eventstate(win);
/* store actual window size in blender window */
bounds = GHOST_GetClientBounds(win->ghostwin);
@@ -644,9 +690,11 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
//GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
/* standard state vars for window */
- glEnable(GL_SCISSOR_TEST);
GPU_state_init();
}
+ else {
+ wm_window_set_drawable(wm, prev_windrawable, false);
+ }
}
/**
@@ -683,7 +731,9 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
wm_init_state.start_y = 0;
#ifdef WITH_X11 /* X11 */
- /* X11, start maximized but use default sane size */
+ /* X11, don't start maximized because we can't figure out the dimensions
+ * of a single display yet if there are multiple, due to lack of Xinerama
+ * handling in GHOST. */
wm_init_state.size_x = min_ii(wm_init_state.size_x, WM_WIN_INIT_SIZE_X);
wm_init_state.size_y = min_ii(wm_init_state.size_y, WM_WIN_INIT_SIZE_Y);
/* pad */
@@ -719,8 +769,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
wm_window_ghostwindow_add(wm, "Blender", win);
}
/* happens after fileread */
- if (win->eventstate == NULL)
- win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
+ wm_window_ensure_eventstate(win);
/* add keymap handlers (1 handler for all keys in map!) */
keymap = WM_keymap_ensure(wm->defaultconf, "Window", 0, 0);
@@ -738,6 +787,9 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
WM_event_add_dropbox_handler(&win->handlers, lb);
}
wm_window_title(wm, win);
+
+ /* add topbar */
+ ED_screen_global_areas_refresh(win);
}
}
@@ -768,15 +820,13 @@ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
wmWindow *WM_window_open(bContext *C, const rcti *rect)
{
wmWindow *win_prev = CTX_wm_window(C);
- wmWindow *win = wm_window_new(C);
+ wmWindow *win = wm_window_new(C, win_prev);
win->posx = rect->xmin;
win->posy = rect->ymin;
win->sizex = BLI_rcti_size_x(rect);
win->sizey = BLI_rcti_size_y(rect);
- win->drawmethod = U.wmdrawmethod;
-
WM_check(C);
if (win->ghostwin) {
@@ -801,8 +851,10 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
Main *bmain = CTX_data_main(C);
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
+ bScreen *screen;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const char *title;
/* convert to native OS window coordinates */
@@ -824,17 +876,19 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
/* test if we have a temp screen already */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
- if (win->screen->temp)
+ if (WM_window_is_temp_screen(win))
break;
/* add new window? */
if (win == NULL) {
- win = wm_window_new(C);
+ win = wm_window_new(C, win_prev);
win->posx = rect.xmin;
win->posy = rect.ymin;
}
+ screen = WM_window_get_active_screen(win);
+
win->sizex = BLI_rcti_size_x(&rect);
win->sizey = BLI_rcti_size_y(&rect);
@@ -843,17 +897,27 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
wm_window_raise(win);
}
- if (win->screen == NULL) {
- /* add new screen */
- win->screen = ED_screen_add(bmain, win, scene, "temp");
+ if (WM_window_get_active_workspace(win) == NULL) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
}
- else {
- /* switch scene for rendering */
- if (win->screen->scene != scene)
- ED_screen_set_scene(C, win->screen, scene);
+
+ if (screen == NULL) {
+ /* add new screen layout */
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = ED_workspace_layout_add(bmain, workspace, win, "temp");
+
+ screen = BKE_workspace_layout_screen_get(layout);
+ WM_window_set_active_layout(win, workspace, layout);
+ }
+
+ /* Set scene and view layer to match original window. */
+ STRNCPY(win->view_layer_name, view_layer->name);
+ if (WM_window_get_active_scene(win) != scene) {
+ ED_screen_scene_change(C, win, scene);
}
- win->screen->temp = 1;
+ screen->temp = 1;
/* make window active, and validate/resize */
CTX_wm_window_set(C, win);
@@ -866,25 +930,35 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
*/
/* ensure it shows the right spacetype editor */
- sa = win->screen->areabase.first;
+ sa = screen->areabase.first;
CTX_wm_area_set(C, sa);
if (type == WM_WINDOW_RENDER) {
ED_area_newspace(C, sa, SPACE_IMAGE, false);
}
+ else if (type == WM_WINDOW_DRIVERS) {
+ ED_area_newspace(C, sa, SPACE_IPO, false);
+ }
else {
ED_area_newspace(C, sa, SPACE_USERPREF, false);
}
- ED_screen_set(C, win->screen);
+ ED_screen_change(C, screen);
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
+ /* do additional setup for specific editor type */
+ if (type == WM_WINDOW_DRIVERS) {
+ ED_drivers_editor_init(C, sa);
+ }
+
if (sa->spacetype == SPACE_IMAGE)
title = IFACE_("Blender Render");
else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
- title = IFACE_("Blender User Preferences");
+ title = IFACE_("Blender Preferences");
else if (sa->spacetype == SPACE_FILE)
title = IFACE_("Blender File View");
+ else if (sa->spacetype == SPACE_IPO)
+ title = IFACE_("Blender Drivers Editor");
else
title = "Blender";
@@ -912,17 +986,25 @@ int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* operator callback */
-int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
+int wm_window_new_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win_src = CTX_wm_window(C);
bool ok;
- ok = (wm_window_copy_test(C, win_src) != NULL);
+ ok = (wm_window_copy_test(C, win_src, true, true) != NULL);
return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
+int wm_window_new_main_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ wmWindow *win_src = CTX_wm_window(C);
+ bool ok;
+
+ ok = (wm_window_copy_test(C, win_src, true, false) != NULL);
+
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
/* fullscreen operator callback */
int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1013,22 +1095,65 @@ static int query_qual(modifierKeyType qual)
return val;
}
+static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate)
+{
+ BLI_assert(ELEM(wm->windrawable, NULL, win));
+
+ wm->windrawable = win;
+ if (activate) {
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ }
+ GPU_context_active_set(win->gpuctx);
+ immActivate();
+}
+
+void wm_window_clear_drawable(wmWindowManager *wm)
+{
+ if (wm->windrawable) {
+ BLF_batch_reset();
+ gpu_batch_presets_reset();
+ immDeactivate();
+ wm->windrawable = NULL;
+ }
+}
+
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
{
+ BLI_assert(GPU_framebuffer_active_get() == NULL);
+
if (win != wm->windrawable && win->ghostwin) {
// win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */
+ wm_window_clear_drawable(wm);
- wm->windrawable = win;
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: set drawable %d\n", __func__, win->winid);
}
- GHOST_ActivateWindowDrawingContext(win->ghostwin);
+
+ wm_window_set_drawable(wm, win, true);
/* this can change per window */
WM_window_set_dpi(win);
}
}
+/* Reset active the current window opengl drawing context. */
+void wm_window_reset_drawable(void)
+{
+ BLI_assert(BLI_thread_is_main());
+ BLI_assert(GPU_framebuffer_active_get() == NULL);
+ wmWindowManager *wm = G_MAIN->wm.first;
+
+ if (wm == NULL)
+ return;
+
+ wmWindow *win = wm->windrawable;
+
+ if (win && win->ghostwin) {
+ wm_window_clear_drawable(wm);
+ wm_window_set_drawable(wm, win, true);
+ }
+}
+
/* called by ghost, here we handle events for windows themselves or send to event system */
/* mouse coordinate converversion happens here */
static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
@@ -1048,7 +1173,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet.
* Can happen on file read (especially full size window) */
- if ((wm->initialized & WM_INIT_WINDOW) == 0) {
+ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
return 1;
}
if (!ghostwin) {
@@ -1252,6 +1377,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
win->posx != posx ||
win->posy != posy)
{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
win->sizex = sizex;
win->sizey = sizey;
win->posx = posx;
@@ -1287,7 +1414,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
wm_window_make_drawable(wm, win);
- wm_draw_window_clear(win);
+ BKE_icon_changed(screen->id.icon_id);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
@@ -1399,6 +1526,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
WM_window_set_dpi(win);
if (U.pixelsize != prev_pixelsize) {
+ BKE_icon_changed(WM_window_get_active_screen(win)->id.icon_id);
+
// 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);
@@ -1407,7 +1536,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
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);
@@ -1538,13 +1666,22 @@ void wm_window_testbreak(void)
/* **************** init ********************** */
+/* bContext can be null in background mode because we don't
+ * need to event handling. */
void wm_ghost_init(bContext *C)
{
if (!g_system) {
- GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
+ GHOST_EventConsumerHandle consumer;
+
+ if (C != NULL) {
+ consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
+ }
g_system = GHOST_CreateSystem();
- GHOST_AddEventConsumer(g_system, consumer);
+
+ if (C != NULL) {
+ GHOST_AddEventConsumer(g_system, consumer);
+ }
if (wm_init_state.native_pixels) {
GHOST_UseNativePixels();
@@ -1790,14 +1927,7 @@ void wm_window_raise(wmWindow *win)
void wm_window_swap_buffers(wmWindow *win)
{
-
-#ifdef WIN32
- glDisable(GL_SCISSOR_TEST);
- GHOST_SwapWindowBuffers(win->ghostwin);
- glEnable(GL_SCISSOR_TEST);
-#else
GHOST_SwapWindowBuffers(win->ghostwin);
-#endif
}
void wm_window_set_swap_interval (wmWindow *win, int interval)
@@ -1884,7 +2014,7 @@ float WM_cursor_pressure(const struct wmWindow *win)
const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
/* if there's tablet data from an active tablet device then add it */
if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
- return td->Pressure;
+ return wm_pressure_curve(td->Pressure);
}
else {
return -1.0f;
@@ -1893,19 +2023,73 @@ float WM_cursor_pressure(const struct wmWindow *win)
/* support for native pixel size */
/* mac retina opens window in size X, but it has up to 2 x more pixels */
-int WM_window_pixels_x(wmWindow *win)
+int WM_window_pixels_x(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
return (int)(f * (float)win->sizex);
}
-
-int WM_window_pixels_y(wmWindow *win)
+int WM_window_pixels_y(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
return (int)(f * (float)win->sizey);
+}
+/**
+ * Get boundaries usable by all window contents, including global areas.
+ */
+void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
+{
+ BLI_rcti_init(r_rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win));
+}
+/**
+ * Get boundaries usable by screen-layouts, excluding global areas.
+ * \note Depends on U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
+ */
+void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
+{
+ rcti window_rect, screen_rect;
+
+ WM_window_rect_calc(win, &window_rect);
+ screen_rect = window_rect;
+
+ /* Subtract global areas from screen rectangle. */
+ for (ScrArea *global_area = win->global_areas.areabase.first; global_area; global_area = global_area->next) {
+ int height = ED_area_global_size_y(global_area) - 1;
+
+ if (global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
+ continue;
+ }
+
+ switch (global_area->global->align) {
+ case GLOBAL_AREA_ALIGN_TOP:
+ if ((screen_rect.ymax - height) > window_rect.ymin) {
+ height += U.pixelsize;
+ }
+ if (screen_rect.ymax < (window_rect.ymax - 1)) {
+ height += U.pixelsize;
+ }
+ screen_rect.ymax -= height;
+ break;
+ case GLOBAL_AREA_ALIGN_BOTTOM:
+ if (screen_rect.ymin > window_rect.ymin) {
+ height += U.pixelsize;
+ }
+ if ((screen_rect.ymin + height) < (window_rect.ymax - 1)) {
+ height += U.pixelsize;
+ }
+ screen_rect.ymin += height;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+
+ BLI_assert(screen_rect.xmin < screen_rect.xmax);
+ BLI_assert(screen_rect.ymin < screen_rect.ymax);
+ *r_rect = screen_rect;
}
bool WM_window_is_fullscreen(wmWindow *win)
@@ -1913,6 +2097,179 @@ bool WM_window_is_fullscreen(wmWindow *win)
return win->windowstate == GHOST_kWindowStateFullScreen;
}
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors in visible workspaces and their visible layouts.
+ */
+void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
+{
+ for (wmWindow *win = win_lb->first; win; win = win->next) {
+ if (WM_window_get_active_scene(win) == scene) {
+ ED_workspace_scene_data_sync(win->workspace_hook, scene);
+ }
+ }
+}
+
+Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return WM_window_get_active_scene(win);
+ }
+ }
+
+ return NULL;
+}
+
+WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return WM_window_get_active_workspace(win);
+ }
+ }
+ return NULL;
+}
+
+Scene *WM_window_get_active_scene(const wmWindow *win)
+{
+ return win->scene;
+}
+
+/**
+ * \warning Only call outside of area/region loops
+ */
+void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win_parent = (win->parent) ? win->parent : win;
+ bool changed = false;
+
+ /* Set scene in parent and its child windows. */
+ if (win_parent->scene != scene) {
+ ED_screen_scene_change(C, win_parent, scene);
+ changed = true;
+ }
+
+ for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ if (win_child->parent == win_parent && win_child->scene != scene) {
+ ED_screen_scene_change(C, win_child, scene);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ /* Update depsgraph and renderers for scene change. */
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win_parent);
+ ED_scene_change_update(bmain, scene, view_layer);
+
+ /* Complete redraw. */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ }
+}
+
+ViewLayer *WM_window_get_active_view_layer(const wmWindow *win)
+{
+ Scene *scene = WM_window_get_active_scene(win);
+ if (scene == NULL) {
+ return NULL;
+ }
+
+ ViewLayer *view_layer = BKE_view_layer_find(scene, win->view_layer_name);
+ if (view_layer) {
+ return view_layer;
+ }
+
+ view_layer = BKE_view_layer_default_view(scene);
+ if (view_layer) {
+ WM_window_set_active_view_layer((wmWindow *)win, view_layer);
+ }
+
+ return view_layer;
+}
+
+void WM_window_set_active_view_layer(wmWindow *win, ViewLayer *view_layer)
+{
+ BLI_assert(BKE_view_layer_find(WM_window_get_active_scene(win), view_layer->name) != NULL);
+
+ wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindow *win_parent = (win->parent) ? win->parent : win;
+
+ /* Set view layer in parent and child windows. */
+ STRNCPY(win_parent->view_layer_name, view_layer->name);
+
+ for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ if (win_child->parent == win_parent) {
+ STRNCPY(win_child->view_layer_name, view_layer->name);
+ }
+ }
+}
+
+void WM_window_ensure_active_view_layer(wmWindow *win)
+{
+ /* Update layer name is correct after scene changes, load without UI, etc. */
+ Scene *scene = WM_window_get_active_scene(win);
+
+ if (scene && BKE_view_layer_find(scene, win->view_layer_name) == NULL) {
+ ViewLayer *view_layer = BKE_view_layer_default_view(scene);
+ STRNCPY(win->view_layer_name, view_layer->name);
+ }
+}
+
+WorkSpace *WM_window_get_active_workspace(const wmWindow *win)
+{
+ return BKE_workspace_active_get(win->workspace_hook);
+}
+
+void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *workspace)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win_parent = (win->parent) ? win->parent : win;
+
+ ED_workspace_change(workspace, C, wm, win);
+
+ for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ if (win_child->parent == win_parent) {
+ bScreen *screen = WM_window_get_active_screen(win_child);
+ /* Don't change temporary screens, they only serve a single purpose. */
+ if (screen->temp) {
+ continue;
+ }
+ ED_workspace_change(workspace, C, wm, win_child);
+ }
+ }
+}
+
+WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win)
+{
+ const WorkSpace *workspace = WM_window_get_active_workspace(win);
+ return (LIKELY(workspace != NULL) ? BKE_workspace_active_layout_get(win->workspace_hook) : NULL);
+}
+void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
+}
+
+/**
+ * Get the active screen of the active workspace in \a win.
+ */
+bScreen *WM_window_get_active_screen(const wmWindow *win)
+{
+ const WorkSpace *workspace = WM_window_get_active_workspace(win);
+ /* May be NULL in rare cases like closing Blender */
+ return (LIKELY(workspace != NULL) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL);
+}
+void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
+{
+ BKE_workspace_active_screen_set(win->workspace_hook, workspace, screen);
+}
+
+bool WM_window_is_temp_screen(const wmWindow *win)
+{
+ const bScreen *screen = WM_window_get_active_screen(win);
+ return (screen && screen->temp != 0);
+}
+
#ifdef WITH_INPUT_IME
/* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */
@@ -1931,3 +2288,34 @@ void wm_window_IME_end(wmWindow *win)
win->ime_data = NULL;
}
#endif /* WITH_INPUT_IME */
+
+/* ****** direct opengl context management ****** */
+
+void *WM_opengl_context_create(void)
+{
+ /* On Windows there is a problem creating contexts that share lists
+ * from one context that is current in another thread.
+ * So we should call this function only on the main thread.
+ */
+ BLI_assert(BLI_thread_is_main());
+ BLI_assert(GPU_framebuffer_active_get() == NULL);
+ return GHOST_CreateOpenGLContext(g_system);
+}
+
+void WM_opengl_context_dispose(void *context)
+{
+ BLI_assert(GPU_framebuffer_active_get() == NULL);
+ GHOST_DisposeOpenGLContext(g_system, (GHOST_ContextHandle)context);
+}
+
+void WM_opengl_context_activate(void *context)
+{
+ BLI_assert(GPU_framebuffer_active_get() == NULL);
+ GHOST_ActivateOpenGLContext((GHOST_ContextHandle)context);
+}
+
+void WM_opengl_context_release(void *context)
+{
+ BLI_assert(GPU_framebuffer_active_get() == NULL);
+ GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context);
+}
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
new file mode 100644
index 00000000000..63a897b2faf
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
@@ -0,0 +1,258 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/message_bus/intern/wm_message_bus.c
+ * \ingroup wm
+ */
+
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+
+#include "BLI_ghash.h"
+
+#include "WM_types.h"
+
+#include "message_bus/wm_message_bus.h"
+#include "message_bus/intern/wm_message_bus_intern.h"
+
+/* -------------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {{{NULL}}};
+
+typedef void (*wmMsgTypeInitFn)(wmMsgTypeInfo *);
+
+static wmMsgTypeInitFn wm_msg_init_fn[WM_MSG_TYPE_NUM] = {
+ WM_msgtypeinfo_init_rna,
+ WM_msgtypeinfo_init_static,
+};
+
+void WM_msgbus_types_init(void)
+{
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wm_msg_init_fn[i](&wm_msg_types[i]);
+ }
+}
+
+struct wmMsgBus *WM_msgbus_create(void)
+{
+ struct wmMsgBus *mbus = MEM_callocN(sizeof(*mbus), __func__);
+ const uint gset_reserve = 512;
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wmMsgTypeInfo *info = &wm_msg_types[i];
+ mbus->messages_gset[i] = BLI_gset_new_ex(info->gset.hash_fn, info->gset.cmp_fn, __func__, gset_reserve);
+ }
+ return mbus;
+}
+
+void WM_msgbus_destroy(struct wmMsgBus *mbus)
+{
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wmMsgTypeInfo *info = &wm_msg_types[i];
+ BLI_gset_free(mbus->messages_gset[i], info->gset.key_free_fn);
+ }
+ MEM_freeN(mbus);
+}
+
+void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner)
+{
+ wmMsgSubscribeKey *msg_key, *msg_key_next;
+ for (msg_key = mbus->messages.first; msg_key; msg_key = msg_key_next) {
+ msg_key_next = msg_key->next;
+
+ wmMsgSubscribeValueLink *msg_lnk_next;
+ for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk; msg_lnk = msg_lnk_next) {
+ msg_lnk_next = msg_lnk->next;
+ if (msg_lnk->params.owner == owner) {
+ if (msg_lnk->params.tag) {
+ mbus->messages_tag_count -= 1;
+ }
+ if (msg_lnk->params.free_data) {
+ msg_lnk->params.free_data(msg_key, &msg_lnk->params);
+ }
+ BLI_remlink(&msg_key->values, msg_lnk);
+ MEM_freeN(msg_lnk);
+ }
+ }
+
+ if (BLI_listbase_is_empty(&msg_key->values)) {
+ const wmMsg *msg = wm_msg_subscribe_value_msg_cast(msg_key);
+ wmMsgTypeInfo *info = &wm_msg_types[msg->type];
+ BLI_remlink(&mbus->messages, msg_key);
+ bool ok = BLI_gset_remove(mbus->messages_gset[msg->type], msg_key, info->gset.key_free_fn);
+ BLI_assert(ok);
+ UNUSED_VARS_NDEBUG(ok);
+ }
+ }
+}
+
+void WM_msg_dump(struct wmMsgBus *mbus, const char *info_str)
+{
+ printf(">>>> %s\n", info_str);
+ for (wmMsgSubscribeKey *key = mbus->messages.first; key; key = key->next) {
+ const wmMsg *msg = wm_msg_subscribe_value_msg_cast(key);
+ const wmMsgTypeInfo *info = &wm_msg_types[msg->type];
+ info->repr(stdout, key);
+ }
+ printf("<<<< %s\n", info_str);
+}
+
+void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
+{
+ if (mbus->messages_tag_count == 0) {
+ // printf("msgbus: skipping\n");
+ return;
+ }
+
+ if (false) {
+ WM_msg_dump(mbus, __func__);
+ }
+
+ // uint a = 0, b = 0;
+ for (wmMsgSubscribeKey *key = mbus->messages.first; key; key = key->next) {
+ for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) {
+ if (msg_lnk->params.tag) {
+ msg_lnk->params.notify(C, key, &msg_lnk->params);
+ msg_lnk->params.tag = false;
+ mbus->messages_tag_count -= 1;
+ }
+ // b++;
+ }
+ // a++;
+ }
+ BLI_assert(mbus->messages_tag_count == 0);
+ mbus->messages_tag_count = 0;
+ // printf("msgbus: keys=%u values=%u\n", a, b);
+}
+
+/**
+ * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
+ * - msg.params
+ * - msg.head.type
+ * - msg.head.id
+ * .. other values should be zeroed.
+ *
+ * \return The key for this subscription.
+ * note that this is only needed in rare cases when the key needs further manipulation.
+ */
+wmMsgSubscribeKey *WM_msg_subscribe_with_key(
+ struct wmMsgBus *mbus,
+ const wmMsgSubscribeKey *msg_key_test,
+ const wmMsgSubscribeValue *msg_val_params)
+{
+ const uint type = wm_msg_subscribe_value_msg_cast(msg_key_test)->type;
+ const wmMsgTypeInfo *info = &wm_msg_types[type];
+ wmMsgSubscribeKey *key;
+
+ BLI_assert(wm_msg_subscribe_value_msg_cast(msg_key_test)->id != NULL);
+
+ void **r_key;
+ if (!BLI_gset_ensure_p_ex(mbus->messages_gset[type], msg_key_test, &r_key)) {
+ key = *r_key = MEM_mallocN(info->msg_key_size, __func__);
+ memcpy(key, msg_key_test, info->msg_key_size);
+ BLI_addtail(&mbus->messages, key);
+ }
+ else {
+ key = *r_key;
+ for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) {
+ if ((msg_lnk->params.notify == msg_val_params->notify) &&
+ (msg_lnk->params.owner == msg_val_params->owner) &&
+ (msg_lnk->params.user_data == msg_val_params->user_data))
+ {
+ return key;
+ }
+ }
+ }
+
+ wmMsgSubscribeValueLink *msg_lnk = MEM_mallocN(sizeof(wmMsgSubscribeValueLink), __func__);
+ msg_lnk->params = *msg_val_params;
+ BLI_addtail(&key->values, msg_lnk);
+ return key;
+}
+
+void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key)
+{
+ CLOG_INFO(
+ WM_LOG_MSGBUS_SUB, 2,
+ "tagging subscribers: (ptr=%p, len=%d)",
+ msg_key, BLI_listbase_count(&msg_key->values)
+ );
+
+ for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk; msg_lnk = msg_lnk->next) {
+ if (false) { /* make an option? */
+ msg_lnk->params.notify(NULL, msg_key, &msg_lnk->params);
+ }
+ else {
+ if (msg_lnk->params.tag == false) {
+ msg_lnk->params.tag = true;
+ mbus->messages_tag_count += 1;
+ }
+ }
+ }
+}
+
+void WM_msg_id_update(
+ struct wmMsgBus *mbus,
+ struct ID *id_src, struct ID *id_dst)
+{
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wmMsgTypeInfo *info = &wm_msg_types[i];
+ if (info->update_by_id != NULL) {
+ info->update_by_id(mbus, id_src, id_dst);
+ }
+ }
+}
+
+void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
+{
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wmMsgTypeInfo *info = &wm_msg_types[i];
+ if (info->remove_by_id != NULL) {
+ info->remove_by_id(mbus, id);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------------- */
+/** \name Internal API
+ *
+ * \note While we could have a separate type for ID's, use RNA since there is enough overlap.
+ * \{ */
+
+void wm_msg_subscribe_value_free(
+ wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
+{
+ if (msg_lnk->params.free_data) {
+ msg_lnk->params.free_data(msg_key, &msg_lnk->params);
+ }
+ BLI_remlink(&msg_key->values, msg_lnk);
+ MEM_freeN(msg_lnk);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
new file mode 100644
index 00000000000..db8b481a3c2
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
@@ -0,0 +1,55 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
+ * \ingroup wm
+ */
+
+#ifndef __WM_MESSAGE_BUS_INTERN_H__
+#define __WM_MESSAGE_BUS_INTERN_H__
+
+/* wm_message_bus.h must be included first */
+
+struct wmMsgBus {
+ struct GSet *messages_gset[WM_MSG_TYPE_NUM];
+ /** Messages in order of being added. */
+ ListBase messages;
+ /** Avoid checking messages when no tags exist. */
+ uint messages_tag_count;
+};
+
+void wm_msg_subscribe_value_free(
+ struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValueLink *msg_lnk);
+
+typedef struct wmMsgSubscribeKey_Generic {
+ wmMsgSubscribeKey head;
+ wmMsg msg;
+} wmMsgSubscribeKey_Generic;
+
+BLI_INLINE const wmMsg *wm_msg_subscribe_value_msg_cast(const wmMsgSubscribeKey *key)
+{
+ return &((wmMsgSubscribeKey_Generic *)key)->msg;
+}
+BLI_INLINE wmMsg *wm_msg_subscribe_value_msg_cast_mut(wmMsgSubscribeKey *key)
+{
+ return &((wmMsgSubscribeKey_Generic *)key)->msg;
+}
+
+#endif /* __WM_MESSAGE_BUS_INTERN_H__ */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
new file mode 100644
index 00000000000..619777fc671
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
@@ -0,0 +1,338 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
+ * \ingroup wm
+ */
+
+
+#include <stdio.h>
+
+#include "CLG_log.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+
+#include "WM_types.h"
+#include "WM_message.h"
+#include "message_bus/intern/wm_message_bus_intern.h"
+
+#include "RNA_access.h"
+
+
+/* -------------------------------------------------------------------------- */
+
+BLI_INLINE uint void_hash_uint(const void *key)
+{
+ size_t y = (size_t)key >> (sizeof(void *));
+ return (unsigned int)y;
+}
+
+static uint wm_msg_rna_gset_hash(const void *key_p)
+{
+ const wmMsgSubscribeKey_RNA *key = key_p;
+ const wmMsgParams_RNA *params = &key->msg.params;
+// printf("%s\n", RNA_struct_identifier(params->ptr.type));
+ uint k = void_hash_uint(params->ptr.type);
+ k ^= void_hash_uint(params->ptr.data);
+ k ^= void_hash_uint(params->ptr.id.data);
+ k ^= void_hash_uint(params->prop);
+ return k;
+}
+static bool wm_msg_rna_gset_cmp(const void *key_a_p, const void *key_b_p)
+{
+ const wmMsgParams_RNA *params_a = &((const wmMsgSubscribeKey_RNA *)key_a_p)->msg.params;
+ const wmMsgParams_RNA *params_b = &((const wmMsgSubscribeKey_RNA *)key_b_p)->msg.params;
+ return !(
+ (params_a->ptr.type ==
+ params_b->ptr.type) &&
+ (params_a->ptr.id.data ==
+ params_b->ptr.id.data) &&
+ (params_a->ptr.data ==
+ params_b->ptr.data) &&
+ (params_a->prop ==
+ params_b->prop)
+ );
+}
+static void wm_msg_rna_gset_key_free(void *key_p)
+{
+ wmMsgSubscribeKey_RNA *key = key_p;
+ wmMsgSubscribeValueLink *msg_lnk_next;
+ for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first; msg_lnk; msg_lnk = msg_lnk_next) {
+ msg_lnk_next = msg_lnk->next;
+ wm_msg_subscribe_value_free(&key->head, msg_lnk);
+ }
+ if (key->msg.params.data_path != NULL) {
+ MEM_freeN(key->msg.params.data_path);
+ }
+ MEM_freeN(key);
+}
+
+static void wm_msg_rna_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
+{
+ const wmMsgSubscribeKey_RNA *m = (wmMsgSubscribeKey_RNA *)msg_key;
+ const char *none = "<none>";
+ fprintf(stream,
+ "<wmMsg_RNA %p, "
+ "id='%s', "
+ "%s.%s values_len=%d\n",
+ m, m->msg.head.id,
+ m->msg.params.ptr.type ? RNA_struct_identifier(m->msg.params.ptr.type) : none,
+ m->msg.params.prop ? RNA_property_identifier((PropertyRNA *)m->msg.params.prop) : none,
+ BLI_listbase_count(&m->head.values));
+}
+
+static void wm_msg_rna_update_by_id(
+ struct wmMsgBus *mbus,
+ ID *id_src, ID *id_dst)
+{
+ GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA];
+ GSetIterator gs_iter;
+ BLI_gsetIterator_init(&gs_iter, gs);
+ while (BLI_gsetIterator_done(&gs_iter) == false) {
+ wmMsgSubscribeKey_RNA *key = BLI_gsetIterator_getKey(&gs_iter);
+ BLI_gsetIterator_step(&gs_iter);
+ if (key->msg.params.ptr.id.data == id_src) {
+
+ /* GSet always needs updating since the key changes. */
+ BLI_gset_remove(gs, key, NULL);
+
+ /* Remove any non-persistent values, so a single persistent
+ * value doesn't modify behavior for the rest. */
+ wmMsgSubscribeValueLink *msg_lnk_next;
+ for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first; msg_lnk; msg_lnk = msg_lnk_next) {
+ msg_lnk_next = msg_lnk->next;
+ if (msg_lnk->params.is_persistent == false) {
+ wm_msg_subscribe_value_free(&key->head, msg_lnk);
+ }
+ }
+
+ bool remove = true;
+
+ if (BLI_listbase_is_empty(&key->head.values)) {
+ /* Remove, no reason to keep. */
+ }
+ else if (key->msg.params.ptr.data == key->msg.params.ptr.id.data) {
+ /* Simple, just update the ID. */
+ key->msg.params.ptr.data = id_dst;
+ key->msg.params.ptr.id.data = id_dst;
+ remove = false;
+ }
+ else {
+ /* we need to resolve this from the */
+ PointerRNA idptr;
+ RNA_id_pointer_create(id_dst, &idptr);
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ if (!RNA_path_resolve(&idptr, key->msg.params.data_path, &ptr, &prop)) {
+ key->msg.params.ptr = ptr;
+ key->msg.params.prop = prop;
+ remove = false;
+ }
+ }
+
+ if (remove) {
+ /* Failed to persist, remove the key. */
+ BLI_remlink(&mbus->messages, key);
+ wm_msg_rna_gset_key_free(key);
+ }
+ else {
+ /* note that it's not impossible this key exists, however it is very unlikely
+ * since a subscriber would need to register in the middle of an undo for eg. so assert for now. */
+ BLI_assert(!BLI_gset_haskey(gs, key));
+ BLI_gset_add(gs, key);
+ }
+ }
+ }
+}
+
+static void wm_msg_rna_remove_by_id(struct wmMsgBus *mbus, const ID *id)
+{
+ GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA];
+ GSetIterator gs_iter;
+ BLI_gsetIterator_init(&gs_iter, gs);
+ while (BLI_gsetIterator_done(&gs_iter) == false) {
+ wmMsgSubscribeKey_RNA *key = BLI_gsetIterator_getKey(&gs_iter);
+ BLI_gsetIterator_step(&gs_iter);
+ if (key->msg.params.ptr.id.data == id) {
+ BLI_remlink(&mbus->messages, key);
+ BLI_gset_remove(gs, key, NULL);
+ wm_msg_rna_gset_key_free(key);
+ }
+ }
+}
+
+void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
+{
+ msgtype_info->gset.hash_fn = wm_msg_rna_gset_hash;
+ msgtype_info->gset.cmp_fn = wm_msg_rna_gset_cmp;
+ msgtype_info->gset.key_free_fn = wm_msg_rna_gset_key_free;
+
+ msgtype_info->repr = wm_msg_rna_repr;
+ msgtype_info->update_by_id = wm_msg_rna_update_by_id;
+ msgtype_info->remove_by_id = wm_msg_rna_remove_by_id;
+
+ msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_RNA);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
+{
+ wmMsgSubscribeKey_RNA key_test;
+ key_test.msg.params = *msg_key_params;
+ return BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_RNA], &key_test);
+}
+
+void WM_msg_publish_rna_params(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
+{
+ wmMsgSubscribeKey_RNA *key;
+
+ const char *none = "<none>";
+ CLOG_INFO(
+ WM_LOG_MSGBUS_PUB, 2,
+ "rna(id='%s', %s.%s)",
+ msg_key_params->ptr.id.data ? ((ID *)msg_key_params->ptr.id.data)->name : none,
+ msg_key_params->ptr.type ? RNA_struct_identifier(msg_key_params->ptr.type) : none,
+ msg_key_params->prop ? RNA_property_identifier((PropertyRNA *)msg_key_params->prop) : none
+ );
+
+ if ((key = WM_msg_lookup_rna(mbus, msg_key_params))) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+
+ /* Support anonymous subscribers, this may be some extra overhead
+ * but we want to be able to be more ambiguous. */
+ if (msg_key_params->ptr.id.data || msg_key_params->ptr.data) {
+ wmMsgParams_RNA msg_key_params_anon = *msg_key_params;
+
+ /* We might want to enable this later? */
+ if (msg_key_params_anon.prop != NULL) {
+ /* All properties for this type. */
+ msg_key_params_anon.prop = NULL;
+ if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+ msg_key_params_anon.prop = msg_key_params->prop;
+ }
+
+ msg_key_params_anon.ptr.id.data = NULL;
+ msg_key_params_anon.ptr.data = NULL;
+ if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+
+ /* Support subscribers to a type. */
+ if (msg_key_params->prop) {
+ msg_key_params_anon.prop = NULL;
+ if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+ }
+ }
+}
+
+void WM_msg_publish_rna(struct wmMsgBus *mbus, PointerRNA *ptr, PropertyRNA *prop)
+{
+ WM_msg_publish_rna_params(mbus, &(wmMsgParams_RNA){ .ptr = *ptr, .prop = prop, });
+}
+
+void WM_msg_subscribe_rna_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_RNA *msg_key_params,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ wmMsgSubscribeKey_RNA msg_key_test = {{NULL}};
+
+ /* use when added */
+ msg_key_test.msg.head.id = id_repr;
+ msg_key_test.msg.head.type = WM_MSG_TYPE_RNA;
+ /* for lookup */
+ msg_key_test.msg.params = *msg_key_params;
+
+ const char *none = "<none>";
+ CLOG_INFO(
+ WM_LOG_MSGBUS_SUB, 3,
+ "rna(id='%s', %s.%s, info='%s')",
+ msg_key_params->ptr.id.data ? ((ID *)msg_key_params->ptr.id.data)->name : none,
+ msg_key_params->ptr.type ? RNA_struct_identifier(msg_key_params->ptr.type) : none,
+ msg_key_params->prop ? RNA_property_identifier((PropertyRNA *)msg_key_params->prop) : none,
+ id_repr
+ );
+
+ wmMsgSubscribeKey_RNA *msg_key = (wmMsgSubscribeKey_RNA *)WM_msg_subscribe_with_key(
+ mbus, &msg_key_test.head, msg_val_params);
+
+ if (msg_val_params->is_persistent) {
+ if (msg_key->msg.params.data_path == NULL) {
+ if (msg_key->msg.params.ptr.data != msg_key->msg.params.ptr.id.data) {
+ /* We assume prop type can't change. */
+ msg_key->msg.params.data_path = RNA_path_from_ID_to_struct(&msg_key->msg.params.ptr);
+ }
+ }
+ }
+}
+
+void WM_msg_subscribe_rna(
+ struct wmMsgBus *mbus,
+ PointerRNA *ptr, const PropertyRNA *prop,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &(const wmMsgParams_RNA){
+ .ptr = *ptr,
+ .prop = prop,
+ },
+ msg_val_params, id_repr);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------------- */
+/** \name ID variants of RNA API
+ *
+ * \note While we could have a separate type for ID's, use RNA since there is enough overlap.
+ * \{ */
+
+void WM_msg_subscribe_ID(
+ struct wmMsgBus *mbus, ID *id, const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ wmMsgParams_RNA msg_key_params = {{{NULL}}};
+ RNA_id_pointer_create(id, &msg_key_params.ptr);
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params, msg_val_params, id_repr);
+}
+
+void WM_msg_publish_ID(struct wmMsgBus *mbus, ID *id)
+{
+ wmMsgParams_RNA msg_key_params = {{{NULL}}};
+ RNA_id_pointer_create(id, &msg_key_params.ptr);
+ WM_msg_publish_rna_params(mbus, &msg_key_params);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c
new file mode 100644
index 00000000000..64894ae164d
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c
@@ -0,0 +1,141 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/message_bus/intern/wm_message_bus_static.c
+ * \ingroup wm
+ */
+
+#include <stdio.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+
+#include "WM_types.h"
+#include "WM_message.h"
+#include "message_bus/intern/wm_message_bus_intern.h"
+
+
+/* -------------------------------------------------------------------------- */
+
+static uint wm_msg_static_gset_hash(const void *key_p)
+{
+ const wmMsgSubscribeKey_Static *key = key_p;
+ const wmMsgParams_Static *params = &key->msg.params;
+ uint k = params->event;
+ return k;
+}
+static bool wm_msg_static_gset_cmp(const void *key_a_p, const void *key_b_p)
+{
+ const wmMsgParams_Static *params_a = &((const wmMsgSubscribeKey_Static *)key_a_p)->msg.params;
+ const wmMsgParams_Static *params_b = &((const wmMsgSubscribeKey_Static *)key_b_p)->msg.params;
+ return !(
+ (params_a->event ==
+ params_b->event)
+ );
+}
+static void wm_msg_static_gset_key_free(void *key_p)
+{
+ wmMsgSubscribeKey *key = key_p;
+ wmMsgSubscribeValueLink *msg_lnk_next;
+ for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk_next) {
+ msg_lnk_next = msg_lnk->next;
+ BLI_remlink(&key->values, msg_lnk);
+ MEM_freeN(msg_lnk);
+ }
+ MEM_freeN(key);
+}
+
+static void wm_msg_static_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
+{
+ const wmMsgSubscribeKey_Static *m = (wmMsgSubscribeKey_Static *)msg_key;
+ fprintf(stream,
+ "<wmMsg_Static %p, "
+ "id='%s', "
+ "values_len=%d\n",
+ m, m->msg.head.id,
+ BLI_listbase_count(&m->head.values));
+}
+
+
+void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msgtype_info)
+{
+ msgtype_info->gset.hash_fn = wm_msg_static_gset_hash;
+ msgtype_info->gset.cmp_fn = wm_msg_static_gset_cmp;
+ msgtype_info->gset.key_free_fn = wm_msg_static_gset_key_free;
+ msgtype_info->repr = wm_msg_static_repr;
+
+ msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_Static);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+wmMsgSubscribeKey_Static *WM_msg_lookup_static(struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params)
+{
+ wmMsgSubscribeKey_Static key_test;
+ key_test.msg.params = *msg_key_params;
+ return BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_STATIC], &key_test);
+}
+
+void WM_msg_publish_static_params(struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params)
+{
+ CLOG_INFO(WM_LOG_MSGBUS_PUB, 2, "static(event=%d)", msg_key_params->event);
+
+ wmMsgSubscribeKey_Static *key = WM_msg_lookup_static(mbus, msg_key_params);
+ if (key) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+}
+
+void WM_msg_publish_static(struct wmMsgBus *mbus, int event)
+{
+ WM_msg_publish_static_params(mbus, &(wmMsgParams_Static){ .event = event, });
+}
+
+void WM_msg_subscribe_static_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_Static *msg_key_params,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ wmMsgSubscribeKey_Static msg_key_test = {{NULL}};
+
+ /* use when added */
+ msg_key_test.msg.head.id = id_repr;
+ msg_key_test.msg.head.type = WM_MSG_TYPE_STATIC;
+ /* for lookup */
+ msg_key_test.msg.params = *msg_key_params;
+
+ WM_msg_subscribe_with_key(mbus, &msg_key_test.head, msg_val_params);
+}
+
+void WM_msg_subscribe_static(
+ struct wmMsgBus *mbus,
+ int event,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ WM_msg_subscribe_static_params(mbus, &(const wmMsgParams_Static){ .event = event, }, msg_val_params, id_repr);
+}
diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h
new file mode 100644
index 00000000000..c1d6f1f6fb8
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/wm_message_bus.h
@@ -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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/message_bus/wm_message_bus.h
+ * \ingroup wm
+ */
+
+#ifndef __WM_MESSAGE_BUS_H__
+#define __WM_MESSAGE_BUS_H__
+
+#include <stdio.h>
+
+struct GSet;
+struct ID;
+struct bContext;
+struct wmMsg;
+
+/* opaque (don't expose outside wm_message_bus.c) */
+struct wmMsgBus;
+struct wmMsgSubscribeKey;
+struct wmMsgSubscribeValue;
+struct wmMsgSubscribeValueLink;
+
+typedef void (*wmMsgNotifyFn)(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+typedef void (*wmMsgSubscribeValueFreeDataFn)(
+ struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+
+/* Exactly what arguments here is not obvious. */
+typedef void (*wmMsgSubscribeValueUpdateIdFn)(
+ struct bContext *C,
+ struct wmMsgBus *mbus,
+ struct ID *id_src, struct ID *id_dst,
+ struct wmMsgSubscribeValue *msg_val);
+enum {
+ WM_MSG_TYPE_RNA = 0,
+ WM_MSG_TYPE_STATIC = 1,
+};
+#define WM_MSG_TYPE_NUM 2
+
+typedef struct wmMsgTypeInfo {
+ struct {
+ unsigned int (*hash_fn)(const void *msg);
+ bool (*cmp_fn)(const void *a, const void *b);
+ void (*key_free_fn)(void *key);
+ } gset;
+
+ void (*update_by_id)(struct wmMsgBus *mbus, struct ID *id_src, struct ID *id_dst);
+ void (*remove_by_id)(struct wmMsgBus *mbus, const struct ID *id);
+ void (*repr)(FILE *stream, const struct wmMsgSubscribeKey *msg_key);
+
+ /* sizeof(wmMsgSubscribeKey_*) */
+ uint msg_key_size;
+} wmMsgTypeInfo;
+
+typedef struct wmMsg {
+ unsigned int type;
+// #ifdef DEBUG
+ /* For debugging: '__func__:__LINE__'. */
+ const char *id;
+// #endif
+} wmMsg;
+
+typedef struct wmMsgSubscribeKey {
+ /** Linked list for predicable ordering, otherwise we would depend on ghash bucketing. */
+ struct wmMsgSubscribeKey *next, *prev;
+ ListBase values;
+ /* over-alloc, eg: wmMsgSubscribeKey_RNA */
+ /* Last member will be 'wmMsg_*' */
+} wmMsgSubscribeKey;
+
+/** One of many in #wmMsgSubscribeKey.values */
+typedef struct wmMsgSubscribeValue {
+ struct wmMsgSubscribe *next, *prev;
+
+ /** Handle, used to iterate and clear. */
+ void *owner;
+ /** User data, can be whatever we like, free using the 'free_data' callback if it's owned. */
+ void *user_data;
+
+ /** Callbacks */
+ wmMsgNotifyFn notify;
+ wmMsgSubscribeValueUpdateIdFn update_id;
+ wmMsgSubscribeValueFreeDataFn free_data;
+
+ /** Keep this subscriber if possible. */
+ uint is_persistent : 1;
+ /* tag to run when handling events,
+ * we may want option for immediate execution. */
+ uint tag : 1;
+} wmMsgSubscribeValue;
+
+/** One of many in #wmMsgSubscribeKey.values */
+typedef struct wmMsgSubscribeValueLink {
+ struct wmMsgSubscribeValueLink *next, *prev;
+ wmMsgSubscribeValue params;
+} wmMsgSubscribeValueLink;
+
+void WM_msgbus_types_init(void);
+
+struct wmMsgBus *WM_msgbus_create(void);
+void WM_msgbus_destroy(struct wmMsgBus *mbus);
+
+void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner);
+
+void WM_msg_dump(struct wmMsgBus *mbus, const char *info);
+void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C);
+
+void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key);
+wmMsgSubscribeKey *WM_msg_subscribe_with_key(
+ struct wmMsgBus *mbus,
+ const wmMsgSubscribeKey *msg_key_test,
+ const wmMsgSubscribeValue *msg_val_params);
+
+void WM_msg_id_update(
+ struct wmMsgBus *mbus,
+ struct ID *id_src, struct ID *id_dst);
+void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id);
+
+/* -------------------------------------------------------------------------- */
+/* wm_message_bus_static.c */
+
+enum {
+ /* generic window redraw */
+ WM_MSG_STATICTYPE_WINDOW_DRAW = 0,
+ WM_MSG_STATICTYPE_SCREEN_EDIT = 1,
+ WM_MSG_STATICTYPE_FILE_READ = 2,
+};
+
+typedef struct wmMsgParams_Static {
+ int event;
+} wmMsgParams_Static;
+
+typedef struct wmMsg_Static {
+ wmMsg head; /* keep first */
+ wmMsgParams_Static params;
+} wmMsg_Static;
+
+typedef struct wmMsgSubscribeKey_Static {
+ wmMsgSubscribeKey head;
+ wmMsg_Static msg;
+} wmMsgSubscribeKey_Static;
+
+void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msg_type);
+
+wmMsgSubscribeKey_Static *WM_msg_lookup_static(
+ struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params);
+void WM_msg_publish_static_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_Static *msg_key_params);
+void WM_msg_publish_static(
+ struct wmMsgBus *mbus,
+ /* wmMsgParams_Static (expanded) */
+ int event);
+void WM_msg_subscribe_static_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_Static *msg_key_params,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+void WM_msg_subscribe_static(
+ struct wmMsgBus *mbus,
+ int event,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+
+/* -------------------------------------------------------------------------- */
+/* wm_message_bus_rna.c */
+
+typedef struct wmMsgParams_RNA {
+ /** when #PointerRNA.data & id.data are NULL. match against all. */
+ PointerRNA ptr;
+ /** when NULL, match against any property. */
+ const PropertyRNA *prop;
+
+ /**
+ * Optional RNA data path for persistent RNA properties, ignore if NULL.
+ * otherwise it's allocated.
+ */
+ char *data_path;
+} wmMsgParams_RNA;
+
+typedef struct wmMsg_RNA {
+ wmMsg head; /* keep first */
+ wmMsgParams_RNA params;
+} wmMsg_RNA;
+
+typedef struct wmMsgSubscribeKey_RNA {
+ wmMsgSubscribeKey head;
+ wmMsg_RNA msg;
+} wmMsgSubscribeKey_RNA;
+
+#ifdef __GNUC__
+#define _WM_MESSAGE_EXTERN_BEGIN \
+ _Pragma("GCC diagnostic push"); \
+ _Pragma("GCC diagnostic ignored \"-Wredundant-decls\"");
+#define _WM_MESSAGE_EXTERN_END \
+ _Pragma("GCC diagnostic pop");
+#else
+#define _WM_MESSAGE_EXTERN_BEGIN
+#define _WM_MESSAGE_EXTERN_END
+#endif
+
+void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msg_type);
+
+wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(
+ struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params);
+void WM_msg_publish_rna_params(
+ struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params);
+void WM_msg_publish_rna(
+ struct wmMsgBus *mbus,
+ /* wmMsgParams_RNA (expanded) */
+ PointerRNA *ptr, PropertyRNA *prop);
+void WM_msg_subscribe_rna_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_RNA *msg_key_params,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+void WM_msg_subscribe_rna(
+ struct wmMsgBus *mbus,
+ PointerRNA *ptr, const PropertyRNA *prop,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+
+/* ID variants */
+void WM_msg_subscribe_ID(
+ struct wmMsgBus *mbus, struct ID *id, const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+void WM_msg_publish_ID(
+ struct wmMsgBus *mbus, struct ID *id);
+
+#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_) { \
+ wmMsgParams_RNA msg_key_params_ = {{{0}}}; \
+ _WM_MESSAGE_EXTERN_BEGIN; \
+ extern PropertyRNA rna_##type_##_##prop_; \
+ _WM_MESSAGE_EXTERN_END; \
+ RNA_pointer_create(id_, &RNA_##type_, data_, &msg_key_params_.ptr); \
+ msg_key_params_.prop = &rna_##type_##_##prop_; \
+ WM_msg_publish_rna_params(mbus, &msg_key_params_); \
+} ((void)0)
+#define WM_msg_subscribe_rna_prop(mbus, id_, data_, type_, prop_, value) { \
+ wmMsgParams_RNA msg_key_params_ = {{{0}}}; \
+ _WM_MESSAGE_EXTERN_BEGIN; \
+ extern PropertyRNA rna_##type_##_##prop_; \
+ _WM_MESSAGE_EXTERN_END; \
+ RNA_pointer_create(id_, &RNA_##type_, data_, &msg_key_params_.ptr); \
+ msg_key_params_.prop = &rna_##type_##_##prop_; \
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params_, value, __func__); \
+} ((void)0)
+
+/* Anonymous variants (for convenience) */
+#define WM_msg_subscribe_rna_anon_type(mbus, type_, value) { \
+ WM_msg_subscribe_rna_params( \
+ mbus, \
+ &(const wmMsgParams_RNA){ \
+ .ptr = (PointerRNA){.type = &RNA_##type_}, \
+ .prop = NULL, \
+ }, \
+ value, __func__); \
+} ((void)0)
+#define WM_msg_subscribe_rna_anon_prop(mbus, type_, prop_, value) { \
+ _WM_MESSAGE_EXTERN_BEGIN; \
+ extern PropertyRNA rna_##type_##_##prop_; \
+ _WM_MESSAGE_EXTERN_END; \
+ WM_msg_subscribe_rna_params( \
+ mbus, \
+ &(const wmMsgParams_RNA){ \
+ .ptr = (PointerRNA){.type = &RNA_##type_}, \
+ .prop = &rna_##type_##_##prop_, \
+ }, \
+ value, __func__); \
+} ((void)0)
+
+#endif /* __WM_MESSAGE_BUS_H__ */
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index 5f850a076f0..89fd2fdf557 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -31,9 +31,12 @@
#ifndef __WM_H__
#define __WM_H__
+struct ARegion;
struct wmWindow;
struct ReportList;
+#include "gizmo/wm_gizmo_wmapi.h"
+
typedef struct wmPaintCursor {
struct wmPaintCursor *next, *prev;
@@ -41,6 +44,9 @@ typedef struct wmPaintCursor {
bool (*poll)(struct bContext *C);
void (*draw)(bContext *C, int, int, void *customdata);
+
+ short space_type;
+ short region_type;
} wmPaintCursor;
@@ -49,7 +55,7 @@ void wm_exit_schedule_delayed(const bContext *C);
extern void wm_close_and_free(bContext *C, wmWindowManager *);
extern void wm_close_and_free_all(bContext *C, ListBase *);
-extern void wm_add_default(bContext *C);
+extern void wm_add_default(struct Main *bmain, bContext *C);
extern void wm_clear_default_size(bContext *C);
/* register to windowmanager for redo or macro */
@@ -81,7 +87,11 @@ void wm_autosave_read(bContext *C, struct ReportList *reports);
void wm_autosave_location(char *filepath);
/* wm_stereo.c */
-void wm_method_draw_stereo3d(const bContext *C, wmWindow *win);
+void wm_stereo3d_draw_interlace(wmWindow *win, struct ARegion *ar);
+void wm_stereo3d_draw_anaglyph(wmWindow *win, struct ARegion *ar);
+void wm_stereo3d_draw_sidebyside(wmWindow *win, int view);
+void wm_stereo3d_draw_topbottom(wmWindow *win, int view);
+
void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy);
int wm_stereo3d_set_exec(bContext *C, wmOperator *op);
int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event);
diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h
index de9ad599781..1e0f3cd6b35 100644
--- a/source/blender/windowmanager/wm_draw.h
+++ b/source/blender/windowmanager/wm_draw.h
@@ -34,30 +34,26 @@
#include "GPU_glew.h"
-typedef struct wmDrawTriple {
- GLuint bind;
- int x, y;
- GLenum target;
-} wmDrawTriple;
+struct GPUOffScreen;
+struct GPUViewport;
+struct GPUTexture;
-typedef struct wmDrawData {
- struct wmDrawData *next, *prev;
- wmDrawTriple *triple;
-} wmDrawData;
+typedef struct wmDrawBuffer {
+ struct GPUOffScreen *offscreen[2];
+ struct GPUViewport *viewport[2];
+ bool stereo;
+ int bound_view;
+} wmDrawBuffer;
struct bContext;
struct wmWindow;
struct ARegion;
/* wm_draw.c */
-void wm_draw_update (struct bContext *C);
-void wm_draw_window_clear (struct wmWindow *win);
-void wm_draw_region_clear (struct wmWindow *win, struct ARegion *ar);
+void wm_draw_update(struct bContext *C);
+void wm_draw_region_clear(struct wmWindow *win, struct ARegion *ar);
+void wm_draw_region_blend(struct ARegion *ar, int view, bool blend);
-void wm_tag_redraw_overlay (struct wmWindow *win, struct ARegion *ar);
-
-void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha, bool is_interlace);
-
-void wm_draw_data_free (struct wmWindow *win);
+struct GPUTexture *wm_draw_region_texture(struct ARegion *ar, int view);
#endif /* __WM_DRAW_H__ */
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index c890f25c053..fe28cbf9895 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -40,7 +40,12 @@
struct ScrArea;
struct ARegion;
-/* wmKeyMap is in DNA_windowmanager.h, it's savable */
+/* wmKeyMap is in DNA_windowmanager.h, it's saveable */
+
+struct wmEventHandler_KeymapFn {
+ void (*handle_post_fn)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data);
+ void *user_data;
+};
typedef struct wmEventHandler {
struct wmEventHandler *next, *prev;
@@ -51,6 +56,10 @@ typedef struct wmEventHandler {
/* keymap handler */
wmKeyMap *keymap; /* pointer to builtin/custom keymaps */
const rcti *bblocal, *bbwin; /* optional local and windowspace bb */
+ /* Run after the keymap item runs. */
+ struct wmEventHandler_KeymapFn keymap_callback;
+
+ struct bToolRef *keymap_tool;
/* modal operator handler */
wmOperator *op; /* for derived/modal handlers */
@@ -68,7 +77,8 @@ typedef struct wmEventHandler {
/* drop box handler */
ListBase *dropboxes;
-
+ /* gizmo handler */
+ struct wmGizmoMap *gizmo_map;
} wmEventHandler;
/* custom types for handlers, for signaling, freeing */
@@ -87,9 +97,12 @@ void wm_event_do_handlers (bContext *C);
void wm_event_add_ghostevent (wmWindowManager *wm, wmWindow *win, int type, int time, void *customdata);
+void wm_event_do_depsgraph(bContext *C);
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
void wm_event_do_notifiers(bContext *C);
+float wm_pressure_curve(float raw_pressure);
+
/* wm_keymap.c */
/* wm_dropbox.c */
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index cee7d6aab0e..40a3d148b7b 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -61,9 +61,6 @@ enum {
MIDDLEMOUSE = 0x0002,
RIGHTMOUSE = 0x0003,
MOUSEMOVE = 0x0004,
- /* only use if you want user option switch possible */
- ACTIONMOUSE = 0x0005,
- SELECTMOUSE = 0x0006,
/* Extra mouse buttons */
BUTTON4MOUSE = 0x0007,
BUTTON5MOUSE = 0x0008,
@@ -324,9 +321,6 @@ enum {
EVT_TWEAK_L = 0x5002,
EVT_TWEAK_M = 0x5003,
EVT_TWEAK_R = 0x5004,
- /* tweak events for action or select mousebutton */
- EVT_TWEAK_A = 0x5005,
- EVT_TWEAK_S = 0x5006,
EVT_GESTURE = 0x5010,
/* 0x5011 is taken, see EVT_ACTIONZONE_FULLSCREEN */
@@ -338,6 +332,8 @@ enum {
EVT_DROP = 0x5023,
EVT_BUT_CANCEL = 0x5024,
+ /* could become gizmo callback */
+ EVT_GIZMO_UPDATE = 0x5025,
/* ********** End of Blender internal events. ********** */
};
@@ -369,7 +365,7 @@ enum {
#define ISMOUSE_GESTURE(event_type) ((event_type) >= MOUSEPAN && (event_type) <= MOUSEROTATE)
#define ISMOUSE_BUTTON(event_type) \
(ELEM(event_type, \
- LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE, ACTIONMOUSE, SELECTMOUSE, \
+ LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE, \
BUTTON4MOUSE, BUTTON5MOUSE, BUTTON6MOUSE, BUTTON7MOUSE))
/* test whether the event is tweak event */
@@ -446,7 +442,7 @@ enum {
GESTURE_MODAL_CIRCLE_ADD = 6, /* circle sel: larger brush */
GESTURE_MODAL_CIRCLE_SUB = 7, /* circle sel: smaller brush */
- GESTURE_MODAL_BEGIN = 8, /* border select/straight line, activate, use release to detect which button */
+ GESTURE_MODAL_BEGIN = 8, /* box select/straight line, activate, use release to detect which button */
/* Uses 'zoom_out' operator property. */
GESTURE_MODAL_IN = 9,
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 465abf011fa..f6f43c3d856 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -39,7 +39,8 @@ void wm_history_file_read(void);
void wm_homefile_read(
struct bContext *C, struct ReportList *reports,
bool use_factory_settings, bool use_empty_data, bool use_userdef,
- const char *filepath_startup_override, const char *app_template_override);
+ const char *filepath_startup_override, const char *app_template_override,
+ bool *r_is_factory_startup);
void wm_file_read_report(bContext *C, struct Main *bmain);
void WM_OT_save_homefile(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h
deleted file mode 100644
index 3240ee4a017..00000000000
--- a/source/blender/windowmanager/wm_subwindow.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * ***** 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) 2007 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/windowmanager/wm_subwindow.h
- * \ingroup wm
- */
-
-
-#ifndef __WM_SUBWINDOW_H__
-#define __WM_SUBWINDOW_H__
-
-
-/* *************** internal api ************** */
-void wm_subwindows_free(wmWindow *win);
-
-int wm_subwindow_open(wmWindow *win, const rcti *winrct, bool activate);
-void wm_subwindow_close(wmWindow *win, int swinid);
-int wm_subwindow_get_id(wmWindow *win); /* returns id */
-
-void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct, bool activate);
-
-void wm_subwindow_size_get(wmWindow *win, int swinid, int *x, int *y);
-void wm_subwindow_origin_get(wmWindow *win, int swinid, int *x, int *y);
-void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]);
-void wm_subwindow_rect_get(wmWindow *win, int swinid, struct rcti *r_rect);
-void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect);
-
-#endif /* __WM_SUBWINDOW_H__ */
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 5fccbd74250..5988c8dab17 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -32,7 +32,11 @@
#ifndef __WM_WINDOW_H__
#define __WM_WINDOW_H__
+struct EnumPropertyItem;
+struct wmEvent;
struct wmOperator;
+struct PointerRNA;
+struct PropertyRNA;
/* *************** internal api ************** */
void wm_ghost_init (bContext *C);
@@ -41,9 +45,9 @@ void wm_ghost_exit(void);
void wm_get_screensize(int *r_width, int *r_height);
void wm_get_desktopsize(int *r_width, int *r_height);
-wmWindow *wm_window_new (bContext *C);
-wmWindow *wm_window_copy (bContext *C, wmWindow *win_src);
-wmWindow *wm_window_copy_test (bContext *C, wmWindow *win_src);
+wmWindow *wm_window_new (bContext *C, wmWindow *parent);
+wmWindow *wm_window_copy (bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child);
+wmWindow *wm_window_copy_test (bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child);
void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_close (bContext *C, wmWindowManager *wm, wmWindow *win);
@@ -53,7 +57,9 @@ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm);
void wm_window_process_events (const bContext *C);
void wm_window_process_events_nosleep(void);
+void wm_window_clear_drawable(wmWindowManager *wm);
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win);
+void wm_window_reset_drawable(void);
void wm_window_raise (wmWindow *win);
void wm_window_lower (wmWindow *win);
@@ -76,10 +82,14 @@ void wm_window_IME_end (wmWindow *win);
/* *************** window operators ************** */
int wm_window_close_exec(bContext *C, struct wmOperator *op);
-int wm_window_duplicate_exec(bContext *C, struct wmOperator *op);
int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op);
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) ATTR_NONNULL();
+int wm_window_new_exec(bContext *C, struct wmOperator *op);
+int wm_window_new_main_exec(bContext *C, struct wmOperator *op);
+
+void wm_test_autorun_warning(bContext *C);
+
/* Initial (unmaximized) size to start with for
* systems that can't find it for themselves (X11).
* Clamped by real desktop limits */